diff --git a/boards/arm/mec15xxevb_assy6853/mec15xxevb_assy6853.dts b/boards/arm/mec15xxevb_assy6853/mec15xxevb_assy6853.dts index 0f442a061c581..aec943a241118 100644 --- a/boards/arm/mec15xxevb_assy6853/mec15xxevb_assy6853.dts +++ b/boards/arm/mec15xxevb_assy6853/mec15xxevb_assy6853.dts @@ -19,8 +19,36 @@ }; aliases { + led0 = &led2; + led1 = &led3; + led2 = &led4; pwm-0 = &pwm0; }; + + leds { + compatible = "gpio-leds"; + led2: led_0 { + /* GPIO156/LED0 on schematic, + * LED2 on silkscreen. + */ + gpios = <&gpiod 14 GPIO_ACTIVE_LOW>; + label = "LED 2"; + }; + led3: led_1 { + /* GPIO157/LED1 on schematic, + * LED3 on silkscreen. + */ + gpios = <&gpiod 15 GPIO_ACTIVE_LOW>; + label = "LED 3"; + }; + led4: led_2 { + /* GPIO153/LED2 on schematic, + * LED4 on silkscreen. + */ + gpios = <&gpiod 11 GPIO_ACTIVE_LOW>; + label = "LED 4"; + }; + }; }; &uart2 { diff --git a/drivers/gpio/gpio_mchp_xec.c b/drivers/gpio/gpio_mchp_xec.c index 505e9ba9ce5c1..20bbc20694ab9 100644 --- a/drivers/gpio/gpio_mchp_xec.c +++ b/drivers/gpio/gpio_mchp_xec.c @@ -11,6 +11,11 @@ #include "gpio_utils.h" +#define GPIO_IN_BASE(config) \ + ((__IO u32_t *)(GPIO_PARIN_BASE + (config->port_num << 2))) + +#define GPIO_OUT_BASE(config) \ + ((__IO u32_t *)(GPIO_PAROUT_BASE + (config->port_num << 2))) static const u32_t valid_ctrl_masks[NUM_MCHP_GPIO_PORTS] = { (MCHP_GPIO_PORT_A_BITMAP), @@ -42,23 +47,19 @@ static int gpio_xec_configure(struct device *dev, { const struct gpio_xec_config *config = dev->config->config_info; __IO u32_t *current_pcr1; - u32_t pcr1 = 0; - u32_t mask = 0; - u32_t gpio_interrupt = 0; + u32_t pcr1 = 0U; + u32_t mask = 0U; + __IO u32_t *gpio_out_reg = GPIO_OUT_BASE(config); /* Validate pin number range in terms of current port */ - if ((valid_ctrl_masks[config->port_num] & BIT(pin)) == 0) { - return -EINVAL; - } - - /* Check for an invalid pin configuration */ - if ((flags & GPIO_INT) && (flags & GPIO_DIR_OUT)) { + if ((valid_ctrl_masks[config->port_num] & BIT(pin)) == 0U) { return -EINVAL; } - /* Check if GPIO port supports interrupts */ - if ((flags & GPIO_INT) && ((config->flags & GPIO_INT) == 0)) { - return -EINVAL; + /* Don't support "open source" mode */ + if (((flags & GPIO_SINGLE_ENDED) != 0U) && + ((flags & GPIO_LINE_OPEN_DRAIN) == 0U)) { + return -ENOTSUP; } /* The flags contain options that require touching registers in the @@ -70,13 +71,19 @@ static int gpio_xec_configure(struct device *dev, mask |= MCHP_GPIO_CTRL_DIR_MASK; mask |= MCHP_GPIO_CTRL_INPAD_DIS_MASK; if (access_op == GPIO_ACCESS_BY_PIN) { - if ((flags & GPIO_DIR_MASK) == GPIO_DIR_IN) { - pcr1 &= ~BIT(MCHP_GPIO_CTRL_DIR_POS); - } else { /* GPIO_DIR_OUT */ - pcr1 |= BIT(MCHP_GPIO_CTRL_DIR_POS); + if ((flags & GPIO_OUTPUT) != 0U) { + if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0U) { + *gpio_out_reg |= BIT(pin); + } else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0U) { + *gpio_out_reg &= ~BIT(pin); + } + pcr1 |= MCHP_GPIO_CTRL_DIR_OUTPUT; + } else { + /* GPIO_INPUT */ + pcr1 |= MCHP_GPIO_CTRL_DIR_INPUT; } } else { /* GPIO_ACCESS_BY_PORT is not supported */ - return -EINVAL; + return -ENOTSUP; } /* Figure out the pullup/pulldown configuration and keep it in the @@ -84,69 +91,129 @@ static int gpio_xec_configure(struct device *dev, */ mask |= MCHP_GPIO_CTRL_PUD_MASK; - if ((flags & GPIO_PUD_MASK) == GPIO_PUD_PULL_UP) { + if ((flags & GPIO_PULL_UP) != 0U) { /* Enable the pull and select the pullup resistor. */ pcr1 |= MCHP_GPIO_CTRL_PUD_PU; - } else if ((flags & GPIO_PUD_MASK) == GPIO_PUD_PULL_DOWN) { + } else if ((flags & GPIO_PULL_DOWN) != 0U) { /* Enable the pull and select the pulldown resistor */ pcr1 |= MCHP_GPIO_CTRL_PUD_PD; } + /* Push-pull or open drain */ + mask |= MCHP_GPIO_CTRL_BUFT_MASK; + + if ((flags & GPIO_OPEN_DRAIN) != 0U) { + /* Open drain */ + pcr1 |= MCHP_GPIO_CTRL_BUFT_OPENDRAIN; + } else { + /* Push-pull */ + pcr1 |= MCHP_GPIO_CTRL_BUFT_PUSHPULL; + } + + /* Use GPIO output register to control pin output, instead of + * using the control register (=> alternate output disable). + */ + mask |= MCHP_GPIO_CTRL_AOD_MASK; + pcr1 |= MCHP_GPIO_CTRL_AOD_DIS; + + /* Now write contents of pcr1 variable to the PCR1 register that + * corresponds to the GPIO being configured + */ + current_pcr1 = config->pcr1_base + pin; + *current_pcr1 = (*current_pcr1 & ~mask) | pcr1; + + return 0; +} + +static int gpio_xec_pin_interrupt_configure(struct device *dev, + unsigned int pin, enum gpio_int_mode mode, + enum gpio_int_trig trig) +{ + const struct gpio_xec_config *config = dev->config->config_info; + struct gpio_xec_data *drv_data = dev->driver_data; + __IO u32_t *current_pcr1; + u32_t pcr1 = 0U; + u32_t mask = 0U; + u32_t gpio_interrupt = 0U; + + /* Validate pin number range in terms of current port */ + if ((valid_ctrl_masks[config->port_num] & BIT(pin)) == 0U) { + return -EINVAL; + } + + /* Check if GPIO port supports interrupts */ + if ((mode != GPIO_INT_MODE_DISABLED) && + ((config->flags & GPIO_INT_ENABLE) == 0U)) { + return -ENOTSUP; + } + /* Assemble mask for level/edge triggered interrrupts */ mask |= MCHP_GPIO_CTRL_IDET_MASK; - if (flags & GPIO_INT) { - if (flags & GPIO_INT_EDGE) { - /* Enable edge interrupts */ - if (flags & GPIO_INT_ACTIVE_HIGH) { - gpio_interrupt = MCHP_GPIO_CTRL_IDET_REDGE; - } else if (flags & GPIO_INT_DOUBLE_EDGE) { - gpio_interrupt = MCHP_GPIO_CTRL_IDET_BEDGE; - } else { - gpio_interrupt = MCHP_GPIO_CTRL_IDET_FEDGE; - } - } else { /* GPIO_INT_LEVEL */ - if (flags & GPIO_INT_ACTIVE_HIGH) { + if (mode == GPIO_INT_MODE_DISABLED) { + /* Explicitly disable interrupts, otherwise the configuration + * results in level triggered/low interrupts + */ + pcr1 |= MCHP_GPIO_CTRL_IDET_DISABLE; + + /* Disable interrupt in the EC aggregator */ + MCHP_GIRQ_ENCLR(config->girq_id) = BIT(pin); + } else { + if (mode == GPIO_INT_MODE_LEVEL) { + /* Enable level interrupts */ + if (trig == GPIO_INT_TRIG_HIGH) { gpio_interrupt = MCHP_GPIO_CTRL_IDET_LVL_HI; } else { gpio_interrupt = MCHP_GPIO_CTRL_IDET_LVL_LO; } + } else { + /* Enable edge interrupts */ + switch (trig) { + case GPIO_INT_TRIG_LOW: + gpio_interrupt = MCHP_GPIO_CTRL_IDET_FEDGE; + break; + case GPIO_INT_TRIG_HIGH: + gpio_interrupt = MCHP_GPIO_CTRL_IDET_REDGE; + break; + case GPIO_INT_TRIG_BOTH: + gpio_interrupt = MCHP_GPIO_CTRL_IDET_BEDGE; + break; + default: + return -EINVAL; + } } + pcr1 |= gpio_interrupt; + /* We enable the interrupts in the EC aggregator so that the - * result can be forwarded to the ARM NVIC + * result can be forwarded to the ARM NVIC */ + MCHP_GIRQ_SRC_CLR(config->girq_id, pin); MCHP_GIRQ_ENSET(config->girq_id) = BIT(pin); - } else { - /* Explicitly disable interrupts, otherwise the configuration - * results in level triggered/low interrupts - */ - pcr1 |= MCHP_GPIO_CTRL_IDET_DISABLE; } - /* Use Gpio output register for writing in order to have simetry with - * respect of Gpio input - */ - mask |= MCHP_GPIO_CTRL_AOD_MASK; - pcr1 |= MCHP_GPIO_CTRL_AOD_MASK; + /* Now write contents of pcr1 variable to the PCR1 register that * corresponds to the GPIO being configured */ current_pcr1 = config->pcr1_base + pin; *current_pcr1 = (*current_pcr1 & ~mask) | pcr1; + if (mode == GPIO_INT_MODE_DISABLED) { + drv_data->pin_callback_enables &= ~BIT(pin); + } else { + drv_data->pin_callback_enables |= BIT(pin); + } + return 0; } - static int gpio_xec_write(struct device *dev, int access_op, u32_t pin, u32_t value) { const struct gpio_xec_config *config = dev->config->config_info; - u32_t port_n = config->port_num; /* GPIO output registers are used for writing */ - __IO u32_t *gpio_base = (__IO u32_t *)(GPIO_PAROUT_BASE - + (port_n << 2)); + __IO u32_t *gpio_base = GPIO_OUT_BASE(config); if (access_op == GPIO_ACCESS_BY_PIN) { if (value) { @@ -170,26 +237,79 @@ static int gpio_xec_write(struct device *dev, } -static int gpio_xec_read(struct device *dev, - int access_op, u32_t pin, u32_t *value) +static int gpio_xec_port_set_masked_raw(struct device *dev, u32_t mask, + u32_t value) +{ + const struct gpio_xec_config *config = dev->config->config_info; + + /* GPIO output registers are used for writing */ + __IO u32_t *gpio_base = GPIO_OUT_BASE(config); + + *gpio_base = (*gpio_base & ~mask) | (mask & value); + + return 0; +} + +static int gpio_xec_port_set_bits_raw(struct device *dev, u32_t mask) +{ + const struct gpio_xec_config *config = dev->config->config_info; + + /* GPIO output registers are used for writing */ + __IO u32_t *gpio_base = GPIO_OUT_BASE(config); + + *gpio_base |= mask; + + return 0; +} + +static int gpio_xec_port_clear_bits_raw(struct device *dev, u32_t mask) +{ + const struct gpio_xec_config *config = dev->config->config_info; + + /* GPIO output registers are used for writing */ + __IO u32_t *gpio_base = GPIO_OUT_BASE(config); + + *gpio_base &= ~mask; + + return 0; +} + +static int gpio_xec_port_toggle_bits(struct device *dev, u32_t mask) +{ + const struct gpio_xec_config *config = dev->config->config_info; + + /* GPIO output registers are used for writing */ + __IO u32_t *gpio_base = GPIO_OUT_BASE(config); + + *gpio_base ^= mask; + + return 0; +} + +static int gpio_xec_port_get_raw(struct device *dev, u32_t *value) { const struct gpio_xec_config *config = dev->config->config_info; - u32_t port_n = config->port_num; /* GPIO input registers are used for reading */ - __IO u32_t *gpio_base = (__IO u32_t *)(GPIO_PARIN_BASE + (port_n << 2)); + __IO u32_t *gpio_base = GPIO_IN_BASE(config); *value = *gpio_base; + + return 0; +} + +static int gpio_xec_read(struct device *dev, + int access_op, u32_t pin, u32_t *value) +{ + gpio_xec_port_get_raw(dev, value); + if (access_op == GPIO_ACCESS_BY_PIN) { *value = (*value & BIT(pin)) >> pin; - } else { /* GPIO_ACCESS_BY_PORT not supported */ - return -EINVAL; } return 0; } - static int gpio_xec_manage_callback(struct device *dev, struct gpio_callback *callback, bool set) { @@ -239,7 +359,7 @@ static void gpio_gpio_xec_port_isr(void *arg) * aggregator result register */ girq_result = MCHP_GIRQ_RESULT(config->girq_id); - enabled_int = girq_result & data->pin_callback_enables; + enabled_int = girq_result & data->pin_callback_enables; /* Clear source register in aggregator before firing callbacks */ REG32(MCHP_GIRQ_SRC_ADDR(config->girq_id)) = girq_result; @@ -251,6 +371,12 @@ static const struct gpio_driver_api gpio_xec_driver_api = { .config = gpio_xec_configure, .write = gpio_xec_write, .read = gpio_xec_read, + .port_get_raw = gpio_xec_port_get_raw, + .port_set_masked_raw = gpio_xec_port_set_masked_raw, + .port_set_bits_raw = gpio_xec_port_set_bits_raw, + .port_clear_bits_raw = gpio_xec_port_clear_bits_raw, + .port_toggle_bits = gpio_xec_port_toggle_bits, + .pin_interrupt_configure = gpio_xec_pin_interrupt_configure, .manage_callback = gpio_xec_manage_callback, .enable_callback = gpio_xec_enable_callback, .disable_callback = gpio_xec_disable_callback, @@ -264,7 +390,7 @@ static const struct gpio_xec_config gpio_xec_port000_036_config = { .port_num = MCHP_GPIO_000_036, #ifdef DT_GPIO_XEC_GPIO000_036_IRQ .girq_id = MCHP_GIRQ11_ID, - .flags = GPIO_INT, + .flags = GPIO_INT_ENABLE, #else .flags = 0, #endif @@ -288,7 +414,7 @@ static int gpio_xec_port000_036_init(struct device *dev) IRQ_CONNECT(DT_GPIO_XEC_GPIO000_036_IRQ, DT_GPIO_XEC_GPIO000_036_IRQ_PRIORITY, - gpio_gpio_xec_port_isr, DEVICE_GET(gpio_xec_port000_036), 0); + gpio_gpio_xec_port_isr, DEVICE_GET(gpio_xec_port000_036), 0U); irq_enable(DT_GPIO_XEC_GPIO000_036_IRQ); #endif @@ -304,7 +430,7 @@ static const struct gpio_xec_config gpio_xec_port040_076_config = { .port_num = MCHP_GPIO_040_076, #ifdef DT_GPIO_XEC_GPIO040_076_IRQ .girq_id = MCHP_GIRQ10_ID, - .flags = GPIO_INT, + .flags = GPIO_INT_ENABLE, #else .flags = 0, #endif @@ -328,7 +454,7 @@ static int gpio_xec_port040_076_init(struct device *dev) IRQ_CONNECT(DT_GPIO_XEC_GPIO040_076_IRQ, DT_GPIO_XEC_GPIO040_076_IRQ_PRIORITY, - gpio_gpio_xec_port_isr, DEVICE_GET(gpio_xec_port040_076), 0); + gpio_gpio_xec_port_isr, DEVICE_GET(gpio_xec_port040_076), 0U); irq_enable(DT_GPIO_XEC_GPIO040_076_IRQ); #endif @@ -344,7 +470,7 @@ static const struct gpio_xec_config gpio_xec_port100_136_config = { .port_num = MCHP_GPIO_100_136, #ifdef DT_GPIO_XEC_GPIO100_136_IRQ .girq_id = MCHP_GIRQ09_ID, - .flags = GPIO_INT, + .flags = GPIO_INT_ENABLE, #else .flags = 0, #endif @@ -368,7 +494,7 @@ static int gpio_xec_port100_136_init(struct device *dev) IRQ_CONNECT(DT_GPIO_XEC_GPIO100_136_IRQ, DT_GPIO_XEC_GPIO100_136_IRQ_PRIORITY, - gpio_gpio_xec_port_isr, DEVICE_GET(gpio_xec_port100_136), 0); + gpio_gpio_xec_port_isr, DEVICE_GET(gpio_xec_port100_136), 0U); irq_enable(DT_GPIO_XEC_GPIO100_136_IRQ); #endif @@ -384,7 +510,7 @@ static const struct gpio_xec_config gpio_xec_port140_176_config = { .port_num = MCHP_GPIO_140_176, #ifdef DT_GPIO_XEC_GPIO140_176_IRQ .girq_id = MCHP_GIRQ08_ID, - .flags = GPIO_INT, + .flags = GPIO_INT_ENABLE, #else .flags = 0, #endif @@ -408,7 +534,7 @@ static int gpio_xec_port140_176_init(struct device *dev) IRQ_CONNECT(DT_GPIO_XEC_GPIO140_176_IRQ, DT_GPIO_XEC_GPIO140_176_IRQ_PRIORITY, - gpio_gpio_xec_port_isr, DEVICE_GET(gpio_xec_port140_176), 0); + gpio_gpio_xec_port_isr, DEVICE_GET(gpio_xec_port140_176), 0U); irq_enable(DT_GPIO_XEC_GPIO140_176_IRQ); #endif @@ -424,7 +550,7 @@ static const struct gpio_xec_config gpio_xec_port200_236_config = { .port_num = MCHP_GPIO_200_236, #ifdef DT_GPIO_XEC_GPIO200_236_IRQ .girq_id = MCHP_GIRQ12_ID, - .flags = GPIO_INT, + .flags = GPIO_INT_ENABLE, #else .flags = 0, #endif @@ -448,7 +574,7 @@ static int gpio_xec_port200_236_init(struct device *dev) IRQ_CONNECT(DT_GPIO_XEC_GPIO200_236_IRQ, DT_GPIO_XEC_GPIO200_236_IRQ_PRIORITY, - gpio_gpio_xec_port_isr, DEVICE_GET(gpio_xec_port200_236), 0); + gpio_gpio_xec_port_isr, DEVICE_GET(gpio_xec_port200_236), 0U); irq_enable(DT_GPIO_XEC_GPIO200_236_IRQ); #endif @@ -464,7 +590,7 @@ static const struct gpio_xec_config gpio_xec_port240_276_config = { .port_num = MCHP_GPIO_240_276, #ifdef DT_GPIO_XEC_GPIO240_276_IRQ .girq_id = MCHP_GIRQ26_ID, - .flags = GPIO_INT, + .flags = GPIO_INT_ENABLE, #else .flags = 0, #endif @@ -488,7 +614,7 @@ static int gpio_xec_port240_276_init(struct device *dev) IRQ_CONNECT(DT_GPIO_XEC_GPIO240_276_IRQ, DT_GPIO_XEC_GPIO240_276_IRQ_PRIORITY, - gpio_gpio_xec_port_isr, DEVICE_GET(gpio_xec_port240_276), 0); + gpio_gpio_xec_port_isr, DEVICE_GET(gpio_xec_port240_276), 0U); irq_enable(DT_GPIO_XEC_GPIO240_276_IRQ); #endif diff --git a/tests/drivers/gpio/gpio_basic_api/boards/mec15xxevb_assy6853.overlay b/tests/drivers/gpio/gpio_basic_api/boards/mec15xxevb_assy6853.overlay new file mode 100644 index 0000000000000..aa8c32802cc89 --- /dev/null +++ b/tests/drivers/gpio/gpio_basic_api/boards/mec15xxevb_assy6853.overlay @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2019 Intel Corporation + * Copyright (c) 2019 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + resources { + compatible = "test,gpio_basic_api"; + + /* Remove jumper on JP15 to disconnect pull-up resistor */ + out-gpios = <&gpiob 8 0>; /* GPIO_050, JP27 Pin 11 */ + in-gpios = <&gpiob 9 0>; /* GPIO_051, JP27 Pin 13 */ + }; +};