Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 302086
b: refs/heads/master
c: 4af8be6
h: refs/heads/master
v: v3
  • Loading branch information
Mark Brown committed May 13, 2012
1 parent d9497bd commit 72c1b2c
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 28 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 06e65cb322f91dc20fbcfc1a7ee2fb105ecc417b
refs/heads/master: 4af8be67fd9989f4e63a8d1defc1895ed0f7d341
97 changes: 70 additions & 27 deletions trunk/drivers/base/regmap/regmap-irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <linux/regmap.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/irqdomain.h>
#include <linux/slab.h>

#include "internal.h"
Expand All @@ -26,6 +27,7 @@ struct regmap_irq_chip_data {
struct regmap_irq_chip *chip;

int irq_base;
struct irq_domain *domain;

void *status_reg_buf;
unsigned int *status_buf;
Expand All @@ -37,7 +39,7 @@ static inline const
struct regmap_irq *irq_to_regmap_irq(struct regmap_irq_chip_data *data,
int irq)
{
return &data->chip->irqs[irq - data->irq_base];
return &data->chip->irqs[irq];
}

static void regmap_irq_lock(struct irq_data *data)
Expand Down Expand Up @@ -74,7 +76,7 @@ static void regmap_irq_enable(struct irq_data *data)
{
struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
struct regmap *map = d->map;
const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->irq);
const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq);

d->mask_buf[irq_data->reg_offset / map->reg_stride] &= ~irq_data->mask;
}
Expand All @@ -83,7 +85,7 @@ static void regmap_irq_disable(struct irq_data *data)
{
struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
struct regmap *map = d->map;
const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->irq);
const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq);

d->mask_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask;
}
Expand Down Expand Up @@ -153,7 +155,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
for (i = 0; i < chip->num_irqs; i++) {
if (data->status_buf[chip->irqs[i].reg_offset /
map->reg_stride] & chip->irqs[i].mask) {
handle_nested_irq(data->irq_base + i);
handle_nested_irq(irq_find_mapping(data->domain, i));
handled = true;
}
}
Expand All @@ -164,6 +166,31 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
return IRQ_NONE;
}

static int regmap_irq_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
struct regmap_irq_chip_data *data = h->host_data;

irq_set_chip_data(virq, data);
irq_set_chip_and_handler(virq, &regmap_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 regmap_domain_ops = {
.map = regmap_irq_map,
.xlate = irq_domain_xlate_twocell,
};

/**
* regmap_add_irq_chip(): Use standard regmap IRQ controller handling
*
Expand All @@ -184,7 +211,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
struct regmap_irq_chip_data **data)
{
struct regmap_irq_chip_data *d;
int cur_irq, i;
int i;
int ret = -ENOMEM;

for (i = 0; i < chip->num_irqs; i++) {
Expand All @@ -195,11 +222,13 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
return -EINVAL;
}

irq_base = irq_alloc_descs(irq_base, 0, chip->num_irqs, 0);
if (irq_base < 0) {
dev_warn(map->dev, "Failed to allocate IRQs: %d\n",
irq_base);
return irq_base;
if (irq_base) {
irq_base = irq_alloc_descs(irq_base, 0, chip->num_irqs, 0);
if (irq_base < 0) {
dev_warn(map->dev, "Failed to allocate IRQs: %d\n",
irq_base);
return irq_base;
}
}

d = kzalloc(sizeof(*d), GFP_KERNEL);
Expand Down Expand Up @@ -249,33 +278,31 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
}
}

/* Register them with genirq */
for (cur_irq = irq_base;
cur_irq < chip->num_irqs + irq_base;
cur_irq++) {
irq_set_chip_data(cur_irq, d);
irq_set_chip_and_handler(cur_irq, &regmap_irq_chip,
handle_edge_irq);
irq_set_nested_thread(cur_irq, 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(cur_irq, IRQF_VALID);
#else
irq_set_noprobe(cur_irq);
#endif
if (irq_base)
d->domain = irq_domain_add_legacy(map->dev->of_node,
chip->num_irqs, irq_base, 0,
&regmap_domain_ops, d);
else
d->domain = irq_domain_add_linear(map->dev->of_node,
chip->num_irqs,
&regmap_domain_ops, d);
if (!d->domain) {
dev_err(map->dev, "Failed to create IRQ domain\n");
ret = -ENOMEM;
goto err_alloc;
}

ret = request_threaded_irq(irq, NULL, regmap_irq_thread, irq_flags,
chip->name, d);
if (ret != 0) {
dev_err(map->dev, "Failed to request IRQ %d: %d\n", irq, ret);
goto err_alloc;
goto err_domain;
}

return 0;

err_domain:
/* Should really dispose of the domain but... */
err_alloc:
kfree(d->mask_buf_def);
kfree(d->mask_buf);
Expand All @@ -298,6 +325,7 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
return;

free_irq(irq, d);
/* We should unmap the domain but... */
kfree(d->mask_buf_def);
kfree(d->mask_buf);
kfree(d->status_reg_buf);
Expand All @@ -315,6 +343,21 @@ EXPORT_SYMBOL_GPL(regmap_del_irq_chip);
*/
int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data)
{
WARN_ON(!data->irq_base);
return data->irq_base;
}
EXPORT_SYMBOL_GPL(regmap_irq_chip_get_base);

/**
* regmap_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ
*
* Useful for drivers to request their own IRQs.
*
* @data: regmap_irq controller to operate on.
* @irq: index of the interrupt requested in the chip IRQs
*/
int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq)
{
return irq_create_mapping(data->domain, irq);
}
EXPORT_SYMBOL_GPL(regmap_irq_get_virq);
3 changes: 3 additions & 0 deletions trunk/drivers/mfd/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@ config PMIC_DA9052

config MFD_DA9052_SPI
bool "Support Dialog Semiconductor DA9052/53 PMIC variants with SPI"
select IRQ_DOMAIN
select REGMAP_SPI
select REGMAP_IRQ
select PMIC_DA9052
Expand All @@ -388,6 +389,7 @@ config MFD_DA9052_SPI

config MFD_DA9052_I2C
bool "Support Dialog Semiconductor DA9052/53 PMIC variants with I2C"
select IRQ_DOMAIN
select REGMAP_I2C
select REGMAP_IRQ
select PMIC_DA9052
Expand Down Expand Up @@ -558,6 +560,7 @@ config MFD_WM8994
bool "Support Wolfson Microelectronics WM8994"
select MFD_CORE
select REGMAP_I2C
select IRQ_DOMAIN
select REGMAP_IRQ
depends on I2C=y && GENERIC_HARDIRQS
help
Expand Down
1 change: 1 addition & 0 deletions trunk/include/linux/regmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
struct regmap_irq_chip_data **data);
void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *data);
int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data);
int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq);

#else

Expand Down

0 comments on commit 72c1b2c

Please sign in to comment.