diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index 08adaf2d640..9772dd8e4ef 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -25,6 +25,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_DAVINCI gpio_davinci.c) zephyr_library_sources_ifdef(CONFIG_GPIO_DW gpio_dw.c) zephyr_library_sources_ifdef(CONFIG_GPIO_EFINIX_SAPPHIRE gpio_efinix_sapphire.c) zephyr_library_sources_ifdef(CONFIG_GPIO_EMUL gpio_emul.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_ENE_KB106X gpio_ene_kb106x.c) zephyr_library_sources_ifdef(CONFIG_GPIO_ENE_KB1200 gpio_ene_kb1200.c) zephyr_library_sources_ifdef(CONFIG_GPIO_EOS_S3 gpio_eos_s3.c) zephyr_library_sources_ifdef(CONFIG_GPIO_ESP32 gpio_esp32.c) diff --git a/drivers/gpio/Kconfig.ene b/drivers/gpio/Kconfig.ene index 7dfc2c8318d..c2432012741 100644 --- a/drivers/gpio/Kconfig.ene +++ b/drivers/gpio/Kconfig.ene @@ -7,3 +7,10 @@ config GPIO_ENE_KB1200 depends on DT_HAS_ENE_KB1200_GPIO_ENABLED help Enable support for the kb1200 GPIO controllers. + +config GPIO_ENE_KB106X + bool "ENE KB106X GPIO Driver" + default y + depends on DT_HAS_ENE_KB106X_GPIO_ENABLED + help + Enable support for the KB106X GPIO controllers. diff --git a/drivers/gpio/gpio_ene_kb106x.c b/drivers/gpio/gpio_ene_kb106x.c new file mode 100644 index 00000000000..ea54f191375 --- /dev/null +++ b/drivers/gpio/gpio_ene_kb106x.c @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2025 ENE Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ene_kb106x_gpio + +#include +#include +#include +#include +#include +#include +#include + +struct gpio_kb106x_data { + /* gpio_driver_data needs to be first */ + struct gpio_driver_data common; + sys_slist_t cb; +}; + +struct gpio_kb106x_config { + /* gpio_driver_config needs to be first */ + struct gpio_driver_config common; + /* base address of GPIO port */ + struct gpio_regs *gpio_regs; + struct gptd_regs *gptd_regs; +}; + +static void gpio_kb106x_isr(const struct device *dev) +{ + const struct gpio_kb106x_config *config = dev->config; + struct gpio_kb106x_data *context = dev->data; + uint32_t pending_flag = config->gptd_regs->GPTDPF; + + gpio_fire_callbacks(&context->cb, dev, pending_flag); + config->gptd_regs->GPTDPF = pending_flag; +} + +static int kb106x_gpio_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) +{ + const struct gpio_kb106x_config *config = dev->config; + + /* ene specific flags. low voltage mode, input voltage threshold (ViH & ViL) 1.8V */ + if (flags & ENE_GPIO_VOLTAGE_1P8) { + WRITE_BIT(config->gpio_regs->GPIOLV, pin, 1); + } else { + WRITE_BIT(config->gpio_regs->GPIOLV, pin, 0); + } + /* ene specific flags. max current driving ability, max support 16 mA */ + if (flags & ENE_GPIO_DRIVING_16MA) { + WRITE_BIT(config->gpio_regs->GPIODC, pin, 1); + } else { + WRITE_BIT(config->gpio_regs->GPIODC, pin, 0); + } + /* pull-up function */ + if (flags & GPIO_PULL_UP) { + WRITE_BIT(config->gpio_regs->GPIOPU, pin, 1); + } else { + WRITE_BIT(config->gpio_regs->GPIOPU, pin, 0); + } + /* output data high/low */ + if (flags & GPIO_OUTPUT_INIT_HIGH) { + WRITE_BIT(config->gpio_regs->GPIOD, pin, 1); + } else if (flags & GPIO_OUTPUT_INIT_LOW) { + WRITE_BIT(config->gpio_regs->GPIOD, pin, 0); + } + /* output enable function */ + if (flags & GPIO_OUTPUT) { + /* [patch] setting open-drain only when output is enabled */ + /* output type push-pull/open-drain */ + if (flags & GPIO_SINGLE_ENDED) { + if (flags & GPIO_LINE_OPEN_DRAIN) { + WRITE_BIT(config->gpio_regs->GPIOOD, pin, 1); + } else { + WRITE_BIT(config->gpio_regs->GPIOOD, pin, 0); + } + } else { + WRITE_BIT(config->gpio_regs->GPIOOD, pin, 0); + } + WRITE_BIT(config->gpio_regs->GPIOOE, pin, 1); + } else { + WRITE_BIT(config->gpio_regs->GPIOOE, pin, 0); + /* [patch] disable open-drain when output is disabled */ + WRITE_BIT(config->gpio_regs->GPIOOD, pin, 0); + } + /* input enable function */ + if (flags & GPIO_INPUT) { + WRITE_BIT(config->gpio_regs->GPIOIE, pin, 1); + } else { + WRITE_BIT(config->gpio_regs->GPIOIE, pin, 0); + } + + return 0; +} + +static int kb106x_gpio_port_get_raw(const struct device *dev, gpio_port_value_t *value) +{ + const struct gpio_kb106x_config *config = dev->config; + + *value = config->gpio_regs->GPIOIN; + return 0; +} + +static int kb106x_gpio_port_set_masked_raw(const struct device *dev, gpio_port_pins_t mask, + gpio_port_value_t value) +{ + const struct gpio_kb106x_config *config = dev->config; + + config->gpio_regs->GPIOD |= (value & mask); + return 0; +} + +static int kb106x_gpio_port_set_bits_raw(const struct device *dev, gpio_port_pins_t pins) +{ + const struct gpio_kb106x_config *config = dev->config; + + config->gpio_regs->GPIOD |= pins; + return 0; +} + +static int kb106x_gpio_port_clear_bits_raw(const struct device *dev, gpio_port_pins_t pins) +{ + const struct gpio_kb106x_config *config = dev->config; + + config->gpio_regs->GPIOD &= ~pins; + return 0; +} + +static int kb106x_gpio_port_toggle_bits(const struct device *dev, gpio_port_pins_t pins) +{ + const struct gpio_kb106x_config *config = dev->config; + + config->gpio_regs->GPIOD ^= pins; + return 0; +} + +static int kb106x_gpio_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin, + enum gpio_int_mode mode, enum gpio_int_trig trig) +{ + const struct gpio_kb106x_config *config = dev->config; + + if (mode & GPIO_INT_EDGE) { + WRITE_BIT(config->gptd_regs->GPTDEL, pin, 0); + if (trig & GPIO_INT_HIGH_1) { + if (trig & GPIO_INT_LOW_0) { /* Falling & Rising edge trigger */ + /* Enable toggle trigger */ + WRITE_BIT(config->gptd_regs->GPTDCHG, pin, 1); + } else { /* Rising edge */ + /* Disable toggle trigger */ + WRITE_BIT(config->gptd_regs->GPTDCHG, pin, 0); + WRITE_BIT(config->gptd_regs->GPTDPS, pin, 1); + } + } else { /* Falling edge */ + /* Disable Toggle trigger */ + WRITE_BIT(config->gptd_regs->GPTDCHG, pin, 0); + WRITE_BIT(config->gptd_regs->GPTDPS, pin, 0); + } + } else { + WRITE_BIT(config->gptd_regs->GPTDEL, pin, 1); + /* Disable Toggle trigger */ + WRITE_BIT(config->gptd_regs->GPTDCHG, pin, 0); + if (trig & GPIO_INT_HIGH_1) { + WRITE_BIT(config->gptd_regs->GPTDPS, pin, 1); + } else { + WRITE_BIT(config->gptd_regs->GPTDPS, pin, 0); + } + } + + /* clear pending flag */ + WRITE_BIT(config->gptd_regs->GPTDPF, pin, 1); + + /* Check if GPIO port needs interrupt support */ + if ((mode & GPIO_INT_DISABLE) || (mode & GPIO_INT_ENABLE) == 0) { + /* Set the mask to disable the interrupt */ + WRITE_BIT(config->gptd_regs->GPTDIE, pin, 0); + } else { + /* Enable the interrupt */ + WRITE_BIT(config->gptd_regs->GPTDIE, pin, 1); + } + + /* Check GPIO wakeup enable */ + if (trig & GPIO_INT_TRIG_WAKE) { + WRITE_BIT(config->gptd_regs->GPTDWE, pin, 1); + } else { + WRITE_BIT(config->gptd_regs->GPTDWE, pin, 0); + } + return 0; +} + +static int kb106x_gpio_manage_callback(const struct device *dev, struct gpio_callback *cb, bool set) +{ + struct gpio_kb106x_data *context = dev->data; + + gpio_manage_callback(&context->cb, cb, set); + return 0; +} + +static uint32_t kb106x_gpio_get_pending_int(const struct device *dev) +{ + const struct gpio_kb106x_config *const config = dev->config; + + return config->gptd_regs->GPTDPF; +} + +static const struct gpio_driver_api kb106x_gpio_api = { + .pin_configure = kb106x_gpio_pin_configure, + .port_get_raw = kb106x_gpio_port_get_raw, + .port_set_masked_raw = kb106x_gpio_port_set_masked_raw, + .port_set_bits_raw = kb106x_gpio_port_set_bits_raw, + .port_clear_bits_raw = kb106x_gpio_port_clear_bits_raw, + .port_toggle_bits = kb106x_gpio_port_toggle_bits, + .pin_interrupt_configure = kb106x_gpio_pin_interrupt_configure, + .manage_callback = kb106x_gpio_manage_callback, + .get_pending_int = kb106x_gpio_get_pending_int, +}; + +#define KB106X_GPIO_INIT(n) \ + static int kb106x_gpio_##n##_init(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQ_BY_IDX(n, 0, irq), DT_INST_IRQ_BY_IDX(n, 0, priority), \ + gpio_kb106x_isr, DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_INST_IRQ_BY_IDX(n, 0, irq)); \ + IRQ_CONNECT(DT_INST_IRQ_BY_IDX(n, 1, irq), DT_INST_IRQ_BY_IDX(n, 1, priority), \ + gpio_kb106x_isr, DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_INST_IRQ_BY_IDX(n, 1, irq)); \ + return 0; \ + }; \ + static const struct gpio_kb106x_config port_##n##_kb106x_config = { \ + .common = {.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n)}, \ + .gpio_regs = (struct gpio_regs *)DT_INST_REG_ADDR_BY_IDX(n, 0), \ + .gptd_regs = (struct gptd_regs *)DT_INST_REG_ADDR_BY_IDX(n, 1), \ + }; \ + static struct gpio_kb106x_data gpio_kb106x_##n##_data; \ + DEVICE_DT_INST_DEFINE(n, &kb106x_gpio_##n##_init, NULL, &gpio_kb106x_##n##_data, \ + &port_##n##_kb106x_config, PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, \ + &kb106x_gpio_api); + +DT_INST_FOREACH_STATUS_OKAY(KB106X_GPIO_INIT) diff --git a/dts/arm/ene/kb106x/kb106x.dtsi b/dts/arm/ene/kb106x/kb106x.dtsi index d8d88f4e303..8f41bcd7c7c 100644 --- a/dts/arm/ene/kb106x/kb106x.dtsi +++ b/dts/arm/ene/kb106x/kb106x.dtsi @@ -60,6 +60,56 @@ #size-cells = <1>; reg = <0x50000000 0x100>; status = "okay"; + + gpio0x1x: gpio@50000000 { + compatible = "ene,kb106x-gpio"; + reg = <0x50000000 0x04>, <0x50010000 0x04>; + interrupts = <2 3>, <3 3>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; + status = "disabled"; + }; + + gpio2x3x: gpio@50000004 { + compatible = "ene,kb106x-gpio"; + reg = <0x50000004 0x04>, <0x50010004 0x04>; + interrupts = <4 3>, <5 3>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; + status = "disabled"; + }; + + gpio4x5x: gpio@50000008 { + compatible = "ene,kb106x-gpio"; + reg = <0x50000008 0x04>, <0x50010008 0x04>; + interrupts = <6 3>, <7 3>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; + status = "disabled"; + }; + + gpio6x7x: gpio@5000000c { + compatible = "ene,kb106x-gpio"; + reg = <0x5000000C 0x04>, <0x5001000C 0x04>; + interrupts = <8 3>, <9 3>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; + status = "disabled"; + }; + + egpio0x1x: gpio@50000100 { + compatible = "ene,kb106x-gpio"; + reg = <0x50000100 0x04>, <0x50010100 0x04>; + interrupts = <2 3>, <3 3>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; + status = "disabled"; + }; }; }; }; diff --git a/dts/bindings/gpio/ene,kb106x-gpio.yaml b/dts/bindings/gpio/ene,kb106x-gpio.yaml new file mode 100644 index 00000000000..290cc1881f1 --- /dev/null +++ b/dts/bindings/gpio/ene,kb106x-gpio.yaml @@ -0,0 +1,33 @@ +# Copyright (c) 2025 ENE Technology Inc. +# SPDX-License-Identifier: Apache-2.0 + +description: | + ENE KB106X GPIO(General purpose IO) Port node + + The GPIO controller provides group control of GPIO functions. Each port + group contains 32 pins. GPIO_00~GPIO_1F belong to the Port0 group, + GPIO_20~GPIO_3F belong to the Port1 group, and so on. + + In particular, the 32 pins of the port group do not share the same IRQ + interrupt, but are assigned to two different IRQ interrupts in groups of 16 + pins. This means that single port group provide two interrupt source. + ex.Port0 group GPIO_00~GPIO_0F shares IRQ18, and Port0 group + GPIO_10~GPIO_1F shares IRQ19. + +compatible: "ene,kb106x-gpio" + +include: [gpio-controller.yaml, base.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + "#gpio-cells": + const: 2 + +gpio-cells: + - pin + - flags diff --git a/include/zephyr/dt-bindings/gpio/ene-kb106x-gpio.h b/include/zephyr/dt-bindings/gpio/ene-kb106x-gpio.h new file mode 100644 index 00000000000..aab7676e14a --- /dev/null +++ b/include/zephyr/dt-bindings/gpio/ene-kb106x-gpio.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025 ENE Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_GPIO_ENE_KB106X_GPIO_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_GPIO_ENE_KB106X_GPIO_H_ + +/** + * @name GPIO pin voltage flags + * + * The voltage flags are a Zephyr specific extension of the standard GPIO flags + * specified by the Linux GPIO binding for use with the ENE KB106x SoCs. + * + * @{ + * Note: Bits 15 down to 8 are reserved for SoC specific flags. + */ + +/** @cond INTERNAL_HIDDEN */ +#define ENE_GPIO_VOLTAGE_POS 8 +#define ENE_GPIO_VOLTAGE_MASK (1U << ENE_GPIO_VOLTAGE_POS) + +#define ENE_GPIO_DRIVING_POS 9 +#define ENE_GPIO_DRIVING_MASK (1U << ENE_GPIO_DRIVING_POS) +/** @endcond */ + +/** Set pin at the default voltage level (3.3V) */ +#define ENE_GPIO_VOLTAGE_DEFAULT (0U << ENE_GPIO_VOLTAGE_POS) +/** Set pin voltage level at 1.8 V */ +#define ENE_GPIO_VOLTAGE_1P8 (1U << ENE_GPIO_VOLTAGE_POS) + +/** Set pin at the default driving current (4mA) */ +#define ENE_GPIO_DRIVING_DEFAULT (0U << ENE_GPIO_DRIVING_POS) +/** Set pin driving current at 16mA */ +#define ENE_GPIO_DRIVING_16MA (1U << ENE_GPIO_DRIVING_POS) + +/** @} */ + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_GPIO_ENE_KB106X_GPIO_H_ */ diff --git a/soc/ene/kb106x/common/reg/gpio.h b/soc/ene/kb106x/common/reg/gpio.h new file mode 100644 index 00000000000..aa200f3efd5 --- /dev/null +++ b/soc/ene/kb106x/common/reg/gpio.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2025 ENE Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ENE_KB106X_GPIO_H +#define ENE_KB106X_GPIO_H + +/** + * Structure type to access General Purpose Input/Output (GPIO). + */ +struct gpio_regs { + volatile uint32_t GPIOFS; /*Function Selection Register */ + volatile uint32_t Reserved1[3]; + volatile uint32_t GPIOOE; /*Output Enable Register */ + volatile uint32_t Reserved2[3]; + volatile uint32_t GPIOD; /*Output Data Register */ + volatile uint32_t Reserved3[3]; + volatile uint32_t GPIOIN; /*Input Data Register */ + volatile uint32_t Reserved4[3]; + volatile uint32_t GPIOPU; /*Pull Up Register */ + volatile uint32_t Reserved5[3]; + volatile uint32_t GPIOOD; /*Open Drain Register */ + volatile uint32_t Reserved6[3]; + volatile uint32_t GPIOIE; /*Input Enable Register */ + volatile uint32_t Reserved7[3]; + volatile uint32_t GPIODC; /*Driving Control Register */ + volatile uint32_t Reserved8[3]; + volatile uint32_t GPIOLV; /*Low Voltage Mode Enable Register */ + volatile uint32_t Reserved9[3]; + volatile uint32_t GPIOPD; /*Pull Down Register */ + volatile uint32_t Reserved10[3]; + volatile uint32_t GPIOFL; /*Function Lock Register */ + volatile uint32_t Reserved11[3]; +}; + +#define NUM_KB106X_GPIO_PORTS 4 + +/*-- Constant Define --------------------------------------------*/ +#define GPIO0B_ESBCLK_SCL5 0x0B +#define GPIO0C_ESBDAT_SDA5 0x0C +#define GPIO0D_RLCTX2_SDA4 0x0D +#define GPIO16_SERTXD_UARTSOUT_SBUDCLK 0x16 +#define GPIO17_SERRXD_UARTSIN_SBUDDAT 0x17 +#define GPIO19_PWM3_PWMLED0 0x19 +#define GPIO30_SERTXD_NKROKSI0 0x30 +#define GPIO48_KSO16_UART_SOUT2 0x48 +#define GPIO4C_PSCLK2_SCL3 0x4C +#define GPIO4D_SDAT2_SDA3 0x4D +#define GPIO4E_PSCLK3_KSO18 0x4E +#define GPIO4F_PSDAT3_KSO19 0x4F +#define GPIO4A_PSCLK1_SCL2_USBDM 0x4A +#define GPIO4B_PSDAT1_SDA2_USBDP 0x4B + +#define GPIO60_SHICS 0x60 +#define GPIO61_SHICLK 0x61 +#define GPIO62_SHIDO 0x62 +#define GPIO78_SHIDI 0x78 +#define GPIO5A_SHR_SPICS 0x5A +#define GPIO58_SHR_SPICLK 0x58 +#define GPIO5C_SHR_MOSI 0x5C +#define GPIO5B_SHR_MISO 0x5B + +#define GPIO01_ESPI_ALERT 0x01 +#define GPIO03_ESPI_CS 0x03 +#define GPIO07_ESPI_RST 0x07 + +#endif /* ENE_KB106X_GPIO_H */ diff --git a/soc/ene/kb106x/common/reg/gptd.h b/soc/ene/kb106x/common/reg/gptd.h new file mode 100644 index 00000000000..3ae47dfcca3 --- /dev/null +++ b/soc/ene/kb106x/common/reg/gptd.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2025 ENE Technology Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ENE_KB106X_GPTD_H +#define ENE_KB106X_GPTD_H + +/** + * Structure type to access GPIO Trigger Detector (GPTD). + */ +struct gptd_regs { + volatile uint32_t GPTDIE; /*Interrupt Enable Register */ + volatile uint32_t Reserved1[3]; + volatile uint32_t GPTDPF; /*Event Pending Flag Register */ + volatile uint32_t Reserved2[3]; + volatile uint32_t GPTDCHG; /*Change Trigger Register */ + volatile uint32_t Reserved3[3]; + volatile uint32_t GPTDEL; /*Level/Edge Trigger Register */ + volatile uint32_t Reserved4[3]; + volatile uint32_t GPTDPS; /*Polarity Selection Register */ + volatile uint32_t Reserved5[3]; + volatile uint32_t GPTDWE; /*WakeUP Enable Register */ + volatile uint32_t Reserved6[3]; +}; + +#endif /* ENE_KB106X_GPTD_H */