All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] lm90: device tree and thermal zone support
@ 2016-01-21 19:34 Stéphan Kochen
       [not found] ` <1453404877-17897-1-git-send-email-stephan-j6uo2F6POYhmR6Xm/wNWPw@public.gmane.org>
  0 siblings, 1 reply; 23+ messages in thread
From: Stéphan Kochen @ 2016-01-21 19:34 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Stéphan Kochen, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Guenter Roeck,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

This patchset adds support to the lm90 driver for initialising sensor
parameters from a device tree, as well as using the sensor in thermal zones
specified in a device tree.

The patchset is extracted from an ongoing personal project to get mainline
running on the Ouya console. The git repository is available at:

  https://github.com/stephank/linux.git

This particular patchset can also be pulled from the 'lm90-of' branch there.

The Ouya has a single GPIO fan, and an ON NCT1008 temperature sensor. With this
patchset, the kernel can do active cooling through a thermal zone, and set
sensible sensor alert parameters without user-space assistance.

There's still something amiss with alerts, though. When the temperature exceeds
one of the bounds, the machine bogs down and the log is flooded with warning
messages. (An interrupt flood? I'm not too concerned at this point, active
cooling should keep us far from the configured sensor alert bounds during
normal operation.)

Please note that these are my very first kernel patches. Hoping I get it right
the first time!

Stéphan Kochen (3):
  lm90: separate register accessors from sysfs
  lm90: initialize parameters from devicetree
  lm90: register with thermal zones

 Documentation/devicetree/bindings/hwmon/lm90.txt |  48 ++
 drivers/hwmon/lm90.c                             | 618 +++++++++++++++--------
 2 files changed, 453 insertions(+), 213 deletions(-)

-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 1/3] lm90: separate register accessors from sysfs
       [not found] ` <1453404877-17897-1-git-send-email-stephan-j6uo2F6POYhmR6Xm/wNWPw@public.gmane.org>
@ 2016-01-21 19:34   ` Stéphan Kochen
       [not found]     ` <1453404877-17897-2-git-send-email-stephan-j6uo2F6POYhmR6Xm/wNWPw@public.gmane.org>
  2016-01-21 19:34   ` [PATCH 2/3] lm90: initialize parameters from devicetree Stéphan Kochen
  2016-01-21 19:34   ` [PATCH 3/3] lm90: register with thermal zones Stéphan Kochen
  2 siblings, 1 reply; 23+ messages in thread
From: Stéphan Kochen @ 2016-01-21 19:34 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Stéphan Kochen, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Guenter Roeck,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Add additional support functions `lm90_get_*` and `lm90_set_*` extracted
from the sysfs routines. The sysfs routines are now just stubs wrapping
the new support functions.

This way we have a consistent register access interface, which can be
used from other integrations down the line. To avoid confusion, all
sysfs methods are now prefixed `lm90_sysfs_*`.

To accomplish this, the `lm90_update_device` signature has changed and
is now `lm90_update`, taking data directly. It no longer serves the
dual purpose of update function *and* driver data getter.

`lm90_set_convrate`, `lm90_select_remote_channel` and `lm90_init_client`
also had redundant i2c client parameters, which have been removed.

Signed-off-by: Stéphan Kochen <stephan-j6uo2F6POYhmR6Xm/wNWPw@public.gmane.org>
---
 drivers/hwmon/lm90.c | 511 ++++++++++++++++++++++++++++++---------------------
 1 file changed, 300 insertions(+), 211 deletions(-)

diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index c9ff08d..88daf72 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -473,10 +473,10 @@ static int lm90_read16(struct i2c_client *client, u8 regh, u8 regl, u16 *value)
  * 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 void lm90_select_remote_channel(
+		struct lm90_data *data, int channel)
 {
+	struct i2c_client *client = data->client;
 	u8 config;
 
 	if (data->kind == max6696) {
@@ -490,32 +490,10 @@ static inline void lm90_select_remote_channel(struct i2c_client *client,
 }
 
 /*
- * Set conversion rate.
- * client->update_lock must be held when calling this function (unless we are
- * in detection or initialization steps).
+ * Update all current register values
  */
-static void lm90_set_convrate(struct i2c_client *client, struct lm90_data *data,
-			      unsigned int interval)
-{
-	int i;
-	unsigned int update_interval;
-
-	/* Shift calculations to avoid rounding errors */
-	interval <<= 6;
-
-	/* find the nearest update rate */
-	for (i = 0, update_interval = LM90_MAX_CONVRATE_MS << 6;
-	     i < data->max_convrate; i++, update_interval >>= 1)
-		if (interval >= update_interval * 3 / 4)
-			break;
-
-	i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE, i);
-	data->update_interval = DIV_ROUND_CLOSEST(update_interval, 64);
-}
-
-static struct lm90_data *lm90_update_device(struct device *dev)
+static void lm90_update(struct lm90_data *data)
 {
-	struct lm90_data *data = dev_get_drvdata(dev);
 	struct i2c_client *client = data->client;
 	unsigned long next_update;
 
@@ -583,7 +561,7 @@ static struct lm90_data *lm90_update_device(struct device *dev)
 		data->alarms = alarms;	/* save as 16 bit value */
 
 		if (data->kind == max6696) {
-			lm90_select_remote_channel(client, data, 1);
+			lm90_select_remote_channel(data, 1);
 			lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT,
 				      &data->temp8[REMOTE2_CRIT]);
 			lm90_read_reg(client, MAX6659_REG_R_REMOTE_EMERG,
@@ -595,7 +573,7 @@ static struct lm90_data *lm90_update_device(struct device *dev)
 				data->temp11[REMOTE2_LOW] = h << 8;
 			if (!lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH, &h))
 				data->temp11[REMOTE2_HIGH] = h << 8;
-			lm90_select_remote_channel(client, data, 0);
+			lm90_select_remote_channel(data, 0);
 
 			if (!lm90_read_reg(client, MAX6696_REG_R_STATUS2,
 					   &alarms))
@@ -624,8 +602,6 @@ static struct lm90_data *lm90_update_device(struct device *dev)
 	}
 
 	mutex_unlock(&data->update_lock);
-
-	return data;
 }
 
 /*
@@ -756,32 +732,31 @@ static u16 temp_to_u16_adt7461(struct lm90_data *data, long val)
 }
 
 /*
- * Sysfs stuff
+ * Register accessors. Getters trigger an update. Setters have locked variants
+ * that require update_lock to be held.
  */
 
-static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr,
-			  char *buf)
+static int lm90_get_temp8(struct lm90_data *data, int index)
 {
-	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-	struct lm90_data *data = lm90_update_device(dev);
 	int temp;
 
+	lm90_update(data);
+
 	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 void lm90_set_temp8_locked(struct lm90_data *data, int index, long val)
 {
 	static const u8 reg[TEMP8_REG_NUM] = {
 		LM90_REG_W_LOCAL_LOW,
@@ -794,90 +769,73 @@ static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr,
 		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;
-	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 && attr->index == 3)
+	if (data->kind == lm99 && index == 3)
 		val -= 16000;
 
-	mutex_lock(&data->update_lock);
 	if (data->kind == adt7461 || data->kind == tmp451)
-		data->temp8[nr] = temp_to_u8_adt7461(data, val);
+		data->temp8[index] = temp_to_u8_adt7461(data, val);
 	else if (data->kind == max6646)
-		data->temp8[nr] = temp_to_u8(val);
+		data->temp8[index] = temp_to_u8(val);
 	else
-		data->temp8[nr] = temp_to_s8(val);
+		data->temp8[index] = 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);
+	lm90_select_remote_channel(data, index >= 6);
+	i2c_smbus_write_byte_data(data->client, reg[index], data->temp8[index]);
+	lm90_select_remote_channel(data, 0);
+}
 
+static void lm90_set_temp8(struct lm90_data *data, int index, long val)
+{
+	mutex_lock(&data->update_lock);
+	lm90_set_temp8_locked(data, index, val);
 	mutex_unlock(&data->update_lock);
-	return count;
 }
 
-static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr,
-			   char *buf)
+static int lm90_get_temp11(struct lm90_data *data, int index)
 {
-	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
-	struct lm90_data *data = lm90_update_device(dev);
 	int temp;
 
+	lm90_update(data);
+
 	if (data->kind == adt7461 || data->kind == tmp451)
-		temp = temp_from_u16_adt7461(data, data->temp11[attr->index]);
+		temp = temp_from_u16_adt7461(data, data->temp11[index]);
 	else if (data->kind == max6646)
-		temp = temp_from_u16(data->temp11[attr->index]);
+		temp = temp_from_u16(data->temp11[index]);
 	else
-		temp = temp_from_s16(data->temp11[attr->index]);
+		temp = temp_from_s16(data->temp11[index]);
 
 	/* +16 degrees offset for temp2 for the LM99 */
-	if (data->kind == lm99 &&  attr->index <= 2)
+	if (data->kind == lm99 && index <= 2)
 		temp += 16000;
 
-	return sprintf(buf, "%d\n", temp);
+	return temp;
 }
 
-static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
-			  const char *buf, size_t count)
+static void lm90_set_temp11_locked(struct lm90_data *data, int index, long val)
 {
-	struct {
-		u8 high;
-		u8 low;
-		int channel;
-	} reg[5] = {
-		{ LM90_REG_W_REMOTE_LOWH, LM90_REG_W_REMOTE_LOWL, 0 },
-		{ LM90_REG_W_REMOTE_HIGHH, LM90_REG_W_REMOTE_HIGHL, 0 },
-		{ LM90_REG_W_REMOTE_OFFSH, LM90_REG_W_REMOTE_OFFSL, 0 },
-		{ LM90_REG_W_REMOTE_LOWH, LM90_REG_W_REMOTE_LOWL, 1 },
-		{ 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;
+	u8 high, low, channel;
 
-	err = kstrtol(buf, 10, &val);
-	if (err < 0)
-		return err;
+#define SELECT_REGS(_reg, _channel) { \
+	high = LM90_REG_W_##_reg##H; \
+	low = LM90_REG_W_##_reg##L; \
+	channel = _channel; \
+}
+	switch (index) {
+	case REMOTE_LOW:    SELECT_REGS(REMOTE_LOW,  0); break;
+	case REMOTE_HIGH:   SELECT_REGS(REMOTE_HIGH, 0); break;
+	case REMOTE_OFFSET: SELECT_REGS(REMOTE_OFFS, 0); break;
+	case REMOTE2_LOW:   SELECT_REGS(REMOTE_LOW,  1); break;
+	case REMOTE2_HIGH:  SELECT_REGS(REMOTE_HIGH, 1); break;
+	default: return;
+	}
+#undef SELECT_REGS
 
 	/* +16 degrees offset for temp2 for the LM99 */
 	if (data->kind == lm99 && index <= 2)
 		val -= 16000;
 
-	mutex_lock(&data->update_lock);
 	if (data->kind == adt7461 || data->kind == tmp451)
 		data->temp11[index] = temp_to_u16_adt7461(data, val);
 	else if (data->kind == max6646)
@@ -887,54 +845,46 @@ static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
 	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);
+	lm90_select_remote_channel(data, channel);
+	i2c_smbus_write_byte_data(client, 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);
+		i2c_smbus_write_byte_data(client, low,
+				data->temp11[index] & 0xff);
+	lm90_select_remote_channel(data, 0);
+}
 
+static void lm90_set_temp11(struct lm90_data *data, int index, long val)
+{
+	mutex_lock(&data->update_lock);
+	lm90_set_temp11_locked(data, index, val);
 	mutex_unlock(&data->update_lock);
-	return count;
 }
 
-static ssize_t show_temphyst(struct device *dev,
-			     struct device_attribute *devattr,
-			     char *buf)
+static ssize_t lm90_get_temphyst(struct lm90_data *data, int index)
 {
-	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-	struct lm90_data *data = lm90_update_device(dev);
 	int temp;
 
+	lm90_update(data);
+
 	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 - temp_from_s8(data->temp_hyst));
+	return temp - temp_from_s8(data->temp_hyst);
 }
 
-static ssize_t set_temphyst(struct device *dev, struct device_attribute *dummy,
-			    const char *buf, size_t count)
+static void lm90_set_temphyst_locked(struct lm90_data *data, long val)
 {
-	struct lm90_data *data = dev_get_drvdata(dev);
-	struct i2c_client *client = data->client;
-	long val;
-	int err;
 	int temp;
 
-	err = kstrtol(buf, 10, &val);
-	if (err < 0)
-		return err;
-
-	mutex_lock(&data->update_lock);
 	if (data->kind == adt7461 || data->kind == tmp451)
 		temp = temp_from_u8_adt7461(data, data->temp8[LOCAL_CRIT]);
 	else if (data->kind == max6646)
@@ -943,43 +893,167 @@ static ssize_t set_temphyst(struct device *dev, struct device_attribute *dummy,
 		temp = temp_from_s8(data->temp8[LOCAL_CRIT]);
 
 	data->temp_hyst = hyst_to_reg(temp - val);
-	i2c_smbus_write_byte_data(client, LM90_REG_W_TCRIT_HYST,
-				  data->temp_hyst);
+	i2c_smbus_write_byte_data(data->client, LM90_REG_W_TCRIT_HYST,
+			data->temp_hyst);
+}
+
+static void lm90_set_temphyst(struct lm90_data *data, long val)
+{
+	mutex_lock(&data->update_lock);
+	lm90_set_temphyst_locked(data, val);
+	mutex_unlock(&data->update_lock);
+}
+
+static void lm90_set_convrate_locked(struct lm90_data *data, unsigned int val)
+{
+	int i;
+	unsigned int update_interval;
+
+	/* Shift calculations to avoid rounding errors */
+	val <<= 6;
+
+	/* find the nearest update rate */
+	for (i = 0, update_interval = LM90_MAX_CONVRATE_MS << 6;
+	     i < data->max_convrate; i++, update_interval >>= 1)
+		if (val >= update_interval * 3 / 4)
+			break;
+
+	i2c_smbus_write_byte_data(data->client, LM90_REG_W_CONVRATE, i);
+	data->update_interval = DIV_ROUND_CLOSEST(update_interval, 64);
+}
+
+static void lm90_set_convrate(struct lm90_data *data, unsigned int val)
+{
+	mutex_lock(&data->update_lock);
+	lm90_set_convrate_locked(data, val);
 	mutex_unlock(&data->update_lock);
+}
+
+/*
+ * Sysfs stuff
+ */
+
+static ssize_t lm90_sysfs_show_temp8(
+		struct device *dev, struct device_attribute *devattr,
+		char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct lm90_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", lm90_get_temp8(data, attr->index));
+}
+
+static ssize_t lm90_sysfs_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);
+	struct lm90_data *data = dev_get_drvdata(dev);
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	lm90_set_temp8(data, attr->index, val);
+
 	return count;
 }
 
-static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy,
-			   char *buf)
+static ssize_t lm90_sysfs_show_temp11(
+		struct device *dev, struct device_attribute *devattr,
+		char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct lm90_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", lm90_get_temp11(data, attr->index));
+}
+
+static ssize_t lm90_sysfs_set_temp11(
+		struct device *dev, struct device_attribute *devattr,
+		const char *buf, size_t count)
 {
-	struct lm90_data *data = lm90_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct lm90_data *data = dev_get_drvdata(dev);
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	lm90_set_temp11(data, attr->index, val);
+
+	return count;
+}
+
+static ssize_t lm90_sysfs_show_temphyst(
+		struct device *dev, struct device_attribute *devattr,
+		char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct lm90_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", lm90_get_temphyst(data, attr->index));
+}
+
+static ssize_t lm90_sysfs_set_temphyst(
+		struct device *dev, struct device_attribute *dummy,
+		const char *buf, size_t count)
+{
+	struct lm90_data *data = dev_get_drvdata(dev);
+	long val;
+	int err;
+
+	err = kstrtol(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	lm90_set_temphyst(data, val);
+
+	return count;
+}
+
+static ssize_t lm90_sysfs_show_alarms(
+		struct device *dev, struct device_attribute *dummy,
+		char *buf)
+{
+	struct lm90_data *data = dev_get_drvdata(dev);
+
+	lm90_update(data);
+
 	return sprintf(buf, "%d\n", data->alarms);
 }
 
-static ssize_t show_alarm(struct device *dev, struct device_attribute
-			  *devattr, char *buf)
+static ssize_t lm90_sysfs_show_alarm(
+		struct device *dev, struct device_attribute *devattr,
+		char *buf)
 {
 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-	struct lm90_data *data = lm90_update_device(dev);
+	struct lm90_data *data = dev_get_drvdata(dev);
 	int bitnr = attr->index;
 
+	lm90_update(data);
+
 	return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1);
 }
 
-static ssize_t show_update_interval(struct device *dev,
-				    struct device_attribute *attr, char *buf)
+static ssize_t lm90_sysfs_show_update_interval(
+		struct device *dev, struct device_attribute *attr,
+		char *buf)
 {
 	struct lm90_data *data = dev_get_drvdata(dev);
 
 	return sprintf(buf, "%u\n", data->update_interval);
 }
 
-static ssize_t set_update_interval(struct device *dev,
-				   struct device_attribute *attr,
-				   const char *buf, size_t count)
+static ssize_t lm90_sysfs_set_update_interval(
+		struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
 {
 	struct lm90_data *data = dev_get_drvdata(dev);
-	struct i2c_client *client = data->client;
 	unsigned long val;
 	int err;
 
@@ -987,49 +1061,55 @@ static ssize_t set_update_interval(struct device *dev,
 	if (err)
 		return err;
 
-	mutex_lock(&data->update_lock);
-	lm90_set_convrate(client, data, clamp_val(val, 0, 100000));
-	mutex_unlock(&data->update_lock);
+	lm90_set_convrate(data, clamp_val(val, 0, 100000));
 
 	return count;
 }
 
-static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp11, NULL,
-	0, LOCAL_TEMP);
-static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp11, NULL,
-	0, REMOTE_TEMP);
-static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp8,
-	set_temp8, LOCAL_LOW);
-static SENSOR_DEVICE_ATTR_2(temp2_min, S_IWUSR | S_IRUGO, show_temp11,
-	set_temp11, 0, REMOTE_LOW);
-static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp8,
-	set_temp8, LOCAL_HIGH);
-static SENSOR_DEVICE_ATTR_2(temp2_max, S_IWUSR | S_IRUGO, show_temp11,
-	set_temp11, 1, REMOTE_HIGH);
-static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp8,
-	set_temp8, LOCAL_CRIT);
-static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp8,
-	set_temp8, REMOTE_CRIT);
-static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temphyst,
-	set_temphyst, LOCAL_CRIT);
-static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL,
-	REMOTE_CRIT);
-static SENSOR_DEVICE_ATTR_2(temp2_offset, S_IWUSR | S_IRUGO, show_temp11,
-	set_temp11, 2, REMOTE_OFFSET);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
+	lm90_sysfs_show_temp11, NULL, LOCAL_TEMP);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO,
+	lm90_sysfs_show_temp11, NULL, REMOTE_TEMP);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
+	lm90_sysfs_show_temp8, lm90_sysfs_set_temp8, LOCAL_LOW);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO,
+	lm90_sysfs_show_temp11, lm90_sysfs_set_temp11, REMOTE_LOW);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
+	lm90_sysfs_show_temp8, lm90_sysfs_set_temp8, LOCAL_HIGH);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO,
+	lm90_sysfs_show_temp11, lm90_sysfs_set_temp11, REMOTE_HIGH);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
+	lm90_sysfs_show_temp8, lm90_sysfs_set_temp8, LOCAL_CRIT);
+static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO,
+	lm90_sysfs_show_temp8, lm90_sysfs_set_temp8, REMOTE_CRIT);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO,
+	lm90_sysfs_show_temphyst, lm90_sysfs_set_temphyst, LOCAL_CRIT);
+static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO,
+	lm90_sysfs_show_temphyst, NULL, REMOTE_CRIT);
+static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO,
+	lm90_sysfs_show_temp11, lm90_sysfs_set_temp11, REMOTE_OFFSET);
 
 /* Individual alarm files */
-static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
-static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2);
-static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
-static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
-static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 5);
-static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO,
+	lm90_sysfs_show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO,
+	lm90_sysfs_show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO,
+	lm90_sysfs_show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO,
+	lm90_sysfs_show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO,
+	lm90_sysfs_show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO,
+	lm90_sysfs_show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO,
+	lm90_sysfs_show_alarm, NULL, 6);
 /* Raw alarm file for compatibility */
-static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static DEVICE_ATTR(alarms, S_IRUGO,
+	lm90_sysfs_show_alarms, NULL);
 
