Login | Register For Free | Help
Search for: (Advanced)

Mailing List Archive: Linux: Kernel

[PATCH 08/14] mfd: Add IRQ domain support for the AB8500

 

 

Linux kernel RSS feed   Index | Next | Previous | View Threaded


lee.jones at linaro

Jun 11, 2012, 8:25 AM

Post #1 of 13 (278 views)
Permalink
[PATCH 08/14] mfd: Add IRQ domain support for the AB8500

As the AB8500 is an IRQ controller in its own right, here we provide
the AB8500 driver with IRQ domain support. This is required if we wish
to reference any of its IRQs from a platform's Device Tree.

Cc: Samuel Ortiz <sameo [at] linux>
Signed-off-by: Lee Jones <lee.jones [at] linaro>
---
drivers/mfd/Kconfig | 1 +
drivers/mfd/ab8500-core.c | 112 +++++++++++++++++++++----------------
include/linux/mfd/abx500/ab8500.h | 4 ++
3 files changed, 70 insertions(+), 47 deletions(-)

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 170072e..e3637c2 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -696,6 +696,7 @@ config AB8500_CORE
bool "ST-Ericsson AB8500 Mixed Signal Power Management chip"
depends on GENERIC_HARDIRQS && ABX500_CORE && MFD_DB8500_PRCMU
select MFD_CORE
+ select IRQ_DOMAIN
help
Select this option to enable access to AB8500 power management
chip. This connects to U8500 either on the SSP/SPI bus (deprecated
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index 4dc5024..82cd31d 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -11,6 +11,7 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/irq.h>
+#include <linux/irqdomain.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/module.h>
@@ -361,7 +362,7 @@ static void ab8500_irq_sync_unlock(struct irq_data *data)
static void ab8500_irq_mask(struct irq_data *data)
{
struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
- int offset = data->irq - ab8500->irq_base;
+ int offset = data->irq;
int index = offset / 8;
int mask = 1 << (offset % 8);

@@ -371,7 +372,7 @@ static void ab8500_irq_mask(struct irq_data *data)
static void ab8500_irq_unmask(struct irq_data *data)
{
struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
- int offset = data->irq - ab8500->irq_base;
+ int offset = data->irq;
int index = offset / 8;
int mask = 1 << (offset % 8);

@@ -501,7 +502,7 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
int bit = __ffs(value);
int line = i * 8 + bit;

- handle_nested_irq(ab8500->irq_base + line);
+ handle_nested_irq(line);
value &= ~(1 << bit);

} while (value);
@@ -510,38 +511,51 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
return IRQ_HANDLED;
}

-static int ab8500_irq_init(struct ab8500 *ab8500)
+/**
+ * ab8500_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ
+ *
+ * Useful for drivers to request their own IRQs.
+ *
+ * @ab8500: ab8500_irq controller to operate on.
+ * @irq: index of the interrupt requested in the chip IRQs
+ */
+int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq)
{
- int base = ab8500->irq_base;
- int irq;
- int num_irqs;
+ if (!ab8500)
+ return -EINVAL;

- if (is_ab9540(ab8500))
- num_irqs = AB9540_NR_IRQS;
- else if (is_ab8505(ab8500))
- num_irqs = AB8505_NR_IRQS;
- else
- num_irqs = AB8500_NR_IRQS;
+ return irq_create_mapping(ab8500->domain, irq);
+}
+EXPORT_SYMBOL_GPL(ab8500_irq_get_virq);
+
+static int ab8500_irq_map(struct irq_domain *d, unsigned int virq,
+ irq_hw_number_t hwirq)
+{
+ struct ab8500 *ab8500 = d->host_data;

- for (irq = base; irq < base + num_irqs; irq++) {
- irq_set_chip_data(irq, ab8500);
- irq_set_chip_and_handler(irq, &ab8500_irq_chip,
- handle_simple_irq);
- irq_set_nested_thread(irq, 1);
+ if (!ab8500)
+ return -EINVAL;
+
+ irq_set_chip_data(virq, ab8500);
+ irq_set_chip_and_handler(virq, &ab8500_irq_chip,
+ handle_simple_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 ab8500_irq_remove(struct ab8500 *ab8500)
+static struct irq_domain_ops ab8500_irq_ops = {
+ .map = ab8500_irq_map,
+ .xlate = irq_domain_xlate_twocell,
+};
+
+static int ab8500_irq_init(struct ab8500 *ab8500, struct device_node *np)
{
- int base = ab8500->irq_base;
- int irq;
int num_irqs;

if (is_ab9540(ab8500))
@@ -551,13 +565,22 @@ static void ab8500_irq_remove(struct ab8500 *ab8500)
else
num_irqs = AB8500_NR_IRQS;

- for (irq = base; irq < base + num_irqs; irq++) {
-#ifdef CONFIG_ARM
- set_irq_flags(irq, 0);
-#endif
- irq_set_chip_and_handler(irq, NULL, NULL);
- irq_set_chip_data(irq, NULL);
+ if (np) {
+ ab8500->domain = irq_domain_add_linear(
+ np, num_irqs, &ab8500_irq_ops, ab8500);
+ }
+ else {
+ ab8500->domain = irq_domain_add_legacy(
+ NULL, num_irqs, ab8500->irq_base,
+ 0, &ab8500_irq_ops, ab8500);
+ }
+
+ if (!ab8500->domain) {
+ dev_err(ab8500->dev, "Failed to create irqdomain\n");
+ return -ENOSYS;
}
+
+ return 0;
}

int ab8500_suspend(struct ab8500 *ab8500)
@@ -1233,11 +1256,9 @@ static int __devinit ab8500_probe(struct platform_device *pdev)

if (plat)
ab8500->irq_base = plat->irq_base;
- else if (np)
- ret = of_property_read_u32(np, "stericsson,irq-base", &ab8500->irq_base);

- if (!ab8500->irq_base) {
- dev_info(&pdev->dev, "couldn't find irq-base\n");
+ if (!(ab8500->irq_base || np)) {
+ dev_info(&pdev->dev, "couldn't find irq-base and not doing DT boot\n");
ret = -EINVAL;
goto out_free_ab8500;
}
@@ -1323,7 +1344,7 @@ static int __devinit ab8500_probe(struct platform_device *pdev)
AB8500_SWITCH_OFF_STATUS, &value);
if (ret < 0)
return ret;
- dev_info(ab8500->dev, "switch off status: %#x", value);
+ dev_info(ab8500->dev, "switch off status: %#x\n", value);

if (plat && plat->init)
plat->init(ab8500);
@@ -1352,8 +1373,8 @@ static int __devinit ab8500_probe(struct platform_device *pdev)
for (i = 0; i < ab8500->mask_size; i++)
ab8500->mask[i] = ab8500->oldmask[i] = 0xff;

- if (ab8500->irq_base) {
- ret = ab8500_irq_init(ab8500);
+ if (ab8500->irq_base || np) {
+ ret = ab8500_irq_init(ab8500, np);
if (ret)
goto out_freeoldmask;

@@ -1370,7 +1391,7 @@ static int __devinit ab8500_probe(struct platform_device *pdev)
IRQF_ONESHOT | IRQF_NO_SUSPEND,
"ab8500", ab8500);
if (ret)
- goto out_removeirq;
+ goto out_freeoldmask;
}

if (!np) {
@@ -1417,15 +1438,12 @@ static int __devinit ab8500_probe(struct platform_device *pdev)
&ab8500_attr_group);
if (ret)
dev_err(ab8500->dev, "error creating sysfs entries\n");
- else
- return ret;
+
+ return ret;

out_freeirq:
- if (ab8500->irq_base)
+ if (ab8500->irq_base || np)
free_irq(ab8500->irq, ab8500);
-out_removeirq:
- if (ab8500->irq_base)
- ab8500_irq_remove(ab8500);
out_freeoldmask:
kfree(ab8500->oldmask);
out_freemask:
@@ -1439,16 +1457,16 @@ out_free_ab8500:
static int __devexit ab8500_remove(struct platform_device *pdev)
{
struct ab8500 *ab8500 = platform_get_drvdata(pdev);
+ struct device_node *np = pdev->dev.of_node;

if (is_ab9540(ab8500))
sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group);
else
sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
mfd_remove_devices(ab8500->dev);
- if (ab8500->irq_base) {
+ if (ab8500->irq_base || np)
free_irq(ab8500->irq, ab8500);
- ab8500_irq_remove(ab8500);
- }
+
kfree(ab8500->oldmask);
kfree(ab8500->mask);
kfree(ab8500);
diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h
index 91dd3ef..48f126c 100644
--- a/include/linux/mfd/abx500/ab8500.h
+++ b/include/linux/mfd/abx500/ab8500.h
@@ -227,6 +227,7 @@ enum ab8500_version {
* @irq_lock: genirq bus lock
* @transfer_ongoing: 0 if no transfer ongoing
* @irq: irq line
+ * @irq_domain: irq domain
* @version: chip version id (e.g. ab8500 or ab9540)
* @chip_id: chip revision id
* @write: register write
@@ -247,6 +248,7 @@ struct ab8500 {
atomic_t transfer_ongoing;
int irq_base;
int irq;
+ struct irq_domain *domain;
enum ab8500_version version;
u8 chip_id;

@@ -336,4 +338,6 @@ static inline int is_ab8500_2p0(struct ab8500 *ab)
return (is_ab8500(ab) && (ab->chip_id == AB8500_CUT2P0));
}

+int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq);
+
#endif /* MFD_AB8500_H */
--
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo [at] vger
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/


linus.walleij at linaro

Jun 11, 2012, 2:33 PM

Post #2 of 13 (272 views)
Permalink
Re: [PATCH 08/14] mfd: Add IRQ domain support for the AB8500 [In reply to]

On Mon, Jun 11, 2012 at 5:25 PM, Lee Jones <lee.jones [at] linaro> wrote:

> As the AB8500 is an IRQ controller in its own right, here we provide
> the AB8500 driver with IRQ domain support. This is required if we wish
> to reference any of its IRQs from a platform's Device Tree.

OK..

> diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
(...)
> -static int ab8500_irq_init(struct ab8500 *ab8500)
> +/**
> + * ab8500_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ
> + *
> + * Useful for drivers to request their own IRQs.

Check style against Documentation/kernel-doc-nano-HOWTO.txt
verbos explanation follows argument documentation.

> + *
> + * @ab8500: ab8500_irq controller to operate on.
> + * @irq: index of the interrupt requested in the chip IRQs
> + */
> +int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq)
> {
> - int base = ab8500->irq_base;
> - int irq;
> - int num_irqs;
> + if (!ab8500)
> + return -EINVAL;
>
> - if (is_ab9540(ab8500))
> - num_irqs = AB9540_NR_IRQS;
> - else if (is_ab8505(ab8500))
> - num_irqs = AB8505_NR_IRQS;
> - else
> - num_irqs = AB8500_NR_IRQS;
> + return irq_create_mapping(ab8500->domain, irq);
> +}
> +EXPORT_SYMBOL_GPL(ab8500_irq_get_virq);
(...)
> @@ -1233,11 +1256,9 @@ static int __devinit ab8500_probe(struct platform_device *pdev)
>
> if (plat)
> ab8500->irq_base = plat->irq_base;
> - else if (np)
> - ret = of_property_read_u32(np, "stericsson,irq-base", &ab8500->irq_base);

So if we're not using the irq base thing anymore, should you also
delete it from the binding document too? (If there is no binding
doc something is wrong and you need to create it I guess...)

> diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h
> index 91dd3ef..48f126c 100644
> --- a/include/linux/mfd/abx500/ab8500.h
> +++ b/include/linux/mfd/abx500/ab8500.h
> @@ -227,6 +227,7 @@ enum ab8500_version {
> * @irq_lock: genirq bus lock
> * @transfer_ongoing: 0 if no transfer ongoing
> * @irq: irq line
> + * @irq_domain: irq domain
> * @version: chip version id (e.g. ab8500 or ab9540)
> * @chip_id: chip revision id
> * @write: register write
> @@ -247,6 +248,7 @@ struct ab8500 {
> atomic_t transfer_ongoing;
> int irq_base;
> int irq;
> + struct irq_domain *domain;

Don't you need to forward-declare struct irq_domain?
I think you're just lucky to have it compiling... (Something
else included <linux/irqdomain.h> on the way here.)

Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo [at] vger
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/


lee.jones at linaro

Jun 12, 2012, 1:01 AM

Post #3 of 13 (268 views)
Permalink
Re: [PATCH 08/14] mfd: Add IRQ domain support for the AB8500 [In reply to]

On 11/06/12 22:33, Linus Walleij wrote:
> On Mon, Jun 11, 2012 at 5:25 PM, Lee Jones<lee.jones [at] linaro> wrote:
>
>> As the AB8500 is an IRQ controller in its own right, here we provide
>> the AB8500 driver with IRQ domain support. This is required if we wish
>> to reference any of its IRQs from a platform's Device Tree.
>
> OK..
>
>> diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
> (...)
>> -static int ab8500_irq_init(struct ab8500 *ab8500)
>> +/**
>> + * ab8500_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ
>> + *
>> + * Useful for drivers to request their own IRQs.
>
> Check style against Documentation/kernel-doc-nano-HOWTO.txt
> verbos explanation follows argument documentation.

Ah, good to know.

I just followed other examples in this case. I'll swap them over.

>> + *
>> + * @ab8500: ab8500_irq controller to operate on.
>> + * @irq: index of the interrupt requested in the chip IRQs
>> + */
>> +int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq)
>> {
>> - int base = ab8500->irq_base;
>> - int irq;
>> - int num_irqs;
>> + if (!ab8500)
>> + return -EINVAL;
>>
>> - if (is_ab9540(ab8500))
>> - num_irqs = AB9540_NR_IRQS;
>> - else if (is_ab8505(ab8500))
>> - num_irqs = AB8505_NR_IRQS;
>> - else
>> - num_irqs = AB8500_NR_IRQS;
>> + return irq_create_mapping(ab8500->domain, irq);
>> +}
>> +EXPORT_SYMBOL_GPL(ab8500_irq_get_virq);
> (...)
>> @@ -1233,11 +1256,9 @@ static int __devinit ab8500_probe(struct platform_device *pdev)
>>
>> if (plat)
>> ab8500->irq_base = plat->irq_base;
>> - else if (np)
>> - ret = of_property_read_u32(np, "stericsson,irq-base",&ab8500->irq_base);
>
> So if we're not using the irq base thing anymore, should you also
> delete it from the binding document too? (If there is no binding
> doc something is wrong and you need to create it I guess...)

No. A document is not required now, as we are using standard bindings.

>> diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h
>> index 91dd3ef..48f126c 100644
>> --- a/include/linux/mfd/abx500/ab8500.h
>> +++ b/include/linux/mfd/abx500/ab8500.h
>> @@ -227,6 +227,7 @@ enum ab8500_version {
>> * @irq_lock: genirq bus lock
>> * @transfer_ongoing: 0 if no transfer ongoing
>> * @irq: irq line
>> + * @irq_domain: irq domain
>> * @version: chip version id (e.g. ab8500 or ab9540)
>> * @chip_id: chip revision id
>> * @write: register write
>> @@ -247,6 +248,7 @@ struct ab8500 {
>> atomic_t transfer_ongoing;
>> int irq_base;
>> int irq;
>> + struct irq_domain *domain;
>
> Don't you need to forward-declare struct irq_domain?
> I think you're just lucky to have it compiling... (Something
> else included<linux/irqdomain.h> on the way here.)

You're right. I'll make the changes and resubmit.

--
Lee Jones
Linaro ST-Ericsson Landing Team Lead
M: +44 77 88 633 515
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo [at] vger
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/


broonie at opensource

Jun 14, 2012, 11:32 AM

Post #4 of 13 (273 views)
Permalink
Re: [PATCH 08/14] mfd: Add IRQ domain support for the AB8500 [In reply to]

On Mon, Jun 11, 2012 at 04:25:01PM +0100, Lee Jones wrote:

> + if (np) {
> + ab8500->domain = irq_domain_add_linear(
> + np, num_irqs, &ab8500_irq_ops, ab8500);
> + }
> + else {
> + ab8500->domain = irq_domain_add_legacy(
> + NULL, num_irqs, ab8500->irq_base,
> + 0, &ab8500_irq_ops, ab8500);
> + }

This is odd, why are you forcing non-DT systems to use a legacy mapping?
The more usual approach is to use a legacy mapping if and only if a base
for the legacy range has been provided, otherwise the system will
needlessly fail to initialise the device...

> + if (!(ab8500->irq_base || np)) {
> + dev_info(&pdev->dev, "couldn't find irq-base and not doing DT boot\n");

...like this. See regmap_irq for an example.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo [at] vger
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/


lee.jones at linaro

Jun 15, 2012, 5:49 AM

Post #5 of 13 (269 views)
Permalink
Re: [PATCH 08/14] mfd: Add IRQ domain support for the AB8500 [In reply to]

On 14/06/12 19:32, Mark Brown wrote:
> On Mon, Jun 11, 2012 at 04:25:01PM +0100, Lee Jones wrote:
>
>> + if (np) {
>> + ab8500->domain = irq_domain_add_linear(
>> + np, num_irqs,&ab8500_irq_ops, ab8500);
>> + }
>> + else {
>> + ab8500->domain = irq_domain_add_legacy(
>> + NULL, num_irqs, ab8500->irq_base,
>> + 0,&ab8500_irq_ops, ab8500);
>> + }
>
> This is odd, why are you forcing non-DT systems to use a legacy mapping?
> The more usual approach is to use a legacy mapping if and only if a base
> for the legacy range has been provided, otherwise the system will
> needlessly fail to initialise the device...

Makes sense. I'll re-submit.

>> + if (!(ab8500->irq_base || np)) {
>> + dev_info(&pdev->dev, "couldn't find irq-base and not doing DT boot\n");
>
> ...like this. See regmap_irq for an example.

--
Lee Jones
Linaro ST-Ericsson Landing Team Lead
M: +44 77 88 633 515
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo [at] vger
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/


lee.jones at linaro

Jun 18, 2012, 2:02 AM

Post #6 of 13 (264 views)
Permalink
Re: [PATCH 08/14] mfd: Add IRQ domain support for the AB8500 [In reply to]

Do this look better to you Mark?

From: Lee Jones <lee.jones [at] linaro>
Date: Sat, 26 May 2012 06:54:04 +0100
Subject: [PATCH 1/1] mfd: Add IRQ domain support for the AB8500

As the AB8500 is an IRQ controller in its own right, here we provide
the AB8500 driver with IRQ domain support. This is required if we wish
to reference any of its IRQs from a platform's Device Tree.

Cc: Samuel Ortiz <sameo [at] linux>
Signed-off-by: Lee Jones <lee.jones [at] linaro>
---
drivers/mfd/Kconfig | 1 +
drivers/mfd/ab8500-core.c | 114 ++++++++++++++++++++-----------------
include/linux/mfd/abx500/ab8500.h | 5 ++
3 files changed, 69 insertions(+), 51 deletions(-)

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 170072e..e3637c2 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -696,6 +696,7 @@ config AB8500_CORE
bool "ST-Ericsson AB8500 Mixed Signal Power Management chip"
depends on GENERIC_HARDIRQS && ABX500_CORE && MFD_DB8500_PRCMU
select MFD_CORE
+ select IRQ_DOMAIN
help
Select this option to enable access to AB8500 power management
chip. This connects to U8500 either on the SSP/SPI bus (deprecated
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index 4dc5024..47bf8aa 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -11,6 +11,7 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/irq.h>
+#include <linux/irqdomain.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/module.h>
@@ -361,7 +362,7 @@ static void ab8500_irq_sync_unlock(struct irq_data *data)
static void ab8500_irq_mask(struct irq_data *data)
{
struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
- int offset = data->irq - ab8500->irq_base;
+ int offset = data->irq;
int index = offset / 8;
int mask = 1 << (offset % 8);

@@ -371,7 +372,7 @@ static void ab8500_irq_mask(struct irq_data *data)
static void ab8500_irq_unmask(struct irq_data *data)
{
struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
- int offset = data->irq - ab8500->irq_base;
+ int offset = data->irq;
int index = offset / 8;
int mask = 1 << (offset % 8);

@@ -501,7 +502,7 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
int bit = __ffs(value);
int line = i * 8 + bit;

- handle_nested_irq(ab8500->irq_base + line);
+ handle_nested_irq(line);
value &= ~(1 << bit);

} while (value);
@@ -510,38 +511,51 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
return IRQ_HANDLED;
}

-static int ab8500_irq_init(struct ab8500 *ab8500)
+/**
+ * ab8500_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ
+ *
+ * @ab8500: ab8500_irq controller to operate on.
+ * @irq: index of the interrupt requested in the chip IRQs
+ *
+ * Useful for drivers to request their own IRQs.
+ */
+int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq)
{
- int base = ab8500->irq_base;
- int irq;
- int num_irqs;
+ if (!ab8500)
+ return -EINVAL;

- if (is_ab9540(ab8500))
- num_irqs = AB9540_NR_IRQS;
- else if (is_ab8505(ab8500))
- num_irqs = AB8505_NR_IRQS;
- else
- num_irqs = AB8500_NR_IRQS;
+ return irq_create_mapping(ab8500->domain, irq);
+}
+EXPORT_SYMBOL_GPL(ab8500_irq_get_virq);
+
+static int ab8500_irq_map(struct irq_domain *d, unsigned int virq,
+ irq_hw_number_t hwirq)
+{
+ struct ab8500 *ab8500 = d->host_data;

- for (irq = base; irq < base + num_irqs; irq++) {
- irq_set_chip_data(irq, ab8500);
- irq_set_chip_and_handler(irq, &ab8500_irq_chip,
- handle_simple_irq);
- irq_set_nested_thread(irq, 1);
+ if (!ab8500)
+ return -EINVAL;
+
+ irq_set_chip_data(virq, ab8500);
+ irq_set_chip_and_handler(virq, &ab8500_irq_chip,
+ handle_simple_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 ab8500_irq_remove(struct ab8500 *ab8500)
+static struct irq_domain_ops ab8500_irq_ops = {
+ .map = ab8500_irq_map,
+ .xlate = irq_domain_xlate_twocell,
+};
+
+static int ab8500_irq_init(struct ab8500 *ab8500, struct device_node *np)
{
- int base = ab8500->irq_base;
- int irq;
int num_irqs;

if (is_ab9540(ab8500))
@@ -551,13 +565,22 @@ static void ab8500_irq_remove(struct ab8500 *ab8500)
else
num_irqs = AB8500_NR_IRQS;

- for (irq = base; irq < base + num_irqs; irq++) {
-#ifdef CONFIG_ARM
- set_irq_flags(irq, 0);
-#endif
- irq_set_chip_and_handler(irq, NULL, NULL);
- irq_set_chip_data(irq, NULL);
+ if (ab8500->irq_base) {
+ ab8500->domain = irq_domain_add_legacy(
+ NULL, num_irqs, ab8500->irq_base,
+ 0, &ab8500_irq_ops, ab8500);
+ }
+ else {
+ ab8500->domain = irq_domain_add_linear(
+ np, num_irqs, &ab8500_irq_ops, ab8500);
+ }
+
+ if (!ab8500->domain) {
+ dev_err(ab8500->dev, "Failed to create irqdomain\n");
+ return -ENOSYS;
}
+
+ return 0;
}

int ab8500_suspend(struct ab8500 *ab8500)
@@ -1233,14 +1256,6 @@ static int __devinit ab8500_probe(struct platform_device *pdev)

if (plat)
ab8500->irq_base = plat->irq_base;
- else if (np)
- ret = of_property_read_u32(np, "stericsson,irq-base", &ab8500->irq_base);
-
- if (!ab8500->irq_base) {
- dev_info(&pdev->dev, "couldn't find irq-base\n");
- ret = -EINVAL;
- goto out_free_ab8500;
- }

ab8500->dev = &pdev->dev;

@@ -1323,7 +1338,7 @@ static int __devinit ab8500_probe(struct platform_device *pdev)
AB8500_SWITCH_OFF_STATUS, &value);
if (ret < 0)
return ret;
- dev_info(ab8500->dev, "switch off status: %#x", value);
+ dev_info(ab8500->dev, "switch off status: %#x\n", value);

if (plat && plat->init)
plat->init(ab8500);
@@ -1352,8 +1367,8 @@ static int __devinit ab8500_probe(struct platform_device *pdev)
for (i = 0; i < ab8500->mask_size; i++)
ab8500->mask[i] = ab8500->oldmask[i] = 0xff;

- if (ab8500->irq_base) {
- ret = ab8500_irq_init(ab8500);
+ if (ab8500->irq_base || np) {
+ ret = ab8500_irq_init(ab8500, np);
if (ret)
goto out_freeoldmask;

@@ -1370,7 +1385,7 @@ static int __devinit ab8500_probe(struct platform_device *pdev)
IRQF_ONESHOT | IRQF_NO_SUSPEND,
"ab8500", ab8500);
if (ret)
- goto out_removeirq;
+ goto out_freeoldmask;
}

if (!np) {
@@ -1417,15 +1432,12 @@ static int __devinit ab8500_probe(struct platform_device *pdev)
&ab8500_attr_group);
if (ret)
dev_err(ab8500->dev, "error creating sysfs entries\n");
- else
- return ret;
+
+ return ret;

out_freeirq:
- if (ab8500->irq_base)
+ if (ab8500->irq_base || np)
free_irq(ab8500->irq, ab8500);
-out_removeirq:
- if (ab8500->irq_base)
- ab8500_irq_remove(ab8500);
out_freeoldmask:
kfree(ab8500->oldmask);
out_freemask:
@@ -1439,16 +1451,16 @@ out_free_ab8500:
static int __devexit ab8500_remove(struct platform_device *pdev)
{
struct ab8500 *ab8500 = platform_get_drvdata(pdev);
+ struct device_node *np = pdev->dev.of_node;

if (is_ab9540(ab8500))
sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group);
else
sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
mfd_remove_devices(ab8500->dev);
- if (ab8500->irq_base) {
+ if (ab8500->irq_base || np)
free_irq(ab8500->irq, ab8500);
- ab8500_irq_remove(ab8500);
- }
+
kfree(ab8500->oldmask);
kfree(ab8500->mask);
kfree(ab8500);
diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h
index 91dd3ef..4ae2cd9 100644
--- a/include/linux/mfd/abx500/ab8500.h
+++ b/include/linux/mfd/abx500/ab8500.h
@@ -9,6 +9,7 @@

#include <linux/atomic.h>
#include <linux/mutex.h>
+#include <linux/irqdomain.h>

struct device;

@@ -227,6 +228,7 @@ enum ab8500_version {
* @irq_lock: genirq bus lock
* @transfer_ongoing: 0 if no transfer ongoing
* @irq: irq line
+ * @irq_domain: irq domain
* @version: chip version id (e.g. ab8500 or ab9540)
* @chip_id: chip revision id
* @write: register write
@@ -247,6 +249,7 @@ struct ab8500 {
atomic_t transfer_ongoing;
int irq_base;
int irq;
+ struct irq_domain *domain;
enum ab8500_version version;
u8 chip_id;

@@ -336,4 +339,6 @@ static inline int is_ab8500_2p0(struct ab8500 *ab)
return (is_ab8500(ab) && (ab->chip_id == AB8500_CUT2P0));
}

+int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq);
+
#endif /* MFD_AB8500_H */
--
1.7.9.5
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo [at] vger
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/


broonie at opensource

Jun 18, 2012, 2:32 AM

Post #7 of 13 (266 views)
Permalink
Re: [PATCH 08/14] mfd: Add IRQ domain support for the AB8500 [In reply to]

On Mon, Jun 18, 2012 at 10:02:53AM +0100, Lee Jones wrote:
> Do this look better to you Mark?

Reviwed-by: Mark Brown <broonie [at] opensource>
Attachments: signature.asc (0.82 KB)


linux at arm

Jun 18, 2012, 3:20 AM

Post #8 of 13 (268 views)
Permalink
Re: [PATCH 08/14] mfd: Add IRQ domain support for the AB8500 [In reply to]

On Mon, Jun 18, 2012 at 10:02:53AM +0100, Lee Jones wrote:
> @@ -361,7 +362,7 @@ static void ab8500_irq_sync_unlock(struct irq_data *data)
> static void ab8500_irq_mask(struct irq_data *data)
> {
> struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
> - int offset = data->irq - ab8500->irq_base;
> + int offset = data->irq;

Are you sure this is right? I thought irq_data->irq was the Linux IRQ
number, irq_data->hwirq was the interrupt number inside the domain.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo [at] vger
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/


broonie at opensource

Jun 18, 2012, 11:56 AM

Post #9 of 13 (269 views)
Permalink
Re: [PATCH 08/14] mfd: Add IRQ domain support for the AB8500 [In reply to]

On Mon, Jun 18, 2012 at 11:20:03AM +0100, Russell King - ARM Linux wrote:

> > + int offset = data->irq;

> Are you sure this is right? I thought irq_data->irq was the Linux IRQ
> number, irq_data->hwirq was the interrupt number inside the domain.

Yes, that's correct. I'm surprised the code runs without crashing...
Attachments: signature.asc (0.82 KB)


linus.walleij at linaro

Jun 20, 2012, 2:12 AM

Post #10 of 13 (260 views)
Permalink
Re: [PATCH 08/14] mfd: Add IRQ domain support for the AB8500 [In reply to]

On Mon, Jun 18, 2012 at 12:20 PM, Russell King - ARM Linux
<linux [at] arm> wrote:
> On Mon, Jun 18, 2012 at 10:02:53AM +0100, Lee Jones wrote:
>> @@ -361,7 +362,7 @@ static void ab8500_irq_sync_unlock(struct irq_data *data)
>> static void ab8500_irq_mask(struct irq_data *data)
>> {
>> struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
>> - int offset = data->irq - ab8500->irq_base;
>> + int offset = data->irq;
>
> Are you sure this is right? I thought irq_data->irq was the Linux IRQ
> number, irq_data->hwirq was the interrupt number inside the domain.

Agree, this need to be fixed and respin...

Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo [at] vger
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/


lee.jones at linaro

Jun 20, 2012, 6:00 AM

Post #11 of 13 (257 views)
Permalink
Re: [PATCH 08/14] mfd: Add IRQ domain support for the AB8500 [In reply to]

On 18/06/12 19:56, Mark Brown wrote:
> On Mon, Jun 18, 2012 at 11:20:03AM +0100, Russell King - ARM Linux wrote:
>
>>> + int offset = data->irq;
>
>> Are you sure this is right? I thought irq_data->irq was the Linux IRQ
>> number, irq_data->hwirq was the interrupt number inside the domain.

Thanks. Good catch. I have just sent a new patch-set to the mailing list
where I have sent the fixed- up patch again.

> Yes, that's correct. I'm surprised the code runs without crashing...

Oddly the code ran perfectly.

--
Lee Jones
Linaro ST-Ericsson Landing Team Lead
M: +44 77 88 633 515
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo [at] vger
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/


linus.walleij at linaro

Jun 21, 2012, 12:37 AM

Post #12 of 13 (260 views)
Permalink
Re: [PATCH 08/14] mfd: Add IRQ domain support for the AB8500 [In reply to]

On Wed, Jun 20, 2012 at 3:00 PM, Lee Jones <lee.jones [at] linaro> wrote:
> On 18/06/12 19:56, Mark Brown wrote:
>>
>> Yes, that's correct. I'm surprised the code runs without crashing...
>
> Oddly the code ran perfectly.

So how did you test it?

The only way to generate an IRQ on the AB8500 with the mainline code is
to push the power button, that should generate an event from the
driver in drivers/input/misc/ab8500-ponkey.c that you can listen to
by doing cat on the proper /dev/input/eventN file.

Please test this scenario before and after the patch and you have some
indication that the IRQdomain is working.

Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo [at] vger
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/


lee.jones at linaro

Jun 26, 2012, 2:04 AM

Post #13 of 13 (256 views)
Permalink
Re: [PATCH 08/14] mfd: Add IRQ domain support for the AB8500 [In reply to]

On 21/06/12 08:37, Linus Walleij wrote:
> On Wed, Jun 20, 2012 at 3:00 PM, Lee Jones<lee.jones [at] linaro> wrote:
>> On 18/06/12 19:56, Mark Brown wrote:
>>>
>>> Yes, that's correct. I'm surprised the code runs without crashing...
>>
>> Oddly the code ran perfectly.
>
> So how did you test it?
>
> The only way to generate an IRQ on the AB8500 with the mainline code is
> to push the power button, that should generate an event from the
> driver in drivers/input/misc/ab8500-ponkey.c that you can listen to
> by doing cat on the proper /dev/input/eventN file.
>
> Please test this scenario before and after the patch and you have some
> indication that the IRQdomain is working.

Yep, works perfectly fall and rise:

> CPU0 CPU1
> 6: 0 2 ab8500 ab8500-ponkey-dbf
> 7: 0 2 ab8500 ab8500-ponkey-dbr

--
Lee Jones
Linaro ST-Ericsson Landing Team Lead
M: +44 77 88 633 515
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo [at] vger
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

Linux kernel RSS feed   Index | Next | Previous | View Threaded
 
 


Interested in having your list archived? Contact Gossamer Threads
 
  Web Applications & Managed Hosting Powered by Gossamer Threads Inc.