apm821xx: lm90 add thermal sensor interface support for device tree

From 912-hwmon-lm90-expose-to-thermal-fw-via-DT.patch:
"This patch adds to lm90 temperature sensor the possibility
to expose itself as thermal zone device, registered on the
thermal framework.

The thermal zone is built only if a device tree node
describing a thermal zone for this sensor is present
inside the lm90 DT node. Otherwise, the driver behavior
will be the same."

Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
This commit is contained in:
Christian Lamparter 2016-07-20 15:44:56 +02:00 committed by Felix Fietkau
parent b46e2a6d95
commit 47eeb9f857
2 changed files with 453 additions and 0 deletions

View file

@ -0,0 +1,302 @@
From: Wei Ni <wni@nvidia.com>
Subject: hwmon: lm90: split set and show temp as common codes
Split set and show temp codes as common functions, so we can use
it directly when implement linux thermal framework.
And handle error return value for the lm90_select_remote_channel
and write_tempx, then set_temp8 and set_temp11 could return it
to user-space.
Discussed in:
http://www.spinics.net/lists/linux-tegra/msg14020.html .
Applied with Jean.
BUG=chrome-os-partner:30834
TEST=None
Signed-off-by: Wei Ni <wni@nvidia.com>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Reviewed-on: https://chromium-review.googlesource.com/175114
Tested-by: Wei Ni <wni.nvidia@gmail.com>
Commit-Queue: Dylan Reid <dgreid@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
(cherry picked from commit 614a96decdc7a3784128c9f21c5471367e2c627d)
Change-Id: Idbe3948812c6737cba94810cd147c29cc527c3cf
Reviewed-on: https://chromium-review.googlesource.com/212413
Reviewed-by: Olof Johansson <olofj@chromium.org>
Commit-Queue: Olof Johansson <olofj@chromium.org>
---
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index c9ff08d..fb9e224 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -473,20 +473,29 @@
* various registers have different meanings as a result of selecting a
* non-default remote channel.
*/
-static inline void lm90_select_remote_channel(struct i2c_client *client,
- struct lm90_data *data,
- int channel)
+static inline int lm90_select_remote_channel(struct i2c_client *client,
+ struct lm90_data *data,
+ int channel)
{
u8 config;
+ int err;
if (data->kind == max6696) {
lm90_read_reg(client, LM90_REG_R_CONFIG1, &config);
config &= ~0x08;
if (channel)
config |= 0x08;
- i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
- config);
+ err = i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
+ config);
+ if (err < 0) {
+ dev_err(&client->dev,
+ "Failed to select remote channel %d, err %d\n",
+ channel, err);
+ return err;
+ }
}
+
+ return 0;
}
/*
@@ -759,29 +768,34 @@
* Sysfs stuff
*/
-static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr,
- char *buf)
+static int read_temp8(struct device *dev, int index)
{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct lm90_data *data = lm90_update_device(dev);
int temp;
if (data->kind == adt7461 || data->kind == tmp451)
- temp = temp_from_u8_adt7461(data, data->temp8[attr->index]);
+ temp = temp_from_u8_adt7461(data, data->temp8[index]);
else if (data->kind == max6646)
- temp = temp_from_u8(data->temp8[attr->index]);
+ temp = temp_from_u8(data->temp8[index]);
else
- temp = temp_from_s8(data->temp8[attr->index]);
+ temp = temp_from_s8(data->temp8[index]);
/* +16 degrees offset for temp2 for the LM99 */
- if (data->kind == lm99 && attr->index == 3)
+ if (data->kind == lm99 && index == 3)
temp += 16000;
- return sprintf(buf, "%d\n", temp);
+ return temp;
}
-static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr,
- const char *buf, size_t count)
+static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+
+ return sprintf(buf, "%d\n", read_temp8(dev, attr->index));
+}
+
+static int write_temp8(struct device *dev, int index, long val)
{
static const u8 reg[TEMP8_REG_NUM] = {
LM90_REG_W_LOCAL_LOW,
@@ -794,10 +808,37 @@
MAX6659_REG_W_REMOTE_EMERG,
};
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct lm90_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
- int nr = attr->index;
+ int err;
+
+ /* +16 degrees offset for temp2 for the LM99 */
+ if (data->kind == lm99 && index == 3)
+ val -= 16000;
+
+ mutex_lock(&data->update_lock);
+ if (data->kind == adt7461 || data->kind == tmp451)
+ data->temp8[index] = temp_to_u8_adt7461(data, val);
+ else if (data->kind == max6646)
+ data->temp8[index] = temp_to_u8(val);
+ else
+ data->temp8[index] = temp_to_s8(val);
+
+ if ((err = lm90_select_remote_channel(client, data, index >= 6)) ||
+ (err = i2c_smbus_write_byte_data(client, reg[index],
+ data->temp8[index])) ||
+ (err = lm90_select_remote_channel(client, data, 0)))
+ dev_err(dev, "write_temp8 failed, err %d\n", err);
+ mutex_unlock(&data->update_lock);
+
+ return err;
+}
+
+static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ int index = attr->index;
long val;
int err;
@@ -805,49 +846,41 @@
if (err < 0)
return err;
- /* +16 degrees offset for temp2 for the LM99 */
- if (data->kind == lm99 && attr->index == 3)
- val -= 16000;
+ err = write_temp8(dev, index, val);
+ if (err < 0)
+ return err;
- mutex_lock(&data->update_lock);
- if (data->kind == adt7461 || data->kind == tmp451)
- data->temp8[nr] = temp_to_u8_adt7461(data, val);
- else if (data->kind == max6646)
- data->temp8[nr] = temp_to_u8(val);
- else
- data->temp8[nr] = temp_to_s8(val);
-
- lm90_select_remote_channel(client, data, nr >= 6);
- i2c_smbus_write_byte_data(client, reg[nr], data->temp8[nr]);
- lm90_select_remote_channel(client, data, 0);
-
- mutex_unlock(&data->update_lock);
return count;
+}
+
+static int read_temp11(struct device *dev, int index)
+{
+ struct lm90_data *data = lm90_update_device(dev);
+ int temp;
+
+ if (data->kind == adt7461 || data->kind == tmp451)
+ temp = temp_from_u16_adt7461(data, data->temp11[index]);
+ else if (data->kind == max6646)
+ temp = temp_from_u16(data->temp11[index]);
+ else
+ temp = temp_from_s16(data->temp11[index]);
+
+ /* +16 degrees offset for temp2 for the LM99 */
+ if (data->kind == lm99 && index <= 2)
+ temp += 16000;
+
+ return temp;
}
static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr,
char *buf)
{
struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
- struct lm90_data *data = lm90_update_device(dev);
- int temp;
- if (data->kind == adt7461 || data->kind == tmp451)
- temp = temp_from_u16_adt7461(data, data->temp11[attr->index]);
- else if (data->kind == max6646)
- temp = temp_from_u16(data->temp11[attr->index]);
- else
- temp = temp_from_s16(data->temp11[attr->index]);
-
- /* +16 degrees offset for temp2 for the LM99 */
- if (data->kind == lm99 && attr->index <= 2)
- temp += 16000;
-
- return sprintf(buf, "%d\n", temp);
+ return sprintf(buf, "%d\n", read_temp11(dev, attr->index));
}
-static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
- const char *buf, size_t count)
+static int write_temp11(struct device *dev, int nr, int index, long val)
{
struct {
u8 high;
@@ -861,17 +894,9 @@
{ LM90_REG_W_REMOTE_HIGHH, LM90_REG_W_REMOTE_HIGHL, 1 }
};
- struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
struct lm90_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
- int nr = attr->nr;
- int index = attr->index;
- long val;
int err;
-
- err = kstrtol(buf, 10, &val);
- if (err < 0)
- return err;
/* +16 degrees offset for temp2 for the LM99 */
if (data->kind == lm99 && index <= 2)
@@ -887,15 +912,50 @@
else
data->temp11[index] = temp_to_s8(val) << 8;
- lm90_select_remote_channel(client, data, reg[nr].channel);
- i2c_smbus_write_byte_data(client, reg[nr].high,
- data->temp11[index] >> 8);
- if (data->flags & LM90_HAVE_REM_LIMIT_EXT)
- i2c_smbus_write_byte_data(client, reg[nr].low,
- data->temp11[index] & 0xff);
- lm90_select_remote_channel(client, data, 0);
+ err = lm90_select_remote_channel(client, data, reg[nr].channel);
+ if (err)
+ goto error;
+
+ err = i2c_smbus_write_byte_data(client, reg[nr].high,
+ data->temp11[index] >> 8);
+ if (err)
+ goto error;
+
+ if (data->flags & LM90_HAVE_REM_LIMIT_EXT) {
+ err = i2c_smbus_write_byte_data(client, reg[nr].low,
+ data->temp11[index] & 0xff);
+ if (err)
+ goto error;
+ }
+
+ err = lm90_select_remote_channel(client, data, 0);
+
+error:
+ if (err)
+ dev_err(dev, "write_temp11 failed, err %d\n", err);
mutex_unlock(&data->update_lock);
+
+ return err;
+}
+
+static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ int nr = attr->nr;
+ int index = attr->index;
+ long val;
+ int err;
+
+ err = kstrtol(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ err = write_temp11(dev, nr, index, val);
+ if (err < 0)
+ return err;
+
return count;
}

