misc: nct1008: Add new suspend mode for Tegra LP1
Daniel Solomon [Thu, 4 Apr 2013 00:53:12 +0000 (17:53 -0700)]
For Tegra devices, it is desirable to keep the NCT1008/72
device awake during some suspend states.

Add new "suspend mode" to support this feature, if
CONFIG_TEGRA_LP1_LOW_COREVOLTAGE is set. Required
parameters are passed in through board file data.

Bug 1261915

Change-Id: Ibae7e6a661d817c0cc514373b934665d68d063b7
Signed-off-by: Daniel Solomon <daniels@nvidia.com>
Reviewed-on: http://git-master/r/216368
Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>

drivers/misc/nct1008.c

index 61cbdca..9bc60c8 100644 (file)
@@ -1224,7 +1224,7 @@ static void nct1008_shutdown(struct i2c_client *client)
 }
 
 #ifdef CONFIG_PM_SLEEP
-static int nct1008_suspend(struct device *dev)
+static int nct1008_suspend_powerdown(struct device *dev)
 {
        struct i2c_client *client = to_i2c_client(dev);
        int err;
@@ -1236,11 +1236,83 @@ static int nct1008_suspend(struct device *dev)
        return err;
 }
 
-static int nct1008_resume(struct device *dev)
+static int nct1008_suspend_wakeup(struct device *dev)
 {
        struct i2c_client *client = to_i2c_client(dev);
        int err;
        struct nct1008_data *data = i2c_get_clientdata(client);
+       long ext_temp;
+
+       err = nct1008_get_temp(dev, &ext_temp, 0);
+       if (err)
+               goto error;
+
+       if (ext_temp > data->plat_data.suspend_ext_limit_lo)
+               err = nct1008_thermal_set_limits(data,
+                       data->plat_data.suspend_ext_limit_lo,
+                       NCT1008_MAX_TEMP * 1000);
+       else
+               err = nct1008_thermal_set_limits(data,
+                       NCT1008_MIN_TEMP * 1000,
+                       data->plat_data.suspend_ext_limit_hi);
+
+       if (err)
+               goto error;
+
+       /* Enable NCT wake */
+       err = enable_irq_wake(client->irq);
+       if (err)
+               dev_err(&client->dev, "Error: %s, error=%d. failed to enable NCT "
+                               "wakeup\n", __func__, err);
+
+
+       return err;
+
+error:
+       dev_err(&client->dev, "\n error in file=: %s %s() line=%d: "
+               "error=%d. Can't set correct LP1 alarm limits or set wakeup irq, "
+               "shutting down device", __FILE__, __func__, __LINE__, err);
+
+       return nct1008_suspend_powerdown(dev);
+}
+
+static int nct1008_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct nct1008_data *data = i2c_get_clientdata(client);
+
+       if (data->plat_data.suspend_with_wakeup &&
+               data->plat_data.suspend_with_wakeup())
+               return nct1008_suspend_wakeup(dev);
+       else
+               return nct1008_suspend_powerdown(dev);
+}
+
+
+static int nct1008_resume_wakeup(struct device *dev)
+{
+       int err = 0;
+       struct i2c_client *client = to_i2c_client(dev);
+
+       err = disable_irq_wake(client->irq);
+       if (err) {
+               dev_err(&client->dev, "Error: %s, error=%d. failed to disable NCT "
+                               "wakeup\n", __func__, err);
+               return err;
+       }
+
+       /* NCT wasn't powered down, so IRQ is still enabled. */
+       /* Disable it before calling update */
+       disable_irq(client->irq);
+
+       return err;
+}
+
+static int nct1008_resume_powerdown(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       int err = 0;
+       struct nct1008_data *data = i2c_get_clientdata(client);
 
        nct1008_power_control(data, true);
        nct1008_configure_sensor(data);
@@ -1250,6 +1322,25 @@ static int nct1008_resume(struct device *dev)
                        __func__, err);
                return err;
        }
+
+       return err;
+}
+
+static int nct1008_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       int err;
+       struct nct1008_data *data = i2c_get_clientdata(client);
+
+       if (data->plat_data.suspend_with_wakeup &&
+               data->plat_data.suspend_with_wakeup())
+               err = nct1008_resume_wakeup(dev);
+       else
+               err = nct1008_resume_powerdown(dev);
+
+       if (err)
+               return err;
+
        nct1008_update(data);
        enable_irq(client->irq);