12
12
#include <zephyr/drivers/pinctrl.h>
13
13
#include <soc.h>
14
14
15
- /* Microchip XEC: each GPIO pin has two 32-bit control register.
15
+ /*
16
+ * Microchip XEC: each GPIO pin has two 32-bit control register.
16
17
* The first 32-bit register contains all pin features except
17
18
* slew rate and driver strength in the second control register.
18
19
* We compute the register index from the beginning of the GPIO
19
20
* control address space which is the same range of the PINCTRL
20
- * parent node.
21
+ * parent node. A zero value in the PINCTRL pinmux field means
22
+ * do not touch.
21
23
*/
22
-
23
24
static void config_drive_slew (struct gpio_regs * const regs , uint32_t idx , uint32_t conf )
24
25
{
25
- uint32_t slew = conf & ( MCHP_XEC_OSPEEDR_MASK << MCHP_XEC_OSPEEDR_POS ) ;
26
- uint32_t drvstr = conf & ( MCHP_XEC_ODRVSTR_MASK << MCHP_XEC_ODRVSTR_POS ) ;
27
- uint32_t val = 0 ;
28
- uint32_t mask = 0 ;
29
-
30
- if ( slew != MCHP_XEC_OSPEEDR_NO_CHG ) {
31
- mask |= MCHP_GPIO_CTRL2_SLEW_MASK ;
32
- if (slew == MCHP_XEC_OSPEEDR_FAST ) {
26
+ uint32_t slew = ( conf >> MCHP_XEC_SLEW_RATE_POS ) & MCHP_XEC_SLEW_RATE_MSK0 ;
27
+ uint32_t drvstr = ( conf >> MCHP_XEC_DRV_STR_POS ) & MCHP_XEC_DRV_STR_MSK0 ;
28
+ uint32_t msk = 0 , val = 0 ;
29
+
30
+ if ( slew ) {
31
+ msk |= MCHP_GPIO_CTRL2_SLEW_MASK ;
32
+ /* slow slew value is 0 */
33
+ if (slew == MCHP_XEC_SLEW_RATE_FAST0 ) {
33
34
val |= MCHP_GPIO_CTRL2_SLEW_FAST ;
34
35
}
35
36
}
36
- if (drvstr != MCHP_XEC_ODRVSTR_NO_CHG ) {
37
- mask |= MCHP_GPIO_CTRL2_DRV_STR_MASK ;
38
- val |= (drvstr << MCHP_GPIO_CTRL2_DRV_STR_POS );
37
+
38
+ if (drvstr ) {
39
+ msk |= MCHP_GPIO_CTRL2_DRV_STR_MASK ;
40
+ /* drive strength values are 0 based */
41
+ val |= ((drvstr - 1u ) << MCHP_GPIO_CTRL2_DRV_STR_POS );
39
42
}
40
43
41
- if (!mask ) {
44
+ if (!msk ) {
42
45
return ;
43
46
}
44
47
45
- regs -> CTRL2 [idx ] = (regs -> CTRL2 [idx ] & ~mask ) | (val & mask );
48
+ regs -> CTRL2 [idx ] = (regs -> CTRL2 [idx ] & ~msk ) | (val & msk );
46
49
}
47
50
48
- /* Configure pin by writing GPIO Control and Control2 registers.
49
- * NOTE: Disable alternate output feature since the GPIO driver does.
50
- * While alternate output is enabled (default state of pin) HW does not
51
- * ignores writes to the parallel output bit for the pin. To set parallel
52
- * output value we must keep pin direction as input, set alternate output
53
- * disable, program pin value to parallel output bit, and then disable
54
- * alternate output mode.
51
+ /*
52
+ * Internal pulls feature:
53
+ * None, weak pull-up, weak pull-down, or repeater mode (both pulls enabled).
54
+ * We do not touch this field unless one or more of the DT booleans are set.
55
+ * If the no-bias boolean is set then disable internal pulls.
56
+ * If pull up and/or down is set enable the respective pull or both for what
57
+ * MCHP calls repeater(keeper) mode.
58
+ */
59
+ static uint32_t prog_pud (uint32_t pcr1 , uint32_t conf )
60
+ {
61
+ if (conf & BIT (MCHP_XEC_NO_PUD_POS )) {
62
+ pcr1 &= ~(MCHP_GPIO_CTRL_PUD_MASK );
63
+ pcr1 |= MCHP_GPIO_CTRL_PUD_NONE ;
64
+ return pcr1 ;
65
+ }
66
+
67
+ if (conf & (BIT (MCHP_XEC_PU_POS ) | BIT (MCHP_XEC_PD_POS ))) {
68
+ pcr1 &= ~(MCHP_GPIO_CTRL_PUD_MASK );
69
+ if (conf & BIT (MCHP_XEC_PU_POS )) {
70
+ pcr1 |= MCHP_GPIO_CTRL_PUD_PU ;
71
+ }
72
+ if (conf & BIT (MCHP_XEC_PD_POS )) {
73
+ pcr1 |= MCHP_GPIO_CTRL_PUD_PD ;
74
+ }
75
+ }
76
+
77
+ return pcr1 ;
78
+ }
79
+
80
+ /*
81
+ * DT enable booleans take precedence over disable booleans.
82
+ * We initially clear alternate output disable allowing us to set output state
83
+ * in the control register. Hardware sets output state bit in both control and
84
+ * parallel output register bits. Alternate output disable only controls which
85
+ * register bit is writable by the EC. We also clear the input pad disable
86
+ * bit because we need the input pin state and we don't know if the requested
87
+ * alternate function is input or bi-directional.
88
+ * Note 1: hardware allows input and output to be simultaneously enabled.
89
+ * Note 2: hardware interrupt detection is only on the input path.
55
90
*/
56
91
static int xec_config_pin (uint32_t portpin , uint32_t conf , uint32_t altf )
57
92
{
58
93
struct gpio_regs * const regs = (struct gpio_regs * const )DT_INST_REG_ADDR (0 );
59
94
uint32_t port = MCHP_XEC_PINMUX_PORT (portpin );
60
95
uint32_t pin = (uint32_t )MCHP_XEC_PINMUX_PIN (portpin );
61
- uint32_t msk = MCHP_GPIO_CTRL_AOD_MASK ;
62
- uint32_t val = MCHP_GPIO_CTRL_AOD_DIS ;
63
- uint32_t idx = 0u ;
64
- uint32_t temp = 0u ;
96
+ uint32_t idx = 0u , pcr1 = 0u ;
65
97
66
98
if (port >= NUM_MCHP_GPIO_PORTS ) {
67
99
return - EINVAL ;
@@ -72,81 +104,84 @@ static int xec_config_pin(uint32_t portpin, uint32_t conf, uint32_t altf)
72
104
73
105
config_drive_slew (regs , idx , conf );
74
106
75
- /* default input pad enabled, buffer type push-pull, no internal pulls,
76
- * and invert polarity normal.
77
- */
78
- msk |= (BIT (MCHP_GPIO_CTRL_INPAD_DIS_POS ) | MCHP_GPIO_CTRL_BUFT_MASK |
79
- MCHP_GPIO_CTRL_PUD_MASK | MCHP_GPIO_CTRL_MUX_MASK
80
- | BIT (MCHP_GPIO_CTRL_POL_POS ));
107
+ /* Clear alternate output disable and input pad disable */
108
+ regs -> CTRL [idx ] &= ~(BIT (MCHP_GPIO_CTRL_AOD_POS ) | BIT (MCHP_GPIO_CTRL_INPAD_DIS_POS ));
109
+ pcr1 = regs -> CTRL [idx ]; /* current configuration including pin input state */
110
+ pcr1 = regs -> CTRL [idx ]; /* read multiple times to allow propagation from pad */
111
+ pcr1 = regs -> CTRL [idx ]; /* Is this necessary? */
81
112
82
- if (conf & BIT (MCHP_XEC_PIN_LOW_POWER_POS )) {
83
- msk |= MCHP_GPIO_CTRL_PWRG_MASK ;
84
- val |= MCHP_GPIO_CTRL_PWRG_OFF ;
85
- }
113
+ pcr1 = prog_pud (pcr1 , conf );
86
114
87
- temp = (conf & MCHP_XEC_PUPDR_MASK ) >> MCHP_XEC_PUPDR_POS ;
88
- switch (temp ) {
89
- case MCHP_XEC_PULL_UP :
90
- val |= MCHP_GPIO_CTRL_PUD_PU ;
91
- break ;
92
- case MCHP_XEC_PULL_DOWN :
93
- val |= MCHP_GPIO_CTRL_PUD_PD ;
94
- break ;
95
- case MCHP_XEC_REPEATER :
96
- val |= MCHP_GPIO_CTRL_PUD_RPT ;
97
- break ;
98
- default :
99
- val |= MCHP_GPIO_CTRL_PUD_NONE ;
100
- break ;
115
+ /* Touch output enable. We always enable input */
116
+ if (conf & BIT (MCHP_XEC_OUT_DIS_POS )) {
117
+ pcr1 &= ~(MCHP_GPIO_CTRL_DIR_OUTPUT );
118
+ }
119
+ if (conf & BIT (MCHP_XEC_OUT_EN_POS )) {
120
+ pcr1 |= MCHP_GPIO_CTRL_DIR_OUTPUT ;
101
121
}
102
122
103
- if ((conf >> MCHP_XEC_OTYPER_POS ) & MCHP_XEC_OTYPER_MASK ) {
104
- val |= MCHP_GPIO_CTRL_BUFT_OPENDRAIN ;
123
+ /* Touch output state? Bit can be set even if the direction is input only */
124
+ if (conf & BIT (MCHP_XEC_OUT_LO_POS )) {
125
+ pcr1 &= ~BIT (MCHP_GPIO_CTRL_OUTVAL_POS );
126
+ }
127
+ if (conf & BIT (MCHP_XEC_OUT_HI_POS )) {
128
+ pcr1 |= BIT (MCHP_GPIO_CTRL_OUTVAL_POS );
105
129
}
106
130
107
- if (conf & MCHP_XEC_FUNC_INV_MSK ) {
108
- val |= BIT (MCHP_GPIO_CTRL_POL_POS );
131
+ /* Touch output buffer type? */
132
+ if (conf & BIT (MCHP_XEC_PUSH_PULL_POS )) {
133
+ pcr1 &= ~(MCHP_GPIO_CTRL_BUFT_OPENDRAIN );
134
+ }
135
+ if (conf & BIT (MCHP_XEC_OPEN_DRAIN_POS )) {
136
+ pcr1 |= MCHP_GPIO_CTRL_BUFT_OPENDRAIN ;
109
137
}
110
138
111
- regs -> CTRL [idx ] = (regs -> CTRL [idx ] & ~msk ) | val ;
139
+ /* Always touch power gate */
140
+ pcr1 &= ~MCHP_GPIO_CTRL_PWRG_MASK ;
141
+ if (conf & BIT (MCHP_XEC_PIN_LOW_POWER_POS )) {
142
+ pcr1 |= MCHP_GPIO_CTRL_PWRG_OFF ;
143
+ } else {
144
+ pcr1 |= MCHP_GPIO_CTRL_PWRG_VTR_IO ;
145
+ }
112
146
113
- temp = (conf >> MCHP_XEC_OVAL_POS ) & MCHP_XEC_OVAL_MASK ;
114
- if (temp ) {
115
- if (temp == MCHP_XEC_OVAL_DRV_HIGH ) {
116
- regs -> PAROUT [port ] |= BIT (pin );
117
- } else {
118
- regs -> PAROUT [port ] &= ~BIT (pin );
119
- }
147
+ /* Always touch MUX (alternate function) */
148
+ pcr1 &= ~MCHP_GPIO_CTRL_MUX_MASK ;
149
+ pcr1 |= (uint32_t )((altf & MCHP_GPIO_CTRL_MUX_MASK0 ) << MCHP_GPIO_CTRL_MUX_POS );
120
150
121
- regs -> CTRL [idx ] |= MCHP_GPIO_CTRL_DIR_OUTPUT ;
151
+ /* Always touch invert of alternate function. Need another bit to avoid touching */
152
+ if (conf & BIT (MCHP_XEC_FUNC_INV_POS )) {
153
+ pcr1 |= BIT (MCHP_GPIO_CTRL_POL_POS );
154
+ } else {
155
+ pcr1 &= ~BIT (MCHP_GPIO_CTRL_POL_POS );
122
156
}
123
157
124
- val = (uint32_t )((altf & MCHP_GPIO_CTRL_MUX_MASK0 ) << MCHP_GPIO_CTRL_MUX_POS );
125
- regs -> CTRL [idx ] |= val ;
158
+ /* output state set in control & parallel regs */
159
+ regs -> CTRL [idx ] = pcr1 ;
160
+ /* make output state in control read-only in control and read-write in parallel reg */
161
+ regs -> CTRL [idx ] = pcr1 | BIT (MCHP_GPIO_CTRL_AOD_POS );
126
162
127
163
return 0 ;
128
164
}
129
165
130
166
int pinctrl_configure_pins (const pinctrl_soc_pin_t * pins , uint8_t pin_cnt ,
131
167
uintptr_t reg )
132
168
{
133
- uint32_t portpin , mux , cfg , func ;
169
+ uint32_t portpin , pinmux , func ;
134
170
int ret ;
135
171
136
172
ARG_UNUSED (reg );
137
173
138
174
for (uint8_t i = 0U ; i < pin_cnt ; i ++ ) {
139
- mux = pins [i ]. pinmux ;
175
+ pinmux = pins [i ];
140
176
141
- func = MCHP_XEC_PINMUX_FUNC (mux );
177
+ func = MCHP_XEC_PINMUX_FUNC (pinmux );
142
178
if (func >= MCHP_AFMAX ) {
143
179
return - EINVAL ;
144
180
}
145
181
146
- cfg = pins [i ].pincfg ;
147
- portpin = MEC_XEC_PINMUX_PORT_PIN (mux );
182
+ portpin = MEC_XEC_PINMUX_PORT_PIN (pinmux );
148
183
149
- ret = xec_config_pin (portpin , cfg , func );
184
+ ret = xec_config_pin (portpin , pinmux , func );
150
185
if (ret < 0 ) {
151
186
return ret ;
152
187
}
0 commit comments