Skip to content

Commit

Permalink
mfd: Provide the STMPE driver with its own IRQ domain
Browse files Browse the repository at this point in the history
The STMPE driver is yet another IRQ controller which requires its
own IRQ domain. So, we provide it with one.

Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
  • Loading branch information
Lee Jones authored and Samuel Ortiz committed Nov 11, 2012
1 parent 7da0cbf commit 76f9399
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 32 deletions.
82 changes: 50 additions & 32 deletions drivers/mfd/stmpe.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/mfd/core.h>
Expand Down Expand Up @@ -757,7 +758,9 @@ static irqreturn_t stmpe_irq(int irq, void *data)
int i;

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;
}

Expand All @@ -778,8 +781,9 @@ static irqreturn_t stmpe_irq(int irq, void *data)
while (status) {
int bit = __ffs(status);
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);
}

Expand Down Expand Up @@ -820,7 +824,7 @@ static void stmpe_irq_sync_unlock(struct irq_data *data)
static void stmpe_irq_mask(struct irq_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 mask = 1 << (offset % 8);

Expand All @@ -830,7 +834,7 @@ static void stmpe_irq_mask(struct irq_data *data)
static void stmpe_irq_unmask(struct irq_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 mask = 1 << (offset % 8);

Expand All @@ -845,43 +849,62 @@ static struct irq_chip stmpe_irq_chip = {
.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;
int num_irqs = stmpe->variant->num_irqs;
int base = stmpe->irq_base;
int irq;

if (stmpe->variant->id_val != STMPE801_ID)
chip = &stmpe_irq_chip;

for (irq = base; irq < base + num_irqs; irq++) {
irq_set_chip_data(irq, stmpe);
irq_set_chip_and_handler(irq, chip, handle_edge_irq);
irq_set_nested_thread(irq, 1);
irq_set_chip_data(virq, stmpe);
irq_set_chip_and_handler(virq, chip, handle_edge_irq);
irq_set_nested_thread(virq, 1);
#ifdef CONFIG_ARM
set_irq_flags(irq, IRQF_VALID);
set_irq_flags(virq, IRQF_VALID);
#else
irq_set_noprobe(irq);
irq_set_noprobe(virq);
#endif
}

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
set_irq_flags(irq, 0);
set_irq_flags(virq, 0);
#endif
irq_set_chip_and_handler(irq, NULL, NULL);
irq_set_chip_data(irq, NULL);
irq_set_chip_and_handler(virq, NULL, 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)
Expand Down Expand Up @@ -954,7 +977,7 @@ static int __devinit stmpe_add_device(struct stmpe *stmpe,
struct mfd_cell *cell)
{
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)
Expand Down Expand Up @@ -1067,7 +1090,7 @@ int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum)
if (ret) {
dev_err(stmpe->dev, "failed to request IRQ: %d\n",
ret);
goto out_removeirq;
goto free_gpio;
}
}

Expand All @@ -1083,9 +1106,6 @@ int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum)
mfd_remove_devices(stmpe->dev);
if (stmpe->irq >= 0)
free_irq(stmpe->irq, stmpe);
out_removeirq:
if (stmpe->irq >= 0)
stmpe_irq_remove(stmpe);
free_gpio:
if (pdata->irq_over_gpio)
gpio_free(pdata->irq_gpio);
Expand All @@ -1098,10 +1118,8 @@ int stmpe_remove(struct stmpe *stmpe)
{
mfd_remove_devices(stmpe->dev);

if (stmpe->irq >= 0) {
if (stmpe->irq >= 0)
free_irq(stmpe->irq, stmpe);
stmpe_irq_remove(stmpe);
}

if (stmpe->pdata->irq_over_gpio)
gpio_free(stmpe->pdata->irq_gpio);
Expand Down
2 changes: 2 additions & 0 deletions include/linux/mfd/stmpe.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ struct stmpe_client_info;
* @lock: lock protecting I/O operations
* @irq_lock: IRQ bus lock
* @dev: device, mostly for dev_dbg()
* @irq_domain: IRQ domain
* @client: client - i2c or spi
* @ci: client specific information
* @partnum: part number
Expand All @@ -79,6 +80,7 @@ struct stmpe {
struct mutex lock;
struct mutex irq_lock;
struct device *dev;
struct irq_domain *domain;
void *client;
struct stmpe_client_info *ci;
enum stmpe_partnum partnum;
Expand Down

0 comments on commit 76f9399

Please sign in to comment.