mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 05:02:12 +00:00
mfd: pm8xxx: convert to v2 irq interfaces to support hierarchical IRQ chips
Convert the PM8XXX IRQ code to use the version 2 IRQ interface in order to support hierarchical IRQ chips. This is necessary so that ssbi-gpio can be setup as a hierarchical IRQ chip with PM8xxx as the parent. IRQ chips in device tree should be usable from the start without having to make an additional call to gpio[d]_to_irq() to get the proper IRQ on the parent. pm8821_irq_domain_ops and pm8821_irq_domain_map are removed by this patch since the irq_chip is now contained in the pm_irq_data struct, and that allows us to use a common IRQ mapping function. This change was tested on an APQ8060 DragonBoard. Signed-off-by: Brian Masney <masneyb@onstation.org> Tested-by: Linus Walleij <linus.walleij@linaro.org> Acked-by: Lee Jones <lee.jones@linaro.org> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
parent
5aa5bd563c
commit
3324a7c1a2
@ -70,22 +70,23 @@
|
|||||||
#define PM8XXX_NR_IRQS 256
|
#define PM8XXX_NR_IRQS 256
|
||||||
#define PM8821_NR_IRQS 112
|
#define PM8821_NR_IRQS 112
|
||||||
|
|
||||||
|
struct pm_irq_data {
|
||||||
|
int num_irqs;
|
||||||
|
struct irq_chip *irq_chip;
|
||||||
|
void (*irq_handler)(struct irq_desc *desc);
|
||||||
|
};
|
||||||
|
|
||||||
struct pm_irq_chip {
|
struct pm_irq_chip {
|
||||||
struct regmap *regmap;
|
struct regmap *regmap;
|
||||||
spinlock_t pm_irq_lock;
|
spinlock_t pm_irq_lock;
|
||||||
struct irq_domain *irqdomain;
|
struct irq_domain *irqdomain;
|
||||||
unsigned int num_irqs;
|
|
||||||
unsigned int num_blocks;
|
unsigned int num_blocks;
|
||||||
unsigned int num_masters;
|
unsigned int num_masters;
|
||||||
|
const struct pm_irq_data *pm_irq_data;
|
||||||
|
/* MUST BE AT THE END OF THIS STRUCT */
|
||||||
u8 config[0];
|
u8 config[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pm_irq_data {
|
|
||||||
int num_irqs;
|
|
||||||
const struct irq_domain_ops *irq_domain_ops;
|
|
||||||
void (*irq_handler)(struct irq_desc *desc);
|
|
||||||
};
|
|
||||||
|
|
||||||
static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, unsigned int bp,
|
static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, unsigned int bp,
|
||||||
unsigned int *ip)
|
unsigned int *ip)
|
||||||
{
|
{
|
||||||
@ -375,21 +376,38 @@ static struct irq_chip pm8xxx_irq_chip = {
|
|||||||
.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE,
|
.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int pm8xxx_irq_domain_map(struct irq_domain *d, unsigned int irq,
|
static void pm8xxx_irq_domain_map(struct pm_irq_chip *chip,
|
||||||
irq_hw_number_t hwirq)
|
struct irq_domain *domain, unsigned int irq,
|
||||||
|
irq_hw_number_t hwirq, unsigned int type)
|
||||||
{
|
{
|
||||||
struct pm_irq_chip *chip = d->host_data;
|
irq_domain_set_info(domain, irq, hwirq, chip->pm_irq_data->irq_chip,
|
||||||
|
chip, handle_level_irq, NULL, NULL);
|
||||||
irq_set_chip_and_handler(irq, &pm8xxx_irq_chip, handle_level_irq);
|
|
||||||
irq_set_chip_data(irq, chip);
|
|
||||||
irq_set_noprobe(irq);
|
irq_set_noprobe(irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pm8xxx_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
|
||||||
|
unsigned int nr_irqs, void *data)
|
||||||
|
{
|
||||||
|
struct pm_irq_chip *chip = domain->host_data;
|
||||||
|
struct irq_fwspec *fwspec = data;
|
||||||
|
irq_hw_number_t hwirq;
|
||||||
|
unsigned int type;
|
||||||
|
int ret, i;
|
||||||
|
|
||||||
|
ret = irq_domain_translate_twocell(domain, fwspec, &hwirq, &type);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
for (i = 0; i < nr_irqs; i++)
|
||||||
|
pm8xxx_irq_domain_map(chip, domain, virq + i, hwirq + i, type);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct irq_domain_ops pm8xxx_irq_domain_ops = {
|
static const struct irq_domain_ops pm8xxx_irq_domain_ops = {
|
||||||
.xlate = irq_domain_xlate_twocell,
|
.alloc = pm8xxx_irq_domain_alloc,
|
||||||
.map = pm8xxx_irq_domain_map,
|
.free = irq_domain_free_irqs_common,
|
||||||
|
.translate = irq_domain_translate_twocell,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void pm8821_irq_mask_ack(struct irq_data *d)
|
static void pm8821_irq_mask_ack(struct irq_data *d)
|
||||||
@ -473,23 +491,6 @@ static struct irq_chip pm8821_irq_chip = {
|
|||||||
.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE,
|
.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int pm8821_irq_domain_map(struct irq_domain *d, unsigned int irq,
|
|
||||||
irq_hw_number_t hwirq)
|
|
||||||
{
|
|
||||||
struct pm_irq_chip *chip = d->host_data;
|
|
||||||
|
|
||||||
irq_set_chip_and_handler(irq, &pm8821_irq_chip, handle_level_irq);
|
|
||||||
irq_set_chip_data(irq, chip);
|
|
||||||
irq_set_noprobe(irq);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct irq_domain_ops pm8821_irq_domain_ops = {
|
|
||||||
.xlate = irq_domain_xlate_twocell,
|
|
||||||
.map = pm8821_irq_domain_map,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct regmap_config ssbi_regmap_config = {
|
static const struct regmap_config ssbi_regmap_config = {
|
||||||
.reg_bits = 16,
|
.reg_bits = 16,
|
||||||
.val_bits = 8,
|
.val_bits = 8,
|
||||||
@ -501,13 +502,13 @@ static const struct regmap_config ssbi_regmap_config = {
|
|||||||
|
|
||||||
static const struct pm_irq_data pm8xxx_data = {
|
static const struct pm_irq_data pm8xxx_data = {
|
||||||
.num_irqs = PM8XXX_NR_IRQS,
|
.num_irqs = PM8XXX_NR_IRQS,
|
||||||
.irq_domain_ops = &pm8xxx_irq_domain_ops,
|
.irq_chip = &pm8xxx_irq_chip,
|
||||||
.irq_handler = pm8xxx_irq_handler,
|
.irq_handler = pm8xxx_irq_handler,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct pm_irq_data pm8821_data = {
|
static const struct pm_irq_data pm8821_data = {
|
||||||
.num_irqs = PM8821_NR_IRQS,
|
.num_irqs = PM8821_NR_IRQS,
|
||||||
.irq_domain_ops = &pm8821_irq_domain_ops,
|
.irq_chip = &pm8821_irq_chip,
|
||||||
.irq_handler = pm8821_irq_handler,
|
.irq_handler = pm8821_irq_handler,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -571,14 +572,14 @@ static int pm8xxx_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
platform_set_drvdata(pdev, chip);
|
platform_set_drvdata(pdev, chip);
|
||||||
chip->regmap = regmap;
|
chip->regmap = regmap;
|
||||||
chip->num_irqs = data->num_irqs;
|
chip->num_blocks = DIV_ROUND_UP(data->num_irqs, 8);
|
||||||
chip->num_blocks = DIV_ROUND_UP(chip->num_irqs, 8);
|
|
||||||
chip->num_masters = DIV_ROUND_UP(chip->num_blocks, 8);
|
chip->num_masters = DIV_ROUND_UP(chip->num_blocks, 8);
|
||||||
|
chip->pm_irq_data = data;
|
||||||
spin_lock_init(&chip->pm_irq_lock);
|
spin_lock_init(&chip->pm_irq_lock);
|
||||||
|
|
||||||
chip->irqdomain = irq_domain_add_linear(pdev->dev.of_node,
|
chip->irqdomain = irq_domain_add_linear(pdev->dev.of_node,
|
||||||
data->num_irqs,
|
data->num_irqs,
|
||||||
data->irq_domain_ops,
|
&pm8xxx_irq_domain_ops,
|
||||||
chip);
|
chip);
|
||||||
if (!chip->irqdomain)
|
if (!chip->irqdomain)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
Loading…
Reference in New Issue
Block a user