From a2aa02dbc8bbfafefce4e7f09f0e848ae825837d Mon Sep 17 00:00:00 2001 From: Yonatan Schachter Date: Tue, 30 Nov 2021 00:49:38 +0200 Subject: [PATCH] drivers: gpio: Added support for raspberry pi Added GPIO support for the RP2040 SoC. Only one core is supported. Signed-off-by: Yonatan Schachter --- CODEOWNERS | 1 + drivers/gpio/CMakeLists.txt | 1 + drivers/gpio/Kconfig | 2 + drivers/gpio/Kconfig.rpi_pico | 10 + drivers/gpio/gpio_rpi_pico.c | 192 +++++++++++++++++++ dts/arm/rpi_pico/rp2040.dtsi | 11 ++ dts/bindings/gpio/raspberrypi,pico-gpio.yaml | 22 +++ scripts/checkpatch/typedefsfile | 1 + 8 files changed, 240 insertions(+) create mode 100644 drivers/gpio/Kconfig.rpi_pico create mode 100644 drivers/gpio/gpio_rpi_pico.c create mode 100644 dts/bindings/gpio/raspberrypi,pico-gpio.yaml diff --git a/CODEOWNERS b/CODEOWNERS index 4ba97bc6f4c..3f2d5de39cd 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -266,6 +266,7 @@ /drivers/gpio/*eos_s3* @wtatarski @kowalewskijan @kgugala /drivers/gpio/*rcar* @julien-massot /drivers/gpio/*esp32* @glaubermaroto +/drivers/gpio/*rpi_pico* @yonsch /drivers/hwinfo/ @alexanderwachter /drivers/i2c/i2c_common.c @sjg20 /drivers/i2c/i2c_emul.c @sjg20 diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index 32412257a2f..af23733f368 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -30,6 +30,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_SAM4L gpio_sam4l.c) zephyr_library_sources_ifdef(CONFIG_GPIO_SX1509B gpio_sx1509b.c) zephyr_library_sources_ifdef(CONFIG_GPIO_INTEL gpio_intel.c) zephyr_library_sources_ifdef(CONFIG_GPIO_STELLARIS gpio_stellaris.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_RPI_PICO gpio_rpi_pico.c) zephyr_library_sources_ifdef(CONFIG_GPIO_RV32M1 gpio_rv32m1.c) zephyr_library_sources_ifdef(CONFIG_GPIO_LMP90XXX gpio_lmp90xxx.c) zephyr_library_sources_ifdef(CONFIG_GPIO_LITEX gpio_litex.c) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index ccec99316a9..7ff6931a371 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -77,6 +77,8 @@ source "drivers/gpio/Kconfig.xec" source "drivers/gpio/Kconfig.stellaris" +source "drivers/gpio/Kconfig.rpi_pico" + source "drivers/gpio/Kconfig.rv32m1" source "drivers/gpio/Kconfig.lmp90xxx" diff --git a/drivers/gpio/Kconfig.rpi_pico b/drivers/gpio/Kconfig.rpi_pico new file mode 100644 index 00000000000..8bd1488d74f --- /dev/null +++ b/drivers/gpio/Kconfig.rpi_pico @@ -0,0 +1,10 @@ +# Copyright (c) 2021 Yonatan Schachter +# SPDX-License-Identifier: Apache-2.0 + +# Workaround for not being able to have commas in macro arguments +DT_COMPAT_RPI_PICO_GPIO := raspberrypi,pico-gpio + +config GPIO_RPI_PICO + default $(dt_compat_enabled,$(DT_COMPAT_RPI_PICO_GPIO)) + select PICOSDK_USE_GPIO + bool "Raspberry Pi Pico GPIO driver" diff --git a/drivers/gpio/gpio_rpi_pico.c b/drivers/gpio/gpio_rpi_pico.c new file mode 100644 index 00000000000..3593076d9db --- /dev/null +++ b/drivers/gpio/gpio_rpi_pico.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2021, Yonatan Schachter + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/* pico-sdk includes */ +#include +#include +#include + +#include "gpio_utils.h" + +#define DT_DRV_COMPAT raspberrypi_pico_gpio + +#define ALL_EVENTS (GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE \ + | GPIO_IRQ_LEVEL_LOW | GPIO_IRQ_LEVEL_HIGH) + +struct gpio_rpi_config { + struct gpio_driver_config common; + void (*bank_config_func)(void); +}; + +struct gpio_rpi_data { + struct gpio_driver_data common; + sys_slist_t callbacks; + uint32_t int_enabled_mask; +}; + +static int gpio_rpi_configure(const struct device *dev, + gpio_pin_t pin, + gpio_flags_t flags) +{ + if (flags & GPIO_SINGLE_ENDED) { + return -ENOTSUP; + } + + gpio_init(pin); + + if (flags & GPIO_OUTPUT) { + gpio_set_dir(pin, GPIO_OUT); + + if (flags & GPIO_OUTPUT_INIT_HIGH) { + gpio_put(pin, 1); + } else if (flags & GPIO_OUTPUT_INIT_LOW) { + gpio_put(pin, 0); + } + } else if (flags & GPIO_INPUT) { + gpio_set_dir(pin, GPIO_IN); + if (flags & GPIO_PULL_UP) { + gpio_pull_up(pin); + } else if (flags & GPIO_PULL_DOWN) { + gpio_pull_down(pin); + } + } + + return 0; +} + +static int gpio_rpi_port_get_raw(const struct device *dev, uint32_t *value) +{ + *value = gpio_get_all(); + return 0; +} + +static int gpio_rpi_port_set_masked_raw(const struct device *port, + uint32_t mask, uint32_t value) +{ + gpio_put_masked(mask, value); + return 0; +} + +static int gpio_rpi_port_set_bits_raw(const struct device *port, + uint32_t pins) +{ + gpio_set_mask(pins); + return 0; +} + +static int gpio_rpi_port_clear_bits_raw(const struct device *port, + uint32_t pins) +{ + gpio_clr_mask(pins); + return 0; +} + +static int gpio_rpi_port_toggle_bits(const struct device *port, + uint32_t pins) +{ + gpio_xor_mask(pins); + return 0; +} + +static int gpio_rpi_pin_interrupt_configure(const struct device *dev, + gpio_pin_t pin, + enum gpio_int_mode mode, + enum gpio_int_trig trig) +{ + struct gpio_rpi_data *data = dev->data; + uint32_t events = 0; + + if (mode != GPIO_INT_DISABLE) { + if (mode & GPIO_INT_EDGE) { + if (trig & GPIO_INT_LOW_0) { + events |= GPIO_IRQ_EDGE_FALL; + } + if (trig & GPIO_INT_HIGH_1) { + events |= GPIO_IRQ_EDGE_RISE; + } + } else { + if (trig & GPIO_INT_LOW_0) { + events |= GPIO_IRQ_LEVEL_LOW; + } + if (trig & GPIO_INT_HIGH_1) { + events |= GPIO_IRQ_LEVEL_HIGH; + } + } + gpio_set_irq_enabled(pin, events, true); + } + WRITE_BIT(data->int_enabled_mask, pin, mode != GPIO_INT_DISABLE); + return 0; +} + +static int gpio_rpi_manage_callback(const struct device *dev, + struct gpio_callback *callback, bool set) +{ + struct gpio_rpi_data *data = dev->data; + + return gpio_manage_callback(&data->callbacks, callback, set); +} + +static const struct gpio_driver_api gpio_rpi_driver_api = { + .pin_configure = gpio_rpi_configure, + .port_get_raw = gpio_rpi_port_get_raw, + .port_set_masked_raw = gpio_rpi_port_set_masked_raw, + .port_set_bits_raw = gpio_rpi_port_set_bits_raw, + .port_clear_bits_raw = gpio_rpi_port_clear_bits_raw, + .port_toggle_bits = gpio_rpi_port_toggle_bits, + .pin_interrupt_configure = gpio_rpi_pin_interrupt_configure, + .manage_callback = gpio_rpi_manage_callback, +}; + +static void gpio_rpi_isr(const struct device *dev) +{ + struct gpio_rpi_data *data = dev->data; + io_irq_ctrl_hw_t *irq_ctrl_base; + const io_rw_32 *status_reg; + uint32_t events; + uint32_t pin; + + irq_ctrl_base = &iobank0_hw->proc0_irq_ctrl; + for (pin = 0; pin < NUM_BANK0_GPIOS; pin++) { + status_reg = &irq_ctrl_base->ints[pin / 8]; + events = (*status_reg >> 4 * (pin % 8)) & ALL_EVENTS; + if (events) { + gpio_acknowledge_irq(pin, ALL_EVENTS); + gpio_fire_callbacks(&data->callbacks, dev, BIT(pin)); + } + } +} + +static int gpio_rpi_bank_init(const struct device *dev) +{ + const struct gpio_rpi_config *config = dev->config; + + config->bank_config_func(); + return 0; +} + +#define GPIO_RPI_INIT(idx) \ + static void bank_##idx##_config_func(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(idx), DT_INST_IRQ(idx, priority), \ + gpio_rpi_isr, DEVICE_DT_INST_GET(idx), 0); \ + irq_enable(DT_INST_IRQN(idx)); \ + } \ + static const struct gpio_rpi_config gpio_rpi_##idx##_config = { \ + .bank_config_func = bank_##idx##_config_func, \ + }; \ + \ + static struct gpio_rpi_data gpio_rpi_##idx##_data; \ + \ + DEVICE_DT_INST_DEFINE(idx, gpio_rpi_bank_init, NULL, \ + &gpio_rpi_##idx##_data, \ + &gpio_rpi_##idx##_config, \ + POST_KERNEL, CONFIG_GPIO_INIT_PRIORITY, \ + &gpio_rpi_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(GPIO_RPI_INIT) diff --git a/dts/arm/rpi_pico/rp2040.dtsi b/dts/arm/rpi_pico/rp2040.dtsi index dd48076e02b..72d6efeb712 100644 --- a/dts/arm/rpi_pico/rp2040.dtsi +++ b/dts/arm/rpi_pico/rp2040.dtsi @@ -5,6 +5,7 @@ */ #include +#include #include #include "rpi_pico_common.dtsi" @@ -51,6 +52,16 @@ label = "PINCTRL"; }; + gpio0: gpio@40014000 { + compatible = "raspberrypi,pico-gpio"; + reg = <0x40014000 DT_SIZE_K(4)>; + interrupts = <13 RPI_PICO_DEFAULT_IRQ_PRIORITY>; + gpio-controller; + #gpio-cells = <2>; + label = "GPIO_0"; + status = "disabled"; + }; + uart0: uart@40034000 { compatible = "raspberrypi,pico-uart"; reg = <0x40034000 DT_SIZE_K(4)>; diff --git a/dts/bindings/gpio/raspberrypi,pico-gpio.yaml b/dts/bindings/gpio/raspberrypi,pico-gpio.yaml new file mode 100644 index 00000000000..ab987ecb758 --- /dev/null +++ b/dts/bindings/gpio/raspberrypi,pico-gpio.yaml @@ -0,0 +1,22 @@ +# Copyright (c) 2021, Yonatan Schachter +# SPDX-License-Identifier: Apache-2.0 + +description: Raspberry Pi Pico GPIO + +compatible: "raspberrypi,pico-gpio" + +include: [gpio-controller.yaml, base.yaml] + +properties: + reg: + required: true + + label: + required: true + + "#gpio-cells": + const: 2 + +gpio-cells: + - pin + - flags diff --git a/scripts/checkpatch/typedefsfile b/scripts/checkpatch/typedefsfile index 7e030b5b97b..ef5109b1474 100644 --- a/scripts/checkpatch/typedefsfile +++ b/scripts/checkpatch/typedefsfile @@ -3,3 +3,4 @@ k_mem_partition_attr_t mbedtls_pk_context z_arch_esf_t pinctrl_soc_pin_t +io_rw_32