drivers: make tegra-throughput driver always post fps
[linux-2.6.git] / drivers / misc / nct1008.c
index a27d9c6..61cbdca 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;
@@ -93,6 +95,7 @@ struct nct1008_data {
        long current_hi_limit;
        int conv_period_ms;
        long etemp;
+       int shutdown_complete;
 
        struct thermal_zone_device *nct_int;
        struct thermal_zone_device *nct_ext;
@@ -101,30 +104,69 @@ struct nct1008_data {
 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;
 }
 
+static int nct1008_write_reg(struct i2c_client *client, u8 reg, u16 value)
+{
+       int ret = 0;
+       struct nct1008_data *data = i2c_get_clientdata(client);
+
+       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);
+
+       return ret;
+}
+
+static int nct1008_read_reg(struct i2c_client *client, u8 reg)
+{
+       int ret = 0;
+       struct nct1008_data *data = i2c_get_clientdata(client);
+       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);
+
+       return ret;
+}
+
 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;
 
        /* Read Local Temp */
        if (itemp) {
-               value = i2c_smbus_read_byte_data(client, LOCAL_TEMP_RD);
+               value = nct1008_read_reg(client, LOCAL_TEMP_RD);
                if (value < 0)
                        goto error;
                temp_local = value_to_temperature(pdata->ext_range, value);
@@ -135,12 +177,12 @@ static int nct1008_get_temp(struct device *dev, long *etemp, long *itemp)
 
        /* Read External Temp */
        if (etemp) {
-               value = i2c_smbus_read_byte_data(client, EXT_TEMP_RD_LO);
+               value = nct1008_read_reg(client, EXT_TEMP_RD_LO);
                if (value < 0)
                        goto error;
                temp_ext_lo = (value >> 6);
 
-               value = i2c_smbus_read_byte_data(client, EXT_TEMP_RD_HI);
+               value = nct1008_read_reg(client, EXT_TEMP_RD_HI);
                if (value < 0)
                        goto error;
                temp_ext_hi = value_to_temperature(pdata->ext_range, value);
@@ -163,24 +205,24 @@ 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;
 
        if (!dev || !buf || !attr)
                return -EINVAL;
 
-       value = i2c_smbus_read_byte_data(client, LOCAL_TEMP_RD);
+       value = nct1008_read_reg(client, LOCAL_TEMP_RD);
        if (value < 0)
                goto error;
        temp1 = value_to_temperature(pdata->ext_range, value);
 
-       value = i2c_smbus_read_byte_data(client, EXT_TEMP_RD_LO);
+       value = nct1008_read_reg(client, EXT_TEMP_RD_LO);
        if (value < 0)
                goto error;
        temp2 = (value >> 6);
-       value = i2c_smbus_read_byte_data(client, EXT_TEMP_RD_HI);
+       value = nct1008_read_reg(client, EXT_TEMP_RD_HI);
        if (value < 0)
                goto error;
        temp = value_to_temperature(pdata->ext_range, value);
@@ -200,16 +242,16 @@ 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 = i2c_smbus_read_byte_data(client, LOCAL_THERM_LIMIT_WR);
+       value = nct1008_read_reg(client, LOCAL_THERM_LIMIT_WR);
        if (value < 0)
                goto error;
        temp = value_to_temperature(pdata->ext_range, value);
 
        /* External temperature h/w shutdown limit */
-       value = i2c_smbus_read_byte_data(client, EXT_THERM_LIMIT_WR);
+       value = nct1008_read_reg(client, EXT_THERM_LIMIT_WR);
        if (value < 0)
                goto error;
        temp2 = value_to_temperature(pdata->ext_range, value);
@@ -262,14 +304,14 @@ 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);
-       err = i2c_smbus_write_byte_data(client, EXT_THERM_LIMIT_WR, temp);
+       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);
-       err = i2c_smbus_write_byte_data(client, LOCAL_THERM_LIMIT_WR, temp);
+       temp = temperature_to_value(pdata->ext_range, (s16)num);
+       err = nct1008_write_reg(client, LOCAL_THERM_LIMIT_WR, temp);
        if (err < 0)
                goto error;
        return count;
@@ -285,15 +327,15 @@ 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 = i2c_smbus_read_byte_data(client, EXT_TEMP_HI_LIMIT_HI_BYTE_RD);
+       value = nct1008_read_reg(client, EXT_TEMP_HI_LIMIT_HI_BYTE_RD);
        if (value < 0)
                goto error;
        temp_hi = value_to_temperature(pdata->ext_range, value);
 
        /* External Temperature Throttling lo-limit */
-       value = i2c_smbus_read_byte_data(client, EXT_TEMP_LO_LIMIT_HI_BYTE_RD);
+       value = nct1008_read_reg(client, EXT_TEMP_LO_LIMIT_HI_BYTE_RD);
        if (value < 0)
                goto error;
        temp_lo = value_to_temperature(pdata->ext_range, value);
