blob: 8b906b44484b8da6ac4a09d0b54f9afb87de2491 [file] [log] [blame]
Samuel Mendoza-Jonas8991ebd2017-05-01 10:39:01 +10001/*
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");