]>
Commit | Line | Data |
---|---|---|
7cb6dcff AD |
1 | /* |
2 | * INA3221 Triple Current/Voltage Monitor | |
3 | * | |
4 | * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ | |
5 | * Andrew F. Davis <[email protected]> | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License version 2 as | |
9 | * published by the Free Software Foundation. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, but | |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * General Public License for more details. | |
15 | */ | |
16 | ||
17 | #include <linux/hwmon.h> | |
18 | #include <linux/hwmon-sysfs.h> | |
19 | #include <linux/i2c.h> | |
20 | #include <linux/module.h> | |
21 | #include <linux/of.h> | |
22 | #include <linux/regmap.h> | |
23 | ||
24 | #define INA3221_DRIVER_NAME "ina3221" | |
25 | ||
26 | #define INA3221_CONFIG 0x00 | |
27 | #define INA3221_SHUNT1 0x01 | |
28 | #define INA3221_BUS1 0x02 | |
29 | #define INA3221_SHUNT2 0x03 | |
30 | #define INA3221_BUS2 0x04 | |
31 | #define INA3221_SHUNT3 0x05 | |
32 | #define INA3221_BUS3 0x06 | |
33 | #define INA3221_CRIT1 0x07 | |
34 | #define INA3221_WARN1 0x08 | |
35 | #define INA3221_CRIT2 0x09 | |
36 | #define INA3221_WARN2 0x0a | |
37 | #define INA3221_CRIT3 0x0b | |
38 | #define INA3221_WARN3 0x0c | |
39 | #define INA3221_MASK_ENABLE 0x0f | |
40 | ||
59d608e1 NC |
41 | #define INA3221_CONFIG_MODE_MASK GENMASK(2, 0) |
42 | #define INA3221_CONFIG_MODE_POWERDOWN 0 | |
791ebc9d NC |
43 | #define INA3221_CONFIG_MODE_SHUNT BIT(0) |
44 | #define INA3221_CONFIG_MODE_BUS BIT(1) | |
45 | #define INA3221_CONFIG_MODE_CONTINUOUS BIT(2) | |
a9e9dd9c | 46 | #define INA3221_CONFIG_CHx_EN(x) BIT(14 - (x)) |
7cb6dcff AD |
47 | |
48 | #define INA3221_RSHUNT_DEFAULT 10000 | |
49 | ||
50 | enum ina3221_fields { | |
51 | /* Configuration */ | |
52 | F_RST, | |
53 | ||
54 | /* Alert Flags */ | |
55 | F_WF3, F_WF2, F_WF1, | |
56 | F_CF3, F_CF2, F_CF1, | |
57 | ||
58 | /* sentinel */ | |
59 | F_MAX_FIELDS | |
60 | }; | |
61 | ||
62 | static const struct reg_field ina3221_reg_fields[] = { | |
63 | [F_RST] = REG_FIELD(INA3221_CONFIG, 15, 15), | |
64 | ||
65 | [F_WF3] = REG_FIELD(INA3221_MASK_ENABLE, 3, 3), | |
66 | [F_WF2] = REG_FIELD(INA3221_MASK_ENABLE, 4, 4), | |
67 | [F_WF1] = REG_FIELD(INA3221_MASK_ENABLE, 5, 5), | |
68 | [F_CF3] = REG_FIELD(INA3221_MASK_ENABLE, 7, 7), | |
69 | [F_CF2] = REG_FIELD(INA3221_MASK_ENABLE, 8, 8), | |
70 | [F_CF1] = REG_FIELD(INA3221_MASK_ENABLE, 9, 9), | |
71 | }; | |
72 | ||
73 | enum ina3221_channels { | |
74 | INA3221_CHANNEL1, | |
75 | INA3221_CHANNEL2, | |
76 | INA3221_CHANNEL3, | |
77 | INA3221_NUM_CHANNELS | |
78 | }; | |
79 | ||
80 | static const unsigned int register_channel[] = { | |
a9e9dd9c NC |
81 | [INA3221_BUS1] = INA3221_CHANNEL1, |
82 | [INA3221_BUS2] = INA3221_CHANNEL2, | |
83 | [INA3221_BUS3] = INA3221_CHANNEL3, | |
7cb6dcff AD |
84 | [INA3221_SHUNT1] = INA3221_CHANNEL1, |
85 | [INA3221_SHUNT2] = INA3221_CHANNEL2, | |
86 | [INA3221_SHUNT3] = INA3221_CHANNEL3, | |
87 | [INA3221_CRIT1] = INA3221_CHANNEL1, | |
88 | [INA3221_CRIT2] = INA3221_CHANNEL2, | |
89 | [INA3221_CRIT3] = INA3221_CHANNEL3, | |
90 | [INA3221_WARN1] = INA3221_CHANNEL1, | |
91 | [INA3221_WARN2] = INA3221_CHANNEL2, | |
92 | [INA3221_WARN3] = INA3221_CHANNEL3, | |
93 | }; | |
94 | ||
a9e9dd9c NC |
95 | /** |
96 | * struct ina3221_input - channel input source specific information | |
97 | * @label: label of channel input source | |
98 | * @shunt_resistor: shunt resistor value of channel input source | |
99 | * @disconnected: connection status of channel input source | |
100 | */ | |
101 | struct ina3221_input { | |
102 | const char *label; | |
103 | int shunt_resistor; | |
104 | bool disconnected; | |
105 | }; | |
106 | ||
7cb6dcff AD |
107 | /** |
108 | * struct ina3221_data - device specific information | |
109 | * @regmap: Register map of the device | |
110 | * @fields: Register fields of the device | |
a9e9dd9c | 111 | * @inputs: Array of channel input source specific structures |
59d608e1 | 112 | * @reg_config: Register value of INA3221_CONFIG |
7cb6dcff AD |
113 | */ |
114 | struct ina3221_data { | |
115 | struct regmap *regmap; | |
116 | struct regmap_field *fields[F_MAX_FIELDS]; | |
a9e9dd9c | 117 | struct ina3221_input inputs[INA3221_NUM_CHANNELS]; |
59d608e1 | 118 | u32 reg_config; |
7cb6dcff AD |
119 | }; |
120 | ||
a9e9dd9c NC |
121 | static inline bool ina3221_is_enabled(struct ina3221_data *ina, int channel) |
122 | { | |
123 | return ina->reg_config & INA3221_CONFIG_CHx_EN(channel); | |
124 | } | |
125 | ||
126 | static ssize_t ina3221_show_label(struct device *dev, | |
127 | struct device_attribute *attr, char *buf) | |
128 | { | |
129 | struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); | |
130 | struct ina3221_data *ina = dev_get_drvdata(dev); | |
131 | unsigned int channel = sd_attr->index; | |
132 | struct ina3221_input *input = &ina->inputs[channel]; | |
133 | ||
134 | return snprintf(buf, PAGE_SIZE, "%s\n", input->label); | |
135 | } | |
136 | ||
137 | static ssize_t ina3221_show_enable(struct device *dev, | |
138 | struct device_attribute *attr, char *buf) | |
139 | { | |
140 | struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); | |
141 | struct ina3221_data *ina = dev_get_drvdata(dev); | |
142 | unsigned int channel = sd_attr->index; | |
143 | ||
144 | return snprintf(buf, PAGE_SIZE, "%d\n", | |
145 | ina3221_is_enabled(ina, channel)); | |
146 | } | |
147 | ||
148 | static ssize_t ina3221_set_enable(struct device *dev, | |
149 | struct device_attribute *attr, | |
150 | const char *buf, size_t count) | |
151 | { | |
152 | struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); | |
153 | struct ina3221_data *ina = dev_get_drvdata(dev); | |
154 | unsigned int channel = sd_attr->index; | |
155 | u16 config, mask = INA3221_CONFIG_CHx_EN(channel); | |
156 | bool enable; | |
157 | int ret; | |
158 | ||
159 | ret = kstrtobool(buf, &enable); | |
160 | if (ret) | |
161 | return ret; | |
162 | ||
163 | config = enable ? mask : 0; | |
164 | ||
165 | /* Enable or disable the channel */ | |
166 | ret = regmap_update_bits(ina->regmap, INA3221_CONFIG, mask, config); | |
167 | if (ret) | |
168 | return ret; | |
169 | ||
170 | /* Cache the latest config register value */ | |
171 | ret = regmap_read(ina->regmap, INA3221_CONFIG, &ina->reg_config); | |
172 | if (ret) | |
173 | return ret; | |
174 | ||
175 | return count; | |
176 | } | |
177 | ||
7cb6dcff AD |
178 | static int ina3221_read_value(struct ina3221_data *ina, unsigned int reg, |
179 | int *val) | |
180 | { | |
181 | unsigned int regval; | |
182 | int ret; | |
183 | ||
184 | ret = regmap_read(ina->regmap, reg, ®val); | |
185 | if (ret) | |
186 | return ret; | |
187 | ||
188 | *val = sign_extend32(regval >> 3, 12); | |
189 | ||
190 | return 0; | |
191 | } | |
192 | ||
193 | static ssize_t ina3221_show_bus_voltage(struct device *dev, | |
194 | struct device_attribute *attr, | |
195 | char *buf) | |
196 | { | |
197 | struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); | |
198 | struct ina3221_data *ina = dev_get_drvdata(dev); | |
199 | unsigned int reg = sd_attr->index; | |
a9e9dd9c | 200 | unsigned int channel = register_channel[reg]; |
7cb6dcff AD |
201 | int val, voltage_mv, ret; |
202 | ||
a9e9dd9c NC |
203 | /* No data for read-only attribute if channel is disabled */ |
204 | if (!attr->store && !ina3221_is_enabled(ina, channel)) | |
205 | return -ENODATA; | |
206 | ||
7cb6dcff AD |
207 | ret = ina3221_read_value(ina, reg, &val); |
208 | if (ret) | |
209 | return ret; | |
210 | ||
211 | voltage_mv = val * 8; | |
212 | ||
213 | return snprintf(buf, PAGE_SIZE, "%d\n", voltage_mv); | |
214 | } | |
215 | ||
216 | static ssize_t ina3221_show_shunt_voltage(struct device *dev, | |
217 | struct device_attribute *attr, | |
218 | char *buf) | |
219 | { | |
220 | struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); | |
221 | struct ina3221_data *ina = dev_get_drvdata(dev); | |
222 | unsigned int reg = sd_attr->index; | |
a9e9dd9c | 223 | unsigned int channel = register_channel[reg]; |
7cb6dcff AD |
224 | int val, voltage_uv, ret; |
225 | ||
a9e9dd9c NC |
226 | /* No data for read-only attribute if channel is disabled */ |
227 | if (!attr->store && !ina3221_is_enabled(ina, channel)) | |
228 | return -ENODATA; | |
229 | ||
7cb6dcff AD |
230 | ret = ina3221_read_value(ina, reg, &val); |
231 | if (ret) | |
232 | return ret; | |
233 | voltage_uv = val * 40; | |
234 | ||
235 | return snprintf(buf, PAGE_SIZE, "%d\n", voltage_uv); | |
236 | } | |
237 | ||
238 | static ssize_t ina3221_show_current(struct device *dev, | |
239 | struct device_attribute *attr, char *buf) | |
240 | { | |
241 | struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); | |
242 | struct ina3221_data *ina = dev_get_drvdata(dev); | |
243 | unsigned int reg = sd_attr->index; | |
244 | unsigned int channel = register_channel[reg]; | |
a9e9dd9c NC |
245 | struct ina3221_input *input = &ina->inputs[channel]; |
246 | int resistance_uo = input->shunt_resistor; | |
7cb6dcff AD |
247 | int val, current_ma, voltage_nv, ret; |
248 | ||
a9e9dd9c NC |
249 | /* No data for read-only attribute if channel is disabled */ |
250 | if (!attr->store && !ina3221_is_enabled(ina, channel)) | |
251 | return -ENODATA; | |
252 | ||
7cb6dcff AD |
253 | ret = ina3221_read_value(ina, reg, &val); |
254 | if (ret) | |
255 | return ret; | |
256 | voltage_nv = val * 40000; | |
257 | ||
258 | current_ma = DIV_ROUND_CLOSEST(voltage_nv, resistance_uo); | |
259 | ||
260 | return snprintf(buf, PAGE_SIZE, "%d\n", current_ma); | |
261 | } | |
262 | ||
263 | static ssize_t ina3221_set_current(struct device *dev, | |
264 | struct device_attribute *attr, | |
265 | const char *buf, size_t count) | |
266 | { | |
267 | struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); | |
268 | struct ina3221_data *ina = dev_get_drvdata(dev); | |
269 | unsigned int reg = sd_attr->index; | |
270 | unsigned int channel = register_channel[reg]; | |
a9e9dd9c NC |
271 | struct ina3221_input *input = &ina->inputs[channel]; |
272 | int resistance_uo = input->shunt_resistor; | |
7cb6dcff AD |
273 | int val, current_ma, voltage_uv, ret; |
274 | ||
275 | ret = kstrtoint(buf, 0, ¤t_ma); | |
276 | if (ret) | |
277 | return ret; | |
278 | ||
279 | /* clamp current */ | |
280 | current_ma = clamp_val(current_ma, | |
281 | INT_MIN / resistance_uo, | |
282 | INT_MAX / resistance_uo); | |
283 | ||
284 | voltage_uv = DIV_ROUND_CLOSEST(current_ma * resistance_uo, 1000); | |
285 | ||
286 | /* clamp voltage */ | |
287 | voltage_uv = clamp_val(voltage_uv, -163800, 163800); | |
288 | ||
289 | /* 1 / 40uV(scale) << 3(register shift) = 5 */ | |
290 | val = DIV_ROUND_CLOSEST(voltage_uv, 5) & 0xfff8; | |
291 | ||
292 | ret = regmap_write(ina->regmap, reg, val); | |
293 | if (ret) | |
294 | return ret; | |
295 | ||
296 | return count; | |
297 | } | |
298 | ||
299 | static ssize_t ina3221_show_shunt(struct device *dev, | |
300 | struct device_attribute *attr, char *buf) | |
301 | { | |
302 | struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); | |
303 | struct ina3221_data *ina = dev_get_drvdata(dev); | |
304 | unsigned int channel = sd_attr->index; | |
a9e9dd9c | 305 | struct ina3221_input *input = &ina->inputs[channel]; |
7cb6dcff | 306 | |
a9e9dd9c | 307 | return snprintf(buf, PAGE_SIZE, "%d\n", input->shunt_resistor); |
7cb6dcff AD |
308 | } |
309 | ||
310 | static ssize_t ina3221_set_shunt(struct device *dev, | |
311 | struct device_attribute *attr, | |
312 | const char *buf, size_t count) | |
313 | { | |
314 | struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); | |
315 | struct ina3221_data *ina = dev_get_drvdata(dev); | |
316 | unsigned int channel = sd_attr->index; | |
a9e9dd9c | 317 | struct ina3221_input *input = &ina->inputs[channel]; |
9ad0df1a | 318 | int val; |
7cb6dcff AD |
319 | int ret; |
320 | ||
9ad0df1a | 321 | ret = kstrtoint(buf, 0, &val); |
7cb6dcff AD |
322 | if (ret) |
323 | return ret; | |
324 | ||
9ad0df1a | 325 | val = clamp_val(val, 1, INT_MAX); |
7cb6dcff | 326 | |
a9e9dd9c | 327 | input->shunt_resistor = val; |
7cb6dcff AD |
328 | |
329 | return count; | |
330 | } | |
331 | ||
332 | static ssize_t ina3221_show_alert(struct device *dev, | |
333 | struct device_attribute *attr, char *buf) | |
334 | { | |
335 | struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr); | |
336 | struct ina3221_data *ina = dev_get_drvdata(dev); | |
337 | unsigned int field = sd_attr->index; | |
338 | unsigned int regval; | |
339 | int ret; | |
340 | ||
341 | ret = regmap_field_read(ina->fields[field], ®val); | |
342 | if (ret) | |
343 | return ret; | |
344 | ||
345 | return snprintf(buf, PAGE_SIZE, "%d\n", regval); | |
346 | } | |
347 | ||
a9e9dd9c NC |
348 | /* input channel label */ |
349 | static SENSOR_DEVICE_ATTR(in1_label, 0444, | |
350 | ina3221_show_label, NULL, INA3221_CHANNEL1); | |
351 | static SENSOR_DEVICE_ATTR(in2_label, 0444, | |
352 | ina3221_show_label, NULL, INA3221_CHANNEL2); | |
353 | static SENSOR_DEVICE_ATTR(in3_label, 0444, | |
354 | ina3221_show_label, NULL, INA3221_CHANNEL3); | |
355 | ||
356 | /* voltage channel enable */ | |
357 | static SENSOR_DEVICE_ATTR(in1_enable, 0644, | |
358 | ina3221_show_enable, ina3221_set_enable, INA3221_CHANNEL1); | |
359 | static SENSOR_DEVICE_ATTR(in2_enable, 0644, | |
360 | ina3221_show_enable, ina3221_set_enable, INA3221_CHANNEL2); | |
361 | static SENSOR_DEVICE_ATTR(in3_enable, 0644, | |
362 | ina3221_show_enable, ina3221_set_enable, INA3221_CHANNEL3); | |
363 | ||
7cb6dcff AD |
364 | /* bus voltage */ |
365 | static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, | |
366 | ina3221_show_bus_voltage, NULL, INA3221_BUS1); | |
367 | static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, | |
368 | ina3221_show_bus_voltage, NULL, INA3221_BUS2); | |
369 | static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, | |
370 | ina3221_show_bus_voltage, NULL, INA3221_BUS3); | |
371 | ||
372 | /* calculated current */ | |
373 | static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, | |
374 | ina3221_show_current, NULL, INA3221_SHUNT1); | |
375 | static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, | |
376 | ina3221_show_current, NULL, INA3221_SHUNT2); | |
377 | static SENSOR_DEVICE_ATTR(curr3_input, S_IRUGO, | |
378 | ina3221_show_current, NULL, INA3221_SHUNT3); | |
379 | ||
380 | /* shunt resistance */ | |
381 | static SENSOR_DEVICE_ATTR(shunt1_resistor, S_IRUGO | S_IWUSR, | |
382 | ina3221_show_shunt, ina3221_set_shunt, INA3221_CHANNEL1); | |
383 | static SENSOR_DEVICE_ATTR(shunt2_resistor, S_IRUGO | S_IWUSR, | |
384 | ina3221_show_shunt, ina3221_set_shunt, INA3221_CHANNEL2); | |
385 | static SENSOR_DEVICE_ATTR(shunt3_resistor, S_IRUGO | S_IWUSR, | |
386 | ina3221_show_shunt, ina3221_set_shunt, INA3221_CHANNEL3); | |
387 | ||
388 | /* critical current */ | |
389 | static SENSOR_DEVICE_ATTR(curr1_crit, S_IRUGO | S_IWUSR, | |
390 | ina3221_show_current, ina3221_set_current, INA3221_CRIT1); | |
391 | static SENSOR_DEVICE_ATTR(curr2_crit, S_IRUGO | S_IWUSR, | |
392 | ina3221_show_current, ina3221_set_current, INA3221_CRIT2); | |
393 | static SENSOR_DEVICE_ATTR(curr3_crit, S_IRUGO | S_IWUSR, | |
394 | ina3221_show_current, ina3221_set_current, INA3221_CRIT3); | |
395 | ||
396 | /* critical current alert */ | |
397 | static SENSOR_DEVICE_ATTR(curr1_crit_alarm, S_IRUGO, | |
398 | ina3221_show_alert, NULL, F_CF1); | |
399 | static SENSOR_DEVICE_ATTR(curr2_crit_alarm, S_IRUGO, | |
400 | ina3221_show_alert, NULL, F_CF2); | |
401 | static SENSOR_DEVICE_ATTR(curr3_crit_alarm, S_IRUGO, | |
402 | ina3221_show_alert, NULL, F_CF3); | |
403 | ||
404 | /* warning current */ | |
405 | static SENSOR_DEVICE_ATTR(curr1_max, S_IRUGO | S_IWUSR, | |
406 | ina3221_show_current, ina3221_set_current, INA3221_WARN1); | |
407 | static SENSOR_DEVICE_ATTR(curr2_max, S_IRUGO | S_IWUSR, | |
408 | ina3221_show_current, ina3221_set_current, INA3221_WARN2); | |
409 | static SENSOR_DEVICE_ATTR(curr3_max, S_IRUGO | S_IWUSR, | |
410 | ina3221_show_current, ina3221_set_current, INA3221_WARN3); | |
411 | ||
412 | /* warning current alert */ | |
413 | static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO, | |
414 | ina3221_show_alert, NULL, F_WF1); | |
415 | static SENSOR_DEVICE_ATTR(curr2_max_alarm, S_IRUGO, | |
416 | ina3221_show_alert, NULL, F_WF2); | |
417 | static SENSOR_DEVICE_ATTR(curr3_max_alarm, S_IRUGO, | |
418 | ina3221_show_alert, NULL, F_WF3); | |
419 | ||
420 | /* shunt voltage */ | |
421 | static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, | |
422 | ina3221_show_shunt_voltage, NULL, INA3221_SHUNT1); | |
423 | static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, | |
424 | ina3221_show_shunt_voltage, NULL, INA3221_SHUNT2); | |
425 | static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, | |
426 | ina3221_show_shunt_voltage, NULL, INA3221_SHUNT3); | |
427 | ||
428 | static struct attribute *ina3221_attrs[] = { | |
a9e9dd9c NC |
429 | /* channel 1 -- make sure label at first */ |
430 | &sensor_dev_attr_in1_label.dev_attr.attr, | |
431 | &sensor_dev_attr_in1_enable.dev_attr.attr, | |
7cb6dcff AD |
432 | &sensor_dev_attr_in1_input.dev_attr.attr, |
433 | &sensor_dev_attr_curr1_input.dev_attr.attr, | |
434 | &sensor_dev_attr_shunt1_resistor.dev_attr.attr, | |
435 | &sensor_dev_attr_curr1_crit.dev_attr.attr, | |
436 | &sensor_dev_attr_curr1_crit_alarm.dev_attr.attr, | |
437 | &sensor_dev_attr_curr1_max.dev_attr.attr, | |
438 | &sensor_dev_attr_curr1_max_alarm.dev_attr.attr, | |
439 | &sensor_dev_attr_in4_input.dev_attr.attr, | |
440 | ||
a9e9dd9c NC |
441 | /* channel 2 -- make sure label at first */ |
442 | &sensor_dev_attr_in2_label.dev_attr.attr, | |
443 | &sensor_dev_attr_in2_enable.dev_attr.attr, | |
7cb6dcff AD |
444 | &sensor_dev_attr_in2_input.dev_attr.attr, |
445 | &sensor_dev_attr_curr2_input.dev_attr.attr, | |
446 | &sensor_dev_attr_shunt2_resistor.dev_attr.attr, | |
447 | &sensor_dev_attr_curr2_crit.dev_attr.attr, | |
448 | &sensor_dev_attr_curr2_crit_alarm.dev_attr.attr, | |
449 | &sensor_dev_attr_curr2_max.dev_attr.attr, | |
450 | &sensor_dev_attr_curr2_max_alarm.dev_attr.attr, | |
451 | &sensor_dev_attr_in5_input.dev_attr.attr, | |
452 | ||
a9e9dd9c NC |
453 | /* channel 3 -- make sure label at first */ |
454 | &sensor_dev_attr_in3_label.dev_attr.attr, | |
455 | &sensor_dev_attr_in3_enable.dev_attr.attr, | |
7cb6dcff AD |
456 | &sensor_dev_attr_in3_input.dev_attr.attr, |
457 | &sensor_dev_attr_curr3_input.dev_attr.attr, | |
458 | &sensor_dev_attr_shunt3_resistor.dev_attr.attr, | |
459 | &sensor_dev_attr_curr3_crit.dev_attr.attr, | |
460 | &sensor_dev_attr_curr3_crit_alarm.dev_attr.attr, | |
461 | &sensor_dev_attr_curr3_max.dev_attr.attr, | |
462 | &sensor_dev_attr_curr3_max_alarm.dev_attr.attr, | |
463 | &sensor_dev_attr_in6_input.dev_attr.attr, | |
464 | ||
465 | NULL, | |
466 | }; | |
a9e9dd9c NC |
467 | |
468 | static umode_t ina3221_attr_is_visible(struct kobject *kobj, | |
469 | struct attribute *attr, int n) | |
470 | { | |
471 | const int max_attrs = ARRAY_SIZE(ina3221_attrs) - 1; | |
472 | const int num_attrs = max_attrs / INA3221_NUM_CHANNELS; | |
473 | struct device *dev = kobj_to_dev(kobj); | |
474 | struct ina3221_data *ina = dev_get_drvdata(dev); | |
475 | enum ina3221_channels channel = n / num_attrs; | |
476 | struct ina3221_input *input = &ina->inputs[channel]; | |
477 | int index = n % num_attrs; | |
478 | ||
479 | /* Hide label node if label is not provided */ | |
480 | if (index == 0 && !input->label) | |
481 | return 0; | |
482 | ||
483 | return attr->mode; | |
484 | } | |
485 | ||
486 | static const struct attribute_group ina3221_group = { | |
487 | .is_visible = ina3221_attr_is_visible, | |
488 | .attrs = ina3221_attrs, | |
489 | }; | |
490 | __ATTRIBUTE_GROUPS(ina3221); | |
7cb6dcff AD |
491 | |
492 | static const struct regmap_range ina3221_yes_ranges[] = { | |
c20217b3 | 493 | regmap_reg_range(INA3221_CONFIG, INA3221_BUS3), |
7cb6dcff AD |
494 | regmap_reg_range(INA3221_MASK_ENABLE, INA3221_MASK_ENABLE), |
495 | }; | |
496 | ||
497 | static const struct regmap_access_table ina3221_volatile_table = { | |
498 | .yes_ranges = ina3221_yes_ranges, | |
499 | .n_yes_ranges = ARRAY_SIZE(ina3221_yes_ranges), | |
500 | }; | |
501 | ||
502 | static const struct regmap_config ina3221_regmap_config = { | |
503 | .reg_bits = 8, | |
504 | .val_bits = 16, | |
505 | ||
506 | .cache_type = REGCACHE_RBTREE, | |
507 | .volatile_table = &ina3221_volatile_table, | |
508 | }; | |
509 | ||
a9e9dd9c NC |
510 | static int ina3221_probe_child_from_dt(struct device *dev, |
511 | struct device_node *child, | |
512 | struct ina3221_data *ina) | |
513 | { | |
514 | struct ina3221_input *input; | |
515 | u32 val; | |
516 | int ret; | |
517 | ||
518 | ret = of_property_read_u32(child, "reg", &val); | |
519 | if (ret) { | |
520 | dev_err(dev, "missing reg property of %s\n", child->name); | |
521 | return ret; | |
522 | } else if (val > INA3221_CHANNEL3) { | |
523 | dev_err(dev, "invalid reg %d of %s\n", val, child->name); | |
524 | return ret; | |
525 | } | |
526 | ||
527 | input = &ina->inputs[val]; | |
528 | ||
529 | /* Log the disconnected channel input */ | |
530 | if (!of_device_is_available(child)) { | |
531 | input->disconnected = true; | |
532 | return 0; | |
533 | } | |
534 | ||
535 | /* Save the connected input label if available */ | |
536 | of_property_read_string(child, "label", &input->label); | |
537 | ||
538 | /* Overwrite default shunt resistor value optionally */ | |
539 | if (!of_property_read_u32(child, "shunt-resistor-micro-ohms", &val)) | |
540 | input->shunt_resistor = val; | |
541 | ||
542 | return 0; | |
543 | } | |
544 | ||
545 | static int ina3221_probe_from_dt(struct device *dev, struct ina3221_data *ina) | |
546 | { | |
547 | const struct device_node *np = dev->of_node; | |
548 | struct device_node *child; | |
549 | int ret; | |
550 | ||
551 | /* Compatible with non-DT platforms */ | |
552 | if (!np) | |
553 | return 0; | |
554 | ||
555 | for_each_child_of_node(np, child) { | |
556 | ret = ina3221_probe_child_from_dt(dev, child, ina); | |
557 | if (ret) | |
558 | return ret; | |
559 | } | |
560 | ||
561 | return 0; | |
562 | } | |
563 | ||
7cb6dcff AD |
564 | static int ina3221_probe(struct i2c_client *client, |
565 | const struct i2c_device_id *id) | |
566 | { | |
567 | struct device *dev = &client->dev; | |
568 | struct ina3221_data *ina; | |
569 | struct device *hwmon_dev; | |
570 | int i, ret; | |
571 | ||
572 | ina = devm_kzalloc(dev, sizeof(*ina), GFP_KERNEL); | |
573 | if (!ina) | |
574 | return -ENOMEM; | |
575 | ||
576 | ina->regmap = devm_regmap_init_i2c(client, &ina3221_regmap_config); | |
577 | if (IS_ERR(ina->regmap)) { | |
578 | dev_err(dev, "Unable to allocate register map\n"); | |
579 | return PTR_ERR(ina->regmap); | |
580 | } | |
581 | ||
582 | for (i = 0; i < F_MAX_FIELDS; i++) { | |
583 | ina->fields[i] = devm_regmap_field_alloc(dev, | |
584 | ina->regmap, | |
585 | ina3221_reg_fields[i]); | |
586 | if (IS_ERR(ina->fields[i])) { | |
587 | dev_err(dev, "Unable to allocate regmap fields\n"); | |
588 | return PTR_ERR(ina->fields[i]); | |
589 | } | |
590 | } | |
591 | ||
592 | for (i = 0; i < INA3221_NUM_CHANNELS; i++) | |
a9e9dd9c NC |
593 | ina->inputs[i].shunt_resistor = INA3221_RSHUNT_DEFAULT; |
594 | ||
595 | ret = ina3221_probe_from_dt(dev, ina); | |
596 | if (ret) { | |
597 | dev_err(dev, "Unable to probe from device tree\n"); | |
598 | return ret; | |
599 | } | |
7cb6dcff AD |
600 | |
601 | ret = regmap_field_write(ina->fields[F_RST], true); | |
602 | if (ret) { | |
603 | dev_err(dev, "Unable to reset device\n"); | |
604 | return ret; | |
605 | } | |
606 | ||
a9e9dd9c NC |
607 | /* Sync config register after reset */ |
608 | ret = regmap_read(ina->regmap, INA3221_CONFIG, &ina->reg_config); | |
609 | if (ret) | |
610 | return ret; | |
611 | ||
612 | /* Disable channels if their inputs are disconnected */ | |
613 | for (i = 0; i < INA3221_NUM_CHANNELS; i++) { | |
614 | if (ina->inputs[i].disconnected) | |
615 | ina->reg_config &= ~INA3221_CONFIG_CHx_EN(i); | |
616 | } | |
617 | ret = regmap_write(ina->regmap, INA3221_CONFIG, ina->reg_config); | |
618 | if (ret) | |
619 | return ret; | |
620 | ||
59d608e1 NC |
621 | dev_set_drvdata(dev, ina); |
622 | ||
7cb6dcff AD |
623 | hwmon_dev = devm_hwmon_device_register_with_groups(dev, |
624 | client->name, | |
625 | ina, ina3221_groups); | |
626 | if (IS_ERR(hwmon_dev)) { | |
627 | dev_err(dev, "Unable to register hwmon device\n"); | |
628 | return PTR_ERR(hwmon_dev); | |
629 | } | |
630 | ||
631 | return 0; | |
632 | } | |
633 | ||
59d608e1 NC |
634 | #ifdef CONFIG_PM |
635 | static int ina3221_suspend(struct device *dev) | |
636 | { | |
637 | struct ina3221_data *ina = dev_get_drvdata(dev); | |
638 | int ret; | |
639 | ||
640 | /* Save config register value and enable cache-only */ | |
641 | ret = regmap_read(ina->regmap, INA3221_CONFIG, &ina->reg_config); | |
642 | if (ret) | |
643 | return ret; | |
644 | ||
645 | /* Set to power-down mode for power saving */ | |
646 | ret = regmap_update_bits(ina->regmap, INA3221_CONFIG, | |
647 | INA3221_CONFIG_MODE_MASK, | |
648 | INA3221_CONFIG_MODE_POWERDOWN); | |
649 | if (ret) | |
650 | return ret; | |
651 | ||
652 | regcache_cache_only(ina->regmap, true); | |
653 | regcache_mark_dirty(ina->regmap); | |
654 | ||
655 | return 0; | |
656 | } | |
657 | ||
658 | static int ina3221_resume(struct device *dev) | |
659 | { | |
660 | struct ina3221_data *ina = dev_get_drvdata(dev); | |
661 | int ret; | |
662 | ||
663 | regcache_cache_only(ina->regmap, false); | |
664 | ||
665 | /* Software reset the chip */ | |
666 | ret = regmap_field_write(ina->fields[F_RST], true); | |
667 | if (ret) { | |
668 | dev_err(dev, "Unable to reset device\n"); | |
669 | return ret; | |
670 | } | |
671 | ||
672 | /* Restore cached register values to hardware */ | |
673 | ret = regcache_sync(ina->regmap); | |
674 | if (ret) | |
675 | return ret; | |
676 | ||
677 | /* Restore config register value to hardware */ | |
678 | ret = regmap_write(ina->regmap, INA3221_CONFIG, ina->reg_config); | |
679 | if (ret) | |
680 | return ret; | |
681 | ||
682 | return 0; | |
683 | } | |
684 | #endif | |
685 | ||
686 | static const struct dev_pm_ops ina3221_pm = { | |
687 | SET_SYSTEM_SLEEP_PM_OPS(ina3221_suspend, ina3221_resume) | |
688 | }; | |
689 | ||
7cb6dcff AD |
690 | static const struct of_device_id ina3221_of_match_table[] = { |
691 | { .compatible = "ti,ina3221", }, | |
692 | { /* sentinel */ } | |
693 | }; | |
694 | MODULE_DEVICE_TABLE(of, ina3221_of_match_table); | |
695 | ||
696 | static const struct i2c_device_id ina3221_ids[] = { | |
697 | { "ina3221", 0 }, | |
698 | { /* sentinel */ } | |
699 | }; | |
700 | MODULE_DEVICE_TABLE(i2c, ina3221_ids); | |
701 | ||
702 | static struct i2c_driver ina3221_i2c_driver = { | |
703 | .probe = ina3221_probe, | |
704 | .driver = { | |
705 | .name = INA3221_DRIVER_NAME, | |
706 | .of_match_table = ina3221_of_match_table, | |
59d608e1 | 707 | .pm = &ina3221_pm, |
7cb6dcff AD |
708 | }, |
709 | .id_table = ina3221_ids, | |
710 | }; | |
711 | module_i2c_driver(ina3221_i2c_driver); | |
712 | ||
713 | MODULE_AUTHOR("Andrew F. Davis <[email protected]>"); | |
714 | MODULE_DESCRIPTION("Texas Instruments INA3221 HWMon Driver"); | |
715 | MODULE_LICENSE("GPL v2"); |