Loading drivers/base/regmap/regmap-irq.c +51 −0 Original line number Original line Diff line number Diff line Loading @@ -29,9 +29,13 @@ struct regmap_irq_chip_data { int irq_base; int irq_base; struct irq_domain *domain; struct irq_domain *domain; int irq; int wake_count; unsigned int *status_buf; unsigned int *status_buf; unsigned int *mask_buf; unsigned int *mask_buf; unsigned int *mask_buf_def; unsigned int *mask_buf_def; unsigned int *wake_buf; unsigned int irq_reg_stride; unsigned int irq_reg_stride; }; }; Loading Loading @@ -71,6 +75,16 @@ static void regmap_irq_sync_unlock(struct irq_data *data) d->chip->mask_base + (i * map->reg_stride)); d->chip->mask_base + (i * map->reg_stride)); } } /* If we've changed our wakeup count propagate it to the parent */ if (d->wake_count < 0) for (i = d->wake_count; i < 0; i++) irq_set_irq_wake(d->irq, 0); else if (d->wake_count > 0) for (i = 0; i < d->wake_count; i++) irq_set_irq_wake(d->irq, 1); d->wake_count = 0; mutex_unlock(&d->lock); mutex_unlock(&d->lock); } } Loading @@ -92,12 +106,35 @@ static void regmap_irq_disable(struct irq_data *data) d->mask_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask; d->mask_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask; } } static int regmap_irq_set_wake(struct irq_data *data, unsigned int on) { 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->hwirq); if (!d->chip->wake_base) return -EINVAL; if (on) { d->wake_buf[irq_data->reg_offset / map->reg_stride] &= ~irq_data->mask; d->wake_count++; } else { d->wake_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask; d->wake_count--; } return 0; } static struct irq_chip regmap_irq_chip = { static struct irq_chip regmap_irq_chip = { .name = "regmap", .name = "regmap", .irq_bus_lock = regmap_irq_lock, .irq_bus_lock = regmap_irq_lock, .irq_bus_sync_unlock = regmap_irq_sync_unlock, .irq_bus_sync_unlock = regmap_irq_sync_unlock, .irq_disable = regmap_irq_disable, .irq_disable = regmap_irq_disable, .irq_enable = regmap_irq_enable, .irq_enable = regmap_irq_enable, .irq_set_wake = regmap_irq_set_wake, }; }; static irqreturn_t regmap_irq_thread(int irq, void *d) static irqreturn_t regmap_irq_thread(int irq, void *d) Loading Loading @@ -240,6 +277,14 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, if (!d->mask_buf_def) if (!d->mask_buf_def) goto err_alloc; goto err_alloc; if (chip->wake_base) { d->wake_buf = kzalloc(sizeof(unsigned int) * chip->num_regs, GFP_KERNEL); if (!d->wake_buf) goto err_alloc; } d->irq = irq; d->map = map; d->map = map; d->chip = chip; d->chip = chip; d->irq_base = irq_base; d->irq_base = irq_base; Loading Loading @@ -294,6 +339,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, err_domain: err_domain: /* Should really dispose of the domain but... */ /* Should really dispose of the domain but... */ err_alloc: err_alloc: kfree(d->wake_buf); kfree(d->mask_buf_def); kfree(d->mask_buf_def); kfree(d->mask_buf); kfree(d->mask_buf); kfree(d->status_buf); kfree(d->status_buf); Loading @@ -315,6 +361,7 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d) free_irq(irq, d); free_irq(irq, d); /* We should unmap the domain but... */ /* We should unmap the domain but... */ kfree(d->wake_buf); kfree(d->mask_buf_def); kfree(d->mask_buf_def); kfree(d->mask_buf); kfree(d->mask_buf); kfree(d->status_buf); kfree(d->status_buf); Loading Loading @@ -346,6 +393,10 @@ EXPORT_SYMBOL_GPL(regmap_irq_chip_get_base); */ */ int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq) int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq) { { /* Handle holes in the IRQ list */ if (!data->chip->irqs[irq].mask) return -EINVAL; return irq_create_mapping(data->domain, irq); return irq_create_mapping(data->domain, irq); } } EXPORT_SYMBOL_GPL(regmap_irq_get_virq); EXPORT_SYMBOL_GPL(regmap_irq_get_virq); include/linux/regmap.h +2 −0 Original line number Original line Diff line number Diff line Loading @@ -219,6 +219,7 @@ struct regmap_irq { * @status_base: Base status register address. * @status_base: Base status register address. * @mask_base: Base mask register address. * @mask_base: Base mask register address. * @ack_base: Base ack address. If zero then the chip is clear on read. * @ack_base: Base ack address. If zero then the chip is clear on read. * @wake_base: Base address for wake enables. If zero unsupported. * @irq_reg_stride: Stride to use for chips where registers are not contiguous. * @irq_reg_stride: Stride to use for chips where registers are not contiguous. * * * @num_regs: Number of registers in each control bank. * @num_regs: Number of registers in each control bank. Loading @@ -232,6 +233,7 @@ struct regmap_irq_chip { unsigned int status_base; unsigned int status_base; unsigned int mask_base; unsigned int mask_base; unsigned int ack_base; unsigned int ack_base; unsigned int wake_base; unsigned int irq_reg_stride; unsigned int irq_reg_stride; int num_regs; int num_regs; Loading Loading
drivers/base/regmap/regmap-irq.c +51 −0 Original line number Original line Diff line number Diff line Loading @@ -29,9 +29,13 @@ struct regmap_irq_chip_data { int irq_base; int irq_base; struct irq_domain *domain; struct irq_domain *domain; int irq; int wake_count; unsigned int *status_buf; unsigned int *status_buf; unsigned int *mask_buf; unsigned int *mask_buf; unsigned int *mask_buf_def; unsigned int *mask_buf_def; unsigned int *wake_buf; unsigned int irq_reg_stride; unsigned int irq_reg_stride; }; }; Loading Loading @@ -71,6 +75,16 @@ static void regmap_irq_sync_unlock(struct irq_data *data) d->chip->mask_base + (i * map->reg_stride)); d->chip->mask_base + (i * map->reg_stride)); } } /* If we've changed our wakeup count propagate it to the parent */ if (d->wake_count < 0) for (i = d->wake_count; i < 0; i++) irq_set_irq_wake(d->irq, 0); else if (d->wake_count > 0) for (i = 0; i < d->wake_count; i++) irq_set_irq_wake(d->irq, 1); d->wake_count = 0; mutex_unlock(&d->lock); mutex_unlock(&d->lock); } } Loading @@ -92,12 +106,35 @@ static void regmap_irq_disable(struct irq_data *data) d->mask_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask; d->mask_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask; } } static int regmap_irq_set_wake(struct irq_data *data, unsigned int on) { 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->hwirq); if (!d->chip->wake_base) return -EINVAL; if (on) { d->wake_buf[irq_data->reg_offset / map->reg_stride] &= ~irq_data->mask; d->wake_count++; } else { d->wake_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask; d->wake_count--; } return 0; } static struct irq_chip regmap_irq_chip = { static struct irq_chip regmap_irq_chip = { .name = "regmap", .name = "regmap", .irq_bus_lock = regmap_irq_lock, .irq_bus_lock = regmap_irq_lock, .irq_bus_sync_unlock = regmap_irq_sync_unlock, .irq_bus_sync_unlock = regmap_irq_sync_unlock, .irq_disable = regmap_irq_disable, .irq_disable = regmap_irq_disable, .irq_enable = regmap_irq_enable, .irq_enable = regmap_irq_enable, .irq_set_wake = regmap_irq_set_wake, }; }; static irqreturn_t regmap_irq_thread(int irq, void *d) static irqreturn_t regmap_irq_thread(int irq, void *d) Loading Loading @@ -240,6 +277,14 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, if (!d->mask_buf_def) if (!d->mask_buf_def) goto err_alloc; goto err_alloc; if (chip->wake_base) { d->wake_buf = kzalloc(sizeof(unsigned int) * chip->num_regs, GFP_KERNEL); if (!d->wake_buf) goto err_alloc; } d->irq = irq; d->map = map; d->map = map; d->chip = chip; d->chip = chip; d->irq_base = irq_base; d->irq_base = irq_base; Loading Loading @@ -294,6 +339,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, err_domain: err_domain: /* Should really dispose of the domain but... */ /* Should really dispose of the domain but... */ err_alloc: err_alloc: kfree(d->wake_buf); kfree(d->mask_buf_def); kfree(d->mask_buf_def); kfree(d->mask_buf); kfree(d->mask_buf); kfree(d->status_buf); kfree(d->status_buf); Loading @@ -315,6 +361,7 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d) free_irq(irq, d); free_irq(irq, d); /* We should unmap the domain but... */ /* We should unmap the domain but... */ kfree(d->wake_buf); kfree(d->mask_buf_def); kfree(d->mask_buf_def); kfree(d->mask_buf); kfree(d->mask_buf); kfree(d->status_buf); kfree(d->status_buf); Loading Loading @@ -346,6 +393,10 @@ EXPORT_SYMBOL_GPL(regmap_irq_chip_get_base); */ */ int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq) int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq) { { /* Handle holes in the IRQ list */ if (!data->chip->irqs[irq].mask) return -EINVAL; return irq_create_mapping(data->domain, irq); return irq_create_mapping(data->domain, irq); } } EXPORT_SYMBOL_GPL(regmap_irq_get_virq); EXPORT_SYMBOL_GPL(regmap_irq_get_virq);
include/linux/regmap.h +2 −0 Original line number Original line Diff line number Diff line Loading @@ -219,6 +219,7 @@ struct regmap_irq { * @status_base: Base status register address. * @status_base: Base status register address. * @mask_base: Base mask register address. * @mask_base: Base mask register address. * @ack_base: Base ack address. If zero then the chip is clear on read. * @ack_base: Base ack address. If zero then the chip is clear on read. * @wake_base: Base address for wake enables. If zero unsupported. * @irq_reg_stride: Stride to use for chips where registers are not contiguous. * @irq_reg_stride: Stride to use for chips where registers are not contiguous. * * * @num_regs: Number of registers in each control bank. * @num_regs: Number of registers in each control bank. Loading @@ -232,6 +233,7 @@ struct regmap_irq_chip { unsigned int status_base; unsigned int status_base; unsigned int mask_base; unsigned int mask_base; unsigned int ack_base; unsigned int ack_base; unsigned int wake_base; unsigned int irq_reg_stride; unsigned int irq_reg_stride; int num_regs; int num_regs; Loading