433 lines
14 KiB
C
433 lines
14 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/gpio.h>
|
|
#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_gpio {
|
|
/* gpio port control register (byte mapping to pin) */
|
|
uint8_t *reg_gpcr;
|
|
/* port driving select control */
|
|
uint8_t *reg_pdsc;
|
|
/* 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 3 external control register */
|
|
uintptr_t func3_ext[GPIO_GROUP_MEMBERS];
|
|
/* function 3 external mask */
|
|
uint8_t func3_ext_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];
|
|
};
|
|
|
|
struct pinctrl_it8xxx2_ksi_kso {
|
|
/*
|
|
* KSI[7:0]/KSO[15:8]/KSO[7:0] port gpio control register
|
|
* (bit mapping to pin)
|
|
*/
|
|
uint8_t *reg_gctrl;
|
|
/* KSI[7:0]/KSO[15:8]/KSO[7:0] port control register */
|
|
uint8_t *reg_ctrl;
|
|
/*
|
|
* KSO push-pull/open-drain bit of KSO[15:0] control register
|
|
* (this bit apply to all pins)
|
|
*/
|
|
int pp_od_mask;
|
|
/*
|
|
* KSI/KSO pullup bit of KSI[7:0]/KSO[15:0] control register
|
|
* (this bit apply to all pins)
|
|
*/
|
|
int pullup_mask;
|
|
};
|
|
|
|
struct pinctrl_it8xxx2_config {
|
|
bool gpio_group;
|
|
union {
|
|
struct pinctrl_it8xxx2_gpio gpio;
|
|
struct pinctrl_it8xxx2_ksi_kso ksi_kso;
|
|
};
|
|
};
|
|
|
|
static int pinctrl_it8xxx2_set(const pinctrl_soc_pin_t *pins)
|
|
{
|
|
const struct pinctrl_it8xxx2_config *pinctrl_config = pins->pinctrls->config;
|
|
const struct pinctrl_it8xxx2_gpio *gpio = &(pinctrl_config->gpio);
|
|
uint32_t pincfg = pins->pincfg;
|
|
uint8_t pin = pins->pin;
|
|
volatile uint8_t *reg_gpcr = (uint8_t *)gpio->reg_gpcr + pin;
|
|
volatile uint8_t *reg_volt_sel = (uint8_t *)(gpio->volt_sel[pin]);
|
|
volatile uint8_t *reg_pdsc = (uint8_t *)gpio->reg_pdsc;
|
|
|
|
/* 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;
|
|
}
|
|
|
|
/*
|
|
* Since not all GPIOs support voltage selection, configure voltage
|
|
* selection register only if it is present.
|
|
*/
|
|
if (reg_volt_sel != NULL) {
|
|
/* 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 &= ~gpio->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 |= gpio->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);
|
|
}
|
|
|
|
/* Driving current selection. */
|
|
if (reg_pdsc != NULL &&
|
|
IT8XXX2_DT_PINCFG_DRIVE_CURRENT(pincfg) != IT8XXX2_DRIVE_DEFAULT) {
|
|
if (IT8XXX2_DT_PINCFG_DRIVE_CURRENT(pincfg) & IT8XXX2_PDSCX_MASK) {
|
|
/* Driving current selects low. */
|
|
*reg_pdsc |= BIT(pin);
|
|
} else {
|
|
/* Driving current selects high. */
|
|
*reg_pdsc &= ~BIT(pin);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int pinctrl_gpio_it8xxx2_configure_pins(const pinctrl_soc_pin_t *pins)
|
|
{
|
|
const struct pinctrl_it8xxx2_config *pinctrl_config = pins->pinctrls->config;
|
|
const struct pinctrl_it8xxx2_gpio *gpio = &(pinctrl_config->gpio);
|
|
uint8_t pin = pins->pin;
|
|
volatile uint8_t *reg_gpcr = (uint8_t *)gpio->reg_gpcr + pin;
|
|
volatile uint8_t *reg_func3_gcr = (uint8_t *)(gpio->func3_gcr[pin]);
|
|
volatile uint8_t *reg_func4_gcr = (uint8_t *)(gpio->func4_gcr[pin]);
|
|
volatile uint8_t *reg_func3_ext = (uint8_t *)(gpio->func3_ext[pin]);
|
|
|
|
/* Handle PIN configuration. */
|
|
if (pinctrl_it8xxx2_set(pins)) {
|
|
LOG_ERR("Pin configuration is invalid.");
|
|
return -EINVAL;
|
|
}
|
|
|
|
/*
|
|
* Default input mode prevents leakage during changes to extended
|
|
* setting (e.g. enabling i2c functionality on GPIO E1/E2 on IT82002)
|
|
*/
|
|
*reg_gpcr = (*reg_gpcr | GPCR_PORT_PIN_MODE_INPUT) &
|
|
~GPCR_PORT_PIN_MODE_OUTPUT;
|
|
|
|
/*
|
|
* If pincfg is input, we don't need to handle
|
|
* alternate function.
|
|
*/
|
|
if (IT8XXX2_DT_PINCFG_INPUT(pins->pincfg)) {
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Handle alternate function.
|
|
*/
|
|
if (reg_func3_gcr != NULL) {
|
|
*reg_func3_gcr &= ~gpio->func3_en_mask[pin];
|
|
}
|
|
/* Ensure that func3-ext setting is in default state. */
|
|
if (reg_func3_ext != NULL) {
|
|
*reg_func3_ext &= ~gpio->func3_ext_mask[pin];
|
|
}
|
|
|
|
switch (pins->alt_func) {
|
|
case IT8XXX2_ALT_FUNC_1:
|
|
/* Func1: Alternate function will be set below. */
|
|
break;
|
|
case IT8XXX2_ALT_FUNC_2:
|
|
/* Func2: WUI function: pin has been set as input above.*/
|
|
return 0;
|
|
case IT8XXX2_ALT_FUNC_3:
|
|
/*
|
|
* Func3: In addition to the alternate setting above,
|
|
* Func3 also need to set the general control.
|
|
*/
|
|
if (reg_func3_gcr != NULL) {
|
|
*reg_func3_gcr |= gpio->func3_en_mask[pin];
|
|
}
|
|
/* Func3-external: Some pins require external setting. */
|
|
if (reg_func3_ext != NULL) {
|
|
*reg_func3_ext |= gpio->func3_ext_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 |= gpio->func4_en_mask[pin];
|
|
break;
|
|
case IT8XXX2_ALT_DEFAULT:
|
|
*reg_func3_gcr &= ~gpio->func3_en_mask[pin];
|
|
*reg_func4_gcr &= ~gpio->func4_en_mask[pin];
|
|
return 0;
|
|
default:
|
|
LOG_ERR("This function is not supported.");
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* Common settings for alternate function. */
|
|
*reg_gpcr &= ~(GPCR_PORT_PIN_MODE_INPUT |
|
|
GPCR_PORT_PIN_MODE_OUTPUT);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int pinctrl_kscan_it8xxx2_set(const pinctrl_soc_pin_t *pins)
|
|
{
|
|
const struct pinctrl_it8xxx2_config *pinctrl_config = pins->pinctrls->config;
|
|
const struct pinctrl_it8xxx2_ksi_kso *ksi_kso = &(pinctrl_config->ksi_kso);
|
|
volatile uint8_t *reg_ctrl = ksi_kso->reg_ctrl;
|
|
uint8_t pullup_mask = ksi_kso->pullup_mask;
|
|
uint8_t pp_od_mask = ksi_kso->pp_od_mask;
|
|
uint32_t pincfg = pins->pincfg;
|
|
|
|
/*
|
|
* Enable or disable internal pull-up (this bit apply to all pins):
|
|
* If KSI[7:0]/KSO[15:0] is in KBS mode , setting 1 enables the internal
|
|
* pull-up (KSO[17:16] setting internal pull-up by GPIO port GPCR register).
|
|
* If KSI[7:0]/KSO[15:0] is in GPIO mode, then this bit is always disabled.
|
|
*/
|
|
switch (IT8XXX2_DT_PINCFG_PULLUP(pincfg)) {
|
|
case IT8XXX2_PULL_PIN_DEFAULT:
|
|
/* Disable internal pulll-up */
|
|
*reg_ctrl &= ~pullup_mask;
|
|
break;
|
|
case IT8XXX2_PULL_UP:
|
|
*reg_ctrl |= pullup_mask;
|
|
break;
|
|
default:
|
|
LOG_ERR("This pull level is not supported.");
|
|
return -EINVAL;
|
|
}
|
|
|
|
/*
|
|
* Set push-pull or open-drain mode (this bit apply to all pins):
|
|
* KSI[7:0] doesn't support push-pull and open-drain settings in kbs mode.
|
|
* If KSO[17:0] is in KBS mode, setting 1 selects open-drain mode,
|
|
* setting 0 selects push-pull mode.
|
|
* If KSO[15:0] is in GPIO mode, then this bit is always disabled.
|
|
*/
|
|
if (pp_od_mask != NO_FUNC) {
|
|
switch (IT8XXX2_DT_PINCFG_PP_OD(pincfg)) {
|
|
case IT8XXX2_PUSH_PULL:
|
|
*reg_ctrl &= ~pp_od_mask;
|
|
break;
|
|
case IT8XXX2_OPEN_DRAIN:
|
|
*reg_ctrl |= pp_od_mask;
|
|
break;
|
|
default:
|
|
LOG_ERR("This pull mode is not supported.");
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int pinctrl_kscan_it8xxx2_configure_pins(const pinctrl_soc_pin_t *pins)
|
|
{
|
|
const struct pinctrl_it8xxx2_config *pinctrl_config = pins->pinctrls->config;
|
|
const struct pinctrl_it8xxx2_ksi_kso *ksi_kso = &(pinctrl_config->ksi_kso);
|
|
|
|
/* Set a pin of KSI[7:0]/KSO[15:0] to pullup, push-pull/open-drain */
|
|
if (pinctrl_kscan_it8xxx2_set(pins)) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
#ifdef CONFIG_SOC_IT8XXX2_REG_SET_V1
|
|
uint8_t pin_mask = BIT(pins->pin);
|
|
volatile uint8_t *reg_gctrl = ksi_kso->reg_gctrl;
|
|
|
|
switch (pins->alt_func) {
|
|
case IT8XXX2_ALT_FUNC_1:
|
|
/* Set a pin of KSI[7:0]/KSO[15:0] to kbs mode */
|
|
*reg_gctrl &= ~pin_mask;
|
|
break;
|
|
case IT8XXX2_ALT_DEFAULT:
|
|
/* Set a pin of KSI[7:0]/KSO[15:0] to gpio mode */
|
|
*reg_gctrl |= pin_mask;
|
|
break;
|
|
#elif CONFIG_SOC_IT8XXX2_REG_SET_V2
|
|
uint8_t pin = pins->pin;
|
|
volatile uint8_t *reg_gctrl = ksi_kso->reg_gctrl + pin;
|
|
|
|
switch (pins->alt_func) {
|
|
case IT8XXX2_ALT_FUNC_1:
|
|
/* Set a pin of KSI[7:0]/KSO[15:0] to kbs mode */
|
|
*reg_gctrl &= ~(GPCR_PORT_PIN_MODE_INPUT |
|
|
GPCR_PORT_PIN_MODE_OUTPUT);
|
|
break;
|
|
case IT8XXX2_ALT_DEFAULT:
|
|
/* Set a pin of KSI[7:0]/KSO[15:0] to gpio mode */
|
|
*reg_gctrl = (*reg_gctrl | GPCR_PORT_PIN_MODE_INPUT) &
|
|
~GPCR_PORT_PIN_MODE_OUTPUT;
|
|
break;
|
|
#endif
|
|
default:
|
|
LOG_ERR("Alternate function not supported");
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
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;
|
|
int status;
|
|
|
|
for (uint8_t i = 0U; i < pin_cnt; i++) {
|
|
pinctrl_config = pins[i].pinctrls->config;
|
|
|
|
if (pinctrl_config->gpio_group) {
|
|
status = pinctrl_gpio_it8xxx2_configure_pins(&pins[i]);
|
|
} else {
|
|
status = pinctrl_kscan_it8xxx2_configure_pins(&pins[i]);
|
|
}
|
|
|
|
if (status < 0) {
|
|
LOG_ERR("%s pin%d configuration is invalid.",
|
|
pins[i].pinctrls->name, pins[i].pin);
|
|
return status;
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
#ifdef CONFIG_SOC_IT8XXX2_REG_SET_V2
|
|
#if defined(CONFIG_I2C_ITE_ENHANCE) && DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(i2c5))
|
|
const struct gpio_dt_spec scl_gpios = GPIO_DT_SPEC_GET(DT_NODELABEL(i2c5), scl_gpios);
|
|
const struct gpio_dt_spec sda_gpios = GPIO_DT_SPEC_GET(DT_NODELABEL(i2c5), sda_gpios);
|
|
|
|
/*
|
|
* When setting these pins as I2C alternate mode and then setting
|
|
* GCR7 or func3-ext of GPIO extended, it will cause leakage.
|
|
* In order to prevent leakage, it must be set to GPIO INPUT mode.
|
|
*/
|
|
/* Set I2C5 SCL as GPIO input to prevent leakage */
|
|
gpio_pin_configure_dt(&scl_gpios, GPIO_INPUT);
|
|
/* Set I2C5 SDA as GPIO input to prevent leakage */
|
|
gpio_pin_configure_dt(&sda_gpios, GPIO_INPUT);
|
|
#endif
|
|
/*
|
|
* Swap the default I2C2 SMCLK2/SMDAT2 pins from GPC7/GPD0 to GPF6/GPF7,
|
|
* and I2C3 SMCLK3/SMDAT3 pins from GPB2/GPB5 to GPH1/GPH2,
|
|
* and I2C5 SMCLK5/SMDAT5 pins from GPE1/GPE2 to GPA4/GPA5,
|
|
*/
|
|
gpio_base->GPIO_GCR7 &= ~(IT8XXX2_GPIO_SMB2PS |
|
|
IT8XXX2_GPIO_SMB3PS |
|
|
IT8XXX2_GPIO_SMB5PS);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
#define INIT_UNION_CONFIG(inst) \
|
|
COND_CODE_1(DT_INST_PROP(inst, gpio_group), \
|
|
(.gpio = { \
|
|
.reg_gpcr = (uint8_t *)DT_INST_REG_ADDR_BY_IDX(inst, 0), \
|
|
.reg_pdsc = (uint8_t *)DT_INST_REG_ADDR_BY_IDX(inst, 1), \
|
|
.func3_gcr = DT_INST_PROP(inst, func3_gcr), \
|
|
.func3_en_mask = DT_INST_PROP(inst, func3_en_mask), \
|
|
.func3_ext = DT_INST_PROP_OR(inst, func3_ext, {0}), \
|
|
.func3_ext_mask = DT_INST_PROP_OR(inst, func3_ext_mask, {0}), \
|
|
.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), \
|
|
}), \
|
|
(.ksi_kso = { \
|
|
.reg_gctrl = (uint8_t *)DT_INST_REG_ADDR_BY_IDX(inst, 0), \
|
|
.reg_ctrl = (uint8_t *)DT_INST_REG_ADDR_BY_IDX(inst, 1), \
|
|
.pp_od_mask = (uint8_t)DT_INST_PROP(inst, pp_od_mask), \
|
|
.pullup_mask = (uint8_t)DT_INST_PROP(inst, pullup_mask), \
|
|
}) \
|
|
)
|
|
|
|
#define PINCTRL_ITE_INIT(inst) \
|
|
static const struct pinctrl_it8xxx2_config pinctrl_it8xxx2_cfg_##inst = { \
|
|
.gpio_group = DT_INST_PROP(inst, gpio_group), \
|
|
{ \
|
|
INIT_UNION_CONFIG(inst) \
|
|
} \
|
|
}; \
|
|
\
|
|
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)
|