ARM: OMAP3+: SmartReflex: clear ERRCONFIG_VPBOUNDINTST only on a need
[pandora-kernel.git] / arch / arm / mach-omap2 / smartreflex.c
index cf246b3..7ec14fd 100644 (file)
@@ -74,10 +74,6 @@ static inline void sr_modify_reg(struct omap_sr *sr, unsigned offset, u32 mask,
                                        u32 value)
 {
        u32 reg_val;
-       u32 errconfig_offs = 0, errconfig_mask = 0;
-
-       reg_val = __raw_readl(sr->base + offset);
-       reg_val &= ~mask;
 
        /*
         * Smartreflex error config register is special as it contains
@@ -88,16 +84,15 @@ static inline void sr_modify_reg(struct omap_sr *sr, unsigned offset, u32 mask,
         * if they are currently set, but does allow the caller to write
         * those bits.
         */
-       if (sr->ip_type == SR_TYPE_V1) {
-               errconfig_offs = ERRCONFIG_V1;
-               errconfig_mask = ERRCONFIG_STATUS_V1_MASK;
-       } else if (sr->ip_type == SR_TYPE_V2) {
-               errconfig_offs = ERRCONFIG_V2;
-               errconfig_mask = ERRCONFIG_VPBOUNDINTST_V2;
-       }
+       if (sr->ip_type == SR_TYPE_V1 && offset == ERRCONFIG_V1)
+               mask |= ERRCONFIG_STATUS_V1_MASK;
+       else if (sr->ip_type == SR_TYPE_V2 && offset == ERRCONFIG_V2)
+               mask |= ERRCONFIG_VPBOUNDINTST_V2;
+
+       reg_val = __raw_readl(sr->base + offset);
+       reg_val &= ~mask;
 
-       if (offset == errconfig_offs)
-               reg_val &= ~errconfig_mask;
+       value &= mask;
 
        reg_val |= value;
 
@@ -294,6 +289,8 @@ error:
 static void sr_v1_disable(struct omap_sr *sr)
 {
        int timeout = 0;
+       int errconf_val = ERRCONFIG_MCUACCUMINTST | ERRCONFIG_MCUVALIDINTST |
+                       ERRCONFIG_MCUBOUNDINTST;
 
        /* Enable MCUDisableAcknowledge interrupt */
        sr_modify_reg(sr, ERRCONFIG_V1,
@@ -302,13 +299,13 @@ static void sr_v1_disable(struct omap_sr *sr)
        /* SRCONFIG - disable SR */
        sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0x0);
 
-       /* Disable all other SR interrupts and clear the status */
+       /* Disable all other SR interrupts and clear the status as needed */
+       if (sr_read_reg(sr, ERRCONFIG_V1) & ERRCONFIG_VPBOUNDINTST_V1)
+               errconf_val |= ERRCONFIG_VPBOUNDINTST_V1;
        sr_modify_reg(sr, ERRCONFIG_V1,
                        (ERRCONFIG_MCUACCUMINTEN | ERRCONFIG_MCUVALIDINTEN |
                        ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_VPBOUNDINTEN_V1),
-                       (ERRCONFIG_MCUACCUMINTST | ERRCONFIG_MCUVALIDINTST |
-                       ERRCONFIG_MCUBOUNDINTST |
-                       ERRCONFIG_VPBOUNDINTST_V1));
+                       errconf_val);
 
        /*
         * Wait for SR to be disabled.
@@ -337,9 +334,17 @@ static void sr_v2_disable(struct omap_sr *sr)
        /* SRCONFIG - disable SR */
        sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0x0);
 
