Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * INA3221 Triple Current/Voltage Monitor
  3 *
  4 * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/
  5 *	Andrew F. Davis <afd@ti.com>
  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
 41#define INA3221_CONFIG_MODE_SHUNT	BIT(1)
 42#define INA3221_CONFIG_MODE_BUS		BIT(2)
 43#define INA3221_CONFIG_MODE_CONTINUOUS	BIT(3)
 44
 45#define INA3221_RSHUNT_DEFAULT		10000
 46
 47enum ina3221_fields {
 48	/* Configuration */
 49	F_RST,
 50
 51	/* Alert Flags */
 52	F_WF3, F_WF2, F_WF1,
 53	F_CF3, F_CF2, F_CF1,
 54
 55	/* sentinel */
 56	F_MAX_FIELDS
 57};
 58
 59static const struct reg_field ina3221_reg_fields[] = {
 60	[F_RST] = REG_FIELD(INA3221_CONFIG, 15, 15),
 61
 62	[F_WF3] = REG_FIELD(INA3221_MASK_ENABLE, 3, 3),
 63	[F_WF2] = REG_FIELD(INA3221_MASK_ENABLE, 4, 4),
 64	[F_WF1] = REG_FIELD(INA3221_MASK_ENABLE, 5, 5),
 65	[F_CF3] = REG_FIELD(INA3221_MASK_ENABLE, 7, 7),
 66	[F_CF2] = REG_FIELD(INA3221_MASK_ENABLE, 8, 8),
 67	[F_CF1] = REG_FIELD(INA3221_MASK_ENABLE, 9, 9),
 68};
 69
 70enum ina3221_channels {
 71	INA3221_CHANNEL1,
 72	INA3221_CHANNEL2,
 73	INA3221_CHANNEL3,
 74	INA3221_NUM_CHANNELS
 75};
 76
 77static const unsigned int register_channel[] = {
 78	[INA3221_SHUNT1] = INA3221_CHANNEL1,
 79	[INA3221_SHUNT2] = INA3221_CHANNEL2,
 80	[INA3221_SHUNT3] = INA3221_CHANNEL3,
 81	[INA3221_CRIT1] = INA3221_CHANNEL1,
 82	[INA3221_CRIT2] = INA3221_CHANNEL2,
 83	[INA3221_CRIT3] = INA3221_CHANNEL3,
 84	[INA3221_WARN1] = INA3221_CHANNEL1,
 85	[INA3221_WARN2] = INA3221_CHANNEL2,
 86	[INA3221_WARN3] = INA3221_CHANNEL3,
 87};
 88
 89/**
 90 * struct ina3221_data - device specific information
 91 * @regmap: Register map of the device
 92 * @fields: Register fields of the device
 93 * @shunt_resistors: Array of resistor values per channel
 94 */
 95struct ina3221_data {
 96	struct regmap *regmap;
 97	struct regmap_field *fields[F_MAX_FIELDS];
 98	int shunt_resistors[INA3221_NUM_CHANNELS];
 99};
100
101static int ina3221_read_value(struct ina3221_data *ina, unsigned int reg,
102			      int *val)
103{
104	unsigned int regval;
105	int ret;
106
107	ret = regmap_read(ina->regmap, reg, &regval);
108	if (ret)
109		return ret;
110
111	*val = sign_extend32(regval >> 3, 12);
112
113	return 0;
114}
115
116static ssize_t ina3221_show_bus_voltage(struct device *dev,
117					struct device_attribute *attr,
118					char *buf)
119{
120	struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
121	struct ina3221_data *ina = dev_get_drvdata(dev);
122	unsigned int reg = sd_attr->index;
123	int val, voltage_mv, ret;
124
125	ret = ina3221_read_value(ina, reg, &val);
126	if (ret)
127		return ret;
128
129	voltage_mv = val * 8;
130
131	return snprintf(buf, PAGE_SIZE, "%d\n", voltage_mv);
132}
133
134static ssize_t ina3221_show_shunt_voltage(struct device *dev,
135					  struct device_attribute *attr,
136					  char *buf)
137{
138	struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
139	struct ina3221_data *ina = dev_get_drvdata(dev);
140	unsigned int reg = sd_attr->index;
141	int val, voltage_uv, ret;
142
143	ret = ina3221_read_value(ina, reg, &val);
144	if (ret)
145		return ret;
146	voltage_uv = val * 40;
147
148	return snprintf(buf, PAGE_SIZE, "%d\n", voltage_uv);
149}
150
151static ssize_t ina3221_show_current(struct device *dev,
152				    struct device_attribute *attr, char *buf)
153{
154	struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
155	struct ina3221_data *ina = dev_get_drvdata(dev);
156	unsigned int reg = sd_attr->index;
157	unsigned int channel = register_channel[reg];
158	int resistance_uo = ina->shunt_resistors[channel];
159	int val, current_ma, voltage_nv, ret;
160
161	ret = ina3221_read_value(ina, reg, &val);
162	if (ret)
163		return ret;
164	voltage_nv = val * 40000;
165
166	current_ma = DIV_ROUND_CLOSEST(voltage_nv, resistance_uo);
167
168	return snprintf(buf, PAGE_SIZE, "%d\n", current_ma);
169}
170
171static ssize_t ina3221_set_current(struct device *dev,
172				   struct device_attribute *attr,
173				   const char *buf, size_t count)
174{
175	struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
176	struct ina3221_data *ina = dev_get_drvdata(dev);
177	unsigned int reg = sd_attr->index;
178	unsigned int channel = register_channel[reg];
179	int resistance_uo = ina->shunt_resistors[channel];
180	int val, current_ma, voltage_uv, ret;
181
182	ret = kstrtoint(buf, 0, &current_ma);
183	if (ret)
184		return ret;
185
186	/* clamp current */
187	current_ma = clamp_val(current_ma,
188			       INT_MIN / resistance_uo,
189			       INT_MAX / resistance_uo);
190
191	voltage_uv = DIV_ROUND_CLOSEST(current_ma * resistance_uo, 1000);
192
193	/* clamp voltage */
194	voltage_uv = clamp_val(voltage_uv, -163800, 163800);
195
196	/* 1 / 40uV(scale) << 3(register shift) = 5 */
197	val = DIV_ROUND_CLOSEST(voltage_uv, 5) & 0xfff8;
198
199	ret = regmap_write(ina->regmap, reg, val);
200	if (ret)
201		return ret;
202
203	return count;
204}
205
206static ssize_t ina3221_show_shunt(struct device *dev,
207				  struct device_attribute *attr, char *buf)
208{
209	struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
210	struct ina3221_data *ina = dev_get_drvdata(dev);
211	unsigned int channel = sd_attr->index;
212	unsigned int resistance_uo;
213
214	resistance_uo = ina->shunt_resistors[channel];
215
216	return snprintf(buf, PAGE_SIZE, "%d\n", resistance_uo);
217}
218
219static ssize_t ina3221_set_shunt(struct device *dev,
220				 struct device_attribute *attr,
221				 const char *buf, size_t count)
222{
223	struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
224	struct ina3221_data *ina = dev_get_drvdata(dev);
225	unsigned int channel = sd_attr->index;
226	int val;
227	int ret;
228
229	ret = kstrtoint(buf, 0, &val);
230	if (ret)
231		return ret;
232
233	val = clamp_val(val, 1, INT_MAX);
234
235	ina->shunt_resistors[channel] = val;
236
237	return count;
238}
239
240static ssize_t ina3221_show_alert(struct device *dev,
241				  struct device_attribute *attr, char *buf)
242{
243	struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(attr);
244	struct ina3221_data *ina = dev_get_drvdata(dev);
245	unsigned int field = sd_attr->index;
246	unsigned int regval;
247	int ret;
248
249	ret = regmap_field_read(ina->fields[field], &regval);
250	if (ret)
251		return ret;
252
253	return snprintf(buf, PAGE_SIZE, "%d\n", regval);
254}
255
256/* bus voltage */
257static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO,
258		ina3221_show_bus_voltage, NULL, INA3221_BUS1);
259static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO,
260		ina3221_show_bus_voltage, NULL, INA3221_BUS2);
261static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO,
262		ina3221_show_bus_voltage, NULL, INA3221_BUS3);
263
264/* calculated current */
265static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO,
266		ina3221_show_current, NULL, INA3221_SHUNT1);
267static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO,
268		ina3221_show_current, NULL, INA3221_SHUNT2);
269static SENSOR_DEVICE_ATTR(curr3_input, S_IRUGO,
270		ina3221_show_current, NULL, INA3221_SHUNT3);
271
272/* shunt resistance */
273static SENSOR_DEVICE_ATTR(shunt1_resistor, S_IRUGO | S_IWUSR,
274		ina3221_show_shunt, ina3221_set_shunt, INA3221_CHANNEL1);
275static SENSOR_DEVICE_ATTR(shunt2_resistor, S_IRUGO | S_IWUSR,
276		ina3221_show_shunt, ina3221_set_shunt, INA3221_CHANNEL2);
277static SENSOR_DEVICE_ATTR(shunt3_resistor, S_IRUGO | S_IWUSR,
278		ina3221_show_shunt, ina3221_set_shunt, INA3221_CHANNEL3);
279
280/* critical current */
281static SENSOR_DEVICE_ATTR(curr1_crit, S_IRUGO | S_IWUSR,
282		ina3221_show_current, ina3221_set_current, INA3221_CRIT1);
283static SENSOR_DEVICE_ATTR(curr2_crit, S_IRUGO | S_IWUSR,
284		ina3221_show_current, ina3221_set_current, INA3221_CRIT2);
285static SENSOR_DEVICE_ATTR(curr3_crit, S_IRUGO | S_IWUSR,
286		ina3221_show_current, ina3221_set_current, INA3221_CRIT3);
287
288/* critical current alert */
289static SENSOR_DEVICE_ATTR(curr1_crit_alarm, S_IRUGO,
290		ina3221_show_alert, NULL, F_CF1);
291static SENSOR_DEVICE_ATTR(curr2_crit_alarm, S_IRUGO,
292		ina3221_show_alert, NULL, F_CF2);
293static SENSOR_DEVICE_ATTR(curr3_crit_alarm, S_IRUGO,
294		ina3221_show_alert, NULL, F_CF3);
295
296/* warning current */
297static SENSOR_DEVICE_ATTR(curr1_max, S_IRUGO | S_IWUSR,
298		ina3221_show_current, ina3221_set_current, INA3221_WARN1);
299static SENSOR_DEVICE_ATTR(curr2_max, S_IRUGO | S_IWUSR,
300		ina3221_show_current, ina3221_set_current, INA3221_WARN2);
301static SENSOR_DEVICE_ATTR(curr3_max, S_IRUGO | S_IWUSR,
302		ina3221_show_current, ina3221_set_current, INA3221_WARN3);
303
304/* warning current alert */
305static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO,
306		ina3221_show_alert, NULL, F_WF1);
307static SENSOR_DEVICE_ATTR(curr2_max_alarm, S_IRUGO,
308		ina3221_show_alert, NULL, F_WF2);
309static SENSOR_DEVICE_ATTR(curr3_max_alarm, S_IRUGO,
310		ina3221_show_alert, NULL, F_WF3);
311
312/* shunt voltage */
313static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO,
314		ina3221_show_shunt_voltage, NULL, INA3221_SHUNT1);
315static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO,
316		ina3221_show_shunt_voltage, NULL, INA3221_SHUNT2);
317static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO,
318		ina3221_show_shunt_voltage, NULL, INA3221_SHUNT3);
319
320static struct attribute *ina3221_attrs[] = {
321	/* channel 1 */
322	&sensor_dev_attr_in1_input.dev_attr.attr,
323	&sensor_dev_attr_curr1_input.dev_attr.attr,
324	&sensor_dev_attr_shunt1_resistor.dev_attr.attr,
325	&sensor_dev_attr_curr1_crit.dev_attr.attr,
326	&sensor_dev_attr_curr1_crit_alarm.dev_attr.attr,
327	&sensor_dev_attr_curr1_max.dev_attr.attr,
328	&sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
329	&sensor_dev_attr_in4_input.dev_attr.attr,
330
331	/* channel 2 */
332	&sensor_dev_attr_in2_input.dev_attr.attr,
333	&sensor_dev_attr_curr2_input.dev_attr.attr,
334	&sensor_dev_attr_shunt2_resistor.dev_attr.attr,
335	&sensor_dev_attr_curr2_crit.dev_attr.attr,
336	&sensor_dev_attr_curr2_crit_alarm.dev_attr.attr,
337	&sensor_dev_attr_curr2_max.dev_attr.attr,
338	&sensor_dev_attr_curr2_max_alarm.dev_attr.attr,
339	&sensor_dev_attr_in5_input.dev_attr.attr,
340
341	/* channel 3 */
342	&sensor_dev_attr_in3_input.dev_attr.attr,
343	&sensor_dev_attr_curr3_input.dev_attr.attr,
344	&sensor_dev_attr_shunt3_resistor.dev_attr.attr,
345	&sensor_dev_attr_curr3_crit.dev_attr.attr,
346	&sensor_dev_attr_curr3_crit_alarm.dev_attr.attr,
347	&sensor_dev_attr_curr3_max.dev_attr.attr,
348	&sensor_dev_attr_curr3_max_alarm.dev_attr.attr,
349	&sensor_dev_attr_in6_input.dev_attr.attr,
350
351	NULL,
352};
353ATTRIBUTE_GROUPS(ina3221);
354
355static const struct regmap_range ina3221_yes_ranges[] = {
356	regmap_reg_range(INA3221_SHUNT1, INA3221_BUS3),
357	regmap_reg_range(INA3221_MASK_ENABLE, INA3221_MASK_ENABLE),
358};
359
360static const struct regmap_access_table ina3221_volatile_table = {
361	.yes_ranges = ina3221_yes_ranges,
362	.n_yes_ranges = ARRAY_SIZE(ina3221_yes_ranges),
363};
364
365static const struct regmap_config ina3221_regmap_config = {
366	.reg_bits = 8,
367	.val_bits = 16,
368
369	.cache_type = REGCACHE_RBTREE,
370	.volatile_table = &ina3221_volatile_table,
371};
372
373static int ina3221_probe(struct i2c_client *client,
374			 const struct i2c_device_id *id)
375{
376	struct device *dev = &client->dev;
377	struct ina3221_data *ina;
378	struct device *hwmon_dev;
379	int i, ret;
380
381	ina = devm_kzalloc(dev, sizeof(*ina), GFP_KERNEL);
382	if (!ina)
383		return -ENOMEM;
384
385	ina->regmap = devm_regmap_init_i2c(client, &ina3221_regmap_config);
386	if (IS_ERR(ina->regmap)) {
387		dev_err(dev, "Unable to allocate register map\n");
388		return PTR_ERR(ina->regmap);
389	}
390
391	for (i = 0; i < F_MAX_FIELDS; i++) {
392		ina->fields[i] = devm_regmap_field_alloc(dev,
393							 ina->regmap,
394							 ina3221_reg_fields[i]);
395		if (IS_ERR(ina->fields[i])) {
396			dev_err(dev, "Unable to allocate regmap fields\n");
397			return PTR_ERR(ina->fields[i]);
398		}
399	}
400
401	for (i = 0; i < INA3221_NUM_CHANNELS; i++)
402		ina->shunt_resistors[i] = INA3221_RSHUNT_DEFAULT;
403
404	ret = regmap_field_write(ina->fields[F_RST], true);
405	if (ret) {
406		dev_err(dev, "Unable to reset device\n");
407		return ret;
408	}
409
410	hwmon_dev = devm_hwmon_device_register_with_groups(dev,
411							   client->name,
412							   ina, ina3221_groups);
413	if (IS_ERR(hwmon_dev)) {
414		dev_err(dev, "Unable to register hwmon device\n");
415		return PTR_ERR(hwmon_dev);
416	}
417
418	return 0;
419}
420
421static const struct of_device_id ina3221_of_match_table[] = {
422	{ .compatible = "ti,ina3221", },
423	{ /* sentinel */ }
424};
425MODULE_DEVICE_TABLE(of, ina3221_of_match_table);
426
427static const struct i2c_device_id ina3221_ids[] = {
428	{ "ina3221", 0 },
429	{ /* sentinel */ }
430};
431MODULE_DEVICE_TABLE(i2c, ina3221_ids);
432
433static struct i2c_driver ina3221_i2c_driver = {
434	.probe = ina3221_probe,
435	.driver = {
436		.name = INA3221_DRIVER_NAME,
437		.of_match_table = ina3221_of_match_table,
438	},
439	.id_table = ina3221_ids,
440};
441module_i2c_driver(ina3221_i2c_driver);
442
443MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
444MODULE_DESCRIPTION("Texas Instruments INA3221 HWMon Driver");
445MODULE_LICENSE("GPL v2");