drivers/gpio: it8xxx2 platform gpio driver
This commit is about platform it8xxx2 gpio. The devicetree use key and led as example. Users can change it to meet their needs. Signed-off-by: Cheryl Su <Cheryl.su@ite.com.tw>
This commit is contained in:
parent
f060540b33
commit
6804e8ff40
4 changed files with 406 additions and 0 deletions
|
@ -10,6 +10,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_ESP32 gpio_esp32.c)
|
|||
zephyr_library_sources_ifdef(CONFIG_GPIO_SIFIVE gpio_sifive.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_GPIO_GECKO gpio_gecko.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_GPIO_IMX gpio_imx.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_GPIO_ITE_IT8XXX2 gpio_ite_it8xxx2.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_GPIO_MCP23S17 gpio_mcp23s17.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_GPIO_MCUX gpio_mcux.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_GPIO_MCUX_IGPIO gpio_mcux_igpio.c)
|
||||
|
|
|
@ -59,6 +59,8 @@ source "drivers/gpio/Kconfig.sx1509b"
|
|||
|
||||
source "drivers/gpio/Kconfig.imx"
|
||||
|
||||
source "drivers/gpio/Kconfig.it8xxx2"
|
||||
|
||||
source "drivers/gpio/Kconfig.intel"
|
||||
|
||||
source "drivers/gpio/Kconfig.xec"
|
||||
|
|
8
drivers/gpio/Kconfig.it8xxx2
Normal file
8
drivers/gpio/Kconfig.it8xxx2
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Copyright (c) 2020 ITE Corporation. All Rights Reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config GPIO_ITE_IT8XXX2
|
||||
bool "ITE IT8XXX2 GPIO driver"
|
||||
select HAS_DTS_GPIO
|
||||
help
|
||||
Enable driver for the ite GPIO controller.
|
395
drivers/gpio/gpio_ite_it8xxx2.c
Normal file
395
drivers/gpio/gpio_ite_it8xxx2.c
Normal file
|
@ -0,0 +1,395 @@
|
|||
/*
|
||||
* Copyright (c) 2020 ITE Corporation. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <device.h>
|
||||
#include <drivers/gpio.h>
|
||||
#include <zephyr/types.h>
|
||||
#include <sys/util.h>
|
||||
#include <string.h>
|
||||
#include <logging/log.h>
|
||||
#include "gpio_utils.h"
|
||||
|
||||
#define DT_DRV_COMPAT ite_it8xxx2_gpio
|
||||
#define GPIO_LOW 0
|
||||
#define GPIO_HIGH 1
|
||||
#define NUM_IO_MAX 8
|
||||
#define CURR_SUPP_GPIO_SET 2
|
||||
|
||||
/*
|
||||
* this two function be used to enable/disable specific irq interrupt
|
||||
*/
|
||||
extern void ite_intc_irq_enable(unsigned int irq);
|
||||
extern void ite_intc_irq_disable(unsigned int irq);
|
||||
|
||||
#define GPIO_GPDRB (DT_REG_ADDR_BY_IDX(DT_NODELABEL(gpiob), 0))
|
||||
#define GPIO_GPDRF (DT_REG_ADDR_BY_IDX(DT_NODELABEL(gpiof), 0))
|
||||
#define GPIO_GPDRM (DT_REG_ADDR_BY_IDX(DT_NODELABEL(gpiom), 0))
|
||||
#define GPCR_OFFSET 0x10
|
||||
#define GPIO_DIR_INPUT 0x80
|
||||
#define GPIO_DIR_OUTPUT 0x40
|
||||
|
||||
struct gpio_ite_wui {
|
||||
volatile uint8_t *reg_addr;
|
||||
volatile uint8_t *clear_addr;
|
||||
volatile uint8_t *bothedge_addr;
|
||||
uint32_t pin;
|
||||
uint32_t irq;
|
||||
};
|
||||
|
||||
static const struct gpio_ite_wui GPIO_GPDRB_wui[NUM_IO_MAX] = {
|
||||
{ &WUEMR10, &WUESR10, &WUBEMR10, BIT(5), 106 }, /* gpb0, */
|
||||
{ &WUEMR10, &WUESR10, &WUBEMR10, BIT(6), 107 }, /* gpb1, */
|
||||
{ &WUEMR8, &WUESR8, &WUBEMR8, BIT(4), 92 }, /* gpb2, */
|
||||
{ &WUEMR10, &WUESR10, &WUBEMR10, BIT(7), 108 }, /* gpb3, */
|
||||
{ &WUEMR9, &WUESR9, &WUBEMR9, BIT(6), 99 }, /* gpb4, */
|
||||
{ &WUEMR11, &WUESR11, &WUBEMR11, BIT(0), 109 }, /* gpb5, */
|
||||
{ &WUEMR11, &WUESR11, &WUBEMR11, BIT(1), 110 }, /* gpb6, */
|
||||
{ &WUEMR11, &WUESR11, &WUBEMR11, BIT(2), 111 }, /* gpb7, */
|
||||
|
||||
};
|
||||
|
||||
static const struct gpio_ite_wui GPIO_GPDRF_wui[NUM_IO_MAX] = {
|
||||
{ &WUEMR10, &WUESR10, &WUBEMR10, BIT(0), 101 }, /* gpf0, */
|
||||
{ &WUEMR10, &WUESR10, &WUBEMR10, BIT(1), 102 }, /* gpf1, */
|
||||
{ &WUEMR10, &WUESR10, &WUBEMR10, BIT(2), 103 }, /* gpf2, */
|
||||
{ &WUEMR10, &WUESR10, &WUBEMR10, BIT(3), 104 }, /* gpf3, */
|
||||
{ &WUEMR6, &WUESR6, &WUBEMR6, BIT(4), 52 }, /* gpf4, */
|
||||
{ &WUEMR6, &WUESR6, &WUBEMR6, BIT(5), 53 }, /* gpf5, */
|
||||
{ &WUEMR6, &WUESR6, &WUBEMR6, BIT(6), 54 }, /* gpf6, */
|
||||
{ &WUEMR6, &WUESR6, &WUBEMR6, BIT(7), 55 }, /* gpf7, */
|
||||
};
|
||||
|
||||
/* struct gpio_ite_reg_table is record different gpio port's register set
|
||||
* base_addr: base address of gpio set
|
||||
* wui[]: wui register group
|
||||
*/
|
||||
struct gpio_ite_reg_table {
|
||||
uint32_t base_addr;
|
||||
const struct gpio_ite_wui *wui;
|
||||
};
|
||||
|
||||
struct gpio_ite_reg_table gpiox_reg[CURR_SUPP_GPIO_SET] = {
|
||||
{GPIO_GPDRB, GPIO_GPDRB_wui}, /* GPIO GROPU B */
|
||||
{GPIO_GPDRF, GPIO_GPDRF_wui}, /* GPIO GROPU F */
|
||||
};
|
||||
|
||||
/* edge/level trigger register */
|
||||
static volatile uint8_t *const reg_ielmr[] = {
|
||||
&IELMR0, &IELMR1, &IELMR2, &IELMR3,
|
||||
&IELMR4, &IELMR5, &IELMR6, &IELMR7,
|
||||
&IELMR8, &IELMR9, &IELMR10, &IELMR11,
|
||||
&IELMR12, &IELMR13, &IELMR14, &IELMR15,
|
||||
&IELMR16, &IELMR17, &IELMR18, &IELMR19,
|
||||
&IELMR20
|
||||
};
|
||||
|
||||
/* high/low trigger register */
|
||||
static volatile uint8_t *const reg_ipolr[] = {
|
||||
&IPOLR0, &IPOLR1, &IPOLR2, &IPOLR3,
|
||||
&IPOLR4, &IPOLR5, &IPOLR6, &IPOLR7,
|
||||
&IPOLR8, &IPOLR9, &IPOLR10, &IPOLR11,
|
||||
&IPOLR12, &IPOLR13, &IPOLR14, &IPOLR15,
|
||||
&IPOLR16, &IPOLR17, &IPOLR18, &IPOLR19,
|
||||
&IPOLR20
|
||||
};
|
||||
|
||||
/*
|
||||
* Strcture gpio_ite_cfg is about the setting of gpio
|
||||
* this config will be used at initial time
|
||||
*/
|
||||
struct gpio_ite_cfg {
|
||||
uint32_t reg_addr; /* gpio register base address */
|
||||
uint8_t gpio_irq[8]; /* gpio's irq */
|
||||
};
|
||||
|
||||
/*
|
||||
* Strcture gpio_ite_data is about callback function
|
||||
*/
|
||||
struct gpio_ite_data {
|
||||
struct gpio_driver_data common;
|
||||
sys_slist_t callbacks;
|
||||
uint32_t pin_callback_enables;
|
||||
};
|
||||
|
||||
/* dev macros for GPIO */
|
||||
#define DEV_GPIO_DATA(dev) \
|
||||
((struct gpio_ite_data *)(dev)->data)
|
||||
|
||||
#define DEV_GPIO_CFG(dev) \
|
||||
((const struct gpio_ite_cfg *)(dev)->config)
|
||||
|
||||
/**
|
||||
* functions for bit / port access
|
||||
*/
|
||||
static inline void set_bit(const struct gpio_ite_cfg *config,
|
||||
uint8_t bit, bool val)
|
||||
{
|
||||
uint8_t regv, new_regv;
|
||||
|
||||
regv = ite_read(config->reg_addr, 1);
|
||||
new_regv = (regv & ~BIT(bit)) | (val << bit);
|
||||
ite_write(config->reg_addr, 1, new_regv);
|
||||
}
|
||||
|
||||
static inline uint8_t get_bit(const struct gpio_ite_cfg *config, uint8_t bit)
|
||||
{
|
||||
uint8_t regv = ite_read(config->reg_addr, 1);
|
||||
|
||||
return !!(regv & BIT(bit));
|
||||
}
|
||||
|
||||
static inline void set_port(const struct gpio_ite_cfg *config, uint8_t value)
|
||||
{
|
||||
ite_write(config->reg_addr, 1, value);
|
||||
}
|
||||
|
||||
static inline uint8_t get_port(const struct gpio_ite_cfg *config)
|
||||
{
|
||||
uint8_t regv = ite_read(config->reg_addr, 1);
|
||||
|
||||
return regv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Driver functions
|
||||
*/
|
||||
static int gpio_ite_configure(const struct device *dev,
|
||||
gpio_pin_t pin, gpio_flags_t flags)
|
||||
{
|
||||
const struct gpio_ite_cfg *gpio_config = DEV_GPIO_CFG(dev);
|
||||
unsigned int gpcr_offset = GPCR_OFFSET;
|
||||
uint32_t gpcr_reg;
|
||||
uint32_t gpcr_reg_addr;
|
||||
|
||||
/* counting the gpio control register's base address */
|
||||
gpcr_reg = ((gpio_config->reg_addr & 0xff) - 1) * NUM_IO_MAX
|
||||
+ gpcr_offset;
|
||||
gpcr_reg_addr = gpcr_reg | (gpio_config->reg_addr & 0xffffff00);
|
||||
if (!(flags & GPIO_SINGLE_ENDED)) {
|
||||
/* Pin open-source/open-drain is not supported */
|
||||
return -ENOTSUP;
|
||||
}
|
||||
if ((flags & GPIO_OUTPUT) && (flags & GPIO_INPUT)) {
|
||||
/* Pin cannot be configured as input and output */
|
||||
return -ENOTSUP;
|
||||
} else if (!(flags & (GPIO_INPUT | GPIO_OUTPUT))) {
|
||||
/* Pin has to be configuread as input or output */
|
||||
return -ENOTSUP;
|
||||
}
|
||||
if (flags & GPIO_OUTPUT) {
|
||||
if (flags & GPIO_OUTPUT_INIT_HIGH) {
|
||||
set_bit(gpio_config, pin, GPIO_HIGH);
|
||||
} else if (flags & GPIO_OUTPUT_INIT_LOW) {
|
||||
set_bit(gpio_config, pin, GPIO_LOW);
|
||||
}
|
||||
ite_write(gpcr_reg_addr + pin, 1, GPIO_DIR_OUTPUT);
|
||||
} else {
|
||||
if ((flags & GPIO_PULL_DOWN) || (flags & GPIO_PULL_UP)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
ite_write(gpcr_reg_addr + pin, 1, GPIO_DIR_INPUT);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_ite_port_get_raw(const struct device *dev,
|
||||
gpio_port_value_t *value)
|
||||
{
|
||||
const struct gpio_ite_cfg *gpio_config = DEV_GPIO_CFG(dev);
|
||||
|
||||
*value = ite_read(gpio_config->reg_addr, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_ite_port_set_masked_raw(const struct device *dev,
|
||||
gpio_port_pins_t mask, gpio_port_value_t value)
|
||||
{
|
||||
const struct gpio_ite_cfg *gpio_config = DEV_GPIO_CFG(dev);
|
||||
uint32_t port_val;
|
||||
|
||||
port_val = get_port(gpio_config);
|
||||
port_val = (port_val & ~mask) | (value & mask);
|
||||
set_port(gpio_config, port_val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_ite_port_set_bits_raw(const struct device *dev,
|
||||
gpio_port_pins_t pins)
|
||||
{
|
||||
const struct gpio_ite_cfg *gpio_config = DEV_GPIO_CFG(dev);
|
||||
uint32_t port_val;
|
||||
|
||||
port_val = get_port(gpio_config);
|
||||
port_val |= pins;
|
||||
set_port(gpio_config, port_val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_ite_port_clear_bits_raw(const struct device *dev,
|
||||
gpio_port_pins_t pins)
|
||||
{
|
||||
const struct gpio_ite_cfg *gpio_config = DEV_GPIO_CFG(dev);
|
||||
uint32_t port_val;
|
||||
|
||||
port_val = get_port(gpio_config);
|
||||
port_val &= ~pins;
|
||||
set_port(gpio_config, port_val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_ite_port_toggle_bits(const struct device *dev,
|
||||
gpio_port_pins_t pins)
|
||||
{
|
||||
const struct gpio_ite_cfg *gpio_config = DEV_GPIO_CFG(dev);
|
||||
uint32_t port_val;
|
||||
|
||||
port_val = get_port(gpio_config);
|
||||
port_val ^= pins;
|
||||
set_port(gpio_config, port_val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_ite_manage_callback(const struct device *dev,
|
||||
struct gpio_callback *callback,
|
||||
bool set)
|
||||
{
|
||||
struct gpio_ite_data *data = DEV_GPIO_DATA(dev);
|
||||
|
||||
return gpio_manage_callback(&data->callbacks, callback, set);
|
||||
}
|
||||
|
||||
static void gpio_ite_isr(const void *arg)
|
||||
{
|
||||
int irq_index = 0;
|
||||
int gpio_index = 0;
|
||||
const struct device *dev = arg;
|
||||
struct gpio_ite_wui *wui_local;
|
||||
struct gpio_ite_reg_table *gpio_tab_local;
|
||||
const struct gpio_ite_cfg *gpio_config = DEV_GPIO_CFG(dev);
|
||||
struct gpio_ite_data *data = DEV_GPIO_DATA(dev);
|
||||
|
||||
|
||||
for (gpio_index = 0; gpio_index < CURR_SUPP_GPIO_SET; gpio_index++) {
|
||||
if (gpio_config->reg_addr == gpiox_reg[gpio_index].base_addr) {
|
||||
gpio_tab_local = &gpiox_reg[gpio_index];
|
||||
}
|
||||
}
|
||||
for (irq_index = 0; irq_index < NUM_IO_MAX; irq_index++) {
|
||||
wui_local = (struct gpio_ite_wui *)&
|
||||
gpio_tab_local->wui[irq_index];
|
||||
if ((*wui_local->clear_addr)&wui_local->pin) {
|
||||
SET_MASK(*wui_local->clear_addr, wui_local->pin);
|
||||
gpio_fire_callbacks(&data->callbacks, dev,
|
||||
BIT(wui_local->pin));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int gpio_ite_pin_interrupt_configure(const struct device *dev,
|
||||
gpio_pin_t pin, enum gpio_int_mode mode, enum gpio_int_trig trig)
|
||||
{
|
||||
int ret = 0;
|
||||
int gpio_index = 0;
|
||||
uint32_t g, i;
|
||||
uint8_t both_tri_en = 0;
|
||||
const struct gpio_ite_cfg *gpio_config = DEV_GPIO_CFG(dev);
|
||||
struct gpio_ite_wui *wui_local;
|
||||
volatile uint8_t *trig_mode;
|
||||
volatile uint8_t *hl_trig;
|
||||
|
||||
g = gpio_config->gpio_irq[pin] / NUM_IO_MAX;
|
||||
i = gpio_config->gpio_irq[pin] % NUM_IO_MAX;
|
||||
trig_mode = reg_ielmr[g];
|
||||
hl_trig = reg_ipolr[g];
|
||||
|
||||
if (mode & GPIO_INT_MODE_DISABLED) {
|
||||
/* Disables interrupt for a pin. */
|
||||
ite_intc_irq_disable(gpio_config->gpio_irq[pin]);
|
||||
return ret;
|
||||
} else if (mode & GPIO_INT_MODE_EDGE) {
|
||||
/* edge trigger */
|
||||
SET_MASK(*trig_mode, BIT(i));
|
||||
} else {
|
||||
/* level trigger */
|
||||
CLEAR_MASK(*trig_mode, BIT(i));
|
||||
}
|
||||
/* both */
|
||||
if ((trig & GPIO_INT_TRIG_LOW) && (trig & GPIO_INT_TRIG_HIGH)) {
|
||||
both_tri_en = 1;
|
||||
} else {
|
||||
if (trig & GPIO_INT_TRIG_LOW) {
|
||||
SET_MASK(*hl_trig, BIT(i));
|
||||
} else if (trig & GPIO_INT_TRIG_HIGH) {
|
||||
CLEAR_MASK(*hl_trig, BIT(i));
|
||||
}
|
||||
}
|
||||
|
||||
/* set wui , only gpiob gpiof, currently */
|
||||
for (gpio_index = 0; gpio_index < CURR_SUPP_GPIO_SET; gpio_index++) {
|
||||
if (gpio_config->reg_addr ==
|
||||
gpiox_reg[gpio_index].base_addr) {
|
||||
wui_local = (struct gpio_ite_wui *)
|
||||
&(gpiox_reg[gpio_index].wui[pin]);
|
||||
SET_MASK(*wui_local->reg_addr, wui_local->pin);
|
||||
SET_MASK(*wui_local->clear_addr, wui_local->pin);
|
||||
if (both_tri_en == 1) {
|
||||
SET_MASK(*wui_local->reg_addr, wui_local->pin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable IRQ */
|
||||
ret = irq_connect_dynamic(
|
||||
gpio_config->gpio_irq[pin], 0, gpio_ite_isr, dev, 0);
|
||||
ite_intc_irq_enable(gpio_config->gpio_irq[pin]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct gpio_driver_api gpio_ite_driver_api = {
|
||||
.pin_configure = gpio_ite_configure,
|
||||
.port_get_raw = gpio_ite_port_get_raw,
|
||||
.port_set_masked_raw = gpio_ite_port_set_masked_raw,
|
||||
.port_set_bits_raw = gpio_ite_port_set_bits_raw,
|
||||
.port_clear_bits_raw = gpio_ite_port_clear_bits_raw,
|
||||
.port_toggle_bits = gpio_ite_port_toggle_bits,
|
||||
.pin_interrupt_configure = gpio_ite_pin_interrupt_configure,
|
||||
.manage_callback = gpio_ite_manage_callback,
|
||||
};
|
||||
|
||||
static int gpio_ite_init(const struct device *dev)
|
||||
{
|
||||
const struct gpio_ite_cfg *gpio_config = DEV_GPIO_CFG(dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_IO_MAX; i++) {
|
||||
/* init disable intc */
|
||||
ite_intc_irq_disable(gpio_config->gpio_irq[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define GPIO_ITE_DEV_CFG_DATA(n, idx) \
|
||||
static struct gpio_ite_data gpio_ite_data_##n##_##idx; \
|
||||
static const struct gpio_ite_cfg gpio_ite_cfg_##n##_##idx = { \
|
||||
.reg_addr = DT_INST_REG_ADDR(idx),\
|
||||
.gpio_irq[0] = DT_INST_IRQ_BY_IDX(idx, 0, irq), \
|
||||
}; \
|
||||
DEVICE_AND_API_INIT(gpio_it8xxx2_dev_##n##_##idx, \
|
||||
DT_PROP(DT_NODELABEL(n), label), \
|
||||
gpio_ite_init, \
|
||||
&gpio_ite_data_##n##_##idx, \
|
||||
&gpio_ite_cfg_##n##_##idx, \
|
||||
POST_KERNEL, \
|
||||
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
|
||||
&gpio_ite_driver_api)
|
||||
#if DT_NODE_HAS_STATUS(DT_NODELABEL(gpiob), okay)
|
||||
GPIO_ITE_DEV_CFG_DATA(gpiob, 0);
|
||||
#endif /* gpiob */
|
||||
#if DT_NODE_HAS_STATUS(DT_NODELABEL(gpiof), okay)
|
||||
GPIO_ITE_DEV_CFG_DATA(gpiof, 1);
|
||||
#endif /* gpiof */
|
Loading…
Add table
Add a link
Reference in a new issue