zephyr/drivers/pinctrl/pinctrl_ite_it8xxx2.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)