Commit 984f6643 authored by Linus Walleij's avatar Linus Walleij

gpio: max732x: convert to GPIOLIB_IRQCHIP

Take a sweep to bring the irq support for the MAX732x expanders
into the gpiolib core to cut down on duplicated code.

Only compile tested! I need some feedback from people using this
expander with interrupts to tell me if things go right or
wrong when I do this.

Cc: Semen Protsenko <semen.protsenko@globallogic.com>
Cc: Mans Rullgard <mans@mansr.com>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent fd9c963c
...@@ -543,7 +543,6 @@ config GPIO_MAX7300 ...@@ -543,7 +543,6 @@ config GPIO_MAX7300
config GPIO_MAX732X config GPIO_MAX732X
tristate "MAX7319, MAX7320-7327 I2C Port Expanders" tristate "MAX7319, MAX7320-7327 I2C Port Expanders"
depends on I2C depends on I2C
select IRQ_DOMAIN
help help
Say yes here to support the MAX7319, MAX7320-7327 series of I2C Say yes here to support the MAX7319, MAX7320-7327 series of I2C
Port Expanders. Each IO port on these chips has a fixed role of Port Expanders. Each IO port on these chips has a fixed role of
...@@ -563,6 +562,7 @@ config GPIO_MAX732X ...@@ -563,6 +562,7 @@ config GPIO_MAX732X
config GPIO_MAX732X_IRQ config GPIO_MAX732X_IRQ
bool "Interrupt controller support for MAX732x" bool "Interrupt controller support for MAX732x"
depends on GPIO_MAX732X=y depends on GPIO_MAX732X=y
select GPIOLIB_IRQCHIP
help help
Say yes here to enable the max732x to be used as an interrupt Say yes here to enable the max732x to be used as an interrupt
controller. It requires the driver to be built in the kernel. controller. It requires the driver to be built in the kernel.
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
* Copyright (C) 2007 Marvell International Ltd. * Copyright (C) 2007 Marvell International Ltd.
* Copyright (C) 2008 Jack Ren <jack.ren@marvell.com> * Copyright (C) 2008 Jack Ren <jack.ren@marvell.com>
* Copyright (C) 2008 Eric Miao <eric.miao@marvell.com> * Copyright (C) 2008 Eric Miao <eric.miao@marvell.com>
* Copyright (C) 2015 Linus Walleij <linus.walleij@linaro.org>
* *
* Derived from drivers/gpio/pca953x.c * Derived from drivers/gpio/pca953x.c
* *
...@@ -16,10 +17,8 @@ ...@@ -16,10 +17,8 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/gpio.h> #include <linux/gpio/driver.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/i2c/max732x.h> #include <linux/i2c/max732x.h>
#include <linux/of.h> #include <linux/of.h>
...@@ -150,9 +149,7 @@ struct max732x_chip { ...@@ -150,9 +149,7 @@ struct max732x_chip {
uint8_t reg_out[2]; uint8_t reg_out[2];
#ifdef CONFIG_GPIO_MAX732X_IRQ #ifdef CONFIG_GPIO_MAX732X_IRQ
struct irq_domain *irq_domain;
struct mutex irq_lock; struct mutex irq_lock;
int irq_base;
uint8_t irq_mask; uint8_t irq_mask;
uint8_t irq_mask_cur; uint8_t irq_mask_cur;
uint8_t irq_trig_raise; uint8_t irq_trig_raise;
...@@ -356,35 +353,26 @@ static void max732x_irq_update_mask(struct max732x_chip *chip) ...@@ -356,35 +353,26 @@ static void max732x_irq_update_mask(struct max732x_chip *chip)
mutex_unlock(&chip->lock); mutex_unlock(&chip->lock);
} }
static int max732x_gpio_to_irq(struct gpio_chip *gc, unsigned off)
{
struct max732x_chip *chip = to_max732x(gc);
if (chip->irq_domain) {
return irq_create_mapping(chip->irq_domain,
chip->irq_base + off);
} else {
return -ENXIO;
}
}
static void max732x_irq_mask(struct irq_data *d) static void max732x_irq_mask(struct irq_data *d)
{ {
struct max732x_chip *chip = irq_data_get_irq_chip_data(d); struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct max732x_chip *chip = to_max732x(gc);
chip->irq_mask_cur &= ~(1 << d->hwirq); chip->irq_mask_cur &= ~(1 << d->hwirq);
} }
static void max732x_irq_unmask(struct irq_data *d) static void max732x_irq_unmask(struct irq_data *d)
{ {
struct max732x_chip *chip = irq_data_get_irq_chip_data(d); struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct max732x_chip *chip = to_max732x(gc);
chip->irq_mask_cur |= 1 << d->hwirq; chip->irq_mask_cur |= 1 << d->hwirq;
} }
static void max732x_irq_bus_lock(struct irq_data *d) static void max732x_irq_bus_lock(struct irq_data *d)
{ {
struct max732x_chip *chip = irq_data_get_irq_chip_data(d); struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct max732x_chip *chip = to_max732x(gc);
mutex_lock(&chip->irq_lock); mutex_lock(&chip->irq_lock);
chip->irq_mask_cur = chip->irq_mask; chip->irq_mask_cur = chip->irq_mask;
...@@ -392,7 +380,8 @@ static void max732x_irq_bus_lock(struct irq_data *d) ...@@ -392,7 +380,8 @@ static void max732x_irq_bus_lock(struct irq_data *d)
static void max732x_irq_bus_sync_unlock(struct irq_data *d) static void max732x_irq_bus_sync_unlock(struct irq_data *d)
{ {
struct max732x_chip *chip = irq_data_get_irq_chip_data(d); struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct max732x_chip *chip = to_max732x(gc);
uint16_t new_irqs; uint16_t new_irqs;
uint16_t level; uint16_t level;
...@@ -410,7 +399,8 @@ static void max732x_irq_bus_sync_unlock(struct irq_data *d) ...@@ -410,7 +399,8 @@ static void max732x_irq_bus_sync_unlock(struct irq_data *d)
static int max732x_irq_set_type(struct irq_data *d, unsigned int type) static int max732x_irq_set_type(struct irq_data *d, unsigned int type)
{ {
struct max732x_chip *chip = irq_data_get_irq_chip_data(d); struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct max732x_chip *chip = to_max732x(gc);
uint16_t off = d->hwirq; uint16_t off = d->hwirq;
uint16_t mask = 1 << off; uint16_t mask = 1 << off;
...@@ -492,7 +482,8 @@ static irqreturn_t max732x_irq_handler(int irq, void *devid) ...@@ -492,7 +482,8 @@ static irqreturn_t max732x_irq_handler(int irq, void *devid)
do { do {
level = __ffs(pending); level = __ffs(pending);
handle_nested_irq(irq_find_mapping(chip->irq_domain, level)); handle_nested_irq(irq_find_mapping(chip->gpio_chip.irqdomain,
level));
pending &= ~(1 << level); pending &= ~(1 << level);
} while (pending); } while (pending);
...@@ -500,68 +491,24 @@ static irqreturn_t max732x_irq_handler(int irq, void *devid) ...@@ -500,68 +491,24 @@ static irqreturn_t max732x_irq_handler(int irq, void *devid)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int max732x_irq_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
struct max732x_chip *chip = h->host_data;
if (!(chip->dir_input & (1 << hw))) {
dev_err(&chip->client->dev,
"Attempt to map output line as IRQ line: %lu\n",
hw);
return -EPERM;
}
irq_set_chip_data(virq, chip);
irq_set_chip_and_handler(virq, &max732x_irq_chip,
handle_edge_irq);
irq_set_nested_thread(virq, 1);
#ifdef CONFIG_ARM
/* ARM needs us to explicitly flag the IRQ as valid
* and will set them noprobe when we do so. */
set_irq_flags(virq, IRQF_VALID);
#else
irq_set_noprobe(virq);
#endif
return 0;
}
static struct irq_domain_ops max732x_irq_domain_ops = {
.map = max732x_irq_map,
.xlate = irq_domain_xlate_twocell,
};
static void max732x_irq_teardown(struct max732x_chip *chip)
{
if (chip->client->irq && chip->irq_domain)
irq_domain_remove(chip->irq_domain);
}
static int max732x_irq_setup(struct max732x_chip *chip, static int max732x_irq_setup(struct max732x_chip *chip,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
struct i2c_client *client = chip->client; struct i2c_client *client = chip->client;
struct max732x_platform_data *pdata = dev_get_platdata(&client->dev); struct max732x_platform_data *pdata = dev_get_platdata(&client->dev);
int has_irq = max732x_features[id->driver_data] >> 32; int has_irq = max732x_features[id->driver_data] >> 32;
int irq_base = 0;
int ret; int ret;
if (((pdata && pdata->irq_base) || client->irq) if (((pdata && pdata->irq_base) || client->irq)
&& has_irq != INT_NONE) { && has_irq != INT_NONE) {
if (pdata) if (pdata)
chip->irq_base = pdata->irq_base; irq_base = pdata->irq_base;
chip->irq_features = has_irq; chip->irq_features = has_irq;
mutex_init(&chip->irq_lock); mutex_init(&chip->irq_lock);
chip->irq_domain = irq_domain_add_simple(client->dev.of_node, ret = devm_request_threaded_irq(&client->dev,
chip->gpio_chip.ngpio, chip->irq_base, client->irq,
&max732x_irq_domain_ops, chip);
if (!chip->irq_domain) {
dev_err(&client->dev, "Failed to create IRQ domain\n");
return -ENOMEM;
}
ret = request_threaded_irq(client->irq,
NULL, NULL,
max732x_irq_handler, max732x_irq_handler,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
...@@ -569,17 +516,25 @@ static int max732x_irq_setup(struct max732x_chip *chip, ...@@ -569,17 +516,25 @@ static int max732x_irq_setup(struct max732x_chip *chip,
if (ret) { if (ret) {
dev_err(&client->dev, "failed to request irq %d\n", dev_err(&client->dev, "failed to request irq %d\n",
client->irq); client->irq);
goto out_failed; return ret;
} }
ret = gpiochip_irqchip_add(&chip->gpio_chip,
chip->gpio_chip.to_irq = max732x_gpio_to_irq; &max732x_irq_chip,
irq_base,
handle_edge_irq,
IRQ_TYPE_NONE);
if (ret) {
dev_err(&client->dev,
"could not connect irqchip to gpiochip\n");
return ret;
}
gpiochip_set_chained_irqchip(&chip->gpio_chip,
&max732x_irq_chip,
client->irq,
NULL);
} }
return 0; return 0;
out_failed:
max732x_irq_teardown(chip);
return ret;
} }
#else /* CONFIG_GPIO_MAX732X_IRQ */ #else /* CONFIG_GPIO_MAX732X_IRQ */
...@@ -595,10 +550,6 @@ static int max732x_irq_setup(struct max732x_chip *chip, ...@@ -595,10 +550,6 @@ static int max732x_irq_setup(struct max732x_chip *chip,
return 0; return 0;
} }
static void max732x_irq_teardown(struct max732x_chip *chip)
{
}
#endif #endif
static int max732x_setup_gpio(struct max732x_chip *chip, static int max732x_setup_gpio(struct max732x_chip *chip,
...@@ -730,13 +681,15 @@ static int max732x_probe(struct i2c_client *client, ...@@ -730,13 +681,15 @@ static int max732x_probe(struct i2c_client *client,
if (nr_port > 8) if (nr_port > 8)
max732x_readb(chip, is_group_a(chip, 8), &chip->reg_out[1]); max732x_readb(chip, is_group_a(chip, 8), &chip->reg_out[1]);
ret = max732x_irq_setup(chip, id); ret = gpiochip_add(&chip->gpio_chip);
if (ret) if (ret)
goto out_failed; goto out_failed;
ret = gpiochip_add(&chip->gpio_chip); ret = max732x_irq_setup(chip, id);
if (ret) if (ret) {
gpiochip_remove(&chip->gpio_chip);
goto out_failed; goto out_failed;
}
if (pdata && pdata->setup) { if (pdata && pdata->setup) {
ret = pdata->setup(client, chip->gpio_chip.base, ret = pdata->setup(client, chip->gpio_chip.base,
...@@ -751,7 +704,6 @@ static int max732x_probe(struct i2c_client *client, ...@@ -751,7 +704,6 @@ static int max732x_probe(struct i2c_client *client,
out_failed: out_failed:
if (chip->client_dummy) if (chip->client_dummy)
i2c_unregister_device(chip->client_dummy); i2c_unregister_device(chip->client_dummy);
max732x_irq_teardown(chip);
return ret; return ret;
} }
...@@ -774,8 +726,6 @@ static int max732x_remove(struct i2c_client *client) ...@@ -774,8 +726,6 @@ static int max732x_remove(struct i2c_client *client)
gpiochip_remove(&chip->gpio_chip); gpiochip_remove(&chip->gpio_chip);
max732x_irq_teardown(chip);
/* unregister any dummy i2c_client */ /* unregister any dummy i2c_client */
if (chip->client_dummy) if (chip->client_dummy)
i2c_unregister_device(chip->client_dummy); i2c_unregister_device(chip->client_dummy);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment