| /* |
| * Copyright (c) 2020 Nuvoton Technology Corporation. |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <zephyr/device.h> |
| #include <zephyr/drivers/gpio.h> |
| #include <zephyr/dt-bindings/pinctrl/npcx-pinctrl.h> |
| #include <zephyr/kernel.h> |
| #include <soc.h> |
| |
| #include "soc_gpio.h" |
| |
| #include <zephyr/logging/log.h> |
| LOG_MODULE_REGISTER(pimux_npcx, LOG_LEVEL_ERR); |
| |
| /* Driver config */ |
| struct npcx_scfg_config { |
| /* scfg device base address */ |
| uintptr_t base_scfg; |
| uintptr_t base_glue; |
| }; |
| |
| /* |
| * Get io list which default functionality are not IOs. Then switch them to |
| * GPIO in pin-mux init function. |
| * |
| * def_io_conf: def-io-conf-list { |
| * compatible = "nuvoton,npcx-pinctrl-def"; |
| * pinctrl-0 = <&alt0_gpio_no_spip |
| * &alt0_gpio_no_fpip |
| * ...>; |
| * }; |
| */ |
| static const struct npcx_alt def_alts[] = |
| NPCX_DT_IO_ALT_ITEMS_LIST(nuvoton_npcx_pinctrl_def, 0); |
| |
| static const struct npcx_lvol def_lvols[] = NPCX_DT_IO_LVOL_ITEMS_DEF_LIST; |
| |
| #if DT_HAS_COMPAT_STATUS_OKAY(nuvoton_npcx_pslctrl_def) |
| static const struct npcx_psl_in psl_in_confs[] = NPCX_DT_PSL_IN_ITEMS_LIST; |
| #endif |
| |
| static const struct npcx_scfg_config npcx_scfg_cfg = { |
| .base_scfg = DT_REG_ADDR_BY_NAME(DT_NODELABEL(scfg), scfg), |
| .base_glue = DT_REG_ADDR_BY_NAME(DT_NODELABEL(scfg), glue), |
| }; |
| |
| /* Driver convenience defines */ |
| #define HAL_SFCG_INST() (struct scfg_reg *)(npcx_scfg_cfg.base_scfg) |
| |
| #define HAL_GLUE_INST() (struct glue_reg *)(npcx_scfg_cfg.base_glue) |
| |
| /* PSL input detection mode is configured by bits 7:4 of PSL_CTS */ |
| #define NPCX_PSL_CTS_MODE_BIT(bit) BIT(bit + 4) |
| /* PSL input assertion events are reported by bits 3:0 of PSL_CTS */ |
| #define NPCX_PSL_CTS_EVENT_BIT(bit) BIT(bit) |
| |
| /* Pin-control local functions */ |
| static void npcx_pinctrl_alt_sel(const struct npcx_alt *alt, int alt_func) |
| { |
| const uint32_t scfg_base = npcx_scfg_cfg.base_scfg; |
| uint8_t alt_mask = BIT(alt->bit); |
| |
| /* |
| * alt_fun == 0 means select GPIO, otherwise Alternate Func. |
| * inverted == 0: |
| * Set devalt bit to select Alternate Func. |
| * inverted == 1: |
| * Clear devalt bit to select Alternate Func. |
| */ |
| if (!!alt_func != !!alt->inverted) { |
| NPCX_DEVALT(scfg_base, alt->group) |= alt_mask; |
| } else { |
| NPCX_DEVALT(scfg_base, alt->group) &= ~alt_mask; |
| } |
| } |
| |
| /* Platform specific pin-control functions */ |
| void npcx_pinctrl_mux_configure(const struct npcx_alt *alts_list, |
| uint8_t alts_size, int altfunc) |
| { |
| int i; |
| |
| for (i = 0; i < alts_size; i++, alts_list++) { |
| npcx_pinctrl_alt_sel(alts_list, altfunc); |
| } |
| } |
| |
| void npcx_lvol_pads_configure(void) |
| { |
| const uint32_t scfg_base = npcx_scfg_cfg.base_scfg; |
| |
| for (int i = 0; i < ARRAY_SIZE(def_lvols); i++) { |
| NPCX_LV_GPIO_CTL(scfg_base, def_lvols[i].ctrl) |
| |= BIT(def_lvols[i].bit); |
| LOG_DBG("IO%x%x turn on low-voltage", def_lvols[i].io_port, |
| def_lvols[i].io_bit); |
| } |
| } |
| |
| void npcx_lvol_restore_io_pads(void) |
| { |
| for (int i = 0; i < ARRAY_SIZE(def_lvols); i++) { |
| npcx_gpio_enable_io_pads( |
| npcx_get_gpio_dev(def_lvols[i].io_port), |
| def_lvols[i].io_bit); |
| } |
| } |
| |
| void npcx_lvol_suspend_io_pads(void) |
| { |
| for (int i = 0; i < ARRAY_SIZE(def_lvols); i++) { |
| npcx_gpio_disable_io_pads( |
| npcx_get_gpio_dev(def_lvols[i].io_port), |
| def_lvols[i].io_bit); |
| } |
| } |
| |
| bool npcx_lvol_is_enabled(int port, int pin) |
| { |
| for (int i = 0; i < ARRAY_SIZE(def_lvols); i++) { |
| if (def_lvols[i].io_port == port && |
| def_lvols[i].io_bit == pin) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| void npcx_pinctrl_i2c_port_sel(int controller, int port) |
| { |
| struct glue_reg *const inst_glue = HAL_GLUE_INST(); |
| |
| if (port != 0) { |
| inst_glue->SMB_SEL |= BIT(controller); |
| } else { |
| inst_glue->SMB_SEL &= ~BIT(controller); |
| } |
| } |
| |
| int npcx_pinctrl_flash_write_protect_set(void) |
| { |
| struct scfg_reg *inst_scfg = HAL_SFCG_INST(); |
| |
| inst_scfg->DEV_CTL4 |= BIT(NPCX_DEV_CTL4_WP_IF); |
| if (!IS_BIT_SET(inst_scfg->DEV_CTL4, NPCX_DEV_CTL4_WP_IF)) { |
| return -EIO; |
| } |
| |
| return 0; |
| } |
| |
| bool npcx_pinctrl_flash_write_protect_is_set(void) |
| { |
| struct scfg_reg *inst_scfg = HAL_SFCG_INST(); |
| |
| return IS_BIT_SET(inst_scfg->DEV_CTL4, NPCX_DEV_CTL4_WP_IF); |
| } |
| |
| void npcx_pinctrl_psl_output_set_inactive(void) |
| { |
| struct gpio_reg *const inst = (struct gpio_reg *) |
| NPCX_DT_PSL_OUT_CONTROLLER(0); |
| int pin = NPCX_DT_PSL_OUT_PIN(0); |
| |
| /* Set PSL_OUT to inactive level by setting related bit of PDOUT */ |
| inst->PDOUT |= BIT(pin); |
| } |
| |
| #if DT_HAS_COMPAT_STATUS_OKAY(nuvoton_npcx_pslctrl_def) |
| static void npcx_pinctrl_psl_detect_mode_sel(uint32_t offset, bool edge_mode) |
| { |
| struct glue_reg *const inst_glue = HAL_GLUE_INST(); |
| |
| if (edge_mode) { |
| inst_glue->PSL_CTS |= NPCX_PSL_CTS_MODE_BIT(offset); |
| } else { |
| inst_glue->PSL_CTS &= ~NPCX_PSL_CTS_MODE_BIT(offset); |
| } |
| } |
| |
| bool npcx_pinctrl_psl_input_asserted(uint32_t i) |
| { |
| struct glue_reg *const inst_glue = HAL_GLUE_INST(); |
| |
| if (i >= ARRAY_SIZE(psl_in_confs)) { |
| return false; |
| } |
| |
| return IS_BIT_SET(inst_glue->PSL_CTS, |
| NPCX_PSL_CTS_EVENT_BIT(psl_in_confs[i].offset)); |
| } |
| |
| void npcx_pinctrl_psl_input_configure(void) |
| { |
| /* Configure detection type of PSL input pads */ |
| for (int i = 0; i < ARRAY_SIZE(psl_in_confs); i++) { |
| /* Detection polarity select */ |
| npcx_pinctrl_alt_sel(&psl_in_confs[i].polarity, |
| (psl_in_confs[i].flag & NPCX_PSL_ACTIVE_HIGH) != 0); |
| /* Detection mode select */ |
| npcx_pinctrl_psl_detect_mode_sel(psl_in_confs[i].offset, |
| (psl_in_confs[i].flag & NPCX_PSL_MODE_EDGE) != 0); |
| } |
| |
| /* Configure pin-mux for all PSL input pads from GPIO to PSL */ |
| for (int i = 0; i < ARRAY_SIZE(psl_in_confs); i++) { |
| npcx_pinctrl_alt_sel(&psl_in_confs[i].pinctrl, 1); |
| } |
| } |
| #endif |
| |
| void npcx_host_interface_sel(enum npcx_hif_type hif_type) |
| { |
| struct scfg_reg *inst_scfg = HAL_SFCG_INST(); |
| |
| SET_FIELD(inst_scfg->DEVCNT, NPCX_DEVCNT_HIF_TYP_SEL_FIELD, hif_type); |
| } |
| |
| /* Pin-control driver registration */ |
| static int npcx_scfg_init(const struct device *dev) |
| { |
| struct scfg_reg *inst_scfg = HAL_SFCG_INST(); |
| |
| /* |
| * Set bit 7 of DEVCNT again for npcx7 series. Please see Errata |
| * for more information. It will be fixed in next chip. |
| */ |
| if (IS_ENABLED(CONFIG_SOC_SERIES_NPCX7)) |
| inst_scfg->DEVCNT |= BIT(7); |
| |
| /* Change all pads whose default functionality isn't IO to GPIO */ |
| npcx_pinctrl_mux_configure(def_alts, ARRAY_SIZE(def_alts), 0); |
| |
| /* Configure default low-voltage pads */ |
| npcx_lvol_pads_configure(); |
| |
| return 0; |
| } |
| |
| SYS_INIT(npcx_scfg_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); |