misc: Removed warnings from MAX1749 driver
[linux-2.6.git] / drivers / misc / nct1008.c
index 6ea6745..d8e8e6b 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Driver for NCT1008, temperature monitoring device from ON Semiconductors
  *
- * Copyright (c) 2010-2012, NVIDIA Corporation.
+ * Copyright (c) 2010-2013, NVIDIA CORPORATION. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -79,6 +79,8 @@
 #define CELSIUS_TO_MILLICELSIUS(x) ((x)*1000)
 #define MILLICELSIUS_TO_CELSIUS(x) ((x)/1000)
 
+#define POWER_ON_DELAY 20 /*ms*/
+
 struct nct1008_data {
        struct workqueue_struct *workqueue;
        struct work_struct work;
@@ -99,15 +101,22 @@ struct nct1008_data {
        struct thermal_zone_device *nct_ext;
 };
 
+static const struct i2c_device_id nct1008_id[] = {
+       { "nct1008", NCT1008 },
+       { "nct72", NCT72},
+       { "nct218", NCT218 },
+       {}
+};
+
 static int conv_period_ms_table[] =
        {16000, 8000, 4000, 2000, 1000, 500, 250, 125, 63, 32, 16};
 
-static inline s8 value_to_temperature(bool extended, u8 value)
+static inline s16 value_to_temperature(bool extended, u8 value)
 {
-       return extended ? (s8)(value - EXTENDED_RANGE_OFFSET) : (s8)value;
+       return extended ? (s16)(value - EXTENDED_RANGE_OFFSET) : (s16)value;
 }
 
-static inline u8 temperature_to_value(bool extended, s8 temp)
+static inline u8 temperature_to_value(bool extended, s16 temp)
 {
        return extended ? (u8)(temp + EXTENDED_RANGE_OFFSET) : (u8)temp;
 }
@@ -117,10 +126,14 @@ static int nct1008_write_reg(struct i2c_client *client, u8 reg, u16 value)
        int ret = 0;
        struct nct1008_data *data = i2c_get_clientdata(client);
 
-       if (data && data->shutdown_complete)
+       mutex_lock(&data->mutex);
+       if (data && data->shutdown_complete) {
+               mutex_unlock(&data->mutex);
                return -ENODEV;
+       }
 
        ret = i2c_smbus_write_byte_data(client, reg, value);
+       mutex_unlock(&data->mutex);
 
        if (ret < 0)
                dev_err(&client->dev, "%s: err %d\n", __func__, ret);
@@ -132,11 +145,14 @@ static int nct1008_read_reg(struct i2c_client *client, u8 reg)
 {
        int ret = 0;
        struct nct1008_data *data = i2c_get_clientdata(client);
-
-       if (data && data->shutdown_complete)
+       mutex_lock(&data->mutex);
+       if (data && data->shutdown_complete) {
+               mutex_unlock(&data->mutex);
                return -ENODEV;
+       }
 
        ret = i2c_smbus_read_byte_data(client, reg);
+       mutex_unlock(&data->mutex);
 
        if (ret < 0)
                dev_err(&client->dev, "%s: err %d\n", __func__, ret);
@@ -148,9 +164,9 @@ static int nct1008_get_temp(struct device *dev, long *etemp, long *itemp)
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct nct1008_platform_data *pdata = client->dev.platform_data;
-       s8 temp_local;
+       s16 temp_local;
        u8 temp_ext_lo;
-       s8 temp_ext_hi;
+       s16 temp_ext_hi;
        long temp_ext_milli;
        long temp_local_milli;
        u8 value;
@@ -196,8 +212,8 @@ static ssize_t nct1008_show_temp(struct device *dev,
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct nct1008_platform_data *pdata = client->dev.platform_data;
-       s8 temp1 = 0;
-       s8 temp = 0;
+       s16 temp1 = 0;
+       s16 temp = 0;
        u8 temp2 = 0;
        int value = 0;
 
@@ -233,7 +249,7 @@ static ssize_t nct1008_show_temp_overheat(struct device *dev,
        struct i2c_client *client = to_i2c_client(dev);
        struct nct1008_platform_data *pdata = client->dev.platform_data;
        int value;
-       s8 temp, temp2;
+       s16 temp, temp2;
 
        /* Local temperature h/w shutdown limit */
        value = nct1008_read_reg(client, LOCAL_THERM_LIMIT_WR);
@@ -295,13 +311,13 @@ static ssize_t nct1008_set_temp_overheat(struct device *dev,
        }
 
        /* External temperature h/w shutdown limit */
-       temp = temperature_to_value(pdata->ext_range, (s8)num);
+       temp = temperature_to_value(pdata->ext_range, (s16)num);
        err = nct1008_write_reg(client, EXT_THERM_LIMIT_WR, temp);
        if (err < 0)
                goto error;
 
        /* Local temperature h/w shutdown limit */
-       temp = temperature_to_value(pdata->ext_range, (s8)num);
+       temp = temperature_to_value(pdata->ext_range, (s16)num);
        err = nct1008_write_reg(client, LOCAL_THERM_LIMIT_WR, temp);
        if (err < 0)
                goto error;
@@ -318,7 +334,7 @@ static ssize_t nct1008_show_temp_alert(struct device *dev,
        struct i2c_client *client = to_i2c_client(dev);
        struct nct1008_platform_data *pdata = client->dev.platform_data;
        int value;
-       s8 temp_hi, temp_lo;
+       s16 temp_hi, temp_lo;
        /* External Temperature Throttling hi-limit */
        value = nct1008_read_reg(client, EXT_TEMP_HI_LIMIT_HI_BYTE_RD);
        if (value < 0)
@@ -359,7 +375,7 @@ static ssize_t nct1008_set_temp_alert(struct device *dev,
        }
 
        /* External Temperature Throttling limit */
-       value = temperature_to_value(pdata->ext_range, (s8)num);
+       value = temperature_to_value(pdata->ext_range, (s16)num);
        err = nct1008_write_reg(client, EXT_TEMP_HI_LIMIT_HI_BYTE_WR, value);
        if (err < 0)
                goto error;
@@ -381,7 +397,7 @@ static ssize_t nct1008_show_ext_temp(struct device *dev,
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct nct1008_platform_data *pdata = client->dev.platform_data;
-       s8 temp_value;
+       s16 temp_value;
        int data = 0;
        int data_lo;
 
@@ -474,7 +490,9 @@ static int nct1008_thermal_set_limits(struct nct1008_data *data,
 static void nct1008_update(struct nct1008_data *data)
 {
        struct thermal_zone_device *thz = data->nct_ext;
-       long temp, trip_temp, low_temp = 0, high_temp = NCT1008_MAX_TEMP * 1000;
+       long low_temp = 0, high_temp = NCT1008_MAX_TEMP * 1000;
+       struct thermal_trip_info *trip_state;
+       long temp, trip_temp, hysteresis_temp;
        int count;
        enum events type = 0;
 
@@ -486,16 +504,20 @@ static void nct1008_update(struct nct1008_data *data)
        thz->ops->get_temp(thz, &temp);
 
        for (count = 0; count < thz->trips; count++) {
-               thz->ops->get_trip_temp(thz, count, &trip_temp);
+               trip_state = &data->plat_data.trips[count];
+               trip_temp = trip_state->trip_temp;
+               hysteresis_temp = trip_temp - trip_state->hysteresis;
+               if ((trip_state->trip_type == THERMAL_TRIP_PASSIVE) &&
+                   !trip_state->tripped)
+                       hysteresis_temp = trip_temp;
 
                if ((trip_temp >= temp) && (trip_temp < high_temp)) {
                        high_temp = trip_temp;
                        type = THERMAL_AUX1;
                }
 
-               if ((trip_temp < temp) && (trip_temp > low_temp)) {
-                       low_temp = trip_temp -
-                                  data->plat_data.trips[count].hysteresis;
+               if ((hysteresis_temp < temp) && (hysteresis_temp > low_temp)) {
+                       low_temp = hysteresis_temp;
                        type = THERMAL_AUX0;
                }
        }
@@ -510,8 +532,8 @@ static int nct1008_ext_get_temp(struct thermal_zone_device *thz,
        struct nct1008_data *data = thz->devdata;
        struct i2c_client *client = data->client;
        struct nct1008_platform_data *pdata = client->dev.platform_data;
-       s8 temp_ext_hi;
-       s8 temp_ext_lo;
+       s16 temp_ext_hi;
+       s16 temp_ext_lo;
        long temp_ext_milli;
        u8 value;
 
@@ -544,8 +566,8 @@ static int nct1008_ext_bind(struct thermal_zone_device *thz,
        for (i = 0; i < data->plat_data.num_trips; i++) {
                if (!strcmp(data->plat_data.trips[i].cdev_type, cdev->type)) {
                        thermal_zone_bind_cooling_device(thz, i, cdev,
-                                       data->plat_data.trips[i].state,
-                                       data->plat_data.trips[i].state);
+                                       data->plat_data.trips[i].upper,
+                                       data->plat_data.trips[i].lower);
                        bind = true;
                }
        }
@@ -574,8 +596,21 @@ static int nct1008_ext_get_trip_temp(struct thermal_zone_device *thz,
                                     unsigned long *temp)
 {
        struct nct1008_data *data = thz->devdata;
+       struct thermal_trip_info *trip_state = &data->plat_data.trips[trip];
+
+       *temp = trip_state->trip_temp;
+
+       if (trip_state->trip_type != THERMAL_TRIP_PASSIVE)
+               return 0;
+
+       if (thz->temperature >= *temp) {
+               trip_state->tripped = true;
+       } else if (trip_state->tripped) {
+               *temp -= trip_state->hysteresis;
+               if (thz->temperature < *temp)
+                       trip_state->tripped = false;
+       }
 
-       *temp = data->plat_data.trips[trip].trip_temp;
        return 0;
 }
 
@@ -605,7 +640,7 @@ static int nct1008_ext_get_trend(struct thermal_zone_device *thz,
                                 enum thermal_trend *trend)
 {
        struct nct1008_data *data = thz->devdata;
-       struct nct_trip_temp *trip_state;
+       struct thermal_trip_info *trip_state;
 
        trip_state = &data->plat_data.trips[trip];
 
@@ -633,7 +668,7 @@ static int nct1008_int_get_temp(struct thermal_zone_device *thz,
        struct nct1008_data *data = thz->devdata;
        struct i2c_client *client = data->client;
        struct nct1008_platform_data *pdata = client->dev.platform_data;
-       s8 temp_local;
+       s16 temp_local;
        long temp_local_milli;
        u8 value;
 
@@ -714,7 +749,7 @@ static void print_reg(const char *reg_name, struct seq_file *s,
 
 static int dbg_nct1008_show(struct seq_file *s, void *unused)
 {
-       seq_printf(s, "nct1008 nct72 Registers\n");
+       seq_printf(s, "NCT Thermal Sensor Registers\n");
        seq_printf(s, "------------------\n");
        print_reg("Local Temp Value    ",     s, 0x00);
        print_reg("Ext Temp Value Hi   ",     s, 0x01);
@@ -753,12 +788,12 @@ static int nct1008_debuginit(struct nct1008_data *nct)
 {
        int err = 0;
        struct dentry *d;
-       if (nct->chip == NCT72)
-               d = debugfs_create_file("nct72", S_IRUGO, NULL,
-                               (void *)nct, &debug_fops);
-       else
-               d = debugfs_create_file("nct1008", S_IRUGO, NULL,
-                               (void *)nct, &debug_fops);
+       const char *name = nct1008_id[nct->chip].name;
+
+       /* create debugfs by selecting chipid */
+       d = debugfs_create_file(name, S_IRUGO, NULL,
+               (void *)nct, &debug_fops);
+
        if ((!d) || IS_ERR(d)) {
                dev_err(&nct->client->dev, "Error: %s debugfs_create_file"
                        " returned an error\n", __func__);
@@ -859,6 +894,8 @@ static irqreturn_t nct1008_irq(int irq, void *dev_id)
 static void nct1008_power_control(struct nct1008_data *data, bool is_enable)
 {
        int ret;
+       const char *name = nct1008_id[data->chip].name;
+
        if (!data->nct_reg) {
                data->nct_reg = regulator_get(&data->client->dev, "vdd");
                if (IS_ERR_OR_NULL(data->nct_reg)) {
@@ -876,20 +913,22 @@ static void nct1008_power_control(struct nct1008_data *data, bool is_enable)
        }
        if (is_enable) {
                ret = regulator_enable(data->nct_reg);
-               usleep_range(100, 1000);
+               msleep(POWER_ON_DELAY);
        } else {
                ret = regulator_disable(data->nct_reg);
        }
 
        if (ret < 0)
-               dev_err(&data->client->dev, "Error in %s rail vdd_nct%s, "
+               dev_err(&data->client->dev, "Error in %s rail vdd_%s, "
                        "error %d\n", (is_enable) ? "enabling" : "disabling",
-                       (data->chip == NCT72) ? "72" : "1008",
+                       name,
                        ret);
        else
                dev_info(&data->client->dev, "success in %s rail vdd_nct%s\n",
                        (is_enable) ? "enabling" : "disabling",
-                       (data->chip == NCT72) ? "72" : "1008");
+                       name);
+
+
 }
 
 static int nct1008_configure_sensor(struct nct1008_data *data)
@@ -897,7 +936,7 @@ static int nct1008_configure_sensor(struct nct1008_data *data)
        struct i2c_client *client = data->client;
        struct nct1008_platform_data *pdata = client->dev.platform_data;
        u8 value;
-       s8 temp;
+       s16 temp;
        u8 temp2;
        int err;
 
@@ -1020,8 +1059,9 @@ error:
 
 static int __devinit nct1008_configure_irq(struct nct1008_data *data)
 {
-       data->workqueue = create_singlethread_workqueue((data->chip == NCT72) \
-                                                       ? "nct72" : "nct1008");
+       const char *name = nct1008_id[data->chip].name;
+
+       data->workqueue = create_singlethread_workqueue(name);
 
        INIT_WORK(&data->work, nct1008_work_func);
 
@@ -1030,7 +1070,7 @@ static int __devinit nct1008_configure_irq(struct nct1008_data *data)
        else
                return request_irq(data->client->irq, nct1008_irq,
                        IRQF_TRIGGER_LOW,
-                       (data->chip == NCT72) ? "nct72" : "nct1008",
+                       name,
                        data);
 }
 
@@ -1069,8 +1109,14 @@ static int __devinit nct1008_probe(struct i2c_client *client,
        memcpy(&data->plat_data, client->dev.platform_data,
                sizeof(struct nct1008_platform_data));
        i2c_set_clientdata(client, data);
+       mutex_init(&data->mutex);
 
        nct1008_power_control(data, true);
+       if (!data->nct_reg) {
+               /* power up failure */
+               err = -EIO;
+               goto cleanup;
+       }
        /* extended range recommended steps 1 through 4 taken care
         * in nct1008_configure_sensor function */
        err = nct1008_configure_sensor(data);   /* sensor is in standby */
@@ -1112,15 +1158,15 @@ static int __devinit nct1008_probe(struct i2c_client *client,
                mask |= (1 << i);
 
        if (data->plat_data.loc_name) {
-               strcpy(nct_int_name, "nct_int_");
-               strcpy(nct_ext_name, "nct_ext_");
+               strcpy(nct_int_name, "Tboard_");
+               strcpy(nct_ext_name, "Tdiode_");
                strncat(nct_int_name, data->plat_data.loc_name,
-                       (THERMAL_NAME_LENGTH - strlen("nct_int_")) - 1);
+                       (THERMAL_NAME_LENGTH - strlen("Tboard_")) - 1);
                strncat(nct_ext_name, data->plat_data.loc_name,
-                       (THERMAL_NAME_LENGTH - strlen("nct_ext_")) - 1);
+                       (THERMAL_NAME_LENGTH - strlen("Tdiode_")) - 1);
        } else {
-               strcpy(nct_int_name, "nct_int");
-               strcpy(nct_ext_name, "nct_ext");
+               strcpy(nct_int_name, "Tboard");
+               strcpy(nct_ext_name, "Tdiode");
        }
 
        data->nct_int = thermal_zone_device_register(nct_int_name,
@@ -1139,7 +1185,7 @@ static int __devinit nct1008_probe(struct i2c_client *client,
                                        mask,
                                        data,
                                        &nct_ext_ops,
-                                       NULL,
+                                       data->plat_data.tzp,
                                        data->plat_data.passive_delay,
                                        0);
        if (IS_ERR_OR_NULL(data->nct_ext)) {
@@ -1150,12 +1196,13 @@ static int __devinit nct1008_probe(struct i2c_client *client,
 
        nct1008_update(data);
 #endif
-
        return 0;
 
 error:
        dev_err(&client->dev, "\n exit %s, err=%d ", __func__, err);
        nct1008_power_control(data, false);
+cleanup:
+       mutex_destroy(&data->mutex);
        if (data->nct_reg)
                regulator_put(data->nct_reg);
        kfree(data);
@@ -1175,7 +1222,7 @@ static int __devexit nct1008_remove(struct i2c_client *client)
        nct1008_power_control(data, false);
        if (data->nct_reg)
                regulator_put(data->nct_reg);
-
+       mutex_destroy(&data->mutex);
        kfree(data);
 
        return 0;
@@ -1184,17 +1231,18 @@ static int __devexit nct1008_remove(struct i2c_client *client)
 static void nct1008_shutdown(struct i2c_client *client)
 {
        struct nct1008_data *data = i2c_get_clientdata(client);
-
        if (client->irq)
                disable_irq(client->irq);
 
        cancel_work_sync(&data->work);
 
+       mutex_lock(&data->mutex);
        data->shutdown_complete = 1;
+       mutex_unlock(&data->mutex);
 }
 
-#ifdef CONFIG_PM
-static int nct1008_suspend(struct device *dev)
+#ifdef CONFIG_PM_SLEEP
+static int nct1008_suspend_powerdown(struct device *dev)
 {
        struct i2c_client *client = to_i2c_client(dev);
        int err;
@@ -1206,11 +1254,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);
@@ -1220,6 +1340,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);
 
@@ -1233,16 +1372,14 @@ static const struct dev_pm_ops nct1008_pm_ops = {
 
 #endif
 
-static const struct i2c_device_id nct1008_id[] = {
-       { "nct1008", NCT1008 },
-       { "nct72", NCT72},
-       {}
-};
 MODULE_DEVICE_TABLE(i2c, nct1008_id);
 
 static struct i2c_driver nct1008_driver = {
        .driver = {
-               .name   = "nct1008_nct72",
+               .name   = "nct_thermal",
+#ifdef CONFIG_PM_SLEEP
+               .pm = &nct1008_pm_ops,
+#endif
        },
        .probe          = nct1008_probe,
        .remove         = __devexit_p(nct1008_remove),