zephyr/drivers/gpio/gpio_dw.c
Tomasz Bursztyka 064f5f0cef drivers/gpio: Manage callback addition/removal properly
It needs to verify if the callback was not already installed, and if so:
if is was in controller's list.
It should return an error in case the node is not found though it was
requested to be removed.
If already inserted, it will be silently removed but added again, to
avoid circular list as stated in the bug.

Fixes #11394

Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2019-01-25 11:24:29 -05:00

762 lines
20 KiB
C

/*
* Copyright (c) 2015 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <errno.h>
#include <kernel.h>
#include <gpio.h>
#include "gpio_dw.h"
#include "gpio_utils.h"
#include <soc.h>
#include <sys_io.h>
#include <init.h>
#include <misc/util.h>
#include <misc/__assert.h>
#include <clock_control.h>
#ifdef CONFIG_SHARED_IRQ
#include <shared_irq.h>
#endif
#ifdef CONFIG_IOAPIC
#include <drivers/ioapic.h>
#endif
#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
#include <power.h>
#endif
/*
* ARC architecture configure IP through IO auxiliary registers.
* Other architectures as ARM and x86 configure IP through MMIO registers
*/
#ifdef GPIO_DW_IO_ACCESS
static inline u32_t dw_read(u32_t base_addr, u32_t offset)
{
return sys_in32(base_addr + offset);
}
static inline void dw_write(u32_t base_addr, u32_t offset,
u32_t val)
{
sys_out32(val, base_addr + offset);
}
static void dw_set_bit(u32_t base_addr, u32_t offset,
u32_t bit, u8_t value)
{
if (!value) {
sys_io_clear_bit(base_addr + offset, bit);
} else {
sys_io_set_bit(base_addr + offset, bit);
}
}
#else
static inline u32_t dw_read(u32_t base_addr, u32_t offset)
{
return sys_read32(base_addr + offset);
}
static inline void dw_write(u32_t base_addr, u32_t offset,
u32_t val)
{
sys_write32(val, base_addr + offset);
}
static void dw_set_bit(u32_t base_addr, u32_t offset,
u32_t bit, u8_t value)
{
if (!value) {
sys_clear_bit(base_addr + offset, bit);
} else {
sys_set_bit(base_addr + offset, bit);
}
}
#endif
#ifdef CONFIG_GPIO_DW_CLOCK_GATE
static inline void _gpio_dw_clock_config(struct device *port)
{
char *drv = CONFIG_GPIO_DW_CLOCK_GATE_DRV_NAME;
struct device *clk;
clk = device_get_binding(drv);
if (clk) {
struct gpio_dw_runtime *context = port->driver_data;
context->clock = clk;
}
}
static inline void _gpio_dw_clock_on(struct device *port)
{
const struct gpio_dw_config *config = port->config->config_info;
struct gpio_dw_runtime *context = port->driver_data;
clock_control_on(context->clock, config->clock_data);
}
static inline void _gpio_dw_clock_off(struct device *port)
{
const struct gpio_dw_config *config = port->config->config_info;
struct gpio_dw_runtime *context = port->driver_data;
clock_control_off(context->clock, config->clock_data);
}
#else
#define _gpio_dw_clock_config(...)
#define _gpio_dw_clock_on(...)
#define _gpio_dw_clock_off(...)
#endif
#ifdef CONFIG_SOC_QUARK_SE_C1000_SS
static inline void dw_set_both_edges(u32_t base_addr, u32_t pin)
{
ARG_UNUSED(base_addr);
ARG_UNUSED(pin);
}
static inline int dw_base_to_block_base(u32_t base_addr)
{
return base_addr;
}
static inline int dw_interrupt_support(const struct gpio_dw_config *config)
{
ARG_UNUSED(config);
return 1;
}
#else
static inline void dw_set_both_edges(u32_t base_addr, u32_t pin)
{
dw_set_bit(base_addr, INT_BOTHEDGE, pin, 1);
}
static inline int dw_base_to_block_base(u32_t base_addr)
{
return (base_addr & 0xFFFFFFC0);
}
static inline int dw_derive_port_from_base(u32_t base_addr)
{
u32_t port = (base_addr & 0x3f) / 12;
return port;
}
static inline int dw_interrupt_support(const struct gpio_dw_config *config)
{
return ((int)(config->irq_num) > 0);
}
#endif
static inline void dw_interrupt_config(struct device *port, int access_op,
u32_t pin, int flags)
{
struct gpio_dw_runtime *context = port->driver_data;
const struct gpio_dw_config *config = port->config->config_info;
u32_t base_addr = dw_base_to_block_base(context->base_addr);
u8_t flag_is_set;
ARG_UNUSED(access_op);
/* set as an input pin */
dw_set_bit(context->base_addr, SWPORTA_DDR, pin, 0);
if (dw_interrupt_support(config)) {
/* level or edge */
flag_is_set = (flags & GPIO_INT_EDGE);
dw_set_bit(base_addr, INTTYPE_LEVEL, pin, flag_is_set);
/* Active low/high */
flag_is_set = (flags & GPIO_INT_ACTIVE_HIGH);
dw_set_bit(base_addr, INT_POLARITY, pin, flag_is_set);
/* both edges */
flag_is_set = (flags & GPIO_INT_DOUBLE_EDGE);
if (flag_is_set) {
dw_set_both_edges(base_addr, pin);
dw_set_bit(base_addr, INTTYPE_LEVEL, pin, flag_is_set);
}
/* use built-in debounce */
flag_is_set = (flags & GPIO_INT_DEBOUNCE);
dw_set_bit(base_addr, PORTA_DEBOUNCE, pin, flag_is_set);
/* Finally enabling interrupt */
dw_set_bit(base_addr, INTEN, pin, 1);
}
}
static inline void dw_pin_config(struct device *port,
u32_t pin, int flags)
{
struct gpio_dw_runtime *context = port->driver_data;
const struct gpio_dw_config *config = port->config->config_info;
u32_t base_addr = dw_base_to_block_base(context->base_addr);
u32_t port_base_addr = context->base_addr;
int interrupt_support = dw_interrupt_support(config);
if (interrupt_support) {
/* clear interrupt enable */
dw_set_bit(base_addr, INTEN, pin, 0);
}
/* set direction */
dw_set_bit(port_base_addr, SWPORTA_DDR, pin, (flags & GPIO_DIR_MASK));
if (interrupt_support && (flags & GPIO_INT)) {
dw_interrupt_config(port, GPIO_ACCESS_BY_PIN, pin, flags);
}
}
static inline void dw_port_config(struct device *port, int flags)
{
const struct gpio_dw_config *config = port->config->config_info;
int i;
for (i = 0; i < config->bits; i++) {
dw_pin_config(port, i, flags);
}
}
static inline int gpio_dw_config(struct device *port, int access_op,
u32_t pin, int flags)
{
if ((flags & GPIO_INT) && (flags & GPIO_DIR_OUT)) {
return -EINVAL;
}
if (GPIO_ACCESS_BY_PIN == access_op) {
dw_pin_config(port, pin, flags);
} else {
dw_port_config(port, flags);
}
return 0;
}
static inline int gpio_dw_write(struct device *port, int access_op,
u32_t pin, u32_t value)
{
struct gpio_dw_runtime *context = port->driver_data;
u32_t base_addr = context->base_addr;
if (GPIO_ACCESS_BY_PIN == access_op) {
dw_set_bit(base_addr, SWPORTA_DR, pin, value);
} else {
dw_write(base_addr, SWPORTA_DR, value);
}
return 0;
}
static inline int gpio_dw_read(struct device *port, int access_op,
u32_t pin, u32_t *value)
{
struct gpio_dw_runtime *context = port->driver_data;
u32_t base_addr = context->base_addr;
#ifndef CONFIG_SOC_QUARK_SE_C1000_SS
u32_t ext_port = EXT_PORTA;
#endif
#ifdef CONFIG_SOC_QUARK_SE_C1000_SS
*value = dw_read(base_addr, EXT_PORTA);
#else
/* 4-port GPIO implementation translates from base address to port */
switch (dw_derive_port_from_base(base_addr)) {
case 1:
ext_port = EXT_PORTB;
break;
case 2:
ext_port = EXT_PORTC;
break;
case 3:
ext_port = EXT_PORTD;
break;
case 0:
default:
break;
}
*value = dw_read(dw_base_to_block_base(base_addr), ext_port);
#endif
if (GPIO_ACCESS_BY_PIN == access_op) {
*value = !!(*value & BIT(pin));
}
return 0;
}
static inline int gpio_dw_manage_callback(struct device *port,
struct gpio_callback *callback,
bool set)
{
struct gpio_dw_runtime *context = port->driver_data;
return _gpio_manage_callback(&context->callbacks, callback, set);
}
static inline int gpio_dw_enable_callback(struct device *port, int access_op,
u32_t pin)
{
const struct gpio_dw_config *config = port->config->config_info;
struct gpio_dw_runtime *context = port->driver_data;
u32_t base_addr = dw_base_to_block_base(context->base_addr);
if (GPIO_ACCESS_BY_PIN == access_op) {
dw_write(base_addr, PORTA_EOI, BIT(pin));
dw_set_bit(base_addr, INTMASK, pin, 0);
} else {
dw_write(base_addr, PORTA_EOI, BIT_MASK(config->bits));
dw_write(base_addr, INTMASK, 0);
}
return 0;
}
static inline int gpio_dw_disable_callback(struct device *port, int access_op,
u32_t pin)
{
const struct gpio_dw_config *config = port->config->config_info;
struct gpio_dw_runtime *context = port->driver_data;
u32_t base_addr = dw_base_to_block_base(context->base_addr);
if (GPIO_ACCESS_BY_PIN == access_op) {
dw_set_bit(base_addr, INTMASK, pin, 1);
} else {
dw_write(base_addr, INTMASK, BIT_MASK(config->bits));
}
return 0;
}
#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
static void gpio_dw_set_power_state(struct device *port, u32_t power_state)
{
struct gpio_dw_runtime *context = port->driver_data;
context->device_power_state = power_state;
}
static u32_t gpio_dw_get_power_state(struct device *port)
{
struct gpio_dw_runtime *context = port->driver_data;
return context->device_power_state;
}
static inline int gpio_dw_suspend_port(struct device *port)
{
_gpio_dw_clock_off(port);
gpio_dw_set_power_state(port, DEVICE_PM_SUSPEND_STATE);
return 0;
}
static inline int gpio_dw_resume_from_suspend_port(struct device *port)
{
_gpio_dw_clock_on(port);
gpio_dw_set_power_state(port, DEVICE_PM_ACTIVE_STATE);
return 0;
}
/*
* Implements the driver control management functionality
* the *context may include IN data or/and OUT data
*/
static int gpio_dw_device_ctrl(struct device *port, u32_t ctrl_command,
void *context)
{
if (ctrl_command == DEVICE_PM_SET_POWER_STATE) {
if (*((u32_t *)context) == DEVICE_PM_SUSPEND_STATE) {
return gpio_dw_suspend_port(port);
} else if (*((u32_t *)context) == DEVICE_PM_ACTIVE_STATE) {
return gpio_dw_resume_from_suspend_port(port);
}
} else if (ctrl_command == DEVICE_PM_GET_POWER_STATE) {
*((u32_t *)context) = gpio_dw_get_power_state(port);
return 0;
}
return 0;
}
#else
#define gpio_dw_set_power_state(...)
#endif
#if defined(CONFIG_SOC_QUARK_SE_C1000) || defined(CONFIG_SOC_QUARK_D2000)
static inline void gpio_dw_unmask_int(u32_t mask_addr)
{
sys_write32(sys_read32(mask_addr) & INT_UNMASK_IA, mask_addr);
}
#elif CONFIG_SOC_QUARK_SE_C1000_SS
static inline void gpio_dw_unmask_int(u32_t mask_addr)
{
sys_write32(sys_read32(mask_addr) & INT_ENABLE_ARC, mask_addr);
}
#else
#define gpio_dw_unmask_int(...)
#endif
static void gpio_dw_isr(void *arg)
{
struct device *port = (struct device *)arg;
struct gpio_dw_runtime *context = port->driver_data;
u32_t base_addr = dw_base_to_block_base(context->base_addr);
u32_t int_status;
int_status = dw_read(base_addr, INTSTATUS);
#ifdef CONFIG_SHARED_IRQ
/* If using with shared IRQ, this function will be called
* by the shared IRQ driver. So check here if the interrupt
* is coming from the GPIO controller (or somewhere else).
*/
if (!int_status) {
return;
}
#endif
dw_write(base_addr, PORTA_EOI, int_status);
_gpio_fire_callbacks(&context->callbacks, port, int_status);
}
static const struct gpio_driver_api api_funcs = {
.config = gpio_dw_config,
.write = gpio_dw_write,
.read = gpio_dw_read,
.manage_callback = gpio_dw_manage_callback,
.enable_callback = gpio_dw_enable_callback,
.disable_callback = gpio_dw_disable_callback,
};
#ifdef CONFIG_PCI
static inline int gpio_dw_setup(struct device *dev)
{
struct gpio_dw_runtime *context = dev->driver_data;
pci_bus_scan_init();
if (!pci_bus_scan(&context->pci_dev)) {
return 0;
}
#ifdef CONFIG_PCI_ENUMERATION
context->base_addr = context->pci_dev.addr;
#endif
pci_enable_regs(&context->pci_dev);
pci_show(&context->pci_dev);
return 1;
}
#else
#define gpio_dw_setup(_unused_) (1)
#endif /* CONFIG_PCI */
static int gpio_dw_initialize(struct device *port)
{
struct gpio_dw_runtime *context = port->driver_data;
const struct gpio_dw_config *config = port->config->config_info;
u32_t base_addr;
if (!gpio_dw_setup(port)) {
port->driver_api = NULL;
return -EPERM;
}
if (dw_interrupt_support(config)) {
base_addr = dw_base_to_block_base(context->base_addr);
#ifdef CONFIG_SOC_QUARK_SE_C1000_SS
/* Need to enable clock for GPIO controller */
dw_set_bit(base_addr, INT_CLOCK_SYNC, CLK_ENA_POS, 1);
#endif /* CONFIG_SOC_QUARK_SE_C1000_SS */
/* interrupts in sync with system clock */
dw_set_bit(base_addr, INT_CLOCK_SYNC, LS_SYNC_POS, 1);
_gpio_dw_clock_config(port);
/* mask and disable interrupts */
dw_write(base_addr, INTMASK, ~(0));
dw_write(base_addr, INTEN, 0);
dw_write(base_addr, PORTA_EOI, ~(0));
config->config_func(port);
}
gpio_dw_set_power_state(port, DEVICE_PM_ACTIVE_STATE);
return 0;
}
/* Bindings to the plaform */
#ifdef CONFIG_GPIO_DW_0
static void gpio_config_0_irq(struct device *port);
static const struct gpio_dw_config gpio_config_0 = {
#ifdef CONFIG_GPIO_DW_0_IRQ_DIRECT
.irq_num = DT_GPIO_DW_0_IRQ,
#endif
.bits = DT_GPIO_DW_0_BITS,
.config_func = gpio_config_0_irq,
#ifdef CONFIG_GPIO_DW_0_IRQ_SHARED
.shared_irq_dev_name = CONFIG_GPIO_DW_0_IRQ_SHARED_NAME,
#endif
#ifdef CONFIG_GPIO_DW_CLOCK_GATE
.clock_data = UINT_TO_POINTER(CONFIG_GPIO_DW_0_CLOCK_GATE_SUBSYS),
#endif
};
static struct gpio_dw_runtime gpio_0_runtime = {
.base_addr = DT_GPIO_DW_0_BASE_ADDR,
#if CONFIG_PCI
.pci_dev.class_type = GPIO_DW_PCI_CLASS,
.pci_dev.bus = GPIO_DW_0_PCI_BUS,
.pci_dev.dev = GPIO_DW_0_PCI_DEV,
.pci_dev.vendor_id = GPIO_DW_PCI_VENDOR_ID,
.pci_dev.device_id = GPIO_DW_PCI_DEVICE_ID,
.pci_dev.function = GPIO_DW_0_PCI_FUNCTION,
.pci_dev.bar = GPIO_DW_0_PCI_BAR,
#endif
};
#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
DEVICE_DEFINE(gpio_dw_0, CONFIG_GPIO_DW_0_NAME, gpio_dw_initialize,
gpio_dw_device_ctrl, &gpio_0_runtime, &gpio_config_0,
POST_KERNEL, CONFIG_GPIO_DW_INIT_PRIORITY,
&api_funcs);
#else
DEVICE_AND_API_INIT(gpio_dw_0, CONFIG_GPIO_DW_0_NAME, gpio_dw_initialize,
&gpio_0_runtime, &gpio_config_0,
POST_KERNEL, CONFIG_GPIO_DW_INIT_PRIORITY,
&api_funcs);
#endif
static void gpio_config_0_irq(struct device *port)
{
#if (DT_GPIO_DW_0_IRQ > 0)
const struct gpio_dw_config *config = port->config->config_info;
#ifdef CONFIG_GPIO_DW_0_IRQ_DIRECT
IRQ_CONNECT(DT_GPIO_DW_0_IRQ, CONFIG_GPIO_DW_0_IRQ_PRI, gpio_dw_isr,
DEVICE_GET(gpio_dw_0), DT_GPIO_DW_0_IRQ_FLAGS);
irq_enable(config->irq_num);
#elif defined(CONFIG_GPIO_DW_0_IRQ_SHARED)
struct device *shared_irq_dev;
shared_irq_dev = device_get_binding(config->shared_irq_dev_name);
__ASSERT(shared_irq_dev != NULL,
"Failed to get gpio_dw_0 device binding");
shared_irq_isr_register(shared_irq_dev, (isr_t)gpio_dw_isr, port);
shared_irq_enable(shared_irq_dev, port);
#endif
gpio_dw_unmask_int(GPIO_DW_PORT_0_INT_MASK);
#endif
}
#endif /* CONFIG_GPIO_DW_0 */
#ifdef CONFIG_GPIO_DW_1
static void gpio_config_1_irq(struct device *port);
static const struct gpio_dw_config gpio_dw_config_1 = {
#ifdef CONFIG_GPIO_DW_1_IRQ_DIRECT
.irq_num = DT_GPIO_DW_1_IRQ,
#endif
.bits = DT_GPIO_DW_1_BITS,
.config_func = gpio_config_1_irq,
#ifdef CONFIG_GPIO_DW_1_IRQ_SHARED
.shared_irq_dev_name = CONFIG_GPIO_DW_1_IRQ_SHARED_NAME,
#endif
#ifdef CONFIG_GPIO_DW_CLOCK_GATE
.clock_data = UINT_TO_POINTER(CONFIG_GPIO_DW_1_CLOCK_GATE_SUBSYS),
#endif
};
static struct gpio_dw_runtime gpio_1_runtime = {
.base_addr = DT_GPIO_DW_1_BASE_ADDR,
#if CONFIG_PCI
.pci_dev.class_type = GPIO_DW_PCI_CLASS,
.pci_dev.bus = GPIO_DW_1_PCI_BUS,
.pci_dev.dev = GPIO_DW_1_PCI_DEV,
.pci_dev.vendor_id = GPIO_DW_PCI_VENDOR_ID,
.pci_dev.device_id = GPIO_DW_PCI_DEVICE_ID,
.pci_dev.function = GPIO_DW_1_PCI_FUNCTION,
.pci_dev.bar = GPIO_DW_1_PCI_BAR,
#endif
};
#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
DEVICE_DEFINE(gpio_dw_1, CONFIG_GPIO_DW_1_NAME, gpio_dw_initialize,
gpio_dw_device_ctrl, &gpio_1_runtime, &gpio_dw_config_1,
POST_KERNEL, CONFIG_GPIO_DW_INIT_PRIORITY,
&api_funcs);
#else
DEVICE_AND_API_INIT(gpio_dw_1, CONFIG_GPIO_DW_1_NAME, gpio_dw_initialize,
&gpio_1_runtime, &gpio_dw_config_1,
POST_KERNEL, CONFIG_GPIO_DW_INIT_PRIORITY,
&api_funcs);
#endif
static void gpio_config_1_irq(struct device *port)
{
#if (DT_GPIO_DW_1_IRQ > 0)
const struct gpio_dw_config *config = port->config->config_info;
#ifdef CONFIG_GPIO_DW_1_IRQ_DIRECT
IRQ_CONNECT(DT_GPIO_DW_1_IRQ, CONFIG_GPIO_DW_1_IRQ_PRI, gpio_dw_isr,
DEVICE_GET(gpio_dw_1), GPIO_DW_1_IRQ_FLAGS);
irq_enable(config->irq_num);
#elif defined(CONFIG_GPIO_DW_1_IRQ_SHARED)
struct device *shared_irq_dev;
shared_irq_dev = device_get_binding(config->shared_irq_dev_name);
__ASSERT(shared_irq_dev != NULL,
"Failed to get gpio_dw_1 device binding");
shared_irq_isr_register(shared_irq_dev, (isr_t)gpio_dw_isr, port);
shared_irq_enable(shared_irq_dev, port);
#endif
gpio_dw_unmask_int(GPIO_DW_PORT_1_INT_MASK);
#endif
}
#endif /* CONFIG_GPIO_DW_1 */
#ifdef CONFIG_GPIO_DW_2
static void gpio_config_2_irq(struct device *port);
static const struct gpio_dw_config gpio_dw_config_2 = {
#ifdef CONFIG_GPIO_DW_2_IRQ_DIRECT
.irq_num = DT_GPIO_DW_2_IRQ,
#endif
.bits = DT_GPIO_DW_2_BITS,
.config_func = gpio_config_2_irq,
#ifdef CONFIG_GPIO_DW_2_IRQ_SHARED
.shared_irq_dev_name = CONFIG_GPIO_DW_2_IRQ_SHARED_NAME,
#endif
#ifdef CONFIG_GPIO_DW_CLOCK_GATE
.clock_data = UINT_TO_POINTER(CONFIG_GPIO_DW_2_CLOCK_GATE_SUBSYS),
#endif
};
static struct gpio_dw_runtime gpio_2_runtime = {
.base_addr = DT_GPIO_DW_2_BASE_ADDR,
#if CONFIG_PCI
.pci_dev.class_type = GPIO_DW_PCI_CLASS,
.pci_dev.bus = GPIO_DW_2_PCI_BUS,
.pci_dev.dev = GPIO_DW_2_PCI_DEV,
.pci_dev.vendor_id = GPIO_DW_PCI_VENDOR_ID,
.pci_dev.device_id = GPIO_DW_PCI_DEVICE_ID,
.pci_dev.function = GPIO_DW_2_PCI_FUNCTION,
.pci_dev.bar = GPIO_DW_2_PCI_BAR,
#endif
};
#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
DEVICE_DEFINE(gpio_dw_2, CONFIG_GPIO_DW_2_NAME, gpio_dw_initialize,
gpio_dw_device_ctrl, &gpio_2_runtime, &gpio_dw_config_2,
POST_KERNEL, CONFIG_GPIO_DW_INIT_PRIORITY,
&api_funcs);
#else
DEVICE_AND_API_INIT(gpio_dw_2, CONFIG_GPIO_DW_2_NAME, gpio_dw_initialize,
&gpio_2_runtime, &gpio_dw_config_2,
POST_KERNEL, CONFIG_GPIO_DW_INIT_PRIORITY,
&api_funcs);
#endif
static void gpio_config_2_irq(struct device *port)
{
#if (DT_GPIO_DW_2_IRQ > 0)
const struct gpio_dw_config *config = port->config->config_info;
#ifdef CONFIG_GPIO_DW_2_IRQ_DIRECT
IRQ_CONNECT(DT_GPIO_DW_2_IRQ, CONFIG_GPIO_DW_2_IRQ_PRI, gpio_dw_isr,
DEVICE_GET(gpio_dw_2), GPIO_DW_2_IRQ_FLAGS);
irq_enable(config->irq_num);
#elif defined(CONFIG_GPIO_DW_2_IRQ_SHARED)
struct device *shared_irq_dev;
shared_irq_dev = device_get_binding(config->shared_irq_dev_name);
__ASSERT(shared_irq_dev != NULL,
"Failed to get gpio_dw_2 device binding");
shared_irq_isr_register(shared_irq_dev, (isr_t)gpio_dw_isr, port);
shared_irq_enable(shared_irq_dev, port);
#endif
gpio_dw_unmask_int(GPIO_DW_PORT_2_INT_MASK);
#endif
}
#endif /* CONFIG_GPIO_DW_2 */
#ifdef CONFIG_GPIO_DW_3
static void gpio_config_3_irq(struct device *port);
static const struct gpio_dw_config gpio_dw_config_3 = {
#ifdef CONFIG_GPIO_DW_3_IRQ_DIRECT
.irq_num = DT_GPIO_DW_3_IRQ,
#endif
.bits = DT_GPIO_DW_3_BITS,
.config_func = gpio_config_3_irq,
#ifdef CONFIG_GPIO_DW_3_IRQ_SHARED
.shared_irq_dev_name = CONFIG_GPIO_DW_3_IRQ_SHARED_NAME,
#endif
#ifdef CONFIG_GPIO_DW_CLOCK_GATE
.clock_data = UINT_TO_POINTER(CONFIG_GPIO_DW_3_CLOCK_GATE_SUBSYS),
#endif
};
static struct gpio_dw_runtime gpio_3_runtime = {
.base_addr = DT_GPIO_DW_3_BASE_ADDR,
#if CONFIG_PCI
.pci_dev.class_type = GPIO_DW_PCI_CLASS,
.pci_dev.bus = GPIO_DW_3_PCI_BUS,
.pci_dev.dev = GPIO_DW_3_PCI_DEV,
.pci_dev.vendor_id = GPIO_DW_PCI_VENDOR_ID,
.pci_dev.device_id = GPIO_DW_PCI_DEVICE_ID,
.pci_dev.function = GPIO_DW_3_PCI_FUNCTION,
.pci_dev.bar = GPIO_DW_3_PCI_BAR,
#endif
};
#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
DEVICE_DEFINE(gpio_dw_3, CONFIG_GPIO_DW_3_NAME, gpio_dw_initialize,
gpio_dw_device_ctrl, &gpio_3_runtime, &gpio_dw_config_3,
POST_KERNEL, CONFIG_GPIO_DW_INIT_PRIORITY,
&api_funcs);
#else
DEVICE_AND_API_INIT(gpio_dw_3, CONFIG_GPIO_DW_3_NAME, gpio_dw_initialize,
&gpio_3_runtime, &gpio_dw_config_3,
POST_KERNEL, CONFIG_GPIO_DW_INIT_PRIORITY,
&api_funcs);
#endif
static void gpio_config_3_irq(struct device *port)
{
#if (DT_GPIO_DW_3_IRQ > 0)
const struct gpio_dw_config *config = port->config->config_info;
#ifdef CONFIG_GPIO_DW_3_IRQ_DIRECT
IRQ_CONNECT(DT_GPIO_DW_3_IRQ, CONFIG_GPIO_DW_3_IRQ_PRI, gpio_dw_isr,
DEVICE_GET(gpio_dw_3), GPIO_DW_3_IRQ_FLAGS);
irq_enable(config->irq_num);
#elif defined(CONFIG_GPIO_DW_3_IRQ_SHARED)
struct device *shared_irq_dev;
shared_irq_dev = device_get_binding(config->shared_irq_dev_name);
__ASSERT(shared_irq_dev != NULL,
"Failed to get gpio_dw_3 device binding");
shared_irq_isr_register(shared_irq_dev, (isr_t)gpio_dw_isr, port);
shared_irq_enable(shared_irq_dev, port);
#endif
gpio_dw_unmask_int(GPIO_DW_PORT_3_INT_MASK);
#endif
}
#endif /* CONFIG_GPIO_DW_3 */