Commit 5184fb92 authored by TOKITA Hiroshi's avatar TOKITA Hiroshi Committed by Benjamin Cabé
Browse files

drivers: gpio: rpi_pico: Add support for RP2350B

As the RP2350B has more than 32 GPIO pins,
we changed the configuration so that it is split into two ports.

To do this, we created a `raspberrypi,pico-gpio-port` node and
moved the previous `raspberrypi,pico-gpio-port` functions to it.

This became a child node of `raspberrypi,pico-gpio-port`, and
`raspberrypi,pico-gpio-port` will remain a gpio mapper.

Signed-off-by: default avatarTOKITA Hiroshi <tokita.hiroshi@gmail.com>
parent 47655aa2
Loading
Loading
Loading
Loading
+1 −1
Changes for boards/raspberrypi/rpi_pico2/rpi_pico2.dtsi: 1 added line, 1 removed line.
Original line number Diff line number Diff line
@@ -97,7 +97,7 @@
	pinctrl-names = "default";
};

&gpio0 {
gpio0_lo: &gpio0 {
	status = "okay";
};

+12 −0
Changes for doc/releases/migration-guide-4.2.rst: 12 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -37,9 +37,21 @@ Boards
Device Drivers and Devicetree
*****************************

Ethernet
========

* Removed Kconfig option ``ETH_STM32_HAL_MII`` (:github:`86074`).
  PHY interface type is now selected via the ``phy-connection-type`` property in the device tree.

GPIO
====

* To support the RP2350B, which has many pins, the RaspberryPi-GPIO configuration has
  been changed. The previous role of :dtcompatible:`raspberrypi,rpi-gpio` has been migrated to
  :dtcompatible:`raspberrypi,rpi-gpio-port`, and :dtcompatible:`raspberrypi,rpi-gpio` is
  now left as a placeholder and mapper.
  The labels have also been changed along, so no changes are necessary for regular use.

Bluetooth
*********

+1 −1
Changes for drivers/gpio/Kconfig.rpi_pico: 1 added line, 1 removed line.
Original line number Diff line number Diff line
@@ -3,7 +3,7 @@

config GPIO_RPI_PICO
	default y
	depends on DT_HAS_RASPBERRYPI_PICO_GPIO_ENABLED
	depends on DT_HAS_RASPBERRYPI_PICO_GPIO_PORT_ENABLED
	select PICOSDK_USE_GPIO
	select PINCTRL
	bool "Raspberry Pi Pico GPIO driver"
+185 −50
Changes for drivers/gpio/gpio_rpi_pico.c: 185 added lines, 50 removed lines.
Original line number Diff line number Diff line
@@ -16,28 +16,115 @@

#include <zephyr/drivers/gpio/gpio_utils.h>

#define DT_DRV_COMPAT raspberrypi_pico_gpio
#define DT_DRV_COMPAT raspberrypi_pico_gpio_port

#define ALL_EVENTS (GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE \
		| GPIO_IRQ_LEVEL_LOW | GPIO_IRQ_LEVEL_HIGH)

#define GPIO_RPI_PINS_PER_PORT 32

#define ADDR_IS_ZERO(n, x)     (DT_INST_REG_ADDR(n) == 0) |
#define ADDR_IS_NON_ZERO(n, x) (DT_INST_REG_ADDR(n) != 0) |
#define GPIO_RPI_LO_AVAILABLE  (DT_INST_FOREACH_STATUS_OKAY_VARGS(ADDR_IS_ZERO) 0)
#define GPIO_RPI_HI_AVAILABLE  (DT_INST_FOREACH_STATUS_OKAY_VARGS(ADDR_IS_NON_ZERO) 0)

#if GPIO_RPI_HI_AVAILABLE
#define PORT_NO(port) ((((struct gpio_rpi_config *)port->config)->high_dev != NULL) ? 0 : 1)
#else
#define PORT_NO(port) ((int)port & 0) /* generate zero and suppress unused warning */
#endif

struct gpio_rpi_config {
	struct gpio_driver_config common;
	void (*bank_config_func)(void);
#if GPIO_RPI_HI_AVAILABLE
	const struct device *high_dev;
#endif
};

struct gpio_rpi_data {
	struct gpio_driver_data common;
	sys_slist_t callbacks;
	uint32_t int_enabled_mask;
	uint32_t single_ended_mask;
	uint32_t open_drain_mask;
};

static inline void gpio_set_dir_out_masked_n(uint n, uint32_t mask)
{
	if (!n) {
		gpio_set_dir_out_masked(mask);
	} else if (n == 1) {
#if PICO_USE_GPIO_COPROCESSOR
		gpioc_hi_oe_set(mask);
#else
		sio_hw->gpio_hi_oe_set = mask;
#endif
	}
}

static inline void gpio_set_dir_in_masked_n(uint n, uint32_t mask)
{
	if (!n) {
		gpio_set_dir_in_masked(mask);
	} else if (n == 1) {
#if PICO_USE_GPIO_COPROCESSOR
		gpioc_hi_oe_clr(mask);
#else
		sio_hw->gpio_hi_oe_clr = mask;
#endif
	}
}

static inline void gpio_set_dir_masked_n(uint n, uint32_t mask, uint32_t value)
{
	if (!n) {
		gpio_set_dir_masked(mask, value);
	} else if (n == 1) {
#if PICO_USE_GPIO_COPROCESSOR
		gpioc_hi_oe_xor((gpioc_hi_oe_get() ^ value) & mask);
#else
		sio_hw->gpio_oe_togl = (sio_hw->gpio_hi_oe ^ value) & mask;
#endif
	}
}

static inline uint32_t gpio_get_all_n(uint n)
{
	if (!n) {
		return gpio_get_all();
	} else if (n == 1) {
#if PICO_USE_GPIO_COPROCESSOR
		return gpioc_hi_in_get();
#else
		return sio_hw->gpio_hi_in;
#endif
	}

	return 0;
}

static inline void gpio_toggle_dir_masked_n(uint n, uint32_t mask)
{
	if (!n) {
#if PICO_USE_GPIO_COPROCESSOR
		gpioc_lo_oe_xor(mask);
#else
		sio_hw->gpio_oe_togl = mask;
#endif
	} else if (n == 1) {
#if PICO_USE_GPIO_COPROCESSOR
		gpioc_hi_oe_xor(mask);
#else
		sio_hw->gpio_hi_oe_togl = mask;
#endif
	}
}

static int gpio_rpi_configure(const struct device *dev,
				gpio_pin_t pin,
				gpio_flags_t flags)
{
	const int offset = GPIO_RPI_PINS_PER_PORT * PORT_NO(dev);
	struct gpio_rpi_data *data = dev->data;

	if (flags == GPIO_DISCONNECTED) {
@@ -51,17 +138,15 @@ static int gpio_rpi_configure(const struct device *dev,
		return 0;
	}

	gpio_set_pulls(pin,
		(flags & GPIO_PULL_UP) != 0U,
		(flags & GPIO_PULL_DOWN) != 0U);
	gpio_set_pulls(pin + offset, (flags & GPIO_PULL_UP) != 0U, (flags & GPIO_PULL_DOWN) != 0U);

	/* Avoid gpio_init, since that also clears previously set direction/high/low */
	gpio_set_function(pin, GPIO_FUNC_SIO);
	gpio_set_function(pin + offset, GPIO_FUNC_SIO);

	if (flags & GPIO_INPUT) {
		gpio_set_dir(pin, GPIO_IN);
		gpio_set_dir(pin + offset, GPIO_IN);
	} else {
		gpio_set_input_enabled(pin, false);
		gpio_set_input_enabled(pin + offset, false);
	}

	if (flags & GPIO_OUTPUT) {
@@ -75,21 +160,21 @@ static int gpio_rpi_configure(const struct device *dev,
			 */
			if (flags & GPIO_LINE_OPEN_DRAIN) {
				data->open_drain_mask |= BIT(pin);
				gpio_put(pin, 0);
				gpio_set_dir(pin, flags & GPIO_OUTPUT_INIT_LOW);
				gpio_put(pin + offset, 0);
				gpio_set_dir(pin + offset, flags & GPIO_OUTPUT_INIT_LOW);
			} else {
				data->open_drain_mask &= ~(BIT(pin));
				gpio_put(pin, 1);
				gpio_set_dir(pin, flags & GPIO_OUTPUT_INIT_HIGH);
				gpio_put(pin + offset, 1);
				gpio_set_dir(pin + offset, flags & GPIO_OUTPUT_INIT_HIGH);
			}
		} else {
			data->single_ended_mask &= ~(BIT(pin));
			if (flags & GPIO_OUTPUT_INIT_HIGH) {
				gpio_put(pin, 1);
				gpio_put(pin + offset, 1);
			} else if (flags & GPIO_OUTPUT_INIT_LOW) {
				gpio_put(pin, 0);
				gpio_put(pin + offset, 0);
			}
			gpio_set_dir(pin, GPIO_OUT);
			gpio_set_dir(pin + offset, GPIO_OUT);
		}
	}

@@ -99,20 +184,21 @@ static int gpio_rpi_configure(const struct device *dev,
#ifdef CONFIG_GPIO_GET_CONFIG
static int gpio_rpi_get_config(const struct device *dev, gpio_pin_t pin, gpio_flags_t *flags)
{
	const int offset = GPIO_RPI_PINS_PER_PORT * PORT_NO(dev);
	struct gpio_rpi_data *data = dev->data;

	*flags = 0;

	/* RP2xxxx supports Bus Keeper mode where both pull-up and pull-down are enabled. */
	if (gpio_is_pulled_up(pin)) {
	if (gpio_is_pulled_up(pin + offset)) {
		*flags |= GPIO_PULL_UP;
	}
	if (gpio_is_pulled_down(pin)) {
	if (gpio_is_pulled_down(pin + offset)) {
		*flags |= GPIO_PULL_DOWN;
	}

	if (gpio_get_dir(pin)) {
		*flags |= gpio_get_out_level(pin) ? GPIO_OUTPUT_HIGH : GPIO_OUTPUT_LOW;
	if (gpio_get_dir(pin + offset)) {
		*flags |= gpio_get_out_level(pin + offset) ? GPIO_OUTPUT_HIGH : GPIO_OUTPUT_LOW;
		if (data->single_ended_mask & BIT(pin)) {
			*flags |=
				data->open_drain_mask & BIT(pin) ? GPIO_OPEN_DRAIN : GPIO_PUSH_PULL;
@@ -127,9 +213,10 @@ static int gpio_rpi_get_config(const struct device *dev, gpio_pin_t pin, gpio_fl
}
#endif

static int gpio_rpi_port_get_raw(const struct device *dev, uint32_t *value)
static int gpio_rpi_port_get_raw(const struct device *port, uint32_t *value)
{
	*value = gpio_get_all();
	*value = gpio_get_all_n(PORT_NO(port));

	return 0;
}

@@ -137,12 +224,16 @@ static int gpio_rpi_port_set_masked_raw(const struct device *port,
					uint32_t mask, uint32_t value)
{
	struct gpio_rpi_data *data = port->data;

	/* First handle push-pull pins: */
	gpio_put_masked(mask & ~data->single_ended_mask, value);
	gpio_put_masked_n(PORT_NO(port), mask & ~data->single_ended_mask, value);
	/* Then handle open-drain pins: */
	gpio_set_dir_masked(mask & data->single_ended_mask & data->open_drain_mask, ~value);
	gpio_set_dir_masked_n(PORT_NO(port), mask & data->single_ended_mask & data->open_drain_mask,
			      ~value);
	/* Then handle open-source pins: */
	gpio_set_dir_masked(mask & data->single_ended_mask & ~data->open_drain_mask, value);
	gpio_set_dir_masked_n(PORT_NO(port),
			      mask & data->single_ended_mask & ~data->open_drain_mask, value);

	return 0;
}

@@ -150,12 +241,16 @@ static int gpio_rpi_port_set_bits_raw(const struct device *port,
					uint32_t pins)
{
	struct gpio_rpi_data *data = port->data;

	/* First handle push-pull pins: */
	gpio_set_mask(pins & ~data->single_ended_mask);
	gpio_set_mask_n(PORT_NO(port), pins & ~data->single_ended_mask);
	/* Then handle open-drain pins: */
	gpio_set_dir_in_masked(pins & data->single_ended_mask & data->open_drain_mask);
	gpio_set_dir_in_masked_n(PORT_NO(port),
				 pins & data->single_ended_mask & data->open_drain_mask);
	/* Then handle open-source pins: */
	gpio_set_dir_out_masked(pins & data->single_ended_mask & ~data->open_drain_mask);
	gpio_set_dir_out_masked_n(PORT_NO(port),
				  pins & data->single_ended_mask & ~data->open_drain_mask);

	return 0;
}

@@ -163,12 +258,16 @@ static int gpio_rpi_port_clear_bits_raw(const struct device *port,
					uint32_t pins)
{
	struct gpio_rpi_data *data = port->data;

	/* First handle push-pull pins: */
	gpio_clr_mask(pins & ~data->single_ended_mask);
	gpio_clr_mask_n(PORT_NO(port), pins & ~data->single_ended_mask);
	/* Then handle open-drain pins: */
	gpio_set_dir_out_masked(pins & data->single_ended_mask & data->open_drain_mask);
	gpio_set_dir_out_masked_n(PORT_NO(port),
				  pins & data->single_ended_mask & data->open_drain_mask);
	/* Then handle open-source pins: */
	gpio_set_dir_in_masked(pins & data->single_ended_mask & ~data->open_drain_mask);
	gpio_set_dir_in_masked_n(PORT_NO(port),
				 pins & data->single_ended_mask & ~data->open_drain_mask);

	return 0;
}

@@ -176,13 +275,12 @@ static int gpio_rpi_port_toggle_bits(const struct device *port,
					uint32_t pins)
{
	struct gpio_rpi_data *data = port->data;

	/* First handle push-pull pins: */
	gpio_xor_mask(pins & ~data->single_ended_mask);
	gpio_xor_mask_n(PORT_NO(port), pins & ~data->single_ended_mask);
	/* Then handle single-ended pins: */
	/* (unfortunately there's no pico-sdk api call that can be used for this,
	 * but it's possible by accessing the registers directly)
	 */
	sio_hw->gpio_oe_togl = (pins & data->single_ended_mask);
	gpio_toggle_dir_masked_n(PORT_NO(port), pins & data->single_ended_mask);

	return 0;
}

@@ -191,10 +289,10 @@ static int gpio_rpi_pin_interrupt_configure(const struct device *dev,
						enum gpio_int_mode mode,
						enum gpio_int_trig trig)
{
	struct gpio_rpi_data *data = dev->data;
	const int offset = GPIO_RPI_PINS_PER_PORT * PORT_NO(dev);
	uint32_t events = 0;

	gpio_set_irq_enabled(pin, ALL_EVENTS, false);
	gpio_set_irq_enabled(pin + offset, ALL_EVENTS, false);
	if (mode != GPIO_INT_DISABLE) {
		if (mode & GPIO_INT_EDGE) {
			if (trig & GPIO_INT_LOW_0) {
@@ -211,9 +309,9 @@ static int gpio_rpi_pin_interrupt_configure(const struct device *dev,
				events |= GPIO_IRQ_LEVEL_HIGH;
			}
		}
		gpio_set_irq_enabled(pin, events, true);
		gpio_set_irq_enabled(pin + offset, events, true);
	}
	WRITE_BIT(data->int_enabled_mask, pin, mode != GPIO_INT_DISABLE);

	return 0;
}

@@ -296,6 +394,18 @@ static void gpio_rpi_isr(const struct device *dev)
		events = (*status_reg >> 4 * (pin % 8)) & ALL_EVENTS;
		if (events) {
			gpio_acknowledge_irq(pin, ALL_EVENTS);

#if GPIO_RPI_HI_AVAILABLE
			if (pin >= GPIO_RPI_PINS_PER_PORT) {
				const struct gpio_rpi_config *config = dev->config;
				struct gpio_rpi_data *high_data = config->high_dev->data;

				gpio_fire_callbacks(&high_data->callbacks, config->high_dev,
						    BIT(pin - GPIO_RPI_PINS_PER_PORT));
				continue;
			}
#endif

			gpio_fire_callbacks(&data->callbacks, dev, BIT(pin));
		}
	}
@@ -305,31 +415,56 @@ static int gpio_rpi_bank_init(const struct device *dev)
{
	const struct gpio_rpi_config *config = dev->config;

	if (config->bank_config_func != NULL) {
		config->bank_config_func();
	}

	return 0;
}

#define GPIO_REG_0U            1
#define IS_GPIO_RPI_LO_NODE(n) UTIL_CAT(GPIO_REG_, DT_REG_ADDR(n))

#define DEVICE_IF_GPIO_RPI_HI_NODE(n) COND_CODE_1(IS_GPIO_RPI_LO_NODE(n), (), (DEVICE_DT_GET(n)))

#define FIND_GPIO_RPI_HI_DEVICE(n)                                                                 \
	COND_CODE_1(UTIL_CAT(GPIO_REG_, DT_REG_ADDR(n)),                                           \
			(DT_FOREACH_CHILD(DT_PARENT(n), DEVICE_IF_GPIO_RPI_HI_NODE)), (NULL))

#if GPIO_RPI_HI_AVAILABLE
#define GPIO_RPI_INIT_HIGH_DEV(idx) .high_dev = FIND_GPIO_RPI_HI_DEVICE(DT_DRV_INST(idx)),
#else
#define GPIO_RPI_INIT_HIGH_DEV(idx)
#endif

#define GPIO_RPI_INIT(idx)                                                                         \
	BUILD_ASSERT(DT_CHILD_NUM(DT_INST_PARENT(idx)) > 0 &&                                      \
			     DT_CHILD_NUM(DT_INST_PARENT(idx)) <= 2,                               \
		     "raspberrypi,pico-gpio node must have one or two child node.");               \
	BUILD_ASSERT(GPIO_RPI_LO_AVAILABLE,                                                        \
		     "raspberrypi,pico-gpio node must have reg=0 child node.");                    \
	IF_ENABLED(IS_GPIO_RPI_LO_NODE(DT_DRV_INST(idx)), (                                        \
		static void bank_##idx##_config_func(void)                                         \
		{                                                                                  \
		IRQ_CONNECT(DT_INST_IRQN(idx), DT_INST_IRQ(idx, priority),	\
			IRQ_CONNECT(DT_IRQN(DT_INST_PARENT(idx)),                                  \
				    DT_IRQ(DT_INST_PARENT(idx), priority),                         \
				    gpio_rpi_isr, DEVICE_DT_INST_GET(idx), 0);                     \
		irq_enable(DT_INST_IRQN(idx));					\
			irq_enable(DT_IRQN(DT_INST_PARENT(idx)));                                  \
		}                                                                                  \
	))                                                                                         \
	static const struct gpio_rpi_config gpio_rpi_##idx##_config = {                            \
		.bank_config_func = bank_##idx##_config_func,			\
		.common =							\
		{								\
		.common = {                                                                        \
			.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(idx),                     \
		}								\
		},                                                                                 \
		IF_ENABLED(IS_GPIO_RPI_LO_NODE(DT_DRV_INST(idx)), (                                \
			.bank_config_func = bank_##idx##_config_func,                              \
		))                                                                                 \
		GPIO_RPI_INIT_HIGH_DEV(idx)                                                        \
	};                                                                                         \
										\
	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,		\
	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)
+15 −2
Changes for dts/arm/raspberrypi/rpi_pico/rp2040.dtsi: 15 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -238,15 +238,28 @@
				 "gpin0", "gpin1";
		};

		gpio0: gpio@40014000 {
		gpio0_map: gpio@40014000 {
			compatible = "raspberrypi,pico-gpio";
			reg = <0x40014000 DT_SIZE_K(4)>;
			interrupts = <13 RPI_PICO_DEFAULT_IRQ_PRIORITY>;
			gpio-controller;

			gpio-map-mask = <0xffffffe0 0xffffffc0>;
			gpio-map-pass-thru = <0x1f 0x3f>;
			gpio-map = <0x0 0x0 &gpio0 0x0 0x0>;

			#gpio-cells = <2>;
			#address-cells = <1>;
			#size-cells = <0>;

			gpio0: gpio-port@0 {
				compatible = "raspberrypi,pico-gpio-port";
				reg = <0x0>;
				status = "disabled";
				gpio-controller;
				#gpio-cells = <2>;
				ngpios = <30>;
			};
		};

		uart0: uart@40034000 {
			compatible = "raspberrypi,pico-uart", "arm,pl011";
Loading