All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/9] hwmon: (adt7410) Clear unwanted bits in the config register
@ 2013-02-15 16:57 ` Lars-Peter Clausen
  0 siblings, 0 replies; 56+ messages in thread
From: Lars-Peter Clausen @ 2013-02-15 16:57 UTC (permalink / raw)
  To: Jean Delvare, Guenter Roeck
  Cc: Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio,
	Lars-Peter Clausen

Make sure to clear the mode bits from the config register before setting the new
mode. Otherwise we might end up with a different mode than we want to.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/hwmon/adt7410.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
index 797c2b8..4ccee4f 100644
--- a/drivers/hwmon/adt7410.c
+++ b/drivers/hwmon/adt7410.c
@@ -364,6 +364,7 @@ static int adt7410_probe(struct i2c_client *client,
 	/*
 	 * Set to 16 bit resolution, continous conversion and comparator mode.
 	 */
+	ret &= ~ADT7410_MODE_MASK;
 	data->config = ret | ADT7410_FULL | ADT7410_RESOLUTION |
 			ADT7410_EVENT_MODE;
 	if (data->config != data->oldconfig) {
-- 
1.8.0


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

* [lm-sensors] [PATCH 1/9] hwmon: (adt7410) Clear unwanted bits in the config register
@ 2013-02-15 16:57 ` Lars-Peter Clausen
  0 siblings, 0 replies; 56+ messages in thread
From: Lars-Peter Clausen @ 2013-02-15 16:57 UTC (permalink / raw)
  To: Jean Delvare, Guenter Roeck
  Cc: Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio,
	Lars-Peter Clausen

Make sure to clear the mode bits from the config register before setting the new
mode. Otherwise we might end up with a different mode than we want to.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/hwmon/adt7410.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
index 797c2b8..4ccee4f 100644
--- a/drivers/hwmon/adt7410.c
+++ b/drivers/hwmon/adt7410.c
@@ -364,6 +364,7 @@ static int adt7410_probe(struct i2c_client *client,
 	/*
 	 * Set to 16 bit resolution, continous conversion and comparator mode.
 	 */
+	ret &= ~ADT7410_MODE_MASK;
 	data->config = ret | ADT7410_FULL | ADT7410_RESOLUTION |
 			ADT7410_EVENT_MODE;
 	if (data->config != data->oldconfig) {
-- 
1.8.0


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

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

* [PATCH 2/9] hwmon: (adt7410) Let suspend/resume depend on CONFIG_PM_SLEEP
  2013-02-15 16:57 ` [lm-sensors] " Lars-Peter Clausen
@ 2013-02-15 16:57   ` Lars-Peter Clausen
  -1 siblings, 0 replies; 56+ messages in thread
From: Lars-Peter Clausen @ 2013-02-15 16:57 UTC (permalink / raw)
  To: Jean Delvare, Guenter Roeck
  Cc: Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio,
	Lars-Peter Clausen

Only build the suspend/resume code if CONFIG_PM_SLEEP is selected. Currently the
code is built if CONFIG_PM is selected, but it will also be selected if only
runtime PM support is built into the kernel.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/hwmon/adt7410.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
index 4ccee4f..ae80815 100644
--- a/drivers/hwmon/adt7410.c
+++ b/drivers/hwmon/adt7410.c
@@ -415,7 +415,7 @@ static const struct i2c_device_id adt7410_ids[] = {
 };
 MODULE_DEVICE_TABLE(i2c, adt7410_ids);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int adt7410_suspend(struct device *dev)
 {
 	int ret;
-- 
1.8.0


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

* [lm-sensors] [PATCH 2/9] hwmon: (adt7410) Let suspend/resume depend on CONFIG_PM_SLEEP
@ 2013-02-15 16:57   ` Lars-Peter Clausen
  0 siblings, 0 replies; 56+ messages in thread
From: Lars-Peter Clausen @ 2013-02-15 16:57 UTC (permalink / raw)
  To: Jean Delvare, Guenter Roeck
  Cc: Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio,
	Lars-Peter Clausen

Only build the suspend/resume code if CONFIG_PM_SLEEP is selected. Currently the
code is built if CONFIG_PM is selected, but it will also be selected if only
runtime PM support is built into the kernel.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/hwmon/adt7410.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
index 4ccee4f..ae80815 100644
--- a/drivers/hwmon/adt7410.c
+++ b/drivers/hwmon/adt7410.c
@@ -415,7 +415,7 @@ static const struct i2c_device_id adt7410_ids[] = {
 };
 MODULE_DEVICE_TABLE(i2c, adt7410_ids);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int adt7410_suspend(struct device *dev)
 {
 	int ret;
-- 
1.8.0


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

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

* [PATCH 3/9] hwmon: (adt7410) Use the SIMPLE_DEV_PM_OPS helper macro
  2013-02-15 16:57 ` [lm-sensors] " Lars-Peter Clausen
@ 2013-02-15 16:57   ` Lars-Peter Clausen
  -1 siblings, 0 replies; 56+ messages in thread
From: Lars-Peter Clausen @ 2013-02-15 16:57 UTC (permalink / raw)
  To: Jean Delvare, Guenter Roeck
  Cc: Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio,
	Lars-Peter Clausen

Use the SIMPLE_DEV_PM_OPS macro to declare the driver's pm_ops.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/hwmon/adt7410.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
index ae80815..4ae16e0 100644
--- a/drivers/hwmon/adt7410.c
+++ b/drivers/hwmon/adt7410.c
@@ -437,10 +437,8 @@ static int adt7410_resume(struct device *dev)
 	return ret;
 }
 
-static const struct dev_pm_ops adt7410_dev_pm_ops = {
-	.suspend	= adt7410_suspend,
-	.resume		= adt7410_resume,
-};
+static SIMPLE_DEV_PM_OPS(adt7410_dev_pm_ops, adt7410_suspend, adt7410_resume);
+
 #define ADT7410_DEV_PM_OPS (&adt7410_dev_pm_ops)
 #else
 #define ADT7410_DEV_PM_OPS NULL
-- 
1.8.0


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

* [lm-sensors] [PATCH 3/9] hwmon: (adt7410) Use the SIMPLE_DEV_PM_OPS helper macro
@ 2013-02-15 16:57   ` Lars-Peter Clausen
  0 siblings, 0 replies; 56+ messages in thread
From: Lars-Peter Clausen @ 2013-02-15 16:57 UTC (permalink / raw)
  To: Jean Delvare, Guenter Roeck
  Cc: Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio,
	Lars-Peter Clausen

Use the SIMPLE_DEV_PM_OPS macro to declare the driver's pm_ops.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/hwmon/adt7410.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
index ae80815..4ae16e0 100644
--- a/drivers/hwmon/adt7410.c
+++ b/drivers/hwmon/adt7410.c
@@ -437,10 +437,8 @@ static int adt7410_resume(struct device *dev)
 	return ret;
 }
 
-static const struct dev_pm_ops adt7410_dev_pm_ops = {
-	.suspend	= adt7410_suspend,
-	.resume		= adt7410_resume,
-};
+static SIMPLE_DEV_PM_OPS(adt7410_dev_pm_ops, adt7410_suspend, adt7410_resume);
+
 #define ADT7410_DEV_PM_OPS (&adt7410_dev_pm_ops)
 #else
 #define ADT7410_DEV_PM_OPS NULL
-- 
1.8.0


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

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

* [PATCH 4/9] hwmon: (adt7410) Use I2C_ADDRS helper macro
  2013-02-15 16:57 ` [lm-sensors] " Lars-Peter Clausen
@ 2013-02-15 16:57   ` Lars-Peter Clausen
  -1 siblings, 0 replies; 56+ messages in thread
From: Lars-Peter Clausen @ 2013-02-15 16:57 UTC (permalink / raw)
  To: Jean Delvare, Guenter Roeck
  Cc: Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio,
	Lars-Peter Clausen

Use the I2C_ADDRS macro to initialize the I2C device's address_list. Doing so
saves a few lines of boilerplate code.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/hwmon/adt7410.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
index 4ae16e0..99f6d32 100644
--- a/drivers/hwmon/adt7410.c
+++ b/drivers/hwmon/adt7410.c
@@ -78,10 +78,6 @@ enum adt7410_type {		/* keep sorted in alphabetical order */
 	adt7410,
 };
 
-/* Addresses scanned */
-static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
-					I2C_CLIENT_END };
-
 static const u8 ADT7410_REG_TEMP[4] = {
 	ADT7410_TEMPERATURE,		/* input */
 	ADT7410_T_ALARM_HIGH,		/* high */
@@ -453,7 +449,7 @@ static struct i2c_driver adt7410_driver = {
 	.probe		= adt7410_probe,
 	.remove		= adt7410_remove,
 	.id_table	= adt7410_ids,
-	.address_list	= normal_i2c,
+	.address_list	= I2C_ADDRS(0x48, 0x49, 0x4a, 0x4b),
 };
 
 module_i2c_driver(adt7410_driver);
-- 
1.8.0


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

* [lm-sensors] [PATCH 4/9] hwmon: (adt7410) Use I2C_ADDRS helper macro
@ 2013-02-15 16:57   ` Lars-Peter Clausen
  0 siblings, 0 replies; 56+ messages in thread
From: Lars-Peter Clausen @ 2013-02-15 16:57 UTC (permalink / raw)
  To: Jean Delvare, Guenter Roeck
  Cc: Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio,
	Lars-Peter Clausen

Use the I2C_ADDRS macro to initialize the I2C device's address_list. Doing so
saves a few lines of boilerplate code.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/hwmon/adt7410.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
index 4ae16e0..99f6d32 100644
--- a/drivers/hwmon/adt7410.c
+++ b/drivers/hwmon/adt7410.c
@@ -78,10 +78,6 @@ enum adt7410_type {		/* keep sorted in alphabetical order */
 	adt7410,
 };
 
-/* Addresses scanned */
-static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
-					I2C_CLIENT_END };
-
 static const u8 ADT7410_REG_TEMP[4] = {
 	ADT7410_TEMPERATURE,		/* input */
 	ADT7410_T_ALARM_HIGH,		/* high */
@@ -453,7 +449,7 @@ static struct i2c_driver adt7410_driver = {
 	.probe		= adt7410_probe,
 	.remove		= adt7410_remove,
 	.id_table	= adt7410_ids,
-	.address_list	= normal_i2c,
+	.address_list	= I2C_ADDRS(0x48, 0x49, 0x4a, 0x4b),
 };
 
 module_i2c_driver(adt7410_driver);
-- 
1.8.0


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

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

* [PATCH 5/9] hwmon: (adt7410) Add device table entry for the adt7420
  2013-02-15 16:57 ` [lm-sensors] " Lars-Peter Clausen
@ 2013-02-15 16:57   ` Lars-Peter Clausen
  -1 siblings, 0 replies; 56+ messages in thread
From: Lars-Peter Clausen @ 2013-02-15 16:57 UTC (permalink / raw)
  To: Jean Delvare, Guenter Roeck
  Cc: Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio,
	Lars-Peter Clausen

The adt7420 is software compatible to the adt7410.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/hwmon/Kconfig   | 4 ++--
 drivers/hwmon/adt7410.c | 3 ++-
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 52d5174..89ac1cb 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -180,11 +180,11 @@ config SENSORS_ADM9240
 	  will be called adm9240.
 
 config SENSORS_ADT7410
-	tristate "Analog Devices ADT7410"
+	tristate "Analog Devices ADT7410/ADT7420"
 	depends on I2C
 	help
 	  If you say yes here you get support for the Analog Devices
-	  ADT7410 temperature monitoring chip.
+	  ADT7410 and ADT7420 temperature monitoring chips.
 
 	  This driver can also be built as a module. If so, the module
 	  will be called adt7410.
diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
index 99f6d32..99a7290 100644
--- a/drivers/hwmon/adt7410.c
+++ b/drivers/hwmon/adt7410.c
@@ -407,6 +407,7 @@ static int adt7410_remove(struct i2c_client *client)
 
 static const struct i2c_device_id adt7410_ids[] = {
 	{ "adt7410", adt7410, },
+	{ "adt7420", adt7410, },
 	{ /* LIST END */ }
 };
 MODULE_DEVICE_TABLE(i2c, adt7410_ids);
@@ -455,5 +456,5 @@ static struct i2c_driver adt7410_driver = {
 module_i2c_driver(adt7410_driver);
 
 MODULE_AUTHOR("Hartmut Knaack");
-MODULE_DESCRIPTION("ADT7410 driver");
+MODULE_DESCRIPTION("ADT7410/ADT7420 driver");
 MODULE_LICENSE("GPL");
-- 
1.8.0


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

* [lm-sensors] [PATCH 5/9] hwmon: (adt7410) Add device table entry for the adt7420
@ 2013-02-15 16:57   ` Lars-Peter Clausen
  0 siblings, 0 replies; 56+ messages in thread
From: Lars-Peter Clausen @ 2013-02-15 16:57 UTC (permalink / raw)
  To: Jean Delvare, Guenter Roeck
  Cc: Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio,
	Lars-Peter Clausen

The adt7420 is software compatible to the adt7410.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/hwmon/Kconfig   | 4 ++--
 drivers/hwmon/adt7410.c | 3 ++-
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 52d5174..89ac1cb 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -180,11 +180,11 @@ config SENSORS_ADM9240
 	  will be called adm9240.
 
 config SENSORS_ADT7410
-	tristate "Analog Devices ADT7410"
+	tristate "Analog Devices ADT7410/ADT7420"
 	depends on I2C
 	help
 	  If you say yes here you get support for the Analog Devices
-	  ADT7410 temperature monitoring chip.
+	  ADT7410 and ADT7420 temperature monitoring chips.
 
 	  This driver can also be built as a module. If so, the module
 	  will be called adt7410.
diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
index 99f6d32..99a7290 100644
--- a/drivers/hwmon/adt7410.c
+++ b/drivers/hwmon/adt7410.c
@@ -407,6 +407,7 @@ static int adt7410_remove(struct i2c_client *client)
 
 static const struct i2c_device_id adt7410_ids[] = {
 	{ "adt7410", adt7410, },
+	{ "adt7420", adt7410, },
 	{ /* LIST END */ }
 };
 MODULE_DEVICE_TABLE(i2c, adt7410_ids);
@@ -455,5 +456,5 @@ static struct i2c_driver adt7410_driver = {
 module_i2c_driver(adt7410_driver);
 
 MODULE_AUTHOR("Hartmut Knaack");
-MODULE_DESCRIPTION("ADT7410 driver");
+MODULE_DESCRIPTION("ADT7410/ADT7420 driver");
 MODULE_LICENSE("GPL");
-- 
1.8.0


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

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

* [PATCH 6/9] hwmon: (adt7410) Don't re-read non-volatile registers
  2013-02-15 16:57 ` [lm-sensors] " Lars-Peter Clausen
@ 2013-02-15 16:57   ` Lars-Peter Clausen
  -1 siblings, 0 replies; 56+ messages in thread
From: Lars-Peter Clausen @ 2013-02-15 16:57 UTC (permalink / raw)
  To: Jean Delvare, Guenter Roeck
  Cc: Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio,
	Lars-Peter Clausen

Currently each time the temperature register is read the driver also reads the
threshold and hysteresis registers. This increases the amount of I2C traffic and
time needed to read the temperature by a factor of ~5. Neither the threshold nor
the hysteresis change on their own, so once we've read them, we should be able
to just use the cached value of the registers. This patch modifies the code
accordingly and only reads the threshold and hysteresis registers once during
probe.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/hwmon/adt7410.c | 89 +++++++++++++++++++++++++++++++------------------
 1 file changed, 56 insertions(+), 33 deletions(-)

diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
index 99a7290..5de0376 100644
--- a/drivers/hwmon/adt7410.c
+++ b/drivers/hwmon/adt7410.c
@@ -119,45 +119,31 @@ static int adt7410_temp_ready(struct i2c_client *client)
 	return -ETIMEDOUT;
 }
 
-static struct adt7410_data *adt7410_update_device(struct device *dev)
+static int adt7410_update_temp(struct device *dev)
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct adt7410_data *data = i2c_get_clientdata(client);
-	struct adt7410_data *ret = data;
+	int ret = 0;
+
 	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
 	    || !data->valid) {
-		int i, status;
 
 		dev_dbg(&client->dev, "Starting update\n");
 
-		status = adt7410_temp_ready(client); /* check for new value */
-		if (unlikely(status)) {
-			ret = ERR_PTR(status);
+		ret = adt7410_temp_ready(client); /* check for new value */
+		if (ret)
 			goto abort;
-		}
-		for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
-			status = i2c_smbus_read_word_swapped(client,
-							ADT7410_REG_TEMP[i]);
-			if (unlikely(status < 0)) {
-				dev_dbg(dev,
-					"Failed to read value: reg %d, error %d\n",
-					ADT7410_REG_TEMP[i], status);
-				ret = ERR_PTR(status);
-				goto abort;
-			}
-			data->temp[i] = status;
-		}
-		status = i2c_smbus_read_byte_data(client, ADT7410_T_HYST);
-		if (unlikely(status < 0)) {
-			dev_dbg(dev,
-				"Failed to read value: reg %d, error %d\n",
-				ADT7410_T_HYST, status);
-			ret = ERR_PTR(status);
+
+		ret = i2c_smbus_read_word_swapped(client, ADT7410_REG_TEMP[0]);
+		if (ret) {
+			dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
+				ADT7410_REG_TEMP[0], ret);
 			goto abort;
 		}
-		data->hyst = status;
+		data->temp[0] = ret;
+
 		data->last_updated = jiffies;
 		data->valid = true;
 	}
@@ -167,6 +153,35 @@ abort:
 	return ret;
 }
 
+static int adt7410_fill_cache(struct i2c_client *client)
+{
+	struct adt7410_data *data = i2c_get_clientdata(client);
+	int ret;
+	int i;
+
+	for (i = 1; i < 3; i++) {
+		ret = i2c_smbus_read_word_swapped(client, ADT7410_REG_TEMP[i]);
+		if (ret) {
+			dev_dbg(&client->dev,
+				"Failed to read value: reg %d, error %d\n",
+				ADT7410_REG_TEMP[0], ret);
+			return ret;
+		}
+		data->temp[i] = ret;
+	}
+
+	ret = i2c_smbus_read_byte_data(client, ADT7410_T_HYST);
+	if (ret) {
+		dev_dbg(&client->dev,
+			"Failed to read value: hyst reg, error %d\n",
+			ret);
+		return ret;
+	}
+	data->hyst = ret;
+
+	return 0;
+}
+
 static s16 ADT7410_TEMP_TO_REG(long temp)
 {
 	return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7410_TEMP_MIN,
@@ -193,10 +208,16 @@ static ssize_t adt7410_show_temp(struct device *dev,
 				 struct device_attribute *da, char *buf)
 {
 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
-	struct adt7410_data *data = adt7410_update_device(dev);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct adt7410_data *data = i2c_get_clientdata(client);
 
-	if (IS_ERR(data))
-		return PTR_ERR(data);
+	if (attr->index == 0) {
+		int ret;
+
+		ret = adt7410_update_temp(dev);
+		if (ret)
+			return ret;
+	}
 
 	return sprintf(buf, "%d\n", ADT7410_REG_TO_TEMP(data,
 		       data->temp[attr->index]));
@@ -232,13 +253,11 @@ static ssize_t adt7410_show_t_hyst(struct device *dev,
 				   char *buf)
 {
 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
-	struct adt7410_data *data;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct adt7410_data *data = i2c_get_clientdata(client);
 	int nr = attr->index;
 	int hyst;
 
-	data = adt7410_update_device(dev);
-	if (IS_ERR(data))
-		return PTR_ERR(data);
 	hyst = (data->hyst & ADT7410_T_HYST_MASK) * 1000;
 
 	/*
@@ -371,6 +390,10 @@ static int adt7410_probe(struct i2c_client *client,
 	}
 	dev_dbg(&client->dev, "Config %02x\n", data->config);
 
+	ret = adt7410_fill_cache(client);
+	if (ret)
+		goto exit_restore;
+
 	/* Register sysfs hooks */
 	ret = sysfs_create_group(&client->dev.kobj, &adt7410_group);
 	if (ret)
-- 
1.8.0


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

* [lm-sensors] [PATCH 6/9] hwmon: (adt7410) Don't re-read non-volatile registers
@ 2013-02-15 16:57   ` Lars-Peter Clausen
  0 siblings, 0 replies; 56+ messages in thread
From: Lars-Peter Clausen @ 2013-02-15 16:57 UTC (permalink / raw)
  To: Jean Delvare, Guenter Roeck
  Cc: Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio,
	Lars-Peter Clausen

Currently each time the temperature register is read the driver also reads the
threshold and hysteresis registers. This increases the amount of I2C traffic and
time needed to read the temperature by a factor of ~5. Neither the threshold nor
the hysteresis change on their own, so once we've read them, we should be able
to just use the cached value of the registers. This patch modifies the code
accordingly and only reads the threshold and hysteresis registers once during
probe.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/hwmon/adt7410.c | 89 +++++++++++++++++++++++++++++++------------------
 1 file changed, 56 insertions(+), 33 deletions(-)

diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
index 99a7290..5de0376 100644
--- a/drivers/hwmon/adt7410.c
+++ b/drivers/hwmon/adt7410.c
@@ -119,45 +119,31 @@ static int adt7410_temp_ready(struct i2c_client *client)
 	return -ETIMEDOUT;
 }
 
-static struct adt7410_data *adt7410_update_device(struct device *dev)
+static int adt7410_update_temp(struct device *dev)
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct adt7410_data *data = i2c_get_clientdata(client);
-	struct adt7410_data *ret = data;
+	int ret = 0;
+
 	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
 	    || !data->valid) {
-		int i, status;
 
 		dev_dbg(&client->dev, "Starting update\n");
 
-		status = adt7410_temp_ready(client); /* check for new value */
-		if (unlikely(status)) {
-			ret = ERR_PTR(status);
+		ret = adt7410_temp_ready(client); /* check for new value */
+		if (ret)
 			goto abort;
-		}
-		for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
-			status = i2c_smbus_read_word_swapped(client,
-							ADT7410_REG_TEMP[i]);
-			if (unlikely(status < 0)) {
-				dev_dbg(dev,
-					"Failed to read value: reg %d, error %d\n",
-					ADT7410_REG_TEMP[i], status);
-				ret = ERR_PTR(status);
-				goto abort;
-			}
-			data->temp[i] = status;
-		}
-		status = i2c_smbus_read_byte_data(client, ADT7410_T_HYST);
-		if (unlikely(status < 0)) {
-			dev_dbg(dev,
-				"Failed to read value: reg %d, error %d\n",
-				ADT7410_T_HYST, status);
-			ret = ERR_PTR(status);
+
+		ret = i2c_smbus_read_word_swapped(client, ADT7410_REG_TEMP[0]);
+		if (ret) {
+			dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
+				ADT7410_REG_TEMP[0], ret);
 			goto abort;
 		}
-		data->hyst = status;
+		data->temp[0] = ret;
+
 		data->last_updated = jiffies;
 		data->valid = true;
 	}
@@ -167,6 +153,35 @@ abort:
 	return ret;
 }
 
+static int adt7410_fill_cache(struct i2c_client *client)
+{
+	struct adt7410_data *data = i2c_get_clientdata(client);
+	int ret;
+	int i;
+
+	for (i = 1; i < 3; i++) {
+		ret = i2c_smbus_read_word_swapped(client, ADT7410_REG_TEMP[i]);
+		if (ret) {
+			dev_dbg(&client->dev,
+				"Failed to read value: reg %d, error %d\n",
+				ADT7410_REG_TEMP[0], ret);
+			return ret;
+		}
+		data->temp[i] = ret;
+	}
+
+	ret = i2c_smbus_read_byte_data(client, ADT7410_T_HYST);
+	if (ret) {
+		dev_dbg(&client->dev,
+			"Failed to read value: hyst reg, error %d\n",
+			ret);
+		return ret;
+	}
+	data->hyst = ret;
+
+	return 0;
+}
+
 static s16 ADT7410_TEMP_TO_REG(long temp)
 {
 	return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7410_TEMP_MIN,
@@ -193,10 +208,16 @@ static ssize_t adt7410_show_temp(struct device *dev,
 				 struct device_attribute *da, char *buf)
 {
 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
-	struct adt7410_data *data = adt7410_update_device(dev);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct adt7410_data *data = i2c_get_clientdata(client);
 
-	if (IS_ERR(data))
-		return PTR_ERR(data);
+	if (attr->index = 0) {
+		int ret;
+
+		ret = adt7410_update_temp(dev);
+		if (ret)
+			return ret;
+	}
 
 	return sprintf(buf, "%d\n", ADT7410_REG_TO_TEMP(data,
 		       data->temp[attr->index]));
@@ -232,13 +253,11 @@ static ssize_t adt7410_show_t_hyst(struct device *dev,
 				   char *buf)
 {
 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
-	struct adt7410_data *data;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct adt7410_data *data = i2c_get_clientdata(client);
 	int nr = attr->index;
 	int hyst;
 
-	data = adt7410_update_device(dev);
-	if (IS_ERR(data))
-		return PTR_ERR(data);
 	hyst = (data->hyst & ADT7410_T_HYST_MASK) * 1000;
 
 	/*
@@ -371,6 +390,10 @@ static int adt7410_probe(struct i2c_client *client,
 	}
 	dev_dbg(&client->dev, "Config %02x\n", data->config);
 
+	ret = adt7410_fill_cache(client);
+	if (ret)
+		goto exit_restore;
+
 	/* Register sysfs hooks */
 	ret = sysfs_create_group(&client->dev.kobj, &adt7410_group);
 	if (ret)
-- 
1.8.0


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

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

* [PATCH 7/9] hwmon: (adt7410) Add support for the adt7310/adt7320
  2013-02-15 16:57 ` [lm-sensors] " Lars-Peter Clausen
@ 2013-02-15 16:57   ` Lars-Peter Clausen
  -1 siblings, 0 replies; 56+ messages in thread
From: Lars-Peter Clausen @ 2013-02-15 16:57 UTC (permalink / raw)
  To: Jean Delvare, Guenter Roeck
  Cc: Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio,
	Lars-Peter Clausen

The adt7310/adt7320 is the SPI version of the adt7410/adt7320. The register map
layout is a bit different, i.e. the register addresses differ between the two
variants, but the bit layouts of the individual registers are identical. So both
chip variants can easily be supported by the same driver. The issue of non
matching register address layouts is solved by a simple look-up table which
translates the I2C addresses to the SPI addresses.

The patch moves the bulk of the adt7410 driver to a common module that will be
shared by the adt7410 and adt7310 drivers. This common module implements the
driver logic and uses a set of virtual functions to perform IO access. The
adt7410 and adt7310 driver modules provide proper implementations of these IO
accessor functions for I2C respective SPI.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/hwmon/Kconfig   |  20 ++
 drivers/hwmon/Makefile  |   2 +
 drivers/hwmon/adt7310.c | 160 ++++++++++++++++
 drivers/hwmon/adt7410.c | 472 ++++++-----------------------------------------
 drivers/hwmon/adt7x10.c | 476 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/hwmon/adt7x10.h |  47 +++++
 6 files changed, 758 insertions(+), 419 deletions(-)
 create mode 100644 drivers/hwmon/adt7310.c
 create mode 100644 drivers/hwmon/adt7x10.c
 create mode 100644 drivers/hwmon/adt7x10.h

diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 89ac1cb..aaa14f4 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -179,9 +179,29 @@ config SENSORS_ADM9240
 	  This driver can also be built as a module.  If so, the module
 	  will be called adm9240.
 
+config SENSORS_ADT7X10
+	tristate
+	help
+	  This module contains common code shared by the ADT7310/ADT7320 and
+	  ADT7410/ADT7420 temperature monitoring chip drivers.
+
+	  If build as a module, the module will be called adt7x10.
+
+config SENSORS_ADT7310
+	tristate "Analog Devices ADT7310/ADT7320"
+	depends on SPI_MASTER
+	select SENSORS_ADT7X10
+	help
+	  If you say yes here you get support for the Analog Devices
+	  ADT7310 and ADT7320 temperature monitoring chips.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called adt7310.
+
 config SENSORS_ADT7410
 	tristate "Analog Devices ADT7410/ADT7420"
 	depends on I2C
+	select SENSORS_ADT7X10
 	help
 	  If you say yes here you get support for the Analog Devices
 	  ADT7410 and ADT7420 temperature monitoring chips.
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 8d6d97e..5d36a57 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -34,6 +34,8 @@ obj-$(CONFIG_SENSORS_ADM9240)	+= adm9240.o
 obj-$(CONFIG_SENSORS_ADS1015)	+= ads1015.o
 obj-$(CONFIG_SENSORS_ADS7828)	+= ads7828.o
 obj-$(CONFIG_SENSORS_ADS7871)	+= ads7871.o
+obj-$(CONFIG_SENSORS_ADT7X10)	+= adt7x10.o
+obj-$(CONFIG_SENSORS_ADT7310)	+= adt7310.o
 obj-$(CONFIG_SENSORS_ADT7410)	+= adt7410.o
 obj-$(CONFIG_SENSORS_ADT7411)	+= adt7411.o
 obj-$(CONFIG_SENSORS_ADT7462)	+= adt7462.o
diff --git a/drivers/hwmon/adt7310.c b/drivers/hwmon/adt7310.c
new file mode 100644
index 0000000..0483e6c
--- /dev/null
+++ b/drivers/hwmon/adt7310.c
@@ -0,0 +1,160 @@
+/*
+ * ADT7310/ADT7310 digital temperature sensor driver
+ *
+ * Copyright 2010-2013 Analog Devices Inc.
+ *   Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/spi/spi.h>
+
+#include "adt7x10.h"
+
+static const u8 adt7371_reg_table[] = {
+	[ADT7410_TEMPERATURE]   = ADT7310_TEMPERATURE,
+	[ADT7410_STATUS]	= ADT7310_STATUS,
+	[ADT7410_CONFIG]	= ADT7310_CONFIG,
+	[ADT7410_T_ALARM_HIGH]	= ADT7310_T_ALARM_HIGH,
+	[ADT7410_T_ALARM_LOW]	= ADT7310_T_ALARM_LOW,
+	[ADT7410_T_CRIT]	= ADT7310_T_CRIT,
+	[ADT7410_T_HYST]	= ADT7310_T_HYST,
+	[ADT7410_ID]		= ADT7310_ID,
+};
+
+#define ADT7310_CMD_REG_MASK			0x28
+#define ADT7310_CMD_REG_OFFSET			3
+#define ADT7310_CMD_READ			0x40
+#define ADT7310_CMD_CON_READ			0x4
+
+#define AD7310_COMMAND(reg) (adt7371_reg_table[(reg)] << ADT7310_CMD_REG_OFFSET)
+
+static int adt7310_spi_read_word(struct device *dev,
+	u8 reg, u16 *data)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	u8 command = AD7310_COMMAND(reg);
+	int ret = 0;
+
+	command |= ADT7310_CMD_READ;
+	ret = spi_write(spi, &command, sizeof(command));
+	if (ret < 0) {
+		dev_err(dev, "SPI write command error\n");
+		return ret;
+	}
+
+	ret = spi_read(spi, (u8 *)data, sizeof(*data));
+	if (ret < 0) {
+		dev_err(dev, "SPI read word error\n");
+		return ret;
+	}
+
+	*data = be16_to_cpu(*data);
+
+	return 0;
+}
+
+static int adt7310_spi_write_word(struct device *dev, u8 reg,
+	u16 data)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	u8 buf[3];
+	int ret = 0;
+
+	buf[0] = AD7310_COMMAND(reg);
+	buf[1] = (u8)(data >> 8);
+	buf[2] = (u8)(data & 0xFF);
+
+	ret = spi_write(spi, buf, 3);
+	if (ret < 0) {
+		dev_err(dev, "SPI write word error\n");
+		return ret;
+	}
+
+	return ret;
+}
+
+static int adt7310_spi_read_byte(struct device *dev, u8 reg,
+	u8 *data)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	u8 command = AD7310_COMMAND(reg);
+	int ret = 0;
+
+	command |= ADT7310_CMD_READ;
+	ret = spi_write(spi, &command, sizeof(command));
+	if (ret < 0) {
+		dev_err(dev, "SPI write command error\n");
+		return ret;
+	}
+
+	ret = spi_read(spi, data, sizeof(*data));
+	if (ret < 0) {
+		dev_err(dev, "SPI read byte error\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int adt7310_spi_write_byte(struct device *dev, u8 reg,
+	u8 data)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	u8 buf[2];
+	int ret = 0;
+
+	buf[0] = AD7310_COMMAND(reg);
+	buf[1] = data;
+
+	ret = spi_write(spi, buf, 2);
+	if (ret < 0) {
+		dev_err(dev, "SPI write byte error\n");
+		return ret;
+	}
+
+	return ret;
+}
+
+static const struct adt7410_ops adt7310_spi_ops = {
+	.read_word = adt7310_spi_read_word,
+	.write_word = adt7310_spi_write_word,
+	.read_byte = adt7310_spi_read_byte,
+	.write_byte = adt7310_spi_write_byte,
+};
+
+static int adt7310_spi_probe(struct spi_device *spi)
+{
+	return adt7410_probe(&spi->dev, spi_get_device_id(spi)->name,
+			&adt7310_spi_ops);
+}
+
+static int adt7310_spi_remove(struct spi_device *spi)
+{
+	return adt7410_remove(&spi->dev);
+}
+
+static const struct spi_device_id adt7310_id[] = {
+	{ "adt7310", 0 },
+	{ "adt7320", 0 },
+	{}
+};
+MODULE_DEVICE_TABLE(spi, adt7310_id);
+
+static struct spi_driver adt7310_driver = {
+	.driver = {
+		.name = "adt7310",
+		.owner = THIS_MODULE,
+		.pm	= ADT7410_DEV_PM_OPS,
+	},
+	.probe = adt7310_spi_probe,
+	.remove = adt7310_spi_remove,
+	.id_table = adt7310_id,
+};
+module_spi_driver(adt7310_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("ADT7310/ADT7420 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
index 5de0376..13734c5 100644
--- a/drivers/hwmon/adt7410.c
+++ b/drivers/hwmon/adt7410.c
@@ -1,483 +1,117 @@
 /*
- * adt7410.c - Part of lm_sensors, Linux kernel modules for hardware
- *	 monitoring
- * This driver handles the ADT7410 and compatible digital temperature sensors.
- * Hartmut Knaack <knaack.h@gmx.de> 2012-07-22
- * based on lm75.c by Frodo Looijaard <frodol@dds.nl>
- * and adt7410.c from iio-staging by Sonic Zhang <sonic.zhang@analog.com>
+ * ADT7410/ADT7420 digital temperature sensor driver
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * Copyright 2010-2013 Analog Devices Inc.
+ *   Author: Lars-Peter Clausen <lars@metafoo.de>
  *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the GPL-2 or later.
  */
 
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/jiffies.h>
 #include <linux/i2c.h>
-#include <linux/hwmon.h>
-#include <linux/hwmon-sysfs.h>
-#include <linux/err.h>
-#include <linux/mutex.h>
-#include <linux/delay.h>
-
-/*
- * ADT7410 registers definition
- */
 
-#define ADT7410_TEMPERATURE		0
-#define ADT7410_STATUS			2
-#define ADT7410_CONFIG			3
-#define ADT7410_T_ALARM_HIGH		4
-#define ADT7410_T_ALARM_LOW		6
-#define ADT7410_T_CRIT			8
-#define ADT7410_T_HYST			0xA
+#include "adt7x10.h"
 
-/*
- * ADT7410 status
- */
-#define ADT7410_STAT_T_LOW		(1 << 4)
-#define ADT7410_STAT_T_HIGH		(1 << 5)
-#define ADT7410_STAT_T_CRIT		(1 << 6)
-#define ADT7410_STAT_NOT_RDY		(1 << 7)
-
-/*
- * ADT7410 config
- */
-#define ADT7410_FAULT_QUEUE_MASK	(1 << 0 | 1 << 1)
-#define ADT7410_CT_POLARITY		(1 << 2)
-#define ADT7410_INT_POLARITY		(1 << 3)
-#define ADT7410_EVENT_MODE		(1 << 4)
-#define ADT7410_MODE_MASK		(1 << 5 | 1 << 6)
-#define ADT7410_FULL			(0 << 5 | 0 << 6)
-#define ADT7410_PD			(1 << 5 | 1 << 6)
-#define ADT7410_RESOLUTION		(1 << 7)
-
-/*
- * ADT7410 masks
- */
-#define ADT7410_T13_VALUE_MASK			0xFFF8
-#define ADT7410_T_HYST_MASK			0xF
-
-/* straight from the datasheet */
-#define ADT7410_TEMP_MIN (-55000)
-#define ADT7410_TEMP_MAX 150000
-
-enum adt7410_type {		/* keep sorted in alphabetical order */
-	adt7410,
-};
-
-static const u8 ADT7410_REG_TEMP[4] = {
-	ADT7410_TEMPERATURE,		/* input */
-	ADT7410_T_ALARM_HIGH,		/* high */
-	ADT7410_T_ALARM_LOW,		/* low */
-	ADT7410_T_CRIT,			/* critical */
-};
-
-/* Each client has this additional data */
-struct adt7410_data {
-	struct device		*hwmon_dev;
-	struct mutex		update_lock;
-	u8			config;
-	u8			oldconfig;
-	bool			valid;		/* true if registers valid */
-	unsigned long		last_updated;	/* In jiffies */
-	s16			temp[4];	/* Register values,
-						   0 = input
-						   1 = high
-						   2 = low
-						   3 = critical */
-	u8			hyst;		/* hysteresis offset */
-};
-
-/*
- * adt7410 register access by I2C
- */
-static int adt7410_temp_ready(struct i2c_client *client)
-{
-	int i, status;
-
-	for (i = 0; i < 6; i++) {
-		status = i2c_smbus_read_byte_data(client, ADT7410_STATUS);
-		if (status < 0)
-			return status;
-		if (!(status & ADT7410_STAT_NOT_RDY))
-			return 0;
-		msleep(60);
-	}
-	return -ETIMEDOUT;
-}
-
-static int adt7410_update_temp(struct device *dev)
+static int adt7410_i2c_read_word(struct device *dev, u8 reg, u16 *data)
 {
 	struct i2c_client *client = to_i2c_client(dev);
-	struct adt7410_data *data = i2c_get_clientdata(client);
 	int ret = 0;
 
-	mutex_lock(&data->update_lock);
-
-	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
-	    || !data->valid) {
-
-		dev_dbg(&client->dev, "Starting update\n");
-
-		ret = adt7410_temp_ready(client); /* check for new value */
-		if (ret)
-			goto abort;
-
-		ret = i2c_smbus_read_word_swapped(client, ADT7410_REG_TEMP[0]);
-		if (ret) {
-			dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
-				ADT7410_REG_TEMP[0], ret);
-			goto abort;
-		}
-		data->temp[0] = ret;
-
-		data->last_updated = jiffies;
-		data->valid = true;
-	}
-
-abort:
-	mutex_unlock(&data->update_lock);
-	return ret;
-}
-
-static int adt7410_fill_cache(struct i2c_client *client)
-{
-	struct adt7410_data *data = i2c_get_clientdata(client);
-	int ret;
-	int i;
-
-	for (i = 1; i < 3; i++) {
-		ret = i2c_smbus_read_word_swapped(client, ADT7410_REG_TEMP[i]);
-		if (ret) {
-			dev_dbg(&client->dev,
-				"Failed to read value: reg %d, error %d\n",
-				ADT7410_REG_TEMP[0], ret);
-			return ret;
-		}
-		data->temp[i] = ret;
-	}
-
-	ret = i2c_smbus_read_byte_data(client, ADT7410_T_HYST);
-	if (ret) {
-		dev_dbg(&client->dev,
-			"Failed to read value: hyst reg, error %d\n",
-			ret);
+	ret = i2c_smbus_read_word_swapped(client, reg);
+	if (ret < 0) {
+		dev_err(dev, "I2C read error\n");
 		return ret;
 	}
-	data->hyst = ret;
-
-	return 0;
-}
 
-static s16 ADT7410_TEMP_TO_REG(long temp)
-{
-	return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7410_TEMP_MIN,
-					   ADT7410_TEMP_MAX) * 128, 1000);
-}
+	*data = ret;
 
-static int ADT7410_REG_TO_TEMP(struct adt7410_data *data, s16 reg)
-{
-	/* in 13 bit mode, bits 0-2 are status flags - mask them out */
-	if (!(data->config & ADT7410_RESOLUTION))
-		reg &= ADT7410_T13_VALUE_MASK;
-	/*
-	 * temperature is stored in twos complement format, in steps of
-	 * 1/128°C
-	 */
-	return DIV_ROUND_CLOSEST(reg * 1000, 128);
+	return 0;
 }
 
-/*-----------------------------------------------------------------------*/
-
-/* sysfs attributes for hwmon */
-
-static ssize_t adt7410_show_temp(struct device *dev,
-				 struct device_attribute *da, char *buf)
+static int adt7410_i2c_write_word(struct device *dev, u8 reg, u16 data)
 {
-	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
 	struct i2c_client *client = to_i2c_client(dev);
-	struct adt7410_data *data = i2c_get_clientdata(client);
-
-	if (attr->index == 0) {
-		int ret;
+	int ret = 0;
 
-		ret = adt7410_update_temp(dev);
-		if (ret)
-			return ret;
-	}
+	ret = i2c_smbus_write_word_swapped(client, reg, data);
+	if (ret < 0)
+		dev_err(dev, "I2C write error\n");
 
-	return sprintf(buf, "%d\n", ADT7410_REG_TO_TEMP(data,
-		       data->temp[attr->index]));
+	return ret;
 }
 
-static ssize_t adt7410_set_temp(struct device *dev,
-				struct device_attribute *da,
-				const char *buf, size_t count)
+static int adt7410_i2c_read_byte(struct device *dev, u8 reg, u8 *data)
 {
-	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
 	struct i2c_client *client = to_i2c_client(dev);
-	struct adt7410_data *data = i2c_get_clientdata(client);
-	int nr = attr->index;
-	long temp;
-	int ret;
+	int ret = 0;
 
-	ret = kstrtol(buf, 10, &temp);
-	if (ret)
+	ret = i2c_smbus_read_byte_data(client, reg);
+	if (ret < 0) {
+		dev_err(dev, "I2C read error\n");
 		return ret;
+	}
 
-	mutex_lock(&data->update_lock);
-	data->temp[nr] = ADT7410_TEMP_TO_REG(temp);
-	ret = i2c_smbus_write_word_swapped(client, ADT7410_REG_TEMP[nr],
-					   data->temp[nr]);
-	if (ret)
-		count = ret;
-	mutex_unlock(&data->update_lock);
-	return count;
-}
-
-static ssize_t adt7410_show_t_hyst(struct device *dev,
-				   struct device_attribute *da,
-				   char *buf)
-{
-	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
-	struct i2c_client *client = to_i2c_client(dev);
-	struct adt7410_data *data = i2c_get_clientdata(client);
-	int nr = attr->index;
-	int hyst;
-
-	hyst = (data->hyst & ADT7410_T_HYST_MASK) * 1000;
-
-	/*
-	 * hysteresis is stored as a 4 bit offset in the device, convert it
-	 * to an absolute value
-	 */
-	if (nr == 2)	/* min has positive offset, others have negative */
-		hyst = -hyst;
-	return sprintf(buf, "%d\n",
-		       ADT7410_REG_TO_TEMP(data, data->temp[nr]) - hyst);
-}
-
-static ssize_t adt7410_set_t_hyst(struct device *dev,
-				  struct device_attribute *da,
-				  const char *buf, size_t count)
-{
-	struct i2c_client *client = to_i2c_client(dev);
-	struct adt7410_data *data = i2c_get_clientdata(client);
-	int limit, ret;
-	long hyst;
-
-	ret = kstrtol(buf, 10, &hyst);
-	if (ret)
-		return ret;
-	/* convert absolute hysteresis value to a 4 bit delta value */
-	limit = ADT7410_REG_TO_TEMP(data, data->temp[1]);
-	hyst = clamp_val(hyst, ADT7410_TEMP_MIN, ADT7410_TEMP_MAX);
-	data->hyst = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000), 0,
-			       ADT7410_T_HYST_MASK);
-	ret = i2c_smbus_write_byte_data(client, ADT7410_T_HYST, data->hyst);
-	if (ret)
-		return ret;
+	*data = (u8)ret;
 
-	return count;
+	return 0;
 }
 
-static ssize_t adt7410_show_alarm(struct device *dev,
-				  struct device_attribute *da,
-				  char *buf)
+static int adt7410_i2c_write_byte(struct device *dev, u8 reg, u8 data)
 {
 	struct i2c_client *client = to_i2c_client(dev);
-	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
-	int ret;
+	int ret = 0;
 
-	ret = i2c_smbus_read_byte_data(client, ADT7410_STATUS);
+	ret = i2c_smbus_write_byte_data(client, reg, data);
 	if (ret < 0)
-		return ret;
+		dev_err(&client->dev, "I2C write error\n");
 
-	return sprintf(buf, "%d\n", !!(ret & attr->index));
+	return ret;
 }
 
-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adt7410_show_temp, NULL, 0);
-static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
-			  adt7410_show_temp, adt7410_set_temp, 1);
-static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
-			  adt7410_show_temp, adt7410_set_temp, 2);
-static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
-			  adt7410_show_temp, adt7410_set_temp, 3);
-static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
-			  adt7410_show_t_hyst, adt7410_set_t_hyst, 1);
-static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO,
-			  adt7410_show_t_hyst, NULL, 2);
-static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO,
-			  adt7410_show_t_hyst, NULL, 3);
-static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, adt7410_show_alarm,
-			  NULL, ADT7410_STAT_T_LOW);
-static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adt7410_show_alarm,
-			  NULL, ADT7410_STAT_T_HIGH);
-static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, adt7410_show_alarm,
-			  NULL, ADT7410_STAT_T_CRIT);
-
-static struct attribute *adt7410_attributes[] = {
-	&sensor_dev_attr_temp1_input.dev_attr.attr,
-	&sensor_dev_attr_temp1_max.dev_attr.attr,
-	&sensor_dev_attr_temp1_min.dev_attr.attr,
-	&sensor_dev_attr_temp1_crit.dev_attr.attr,
-	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
-	&sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
-	&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
-	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
-	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
-	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
-	NULL
-};
-
-static const struct attribute_group adt7410_group = {
-	.attrs = adt7410_attributes,
+static const struct adt7410_ops adt7410_i2c_ops = {
+	.read_word = adt7410_i2c_read_word,
+	.write_word = adt7410_i2c_write_word,
+	.read_byte = adt7410_i2c_read_byte,
+	.write_byte = adt7410_i2c_write_byte,
 };
 
-/*-----------------------------------------------------------------------*/
-
-/* device probe and removal */
-
-static int adt7410_probe(struct i2c_client *client,
-			 const struct i2c_device_id *id)
+static int adt7410_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
 {
-	struct adt7410_data *data;
-	int ret;
 
 	if (!i2c_check_functionality(client->adapter,
 			I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
 		return -ENODEV;
 
-	data = devm_kzalloc(&client->dev, sizeof(struct adt7410_data),
-			    GFP_KERNEL);
-	if (!data)
-		return -ENOMEM;
-
-	i2c_set_clientdata(client, data);
-	mutex_init(&data->update_lock);
-
-	/* configure as specified */
-	ret = i2c_smbus_read_byte_data(client, ADT7410_CONFIG);
-	if (ret < 0) {
-		dev_dbg(&client->dev, "Can't read config? %d\n", ret);
-		return ret;
-	}
-	data->oldconfig = ret;
-	/*
-	 * Set to 16 bit resolution, continous conversion and comparator mode.
-	 */
-	ret &= ~ADT7410_MODE_MASK;
-	data->config = ret | ADT7410_FULL | ADT7410_RESOLUTION |
-			ADT7410_EVENT_MODE;
-	if (data->config != data->oldconfig) {
-		ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
-						data->config);
-		if (ret)
-			return ret;
-	}
-	dev_dbg(&client->dev, "Config %02x\n", data->config);
-
-	ret = adt7410_fill_cache(client);
-	if (ret)
-		goto exit_restore;
-
-	/* Register sysfs hooks */
-	ret = sysfs_create_group(&client->dev.kobj, &adt7410_group);
-	if (ret)
-		goto exit_restore;
-
-	data->hwmon_dev = hwmon_device_register(&client->dev);
-	if (IS_ERR(data->hwmon_dev)) {
-		ret = PTR_ERR(data->hwmon_dev);
-		goto exit_remove;
-	}
-
-	dev_info(&client->dev, "sensor '%s'\n", client->name);
-
-	return 0;
-
-exit_remove:
-	sysfs_remove_group(&client->dev.kobj, &adt7410_group);
-exit_restore:
-	i2c_smbus_write_byte_data(client, ADT7410_CONFIG, data->oldconfig);
-	return ret;
+	return adt7410_probe(&client->dev, NULL, &adt7410_i2c_ops);
 }
 
-static int adt7410_remove(struct i2c_client *client)
+static int adt7410_i2c_remove(struct i2c_client *client)
 {
-	struct adt7410_data *data = i2c_get_clientdata(client);
-
-	hwmon_device_unregister(data->hwmon_dev);
-	sysfs_remove_group(&client->dev.kobj, &adt7410_group);
-	if (data->oldconfig != data->config)
-		i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
-					  data->oldconfig);
-	return 0;
+	return adt7410_remove(&client->dev);
 }
 
-static const struct i2c_device_id adt7410_ids[] = {
-	{ "adt7410", adt7410, },
-	{ "adt7420", adt7410, },
-	{ /* LIST END */ }
+static const struct i2c_device_id adt7410_id[] = {
+	{ "adt7410", 0 },
+	{ "adt7420", 0 },
+	{}
 };
-MODULE_DEVICE_TABLE(i2c, adt7410_ids);
-
-#ifdef CONFIG_PM_SLEEP
-static int adt7410_suspend(struct device *dev)
-{
-	int ret;
-	struct i2c_client *client = to_i2c_client(dev);
-	struct adt7410_data *data = i2c_get_clientdata(client);
-
-	ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
-					data->config | ADT7410_PD);
-	return ret;
-}
-
-static int adt7410_resume(struct device *dev)
-{
-	int ret;
-	struct i2c_client *client = to_i2c_client(dev);
-	struct adt7410_data *data = i2c_get_clientdata(client);
-
-	ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG, data->config);
-	return ret;
-}
-
-static SIMPLE_DEV_PM_OPS(adt7410_dev_pm_ops, adt7410_suspend, adt7410_resume);
-
-#define ADT7410_DEV_PM_OPS (&adt7410_dev_pm_ops)
-#else
-#define ADT7410_DEV_PM_OPS NULL
-#endif /* CONFIG_PM */
+MODULE_DEVICE_TABLE(i2c, adt7410_id);
 
 static struct i2c_driver adt7410_driver = {
-	.class		= I2C_CLASS_HWMON,
 	.driver = {
-		.name	= "adt7410",
+		.name = "adt7410",
 		.pm	= ADT7410_DEV_PM_OPS,
 	},
-	.probe		= adt7410_probe,
-	.remove		= adt7410_remove,
-	.id_table	= adt7410_ids,
-	.address_list	= I2C_ADDRS(0x48, 0x49, 0x4a, 0x4b),
+	.probe = adt7410_i2c_probe,
+	.remove = adt7410_i2c_remove,
+	.id_table = adt7410_id,
+	.address_list = I2C_ADDRS(0x48, 0x49, 0x4a, 0x4b),
+	.class = I2C_CLASS_HWMON,
 };
-
 module_i2c_driver(adt7410_driver);
 
-MODULE_AUTHOR("Hartmut Knaack");
-MODULE_DESCRIPTION("ADT7410/ADT7420 driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("ADT7410/AD7420 driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/adt7x10.c b/drivers/hwmon/adt7x10.c
new file mode 100644
index 0000000..2598aaf
--- /dev/null
+++ b/drivers/hwmon/adt7x10.c
@@ -0,0 +1,476 @@
+/*
+ * adt7410.c - Part of lm_sensors, Linux kernel modules for hardware
+ *	 monitoring
+ * This driver handles the ADT7410 and compatible digital temperature sensors.
+ * Hartmut Knaack <knaack.h@gmx.de> 2012-07-22
+ * based on lm75.c by Frodo Looijaard <frodol@dds.nl>
+ * and adt7410.c from iio-staging by Sonic Zhang <sonic.zhang@analog.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+
+#include "adt7x10.h"
+
+/*
+ * ADT7410 status
+ */
+#define ADT7410_STAT_T_LOW		(1 << 4)
+#define ADT7410_STAT_T_HIGH		(1 << 5)
+#define ADT7410_STAT_T_CRIT		(1 << 6)
+#define ADT7410_STAT_NOT_RDY		(1 << 7)
+
+/*
+ * ADT7410 config
+ */
+#define ADT7410_FAULT_QUEUE_MASK	(1 << 0 | 1 << 1)
+#define ADT7410_CT_POLARITY		(1 << 2)
+#define ADT7410_INT_POLARITY		(1 << 3)
+#define ADT7410_EVENT_MODE		(1 << 4)
+#define ADT7410_MODE_MASK		(1 << 5 | 1 << 6)
+#define ADT7410_FULL			(0 << 5 | 0 << 6)
+#define ADT7410_PD			(1 << 5 | 1 << 6)
+#define ADT7410_RESOLUTION		(1 << 7)
+
+/*
+ * ADT7410 masks
+ */
+#define ADT7410_T13_VALUE_MASK			0xFFF8
+#define ADT7410_T_HYST_MASK			0xF
+
+/* straight from the datasheet */
+#define ADT7410_TEMP_MIN (-55000)
+#define ADT7410_TEMP_MAX 150000
+
+/* Each client has this additional data */
+struct adt7410_data {
+	const struct adt7410_ops *ops;
+	const char		*name;
+	struct device		*hwmon_dev;
+	struct mutex		update_lock;
+	u8			config;
+	u8			oldconfig;
+	bool			valid;		/* true if registers valid */
+	unsigned long		last_updated;	/* In jiffies */
+	s16			temp[4];	/* Register values,
+						   0 = input
+						   1 = high
+						   2 = low
+						   3 = critical */
+	u8			hyst;		/* hysteresis offset */
+};
+
+static int adt7410_read_word(struct device *dev, u8 reg, u16 *data)
+{
+	struct adt7410_data *d = dev_get_drvdata(dev);
+	return d->ops->read_word(dev, reg, data);
+}
+
+static int adt7410_write_word(struct device *dev, u8 reg, u16 data)
+{
+	struct adt7410_data *d = dev_get_drvdata(dev);
+	return d->ops->write_word(dev, reg, data);
+}
+
+static int adt7410_read_byte(struct device *dev, u8 reg, u8 *data)
+{
+	struct adt7410_data *d = dev_get_drvdata(dev);
+	return d->ops->read_byte(dev, reg, data);
+}
+
+static int adt7410_write_byte(struct device *dev, u8 reg, u8 data)
+{
+	struct adt7410_data *d = dev_get_drvdata(dev);
+	return d->ops->write_byte(dev, reg, data);
+}
+
+static const u8 ADT7410_REG_TEMP[4] = {
+	ADT7410_TEMPERATURE,		/* input */
+	ADT7410_T_ALARM_HIGH,		/* high */
+	ADT7410_T_ALARM_LOW,		/* low */
+	ADT7410_T_CRIT,			/* critical */
+};
+
+/*
+ * adt7410 register access by I2C
+ */
+static int adt7410_temp_ready(struct device *dev)
+{
+	int i, ret;
+	u8 status;
+
+	for (i = 0; i < 6; i++) {
+		ret = adt7410_read_byte(dev, ADT7410_STATUS, &status);
+		if (ret)
+			return ret;
+		if (!(status & ADT7410_STAT_NOT_RDY))
+			return 0;
+		msleep(60);
+	}
+	return -ETIMEDOUT;
+}
+
+static int adt7410_update_temp(struct device *dev)
+{
+	struct adt7410_data *data = dev_get_drvdata(dev);
+	int ret = 0;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	    || !data->valid) {
+
+		dev_dbg(dev, "Starting update\n");
+
+		ret = adt7410_temp_ready(dev); /* check for new value */
+		if (ret)
+			goto abort;
+
+		ret = adt7410_read_word(dev, ADT7410_REG_TEMP[0],
+					&data->temp[0]);
+		if (ret) {
+			dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
+				ADT7410_REG_TEMP[0], ret);
+			goto abort;
+		}
+		data->last_updated = jiffies;
+		data->valid = true;
+	}
+
+abort:
+	mutex_unlock(&data->update_lock);
+	return ret;
+}
+
+static int adt7410_fill_cache(struct device *dev)
+{
+	struct adt7410_data *data = dev_get_drvdata(dev);
+	int ret;
+	int i;
+
+	for (i = 1; i < ARRAY_SIZE(data->temp); i++) {
+		ret = adt7410_read_word(dev, ADT7410_REG_TEMP[i],
+					&data->temp[i]);
+		if (ret) {
+			dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
+				ADT7410_REG_TEMP[0], ret);
+			return ret;
+		}
+	}
+
+	ret = adt7410_read_byte(dev, ADT7410_T_HYST, &data->hyst);
+	if (ret) {
+		dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
+				ADT7410_T_HYST, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static s16 ADT7410_TEMP_TO_REG(long temp)
+{
+	return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7410_TEMP_MIN,
+					       ADT7410_TEMP_MAX) * 128, 1000);
+}
+
+static int ADT7410_REG_TO_TEMP(struct adt7410_data *data, s16 reg)
+{
+	/* in 13 bit mode, bits 0-2 are status flags - mask them out */
+	if (!(data->config & ADT7410_RESOLUTION))
+		reg &= ADT7410_T13_VALUE_MASK;
+	/*
+	 * temperature is stored in twos complement format, in steps of
+	 * 1/128°C
+	 */
+	return DIV_ROUND_CLOSEST(reg * 1000, 128);
+}
+
+/*-----------------------------------------------------------------------*/
+
+/* sysfs attributes for hwmon */
+
+static ssize_t adt7410_show_temp(struct device *dev,
+				 struct device_attribute *da, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct adt7410_data *data = dev_get_drvdata(dev);
+
+
+	if (attr->index == 0) {
+		int ret;
+
+		ret = adt7410_update_temp(dev);
+		if (ret)
+			return ret;
+	}
+
+	return sprintf(buf, "%d\n", ADT7410_REG_TO_TEMP(data,
+		       data->temp[attr->index]));
+}
+
+static ssize_t adt7410_set_temp(struct device *dev,
+				struct device_attribute *da,
+				const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct adt7410_data *data = dev_get_drvdata(dev);
+	int nr = attr->index;
+	long temp;
+	int ret;
+
+	ret = kstrtol(buf, 10, &temp);
+	if (ret)
+		return ret;
+
+	mutex_lock(&data->update_lock);
+	data->temp[nr] = ADT7410_TEMP_TO_REG(temp);
+	ret = adt7410_write_word(dev, ADT7410_REG_TEMP[nr], data->temp[nr]);
+	if (ret)
+		count = ret;
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t adt7410_show_t_hyst(struct device *dev,
+				   struct device_attribute *da,
+				   char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct adt7410_data *data = dev_get_drvdata(dev);
+	int nr = attr->index;
+	int hyst;
+
+	hyst = (data->hyst & ADT7410_T_HYST_MASK) * 1000;
+
+	/*
+	 * hysteresis is stored as a 4 bit offset in the device, convert it
+	 * to an absolute value
+	 */
+	if (nr == 2)	/* min has positive offset, others have negative */
+		hyst = -hyst;
+	return sprintf(buf, "%d\n",
+		       ADT7410_REG_TO_TEMP(data, data->temp[nr]) - hyst);
+}
+
+static ssize_t adt7410_set_t_hyst(struct device *dev,
+				  struct device_attribute *da,
+				  const char *buf, size_t count)
+{
+	struct adt7410_data *data = dev_get_drvdata(dev);
+	int limit, ret;
+	long hyst;
+
+	ret = kstrtol(buf, 10, &hyst);
+	if (ret)
+		return ret;
+	/* convert absolute hysteresis value to a 4 bit delta value */
+	limit = ADT7410_REG_TO_TEMP(data, data->temp[1]);
+	hyst = clamp_val(hyst, ADT7410_TEMP_MIN, ADT7410_TEMP_MAX);
+	data->hyst = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000),
+				   0, ADT7410_T_HYST_MASK);
+	ret = adt7410_write_byte(dev, ADT7410_T_HYST, data->hyst);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+static ssize_t adt7410_show_alarm(struct device *dev,
+				  struct device_attribute *da,
+				  char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	u8 status;
+	int ret;
+
+	ret = adt7410_read_byte(dev, ADT7410_STATUS, &status);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%d\n", !!(status & attr->index));
+}
+
+static ssize_t adt7410_show_name(struct device *dev,
+				  struct device_attribute *da, char *buf)
+{
+	struct adt7410_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%s\n", data->name);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adt7410_show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
+			  adt7410_show_temp, adt7410_set_temp, 1);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
+			  adt7410_show_temp, adt7410_set_temp, 2);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
+			  adt7410_show_temp, adt7410_set_temp, 3);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
+			  adt7410_show_t_hyst, adt7410_set_t_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO,
+			  adt7410_show_t_hyst, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO,
+			  adt7410_show_t_hyst, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, adt7410_show_alarm,
+			  NULL, ADT7410_STAT_T_LOW);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adt7410_show_alarm,
+			  NULL, ADT7410_STAT_T_HIGH);
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, adt7410_show_alarm,
+			  NULL, ADT7410_STAT_T_CRIT);
+static DEVICE_ATTR(name, S_IRUGO, adt7410_show_name, NULL);
+
+static struct attribute *adt7410_attributes[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group adt7410_group = {
+	.attrs = adt7410_attributes,
+};
+
+int adt7410_probe(struct device *dev, const char *name,
+	const struct adt7410_ops *ops)
+{
+	struct adt7410_data *data;
+	int ret;
+
+	data = devm_kzalloc(dev, sizeof(struct adt7410_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->ops = ops;
+	data->name = name;
+
+	dev_set_drvdata(dev, data);
+	mutex_init(&data->update_lock);
+
+	/* configure as specified */
+	ret = adt7410_read_byte(dev, ADT7410_CONFIG, &data->oldconfig);
+	if (ret < 0) {
+		dev_dbg(dev, "Can't read config? %d\n", ret);
+		return ret;
+	}
+	/*
+	 * Set to 16 bit resolution, continous conversion and comparator mode.
+	 */
+	data->config = data->oldconfig;
+	data->config &= ~ADT7410_MODE_MASK;
+	data->config |= ADT7410_FULL | ADT7410_RESOLUTION | ADT7410_EVENT_MODE;
+	if (data->config != data->oldconfig) {
+		ret = adt7410_write_byte(dev, ADT7410_CONFIG, data->config);
+		if (ret)
+			return ret;
+	}
+	dev_dbg(dev, "Config %02x\n", data->config);
+
+	ret = adt7410_fill_cache(dev);
+	if (ret)
+		goto exit_restore;
+
+	/* Register sysfs hooks */
+	ret = sysfs_create_group(&dev->kobj, &adt7410_group);
+	if (ret)
+		goto exit_restore;
+
+	/*
+	 * The I2C device will already have it's own 'name' attribute, but for
+	 * the SPI device we need to register it. name will only be non NULL if
+	 * the device doesn't register the 'name' attribute on its own.
+	 */
+	if (name) {
+		ret = device_create_file(dev, &dev_attr_name);
+		if (ret)
+			goto exit_remove;
+	}
+
+	data->hwmon_dev = hwmon_device_register(dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		ret = PTR_ERR(data->hwmon_dev);
+		goto exit_remove_name;
+	}
+
+	return 0;
+
+exit_remove_name:
+	if (name)
+		device_remove_file(dev, &dev_attr_name);
+exit_remove:
+	sysfs_remove_group(&dev->kobj, &adt7410_group);
+exit_restore:
+	adt7410_write_byte(dev, ADT7410_CONFIG, data->oldconfig);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(adt7410_probe);
+
+int adt7410_remove(struct device *dev)
+{
+	struct adt7410_data *data = dev_get_drvdata(dev);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	if (data->name)
+		device_remove_file(dev, &dev_attr_name);
+	sysfs_remove_group(&dev->kobj, &adt7410_group);
+	if (data->oldconfig != data->config)
+		adt7410_write_byte(dev, ADT7410_CONFIG,
+					  data->oldconfig);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(adt7410_remove);
+
+#ifdef CONFIG_PM_SLEEP
+
+static int adt7410_suspend(struct device *dev)
+{
+	struct adt7410_data *data = dev_get_drvdata(dev);
+
+	return adt7410_write_byte(dev, ADT7410_CONFIG,
+		data->config | ADT7410_PD);
+}
+
+static int adt7410_resume(struct device *dev)
+{
+	struct adt7410_data *data = dev_get_drvdata(dev);
+
+	return adt7410_write_byte(dev, ADT7410_CONFIG, data->config);
+}
+
+SIMPLE_DEV_PM_OPS(adt7410_dev_pm_ops, adt7410_suspend, adt7410_resume);
+EXPORT_SYMBOL_GPL(adt7410_dev_pm_ops);
+
+#endif /* CONFIG_PM_SLEEP */
+
+MODULE_AUTHOR("Hartmut Knaack");
+MODULE_DESCRIPTION("ADT7410 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/adt7x10.h b/drivers/hwmon/adt7x10.h
new file mode 100644
index 0000000..17c8053
--- /dev/null
+++ b/drivers/hwmon/adt7x10.h
@@ -0,0 +1,47 @@
+#ifndef __HWMON_ADT7410_H__
+#define __HWMON_ADT7410_H__
+
+#include <linux/types.h>
+
+/* ADT7410 registers definition */
+#define ADT7410_TEMPERATURE		0
+#define ADT7410_STATUS			2
+#define ADT7410_CONFIG			3
+#define ADT7410_T_ALARM_HIGH		4
+#define ADT7410_T_ALARM_LOW		6
+#define ADT7410_T_CRIT			8
+#define ADT7410_T_HYST			0xA
+#define ADT7410_ID			0xB
+
+/* ADT7310 registers definition */
+#define ADT7310_STATUS			0
+#define ADT7310_CONFIG			1
+#define ADT7310_TEMPERATURE		2
+#define ADT7310_ID			3
+#define ADT7310_T_CRIT			4
+#define ADT7310_T_HYST			5
+#define ADT7310_T_ALARM_HIGH		6
+#define ADT7310_T_ALARM_LOW		7
+
+struct device;
+
+struct adt7410_ops {
+	int (*read_word)(struct device *, u8 reg, u16 *data);
+	int (*write_word)(struct device *, u8 reg, u16 data);
+	int (*read_byte)(struct device *, u8 reg, u8 *data);
+	int (*write_byte)(struct device *, u8 reg, u8 data);
+};
+
+int adt7410_probe(struct device *dev, const char *name,
+	const struct adt7410_ops *ops);
+int adt7410_remove(struct device *dev);
+
+
+#ifdef CONFIG_PM_SLEEP
+extern const struct dev_pm_ops adt7410_dev_pm_ops;
+#define ADT7410_DEV_PM_OPS (&adt7410_dev_pm_ops)
+#else
+#define ADT7410_DEV_PM_OPS NULL
+#endif
+
+#endif
-- 
1.8.0


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

* [lm-sensors] [PATCH 7/9] hwmon: (adt7410) Add =?utf-8?q?_support_for_the_adt73
@ 2013-02-15 16:57   ` Lars-Peter Clausen
  0 siblings, 0 replies; 56+ messages in thread
From: Lars-Peter Clausen @ 2013-02-15 16:57 UTC (permalink / raw)
  To: Jean Delvare, Guenter Roeck
  Cc: Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio,
	Lars-Peter Clausen

VGhlIGFkdDczMTAvYWR0NzMyMCBpcyB0aGUgU1BJIHZlcnNpb24gb2YgdGhlIGFkdDc0MTAvYWR0
NzMyMC4gVGhlIHJlZ2lzdGVyIG1hcApsYXlvdXQgaXMgYSBiaXQgZGlmZmVyZW50LCBpLmUuIHRo
ZSByZWdpc3RlciBhZGRyZXNzZXMgZGlmZmVyIGJldHdlZW4gdGhlIHR3bwp2YXJpYW50cywgYnV0
IHRoZSBiaXQgbGF5b3V0cyBvZiB0aGUgaW5kaXZpZHVhbCByZWdpc3RlcnMgYXJlIGlkZW50aWNh
bC4gU28gYm90aApjaGlwIHZhcmlhbnRzIGNhbiBlYXNpbHkgYmUgc3VwcG9ydGVkIGJ5IHRoZSBz
YW1lIGRyaXZlci4gVGhlIGlzc3VlIG9mIG5vbgptYXRjaGluZyByZWdpc3RlciBhZGRyZXNzIGxh
eW91dHMgaXMgc29sdmVkIGJ5IGEgc2ltcGxlIGxvb2stdXAgdGFibGUgd2hpY2gKdHJhbnNsYXRl
cyB0aGUgSTJDIGFkZHJlc3NlcyB0byB0aGUgU1BJIGFkZHJlc3Nlcy4KClRoZSBwYXRjaCBtb3Zl
cyB0aGUgYnVsayBvZiB0aGUgYWR0NzQxMCBkcml2ZXIgdG8gYSBjb21tb24gbW9kdWxlIHRoYXQg
d2lsbCBiZQpzaGFyZWQgYnkgdGhlIGFkdDc0MTAgYW5kIGFkdDczMTAgZHJpdmVycy4gVGhpcyBj
b21tb24gbW9kdWxlIGltcGxlbWVudHMgdGhlCmRyaXZlciBsb2dpYyBhbmQgdXNlcyBhIHNldCBv
ZiB2aXJ0dWFsIGZ1bmN0aW9ucyB0byBwZXJmb3JtIElPIGFjY2Vzcy4gVGhlCmFkdDc0MTAgYW5k
IGFkdDczMTAgZHJpdmVyIG1vZHVsZXMgcHJvdmlkZSBwcm9wZXIgaW1wbGVtZW50YXRpb25zIG9m
IHRoZXNlIElPCmFjY2Vzc29yIGZ1bmN0aW9ucyBmb3IgSTJDIHJlc3BlY3RpdmUgU1BJLgoKU2ln
bmVkLW9mZi1ieTogTGFycy1QZXRlciBDbGF1c2VuIDxsYXJzQG1ldGFmb28uZGU+Ci0tLQogZHJp
dmVycy9od21vbi9LY29uZmlnICAgfCAgMjAgKysKIGRyaXZlcnMvaHdtb24vTWFrZWZpbGUgIHwg
ICAyICsKIGRyaXZlcnMvaHdtb24vYWR0NzMxMC5jIHwgMTYwICsrKysrKysrKysrKysrKysKIGRy
aXZlcnMvaHdtb24vYWR0NzQxMC5jIHwgNDcyICsrKysrKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tCiBkcml2ZXJzL2h3bW9uL2FkdDd4MTAuYyB8IDQ3NiArKysrKysr
KysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysKIGRyaXZlcnMvaHdtb24v
YWR0N3gxMC5oIHwgIDQ3ICsrKysrCiA2IGZpbGVzIGNoYW5nZWQsIDc1OCBpbnNlcnRpb25zKCsp
LCA0MTkgZGVsZXRpb25zKC0pCiBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy9od21vbi9hZHQ3
MzEwLmMKIGNyZWF0ZSBtb2RlIDEwMDY0NCBkcml2ZXJzL2h3bW9uL2FkdDd4MTAuYwogY3JlYXRl
IG1vZGUgMTAwNjQ0IGRyaXZlcnMvaHdtb24vYWR0N3gxMC5oCgpkaWZmIC0tZ2l0IGEvZHJpdmVy
cy9od21vbi9LY29uZmlnIGIvZHJpdmVycy9od21vbi9LY29uZmlnCmluZGV4IDg5YWMxY2IuLmFh
YTE0ZjQgMTAwNjQ0Ci0tLSBhL2RyaXZlcnMvaHdtb24vS2NvbmZpZworKysgYi9kcml2ZXJzL2h3
bW9uL0tjb25maWcKQEAgLTE3OSw5ICsxNzksMjkgQEAgY29uZmlnIFNFTlNPUlNfQURNOTI0MAog
CSAgVGhpcyBkcml2ZXIgY2FuIGFsc28gYmUgYnVpbHQgYXMgYSBtb2R1bGUuICBJZiBzbywgdGhl
IG1vZHVsZQogCSAgd2lsbCBiZSBjYWxsZWQgYWRtOTI0MC4KIAorY29uZmlnIFNFTlNPUlNfQURU
N1gxMAorCXRyaXN0YXRlCisJaGVscAorCSAgVGhpcyBtb2R1bGUgY29udGFpbnMgY29tbW9uIGNv
ZGUgc2hhcmVkIGJ5IHRoZSBBRFQ3MzEwL0FEVDczMjAgYW5kCisJICBBRFQ3NDEwL0FEVDc0MjAg
dGVtcGVyYXR1cmUgbW9uaXRvcmluZyBjaGlwIGRyaXZlcnMuCisKKwkgIElmIGJ1aWxkIGFzIGEg
bW9kdWxlLCB0aGUgbW9kdWxlIHdpbGwgYmUgY2FsbGVkIGFkdDd4MTAuCisKK2NvbmZpZyBTRU5T
T1JTX0FEVDczMTAKKwl0cmlzdGF0ZSAiQW5hbG9nIERldmljZXMgQURUNzMxMC9BRFQ3MzIwIgor
CWRlcGVuZHMgb24gU1BJX01BU1RFUgorCXNlbGVjdCBTRU5TT1JTX0FEVDdYMTAKKwloZWxwCisJ
ICBJZiB5b3Ugc2F5IHllcyBoZXJlIHlvdSBnZXQgc3VwcG9ydCBmb3IgdGhlIEFuYWxvZyBEZXZp
Y2VzCisJICBBRFQ3MzEwIGFuZCBBRFQ3MzIwIHRlbXBlcmF0dXJlIG1vbml0b3JpbmcgY2hpcHMu
CisKKwkgIFRoaXMgZHJpdmVyIGNhbiBhbHNvIGJlIGJ1aWx0IGFzIGEgbW9kdWxlLiBJZiBzbywg
dGhlIG1vZHVsZQorCSAgd2lsbCBiZSBjYWxsZWQgYWR0NzMxMC4KKwogY29uZmlnIFNFTlNPUlNf
QURUNzQxMAogCXRyaXN0YXRlICJBbmFsb2cgRGV2aWNlcyBBRFQ3NDEwL0FEVDc0MjAiCiAJZGVw
ZW5kcyBvbiBJMkMKKwlzZWxlY3QgU0VOU09SU19BRFQ3WDEwCiAJaGVscAogCSAgSWYgeW91IHNh
eSB5ZXMgaGVyZSB5b3UgZ2V0IHN1cHBvcnQgZm9yIHRoZSBBbmFsb2cgRGV2aWNlcwogCSAgQURU
NzQxMCBhbmQgQURUNzQyMCB0ZW1wZXJhdHVyZSBtb25pdG9yaW5nIGNoaXBzLgpkaWZmIC0tZ2l0
IGEvZHJpdmVycy9od21vbi9NYWtlZmlsZSBiL2RyaXZlcnMvaHdtb24vTWFrZWZpbGUKaW5kZXgg
OGQ2ZDk3ZS4uNWQzNmE1NyAxMDA2NDQKLS0tIGEvZHJpdmVycy9od21vbi9NYWtlZmlsZQorKysg
Yi9kcml2ZXJzL2h3bW9uL01ha2VmaWxlCkBAIC0zNCw2ICszNCw4IEBAIG9iai0kKENPTkZJR19T
RU5TT1JTX0FETTkyNDApCSs9IGFkbTkyNDAubwogb2JqLSQoQ09ORklHX1NFTlNPUlNfQURTMTAx
NSkJKz0gYWRzMTAxNS5vCiBvYmotJChDT05GSUdfU0VOU09SU19BRFM3ODI4KQkrPSBhZHM3ODI4
Lm8KIG9iai0kKENPTkZJR19TRU5TT1JTX0FEUzc4NzEpCSs9IGFkczc4NzEubworb2JqLSQoQ09O
RklHX1NFTlNPUlNfQURUN1gxMCkJKz0gYWR0N3gxMC5vCitvYmotJChDT05GSUdfU0VOU09SU19B
RFQ3MzEwKQkrPSBhZHQ3MzEwLm8KIG9iai0kKENPTkZJR19TRU5TT1JTX0FEVDc0MTApCSs9IGFk
dDc0MTAubwogb2JqLSQoQ09ORklHX1NFTlNPUlNfQURUNzQxMSkJKz0gYWR0NzQxMS5vCiBvYmot
JChDT05GSUdfU0VOU09SU19BRFQ3NDYyKQkrPSBhZHQ3NDYyLm8KZGlmZiAtLWdpdCBhL2RyaXZl
cnMvaHdtb24vYWR0NzMxMC5jIGIvZHJpdmVycy9od21vbi9hZHQ3MzEwLmMKbmV3IGZpbGUgbW9k
ZSAxMDA2NDQKaW5kZXggMDAwMDAwMC4uMDQ4M2U2YwotLS0gL2Rldi9udWxsCisrKyBiL2RyaXZl
cnMvaHdtb24vYWR0NzMxMC5jCkBAIC0wLDAgKzEsMTYwIEBACisvKgorICogQURUNzMxMC9BRFQ3
MzEwIGRpZ2l0YWwgdGVtcGVyYXR1cmUgc2Vuc29yIGRyaXZlcgorICoKKyAqIENvcHlyaWdodCAy
MDEwLTIwMTMgQW5hbG9nIERldmljZXMgSW5jLgorICogICBBdXRob3I6IExhcnMtUGV0ZXIgQ2xh
dXNlbiA8bGFyc0BtZXRhZm9vLmRlPgorICoKKyAqIExpY2Vuc2VkIHVuZGVyIHRoZSBHUEwtMiBv
ciBsYXRlci4KKyAqLworCisjaW5jbHVkZSA8bGludXgvbW9kdWxlLmg+CisjaW5jbHVkZSA8bGlu
dXgvaW5pdC5oPgorI2luY2x1ZGUgPGxpbnV4L3NwaS9zcGkuaD4KKworI2luY2x1ZGUgImFkdDd4
MTAuaCIKKworc3RhdGljIGNvbnN0IHU4IGFkdDczNzFfcmVnX3RhYmxlW10gPSB7CisJW0FEVDc0
MTBfVEVNUEVSQVRVUkVdICAgPSBBRFQ3MzEwX1RFTVBFUkFUVVJFLAorCVtBRFQ3NDEwX1NUQVRV
U10JPSBBRFQ3MzEwX1NUQVRVUywKKwlbQURUNzQxMF9DT05GSUddCT0gQURUNzMxMF9DT05GSUcs
CisJW0FEVDc0MTBfVF9BTEFSTV9ISUdIXQk9IEFEVDczMTBfVF9BTEFSTV9ISUdILAorCVtBRFQ3
NDEwX1RfQUxBUk1fTE9XXQk9IEFEVDczMTBfVF9BTEFSTV9MT1csCisJW0FEVDc0MTBfVF9DUklU
XQk9IEFEVDczMTBfVF9DUklULAorCVtBRFQ3NDEwX1RfSFlTVF0JPSBBRFQ3MzEwX1RfSFlTVCwK
KwlbQURUNzQxMF9JRF0JCT0gQURUNzMxMF9JRCwKK307CisKKyNkZWZpbmUgQURUNzMxMF9DTURf
UkVHX01BU0sJCQkweDI4CisjZGVmaW5lIEFEVDczMTBfQ01EX1JFR19PRkZTRVQJCQkzCisjZGVm
aW5lIEFEVDczMTBfQ01EX1JFQUQJCQkweDQwCisjZGVmaW5lIEFEVDczMTBfQ01EX0NPTl9SRUFE
CQkJMHg0CisKKyNkZWZpbmUgQUQ3MzEwX0NPTU1BTkQocmVnKSAoYWR0NzM3MV9yZWdfdGFibGVb
KHJlZyldIDw8IEFEVDczMTBfQ01EX1JFR19PRkZTRVQpCisKK3N0YXRpYyBpbnQgYWR0NzMxMF9z
cGlfcmVhZF93b3JkKHN0cnVjdCBkZXZpY2UgKmRldiwKKwl1OCByZWcsIHUxNiAqZGF0YSkKK3sK
KwlzdHJ1Y3Qgc3BpX2RldmljZSAqc3BpID0gdG9fc3BpX2RldmljZShkZXYpOworCXU4IGNvbW1h
bmQgPSBBRDczMTBfQ09NTUFORChyZWcpOworCWludCByZXQgPSAwOworCisJY29tbWFuZCB8PSBB
RFQ3MzEwX0NNRF9SRUFEOworCXJldCA9IHNwaV93cml0ZShzcGksICZjb21tYW5kLCBzaXplb2Yo
Y29tbWFuZCkpOworCWlmIChyZXQgPCAwKSB7CisJCWRldl9lcnIoZGV2LCAiU1BJIHdyaXRlIGNv
bW1hbmQgZXJyb3JcbiIpOworCQlyZXR1cm4gcmV0OworCX0KKworCXJldCA9IHNwaV9yZWFkKHNw
aSwgKHU4ICopZGF0YSwgc2l6ZW9mKCpkYXRhKSk7CisJaWYgKHJldCA8IDApIHsKKwkJZGV2X2Vy
cihkZXYsICJTUEkgcmVhZCB3b3JkIGVycm9yXG4iKTsKKwkJcmV0dXJuIHJldDsKKwl9CisKKwkq
ZGF0YSA9IGJlMTZfdG9fY3B1KCpkYXRhKTsKKworCXJldHVybiAwOworfQorCitzdGF0aWMgaW50
IGFkdDczMTBfc3BpX3dyaXRlX3dvcmQoc3RydWN0IGRldmljZSAqZGV2LCB1OCByZWcsCisJdTE2
IGRhdGEpCit7CisJc3RydWN0IHNwaV9kZXZpY2UgKnNwaSA9IHRvX3NwaV9kZXZpY2UoZGV2KTsK
Kwl1OCBidWZbM107CisJaW50IHJldCA9IDA7CisKKwlidWZbMF0gPSBBRDczMTBfQ09NTUFORChy
ZWcpOworCWJ1ZlsxXSA9ICh1OCkoZGF0YSA+PiA4KTsKKwlidWZbMl0gPSAodTgpKGRhdGEgJiAw
eEZGKTsKKworCXJldCA9IHNwaV93cml0ZShzcGksIGJ1ZiwgMyk7CisJaWYgKHJldCA8IDApIHsK
KwkJZGV2X2VycihkZXYsICJTUEkgd3JpdGUgd29yZCBlcnJvclxuIik7CisJCXJldHVybiByZXQ7
CisJfQorCisJcmV0dXJuIHJldDsKK30KKworc3RhdGljIGludCBhZHQ3MzEwX3NwaV9yZWFkX2J5
dGUoc3RydWN0IGRldmljZSAqZGV2LCB1OCByZWcsCisJdTggKmRhdGEpCit7CisJc3RydWN0IHNw
aV9kZXZpY2UgKnNwaSA9IHRvX3NwaV9kZXZpY2UoZGV2KTsKKwl1OCBjb21tYW5kID0gQUQ3MzEw
X0NPTU1BTkQocmVnKTsKKwlpbnQgcmV0ID0gMDsKKworCWNvbW1hbmQgfD0gQURUNzMxMF9DTURf
UkVBRDsKKwlyZXQgPSBzcGlfd3JpdGUoc3BpLCAmY29tbWFuZCwgc2l6ZW9mKGNvbW1hbmQpKTsK
KwlpZiAocmV0IDwgMCkgeworCQlkZXZfZXJyKGRldiwgIlNQSSB3cml0ZSBjb21tYW5kIGVycm9y
XG4iKTsKKwkJcmV0dXJuIHJldDsKKwl9CisKKwlyZXQgPSBzcGlfcmVhZChzcGksIGRhdGEsIHNp
emVvZigqZGF0YSkpOworCWlmIChyZXQgPCAwKSB7CisJCWRldl9lcnIoZGV2LCAiU1BJIHJlYWQg
Ynl0ZSBlcnJvclxuIik7CisJCXJldHVybiByZXQ7CisJfQorCisJcmV0dXJuIDA7Cit9CisKK3N0
YXRpYyBpbnQgYWR0NzMxMF9zcGlfd3JpdGVfYnl0ZShzdHJ1Y3QgZGV2aWNlICpkZXYsIHU4IHJl
ZywKKwl1OCBkYXRhKQoreworCXN0cnVjdCBzcGlfZGV2aWNlICpzcGkgPSB0b19zcGlfZGV2aWNl
KGRldik7CisJdTggYnVmWzJdOworCWludCByZXQgPSAwOworCisJYnVmWzBdID0gQUQ3MzEwX0NP
TU1BTkQocmVnKTsKKwlidWZbMV0gPSBkYXRhOworCisJcmV0ID0gc3BpX3dyaXRlKHNwaSwgYnVm
LCAyKTsKKwlpZiAocmV0IDwgMCkgeworCQlkZXZfZXJyKGRldiwgIlNQSSB3cml0ZSBieXRlIGVy
cm9yXG4iKTsKKwkJcmV0dXJuIHJldDsKKwl9CisKKwlyZXR1cm4gcmV0OworfQorCitzdGF0aWMg
Y29uc3Qgc3RydWN0IGFkdDc0MTBfb3BzIGFkdDczMTBfc3BpX29wcyA9IHsKKwkucmVhZF93b3Jk
ID0gYWR0NzMxMF9zcGlfcmVhZF93b3JkLAorCS53cml0ZV93b3JkID0gYWR0NzMxMF9zcGlfd3Jp
dGVfd29yZCwKKwkucmVhZF9ieXRlID0gYWR0NzMxMF9zcGlfcmVhZF9ieXRlLAorCS53cml0ZV9i
eXRlID0gYWR0NzMxMF9zcGlfd3JpdGVfYnl0ZSwKK307CisKK3N0YXRpYyBpbnQgYWR0NzMxMF9z
cGlfcHJvYmUoc3RydWN0IHNwaV9kZXZpY2UgKnNwaSkKK3sKKwlyZXR1cm4gYWR0NzQxMF9wcm9i
ZSgmc3BpLT5kZXYsIHNwaV9nZXRfZGV2aWNlX2lkKHNwaSktPm5hbWUsCisJCQkmYWR0NzMxMF9z
cGlfb3BzKTsKK30KKworc3RhdGljIGludCBhZHQ3MzEwX3NwaV9yZW1vdmUoc3RydWN0IHNwaV9k
ZXZpY2UgKnNwaSkKK3sKKwlyZXR1cm4gYWR0NzQxMF9yZW1vdmUoJnNwaS0+ZGV2KTsKK30KKwor
c3RhdGljIGNvbnN0IHN0cnVjdCBzcGlfZGV2aWNlX2lkIGFkdDczMTBfaWRbXSA9IHsKKwl7ICJh
ZHQ3MzEwIiwgMCB9LAorCXsgImFkdDczMjAiLCAwIH0sCisJe30KK307CitNT0RVTEVfREVWSUNF
X1RBQkxFKHNwaSwgYWR0NzMxMF9pZCk7CisKK3N0YXRpYyBzdHJ1Y3Qgc3BpX2RyaXZlciBhZHQ3
MzEwX2RyaXZlciA9IHsKKwkuZHJpdmVyID0geworCQkubmFtZSA9ICJhZHQ3MzEwIiwKKwkJLm93
bmVyID0gVEhJU19NT0RVTEUsCisJCS5wbQk9IEFEVDc0MTBfREVWX1BNX09QUywKKwl9LAorCS5w
cm9iZSA9IGFkdDczMTBfc3BpX3Byb2JlLAorCS5yZW1vdmUgPSBhZHQ3MzEwX3NwaV9yZW1vdmUs
CisJLmlkX3RhYmxlID0gYWR0NzMxMF9pZCwKK307Cittb2R1bGVfc3BpX2RyaXZlcihhZHQ3MzEw
X2RyaXZlcik7CisKK01PRFVMRV9BVVRIT1IoIkxhcnMtUGV0ZXIgQ2xhdXNlbiA8bGFyc0BtZXRh
Zm9vLmRlPiIpOworTU9EVUxFX0RFU0NSSVBUSU9OKCJBRFQ3MzEwL0FEVDc0MjAgZHJpdmVyIik7
CitNT0RVTEVfTElDRU5TRSgiR1BMIik7CmRpZmYgLS1naXQgYS9kcml2ZXJzL2h3bW9uL2FkdDc0
MTAuYyBiL2RyaXZlcnMvaHdtb24vYWR0NzQxMC5jCmluZGV4IDVkZTAzNzYuLjEzNzM0YzUgMTAw
NjQ0Ci0tLSBhL2RyaXZlcnMvaHdtb24vYWR0NzQxMC5jCisrKyBiL2RyaXZlcnMvaHdtb24vYWR0
NzQxMC5jCkBAIC0xLDQ4MyArMSwxMTcgQEAKIC8qCi0gKiBhZHQ3NDEwLmMgLSBQYXJ0IG9mIGxt
X3NlbnNvcnMsIExpbnV4IGtlcm5lbCBtb2R1bGVzIGZvciBoYXJkd2FyZQotICoJIG1vbml0b3Jp
bmcKLSAqIFRoaXMgZHJpdmVyIGhhbmRsZXMgdGhlIEFEVDc0MTAgYW5kIGNvbXBhdGlibGUgZGln
aXRhbCB0ZW1wZXJhdHVyZSBzZW5zb3JzLgotICogSGFydG11dCBLbmFhY2sgPGtuYWFjay5oQGdt
eC5kZT4gMjAxMi0wNy0yMgotICogYmFzZWQgb24gbG03NS5jIGJ5IEZyb2RvIExvb2lqYWFyZCA8
ZnJvZG9sQGRkcy5ubD4KLSAqIGFuZCBhZHQ3NDEwLmMgZnJvbSBpaW8tc3RhZ2luZyBieSBTb25p
YyBaaGFuZyA8c29uaWMuemhhbmdAYW5hbG9nLmNvbT4KKyAqIEFEVDc0MTAvQURUNzQyMCBkaWdp
dGFsIHRlbXBlcmF0dXJlIHNlbnNvciBkcml2ZXIKICAqCi0gKiBUaGlzIHByb2dyYW0gaXMgZnJl
ZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeQotICogaXQg
dW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJs
aXNoZWQgYnkKLSAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlciB2ZXJzaW9u
IDIgb2YgdGhlIExpY2Vuc2UsIG9yCi0gKiAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJz
aW9uLgorICogQ29weXJpZ2h0IDIwMTAtMjAxMyBBbmFsb2cgRGV2aWNlcyBJbmMuCisgKiAgIEF1
dGhvcjogTGFycy1QZXRlciBDbGF1c2VuIDxsYXJzQG1ldGFmb28uZGU+CiAgKgotICogVGhpcyBw
cm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWws
Ci0gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3
YXJyYW50eSBvZgotICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxB
UiBQVVJQT1NFLiAgU2VlIHRoZQotICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1v
cmUgZGV0YWlscy4KLSAqCi0gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRo
ZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZQotICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW07
IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmUKLSAqIEZvdW5kYXRpb24sIEluYy4s
IDY3NSBNYXNzIEF2ZSwgQ2FtYnJpZGdlLCBNQSAwMjEzOSwgVVNBLgorICogTGljZW5zZWQgdW5k
ZXIgdGhlIEdQTC0yIG9yIGxhdGVyLgogICovCiAKICNpbmNsdWRlIDxsaW51eC9tb2R1bGUuaD4K
ICNpbmNsdWRlIDxsaW51eC9pbml0Lmg+Ci0jaW5jbHVkZSA8bGludXgvc2xhYi5oPgotI2luY2x1
ZGUgPGxpbnV4L2ppZmZpZXMuaD4KICNpbmNsdWRlIDxsaW51eC9pMmMuaD4KLSNpbmNsdWRlIDxs
aW51eC9od21vbi5oPgotI2luY2x1ZGUgPGxpbnV4L2h3bW9uLXN5c2ZzLmg+Ci0jaW5jbHVkZSA8
bGludXgvZXJyLmg+Ci0jaW5jbHVkZSA8bGludXgvbXV0ZXguaD4KLSNpbmNsdWRlIDxsaW51eC9k
ZWxheS5oPgotCi0vKgotICogQURUNzQxMCByZWdpc3RlcnMgZGVmaW5pdGlvbgotICovCiAKLSNk
ZWZpbmUgQURUNzQxMF9URU1QRVJBVFVSRQkJMAotI2RlZmluZSBBRFQ3NDEwX1NUQVRVUwkJCTIK
LSNkZWZpbmUgQURUNzQxMF9DT05GSUcJCQkzCi0jZGVmaW5lIEFEVDc0MTBfVF9BTEFSTV9ISUdI
CQk0Ci0jZGVmaW5lIEFEVDc0MTBfVF9BTEFSTV9MT1cJCTYKLSNkZWZpbmUgQURUNzQxMF9UX0NS
SVQJCQk4Ci0jZGVmaW5lIEFEVDc0MTBfVF9IWVNUCQkJMHhBCisjaW5jbHVkZSAiYWR0N3gxMC5o
IgogCi0vKgotICogQURUNzQxMCBzdGF0dXMKLSAqLwotI2RlZmluZSBBRFQ3NDEwX1NUQVRfVF9M
T1cJCSgxIDw8IDQpCi0jZGVmaW5lIEFEVDc0MTBfU1RBVF9UX0hJR0gJCSgxIDw8IDUpCi0jZGVm
aW5lIEFEVDc0MTBfU1RBVF9UX0NSSVQJCSgxIDw8IDYpCi0jZGVmaW5lIEFEVDc0MTBfU1RBVF9O
T1RfUkRZCQkoMSA8PCA3KQotCi0vKgotICogQURUNzQxMCBjb25maWcKLSAqLwotI2RlZmluZSBB
RFQ3NDEwX0ZBVUxUX1FVRVVFX01BU0sJKDEgPDwgMCB8IDEgPDwgMSkKLSNkZWZpbmUgQURUNzQx
MF9DVF9QT0xBUklUWQkJKDEgPDwgMikKLSNkZWZpbmUgQURUNzQxMF9JTlRfUE9MQVJJVFkJCSgx
IDw8IDMpCi0jZGVmaW5lIEFEVDc0MTBfRVZFTlRfTU9ERQkJKDEgPDwgNCkKLSNkZWZpbmUgQURU
NzQxMF9NT0RFX01BU0sJCSgxIDw8IDUgfCAxIDw8IDYpCi0jZGVmaW5lIEFEVDc0MTBfRlVMTAkJ
CSgwIDw8IDUgfCAwIDw8IDYpCi0jZGVmaW5lIEFEVDc0MTBfUEQJCQkoMSA8PCA1IHwgMSA8PCA2
KQotI2RlZmluZSBBRFQ3NDEwX1JFU09MVVRJT04JCSgxIDw8IDcpCi0KLS8qCi0gKiBBRFQ3NDEw
IG1hc2tzCi0gKi8KLSNkZWZpbmUgQURUNzQxMF9UMTNfVkFMVUVfTUFTSwkJCTB4RkZGOAotI2Rl
ZmluZSBBRFQ3NDEwX1RfSFlTVF9NQVNLCQkJMHhGCi0KLS8qIHN0cmFpZ2h0IGZyb20gdGhlIGRh
dGFzaGVldCAqLwotI2RlZmluZSBBRFQ3NDEwX1RFTVBfTUlOICgtNTUwMDApCi0jZGVmaW5lIEFE
VDc0MTBfVEVNUF9NQVggMTUwMDAwCi0KLWVudW0gYWR0NzQxMF90eXBlIHsJCS8qIGtlZXAgc29y
dGVkIGluIGFscGhhYmV0aWNhbCBvcmRlciAqLwotCWFkdDc0MTAsCi19OwotCi1zdGF0aWMgY29u
c3QgdTggQURUNzQxMF9SRUdfVEVNUFs0XSA9IHsKLQlBRFQ3NDEwX1RFTVBFUkFUVVJFLAkJLyog
aW5wdXQgKi8KLQlBRFQ3NDEwX1RfQUxBUk1fSElHSCwJCS8qIGhpZ2ggKi8KLQlBRFQ3NDEwX1Rf
QUxBUk1fTE9XLAkJLyogbG93ICovCi0JQURUNzQxMF9UX0NSSVQsCQkJLyogY3JpdGljYWwgKi8K
LX07Ci0KLS8qIEVhY2ggY2xpZW50IGhhcyB0aGlzIGFkZGl0aW9uYWwgZGF0YSAqLwotc3RydWN0
IGFkdDc0MTBfZGF0YSB7Ci0Jc3RydWN0IGRldmljZQkJKmh3bW9uX2RldjsKLQlzdHJ1Y3QgbXV0
ZXgJCXVwZGF0ZV9sb2NrOwotCXU4CQkJY29uZmlnOwotCXU4CQkJb2xkY29uZmlnOwotCWJvb2wJ
CQl2YWxpZDsJCS8qIHRydWUgaWYgcmVnaXN0ZXJzIHZhbGlkICovCi0JdW5zaWduZWQgbG9uZwkJ
bGFzdF91cGRhdGVkOwkvKiBJbiBqaWZmaWVzICovCi0JczE2CQkJdGVtcFs0XTsJLyogUmVnaXN0
ZXIgdmFsdWVzLAotCQkJCQkJICAgMCA9IGlucHV0Ci0JCQkJCQkgICAxID0gaGlnaAotCQkJCQkJ
ICAgMiA9IGxvdwotCQkJCQkJICAgMyA9IGNyaXRpY2FsICovCi0JdTgJCQloeXN0OwkJLyogaHlz
dGVyZXNpcyBvZmZzZXQgKi8KLX07Ci0KLS8qCi0gKiBhZHQ3NDEwIHJlZ2lzdGVyIGFjY2VzcyBi
eSBJMkMKLSAqLwotc3RhdGljIGludCBhZHQ3NDEwX3RlbXBfcmVhZHkoc3RydWN0IGkyY19jbGll
bnQgKmNsaWVudCkKLXsKLQlpbnQgaSwgc3RhdHVzOwotCi0JZm9yIChpID0gMDsgaSA8IDY7IGkr
KykgewotCQlzdGF0dXMgPSBpMmNfc21idXNfcmVhZF9ieXRlX2RhdGEoY2xpZW50LCBBRFQ3NDEw
X1NUQVRVUyk7Ci0JCWlmIChzdGF0dXMgPCAwKQotCQkJcmV0dXJuIHN0YXR1czsKLQkJaWYgKCEo
c3RhdHVzICYgQURUNzQxMF9TVEFUX05PVF9SRFkpKQotCQkJcmV0dXJuIDA7Ci0JCW1zbGVlcCg2
MCk7Ci0JfQotCXJldHVybiAtRVRJTUVET1VUOwotfQotCi1zdGF0aWMgaW50IGFkdDc0MTBfdXBk
YXRlX3RlbXAoc3RydWN0IGRldmljZSAqZGV2KQorc3RhdGljIGludCBhZHQ3NDEwX2kyY19yZWFk
X3dvcmQoc3RydWN0IGRldmljZSAqZGV2LCB1OCByZWcsIHUxNiAqZGF0YSkKIHsKIAlzdHJ1Y3Qg
aTJjX2NsaWVudCAqY2xpZW50ID0gdG9faTJjX2NsaWVudChkZXYpOwotCXN0cnVjdCBhZHQ3NDEw
X2RhdGEgKmRhdGEgPSBpMmNfZ2V0X2NsaWVudGRhdGEoY2xpZW50KTsKIAlpbnQgcmV0ID0gMDsK
IAotCW11dGV4X2xvY2soJmRhdGEtPnVwZGF0ZV9sb2NrKTsKLQotCWlmICh0aW1lX2FmdGVyKGpp
ZmZpZXMsIGRhdGEtPmxhc3RfdXBkYXRlZCArIEhaICsgSFogLyAyKQotCSAgICB8fCAhZGF0YS0+
dmFsaWQpIHsKLQotCQlkZXZfZGJnKCZjbGllbnQtPmRldiwgIlN0YXJ0aW5nIHVwZGF0ZVxuIik7
Ci0KLQkJcmV0ID0gYWR0NzQxMF90ZW1wX3JlYWR5KGNsaWVudCk7IC8qIGNoZWNrIGZvciBuZXcg
dmFsdWUgKi8KLQkJaWYgKHJldCkKLQkJCWdvdG8gYWJvcnQ7Ci0KLQkJcmV0ID0gaTJjX3NtYnVz
X3JlYWRfd29yZF9zd2FwcGVkKGNsaWVudCwgQURUNzQxMF9SRUdfVEVNUFswXSk7Ci0JCWlmIChy
ZXQpIHsKLQkJCWRldl9kYmcoZGV2LCAiRmFpbGVkIHRvIHJlYWQgdmFsdWU6IHJlZyAlZCwgZXJy
b3IgJWRcbiIsCi0JCQkJQURUNzQxMF9SRUdfVEVNUFswXSwgcmV0KTsKLQkJCWdvdG8gYWJvcnQ7
Ci0JCX0KLQkJZGF0YS0+dGVtcFswXSA9IHJldDsKLQotCQlkYXRhLT5sYXN0X3VwZGF0ZWQgPSBq
aWZmaWVzOwotCQlkYXRhLT52YWxpZCA9IHRydWU7Ci0JfQotCi1hYm9ydDoKLQltdXRleF91bmxv
Y2soJmRhdGEtPnVwZGF0ZV9sb2NrKTsKLQlyZXR1cm4gcmV0OwotfQotCi1zdGF0aWMgaW50IGFk
dDc0MTBfZmlsbF9jYWNoZShzdHJ1Y3QgaTJjX2NsaWVudCAqY2xpZW50KQotewotCXN0cnVjdCBh
ZHQ3NDEwX2RhdGEgKmRhdGEgPSBpMmNfZ2V0X2NsaWVudGRhdGEoY2xpZW50KTsKLQlpbnQgcmV0
OwotCWludCBpOwotCi0JZm9yIChpID0gMTsgaSA8IDM7IGkrKykgewotCQlyZXQgPSBpMmNfc21i
dXNfcmVhZF93b3JkX3N3YXBwZWQoY2xpZW50LCBBRFQ3NDEwX1JFR19URU1QW2ldKTsKLQkJaWYg
KHJldCkgewotCQkJZGV2X2RiZygmY2xpZW50LT5kZXYsCi0JCQkJIkZhaWxlZCB0byByZWFkIHZh
bHVlOiByZWcgJWQsIGVycm9yICVkXG4iLAotCQkJCUFEVDc0MTBfUkVHX1RFTVBbMF0sIHJldCk7
Ci0JCQlyZXR1cm4gcmV0OwotCQl9Ci0JCWRhdGEtPnRlbXBbaV0gPSByZXQ7Ci0JfQotCi0JcmV0
ID0gaTJjX3NtYnVzX3JlYWRfYnl0ZV9kYXRhKGNsaWVudCwgQURUNzQxMF9UX0hZU1QpOwotCWlm
IChyZXQpIHsKLQkJZGV2X2RiZygmY2xpZW50LT5kZXYsCi0JCQkiRmFpbGVkIHRvIHJlYWQgdmFs
dWU6IGh5c3QgcmVnLCBlcnJvciAlZFxuIiwKLQkJCXJldCk7CisJcmV0ID0gaTJjX3NtYnVzX3Jl
YWRfd29yZF9zd2FwcGVkKGNsaWVudCwgcmVnKTsKKwlpZiAocmV0IDwgMCkgeworCQlkZXZfZXJy
KGRldiwgIkkyQyByZWFkIGVycm9yXG4iKTsKIAkJcmV0dXJuIHJldDsKIAl9Ci0JZGF0YS0+aHlz
dCA9IHJldDsKLQotCXJldHVybiAwOwotfQogCi1zdGF0aWMgczE2IEFEVDc0MTBfVEVNUF9UT19S
RUcobG9uZyB0ZW1wKQotewotCXJldHVybiBESVZfUk9VTkRfQ0xPU0VTVChjbGFtcF92YWwodGVt
cCwgQURUNzQxMF9URU1QX01JTiwKLQkJCQkJICAgQURUNzQxMF9URU1QX01BWCkgKiAxMjgsIDEw
MDApOwotfQorCSpkYXRhID0gcmV0OwogCi1zdGF0aWMgaW50IEFEVDc0MTBfUkVHX1RPX1RFTVAo
c3RydWN0IGFkdDc0MTBfZGF0YSAqZGF0YSwgczE2IHJlZykKLXsKLQkvKiBpbiAxMyBiaXQgbW9k
ZSwgYml0cyAwLTIgYXJlIHN0YXR1cyBmbGFncyAtIG1hc2sgdGhlbSBvdXQgKi8KLQlpZiAoIShk
YXRhLT5jb25maWcgJiBBRFQ3NDEwX1JFU09MVVRJT04pKQotCQlyZWcgJj0gQURUNzQxMF9UMTNf
VkFMVUVfTUFTSzsKLQkvKgotCSAqIHRlbXBlcmF0dXJlIGlzIHN0b3JlZCBpbiB0d29zIGNvbXBs
ZW1lbnQgZm9ybWF0LCBpbiBzdGVwcyBvZgotCSAqIDEvMTI4wrBDCi0JICovCi0JcmV0dXJuIERJ
Vl9ST1VORF9DTE9TRVNUKHJlZyAqIDEwMDAsIDEyOCk7CisJcmV0dXJuIDA7CiB9CiAKLS8qLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0qLwotCi0vKiBzeXNmcyBhdHRyaWJ1dGVzIGZvciBod21vbiAqLwotCi1zdGF0
aWMgc3NpemVfdCBhZHQ3NDEwX3Nob3dfdGVtcChzdHJ1Y3QgZGV2aWNlICpkZXYsCi0JCQkJIHN0
cnVjdCBkZXZpY2VfYXR0cmlidXRlICpkYSwgY2hhciAqYnVmKQorc3RhdGljIGludCBhZHQ3NDEw
X2kyY193cml0ZV93b3JkKHN0cnVjdCBkZXZpY2UgKmRldiwgdTggcmVnLCB1MTYgZGF0YSkKIHsK
LQlzdHJ1Y3Qgc2Vuc29yX2RldmljZV9hdHRyaWJ1dGUgKmF0dHIgPSB0b19zZW5zb3JfZGV2X2F0
dHIoZGEpOwogCXN0cnVjdCBpMmNfY2xpZW50ICpjbGllbnQgPSB0b19pMmNfY2xpZW50KGRldik7
Ci0Jc3RydWN0IGFkdDc0MTBfZGF0YSAqZGF0YSA9IGkyY19nZXRfY2xpZW50ZGF0YShjbGllbnQp
OwotCi0JaWYgKGF0dHItPmluZGV4ID09IDApIHsKLQkJaW50IHJldDsKKwlpbnQgcmV0ID0gMDsK
IAotCQlyZXQgPSBhZHQ3NDEwX3VwZGF0ZV90ZW1wKGRldik7Ci0JCWlmIChyZXQpCi0JCQlyZXR1
cm4gcmV0OwotCX0KKwlyZXQgPSBpMmNfc21idXNfd3JpdGVfd29yZF9zd2FwcGVkKGNsaWVudCwg
cmVnLCBkYXRhKTsKKwlpZiAocmV0IDwgMCkKKwkJZGV2X2VycihkZXYsICJJMkMgd3JpdGUgZXJy
b3JcbiIpOwogCi0JcmV0dXJuIHNwcmludGYoYnVmLCAiJWRcbiIsIEFEVDc0MTBfUkVHX1RPX1RF
TVAoZGF0YSwKLQkJICAgICAgIGRhdGEtPnRlbXBbYXR0ci0+aW5kZXhdKSk7CisJcmV0dXJuIHJl
dDsKIH0KIAotc3RhdGljIHNzaXplX3QgYWR0NzQxMF9zZXRfdGVtcChzdHJ1Y3QgZGV2aWNlICpk
ZXYsCi0JCQkJc3RydWN0IGRldmljZV9hdHRyaWJ1dGUgKmRhLAotCQkJCWNvbnN0IGNoYXIgKmJ1
Ziwgc2l6ZV90IGNvdW50KQorc3RhdGljIGludCBhZHQ3NDEwX2kyY19yZWFkX2J5dGUoc3RydWN0
IGRldmljZSAqZGV2LCB1OCByZWcsIHU4ICpkYXRhKQogewotCXN0cnVjdCBzZW5zb3JfZGV2aWNl
X2F0dHJpYnV0ZSAqYXR0ciA9IHRvX3NlbnNvcl9kZXZfYXR0cihkYSk7CiAJc3RydWN0IGkyY19j
bGllbnQgKmNsaWVudCA9IHRvX2kyY19jbGllbnQoZGV2KTsKLQlzdHJ1Y3QgYWR0NzQxMF9kYXRh
ICpkYXRhID0gaTJjX2dldF9jbGllbnRkYXRhKGNsaWVudCk7Ci0JaW50IG5yID0gYXR0ci0+aW5k
ZXg7Ci0JbG9uZyB0ZW1wOwotCWludCByZXQ7CisJaW50IHJldCA9IDA7CiAKLQlyZXQgPSBrc3Ry
dG9sKGJ1ZiwgMTAsICZ0ZW1wKTsKLQlpZiAocmV0KQorCXJldCA9IGkyY19zbWJ1c19yZWFkX2J5
dGVfZGF0YShjbGllbnQsIHJlZyk7CisJaWYgKHJldCA8IDApIHsKKwkJZGV2X2VycihkZXYsICJJ
MkMgcmVhZCBlcnJvclxuIik7CiAJCXJldHVybiByZXQ7CisJfQogCi0JbXV0ZXhfbG9jaygmZGF0
YS0+dXBkYXRlX2xvY2spOwotCWRhdGEtPnRlbXBbbnJdID0gQURUNzQxMF9URU1QX1RPX1JFRyh0
ZW1wKTsKLQlyZXQgPSBpMmNfc21idXNfd3JpdGVfd29yZF9zd2FwcGVkKGNsaWVudCwgQURUNzQx
MF9SRUdfVEVNUFtucl0sCi0JCQkJCSAgIGRhdGEtPnRlbXBbbnJdKTsKLQlpZiAocmV0KQotCQlj
b3VudCA9IHJldDsKLQltdXRleF91bmxvY2soJmRhdGEtPnVwZGF0ZV9sb2NrKTsKLQlyZXR1cm4g
Y291bnQ7Ci19Ci0KLXN0YXRpYyBzc2l6ZV90IGFkdDc0MTBfc2hvd190X2h5c3Qoc3RydWN0IGRl
dmljZSAqZGV2LAotCQkJCSAgIHN0cnVjdCBkZXZpY2VfYXR0cmlidXRlICpkYSwKLQkJCQkgICBj
aGFyICpidWYpCi17Ci0Jc3RydWN0IHNlbnNvcl9kZXZpY2VfYXR0cmlidXRlICphdHRyID0gdG9f
c2Vuc29yX2Rldl9hdHRyKGRhKTsKLQlzdHJ1Y3QgaTJjX2NsaWVudCAqY2xpZW50ID0gdG9faTJj
X2NsaWVudChkZXYpOwotCXN0cnVjdCBhZHQ3NDEwX2RhdGEgKmRhdGEgPSBpMmNfZ2V0X2NsaWVu
dGRhdGEoY2xpZW50KTsKLQlpbnQgbnIgPSBhdHRyLT5pbmRleDsKLQlpbnQgaHlzdDsKLQotCWh5
c3QgPSAoZGF0YS0+aHlzdCAmIEFEVDc0MTBfVF9IWVNUX01BU0spICogMTAwMDsKLQotCS8qCi0J
ICogaHlzdGVyZXNpcyBpcyBzdG9yZWQgYXMgYSA0IGJpdCBvZmZzZXQgaW4gdGhlIGRldmljZSwg
Y29udmVydCBpdAotCSAqIHRvIGFuIGFic29sdXRlIHZhbHVlCi0JICovCi0JaWYgKG5yID09IDIp
CS8qIG1pbiBoYXMgcG9zaXRpdmUgb2Zmc2V0LCBvdGhlcnMgaGF2ZSBuZWdhdGl2ZSAqLwotCQlo
eXN0ID0gLWh5c3Q7Ci0JcmV0dXJuIHNwcmludGYoYnVmLCAiJWRcbiIsCi0JCSAgICAgICBBRFQ3
NDEwX1JFR19UT19URU1QKGRhdGEsIGRhdGEtPnRlbXBbbnJdKSAtIGh5c3QpOwotfQotCi1zdGF0
aWMgc3NpemVfdCBhZHQ3NDEwX3NldF90X2h5c3Qoc3RydWN0IGRldmljZSAqZGV2LAotCQkJCSAg
c3RydWN0IGRldmljZV9hdHRyaWJ1dGUgKmRhLAotCQkJCSAgY29uc3QgY2hhciAqYnVmLCBzaXpl
X3QgY291bnQpCi17Ci0Jc3RydWN0IGkyY19jbGllbnQgKmNsaWVudCA9IHRvX2kyY19jbGllbnQo
ZGV2KTsKLQlzdHJ1Y3QgYWR0NzQxMF9kYXRhICpkYXRhID0gaTJjX2dldF9jbGllbnRkYXRhKGNs
aWVudCk7Ci0JaW50IGxpbWl0LCByZXQ7Ci0JbG9uZyBoeXN0OwotCi0JcmV0ID0ga3N0cnRvbChi
dWYsIDEwLCAmaHlzdCk7Ci0JaWYgKHJldCkKLQkJcmV0dXJuIHJldDsKLQkvKiBjb252ZXJ0IGFi
c29sdXRlIGh5c3RlcmVzaXMgdmFsdWUgdG8gYSA0IGJpdCBkZWx0YSB2YWx1ZSAqLwotCWxpbWl0
ID0gQURUNzQxMF9SRUdfVE9fVEVNUChkYXRhLCBkYXRhLT50ZW1wWzFdKTsKLQloeXN0ID0gY2xh
bXBfdmFsKGh5c3QsIEFEVDc0MTBfVEVNUF9NSU4sIEFEVDc0MTBfVEVNUF9NQVgpOwotCWRhdGEt
Pmh5c3QgPSBjbGFtcF92YWwoRElWX1JPVU5EX0NMT1NFU1QobGltaXQgLSBoeXN0LCAxMDAwKSwg
MCwKLQkJCSAgICAgICBBRFQ3NDEwX1RfSFlTVF9NQVNLKTsKLQlyZXQgPSBpMmNfc21idXNfd3Jp
dGVfYnl0ZV9kYXRhKGNsaWVudCwgQURUNzQxMF9UX0hZU1QsIGRhdGEtPmh5c3QpOwotCWlmIChy
ZXQpCi0JCXJldHVybiByZXQ7CisJKmRhdGEgPSAodTgpcmV0OwogCi0JcmV0dXJuIGNvdW50Owor
CXJldHVybiAwOwogfQogCi1zdGF0aWMgc3NpemVfdCBhZHQ3NDEwX3Nob3dfYWxhcm0oc3RydWN0
IGRldmljZSAqZGV2LAotCQkJCSAgc3RydWN0IGRldmljZV9hdHRyaWJ1dGUgKmRhLAotCQkJCSAg
Y2hhciAqYnVmKQorc3RhdGljIGludCBhZHQ3NDEwX2kyY193cml0ZV9ieXRlKHN0cnVjdCBkZXZp
Y2UgKmRldiwgdTggcmVnLCB1OCBkYXRhKQogewogCXN0cnVjdCBpMmNfY2xpZW50ICpjbGllbnQg
PSB0b19pMmNfY2xpZW50KGRldik7Ci0Jc3RydWN0IHNlbnNvcl9kZXZpY2VfYXR0cmlidXRlICph
dHRyID0gdG9fc2Vuc29yX2Rldl9hdHRyKGRhKTsKLQlpbnQgcmV0OworCWludCByZXQgPSAwOwog
Ci0JcmV0ID0gaTJjX3NtYnVzX3JlYWRfYnl0ZV9kYXRhKGNsaWVudCwgQURUNzQxMF9TVEFUVVMp
OworCXJldCA9IGkyY19zbWJ1c193cml0ZV9ieXRlX2RhdGEoY2xpZW50LCByZWcsIGRhdGEpOwog
CWlmIChyZXQgPCAwKQotCQlyZXR1cm4gcmV0OworCQlkZXZfZXJyKCZjbGllbnQtPmRldiwgIkky
QyB3cml0ZSBlcnJvclxuIik7CiAKLQlyZXR1cm4gc3ByaW50ZihidWYsICIlZFxuIiwgISEocmV0
ICYgYXR0ci0+aW5kZXgpKTsKKwlyZXR1cm4gcmV0OwogfQogCi1zdGF0aWMgU0VOU09SX0RFVklD
RV9BVFRSKHRlbXAxX2lucHV0LCBTX0lSVUdPLCBhZHQ3NDEwX3Nob3dfdGVtcCwgTlVMTCwgMCk7
Ci1zdGF0aWMgU0VOU09SX0RFVklDRV9BVFRSKHRlbXAxX21heCwgU19JV1VTUiB8IFNfSVJVR08s
Ci0JCQkgIGFkdDc0MTBfc2hvd190ZW1wLCBhZHQ3NDEwX3NldF90ZW1wLCAxKTsKLXN0YXRpYyBT
RU5TT1JfREVWSUNFX0FUVFIodGVtcDFfbWluLCBTX0lXVVNSIHwgU19JUlVHTywKLQkJCSAgYWR0
NzQxMF9zaG93X3RlbXAsIGFkdDc0MTBfc2V0X3RlbXAsIDIpOwotc3RhdGljIFNFTlNPUl9ERVZJ
Q0VfQVRUUih0ZW1wMV9jcml0LCBTX0lXVVNSIHwgU19JUlVHTywKLQkJCSAgYWR0NzQxMF9zaG93
X3RlbXAsIGFkdDc0MTBfc2V0X3RlbXAsIDMpOwotc3RhdGljIFNFTlNPUl9ERVZJQ0VfQVRUUih0
ZW1wMV9tYXhfaHlzdCwgU19JV1VTUiB8IFNfSVJVR08sCi0JCQkgIGFkdDc0MTBfc2hvd190X2h5
c3QsIGFkdDc0MTBfc2V0X3RfaHlzdCwgMSk7Ci1zdGF0aWMgU0VOU09SX0RFVklDRV9BVFRSKHRl
bXAxX21pbl9oeXN0LCBTX0lSVUdPLAotCQkJICBhZHQ3NDEwX3Nob3dfdF9oeXN0LCBOVUxMLCAy
KTsKLXN0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIodGVtcDFfY3JpdF9oeXN0LCBTX0lSVUdPLAot
CQkJICBhZHQ3NDEwX3Nob3dfdF9oeXN0LCBOVUxMLCAzKTsKLXN0YXRpYyBTRU5TT1JfREVWSUNF
X0FUVFIodGVtcDFfbWluX2FsYXJtLCBTX0lSVUdPLCBhZHQ3NDEwX3Nob3dfYWxhcm0sCi0JCQkg
IE5VTEwsIEFEVDc0MTBfU1RBVF9UX0xPVyk7Ci1zdGF0aWMgU0VOU09SX0RFVklDRV9BVFRSKHRl
bXAxX21heF9hbGFybSwgU19JUlVHTywgYWR0NzQxMF9zaG93X2FsYXJtLAotCQkJICBOVUxMLCBB
RFQ3NDEwX1NUQVRfVF9ISUdIKTsKLXN0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIodGVtcDFfY3Jp
dF9hbGFybSwgU19JUlVHTywgYWR0NzQxMF9zaG93X2FsYXJtLAotCQkJICBOVUxMLCBBRFQ3NDEw
X1NUQVRfVF9DUklUKTsKLQotc3RhdGljIHN0cnVjdCBhdHRyaWJ1dGUgKmFkdDc0MTBfYXR0cmli
dXRlc1tdID0gewotCSZzZW5zb3JfZGV2X2F0dHJfdGVtcDFfaW5wdXQuZGV2X2F0dHIuYXR0ciwK
LQkmc2Vuc29yX2Rldl9hdHRyX3RlbXAxX21heC5kZXZfYXR0ci5hdHRyLAotCSZzZW5zb3JfZGV2
X2F0dHJfdGVtcDFfbWluLmRldl9hdHRyLmF0dHIsCi0JJnNlbnNvcl9kZXZfYXR0cl90ZW1wMV9j
cml0LmRldl9hdHRyLmF0dHIsCi0JJnNlbnNvcl9kZXZfYXR0cl90ZW1wMV9tYXhfaHlzdC5kZXZf
YXR0ci5hdHRyLAotCSZzZW5zb3JfZGV2X2F0dHJfdGVtcDFfbWluX2h5c3QuZGV2X2F0dHIuYXR0
ciwKLQkmc2Vuc29yX2Rldl9hdHRyX3RlbXAxX2NyaXRfaHlzdC5kZXZfYXR0ci5hdHRyLAotCSZz
ZW5zb3JfZGV2X2F0dHJfdGVtcDFfbWluX2FsYXJtLmRldl9hdHRyLmF0dHIsCi0JJnNlbnNvcl9k
ZXZfYXR0cl90ZW1wMV9tYXhfYWxhcm0uZGV2X2F0dHIuYXR0ciwKLQkmc2Vuc29yX2Rldl9hdHRy
X3RlbXAxX2NyaXRfYWxhcm0uZGV2X2F0dHIuYXR0ciwKLQlOVUxMCi19OwotCi1zdGF0aWMgY29u
c3Qgc3RydWN0IGF0dHJpYnV0ZV9ncm91cCBhZHQ3NDEwX2dyb3VwID0gewotCS5hdHRycyA9IGFk
dDc0MTBfYXR0cmlidXRlcywKK3N0YXRpYyBjb25zdCBzdHJ1Y3QgYWR0NzQxMF9vcHMgYWR0NzQx
MF9pMmNfb3BzID0geworCS5yZWFkX3dvcmQgPSBhZHQ3NDEwX2kyY19yZWFkX3dvcmQsCisJLndy
aXRlX3dvcmQgPSBhZHQ3NDEwX2kyY193cml0ZV93b3JkLAorCS5yZWFkX2J5dGUgPSBhZHQ3NDEw
X2kyY19yZWFkX2J5dGUsCisJLndyaXRlX2J5dGUgPSBhZHQ3NDEwX2kyY193cml0ZV9ieXRlLAog
fTsKIAotLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovCi0KLS8qIGRldmljZSBwcm9iZSBhbmQgcmVtb3ZhbCAq
LwotCi1zdGF0aWMgaW50IGFkdDc0MTBfcHJvYmUoc3RydWN0IGkyY19jbGllbnQgKmNsaWVudCwK
LQkJCSBjb25zdCBzdHJ1Y3QgaTJjX2RldmljZV9pZCAqaWQpCitzdGF0aWMgaW50IGFkdDc0MTBf
aTJjX3Byb2JlKHN0cnVjdCBpMmNfY2xpZW50ICpjbGllbnQsCisJY29uc3Qgc3RydWN0IGkyY19k
ZXZpY2VfaWQgKmlkKQogewotCXN0cnVjdCBhZHQ3NDEwX2RhdGEgKmRhdGE7Ci0JaW50IHJldDsK
IAogCWlmICghaTJjX2NoZWNrX2Z1bmN0aW9uYWxpdHkoY2xpZW50LT5hZGFwdGVyLAogCQkJSTJD
X0ZVTkNfU01CVVNfQllURV9EQVRBIHwgSTJDX0ZVTkNfU01CVVNfV09SRF9EQVRBKSkKIAkJcmV0
dXJuIC1FTk9ERVY7CiAKLQlkYXRhID0gZGV2bV9remFsbG9jKCZjbGllbnQtPmRldiwgc2l6ZW9m
KHN0cnVjdCBhZHQ3NDEwX2RhdGEpLAotCQkJICAgIEdGUF9LRVJORUwpOwotCWlmICghZGF0YSkK
LQkJcmV0dXJuIC1FTk9NRU07Ci0KLQlpMmNfc2V0X2NsaWVudGRhdGEoY2xpZW50LCBkYXRhKTsK
LQltdXRleF9pbml0KCZkYXRhLT51cGRhdGVfbG9jayk7Ci0KLQkvKiBjb25maWd1cmUgYXMgc3Bl
Y2lmaWVkICovCi0JcmV0ID0gaTJjX3NtYnVzX3JlYWRfYnl0ZV9kYXRhKGNsaWVudCwgQURUNzQx
MF9DT05GSUcpOwotCWlmIChyZXQgPCAwKSB7Ci0JCWRldl9kYmcoJmNsaWVudC0+ZGV2LCAiQ2Fu
J3QgcmVhZCBjb25maWc/ICVkXG4iLCByZXQpOwotCQlyZXR1cm4gcmV0OwotCX0KLQlkYXRhLT5v
bGRjb25maWcgPSByZXQ7Ci0JLyoKLQkgKiBTZXQgdG8gMTYgYml0IHJlc29sdXRpb24sIGNvbnRp
bm91cyBjb252ZXJzaW9uIGFuZCBjb21wYXJhdG9yIG1vZGUuCi0JICovCi0JcmV0ICY9IH5BRFQ3
NDEwX01PREVfTUFTSzsKLQlkYXRhLT5jb25maWcgPSByZXQgfCBBRFQ3NDEwX0ZVTEwgfCBBRFQ3
NDEwX1JFU09MVVRJT04gfAotCQkJQURUNzQxMF9FVkVOVF9NT0RFOwotCWlmIChkYXRhLT5jb25m
aWcgIT0gZGF0YS0+b2xkY29uZmlnKSB7Ci0JCXJldCA9IGkyY19zbWJ1c193cml0ZV9ieXRlX2Rh
dGEoY2xpZW50LCBBRFQ3NDEwX0NPTkZJRywKLQkJCQkJCWRhdGEtPmNvbmZpZyk7Ci0JCWlmIChy
ZXQpCi0JCQlyZXR1cm4gcmV0OwotCX0KLQlkZXZfZGJnKCZjbGllbnQtPmRldiwgIkNvbmZpZyAl
MDJ4XG4iLCBkYXRhLT5jb25maWcpOwotCi0JcmV0ID0gYWR0NzQxMF9maWxsX2NhY2hlKGNsaWVu
dCk7Ci0JaWYgKHJldCkKLQkJZ290byBleGl0X3Jlc3RvcmU7Ci0KLQkvKiBSZWdpc3RlciBzeXNm
cyBob29rcyAqLwotCXJldCA9IHN5c2ZzX2NyZWF0ZV9ncm91cCgmY2xpZW50LT5kZXYua29iaiwg
JmFkdDc0MTBfZ3JvdXApOwotCWlmIChyZXQpCi0JCWdvdG8gZXhpdF9yZXN0b3JlOwotCi0JZGF0
YS0+aHdtb25fZGV2ID0gaHdtb25fZGV2aWNlX3JlZ2lzdGVyKCZjbGllbnQtPmRldik7Ci0JaWYg
KElTX0VSUihkYXRhLT5od21vbl9kZXYpKSB7Ci0JCXJldCA9IFBUUl9FUlIoZGF0YS0+aHdtb25f
ZGV2KTsKLQkJZ290byBleGl0X3JlbW92ZTsKLQl9Ci0KLQlkZXZfaW5mbygmY2xpZW50LT5kZXYs
ICJzZW5zb3IgJyVzJ1xuIiwgY2xpZW50LT5uYW1lKTsKLQotCXJldHVybiAwOwotCi1leGl0X3Jl
bW92ZToKLQlzeXNmc19yZW1vdmVfZ3JvdXAoJmNsaWVudC0+ZGV2LmtvYmosICZhZHQ3NDEwX2dy
b3VwKTsKLWV4aXRfcmVzdG9yZToKLQlpMmNfc21idXNfd3JpdGVfYnl0ZV9kYXRhKGNsaWVudCwg
QURUNzQxMF9DT05GSUcsIGRhdGEtPm9sZGNvbmZpZyk7Ci0JcmV0dXJuIHJldDsKKwlyZXR1cm4g
YWR0NzQxMF9wcm9iZSgmY2xpZW50LT5kZXYsIE5VTEwsICZhZHQ3NDEwX2kyY19vcHMpOwogfQog
Ci1zdGF0aWMgaW50IGFkdDc0MTBfcmVtb3ZlKHN0cnVjdCBpMmNfY2xpZW50ICpjbGllbnQpCitz
dGF0aWMgaW50IGFkdDc0MTBfaTJjX3JlbW92ZShzdHJ1Y3QgaTJjX2NsaWVudCAqY2xpZW50KQog
ewotCXN0cnVjdCBhZHQ3NDEwX2RhdGEgKmRhdGEgPSBpMmNfZ2V0X2NsaWVudGRhdGEoY2xpZW50
KTsKLQotCWh3bW9uX2RldmljZV91bnJlZ2lzdGVyKGRhdGEtPmh3bW9uX2Rldik7Ci0Jc3lzZnNf
cmVtb3ZlX2dyb3VwKCZjbGllbnQtPmRldi5rb2JqLCAmYWR0NzQxMF9ncm91cCk7Ci0JaWYgKGRh
dGEtPm9sZGNvbmZpZyAhPSBkYXRhLT5jb25maWcpCi0JCWkyY19zbWJ1c193cml0ZV9ieXRlX2Rh
dGEoY2xpZW50LCBBRFQ3NDEwX0NPTkZJRywKLQkJCQkJICBkYXRhLT5vbGRjb25maWcpOwotCXJl
dHVybiAwOworCXJldHVybiBhZHQ3NDEwX3JlbW92ZSgmY2xpZW50LT5kZXYpOwogfQogCi1zdGF0
aWMgY29uc3Qgc3RydWN0IGkyY19kZXZpY2VfaWQgYWR0NzQxMF9pZHNbXSA9IHsKLQl7ICJhZHQ3
NDEwIiwgYWR0NzQxMCwgfSwKLQl7ICJhZHQ3NDIwIiwgYWR0NzQxMCwgfSwKLQl7IC8qIExJU1Qg
RU5EICovIH0KK3N0YXRpYyBjb25zdCBzdHJ1Y3QgaTJjX2RldmljZV9pZCBhZHQ3NDEwX2lkW10g
PSB7CisJeyAiYWR0NzQxMCIsIDAgfSwKKwl7ICJhZHQ3NDIwIiwgMCB9LAorCXt9CiB9OwotTU9E
VUxFX0RFVklDRV9UQUJMRShpMmMsIGFkdDc0MTBfaWRzKTsKLQotI2lmZGVmIENPTkZJR19QTV9T
TEVFUAotc3RhdGljIGludCBhZHQ3NDEwX3N1c3BlbmQoc3RydWN0IGRldmljZSAqZGV2KQotewot
CWludCByZXQ7Ci0Jc3RydWN0IGkyY19jbGllbnQgKmNsaWVudCA9IHRvX2kyY19jbGllbnQoZGV2
KTsKLQlzdHJ1Y3QgYWR0NzQxMF9kYXRhICpkYXRhID0gaTJjX2dldF9jbGllbnRkYXRhKGNsaWVu
dCk7Ci0KLQlyZXQgPSBpMmNfc21idXNfd3JpdGVfYnl0ZV9kYXRhKGNsaWVudCwgQURUNzQxMF9D
T05GSUcsCi0JCQkJCWRhdGEtPmNvbmZpZyB8IEFEVDc0MTBfUEQpOwotCXJldHVybiByZXQ7Ci19
Ci0KLXN0YXRpYyBpbnQgYWR0NzQxMF9yZXN1bWUoc3RydWN0IGRldmljZSAqZGV2KQotewotCWlu
dCByZXQ7Ci0Jc3RydWN0IGkyY19jbGllbnQgKmNsaWVudCA9IHRvX2kyY19jbGllbnQoZGV2KTsK
LQlzdHJ1Y3QgYWR0NzQxMF9kYXRhICpkYXRhID0gaTJjX2dldF9jbGllbnRkYXRhKGNsaWVudCk7
Ci0KLQlyZXQgPSBpMmNfc21idXNfd3JpdGVfYnl0ZV9kYXRhKGNsaWVudCwgQURUNzQxMF9DT05G
SUcsIGRhdGEtPmNvbmZpZyk7Ci0JcmV0dXJuIHJldDsKLX0KLQotc3RhdGljIFNJTVBMRV9ERVZf
UE1fT1BTKGFkdDc0MTBfZGV2X3BtX29wcywgYWR0NzQxMF9zdXNwZW5kLCBhZHQ3NDEwX3Jlc3Vt
ZSk7Ci0KLSNkZWZpbmUgQURUNzQxMF9ERVZfUE1fT1BTICgmYWR0NzQxMF9kZXZfcG1fb3BzKQot
I2Vsc2UKLSNkZWZpbmUgQURUNzQxMF9ERVZfUE1fT1BTIE5VTEwKLSNlbmRpZiAvKiBDT05GSUdf
UE0gKi8KK01PRFVMRV9ERVZJQ0VfVEFCTEUoaTJjLCBhZHQ3NDEwX2lkKTsKIAogc3RhdGljIHN0
cnVjdCBpMmNfZHJpdmVyIGFkdDc0MTBfZHJpdmVyID0gewotCS5jbGFzcwkJPSBJMkNfQ0xBU1Nf
SFdNT04sCiAJLmRyaXZlciA9IHsKLQkJLm5hbWUJPSAiYWR0NzQxMCIsCisJCS5uYW1lID0gImFk
dDc0MTAiLAogCQkucG0JPSBBRFQ3NDEwX0RFVl9QTV9PUFMsCiAJfSwKLQkucHJvYmUJCT0gYWR0
NzQxMF9wcm9iZSwKLQkucmVtb3ZlCQk9IGFkdDc0MTBfcmVtb3ZlLAotCS5pZF90YWJsZQk9IGFk
dDc0MTBfaWRzLAotCS5hZGRyZXNzX2xpc3QJPSBJMkNfQUREUlMoMHg0OCwgMHg0OSwgMHg0YSwg
MHg0YiksCisJLnByb2JlID0gYWR0NzQxMF9pMmNfcHJvYmUsCisJLnJlbW92ZSA9IGFkdDc0MTBf
aTJjX3JlbW92ZSwKKwkuaWRfdGFibGUgPSBhZHQ3NDEwX2lkLAorCS5hZGRyZXNzX2xpc3QgPSBJ
MkNfQUREUlMoMHg0OCwgMHg0OSwgMHg0YSwgMHg0YiksCisJLmNsYXNzID0gSTJDX0NMQVNTX0hX
TU9OLAogfTsKLQogbW9kdWxlX2kyY19kcml2ZXIoYWR0NzQxMF9kcml2ZXIpOwogCi1NT0RVTEVf
QVVUSE9SKCJIYXJ0bXV0IEtuYWFjayIpOwotTU9EVUxFX0RFU0NSSVBUSU9OKCJBRFQ3NDEwL0FE
VDc0MjAgZHJpdmVyIik7CitNT0RVTEVfQVVUSE9SKCJMYXJzLVBldGVyIENsYXVzZW4gPGxhcnNA
bWV0YWZvby5kZT4iKTsKK01PRFVMRV9ERVNDUklQVElPTigiQURUNzQxMC9BRDc0MjAgZHJpdmVy
Iik7CiBNT0RVTEVfTElDRU5TRSgiR1BMIik7CmRpZmYgLS1naXQgYS9kcml2ZXJzL2h3bW9uL2Fk
dDd4MTAuYyBiL2RyaXZlcnMvaHdtb24vYWR0N3gxMC5jCm5ldyBmaWxlIG1vZGUgMTAwNjQ0Cmlu
ZGV4IDAwMDAwMDAuLjI1OThhYWYKLS0tIC9kZXYvbnVsbAorKysgYi9kcml2ZXJzL2h3bW9uL2Fk
dDd4MTAuYwpAQCAtMCwwICsxLDQ3NiBAQAorLyoKKyAqIGFkdDc0MTAuYyAtIFBhcnQgb2YgbG1f
c2Vuc29ycywgTGludXgga2VybmVsIG1vZHVsZXMgZm9yIGhhcmR3YXJlCisgKgkgbW9uaXRvcmlu
ZworICogVGhpcyBkcml2ZXIgaGFuZGxlcyB0aGUgQURUNzQxMCBhbmQgY29tcGF0aWJsZSBkaWdp
dGFsIHRlbXBlcmF0dXJlIHNlbnNvcnMuCisgKiBIYXJ0bXV0IEtuYWFjayA8a25hYWNrLmhAZ214
LmRlPiAyMDEyLTA3LTIyCisgKiBiYXNlZCBvbiBsbTc1LmMgYnkgRnJvZG8gTG9vaWphYXJkIDxm
cm9kb2xAZGRzLm5sPgorICogYW5kIGFkdDc0MTAuYyBmcm9tIGlpby1zdGFnaW5nIGJ5IFNvbmlj
IFpoYW5nIDxzb25pYy56aGFuZ0BhbmFsb2cuY29tPgorICoKKyAqIFRoaXMgcHJvZ3JhbSBpcyBm
cmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5CisgKiBp
dCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1
Ymxpc2hlZCBieQorICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyIHZlcnNp
b24gMiBvZiB0aGUgTGljZW5zZSwgb3IKKyAqIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZl
cnNpb24uCisgKgorICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRo
YXQgaXQgd2lsbCBiZSB1c2VmdWwsCisgKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhv
dXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZgorICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJ
VE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZQorICogR05VIEdlbmVyYWwg
UHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy4KKyAqCisgKiBZb3Ugc2hvdWxkIGhhdmUg
cmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZQorICogYWxv
bmcgd2l0aCB0aGlzIHByb2dyYW07IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmUK
KyAqIEZvdW5kYXRpb24sIEluYy4sIDY3NSBNYXNzIEF2ZSwgQ2FtYnJpZGdlLCBNQSAwMjEzOSwg
VVNBLgorICovCisKKyNpbmNsdWRlIDxsaW51eC9tb2R1bGUuaD4KKyNpbmNsdWRlIDxsaW51eC9p
bml0Lmg+CisjaW5jbHVkZSA8bGludXgvc2xhYi5oPgorI2luY2x1ZGUgPGxpbnV4L2ppZmZpZXMu
aD4KKyNpbmNsdWRlIDxsaW51eC9od21vbi5oPgorI2luY2x1ZGUgPGxpbnV4L2h3bW9uLXN5c2Zz
Lmg+CisjaW5jbHVkZSA8bGludXgvZXJyLmg+CisjaW5jbHVkZSA8bGludXgvbXV0ZXguaD4KKyNp
bmNsdWRlIDxsaW51eC9kZWxheS5oPgorCisjaW5jbHVkZSAiYWR0N3gxMC5oIgorCisvKgorICog
QURUNzQxMCBzdGF0dXMKKyAqLworI2RlZmluZSBBRFQ3NDEwX1NUQVRfVF9MT1cJCSgxIDw8IDQp
CisjZGVmaW5lIEFEVDc0MTBfU1RBVF9UX0hJR0gJCSgxIDw8IDUpCisjZGVmaW5lIEFEVDc0MTBf
U1RBVF9UX0NSSVQJCSgxIDw8IDYpCisjZGVmaW5lIEFEVDc0MTBfU1RBVF9OT1RfUkRZCQkoMSA8
PCA3KQorCisvKgorICogQURUNzQxMCBjb25maWcKKyAqLworI2RlZmluZSBBRFQ3NDEwX0ZBVUxU
X1FVRVVFX01BU0sJKDEgPDwgMCB8IDEgPDwgMSkKKyNkZWZpbmUgQURUNzQxMF9DVF9QT0xBUklU
WQkJKDEgPDwgMikKKyNkZWZpbmUgQURUNzQxMF9JTlRfUE9MQVJJVFkJCSgxIDw8IDMpCisjZGVm
aW5lIEFEVDc0MTBfRVZFTlRfTU9ERQkJKDEgPDwgNCkKKyNkZWZpbmUgQURUNzQxMF9NT0RFX01B
U0sJCSgxIDw8IDUgfCAxIDw8IDYpCisjZGVmaW5lIEFEVDc0MTBfRlVMTAkJCSgwIDw8IDUgfCAw
IDw8IDYpCisjZGVmaW5lIEFEVDc0MTBfUEQJCQkoMSA8PCA1IHwgMSA8PCA2KQorI2RlZmluZSBB
RFQ3NDEwX1JFU09MVVRJT04JCSgxIDw8IDcpCisKKy8qCisgKiBBRFQ3NDEwIG1hc2tzCisgKi8K
KyNkZWZpbmUgQURUNzQxMF9UMTNfVkFMVUVfTUFTSwkJCTB4RkZGOAorI2RlZmluZSBBRFQ3NDEw
X1RfSFlTVF9NQVNLCQkJMHhGCisKKy8qIHN0cmFpZ2h0IGZyb20gdGhlIGRhdGFzaGVldCAqLwor
I2RlZmluZSBBRFQ3NDEwX1RFTVBfTUlOICgtNTUwMDApCisjZGVmaW5lIEFEVDc0MTBfVEVNUF9N
QVggMTUwMDAwCisKKy8qIEVhY2ggY2xpZW50IGhhcyB0aGlzIGFkZGl0aW9uYWwgZGF0YSAqLwor
c3RydWN0IGFkdDc0MTBfZGF0YSB7CisJY29uc3Qgc3RydWN0IGFkdDc0MTBfb3BzICpvcHM7CisJ
Y29uc3QgY2hhcgkJKm5hbWU7CisJc3RydWN0IGRldmljZQkJKmh3bW9uX2RldjsKKwlzdHJ1Y3Qg
bXV0ZXgJCXVwZGF0ZV9sb2NrOworCXU4CQkJY29uZmlnOworCXU4CQkJb2xkY29uZmlnOworCWJv
b2wJCQl2YWxpZDsJCS8qIHRydWUgaWYgcmVnaXN0ZXJzIHZhbGlkICovCisJdW5zaWduZWQgbG9u
ZwkJbGFzdF91cGRhdGVkOwkvKiBJbiBqaWZmaWVzICovCisJczE2CQkJdGVtcFs0XTsJLyogUmVn
aXN0ZXIgdmFsdWVzLAorCQkJCQkJICAgMCA9IGlucHV0CisJCQkJCQkgICAxID0gaGlnaAorCQkJ
CQkJICAgMiA9IGxvdworCQkJCQkJICAgMyA9IGNyaXRpY2FsICovCisJdTgJCQloeXN0OwkJLyog
aHlzdGVyZXNpcyBvZmZzZXQgKi8KK307CisKK3N0YXRpYyBpbnQgYWR0NzQxMF9yZWFkX3dvcmQo
c3RydWN0IGRldmljZSAqZGV2LCB1OCByZWcsIHUxNiAqZGF0YSkKK3sKKwlzdHJ1Y3QgYWR0NzQx
MF9kYXRhICpkID0gZGV2X2dldF9kcnZkYXRhKGRldik7CisJcmV0dXJuIGQtPm9wcy0+cmVhZF93
b3JkKGRldiwgcmVnLCBkYXRhKTsKK30KKworc3RhdGljIGludCBhZHQ3NDEwX3dyaXRlX3dvcmQo
c3RydWN0IGRldmljZSAqZGV2LCB1OCByZWcsIHUxNiBkYXRhKQoreworCXN0cnVjdCBhZHQ3NDEw
X2RhdGEgKmQgPSBkZXZfZ2V0X2RydmRhdGEoZGV2KTsKKwlyZXR1cm4gZC0+b3BzLT53cml0ZV93
b3JkKGRldiwgcmVnLCBkYXRhKTsKK30KKworc3RhdGljIGludCBhZHQ3NDEwX3JlYWRfYnl0ZShz
dHJ1Y3QgZGV2aWNlICpkZXYsIHU4IHJlZywgdTggKmRhdGEpCit7CisJc3RydWN0IGFkdDc0MTBf
ZGF0YSAqZCA9IGRldl9nZXRfZHJ2ZGF0YShkZXYpOworCXJldHVybiBkLT5vcHMtPnJlYWRfYnl0
ZShkZXYsIHJlZywgZGF0YSk7Cit9CisKK3N0YXRpYyBpbnQgYWR0NzQxMF93cml0ZV9ieXRlKHN0
cnVjdCBkZXZpY2UgKmRldiwgdTggcmVnLCB1OCBkYXRhKQoreworCXN0cnVjdCBhZHQ3NDEwX2Rh
dGEgKmQgPSBkZXZfZ2V0X2RydmRhdGEoZGV2KTsKKwlyZXR1cm4gZC0+b3BzLT53cml0ZV9ieXRl
KGRldiwgcmVnLCBkYXRhKTsKK30KKworc3RhdGljIGNvbnN0IHU4IEFEVDc0MTBfUkVHX1RFTVBb
NF0gPSB7CisJQURUNzQxMF9URU1QRVJBVFVSRSwJCS8qIGlucHV0ICovCisJQURUNzQxMF9UX0FM
QVJNX0hJR0gsCQkvKiBoaWdoICovCisJQURUNzQxMF9UX0FMQVJNX0xPVywJCS8qIGxvdyAqLwor
CUFEVDc0MTBfVF9DUklULAkJCS8qIGNyaXRpY2FsICovCit9OworCisvKgorICogYWR0NzQxMCBy
ZWdpc3RlciBhY2Nlc3MgYnkgSTJDCisgKi8KK3N0YXRpYyBpbnQgYWR0NzQxMF90ZW1wX3JlYWR5
KHN0cnVjdCBkZXZpY2UgKmRldikKK3sKKwlpbnQgaSwgcmV0OworCXU4IHN0YXR1czsKKworCWZv
ciAoaSA9IDA7IGkgPCA2OyBpKyspIHsKKwkJcmV0ID0gYWR0NzQxMF9yZWFkX2J5dGUoZGV2LCBB
RFQ3NDEwX1NUQVRVUywgJnN0YXR1cyk7CisJCWlmIChyZXQpCisJCQlyZXR1cm4gcmV0OworCQlp
ZiAoIShzdGF0dXMgJiBBRFQ3NDEwX1NUQVRfTk9UX1JEWSkpCisJCQlyZXR1cm4gMDsKKwkJbXNs
ZWVwKDYwKTsKKwl9CisJcmV0dXJuIC1FVElNRURPVVQ7Cit9CisKK3N0YXRpYyBpbnQgYWR0NzQx
MF91cGRhdGVfdGVtcChzdHJ1Y3QgZGV2aWNlICpkZXYpCit7CisJc3RydWN0IGFkdDc0MTBfZGF0
YSAqZGF0YSA9IGRldl9nZXRfZHJ2ZGF0YShkZXYpOworCWludCByZXQgPSAwOworCisJbXV0ZXhf
bG9jaygmZGF0YS0+dXBkYXRlX2xvY2spOworCisJaWYgKHRpbWVfYWZ0ZXIoamlmZmllcywgZGF0
YS0+bGFzdF91cGRhdGVkICsgSFogKyBIWiAvIDIpCisJICAgIHx8ICFkYXRhLT52YWxpZCkgewor
CisJCWRldl9kYmcoZGV2LCAiU3RhcnRpbmcgdXBkYXRlXG4iKTsKKworCQlyZXQgPSBhZHQ3NDEw
X3RlbXBfcmVhZHkoZGV2KTsgLyogY2hlY2sgZm9yIG5ldyB2YWx1ZSAqLworCQlpZiAocmV0KQor
CQkJZ290byBhYm9ydDsKKworCQlyZXQgPSBhZHQ3NDEwX3JlYWRfd29yZChkZXYsIEFEVDc0MTBf
UkVHX1RFTVBbMF0sCisJCQkJCSZkYXRhLT50ZW1wWzBdKTsKKwkJaWYgKHJldCkgeworCQkJZGV2
X2RiZyhkZXYsICJGYWlsZWQgdG8gcmVhZCB2YWx1ZTogcmVnICVkLCBlcnJvciAlZFxuIiwKKwkJ
CQlBRFQ3NDEwX1JFR19URU1QWzBdLCByZXQpOworCQkJZ290byBhYm9ydDsKKwkJfQorCQlkYXRh
LT5sYXN0X3VwZGF0ZWQgPSBqaWZmaWVzOworCQlkYXRhLT52YWxpZCA9IHRydWU7CisJfQorCith
Ym9ydDoKKwltdXRleF91bmxvY2soJmRhdGEtPnVwZGF0ZV9sb2NrKTsKKwlyZXR1cm4gcmV0Owor
fQorCitzdGF0aWMgaW50IGFkdDc0MTBfZmlsbF9jYWNoZShzdHJ1Y3QgZGV2aWNlICpkZXYpCit7
CisJc3RydWN0IGFkdDc0MTBfZGF0YSAqZGF0YSA9IGRldl9nZXRfZHJ2ZGF0YShkZXYpOworCWlu
dCByZXQ7CisJaW50IGk7CisKKwlmb3IgKGkgPSAxOyBpIDwgQVJSQVlfU0laRShkYXRhLT50ZW1w
KTsgaSsrKSB7CisJCXJldCA9IGFkdDc0MTBfcmVhZF93b3JkKGRldiwgQURUNzQxMF9SRUdfVEVN
UFtpXSwKKwkJCQkJJmRhdGEtPnRlbXBbaV0pOworCQlpZiAocmV0KSB7CisJCQlkZXZfZGJnKGRl
diwgIkZhaWxlZCB0byByZWFkIHZhbHVlOiByZWcgJWQsIGVycm9yICVkXG4iLAorCQkJCUFEVDc0
MTBfUkVHX1RFTVBbMF0sIHJldCk7CisJCQlyZXR1cm4gcmV0OworCQl9CisJfQorCisJcmV0ID0g
YWR0NzQxMF9yZWFkX2J5dGUoZGV2LCBBRFQ3NDEwX1RfSFlTVCwgJmRhdGEtPmh5c3QpOworCWlm
IChyZXQpIHsKKwkJZGV2X2RiZyhkZXYsICJGYWlsZWQgdG8gcmVhZCB2YWx1ZTogcmVnICVkLCBl
cnJvciAlZFxuIiwKKwkJCQlBRFQ3NDEwX1RfSFlTVCwgcmV0KTsKKwkJcmV0dXJuIHJldDsKKwl9
CisKKwlyZXR1cm4gMDsKK30KKworc3RhdGljIHMxNiBBRFQ3NDEwX1RFTVBfVE9fUkVHKGxvbmcg
dGVtcCkKK3sKKwlyZXR1cm4gRElWX1JPVU5EX0NMT1NFU1QoY2xhbXBfdmFsKHRlbXAsIEFEVDc0
MTBfVEVNUF9NSU4sCisJCQkJCSAgICAgICBBRFQ3NDEwX1RFTVBfTUFYKSAqIDEyOCwgMTAwMCk7
Cit9CisKK3N0YXRpYyBpbnQgQURUNzQxMF9SRUdfVE9fVEVNUChzdHJ1Y3QgYWR0NzQxMF9kYXRh
ICpkYXRhLCBzMTYgcmVnKQoreworCS8qIGluIDEzIGJpdCBtb2RlLCBiaXRzIDAtMiBhcmUgc3Rh
dHVzIGZsYWdzIC0gbWFzayB0aGVtIG91dCAqLworCWlmICghKGRhdGEtPmNvbmZpZyAmIEFEVDc0
MTBfUkVTT0xVVElPTikpCisJCXJlZyAmPSBBRFQ3NDEwX1QxM19WQUxVRV9NQVNLOworCS8qCisJ
ICogdGVtcGVyYXR1cmUgaXMgc3RvcmVkIGluIHR3b3MgY29tcGxlbWVudCBmb3JtYXQsIGluIHN0
ZXBzIG9mCisJICogMS8xMjjCsEMKKwkgKi8KKwlyZXR1cm4gRElWX1JPVU5EX0NMT1NFU1QocmVn
ICogMTAwMCwgMTI4KTsKK30KKworLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovCisKKy8qIHN5c2ZzIGF0dHJp
YnV0ZXMgZm9yIGh3bW9uICovCisKK3N0YXRpYyBzc2l6ZV90IGFkdDc0MTBfc2hvd190ZW1wKHN0
cnVjdCBkZXZpY2UgKmRldiwKKwkJCQkgc3RydWN0IGRldmljZV9hdHRyaWJ1dGUgKmRhLCBjaGFy
ICpidWYpCit7CisJc3RydWN0IHNlbnNvcl9kZXZpY2VfYXR0cmlidXRlICphdHRyID0gdG9fc2Vu
c29yX2Rldl9hdHRyKGRhKTsKKwlzdHJ1Y3QgYWR0NzQxMF9kYXRhICpkYXRhID0gZGV2X2dldF9k
cnZkYXRhKGRldik7CisKKworCWlmIChhdHRyLT5pbmRleCA9PSAwKSB7CisJCWludCByZXQ7CisK
KwkJcmV0ID0gYWR0NzQxMF91cGRhdGVfdGVtcChkZXYpOworCQlpZiAocmV0KQorCQkJcmV0dXJu
IHJldDsKKwl9CisKKwlyZXR1cm4gc3ByaW50ZihidWYsICIlZFxuIiwgQURUNzQxMF9SRUdfVE9f
VEVNUChkYXRhLAorCQkgICAgICAgZGF0YS0+dGVtcFthdHRyLT5pbmRleF0pKTsKK30KKworc3Rh
dGljIHNzaXplX3QgYWR0NzQxMF9zZXRfdGVtcChzdHJ1Y3QgZGV2aWNlICpkZXYsCisJCQkJc3Ry
dWN0IGRldmljZV9hdHRyaWJ1dGUgKmRhLAorCQkJCWNvbnN0IGNoYXIgKmJ1Ziwgc2l6ZV90IGNv
dW50KQoreworCXN0cnVjdCBzZW5zb3JfZGV2aWNlX2F0dHJpYnV0ZSAqYXR0ciA9IHRvX3NlbnNv
cl9kZXZfYXR0cihkYSk7CisJc3RydWN0IGFkdDc0MTBfZGF0YSAqZGF0YSA9IGRldl9nZXRfZHJ2
ZGF0YShkZXYpOworCWludCBuciA9IGF0dHItPmluZGV4OworCWxvbmcgdGVtcDsKKwlpbnQgcmV0
OworCisJcmV0ID0ga3N0cnRvbChidWYsIDEwLCAmdGVtcCk7CisJaWYgKHJldCkKKwkJcmV0dXJu
IHJldDsKKworCW11dGV4X2xvY2soJmRhdGEtPnVwZGF0ZV9sb2NrKTsKKwlkYXRhLT50ZW1wW25y
XSA9IEFEVDc0MTBfVEVNUF9UT19SRUcodGVtcCk7CisJcmV0ID0gYWR0NzQxMF93cml0ZV93b3Jk
KGRldiwgQURUNzQxMF9SRUdfVEVNUFtucl0sIGRhdGEtPnRlbXBbbnJdKTsKKwlpZiAocmV0KQor
CQljb3VudCA9IHJldDsKKwltdXRleF91bmxvY2soJmRhdGEtPnVwZGF0ZV9sb2NrKTsKKwlyZXR1
cm4gY291bnQ7Cit9CisKK3N0YXRpYyBzc2l6ZV90IGFkdDc0MTBfc2hvd190X2h5c3Qoc3RydWN0
IGRldmljZSAqZGV2LAorCQkJCSAgIHN0cnVjdCBkZXZpY2VfYXR0cmlidXRlICpkYSwKKwkJCQkg
ICBjaGFyICpidWYpCit7CisJc3RydWN0IHNlbnNvcl9kZXZpY2VfYXR0cmlidXRlICphdHRyID0g
dG9fc2Vuc29yX2Rldl9hdHRyKGRhKTsKKwlzdHJ1Y3QgYWR0NzQxMF9kYXRhICpkYXRhID0gZGV2
X2dldF9kcnZkYXRhKGRldik7CisJaW50IG5yID0gYXR0ci0+aW5kZXg7CisJaW50IGh5c3Q7CisK
KwloeXN0ID0gKGRhdGEtPmh5c3QgJiBBRFQ3NDEwX1RfSFlTVF9NQVNLKSAqIDEwMDA7CisKKwkv
KgorCSAqIGh5c3RlcmVzaXMgaXMgc3RvcmVkIGFzIGEgNCBiaXQgb2Zmc2V0IGluIHRoZSBkZXZp
Y2UsIGNvbnZlcnQgaXQKKwkgKiB0byBhbiBhYnNvbHV0ZSB2YWx1ZQorCSAqLworCWlmIChuciA9
PSAyKQkvKiBtaW4gaGFzIHBvc2l0aXZlIG9mZnNldCwgb3RoZXJzIGhhdmUgbmVnYXRpdmUgKi8K
KwkJaHlzdCA9IC1oeXN0OworCXJldHVybiBzcHJpbnRmKGJ1ZiwgIiVkXG4iLAorCQkgICAgICAg
QURUNzQxMF9SRUdfVE9fVEVNUChkYXRhLCBkYXRhLT50ZW1wW25yXSkgLSBoeXN0KTsKK30KKwor
c3RhdGljIHNzaXplX3QgYWR0NzQxMF9zZXRfdF9oeXN0KHN0cnVjdCBkZXZpY2UgKmRldiwKKwkJ
CQkgIHN0cnVjdCBkZXZpY2VfYXR0cmlidXRlICpkYSwKKwkJCQkgIGNvbnN0IGNoYXIgKmJ1Ziwg
c2l6ZV90IGNvdW50KQoreworCXN0cnVjdCBhZHQ3NDEwX2RhdGEgKmRhdGEgPSBkZXZfZ2V0X2Ry
dmRhdGEoZGV2KTsKKwlpbnQgbGltaXQsIHJldDsKKwlsb25nIGh5c3Q7CisKKwlyZXQgPSBrc3Ry
dG9sKGJ1ZiwgMTAsICZoeXN0KTsKKwlpZiAocmV0KQorCQlyZXR1cm4gcmV0OworCS8qIGNvbnZl
cnQgYWJzb2x1dGUgaHlzdGVyZXNpcyB2YWx1ZSB0byBhIDQgYml0IGRlbHRhIHZhbHVlICovCisJ
bGltaXQgPSBBRFQ3NDEwX1JFR19UT19URU1QKGRhdGEsIGRhdGEtPnRlbXBbMV0pOworCWh5c3Qg
PSBjbGFtcF92YWwoaHlzdCwgQURUNzQxMF9URU1QX01JTiwgQURUNzQxMF9URU1QX01BWCk7CisJ
ZGF0YS0+aHlzdCA9IGNsYW1wX3ZhbChESVZfUk9VTkRfQ0xPU0VTVChsaW1pdCAtIGh5c3QsIDEw
MDApLAorCQkJCSAgIDAsIEFEVDc0MTBfVF9IWVNUX01BU0spOworCXJldCA9IGFkdDc0MTBfd3Jp
dGVfYnl0ZShkZXYsIEFEVDc0MTBfVF9IWVNULCBkYXRhLT5oeXN0KTsKKwlpZiAocmV0KQorCQly
ZXR1cm4gcmV0OworCisJcmV0dXJuIGNvdW50OworfQorCitzdGF0aWMgc3NpemVfdCBhZHQ3NDEw
X3Nob3dfYWxhcm0oc3RydWN0IGRldmljZSAqZGV2LAorCQkJCSAgc3RydWN0IGRldmljZV9hdHRy
aWJ1dGUgKmRhLAorCQkJCSAgY2hhciAqYnVmKQoreworCXN0cnVjdCBzZW5zb3JfZGV2aWNlX2F0
dHJpYnV0ZSAqYXR0ciA9IHRvX3NlbnNvcl9kZXZfYXR0cihkYSk7CisJdTggc3RhdHVzOworCWlu
dCByZXQ7CisKKwlyZXQgPSBhZHQ3NDEwX3JlYWRfYnl0ZShkZXYsIEFEVDc0MTBfU1RBVFVTLCAm
c3RhdHVzKTsKKwlpZiAocmV0IDwgMCkKKwkJcmV0dXJuIHJldDsKKworCXJldHVybiBzcHJpbnRm
KGJ1ZiwgIiVkXG4iLCAhIShzdGF0dXMgJiBhdHRyLT5pbmRleCkpOworfQorCitzdGF0aWMgc3Np
emVfdCBhZHQ3NDEwX3Nob3dfbmFtZShzdHJ1Y3QgZGV2aWNlICpkZXYsCisJCQkJICBzdHJ1Y3Qg
ZGV2aWNlX2F0dHJpYnV0ZSAqZGEsIGNoYXIgKmJ1ZikKK3sKKwlzdHJ1Y3QgYWR0NzQxMF9kYXRh
ICpkYXRhID0gZGV2X2dldF9kcnZkYXRhKGRldik7CisKKwlyZXR1cm4gc3ByaW50ZihidWYsICIl
c1xuIiwgZGF0YS0+bmFtZSk7Cit9CisKK3N0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIodGVtcDFf
aW5wdXQsIFNfSVJVR08sIGFkdDc0MTBfc2hvd190ZW1wLCBOVUxMLCAwKTsKK3N0YXRpYyBTRU5T
T1JfREVWSUNFX0FUVFIodGVtcDFfbWF4LCBTX0lXVVNSIHwgU19JUlVHTywKKwkJCSAgYWR0NzQx
MF9zaG93X3RlbXAsIGFkdDc0MTBfc2V0X3RlbXAsIDEpOworc3RhdGljIFNFTlNPUl9ERVZJQ0Vf
QVRUUih0ZW1wMV9taW4sIFNfSVdVU1IgfCBTX0lSVUdPLAorCQkJICBhZHQ3NDEwX3Nob3dfdGVt
cCwgYWR0NzQxMF9zZXRfdGVtcCwgMik7CitzdGF0aWMgU0VOU09SX0RFVklDRV9BVFRSKHRlbXAx
X2NyaXQsIFNfSVdVU1IgfCBTX0lSVUdPLAorCQkJICBhZHQ3NDEwX3Nob3dfdGVtcCwgYWR0NzQx
MF9zZXRfdGVtcCwgMyk7CitzdGF0aWMgU0VOU09SX0RFVklDRV9BVFRSKHRlbXAxX21heF9oeXN0
LCBTX0lXVVNSIHwgU19JUlVHTywKKwkJCSAgYWR0NzQxMF9zaG93X3RfaHlzdCwgYWR0NzQxMF9z
ZXRfdF9oeXN0LCAxKTsKK3N0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIodGVtcDFfbWluX2h5c3Qs
IFNfSVJVR08sCisJCQkgIGFkdDc0MTBfc2hvd190X2h5c3QsIE5VTEwsIDIpOworc3RhdGljIFNF
TlNPUl9ERVZJQ0VfQVRUUih0ZW1wMV9jcml0X2h5c3QsIFNfSVJVR08sCisJCQkgIGFkdDc0MTBf
c2hvd190X2h5c3QsIE5VTEwsIDMpOworc3RhdGljIFNFTlNPUl9ERVZJQ0VfQVRUUih0ZW1wMV9t
aW5fYWxhcm0sIFNfSVJVR08sIGFkdDc0MTBfc2hvd19hbGFybSwKKwkJCSAgTlVMTCwgQURUNzQx
MF9TVEFUX1RfTE9XKTsKK3N0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIodGVtcDFfbWF4X2FsYXJt
LCBTX0lSVUdPLCBhZHQ3NDEwX3Nob3dfYWxhcm0sCisJCQkgIE5VTEwsIEFEVDc0MTBfU1RBVF9U
X0hJR0gpOworc3RhdGljIFNFTlNPUl9ERVZJQ0VfQVRUUih0ZW1wMV9jcml0X2FsYXJtLCBTX0lS
VUdPLCBhZHQ3NDEwX3Nob3dfYWxhcm0sCisJCQkgIE5VTEwsIEFEVDc0MTBfU1RBVF9UX0NSSVQp
Oworc3RhdGljIERFVklDRV9BVFRSKG5hbWUsIFNfSVJVR08sIGFkdDc0MTBfc2hvd19uYW1lLCBO
VUxMKTsKKworc3RhdGljIHN0cnVjdCBhdHRyaWJ1dGUgKmFkdDc0MTBfYXR0cmlidXRlc1tdID0g
eworCSZzZW5zb3JfZGV2X2F0dHJfdGVtcDFfaW5wdXQuZGV2X2F0dHIuYXR0ciwKKwkmc2Vuc29y
X2Rldl9hdHRyX3RlbXAxX21heC5kZXZfYXR0ci5hdHRyLAorCSZzZW5zb3JfZGV2X2F0dHJfdGVt
cDFfbWluLmRldl9hdHRyLmF0dHIsCisJJnNlbnNvcl9kZXZfYXR0cl90ZW1wMV9jcml0LmRldl9h
dHRyLmF0dHIsCisJJnNlbnNvcl9kZXZfYXR0cl90ZW1wMV9tYXhfaHlzdC5kZXZfYXR0ci5hdHRy
LAorCSZzZW5zb3JfZGV2X2F0dHJfdGVtcDFfbWluX2h5c3QuZGV2X2F0dHIuYXR0ciwKKwkmc2Vu
c29yX2Rldl9hdHRyX3RlbXAxX2NyaXRfaHlzdC5kZXZfYXR0ci5hdHRyLAorCSZzZW5zb3JfZGV2
X2F0dHJfdGVtcDFfbWluX2FsYXJtLmRldl9hdHRyLmF0dHIsCisJJnNlbnNvcl9kZXZfYXR0cl90
ZW1wMV9tYXhfYWxhcm0uZGV2X2F0dHIuYXR0ciwKKwkmc2Vuc29yX2Rldl9hdHRyX3RlbXAxX2Ny
aXRfYWxhcm0uZGV2X2F0dHIuYXR0ciwKKwlOVUxMCit9OworCitzdGF0aWMgY29uc3Qgc3RydWN0
IGF0dHJpYnV0ZV9ncm91cCBhZHQ3NDEwX2dyb3VwID0geworCS5hdHRycyA9IGFkdDc0MTBfYXR0
cmlidXRlcywKK307CisKK2ludCBhZHQ3NDEwX3Byb2JlKHN0cnVjdCBkZXZpY2UgKmRldiwgY29u
c3QgY2hhciAqbmFtZSwKKwljb25zdCBzdHJ1Y3QgYWR0NzQxMF9vcHMgKm9wcykKK3sKKwlzdHJ1
Y3QgYWR0NzQxMF9kYXRhICpkYXRhOworCWludCByZXQ7CisKKwlkYXRhID0gZGV2bV9remFsbG9j
KGRldiwgc2l6ZW9mKHN0cnVjdCBhZHQ3NDEwX2RhdGEpLAorCQkJICAgIEdGUF9LRVJORUwpOwor
CWlmICghZGF0YSkKKwkJcmV0dXJuIC1FTk9NRU07CisKKwlkYXRhLT5vcHMgPSBvcHM7CisJZGF0
YS0+bmFtZSA9IG5hbWU7CisKKwlkZXZfc2V0X2RydmRhdGEoZGV2LCBkYXRhKTsKKwltdXRleF9p
bml0KCZkYXRhLT51cGRhdGVfbG9jayk7CisKKwkvKiBjb25maWd1cmUgYXMgc3BlY2lmaWVkICov
CisJcmV0ID0gYWR0NzQxMF9yZWFkX2J5dGUoZGV2LCBBRFQ3NDEwX0NPTkZJRywgJmRhdGEtPm9s
ZGNvbmZpZyk7CisJaWYgKHJldCA8IDApIHsKKwkJZGV2X2RiZyhkZXYsICJDYW4ndCByZWFkIGNv
bmZpZz8gJWRcbiIsIHJldCk7CisJCXJldHVybiByZXQ7CisJfQorCS8qCisJICogU2V0IHRvIDE2
IGJpdCByZXNvbHV0aW9uLCBjb250aW5vdXMgY29udmVyc2lvbiBhbmQgY29tcGFyYXRvciBtb2Rl
LgorCSAqLworCWRhdGEtPmNvbmZpZyA9IGRhdGEtPm9sZGNvbmZpZzsKKwlkYXRhLT5jb25maWcg
Jj0gfkFEVDc0MTBfTU9ERV9NQVNLOworCWRhdGEtPmNvbmZpZyB8PSBBRFQ3NDEwX0ZVTEwgfCBB
RFQ3NDEwX1JFU09MVVRJT04gfCBBRFQ3NDEwX0VWRU5UX01PREU7CisJaWYgKGRhdGEtPmNvbmZp
ZyAhPSBkYXRhLT5vbGRjb25maWcpIHsKKwkJcmV0ID0gYWR0NzQxMF93cml0ZV9ieXRlKGRldiwg
QURUNzQxMF9DT05GSUcsIGRhdGEtPmNvbmZpZyk7CisJCWlmIChyZXQpCisJCQlyZXR1cm4gcmV0
OworCX0KKwlkZXZfZGJnKGRldiwgIkNvbmZpZyAlMDJ4XG4iLCBkYXRhLT5jb25maWcpOworCisJ
cmV0ID0gYWR0NzQxMF9maWxsX2NhY2hlKGRldik7CisJaWYgKHJldCkKKwkJZ290byBleGl0X3Jl
c3RvcmU7CisKKwkvKiBSZWdpc3RlciBzeXNmcyBob29rcyAqLworCXJldCA9IHN5c2ZzX2NyZWF0
ZV9ncm91cCgmZGV2LT5rb2JqLCAmYWR0NzQxMF9ncm91cCk7CisJaWYgKHJldCkKKwkJZ290byBl
eGl0X3Jlc3RvcmU7CisKKwkvKgorCSAqIFRoZSBJMkMgZGV2aWNlIHdpbGwgYWxyZWFkeSBoYXZl
IGl0J3Mgb3duICduYW1lJyBhdHRyaWJ1dGUsIGJ1dCBmb3IKKwkgKiB0aGUgU1BJIGRldmljZSB3
ZSBuZWVkIHRvIHJlZ2lzdGVyIGl0LiBuYW1lIHdpbGwgb25seSBiZSBub24gTlVMTCBpZgorCSAq
IHRoZSBkZXZpY2UgZG9lc24ndCByZWdpc3RlciB0aGUgJ25hbWUnIGF0dHJpYnV0ZSBvbiBpdHMg
b3duLgorCSAqLworCWlmIChuYW1lKSB7CisJCXJldCA9IGRldmljZV9jcmVhdGVfZmlsZShkZXYs
ICZkZXZfYXR0cl9uYW1lKTsKKwkJaWYgKHJldCkKKwkJCWdvdG8gZXhpdF9yZW1vdmU7CisJfQor
CisJZGF0YS0+aHdtb25fZGV2ID0gaHdtb25fZGV2aWNlX3JlZ2lzdGVyKGRldik7CisJaWYgKElT
X0VSUihkYXRhLT5od21vbl9kZXYpKSB7CisJCXJldCA9IFBUUl9FUlIoZGF0YS0+aHdtb25fZGV2
KTsKKwkJZ290byBleGl0X3JlbW92ZV9uYW1lOworCX0KKworCXJldHVybiAwOworCitleGl0X3Jl
bW92ZV9uYW1lOgorCWlmIChuYW1lKQorCQlkZXZpY2VfcmVtb3ZlX2ZpbGUoZGV2LCAmZGV2X2F0
dHJfbmFtZSk7CitleGl0X3JlbW92ZToKKwlzeXNmc19yZW1vdmVfZ3JvdXAoJmRldi0+a29iaiwg
JmFkdDc0MTBfZ3JvdXApOworZXhpdF9yZXN0b3JlOgorCWFkdDc0MTBfd3JpdGVfYnl0ZShkZXYs
IEFEVDc0MTBfQ09ORklHLCBkYXRhLT5vbGRjb25maWcpOworCXJldHVybiByZXQ7Cit9CitFWFBP
UlRfU1lNQk9MX0dQTChhZHQ3NDEwX3Byb2JlKTsKKworaW50IGFkdDc0MTBfcmVtb3ZlKHN0cnVj
dCBkZXZpY2UgKmRldikKK3sKKwlzdHJ1Y3QgYWR0NzQxMF9kYXRhICpkYXRhID0gZGV2X2dldF9k
cnZkYXRhKGRldik7CisKKwlod21vbl9kZXZpY2VfdW5yZWdpc3RlcihkYXRhLT5od21vbl9kZXYp
OworCWlmIChkYXRhLT5uYW1lKQorCQlkZXZpY2VfcmVtb3ZlX2ZpbGUoZGV2LCAmZGV2X2F0dHJf
bmFtZSk7CisJc3lzZnNfcmVtb3ZlX2dyb3VwKCZkZXYtPmtvYmosICZhZHQ3NDEwX2dyb3VwKTsK
KwlpZiAoZGF0YS0+b2xkY29uZmlnICE9IGRhdGEtPmNvbmZpZykKKwkJYWR0NzQxMF93cml0ZV9i
eXRlKGRldiwgQURUNzQxMF9DT05GSUcsCisJCQkJCSAgZGF0YS0+b2xkY29uZmlnKTsKKwlyZXR1
cm4gMDsKK30KK0VYUE9SVF9TWU1CT0xfR1BMKGFkdDc0MTBfcmVtb3ZlKTsKKworI2lmZGVmIENP
TkZJR19QTV9TTEVFUAorCitzdGF0aWMgaW50IGFkdDc0MTBfc3VzcGVuZChzdHJ1Y3QgZGV2aWNl
ICpkZXYpCit7CisJc3RydWN0IGFkdDc0MTBfZGF0YSAqZGF0YSA9IGRldl9nZXRfZHJ2ZGF0YShk
ZXYpOworCisJcmV0dXJuIGFkdDc0MTBfd3JpdGVfYnl0ZShkZXYsIEFEVDc0MTBfQ09ORklHLAor
CQlkYXRhLT5jb25maWcgfCBBRFQ3NDEwX1BEKTsKK30KKworc3RhdGljIGludCBhZHQ3NDEwX3Jl
c3VtZShzdHJ1Y3QgZGV2aWNlICpkZXYpCit7CisJc3RydWN0IGFkdDc0MTBfZGF0YSAqZGF0YSA9
IGRldl9nZXRfZHJ2ZGF0YShkZXYpOworCisJcmV0dXJuIGFkdDc0MTBfd3JpdGVfYnl0ZShkZXYs
IEFEVDc0MTBfQ09ORklHLCBkYXRhLT5jb25maWcpOworfQorCitTSU1QTEVfREVWX1BNX09QUyhh
ZHQ3NDEwX2Rldl9wbV9vcHMsIGFkdDc0MTBfc3VzcGVuZCwgYWR0NzQxMF9yZXN1bWUpOworRVhQ
T1JUX1NZTUJPTF9HUEwoYWR0NzQxMF9kZXZfcG1fb3BzKTsKKworI2VuZGlmIC8qIENPTkZJR19Q
TV9TTEVFUCAqLworCitNT0RVTEVfQVVUSE9SKCJIYXJ0bXV0IEtuYWFjayIpOworTU9EVUxFX0RF
U0NSSVBUSU9OKCJBRFQ3NDEwIGRyaXZlciIpOworTU9EVUxFX0xJQ0VOU0UoIkdQTCIpOwpkaWZm
IC0tZ2l0IGEvZHJpdmVycy9od21vbi9hZHQ3eDEwLmggYi9kcml2ZXJzL2h3bW9uL2FkdDd4MTAu
aApuZXcgZmlsZSBtb2RlIDEwMDY0NAppbmRleCAwMDAwMDAwLi4xN2M4MDUzCi0tLSAvZGV2L251
bGwKKysrIGIvZHJpdmVycy9od21vbi9hZHQ3eDEwLmgKQEAgLTAsMCArMSw0NyBAQAorI2lmbmRl
ZiBfX0hXTU9OX0FEVDc0MTBfSF9fCisjZGVmaW5lIF9fSFdNT05fQURUNzQxMF9IX18KKworI2lu
Y2x1ZGUgPGxpbnV4L3R5cGVzLmg+CisKKy8qIEFEVDc0MTAgcmVnaXN0ZXJzIGRlZmluaXRpb24g
Ki8KKyNkZWZpbmUgQURUNzQxMF9URU1QRVJBVFVSRQkJMAorI2RlZmluZSBBRFQ3NDEwX1NUQVRV
UwkJCTIKKyNkZWZpbmUgQURUNzQxMF9DT05GSUcJCQkzCisjZGVmaW5lIEFEVDc0MTBfVF9BTEFS
TV9ISUdICQk0CisjZGVmaW5lIEFEVDc0MTBfVF9BTEFSTV9MT1cJCTYKKyNkZWZpbmUgQURUNzQx
MF9UX0NSSVQJCQk4CisjZGVmaW5lIEFEVDc0MTBfVF9IWVNUCQkJMHhBCisjZGVmaW5lIEFEVDc0
MTBfSUQJCQkweEIKKworLyogQURUNzMxMCByZWdpc3RlcnMgZGVmaW5pdGlvbiAqLworI2RlZmlu
ZSBBRFQ3MzEwX1NUQVRVUwkJCTAKKyNkZWZpbmUgQURUNzMxMF9DT05GSUcJCQkxCisjZGVmaW5l
IEFEVDczMTBfVEVNUEVSQVRVUkUJCTIKKyNkZWZpbmUgQURUNzMxMF9JRAkJCTMKKyNkZWZpbmUg
QURUNzMxMF9UX0NSSVQJCQk0CisjZGVmaW5lIEFEVDczMTBfVF9IWVNUCQkJNQorI2RlZmluZSBB
RFQ3MzEwX1RfQUxBUk1fSElHSAkJNgorI2RlZmluZSBBRFQ3MzEwX1RfQUxBUk1fTE9XCQk3CisK
K3N0cnVjdCBkZXZpY2U7CisKK3N0cnVjdCBhZHQ3NDEwX29wcyB7CisJaW50ICgqcmVhZF93b3Jk
KShzdHJ1Y3QgZGV2aWNlICosIHU4IHJlZywgdTE2ICpkYXRhKTsKKwlpbnQgKCp3cml0ZV93b3Jk
KShzdHJ1Y3QgZGV2aWNlICosIHU4IHJlZywgdTE2IGRhdGEpOworCWludCAoKnJlYWRfYnl0ZSko
c3RydWN0IGRldmljZSAqLCB1OCByZWcsIHU4ICpkYXRhKTsKKwlpbnQgKCp3cml0ZV9ieXRlKShz
dHJ1Y3QgZGV2aWNlICosIHU4IHJlZywgdTggZGF0YSk7Cit9OworCitpbnQgYWR0NzQxMF9wcm9i
ZShzdHJ1Y3QgZGV2aWNlICpkZXYsIGNvbnN0IGNoYXIgKm5hbWUsCisJY29uc3Qgc3RydWN0IGFk
dDc0MTBfb3BzICpvcHMpOworaW50IGFkdDc0MTBfcmVtb3ZlKHN0cnVjdCBkZXZpY2UgKmRldik7
CisKKworI2lmZGVmIENPTkZJR19QTV9TTEVFUAorZXh0ZXJuIGNvbnN0IHN0cnVjdCBkZXZfcG1f
b3BzIGFkdDc0MTBfZGV2X3BtX29wczsKKyNkZWZpbmUgQURUNzQxMF9ERVZfUE1fT1BTICgmYWR0
NzQxMF9kZXZfcG1fb3BzKQorI2Vsc2UKKyNkZWZpbmUgQURUNzQxMF9ERVZfUE1fT1BTIE5VTEwK
KyNlbmRpZgorCisjZW5kaWYKLS0gCjEuOC4wCgoKX19fX19fX19fX19fX19fX19fX19fX19fX19f
X19fX19fX19fX19fX19fX19fX18KbG0tc2Vuc29ycyBtYWlsaW5nIGxpc3QKbG0tc2Vuc29yc0Bs
bS1zZW5zb3JzLm9yZwpodHRwOi8vbGlzdHMubG0tc2Vuc29ycy5vcmcvbWFpbG1hbi9saXN0aW5m
by9sbS1zZW5zb3Jz

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

* [PATCH 8/9] hwmon: (adt7x10) Add alarm interrupt support
  2013-02-15 16:57 ` [lm-sensors] " Lars-Peter Clausen
@ 2013-02-15 16:57   ` Lars-Peter Clausen
  -1 siblings, 0 replies; 56+ messages in thread
From: Lars-Peter Clausen @ 2013-02-15 16:57 UTC (permalink / raw)
  To: Jean Delvare, Guenter Roeck
  Cc: Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio,
	Lars-Peter Clausen

This allows a userspace application to poll() on the alarm files to get notified
in case of an temperature threshold event.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/hwmon/adt7310.c |  4 ++--
 drivers/hwmon/adt7410.c |  4 ++--
 drivers/hwmon/adt7x10.c | 49 ++++++++++++++++++++++++++++++++++++++++++++-----
 drivers/hwmon/adt7x10.h |  4 ++--
 4 files changed, 50 insertions(+), 11 deletions(-)

diff --git a/drivers/hwmon/adt7310.c b/drivers/hwmon/adt7310.c
index 0483e6c..dcd8d5a 100644
--- a/drivers/hwmon/adt7310.c
+++ b/drivers/hwmon/adt7310.c
@@ -127,13 +127,13 @@ static const struct adt7410_ops adt7310_spi_ops = {
 
 static int adt7310_spi_probe(struct spi_device *spi)
 {
-	return adt7410_probe(&spi->dev, spi_get_device_id(spi)->name,
+	return adt7410_probe(&spi->dev, spi_get_device_id(spi)->name, spi->irq,
 			&adt7310_spi_ops);
 }
 
 static int adt7310_spi_remove(struct spi_device *spi)
 {
-	return adt7410_remove(&spi->dev);
+	return adt7410_remove(&spi->dev, spi->irq);
 }
 
 static const struct spi_device_id adt7310_id[] = {
diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
index 13734c5..35880c6 100644
--- a/drivers/hwmon/adt7410.c
+++ b/drivers/hwmon/adt7410.c
@@ -84,12 +84,12 @@ static int adt7410_i2c_probe(struct i2c_client *client,
 			I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
 		return -ENODEV;
 
-	return adt7410_probe(&client->dev, NULL, &adt7410_i2c_ops);
+	return adt7410_probe(&client->dev, NULL, client->irq, &adt7410_i2c_ops);
 }
 
 static int adt7410_i2c_remove(struct i2c_client *client)
 {
-	return adt7410_remove(&client->dev);
+	return adt7410_remove(&client->dev, client->irq);
 }
 
 static const struct i2c_device_id adt7410_id[] = {
diff --git a/drivers/hwmon/adt7x10.c b/drivers/hwmon/adt7x10.c
index 2598aaf..d042596 100644
--- a/drivers/hwmon/adt7x10.c
+++ b/drivers/hwmon/adt7x10.c
@@ -30,6 +30,7 @@
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include <linux/delay.h>
+#include <linux/interrupt.h>
 
 #include "adt7x10.h"
 
@@ -112,6 +113,26 @@ static const u8 ADT7410_REG_TEMP[4] = {
 	ADT7410_T_CRIT,			/* critical */
 };
 
+static irqreturn_t adt7410_irq_handler(int irq, void *private)
+{
+	struct device *dev = private;
+	u8 status;
+	int ret;
+
+	ret = adt7410_read_byte(dev, ADT7410_STATUS, &status);
+	if (ret)
+		return IRQ_HANDLED;
+
+	if (status & ADT7410_STAT_T_HIGH)
+		sysfs_notify(&dev->kobj, NULL, "temp1_max_alarm");
+	if (status & ADT7410_STAT_T_LOW)
+		sysfs_notify(&dev->kobj, NULL, "temp1_min_alarm");
+	if (status & ADT7410_STAT_T_CRIT)
+		sysfs_notify(&dev->kobj, NULL, "temp1_crit_alarm");
+
+	return IRQ_HANDLED;
+}
+
 /*
  * adt7410 register access by I2C
  */
@@ -359,7 +380,7 @@ static const struct attribute_group adt7410_group = {
 	.attrs = adt7410_attributes,
 };
 
-int adt7410_probe(struct device *dev, const char *name,
+int adt7410_probe(struct device *dev, const char *name, int irq,
 	const struct adt7410_ops *ops)
 {
 	struct adt7410_data *data;
@@ -383,11 +404,17 @@ int adt7410_probe(struct device *dev, const char *name,
 		return ret;
 	}
 	/*
-	 * Set to 16 bit resolution, continous conversion and comparator mode.
+	 * Set to 16 bit resolution and continous conversion
 	 */
 	data->config = data->oldconfig;
-	data->config &= ~ADT7410_MODE_MASK;
-	data->config |= ADT7410_FULL | ADT7410_RESOLUTION | ADT7410_EVENT_MODE;
+	data->config &= ~(ADT7410_MODE_MASK | ADT7410_CT_POLARITY |
+			ADT7410_INT_POLARITY);
+	data->config |= ADT7410_FULL | ADT7410_RESOLUTION;
+
+	/* If we are not using interrupts use comperator mode */
+	if (irq <= 0)
+		data->config |= ADT7410_EVENT_MODE;
+
 	if (data->config != data->oldconfig) {
 		ret = adt7410_write_byte(dev, ADT7410_CONFIG, data->config);
 		if (ret)
@@ -421,8 +448,17 @@ int adt7410_probe(struct device *dev, const char *name,
 		goto exit_remove_name;
 	}
 
+	if (irq > 0) {
+		ret = request_threaded_irq(irq, NULL, adt7410_irq_handler,
+				IRQF_TRIGGER_LOW | IRQF_ONESHOT, name, dev);
+		if (ret)
+			goto exit_hwmon_device_unregister;
+	}
+
 	return 0;
 
+exit_hwmon_device_unregister:
+	hwmon_device_unregister(data->hwmon_dev);
 exit_remove_name:
 	if (name)
 		device_remove_file(dev, &dev_attr_name);
@@ -434,10 +470,13 @@ exit_restore:
 }
 EXPORT_SYMBOL_GPL(adt7410_probe);
 
-int adt7410_remove(struct device *dev)
+int adt7410_remove(struct device *dev, int irq)
 {
 	struct adt7410_data *data = dev_get_drvdata(dev);
 
+	if (irq > 0)
+		free_irq(irq, dev);
+
 	hwmon_device_unregister(data->hwmon_dev);
 	if (data->name)
 		device_remove_file(dev, &dev_attr_name);
diff --git a/drivers/hwmon/adt7x10.h b/drivers/hwmon/adt7x10.h
index 17c8053..173b094 100644
--- a/drivers/hwmon/adt7x10.h
+++ b/drivers/hwmon/adt7x10.h
@@ -32,9 +32,9 @@ struct adt7410_ops {
 	int (*write_byte)(struct device *, u8 reg, u8 data);
 };
 
-int adt7410_probe(struct device *dev, const char *name,
+int adt7410_probe(struct device *dev, const char *name, int irq,
 	const struct adt7410_ops *ops);
-int adt7410_remove(struct device *dev);
+int adt7410_remove(struct device *dev, int irq);
 
 
 #ifdef CONFIG_PM_SLEEP
-- 
1.8.0


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

* [lm-sensors] [PATCH 8/9] hwmon: (adt7x10) Add alarm interrupt support
@ 2013-02-15 16:57   ` Lars-Peter Clausen
  0 siblings, 0 replies; 56+ messages in thread
From: Lars-Peter Clausen @ 2013-02-15 16:57 UTC (permalink / raw)
  To: Jean Delvare, Guenter Roeck
  Cc: Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio,
	Lars-Peter Clausen

This allows a userspace application to poll() on the alarm files to get notified
in case of an temperature threshold event.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/hwmon/adt7310.c |  4 ++--
 drivers/hwmon/adt7410.c |  4 ++--
 drivers/hwmon/adt7x10.c | 49 ++++++++++++++++++++++++++++++++++++++++++++-----
 drivers/hwmon/adt7x10.h |  4 ++--
 4 files changed, 50 insertions(+), 11 deletions(-)

diff --git a/drivers/hwmon/adt7310.c b/drivers/hwmon/adt7310.c
index 0483e6c..dcd8d5a 100644
--- a/drivers/hwmon/adt7310.c
+++ b/drivers/hwmon/adt7310.c
@@ -127,13 +127,13 @@ static const struct adt7410_ops adt7310_spi_ops = {
 
 static int adt7310_spi_probe(struct spi_device *spi)
 {
-	return adt7410_probe(&spi->dev, spi_get_device_id(spi)->name,
+	return adt7410_probe(&spi->dev, spi_get_device_id(spi)->name, spi->irq,
 			&adt7310_spi_ops);
 }
 
 static int adt7310_spi_remove(struct spi_device *spi)
 {
-	return adt7410_remove(&spi->dev);
+	return adt7410_remove(&spi->dev, spi->irq);
 }
 
 static const struct spi_device_id adt7310_id[] = {
diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
index 13734c5..35880c6 100644
--- a/drivers/hwmon/adt7410.c
+++ b/drivers/hwmon/adt7410.c
@@ -84,12 +84,12 @@ static int adt7410_i2c_probe(struct i2c_client *client,
 			I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
 		return -ENODEV;
 
-	return adt7410_probe(&client->dev, NULL, &adt7410_i2c_ops);
+	return adt7410_probe(&client->dev, NULL, client->irq, &adt7410_i2c_ops);
 }
 
 static int adt7410_i2c_remove(struct i2c_client *client)
 {
-	return adt7410_remove(&client->dev);
+	return adt7410_remove(&client->dev, client->irq);
 }
 
 static const struct i2c_device_id adt7410_id[] = {
diff --git a/drivers/hwmon/adt7x10.c b/drivers/hwmon/adt7x10.c
index 2598aaf..d042596 100644
--- a/drivers/hwmon/adt7x10.c
+++ b/drivers/hwmon/adt7x10.c
@@ -30,6 +30,7 @@
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include <linux/delay.h>
+#include <linux/interrupt.h>
 
 #include "adt7x10.h"
 
@@ -112,6 +113,26 @@ static const u8 ADT7410_REG_TEMP[4] = {
 	ADT7410_T_CRIT,			/* critical */
 };
 
+static irqreturn_t adt7410_irq_handler(int irq, void *private)
+{
+	struct device *dev = private;
+	u8 status;
+	int ret;
+
+	ret = adt7410_read_byte(dev, ADT7410_STATUS, &status);
+	if (ret)
+		return IRQ_HANDLED;
+
+	if (status & ADT7410_STAT_T_HIGH)
+		sysfs_notify(&dev->kobj, NULL, "temp1_max_alarm");
+	if (status & ADT7410_STAT_T_LOW)
+		sysfs_notify(&dev->kobj, NULL, "temp1_min_alarm");
+	if (status & ADT7410_STAT_T_CRIT)
+		sysfs_notify(&dev->kobj, NULL, "temp1_crit_alarm");
+
+	return IRQ_HANDLED;
+}
+
 /*
  * adt7410 register access by I2C
  */
@@ -359,7 +380,7 @@ static const struct attribute_group adt7410_group = {
 	.attrs = adt7410_attributes,
 };
 
-int adt7410_probe(struct device *dev, const char *name,
+int adt7410_probe(struct device *dev, const char *name, int irq,
 	const struct adt7410_ops *ops)
 {
 	struct adt7410_data *data;
@@ -383,11 +404,17 @@ int adt7410_probe(struct device *dev, const char *name,
 		return ret;
 	}
 	/*
-	 * Set to 16 bit resolution, continous conversion and comparator mode.
+	 * Set to 16 bit resolution and continous conversion
 	 */
 	data->config = data->oldconfig;
-	data->config &= ~ADT7410_MODE_MASK;
-	data->config |= ADT7410_FULL | ADT7410_RESOLUTION | ADT7410_EVENT_MODE;
+	data->config &= ~(ADT7410_MODE_MASK | ADT7410_CT_POLARITY |
+			ADT7410_INT_POLARITY);
+	data->config |= ADT7410_FULL | ADT7410_RESOLUTION;
+
+	/* If we are not using interrupts use comperator mode */
+	if (irq <= 0)
+		data->config |= ADT7410_EVENT_MODE;
+
 	if (data->config != data->oldconfig) {
 		ret = adt7410_write_byte(dev, ADT7410_CONFIG, data->config);
 		if (ret)
@@ -421,8 +448,17 @@ int adt7410_probe(struct device *dev, const char *name,
 		goto exit_remove_name;
 	}
 
+	if (irq > 0) {
+		ret = request_threaded_irq(irq, NULL, adt7410_irq_handler,
+				IRQF_TRIGGER_LOW | IRQF_ONESHOT, name, dev);
+		if (ret)
+			goto exit_hwmon_device_unregister;
+	}
+
 	return 0;
 
+exit_hwmon_device_unregister:
+	hwmon_device_unregister(data->hwmon_dev);
 exit_remove_name:
 	if (name)
 		device_remove_file(dev, &dev_attr_name);
@@ -434,10 +470,13 @@ exit_restore:
 }
 EXPORT_SYMBOL_GPL(adt7410_probe);
 
-int adt7410_remove(struct device *dev)
+int adt7410_remove(struct device *dev, int irq)
 {
 	struct adt7410_data *data = dev_get_drvdata(dev);
 
+	if (irq > 0)
+		free_irq(irq, dev);
+
 	hwmon_device_unregister(data->hwmon_dev);
 	if (data->name)
 		device_remove_file(dev, &dev_attr_name);
diff --git a/drivers/hwmon/adt7x10.h b/drivers/hwmon/adt7x10.h
index 17c8053..173b094 100644
--- a/drivers/hwmon/adt7x10.h
+++ b/drivers/hwmon/adt7x10.h
@@ -32,9 +32,9 @@ struct adt7410_ops {
 	int (*write_byte)(struct device *, u8 reg, u8 data);
 };
 
-int adt7410_probe(struct device *dev, const char *name,
+int adt7410_probe(struct device *dev, const char *name, int irq,
 	const struct adt7410_ops *ops);
-int adt7410_remove(struct device *dev);
+int adt7410_remove(struct device *dev, int irq);
 
 
 #ifdef CONFIG_PM_SLEEP
-- 
1.8.0


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

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

* [PATCH 9/9] staging:iio: Remove adt7410 driver
  2013-02-15 16:57 ` [lm-sensors] " Lars-Peter Clausen
@ 2013-02-15 16:57   ` Lars-Peter Clausen
  -1 siblings, 0 replies; 56+ messages in thread
From: Lars-Peter Clausen @ 2013-02-15 16:57 UTC (permalink / raw)
  To: Jean Delvare, Guenter Roeck
  Cc: Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio,
	Lars-Peter Clausen

The adt7410 hwmon driver is feature wise more or less on par with the IIO
driver. So we can finally remove the IIO driver.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/staging/iio/adc/Kconfig   |    7 -
 drivers/staging/iio/adc/Makefile  |    1 -
 drivers/staging/iio/adc/adt7410.c | 1102 -------------------------------------
 3 files changed, 1110 deletions(-)
 delete mode 100644 drivers/staging/iio/adc/adt7410.c

diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig
index fb8c239..029ae54 100644
--- a/drivers/staging/iio/adc/Kconfig
+++ b/drivers/staging/iio/adc/Kconfig
@@ -90,13 +90,6 @@ config AD7192
 	  To compile this driver as a module, choose M here: the
 	  module will be called ad7192.
 
-config ADT7410
-	tristate "Analog Devices ADT7310/ADT7410 temperature sensor driver"
-	depends on I2C || SPI_MASTER
-	help
-	  Say yes here to build support for Analog Devices ADT7310/ADT7410
-	  temperature sensors.
-
 config AD7280
 	tristate "Analog Devices AD7280A Lithium Ion Battery Monitoring System"
 	depends on SPI
diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile
index d285596..3e9fb14 100644
--- a/drivers/staging/iio/adc/Makefile
+++ b/drivers/staging/iio/adc/Makefile
@@ -16,7 +16,6 @@ obj-$(CONFIG_AD7291) += ad7291.o
 obj-$(CONFIG_AD7780) += ad7780.o
 obj-$(CONFIG_AD7816) += ad7816.o
 obj-$(CONFIG_AD7192) += ad7192.o
-obj-$(CONFIG_ADT7410) += adt7410.o
 obj-$(CONFIG_AD7280) += ad7280a.o
 obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o
 obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o
diff --git a/drivers/staging/iio/adc/adt7410.c b/drivers/staging/iio/adc/adt7410.c
deleted file mode 100644
index 35455e1..0000000
--- a/drivers/staging/iio/adc/adt7410.c
+++ /dev/null
@@ -1,1102 +0,0 @@
-/*
- * ADT7410 digital temperature sensor driver supporting ADT7310/ADT7410
- *
- * Copyright 2010 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/list.h>
-#include <linux/i2c.h>
-#include <linux/spi/spi.h>
-#include <linux/module.h>
-
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-#include <linux/iio/events.h>
-
-/*
- * ADT7410 registers definition
- */
-
-#define ADT7410_TEMPERATURE		0
-#define ADT7410_STATUS			2
-#define ADT7410_CONFIG			3
-#define ADT7410_T_ALARM_HIGH		4
-#define ADT7410_T_ALARM_LOW		6
-#define ADT7410_T_CRIT			8
-#define ADT7410_T_HYST			0xA
-#define ADT7410_ID			0xB
-#define ADT7410_RESET			0x2F
-
-/*
- * ADT7310 registers definition
- */
-
-#define ADT7310_STATUS			0
-#define ADT7310_CONFIG			1
-#define ADT7310_TEMPERATURE		2
-#define ADT7310_ID			3
-#define ADT7310_T_CRIT			4
-#define ADT7310_T_HYST			5
-#define ADT7310_T_ALARM_HIGH		6
-#define ADT7310_T_ALARM_LOW		7
-
-/*
- * ADT7410 status
- */
-#define ADT7410_STAT_T_LOW		0x10
-#define ADT7410_STAT_T_HIGH		0x20
-#define ADT7410_STAT_T_CRIT		0x40
-#define ADT7410_STAT_NOT_RDY		0x80
-
-/*
- * ADT7410 config
- */
-#define ADT7410_FAULT_QUEUE_MASK	0x3
-#define ADT7410_CT_POLARITY		0x4
-#define ADT7410_INT_POLARITY		0x8
-#define ADT7410_EVENT_MODE		0x10
-#define ADT7410_MODE_MASK		0x60
-#define ADT7410_ONESHOT			0x20
-#define ADT7410_SPS			0x40
-#define ADT7410_PD			0x60
-#define ADT7410_RESOLUTION		0x80
-
-/*
- * ADT7410 masks
- */
-#define ADT7410_T16_VALUE_SIGN			0x8000
-#define ADT7410_T16_VALUE_FLOAT_OFFSET		7
-#define ADT7410_T16_VALUE_FLOAT_MASK		0x7F
-#define ADT7410_T13_VALUE_SIGN			0x1000
-#define ADT7410_T13_VALUE_OFFSET		3
-#define ADT7410_T13_VALUE_FLOAT_OFFSET		4
-#define ADT7410_T13_VALUE_FLOAT_MASK		0xF
-#define ADT7410_T_HYST_MASK			0xF
-#define ADT7410_DEVICE_ID_MASK			0xF
-#define ADT7410_MANUFACTORY_ID_MASK		0xF0
-#define ADT7410_MANUFACTORY_ID_OFFSET		4
-
-
-#define ADT7310_CMD_REG_MASK			0x28
-#define ADT7310_CMD_REG_OFFSET			3
-#define ADT7310_CMD_READ			0x40
-#define ADT7310_CMD_CON_READ			0x4
-
-#define ADT7410_IRQS				2
-
-/*
- * struct adt7410_chip_info - chip specifc information
- */
-
-struct adt7410_chip_info;
-
-struct adt7410_ops {
-	int (*read_word)(struct adt7410_chip_info *, u8 reg, u16 *data);
-	int (*write_word)(struct adt7410_chip_info *, u8 reg, u16 data);
-	int (*read_byte)(struct adt7410_chip_info *, u8 reg, u8 *data);
-	int (*write_byte)(struct adt7410_chip_info *, u8 reg, u8 data);
-};
-
-struct adt7410_chip_info {
-	struct device *dev;
-	u8  config;
-
-	const struct adt7410_ops *ops;
-};
-
-static int adt7410_read_word(struct adt7410_chip_info *chip, u8 reg, u16 *data)
-{
-	return chip->ops->read_word(chip, reg, data);
-}
-
-static int adt7410_write_word(struct adt7410_chip_info *chip, u8 reg, u16 data)
-{
-	return chip->ops->write_word(chip, reg, data);
-}
-
-static int adt7410_read_byte(struct adt7410_chip_info *chip, u8 reg, u8 *data)
-{
-	return chip->ops->read_byte(chip, reg, data);
-}
-
-static int adt7410_write_byte(struct adt7410_chip_info *chip, u8 reg, u8 data)
-{
-	return chip->ops->write_byte(chip, reg, data);
-}
-
-static ssize_t adt7410_show_mode(struct device *dev,
-		struct device_attribute *attr,
-		char *buf)
-{
-	struct iio_dev *dev_info = dev_to_iio_dev(dev);
-	struct adt7410_chip_info *chip = iio_priv(dev_info);
-	u8 config;
-
-	config = chip->config & ADT7410_MODE_MASK;
-
-	switch (config) {
-	case ADT7410_PD:
-		return sprintf(buf, "power-down\n");
-	case ADT7410_ONESHOT:
-		return sprintf(buf, "one-shot\n");
-	case ADT7410_SPS:
-		return sprintf(buf, "sps\n");
-	default:
-		return sprintf(buf, "full\n");
-	}
-}
-
-static ssize_t adt7410_store_mode(struct device *dev,
-		struct device_attribute *attr,
-		const char *buf,
-		size_t len)
-{
-	struct iio_dev *dev_info = dev_to_iio_dev(dev);
-	struct adt7410_chip_info *chip = iio_priv(dev_info);
-	u16 config;
-	int ret;
-
-	ret = adt7410_read_byte(chip, ADT7410_CONFIG, &chip->config);
-	if (ret)
-		return -EIO;
-
-	config = chip->config & (~ADT7410_MODE_MASK);
-	if (strcmp(buf, "power-down"))
-		config |= ADT7410_PD;
-	else if (strcmp(buf, "one-shot"))
-		config |= ADT7410_ONESHOT;
-	else if (strcmp(buf, "sps"))
-		config |= ADT7410_SPS;
-
-	ret = adt7410_write_byte(chip, ADT7410_CONFIG, config);
-	if (ret)
-		return -EIO;
-
-	chip->config = config;
-
-	return len;
-}
-
-static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
-		adt7410_show_mode,
-		adt7410_store_mode,
-		0);
-
-static ssize_t adt7410_show_available_modes(struct device *dev,
-		struct device_attribute *attr,
-		char *buf)
-{
-	return sprintf(buf, "full\none-shot\nsps\npower-down\n");
-}
-
-static IIO_DEVICE_ATTR(available_modes, S_IRUGO, adt7410_show_available_modes, NULL, 0);
-
-static ssize_t adt7410_show_resolution(struct device *dev,
-		struct device_attribute *attr,
-		char *buf)
-{
-	struct iio_dev *dev_info = dev_to_iio_dev(dev);
-	struct adt7410_chip_info *chip = iio_priv(dev_info);
-	int ret;
-	int bits;
-
-	ret = adt7410_read_byte(chip, ADT7410_CONFIG, &chip->config);
-	if (ret)
-		return -EIO;
-
-	if (chip->config & ADT7410_RESOLUTION)
-		bits = 16;
-	else
-		bits = 13;
-
-	return sprintf(buf, "%d bits\n", bits);
-}
-
-static ssize_t adt7410_store_resolution(struct device *dev,
-		struct device_attribute *attr,
-		const char *buf,
-		size_t len)
-{
-	struct iio_dev *dev_info = dev_to_iio_dev(dev);
-	struct adt7410_chip_info *chip = iio_priv(dev_info);
-	unsigned long data;
-	u16 config;
-	int ret;
-
-	ret = strict_strtoul(buf, 10, &data);
-	if (ret)
-		return -EINVAL;
-
-	ret = adt7410_read_byte(chip, ADT7410_CONFIG, &chip->config);
-	if (ret)
-		return -EIO;
-
-	config = chip->config & (~ADT7410_RESOLUTION);
-	if (data)
-		config |= ADT7410_RESOLUTION;
-
-	ret = adt7410_write_byte(chip, ADT7410_CONFIG, config);
-	if (ret)
-		return -EIO;
-
-	chip->config = config;
-
-	return len;
-}
-
-static IIO_DEVICE_ATTR(resolution, S_IRUGO | S_IWUSR,
-		adt7410_show_resolution,
-		adt7410_store_resolution,
-		0);
-
-static ssize_t adt7410_show_id(struct device *dev,
-		struct device_attribute *attr,
-		char *buf)
-{
-	struct iio_dev *dev_info = dev_to_iio_dev(dev);
-	struct adt7410_chip_info *chip = iio_priv(dev_info);
-	u8 id;
-	int ret;
-
-	ret = adt7410_read_byte(chip, ADT7410_ID, &id);
-	if (ret)
-		return -EIO;
-
-	return sprintf(buf, "device id: 0x%x\nmanufactory id: 0x%x\n",
-			id & ADT7410_DEVICE_ID_MASK,
-			(id & ADT7410_MANUFACTORY_ID_MASK) >> ADT7410_MANUFACTORY_ID_OFFSET);
-}
-
-static IIO_DEVICE_ATTR(id, S_IRUGO | S_IWUSR,
-		adt7410_show_id,
-		NULL,
-		0);
-
-static ssize_t adt7410_convert_temperature(struct adt7410_chip_info *chip,
-		u16 data, char *buf)
-{
-	char sign = ' ';
-
-	if (!(chip->config & ADT7410_RESOLUTION))
-		data &= ~0x7;
-
-	if (data & ADT7410_T16_VALUE_SIGN) {
-		/* convert supplement to positive value */
-		data = (u16)((ADT7410_T16_VALUE_SIGN << 1) - (u32)data);
-		sign = '-';
-	}
-	return sprintf(buf, "%c%d.%.7d\n", sign,
-			(data >> ADT7410_T16_VALUE_FLOAT_OFFSET),
-			(data & ADT7410_T16_VALUE_FLOAT_MASK) * 78125);
-}
-
-static ssize_t adt7410_show_value(struct device *dev,
-		struct device_attribute *attr,
-		char *buf)
-{
-	struct iio_dev *dev_info = dev_to_iio_dev(dev);
-	struct adt7410_chip_info *chip = iio_priv(dev_info);
-	u8 status;
-	u16 data;
-	int ret, i = 0;
-
-	do {
-		ret = adt7410_read_byte(chip, ADT7410_STATUS, &status);
-		if (ret)
-			return -EIO;
-		i++;
-		if (i == 10000)
-			return -EIO;
-	} while (status & ADT7410_STAT_NOT_RDY);
-
-	ret = adt7410_read_word(chip, ADT7410_TEMPERATURE, &data);
-	if (ret)
-		return -EIO;
-
-	return adt7410_convert_temperature(chip, data, buf);
-}
-
-static IIO_DEVICE_ATTR(value, S_IRUGO, adt7410_show_value, NULL, 0);
-
-static struct attribute *adt7410_attributes[] = {
-	&iio_dev_attr_available_modes.dev_attr.attr,
-	&iio_dev_attr_mode.dev_attr.attr,
-	&iio_dev_attr_resolution.dev_attr.attr,
-	&iio_dev_attr_id.dev_attr.attr,
-	&iio_dev_attr_value.dev_attr.attr,
-	NULL,
-};
-
-static const struct attribute_group adt7410_attribute_group = {
-	.attrs = adt7410_attributes,
-};
-
-static irqreturn_t adt7410_event_handler(int irq, void *private)
-{
-	struct iio_dev *indio_dev = private;
-	struct adt7410_chip_info *chip = iio_priv(indio_dev);
-	s64 timestamp = iio_get_time_ns();
-	u8 status;
-
-	if (adt7410_read_byte(chip, ADT7410_STATUS, &status))
-		return IRQ_HANDLED;
-
-	if (status & ADT7410_STAT_T_HIGH)
-		iio_push_event(indio_dev,
-			       IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0,
-						    IIO_EV_TYPE_THRESH,
-						    IIO_EV_DIR_RISING),
-			       timestamp);
-	if (status & ADT7410_STAT_T_LOW)
-		iio_push_event(indio_dev,
-			       IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0,
-						    IIO_EV_TYPE_THRESH,
-						    IIO_EV_DIR_FALLING),
-			       timestamp);
-	if (status & ADT7410_STAT_T_CRIT)
-		iio_push_event(indio_dev,
-			       IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0,
-						    IIO_EV_TYPE_THRESH,
-						    IIO_EV_DIR_RISING),
-			       timestamp);
-
-	return IRQ_HANDLED;
-}
-
-static ssize_t adt7410_show_event_mode(struct device *dev,
-		struct device_attribute *attr,
-		char *buf)
-{
-	struct iio_dev *dev_info = dev_to_iio_dev(dev);
-	struct adt7410_chip_info *chip = iio_priv(dev_info);
-	int ret;
-
-	ret = adt7410_read_byte(chip, ADT7410_CONFIG, &chip->config);
-	if (ret)
-		return -EIO;
-
-	if (chip->config & ADT7410_EVENT_MODE)
-		return sprintf(buf, "interrupt\n");
-	else
-		return sprintf(buf, "comparator\n");
-}
-
-static ssize_t adt7410_set_event_mode(struct device *dev,
-		struct device_attribute *attr,
-		const char *buf,
-		size_t len)
-{
-	struct iio_dev *dev_info = dev_to_iio_dev(dev);
-	struct adt7410_chip_info *chip = iio_priv(dev_info);
-	u16 config;
-	int ret;
-
-	ret = adt7410_read_byte(chip, ADT7410_CONFIG, &chip->config);
-	if (ret)
-		return -EIO;
-
-	config = chip->config &= ~ADT7410_EVENT_MODE;
-	if (strcmp(buf, "comparator") != 0)
-		config |= ADT7410_EVENT_MODE;
-
-	ret = adt7410_write_byte(chip, ADT7410_CONFIG, config);
-	if (ret)
-		return -EIO;
-
-	chip->config = config;
-
-	return ret;
-}
-
-static ssize_t adt7410_show_available_event_modes(struct device *dev,
-		struct device_attribute *attr,
-		char *buf)
-{
-	return sprintf(buf, "comparator\ninterrupt\n");
-}
-
-static ssize_t adt7410_show_fault_queue(struct device *dev,
-		struct device_attribute *attr,
-		char *buf)
-{
-	struct iio_dev *dev_info = dev_to_iio_dev(dev);
-	struct adt7410_chip_info *chip = iio_priv(dev_info);
-	int ret;
-
-	ret = adt7410_read_byte(chip, ADT7410_CONFIG, &chip->config);
-	if (ret)
-		return -EIO;
-
-	return sprintf(buf, "%d\n", chip->config & ADT7410_FAULT_QUEUE_MASK);
-}
-
-static ssize_t adt7410_set_fault_queue(struct device *dev,
-		struct device_attribute *attr,
-		const char *buf,
-		size_t len)
-{
-	struct iio_dev *dev_info = dev_to_iio_dev(dev);
-	struct adt7410_chip_info *chip = iio_priv(dev_info);
-	unsigned long data;
-	int ret;
-	u8 config;
-
-	ret = strict_strtoul(buf, 10, &data);
-	if (ret || data > 3)
-		return -EINVAL;
-
-	ret = adt7410_read_byte(chip, ADT7410_CONFIG, &chip->config);
-	if (ret)
-		return -EIO;
-
-	config = chip->config & ~ADT7410_FAULT_QUEUE_MASK;
-	config |= data;
-	ret = adt7410_write_byte(chip, ADT7410_CONFIG, config);
-	if (ret)
-		return -EIO;
-
-	chip->config = config;
-
-	return ret;
-}
-
-static inline ssize_t adt7410_show_t_bound(struct device *dev,
-		struct device_attribute *attr,
-		u8 bound_reg,
-		char *buf)
-{
-	struct iio_dev *dev_info = dev_to_iio_dev(dev);
-	struct adt7410_chip_info *chip = iio_priv(dev_info);
-	u16 data;
-	int ret;
-
-	ret = adt7410_read_word(chip, bound_reg, &data);
-	if (ret)
-		return -EIO;
-
-	return adt7410_convert_temperature(chip, data, buf);
-}
-
-static inline ssize_t adt7410_set_t_bound(struct device *dev,
-		struct device_attribute *attr,
-		u8 bound_reg,
-		const char *buf,
-		size_t len)
-{
-	struct iio_dev *dev_info = dev_to_iio_dev(dev);
-	struct adt7410_chip_info *chip = iio_priv(dev_info);
-	long tmp1, tmp2;
-	u16 data;
-	char *pos;
-	int ret;
-
-	pos = strchr(buf, '.');
-
-	ret = strict_strtol(buf, 10, &tmp1);
-
-	if (ret || tmp1 > 127 || tmp1 < -128)
-		return -EINVAL;
-
-	if (pos) {
-		len = strlen(pos);
-
-		if (chip->config & ADT7410_RESOLUTION) {
-			if (len > ADT7410_T16_VALUE_FLOAT_OFFSET)
-				len = ADT7410_T16_VALUE_FLOAT_OFFSET;
-			pos[len] = 0;
-			ret = strict_strtol(pos, 10, &tmp2);
-
-			if (!ret)
-				tmp2 = (tmp2 / 78125) * 78125;
-		} else {
-			if (len > ADT7410_T13_VALUE_FLOAT_OFFSET)
-				len = ADT7410_T13_VALUE_FLOAT_OFFSET;
-			pos[len] = 0;
-			ret = strict_strtol(pos, 10, &tmp2);
-
-			if (!ret)
-				tmp2 = (tmp2 / 625) * 625;
-		}
-	}
-
-	if (tmp1 < 0)
-		data = (u16)(-tmp1);
-	else
-		data = (u16)tmp1;
-
-	if (chip->config & ADT7410_RESOLUTION) {
-		data = (data << ADT7410_T16_VALUE_FLOAT_OFFSET) |
-			(tmp2 & ADT7410_T16_VALUE_FLOAT_MASK);
-
-		if (tmp1 < 0)
-			/* convert positive value to supplyment */
-			data = (u16)((ADT7410_T16_VALUE_SIGN << 1) - (u32)data);
-	} else {
-		data = (data << ADT7410_T13_VALUE_FLOAT_OFFSET) |
-			(tmp2 & ADT7410_T13_VALUE_FLOAT_MASK);
-
-		if (tmp1 < 0)
-			/* convert positive value to supplyment */
-			data = (ADT7410_T13_VALUE_SIGN << 1) - data;
-		data <<= ADT7410_T13_VALUE_OFFSET;
-	}
-
-	ret = adt7410_write_word(chip, bound_reg, data);
-	if (ret)
-		return -EIO;
-
-	return ret;
-}
-
-static ssize_t adt7410_show_t_alarm_high(struct device *dev,
-		struct device_attribute *attr,
-		char *buf)
-{
-	return adt7410_show_t_bound(dev, attr,
-			ADT7410_T_ALARM_HIGH, buf);
-}
-
-static inline ssize_t adt7410_set_t_alarm_high(struct device *dev,
-		struct device_attribute *attr,
-		const char *buf,
-		size_t len)
-{
-	return adt7410_set_t_bound(dev, attr,
-			ADT7410_T_ALARM_HIGH, buf, len);
-}
-
-static ssize_t adt7410_show_t_alarm_low(struct device *dev,
-		struct device_attribute *attr,
-		char *buf)
-{
-	return adt7410_show_t_bound(dev, attr,
-			ADT7410_T_ALARM_LOW, buf);
-}
-
-static inline ssize_t adt7410_set_t_alarm_low(struct device *dev,
-		struct device_attribute *attr,
-		const char *buf,
-		size_t len)
-{
-	return adt7410_set_t_bound(dev, attr,
-			ADT7410_T_ALARM_LOW, buf, len);
-}
-
-static ssize_t adt7410_show_t_crit(struct device *dev,
-		struct device_attribute *attr,
-		char *buf)
-{
-	return adt7410_show_t_bound(dev, attr,
-			ADT7410_T_CRIT, buf);
-}
-
-static inline ssize_t adt7410_set_t_crit(struct device *dev,
-		struct device_attribute *attr,
-		const char *buf,
-		size_t len)
-{
-	return adt7410_set_t_bound(dev, attr,
-			ADT7410_T_CRIT, buf, len);
-}
-
-static ssize_t adt7410_show_t_hyst(struct device *dev,
-		struct device_attribute *attr,
-		char *buf)
-{
-	struct iio_dev *dev_info = dev_to_iio_dev(dev);
-	struct adt7410_chip_info *chip = iio_priv(dev_info);
-	int ret;
-	u8 t_hyst;
-
-	ret = adt7410_read_byte(chip, ADT7410_T_HYST, &t_hyst);
-	if (ret)
-		return -EIO;
-
-	return sprintf(buf, "%d\n", t_hyst & ADT7410_T_HYST_MASK);
-}
-
-static inline ssize_t adt7410_set_t_hyst(struct device *dev,
-		struct device_attribute *attr,
-		const char *buf,
-		size_t len)
-{
-	struct iio_dev *dev_info = dev_to_iio_dev(dev);
-	struct adt7410_chip_info *chip = iio_priv(dev_info);
-	int ret;
-	unsigned long data;
-	u8 t_hyst;
-
-	ret = strict_strtol(buf, 10, &data);
-
-	if (ret || data > ADT7410_T_HYST_MASK)
-		return -EINVAL;
-
-	t_hyst = (u8)data;
-
-	ret = adt7410_write_byte(chip, ADT7410_T_HYST, t_hyst);
-	if (ret)
-		return -EIO;
-
-	return ret;
-}
-
-static IIO_DEVICE_ATTR(event_mode,
-		       S_IRUGO | S_IWUSR,
-		       adt7410_show_event_mode, adt7410_set_event_mode, 0);
-static IIO_DEVICE_ATTR(available_event_modes,
-		       S_IRUGO,
-		       adt7410_show_available_event_modes, NULL, 0);
-static IIO_DEVICE_ATTR(fault_queue,
-		       S_IRUGO | S_IWUSR,
-		       adt7410_show_fault_queue, adt7410_set_fault_queue, 0);
-static IIO_DEVICE_ATTR(t_alarm_high,
-		       S_IRUGO | S_IWUSR,
-		       adt7410_show_t_alarm_high, adt7410_set_t_alarm_high, 0);
-static IIO_DEVICE_ATTR(t_alarm_low,
-		       S_IRUGO | S_IWUSR,
-		       adt7410_show_t_alarm_low, adt7410_set_t_alarm_low, 0);
-static IIO_DEVICE_ATTR(t_crit,
-		       S_IRUGO | S_IWUSR,
-		       adt7410_show_t_crit, adt7410_set_t_crit, 0);
-static IIO_DEVICE_ATTR(t_hyst,
-		       S_IRUGO | S_IWUSR,
-		       adt7410_show_t_hyst, adt7410_set_t_hyst, 0);
-
-static struct attribute *adt7410_event_int_attributes[] = {
-	&iio_dev_attr_event_mode.dev_attr.attr,
-	&iio_dev_attr_available_event_modes.dev_attr.attr,
-	&iio_dev_attr_fault_queue.dev_attr.attr,
-	&iio_dev_attr_t_alarm_high.dev_attr.attr,
-	&iio_dev_attr_t_alarm_low.dev_attr.attr,
-	&iio_dev_attr_t_crit.dev_attr.attr,
-	&iio_dev_attr_t_hyst.dev_attr.attr,
-	NULL,
-};
-
-static struct attribute_group adt7410_event_attribute_group = {
-	.attrs = adt7410_event_int_attributes,
-	.name = "events",
-};
-
-static const struct iio_info adt7410_info = {
-	.attrs = &adt7410_attribute_group,
-	.event_attrs = &adt7410_event_attribute_group,
-	.driver_module = THIS_MODULE,
-};
-
-/*
- * device probe and remove
- */
-
-static int adt7410_probe(struct device *dev, int irq,
-	const char *name, const struct adt7410_ops *ops)
-{
-	unsigned long *adt7410_platform_data = dev->platform_data;
-	unsigned long local_pdata[] = {0, 0};
-	struct adt7410_chip_info *chip;
-	struct iio_dev *indio_dev;
-	int ret = 0;
-
-	indio_dev = iio_device_alloc(sizeof(*chip));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-	chip = iio_priv(indio_dev);
-	/* this is only used for device removal purposes */
-	dev_set_drvdata(dev, indio_dev);
-
-	chip->dev = dev;
-	chip->ops = ops;
-
-	indio_dev->name = name;
-	indio_dev->dev.parent = dev;
-	indio_dev->info = &adt7410_info;
-	indio_dev->modes = INDIO_DIRECT_MODE;
-
-	if (!adt7410_platform_data)
-		adt7410_platform_data = local_pdata;
-
-	/* CT critcal temperature event. line 0 */
-	if (irq) {
-		ret = request_threaded_irq(irq,
-					   NULL,
-					   &adt7410_event_handler,
-					   IRQF_TRIGGER_LOW | IRQF_ONESHOT,
-					   name,
-					   indio_dev);
-		if (ret)
-			goto error_free_dev;
-	}
-
-	/* INT bound temperature alarm event. line 1 */
-	if (adt7410_platform_data[0]) {
-		ret = request_threaded_irq(adt7410_platform_data[0],
-					   NULL,
-					   &adt7410_event_handler,
-					   adt7410_platform_data[1] |
-					   IRQF_ONESHOT,
-					   name,
-					   indio_dev);
-		if (ret)
-			goto error_unreg_ct_irq;
-	}
-
-	ret = adt7410_read_byte(chip, ADT7410_CONFIG, &chip->config);
-	if (ret) {
-		ret = -EIO;
-		goto error_unreg_int_irq;
-	}
-
-	chip->config |= ADT7410_RESOLUTION;
-
-	if (irq && adt7410_platform_data[0]) {
-
-		/* set irq polarity low level */
-		chip->config &= ~ADT7410_CT_POLARITY;
-
-		if (adt7410_platform_data[1] & IRQF_TRIGGER_HIGH)
-			chip->config |= ADT7410_INT_POLARITY;
-		else
-			chip->config &= ~ADT7410_INT_POLARITY;
-	}
-
-	ret = adt7410_write_byte(chip, ADT7410_CONFIG, chip->config);
-	if (ret) {
-		ret = -EIO;
-		goto error_unreg_int_irq;
-	}
-	ret = iio_device_register(indio_dev);
-	if (ret)
-		goto error_unreg_int_irq;
-
-	dev_info(dev, "%s temperature sensor registered.\n",
-			 name);
-
-	return 0;
-
-error_unreg_int_irq:
-	free_irq(adt7410_platform_data[0], indio_dev);
-error_unreg_ct_irq:
-	free_irq(irq, indio_dev);
-error_free_dev:
-	iio_device_free(indio_dev);
-error_ret:
-	return ret;
-}
-
-static int adt7410_remove(struct device *dev, int irq)
-{
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	unsigned long *adt7410_platform_data = dev->platform_data;
-
-	iio_device_unregister(indio_dev);
-	if (adt7410_platform_data[0])
-		free_irq(adt7410_platform_data[0], indio_dev);
-	if (irq)
-		free_irq(irq, indio_dev);
-	iio_device_free(indio_dev);
-
-	return 0;
-}
-
-#if IS_ENABLED(CONFIG_I2C)
-
-static int adt7410_i2c_read_word(struct adt7410_chip_info *chip, u8 reg,
-	u16 *data)
-{
-	struct i2c_client *client = to_i2c_client(chip->dev);
-	int ret = 0;
-
-	ret = i2c_smbus_read_word_data(client, reg);
-	if (ret < 0) {
-		dev_err(&client->dev, "I2C read error\n");
-		return ret;
-	}
-
-	*data = swab16((u16)ret);
-
-	return 0;
-}
-
-static int adt7410_i2c_write_word(struct adt7410_chip_info *chip, u8 reg,
-	u16 data)
-{
-	struct i2c_client *client = to_i2c_client(chip->dev);
-	int ret = 0;
-
-	ret = i2c_smbus_write_word_data(client, reg, swab16(data));
-	if (ret < 0)
-		dev_err(&client->dev, "I2C write error\n");
-
-	return ret;
-}
-
-static int adt7410_i2c_read_byte(struct adt7410_chip_info *chip, u8 reg,
-	u8 *data)
-{
-	struct i2c_client *client = to_i2c_client(chip->dev);
-	int ret = 0;
-
-	ret = i2c_smbus_read_byte_data(client, reg);
-	if (ret < 0) {
-		dev_err(&client->dev, "I2C read error\n");
-		return ret;
-	}
-
-	*data = (u8)ret;
-
-	return 0;
-}
-
-static int adt7410_i2c_write_byte(struct adt7410_chip_info *chip, u8 reg,
-	u8 data)
-{
-	struct i2c_client *client = to_i2c_client(chip->dev);
-	int ret = 0;
-
-	ret = i2c_smbus_write_byte_data(client, reg, data);
-	if (ret < 0)
-		dev_err(&client->dev, "I2C write error\n");
-
-	return ret;
-}
-
-static const struct adt7410_ops adt7410_i2c_ops = {
-	.read_word = adt7410_i2c_read_word,
-	.write_word = adt7410_i2c_write_word,
-	.read_byte = adt7410_i2c_read_byte,
-	.write_byte = adt7410_i2c_write_byte,
-};
-
-static int adt7410_i2c_probe(struct i2c_client *client,
-	const struct i2c_device_id *id)
-{
-	return adt7410_probe(&client->dev, client->irq, id->name,
-		&adt7410_i2c_ops);
-}
-
-static int adt7410_i2c_remove(struct i2c_client *client)
-{
-	return adt7410_remove(&client->dev, client->irq);
-}
-
-static const struct i2c_device_id adt7410_id[] = {
-	{ "adt7410", 0 },
-	{}
-};
-
-MODULE_DEVICE_TABLE(i2c, adt7410_id);
-
-static struct i2c_driver adt7410_driver = {
-	.driver = {
-		.name = "adt7410",
-	},
-	.probe = adt7410_i2c_probe,
-	.remove = adt7410_i2c_remove,
-	.id_table = adt7410_id,
-};
-
-static int __init adt7410_i2c_init(void)
-{
-	return i2c_add_driver(&adt7410_driver);
-}
-
-static void __exit adt7410_i2c_exit(void)
-{
-	i2c_del_driver(&adt7410_driver);
-}
-
-#else
-
-static int  __init adt7410_i2c_init(void) { return 0; };
-static void __exit adt7410_i2c_exit(void) {};
-
-#endif
-
-#if IS_ENABLED(CONFIG_SPI_MASTER)
-
-static const u8 adt7371_reg_table[] = {
-	[ADT7410_TEMPERATURE]   = ADT7310_TEMPERATURE,
-	[ADT7410_STATUS]	= ADT7310_STATUS,
-	[ADT7410_CONFIG]	= ADT7310_CONFIG,
-	[ADT7410_T_ALARM_HIGH]	= ADT7310_T_ALARM_HIGH,
-	[ADT7410_T_ALARM_LOW]	= ADT7310_T_ALARM_LOW,
-	[ADT7410_T_CRIT]	= ADT7310_T_CRIT,
-	[ADT7410_T_HYST]	= ADT7310_T_HYST,
-	[ADT7410_ID]		= ADT7310_ID,
-};
-
-#define AD7310_COMMAND(reg) (adt7371_reg_table[(reg)] << ADT7310_CMD_REG_OFFSET)
-
-static int adt7310_spi_read_word(struct adt7410_chip_info *chip,
-	u8 reg, u16 *data)
-{
-	struct spi_device *spi = to_spi_device(chip->dev);
-	u8 command = AD7310_COMMAND(reg);
-	int ret = 0;
-
-	command |= ADT7310_CMD_READ;
-	ret = spi_write(spi, &command, sizeof(command));
-	if (ret < 0) {
-		dev_err(&spi->dev, "SPI write command error\n");
-		return ret;
-	}
-
-	ret = spi_read(spi, (u8 *)data, sizeof(*data));
-	if (ret < 0) {
-		dev_err(&spi->dev, "SPI read word error\n");
-		return ret;
-	}
-
-	*data = be16_to_cpu(*data);
-
-	return 0;
-}
-
-static int adt7310_spi_write_word(struct adt7410_chip_info *chip, u8 reg,
-	u16 data)
-{
-	struct spi_device *spi = to_spi_device(chip->dev);
-	u8 buf[3];
-	int ret = 0;
-
-	buf[0] = AD7310_COMMAND(reg);
-	buf[1] = (u8)(data >> 8);
-	buf[2] = (u8)(data & 0xFF);
-
-	ret = spi_write(spi, buf, 3);
-	if (ret < 0) {
-		dev_err(&spi->dev, "SPI write word error\n");
-		return ret;
-	}
-
-	return ret;
-}
-
-static int adt7310_spi_read_byte(struct adt7410_chip_info *chip, u8 reg,
-	u8 *data)
-{
-	struct spi_device *spi = to_spi_device(chip->dev);
-	u8 command = AD7310_COMMAND(reg);
-	int ret = 0;
-
-	command |= ADT7310_CMD_READ;
-	ret = spi_write(spi, &command, sizeof(command));
-	if (ret < 0) {
-		dev_err(&spi->dev, "SPI write command error\n");
-		return ret;
-	}
-
-	ret = spi_read(spi, data, sizeof(*data));
-	if (ret < 0) {
-		dev_err(&spi->dev, "SPI read byte error\n");
-		return ret;
-	}
-
-	return 0;
-}
-
-static int adt7310_spi_write_byte(struct adt7410_chip_info *chip, u8 reg,
-	u8 data)
-{
-	struct spi_device *spi = to_spi_device(chip->dev);
-	u8 buf[2];
-	int ret = 0;
-
-	buf[0] = AD7310_COMMAND(reg);
-	buf[1] = data;
-
-	ret = spi_write(spi, buf, 2);
-	if (ret < 0) {
-		dev_err(&spi->dev, "SPI write byte error\n");
-		return ret;
-	}
-
-	return ret;
-}
-
-static const struct adt7410_ops adt7310_spi_ops = {
-	.read_word = adt7310_spi_read_word,
-	.write_word = adt7310_spi_write_word,
-	.read_byte = adt7310_spi_read_byte,
-	.write_byte = adt7310_spi_write_byte,
-};
-
-static int adt7310_spi_probe(struct spi_device *spi)
-{
-	return adt7410_probe(&spi->dev, spi->irq,
-		spi_get_device_id(spi)->name, &adt7310_spi_ops);
-}
-
-static int adt7310_spi_remove(struct spi_device *spi)
-{
-	return adt7410_remove(&spi->dev, spi->irq);
-}
-
-static const struct spi_device_id adt7310_id[] = {
-	{ "adt7310", 0 },
-	{}
-};
-MODULE_DEVICE_TABLE(spi, adt7310_id);
-
-static struct spi_driver adt7310_driver = {
-	.driver = {
-		.name = "adt7310",
-		.owner = THIS_MODULE,
-	},
-	.probe = adt7310_spi_probe,
-	.remove = adt7310_spi_remove,
-	.id_table = adt7310_id,
-};
-
-static int __init adt7310_spi_init(void)
-{
-	return spi_register_driver(&adt7310_driver);
-}
-
-static void adt7310_spi_exit(void)
-{
-	spi_unregister_driver(&adt7310_driver);
-}
-
-#else
-
-static int __init adt7310_spi_init(void) { return 0; };
-static void adt7310_spi_exit(void) {};
-
-#endif
-
-static int __init adt7410_init(void)
-{
-	int ret;
-
-	ret = adt7310_spi_init();
-	if (ret)
-		return ret;
-
-	ret = adt7410_i2c_init();
-	if (ret)
-		adt7310_spi_exit();
-
-	return ret;
-}
-module_init(adt7410_init);
-
-static void __exit adt7410_exit(void)
-{
-	adt7410_i2c_exit();
-	adt7310_spi_exit();
-}
-module_exit(adt7410_exit);
-
-MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
-MODULE_DESCRIPTION("Analog Devices ADT7310/ADT7410 digital temperature sensor driver");
-MODULE_LICENSE("GPL v2");
-- 
1.8.0


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

* [lm-sensors] [PATCH 9/9] staging:iio: Remove adt7410 driver
@ 2013-02-15 16:57   ` Lars-Peter Clausen
  0 siblings, 0 replies; 56+ messages in thread
From: Lars-Peter Clausen @ 2013-02-15 16:57 UTC (permalink / raw)
  To: Jean Delvare, Guenter Roeck
  Cc: Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio,
	Lars-Peter Clausen

The adt7410 hwmon driver is feature wise more or less on par with the IIO
driver. So we can finally remove the IIO driver.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/staging/iio/adc/Kconfig   |    7 -
 drivers/staging/iio/adc/Makefile  |    1 -
 drivers/staging/iio/adc/adt7410.c | 1102 -------------------------------------
 3 files changed, 1110 deletions(-)
 delete mode 100644 drivers/staging/iio/adc/adt7410.c

diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig
index fb8c239..029ae54 100644
--- a/drivers/staging/iio/adc/Kconfig
+++ b/drivers/staging/iio/adc/Kconfig
@@ -90,13 +90,6 @@ config AD7192
 	  To compile this driver as a module, choose M here: the
 	  module will be called ad7192.
 
-config ADT7410
-	tristate "Analog Devices ADT7310/ADT7410 temperature sensor driver"
-	depends on I2C || SPI_MASTER
-	help
-	  Say yes here to build support for Analog Devices ADT7310/ADT7410
-	  temperature sensors.
-
 config AD7280
 	tristate "Analog Devices AD7280A Lithium Ion Battery Monitoring System"
 	depends on SPI
diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile
index d285596..3e9fb14 100644
--- a/drivers/staging/iio/adc/Makefile
+++ b/drivers/staging/iio/adc/Makefile
@@ -16,7 +16,6 @@ obj-$(CONFIG_AD7291) += ad7291.o
 obj-$(CONFIG_AD7780) += ad7780.o
 obj-$(CONFIG_AD7816) += ad7816.o
 obj-$(CONFIG_AD7192) += ad7192.o
-obj-$(CONFIG_ADT7410) += adt7410.o
 obj-$(CONFIG_AD7280) += ad7280a.o
 obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o
 obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o
diff --git a/drivers/staging/iio/adc/adt7410.c b/drivers/staging/iio/adc/adt7410.c
deleted file mode 100644
index 35455e1..0000000
--- a/drivers/staging/iio/adc/adt7410.c
+++ /dev/null
@@ -1,1102 +0,0 @@
-/*
- * ADT7410 digital temperature sensor driver supporting ADT7310/ADT7410
- *
- * Copyright 2010 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/list.h>
-#include <linux/i2c.h>
-#include <linux/spi/spi.h>
-#include <linux/module.h>
-
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-#include <linux/iio/events.h>
-
-/*
- * ADT7410 registers definition
- */
-
-#define ADT7410_TEMPERATURE		0
-#define ADT7410_STATUS			2
-#define ADT7410_CONFIG			3
-#define ADT7410_T_ALARM_HIGH		4
-#define ADT7410_T_ALARM_LOW		6
-#define ADT7410_T_CRIT			8
-#define ADT7410_T_HYST			0xA
-#define ADT7410_ID			0xB
-#define ADT7410_RESET			0x2F
-
-/*
- * ADT7310 registers definition
- */
-
-#define ADT7310_STATUS			0
-#define ADT7310_CONFIG			1
-#define ADT7310_TEMPERATURE		2
-#define ADT7310_ID			3
-#define ADT7310_T_CRIT			4
-#define ADT7310_T_HYST			5
-#define ADT7310_T_ALARM_HIGH		6
-#define ADT7310_T_ALARM_LOW		7
-
-/*
- * ADT7410 status
- */
-#define ADT7410_STAT_T_LOW		0x10
-#define ADT7410_STAT_T_HIGH		0x20
-#define ADT7410_STAT_T_CRIT		0x40
-#define ADT7410_STAT_NOT_RDY		0x80
-
-/*
- * ADT7410 config
- */
-#define ADT7410_FAULT_QUEUE_MASK	0x3
-#define ADT7410_CT_POLARITY		0x4
-#define ADT7410_INT_POLARITY		0x8
-#define ADT7410_EVENT_MODE		0x10
-#define ADT7410_MODE_MASK		0x60
-#define ADT7410_ONESHOT			0x20
-#define ADT7410_SPS			0x40
-#define ADT7410_PD			0x60
-#define ADT7410_RESOLUTION		0x80
-
-/*
- * ADT7410 masks
- */
-#define ADT7410_T16_VALUE_SIGN			0x8000
-#define ADT7410_T16_VALUE_FLOAT_OFFSET		7
-#define ADT7410_T16_VALUE_FLOAT_MASK		0x7F
-#define ADT7410_T13_VALUE_SIGN			0x1000
-#define ADT7410_T13_VALUE_OFFSET		3
-#define ADT7410_T13_VALUE_FLOAT_OFFSET		4
-#define ADT7410_T13_VALUE_FLOAT_MASK		0xF
-#define ADT7410_T_HYST_MASK			0xF
-#define ADT7410_DEVICE_ID_MASK			0xF
-#define ADT7410_MANUFACTORY_ID_MASK		0xF0
-#define ADT7410_MANUFACTORY_ID_OFFSET		4
-
-
-#define ADT7310_CMD_REG_MASK			0x28
-#define ADT7310_CMD_REG_OFFSET			3
-#define ADT7310_CMD_READ			0x40
-#define ADT7310_CMD_CON_READ			0x4
-
-#define ADT7410_IRQS				2
-
-/*
- * struct adt7410_chip_info - chip specifc information
- */
-
-struct adt7410_chip_info;
-
-struct adt7410_ops {
-	int (*read_word)(struct adt7410_chip_info *, u8 reg, u16 *data);
-	int (*write_word)(struct adt7410_chip_info *, u8 reg, u16 data);
-	int (*read_byte)(struct adt7410_chip_info *, u8 reg, u8 *data);
-	int (*write_byte)(struct adt7410_chip_info *, u8 reg, u8 data);
-};
-
-struct adt7410_chip_info {
-	struct device *dev;
-	u8  config;
-
-	const struct adt7410_ops *ops;
-};
-
-static int adt7410_read_word(struct adt7410_chip_info *chip, u8 reg, u16 *data)
-{
-	return chip->ops->read_word(chip, reg, data);
-}
-
-static int adt7410_write_word(struct adt7410_chip_info *chip, u8 reg, u16 data)
-{
-	return chip->ops->write_word(chip, reg, data);
-}
-
-static int adt7410_read_byte(struct adt7410_chip_info *chip, u8 reg, u8 *data)
-{
-	return chip->ops->read_byte(chip, reg, data);
-}
-
-static int adt7410_write_byte(struct adt7410_chip_info *chip, u8 reg, u8 data)
-{
-	return chip->ops->write_byte(chip, reg, data);
-}
-
-static ssize_t adt7410_show_mode(struct device *dev,
-		struct device_attribute *attr,
-		char *buf)
-{
-	struct iio_dev *dev_info = dev_to_iio_dev(dev);
-	struct adt7410_chip_info *chip = iio_priv(dev_info);
-	u8 config;
-
-	config = chip->config & ADT7410_MODE_MASK;
-
-	switch (config) {
-	case ADT7410_PD:
-		return sprintf(buf, "power-down\n");
-	case ADT7410_ONESHOT:
-		return sprintf(buf, "one-shot\n");
-	case ADT7410_SPS:
-		return sprintf(buf, "sps\n");
-	default:
-		return sprintf(buf, "full\n");
-	}
-}
-
-static ssize_t adt7410_store_mode(struct device *dev,
-		struct device_attribute *attr,
-		const char *buf,
-		size_t len)
-{
-	struct iio_dev *dev_info = dev_to_iio_dev(dev);
-	struct adt7410_chip_info *chip = iio_priv(dev_info);
-	u16 config;
-	int ret;
-
-	ret = adt7410_read_byte(chip, ADT7410_CONFIG, &chip->config);
-	if (ret)
-		return -EIO;
-
-	config = chip->config & (~ADT7410_MODE_MASK);
-	if (strcmp(buf, "power-down"))
-		config |= ADT7410_PD;
-	else if (strcmp(buf, "one-shot"))
-		config |= ADT7410_ONESHOT;
-	else if (strcmp(buf, "sps"))
-		config |= ADT7410_SPS;
-
-	ret = adt7410_write_byte(chip, ADT7410_CONFIG, config);
-	if (ret)
-		return -EIO;
-
-	chip->config = config;
-
-	return len;
-}
-
-static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
-		adt7410_show_mode,
-		adt7410_store_mode,
-		0);
-
-static ssize_t adt7410_show_available_modes(struct device *dev,
-		struct device_attribute *attr,
-		char *buf)
-{
-	return sprintf(buf, "full\none-shot\nsps\npower-down\n");
-}
-
-static IIO_DEVICE_ATTR(available_modes, S_IRUGO, adt7410_show_available_modes, NULL, 0);
-
-static ssize_t adt7410_show_resolution(struct device *dev,
-		struct device_attribute *attr,
-		char *buf)
-{
-	struct iio_dev *dev_info = dev_to_iio_dev(dev);
-	struct adt7410_chip_info *chip = iio_priv(dev_info);
-	int ret;
-	int bits;
-
-	ret = adt7410_read_byte(chip, ADT7410_CONFIG, &chip->config);
-	if (ret)
-		return -EIO;
-
-	if (chip->config & ADT7410_RESOLUTION)
-		bits = 16;
-	else
-		bits = 13;
-
-	return sprintf(buf, "%d bits\n", bits);
-}
-
-static ssize_t adt7410_store_resolution(struct device *dev,
-		struct device_attribute *attr,
-		const char *buf,
-		size_t len)
-{
-	struct iio_dev *dev_info = dev_to_iio_dev(dev);
-	struct adt7410_chip_info *chip = iio_priv(dev_info);
-	unsigned long data;
-	u16 config;
-	int ret;
-
-	ret = strict_strtoul(buf, 10, &data);
-	if (ret)
-		return -EINVAL;
-
-	ret = adt7410_read_byte(chip, ADT7410_CONFIG, &chip->config);
-	if (ret)
-		return -EIO;
-
-	config = chip->config & (~ADT7410_RESOLUTION);
-	if (data)
-		config |= ADT7410_RESOLUTION;
-
-	ret = adt7410_write_byte(chip, ADT7410_CONFIG, config);
-	if (ret)
-		return -EIO;
-
-	chip->config = config;
-
-	return len;
-}
-
-static IIO_DEVICE_ATTR(resolution, S_IRUGO | S_IWUSR,
-		adt7410_show_resolution,
-		adt7410_store_resolution,
-		0);
-
-static ssize_t adt7410_show_id(struct device *dev,
-		struct device_attribute *attr,
-		char *buf)
-{
-	struct iio_dev *dev_info = dev_to_iio_dev(dev);
-	struct adt7410_chip_info *chip = iio_priv(dev_info);
-	u8 id;
-	int ret;
-
-	ret = adt7410_read_byte(chip, ADT7410_ID, &id);
-	if (ret)
-		return -EIO;
-
-	return sprintf(buf, "device id: 0x%x\nmanufactory id: 0x%x\n",
-			id & ADT7410_DEVICE_ID_MASK,
-			(id & ADT7410_MANUFACTORY_ID_MASK) >> ADT7410_MANUFACTORY_ID_OFFSET);
-}
-
-static IIO_DEVICE_ATTR(id, S_IRUGO | S_IWUSR,
-		adt7410_show_id,
-		NULL,
-		0);
-
-static ssize_t adt7410_convert_temperature(struct adt7410_chip_info *chip,
-		u16 data, char *buf)
-{
-	char sign = ' ';
-
-	if (!(chip->config & ADT7410_RESOLUTION))
-		data &= ~0x7;
-
-	if (data & ADT7410_T16_VALUE_SIGN) {
-		/* convert supplement to positive value */
-		data = (u16)((ADT7410_T16_VALUE_SIGN << 1) - (u32)data);
-		sign = '-';
-	}
-	return sprintf(buf, "%c%d.%.7d\n", sign,
-			(data >> ADT7410_T16_VALUE_FLOAT_OFFSET),
-			(data & ADT7410_T16_VALUE_FLOAT_MASK) * 78125);
-}
-
-static ssize_t adt7410_show_value(struct device *dev,
-		struct device_attribute *attr,
-		char *buf)
-{
-	struct iio_dev *dev_info = dev_to_iio_dev(dev);
-	struct adt7410_chip_info *chip = iio_priv(dev_info);
-	u8 status;
-	u16 data;
-	int ret, i = 0;
-
-	do {
-		ret = adt7410_read_byte(chip, ADT7410_STATUS, &status);
-		if (ret)
-			return -EIO;
-		i++;
-		if (i = 10000)
-			return -EIO;
-	} while (status & ADT7410_STAT_NOT_RDY);
-
-	ret = adt7410_read_word(chip, ADT7410_TEMPERATURE, &data);
-	if (ret)
-		return -EIO;
-
-	return adt7410_convert_temperature(chip, data, buf);
-}
-
-static IIO_DEVICE_ATTR(value, S_IRUGO, adt7410_show_value, NULL, 0);
-
-static struct attribute *adt7410_attributes[] = {
-	&iio_dev_attr_available_modes.dev_attr.attr,
-	&iio_dev_attr_mode.dev_attr.attr,
-	&iio_dev_attr_resolution.dev_attr.attr,
-	&iio_dev_attr_id.dev_attr.attr,
-	&iio_dev_attr_value.dev_attr.attr,
-	NULL,
-};
-
-static const struct attribute_group adt7410_attribute_group = {
-	.attrs = adt7410_attributes,
-};
-
-static irqreturn_t adt7410_event_handler(int irq, void *private)
-{
-	struct iio_dev *indio_dev = private;
-	struct adt7410_chip_info *chip = iio_priv(indio_dev);
-	s64 timestamp = iio_get_time_ns();
-	u8 status;
-
-	if (adt7410_read_byte(chip, ADT7410_STATUS, &status))
-		return IRQ_HANDLED;
-
-	if (status & ADT7410_STAT_T_HIGH)
-		iio_push_event(indio_dev,
-			       IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0,
-						    IIO_EV_TYPE_THRESH,
-						    IIO_EV_DIR_RISING),
-			       timestamp);
-	if (status & ADT7410_STAT_T_LOW)
-		iio_push_event(indio_dev,
-			       IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0,
-						    IIO_EV_TYPE_THRESH,
-						    IIO_EV_DIR_FALLING),
-			       timestamp);
-	if (status & ADT7410_STAT_T_CRIT)
-		iio_push_event(indio_dev,
-			       IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0,
-						    IIO_EV_TYPE_THRESH,
-						    IIO_EV_DIR_RISING),
-			       timestamp);
-
-	return IRQ_HANDLED;
-}
-
-static ssize_t adt7410_show_event_mode(struct device *dev,
-		struct device_attribute *attr,
-		char *buf)
-{
-	struct iio_dev *dev_info = dev_to_iio_dev(dev);
-	struct adt7410_chip_info *chip = iio_priv(dev_info);
-	int ret;
-
-	ret = adt7410_read_byte(chip, ADT7410_CONFIG, &chip->config);
-	if (ret)
-		return -EIO;
-
-	if (chip->config & ADT7410_EVENT_MODE)
-		return sprintf(buf, "interrupt\n");
-	else
-		return sprintf(buf, "comparator\n");
-}
-
-static ssize_t adt7410_set_event_mode(struct device *dev,
-		struct device_attribute *attr,
-		const char *buf,
-		size_t len)
-{
-	struct iio_dev *dev_info = dev_to_iio_dev(dev);
-	struct adt7410_chip_info *chip = iio_priv(dev_info);
-	u16 config;
-	int ret;
-
-	ret = adt7410_read_byte(chip, ADT7410_CONFIG, &chip->config);
-	if (ret)
-		return -EIO;
-
-	config = chip->config &= ~ADT7410_EVENT_MODE;
-	if (strcmp(buf, "comparator") != 0)
-		config |= ADT7410_EVENT_MODE;
-
-	ret = adt7410_write_byte(chip, ADT7410_CONFIG, config);
-	if (ret)
-		return -EIO;
-
-	chip->config = config;
-
-	return ret;
-}
-
-static ssize_t adt7410_show_available_event_modes(struct device *dev,
-		struct device_attribute *attr,
-		char *buf)
-{
-	return sprintf(buf, "comparator\ninterrupt\n");
-}
-
-static ssize_t adt7410_show_fault_queue(struct device *dev,
-		struct device_attribute *attr,
-		char *buf)
-{
-	struct iio_dev *dev_info = dev_to_iio_dev(dev);
-	struct adt7410_chip_info *chip = iio_priv(dev_info);
-	int ret;
-
-	ret = adt7410_read_byte(chip, ADT7410_CONFIG, &chip->config);
-	if (ret)
-		return -EIO;
-
-	return sprintf(buf, "%d\n", chip->config & ADT7410_FAULT_QUEUE_MASK);
-}
-
-static ssize_t adt7410_set_fault_queue(struct device *dev,
-		struct device_attribute *attr,
-		const char *buf,
-		size_t len)
-{
-	struct iio_dev *dev_info = dev_to_iio_dev(dev);
-	struct adt7410_chip_info *chip = iio_priv(dev_info);
-	unsigned long data;
-	int ret;
-	u8 config;
-
-	ret = strict_strtoul(buf, 10, &data);
-	if (ret || data > 3)
-		return -EINVAL;
-
-	ret = adt7410_read_byte(chip, ADT7410_CONFIG, &chip->config);
-	if (ret)
-		return -EIO;
-
-	config = chip->config & ~ADT7410_FAULT_QUEUE_MASK;
-	config |= data;
-	ret = adt7410_write_byte(chip, ADT7410_CONFIG, config);
-	if (ret)
-		return -EIO;
-
-	chip->config = config;
-
-	return ret;
-}
-
-static inline ssize_t adt7410_show_t_bound(struct device *dev,
-		struct device_attribute *attr,
-		u8 bound_reg,
-		char *buf)
-{
-	struct iio_dev *dev_info = dev_to_iio_dev(dev);
-	struct adt7410_chip_info *chip = iio_priv(dev_info);
-	u16 data;
-	int ret;
-
-	ret = adt7410_read_word(chip, bound_reg, &data);
-	if (ret)
-		return -EIO;
-
-	return adt7410_convert_temperature(chip, data, buf);
-}
-
-static inline ssize_t adt7410_set_t_bound(struct device *dev,
-		struct device_attribute *attr,
-		u8 bound_reg,
-		const char *buf,
-		size_t len)
-{
-	struct iio_dev *dev_info = dev_to_iio_dev(dev);
-	struct adt7410_chip_info *chip = iio_priv(dev_info);
-	long tmp1, tmp2;
-	u16 data;
-	char *pos;
-	int ret;
-
-	pos = strchr(buf, '.');
-
-	ret = strict_strtol(buf, 10, &tmp1);
-
-	if (ret || tmp1 > 127 || tmp1 < -128)
-		return -EINVAL;
-
-	if (pos) {
-		len = strlen(pos);
-
-		if (chip->config & ADT7410_RESOLUTION) {
-			if (len > ADT7410_T16_VALUE_FLOAT_OFFSET)
-				len = ADT7410_T16_VALUE_FLOAT_OFFSET;
-			pos[len] = 0;
-			ret = strict_strtol(pos, 10, &tmp2);
-
-			if (!ret)
-				tmp2 = (tmp2 / 78125) * 78125;
-		} else {
-			if (len > ADT7410_T13_VALUE_FLOAT_OFFSET)
-				len = ADT7410_T13_VALUE_FLOAT_OFFSET;
-			pos[len] = 0;
-			ret = strict_strtol(pos, 10, &tmp2);
-
-			if (!ret)
-				tmp2 = (tmp2 / 625) * 625;
-		}
-	}
-
-	if (tmp1 < 0)
-		data = (u16)(-tmp1);
-	else
-		data = (u16)tmp1;
-
-	if (chip->config & ADT7410_RESOLUTION) {
-		data = (data << ADT7410_T16_VALUE_FLOAT_OFFSET) |
-			(tmp2 & ADT7410_T16_VALUE_FLOAT_MASK);
-
-		if (tmp1 < 0)
-			/* convert positive value to supplyment */
-			data = (u16)((ADT7410_T16_VALUE_SIGN << 1) - (u32)data);
-	} else {
-		data = (data << ADT7410_T13_VALUE_FLOAT_OFFSET) |
-			(tmp2 & ADT7410_T13_VALUE_FLOAT_MASK);
-
-		if (tmp1 < 0)
-			/* convert positive value to supplyment */
-			data = (ADT7410_T13_VALUE_SIGN << 1) - data;
-		data <<= ADT7410_T13_VALUE_OFFSET;
-	}
-
-	ret = adt7410_write_word(chip, bound_reg, data);
-	if (ret)
-		return -EIO;
-
-	return ret;
-}
-
-static ssize_t adt7410_show_t_alarm_high(struct device *dev,
-		struct device_attribute *attr,
-		char *buf)
-{
-	return adt7410_show_t_bound(dev, attr,
-			ADT7410_T_ALARM_HIGH, buf);
-}
-
-static inline ssize_t adt7410_set_t_alarm_high(struct device *dev,
-		struct device_attribute *attr,
-		const char *buf,
-		size_t len)
-{
-	return adt7410_set_t_bound(dev, attr,
-			ADT7410_T_ALARM_HIGH, buf, len);
-}
-
-static ssize_t adt7410_show_t_alarm_low(struct device *dev,
-		struct device_attribute *attr,
-		char *buf)
-{
-	return adt7410_show_t_bound(dev, attr,
-			ADT7410_T_ALARM_LOW, buf);
-}
-
-static inline ssize_t adt7410_set_t_alarm_low(struct device *dev,
-		struct device_attribute *attr,
-		const char *buf,
-		size_t len)
-{
-	return adt7410_set_t_bound(dev, attr,
-			ADT7410_T_ALARM_LOW, buf, len);
-}
-
-static ssize_t adt7410_show_t_crit(struct device *dev,
-		struct device_attribute *attr,
-		char *buf)
-{
-	return adt7410_show_t_bound(dev, attr,
-			ADT7410_T_CRIT, buf);
-}
-
-static inline ssize_t adt7410_set_t_crit(struct device *dev,
-		struct device_attribute *attr,
-		const char *buf,
-		size_t len)
-{
-	return adt7410_set_t_bound(dev, attr,
-			ADT7410_T_CRIT, buf, len);
-}
-
-static ssize_t adt7410_show_t_hyst(struct device *dev,
-		struct device_attribute *attr,
-		char *buf)
-{
-	struct iio_dev *dev_info = dev_to_iio_dev(dev);
-	struct adt7410_chip_info *chip = iio_priv(dev_info);
-	int ret;
-	u8 t_hyst;
-
-	ret = adt7410_read_byte(chip, ADT7410_T_HYST, &t_hyst);
-	if (ret)
-		return -EIO;
-
-	return sprintf(buf, "%d\n", t_hyst & ADT7410_T_HYST_MASK);
-}
-
-static inline ssize_t adt7410_set_t_hyst(struct device *dev,
-		struct device_attribute *attr,
-		const char *buf,
-		size_t len)
-{
-	struct iio_dev *dev_info = dev_to_iio_dev(dev);
-	struct adt7410_chip_info *chip = iio_priv(dev_info);
-	int ret;
-	unsigned long data;
-	u8 t_hyst;
-
-	ret = strict_strtol(buf, 10, &data);
-
-	if (ret || data > ADT7410_T_HYST_MASK)
-		return -EINVAL;
-
-	t_hyst = (u8)data;
-
-	ret = adt7410_write_byte(chip, ADT7410_T_HYST, t_hyst);
-	if (ret)
-		return -EIO;
-
-	return ret;
-}
-
-static IIO_DEVICE_ATTR(event_mode,
-		       S_IRUGO | S_IWUSR,
-		       adt7410_show_event_mode, adt7410_set_event_mode, 0);
-static IIO_DEVICE_ATTR(available_event_modes,
-		       S_IRUGO,
-		       adt7410_show_available_event_modes, NULL, 0);
-static IIO_DEVICE_ATTR(fault_queue,
-		       S_IRUGO | S_IWUSR,
-		       adt7410_show_fault_queue, adt7410_set_fault_queue, 0);
-static IIO_DEVICE_ATTR(t_alarm_high,
-		       S_IRUGO | S_IWUSR,
-		       adt7410_show_t_alarm_high, adt7410_set_t_alarm_high, 0);
-static IIO_DEVICE_ATTR(t_alarm_low,
-		       S_IRUGO | S_IWUSR,
-		       adt7410_show_t_alarm_low, adt7410_set_t_alarm_low, 0);
-static IIO_DEVICE_ATTR(t_crit,
-		       S_IRUGO | S_IWUSR,
-		       adt7410_show_t_crit, adt7410_set_t_crit, 0);
-static IIO_DEVICE_ATTR(t_hyst,
-		       S_IRUGO | S_IWUSR,
-		       adt7410_show_t_hyst, adt7410_set_t_hyst, 0);
-
-static struct attribute *adt7410_event_int_attributes[] = {
-	&iio_dev_attr_event_mode.dev_attr.attr,
-	&iio_dev_attr_available_event_modes.dev_attr.attr,
-	&iio_dev_attr_fault_queue.dev_attr.attr,
-	&iio_dev_attr_t_alarm_high.dev_attr.attr,
-	&iio_dev_attr_t_alarm_low.dev_attr.attr,
-	&iio_dev_attr_t_crit.dev_attr.attr,
-	&iio_dev_attr_t_hyst.dev_attr.attr,
-	NULL,
-};
-
-static struct attribute_group adt7410_event_attribute_group = {
-	.attrs = adt7410_event_int_attributes,
-	.name = "events",
-};
-
-static const struct iio_info adt7410_info = {
-	.attrs = &adt7410_attribute_group,
-	.event_attrs = &adt7410_event_attribute_group,
-	.driver_module = THIS_MODULE,
-};
-
-/*
- * device probe and remove
- */
-
-static int adt7410_probe(struct device *dev, int irq,
-	const char *name, const struct adt7410_ops *ops)
-{
-	unsigned long *adt7410_platform_data = dev->platform_data;
-	unsigned long local_pdata[] = {0, 0};
-	struct adt7410_chip_info *chip;
-	struct iio_dev *indio_dev;
-	int ret = 0;
-
-	indio_dev = iio_device_alloc(sizeof(*chip));
-	if (indio_dev = NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-	chip = iio_priv(indio_dev);
-	/* this is only used for device removal purposes */
-	dev_set_drvdata(dev, indio_dev);
-
-	chip->dev = dev;
-	chip->ops = ops;
-
-	indio_dev->name = name;
-	indio_dev->dev.parent = dev;
-	indio_dev->info = &adt7410_info;
-	indio_dev->modes = INDIO_DIRECT_MODE;
-
-	if (!adt7410_platform_data)
-		adt7410_platform_data = local_pdata;
-
-	/* CT critcal temperature event. line 0 */
-	if (irq) {
-		ret = request_threaded_irq(irq,
-					   NULL,
-					   &adt7410_event_handler,
-					   IRQF_TRIGGER_LOW | IRQF_ONESHOT,
-					   name,
-					   indio_dev);
-		if (ret)
-			goto error_free_dev;
-	}
-
-	/* INT bound temperature alarm event. line 1 */
-	if (adt7410_platform_data[0]) {
-		ret = request_threaded_irq(adt7410_platform_data[0],
-					   NULL,
-					   &adt7410_event_handler,
-					   adt7410_platform_data[1] |
-					   IRQF_ONESHOT,
-					   name,
-					   indio_dev);
-		if (ret)
-			goto error_unreg_ct_irq;
-	}
-
-	ret = adt7410_read_byte(chip, ADT7410_CONFIG, &chip->config);
-	if (ret) {
-		ret = -EIO;
-		goto error_unreg_int_irq;
-	}
-
-	chip->config |= ADT7410_RESOLUTION;
-
-	if (irq && adt7410_platform_data[0]) {
-
-		/* set irq polarity low level */
-		chip->config &= ~ADT7410_CT_POLARITY;
-
-		if (adt7410_platform_data[1] & IRQF_TRIGGER_HIGH)
-			chip->config |= ADT7410_INT_POLARITY;
-		else
-			chip->config &= ~ADT7410_INT_POLARITY;
-	}
-
-	ret = adt7410_write_byte(chip, ADT7410_CONFIG, chip->config);
-	if (ret) {
-		ret = -EIO;
-		goto error_unreg_int_irq;
-	}
-	ret = iio_device_register(indio_dev);
-	if (ret)
-		goto error_unreg_int_irq;
-
-	dev_info(dev, "%s temperature sensor registered.\n",
-			 name);
-
-	return 0;
-
-error_unreg_int_irq:
-	free_irq(adt7410_platform_data[0], indio_dev);
-error_unreg_ct_irq:
-	free_irq(irq, indio_dev);
-error_free_dev:
-	iio_device_free(indio_dev);
-error_ret:
-	return ret;
-}
-
-static int adt7410_remove(struct device *dev, int irq)
-{
-	struct iio_dev *indio_dev = dev_get_drvdata(dev);
-	unsigned long *adt7410_platform_data = dev->platform_data;
-
-	iio_device_unregister(indio_dev);
-	if (adt7410_platform_data[0])
-		free_irq(adt7410_platform_data[0], indio_dev);
-	if (irq)
-		free_irq(irq, indio_dev);
-	iio_device_free(indio_dev);
-
-	return 0;
-}
-
-#if IS_ENABLED(CONFIG_I2C)
-
-static int adt7410_i2c_read_word(struct adt7410_chip_info *chip, u8 reg,
-	u16 *data)
-{
-	struct i2c_client *client = to_i2c_client(chip->dev);
-	int ret = 0;
-
-	ret = i2c_smbus_read_word_data(client, reg);
-	if (ret < 0) {
-		dev_err(&client->dev, "I2C read error\n");
-		return ret;
-	}
-
-	*data = swab16((u16)ret);
-
-	return 0;
-}
-
-static int adt7410_i2c_write_word(struct adt7410_chip_info *chip, u8 reg,
-	u16 data)
-{
-	struct i2c_client *client = to_i2c_client(chip->dev);
-	int ret = 0;
-
-	ret = i2c_smbus_write_word_data(client, reg, swab16(data));
-	if (ret < 0)
-		dev_err(&client->dev, "I2C write error\n");
-
-	return ret;
-}
-
-static int adt7410_i2c_read_byte(struct adt7410_chip_info *chip, u8 reg,
-	u8 *data)
-{
-	struct i2c_client *client = to_i2c_client(chip->dev);
-	int ret = 0;
-
-	ret = i2c_smbus_read_byte_data(client, reg);
-	if (ret < 0) {
-		dev_err(&client->dev, "I2C read error\n");
-		return ret;
-	}
-
-	*data = (u8)ret;
-
-	return 0;
-}
-
-static int adt7410_i2c_write_byte(struct adt7410_chip_info *chip, u8 reg,
-	u8 data)
-{
-	struct i2c_client *client = to_i2c_client(chip->dev);
-	int ret = 0;
-
-	ret = i2c_smbus_write_byte_data(client, reg, data);
-	if (ret < 0)
-		dev_err(&client->dev, "I2C write error\n");
-
-	return ret;
-}
-
-static const struct adt7410_ops adt7410_i2c_ops = {
-	.read_word = adt7410_i2c_read_word,
-	.write_word = adt7410_i2c_write_word,
-	.read_byte = adt7410_i2c_read_byte,
-	.write_byte = adt7410_i2c_write_byte,
-};
-
-static int adt7410_i2c_probe(struct i2c_client *client,
-	const struct i2c_device_id *id)
-{
-	return adt7410_probe(&client->dev, client->irq, id->name,
-		&adt7410_i2c_ops);
-}
-
-static int adt7410_i2c_remove(struct i2c_client *client)
-{
-	return adt7410_remove(&client->dev, client->irq);
-}
-
-static const struct i2c_device_id adt7410_id[] = {
-	{ "adt7410", 0 },
-	{}
-};
-
-MODULE_DEVICE_TABLE(i2c, adt7410_id);
-
-static struct i2c_driver adt7410_driver = {
-	.driver = {
-		.name = "adt7410",
-	},
-	.probe = adt7410_i2c_probe,
-	.remove = adt7410_i2c_remove,
-	.id_table = adt7410_id,
-};
-
-static int __init adt7410_i2c_init(void)
-{
-	return i2c_add_driver(&adt7410_driver);
-}
-
-static void __exit adt7410_i2c_exit(void)
-{
-	i2c_del_driver(&adt7410_driver);
-}
-
-#else
-
-static int  __init adt7410_i2c_init(void) { return 0; };
-static void __exit adt7410_i2c_exit(void) {};
-
-#endif
-
-#if IS_ENABLED(CONFIG_SPI_MASTER)
-
-static const u8 adt7371_reg_table[] = {
-	[ADT7410_TEMPERATURE]   = ADT7310_TEMPERATURE,
-	[ADT7410_STATUS]	= ADT7310_STATUS,
-	[ADT7410_CONFIG]	= ADT7310_CONFIG,
-	[ADT7410_T_ALARM_HIGH]	= ADT7310_T_ALARM_HIGH,
-	[ADT7410_T_ALARM_LOW]	= ADT7310_T_ALARM_LOW,
-	[ADT7410_T_CRIT]	= ADT7310_T_CRIT,
-	[ADT7410_T_HYST]	= ADT7310_T_HYST,
-	[ADT7410_ID]		= ADT7310_ID,
-};
-
-#define AD7310_COMMAND(reg) (adt7371_reg_table[(reg)] << ADT7310_CMD_REG_OFFSET)
-
-static int adt7310_spi_read_word(struct adt7410_chip_info *chip,
-	u8 reg, u16 *data)
-{
-	struct spi_device *spi = to_spi_device(chip->dev);
-	u8 command = AD7310_COMMAND(reg);
-	int ret = 0;
-
-	command |= ADT7310_CMD_READ;
-	ret = spi_write(spi, &command, sizeof(command));
-	if (ret < 0) {
-		dev_err(&spi->dev, "SPI write command error\n");
-		return ret;
-	}
-
-	ret = spi_read(spi, (u8 *)data, sizeof(*data));
-	if (ret < 0) {
-		dev_err(&spi->dev, "SPI read word error\n");
-		return ret;
-	}
-
-	*data = be16_to_cpu(*data);
-
-	return 0;
-}
-
-static int adt7310_spi_write_word(struct adt7410_chip_info *chip, u8 reg,
-	u16 data)
-{
-	struct spi_device *spi = to_spi_device(chip->dev);
-	u8 buf[3];
-	int ret = 0;
-
-	buf[0] = AD7310_COMMAND(reg);
-	buf[1] = (u8)(data >> 8);
-	buf[2] = (u8)(data & 0xFF);
-
-	ret = spi_write(spi, buf, 3);
-	if (ret < 0) {
-		dev_err(&spi->dev, "SPI write word error\n");
-		return ret;
-	}
-
-	return ret;
-}
-
-static int adt7310_spi_read_byte(struct adt7410_chip_info *chip, u8 reg,
-	u8 *data)
-{
-	struct spi_device *spi = to_spi_device(chip->dev);
-	u8 command = AD7310_COMMAND(reg);
-	int ret = 0;
-
-	command |= ADT7310_CMD_READ;
-	ret = spi_write(spi, &command, sizeof(command));
-	if (ret < 0) {
-		dev_err(&spi->dev, "SPI write command error\n");
-		return ret;
-	}
-
-	ret = spi_read(spi, data, sizeof(*data));
-	if (ret < 0) {
-		dev_err(&spi->dev, "SPI read byte error\n");
-		return ret;
-	}
-
-	return 0;
-}
-
-static int adt7310_spi_write_byte(struct adt7410_chip_info *chip, u8 reg,
-	u8 data)
-{
-	struct spi_device *spi = to_spi_device(chip->dev);
-	u8 buf[2];
-	int ret = 0;
-
-	buf[0] = AD7310_COMMAND(reg);
-	buf[1] = data;
-
-	ret = spi_write(spi, buf, 2);
-	if (ret < 0) {
-		dev_err(&spi->dev, "SPI write byte error\n");
-		return ret;
-	}
-
-	return ret;
-}
-
-static const struct adt7410_ops adt7310_spi_ops = {
-	.read_word = adt7310_spi_read_word,
-	.write_word = adt7310_spi_write_word,
-	.read_byte = adt7310_spi_read_byte,
-	.write_byte = adt7310_spi_write_byte,
-};
-
-static int adt7310_spi_probe(struct spi_device *spi)
-{
-	return adt7410_probe(&spi->dev, spi->irq,
-		spi_get_device_id(spi)->name, &adt7310_spi_ops);
-}
-
-static int adt7310_spi_remove(struct spi_device *spi)
-{
-	return adt7410_remove(&spi->dev, spi->irq);
-}
-
-static const struct spi_device_id adt7310_id[] = {
-	{ "adt7310", 0 },
-	{}
-};
-MODULE_DEVICE_TABLE(spi, adt7310_id);
-
-static struct spi_driver adt7310_driver = {
-	.driver = {
-		.name = "adt7310",
-		.owner = THIS_MODULE,
-	},
-	.probe = adt7310_spi_probe,
-	.remove = adt7310_spi_remove,
-	.id_table = adt7310_id,
-};
-
-static int __init adt7310_spi_init(void)
-{
-	return spi_register_driver(&adt7310_driver);
-}
-
-static void adt7310_spi_exit(void)
-{
-	spi_unregister_driver(&adt7310_driver);
-}
-
-#else
-
-static int __init adt7310_spi_init(void) { return 0; };
-static void adt7310_spi_exit(void) {};
-
-#endif
-
-static int __init adt7410_init(void)
-{
-	int ret;
-
-	ret = adt7310_spi_init();
-	if (ret)
-		return ret;
-
-	ret = adt7410_i2c_init();
-	if (ret)
-		adt7310_spi_exit();
-
-	return ret;
-}
-module_init(adt7410_init);
-
-static void __exit adt7410_exit(void)
-{
-	adt7410_i2c_exit();
-	adt7310_spi_exit();
-}
-module_exit(adt7410_exit);
-
-MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
-MODULE_DESCRIPTION("Analog Devices ADT7310/ADT7410 digital temperature sensor driver");
-MODULE_LICENSE("GPL v2");
-- 
1.8.0


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

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

* Re: [PATCH 7/9] hwmon: (adt7410) Add support for the adt7310/adt7320
  2013-02-15 16:57   ` [lm-sensors] [PATCH 7/9] hwmon: (adt7410) Add =?utf-8?q?_support_for_the_adt73 Lars-Peter Clausen
@ 2013-02-15 20:05     ` Hartmut Knaack
  -1 siblings, 0 replies; 56+ messages in thread
From: Hartmut Knaack @ 2013-02-15 20:05 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Jean Delvare, Guenter Roeck, Jonathan Cameron, lm-sensors, linux-iio

I had a quick look over your patches and found some minor typo, see below. I will apply all the patches to see the result.
Also keep in mind to add some changes to Documentation/hwmon/adt7410 (and add an adt7310 as well?).

Lars-Peter Clausen schrieb:
<...>
> diff --git a/drivers/hwmon/adt7310.c b/drivers/hwmon/adt7310.c
> new file mode 100644
> index 0000000..0483e6c
> --- /dev/null
> +++ b/drivers/hwmon/adt7310.c
> @@ -0,0 +1,160 @@
> +/*
> + * ADT7310/ADT7310 digital temperature sensor driver
> + *
> + * Copyright 2010-2013 Analog Devices Inc.
> + *   Author: Lars-Peter Clausen <lars@metafoo.de>
> + *
> + * Licensed under the GPL-2 or later.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/spi/spi.h>
> +
> +#include "adt7x10.h"
> +
> +static const u8 adt7371_reg_table[] = {
> +	[ADT7410_TEMPERATURE]   = ADT7310_TEMPERATURE,
> +	[ADT7410_STATUS]	= ADT7310_STATUS,
> +	[ADT7410_CONFIG]	= ADT7310_CONFIG,
> +	[ADT7410_T_ALARM_HIGH]	= ADT7310_T_ALARM_HIGH,
> +	[ADT7410_T_ALARM_LOW]	= ADT7310_T_ALARM_LOW,
> +	[ADT7410_T_CRIT]	= ADT7310_T_CRIT,
> +	[ADT7410_T_HYST]	= ADT7310_T_HYST,
> +	[ADT7410_ID]		= ADT7310_ID,
> +};
Just out of curiousity, whats the reason for the name adt7371 here?
> +
> +#define ADT7310_CMD_REG_MASK			0x28
> +#define ADT7310_CMD_REG_OFFSET			3
> +#define ADT7310_CMD_READ			0x40
> +#define ADT7310_CMD_CON_READ			0x4
> +
> +#define AD7310_COMMAND(reg) (adt7371_reg_table[(reg)] << ADT7310_CMD_REG_OFFSET)
> +
> +static int adt7310_spi_read_word(struct device *dev,
> +	u8 reg, u16 *data)
> +{
> +	struct spi_device *spi = to_spi_device(dev);
> +	u8 command = AD7310_COMMAND(reg);
> +	int ret = 0;
> +
> +	command |= ADT7310_CMD_READ;
> +	ret = spi_write(spi, &command, sizeof(command));
> +	if (ret < 0) {
> +		dev_err(dev, "SPI write command error\n");
> +		return ret;
> +	}
> +
> +	ret = spi_read(spi, (u8 *)data, sizeof(*data));
> +	if (ret < 0) {
> +		dev_err(dev, "SPI read word error\n");
> +		return ret;
> +	}
> +
> +	*data = be16_to_cpu(*data);
> +
> +	return 0;
> +}
> +
> +static int adt7310_spi_write_word(struct device *dev, u8 reg,
> +	u16 data)
> +{
> +	struct spi_device *spi = to_spi_device(dev);
> +	u8 buf[3];
> +	int ret = 0;
> +
> +	buf[0] = AD7310_COMMAND(reg);
> +	buf[1] = (u8)(data >> 8);
> +	buf[2] = (u8)(data & 0xFF);
> +
> +	ret = spi_write(spi, buf, 3);
> +	if (ret < 0) {
> +		dev_err(dev, "SPI write word error\n");
> +		return ret;
> +	}
> +
> +	return ret;
> +}
> +
> +static int adt7310_spi_read_byte(struct device *dev, u8 reg,
> +	u8 *data)
> +{
> +	struct spi_device *spi = to_spi_device(dev);
> +	u8 command = AD7310_COMMAND(reg);
> +	int ret = 0;
> +
> +	command |= ADT7310_CMD_READ;
> +	ret = spi_write(spi, &command, sizeof(command));
> +	if (ret < 0) {
> +		dev_err(dev, "SPI write command error\n");
> +		return ret;
> +	}
> +
> +	ret = spi_read(spi, data, sizeof(*data));
> +	if (ret < 0) {
> +		dev_err(dev, "SPI read byte error\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int adt7310_spi_write_byte(struct device *dev, u8 reg,
> +	u8 data)
> +{
> +	struct spi_device *spi = to_spi_device(dev);
> +	u8 buf[2];
> +	int ret = 0;
> +
> +	buf[0] = AD7310_COMMAND(reg);
> +	buf[1] = data;
> +
> +	ret = spi_write(spi, buf, 2);
> +	if (ret < 0) {
> +		dev_err(dev, "SPI write byte error\n");
> +		return ret;
> +	}
> +
> +	return ret;
> +}
> +
> +static const struct adt7410_ops adt7310_spi_ops = {
> +	.read_word = adt7310_spi_read_word,
> +	.write_word = adt7310_spi_write_word,
> +	.read_byte = adt7310_spi_read_byte,
> +	.write_byte = adt7310_spi_write_byte,
> +};
> +
> +static int adt7310_spi_probe(struct spi_device *spi)
> +{
> +	return adt7410_probe(&spi->dev, spi_get_device_id(spi)->name,
> +			&adt7310_spi_ops);
> +}
> +
> +static int adt7310_spi_remove(struct spi_device *spi)
> +{
> +	return adt7410_remove(&spi->dev);
> +}
> +
> +static const struct spi_device_id adt7310_id[] = {
> +	{ "adt7310", 0 },
> +	{ "adt7320", 0 },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(spi, adt7310_id);
> +
> +static struct spi_driver adt7310_driver = {
> +	.driver = {
> +		.name = "adt7310",
> +		.owner = THIS_MODULE,
> +		.pm	= ADT7410_DEV_PM_OPS,
> +	},
> +	.probe = adt7310_spi_probe,
> +	.remove = adt7310_spi_remove,
> +	.id_table = adt7310_id,
> +};
> +module_spi_driver(adt7310_driver);
> +
> +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
> +MODULE_DESCRIPTION("ADT7310/ADT7420 driver");
This should be ADT7310/ADT7320, right?
> +MODULE_LICENSE("GPL");
<...>
> --- /dev/null
> +++ b/drivers/hwmon/adt7x10.c
> @@ -0,0 +1,476 @@
> +/*
> + * adt7410.c - Part of lm_sensors, Linux kernel modules for hardware
> + *	 monitoring
> + * This driver handles the ADT7410 and compatible digital temperature sensors.
> + * Hartmut Knaack <knaack.h@gmx.de> 2012-07-22
> + * based on lm75.c by Frodo Looijaard <frodol@dds.nl>
> + * and adt7410.c from iio-staging by Sonic Zhang <sonic.zhang@analog.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/slab.h>
> +#include <linux/jiffies.h>
> +#include <linux/hwmon.h>
> +#include <linux/hwmon-sysfs.h>
> +#include <linux/err.h>
> +#include <linux/mutex.h>
> +#include <linux/delay.h>
> +
> +#include "adt7x10.h"
> +
> +/*
> + * ADT7410 status
> + */
> +#define ADT7410_STAT_T_LOW		(1 << 4)
> +#define ADT7410_STAT_T_HIGH		(1 << 5)
> +#define ADT7410_STAT_T_CRIT		(1 << 6)
> +#define ADT7410_STAT_NOT_RDY		(1 << 7)
> +
> +/*
> + * ADT7410 config
> + */
> +#define ADT7410_FAULT_QUEUE_MASK	(1 << 0 | 1 << 1)
> +#define ADT7410_CT_POLARITY		(1 << 2)
> +#define ADT7410_INT_POLARITY		(1 << 3)
> +#define ADT7410_EVENT_MODE		(1 << 4)
> +#define ADT7410_MODE_MASK		(1 << 5 | 1 << 6)
> +#define ADT7410_FULL			(0 << 5 | 0 << 6)
> +#define ADT7410_PD			(1 << 5 | 1 << 6)
> +#define ADT7410_RESOLUTION		(1 << 7)
> +
> +/*
> + * ADT7410 masks
> + */
> +#define ADT7410_T13_VALUE_MASK			0xFFF8
> +#define ADT7410_T_HYST_MASK			0xF
> +
> +/* straight from the datasheet */
> +#define ADT7410_TEMP_MIN (-55000)
> +#define ADT7410_TEMP_MAX 150000
> +
> +/* Each client has this additional data */
> +struct adt7410_data {
> +	const struct adt7410_ops *ops;
> +	const char		*name;
> +	struct device		*hwmon_dev;
> +	struct mutex		update_lock;
> +	u8			config;
> +	u8			oldconfig;
> +	bool			valid;		/* true if registers valid */
> +	unsigned long		last_updated;	/* In jiffies */
> +	s16			temp[4];	/* Register values,
> +						   0 = input
> +						   1 = high
> +						   2 = low
> +						   3 = critical */
> +	u8			hyst;		/* hysteresis offset */
> +};
> +
> +static int adt7410_read_word(struct device *dev, u8 reg, u16 *data)
> +{
> +	struct adt7410_data *d = dev_get_drvdata(dev);
> +	return d->ops->read_word(dev, reg, data);
> +}
> +
> +static int adt7410_write_word(struct device *dev, u8 reg, u16 data)
> +{
> +	struct adt7410_data *d = dev_get_drvdata(dev);
> +	return d->ops->write_word(dev, reg, data);
> +}
> +
> +static int adt7410_read_byte(struct device *dev, u8 reg, u8 *data)
> +{
> +	struct adt7410_data *d = dev_get_drvdata(dev);
> +	return d->ops->read_byte(dev, reg, data);
> +}
> +
> +static int adt7410_write_byte(struct device *dev, u8 reg, u8 data)
> +{
> +	struct adt7410_data *d = dev_get_drvdata(dev);
> +	return d->ops->write_byte(dev, reg, data);
> +}
> +
> +static const u8 ADT7410_REG_TEMP[4] = {
> +	ADT7410_TEMPERATURE,		/* input */
> +	ADT7410_T_ALARM_HIGH,		/* high */
> +	ADT7410_T_ALARM_LOW,		/* low */
> +	ADT7410_T_CRIT,			/* critical */
> +};
> +
> +/*
> + * adt7410 register access by I2C
> + */
> +static int adt7410_temp_ready(struct device *dev)
> +{
> +	int i, ret;
> +	u8 status;
> +
> +	for (i = 0; i < 6; i++) {
> +		ret = adt7410_read_byte(dev, ADT7410_STATUS, &status);
> +		if (ret)
> +			return ret;
> +		if (!(status & ADT7410_STAT_NOT_RDY))
> +			return 0;
> +		msleep(60);
> +	}
> +	return -ETIMEDOUT;
> +}
> +
> +static int adt7410_update_temp(struct device *dev)
> +{
> +	struct adt7410_data *data = dev_get_drvdata(dev);
> +	int ret = 0;
> +
> +	mutex_lock(&data->update_lock);
> +
> +	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
> +	    || !data->valid) {
> +
> +		dev_dbg(dev, "Starting update\n");
> +
> +		ret = adt7410_temp_ready(dev); /* check for new value */
> +		if (ret)
> +			goto abort;
> +
> +		ret = adt7410_read_word(dev, ADT7410_REG_TEMP[0],
> +					&data->temp[0]);
> +		if (ret) {
> +			dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
> +				ADT7410_REG_TEMP[0], ret);
> +			goto abort;
> +		}
> +		data->last_updated = jiffies;
> +		data->valid = true;
> +	}
> +
> +abort:
> +	mutex_unlock(&data->update_lock);
> +	return ret;
> +}
> +
> +static int adt7410_fill_cache(struct device *dev)
> +{
> +	struct adt7410_data *data = dev_get_drvdata(dev);
> +	int ret;
> +	int i;
> +
> +	for (i = 1; i < ARRAY_SIZE(data->temp); i++) {
> +		ret = adt7410_read_word(dev, ADT7410_REG_TEMP[i],
> +					&data->temp[i]);
> +		if (ret) {
> +			dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
> +				ADT7410_REG_TEMP[0], ret);
> +			return ret;
> +		}
> +	}
> +
> +	ret = adt7410_read_byte(dev, ADT7410_T_HYST, &data->hyst);
> +	if (ret) {
> +		dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
> +				ADT7410_T_HYST, ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static s16 ADT7410_TEMP_TO_REG(long temp)
> +{
> +	return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7410_TEMP_MIN,
> +					       ADT7410_TEMP_MAX) * 128, 1000);
> +}
> +
> +static int ADT7410_REG_TO_TEMP(struct adt7410_data *data, s16 reg)
> +{
> +	/* in 13 bit mode, bits 0-2 are status flags - mask them out */
> +	if (!(data->config & ADT7410_RESOLUTION))
> +		reg &= ADT7410_T13_VALUE_MASK;
> +	/*
> +	 * temperature is stored in twos complement format, in steps of
> +	 * 1/128°C
> +	 */
> +	return DIV_ROUND_CLOSEST(reg * 1000, 128);
> +}
> +
> +/*-----------------------------------------------------------------------*/
> +
> +/* sysfs attributes for hwmon */
> +
> +static ssize_t adt7410_show_temp(struct device *dev,
> +				 struct device_attribute *da, char *buf)
> +{
> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
> +	struct adt7410_data *data = dev_get_drvdata(dev);
> +
> +
> +	if (attr->index == 0) {
> +		int ret;
> +
> +		ret = adt7410_update_temp(dev);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return sprintf(buf, "%d\n", ADT7410_REG_TO_TEMP(data,
> +		       data->temp[attr->index]));
> +}
> +
> +static ssize_t adt7410_set_temp(struct device *dev,
> +				struct device_attribute *da,
> +				const char *buf, size_t count)
> +{
> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
> +	struct adt7410_data *data = dev_get_drvdata(dev);
> +	int nr = attr->index;
> +	long temp;
> +	int ret;
> +
> +	ret = kstrtol(buf, 10, &temp);
> +	if (ret)
> +		return ret;
> +
> +	mutex_lock(&data->update_lock);
> +	data->temp[nr] = ADT7410_TEMP_TO_REG(temp);
> +	ret = adt7410_write_word(dev, ADT7410_REG_TEMP[nr], data->temp[nr]);
> +	if (ret)
> +		count = ret;
> +	mutex_unlock(&data->update_lock);
> +	return count;
> +}
> +
> +static ssize_t adt7410_show_t_hyst(struct device *dev,
> +				   struct device_attribute *da,
> +				   char *buf)
> +{
> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
> +	struct adt7410_data *data = dev_get_drvdata(dev);
> +	int nr = attr->index;
> +	int hyst;
> +
> +	hyst = (data->hyst & ADT7410_T_HYST_MASK) * 1000;
> +
> +	/*
> +	 * hysteresis is stored as a 4 bit offset in the device, convert it
> +	 * to an absolute value
> +	 */
> +	if (nr == 2)	/* min has positive offset, others have negative */
> +		hyst = -hyst;
> +	return sprintf(buf, "%d\n",
> +		       ADT7410_REG_TO_TEMP(data, data->temp[nr]) - hyst);
> +}
> +
> +static ssize_t adt7410_set_t_hyst(struct device *dev,
> +				  struct device_attribute *da,
> +				  const char *buf, size_t count)
> +{
> +	struct adt7410_data *data = dev_get_drvdata(dev);
> +	int limit, ret;
> +	long hyst;
> +
> +	ret = kstrtol(buf, 10, &hyst);
> +	if (ret)
> +		return ret;
> +	/* convert absolute hysteresis value to a 4 bit delta value */
> +	limit = ADT7410_REG_TO_TEMP(data, data->temp[1]);
> +	hyst = clamp_val(hyst, ADT7410_TEMP_MIN, ADT7410_TEMP_MAX);
> +	data->hyst = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000),
> +				   0, ADT7410_T_HYST_MASK);
> +	ret = adt7410_write_byte(dev, ADT7410_T_HYST, data->hyst);
> +	if (ret)
> +		return ret;
> +
> +	return count;
> +}
> +
> +static ssize_t adt7410_show_alarm(struct device *dev,
> +				  struct device_attribute *da,
> +				  char *buf)
> +{
> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
> +	u8 status;
> +	int ret;
> +
> +	ret = adt7410_read_byte(dev, ADT7410_STATUS, &status);
> +	if (ret < 0)
> +		return ret;
> +
> +	return sprintf(buf, "%d\n", !!(status & attr->index));
> +}
> +
> +static ssize_t adt7410_show_name(struct device *dev,
> +				  struct device_attribute *da, char *buf)
> +{
> +	struct adt7410_data *data = dev_get_drvdata(dev);
> +
> +	return sprintf(buf, "%s\n", data->name);
> +}
> +
> +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adt7410_show_temp, NULL, 0);
> +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
> +			  adt7410_show_temp, adt7410_set_temp, 1);
> +static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
> +			  adt7410_show_temp, adt7410_set_temp, 2);
> +static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
> +			  adt7410_show_temp, adt7410_set_temp, 3);
> +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
> +			  adt7410_show_t_hyst, adt7410_set_t_hyst, 1);
> +static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO,
> +			  adt7410_show_t_hyst, NULL, 2);
> +static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO,
> +			  adt7410_show_t_hyst, NULL, 3);
> +static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, adt7410_show_alarm,
> +			  NULL, ADT7410_STAT_T_LOW);
> +static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adt7410_show_alarm,
> +			  NULL, ADT7410_STAT_T_HIGH);
> +static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, adt7410_show_alarm,
> +			  NULL, ADT7410_STAT_T_CRIT);
> +static DEVICE_ATTR(name, S_IRUGO, adt7410_show_name, NULL);
> +
> +static struct attribute *adt7410_attributes[] = {
> +	&sensor_dev_attr_temp1_input.dev_attr.attr,
> +	&sensor_dev_attr_temp1_max.dev_attr.attr,
> +	&sensor_dev_attr_temp1_min.dev_attr.attr,
> +	&sensor_dev_attr_temp1_crit.dev_attr.attr,
> +	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
> +	&sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
> +	&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
> +	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
> +	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
> +	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
> +	NULL
> +};
> +
> +static const struct attribute_group adt7410_group = {
> +	.attrs = adt7410_attributes,
> +};
> +
> +int adt7410_probe(struct device *dev, const char *name,
> +	const struct adt7410_ops *ops)
> +{
> +	struct adt7410_data *data;
> +	int ret;
> +
> +	data = devm_kzalloc(dev, sizeof(struct adt7410_data),
> +			    GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	data->ops = ops;
> +	data->name = name;
> +
> +	dev_set_drvdata(dev, data);
> +	mutex_init(&data->update_lock);
> +
> +	/* configure as specified */
> +	ret = adt7410_read_byte(dev, ADT7410_CONFIG, &data->oldconfig);
> +	if (ret < 0) {
> +		dev_dbg(dev, "Can't read config? %d\n", ret);
> +		return ret;
> +	}
> +	/*
> +	 * Set to 16 bit resolution, continous conversion and comparator mode.
> +	 */
> +	data->config = data->oldconfig;
> +	data->config &= ~ADT7410_MODE_MASK;
> +	data->config |= ADT7410_FULL | ADT7410_RESOLUTION | ADT7410_EVENT_MODE;
> +	if (data->config != data->oldconfig) {
> +		ret = adt7410_write_byte(dev, ADT7410_CONFIG, data->config);
> +		if (ret)
> +			return ret;
> +	}
> +	dev_dbg(dev, "Config %02x\n", data->config);
> +
> +	ret = adt7410_fill_cache(dev);
> +	if (ret)
> +		goto exit_restore;
> +
> +	/* Register sysfs hooks */
> +	ret = sysfs_create_group(&dev->kobj, &adt7410_group);
> +	if (ret)
> +		goto exit_restore;
> +
> +	/*
> +	 * The I2C device will already have it's own 'name' attribute, but for
> +	 * the SPI device we need to register it. name will only be non NULL if
> +	 * the device doesn't register the 'name' attribute on its own.
> +	 */
> +	if (name) {
> +		ret = device_create_file(dev, &dev_attr_name);
> +		if (ret)
> +			goto exit_remove;
> +	}
> +
> +	data->hwmon_dev = hwmon_device_register(dev);
> +	if (IS_ERR(data->hwmon_dev)) {
> +		ret = PTR_ERR(data->hwmon_dev);
> +		goto exit_remove_name;
> +	}
> +
> +	return 0;
> +
> +exit_remove_name:
> +	if (name)
> +		device_remove_file(dev, &dev_attr_name);
> +exit_remove:
> +	sysfs_remove_group(&dev->kobj, &adt7410_group);
> +exit_restore:
> +	adt7410_write_byte(dev, ADT7410_CONFIG, data->oldconfig);
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(adt7410_probe);
> +
> +int adt7410_remove(struct device *dev)
> +{
> +	struct adt7410_data *data = dev_get_drvdata(dev);
> +
> +	hwmon_device_unregister(data->hwmon_dev);
> +	if (data->name)
> +		device_remove_file(dev, &dev_attr_name);
> +	sysfs_remove_group(&dev->kobj, &adt7410_group);
> +	if (data->oldconfig != data->config)
> +		adt7410_write_byte(dev, ADT7410_CONFIG,
> +					  data->oldconfig);
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(adt7410_remove);
> +
> +#ifdef CONFIG_PM_SLEEP
> +
> +static int adt7410_suspend(struct device *dev)
> +{
> +	struct adt7410_data *data = dev_get_drvdata(dev);
> +
> +	return adt7410_write_byte(dev, ADT7410_CONFIG,
> +		data->config | ADT7410_PD);
> +}
> +
> +static int adt7410_resume(struct device *dev)
> +{
> +	struct adt7410_data *data = dev_get_drvdata(dev);
> +
> +	return adt7410_write_byte(dev, ADT7410_CONFIG, data->config);
> +}
> +
> +SIMPLE_DEV_PM_OPS(adt7410_dev_pm_ops, adt7410_suspend, adt7410_resume);
> +EXPORT_SYMBOL_GPL(adt7410_dev_pm_ops);
> +
> +#endif /* CONFIG_PM_SLEEP */
> +
> +MODULE_AUTHOR("Hartmut Knaack");
> +MODULE_DESCRIPTION("ADT7410 driver");
This description does not seem appropriate any longer.
> +MODULE_LICENSE("GPL");
<...>


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

* Re: [lm-sensors] [PATCH 7/9] hwmon: (adt7410) Add support for the adt7310/adt7320
@ 2013-02-15 20:05     ` Hartmut Knaack
  0 siblings, 0 replies; 56+ messages in thread
From: Hartmut Knaack @ 2013-02-15 20:05 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Jean Delvare, Guenter Roeck, Jonathan Cameron, lm-sensors, linux-iio

SSBoYWQgYSBxdWljayBsb29rIG92ZXIgeW91ciBwYXRjaGVzIGFuZCBmb3VuZCBzb21lIG1pbm9y
IHR5cG8sIHNlZSBiZWxvdy4gSSB3aWxsIGFwcGx5IGFsbCB0aGUgcGF0Y2hlcyB0byBzZWUgdGhl
IHJlc3VsdC4KQWxzbyBrZWVwIGluIG1pbmQgdG8gYWRkIHNvbWUgY2hhbmdlcyB0byBEb2N1bWVu
dGF0aW9uL2h3bW9uL2FkdDc0MTAgKGFuZCBhZGQgYW4gYWR0NzMxMCBhcyB3ZWxsPykuCgpMYXJz
LVBldGVyIENsYXVzZW4gc2NocmllYjoKPC4uLj4KPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9od21v
bi9hZHQ3MzEwLmMgYi9kcml2ZXJzL2h3bW9uL2FkdDczMTAuYwo+IG5ldyBmaWxlIG1vZGUgMTAw
NjQ0Cj4gaW5kZXggMDAwMDAwMC4uMDQ4M2U2Ywo+IC0tLSAvZGV2L251bGwKPiArKysgYi9kcml2
ZXJzL2h3bW9uL2FkdDczMTAuYwo+IEBAIC0wLDAgKzEsMTYwIEBACj4gKy8qCj4gKyAqIEFEVDcz
MTAvQURUNzMxMCBkaWdpdGFsIHRlbXBlcmF0dXJlIHNlbnNvciBkcml2ZXIKPiArICoKPiArICog
Q29weXJpZ2h0IDIwMTAtMjAxMyBBbmFsb2cgRGV2aWNlcyBJbmMuCj4gKyAqICAgQXV0aG9yOiBM
YXJzLVBldGVyIENsYXVzZW4gPGxhcnNAbWV0YWZvby5kZT4KPiArICoKPiArICogTGljZW5zZWQg
dW5kZXIgdGhlIEdQTC0yIG9yIGxhdGVyLgo+ICsgKi8KPiArCj4gKyNpbmNsdWRlIDxsaW51eC9t
b2R1bGUuaD4KPiArI2luY2x1ZGUgPGxpbnV4L2luaXQuaD4KPiArI2luY2x1ZGUgPGxpbnV4L3Nw
aS9zcGkuaD4KPiArCj4gKyNpbmNsdWRlICJhZHQ3eDEwLmgiCj4gKwo+ICtzdGF0aWMgY29uc3Qg
dTggYWR0NzM3MV9yZWdfdGFibGVbXSA9IHsKPiArCVtBRFQ3NDEwX1RFTVBFUkFUVVJFXSAgID0g
QURUNzMxMF9URU1QRVJBVFVSRSwKPiArCVtBRFQ3NDEwX1NUQVRVU10JPSBBRFQ3MzEwX1NUQVRV
UywKPiArCVtBRFQ3NDEwX0NPTkZJR10JPSBBRFQ3MzEwX0NPTkZJRywKPiArCVtBRFQ3NDEwX1Rf
QUxBUk1fSElHSF0JPSBBRFQ3MzEwX1RfQUxBUk1fSElHSCwKPiArCVtBRFQ3NDEwX1RfQUxBUk1f
TE9XXQk9IEFEVDczMTBfVF9BTEFSTV9MT1csCj4gKwlbQURUNzQxMF9UX0NSSVRdCT0gQURUNzMx
MF9UX0NSSVQsCj4gKwlbQURUNzQxMF9UX0hZU1RdCT0gQURUNzMxMF9UX0hZU1QsCj4gKwlbQURU
NzQxMF9JRF0JCT0gQURUNzMxMF9JRCwKPiArfTsKSnVzdCBvdXQgb2YgY3VyaW91c2l0eSwgd2hh
dHMgdGhlIHJlYXNvbiBmb3IgdGhlIG5hbWUgYWR0NzM3MSBoZXJlPwo+ICsKPiArI2RlZmluZSBB
RFQ3MzEwX0NNRF9SRUdfTUFTSwkJCTB4MjgKPiArI2RlZmluZSBBRFQ3MzEwX0NNRF9SRUdfT0ZG
U0VUCQkJMwo+ICsjZGVmaW5lIEFEVDczMTBfQ01EX1JFQUQJCQkweDQwCj4gKyNkZWZpbmUgQURU
NzMxMF9DTURfQ09OX1JFQUQJCQkweDQKPiArCj4gKyNkZWZpbmUgQUQ3MzEwX0NPTU1BTkQocmVn
KSAoYWR0NzM3MV9yZWdfdGFibGVbKHJlZyldIDw8IEFEVDczMTBfQ01EX1JFR19PRkZTRVQpCj4g
Kwo+ICtzdGF0aWMgaW50IGFkdDczMTBfc3BpX3JlYWRfd29yZChzdHJ1Y3QgZGV2aWNlICpkZXYs
Cj4gKwl1OCByZWcsIHUxNiAqZGF0YSkKPiArewo+ICsJc3RydWN0IHNwaV9kZXZpY2UgKnNwaSA9
IHRvX3NwaV9kZXZpY2UoZGV2KTsKPiArCXU4IGNvbW1hbmQgPSBBRDczMTBfQ09NTUFORChyZWcp
Owo+ICsJaW50IHJldCA9IDA7Cj4gKwo+ICsJY29tbWFuZCB8PSBBRFQ3MzEwX0NNRF9SRUFEOwo+
ICsJcmV0ID0gc3BpX3dyaXRlKHNwaSwgJmNvbW1hbmQsIHNpemVvZihjb21tYW5kKSk7Cj4gKwlp
ZiAocmV0IDwgMCkgewo+ICsJCWRldl9lcnIoZGV2LCAiU1BJIHdyaXRlIGNvbW1hbmQgZXJyb3Jc
biIpOwo+ICsJCXJldHVybiByZXQ7Cj4gKwl9Cj4gKwo+ICsJcmV0ID0gc3BpX3JlYWQoc3BpLCAo
dTggKilkYXRhLCBzaXplb2YoKmRhdGEpKTsKPiArCWlmIChyZXQgPCAwKSB7Cj4gKwkJZGV2X2Vy
cihkZXYsICJTUEkgcmVhZCB3b3JkIGVycm9yXG4iKTsKPiArCQlyZXR1cm4gcmV0Owo+ICsJfQo+
ICsKPiArCSpkYXRhID0gYmUxNl90b19jcHUoKmRhdGEpOwo+ICsKPiArCXJldHVybiAwOwo+ICt9
Cj4gKwo+ICtzdGF0aWMgaW50IGFkdDczMTBfc3BpX3dyaXRlX3dvcmQoc3RydWN0IGRldmljZSAq
ZGV2LCB1OCByZWcsCj4gKwl1MTYgZGF0YSkKPiArewo+ICsJc3RydWN0IHNwaV9kZXZpY2UgKnNw
aSA9IHRvX3NwaV9kZXZpY2UoZGV2KTsKPiArCXU4IGJ1ZlszXTsKPiArCWludCByZXQgPSAwOwo+
ICsKPiArCWJ1ZlswXSA9IEFENzMxMF9DT01NQU5EKHJlZyk7Cj4gKwlidWZbMV0gPSAodTgpKGRh
dGEgPj4gOCk7Cj4gKwlidWZbMl0gPSAodTgpKGRhdGEgJiAweEZGKTsKPiArCj4gKwlyZXQgPSBz
cGlfd3JpdGUoc3BpLCBidWYsIDMpOwo+ICsJaWYgKHJldCA8IDApIHsKPiArCQlkZXZfZXJyKGRl
diwgIlNQSSB3cml0ZSB3b3JkIGVycm9yXG4iKTsKPiArCQlyZXR1cm4gcmV0Owo+ICsJfQo+ICsK
PiArCXJldHVybiByZXQ7Cj4gK30KPiArCj4gK3N0YXRpYyBpbnQgYWR0NzMxMF9zcGlfcmVhZF9i
eXRlKHN0cnVjdCBkZXZpY2UgKmRldiwgdTggcmVnLAo+ICsJdTggKmRhdGEpCj4gK3sKPiArCXN0
cnVjdCBzcGlfZGV2aWNlICpzcGkgPSB0b19zcGlfZGV2aWNlKGRldik7Cj4gKwl1OCBjb21tYW5k
ID0gQUQ3MzEwX0NPTU1BTkQocmVnKTsKPiArCWludCByZXQgPSAwOwo+ICsKPiArCWNvbW1hbmQg
fD0gQURUNzMxMF9DTURfUkVBRDsKPiArCXJldCA9IHNwaV93cml0ZShzcGksICZjb21tYW5kLCBz
aXplb2YoY29tbWFuZCkpOwo+ICsJaWYgKHJldCA8IDApIHsKPiArCQlkZXZfZXJyKGRldiwgIlNQ
SSB3cml0ZSBjb21tYW5kIGVycm9yXG4iKTsKPiArCQlyZXR1cm4gcmV0Owo+ICsJfQo+ICsKPiAr
CXJldCA9IHNwaV9yZWFkKHNwaSwgZGF0YSwgc2l6ZW9mKCpkYXRhKSk7Cj4gKwlpZiAocmV0IDwg
MCkgewo+ICsJCWRldl9lcnIoZGV2LCAiU1BJIHJlYWQgYnl0ZSBlcnJvclxuIik7Cj4gKwkJcmV0
dXJuIHJldDsKPiArCX0KPiArCj4gKwlyZXR1cm4gMDsKPiArfQo+ICsKPiArc3RhdGljIGludCBh
ZHQ3MzEwX3NwaV93cml0ZV9ieXRlKHN0cnVjdCBkZXZpY2UgKmRldiwgdTggcmVnLAo+ICsJdTgg
ZGF0YSkKPiArewo+ICsJc3RydWN0IHNwaV9kZXZpY2UgKnNwaSA9IHRvX3NwaV9kZXZpY2UoZGV2
KTsKPiArCXU4IGJ1ZlsyXTsKPiArCWludCByZXQgPSAwOwo+ICsKPiArCWJ1ZlswXSA9IEFENzMx
MF9DT01NQU5EKHJlZyk7Cj4gKwlidWZbMV0gPSBkYXRhOwo+ICsKPiArCXJldCA9IHNwaV93cml0
ZShzcGksIGJ1ZiwgMik7Cj4gKwlpZiAocmV0IDwgMCkgewo+ICsJCWRldl9lcnIoZGV2LCAiU1BJ
IHdyaXRlIGJ5dGUgZXJyb3JcbiIpOwo+ICsJCXJldHVybiByZXQ7Cj4gKwl9Cj4gKwo+ICsJcmV0
dXJuIHJldDsKPiArfQo+ICsKPiArc3RhdGljIGNvbnN0IHN0cnVjdCBhZHQ3NDEwX29wcyBhZHQ3
MzEwX3NwaV9vcHMgPSB7Cj4gKwkucmVhZF93b3JkID0gYWR0NzMxMF9zcGlfcmVhZF93b3JkLAo+
ICsJLndyaXRlX3dvcmQgPSBhZHQ3MzEwX3NwaV93cml0ZV93b3JkLAo+ICsJLnJlYWRfYnl0ZSA9
IGFkdDczMTBfc3BpX3JlYWRfYnl0ZSwKPiArCS53cml0ZV9ieXRlID0gYWR0NzMxMF9zcGlfd3Jp
dGVfYnl0ZSwKPiArfTsKPiArCj4gK3N0YXRpYyBpbnQgYWR0NzMxMF9zcGlfcHJvYmUoc3RydWN0
IHNwaV9kZXZpY2UgKnNwaSkKPiArewo+ICsJcmV0dXJuIGFkdDc0MTBfcHJvYmUoJnNwaS0+ZGV2
LCBzcGlfZ2V0X2RldmljZV9pZChzcGkpLT5uYW1lLAo+ICsJCQkmYWR0NzMxMF9zcGlfb3BzKTsK
PiArfQo+ICsKPiArc3RhdGljIGludCBhZHQ3MzEwX3NwaV9yZW1vdmUoc3RydWN0IHNwaV9kZXZp
Y2UgKnNwaSkKPiArewo+ICsJcmV0dXJuIGFkdDc0MTBfcmVtb3ZlKCZzcGktPmRldik7Cj4gK30K
PiArCj4gK3N0YXRpYyBjb25zdCBzdHJ1Y3Qgc3BpX2RldmljZV9pZCBhZHQ3MzEwX2lkW10gPSB7
Cj4gKwl7ICJhZHQ3MzEwIiwgMCB9LAo+ICsJeyAiYWR0NzMyMCIsIDAgfSwKPiArCXt9Cj4gK307
Cj4gK01PRFVMRV9ERVZJQ0VfVEFCTEUoc3BpLCBhZHQ3MzEwX2lkKTsKPiArCj4gK3N0YXRpYyBz
dHJ1Y3Qgc3BpX2RyaXZlciBhZHQ3MzEwX2RyaXZlciA9IHsKPiArCS5kcml2ZXIgPSB7Cj4gKwkJ
Lm5hbWUgPSAiYWR0NzMxMCIsCj4gKwkJLm93bmVyID0gVEhJU19NT0RVTEUsCj4gKwkJLnBtCT0g
QURUNzQxMF9ERVZfUE1fT1BTLAo+ICsJfSwKPiArCS5wcm9iZSA9IGFkdDczMTBfc3BpX3Byb2Jl
LAo+ICsJLnJlbW92ZSA9IGFkdDczMTBfc3BpX3JlbW92ZSwKPiArCS5pZF90YWJsZSA9IGFkdDcz
MTBfaWQsCj4gK307Cj4gK21vZHVsZV9zcGlfZHJpdmVyKGFkdDczMTBfZHJpdmVyKTsKPiArCj4g
K01PRFVMRV9BVVRIT1IoIkxhcnMtUGV0ZXIgQ2xhdXNlbiA8bGFyc0BtZXRhZm9vLmRlPiIpOwo+
ICtNT0RVTEVfREVTQ1JJUFRJT04oIkFEVDczMTAvQURUNzQyMCBkcml2ZXIiKTsKVGhpcyBzaG91
bGQgYmUgQURUNzMxMC9BRFQ3MzIwLCByaWdodD8KPiArTU9EVUxFX0xJQ0VOU0UoIkdQTCIpOwo8
Li4uPgo+IC0tLSAvZGV2L251bGwKPiArKysgYi9kcml2ZXJzL2h3bW9uL2FkdDd4MTAuYwo+IEBA
IC0wLDAgKzEsNDc2IEBACj4gKy8qCj4gKyAqIGFkdDc0MTAuYyAtIFBhcnQgb2YgbG1fc2Vuc29y
cywgTGludXgga2VybmVsIG1vZHVsZXMgZm9yIGhhcmR3YXJlCj4gKyAqCSBtb25pdG9yaW5nCj4g
KyAqIFRoaXMgZHJpdmVyIGhhbmRsZXMgdGhlIEFEVDc0MTAgYW5kIGNvbXBhdGlibGUgZGlnaXRh
bCB0ZW1wZXJhdHVyZSBzZW5zb3JzLgo+ICsgKiBIYXJ0bXV0IEtuYWFjayA8a25hYWNrLmhAZ214
LmRlPiAyMDEyLTA3LTIyCj4gKyAqIGJhc2VkIG9uIGxtNzUuYyBieSBGcm9kbyBMb29pamFhcmQg
PGZyb2RvbEBkZHMubmw+Cj4gKyAqIGFuZCBhZHQ3NDEwLmMgZnJvbSBpaW8tc3RhZ2luZyBieSBT
b25pYyBaaGFuZyA8c29uaWMuemhhbmdAYW5hbG9nLmNvbT4KPiArICoKPiArICogVGhpcyBwcm9n
cmFtIGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2Rp
ZnkKPiArICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGlj
ZW5zZSBhcyBwdWJsaXNoZWQgYnkKPiArICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsg
ZWl0aGVyIHZlcnNpb24gMiBvZiB0aGUgTGljZW5zZSwgb3IKPiArICogKGF0IHlvdXIgb3B0aW9u
KSBhbnkgbGF0ZXIgdmVyc2lvbi4KPiArICoKPiArICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1
dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsCj4gKyAqIGJ1dCBXSVRIT1VU
IEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mCj4gKyAq
IE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNl
ZSB0aGUKPiArICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy4K
PiArICoKPiArICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdl
bmVyYWwgUHVibGljIExpY2Vuc2UKPiArICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW07IGlmIG5v
dCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmUKPiArICogRm91bmRhdGlvbiwgSW5jLiwgNjc1
IE1hc3MgQXZlLCBDYW1icmlkZ2UsIE1BIDAyMTM5LCBVU0EuCj4gKyAqLwo+ICsKPiArI2luY2x1
ZGUgPGxpbnV4L21vZHVsZS5oPgo+ICsjaW5jbHVkZSA8bGludXgvaW5pdC5oPgo+ICsjaW5jbHVk
ZSA8bGludXgvc2xhYi5oPgo+ICsjaW5jbHVkZSA8bGludXgvamlmZmllcy5oPgo+ICsjaW5jbHVk
ZSA8bGludXgvaHdtb24uaD4KPiArI2luY2x1ZGUgPGxpbnV4L2h3bW9uLXN5c2ZzLmg+Cj4gKyNp
bmNsdWRlIDxsaW51eC9lcnIuaD4KPiArI2luY2x1ZGUgPGxpbnV4L211dGV4Lmg+Cj4gKyNpbmNs
dWRlIDxsaW51eC9kZWxheS5oPgo+ICsKPiArI2luY2x1ZGUgImFkdDd4MTAuaCIKPiArCj4gKy8q
Cj4gKyAqIEFEVDc0MTAgc3RhdHVzCj4gKyAqLwo+ICsjZGVmaW5lIEFEVDc0MTBfU1RBVF9UX0xP
VwkJKDEgPDwgNCkKPiArI2RlZmluZSBBRFQ3NDEwX1NUQVRfVF9ISUdICQkoMSA8PCA1KQo+ICsj
ZGVmaW5lIEFEVDc0MTBfU1RBVF9UX0NSSVQJCSgxIDw8IDYpCj4gKyNkZWZpbmUgQURUNzQxMF9T
VEFUX05PVF9SRFkJCSgxIDw8IDcpCj4gKwo+ICsvKgo+ICsgKiBBRFQ3NDEwIGNvbmZpZwo+ICsg
Ki8KPiArI2RlZmluZSBBRFQ3NDEwX0ZBVUxUX1FVRVVFX01BU0sJKDEgPDwgMCB8IDEgPDwgMSkK
PiArI2RlZmluZSBBRFQ3NDEwX0NUX1BPTEFSSVRZCQkoMSA8PCAyKQo+ICsjZGVmaW5lIEFEVDc0
MTBfSU5UX1BPTEFSSVRZCQkoMSA8PCAzKQo+ICsjZGVmaW5lIEFEVDc0MTBfRVZFTlRfTU9ERQkJ
KDEgPDwgNCkKPiArI2RlZmluZSBBRFQ3NDEwX01PREVfTUFTSwkJKDEgPDwgNSB8IDEgPDwgNikK
PiArI2RlZmluZSBBRFQ3NDEwX0ZVTEwJCQkoMCA8PCA1IHwgMCA8PCA2KQo+ICsjZGVmaW5lIEFE
VDc0MTBfUEQJCQkoMSA8PCA1IHwgMSA8PCA2KQo+ICsjZGVmaW5lIEFEVDc0MTBfUkVTT0xVVElP
TgkJKDEgPDwgNykKPiArCj4gKy8qCj4gKyAqIEFEVDc0MTAgbWFza3MKPiArICovCj4gKyNkZWZp
bmUgQURUNzQxMF9UMTNfVkFMVUVfTUFTSwkJCTB4RkZGOAo+ICsjZGVmaW5lIEFEVDc0MTBfVF9I
WVNUX01BU0sJCQkweEYKPiArCj4gKy8qIHN0cmFpZ2h0IGZyb20gdGhlIGRhdGFzaGVldCAqLwo+
ICsjZGVmaW5lIEFEVDc0MTBfVEVNUF9NSU4gKC01NTAwMCkKPiArI2RlZmluZSBBRFQ3NDEwX1RF
TVBfTUFYIDE1MDAwMAo+ICsKPiArLyogRWFjaCBjbGllbnQgaGFzIHRoaXMgYWRkaXRpb25hbCBk
YXRhICovCj4gK3N0cnVjdCBhZHQ3NDEwX2RhdGEgewo+ICsJY29uc3Qgc3RydWN0IGFkdDc0MTBf
b3BzICpvcHM7Cj4gKwljb25zdCBjaGFyCQkqbmFtZTsKPiArCXN0cnVjdCBkZXZpY2UJCSpod21v
bl9kZXY7Cj4gKwlzdHJ1Y3QgbXV0ZXgJCXVwZGF0ZV9sb2NrOwo+ICsJdTgJCQljb25maWc7Cj4g
Kwl1OAkJCW9sZGNvbmZpZzsKPiArCWJvb2wJCQl2YWxpZDsJCS8qIHRydWUgaWYgcmVnaXN0ZXJz
IHZhbGlkICovCj4gKwl1bnNpZ25lZCBsb25nCQlsYXN0X3VwZGF0ZWQ7CS8qIEluIGppZmZpZXMg
Ki8KPiArCXMxNgkJCXRlbXBbNF07CS8qIFJlZ2lzdGVyIHZhbHVlcywKPiArCQkJCQkJICAgMCA9
IGlucHV0Cj4gKwkJCQkJCSAgIDEgPSBoaWdoCj4gKwkJCQkJCSAgIDIgPSBsb3cKPiArCQkJCQkJ
ICAgMyA9IGNyaXRpY2FsICovCj4gKwl1OAkJCWh5c3Q7CQkvKiBoeXN0ZXJlc2lzIG9mZnNldCAq
Lwo+ICt9Owo+ICsKPiArc3RhdGljIGludCBhZHQ3NDEwX3JlYWRfd29yZChzdHJ1Y3QgZGV2aWNl
ICpkZXYsIHU4IHJlZywgdTE2ICpkYXRhKQo+ICt7Cj4gKwlzdHJ1Y3QgYWR0NzQxMF9kYXRhICpk
ID0gZGV2X2dldF9kcnZkYXRhKGRldik7Cj4gKwlyZXR1cm4gZC0+b3BzLT5yZWFkX3dvcmQoZGV2
LCByZWcsIGRhdGEpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IGFkdDc0MTBfd3JpdGVfd29yZChz
dHJ1Y3QgZGV2aWNlICpkZXYsIHU4IHJlZywgdTE2IGRhdGEpCj4gK3sKPiArCXN0cnVjdCBhZHQ3
NDEwX2RhdGEgKmQgPSBkZXZfZ2V0X2RydmRhdGEoZGV2KTsKPiArCXJldHVybiBkLT5vcHMtPndy
aXRlX3dvcmQoZGV2LCByZWcsIGRhdGEpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IGFkdDc0MTBf
cmVhZF9ieXRlKHN0cnVjdCBkZXZpY2UgKmRldiwgdTggcmVnLCB1OCAqZGF0YSkKPiArewo+ICsJ
c3RydWN0IGFkdDc0MTBfZGF0YSAqZCA9IGRldl9nZXRfZHJ2ZGF0YShkZXYpOwo+ICsJcmV0dXJu
IGQtPm9wcy0+cmVhZF9ieXRlKGRldiwgcmVnLCBkYXRhKTsKPiArfQo+ICsKPiArc3RhdGljIGlu
dCBhZHQ3NDEwX3dyaXRlX2J5dGUoc3RydWN0IGRldmljZSAqZGV2LCB1OCByZWcsIHU4IGRhdGEp
Cj4gK3sKPiArCXN0cnVjdCBhZHQ3NDEwX2RhdGEgKmQgPSBkZXZfZ2V0X2RydmRhdGEoZGV2KTsK
PiArCXJldHVybiBkLT5vcHMtPndyaXRlX2J5dGUoZGV2LCByZWcsIGRhdGEpOwo+ICt9Cj4gKwo+
ICtzdGF0aWMgY29uc3QgdTggQURUNzQxMF9SRUdfVEVNUFs0XSA9IHsKPiArCUFEVDc0MTBfVEVN
UEVSQVRVUkUsCQkvKiBpbnB1dCAqLwo+ICsJQURUNzQxMF9UX0FMQVJNX0hJR0gsCQkvKiBoaWdo
ICovCj4gKwlBRFQ3NDEwX1RfQUxBUk1fTE9XLAkJLyogbG93ICovCj4gKwlBRFQ3NDEwX1RfQ1JJ
VCwJCQkvKiBjcml0aWNhbCAqLwo+ICt9Owo+ICsKPiArLyoKPiArICogYWR0NzQxMCByZWdpc3Rl
ciBhY2Nlc3MgYnkgSTJDCj4gKyAqLwo+ICtzdGF0aWMgaW50IGFkdDc0MTBfdGVtcF9yZWFkeShz
dHJ1Y3QgZGV2aWNlICpkZXYpCj4gK3sKPiArCWludCBpLCByZXQ7Cj4gKwl1OCBzdGF0dXM7Cj4g
Kwo+ICsJZm9yIChpID0gMDsgaSA8IDY7IGkrKykgewo+ICsJCXJldCA9IGFkdDc0MTBfcmVhZF9i
eXRlKGRldiwgQURUNzQxMF9TVEFUVVMsICZzdGF0dXMpOwo+ICsJCWlmIChyZXQpCj4gKwkJCXJl
dHVybiByZXQ7Cj4gKwkJaWYgKCEoc3RhdHVzICYgQURUNzQxMF9TVEFUX05PVF9SRFkpKQo+ICsJ
CQlyZXR1cm4gMDsKPiArCQltc2xlZXAoNjApOwo+ICsJfQo+ICsJcmV0dXJuIC1FVElNRURPVVQ7
Cj4gK30KPiArCj4gK3N0YXRpYyBpbnQgYWR0NzQxMF91cGRhdGVfdGVtcChzdHJ1Y3QgZGV2aWNl
ICpkZXYpCj4gK3sKPiArCXN0cnVjdCBhZHQ3NDEwX2RhdGEgKmRhdGEgPSBkZXZfZ2V0X2RydmRh
dGEoZGV2KTsKPiArCWludCByZXQgPSAwOwo+ICsKPiArCW11dGV4X2xvY2soJmRhdGEtPnVwZGF0
ZV9sb2NrKTsKPiArCj4gKwlpZiAodGltZV9hZnRlcihqaWZmaWVzLCBkYXRhLT5sYXN0X3VwZGF0
ZWQgKyBIWiArIEhaIC8gMikKPiArCSAgICB8fCAhZGF0YS0+dmFsaWQpIHsKPiArCj4gKwkJZGV2
X2RiZyhkZXYsICJTdGFydGluZyB1cGRhdGVcbiIpOwo+ICsKPiArCQlyZXQgPSBhZHQ3NDEwX3Rl
bXBfcmVhZHkoZGV2KTsgLyogY2hlY2sgZm9yIG5ldyB2YWx1ZSAqLwo+ICsJCWlmIChyZXQpCj4g
KwkJCWdvdG8gYWJvcnQ7Cj4gKwo+ICsJCXJldCA9IGFkdDc0MTBfcmVhZF93b3JkKGRldiwgQURU
NzQxMF9SRUdfVEVNUFswXSwKPiArCQkJCQkmZGF0YS0+dGVtcFswXSk7Cj4gKwkJaWYgKHJldCkg
ewo+ICsJCQlkZXZfZGJnKGRldiwgIkZhaWxlZCB0byByZWFkIHZhbHVlOiByZWcgJWQsIGVycm9y
ICVkXG4iLAo+ICsJCQkJQURUNzQxMF9SRUdfVEVNUFswXSwgcmV0KTsKPiArCQkJZ290byBhYm9y
dDsKPiArCQl9Cj4gKwkJZGF0YS0+bGFzdF91cGRhdGVkID0gamlmZmllczsKPiArCQlkYXRhLT52
YWxpZCA9IHRydWU7Cj4gKwl9Cj4gKwo+ICthYm9ydDoKPiArCW11dGV4X3VubG9jaygmZGF0YS0+
dXBkYXRlX2xvY2spOwo+ICsJcmV0dXJuIHJldDsKPiArfQo+ICsKPiArc3RhdGljIGludCBhZHQ3
NDEwX2ZpbGxfY2FjaGUoc3RydWN0IGRldmljZSAqZGV2KQo+ICt7Cj4gKwlzdHJ1Y3QgYWR0NzQx
MF9kYXRhICpkYXRhID0gZGV2X2dldF9kcnZkYXRhKGRldik7Cj4gKwlpbnQgcmV0Owo+ICsJaW50
IGk7Cj4gKwo+ICsJZm9yIChpID0gMTsgaSA8IEFSUkFZX1NJWkUoZGF0YS0+dGVtcCk7IGkrKykg
ewo+ICsJCXJldCA9IGFkdDc0MTBfcmVhZF93b3JkKGRldiwgQURUNzQxMF9SRUdfVEVNUFtpXSwK
PiArCQkJCQkmZGF0YS0+dGVtcFtpXSk7Cj4gKwkJaWYgKHJldCkgewo+ICsJCQlkZXZfZGJnKGRl
diwgIkZhaWxlZCB0byByZWFkIHZhbHVlOiByZWcgJWQsIGVycm9yICVkXG4iLAo+ICsJCQkJQURU
NzQxMF9SRUdfVEVNUFswXSwgcmV0KTsKPiArCQkJcmV0dXJuIHJldDsKPiArCQl9Cj4gKwl9Cj4g
Kwo+ICsJcmV0ID0gYWR0NzQxMF9yZWFkX2J5dGUoZGV2LCBBRFQ3NDEwX1RfSFlTVCwgJmRhdGEt
Pmh5c3QpOwo+ICsJaWYgKHJldCkgewo+ICsJCWRldl9kYmcoZGV2LCAiRmFpbGVkIHRvIHJlYWQg
dmFsdWU6IHJlZyAlZCwgZXJyb3IgJWRcbiIsCj4gKwkJCQlBRFQ3NDEwX1RfSFlTVCwgcmV0KTsK
PiArCQlyZXR1cm4gcmV0Owo+ICsJfQo+ICsKPiArCXJldHVybiAwOwo+ICt9Cj4gKwo+ICtzdGF0
aWMgczE2IEFEVDc0MTBfVEVNUF9UT19SRUcobG9uZyB0ZW1wKQo+ICt7Cj4gKwlyZXR1cm4gRElW
X1JPVU5EX0NMT1NFU1QoY2xhbXBfdmFsKHRlbXAsIEFEVDc0MTBfVEVNUF9NSU4sCj4gKwkJCQkJ
ICAgICAgIEFEVDc0MTBfVEVNUF9NQVgpICogMTI4LCAxMDAwKTsKPiArfQo+ICsKPiArc3RhdGlj
IGludCBBRFQ3NDEwX1JFR19UT19URU1QKHN0cnVjdCBhZHQ3NDEwX2RhdGEgKmRhdGEsIHMxNiBy
ZWcpCj4gK3sKPiArCS8qIGluIDEzIGJpdCBtb2RlLCBiaXRzIDAtMiBhcmUgc3RhdHVzIGZsYWdz
IC0gbWFzayB0aGVtIG91dCAqLwo+ICsJaWYgKCEoZGF0YS0+Y29uZmlnICYgQURUNzQxMF9SRVNP
TFVUSU9OKSkKPiArCQlyZWcgJj0gQURUNzQxMF9UMTNfVkFMVUVfTUFTSzsKPiArCS8qCj4gKwkg
KiB0ZW1wZXJhdHVyZSBpcyBzdG9yZWQgaW4gdHdvcyBjb21wbGVtZW50IGZvcm1hdCwgaW4gc3Rl
cHMgb2YKPiArCSAqIDEvMTI4wrBDCj4gKwkgKi8KPiArCXJldHVybiBESVZfUk9VTkRfQ0xPU0VT
VChyZWcgKiAxMDAwLCAxMjgpOwo+ICt9Cj4gKwo+ICsvKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi8KPiArCj4g
Ky8qIHN5c2ZzIGF0dHJpYnV0ZXMgZm9yIGh3bW9uICovCj4gKwo+ICtzdGF0aWMgc3NpemVfdCBh
ZHQ3NDEwX3Nob3dfdGVtcChzdHJ1Y3QgZGV2aWNlICpkZXYsCj4gKwkJCQkgc3RydWN0IGRldmlj
ZV9hdHRyaWJ1dGUgKmRhLCBjaGFyICpidWYpCj4gK3sKPiArCXN0cnVjdCBzZW5zb3JfZGV2aWNl
X2F0dHJpYnV0ZSAqYXR0ciA9IHRvX3NlbnNvcl9kZXZfYXR0cihkYSk7Cj4gKwlzdHJ1Y3QgYWR0
NzQxMF9kYXRhICpkYXRhID0gZGV2X2dldF9kcnZkYXRhKGRldik7Cj4gKwo+ICsKPiArCWlmIChh
dHRyLT5pbmRleCA9PSAwKSB7Cj4gKwkJaW50IHJldDsKPiArCj4gKwkJcmV0ID0gYWR0NzQxMF91
cGRhdGVfdGVtcChkZXYpOwo+ICsJCWlmIChyZXQpCj4gKwkJCXJldHVybiByZXQ7Cj4gKwl9Cj4g
Kwo+ICsJcmV0dXJuIHNwcmludGYoYnVmLCAiJWRcbiIsIEFEVDc0MTBfUkVHX1RPX1RFTVAoZGF0
YSwKPiArCQkgICAgICAgZGF0YS0+dGVtcFthdHRyLT5pbmRleF0pKTsKPiArfQo+ICsKPiArc3Rh
dGljIHNzaXplX3QgYWR0NzQxMF9zZXRfdGVtcChzdHJ1Y3QgZGV2aWNlICpkZXYsCj4gKwkJCQlz
dHJ1Y3QgZGV2aWNlX2F0dHJpYnV0ZSAqZGEsCj4gKwkJCQljb25zdCBjaGFyICpidWYsIHNpemVf
dCBjb3VudCkKPiArewo+ICsJc3RydWN0IHNlbnNvcl9kZXZpY2VfYXR0cmlidXRlICphdHRyID0g
dG9fc2Vuc29yX2Rldl9hdHRyKGRhKTsKPiArCXN0cnVjdCBhZHQ3NDEwX2RhdGEgKmRhdGEgPSBk
ZXZfZ2V0X2RydmRhdGEoZGV2KTsKPiArCWludCBuciA9IGF0dHItPmluZGV4Owo+ICsJbG9uZyB0
ZW1wOwo+ICsJaW50IHJldDsKPiArCj4gKwlyZXQgPSBrc3RydG9sKGJ1ZiwgMTAsICZ0ZW1wKTsK
PiArCWlmIChyZXQpCj4gKwkJcmV0dXJuIHJldDsKPiArCj4gKwltdXRleF9sb2NrKCZkYXRhLT51
cGRhdGVfbG9jayk7Cj4gKwlkYXRhLT50ZW1wW25yXSA9IEFEVDc0MTBfVEVNUF9UT19SRUcodGVt
cCk7Cj4gKwlyZXQgPSBhZHQ3NDEwX3dyaXRlX3dvcmQoZGV2LCBBRFQ3NDEwX1JFR19URU1QW25y
XSwgZGF0YS0+dGVtcFtucl0pOwo+ICsJaWYgKHJldCkKPiArCQljb3VudCA9IHJldDsKPiArCW11
dGV4X3VubG9jaygmZGF0YS0+dXBkYXRlX2xvY2spOwo+ICsJcmV0dXJuIGNvdW50Owo+ICt9Cj4g
Kwo+ICtzdGF0aWMgc3NpemVfdCBhZHQ3NDEwX3Nob3dfdF9oeXN0KHN0cnVjdCBkZXZpY2UgKmRl
diwKPiArCQkJCSAgIHN0cnVjdCBkZXZpY2VfYXR0cmlidXRlICpkYSwKPiArCQkJCSAgIGNoYXIg
KmJ1ZikKPiArewo+ICsJc3RydWN0IHNlbnNvcl9kZXZpY2VfYXR0cmlidXRlICphdHRyID0gdG9f
c2Vuc29yX2Rldl9hdHRyKGRhKTsKPiArCXN0cnVjdCBhZHQ3NDEwX2RhdGEgKmRhdGEgPSBkZXZf
Z2V0X2RydmRhdGEoZGV2KTsKPiArCWludCBuciA9IGF0dHItPmluZGV4Owo+ICsJaW50IGh5c3Q7
Cj4gKwo+ICsJaHlzdCA9IChkYXRhLT5oeXN0ICYgQURUNzQxMF9UX0hZU1RfTUFTSykgKiAxMDAw
Owo+ICsKPiArCS8qCj4gKwkgKiBoeXN0ZXJlc2lzIGlzIHN0b3JlZCBhcyBhIDQgYml0IG9mZnNl
dCBpbiB0aGUgZGV2aWNlLCBjb252ZXJ0IGl0Cj4gKwkgKiB0byBhbiBhYnNvbHV0ZSB2YWx1ZQo+
ICsJICovCj4gKwlpZiAobnIgPT0gMikJLyogbWluIGhhcyBwb3NpdGl2ZSBvZmZzZXQsIG90aGVy
cyBoYXZlIG5lZ2F0aXZlICovCj4gKwkJaHlzdCA9IC1oeXN0Owo+ICsJcmV0dXJuIHNwcmludGYo
YnVmLCAiJWRcbiIsCj4gKwkJICAgICAgIEFEVDc0MTBfUkVHX1RPX1RFTVAoZGF0YSwgZGF0YS0+
dGVtcFtucl0pIC0gaHlzdCk7Cj4gK30KPiArCj4gK3N0YXRpYyBzc2l6ZV90IGFkdDc0MTBfc2V0
X3RfaHlzdChzdHJ1Y3QgZGV2aWNlICpkZXYsCj4gKwkJCQkgIHN0cnVjdCBkZXZpY2VfYXR0cmli
dXRlICpkYSwKPiArCQkJCSAgY29uc3QgY2hhciAqYnVmLCBzaXplX3QgY291bnQpCj4gK3sKPiAr
CXN0cnVjdCBhZHQ3NDEwX2RhdGEgKmRhdGEgPSBkZXZfZ2V0X2RydmRhdGEoZGV2KTsKPiArCWlu
dCBsaW1pdCwgcmV0Owo+ICsJbG9uZyBoeXN0Owo+ICsKPiArCXJldCA9IGtzdHJ0b2woYnVmLCAx
MCwgJmh5c3QpOwo+ICsJaWYgKHJldCkKPiArCQlyZXR1cm4gcmV0Owo+ICsJLyogY29udmVydCBh
YnNvbHV0ZSBoeXN0ZXJlc2lzIHZhbHVlIHRvIGEgNCBiaXQgZGVsdGEgdmFsdWUgKi8KPiArCWxp
bWl0ID0gQURUNzQxMF9SRUdfVE9fVEVNUChkYXRhLCBkYXRhLT50ZW1wWzFdKTsKPiArCWh5c3Qg
PSBjbGFtcF92YWwoaHlzdCwgQURUNzQxMF9URU1QX01JTiwgQURUNzQxMF9URU1QX01BWCk7Cj4g
KwlkYXRhLT5oeXN0ID0gY2xhbXBfdmFsKERJVl9ST1VORF9DTE9TRVNUKGxpbWl0IC0gaHlzdCwg
MTAwMCksCj4gKwkJCQkgICAwLCBBRFQ3NDEwX1RfSFlTVF9NQVNLKTsKPiArCXJldCA9IGFkdDc0
MTBfd3JpdGVfYnl0ZShkZXYsIEFEVDc0MTBfVF9IWVNULCBkYXRhLT5oeXN0KTsKPiArCWlmIChy
ZXQpCj4gKwkJcmV0dXJuIHJldDsKPiArCj4gKwlyZXR1cm4gY291bnQ7Cj4gK30KPiArCj4gK3N0
YXRpYyBzc2l6ZV90IGFkdDc0MTBfc2hvd19hbGFybShzdHJ1Y3QgZGV2aWNlICpkZXYsCj4gKwkJ
CQkgIHN0cnVjdCBkZXZpY2VfYXR0cmlidXRlICpkYSwKPiArCQkJCSAgY2hhciAqYnVmKQo+ICt7
Cj4gKwlzdHJ1Y3Qgc2Vuc29yX2RldmljZV9hdHRyaWJ1dGUgKmF0dHIgPSB0b19zZW5zb3JfZGV2
X2F0dHIoZGEpOwo+ICsJdTggc3RhdHVzOwo+ICsJaW50IHJldDsKPiArCj4gKwlyZXQgPSBhZHQ3
NDEwX3JlYWRfYnl0ZShkZXYsIEFEVDc0MTBfU1RBVFVTLCAmc3RhdHVzKTsKPiArCWlmIChyZXQg
PCAwKQo+ICsJCXJldHVybiByZXQ7Cj4gKwo+ICsJcmV0dXJuIHNwcmludGYoYnVmLCAiJWRcbiIs
ICEhKHN0YXR1cyAmIGF0dHItPmluZGV4KSk7Cj4gK30KPiArCj4gK3N0YXRpYyBzc2l6ZV90IGFk
dDc0MTBfc2hvd19uYW1lKHN0cnVjdCBkZXZpY2UgKmRldiwKPiArCQkJCSAgc3RydWN0IGRldmlj
ZV9hdHRyaWJ1dGUgKmRhLCBjaGFyICpidWYpCj4gK3sKPiArCXN0cnVjdCBhZHQ3NDEwX2RhdGEg
KmRhdGEgPSBkZXZfZ2V0X2RydmRhdGEoZGV2KTsKPiArCj4gKwlyZXR1cm4gc3ByaW50ZihidWYs
ICIlc1xuIiwgZGF0YS0+bmFtZSk7Cj4gK30KPiArCj4gK3N0YXRpYyBTRU5TT1JfREVWSUNFX0FU
VFIodGVtcDFfaW5wdXQsIFNfSVJVR08sIGFkdDc0MTBfc2hvd190ZW1wLCBOVUxMLCAwKTsKPiAr
c3RhdGljIFNFTlNPUl9ERVZJQ0VfQVRUUih0ZW1wMV9tYXgsIFNfSVdVU1IgfCBTX0lSVUdPLAo+
ICsJCQkgIGFkdDc0MTBfc2hvd190ZW1wLCBhZHQ3NDEwX3NldF90ZW1wLCAxKTsKPiArc3RhdGlj
IFNFTlNPUl9ERVZJQ0VfQVRUUih0ZW1wMV9taW4sIFNfSVdVU1IgfCBTX0lSVUdPLAo+ICsJCQkg
IGFkdDc0MTBfc2hvd190ZW1wLCBhZHQ3NDEwX3NldF90ZW1wLCAyKTsKPiArc3RhdGljIFNFTlNP
Ul9ERVZJQ0VfQVRUUih0ZW1wMV9jcml0LCBTX0lXVVNSIHwgU19JUlVHTywKPiArCQkJICBhZHQ3
NDEwX3Nob3dfdGVtcCwgYWR0NzQxMF9zZXRfdGVtcCwgMyk7Cj4gK3N0YXRpYyBTRU5TT1JfREVW
SUNFX0FUVFIodGVtcDFfbWF4X2h5c3QsIFNfSVdVU1IgfCBTX0lSVUdPLAo+ICsJCQkgIGFkdDc0
MTBfc2hvd190X2h5c3QsIGFkdDc0MTBfc2V0X3RfaHlzdCwgMSk7Cj4gK3N0YXRpYyBTRU5TT1Jf
REVWSUNFX0FUVFIodGVtcDFfbWluX2h5c3QsIFNfSVJVR08sCj4gKwkJCSAgYWR0NzQxMF9zaG93
X3RfaHlzdCwgTlVMTCwgMik7Cj4gK3N0YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIodGVtcDFfY3Jp
dF9oeXN0LCBTX0lSVUdPLAo+ICsJCQkgIGFkdDc0MTBfc2hvd190X2h5c3QsIE5VTEwsIDMpOwo+
ICtzdGF0aWMgU0VOU09SX0RFVklDRV9BVFRSKHRlbXAxX21pbl9hbGFybSwgU19JUlVHTywgYWR0
NzQxMF9zaG93X2FsYXJtLAo+ICsJCQkgIE5VTEwsIEFEVDc0MTBfU1RBVF9UX0xPVyk7Cj4gK3N0
YXRpYyBTRU5TT1JfREVWSUNFX0FUVFIodGVtcDFfbWF4X2FsYXJtLCBTX0lSVUdPLCBhZHQ3NDEw
X3Nob3dfYWxhcm0sCj4gKwkJCSAgTlVMTCwgQURUNzQxMF9TVEFUX1RfSElHSCk7Cj4gK3N0YXRp
YyBTRU5TT1JfREVWSUNFX0FUVFIodGVtcDFfY3JpdF9hbGFybSwgU19JUlVHTywgYWR0NzQxMF9z
aG93X2FsYXJtLAo+ICsJCQkgIE5VTEwsIEFEVDc0MTBfU1RBVF9UX0NSSVQpOwo+ICtzdGF0aWMg
REVWSUNFX0FUVFIobmFtZSwgU19JUlVHTywgYWR0NzQxMF9zaG93X25hbWUsIE5VTEwpOwo+ICsK
PiArc3RhdGljIHN0cnVjdCBhdHRyaWJ1dGUgKmFkdDc0MTBfYXR0cmlidXRlc1tdID0gewo+ICsJ
JnNlbnNvcl9kZXZfYXR0cl90ZW1wMV9pbnB1dC5kZXZfYXR0ci5hdHRyLAo+ICsJJnNlbnNvcl9k
ZXZfYXR0cl90ZW1wMV9tYXguZGV2X2F0dHIuYXR0ciwKPiArCSZzZW5zb3JfZGV2X2F0dHJfdGVt
cDFfbWluLmRldl9hdHRyLmF0dHIsCj4gKwkmc2Vuc29yX2Rldl9hdHRyX3RlbXAxX2NyaXQuZGV2
X2F0dHIuYXR0ciwKPiArCSZzZW5zb3JfZGV2X2F0dHJfdGVtcDFfbWF4X2h5c3QuZGV2X2F0dHIu
YXR0ciwKPiArCSZzZW5zb3JfZGV2X2F0dHJfdGVtcDFfbWluX2h5c3QuZGV2X2F0dHIuYXR0ciwK
PiArCSZzZW5zb3JfZGV2X2F0dHJfdGVtcDFfY3JpdF9oeXN0LmRldl9hdHRyLmF0dHIsCj4gKwkm
c2Vuc29yX2Rldl9hdHRyX3RlbXAxX21pbl9hbGFybS5kZXZfYXR0ci5hdHRyLAo+ICsJJnNlbnNv
cl9kZXZfYXR0cl90ZW1wMV9tYXhfYWxhcm0uZGV2X2F0dHIuYXR0ciwKPiArCSZzZW5zb3JfZGV2
X2F0dHJfdGVtcDFfY3JpdF9hbGFybS5kZXZfYXR0ci5hdHRyLAo+ICsJTlVMTAo+ICt9Owo+ICsK
PiArc3RhdGljIGNvbnN0IHN0cnVjdCBhdHRyaWJ1dGVfZ3JvdXAgYWR0NzQxMF9ncm91cCA9IHsK
PiArCS5hdHRycyA9IGFkdDc0MTBfYXR0cmlidXRlcywKPiArfTsKPiArCj4gK2ludCBhZHQ3NDEw
X3Byb2JlKHN0cnVjdCBkZXZpY2UgKmRldiwgY29uc3QgY2hhciAqbmFtZSwKPiArCWNvbnN0IHN0
cnVjdCBhZHQ3NDEwX29wcyAqb3BzKQo+ICt7Cj4gKwlzdHJ1Y3QgYWR0NzQxMF9kYXRhICpkYXRh
Owo+ICsJaW50IHJldDsKPiArCj4gKwlkYXRhID0gZGV2bV9remFsbG9jKGRldiwgc2l6ZW9mKHN0
cnVjdCBhZHQ3NDEwX2RhdGEpLAo+ICsJCQkgICAgR0ZQX0tFUk5FTCk7Cj4gKwlpZiAoIWRhdGEp
Cj4gKwkJcmV0dXJuIC1FTk9NRU07Cj4gKwo+ICsJZGF0YS0+b3BzID0gb3BzOwo+ICsJZGF0YS0+
bmFtZSA9IG5hbWU7Cj4gKwo+ICsJZGV2X3NldF9kcnZkYXRhKGRldiwgZGF0YSk7Cj4gKwltdXRl
eF9pbml0KCZkYXRhLT51cGRhdGVfbG9jayk7Cj4gKwo+ICsJLyogY29uZmlndXJlIGFzIHNwZWNp
ZmllZCAqLwo+ICsJcmV0ID0gYWR0NzQxMF9yZWFkX2J5dGUoZGV2LCBBRFQ3NDEwX0NPTkZJRywg
JmRhdGEtPm9sZGNvbmZpZyk7Cj4gKwlpZiAocmV0IDwgMCkgewo+ICsJCWRldl9kYmcoZGV2LCAi
Q2FuJ3QgcmVhZCBjb25maWc/ICVkXG4iLCByZXQpOwo+ICsJCXJldHVybiByZXQ7Cj4gKwl9Cj4g
KwkvKgo+ICsJICogU2V0IHRvIDE2IGJpdCByZXNvbHV0aW9uLCBjb250aW5vdXMgY29udmVyc2lv
biBhbmQgY29tcGFyYXRvciBtb2RlLgo+ICsJICovCj4gKwlkYXRhLT5jb25maWcgPSBkYXRhLT5v
bGRjb25maWc7Cj4gKwlkYXRhLT5jb25maWcgJj0gfkFEVDc0MTBfTU9ERV9NQVNLOwo+ICsJZGF0
YS0+Y29uZmlnIHw9IEFEVDc0MTBfRlVMTCB8IEFEVDc0MTBfUkVTT0xVVElPTiB8IEFEVDc0MTBf
RVZFTlRfTU9ERTsKPiArCWlmIChkYXRhLT5jb25maWcgIT0gZGF0YS0+b2xkY29uZmlnKSB7Cj4g
KwkJcmV0ID0gYWR0NzQxMF93cml0ZV9ieXRlKGRldiwgQURUNzQxMF9DT05GSUcsIGRhdGEtPmNv
bmZpZyk7Cj4gKwkJaWYgKHJldCkKPiArCQkJcmV0dXJuIHJldDsKPiArCX0KPiArCWRldl9kYmco
ZGV2LCAiQ29uZmlnICUwMnhcbiIsIGRhdGEtPmNvbmZpZyk7Cj4gKwo+ICsJcmV0ID0gYWR0NzQx
MF9maWxsX2NhY2hlKGRldik7Cj4gKwlpZiAocmV0KQo+ICsJCWdvdG8gZXhpdF9yZXN0b3JlOwo+
ICsKPiArCS8qIFJlZ2lzdGVyIHN5c2ZzIGhvb2tzICovCj4gKwlyZXQgPSBzeXNmc19jcmVhdGVf
Z3JvdXAoJmRldi0+a29iaiwgJmFkdDc0MTBfZ3JvdXApOwo+ICsJaWYgKHJldCkKPiArCQlnb3Rv
IGV4aXRfcmVzdG9yZTsKPiArCj4gKwkvKgo+ICsJICogVGhlIEkyQyBkZXZpY2Ugd2lsbCBhbHJl
YWR5IGhhdmUgaXQncyBvd24gJ25hbWUnIGF0dHJpYnV0ZSwgYnV0IGZvcgo+ICsJICogdGhlIFNQ
SSBkZXZpY2Ugd2UgbmVlZCB0byByZWdpc3RlciBpdC4gbmFtZSB3aWxsIG9ubHkgYmUgbm9uIE5V
TEwgaWYKPiArCSAqIHRoZSBkZXZpY2UgZG9lc24ndCByZWdpc3RlciB0aGUgJ25hbWUnIGF0dHJp
YnV0ZSBvbiBpdHMgb3duLgo+ICsJICovCj4gKwlpZiAobmFtZSkgewo+ICsJCXJldCA9IGRldmlj
ZV9jcmVhdGVfZmlsZShkZXYsICZkZXZfYXR0cl9uYW1lKTsKPiArCQlpZiAocmV0KQo+ICsJCQln
b3RvIGV4aXRfcmVtb3ZlOwo+ICsJfQo+ICsKPiArCWRhdGEtPmh3bW9uX2RldiA9IGh3bW9uX2Rl
dmljZV9yZWdpc3RlcihkZXYpOwo+ICsJaWYgKElTX0VSUihkYXRhLT5od21vbl9kZXYpKSB7Cj4g
KwkJcmV0ID0gUFRSX0VSUihkYXRhLT5od21vbl9kZXYpOwo+ICsJCWdvdG8gZXhpdF9yZW1vdmVf
bmFtZTsKPiArCX0KPiArCj4gKwlyZXR1cm4gMDsKPiArCj4gK2V4aXRfcmVtb3ZlX25hbWU6Cj4g
KwlpZiAobmFtZSkKPiArCQlkZXZpY2VfcmVtb3ZlX2ZpbGUoZGV2LCAmZGV2X2F0dHJfbmFtZSk7
Cj4gK2V4aXRfcmVtb3ZlOgo+ICsJc3lzZnNfcmVtb3ZlX2dyb3VwKCZkZXYtPmtvYmosICZhZHQ3
NDEwX2dyb3VwKTsKPiArZXhpdF9yZXN0b3JlOgo+ICsJYWR0NzQxMF93cml0ZV9ieXRlKGRldiwg
QURUNzQxMF9DT05GSUcsIGRhdGEtPm9sZGNvbmZpZyk7Cj4gKwlyZXR1cm4gcmV0Owo+ICt9Cj4g
K0VYUE9SVF9TWU1CT0xfR1BMKGFkdDc0MTBfcHJvYmUpOwo+ICsKPiAraW50IGFkdDc0MTBfcmVt
b3ZlKHN0cnVjdCBkZXZpY2UgKmRldikKPiArewo+ICsJc3RydWN0IGFkdDc0MTBfZGF0YSAqZGF0
YSA9IGRldl9nZXRfZHJ2ZGF0YShkZXYpOwo+ICsKPiArCWh3bW9uX2RldmljZV91bnJlZ2lzdGVy
KGRhdGEtPmh3bW9uX2Rldik7Cj4gKwlpZiAoZGF0YS0+bmFtZSkKPiArCQlkZXZpY2VfcmVtb3Zl
X2ZpbGUoZGV2LCAmZGV2X2F0dHJfbmFtZSk7Cj4gKwlzeXNmc19yZW1vdmVfZ3JvdXAoJmRldi0+
a29iaiwgJmFkdDc0MTBfZ3JvdXApOwo+ICsJaWYgKGRhdGEtPm9sZGNvbmZpZyAhPSBkYXRhLT5j
b25maWcpCj4gKwkJYWR0NzQxMF93cml0ZV9ieXRlKGRldiwgQURUNzQxMF9DT05GSUcsCj4gKwkJ
CQkJICBkYXRhLT5vbGRjb25maWcpOwo+ICsJcmV0dXJuIDA7Cj4gK30KPiArRVhQT1JUX1NZTUJP
TF9HUEwoYWR0NzQxMF9yZW1vdmUpOwo+ICsKPiArI2lmZGVmIENPTkZJR19QTV9TTEVFUAo+ICsK
PiArc3RhdGljIGludCBhZHQ3NDEwX3N1c3BlbmQoc3RydWN0IGRldmljZSAqZGV2KQo+ICt7Cj4g
KwlzdHJ1Y3QgYWR0NzQxMF9kYXRhICpkYXRhID0gZGV2X2dldF9kcnZkYXRhKGRldik7Cj4gKwo+
ICsJcmV0dXJuIGFkdDc0MTBfd3JpdGVfYnl0ZShkZXYsIEFEVDc0MTBfQ09ORklHLAo+ICsJCWRh
dGEtPmNvbmZpZyB8IEFEVDc0MTBfUEQpOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IGFkdDc0MTBf
cmVzdW1lKHN0cnVjdCBkZXZpY2UgKmRldikKPiArewo+ICsJc3RydWN0IGFkdDc0MTBfZGF0YSAq
ZGF0YSA9IGRldl9nZXRfZHJ2ZGF0YShkZXYpOwo+ICsKPiArCXJldHVybiBhZHQ3NDEwX3dyaXRl
X2J5dGUoZGV2LCBBRFQ3NDEwX0NPTkZJRywgZGF0YS0+Y29uZmlnKTsKPiArfQo+ICsKPiArU0lN
UExFX0RFVl9QTV9PUFMoYWR0NzQxMF9kZXZfcG1fb3BzLCBhZHQ3NDEwX3N1c3BlbmQsIGFkdDc0
MTBfcmVzdW1lKTsKPiArRVhQT1JUX1NZTUJPTF9HUEwoYWR0NzQxMF9kZXZfcG1fb3BzKTsKPiAr
Cj4gKyNlbmRpZiAvKiBDT05GSUdfUE1fU0xFRVAgKi8KPiArCj4gK01PRFVMRV9BVVRIT1IoIkhh
cnRtdXQgS25hYWNrIik7Cj4gK01PRFVMRV9ERVNDUklQVElPTigiQURUNzQxMCBkcml2ZXIiKTsK
VGhpcyBkZXNjcmlwdGlvbiBkb2VzIG5vdCBzZWVtIGFwcHJvcHJpYXRlIGFueSBsb25nZXIuCj4g
K01PRFVMRV9MSUNFTlNFKCJHUEwiKTsKPC4uLj4KCgpfX19fX19fX19fX19fX19fX19fX19fX19f
X19fX19fX19fX19fX19fX19fX19fXwpsbS1zZW5zb3JzIG1haWxpbmcgbGlzdApsbS1zZW5zb3Jz
QGxtLXNlbnNvcnMub3JnCmh0dHA6Ly9saXN0cy5sbS1zZW5zb3JzLm9yZy9tYWlsbWFuL2xpc3Rp
bmZvL2xtLXNlbnNvcnM

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

* Re: [PATCH 1/9] hwmon: (adt7410) Clear unwanted bits in the config register
  2013-02-15 16:57 ` [lm-sensors] " Lars-Peter Clausen
@ 2013-02-15 20:06   ` Guenter Roeck
  -1 siblings, 0 replies; 56+ messages in thread
From: Guenter Roeck @ 2013-02-15 20:06 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Jean Delvare, Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio

On Fri, Feb 15, 2013 at 05:57:10PM +0100, Lars-Peter Clausen wrote:
> Make sure to clear the mode bits from the config register before setting the new
> mode. Otherwise we might end up with a different mode than we want to.
> 
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>

Applied to hwmon-next.

Thanks,
Guenter

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

* Re: [lm-sensors] [PATCH 1/9] hwmon: (adt7410) Clear unwanted bits in the config register
@ 2013-02-15 20:06   ` Guenter Roeck
  0 siblings, 0 replies; 56+ messages in thread
From: Guenter Roeck @ 2013-02-15 20:06 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Jean Delvare, Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio

On Fri, Feb 15, 2013 at 05:57:10PM +0100, Lars-Peter Clausen wrote:
> Make sure to clear the mode bits from the config register before setting the new
> mode. Otherwise we might end up with a different mode than we want to.
> 
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>

Applied to hwmon-next.

Thanks,
Guenter

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

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

* Re: [PATCH 2/9] hwmon: (adt7410) Let suspend/resume depend on CONFIG_PM_SLEEP
  2013-02-15 16:57   ` [lm-sensors] " Lars-Peter Clausen
@ 2013-02-15 20:07     ` Guenter Roeck
  -1 siblings, 0 replies; 56+ messages in thread
From: Guenter Roeck @ 2013-02-15 20:07 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Jean Delvare, Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio

On Fri, Feb 15, 2013 at 05:57:11PM +0100, Lars-Peter Clausen wrote:
> Only build the suspend/resume code if CONFIG_PM_SLEEP is selected. Currently the
> code is built if CONFIG_PM is selected, but it will also be selected if only
> runtime PM support is built into the kernel.
> 
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>

Applied to hwmon-next.

Thanks,
Guenter

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

* Re: [lm-sensors] [PATCH 2/9] hwmon: (adt7410) Let suspend/resume depend on CONFIG_PM_SLEEP
@ 2013-02-15 20:07     ` Guenter Roeck
  0 siblings, 0 replies; 56+ messages in thread
From: Guenter Roeck @ 2013-02-15 20:07 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Jean Delvare, Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio

On Fri, Feb 15, 2013 at 05:57:11PM +0100, Lars-Peter Clausen wrote:
> Only build the suspend/resume code if CONFIG_PM_SLEEP is selected. Currently the
> code is built if CONFIG_PM is selected, but it will also be selected if only
> runtime PM support is built into the kernel.
> 
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>

Applied to hwmon-next.

Thanks,
Guenter

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

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

* Re: [PATCH 3/9] hwmon: (adt7410) Use the SIMPLE_DEV_PM_OPS helper macro
  2013-02-15 16:57   ` [lm-sensors] " Lars-Peter Clausen
@ 2013-02-15 20:07     ` Guenter Roeck
  -1 siblings, 0 replies; 56+ messages in thread
From: Guenter Roeck @ 2013-02-15 20:07 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Jean Delvare, Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio

On Fri, Feb 15, 2013 at 05:57:12PM +0100, Lars-Peter Clausen wrote:
> Use the SIMPLE_DEV_PM_OPS macro to declare the driver's pm_ops.
> 
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>

Applied to hwmon-next.

Thanks,
Guenter

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

* Re: [lm-sensors] [PATCH 3/9] hwmon: (adt7410) Use the SIMPLE_DEV_PM_OPS helper macro
@ 2013-02-15 20:07     ` Guenter Roeck
  0 siblings, 0 replies; 56+ messages in thread
From: Guenter Roeck @ 2013-02-15 20:07 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Jean Delvare, Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio

On Fri, Feb 15, 2013 at 05:57:12PM +0100, Lars-Peter Clausen wrote:
> Use the SIMPLE_DEV_PM_OPS macro to declare the driver's pm_ops.
> 
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>

Applied to hwmon-next.

Thanks,
Guenter

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

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

* Re: [PATCH 4/9] hwmon: (adt7410) Use I2C_ADDRS helper macro
  2013-02-15 16:57   ` [lm-sensors] " Lars-Peter Clausen
@ 2013-02-15 20:07     ` Guenter Roeck
  -1 siblings, 0 replies; 56+ messages in thread
From: Guenter Roeck @ 2013-02-15 20:07 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Jean Delvare, Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio

On Fri, Feb 15, 2013 at 05:57:13PM +0100, Lars-Peter Clausen wrote:
> Use the I2C_ADDRS macro to initialize the I2C device's address_list. Doing so
> saves a few lines of boilerplate code.
> 
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>

Applied to hwmon-next.

Thanks,
Guenter

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

* Re: [lm-sensors] [PATCH 4/9] hwmon: (adt7410) Use I2C_ADDRS helper macro
@ 2013-02-15 20:07     ` Guenter Roeck
  0 siblings, 0 replies; 56+ messages in thread
From: Guenter Roeck @ 2013-02-15 20:07 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Jean Delvare, Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio

On Fri, Feb 15, 2013 at 05:57:13PM +0100, Lars-Peter Clausen wrote:
> Use the I2C_ADDRS macro to initialize the I2C device's address_list. Doing so
> saves a few lines of boilerplate code.
> 
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>

Applied to hwmon-next.

Thanks,
Guenter

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

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

* Re: [PATCH 5/9] hwmon: (adt7410) Add device table entry for the adt7420
  2013-02-15 16:57   ` [lm-sensors] " Lars-Peter Clausen
@ 2013-02-15 20:08     ` Guenter Roeck
  -1 siblings, 0 replies; 56+ messages in thread
From: Guenter Roeck @ 2013-02-15 20:08 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Jean Delvare, Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio

On Fri, Feb 15, 2013 at 05:57:14PM +0100, Lars-Peter Clausen wrote:
> The adt7420 is software compatible to the adt7410.
> 
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>

Applied to hwmon-next.

Thanks,
Guenter

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

* Re: [lm-sensors] [PATCH 5/9] hwmon: (adt7410) Add device table entry for the adt7420
@ 2013-02-15 20:08     ` Guenter Roeck
  0 siblings, 0 replies; 56+ messages in thread
From: Guenter Roeck @ 2013-02-15 20:08 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Jean Delvare, Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio

On Fri, Feb 15, 2013 at 05:57:14PM +0100, Lars-Peter Clausen wrote:
> The adt7420 is software compatible to the adt7410.
> 
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>

Applied to hwmon-next.

Thanks,
Guenter

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

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

* Re: [PATCH 6/9] hwmon: (adt7410) Don't re-read non-volatile registers
  2013-02-15 16:57   ` [lm-sensors] " Lars-Peter Clausen
@ 2013-02-15 20:20     ` Guenter Roeck
  -1 siblings, 0 replies; 56+ messages in thread
From: Guenter Roeck @ 2013-02-15 20:20 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Jean Delvare, Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio

On Fri, Feb 15, 2013 at 05:57:15PM +0100, Lars-Peter Clausen wrote:
> Currently each time the temperature register is read the driver also reads the
> threshold and hysteresis registers. This increases the amount of I2C traffic and
> time needed to read the temperature by a factor of ~5. Neither the threshold nor
> the hysteresis change on their own, so once we've read them, we should be able
> to just use the cached value of the registers. This patch modifies the code
> accordingly and only reads the threshold and hysteresis registers once during
> probe.
> 
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
> ---
>  drivers/hwmon/adt7410.c | 89 +++++++++++++++++++++++++++++++------------------
>  1 file changed, 56 insertions(+), 33 deletions(-)
> 
> diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
> index 99a7290..5de0376 100644
> --- a/drivers/hwmon/adt7410.c
> +++ b/drivers/hwmon/adt7410.c
> @@ -119,45 +119,31 @@ static int adt7410_temp_ready(struct i2c_client *client)
>  	return -ETIMEDOUT;
>  }
>  
> -static struct adt7410_data *adt7410_update_device(struct device *dev)
> +static int adt7410_update_temp(struct device *dev)
>  {
>  	struct i2c_client *client = to_i2c_client(dev);
>  	struct adt7410_data *data = i2c_get_clientdata(client);
> -	struct adt7410_data *ret = data;
> +	int ret = 0;
> +
>  	mutex_lock(&data->update_lock);
>  
>  	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
>  	    || !data->valid) {
> -		int i, status;
>  
>  		dev_dbg(&client->dev, "Starting update\n");
>  
> -		status = adt7410_temp_ready(client); /* check for new value */
> -		if (unlikely(status)) {
> -			ret = ERR_PTR(status);
> +		ret = adt7410_temp_ready(client); /* check for new value */
> +		if (ret)
>  			goto abort;
> -		}
> -		for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
> -			status = i2c_smbus_read_word_swapped(client,
> -							ADT7410_REG_TEMP[i]);
> -			if (unlikely(status < 0)) {
> -				dev_dbg(dev,
> -					"Failed to read value: reg %d, error %d\n",
> -					ADT7410_REG_TEMP[i], status);
> -				ret = ERR_PTR(status);
> -				goto abort;
> -			}
> -			data->temp[i] = status;
> -		}
> -		status = i2c_smbus_read_byte_data(client, ADT7410_T_HYST);
> -		if (unlikely(status < 0)) {
> -			dev_dbg(dev,
> -				"Failed to read value: reg %d, error %d\n",
> -				ADT7410_T_HYST, status);
> -			ret = ERR_PTR(status);
> +
> +		ret = i2c_smbus_read_word_swapped(client, ADT7410_REG_TEMP[0]);
> +		if (ret) {

Should be
		if (ret < 0) {

or non-zero temperatures always create an error condition.

> +			dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
> +				ADT7410_REG_TEMP[0], ret);
>  			goto abort;
>  		}
> -		data->hyst = status;
> +		data->temp[0] = ret;
> +
>  		data->last_updated = jiffies;
>  		data->valid = true;
>  	}
> @@ -167,6 +153,35 @@ abort:
>  	return ret;

	ret can be > 0 as no-error return. So you'll either have to
	change the no-error return case to always return 0, or change the
	return value check when the function is called.
>  }
>  
> +static int adt7410_fill_cache(struct i2c_client *client)
> +{
> +	struct adt7410_data *data = i2c_get_clientdata(client);
> +	int ret;
> +	int i;
> +
> +	for (i = 1; i < 3; i++) {

I think using ARRAY_SIZE would be better here. With "i < 3" you don't read the
critical temperature, which proves the point (unless I am missing something).

> +		ret = i2c_smbus_read_word_swapped(client, ADT7410_REG_TEMP[i]);
> +		if (ret) {

		ret < 0

> +			dev_dbg(&client->dev,
> +				"Failed to read value: reg %d, error %d\n",
> +				ADT7410_REG_TEMP[0], ret);
> +			return ret;
> +		}
> +		data->temp[i] = ret;
> +	}
> +
> +	ret = i2c_smbus_read_byte_data(client, ADT7410_T_HYST);
> +	if (ret) {

	ret < 0

> +		dev_dbg(&client->dev,
> +			"Failed to read value: hyst reg, error %d\n",
> +			ret);
> +		return ret;
> +	}
> +	data->hyst = ret;
> +
> +	return 0;
> +}
> +
>  static s16 ADT7410_TEMP_TO_REG(long temp)
>  {
>  	return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7410_TEMP_MIN,
> @@ -193,10 +208,16 @@ static ssize_t adt7410_show_temp(struct device *dev,
>  				 struct device_attribute *da, char *buf)
>  {
>  	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
> -	struct adt7410_data *data = adt7410_update_device(dev);
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct adt7410_data *data = i2c_get_clientdata(client);
>  
> -	if (IS_ERR(data))
> -		return PTR_ERR(data);
> +	if (attr->index == 0) {
> +		int ret;
> +
> +		ret = adt7410_update_temp(dev);
> +		if (ret)

Problematic; see above.

> +			return ret;
> +	}
>  
>  	return sprintf(buf, "%d\n", ADT7410_REG_TO_TEMP(data,
>  		       data->temp[attr->index]));
> @@ -232,13 +253,11 @@ static ssize_t adt7410_show_t_hyst(struct device *dev,
>  				   char *buf)
>  {
>  	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
> -	struct adt7410_data *data;
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct adt7410_data *data = i2c_get_clientdata(client);
>  	int nr = attr->index;
>  	int hyst;
>  
> -	data = adt7410_update_device(dev);
> -	if (IS_ERR(data))
> -		return PTR_ERR(data);
>  	hyst = (data->hyst & ADT7410_T_HYST_MASK) * 1000;
>  
>  	/*
> @@ -371,6 +390,10 @@ static int adt7410_probe(struct i2c_client *client,
>  	}
>  	dev_dbg(&client->dev, "Config %02x\n", data->config);
>  
> +	ret = adt7410_fill_cache(client);
> +	if (ret)
> +		goto exit_restore;
> +
>  	/* Register sysfs hooks */
>  	ret = sysfs_create_group(&client->dev.kobj, &adt7410_group);
>  	if (ret)
> -- 
> 1.8.0
> 
> 

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

* Re: [lm-sensors] [PATCH 6/9] hwmon: (adt7410) Don't re-read non-volatile registers
@ 2013-02-15 20:20     ` Guenter Roeck
  0 siblings, 0 replies; 56+ messages in thread
From: Guenter Roeck @ 2013-02-15 20:20 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Jean Delvare, Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio

On Fri, Feb 15, 2013 at 05:57:15PM +0100, Lars-Peter Clausen wrote:
> Currently each time the temperature register is read the driver also reads the
> threshold and hysteresis registers. This increases the amount of I2C traffic and
> time needed to read the temperature by a factor of ~5. Neither the threshold nor
> the hysteresis change on their own, so once we've read them, we should be able
> to just use the cached value of the registers. This patch modifies the code
> accordingly and only reads the threshold and hysteresis registers once during
> probe.
> 
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
> ---
>  drivers/hwmon/adt7410.c | 89 +++++++++++++++++++++++++++++++------------------
>  1 file changed, 56 insertions(+), 33 deletions(-)
> 
> diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
> index 99a7290..5de0376 100644
> --- a/drivers/hwmon/adt7410.c
> +++ b/drivers/hwmon/adt7410.c
> @@ -119,45 +119,31 @@ static int adt7410_temp_ready(struct i2c_client *client)
>  	return -ETIMEDOUT;
>  }
>  
> -static struct adt7410_data *adt7410_update_device(struct device *dev)
> +static int adt7410_update_temp(struct device *dev)
>  {
>  	struct i2c_client *client = to_i2c_client(dev);
>  	struct adt7410_data *data = i2c_get_clientdata(client);
> -	struct adt7410_data *ret = data;
> +	int ret = 0;
> +
>  	mutex_lock(&data->update_lock);
>  
>  	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
>  	    || !data->valid) {
> -		int i, status;
>  
>  		dev_dbg(&client->dev, "Starting update\n");
>  
> -		status = adt7410_temp_ready(client); /* check for new value */
> -		if (unlikely(status)) {
> -			ret = ERR_PTR(status);
> +		ret = adt7410_temp_ready(client); /* check for new value */
> +		if (ret)
>  			goto abort;
> -		}
> -		for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
> -			status = i2c_smbus_read_word_swapped(client,
> -							ADT7410_REG_TEMP[i]);
> -			if (unlikely(status < 0)) {
> -				dev_dbg(dev,
> -					"Failed to read value: reg %d, error %d\n",
> -					ADT7410_REG_TEMP[i], status);
> -				ret = ERR_PTR(status);
> -				goto abort;
> -			}
> -			data->temp[i] = status;
> -		}
> -		status = i2c_smbus_read_byte_data(client, ADT7410_T_HYST);
> -		if (unlikely(status < 0)) {
> -			dev_dbg(dev,
> -				"Failed to read value: reg %d, error %d\n",
> -				ADT7410_T_HYST, status);
> -			ret = ERR_PTR(status);
> +
> +		ret = i2c_smbus_read_word_swapped(client, ADT7410_REG_TEMP[0]);
> +		if (ret) {

Should be
		if (ret < 0) {

or non-zero temperatures always create an error condition.

> +			dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
> +				ADT7410_REG_TEMP[0], ret);
>  			goto abort;
>  		}
> -		data->hyst = status;
> +		data->temp[0] = ret;
> +
>  		data->last_updated = jiffies;
>  		data->valid = true;
>  	}
> @@ -167,6 +153,35 @@ abort:
>  	return ret;

	ret can be > 0 as no-error return. So you'll either have to
	change the no-error return case to always return 0, or change the
	return value check when the function is called.
>  }
>  
> +static int adt7410_fill_cache(struct i2c_client *client)
> +{
> +	struct adt7410_data *data = i2c_get_clientdata(client);
> +	int ret;
> +	int i;
> +
> +	for (i = 1; i < 3; i++) {

I think using ARRAY_SIZE would be better here. With "i < 3" you don't read the
critical temperature, which proves the point (unless I am missing something).

> +		ret = i2c_smbus_read_word_swapped(client, ADT7410_REG_TEMP[i]);
> +		if (ret) {

		ret < 0

> +			dev_dbg(&client->dev,
> +				"Failed to read value: reg %d, error %d\n",
> +				ADT7410_REG_TEMP[0], ret);
> +			return ret;
> +		}
> +		data->temp[i] = ret;
> +	}
> +
> +	ret = i2c_smbus_read_byte_data(client, ADT7410_T_HYST);
> +	if (ret) {

	ret < 0

> +		dev_dbg(&client->dev,
> +			"Failed to read value: hyst reg, error %d\n",
> +			ret);
> +		return ret;
> +	}
> +	data->hyst = ret;
> +
> +	return 0;
> +}
> +
>  static s16 ADT7410_TEMP_TO_REG(long temp)
>  {
>  	return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7410_TEMP_MIN,
> @@ -193,10 +208,16 @@ static ssize_t adt7410_show_temp(struct device *dev,
>  				 struct device_attribute *da, char *buf)
>  {
>  	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
> -	struct adt7410_data *data = adt7410_update_device(dev);
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct adt7410_data *data = i2c_get_clientdata(client);
>  
> -	if (IS_ERR(data))
> -		return PTR_ERR(data);
> +	if (attr->index = 0) {
> +		int ret;
> +
> +		ret = adt7410_update_temp(dev);
> +		if (ret)

Problematic; see above.

> +			return ret;
> +	}
>  
>  	return sprintf(buf, "%d\n", ADT7410_REG_TO_TEMP(data,
>  		       data->temp[attr->index]));
> @@ -232,13 +253,11 @@ static ssize_t adt7410_show_t_hyst(struct device *dev,
>  				   char *buf)
>  {
>  	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
> -	struct adt7410_data *data;
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct adt7410_data *data = i2c_get_clientdata(client);
>  	int nr = attr->index;
>  	int hyst;
>  
> -	data = adt7410_update_device(dev);
> -	if (IS_ERR(data))
> -		return PTR_ERR(data);
>  	hyst = (data->hyst & ADT7410_T_HYST_MASK) * 1000;
>  
>  	/*
> @@ -371,6 +390,10 @@ static int adt7410_probe(struct i2c_client *client,
>  	}
>  	dev_dbg(&client->dev, "Config %02x\n", data->config);
>  
> +	ret = adt7410_fill_cache(client);
> +	if (ret)
> +		goto exit_restore;
> +
>  	/* Register sysfs hooks */
>  	ret = sysfs_create_group(&client->dev.kobj, &adt7410_group);
>  	if (ret)
> -- 
> 1.8.0
> 
> 

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

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

* Re: [PATCH 7/9] hwmon: (adt7410) Add support for the adt7310/adt7320
  2013-02-15 16:57   ` [lm-sensors] [PATCH 7/9] hwmon: (adt7410) Add =?utf-8?q?_support_for_the_adt73 Lars-Peter Clausen
@ 2013-02-15 20:32     ` Guenter Roeck
  -1 siblings, 0 replies; 56+ messages in thread
From: Guenter Roeck @ 2013-02-15 20:32 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Jean Delvare, Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio

On Fri, Feb 15, 2013 at 05:57:16PM +0100, Lars-Peter Clausen wrote:
> The adt7310/adt7320 is the SPI version of the adt7410/adt7320. The register map
> layout is a bit different, i.e. the register addresses differ between the two
> variants, but the bit layouts of the individual registers are identical. So both
> chip variants can easily be supported by the same driver. The issue of non
> matching register address layouts is solved by a simple look-up table which
> translates the I2C addresses to the SPI addresses.
> 
> The patch moves the bulk of the adt7410 driver to a common module that will be
> shared by the adt7410 and adt7310 drivers. This common module implements the
> driver logic and uses a set of virtual functions to perform IO access. The
> adt7410 and adt7310 driver modules provide proper implementations of these IO
> accessor functions for I2C respective SPI.
> 
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
> ---
>  drivers/hwmon/Kconfig   |  20 ++
>  drivers/hwmon/Makefile  |   2 +
>  drivers/hwmon/adt7310.c | 160 ++++++++++++++++
>  drivers/hwmon/adt7410.c | 472 ++++++-----------------------------------------
>  drivers/hwmon/adt7x10.c | 476 ++++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/hwmon/adt7x10.h |  47 +++++
>  6 files changed, 758 insertions(+), 419 deletions(-)
>  create mode 100644 drivers/hwmon/adt7310.c
>  create mode 100644 drivers/hwmon/adt7x10.c
>  create mode 100644 drivers/hwmon/adt7x10.h
> 
> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> index 89ac1cb..aaa14f4 100644
> --- a/drivers/hwmon/Kconfig
> +++ b/drivers/hwmon/Kconfig
> @@ -179,9 +179,29 @@ config SENSORS_ADM9240
>  	  This driver can also be built as a module.  If so, the module
>  	  will be called adm9240.
>  
> +config SENSORS_ADT7X10
> +	tristate
> +	help
> +	  This module contains common code shared by the ADT7310/ADT7320 and
> +	  ADT7410/ADT7420 temperature monitoring chip drivers.
> +
> +	  If build as a module, the module will be called adt7x10.
> +
> +config SENSORS_ADT7310
> +	tristate "Analog Devices ADT7310/ADT7320"
> +	depends on SPI_MASTER
> +	select SENSORS_ADT7X10
> +	help
> +	  If you say yes here you get support for the Analog Devices
> +	  ADT7310 and ADT7320 temperature monitoring chips.
> +
> +	  This driver can also be built as a module. If so, the module
> +	  will be called adt7310.
> +
>  config SENSORS_ADT7410
>  	tristate "Analog Devices ADT7410/ADT7420"
>  	depends on I2C
> +	select SENSORS_ADT7X10
>  	help
>  	  If you say yes here you get support for the Analog Devices
>  	  ADT7410 and ADT7420 temperature monitoring chips.
> diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
> index 8d6d97e..5d36a57 100644
> --- a/drivers/hwmon/Makefile
> +++ b/drivers/hwmon/Makefile
> @@ -34,6 +34,8 @@ obj-$(CONFIG_SENSORS_ADM9240)	+= adm9240.o
>  obj-$(CONFIG_SENSORS_ADS1015)	+= ads1015.o
>  obj-$(CONFIG_SENSORS_ADS7828)	+= ads7828.o
>  obj-$(CONFIG_SENSORS_ADS7871)	+= ads7871.o
> +obj-$(CONFIG_SENSORS_ADT7X10)	+= adt7x10.o
> +obj-$(CONFIG_SENSORS_ADT7310)	+= adt7310.o
>  obj-$(CONFIG_SENSORS_ADT7410)	+= adt7410.o
>  obj-$(CONFIG_SENSORS_ADT7411)	+= adt7411.o
>  obj-$(CONFIG_SENSORS_ADT7462)	+= adt7462.o
> diff --git a/drivers/hwmon/adt7310.c b/drivers/hwmon/adt7310.c
> new file mode 100644
> index 0000000..0483e6c
> --- /dev/null
> +++ b/drivers/hwmon/adt7310.c
> @@ -0,0 +1,160 @@
> +/*
> + * ADT7310/ADT7310 digital temperature sensor driver
> + *
> + * Copyright 2010-2013 Analog Devices Inc.
> + *   Author: Lars-Peter Clausen <lars@metafoo.de>
> + *
> + * Licensed under the GPL-2 or later.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/spi/spi.h>
> +
> +#include "adt7x10.h"
> +
> +static const u8 adt7371_reg_table[] = {
> +	[ADT7410_TEMPERATURE]   = ADT7310_TEMPERATURE,
> +	[ADT7410_STATUS]	= ADT7310_STATUS,
> +	[ADT7410_CONFIG]	= ADT7310_CONFIG,
> +	[ADT7410_T_ALARM_HIGH]	= ADT7310_T_ALARM_HIGH,
> +	[ADT7410_T_ALARM_LOW]	= ADT7310_T_ALARM_LOW,
> +	[ADT7410_T_CRIT]	= ADT7310_T_CRIT,
> +	[ADT7410_T_HYST]	= ADT7310_T_HYST,
> +	[ADT7410_ID]		= ADT7310_ID,
> +};
> +
> +#define ADT7310_CMD_REG_MASK			0x28
> +#define ADT7310_CMD_REG_OFFSET			3
> +#define ADT7310_CMD_READ			0x40
> +#define ADT7310_CMD_CON_READ			0x4
> +
> +#define AD7310_COMMAND(reg) (adt7371_reg_table[(reg)] << ADT7310_CMD_REG_OFFSET)
> +
> +static int adt7310_spi_read_word(struct device *dev,
> +	u8 reg, u16 *data)

I don't really like the approach of separating the return value from the error
code, if both can be returned directly. There are two reasons: First, the code
gets more complex, and second, the compiler tends to get confused under some
conditions abd believe that the return value is not set. And I really don't want
to have to deal with the resulting build warnings, after getting rid of pretty
much all such warnings in the hwmon subsystem. So I'd really appreciate if you
could rewrite this and the subsequent patches to return both error and value as
function return values.

Thanks,
Guenter

> +{
> +	struct spi_device *spi = to_spi_device(dev);
> +	u8 command = AD7310_COMMAND(reg);
> +	int ret = 0;
> +
> +	command |= ADT7310_CMD_READ;
> +	ret = spi_write(spi, &command, sizeof(command));
> +	if (ret < 0) {
> +		dev_err(dev, "SPI write command error\n");
> +		return ret;
> +	}
> +
> +	ret = spi_read(spi, (u8 *)data, sizeof(*data));
> +	if (ret < 0) {
> +		dev_err(dev, "SPI read word error\n");
> +		return ret;
> +	}
> +
> +	*data = be16_to_cpu(*data);
> +
> +	return 0;
> +}
> +
> +static int adt7310_spi_write_word(struct device *dev, u8 reg,
> +	u16 data)
> +{
> +	struct spi_device *spi = to_spi_device(dev);
> +	u8 buf[3];
> +	int ret = 0;
> +
> +	buf[0] = AD7310_COMMAND(reg);
> +	buf[1] = (u8)(data >> 8);
> +	buf[2] = (u8)(data & 0xFF);
> +
> +	ret = spi_write(spi, buf, 3);
> +	if (ret < 0) {
> +		dev_err(dev, "SPI write word error\n");
> +		return ret;
> +	}
> +
> +	return ret;
> +}
> +
> +static int adt7310_spi_read_byte(struct device *dev, u8 reg,
> +	u8 *data)
> +{
> +	struct spi_device *spi = to_spi_device(dev);
> +	u8 command = AD7310_COMMAND(reg);
> +	int ret = 0;
> +
> +	command |= ADT7310_CMD_READ;
> +	ret = spi_write(spi, &command, sizeof(command));
> +	if (ret < 0) {
> +		dev_err(dev, "SPI write command error\n");
> +		return ret;
> +	}
> +
> +	ret = spi_read(spi, data, sizeof(*data));
> +	if (ret < 0) {
> +		dev_err(dev, "SPI read byte error\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int adt7310_spi_write_byte(struct device *dev, u8 reg,
> +	u8 data)
> +{
> +	struct spi_device *spi = to_spi_device(dev);
> +	u8 buf[2];
> +	int ret = 0;
> +
> +	buf[0] = AD7310_COMMAND(reg);
> +	buf[1] = data;
> +
> +	ret = spi_write(spi, buf, 2);
> +	if (ret < 0) {
> +		dev_err(dev, "SPI write byte error\n");
> +		return ret;
> +	}
> +
> +	return ret;
> +}
> +
> +static const struct adt7410_ops adt7310_spi_ops = {
> +	.read_word = adt7310_spi_read_word,
> +	.write_word = adt7310_spi_write_word,
> +	.read_byte = adt7310_spi_read_byte,
> +	.write_byte = adt7310_spi_write_byte,
> +};
> +
> +static int adt7310_spi_probe(struct spi_device *spi)
> +{
> +	return adt7410_probe(&spi->dev, spi_get_device_id(spi)->name,
> +			&adt7310_spi_ops);
> +}
> +
> +static int adt7310_spi_remove(struct spi_device *spi)
> +{
> +	return adt7410_remove(&spi->dev);
> +}
> +
> +static const struct spi_device_id adt7310_id[] = {
> +	{ "adt7310", 0 },
> +	{ "adt7320", 0 },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(spi, adt7310_id);
> +
> +static struct spi_driver adt7310_driver = {
> +	.driver = {
> +		.name = "adt7310",
> +		.owner = THIS_MODULE,
> +		.pm	= ADT7410_DEV_PM_OPS,
> +	},
> +	.probe = adt7310_spi_probe,
> +	.remove = adt7310_spi_remove,
> +	.id_table = adt7310_id,
> +};
> +module_spi_driver(adt7310_driver);
> +
> +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
> +MODULE_DESCRIPTION("ADT7310/ADT7420 driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
> index 5de0376..13734c5 100644
> --- a/drivers/hwmon/adt7410.c
> +++ b/drivers/hwmon/adt7410.c
> @@ -1,483 +1,117 @@
>  /*
> - * adt7410.c - Part of lm_sensors, Linux kernel modules for hardware
> - *	 monitoring
> - * This driver handles the ADT7410 and compatible digital temperature sensors.
> - * Hartmut Knaack <knaack.h@gmx.de> 2012-07-22
> - * based on lm75.c by Frodo Looijaard <frodol@dds.nl>
> - * and adt7410.c from iio-staging by Sonic Zhang <sonic.zhang@analog.com>
> + * ADT7410/ADT7420 digital temperature sensor driver
>   *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; either version 2 of the License, or
> - * (at your option) any later version.
> + * Copyright 2010-2013 Analog Devices Inc.
> + *   Author: Lars-Peter Clausen <lars@metafoo.de>
>   *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program; if not, write to the Free Software
> - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + * Licensed under the GPL-2 or later.
>   */
>  
>  #include <linux/module.h>
>  #include <linux/init.h>
> -#include <linux/slab.h>
> -#include <linux/jiffies.h>
>  #include <linux/i2c.h>
> -#include <linux/hwmon.h>
> -#include <linux/hwmon-sysfs.h>
> -#include <linux/err.h>
> -#include <linux/mutex.h>
> -#include <linux/delay.h>
> -
> -/*
> - * ADT7410 registers definition
> - */
>  
> -#define ADT7410_TEMPERATURE		0
> -#define ADT7410_STATUS			2
> -#define ADT7410_CONFIG			3
> -#define ADT7410_T_ALARM_HIGH		4
> -#define ADT7410_T_ALARM_LOW		6
> -#define ADT7410_T_CRIT			8
> -#define ADT7410_T_HYST			0xA
> +#include "adt7x10.h"
>  
> -/*
> - * ADT7410 status
> - */
> -#define ADT7410_STAT_T_LOW		(1 << 4)
> -#define ADT7410_STAT_T_HIGH		(1 << 5)
> -#define ADT7410_STAT_T_CRIT		(1 << 6)
> -#define ADT7410_STAT_NOT_RDY		(1 << 7)
> -
> -/*
> - * ADT7410 config
> - */
> -#define ADT7410_FAULT_QUEUE_MASK	(1 << 0 | 1 << 1)
> -#define ADT7410_CT_POLARITY		(1 << 2)
> -#define ADT7410_INT_POLARITY		(1 << 3)
> -#define ADT7410_EVENT_MODE		(1 << 4)
> -#define ADT7410_MODE_MASK		(1 << 5 | 1 << 6)
> -#define ADT7410_FULL			(0 << 5 | 0 << 6)
> -#define ADT7410_PD			(1 << 5 | 1 << 6)
> -#define ADT7410_RESOLUTION		(1 << 7)
> -
> -/*
> - * ADT7410 masks
> - */
> -#define ADT7410_T13_VALUE_MASK			0xFFF8
> -#define ADT7410_T_HYST_MASK			0xF
> -
> -/* straight from the datasheet */
> -#define ADT7410_TEMP_MIN (-55000)
> -#define ADT7410_TEMP_MAX 150000
> -
> -enum adt7410_type {		/* keep sorted in alphabetical order */
> -	adt7410,
> -};
> -
> -static const u8 ADT7410_REG_TEMP[4] = {
> -	ADT7410_TEMPERATURE,		/* input */
> -	ADT7410_T_ALARM_HIGH,		/* high */
> -	ADT7410_T_ALARM_LOW,		/* low */
> -	ADT7410_T_CRIT,			/* critical */
> -};
> -
> -/* Each client has this additional data */
> -struct adt7410_data {
> -	struct device		*hwmon_dev;
> -	struct mutex		update_lock;
> -	u8			config;
> -	u8			oldconfig;
> -	bool			valid;		/* true if registers valid */
> -	unsigned long		last_updated;	/* In jiffies */
> -	s16			temp[4];	/* Register values,
> -						   0 = input
> -						   1 = high
> -						   2 = low
> -						   3 = critical */
> -	u8			hyst;		/* hysteresis offset */
> -};
> -
> -/*
> - * adt7410 register access by I2C
> - */
> -static int adt7410_temp_ready(struct i2c_client *client)
> -{
> -	int i, status;
> -
> -	for (i = 0; i < 6; i++) {
> -		status = i2c_smbus_read_byte_data(client, ADT7410_STATUS);
> -		if (status < 0)
> -			return status;
> -		if (!(status & ADT7410_STAT_NOT_RDY))
> -			return 0;
> -		msleep(60);
> -	}
> -	return -ETIMEDOUT;
> -}
> -
> -static int adt7410_update_temp(struct device *dev)
> +static int adt7410_i2c_read_word(struct device *dev, u8 reg, u16 *data)
>  {
>  	struct i2c_client *client = to_i2c_client(dev);
> -	struct adt7410_data *data = i2c_get_clientdata(client);
>  	int ret = 0;
>  
> -	mutex_lock(&data->update_lock);
> -
> -	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
> -	    || !data->valid) {
> -
> -		dev_dbg(&client->dev, "Starting update\n");
> -
> -		ret = adt7410_temp_ready(client); /* check for new value */
> -		if (ret)
> -			goto abort;
> -
> -		ret = i2c_smbus_read_word_swapped(client, ADT7410_REG_TEMP[0]);
> -		if (ret) {
> -			dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
> -				ADT7410_REG_TEMP[0], ret);
> -			goto abort;
> -		}
> -		data->temp[0] = ret;
> -
> -		data->last_updated = jiffies;
> -		data->valid = true;
> -	}
> -
> -abort:
> -	mutex_unlock(&data->update_lock);
> -	return ret;
> -}
> -
> -static int adt7410_fill_cache(struct i2c_client *client)
> -{
> -	struct adt7410_data *data = i2c_get_clientdata(client);
> -	int ret;
> -	int i;
> -
> -	for (i = 1; i < 3; i++) {
> -		ret = i2c_smbus_read_word_swapped(client, ADT7410_REG_TEMP[i]);
> -		if (ret) {
> -			dev_dbg(&client->dev,
> -				"Failed to read value: reg %d, error %d\n",
> -				ADT7410_REG_TEMP[0], ret);
> -			return ret;
> -		}
> -		data->temp[i] = ret;
> -	}
> -
> -	ret = i2c_smbus_read_byte_data(client, ADT7410_T_HYST);
> -	if (ret) {
> -		dev_dbg(&client->dev,
> -			"Failed to read value: hyst reg, error %d\n",
> -			ret);
> +	ret = i2c_smbus_read_word_swapped(client, reg);
> +	if (ret < 0) {
> +		dev_err(dev, "I2C read error\n");
>  		return ret;
>  	}
> -	data->hyst = ret;
> -
> -	return 0;
> -}
>  
> -static s16 ADT7410_TEMP_TO_REG(long temp)
> -{
> -	return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7410_TEMP_MIN,
> -					   ADT7410_TEMP_MAX) * 128, 1000);
> -}
> +	*data = ret;
>  
> -static int ADT7410_REG_TO_TEMP(struct adt7410_data *data, s16 reg)
> -{
> -	/* in 13 bit mode, bits 0-2 are status flags - mask them out */
> -	if (!(data->config & ADT7410_RESOLUTION))
> -		reg &= ADT7410_T13_VALUE_MASK;
> -	/*
> -	 * temperature is stored in twos complement format, in steps of
> -	 * 1/128°C
> -	 */
> -	return DIV_ROUND_CLOSEST(reg * 1000, 128);
> +	return 0;
>  }
>  
> -/*-----------------------------------------------------------------------*/
> -
> -/* sysfs attributes for hwmon */
> -
> -static ssize_t adt7410_show_temp(struct device *dev,
> -				 struct device_attribute *da, char *buf)
> +static int adt7410_i2c_write_word(struct device *dev, u8 reg, u16 data)
>  {
> -	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
>  	struct i2c_client *client = to_i2c_client(dev);
> -	struct adt7410_data *data = i2c_get_clientdata(client);
> -
> -	if (attr->index == 0) {
> -		int ret;
> +	int ret = 0;
>  
> -		ret = adt7410_update_temp(dev);
> -		if (ret)
> -			return ret;
> -	}
> +	ret = i2c_smbus_write_word_swapped(client, reg, data);
> +	if (ret < 0)
> +		dev_err(dev, "I2C write error\n");
>  
> -	return sprintf(buf, "%d\n", ADT7410_REG_TO_TEMP(data,
> -		       data->temp[attr->index]));
> +	return ret;
>  }
>  
> -static ssize_t adt7410_set_temp(struct device *dev,
> -				struct device_attribute *da,
> -				const char *buf, size_t count)
> +static int adt7410_i2c_read_byte(struct device *dev, u8 reg, u8 *data)
>  {
> -	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
>  	struct i2c_client *client = to_i2c_client(dev);
> -	struct adt7410_data *data = i2c_get_clientdata(client);
> -	int nr = attr->index;
> -	long temp;
> -	int ret;
> +	int ret = 0;
>  
> -	ret = kstrtol(buf, 10, &temp);
> -	if (ret)
> +	ret = i2c_smbus_read_byte_data(client, reg);
> +	if (ret < 0) {
> +		dev_err(dev, "I2C read error\n");
>  		return ret;
> +	}
>  
> -	mutex_lock(&data->update_lock);
> -	data->temp[nr] = ADT7410_TEMP_TO_REG(temp);
> -	ret = i2c_smbus_write_word_swapped(client, ADT7410_REG_TEMP[nr],
> -					   data->temp[nr]);
> -	if (ret)
> -		count = ret;
> -	mutex_unlock(&data->update_lock);
> -	return count;
> -}
> -
> -static ssize_t adt7410_show_t_hyst(struct device *dev,
> -				   struct device_attribute *da,
> -				   char *buf)
> -{
> -	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
> -	struct i2c_client *client = to_i2c_client(dev);
> -	struct adt7410_data *data = i2c_get_clientdata(client);
> -	int nr = attr->index;
> -	int hyst;
> -
> -	hyst = (data->hyst & ADT7410_T_HYST_MASK) * 1000;
> -
> -	/*
> -	 * hysteresis is stored as a 4 bit offset in the device, convert it
> -	 * to an absolute value
> -	 */
> -	if (nr == 2)	/* min has positive offset, others have negative */
> -		hyst = -hyst;
> -	return sprintf(buf, "%d\n",
> -		       ADT7410_REG_TO_TEMP(data, data->temp[nr]) - hyst);
> -}
> -
> -static ssize_t adt7410_set_t_hyst(struct device *dev,
> -				  struct device_attribute *da,
> -				  const char *buf, size_t count)
> -{
> -	struct i2c_client *client = to_i2c_client(dev);
> -	struct adt7410_data *data = i2c_get_clientdata(client);
> -	int limit, ret;
> -	long hyst;
> -
> -	ret = kstrtol(buf, 10, &hyst);
> -	if (ret)
> -		return ret;
> -	/* convert absolute hysteresis value to a 4 bit delta value */
> -	limit = ADT7410_REG_TO_TEMP(data, data->temp[1]);
> -	hyst = clamp_val(hyst, ADT7410_TEMP_MIN, ADT7410_TEMP_MAX);
> -	data->hyst = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000), 0,
> -			       ADT7410_T_HYST_MASK);
> -	ret = i2c_smbus_write_byte_data(client, ADT7410_T_HYST, data->hyst);
> -	if (ret)
> -		return ret;
> +	*data = (u8)ret;
>  
> -	return count;
> +	return 0;
>  }
>  
> -static ssize_t adt7410_show_alarm(struct device *dev,
> -				  struct device_attribute *da,
> -				  char *buf)
> +static int adt7410_i2c_write_byte(struct device *dev, u8 reg, u8 data)
>  {
>  	struct i2c_client *client = to_i2c_client(dev);
> -	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
> -	int ret;
> +	int ret = 0;
>  
> -	ret = i2c_smbus_read_byte_data(client, ADT7410_STATUS);
> +	ret = i2c_smbus_write_byte_data(client, reg, data);
>  	if (ret < 0)
> -		return ret;
> +		dev_err(&client->dev, "I2C write error\n");
>  
> -	return sprintf(buf, "%d\n", !!(ret & attr->index));
> +	return ret;
>  }
>  
> -static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adt7410_show_temp, NULL, 0);
> -static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
> -			  adt7410_show_temp, adt7410_set_temp, 1);
> -static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
> -			  adt7410_show_temp, adt7410_set_temp, 2);
> -static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
> -			  adt7410_show_temp, adt7410_set_temp, 3);
> -static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
> -			  adt7410_show_t_hyst, adt7410_set_t_hyst, 1);
> -static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO,
> -			  adt7410_show_t_hyst, NULL, 2);
> -static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO,
> -			  adt7410_show_t_hyst, NULL, 3);
> -static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, adt7410_show_alarm,
> -			  NULL, ADT7410_STAT_T_LOW);
> -static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adt7410_show_alarm,
> -			  NULL, ADT7410_STAT_T_HIGH);
> -static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, adt7410_show_alarm,
> -			  NULL, ADT7410_STAT_T_CRIT);
> -
> -static struct attribute *adt7410_attributes[] = {
> -	&sensor_dev_attr_temp1_input.dev_attr.attr,
> -	&sensor_dev_attr_temp1_max.dev_attr.attr,
> -	&sensor_dev_attr_temp1_min.dev_attr.attr,
> -	&sensor_dev_attr_temp1_crit.dev_attr.attr,
> -	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
> -	&sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
> -	&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
> -	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
> -	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
> -	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
> -	NULL
> -};
> -
> -static const struct attribute_group adt7410_group = {
> -	.attrs = adt7410_attributes,
> +static const struct adt7410_ops adt7410_i2c_ops = {
> +	.read_word = adt7410_i2c_read_word,
> +	.write_word = adt7410_i2c_write_word,
> +	.read_byte = adt7410_i2c_read_byte,
> +	.write_byte = adt7410_i2c_write_byte,
>  };
>  
> -/*-----------------------------------------------------------------------*/
> -
> -/* device probe and removal */
> -
> -static int adt7410_probe(struct i2c_client *client,
> -			 const struct i2c_device_id *id)
> +static int adt7410_i2c_probe(struct i2c_client *client,
> +	const struct i2c_device_id *id)
>  {
> -	struct adt7410_data *data;
> -	int ret;
>  
>  	if (!i2c_check_functionality(client->adapter,
>  			I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
>  		return -ENODEV;
>  
> -	data = devm_kzalloc(&client->dev, sizeof(struct adt7410_data),
> -			    GFP_KERNEL);
> -	if (!data)
> -		return -ENOMEM;
> -
> -	i2c_set_clientdata(client, data);
> -	mutex_init(&data->update_lock);
> -
> -	/* configure as specified */
> -	ret = i2c_smbus_read_byte_data(client, ADT7410_CONFIG);
> -	if (ret < 0) {
> -		dev_dbg(&client->dev, "Can't read config? %d\n", ret);
> -		return ret;
> -	}
> -	data->oldconfig = ret;
> -	/*
> -	 * Set to 16 bit resolution, continous conversion and comparator mode.
> -	 */
> -	ret &= ~ADT7410_MODE_MASK;
> -	data->config = ret | ADT7410_FULL | ADT7410_RESOLUTION |
> -			ADT7410_EVENT_MODE;
> -	if (data->config != data->oldconfig) {
> -		ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
> -						data->config);
> -		if (ret)
> -			return ret;
> -	}
> -	dev_dbg(&client->dev, "Config %02x\n", data->config);
> -
> -	ret = adt7410_fill_cache(client);
> -	if (ret)
> -		goto exit_restore;
> -
> -	/* Register sysfs hooks */
> -	ret = sysfs_create_group(&client->dev.kobj, &adt7410_group);
> -	if (ret)
> -		goto exit_restore;
> -
> -	data->hwmon_dev = hwmon_device_register(&client->dev);
> -	if (IS_ERR(data->hwmon_dev)) {
> -		ret = PTR_ERR(data->hwmon_dev);
> -		goto exit_remove;
> -	}
> -
> -	dev_info(&client->dev, "sensor '%s'\n", client->name);
> -
> -	return 0;
> -
> -exit_remove:
> -	sysfs_remove_group(&client->dev.kobj, &adt7410_group);
> -exit_restore:
> -	i2c_smbus_write_byte_data(client, ADT7410_CONFIG, data->oldconfig);
> -	return ret;
> +	return adt7410_probe(&client->dev, NULL, &adt7410_i2c_ops);
>  }
>  
> -static int adt7410_remove(struct i2c_client *client)
> +static int adt7410_i2c_remove(struct i2c_client *client)
>  {
> -	struct adt7410_data *data = i2c_get_clientdata(client);
> -
> -	hwmon_device_unregister(data->hwmon_dev);
> -	sysfs_remove_group(&client->dev.kobj, &adt7410_group);
> -	if (data->oldconfig != data->config)
> -		i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
> -					  data->oldconfig);
> -	return 0;
> +	return adt7410_remove(&client->dev);
>  }
>  
> -static const struct i2c_device_id adt7410_ids[] = {
> -	{ "adt7410", adt7410, },
> -	{ "adt7420", adt7410, },
> -	{ /* LIST END */ }
> +static const struct i2c_device_id adt7410_id[] = {
> +	{ "adt7410", 0 },
> +	{ "adt7420", 0 },
> +	{}
>  };
> -MODULE_DEVICE_TABLE(i2c, adt7410_ids);
> -
> -#ifdef CONFIG_PM_SLEEP
> -static int adt7410_suspend(struct device *dev)
> -{
> -	int ret;
> -	struct i2c_client *client = to_i2c_client(dev);
> -	struct adt7410_data *data = i2c_get_clientdata(client);
> -
> -	ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
> -					data->config | ADT7410_PD);
> -	return ret;
> -}
> -
> -static int adt7410_resume(struct device *dev)
> -{
> -	int ret;
> -	struct i2c_client *client = to_i2c_client(dev);
> -	struct adt7410_data *data = i2c_get_clientdata(client);
> -
> -	ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG, data->config);
> -	return ret;
> -}
> -
> -static SIMPLE_DEV_PM_OPS(adt7410_dev_pm_ops, adt7410_suspend, adt7410_resume);
> -
> -#define ADT7410_DEV_PM_OPS (&adt7410_dev_pm_ops)
> -#else
> -#define ADT7410_DEV_PM_OPS NULL
> -#endif /* CONFIG_PM */
> +MODULE_DEVICE_TABLE(i2c, adt7410_id);
>  
>  static struct i2c_driver adt7410_driver = {
> -	.class		= I2C_CLASS_HWMON,
>  	.driver = {
> -		.name	= "adt7410",
> +		.name = "adt7410",
>  		.pm	= ADT7410_DEV_PM_OPS,
>  	},
> -	.probe		= adt7410_probe,
> -	.remove		= adt7410_remove,
> -	.id_table	= adt7410_ids,
> -	.address_list	= I2C_ADDRS(0x48, 0x49, 0x4a, 0x4b),
> +	.probe = adt7410_i2c_probe,
> +	.remove = adt7410_i2c_remove,
> +	.id_table = adt7410_id,
> +	.address_list = I2C_ADDRS(0x48, 0x49, 0x4a, 0x4b),
> +	.class = I2C_CLASS_HWMON,
>  };
> -
>  module_i2c_driver(adt7410_driver);
>  
> -MODULE_AUTHOR("Hartmut Knaack");
> -MODULE_DESCRIPTION("ADT7410/ADT7420 driver");
> +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
> +MODULE_DESCRIPTION("ADT7410/AD7420 driver");
>  MODULE_LICENSE("GPL");
> diff --git a/drivers/hwmon/adt7x10.c b/drivers/hwmon/adt7x10.c
> new file mode 100644
> index 0000000..2598aaf
> --- /dev/null
> +++ b/drivers/hwmon/adt7x10.c
> @@ -0,0 +1,476 @@
> +/*
> + * adt7410.c - Part of lm_sensors, Linux kernel modules for hardware
> + *	 monitoring
> + * This driver handles the ADT7410 and compatible digital temperature sensors.
> + * Hartmut Knaack <knaack.h@gmx.de> 2012-07-22
> + * based on lm75.c by Frodo Looijaard <frodol@dds.nl>
> + * and adt7410.c from iio-staging by Sonic Zhang <sonic.zhang@analog.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/slab.h>
> +#include <linux/jiffies.h>
> +#include <linux/hwmon.h>
> +#include <linux/hwmon-sysfs.h>
> +#include <linux/err.h>
> +#include <linux/mutex.h>
> +#include <linux/delay.h>
> +
> +#include "adt7x10.h"
> +
> +/*
> + * ADT7410 status
> + */
> +#define ADT7410_STAT_T_LOW		(1 << 4)
> +#define ADT7410_STAT_T_HIGH		(1 << 5)
> +#define ADT7410_STAT_T_CRIT		(1 << 6)
> +#define ADT7410_STAT_NOT_RDY		(1 << 7)
> +
> +/*
> + * ADT7410 config
> + */
> +#define ADT7410_FAULT_QUEUE_MASK	(1 << 0 | 1 << 1)
> +#define ADT7410_CT_POLARITY		(1 << 2)
> +#define ADT7410_INT_POLARITY		(1 << 3)
> +#define ADT7410_EVENT_MODE		(1 << 4)
> +#define ADT7410_MODE_MASK		(1 << 5 | 1 << 6)
> +#define ADT7410_FULL			(0 << 5 | 0 << 6)
> +#define ADT7410_PD			(1 << 5 | 1 << 6)
> +#define ADT7410_RESOLUTION		(1 << 7)
> +
> +/*
> + * ADT7410 masks
> + */
> +#define ADT7410_T13_VALUE_MASK			0xFFF8
> +#define ADT7410_T_HYST_MASK			0xF
> +
> +/* straight from the datasheet */
> +#define ADT7410_TEMP_MIN (-55000)
> +#define ADT7410_TEMP_MAX 150000
> +
> +/* Each client has this additional data */
> +struct adt7410_data {
> +	const struct adt7410_ops *ops;
> +	const char		*name;
> +	struct device		*hwmon_dev;
> +	struct mutex		update_lock;
> +	u8			config;
> +	u8			oldconfig;
> +	bool			valid;		/* true if registers valid */
> +	unsigned long		last_updated;	/* In jiffies */
> +	s16			temp[4];	/* Register values,
> +						   0 = input
> +						   1 = high
> +						   2 = low
> +						   3 = critical */
> +	u8			hyst;		/* hysteresis offset */
> +};
> +
> +static int adt7410_read_word(struct device *dev, u8 reg, u16 *data)
> +{
> +	struct adt7410_data *d = dev_get_drvdata(dev);
> +	return d->ops->read_word(dev, reg, data);
> +}
> +
> +static int adt7410_write_word(struct device *dev, u8 reg, u16 data)
> +{
> +	struct adt7410_data *d = dev_get_drvdata(dev);
> +	return d->ops->write_word(dev, reg, data);
> +}
> +
> +static int adt7410_read_byte(struct device *dev, u8 reg, u8 *data)
> +{
> +	struct adt7410_data *d = dev_get_drvdata(dev);
> +	return d->ops->read_byte(dev, reg, data);
> +}
> +
> +static int adt7410_write_byte(struct device *dev, u8 reg, u8 data)
> +{
> +	struct adt7410_data *d = dev_get_drvdata(dev);
> +	return d->ops->write_byte(dev, reg, data);
> +}
> +
> +static const u8 ADT7410_REG_TEMP[4] = {
> +	ADT7410_TEMPERATURE,		/* input */
> +	ADT7410_T_ALARM_HIGH,		/* high */
> +	ADT7410_T_ALARM_LOW,		/* low */
> +	ADT7410_T_CRIT,			/* critical */
> +};
> +
> +/*
> + * adt7410 register access by I2C
> + */
> +static int adt7410_temp_ready(struct device *dev)
> +{
> +	int i, ret;
> +	u8 status;
> +
> +	for (i = 0; i < 6; i++) {
> +		ret = adt7410_read_byte(dev, ADT7410_STATUS, &status);
> +		if (ret)
> +			return ret;
> +		if (!(status & ADT7410_STAT_NOT_RDY))
> +			return 0;
> +		msleep(60);
> +	}
> +	return -ETIMEDOUT;
> +}
> +
> +static int adt7410_update_temp(struct device *dev)
> +{
> +	struct adt7410_data *data = dev_get_drvdata(dev);
> +	int ret = 0;
> +
> +	mutex_lock(&data->update_lock);
> +
> +	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
> +	    || !data->valid) {
> +
> +		dev_dbg(dev, "Starting update\n");
> +
> +		ret = adt7410_temp_ready(dev); /* check for new value */
> +		if (ret)
> +			goto abort;
> +
> +		ret = adt7410_read_word(dev, ADT7410_REG_TEMP[0],
> +					&data->temp[0]);
> +		if (ret) {
> +			dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
> +				ADT7410_REG_TEMP[0], ret);
> +			goto abort;
> +		}
> +		data->last_updated = jiffies;
> +		data->valid = true;
> +	}
> +
> +abort:
> +	mutex_unlock(&data->update_lock);
> +	return ret;
> +}
> +
> +static int adt7410_fill_cache(struct device *dev)
> +{
> +	struct adt7410_data *data = dev_get_drvdata(dev);
> +	int ret;
> +	int i;
> +
> +	for (i = 1; i < ARRAY_SIZE(data->temp); i++) {
> +		ret = adt7410_read_word(dev, ADT7410_REG_TEMP[i],
> +					&data->temp[i]);
> +		if (ret) {
> +			dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
> +				ADT7410_REG_TEMP[0], ret);
> +			return ret;
> +		}
> +	}
> +
> +	ret = adt7410_read_byte(dev, ADT7410_T_HYST, &data->hyst);
> +	if (ret) {
> +		dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
> +				ADT7410_T_HYST, ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static s16 ADT7410_TEMP_TO_REG(long temp)
> +{
> +	return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7410_TEMP_MIN,
> +					       ADT7410_TEMP_MAX) * 128, 1000);
> +}
> +
> +static int ADT7410_REG_TO_TEMP(struct adt7410_data *data, s16 reg)
> +{
> +	/* in 13 bit mode, bits 0-2 are status flags - mask them out */
> +	if (!(data->config & ADT7410_RESOLUTION))
> +		reg &= ADT7410_T13_VALUE_MASK;
> +	/*
> +	 * temperature is stored in twos complement format, in steps of
> +	 * 1/128°C
> +	 */
> +	return DIV_ROUND_CLOSEST(reg * 1000, 128);
> +}
> +
> +/*-----------------------------------------------------------------------*/
> +
> +/* sysfs attributes for hwmon */
> +
> +static ssize_t adt7410_show_temp(struct device *dev,
> +				 struct device_attribute *da, char *buf)
> +{
> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
> +	struct adt7410_data *data = dev_get_drvdata(dev);
> +
> +
> +	if (attr->index == 0) {
> +		int ret;
> +
> +		ret = adt7410_update_temp(dev);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return sprintf(buf, "%d\n", ADT7410_REG_TO_TEMP(data,
> +		       data->temp[attr->index]));
> +}
> +
> +static ssize_t adt7410_set_temp(struct device *dev,
> +				struct device_attribute *da,
> +				const char *buf, size_t count)
> +{
> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
> +	struct adt7410_data *data = dev_get_drvdata(dev);
> +	int nr = attr->index;
> +	long temp;
> +	int ret;
> +
> +	ret = kstrtol(buf, 10, &temp);
> +	if (ret)
> +		return ret;
> +
> +	mutex_lock(&data->update_lock);
> +	data->temp[nr] = ADT7410_TEMP_TO_REG(temp);
> +	ret = adt7410_write_word(dev, ADT7410_REG_TEMP[nr], data->temp[nr]);
> +	if (ret)
> +		count = ret;
> +	mutex_unlock(&data->update_lock);
> +	return count;
> +}
> +
> +static ssize_t adt7410_show_t_hyst(struct device *dev,
> +				   struct device_attribute *da,
> +				   char *buf)
> +{
> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
> +	struct adt7410_data *data = dev_get_drvdata(dev);
> +	int nr = attr->index;
> +	int hyst;
> +
> +	hyst = (data->hyst & ADT7410_T_HYST_MASK) * 1000;
> +
> +	/*
> +	 * hysteresis is stored as a 4 bit offset in the device, convert it
> +	 * to an absolute value
> +	 */
> +	if (nr == 2)	/* min has positive offset, others have negative */
> +		hyst = -hyst;
> +	return sprintf(buf, "%d\n",
> +		       ADT7410_REG_TO_TEMP(data, data->temp[nr]) - hyst);
> +}
> +
> +static ssize_t adt7410_set_t_hyst(struct device *dev,
> +				  struct device_attribute *da,
> +				  const char *buf, size_t count)
> +{
> +	struct adt7410_data *data = dev_get_drvdata(dev);
> +	int limit, ret;
> +	long hyst;
> +
> +	ret = kstrtol(buf, 10, &hyst);
> +	if (ret)
> +		return ret;
> +	/* convert absolute hysteresis value to a 4 bit delta value */
> +	limit = ADT7410_REG_TO_TEMP(data, data->temp[1]);
> +	hyst = clamp_val(hyst, ADT7410_TEMP_MIN, ADT7410_TEMP_MAX);
> +	data->hyst = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000),
> +				   0, ADT7410_T_HYST_MASK);
> +	ret = adt7410_write_byte(dev, ADT7410_T_HYST, data->hyst);
> +	if (ret)
> +		return ret;
> +
> +	return count;
> +}
> +
> +static ssize_t adt7410_show_alarm(struct device *dev,
> +				  struct device_attribute *da,
> +				  char *buf)
> +{
> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
> +	u8 status;
> +	int ret;
> +
> +	ret = adt7410_read_byte(dev, ADT7410_STATUS, &status);
> +	if (ret < 0)
> +		return ret;
> +
> +	return sprintf(buf, "%d\n", !!(status & attr->index));
> +}
> +
> +static ssize_t adt7410_show_name(struct device *dev,
> +				  struct device_attribute *da, char *buf)
> +{
> +	struct adt7410_data *data = dev_get_drvdata(dev);
> +
> +	return sprintf(buf, "%s\n", data->name);
> +}
> +
> +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adt7410_show_temp, NULL, 0);
> +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
> +			  adt7410_show_temp, adt7410_set_temp, 1);
> +static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
> +			  adt7410_show_temp, adt7410_set_temp, 2);
> +static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
> +			  adt7410_show_temp, adt7410_set_temp, 3);
> +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
> +			  adt7410_show_t_hyst, adt7410_set_t_hyst, 1);
> +static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO,
> +			  adt7410_show_t_hyst, NULL, 2);
> +static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO,
> +			  adt7410_show_t_hyst, NULL, 3);
> +static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, adt7410_show_alarm,
> +			  NULL, ADT7410_STAT_T_LOW);
> +static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adt7410_show_alarm,
> +			  NULL, ADT7410_STAT_T_HIGH);
> +static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, adt7410_show_alarm,
> +			  NULL, ADT7410_STAT_T_CRIT);
> +static DEVICE_ATTR(name, S_IRUGO, adt7410_show_name, NULL);
> +
> +static struct attribute *adt7410_attributes[] = {
> +	&sensor_dev_attr_temp1_input.dev_attr.attr,
> +	&sensor_dev_attr_temp1_max.dev_attr.attr,
> +	&sensor_dev_attr_temp1_min.dev_attr.attr,
> +	&sensor_dev_attr_temp1_crit.dev_attr.attr,
> +	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
> +	&sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
> +	&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
> +	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
> +	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
> +	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
> +	NULL
> +};
> +
> +static const struct attribute_group adt7410_group = {
> +	.attrs = adt7410_attributes,
> +};
> +
> +int adt7410_probe(struct device *dev, const char *name,
> +	const struct adt7410_ops *ops)
> +{
> +	struct adt7410_data *data;
> +	int ret;
> +
> +	data = devm_kzalloc(dev, sizeof(struct adt7410_data),
> +			    GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	data->ops = ops;
> +	data->name = name;
> +
> +	dev_set_drvdata(dev, data);
> +	mutex_init(&data->update_lock);
> +
> +	/* configure as specified */
> +	ret = adt7410_read_byte(dev, ADT7410_CONFIG, &data->oldconfig);
> +	if (ret < 0) {
> +		dev_dbg(dev, "Can't read config? %d\n", ret);
> +		return ret;
> +	}
> +	/*
> +	 * Set to 16 bit resolution, continous conversion and comparator mode.
> +	 */
> +	data->config = data->oldconfig;
> +	data->config &= ~ADT7410_MODE_MASK;
> +	data->config |= ADT7410_FULL | ADT7410_RESOLUTION | ADT7410_EVENT_MODE;
> +	if (data->config != data->oldconfig) {
> +		ret = adt7410_write_byte(dev, ADT7410_CONFIG, data->config);
> +		if (ret)
> +			return ret;
> +	}
> +	dev_dbg(dev, "Config %02x\n", data->config);
> +
> +	ret = adt7410_fill_cache(dev);
> +	if (ret)
> +		goto exit_restore;
> +
> +	/* Register sysfs hooks */
> +	ret = sysfs_create_group(&dev->kobj, &adt7410_group);
> +	if (ret)
> +		goto exit_restore;
> +
> +	/*
> +	 * The I2C device will already have it's own 'name' attribute, but for
> +	 * the SPI device we need to register it. name will only be non NULL if
> +	 * the device doesn't register the 'name' attribute on its own.
> +	 */
> +	if (name) {
> +		ret = device_create_file(dev, &dev_attr_name);
> +		if (ret)
> +			goto exit_remove;
> +	}
> +
> +	data->hwmon_dev = hwmon_device_register(dev);
> +	if (IS_ERR(data->hwmon_dev)) {
> +		ret = PTR_ERR(data->hwmon_dev);
> +		goto exit_remove_name;
> +	}
> +
> +	return 0;
> +
> +exit_remove_name:
> +	if (name)
> +		device_remove_file(dev, &dev_attr_name);
> +exit_remove:
> +	sysfs_remove_group(&dev->kobj, &adt7410_group);
> +exit_restore:
> +	adt7410_write_byte(dev, ADT7410_CONFIG, data->oldconfig);
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(adt7410_probe);
> +
> +int adt7410_remove(struct device *dev)
> +{
> +	struct adt7410_data *data = dev_get_drvdata(dev);
> +
> +	hwmon_device_unregister(data->hwmon_dev);
> +	if (data->name)
> +		device_remove_file(dev, &dev_attr_name);
> +	sysfs_remove_group(&dev->kobj, &adt7410_group);
> +	if (data->oldconfig != data->config)
> +		adt7410_write_byte(dev, ADT7410_CONFIG,
> +					  data->oldconfig);
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(adt7410_remove);
> +
> +#ifdef CONFIG_PM_SLEEP
> +
> +static int adt7410_suspend(struct device *dev)
> +{
> +	struct adt7410_data *data = dev_get_drvdata(dev);
> +
> +	return adt7410_write_byte(dev, ADT7410_CONFIG,
> +		data->config | ADT7410_PD);
> +}
> +
> +static int adt7410_resume(struct device *dev)
> +{
> +	struct adt7410_data *data = dev_get_drvdata(dev);
> +
> +	return adt7410_write_byte(dev, ADT7410_CONFIG, data->config);
> +}
> +
> +SIMPLE_DEV_PM_OPS(adt7410_dev_pm_ops, adt7410_suspend, adt7410_resume);
> +EXPORT_SYMBOL_GPL(adt7410_dev_pm_ops);
> +
> +#endif /* CONFIG_PM_SLEEP */
> +
> +MODULE_AUTHOR("Hartmut Knaack");
> +MODULE_DESCRIPTION("ADT7410 driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/hwmon/adt7x10.h b/drivers/hwmon/adt7x10.h
> new file mode 100644
> index 0000000..17c8053
> --- /dev/null
> +++ b/drivers/hwmon/adt7x10.h
> @@ -0,0 +1,47 @@
> +#ifndef __HWMON_ADT7410_H__
> +#define __HWMON_ADT7410_H__
> +
> +#include <linux/types.h>
> +
> +/* ADT7410 registers definition */
> +#define ADT7410_TEMPERATURE		0
> +#define ADT7410_STATUS			2
> +#define ADT7410_CONFIG			3
> +#define ADT7410_T_ALARM_HIGH		4
> +#define ADT7410_T_ALARM_LOW		6
> +#define ADT7410_T_CRIT			8
> +#define ADT7410_T_HYST			0xA
> +#define ADT7410_ID			0xB
> +
> +/* ADT7310 registers definition */
> +#define ADT7310_STATUS			0
> +#define ADT7310_CONFIG			1
> +#define ADT7310_TEMPERATURE		2
> +#define ADT7310_ID			3
> +#define ADT7310_T_CRIT			4
> +#define ADT7310_T_HYST			5
> +#define ADT7310_T_ALARM_HIGH		6
> +#define ADT7310_T_ALARM_LOW		7
> +
> +struct device;
> +
> +struct adt7410_ops {
> +	int (*read_word)(struct device *, u8 reg, u16 *data);
> +	int (*write_word)(struct device *, u8 reg, u16 data);
> +	int (*read_byte)(struct device *, u8 reg, u8 *data);
> +	int (*write_byte)(struct device *, u8 reg, u8 data);
> +};
> +
> +int adt7410_probe(struct device *dev, const char *name,
> +	const struct adt7410_ops *ops);
> +int adt7410_remove(struct device *dev);
> +
> +
> +#ifdef CONFIG_PM_SLEEP
> +extern const struct dev_pm_ops adt7410_dev_pm_ops;
> +#define ADT7410_DEV_PM_OPS (&adt7410_dev_pm_ops)
> +#else
> +#define ADT7410_DEV_PM_OPS NULL
> +#endif
> +
> +#endif
> -- 
> 1.8.0
> 
> 

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

* Re: [lm-sensors] [PATCH 7/9] hwmon: (adt7410) Add support for the adt7310/adt7320
@ 2013-02-15 20:32     ` Guenter Roeck
  0 siblings, 0 replies; 56+ messages in thread
From: Guenter Roeck @ 2013-02-15 20:32 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Jean Delvare, Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio

On Fri, Feb 15, 2013 at 05:57:16PM +0100, Lars-Peter Clausen wrote:
> The adt7310/adt7320 is the SPI version of the adt7410/adt7320. The register map
> layout is a bit different, i.e. the register addresses differ between the two
> variants, but the bit layouts of the individual registers are identical. So both
> chip variants can easily be supported by the same driver. The issue of non
> matching register address layouts is solved by a simple look-up table which
> translates the I2C addresses to the SPI addresses.
> 
> The patch moves the bulk of the adt7410 driver to a common module that will be
> shared by the adt7410 and adt7310 drivers. This common module implements the
> driver logic and uses a set of virtual functions to perform IO access. The
> adt7410 and adt7310 driver modules provide proper implementations of these IO
> accessor functions for I2C respective SPI.
> 
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
> ---
>  drivers/hwmon/Kconfig   |  20 ++
>  drivers/hwmon/Makefile  |   2 +
>  drivers/hwmon/adt7310.c | 160 ++++++++++++++++
>  drivers/hwmon/adt7410.c | 472 ++++++-----------------------------------------
>  drivers/hwmon/adt7x10.c | 476 ++++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/hwmon/adt7x10.h |  47 +++++
>  6 files changed, 758 insertions(+), 419 deletions(-)
>  create mode 100644 drivers/hwmon/adt7310.c
>  create mode 100644 drivers/hwmon/adt7x10.c
>  create mode 100644 drivers/hwmon/adt7x10.h
> 
> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> index 89ac1cb..aaa14f4 100644
> --- a/drivers/hwmon/Kconfig
> +++ b/drivers/hwmon/Kconfig
> @@ -179,9 +179,29 @@ config SENSORS_ADM9240
>  	  This driver can also be built as a module.  If so, the module
>  	  will be called adm9240.
>  
> +config SENSORS_ADT7X10
> +	tristate
> +	help
> +	  This module contains common code shared by the ADT7310/ADT7320 and
> +	  ADT7410/ADT7420 temperature monitoring chip drivers.
> +
> +	  If build as a module, the module will be called adt7x10.
> +
> +config SENSORS_ADT7310
> +	tristate "Analog Devices ADT7310/ADT7320"
> +	depends on SPI_MASTER
> +	select SENSORS_ADT7X10
> +	help
> +	  If you say yes here you get support for the Analog Devices
> +	  ADT7310 and ADT7320 temperature monitoring chips.
> +
> +	  This driver can also be built as a module. If so, the module
> +	  will be called adt7310.
> +
>  config SENSORS_ADT7410
>  	tristate "Analog Devices ADT7410/ADT7420"
>  	depends on I2C
> +	select SENSORS_ADT7X10
>  	help
>  	  If you say yes here you get support for the Analog Devices
>  	  ADT7410 and ADT7420 temperature monitoring chips.
> diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
> index 8d6d97e..5d36a57 100644
> --- a/drivers/hwmon/Makefile
> +++ b/drivers/hwmon/Makefile
> @@ -34,6 +34,8 @@ obj-$(CONFIG_SENSORS_ADM9240)	+= adm9240.o
>  obj-$(CONFIG_SENSORS_ADS1015)	+= ads1015.o
>  obj-$(CONFIG_SENSORS_ADS7828)	+= ads7828.o
>  obj-$(CONFIG_SENSORS_ADS7871)	+= ads7871.o
> +obj-$(CONFIG_SENSORS_ADT7X10)	+= adt7x10.o
> +obj-$(CONFIG_SENSORS_ADT7310)	+= adt7310.o
>  obj-$(CONFIG_SENSORS_ADT7410)	+= adt7410.o
>  obj-$(CONFIG_SENSORS_ADT7411)	+= adt7411.o
>  obj-$(CONFIG_SENSORS_ADT7462)	+= adt7462.o
> diff --git a/drivers/hwmon/adt7310.c b/drivers/hwmon/adt7310.c
> new file mode 100644
> index 0000000..0483e6c
> --- /dev/null
> +++ b/drivers/hwmon/adt7310.c
> @@ -0,0 +1,160 @@
> +/*
> + * ADT7310/ADT7310 digital temperature sensor driver
> + *
> + * Copyright 2010-2013 Analog Devices Inc.
> + *   Author: Lars-Peter Clausen <lars@metafoo.de>
> + *
> + * Licensed under the GPL-2 or later.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/spi/spi.h>
> +
> +#include "adt7x10.h"
> +
> +static const u8 adt7371_reg_table[] = {
> +	[ADT7410_TEMPERATURE]   = ADT7310_TEMPERATURE,
> +	[ADT7410_STATUS]	= ADT7310_STATUS,
> +	[ADT7410_CONFIG]	= ADT7310_CONFIG,
> +	[ADT7410_T_ALARM_HIGH]	= ADT7310_T_ALARM_HIGH,
> +	[ADT7410_T_ALARM_LOW]	= ADT7310_T_ALARM_LOW,
> +	[ADT7410_T_CRIT]	= ADT7310_T_CRIT,
> +	[ADT7410_T_HYST]	= ADT7310_T_HYST,
> +	[ADT7410_ID]		= ADT7310_ID,
> +};
> +
> +#define ADT7310_CMD_REG_MASK			0x28
> +#define ADT7310_CMD_REG_OFFSET			3
> +#define ADT7310_CMD_READ			0x40
> +#define ADT7310_CMD_CON_READ			0x4
> +
> +#define AD7310_COMMAND(reg) (adt7371_reg_table[(reg)] << ADT7310_CMD_REG_OFFSET)
> +
> +static int adt7310_spi_read_word(struct device *dev,
> +	u8 reg, u16 *data)

I don't really like the approach of separating the return value from the error
code, if both can be returned directly. There are two reasons: First, the code
gets more complex, and second, the compiler tends to get confused under some
conditions abd believe that the return value is not set. And I really don't want
to have to deal with the resulting build warnings, after getting rid of pretty
much all such warnings in the hwmon subsystem. So I'd really appreciate if you
could rewrite this and the subsequent patches to return both error and value as
function return values.

Thanks,
Guenter

> +{
> +	struct spi_device *spi = to_spi_device(dev);
> +	u8 command = AD7310_COMMAND(reg);
> +	int ret = 0;
> +
> +	command |= ADT7310_CMD_READ;
> +	ret = spi_write(spi, &command, sizeof(command));
> +	if (ret < 0) {
> +		dev_err(dev, "SPI write command error\n");
> +		return ret;
> +	}
> +
> +	ret = spi_read(spi, (u8 *)data, sizeof(*data));
> +	if (ret < 0) {
> +		dev_err(dev, "SPI read word error\n");
> +		return ret;
> +	}
> +
> +	*data = be16_to_cpu(*data);
> +
> +	return 0;
> +}
> +
> +static int adt7310_spi_write_word(struct device *dev, u8 reg,
> +	u16 data)
> +{
> +	struct spi_device *spi = to_spi_device(dev);
> +	u8 buf[3];
> +	int ret = 0;
> +
> +	buf[0] = AD7310_COMMAND(reg);
> +	buf[1] = (u8)(data >> 8);
> +	buf[2] = (u8)(data & 0xFF);
> +
> +	ret = spi_write(spi, buf, 3);
> +	if (ret < 0) {
> +		dev_err(dev, "SPI write word error\n");
> +		return ret;
> +	}
> +
> +	return ret;
> +}
> +
> +static int adt7310_spi_read_byte(struct device *dev, u8 reg,
> +	u8 *data)
> +{
> +	struct spi_device *spi = to_spi_device(dev);
> +	u8 command = AD7310_COMMAND(reg);
> +	int ret = 0;
> +
> +	command |= ADT7310_CMD_READ;
> +	ret = spi_write(spi, &command, sizeof(command));
> +	if (ret < 0) {
> +		dev_err(dev, "SPI write command error\n");
> +		return ret;
> +	}
> +
> +	ret = spi_read(spi, data, sizeof(*data));
> +	if (ret < 0) {
> +		dev_err(dev, "SPI read byte error\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int adt7310_spi_write_byte(struct device *dev, u8 reg,
> +	u8 data)
> +{
> +	struct spi_device *spi = to_spi_device(dev);
> +	u8 buf[2];
> +	int ret = 0;
> +
> +	buf[0] = AD7310_COMMAND(reg);
> +	buf[1] = data;
> +
> +	ret = spi_write(spi, buf, 2);
> +	if (ret < 0) {
> +		dev_err(dev, "SPI write byte error\n");
> +		return ret;
> +	}
> +
> +	return ret;
> +}
> +
> +static const struct adt7410_ops adt7310_spi_ops = {
> +	.read_word = adt7310_spi_read_word,
> +	.write_word = adt7310_spi_write_word,
> +	.read_byte = adt7310_spi_read_byte,
> +	.write_byte = adt7310_spi_write_byte,
> +};
> +
> +static int adt7310_spi_probe(struct spi_device *spi)
> +{
> +	return adt7410_probe(&spi->dev, spi_get_device_id(spi)->name,
> +			&adt7310_spi_ops);
> +}
> +
> +static int adt7310_spi_remove(struct spi_device *spi)
> +{
> +	return adt7410_remove(&spi->dev);
> +}
> +
> +static const struct spi_device_id adt7310_id[] = {
> +	{ "adt7310", 0 },
> +	{ "adt7320", 0 },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(spi, adt7310_id);
> +
> +static struct spi_driver adt7310_driver = {
> +	.driver = {
> +		.name = "adt7310",
> +		.owner = THIS_MODULE,
> +		.pm	= ADT7410_DEV_PM_OPS,
> +	},
> +	.probe = adt7310_spi_probe,
> +	.remove = adt7310_spi_remove,
> +	.id_table = adt7310_id,
> +};
> +module_spi_driver(adt7310_driver);
> +
> +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
> +MODULE_DESCRIPTION("ADT7310/ADT7420 driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
> index 5de0376..13734c5 100644
> --- a/drivers/hwmon/adt7410.c
> +++ b/drivers/hwmon/adt7410.c
> @@ -1,483 +1,117 @@
>  /*
> - * adt7410.c - Part of lm_sensors, Linux kernel modules for hardware
> - *	 monitoring
> - * This driver handles the ADT7410 and compatible digital temperature sensors.
> - * Hartmut Knaack <knaack.h@gmx.de> 2012-07-22
> - * based on lm75.c by Frodo Looijaard <frodol@dds.nl>
> - * and adt7410.c from iio-staging by Sonic Zhang <sonic.zhang@analog.com>
> + * ADT7410/ADT7420 digital temperature sensor driver
>   *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; either version 2 of the License, or
> - * (at your option) any later version.
> + * Copyright 2010-2013 Analog Devices Inc.
> + *   Author: Lars-Peter Clausen <lars@metafoo.de>
>   *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program; if not, write to the Free Software
> - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + * Licensed under the GPL-2 or later.
>   */
>  
>  #include <linux/module.h>
>  #include <linux/init.h>
> -#include <linux/slab.h>
> -#include <linux/jiffies.h>
>  #include <linux/i2c.h>
> -#include <linux/hwmon.h>
> -#include <linux/hwmon-sysfs.h>
> -#include <linux/err.h>
> -#include <linux/mutex.h>
> -#include <linux/delay.h>
> -
> -/*
> - * ADT7410 registers definition
> - */
>  
> -#define ADT7410_TEMPERATURE		0
> -#define ADT7410_STATUS			2
> -#define ADT7410_CONFIG			3
> -#define ADT7410_T_ALARM_HIGH		4
> -#define ADT7410_T_ALARM_LOW		6
> -#define ADT7410_T_CRIT			8
> -#define ADT7410_T_HYST			0xA
> +#include "adt7x10.h"
>  
> -/*
> - * ADT7410 status
> - */
> -#define ADT7410_STAT_T_LOW		(1 << 4)
> -#define ADT7410_STAT_T_HIGH		(1 << 5)
> -#define ADT7410_STAT_T_CRIT		(1 << 6)
> -#define ADT7410_STAT_NOT_RDY		(1 << 7)
> -
> -/*
> - * ADT7410 config
> - */
> -#define ADT7410_FAULT_QUEUE_MASK	(1 << 0 | 1 << 1)
> -#define ADT7410_CT_POLARITY		(1 << 2)
> -#define ADT7410_INT_POLARITY		(1 << 3)
> -#define ADT7410_EVENT_MODE		(1 << 4)
> -#define ADT7410_MODE_MASK		(1 << 5 | 1 << 6)
> -#define ADT7410_FULL			(0 << 5 | 0 << 6)
> -#define ADT7410_PD			(1 << 5 | 1 << 6)
> -#define ADT7410_RESOLUTION		(1 << 7)
> -
> -/*
> - * ADT7410 masks
> - */
> -#define ADT7410_T13_VALUE_MASK			0xFFF8
> -#define ADT7410_T_HYST_MASK			0xF
> -
> -/* straight from the datasheet */
> -#define ADT7410_TEMP_MIN (-55000)
> -#define ADT7410_TEMP_MAX 150000
> -
> -enum adt7410_type {		/* keep sorted in alphabetical order */
> -	adt7410,
> -};
> -
> -static const u8 ADT7410_REG_TEMP[4] = {
> -	ADT7410_TEMPERATURE,		/* input */
> -	ADT7410_T_ALARM_HIGH,		/* high */
> -	ADT7410_T_ALARM_LOW,		/* low */
> -	ADT7410_T_CRIT,			/* critical */
> -};
> -
> -/* Each client has this additional data */
> -struct adt7410_data {
> -	struct device		*hwmon_dev;
> -	struct mutex		update_lock;
> -	u8			config;
> -	u8			oldconfig;
> -	bool			valid;		/* true if registers valid */
> -	unsigned long		last_updated;	/* In jiffies */
> -	s16			temp[4];	/* Register values,
> -						   0 = input
> -						   1 = high
> -						   2 = low
> -						   3 = critical */
> -	u8			hyst;		/* hysteresis offset */
> -};
> -
> -/*
> - * adt7410 register access by I2C
> - */
> -static int adt7410_temp_ready(struct i2c_client *client)
> -{
> -	int i, status;
> -
> -	for (i = 0; i < 6; i++) {
> -		status = i2c_smbus_read_byte_data(client, ADT7410_STATUS);
> -		if (status < 0)
> -			return status;
> -		if (!(status & ADT7410_STAT_NOT_RDY))
> -			return 0;
> -		msleep(60);
> -	}
> -	return -ETIMEDOUT;
> -}
> -
> -static int adt7410_update_temp(struct device *dev)
> +static int adt7410_i2c_read_word(struct device *dev, u8 reg, u16 *data)
>  {
>  	struct i2c_client *client = to_i2c_client(dev);
> -	struct adt7410_data *data = i2c_get_clientdata(client);
>  	int ret = 0;
>  
> -	mutex_lock(&data->update_lock);
> -
> -	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
> -	    || !data->valid) {
> -
> -		dev_dbg(&client->dev, "Starting update\n");
> -
> -		ret = adt7410_temp_ready(client); /* check for new value */
> -		if (ret)
> -			goto abort;
> -
> -		ret = i2c_smbus_read_word_swapped(client, ADT7410_REG_TEMP[0]);
> -		if (ret) {
> -			dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
> -				ADT7410_REG_TEMP[0], ret);
> -			goto abort;
> -		}
> -		data->temp[0] = ret;
> -
> -		data->last_updated = jiffies;
> -		data->valid = true;
> -	}
> -
> -abort:
> -	mutex_unlock(&data->update_lock);
> -	return ret;
> -}
> -
> -static int adt7410_fill_cache(struct i2c_client *client)
> -{
> -	struct adt7410_data *data = i2c_get_clientdata(client);
> -	int ret;
> -	int i;
> -
> -	for (i = 1; i < 3; i++) {
> -		ret = i2c_smbus_read_word_swapped(client, ADT7410_REG_TEMP[i]);
> -		if (ret) {
> -			dev_dbg(&client->dev,
> -				"Failed to read value: reg %d, error %d\n",
> -				ADT7410_REG_TEMP[0], ret);
> -			return ret;
> -		}
> -		data->temp[i] = ret;
> -	}
> -
> -	ret = i2c_smbus_read_byte_data(client, ADT7410_T_HYST);
> -	if (ret) {
> -		dev_dbg(&client->dev,
> -			"Failed to read value: hyst reg, error %d\n",
> -			ret);
> +	ret = i2c_smbus_read_word_swapped(client, reg);
> +	if (ret < 0) {
> +		dev_err(dev, "I2C read error\n");
>  		return ret;
>  	}
> -	data->hyst = ret;
> -
> -	return 0;
> -}
>  
> -static s16 ADT7410_TEMP_TO_REG(long temp)
> -{
> -	return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7410_TEMP_MIN,
> -					   ADT7410_TEMP_MAX) * 128, 1000);
> -}
> +	*data = ret;
>  
> -static int ADT7410_REG_TO_TEMP(struct adt7410_data *data, s16 reg)
> -{
> -	/* in 13 bit mode, bits 0-2 are status flags - mask them out */
> -	if (!(data->config & ADT7410_RESOLUTION))
> -		reg &= ADT7410_T13_VALUE_MASK;
> -	/*
> -	 * temperature is stored in twos complement format, in steps of
> -	 * 1/128°C
> -	 */
> -	return DIV_ROUND_CLOSEST(reg * 1000, 128);
> +	return 0;
>  }
>  
> -/*-----------------------------------------------------------------------*/
> -
> -/* sysfs attributes for hwmon */
> -
> -static ssize_t adt7410_show_temp(struct device *dev,
> -				 struct device_attribute *da, char *buf)
> +static int adt7410_i2c_write_word(struct device *dev, u8 reg, u16 data)
>  {
> -	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
>  	struct i2c_client *client = to_i2c_client(dev);
> -	struct adt7410_data *data = i2c_get_clientdata(client);
> -
> -	if (attr->index == 0) {
> -		int ret;
> +	int ret = 0;
>  
> -		ret = adt7410_update_temp(dev);
> -		if (ret)
> -			return ret;
> -	}
> +	ret = i2c_smbus_write_word_swapped(client, reg, data);
> +	if (ret < 0)
> +		dev_err(dev, "I2C write error\n");
>  
> -	return sprintf(buf, "%d\n", ADT7410_REG_TO_TEMP(data,
> -		       data->temp[attr->index]));
> +	return ret;
>  }
>  
> -static ssize_t adt7410_set_temp(struct device *dev,
> -				struct device_attribute *da,
> -				const char *buf, size_t count)
> +static int adt7410_i2c_read_byte(struct device *dev, u8 reg, u8 *data)
>  {
> -	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
>  	struct i2c_client *client = to_i2c_client(dev);
> -	struct adt7410_data *data = i2c_get_clientdata(client);
> -	int nr = attr->index;
> -	long temp;
> -	int ret;
> +	int ret = 0;
>  
> -	ret = kstrtol(buf, 10, &temp);
> -	if (ret)
> +	ret = i2c_smbus_read_byte_data(client, reg);
> +	if (ret < 0) {
> +		dev_err(dev, "I2C read error\n");
>  		return ret;
> +	}
>  
> -	mutex_lock(&data->update_lock);
> -	data->temp[nr] = ADT7410_TEMP_TO_REG(temp);
> -	ret = i2c_smbus_write_word_swapped(client, ADT7410_REG_TEMP[nr],
> -					   data->temp[nr]);
> -	if (ret)
> -		count = ret;
> -	mutex_unlock(&data->update_lock);
> -	return count;
> -}
> -
> -static ssize_t adt7410_show_t_hyst(struct device *dev,
> -				   struct device_attribute *da,
> -				   char *buf)
> -{
> -	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
> -	struct i2c_client *client = to_i2c_client(dev);
> -	struct adt7410_data *data = i2c_get_clientdata(client);
> -	int nr = attr->index;
> -	int hyst;
> -
> -	hyst = (data->hyst & ADT7410_T_HYST_MASK) * 1000;
> -
> -	/*
> -	 * hysteresis is stored as a 4 bit offset in the device, convert it
> -	 * to an absolute value
> -	 */
> -	if (nr == 2)	/* min has positive offset, others have negative */
> -		hyst = -hyst;
> -	return sprintf(buf, "%d\n",
> -		       ADT7410_REG_TO_TEMP(data, data->temp[nr]) - hyst);
> -}
> -
> -static ssize_t adt7410_set_t_hyst(struct device *dev,
> -				  struct device_attribute *da,
> -				  const char *buf, size_t count)
> -{
> -	struct i2c_client *client = to_i2c_client(dev);
> -	struct adt7410_data *data = i2c_get_clientdata(client);
> -	int limit, ret;
> -	long hyst;
> -
> -	ret = kstrtol(buf, 10, &hyst);
> -	if (ret)
> -		return ret;
> -	/* convert absolute hysteresis value to a 4 bit delta value */
> -	limit = ADT7410_REG_TO_TEMP(data, data->temp[1]);
> -	hyst = clamp_val(hyst, ADT7410_TEMP_MIN, ADT7410_TEMP_MAX);
> -	data->hyst = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000), 0,
> -			       ADT7410_T_HYST_MASK);
> -	ret = i2c_smbus_write_byte_data(client, ADT7410_T_HYST, data->hyst);
> -	if (ret)
> -		return ret;
> +	*data = (u8)ret;
>  
> -	return count;
> +	return 0;
>  }
>  
> -static ssize_t adt7410_show_alarm(struct device *dev,
> -				  struct device_attribute *da,
> -				  char *buf)
> +static int adt7410_i2c_write_byte(struct device *dev, u8 reg, u8 data)
>  {
>  	struct i2c_client *client = to_i2c_client(dev);
> -	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
> -	int ret;
> +	int ret = 0;
>  
> -	ret = i2c_smbus_read_byte_data(client, ADT7410_STATUS);
> +	ret = i2c_smbus_write_byte_data(client, reg, data);
>  	if (ret < 0)
> -		return ret;
> +		dev_err(&client->dev, "I2C write error\n");
>  
> -	return sprintf(buf, "%d\n", !!(ret & attr->index));
> +	return ret;
>  }
>  
> -static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adt7410_show_temp, NULL, 0);
> -static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
> -			  adt7410_show_temp, adt7410_set_temp, 1);
> -static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
> -			  adt7410_show_temp, adt7410_set_temp, 2);
> -static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
> -			  adt7410_show_temp, adt7410_set_temp, 3);
> -static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
> -			  adt7410_show_t_hyst, adt7410_set_t_hyst, 1);
> -static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO,
> -			  adt7410_show_t_hyst, NULL, 2);
> -static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO,
> -			  adt7410_show_t_hyst, NULL, 3);
> -static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, adt7410_show_alarm,
> -			  NULL, ADT7410_STAT_T_LOW);
> -static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adt7410_show_alarm,
> -			  NULL, ADT7410_STAT_T_HIGH);
> -static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, adt7410_show_alarm,
> -			  NULL, ADT7410_STAT_T_CRIT);
> -
> -static struct attribute *adt7410_attributes[] = {
> -	&sensor_dev_attr_temp1_input.dev_attr.attr,
> -	&sensor_dev_attr_temp1_max.dev_attr.attr,
> -	&sensor_dev_attr_temp1_min.dev_attr.attr,
> -	&sensor_dev_attr_temp1_crit.dev_attr.attr,
> -	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
> -	&sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
> -	&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
> -	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
> -	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
> -	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
> -	NULL
> -};
> -
> -static const struct attribute_group adt7410_group = {
> -	.attrs = adt7410_attributes,
> +static const struct adt7410_ops adt7410_i2c_ops = {
> +	.read_word = adt7410_i2c_read_word,
> +	.write_word = adt7410_i2c_write_word,
> +	.read_byte = adt7410_i2c_read_byte,
> +	.write_byte = adt7410_i2c_write_byte,
>  };
>  
> -/*-----------------------------------------------------------------------*/
> -
> -/* device probe and removal */
> -
> -static int adt7410_probe(struct i2c_client *client,
> -			 const struct i2c_device_id *id)
> +static int adt7410_i2c_probe(struct i2c_client *client,
> +	const struct i2c_device_id *id)
>  {
> -	struct adt7410_data *data;
> -	int ret;
>  
>  	if (!i2c_check_functionality(client->adapter,
>  			I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
>  		return -ENODEV;
>  
> -	data = devm_kzalloc(&client->dev, sizeof(struct adt7410_data),
> -			    GFP_KERNEL);
> -	if (!data)
> -		return -ENOMEM;
> -
> -	i2c_set_clientdata(client, data);
> -	mutex_init(&data->update_lock);
> -
> -	/* configure as specified */
> -	ret = i2c_smbus_read_byte_data(client, ADT7410_CONFIG);
> -	if (ret < 0) {
> -		dev_dbg(&client->dev, "Can't read config? %d\n", ret);
> -		return ret;
> -	}
> -	data->oldconfig = ret;
> -	/*
> -	 * Set to 16 bit resolution, continous conversion and comparator mode.
> -	 */
> -	ret &= ~ADT7410_MODE_MASK;
> -	data->config = ret | ADT7410_FULL | ADT7410_RESOLUTION |
> -			ADT7410_EVENT_MODE;
> -	if (data->config != data->oldconfig) {
> -		ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
> -						data->config);
> -		if (ret)
> -			return ret;
> -	}
> -	dev_dbg(&client->dev, "Config %02x\n", data->config);
> -
> -	ret = adt7410_fill_cache(client);
> -	if (ret)
> -		goto exit_restore;
> -
> -	/* Register sysfs hooks */
> -	ret = sysfs_create_group(&client->dev.kobj, &adt7410_group);
> -	if (ret)
> -		goto exit_restore;
> -
> -	data->hwmon_dev = hwmon_device_register(&client->dev);
> -	if (IS_ERR(data->hwmon_dev)) {
> -		ret = PTR_ERR(data->hwmon_dev);
> -		goto exit_remove;
> -	}
> -
> -	dev_info(&client->dev, "sensor '%s'\n", client->name);
> -
> -	return 0;
> -
> -exit_remove:
> -	sysfs_remove_group(&client->dev.kobj, &adt7410_group);
> -exit_restore:
> -	i2c_smbus_write_byte_data(client, ADT7410_CONFIG, data->oldconfig);
> -	return ret;
> +	return adt7410_probe(&client->dev, NULL, &adt7410_i2c_ops);
>  }
>  
> -static int adt7410_remove(struct i2c_client *client)
> +static int adt7410_i2c_remove(struct i2c_client *client)
>  {
> -	struct adt7410_data *data = i2c_get_clientdata(client);
> -
> -	hwmon_device_unregister(data->hwmon_dev);
> -	sysfs_remove_group(&client->dev.kobj, &adt7410_group);
> -	if (data->oldconfig != data->config)
> -		i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
> -					  data->oldconfig);
> -	return 0;
> +	return adt7410_remove(&client->dev);
>  }
>  
> -static const struct i2c_device_id adt7410_ids[] = {
> -	{ "adt7410", adt7410, },
> -	{ "adt7420", adt7410, },
> -	{ /* LIST END */ }
> +static const struct i2c_device_id adt7410_id[] = {
> +	{ "adt7410", 0 },
> +	{ "adt7420", 0 },
> +	{}
>  };
> -MODULE_DEVICE_TABLE(i2c, adt7410_ids);
> -
> -#ifdef CONFIG_PM_SLEEP
> -static int adt7410_suspend(struct device *dev)
> -{
> -	int ret;
> -	struct i2c_client *client = to_i2c_client(dev);
> -	struct adt7410_data *data = i2c_get_clientdata(client);
> -
> -	ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
> -					data->config | ADT7410_PD);
> -	return ret;
> -}
> -
> -static int adt7410_resume(struct device *dev)
> -{
> -	int ret;
> -	struct i2c_client *client = to_i2c_client(dev);
> -	struct adt7410_data *data = i2c_get_clientdata(client);
> -
> -	ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG, data->config);
> -	return ret;
> -}
> -
> -static SIMPLE_DEV_PM_OPS(adt7410_dev_pm_ops, adt7410_suspend, adt7410_resume);
> -
> -#define ADT7410_DEV_PM_OPS (&adt7410_dev_pm_ops)
> -#else
> -#define ADT7410_DEV_PM_OPS NULL
> -#endif /* CONFIG_PM */
> +MODULE_DEVICE_TABLE(i2c, adt7410_id);
>  
>  static struct i2c_driver adt7410_driver = {
> -	.class		= I2C_CLASS_HWMON,
>  	.driver = {
> -		.name	= "adt7410",
> +		.name = "adt7410",
>  		.pm	= ADT7410_DEV_PM_OPS,
>  	},
> -	.probe		= adt7410_probe,
> -	.remove		= adt7410_remove,
> -	.id_table	= adt7410_ids,
> -	.address_list	= I2C_ADDRS(0x48, 0x49, 0x4a, 0x4b),
> +	.probe = adt7410_i2c_probe,
> +	.remove = adt7410_i2c_remove,
> +	.id_table = adt7410_id,
> +	.address_list = I2C_ADDRS(0x48, 0x49, 0x4a, 0x4b),
> +	.class = I2C_CLASS_HWMON,
>  };
> -
>  module_i2c_driver(adt7410_driver);
>  
> -MODULE_AUTHOR("Hartmut Knaack");
> -MODULE_DESCRIPTION("ADT7410/ADT7420 driver");
> +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
> +MODULE_DESCRIPTION("ADT7410/AD7420 driver");
>  MODULE_LICENSE("GPL");
> diff --git a/drivers/hwmon/adt7x10.c b/drivers/hwmon/adt7x10.c
> new file mode 100644
> index 0000000..2598aaf
> --- /dev/null
> +++ b/drivers/hwmon/adt7x10.c
> @@ -0,0 +1,476 @@
> +/*
> + * adt7410.c - Part of lm_sensors, Linux kernel modules for hardware
> + *	 monitoring
> + * This driver handles the ADT7410 and compatible digital temperature sensors.
> + * Hartmut Knaack <knaack.h@gmx.de> 2012-07-22
> + * based on lm75.c by Frodo Looijaard <frodol@dds.nl>
> + * and adt7410.c from iio-staging by Sonic Zhang <sonic.zhang@analog.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/slab.h>
> +#include <linux/jiffies.h>
> +#include <linux/hwmon.h>
> +#include <linux/hwmon-sysfs.h>
> +#include <linux/err.h>
> +#include <linux/mutex.h>
> +#include <linux/delay.h>
> +
> +#include "adt7x10.h"
> +
> +/*
> + * ADT7410 status
> + */
> +#define ADT7410_STAT_T_LOW		(1 << 4)
> +#define ADT7410_STAT_T_HIGH		(1 << 5)
> +#define ADT7410_STAT_T_CRIT		(1 << 6)
> +#define ADT7410_STAT_NOT_RDY		(1 << 7)
> +
> +/*
> + * ADT7410 config
> + */
> +#define ADT7410_FAULT_QUEUE_MASK	(1 << 0 | 1 << 1)
> +#define ADT7410_CT_POLARITY		(1 << 2)
> +#define ADT7410_INT_POLARITY		(1 << 3)
> +#define ADT7410_EVENT_MODE		(1 << 4)
> +#define ADT7410_MODE_MASK		(1 << 5 | 1 << 6)
> +#define ADT7410_FULL			(0 << 5 | 0 << 6)
> +#define ADT7410_PD			(1 << 5 | 1 << 6)
> +#define ADT7410_RESOLUTION		(1 << 7)
> +
> +/*
> + * ADT7410 masks
> + */
> +#define ADT7410_T13_VALUE_MASK			0xFFF8
> +#define ADT7410_T_HYST_MASK			0xF
> +
> +/* straight from the datasheet */
> +#define ADT7410_TEMP_MIN (-55000)
> +#define ADT7410_TEMP_MAX 150000
> +
> +/* Each client has this additional data */
> +struct adt7410_data {
> +	const struct adt7410_ops *ops;
> +	const char		*name;
> +	struct device		*hwmon_dev;
> +	struct mutex		update_lock;
> +	u8			config;
> +	u8			oldconfig;
> +	bool			valid;		/* true if registers valid */
> +	unsigned long		last_updated;	/* In jiffies */
> +	s16			temp[4];	/* Register values,
> +						   0 = input
> +						   1 = high
> +						   2 = low
> +						   3 = critical */
> +	u8			hyst;		/* hysteresis offset */
> +};
> +
> +static int adt7410_read_word(struct device *dev, u8 reg, u16 *data)
> +{
> +	struct adt7410_data *d = dev_get_drvdata(dev);
> +	return d->ops->read_word(dev, reg, data);
> +}
> +
> +static int adt7410_write_word(struct device *dev, u8 reg, u16 data)
> +{
> +	struct adt7410_data *d = dev_get_drvdata(dev);
> +	return d->ops->write_word(dev, reg, data);
> +}
> +
> +static int adt7410_read_byte(struct device *dev, u8 reg, u8 *data)
> +{
> +	struct adt7410_data *d = dev_get_drvdata(dev);
> +	return d->ops->read_byte(dev, reg, data);
> +}
> +
> +static int adt7410_write_byte(struct device *dev, u8 reg, u8 data)
> +{
> +	struct adt7410_data *d = dev_get_drvdata(dev);
> +	return d->ops->write_byte(dev, reg, data);
> +}
> +
> +static const u8 ADT7410_REG_TEMP[4] = {
> +	ADT7410_TEMPERATURE,		/* input */
> +	ADT7410_T_ALARM_HIGH,		/* high */
> +	ADT7410_T_ALARM_LOW,		/* low */
> +	ADT7410_T_CRIT,			/* critical */
> +};
> +
> +/*
> + * adt7410 register access by I2C
> + */
> +static int adt7410_temp_ready(struct device *dev)
> +{
> +	int i, ret;
> +	u8 status;
> +
> +	for (i = 0; i < 6; i++) {
> +		ret = adt7410_read_byte(dev, ADT7410_STATUS, &status);
> +		if (ret)
> +			return ret;
> +		if (!(status & ADT7410_STAT_NOT_RDY))
> +			return 0;
> +		msleep(60);
> +	}
> +	return -ETIMEDOUT;
> +}
> +
> +static int adt7410_update_temp(struct device *dev)
> +{
> +	struct adt7410_data *data = dev_get_drvdata(dev);
> +	int ret = 0;
> +
> +	mutex_lock(&data->update_lock);
> +
> +	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
> +	    || !data->valid) {
> +
> +		dev_dbg(dev, "Starting update\n");
> +
> +		ret = adt7410_temp_ready(dev); /* check for new value */
> +		if (ret)
> +			goto abort;
> +
> +		ret = adt7410_read_word(dev, ADT7410_REG_TEMP[0],
> +					&data->temp[0]);
> +		if (ret) {
> +			dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
> +				ADT7410_REG_TEMP[0], ret);
> +			goto abort;
> +		}
> +		data->last_updated = jiffies;
> +		data->valid = true;
> +	}
> +
> +abort:
> +	mutex_unlock(&data->update_lock);
> +	return ret;
> +}
> +
> +static int adt7410_fill_cache(struct device *dev)
> +{
> +	struct adt7410_data *data = dev_get_drvdata(dev);
> +	int ret;
> +	int i;
> +
> +	for (i = 1; i < ARRAY_SIZE(data->temp); i++) {
> +		ret = adt7410_read_word(dev, ADT7410_REG_TEMP[i],
> +					&data->temp[i]);
> +		if (ret) {
> +			dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
> +				ADT7410_REG_TEMP[0], ret);
> +			return ret;
> +		}
> +	}
> +
> +	ret = adt7410_read_byte(dev, ADT7410_T_HYST, &data->hyst);
> +	if (ret) {
> +		dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
> +				ADT7410_T_HYST, ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static s16 ADT7410_TEMP_TO_REG(long temp)
> +{
> +	return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7410_TEMP_MIN,
> +					       ADT7410_TEMP_MAX) * 128, 1000);
> +}
> +
> +static int ADT7410_REG_TO_TEMP(struct adt7410_data *data, s16 reg)
> +{
> +	/* in 13 bit mode, bits 0-2 are status flags - mask them out */
> +	if (!(data->config & ADT7410_RESOLUTION))
> +		reg &= ADT7410_T13_VALUE_MASK;
> +	/*
> +	 * temperature is stored in twos complement format, in steps of
> +	 * 1/128°C
> +	 */
> +	return DIV_ROUND_CLOSEST(reg * 1000, 128);
> +}
> +
> +/*-----------------------------------------------------------------------*/
> +
> +/* sysfs attributes for hwmon */
> +
> +static ssize_t adt7410_show_temp(struct device *dev,
> +				 struct device_attribute *da, char *buf)
> +{
> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
> +	struct adt7410_data *data = dev_get_drvdata(dev);
> +
> +
> +	if (attr->index == 0) {
> +		int ret;
> +
> +		ret = adt7410_update_temp(dev);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return sprintf(buf, "%d\n", ADT7410_REG_TO_TEMP(data,
> +		       data->temp[attr->index]));
> +}
> +
> +static ssize_t adt7410_set_temp(struct device *dev,
> +				struct device_attribute *da,
> +				const char *buf, size_t count)
> +{
> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
> +	struct adt7410_data *data = dev_get_drvdata(dev);
> +	int nr = attr->index;
> +	long temp;
> +	int ret;
> +
> +	ret = kstrtol(buf, 10, &temp);
> +	if (ret)
> +		return ret;
> +
> +	mutex_lock(&data->update_lock);
> +	data->temp[nr] = ADT7410_TEMP_TO_REG(temp);
> +	ret = adt7410_write_word(dev, ADT7410_REG_TEMP[nr], data->temp[nr]);
> +	if (ret)
> +		count = ret;
> +	mutex_unlock(&data->update_lock);
> +	return count;
> +}
> +
> +static ssize_t adt7410_show_t_hyst(struct device *dev,
> +				   struct device_attribute *da,
> +				   char *buf)
> +{
> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
> +	struct adt7410_data *data = dev_get_drvdata(dev);
> +	int nr = attr->index;
> +	int hyst;
> +
> +	hyst = (data->hyst & ADT7410_T_HYST_MASK) * 1000;
> +
> +	/*
> +	 * hysteresis is stored as a 4 bit offset in the device, convert it
> +	 * to an absolute value
> +	 */
> +	if (nr == 2)	/* min has positive offset, others have negative */
> +		hyst = -hyst;
> +	return sprintf(buf, "%d\n",
> +		       ADT7410_REG_TO_TEMP(data, data->temp[nr]) - hyst);
> +}
> +
> +static ssize_t adt7410_set_t_hyst(struct device *dev,
> +				  struct device_attribute *da,
> +				  const char *buf, size_t count)
> +{
> +	struct adt7410_data *data = dev_get_drvdata(dev);
> +	int limit, ret;
> +	long hyst;
> +
> +	ret = kstrtol(buf, 10, &hyst);
> +	if (ret)
> +		return ret;
> +	/* convert absolute hysteresis value to a 4 bit delta value */
> +	limit = ADT7410_REG_TO_TEMP(data, data->temp[1]);
> +	hyst = clamp_val(hyst, ADT7410_TEMP_MIN, ADT7410_TEMP_MAX);
> +	data->hyst = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000),
> +				   0, ADT7410_T_HYST_MASK);
> +	ret = adt7410_write_byte(dev, ADT7410_T_HYST, data->hyst);
> +	if (ret)
> +		return ret;
> +
> +	return count;
> +}
> +
> +static ssize_t adt7410_show_alarm(struct device *dev,
> +				  struct device_attribute *da,
> +				  char *buf)
> +{
> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
> +	u8 status;
> +	int ret;
> +
> +	ret = adt7410_read_byte(dev, ADT7410_STATUS, &status);
> +	if (ret < 0)
> +		return ret;
> +
> +	return sprintf(buf, "%d\n", !!(status & attr->index));
> +}
> +
> +static ssize_t adt7410_show_name(struct device *dev,
> +				  struct device_attribute *da, char *buf)
> +{
> +	struct adt7410_data *data = dev_get_drvdata(dev);
> +
> +	return sprintf(buf, "%s\n", data->name);
> +}
> +
> +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adt7410_show_temp, NULL, 0);
> +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
> +			  adt7410_show_temp, adt7410_set_temp, 1);
> +static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
> +			  adt7410_show_temp, adt7410_set_temp, 2);
> +static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
> +			  adt7410_show_temp, adt7410_set_temp, 3);
> +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
> +			  adt7410_show_t_hyst, adt7410_set_t_hyst, 1);
> +static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO,
> +			  adt7410_show_t_hyst, NULL, 2);
> +static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO,
> +			  adt7410_show_t_hyst, NULL, 3);
> +static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, adt7410_show_alarm,
> +			  NULL, ADT7410_STAT_T_LOW);
> +static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adt7410_show_alarm,
> +			  NULL, ADT7410_STAT_T_HIGH);
> +static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, adt7410_show_alarm,
> +			  NULL, ADT7410_STAT_T_CRIT);
> +static DEVICE_ATTR(name, S_IRUGO, adt7410_show_name, NULL);
> +
> +static struct attribute *adt7410_attributes[] = {
> +	&sensor_dev_attr_temp1_input.dev_attr.attr,
> +	&sensor_dev_attr_temp1_max.dev_attr.attr,
> +	&sensor_dev_attr_temp1_min.dev_attr.attr,
> +	&sensor_dev_attr_temp1_crit.dev_attr.attr,
> +	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
> +	&sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
> +	&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
> +	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
> +	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
> +	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
> +	NULL
> +};
> +
> +static const struct attribute_group adt7410_group = {
> +	.attrs = adt7410_attributes,
> +};
> +
> +int adt7410_probe(struct device *dev, const char *name,
> +	const struct adt7410_ops *ops)
> +{
> +	struct adt7410_data *data;
> +	int ret;
> +
> +	data = devm_kzalloc(dev, sizeof(struct adt7410_data),
> +			    GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	data->ops = ops;
> +	data->name = name;
> +
> +	dev_set_drvdata(dev, data);
> +	mutex_init(&data->update_lock);
> +
> +	/* configure as specified */
> +	ret = adt7410_read_byte(dev, ADT7410_CONFIG, &data->oldconfig);
> +	if (ret < 0) {
> +		dev_dbg(dev, "Can't read config? %d\n", ret);
> +		return ret;
> +	}
> +	/*
> +	 * Set to 16 bit resolution, continous conversion and comparator mode.
> +	 */
> +	data->config = data->oldconfig;
> +	data->config &= ~ADT7410_MODE_MASK;
> +	data->config |= ADT7410_FULL | ADT7410_RESOLUTION | ADT7410_EVENT_MODE;
> +	if (data->config != data->oldconfig) {
> +		ret = adt7410_write_byte(dev, ADT7410_CONFIG, data->config);
> +		if (ret)
> +			return ret;
> +	}
> +	dev_dbg(dev, "Config %02x\n", data->config);
> +
> +	ret = adt7410_fill_cache(dev);
> +	if (ret)
> +		goto exit_restore;
> +
> +	/* Register sysfs hooks */
> +	ret = sysfs_create_group(&dev->kobj, &adt7410_group);
> +	if (ret)
> +		goto exit_restore;
> +
> +	/*
> +	 * The I2C device will already have it's own 'name' attribute, but for
> +	 * the SPI device we need to register it. name will only be non NULL if
> +	 * the device doesn't register the 'name' attribute on its own.
> +	 */
> +	if (name) {
> +		ret = device_create_file(dev, &dev_attr_name);
> +		if (ret)
> +			goto exit_remove;
> +	}
> +
> +	data->hwmon_dev = hwmon_device_register(dev);
> +	if (IS_ERR(data->hwmon_dev)) {
> +		ret = PTR_ERR(data->hwmon_dev);
> +		goto exit_remove_name;
> +	}
> +
> +	return 0;
> +
> +exit_remove_name:
> +	if (name)
> +		device_remove_file(dev, &dev_attr_name);
> +exit_remove:
> +	sysfs_remove_group(&dev->kobj, &adt7410_group);
> +exit_restore:
> +	adt7410_write_byte(dev, ADT7410_CONFIG, data->oldconfig);
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(adt7410_probe);
> +
> +int adt7410_remove(struct device *dev)
> +{
> +	struct adt7410_data *data = dev_get_drvdata(dev);
> +
> +	hwmon_device_unregister(data->hwmon_dev);
> +	if (data->name)
> +		device_remove_file(dev, &dev_attr_name);
> +	sysfs_remove_group(&dev->kobj, &adt7410_group);
> +	if (data->oldconfig != data->config)
> +		adt7410_write_byte(dev, ADT7410_CONFIG,
> +					  data->oldconfig);
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(adt7410_remove);
> +
> +#ifdef CONFIG_PM_SLEEP
> +
> +static int adt7410_suspend(struct device *dev)
> +{
> +	struct adt7410_data *data = dev_get_drvdata(dev);
> +
> +	return adt7410_write_byte(dev, ADT7410_CONFIG,
> +		data->config | ADT7410_PD);
> +}
> +
> +static int adt7410_resume(struct device *dev)
> +{
> +	struct adt7410_data *data = dev_get_drvdata(dev);
> +
> +	return adt7410_write_byte(dev, ADT7410_CONFIG, data->config);
> +}
> +
> +SIMPLE_DEV_PM_OPS(adt7410_dev_pm_ops, adt7410_suspend, adt7410_resume);
> +EXPORT_SYMBOL_GPL(adt7410_dev_pm_ops);
> +
> +#endif /* CONFIG_PM_SLEEP */
> +
> +MODULE_AUTHOR("Hartmut Knaack");
> +MODULE_DESCRIPTION("ADT7410 driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/hwmon/adt7x10.h b/drivers/hwmon/adt7x10.h
> new file mode 100644
> index 0000000..17c8053
> --- /dev/null
> +++ b/drivers/hwmon/adt7x10.h
> @@ -0,0 +1,47 @@
> +#ifndef __HWMON_ADT7410_H__
> +#define __HWMON_ADT7410_H__
> +
> +#include <linux/types.h>
> +
> +/* ADT7410 registers definition */
> +#define ADT7410_TEMPERATURE		0
> +#define ADT7410_STATUS			2
> +#define ADT7410_CONFIG			3
> +#define ADT7410_T_ALARM_HIGH		4
> +#define ADT7410_T_ALARM_LOW		6
> +#define ADT7410_T_CRIT			8
> +#define ADT7410_T_HYST			0xA
> +#define ADT7410_ID			0xB
> +
> +/* ADT7310 registers definition */
> +#define ADT7310_STATUS			0
> +#define ADT7310_CONFIG			1
> +#define ADT7310_TEMPERATURE		2
> +#define ADT7310_ID			3
> +#define ADT7310_T_CRIT			4
> +#define ADT7310_T_HYST			5
> +#define ADT7310_T_ALARM_HIGH		6
> +#define ADT7310_T_ALARM_LOW		7
> +
> +struct device;
> +
> +struct adt7410_ops {
> +	int (*read_word)(struct device *, u8 reg, u16 *data);
> +	int (*write_word)(struct device *, u8 reg, u16 data);
> +	int (*read_byte)(struct device *, u8 reg, u8 *data);
> +	int (*write_byte)(struct device *, u8 reg, u8 data);
> +};
> +
> +int adt7410_probe(struct device *dev, const char *name,
> +	const struct adt7410_ops *ops);
> +int adt7410_remove(struct device *dev);
> +
> +
> +#ifdef CONFIG_PM_SLEEP
> +extern const struct dev_pm_ops adt7410_dev_pm_ops;
> +#define ADT7410_DEV_PM_OPS (&adt7410_dev_pm_ops)
> +#else
> +#define ADT7410_DEV_PM_OPS NULL
> +#endif
> +
> +#endif
> -- 
> 1.8.0
> 
> 

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

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

* Re: [lm-sensors] [PATCH 7/9] hwmon: (adt7410) Add support for the adt7310/adt7320
  2013-02-15 20:05     ` [lm-sensors] " Hartmut Knaack
  (?)
@ 2013-02-16  0:40     ` Andrey Repin
  -1 siblings, 0 replies; 56+ messages in thread
From: Andrey Repin @ 2013-02-16  0:40 UTC (permalink / raw)
  To: lm-sensors

Greetings, Lars-Peter Clausen!

> The adt7310/adt7320 is the SPI version of
> the adt7410/adt7320. The register map

Typo, I suppose?  ^
Just making sure it doesn't end copy-pasted somewhere else.

> layout is a bit different, i.e. the register addresses differ between the two
> variants, but the bit layouts of the individual registers are identical. So both
> chip variants can easily be supported by the same driver. The issue of non
> matching register address layouts is solved by a simple look-up table which
> translates the I2C addresses to the SPI addresses.

> The patch moves the bulk of the adt7410 driver to a common module that will be
> shared by the adt7410 and adt7310 drivers. This common module implements the
> driver logic and uses a set of virtual functions to perform IO access. The
> adt7410 and adt7310 driver modules provide proper implementations of these IO
> accessor functions for I2C respective SPI.


--
WBR,
Andrey Repin (hell-for-yahoo@umail.ru) 16.02.2013, <04:39>

Sorry for my terrible english...


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

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

* Re: [lm-sensors] [PATCH 7/9] hwmon: (adt7410) Add support for the adt7310/adt7320
  2013-02-15 20:05     ` [lm-sensors] " Hartmut Knaack
  (?)
  (?)
@ 2013-02-16 15:49     ` Lars-Peter Clausen
  -1 siblings, 0 replies; 56+ messages in thread
From: Lars-Peter Clausen @ 2013-02-16 15:49 UTC (permalink / raw)
  To: lm-sensors

On 02/16/2013 01:40 AM, Andrey Repin wrote:
> Greetings, Lars-Peter Clausen!
> 
>> The adt7310/adt7320 is the SPI version of
>> the adt7410/adt7320. The register map
> 
> Typo, I suppose?  ^
> Just making sure it doesn't end copy-pasted somewhere else.
> 

Yep, thanks.

- Lars

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

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

* Re: [PATCH 7/9] hwmon: (adt7410) Add support for the adt7310/adt7320
  2013-02-15 20:05     ` [lm-sensors] " Hartmut Knaack
@ 2013-02-16 15:54       ` Lars-Peter Clausen
  -1 siblings, 0 replies; 56+ messages in thread
From: Lars-Peter Clausen @ 2013-02-16 15:54 UTC (permalink / raw)
  To: Hartmut Knaack
  Cc: Jean Delvare, Guenter Roeck, Jonathan Cameron, lm-sensors, linux-iio

On 02/15/2013 09:05 PM, Hartmut Knaack wrote:
> I had a quick look over your patches and found some minor typo, see below. I will apply all the patches to see the result.
> Also keep in mind to add some changes to Documentation/hwmon/adt7410 (and add an adt7310 as well?).

yep, forgot about the documentation, will do this in v2. But I don't think it
makes sense to have to separate documents for the adt7410 and adt7310, the
devices really only differ in their interface and all of the real driver logic
is implemented in the common code.

> 
> Lars-Peter Clausen schrieb:
> <...>
>> diff --git a/drivers/hwmon/adt7310.c b/drivers/hwmon/adt7310.c
>> new file mode 100644
>> index 0000000..0483e6c
>> --- /dev/null
>> +++ b/drivers/hwmon/adt7310.c
>> @@ -0,0 +1,160 @@
>> +/*
>> + * ADT7310/ADT7310 digital temperature sensor driver
>> + *
>> + * Copyright 2010-2013 Analog Devices Inc.
>> + *   Author: Lars-Peter Clausen <lars@metafoo.de>
>> + *
>> + * Licensed under the GPL-2 or later.
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/spi/spi.h>
>> +
>> +#include "adt7x10.h"
>> +
>> +static const u8 adt7371_reg_table[] = {
>> +	[ADT7410_TEMPERATURE]   = ADT7310_TEMPERATURE,
>> +	[ADT7410_STATUS]	= ADT7310_STATUS,
>> +	[ADT7410_CONFIG]	= ADT7310_CONFIG,
>> +	[ADT7410_T_ALARM_HIGH]	= ADT7310_T_ALARM_HIGH,
>> +	[ADT7410_T_ALARM_LOW]	= ADT7310_T_ALARM_LOW,
>> +	[ADT7410_T_CRIT]	= ADT7310_T_CRIT,
>> +	[ADT7410_T_HYST]	= ADT7310_T_HYST,
>> +	[ADT7410_ID]		= ADT7310_ID,
>> +};
> Just out of curiousity, whats the reason for the name adt7371 here?

That's also a typo. And don't ask we how I got from adt7310 to adt7371, I have
no idea.

[...]
>> +
>> +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
>> +MODULE_DESCRIPTION("ADT7310/ADT7420 driver");
> This should be ADT7310/ADT7320, right?

Yes, fixed.

>> +MODULE_LICENSE("GPL");
> <...>
>> --- /dev/null
>> +++ b/drivers/hwmon/adt7x10.c
>> @@ -0,0 +1,476 @@
[...]
>> +
>> +MODULE_AUTHOR("Hartmut Knaack");
>> +MODULE_DESCRIPTION("ADT7410 driver");
> This description does not seem appropriate any longer.

Changed it to "ADT7410/ADT7420, ADT7310/ADT7320 common code".

Thanks,
- Lars

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

* Re: [lm-sensors] [PATCH 7/9] hwmon: (adt7410) Add support for the adt7310/adt7320
@ 2013-02-16 15:54       ` Lars-Peter Clausen
  0 siblings, 0 replies; 56+ messages in thread
From: Lars-Peter Clausen @ 2013-02-16 15:54 UTC (permalink / raw)
  To: Hartmut Knaack
  Cc: Jean Delvare, Guenter Roeck, Jonathan Cameron, lm-sensors, linux-iio

On 02/15/2013 09:05 PM, Hartmut Knaack wrote:
> I had a quick look over your patches and found some minor typo, see below. I will apply all the patches to see the result.
> Also keep in mind to add some changes to Documentation/hwmon/adt7410 (and add an adt7310 as well?).

yep, forgot about the documentation, will do this in v2. But I don't think it
makes sense to have to separate documents for the adt7410 and adt7310, the
devices really only differ in their interface and all of the real driver logic
is implemented in the common code.

> 
> Lars-Peter Clausen schrieb:
> <...>
>> diff --git a/drivers/hwmon/adt7310.c b/drivers/hwmon/adt7310.c
>> new file mode 100644
>> index 0000000..0483e6c
>> --- /dev/null
>> +++ b/drivers/hwmon/adt7310.c
>> @@ -0,0 +1,160 @@
>> +/*
>> + * ADT7310/ADT7310 digital temperature sensor driver
>> + *
>> + * Copyright 2010-2013 Analog Devices Inc.
>> + *   Author: Lars-Peter Clausen <lars@metafoo.de>
>> + *
>> + * Licensed under the GPL-2 or later.
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/spi/spi.h>
>> +
>> +#include "adt7x10.h"
>> +
>> +static const u8 adt7371_reg_table[] = {
>> +	[ADT7410_TEMPERATURE]   = ADT7310_TEMPERATURE,
>> +	[ADT7410_STATUS]	= ADT7310_STATUS,
>> +	[ADT7410_CONFIG]	= ADT7310_CONFIG,
>> +	[ADT7410_T_ALARM_HIGH]	= ADT7310_T_ALARM_HIGH,
>> +	[ADT7410_T_ALARM_LOW]	= ADT7310_T_ALARM_LOW,
>> +	[ADT7410_T_CRIT]	= ADT7310_T_CRIT,
>> +	[ADT7410_T_HYST]	= ADT7310_T_HYST,
>> +	[ADT7410_ID]		= ADT7310_ID,
>> +};
> Just out of curiousity, whats the reason for the name adt7371 here?

That's also a typo. And don't ask we how I got from adt7310 to adt7371, I have
no idea.

[...]
>> +
>> +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
>> +MODULE_DESCRIPTION("ADT7310/ADT7420 driver");
> This should be ADT7310/ADT7320, right?

Yes, fixed.

>> +MODULE_LICENSE("GPL");
> <...>
>> --- /dev/null
>> +++ b/drivers/hwmon/adt7x10.c
>> @@ -0,0 +1,476 @@
[...]
>> +
>> +MODULE_AUTHOR("Hartmut Knaack");
>> +MODULE_DESCRIPTION("ADT7410 driver");
> This description does not seem appropriate any longer.

Changed it to "ADT7410/ADT7420, ADT7310/ADT7320 common code".

Thanks,
- Lars

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

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

* Re: [PATCH 6/9] hwmon: (adt7410) Don't re-read non-volatile registers
  2013-02-15 20:20     ` [lm-sensors] " Guenter Roeck
@ 2013-02-16 15:56       ` Lars-Peter Clausen
  -1 siblings, 0 replies; 56+ messages in thread
From: Lars-Peter Clausen @ 2013-02-16 15:56 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: Jean Delvare, Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio

On 02/15/2013 09:20 PM, Guenter Roeck wrote:
> On Fri, Feb 15, 2013 at 05:57:15PM +0100, Lars-Peter Clausen wrote:
>> Currently each time the temperature register is read the driver also reads the
>> threshold and hysteresis registers. This increases the amount of I2C traffic and
>> time needed to read the temperature by a factor of ~5. Neither the threshold nor
>> the hysteresis change on their own, so once we've read them, we should be able
>> to just use the cached value of the registers. This patch modifies the code
>> accordingly and only reads the threshold and hysteresis registers once during
>> probe.
>>
>> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
>> ---
>>  drivers/hwmon/adt7410.c | 89 +++++++++++++++++++++++++++++++------------------
>>  1 file changed, 56 insertions(+), 33 deletions(-)
>>
>> diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
>> index 99a7290..5de0376 100644
>> --- a/drivers/hwmon/adt7410.c
>> +++ b/drivers/hwmon/adt7410.c
>> @@ -119,45 +119,31 @@ static int adt7410_temp_ready(struct i2c_client *client)
>>  	return -ETIMEDOUT;
>>  }
>>  
>> -static struct adt7410_data *adt7410_update_device(struct device *dev)
>> +static int adt7410_update_temp(struct device *dev)
>>  {
>>  	struct i2c_client *client = to_i2c_client(dev);
>>  	struct adt7410_data *data = i2c_get_clientdata(client);
>> -	struct adt7410_data *ret = data;
>> +	int ret = 0;
>> +
>>  	mutex_lock(&data->update_lock);
>>  
>>  	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
>>  	    || !data->valid) {
>> -		int i, status;
>>  
>>  		dev_dbg(&client->dev, "Starting update\n");
>>  
>> -		status = adt7410_temp_ready(client); /* check for new value */
>> -		if (unlikely(status)) {
>> -			ret = ERR_PTR(status);
>> +		ret = adt7410_temp_ready(client); /* check for new value */
>> +		if (ret)
>>  			goto abort;
>> -		}
>> -		for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
>> -			status = i2c_smbus_read_word_swapped(client,
>> -							ADT7410_REG_TEMP[i]);
>> -			if (unlikely(status < 0)) {
>> -				dev_dbg(dev,
>> -					"Failed to read value: reg %d, error %d\n",
>> -					ADT7410_REG_TEMP[i], status);
>> -				ret = ERR_PTR(status);
>> -				goto abort;
>> -			}
>> -			data->temp[i] = status;
>> -		}
>> -		status = i2c_smbus_read_byte_data(client, ADT7410_T_HYST);
>> -		if (unlikely(status < 0)) {
>> -			dev_dbg(dev,
>> -				"Failed to read value: reg %d, error %d\n",
>> -				ADT7410_T_HYST, status);
>> -			ret = ERR_PTR(status);
>> +
>> +		ret = i2c_smbus_read_word_swapped(client, ADT7410_REG_TEMP[0]);
>> +		if (ret) {
> 
> Should be
> 		if (ret < 0) {
> 
> or non-zero temperatures always create an error condition.
> 
>> +			dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
>> +				ADT7410_REG_TEMP[0], ret);
>>  			goto abort;
>>  		}
>> -		data->hyst = status;
>> +		data->temp[0] = ret;
>> +
>>  		data->last_updated = jiffies;
>>  		data->valid = true;
>>  	}
>> @@ -167,6 +153,35 @@ abort:
>>  	return ret;
> 
> 	ret can be > 0 as no-error return. So you'll either have to
> 	change the no-error return case to always return 0, or change the
> 	return value check when the function is called.
>>  }
>>  
>> +static int adt7410_fill_cache(struct i2c_client *client)
>> +{
>> +	struct adt7410_data *data = i2c_get_clientdata(client);
>> +	int ret;
>> +	int i;
>> +
>> +	for (i = 1; i < 3; i++) {
> 
> I think using ARRAY_SIZE would be better here. With "i < 3" you don't read the
> critical temperature, which proves the point (unless I am missing something).
> 
>> +		ret = i2c_smbus_read_word_swapped(client, ADT7410_REG_TEMP[i]);
>> +		if (ret) {
> 
> 		ret < 0
> 
>> +			dev_dbg(&client->dev,
>> +				"Failed to read value: reg %d, error %d\n",
>> +				ADT7410_REG_TEMP[0], ret);
>> +			return ret;
>> +		}
>> +		data->temp[i] = ret;
>> +	}
>> +
>> +	ret = i2c_smbus_read_byte_data(client, ADT7410_T_HYST);
>> +	if (ret) {
> 
> 	ret < 0
> 
>> +		dev_dbg(&client->dev,
>> +			"Failed to read value: hyst reg, error %d\n",
>> +			ret);
>> +		return ret;
>> +	}
>> +	data->hyst = ret;
>> +
>> +	return 0;
>> +}
>> +
>>  static s16 ADT7410_TEMP_TO_REG(long temp)
>>  {
>>  	return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7410_TEMP_MIN,
>> @@ -193,10 +208,16 @@ static ssize_t adt7410_show_temp(struct device *dev,
>>  				 struct device_attribute *da, char *buf)
>>  {
>>  	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
>> -	struct adt7410_data *data = adt7410_update_device(dev);
>> +	struct i2c_client *client = to_i2c_client(dev);
>> +	struct adt7410_data *data = i2c_get_clientdata(client);
>>  
>> -	if (IS_ERR(data))
>> -		return PTR_ERR(data);
>> +	if (attr->index == 0) {
>> +		int ret;
>> +
>> +		ret = adt7410_update_temp(dev);
>> +		if (ret)
> 
> Problematic; see above.
> 

Yep all correct, I somehow mixed up a few things between patch 6 and 7. Will
fix it for v2.

Thanks,
- Lars

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

* Re: [lm-sensors] [PATCH 6/9] hwmon: (adt7410) Don't re-read non-volatile registers
@ 2013-02-16 15:56       ` Lars-Peter Clausen
  0 siblings, 0 replies; 56+ messages in thread
From: Lars-Peter Clausen @ 2013-02-16 15:56 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: Jean Delvare, Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio

On 02/15/2013 09:20 PM, Guenter Roeck wrote:
> On Fri, Feb 15, 2013 at 05:57:15PM +0100, Lars-Peter Clausen wrote:
>> Currently each time the temperature register is read the driver also reads the
>> threshold and hysteresis registers. This increases the amount of I2C traffic and
>> time needed to read the temperature by a factor of ~5. Neither the threshold nor
>> the hysteresis change on their own, so once we've read them, we should be able
>> to just use the cached value of the registers. This patch modifies the code
>> accordingly and only reads the threshold and hysteresis registers once during
>> probe.
>>
>> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
>> ---
>>  drivers/hwmon/adt7410.c | 89 +++++++++++++++++++++++++++++++------------------
>>  1 file changed, 56 insertions(+), 33 deletions(-)
>>
>> diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
>> index 99a7290..5de0376 100644
>> --- a/drivers/hwmon/adt7410.c
>> +++ b/drivers/hwmon/adt7410.c
>> @@ -119,45 +119,31 @@ static int adt7410_temp_ready(struct i2c_client *client)
>>  	return -ETIMEDOUT;
>>  }
>>  
>> -static struct adt7410_data *adt7410_update_device(struct device *dev)
>> +static int adt7410_update_temp(struct device *dev)
>>  {
>>  	struct i2c_client *client = to_i2c_client(dev);
>>  	struct adt7410_data *data = i2c_get_clientdata(client);
>> -	struct adt7410_data *ret = data;
>> +	int ret = 0;
>> +
>>  	mutex_lock(&data->update_lock);
>>  
>>  	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
>>  	    || !data->valid) {
>> -		int i, status;
>>  
>>  		dev_dbg(&client->dev, "Starting update\n");
>>  
>> -		status = adt7410_temp_ready(client); /* check for new value */
>> -		if (unlikely(status)) {
>> -			ret = ERR_PTR(status);
>> +		ret = adt7410_temp_ready(client); /* check for new value */
>> +		if (ret)
>>  			goto abort;
>> -		}
>> -		for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
>> -			status = i2c_smbus_read_word_swapped(client,
>> -							ADT7410_REG_TEMP[i]);
>> -			if (unlikely(status < 0)) {
>> -				dev_dbg(dev,
>> -					"Failed to read value: reg %d, error %d\n",
>> -					ADT7410_REG_TEMP[i], status);
>> -				ret = ERR_PTR(status);
>> -				goto abort;
>> -			}
>> -			data->temp[i] = status;
>> -		}
>> -		status = i2c_smbus_read_byte_data(client, ADT7410_T_HYST);
>> -		if (unlikely(status < 0)) {
>> -			dev_dbg(dev,
>> -				"Failed to read value: reg %d, error %d\n",
>> -				ADT7410_T_HYST, status);
>> -			ret = ERR_PTR(status);
>> +
>> +		ret = i2c_smbus_read_word_swapped(client, ADT7410_REG_TEMP[0]);
>> +		if (ret) {
> 
> Should be
> 		if (ret < 0) {
> 
> or non-zero temperatures always create an error condition.
> 
>> +			dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
>> +				ADT7410_REG_TEMP[0], ret);
>>  			goto abort;
>>  		}
>> -		data->hyst = status;
>> +		data->temp[0] = ret;
>> +
>>  		data->last_updated = jiffies;
>>  		data->valid = true;
>>  	}
>> @@ -167,6 +153,35 @@ abort:
>>  	return ret;
> 
> 	ret can be > 0 as no-error return. So you'll either have to
> 	change the no-error return case to always return 0, or change the
> 	return value check when the function is called.
>>  }
>>  
>> +static int adt7410_fill_cache(struct i2c_client *client)
>> +{
>> +	struct adt7410_data *data = i2c_get_clientdata(client);
>> +	int ret;
>> +	int i;
>> +
>> +	for (i = 1; i < 3; i++) {
> 
> I think using ARRAY_SIZE would be better here. With "i < 3" you don't read the
> critical temperature, which proves the point (unless I am missing something).
> 
>> +		ret = i2c_smbus_read_word_swapped(client, ADT7410_REG_TEMP[i]);
>> +		if (ret) {
> 
> 		ret < 0
> 
>> +			dev_dbg(&client->dev,
>> +				"Failed to read value: reg %d, error %d\n",
>> +				ADT7410_REG_TEMP[0], ret);
>> +			return ret;
>> +		}
>> +		data->temp[i] = ret;
>> +	}
>> +
>> +	ret = i2c_smbus_read_byte_data(client, ADT7410_T_HYST);
>> +	if (ret) {
> 
> 	ret < 0
> 
>> +		dev_dbg(&client->dev,
>> +			"Failed to read value: hyst reg, error %d\n",
>> +			ret);
>> +		return ret;
>> +	}
>> +	data->hyst = ret;
>> +
>> +	return 0;
>> +}
>> +
>>  static s16 ADT7410_TEMP_TO_REG(long temp)
>>  {
>>  	return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7410_TEMP_MIN,
>> @@ -193,10 +208,16 @@ static ssize_t adt7410_show_temp(struct device *dev,
>>  				 struct device_attribute *da, char *buf)
>>  {
>>  	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
>> -	struct adt7410_data *data = adt7410_update_device(dev);
>> +	struct i2c_client *client = to_i2c_client(dev);
>> +	struct adt7410_data *data = i2c_get_clientdata(client);
>>  
>> -	if (IS_ERR(data))
>> -		return PTR_ERR(data);
>> +	if (attr->index = 0) {
>> +		int ret;
>> +
>> +		ret = adt7410_update_temp(dev);
>> +		if (ret)
> 
> Problematic; see above.
> 

Yep all correct, I somehow mixed up a few things between patch 6 and 7. Will
fix it for v2.

Thanks,
- Lars

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

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

* Re: [PATCH 7/9] hwmon: (adt7410) Add support for the adt7310/adt7320
  2013-02-15 20:32     ` [lm-sensors] " Guenter Roeck
@ 2013-02-16 16:04       ` Lars-Peter Clausen
  -1 siblings, 0 replies; 56+ messages in thread
From: Lars-Peter Clausen @ 2013-02-16 16:04 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: Jean Delvare, Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio

On 02/15/2013 09:32 PM, Guenter Roeck wrote:
> On Fri, Feb 15, 2013 at 05:57:16PM +0100, Lars-Peter Clausen wrote:
>> The adt7310/adt7320 is the SPI version of the adt7410/adt7320. The register map
>> layout is a bit different, i.e. the register addresses differ between the two
>> variants, but the bit layouts of the individual registers are identical. So both
>> chip variants can easily be supported by the same driver. The issue of non
>> matching register address layouts is solved by a simple look-up table which
>> translates the I2C addresses to the SPI addresses.
>>
>> The patch moves the bulk of the adt7410 driver to a common module that will be
>> shared by the adt7410 and adt7310 drivers. This common module implements the
>> driver logic and uses a set of virtual functions to perform IO access. The
>> adt7410 and adt7310 driver modules provide proper implementations of these IO
>> accessor functions for I2C respective SPI.
>>
>> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
>> ---
>>  drivers/hwmon/Kconfig   |  20 ++
>>  drivers/hwmon/Makefile  |   2 +
>>  drivers/hwmon/adt7310.c | 160 ++++++++++++++++
>>  drivers/hwmon/adt7410.c | 472 ++++++-----------------------------------------
>>  drivers/hwmon/adt7x10.c | 476 ++++++++++++++++++++++++++++++++++++++++++++++++
>>  drivers/hwmon/adt7x10.h |  47 +++++
>>  6 files changed, 758 insertions(+), 419 deletions(-)
>>  create mode 100644 drivers/hwmon/adt7310.c
>>  create mode 100644 drivers/hwmon/adt7x10.c
>>  create mode 100644 drivers/hwmon/adt7x10.h
>>
>> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
>> index 89ac1cb..aaa14f4 100644
>> --- a/drivers/hwmon/Kconfig
>> +++ b/drivers/hwmon/Kconfig
>> @@ -179,9 +179,29 @@ config SENSORS_ADM9240
>>  	  This driver can also be built as a module.  If so, the module
>>  	  will be called adm9240.
>>  
>> +config SENSORS_ADT7X10
>> +	tristate
>> +	help
>> +	  This module contains common code shared by the ADT7310/ADT7320 and
>> +	  ADT7410/ADT7420 temperature monitoring chip drivers.
>> +
>> +	  If build as a module, the module will be called adt7x10.
>> +
>> +config SENSORS_ADT7310
>> +	tristate "Analog Devices ADT7310/ADT7320"
>> +	depends on SPI_MASTER
>> +	select SENSORS_ADT7X10
>> +	help
>> +	  If you say yes here you get support for the Analog Devices
>> +	  ADT7310 and ADT7320 temperature monitoring chips.
>> +
>> +	  This driver can also be built as a module. If so, the module
>> +	  will be called adt7310.
>> +
>>  config SENSORS_ADT7410
>>  	tristate "Analog Devices ADT7410/ADT7420"
>>  	depends on I2C
>> +	select SENSORS_ADT7X10
>>  	help
>>  	  If you say yes here you get support for the Analog Devices
>>  	  ADT7410 and ADT7420 temperature monitoring chips.
>> diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
>> index 8d6d97e..5d36a57 100644
>> --- a/drivers/hwmon/Makefile
>> +++ b/drivers/hwmon/Makefile
>> @@ -34,6 +34,8 @@ obj-$(CONFIG_SENSORS_ADM9240)	+= adm9240.o
>>  obj-$(CONFIG_SENSORS_ADS1015)	+= ads1015.o
>>  obj-$(CONFIG_SENSORS_ADS7828)	+= ads7828.o
>>  obj-$(CONFIG_SENSORS_ADS7871)	+= ads7871.o
>> +obj-$(CONFIG_SENSORS_ADT7X10)	+= adt7x10.o
>> +obj-$(CONFIG_SENSORS_ADT7310)	+= adt7310.o
>>  obj-$(CONFIG_SENSORS_ADT7410)	+= adt7410.o
>>  obj-$(CONFIG_SENSORS_ADT7411)	+= adt7411.o
>>  obj-$(CONFIG_SENSORS_ADT7462)	+= adt7462.o
>> diff --git a/drivers/hwmon/adt7310.c b/drivers/hwmon/adt7310.c
>> new file mode 100644
>> index 0000000..0483e6c
>> --- /dev/null
>> +++ b/drivers/hwmon/adt7310.c
>> @@ -0,0 +1,160 @@
>> +/*
>> + * ADT7310/ADT7310 digital temperature sensor driver
>> + *
>> + * Copyright 2010-2013 Analog Devices Inc.
>> + *   Author: Lars-Peter Clausen <lars@metafoo.de>
>> + *
>> + * Licensed under the GPL-2 or later.
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/spi/spi.h>
>> +
>> +#include "adt7x10.h"
>> +
>> +static const u8 adt7371_reg_table[] = {
>> +	[ADT7410_TEMPERATURE]   = ADT7310_TEMPERATURE,
>> +	[ADT7410_STATUS]	= ADT7310_STATUS,
>> +	[ADT7410_CONFIG]	= ADT7310_CONFIG,
>> +	[ADT7410_T_ALARM_HIGH]	= ADT7310_T_ALARM_HIGH,
>> +	[ADT7410_T_ALARM_LOW]	= ADT7310_T_ALARM_LOW,
>> +	[ADT7410_T_CRIT]	= ADT7310_T_CRIT,
>> +	[ADT7410_T_HYST]	= ADT7310_T_HYST,
>> +	[ADT7410_ID]		= ADT7310_ID,
>> +};
>> +
>> +#define ADT7310_CMD_REG_MASK			0x28
>> +#define ADT7310_CMD_REG_OFFSET			3
>> +#define ADT7310_CMD_READ			0x40
>> +#define ADT7310_CMD_CON_READ			0x4
>> +
>> +#define AD7310_COMMAND(reg) (adt7371_reg_table[(reg)] << ADT7310_CMD_REG_OFFSET)
>> +
>> +static int adt7310_spi_read_word(struct device *dev,
>> +	u8 reg, u16 *data)
> 
> I don't really like the approach of separating the return value from the error
> code, if both can be returned directly. There are two reasons: First, the code
> gets more complex, and second, the compiler tends to get confused under some
> conditions abd believe that the return value is not set. And I really don't want
> to have to deal with the resulting build warnings, after getting rid of pretty
> much all such warnings in the hwmon subsystem. So I'd really appreciate if you
> could rewrite this and the subsequent patches to return both error and value as
> function return values.
> 

I can change it, but I don't think that the current code will confuse the
compiler, the return value is set under all circumstances. And the code
actually gets slightly more complex by rewriting it. Most of the time we don't
want to store the result of the read operation on stack but rather somewhere else.

	ret = adt7410_read_word(dev, TEMP);
	if (ret < 0) {
		...
	}
	data->temp[0] = ret;

Without the change we can write it as:

	ret = adt7410_read_word(dev, TEMP, &data->temp[0])
	if (ret) {
		...
	}

The difference is not that big, so I won't argue over it if you prefer the
first version.

Thanks,
- Lars

>> +{
>> +	struct spi_device *spi = to_spi_device(dev);
>> +	u8 command = AD7310_COMMAND(reg);
>> +	int ret = 0;
>> +
>> +	command |= ADT7310_CMD_READ;
>> +	ret = spi_write(spi, &command, sizeof(command));
>> +	if (ret < 0) {
>> +		dev_err(dev, "SPI write command error\n");
>> +		return ret;
>> +	}
>> +
>> +	ret = spi_read(spi, (u8 *)data, sizeof(*data));
>> +	if (ret < 0) {
>> +		dev_err(dev, "SPI read word error\n");
>> +		return ret;
>> +	}
>> +
>> +	*data = be16_to_cpu(*data);
>> +
>> +	return 0;
>> +}
>> +
>> +static int adt7310_spi_write_word(struct device *dev, u8 reg,
>> +	u16 data)
>> +{
>> +	struct spi_device *spi = to_spi_device(dev);
>> +	u8 buf[3];
>> +	int ret = 0;
>> +
>> +	buf[0] = AD7310_COMMAND(reg);
>> +	buf[1] = (u8)(data >> 8);
>> +	buf[2] = (u8)(data & 0xFF);
>> +
>> +	ret = spi_write(spi, buf, 3);
>> +	if (ret < 0) {
>> +		dev_err(dev, "SPI write word error\n");
>> +		return ret;
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> +static int adt7310_spi_read_byte(struct device *dev, u8 reg,
>> +	u8 *data)
>> +{
>> +	struct spi_device *spi = to_spi_device(dev);
>> +	u8 command = AD7310_COMMAND(reg);
>> +	int ret = 0;
>> +
>> +	command |= ADT7310_CMD_READ;
>> +	ret = spi_write(spi, &command, sizeof(command));
>> +	if (ret < 0) {
>> +		dev_err(dev, "SPI write command error\n");
>> +		return ret;
>> +	}
>> +
>> +	ret = spi_read(spi, data, sizeof(*data));
>> +	if (ret < 0) {
>> +		dev_err(dev, "SPI read byte error\n");
>> +		return ret;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int adt7310_spi_write_byte(struct device *dev, u8 reg,
>> +	u8 data)
>> +{
>> +	struct spi_device *spi = to_spi_device(dev);
>> +	u8 buf[2];
>> +	int ret = 0;
>> +
>> +	buf[0] = AD7310_COMMAND(reg);
>> +	buf[1] = data;
>> +
>> +	ret = spi_write(spi, buf, 2);
>> +	if (ret < 0) {
>> +		dev_err(dev, "SPI write byte error\n");
>> +		return ret;
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> +static const struct adt7410_ops adt7310_spi_ops = {
>> +	.read_word = adt7310_spi_read_word,
>> +	.write_word = adt7310_spi_write_word,
>> +	.read_byte = adt7310_spi_read_byte,
>> +	.write_byte = adt7310_spi_write_byte,
>> +};
>> +
>> +static int adt7310_spi_probe(struct spi_device *spi)
>> +{
>> +	return adt7410_probe(&spi->dev, spi_get_device_id(spi)->name,
>> +			&adt7310_spi_ops);
>> +}
>> +
>> +static int adt7310_spi_remove(struct spi_device *spi)
>> +{
>> +	return adt7410_remove(&spi->dev);
>> +}
>> +
>> +static const struct spi_device_id adt7310_id[] = {
>> +	{ "adt7310", 0 },
>> +	{ "adt7320", 0 },
>> +	{}
>> +};
>> +MODULE_DEVICE_TABLE(spi, adt7310_id);
>> +
>> +static struct spi_driver adt7310_driver = {
>> +	.driver = {
>> +		.name = "adt7310",
>> +		.owner = THIS_MODULE,
>> +		.pm	= ADT7410_DEV_PM_OPS,
>> +	},
>> +	.probe = adt7310_spi_probe,
>> +	.remove = adt7310_spi_remove,
>> +	.id_table = adt7310_id,
>> +};
>> +module_spi_driver(adt7310_driver);
>> +
>> +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
>> +MODULE_DESCRIPTION("ADT7310/ADT7420 driver");
>> +MODULE_LICENSE("GPL");
>> diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
>> index 5de0376..13734c5 100644
>> --- a/drivers/hwmon/adt7410.c
>> +++ b/drivers/hwmon/adt7410.c
>> @@ -1,483 +1,117 @@
>>  /*
>> - * adt7410.c - Part of lm_sensors, Linux kernel modules for hardware
>> - *	 monitoring
>> - * This driver handles the ADT7410 and compatible digital temperature sensors.
>> - * Hartmut Knaack <knaack.h@gmx.de> 2012-07-22
>> - * based on lm75.c by Frodo Looijaard <frodol@dds.nl>
>> - * and adt7410.c from iio-staging by Sonic Zhang <sonic.zhang@analog.com>
>> + * ADT7410/ADT7420 digital temperature sensor driver
>>   *
>> - * This program is free software; you can redistribute it and/or modify
>> - * it under the terms of the GNU General Public License as published by
>> - * the Free Software Foundation; either version 2 of the License, or
>> - * (at your option) any later version.
>> + * Copyright 2010-2013 Analog Devices Inc.
>> + *   Author: Lars-Peter Clausen <lars@metafoo.de>
>>   *
>> - * This program is distributed in the hope that it will be useful,
>> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> - * GNU General Public License for more details.
>> - *
>> - * You should have received a copy of the GNU General Public License
>> - * along with this program; if not, write to the Free Software
>> - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
>> + * Licensed under the GPL-2 or later.
>>   */
>>  
>>  #include <linux/module.h>
>>  #include <linux/init.h>
>> -#include <linux/slab.h>
>> -#include <linux/jiffies.h>
>>  #include <linux/i2c.h>
>> -#include <linux/hwmon.h>
>> -#include <linux/hwmon-sysfs.h>
>> -#include <linux/err.h>
>> -#include <linux/mutex.h>
>> -#include <linux/delay.h>
>> -
>> -/*
>> - * ADT7410 registers definition
>> - */
>>  
>> -#define ADT7410_TEMPERATURE		0
>> -#define ADT7410_STATUS			2
>> -#define ADT7410_CONFIG			3
>> -#define ADT7410_T_ALARM_HIGH		4
>> -#define ADT7410_T_ALARM_LOW		6
>> -#define ADT7410_T_CRIT			8
>> -#define ADT7410_T_HYST			0xA
>> +#include "adt7x10.h"
>>  
>> -/*
>> - * ADT7410 status
>> - */
>> -#define ADT7410_STAT_T_LOW		(1 << 4)
>> -#define ADT7410_STAT_T_HIGH		(1 << 5)
>> -#define ADT7410_STAT_T_CRIT		(1 << 6)
>> -#define ADT7410_STAT_NOT_RDY		(1 << 7)
>> -
>> -/*
>> - * ADT7410 config
>> - */
>> -#define ADT7410_FAULT_QUEUE_MASK	(1 << 0 | 1 << 1)
>> -#define ADT7410_CT_POLARITY		(1 << 2)
>> -#define ADT7410_INT_POLARITY		(1 << 3)
>> -#define ADT7410_EVENT_MODE		(1 << 4)
>> -#define ADT7410_MODE_MASK		(1 << 5 | 1 << 6)
>> -#define ADT7410_FULL			(0 << 5 | 0 << 6)
>> -#define ADT7410_PD			(1 << 5 | 1 << 6)
>> -#define ADT7410_RESOLUTION		(1 << 7)
>> -
>> -/*
>> - * ADT7410 masks
>> - */
>> -#define ADT7410_T13_VALUE_MASK			0xFFF8
>> -#define ADT7410_T_HYST_MASK			0xF
>> -
>> -/* straight from the datasheet */
>> -#define ADT7410_TEMP_MIN (-55000)
>> -#define ADT7410_TEMP_MAX 150000
>> -
>> -enum adt7410_type {		/* keep sorted in alphabetical order */
>> -	adt7410,
>> -};
>> -
>> -static const u8 ADT7410_REG_TEMP[4] = {
>> -	ADT7410_TEMPERATURE,		/* input */
>> -	ADT7410_T_ALARM_HIGH,		/* high */
>> -	ADT7410_T_ALARM_LOW,		/* low */
>> -	ADT7410_T_CRIT,			/* critical */
>> -};
>> -
>> -/* Each client has this additional data */
>> -struct adt7410_data {
>> -	struct device		*hwmon_dev;
>> -	struct mutex		update_lock;
>> -	u8			config;
>> -	u8			oldconfig;
>> -	bool			valid;		/* true if registers valid */
>> -	unsigned long		last_updated;	/* In jiffies */
>> -	s16			temp[4];	/* Register values,
>> -						   0 = input
>> -						   1 = high
>> -						   2 = low
>> -						   3 = critical */
>> -	u8			hyst;		/* hysteresis offset */
>> -};
>> -
>> -/*
>> - * adt7410 register access by I2C
>> - */
>> -static int adt7410_temp_ready(struct i2c_client *client)
>> -{
>> -	int i, status;
>> -
>> -	for (i = 0; i < 6; i++) {
>> -		status = i2c_smbus_read_byte_data(client, ADT7410_STATUS);
>> -		if (status < 0)
>> -			return status;
>> -		if (!(status & ADT7410_STAT_NOT_RDY))
>> -			return 0;
>> -		msleep(60);
>> -	}
>> -	return -ETIMEDOUT;
>> -}
>> -
>> -static int adt7410_update_temp(struct device *dev)
>> +static int adt7410_i2c_read_word(struct device *dev, u8 reg, u16 *data)
>>  {
>>  	struct i2c_client *client = to_i2c_client(dev);
>> -	struct adt7410_data *data = i2c_get_clientdata(client);
>>  	int ret = 0;
>>  
>> -	mutex_lock(&data->update_lock);
>> -
>> -	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
>> -	    || !data->valid) {
>> -
>> -		dev_dbg(&client->dev, "Starting update\n");
>> -
>> -		ret = adt7410_temp_ready(client); /* check for new value */
>> -		if (ret)
>> -			goto abort;
>> -
>> -		ret = i2c_smbus_read_word_swapped(client, ADT7410_REG_TEMP[0]);
>> -		if (ret) {
>> -			dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
>> -				ADT7410_REG_TEMP[0], ret);
>> -			goto abort;
>> -		}
>> -		data->temp[0] = ret;
>> -
>> -		data->last_updated = jiffies;
>> -		data->valid = true;
>> -	}
>> -
>> -abort:
>> -	mutex_unlock(&data->update_lock);
>> -	return ret;
>> -}
>> -
>> -static int adt7410_fill_cache(struct i2c_client *client)
>> -{
>> -	struct adt7410_data *data = i2c_get_clientdata(client);
>> -	int ret;
>> -	int i;
>> -
>> -	for (i = 1; i < 3; i++) {
>> -		ret = i2c_smbus_read_word_swapped(client, ADT7410_REG_TEMP[i]);
>> -		if (ret) {
>> -			dev_dbg(&client->dev,
>> -				"Failed to read value: reg %d, error %d\n",
>> -				ADT7410_REG_TEMP[0], ret);
>> -			return ret;
>> -		}
>> -		data->temp[i] = ret;
>> -	}
>> -
>> -	ret = i2c_smbus_read_byte_data(client, ADT7410_T_HYST);
>> -	if (ret) {
>> -		dev_dbg(&client->dev,
>> -			"Failed to read value: hyst reg, error %d\n",
>> -			ret);
>> +	ret = i2c_smbus_read_word_swapped(client, reg);
>> +	if (ret < 0) {
>> +		dev_err(dev, "I2C read error\n");
>>  		return ret;
>>  	}
>> -	data->hyst = ret;
>> -
>> -	return 0;
>> -}
>>  
>> -static s16 ADT7410_TEMP_TO_REG(long temp)
>> -{
>> -	return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7410_TEMP_MIN,
>> -					   ADT7410_TEMP_MAX) * 128, 1000);
>> -}
>> +	*data = ret;
>>  
>> -static int ADT7410_REG_TO_TEMP(struct adt7410_data *data, s16 reg)
>> -{
>> -	/* in 13 bit mode, bits 0-2 are status flags - mask them out */
>> -	if (!(data->config & ADT7410_RESOLUTION))
>> -		reg &= ADT7410_T13_VALUE_MASK;
>> -	/*
>> -	 * temperature is stored in twos complement format, in steps of
>> -	 * 1/128°C
>> -	 */
>> -	return DIV_ROUND_CLOSEST(reg * 1000, 128);
>> +	return 0;
>>  }
>>  
>> -/*-----------------------------------------------------------------------*/
>> -
>> -/* sysfs attributes for hwmon */
>> -
>> -static ssize_t adt7410_show_temp(struct device *dev,
>> -				 struct device_attribute *da, char *buf)
>> +static int adt7410_i2c_write_word(struct device *dev, u8 reg, u16 data)
>>  {
>> -	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
>>  	struct i2c_client *client = to_i2c_client(dev);
>> -	struct adt7410_data *data = i2c_get_clientdata(client);
>> -
>> -	if (attr->index == 0) {
>> -		int ret;
>> +	int ret = 0;
>>  
>> -		ret = adt7410_update_temp(dev);
>> -		if (ret)
>> -			return ret;
>> -	}
>> +	ret = i2c_smbus_write_word_swapped(client, reg, data);
>> +	if (ret < 0)
>> +		dev_err(dev, "I2C write error\n");
>>  
>> -	return sprintf(buf, "%d\n", ADT7410_REG_TO_TEMP(data,
>> -		       data->temp[attr->index]));
>> +	return ret;
>>  }
>>  
>> -static ssize_t adt7410_set_temp(struct device *dev,
>> -				struct device_attribute *da,
>> -				const char *buf, size_t count)
>> +static int adt7410_i2c_read_byte(struct device *dev, u8 reg, u8 *data)
>>  {
>> -	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
>>  	struct i2c_client *client = to_i2c_client(dev);
>> -	struct adt7410_data *data = i2c_get_clientdata(client);
>> -	int nr = attr->index;
>> -	long temp;
>> -	int ret;
>> +	int ret = 0;
>>  
>> -	ret = kstrtol(buf, 10, &temp);
>> -	if (ret)
>> +	ret = i2c_smbus_read_byte_data(client, reg);
>> +	if (ret < 0) {
>> +		dev_err(dev, "I2C read error\n");
>>  		return ret;
>> +	}
>>  
>> -	mutex_lock(&data->update_lock);
>> -	data->temp[nr] = ADT7410_TEMP_TO_REG(temp);
>> -	ret = i2c_smbus_write_word_swapped(client, ADT7410_REG_TEMP[nr],
>> -					   data->temp[nr]);
>> -	if (ret)
>> -		count = ret;
>> -	mutex_unlock(&data->update_lock);
>> -	return count;
>> -}
>> -
>> -static ssize_t adt7410_show_t_hyst(struct device *dev,
>> -				   struct device_attribute *da,
>> -				   char *buf)
>> -{
>> -	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
>> -	struct i2c_client *client = to_i2c_client(dev);
>> -	struct adt7410_data *data = i2c_get_clientdata(client);
>> -	int nr = attr->index;
>> -	int hyst;
>> -
>> -	hyst = (data->hyst & ADT7410_T_HYST_MASK) * 1000;
>> -
>> -	/*
>> -	 * hysteresis is stored as a 4 bit offset in the device, convert it
>> -	 * to an absolute value
>> -	 */
>> -	if (nr == 2)	/* min has positive offset, others have negative */
>> -		hyst = -hyst;
>> -	return sprintf(buf, "%d\n",
>> -		       ADT7410_REG_TO_TEMP(data, data->temp[nr]) - hyst);
>> -}
>> -
>> -static ssize_t adt7410_set_t_hyst(struct device *dev,
>> -				  struct device_attribute *da,
>> -				  const char *buf, size_t count)
>> -{
>> -	struct i2c_client *client = to_i2c_client(dev);
>> -	struct adt7410_data *data = i2c_get_clientdata(client);
>> -	int limit, ret;
>> -	long hyst;
>> -
>> -	ret = kstrtol(buf, 10, &hyst);
>> -	if (ret)
>> -		return ret;
>> -	/* convert absolute hysteresis value to a 4 bit delta value */
>> -	limit = ADT7410_REG_TO_TEMP(data, data->temp[1]);
>> -	hyst = clamp_val(hyst, ADT7410_TEMP_MIN, ADT7410_TEMP_MAX);
>> -	data->hyst = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000), 0,
>> -			       ADT7410_T_HYST_MASK);
>> -	ret = i2c_smbus_write_byte_data(client, ADT7410_T_HYST, data->hyst);
>> -	if (ret)
>> -		return ret;
>> +	*data = (u8)ret;
>>  
>> -	return count;
>> +	return 0;
>>  }
>>  
>> -static ssize_t adt7410_show_alarm(struct device *dev,
>> -				  struct device_attribute *da,
>> -				  char *buf)
>> +static int adt7410_i2c_write_byte(struct device *dev, u8 reg, u8 data)
>>  {
>>  	struct i2c_client *client = to_i2c_client(dev);
>> -	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
>> -	int ret;
>> +	int ret = 0;
>>  
>> -	ret = i2c_smbus_read_byte_data(client, ADT7410_STATUS);
>> +	ret = i2c_smbus_write_byte_data(client, reg, data);
>>  	if (ret < 0)
>> -		return ret;
>> +		dev_err(&client->dev, "I2C write error\n");
>>  
>> -	return sprintf(buf, "%d\n", !!(ret & attr->index));
>> +	return ret;
>>  }
>>  
>> -static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adt7410_show_temp, NULL, 0);
>> -static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
>> -			  adt7410_show_temp, adt7410_set_temp, 1);
>> -static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
>> -			  adt7410_show_temp, adt7410_set_temp, 2);
>> -static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
>> -			  adt7410_show_temp, adt7410_set_temp, 3);
>> -static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
>> -			  adt7410_show_t_hyst, adt7410_set_t_hyst, 1);
>> -static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO,
>> -			  adt7410_show_t_hyst, NULL, 2);
>> -static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO,
>> -			  adt7410_show_t_hyst, NULL, 3);
>> -static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, adt7410_show_alarm,
>> -			  NULL, ADT7410_STAT_T_LOW);
>> -static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adt7410_show_alarm,
>> -			  NULL, ADT7410_STAT_T_HIGH);
>> -static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, adt7410_show_alarm,
>> -			  NULL, ADT7410_STAT_T_CRIT);
>> -
>> -static struct attribute *adt7410_attributes[] = {
>> -	&sensor_dev_attr_temp1_input.dev_attr.attr,
>> -	&sensor_dev_attr_temp1_max.dev_attr.attr,
>> -	&sensor_dev_attr_temp1_min.dev_attr.attr,
>> -	&sensor_dev_attr_temp1_crit.dev_attr.attr,
>> -	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
>> -	&sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
>> -	&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
>> -	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
>> -	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
>> -	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
>> -	NULL
>> -};
>> -
>> -static const struct attribute_group adt7410_group = {
>> -	.attrs = adt7410_attributes,
>> +static const struct adt7410_ops adt7410_i2c_ops = {
>> +	.read_word = adt7410_i2c_read_word,
>> +	.write_word = adt7410_i2c_write_word,
>> +	.read_byte = adt7410_i2c_read_byte,
>> +	.write_byte = adt7410_i2c_write_byte,
>>  };
>>  
>> -/*-----------------------------------------------------------------------*/
>> -
>> -/* device probe and removal */
>> -
>> -static int adt7410_probe(struct i2c_client *client,
>> -			 const struct i2c_device_id *id)
>> +static int adt7410_i2c_probe(struct i2c_client *client,
>> +	const struct i2c_device_id *id)
>>  {
>> -	struct adt7410_data *data;
>> -	int ret;
>>  
>>  	if (!i2c_check_functionality(client->adapter,
>>  			I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
>>  		return -ENODEV;
>>  
>> -	data = devm_kzalloc(&client->dev, sizeof(struct adt7410_data),
>> -			    GFP_KERNEL);
>> -	if (!data)
>> -		return -ENOMEM;
>> -
>> -	i2c_set_clientdata(client, data);
>> -	mutex_init(&data->update_lock);
>> -
>> -	/* configure as specified */
>> -	ret = i2c_smbus_read_byte_data(client, ADT7410_CONFIG);
>> -	if (ret < 0) {
>> -		dev_dbg(&client->dev, "Can't read config? %d\n", ret);
>> -		return ret;
>> -	}
>> -	data->oldconfig = ret;
>> -	/*
>> -	 * Set to 16 bit resolution, continous conversion and comparator mode.
>> -	 */
>> -	ret &= ~ADT7410_MODE_MASK;
>> -	data->config = ret | ADT7410_FULL | ADT7410_RESOLUTION |
>> -			ADT7410_EVENT_MODE;
>> -	if (data->config != data->oldconfig) {
>> -		ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
>> -						data->config);
>> -		if (ret)
>> -			return ret;
>> -	}
>> -	dev_dbg(&client->dev, "Config %02x\n", data->config);
>> -
>> -	ret = adt7410_fill_cache(client);
>> -	if (ret)
>> -		goto exit_restore;
>> -
>> -	/* Register sysfs hooks */
>> -	ret = sysfs_create_group(&client->dev.kobj, &adt7410_group);
>> -	if (ret)
>> -		goto exit_restore;
>> -
>> -	data->hwmon_dev = hwmon_device_register(&client->dev);
>> -	if (IS_ERR(data->hwmon_dev)) {
>> -		ret = PTR_ERR(data->hwmon_dev);
>> -		goto exit_remove;
>> -	}
>> -
>> -	dev_info(&client->dev, "sensor '%s'\n", client->name);
>> -
>> -	return 0;
>> -
>> -exit_remove:
>> -	sysfs_remove_group(&client->dev.kobj, &adt7410_group);
>> -exit_restore:
>> -	i2c_smbus_write_byte_data(client, ADT7410_CONFIG, data->oldconfig);
>> -	return ret;
>> +	return adt7410_probe(&client->dev, NULL, &adt7410_i2c_ops);
>>  }
>>  
>> -static int adt7410_remove(struct i2c_client *client)
>> +static int adt7410_i2c_remove(struct i2c_client *client)
>>  {
>> -	struct adt7410_data *data = i2c_get_clientdata(client);
>> -
>> -	hwmon_device_unregister(data->hwmon_dev);
>> -	sysfs_remove_group(&client->dev.kobj, &adt7410_group);
>> -	if (data->oldconfig != data->config)
>> -		i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
>> -					  data->oldconfig);
>> -	return 0;
>> +	return adt7410_remove(&client->dev);
>>  }
>>  
>> -static const struct i2c_device_id adt7410_ids[] = {
>> -	{ "adt7410", adt7410, },
>> -	{ "adt7420", adt7410, },
>> -	{ /* LIST END */ }
>> +static const struct i2c_device_id adt7410_id[] = {
>> +	{ "adt7410", 0 },
>> +	{ "adt7420", 0 },
>> +	{}
>>  };
>> -MODULE_DEVICE_TABLE(i2c, adt7410_ids);
>> -
>> -#ifdef CONFIG_PM_SLEEP
>> -static int adt7410_suspend(struct device *dev)
>> -{
>> -	int ret;
>> -	struct i2c_client *client = to_i2c_client(dev);
>> -	struct adt7410_data *data = i2c_get_clientdata(client);
>> -
>> -	ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
>> -					data->config | ADT7410_PD);
>> -	return ret;
>> -}
>> -
>> -static int adt7410_resume(struct device *dev)
>> -{
>> -	int ret;
>> -	struct i2c_client *client = to_i2c_client(dev);
>> -	struct adt7410_data *data = i2c_get_clientdata(client);
>> -
>> -	ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG, data->config);
>> -	return ret;
>> -}
>> -
>> -static SIMPLE_DEV_PM_OPS(adt7410_dev_pm_ops, adt7410_suspend, adt7410_resume);
>> -
>> -#define ADT7410_DEV_PM_OPS (&adt7410_dev_pm_ops)
>> -#else
>> -#define ADT7410_DEV_PM_OPS NULL
>> -#endif /* CONFIG_PM */
>> +MODULE_DEVICE_TABLE(i2c, adt7410_id);
>>  
>>  static struct i2c_driver adt7410_driver = {
>> -	.class		= I2C_CLASS_HWMON,
>>  	.driver = {
>> -		.name	= "adt7410",
>> +		.name = "adt7410",
>>  		.pm	= ADT7410_DEV_PM_OPS,
>>  	},
>> -	.probe		= adt7410_probe,
>> -	.remove		= adt7410_remove,
>> -	.id_table	= adt7410_ids,
>> -	.address_list	= I2C_ADDRS(0x48, 0x49, 0x4a, 0x4b),
>> +	.probe = adt7410_i2c_probe,
>> +	.remove = adt7410_i2c_remove,
>> +	.id_table = adt7410_id,
>> +	.address_list = I2C_ADDRS(0x48, 0x49, 0x4a, 0x4b),
>> +	.class = I2C_CLASS_HWMON,
>>  };
>> -
>>  module_i2c_driver(adt7410_driver);
>>  
>> -MODULE_AUTHOR("Hartmut Knaack");
>> -MODULE_DESCRIPTION("ADT7410/ADT7420 driver");
>> +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
>> +MODULE_DESCRIPTION("ADT7410/AD7420 driver");
>>  MODULE_LICENSE("GPL");
>> diff --git a/drivers/hwmon/adt7x10.c b/drivers/hwmon/adt7x10.c
>> new file mode 100644
>> index 0000000..2598aaf
>> --- /dev/null
>> +++ b/drivers/hwmon/adt7x10.c
>> @@ -0,0 +1,476 @@
>> +/*
>> + * adt7410.c - Part of lm_sensors, Linux kernel modules for hardware
>> + *	 monitoring
>> + * This driver handles the ADT7410 and compatible digital temperature sensors.
>> + * Hartmut Knaack <knaack.h@gmx.de> 2012-07-22
>> + * based on lm75.c by Frodo Looijaard <frodol@dds.nl>
>> + * and adt7410.c from iio-staging by Sonic Zhang <sonic.zhang@analog.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, write to the Free Software
>> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/slab.h>
>> +#include <linux/jiffies.h>
>> +#include <linux/hwmon.h>
>> +#include <linux/hwmon-sysfs.h>
>> +#include <linux/err.h>
>> +#include <linux/mutex.h>
>> +#include <linux/delay.h>
>> +
>> +#include "adt7x10.h"
>> +
>> +/*
>> + * ADT7410 status
>> + */
>> +#define ADT7410_STAT_T_LOW		(1 << 4)
>> +#define ADT7410_STAT_T_HIGH		(1 << 5)
>> +#define ADT7410_STAT_T_CRIT		(1 << 6)
>> +#define ADT7410_STAT_NOT_RDY		(1 << 7)
>> +
>> +/*
>> + * ADT7410 config
>> + */
>> +#define ADT7410_FAULT_QUEUE_MASK	(1 << 0 | 1 << 1)
>> +#define ADT7410_CT_POLARITY		(1 << 2)
>> +#define ADT7410_INT_POLARITY		(1 << 3)
>> +#define ADT7410_EVENT_MODE		(1 << 4)
>> +#define ADT7410_MODE_MASK		(1 << 5 | 1 << 6)
>> +#define ADT7410_FULL			(0 << 5 | 0 << 6)
>> +#define ADT7410_PD			(1 << 5 | 1 << 6)
>> +#define ADT7410_RESOLUTION		(1 << 7)
>> +
>> +/*
>> + * ADT7410 masks
>> + */
>> +#define ADT7410_T13_VALUE_MASK			0xFFF8
>> +#define ADT7410_T_HYST_MASK			0xF
>> +
>> +/* straight from the datasheet */
>> +#define ADT7410_TEMP_MIN (-55000)
>> +#define ADT7410_TEMP_MAX 150000
>> +
>> +/* Each client has this additional data */
>> +struct adt7410_data {
>> +	const struct adt7410_ops *ops;
>> +	const char		*name;
>> +	struct device		*hwmon_dev;
>> +	struct mutex		update_lock;
>> +	u8			config;
>> +	u8			oldconfig;
>> +	bool			valid;		/* true if registers valid */
>> +	unsigned long		last_updated;	/* In jiffies */
>> +	s16			temp[4];	/* Register values,
>> +						   0 = input
>> +						   1 = high
>> +						   2 = low
>> +						   3 = critical */
>> +	u8			hyst;		/* hysteresis offset */
>> +};
>> +
>> +static int adt7410_read_word(struct device *dev, u8 reg, u16 *data)
>> +{
>> +	struct adt7410_data *d = dev_get_drvdata(dev);
>> +	return d->ops->read_word(dev, reg, data);
>> +}
>> +
>> +static int adt7410_write_word(struct device *dev, u8 reg, u16 data)
>> +{
>> +	struct adt7410_data *d = dev_get_drvdata(dev);
>> +	return d->ops->write_word(dev, reg, data);
>> +}
>> +
>> +static int adt7410_read_byte(struct device *dev, u8 reg, u8 *data)
>> +{
>> +	struct adt7410_data *d = dev_get_drvdata(dev);
>> +	return d->ops->read_byte(dev, reg, data);
>> +}
>> +
>> +static int adt7410_write_byte(struct device *dev, u8 reg, u8 data)
>> +{
>> +	struct adt7410_data *d = dev_get_drvdata(dev);
>> +	return d->ops->write_byte(dev, reg, data);
>> +}
>> +
>> +static const u8 ADT7410_REG_TEMP[4] = {
>> +	ADT7410_TEMPERATURE,		/* input */
>> +	ADT7410_T_ALARM_HIGH,		/* high */
>> +	ADT7410_T_ALARM_LOW,		/* low */
>> +	ADT7410_T_CRIT,			/* critical */
>> +};
>> +
>> +/*
>> + * adt7410 register access by I2C
>> + */
>> +static int adt7410_temp_ready(struct device *dev)
>> +{
>> +	int i, ret;
>> +	u8 status;
>> +
>> +	for (i = 0; i < 6; i++) {
>> +		ret = adt7410_read_byte(dev, ADT7410_STATUS, &status);
>> +		if (ret)
>> +			return ret;
>> +		if (!(status & ADT7410_STAT_NOT_RDY))
>> +			return 0;
>> +		msleep(60);
>> +	}
>> +	return -ETIMEDOUT;
>> +}
>> +
>> +static int adt7410_update_temp(struct device *dev)
>> +{
>> +	struct adt7410_data *data = dev_get_drvdata(dev);
>> +	int ret = 0;
>> +
>> +	mutex_lock(&data->update_lock);
>> +
>> +	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
>> +	    || !data->valid) {
>> +
>> +		dev_dbg(dev, "Starting update\n");
>> +
>> +		ret = adt7410_temp_ready(dev); /* check for new value */
>> +		if (ret)
>> +			goto abort;
>> +
>> +		ret = adt7410_read_word(dev, ADT7410_REG_TEMP[0],
>> +					&data->temp[0]);
>> +		if (ret) {
>> +			dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
>> +				ADT7410_REG_TEMP[0], ret);
>> +			goto abort;
>> +		}
>> +		data->last_updated = jiffies;
>> +		data->valid = true;
>> +	}
>> +
>> +abort:
>> +	mutex_unlock(&data->update_lock);
>> +	return ret;
>> +}
>> +
>> +static int adt7410_fill_cache(struct device *dev)
>> +{
>> +	struct adt7410_data *data = dev_get_drvdata(dev);
>> +	int ret;
>> +	int i;
>> +
>> +	for (i = 1; i < ARRAY_SIZE(data->temp); i++) {
>> +		ret = adt7410_read_word(dev, ADT7410_REG_TEMP[i],
>> +					&data->temp[i]);
>> +		if (ret) {
>> +			dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
>> +				ADT7410_REG_TEMP[0], ret);
>> +			return ret;
>> +		}
>> +	}
>> +
>> +	ret = adt7410_read_byte(dev, ADT7410_T_HYST, &data->hyst);
>> +	if (ret) {
>> +		dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
>> +				ADT7410_T_HYST, ret);
>> +		return ret;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static s16 ADT7410_TEMP_TO_REG(long temp)
>> +{
>> +	return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7410_TEMP_MIN,
>> +					       ADT7410_TEMP_MAX) * 128, 1000);
>> +}
>> +
>> +static int ADT7410_REG_TO_TEMP(struct adt7410_data *data, s16 reg)
>> +{
>> +	/* in 13 bit mode, bits 0-2 are status flags - mask them out */
>> +	if (!(data->config & ADT7410_RESOLUTION))
>> +		reg &= ADT7410_T13_VALUE_MASK;
>> +	/*
>> +	 * temperature is stored in twos complement format, in steps of
>> +	 * 1/128°C
>> +	 */
>> +	return DIV_ROUND_CLOSEST(reg * 1000, 128);
>> +}
>> +
>> +/*-----------------------------------------------------------------------*/
>> +
>> +/* sysfs attributes for hwmon */
>> +
>> +static ssize_t adt7410_show_temp(struct device *dev,
>> +				 struct device_attribute *da, char *buf)
>> +{
>> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
>> +	struct adt7410_data *data = dev_get_drvdata(dev);
>> +
>> +
>> +	if (attr->index == 0) {
>> +		int ret;
>> +
>> +		ret = adt7410_update_temp(dev);
>> +		if (ret)
>> +			return ret;
>> +	}
>> +
>> +	return sprintf(buf, "%d\n", ADT7410_REG_TO_TEMP(data,
>> +		       data->temp[attr->index]));
>> +}
>> +
>> +static ssize_t adt7410_set_temp(struct device *dev,
>> +				struct device_attribute *da,
>> +				const char *buf, size_t count)
>> +{
>> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
>> +	struct adt7410_data *data = dev_get_drvdata(dev);
>> +	int nr = attr->index;
>> +	long temp;
>> +	int ret;
>> +
>> +	ret = kstrtol(buf, 10, &temp);
>> +	if (ret)
>> +		return ret;
>> +
>> +	mutex_lock(&data->update_lock);
>> +	data->temp[nr] = ADT7410_TEMP_TO_REG(temp);
>> +	ret = adt7410_write_word(dev, ADT7410_REG_TEMP[nr], data->temp[nr]);
>> +	if (ret)
>> +		count = ret;
>> +	mutex_unlock(&data->update_lock);
>> +	return count;
>> +}
>> +
>> +static ssize_t adt7410_show_t_hyst(struct device *dev,
>> +				   struct device_attribute *da,
>> +				   char *buf)
>> +{
>> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
>> +	struct adt7410_data *data = dev_get_drvdata(dev);
>> +	int nr = attr->index;
>> +	int hyst;
>> +
>> +	hyst = (data->hyst & ADT7410_T_HYST_MASK) * 1000;
>> +
>> +	/*
>> +	 * hysteresis is stored as a 4 bit offset in the device, convert it
>> +	 * to an absolute value
>> +	 */
>> +	if (nr == 2)	/* min has positive offset, others have negative */
>> +		hyst = -hyst;
>> +	return sprintf(buf, "%d\n",
>> +		       ADT7410_REG_TO_TEMP(data, data->temp[nr]) - hyst);
>> +}
>> +
>> +static ssize_t adt7410_set_t_hyst(struct device *dev,
>> +				  struct device_attribute *da,
>> +				  const char *buf, size_t count)
>> +{
>> +	struct adt7410_data *data = dev_get_drvdata(dev);
>> +	int limit, ret;
>> +	long hyst;
>> +
>> +	ret = kstrtol(buf, 10, &hyst);
>> +	if (ret)
>> +		return ret;
>> +	/* convert absolute hysteresis value to a 4 bit delta value */
>> +	limit = ADT7410_REG_TO_TEMP(data, data->temp[1]);
>> +	hyst = clamp_val(hyst, ADT7410_TEMP_MIN, ADT7410_TEMP_MAX);
>> +	data->hyst = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000),
>> +				   0, ADT7410_T_HYST_MASK);
>> +	ret = adt7410_write_byte(dev, ADT7410_T_HYST, data->hyst);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return count;
>> +}
>> +
>> +static ssize_t adt7410_show_alarm(struct device *dev,
>> +				  struct device_attribute *da,
>> +				  char *buf)
>> +{
>> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
>> +	u8 status;
>> +	int ret;
>> +
>> +	ret = adt7410_read_byte(dev, ADT7410_STATUS, &status);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	return sprintf(buf, "%d\n", !!(status & attr->index));
>> +}
>> +
>> +static ssize_t adt7410_show_name(struct device *dev,
>> +				  struct device_attribute *da, char *buf)
>> +{
>> +	struct adt7410_data *data = dev_get_drvdata(dev);
>> +
>> +	return sprintf(buf, "%s\n", data->name);
>> +}
>> +
>> +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adt7410_show_temp, NULL, 0);
>> +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
>> +			  adt7410_show_temp, adt7410_set_temp, 1);
>> +static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
>> +			  adt7410_show_temp, adt7410_set_temp, 2);
>> +static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
>> +			  adt7410_show_temp, adt7410_set_temp, 3);
>> +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
>> +			  adt7410_show_t_hyst, adt7410_set_t_hyst, 1);
>> +static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO,
>> +			  adt7410_show_t_hyst, NULL, 2);
>> +static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO,
>> +			  adt7410_show_t_hyst, NULL, 3);
>> +static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, adt7410_show_alarm,
>> +			  NULL, ADT7410_STAT_T_LOW);
>> +static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adt7410_show_alarm,
>> +			  NULL, ADT7410_STAT_T_HIGH);
>> +static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, adt7410_show_alarm,
>> +			  NULL, ADT7410_STAT_T_CRIT);
>> +static DEVICE_ATTR(name, S_IRUGO, adt7410_show_name, NULL);
>> +
>> +static struct attribute *adt7410_attributes[] = {
>> +	&sensor_dev_attr_temp1_input.dev_attr.attr,
>> +	&sensor_dev_attr_temp1_max.dev_attr.attr,
>> +	&sensor_dev_attr_temp1_min.dev_attr.attr,
>> +	&sensor_dev_attr_temp1_crit.dev_attr.attr,
>> +	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
>> +	&sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
>> +	&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
>> +	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
>> +	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
>> +	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
>> +	NULL
>> +};
>> +
>> +static const struct attribute_group adt7410_group = {
>> +	.attrs = adt7410_attributes,
>> +};
>> +
>> +int adt7410_probe(struct device *dev, const char *name,
>> +	const struct adt7410_ops *ops)
>> +{
>> +	struct adt7410_data *data;
>> +	int ret;
>> +
>> +	data = devm_kzalloc(dev, sizeof(struct adt7410_data),
>> +			    GFP_KERNEL);
>> +	if (!data)
>> +		return -ENOMEM;
>> +
>> +	data->ops = ops;
>> +	data->name = name;
>> +
>> +	dev_set_drvdata(dev, data);
>> +	mutex_init(&data->update_lock);
>> +
>> +	/* configure as specified */
>> +	ret = adt7410_read_byte(dev, ADT7410_CONFIG, &data->oldconfig);
>> +	if (ret < 0) {
>> +		dev_dbg(dev, "Can't read config? %d\n", ret);
>> +		return ret;
>> +	}
>> +	/*
>> +	 * Set to 16 bit resolution, continous conversion and comparator mode.
>> +	 */
>> +	data->config = data->oldconfig;
>> +	data->config &= ~ADT7410_MODE_MASK;
>> +	data->config |= ADT7410_FULL | ADT7410_RESOLUTION | ADT7410_EVENT_MODE;
>> +	if (data->config != data->oldconfig) {
>> +		ret = adt7410_write_byte(dev, ADT7410_CONFIG, data->config);
>> +		if (ret)
>> +			return ret;
>> +	}
>> +	dev_dbg(dev, "Config %02x\n", data->config);
>> +
>> +	ret = adt7410_fill_cache(dev);
>> +	if (ret)
>> +		goto exit_restore;
>> +
>> +	/* Register sysfs hooks */
>> +	ret = sysfs_create_group(&dev->kobj, &adt7410_group);
>> +	if (ret)
>> +		goto exit_restore;
>> +
>> +	/*
>> +	 * The I2C device will already have it's own 'name' attribute, but for
>> +	 * the SPI device we need to register it. name will only be non NULL if
>> +	 * the device doesn't register the 'name' attribute on its own.
>> +	 */
>> +	if (name) {
>> +		ret = device_create_file(dev, &dev_attr_name);
>> +		if (ret)
>> +			goto exit_remove;
>> +	}
>> +
>> +	data->hwmon_dev = hwmon_device_register(dev);
>> +	if (IS_ERR(data->hwmon_dev)) {
>> +		ret = PTR_ERR(data->hwmon_dev);
>> +		goto exit_remove_name;
>> +	}
>> +
>> +	return 0;
>> +
>> +exit_remove_name:
>> +	if (name)
>> +		device_remove_file(dev, &dev_attr_name);
>> +exit_remove:
>> +	sysfs_remove_group(&dev->kobj, &adt7410_group);
>> +exit_restore:
>> +	adt7410_write_byte(dev, ADT7410_CONFIG, data->oldconfig);
>> +	return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(adt7410_probe);
>> +
>> +int adt7410_remove(struct device *dev)
>> +{
>> +	struct adt7410_data *data = dev_get_drvdata(dev);
>> +
>> +	hwmon_device_unregister(data->hwmon_dev);
>> +	if (data->name)
>> +		device_remove_file(dev, &dev_attr_name);
>> +	sysfs_remove_group(&dev->kobj, &adt7410_group);
>> +	if (data->oldconfig != data->config)
>> +		adt7410_write_byte(dev, ADT7410_CONFIG,
>> +					  data->oldconfig);
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(adt7410_remove);
>> +
>> +#ifdef CONFIG_PM_SLEEP
>> +
>> +static int adt7410_suspend(struct device *dev)
>> +{
>> +	struct adt7410_data *data = dev_get_drvdata(dev);
>> +
>> +	return adt7410_write_byte(dev, ADT7410_CONFIG,
>> +		data->config | ADT7410_PD);
>> +}
>> +
>> +static int adt7410_resume(struct device *dev)
>> +{
>> +	struct adt7410_data *data = dev_get_drvdata(dev);
>> +
>> +	return adt7410_write_byte(dev, ADT7410_CONFIG, data->config);
>> +}
>> +
>> +SIMPLE_DEV_PM_OPS(adt7410_dev_pm_ops, adt7410_suspend, adt7410_resume);
>> +EXPORT_SYMBOL_GPL(adt7410_dev_pm_ops);
>> +
>> +#endif /* CONFIG_PM_SLEEP */
>> +
>> +MODULE_AUTHOR("Hartmut Knaack");
>> +MODULE_DESCRIPTION("ADT7410 driver");
>> +MODULE_LICENSE("GPL");
>> diff --git a/drivers/hwmon/adt7x10.h b/drivers/hwmon/adt7x10.h
>> new file mode 100644
>> index 0000000..17c8053
>> --- /dev/null
>> +++ b/drivers/hwmon/adt7x10.h
>> @@ -0,0 +1,47 @@
>> +#ifndef __HWMON_ADT7410_H__
>> +#define __HWMON_ADT7410_H__
>> +
>> +#include <linux/types.h>
>> +
>> +/* ADT7410 registers definition */
>> +#define ADT7410_TEMPERATURE		0
>> +#define ADT7410_STATUS			2
>> +#define ADT7410_CONFIG			3
>> +#define ADT7410_T_ALARM_HIGH		4
>> +#define ADT7410_T_ALARM_LOW		6
>> +#define ADT7410_T_CRIT			8
>> +#define ADT7410_T_HYST			0xA
>> +#define ADT7410_ID			0xB
>> +
>> +/* ADT7310 registers definition */
>> +#define ADT7310_STATUS			0
>> +#define ADT7310_CONFIG			1
>> +#define ADT7310_TEMPERATURE		2
>> +#define ADT7310_ID			3
>> +#define ADT7310_T_CRIT			4
>> +#define ADT7310_T_HYST			5
>> +#define ADT7310_T_ALARM_HIGH		6
>> +#define ADT7310_T_ALARM_LOW		7
>> +
>> +struct device;
>> +
>> +struct adt7410_ops {
>> +	int (*read_word)(struct device *, u8 reg, u16 *data);
>> +	int (*write_word)(struct device *, u8 reg, u16 data);
>> +	int (*read_byte)(struct device *, u8 reg, u8 *data);
>> +	int (*write_byte)(struct device *, u8 reg, u8 data);
>> +};
>> +
>> +int adt7410_probe(struct device *dev, const char *name,
>> +	const struct adt7410_ops *ops);
>> +int adt7410_remove(struct device *dev);
>> +
>> +
>> +#ifdef CONFIG_PM_SLEEP
>> +extern const struct dev_pm_ops adt7410_dev_pm_ops;
>> +#define ADT7410_DEV_PM_OPS (&adt7410_dev_pm_ops)
>> +#else
>> +#define ADT7410_DEV_PM_OPS NULL
>> +#endif
>> +
>> +#endif
>> -- 
>> 1.8.0
>>
>>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* Re: [lm-sensors] [PATCH 7/9] hwmon: (adt7410) Add support for the adt7310/adt7320
@ 2013-02-16 16:04       ` Lars-Peter Clausen
  0 siblings, 0 replies; 56+ messages in thread
From: Lars-Peter Clausen @ 2013-02-16 16:04 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: Jean Delvare, Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio

On 02/15/2013 09:32 PM, Guenter Roeck wrote:
> On Fri, Feb 15, 2013 at 05:57:16PM +0100, Lars-Peter Clausen wrote:
>> The adt7310/adt7320 is the SPI version of the adt7410/adt7320. The register map
>> layout is a bit different, i.e. the register addresses differ between the two
>> variants, but the bit layouts of the individual registers are identical. So both
>> chip variants can easily be supported by the same driver. The issue of non
>> matching register address layouts is solved by a simple look-up table which
>> translates the I2C addresses to the SPI addresses.
>>
>> The patch moves the bulk of the adt7410 driver to a common module that will be
>> shared by the adt7410 and adt7310 drivers. This common module implements the
>> driver logic and uses a set of virtual functions to perform IO access. The
>> adt7410 and adt7310 driver modules provide proper implementations of these IO
>> accessor functions for I2C respective SPI.
>>
>> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
>> ---
>>  drivers/hwmon/Kconfig   |  20 ++
>>  drivers/hwmon/Makefile  |   2 +
>>  drivers/hwmon/adt7310.c | 160 ++++++++++++++++
>>  drivers/hwmon/adt7410.c | 472 ++++++-----------------------------------------
>>  drivers/hwmon/adt7x10.c | 476 ++++++++++++++++++++++++++++++++++++++++++++++++
>>  drivers/hwmon/adt7x10.h |  47 +++++
>>  6 files changed, 758 insertions(+), 419 deletions(-)
>>  create mode 100644 drivers/hwmon/adt7310.c
>>  create mode 100644 drivers/hwmon/adt7x10.c
>>  create mode 100644 drivers/hwmon/adt7x10.h
>>
>> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
>> index 89ac1cb..aaa14f4 100644
>> --- a/drivers/hwmon/Kconfig
>> +++ b/drivers/hwmon/Kconfig
>> @@ -179,9 +179,29 @@ config SENSORS_ADM9240
>>  	  This driver can also be built as a module.  If so, the module
>>  	  will be called adm9240.
>>  
>> +config SENSORS_ADT7X10
>> +	tristate
>> +	help
>> +	  This module contains common code shared by the ADT7310/ADT7320 and
>> +	  ADT7410/ADT7420 temperature monitoring chip drivers.
>> +
>> +	  If build as a module, the module will be called adt7x10.
>> +
>> +config SENSORS_ADT7310
>> +	tristate "Analog Devices ADT7310/ADT7320"
>> +	depends on SPI_MASTER
>> +	select SENSORS_ADT7X10
>> +	help
>> +	  If you say yes here you get support for the Analog Devices
>> +	  ADT7310 and ADT7320 temperature monitoring chips.
>> +
>> +	  This driver can also be built as a module. If so, the module
>> +	  will be called adt7310.
>> +
>>  config SENSORS_ADT7410
>>  	tristate "Analog Devices ADT7410/ADT7420"
>>  	depends on I2C
>> +	select SENSORS_ADT7X10
>>  	help
>>  	  If you say yes here you get support for the Analog Devices
>>  	  ADT7410 and ADT7420 temperature monitoring chips.
>> diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
>> index 8d6d97e..5d36a57 100644
>> --- a/drivers/hwmon/Makefile
>> +++ b/drivers/hwmon/Makefile
>> @@ -34,6 +34,8 @@ obj-$(CONFIG_SENSORS_ADM9240)	+= adm9240.o
>>  obj-$(CONFIG_SENSORS_ADS1015)	+= ads1015.o
>>  obj-$(CONFIG_SENSORS_ADS7828)	+= ads7828.o
>>  obj-$(CONFIG_SENSORS_ADS7871)	+= ads7871.o
>> +obj-$(CONFIG_SENSORS_ADT7X10)	+= adt7x10.o
>> +obj-$(CONFIG_SENSORS_ADT7310)	+= adt7310.o
>>  obj-$(CONFIG_SENSORS_ADT7410)	+= adt7410.o
>>  obj-$(CONFIG_SENSORS_ADT7411)	+= adt7411.o
>>  obj-$(CONFIG_SENSORS_ADT7462)	+= adt7462.o
>> diff --git a/drivers/hwmon/adt7310.c b/drivers/hwmon/adt7310.c
>> new file mode 100644
>> index 0000000..0483e6c
>> --- /dev/null
>> +++ b/drivers/hwmon/adt7310.c
>> @@ -0,0 +1,160 @@
>> +/*
>> + * ADT7310/ADT7310 digital temperature sensor driver
>> + *
>> + * Copyright 2010-2013 Analog Devices Inc.
>> + *   Author: Lars-Peter Clausen <lars@metafoo.de>
>> + *
>> + * Licensed under the GPL-2 or later.
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/spi/spi.h>
>> +
>> +#include "adt7x10.h"
>> +
>> +static const u8 adt7371_reg_table[] = {
>> +	[ADT7410_TEMPERATURE]   = ADT7310_TEMPERATURE,
>> +	[ADT7410_STATUS]	= ADT7310_STATUS,
>> +	[ADT7410_CONFIG]	= ADT7310_CONFIG,
>> +	[ADT7410_T_ALARM_HIGH]	= ADT7310_T_ALARM_HIGH,
>> +	[ADT7410_T_ALARM_LOW]	= ADT7310_T_ALARM_LOW,
>> +	[ADT7410_T_CRIT]	= ADT7310_T_CRIT,
>> +	[ADT7410_T_HYST]	= ADT7310_T_HYST,
>> +	[ADT7410_ID]		= ADT7310_ID,
>> +};
>> +
>> +#define ADT7310_CMD_REG_MASK			0x28
>> +#define ADT7310_CMD_REG_OFFSET			3
>> +#define ADT7310_CMD_READ			0x40
>> +#define ADT7310_CMD_CON_READ			0x4
>> +
>> +#define AD7310_COMMAND(reg) (adt7371_reg_table[(reg)] << ADT7310_CMD_REG_OFFSET)
>> +
>> +static int adt7310_spi_read_word(struct device *dev,
>> +	u8 reg, u16 *data)
> 
> I don't really like the approach of separating the return value from the error
> code, if both can be returned directly. There are two reasons: First, the code
> gets more complex, and second, the compiler tends to get confused under some
> conditions abd believe that the return value is not set. And I really don't want
> to have to deal with the resulting build warnings, after getting rid of pretty
> much all such warnings in the hwmon subsystem. So I'd really appreciate if you
> could rewrite this and the subsequent patches to return both error and value as
> function return values.
> 

I can change it, but I don't think that the current code will confuse the
compiler, the return value is set under all circumstances. And the code
actually gets slightly more complex by rewriting it. Most of the time we don't
want to store the result of the read operation on stack but rather somewhere else.

	ret = adt7410_read_word(dev, TEMP);
	if (ret < 0) {
		...
	}
	data->temp[0] = ret;

Without the change we can write it as:

	ret = adt7410_read_word(dev, TEMP, &data->temp[0])
	if (ret) {
		...
	}

The difference is not that big, so I won't argue over it if you prefer the
first version.

Thanks,
- Lars

>> +{
>> +	struct spi_device *spi = to_spi_device(dev);
>> +	u8 command = AD7310_COMMAND(reg);
>> +	int ret = 0;
>> +
>> +	command |= ADT7310_CMD_READ;
>> +	ret = spi_write(spi, &command, sizeof(command));
>> +	if (ret < 0) {
>> +		dev_err(dev, "SPI write command error\n");
>> +		return ret;
>> +	}
>> +
>> +	ret = spi_read(spi, (u8 *)data, sizeof(*data));
>> +	if (ret < 0) {
>> +		dev_err(dev, "SPI read word error\n");
>> +		return ret;
>> +	}
>> +
>> +	*data = be16_to_cpu(*data);
>> +
>> +	return 0;
>> +}
>> +
>> +static int adt7310_spi_write_word(struct device *dev, u8 reg,
>> +	u16 data)
>> +{
>> +	struct spi_device *spi = to_spi_device(dev);
>> +	u8 buf[3];
>> +	int ret = 0;
>> +
>> +	buf[0] = AD7310_COMMAND(reg);
>> +	buf[1] = (u8)(data >> 8);
>> +	buf[2] = (u8)(data & 0xFF);
>> +
>> +	ret = spi_write(spi, buf, 3);
>> +	if (ret < 0) {
>> +		dev_err(dev, "SPI write word error\n");
>> +		return ret;
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> +static int adt7310_spi_read_byte(struct device *dev, u8 reg,
>> +	u8 *data)
>> +{
>> +	struct spi_device *spi = to_spi_device(dev);
>> +	u8 command = AD7310_COMMAND(reg);
>> +	int ret = 0;
>> +
>> +	command |= ADT7310_CMD_READ;
>> +	ret = spi_write(spi, &command, sizeof(command));
>> +	if (ret < 0) {
>> +		dev_err(dev, "SPI write command error\n");
>> +		return ret;
>> +	}
>> +
>> +	ret = spi_read(spi, data, sizeof(*data));
>> +	if (ret < 0) {
>> +		dev_err(dev, "SPI read byte error\n");
>> +		return ret;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int adt7310_spi_write_byte(struct device *dev, u8 reg,
>> +	u8 data)
>> +{
>> +	struct spi_device *spi = to_spi_device(dev);
>> +	u8 buf[2];
>> +	int ret = 0;
>> +
>> +	buf[0] = AD7310_COMMAND(reg);
>> +	buf[1] = data;
>> +
>> +	ret = spi_write(spi, buf, 2);
>> +	if (ret < 0) {
>> +		dev_err(dev, "SPI write byte error\n");
>> +		return ret;
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> +static const struct adt7410_ops adt7310_spi_ops = {
>> +	.read_word = adt7310_spi_read_word,
>> +	.write_word = adt7310_spi_write_word,
>> +	.read_byte = adt7310_spi_read_byte,
>> +	.write_byte = adt7310_spi_write_byte,
>> +};
>> +
>> +static int adt7310_spi_probe(struct spi_device *spi)
>> +{
>> +	return adt7410_probe(&spi->dev, spi_get_device_id(spi)->name,
>> +			&adt7310_spi_ops);
>> +}
>> +
>> +static int adt7310_spi_remove(struct spi_device *spi)
>> +{
>> +	return adt7410_remove(&spi->dev);
>> +}
>> +
>> +static const struct spi_device_id adt7310_id[] = {
>> +	{ "adt7310", 0 },
>> +	{ "adt7320", 0 },
>> +	{}
>> +};
>> +MODULE_DEVICE_TABLE(spi, adt7310_id);
>> +
>> +static struct spi_driver adt7310_driver = {
>> +	.driver = {
>> +		.name = "adt7310",
>> +		.owner = THIS_MODULE,
>> +		.pm	= ADT7410_DEV_PM_OPS,
>> +	},
>> +	.probe = adt7310_spi_probe,
>> +	.remove = adt7310_spi_remove,
>> +	.id_table = adt7310_id,
>> +};
>> +module_spi_driver(adt7310_driver);
>> +
>> +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
>> +MODULE_DESCRIPTION("ADT7310/ADT7420 driver");
>> +MODULE_LICENSE("GPL");
>> diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
>> index 5de0376..13734c5 100644
>> --- a/drivers/hwmon/adt7410.c
>> +++ b/drivers/hwmon/adt7410.c
>> @@ -1,483 +1,117 @@
>>  /*
>> - * adt7410.c - Part of lm_sensors, Linux kernel modules for hardware
>> - *	 monitoring
>> - * This driver handles the ADT7410 and compatible digital temperature sensors.
>> - * Hartmut Knaack <knaack.h@gmx.de> 2012-07-22
>> - * based on lm75.c by Frodo Looijaard <frodol@dds.nl>
>> - * and adt7410.c from iio-staging by Sonic Zhang <sonic.zhang@analog.com>
>> + * ADT7410/ADT7420 digital temperature sensor driver
>>   *
>> - * This program is free software; you can redistribute it and/or modify
>> - * it under the terms of the GNU General Public License as published by
>> - * the Free Software Foundation; either version 2 of the License, or
>> - * (at your option) any later version.
>> + * Copyright 2010-2013 Analog Devices Inc.
>> + *   Author: Lars-Peter Clausen <lars@metafoo.de>
>>   *
>> - * This program is distributed in the hope that it will be useful,
>> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> - * GNU General Public License for more details.
>> - *
>> - * You should have received a copy of the GNU General Public License
>> - * along with this program; if not, write to the Free Software
>> - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
>> + * Licensed under the GPL-2 or later.
>>   */
>>  
>>  #include <linux/module.h>
>>  #include <linux/init.h>
>> -#include <linux/slab.h>
>> -#include <linux/jiffies.h>
>>  #include <linux/i2c.h>
>> -#include <linux/hwmon.h>
>> -#include <linux/hwmon-sysfs.h>
>> -#include <linux/err.h>
>> -#include <linux/mutex.h>
>> -#include <linux/delay.h>
>> -
>> -/*
>> - * ADT7410 registers definition
>> - */
>>  
>> -#define ADT7410_TEMPERATURE		0
>> -#define ADT7410_STATUS			2
>> -#define ADT7410_CONFIG			3
>> -#define ADT7410_T_ALARM_HIGH		4
>> -#define ADT7410_T_ALARM_LOW		6
>> -#define ADT7410_T_CRIT			8
>> -#define ADT7410_T_HYST			0xA
>> +#include "adt7x10.h"
>>  
>> -/*
>> - * ADT7410 status
>> - */
>> -#define ADT7410_STAT_T_LOW		(1 << 4)
>> -#define ADT7410_STAT_T_HIGH		(1 << 5)
>> -#define ADT7410_STAT_T_CRIT		(1 << 6)
>> -#define ADT7410_STAT_NOT_RDY		(1 << 7)
>> -
>> -/*
>> - * ADT7410 config
>> - */
>> -#define ADT7410_FAULT_QUEUE_MASK	(1 << 0 | 1 << 1)
>> -#define ADT7410_CT_POLARITY		(1 << 2)
>> -#define ADT7410_INT_POLARITY		(1 << 3)
>> -#define ADT7410_EVENT_MODE		(1 << 4)
>> -#define ADT7410_MODE_MASK		(1 << 5 | 1 << 6)
>> -#define ADT7410_FULL			(0 << 5 | 0 << 6)
>> -#define ADT7410_PD			(1 << 5 | 1 << 6)
>> -#define ADT7410_RESOLUTION		(1 << 7)
>> -
>> -/*
>> - * ADT7410 masks
>> - */
>> -#define ADT7410_T13_VALUE_MASK			0xFFF8
>> -#define ADT7410_T_HYST_MASK			0xF
>> -
>> -/* straight from the datasheet */
>> -#define ADT7410_TEMP_MIN (-55000)
>> -#define ADT7410_TEMP_MAX 150000
>> -
>> -enum adt7410_type {		/* keep sorted in alphabetical order */
>> -	adt7410,
>> -};
>> -
>> -static const u8 ADT7410_REG_TEMP[4] = {
>> -	ADT7410_TEMPERATURE,		/* input */
>> -	ADT7410_T_ALARM_HIGH,		/* high */
>> -	ADT7410_T_ALARM_LOW,		/* low */
>> -	ADT7410_T_CRIT,			/* critical */
>> -};
>> -
>> -/* Each client has this additional data */
>> -struct adt7410_data {
>> -	struct device		*hwmon_dev;
>> -	struct mutex		update_lock;
>> -	u8			config;
>> -	u8			oldconfig;
>> -	bool			valid;		/* true if registers valid */
>> -	unsigned long		last_updated;	/* In jiffies */
>> -	s16			temp[4];	/* Register values,
>> -						   0 = input
>> -						   1 = high
>> -						   2 = low
>> -						   3 = critical */
>> -	u8			hyst;		/* hysteresis offset */
>> -};
>> -
>> -/*
>> - * adt7410 register access by I2C
>> - */
>> -static int adt7410_temp_ready(struct i2c_client *client)
>> -{
>> -	int i, status;
>> -
>> -	for (i = 0; i < 6; i++) {
>> -		status = i2c_smbus_read_byte_data(client, ADT7410_STATUS);
>> -		if (status < 0)
>> -			return status;
>> -		if (!(status & ADT7410_STAT_NOT_RDY))
>> -			return 0;
>> -		msleep(60);
>> -	}
>> -	return -ETIMEDOUT;
>> -}
>> -
>> -static int adt7410_update_temp(struct device *dev)
>> +static int adt7410_i2c_read_word(struct device *dev, u8 reg, u16 *data)
>>  {
>>  	struct i2c_client *client = to_i2c_client(dev);
>> -	struct adt7410_data *data = i2c_get_clientdata(client);
>>  	int ret = 0;
>>  
>> -	mutex_lock(&data->update_lock);
>> -
>> -	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
>> -	    || !data->valid) {
>> -
>> -		dev_dbg(&client->dev, "Starting update\n");
>> -
>> -		ret = adt7410_temp_ready(client); /* check for new value */
>> -		if (ret)
>> -			goto abort;
>> -
>> -		ret = i2c_smbus_read_word_swapped(client, ADT7410_REG_TEMP[0]);
>> -		if (ret) {
>> -			dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
>> -				ADT7410_REG_TEMP[0], ret);
>> -			goto abort;
>> -		}
>> -		data->temp[0] = ret;
>> -
>> -		data->last_updated = jiffies;
>> -		data->valid = true;
>> -	}
>> -
>> -abort:
>> -	mutex_unlock(&data->update_lock);
>> -	return ret;
>> -}
>> -
>> -static int adt7410_fill_cache(struct i2c_client *client)
>> -{
>> -	struct adt7410_data *data = i2c_get_clientdata(client);
>> -	int ret;
>> -	int i;
>> -
>> -	for (i = 1; i < 3; i++) {
>> -		ret = i2c_smbus_read_word_swapped(client, ADT7410_REG_TEMP[i]);
>> -		if (ret) {
>> -			dev_dbg(&client->dev,
>> -				"Failed to read value: reg %d, error %d\n",
>> -				ADT7410_REG_TEMP[0], ret);
>> -			return ret;
>> -		}
>> -		data->temp[i] = ret;
>> -	}
>> -
>> -	ret = i2c_smbus_read_byte_data(client, ADT7410_T_HYST);
>> -	if (ret) {
>> -		dev_dbg(&client->dev,
>> -			"Failed to read value: hyst reg, error %d\n",
>> -			ret);
>> +	ret = i2c_smbus_read_word_swapped(client, reg);
>> +	if (ret < 0) {
>> +		dev_err(dev, "I2C read error\n");
>>  		return ret;
>>  	}
>> -	data->hyst = ret;
>> -
>> -	return 0;
>> -}
>>  
>> -static s16 ADT7410_TEMP_TO_REG(long temp)
>> -{
>> -	return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7410_TEMP_MIN,
>> -					   ADT7410_TEMP_MAX) * 128, 1000);
>> -}
>> +	*data = ret;
>>  
>> -static int ADT7410_REG_TO_TEMP(struct adt7410_data *data, s16 reg)
>> -{
>> -	/* in 13 bit mode, bits 0-2 are status flags - mask them out */
>> -	if (!(data->config & ADT7410_RESOLUTION))
>> -		reg &= ADT7410_T13_VALUE_MASK;
>> -	/*
>> -	 * temperature is stored in twos complement format, in steps of
>> -	 * 1/128°C
>> -	 */
>> -	return DIV_ROUND_CLOSEST(reg * 1000, 128);
>> +	return 0;
>>  }
>>  
>> -/*-----------------------------------------------------------------------*/
>> -
>> -/* sysfs attributes for hwmon */
>> -
>> -static ssize_t adt7410_show_temp(struct device *dev,
>> -				 struct device_attribute *da, char *buf)
>> +static int adt7410_i2c_write_word(struct device *dev, u8 reg, u16 data)
>>  {
>> -	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
>>  	struct i2c_client *client = to_i2c_client(dev);
>> -	struct adt7410_data *data = i2c_get_clientdata(client);
>> -
>> -	if (attr->index == 0) {
>> -		int ret;
>> +	int ret = 0;
>>  
>> -		ret = adt7410_update_temp(dev);
>> -		if (ret)
>> -			return ret;
>> -	}
>> +	ret = i2c_smbus_write_word_swapped(client, reg, data);
>> +	if (ret < 0)
>> +		dev_err(dev, "I2C write error\n");
>>  
>> -	return sprintf(buf, "%d\n", ADT7410_REG_TO_TEMP(data,
>> -		       data->temp[attr->index]));
>> +	return ret;
>>  }
>>  
>> -static ssize_t adt7410_set_temp(struct device *dev,
>> -				struct device_attribute *da,
>> -				const char *buf, size_t count)
>> +static int adt7410_i2c_read_byte(struct device *dev, u8 reg, u8 *data)
>>  {
>> -	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
>>  	struct i2c_client *client = to_i2c_client(dev);
>> -	struct adt7410_data *data = i2c_get_clientdata(client);
>> -	int nr = attr->index;
>> -	long temp;
>> -	int ret;
>> +	int ret = 0;
>>  
>> -	ret = kstrtol(buf, 10, &temp);
>> -	if (ret)
>> +	ret = i2c_smbus_read_byte_data(client, reg);
>> +	if (ret < 0) {
>> +		dev_err(dev, "I2C read error\n");
>>  		return ret;
>> +	}
>>  
>> -	mutex_lock(&data->update_lock);
>> -	data->temp[nr] = ADT7410_TEMP_TO_REG(temp);
>> -	ret = i2c_smbus_write_word_swapped(client, ADT7410_REG_TEMP[nr],
>> -					   data->temp[nr]);
>> -	if (ret)
>> -		count = ret;
>> -	mutex_unlock(&data->update_lock);
>> -	return count;
>> -}
>> -
>> -static ssize_t adt7410_show_t_hyst(struct device *dev,
>> -				   struct device_attribute *da,
>> -				   char *buf)
>> -{
>> -	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
>> -	struct i2c_client *client = to_i2c_client(dev);
>> -	struct adt7410_data *data = i2c_get_clientdata(client);
>> -	int nr = attr->index;
>> -	int hyst;
>> -
>> -	hyst = (data->hyst & ADT7410_T_HYST_MASK) * 1000;
>> -
>> -	/*
>> -	 * hysteresis is stored as a 4 bit offset in the device, convert it
>> -	 * to an absolute value
>> -	 */
>> -	if (nr == 2)	/* min has positive offset, others have negative */
>> -		hyst = -hyst;
>> -	return sprintf(buf, "%d\n",
>> -		       ADT7410_REG_TO_TEMP(data, data->temp[nr]) - hyst);
>> -}
>> -
>> -static ssize_t adt7410_set_t_hyst(struct device *dev,
>> -				  struct device_attribute *da,
>> -				  const char *buf, size_t count)
>> -{
>> -	struct i2c_client *client = to_i2c_client(dev);
>> -	struct adt7410_data *data = i2c_get_clientdata(client);
>> -	int limit, ret;
>> -	long hyst;
>> -
>> -	ret = kstrtol(buf, 10, &hyst);
>> -	if (ret)
>> -		return ret;
>> -	/* convert absolute hysteresis value to a 4 bit delta value */
>> -	limit = ADT7410_REG_TO_TEMP(data, data->temp[1]);
>> -	hyst = clamp_val(hyst, ADT7410_TEMP_MIN, ADT7410_TEMP_MAX);
>> -	data->hyst = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000), 0,
>> -			       ADT7410_T_HYST_MASK);
>> -	ret = i2c_smbus_write_byte_data(client, ADT7410_T_HYST, data->hyst);
>> -	if (ret)
>> -		return ret;
>> +	*data = (u8)ret;
>>  
>> -	return count;
>> +	return 0;
>>  }
>>  
>> -static ssize_t adt7410_show_alarm(struct device *dev,
>> -				  struct device_attribute *da,
>> -				  char *buf)
>> +static int adt7410_i2c_write_byte(struct device *dev, u8 reg, u8 data)
>>  {
>>  	struct i2c_client *client = to_i2c_client(dev);
>> -	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
>> -	int ret;
>> +	int ret = 0;
>>  
>> -	ret = i2c_smbus_read_byte_data(client, ADT7410_STATUS);
>> +	ret = i2c_smbus_write_byte_data(client, reg, data);
>>  	if (ret < 0)
>> -		return ret;
>> +		dev_err(&client->dev, "I2C write error\n");
>>  
>> -	return sprintf(buf, "%d\n", !!(ret & attr->index));
>> +	return ret;
>>  }
>>  
>> -static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adt7410_show_temp, NULL, 0);
>> -static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
>> -			  adt7410_show_temp, adt7410_set_temp, 1);
>> -static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
>> -			  adt7410_show_temp, adt7410_set_temp, 2);
>> -static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
>> -			  adt7410_show_temp, adt7410_set_temp, 3);
>> -static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
>> -			  adt7410_show_t_hyst, adt7410_set_t_hyst, 1);
>> -static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO,
>> -			  adt7410_show_t_hyst, NULL, 2);
>> -static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO,
>> -			  adt7410_show_t_hyst, NULL, 3);
>> -static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, adt7410_show_alarm,
>> -			  NULL, ADT7410_STAT_T_LOW);
>> -static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adt7410_show_alarm,
>> -			  NULL, ADT7410_STAT_T_HIGH);
>> -static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, adt7410_show_alarm,
>> -			  NULL, ADT7410_STAT_T_CRIT);
>> -
>> -static struct attribute *adt7410_attributes[] = {
>> -	&sensor_dev_attr_temp1_input.dev_attr.attr,
>> -	&sensor_dev_attr_temp1_max.dev_attr.attr,
>> -	&sensor_dev_attr_temp1_min.dev_attr.attr,
>> -	&sensor_dev_attr_temp1_crit.dev_attr.attr,
>> -	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
>> -	&sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
>> -	&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
>> -	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
>> -	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
>> -	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
>> -	NULL
>> -};
>> -
>> -static const struct attribute_group adt7410_group = {
>> -	.attrs = adt7410_attributes,
>> +static const struct adt7410_ops adt7410_i2c_ops = {
>> +	.read_word = adt7410_i2c_read_word,
>> +	.write_word = adt7410_i2c_write_word,
>> +	.read_byte = adt7410_i2c_read_byte,
>> +	.write_byte = adt7410_i2c_write_byte,
>>  };
>>  
>> -/*-----------------------------------------------------------------------*/
>> -
>> -/* device probe and removal */
>> -
>> -static int adt7410_probe(struct i2c_client *client,
>> -			 const struct i2c_device_id *id)
>> +static int adt7410_i2c_probe(struct i2c_client *client,
>> +	const struct i2c_device_id *id)
>>  {
>> -	struct adt7410_data *data;
>> -	int ret;
>>  
>>  	if (!i2c_check_functionality(client->adapter,
>>  			I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
>>  		return -ENODEV;
>>  
>> -	data = devm_kzalloc(&client->dev, sizeof(struct adt7410_data),
>> -			    GFP_KERNEL);
>> -	if (!data)
>> -		return -ENOMEM;
>> -
>> -	i2c_set_clientdata(client, data);
>> -	mutex_init(&data->update_lock);
>> -
>> -	/* configure as specified */
>> -	ret = i2c_smbus_read_byte_data(client, ADT7410_CONFIG);
>> -	if (ret < 0) {
>> -		dev_dbg(&client->dev, "Can't read config? %d\n", ret);
>> -		return ret;
>> -	}
>> -	data->oldconfig = ret;
>> -	/*
>> -	 * Set to 16 bit resolution, continous conversion and comparator mode.
>> -	 */
>> -	ret &= ~ADT7410_MODE_MASK;
>> -	data->config = ret | ADT7410_FULL | ADT7410_RESOLUTION |
>> -			ADT7410_EVENT_MODE;
>> -	if (data->config != data->oldconfig) {
>> -		ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
>> -						data->config);
>> -		if (ret)
>> -			return ret;
>> -	}
>> -	dev_dbg(&client->dev, "Config %02x\n", data->config);
>> -
>> -	ret = adt7410_fill_cache(client);
>> -	if (ret)
>> -		goto exit_restore;
>> -
>> -	/* Register sysfs hooks */
>> -	ret = sysfs_create_group(&client->dev.kobj, &adt7410_group);
>> -	if (ret)
>> -		goto exit_restore;
>> -
>> -	data->hwmon_dev = hwmon_device_register(&client->dev);
>> -	if (IS_ERR(data->hwmon_dev)) {
>> -		ret = PTR_ERR(data->hwmon_dev);
>> -		goto exit_remove;
>> -	}
>> -
>> -	dev_info(&client->dev, "sensor '%s'\n", client->name);
>> -
>> -	return 0;
>> -
>> -exit_remove:
>> -	sysfs_remove_group(&client->dev.kobj, &adt7410_group);
>> -exit_restore:
>> -	i2c_smbus_write_byte_data(client, ADT7410_CONFIG, data->oldconfig);
>> -	return ret;
>> +	return adt7410_probe(&client->dev, NULL, &adt7410_i2c_ops);
>>  }
>>  
>> -static int adt7410_remove(struct i2c_client *client)
>> +static int adt7410_i2c_remove(struct i2c_client *client)
>>  {
>> -	struct adt7410_data *data = i2c_get_clientdata(client);
>> -
>> -	hwmon_device_unregister(data->hwmon_dev);
>> -	sysfs_remove_group(&client->dev.kobj, &adt7410_group);
>> -	if (data->oldconfig != data->config)
>> -		i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
>> -					  data->oldconfig);
>> -	return 0;
>> +	return adt7410_remove(&client->dev);
>>  }
>>  
>> -static const struct i2c_device_id adt7410_ids[] = {
>> -	{ "adt7410", adt7410, },
>> -	{ "adt7420", adt7410, },
>> -	{ /* LIST END */ }
>> +static const struct i2c_device_id adt7410_id[] = {
>> +	{ "adt7410", 0 },
>> +	{ "adt7420", 0 },
>> +	{}
>>  };
>> -MODULE_DEVICE_TABLE(i2c, adt7410_ids);
>> -
>> -#ifdef CONFIG_PM_SLEEP
>> -static int adt7410_suspend(struct device *dev)
>> -{
>> -	int ret;
>> -	struct i2c_client *client = to_i2c_client(dev);
>> -	struct adt7410_data *data = i2c_get_clientdata(client);
>> -
>> -	ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
>> -					data->config | ADT7410_PD);
>> -	return ret;
>> -}
>> -
>> -static int adt7410_resume(struct device *dev)
>> -{
>> -	int ret;
>> -	struct i2c_client *client = to_i2c_client(dev);
>> -	struct adt7410_data *data = i2c_get_clientdata(client);
>> -
>> -	ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG, data->config);
>> -	return ret;
>> -}
>> -
>> -static SIMPLE_DEV_PM_OPS(adt7410_dev_pm_ops, adt7410_suspend, adt7410_resume);
>> -
>> -#define ADT7410_DEV_PM_OPS (&adt7410_dev_pm_ops)
>> -#else
>> -#define ADT7410_DEV_PM_OPS NULL
>> -#endif /* CONFIG_PM */
>> +MODULE_DEVICE_TABLE(i2c, adt7410_id);
>>  
>>  static struct i2c_driver adt7410_driver = {
>> -	.class		= I2C_CLASS_HWMON,
>>  	.driver = {
>> -		.name	= "adt7410",
>> +		.name = "adt7410",
>>  		.pm	= ADT7410_DEV_PM_OPS,
>>  	},
>> -	.probe		= adt7410_probe,
>> -	.remove		= adt7410_remove,
>> -	.id_table	= adt7410_ids,
>> -	.address_list	= I2C_ADDRS(0x48, 0x49, 0x4a, 0x4b),
>> +	.probe = adt7410_i2c_probe,
>> +	.remove = adt7410_i2c_remove,
>> +	.id_table = adt7410_id,
>> +	.address_list = I2C_ADDRS(0x48, 0x49, 0x4a, 0x4b),
>> +	.class = I2C_CLASS_HWMON,
>>  };
>> -
>>  module_i2c_driver(adt7410_driver);
>>  
>> -MODULE_AUTHOR("Hartmut Knaack");
>> -MODULE_DESCRIPTION("ADT7410/ADT7420 driver");
>> +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
>> +MODULE_DESCRIPTION("ADT7410/AD7420 driver");
>>  MODULE_LICENSE("GPL");
>> diff --git a/drivers/hwmon/adt7x10.c b/drivers/hwmon/adt7x10.c
>> new file mode 100644
>> index 0000000..2598aaf
>> --- /dev/null
>> +++ b/drivers/hwmon/adt7x10.c
>> @@ -0,0 +1,476 @@
>> +/*
>> + * adt7410.c - Part of lm_sensors, Linux kernel modules for hardware
>> + *	 monitoring
>> + * This driver handles the ADT7410 and compatible digital temperature sensors.
>> + * Hartmut Knaack <knaack.h@gmx.de> 2012-07-22
>> + * based on lm75.c by Frodo Looijaard <frodol@dds.nl>
>> + * and adt7410.c from iio-staging by Sonic Zhang <sonic.zhang@analog.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, write to the Free Software
>> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/slab.h>
>> +#include <linux/jiffies.h>
>> +#include <linux/hwmon.h>
>> +#include <linux/hwmon-sysfs.h>
>> +#include <linux/err.h>
>> +#include <linux/mutex.h>
>> +#include <linux/delay.h>
>> +
>> +#include "adt7x10.h"
>> +
>> +/*
>> + * ADT7410 status
>> + */
>> +#define ADT7410_STAT_T_LOW		(1 << 4)
>> +#define ADT7410_STAT_T_HIGH		(1 << 5)
>> +#define ADT7410_STAT_T_CRIT		(1 << 6)
>> +#define ADT7410_STAT_NOT_RDY		(1 << 7)
>> +
>> +/*
>> + * ADT7410 config
>> + */
>> +#define ADT7410_FAULT_QUEUE_MASK	(1 << 0 | 1 << 1)
>> +#define ADT7410_CT_POLARITY		(1 << 2)
>> +#define ADT7410_INT_POLARITY		(1 << 3)
>> +#define ADT7410_EVENT_MODE		(1 << 4)
>> +#define ADT7410_MODE_MASK		(1 << 5 | 1 << 6)
>> +#define ADT7410_FULL			(0 << 5 | 0 << 6)
>> +#define ADT7410_PD			(1 << 5 | 1 << 6)
>> +#define ADT7410_RESOLUTION		(1 << 7)
>> +
>> +/*
>> + * ADT7410 masks
>> + */
>> +#define ADT7410_T13_VALUE_MASK			0xFFF8
>> +#define ADT7410_T_HYST_MASK			0xF
>> +
>> +/* straight from the datasheet */
>> +#define ADT7410_TEMP_MIN (-55000)
>> +#define ADT7410_TEMP_MAX 150000
>> +
>> +/* Each client has this additional data */
>> +struct adt7410_data {
>> +	const struct adt7410_ops *ops;
>> +	const char		*name;
>> +	struct device		*hwmon_dev;
>> +	struct mutex		update_lock;
>> +	u8			config;
>> +	u8			oldconfig;
>> +	bool			valid;		/* true if registers valid */
>> +	unsigned long		last_updated;	/* In jiffies */
>> +	s16			temp[4];	/* Register values,
>> +						   0 = input
>> +						   1 = high
>> +						   2 = low
>> +						   3 = critical */
>> +	u8			hyst;		/* hysteresis offset */
>> +};
>> +
>> +static int adt7410_read_word(struct device *dev, u8 reg, u16 *data)
>> +{
>> +	struct adt7410_data *d = dev_get_drvdata(dev);
>> +	return d->ops->read_word(dev, reg, data);
>> +}
>> +
>> +static int adt7410_write_word(struct device *dev, u8 reg, u16 data)
>> +{
>> +	struct adt7410_data *d = dev_get_drvdata(dev);
>> +	return d->ops->write_word(dev, reg, data);
>> +}
>> +
>> +static int adt7410_read_byte(struct device *dev, u8 reg, u8 *data)
>> +{
>> +	struct adt7410_data *d = dev_get_drvdata(dev);
>> +	return d->ops->read_byte(dev, reg, data);
>> +}
>> +
>> +static int adt7410_write_byte(struct device *dev, u8 reg, u8 data)
>> +{
>> +	struct adt7410_data *d = dev_get_drvdata(dev);
>> +	return d->ops->write_byte(dev, reg, data);
>> +}
>> +
>> +static const u8 ADT7410_REG_TEMP[4] = {
>> +	ADT7410_TEMPERATURE,		/* input */
>> +	ADT7410_T_ALARM_HIGH,		/* high */
>> +	ADT7410_T_ALARM_LOW,		/* low */
>> +	ADT7410_T_CRIT,			/* critical */
>> +};
>> +
>> +/*
>> + * adt7410 register access by I2C
>> + */
>> +static int adt7410_temp_ready(struct device *dev)
>> +{
>> +	int i, ret;
>> +	u8 status;
>> +
>> +	for (i = 0; i < 6; i++) {
>> +		ret = adt7410_read_byte(dev, ADT7410_STATUS, &status);
>> +		if (ret)
>> +			return ret;
>> +		if (!(status & ADT7410_STAT_NOT_RDY))
>> +			return 0;
>> +		msleep(60);
>> +	}
>> +	return -ETIMEDOUT;
>> +}
>> +
>> +static int adt7410_update_temp(struct device *dev)
>> +{
>> +	struct adt7410_data *data = dev_get_drvdata(dev);
>> +	int ret = 0;
>> +
>> +	mutex_lock(&data->update_lock);
>> +
>> +	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
>> +	    || !data->valid) {
>> +
>> +		dev_dbg(dev, "Starting update\n");
>> +
>> +		ret = adt7410_temp_ready(dev); /* check for new value */
>> +		if (ret)
>> +			goto abort;
>> +
>> +		ret = adt7410_read_word(dev, ADT7410_REG_TEMP[0],
>> +					&data->temp[0]);
>> +		if (ret) {
>> +			dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
>> +				ADT7410_REG_TEMP[0], ret);
>> +			goto abort;
>> +		}
>> +		data->last_updated = jiffies;
>> +		data->valid = true;
>> +	}
>> +
>> +abort:
>> +	mutex_unlock(&data->update_lock);
>> +	return ret;
>> +}
>> +
>> +static int adt7410_fill_cache(struct device *dev)
>> +{
>> +	struct adt7410_data *data = dev_get_drvdata(dev);
>> +	int ret;
>> +	int i;
>> +
>> +	for (i = 1; i < ARRAY_SIZE(data->temp); i++) {
>> +		ret = adt7410_read_word(dev, ADT7410_REG_TEMP[i],
>> +					&data->temp[i]);
>> +		if (ret) {
>> +			dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
>> +				ADT7410_REG_TEMP[0], ret);
>> +			return ret;
>> +		}
>> +	}
>> +
>> +	ret = adt7410_read_byte(dev, ADT7410_T_HYST, &data->hyst);
>> +	if (ret) {
>> +		dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
>> +				ADT7410_T_HYST, ret);
>> +		return ret;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static s16 ADT7410_TEMP_TO_REG(long temp)
>> +{
>> +	return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7410_TEMP_MIN,
>> +					       ADT7410_TEMP_MAX) * 128, 1000);
>> +}
>> +
>> +static int ADT7410_REG_TO_TEMP(struct adt7410_data *data, s16 reg)
>> +{
>> +	/* in 13 bit mode, bits 0-2 are status flags - mask them out */
>> +	if (!(data->config & ADT7410_RESOLUTION))
>> +		reg &= ADT7410_T13_VALUE_MASK;
>> +	/*
>> +	 * temperature is stored in twos complement format, in steps of
>> +	 * 1/128°C
>> +	 */
>> +	return DIV_ROUND_CLOSEST(reg * 1000, 128);
>> +}
>> +
>> +/*-----------------------------------------------------------------------*/
>> +
>> +/* sysfs attributes for hwmon */
>> +
>> +static ssize_t adt7410_show_temp(struct device *dev,
>> +				 struct device_attribute *da, char *buf)
>> +{
>> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
>> +	struct adt7410_data *data = dev_get_drvdata(dev);
>> +
>> +
>> +	if (attr->index == 0) {
>> +		int ret;
>> +
>> +		ret = adt7410_update_temp(dev);
>> +		if (ret)
>> +			return ret;
>> +	}
>> +
>> +	return sprintf(buf, "%d\n", ADT7410_REG_TO_TEMP(data,
>> +		       data->temp[attr->index]));
>> +}
>> +
>> +static ssize_t adt7410_set_temp(struct device *dev,
>> +				struct device_attribute *da,
>> +				const char *buf, size_t count)
>> +{
>> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
>> +	struct adt7410_data *data = dev_get_drvdata(dev);
>> +	int nr = attr->index;
>> +	long temp;
>> +	int ret;
>> +
>> +	ret = kstrtol(buf, 10, &temp);
>> +	if (ret)
>> +		return ret;
>> +
>> +	mutex_lock(&data->update_lock);
>> +	data->temp[nr] = ADT7410_TEMP_TO_REG(temp);
>> +	ret = adt7410_write_word(dev, ADT7410_REG_TEMP[nr], data->temp[nr]);
>> +	if (ret)
>> +		count = ret;
>> +	mutex_unlock(&data->update_lock);
>> +	return count;
>> +}
>> +
>> +static ssize_t adt7410_show_t_hyst(struct device *dev,
>> +				   struct device_attribute *da,
>> +				   char *buf)
>> +{
>> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
>> +	struct adt7410_data *data = dev_get_drvdata(dev);
>> +	int nr = attr->index;
>> +	int hyst;
>> +
>> +	hyst = (data->hyst & ADT7410_T_HYST_MASK) * 1000;
>> +
>> +	/*
>> +	 * hysteresis is stored as a 4 bit offset in the device, convert it
>> +	 * to an absolute value
>> +	 */
>> +	if (nr == 2)	/* min has positive offset, others have negative */
>> +		hyst = -hyst;
>> +	return sprintf(buf, "%d\n",
>> +		       ADT7410_REG_TO_TEMP(data, data->temp[nr]) - hyst);
>> +}
>> +
>> +static ssize_t adt7410_set_t_hyst(struct device *dev,
>> +				  struct device_attribute *da,
>> +				  const char *buf, size_t count)
>> +{
>> +	struct adt7410_data *data = dev_get_drvdata(dev);
>> +	int limit, ret;
>> +	long hyst;
>> +
>> +	ret = kstrtol(buf, 10, &hyst);
>> +	if (ret)
>> +		return ret;
>> +	/* convert absolute hysteresis value to a 4 bit delta value */
>> +	limit = ADT7410_REG_TO_TEMP(data, data->temp[1]);
>> +	hyst = clamp_val(hyst, ADT7410_TEMP_MIN, ADT7410_TEMP_MAX);
>> +	data->hyst = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000),
>> +				   0, ADT7410_T_HYST_MASK);
>> +	ret = adt7410_write_byte(dev, ADT7410_T_HYST, data->hyst);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return count;
>> +}
>> +
>> +static ssize_t adt7410_show_alarm(struct device *dev,
>> +				  struct device_attribute *da,
>> +				  char *buf)
>> +{
>> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
>> +	u8 status;
>> +	int ret;
>> +
>> +	ret = adt7410_read_byte(dev, ADT7410_STATUS, &status);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	return sprintf(buf, "%d\n", !!(status & attr->index));
>> +}
>> +
>> +static ssize_t adt7410_show_name(struct device *dev,
>> +				  struct device_attribute *da, char *buf)
>> +{
>> +	struct adt7410_data *data = dev_get_drvdata(dev);
>> +
>> +	return sprintf(buf, "%s\n", data->name);
>> +}
>> +
>> +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adt7410_show_temp, NULL, 0);
>> +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
>> +			  adt7410_show_temp, adt7410_set_temp, 1);
>> +static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
>> +			  adt7410_show_temp, adt7410_set_temp, 2);
>> +static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
>> +			  adt7410_show_temp, adt7410_set_temp, 3);
>> +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
>> +			  adt7410_show_t_hyst, adt7410_set_t_hyst, 1);
>> +static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO,
>> +			  adt7410_show_t_hyst, NULL, 2);
>> +static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO,
>> +			  adt7410_show_t_hyst, NULL, 3);
>> +static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, adt7410_show_alarm,
>> +			  NULL, ADT7410_STAT_T_LOW);
>> +static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adt7410_show_alarm,
>> +			  NULL, ADT7410_STAT_T_HIGH);
>> +static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, adt7410_show_alarm,
>> +			  NULL, ADT7410_STAT_T_CRIT);
>> +static DEVICE_ATTR(name, S_IRUGO, adt7410_show_name, NULL);
>> +
>> +static struct attribute *adt7410_attributes[] = {
>> +	&sensor_dev_attr_temp1_input.dev_attr.attr,
>> +	&sensor_dev_attr_temp1_max.dev_attr.attr,
>> +	&sensor_dev_attr_temp1_min.dev_attr.attr,
>> +	&sensor_dev_attr_temp1_crit.dev_attr.attr,
>> +	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
>> +	&sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
>> +	&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
>> +	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
>> +	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
>> +	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
>> +	NULL
>> +};
>> +
>> +static const struct attribute_group adt7410_group = {
>> +	.attrs = adt7410_attributes,
>> +};
>> +
>> +int adt7410_probe(struct device *dev, const char *name,
>> +	const struct adt7410_ops *ops)
>> +{
>> +	struct adt7410_data *data;
>> +	int ret;
>> +
>> +	data = devm_kzalloc(dev, sizeof(struct adt7410_data),
>> +			    GFP_KERNEL);
>> +	if (!data)
>> +		return -ENOMEM;
>> +
>> +	data->ops = ops;
>> +	data->name = name;
>> +
>> +	dev_set_drvdata(dev, data);
>> +	mutex_init(&data->update_lock);
>> +
>> +	/* configure as specified */
>> +	ret = adt7410_read_byte(dev, ADT7410_CONFIG, &data->oldconfig);
>> +	if (ret < 0) {
>> +		dev_dbg(dev, "Can't read config? %d\n", ret);
>> +		return ret;
>> +	}
>> +	/*
>> +	 * Set to 16 bit resolution, continous conversion and comparator mode.
>> +	 */
>> +	data->config = data->oldconfig;
>> +	data->config &= ~ADT7410_MODE_MASK;
>> +	data->config |= ADT7410_FULL | ADT7410_RESOLUTION | ADT7410_EVENT_MODE;
>> +	if (data->config != data->oldconfig) {
>> +		ret = adt7410_write_byte(dev, ADT7410_CONFIG, data->config);
>> +		if (ret)
>> +			return ret;
>> +	}
>> +	dev_dbg(dev, "Config %02x\n", data->config);
>> +
>> +	ret = adt7410_fill_cache(dev);
>> +	if (ret)
>> +		goto exit_restore;
>> +
>> +	/* Register sysfs hooks */
>> +	ret = sysfs_create_group(&dev->kobj, &adt7410_group);
>> +	if (ret)
>> +		goto exit_restore;
>> +
>> +	/*
>> +	 * The I2C device will already have it's own 'name' attribute, but for
>> +	 * the SPI device we need to register it. name will only be non NULL if
>> +	 * the device doesn't register the 'name' attribute on its own.
>> +	 */
>> +	if (name) {
>> +		ret = device_create_file(dev, &dev_attr_name);
>> +		if (ret)
>> +			goto exit_remove;
>> +	}
>> +
>> +	data->hwmon_dev = hwmon_device_register(dev);
>> +	if (IS_ERR(data->hwmon_dev)) {
>> +		ret = PTR_ERR(data->hwmon_dev);
>> +		goto exit_remove_name;
>> +	}
>> +
>> +	return 0;
>> +
>> +exit_remove_name:
>> +	if (name)
>> +		device_remove_file(dev, &dev_attr_name);
>> +exit_remove:
>> +	sysfs_remove_group(&dev->kobj, &adt7410_group);
>> +exit_restore:
>> +	adt7410_write_byte(dev, ADT7410_CONFIG, data->oldconfig);
>> +	return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(adt7410_probe);
>> +
>> +int adt7410_remove(struct device *dev)
>> +{
>> +	struct adt7410_data *data = dev_get_drvdata(dev);
>> +
>> +	hwmon_device_unregister(data->hwmon_dev);
>> +	if (data->name)
>> +		device_remove_file(dev, &dev_attr_name);
>> +	sysfs_remove_group(&dev->kobj, &adt7410_group);
>> +	if (data->oldconfig != data->config)
>> +		adt7410_write_byte(dev, ADT7410_CONFIG,
>> +					  data->oldconfig);
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(adt7410_remove);
>> +
>> +#ifdef CONFIG_PM_SLEEP
>> +
>> +static int adt7410_suspend(struct device *dev)
>> +{
>> +	struct adt7410_data *data = dev_get_drvdata(dev);
>> +
>> +	return adt7410_write_byte(dev, ADT7410_CONFIG,
>> +		data->config | ADT7410_PD);
>> +}
>> +
>> +static int adt7410_resume(struct device *dev)
>> +{
>> +	struct adt7410_data *data = dev_get_drvdata(dev);
>> +
>> +	return adt7410_write_byte(dev, ADT7410_CONFIG, data->config);
>> +}
>> +
>> +SIMPLE_DEV_PM_OPS(adt7410_dev_pm_ops, adt7410_suspend, adt7410_resume);
>> +EXPORT_SYMBOL_GPL(adt7410_dev_pm_ops);
>> +
>> +#endif /* CONFIG_PM_SLEEP */
>> +
>> +MODULE_AUTHOR("Hartmut Knaack");
>> +MODULE_DESCRIPTION("ADT7410 driver");
>> +MODULE_LICENSE("GPL");
>> diff --git a/drivers/hwmon/adt7x10.h b/drivers/hwmon/adt7x10.h
>> new file mode 100644
>> index 0000000..17c8053
>> --- /dev/null
>> +++ b/drivers/hwmon/adt7x10.h
>> @@ -0,0 +1,47 @@
>> +#ifndef __HWMON_ADT7410_H__
>> +#define __HWMON_ADT7410_H__
>> +
>> +#include <linux/types.h>
>> +
>> +/* ADT7410 registers definition */
>> +#define ADT7410_TEMPERATURE		0
>> +#define ADT7410_STATUS			2
>> +#define ADT7410_CONFIG			3
>> +#define ADT7410_T_ALARM_HIGH		4
>> +#define ADT7410_T_ALARM_LOW		6
>> +#define ADT7410_T_CRIT			8
>> +#define ADT7410_T_HYST			0xA
>> +#define ADT7410_ID			0xB
>> +
>> +/* ADT7310 registers definition */
>> +#define ADT7310_STATUS			0
>> +#define ADT7310_CONFIG			1
>> +#define ADT7310_TEMPERATURE		2
>> +#define ADT7310_ID			3
>> +#define ADT7310_T_CRIT			4
>> +#define ADT7310_T_HYST			5
>> +#define ADT7310_T_ALARM_HIGH		6
>> +#define ADT7310_T_ALARM_LOW		7
>> +
>> +struct device;
>> +
>> +struct adt7410_ops {
>> +	int (*read_word)(struct device *, u8 reg, u16 *data);
>> +	int (*write_word)(struct device *, u8 reg, u16 data);
>> +	int (*read_byte)(struct device *, u8 reg, u8 *data);
>> +	int (*write_byte)(struct device *, u8 reg, u8 data);
>> +};
>> +
>> +int adt7410_probe(struct device *dev, const char *name,
>> +	const struct adt7410_ops *ops);
>> +int adt7410_remove(struct device *dev);
>> +
>> +
>> +#ifdef CONFIG_PM_SLEEP
>> +extern const struct dev_pm_ops adt7410_dev_pm_ops;
>> +#define ADT7410_DEV_PM_OPS (&adt7410_dev_pm_ops)
>> +#else
>> +#define ADT7410_DEV_PM_OPS NULL
>> +#endif
>> +
>> +#endif
>> -- 
>> 1.8.0
>>
>>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

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

* Re: [PATCH 7/9] hwmon: (adt7410) Add support for the adt7310/adt7320
  2013-02-16 16:04       ` [lm-sensors] " Lars-Peter Clausen
@ 2013-02-16 19:15         ` Guenter Roeck
  -1 siblings, 0 replies; 56+ messages in thread
From: Guenter Roeck @ 2013-02-16 19:15 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Jean Delvare, Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio

On Sat, Feb 16, 2013 at 05:04:15PM +0100, Lars-Peter Clausen wrote:
> On 02/15/2013 09:32 PM, Guenter Roeck wrote:
> > On Fri, Feb 15, 2013 at 05:57:16PM +0100, Lars-Peter Clausen wrote:
> >> The adt7310/adt7320 is the SPI version of the adt7410/adt7320. The register map
> >> layout is a bit different, i.e. the register addresses differ between the two
> >> variants, but the bit layouts of the individual registers are identical. So both
> >> chip variants can easily be supported by the same driver. The issue of non
> >> matching register address layouts is solved by a simple look-up table which
> >> translates the I2C addresses to the SPI addresses.
> >>
> >> The patch moves the bulk of the adt7410 driver to a common module that will be
> >> shared by the adt7410 and adt7310 drivers. This common module implements the
> >> driver logic and uses a set of virtual functions to perform IO access. The
> >> adt7410 and adt7310 driver modules provide proper implementations of these IO
> >> accessor functions for I2C respective SPI.
> >>
> >> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
> >> ---
> >>  drivers/hwmon/Kconfig   |  20 ++
> >>  drivers/hwmon/Makefile  |   2 +
> >>  drivers/hwmon/adt7310.c | 160 ++++++++++++++++
> >>  drivers/hwmon/adt7410.c | 472 ++++++-----------------------------------------
> >>  drivers/hwmon/adt7x10.c | 476 ++++++++++++++++++++++++++++++++++++++++++++++++
> >>  drivers/hwmon/adt7x10.h |  47 +++++
> >>  6 files changed, 758 insertions(+), 419 deletions(-)
> >>  create mode 100644 drivers/hwmon/adt7310.c
> >>  create mode 100644 drivers/hwmon/adt7x10.c
> >>  create mode 100644 drivers/hwmon/adt7x10.h
> >>
> >> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> >> index 89ac1cb..aaa14f4 100644
> >> --- a/drivers/hwmon/Kconfig
> >> +++ b/drivers/hwmon/Kconfig
> >> @@ -179,9 +179,29 @@ config SENSORS_ADM9240
> >>  	  This driver can also be built as a module.  If so, the module
> >>  	  will be called adm9240.
> >>  
> >> +config SENSORS_ADT7X10
> >> +	tristate
> >> +	help
> >> +	  This module contains common code shared by the ADT7310/ADT7320 and
> >> +	  ADT7410/ADT7420 temperature monitoring chip drivers.
> >> +
> >> +	  If build as a module, the module will be called adt7x10.
> >> +
> >> +config SENSORS_ADT7310
> >> +	tristate "Analog Devices ADT7310/ADT7320"
> >> +	depends on SPI_MASTER
> >> +	select SENSORS_ADT7X10
> >> +	help
> >> +	  If you say yes here you get support for the Analog Devices
> >> +	  ADT7310 and ADT7320 temperature monitoring chips.
> >> +
> >> +	  This driver can also be built as a module. If so, the module
> >> +	  will be called adt7310.
> >> +
> >>  config SENSORS_ADT7410
> >>  	tristate "Analog Devices ADT7410/ADT7420"
> >>  	depends on I2C
> >> +	select SENSORS_ADT7X10
> >>  	help
> >>  	  If you say yes here you get support for the Analog Devices
> >>  	  ADT7410 and ADT7420 temperature monitoring chips.
> >> diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
> >> index 8d6d97e..5d36a57 100644
> >> --- a/drivers/hwmon/Makefile
> >> +++ b/drivers/hwmon/Makefile
> >> @@ -34,6 +34,8 @@ obj-$(CONFIG_SENSORS_ADM9240)	+= adm9240.o
> >>  obj-$(CONFIG_SENSORS_ADS1015)	+= ads1015.o
> >>  obj-$(CONFIG_SENSORS_ADS7828)	+= ads7828.o
> >>  obj-$(CONFIG_SENSORS_ADS7871)	+= ads7871.o
> >> +obj-$(CONFIG_SENSORS_ADT7X10)	+= adt7x10.o
> >> +obj-$(CONFIG_SENSORS_ADT7310)	+= adt7310.o
> >>  obj-$(CONFIG_SENSORS_ADT7410)	+= adt7410.o
> >>  obj-$(CONFIG_SENSORS_ADT7411)	+= adt7411.o
> >>  obj-$(CONFIG_SENSORS_ADT7462)	+= adt7462.o
> >> diff --git a/drivers/hwmon/adt7310.c b/drivers/hwmon/adt7310.c
> >> new file mode 100644
> >> index 0000000..0483e6c
> >> --- /dev/null
> >> +++ b/drivers/hwmon/adt7310.c
> >> @@ -0,0 +1,160 @@
> >> +/*
> >> + * ADT7310/ADT7310 digital temperature sensor driver
> >> + *
> >> + * Copyright 2010-2013 Analog Devices Inc.
> >> + *   Author: Lars-Peter Clausen <lars@metafoo.de>
> >> + *
> >> + * Licensed under the GPL-2 or later.
> >> + */
> >> +
> >> +#include <linux/module.h>
> >> +#include <linux/init.h>
> >> +#include <linux/spi/spi.h>
> >> +
> >> +#include "adt7x10.h"
> >> +
> >> +static const u8 adt7371_reg_table[] = {
> >> +	[ADT7410_TEMPERATURE]   = ADT7310_TEMPERATURE,
> >> +	[ADT7410_STATUS]	= ADT7310_STATUS,
> >> +	[ADT7410_CONFIG]	= ADT7310_CONFIG,
> >> +	[ADT7410_T_ALARM_HIGH]	= ADT7310_T_ALARM_HIGH,
> >> +	[ADT7410_T_ALARM_LOW]	= ADT7310_T_ALARM_LOW,
> >> +	[ADT7410_T_CRIT]	= ADT7310_T_CRIT,
> >> +	[ADT7410_T_HYST]	= ADT7310_T_HYST,
> >> +	[ADT7410_ID]		= ADT7310_ID,
> >> +};
> >> +
> >> +#define ADT7310_CMD_REG_MASK			0x28
> >> +#define ADT7310_CMD_REG_OFFSET			3
> >> +#define ADT7310_CMD_READ			0x40
> >> +#define ADT7310_CMD_CON_READ			0x4
> >> +
> >> +#define AD7310_COMMAND(reg) (adt7371_reg_table[(reg)] << ADT7310_CMD_REG_OFFSET)
> >> +
> >> +static int adt7310_spi_read_word(struct device *dev,
> >> +	u8 reg, u16 *data)
> > 
> > I don't really like the approach of separating the return value from the error
> > code, if both can be returned directly. There are two reasons: First, the code
> > gets more complex, and second, the compiler tends to get confused under some
> > conditions abd believe that the return value is not set. And I really don't want
> > to have to deal with the resulting build warnings, after getting rid of pretty
> > much all such warnings in the hwmon subsystem. So I'd really appreciate if you
> > could rewrite this and the subsequent patches to return both error and value as
> > function return values.
> > 
> 
> I can change it, but I don't think that the current code will confuse the
> compiler, the return value is set under all circumstances. And the code

There still tend to be conditions (mostly hit with randconfig configurations or
with some oddball configurations) where it gets confused; at least that is what
tends to happen.

> actually gets slightly more complex by rewriting it. Most of the time we don't
> want to store the result of the read operation on stack but rather somewhere else.
> 
> 	ret = adt7410_read_word(dev, TEMP);
> 	if (ret < 0) {
> 		...
> 	}
> 	data->temp[0] = ret;
> 
> Without the change we can write it as:
> 
> 	ret = adt7410_read_word(dev, TEMP, &data->temp[0])
> 	if (ret) {
> 		...
> 	}
> 
> The difference is not that big, so I won't argue over it if you prefer the
> first version.
> 
On the other side, you can then use functions such as spi_w8r16 and spi_w8r8,
and you don't need the conversion from one method to another in the i2c code.

So, yes, I would appreciate if you can make that change.

Thanks,
Guenter

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

* Re: [lm-sensors] [PATCH 7/9] hwmon: (adt7410) Add support for the adt7310/adt7320
@ 2013-02-16 19:15         ` Guenter Roeck
  0 siblings, 0 replies; 56+ messages in thread
From: Guenter Roeck @ 2013-02-16 19:15 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Jean Delvare, Hartmut Knaack, Jonathan Cameron, lm-sensors, linux-iio

On Sat, Feb 16, 2013 at 05:04:15PM +0100, Lars-Peter Clausen wrote:
> On 02/15/2013 09:32 PM, Guenter Roeck wrote:
> > On Fri, Feb 15, 2013 at 05:57:16PM +0100, Lars-Peter Clausen wrote:
> >> The adt7310/adt7320 is the SPI version of the adt7410/adt7320. The register map
> >> layout is a bit different, i.e. the register addresses differ between the two
> >> variants, but the bit layouts of the individual registers are identical. So both
> >> chip variants can easily be supported by the same driver. The issue of non
> >> matching register address layouts is solved by a simple look-up table which
> >> translates the I2C addresses to the SPI addresses.
> >>
> >> The patch moves the bulk of the adt7410 driver to a common module that will be
> >> shared by the adt7410 and adt7310 drivers. This common module implements the
> >> driver logic and uses a set of virtual functions to perform IO access. The
> >> adt7410 and adt7310 driver modules provide proper implementations of these IO
> >> accessor functions for I2C respective SPI.
> >>
> >> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
> >> ---
> >>  drivers/hwmon/Kconfig   |  20 ++
> >>  drivers/hwmon/Makefile  |   2 +
> >>  drivers/hwmon/adt7310.c | 160 ++++++++++++++++
> >>  drivers/hwmon/adt7410.c | 472 ++++++-----------------------------------------
> >>  drivers/hwmon/adt7x10.c | 476 ++++++++++++++++++++++++++++++++++++++++++++++++
> >>  drivers/hwmon/adt7x10.h |  47 +++++
> >>  6 files changed, 758 insertions(+), 419 deletions(-)
> >>  create mode 100644 drivers/hwmon/adt7310.c
> >>  create mode 100644 drivers/hwmon/adt7x10.c
> >>  create mode 100644 drivers/hwmon/adt7x10.h
> >>
> >> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> >> index 89ac1cb..aaa14f4 100644
> >> --- a/drivers/hwmon/Kconfig
> >> +++ b/drivers/hwmon/Kconfig
> >> @@ -179,9 +179,29 @@ config SENSORS_ADM9240
> >>  	  This driver can also be built as a module.  If so, the module
> >>  	  will be called adm9240.
> >>  
> >> +config SENSORS_ADT7X10
> >> +	tristate
> >> +	help
> >> +	  This module contains common code shared by the ADT7310/ADT7320 and
> >> +	  ADT7410/ADT7420 temperature monitoring chip drivers.
> >> +
> >> +	  If build as a module, the module will be called adt7x10.
> >> +
> >> +config SENSORS_ADT7310
> >> +	tristate "Analog Devices ADT7310/ADT7320"
> >> +	depends on SPI_MASTER
> >> +	select SENSORS_ADT7X10
> >> +	help
> >> +	  If you say yes here you get support for the Analog Devices
> >> +	  ADT7310 and ADT7320 temperature monitoring chips.
> >> +
> >> +	  This driver can also be built as a module. If so, the module
> >> +	  will be called adt7310.
> >> +
> >>  config SENSORS_ADT7410
> >>  	tristate "Analog Devices ADT7410/ADT7420"
> >>  	depends on I2C
> >> +	select SENSORS_ADT7X10
> >>  	help
> >>  	  If you say yes here you get support for the Analog Devices
> >>  	  ADT7410 and ADT7420 temperature monitoring chips.
> >> diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
> >> index 8d6d97e..5d36a57 100644
> >> --- a/drivers/hwmon/Makefile
> >> +++ b/drivers/hwmon/Makefile
> >> @@ -34,6 +34,8 @@ obj-$(CONFIG_SENSORS_ADM9240)	+= adm9240.o
> >>  obj-$(CONFIG_SENSORS_ADS1015)	+= ads1015.o
> >>  obj-$(CONFIG_SENSORS_ADS7828)	+= ads7828.o
> >>  obj-$(CONFIG_SENSORS_ADS7871)	+= ads7871.o
> >> +obj-$(CONFIG_SENSORS_ADT7X10)	+= adt7x10.o
> >> +obj-$(CONFIG_SENSORS_ADT7310)	+= adt7310.o
> >>  obj-$(CONFIG_SENSORS_ADT7410)	+= adt7410.o
> >>  obj-$(CONFIG_SENSORS_ADT7411)	+= adt7411.o
> >>  obj-$(CONFIG_SENSORS_ADT7462)	+= adt7462.o
> >> diff --git a/drivers/hwmon/adt7310.c b/drivers/hwmon/adt7310.c
> >> new file mode 100644
> >> index 0000000..0483e6c
> >> --- /dev/null
> >> +++ b/drivers/hwmon/adt7310.c
> >> @@ -0,0 +1,160 @@
> >> +/*
> >> + * ADT7310/ADT7310 digital temperature sensor driver
> >> + *
> >> + * Copyright 2010-2013 Analog Devices Inc.
> >> + *   Author: Lars-Peter Clausen <lars@metafoo.de>
> >> + *
> >> + * Licensed under the GPL-2 or later.
> >> + */
> >> +
> >> +#include <linux/module.h>
> >> +#include <linux/init.h>
> >> +#include <linux/spi/spi.h>
> >> +
> >> +#include "adt7x10.h"
> >> +
> >> +static const u8 adt7371_reg_table[] = {
> >> +	[ADT7410_TEMPERATURE]   = ADT7310_TEMPERATURE,
> >> +	[ADT7410_STATUS]	= ADT7310_STATUS,
> >> +	[ADT7410_CONFIG]	= ADT7310_CONFIG,
> >> +	[ADT7410_T_ALARM_HIGH]	= ADT7310_T_ALARM_HIGH,
> >> +	[ADT7410_T_ALARM_LOW]	= ADT7310_T_ALARM_LOW,
> >> +	[ADT7410_T_CRIT]	= ADT7310_T_CRIT,
> >> +	[ADT7410_T_HYST]	= ADT7310_T_HYST,
> >> +	[ADT7410_ID]		= ADT7310_ID,
> >> +};
> >> +
> >> +#define ADT7310_CMD_REG_MASK			0x28
> >> +#define ADT7310_CMD_REG_OFFSET			3
> >> +#define ADT7310_CMD_READ			0x40
> >> +#define ADT7310_CMD_CON_READ			0x4
> >> +
> >> +#define AD7310_COMMAND(reg) (adt7371_reg_table[(reg)] << ADT7310_CMD_REG_OFFSET)
> >> +
> >> +static int adt7310_spi_read_word(struct device *dev,
> >> +	u8 reg, u16 *data)
> > 
> > I don't really like the approach of separating the return value from the error
> > code, if both can be returned directly. There are two reasons: First, the code
> > gets more complex, and second, the compiler tends to get confused under some
> > conditions abd believe that the return value is not set. And I really don't want
> > to have to deal with the resulting build warnings, after getting rid of pretty
> > much all such warnings in the hwmon subsystem. So I'd really appreciate if you
> > could rewrite this and the subsequent patches to return both error and value as
> > function return values.
> > 
> 
> I can change it, but I don't think that the current code will confuse the
> compiler, the return value is set under all circumstances. And the code

There still tend to be conditions (mostly hit with randconfig configurations or
with some oddball configurations) where it gets confused; at least that is what
tends to happen.

> actually gets slightly more complex by rewriting it. Most of the time we don't
> want to store the result of the read operation on stack but rather somewhere else.
> 
> 	ret = adt7410_read_word(dev, TEMP);
> 	if (ret < 0) {
> 		...
> 	}
> 	data->temp[0] = ret;
> 
> Without the change we can write it as:
> 
> 	ret = adt7410_read_word(dev, TEMP, &data->temp[0])
> 	if (ret) {
> 		...
> 	}
> 
> The difference is not that big, so I won't argue over it if you prefer the
> first version.
> 
On the other side, you can then use functions such as spi_w8r16 and spi_w8r8,
and you don't need the conversion from one method to another in the i2c code.

So, yes, I would appreciate if you can make that change.

Thanks,
Guenter

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

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

* Re: [PATCH 1/9] hwmon: (adt7410) Clear unwanted bits in the config register
  2013-02-15 16:57 ` [lm-sensors] " Lars-Peter Clausen
@ 2013-02-19 23:03   ` Hartmut Knaack
  -1 siblings, 0 replies; 56+ messages in thread
From: Hartmut Knaack @ 2013-02-19 23:03 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Jean Delvare, Guenter Roeck, Jonathan Cameron, lm-sensors, linux-iio

Lars-Peter Clausen schrieb:
> Make sure to clear the mode bits from the config register before setting the new
> mode. Otherwise we might end up with a different mode than we want to.
>
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Reviewed-by: Hartmut Knaack <knaack.h@gmx.de>
> ---
>  drivers/hwmon/adt7410.c | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
> index 797c2b8..4ccee4f 100644
> --- a/drivers/hwmon/adt7410.c
> +++ b/drivers/hwmon/adt7410.c
> @@ -364,6 +364,7 @@ static int adt7410_probe(struct i2c_client *client,
>  	/*
>  	 * Set to 16 bit resolution, continous conversion and comparator mode.
>  	 */
> +	ret &= ~ADT7410_MODE_MASK;
>  	data->config = ret | ADT7410_FULL | ADT7410_RESOLUTION |
>  			ADT7410_EVENT_MODE;
>  	if (data->config != data->oldconfig) {


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

* Re: [lm-sensors] [PATCH 1/9] hwmon: (adt7410) Clear unwanted bits in the config register
@ 2013-02-19 23:03   ` Hartmut Knaack
  0 siblings, 0 replies; 56+ messages in thread
From: Hartmut Knaack @ 2013-02-19 23:03 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Jean Delvare, Guenter Roeck, Jonathan Cameron, lm-sensors, linux-iio

Lars-Peter Clausen schrieb:
> Make sure to clear the mode bits from the config register before setting the new
> mode. Otherwise we might end up with a different mode than we want to.
>
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Reviewed-by: Hartmut Knaack <knaack.h@gmx.de>
> ---
>  drivers/hwmon/adt7410.c | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
> index 797c2b8..4ccee4f 100644
> --- a/drivers/hwmon/adt7410.c
> +++ b/drivers/hwmon/adt7410.c
> @@ -364,6 +364,7 @@ static int adt7410_probe(struct i2c_client *client,
>  	/*
>  	 * Set to 16 bit resolution, continous conversion and comparator mode.
>  	 */
> +	ret &= ~ADT7410_MODE_MASK;
>  	data->config = ret | ADT7410_FULL | ADT7410_RESOLUTION |
>  			ADT7410_EVENT_MODE;
>  	if (data->config != data->oldconfig) {


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

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

* Re: [PATCH 2/9] hwmon: (adt7410) Let suspend/resume depend on CONFIG_PM_SLEEP
  2013-02-15 16:57   ` [lm-sensors] " Lars-Peter Clausen
@ 2013-02-19 23:07     ` Hartmut Knaack
  -1 siblings, 0 replies; 56+ messages in thread
From: Hartmut Knaack @ 2013-02-19 23:07 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Jean Delvare, Guenter Roeck, Jonathan Cameron, lm-sensors, linux-iio

Lars-Peter Clausen schrieb:
> Only build the suspend/resume code if CONFIG_PM_SLEEP is selected. Currently the
> code is built if CONFIG_PM is selected, but it will also be selected if only
> runtime PM support is built into the kernel.
>
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Acked-by: Hartmut Knaack <knaack.h@gmx.de>
> ---
>  drivers/hwmon/adt7410.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
> index 4ccee4f..ae80815 100644
> --- a/drivers/hwmon/adt7410.c
> +++ b/drivers/hwmon/adt7410.c
> @@ -415,7 +415,7 @@ static const struct i2c_device_id adt7410_ids[] = {
>  };
>  MODULE_DEVICE_TABLE(i2c, adt7410_ids);
>  
> -#ifdef CONFIG_PM
> +#ifdef CONFIG_PM_SLEEP
>  static int adt7410_suspend(struct device *dev)
>  {
>  	int ret;


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

* Re: [lm-sensors] [PATCH 2/9] hwmon: (adt7410) Let suspend/resume depend on CONFIG_PM_SLEEP
@ 2013-02-19 23:07     ` Hartmut Knaack
  0 siblings, 0 replies; 56+ messages in thread
From: Hartmut Knaack @ 2013-02-19 23:07 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Jean Delvare, Guenter Roeck, Jonathan Cameron, lm-sensors, linux-iio

Lars-Peter Clausen schrieb:
> Only build the suspend/resume code if CONFIG_PM_SLEEP is selected. Currently the
> code is built if CONFIG_PM is selected, but it will also be selected if only
> runtime PM support is built into the kernel.
>
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Acked-by: Hartmut Knaack <knaack.h@gmx.de>
> ---
>  drivers/hwmon/adt7410.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
> index 4ccee4f..ae80815 100644
> --- a/drivers/hwmon/adt7410.c
> +++ b/drivers/hwmon/adt7410.c
> @@ -415,7 +415,7 @@ static const struct i2c_device_id adt7410_ids[] = {
>  };
>  MODULE_DEVICE_TABLE(i2c, adt7410_ids);
>  
> -#ifdef CONFIG_PM
> +#ifdef CONFIG_PM_SLEEP
>  static int adt7410_suspend(struct device *dev)
>  {
>  	int ret;


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

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

* Re: [PATCH 3/9] hwmon: (adt7410) Use the SIMPLE_DEV_PM_OPS helper macro
  2013-02-15 16:57   ` [lm-sensors] " Lars-Peter Clausen
@ 2013-02-19 23:13     ` Hartmut Knaack
  -1 siblings, 0 replies; 56+ messages in thread
From: Hartmut Knaack @ 2013-02-19 23:13 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Jean Delvare, Guenter Roeck, Jonathan Cameron, lm-sensors, linux-iio

Lars-Peter Clausen schrieb:
> Use the SIMPLE_DEV_PM_OPS macro to declare the driver's pm_ops.
>
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Reviewed-by: Hartmut Knaack <knaack.h@gmx.de>
> ---
>  drivers/hwmon/adt7410.c | 6 ++----
>  1 file changed, 2 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
> index ae80815..4ae16e0 100644
> --- a/drivers/hwmon/adt7410.c
> +++ b/drivers/hwmon/adt7410.c
> @@ -437,10 +437,8 @@ static int adt7410_resume(struct device *dev)
>  	return ret;
>  }
>  
> -static const struct dev_pm_ops adt7410_dev_pm_ops = {
> -	.suspend	= adt7410_suspend,
> -	.resume		= adt7410_resume,
> -};
> +static SIMPLE_DEV_PM_OPS(adt7410_dev_pm_ops, adt7410_suspend, adt7410_resume);
> +
>  #define ADT7410_DEV_PM_OPS (&adt7410_dev_pm_ops)
>  #else
>  #define ADT7410_DEV_PM_OPS NULL


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

* Re: [lm-sensors] [PATCH 3/9] hwmon: (adt7410) Use the SIMPLE_DEV_PM_OPS helper macro
@ 2013-02-19 23:13     ` Hartmut Knaack
  0 siblings, 0 replies; 56+ messages in thread
From: Hartmut Knaack @ 2013-02-19 23:13 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Jean Delvare, Guenter Roeck, Jonathan Cameron, lm-sensors, linux-iio

Lars-Peter Clausen schrieb:
> Use the SIMPLE_DEV_PM_OPS macro to declare the driver's pm_ops.
>
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Reviewed-by: Hartmut Knaack <knaack.h@gmx.de>
> ---
>  drivers/hwmon/adt7410.c | 6 ++----
>  1 file changed, 2 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
> index ae80815..4ae16e0 100644
> --- a/drivers/hwmon/adt7410.c
> +++ b/drivers/hwmon/adt7410.c
> @@ -437,10 +437,8 @@ static int adt7410_resume(struct device *dev)
>  	return ret;
>  }
>  
> -static const struct dev_pm_ops adt7410_dev_pm_ops = {
> -	.suspend	= adt7410_suspend,
> -	.resume		= adt7410_resume,
> -};
> +static SIMPLE_DEV_PM_OPS(adt7410_dev_pm_ops, adt7410_suspend, adt7410_resume);
> +
>  #define ADT7410_DEV_PM_OPS (&adt7410_dev_pm_ops)
>  #else
>  #define ADT7410_DEV_PM_OPS NULL


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

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

* Re: [PATCH 4/9] hwmon: (adt7410) Use I2C_ADDRS helper macro
  2013-02-15 16:57   ` [lm-sensors] " Lars-Peter Clausen
@ 2013-02-19 23:17     ` Hartmut Knaack
  -1 siblings, 0 replies; 56+ messages in thread
From: Hartmut Knaack @ 2013-02-19 23:17 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Jean Delvare, Guenter Roeck, Jonathan Cameron, lm-sensors, linux-iio

Lars-Peter Clausen schrieb:
> Use the I2C_ADDRS macro to initialize the I2C device's address_list. Doing so
> saves a few lines of boilerplate code.
>
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Reviewed-by: Hartmut Knaack <knaack.h@gmx.de>
> ---
>  drivers/hwmon/adt7410.c | 6 +-----
>  1 file changed, 1 insertion(+), 5 deletions(-)
>
> diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
> index 4ae16e0..99f6d32 100644
> --- a/drivers/hwmon/adt7410.c
> +++ b/drivers/hwmon/adt7410.c
> @@ -78,10 +78,6 @@ enum adt7410_type {		/* keep sorted in alphabetical order */
>  	adt7410,
>  };
>  
> -/* Addresses scanned */
> -static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
> -					I2C_CLIENT_END };
> -
>  static const u8 ADT7410_REG_TEMP[4] = {
>  	ADT7410_TEMPERATURE,		/* input */
>  	ADT7410_T_ALARM_HIGH,		/* high */
> @@ -453,7 +449,7 @@ static struct i2c_driver adt7410_driver = {
>  	.probe		= adt7410_probe,
>  	.remove		= adt7410_remove,
>  	.id_table	= adt7410_ids,
> -	.address_list	= normal_i2c,
> +	.address_list	= I2C_ADDRS(0x48, 0x49, 0x4a, 0x4b),
>  };
>  
>  module_i2c_driver(adt7410_driver);


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

* Re: [lm-sensors] [PATCH 4/9] hwmon: (adt7410) Use I2C_ADDRS helper macro
@ 2013-02-19 23:17     ` Hartmut Knaack
  0 siblings, 0 replies; 56+ messages in thread
From: Hartmut Knaack @ 2013-02-19 23:17 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Jean Delvare, Guenter Roeck, Jonathan Cameron, lm-sensors, linux-iio

Lars-Peter Clausen schrieb:
> Use the I2C_ADDRS macro to initialize the I2C device's address_list. Doing so
> saves a few lines of boilerplate code.
>
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Reviewed-by: Hartmut Knaack <knaack.h@gmx.de>
> ---
>  drivers/hwmon/adt7410.c | 6 +-----
>  1 file changed, 1 insertion(+), 5 deletions(-)
>
> diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
> index 4ae16e0..99f6d32 100644
> --- a/drivers/hwmon/adt7410.c
> +++ b/drivers/hwmon/adt7410.c
> @@ -78,10 +78,6 @@ enum adt7410_type {		/* keep sorted in alphabetical order */
>  	adt7410,
>  };
>  
> -/* Addresses scanned */
> -static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
> -					I2C_CLIENT_END };
> -
>  static const u8 ADT7410_REG_TEMP[4] = {
>  	ADT7410_TEMPERATURE,		/* input */
>  	ADT7410_T_ALARM_HIGH,		/* high */
> @@ -453,7 +449,7 @@ static struct i2c_driver adt7410_driver = {
>  	.probe		= adt7410_probe,
>  	.remove		= adt7410_remove,
>  	.id_table	= adt7410_ids,
> -	.address_list	= normal_i2c,
> +	.address_list	= I2C_ADDRS(0x48, 0x49, 0x4a, 0x4b),
>  };
>  
>  module_i2c_driver(adt7410_driver);


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

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

* Re: [PATCH 5/9] hwmon: (adt7410) Add device table entry for the adt7420
  2013-02-15 16:57   ` [lm-sensors] " Lars-Peter Clausen
@ 2013-02-19 23:21     ` Hartmut Knaack
  -1 siblings, 0 replies; 56+ messages in thread
From: Hartmut Knaack @ 2013-02-19 23:21 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Jean Delvare, Guenter Roeck, Jonathan Cameron, lm-sensors, linux-iio

Lars-Peter Clausen schrieb:
> The adt7420 is software compatible to the adt7410.
>
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Reviewed-by: Hartmut Knaack <knaack.h@gmx.de>
> ---
>  drivers/hwmon/Kconfig   | 4 ++--
>  drivers/hwmon/adt7410.c | 3 ++-
>  2 files changed, 4 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> index 52d5174..89ac1cb 100644
> --- a/drivers/hwmon/Kconfig
> +++ b/drivers/hwmon/Kconfig
> @@ -180,11 +180,11 @@ config SENSORS_ADM9240
>  	  will be called adm9240.
>  
>  config SENSORS_ADT7410
> -	tristate "Analog Devices ADT7410"
> +	tristate "Analog Devices ADT7410/ADT7420"
>  	depends on I2C
>  	help
>  	  If you say yes here you get support for the Analog Devices
> -	  ADT7410 temperature monitoring chip.
> +	  ADT7410 and ADT7420 temperature monitoring chips.
>  
>  	  This driver can also be built as a module. If so, the module
>  	  will be called adt7410.
> diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
> index 99f6d32..99a7290 100644
> --- a/drivers/hwmon/adt7410.c
> +++ b/drivers/hwmon/adt7410.c
> @@ -407,6 +407,7 @@ static int adt7410_remove(struct i2c_client *client)
>  
>  static const struct i2c_device_id adt7410_ids[] = {
>  	{ "adt7410", adt7410, },
> +	{ "adt7420", adt7410, },
>  	{ /* LIST END */ }
>  };
>  MODULE_DEVICE_TABLE(i2c, adt7410_ids);
> @@ -455,5 +456,5 @@ static struct i2c_driver adt7410_driver = {
>  module_i2c_driver(adt7410_driver);
>  
>  MODULE_AUTHOR("Hartmut Knaack");
> -MODULE_DESCRIPTION("ADT7410 driver");
> +MODULE_DESCRIPTION("ADT7410/ADT7420 driver");
>  MODULE_LICENSE("GPL");


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

* Re: [lm-sensors] [PATCH 5/9] hwmon: (adt7410) Add device table entry for the adt7420
@ 2013-02-19 23:21     ` Hartmut Knaack
  0 siblings, 0 replies; 56+ messages in thread
From: Hartmut Knaack @ 2013-02-19 23:21 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Jean Delvare, Guenter Roeck, Jonathan Cameron, lm-sensors, linux-iio

Lars-Peter Clausen schrieb:
> The adt7420 is software compatible to the adt7410.
>
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Reviewed-by: Hartmut Knaack <knaack.h@gmx.de>
> ---
>  drivers/hwmon/Kconfig   | 4 ++--
>  drivers/hwmon/adt7410.c | 3 ++-
>  2 files changed, 4 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> index 52d5174..89ac1cb 100644
> --- a/drivers/hwmon/Kconfig
> +++ b/drivers/hwmon/Kconfig
> @@ -180,11 +180,11 @@ config SENSORS_ADM9240
>  	  will be called adm9240.
>  
>  config SENSORS_ADT7410
> -	tristate "Analog Devices ADT7410"
> +	tristate "Analog Devices ADT7410/ADT7420"
>  	depends on I2C
>  	help
>  	  If you say yes here you get support for the Analog Devices
> -	  ADT7410 temperature monitoring chip.
> +	  ADT7410 and ADT7420 temperature monitoring chips.
>  
>  	  This driver can also be built as a module. If so, the module
>  	  will be called adt7410.
> diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
> index 99f6d32..99a7290 100644
> --- a/drivers/hwmon/adt7410.c
> +++ b/drivers/hwmon/adt7410.c
> @@ -407,6 +407,7 @@ static int adt7410_remove(struct i2c_client *client)
>  
>  static const struct i2c_device_id adt7410_ids[] = {
>  	{ "adt7410", adt7410, },
> +	{ "adt7420", adt7410, },
>  	{ /* LIST END */ }
>  };
>  MODULE_DEVICE_TABLE(i2c, adt7410_ids);
> @@ -455,5 +456,5 @@ static struct i2c_driver adt7410_driver = {
>  module_i2c_driver(adt7410_driver);
>  
>  MODULE_AUTHOR("Hartmut Knaack");
> -MODULE_DESCRIPTION("ADT7410 driver");
> +MODULE_DESCRIPTION("ADT7410/ADT7420 driver");
>  MODULE_LICENSE("GPL");


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

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

* Re: [PATCH 5/9] hwmon: (adt7410) Add device table entry for the adt7420
  2013-02-15 16:57   ` [lm-sensors] " Lars-Peter Clausen
@ 2013-02-21  0:10     ` Hartmut Knaack
  -1 siblings, 0 replies; 56+ messages in thread
From: Hartmut Knaack @ 2013-02-21  0:10 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Jean Delvare, Guenter Roeck, Jonathan Cameron, lm-sensors, linux-iio

Lars-Peter Clausen schrieb:
> The adt7420 is software compatible to the adt7410.
>
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>

I did some basic testing of the patch-set until this one (instantiation, removal, get/set min/max/crit/hyst, monitor temperatures and alarm triggers while changing temperatures) on an ADT7410, all went fine. No suspend/resume tested.
Tested-by: Hartmut Knaack <knaack.h@gmx.de>
> ---
>  drivers/hwmon/Kconfig   | 4 ++--
>  drivers/hwmon/adt7410.c | 3 ++-
>  2 files changed, 4 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> index 52d5174..89ac1cb 100644
> --- a/drivers/hwmon/Kconfig
> +++ b/drivers/hwmon/Kconfig
> @@ -180,11 +180,11 @@ config SENSORS_ADM9240
>  	  will be called adm9240.
>  
>  config SENSORS_ADT7410
> -	tristate "Analog Devices ADT7410"
> +	tristate "Analog Devices ADT7410/ADT7420"
>  	depends on I2C
>  	help
>  	  If you say yes here you get support for the Analog Devices
> -	  ADT7410 temperature monitoring chip.
> +	  ADT7410 and ADT7420 temperature monitoring chips.
>  
>  	  This driver can also be built as a module. If so, the module
>  	  will be called adt7410.
> diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
> index 99f6d32..99a7290 100644
> --- a/drivers/hwmon/adt7410.c
> +++ b/drivers/hwmon/adt7410.c
> @@ -407,6 +407,7 @@ static int adt7410_remove(struct i2c_client *client)
>  
>  static const struct i2c_device_id adt7410_ids[] = {
>  	{ "adt7410", adt7410, },
> +	{ "adt7420", adt7410, },
>  	{ /* LIST END */ }
>  };
>  MODULE_DEVICE_TABLE(i2c, adt7410_ids);
> @@ -455,5 +456,5 @@ static struct i2c_driver adt7410_driver = {
>  module_i2c_driver(adt7410_driver);
>  
>  MODULE_AUTHOR("Hartmut Knaack");
> -MODULE_DESCRIPTION("ADT7410 driver");
> +MODULE_DESCRIPTION("ADT7410/ADT7420 driver");
>  MODULE_LICENSE("GPL");


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

* Re: [lm-sensors] [PATCH 5/9] hwmon: (adt7410) Add device table entry for the adt7420
@ 2013-02-21  0:10     ` Hartmut Knaack
  0 siblings, 0 replies; 56+ messages in thread
From: Hartmut Knaack @ 2013-02-21  0:10 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Jean Delvare, Guenter Roeck, Jonathan Cameron, lm-sensors, linux-iio

Lars-Peter Clausen schrieb:
> The adt7420 is software compatible to the adt7410.
>
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>

I did some basic testing of the patch-set until this one (instantiation, removal, get/set min/max/crit/hyst, monitor temperatures and alarm triggers while changing temperatures) on an ADT7410, all went fine. No suspend/resume tested.
Tested-by: Hartmut Knaack <knaack.h@gmx.de>
> ---
>  drivers/hwmon/Kconfig   | 4 ++--
>  drivers/hwmon/adt7410.c | 3 ++-
>  2 files changed, 4 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> index 52d5174..89ac1cb 100644
> --- a/drivers/hwmon/Kconfig
> +++ b/drivers/hwmon/Kconfig
> @@ -180,11 +180,11 @@ config SENSORS_ADM9240
>  	  will be called adm9240.
>  
>  config SENSORS_ADT7410
> -	tristate "Analog Devices ADT7410"
> +	tristate "Analog Devices ADT7410/ADT7420"
>  	depends on I2C
>  	help
>  	  If you say yes here you get support for the Analog Devices
> -	  ADT7410 temperature monitoring chip.
> +	  ADT7410 and ADT7420 temperature monitoring chips.
>  
>  	  This driver can also be built as a module. If so, the module
>  	  will be called adt7410.
> diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
> index 99f6d32..99a7290 100644
> --- a/drivers/hwmon/adt7410.c
> +++ b/drivers/hwmon/adt7410.c
> @@ -407,6 +407,7 @@ static int adt7410_remove(struct i2c_client *client)
>  
>  static const struct i2c_device_id adt7410_ids[] = {
>  	{ "adt7410", adt7410, },
> +	{ "adt7420", adt7410, },
>  	{ /* LIST END */ }
>  };
>  MODULE_DEVICE_TABLE(i2c, adt7410_ids);
> @@ -455,5 +456,5 @@ static struct i2c_driver adt7410_driver = {
>  module_i2c_driver(adt7410_driver);
>  
>  MODULE_AUTHOR("Hartmut Knaack");
> -MODULE_DESCRIPTION("ADT7410 driver");
> +MODULE_DESCRIPTION("ADT7410/ADT7420 driver");
>  MODULE_LICENSE("GPL");


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

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

end of thread, other threads:[~2013-02-21  0:10 UTC | newest]

Thread overview: 56+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-02-15 16:57 [PATCH 1/9] hwmon: (adt7410) Clear unwanted bits in the config register Lars-Peter Clausen
2013-02-15 16:57 ` [lm-sensors] " Lars-Peter Clausen
2013-02-15 16:57 ` [PATCH 2/9] hwmon: (adt7410) Let suspend/resume depend on CONFIG_PM_SLEEP Lars-Peter Clausen
2013-02-15 16:57   ` [lm-sensors] " Lars-Peter Clausen
2013-02-15 20:07   ` Guenter Roeck
2013-02-15 20:07     ` [lm-sensors] " Guenter Roeck
2013-02-19 23:07   ` Hartmut Knaack
2013-02-19 23:07     ` [lm-sensors] " Hartmut Knaack
2013-02-15 16:57 ` [PATCH 3/9] hwmon: (adt7410) Use the SIMPLE_DEV_PM_OPS helper macro Lars-Peter Clausen
2013-02-15 16:57   ` [lm-sensors] " Lars-Peter Clausen
2013-02-15 20:07   ` Guenter Roeck
2013-02-15 20:07     ` [lm-sensors] " Guenter Roeck
2013-02-19 23:13   ` Hartmut Knaack
2013-02-19 23:13     ` [lm-sensors] " Hartmut Knaack
2013-02-15 16:57 ` [PATCH 4/9] hwmon: (adt7410) Use I2C_ADDRS " Lars-Peter Clausen
2013-02-15 16:57   ` [lm-sensors] " Lars-Peter Clausen
2013-02-15 20:07   ` Guenter Roeck
2013-02-15 20:07     ` [lm-sensors] " Guenter Roeck
2013-02-19 23:17   ` Hartmut Knaack
2013-02-19 23:17     ` [lm-sensors] " Hartmut Knaack
2013-02-15 16:57 ` [PATCH 5/9] hwmon: (adt7410) Add device table entry for the adt7420 Lars-Peter Clausen
2013-02-15 16:57   ` [lm-sensors] " Lars-Peter Clausen
2013-02-15 20:08   ` Guenter Roeck
2013-02-15 20:08     ` [lm-sensors] " Guenter Roeck
2013-02-19 23:21   ` Hartmut Knaack
2013-02-19 23:21     ` [lm-sensors] " Hartmut Knaack
2013-02-21  0:10   ` Hartmut Knaack
2013-02-21  0:10     ` [lm-sensors] " Hartmut Knaack
2013-02-15 16:57 ` [PATCH 6/9] hwmon: (adt7410) Don't re-read non-volatile registers Lars-Peter Clausen
2013-02-15 16:57   ` [lm-sensors] " Lars-Peter Clausen
2013-02-15 20:20   ` Guenter Roeck
2013-02-15 20:20     ` [lm-sensors] " Guenter Roeck
2013-02-16 15:56     ` Lars-Peter Clausen
2013-02-16 15:56       ` [lm-sensors] " Lars-Peter Clausen
2013-02-15 16:57 ` [PATCH 7/9] hwmon: (adt7410) Add support for the adt7310/adt7320 Lars-Peter Clausen
2013-02-15 16:57   ` [lm-sensors] [PATCH 7/9] hwmon: (adt7410) Add =?utf-8?q?_support_for_the_adt73 Lars-Peter Clausen
2013-02-15 20:05   ` [PATCH 7/9] hwmon: (adt7410) Add support for the adt7310/adt7320 Hartmut Knaack
2013-02-15 20:05     ` [lm-sensors] " Hartmut Knaack
2013-02-16  0:40     ` Andrey Repin
2013-02-16 15:49     ` Lars-Peter Clausen
2013-02-16 15:54     ` Lars-Peter Clausen
2013-02-16 15:54       ` [lm-sensors] " Lars-Peter Clausen
2013-02-15 20:32   ` Guenter Roeck
2013-02-15 20:32     ` [lm-sensors] " Guenter Roeck
2013-02-16 16:04     ` Lars-Peter Clausen
2013-02-16 16:04       ` [lm-sensors] " Lars-Peter Clausen
2013-02-16 19:15       ` Guenter Roeck
2013-02-16 19:15         ` [lm-sensors] " Guenter Roeck
2013-02-15 16:57 ` [PATCH 8/9] hwmon: (adt7x10) Add alarm interrupt support Lars-Peter Clausen
2013-02-15 16:57   ` [lm-sensors] " Lars-Peter Clausen
2013-02-15 16:57 ` [PATCH 9/9] staging:iio: Remove adt7410 driver Lars-Peter Clausen
2013-02-15 16:57   ` [lm-sensors] " Lars-Peter Clausen
2013-02-15 20:06 ` [PATCH 1/9] hwmon: (adt7410) Clear unwanted bits in the config register Guenter Roeck
2013-02-15 20:06   ` [lm-sensors] " Guenter Roeck
2013-02-19 23:03 ` Hartmut Knaack
2013-02-19 23:03   ` [lm-sensors] " Hartmut Knaack

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.