From 33c35da90ddf6779afd6c55ca71e2e6ad6e86767 Mon Sep 17 00:00:00 2001 From: Xing Chen Date: Tue, 1 Jul 2025 12:09:46 +0800 Subject: [PATCH 1/3] drivers: gpio: add gpio for sama7g5 Add driver for sama7g5 GPIO controller (PIO4) Signed-off-by: Xing Chen --- drivers/gpio/CMakeLists.txt | 1 + drivers/gpio/Kconfig.sam | 8 + drivers/gpio/gpio_sam_pio4.c | 360 ++++++++++++++++++ dts/bindings/gpio/microchip,sam-pio4.yaml | 25 ++ .../dt-bindings/gpio/microchip-sam-gpio.h | 38 ++ 5 files changed, 432 insertions(+) create mode 100644 drivers/gpio/gpio_sam_pio4.c create mode 100644 dts/bindings/gpio/microchip,sam-pio4.yaml create mode 100644 include/zephyr/dt-bindings/gpio/microchip-sam-gpio.h diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index 9772dd8e4ef43..80ba7a0628617 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -97,6 +97,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_RZT2M gpio_rzt2m.c) zephyr_library_sources_ifdef(CONFIG_GPIO_SAM gpio_sam.c) zephyr_library_sources_ifdef(CONFIG_GPIO_SAM0 gpio_sam0.c) zephyr_library_sources_ifdef(CONFIG_GPIO_SAM4L gpio_sam4l.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_SAM_PIO4 gpio_sam_pio4.c) zephyr_library_sources_ifdef(CONFIG_GPIO_SEDI gpio_sedi.c) zephyr_library_sources_ifdef(CONFIG_GPIO_SI32 gpio_si32.c) zephyr_library_sources_ifdef(CONFIG_GPIO_SIFIVE gpio_sifive.c) diff --git a/drivers/gpio/Kconfig.sam b/drivers/gpio/Kconfig.sam index fc6a53789ead2..b43c054ad05f9 100644 --- a/drivers/gpio/Kconfig.sam +++ b/drivers/gpio/Kconfig.sam @@ -17,3 +17,11 @@ config GPIO_SAM4L depends on DT_HAS_ATMEL_SAM4L_GPIO_ENABLED help Enable support for the Atmel SAM4L 'PORT' GPIO controllers. + +config GPIO_SAM_PIO4 + bool "Microchip SAM PIO4 GPIO driver" + default y + depends on DT_HAS_MICROCHIP_SAM_PIO4_ENABLED + help + Microchip Parallel Input/Output Controller is used on SAMA5D2 and + SAMA7G5 SoC series diff --git a/drivers/gpio/gpio_sam_pio4.c b/drivers/gpio/gpio_sam_pio4.c new file mode 100644 index 0000000000000..3e7852779303b --- /dev/null +++ b/drivers/gpio/gpio_sam_pio4.c @@ -0,0 +1,360 @@ +/* + * Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#define DT_DRV_COMPAT microchip_sam_pio4 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +typedef void (*config_func_t)(const struct device *dev); + +struct gpio_sam_config { + /* gpio_driver_config needs to be first */ + struct gpio_driver_config common; + pio_group_registers_t *regs; + config_func_t config_func; + + const struct atmel_sam_pmc_config clock_cfg; +}; + +struct gpio_sam_runtime { + /* gpio_driver_data needs to be first */ + struct gpio_driver_data common; + struct k_spinlock lock; + sys_slist_t cb; +}; + +static int gpio_sam_config(const struct device *dev, gpio_pin_t pin, + gpio_flags_t flags) +{ + const struct gpio_sam_config * const cfg = dev->config; + struct gpio_sam_runtime *context = dev->data; + pio_group_registers_t * const pio = cfg->regs; + k_spinlock_key_t key; + const uint32_t mask = BIT(pin); + uint32_t conf; + + /* Check if pin number is out of range */ + if ((mask & cfg->common.port_pin_mask) == 0U) { + return -ENOTSUP; + } + + /* Get PIO configuration */ + key = k_spin_lock(&context->lock); + pio->PIO_MSKR = mask; + conf = pio->PIO_CFGR; + k_spin_unlock(&context->lock, key); + + if ((flags & GPIO_SINGLE_ENDED) != 0U) { + if ((flags & GPIO_LINE_OPEN_DRAIN) != 0U) { + /* Enable open-drain drive mode */ + conf &= ~PIO_S_PIO_CFGR_OPD_Msk; + conf |= PIO_S_PIO_CFGR_OPD(PIO_S_PIO_CFGR_OPD_ENABLED_Val); + } else { + /* Open-drain is the only supported single-ended mode */ + return -ENOTSUP; + } + } else { + /* Disable open-drain drive mode */ + conf &= ~PIO_S_PIO_CFGR_OPD_Msk; + conf |= PIO_S_PIO_CFGR_OPD(PIO_S_PIO_CFGR_OPD_DISABLED_Val); + } + + if ((flags & (GPIO_OUTPUT | GPIO_INPUT)) == 0U) { + /* Neither input nor output mode is selected */ + + /* Disable the interrupt. */ + pio->PIO_IDR = mask; + /* Disable pull-up and pull-down */ + conf &= ~(PIO_CFGR_PUEN_Msk | PIO_CFGR_PDEN_Msk); + + /* Let the PIO control the pin (instead of a peripheral). */ + conf &= ~PIO_S_PIO_CFGR_FUNC_Msk; + /* Disable output. */ + conf &= ~PIO_S_PIO_CFGR_DIR_Msk; + + /* Update PIO configuration */ + key = k_spin_lock(&context->lock); + pio->PIO_MSKR = mask; + pio->PIO_CFGR = conf; + k_spin_unlock(&context->lock, key); + + return 0; + } + + if ((flags & GPIO_OUTPUT) != 0U) { + if ((flags & GPIO_OUTPUT_INIT_LOW) != 0U) { + pio->PIO_CODR = mask; + } + if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0U) { + pio->PIO_SODR = mask; + } + + conf &= ~PIO_S_PIO_CFGR_DIR_Msk; + conf |= PIO_S_PIO_CFGR_DIR(PIO_S_PIO_CFGR_DIR_OUTPUT_Val); + } else { /* GPIO_INPUT */ + conf &= ~PIO_S_PIO_CFGR_DIR_Msk; + conf |= PIO_S_PIO_CFGR_DIR(PIO_S_PIO_CFGR_DIR_INPUT_Val); + } + + /* Disable pull-up and pull-down by default */ + conf &= ~(PIO_CFGR_PUEN_Msk | PIO_CFGR_PDEN_Msk); + if (((flags & GPIO_PULL_UP) != 0U) && ((flags & GPIO_PULL_DOWN) != 0U)) { + return -ENOTSUP; + } + if ((flags & GPIO_PULL_UP) != 0U) { + /* Enable pull-up. */ + conf |= PIO_CFGR_PUEN(PIO_CFGR_PUEN_ENABLED_Val); + } + if ((flags & GPIO_PULL_DOWN) != 0U) { + /* Enable pull-down. */ + conf |= PIO_CFGR_PDEN(PIO_CFGR_PDEN_ENABLED_Val); + } + + /* Processing SAM PIO4 specific flags */ + if ((flags & SAM_GPIO_DIS_SLEWRATE) != 0U) { + /* Disable slew rate control. */ + conf &= ~PIO_CFGR_SR_Msk; + } else { + /* Enable slew rate control by default. */ + conf |= PIO_CFGR_SR(PIO_CFGR_SR_ENABLED_Val); + } + if ((flags & SAM_GPIO_DEBOUNCE) != 0U) { + conf |= PIO_CFGR_IFEN(PIO_CFGR_IFEN_ENABLED_Val); + conf |= PIO_CFGR_IFSCEN(PIO_CFGR_IFSCEN_ENABLED_Val); + } else { + conf &= ~PIO_CFGR_IFEN_Msk; + conf &= ~PIO_CFGR_IFSCEN_Msk; + } + if ((flags & SAM_GPIO_DIS_SCHMIT) != 0U) { + /* Disable schmitt trigger */ + conf |= PIO_CFGR_SCHMITT(PIO_CFGR_SCHMITT_DISABLED_Val); + } + if ((flags & SAM_GPIO_DRVSTR_MASK) != 0U) { + conf &= ~PIO_CFGR_DRVSTR_Msk; + conf |= PIO_CFGR_DRVSTR((flags & SAM_GPIO_DRVSTR_MASK) + >> SAM_GPIO_DRVSTR_POS); + } else { + /* Use default drive strength */ + conf &= ~PIO_CFGR_DRVSTR_Msk; + } + + /* Enable the PIO to control the pin (instead of a peripheral). */ + conf &= ~PIO_S_PIO_CFGR_FUNC_Msk; + conf |= PIO_S_PIO_CFGR_FUNC(PIO_S_PIO_CFGR_FUNC_GPIO_Val); + + /* Update PIO configuration */ + key = k_spin_lock(&context->lock); + pio->PIO_MSKR = mask; + pio->PIO_CFGR = conf; + k_spin_unlock(&context->lock, key); + + return 0; +} + +static int gpio_sam_port_get_raw(const struct device *dev, uint32_t *value) +{ + const struct gpio_sam_config * const cfg = dev->config; + pio_group_registers_t * const pio = cfg->regs; + + *value = pio->PIO_PDSR; + + return 0; +} + +static int gpio_sam_port_set_masked_raw(const struct device *dev, + uint32_t mask, + uint32_t value) +{ + const struct gpio_sam_config * const cfg = dev->config; + pio_group_registers_t * const pio = cfg->regs; + + pio->PIO_ODSR = (pio->PIO_ODSR & ~mask) | (mask & value); + + return 0; +} + +static int gpio_sam_port_set_bits_raw(const struct device *dev, uint32_t mask) +{ + const struct gpio_sam_config * const cfg = dev->config; + pio_group_registers_t * const pio = cfg->regs; + + pio->PIO_SODR = mask; + + return 0; +} + +static int gpio_sam_port_clear_bits_raw(const struct device *dev, + uint32_t mask) +{ + const struct gpio_sam_config * const cfg = dev->config; + pio_group_registers_t * const pio = cfg->regs; + + pio->PIO_CODR = mask; + + return 0; +} + +static int gpio_sam_port_toggle_bits(const struct device *dev, uint32_t mask) +{ + const struct gpio_sam_config * const cfg = dev->config; + pio_group_registers_t * const pio = cfg->regs; + + pio->PIO_ODSR ^= mask; + + return 0; +} + +static int gpio_sam_pin_interrupt_configure(const struct device *dev, + gpio_pin_t pin, + enum gpio_int_mode mode, + enum gpio_int_trig trig) +{ + const struct gpio_sam_config * const cfg = dev->config; + struct gpio_sam_runtime *context = dev->data; + pio_group_registers_t * const pio = cfg->regs; + k_spinlock_key_t key; + const uint32_t mask = BIT(pin); + uint32_t conf; + + /* Check if pin number is out of range */ + if ((mask & cfg->common.port_pin_mask) == 0U) { + return -ENOTSUP; + } + + /* Disable the interrupt. */ + pio->PIO_IDR = mask; + + if (mode == GPIO_INT_MODE_DISABLED) { + return 0; + } + + /* Get PIO configuration */ + key = k_spin_lock(&context->lock); + pio->PIO_MSKR = mask; + conf = pio->PIO_CFGR; + k_spin_unlock(&context->lock, key); + + conf &= ~PIO_S_PIO_CFGR_EVTSEL_Msk; + + if (mode == GPIO_INT_MODE_LEVEL) { + if (trig == GPIO_INT_TRIG_LOW) { + conf |= PIO_S_PIO_CFGR_EVTSEL(PIO_S_PIO_CFGR_EVTSEL_LOW_Val); + } else if (trig == GPIO_INT_TRIG_HIGH) { + conf |= PIO_S_PIO_CFGR_EVTSEL(PIO_S_PIO_CFGR_EVTSEL_HIGH_Val); + } else { + return -ENOTSUP; + } + } else { /* GPIO_INT_MODE_EDGE */ + if (trig == GPIO_INT_TRIG_LOW) { + conf |= PIO_S_PIO_CFGR_EVTSEL(PIO_S_PIO_CFGR_EVTSEL_FALLING_Val); + } else if (trig == GPIO_INT_TRIG_HIGH) { + conf |= PIO_S_PIO_CFGR_EVTSEL(PIO_S_PIO_CFGR_EVTSEL_RISING_Val); + } else if (trig == GPIO_INT_TRIG_BOTH) { + conf |= PIO_S_PIO_CFGR_EVTSEL(PIO_S_PIO_CFGR_EVTSEL_BOTH_Val); + } else { + return -ENOTSUP; + } + } + + /* Update PIO configuration */ + key = k_spin_lock(&context->lock); + pio->PIO_MSKR = mask; + pio->PIO_CFGR = conf; + k_spin_unlock(&context->lock, key); + + /* Clear any pending interrupts */ + (void)pio->PIO_ISR; + /* Enable the interrupt. */ + pio->PIO_IER = mask; + + return 0; +} + +static void gpio_sam_isr(const struct device *dev) +{ + const struct gpio_sam_config * const cfg = dev->config; + pio_group_registers_t * const pio = cfg->regs; + struct gpio_sam_runtime *context = dev->data; + uint32_t int_stat; + + int_stat = pio->PIO_ISR; + + gpio_fire_callbacks(&context->cb, dev, int_stat); +} + +static int gpio_sam_manage_callback(const struct device *port, + struct gpio_callback *callback, + bool set) +{ + struct gpio_sam_runtime *context = port->data; + + return gpio_manage_callback(&context->cb, callback, set); +} + +static DEVICE_API(gpio, gpio_sam_api) = { + .pin_configure = gpio_sam_config, + .port_get_raw = gpio_sam_port_get_raw, + .port_set_masked_raw = gpio_sam_port_set_masked_raw, + .port_set_bits_raw = gpio_sam_port_set_bits_raw, + .port_clear_bits_raw = gpio_sam_port_clear_bits_raw, + .port_toggle_bits = gpio_sam_port_toggle_bits, + .pin_interrupt_configure = gpio_sam_pin_interrupt_configure, + .manage_callback = gpio_sam_manage_callback, +}; + +int gpio_sam_init(const struct device *dev) +{ + const struct gpio_sam_config * const cfg = dev->config; + + /* Enable GPIO clock in PMC. This is necessary to enable interrupts */ + (void)clock_control_on(SAM_DT_PMC_CONTROLLER, + (clock_control_subsys_t)&cfg->clock_cfg); + + cfg->config_func(dev); + + return 0; +} + +#define GPIO_SAM_INIT(n) \ + static void port_##n##_sam_config_func(const struct device *dev); \ + \ + static const struct gpio_sam_config port_##n##_sam_config = { \ + .common = { \ + .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \ + }, \ + .regs = (pio_group_registers_t *)DT_INST_REG_ADDR(n), \ + .clock_cfg = SAM_DT_INST_CLOCK_PMC_CFG(n), \ + .config_func = port_##n##_sam_config_func, \ + }; \ + \ + static struct gpio_sam_runtime port_##n##_sam_runtime; \ + \ + DEVICE_DT_INST_DEFINE(n, gpio_sam_init, NULL, \ + &port_##n##_sam_runtime, \ + &port_##n##_sam_config, PRE_KERNEL_1, \ + CONFIG_GPIO_INIT_PRIORITY, \ + &gpio_sam_api); \ + \ + static void port_##n##_sam_config_func(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), \ + gpio_sam_isr, \ + DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_INST_IRQN(n)); \ + } + +DT_INST_FOREACH_STATUS_OKAY(GPIO_SAM_INIT) diff --git a/dts/bindings/gpio/microchip,sam-pio4.yaml b/dts/bindings/gpio/microchip,sam-pio4.yaml new file mode 100644 index 0000000000000..39a4e94f78992 --- /dev/null +++ b/dts/bindings/gpio/microchip,sam-pio4.yaml @@ -0,0 +1,25 @@ +# Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries +# SPDX-License-Identifier: Apache-2.0 + +description: SAM PIO4 GPIO PORT + +compatible: "microchip,sam-pio4" + +include: [gpio-controller.yaml, base.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + clocks: + required: true + + "#gpio-cells": + const: 2 + +gpio-cells: + - pin + - flags diff --git a/include/zephyr/dt-bindings/gpio/microchip-sam-gpio.h b/include/zephyr/dt-bindings/gpio/microchip-sam-gpio.h new file mode 100644 index 0000000000000..f4ee74579a09e --- /dev/null +++ b/include/zephyr/dt-bindings/gpio/microchip-sam-gpio.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_GPIO_MICROCHIP_SAM_GPIO_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_GPIO_MICROCHIP_SAM_GPIO_H_ + +/* + * By default the gpio driver will enable slew rate control for + * each GPIO being used. + * Use this flag to disable the enable operation + */ +#define SAM_GPIO_DIS_SLEWRATE (1U << 8) +/* + * With this flag, IFEN and IFSCEN will be enabled simultaneously + */ +#define SAM_GPIO_DEBOUNCE (1U << 9) +/* + * The Schmitt Trigger is enabled after chip reset + * Use this flag to disable it + */ +#define SAM_GPIO_DIS_SCHMIT (1U << 10) + +/* + * Use these flags to select the drive strength + * Otherwise the SAM_GPIO_DRVSTR_DEFAULT will be used + */ +#define SAM_GPIO_DRVSTR_POS (11U) +#define SAM_GPIO_DRVSTR_MASK (0x3U << SAM_GPIO_DRVSTR_POS) +#define SAM_GPIO_DRVSTR_DEFAULT (0U << SAM_GPIO_DRVSTR_POS) +#define SAM_GPIO_DRVSTR_LOW (1U << SAM_GPIO_DRVSTR_POS) +#define SAM_GPIO_DRVSTR_MED (2U << SAM_GPIO_DRVSTR_POS) +#define SAM_GPIO_DRVSTR_HI (3U << SAM_GPIO_DRVSTR_POS) + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_GPIO_MICROCHIP_SAM_GPIO_H_ */ From 39deee1658f0e8b68ba4ab92f4cc4904f83953a9 Mon Sep 17 00:00:00 2001 From: Xing Chen Date: Tue, 1 Jul 2025 12:21:39 +0800 Subject: [PATCH 2/3] dts: microchip: sam: add pio device to sama7g5 Add pioa, piob, pioc, piod and pioe devices to sama7g5 Signed-off-by: Xing Chen --- dts/arm/microchip/sam/sama7g5.dtsi | 54 ++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/dts/arm/microchip/sam/sama7g5.dtsi b/dts/arm/microchip/sam/sama7g5.dtsi index 5a68520614541..7a8fbbd7b4730 100644 --- a/dts/arm/microchip/sam/sama7g5.dtsi +++ b/dts/arm/microchip/sam/sama7g5.dtsi @@ -429,6 +429,60 @@ pinctrl: pinctrl@e0014000 { compatible = "microchip,sama7g5-pinctrl"; reg = <0xe0014000 0x800>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0xe0014000 0xe0014000 0x800>; + + pioa: gpio@e0014000 { + compatible = "microchip,sam-pio4"; + reg = <0xe0014000 0x40>; + interrupt-parent = <&gic>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 11>; + }; + + piob: gpio@e0014040 { + compatible = "microchip,sam-pio4"; + reg = <0xe0014040 0x40>; + interrupt-parent = <&gic>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 11>; + }; + + pioc: gpio@e0014080 { + compatible = "microchip,sam-pio4"; + reg = <0xe0014080 0x40>; + interrupt-parent = <&gic>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 11>; + }; + + piod: gpio@e00140c0 { + compatible = "microchip,sam-pio4"; + reg = <0xe00140c0 0x40>; + interrupt-parent = <&gic>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 11>; + }; + + pioe: gpio@e0014100 { + compatible = "microchip,sam-pio4"; + reg = <0xe0014100 0x40>; + interrupt-parent = <&gic>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 11>; + gpio-reserved-ranges = <8 24>; + }; }; pit64b0: timer@e1800000 { From 5d23d0c9fbd2e5610cb0871ada2e399e2f905753 Mon Sep 17 00:00:00 2001 From: Xing Chen Date: Tue, 1 Jul 2025 12:23:55 +0800 Subject: [PATCH 3/3] boards: microchip: sam: add led and button device for sama7g54-ek Devices has been verified by samples/basic/button Signed-off-by: Xing Chen --- .../microchip/sam/sama7g54_ek/sama7g54_ek.dts | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/boards/microchip/sam/sama7g54_ek/sama7g54_ek.dts b/boards/microchip/sam/sama7g54_ek/sama7g54_ek.dts index d17d3ac722e42..093b2a72b42ee 100644 --- a/boards/microchip/sam/sama7g54_ek/sama7g54_ek.dts +++ b/boards/microchip/sam/sama7g54_ek/sama7g54_ek.dts @@ -9,12 +9,20 @@ #include #include #include +#include +#include +#include #include / { model = "SAMA7G54-EK board"; compatible = "microchip,sama7g5ek", "microchip,sama7g5", "microchip,sama7"; + aliases { + led0 = &led_green; + sw0 = &button_user; + }; + chosen { zephyr,sram = &ddram; zephyr,console = &usart3; @@ -35,6 +43,37 @@ compatible = "ddram"; reg = <0x60000000 DT_SIZE_M(512)>; }; + + leds { + compatible = "gpio-leds"; + status = "okay"; + + led_red: red { + label = "red"; + gpios = <&piob 8 GPIO_ACTIVE_HIGH>; + }; + + led_green: green { + label = "green"; + gpios = <&pioa 13 GPIO_ACTIVE_HIGH>; + }; + + led_blue: blue { + label = "blue"; + gpios = <&piod 20 GPIO_ACTIVE_HIGH>; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + status = "okay"; + + button_user: button_0 { + label = "PB_USER"; + gpios = <&pioa 12 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + zephyr,code = ; + }; + }; }; &flx3 {