Commit 76f93992 authored by Lee Jones's avatar Lee Jones Committed by Samuel Ortiz

mfd: Provide the STMPE driver with its own IRQ domain

The STMPE driver is yet another IRQ controller which requires its
own IRQ domain. So, we provide it with one.
Acked-by: default avatarArnd Bergmann <arnd@arndb.de>
Acked-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Signed-off-by: default avatarLee Jones <lee.jones@linaro.org>
Signed-off-by: default avatarSamuel Ortiz <sameo@linux.intel.com>
parent 7da0cbfc
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mfd/core.h> #include <linux/mfd/core.h>
...@@ -757,7 +758,9 @@ static irqreturn_t stmpe_irq(int irq, void *data) ...@@ -757,7 +758,9 @@ static irqreturn_t stmpe_irq(int irq, void *data)
int i; int i;
if (variant->id_val == STMPE801_ID) { if (variant->id_val == STMPE801_ID) {
handle_nested_irq(stmpe->irq_base); int base = irq_create_mapping(stmpe->domain, 0);
handle_nested_irq(base);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -778,8 +781,9 @@ static irqreturn_t stmpe_irq(int irq, void *data) ...@@ -778,8 +781,9 @@ static irqreturn_t stmpe_irq(int irq, void *data)
while (status) { while (status) {
int bit = __ffs(status); int bit = __ffs(status);
int line = bank * 8 + bit; int line = bank * 8 + bit;
int nestedirq = irq_create_mapping(stmpe->domain, line);
handle_nested_irq(stmpe->irq_base + line); handle_nested_irq(nestedirq);
status &= ~(1 << bit); status &= ~(1 << bit);
} }
...@@ -820,7 +824,7 @@ static void stmpe_irq_sync_unlock(struct irq_data *data) ...@@ -820,7 +824,7 @@ static void stmpe_irq_sync_unlock(struct irq_data *data)
static void stmpe_irq_mask(struct irq_data *data) static void stmpe_irq_mask(struct irq_data *data)
{ {
struct stmpe *stmpe = irq_data_get_irq_chip_data(data); struct stmpe *stmpe = irq_data_get_irq_chip_data(data);
int offset = data->irq - stmpe->irq_base; int offset = data->hwirq;
int regoffset = offset / 8; int regoffset = offset / 8;
int mask = 1 << (offset % 8); int mask = 1 << (offset % 8);
...@@ -830,7 +834,7 @@ static void stmpe_irq_mask(struct irq_data *data) ...@@ -830,7 +834,7 @@ static void stmpe_irq_mask(struct irq_data *data)
static void stmpe_irq_unmask(struct irq_data *data) static void stmpe_irq_unmask(struct irq_data *data)
{ {
struct stmpe *stmpe = irq_data_get_irq_chip_data(data); struct stmpe *stmpe = irq_data_get_irq_chip_data(data);
int offset = data->irq - stmpe->irq_base; int offset = data->hwirq;
int regoffset = offset / 8; int regoffset = offset / 8;
int mask = 1 << (offset % 8); int mask = 1 << (offset % 8);
...@@ -845,43 +849,62 @@ static struct irq_chip stmpe_irq_chip = { ...@@ -845,43 +849,62 @@ static struct irq_chip stmpe_irq_chip = {
.irq_unmask = stmpe_irq_unmask, .irq_unmask = stmpe_irq_unmask,
}; };
static int __devinit stmpe_irq_init(struct stmpe *stmpe) static int stmpe_irq_map(struct irq_domain *d, unsigned int virq,
irq_hw_number_t hwirq)
{ {
struct stmpe *stmpe = d->host_data;
struct irq_chip *chip = NULL; struct irq_chip *chip = NULL;
int num_irqs = stmpe->variant->num_irqs;
int base = stmpe->irq_base;
int irq;
if (stmpe->variant->id_val != STMPE801_ID) if (stmpe->variant->id_val != STMPE801_ID)
chip = &stmpe_irq_chip; chip = &stmpe_irq_chip;
for (irq = base; irq < base + num_irqs; irq++) { irq_set_chip_data(virq, stmpe);
irq_set_chip_data(irq, stmpe); irq_set_chip_and_handler(virq, chip, handle_edge_irq);
irq_set_chip_and_handler(irq, chip, handle_edge_irq); irq_set_nested_thread(virq, 1);
irq_set_nested_thread(irq, 1);
#ifdef CONFIG_ARM #ifdef CONFIG_ARM
set_irq_flags(irq, IRQF_VALID); set_irq_flags(virq, IRQF_VALID);
#else #else
irq_set_noprobe(irq); irq_set_noprobe(virq);
#endif #endif
}
return 0; return 0;
} }
static void stmpe_irq_remove(struct stmpe *stmpe) static void stmpe_irq_unmap(struct irq_domain *d, unsigned int virq)
{ {
int num_irqs = stmpe->variant->num_irqs;
int base = stmpe->irq_base;
int irq;
for (irq = base; irq < base + num_irqs; irq++) {
#ifdef CONFIG_ARM #ifdef CONFIG_ARM
set_irq_flags(irq, 0); set_irq_flags(virq, 0);
#endif #endif
irq_set_chip_and_handler(irq, NULL, NULL); irq_set_chip_and_handler(virq, NULL, NULL);
irq_set_chip_data(irq, NULL); irq_set_chip_data(virq, NULL);
}
static struct irq_domain_ops stmpe_irq_ops = {
.map = stmpe_irq_map,
.unmap = stmpe_irq_unmap,
.xlate = irq_domain_xlate_twocell,
};
static int __devinit stmpe_irq_init(struct stmpe *stmpe)
{
int base = stmpe->irq_base;
int num_irqs = stmpe->variant->num_irqs;
if (base) {
stmpe->domain = irq_domain_add_legacy(
NULL, num_irqs, base, 0, &stmpe_irq_ops, stmpe);
}
else {
stmpe->domain = irq_domain_add_linear(
NULL, num_irqs, &stmpe_irq_ops, stmpe);
}
if (!stmpe->domain) {
dev_err(stmpe->dev, "Failed to create irqdomain\n");
return -ENOSYS;
} }
return 0;
} }
static int __devinit stmpe_chip_init(struct stmpe *stmpe) static int __devinit stmpe_chip_init(struct stmpe *stmpe)
...@@ -954,7 +977,7 @@ static int __devinit stmpe_add_device(struct stmpe *stmpe, ...@@ -954,7 +977,7 @@ static int __devinit stmpe_add_device(struct stmpe *stmpe,
struct mfd_cell *cell) struct mfd_cell *cell)
{ {
return mfd_add_devices(stmpe->dev, stmpe->pdata->id, cell, 1, return mfd_add_devices(stmpe->dev, stmpe->pdata->id, cell, 1,
NULL, stmpe->irq_base, NULL); NULL, stmpe->irq_base, stmpe->domain);
} }
static int __devinit stmpe_devices_init(struct stmpe *stmpe) static int __devinit stmpe_devices_init(struct stmpe *stmpe)
...@@ -1067,7 +1090,7 @@ int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum) ...@@ -1067,7 +1090,7 @@ int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum)
if (ret) { if (ret) {
dev_err(stmpe->dev, "failed to request IRQ: %d\n", dev_err(stmpe->dev, "failed to request IRQ: %d\n",
ret); ret);
goto out_removeirq; goto free_gpio;
} }
} }
...@@ -1083,9 +1106,6 @@ int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum) ...@@ -1083,9 +1106,6 @@ int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum)
mfd_remove_devices(stmpe->dev); mfd_remove_devices(stmpe->dev);
if (stmpe->irq >= 0) if (stmpe->irq >= 0)
free_irq(stmpe->irq, stmpe); free_irq(stmpe->irq, stmpe);
out_removeirq:
if (stmpe->irq >= 0)
stmpe_irq_remove(stmpe);
free_gpio: free_gpio:
if (pdata->irq_over_gpio) if (pdata->irq_over_gpio)
gpio_free(pdata->irq_gpio); gpio_free(pdata->irq_gpio);
...@@ -1098,10 +1118,8 @@ int stmpe_remove(struct stmpe *stmpe) ...@@ -1098,10 +1118,8 @@ int stmpe_remove(struct stmpe *stmpe)
{ {
mfd_remove_devices(stmpe->dev); mfd_remove_devices(stmpe->dev);
if (stmpe->irq >= 0) { if (stmpe->irq >= 0)
free_irq(stmpe->irq, stmpe); free_irq(stmpe->irq, stmpe);
stmpe_irq_remove(stmpe);
}
if (stmpe->pdata->irq_over_gpio) if (stmpe->pdata->irq_over_gpio)
gpio_free(stmpe->pdata->irq_gpio); gpio_free(stmpe->pdata->irq_gpio);
......
...@@ -62,6 +62,7 @@ struct stmpe_client_info; ...@@ -62,6 +62,7 @@ struct stmpe_client_info;
* @lock: lock protecting I/O operations * @lock: lock protecting I/O operations
* @irq_lock: IRQ bus lock * @irq_lock: IRQ bus lock
* @dev: device, mostly for dev_dbg() * @dev: device, mostly for dev_dbg()
* @irq_domain: IRQ domain
* @client: client - i2c or spi * @client: client - i2c or spi
* @ci: client specific information * @ci: client specific information
* @partnum: part number * @partnum: part number
...@@ -79,6 +80,7 @@ struct stmpe { ...@@ -79,6 +80,7 @@ struct stmpe {
struct mutex lock; struct mutex lock;
struct mutex irq_lock; struct mutex irq_lock;
struct device *dev; struct device *dev;
struct irq_domain *domain;
void *client; void *client;
struct stmpe_client_info *ci; struct stmpe_client_info *ci;
enum stmpe_partnum partnum; enum stmpe_partnum partnum;
......
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