209 lines
6.5 KiB
C
209 lines
6.5 KiB
C
/*
|
|
* Copyright (c) 2022 ITE Corporation. All Rights Reserved.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#define DT_DRV_COMPAT ite_it8xxx2_pinctrl_func
|
|
|
|
#include <zephyr/drivers/pinctrl.h>
|
|
#include <zephyr/logging/log.h>
|
|
|
|
#include <chip_chipregs.h>
|
|
|
|
LOG_MODULE_REGISTER(pinctrl_ite_it8xxx2, LOG_LEVEL_ERR);
|
|
|
|
#define GPIO_IT8XXX2_REG_BASE \
|
|
((struct gpio_it8xxx2_regs *)DT_REG_ADDR(DT_NODELABEL(gpiogcr)))
|
|
#define GPIO_GROUP_MEMBERS 8
|
|
|
|
struct pinctrl_it8xxx2_config {
|
|
/* gpio port control register (byte mapping to pin) */
|
|
uint8_t *reg_gpcr;
|
|
/* function 3 general control register */
|
|
uintptr_t func3_gcr[GPIO_GROUP_MEMBERS];
|
|
/* function 3 enable mask */
|
|
uint8_t func3_en_mask[GPIO_GROUP_MEMBERS];
|
|
/* function 4 general control register */
|
|
uintptr_t func4_gcr[GPIO_GROUP_MEMBERS];
|
|
/* function 4 enable mask */
|
|
uint8_t func4_en_mask[GPIO_GROUP_MEMBERS];
|
|
/* Input voltage selection */
|
|
uintptr_t volt_sel[GPIO_GROUP_MEMBERS];
|
|
/* Input voltage selection mask */
|
|
uint8_t volt_sel_mask[GPIO_GROUP_MEMBERS];
|
|
};
|
|
|
|
static int pinctrl_it8xxx2_set(const pinctrl_soc_pin_t *pins)
|
|
{
|
|
const struct pinctrl_it8xxx2_config *pinctrl_config = pins->pinctrls->config;
|
|
uint32_t pincfg = pins->pincfg;
|
|
uint8_t pin = pins->pin;
|
|
volatile uint8_t *reg_gpcr = (uint8_t *)pinctrl_config->reg_gpcr + pin;
|
|
volatile uint8_t *reg_volt_sel = (uint8_t *)(pinctrl_config->volt_sel[pin]);
|
|
|
|
/* Setting pull-up or pull-down. */
|
|
switch (IT8XXX2_DT_PINCFG_PUPDR(pincfg)) {
|
|
case IT8XXX2_PULL_PIN_DEFAULT:
|
|
/* No pull-up or pull-down */
|
|
*reg_gpcr &= ~(GPCR_PORT_PIN_MODE_PULLUP |
|
|
GPCR_PORT_PIN_MODE_PULLDOWN);
|
|
break;
|
|
case IT8XXX2_PULL_UP:
|
|
*reg_gpcr = (*reg_gpcr | GPCR_PORT_PIN_MODE_PULLUP) &
|
|
~GPCR_PORT_PIN_MODE_PULLDOWN;
|
|
break;
|
|
case IT8XXX2_PULL_DOWN:
|
|
*reg_gpcr = (*reg_gpcr | GPCR_PORT_PIN_MODE_PULLDOWN) &
|
|
~GPCR_PORT_PIN_MODE_PULLUP;
|
|
break;
|
|
default:
|
|
LOG_ERR("This pull level is not supported.");
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* Setting voltage 3.3V or 1.8V. */
|
|
switch (IT8XXX2_DT_PINCFG_VOLTAGE(pincfg)) {
|
|
case IT8XXX2_VOLTAGE_3V3:
|
|
/* Input voltage selection 3.3V. */
|
|
*reg_volt_sel &= ~pinctrl_config->volt_sel_mask[pin];
|
|
break;
|
|
case IT8XXX2_VOLTAGE_1V8:
|
|
__ASSERT(!(IT8XXX2_DT_PINCFG_PUPDR(pincfg)
|
|
== IT8XXX2_PULL_UP),
|
|
"Don't enable internal pullup if 1.8V voltage is used");
|
|
/* Input voltage selection 1.8V. */
|
|
*reg_volt_sel |= pinctrl_config->volt_sel_mask[pin];
|
|
break;
|
|
default:
|
|
LOG_ERR("The voltage selection is not supported");
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* Setting tri-state mode. */
|
|
if (IT8XXX2_DT_PINCFG_IMPEDANCE(pincfg)) {
|
|
*reg_gpcr |= (GPCR_PORT_PIN_MODE_PULLUP |
|
|
GPCR_PORT_PIN_MODE_PULLDOWN);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt,
|
|
uintptr_t reg)
|
|
{
|
|
ARG_UNUSED(reg);
|
|
|
|
const struct pinctrl_it8xxx2_config *pinctrl_config;
|
|
volatile uint8_t *reg_gpcr;
|
|
volatile uint8_t *reg_func3_gcr;
|
|
volatile uint8_t *reg_func4_gcr;
|
|
uint8_t pin;
|
|
|
|
for (uint8_t i = 0U; i < pin_cnt; i++) {
|
|
pinctrl_config = pins[i].pinctrls->config;
|
|
pin = pins[i].pin;
|
|
reg_gpcr = (uint8_t *)pinctrl_config->reg_gpcr + pin;
|
|
reg_func3_gcr = (uint8_t *)(pinctrl_config->func3_gcr[pin]);
|
|
reg_func4_gcr = (uint8_t *)(pinctrl_config->func4_gcr[pin]);
|
|
|
|
/* Handle PIN configuration. */
|
|
if (pinctrl_it8xxx2_set(&pins[i])) {
|
|
LOG_ERR("Pin configuration is invalid.");
|
|
return -EINVAL;
|
|
}
|
|
|
|
/*
|
|
* If pincfg is input, we don't need to handle
|
|
* alternate function.
|
|
*/
|
|
if (IT8XXX2_DT_PINCFG_INPUT(pins[i].pincfg)) {
|
|
*reg_gpcr = (*reg_gpcr | GPCR_PORT_PIN_MODE_INPUT) &
|
|
~GPCR_PORT_PIN_MODE_OUTPUT;
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* Handle alternate function.
|
|
*/
|
|
/* Common settings for alternate function. */
|
|
*reg_gpcr &= ~(GPCR_PORT_PIN_MODE_INPUT |
|
|
GPCR_PORT_PIN_MODE_OUTPUT);
|
|
switch (pins[i].alt_func) {
|
|
case IT8XXX2_ALT_FUNC_1:
|
|
/* Func1: Alternate function has been set above. */
|
|
break;
|
|
case IT8XXX2_ALT_FUNC_2:
|
|
/* Func2: WUI function: turn the pin into an input */
|
|
*reg_gpcr |= GPCR_PORT_PIN_MODE_INPUT;
|
|
break;
|
|
case IT8XXX2_ALT_FUNC_3:
|
|
/*
|
|
* Func3: In addition to the alternate setting above,
|
|
* Func3 also need to set the general control.
|
|
*/
|
|
*reg_func3_gcr |= pinctrl_config->func3_en_mask[pin];
|
|
break;
|
|
case IT8XXX2_ALT_FUNC_4:
|
|
/*
|
|
* Func4: In addition to the alternate setting above,
|
|
* Func4 also need to set the general control.
|
|
*/
|
|
*reg_func4_gcr |= pinctrl_config->func4_en_mask[pin];
|
|
break;
|
|
case IT8XXX2_ALT_DEFAULT:
|
|
*reg_gpcr = (*reg_gpcr | GPCR_PORT_PIN_MODE_INPUT) &
|
|
~GPCR_PORT_PIN_MODE_OUTPUT;
|
|
*reg_func3_gcr &= ~pinctrl_config->func3_en_mask[pin];
|
|
*reg_func4_gcr &= ~pinctrl_config->func4_en_mask[pin];
|
|
break;
|
|
default:
|
|
LOG_ERR("This function is not supported.");
|
|
return -EINVAL;
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int pinctrl_it8xxx2_init(const struct device *dev)
|
|
{
|
|
struct gpio_it8xxx2_regs *const gpio_base = GPIO_IT8XXX2_REG_BASE;
|
|
|
|
/*
|
|
* The default value of LPCRSTEN is bit2:1 = 10b(GPD2) in GCR.
|
|
* If LPC reset is enabled on GPB7, we have to clear bit2:1
|
|
* to 00b.
|
|
*/
|
|
gpio_base->GPIO_GCR &= ~IT8XXX2_GPIO_LPCRSTEN;
|
|
|
|
/*
|
|
* TODO: If UART2 swaps from bit2:1 to bit6:5 in H group, we
|
|
* have to set UART1PSEL = 1 in UART1PMR register.
|
|
*/
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define PINCTRL_ITE_INIT(inst) \
|
|
static const struct pinctrl_it8xxx2_config pinctrl_it8xxx2_cfg_##inst = { \
|
|
.reg_gpcr = (uint8_t *)DT_INST_REG_ADDR(inst), \
|
|
.func3_gcr = DT_INST_PROP(inst, func3_gcr), \
|
|
.func3_en_mask = DT_INST_PROP(inst, func3_en_mask), \
|
|
.func4_gcr = DT_INST_PROP(inst, func4_gcr), \
|
|
.func4_en_mask = DT_INST_PROP(inst, func4_en_mask), \
|
|
.volt_sel = DT_INST_PROP(inst, volt_sel), \
|
|
.volt_sel_mask = DT_INST_PROP(inst, volt_sel_mask), \
|
|
}; \
|
|
\
|
|
DEVICE_DT_INST_DEFINE(inst, &pinctrl_it8xxx2_init, \
|
|
NULL, \
|
|
NULL, \
|
|
&pinctrl_it8xxx2_cfg_##inst, \
|
|
PRE_KERNEL_1, \
|
|
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
|
|
NULL);
|
|
|
|
DT_INST_FOREACH_STATUS_OKAY(PINCTRL_ITE_INIT)
|