]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
regmap: add support for mask all interrupts on shutdown
authorLaxman Dewangan <ldewangan@nvidia.com>
Thu, 27 Mar 2014 13:36:21 +0000 (19:06 +0530)
committerLaxman Dewangan <ldewangan@nvidia.com>
Fri, 28 Mar 2014 13:32:40 +0000 (06:32 -0700)
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

drivers/base/regmap/regmap-irq.c
include/linux/regmap.h

index 69454e37f966f98e016469a7b1e25ce5544c292c..abb6c4b681c49a55f2c283aac6cd46e29b317917 100644 (file)
@@ -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]
@@ -605,6 +616,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
  *
index 882d360b9d75692ee2d3bb68b3fed6943a3eacfb..08f75c2f93c830829d6b40e26bebe40aa707217d 100644 (file)
@@ -491,6 +491,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
                        int irq_base, const struct regmap_irq_chip *chip,
                        struct regmap_irq_chip_data **data);
 void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *data);
+void regmap_shutdown_irq_chip(struct regmap_irq_chip_data *d);
 int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data);
 int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq);
 struct irq_domain *regmap_irq_get_domain(struct regmap_irq_chip_data *data);