mfd: Add tps65910-irq devicetree init and irqdomain support

This change changes the tps65910-irq code to use irqdomain, and support
initialization from devicetree. This assumes that the irq_base in the
platform data is -1 if devicetree is used.

Signed-off-by: Rhyland Klein <rklein@nvidia.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
Rhyland Klein 2012-05-18 11:52:19 +02:00 committed by Samuel Ortiz
parent b09530ef84
commit 21f7541d88
3 changed files with 63 additions and 33 deletions

View file

@ -190,6 +190,7 @@ config MFD_TPS65910
depends on I2C=y && GPIOLIB depends on I2C=y && GPIOLIB
select MFD_CORE select MFD_CORE
select REGMAP_I2C select REGMAP_I2C
select IRQ_DOMAIN
help help
if you say yes here you get support for the TPS65910 series of if you say yes here you get support for the TPS65910 series of
Power Management chips. Power Management chips.

View file

@ -20,15 +20,10 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/mfd/tps65910.h> #include <linux/mfd/tps65910.h>
static inline int irq_to_tps65910_irq(struct tps65910 *tps65910,
int irq)
{
return (irq - tps65910->irq_base);
}
/* /*
* This is a threaded IRQ handler so can access I2C/SPI. Since all * This is a threaded IRQ handler so can access I2C/SPI. Since all
* interrupts are clear on read the IRQ line will be reasserted and * interrupts are clear on read the IRQ line will be reasserted and
@ -76,7 +71,7 @@ static irqreturn_t tps65910_irq(int irq, void *irq_data)
if (!(irq_sts & (1 << i))) if (!(irq_sts & (1 << i)))
continue; continue;
handle_nested_irq(tps65910->irq_base + i); handle_nested_irq(irq_find_mapping(tps65910->domain, i));
} }
/* Write the STS register back to clear IRQs we handled */ /* Write the STS register back to clear IRQs we handled */
@ -135,14 +130,14 @@ static void tps65910_irq_enable(struct irq_data *data)
{ {
struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data); struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data);
tps65910->irq_mask &= ~( 1 << irq_to_tps65910_irq(tps65910, data->irq)); tps65910->irq_mask &= ~(1 << data->hwirq);
} }
static void tps65910_irq_disable(struct irq_data *data) static void tps65910_irq_disable(struct irq_data *data)
{ {
struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data); struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data);
tps65910->irq_mask |= ( 1 << irq_to_tps65910_irq(tps65910, data->irq)); tps65910->irq_mask |= (1 << data->hwirq);
} }
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
@ -164,10 +159,35 @@ static struct irq_chip tps65910_irq_chip = {
.irq_set_wake = tps65910_irq_set_wake, .irq_set_wake = tps65910_irq_set_wake,
}; };
static int tps65910_irq_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
struct tps65910 *tps65910 = h->host_data;
irq_set_chip_data(virq, tps65910);
irq_set_chip_and_handler(virq, &tps65910_irq_chip, handle_edge_irq);
irq_set_nested_thread(virq, 1);
/* ARM needs us to explicitly flag the IRQ as valid
* and will set them noprobe when we do so. */
#ifdef CONFIG_ARM
set_irq_flags(virq, IRQF_VALID);
#else
irq_set_noprobe(virq);
#endif
return 0;
}
static struct irq_domain_ops tps65910_domain_ops = {
.map = tps65910_irq_map,
.xlate = irq_domain_xlate_twocell,
};
int tps65910_irq_init(struct tps65910 *tps65910, int irq, int tps65910_irq_init(struct tps65910 *tps65910, int irq,
struct tps65910_platform_data *pdata) struct tps65910_platform_data *pdata)
{ {
int ret, cur_irq; int ret;
int flags = IRQF_ONESHOT; int flags = IRQF_ONESHOT;
if (!irq) { if (!irq) {
@ -175,17 +195,11 @@ int tps65910_irq_init(struct tps65910 *tps65910, int irq,
return -EINVAL; return -EINVAL;
} }
if (!pdata || !pdata->irq_base) { if (!pdata) {
dev_warn(tps65910->dev, "No interrupt support, no IRQ base\n"); dev_warn(tps65910->dev, "No interrupt support, no pdata\n");
return -EINVAL; return -EINVAL;
} }
tps65910->irq_mask = 0xFFFFFF;
mutex_init(&tps65910->irq_lock);
tps65910->chip_irq = irq;
tps65910->irq_base = pdata->irq_base;
switch (tps65910_chip_id(tps65910)) { switch (tps65910_chip_id(tps65910)) {
case TPS65910: case TPS65910:
tps65910->irq_num = TPS65910_NUM_IRQ; tps65910->irq_num = TPS65910_NUM_IRQ;
@ -195,22 +209,36 @@ int tps65910_irq_init(struct tps65910 *tps65910, int irq,
break; break;
} }
/* Register with genirq */ if (pdata->irq_base > 0) {
for (cur_irq = tps65910->irq_base; pdata->irq_base = irq_alloc_descs(pdata->irq_base, 0,
cur_irq < tps65910->irq_num + tps65910->irq_base; tps65910->irq_num, -1);
cur_irq++) { if (pdata->irq_base < 0) {
irq_set_chip_data(cur_irq, tps65910); dev_warn(tps65910->dev, "Failed to alloc IRQs: %d\n",
irq_set_chip_and_handler(cur_irq, &tps65910_irq_chip, pdata->irq_base);
handle_edge_irq); return pdata->irq_base;
irq_set_nested_thread(cur_irq, 1); }
}
/* ARM needs us to explicitly flag the IRQ as valid tps65910->irq_mask = 0xFFFFFF;
* and will set them noprobe when we do so. */
#ifdef CONFIG_ARM mutex_init(&tps65910->irq_lock);
set_irq_flags(cur_irq, IRQF_VALID); tps65910->chip_irq = irq;
#else tps65910->irq_base = pdata->irq_base;
irq_set_noprobe(cur_irq);
#endif if (pdata->irq_base > 0)
tps65910->domain = irq_domain_add_legacy(tps65910->dev->of_node,
tps65910->irq_num,
pdata->irq_base,
0,
&tps65910_domain_ops, tps65910);
else
tps65910->domain = irq_domain_add_linear(tps65910->dev->of_node,
tps65910->irq_num,
&tps65910_domain_ops, tps65910);
if (!tps65910->domain) {
dev_err(tps65910->dev, "Failed to create IRQ domain\n");
return -ENOMEM;
} }
ret = request_threaded_irq(irq, NULL, tps65910_irq, flags, ret = request_threaded_irq(irq, NULL, tps65910_irq, flags,

View file

@ -836,6 +836,7 @@ struct tps65910 {
int irq_base; int irq_base;
int irq_num; int irq_num;
u32 irq_mask; u32 irq_mask;
struct irq_domain *domain;
}; };
struct tps65910_platform_data { struct tps65910_platform_data {