-       /* Disable all other SR interrupts and clear the status */
-       sr_modify_reg(sr, ERRCONFIG_V2, ERRCONFIG_VPBOUNDINTEN_V2,
+       /*
+        * Disable all other SR interrupts and clear the status
+        * write to status register ONLY on need basis - only if status
+        * is set.
+        */
+       if (sr_read_reg(sr, ERRCONFIG_V2) & ERRCONFIG_VPBOUNDINTST_V2)
+               sr_modify_reg(sr, ERRCONFIG_V2, ERRCONFIG_VPBOUNDINTEN_V2,
                        ERRCONFIG_VPBOUNDINTST_V2);
+       else
+               sr_modify_reg(sr, ERRCONFIG_V2, ERRCONFIG_VPBOUNDINTEN_V2,
+                               0x0);
        sr_write_reg(sr, IRQENABLE_CLR, (IRQENABLE_MCUACCUMINT |
                        IRQENABLE_MCUVALIDINT |
                        IRQENABLE_MCUBOUNDSINT));
@@ -447,8 +452,52 @@ int sr_configure_errgen(struct voltagedomain *voltdm)
                sr_errconfig);
 
        /* Enabling the interrupts if the ERROR module is used */
-       sr_modify_reg(sr, errconfig_offs,
-               vpboundint_en, (vpboundint_en | vpboundint_st));
+       sr_modify_reg(sr, errconfig_offs, (vpboundint_en | vpboundint_st),
+                     vpboundint_en);
+
+       return 0;
+}
+
+/**
+ * sr_disable_errgen() - Disables SmartReflex AVS module's errgen component
+ * @voltdm:    VDD pointer to which the SR module to be configured belongs to.
+ *
+ * This API is to be called from the smartreflex class driver to
+ * disable the error generator module inside the smartreflex module.
+ *
+ * Returns 0 on success and error value in case of failure.
+ */
+int sr_disable_errgen(struct voltagedomain *voltdm)
+{
+       u32 errconfig_offs, vpboundint_en;
+       u32 vpboundint_st;
+       struct omap_sr *sr = _sr_lookup(voltdm);
+
+       if (IS_ERR(sr)) {
+               pr_warning("%s: omap_sr struct for sr_%s not found\n",
+                       __func__, voltdm->name);
+               return -EINVAL;
+       }
+
+       if (sr->ip_type == SR_TYPE_V1) {
+               errconfig_offs = ERRCONFIG_V1;
+               vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V1;
+               vpboundint_st = ERRCONFIG_VPBOUNDINTST_V1;
+       } else if (sr->ip_type == SR_TYPE_V2) {
+               errconfig_offs = ERRCONFIG_V2;
+               vpboundint_en = ERRCONFIG_VPBOUNDINTEN_V2;
+               vpboundint_st = ERRCONFIG_VPBOUNDINTST_V2;
+       } else {
+               dev_err(&sr->pdev->dev, "%s: Trying to Configure smartreflex"
+                       "module without specifying the ip\n", __func__);
+               return -EINVAL;
+       }
+
+       /* Disable the interrupts of ERROR module */
+       sr_modify_reg(sr, errconfig_offs, vpboundint_en | vpboundint_st, 0);
+
+       /* Disable the Sensor and errorgen */
+       sr_modify_reg(sr, SRCONFIG, SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN, 0);
 
        return 0;
 }
@@ -897,7 +946,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
                ret = sr_late_init(sr_info);
                if (ret) {
                        pr_warning("%s: Error in SR late init\n", __func__);
-                       return ret;
+                       goto err_iounmap;
                }
        }
 
@@ -1011,8 +1060,32 @@ static int __devexit omap_sr_remove(struct platform_device *pdev)
        return 0;
 }
 
+static void __devexit omap_sr_shutdown(struct platform_device *pdev)
+{
+       struct omap_sr_data *pdata = pdev->dev.platform_data;
+       struct omap_sr *sr_info;
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "%s: platform data missing\n", __func__);
+               return;
+       }
+
+       sr_info = _sr_lookup(pdata->voltdm);
+       if (IS_ERR(sr_info)) {
+               dev_warn(&pdev->dev, "%s: omap_sr struct not found\n",
+                       __func__);
+               return;
+       }
+
+       if (sr_info->autocomp_active)
+               sr_stop_vddautocomp(sr_info);
+
+       return;
+}
+
 static struct platform_driver smartreflex_driver = {
-       .remove         = omap_sr_remove,
+       .remove         = __devexit_p(omap_sr_remove),
+       .shutdown       = __devexit_p(omap_sr_shutdown),
        .driver         = {
                .name   = "smartreflex",
        },