/* * Copyright (c) 2020 ITE Corporation. All Rights Reserved. * * SPDX-License-Identifier: Apache-2.0 */ /** * @brief PINMUX driver for the IT8xxx2 */ #include #include #include #include #include #define DT_DRV_COMPAT ite_it8xxx2_pinmux #include LOG_MODULE_REGISTER(pinmux_ite_it8xxx2, LOG_LEVEL_ERR); struct pinmux_it8xxx2_config { /* gpio port control register (byte mapping to pin) */ uintptr_t reg_gpcr; /* function 3 general control register */ uintptr_t func3_gcr[8]; /* function 4 general control register */ uintptr_t func4_gcr[8]; /* function 3 enable mask */ uint8_t func3_en_mask[8]; /* function 4 enable mask */ uint8_t func4_en_mask[8]; }; #define DEV_CFG(dev) \ ((const struct pinmux_it8xxx2_config * const) \ (dev)->config) static int pinmux_it8xxx2_set(const struct device *dev, uint32_t pin, uint32_t func) { const struct pinmux_it8xxx2_config *pinmux_config = DEV_CFG(dev); volatile uint8_t *reg_gpcr = (uint8_t *)(pinmux_config->reg_gpcr + pin); volatile uint8_t *reg_func3_gcr = (uint8_t *)(pinmux_config->func3_gcr[pin]); volatile uint8_t *reg_func4_gcr = (uint8_t *)(pinmux_config->func4_gcr[pin]); if (pin >= IT8XXX2_PINMUX_PINS) { return -EINVAL; } /* Common settings for alternate function. */ *reg_gpcr &= ~(GPCR_PORT_PIN_MODE_INPUT | GPCR_PORT_PIN_MODE_OUTPUT); switch (func) { case IT8XXX2_PINMUX_FUNC_1: /* Func1: Alternate function has been set above. */ break; case IT8XXX2_PINMUX_FUNC_2: /* Func2: WUI function: turn the pin into an input */ *reg_gpcr |= GPCR_PORT_PIN_MODE_INPUT; break; case IT8XXX2_PINMUX_FUNC_3: /* * Func3: In addition to the alternate setting above, * Func3 also need to set the general control. */ *reg_func3_gcr |= pinmux_config->func3_en_mask[pin]; break; case IT8XXX2_PINMUX_FUNC_4: /* * Func4: In addition to the alternate setting above, * Func4 also need to set the general control. */ *reg_func4_gcr |= pinmux_config->func4_en_mask[pin]; break; default: LOG_ERR("This function is not supported"); return -EINVAL; } return 0; } static int pinmux_it8xxx2_get(const struct device *dev, uint32_t pin, uint32_t *func) { const struct pinmux_it8xxx2_config *pinmux_config = DEV_CFG(dev); volatile uint8_t *reg_gpcr = (uint8_t *)(pinmux_config->reg_gpcr + pin); if (pin >= IT8XXX2_PINMUX_PINS || func == NULL) { return -EINVAL; } *func = (*reg_gpcr & (GPCR_PORT_PIN_MODE_INPUT | GPCR_PORT_PIN_MODE_OUTPUT)) == GPCR_PORT_PIN_MODE_INPUT ? IT8XXX2_PINMUX_FUNC_2 : IT8XXX2_PINMUX_FUNC_1; /* TODO: IT8XXX2_PINMUX_FUNC_3 & IT8XXX2_PINMUX_FUNC_4 */ return 0; } static int pinmux_it8xxx2_pullup(const struct device *dev, uint32_t pin, uint8_t func) { const struct pinmux_it8xxx2_config *pinmux_config = DEV_CFG(dev); volatile uint8_t *reg_gpcr = (uint8_t *)(pinmux_config->reg_gpcr + pin); if (func == PINMUX_PULLUP_ENABLE) { *reg_gpcr = (*reg_gpcr | GPCR_PORT_PIN_MODE_PULLUP) & ~GPCR_PORT_PIN_MODE_PULLDOWN; } else if (func == PINMUX_PULLUP_DISABLE) { *reg_gpcr &= ~(GPCR_PORT_PIN_MODE_PULLUP | GPCR_PORT_PIN_MODE_PULLDOWN); } else { return -EINVAL; } return 0; } static int pinmux_it8xxx2_input(const struct device *dev, uint32_t pin, uint8_t func) { const struct pinmux_it8xxx2_config *pinmux_config = DEV_CFG(dev); volatile uint8_t *reg_gpcr = (uint8_t *)(pinmux_config->reg_gpcr + pin); *reg_gpcr &= ~(GPCR_PORT_PIN_MODE_INPUT | GPCR_PORT_PIN_MODE_OUTPUT); if (func == PINMUX_INPUT_ENABLED) { *reg_gpcr |= GPCR_PORT_PIN_MODE_INPUT; } else if (func == PINMUX_OUTPUT_ENABLED) { *reg_gpcr |= GPCR_PORT_PIN_MODE_OUTPUT; } else { return -EINVAL; } return 0; } static int pinmux_it8xxx2_init(const struct device *dev) { ARG_UNUSED(dev); /* * 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. */ IT8XXX2_GPIO_GCR &= ~(BIT(1) | BIT(2)); /* * TODO: If SMBUS3 swaps from H group to F group, we have to * set SMB3PSEL = 1 in PMER3 register. */ /* * TODO: If UART2 swaps from bit2:1 to bit6:5 in H group, we * have to set UART1PSEL = 1 in UART1PMR register. */ return 0; } static const struct pinmux_driver_api pinmux_it8xxx2_driver_api = { .set = pinmux_it8xxx2_set, .get = pinmux_it8xxx2_get, .pullup = pinmux_it8xxx2_pullup, .input = pinmux_it8xxx2_input, }; #define PINMUX_ITE_INIT(inst) \ static const struct pinmux_it8xxx2_config pinmux_it8xxx2_cfg_##inst = { \ .reg_gpcr = 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), \ }; \ \ DEVICE_DT_INST_DEFINE(inst, \ &pinmux_it8xxx2_init, \ NULL, NULL, &pinmux_it8xxx2_cfg_##inst, \ PRE_KERNEL_1, \ CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ &pinmux_it8xxx2_driver_api); DT_INST_FOREACH_STATUS_OKAY(PINMUX_ITE_INIT)