regmap: irq: Add support to call client specific pre/post interrupt service
authorLaxman Dewangan <ldewangan@nvidia.com>
Fri, 20 May 2016 15:10:26 +0000 (20:40 +0530)
committerMark Brown <broonie@kernel.org>
Thu, 2 Jun 2016 23:41:15 +0000 (00:41 +0100)
Regmap irq implements the generic interrupt service routine which
is common for most of devices. Some devices, like MAX77620, MAX20024
needs the special handling before and after servicing the interrupt
as generic. For the example, MAX77620 programming guidelines for
interrupt servicing says:
1. When interrupt occurs from PMIC, mask the PMIC interrupt by setting
   GLBLM.
2. Read IRQTOP and service the interrupt accordingly.
3. Once all interrupts has been checked and serviced, the interrupt
   service routine un-masks the hardware interrupt line by clearing
   GLBLM.

The step (2) is implemented in regmap irq as generic routine. For
step (1) and (3), add callbacks from regmap irq to client driver
to handle chip specific configurations.

Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/base/regmap/regmap-irq.c
include/linux/regmap.h

index 26f799e71c82355e02ef58ff9847cef33545e444..ec262476d04387053ffc091b6c24993f5ce15415 100644 (file)
@@ -268,13 +268,16 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
        bool handled = false;
        u32 reg;
 
+       if (chip->handle_pre_irq)
+               chip->handle_pre_irq(chip->irq_drv_data);
+
        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;
                }
        }
 
@@ -296,7 +299,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++) {
@@ -312,7 +315,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
                                break;
                        default:
                                BUG();
-                               return IRQ_NONE;
+                               goto exit;
                        }
                }
 
@@ -329,7 +332,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;
                        }
                }
        }
@@ -365,6 +368,10 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
        if (chip->runtime_pm)
                pm_runtime_put(map->dev);
 
+exit:
+       if (chip->handle_post_irq)
+               chip->handle_post_irq(chip->irq_drv_data);
+
        if (handled)
                return IRQ_HANDLED;
        else
index 3dc08ce15426e67eff3cd1c785544c6877603e97..a0bfe481f9abf1a76748f58eaecca5af26e787d6 100644 (file)
@@ -851,6 +851,12 @@ struct regmap_irq {
  * @num_type_reg:    Number of type registers.
  * @type_reg_stride: Stride to use for chips where type registers are not
  *                     contiguous.
+ * @handle_pre_irq:  Driver specific callback to handle interrupt from device
+ *                  before regmap_irq_handler process the interrupts.
+ * @handle_post_irq: Driver specific callback to handle interrupt from device
+ *                  after handling the interrupts in regmap_irq_handler().
+ * @irq_drv_data:    Driver specific IRQ data which is passed as parameter when
+ *                  driver specific pre/post interrupt handler is called.
  */
 struct regmap_irq_chip {
        const char *name;
@@ -877,6 +883,10 @@ struct regmap_irq_chip {
 
        int num_type_reg;
        unsigned int type_reg_stride;
+
+       int (*handle_pre_irq)(void *irq_drv_data);
+       int (*handle_post_irq)(void *irq_drv_data);
+       void *irq_drv_data;
 };
 
 struct regmap_irq_chip_data;