diff --git a/boards/arm/lpcxpresso54114/lpcxpresso54114_m4.dts b/boards/arm/lpcxpresso54114/lpcxpresso54114_m4.dts index 6886b88411888..af47479ac4e97 100644 --- a/boards/arm/lpcxpresso54114/lpcxpresso54114_m4.dts +++ b/boards/arm/lpcxpresso54114/lpcxpresso54114_m4.dts @@ -30,15 +30,15 @@ compatible = "gpio-keys"; user_button_1: button_0 { label = "User SW1"; - gpios = <&gpio0 24 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 24 GPIO_ACTIVE_LOW>; }; user_button_2: button_1 { label = "User SW2"; - gpios = <&gpio0 31 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 31 GPIO_ACTIVE_LOW>; }; user_button_3: button_2 { label = "User SW3"; - gpios = <&gpio0 4 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 4 GPIO_ACTIVE_LOW>; }; }; }; diff --git a/boards/arm/lpcxpresso54114/pinmux.c b/boards/arm/lpcxpresso54114/pinmux.c index eb1abb2b4da7d..7cb6e23f25e76 100644 --- a/boards/arm/lpcxpresso54114/pinmux.c +++ b/boards/arm/lpcxpresso54114/pinmux.c @@ -90,6 +90,7 @@ static int lpcxpresso_54114_pinmux_init(struct device *dev) IOCON_PIO_OPENDRAIN_DI ); pinmux_pin_set(port0, 4, port0_pin4_config); + #endif #ifdef CONFIG_GPIO_MCUX_LPC_PORT1 diff --git a/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu0.dts b/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu0.dts index 8bced3280fb65..b978290c6c7c6 100644 --- a/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu0.dts +++ b/boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu0.dts @@ -30,15 +30,15 @@ compatible = "gpio-keys"; user_button_1: button_0 { label = "User SW1"; - gpios = <&gpio0 5 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio0 5 GPIO_ACTIVE_HIGH>; }; user_button_2: button_1 { label = "User SW2"; - gpios = <&gpio1 18 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio1 18 GPIO_ACTIVE_LOW>; }; user_button_3: button_2 { label = "User SW3"; - gpios = <&gpio1 9 GPIO_INT_ACTIVE_LOW>; + gpios = <&gpio1 9 GPIO_ACTIVE_LOW>; }; }; }; diff --git a/boards/arm/lpcxpresso55s69/pinmux.c b/boards/arm/lpcxpresso55s69/pinmux.c index fd24f1f476805..8380adc6bd88e 100644 --- a/boards/arm/lpcxpresso55s69/pinmux.c +++ b/boards/arm/lpcxpresso55s69/pinmux.c @@ -48,8 +48,8 @@ static int lpcxpresso_55s69_pinmux_init(struct device *dev) #endif -#ifdef CONFIG_GPIO_MCUX_LPC_PORT0 - const u32_t port0_pin5_config = ( +#ifdef DT_GPIO_KEYS_SW0_GPIO_CONTROLLER + const u32_t sw0_config = ( IOCON_PIO_FUNC0 | IOCON_PIO_MODE_PULLUP | IOCON_PIO_INV_DI | @@ -58,12 +58,11 @@ static int lpcxpresso_55s69_pinmux_init(struct device *dev) IOCON_PIO_SLEW_STANDARD | IOCON_PIO_OPENDRAIN_DI ); - - pinmux_pin_set(port0, 5, port0_pin5_config); + pinmux_pin_set(port0, DT_ALIAS_SW0_GPIOS_PIN, sw0_config); #endif -#ifdef CONFIG_GPIO_MCUX_LPC_PORT0 - const u32_t port1_pin18_config = ( +#ifdef DT_GPIO_KEYS_SW1_GPIO_CONTROLLER + const u32_t sw1_config = ( IOCON_PIO_FUNC0 | IOCON_PIO_MODE_PULLUP | IOCON_PIO_INV_DI | @@ -72,10 +71,11 @@ static int lpcxpresso_55s69_pinmux_init(struct device *dev) IOCON_PIO_SLEW_STANDARD | IOCON_PIO_OPENDRAIN_DI ); + pinmux_pin_set(port1, DT_ALIAS_SW1_GPIOS_PIN, sw1_config); +#endif - pinmux_pin_set(port1, 18, port1_pin18_config); - - const u32_t port1_pin9_config = ( +#ifdef DT_GPIO_KEYS_SW2_GPIO_CONTROLLER + const u32_t sw2_config = ( IOCON_PIO_FUNC0 | IOCON_PIO_MODE_PULLUP | IOCON_PIO_INV_DI | @@ -84,8 +84,7 @@ static int lpcxpresso_55s69_pinmux_init(struct device *dev) IOCON_PIO_SLEW_STANDARD | IOCON_PIO_OPENDRAIN_DI ); - - pinmux_pin_set(port1, 9, port1_pin9_config); + pinmux_pin_set(port1, DT_ALIAS_SW2_GPIOS_PIN, sw2_config); #endif return 0; diff --git a/drivers/gpio/Kconfig.mcux_lpc b/drivers/gpio/Kconfig.mcux_lpc index b264158e4c05e..152e3b47e5ec4 100644 --- a/drivers/gpio/Kconfig.mcux_lpc +++ b/drivers/gpio/Kconfig.mcux_lpc @@ -8,6 +8,7 @@ menuconfig GPIO_MCUX_LPC bool "MCUX LPC GPIO driver" depends on HAS_MCUX + select HAS_DTS_GPIO help Enable the MCUX LPC pinmux driver. diff --git a/drivers/gpio/gpio_mcux_lpc.c b/drivers/gpio/gpio_mcux_lpc.c index cfbdc90a03784..fe8bb8d19c9f8 100644 --- a/drivers/gpio/gpio_mcux_lpc.c +++ b/drivers/gpio/gpio_mcux_lpc.c @@ -8,9 +8,8 @@ * @brief GPIO driver for LPC54XXX family * * Note: - * - Only basic GPIO features sufficient to blinky functionality - * are currently implemented. - * - Interrupt mode is not implemented. + * - fsl_pint internally tries to manage interrupts, but this is not used (e.g. + * s_pintCallback), Zephyr's interrupt management system is used in place. */ #include @@ -20,13 +19,22 @@ #include #include "gpio_utils.h" #include +#include +#include #include -#define PORT0_IDX 0u -#define PORT1_IDX 1u +#define PORT0_IDX 0u +#define PORT1_IDX 1u + +#define PIN_TO_INPUT_MUX_CONNECTION(port, pin) \ + ((PINTSEL0 << PMUX_SHIFT) + (32 * port) + (pin)) + +#define NO_PINT_INT ((1 << sizeof(pint_pin_int_t)) - 1) struct gpio_mcux_lpc_config { GPIO_Type *gpio_base; + PINT_Type *pint_base; + IOCON_Type *pinmux_base; u32_t port_no; clock_ip_name_t clock_ip_name; }; @@ -38,55 +46,75 @@ struct gpio_mcux_lpc_data { sys_slist_t callbacks; /* pin callback routine enable flags, by pin number */ u32_t pin_callback_enables; + /* pin association with PINT id */ + pint_pin_int_t pint_id[32]; + /* ISR allocated in device tree to this port */ + u32_t isr_list[8]; + /* index to to table above */ + u32_t isr_list_idx; }; -static int gpio_mcux_lpc_configure(struct device *dev, - int access_op, u32_t pin, int flags) +static int gpio_mcux_lpc_configure(struct device *dev, int access_op, u32_t pin, + int flags) { const struct gpio_mcux_lpc_config *config = dev->config->config_info; GPIO_Type *gpio_base = config->gpio_base; + u32_t port = config->port_no; - /* Check for an invalid pin configuration */ - if ((flags & GPIO_INT) && (flags & GPIO_DIR_OUT)) { - return -EINVAL; + if (((flags & GPIO_INPUT) != 0) && ((flags & GPIO_OUTPUT) != 0)) { + return -ENOTSUP; } - /* Check if GPIO port supports interrupts */ - if (flags & GPIO_INT) { + if ((flags & GPIO_SINGLE_ENDED) != 0) { return -ENOTSUP; } + if (flags & (GPIO_PULL_UP | GPIO_PULL_DOWN)) { + IOCON_Type *pinmux_base = config->pinmux_base; + u32_t *pinconfig = (u32_t *)&(pinmux_base->PIO[port][pin]); + + *pinconfig &= ~(IOCON_PIO_MODE_PULLUP|IOCON_PIO_MODE_PULLDOWN); + if ((flags & GPIO_PULL_UP) != 0) { + *pinconfig |= IOCON_PIO_MODE_PULLUP; + } else if ((flags & GPIO_PULL_DOWN) != 0) { + *pinconfig |= IOCON_PIO_MODE_PULLDOWN; + } + } + /* supports access by pin now,you can add access by port when needed */ if (access_op == GPIO_ACCESS_BY_PIN) { - /* input-0,output-1 */ - if ((flags & GPIO_DIR_MASK) == GPIO_DIR_IN) { - gpio_base->DIR[config->port_no] &= ~(BIT(pin)); - } else { - gpio_base->SET[config->port_no] = BIT(pin); - gpio_base->DIR[config->port_no] |= BIT(pin); + if (flags & GPIO_OUTPUT_INIT_HIGH) { + gpio_base->SET[port] = BIT(pin); + } + + if (flags & GPIO_OUTPUT_INIT_LOW) { + gpio_base->CLR[port] = BIT(pin); } - } else { + /* input-0,output-1 */ + WRITE_BIT(gpio_base->DIR[port], pin, flags & GPIO_OUTPUT); + } else { return -EINVAL; } return 0; } -static int gpio_mcux_lpc_write(struct device *dev, - int access_op, u32_t pin, u32_t value) +static int gpio_mcux_lpc_write(struct device *dev, int access_op, u32_t pin, + u32_t value) { const struct gpio_mcux_lpc_config *config = dev->config->config_info; GPIO_Type *gpio_base = config->gpio_base; + u32_t port = config->port_no; /* Check for an invalid pin number */ - if (pin >= ARRAY_SIZE(gpio_base->B[config->port_no])) { + if (pin >= ARRAY_SIZE(gpio_base->B[port])) { return -EINVAL; } if (access_op == GPIO_ACCESS_BY_PIN) { /* Set/Clear the data output for the respective pin */ - gpio_base->B[config->port_no][pin] = value; + gpio_base->B[port][pin] = value; } else { /* return an error for all other options */ return -EINVAL; } @@ -94,8 +122,8 @@ static int gpio_mcux_lpc_write(struct device *dev, return 0; } -static int gpio_mcux_lpc_read(struct device *dev, - int access_op, u32_t pin, u32_t *value) +static int gpio_mcux_lpc_read(struct device *dev, int access_op, u32_t pin, + u32_t *value) { const struct gpio_mcux_lpc_config *config = dev->config->config_info; GPIO_Type *gpio_base = config->gpio_base; @@ -111,12 +139,248 @@ static int gpio_mcux_lpc_read(struct device *dev, return 0; } +static int gpio_mcux_lpc_port_get_raw(struct device *dev, u32_t *value) +{ + const struct gpio_mcux_lpc_config *config = dev->config->config_info; + GPIO_Type *gpio_base = config->gpio_base; + + *value = gpio_base->PIN[config->port_no]; + + return 0; +} + +static int gpio_mcux_lpc_port_set_masked_raw(struct device *dev, u32_t mask, + u32_t value) +{ + const struct gpio_mcux_lpc_config *config = dev->config->config_info; + GPIO_Type *gpio_base = config->gpio_base; + u32_t port = config->port_no; + + /* Writing 0 allows R+W, 1 disables the pin */ + gpio_base->MASK[port] = ~mask; + gpio_base->PIN[port] = value; + /* Enable back the pins, user won't assume pins remain masked*/ + gpio_base->MASK[port] = 0U; + + return 0; +} + +static int gpio_mcux_lpc_port_set_bits_raw(struct device *dev, u32_t mask) +{ + const struct gpio_mcux_lpc_config *config = dev->config->config_info; + GPIO_Type *gpio_base = config->gpio_base; + + gpio_base->SET[config->port_no] = mask; + + return 0; +} + +static int gpio_mcux_lpc_port_clear_bits_raw(struct device *dev, u32_t mask) +{ + const struct gpio_mcux_lpc_config *config = dev->config->config_info; + GPIO_Type *gpio_base = config->gpio_base; + + gpio_base->CLR[config->port_no] = mask; + + return 0; +} + +static int gpio_mcux_lpc_port_toggle_bits(struct device *dev, u32_t mask) +{ + const struct gpio_mcux_lpc_config *config = dev->config->config_info; + GPIO_Type *gpio_base = config->gpio_base; + + gpio_base->NOT[config->port_no] = mask; + + return 0; +} + +static void gpio_mcux_lpc_port_isr(void *arg) +{ + struct device *dev = (struct device *)arg; + const struct gpio_mcux_lpc_config *config = dev->config->config_info; + struct gpio_mcux_lpc_data *data = dev->driver_data; + u32_t enabled_int; + u32_t int_flags; + u32_t pin; + + for (pin = 0; pin < 32; pin++) { + if (data->pint_id[pin] != NO_PINT_INT) { + int_flags = PINT_PinInterruptGetStatus( + config->pint_base, data->pint_id[pin]); + enabled_int = + (int_flags << pin) & data->pin_callback_enables; + + PINT_PinInterruptClrStatus(config->pint_base, + data->pint_id[pin]); + + gpio_fire_callbacks(&data->callbacks, dev, enabled_int); + } + } +} + +static u32_t get_free_isr(struct gpio_mcux_lpc_data *data) +{ + u32_t i; + u32_t isr; + + for (i = 0; i < data->isr_list_idx; i++) { + if (data->isr_list[i] != -1) { + isr = data->isr_list[i]; + data->isr_list[i] = -1; + return isr; + } + } + + return -EINVAL; +} + +/* Function configures INPUTMUX device to route pin interrupts to a certain + * PINT. PINT no. is unknown, rather it's determined from ISR no. + */ +static u32_t attach_pin_to_isr(u32_t port, u32_t pin, u32_t isr_no) +{ + u32_t pint_idx; + /* Connect trigger sources to PINT */ + INPUTMUX_Init(INPUTMUX); + + /* Code asumes PIN_INT values are grouped [0..3] and [4..7]. + * This scenario is true in LPC54xxx/LPC55xxx. + */ + if (isr_no < PIN_INT4_IRQn) { + pint_idx = isr_no - PIN_INT0_IRQn; + } else { + pint_idx = isr_no - PIN_INT4_IRQn; + } + + INPUTMUX_AttachSignal(INPUTMUX, pint_idx, + PIN_TO_INPUT_MUX_CONNECTION(port, pin)); + + /* Turnoff clock to inputmux to save power. Clock is only needed to make + * changes. Can be turned off after. + */ + INPUTMUX_Deinit(INPUTMUX); + + return pint_idx; +} + +static void gpio_mcux_lpc_port_isr(void *arg); + + +static int gpio_mcux_lpc_pin_interrupt_configure(struct device *dev, + unsigned int pin, enum gpio_int_mode mode, + enum gpio_int_trig trig) +{ + const struct gpio_mcux_lpc_config *config = dev->config->config_info; + struct gpio_mcux_lpc_data *data = dev->driver_data; + pint_pin_enable_t interruptMode = kPINT_PinIntEnableNone; + GPIO_Type *gpio_base = config->gpio_base; + u32_t port = config->port_no; + u32_t isr; + u32_t pint_idx; + + /* Ensure pin used as interrupt is set as input*/ + if ((mode & GPIO_INT_ENABLE) && + ((gpio_base->DIR[port] & BIT(pin)) != 0)) { + return -ENOTSUP; + } + + switch (mode) { + case GPIO_INT_MODE_DISABLED: + interruptMode = kPINT_PinIntEnableNone; + break; + case GPIO_INT_MODE_LEVEL: + if (trig == GPIO_INT_TRIG_HIGH) { + interruptMode = kPINT_PinIntEnableHighLevel; + } else if (trig == GPIO_INT_TRIG_LOW) { + interruptMode = kPINT_PinIntEnableLowLevel; + } else { + return -ENOTSUP; + } + break; + case GPIO_INT_MODE_EDGE: + if (trig == GPIO_INT_TRIG_HIGH) { + interruptMode = kPINT_PinIntEnableRiseEdge; + } else if (trig == GPIO_INT_TRIG_LOW) { + interruptMode = kPINT_PinIntEnableFallEdge; + } else { + interruptMode = kPINT_PinIntEnableBothEdges; + } + break; + default: + return -ENOTSUP; + } + + /* First time calling this function routes PIN->PINT->INPUTMUX->NVIC */ + if (data->pint_id[pin] == NO_PINT_INT) { + isr = get_free_isr(data); + if (isr == -EINVAL) { + /* Didn't find any free interrupt in this port */ + return -EBUSY; + } + pint_idx = attach_pin_to_isr(port, pin, isr); + data->pint_id[pin] = pint_idx; + } + + PINT_PinInterruptConfig(config->pint_base, data->pint_id[pin], + interruptMode, + (pint_cb_t)gpio_mcux_lpc_port_isr); + + WRITE_BIT(data->pin_callback_enables, pin, mode != GPIO_INT_DISABLE); + + return 0; +} + +static int gpio_mcux_lpc_manage_cb(struct device *port, + struct gpio_callback *callback, bool set) +{ + struct gpio_mcux_lpc_data *data = port->driver_data; + + return gpio_manage_callback(&data->callbacks, callback, set); +} + +static int gpio_mcux_lpc_enable_cb(struct device *port, int access_op, + u32_t pin) +{ + struct gpio_mcux_lpc_data *data = port->driver_data; + + if (access_op == GPIO_ACCESS_BY_PIN) { + data->pin_callback_enables |= BIT(pin); + } else { + data->pin_callback_enables = 0xFFFFFFFF; + } + + return 0; +} + +static int gpio_mcux_lpc_disable_cb(struct device *port, int access_op, + u32_t pin) +{ + struct gpio_mcux_lpc_data *data = port->driver_data; + + if (access_op == GPIO_ACCESS_BY_PIN) { + data->pin_callback_enables &= ~BIT(pin); + } else { + data->pin_callback_enables = 0U; + } + + return 0; +} + static int gpio_mcux_lpc_init(struct device *dev) { const struct gpio_mcux_lpc_config *config = dev->config->config_info; + struct gpio_mcux_lpc_data *data = dev->driver_data; + int i; CLOCK_EnableClock(config->clock_ip_name); + for (i = 0; i < 32; i++) { + data->pint_id[i] = NO_PINT_INT; + } + + data->isr_list_idx = 0; + return 0; } @@ -124,36 +388,147 @@ static const struct gpio_driver_api gpio_mcux_lpc_driver_api = { .config = gpio_mcux_lpc_configure, .write = gpio_mcux_lpc_write, .read = gpio_mcux_lpc_read, + .port_get_raw = gpio_mcux_lpc_port_get_raw, + .port_set_masked_raw = gpio_mcux_lpc_port_set_masked_raw, + .port_set_bits_raw = gpio_mcux_lpc_port_set_bits_raw, + .port_clear_bits_raw = gpio_mcux_lpc_port_clear_bits_raw, + .port_toggle_bits = gpio_mcux_lpc_port_toggle_bits, + .pin_interrupt_configure = gpio_mcux_lpc_pin_interrupt_configure, + .manage_callback = gpio_mcux_lpc_manage_cb, + .enable_callback = gpio_mcux_lpc_enable_cb, + .disable_callback = gpio_mcux_lpc_disable_cb, }; #ifdef CONFIG_GPIO_MCUX_LPC_PORT0 +static int lpc_gpio_0_init(struct device *dev); + static const struct gpio_mcux_lpc_config gpio_mcux_lpc_port0_config = { .gpio_base = GPIO, + .pint_base = PINT, /* TODO: SECPINT issue #16330 */ + .pinmux_base = IOCON, .port_no = PORT0_IDX, .clock_ip_name = kCLOCK_Gpio0, }; static struct gpio_mcux_lpc_data gpio_mcux_lpc_port0_data; -DEVICE_AND_API_INIT(gpio_mcux_lpc_port0, CONFIG_GPIO_MCUX_LPC_PORT0_NAME, - gpio_mcux_lpc_init, - &gpio_mcux_lpc_port0_data, &gpio_mcux_lpc_port0_config, - POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, +DEVICE_AND_API_INIT(gpio_mcux_lpc_port0, DT_INST_0_NXP_LPC_GPIO_LABEL, + lpc_gpio_0_init, &gpio_mcux_lpc_port0_data, + &gpio_mcux_lpc_port0_config, POST_KERNEL, + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &gpio_mcux_lpc_driver_api); + +static int lpc_gpio_0_init(struct device *dev) +{ +#if defined(DT_INST_0_NXP_LPC_GPIO_IRQ_0) || \ + defined(DT_INST_0_NXP_LPC_GPIO_IRQ_1) || \ + defined(DT_INST_0_NXP_LPC_GPIO_IRQ_2) || \ + defined(DT_INST_0_NXP_LPC_GPIO_IRQ_3) + struct gpio_mcux_lpc_data *data = dev->driver_data; +#endif + + gpio_mcux_lpc_init(dev); + +#ifdef DT_INST_0_NXP_LPC_GPIO_IRQ_0 + IRQ_CONNECT(DT_INST_0_NXP_LPC_GPIO_IRQ_0, + DT_INST_0_NXP_LPC_GPIO_IRQ_0_PRIORITY, + gpio_mcux_lpc_port_isr, DEVICE_GET(gpio_mcux_lpc_port0), 0); + irq_enable(DT_INST_0_NXP_LPC_GPIO_IRQ_0); + data->isr_list[data->isr_list_idx++] = DT_INST_0_NXP_LPC_GPIO_IRQ_0; +#endif + +#ifdef DT_INST_0_NXP_LPC_GPIO_IRQ_1 + IRQ_CONNECT(DT_INST_0_NXP_LPC_GPIO_IRQ_1, + DT_INST_0_NXP_LPC_GPIO_IRQ_1_PRIORITY, + gpio_mcux_lpc_port_isr, DEVICE_GET(gpio_mcux_lpc_port0), 0); + irq_enable(DT_INST_0_NXP_LPC_GPIO_IRQ_1); + data->isr_list[data->isr_list_idx++] = DT_INST_0_NXP_LPC_GPIO_IRQ_1; +#endif + +#ifdef DT_INST_0_NXP_LPC_GPIO_IRQ_2 + IRQ_CONNECT(DT_INST_0_NXP_LPC_GPIO_IRQ_2, + DT_INST_0_NXP_LPC_GPIO_IRQ_2_PRIORITY, + gpio_mcux_lpc_port_isr, DEVICE_GET(gpio_mcux_lpc_port0), 0); + irq_enable(DT_INST_0_NXP_LPC_GPIO_IRQ_2); + data->isr_list[data->isr_list_idx++] = DT_INST_0_NXP_LPC_GPIO_IRQ_2; +#endif + +#ifdef DT_INST_0_NXP_LPC_GPIO_IRQ_3 + IRQ_CONNECT(DT_INST_0_NXP_LPC_GPIO_IRQ_3, + DT_INST_0_NXP_LPC_GPIO_IRQ_3_PRIORITY, + gpio_mcux_lpc_port_isr, DEVICE_GET(gpio_mcux_lpc_port0), 0); + irq_enable(DT_INST_0_NXP_LPC_GPIO_IRQ_3); + data->isr_list[data->isr_list_idx++] = DT_INST_0_NXP_LPC_GPIO_IRQ_3; +#endif + + return 0; +} + #endif /* CONFIG_GPIO_MCUX_LPC_PORT0 */ #ifdef CONFIG_GPIO_MCUX_LPC_PORT1 +static int lpc_gpio_1_init(struct device *dev); + static const struct gpio_mcux_lpc_config gpio_mcux_lpc_port1_config = { .gpio_base = GPIO, + .pint_base = PINT, + .pinmux_base = IOCON, .port_no = PORT1_IDX, .clock_ip_name = kCLOCK_Gpio1, }; static struct gpio_mcux_lpc_data gpio_mcux_lpc_port1_data; -DEVICE_AND_API_INIT(gpio_mcux_lpc_port1, CONFIG_GPIO_MCUX_LPC_PORT1_NAME, - gpio_mcux_lpc_init, - &gpio_mcux_lpc_port1_data, &gpio_mcux_lpc_port1_config, - POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, +DEVICE_AND_API_INIT(gpio_mcux_lpc_port1, DT_INST_1_NXP_LPC_GPIO_LABEL, + lpc_gpio_1_init, &gpio_mcux_lpc_port1_data, + &gpio_mcux_lpc_port1_config, POST_KERNEL, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &gpio_mcux_lpc_driver_api); + +static int lpc_gpio_1_init(struct device *dev) +{ +#if defined(DT_INST_1_NXP_LPC_GPIO_IRQ_0) || \ + defined(DT_INST_1_NXP_LPC_GPIO_IRQ_1) || \ + defined(DT_INST_1_NXP_LPC_GPIO_IRQ_2) || \ + defined(DT_INST_1_NXP_LPC_GPIO_IRQ_3) + struct gpio_mcux_lpc_data *data = dev->driver_data; +#endif + + gpio_mcux_lpc_init(dev); + +#ifdef DT_INST_1_NXP_LPC_GPIO_IRQ_0 + IRQ_CONNECT(DT_INST_1_NXP_LPC_GPIO_IRQ_0, + DT_INST_1_NXP_LPC_GPIO_IRQ_0_PRIORITY, + gpio_mcux_lpc_port_isr, DEVICE_GET(gpio_mcux_lpc_port1), 0); + irq_enable(DT_INST_1_NXP_LPC_GPIO_IRQ_0); + data->isr_list[data->isr_list_idx++] = DT_INST_1_NXP_LPC_GPIO_IRQ_0; +#endif + +#ifdef DT_INST_1_NXP_LPC_GPIO_IRQ_1 + IRQ_CONNECT(DT_INST_1_NXP_LPC_GPIO_IRQ_1, + DT_INST_1_NXP_LPC_GPIO_IRQ_1_PRIORITY, + gpio_mcux_lpc_port_isr, DEVICE_GET(gpio_mcux_lpc_port1), 0); + irq_enable(DT_INST_1_NXP_LPC_GPIO_IRQ_1); + data->isr_list[data->isr_list_idx++] = DT_INST_1_NXP_LPC_GPIO_IRQ_1; +#endif + +#ifdef DT_INST_1_NXP_LPC_GPIO_IRQ_2 + IRQ_CONNECT(DT_INST_1_NXP_LPC_GPIO_IRQ_2, + DT_INST_1_NXP_LPC_GPIO_IRQ_2_PRIORITY, + gpio_mcux_lpc_port_isr, DEVICE_GET(gpio_mcux_lpc_port1), 0); + irq_enable(DT_INST_1_NXP_LPC_GPIO_IRQ_2); + data->isr_list[data->isr_list_idx++] = DT_INST_1_NXP_LPC_GPIO_IRQ_2; +#endif + +#ifdef DT_INST_1_NXP_LPC_GPIO_IRQ_3 + IRQ_CONNECT(DT_INST_1_NXP_LPC_GPIO_IRQ_3, + DT_INST_1_NXP_LPC_GPIO_IRQ_3_PRIORITY, + gpio_mcux_lpc_port_isr, DEVICE_GET(gpio_mcux_lpc_port1), 0); + irq_enable(DT_INST_1_NXP_LPC_GPIO_IRQ_3); + data->isr_list[data->isr_list_idx++] = DT_INST_1_NXP_LPC_GPIO_IRQ_3; +#endif + + return 0; +} + #endif /* CONFIG_GPIO_MCUX_LPC_PORT1 */ diff --git a/dts/arm/nxp/nxp_lpc54xxx.dtsi b/dts/arm/nxp/nxp_lpc54xxx.dtsi index 31dad79df35a9..e12c316d0c62e 100644 --- a/dts/arm/nxp/nxp_lpc54xxx.dtsi +++ b/dts/arm/nxp/nxp_lpc54xxx.dtsi @@ -58,18 +58,18 @@ }; gpio0: gpio@0 { - compatible = "nxp,kinetis-gpio"; + compatible = "nxp,lpc-gpio"; reg = <0x4008c000 0x2488>; - interrupts = <2 2>; + interrupts = <4 2>,<5 2>,<6 2>,<7 2>; label = "GPIO_0"; gpio-controller; #gpio-cells = <2>; }; gpio1: gpio@1 { - compatible = "nxp,kinetis-gpio"; + compatible = "nxp,lpc-gpio"; reg = <0x4008C000 0x2488>; - interrupts = <3 2>; + interrupts = <32 2>,<33 2>,<34 2>,<35 2>; label = "GPIO_1"; gpio-controller; #gpio-cells = <2>; diff --git a/dts/arm/nxp/nxp_lpc55S6x.dtsi b/dts/arm/nxp/nxp_lpc55S6x.dtsi index 094dc26a2fda8..a8f7b732e1207 100644 --- a/dts/arm/nxp/nxp_lpc55S6x.dtsi +++ b/dts/arm/nxp/nxp_lpc55S6x.dtsi @@ -63,23 +63,39 @@ status = "disabled"; }; - gpio0: gpio@0 { - compatible = "nxp,kinetis-gpio"; + gpio0:gpio@0 { + compatible = "nxp,lpc-gpio"; reg = <0x5008c000 0x2488>; - interrupts = <2 2>; + interrupts = <4 2>,<5 2>,<6 2>,<7 2>; label = "GPIO_0"; gpio-controller; #gpio-cells = <2>; }; - gpio1: gpio@1 { - compatible = "nxp,kinetis-gpio"; + gpio1:gpio@1 { + compatible = "nxp,lpc-gpio"; reg = <0x5008c000 0x2488>; - interrupts = <3 2>; + interrupts = <32 2>,<33 2>,<34 2>,<35 2>; label = "GPIO_1"; gpio-controller; #gpio-cells = <2>; }; + + gpio2:gpio@2 { + compatible = "nxp,lpc-gpio"; + reg = <0x5008c000 0x2488>; + label = "GPIO_2"; + gpio-controller; + #gpio-cells = <2>; + }; + + gpio3:gpio@3 { + compatible = "nxp,lpc-gpio"; + reg = <0x5008c000 0x2488>; + label = "GPIO_3"; + gpio-controller; + #gpio-cells = <2>; + }; }; }; diff --git a/dts/bindings/gpio/nxp,lpc-gpio.yaml b/dts/bindings/gpio/nxp,lpc-gpio.yaml new file mode 100644 index 0000000000000..3b18a3ae9a28e --- /dev/null +++ b/dts/bindings/gpio/nxp,lpc-gpio.yaml @@ -0,0 +1,26 @@ +# Copyright (c) 2019, NXP +# SPDX-License-Identifier: Apache-2.0 + +title: LPC GPIO + +description: > + This is a representation of the LPC GPIO nodes + +compatible: "nxp,lpc-gpio" + +include: [gpio-controller.yaml, base.yaml] + +properties: + reg: + required: true + + label: + required: true + + "#gpio-cells": + const: 2 + +gpio-cells: + - pin + - flags +... \ No newline at end of file diff --git a/soc/arm/nxp_lpc/lpc54xxx/soc.c b/soc/arm/nxp_lpc/lpc54xxx/soc.c index 869a85f9ef5b5..a9273d7769d91 100644 --- a/soc/arm/nxp_lpc/lpc54xxx/soc.c +++ b/soc/arm/nxp_lpc/lpc54xxx/soc.c @@ -24,6 +24,7 @@ #include #include #include +#include /** * @@ -90,6 +91,11 @@ static int nxp_lpc54114_init(struct device *arg) /* Initialize FRO/system clock to 48 MHz */ clock_init(); +#ifdef CONFIG_GPIO_MCUX_LPC + /* Turn on PINT device*/ + PINT_Init(PINT); +#endif + /* * install default handler that simply resets the CPU if configured in * the kernel, NOP otherwise diff --git a/soc/arm/nxp_lpc/lpc54xxx/soc.h b/soc/arm/nxp_lpc/lpc54xxx/soc.h index 91d7dd0744ed3..3372c51ab1057 100644 --- a/soc/arm/nxp_lpc/lpc54xxx/soc.h +++ b/soc/arm/nxp_lpc/lpc54xxx/soc.h @@ -34,5 +34,6 @@ #define IOCON_PIO_OPENDRAIN_DI 0x00u #define IOCON_PIO_SLEW_STANDARD 0x00u #define IOCON_PIO_MODE_PULLUP 0x10u +#define IOCON_PIO_MODE_PULLDOWN 0x08u #endif /* _SOC__H_ */ diff --git a/soc/arm/nxp_lpc/lpc55xxx/soc.c b/soc/arm/nxp_lpc/lpc55xxx/soc.c index 8a7eb674f7651..29e25342185d8 100644 --- a/soc/arm/nxp_lpc/lpc55xxx/soc.c +++ b/soc/arm/nxp_lpc/lpc55xxx/soc.c @@ -24,6 +24,7 @@ #include #include #include +#include /** * @@ -84,9 +85,14 @@ static int nxp_lpc55s69_init(struct device *arg) z_arm_clear_faults(); - /* Initialize FRO/system clock to 48 MHz */ + /* Initialize FRO/system clock to 96 MHz */ clock_init(); +#ifdef CONFIG_GPIO_MCUX_LPC + /* Turn on PINT device*/ + PINT_Init(PINT); +#endif + /* * install default handler that simply resets the CPU if configured in * the kernel, NOP otherwise diff --git a/tests/drivers/gpio/gpio_basic_api/boards/lpcxpresso54114_m4.overlay b/tests/drivers/gpio/gpio_basic_api/boards/lpcxpresso54114_m4.overlay new file mode 100644 index 0000000000000..1c161abe96232 --- /dev/null +++ b/tests/drivers/gpio/gpio_basic_api/boards/lpcxpresso54114_m4.overlay @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2019, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + resources { + compatible = "test,gpio_basic_api"; + out-gpios = <&gpio0 8 0>; /* Arduino D0 */ + in-gpios = <&gpio0 9 0>; /* Arduino D1 */ + }; +}; diff --git a/tests/drivers/gpio/gpio_basic_api/boards/lpcxpresso55s69_cpu0.overlay b/tests/drivers/gpio/gpio_basic_api/boards/lpcxpresso55s69_cpu0.overlay new file mode 100644 index 0000000000000..cecc632da6d39 --- /dev/null +++ b/tests/drivers/gpio/gpio_basic_api/boards/lpcxpresso55s69_cpu0.overlay @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2019, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + resources { + compatible = "test,gpio_basic_api"; + out-gpios = <&gpio0 16 0>; /* Arduino A0 */ + in-gpios = <&gpio0 23 0>; /* Arduino A1 */ + }; +}; diff --git a/tests/drivers/gpio/gpio_basic_api/src/main.c b/tests/drivers/gpio/gpio_basic_api/src/main.c index a7dc9bda5925b..b4adadbcedfcd 100644 --- a/tests/drivers/gpio/gpio_basic_api/src/main.c +++ b/tests/drivers/gpio/gpio_basic_api/src/main.c @@ -8,15 +8,16 @@ #include "test_gpio.h" /* Grotesque hack for pinmux boards */ -#ifdef CONFIG_BOARD_FRDM_K64F +#if defined(CONFIG_BOARD_FRDM_K64F) #include #include #elif defined(CONFIG_BOARD_UDOO_NEO_FULL_M4) #include "device_imx.h" -#endif - -#ifdef CONFIG_BOARD_MIMXRT1050_EVK +#elif defined(CONFIG_BOARD_MIMXRT1050_EVK) #include +#elif defined(CONFIG_SOC_FAMILY_LPC) +#include +#include "soc.h" #endif static void board_setup(void) @@ -32,7 +33,7 @@ static void board_setup(void) } #endif -#ifdef CONFIG_BOARD_FRDM_K64F +#if defined(CONFIG_BOARD_FRDM_K64F) /* TODO figure out how to get this from "GPIO_2" */ const char *pmx_name = "portc"; struct device *pmx = device_get_binding(pmx_name); @@ -81,9 +82,7 @@ static void board_setup(void) IOMUXC_SW_PAD_CTL_PAD_RGMII2_RD3_PKE_MASK | IOMUXC_SW_PAD_CTL_PAD_RGMII2_RD3_SPEED(2) | IOMUXC_SW_PAD_CTL_PAD_RGMII2_RD3_DSE(6); -#endif - -#ifdef CONFIG_BOARD_MIMXRT1050_EVK +#elif defined(CONFIG_BOARD_MIMXRT1050_EVK) IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_06_GPIO1_IO22, 0); IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_07_GPIO1_IO23, 0); @@ -97,6 +96,19 @@ static void board_setup(void) IOMUXC_SW_PAD_CTL_PAD_PKE_MASK | IOMUXC_SW_PAD_CTL_PAD_SPEED(2) | IOMUXC_SW_PAD_CTL_PAD_DSE(6)); +#elif defined(CONFIG_SOC_FAMILY_LPC) + /* Assumes ARDUINO pins are mapped on PORT0 on all boards*/ + struct device *port0 = + device_get_binding(CONFIG_PINMUX_MCUX_LPC_PORT0_NAME); + const u32_t pin_config = ( + IOCON_PIO_FUNC0 | + IOCON_PIO_INV_DI | + IOCON_PIO_DIGITAL_EN | + IOCON_PIO_INPFILT_OFF | + IOCON_PIO_OPENDRAIN_DI + ); + pinmux_pin_set(port0, PIN_IN, pin_config); + pinmux_pin_set(port0, PIN_OUT, pin_config); #endif } diff --git a/tests/drivers/gpio/gpio_basic_api/src/test_gpio_port.c b/tests/drivers/gpio/gpio_basic_api/src/test_gpio_port.c index a97b5610c3b46..55b16ad21ba84 100644 --- a/tests/drivers/gpio/gpio_basic_api/src/test_gpio_port.c +++ b/tests/drivers/gpio/gpio_basic_api/src/test_gpio_port.c @@ -415,7 +415,7 @@ static int check_pulls(void) return TC_FAIL; } zassert_equal(raw_in(), false, - "logical pull-up does not read low"); + "logical pull-down does not read low"); zassert_equal(logic_in(), true, "logical pull-down reads false"); diff --git a/west.yml b/west.yml index 25d8890834d35..9516661f504df 100644 --- a/west.yml +++ b/west.yml @@ -83,7 +83,7 @@ manifest: revision: bc62a2fa9d98ddb5d633c932ea199bc68e10f194 path: modules/fs/nffs - name: hal_nxp - revision: 97265a5396edc6a9de5f2fb643d505f37064e606 + revision: 47914cb291b3cfdea8248bd15787d7d733f71729 path: modules/hal/nxp - name: open-amp revision: 9b591b289e1f37339bd038b5a1f0e6c8ad39c63a