1 /*
2 * Copyright (c) 2022 Nuvoton Technology Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <assert.h>
7 #include <zephyr/drivers/pinctrl.h>
8 #include <soc.h>
9
10 /* Driver config */
11 struct npcx_pinctrl_config {
12 /* Device base address used for pinctrl driver */
13 uintptr_t base_scfg;
14 uintptr_t base_glue;
15 };
16
17 static const struct npcx_pinctrl_config npcx_pinctrl_cfg = {
18 .base_scfg = NPCX_SCFG_REG_ADDR,
19 .base_glue = NPCX_GLUE_REG_ADDR,
20 };
21
22 /* PWM pinctrl config */
23 struct npcx_pwm_pinctrl_config {
24 uintptr_t base;
25 int channel;
26 };
27
28 #define NPCX_PWM_PINCTRL_CFG_INIT(node_id) \
29 { \
30 .base = DT_REG_ADDR(node_id), \
31 .channel = DT_PROP(node_id, pwm_channel), \
32 },
33
34 static const struct npcx_pwm_pinctrl_config pwm_pinctrl_cfg[] = {
35 DT_FOREACH_STATUS_OKAY(nuvoton_npcx_pwm, NPCX_PWM_PINCTRL_CFG_INIT)
36 };
37
38 /* Pin-control local functions for peripheral devices */
npcx_periph_pinmux_has_lock(int group)39 static bool npcx_periph_pinmux_has_lock(int group)
40 {
41 if ((BIT(group) & NPCX_DEVALT_LK_GROUP_MASK) != 0) {
42 return true;
43 }
44
45 return false;
46 }
47
npcx_periph_pinmux_configure(const struct npcx_periph * alt,bool is_alternate,bool is_locked)48 static void npcx_periph_pinmux_configure(const struct npcx_periph *alt, bool is_alternate,
49 bool is_locked)
50 {
51 const uintptr_t scfg_base = npcx_pinctrl_cfg.base_scfg;
52 uint8_t alt_mask = BIT(alt->bit);
53
54 /*
55 * is_alternate == 0 means select GPIO, otherwise Alternate Func.
56 * inverted == 0:
57 * Set devalt bit to select Alternate Func.
58 * inverted == 1:
59 * Clear devalt bit to select Alternate Func.
60 */
61 if (is_alternate != alt->inverted) {
62 NPCX_DEVALT(scfg_base, alt->group) |= alt_mask;
63 } else {
64 NPCX_DEVALT(scfg_base, alt->group) &= ~alt_mask;
65 }
66
67 if (is_locked && npcx_periph_pinmux_has_lock(alt->group)) {
68 NPCX_DEVALT_LK(scfg_base, alt->group) |= alt_mask;
69 }
70 }
71
npcx_periph_pupd_configure(const struct npcx_periph * pupd,enum npcx_io_bias_type type)72 static void npcx_periph_pupd_configure(const struct npcx_periph *pupd,
73 enum npcx_io_bias_type type)
74 {
75 const uintptr_t scfg_base = npcx_pinctrl_cfg.base_scfg;
76
77 if (type == NPCX_BIAS_TYPE_NONE) {
78 NPCX_PUPD_EN(scfg_base, pupd->group) &= ~BIT(pupd->bit);
79 } else {
80 NPCX_PUPD_EN(scfg_base, pupd->group) |= BIT(pupd->bit);
81 }
82 }
83
npcx_periph_pwm_drive_mode_configure(const struct npcx_periph * periph,bool is_od)84 static void npcx_periph_pwm_drive_mode_configure(const struct npcx_periph *periph,
85 bool is_od)
86 {
87 uintptr_t reg = 0;
88
89 /* Find selected pwm module which enables open-drain prop. */
90 for (int i = 0; i < ARRAY_SIZE(pwm_pinctrl_cfg); i++) {
91 if (periph->group == pwm_pinctrl_cfg[i].channel) {
92 reg = pwm_pinctrl_cfg[i].base;
93 break;
94 }
95 }
96
97 if (reg == 0) {
98 return;
99 }
100
101 struct pwm_reg *const inst = (struct pwm_reg *)(reg);
102
103 if (is_od) {
104 inst->PWMCTLEX |= BIT(NPCX_PWMCTLEX_OD_OUT);
105 } else {
106 inst->PWMCTLEX &= ~BIT(NPCX_PWMCTLEX_OD_OUT);
107 }
108 }
109
npcx_periph_configure(const pinctrl_soc_pin_t * pin,uintptr_t reg)110 static void npcx_periph_configure(const pinctrl_soc_pin_t *pin, uintptr_t reg)
111 {
112 if (pin->cfg.periph.type == NPCX_PINCTRL_TYPE_PERIPH_PINMUX) {
113 /* Configure peripheral device's pinmux functionality */
114 npcx_periph_pinmux_configure(&pin->cfg.periph,
115 !pin->flags.pinmux_gpio,
116 pin->flags.pinmux_lock);
117 } else if (pin->cfg.periph.type == NPCX_PINCTRL_TYPE_PERIPH_PUPD) {
118 /* Configure peripheral device's internal PU/PD */
119 npcx_periph_pupd_configure(&pin->cfg.periph,
120 pin->flags.io_bias_type);
121 } else if (pin->cfg.periph.type == NPCX_PINCTRL_TYPE_PERIPH_DRIVE) {
122 /* Configure peripheral device's drive mode. (Only PWM pads support it) */
123 npcx_periph_pwm_drive_mode_configure(&pin->cfg.periph,
124 pin->flags.io_drive_type == NPCX_DRIVE_TYPE_OPEN_DRAIN);
125 }
126 }
127
npcx_psl_input_detection_configure(const pinctrl_soc_pin_t * pin)128 static void npcx_psl_input_detection_configure(const pinctrl_soc_pin_t *pin)
129 {
130 struct glue_reg *inst_glue = (struct glue_reg *)(npcx_pinctrl_cfg.base_glue);
131 const uintptr_t scfg_base = npcx_pinctrl_cfg.base_scfg;
132 const struct npcx_psl_input *psl_in = (const struct npcx_psl_input *)&pin->cfg.psl_in;
133
134 /* Configure detection polarity of PSL input pads */
135 if (pin->flags.psl_in_polarity == NPCX_PSL_IN_POL_HIGH) {
136 NPCX_DEVALT(scfg_base, psl_in->pol_group) |= BIT(psl_in->pol_bit);
137 } else {
138 NPCX_DEVALT(scfg_base, psl_in->pol_group) &= ~BIT(psl_in->pol_bit);
139 }
140
141 /* Configure detection mode of PSL input pads */
142 if (pin->flags.psl_in_mode == NPCX_PSL_IN_MODE_EDGE) {
143 inst_glue->PSL_CTS |= NPCX_PSL_CTS_MODE_BIT(psl_in->port);
144 } else {
145 inst_glue->PSL_CTS &= ~NPCX_PSL_CTS_MODE_BIT(psl_in->port);
146 }
147 }
148
npcx_device_control_configure(const pinctrl_soc_pin_t * pin)149 static void npcx_device_control_configure(const pinctrl_soc_pin_t *pin)
150 {
151 const struct npcx_dev_ctl *ctrl = (const struct npcx_dev_ctl *)&pin->cfg.dev_ctl;
152 const uintptr_t scfg_base = npcx_pinctrl_cfg.base_scfg;
153
154 SET_FIELD(NPCX_DEV_CTL(scfg_base, ctrl->offest),
155 FIELD(ctrl->field_offset, ctrl->field_size),
156 ctrl->field_value);
157 }
158
159 /* Pinctrl API implementation */
pinctrl_configure_pins(const pinctrl_soc_pin_t * pins,uint8_t pin_cnt,uintptr_t reg)160 int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt,
161 uintptr_t reg)
162 {
163 ARG_UNUSED(reg);
164
165 /* Configure all peripheral devices' properties here. */
166 for (uint8_t i = 0; i < pin_cnt; i++) {
167 if (pins[i].flags.type == NPCX_PINCTRL_TYPE_PERIPH) {
168 /* Configure peripheral device's pinmux functionality */
169 npcx_periph_configure(&pins[i], reg);
170 } else if (pins[i].flags.type == NPCX_PINCTRL_TYPE_DEVICE_CTRL) {
171 /* Configure device's io characteristics */
172 npcx_device_control_configure(&pins[i]);
173 } else if (pins[i].flags.type == NPCX_PINCTRL_TYPE_PSL_IN) {
174 /* Configure SPL input's detection mode */
175 npcx_psl_input_detection_configure(&pins[i]);
176 } else {
177 return -ENOTSUP;
178 }
179 }
180
181 return 0;
182 }
183