aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon
diff options
context:
space:
mode:
authorBartosz Golaszewski <bgolaszewski@baylibre.com>2015-01-05 09:20:52 -0500
committerGuenter Roeck <linux@roeck-us.net>2015-01-26 00:23:58 -0500
commit509416a8e741d11d65c027f510b79573f69f6de8 (patch)
tree0d74b0fa17306f70b65510c855ce3d0807f6363e /drivers/hwmon
parent3c535bca9a43eb04d64537b55994c88e399a9981 (diff)
hwmon: (ina2xx) reinitialize the chip in case it's been reset
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> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Diffstat (limited to 'drivers/hwmon')
-rw-r--r--drivers/hwmon/ina2xx.c128
1 files changed, 91 insertions, 37 deletions
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index e01feba909c3..ffbd60f52619 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -35,6 +35,7 @@
35#include <linux/hwmon-sysfs.h> 35#include <linux/hwmon-sysfs.h>
36#include <linux/jiffies.h> 36#include <linux/jiffies.h>
37#include <linux/of.h> 37#include <linux/of.h>
38#include <linux/delay.h>
38 39
39#include <linux/platform_data/ina2xx.h> 40#include <linux/platform_data/ina2xx.h>
40 41
@@ -64,6 +65,9 @@
64 65
65/* worst case is 68.10 ms (~14.6Hz, ina219) */ 66/* worst case is 68.10 ms (~14.6Hz, ina219) */
66#define INA2XX_CONVERSION_RATE 15 67#define INA2XX_CONVERSION_RATE 15
68#define INA2XX_MAX_DELAY 69 /* worst case delay in ms */
69
70#define INA2XX_RSHUNT_DEFAULT 10000
67 71
68enum ina2xx_ids { ina219, ina226 }; 72enum ina2xx_ids { ina219, ina226 };
69 73
@@ -81,6 +85,8 @@ struct ina2xx_data {
81 struct i2c_client *client; 85 struct i2c_client *client;
82 const struct ina2xx_config *config; 86 const struct ina2xx_config *config;
83 87
88 long rshunt;
89
84 struct mutex update_lock; 90 struct mutex update_lock;
85 bool valid; 91 bool valid;
86 unsigned long last_updated; 92 unsigned long last_updated;
@@ -110,34 +116,96 @@ static const struct ina2xx_config ina2xx_config[] = {
110 }, 116 },
111}; 117};
112 118
113static struct ina2xx_data *ina2xx_update_device(struct device *dev) 119/*
120 * Initialize the configuration and calibration registers.
121 */
122static int ina2xx_init(struct ina2xx_data *data)
114{ 123{
115 struct ina2xx_data *data = dev_get_drvdata(dev);
116 struct i2c_client *client = data->client; 124 struct i2c_client *client = data->client;
117 struct ina2xx_data *ret = data; 125 int ret;
118 126
119 mutex_lock(&data->update_lock); 127 /* device configuration */
128 ret = i2c_smbus_write_word_swapped(client, INA2XX_CONFIG,
129 data->config->config_default);
130 if (ret < 0)
131 return ret;
120 132
121 if (time_after(jiffies, data->last_updated + 133 /*
122 HZ / INA2XX_CONVERSION_RATE) || !data->valid) { 134 * Set current LSB to 1mA, shunt is in uOhms
135 * (equation 13 in datasheet).
136 */
137 return i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION,
138 data->config->calibration_factor / data->rshunt);
139}
123 140
124 int i; 141static int ina2xx_do_update(struct device *dev)
142{
143 struct ina2xx_data *data = dev_get_drvdata(dev);
144 struct i2c_client *client = data->client;
145 int i, rv, retry;
125 146
126 dev_dbg(&client->dev, "Starting ina2xx update\n"); 147 dev_dbg(&client->dev, "Starting ina2xx update\n");
127 148
149 for (retry = 5; retry; retry--) {
128 /* Read all registers */ 150 /* Read all registers */
129 for (i = 0; i < data->config->registers; i++) { 151 for (i = 0; i < data->config->registers; i++) {
130 int rv = i2c_smbus_read_word_swapped(client, i); 152 rv = i2c_smbus_read_word_swapped(client, i);
131 if (rv < 0) { 153 if (rv < 0)
132 ret = ERR_PTR(rv); 154 return rv;
133 goto abort;
134 }
135 data->regs[i] = rv; 155 data->regs[i] = rv;
136 } 156 }
157
158 /*
159 * If the current value in the calibration register is 0, the
160 * power and current registers will also remain at 0. In case
161 * the chip has been reset let's check the calibration
162 * register and reinitialize if needed.
163 */
164 if (data->regs[INA2XX_CALIBRATION] == 0) {
165 dev_warn(dev, "chip not calibrated, reinitializing\n");
166
167 rv = ina2xx_init(data);
168 if (rv < 0)
169 return rv;
170
171 /*
172 * Let's make sure the power and current registers
173 * have been updated before trying again.
174 */
175 msleep(INA2XX_MAX_DELAY);
176 continue;
177 }
178
137 data->last_updated = jiffies; 179 data->last_updated = jiffies;
138 data->valid = 1; 180 data->valid = 1;
181
182 return 0;
139 } 183 }
140abort: 184
185 /*
186 * If we're here then although all write operations succeeded, the
187 * chip still returns 0 in the calibration register. Nothing more we
188 * can do here.
189 */
190 dev_err(dev, "unable to reinitialize the chip\n");
191 return -ENODEV;
192}
193
194static struct ina2xx_data *ina2xx_update_device(struct device *dev)
195{
196 struct ina2xx_data *data = dev_get_drvdata(dev);
197 struct ina2xx_data *ret = data;
198 int rv;
199
200 mutex_lock(&data->update_lock);
201
202 if (time_after(jiffies, data->last_updated +
203 HZ / INA2XX_CONVERSION_RATE) || !data->valid) {
204 rv = ina2xx_do_update(dev);
205 if (rv < 0)
206 ret = ERR_PTR(rv);
207 }
208
141 mutex_unlock(&data->update_lock); 209 mutex_unlock(&data->update_lock);
142 return ret; 210 return ret;
143} 211}
@@ -221,7 +289,6 @@ static int ina2xx_probe(struct i2c_client *client,
221 struct device *dev = &client->dev; 289 struct device *dev = &client->dev;
222 struct ina2xx_data *data; 290 struct ina2xx_data *data;
223 struct device *hwmon_dev; 291 struct device *hwmon_dev;
224 long shunt = 10000; /* default shunt value 10mOhms */
225 u32 val; 292 u32 val;
226 int ret; 293 int ret;
227 294
@@ -234,41 +301,28 @@ static int ina2xx_probe(struct i2c_client *client,
234 301
235 if (dev_get_platdata(dev)) { 302 if (dev_get_platdata(dev)) {
236 pdata = dev_get_platdata(dev); 303 pdata = dev_get_platdata(dev);
237 shunt = pdata->shunt_uohms; 304 data->rshunt = pdata->shunt_uohms;
238 } else if (!of_property_read_u32(dev->of_node, 305 } else if (!of_property_read_u32(dev->of_node,
239 "shunt-resistor", &val)) { 306 "shunt-resistor", &val)) {
240 shunt = val; 307 data->rshunt = val;
308 } else {
309 data->rshunt = INA2XX_RSHUNT_DEFAULT;
241 } 310 }
242 311
243 if (shunt <= 0)
244 return -ENODEV;
245
246 /* set the device type */ 312 /* set the device type */
247 data->kind = id->driver_data; 313 data->kind = id->driver_data;
248 data->config = &ina2xx_config[data->kind]; 314 data->config = &ina2xx_config[data->kind];
315 data->client = client;
249 316
250 /* device configuration */ 317 if (data->rshunt <= 0)
251 ret = i2c_smbus_write_word_swapped(client, INA2XX_CONFIG,
252 data->config->config_default);
253 if (ret < 0) {
254 dev_err(dev,
255 "error writing to the config register: %d", ret);
256 return -ENODEV; 318 return -ENODEV;
257 }
258 319
259 /* 320 ret = ina2xx_init(data);
260 * Set current LSB to 1mA, shunt is in uOhms
261 * (equation 13 in datasheet).
262 */
263 ret = i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION,
264 data->config->calibration_factor / shunt);
265 if (ret < 0) { 321 if (ret < 0) {
266 dev_err(dev, 322 dev_err(dev, "error configuring the device: %d\n", ret);
267 "error writing to the calibration register: %d", ret);
268 return -ENODEV; 323 return -ENODEV;
269 } 324 }
270 325
271 data->client = client;
272 mutex_init(&data->update_lock); 326 mutex_init(&data->update_lock);
273 327
274 hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, 328 hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
@@ -277,7 +331,7 @@ static int ina2xx_probe(struct i2c_client *client,
277 return PTR_ERR(hwmon_dev); 331 return PTR_ERR(hwmon_dev);
278 332
279 dev_info(dev, "power monitor %s (Rshunt = %li uOhm)\n", 333 dev_info(dev, "power monitor %s (Rshunt = %li uOhm)\n",
280 id->name, shunt); 334 id->name, data->rshunt);
281 335
282 return 0; 336 return 0;
283} 337}