-static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval,
-		   set_update_interval);
+static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR,
+	lm90_sysfs_show_update_interval, lm90_sysfs_set_update_interval);
 
 static struct attribute *lm90_attributes[] = {
 	&sensor_dev_attr_temp1_input.dev_attr.attr,
@@ -1071,14 +1151,14 @@ static const struct attribute_group lm90_temp2_offset_group = {
 /*
  * Additional attributes for devices with emergency sensors
  */
-static SENSOR_DEVICE_ATTR(temp1_emergency, S_IWUSR | S_IRUGO, show_temp8,
-	set_temp8, LOCAL_EMERG);
-static SENSOR_DEVICE_ATTR(temp2_emergency, S_IWUSR | S_IRUGO, show_temp8,
-	set_temp8, REMOTE_EMERG);
-static SENSOR_DEVICE_ATTR(temp1_emergency_hyst, S_IRUGO, show_temphyst,
-			  NULL, LOCAL_EMERG);
-static SENSOR_DEVICE_ATTR(temp2_emergency_hyst, S_IRUGO, show_temphyst,
-			  NULL, REMOTE_EMERG);
+static SENSOR_DEVICE_ATTR(temp1_emergency, S_IWUSR | S_IRUGO,
+	lm90_sysfs_show_temp8, lm90_sysfs_set_temp8, LOCAL_EMERG);
+static SENSOR_DEVICE_ATTR(temp2_emergency, S_IWUSR | S_IRUGO,
+	lm90_sysfs_show_temp8, lm90_sysfs_set_temp8, REMOTE_EMERG);
+static SENSOR_DEVICE_ATTR(temp1_emergency_hyst, S_IRUGO,
+	lm90_sysfs_show_temphyst, NULL, LOCAL_EMERG);
+static SENSOR_DEVICE_ATTR(temp2_emergency_hyst, S_IRUGO,
+	lm90_sysfs_show_temphyst, NULL, REMOTE_EMERG);
 
 static struct attribute *lm90_emergency_attributes[] = {
 	&sensor_dev_attr_temp1_emergency.dev_attr.attr,
@@ -1092,8 +1172,10 @@ static const struct attribute_group lm90_emergency_group = {
 	.attrs = lm90_emergency_attributes,
 };
 
-static SENSOR_DEVICE_ATTR(temp1_emergency_alarm, S_IRUGO, show_alarm, NULL, 15);
-static SENSOR_DEVICE_ATTR(temp2_emergency_alarm, S_IRUGO, show_alarm, NULL, 13);
+static SENSOR_DEVICE_ATTR(temp1_emergency_alarm, S_IRUGO,
+	lm90_sysfs_show_alarm, NULL, 15);
+static SENSOR_DEVICE_ATTR(temp2_emergency_alarm, S_IRUGO,
+	lm90_sysfs_show_alarm, NULL, 13);
 
 static struct attribute *lm90_emergency_alarm_attributes[] = {
 	&sensor_dev_attr_temp1_emergency_alarm.dev_attr.attr,
@@ -1108,26 +1190,31 @@ static const struct attribute_group lm90_emergency_alarm_group = {
 /*
  * Additional attributes for devices with 3 temperature sensors
  */
-static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp11, NULL,
-	0, REMOTE2_TEMP);
-static SENSOR_DEVICE_ATTR_2(temp3_min, S_IWUSR | S_IRUGO, show_temp11,
-	set_temp11, 3, REMOTE2_LOW);
-static SENSOR_DEVICE_ATTR_2(temp3_max, S_IWUSR | S_IRUGO, show_temp11,
-	set_temp11, 4, REMOTE2_HIGH);
-static SENSOR_DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_temp8,
-	set_temp8, REMOTE2_CRIT);
-static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO, show_temphyst, NULL,
-	REMOTE2_CRIT);
-static SENSOR_DEVICE_ATTR(temp3_emergency, S_IWUSR | S_IRUGO, show_temp8,
-	set_temp8, REMOTE2_EMERG);
-static SENSOR_DEVICE_ATTR(temp3_emergency_hyst, S_IRUGO, show_temphyst,
-			  NULL, REMOTE2_EMERG);
-
-static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 9);
-static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 10);
-static SENSOR_DEVICE_ATTR(temp3_min_alarm, S_IRUGO, show_alarm, NULL, 11);
-static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL, 12);
-static SENSOR_DEVICE_ATTR(temp3_emergency_alarm, S_IRUGO, show_alarm, NULL, 14);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO,
+	lm90_sysfs_show_temp11, NULL, REMOTE2_TEMP);
+static SENSOR_DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO,
+	lm90_sysfs_show_temp11, lm90_sysfs_set_temp11, REMOTE2_LOW);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO,
+	lm90_sysfs_show_temp11, lm90_sysfs_set_temp11, REMOTE2_HIGH);
+static SENSOR_DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO,
+	lm90_sysfs_show_temp8, lm90_sysfs_set_temp8, REMOTE2_CRIT);
+static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO,
+	lm90_sysfs_show_temphyst, NULL, REMOTE2_CRIT);
+static SENSOR_DEVICE_ATTR(temp3_emergency, S_IWUSR | S_IRUGO,
+	lm90_sysfs_show_temp8, lm90_sysfs_set_temp8, REMOTE2_EMERG);
+static SENSOR_DEVICE_ATTR(temp3_emergency_hyst, S_IRUGO,
+	lm90_sysfs_show_temphyst, NULL, REMOTE2_EMERG);
+
+static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO,
+	lm90_sysfs_show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO,
+	lm90_sysfs_show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(temp3_min_alarm, S_IRUGO,
+	lm90_sysfs_show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO,
+	lm90_sysfs_show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(temp3_emergency_alarm, S_IRUGO,
+	lm90_sysfs_show_alarm, NULL, 14);
 
 static struct attribute *lm90_temp3_attributes[] = {
 	&sensor_dev_attr_temp3_input.dev_attr.attr,
@@ -1151,15 +1238,15 @@ static const struct attribute_group lm90_temp3_group = {
 };
 
 /* pec used for ADM1032 only */
-static ssize_t show_pec(struct device *dev, struct device_attribute *dummy,
-			char *buf)
+static ssize_t lm90_sysfs_show_pec(struct device *dev,
+		struct device_attribute *dummy, char *buf)
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	return sprintf(buf, "%d\n", !!(client->flags & I2C_CLIENT_PEC));
 }
 
-static ssize_t set_pec(struct device *dev, struct device_attribute *dummy,
-		       const char *buf, size_t count)
+static ssize_t lm90_sysfs_set_pec(struct device *dev,
+		struct device_attribute *dummy, const char *buf, size_t count)
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	long val;
@@ -1183,7 +1270,8 @@ static ssize_t set_pec(struct device *dev, struct device_attribute *dummy,
 	return count;
 }
 
-static DEVICE_ATTR(pec, S_IWUSR | S_IRUGO, show_pec, set_pec);
+static DEVICE_ATTR(pec, S_IWUSR | S_IRUGO,
+	lm90_sysfs_show_pec, lm90_sysfs_set_pec);
 
 /*
  * Real code
@@ -1413,8 +1501,9 @@ static void lm90_restore_conf(struct i2c_client *client, struct lm90_data *data)
 				  data->config_orig);
 }
 
-static void lm90_init_client(struct i2c_client *client, struct lm90_data *data)
+static void lm90_init_client(struct lm90_data *data)
 {
+	struct i2c_client *client = data->client;
 	u8 config, convrate;
 
 	if (lm90_read_reg(client, LM90_REG_R_CONVRATE, &convrate) < 0) {
@@ -1426,7 +1515,7 @@ static void lm90_init_client(struct i2c_client *client, struct lm90_data *data)
 	/*
 	 * Start the conversions.
 	 */
-	lm90_set_convrate(client, data, 500);	/* 500ms; 2Hz conversion rate */
+	lm90_set_convrate_locked(data, 500);  /* 500ms / 2Hz  */
 	if (lm90_read_reg(client, LM90_REG_R_CONFIG1, &config) < 0) {
 		dev_warn(&client->dev, "Initialization failed!\n");
 		return;
@@ -1557,7 +1646,7 @@ static int lm90_probe(struct i2c_client *client,
 	data->max_convrate = lm90_params[data->kind].max_convrate;
 
 	/* Initialize the LM90 chip */
-	lm90_init_client(client, data);
+	lm90_init_client(data);
 
 	/* Register sysfs hooks */
 	data->groups[groups++] = &lm90_group;
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 2/3] lm90: initialize parameters from devicetree
       [not found] ` <1453404877-17897-1-git-send-email-stephan-j6uo2F6POYhmR6Xm/wNWPw@public.gmane.org>
  2016-01-21 19:34   ` [PATCH 1/3] lm90: separate register accessors from sysfs Stéphan Kochen
@ 2016-01-21 19:34   ` Stéphan Kochen
       [not found]     ` <1453404877-17897-3-git-send-email-stephan-j6uo2F6POYhmR6Xm/wNWPw@public.gmane.org>
  2016-01-21 19:34   ` [PATCH 3/3] lm90: register with thermal zones Stéphan Kochen
  2 siblings, 1 reply; 23+ messages in thread
From: Stéphan Kochen @ 2016-01-21 19:34 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Stéphan Kochen, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Guenter Roeck,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Allow a device tree to set initial temperature sensor parameters.

Userspace can still override actual values through sysfs.

Signed-off-by: Stéphan Kochen <stephan-j6uo2F6POYhmR6Xm/wNWPw@public.gmane.org>
---
 Documentation/devicetree/bindings/hwmon/lm90.txt | 40 +++++++++++++++++
 drivers/hwmon/lm90.c                             | 55 ++++++++++++++++++++++--
 2 files changed, 92 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/hwmon/lm90.txt b/Documentation/devicetree/bindings/hwmon/lm90.txt
index e863248..045e94b 100644
--- a/Documentation/devicetree/bindings/hwmon/lm90.txt
+++ b/Documentation/devicetree/bindings/hwmon/lm90.txt
@@ -33,6 +33,38 @@ Optional properties:
               LM90 "-ALERT" pin output.
               See interrupt-controller/interrupts.txt for the format.
 
+- update-interval: Interval at which temperatures are sampled,
+  Type: unsigned   in milliseconds.
+  Size: one cell
+
+- local-low:      Valid temperature range for the chip internal sensor,
+  local-high:     outside which the alert will be set. Values are in
+  local-critical: millicelcius.
+  Type: signed
+  Size: one cell
+
+- remote-low:      Valid temperature range for the external sensor,
+  remote-high:     outside which the alert will be set. Values are in
+  remote-critical: millicelciius.
+  Type: signed
+  Size: one cell
+
+- remote-offset:   Where available, an external sensor temperature offset.
+  Type: signed
+  Size: one cell
+
+- local-emergency:  On max6659, max6695 and max6696, a configurable
+  remote-emergency: 3rd upper bound on temperature.
+  Type: signed
+  Size: one cell
+
+- remote2-low:      On max6695 and max6696, a second external sensor.
+  remote2-high:
+  remote2-critical:
+  remote2-emergency:
+  Type: signed
+  Size: one cell
+
 Example LM90 node:
 
 temp-sensor {
@@ -41,4 +73,12 @@ temp-sensor {
 	vcc-supply = <&palmas_ldo6_reg>;
 	interrupt-parent = <&gpio>;
 	interrupts = <TEGRA_GPIO(O, 4) IRQ_TYPE_LEVEL_LOW>;
+	update-interval = <500>;
+	local-low = <5000>;
+	local-high = <80000>;
+	local-critical = <90000>;
+	remote-low = <5000>;
+	remote-high = <80000>;
+	remote-critical = <90000>;
+	remote-offset = <(-62125)>;
 }
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index 88daf72..8ae8791 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -93,6 +93,7 @@
 #include <linux/hwmon.h>
 #include <linux/err.h>
 #include <linux/mutex.h>
+#include <linux/of.h>
 #include <linux/sysfs.h>
 #include <linux/interrupt.h>
 #include <linux/regulator/consumer.h>
@@ -1504,8 +1505,16 @@ static void lm90_restore_conf(struct i2c_client *client, struct lm90_data *data)
 static void lm90_init_client(struct lm90_data *data)
 {
 	struct i2c_client *client = data->client;
+	struct device *dev = &client->dev;
 	u8 config, convrate;
+	u32 ms;
+#ifdef CONFIG_OF
+	s32 temp;
+#endif
 
+	/*
+	 * Save old conversion rate.
+	 */
 	if (lm90_read_reg(client, LM90_REG_R_CONVRATE, &convrate) < 0) {
 		dev_warn(&client->dev, "Failed to read convrate register!\n");
 		convrate = LM90_DEF_CONVRATE_RVAL;
@@ -1515,14 +1524,24 @@ static void lm90_init_client(struct lm90_data *data)
 	/*
 	 * Start the conversions.
 	 */
-	lm90_set_convrate_locked(data, 500);  /* 500ms / 2Hz  */
+#ifdef CONFIG_OF
+	if (of_property_read_u32(dev->of_node, "update-interval", &ms) < 0)
+#endif
+		ms = 500;  /* default rate: 2Hz */
+	lm90_set_convrate_locked(data, ms);
+
+	/*
+	 * Save old config
+	 */
 	if (lm90_read_reg(client, LM90_REG_R_CONFIG1, &config) < 0) {
-		dev_warn(&client->dev, "Initialization failed!\n");
+		dev_warn(dev, "Initialization failed!\n");
 		return;
 	}
 	data->config_orig = config;
 
-	/* Check Temperature Range Select */
+	/*
+	 * Check Temperature Range Select
+	 */
 	if (data->kind == adt7461 || data->kind == tmp451) {
 		if (config & 0x04)
 			data->flags |= LM90_FLAG_ADT7461_EXT;
@@ -1545,6 +1564,36 @@ static void lm90_init_client(struct lm90_data *data)
 	config &= 0xBF;	/* run */
 	if (config != data->config_orig) /* Only write if changed */
 		i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config);
+
+#ifdef CONFIG_OF
+	/*
+	 * Set initial values from devicetree
+	 */
+#define INIT_REG(_property, _index, _bits) { \
+	if (of_property_read_s32(dev->of_node, _property, &temp) == 0) \
+		lm90_set_temp##_bits##_locked(data, _index, temp); \
+}
+	INIT_REG("local-low", LOCAL_LOW, 8);
+	INIT_REG("local-high", LOCAL_HIGH, 8);
+	INIT_REG("local-critical", LOCAL_CRIT, 8);
+	INIT_REG("remote-low", REMOTE_LOW, 11);
+	INIT_REG("remote-high", REMOTE_HIGH, 11);
+	INIT_REG("remote-critical", REMOTE_CRIT, 8);
+	if (data->flags & LM90_HAVE_OFFSET) {
+		INIT_REG("remote-offset", REMOTE_OFFSET, 11);
+	}
+	if (data->flags & LM90_HAVE_EMERGENCY) {
+		INIT_REG("local-emergency", LOCAL_EMERG, 8);
+		INIT_REG("remote-emergency", REMOTE_EMERG, 8);
+	}
+	if (data->flags & LM90_HAVE_TEMP3) {
+		INIT_REG("remote2-low", REMOTE2_LOW, 11);
+		INIT_REG("remote2-high", REMOTE2_HIGH, 11);
+		INIT_REG("remote2-critical", REMOTE2_CRIT, 8);
+		INIT_REG("remote2-emergency", REMOTE2_EMERG, 8);
+	}
+#undef INIT_REG
+#endif
 }
 
 static bool lm90_is_tripped(struct i2c_client *client, u16 *status)
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 3/3] lm90: register with thermal zones
       [not found] ` <1453404877-17897-1-git-send-email-stephan-j6uo2F6POYhmR6Xm/wNWPw@public.gmane.org>
  2016-01-21 19:34   ` [PATCH 1/3] lm90: separate register accessors from sysfs Stéphan Kochen
  2016-01-21 19:34   ` [PATCH 2/3] lm90: initialize parameters from devicetree Stéphan Kochen
@ 2016-01-21 19:34   ` Stéphan Kochen
       [not found]     ` <1453404877-17897-4-git-send-email-stephan-j6uo2F6POYhmR6Xm/wNWPw@public.gmane.org>
  2 siblings, 1 reply; 23+ messages in thread
From: Stéphan Kochen @ 2016-01-21 19:34 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Stéphan Kochen, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Guenter Roeck,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Any lm90-driven node in the device tree can now be referenced in thermal
zones. One thermal zone device is registered for each sensor present.

Signed-off-by: Stéphan Kochen <stephan-j6uo2F6POYhmR6Xm/wNWPw@public.gmane.org>
---
 Documentation/devicetree/bindings/hwmon/lm90.txt |  8 ++++
 drivers/hwmon/lm90.c                             | 54 ++++++++++++++++++++++++
 2 files changed, 62 insertions(+)

diff --git a/Documentation/devicetree/bindings/hwmon/lm90.txt b/Documentation/devicetree/bindings/hwmon/lm90.txt
index 045e94b..da9aae7 100644
--- a/Documentation/devicetree/bindings/hwmon/lm90.txt
+++ b/Documentation/devicetree/bindings/hwmon/lm90.txt
@@ -28,6 +28,13 @@ Required node properties:
 
 - vcc-supply: vcc regulator for the supply voltage.
 
+- #thermal-sensor-cells: Should be 1. See ../../thermal/thermal.txt for a
+                         description of this property. Use the following
+                         values to refer to a specific sensor:
+                         0: chip internal sensor
+                         1: external sensor
+                         2: second external sensor, if present
+
 Optional properties:
 - interrupts: Contains a single interrupt specifier which describes the
               LM90 "-ALERT" pin output.
@@ -81,4 +88,5 @@ temp-sensor {
 	remote-high = <80000>;
 	remote-critical = <90000>;
 	remote-offset = <(-62125)>;
+	#thermal-sensor-cells = <1>;
 }
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index 8ae8791..4577916 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -95,6 +95,7 @@
 #include <linux/mutex.h>
 #include <linux/of.h>
 #include <linux/sysfs.h>
+#include <linux/thermal.h>
 #include <linux/interrupt.h>
 #include <linux/regulator/consumer.h>
 
@@ -207,6 +208,8 @@ enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680,
 #define MAX6696_STATUS2_R2OT2	(1 << 6) /* remote2 emergency limit tripped */
 #define MAX6696_STATUS2_LOT2	(1 << 7) /* local emergency limit tripped */
 
+#define LM90_NUM_SENSORS(d) (((d)->flags & LM90_HAVE_TEMP3) ? 3 : 2)
+
 /*
  * Driver data (common to all clients)
  */
@@ -365,6 +368,13 @@ enum lm90_temp11_reg_index {
  * Client data (each client gets its own)
  */
 
+struct lm90_sensor {
+	struct lm90_data *data;
+	int index;
+
+	struct thermal_zone_device *tz;
+};
+
 struct lm90_data {
 	struct i2c_client *client;
 	struct device *hwmon_dev;
@@ -390,6 +400,10 @@ struct lm90_data {
 	s16 temp11[TEMP11_REG_NUM];
 	u8 temp_hyst;
 	u16 alarms; /* bitvector (upper 8 bits for max6695/96) */
+
+#ifdef CONFIG_THERMAL_OF
+	struct lm90_sensor sensors[3];
+#endif
 };
 
 /*
@@ -1275,6 +1289,23 @@ static DEVICE_ATTR(pec, S_IWUSR | S_IRUGO,
 	lm90_sysfs_show_pec, lm90_sysfs_set_pec);
 
 /*
+ * Thermal zone code
+ */
+
+#ifdef CONFIG_THERMAL_OF
+static int lm90_of_get_temp(void *data, int *out_temp)
+{
+	struct lm90_sensor *sensor = data;
+	*out_temp = lm90_get_temp11(sensor->data, sensor->index);
+	return 0;
+}
+
+static const struct thermal_zone_of_device_ops lm90_of_thermal_ops = {
+	.get_temp = lm90_of_get_temp,
+};
+#endif
+
+/*
  * Real code
  */
 
@@ -1653,6 +1684,7 @@ static int lm90_probe(struct i2c_client *client,
 	struct regulator *regulator;
 	int groups = 0;
 	int err;
+	unsigned int i;
 
 	regulator = devm_regulator_get(dev, "vcc");
 	if (IS_ERR(regulator))
@@ -1737,6 +1769,20 @@ static int lm90_probe(struct i2c_client *client,
 		}
 	}
 
+#ifdef CONFIG_THERMAL_OF
+	data->sensors[0].index = LOCAL_TEMP;
+	data->sensors[1].index = REMOTE_TEMP;
+	data->sensors[2].index = REMOTE2_TEMP;
+	for (i = 0; i < LM90_NUM_SENSORS(data); i++) {
+		data->sensors[i].data = data;
+		data->sensors[i].tz = thermal_zone_of_sensor_register(
+			dev, i, &data->sensors[i],
+			&lm90_of_thermal_ops);
+		if (IS_ERR(data->sensors[i].tz))
+			data->sensors[i].tz = NULL;
+	}
+#endif
+
 	return 0;
 
 exit_unregister:
@@ -1753,6 +1799,14 @@ exit_restore:
 static int lm90_remove(struct i2c_client *client)
 {
 	struct lm90_data *data = i2c_get_clientdata(client);
+#ifdef CONFIG_THERMAL_OF
+	unsigned int i;
+
+	for (i = 0; i < LM90_NUM_SENSORS(data); i++) {
+		thermal_zone_of_sensor_unregister(&client->dev,
+						  data->sensors[i].tz);
+	}
+#endif
 
 	hwmon_device_unregister(data->hwmon_dev);
 	device_remove_file(&client->dev, &dev_attr_pec);
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH 1/3] lm90: separate register accessors from sysfs
       [not found]     ` <1453404877-17897-2-git-send-email-stephan-j6uo2F6POYhmR6Xm/wNWPw@public.gmane.org>
@ 2016-01-22 14:42         ` Guenter Roeck
  0 siblings, 0 replies; 23+ messages in thread
From: Guenter Roeck @ 2016-01-22 14:42 UTC (permalink / raw)
  To: Stéphan Kochen, Jean Delvare
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On 01/21/2016 11:34 AM, Stéphan Kochen wrote:
> Add additional support functions `lm90_get_*` and `lm90_set_*` extracted
> from the sysfs routines. The sysfs routines are now just stubs wrapping
> the new support functions.
>
> This way we have a consistent register access interface, which can be
> used from other integrations down the line. To avoid confusion, all
> sysfs methods are now prefixed `lm90_sysfs_*`.
>
> To accomplish this, the `lm90_update_device` signature has changed and
> is now `lm90_update`, taking data directly. It no longer serves the
> dual purpose of update function *and* driver data getter.
>
> `lm90_set_convrate`, `lm90_select_remote_channel` and `lm90_init_client`
> also had redundant i2c client parameters, which have been removed.
>
> Signed-off-by: Stéphan Kochen <stephan-j6uo2F6POYhmR6Xm/wNWPw@public.gmane.org>
> ---
>   drivers/hwmon/lm90.c | 511 ++++++++++++++++++++++++++++++---------------------
>   1 file changed, 300 insertions(+), 211 deletions(-)
>
> diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
> index c9ff08d..88daf72 100644
> --- a/drivers/hwmon/lm90.c
> +++ b/drivers/hwmon/lm90.c
> @@ -473,10 +473,10 @@ static int lm90_read16(struct i2c_client *client, u8 regh, u8 regl, u16 *value)
>    * 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 void lm90_select_remote_channel(
> +		struct lm90_data *data, int channel)

Very much personal preference here, unrelated change, and violates coding style.

Please only one logical change per patch. If you think it is worthwhile to remove
the client argument, prepare a separate patch with only that change, and show
that it reduces code size. Also please make sure that your patch follows
coding style.

>   {
> +	struct i2c_client *client = data->client;
>   	u8 config;
>
>   	if (data->kind == max6696) {
> @@ -490,32 +490,10 @@ static inline void lm90_select_remote_channel(struct i2c_client *client,
>   }
>
>   /*
> - * Set conversion rate.
> - * client->update_lock must be held when calling this function (unless we are
> - * in detection or initialization steps).
> + * Update all current register values
>    */
> -static void lm90_set_convrate(struct i2c_client *client, struct lm90_data *data,
> -			      unsigned int interval)
> -{
> -	int i;
> -	unsigned int update_interval;
> -
> -	/* Shift calculations to avoid rounding errors */
> -	interval <<= 6;
> -
> -	/* find the nearest update rate */
> -	for (i = 0, update_interval = LM90_MAX_CONVRATE_MS << 6;
> -	     i < data->max_convrate; i++, update_interval >>= 1)
> -		if (interval >= update_interval * 3 / 4)
> -			break;
> -
> -	i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE, i);
> -	data->update_interval = DIV_ROUND_CLOSEST(update_interval, 64);
> -}
> -
> -static struct lm90_data *lm90_update_device(struct device *dev)
> +static void lm90_update(struct lm90_data *data)
>   {
> -	struct lm90_data *data = dev_get_drvdata(dev);
>   	struct i2c_client *client = data->client;
>   	unsigned long next_update;
>
> @@ -583,7 +561,7 @@ static struct lm90_data *lm90_update_device(struct device *dev)
>   		data->alarms = alarms;	/* save as 16 bit value */
>
>   		if (data->kind == max6696) {
> -			lm90_select_remote_channel(client, data, 1);
> +			lm90_select_remote_channel(data, 1);
>   			lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT,
>   				      &data->temp8[REMOTE2_CRIT]);
>   			lm90_read_reg(client, MAX6659_REG_R_REMOTE_EMERG,
> @@ -595,7 +573,7 @@ static struct lm90_data *lm90_update_device(struct device *dev)
>   				data->temp11[REMOTE2_LOW] = h << 8;
>   			if (!lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH, &h))
>   				data->temp11[REMOTE2_HIGH] = h << 8;
> -			lm90_select_remote_channel(client, data, 0);
> +			lm90_select_remote_channel(data, 0);
>
>   			if (!lm90_read_reg(client, MAX6696_REG_R_STATUS2,
>   					   &alarms))
> @@ -624,8 +602,6 @@ static struct lm90_data *lm90_update_device(struct device *dev)
>   	}
>
>   	mutex_unlock(&data->update_lock);
> -
> -	return data;
>   }
>
>   /*
> @@ -756,32 +732,31 @@ static u16 temp_to_u16_adt7461(struct lm90_data *data, long val)
>   }
>
>   /*
> - * Sysfs stuff
> + * Register accessors. Getters trigger an update. Setters have locked variants
> + * that require update_lock to be held.
>    */
>
> -static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr,
> -			  char *buf)
> +static int lm90_get_temp8(struct lm90_data *data, int index)
>   {
> -	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
> -	struct lm90_data *data = lm90_update_device(dev);
>   	int temp;
>
> +	lm90_update(data);
> +
>   	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 void lm90_set_temp8_locked(struct lm90_data *data, int index, long val)
>   {
>   	static const u8 reg[TEMP8_REG_NUM] = {
>   		LM90_REG_W_LOCAL_LOW,
> @@ -794,90 +769,73 @@ static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr,
>   		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;
> -	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 && attr->index == 3)
> +	if (data->kind == lm99 && index == 3)
>   		val -= 16000;
>
> -	mutex_lock(&data->update_lock);
>   	if (data->kind == adt7461 || data->kind == tmp451)
> -		data->temp8[nr] = temp_to_u8_adt7461(data, val);
> +		data->temp8[index] = temp_to_u8_adt7461(data, val);
>   	else if (data->kind == max6646)
> -		data->temp8[nr] = temp_to_u8(val);
> +		data->temp8[index] = temp_to_u8(val);
>   	else
> -		data->temp8[nr] = temp_to_s8(val);
> +		data->temp8[index] = 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);
> +	lm90_select_remote_channel(data, index >= 6);
> +	i2c_smbus_write_byte_data(data->client, reg[index], data->temp8[index]);
> +	lm90_select_remote_channel(data, 0);
> +}
>
> +static void lm90_set_temp8(struct lm90_data *data, int index, long val)
> +{
> +	mutex_lock(&data->update_lock);
> +	lm90_set_temp8_locked(data, index, val);
>   	mutex_unlock(&data->update_lock);
> -	return count;
>   }
>
> -static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr,
> -			   char *buf)
> +static int lm90_get_temp11(struct lm90_data *data, int index)
>   {
> -	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
> -	struct lm90_data *data = lm90_update_device(dev);
>   	int temp;
>
> +	lm90_update(data);
> +
>   	if (data->kind == adt7461 || data->kind == tmp451)
> -		temp = temp_from_u16_adt7461(data, data->temp11[attr->index]);
> +		temp = temp_from_u16_adt7461(data, data->temp11[index]);
>   	else if (data->kind == max6646)
> -		temp = temp_from_u16(data->temp11[attr->index]);
> +		temp = temp_from_u16(data->temp11[index]);
>   	else
> -		temp = temp_from_s16(data->temp11[attr->index]);
> +		temp = temp_from_s16(data->temp11[index]);
>
>   	/* +16 degrees offset for temp2 for the LM99 */
> -	if (data->kind == lm99 &&  attr->index <= 2)
> +	if (data->kind == lm99 && index <= 2)
>   		temp += 16000;
>
> -	return sprintf(buf, "%d\n", temp);
> +	return temp;
>   }
>
> -static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
> -			  const char *buf, size_t count)
> +static void lm90_set_temp11_locked(struct lm90_data *data, int index, long val)
>   {
> -	struct {
> -		u8 high;
> -		u8 low;
> -		int channel;
> -	} reg[5] = {
> -		{ LM90_REG_W_REMOTE_LOWH, LM90_REG_W_REMOTE_LOWL, 0 },
> -		{ LM90_REG_W_REMOTE_HIGHH, LM90_REG_W_REMOTE_HIGHL, 0 },
> -		{ LM90_REG_W_REMOTE_OFFSH, LM90_REG_W_REMOTE_OFFSL, 0 },
> -		{ LM90_REG_W_REMOTE_LOWH, LM90_REG_W_REMOTE_LOWL, 1 },
> -		{ LM90_REG_W_REMOTE_HIGHH, LM90_REG_W_REMOTE_HIGHL, 1 }
> -	};

Another set of personal preference changes.

> -
> -	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;
> +	u8 high, low, channel;
>
> -	err = kstrtol(buf, 10, &val);
> -	if (err < 0)
> -		return err;
> +#define SELECT_REGS(_reg, _channel) { \
> +	high = LM90_REG_W_##_reg##H; \
> +	low = LM90_REG_W_##_reg##L; \
> +	channel = _channel; \
> +}

We have been trying to get rid of function defines such as this one.
Most of the time it increases code size, and reduces readability.
Plus, it increases the amount of time we have to spend reviewing
the code to ensure it is correct.

> +	switch (index) {
> +	case REMOTE_LOW:    SELECT_REGS(REMOTE_LOW,  0); break;
> +	case REMOTE_HIGH:   SELECT_REGS(REMOTE_HIGH, 0); break;
> +	case REMOTE_OFFSET: SELECT_REGS(REMOTE_OFFS, 0); break;
> +	case REMOTE2_LOW:   SELECT_REGS(REMOTE_LOW,  1); break;
> +	case REMOTE2_HIGH:  SELECT_REGS(REMOTE_HIGH, 1); break;
> +	default: return;

... and, in this case, introduces checkpatch errors.

This patch is clearly more than what its headline says. It is
too complex to review as single patch. Please split into
logical changes, and explain why you make those changes.

Thanks,
Guenter


> +	}
> +#undef SELECT_REGS
>
>   	/* +16 degrees offset for temp2 for the LM99 */
>   	if (data->kind == lm99 && index <= 2)
>   		val -= 16000;
>
> -	mutex_lock(&data->update_lock);
>   	if (data->kind == adt7461 || data->kind == tmp451)
>   		data->temp11[index] = temp_to_u16_adt7461(data, val);
>   	else if (data->kind == max6646)
> @@ -887,54 +845,46 @@ static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
>   	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);
> +	lm90_select_remote_channel(data, channel);
> +	i2c_smbus_write_byte_data(client, 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);
> +		i2c_smbus_write_byte_data(client, low,
> +				data->temp11[index] & 0xff);
> +	lm90_select_remote_channel(data, 0);
> +}
>
> +static void lm90_set_temp11(struct lm90_data *data, int index, long val)
> +{
> +	mutex_lock(&data->update_lock);
> +	lm90_set_temp11_locked(data, index, val);
>   	mutex_unlock(&data->update_lock);
> -	return count;
>   }
>
> -static ssize_t show_temphyst(struct device *dev,
> -			     struct device_attribute *devattr,
> -			     char *buf)
> +static ssize_t lm90_get_temphyst(struct lm90_data *data, int index)
>   {
> -	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
> -	struct lm90_data *data = lm90_update_device(dev);
>   	int temp;
>
> +	lm90_update(data);
> +
>   	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 - temp_from_s8(data->temp_hyst));
> +	return temp - temp_from_s8(data->temp_hyst);
>   }
>
> -static ssize_t set_temphyst(struct device *dev, struct device_attribute *dummy,
> -			    const char *buf, size_t count)
> +static void lm90_set_temphyst_locked(struct lm90_data *data, long val)
>   {
> -	struct lm90_data *data = dev_get_drvdata(dev);
> -	struct i2c_client *client = data->client;
> -	long val;
> -	int err;
>   	int temp;
>
> -	err = kstrtol(buf, 10, &val);
> -	if (err < 0)
> -		return err;
> -
> -	mutex_lock(&data->update_lock);
>   	if (data->kind == adt7461 || data->kind == tmp451)
>   		temp = temp_from_u8_adt7461(data, data->temp8[LOCAL_CRIT]);
>   	else if (data->kind == max6646)
> @@ -943,43 +893,167 @@ static ssize_t set_temphyst(struct device *dev, struct device_attribute *dummy,
>   		temp = temp_from_s8(data->temp8[LOCAL_CRIT]);
>
>   	data->temp_hyst = hyst_to_reg(temp - val);
> -	i2c_smbus_write_byte_data(client, LM90_REG_W_TCRIT_HYST,
> -				  data->temp_hyst);
> +	i2c_smbus_write_byte_data(data->client, LM90_REG_W_TCRIT_HYST,
> +			data->temp_hyst);
> +}
> +
> +static void lm90_set_temphyst(struct lm90_data *data, long val)
> +{
> +	mutex_lock(&data->update_lock);
> +	lm90_set_temphyst_locked(data, val);
> +	mutex_unlock(&data->update_lock);
> +}
> +
> +static void lm90_set_convrate_locked(struct lm90_data *data, unsigned int val)
> +{
> +	int i;
> +	unsigned int update_interval;
> +
> +	/* Shift calculations to avoid rounding errors */
> +	val <<= 6;
> +
> +	/* find the nearest update rate */
> +	for (i = 0, update_interval = LM90_MAX_CONVRATE_MS << 6;
> +	     i < data->max_convrate; i++, update_interval >>= 1)
> +		if (val >= update_interval * 3 / 4)
> +			break;
> +
> +	i2c_smbus_write_byte_data(data->client, LM90_REG_W_CONVRATE, i);
> +	data->update_interval = DIV_ROUND_CLOSEST(update_interval, 64);
> +}
> +
> +static void lm90_set_convrate(struct lm90_data *data, unsigned int val)
> +{
> +	mutex_lock(&data->update_lock);
> +	lm90_set_convrate_locked(data, val);
>   	mutex_unlock(&data->update_lock);
> +}
> +
> +/*
> + * Sysfs stuff
> + */
> +
> +static ssize_t lm90_sysfs_show_temp8(
> +		struct device *dev, struct device_attribute *devattr,
> +		char *buf)
> +{
> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
> +	struct lm90_data *data = dev_get_drvdata(dev);
> +
> +	return sprintf(buf, "%d\n", lm90_get_temp8(data, attr->index));
> +}
> +
> +static ssize_t lm90_sysfs_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);
> +	struct lm90_data *data = dev_get_drvdata(dev);
> +	long val;
> +	int err;
> +
> +	err = kstrtol(buf, 10, &val);
> +	if (err < 0)
> +		return err;
> +
> +	lm90_set_temp8(data, attr->index, val);
> +
>   	return count;
>   }
>
> -static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy,
> -			   char *buf)
> +static ssize_t lm90_sysfs_show_temp11(
> +		struct device *dev, struct device_attribute *devattr,
> +		char *buf)
> +{
> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
> +	struct lm90_data *data = dev_get_drvdata(dev);
> +
> +	return sprintf(buf, "%d\n", lm90_get_temp11(data, attr->index));
> +}
> +
> +static ssize_t lm90_sysfs_set_temp11(
> +		struct device *dev, struct device_attribute *devattr,
> +		const char *buf, size_t count)
>   {
> -	struct lm90_data *data = lm90_update_device(dev);
> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
> +	struct lm90_data *data = dev_get_drvdata(dev);
> +	long val;
> +	int err;
> +
> +	err = kstrtol(buf, 10, &val);
> +	if (err < 0)
> +		return err;
> +
> +	lm90_set_temp11(data, attr->index, val);
> +
> +	return count;
> +}
> +
> +static ssize_t lm90_sysfs_show_temphyst(
> +		struct device *dev, struct device_attribute *devattr,
> +		char *buf)
> +{
> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
> +	struct lm90_data *data = dev_get_drvdata(dev);
> +
> +	return sprintf(buf, "%d\n", lm90_get_temphyst(data, attr->index));
> +}
> +
> +static ssize_t lm90_sysfs_set_temphyst(
> +		struct device *dev, struct device_attribute *dummy,
> +		const char *buf, size_t count)
> +{
> +	struct lm90_data *data = dev_get_drvdata(dev);
> +	long val;
> +	int err;
> +
> +	err = kstrtol(buf, 10, &val);
> +	if (err < 0)
> +		return err;
> +
> +	lm90_set_temphyst(data, val);
> +
> +	return count;
> +}
> +
> +static ssize_t lm90_sysfs_show_alarms(
> +		struct device *dev, struct device_attribute *dummy,
> +		char *buf)
> +{
> +	struct lm90_data *data = dev_get_drvdata(dev);
> +
> +	lm90_update(data);
> +
>   	return sprintf(buf, "%d\n", data->alarms);
>   }
>
> -static ssize_t show_alarm(struct device *dev, struct device_attribute
> -			  *devattr, char *buf)
> +static ssize_t lm90_sysfs_show_alarm(
> +		struct device *dev, struct device_attribute *devattr,
> +		char *buf)
>   {
>   	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
> -	struct lm90_data *data = lm90_update_device(dev);
> +	struct lm90_data *data = dev_get_drvdata(dev);
>   	int bitnr = attr->index;
>
> +	lm90_update(data);
> +
>   	return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1);
>   }
>
> -static ssize_t show_update_interval(struct device *dev,
> -				    struct device_attribute *attr, char *buf)
> +static ssize_t lm90_sysfs_show_update_interval(
> +		struct device *dev, struct device_attribute *attr,
> +		char *buf)
>   {
>   	struct lm90_data *data = dev_get_drvdata(dev);
>
>   	return sprintf(buf, "%u\n", data->update_interval);
>   }
>
> -static ssize_t set_update_interval(struct device *dev,
> -				   struct device_attribute *attr,
> -				   const char *buf, size_t count)
> +static ssize_t lm90_sysfs_set_update_interval(
> +		struct device *dev, struct device_attribute *attr,
> +		const char *buf, size_t count)
>   {
>   	struct lm90_data *data = dev_get_drvdata(dev);
> -	struct i2c_client *client = data->client;
>   	unsigned long val;
>   	int err;
>
> @@ -987,49 +1061,55 @@ static ssize_t set_update_interval(struct device *dev,
>   	if (err)
>   		return err;
>
> -	mutex_lock(&data->update_lock);
> -	lm90_set_convrate(client, data, clamp_val(val, 0, 100000));
> -	mutex_unlock(&data->update_lock);
> +	lm90_set_convrate(data, clamp_val(val, 0, 100000));
>
>   	return count;
>   }
>
> -static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp11, NULL,
> -	0, LOCAL_TEMP);
> -static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp11, NULL,
> -	0, REMOTE_TEMP);
> -static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp8,
> -	set_temp8, LOCAL_LOW);
> -static SENSOR_DEVICE_ATTR_2(temp2_min, S_IWUSR | S_IRUGO, show_temp11,
> -	set_temp11, 0, REMOTE_LOW);
> -static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp8,
> -	set_temp8, LOCAL_HIGH);
> -static SENSOR_DEVICE_ATTR_2(temp2_max, S_IWUSR | S_IRUGO, show_temp11,
> -	set_temp11, 1, REMOTE_HIGH);
> -static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp8,
> -	set_temp8, LOCAL_CRIT);
> -static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp8,
> -	set_temp8, REMOTE_CRIT);
> -static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temphyst,
> -	set_temphyst, LOCAL_CRIT);
> -static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL,
> -	REMOTE_CRIT);
> -static SENSOR_DEVICE_ATTR_2(temp2_offset, S_IWUSR | S_IRUGO, show_temp11,
> -	set_temp11, 2, REMOTE_OFFSET);
> +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
> +	lm90_sysfs_show_temp11, NULL, LOCAL_TEMP);
> +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO,
> +	lm90_sysfs_show_temp11, NULL, REMOTE_TEMP);
> +static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
> +	lm90_sysfs_show_temp8, lm90_sysfs_set_temp8, LOCAL_LOW);
> +static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO,
> +	lm90_sysfs_show_temp11, lm90_sysfs_set_temp11, REMOTE_LOW);
> +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
> +	lm90_sysfs_show_temp8, lm90_sysfs_set_temp8, LOCAL_HIGH);
> +static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO,
> +	lm90_sysfs_show_temp11, lm90_sysfs_set_temp11, REMOTE_HIGH);
> +static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
> +	lm90_sysfs_show_temp8, lm90_sysfs_set_temp8, LOCAL_CRIT);
> +static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO,
> +	lm90_sysfs_show_temp8, lm90_sysfs_set_temp8, REMOTE_CRIT);
> +static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO,
> +	lm90_sysfs_show_temphyst, lm90_sysfs_set_temphyst, LOCAL_CRIT);
> +static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO,
> +	lm90_sysfs_show_temphyst, NULL, REMOTE_CRIT);
> +static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO,
> +	lm90_sysfs_show_temp11, lm90_sysfs_set_temp11, REMOTE_OFFSET);
>
>   /* Individual alarm files */
> -static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
> -static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
> -static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2);
> -static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
> -static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
> -static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 5);
> -static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
> +static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO,
> +	lm90_sysfs_show_alarm, NULL, 0);
> +static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO,
> +	lm90_sysfs_show_alarm, NULL, 1);
> +static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO,
> +	lm90_sysfs_show_alarm, NULL, 2);
> +static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO,
> +	lm90_sysfs_show_alarm, NULL, 3);
> +static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO,
> +	lm90_sysfs_show_alarm, NULL, 4);
> +static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO,
> +	lm90_sysfs_show_alarm, NULL, 5);
> +static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO,
> +	lm90_sysfs_show_alarm, NULL, 6);
>   /* Raw alarm file for compatibility */
> -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
> +static DEVICE_ATTR(alarms, S_IRUGO,
> +	lm90_sysfs_show_alarms, NULL);
>
> -static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval,
> -		   set_update_interval);
> +static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR,
> +	lm90_sysfs_show_update_interval, lm90_sysfs_set_update_interval);
>
>   static struct attribute *lm90_attributes[] = {
>   	&sensor_dev_attr_temp1_input.dev_attr.attr,
> @@ -1071,14 +1151,14 @@ static const struct attribute_group lm90_temp2_offset_group = {
>   /*
>    * Additional attributes for devices with emergency sensors
>    */
> -static SENSOR_DEVICE_ATTR(temp1_emergency, S_IWUSR | S_IRUGO, show_temp8,
> -	set_temp8, LOCAL_EMERG);
> -static SENSOR_DEVICE_ATTR(temp2_emergency, S_IWUSR | S_IRUGO, show_temp8,
> -	set_temp8, REMOTE_EMERG);
> -static SENSOR_DEVICE_ATTR(temp1_emergency_hyst, S_IRUGO, show_temphyst,
> -			  NULL, LOCAL_EMERG);
> -static SENSOR_DEVICE_ATTR(temp2_emergency_hyst, S_IRUGO, show_temphyst,
> -			  NULL, REMOTE_EMERG);
> +static SENSOR_DEVICE_ATTR(temp1_emergency, S_IWUSR | S_IRUGO,
> +	lm90_sysfs_show_temp8, lm90_sysfs_set_temp8, LOCAL_EMERG);
> +static SENSOR_DEVICE_ATTR(temp2_emergency, S_IWUSR | S_IRUGO,
> +	lm90_sysfs_show_temp8, lm90_sysfs_set_temp8, REMOTE_EMERG);
> +static SENSOR_DEVICE_ATTR(temp1_emergency_hyst, S_IRUGO,
> +	lm90_sysfs_show_temphyst, NULL, LOCAL_EMERG);
> +static SENSOR_DEVICE_ATTR(temp2_emergency_hyst, S_IRUGO,
> +	lm90_sysfs_show_temphyst, NULL, REMOTE_EMERG);
>
>   static struct attribute *lm90_emergency_attributes[] = {
>   	&sensor_dev_attr_temp1_emergency.dev_attr.attr,
> @@ -1092,8 +1172,10 @@ static const struct attribute_group lm90_emergency_group = {
>   	.attrs = lm90_emergency_attributes,
>   };
>
> -static SENSOR_DEVICE_ATTR(temp1_emergency_alarm, S_IRUGO, show_alarm, NULL, 15);
> -static SENSOR_DEVICE_ATTR(temp2_emergency_alarm, S_IRUGO, show_alarm, NULL, 13);
> +static SENSOR_DEVICE_ATTR(temp1_emergency_alarm, S_IRUGO,
> +	lm90_sysfs_show_alarm, NULL, 15);
> +static SENSOR_DEVICE_ATTR(temp2_emergency_alarm, S_IRUGO,
> +	lm90_sysfs_show_alarm, NULL, 13);
>
>   static struct attribute *lm90_emergency_alarm_attributes[] = {
>   	&sensor_dev_attr_temp1_emergency_alarm.dev_attr.attr,
> @@ -1108,26 +1190,31 @@ static const struct attribute_group lm90_emergency_alarm_group = {
>   /*
>    * Additional attributes for devices with 3 temperature sensors
>    */
> -static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp11, NULL,
> -	0, REMOTE2_TEMP);
> -static SENSOR_DEVICE_ATTR_2(temp3_min, S_IWUSR | S_IRUGO, show_temp11,
> -	set_temp11, 3, REMOTE2_LOW);
> -static SENSOR_DEVICE_ATTR_2(temp3_max, S_IWUSR | S_IRUGO, show_temp11,
> -	set_temp11, 4, REMOTE2_HIGH);
> -static SENSOR_DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_temp8,
> -	set_temp8, REMOTE2_CRIT);
> -static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO, show_temphyst, NULL,
> -	REMOTE2_CRIT);
> -static SENSOR_DEVICE_ATTR(temp3_emergency, S_IWUSR | S_IRUGO, show_temp8,
> -	set_temp8, REMOTE2_EMERG);
> -static SENSOR_DEVICE_ATTR(temp3_emergency_hyst, S_IRUGO, show_temphyst,
> -			  NULL, REMOTE2_EMERG);
> -
> -static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 9);
> -static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 10);
> -static SENSOR_DEVICE_ATTR(temp3_min_alarm, S_IRUGO, show_alarm, NULL, 11);
> -static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL, 12);
> -static SENSOR_DEVICE_ATTR(temp3_emergency_alarm, S_IRUGO, show_alarm, NULL, 14);
> +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO,
> +	lm90_sysfs_show_temp11, NULL, REMOTE2_TEMP);
> +static SENSOR_DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO,
> +	lm90_sysfs_show_temp11, lm90_sysfs_set_temp11, REMOTE2_LOW);
> +static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO,
> +	lm90_sysfs_show_temp11, lm90_sysfs_set_temp11, REMOTE2_HIGH);
> +static SENSOR_DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO,
> +	lm90_sysfs_show_temp8, lm90_sysfs_set_temp8, REMOTE2_CRIT);
> +static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO,
> +	lm90_sysfs_show_temphyst, NULL, REMOTE2_CRIT);
> +static SENSOR_DEVICE_ATTR(temp3_emergency, S_IWUSR | S_IRUGO,
> +	lm90_sysfs_show_temp8, lm90_sysfs_set_temp8, REMOTE2_EMERG);
> +static SENSOR_DEVICE_ATTR(temp3_emergency_hyst, S_IRUGO,
> +	lm90_sysfs_show_temphyst, NULL, REMOTE2_EMERG);
> +
> +static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO,
> +	lm90_sysfs_show_alarm, NULL, 9);
> +static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO,
> +	lm90_sysfs_show_alarm, NULL, 10);
> +static SENSOR_DEVICE_ATTR(temp3_min_alarm, S_IRUGO,
> +	lm90_sysfs_show_alarm, NULL, 11);
> +static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO,
> +	lm90_sysfs_show_alarm, NULL, 12);
> +static SENSOR_DEVICE_ATTR(temp3_emergency_alarm, S_IRUGO,
> +	lm90_sysfs_show_alarm, NULL, 14);
>
>   static struct attribute *lm90_temp3_attributes[] = {
>   	&sensor_dev_attr_temp3_input.dev_attr.attr,
> @@ -1151,15 +1238,15 @@ static const struct attribute_group lm90_temp3_group = {
>   };
>
>   /* pec used for ADM1032 only */
> -static ssize_t show_pec(struct device *dev, struct device_attribute *dummy,
> -			char *buf)
> +static ssize_t lm90_sysfs_show_pec(struct device *dev,
> +		struct device_attribute *dummy, char *buf)
>   {
>   	struct i2c_client *client = to_i2c_client(dev);
>   	return sprintf(buf, "%d\n", !!(client->flags & I2C_CLIENT_PEC));
>   }
>
> -static ssize_t set_pec(struct device *dev, struct device_attribute *dummy,
> -		       const char *buf, size_t count)
> +static ssize_t lm90_sysfs_set_pec(struct device *dev,
> +		struct device_attribute *dummy, const char *buf, size_t count)
>   {
>   	struct i2c_client *client = to_i2c_client(dev);
>   	long val;
> @@ -1183,7 +1270,8 @@ static ssize_t set_pec(struct device *dev, struct device_attribute *dummy,
>   	return count;
>   }
>
> -static DEVICE_ATTR(pec, S_IWUSR | S_IRUGO, show_pec, set_pec);
> +static DEVICE_ATTR(pec, S_IWUSR | S_IRUGO,
> +	lm90_sysfs_show_pec, lm90_sysfs_set_pec);
>
>   /*
>    * Real code
> @@ -1413,8 +1501,9 @@ static void lm90_restore_conf(struct i2c_client *client, struct lm90_data *data)
>   				  data->config_orig);
>   }
>
> -static void lm90_init_client(struct i2c_client *client, struct lm90_data *data)
> +static void lm90_init_client(struct lm90_data *data)
>   {
> +	struct i2c_client *client = data->client;
>   	u8 config, convrate;
>
>   	if (lm90_read_reg(client, LM90_REG_R_CONVRATE, &convrate) < 0) {
> @@ -1426,7 +1515,7 @@ static void lm90_init_client(struct i2c_client *client, struct lm90_data *data)
>   	/*
>   	 * Start the conversions.
>   	 */
> -	lm90_set_convrate(client, data, 500);	/* 500ms; 2Hz conversion rate */
> +	lm90_set_convrate_locked(data, 500);  /* 500ms / 2Hz  */
>   	if (lm90_read_reg(client, LM90_REG_R_CONFIG1, &config) < 0) {
>   		dev_warn(&client->dev, "Initialization failed!\n");
>   		return;
> @@ -1557,7 +1646,7 @@ static int lm90_probe(struct i2c_client *client,
>   	data->max_convrate = lm90_params[data->kind].max_convrate;
>
>   	/* Initialize the LM90 chip */
> -	lm90_init_client(client, data);
> +	lm90_init_client(data);
>
>   	/* Register sysfs hooks */
>   	data->groups[groups++] = &lm90_group;
>

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [lm-sensors] [PATCH 1/3] lm90: separate register accessors from sysfs
@ 2016-01-22 14:42         ` Guenter Roeck
  0 siblings, 0 replies; 23+ messages in thread
From: Guenter Roeck @ 2016-01-22 14:42 UTC (permalink / raw)
  To: Stéphan Kochen, Jean Delvare
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

T24gMDEvMjEvMjAxNiAxMTozNCBBTSwgU3TDqXBoYW4gS29jaGVuIHdyb3RlOgo+IEFkZCBhZGRp
dGlvbmFsIHN1cHBvcnQgZnVuY3Rpb25zIGBsbTkwX2dldF8qYCBhbmQgYGxtOTBfc2V0XypgIGV4
dHJhY3RlZAo+IGZyb20gdGhlIHN5c2ZzIHJvdXRpbmVzLiBUaGUgc3lzZnMgcm91dGluZXMgYXJl
IG5vdyBqdXN0IHN0dWJzIHdyYXBwaW5nCj4gdGhlIG5ldyBzdXBwb3J0IGZ1bmN0aW9ucy4KPgo+
IFRoaXMgd2F5IHdlIGhhdmUgYSBjb25zaXN0ZW50IHJlZ2lzdGVyIGFjY2VzcyBpbnRlcmZhY2Us
IHdoaWNoIGNhbiBiZQo+IHVzZWQgZnJvbSBvdGhlciBpbnRlZ3JhdGlvbnMgZG93biB0aGUgbGlu
ZS4gVG8gYXZvaWQgY29uZnVzaW9uLCBhbGwKPiBzeXNmcyBtZXRob2RzIGFyZSBub3cgcHJlZml4
ZWQgYGxtOTBfc3lzZnNfKmAuCj4KPiBUbyBhY2NvbXBsaXNoIHRoaXMsIHRoZSBgbG05MF91cGRh
dGVfZGV2aWNlYCBzaWduYXR1cmUgaGFzIGNoYW5nZWQgYW5kCj4gaXMgbm93IGBsbTkwX3VwZGF0
ZWAsIHRha2luZyBkYXRhIGRpcmVjdGx5LiBJdCBubyBsb25nZXIgc2VydmVzIHRoZQo+IGR1YWwg
cHVycG9zZSBvZiB1cGRhdGUgZnVuY3Rpb24gKmFuZCogZHJpdmVyIGRhdGEgZ2V0dGVyLgo+Cj4g
YGxtOTBfc2V0X2NvbnZyYXRlYCwgYGxtOTBfc2VsZWN0X3JlbW90ZV9jaGFubmVsYCBhbmQgYGxt
OTBfaW5pdF9jbGllbnRgCj4gYWxzbyBoYWQgcmVkdW5kYW50IGkyYyBjbGllbnQgcGFyYW1ldGVy
cywgd2hpY2ggaGF2ZSBiZWVuIHJlbW92ZWQuCj4KPiBTaWduZWQtb2ZmLWJ5OiBTdMOpcGhhbiBL
b2NoZW4gPHN0ZXBoYW5Aa29jaGVuLm5sPgo+IC0tLQo+ICAgZHJpdmVycy9od21vbi9sbTkwLmMg
fCA1MTEgKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrLS0tLS0tLS0tLS0tLS0tLS0tLS0t
Cj4gICAxIGZpbGUgY2hhbmdlZCwgMzAwIGluc2VydGlvbnMoKyksIDIxMSBkZWxldGlvbnMoLSkK
Pgo+IGRpZmYgLS1naXQgYS9kcml2ZXJzL2h3bW9uL2xtOTAuYyBiL2RyaXZlcnMvaHdtb24vbG05
MC5jCj4gaW5kZXggYzlmZjA4ZC4uODhkYWY3MiAxMDA2NDQKPiAtLS0gYS9kcml2ZXJzL2h3bW9u
L2xtOTAuYwo+ICsrKyBiL2RyaXZlcnMvaHdtb24vbG05MC5jCj4gQEAgLTQ3MywxMCArNDczLDEw
IEBAIHN0YXRpYyBpbnQgbG05MF9yZWFkMTYoc3RydWN0IGkyY19jbGllbnQgKmNsaWVudCwgdTgg
cmVnaCwgdTggcmVnbCwgdTE2ICp2YWx1ZSkKPiAgICAqIHZhcmlvdXMgcmVnaXN0ZXJzIGhhdmUg
ZGlmZmVyZW50IG1lYW5pbmdzIGFzIGEgcmVzdWx0IG9mIHNlbGVjdGluZyBhCj4gICAgKiBub24t
ZGVmYXVsdCByZW1vdGUgY2hhbm5lbC4KPiAgICAqLwo+IC1zdGF0aWMgaW5saW5lIHZvaWQgbG05
MF9zZWxlY3RfcmVtb3RlX2NoYW5uZWwoc3RydWN0IGkyY19jbGllbnQgKmNsaWVudCwKPiAtCQkJ
CQkgICAgICBzdHJ1Y3QgbG05MF9kYXRhICpkYXRhLAo+IC0JCQkJCSAgICAgIGludCBjaGFubmVs
KQo+ICtzdGF0aWMgaW5saW5lIHZvaWQgbG05MF9zZWxlY3RfcmVtb3RlX2NoYW5uZWwoCj4gKwkJ
c3RydWN0IGxtOTBfZGF0YSAqZGF0YSwgaW50IGNoYW5uZWwpCgpWZXJ5IG11Y2ggcGVyc29uYWwg
cHJlZmVyZW5jZSBoZXJlLCB1bnJlbGF0ZWQgY2hhbmdlLCBhbmQgdmlvbGF0ZXMgY29kaW5nIHN0
eWxlLgoKUGxlYXNlIG9ubHkgb25lIGxvZ2ljYWwgY2hhbmdlIHBlciBwYXRjaC4gSWYgeW91IHRo
aW5rIGl0IGlzIHdvcnRod2hpbGUgdG8gcmVtb3ZlCnRoZSBjbGllbnQgYXJndW1lbnQsIHByZXBh
cmUgYSBzZXBhcmF0ZSBwYXRjaCB3aXRoIG9ubHkgdGhhdCBjaGFuZ2UsIGFuZCBzaG93CnRoYXQg
aXQgcmVkdWNlcyBjb2RlIHNpemUuIEFsc28gcGxlYXNlIG1ha2Ugc3VyZSB0aGF0IHlvdXIgcGF0
Y2ggZm9sbG93cwpjb2Rpbmcgc3R5bGUuCgo+ICAgewo+ICsJc3RydWN0IGkyY19jbGllbnQgKmNs
aWVudCA9IGRhdGEtPmNsaWVudDsKPiAgIAl1OCBjb25maWc7Cj4KPiAgIAlpZiAoZGF0YS0+a2lu
ZCA9PSBtYXg2Njk2KSB7Cj4gQEAgLTQ5MCwzMiArNDkwLDEwIEBAIHN0YXRpYyBpbmxpbmUgdm9p
ZCBsbTkwX3NlbGVjdF9yZW1vdGVfY2hhbm5lbChzdHJ1Y3QgaTJjX2NsaWVudCAqY2xpZW50LAo+
ICAgfQo+Cj4gICAvKgo+IC0gKiBTZXQgY29udmVyc2lvbiByYXRlLgo+IC0gKiBjbGllbnQtPnVw
ZGF0ZV9sb2NrIG11c3QgYmUgaGVsZCB3aGVuIGNhbGxpbmcgdGhpcyBmdW5jdGlvbiAodW5sZXNz
IHdlIGFyZQo+IC0gKiBpbiBkZXRlY3Rpb24gb3IgaW5pdGlhbGl6YXRpb24gc3RlcHMpLgo+ICsg
KiBVcGRhdGUgYWxsIGN1cnJlbnQgcmVnaXN0ZXIgdmFsdWVzCj4gICAgKi8KPiAtc3RhdGljIHZv
aWQgbG05MF9zZXRfY29udnJhdGUoc3RydWN0IGkyY19jbGllbnQgKmNsaWVudCwgc3RydWN0IGxt
OTBfZGF0YSAqZGF0YSwKPiAtCQkJICAgICAgdW5zaWduZWQgaW50IGludGVydmFsKQo+IC17Cj4g
LQlpbnQgaTsKPiAtCXVuc2lnbmVkIGludCB1cGRhdGVfaW50ZXJ2YWw7Cj4gLQo+IC0JLyogU2hp
ZnQgY2FsY3VsYXRpb25zIHRvIGF2b2lkIHJvdW5kaW5nIGVycm9ycyAqLwo+IC0JaW50ZXJ2YWwg
PDw9IDY7Cj4gLQo+IC0JLyogZmluZCB0aGUgbmVhcmVzdCB1cGRhdGUgcmF0ZSAqLwo+IC0JZm9y
IChpID0gMCwgdXBkYXRlX2ludGVydmFsID0gTE05MF9NQVhfQ09OVlJBVEVfTVMgPDwgNjsKPiAt
CSAgICAgaSA8IGRhdGEtPm1heF9jb252cmF0ZTsgaSsrLCB1cGRhdGVfaW50ZXJ2YWwgPj49IDEp
Cj4gLQkJaWYgKGludGVydmFsID49IHVwZGF0ZV9pbnRlcnZhbCAqIDMgLyA0KQo+IC0JCQlicmVh
azsKPiAtCj4gLQlpMmNfc21idXNfd3JpdGVfYnl0ZV9kYXRhKGNsaWVudCwgTE05MF9SRUdfV19D
T05WUkFURSwgaSk7Cj4gLQlkYXRhLT51cGRhdGVfaW50ZXJ2YWwgPSBESVZfUk9VTkRfQ0xPU0VT
VCh1cGRhdGVfaW50ZXJ2YWwsIDY0KTsKPiAtfQo+IC0KPiAtc3RhdGljIHN0cnVjdCBsbTkwX2Rh
dGEgKmxtOTBfdXBkYXRlX2RldmljZShzdHJ1Y3QgZGV2aWNlICpkZXYpCj4gK3N0YXRpYyB2b2lk
IGxtOTBfdXBkYXRlKHN0cnVjdCBsbTkwX2RhdGEgKmRhdGEpCj4gICB7Cj4gLQlzdHJ1Y3QgbG05
MF9kYXRhICpkYXRhID0gZGV2X2dldF9kcnZkYXRhKGRldik7Cj4gICAJc3RydWN0IGkyY19jbGll
bnQgKmNsaWVudCA9IGRhdGEtPmNsaWVudDsKPiAgIAl1bnNpZ25lZCBsb25nIG5leHRfdXBkYXRl
Owo+Cj4gQEAgLTU4Myw3ICs1NjEsNyBAQCBzdGF0aWMgc3RydWN0IGxtOTBfZGF0YSAqbG05MF91
cGRhdGVfZGV2aWNlKHN0cnVjdCBkZXZpY2UgKmRldikKPiAgIAkJZGF0YS0+YWxhcm1zID0gYWxh
cm1zOwkvKiBzYXZlIGFzIDE2IGJpdCB2YWx1ZSAqLwo+Cj4gICAJCWlmIChkYXRhLT5raW5kID09
IG1heDY2OTYpIHsKPiAtCQkJbG05MF9zZWxlY3RfcmVtb3RlX2NoYW5uZWwoY2xpZW50LCBkYXRh
LCAxKTsKPiArCQkJbG05MF9zZWxlY3RfcmVtb3RlX2NoYW5uZWwoZGF0YSwgMSk7Cj4gICAJCQls
bTkwX3JlYWRfcmVnKGNsaWVudCwgTE05MF9SRUdfUl9SRU1PVEVfQ1JJVCwKPiAgIAkJCQkgICAg
ICAmZGF0YS0+dGVtcDhbUkVNT1RFMl9DUklUXSk7Cj4gICAJCQlsbTkwX3JlYWRfcmVnKGNsaWVu
dCwgTUFYNjY1OV9SRUdfUl9SRU1PVEVfRU1FUkcsCj4gQEAgLTU5NSw3ICs1NzMsNyBAQCBzdGF0
aWMgc3RydWN0IGxtOTBfZGF0YSAqbG05MF91cGRhdGVfZGV2aWNlKHN0cnVjdCBkZXZpY2UgKmRl
dikKPiAgIAkJCQlkYXRhLT50ZW1wMTFbUkVNT1RFMl9MT1ddID0gaCA8PCA4Owo+ICAgCQkJaWYg
KCFsbTkwX3JlYWRfcmVnKGNsaWVudCwgTE05MF9SRUdfUl9SRU1PVEVfSElHSEgsICZoKSkKPiAg
IAkJCQlkYXRhLT50ZW1wMTFbUkVNT1RFMl9ISUdIXSA9IGggPDwgODsKPiAtCQkJbG05MF9zZWxl
Y3RfcmVtb3RlX2NoYW5uZWwoY2xpZW50LCBkYXRhLCAwKTsKPiArCQkJbG05MF9zZWxlY3RfcmVt
b3RlX2NoYW5uZWwoZGF0YSwgMCk7Cj4KPiAgIAkJCWlmICghbG05MF9yZWFkX3JlZyhjbGllbnQs
IE1BWDY2OTZfUkVHX1JfU1RBVFVTMiwKPiAgIAkJCQkJICAgJmFsYXJtcykpCj4gQEAgLTYyNCw4
ICs2MDIsNiBAQCBzdGF0aWMgc3RydWN0IGxtOTBfZGF0YSAqbG05MF91cGRhdGVfZGV2aWNlKHN0
cnVjdCBkZXZpY2UgKmRldikKPiAgIAl9Cj4KPiAgIAltdXRleF91bmxvY2soJmRhdGEtPnVwZGF0
ZV9sb2NrKTsKPiAtCj4gLQlyZXR1cm4gZGF0YTsKPiAgIH0KPgo+ICAgLyoKPiBAQCAtNzU2LDMy
ICs3MzIsMzEgQEAgc3RhdGljIHUxNiB0ZW1wX3RvX3UxNl9hZHQ3NDYxKHN0cnVjdCBsbTkwX2Rh
dGEgKmRhdGEsIGxvbmcgdmFsKQo+ICAgfQo+Cj4gICAvKgo+IC0gKiBTeXNmcyBzdHVmZgo+ICsg
KiBSZWdpc3RlciBhY2Nlc3NvcnMuIEdldHRlcnMgdHJpZ2dlciBhbiB1cGRhdGUuIFNldHRlcnMg
aGF2ZSBsb2NrZWQgdmFyaWFudHMKPiArICogdGhhdCByZXF1aXJlIHVwZGF0ZV9sb2NrIHRvIGJl
IGhlbGQuCj4gICAgKi8KPgo+IC1zdGF0aWMgc3NpemVfdCBzaG93X3RlbXA4KHN0cnVjdCBkZXZp
Y2UgKmRldiwgc3RydWN0IGRldmljZV9hdHRyaWJ1dGUgKmRldmF0dHIsCj4gLQkJCSAgY2hhciAq
YnVmKQo+ICtzdGF0aWMgaW50IGxtOTBfZ2V0X3RlbXA4KHN0cnVjdCBsbTkwX2RhdGEgKmRhdGEs
IGludCBpbmRleCkKPiAgIHsKPiAtCXN0cnVjdCBzZW5zb3JfZGV2aWNlX2F0dHJpYnV0ZSAqYXR0
ciA9IHRvX3NlbnNvcl9kZXZfYXR0cihkZXZhdHRyKTsKPiAtCXN0cnVjdCBsbTkwX2RhdGEgKmRh
dGEgPSBsbTkwX3VwZGF0ZV9kZXZpY2UoZGV2KTsKPiAgIAlpbnQgdGVtcDsKPgo+ICsJbG05MF91
cGRhdGUoZGF0YSk7Cj4gKwo+ICAgCWlmIChkYXRhLT5raW5kID09IGFkdDc0NjEgfHwgZGF0YS0+
a2luZCA9PSB0bXA0NTEpCj4gLQkJdGVtcCA9IHRlbXBfZnJvbV91OF9hZHQ3NDYxKGRhdGEsIGRh
dGEtPnRlbXA4W2F0dHItPmluZGV4XSk7Cj4gKwkJdGVtcCA9IHRlbXBfZnJvbV91OF9hZHQ3NDYx
KGRhdGEsIGRhdGEtPnRlbXA4W2luZGV4XSk7Cj4gICAJZWxzZSBpZiAoZGF0YS0+a2luZCA9PSBt
YXg2NjQ2KQo+IC0JCXRlbXAgPSB0ZW1wX2Zyb21fdTgoZGF0YS0+dGVtcDhbYXR0ci0+aW5kZXhd
KTsKPiArCQl0ZW1wID0gdGVtcF9mcm9tX3U4KGRhdGEtPnRlbXA4W2luZGV4XSk7Cj4gICAJZWxz
ZQo+IC0JCXRlbXAgPSB0ZW1wX2Zyb21fczgoZGF0YS0+dGVtcDhbYXR0ci0+aW5kZXhdKTsKPiAr
CQl0ZW1wID0gdGVtcF9mcm9tX3M4KGRhdGEtPnRlbXA4W2luZGV4XSk7Cj4KPiAgIAkvKiArMTYg
ZGVncmVlcyBvZmZzZXQgZm9yIHRlbXAyIGZvciB0aGUgTE05OSAqLwo+IC0JaWYgKGRhdGEtPmtp
bmQgPT0gbG05OSAmJiBhdHRyLT5pbmRleCA9PSAzKQo+ICsJaWYgKGRhdGEtPmtpbmQgPT0gbG05
OSAmJiBpbmRleCA9PSAzKQo+ICAgCQl0ZW1wICs9IDE2MDAwOwo+Cj4gLQlyZXR1cm4gc3ByaW50
ZihidWYsICIlZFxuIiwgdGVtcCk7Cj4gKwlyZXR1cm4gdGVtcDsKPiAgIH0KPgo+IC1zdGF0aWMg
c3NpemVfdCBzZXRfdGVtcDgoc3RydWN0IGRldmljZSAqZGV2LCBzdHJ1Y3QgZGV2aWNlX2F0dHJp
YnV0ZSAqZGV2YXR0ciwKPiAtCQkJIGNvbnN0IGNoYXIgKmJ1Ziwgc2l6ZV90IGNvdW50KQo+ICtz
dGF0aWMgdm9pZCBsbTkwX3NldF90ZW1wOF9sb2NrZWQoc3RydWN0IGxtOTBfZGF0YSAqZGF0YSwg
aW50IGluZGV4LCBsb25nIHZhbCkKPiAgIHsKPiAgIAlzdGF0aWMgY29uc3QgdTggcmVnW1RFTVA4
X1JFR19OVU1dID0gewo+ICAgCQlMTTkwX1JFR19XX0xPQ0FMX0xPVywKPiBAQCAtNzk0LDkwICs3
NjksNzMgQEAgc3RhdGljIHNzaXplX3Qgc2V0X3RlbXA4KHN0cnVjdCBkZXZpY2UgKmRldiwgc3Ry
dWN0IGRldmljZV9hdHRyaWJ1dGUgKmRldmF0dHIsCj4gICAJCU1BWDY2NTlfUkVHX1dfUkVNT1RF
X0VNRVJHLAo+ICAgCX07Cj4KPiAtCXN0cnVjdCBzZW5zb3JfZGV2aWNlX2F0dHJpYnV0ZSAqYXR0
ciA9IHRvX3NlbnNvcl9kZXZfYXR0cihkZXZhdHRyKTsKPiAtCXN0cnVjdCBsbTkwX2RhdGEgKmRh
dGEgPSBkZXZfZ2V0X2RydmRhdGEoZGV2KTsKPiAtCXN0cnVjdCBpMmNfY2xpZW50ICpjbGllbnQg
PSBkYXRhLT5jbGllbnQ7Cj4gLQlpbnQgbnIgPSBhdHRyLT5pbmRleDsKPiAtCWxvbmcgdmFsOwo+
IC0JaW50IGVycjsKPiAtCj4gLQllcnIgPSBrc3RydG9sKGJ1ZiwgMTAsICZ2YWwpOwo+IC0JaWYg
KGVyciA8IDApCj4gLQkJcmV0dXJuIGVycjsKPiAtCj4gICAJLyogKzE2IGRlZ3JlZXMgb2Zmc2V0
IGZvciB0ZW1wMiBmb3IgdGhlIExNOTkgKi8KPiAtCWlmIChkYXRhLT5raW5kID09IGxtOTkgJiYg
YXR0ci0+aW5kZXggPT0gMykKPiArCWlmIChkYXRhLT5raW5kID09IGxtOTkgJiYgaW5kZXggPT0g
MykKPiAgIAkJdmFsIC09IDE2MDAwOwo+Cj4gLQltdXRleF9sb2NrKCZkYXRhLT51cGRhdGVfbG9j
ayk7Cj4gICAJaWYgKGRhdGEtPmtpbmQgPT0gYWR0NzQ2MSB8fCBkYXRhLT5raW5kID09IHRtcDQ1
MSkKPiAtCQlkYXRhLT50ZW1wOFtucl0gPSB0ZW1wX3RvX3U4X2FkdDc0NjEoZGF0YSwgdmFsKTsK
PiArCQlkYXRhLT50ZW1wOFtpbmRleF0gPSB0ZW1wX3RvX3U4X2FkdDc0NjEoZGF0YSwgdmFsKTsK
PiAgIAllbHNlIGlmIChkYXRhLT5raW5kID09IG1heDY2NDYpCj4gLQkJZGF0YS0+dGVtcDhbbnJd
ID0gdGVtcF90b191OCh2YWwpOwo+ICsJCWRhdGEtPnRlbXA4W2luZGV4XSA9IHRlbXBfdG9fdTgo
dmFsKTsKPiAgIAllbHNlCj4gLQkJZGF0YS0+dGVtcDhbbnJdID0gdGVtcF90b19zOCh2YWwpOwo+
ICsJCWRhdGEtPnRlbXA4W2luZGV4XSA9IHRlbXBfdG9fczgodmFsKTsKPgo+IC0JbG05MF9zZWxl
Y3RfcmVtb3RlX2NoYW5uZWwoY2xpZW50LCBkYXRhLCBuciA+PSA2KTsKPiAtCWkyY19zbWJ1c193
cml0ZV9ieXRlX2RhdGEoY2xpZW50LCByZWdbbnJdLCBkYXRhLT50ZW1wOFtucl0pOwo+IC0JbG05
MF9zZWxlY3RfcmVtb3RlX2NoYW5uZWwoY2xpZW50LCBkYXRhLCAwKTsKPiArCWxtOTBfc2VsZWN0
X3JlbW90ZV9jaGFubmVsKGRhdGEsIGluZGV4ID49IDYpOwo+ICsJaTJjX3NtYnVzX3dyaXRlX2J5
dGVfZGF0YShkYXRhLT5jbGllbnQsIHJlZ1tpbmRleF0sIGRhdGEtPnRlbXA4W2luZGV4XSk7Cj4g
KwlsbTkwX3NlbGVjdF9yZW1vdGVfY2hhbm5lbChkYXRhLCAwKTsKPiArfQo+Cj4gK3N0YXRpYyB2
b2lkIGxtOTBfc2V0X3RlbXA4KHN0cnVjdCBsbTkwX2RhdGEgKmRhdGEsIGludCBpbmRleCwgbG9u
ZyB2YWwpCj4gK3sKPiArCW11dGV4X2xvY2soJmRhdGEtPnVwZGF0ZV9sb2NrKTsKPiArCWxtOTBf
c2V0X3RlbXA4X2xvY2tlZChkYXRhLCBpbmRleCwgdmFsKTsKPiAgIAltdXRleF91bmxvY2soJmRh
dGEtPnVwZGF0ZV9sb2NrKTsKPiAtCXJldHVybiBjb3VudDsKPiAgIH0KPgo+IC1zdGF0aWMgc3Np
emVfdCBzaG93X3RlbXAxMShzdHJ1Y3QgZGV2aWNlICpkZXYsIHN0cnVjdCBkZXZpY2VfYXR0cmli
dXRlICpkZXZhdHRyLAo+IC0JCQkgICBjaGFyICpidWYpCj4gK3N0YXRpYyBpbnQgbG05MF9nZXRf
dGVtcDExKHN0cnVjdCBsbTkwX2RhdGEgKmRhdGEsIGludCBpbmRleCkKPiAgIHsKPiAtCXN0cnVj
dCBzZW5zb3JfZGV2aWNlX2F0dHJpYnV0ZV8yICphdHRyID0gdG9fc2Vuc29yX2Rldl9hdHRyXzIo
ZGV2YXR0cik7Cj4gLQlzdHJ1Y3QgbG05MF9kYXRhICpkYXRhID0gbG05MF91cGRhdGVfZGV2aWNl
KGRldik7Cj4gICAJaW50IHRlbXA7Cj4KPiArCWxtOTBfdXBkYXRlKGRhdGEpOwo+ICsKPiAgIAlp
ZiAoZGF0YS0+a2luZCA9PSBhZHQ3NDYxIHx8IGRhdGEtPmtpbmQgPT0gdG1wNDUxKQo+IC0JCXRl
bXAgPSB0ZW1wX2Zyb21fdTE2X2FkdDc0NjEoZGF0YSwgZGF0YS0+dGVtcDExW2F0dHItPmluZGV4
XSk7Cj4gKwkJdGVtcCA9IHRlbXBfZnJvbV91MTZfYWR0NzQ2MShkYXRhLCBkYXRhLT50ZW1wMTFb
aW5kZXhdKTsKPiAgIAllbHNlIGlmIChkYXRhLT5raW5kID09IG1heDY2NDYpCj4gLQkJdGVtcCA9
IHRlbXBfZnJvbV91MTYoZGF0YS0+dGVtcDExW2F0dHItPmluZGV4XSk7Cj4gKwkJdGVtcCA9IHRl
bXBfZnJvbV91MTYoZGF0YS0+dGVtcDExW2luZGV4XSk7Cj4gICAJZWxzZQo+IC0JCXRlbXAgPSB0
ZW1wX2Zyb21fczE2KGRhdGEtPnRlbXAxMVthdHRyLT5pbmRleF0pOwo+ICsJCXRlbXAgPSB0ZW1w
X2Zyb21fczE2KGRhdGEtPnRlbXAxMVtpbmRleF0pOwo+Cj4gICAJLyogKzE2IGRlZ3JlZXMgb2Zm
c2V0IGZvciB0ZW1wMiBmb3IgdGhlIExNOTkgKi8KPiAtCWlmIChkYXRhLT5raW5kID09IGxtOTkg
JiYgIGF0dHItPmluZGV4IDw9IDIpCj4gKwlpZiAoZGF0YS0+a2luZCA9PSBsbTk5ICYmIGluZGV4
IDw9IDIpCj4gICAJCXRlbXAgKz0gMTYwMDA7Cj4KPiAtCXJldHVybiBzcHJpbnRmKGJ1ZiwgIiVk
XG4iLCB0ZW1wKTsKPiArCXJldHVybiB0ZW1wOwo+ICAgfQo+Cj4gLXN0YXRpYyBzc2l6ZV90IHNl
dF90ZW1wMTEoc3RydWN0IGRldmljZSAqZGV2LCBzdHJ1Y3QgZGV2aWNlX2F0dHJpYnV0ZSAqZGV2
YXR0ciwKPiAtCQkJICBjb25zdCBjaGFyICpidWYsIHNpemVfdCBjb3VudCkKPiArc3RhdGljIHZv
aWQgbG05MF9zZXRfdGVtcDExX2xvY2tlZChzdHJ1Y3QgbG05MF9kYXRhICpkYXRhLCBpbnQgaW5k
ZXgsIGxvbmcgdmFsKQo+ICAgewo+IC0Jc3RydWN0IHsKPiAtCQl1OCBoaWdoOwo+IC0JCXU4IGxv
dzsKPiAtCQlpbnQgY2hhbm5lbDsKPiAtCX0gcmVnWzVdID0gewo+IC0JCXsgTE05MF9SRUdfV19S
RU1PVEVfTE9XSCwgTE05MF9SRUdfV19SRU1PVEVfTE9XTCwgMCB9LAo+IC0JCXsgTE05MF9SRUdf
V19SRU1PVEVfSElHSEgsIExNOTBfUkVHX1dfUkVNT1RFX0hJR0hMLCAwIH0sCj4gLQkJeyBMTTkw
X1JFR19XX1JFTU9URV9PRkZTSCwgTE05MF9SRUdfV19SRU1PVEVfT0ZGU0wsIDAgfSwKPiAtCQl7
IExNOTBfUkVHX1dfUkVNT1RFX0xPV0gsIExNOTBfUkVHX1dfUkVNT1RFX0xPV0wsIDEgfSwKPiAt
CQl7IExNOTBfUkVHX1dfUkVNT1RFX0hJR0hILCBMTTkwX1JFR19XX1JFTU9URV9ISUdITCwgMSB9
Cj4gLQl9OwoKQW5vdGhlciBzZXQgb2YgcGVyc29uYWwgcHJlZmVyZW5jZSBjaGFuZ2VzLgoKPiAt
Cj4gLQlzdHJ1Y3Qgc2Vuc29yX2RldmljZV9hdHRyaWJ1dGVfMiAqYXR0ciA9IHRvX3NlbnNvcl9k
ZXZfYXR0cl8yKGRldmF0dHIpOwo+IC0Jc3RydWN0IGxtOTBfZGF0YSAqZGF0YSA9IGRldl9nZXRf
ZHJ2ZGF0YShkZXYpOwo+ICAgCXN0cnVjdCBpMmNfY2xpZW50ICpjbGllbnQgPSBkYXRhLT5jbGll
bnQ7Cj4gLQlpbnQgbnIgPSBhdHRyLT5ucjsKPiAtCWludCBpbmRleCA9IGF0dHItPmluZGV4Owo+
IC0JbG9uZyB2YWw7Cj4gLQlpbnQgZXJyOwo+ICsJdTggaGlnaCwgbG93LCBjaGFubmVsOwo+Cj4g
LQllcnIgPSBrc3RydG9sKGJ1ZiwgMTAsICZ2YWwpOwo+IC0JaWYgKGVyciA8IDApCj4gLQkJcmV0
dXJuIGVycjsKPiArI2RlZmluZSBTRUxFQ1RfUkVHUyhfcmVnLCBfY2hhbm5lbCkgeyBcCj4gKwlo
aWdoID0gTE05MF9SRUdfV18jI19yZWcjI0g7IFwKPiArCWxvdyA9IExNOTBfUkVHX1dfIyNfcmVn
IyNMOyBcCj4gKwljaGFubmVsID0gX2NoYW5uZWw7IFwKPiArfQoKV2UgaGF2ZSBiZWVuIHRyeWlu
ZyB0byBnZXQgcmlkIG9mIGZ1bmN0aW9uIGRlZmluZXMgc3VjaCBhcyB0aGlzIG9uZS4KTW9zdCBv
ZiB0aGUgdGltZSBpdCBpbmNyZWFzZXMgY29kZSBzaXplLCBhbmQgcmVkdWNlcyByZWFkYWJpbGl0
eS4KUGx1cywgaXQgaW5jcmVhc2VzIHRoZSBhbW91bnQgb2YgdGltZSB3ZSBoYXZlIHRvIHNwZW5k
IHJldmlld2luZwp0aGUgY29kZSB0byBlbnN1cmUgaXQgaXMgY29ycmVjdC4KCj4gKwlzd2l0Y2gg
KGluZGV4KSB7Cj4gKwljYXNlIFJFTU9URV9MT1c6ICAgIFNFTEVDVF9SRUdTKFJFTU9URV9MT1cs
ICAwKTsgYnJlYWs7Cj4gKwljYXNlIFJFTU9URV9ISUdIOiAgIFNFTEVDVF9SRUdTKFJFTU9URV9I
SUdILCAwKTsgYnJlYWs7Cj4gKwljYXNlIFJFTU9URV9PRkZTRVQ6IFNFTEVDVF9SRUdTKFJFTU9U
RV9PRkZTLCAwKTsgYnJlYWs7Cj4gKwljYXNlIFJFTU9URTJfTE9XOiAgIFNFTEVDVF9SRUdTKFJF
TU9URV9MT1csICAxKTsgYnJlYWs7Cj4gKwljYXNlIFJFTU9URTJfSElHSDogIFNFTEVDVF9SRUdT
KFJFTU9URV9ISUdILCAxKTsgYnJlYWs7Cj4gKwlkZWZhdWx0OiByZXR1cm47CgouLi4gYW5kLCBp
biB0aGlzIGNhc2UsIGludHJvZHVjZXMgY2hlY2twYXRjaCBlcnJvcnMuCgpUaGlzIHBhdGNoIGlz
IGNsZWFybHkgbW9yZSB0aGFuIHdoYXQgaXRzIGhlYWRsaW5lIHNheXMuIEl0IGlzCnRvbyBjb21w
bGV4IHRvIHJldmlldyBhcyBzaW5nbGUgcGF0Y2guIFBsZWFzZSBzcGxpdCBpbnRvCmxvZ2ljYWwg
Y2hhbmdlcywgYW5kIGV4cGxhaW4gd2h5IHlvdSBtYWtlIHRob3NlIGNoYW5nZXMuCgpUaGFua3Ms
Ckd1ZW50ZXIKCgo+ICsJfQo+ICsjdW5kZWYgU0VMRUNUX1JFR1MKPgo+ICAgCS8qICsxNiBkZWdy
ZWVzIG9mZnNldCBmb3IgdGVtcDIgZm9yIHRoZSBMTTk5ICovCj4gICAJaWYgKGRhdGEtPmtpbmQg
PT0gbG05OSAmJiBpbmRleCA8PSAyKQo+ICAgCQl2YWwgLT0gMTYwMDA7Cj4KPiAtCW11dGV4X2xv
Y2soJmRhdGEtPnVwZGF0ZV9sb2NrKTsKPiAgIAlpZiAoZGF0YS0+a2luZCA9PSBhZHQ3NDYxIHx8
IGRhdGEtPmtpbmQgPT0gdG1wNDUxKQo+ICAgCQlkYXRhLT50ZW1wMTFbaW5kZXhdID0gdGVtcF90
b191MTZfYWR0NzQ2MShkYXRhLCB2YWwpOwo+ICAgCWVsc2UgaWYgKGRhdGEtPmtpbmQgPT0gbWF4
NjY0NikKPiBAQCAtODg3LDU0ICs4NDUsNDYgQEAgc3RhdGljIHNzaXplX3Qgc2V0X3RlbXAxMShz
dHJ1Y3QgZGV2aWNlICpkZXYsIHN0cnVjdCBkZXZpY2VfYXR0cmlidXRlICpkZXZhdHRyLAo+ICAg
CWVsc2UKPiAgIAkJZGF0YS0+dGVtcDExW2luZGV4XSA9IHRlbXBfdG9fczgodmFsKSA8PCA4Owo+
Cj4gLQlsbTkwX3NlbGVjdF9yZW1vdGVfY2hhbm5lbChjbGllbnQsIGRhdGEsIHJlZ1tucl0uY2hh
bm5lbCk7Cj4gLQlpMmNfc21idXNfd3JpdGVfYnl0ZV9kYXRhKGNsaWVudCwgcmVnW25yXS5oaWdo
LAo+IC0JCQkJICBkYXRhLT50ZW1wMTFbaW5kZXhdID4+IDgpOwo+ICsJbG05MF9zZWxlY3RfcmVt
b3RlX2NoYW5uZWwoZGF0YSwgY2hhbm5lbCk7Cj4gKwlpMmNfc21idXNfd3JpdGVfYnl0ZV9kYXRh
KGNsaWVudCwgaGlnaCwKPiArCQkJZGF0YS0+dGVtcDExW2luZGV4XSA+PiA4KTsKPiAgIAlpZiAo
ZGF0YS0+ZmxhZ3MgJiBMTTkwX0hBVkVfUkVNX0xJTUlUX0VYVCkKPiAtCQlpMmNfc21idXNfd3Jp
dGVfYnl0ZV9kYXRhKGNsaWVudCwgcmVnW25yXS5sb3csCj4gLQkJCQkJICBkYXRhLT50ZW1wMTFb
aW5kZXhdICYgMHhmZik7Cj4gLQlsbTkwX3NlbGVjdF9yZW1vdGVfY2hhbm5lbChjbGllbnQsIGRh
dGEsIDApOwo+ICsJCWkyY19zbWJ1c193cml0ZV9ieXRlX2RhdGEoY2xpZW50LCBsb3csCj4gKwkJ
CQlkYXRhLT50ZW1wMTFbaW5kZXhdICYgMHhmZik7Cj4gKwlsbTkwX3NlbGVjdF9yZW1vdGVfY2hh
bm5lbChkYXRhLCAwKTsKPiArfQo+Cj4gK3N0YXRpYyB2b2lkIGxtOTBfc2V0X3RlbXAxMShzdHJ1
Y3QgbG05MF9kYXRhICpkYXRhLCBpbnQgaW5kZXgsIGxvbmcgdmFsKQo+ICt7Cj4gKwltdXRleF9s
b2NrKCZkYXRhLT51cGRhdGVfbG9jayk7Cj4gKwlsbTkwX3NldF90ZW1wMTFfbG9ja2VkKGRhdGEs
IGluZGV4LCB2YWwpOwo+ICAgCW11dGV4X3VubG9jaygmZGF0YS0+dXBkYXRlX2xvY2spOwo+IC0J
cmV0dXJuIGNvdW50Owo+ICAgfQo+Cj4gLXN0YXRpYyBzc2l6ZV90IHNob3dfdGVtcGh5c3Qoc3Ry
dWN0IGRldmljZSAqZGV2LAo+IC0JCQkgICAgIHN0cnVjdCBkZXZpY2VfYXR0cmlidXRlICpkZXZh
dHRyLAo+IC0JCQkgICAgIGNoYXIgKmJ1ZikKPiArc3RhdGljIHNzaXplX3QgbG05MF9nZXRfdGVt
cGh5c3Qoc3RydWN0IGxtOTBfZGF0YSAqZGF0YSwgaW50IGluZGV4KQo+ICAgewo+IC0Jc3RydWN0
IHNlbnNvcl9kZXZpY2VfYXR0cmlidXRlICphdHRyID0gdG9fc2Vuc29yX2Rldl9hdHRyKGRldmF0
dHIpOwo+IC0Jc3RydWN0IGxtOTBfZGF0YSAqZGF0YSA9IGxtOTBfdXBkYXRlX2RldmljZShkZXYp
Owo+ICAgCWludCB0ZW1wOwo+Cj4gKwlsbTkwX3VwZGF0ZShkYXRhKTsKPiArCj4gICAJaWYgKGRh
dGEtPmtpbmQgPT0gYWR0NzQ2MSB8fCBkYXRhLT5raW5kID09IHRtcDQ1MSkKPiAtCQl0ZW1wID0g
dGVtcF9mcm9tX3U4X2FkdDc0NjEoZGF0YSwgZGF0YS0+dGVtcDhbYXR0ci0+aW5kZXhdKTsKPiAr
CQl0ZW1wID0gdGVtcF9mcm9tX3U4X2FkdDc0NjEoZGF0YSwgZGF0YS0+dGVtcDhbaW5kZXhdKTsK
PiAgIAllbHNlIGlmIChkYXRhLT5raW5kID09IG1heDY2NDYpCj4gLQkJdGVtcCA9IHRlbXBfZnJv
bV91OChkYXRhLT50ZW1wOFthdHRyLT5pbmRleF0pOwo+ICsJCXRlbXAgPSB0ZW1wX2Zyb21fdTgo
ZGF0YS0+dGVtcDhbaW5kZXhdKTsKPiAgIAllbHNlCj4gLQkJdGVtcCA9IHRlbXBfZnJvbV9zOChk
YXRhLT50ZW1wOFthdHRyLT5pbmRleF0pOwo+ICsJCXRlbXAgPSB0ZW1wX2Zyb21fczgoZGF0YS0+
dGVtcDhbaW5kZXhdKTsKPgo+ICAgCS8qICsxNiBkZWdyZWVzIG9mZnNldCBmb3IgdGVtcDIgZm9y
IHRoZSBMTTk5ICovCj4gLQlpZiAoZGF0YS0+a2luZCA9PSBsbTk5ICYmIGF0dHItPmluZGV4ID09
IDMpCj4gKwlpZiAoZGF0YS0+a2luZCA9PSBsbTk5ICYmIGluZGV4ID09IDMpCj4gICAJCXRlbXAg
Kz0gMTYwMDA7Cj4KPiAtCXJldHVybiBzcHJpbnRmKGJ1ZiwgIiVkXG4iLCB0ZW1wIC0gdGVtcF9m
cm9tX3M4KGRhdGEtPnRlbXBfaHlzdCkpOwo+ICsJcmV0dXJuIHRlbXAgLSB0ZW1wX2Zyb21fczgo
ZGF0YS0+dGVtcF9oeXN0KTsKPiAgIH0KPgo+IC1zdGF0aWMgc3NpemVfdCBzZXRfdGVtcGh5c3Qo
c3RydWN0IGRldmljZSAqZGV2LCBzdHJ1Y3QgZGV2aWNlX2F0dHJpYnV0ZSAqZHVtbXksCj4gLQkJ
CSAgICBjb25zdCBjaGFyICpidWYsIHNpemVfdCBjb3VudCkKPiArc3RhdGljIHZvaWQgbG05MF9z
ZXRfdGVtcGh5c3RfbG9ja2VkKHN0cnVjdCBsbTkwX2RhdGEgKmRhdGEsIGxvbmcgdmFsKQo+ICAg
ewo+IC0Jc3RydWN0IGxtOTBfZGF0YSAqZGF0YSA9IGRldl9nZXRfZHJ2ZGF0YShkZXYpOwo+IC0J
c3RydWN0IGkyY19jbGllbnQgKmNsaWVudCA9IGRhdGEtPmNsaWVudDsKPiAtCWxvbmcgdmFsOwo+
IC0JaW50IGVycjsKPiAgIAlpbnQgdGVtcDsKPgo+IC0JZXJyID0ga3N0cnRvbChidWYsIDEwLCAm
dmFsKTsKPiAtCWlmIChlcnIgPCAwKQo+IC0JCXJldHVybiBlcnI7Cj4gLQo+IC0JbXV0ZXhfbG9j
aygmZGF0YS0+dXBkYXRlX2xvY2spOwo+ICAgCWlmIChkYXRhLT5raW5kID09IGFkdDc0NjEgfHwg
ZGF0YS0+a2luZCA9PSB0bXA0NTEpCj4gICAJCXRlbXAgPSB0ZW1wX2Zyb21fdThfYWR0NzQ2MShk
YXRhLCBkYXRhLT50ZW1wOFtMT0NBTF9DUklUXSk7Cj4gICAJZWxzZSBpZiAoZGF0YS0+a2luZCA9
PSBtYXg2NjQ2KQo+IEBAIC05NDMsNDMgKzg5MywxNjcgQEAgc3RhdGljIHNzaXplX3Qgc2V0X3Rl
bXBoeXN0KHN0cnVjdCBkZXZpY2UgKmRldiwgc3RydWN0IGRldmljZV9hdHRyaWJ1dGUgKmR1bW15
LAo+ICAgCQl0ZW1wID0gdGVtcF9mcm9tX3M4KGRhdGEtPnRlbXA4W0xPQ0FMX0NSSVRdKTsKPgo+
ICAgCWRhdGEtPnRlbXBfaHlzdCA9IGh5c3RfdG9fcmVnKHRlbXAgLSB2YWwpOwo+IC0JaTJjX3Nt
YnVzX3dyaXRlX2J5dGVfZGF0YShjbGllbnQsIExNOTBfUkVHX1dfVENSSVRfSFlTVCwKPiAtCQkJ
CSAgZGF0YS0+dGVtcF9oeXN0KTsKPiArCWkyY19zbWJ1c193cml0ZV9ieXRlX2RhdGEoZGF0YS0+
Y2xpZW50LCBMTTkwX1JFR19XX1RDUklUX0hZU1QsCj4gKwkJCWRhdGEtPnRlbXBfaHlzdCk7Cj4g
K30KPiArCj4gK3N0YXRpYyB2b2lkIGxtOTBfc2V0X3RlbXBoeXN0KHN0cnVjdCBsbTkwX2RhdGEg
KmRhdGEsIGxvbmcgdmFsKQo+ICt7Cj4gKwltdXRleF9sb2NrKCZkYXRhLT51cGRhdGVfbG9jayk7
Cj4gKwlsbTkwX3NldF90ZW1waHlzdF9sb2NrZWQoZGF0YSwgdmFsKTsKPiArCW11dGV4X3VubG9j
aygmZGF0YS0+dXBkYXRlX2xvY2spOwo+ICt9Cj4gKwo+ICtzdGF0aWMgdm9pZCBsbTkwX3NldF9j
b252cmF0ZV9sb2NrZWQoc3RydWN0IGxtOTBfZGF0YSAqZGF0YSwgdW5zaWduZWQgaW50IHZhbCkK
PiArewo+ICsJaW50IGk7Cj4gKwl1bnNpZ25lZCBpbnQgdXBkYXRlX2ludGVydmFsOwo+ICsKPiAr
CS8qIFNoaWZ0IGNhbGN1bGF0aW9ucyB0byBhdm9pZCByb3VuZGluZyBlcnJvcnMgKi8KPiArCXZh
bCA8PD0gNjsKPiArCj4gKwkvKiBmaW5kIHRoZSBuZWFyZXN0IHVwZGF0ZSByYXRlICovCj4gKwlm
b3IgKGkgPSAwLCB1cGRhdGVfaW50ZXJ2YWwgPSBMTTkwX01BWF9DT05WUkFURV9NUyA8PCA2Owo+
ICsJICAgICBpIDwgZGF0YS0+bWF4X2NvbnZyYXRlOyBpKyssIHVwZGF0ZV9pbnRlcnZhbCA+Pj0g
MSkKPiArCQlpZiAodmFsID49IHVwZGF0ZV9pbnRlcnZhbCAqIDMgLyA0KQo+ICsJCQlicmVhazsK
PiArCj4gKwlpMmNfc21idXNfd3JpdGVfYnl0ZV9kYXRhKGRhdGEtPmNsaWVudCwgTE05MF9SRUdf
V19DT05WUkFURSwgaSk7Cj4gKwlkYXRhLT51cGRhdGVfaW50ZXJ2YWwgPSBESVZfUk9VTkRfQ0xP
U0VTVCh1cGRhdGVfaW50ZXJ2YWwsIDY0KTsKPiArfQo+ICsKPiArc3RhdGljIHZvaWQgbG05MF9z
ZXRfY29udnJhdGUoc3RydWN0IGxtOTBfZGF0YSAqZGF0YSwgdW5zaWduZWQgaW50IHZhbCkKPiAr
ewo+ICsJbXV0ZXhfbG9jaygmZGF0YS0+dXBkYXRlX2xvY2spOwo+ICsJbG05MF9zZXRfY29udnJh
dGVfbG9ja2VkKGRhdGEsIHZhbCk7Cj4gICAJbXV0ZXhfdW5sb2NrKCZkYXRhLT51cGRhdGVfbG9j
ayk7Cj4gK30KPiArCj4gKy8qCj4gKyAqIFN5c2ZzIHN0dWZmCj4gKyAqLwo+ICsKPiArc3RhdGlj
IHNzaXplX3QgbG05MF9zeXNmc19zaG93X3RlbXA4KAo+ICsJCXN0cnVjdCBkZXZpY2UgKmRldiwg
c3RydWN0IGRldmljZV9hdHRyaWJ1dGUgKmRldmF0dHIsCj4gKwkJY2hhciAqYnVmKQo+ICt7Cj4g
KwlzdHJ1Y3Qgc2Vuc29yX2RldmljZV9hdHRyaWJ1dGUgKmF0dHIgPSB0b19zZW5zb3JfZGV2X2F0
dHIoZGV2YXR0cik7Cj4gKwlzdHJ1Y3QgbG05MF9kYXRhICpkYXRhID0gZGV2X2dldF9kcnZkYXRh
KGRldik7Cj4gKwo+ICsJcmV0dXJuIHNwcmludGYoYnVmLCAiJWRcbiIsIGxtOTBfZ2V0X3RlbXA4
KGRhdGEsIGF0dHItPmluZGV4KSk7Cj4gK30KPiArCj4gK3N0YXRpYyBzc2l6ZV90IGxtOTBfc3lz
ZnNfc2V0X3RlbXA4KAo+ICsJCXN0cnVjdCBkZXZpY2UgKmRldiwgc3RydWN0IGRldmljZV9hdHRy
aWJ1dGUgKmRldmF0dHIsCj4gKwkJY29uc3QgY2hhciAqYnVmLCBzaXplX3QgY291bnQpCj4gK3sK
PiArCXN0cnVjdCBzZW5zb3JfZGV2aWNlX2F0dHJpYnV0ZSAqYXR0ciA9IHRvX3NlbnNvcl9kZXZf
YXR0cihkZXZhdHRyKTsKPiArCXN0cnVjdCBsbTkwX2RhdGEgKmRhdGEgPSBkZXZfZ2V0X2RydmRh
dGEoZGV2KTsKPiArCWxvbmcgdmFsOwo+ICsJaW50IGVycjsKPiArCj4gKwllcnIgPSBrc3RydG9s
KGJ1ZiwgMTAsICZ2YWwpOwo+ICsJaWYgKGVyciA8IDApCj4gKwkJcmV0dXJuIGVycjsKPiArCj4g
KwlsbTkwX3NldF90ZW1wOChkYXRhLCBhdHRyLT5pbmRleCwgdmFsKTsKPiArCj4gICAJcmV0dXJu
IGNvdW50Owo+ICAgfQo+Cj4gLXN0YXRpYyBzc2l6ZV90IHNob3dfYWxhcm1zKHN0cnVjdCBkZXZp
Y2UgKmRldiwgc3RydWN0IGRldmljZV9hdHRyaWJ1dGUgKmR1bW15LAo+IC0JCQkgICBjaGFyICpi
dWYpCj4gK3N0YXRpYyBzc2l6ZV90IGxtOTBfc3lzZnNfc2hvd190ZW1wMTEoCj4gKwkJc3RydWN0
IGRldmljZSAqZGV2LCBzdHJ1Y3QgZGV2aWNlX2F0dHJpYnV0ZSAqZGV2YXR0ciwKPiArCQljaGFy
ICpidWYpCj4gK3sKPiArCXN0cnVjdCBzZW5zb3JfZGV2aWNlX2F0dHJpYnV0ZSAqYXR0ciA9IHRv
X3NlbnNvcl9kZXZfYXR0cihkZXZhdHRyKTsKPiArCXN0cnVjdCBsbTkwX2RhdGEgKmRhdGEgPSBk
ZXZfZ2V0X2RydmRhdGEoZGV2KTsKPiArCj4gKwlyZXR1cm4gc3ByaW50ZihidWYsICIlZFxuIiwg
bG05MF9nZXRfdGVtcDExKGRhdGEsIGF0dHItPmluZGV4KSk7Cj4gK30KPiArCj4gK3N0YXRpYyBz
c2l6ZV90IGxtOTBfc3lzZnNfc2V0X3RlbXAxMSgKPiArCQlzdHJ1Y3QgZGV2aWNlICpkZXYsIHN0
cnVjdCBkZXZpY2VfYXR0cmlidXRlICpkZXZhdHRyLAo+ICsJCWNvbnN0IGNoYXIgKmJ1Ziwgc2l6
ZV90IGNvdW50KQo+ICAgewo+IC0Jc3RydWN0IGxtOTBfZGF0YSAqZGF0YSA9IGxtOTBfdXBkYXRl
X2RldmljZShkZXYpOwo+ICsJc3RydWN0IHNlbnNvcl9kZXZpY2VfYXR0cmlidXRlICphdHRyID0g
dG9fc2Vuc29yX2Rldl9hdHRyKGRldmF0dHIpOwo+ICsJc3RydWN0IGxtOTBfZGF0YSAqZGF0YSA9
IGRldl9nZXRfZHJ2ZGF0YShkZXYpOwo+ICsJbG9uZyB2YWw7Cj4gKwlpbnQgZXJyOwo+ICsKPiAr
CWVyciA9IGtzdHJ0b2woYnVmLCAxMCwgJnZhbCk7Cj4gKwlpZiAoZXJyIDwgMCkKPiArCQlyZXR1
cm4gZXJyOwo+ICsKPiArCWxtOTBfc2V0X3RlbXAxMShkYXRhLCBhdHRyLT5pbmRleCwgdmFsKTsK
PiArCj4gKwlyZXR1cm4gY291bnQ7Cj4gK30KPiArCj4gK3N0YXRpYyBzc2l6ZV90IGxtOTBfc3lz
ZnNfc2hvd190ZW1waHlzdCgKPiArCQlzdHJ1Y3QgZGV2aWNlICpkZXYsIHN0cnVjdCBkZXZpY2Vf
YXR0cmlidXRlICpkZXZhdHRyLAo+ICsJCWNoYXIgKmJ1ZikKPiArewo+ICsJc3RydWN0IHNlbnNv
cl9kZXZpY2VfYXR0cmlidXRlICphdHRyID0gdG9fc2Vuc29yX2Rldl9hdHRyKGRldmF0dHIpOwo+
ICsJc3RydWN0IGxtOTBfZGF0YSAqZGF0YSA9IGRldl9nZXRfZHJ2ZGF0YShkZXYpOwo+ICsKPiAr
CXJldHVybiBzcHJpbnRmKGJ1ZiwgIiVkXG4iLCBsbTkwX2dldF90ZW1waHlzdChkYXRhLCBhdHRy
LT5pbmRleCkpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgc3NpemVfdCBsbTkwX3N5c2ZzX3NldF90ZW1w
aHlzdCgKPiArCQlzdHJ1Y3QgZGV2aWNlICpkZXYsIHN0cnVjdCBkZXZpY2VfYXR0cmlidXRlICpk
dW1teSwKPiArCQljb25zdCBjaGFyICpidWYsIHNpemVfdCBjb3VudCkKPiArewo+ICsJc3RydWN0
IGxtOTBfZGF0YSAqZGF0YSA9IGRldl9nZXRfZHJ2ZGF0YShkZXYpOwo+ICsJbG9uZyB2YWw7Cj4g
KwlpbnQgZXJyOwo+ICsKPiArCWVyciA9IGtzdHJ0b2woYnVmLCAxMCwgJnZhbCk7Cj4gKwlpZiAo
ZXJyIDwgMCkKPiArCQlyZXR1cm4gZXJyOwo+ICsKPiArCWxtOTBfc2V0X3RlbXBoeXN0KGRhdGEs
IHZhbCk7Cj4gKwo+ICsJcmV0dXJuIGNvdW50Owo+ICt9Cj4gKwo+ICtzdGF0aWMgc3NpemVfdCBs
bTkwX3N5c2ZzX3Nob3dfYWxhcm1zKAo+ICsJCXN0cnVjdCBkZXZpY2UgKmRldiwgc3RydWN0IGRl
dmljZV9hdHRyaWJ1dGUgKmR1bW15LAo+ICsJCWNoYXIgKmJ1ZikKPiArewo+ICsJc3RydWN0IGxt
OTBfZGF0YSAqZGF0YSA9IGRldl9nZXRfZHJ2ZGF0YShkZXYpOwo+ICsKPiArCWxtOTBfdXBkYXRl
KGRhdGEpOwo+ICsKPiAgIAlyZXR1cm4gc3ByaW50ZihidWYsICIlZFxuIiwgZGF0YS0+YWxhcm1z
KTsKPiAgIH0KPgo+IC1zdGF0aWMgc3NpemVfdCBzaG93X2FsYXJtKHN0cnVjdCBkZXZpY2UgKmRl
diwgc3RydWN0IGRldmljZV9hdHRyaWJ1dGUKPiAtCQkJICAqZGV2YXR0ciwgY2hhciAqYnVmKQo+
ICtzdGF0aWMgc3NpemVfdCBsbTkwX3N5c2ZzX3Nob3dfYWxhcm0oCj4gKwkJc3RydWN0IGRldmlj
ZSAqZGV2LCBzdHJ1Y3QgZGV2aWNlX2F0dHJpYnV0ZSAqZGV2YXR0ciwKPiArCQljaGFyICpidWYp
Cj4gICB7Cj4gICAJc3RydWN0IHNlbnNvcl9kZXZpY2VfYXR0cmlidXRlICphdHRyID0gdG9fc2Vu
c29yX2Rldl9hdHRyKGRldmF0dHIpOwo+IC0Jc3RydWN0IGxtOTBfZGF0YSAqZGF0YSA9IGxtOTBf
dXBkYXRlX2RldmljZShkZXYpOwo+ICsJc3RydWN0IGxtOTBfZGF0YSAqZGF0YSA9IGRldl9nZXRf
ZHJ2ZGF0YShkZXYpOwo+ICAgCWludCBiaXRuciA9IGF0dHItPmluZGV4Owo+Cj4gKwlsbTkwX3Vw
ZGF0ZShkYXRhKTsKPiArCj4gICAJcmV0dXJuIHNwcmludGYoYnVmLCAiJWRcbiIsIChkYXRhLT5h
bGFybXMgPj4gYml0bnIpICYgMSk7Cj4gICB9Cj4KPiAtc3RhdGljIHNzaXplX3Qgc2hvd191cGRh
dGVfaW50ZXJ2YWwoc3RydWN0IGRldmljZSAqZGV2LAo+IC0JCQkJICAgIHN0cnVjdCBkZXZpY2Vf
YXR0cmlidXRlICphdHRyLCBjaGFyICpidWYpCj4gK3N0YXRpYyBzc2l6ZV90IGxtOTBfc3lzZnNf
c2hvd191cGRhdGVfaW50ZXJ2YWwoCj4gKwkJc3RydWN0IGRldmljZSAqZGV2LCBzdHJ1Y3QgZGV2
aWNlX2F0dHJpYnV0ZSAqYXR0ciwKPiArCQljaGFyICpidWYpCj4gICB7Cj4gICAJc3RydWN0IGxt
OTBfZGF0YSAqZGF0YSA9IGRldl9nZXRfZHJ2ZGF0YShkZXYpOwo+Cj4gICAJcmV0dXJuIHNwcmlu
dGYoYnVmLCAiJXVcbiIsIGRhdGEtPnVwZGF0ZV9pbnRlcnZhbCk7Cj4gICB9Cj4KPiAtc3RhdGlj
IHNzaXplX3Qgc2V0X3VwZGF0ZV9pbnRlcnZhbChzdHJ1Y3QgZGV2aWNlICpkZXYsCj4gLQkJCQkg
ICBzdHJ1Y3QgZGV2aWNlX2F0dHJpYnV0ZSAqYXR0ciwKPiAtCQkJCSAgIGNvbnN0IGNoYXIgKmJ1
Ziwgc2l6ZV90IGNvdW50KQo+ICtzdGF0aWMgc3NpemVfdCBsbTkwX3N5c2ZzX3NldF91cGRhdGVf
aW50ZXJ2YWwoCj4gKwkJc3RydWN0IGRldmljZSAqZGV2LCBzdHJ1Y3QgZGV2aWNlX2F0dHJpYnV0
ZSAqYXR0ciwKPiArCQljb25zdCBjaGFyICpidWYsIHNpemVfdCBjb3VudCkKPiAgIHsKPiAgIAlz
dHJ1Y3QgbG05MF9kYXRhICpkYXRhID0gZGV2X2dldF9kcnZkYXRhKGRldik7Cj4gLQlzdHJ1Y3Qg
aTJjX2NsaWVudCAqY2xpZW50ID0gZGF0YS0+Y2xpZW50Owo+ICAgCXVuc2lnbmVkIGxvbmcgdmFs
Owo+ICAgCWludCBlcnI7Cj4KPiBAQCAtOTg3LDQ5ICsxMDYxLDU1IEBAIHN0YXRpYyBzc2l6ZV90
IHNldF91cGRhdGVfaW50ZXJ2YWwoc3RydWN0IGRldmljZSAqZGV2LAo+ICAgCWlmIChlcnIpCj4g
ICAJCXJldHVybiBlcnI7Cj4KPiAtCW11dGV4X2xvY2soJmRhdGEtPnVwZGF0ZV9sb2NrKTsKPiAt
CWxtOTBfc2V0X2NvbnZyYXRlKGNsaWVudCwgZGF0YSwgY2xhbXBfdmFsKHZhbCwgMCwgMTAwMDAw
KSk7Cj4gLQltdXRleF91bmxvY2soJmRhdGEtPnVwZGF0ZV9sb2NrKTsKPiArCWxtOTBfc2V0X2Nv
bnZyYXRlKGRhdGEsIGNsYW1wX3ZhbCh2YWwsIDAsIDEwMDAwMCkpOwo+Cj4gICAJcmV0dXJuIGNv
dW50Owo+ICAgfQo+Cj4gLXN0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFJfMih0ZW1wMV9pbnB1dCwg
U19JUlVHTywgc2hvd190ZW1wMTEsIE5VTEwsCj4gLQkwLCBMT0NBTF9URU1QKTsKPiAtc3RhdGlj
IFNFTlNPUl9ERVZJQ0VfQVRUUl8yKHRlbXAyX2lucHV0LCBTX0lSVUdPLCBzaG93X3RlbXAxMSwg
TlVMTCwKPiAtCTAsIFJFTU9URV9URU1QKTsKPiAtc3RhdGljIFNFTlNPUl9ERVZJQ0VfQVRUUih0
ZW1wMV9taW4sIFNfSVdVU1IgfCBTX0lSVUdPLCBzaG93X3RlbXA4LAo+IC0Jc2V0X3RlbXA4LCBM
T0NBTF9MT1cpOwo+IC1zdGF0aWMgU0VOU09SX0RFVklDRV9BVFRSXzIodGVtcDJfbWluLCBTX0lX
VVNSIHwgU19JUlVHTywgc2hvd190ZW1wMTEsCj4gLQlzZXRfdGVtcDExLCAwLCBSRU1PVEVfTE9X
KTsKPiAtc3RhdGljIFNFTlNPUl9ERVZJQ0VfQVRUUih0ZW1wMV9tYXgsIFNfSVdVU1IgfCBTX0lS
VUdPLCBzaG93X3RlbXA4LAo+IC0Jc2V0X3RlbXA4LCBMT0NBTF9ISUdIKTsKPiAtc3RhdGljIFNF
TlNPUl9ERVZJQ0VfQVRUUl8yKHRlbXAyX21heCwgU19JV1VTUiB8IFNfSVJVR08sIHNob3dfdGVt
cDExLAo+IC0Jc2V0X3RlbXAxMSwgMSwgUkVNT1RFX0hJR0gpOwo+IC1zdGF0aWMgU0VOU09SX0RF
VklDRV9BVFRSKHRlbXAxX2NyaXQsIFNfSVdVU1IgfCBTX0lSVUdPLCBzaG93X3RlbXA4LAo+IC0J
c2V0X3RlbXA4LCBMT0NBTF9DUklUKTsKPiAtc3RhdGljIFNFTlNPUl9ERVZJQ0VfQVRUUih0ZW1w
Ml9jcml0LCBTX0lXVVNSIHwgU19JUlVHTywgc2hvd190ZW1wOCwKPiAtCXNldF90ZW1wOCwgUkVN
T1RFX0NSSVQpOwo+IC1zdGF0aWMgU0VOU09SX0RFVklDRV9BVFRSKHRlbXAxX2NyaXRfaHlzdCwg
U19JV1VTUiB8IFNfSVJVR08sIHNob3dfdGVtcGh5c3QsCj4gLQlzZXRfdGVtcGh5c3QsIExPQ0FM
X0NSSVQpOwo+IC1zdGF0aWMgU0VOU09SX0RFVklDRV9BVFRSKHRlbXAyX2NyaXRfaHlzdCwgU19J
UlVHTywgc2hvd190ZW1waHlzdCwgTlVMTCwKPiAtCVJFTU9URV9DUklUKTsKPiAtc3RhdGljIFNF
TlNPUl9ERVZJQ0VfQVRUUl8yKHRlbXAyX29mZnNldCwgU19JV1VTUiB8IFNfSVJVR08sIHNob3df
dGVtcDExLAo+IC0Jc2V0X3RlbXAxMSwgMiwgUkVNT1RFX09GRlNFVCk7Cj4gK3N0YXRpYyBTRU5T
T1JfREVWSUNFX0FUVFIodGVtcDFfaW5wdXQsIFNfSVJVR08sCj4gKwlsbTkwX3N5c2ZzX3Nob3df
dGVtcDExLCBOVUxMLCBMT0NBTF9URU1QKTsKPiArc3RhdGljIFNFTlNPUl9ERVZJQ0VfQVRUUih0
ZW1wMl9pbnB1dCwgU19JUlVHTywKPiArCWxtOTBfc3lzZnNfc2hvd190ZW1wMTEsIE5VTEwsIFJF
TU9URV9URU1QKTsKPiArc3RhdGljIFNFTlNPUl9ERVZJQ0VfQVRUUih0ZW1wMV9taW4sIFNfSVdV
U1IgfCBTX0lSVUdPLAo+ICsJbG05MF9zeXNmc19zaG93X3RlbXA4LCBsbTkwX3N5c2ZzX3NldF90
ZW1wOCwgTE9DQUxfTE9XKTsKPiArc3RhdGljIFNFTlNPUl9ERVZJQ0VfQVRUUih0ZW1wMl9taW4s
IFNfSVdVU1IgfCBTX0lSVUdPLAo+ICsJbG05MF9zeXNmc19zaG93X3RlbXAxMSwgbG05MF9zeXNm
c19zZXRfdGVtcDExLCBSRU1PVEVfTE9XKTsKPiArc3RhdGljIFNFTlNPUl9ERVZJQ0VfQVRUUih0
ZW1wMV9tYXgsIFNfSVdVU1IgfCBTX0lSVUdPLAo+ICsJbG05MF9zeXNmc19zaG93X3RlbXA4LCBs
bTkwX3N5c2ZzX3NldF90ZW1wOCwgTE9DQUxfSElHSCk7Cj4gK3N0YXRpYyBTRU5TT1JfREVWSUNF
X0FUVFIodGVtcDJfbWF4LCBTX0lXVVNSIHwgU19JUlVHTywKPiArCWxtOTBfc3lzZnNfc2hvd190
ZW1wMTEsIGxtOTBfc3lzZnNfc2V0X3RlbXAxMSwgUkVNT1RFX0hJR0gpOwo+ICtzdGF0aWMgU0VO
U09SX0RFVklDRV9BVFRSKHRlbXAxX2NyaXQsIFNfSVdVU1IgfCBTX0lSVUdPLAo+ICsJbG05MF9z
eXNmc19zaG93X3RlbXA4LCBsbTkwX3N5c2ZzX3NldF90ZW1wOCwgTE9DQUxfQ1JJVCk7Cj4gK3N0
YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIodGVtcDJfY3JpdCwgU19JV1VTUiB8IFNfSVJVR08sCj4g
KwlsbTkwX3N5c2ZzX3Nob3dfdGVtcDgsIGxtOTBfc3lzZnNfc2V0X3RlbXA4LCBSRU1PVEVfQ1JJ
VCk7Cj4gK3N0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIodGVtcDFfY3JpdF9oeXN0LCBTX0lXVVNS
IHwgU19JUlVHTywKPiArCWxtOTBfc3lzZnNfc2hvd190ZW1waHlzdCwgbG05MF9zeXNmc19zZXRf
dGVtcGh5c3QsIExPQ0FMX0NSSVQpOwo+ICtzdGF0aWMgU0VOU09SX0RFVklDRV9BVFRSKHRlbXAy
X2NyaXRfaHlzdCwgU19JUlVHTywKPiArCWxtOTBfc3lzZnNfc2hvd190ZW1waHlzdCwgTlVMTCwg
UkVNT1RFX0NSSVQpOwo+ICtzdGF0aWMgU0VOU09SX0RFVklDRV9BVFRSKHRlbXAyX29mZnNldCwg
U19JV1VTUiB8IFNfSVJVR08sCj4gKwlsbTkwX3N5c2ZzX3Nob3dfdGVtcDExLCBsbTkwX3N5c2Zz
X3NldF90ZW1wMTEsIFJFTU9URV9PRkZTRVQpOwo+Cj4gICAvKiBJbmRpdmlkdWFsIGFsYXJtIGZp
bGVzICovCj4gLXN0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIodGVtcDFfY3JpdF9hbGFybSwgU19J
UlVHTywgc2hvd19hbGFybSwgTlVMTCwgMCk7Cj4gLXN0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIo
dGVtcDJfY3JpdF9hbGFybSwgU19JUlVHTywgc2hvd19hbGFybSwgTlVMTCwgMSk7Cj4gLXN0YXRp
YyBTRU5TT1JfREVWSUNFX0FUVFIodGVtcDJfZmF1bHQsIFNfSVJVR08sIHNob3dfYWxhcm0sIE5V
TEwsIDIpOwo+IC1zdGF0aWMgU0VOU09SX0RFVklDRV9BVFRSKHRlbXAyX21pbl9hbGFybSwgU19J
UlVHTywgc2hvd19hbGFybSwgTlVMTCwgMyk7Cj4gLXN0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIo
dGVtcDJfbWF4X2FsYXJtLCBTX0lSVUdPLCBzaG93X2FsYXJtLCBOVUxMLCA0KTsKPiAtc3RhdGlj
IFNFTlNPUl9ERVZJQ0VfQVRUUih0ZW1wMV9taW5fYWxhcm0sIFNfSVJVR08sIHNob3dfYWxhcm0s
IE5VTEwsIDUpOwo+IC1zdGF0aWMgU0VOU09SX0RFVklDRV9BVFRSKHRlbXAxX21heF9hbGFybSwg
U19JUlVHTywgc2hvd19hbGFybSwgTlVMTCwgNik7Cj4gK3N0YXRpYyBTRU5TT1JfREVWSUNFX0FU
VFIodGVtcDFfY3JpdF9hbGFybSwgU19JUlVHTywKPiArCWxtOTBfc3lzZnNfc2hvd19hbGFybSwg
TlVMTCwgMCk7Cj4gK3N0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIodGVtcDJfY3JpdF9hbGFybSwg
U19JUlVHTywKPiArCWxtOTBfc3lzZnNfc2hvd19hbGFybSwgTlVMTCwgMSk7Cj4gK3N0YXRpYyBT
RU5TT1JfREVWSUNFX0FUVFIodGVtcDJfZmF1bHQsIFNfSVJVR08sCj4gKwlsbTkwX3N5c2ZzX3No
b3dfYWxhcm0sIE5VTEwsIDIpOwo+ICtzdGF0aWMgU0VOU09SX0RFVklDRV9BVFRSKHRlbXAyX21p
bl9hbGFybSwgU19JUlVHTywKPiArCWxtOTBfc3lzZnNfc2hvd19hbGFybSwgTlVMTCwgMyk7Cj4g
K3N0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIodGVtcDJfbWF4X2FsYXJtLCBTX0lSVUdPLAo+ICsJ
bG05MF9zeXNmc19zaG93X2FsYXJtLCBOVUxMLCA0KTsKPiArc3RhdGljIFNFTlNPUl9ERVZJQ0Vf
QVRUUih0ZW1wMV9taW5fYWxhcm0sIFNfSVJVR08sCj4gKwlsbTkwX3N5c2ZzX3Nob3dfYWxhcm0s
IE5VTEwsIDUpOwo+ICtzdGF0aWMgU0VOU09SX0RFVklDRV9BVFRSKHRlbXAxX21heF9hbGFybSwg
U19JUlVHTywKPiArCWxtOTBfc3lzZnNfc2hvd19hbGFybSwgTlVMTCwgNik7Cj4gICAvKiBSYXcg
YWxhcm0gZmlsZSBmb3IgY29tcGF0aWJpbGl0eSAqLwo+IC1zdGF0aWMgREVWSUNFX0FUVFIoYWxh
cm1zLCBTX0lSVUdPLCBzaG93X2FsYXJtcywgTlVMTCk7Cj4gK3N0YXRpYyBERVZJQ0VfQVRUUihh
bGFybXMsIFNfSVJVR08sCj4gKwlsbTkwX3N5c2ZzX3Nob3dfYWxhcm1zLCBOVUxMKTsKPgo+IC1z
dGF0aWMgREVWSUNFX0FUVFIodXBkYXRlX2ludGVydmFsLCBTX0lSVUdPIHwgU19JV1VTUiwgc2hv
d191cGRhdGVfaW50ZXJ2YWwsCj4gLQkJICAgc2V0X3VwZGF0ZV9pbnRlcnZhbCk7Cj4gK3N0YXRp
YyBERVZJQ0VfQVRUUih1cGRhdGVfaW50ZXJ2YWwsIFNfSVJVR08gfCBTX0lXVVNSLAo+ICsJbG05
MF9zeXNmc19zaG93X3VwZGF0ZV9pbnRlcnZhbCwgbG05MF9zeXNmc19zZXRfdXBkYXRlX2ludGVy
dmFsKTsKPgo+ICAgc3RhdGljIHN0cnVjdCBhdHRyaWJ1dGUgKmxtOTBfYXR0cmlidXRlc1tdID0g
ewo+ICAgCSZzZW5zb3JfZGV2X2F0dHJfdGVtcDFfaW5wdXQuZGV2X2F0dHIuYXR0ciwKPiBAQCAt
MTA3MSwxNCArMTE1MSwxNCBAQCBzdGF0aWMgY29uc3Qgc3RydWN0IGF0dHJpYnV0ZV9ncm91cCBs
bTkwX3RlbXAyX29mZnNldF9ncm91cCA9IHsKPiAgIC8qCj4gICAgKiBBZGRpdGlvbmFsIGF0dHJp
YnV0ZXMgZm9yIGRldmljZXMgd2l0aCBlbWVyZ2VuY3kgc2Vuc29ycwo+ICAgICovCj4gLXN0YXRp
YyBTRU5TT1JfREVWSUNFX0FUVFIodGVtcDFfZW1lcmdlbmN5LCBTX0lXVVNSIHwgU19JUlVHTywg
c2hvd190ZW1wOCwKPiAtCXNldF90ZW1wOCwgTE9DQUxfRU1FUkcpOwo+IC1zdGF0aWMgU0VOU09S
X0RFVklDRV9BVFRSKHRlbXAyX2VtZXJnZW5jeSwgU19JV1VTUiB8IFNfSVJVR08sIHNob3dfdGVt
cDgsCj4gLQlzZXRfdGVtcDgsIFJFTU9URV9FTUVSRyk7Cj4gLXN0YXRpYyBTRU5TT1JfREVWSUNF
X0FUVFIodGVtcDFfZW1lcmdlbmN5X2h5c3QsIFNfSVJVR08sIHNob3dfdGVtcGh5c3QsCj4gLQkJ
CSAgTlVMTCwgTE9DQUxfRU1FUkcpOwo+IC1zdGF0aWMgU0VOU09SX0RFVklDRV9BVFRSKHRlbXAy
X2VtZXJnZW5jeV9oeXN0LCBTX0lSVUdPLCBzaG93X3RlbXBoeXN0LAo+IC0JCQkgIE5VTEwsIFJF
TU9URV9FTUVSRyk7Cj4gK3N0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIodGVtcDFfZW1lcmdlbmN5
LCBTX0lXVVNSIHwgU19JUlVHTywKPiArCWxtOTBfc3lzZnNfc2hvd190ZW1wOCwgbG05MF9zeXNm
c19zZXRfdGVtcDgsIExPQ0FMX0VNRVJHKTsKPiArc3RhdGljIFNFTlNPUl9ERVZJQ0VfQVRUUih0
ZW1wMl9lbWVyZ2VuY3ksIFNfSVdVU1IgfCBTX0lSVUdPLAo+ICsJbG05MF9zeXNmc19zaG93X3Rl
bXA4LCBsbTkwX3N5c2ZzX3NldF90ZW1wOCwgUkVNT1RFX0VNRVJHKTsKPiArc3RhdGljIFNFTlNP
Ul9ERVZJQ0VfQVRUUih0ZW1wMV9lbWVyZ2VuY3lfaHlzdCwgU19JUlVHTywKPiArCWxtOTBfc3lz
ZnNfc2hvd190ZW1waHlzdCwgTlVMTCwgTE9DQUxfRU1FUkcpOwo+ICtzdGF0aWMgU0VOU09SX0RF
VklDRV9BVFRSKHRlbXAyX2VtZXJnZW5jeV9oeXN0LCBTX0lSVUdPLAo+ICsJbG05MF9zeXNmc19z
aG93X3RlbXBoeXN0LCBOVUxMLCBSRU1PVEVfRU1FUkcpOwo+Cj4gICBzdGF0aWMgc3RydWN0IGF0
dHJpYnV0ZSAqbG05MF9lbWVyZ2VuY3lfYXR0cmlidXRlc1tdID0gewo+ICAgCSZzZW5zb3JfZGV2
X2F0dHJfdGVtcDFfZW1lcmdlbmN5LmRldl9hdHRyLmF0dHIsCj4gQEAgLTEwOTIsOCArMTE3Miwx
MCBAQCBzdGF0aWMgY29uc3Qgc3RydWN0IGF0dHJpYnV0ZV9ncm91cCBsbTkwX2VtZXJnZW5jeV9n
cm91cCA9IHsKPiAgIAkuYXR0cnMgPSBsbTkwX2VtZXJnZW5jeV9hdHRyaWJ1dGVzLAo+ICAgfTsK
Pgo+IC1zdGF0aWMgU0VOU09SX0RFVklDRV9BVFRSKHRlbXAxX2VtZXJnZW5jeV9hbGFybSwgU19J
UlVHTywgc2hvd19hbGFybSwgTlVMTCwgMTUpOwo+IC1zdGF0aWMgU0VOU09SX0RFVklDRV9BVFRS
KHRlbXAyX2VtZXJnZW5jeV9hbGFybSwgU19JUlVHTywgc2hvd19hbGFybSwgTlVMTCwgMTMpOwo+
ICtzdGF0aWMgU0VOU09SX0RFVklDRV9BVFRSKHRlbXAxX2VtZXJnZW5jeV9hbGFybSwgU19JUlVH
TywKPiArCWxtOTBfc3lzZnNfc2hvd19hbGFybSwgTlVMTCwgMTUpOwo+ICtzdGF0aWMgU0VOU09S
X0RFVklDRV9BVFRSKHRlbXAyX2VtZXJnZW5jeV9hbGFybSwgU19JUlVHTywKPiArCWxtOTBfc3lz
ZnNfc2hvd19hbGFybSwgTlVMTCwgMTMpOwo+Cj4gICBzdGF0aWMgc3RydWN0IGF0dHJpYnV0ZSAq
bG05MF9lbWVyZ2VuY3lfYWxhcm1fYXR0cmlidXRlc1tdID0gewo+ICAgCSZzZW5zb3JfZGV2X2F0
dHJfdGVtcDFfZW1lcmdlbmN5X2FsYXJtLmRldl9hdHRyLmF0dHIsCj4gQEAgLTExMDgsMjYgKzEx
OTAsMzEgQEAgc3RhdGljIGNvbnN0IHN0cnVjdCBhdHRyaWJ1dGVfZ3JvdXAgbG05MF9lbWVyZ2Vu
Y3lfYWxhcm1fZ3JvdXAgPSB7Cj4gICAvKgo+ICAgICogQWRkaXRpb25hbCBhdHRyaWJ1dGVzIGZv
ciBkZXZpY2VzIHdpdGggMyB0ZW1wZXJhdHVyZSBzZW5zb3JzCj4gICAgKi8KPiAtc3RhdGljIFNF
TlNPUl9ERVZJQ0VfQVRUUl8yKHRlbXAzX2lucHV0LCBTX0lSVUdPLCBzaG93X3RlbXAxMSwgTlVM
TCwKPiAtCTAsIFJFTU9URTJfVEVNUCk7Cj4gLXN0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFJfMih0
ZW1wM19taW4sIFNfSVdVU1IgfCBTX0lSVUdPLCBzaG93X3RlbXAxMSwKPiAtCXNldF90ZW1wMTEs
IDMsIFJFTU9URTJfTE9XKTsKPiAtc3RhdGljIFNFTlNPUl9ERVZJQ0VfQVRUUl8yKHRlbXAzX21h
eCwgU19JV1VTUiB8IFNfSVJVR08sIHNob3dfdGVtcDExLAo+IC0Jc2V0X3RlbXAxMSwgNCwgUkVN
T1RFMl9ISUdIKTsKPiAtc3RhdGljIFNFTlNPUl9ERVZJQ0VfQVRUUih0ZW1wM19jcml0LCBTX0lX
VVNSIHwgU19JUlVHTywgc2hvd190ZW1wOCwKPiAtCXNldF90ZW1wOCwgUkVNT1RFMl9DUklUKTsK
PiAtc3RhdGljIFNFTlNPUl9ERVZJQ0VfQVRUUih0ZW1wM19jcml0X2h5c3QsIFNfSVJVR08sIHNo
b3dfdGVtcGh5c3QsIE5VTEwsCj4gLQlSRU1PVEUyX0NSSVQpOwo+IC1zdGF0aWMgU0VOU09SX0RF
VklDRV9BVFRSKHRlbXAzX2VtZXJnZW5jeSwgU19JV1VTUiB8IFNfSVJVR08sIHNob3dfdGVtcDgs
Cj4gLQlzZXRfdGVtcDgsIFJFTU9URTJfRU1FUkcpOwo+IC1zdGF0aWMgU0VOU09SX0RFVklDRV9B
VFRSKHRlbXAzX2VtZXJnZW5jeV9oeXN0LCBTX0lSVUdPLCBzaG93X3RlbXBoeXN0LAo+IC0JCQkg
IE5VTEwsIFJFTU9URTJfRU1FUkcpOwo+IC0KPiAtc3RhdGljIFNFTlNPUl9ERVZJQ0VfQVRUUih0
ZW1wM19jcml0X2FsYXJtLCBTX0lSVUdPLCBzaG93X2FsYXJtLCBOVUxMLCA5KTsKPiAtc3RhdGlj
IFNFTlNPUl9ERVZJQ0VfQVRUUih0ZW1wM19mYXVsdCwgU19JUlVHTywgc2hvd19hbGFybSwgTlVM
TCwgMTApOwo+IC1zdGF0aWMgU0VOU09SX0RFVklDRV9BVFRSKHRlbXAzX21pbl9hbGFybSwgU19J
UlVHTywgc2hvd19hbGFybSwgTlVMTCwgMTEpOwo+IC1zdGF0aWMgU0VOU09SX0RFVklDRV9BVFRS
KHRlbXAzX21heF9hbGFybSwgU19JUlVHTywgc2hvd19hbGFybSwgTlVMTCwgMTIpOwo+IC1zdGF0
aWMgU0VOU09SX0RFVklDRV9BVFRSKHRlbXAzX2VtZXJnZW5jeV9hbGFybSwgU19JUlVHTywgc2hv
d19hbGFybSwgTlVMTCwgMTQpOwo+ICtzdGF0aWMgU0VOU09SX0RFVklDRV9BVFRSKHRlbXAzX2lu
cHV0LCBTX0lSVUdPLAo+ICsJbG05MF9zeXNmc19zaG93X3RlbXAxMSwgTlVMTCwgUkVNT1RFMl9U
RU1QKTsKPiArc3RhdGljIFNFTlNPUl9ERVZJQ0VfQVRUUih0ZW1wM19taW4sIFNfSVdVU1IgfCBT
X0lSVUdPLAo+ICsJbG05MF9zeXNmc19zaG93X3RlbXAxMSwgbG05MF9zeXNmc19zZXRfdGVtcDEx
LCBSRU1PVEUyX0xPVyk7Cj4gK3N0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIodGVtcDNfbWF4LCBT
X0lXVVNSIHwgU19JUlVHTywKPiArCWxtOTBfc3lzZnNfc2hvd190ZW1wMTEsIGxtOTBfc3lzZnNf
c2V0X3RlbXAxMSwgUkVNT1RFMl9ISUdIKTsKPiArc3RhdGljIFNFTlNPUl9ERVZJQ0VfQVRUUih0
ZW1wM19jcml0LCBTX0lXVVNSIHwgU19JUlVHTywKPiArCWxtOTBfc3lzZnNfc2hvd190ZW1wOCwg
bG05MF9zeXNmc19zZXRfdGVtcDgsIFJFTU9URTJfQ1JJVCk7Cj4gK3N0YXRpYyBTRU5TT1JfREVW
SUNFX0FUVFIodGVtcDNfY3JpdF9oeXN0LCBTX0lSVUdPLAo+ICsJbG05MF9zeXNmc19zaG93X3Rl
bXBoeXN0LCBOVUxMLCBSRU1PVEUyX0NSSVQpOwo+ICtzdGF0aWMgU0VOU09SX0RFVklDRV9BVFRS
KHRlbXAzX2VtZXJnZW5jeSwgU19JV1VTUiB8IFNfSVJVR08sCj4gKwlsbTkwX3N5c2ZzX3Nob3df
dGVtcDgsIGxtOTBfc3lzZnNfc2V0X3RlbXA4LCBSRU1PVEUyX0VNRVJHKTsKPiArc3RhdGljIFNF
TlNPUl9ERVZJQ0VfQVRUUih0ZW1wM19lbWVyZ2VuY3lfaHlzdCwgU19JUlVHTywKPiArCWxtOTBf
c3lzZnNfc2hvd190ZW1waHlzdCwgTlVMTCwgUkVNT1RFMl9FTUVSRyk7Cj4gKwo+ICtzdGF0aWMg
U0VOU09SX0RFVklDRV9BVFRSKHRlbXAzX2NyaXRfYWxhcm0sIFNfSVJVR08sCj4gKwlsbTkwX3N5
c2ZzX3Nob3dfYWxhcm0sIE5VTEwsIDkpOwo+ICtzdGF0aWMgU0VOU09SX0RFVklDRV9BVFRSKHRl
bXAzX2ZhdWx0LCBTX0lSVUdPLAo+ICsJbG05MF9zeXNmc19zaG93X2FsYXJtLCBOVUxMLCAxMCk7
Cj4gK3N0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIodGVtcDNfbWluX2FsYXJtLCBTX0lSVUdPLAo+
ICsJbG05MF9zeXNmc19zaG93X2FsYXJtLCBOVUxMLCAxMSk7Cj4gK3N0YXRpYyBTRU5TT1JfREVW
SUNFX0FUVFIodGVtcDNfbWF4X2FsYXJtLCBTX0lSVUdPLAo+ICsJbG05MF9zeXNmc19zaG93X2Fs
YXJtLCBOVUxMLCAxMik7Cj4gK3N0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIodGVtcDNfZW1lcmdl
bmN5X2FsYXJtLCBTX0lSVUdPLAo+ICsJbG05MF9zeXNmc19zaG93X2FsYXJtLCBOVUxMLCAxNCk7
Cj4KPiAgIHN0YXRpYyBzdHJ1Y3QgYXR0cmlidXRlICpsbTkwX3RlbXAzX2F0dHJpYnV0ZXNbXSA9
IHsKPiAgIAkmc2Vuc29yX2Rldl9hdHRyX3RlbXAzX2lucHV0LmRldl9hdHRyLmF0dHIsCj4gQEAg
LTExNTEsMTUgKzEyMzgsMTUgQEAgc3RhdGljIGNvbnN0IHN0cnVjdCBhdHRyaWJ1dGVfZ3JvdXAg
bG05MF90ZW1wM19ncm91cCA9IHsKPiAgIH07Cj4KPiAgIC8qIHBlYyB1c2VkIGZvciBBRE0xMDMy
IG9ubHkgKi8KPiAtc3RhdGljIHNzaXplX3Qgc2hvd19wZWMoc3RydWN0IGRldmljZSAqZGV2LCBz
dHJ1Y3QgZGV2aWNlX2F0dHJpYnV0ZSAqZHVtbXksCj4gLQkJCWNoYXIgKmJ1ZikKPiArc3RhdGlj
IHNzaXplX3QgbG05MF9zeXNmc19zaG93X3BlYyhzdHJ1Y3QgZGV2aWNlICpkZXYsCj4gKwkJc3Ry
dWN0IGRldmljZV9hdHRyaWJ1dGUgKmR1bW15LCBjaGFyICpidWYpCj4gICB7Cj4gICAJc3RydWN0
IGkyY19jbGllbnQgKmNsaWVudCA9IHRvX2kyY19jbGllbnQoZGV2KTsKPiAgIAlyZXR1cm4gc3By
aW50ZihidWYsICIlZFxuIiwgISEoY2xpZW50LT5mbGFncyAmIEkyQ19DTElFTlRfUEVDKSk7Cj4g
ICB9Cj4KPiAtc3RhdGljIHNzaXplX3Qgc2V0X3BlYyhzdHJ1Y3QgZGV2aWNlICpkZXYsIHN0cnVj
dCBkZXZpY2VfYXR0cmlidXRlICpkdW1teSwKPiAtCQkgICAgICAgY29uc3QgY2hhciAqYnVmLCBz
aXplX3QgY291bnQpCj4gK3N0YXRpYyBzc2l6ZV90IGxtOTBfc3lzZnNfc2V0X3BlYyhzdHJ1Y3Qg
ZGV2aWNlICpkZXYsCj4gKwkJc3RydWN0IGRldmljZV9hdHRyaWJ1dGUgKmR1bW15LCBjb25zdCBj
aGFyICpidWYsIHNpemVfdCBjb3VudCkKPiAgIHsKPiAgIAlzdHJ1Y3QgaTJjX2NsaWVudCAqY2xp
ZW50ID0gdG9faTJjX2NsaWVudChkZXYpOwo+ICAgCWxvbmcgdmFsOwo+IEBAIC0xMTgzLDcgKzEy
NzAsOCBAQCBzdGF0aWMgc3NpemVfdCBzZXRfcGVjKHN0cnVjdCBkZXZpY2UgKmRldiwgc3RydWN0
IGRldmljZV9hdHRyaWJ1dGUgKmR1bW15LAo+ICAgCXJldHVybiBjb3VudDsKPiAgIH0KPgo+IC1z
dGF0aWMgREVWSUNFX0FUVFIocGVjLCBTX0lXVVNSIHwgU19JUlVHTywgc2hvd19wZWMsIHNldF9w
ZWMpOwo+ICtzdGF0aWMgREVWSUNFX0FUVFIocGVjLCBTX0lXVVNSIHwgU19JUlVHTywKPiArCWxt
OTBfc3lzZnNfc2hvd19wZWMsIGxtOTBfc3lzZnNfc2V0X3BlYyk7Cj4KPiAgIC8qCj4gICAgKiBS
ZWFsIGNvZGUKPiBAQCAtMTQxMyw4ICsxNTAxLDkgQEAgc3RhdGljIHZvaWQgbG05MF9yZXN0b3Jl
X2NvbmYoc3RydWN0IGkyY19jbGllbnQgKmNsaWVudCwgc3RydWN0IGxtOTBfZGF0YSAqZGF0YSkK
PiAgIAkJCQkgIGRhdGEtPmNvbmZpZ19vcmlnKTsKPiAgIH0KPgo+IC1zdGF0aWMgdm9pZCBsbTkw
X2luaXRfY2xpZW50KHN0cnVjdCBpMmNfY2xpZW50ICpjbGllbnQsIHN0cnVjdCBsbTkwX2RhdGEg
KmRhdGEpCj4gK3N0YXRpYyB2b2lkIGxtOTBfaW5pdF9jbGllbnQoc3RydWN0IGxtOTBfZGF0YSAq
ZGF0YSkKPiAgIHsKPiArCXN0cnVjdCBpMmNfY2xpZW50ICpjbGllbnQgPSBkYXRhLT5jbGllbnQ7
Cj4gICAJdTggY29uZmlnLCBjb252cmF0ZTsKPgo+ICAgCWlmIChsbTkwX3JlYWRfcmVnKGNsaWVu
dCwgTE05MF9SRUdfUl9DT05WUkFURSwgJmNvbnZyYXRlKSA8IDApIHsKPiBAQCAtMTQyNiw3ICsx
NTE1LDcgQEAgc3RhdGljIHZvaWQgbG05MF9pbml0X2NsaWVudChzdHJ1Y3QgaTJjX2NsaWVudCAq
Y2xpZW50LCBzdHJ1Y3QgbG05MF9kYXRhICpkYXRhKQo+ICAgCS8qCj4gICAJICogU3RhcnQgdGhl
IGNvbnZlcnNpb25zLgo+ICAgCSAqLwo+IC0JbG05MF9zZXRfY29udnJhdGUoY2xpZW50LCBkYXRh
LCA1MDApOwkvKiA1MDBtczsgMkh6IGNvbnZlcnNpb24gcmF0ZSAqLwo+ICsJbG05MF9zZXRfY29u
dnJhdGVfbG9ja2VkKGRhdGEsIDUwMCk7ICAvKiA1MDBtcyAvIDJIeiAgKi8KPiAgIAlpZiAobG05
MF9yZWFkX3JlZyhjbGllbnQsIExNOTBfUkVHX1JfQ09ORklHMSwgJmNvbmZpZykgPCAwKSB7Cj4g
ICAJCWRldl93YXJuKCZjbGllbnQtPmRldiwgIkluaXRpYWxpemF0aW9uIGZhaWxlZCFcbiIpOwo+
ICAgCQlyZXR1cm47Cj4gQEAgLTE1NTcsNyArMTY0Niw3IEBAIHN0YXRpYyBpbnQgbG05MF9wcm9i
ZShzdHJ1Y3QgaTJjX2NsaWVudCAqY2xpZW50LAo+ICAgCWRhdGEtPm1heF9jb252cmF0ZSA9IGxt
OTBfcGFyYW1zW2RhdGEtPmtpbmRdLm1heF9jb252cmF0ZTsKPgo+ICAgCS8qIEluaXRpYWxpemUg
dGhlIExNOTAgY2hpcCAqLwo+IC0JbG05MF9pbml0X2NsaWVudChjbGllbnQsIGRhdGEpOwo+ICsJ
bG05MF9pbml0X2NsaWVudChkYXRhKTsKPgo+ICAgCS8qIFJlZ2lzdGVyIHN5c2ZzIGhvb2tzICov
Cj4gICAJZGF0YS0+Z3JvdXBzW2dyb3VwcysrXSA9ICZsbTkwX2dyb3VwOwo+CgoKX19fX19fX19f
X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18KbG0tc2Vuc29ycyBtYWlsaW5n
IGxpc3QKbG0tc2Vuc29yc0BsbS1zZW5zb3JzLm9yZwpodHRwOi8vbGlzdHMubG0tc2Vuc29ycy5v
cmcvbWFpbG1hbi9saXN0aW5mby9sbS1zZW5zb3Jz

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 2/3] lm90: initialize parameters from devicetree
       [not found]     ` <1453404877-17897-3-git-send-email-stephan-j6uo2F6POYhmR6Xm/wNWPw@public.gmane.org>
@ 2016-01-22 14:53         ` Guenter Roeck
  0 siblings, 0 replies; 23+ messages in thread
From: Guenter Roeck @ 2016-01-22 14:53 UTC (permalink / raw)
  To: Stéphan Kochen, Jean Delvare
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On 01/21/2016 11:34 AM, Stéphan Kochen wrote:
> Allow a device tree to set initial temperature sensor parameters.
>
> Userspace can still override actual values through sysfs.
>
> Signed-off-by: Stéphan Kochen <stephan-j6uo2F6POYhmR6Xm/wNWPw@public.gmane.org>
> ---
>   Documentation/devicetree/bindings/hwmon/lm90.txt | 40 +++++++++++++++++
>   drivers/hwmon/lm90.c                             | 55 ++++++++++++++++++++++--
>   2 files changed, 92 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/hwmon/lm90.txt b/Documentation/devicetree/bindings/hwmon/lm90.txt
> index e863248..045e94b 100644
> --- a/Documentation/devicetree/bindings/hwmon/lm90.txt
> +++ b/Documentation/devicetree/bindings/hwmon/lm90.txt
> @@ -33,6 +33,38 @@ Optional properties:
>                 LM90 "-ALERT" pin output.
>                 See interrupt-controller/interrupts.txt for the format.
>
> +- update-interval: Interval at which temperatures are sampled,
> +  Type: unsigned   in milliseconds.
> +  Size: one cell
> +
> +- local-low:      Valid temperature range for the chip internal sensor,
> +  local-high:     outside which the alert will be set. Values are in
> +  local-critical: millicelcius.
> +  Type: signed
> +  Size: one cell
> +
> +- remote-low:      Valid temperature range for the external sensor,
> +  remote-high:     outside which the alert will be set. Values are in
> +  remote-critical: millicelciius.
> +  Type: signed
> +  Size: one cell
> +
> +- remote-offset:   Where available, an external sensor temperature offset.
> +  Type: signed
> +  Size: one cell
> +
> +- local-emergency:  On max6659, max6695 and max6696, a configurable
> +  remote-emergency: 3rd upper bound on temperature.
> +  Type: signed
> +  Size: one cell
> +
> +- remote2-low:      On max6695 and max6696, a second external sensor.
> +  remote2-high:
> +  remote2-critical:
> +  remote2-emergency:
> +  Type: signed
> +  Size: one cell
> +

This very much smells like configuration, not hardware description.

Having said that, the thermal subsystem does something similar. This raises even more
questions, though. Since patch 3 of the series introduces registration with the thermal
subsystem, it seems to me that the thermal subsystem should provide any limits used
to program the chips, and that there should be a mechanism for the thermal subsystem
to interact with the driver to both set the limits and to be informed if a limit
is exceeded.

Also, _if_ such a set of properties is introduced and accepted by the devicetree
reviewers, it should probably be a set of properties which applies to _all_ hardware
monitoring drivers, not just to one. Even if support is not implemented immediately
in the hwmon core, the properties should be usable in a generic way, and not
reflect sysfs attribute names used by the hwmon subsystem.

Thanks,
Guenter

>   Example LM90 node:
>
>   temp-sensor {
> @@ -41,4 +73,12 @@ temp-sensor {
>   	vcc-supply = <&palmas_ldo6_reg>;
>   	interrupt-parent = <&gpio>;
>   	interrupts = <TEGRA_GPIO(O, 4) IRQ_TYPE_LEVEL_LOW>;
> +	update-interval = <500>;
> +	local-low = <5000>;
> +	local-high = <80000>;
> +	local-critical = <90000>;
> +	remote-low = <5000>;
> +	remote-high = <80000>;
> +	remote-critical = <90000>;
> +	remote-offset = <(-62125)>;
>   }
> diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
> index 88daf72..8ae8791 100644
> --- a/drivers/hwmon/lm90.c
> +++ b/drivers/hwmon/lm90.c
> @@ -93,6 +93,7 @@
>   #include <linux/hwmon.h>
>   #include <linux/err.h>
>   #include <linux/mutex.h>
> +#include <linux/of.h>
>   #include <linux/sysfs.h>
>   #include <linux/interrupt.h>
>   #include <linux/regulator/consumer.h>
> @@ -1504,8 +1505,16 @@ static void lm90_restore_conf(struct i2c_client *client, struct lm90_data *data)
>   static void lm90_init_client(struct lm90_data *data)
>   {
>   	struct i2c_client *client = data->client;
> +	struct device *dev = &client->dev;
>   	u8 config, convrate;
> +	u32 ms;
> +#ifdef CONFIG_OF
> +	s32 temp;
> +#endif
>
> +	/*
> +	 * Save old conversion rate.
> +	 */
>   	if (lm90_read_reg(client, LM90_REG_R_CONVRATE, &convrate) < 0) {
>   		dev_warn(&client->dev, "Failed to read convrate register!\n");
>   		convrate = LM90_DEF_CONVRATE_RVAL;
> @@ -1515,14 +1524,24 @@ static void lm90_init_client(struct lm90_data *data)
>   	/*
>   	 * Start the conversions.
>   	 */
> -	lm90_set_convrate_locked(data, 500);  /* 500ms / 2Hz  */
> +#ifdef CONFIG_OF
> +	if (of_property_read_u32(dev->of_node, "update-interval", &ms) < 0)
> +#endif
> +		ms = 500;  /* default rate: 2Hz */
> +	lm90_set_convrate_locked(data, ms);
> +
> +	/*
> +	 * Save old config
> +	 */
>   	if (lm90_read_reg(client, LM90_REG_R_CONFIG1, &config) < 0) {
> -		dev_warn(&client->dev, "Initialization failed!\n");
> +		dev_warn(dev, "Initialization failed!\n");
>   		return;
>   	}
>   	data->config_orig = config;
>
> -	/* Check Temperature Range Select */
> +	/*
> +	 * Check Temperature Range Select
> +	 */
>   	if (data->kind == adt7461 || data->kind == tmp451) {
>   		if (config & 0x04)
>   			data->flags |= LM90_FLAG_ADT7461_EXT;
> @@ -1545,6 +1564,36 @@ static void lm90_init_client(struct lm90_data *data)
>   	config &= 0xBF;	/* run */
>   	if (config != data->config_orig) /* Only write if changed */
>   		i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config);
> +
> +#ifdef CONFIG_OF
> +	/*
> +	 * Set initial values from devicetree
> +	 */
> +#define INIT_REG(_property, _index, _bits) { \
> +	if (of_property_read_s32(dev->of_node, _property, &temp) == 0) \
> +		lm90_set_temp##_bits##_locked(data, _index, temp); \
> +}
> +	INIT_REG("local-low", LOCAL_LOW, 8);
> +	INIT_REG("local-high", LOCAL_HIGH, 8);
> +	INIT_REG("local-critical", LOCAL_CRIT, 8);
> +	INIT_REG("remote-low", REMOTE_LOW, 11);
> +	INIT_REG("remote-high", REMOTE_HIGH, 11);
> +	INIT_REG("remote-critical", REMOTE_CRIT, 8);
> +	if (data->flags & LM90_HAVE_OFFSET) {
> +		INIT_REG("remote-offset", REMOTE_OFFSET, 11);
> +	}
> +	if (data->flags & LM90_HAVE_EMERGENCY) {
> +		INIT_REG("local-emergency", LOCAL_EMERG, 8);
> +		INIT_REG("remote-emergency", REMOTE_EMERG, 8);
> +	}
> +	if (data->flags & LM90_HAVE_TEMP3) {
> +		INIT_REG("remote2-low", REMOTE2_LOW, 11);
> +		INIT_REG("remote2-high", REMOTE2_HIGH, 11);
> +		INIT_REG("remote2-critical", REMOTE2_CRIT, 8);
> +		INIT_REG("remote2-emergency", REMOTE2_EMERG, 8);
> +	}
> +#undef INIT_REG
> +#endif
>   }
>
>   static bool lm90_is_tripped(struct i2c_client *client, u16 *status)
>

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [lm-sensors] [PATCH 2/3] lm90: initialize parameters from devicetree
@ 2016-01-22 14:53         ` Guenter Roeck
  0 siblings, 0 replies; 23+ messages in thread
From: Guenter Roeck @ 2016-01-22 14:53 UTC (permalink / raw)
  To: Stéphan Kochen, Jean Delvare
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

T24gMDEvMjEvMjAxNiAxMTozNCBBTSwgU3TDqXBoYW4gS29jaGVuIHdyb3RlOgo+IEFsbG93IGEg
ZGV2aWNlIHRyZWUgdG8gc2V0IGluaXRpYWwgdGVtcGVyYXR1cmUgc2Vuc29yIHBhcmFtZXRlcnMu
Cj4KPiBVc2Vyc3BhY2UgY2FuIHN0aWxsIG92ZXJyaWRlIGFjdHVhbCB2YWx1ZXMgdGhyb3VnaCBz
eXNmcy4KPgo+IFNpZ25lZC1vZmYtYnk6IFN0w6lwaGFuIEtvY2hlbiA8c3RlcGhhbkBrb2NoZW4u
bmw+Cj4gLS0tCj4gICBEb2N1bWVudGF0aW9uL2RldmljZXRyZWUvYmluZGluZ3MvaHdtb24vbG05
MC50eHQgfCA0MCArKysrKysrKysrKysrKysrKwo+ICAgZHJpdmVycy9od21vbi9sbTkwLmMgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgIHwgNTUgKysrKysrKysrKysrKysrKysrKysrKy0tCj4g
ICAyIGZpbGVzIGNoYW5nZWQsIDkyIGluc2VydGlvbnMoKyksIDMgZGVsZXRpb25zKC0pCj4KPiBk
aWZmIC0tZ2l0IGEvRG9jdW1lbnRhdGlvbi9kZXZpY2V0cmVlL2JpbmRpbmdzL2h3bW9uL2xtOTAu
dHh0IGIvRG9jdW1lbnRhdGlvbi9kZXZpY2V0cmVlL2JpbmRpbmdzL2h3bW9uL2xtOTAudHh0Cj4g
aW5kZXggZTg2MzI0OC4uMDQ1ZTk0YiAxMDA2NDQKPiAtLS0gYS9Eb2N1bWVudGF0aW9uL2Rldmlj
ZXRyZWUvYmluZGluZ3MvaHdtb24vbG05MC50eHQKPiArKysgYi9Eb2N1bWVudGF0aW9uL2Rldmlj
ZXRyZWUvYmluZGluZ3MvaHdtb24vbG05MC50eHQKPiBAQCAtMzMsNiArMzMsMzggQEAgT3B0aW9u
YWwgcHJvcGVydGllczoKPiAgICAgICAgICAgICAgICAgTE05MCAiLUFMRVJUIiBwaW4gb3V0cHV0
Lgo+ICAgICAgICAgICAgICAgICBTZWUgaW50ZXJydXB0LWNvbnRyb2xsZXIvaW50ZXJydXB0cy50
eHQgZm9yIHRoZSBmb3JtYXQuCj4KPiArLSB1cGRhdGUtaW50ZXJ2YWw6IEludGVydmFsIGF0IHdo
aWNoIHRlbXBlcmF0dXJlcyBhcmUgc2FtcGxlZCwKPiArICBUeXBlOiB1bnNpZ25lZCAgIGluIG1p
bGxpc2Vjb25kcy4KPiArICBTaXplOiBvbmUgY2VsbAo+ICsKPiArLSBsb2NhbC1sb3c6ICAgICAg
VmFsaWQgdGVtcGVyYXR1cmUgcmFuZ2UgZm9yIHRoZSBjaGlwIGludGVybmFsIHNlbnNvciwKPiAr
ICBsb2NhbC1oaWdoOiAgICAgb3V0c2lkZSB3aGljaCB0aGUgYWxlcnQgd2lsbCBiZSBzZXQuIFZh
bHVlcyBhcmUgaW4KPiArICBsb2NhbC1jcml0aWNhbDogbWlsbGljZWxjaXVzLgo+ICsgIFR5cGU6
IHNpZ25lZAo+ICsgIFNpemU6IG9uZSBjZWxsCj4gKwo+ICstIHJlbW90ZS1sb3c6ICAgICAgVmFs
aWQgdGVtcGVyYXR1cmUgcmFuZ2UgZm9yIHRoZSBleHRlcm5hbCBzZW5zb3IsCj4gKyAgcmVtb3Rl
LWhpZ2g6ICAgICBvdXRzaWRlIHdoaWNoIHRoZSBhbGVydCB3aWxsIGJlIHNldC4gVmFsdWVzIGFy
ZSBpbgo+ICsgIHJlbW90ZS1jcml0aWNhbDogbWlsbGljZWxjaWl1cy4KPiArICBUeXBlOiBzaWdu
ZWQKPiArICBTaXplOiBvbmUgY2VsbAo+ICsKPiArLSByZW1vdGUtb2Zmc2V0OiAgIFdoZXJlIGF2
YWlsYWJsZSwgYW4gZXh0ZXJuYWwgc2Vuc29yIHRlbXBlcmF0dXJlIG9mZnNldC4KPiArICBUeXBl
OiBzaWduZWQKPiArICBTaXplOiBvbmUgY2VsbAo+ICsKPiArLSBsb2NhbC1lbWVyZ2VuY3k6ICBP
biBtYXg2NjU5LCBtYXg2Njk1IGFuZCBtYXg2Njk2LCBhIGNvbmZpZ3VyYWJsZQo+ICsgIHJlbW90
ZS1lbWVyZ2VuY3k6IDNyZCB1cHBlciBib3VuZCBvbiB0ZW1wZXJhdHVyZS4KPiArICBUeXBlOiBz
aWduZWQKPiArICBTaXplOiBvbmUgY2VsbAo+ICsKPiArLSByZW1vdGUyLWxvdzogICAgICBPbiBt
YXg2Njk1IGFuZCBtYXg2Njk2LCBhIHNlY29uZCBleHRlcm5hbCBzZW5zb3IuCj4gKyAgcmVtb3Rl
Mi1oaWdoOgo+ICsgIHJlbW90ZTItY3JpdGljYWw6Cj4gKyAgcmVtb3RlMi1lbWVyZ2VuY3k6Cj4g
KyAgVHlwZTogc2lnbmVkCj4gKyAgU2l6ZTogb25lIGNlbGwKPiArCgpUaGlzIHZlcnkgbXVjaCBz
bWVsbHMgbGlrZSBjb25maWd1cmF0aW9uLCBub3QgaGFyZHdhcmUgZGVzY3JpcHRpb24uCgpIYXZp
bmcgc2FpZCB0aGF0LCB0aGUgdGhlcm1hbCBzdWJzeXN0ZW0gZG9lcyBzb21ldGhpbmcgc2ltaWxh
ci4gVGhpcyByYWlzZXMgZXZlbiBtb3JlCnF1ZXN0aW9ucywgdGhvdWdoLiBTaW5jZSBwYXRjaCAz
IG9mIHRoZSBzZXJpZXMgaW50cm9kdWNlcyByZWdpc3RyYXRpb24gd2l0aCB0aGUgdGhlcm1hbApz
dWJzeXN0ZW0sIGl0IHNlZW1zIHRvIG1lIHRoYXQgdGhlIHRoZXJtYWwgc3Vic3lzdGVtIHNob3Vs
ZCBwcm92aWRlIGFueSBsaW1pdHMgdXNlZAp0byBwcm9ncmFtIHRoZSBjaGlwcywgYW5kIHRoYXQg
dGhlcmUgc2hvdWxkIGJlIGEgbWVjaGFuaXNtIGZvciB0aGUgdGhlcm1hbCBzdWJzeXN0ZW0KdG8g
aW50ZXJhY3Qgd2l0aCB0aGUgZHJpdmVyIHRvIGJvdGggc2V0IHRoZSBsaW1pdHMgYW5kIHRvIGJl
IGluZm9ybWVkIGlmIGEgbGltaXQKaXMgZXhjZWVkZWQuCgpBbHNvLCBfaWZfIHN1Y2ggYSBzZXQg
b2YgcHJvcGVydGllcyBpcyBpbnRyb2R1Y2VkIGFuZCBhY2NlcHRlZCBieSB0aGUgZGV2aWNldHJl
ZQpyZXZpZXdlcnMsIGl0IHNob3VsZCBwcm9iYWJseSBiZSBhIHNldCBvZiBwcm9wZXJ0aWVzIHdo
aWNoIGFwcGxpZXMgdG8gX2FsbF8gaGFyZHdhcmUKbW9uaXRvcmluZyBkcml2ZXJzLCBub3QganVz
dCB0byBvbmUuIEV2ZW4gaWYgc3VwcG9ydCBpcyBub3QgaW1wbGVtZW50ZWQgaW1tZWRpYXRlbHkK
aW4gdGhlIGh3bW9uIGNvcmUsIHRoZSBwcm9wZXJ0aWVzIHNob3VsZCBiZSB1c2FibGUgaW4gYSBn
ZW5lcmljIHdheSwgYW5kIG5vdApyZWZsZWN0IHN5c2ZzIGF0dHJpYnV0ZSBuYW1lcyB1c2VkIGJ5
IHRoZSBod21vbiBzdWJzeXN0ZW0uCgpUaGFua3MsCkd1ZW50ZXIKCj4gICBFeGFtcGxlIExNOTAg
bm9kZToKPgo+ICAgdGVtcC1zZW5zb3Igewo+IEBAIC00MSw0ICs3MywxMiBAQCB0ZW1wLXNlbnNv
ciB7Cj4gICAJdmNjLXN1cHBseSA9IDwmcGFsbWFzX2xkbzZfcmVnPjsKPiAgIAlpbnRlcnJ1cHQt
cGFyZW50ID0gPCZncGlvPjsKPiAgIAlpbnRlcnJ1cHRzID0gPFRFR1JBX0dQSU8oTywgNCkgSVJR
X1RZUEVfTEVWRUxfTE9XPjsKPiArCXVwZGF0ZS1pbnRlcnZhbCA9IDw1MDA+Owo+ICsJbG9jYWwt
bG93ID0gPDUwMDA+Owo+ICsJbG9jYWwtaGlnaCA9IDw4MDAwMD47Cj4gKwlsb2NhbC1jcml0aWNh
bCA9IDw5MDAwMD47Cj4gKwlyZW1vdGUtbG93ID0gPDUwMDA+Owo+ICsJcmVtb3RlLWhpZ2ggPSA8
ODAwMDA+Owo+ICsJcmVtb3RlLWNyaXRpY2FsID0gPDkwMDAwPjsKPiArCXJlbW90ZS1vZmZzZXQg
PSA8KC02MjEyNSk+Owo+ICAgfQo+IGRpZmYgLS1naXQgYS9kcml2ZXJzL2h3bW9uL2xtOTAuYyBi
L2RyaXZlcnMvaHdtb24vbG05MC5jCj4gaW5kZXggODhkYWY3Mi4uOGFlODc5MSAxMDA2NDQKPiAt
LS0gYS9kcml2ZXJzL2h3bW9uL2xtOTAuYwo+ICsrKyBiL2RyaXZlcnMvaHdtb24vbG05MC5jCj4g
QEAgLTkzLDYgKzkzLDcgQEAKPiAgICNpbmNsdWRlIDxsaW51eC9od21vbi5oPgo+ICAgI2luY2x1
ZGUgPGxpbnV4L2Vyci5oPgo+ICAgI2luY2x1ZGUgPGxpbnV4L211dGV4Lmg+Cj4gKyNpbmNsdWRl
IDxsaW51eC9vZi5oPgo+ICAgI2luY2x1ZGUgPGxpbnV4L3N5c2ZzLmg+Cj4gICAjaW5jbHVkZSA8
bGludXgvaW50ZXJydXB0Lmg+Cj4gICAjaW5jbHVkZSA8bGludXgvcmVndWxhdG9yL2NvbnN1bWVy
Lmg+Cj4gQEAgLTE1MDQsOCArMTUwNSwxNiBAQCBzdGF0aWMgdm9pZCBsbTkwX3Jlc3RvcmVfY29u
ZihzdHJ1Y3QgaTJjX2NsaWVudCAqY2xpZW50LCBzdHJ1Y3QgbG05MF9kYXRhICpkYXRhKQo+ICAg
c3RhdGljIHZvaWQgbG05MF9pbml0X2NsaWVudChzdHJ1Y3QgbG05MF9kYXRhICpkYXRhKQo+ICAg
ewo+ICAgCXN0cnVjdCBpMmNfY2xpZW50ICpjbGllbnQgPSBkYXRhLT5jbGllbnQ7Cj4gKwlzdHJ1
Y3QgZGV2aWNlICpkZXYgPSAmY2xpZW50LT5kZXY7Cj4gICAJdTggY29uZmlnLCBjb252cmF0ZTsK
PiArCXUzMiBtczsKPiArI2lmZGVmIENPTkZJR19PRgo+ICsJczMyIHRlbXA7Cj4gKyNlbmRpZgo+
Cj4gKwkvKgo+ICsJICogU2F2ZSBvbGQgY29udmVyc2lvbiByYXRlLgo+ICsJICovCj4gICAJaWYg
KGxtOTBfcmVhZF9yZWcoY2xpZW50LCBMTTkwX1JFR19SX0NPTlZSQVRFLCAmY29udnJhdGUpIDwg
MCkgewo+ICAgCQlkZXZfd2FybigmY2xpZW50LT5kZXYsICJGYWlsZWQgdG8gcmVhZCBjb252cmF0
ZSByZWdpc3RlciFcbiIpOwo+ICAgCQljb252cmF0ZSA9IExNOTBfREVGX0NPTlZSQVRFX1JWQUw7
Cj4gQEAgLTE1MTUsMTQgKzE1MjQsMjQgQEAgc3RhdGljIHZvaWQgbG05MF9pbml0X2NsaWVudChz
dHJ1Y3QgbG05MF9kYXRhICpkYXRhKQo+ICAgCS8qCj4gICAJICogU3RhcnQgdGhlIGNvbnZlcnNp
b25zLgo+ICAgCSAqLwo+IC0JbG05MF9zZXRfY29udnJhdGVfbG9ja2VkKGRhdGEsIDUwMCk7ICAv
KiA1MDBtcyAvIDJIeiAgKi8KPiArI2lmZGVmIENPTkZJR19PRgo+ICsJaWYgKG9mX3Byb3BlcnR5
X3JlYWRfdTMyKGRldi0+b2Zfbm9kZSwgInVwZGF0ZS1pbnRlcnZhbCIsICZtcykgPCAwKQo+ICsj
ZW5kaWYKPiArCQltcyA9IDUwMDsgIC8qIGRlZmF1bHQgcmF0ZTogMkh6ICovCj4gKwlsbTkwX3Nl
dF9jb252cmF0ZV9sb2NrZWQoZGF0YSwgbXMpOwo+ICsKPiArCS8qCj4gKwkgKiBTYXZlIG9sZCBj
b25maWcKPiArCSAqLwo+ICAgCWlmIChsbTkwX3JlYWRfcmVnKGNsaWVudCwgTE05MF9SRUdfUl9D
T05GSUcxLCAmY29uZmlnKSA8IDApIHsKPiAtCQlkZXZfd2FybigmY2xpZW50LT5kZXYsICJJbml0
aWFsaXphdGlvbiBmYWlsZWQhXG4iKTsKPiArCQlkZXZfd2FybihkZXYsICJJbml0aWFsaXphdGlv
biBmYWlsZWQhXG4iKTsKPiAgIAkJcmV0dXJuOwo+ICAgCX0KPiAgIAlkYXRhLT5jb25maWdfb3Jp
ZyA9IGNvbmZpZzsKPgo+IC0JLyogQ2hlY2sgVGVtcGVyYXR1cmUgUmFuZ2UgU2VsZWN0ICovCj4g
KwkvKgo+ICsJICogQ2hlY2sgVGVtcGVyYXR1cmUgUmFuZ2UgU2VsZWN0Cj4gKwkgKi8KPiAgIAlp
ZiAoZGF0YS0+a2luZCA9PSBhZHQ3NDYxIHx8IGRhdGEtPmtpbmQgPT0gdG1wNDUxKSB7Cj4gICAJ
CWlmIChjb25maWcgJiAweDA0KQo+ICAgCQkJZGF0YS0+ZmxhZ3MgfD0gTE05MF9GTEFHX0FEVDc0
NjFfRVhUOwo+IEBAIC0xNTQ1LDYgKzE1NjQsMzYgQEAgc3RhdGljIHZvaWQgbG05MF9pbml0X2Ns
aWVudChzdHJ1Y3QgbG05MF9kYXRhICpkYXRhKQo+ICAgCWNvbmZpZyAmPSAweEJGOwkvKiBydW4g
Ki8KPiAgIAlpZiAoY29uZmlnICE9IGRhdGEtPmNvbmZpZ19vcmlnKSAvKiBPbmx5IHdyaXRlIGlm
IGNoYW5nZWQgKi8KPiAgIAkJaTJjX3NtYnVzX3dyaXRlX2J5dGVfZGF0YShjbGllbnQsIExNOTBf
UkVHX1dfQ09ORklHMSwgY29uZmlnKTsKPiArCj4gKyNpZmRlZiBDT05GSUdfT0YKPiArCS8qCj4g
KwkgKiBTZXQgaW5pdGlhbCB2YWx1ZXMgZnJvbSBkZXZpY2V0cmVlCj4gKwkgKi8KPiArI2RlZmlu
ZSBJTklUX1JFRyhfcHJvcGVydHksIF9pbmRleCwgX2JpdHMpIHsgXAo+ICsJaWYgKG9mX3Byb3Bl
cnR5X3JlYWRfczMyKGRldi0+b2Zfbm9kZSwgX3Byb3BlcnR5LCAmdGVtcCkgPT0gMCkgXAo+ICsJ
CWxtOTBfc2V0X3RlbXAjI19iaXRzIyNfbG9ja2VkKGRhdGEsIF9pbmRleCwgdGVtcCk7IFwKPiAr
fQo+ICsJSU5JVF9SRUcoImxvY2FsLWxvdyIsIExPQ0FMX0xPVywgOCk7Cj4gKwlJTklUX1JFRygi
bG9jYWwtaGlnaCIsIExPQ0FMX0hJR0gsIDgpOwo+ICsJSU5JVF9SRUcoImxvY2FsLWNyaXRpY2Fs
IiwgTE9DQUxfQ1JJVCwgOCk7Cj4gKwlJTklUX1JFRygicmVtb3RlLWxvdyIsIFJFTU9URV9MT1cs
IDExKTsKPiArCUlOSVRfUkVHKCJyZW1vdGUtaGlnaCIsIFJFTU9URV9ISUdILCAxMSk7Cj4gKwlJ
TklUX1JFRygicmVtb3RlLWNyaXRpY2FsIiwgUkVNT1RFX0NSSVQsIDgpOwo+ICsJaWYgKGRhdGEt
PmZsYWdzICYgTE05MF9IQVZFX09GRlNFVCkgewo+ICsJCUlOSVRfUkVHKCJyZW1vdGUtb2Zmc2V0
IiwgUkVNT1RFX09GRlNFVCwgMTEpOwo+ICsJfQo+ICsJaWYgKGRhdGEtPmZsYWdzICYgTE05MF9I
QVZFX0VNRVJHRU5DWSkgewo+ICsJCUlOSVRfUkVHKCJsb2NhbC1lbWVyZ2VuY3kiLCBMT0NBTF9F
TUVSRywgOCk7Cj4gKwkJSU5JVF9SRUcoInJlbW90ZS1lbWVyZ2VuY3kiLCBSRU1PVEVfRU1FUkcs
IDgpOwo+ICsJfQo+ICsJaWYgKGRhdGEtPmZsYWdzICYgTE05MF9IQVZFX1RFTVAzKSB7Cj4gKwkJ
SU5JVF9SRUcoInJlbW90ZTItbG93IiwgUkVNT1RFMl9MT1csIDExKTsKPiArCQlJTklUX1JFRygi
cmVtb3RlMi1oaWdoIiwgUkVNT1RFMl9ISUdILCAxMSk7Cj4gKwkJSU5JVF9SRUcoInJlbW90ZTIt
Y3JpdGljYWwiLCBSRU1PVEUyX0NSSVQsIDgpOwo+ICsJCUlOSVRfUkVHKCJyZW1vdGUyLWVtZXJn
ZW5jeSIsIFJFTU9URTJfRU1FUkcsIDgpOwo+ICsJfQo+ICsjdW5kZWYgSU5JVF9SRUcKPiArI2Vu
ZGlmCj4gICB9Cj4KPiAgIHN0YXRpYyBib29sIGxtOTBfaXNfdHJpcHBlZChzdHJ1Y3QgaTJjX2Ns
aWVudCAqY2xpZW50LCB1MTYgKnN0YXR1cykKPgoKCl9fX19fX19fX19fX19fX19fX19fX19fX19f
X19fX19fX19fX19fX19fX19fX19fCmxtLXNlbnNvcnMgbWFpbGluZyBsaXN0CmxtLXNlbnNvcnNA
bG0tc2Vuc29ycy5vcmcKaHR0cDovL2xpc3RzLmxtLXNlbnNvcnMub3JnL21haWxtYW4vbGlzdGlu
Zm8vbG0tc2Vuc29ycw=

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 1/3] lm90: separate register accessors from sysfs
       [not found]         ` <56A23FD2.9040009-0h96xk9xTtrk1uMJSBkQmQ@public.gmane.org>
@ 2016-01-22 22:00             ` Stéphan Kochen
  0 siblings, 0 replies; 23+ messages in thread
From: Stéphan Kochen @ 2016-01-22 22:00 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: Jean Delvare, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, lm-sensors-GZX6beZjE8VD60Wz+7aTrA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Guenter,

Thanks for the taking the time to review!

You are absolutely right. I will split this up, more carefully check
coding style and simply do away with unnecessary changes.

Regarding:

On Fri, Jan 22, 2016 at 06:42:26AM -0800, Guenter Roeck wrote:
> On 01/21/2016 11:34 AM, Stéphan Kochen wrote:
> >+#define SELECT_REGS(_reg, _channel) { \
> >+	high = LM90_REG_W_##_reg##H; \
> >+	low = LM90_REG_W_##_reg##L; \
> >+	channel = _channel; \
> >+}
> 
> We have been trying to get rid of function defines such as this one.
> Most of the time it increases code size, and reduces readability.
> Plus, it increases the amount of time we have to spend reviewing
> the code to ensure it is correct.
> 
> >+	switch (index) {
> >+	case REMOTE_LOW:    SELECT_REGS(REMOTE_LOW,  0); break;
> >+	case REMOTE_HIGH:   SELECT_REGS(REMOTE_HIGH, 0); break;
> >+	case REMOTE_OFFSET: SELECT_REGS(REMOTE_OFFS, 0); break;
> >+	case REMOTE2_LOW:   SELECT_REGS(REMOTE_LOW,  1); break;
> >+	case REMOTE2_HIGH:  SELECT_REGS(REMOTE_HIGH, 1); break;
> >+	default: return;
> 
> ... and, in this case, introduces checkpatch errors.

Should I simply unfold the macro here? Another option would be an array
of structs like in set_temp8, but it'd have some gaps here. Or is some
other construct preferred?

I guess this is where I snuck in another change (which I will separate),
to replace SENSOR_DEVICE_ATTR_2 with regular ATTR. The setter args of
_ATTR_2 were using literal numbers to point into an array defined in the
setter function. (Maybe to avoid exactly the kind of thing I built
here.)

Would it be an idea to combine temp8 and temp11 variants, and let the
getters and setters figure out what kind of register access to do based
on register index?

Thanks again,

-- 
Stéphan Kochen
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [lm-sensors] [PATCH 1/3] lm90: separate register accessors from sysfs
@ 2016-01-22 22:00             ` Stéphan Kochen
  0 siblings, 0 replies; 23+ messages in thread
From: Stéphan Kochen @ 2016-01-22 22:00 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: Jean Delvare, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, lm-sensors-GZX6beZjE8VD60Wz+7aTrA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Guenter,

Thanks for the taking the time to review!

You are absolutely right. I will split this up, more carefully check
coding style and simply do away with unnecessary changes.

Regarding:

On Fri, Jan 22, 2016 at 06:42:26AM -0800, Guenter Roeck wrote:
> On 01/21/2016 11:34 AM, Stéphan Kochen wrote:
> >+#define SELECT_REGS(_reg, _channel) { \
> >+	high = LM90_REG_W_##_reg##H; \
> >+	low = LM90_REG_W_##_reg##L; \
> >+	channel = _channel; \
> >+}
> 
> We have been trying to get rid of function defines such as this one.
> Most of the time it increases code size, and reduces readability.
> Plus, it increases the amount of time we have to spend reviewing
> the code to ensure it is correct.
> 
> >+	switch (index) {
> >+	case REMOTE_LOW:    SELECT_REGS(REMOTE_LOW,  0); break;
> >+	case REMOTE_HIGH:   SELECT_REGS(REMOTE_HIGH, 0); break;
> >+	case REMOTE_OFFSET: SELECT_REGS(REMOTE_OFFS, 0); break;
> >+	case REMOTE2_LOW:   SELECT_REGS(REMOTE_LOW,  1); break;
> >+	case REMOTE2_HIGH:  SELECT_REGS(REMOTE_HIGH, 1); break;
> >+	default: return;
> 
> ... and, in this case, introduces checkpatch errors.

Should I simply unfold the macro here? Another option would be an array
of structs like in set_temp8, but it'd have some gaps here. Or is some
other construct preferred?

I guess this is where I snuck in another change (which I will separate),
to replace SENSOR_DEVICE_ATTR_2 with regular ATTR. The setter args of
_ATTR_2 were using literal numbers to point into an array defined in the
setter function. (Maybe to avoid exactly the kind of thing I built
here.)

Would it be an idea to combine temp8 and temp11 variants, and let the
getters and setters figure out what kind of register access to do based
on register index?

Thanks again,

-- 
Stéphan Kochen

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 2/3] lm90: initialize parameters from devicetree
       [not found]         ` <56A24278.8050909-0h96xk9xTtrk1uMJSBkQmQ@public.gmane.org>
@ 2016-01-22 22:32             ` Stéphan Kochen
  0 siblings, 0 replies; 23+ messages in thread
From: Stéphan Kochen @ 2016-01-22 22:32 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: Jean Delvare, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, lm-sensors-GZX6beZjE8VD60Wz+7aTrA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Fri, Jan 22, 2016 at 06:53:44AM -0800, Guenter Roeck wrote:
> On 01/21/2016 11:34 AM, Stéphan Kochen wrote:
> >Allow a device tree to set initial temperature sensor parameters.
> 
> This very much smells like configuration, not hardware description.
> 
> Having said that, the thermal subsystem does something similar. This raises even more
> questions, though. Since patch 3 of the series introduces registration with the thermal
> subsystem, it seems to me that the thermal subsystem should provide any limits used
> to program the chips, and that there should be a mechanism for the thermal subsystem
> to interact with the driver to both set the limits and to be informed if a limit
> is exceeded.
> 
> Also, _if_ such a set of properties is introduced and accepted by the devicetree
> reviewers, it should probably be a set of properties which applies to _all_ hardware
> monitoring drivers, not just to one. Even if support is not implemented immediately
> in the hwmon core, the properties should be usable in a generic way, and not
> reflect sysfs attribute names used by the hwmon subsystem.

The original kernel for Ouya is a 3.1 kernel from nVidia's old
Linux4Tegra branches. This kernel had its own Tegra-specific thermal
zone support which seems to do more or less that: the thermal zone
system actually uses the sensor alert interrupts to detect when it needs
to act, and reconfigures alert bounds as the temperature slides to
another range it wants to monitor.

Thermal zones in current master only have the ability to check sensor
values at an interval.

I'd agree that update-interval and the low/high bounds could be
controlled by the thermal zone system. I'm less certain what to do with
the critical/emergency bounds, and the remote-offset.

Thing about Ouya is that, even with the thermal zone currently working,
the alert bounds set when the system comes up seem to be crippling the
system with interrupts shortly after the sensor is activated. So they
have to be set to something sane. Hence why I added both.

I'm not sure if you're expecting me to do the work of extending thermal
zones. I guess I'd need to figure out how a sensor would notify a
thermal zone of an alert, and implement that functionality while staying
backwards compatible.

Thanks again,

-- 
Stéphan Kochen
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [lm-sensors] [PATCH 2/3] lm90: initialize parameters from devicetree
@ 2016-01-22 22:32             ` Stéphan Kochen
  0 siblings, 0 replies; 23+ messages in thread
From: Stéphan Kochen @ 2016-01-22 22:32 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: Jean Delvare, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, lm-sensors-GZX6beZjE8VD60Wz+7aTrA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Fri, Jan 22, 2016 at 06:53:44AM -0800, Guenter Roeck wrote:
> On 01/21/2016 11:34 AM, Stéphan Kochen wrote:
> >Allow a device tree to set initial temperature sensor parameters.
> 
> This very much smells like configuration, not hardware description.
> 
> Having said that, the thermal subsystem does something similar. This raises even more
> questions, though. Since patch 3 of the series introduces registration with the thermal
> subsystem, it seems to me that the thermal subsystem should provide any limits used
> to program the chips, and that there should be a mechanism for the thermal subsystem
> to interact with the driver to both set the limits and to be informed if a limit
> is exceeded.
> 
> Also, _if_ such a set of properties is introduced and accepted by the devicetree
> reviewers, it should probably be a set of properties which applies to _all_ hardware
> monitoring drivers, not just to one. Even if support is not implemented immediately
> in the hwmon core, the properties should be usable in a generic way, and not
> reflect sysfs attribute names used by the hwmon subsystem.

The original kernel for Ouya is a 3.1 kernel from nVidia's old
Linux4Tegra branches. This kernel had its own Tegra-specific thermal
zone support which seems to do more or less that: the thermal zone
system actually uses the sensor alert interrupts to detect when it needs
to act, and reconfigures alert bounds as the temperature slides to
another range it wants to monitor.

Thermal zones in current master only have the ability to check sensor
values at an interval.

I'd agree that update-interval and the low/high bounds could be
controlled by the thermal zone system. I'm less certain what to do with
the critical/emergency bounds, and the remote-offset.

Thing about Ouya is that, even with the thermal zone currently working,
the alert bounds set when the system comes up seem to be crippling the
system with interrupts shortly after the sensor is activated. So they
have to be set to something sane. Hence why I added both.

I'm not sure if you're expecting me to do the work of extending thermal
zones. I guess I'd need to figure out how a sensor would notify a
thermal zone of an alert, and implement that functionality while staying
backwards compatible.

Thanks again,

-- 
Stéphan Kochen

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 3/3] lm90: register with thermal zones
       [not found]     ` <1453404877-17897-4-git-send-email-stephan-j6uo2F6POYhmR6Xm/wNWPw@public.gmane.org>
@ 2016-01-22 22:45         ` Rob Herring
  0 siblings, 0 replies; 23+ messages in thread
From: Rob Herring @ 2016-01-22 22:45 UTC (permalink / raw)
  To: Stéphan Kochen
  Cc: Jean Delvare, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Guenter Roeck, lm-sensors-GZX6beZjE8VD60Wz+7aTrA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Thu, Jan 21, 2016 at 08:34:37PM +0100, Stéphan Kochen wrote:
> Any lm90-driven node in the device tree can now be referenced in thermal
> zones. One thermal zone device is registered for each sensor present.
> 
> Signed-off-by: Stéphan Kochen <stephan-j6uo2F6POYhmR6Xm/wNWPw@public.gmane.org>
> ---
>  Documentation/devicetree/bindings/hwmon/lm90.txt |  8 ++++
>  drivers/hwmon/lm90.c                             | 54 ++++++++++++++++++++++++
>  2 files changed, 62 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/hwmon/lm90.txt b/Documentation/devicetree/bindings/hwmon/lm90.txt
> index 045e94b..da9aae7 100644
> --- a/Documentation/devicetree/bindings/hwmon/lm90.txt
> +++ b/Documentation/devicetree/bindings/hwmon/lm90.txt
> @@ -28,6 +28,13 @@ Required node properties:
>  
>  - vcc-supply: vcc regulator for the supply voltage.
>  
> +- #thermal-sensor-cells: Should be 1. See ../../thermal/thermal.txt for a
> +                         description of this property. Use the following
> +                         values to refer to a specific sensor:
> +                         0: chip internal sensor
> +                         1: external sensor
> +                         2: second external sensor, if present

From my read of an LM90 datasheet, there is only an onchip sensor and a 
single external one.

Rob
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [lm-sensors] [PATCH 3/3] lm90: register with thermal zones
@ 2016-01-22 22:45         ` Rob Herring
  0 siblings, 0 replies; 23+ messages in thread
From: Rob Herring @ 2016-01-22 22:45 UTC (permalink / raw)
  To: Stéphan Kochen
  Cc: Jean Delvare, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Guenter Roeck, lm-sensors-GZX6beZjE8VD60Wz+7aTrA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Thu, Jan 21, 2016 at 08:34:37PM +0100, Stéphan Kochen wrote:
> Any lm90-driven node in the device tree can now be referenced in thermal
> zones. One thermal zone device is registered for each sensor present.
> 
> Signed-off-by: Stéphan Kochen <stephan@kochen.nl>
> ---
>  Documentation/devicetree/bindings/hwmon/lm90.txt |  8 ++++
>  drivers/hwmon/lm90.c                             | 54 ++++++++++++++++++++++++
>  2 files changed, 62 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/hwmon/lm90.txt b/Documentation/devicetree/bindings/hwmon/lm90.txt
> index 045e94b..da9aae7 100644
> --- a/Documentation/devicetree/bindings/hwmon/lm90.txt
> +++ b/Documentation/devicetree/bindings/hwmon/lm90.txt
> @@ -28,6 +28,13 @@ Required node properties:
>  
>  - vcc-supply: vcc regulator for the supply voltage.
>  
> +- #thermal-sensor-cells: Should be 1. See ../../thermal/thermal.txt for a
> +                         description of this property. Use the following
> +                         values to refer to a specific sensor:
> +                         0: chip internal sensor
> +                         1: external sensor
> +                         2: second external sensor, if present

From my read of an LM90 datasheet, there is only an onchip sensor and a 
single external one.

Rob

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 3/3] lm90: register with thermal zones
  2016-01-22 22:45         ` [lm-sensors] " Rob Herring
@ 2016-01-22 23:02           ` Stéphan Kochen
  -1 siblings, 0 replies; 23+ messages in thread
From: Stéphan Kochen @ 2016-01-22 23:02 UTC (permalink / raw)
  To: Rob Herring
  Cc: Jean Delvare, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Guenter Roeck, lm-sensors-GZX6beZjE8VD60Wz+7aTrA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Fri, Jan 22, 2016 at 04:45:42PM -0600, Rob Herring wrote:
> On Thu, Jan 21, 2016 at 08:34:37PM +0100, Stéphan Kochen wrote:
> > +- #thermal-sensor-cells: Should be 1. See ../../thermal/thermal.txt for a
> > +                         description of this property. Use the following
> > +                         values to refer to a specific sensor:
> > +                         0: chip internal sensor
> > +                         1: external sensor
> > +                         2: second external sensor, if present
> 
> From my read of an LM90 datasheet, there is only an onchip sensor and a 
> single external one.

MAX6695 and MAX6696 have two external sensors, and also use the lm90
driver. (The LM90_HAVE_TEMP3 flag in the code.)

-- 
Stéphan Kochen
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [lm-sensors] [PATCH 3/3] lm90: register with thermal zones
@ 2016-01-22 23:02           ` Stéphan Kochen
  0 siblings, 0 replies; 23+ messages in thread
From: Stéphan Kochen @ 2016-01-22 23:02 UTC (permalink / raw)
  To: Rob Herring
  Cc: Jean Delvare, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Guenter Roeck, lm-sensors-GZX6beZjE8VD60Wz+7aTrA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Fri, Jan 22, 2016 at 04:45:42PM -0600, Rob Herring wrote:
> On Thu, Jan 21, 2016 at 08:34:37PM +0100, Stéphan Kochen wrote:
> > +- #thermal-sensor-cells: Should be 1. See ../../thermal/thermal.txt for a
> > +                         description of this property. Use the following
> > +                         values to refer to a specific sensor:
> > +                         0: chip internal sensor
> > +                         1: external sensor
> > +                         2: second external sensor, if present
> 
> From my read of an LM90 datasheet, there is only an onchip sensor and a 
> single external one.

MAX6695 and MAX6696 have two external sensors, and also use the lm90
driver. (The LM90_HAVE_TEMP3 flag in the code.)

-- 
Stéphan Kochen

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 3/3] lm90: register with thermal zones
       [not found]           ` <20160122230239.GA22301-3Ql6wuUqVi7fKcxHm0zdRv8+0UxHXcjY@public.gmane.org>
@ 2016-01-22 23:11               ` Rob Herring
  0 siblings, 0 replies; 23+ messages in thread
From: Rob Herring @ 2016-01-22 23:11 UTC (permalink / raw)
  To: Stéphan Kochen
  Cc: Jean Delvare, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Guenter Roeck, lm-sensors-GZX6beZjE8VD60Wz+7aTrA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On Fri, Jan 22, 2016 at 5:02 PM, Stéphan Kochen <stephan-j6uo2F6POYhmR6Xm/wNWPw@public.gmane.org> wrote:
> On Fri, Jan 22, 2016 at 04:45:42PM -0600, Rob Herring wrote:
>> On Thu, Jan 21, 2016 at 08:34:37PM +0100, Stéphan Kochen wrote:
>> > +- #thermal-sensor-cells: Should be 1. See ../../thermal/thermal.txt for a
>> > +                         description of this property. Use the following
>> > +                         values to refer to a specific sensor:
>> > +                         0: chip internal sensor
>> > +                         1: external sensor
>> > +                         2: second external sensor, if present
>>
>> From my read of an LM90 datasheet, there is only an onchip sensor and a
>> single external one.
>
> MAX6695 and MAX6696 have two external sensors, and also use the lm90
> driver. (The LM90_HAVE_TEMP3 flag in the code.)

Okay.

This change alone seems fine, but I agree with Guenter's comments. I
think having the data in DT is fine, but it should be something
common.

Rob
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [lm-sensors] [PATCH 3/3] lm90: register with thermal zones
@ 2016-01-22 23:11               ` Rob Herring
  0 siblings, 0 replies; 23+ messages in thread
From: Rob Herring @ 2016-01-22 23:11 UTC (permalink / raw)
  To: Stéphan Kochen
  Cc: Jean Delvare, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Guenter Roeck, lm-sensors-GZX6beZjE8VD60Wz+7aTrA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

T24gRnJpLCBKYW4gMjIsIDIwMTYgYXQgNTowMiBQTSwgU3TDqXBoYW4gS29jaGVuIDxzdGVwaGFu
QGtvY2hlbi5ubD4gd3JvdGU6Cj4gT24gRnJpLCBKYW4gMjIsIDIwMTYgYXQgMDQ6NDU6NDJQTSAt
MDYwMCwgUm9iIEhlcnJpbmcgd3JvdGU6Cj4+IE9uIFRodSwgSmFuIDIxLCAyMDE2IGF0IDA4OjM0
OjM3UE0gKzAxMDAsIFN0w6lwaGFuIEtvY2hlbiB3cm90ZToKPj4gPiArLSAjdGhlcm1hbC1zZW5z
b3ItY2VsbHM6IFNob3VsZCBiZSAxLiBTZWUgLi4vLi4vdGhlcm1hbC90aGVybWFsLnR4dCBmb3Ig
YQo+PiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gb2YgdGhpcyBwcm9w
ZXJ0eS4gVXNlIHRoZSBmb2xsb3dpbmcKPj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgIHZh
bHVlcyB0byByZWZlciB0byBhIHNwZWNpZmljIHNlbnNvcjoKPj4gPiArICAgICAgICAgICAgICAg
ICAgICAgICAgIDA6IGNoaXAgaW50ZXJuYWwgc2Vuc29yCj4+ID4gKyAgICAgICAgICAgICAgICAg
ICAgICAgICAxOiBleHRlcm5hbCBzZW5zb3IKPj4gPiArICAgICAgICAgICAgICAgICAgICAgICAg
IDI6IHNlY29uZCBleHRlcm5hbCBzZW5zb3IsIGlmIHByZXNlbnQKPj4KPj4gRnJvbSBteSByZWFk
IG9mIGFuIExNOTAgZGF0YXNoZWV0LCB0aGVyZSBpcyBvbmx5IGFuIG9uY2hpcCBzZW5zb3IgYW5k
IGEKPj4gc2luZ2xlIGV4dGVybmFsIG9uZS4KPgo+IE1BWDY2OTUgYW5kIE1BWDY2OTYgaGF2ZSB0
d28gZXh0ZXJuYWwgc2Vuc29ycywgYW5kIGFsc28gdXNlIHRoZSBsbTkwCj4gZHJpdmVyLiAoVGhl
IExNOTBfSEFWRV9URU1QMyBmbGFnIGluIHRoZSBjb2RlLikKCk9rYXkuCgpUaGlzIGNoYW5nZSBh
bG9uZSBzZWVtcyBmaW5lLCBidXQgSSBhZ3JlZSB3aXRoIEd1ZW50ZXIncyBjb21tZW50cy4gSQp0
aGluayBoYXZpbmcgdGhlIGRhdGEgaW4gRFQgaXMgZmluZSwgYnV0IGl0IHNob3VsZCBiZSBzb21l
dGhpbmcKY29tbW9uLgoKUm9iCgpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f
X19fX19fX19fXwpsbS1zZW5zb3JzIG1haWxpbmcgbGlzdApsbS1zZW5zb3JzQGxtLXNlbnNvcnMu
b3JnCmh0dHA6Ly9saXN0cy5sbS1zZW5zb3JzLm9yZy9tYWlsbWFuL2xpc3RpbmZvL2xtLXNlbnNv
cnM

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 2/3] lm90: initialize parameters from devicetree
  2016-01-22 22:32             ` [lm-sensors] " Stéphan Kochen
  (?)
@ 2016-01-23  2:53             ` Guenter Roeck
       [not found]               ` <56A2EB3E.4080002-0h96xk9xTtrk1uMJSBkQmQ@public.gmane.org>
  -1 siblings, 1 reply; 23+ messages in thread
From: Guenter Roeck @ 2016-01-23  2:53 UTC (permalink / raw)
  To: Stéphan Kochen
  Cc: Jean Delvare, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, lm-sensors, devicetree, linux-pm,
	Zhang Rui, Eduardo Valentin

On 01/22/2016 02:32 PM, Stéphan Kochen wrote:
> On Fri, Jan 22, 2016 at 06:53:44AM -0800, Guenter Roeck wrote:
>> On 01/21/2016 11:34 AM, Stéphan Kochen wrote:
>>> Allow a device tree to set initial temperature sensor parameters.
>>
>> This very much smells like configuration, not hardware description.
>>
>> Having said that, the thermal subsystem does something similar. This raises even more
>> questions, though. Since patch 3 of the series introduces registration with the thermal
>> subsystem, it seems to me that the thermal subsystem should provide any limits used
>> to program the chips, and that there should be a mechanism for the thermal subsystem
>> to interact with the driver to both set the limits and to be informed if a limit
>> is exceeded.
>>
>> Also, _if_ such a set of properties is introduced and accepted by the devicetree
>> reviewers, it should probably be a set of properties which applies to _all_ hardware
>> monitoring drivers, not just to one. Even if support is not implemented immediately
>> in the hwmon core, the properties should be usable in a generic way, and not
>> reflect sysfs attribute names used by the hwmon subsystem.
>
> The original kernel for Ouya is a 3.1 kernel from nVidia's old
> Linux4Tegra branches. This kernel had its own Tegra-specific thermal
> zone support which seems to do more or less that: the thermal zone
> system actually uses the sensor alert interrupts to detect when it needs
> to act, and reconfigures alert bounds as the temperature slides to
> another range it wants to monitor.
>
> Thermal zones in current master only have the ability to check sensor
> values at an interval.
>
> I'd agree that update-interval and the low/high bounds could be
> controlled by the thermal zone system. I'm less certain what to do with
> the critical/emergency bounds, and the remote-offset.
>
> Thing about Ouya is that, even with the thermal zone currently working,
> the alert bounds set when the system comes up seem to be crippling the
> system with interrupts shortly after the sensor is activated. So they
> have to be set to something sane. Hence why I added both.
>
> I'm not sure if you're expecting me to do the work of extending thermal
> zones. I guess I'd need to figure out how a sensor would notify a
> thermal zone of an alert, and implement that functionality while staying
> backwards compatible.
>
The thermal subsystem supports setting trip points, which I would think
is what you are looking for here. Question is if an how you can use the
information from the thermal subsystem (and thus the thermal zone configuration)
to set the various limits in the lm90 driver. This should hopefully be sufficient
to fix your immediate problem. For handling alerts, I guess we'll have to wait for
thermal subsystem improvements (unless of course you volunteer to do that work.

Copying the the linux-pm mailing list and thermal maintainers for additional advise.

Thanks,
Guenter


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [lm-sensors] [PATCH 1/3] lm90: separate register accessors from sysfs
       [not found]             ` <20160122220056.GA21534-3Ql6wuUqVi7fKcxHm0zdRv8+0UxHXcjY@public.gmane.org>
@ 2016-01-25  9:41               ` Jean Delvare
  0 siblings, 0 replies; 23+ messages in thread
From: Jean Delvare @ 2016-01-25  9:41 UTC (permalink / raw)
  To: Stéphan Kochen
  Cc: Guenter Roeck, Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA,
	Jean Delvare, Pawel Moll, Ian Campbell,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA, Rob Herring, Kumar Gala

Hi Stéphan and Guenter,

On Fri, 22 Jan 2016 23:00:57 +0100, Stéphan Kochen wrote:
> Guenter,
> 
> Thanks for the taking the time to review!
> 
> You are absolutely right. I will split this up, more carefully check
> coding style and simply do away with unnecessary changes.

Yes, thanks Guenter for the initial review.

> Regarding:
> 
> On Fri, Jan 22, 2016 at 06:42:26AM -0800, Guenter Roeck wrote:
> > On 01/21/2016 11:34 AM, Stéphan Kochen wrote:
> > >+#define SELECT_REGS(_reg, _channel) { \
> > >+	high = LM90_REG_W_##_reg##H; \
> > >+	low = LM90_REG_W_##_reg##L; \
> > >+	channel = _channel; \
> > >+}
> > 
> > We have been trying to get rid of function defines such as this one.
> > Most of the time it increases code size, and reduces readability.
> > Plus, it increases the amount of time we have to spend reviewing
> > the code to ensure it is correct.
> > 
> > >+	switch (index) {
> > >+	case REMOTE_LOW:    SELECT_REGS(REMOTE_LOW,  0); break;
> > >+	case REMOTE_HIGH:   SELECT_REGS(REMOTE_HIGH, 0); break;
> > >+	case REMOTE_OFFSET: SELECT_REGS(REMOTE_OFFS, 0); break;
> > >+	case REMOTE2_LOW:   SELECT_REGS(REMOTE_LOW,  1); break;
> > >+	case REMOTE2_HIGH:  SELECT_REGS(REMOTE_HIGH, 1); break;
> > >+	default: return;
> > 
> > ... and, in this case, introduces checkpatch errors.
> 
> Should I simply unfold the macro here? Another option would be an array
> of structs like in set_temp8, but it'd have some gaps here. Or is some
> other construct preferred?

Anything will be better than macro-generated functions.

> I guess this is where I snuck in another change (which I will separate),
> to replace SENSOR_DEVICE_ATTR_2 with regular ATTR. The setter args of
> _ATTR_2 were using literal numbers to point into an array defined in the
> setter function. (Maybe to avoid exactly the kind of thing I built
> here.)
> 
> Would it be an idea to combine temp8 and temp11 variants, and let the
> getters and setters figure out what kind of register access to do based
> on register index?

Can't answer that as long as I don't know which problem you are trying
to solve. Hopefully this will become clearer once the changes are
cleanly separated into incremental steps.

-- 
Jean Delvare
SUSE L3 Support
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Interrupt driven thermal OF sensors (was: [PATCH 2/3] lm90: initialize parameters from devicetree)
       [not found]               ` <56A2EB3E.4080002-0h96xk9xTtrk1uMJSBkQmQ@public.gmane.org>
@ 2016-01-27 21:18                 ` Stéphan Kochen
  2016-01-28  5:05                   ` Interrupt driven thermal OF sensors Guenter Roeck
  0 siblings, 1 reply; 23+ messages in thread
From: Stéphan Kochen @ 2016-01-27 21:18 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: Jean Delvare, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, lm-sensors-GZX6beZjE8VD60Wz+7aTrA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Zhang Rui, Eduardo Valentin

On Fri, Jan 22, 2016 at 06:53:50PM -0800, Guenter Roeck wrote:
> The thermal subsystem supports setting trip points, which I would think
> is what you are looking for here. Question is if an how you can use the
> information from the thermal subsystem (and thus the thermal zone configuration)
> to set the various limits in the lm90 driver. This should hopefully be sufficient
> to fix your immediate problem. For handling alerts, I guess we'll have to wait for
> thermal subsystem improvements (unless of course you volunteer to do that work.

I may take a shot at this. So in short, the goal is to have a device
tree thermal zone communicate trip points to the sensor driver, and use
interrupts to act on trips.

(This indirectly solves my problem of my sensor having weird initial
values. Perhaps we also want a solution for this case if the thermal
subsystem is disabled, but for me there'd be no need.)

Here's what I see:

 - The thermal core layer already supports interrupt driven systems.
   Support is missing from thermal OF, the layer between thermal core
   and the sensor driver implementing device tree support.

 - Thermal OF registers a device in thermal core for each zone defined
   in the device tree.

 - In theory, a thermal zone in the device tree can have multiple
   sensors, and multiple zones can refer to the same sensor, but the
   current implementation only supports 1-on-1 relations.

 - There are already exports thermal_zone_device_update and
   thermal_notify_framework in thermal core, which allow external code
   to trigger an update.

 - Updates happen by explicit calls to such exports, or by an optional
   and configurable interval in thermal core.

What I think we want:

 - Any additions should be optional extensions implemented by sensor
   drivers. Polling should keep on working for all sensor drivers
   already supporting thermal OF, with no interface changes.

 - For interrupt-capable sensor drivers, the thermal OF device should
   keep the sensor driver updated with the current nearest trip
   temperature and hysteresis. (Don't burden drivers with a full list of
   trip points.)

 - In the case of LM90, this would set the low and high alert
   temperatures. LM90 can have additional alerts (critical, emergency),
   but a sensor driver registered with thermal OF should disable any
   additional alerts.

 - Similarly, a sensor driver should disable alerts when there is no
   current trip temperature or hysteresis. (E.g., we're below the lowest
   trip point.)

Implementation-wise:

 - The struct thermal_zone_of_device_ops needs an additional function to
   set the current sensor trip temperature and hysteresis. Presence of
   this function indicates the sensor driver has interrupt support.

 - The thermal OF device will call this function every time the
   temperature slides across trip points. (Or when trip points are
   altered.)

 - The thermal OF device should ignore the polling delay (set it to 0)
   if its sensor has interrupt support. (In this case, we can also make
   polling-delay optional. It's currently required in the device tree.)

 - On interrupt, the sensor driver should call
   thermal_zone_device_update with its thermal_zone_device, as returned
   by thermal_zone_of_sensor_register.

My only concern is that I don't understand kernel contexts and interrupt
handling well enough. It looks like at least its up to the sensor driver
to ensure calls into the thermal subsystem have long left the hardware
interrupt context, which I think should be sufficient.

Hoping all of this sounds about right!

-- 
Stéphan Kochen
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: Interrupt driven thermal OF sensors
  2016-01-27 21:18                 ` Interrupt driven thermal OF sensors (was: [PATCH 2/3] lm90: initialize parameters from devicetree) Stéphan Kochen
@ 2016-01-28  5:05                   ` Guenter Roeck
  2016-01-29  0:16                     ` Stéphan Kochen
  0 siblings, 1 reply; 23+ messages in thread
From: Guenter Roeck @ 2016-01-28  5:05 UTC (permalink / raw)
  To: Stéphan Kochen
  Cc: Jean Delvare, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, lm-sensors, devicetree, linux-pm,
	Zhang Rui, Eduardo Valentin

On 01/27/2016 01:18 PM, Stéphan Kochen wrote:
> On Fri, Jan 22, 2016 at 06:53:50PM -0800, Guenter Roeck wrote:
>> The thermal subsystem supports setting trip points, which I would think
>> is what you are looking for here. Question is if an how you can use the
>> information from the thermal subsystem (and thus the thermal zone configuration)
>> to set the various limits in the lm90 driver. This should hopefully be sufficient
>> to fix your immediate problem. For handling alerts, I guess we'll have to wait for
>> thermal subsystem improvements (unless of course you volunteer to do that work.
>
> I may take a shot at this. So in short, the goal is to have a device
> tree thermal zone communicate trip points to the sensor driver, and use
> interrupts to act on trips.
>
> (This indirectly solves my problem of my sensor having weird initial
> values. Perhaps we also want a solution for this case if the thermal
> subsystem is disabled, but for me there'd be no need.)
>
> Here's what I see:
>
>   - The thermal core layer already supports interrupt driven systems.
>     Support is missing from thermal OF, the layer between thermal core
>     and the sensor driver implementing device tree support.
>
>   - Thermal OF registers a device in thermal core for each zone defined
>     in the device tree.
>
>   - In theory, a thermal zone in the device tree can have multiple
>     sensors, and multiple zones can refer to the same sensor, but the
>     current implementation only supports 1-on-1 relations.
>
>   - There are already exports thermal_zone_device_update and
>     thermal_notify_framework in thermal core, which allow external code
>     to trigger an update.
>
>   - Updates happen by explicit calls to such exports, or by an optional
>     and configurable interval in thermal core.
>
> What I think we want:
>
>   - Any additions should be optional extensions implemented by sensor
>     drivers. Polling should keep on working for all sensor drivers
>     already supporting thermal OF, with no interface changes.
>
>   - For interrupt-capable sensor drivers, the thermal OF device should
>     keep the sensor driver updated with the current nearest trip
>     temperature and hysteresis. (Don't burden drivers with a full list of
>     trip points.)
>
>   - In the case of LM90, this would set the low and high alert
>     temperatures. LM90 can have additional alerts (critical, emergency),
>     but a sensor driver registered with thermal OF should disable any
>     additional alerts.
>
... and thus disable any external chip signals associated with those limits.

>   - Similarly, a sensor driver should disable alerts when there is no
>     current trip temperature or hysteresis. (E.g., we're below the lowest
>     trip point.)
>

The idea with most if not all temperature sensors is that multiple trip points
would be configured as multiple limits in the chip. Often those limits,
when reached, are tied to pins to cause a specific action (eg to cause
an interrupt, turn on a fan, or shut down the hardware). In effect, you
suggest to re-define this mechanism and, for all practical purposes,
use just one of the limits provided by the chip(s).

Personally I don't think that would be a good idea, because it would have
impact on hardware design. It would effectively limit the use of the thermal
subsystem with temperature sensor chips to hardware designs which take
the thermal subsystem's expectations and assumptions into account.
At the same time, it would for all practical purposes mandate the use
of the thermal subsystem on such systems, because the hardware would depend
on the thermal subsystem's implementation to control the temperature
in the system.

While it may be feasible in some situations to have the thermal subsystem
dynamically set free-moving limits, there are many other situations where
those limits are tied to hardware responses, and the limits need to be static.

Maybe this is just a different world view. The thermal subsystem may see the
world assuming that it always has an unlimited number of trip points available,
and the chip it supports only support lower and upper boundaries (or trip points),
which can be set and changed as needed. This is somewhat different to the
traditional world view, implemented not only in many temperature sensors,
but also in fan controller or Super-IO chips, where a set of temperatures
is programmed into the chip only once. I hope that it is possible to support
both mechanisms.

Thanks,
Guenter

> Implementation-wise:
>
>   - The struct thermal_zone_of_device_ops needs an additional function to
>     set the current sensor trip temperature and hysteresis. Presence of
>     this function indicates the sensor driver has interrupt support.
>
>   - The thermal OF device will call this function every time the
>     temperature slides across trip points. (Or when trip points are
>     altered.)
>
>   - The thermal OF device should ignore the polling delay (set it to 0)
>     if its sensor has interrupt support. (In this case, we can also make
>     polling-delay optional. It's currently required in the device tree.)
>
>   - On interrupt, the sensor driver should call
>     thermal_zone_device_update with its thermal_zone_device, as returned
>     by thermal_zone_of_sensor_register.
>
> My only concern is that I don't understand kernel contexts and interrupt
> handling well enough. It looks like at least its up to the sensor driver
> to ensure calls into the thermal subsystem have long left the hardware
> interrupt context, which I think should be sufficient.
>
> Hoping all of this sounds about right!
>


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: Interrupt driven thermal OF sensors
  2016-01-28  5:05                   ` Interrupt driven thermal OF sensors Guenter Roeck
@ 2016-01-29  0:16                     ` Stéphan Kochen
  0 siblings, 0 replies; 23+ messages in thread
From: Stéphan Kochen @ 2016-01-29  0:16 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: Jean Delvare, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, lm-sensors, devicetree, linux-pm,
	Zhang Rui, Eduardo Valentin

On Wed, Jan 27, 2016 at 09:05:08PM -0800, Guenter Roeck wrote:
> ... and thus disable any external chip signals associated with those limits.
> 
> The idea with most if not all temperature sensors is that multiple trip points
> would be configured as multiple limits in the chip. Often those limits,
> when reached, are tied to pins to cause a specific action (eg to cause
> an interrupt, turn on a fan, or shut down the hardware). In effect, you
> suggest to re-define this mechanism and, for all practical purposes,
> use just one of the limits provided by the chip(s).
> 
> Personally I don't think that would be a good idea, because it would have
> impact on hardware design. It would effectively limit the use of the thermal
> subsystem with temperature sensor chips to hardware designs which take
> the thermal subsystem's expectations and assumptions into account.
> At the same time, it would for all practical purposes mandate the use
> of the thermal subsystem on such systems, because the hardware would depend
> on the thermal subsystem's implementation to control the temperature
> in the system.

Ah, whoops. That makes a lot of sense. And I think I even saw the
poweroff in action once, when I misconfigured the temperature offset
register.

> While it may be feasible in some situations to have the thermal subsystem
> dynamically set free-moving limits, there are many other situations where
> those limits are tied to hardware responses, and the limits need to be static.
> 
> Maybe this is just a different world view. The thermal subsystem may see the
> world assuming that it always has an unlimited number of trip points available,
> and the chip it supports only support lower and upper boundaries (or trip points),
> which can be set and changed as needed. This is somewhat different to the
> traditional world view, implemented not only in many temperature sensors,
> but also in fan controller or Super-IO chips, where a set of temperatures
> is programmed into the chip only once. I hope that it is possible to support
> both mechanisms.

That would be nice.

For starters, I think it should be possible for a driver to enable
thermal subsystem stuff only if an of_node is present. (Though I haven't
checked what that's set to with `status = "disabled"` in the device
tree. Hopefully NULL.)

So, one option is to, instead of thermal OF telling the driver what the
limits are, we simply have thermal OF only notify the driver of trip
changes, and the driver does all the work of inspecting defined trips.

In the LM90 case, it can set low/high and critical alerts nicely based
on trip types (critical or not). But, for example, MAX6696 has an
additional 'emergency' alert. Should that just be left untouched?

Either way, this means hardcoding thermal trip to sensor alert mapping
in the driver. A more elaborate solution would be to define that mapping
in the device tree, and have thermal OF handle it, instructing the
driver to set specific alerts. (And then the device tree author may
choose to leave certain sensor alerts alone.)

-- 
Stéphan Kochen

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2016-01-29  0:16 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-21 19:34 [PATCH 0/3] lm90: device tree and thermal zone support Stéphan Kochen
     [not found] ` <1453404877-17897-1-git-send-email-stephan-j6uo2F6POYhmR6Xm/wNWPw@public.gmane.org>
2016-01-21 19:34   ` [PATCH 1/3] lm90: separate register accessors from sysfs Stéphan Kochen
     [not found]     ` <1453404877-17897-2-git-send-email-stephan-j6uo2F6POYhmR6Xm/wNWPw@public.gmane.org>
2016-01-22 14:42       ` Guenter Roeck
2016-01-22 14:42         ` [lm-sensors] " Guenter Roeck
     [not found]         ` <56A23FD2.9040009-0h96xk9xTtrk1uMJSBkQmQ@public.gmane.org>
2016-01-22 22:00           ` Stéphan Kochen
2016-01-22 22:00             ` [lm-sensors] " Stéphan Kochen
     [not found]             ` <20160122220056.GA21534-3Ql6wuUqVi7fKcxHm0zdRv8+0UxHXcjY@public.gmane.org>
2016-01-25  9:41               ` Jean Delvare
2016-01-21 19:34   ` [PATCH 2/3] lm90: initialize parameters from devicetree Stéphan Kochen
     [not found]     ` <1453404877-17897-3-git-send-email-stephan-j6uo2F6POYhmR6Xm/wNWPw@public.gmane.org>
2016-01-22 14:53       ` Guenter Roeck
2016-01-22 14:53         ` [lm-sensors] " Guenter Roeck
     [not found]         ` <56A24278.8050909-0h96xk9xTtrk1uMJSBkQmQ@public.gmane.org>
2016-01-22 22:32           ` Stéphan Kochen
2016-01-22 22:32             ` [lm-sensors] " Stéphan Kochen
2016-01-23  2:53             ` Guenter Roeck
     [not found]               ` <56A2EB3E.4080002-0h96xk9xTtrk1uMJSBkQmQ@public.gmane.org>
2016-01-27 21:18                 ` Interrupt driven thermal OF sensors (was: [PATCH 2/3] lm90: initialize parameters from devicetree) Stéphan Kochen
2016-01-28  5:05                   ` Interrupt driven thermal OF sensors Guenter Roeck
2016-01-29  0:16                     ` Stéphan Kochen
2016-01-21 19:34   ` [PATCH 3/3] lm90: register with thermal zones Stéphan Kochen
     [not found]     ` <1453404877-17897-4-git-send-email-stephan-j6uo2F6POYhmR6Xm/wNWPw@public.gmane.org>
2016-01-22 22:45       ` Rob Herring
2016-01-22 22:45         ` [lm-sensors] " Rob Herring
2016-01-22 23:02         ` Stéphan Kochen
2016-01-22 23:02           ` [lm-sensors] " Stéphan Kochen
     [not found]           ` <20160122230239.GA22301-3Ql6wuUqVi7fKcxHm0zdRv8+0UxHXcjY@public.gmane.org>
2016-01-22 23:11             ` Rob Herring
2016-01-22 23:11               ` [lm-sensors] " Rob Herring

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.