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
parent fef7879583
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;
}
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;
@ -311,7 +323,7 @@ static int gpio_xec_port000_036_init(const struct device *dev);
static const struct gpio_xec_config gpio_xec_port000_036_config = {
.common = {
.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_NODE(
DT_NODELABEL(gpio_000_036)),
DT_NODELABEL(gpio_000_036)),
},
.pcr1_base = (uint32_t *) DT_REG_ADDR(DT_NODELABEL(gpio_000_036)),
.port_num = MCHP_GPIO_000_036,
@ -326,11 +338,11 @@ static const struct gpio_xec_config gpio_xec_port000_036_config = {
static struct gpio_xec_data gpio_xec_port000_036_data;
DEVICE_AND_API_INIT(gpio_xec_port000_036,
DT_LABEL(DT_NODELABEL(gpio_000_036)),
gpio_xec_port000_036_init,
&gpio_xec_port000_036_data, &gpio_xec_port000_036_config,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
&gpio_xec_driver_api);
DT_LABEL(DT_NODELABEL(gpio_000_036)),
gpio_xec_port000_036_init,
&gpio_xec_port000_036_data, &gpio_xec_port000_036_config,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
&gpio_xec_driver_api);
static int gpio_xec_port000_036_init(const struct device *dev)
{
@ -341,8 +353,8 @@ static int gpio_xec_port000_036_init(const struct device *dev)
MCHP_GIRQ_BLK_SETEN(config->girq_id);
IRQ_CONNECT(DT_IRQ(DT_NODELABEL(gpio_000_036), irq),
DT_IRQ(DT_NODELABEL(gpio_000_036), priority),
gpio_gpio_xec_port_isr, DEVICE_GET(gpio_xec_port000_036), 0U);
DT_IRQ(DT_NODELABEL(gpio_000_036), priority),
gpio_gpio_xec_port_isr, DEVICE_GET(gpio_xec_port000_036), 0U);
irq_enable(DT_IRQ(DT_NODELABEL(gpio_000_036), irq));
#endif
@ -356,7 +368,7 @@ static int gpio_xec_port040_076_init(const struct device *dev);
static const struct gpio_xec_config gpio_xec_port040_076_config = {
.common = {
.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_NODE(
DT_NODELABEL(gpio_040_076)),
DT_NODELABEL(gpio_040_076)),
},
.pcr1_base = (uint32_t *) DT_REG_ADDR(DT_NODELABEL(gpio_040_076)),
.port_num = MCHP_GPIO_040_076,
@ -371,11 +383,11 @@ static const struct gpio_xec_config gpio_xec_port040_076_config = {
static struct gpio_xec_data gpio_xec_port040_076_data;
DEVICE_AND_API_INIT(gpio_xec_port040_076,
DT_LABEL(DT_NODELABEL(gpio_040_076)),
gpio_xec_port040_076_init,
&gpio_xec_port040_076_data, &gpio_xec_port040_076_config,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
&gpio_xec_driver_api);
DT_LABEL(DT_NODELABEL(gpio_040_076)),
gpio_xec_port040_076_init,
&gpio_xec_port040_076_data, &gpio_xec_port040_076_config,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
&gpio_xec_driver_api);
static int gpio_xec_port040_076_init(const struct device *dev)
{
@ -386,8 +398,8 @@ static int gpio_xec_port040_076_init(const struct device *dev)
MCHP_GIRQ_BLK_SETEN(config->girq_id);
IRQ_CONNECT(DT_IRQ(DT_NODELABEL(gpio_040_076), irq),
DT_IRQ(DT_NODELABEL(gpio_040_076), priority),
gpio_gpio_xec_port_isr, DEVICE_GET(gpio_xec_port040_076), 0U);
DT_IRQ(DT_NODELABEL(gpio_040_076), priority),
gpio_gpio_xec_port_isr, DEVICE_GET(gpio_xec_port040_076), 0U);
irq_enable(DT_IRQ(DT_NODELABEL(gpio_040_076), irq));
#endif
@ -401,7 +413,7 @@ static int gpio_xec_port100_136_init(const struct device *dev);
static const struct gpio_xec_config gpio_xec_port100_136_config = {
.common = {
.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_NODE(
DT_NODELABEL(gpio_100_136)),
DT_NODELABEL(gpio_100_136)),
},
.pcr1_base = (uint32_t *) DT_REG_ADDR(DT_NODELABEL(gpio_100_136)),
.port_num = MCHP_GPIO_100_136,
@ -416,11 +428,11 @@ static const struct gpio_xec_config gpio_xec_port100_136_config = {
static struct gpio_xec_data gpio_xec_port100_136_data;
DEVICE_AND_API_INIT(gpio_xec_port100_136,
DT_LABEL(DT_NODELABEL(gpio_100_136)),
gpio_xec_port100_136_init,
&gpio_xec_port100_136_data, &gpio_xec_port100_136_config,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
&gpio_xec_driver_api);
DT_LABEL(DT_NODELABEL(gpio_100_136)),
gpio_xec_port100_136_init,
&gpio_xec_port100_136_data, &gpio_xec_port100_136_config,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
&gpio_xec_driver_api);
static int gpio_xec_port100_136_init(const struct device *dev)
{
@ -431,8 +443,8 @@ static int gpio_xec_port100_136_init(const struct device *dev)
MCHP_GIRQ_BLK_SETEN(config->girq_id);
IRQ_CONNECT(DT_IRQ(DT_NODELABEL(gpio_100_136), irq),
DT_IRQ(DT_NODELABEL(gpio_100_136), priority),
gpio_gpio_xec_port_isr, DEVICE_GET(gpio_xec_port100_136), 0U);
DT_IRQ(DT_NODELABEL(gpio_100_136), priority),
gpio_gpio_xec_port_isr, DEVICE_GET(gpio_xec_port100_136), 0U);
irq_enable(DT_IRQ(DT_NODELABEL(gpio_100_136), irq));
#endif
@ -446,7 +458,7 @@ static int gpio_xec_port140_176_init(const struct device *dev);
static const struct gpio_xec_config gpio_xec_port140_176_config = {
.common = {
.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_NODE(
DT_NODELABEL(gpio_140_176)),
DT_NODELABEL(gpio_140_176)),
},
.pcr1_base = (uint32_t *) DT_REG_ADDR(DT_NODELABEL(gpio_140_176)),
.port_num = MCHP_GPIO_140_176,
@ -461,11 +473,11 @@ static const struct gpio_xec_config gpio_xec_port140_176_config = {
static struct gpio_xec_data gpio_xec_port140_176_data;
DEVICE_AND_API_INIT(gpio_xec_port140_176,
DT_LABEL(DT_NODELABEL(gpio_140_176)),
gpio_xec_port140_176_init,
&gpio_xec_port140_176_data, &gpio_xec_port140_176_config,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
&gpio_xec_driver_api);
DT_LABEL(DT_NODELABEL(gpio_140_176)),
gpio_xec_port140_176_init,
&gpio_xec_port140_176_data, &gpio_xec_port140_176_config,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
&gpio_xec_driver_api);
static int gpio_xec_port140_176_init(const struct device *dev)
{
@ -476,8 +488,8 @@ static int gpio_xec_port140_176_init(const struct device *dev)
MCHP_GIRQ_BLK_SETEN(config->girq_id);
IRQ_CONNECT(DT_IRQ(DT_NODELABEL(gpio_140_176), irq),
DT_IRQ(DT_NODELABEL(gpio_140_176), priority),
gpio_gpio_xec_port_isr, DEVICE_GET(gpio_xec_port140_176), 0U);
DT_IRQ(DT_NODELABEL(gpio_140_176), priority),
gpio_gpio_xec_port_isr, DEVICE_GET(gpio_xec_port140_176), 0U);
irq_enable(DT_IRQ(DT_NODELABEL(gpio_140_176), irq));
#endif
@ -491,7 +503,7 @@ static int gpio_xec_port200_236_init(const struct device *dev);
static const struct gpio_xec_config gpio_xec_port200_236_config = {
.common = {
.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_NODE(
DT_NODELABEL(gpio_200_236)),
DT_NODELABEL(gpio_200_236)),
},
.pcr1_base = (uint32_t *) DT_REG_ADDR(DT_NODELABEL(gpio_200_236)),
.port_num = MCHP_GPIO_200_236,
@ -506,11 +518,11 @@ static const struct gpio_xec_config gpio_xec_port200_236_config = {
static struct gpio_xec_data gpio_xec_port200_236_data;
DEVICE_AND_API_INIT(gpio_xec_port200_236,
DT_LABEL(DT_NODELABEL(gpio_200_236)),
gpio_xec_port200_236_init,
&gpio_xec_port200_236_data, &gpio_xec_port200_236_config,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
&gpio_xec_driver_api);
DT_LABEL(DT_NODELABEL(gpio_200_236)),
gpio_xec_port200_236_init,
&gpio_xec_port200_236_data, &gpio_xec_port200_236_config,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
&gpio_xec_driver_api);
static int gpio_xec_port200_236_init(const struct device *dev)
{
@ -521,8 +533,8 @@ static int gpio_xec_port200_236_init(const struct device *dev)
MCHP_GIRQ_BLK_SETEN(config->girq_id);
IRQ_CONNECT(DT_IRQ(DT_NODELABEL(gpio_200_236), irq),
DT_IRQ(DT_NODELABEL(gpio_200_236), priority),
gpio_gpio_xec_port_isr, DEVICE_GET(gpio_xec_port200_236), 0U);
DT_IRQ(DT_NODELABEL(gpio_200_236), priority),
gpio_gpio_xec_port_isr, DEVICE_GET(gpio_xec_port200_236), 0U);
irq_enable(DT_IRQ(DT_NODELABEL(gpio_200_236), irq));
#endif
@ -536,7 +548,7 @@ static int gpio_xec_port240_276_init(const struct device *dev);
static const struct gpio_xec_config gpio_xec_port240_276_config = {
.common = {
.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_NODE(
DT_NODELABEL(gpio_240_276)),
DT_NODELABEL(gpio_240_276)),
},
.pcr1_base = (uint32_t *) DT_REG_ADDR(DT_NODELABEL(gpio_240_276)),
.port_num = MCHP_GPIO_240_276,
@ -551,11 +563,11 @@ static const struct gpio_xec_config gpio_xec_port240_276_config = {
static struct gpio_xec_data gpio_xec_port240_276_data;
DEVICE_AND_API_INIT(gpio_xec_port240_276,
DT_LABEL(DT_NODELABEL(gpio_240_276)),
gpio_xec_port240_276_init,
&gpio_xec_port240_276_data, &gpio_xec_port240_276_config,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
&gpio_xec_driver_api);
DT_LABEL(DT_NODELABEL(gpio_240_276)),
gpio_xec_port240_276_init,
&gpio_xec_port240_276_data, &gpio_xec_port240_276_config,
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
&gpio_xec_driver_api);
static int gpio_xec_port240_276_init(const struct device *dev)
{
@ -566,8 +578,8 @@ static int gpio_xec_port240_276_init(const struct device *dev)
MCHP_GIRQ_BLK_SETEN(config->girq_id);
IRQ_CONNECT(DT_IRQ(DT_NODELABEL(gpio_240_276), irq),
DT_IRQ(DT_NODELABEL(gpio_240_276), priority),
gpio_gpio_xec_port_isr, DEVICE_GET(gpio_xec_port240_276), 0U);
DT_IRQ(DT_NODELABEL(gpio_240_276), priority),
gpio_gpio_xec_port_isr, DEVICE_GET(gpio_xec_port240_276), 0U);
irq_enable(DT_IRQ(DT_NODELABEL(gpio_240_276), irq));
#endif