summaryrefslogtreecommitdiff
path: root/drivers/misc
diff options
context:
space:
mode:
authorDan Willemsen <dwillemsen@nvidia.com>2011-03-31 21:46:58 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2011-04-26 15:51:32 -0700
commit1740660b11191345c9b0b50cbde553e65562545e (patch)
tree17a30df5fc0e92e1b57b123062838adf6d351fa6 /drivers/misc
parentac223361e2b12c486a24485e8940943e845c5ece (diff)
misc: nct1008: sysfs interface for THERM setting
Enabling external temperature sensor for honeycomb t30 - added sysfs interface in external temperature sensor - Set THERM threshold for nct1008 external temperature sensor as 75 degree celsius - hysteresis of 5 deg celsius selected to prevent system going in and out of reset for threshold temperatures. Bug 789904 Original-Change-Id: I305a05bc57ae485334ccf2dc1bde3d6afd4fceae Reviewed-on: http://git-master/r/18894 Reviewed-by: Bitan Biswas <bbiswas@nvidia.com> Tested-by: Bitan Biswas <bbiswas@nvidia.com> Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com> Change-Id: I2b0c97ecef1a11282e92d4d8f3e64b3633bb362e
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/nct1008.c378
1 files changed, 336 insertions, 42 deletions
diff --git a/drivers/misc/nct1008.c b/drivers/misc/nct1008.c
index 6bdad35f3796..dd4a89149c91 100644
--- a/drivers/misc/nct1008.c
+++ b/drivers/misc/nct1008.c
@@ -28,6 +28,7 @@
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/gpio.h>
+#include <linux/device.h>
#include <linux/nct1008.h>
@@ -35,15 +36,20 @@
/* Register Addresses */
#define LOCAL_TEMP_RD 0x00
-#define EXT_HI_TEMP_RD 0x01
-#define EXT_LO_TEMP_RD 0x10
+#define EXT_TEMP_RD_HI 0x01
+#define EXT_TEMP_RD_LO 0x10
#define STATUS_RD 0x02
#define CONFIG_RD 0x03
+#define LOCAL_TEMP_HI_LIMIT_RD 0x05
+
+#define EXT_TEMP_HI_LIMIT_HI_BYTE_RD 0x07
+
#define CONFIG_WR 0x09
#define CONV_RATE_WR 0x0A
#define LOCAL_TEMP_HI_LIMIT_WR 0x0B
-#define EXT_TEMP_HI_LIMIT_HI_BYTE 0x0D
+#define EXT_TEMP_HI_LIMIT_HI_BYTE_WR 0x0D
+#define EXT_TEMP_RD_LOW 0x10
#define OFFSET_WR 0x11
#define EXT_THERM_LIMIT_WR 0x19
#define LOCAL_THERM_LIMIT_WR 0x20
@@ -59,33 +65,263 @@
#define STANDARD_RANGE_MAX 127U
#define EXTENDED_RANGE_MAX (150U + EXTENDED_RANGE_OFFSET)
+#define NCT1008_MIN_TEMP -64
+#define NCT1008_MAX_TEMP 191
+
+#define MAX_STR_PRINT 50
+
struct nct1008_data {
struct work_struct work;
struct i2c_client *client;
+ struct nct1008_platform_data plat_data;
struct mutex mutex;
u8 config;
void (*alarm_fn)(bool raised);
};
+static inline u8 value_to_temperature(bool extended, u8 value)
+{
+ return extended ? (u8)(value - EXTENDED_RANGE_OFFSET) : value;
+}
+
+static inline u8 temperature_to_value(bool extended, u8 temp)
+{
+ return extended ? (u8)(temp + EXTENDED_RANGE_OFFSET) : temp;
+}
+
+static int nct1008_get_temp(struct device *dev, u8 *pTemp)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct nct1008_platform_data *pdata = client->dev.platform_data;
+ u8 temp1, temp2, temp;
+ u8 value;
+ value = i2c_smbus_read_byte_data(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_LOW);
+ if (value < 0)
+ goto error;
+ temp2 = (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) {
+ if (temp1 > (temp + 1))
+ *pTemp = temp1;
+ else
+ *pTemp = (temp + 1);
+ } else {
+ if (temp1 > temp)
+ *pTemp = temp1;
+ else
+ *pTemp = temp;
+ }
+ return 0;
+error:
+ dev_err(&client->dev, "\n error in file=: %s %s() line=%d: "
+ "error=%d ", __FILE__, __func__, __LINE__, value);
+ return value;
+}
+
static ssize_t nct1008_show_temp(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
- signed int temp_value = 0;
- u8 data = 0;
+ struct nct1008_platform_data *pdata = client->dev.platform_data;
+ u8 temp1 = 0;
+ u8 temp = 0;
+ u8 temp2 = 0;
+ u8 value;
if (!dev || !buf || !attr)
return -EINVAL;
- data = i2c_smbus_read_byte_data(client, LOCAL_TEMP_RD);
- if (data < 0) {
- dev_err(&client->dev, "%s: failed to read "
- "temperature\n", __func__);
+ value = i2c_smbus_read_byte_data(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_LOW);
+ if (value < 0)
+ goto error;
+ temp2 = (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) {
+ if (temp2 == 1)
+ return snprintf(buf, MAX_STR_PRINT, "%d %d.25\n",
+ temp1, temp);
+ else if (temp2 == 2)
+ return snprintf(buf, MAX_STR_PRINT, "%d %d.5\n",
+ temp1, temp);
+ else if (temp2 == 3)
+ return snprintf(buf, MAX_STR_PRINT, "%d %d.75\n",
+ temp1, temp);
+ } else {
+ return snprintf(buf, MAX_STR_PRINT, "%d %d.0\n",
+ temp1, temp);
+ }
+error:
+ snprintf(buf, MAX_STR_PRINT, " Rd Error\n");
+ return value;
+}
+
+static ssize_t nct1008_show_temp_overheat(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct nct1008_platform_data *pdata = client->dev.platform_data;
+ u8 value;
+ u8 temp, temp2;
+
+ /* Local temperature h/w shutdown limit */
+ value = i2c_smbus_read_byte_data(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);
+ if (value < 0)
+ goto error;
+ temp2 = value_to_temperature(pdata->ext_range, value);
+
+ return snprintf(buf, MAX_STR_PRINT, "%d %d\n", temp, temp2);
+error:
+ snprintf(buf, MAX_STR_PRINT, " Rd overheat Error\n");
+ dev_err(dev, "%s: failed to read temperature-overheat "
+ "\n", __func__);
+ return value;
+}
+
+static ssize_t nct1008_set_temp_overheat(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ long int num;
+ int err;
+ u8 temp;
+ u8 currTemp;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct nct1008_platform_data *pdata = client->dev.platform_data;
+ char bufTemp[MAX_STR_PRINT];
+ char bufOverheat[MAX_STR_PRINT];
+ unsigned int ret;
+
+ if (strict_strtoul(buf, 0, &num)) {
+ dev_err(dev, "\n file: %s, line=%d return %s() ", __FILE__,
+ __LINE__, __func__);
return -EINVAL;
}
+ if (((int)num < NCT1008_MIN_TEMP) || ((int)num >= NCT1008_MAX_TEMP)) {
+ dev_err(dev, "\n file: %s, line=%d return %s() ", __FILE__,
+ __LINE__, __func__);
+ return -EINVAL;
+ }
+ /* check for system power down */
+ err = nct1008_get_temp(dev, &currTemp);
+ if (err < 0)
+ goto error;
- temp_value = (signed int)data;
- return sprintf(buf, "%d\n", temp_value);
+ 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, "
+ "new overheat temp=%d\n\n", currTemp, (int)num);
+ }
+
+ /* External temperature h/w shutdown limit */
+ temp = temperature_to_value(pdata->ext_range, (u8)num);
+ err = i2c_smbus_write_byte_data(client, EXT_THERM_LIMIT_WR, temp);
+ if (err < 0)
+ goto error;
+
+ /* Local temperature h/w shutdown limit */
+ temp = temperature_to_value(pdata->ext_range, (u8)num);
+ err = i2c_smbus_write_byte_data(client, LOCAL_THERM_LIMIT_WR, temp);
+ if (err < 0)
+ goto error;
+ return count;
+error:
+ dev_err(dev, " %s: failed to set temperature-overheat\n", __func__);
+ return err;
+}
+
+static ssize_t nct1008_show_temp_alert(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct nct1008_platform_data *pdata = client->dev.platform_data;
+ u8 value;
+ u8 temp, temp2;
+ /* External Temperature Throttling limit */
+ value = i2c_smbus_read_byte_data(client, EXT_TEMP_HI_LIMIT_HI_BYTE_RD);
+ if (value < 0)
+ goto error;
+ temp2 = value_to_temperature(pdata->ext_range, value);
+
+ /* Local Temperature Throttling limit */
+ value = i2c_smbus_read_byte_data(client, LOCAL_TEMP_HI_LIMIT_RD);
+ if (value < 0)
+ goto error;
+ temp = value_to_temperature(pdata->ext_range, value);
+
+ return snprintf(buf, MAX_STR_PRINT, "%d %d\n", temp, temp2);
+error:
+ snprintf(buf, MAX_STR_PRINT, " Rd overheat Error\n");
+ dev_err(dev, "%s: failed to read temperature-overheat "
+ "\n", __func__);
+ return value;
+}
+
+static ssize_t nct1008_set_temp_alert(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ long int num;
+ int value;
+ int err;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct nct1008_platform_data *pdata = client->dev.platform_data;
+
+ if (strict_strtoul(buf, 0, &num)) {
+ dev_err(dev, "\n file: %s, line=%d return %s() ", __FILE__,
+ __LINE__, __func__);
+ return -EINVAL;
+ }
+ if (((int)num < NCT1008_MIN_TEMP) || ((int)num >= NCT1008_MAX_TEMP)) {
+ dev_err(dev, "\n file: %s, line=%d return %s() ", __FILE__,
+ __LINE__, __func__);
+ return -EINVAL;
+ }
+
+ /* External Temperature Throttling limit */
+ value = temperature_to_value(pdata->ext_range, num);
+ err = i2c_smbus_write_byte_data(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);
+ if (err < 0)
+ goto error;
+
+ return count;
+error:
+ dev_err(dev, "%s: failed to set temperature-alert "
+ "\n", __func__);
+ return err;
}
static ssize_t nct1008_show_ext_temp(struct device *dev,
@@ -98,7 +334,7 @@ static ssize_t nct1008_show_ext_temp(struct device *dev,
if (!dev || !buf || !attr)
return -EINVAL;
- data = i2c_smbus_read_byte_data(client, EXT_HI_TEMP_RD);
+ data = i2c_smbus_read_byte_data(client, EXT_TEMP_RD_HI);
if (data < 0) {
dev_err(&client->dev, "%s: failed to read "
"ext_temperature\n", __func__);
@@ -107,16 +343,22 @@ static ssize_t nct1008_show_ext_temp(struct device *dev,
temp_value = (signed int)data;
- data = i2c_smbus_read_byte_data(client, EXT_LO_TEMP_RD);
+ data = i2c_smbus_read_byte_data(client, EXT_TEMP_RD_LO);
return sprintf(buf, "%d.%d\n", temp_value, (25 * (data >> 6)));
}
static DEVICE_ATTR(temperature, S_IRUGO, nct1008_show_temp, NULL);
+static DEVICE_ATTR(temperature_overheat, (S_IRUGO | (S_IWUSR | S_IWGRP)),
+ nct1008_show_temp_overheat, nct1008_set_temp_overheat);
+static DEVICE_ATTR(temperature_alert, (S_IRUGO | (S_IWUSR | S_IWGRP)),
+ nct1008_show_temp_alert, nct1008_set_temp_alert);
static DEVICE_ATTR(ext_temperature, S_IRUGO, nct1008_show_ext_temp, NULL);
static struct attribute *nct1008_attributes[] = {
&dev_attr_temperature.attr,
+ &dev_attr_temperature_overheat.attr,
+ &dev_attr_temperature_alert.attr,
&dev_attr_ext_temperature.attr,
NULL
};
@@ -141,10 +383,10 @@ static void nct1008_disable(struct i2c_client *client)
data->config | STANDBY_BIT);
}
-
static void nct1008_work_func(struct work_struct *work)
{
- struct nct1008_data *data = container_of(work, struct nct1008_data, work);
+ struct nct1008_data *data = container_of(work, struct nct1008_data,
+ work);
int irq = data->client->irq;
mutex_lock(&data->mutex);
@@ -165,22 +407,14 @@ static irqreturn_t nct1008_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static inline u8 value_to_temperature(bool extended, u8 value)
-{
- return (extended ? (u8)(value - EXTENDED_RANGE_OFFSET) : value);
-}
-
-static inline u8 temperature_to_value(bool extended, u8 temp)
-{
- return (extended ? (u8)(temp + EXTENDED_RANGE_OFFSET) : temp);
-}
-
static int __devinit nct1008_configure_sensor(struct nct1008_data* data)
{
struct i2c_client *client = data->client;
struct nct1008_platform_data *pdata = client->dev.platform_data;
u8 value;
int err;
+ u8 temp;
+ u8 temp2;
if (!pdata || !pdata->supported_hwrev)
return -ENODEV;
@@ -203,42 +437,96 @@ static int __devinit nct1008_configure_sensor(struct nct1008_data* data)
goto error;
/* External temperature h/w shutdown limit */
- value = temperature_to_value(pdata->ext_range, pdata->shutdown_ext_limit);
+ value = temperature_to_value(pdata->ext_range,
+ pdata->shutdown_ext_limit);
err = i2c_smbus_write_byte_data(client, EXT_THERM_LIMIT_WR, value);
if (err < 0)
goto error;
/* Local temperature h/w shutdown limit */
- value = temperature_to_value(pdata->ext_range, pdata->shutdown_local_limit);
+ value = temperature_to_value(pdata->ext_range,
+ pdata->shutdown_local_limit);
err = i2c_smbus_write_byte_data(client, LOCAL_THERM_LIMIT_WR, value);
if (err < 0)
goto error;
/* External Temperature Throttling limit */
- value = temperature_to_value(pdata->ext_range, pdata->throttling_ext_limit);
- err = i2c_smbus_write_byte_data(client, EXT_TEMP_HI_LIMIT_HI_BYTE, value);
+ value = temperature_to_value(pdata->ext_range,
+ pdata->throttling_ext_limit);
+ err = i2c_smbus_write_byte_data(client, EXT_TEMP_HI_LIMIT_HI_BYTE_WR,
+ value);
if (err < 0)
goto error;
/* Local Temperature Throttling limit */
+ /* Local and remote Temperature Throttling limit kept same */
+ /*
value = pdata->ext_range ? EXTENDED_RANGE_MAX : STANDARD_RANGE_MAX;
- err = i2c_smbus_write_byte_data(client, LOCAL_TEMP_HI_LIMIT_WR, value);
+ */
+ err = i2c_smbus_write_byte_data(client, LOCAL_TEMP_HI_LIMIT_WR,
+ value);
if (err < 0)
goto error;
+ /* read initial temperature */
+ value = i2c_smbus_read_byte_data(client, LOCAL_TEMP_RD);
+ if (value < 0) {
+ err = value;
+ goto error;
+ }
+ temp = value_to_temperature(pdata->ext_range, value);
+ dev_dbg(&client->dev, "\n initial local temp read=%d ", temp);
+
+ value = i2c_smbus_read_byte_data(client, EXT_TEMP_RD_LOW);
+ if (value < 0) {
+ err = value;
+ goto error;
+ }
+ temp2 = (value >> 6);
+ value = i2c_smbus_read_byte_data(client, EXT_TEMP_RD_HI);
+ if (value < 0) {
+ err = value;
+ goto error;
+ }
+ temp = value_to_temperature(pdata->ext_range, value);
+
+ if (temp2 > 0) {
+ if (temp2 == 1)
+ dev_dbg(&client->dev, "\n initial external temp "
+ "read=%d.25 deg ", temp);
+ else if (temp2 == 2)
+ dev_dbg(&client->dev, "\n initial external temp "
+ "read=%d.5 deg ", temp);
+ else if (temp2 == 3)
+ dev_dbg(&client->dev, "\n initial external temp "
+ "read=%d.75 deg ", temp);
+ } else {
+ dev_dbg(&client->dev, "\n initial external temp read=%d.0 deg ",
+ temp);
+ }
+
/* Remote channel offset */
err = i2c_smbus_write_byte_data(client, OFFSET_WR, pdata->offset);
if (err < 0)
goto error;
/* THERM hysteresis */
- err = i2c_smbus_write_byte_data(client, THERM_HYSTERESIS_WR, pdata->hysteresis);
+ err = i2c_smbus_write_byte_data(client, THERM_HYSTERESIS_WR,
+ pdata->hysteresis);
if (err < 0)
goto error;
+ /* register sysfs hooks */
+ err = sysfs_create_group(&client->dev.kobj, &nct1008_attr_group);
+ if (err < 0) {
+ dev_err(&client->dev, "\n sysfs create err=%d ", err);
+ goto error;
+ }
+
data->alarm_fn = pdata->alarm_fn;
return 0;
error:
+ dev_err(&client->dev, "\n exit %s, err=%d ", __func__, err);
return err;
}
@@ -246,11 +534,16 @@ static int __devinit nct1008_configure_irq(struct nct1008_data *data)
{
INIT_WORK(&data->work, nct1008_work_func);
- return request_irq(data->client->irq, nct1008_irq, IRQF_TRIGGER_RISING |
- IRQF_TRIGGER_FALLING, DRIVER_NAME, data);
+ if (data->client->irq < 0)
+ return 0;
+ else
+ return request_irq(data->client->irq, nct1008_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ DRIVER_NAME, data);
}
-static int __devinit nct1008_probe(struct i2c_client *client, const struct i2c_device_id *id)
+static int __devinit nct1008_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct nct1008_data *data;
int err;
@@ -265,18 +558,18 @@ static int __devinit nct1008_probe(struct i2c_client *client, const struct i2c_d
mutex_init(&data->mutex);
err = nct1008_configure_sensor(data); /* sensor is in standby */
- if (err < 0)
+ if (err < 0) {
+ dev_err(&client->dev, "\n error file: %s : %s(), line=%d ",
+ __FILE__, __func__, __LINE__);
goto error;
+ }
err = nct1008_configure_irq(data);
- if (err < 0)
- goto error;
-
- /* register sysfs hooks */
- err = sysfs_create_group(&client->dev.kobj, &nct1008_attr_group);
- if (err < 0)
+ if (err < 0) {
+ dev_err(&client->dev, "\n error file: %s : %s(), line=%d ",
+ __FILE__, __func__, __LINE__);
goto error;
-
+ }
dev_info(&client->dev, "%s: initialized\n", __func__);
nct1008_enable(client); /* sensor is running */
@@ -286,6 +579,7 @@ static int __devinit nct1008_probe(struct i2c_client *client, const struct i2c_d
return 0;
error:
+ dev_err(&client->dev, "\n exit %s, err=%d ", __func__, err);
kfree(data);
return err;
}