Loading drivers/base/regmap/regmap-irq.c +75 −17 Original line number Diff line number Diff line Loading @@ -16,12 +16,14 @@ #include <linux/irq.h> #include <linux/interrupt.h> #include <linux/irqdomain.h> #include <linux/pm_runtime.h> #include <linux/slab.h> #include "internal.h" struct regmap_irq_chip_data { struct mutex lock; struct irq_chip irq_chip; struct regmap *map; const struct regmap_irq_chip *chip; Loading Loading @@ -59,6 +61,14 @@ static void regmap_irq_sync_unlock(struct irq_data *data) struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data); struct regmap *map = d->map; int i, ret; u32 reg; if (d->chip->runtime_pm) { ret = pm_runtime_get_sync(map->dev); if (ret < 0) dev_err(map->dev, "IRQ sync failed to resume: %d\n", ret); } /* * If there's been a change in the mask write it back to the Loading @@ -66,15 +76,22 @@ static void regmap_irq_sync_unlock(struct irq_data *data) * suppress pointless writes. */ for (i = 0; i < d->chip->num_regs; i++) { ret = regmap_update_bits(d->map, d->chip->mask_base + (i * map->reg_stride * d->irq_reg_stride), reg = d->chip->mask_base + (i * map->reg_stride * d->irq_reg_stride); if (d->chip->mask_invert) ret = regmap_update_bits(d->map, reg, d->mask_buf_def[i], ~d->mask_buf[i]); else ret = regmap_update_bits(d->map, reg, d->mask_buf_def[i], d->mask_buf[i]); if (ret != 0) dev_err(d->map->dev, "Failed to sync masks in %x\n", d->chip->mask_base + (i * map->reg_stride)); reg); } if (d->chip->runtime_pm) pm_runtime_put(map->dev); /* 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++) Loading Loading @@ -128,8 +145,7 @@ static int regmap_irq_set_wake(struct irq_data *data, unsigned int on) return 0; } static struct irq_chip regmap_irq_chip = { .name = "regmap", static const struct irq_chip regmap_irq_chip = { .irq_bus_lock = regmap_irq_lock, .irq_bus_sync_unlock = regmap_irq_sync_unlock, .irq_disable = regmap_irq_disable, Loading @@ -144,6 +160,16 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) struct regmap *map = data->map; int ret, i; bool handled = false; u32 reg; if (chip->runtime_pm) { ret = pm_runtime_get_sync(map->dev); if (ret < 0) { dev_err(map->dev, "IRQ thread failed to resume: %d\n", ret); return IRQ_NONE; } } /* * Ignore masked IRQs and ack if we need to; we ack early so Loading @@ -160,20 +186,20 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) if (ret != 0) { dev_err(map->dev, "Failed to read IRQ status: %d\n", ret); if (chip->runtime_pm) pm_runtime_put(map->dev); return IRQ_NONE; } data->status_buf[i] &= ~data->mask_buf[i]; if (data->status_buf[i] && chip->ack_base) { ret = regmap_write(map, chip->ack_base + (i * map->reg_stride * data->irq_reg_stride), data->status_buf[i]); reg = chip->ack_base + (i * map->reg_stride * data->irq_reg_stride); ret = regmap_write(map, reg, data->status_buf[i]); if (ret != 0) dev_err(map->dev, "Failed to ack 0x%x: %d\n", chip->ack_base + (i * map->reg_stride), ret); reg, ret); } } Loading @@ -185,6 +211,9 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) } } if (chip->runtime_pm) pm_runtime_put(map->dev); if (handled) return IRQ_HANDLED; else Loading @@ -197,7 +226,7 @@ static int regmap_irq_map(struct irq_domain *h, unsigned int virq, struct regmap_irq_chip_data *data = h->host_data; irq_set_chip_data(virq, data); irq_set_chip_and_handler(virq, ®map_irq_chip, handle_edge_irq); irq_set_chip(virq, &data->irq_chip); irq_set_nested_thread(virq, 1); /* ARM needs us to explicitly flag the IRQ as valid Loading Loading @@ -238,6 +267,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, struct regmap_irq_chip_data *d; int i; int ret = -ENOMEM; u32 reg; for (i = 0; i < chip->num_irqs; i++) { if (chip->irqs[i].reg_offset % map->reg_stride) Loading Loading @@ -284,6 +314,13 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, goto err_alloc; } d->irq_chip = regmap_irq_chip; d->irq_chip.name = chip->name; if (!chip->wake_base) { d->irq_chip.irq_set_wake = NULL; d->irq_chip.flags |= IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE; } d->irq = irq; d->map = map; d->chip = chip; Loading @@ -303,16 +340,37 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, /* Mask all the interrupts by default */ for (i = 0; i < chip->num_regs; i++) { d->mask_buf[i] = d->mask_buf_def[i]; ret = regmap_write(map, chip->mask_base + (i * map->reg_stride * d->irq_reg_stride), d->mask_buf[i]); reg = chip->mask_base + (i * map->reg_stride * d->irq_reg_stride); if (chip->mask_invert) ret = regmap_update_bits(map, reg, d->mask_buf[i], ~d->mask_buf[i]); else ret = regmap_update_bits(map, reg, d->mask_buf[i], d->mask_buf[i]); if (ret != 0) { dev_err(map->dev, "Failed to set masks in 0x%x: %d\n", chip->mask_base + (i * map->reg_stride), ret); reg, ret); goto err_alloc; } } /* Wake is disabled by default */ if (d->wake_buf) { for (i = 0; i < chip->num_regs; i++) { d->wake_buf[i] = d->mask_buf_def[i]; reg = chip->wake_base + (i * map->reg_stride * d->irq_reg_stride); ret = regmap_update_bits(map, reg, d->wake_buf[i], d->wake_buf[i]); if (ret != 0) { dev_err(map->dev, "Failed to set masks in 0x%x: %d\n", reg, ret); goto err_alloc; } } } if (irq_base) d->domain = irq_domain_add_legacy(map->dev->of_node, chip->num_irqs, irq_base, 0, Loading drivers/base/regmap/regmap.c +4 −9 Original line number Diff line number Diff line Loading @@ -659,13 +659,12 @@ EXPORT_SYMBOL_GPL(devm_regmap_init); * new cache. This can be used to restore the cache to defaults or to * update the cache configuration to reflect runtime discovery of the * hardware. * * No explicit locking is done here, the user needs to ensure that * this function will not race with other calls to regmap. */ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config) { int ret; map->lock(map); regcache_exit(map); regmap_debugfs_exit(map); Loading @@ -681,11 +680,7 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config) map->cache_bypass = false; map->cache_only = false; ret = regcache_init(map, config); map->unlock(map); return ret; return regcache_init(map, config); } EXPORT_SYMBOL_GPL(regmap_reinit_cache); Loading drivers/mfd/wm8994-irq.c +1 −0 Original line number Diff line number Diff line Loading @@ -135,6 +135,7 @@ static struct regmap_irq_chip wm8994_irq_chip = { .status_base = WM8994_INTERRUPT_STATUS_1, .mask_base = WM8994_INTERRUPT_STATUS_1_MASK, .ack_base = WM8994_INTERRUPT_STATUS_1, .runtime_pm = true, }; int wm8994_irq_init(struct wm8994 *wm8994) Loading include/linux/regmap.h +3 −0 Original line number Diff line number Diff line Loading @@ -285,6 +285,7 @@ struct regmap_irq { * @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. * @runtime_pm: Hold a runtime PM lock on the device when accessing it. * * @num_regs: Number of registers in each control bank. * @irqs: Descriptors for individual IRQs. Interrupt numbers are Loading @@ -299,6 +300,8 @@ struct regmap_irq_chip { unsigned int ack_base; unsigned int wake_base; unsigned int irq_reg_stride; unsigned int mask_invert; bool runtime_pm; int num_regs; Loading Loading
drivers/base/regmap/regmap-irq.c +75 −17 Original line number Diff line number Diff line Loading @@ -16,12 +16,14 @@ #include <linux/irq.h> #include <linux/interrupt.h> #include <linux/irqdomain.h> #include <linux/pm_runtime.h> #include <linux/slab.h> #include "internal.h" struct regmap_irq_chip_data { struct mutex lock; struct irq_chip irq_chip; struct regmap *map; const struct regmap_irq_chip *chip; Loading Loading @@ -59,6 +61,14 @@ static void regmap_irq_sync_unlock(struct irq_data *data) struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data); struct regmap *map = d->map; int i, ret; u32 reg; if (d->chip->runtime_pm) { ret = pm_runtime_get_sync(map->dev); if (ret < 0) dev_err(map->dev, "IRQ sync failed to resume: %d\n", ret); } /* * If there's been a change in the mask write it back to the Loading @@ -66,15 +76,22 @@ static void regmap_irq_sync_unlock(struct irq_data *data) * suppress pointless writes. */ for (i = 0; i < d->chip->num_regs; i++) { ret = regmap_update_bits(d->map, d->chip->mask_base + (i * map->reg_stride * d->irq_reg_stride), reg = d->chip->mask_base + (i * map->reg_stride * d->irq_reg_stride); if (d->chip->mask_invert) ret = regmap_update_bits(d->map, reg, d->mask_buf_def[i], ~d->mask_buf[i]); else ret = regmap_update_bits(d->map, reg, d->mask_buf_def[i], d->mask_buf[i]); if (ret != 0) dev_err(d->map->dev, "Failed to sync masks in %x\n", d->chip->mask_base + (i * map->reg_stride)); reg); } if (d->chip->runtime_pm) pm_runtime_put(map->dev); /* 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++) Loading Loading @@ -128,8 +145,7 @@ static int regmap_irq_set_wake(struct irq_data *data, unsigned int on) return 0; } static struct irq_chip regmap_irq_chip = { .name = "regmap", static const struct irq_chip regmap_irq_chip = { .irq_bus_lock = regmap_irq_lock, .irq_bus_sync_unlock = regmap_irq_sync_unlock, .irq_disable = regmap_irq_disable, Loading @@ -144,6 +160,16 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) struct regmap *map = data->map; int ret, i; bool handled = false; u32 reg; if (chip->runtime_pm) { ret = pm_runtime_get_sync(map->dev); if (ret < 0) { dev_err(map->dev, "IRQ thread failed to resume: %d\n", ret); return IRQ_NONE; } } /* * Ignore masked IRQs and ack if we need to; we ack early so Loading @@ -160,20 +186,20 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) if (ret != 0) { dev_err(map->dev, "Failed to read IRQ status: %d\n", ret); if (chip->runtime_pm) pm_runtime_put(map->dev); return IRQ_NONE; } data->status_buf[i] &= ~data->mask_buf[i]; if (data->status_buf[i] && chip->ack_base) { ret = regmap_write(map, chip->ack_base + (i * map->reg_stride * data->irq_reg_stride), data->status_buf[i]); reg = chip->ack_base + (i * map->reg_stride * data->irq_reg_stride); ret = regmap_write(map, reg, data->status_buf[i]); if (ret != 0) dev_err(map->dev, "Failed to ack 0x%x: %d\n", chip->ack_base + (i * map->reg_stride), ret); reg, ret); } } Loading @@ -185,6 +211,9 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) } } if (chip->runtime_pm) pm_runtime_put(map->dev); if (handled) return IRQ_HANDLED; else Loading @@ -197,7 +226,7 @@ static int regmap_irq_map(struct irq_domain *h, unsigned int virq, struct regmap_irq_chip_data *data = h->host_data; irq_set_chip_data(virq, data); irq_set_chip_and_handler(virq, ®map_irq_chip, handle_edge_irq); irq_set_chip(virq, &data->irq_chip); irq_set_nested_thread(virq, 1); /* ARM needs us to explicitly flag the IRQ as valid Loading Loading @@ -238,6 +267,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, struct regmap_irq_chip_data *d; int i; int ret = -ENOMEM; u32 reg; for (i = 0; i < chip->num_irqs; i++) { if (chip->irqs[i].reg_offset % map->reg_stride) Loading Loading @@ -284,6 +314,13 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, goto err_alloc; } d->irq_chip = regmap_irq_chip; d->irq_chip.name = chip->name; if (!chip->wake_base) { d->irq_chip.irq_set_wake = NULL; d->irq_chip.flags |= IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE; } d->irq = irq; d->map = map; d->chip = chip; Loading @@ -303,16 +340,37 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, /* Mask all the interrupts by default */ for (i = 0; i < chip->num_regs; i++) { d->mask_buf[i] = d->mask_buf_def[i]; ret = regmap_write(map, chip->mask_base + (i * map->reg_stride * d->irq_reg_stride), d->mask_buf[i]); reg = chip->mask_base + (i * map->reg_stride * d->irq_reg_stride); if (chip->mask_invert) ret = regmap_update_bits(map, reg, d->mask_buf[i], ~d->mask_buf[i]); else ret = regmap_update_bits(map, reg, d->mask_buf[i], d->mask_buf[i]); if (ret != 0) { dev_err(map->dev, "Failed to set masks in 0x%x: %d\n", chip->mask_base + (i * map->reg_stride), ret); reg, ret); goto err_alloc; } } /* Wake is disabled by default */ if (d->wake_buf) { for (i = 0; i < chip->num_regs; i++) { d->wake_buf[i] = d->mask_buf_def[i]; reg = chip->wake_base + (i * map->reg_stride * d->irq_reg_stride); ret = regmap_update_bits(map, reg, d->wake_buf[i], d->wake_buf[i]); if (ret != 0) { dev_err(map->dev, "Failed to set masks in 0x%x: %d\n", reg, ret); goto err_alloc; } } } if (irq_base) d->domain = irq_domain_add_legacy(map->dev->of_node, chip->num_irqs, irq_base, 0, Loading
drivers/base/regmap/regmap.c +4 −9 Original line number Diff line number Diff line Loading @@ -659,13 +659,12 @@ EXPORT_SYMBOL_GPL(devm_regmap_init); * new cache. This can be used to restore the cache to defaults or to * update the cache configuration to reflect runtime discovery of the * hardware. * * No explicit locking is done here, the user needs to ensure that * this function will not race with other calls to regmap. */ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config) { int ret; map->lock(map); regcache_exit(map); regmap_debugfs_exit(map); Loading @@ -681,11 +680,7 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config) map->cache_bypass = false; map->cache_only = false; ret = regcache_init(map, config); map->unlock(map); return ret; return regcache_init(map, config); } EXPORT_SYMBOL_GPL(regmap_reinit_cache); Loading
drivers/mfd/wm8994-irq.c +1 −0 Original line number Diff line number Diff line Loading @@ -135,6 +135,7 @@ static struct regmap_irq_chip wm8994_irq_chip = { .status_base = WM8994_INTERRUPT_STATUS_1, .mask_base = WM8994_INTERRUPT_STATUS_1_MASK, .ack_base = WM8994_INTERRUPT_STATUS_1, .runtime_pm = true, }; int wm8994_irq_init(struct wm8994 *wm8994) Loading
include/linux/regmap.h +3 −0 Original line number Diff line number Diff line Loading @@ -285,6 +285,7 @@ struct regmap_irq { * @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. * @runtime_pm: Hold a runtime PM lock on the device when accessing it. * * @num_regs: Number of registers in each control bank. * @irqs: Descriptors for individual IRQs. Interrupt numbers are Loading @@ -299,6 +300,8 @@ struct regmap_irq_chip { unsigned int ack_base; unsigned int wake_base; unsigned int irq_reg_stride; unsigned int mask_invert; bool runtime_pm; int num_regs; Loading