xref: /linux/drivers/hwmon/ltc4222.c (revision 79ffe8594f23475d83112cd5bd68805f91e49170)
1*79ffe859SGuenter Roeck /*
2*79ffe859SGuenter Roeck  * Driver for Linear Technology LTC4222 Dual Hot Swap controller
3*79ffe859SGuenter Roeck  *
4*79ffe859SGuenter Roeck  * Copyright (c) 2014 Guenter Roeck
5*79ffe859SGuenter Roeck  *
6*79ffe859SGuenter Roeck  * This program is free software; you can redistribute it and/or modify
7*79ffe859SGuenter Roeck  * it under the terms of the GNU General Public License as published by
8*79ffe859SGuenter Roeck  * the Free Software Foundation; either version 2 of the License, or
9*79ffe859SGuenter Roeck  * (at your option) any later version.
10*79ffe859SGuenter Roeck  *
11*79ffe859SGuenter Roeck  * This program is distributed in the hope that it will be useful,
12*79ffe859SGuenter Roeck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13*79ffe859SGuenter Roeck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*79ffe859SGuenter Roeck  * GNU General Public License for more details.
15*79ffe859SGuenter Roeck  */
16*79ffe859SGuenter Roeck 
17*79ffe859SGuenter Roeck #include <linux/kernel.h>
18*79ffe859SGuenter Roeck #include <linux/module.h>
19*79ffe859SGuenter Roeck #include <linux/err.h>
20*79ffe859SGuenter Roeck #include <linux/slab.h>
21*79ffe859SGuenter Roeck #include <linux/bitops.h>
22*79ffe859SGuenter Roeck #include <linux/i2c.h>
23*79ffe859SGuenter Roeck #include <linux/hwmon.h>
24*79ffe859SGuenter Roeck #include <linux/hwmon-sysfs.h>
25*79ffe859SGuenter Roeck #include <linux/jiffies.h>
26*79ffe859SGuenter Roeck #include <linux/regmap.h>
27*79ffe859SGuenter Roeck 
28*79ffe859SGuenter Roeck /* chip registers */
29*79ffe859SGuenter Roeck 
30*79ffe859SGuenter Roeck #define LTC4222_CONTROL1	0xd0
31*79ffe859SGuenter Roeck #define LTC4222_ALERT1		0xd1
32*79ffe859SGuenter Roeck #define LTC4222_STATUS1		0xd2
33*79ffe859SGuenter Roeck #define LTC4222_FAULT1		0xd3
34*79ffe859SGuenter Roeck #define LTC4222_CONTROL2	0xd4
35*79ffe859SGuenter Roeck #define LTC4222_ALERT2		0xd5
36*79ffe859SGuenter Roeck #define LTC4222_STATUS2		0xd6
37*79ffe859SGuenter Roeck #define LTC4222_FAULT2		0xd7
38*79ffe859SGuenter Roeck #define LTC4222_SOURCE1		0xd8
39*79ffe859SGuenter Roeck #define LTC4222_SOURCE2		0xda
40*79ffe859SGuenter Roeck #define LTC4222_ADIN1		0xdc
41*79ffe859SGuenter Roeck #define LTC4222_ADIN2		0xde
42*79ffe859SGuenter Roeck #define LTC4222_SENSE1		0xe0
43*79ffe859SGuenter Roeck #define LTC4222_SENSE2		0xe2
44*79ffe859SGuenter Roeck #define LTC4222_ADC_CONTROL	0xe4
45*79ffe859SGuenter Roeck 
46*79ffe859SGuenter Roeck /*
47*79ffe859SGuenter Roeck  * Fault register bits
48*79ffe859SGuenter Roeck  */
49*79ffe859SGuenter Roeck #define FAULT_OV	BIT(0)
50*79ffe859SGuenter Roeck #define FAULT_UV	BIT(1)
51*79ffe859SGuenter Roeck #define FAULT_OC	BIT(2)
52*79ffe859SGuenter Roeck #define FAULT_POWER_BAD	BIT(3)
53*79ffe859SGuenter Roeck #define FAULT_FET_BAD	BIT(5)
54*79ffe859SGuenter Roeck 
55*79ffe859SGuenter Roeck /* Return the voltage from the given register in mV or mA */
56*79ffe859SGuenter Roeck static int ltc4222_get_value(struct device *dev, u8 reg)
57*79ffe859SGuenter Roeck {
58*79ffe859SGuenter Roeck 	struct regmap *regmap = dev_get_drvdata(dev);
59*79ffe859SGuenter Roeck 	unsigned int val;
60*79ffe859SGuenter Roeck 	u8 buf[2];
61*79ffe859SGuenter Roeck 	int ret;
62*79ffe859SGuenter Roeck 
63*79ffe859SGuenter Roeck 	ret = regmap_bulk_read(regmap, reg, buf, 2);
64*79ffe859SGuenter Roeck 	if (ret < 0)
65*79ffe859SGuenter Roeck 		return ret;
66*79ffe859SGuenter Roeck 
67*79ffe859SGuenter Roeck 	val = ((buf[0] << 8) + buf[1]) >> 6;
68*79ffe859SGuenter Roeck 
69*79ffe859SGuenter Roeck 	switch (reg) {
70*79ffe859SGuenter Roeck 	case LTC4222_ADIN1:
71*79ffe859SGuenter Roeck 	case LTC4222_ADIN2:
72*79ffe859SGuenter Roeck 		/* 1.25 mV resolution. Convert to mV. */
73*79ffe859SGuenter Roeck 		val = DIV_ROUND_CLOSEST(val * 5, 4);
74*79ffe859SGuenter Roeck 		break;
75*79ffe859SGuenter Roeck 	case LTC4222_SOURCE1:
76*79ffe859SGuenter Roeck 	case LTC4222_SOURCE2:
77*79ffe859SGuenter Roeck 		/* 31.25 mV resolution. Convert to mV. */
78*79ffe859SGuenter Roeck 		val = DIV_ROUND_CLOSEST(val * 125, 4);
79*79ffe859SGuenter Roeck 		break;
80*79ffe859SGuenter Roeck 	case LTC4222_SENSE1:
81*79ffe859SGuenter Roeck 	case LTC4222_SENSE2:
82*79ffe859SGuenter Roeck 		/*
83*79ffe859SGuenter Roeck 		 * 62.5 uV resolution. Convert to current as measured with
84*79ffe859SGuenter Roeck 		 * an 1 mOhm sense resistor, in mA. If a different sense
85*79ffe859SGuenter Roeck 		 * resistor is installed, calculate the actual current by
86*79ffe859SGuenter Roeck 		 * dividing the reported current by the sense resistor value
87*79ffe859SGuenter Roeck 		 * in mOhm.
88*79ffe859SGuenter Roeck 		 */
89*79ffe859SGuenter Roeck 		val = DIV_ROUND_CLOSEST(val * 125, 2);
90*79ffe859SGuenter Roeck 		break;
91*79ffe859SGuenter Roeck 	default:
92*79ffe859SGuenter Roeck 		return -EINVAL;
93*79ffe859SGuenter Roeck 	}
94*79ffe859SGuenter Roeck 	return val;
95*79ffe859SGuenter Roeck }
96*79ffe859SGuenter Roeck 
97*79ffe859SGuenter Roeck static ssize_t ltc4222_show_value(struct device *dev,
98*79ffe859SGuenter Roeck 				  struct device_attribute *da, char *buf)
99*79ffe859SGuenter Roeck {
100*79ffe859SGuenter Roeck 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
101*79ffe859SGuenter Roeck 	int value;
102*79ffe859SGuenter Roeck 
103*79ffe859SGuenter Roeck 	value = ltc4222_get_value(dev, attr->index);
104*79ffe859SGuenter Roeck 	if (value < 0)
105*79ffe859SGuenter Roeck 		return value;
106*79ffe859SGuenter Roeck 	return snprintf(buf, PAGE_SIZE, "%d\n", value);
107*79ffe859SGuenter Roeck }
108*79ffe859SGuenter Roeck 
109*79ffe859SGuenter Roeck static ssize_t ltc4222_show_bool(struct device *dev,
110*79ffe859SGuenter Roeck 				 struct device_attribute *da, char *buf)
111*79ffe859SGuenter Roeck {
112*79ffe859SGuenter Roeck 	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(da);
113*79ffe859SGuenter Roeck 	struct regmap *regmap = dev_get_drvdata(dev);
114*79ffe859SGuenter Roeck 	unsigned int fault;
115*79ffe859SGuenter Roeck 	int ret;
116*79ffe859SGuenter Roeck 
117*79ffe859SGuenter Roeck 	ret = regmap_read(regmap, attr->nr, &fault);
118*79ffe859SGuenter Roeck 	if (ret < 0)
119*79ffe859SGuenter Roeck 		return ret;
120*79ffe859SGuenter Roeck 	fault &= attr->index;
121*79ffe859SGuenter Roeck 	if (fault)		/* Clear reported faults in chip register */
122*79ffe859SGuenter Roeck 		regmap_update_bits(regmap, attr->nr, attr->index, 0);
123*79ffe859SGuenter Roeck 
124*79ffe859SGuenter Roeck 	return snprintf(buf, PAGE_SIZE, "%d\n", !!fault);
125*79ffe859SGuenter Roeck }
126*79ffe859SGuenter Roeck 
127*79ffe859SGuenter Roeck /* Voltages */
128*79ffe859SGuenter Roeck static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4222_show_value, NULL,
129*79ffe859SGuenter Roeck 			  LTC4222_SOURCE1);
130*79ffe859SGuenter Roeck static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4222_show_value, NULL,
131*79ffe859SGuenter Roeck 			  LTC4222_ADIN1);
132*79ffe859SGuenter Roeck static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, ltc4222_show_value, NULL,
133*79ffe859SGuenter Roeck 			  LTC4222_SOURCE2);
134*79ffe859SGuenter Roeck static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, ltc4222_show_value, NULL,
135*79ffe859SGuenter Roeck 			  LTC4222_ADIN2);
136*79ffe859SGuenter Roeck 
137*79ffe859SGuenter Roeck /*
138*79ffe859SGuenter Roeck  * Voltage alarms
139*79ffe859SGuenter Roeck  * UV/OV faults are associated with the input voltage, and power bad and fet
140*79ffe859SGuenter Roeck  * faults are associated with the output voltage.
141*79ffe859SGuenter Roeck  */
142*79ffe859SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in1_min_alarm, S_IRUGO, ltc4222_show_bool, NULL,
143*79ffe859SGuenter Roeck 			    LTC4222_FAULT1, FAULT_UV);
144*79ffe859SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in1_max_alarm, S_IRUGO, ltc4222_show_bool, NULL,
145*79ffe859SGuenter Roeck 			    LTC4222_FAULT1, FAULT_OV);
146*79ffe859SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in2_alarm, S_IRUGO, ltc4222_show_bool, NULL,
147*79ffe859SGuenter Roeck 			    LTC4222_FAULT1, FAULT_POWER_BAD | FAULT_FET_BAD);
148*79ffe859SGuenter Roeck 
149*79ffe859SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in3_min_alarm, S_IRUGO, ltc4222_show_bool, NULL,
150*79ffe859SGuenter Roeck 			    LTC4222_FAULT2, FAULT_UV);
151*79ffe859SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in3_max_alarm, S_IRUGO, ltc4222_show_bool, NULL,
152*79ffe859SGuenter Roeck 			    LTC4222_FAULT2, FAULT_OV);
153*79ffe859SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in4_alarm, S_IRUGO, ltc4222_show_bool, NULL,
154*79ffe859SGuenter Roeck 			    LTC4222_FAULT2, FAULT_POWER_BAD | FAULT_FET_BAD);
155*79ffe859SGuenter Roeck 
156*79ffe859SGuenter Roeck /* Current (via sense resistor) */
157*79ffe859SGuenter Roeck static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4222_show_value, NULL,
158*79ffe859SGuenter Roeck 			  LTC4222_SENSE1);
159*79ffe859SGuenter Roeck static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, ltc4222_show_value, NULL,
160*79ffe859SGuenter Roeck 			  LTC4222_SENSE2);
161*79ffe859SGuenter Roeck 
162*79ffe859SGuenter Roeck /* Overcurrent alarm */
163*79ffe859SGuenter Roeck static SENSOR_DEVICE_ATTR_2(curr1_max_alarm, S_IRUGO, ltc4222_show_bool, NULL,
164*79ffe859SGuenter Roeck 			    LTC4222_FAULT1, FAULT_OC);
165*79ffe859SGuenter Roeck static SENSOR_DEVICE_ATTR_2(curr2_max_alarm, S_IRUGO, ltc4222_show_bool, NULL,
166*79ffe859SGuenter Roeck 			    LTC4222_FAULT2, FAULT_OC);
167*79ffe859SGuenter Roeck 
168*79ffe859SGuenter Roeck static struct attribute *ltc4222_attrs[] = {
169*79ffe859SGuenter Roeck 	&sensor_dev_attr_in1_input.dev_attr.attr,
170*79ffe859SGuenter Roeck 	&sensor_dev_attr_in1_min_alarm.dev_attr.attr,
171*79ffe859SGuenter Roeck 	&sensor_dev_attr_in1_max_alarm.dev_attr.attr,
172*79ffe859SGuenter Roeck 	&sensor_dev_attr_in2_input.dev_attr.attr,
173*79ffe859SGuenter Roeck 	&sensor_dev_attr_in2_alarm.dev_attr.attr,
174*79ffe859SGuenter Roeck 	&sensor_dev_attr_in3_input.dev_attr.attr,
175*79ffe859SGuenter Roeck 	&sensor_dev_attr_in3_min_alarm.dev_attr.attr,
176*79ffe859SGuenter Roeck 	&sensor_dev_attr_in3_max_alarm.dev_attr.attr,
177*79ffe859SGuenter Roeck 	&sensor_dev_attr_in4_input.dev_attr.attr,
178*79ffe859SGuenter Roeck 	&sensor_dev_attr_in4_alarm.dev_attr.attr,
179*79ffe859SGuenter Roeck 
180*79ffe859SGuenter Roeck 	&sensor_dev_attr_curr1_input.dev_attr.attr,
181*79ffe859SGuenter Roeck 	&sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
182*79ffe859SGuenter Roeck 	&sensor_dev_attr_curr2_input.dev_attr.attr,
183*79ffe859SGuenter Roeck 	&sensor_dev_attr_curr2_max_alarm.dev_attr.attr,
184*79ffe859SGuenter Roeck 
185*79ffe859SGuenter Roeck 	NULL,
186*79ffe859SGuenter Roeck };
187*79ffe859SGuenter Roeck ATTRIBUTE_GROUPS(ltc4222);
188*79ffe859SGuenter Roeck 
189*79ffe859SGuenter Roeck static struct regmap_config ltc4222_regmap_config = {
190*79ffe859SGuenter Roeck 	.reg_bits = 8,
191*79ffe859SGuenter Roeck 	.val_bits = 8,
192*79ffe859SGuenter Roeck 	.max_register = LTC4222_ADC_CONTROL,
193*79ffe859SGuenter Roeck };
194*79ffe859SGuenter Roeck 
195*79ffe859SGuenter Roeck static int ltc4222_probe(struct i2c_client *client,
196*79ffe859SGuenter Roeck 			 const struct i2c_device_id *id)
197*79ffe859SGuenter Roeck {
198*79ffe859SGuenter Roeck 	struct device *dev = &client->dev;
199*79ffe859SGuenter Roeck 	struct device *hwmon_dev;
200*79ffe859SGuenter Roeck 	struct regmap *regmap;
201*79ffe859SGuenter Roeck 
202*79ffe859SGuenter Roeck 	regmap = devm_regmap_init_i2c(client, &ltc4222_regmap_config);
203*79ffe859SGuenter Roeck 	if (IS_ERR(regmap)) {
204*79ffe859SGuenter Roeck 		dev_err(dev, "failed to allocate register map\n");
205*79ffe859SGuenter Roeck 		return PTR_ERR(regmap);
206*79ffe859SGuenter Roeck 	}
207*79ffe859SGuenter Roeck 
208*79ffe859SGuenter Roeck 	/* Clear faults */
209*79ffe859SGuenter Roeck 	regmap_write(regmap, LTC4222_FAULT1, 0x00);
210*79ffe859SGuenter Roeck 	regmap_write(regmap, LTC4222_FAULT2, 0x00);
211*79ffe859SGuenter Roeck 
212*79ffe859SGuenter Roeck 	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
213*79ffe859SGuenter Roeck 							   regmap,
214*79ffe859SGuenter Roeck 							   ltc4222_groups);
215*79ffe859SGuenter Roeck 	return PTR_ERR_OR_ZERO(hwmon_dev);
216*79ffe859SGuenter Roeck }
217*79ffe859SGuenter Roeck 
218*79ffe859SGuenter Roeck static const struct i2c_device_id ltc4222_id[] = {
219*79ffe859SGuenter Roeck 	{"ltc4222", 0},
220*79ffe859SGuenter Roeck 	{ }
221*79ffe859SGuenter Roeck };
222*79ffe859SGuenter Roeck 
223*79ffe859SGuenter Roeck MODULE_DEVICE_TABLE(i2c, ltc4222_id);
224*79ffe859SGuenter Roeck 
225*79ffe859SGuenter Roeck static struct i2c_driver ltc4222_driver = {
226*79ffe859SGuenter Roeck 	.driver = {
227*79ffe859SGuenter Roeck 		   .name = "ltc4222",
228*79ffe859SGuenter Roeck 		   },
229*79ffe859SGuenter Roeck 	.probe = ltc4222_probe,
230*79ffe859SGuenter Roeck 	.id_table = ltc4222_id,
231*79ffe859SGuenter Roeck };
232*79ffe859SGuenter Roeck 
233*79ffe859SGuenter Roeck module_i2c_driver(ltc4222_driver);
234*79ffe859SGuenter Roeck 
235*79ffe859SGuenter Roeck MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
236*79ffe859SGuenter Roeck MODULE_DESCRIPTION("LTC4222 driver");
237*79ffe859SGuenter Roeck MODULE_LICENSE("GPL");
238