View file

@ -0,0 +1,151 @@
From: Wei Ni <wni@nvidia.com>
Subject: hwmon: lm90: expose to thermal fw via DT nodes
This patch adds to lm90 temperature sensor the possibility
to expose itself as thermal zone device, registered on the
thermal framework.
The thermal zone is built only if a device tree node
describing a thermal zone for this sensor is present
inside the lm90 DT node. Otherwise, the driver behavior
will be the same.
Discussed in:
http://www.gossamer-threads.com/lists/linux/kernel/1992853
BUG=chrome-os-partner:30834
TEST=Verified. Build and boot up system.
Signed-off-by: Wei Ni <wni@nvidia.com>
Reviewed-on: https://chromium-review.googlesource.com/181447
Reviewed-by: Dylan Reid <dgreid@chromium.org>
Tested-by: Dylan Reid <dgreid@chromium.org>
Commit-Queue: Dylan Reid <dgreid@chromium.org>
Change-Id: Id356b94d7e8f4b49ec15e46b17a1fa2ff0cbf8cf
Reviewed-on: https://chromium-review.googlesource.com/212414
Tested-by: Wei Ni <wni.nvidia@gmail.com>
Reviewed-by: Olof Johansson <olofj@chromium.org>
Commit-Queue: Olof Johansson <olofj@chromium.org>
---
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index fb9e224..c54d3c8 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -96,6 +96,8 @@
#include <linux/sysfs.h>
#include <linux/interrupt.h>
#include <linux/regulator/consumer.h>
+#include <linux/of.h>
+#include <linux/thermal.h>
/*
* Addresses to scan
@@ -118,6 +120,13 @@
enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680,
max6646, w83l771, max6696, sa56004, g781, tmp451 };
+
+enum sensor_id {
+ LOCAL = 0,
+ REMOTE,
+ REMOTE2,
+ SENSOR_ID_END,
+};
/*
* The LM90 registers
@@ -368,6 +377,7 @@
struct i2c_client *client;
struct device *hwmon_dev;
const struct attribute_group *groups[6];
+ struct thermal_zone_device *tz[SENSOR_ID_END];
struct mutex update_lock;
struct regulator *regulator;
char valid; /* zero until following fields are valid */
@@ -878,6 +888,24 @@
struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
return sprintf(buf, "%d\n", read_temp11(dev, attr->index));
+}
+
+static int lm90_read_local_temp(void *dev, int *temp)
+{
+ *temp = read_temp11(dev, 4);
+ return 0;
+}
+
+static int lm90_read_remote_temp(void *dev, int *temp)
+{
+ *temp = read_temp11(dev, 0);
+ return 0;
+}
+
+static int lm90_read_remote2_temp(void *dev, int *temp)
+{
+ *temp = read_temp11(dev, 5);
+ return 0;
}
static int write_temp11(struct device *dev, int nr, int index, long val)
@@ -1150,6 +1238,18 @@
.attrs = lm90_temp3_attributes,
};
+static const struct thermal_zone_of_device_ops local_temp_sensor = {
+ .get_temp = lm90_read_local_temp,
+};
+
+static const struct thermal_zone_of_device_ops remote_temp_sensor = {
+ .get_temp = lm90_read_remote_temp,
+};
+
+static const struct thermal_zone_of_device_ops remote2_temp_sensor = {
+ .get_temp = lm90_read_remote2_temp,
+};
+
/* pec used for ADM1032 only */
static ssize_t show_pec(struct device *dev, struct device_attribute *dummy,
char *buf)
@@ -1599,6 +1699,30 @@
}
}
+ data->tz[LOCAL] = thermal_zone_of_sensor_register(&client->dev,
+ LOCAL,
+ &client->dev,
+ &local_temp_sensor);
+ if (IS_ERR(data->tz[LOCAL]))
+ data->tz[LOCAL] = NULL;
+
+ data->tz[REMOTE] = thermal_zone_of_sensor_register(&client->dev,
+ REMOTE,
+ &client->dev,
+ &remote_temp_sensor);
+ if (IS_ERR(data->tz[REMOTE]))
+ data->tz[REMOTE] = NULL;
+
+ if (data->flags & LM90_HAVE_TEMP3) {
+ data->tz[REMOTE2] = thermal_zone_of_sensor_register(
+ &client->dev,
+ REMOTE2,
+ &client->dev,
+ &remote2_temp_sensor);
+ if (IS_ERR(data->tz[REMOTE2]))
+ data->tz[REMOTE2] = NULL;
+ }
+
return 0;
exit_unregister:
@@ -1674,8 +1726,11 @@
static int lm90_remove(struct i2c_client *client)
{
+ int i;
struct lm90_data *data = i2c_get_clientdata(client);
+ for (i = 0; i < SENSOR_ID_END; i++)
+ thermal_zone_of_sensor_unregister(&client->dev, data->tz[i]);
hwmon_device_unregister(data->hwmon_dev);
device_remove_file(&client->dev, &dev_attr_pec);
lm90_restore_conf(client, data);