gpio: mchp_xec: fix glitch setting pin to output

A GPIO's parallel output bit in the parallel output
registers is read-only until the AOD bit is set to 1
in the pin's control registers. The proper sequence to
preset the state of an output pin is:
Configure pin as input with AOD=1 in the control register
Set pin state in the parallel output register
Set direction to output in the pin's control register.

Signed-off-by: Scott Worley <scott.worley@microchip.com>
This commit is contained in:
Scott Worley 2020-10-14 16:10:16 -04:00 committed by Anas Nashif
commit 03e510d68b

View file

@ -44,6 +44,17 @@ struct gpio_xec_config {
uint32_t flags;
};
/*
* notes: The GPIO parallel output bits are read-only until the
* Alternate-Output-Disable (AOD) bit is set in the pin's control
* register. To preload a parallel output value to prevent certain
* classes of glitching for output pins we must:
* Set GPIO control AOD=1 with the pin direction set to input.
* Program the new pin value in the respective GPIO parallel output
* register.
* Program other GPIO control bits except direction.
* Last step set the GPIO control register direction bit to output.
*/
static int gpio_xec_configure(const struct device *dev,
gpio_pin_t pin, gpio_flags_t flags)
{
@ -66,18 +77,12 @@ static int gpio_xec_configure(const struct device *dev,
/* The flags contain options that require touching registers in the
* PCRs for a given GPIO. There are no GPIO modules in Microchip SOCs!
*
* Start with the GPIO module and set up the pin direction register.
* 0 - pin is input, 1 - pin is output
* Keep direction as input until last.
* Clear input pad disable allowing input pad to operate.
*/
mask |= MCHP_GPIO_CTRL_DIR_MASK;
mask |= MCHP_GPIO_CTRL_INPAD_DIS_MASK;
if ((flags & GPIO_OUTPUT) != 0U) {
pcr1 |= MCHP_GPIO_CTRL_DIR_OUTPUT;
} else {
/* GPIO_INPUT */
pcr1 |= MCHP_GPIO_CTRL_DIR_INPUT;
}
/* Figure out the pullup/pulldown configuration and keep it in the
* pcr1 variable
@ -110,7 +115,10 @@ static int gpio_xec_configure(const struct device *dev,
pcr1 |= MCHP_GPIO_CTRL_AOD_DIS;
/* Now write contents of pcr1 variable to the PCR1 register that
* corresponds to the GPIO being configured
* corresponds to the GPIO being configured.
* AOD is 1 and direction is input. HW will allow use to set the
* GPIO parallel output bit for this pin and with the pin direction
* as input no glitch will occur.
*/
current_pcr1 = config->pcr1_base + pin;
*current_pcr1 = (*current_pcr1 & ~mask) | pcr1;
@ -121,6 +129,10 @@ static int gpio_xec_configure(const struct device *dev,
} else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0U) {
*gpio_out_reg &= ~BIT(pin);
}
mask = MCHP_GPIO_CTRL_DIR_MASK;
pcr1 = MCHP_GPIO_CTRL_DIR_OUTPUT;
*current_pcr1 = (*current_pcr1 & ~mask) | pcr1;
}
return 0;