| /* |
| * 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> |
| 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) |