@@ -326,15 +368,13 @@ static ssize_t nct1008_set_temp_alert(struct device *dev,
        }
 
        /* External Temperature Throttling limit */
-       value = temperature_to_value(pdata->ext_range, (s8)num);
-       err = i2c_smbus_write_byte_data(client, EXT_TEMP_HI_LIMIT_HI_BYTE_WR,
-               value);
+       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;
 
        /* Local Temperature Throttling limit */
-       err = i2c_smbus_write_byte_data(client, LOCAL_TEMP_HI_LIMIT_WR,
-               value);
+       err = nct1008_write_reg(client, LOCAL_TEMP_HI_LIMIT_WR, value);
        if (err < 0)
                goto error;
 
@@ -350,7 +390,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;
 
@@ -360,14 +400,14 @@ static ssize_t nct1008_show_ext_temp(struct device *dev,
        /* When reading the full external temperature value, read the
         * LSB first. This causes the MSB to be locked (that is, the
         * ADC does not write to it) until it is read */
-       data_lo = i2c_smbus_read_byte_data(client, EXT_TEMP_RD_LO);
+       data_lo = nct1008_read_reg(client, EXT_TEMP_RD_LO);
        if (data_lo < 0) {
                dev_err(&client->dev, "%s: failed to read "
                        "ext_temperature, i2c error=%d\n", __func__, data_lo);
                goto error;
        }
 
-       data = i2c_smbus_read_byte_data(client, EXT_TEMP_RD_HI);
+       data = nct1008_read_reg(client, EXT_TEMP_RD_HI);
        if (data < 0) {
                dev_err(&client->dev, "%s: failed to read "
                        "ext_temperature, i2c error=%d\n", __func__, data);
@@ -417,7 +457,7 @@ static int nct1008_thermal_set_limits(struct nct1008_data *data,
        if (data->current_lo_limit != lo_limit) {
                value = temperature_to_value(extended_range, lo_limit);
                pr_debug("%s: set lo_limit %ld\n", __func__, lo_limit);
-               err = i2c_smbus_write_byte_data(data->client,
+               err = nct1008_write_reg(data->client,
                                EXT_TEMP_LO_LIMIT_HI_BYTE_WR, value);
                if (err)
                        return err;
@@ -428,7 +468,7 @@ static int nct1008_thermal_set_limits(struct nct1008_data *data,
        if (data->current_hi_limit != hi_limit) {
                value = temperature_to_value(extended_range, hi_limit);
                pr_debug("%s: set hi_limit %ld\n", __func__, hi_limit);
-               err = i2c_smbus_write_byte_data(data->client,
+               err = nct1008_write_reg(data->client,
                                EXT_TEMP_HI_LIMIT_HI_BYTE_WR, value);
                if (err)
                        return err;
@@ -443,29 +483,34 @@ 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;
 
        if (!thz)
                return;
 
-       if (!thz->passive)
-               thermal_zone_device_update(thz);
+       thermal_zone_device_update(thz);
 
        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;
                }
        }
@@ -480,18 +525,18 @@ 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;
 
        /* Read External Temp */
-       value = i2c_smbus_read_byte_data(client, EXT_TEMP_RD_LO);
+       value = nct1008_read_reg(client, EXT_TEMP_RD_LO);
        if (value < 0)
                return -1;
        temp_ext_lo = (value >> 6);
 
-       value = i2c_smbus_read_byte_data(client, EXT_TEMP_RD_HI);
+       value = nct1008_read_reg(client, EXT_TEMP_RD_HI);
        if (value < 0)
                return -1;
        temp_ext_hi = value_to_temperature(pdata->ext_range, value);
@@ -514,8 +559,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;
                }
        }
@@ -544,8 +589,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;
 }
 
@@ -575,7 +633,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];
 
@@ -603,12 +661,12 @@ 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;
 
        /* Read Local Temp */
-       value = i2c_smbus_read_byte_data(client, LOCAL_TEMP_RD);
+       value = nct1008_read_reg(client, LOCAL_TEMP_RD);
        if (value < 0)
                return -1;
        temp_local = value_to_temperature(pdata->ext_range, value);
@@ -671,8 +729,7 @@ static void print_reg(const char *reg_name, struct seq_file *s,
        struct nct1008_data *nct_data = s->private;
        int ret;
 
-       ret = i2c_smbus_read_byte_data(nct_data->client,
-               offset);
+       ret = nct1008_read_reg(nct_data->client, offset);
        if (ret >= 0)
                seq_printf(s, "Reg %s Addr = 0x%02x Reg 0x%02x "
                "Value 0x%02x\n", reg_name,
@@ -758,7 +815,7 @@ static int nct1008_enable(struct i2c_client *client)
        struct nct1008_data *data = i2c_get_clientdata(client);
        int err;
 
-       err = i2c_smbus_write_byte_data(client, CONFIG_WR, data->config);
+       err = nct1008_write_reg(client, CONFIG_WR, data->config);
        if (err < 0)
                dev_err(&client->dev, "%s, line=%d, i2c write error=%d\n",
                __func__, __LINE__, err);
@@ -770,8 +827,8 @@ static int nct1008_disable(struct i2c_client *client)
        struct nct1008_data *data = i2c_get_clientdata(client);
        int err;
 
-       err = i2c_smbus_write_byte_data(client, CONFIG_WR,
-                                       data->config | STANDBY_BIT);
+       err = nct1008_write_reg(client, CONFIG_WR,
+                               data->config | STANDBY_BIT);
        if (err < 0)
                dev_err(&client->dev, "%s, line=%d, i2c write error=%d\n",
                __func__, __LINE__, err);
@@ -782,7 +839,9 @@ static int nct1008_within_limits(struct nct1008_data *data)
 {
        int intr_status;
 
-       intr_status = i2c_smbus_read_byte_data(data->client, STATUS_RD);
+       intr_status = nct1008_read_reg(data->client, STATUS_RD);
+       if (intr_status < 0)
+               return intr_status;
 
        return !(intr_status & (BIT(3) | BIT(4)));
 }
@@ -791,22 +850,24 @@ static void nct1008_work_func(struct work_struct *work)
 {
        struct nct1008_data *data = container_of(work, struct nct1008_data,
                                                work);
-       int intr_status;
+       int err;
        struct timespec ts;
 
-       nct1008_disable(data->client);
+       err = nct1008_disable(data->client);
+       if (err == -ENODEV)
+               return;
 
        if (!nct1008_within_limits(data))
                nct1008_update(data);
 
        /* Initiate one-shot conversion */
-       i2c_smbus_write_byte_data(data->client, ONE_SHOT, 0x1);
+       nct1008_write_reg(data->client, ONE_SHOT, 0x1);
 
        /* Give hardware necessary time to finish conversion */
        ts = ns_to_timespec(MAX_CONV_TIME_ONESHOT_MS * 1000 * 1000);
        hrtimer_nanosleep(&ts, NULL, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
 
-       intr_status = i2c_smbus_read_byte_data(data->client, STATUS_RD);
+       nct1008_read_reg(data->client, STATUS_RD);
 
        nct1008_enable(data->client);
 
@@ -843,7 +904,7 @@ 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);
        }
@@ -864,7 +925,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;
 
@@ -872,21 +933,21 @@ static int nct1008_configure_sensor(struct nct1008_data *data)
                return -ENODEV;
 
        /* Initially place in Standby */
-       err = i2c_smbus_write_byte_data(client, CONFIG_WR, STANDBY_BIT);
+       err = nct1008_write_reg(client, CONFIG_WR, STANDBY_BIT);
        if (err)
                goto error;
 
        /* External temperature h/w shutdown limit */
        value = temperature_to_value(pdata->ext_range,
                                        pdata->shutdown_ext_limit);
-       err = i2c_smbus_write_byte_data(client, EXT_THERM_LIMIT_WR, value);
+       err = nct1008_write_reg(client, EXT_THERM_LIMIT_WR, value);
        if (err)
                goto error;
 
        /* Local temperature h/w shutdown limit */
        value = temperature_to_value(pdata->ext_range,
                                        pdata->shutdown_local_limit);
-       err = i2c_smbus_write_byte_data(client, LOCAL_THERM_LIMIT_WR, value);
+       err = nct1008_write_reg(client, LOCAL_THERM_LIMIT_WR, value);
        if (err)
                goto error;
 
@@ -895,40 +956,38 @@ static int nct1008_configure_sensor(struct nct1008_data *data)
                data->config |= EXTENDED_RANGE_BIT;
        data->config &= ~(THERM2_BIT | ALERT_BIT);
 
-       err = i2c_smbus_write_byte_data(client, CONFIG_WR, data->config);
+       err = nct1008_write_reg(client, CONFIG_WR, data->config);
        if (err)
                goto error;
 
        /* Temperature conversion rate */
-       err = i2c_smbus_write_byte_data(client, CONV_RATE_WR, pdata->conv_rate);
+       err = nct1008_write_reg(client, CONV_RATE_WR, pdata->conv_rate);
        if (err)
                goto error;
 
        data->conv_period_ms = conv_period_ms_table[pdata->conv_rate];
 
        /* Setup local hi and lo limits */
-       err = i2c_smbus_write_byte_data(client,
+       err = nct1008_write_reg(client,
                LOCAL_TEMP_HI_LIMIT_WR, NCT1008_MAX_TEMP);
        if (err)
                goto error;
 
-       err = i2c_smbus_write_byte_data(client,
-               LOCAL_TEMP_LO_LIMIT_WR, 0);
+       err = nct1008_write_reg(client, LOCAL_TEMP_LO_LIMIT_WR, 0);
        if (err)
                goto error;
 
        /* Setup external hi and lo limits */
-       err = i2c_smbus_write_byte_data(client,
-               EXT_TEMP_LO_LIMIT_HI_BYTE_WR, 0);
+       err = nct1008_write_reg(client, EXT_TEMP_LO_LIMIT_HI_BYTE_WR, 0);
        if (err)
                goto error;
-       err = i2c_smbus_write_byte_data(client, EXT_TEMP_HI_LIMIT_HI_BYTE_WR,
+       err = nct1008_write_reg(client, EXT_TEMP_HI_LIMIT_HI_BYTE_WR,
                        NCT1008_MAX_TEMP);
        if (err)
                goto error;
 
        /* read initial temperature */
-       value = i2c_smbus_read_byte_data(client, LOCAL_TEMP_RD);
+       value = nct1008_read_reg(client, LOCAL_TEMP_RD);
        if (value < 0) {
                err = value;
                goto error;
@@ -936,13 +995,13 @@ static int nct1008_configure_sensor(struct nct1008_data *data)
        temp = value_to_temperature(pdata->ext_range, value);
        dev_dbg(&client->dev, "\n initial local temp = %d ", temp);
 
-       value = i2c_smbus_read_byte_data(client, EXT_TEMP_RD_LO);
+       value = nct1008_read_reg(client, EXT_TEMP_RD_LO);
        if (value < 0) {
                err = value;
                goto error;
        }
        temp2 = (value >> 6);
-       value = i2c_smbus_read_byte_data(client, EXT_TEMP_RD_HI);
+       value = nct1008_read_reg(client, EXT_TEMP_RD_HI);
        if (value < 0) {
                err = value;
                goto error;
@@ -956,16 +1015,31 @@ static int nct1008_configure_sensor(struct nct1008_data *data)
                dev_dbg(&client->dev, "\n initial ext temp = %d.0 deg", temp);
 
        /* Remote channel offset */
-       err = i2c_smbus_write_byte_data(client, OFFSET_WR, pdata->offset / 4);
+       err = nct1008_write_reg(client, OFFSET_WR, pdata->offset / 4);
        if (err < 0)
                goto error;
 
        /* Remote channel offset fraction (quarters) */
-       err = i2c_smbus_write_byte_data(client, OFFSET_QUARTER_WR,
+       err = nct1008_write_reg(client, OFFSET_QUARTER_WR,
                                        (pdata->offset % 4) << 6);
        if (err < 0)
                goto error;
 
+       /* Reset current hi/lo limit values with register values */
+       value = nct1008_read_reg(data->client, EXT_TEMP_LO_LIMIT_HI_BYTE_RD);
+       if (value < 0) {
+               err = value;
+               goto error;
+       }
+       data->current_lo_limit = value_to_temperature(pdata->ext_range, value);
+
+       value = nct1008_read_reg(data->client, EXT_TEMP_HI_LIMIT_HI_BYTE_RD);
+       if (value < 0) {
+               err = value;
+               goto error;
+       }
+       data->current_hi_limit = value_to_temperature(pdata->ext_range, value);
+
        return 0;
 error:
        dev_err(&client->dev, "\n exit %s, err=%d ", __func__, err);
@@ -1023,6 +1097,7 @@ 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);
        /* extended range recommended steps 1 through 4 taken care
@@ -1093,7 +1168,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)) {
@@ -1104,12 +1179,12 @@ 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);
+       mutex_destroy(&data->mutex);
        if (data->nct_reg)
                regulator_put(data->nct_reg);
        kfree(data);
@@ -1129,13 +1204,26 @@ 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;
 }
 
-#ifdef CONFIG_PM
+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_SLEEP
 static int nct1008_suspend(struct device *dev)
 {
        struct i2c_client *client = to_i2c_client(dev);
@@ -1185,14 +1273,14 @@ MODULE_DEVICE_TABLE(i2c, nct1008_id);
 static struct i2c_driver nct1008_driver = {
        .driver = {
                .name   = "nct1008_nct72",
-#ifdef CONFIG_PM
-               .pm     = &nct1008_pm_ops,
+#ifdef CONFIG_PM_SLEEP
+               .pm = &nct1008_pm_ops,
 #endif
        },
        .probe          = nct1008_probe,
        .remove         = __devexit_p(nct1008_remove),
        .id_table       = nct1008_id,
-
+       .shutdown       = nct1008_shutdown,
 };
 
 static int __init nct1008_init(void)