drivers/gpio/gpio_intel_apl: remove dependency on shared interrupts

The GPIO driver for the Intel Apollo Lake has so many pins it has to
export ten devices to shoehorn its one device into the GPIO API. The
current implementation uses the shared IRQ driver because these
pseudodevices all share one IRQ. However, since the GPIO driver is
aware of all the possible interrupt sources, it's smaller and faster
(and not even messy) to handle it internally, so this patch eliminates
the dependency on the shared IRQ driver.

Signed-off-by: Charles E. Youse <charles.youse@intel.com>
This commit is contained in:
Charles E. Youse 2019-04-21 20:59:40 -07:00 committed by Andrew Boie
commit 6fc655351c
5 changed files with 92 additions and 118 deletions

View file

@ -15,13 +15,14 @@
* The GPIO controller has 245 pins divided into four sets.
* Each set has its own MMIO address space. Due to GPIO
* callback only allowing 32 pins (as a 32-bit mask) at once,
* each set is further sub-divided into multiple devices.
* Because of this, shared IRQ must be used.
* each set is further sub-divided into multiple devices, so
* we export GPIO_INTEL_APL_NR_SUBDEVS devices to the kernel.
*/
#define GPIO_INTEL_APL_NR_SUBDEVS 10
#include <errno.h>
#include <gpio.h>
#include <shared_irq.h>
#include <soc.h>
#include <sys_io.h>
#include <misc/__assert.h>
@ -30,9 +31,12 @@
#include "gpio_utils.h"
#ifndef CONFIG_SHARED_IRQ
#error "Need CONFIG_SHARED_IRQ!"
#endif
/*
* only IRQ 14 is supported now. the docs say IRQ 15 is supported
* as well, but my (admitted cursory) testing disagrees.
*/
BUILD_ASSERT(DT_APL_GPIO_IRQ == 14);
#define REG_PAD_BASE_ADDR 0x000C
@ -148,29 +152,45 @@ static bool check_perm(struct device *dev, u32_t raw_pin)
#define check_perm(...) (1)
#endif
/*
* as the kernel initializes the subdevices, we add them
* to the list of devices to check at ISR time.
*/
static int nr_isr_devs;
static struct device *isr_devs[GPIO_INTEL_APL_NR_SUBDEVS];
static int gpio_intel_apl_isr(struct device *dev)
{
const struct gpio_intel_apl_config *cfg = dev->config->config_info;
struct gpio_intel_apl_data *data = dev->driver_data;
const struct gpio_intel_apl_config *cfg;
struct gpio_intel_apl_data *data;
struct gpio_callback *cb, *tmp;
u32_t reg, int_sts, cur_mask, acc_mask;
int isr_dev;
reg = cfg->reg_base + REG_GPI_INT_STS_BASE
+ ((cfg->pin_offset >> 5) << 2);
int_sts = sys_read32(reg);
acc_mask = 0U;
for (isr_dev = 0; isr_dev < nr_isr_devs; ++isr_dev) {
dev = isr_devs[isr_dev];
cfg = dev->config->config_info;
data = dev->driver_data;
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&data->cb, cb, tmp, node) {
cur_mask = int_sts & cb->pin_mask;
acc_mask |= cur_mask;
if (cur_mask) {
__ASSERT(cb->handler, "No callback handler!");
cb->handler(dev, cb, cur_mask);
reg = cfg->reg_base + REG_GPI_INT_STS_BASE
+ ((cfg->pin_offset >> 5) << 2);
int_sts = sys_read32(reg);
acc_mask = 0U;
SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&data->cb, cb, tmp, node) {
cur_mask = int_sts & cb->pin_mask;
acc_mask |= cur_mask;
if (cur_mask) {
__ASSERT(cb->handler, "No callback handler!");
cb->handler(dev, cb, cur_mask);
}
}
}
/* clear handled interrupt bits */
sys_write32(acc_mask, reg);
/* clear handled interrupt bits */
sys_write32(acc_mask, reg);
}
return 0;
}
@ -432,18 +452,28 @@ static const struct gpio_driver_api gpio_intel_apl_api = {
.disable_callback = gpio_intel_apl_disable_callback,
};
static void gpio_intel_apl_irq_config(struct device *dev);
int gpio_intel_apl_init(struct device *dev)
{
const struct gpio_intel_apl_config *cfg = dev->config->config_info;
struct gpio_intel_apl_data *data = dev->driver_data;
gpio_intel_apl_irq_config(dev);
data->pad_base = sys_read32(cfg->reg_base + REG_PAD_BASE_ADDR);
/* Set to route interrupt through IRQ 14 */
__ASSERT(nr_isr_devs < GPIO_INTEL_APL_NR_SUBDEVS, "too many subdevs");
if (nr_isr_devs == 0) {
IRQ_CONNECT(DT_APL_GPIO_IRQ,
DT_APL_GPIO_IRQ_PRIORITY,
gpio_intel_apl_isr, NULL,
DT_APL_GPIO_IRQ_SENSE);
irq_enable(DT_APL_GPIO_IRQ);
}
isr_devs[nr_isr_devs++] = dev;
/* route to IRQ 14 */
sys_bitfield_clear_bit(data->pad_base + REG_MISCCFG,
MISCCFG_IRQ_ROUTE_POS);
@ -470,6 +500,8 @@ DEVICE_AND_API_INIT(gpio_intel_apl_##dir_l##_##pos, \
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \
&gpio_intel_apl_api)
/* "sub" devices. no more than GPIO_INTEL_APL_NR_SUBDEVS of these! */
GPIO_INTEL_APL_DEV_CFG_DATA(n, N, 0, 0, 32);
GPIO_INTEL_APL_DEV_CFG_DATA(n, N, 1, 32, 32);
GPIO_INTEL_APL_DEV_CFG_DATA(n, N, 2, 32, 14);
@ -483,15 +515,3 @@ GPIO_INTEL_APL_DEV_CFG_DATA(w, W, 1, 32, 15);
GPIO_INTEL_APL_DEV_CFG_DATA(sw, SW, 0, 0, 32);
GPIO_INTEL_APL_DEV_CFG_DATA(sw, SW, 1, 32, 11);
static void gpio_intel_apl_irq_config(struct device *dev)
{
struct device *irq_dev;
irq_dev = device_get_binding(DT_SHARED_IRQ_SHAREDIRQ0_LABEL);
__ASSERT(irq_dev != NULL,
"Failed to get shared IRQ device binding");
shared_irq_isr_register(irq_dev, gpio_intel_apl_isr, dev);
shared_irq_enable(irq_dev, dev);
}