gpio: omap: convert driver to use gpiolib irqchip
Converts the GPIO OMAP driver to register its chained irq handler and irqchip using the helpers in the gpiolib core. Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk> Tested-by: Tony Lindgren <tony@atomide.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
parent
cd0a3748f3
commit
fb655f57ce
2 changed files with 52 additions and 56 deletions
drivers/gpio
|
@ -247,6 +247,7 @@ config GPIO_OMAP
|
||||||
bool "TI OMAP GPIO support"
|
bool "TI OMAP GPIO support"
|
||||||
default y if ARCH_OMAP
|
default y if ARCH_OMAP
|
||||||
depends on ARM && ARCH_OMAP
|
depends on ARM && ARCH_OMAP
|
||||||
|
select GPIOLIB_IRQCHIP
|
||||||
help
|
help
|
||||||
Say yes here to enable GPIO support for TI OMAP SoCs.
|
Say yes here to enable GPIO support for TI OMAP SoCs.
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
#include <linux/pm.h>
|
#include <linux/pm.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
#include <linux/irqdomain.h>
|
|
||||||
#include <linux/irqchip/chained_irq.h>
|
#include <linux/irqchip/chained_irq.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio.h>
|
||||||
#include <linux/platform_data/gpio-omap.h>
|
#include <linux/platform_data/gpio-omap.h>
|
||||||
|
@ -52,7 +51,6 @@ struct gpio_bank {
|
||||||
struct list_head node;
|
struct list_head node;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
u16 irq;
|
u16 irq;
|
||||||
struct irq_domain *domain;
|
|
||||||
u32 non_wakeup_gpios;
|
u32 non_wakeup_gpios;
|
||||||
u32 enabled_non_wakeup_gpios;
|
u32 enabled_non_wakeup_gpios;
|
||||||
struct gpio_regs context;
|
struct gpio_regs context;
|
||||||
|
@ -95,11 +93,10 @@ static int irq_to_gpio(struct gpio_bank *bank, unsigned int gpio_irq)
|
||||||
return bank->chip.base + gpio_irq;
|
return bank->chip.base + gpio_irq;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int omap_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
static inline struct gpio_bank *_irq_data_get_bank(struct irq_data *d)
|
||||||
{
|
{
|
||||||
struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
|
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
|
||||||
|
return container_of(chip, struct gpio_bank, chip);
|
||||||
return irq_find_mapping(bank->domain, offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
|
static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
|
||||||
|
@ -479,7 +476,7 @@ static int gpio_is_input(struct gpio_bank *bank, int mask)
|
||||||
|
|
||||||
static int gpio_irq_type(struct irq_data *d, unsigned type)
|
static int gpio_irq_type(struct irq_data *d, unsigned type)
|
||||||
{
|
{
|
||||||
struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
|
struct gpio_bank *bank = _irq_data_get_bank(d);
|
||||||
unsigned gpio = 0;
|
unsigned gpio = 0;
|
||||||
int retval;
|
int retval;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
@ -514,14 +511,6 @@ static int gpio_irq_type(struct irq_data *d, unsigned type)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = gpio_lock_as_irq(&bank->chip, offset);
|
|
||||||
if (retval) {
|
|
||||||
dev_err(bank->dev, "unable to lock offset %d for IRQ\n",
|
|
||||||
offset);
|
|
||||||
spin_unlock_irqrestore(&bank->lock, flags);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
bank->irq_usage |= 1 << GPIO_INDEX(bank, gpio);
|
bank->irq_usage |= 1 << GPIO_INDEX(bank, gpio);
|
||||||
spin_unlock_irqrestore(&bank->lock, flags);
|
spin_unlock_irqrestore(&bank->lock, flags);
|
||||||
|
|
||||||
|
@ -664,7 +653,7 @@ static void _reset_gpio(struct gpio_bank *bank, int gpio)
|
||||||
/* Use disable_irq_wake() and enable_irq_wake() functions from drivers */
|
/* Use disable_irq_wake() and enable_irq_wake() functions from drivers */
|
||||||
static int gpio_wake_enable(struct irq_data *d, unsigned int enable)
|
static int gpio_wake_enable(struct irq_data *d, unsigned int enable)
|
||||||
{
|
{
|
||||||
struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
|
struct gpio_bank *bank = _irq_data_get_bank(d);
|
||||||
unsigned int gpio = irq_to_gpio(bank, d->hwirq);
|
unsigned int gpio = irq_to_gpio(bank, d->hwirq);
|
||||||
|
|
||||||
return _set_gpio_wakeup(bank, gpio, enable);
|
return _set_gpio_wakeup(bank, gpio, enable);
|
||||||
|
@ -732,11 +721,12 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
|
||||||
unsigned int bit;
|
unsigned int bit;
|
||||||
struct gpio_bank *bank;
|
struct gpio_bank *bank;
|
||||||
int unmasked = 0;
|
int unmasked = 0;
|
||||||
struct irq_chip *chip = irq_desc_get_chip(desc);
|
struct irq_chip *irqchip = irq_desc_get_chip(desc);
|
||||||
|
struct gpio_chip *chip = irq_get_handler_data(irq);
|
||||||
|
|
||||||
chained_irq_enter(chip, desc);
|
chained_irq_enter(irqchip, desc);
|
||||||
|
|
||||||
bank = irq_get_handler_data(irq);
|
bank = container_of(chip, struct gpio_bank, chip);
|
||||||
isr_reg = bank->base + bank->regs->irqstatus;
|
isr_reg = bank->base + bank->regs->irqstatus;
|
||||||
pm_runtime_get_sync(bank->dev);
|
pm_runtime_get_sync(bank->dev);
|
||||||
|
|
||||||
|
@ -764,7 +754,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
|
||||||
configured, we could unmask GPIO bank interrupt immediately */
|
configured, we could unmask GPIO bank interrupt immediately */
|
||||||
if (!level_mask && !unmasked) {
|
if (!level_mask && !unmasked) {
|
||||||
unmasked = 1;
|
unmasked = 1;
|
||||||
chained_irq_exit(chip, desc);
|
chained_irq_exit(irqchip, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isr)
|
if (!isr)
|
||||||
|
@ -784,7 +774,8 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
|
||||||
if (bank->toggle_mask & (1 << bit))
|
if (bank->toggle_mask & (1 << bit))
|
||||||
_toggle_gpio_edge_triggering(bank, bit);
|
_toggle_gpio_edge_triggering(bank, bit);
|
||||||
|
|
||||||
generic_handle_irq(irq_find_mapping(bank->domain, bit));
|
generic_handle_irq(irq_find_mapping(bank->chip.irqdomain,
|
||||||
|
bit));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* if bank has any level sensitive GPIO pin interrupt
|
/* if bank has any level sensitive GPIO pin interrupt
|
||||||
|
@ -793,13 +784,13 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
|
||||||
interrupt */
|
interrupt */
|
||||||
exit:
|
exit:
|
||||||
if (!unmasked)
|
if (!unmasked)
|
||||||
chained_irq_exit(chip, desc);
|
chained_irq_exit(irqchip, desc);
|
||||||
pm_runtime_put(bank->dev);
|
pm_runtime_put(bank->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gpio_irq_shutdown(struct irq_data *d)
|
static void gpio_irq_shutdown(struct irq_data *d)
|
||||||
{
|
{
|
||||||
struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
|
struct gpio_bank *bank = _irq_data_get_bank(d);
|
||||||
unsigned int gpio = irq_to_gpio(bank, d->hwirq);
|
unsigned int gpio = irq_to_gpio(bank, d->hwirq);
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
unsigned offset = GPIO_INDEX(bank, gpio);
|
unsigned offset = GPIO_INDEX(bank, gpio);
|
||||||
|
@ -821,7 +812,7 @@ static void gpio_irq_shutdown(struct irq_data *d)
|
||||||
|
|
||||||
static void gpio_ack_irq(struct irq_data *d)
|
static void gpio_ack_irq(struct irq_data *d)
|
||||||
{
|
{
|
||||||
struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
|
struct gpio_bank *bank = _irq_data_get_bank(d);
|
||||||
unsigned int gpio = irq_to_gpio(bank, d->hwirq);
|
unsigned int gpio = irq_to_gpio(bank, d->hwirq);
|
||||||
|
|
||||||
_clear_gpio_irqstatus(bank, gpio);
|
_clear_gpio_irqstatus(bank, gpio);
|
||||||
|
@ -829,7 +820,7 @@ static void gpio_ack_irq(struct irq_data *d)
|
||||||
|
|
||||||
static void gpio_mask_irq(struct irq_data *d)
|
static void gpio_mask_irq(struct irq_data *d)
|
||||||
{
|
{
|
||||||
struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
|
struct gpio_bank *bank = _irq_data_get_bank(d);
|
||||||
unsigned int gpio = irq_to_gpio(bank, d->hwirq);
|
unsigned int gpio = irq_to_gpio(bank, d->hwirq);
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
|
@ -841,7 +832,7 @@ static void gpio_mask_irq(struct irq_data *d)
|
||||||
|
|
||||||
static void gpio_unmask_irq(struct irq_data *d)
|
static void gpio_unmask_irq(struct irq_data *d)
|
||||||
{
|
{
|
||||||
struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
|
struct gpio_bank *bank = _irq_data_get_bank(d);
|
||||||
unsigned int gpio = irq_to_gpio(bank, d->hwirq);
|
unsigned int gpio = irq_to_gpio(bank, d->hwirq);
|
||||||
unsigned int irq_mask = GPIO_BIT(bank, gpio);
|
unsigned int irq_mask = GPIO_BIT(bank, gpio);
|
||||||
u32 trigger = irqd_get_trigger_type(d);
|
u32 trigger = irqd_get_trigger_type(d);
|
||||||
|
@ -1085,6 +1076,7 @@ static int omap_gpio_chip_init(struct gpio_bank *bank)
|
||||||
{
|
{
|
||||||
int j;
|
int j;
|
||||||
static int gpio;
|
static int gpio;
|
||||||
|
int irq_base = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1098,7 +1090,6 @@ static int omap_gpio_chip_init(struct gpio_bank *bank)
|
||||||
bank->chip.direction_output = gpio_output;
|
bank->chip.direction_output = gpio_output;
|
||||||
bank->chip.set_debounce = gpio_debounce;
|
bank->chip.set_debounce = gpio_debounce;
|
||||||
bank->chip.set = gpio_set;
|
bank->chip.set = gpio_set;
|
||||||
bank->chip.to_irq = omap_gpio_to_irq;
|
|
||||||
if (bank->is_mpuio) {
|
if (bank->is_mpuio) {
|
||||||
bank->chip.label = "mpuio";
|
bank->chip.label = "mpuio";
|
||||||
if (bank->regs->wkup_en)
|
if (bank->regs->wkup_en)
|
||||||
|
@ -1113,24 +1104,46 @@ static int omap_gpio_chip_init(struct gpio_bank *bank)
|
||||||
|
|
||||||
ret = gpiochip_add(&bank->chip);
|
ret = gpiochip_add(&bank->chip);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(bank->dev, "Could not register gpio chip\n", ret);
|
dev_err(bank->dev, "Could not register gpio chip %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_ARCH_OMAP1
|
||||||
|
/*
|
||||||
|
* REVISIT: Once we have OMAP1 supporting SPARSE_IRQ, we can drop
|
||||||
|
* irq_alloc_descs() since a base IRQ offset will no longer be needed.
|
||||||
|
*/
|
||||||
|
irq_base = irq_alloc_descs(-1, 0, bank->width, 0);
|
||||||
|
if (irq_base < 0) {
|
||||||
|
dev_err(bank->dev, "Couldn't allocate IRQ numbers\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ret = gpiochip_irqchip_add(&bank->chip, &gpio_irq_chip,
|
||||||
|
irq_base, gpio_irq_handler,
|
||||||
|
IRQ_TYPE_NONE);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
dev_err(bank->dev, "Couldn't add irqchip to gpiochip %d\n", ret);
|
||||||
|
ret = gpiochip_remove(&bank->chip);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
gpiochip_set_chained_irqchip(&bank->chip, &gpio_irq_chip,
|
||||||
|
bank->irq, gpio_irq_handler);
|
||||||
|
|
||||||
for (j = 0; j < bank->width; j++) {
|
for (j = 0; j < bank->width; j++) {
|
||||||
int irq = irq_create_mapping(bank->domain, j);
|
int irq = irq_find_mapping(bank->chip.irqdomain, j);
|
||||||
irq_set_lockdep_class(irq, &gpio_lock_class);
|
irq_set_lockdep_class(irq, &gpio_lock_class);
|
||||||
irq_set_chip_data(irq, bank);
|
|
||||||
if (bank->is_mpuio) {
|
if (bank->is_mpuio) {
|
||||||
omap_mpuio_alloc_gc(bank, irq, bank->width);
|
omap_mpuio_alloc_gc(bank, irq, bank->width);
|
||||||
} else {
|
irq_set_chip_and_handler(irq, NULL, NULL);
|
||||||
irq_set_chip_and_handler(irq, &gpio_irq_chip,
|
set_irq_flags(irq, 0);
|
||||||
handle_simple_irq);
|
|
||||||
set_irq_flags(irq, IRQF_VALID);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
irq_set_chained_handler(bank->irq, gpio_irq_handler);
|
|
||||||
irq_set_handler_data(bank->irq, bank);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id omap_gpio_match[];
|
static const struct of_device_id omap_gpio_match[];
|
||||||
|
@ -1143,7 +1156,6 @@ static int omap_gpio_probe(struct platform_device *pdev)
|
||||||
const struct omap_gpio_platform_data *pdata;
|
const struct omap_gpio_platform_data *pdata;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
struct gpio_bank *bank;
|
struct gpio_bank *bank;
|
||||||
int irq_base = 0;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
match = of_match_device(of_match_ptr(omap_gpio_match), dev);
|
match = of_match_device(of_match_ptr(omap_gpio_match), dev);
|
||||||
|
@ -1166,6 +1178,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
bank->irq = res->start;
|
bank->irq = res->start;
|
||||||
bank->dev = dev;
|
bank->dev = dev;
|
||||||
|
bank->chip.dev = dev;
|
||||||
bank->dbck_flag = pdata->dbck_flag;
|
bank->dbck_flag = pdata->dbck_flag;
|
||||||
bank->stride = pdata->bank_stride;
|
bank->stride = pdata->bank_stride;
|
||||||
bank->width = pdata->bank_width;
|
bank->width = pdata->bank_width;
|
||||||
|
@ -1186,24 +1199,6 @@ static int omap_gpio_probe(struct platform_device *pdev)
|
||||||
pdata->get_context_loss_count;
|
pdata->get_context_loss_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_ARCH_OMAP1
|
|
||||||
/*
|
|
||||||
* REVISIT: Once we have OMAP1 supporting SPARSE_IRQ, we can drop
|
|
||||||
* irq_alloc_descs() since a base IRQ offset will no longer be needed.
|
|
||||||
*/
|
|
||||||
irq_base = irq_alloc_descs(-1, 0, bank->width, 0);
|
|
||||||
if (irq_base < 0) {
|
|
||||||
dev_err(dev, "Couldn't allocate IRQ numbers\n");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
bank->domain = irq_domain_add_simple(node, bank->width, irq_base,
|
|
||||||
&irq_domain_simple_ops, NULL);
|
|
||||||
if (!bank->domain) {
|
|
||||||
dev_err(dev, "Couldn't register an IRQ domain\n");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bank->regs->set_dataout && bank->regs->clr_dataout)
|
if (bank->regs->set_dataout && bank->regs->clr_dataout)
|
||||||
bank->set_dataout = _set_gpio_dataout_reg;
|
bank->set_dataout = _set_gpio_dataout_reg;
|
||||||
else
|
else
|
||||||
|
@ -1215,7 +1210,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
bank->base = devm_ioremap_resource(dev, res);
|
bank->base = devm_ioremap_resource(dev, res);
|
||||||
if (IS_ERR(bank->base)) {
|
if (IS_ERR(bank->base)) {
|
||||||
irq_domain_remove(bank->domain);
|
irq_domain_remove(bank->chip.irqdomain);
|
||||||
return PTR_ERR(bank->base);
|
return PTR_ERR(bank->base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue