* [lm-sensors] [PATCH v7 0/5] hwmon: ina2xx: implement chip reinitialization and add new attributes
@ 2014-12-13 16:27 ` Bartosz Golaszewski
0 siblings, 0 replies; 16+ messages in thread
From: Bartosz Golaszewski @ 2014-12-13 16:27 UTC (permalink / raw)
To: Guenter Roeck
Cc: LKML, Benoit Cousson, Patrick Titiano, LM Sensors,
Bartosz Golaszewski
This series implements a mechanism to detect if the chip is in its POR state
and reinitialize it if needed. It also extends the sysfs interface to make the
driver configurable at run-time.
The shunt_resistor attribute allows to change the shunt resistance value
at run-time in cases where ina2xx used to do the measurement isn't integrated
with the shunt.
The avg_rate attribute allows to increase/decrease noise reduction.
v7:
- implemented a retry counter for the reinitialization procedure
- using msleep() (since the sleep is > 20ms) instead of mdelay()
when waiting for the chip update
v6:
https://www.mail-archive.com/linux-kernel%40vger.kernel.org/msg787390.html
Bartosz Golaszewski (5):
hwmon: ina2xx: reinitialize the chip in case it's been reset
hwmon: ina2xx: remove a stray new line
hwmon: ina2xx: don't accept shunt values greater than the calibration factor
hwmon: ina2xx: make shunt resistance configurable at run-time
hwmon: ina2xx: allow to change the averaging rate at run-time
Documentation/hwmon/ina2xx | 8 +-
drivers/hwmon/ina2xx.c | 304 +++++++++++++++++++++++++++++++++++++++------
2 files changed, 269 insertions(+), 43 deletions(-)
--
2.1.3
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v7 0/5] hwmon: ina2xx: implement chip reinitialization and add new attributes
@ 2014-12-13 16:27 ` Bartosz Golaszewski
0 siblings, 0 replies; 16+ messages in thread
From: Bartosz Golaszewski @ 2014-12-13 16:27 UTC (permalink / raw)
To: Guenter Roeck
Cc: LKML, Benoit Cousson, Patrick Titiano, LM Sensors,
Bartosz Golaszewski
This series implements a mechanism to detect if the chip is in its POR state
and reinitialize it if needed. It also extends the sysfs interface to make the
driver configurable at run-time.
The shunt_resistor attribute allows to change the shunt resistance value
at run-time in cases where ina2xx used to do the measurement isn't integrated
with the shunt.
The avg_rate attribute allows to increase/decrease noise reduction.
v7:
- implemented a retry counter for the reinitialization procedure
- using msleep() (since the sleep is > 20ms) instead of mdelay()
when waiting for the chip update
v6:
https://www.mail-archive.com/linux-kernel%40vger.kernel.org/msg787390.html
Bartosz Golaszewski (5):
hwmon: ina2xx: reinitialize the chip in case it's been reset
hwmon: ina2xx: remove a stray new line
hwmon: ina2xx: don't accept shunt values greater than the calibration factor
hwmon: ina2xx: make shunt resistance configurable at run-time
hwmon: ina2xx: allow to change the averaging rate at run-time
Documentation/hwmon/ina2xx | 8 +-
drivers/hwmon/ina2xx.c | 304 +++++++++++++++++++++++++++++++++++++++------
2 files changed, 269 insertions(+), 43 deletions(-)
--
2.1.3
^ permalink raw reply [flat|nested] 16+ messages in thread
* [lm-sensors] [PATCH v7 1/5] hwmon: ina2xx: reinitialize the chip in case it's been reset
2014-12-13 16:27 ` Bartosz Golaszewski
@ 2014-12-13 16:27 ` Bartosz Golaszewski
-1 siblings, 0 replies; 16+ messages in thread
From: Bartosz Golaszewski @ 2014-12-13 16:27 UTC (permalink / raw)
To: Guenter Roeck
Cc: LKML, Benoit Cousson, Patrick Titiano, LM Sensors,
Bartosz Golaszewski
Chips from the ina family don't like to be uninitialized. In case the power
is cut-off and restored again the calibration register will be reset
to 0 and both the power and current registers will remain at 0.
Check the calibration register in ina2xx_update_device() and reinitialize
the chip if needed.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
drivers/hwmon/ina2xx.c | 128 +++++++++++++++++++++++++++++++++++--------------
1 file changed, 91 insertions(+), 37 deletions(-)
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index e01feba..ffbd60f 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -35,6 +35,7 @@
#include <linux/hwmon-sysfs.h>
#include <linux/jiffies.h>
#include <linux/of.h>
+#include <linux/delay.h>
#include <linux/platform_data/ina2xx.h>
@@ -64,6 +65,9 @@
/* worst case is 68.10 ms (~14.6Hz, ina219) */
#define INA2XX_CONVERSION_RATE 15
+#define INA2XX_MAX_DELAY 69 /* worst case delay in ms */
+
+#define INA2XX_RSHUNT_DEFAULT 10000
enum ina2xx_ids { ina219, ina226 };
@@ -81,6 +85,8 @@ struct ina2xx_data {
struct i2c_client *client;
const struct ina2xx_config *config;
+ long rshunt;
+
struct mutex update_lock;
bool valid;
unsigned long last_updated;
@@ -110,34 +116,96 @@ static const struct ina2xx_config ina2xx_config[] = {
},
};
-static struct ina2xx_data *ina2xx_update_device(struct device *dev)
+/*
+ * Initialize the configuration and calibration registers.
+ */
+static int ina2xx_init(struct ina2xx_data *data)
{
- struct ina2xx_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
- struct ina2xx_data *ret = data;
+ int ret;
- mutex_lock(&data->update_lock);
+ /* device configuration */
+ ret = i2c_smbus_write_word_swapped(client, INA2XX_CONFIG,
+ data->config->config_default);
+ if (ret < 0)
+ return ret;
- if (time_after(jiffies, data->last_updated +
- HZ / INA2XX_CONVERSION_RATE) || !data->valid) {
+ /*
+ * Set current LSB to 1mA, shunt is in uOhms
+ * (equation 13 in datasheet).
+ */
+ return i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION,
+ data->config->calibration_factor / data->rshunt);
+}
- int i;
+static int ina2xx_do_update(struct device *dev)
+{
+ struct ina2xx_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
+ int i, rv, retry;
- dev_dbg(&client->dev, "Starting ina2xx update\n");
+ dev_dbg(&client->dev, "Starting ina2xx update\n");
+ for (retry = 5; retry; retry--) {
/* Read all registers */
for (i = 0; i < data->config->registers; i++) {
- int rv = i2c_smbus_read_word_swapped(client, i);
- if (rv < 0) {
- ret = ERR_PTR(rv);
- goto abort;
- }
+ rv = i2c_smbus_read_word_swapped(client, i);
+ if (rv < 0)
+ return rv;
data->regs[i] = rv;
}
+
+ /*
+ * If the current value in the calibration register is 0, the
+ * power and current registers will also remain at 0. In case
+ * the chip has been reset let's check the calibration
+ * register and reinitialize if needed.
+ */
+ if (data->regs[INA2XX_CALIBRATION] = 0) {
+ dev_warn(dev, "chip not calibrated, reinitializing\n");
+
+ rv = ina2xx_init(data);
+ if (rv < 0)
+ return rv;
+
+ /*
+ * Let's make sure the power and current registers
+ * have been updated before trying again.
+ */
+ msleep(INA2XX_MAX_DELAY);
+ continue;
+ }
+
data->last_updated = jiffies;
data->valid = 1;
+
+ return 0;
}
-abort:
+
+ /*
+ * If we're here then although all write operations succeeded, the
+ * chip still returns 0 in the calibration register. Nothing more we
+ * can do here.
+ */
+ dev_err(dev, "unable to reinitialize the chip\n");
+ return -ENODEV;
+}
+
+static struct ina2xx_data *ina2xx_update_device(struct device *dev)
+{
+ struct ina2xx_data *data = dev_get_drvdata(dev);
+ struct ina2xx_data *ret = data;
+ int rv;
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated +
+ HZ / INA2XX_CONVERSION_RATE) || !data->valid) {
+ rv = ina2xx_do_update(dev);
+ if (rv < 0)
+ ret = ERR_PTR(rv);
+ }
+
mutex_unlock(&data->update_lock);
return ret;
}
@@ -221,7 +289,6 @@ static int ina2xx_probe(struct i2c_client *client,
struct device *dev = &client->dev;
struct ina2xx_data *data;
struct device *hwmon_dev;
- long shunt = 10000; /* default shunt value 10mOhms */
u32 val;
int ret;
@@ -234,41 +301,28 @@ static int ina2xx_probe(struct i2c_client *client,
if (dev_get_platdata(dev)) {
pdata = dev_get_platdata(dev);
- shunt = pdata->shunt_uohms;
+ data->rshunt = pdata->shunt_uohms;
} else if (!of_property_read_u32(dev->of_node,
"shunt-resistor", &val)) {
- shunt = val;
+ data->rshunt = val;
+ } else {
+ data->rshunt = INA2XX_RSHUNT_DEFAULT;
}
- if (shunt <= 0)
- return -ENODEV;
-
/* set the device type */
data->kind = id->driver_data;
data->config = &ina2xx_config[data->kind];
+ data->client = client;
- /* device configuration */
- ret = i2c_smbus_write_word_swapped(client, INA2XX_CONFIG,
- data->config->config_default);
- if (ret < 0) {
- dev_err(dev,
- "error writing to the config register: %d", ret);
+ if (data->rshunt <= 0)
return -ENODEV;
- }
- /*
- * Set current LSB to 1mA, shunt is in uOhms
- * (equation 13 in datasheet).
- */
- ret = i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION,
- data->config->calibration_factor / shunt);
+ ret = ina2xx_init(data);
if (ret < 0) {
- dev_err(dev,
- "error writing to the calibration register: %d", ret);
+ dev_err(dev, "error configuring the device: %d\n", ret);
return -ENODEV;
}
- data->client = client;
mutex_init(&data->update_lock);
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
@@ -277,7 +331,7 @@ static int ina2xx_probe(struct i2c_client *client,
return PTR_ERR(hwmon_dev);
dev_info(dev, "power monitor %s (Rshunt = %li uOhm)\n",
- id->name, shunt);
+ id->name, data->rshunt);
return 0;
}
--
2.1.3
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v7 1/5] hwmon: ina2xx: reinitialize the chip in case it's been reset
@ 2014-12-13 16:27 ` Bartosz Golaszewski
0 siblings, 0 replies; 16+ messages in thread
From: Bartosz Golaszewski @ 2014-12-13 16:27 UTC (permalink / raw)
To: Guenter Roeck
Cc: LKML, Benoit Cousson, Patrick Titiano, LM Sensors,
Bartosz Golaszewski
Chips from the ina family don't like to be uninitialized. In case the power
is cut-off and restored again the calibration register will be reset
to 0 and both the power and current registers will remain at 0.
Check the calibration register in ina2xx_update_device() and reinitialize
the chip if needed.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
drivers/hwmon/ina2xx.c | 128 +++++++++++++++++++++++++++++++++++--------------
1 file changed, 91 insertions(+), 37 deletions(-)
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index e01feba..ffbd60f 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -35,6 +35,7 @@
#include <linux/hwmon-sysfs.h>
#include <linux/jiffies.h>
#include <linux/of.h>
+#include <linux/delay.h>
#include <linux/platform_data/ina2xx.h>
@@ -64,6 +65,9 @@
/* worst case is 68.10 ms (~14.6Hz, ina219) */
#define INA2XX_CONVERSION_RATE 15
+#define INA2XX_MAX_DELAY 69 /* worst case delay in ms */
+
+#define INA2XX_RSHUNT_DEFAULT 10000
enum ina2xx_ids { ina219, ina226 };
@@ -81,6 +85,8 @@ struct ina2xx_data {
struct i2c_client *client;
const struct ina2xx_config *config;
+ long rshunt;
+
struct mutex update_lock;
bool valid;
unsigned long last_updated;
@@ -110,34 +116,96 @@ static const struct ina2xx_config ina2xx_config[] = {
},
};
-static struct ina2xx_data *ina2xx_update_device(struct device *dev)
+/*
+ * Initialize the configuration and calibration registers.
+ */
+static int ina2xx_init(struct ina2xx_data *data)
{
- struct ina2xx_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
- struct ina2xx_data *ret = data;
+ int ret;
- mutex_lock(&data->update_lock);
+ /* device configuration */
+ ret = i2c_smbus_write_word_swapped(client, INA2XX_CONFIG,
+ data->config->config_default);
+ if (ret < 0)
+ return ret;
- if (time_after(jiffies, data->last_updated +
- HZ / INA2XX_CONVERSION_RATE) || !data->valid) {
+ /*
+ * Set current LSB to 1mA, shunt is in uOhms
+ * (equation 13 in datasheet).
+ */
+ return i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION,
+ data->config->calibration_factor / data->rshunt);
+}
- int i;
+static int ina2xx_do_update(struct device *dev)
+{
+ struct ina2xx_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
+ int i, rv, retry;
- dev_dbg(&client->dev, "Starting ina2xx update\n");
+ dev_dbg(&client->dev, "Starting ina2xx update\n");
+ for (retry = 5; retry; retry--) {
/* Read all registers */
for (i = 0; i < data->config->registers; i++) {
- int rv = i2c_smbus_read_word_swapped(client, i);
- if (rv < 0) {
- ret = ERR_PTR(rv);
- goto abort;
- }
+ rv = i2c_smbus_read_word_swapped(client, i);
+ if (rv < 0)
+ return rv;
data->regs[i] = rv;
}
+
+ /*
+ * If the current value in the calibration register is 0, the
+ * power and current registers will also remain at 0. In case
+ * the chip has been reset let's check the calibration
+ * register and reinitialize if needed.
+ */
+ if (data->regs[INA2XX_CALIBRATION] == 0) {
+ dev_warn(dev, "chip not calibrated, reinitializing\n");
+
+ rv = ina2xx_init(data);
+ if (rv < 0)
+ return rv;
+
+ /*
+ * Let's make sure the power and current registers
+ * have been updated before trying again.
+ */
+ msleep(INA2XX_MAX_DELAY);
+ continue;
+ }
+
data->last_updated = jiffies;
data->valid = 1;
+
+ return 0;
}
-abort:
+
+ /*
+ * If we're here then although all write operations succeeded, the
+ * chip still returns 0 in the calibration register. Nothing more we
+ * can do here.
+ */
+ dev_err(dev, "unable to reinitialize the chip\n");
+ return -ENODEV;
+}
+
+static struct ina2xx_data *ina2xx_update_device(struct device *dev)
+{
+ struct ina2xx_data *data = dev_get_drvdata(dev);
+ struct ina2xx_data *ret = data;
+ int rv;
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated +
+ HZ / INA2XX_CONVERSION_RATE) || !data->valid) {
+ rv = ina2xx_do_update(dev);
+ if (rv < 0)
+ ret = ERR_PTR(rv);
+ }
+
mutex_unlock(&data->update_lock);
return ret;
}
@@ -221,7 +289,6 @@ static int ina2xx_probe(struct i2c_client *client,
struct device *dev = &client->dev;
struct ina2xx_data *data;
struct device *hwmon_dev;
- long shunt = 10000; /* default shunt value 10mOhms */
u32 val;
int ret;
@@ -234,41 +301,28 @@ static int ina2xx_probe(struct i2c_client *client,
if (dev_get_platdata(dev)) {
pdata = dev_get_platdata(dev);
- shunt = pdata->shunt_uohms;
+ data->rshunt = pdata->shunt_uohms;
} else if (!of_property_read_u32(dev->of_node,
"shunt-resistor", &val)) {
- shunt = val;
+ data->rshunt = val;
+ } else {
+ data->rshunt = INA2XX_RSHUNT_DEFAULT;
}
- if (shunt <= 0)
- return -ENODEV;
-
/* set the device type */
data->kind = id->driver_data;
data->config = &ina2xx_config[data->kind];
+ data->client = client;
- /* device configuration */
- ret = i2c_smbus_write_word_swapped(client, INA2XX_CONFIG,
- data->config->config_default);
- if (ret < 0) {
- dev_err(dev,
- "error writing to the config register: %d", ret);
+ if (data->rshunt <= 0)
return -ENODEV;
- }
- /*
- * Set current LSB to 1mA, shunt is in uOhms
- * (equation 13 in datasheet).
- */
- ret = i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION,
- data->config->calibration_factor / shunt);
+ ret = ina2xx_init(data);
if (ret < 0) {
- dev_err(dev,
- "error writing to the calibration register: %d", ret);
+ dev_err(dev, "error configuring the device: %d\n", ret);
return -ENODEV;
}
- data->client = client;
mutex_init(&data->update_lock);
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
@@ -277,7 +331,7 @@ static int ina2xx_probe(struct i2c_client *client,
return PTR_ERR(hwmon_dev);
dev_info(dev, "power monitor %s (Rshunt = %li uOhm)\n",
- id->name, shunt);
+ id->name, data->rshunt);
return 0;
}
--
2.1.3
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [lm-sensors] [PATCH v7 2/5] hwmon: ina2xx: remove a stray new line
2014-12-13 16:27 ` Bartosz Golaszewski
@ 2014-12-13 16:27 ` Bartosz Golaszewski
-1 siblings, 0 replies; 16+ messages in thread
From: Bartosz Golaszewski @ 2014-12-13 16:27 UTC (permalink / raw)
To: Guenter Roeck
Cc: LKML, Benoit Cousson, Patrick Titiano, LM Sensors,
Bartosz Golaszewski
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
drivers/hwmon/ina2xx.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index ffbd60f..39e017b 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -52,7 +52,6 @@
#define INA226_ALERT_LIMIT 0x07
#define INA226_DIE_ID 0xFF
-
/* register count */
#define INA219_REGISTERS 6
#define INA226_REGISTERS 8
--
2.1.3
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v7 2/5] hwmon: ina2xx: remove a stray new line
@ 2014-12-13 16:27 ` Bartosz Golaszewski
0 siblings, 0 replies; 16+ messages in thread
From: Bartosz Golaszewski @ 2014-12-13 16:27 UTC (permalink / raw)
To: Guenter Roeck
Cc: LKML, Benoit Cousson, Patrick Titiano, LM Sensors,
Bartosz Golaszewski
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
drivers/hwmon/ina2xx.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index ffbd60f..39e017b 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -52,7 +52,6 @@
#define INA226_ALERT_LIMIT 0x07
#define INA226_DIE_ID 0xFF
-
/* register count */
#define INA219_REGISTERS 6
#define INA226_REGISTERS 8
--
2.1.3
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [lm-sensors] [PATCH v7 3/5] hwmon: ina2xx: don't accept shunt values greater than the calibration fa
2014-12-13 16:27 ` Bartosz Golaszewski
@ 2014-12-13 16:27 ` Bartosz Golaszewski
-1 siblings, 0 replies; 16+ messages in thread
From: Bartosz Golaszewski @ 2014-12-13 16:27 UTC (permalink / raw)
To: Guenter Roeck
Cc: LKML, Benoit Cousson, Patrick Titiano, LM Sensors,
Bartosz Golaszewski
Shunt resistance values greater than the chip's calibration factor make no
sense since the actual value written to the register equals:
<calibration factor> / <shunt>
Bail-out from ina2xx_probe() if the configured value is greater than the
calibration factor.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
drivers/hwmon/ina2xx.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index 39e017b..3234e57 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -313,7 +313,8 @@ static int ina2xx_probe(struct i2c_client *client,
data->config = &ina2xx_config[data->kind];
data->client = client;
- if (data->rshunt <= 0)
+ if (data->rshunt <= 0 ||
+ data->rshunt > data->config->calibration_factor)
return -ENODEV;
ret = ina2xx_init(data);
--
2.1.3
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v7 3/5] hwmon: ina2xx: don't accept shunt values greater than the calibration factor
@ 2014-12-13 16:27 ` Bartosz Golaszewski
0 siblings, 0 replies; 16+ messages in thread
From: Bartosz Golaszewski @ 2014-12-13 16:27 UTC (permalink / raw)
To: Guenter Roeck
Cc: LKML, Benoit Cousson, Patrick Titiano, LM Sensors,
Bartosz Golaszewski
Shunt resistance values greater than the chip's calibration factor make no
sense since the actual value written to the register equals:
<calibration factor> / <shunt>
Bail-out from ina2xx_probe() if the configured value is greater than the
calibration factor.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
drivers/hwmon/ina2xx.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index 39e017b..3234e57 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -313,7 +313,8 @@ static int ina2xx_probe(struct i2c_client *client,
data->config = &ina2xx_config[data->kind];
data->client = client;
- if (data->rshunt <= 0)
+ if (data->rshunt <= 0 ||
+ data->rshunt > data->config->calibration_factor)
return -ENODEV;
ret = ina2xx_init(data);
--
2.1.3
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [lm-sensors] [PATCH v7 4/5] hwmon: ina2xx: make shunt resistance configurable at run-time
2014-12-13 16:27 ` Bartosz Golaszewski
@ 2014-12-13 16:27 ` Bartosz Golaszewski
-1 siblings, 0 replies; 16+ messages in thread
From: Bartosz Golaszewski @ 2014-12-13 16:27 UTC (permalink / raw)
To: Guenter Roeck
Cc: LKML, Benoit Cousson, Patrick Titiano, LM Sensors,
Bartosz Golaszewski
The shunt resistance can only be set via platform_data or device tree. This
isn't suitable for devices in which the shunt resistance can change/isn't
known at boot-time.
Add a sysfs attribute that allows to read and set the shunt resistance.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
Documentation/hwmon/ina2xx | 5 +++--
drivers/hwmon/ina2xx.c | 48 ++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 49 insertions(+), 4 deletions(-)
diff --git a/Documentation/hwmon/ina2xx b/Documentation/hwmon/ina2xx
index 4223c2d..320dd69 100644
--- a/Documentation/hwmon/ina2xx
+++ b/Documentation/hwmon/ina2xx
@@ -44,6 +44,7 @@ The INA226 monitors both a shunt voltage drop and bus supply voltage.
The INA230 is a high or low side current shunt and power monitor with an I2C
interface. The INA230 monitors both a shunt voltage drop and bus supply voltage.
-The shunt value in micro-ohms can be set via platform data or device tree.
-Please refer to the Documentation/devicetree/bindings/i2c/ina2xx.txt for bindings
+The shunt value in micro-ohms can be set via platform data or device tree at
+compile-time or via the shunt_resistor attribute in sysfs at run-time. Please
+refer to the Documentation/devicetree/bindings/i2c/ina2xx.txt for bindings
if the device tree is used.
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index 3234e57..49537ea 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -115,6 +115,12 @@ static const struct ina2xx_config ina2xx_config[] = {
},
};
+static int ina2xx_calibrate(struct ina2xx_data *data)
+{
+ return i2c_smbus_write_word_swapped(data->client, INA2XX_CALIBRATION,
+ data->config->calibration_factor / data->rshunt);
+}
+
/*
* Initialize the configuration and calibration registers.
*/
@@ -133,8 +139,7 @@ static int ina2xx_init(struct ina2xx_data *data)
* Set current LSB to 1mA, shunt is in uOhms
* (equation 13 in datasheet).
*/
- return i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION,
- data->config->calibration_factor / data->rshunt);
+ return ina2xx_calibrate(data);
}
static int ina2xx_do_update(struct device *dev)
@@ -231,6 +236,9 @@ static int ina2xx_get_value(struct ina2xx_data *data, u8 reg)
/* signed register, LSB=1mA (selected), in mA */
val = (s16)data->regs[reg];
break;
+ case INA2XX_CALIBRATION:
+ val = data->config->calibration_factor / data->regs[reg];
+ break;
default:
/* programmer goofed */
WARN_ON_ONCE(1);
@@ -254,6 +262,36 @@ static ssize_t ina2xx_show_value(struct device *dev,
ina2xx_get_value(data, attr->index));
}
+static ssize_t ina2xx_set_shunt(struct device *dev,
+ struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ struct ina2xx_data *data = ina2xx_update_device(dev);
+ unsigned long val;
+ int status;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ status = kstrtoul(buf, 10, &val);
+ if (status < 0)
+ return status;
+
+ if (val = 0 ||
+ /* Values greater than the calibration factor make no sense. */
+ val > data->config->calibration_factor)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ data->rshunt = val;
+ status = ina2xx_calibrate(data);
+ mutex_unlock(&data->update_lock);
+ if (status < 0)
+ return status;
+
+ return count;
+}
+
/* shunt voltage */
static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ina2xx_show_value, NULL,
INA2XX_SHUNT_VOLTAGE);
@@ -270,12 +308,18 @@ static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ina2xx_show_value, NULL,
static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ina2xx_show_value, NULL,
INA2XX_POWER);
+/* shunt resistance */
+static SENSOR_DEVICE_ATTR(shunt_resistor, S_IRUGO | S_IWUSR,
+ ina2xx_show_value, ina2xx_set_shunt,
+ INA2XX_CALIBRATION);
+
/* pointers to created device attributes */
static struct attribute *ina2xx_attrs[] = {
&sensor_dev_attr_in0_input.dev_attr.attr,
&sensor_dev_attr_in1_input.dev_attr.attr,
&sensor_dev_attr_curr1_input.dev_attr.attr,
&sensor_dev_attr_power1_input.dev_attr.attr,
+ &sensor_dev_attr_shunt_resistor.dev_attr.attr,
NULL,
};
ATTRIBUTE_GROUPS(ina2xx);
--
2.1.3
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v7 4/5] hwmon: ina2xx: make shunt resistance configurable at run-time
@ 2014-12-13 16:27 ` Bartosz Golaszewski
0 siblings, 0 replies; 16+ messages in thread
From: Bartosz Golaszewski @ 2014-12-13 16:27 UTC (permalink / raw)
To: Guenter Roeck
Cc: LKML, Benoit Cousson, Patrick Titiano, LM Sensors,
Bartosz Golaszewski
The shunt resistance can only be set via platform_data or device tree. This
isn't suitable for devices in which the shunt resistance can change/isn't
known at boot-time.
Add a sysfs attribute that allows to read and set the shunt resistance.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
Documentation/hwmon/ina2xx | 5 +++--
drivers/hwmon/ina2xx.c | 48 ++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 49 insertions(+), 4 deletions(-)
diff --git a/Documentation/hwmon/ina2xx b/Documentation/hwmon/ina2xx
index 4223c2d..320dd69 100644
--- a/Documentation/hwmon/ina2xx
+++ b/Documentation/hwmon/ina2xx
@@ -44,6 +44,7 @@ The INA226 monitors both a shunt voltage drop and bus supply voltage.
The INA230 is a high or low side current shunt and power monitor with an I2C
interface. The INA230 monitors both a shunt voltage drop and bus supply voltage.
-The shunt value in micro-ohms can be set via platform data or device tree.
-Please refer to the Documentation/devicetree/bindings/i2c/ina2xx.txt for bindings
+The shunt value in micro-ohms can be set via platform data or device tree at
+compile-time or via the shunt_resistor attribute in sysfs at run-time. Please
+refer to the Documentation/devicetree/bindings/i2c/ina2xx.txt for bindings
if the device tree is used.
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index 3234e57..49537ea 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -115,6 +115,12 @@ static const struct ina2xx_config ina2xx_config[] = {
},
};
+static int ina2xx_calibrate(struct ina2xx_data *data)
+{
+ return i2c_smbus_write_word_swapped(data->client, INA2XX_CALIBRATION,
+ data->config->calibration_factor / data->rshunt);
+}
+
/*
* Initialize the configuration and calibration registers.
*/
@@ -133,8 +139,7 @@ static int ina2xx_init(struct ina2xx_data *data)
* Set current LSB to 1mA, shunt is in uOhms
* (equation 13 in datasheet).
*/
- return i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION,
- data->config->calibration_factor / data->rshunt);
+ return ina2xx_calibrate(data);
}
static int ina2xx_do_update(struct device *dev)
@@ -231,6 +236,9 @@ static int ina2xx_get_value(struct ina2xx_data *data, u8 reg)
/* signed register, LSB=1mA (selected), in mA */
val = (s16)data->regs[reg];
break;
+ case INA2XX_CALIBRATION:
+ val = data->config->calibration_factor / data->regs[reg];
+ break;
default:
/* programmer goofed */
WARN_ON_ONCE(1);
@@ -254,6 +262,36 @@ static ssize_t ina2xx_show_value(struct device *dev,
ina2xx_get_value(data, attr->index));
}
+static ssize_t ina2xx_set_shunt(struct device *dev,
+ struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ struct ina2xx_data *data = ina2xx_update_device(dev);
+ unsigned long val;
+ int status;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ status = kstrtoul(buf, 10, &val);
+ if (status < 0)
+ return status;
+
+ if (val == 0 ||
+ /* Values greater than the calibration factor make no sense. */
+ val > data->config->calibration_factor)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ data->rshunt = val;
+ status = ina2xx_calibrate(data);
+ mutex_unlock(&data->update_lock);
+ if (status < 0)
+ return status;
+
+ return count;
+}
+
/* shunt voltage */
static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ina2xx_show_value, NULL,
INA2XX_SHUNT_VOLTAGE);
@@ -270,12 +308,18 @@ static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ina2xx_show_value, NULL,
static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ina2xx_show_value, NULL,
INA2XX_POWER);
+/* shunt resistance */
+static SENSOR_DEVICE_ATTR(shunt_resistor, S_IRUGO | S_IWUSR,
+ ina2xx_show_value, ina2xx_set_shunt,
+ INA2XX_CALIBRATION);
+
/* pointers to created device attributes */
static struct attribute *ina2xx_attrs[] = {
&sensor_dev_attr_in0_input.dev_attr.attr,
&sensor_dev_attr_in1_input.dev_attr.attr,
&sensor_dev_attr_curr1_input.dev_attr.attr,
&sensor_dev_attr_power1_input.dev_attr.attr,
+ &sensor_dev_attr_shunt_resistor.dev_attr.attr,
NULL,
};
ATTRIBUTE_GROUPS(ina2xx);
--
2.1.3
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [lm-sensors] [PATCH v7 5/5] hwmon: ina2xx: allow to change the averaging rate at run-time
2014-12-13 16:27 ` Bartosz Golaszewski
@ 2014-12-13 16:27 ` Bartosz Golaszewski
-1 siblings, 0 replies; 16+ messages in thread
From: Bartosz Golaszewski @ 2014-12-13 16:27 UTC (permalink / raw)
To: Guenter Roeck
Cc: LKML, Benoit Cousson, Patrick Titiano, LM Sensors,
Bartosz Golaszewski
The averaging rate of ina226 is hardcoded to 16 in the driver. Make it
modifiable at run-time via a new sysfs attribute.
While we're at it - add an additional variable to ina2xx_data, which holds
the current configuration settings - this way we'll be able to restore the
configuration in case of an unexpected chip reset.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
Documentation/hwmon/ina2xx | 3 ++
drivers/hwmon/ina2xx.c | 132 +++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 131 insertions(+), 4 deletions(-)
diff --git a/Documentation/hwmon/ina2xx b/Documentation/hwmon/ina2xx
index 320dd69..a11256d 100644
--- a/Documentation/hwmon/ina2xx
+++ b/Documentation/hwmon/ina2xx
@@ -48,3 +48,6 @@ The shunt value in micro-ohms can be set via platform data or device tree at
compile-time or via the shunt_resistor attribute in sysfs at run-time. Please
refer to the Documentation/devicetree/bindings/i2c/ina2xx.txt for bindings
if the device tree is used.
+
+The averaging rate of INA226 and INA230 can be changed via the avg_rate sysfs
+attribute. The available rates are: 1, 4, 16, 64, 128, 256, 512 and 1024.
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index 49537ea..d6fccad 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -68,6 +68,15 @@
#define INA2XX_RSHUNT_DEFAULT 10000
+/* bit masks for the averaging setting in the configuration register */
+#define INA226_AVG_RD_MASK 0x0E00
+#define INA226_AVG_WR_MASK 0xF1FF
+
+#define INA226_READ_AVG(reg) ((reg & INA226_AVG_RD_MASK) >> 9)
+
+/* common attrs, ina226 attrs and NULL */
+#define INA2XX_MAX_ATTRIBUTE_GROUPS 3
+
enum ina2xx_ids { ina219, ina226 };
struct ina2xx_config {
@@ -85,12 +94,14 @@ struct ina2xx_data {
const struct ina2xx_config *config;
long rshunt;
+ u16 curr_config;
struct mutex update_lock;
bool valid;
unsigned long last_updated;
int kind;
+ const struct attribute_group *groups[INA2XX_MAX_ATTRIBUTE_GROUPS];
u16 regs[INA2XX_MAX_REGISTERS];
};
@@ -115,6 +126,38 @@ static const struct ina2xx_config ina2xx_config[] = {
},
};
+/*
+ * Available averaging rates for ina226. The indices correspond with
+ * the bit values expected by the chip (according to the ina226 datasheet,
+ * table 3 AVG bit settings, found at
+ * http://www.ti.com/lit/ds/symlink/ina226.pdf.
+ */
+static const int ina226_avg_tab[] = { 1, 4, 16, 64, 128, 256, 512, 1024 };
+
+static int ina226_avg_bits(int avg)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ina226_avg_tab); i++) {
+ if (avg = ina226_avg_tab[i])
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+static int ina226_avg_val(int bits)
+{
+ /*
+ * Value read from the config register should be correct, but do check
+ * the boundary just in case.
+ */
+ if (bits >= ARRAY_SIZE(ina226_avg_tab))
+ return -ENODEV;
+
+ return ina226_avg_tab[bits];
+}
+
static int ina2xx_calibrate(struct ina2xx_data *data)
{
return i2c_smbus_write_word_swapped(data->client, INA2XX_CALIBRATION,
@@ -131,7 +174,7 @@ static int ina2xx_init(struct ina2xx_data *data)
/* device configuration */
ret = i2c_smbus_write_word_swapped(client, INA2XX_CONFIG,
- data->config->config_default);
+ data->curr_config);
if (ret < 0)
return ret;
@@ -292,6 +335,66 @@ static ssize_t ina2xx_set_shunt(struct device *dev,
return count;
}
+static ssize_t ina226_show_avg(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct ina2xx_data *data = ina2xx_update_device(dev);
+ int avg, i, written = 0;
+ const char *fmt;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ avg = ina226_avg_val(INA226_READ_AVG(data->regs[INA2XX_CONFIG]));
+ if (avg < 0)
+ return avg;
+
+ for (i = 0; i < ARRAY_SIZE(ina226_avg_tab); i++) {
+ if (avg = ina226_avg_tab[i])
+ fmt = "\t[%d]";
+ else
+ fmt = "\t%d";
+
+ written += snprintf(buf + written, PAGE_SIZE - written,
+ fmt, ina226_avg_tab[i]);
+ }
+ written += snprintf(buf + written, PAGE_SIZE - written, "\n");
+
+ return written;
+}
+
+static ssize_t ina226_set_avg(struct device *dev,
+ struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ struct ina2xx_data *data = ina2xx_update_device(dev);
+ long val;
+ int status, avg;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ status = kstrtol(buf, 10, &val);
+ if (status < 0)
+ return status;
+
+ avg = ina226_avg_bits(val);
+ if (avg < 0)
+ return avg;
+
+ mutex_lock(&data->update_lock);
+ data->curr_config = (data->regs[INA2XX_CONFIG] &
+ INA226_AVG_WR_MASK) | (avg << 9);
+ status = i2c_smbus_write_word_swapped(data->client,
+ INA2XX_CONFIG,
+ data->curr_config);
+ mutex_unlock(&data->update_lock);
+ if (status < 0)
+ return status;
+
+ return count;
+}
+
/* shunt voltage */
static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ina2xx_show_value, NULL,
INA2XX_SHUNT_VOLTAGE);
@@ -313,6 +416,10 @@ static SENSOR_DEVICE_ATTR(shunt_resistor, S_IRUGO | S_IWUSR,
ina2xx_show_value, ina2xx_set_shunt,
INA2XX_CALIBRATION);
+/* averaging rate */
+static SENSOR_DEVICE_ATTR(avg_rate, S_IRUGO | S_IWUSR,
+ ina226_show_avg, ina226_set_avg, 0);
+
/* pointers to created device attributes */
static struct attribute *ina2xx_attrs[] = {
&sensor_dev_attr_in0_input.dev_attr.attr,
@@ -322,7 +429,19 @@ static struct attribute *ina2xx_attrs[] = {
&sensor_dev_attr_shunt_resistor.dev_attr.attr,
NULL,
};
-ATTRIBUTE_GROUPS(ina2xx);
+
+static const struct attribute_group ina2xx_group = {
+ .attrs = ina2xx_attrs,
+};
+
+static struct attribute *ina226_attrs[] = {
+ &sensor_dev_attr_avg_rate.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ina226_group = {
+ .attrs = ina226_attrs,
+};
static int ina2xx_probe(struct i2c_client *client,
const struct i2c_device_id *id)
@@ -333,7 +452,7 @@ static int ina2xx_probe(struct i2c_client *client,
struct ina2xx_data *data;
struct device *hwmon_dev;
u32 val;
- int ret;
+ int ret, group = 0;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
return -ENODEV;
@@ -355,6 +474,7 @@ static int ina2xx_probe(struct i2c_client *client,
/* set the device type */
data->kind = id->driver_data;
data->config = &ina2xx_config[data->kind];
+ data->curr_config = data->config->config_default;
data->client = client;
if (data->rshunt <= 0 ||
@@ -369,8 +489,12 @@ static int ina2xx_probe(struct i2c_client *client,
mutex_init(&data->update_lock);
+ data->groups[group++] = &ina2xx_group;
+ if (data->kind = ina226)
+ data->groups[group++] = &ina226_group;
+
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
- data, ina2xx_groups);
+ data, data->groups);
if (IS_ERR(hwmon_dev))
return PTR_ERR(hwmon_dev);
--
2.1.3
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v7 5/5] hwmon: ina2xx: allow to change the averaging rate at run-time
@ 2014-12-13 16:27 ` Bartosz Golaszewski
0 siblings, 0 replies; 16+ messages in thread
From: Bartosz Golaszewski @ 2014-12-13 16:27 UTC (permalink / raw)
To: Guenter Roeck
Cc: LKML, Benoit Cousson, Patrick Titiano, LM Sensors,
Bartosz Golaszewski
The averaging rate of ina226 is hardcoded to 16 in the driver. Make it
modifiable at run-time via a new sysfs attribute.
While we're at it - add an additional variable to ina2xx_data, which holds
the current configuration settings - this way we'll be able to restore the
configuration in case of an unexpected chip reset.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
Documentation/hwmon/ina2xx | 3 ++
drivers/hwmon/ina2xx.c | 132 +++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 131 insertions(+), 4 deletions(-)
diff --git a/Documentation/hwmon/ina2xx b/Documentation/hwmon/ina2xx
index 320dd69..a11256d 100644
--- a/Documentation/hwmon/ina2xx
+++ b/Documentation/hwmon/ina2xx
@@ -48,3 +48,6 @@ The shunt value in micro-ohms can be set via platform data or device tree at
compile-time or via the shunt_resistor attribute in sysfs at run-time. Please
refer to the Documentation/devicetree/bindings/i2c/ina2xx.txt for bindings
if the device tree is used.
+
+The averaging rate of INA226 and INA230 can be changed via the avg_rate sysfs
+attribute. The available rates are: 1, 4, 16, 64, 128, 256, 512 and 1024.
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index 49537ea..d6fccad 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -68,6 +68,15 @@
#define INA2XX_RSHUNT_DEFAULT 10000
+/* bit masks for the averaging setting in the configuration register */
+#define INA226_AVG_RD_MASK 0x0E00
+#define INA226_AVG_WR_MASK 0xF1FF
+
+#define INA226_READ_AVG(reg) ((reg & INA226_AVG_RD_MASK) >> 9)
+
+/* common attrs, ina226 attrs and NULL */
+#define INA2XX_MAX_ATTRIBUTE_GROUPS 3
+
enum ina2xx_ids { ina219, ina226 };
struct ina2xx_config {
@@ -85,12 +94,14 @@ struct ina2xx_data {
const struct ina2xx_config *config;
long rshunt;
+ u16 curr_config;
struct mutex update_lock;
bool valid;
unsigned long last_updated;
int kind;
+ const struct attribute_group *groups[INA2XX_MAX_ATTRIBUTE_GROUPS];
u16 regs[INA2XX_MAX_REGISTERS];
};
@@ -115,6 +126,38 @@ static const struct ina2xx_config ina2xx_config[] = {
},
};
+/*
+ * Available averaging rates for ina226. The indices correspond with
+ * the bit values expected by the chip (according to the ina226 datasheet,
+ * table 3 AVG bit settings, found at
+ * http://www.ti.com/lit/ds/symlink/ina226.pdf.
+ */
+static const int ina226_avg_tab[] = { 1, 4, 16, 64, 128, 256, 512, 1024 };
+
+static int ina226_avg_bits(int avg)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ina226_avg_tab); i++) {
+ if (avg == ina226_avg_tab[i])
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+static int ina226_avg_val(int bits)
+{
+ /*
+ * Value read from the config register should be correct, but do check
+ * the boundary just in case.
+ */
+ if (bits >= ARRAY_SIZE(ina226_avg_tab))
+ return -ENODEV;
+
+ return ina226_avg_tab[bits];
+}
+
static int ina2xx_calibrate(struct ina2xx_data *data)
{
return i2c_smbus_write_word_swapped(data->client, INA2XX_CALIBRATION,
@@ -131,7 +174,7 @@ static int ina2xx_init(struct ina2xx_data *data)
/* device configuration */
ret = i2c_smbus_write_word_swapped(client, INA2XX_CONFIG,
- data->config->config_default);
+ data->curr_config);
if (ret < 0)
return ret;
@@ -292,6 +335,66 @@ static ssize_t ina2xx_set_shunt(struct device *dev,
return count;
}
+static ssize_t ina226_show_avg(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct ina2xx_data *data = ina2xx_update_device(dev);
+ int avg, i, written = 0;
+ const char *fmt;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ avg = ina226_avg_val(INA226_READ_AVG(data->regs[INA2XX_CONFIG]));
+ if (avg < 0)
+ return avg;
+
+ for (i = 0; i < ARRAY_SIZE(ina226_avg_tab); i++) {
+ if (avg == ina226_avg_tab[i])
+ fmt = "\t[%d]";
+ else
+ fmt = "\t%d";
+
+ written += snprintf(buf + written, PAGE_SIZE - written,
+ fmt, ina226_avg_tab[i]);
+ }
+ written += snprintf(buf + written, PAGE_SIZE - written, "\n");
+
+ return written;
+}
+
+static ssize_t ina226_set_avg(struct device *dev,
+ struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ struct ina2xx_data *data = ina2xx_update_device(dev);
+ long val;
+ int status, avg;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ status = kstrtol(buf, 10, &val);
+ if (status < 0)
+ return status;
+
+ avg = ina226_avg_bits(val);
+ if (avg < 0)
+ return avg;
+
+ mutex_lock(&data->update_lock);
+ data->curr_config = (data->regs[INA2XX_CONFIG] &
+ INA226_AVG_WR_MASK) | (avg << 9);
+ status = i2c_smbus_write_word_swapped(data->client,
+ INA2XX_CONFIG,
+ data->curr_config);
+ mutex_unlock(&data->update_lock);
+ if (status < 0)
+ return status;
+
+ return count;
+}
+
/* shunt voltage */
static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ina2xx_show_value, NULL,
INA2XX_SHUNT_VOLTAGE);
@@ -313,6 +416,10 @@ static SENSOR_DEVICE_ATTR(shunt_resistor, S_IRUGO | S_IWUSR,
ina2xx_show_value, ina2xx_set_shunt,
INA2XX_CALIBRATION);
+/* averaging rate */
+static SENSOR_DEVICE_ATTR(avg_rate, S_IRUGO | S_IWUSR,
+ ina226_show_avg, ina226_set_avg, 0);
+
/* pointers to created device attributes */
static struct attribute *ina2xx_attrs[] = {
&sensor_dev_attr_in0_input.dev_attr.attr,
@@ -322,7 +429,19 @@ static struct attribute *ina2xx_attrs[] = {
&sensor_dev_attr_shunt_resistor.dev_attr.attr,
NULL,
};
-ATTRIBUTE_GROUPS(ina2xx);
+
+static const struct attribute_group ina2xx_group = {
+ .attrs = ina2xx_attrs,
+};
+
+static struct attribute *ina226_attrs[] = {
+ &sensor_dev_attr_avg_rate.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ina226_group = {
+ .attrs = ina226_attrs,
+};
static int ina2xx_probe(struct i2c_client *client,
const struct i2c_device_id *id)
@@ -333,7 +452,7 @@ static int ina2xx_probe(struct i2c_client *client,
struct ina2xx_data *data;
struct device *hwmon_dev;
u32 val;
- int ret;
+ int ret, group = 0;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
return -ENODEV;
@@ -355,6 +474,7 @@ static int ina2xx_probe(struct i2c_client *client,
/* set the device type */
data->kind = id->driver_data;
data->config = &ina2xx_config[data->kind];
+ data->curr_config = data->config->config_default;
data->client = client;
if (data->rshunt <= 0 ||
@@ -369,8 +489,12 @@ static int ina2xx_probe(struct i2c_client *client,
mutex_init(&data->update_lock);
+ data->groups[group++] = &ina2xx_group;
+ if (data->kind == ina226)
+ data->groups[group++] = &ina226_group;
+
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
- data, ina2xx_groups);
+ data, data->groups);
if (IS_ERR(hwmon_dev))
return PTR_ERR(hwmon_dev);
--
2.1.3
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [lm-sensors] [PATCH v7 0/5] hwmon: ina2xx: implement chip reinitialization and add new attribute
2014-12-13 16:27 ` Bartosz Golaszewski
@ 2014-12-20 3:23 ` Guenter Roeck
-1 siblings, 0 replies; 16+ messages in thread
From: Guenter Roeck @ 2014-12-20 3:23 UTC (permalink / raw)
To: Bartosz Golaszewski; +Cc: LKML, Benoit Cousson, Patrick Titiano, LM Sensors
On 12/13/2014 08:27 AM, Bartosz Golaszewski wrote:
> This series implements a mechanism to detect if the chip is in its POR state
> and reinitialize it if needed. It also extends the sysfs interface to make the
> driver configurable at run-time.
>
> The shunt_resistor attribute allows to change the shunt resistance value
> at run-time in cases where ina2xx used to do the measurement isn't integrated
> with the shunt.
>
> The avg_rate attribute allows to increase/decrease noise reduction.
>
> v7:
> - implemented a retry counter for the reinitialization procedure
> - using msleep() (since the sleep is > 20ms) instead of mdelay()
> when waiting for the chip update
>
> v6:
> https://www.mail-archive.com/linux-kernel%40vger.kernel.org/msg787390.html
>
> Bartosz Golaszewski (5):
> hwmon: ina2xx: reinitialize the chip in case it's been reset
> hwmon: ina2xx: remove a stray new line
> hwmon: ina2xx: don't accept shunt values greater than the calibration factor
> hwmon: ina2xx: make shunt resistance configurable at run-time
> hwmon: ina2xx: allow to change the averaging rate at run-time
>
> Documentation/hwmon/ina2xx | 8 +-
> drivers/hwmon/ina2xx.c | 304 +++++++++++++++++++++++++++++++++++++++------
> 2 files changed, 269 insertions(+), 43 deletions(-)
>
I didn't forget those patches; I have been busy in the last couple of weeks.
Also, I'll be out for the next two weeks. I'll look into the patches after
I am back.
Guenter
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v7 0/5] hwmon: ina2xx: implement chip reinitialization and add new attributes
@ 2014-12-20 3:23 ` Guenter Roeck
0 siblings, 0 replies; 16+ messages in thread
From: Guenter Roeck @ 2014-12-20 3:23 UTC (permalink / raw)
To: Bartosz Golaszewski; +Cc: LKML, Benoit Cousson, Patrick Titiano, LM Sensors
On 12/13/2014 08:27 AM, Bartosz Golaszewski wrote:
> This series implements a mechanism to detect if the chip is in its POR state
> and reinitialize it if needed. It also extends the sysfs interface to make the
> driver configurable at run-time.
>
> The shunt_resistor attribute allows to change the shunt resistance value
> at run-time in cases where ina2xx used to do the measurement isn't integrated
> with the shunt.
>
> The avg_rate attribute allows to increase/decrease noise reduction.
>
> v7:
> - implemented a retry counter for the reinitialization procedure
> - using msleep() (since the sleep is > 20ms) instead of mdelay()
> when waiting for the chip update
>
> v6:
> https://www.mail-archive.com/linux-kernel%40vger.kernel.org/msg787390.html
>
> Bartosz Golaszewski (5):
> hwmon: ina2xx: reinitialize the chip in case it's been reset
> hwmon: ina2xx: remove a stray new line
> hwmon: ina2xx: don't accept shunt values greater than the calibration factor
> hwmon: ina2xx: make shunt resistance configurable at run-time
> hwmon: ina2xx: allow to change the averaging rate at run-time
>
> Documentation/hwmon/ina2xx | 8 +-
> drivers/hwmon/ina2xx.c | 304 +++++++++++++++++++++++++++++++++++++++------
> 2 files changed, 269 insertions(+), 43 deletions(-)
>
I didn't forget those patches; I have been busy in the last couple of weeks.
Also, I'll be out for the next two weeks. I'll look into the patches after
I am back.
Guenter
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [lm-sensors] [v7, 5/5] hwmon: ina2xx: allow to change the averaging rate at run-time
2014-12-13 16:27 ` Bartosz Golaszewski
@ 2014-12-21 16:36 ` Guenter Roeck
-1 siblings, 0 replies; 16+ messages in thread
From: Guenter Roeck @ 2014-12-21 16:36 UTC (permalink / raw)
To: Bartosz Golaszewski; +Cc: Patrick Titiano, LKML, Benoit Cousson, LM Sensors
On Sat, Dec 13, 2014 at 05:27:21PM +0100, Bartosz Golaszewski wrote:
> The averaging rate of ina226 is hardcoded to 16 in the driver. Make it
> modifiable at run-time via a new sysfs attribute.
>
> While we're at it - add an additional variable to ina2xx_data, which holds
> the current configuration settings - this way we'll be able to restore the
> configuration in case of an unexpected chip reset.
>
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> ---
> Documentation/hwmon/ina2xx | 3 ++
> drivers/hwmon/ina2xx.c | 132 +++++++++++++++++++++++++++++++++++++++++++--
> 2 files changed, 131 insertions(+), 4 deletions(-)
>
> diff --git a/Documentation/hwmon/ina2xx b/Documentation/hwmon/ina2xx
> index 320dd69..a11256d 100644
> --- a/Documentation/hwmon/ina2xx
> +++ b/Documentation/hwmon/ina2xx
> @@ -48,3 +48,6 @@ The shunt value in micro-ohms can be set via platform data or device tree at
> compile-time or via the shunt_resistor attribute in sysfs at run-time. Please
> refer to the Documentation/devicetree/bindings/i2c/ina2xx.txt for bindings
> if the device tree is used.
> +
> +The averaging rate of INA226 and INA230 can be changed via the avg_rate sysfs
> +attribute. The available rates are: 1, 4, 16, 64, 128, 256, 512 and 1024.
> diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
> index 49537ea..d6fccad 100644
> --- a/drivers/hwmon/ina2xx.c
> +++ b/drivers/hwmon/ina2xx.c
> @@ -68,6 +68,15 @@
>
> #define INA2XX_RSHUNT_DEFAULT 10000
>
> +/* bit masks for the averaging setting in the configuration register */
> +#define INA226_AVG_RD_MASK 0x0E00
> +#define INA226_AVG_WR_MASK 0xF1FF
> +
> +#define INA226_READ_AVG(reg) ((reg & INA226_AVG_RD_MASK) >> 9)
> +
> +/* common attrs, ina226 attrs and NULL */
> +#define INA2XX_MAX_ATTRIBUTE_GROUPS 3
> +
> enum ina2xx_ids { ina219, ina226 };
>
> struct ina2xx_config {
> @@ -85,12 +94,14 @@ struct ina2xx_data {
> const struct ina2xx_config *config;
>
> long rshunt;
> + u16 curr_config;
>
> struct mutex update_lock;
> bool valid;
> unsigned long last_updated;
>
> int kind;
> + const struct attribute_group *groups[INA2XX_MAX_ATTRIBUTE_GROUPS];
> u16 regs[INA2XX_MAX_REGISTERS];
> };
>
> @@ -115,6 +126,38 @@ static const struct ina2xx_config ina2xx_config[] = {
> },
> };
>
> +/*
> + * Available averaging rates for ina226. The indices correspond with
> + * the bit values expected by the chip (according to the ina226 datasheet,
> + * table 3 AVG bit settings, found at
> + * http://www.ti.com/lit/ds/symlink/ina226.pdf.
> + */
> +static const int ina226_avg_tab[] = { 1, 4, 16, 64, 128, 256, 512, 1024 };
> +
> +static int ina226_avg_bits(int avg)
> +{
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(ina226_avg_tab); i++) {
> + if (avg = ina226_avg_tab[i])
> + return i;
I would suggest to select the closest valid average.
> + }
> +
> + return -EINVAL;
> +}
> +
> +static int ina226_avg_val(int bits)
> +{
> + /*
> + * Value read from the config register should be correct, but do check
> + * the boundary just in case.
> + */
> + if (bits >= ARRAY_SIZE(ina226_avg_tab))
> + return -ENODEV;
> +
> + return ina226_avg_tab[bits];
> +}
> +
> static int ina2xx_calibrate(struct ina2xx_data *data)
> {
> return i2c_smbus_write_word_swapped(data->client, INA2XX_CALIBRATION,
> @@ -131,7 +174,7 @@ static int ina2xx_init(struct ina2xx_data *data)
>
> /* device configuration */
> ret = i2c_smbus_write_word_swapped(client, INA2XX_CONFIG,
> - data->config->config_default);
> + data->curr_config);
> if (ret < 0)
> return ret;
>
> @@ -292,6 +335,66 @@ static ssize_t ina2xx_set_shunt(struct device *dev,
> return count;
> }
>
> +static ssize_t ina226_show_avg(struct device *dev,
> + struct device_attribute *da, char *buf)
> +{
> + struct ina2xx_data *data = ina2xx_update_device(dev);
> + int avg, i, written = 0;
> + const char *fmt;
> +
> + if (IS_ERR(data))
> + return PTR_ERR(data);
> +
> + avg = ina226_avg_val(INA226_READ_AVG(data->regs[INA2XX_CONFIG]));
> + if (avg < 0)
> + return avg;
> +
> + for (i = 0; i < ARRAY_SIZE(ina226_avg_tab); i++) {
> + if (avg = ina226_avg_tab[i])
> + fmt = "\t[%d]";
> + else
> + fmt = "\t%d";
> +
> + written += snprintf(buf + written, PAGE_SIZE - written,
> + fmt, ina226_avg_tab[i]);
> + }
> + written += snprintf(buf + written, PAGE_SIZE - written, "\n");
> +
No. sysfs attributes return a single value, not a range.
So you have to return the current value here and nothing else.
This is why it would be better to be more flexibe when accepting a new average.
> + return written;
> +}
> +
> +static ssize_t ina226_set_avg(struct device *dev,
> + struct device_attribute *da,
> + const char *buf, size_t count)
> +{
> + struct ina2xx_data *data = ina2xx_update_device(dev);
Calling update_device here is not necessary.
> + long val;
> + int status, avg;
> +
> + if (IS_ERR(data))
> + return PTR_ERR(data);
> +
> + status = kstrtol(buf, 10, &val);
> + if (status < 0)
> + return status;
> +
> + avg = ina226_avg_bits(val);
> + if (avg < 0)
> + return avg;
> +
> + mutex_lock(&data->update_lock);
> + data->curr_config = (data->regs[INA2XX_CONFIG] &
> + INA226_AVG_WR_MASK) | (avg << 9);
> + status = i2c_smbus_write_word_swapped(data->client,
> + INA2XX_CONFIG,
> + data->curr_config);
You should set data->valid to 0 here to ensure that the next access
re-reads all registers.
> + mutex_unlock(&data->update_lock);
> + if (status < 0)
> + return status;
> +
> + return count;
> +}
> +
> /* shunt voltage */
> static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ina2xx_show_value, NULL,
> INA2XX_SHUNT_VOLTAGE);
> @@ -313,6 +416,10 @@ static SENSOR_DEVICE_ATTR(shunt_resistor, S_IRUGO | S_IWUSR,
> ina2xx_show_value, ina2xx_set_shunt,
> INA2XX_CALIBRATION);
>
> +/* averaging rate */
> +static SENSOR_DEVICE_ATTR(avg_rate, S_IRUGO | S_IWUSR,
> + ina226_show_avg, ina226_set_avg, 0);
> +
> /* pointers to created device attributes */
> static struct attribute *ina2xx_attrs[] = {
> &sensor_dev_attr_in0_input.dev_attr.attr,
> @@ -322,7 +429,19 @@ static struct attribute *ina2xx_attrs[] = {
> &sensor_dev_attr_shunt_resistor.dev_attr.attr,
> NULL,
> };
> -ATTRIBUTE_GROUPS(ina2xx);
> +
> +static const struct attribute_group ina2xx_group = {
> + .attrs = ina2xx_attrs,
> +};
> +
> +static struct attribute *ina226_attrs[] = {
> + &sensor_dev_attr_avg_rate.dev_attr.attr,
> + NULL,
> +};
> +
> +static const struct attribute_group ina226_group = {
> + .attrs = ina226_attrs,
> +};
>
> static int ina2xx_probe(struct i2c_client *client,
> const struct i2c_device_id *id)
> @@ -333,7 +452,7 @@ static int ina2xx_probe(struct i2c_client *client,
> struct ina2xx_data *data;
> struct device *hwmon_dev;
> u32 val;
> - int ret;
> + int ret, group = 0;
>
> if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
> return -ENODEV;
> @@ -355,6 +474,7 @@ static int ina2xx_probe(struct i2c_client *client,
> /* set the device type */
> data->kind = id->driver_data;
> data->config = &ina2xx_config[data->kind];
> + data->curr_config = data->config->config_default;
> data->client = client;
>
> if (data->rshunt <= 0 ||
> @@ -369,8 +489,12 @@ static int ina2xx_probe(struct i2c_client *client,
>
> mutex_init(&data->update_lock);
>
> + data->groups[group++] = &ina2xx_group;
> + if (data->kind = ina226)
> + data->groups[group++] = &ina226_group;
> +
> hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
> - data, ina2xx_groups);
> + data, data->groups);
> if (IS_ERR(hwmon_dev))
> return PTR_ERR(hwmon_dev);
>
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [v7, 5/5] hwmon: ina2xx: allow to change the averaging rate at run-time
@ 2014-12-21 16:36 ` Guenter Roeck
0 siblings, 0 replies; 16+ messages in thread
From: Guenter Roeck @ 2014-12-21 16:36 UTC (permalink / raw)
To: Bartosz Golaszewski; +Cc: Patrick Titiano, LKML, Benoit Cousson, LM Sensors
On Sat, Dec 13, 2014 at 05:27:21PM +0100, Bartosz Golaszewski wrote:
> The averaging rate of ina226 is hardcoded to 16 in the driver. Make it
> modifiable at run-time via a new sysfs attribute.
>
> While we're at it - add an additional variable to ina2xx_data, which holds
> the current configuration settings - this way we'll be able to restore the
> configuration in case of an unexpected chip reset.
>
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> ---
> Documentation/hwmon/ina2xx | 3 ++
> drivers/hwmon/ina2xx.c | 132 +++++++++++++++++++++++++++++++++++++++++++--
> 2 files changed, 131 insertions(+), 4 deletions(-)
>
> diff --git a/Documentation/hwmon/ina2xx b/Documentation/hwmon/ina2xx
> index 320dd69..a11256d 100644
> --- a/Documentation/hwmon/ina2xx
> +++ b/Documentation/hwmon/ina2xx
> @@ -48,3 +48,6 @@ The shunt value in micro-ohms can be set via platform data or device tree at
> compile-time or via the shunt_resistor attribute in sysfs at run-time. Please
> refer to the Documentation/devicetree/bindings/i2c/ina2xx.txt for bindings
> if the device tree is used.
> +
> +The averaging rate of INA226 and INA230 can be changed via the avg_rate sysfs
> +attribute. The available rates are: 1, 4, 16, 64, 128, 256, 512 and 1024.
> diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
> index 49537ea..d6fccad 100644
> --- a/drivers/hwmon/ina2xx.c
> +++ b/drivers/hwmon/ina2xx.c
> @@ -68,6 +68,15 @@
>
> #define INA2XX_RSHUNT_DEFAULT 10000
>
> +/* bit masks for the averaging setting in the configuration register */
> +#define INA226_AVG_RD_MASK 0x0E00
> +#define INA226_AVG_WR_MASK 0xF1FF
> +
> +#define INA226_READ_AVG(reg) ((reg & INA226_AVG_RD_MASK) >> 9)
> +
> +/* common attrs, ina226 attrs and NULL */
> +#define INA2XX_MAX_ATTRIBUTE_GROUPS 3
> +
> enum ina2xx_ids { ina219, ina226 };
>
> struct ina2xx_config {
> @@ -85,12 +94,14 @@ struct ina2xx_data {
> const struct ina2xx_config *config;
>
> long rshunt;
> + u16 curr_config;
>
> struct mutex update_lock;
> bool valid;
> unsigned long last_updated;
>
> int kind;
> + const struct attribute_group *groups[INA2XX_MAX_ATTRIBUTE_GROUPS];
> u16 regs[INA2XX_MAX_REGISTERS];
> };
>
> @@ -115,6 +126,38 @@ static const struct ina2xx_config ina2xx_config[] = {
> },
> };
>
> +/*
> + * Available averaging rates for ina226. The indices correspond with
> + * the bit values expected by the chip (according to the ina226 datasheet,
> + * table 3 AVG bit settings, found at
> + * http://www.ti.com/lit/ds/symlink/ina226.pdf.
> + */
> +static const int ina226_avg_tab[] = { 1, 4, 16, 64, 128, 256, 512, 1024 };
> +
> +static int ina226_avg_bits(int avg)
> +{
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(ina226_avg_tab); i++) {
> + if (avg == ina226_avg_tab[i])
> + return i;
I would suggest to select the closest valid average.
> + }
> +
> + return -EINVAL;
> +}
> +
> +static int ina226_avg_val(int bits)
> +{
> + /*
> + * Value read from the config register should be correct, but do check
> + * the boundary just in case.
> + */
> + if (bits >= ARRAY_SIZE(ina226_avg_tab))
> + return -ENODEV;
> +
> + return ina226_avg_tab[bits];
> +}
> +
> static int ina2xx_calibrate(struct ina2xx_data *data)
> {
> return i2c_smbus_write_word_swapped(data->client, INA2XX_CALIBRATION,
> @@ -131,7 +174,7 @@ static int ina2xx_init(struct ina2xx_data *data)
>
> /* device configuration */
> ret = i2c_smbus_write_word_swapped(client, INA2XX_CONFIG,
> - data->config->config_default);
> + data->curr_config);
> if (ret < 0)
> return ret;
>
> @@ -292,6 +335,66 @@ static ssize_t ina2xx_set_shunt(struct device *dev,
> return count;
> }
>
> +static ssize_t ina226_show_avg(struct device *dev,
> + struct device_attribute *da, char *buf)
> +{
> + struct ina2xx_data *data = ina2xx_update_device(dev);
> + int avg, i, written = 0;
> + const char *fmt;
> +
> + if (IS_ERR(data))
> + return PTR_ERR(data);
> +
> + avg = ina226_avg_val(INA226_READ_AVG(data->regs[INA2XX_CONFIG]));
> + if (avg < 0)
> + return avg;
> +
> + for (i = 0; i < ARRAY_SIZE(ina226_avg_tab); i++) {
> + if (avg == ina226_avg_tab[i])
> + fmt = "\t[%d]";
> + else
> + fmt = "\t%d";
> +
> + written += snprintf(buf + written, PAGE_SIZE - written,
> + fmt, ina226_avg_tab[i]);
> + }
> + written += snprintf(buf + written, PAGE_SIZE - written, "\n");
> +
No. sysfs attributes return a single value, not a range.
So you have to return the current value here and nothing else.
This is why it would be better to be more flexibe when accepting a new average.
> + return written;
> +}
> +
> +static ssize_t ina226_set_avg(struct device *dev,
> + struct device_attribute *da,
> + const char *buf, size_t count)
> +{
> + struct ina2xx_data *data = ina2xx_update_device(dev);
Calling update_device here is not necessary.
> + long val;
> + int status, avg;
> +
> + if (IS_ERR(data))
> + return PTR_ERR(data);
> +
> + status = kstrtol(buf, 10, &val);
> + if (status < 0)
> + return status;
> +
> + avg = ina226_avg_bits(val);
> + if (avg < 0)
> + return avg;
> +
> + mutex_lock(&data->update_lock);
> + data->curr_config = (data->regs[INA2XX_CONFIG] &
> + INA226_AVG_WR_MASK) | (avg << 9);
> + status = i2c_smbus_write_word_swapped(data->client,
> + INA2XX_CONFIG,
> + data->curr_config);
You should set data->valid to 0 here to ensure that the next access
re-reads all registers.
> + mutex_unlock(&data->update_lock);
> + if (status < 0)
> + return status;
> +
> + return count;
> +}
> +
> /* shunt voltage */
> static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ina2xx_show_value, NULL,
> INA2XX_SHUNT_VOLTAGE);
> @@ -313,6 +416,10 @@ static SENSOR_DEVICE_ATTR(shunt_resistor, S_IRUGO | S_IWUSR,
> ina2xx_show_value, ina2xx_set_shunt,
> INA2XX_CALIBRATION);
>
> +/* averaging rate */
> +static SENSOR_DEVICE_ATTR(avg_rate, S_IRUGO | S_IWUSR,
> + ina226_show_avg, ina226_set_avg, 0);
> +
> /* pointers to created device attributes */
> static struct attribute *ina2xx_attrs[] = {
> &sensor_dev_attr_in0_input.dev_attr.attr,
> @@ -322,7 +429,19 @@ static struct attribute *ina2xx_attrs[] = {
> &sensor_dev_attr_shunt_resistor.dev_attr.attr,
> NULL,
> };
> -ATTRIBUTE_GROUPS(ina2xx);
> +
> +static const struct attribute_group ina2xx_group = {
> + .attrs = ina2xx_attrs,
> +};
> +
> +static struct attribute *ina226_attrs[] = {
> + &sensor_dev_attr_avg_rate.dev_attr.attr,
> + NULL,
> +};
> +
> +static const struct attribute_group ina226_group = {
> + .attrs = ina226_attrs,
> +};
>
> static int ina2xx_probe(struct i2c_client *client,
> const struct i2c_device_id *id)
> @@ -333,7 +452,7 @@ static int ina2xx_probe(struct i2c_client *client,
> struct ina2xx_data *data;
> struct device *hwmon_dev;
> u32 val;
> - int ret;
> + int ret, group = 0;
>
> if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
> return -ENODEV;
> @@ -355,6 +474,7 @@ static int ina2xx_probe(struct i2c_client *client,
> /* set the device type */
> data->kind = id->driver_data;
> data->config = &ina2xx_config[data->kind];
> + data->curr_config = data->config->config_default;
> data->client = client;
>
> if (data->rshunt <= 0 ||
> @@ -369,8 +489,12 @@ static int ina2xx_probe(struct i2c_client *client,
>
> mutex_init(&data->update_lock);
>
> + data->groups[group++] = &ina2xx_group;
> + if (data->kind == ina226)
> + data->groups[group++] = &ina226_group;
> +
> hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
> - data, ina2xx_groups);
> + data, data->groups);
> if (IS_ERR(hwmon_dev))
> return PTR_ERR(hwmon_dev);
>
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2014-12-21 16:36 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-12-13 16:27 [lm-sensors] [PATCH v7 0/5] hwmon: ina2xx: implement chip reinitialization and add new attributes Bartosz Golaszewski
2014-12-13 16:27 ` Bartosz Golaszewski
2014-12-13 16:27 ` [lm-sensors] [PATCH v7 1/5] hwmon: ina2xx: reinitialize the chip in case it's been reset Bartosz Golaszewski
2014-12-13 16:27 ` Bartosz Golaszewski
2014-12-13 16:27 ` [lm-sensors] [PATCH v7 2/5] hwmon: ina2xx: remove a stray new line Bartosz Golaszewski
2014-12-13 16:27 ` Bartosz Golaszewski
2014-12-13 16:27 ` [lm-sensors] [PATCH v7 3/5] hwmon: ina2xx: don't accept shunt values greater than the calibration fa Bartosz Golaszewski
2014-12-13 16:27 ` [PATCH v7 3/5] hwmon: ina2xx: don't accept shunt values greater than the calibration factor Bartosz Golaszewski
2014-12-13 16:27 ` [lm-sensors] [PATCH v7 4/5] hwmon: ina2xx: make shunt resistance configurable at run-time Bartosz Golaszewski
2014-12-13 16:27 ` Bartosz Golaszewski
2014-12-13 16:27 ` [lm-sensors] [PATCH v7 5/5] hwmon: ina2xx: allow to change the averaging rate " Bartosz Golaszewski
2014-12-13 16:27 ` Bartosz Golaszewski
2014-12-21 16:36 ` [lm-sensors] [v7, " Guenter Roeck
2014-12-21 16:36 ` Guenter Roeck
2014-12-20 3:23 ` [lm-sensors] [PATCH v7 0/5] hwmon: ina2xx: implement chip reinitialization and add new attribute Guenter Roeck
2014-12-20 3:23 ` [PATCH v7 0/5] hwmon: ina2xx: implement chip reinitialization and add new attributes Guenter Roeck
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.