1010#include <zephyr/arch/cpu.h>
1111#include <zephyr/device.h>
1212#include <zephyr/drivers/gpio.h>
13+ #include <zephyr/dt-bindings/gpio/gpio.h>
1314#include <zephyr/dt-bindings/pinctrl/mchp-xec-pinctrl.h>
1415#include <soc.h>
1516#include <zephyr/arch/arm/aarch32/cortex_m/cmsis.h>
@@ -82,102 +83,120 @@ static inline void xec_mask_write32(uintptr_t addr, uint32_t mask, uint32_t val)
8283}
8384
8485/*
85- * notes: The GPIO parallel output bits are read-only until the
86- * Alternate-Output-Disable (AOD) bit is set in the pin's control
87- * register. To preload a parallel output value to prevent certain
88- * classes of glitching for output pins we must:
89- * Set GPIO control AOD=1 with the pin direction set to input.
90- * Program the new pin value in the respective GPIO parallel output
91- * register.
92- * Program other GPIO control bits except direction.
93- * Last step set the GPIO control register direction bit to output.
86+ * NOTE: gpio_flags_t b[15:0] are defined in the dt-binding gpio header.
87+ * b[31:16] are defined in the driver gpio header.
88+ * Hardware only supports push-pull or open-drain.
9489 */
95- static int gpio_xec_configure (const struct device * dev ,
96- gpio_pin_t pin , gpio_flags_t flags )
90+ static int gpio_xec_validate_flags (gpio_flags_t flags )
9791{
98- const struct gpio_xec_config * config = dev -> config ;
99- uintptr_t pcr1_addr = pin_ctrl_addr (dev , pin );
100- uintptr_t pout_addr = pin_parout_addr (dev );
101- uint32_t pcr1 = 0U ;
102- uint32_t mask = 0U ;
103-
104- /* Validate pin number range in terms of current port */
105- if ((valid_ctrl_masks [config -> port_num ] & BIT (pin )) == 0U ) {
106- return - EINVAL ;
92+ if ((flags & (GPIO_SINGLE_ENDED | GPIO_LINE_OPEN_DRAIN ))
93+ == (GPIO_SINGLE_ENDED | GPIO_LINE_OPEN_SOURCE )) {
94+ return - ENOTSUP ;
10795 }
10896
109- /* Don't support "open source" mode */
110- if (((flags & GPIO_SINGLE_ENDED ) != 0U ) &&
111- ((flags & GPIO_LINE_OPEN_DRAIN ) == 0U )) {
112- return - ENOTSUP ;
97+ if ((flags & GPIO_OUTPUT_INIT_LOW ) && (flags & GPIO_OUTPUT_INIT_HIGH )) {
98+ return - EINVAL ;
11399 }
114100
115- /* The flags contain options that require touching registers in the
116- * PCRs for a given GPIO. There are no GPIO modules in Microchip SOCs!
117- * Keep direction as input until last.
118- * Clear input pad disable allowing input pad to operate.
119- * Clear Power gate to allow pads to operate.
120- */
121- mask |= MCHP_GPIO_CTRL_DIR_MASK ;
122- mask |= MCHP_GPIO_CTRL_INPAD_DIS_MASK ;
123- mask |= MCHP_GPIO_CTRL_PWRG_MASK ;
124- pcr1 |= MCHP_GPIO_CTRL_DIR_INPUT ;
101+ return 0 ;
102+ }
125103
126- /* Figure out the pullup/pulldown configuration and keep it in the
127- * pcr1 variable
128- */
129- mask |= MCHP_GPIO_CTRL_PUD_MASK ;
130-
131- if ((flags & GPIO_PULL_UP ) != 0U ) {
132- /* Enable the pull and select the pullup resistor. */
133- pcr1 |= MCHP_GPIO_CTRL_PUD_PU ;
134- } else if ((flags & GPIO_PULL_DOWN ) != 0U ) {
135- /* Enable the pull and select the pulldown resistor */
136- pcr1 |= MCHP_GPIO_CTRL_PUD_PD ;
104+ /*
105+ * Each GPIO pin has two 32-bit control registers. Control 1 configures pin
106+ * features except for drive strength and slew rate in Control 2.
107+ * A pin's input and output state can be read/written from either the Control 1
108+ * register or from corresponding bits in the GPIO parallel input/output registers.
109+ * The parallel input and output registers group 32 pins into each register.
110+ * The GPIO hardware restricts the pin output state to Control 1 or the parallel bit.
111+ * Both output bits reflect each other on read and writes but only one is writable
112+ * selected by the output control select bit in Control 1. In the configuration API
113+ * we use Control 1 to configure all pin features and output state. Before exiting,
114+ * we set the output select for parallel mode enabling writes to the parallel output bit.
115+ */
116+ static int gpio_xec_configure (const struct device * dev ,
117+ gpio_pin_t pin , gpio_flags_t flags )
118+ {
119+ const struct gpio_xec_config * config = dev -> config ;
120+ uintptr_t pcr1_addr = 0u ;
121+ uint32_t pcr1 = 0u , pcr1_new = 0u ;
122+ uint32_t msk = (MCHP_GPIO_CTRL_PWRG_MASK
123+ | MCHP_GPIO_CTRL_BUFT_MASK | MCHP_GPIO_CTRL_DIR_MASK
124+ | MCHP_GPIO_CTRL_AOD_MASK | BIT (MCHP_GPIO_CTRL_POL_POS )
125+ | MCHP_GPIO_CTRL_MUX_MASK | MCHP_GPIO_CTRL_INPAD_DIS_MASK );
126+
127+ if (!(valid_ctrl_masks [config -> port_num ] & BIT (pin ))) {
128+ return - EINVAL ;
137129 }
138130
139- /* Push-pull or open drain */
140- mask |= MCHP_GPIO_CTRL_BUFT_MASK ;
131+ int ret = gpio_xec_validate_flags (flags );
141132
142- if ((flags & GPIO_OPEN_DRAIN ) != 0U ) {
143- /* Open drain */
144- pcr1 |= MCHP_GPIO_CTRL_BUFT_OPENDRAIN ;
145- } else {
146- /* Push-pull */
147- pcr1 |= MCHP_GPIO_CTRL_BUFT_PUSHPULL ;
133+ if (ret ) {
134+ return ret ;
148135 }
149136
150- /* Use GPIO output register to control pin output, instead of
151- * using the control register (=> alternate output disable).
152- */
153- mask |= MCHP_GPIO_CTRL_AOD_MASK ;
154- pcr1 |= MCHP_GPIO_CTRL_AOD_DIS ;
137+ pcr1_addr = pin_ctrl_addr (dev , pin );
138+ pcr1 = sys_read32 (pcr1_addr );
155139
156- /* Make sure disconnected on first control register write */
157140 if (flags == GPIO_DISCONNECTED ) {
158- pcr1 |= MCHP_GPIO_CTRL_PWRG_OFF ;
141+ pcr1 = (pcr1 & ~MCHP_GPIO_CTRL_PWRG_MASK ) | MCHP_GPIO_CTRL_PWRG_OFF ;
142+ sys_write32 (pcr1 , pcr1_addr );
143+ return 0 ;
159144 }
160145
161- /* Now write contents of pcr1 variable to the PCR1 register that
162- * corresponds to the GPIO being configured.
163- * AOD is 1 and direction is input. HW will allow use to set the
164- * GPIO parallel output bit for this pin and with the pin direction
165- * as input no glitch will occur.
166- */
167- xec_mask_write32 (pcr1_addr , mask , pcr1 );
146+ /* final pin state will be powered */
147+ pcr1_new = MCHP_GPIO_CTRL_PWRG_VTR_IO ;
168148
169- if ((flags & GPIO_OUTPUT ) != 0U ) {
170- if ((flags & GPIO_OUTPUT_INIT_HIGH ) != 0U ) {
171- sys_set_bit (pout_addr , pin );
172- } else if ((flags & GPIO_OUTPUT_INIT_LOW ) != 0U ) {
173- sys_clear_bit (pout_addr , pin );
149+ /* always enable input pad */
150+ if (pcr1 & BIT (MCHP_GPIO_CTRL_INPAD_DIS_POS )) {
151+ pcr1 &= ~BIT (MCHP_GPIO_CTRL_INPAD_DIS_POS );
152+ sys_write32 (pcr1 , pcr1_addr );
153+ }
154+
155+ if (flags & GPIO_OUTPUT ) {
156+ pcr1_new |= BIT (MCHP_GPIO_CTRL_DIR_POS );
157+ msk |= BIT (MCHP_GPIO_CTRL_OUTVAL_POS );
158+ if (flags & GPIO_OUTPUT_INIT_HIGH ) {
159+ pcr1_new |= BIT (MCHP_GPIO_CTRL_OUTVAL_POS );
160+ } else if (flags & GPIO_OUTPUT_INIT_LOW ) {
161+ pcr1_new &= ~BIT (MCHP_GPIO_CTRL_OUTVAL_POS );
162+ } else { /* copy current input state to output state */
163+ if ((pcr1 & MCHP_GPIO_CTRL_PWRG_MASK ) == MCHP_GPIO_CTRL_PWRG_OFF ) {
164+ pcr1 &= ~(MCHP_GPIO_CTRL_PWRG_MASK );
165+ pcr1 |= MCHP_GPIO_CTRL_PWRG_VTR_IO ;
166+ sys_write32 (pcr1 , pcr1_addr );
167+ }
168+ pcr1 = sys_read32 (pcr1_addr );
169+ if (pcr1 & BIT (MCHP_GPIO_CTRL_INPAD_VAL_POS )) {
170+ pcr1_new |= BIT (MCHP_GPIO_CTRL_OUTVAL_POS );
171+ } else {
172+ pcr1_new &= ~BIT (MCHP_GPIO_CTRL_OUTVAL_POS );
173+ }
174174 }
175+ if (flags & GPIO_LINE_OPEN_DRAIN ) {
176+ pcr1_new |= BIT (MCHP_GPIO_CTRL_BUFT_POS );
177+ }
178+ }
175179
176- mask = MCHP_GPIO_CTRL_DIR_MASK ;
177- pcr1 = MCHP_GPIO_CTRL_DIR_OUTPUT ;
178- xec_mask_write32 (pcr1_addr , mask , pcr1 );
180+ if (flags & (GPIO_PULL_UP | GPIO_PULL_DOWN )) {
181+ msk |= MCHP_GPIO_CTRL_PUD_MASK ;
182+ /* both bits specifies repeater mode */
183+ if (flags & GPIO_PULL_UP ) {
184+ pcr1_new |= MCHP_GPIO_CTRL_PUD_PU ;
185+ }
186+ if (flags & GPIO_PULL_DOWN ) {
187+ pcr1_new |= MCHP_GPIO_CTRL_PUD_PD ;
188+ }
179189 }
180190
191+ /*
192+ * Problem, if pin was power gated off we can't read input.
193+ * How to turn on pin to read input but not glitch it?
194+ */
195+ pcr1 = (pcr1 & ~msk ) | (pcr1_new & msk );
196+ sys_write32 (pcr1 , pcr1_addr ); /* configuration. may generate a single edge */
197+ /* Control output bit becomes read-only and parallel out register bit becomes r/w */
198+ sys_write32 (pcr1 | BIT (MCHP_GPIO_CTRL_AOD_POS ), pcr1_addr );
199+
181200 return 0 ;
182201}
183202
@@ -257,6 +276,8 @@ static int gpio_xec_pin_interrupt_configure(const struct device *dev,
257276
258277 /* pin configuration matches requested detection mode? */
259278 pcr1 = sys_read32 (pcr1_addr );
279+ /* HW detects interrupt on input. Make sure input pad disable is cleared */
280+ pcr1 &= ~BIT (MCHP_GPIO_CTRL_INPAD_DIS_POS );
260281
261282 if ((pcr1 & MCHP_GPIO_CTRL_IDET_MASK ) == pcr1_req ) {
262283 gpio_xec_intr_en (pin , mode , config -> girq_id );
@@ -354,13 +375,95 @@ static int gpio_xec_manage_callback(const struct device *dev,
354375 return 0 ;
355376}
356377
378+ #ifdef CONFIG_GPIO_GET_DIRECTION
379+ static int gpio_xec_get_direction (const struct device * port , gpio_port_pins_t map ,
380+ gpio_port_pins_t * inputs , gpio_port_pins_t * outputs )
381+ {
382+ if (!port ) {
383+ return - EINVAL ;
384+ }
385+
386+ const struct gpio_xec_config * config = port -> config ;
387+ uint32_t valid_msk = valid_ctrl_masks [config -> port_num ];
388+
389+ * inputs = 0u ;
390+ * outputs = 0u ;
391+ for (uint8_t pin = 0 ; pin < 32 ; pin ++ ) {
392+ if (!map ) {
393+ break ;
394+ }
395+ if ((map & BIT (pin )) && (valid_msk & BIT (pin ))) {
396+ uintptr_t pcr1_addr = pin_ctrl_addr (port , pin );
397+ uint32_t pcr1 = sys_read32 (pcr1_addr );
398+
399+ if (!((pcr1 & MCHP_GPIO_CTRL_PWRG_MASK ) == MCHP_GPIO_CTRL_PWRG_OFF )) {
400+ if (outputs && (pcr1 & BIT (MCHP_GPIO_CTRL_DIR_POS ))) {
401+ * outputs |= BIT (pin );
402+ } else if (inputs && !(pcr1 & BIT (MCHP_GPIO_CTRL_INPAD_DIS_POS ))) {
403+ * inputs |= BIT (pin );
404+ }
405+ }
406+
407+ map &= ~BIT (pin );
408+ }
409+ }
410+
411+ return 0 ;
412+ }
413+ #endif
414+
415+ #ifdef CONFIG_GPIO_GET_CONFIG
416+ int gpio_xec_get_config (const struct device * port , gpio_pin_t pin , gpio_flags_t * flags )
417+ {
418+ if (!port || !flags ) {
419+ return - EINVAL ;
420+ }
421+
422+ const struct gpio_xec_config * config = port -> config ;
423+ uint32_t valid_msk = valid_ctrl_masks [config -> port_num ];
424+
425+ if (!(valid_msk & BIT (pin ))) {
426+ return - EINVAL ;
427+ /* Or should we set *flags = GPIO_DISCONNECTED and return success? */
428+ }
429+
430+ uintptr_t pcr1_addr = pin_ctrl_addr (port , pin );
431+ uint32_t pcr1 = sys_read32 (pcr1_addr );
432+ uint32_t pin_flags = 0u ;
433+
434+ if (pcr1 & BIT (MCHP_GPIO_CTRL_DIR_POS )) {
435+ pin_flags |= GPIO_OUTPUT ;
436+ if (pcr1 & BIT (MCHP_GPIO_CTRL_OUTVAL_POS )) {
437+ pin_flags |= GPIO_OUTPUT_INIT_HIGH ;
438+ } else {
439+ pin_flags |= GPIO_OUTPUT_INIT_LOW ;
440+ }
441+
442+ if (pcr1 & BIT (MCHP_GPIO_CTRL_BUFT_POS )) {
443+ pin_flags |= GPIO_OPEN_DRAIN ;
444+ }
445+ } else if (!(pcr1 & BIT (MCHP_GPIO_CTRL_INPAD_DIS_POS ))) {
446+ pin_flags |= GPIO_INPUT ;
447+ }
448+
449+ if (pin_flags ) {
450+ * flags = pin_flags ;
451+ } else {
452+ * flags = GPIO_DISCONNECTED ;
453+ }
454+
455+ return 0 ;
456+ }
457+ #endif
458+
357459static void gpio_gpio_xec_port_isr (const struct device * dev )
358460{
359461 const struct gpio_xec_config * config = dev -> config ;
360462 struct gpio_xec_data * data = dev -> data ;
361463 uint32_t girq_result ;
362464
363- /* Figure out which interrupts have been triggered from the EC
465+ /*
466+ * Figure out which interrupts have been triggered from the EC
364467 * aggregator result register
365468 */
366469 girq_result = mchp_soc_ecia_girq_result (config -> girq_id );
@@ -381,6 +484,12 @@ static const struct gpio_driver_api gpio_xec_driver_api = {
381484 .port_toggle_bits = gpio_xec_port_toggle_bits ,
382485 .pin_interrupt_configure = gpio_xec_pin_interrupt_configure ,
383486 .manage_callback = gpio_xec_manage_callback ,
487+ #ifdef CONFIG_GPIO_GET_DIRECTION
488+ .port_get_direction = gpio_xec_get_direction ,
489+ #endif
490+ #ifdef CONFIG_GPIO_GET_CONFIG
491+ .pin_get_config = gpio_xec_get_config ,
492+ #endif
384493};
385494
386495#define XEC_GPIO_PORT_FLAGS (n ) \
0 commit comments