aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/ina2xx.c
diff options
context:
space:
mode:
authorBartosz Golaszewski <bgolaszewski@baylibre.com>2015-01-09 11:03:42 -0500
committerGuenter Roeck <linux@roeck-us.net>2015-01-26 00:23:59 -0500
commit72a87a47a81e062fc27b7675db33cf29458bc6d2 (patch)
tree36b42c9ca7a0f0874992c483b4687a7c57aeab4d /drivers/hwmon/ina2xx.c
parent8a5fc79513afe325fd755026299d0bfdb47e42de (diff)
hwmon: (ina2xx) implement update_interval attribute for ina226
This attribute allows to configure the update interval of ina226. Although the bus and shunt voltage conversion times remain hardcoded to 1.1 ms, we can now modify said interval by changing the averaging rate. 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> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Diffstat (limited to 'drivers/hwmon/ina2xx.c')
-rw-r--r--drivers/hwmon/ina2xx.c164
1 files changed, 158 insertions, 6 deletions
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index 49537ea80748..a16d6a283286 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -68,6 +68,21 @@
68 68
69#define INA2XX_RSHUNT_DEFAULT 10000 69#define INA2XX_RSHUNT_DEFAULT 10000
70 70
71/* bit mask for reading the averaging setting in the configuration register */
72#define INA226_AVG_RD_MASK 0x0E00
73
74#define INA226_READ_AVG(reg) (((reg) & INA226_AVG_RD_MASK) >> 9)
75#define INA226_SHIFT_AVG(val) ((val) << 9)
76
77/* common attrs, ina226 attrs and NULL */
78#define INA2XX_MAX_ATTRIBUTE_GROUPS 3
79
80/*
81 * Both bus voltage and shunt voltage conversion times for ina226 are set
82 * to 0b0100 on POR, which translates to 2200 microseconds in total.
83 */
84#define INA226_TOTAL_CONV_TIME_DEFAULT 2200
85
71enum ina2xx_ids { ina219, ina226 }; 86enum ina2xx_ids { ina219, ina226 };
72 87
73struct ina2xx_config { 88struct ina2xx_config {
@@ -85,12 +100,15 @@ struct ina2xx_data {
85 const struct ina2xx_config *config; 100 const struct ina2xx_config *config;
86 101
87 long rshunt; 102 long rshunt;
103 u16 curr_config;
88 104
89 struct mutex update_lock; 105 struct mutex update_lock;
90 bool valid; 106 bool valid;
91 unsigned long last_updated; 107 unsigned long last_updated;
108 int update_interval; /* in jiffies */
92 109
93 int kind; 110 int kind;
111 const struct attribute_group *groups[INA2XX_MAX_ATTRIBUTE_GROUPS];
94 u16 regs[INA2XX_MAX_REGISTERS]; 112 u16 regs[INA2XX_MAX_REGISTERS];
95}; 113};
96 114
@@ -115,6 +133,57 @@ static const struct ina2xx_config ina2xx_config[] = {
115 }, 133 },
116}; 134};
117 135
136/*
137 * Available averaging rates for ina226. The indices correspond with
138 * the bit values expected by the chip (according to the ina226 datasheet,
139 * table 3 AVG bit settings, found at
140 * http://www.ti.com/lit/ds/symlink/ina226.pdf.
141 */
142static const int ina226_avg_tab[] = { 1, 4, 16, 64, 128, 256, 512, 1024 };
143
144static int ina226_avg_bits(int avg)
145{
146 int i;
147
148 /* Get the closest average from the tab. */
149 for (i = 0; i < ARRAY_SIZE(ina226_avg_tab) - 1; i++) {
150 if (avg <= (ina226_avg_tab[i] + ina226_avg_tab[i + 1]) / 2)
151 break;
152 }
153
154 return i; /* Return 0b0111 for values greater than 1024. */
155}
156
157static int ina226_reg_to_interval(u16 config)
158{
159 int avg = ina226_avg_tab[INA226_READ_AVG(config)];
160
161 /*
162 * Multiply the total conversion time by the number of averages.
163 * Return the result in milliseconds.
164 */
165 return DIV_ROUND_CLOSEST(avg * INA226_TOTAL_CONV_TIME_DEFAULT, 1000);
166}
167
168static u16 ina226_interval_to_reg(int interval, u16 config)
169{
170 int avg, avg_bits;
171
172 avg = DIV_ROUND_CLOSEST(interval * 1000,
173 INA226_TOTAL_CONV_TIME_DEFAULT);
174 avg_bits = ina226_avg_bits(avg);
175
176 return (config & ~INA226_AVG_RD_MASK) | INA226_SHIFT_AVG(avg_bits);
177}
178
179static void ina226_set_update_interval(struct ina2xx_data *data)
180{
181 int ms;
182
183 ms = ina226_reg_to_interval(data->curr_config);
184 data->update_interval = msecs_to_jiffies(ms);
185}
186
118static int ina2xx_calibrate(struct ina2xx_data *data) 187static int ina2xx_calibrate(struct ina2xx_data *data)
119{ 188{
120 return i2c_smbus_write_word_swapped(data->client, INA2XX_CALIBRATION, 189 return i2c_smbus_write_word_swapped(data->client, INA2XX_CALIBRATION,
@@ -131,7 +200,7 @@ static int ina2xx_init(struct ina2xx_data *data)
131 200
132 /* device configuration */ 201 /* device configuration */
133 ret = i2c_smbus_write_word_swapped(client, INA2XX_CONFIG, 202 ret = i2c_smbus_write_word_swapped(client, INA2XX_CONFIG,
134 data->config->config_default); 203 data->curr_config);
135 if (ret < 0) 204 if (ret < 0)
136 return ret; 205 return ret;
137 206
@@ -199,12 +268,13 @@ static struct ina2xx_data *ina2xx_update_device(struct device *dev)
199{ 268{
200 struct ina2xx_data *data = dev_get_drvdata(dev); 269 struct ina2xx_data *data = dev_get_drvdata(dev);
201 struct ina2xx_data *ret = data; 270 struct ina2xx_data *ret = data;
271 unsigned long after;
202 int rv; 272 int rv;
203 273
204 mutex_lock(&data->update_lock); 274 mutex_lock(&data->update_lock);
205 275
206 if (time_after(jiffies, data->last_updated + 276 after = data->last_updated + data->update_interval;
207 HZ / INA2XX_CONVERSION_RATE) || !data->valid) { 277 if (time_after(jiffies, after) || !data->valid) {
208 rv = ina2xx_do_update(dev); 278 rv = ina2xx_do_update(dev);
209 if (rv < 0) 279 if (rv < 0)
210 ret = ERR_PTR(rv); 280 ret = ERR_PTR(rv);
@@ -292,6 +362,58 @@ static ssize_t ina2xx_set_shunt(struct device *dev,
292 return count; 362 return count;
293} 363}
294 364
365static ssize_t ina226_set_interval(struct device *dev,
366 struct device_attribute *da,
367 const char *buf, size_t count)
368{
369 struct ina2xx_data *data = dev_get_drvdata(dev);
370 unsigned long val;
371 int status;
372
373 if (IS_ERR(data))
374 return PTR_ERR(data);
375
376 status = kstrtoul(buf, 10, &val);
377 if (status < 0)
378 return status;
379
380 if (val > INT_MAX || val == 0)
381 return -EINVAL;
382
383 mutex_lock(&data->update_lock);
384 data->curr_config = ina226_interval_to_reg(val,
385 data->regs[INA2XX_CONFIG]);
386 status = i2c_smbus_write_word_swapped(data->client,
387 INA2XX_CONFIG,
388 data->curr_config);
389
390 ina226_set_update_interval(data);
391 /* Make sure the next access re-reads all registers. */
392 data->valid = 0;
393 mutex_unlock(&data->update_lock);
394 if (status < 0)
395 return status;
396
397 return count;
398}
399
400static ssize_t ina226_show_interval(struct device *dev,
401 struct device_attribute *da, char *buf)
402{
403 struct ina2xx_data *data = ina2xx_update_device(dev);
404
405 if (IS_ERR(data))
406 return PTR_ERR(data);
407
408 /*
409 * We don't use data->update_interval here as we want to display
410 * the actual interval used by the chip and jiffies_to_msecs()
411 * doesn't seem to be accurate enough.
412 */
413 return snprintf(buf, PAGE_SIZE, "%d\n",
414 ina226_reg_to_interval(data->regs[INA2XX_CONFIG]));
415}
416
295/* shunt voltage */ 417/* shunt voltage */
296static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ina2xx_show_value, NULL, 418static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ina2xx_show_value, NULL,
297 INA2XX_SHUNT_VOLTAGE); 419 INA2XX_SHUNT_VOLTAGE);
@@ -313,6 +435,10 @@ static SENSOR_DEVICE_ATTR(shunt_resistor, S_IRUGO | S_IWUSR,
313 ina2xx_show_value, ina2xx_set_shunt, 435 ina2xx_show_value, ina2xx_set_shunt,
314 INA2XX_CALIBRATION); 436 INA2XX_CALIBRATION);
315 437
438/* update interval (ina226 only) */
439static SENSOR_DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR,
440 ina226_show_interval, ina226_set_interval, 0);
441
316/* pointers to created device attributes */ 442/* pointers to created device attributes */
317static struct attribute *ina2xx_attrs[] = { 443static struct attribute *ina2xx_attrs[] = {
318 &sensor_dev_attr_in0_input.dev_attr.attr, 444 &sensor_dev_attr_in0_input.dev_attr.attr,
@@ -322,7 +448,19 @@ static struct attribute *ina2xx_attrs[] = {
322 &sensor_dev_attr_shunt_resistor.dev_attr.attr, 448 &sensor_dev_attr_shunt_resistor.dev_attr.attr,
323 NULL, 449 NULL,
324}; 450};
325ATTRIBUTE_GROUPS(ina2xx); 451
452static const struct attribute_group ina2xx_group = {
453 .attrs = ina2xx_attrs,
454};
455
456static struct attribute *ina226_attrs[] = {
457 &sensor_dev_attr_update_interval.dev_attr.attr,
458 NULL,
459};
460
461static const struct attribute_group ina226_group = {
462 .attrs = ina226_attrs,
463};
326 464
327static int ina2xx_probe(struct i2c_client *client, 465static int ina2xx_probe(struct i2c_client *client,
328 const struct i2c_device_id *id) 466 const struct i2c_device_id *id)
@@ -333,7 +471,7 @@ static int ina2xx_probe(struct i2c_client *client,
333 struct ina2xx_data *data; 471 struct ina2xx_data *data;
334 struct device *hwmon_dev; 472 struct device *hwmon_dev;
335 u32 val; 473 u32 val;
336 int ret; 474 int ret, group = 0;
337 475
338 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) 476 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
339 return -ENODEV; 477 return -ENODEV;
@@ -355,8 +493,18 @@ static int ina2xx_probe(struct i2c_client *client,
355 /* set the device type */ 493 /* set the device type */
356 data->kind = id->driver_data; 494 data->kind = id->driver_data;
357 data->config = &ina2xx_config[data->kind]; 495 data->config = &ina2xx_config[data->kind];
496 data->curr_config = data->config->config_default;
358 data->client = client; 497 data->client = client;
359 498
499 /*
500 * Ina226 has a variable update_interval. For ina219 we
501 * use a constant value.
502 */
503 if (data->kind == ina226)
504 ina226_set_update_interval(data);
505 else
506 data->update_interval = HZ / INA2XX_CONVERSION_RATE;
507
360 if (data->rshunt <= 0 || 508 if (data->rshunt <= 0 ||
361 data->rshunt > data->config->calibration_factor) 509 data->rshunt > data->config->calibration_factor)
362 return -ENODEV; 510 return -ENODEV;
@@ -369,8 +517,12 @@ static int ina2xx_probe(struct i2c_client *client,
369 517
370 mutex_init(&data->update_lock); 518 mutex_init(&data->update_lock);
371 519
520 data->groups[group++] = &ina2xx_group;
521 if (data->kind == ina226)
522 data->groups[group++] = &ina226_group;
523
372 hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, 524 hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
373 data, ina2xx_groups); 525 data, data->groups);
374 if (IS_ERR(hwmon_dev)) 526 if (IS_ERR(hwmon_dev))
375 return PTR_ERR(hwmon_dev); 527 return PTR_ERR(hwmon_dev);
376 528