aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamuel Mendoza-Jonas <sam@mendozajonas.com>2017-04-30 20:39:01 -0400
committerGuenter Roeck <linux@roeck-us.net>2017-06-11 20:08:19 -0400
commit8991ebd9c9a69dcc03f5a961718a7a3184c1295d (patch)
tree9d900529a7753b1d2dcdb80dba5a0b5461237515
parent419220dc48699a3d215c8006d19b897c7796c0d2 (diff)
hwmon: (pmbus) Add client driver for IR35221
IR35221 is a Digital DC-DC Multiphase Converter Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com> [groeck: Preserve alphabetic order in Kconfig; add missing break statements (from Dan Carpenter); add missing error checks] Signed-off-by: Guenter Roeck <linux@roeck-us.net>
-rw-r--r--Documentation/hwmon/ir3522187
-rw-r--r--drivers/hwmon/pmbus/Kconfig10
-rw-r--r--drivers/hwmon/pmbus/Makefile1
-rw-r--r--drivers/hwmon/pmbus/ir35221.c337
4 files changed, 435 insertions, 0 deletions
diff --git a/Documentation/hwmon/ir35221 b/Documentation/hwmon/ir35221
new file mode 100644
index 000000000000..f7e112752c04
--- /dev/null
+++ b/Documentation/hwmon/ir35221
@@ -0,0 +1,87 @@
1Kernel driver ir35221
2=====================
3
4Supported chips:
5 * Infinion IR35221
6 Prefix: 'ir35221'
7 Addresses scanned: -
8 Datasheet: Datasheet is not publicly available.
9
10Author: Samuel Mendoza-Jonas <sam@mendozajonas.com>
11
12
13Description
14-----------
15
16IR35221 is a Digital DC-DC Multiphase Converter
17
18
19Usage Notes
20-----------
21
22This driver does not probe for PMBus devices. You will have to instantiate
23devices explicitly.
24
25Example: the following commands will load the driver for an IR35221
26at address 0x70 on I2C bus #4:
27
28# modprobe ir35221
29# echo ir35221 0x70 > /sys/bus/i2c/devices/i2c-4/new_device
30
31
32Sysfs attributes
33----------------
34
35curr1_label "iin"
36curr1_input Measured input current
37curr1_max Maximum current
38curr1_max_alarm Current high alarm
39
40curr[2-3]_label "iout[1-2]"
41curr[2-3]_input Measured output current
42curr[2-3]_crit Critical maximum current
43curr[2-3]_crit_alarm Current critical high alarm
44curr[2-3]_highest Highest output current
45curr[2-3]_lowest Lowest output current
46curr[2-3]_max Maximum current
47curr[2-3]_max_alarm Current high alarm
48
49in1_label "vin"
50in1_input Measured input voltage
51in1_crit Critical maximum input voltage
52in1_crit_alarm Input voltage critical high alarm
53in1_highest Highest input voltage
54in1_lowest Lowest input voltage
55in1_min Minimum input voltage
56in1_min_alarm Input voltage low alarm
57
58in[2-3]_label "vout[1-2]"
59in[2-3]_input Measured output voltage
60in[2-3]_lcrit Critical minimum output voltage
61in[2-3]_lcrit_alarm Output voltage critical low alarm
62in[2-3]_crit Critical maximum output voltage
63in[2-3]_crit_alarm Output voltage critical high alarm
64in[2-3]_highest Highest output voltage
65in[2-3]_lowest Lowest output voltage
66in[2-3]_max Maximum output voltage
67in[2-3]_max_alarm Output voltage high alarm
68in[2-3]_min Minimum output voltage
69in[2-3]_min_alarm Output voltage low alarm
70
71power1_label "pin"
72power1_input Measured input power
73power1_alarm Input power high alarm
74power1_max Input power limit
75
76power[2-3]_label "pout[1-2]"
77power[2-3]_input Measured output power
78power[2-3]_max Output power limit
79power[2-3]_max_alarm Output power high alarm
80
81temp[1-2]_input Measured temperature
82temp[1-2]_crit Critical high temperature
83temp[1-2]_crit_alarm Chip temperature critical high alarm
84temp[1-2]_highest Highest temperature
85temp[1-2]_lowest Lowest temperature
86temp[1-2]_max Maximum temperature
87temp[1-2]_max_alarm Chip temperature high alarm
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
index cad1229b7e17..68d717a3fd59 100644
--- a/drivers/hwmon/pmbus/Kconfig
+++ b/drivers/hwmon/pmbus/Kconfig
@@ -37,6 +37,16 @@ config SENSORS_ADM1275
37 This driver can also be built as a module. If so, the module will 37 This driver can also be built as a module. If so, the module will
38 be called adm1275. 38 be called adm1275.
39 39
40config SENSORS_IR35221
41 tristate "Infineon IR35221"
42 default n
43 help
44 If you say yes here you get hardware monitoring support for the
45 Infineon IR35221 controller.
46
47 This driver can also be built as a module. If so, the module will
48 be called ir35521.
49
40config SENSORS_LM25066 50config SENSORS_LM25066
41 tristate "National Semiconductor LM25066 and compatibles" 51 tristate "National Semiconductor LM25066 and compatibles"
42 default n 52 default n
diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile
index 562132054aaf..75bb7ca619d9 100644
--- a/drivers/hwmon/pmbus/Makefile
+++ b/drivers/hwmon/pmbus/Makefile
@@ -5,6 +5,7 @@
5obj-$(CONFIG_PMBUS) += pmbus_core.o 5obj-$(CONFIG_PMBUS) += pmbus_core.o
6obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o 6obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o
7obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o 7obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o
8obj-$(CONFIG_SENSORS_IR35221) += ir35221.o
8obj-$(CONFIG_SENSORS_LM25066) += lm25066.o 9obj-$(CONFIG_SENSORS_LM25066) += lm25066.o
9obj-$(CONFIG_SENSORS_LTC2978) += ltc2978.o 10obj-$(CONFIG_SENSORS_LTC2978) += ltc2978.o
10obj-$(CONFIG_SENSORS_LTC3815) += ltc3815.o 11obj-$(CONFIG_SENSORS_LTC3815) += ltc3815.o
diff --git a/drivers/hwmon/pmbus/ir35221.c b/drivers/hwmon/pmbus/ir35221.c
new file mode 100644
index 000000000000..8b906b44484b
--- /dev/null
+++ b/drivers/hwmon/pmbus/ir35221.c
@@ -0,0 +1,337 @@
1/*
2 * Hardware monitoring driver for IR35221
3 *
4 * Copyright (C) IBM Corporation 2017.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
12#include <linux/err.h>
13#include <linux/i2c.h>
14#include <linux/init.h>
15#include <linux/kernel.h>
16#include <linux/module.h>
17#include "pmbus.h"
18
19#define IR35221_MFR_VIN_PEAK 0xc5
20#define IR35221_MFR_VOUT_PEAK 0xc6
21#define IR35221_MFR_IOUT_PEAK 0xc7
22#define IR35221_MFR_TEMP_PEAK 0xc8
23#define IR35221_MFR_VIN_VALLEY 0xc9
24#define IR35221_MFR_VOUT_VALLEY 0xca
25#define IR35221_MFR_IOUT_VALLEY 0xcb
26#define IR35221_MFR_TEMP_VALLEY 0xcc
27
28static long ir35221_reg2data(int data, enum pmbus_sensor_classes class)
29{
30 s16 exponent;
31 s32 mantissa;
32 long val;
33
34 /* We only modify LINEAR11 formats */
35 exponent = ((s16)data) >> 11;
36 mantissa = ((s16)((data & 0x7ff) << 5)) >> 5;
37
38 val = mantissa * 1000L;
39
40 /* scale result to micro-units for power sensors */
41 if (class == PSC_POWER)
42 val = val * 1000L;
43
44 if (exponent >= 0)
45 val <<= exponent;
46 else
47 val >>= -exponent;
48
49 return val;
50}
51
52#define MAX_MANTISSA (1023 * 1000)
53#define MIN_MANTISSA (511 * 1000)
54
55static u16 ir35221_data2reg(long val, enum pmbus_sensor_classes class)
56{
57 s16 exponent = 0, mantissa;
58 bool negative = false;
59
60 if (val == 0)
61 return 0;
62
63 if (val < 0) {
64 negative = true;
65 val = -val;
66 }
67
68 /* Power is in uW. Convert to mW before converting. */
69 if (class == PSC_POWER)
70 val = DIV_ROUND_CLOSEST(val, 1000L);
71
72 /* Reduce large mantissa until it fits into 10 bit */
73 while (val >= MAX_MANTISSA && exponent < 15) {
74 exponent++;
75 val >>= 1;
76 }
77 /* Increase small mantissa to improve precision */
78 while (val < MIN_MANTISSA && exponent > -15) {
79 exponent--;
80 val <<= 1;
81 }
82
83 /* Convert mantissa from milli-units to units */
84 mantissa = DIV_ROUND_CLOSEST(val, 1000);
85
86 /* Ensure that resulting number is within range */
87 if (mantissa > 0x3ff)
88 mantissa = 0x3ff;
89
90 /* restore sign */
91 if (negative)
92 mantissa = -mantissa;
93
94 /* Convert to 5 bit exponent, 11 bit mantissa */
95 return (mantissa & 0x7ff) | ((exponent << 11) & 0xf800);
96}
97
98static u16 ir35221_scale_result(s16 data, int shift,
99 enum pmbus_sensor_classes class)
100{
101 long val;
102
103 val = ir35221_reg2data(data, class);
104
105 if (shift < 0)
106 val >>= -shift;
107 else
108 val <<= shift;
109
110 return ir35221_data2reg(val, class);
111}
112
113static int ir35221_read_word_data(struct i2c_client *client, int page, int reg)
114{
115 int ret;
116
117 switch (reg) {
118 case PMBUS_IOUT_OC_FAULT_LIMIT:
119 case PMBUS_IOUT_OC_WARN_LIMIT:
120 ret = pmbus_read_word_data(client, page, reg);
121 if (ret < 0)
122 break;
123 ret = ir35221_scale_result(ret, 1, PSC_CURRENT_OUT);
124 break;
125 case PMBUS_VIN_OV_FAULT_LIMIT:
126 case PMBUS_VIN_OV_WARN_LIMIT:
127 case PMBUS_VIN_UV_WARN_LIMIT:
128 ret = pmbus_read_word_data(client, page, reg);
129 ret = ir35221_scale_result(ret, -4, PSC_VOLTAGE_IN);
130 break;
131 case PMBUS_IIN_OC_WARN_LIMIT:
132 ret = pmbus_read_word_data(client, page, reg);
133 if (ret < 0)
134 break;
135 ret = ir35221_scale_result(ret, -1, PSC_CURRENT_IN);
136 break;
137 case PMBUS_READ_VIN:
138 ret = pmbus_read_word_data(client, page, PMBUS_READ_VIN);
139 if (ret < 0)
140 break;
141 ret = ir35221_scale_result(ret, -5, PSC_VOLTAGE_IN);
142 break;
143 case PMBUS_READ_IIN:
144 ret = pmbus_read_word_data(client, page, PMBUS_READ_IIN);
145 if (ret < 0)
146 break;
147 if (page == 0)
148 ret = ir35221_scale_result(ret, -4, PSC_CURRENT_IN);
149 else
150 ret = ir35221_scale_result(ret, -5, PSC_CURRENT_IN);
151 break;
152 case PMBUS_READ_POUT:
153 ret = pmbus_read_word_data(client, page, PMBUS_READ_POUT);
154 if (ret < 0)
155 break;
156 ret = ir35221_scale_result(ret, -1, PSC_POWER);
157 break;
158 case PMBUS_READ_PIN:
159 ret = pmbus_read_word_data(client, page, PMBUS_READ_PIN);
160 if (ret < 0)
161 break;
162 ret = ir35221_scale_result(ret, -1, PSC_POWER);
163 break;
164 case PMBUS_READ_IOUT:
165 ret = pmbus_read_word_data(client, page, PMBUS_READ_IOUT);
166 if (ret < 0)
167 break;
168 if (page == 0)
169 ret = ir35221_scale_result(ret, -1, PSC_CURRENT_OUT);
170 else
171 ret = ir35221_scale_result(ret, -2, PSC_CURRENT_OUT);
172 break;
173 case PMBUS_VIRT_READ_VIN_MAX:
174 ret = pmbus_read_word_data(client, page, IR35221_MFR_VIN_PEAK);
175 if (ret < 0)
176 break;
177 ret = ir35221_scale_result(ret, -5, PSC_VOLTAGE_IN);
178 break;
179 case PMBUS_VIRT_READ_VOUT_MAX:
180 ret = pmbus_read_word_data(client, page, IR35221_MFR_VOUT_PEAK);
181 break;
182 case PMBUS_VIRT_READ_IOUT_MAX:
183 ret = pmbus_read_word_data(client, page, IR35221_MFR_IOUT_PEAK);
184 if (ret < 0)
185 break;
186 if (page == 0)
187 ret = ir35221_scale_result(ret, -1, PSC_CURRENT_IN);
188 else
189 ret = ir35221_scale_result(ret, -2, PSC_CURRENT_IN);
190 break;
191 case PMBUS_VIRT_READ_TEMP_MAX:
192 ret = pmbus_read_word_data(client, page, IR35221_MFR_TEMP_PEAK);
193 break;
194 case PMBUS_VIRT_READ_VIN_MIN:
195 ret = pmbus_read_word_data(client, page,
196 IR35221_MFR_VIN_VALLEY);
197 if (ret < 0)
198 break;
199 ret = ir35221_scale_result(ret, -5, PSC_VOLTAGE_IN);
200 break;
201 case PMBUS_VIRT_READ_VOUT_MIN:
202 ret = pmbus_read_word_data(client, page,
203 IR35221_MFR_VOUT_VALLEY);
204 break;
205 case PMBUS_VIRT_READ_IOUT_MIN:
206 ret = pmbus_read_word_data(client, page,
207 IR35221_MFR_IOUT_VALLEY);
208 if (ret < 0)
209 break;
210 if (page == 0)
211 ret = ir35221_scale_result(ret, -1, PSC_CURRENT_IN);
212 else
213 ret = ir35221_scale_result(ret, -2, PSC_CURRENT_IN);
214 break;
215 case PMBUS_VIRT_READ_TEMP_MIN:
216 ret = pmbus_read_word_data(client, page,
217 IR35221_MFR_TEMP_VALLEY);
218 break;
219 default:
220 ret = -ENODATA;
221 break;
222 }
223
224 return ret;
225}
226
227static int ir35221_write_word_data(struct i2c_client *client, int page, int reg,
228 u16 word)
229{
230 int ret;
231 u16 val;
232
233 switch (reg) {
234 case PMBUS_IOUT_OC_FAULT_LIMIT:
235 case PMBUS_IOUT_OC_WARN_LIMIT:
236 val = ir35221_scale_result(word, -1, PSC_CURRENT_OUT);
237 ret = pmbus_write_word_data(client, page, reg, val);
238 break;
239 case PMBUS_VIN_OV_FAULT_LIMIT:
240 case PMBUS_VIN_OV_WARN_LIMIT:
241 case PMBUS_VIN_UV_WARN_LIMIT:
242 val = ir35221_scale_result(word, 4, PSC_VOLTAGE_IN);
243 ret = pmbus_write_word_data(client, page, reg, val);
244 break;
245 case PMBUS_IIN_OC_WARN_LIMIT:
246 val = ir35221_scale_result(word, 1, PSC_CURRENT_IN);
247 ret = pmbus_write_word_data(client, page, reg, val);
248 break;
249 default:
250 ret = -ENODATA;
251 break;
252 }
253
254 return ret;
255}
256
257static int ir35221_probe(struct i2c_client *client,
258 const struct i2c_device_id *id)
259{
260 struct pmbus_driver_info *info;
261 u8 buf[I2C_SMBUS_BLOCK_MAX];
262 int ret;
263
264 if (!i2c_check_functionality(client->adapter,
265 I2C_FUNC_SMBUS_READ_BYTE_DATA
266 | I2C_FUNC_SMBUS_READ_WORD_DATA
267 | I2C_FUNC_SMBUS_READ_BLOCK_DATA))
268 return -ENODEV;
269
270 ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);
271 if (ret < 0) {
272 dev_err(&client->dev, "Failed to read PMBUS_MFR_ID\n");
273 return ret;
274 }
275 if (ret != 2 || strncmp(buf, "RI", strlen("RI"))) {
276 dev_err(&client->dev, "MFR_ID unrecognised\n");
277 return -ENODEV;
278 }
279
280 ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf);
281 if (ret < 0) {
282 dev_err(&client->dev, "Failed to read PMBUS_MFR_MODEL\n");
283 return ret;
284 }
285 if (ret != 2 || !(buf[0] == 0x6c && buf[1] == 0x00)) {
286 dev_err(&client->dev, "MFR_MODEL unrecognised\n");
287 return -ENODEV;
288 }
289
290 info = devm_kzalloc(&client->dev, sizeof(struct pmbus_driver_info),
291 GFP_KERNEL);
292 if (!info)
293 return -ENOMEM;
294
295 info->write_word_data = ir35221_write_word_data;
296 info->read_word_data = ir35221_read_word_data;
297
298 info->pages = 2;
299 info->format[PSC_VOLTAGE_IN] = linear;
300 info->format[PSC_VOLTAGE_OUT] = linear;
301 info->format[PSC_CURRENT_IN] = linear;
302 info->format[PSC_CURRENT_OUT] = linear;
303 info->format[PSC_POWER] = linear;
304 info->format[PSC_TEMPERATURE] = linear;
305
306 info->func[0] = PMBUS_HAVE_VIN
307 | PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN
308 | PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN
309 | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
310 | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT
311 | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP;
312 info->func[1] = info->func[0];
313
314 return pmbus_do_probe(client, id, info);
315}
316
317static const struct i2c_device_id ir35221_id[] = {
318 {"ir35221", 0},
319 {}
320};
321
322MODULE_DEVICE_TABLE(i2c, ir35221_id);
323
324static struct i2c_driver ir35221_driver = {
325 .driver = {
326 .name = "ir35221",
327 },
328 .probe = ir35221_probe,
329 .remove = pmbus_do_remove,
330 .id_table = ir35221_id,
331};
332
333module_i2c_driver(ir35221_driver);
334
335MODULE_AUTHOR("Samuel Mendoza-Jonas <sam@mendozajonas.com");
336MODULE_DESCRIPTION("PMBus driver for IR35221");
337MODULE_LICENSE("GPL");