summaryrefslogtreecommitdiff
path: root/drivers/base
diff options
context:
space:
mode:
authorLaxman Dewangan <ldewangan@nvidia.com>2014-03-27 19:06:21 +0530
committerLaxman Dewangan <ldewangan@nvidia.com>2014-03-28 06:32:40 -0700
commite6058d212505b786b6bdde5c8e4cb2b882911c58 (patch)
treed1b771efd036b5f4908bc247823fbba324ba0bb6 /drivers/base
parent88e3e6066bc668a36f4c83620e37728b235665d7 (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.c58
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.