diff options
author | Laxman Dewangan <ldewangan@nvidia.com> | 2014-03-27 19:06:21 +0530 |
---|---|---|
committer | Laxman Dewangan <ldewangan@nvidia.com> | 2014-03-28 06:32:40 -0700 |
commit | e6058d212505b786b6bdde5c8e4cb2b882911c58 (patch) | |
tree | d1b771efd036b5f4908bc247823fbba324ba0bb6 /drivers/base | |
parent | 88e3e6066bc668a36f4c83620e37728b235665d7 (diff) |
regmap: add support for mask all interrupts on shutdown
Add API to implement the mask of all interrupt which can be
called during shutdown process. This will make sure that
no interrupt get generated during shutdown.
Change-Id: I69d6a9b1e6323b1a1ec722d23e52360949448ff7
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Reviewed-on: http://git-master/r/387781
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/regmap/regmap-irq.c | 58 |
1 files changed, 54 insertions, 4 deletions
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index 69454e37f966..abb6c4b681c4 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c @@ -23,6 +23,7 @@ struct regmap_irq_chip_data { struct mutex lock; + struct mutex shutdown_lock; struct irq_chip irq_chip; struct regmap *map; @@ -31,6 +32,7 @@ struct regmap_irq_chip_data { int irq_base; struct irq_domain *domain; + int shutdown; int irq; int wake_count; @@ -234,13 +236,19 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) bool handled = false; u32 reg; + mutex_lock(&data->shutdown_lock); + if (data->shutdown) { + dev_err(map->dev, "IRQ %d thread calls after shutdown\n", irq); + goto exit; + } + 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); pm_runtime_put(map->dev); - return IRQ_NONE; + goto exit; } } @@ -262,7 +270,7 @@ 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); - return IRQ_NONE; + goto exit; } for (i = 0; i < data->chip->num_regs; i++) { @@ -278,7 +286,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) break; default: BUG(); - return IRQ_NONE; + goto exit; } } @@ -295,7 +303,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) ret); if (chip->runtime_pm) pm_runtime_put(map->dev); - return IRQ_NONE; + goto exit; } } } @@ -331,6 +339,8 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) if (chip->runtime_pm) pm_runtime_put(map->dev); +exit: + mutex_unlock(&data->shutdown_lock); if (handled) return IRQ_HANDLED; else @@ -466,6 +476,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, } mutex_init(&d->lock); + mutex_init(&d->shutdown_lock); for (i = 0; i < chip->num_irqs; i++) d->mask_buf_def[chip->irqs[i].reg_offset / map->reg_stride] @@ -606,6 +617,45 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d) EXPORT_SYMBOL_GPL(regmap_del_irq_chip); /** + * regmap_shutdown_irq_chip(): Shutdown all interrupts + * + * @d: regmap_irq_chip_data allocated by regmap_add_irq_chip() + */ +void regmap_shutdown_irq_chip(struct regmap_irq_chip_data *d) +{ + u32 reg; + int i, ret; + + if (!d) + return; + + mutex_lock(&d->shutdown_lock); + disable_irq(d->irq); + + /* Mask all the interrupts by default */ + for (i = 0; i < d->chip->num_regs; i++) { + if (!d->chip->mask_base) + continue; + + reg = d->chip->mask_base + + (i * d->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_def[i]); + else + ret = regmap_update_bits(d->map, reg, + d->mask_buf_def[i], d->mask_buf_def[i]); + if (ret != 0) + dev_err(d->map->dev, "Failed to set masks in 0x%x: %d\n", + reg, ret); + } + + d->shutdown = true; + mutex_unlock(&d->shutdown_lock); +} +EXPORT_SYMBOL_GPL(regmap_shutdown_irq_chip); + +/** * regmap_irq_chip_get_base(): Retrieve interrupt base for a regmap IRQ chip * * Useful for drivers to request their own IRQs. |