diff options
author | Joshua Primero <jprimero@nvidia.com> | 2011-09-16 11:49:05 -0700 |
---|---|---|
committer | Rohan Somvanshi <rsomvanshi@nvidia.com> | 2011-09-21 00:00:32 -0700 |
commit | 8ccc1756061c64a0fe113eddef2e3945a09e8795 (patch) | |
tree | 53c5a50ea3ea4babeb27c156c9fd2ac5ca0e906a | |
parent | 21e30b0910d6ee38eb7f1e68e21507a80758c74d (diff) |
arm: tegra: power: Improved thermal accuracy
Instead of rounding up when measuring temperature in celsius,
report back temperature in millicelsius.
Change-Id: I5b99dd9f1c41e929d83a42662d693fe31a779a52
Reviewed-on: http://git-master/r/52953
Reviewed-by: Joshua Primero <jprimero@nvidia.com>
Tested-by: Joshua Primero <jprimero@nvidia.com>
Reviewed-by: Diwakar Tundlam <dtundlam@nvidia.com>
-rw-r--r-- | drivers/misc/nct1008.c | 89 |
1 files changed, 52 insertions, 37 deletions
diff --git a/drivers/misc/nct1008.c b/drivers/misc/nct1008.c index d8323d7b1e67..7ba70c35021b 100644 --- a/drivers/misc/nct1008.c +++ b/drivers/misc/nct1008.c @@ -75,6 +75,9 @@ #define MAX_STR_PRINT 50 +#define CELSIUS_TO_MILLICELSIUS(x) ((x)*1000) +#define MILLICELSIUS_TO_CELSIUS(x) ((x)/1000) + struct nct1008_data { struct work_struct work; struct i2c_client *client; @@ -97,33 +100,41 @@ static inline u8 temperature_to_value(bool extended, s8 temp) return extended ? (u8)(temp + EXTENDED_RANGE_OFFSET) : (u8)temp; } -static int nct1008_get_temp(struct device *dev, u8 *pTemp) +static int nct1008_get_temp(struct device *dev, long *pTemp) { struct i2c_client *client = to_i2c_client(dev); struct nct1008_platform_data *pdata = client->dev.platform_data; - s8 temp1; - u8 temp2; - s8 temp; - int value; + s8 temp_local; + u8 temp_ext_lo; + s8 temp_ext_hi; + long temp_ext_milli; + long temp_local_milli; + u8 value; + + /* Read Local Temp */ value = i2c_smbus_read_byte_data(client, LOCAL_TEMP_RD); if (value < 0) goto error; - temp1 = value_to_temperature(pdata->ext_range, value); + temp_local = value_to_temperature(pdata->ext_range, value); + temp_local_milli = CELSIUS_TO_MILLICELSIUS(temp_local); + /* Read External Temp */ value = i2c_smbus_read_byte_data(client, EXT_TEMP_RD_LO); if (value < 0) goto error; - temp2 = (value >> 6); + temp_ext_lo = (value >> 6); + value = i2c_smbus_read_byte_data(client, EXT_TEMP_RD_HI); if (value < 0) goto error; - temp = value_to_temperature(pdata->ext_range, value); - if (temp2 > 0) - *pTemp = max((int)temp1, (int)temp + 1); - else - *pTemp = max(temp1, temp); + temp_ext_hi = value_to_temperature(pdata->ext_range, value); + + temp_ext_milli = CELSIUS_TO_MILLICELSIUS(temp_ext_hi) + temp_ext_lo * 250; - dev_dbg(dev, "\n %s: ret temp=%dC ", __func__, *pTemp); + /* Return max between Local and External Temp */ + *pTemp = max(temp_local_milli, temp_ext_milli); + + dev_dbg(dev, "\n %s: ret temp=%ldC ", __func__, *pTemp); return 0; error: dev_err(&client->dev, "\n error in file=: %s %s() line=%d: " @@ -201,7 +212,7 @@ static ssize_t nct1008_set_temp_overheat(struct device *dev, long int num; int err; u8 temp; - u8 currTemp; + long currTemp; struct i2c_client *client = to_i2c_client(dev); struct nct1008_platform_data *pdata = client->dev.platform_data; char bufTemp[MAX_STR_PRINT]; @@ -223,12 +234,14 @@ static ssize_t nct1008_set_temp_overheat(struct device *dev, if (err) goto error; + currTemp = MILLICELSIUS_TO_CELSIUS(currTemp); + if (currTemp >= (int)num) { ret = nct1008_show_temp(dev, attr, bufTemp); ret = nct1008_show_temp_overheat(dev, attr, bufOverheat); dev_err(dev, "\nCurrent temp: %s ", bufTemp); dev_err(dev, "\nOld overheat limit: %s ", bufOverheat); - dev_err(dev, "\nReset from overheat: curr temp=%d, " + dev_err(dev, "\nReset from overheat: curr temp=%ld, " "new overheat temp=%d\n\n", currTemp, (int)num); } @@ -537,30 +550,31 @@ static void nct1008_work_func(struct work_struct *work) struct nct1008_data *data = container_of(work, struct nct1008_data, work); bool extended_range = data->plat_data.ext_range; - u8 temperature, value; + long temp_milli; + u8 value; int err = 0, i; int hysteresis; int nentries = data->limits_sz; int lo_limit = 0, hi_limit = 0; - int intr_status; + long throttling_ext_limit_milli; + int intr_status = i2c_smbus_read_byte_data(data->client, STATUS_RD); - intr_status = i2c_smbus_read_byte_data(data->client, STATUS_RD); if (intr_status < 0) { pr_err("%s, line=%d, i2c read error=%d\n", __func__, __LINE__, intr_status); return; } - err = nct1008_get_temp(&data->client->dev, &temperature); + intr_status &= (BIT(3) | BIT(4)); + if (!intr_status) + return; + + err = nct1008_get_temp(&data->client->dev, &temp_milli); if (err) { pr_err("%s: get temp fail(%d)", __func__, err); return; } - intr_status &= (BIT(3) | BIT(4)); - if (!intr_status) - return; - err = nct1008_disable_alert(data); if (err) { pr_err("%s: disable alert fail(error=%d)\n", @@ -568,30 +582,31 @@ static void nct1008_work_func(struct work_struct *work) return; } - hysteresis = ALERT_HYSTERESIS_EDP; + throttling_ext_limit_milli = + CELSIUS_TO_MILLICELSIUS(data->plat_data.throttling_ext_limit); - if (temperature >= data->plat_data.throttling_ext_limit) { + if (temp_milli >= throttling_ext_limit_milli) { /* start throttling */ therm_throttle(data, true); hysteresis = ALERT_HYSTERESIS_THROTTLE; - } else if (temperature <= - (data->plat_data.throttling_ext_limit - + } else if (temp_milli <= + (throttling_ext_limit_milli - ALERT_HYSTERESIS_THROTTLE)) { /* switch off throttling */ therm_throttle(data, false); } - if (temperature < data->limits[0]) { + if (temp_milli < CELSIUS_TO_MILLICELSIUS(data->limits[0])) { lo_limit = 0; hi_limit = data->limits[0]; - } else if (temperature >= data->limits[nentries-1]) { + } else if (temp_milli >= CELSIUS_TO_MILLICELSIUS(data->limits[nentries-1])) { lo_limit = data->limits[nentries-1] - hysteresis; hi_limit = data->plat_data.shutdown_ext_limit; } else { for (i = 0; (i + 1) < nentries; i++) { - if (temperature >= data->limits[i] && - temperature < data->limits[i + 1]) { + if (temp_milli >= CELSIUS_TO_MILLICELSIUS(data->limits[i]) && + temp_milli < CELSIUS_TO_MILLICELSIUS(data->limits[i + 1])) { lo_limit = data->limits[i] - hysteresis; hi_limit = data->limits[i + 1]; break; @@ -630,14 +645,14 @@ static void nct1008_work_func(struct work_struct *work) } /* inform edp governor */ - if (edp_thermal_zone_val != temperature) + if (edp_thermal_zone_val != temp_milli) /* * FIXME: Move this direct tegra_ function call to be called * via a pointer in 'struct nct1008_data' (like 'alarm_fn') */ - tegra_edp_update_thermal_zone(temperature); + tegra_edp_update_thermal_zone(MILLICELSIUS_TO_CELSIUS(temp_milli)); - edp_thermal_zone_val = temperature; + edp_thermal_zone_val = temp_milli; out: nct1008_enable_alert(data); @@ -874,7 +889,7 @@ static int __devinit nct1008_probe(struct i2c_client *client, { struct nct1008_data *data; int err; - u8 temperature; + long temp_milli; unsigned int delay; data = kzalloc(sizeof(struct nct1008_data), GFP_KERNEL); @@ -919,13 +934,13 @@ static int __devinit nct1008_probe(struct i2c_client *client, data->plat_data.conv_rate); msleep(delay); /* 63msec for default conv rate 0x8 */ } - err = nct1008_get_temp(&data->client->dev, &temperature); + err = nct1008_get_temp(&data->client->dev, &temp_milli); if (err) { pr_err("%s: get temp fail(%d)", __func__, err); return 0; /*do not fail init on the 1st read */ } - tegra_edp_update_thermal_zone(temperature); + tegra_edp_update_thermal_zone(MILLICELSIUS_TO_CELSIUS(temp_milli)); return 0; error: |