drivers: gpio: gpio driver

Add gpio driver for ENE KB106X

Signed-off-by: Steven Chang <steven@ene.com.tw>
This commit is contained in:
Steven Chang 2025-06-27 15:25:16 +08:00 committed by Benjamin Cabé
parent d9310b6648
commit 7d2be3bbff
8 changed files with 467 additions and 0 deletions

View File

@ -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)

View File

@ -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.

View File

@ -0,0 +1,240 @@
/*
* Copyright (c) 2025 ENE Technology Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT ene_kb106x_gpio
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/gpio/gpio_utils.h>
#include <zephyr/dt-bindings/gpio/ene-kb106x-gpio.h>
#include <zephyr/sys/util_macro.h>
#include <reg/gpio.h>
#include <reg/gptd.h>
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)

View File

@ -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";
};
};
};
};

View File

@ -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

View File

@ -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_ */

View File

@ -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 */

View File

@ -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 */