Skip to content

Commit

Permalink
mfd: Convert tps6586x to irq_domain
Browse files Browse the repository at this point in the history
Allocate the irq base if it base is not porvided i.e.
in case of device tree invocation of this driver.
Convert the tps6586x driver to irq domain, using a
legacy IRQ mapping if an irq_base is specified in
platform data or dynamically allocated and otherwise
using a linear mapping.

Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
  • Loading branch information
Laxman Dewangan authored and Samuel Ortiz committed Nov 13, 2012
1 parent 210afee commit 605511a
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 25 deletions.
91 changes: 66 additions & 25 deletions drivers/mfd/tps6586x.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@

#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/machine.h>
Expand Down Expand Up @@ -116,6 +118,7 @@ struct tps6586x {
int irq_base;
u32 irq_en;
u8 mask_reg[5];
struct irq_domain *irq_domain;
};

static inline struct tps6586x *dev_to_tps6586x(struct device *dev)
Expand Down Expand Up @@ -184,6 +187,14 @@ int tps6586x_update(struct device *dev, int reg, uint8_t val, uint8_t mask)
}
EXPORT_SYMBOL_GPL(tps6586x_update);

int tps6586x_irq_get_virq(struct device *dev, int irq)
{
struct tps6586x *tps6586x = dev_to_tps6586x(dev);

return irq_create_mapping(tps6586x->irq_domain, irq);
}
EXPORT_SYMBOL_GPL(tps6586x_irq_get_virq);

static int __remove_subdev(struct device *dev, void *unused)
{
platform_device_unregister(to_platform_device(dev));
Expand All @@ -205,7 +216,7 @@ static void tps6586x_irq_lock(struct irq_data *data)
static void tps6586x_irq_enable(struct irq_data *irq_data)
{
struct tps6586x *tps6586x = irq_data_get_irq_chip_data(irq_data);
unsigned int __irq = irq_data->irq - tps6586x->irq_base;
unsigned int __irq = irq_data->hwirq;
const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq];

tps6586x->mask_reg[data->mask_reg] &= ~data->mask_mask;
Expand All @@ -216,7 +227,7 @@ static void tps6586x_irq_disable(struct irq_data *irq_data)
{
struct tps6586x *tps6586x = irq_data_get_irq_chip_data(irq_data);

unsigned int __irq = irq_data->irq - tps6586x->irq_base;
unsigned int __irq = irq_data->hwirq;
const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq];

tps6586x->mask_reg[data->mask_reg] |= data->mask_mask;
Expand All @@ -239,6 +250,39 @@ static void tps6586x_irq_sync_unlock(struct irq_data *data)
mutex_unlock(&tps6586x->irq_lock);
}

static struct irq_chip tps6586x_irq_chip = {
.name = "tps6586x",
.irq_bus_lock = tps6586x_irq_lock,
.irq_bus_sync_unlock = tps6586x_irq_sync_unlock,
.irq_disable = tps6586x_irq_disable,
.irq_enable = tps6586x_irq_enable,
};

static int tps6586x_irq_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
struct tps6586x *tps6586x = h->host_data;

irq_set_chip_data(virq, tps6586x);
irq_set_chip_and_handler(virq, &tps6586x_irq_chip, handle_simple_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 tps6586x_domain_ops = {
.map = tps6586x_irq_map,
.xlate = irq_domain_xlate_twocell,
};

static irqreturn_t tps6586x_irq(int irq, void *data)
{
struct tps6586x *tps6586x = data;
Expand All @@ -259,7 +303,8 @@ static irqreturn_t tps6586x_irq(int irq, void *data)
int i = __ffs(acks);

if (tps6586x->irq_en & (1 << i))
handle_nested_irq(tps6586x->irq_base + i);
handle_nested_irq(
irq_find_mapping(tps6586x->irq_domain, i));

acks &= ~(1 << i);
}
Expand All @@ -272,11 +317,8 @@ static int __devinit tps6586x_irq_init(struct tps6586x *tps6586x, int irq,
{
int i, ret;
u8 tmp[4];

if (!irq_base) {
dev_warn(tps6586x->dev, "No interrupt support on IRQ base\n");
return -EINVAL;
}
int new_irq_base;
int irq_num = ARRAY_SIZE(tps6586x_irqs);

mutex_init(&tps6586x->irq_lock);
for (i = 0; i < 5; i++) {
Expand All @@ -286,25 +328,24 @@ static int __devinit tps6586x_irq_init(struct tps6586x *tps6586x, int irq,

tps6586x_reads(tps6586x->dev, TPS6586X_INT_ACK1, sizeof(tmp), tmp);

tps6586x->irq_base = irq_base;

tps6586x->irq_chip.name = "tps6586x";
tps6586x->irq_chip.irq_enable = tps6586x_irq_enable;
tps6586x->irq_chip.irq_disable = tps6586x_irq_disable;
tps6586x->irq_chip.irq_bus_lock = tps6586x_irq_lock;
tps6586x->irq_chip.irq_bus_sync_unlock = tps6586x_irq_sync_unlock;

for (i = 0; i < ARRAY_SIZE(tps6586x_irqs); i++) {
int __irq = i + tps6586x->irq_base;
irq_set_chip_data(__irq, tps6586x);
irq_set_chip_and_handler(__irq, &tps6586x->irq_chip,
handle_simple_irq);
irq_set_nested_thread(__irq, 1);
#ifdef CONFIG_ARM
set_irq_flags(__irq, IRQF_VALID);
#endif
if (irq_base > 0) {
new_irq_base = irq_alloc_descs(irq_base, 0, irq_num, -1);
if (new_irq_base < 0) {
dev_err(tps6586x->dev,
"Failed to alloc IRQs: %d\n", new_irq_base);
return new_irq_base;
}
} else {
new_irq_base = 0;
}

tps6586x->irq_domain = irq_domain_add_simple(tps6586x->dev->of_node,
irq_num, new_irq_base, &tps6586x_domain_ops,
tps6586x);
if (!tps6586x->irq_domain) {
dev_err(tps6586x->dev, "Failed to create IRQ domain\n");
return -ENOMEM;
}
ret = request_threaded_irq(irq, NULL, tps6586x_irq, IRQF_ONESHOT,
"tps6586x", tps6586x);

Expand Down
1 change: 1 addition & 0 deletions include/linux/mfd/tps6586x.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,6 @@ extern int tps6586x_set_bits(struct device *dev, int reg, uint8_t bit_mask);
extern int tps6586x_clr_bits(struct device *dev, int reg, uint8_t bit_mask);
extern int tps6586x_update(struct device *dev, int reg, uint8_t val,
uint8_t mask);
extern int tps6586x_irq_get_virq(struct device *dev, int irq);

#endif /*__LINUX_MFD_TPS6586X_H */

0 comments on commit 605511a

Please sign in to comment.