diff options
Diffstat (limited to 'drivers/hwmon/pmbus/pmbus_core.c')
-rw-r--r-- | drivers/hwmon/pmbus/pmbus_core.c | 1758 |
1 files changed, 1758 insertions, 0 deletions
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c new file mode 100644 index 00000000000..5c1b6cf3170 --- /dev/null +++ b/drivers/hwmon/pmbus/pmbus_core.c | |||
@@ -0,0 +1,1758 @@ | |||
1 | /* | ||
2 | * Hardware monitoring driver for PMBus devices | ||
3 | * | ||
4 | * Copyright (c) 2010, 2011 Ericsson AB. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/err.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/i2c.h> | ||
27 | #include <linux/hwmon.h> | ||
28 | #include <linux/hwmon-sysfs.h> | ||
29 | #include <linux/delay.h> | ||
30 | #include <linux/i2c/pmbus.h> | ||
31 | #include "pmbus.h" | ||
32 | |||
33 | /* | ||
34 | * Constants needed to determine number of sensors, booleans, and labels. | ||
35 | */ | ||
36 | #define PMBUS_MAX_INPUT_SENSORS 22 /* 10*volt, 7*curr, 5*power */ | ||
37 | #define PMBUS_VOUT_SENSORS_PER_PAGE 9 /* input, min, max, lcrit, | ||
38 | crit, lowest, highest, avg, | ||
39 | reset */ | ||
40 | #define PMBUS_IOUT_SENSORS_PER_PAGE 8 /* input, min, max, crit, | ||
41 | lowest, highest, avg, | ||
42 | reset */ | ||
43 | #define PMBUS_POUT_SENSORS_PER_PAGE 4 /* input, cap, max, crit */ | ||
44 | #define PMBUS_MAX_SENSORS_PER_FAN 1 /* input */ | ||
45 | #define PMBUS_MAX_SENSORS_PER_TEMP 8 /* input, min, max, lcrit, | ||
46 | crit, lowest, highest, | ||
47 | reset */ | ||
48 | |||
49 | #define PMBUS_MAX_INPUT_BOOLEANS 7 /* v: min_alarm, max_alarm, | ||
50 | lcrit_alarm, crit_alarm; | ||
51 | c: alarm, crit_alarm; | ||
52 | p: crit_alarm */ | ||
53 | #define PMBUS_VOUT_BOOLEANS_PER_PAGE 4 /* min_alarm, max_alarm, | ||
54 | lcrit_alarm, crit_alarm */ | ||
55 | #define PMBUS_IOUT_BOOLEANS_PER_PAGE 3 /* alarm, lcrit_alarm, | ||
56 | crit_alarm */ | ||
57 | #define PMBUS_POUT_BOOLEANS_PER_PAGE 2 /* alarm, crit_alarm */ | ||
58 | #define PMBUS_MAX_BOOLEANS_PER_FAN 2 /* alarm, fault */ | ||
59 | #define PMBUS_MAX_BOOLEANS_PER_TEMP 4 /* min_alarm, max_alarm, | ||
60 | lcrit_alarm, crit_alarm */ | ||
61 | |||
62 | #define PMBUS_MAX_INPUT_LABELS 4 /* vin, vcap, iin, pin */ | ||
63 | |||
64 | /* | ||
65 | * status, status_vout, status_iout, status_fans, status_fan34, and status_temp | ||
66 | * are paged. status_input is unpaged. | ||
67 | */ | ||
68 | #define PB_NUM_STATUS_REG (PMBUS_PAGES * 6 + 1) | ||
69 | |||
70 | /* | ||
71 | * Index into status register array, per status register group | ||
72 | */ | ||
73 | #define PB_STATUS_BASE 0 | ||
74 | #define PB_STATUS_VOUT_BASE (PB_STATUS_BASE + PMBUS_PAGES) | ||
75 | #define PB_STATUS_IOUT_BASE (PB_STATUS_VOUT_BASE + PMBUS_PAGES) | ||
76 | #define PB_STATUS_FAN_BASE (PB_STATUS_IOUT_BASE + PMBUS_PAGES) | ||
77 | #define PB_STATUS_FAN34_BASE (PB_STATUS_FAN_BASE + PMBUS_PAGES) | ||
78 | #define PB_STATUS_INPUT_BASE (PB_STATUS_FAN34_BASE + PMBUS_PAGES) | ||
79 | #define PB_STATUS_TEMP_BASE (PB_STATUS_INPUT_BASE + 1) | ||
80 | |||
81 | #define PMBUS_NAME_SIZE 24 | ||
82 | |||
83 | struct pmbus_sensor { | ||
84 | char name[PMBUS_NAME_SIZE]; /* sysfs sensor name */ | ||
85 | struct sensor_device_attribute attribute; | ||
86 | u8 page; /* page number */ | ||
87 | u16 reg; /* register */ | ||
88 | enum pmbus_sensor_classes class; /* sensor class */ | ||
89 | bool update; /* runtime sensor update needed */ | ||
90 | int data; /* Sensor data. | ||
91 | Negative if there was a read error */ | ||
92 | }; | ||
93 | |||
94 | struct pmbus_boolean { | ||
95 | char name[PMBUS_NAME_SIZE]; /* sysfs boolean name */ | ||
96 | struct sensor_device_attribute attribute; | ||
97 | }; | ||
98 | |||
99 | struct pmbus_label { | ||
100 | char name[PMBUS_NAME_SIZE]; /* sysfs label name */ | ||
101 | struct sensor_device_attribute attribute; | ||
102 | char label[PMBUS_NAME_SIZE]; /* label */ | ||
103 | }; | ||
104 | |||
105 | struct pmbus_data { | ||
106 | struct device *hwmon_dev; | ||
107 | |||
108 | u32 flags; /* from platform data */ | ||
109 | |||
110 | int exponent; /* linear mode: exponent for output voltages */ | ||
111 | |||
112 | const struct pmbus_driver_info *info; | ||
113 | |||
114 | int max_attributes; | ||
115 | int num_attributes; | ||
116 | struct attribute **attributes; | ||
117 | struct attribute_group group; | ||
118 | |||
119 | /* | ||
120 | * Sensors cover both sensor and limit registers. | ||
121 | */ | ||
122 | int max_sensors; | ||
123 | int num_sensors; | ||
124 | struct pmbus_sensor *sensors; | ||
125 | /* | ||
126 | * Booleans are used for alarms. | ||
127 | * Values are determined from status registers. | ||
128 | */ | ||
129 | int max_booleans; | ||
130 | int num_booleans; | ||
131 | struct pmbus_boolean *booleans; | ||
132 | /* | ||
133 | * Labels are used to map generic names (e.g., "in1") | ||
134 | * to PMBus specific names (e.g., "vin" or "vout1"). | ||
135 | */ | ||
136 | int max_labels; | ||
137 | int num_labels; | ||
138 | struct pmbus_label *labels; | ||
139 | |||
140 | struct mutex update_lock; | ||
141 | bool valid; | ||
142 | unsigned long last_updated; /* in jiffies */ | ||
143 | |||
144 | /* | ||
145 | * A single status register covers multiple attributes, | ||
146 | * so we keep them all together. | ||
147 | */ | ||
148 | u8 status[PB_NUM_STATUS_REG]; | ||
149 | |||
150 | u8 currpage; | ||
151 | }; | ||
152 | |||
153 | int pmbus_set_page(struct i2c_client *client, u8 page) | ||
154 | { | ||
155 | struct pmbus_data *data = i2c_get_clientdata(client); | ||
156 | int rv = 0; | ||
157 | int newpage; | ||
158 | |||
159 | if (page != data->currpage) { | ||
160 | rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page); | ||
161 | newpage = i2c_smbus_read_byte_data(client, PMBUS_PAGE); | ||
162 | if (newpage != page) | ||
163 | rv = -EINVAL; | ||
164 | else | ||
165 | data->currpage = page; | ||
166 | } | ||
167 | return rv; | ||
168 | } | ||
169 | EXPORT_SYMBOL_GPL(pmbus_set_page); | ||
170 | |||
171 | int pmbus_write_byte(struct i2c_client *client, int page, u8 value) | ||
172 | { | ||
173 | int rv; | ||
174 | |||
175 | if (page >= 0) { | ||
176 | rv = pmbus_set_page(client, page); | ||
177 | if (rv < 0) | ||
178 | return rv; | ||
179 | } | ||
180 | |||
181 | return i2c_smbus_write_byte(client, value); | ||
182 | } | ||
183 | EXPORT_SYMBOL_GPL(pmbus_write_byte); | ||
184 | |||
185 | int pmbus_write_word_data(struct i2c_client *client, u8 page, u8 reg, u16 word) | ||
186 | { | ||
187 | int rv; | ||
188 | |||
189 | rv = pmbus_set_page(client, page); | ||
190 | if (rv < 0) | ||
191 | return rv; | ||
192 | |||
193 | return i2c_smbus_write_word_data(client, reg, word); | ||
194 | } | ||
195 | EXPORT_SYMBOL_GPL(pmbus_write_word_data); | ||
196 | |||
197 | /* | ||
198 | * _pmbus_write_word_data() is similar to pmbus_write_word_data(), but checks if | ||
199 | * a device specific mapping function exists and calls it if necessary. | ||
200 | */ | ||
201 | static int _pmbus_write_word_data(struct i2c_client *client, int page, int reg, | ||
202 | u16 word) | ||
203 | { | ||
204 | struct pmbus_data *data = i2c_get_clientdata(client); | ||
205 | const struct pmbus_driver_info *info = data->info; | ||
206 | int status; | ||
207 | |||
208 | if (info->write_word_data) { | ||
209 | status = info->write_word_data(client, page, reg, word); | ||
210 | if (status != -ENODATA) | ||
211 | return status; | ||
212 | } | ||
213 | if (reg >= PMBUS_VIRT_BASE) | ||
214 | return -EINVAL; | ||
215 | return pmbus_write_word_data(client, page, reg, word); | ||
216 | } | ||
217 | |||
218 | int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg) | ||
219 | { | ||
220 | int rv; | ||
221 | |||
222 | rv = pmbus_set_page(client, page); | ||
223 | if (rv < 0) | ||
224 | return rv; | ||
225 | |||
226 | return i2c_smbus_read_word_data(client, reg); | ||
227 | } | ||
228 | EXPORT_SYMBOL_GPL(pmbus_read_word_data); | ||
229 | |||
230 | /* | ||
231 | * _pmbus_read_word_data() is similar to pmbus_read_word_data(), but checks if | ||
232 | * a device specific mapping function exists and calls it if necessary. | ||
233 | */ | ||
234 | static int _pmbus_read_word_data(struct i2c_client *client, int page, int reg) | ||
235 | { | ||
236 | struct pmbus_data *data = i2c_get_clientdata(client); | ||
237 | const struct pmbus_driver_info *info = data->info; | ||
238 | int status; | ||
239 | |||
240 | if (info->read_word_data) { | ||
241 | status = info->read_word_data(client, page, reg); | ||
242 | if (status != -ENODATA) | ||
243 | return status; | ||
244 | } | ||
245 | if (reg >= PMBUS_VIRT_BASE) | ||
246 | return -EINVAL; | ||
247 | return pmbus_read_word_data(client, page, reg); | ||
248 | } | ||
249 | |||
250 | int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg) | ||
251 | { | ||
252 | int rv; | ||
253 | |||
254 | if (page >= 0) { | ||
255 | rv = pmbus_set_page(client, page); | ||
256 | if (rv < 0) | ||
257 | return rv; | ||
258 | } | ||
259 | |||
260 | return i2c_smbus_read_byte_data(client, reg); | ||
261 | } | ||
262 | EXPORT_SYMBOL_GPL(pmbus_read_byte_data); | ||
263 | |||
264 | /* | ||
265 | * _pmbus_read_byte_data() is similar to pmbus_read_byte_data(), but checks if | ||
266 | * a device specific mapping function exists and calls it if necessary. | ||
267 | */ | ||
268 | static int _pmbus_read_byte_data(struct i2c_client *client, int page, int reg) | ||
269 | { | ||
270 | struct pmbus_data *data = i2c_get_clientdata(client); | ||
271 | const struct pmbus_driver_info *info = data->info; | ||
272 | int status; | ||
273 | |||
274 | if (info->read_byte_data) { | ||
275 | status = info->read_byte_data(client, page, reg); | ||
276 | if (status != -ENODATA) | ||
277 | return status; | ||
278 | } | ||
279 | return pmbus_read_byte_data(client, page, reg); | ||
280 | } | ||
281 | |||
282 | static void pmbus_clear_fault_page(struct i2c_client *client, int page) | ||
283 | { | ||
284 | pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS); | ||
285 | } | ||
286 | |||
287 | void pmbus_clear_faults(struct i2c_client *client) | ||
288 | { | ||
289 | struct pmbus_data *data = i2c_get_clientdata(client); | ||
290 | int i; | ||
291 | |||
292 | for (i = 0; i < data->info->pages; i++) | ||
293 | pmbus_clear_fault_page(client, i); | ||
294 | } | ||
295 | EXPORT_SYMBOL_GPL(pmbus_clear_faults); | ||
296 | |||
297 | static int pmbus_check_status_cml(struct i2c_client *client) | ||
298 | { | ||
299 | int status, status2; | ||
300 | |||
301 | status = pmbus_read_byte_data(client, -1, PMBUS_STATUS_BYTE); | ||
302 | if (status < 0 || (status & PB_STATUS_CML)) { | ||
303 | status2 = pmbus_read_byte_data(client, -1, PMBUS_STATUS_CML); | ||
304 | if (status2 < 0 || (status2 & PB_CML_FAULT_INVALID_COMMAND)) | ||
305 | return -EINVAL; | ||
306 | } | ||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg) | ||
311 | { | ||
312 | int rv; | ||
313 | struct pmbus_data *data = i2c_get_clientdata(client); | ||
314 | |||
315 | rv = _pmbus_read_byte_data(client, page, reg); | ||
316 | if (rv >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK)) | ||
317 | rv = pmbus_check_status_cml(client); | ||
318 | pmbus_clear_fault_page(client, -1); | ||
319 | return rv >= 0; | ||
320 | } | ||
321 | EXPORT_SYMBOL_GPL(pmbus_check_byte_register); | ||
322 | |||
323 | bool pmbus_check_word_register(struct i2c_client *client, int page, int reg) | ||
324 | { | ||
325 | int rv; | ||
326 | struct pmbus_data *data = i2c_get_clientdata(client); | ||
327 | |||
328 | rv = _pmbus_read_word_data(client, page, reg); | ||
329 | if (rv >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK)) | ||
330 | rv = pmbus_check_status_cml(client); | ||
331 | pmbus_clear_fault_page(client, -1); | ||
332 | return rv >= 0; | ||
333 | } | ||
334 | EXPORT_SYMBOL_GPL(pmbus_check_word_register); | ||
335 | |||
336 | const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client *client) | ||
337 | { | ||
338 | struct pmbus_data *data = i2c_get_clientdata(client); | ||
339 | |||
340 | return data->info; | ||
341 | } | ||
342 | EXPORT_SYMBOL_GPL(pmbus_get_driver_info); | ||
343 | |||
344 | static struct pmbus_data *pmbus_update_device(struct device *dev) | ||
345 | { | ||
346 | struct i2c_client *client = to_i2c_client(dev); | ||
347 | struct pmbus_data *data = i2c_get_clientdata(client); | ||
348 | const struct pmbus_driver_info *info = data->info; | ||
349 | |||
350 | mutex_lock(&data->update_lock); | ||
351 | if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { | ||
352 | int i; | ||
353 | |||
354 | for (i = 0; i < info->pages; i++) | ||
355 | data->status[PB_STATUS_BASE + i] | ||
356 | = pmbus_read_byte_data(client, i, | ||
357 | PMBUS_STATUS_BYTE); | ||
358 | for (i = 0; i < info->pages; i++) { | ||
359 | if (!(info->func[i] & PMBUS_HAVE_STATUS_VOUT)) | ||
360 | continue; | ||
361 | data->status[PB_STATUS_VOUT_BASE + i] | ||
362 | = _pmbus_read_byte_data(client, i, PMBUS_STATUS_VOUT); | ||
363 | } | ||
364 | for (i = 0; i < info->pages; i++) { | ||
365 | if (!(info->func[i] & PMBUS_HAVE_STATUS_IOUT)) | ||
366 | continue; | ||
367 | data->status[PB_STATUS_IOUT_BASE + i] | ||
368 | = _pmbus_read_byte_data(client, i, PMBUS_STATUS_IOUT); | ||
369 | } | ||
370 | for (i = 0; i < info->pages; i++) { | ||
371 | if (!(info->func[i] & PMBUS_HAVE_STATUS_TEMP)) | ||
372 | continue; | ||
373 | data->status[PB_STATUS_TEMP_BASE + i] | ||
374 | = _pmbus_read_byte_data(client, i, | ||
375 | PMBUS_STATUS_TEMPERATURE); | ||
376 | } | ||
377 | for (i = 0; i < info->pages; i++) { | ||
378 | if (!(info->func[i] & PMBUS_HAVE_STATUS_FAN12)) | ||
379 | continue; | ||
380 | data->status[PB_STATUS_FAN_BASE + i] | ||
381 | = _pmbus_read_byte_data(client, i, | ||
382 | PMBUS_STATUS_FAN_12); | ||
383 | } | ||
384 | |||
385 | for (i = 0; i < info->pages; i++) { | ||
386 | if (!(info->func[i] & PMBUS_HAVE_STATUS_FAN34)) | ||
387 | continue; | ||
388 | data->status[PB_STATUS_FAN34_BASE + i] | ||
389 | = _pmbus_read_byte_data(client, i, | ||
390 | PMBUS_STATUS_FAN_34); | ||
391 | } | ||
392 | |||
393 | if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) | ||
394 | data->status[PB_STATUS_INPUT_BASE] | ||
395 | = _pmbus_read_byte_data(client, 0, | ||
396 | PMBUS_STATUS_INPUT); | ||
397 | |||
398 | for (i = 0; i < data->num_sensors; i++) { | ||
399 | struct pmbus_sensor *sensor = &data->sensors[i]; | ||
400 | |||
401 | if (!data->valid || sensor->update) | ||
402 | sensor->data | ||
403 | = _pmbus_read_word_data(client, | ||
404 | sensor->page, | ||
405 | sensor->reg); | ||
406 | } | ||
407 | pmbus_clear_faults(client); | ||
408 | data->last_updated = jiffies; | ||
409 | data->valid = 1; | ||
410 | } | ||
411 | mutex_unlock(&data->update_lock); | ||
412 | return data; | ||
413 | } | ||
414 | |||
415 | /* | ||
416 | * Convert linear sensor values to milli- or micro-units | ||
417 | * depending on sensor type. | ||
418 | */ | ||
419 | static long pmbus_reg2data_linear(struct pmbus_data *data, | ||
420 | struct pmbus_sensor *sensor) | ||
421 | { | ||
422 | s16 exponent; | ||
423 | s32 mantissa; | ||
424 | long val; | ||
425 | |||
426 | if (sensor->class == PSC_VOLTAGE_OUT) { /* LINEAR16 */ | ||
427 | exponent = data->exponent; | ||
428 | mantissa = (u16) sensor->data; | ||
429 | } else { /* LINEAR11 */ | ||
430 | exponent = (sensor->data >> 11) & 0x001f; | ||
431 | mantissa = sensor->data & 0x07ff; | ||
432 | |||
433 | if (exponent > 0x0f) | ||
434 | exponent |= 0xffe0; /* sign extend exponent */ | ||
435 | if (mantissa > 0x03ff) | ||
436 | mantissa |= 0xfffff800; /* sign extend mantissa */ | ||
437 | } | ||
438 | |||
439 | val = mantissa; | ||
440 | |||
441 | /* scale result to milli-units for all sensors except fans */ | ||
442 | if (sensor->class != PSC_FAN) | ||
443 | val = val * 1000L; | ||
444 | |||
445 | /* scale result to micro-units for power sensors */ | ||
446 | if (sensor->class == PSC_POWER) | ||
447 | val = val * 1000L; | ||
448 | |||
449 | if (exponent >= 0) | ||
450 | val <<= exponent; | ||
451 | else | ||
452 | val >>= -exponent; | ||
453 | |||
454 | return val; | ||
455 | } | ||
456 | |||
457 | /* | ||
458 | * Convert direct sensor values to milli- or micro-units | ||
459 | * depending on sensor type. | ||
460 | */ | ||
461 | static long pmbus_reg2data_direct(struct pmbus_data *data, | ||
462 | struct pmbus_sensor *sensor) | ||
463 | { | ||
464 | long val = (s16) sensor->data; | ||
465 | long m, b, R; | ||
466 | |||
467 | m = data->info->m[sensor->class]; | ||
468 | b = data->info->b[sensor->class]; | ||
469 | R = data->info->R[sensor->class]; | ||
470 | |||
471 | if (m == 0) | ||
472 | return 0; | ||
473 | |||
474 | /* X = 1/m * (Y * 10^-R - b) */ | ||
475 | R = -R; | ||
476 | /* scale result to milli-units for everything but fans */ | ||
477 | if (sensor->class != PSC_FAN) { | ||
478 | R += 3; | ||
479 | b *= 1000; | ||
480 | } | ||
481 | |||
482 | /* scale result to micro-units for power sensors */ | ||
483 | if (sensor->class == PSC_POWER) { | ||
484 | R += 3; | ||
485 | b *= 1000; | ||
486 | } | ||
487 | |||
488 | while (R > 0) { | ||
489 | val *= 10; | ||
490 | R--; | ||
491 | } | ||
492 | while (R < 0) { | ||
493 | val = DIV_ROUND_CLOSEST(val, 10); | ||
494 | R++; | ||
495 | } | ||
496 | |||
497 | return (val - b) / m; | ||
498 | } | ||
499 | |||
500 | /* | ||
501 | * Convert VID sensor values to milli- or micro-units | ||
502 | * depending on sensor type. | ||
503 | * We currently only support VR11. | ||
504 | */ | ||
505 | static long pmbus_reg2data_vid(struct pmbus_data *data, | ||
506 | struct pmbus_sensor *sensor) | ||
507 | { | ||
508 | long val = sensor->data; | ||
509 | |||
510 | if (val < 0x02 || val > 0xb2) | ||
511 | return 0; | ||
512 | return DIV_ROUND_CLOSEST(160000 - (val - 2) * 625, 100); | ||
513 | } | ||
514 | |||
515 | static long pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor) | ||
516 | { | ||
517 | long val; | ||
518 | |||
519 | switch (data->info->format[sensor->class]) { | ||
520 | case direct: | ||
521 | val = pmbus_reg2data_direct(data, sensor); | ||
522 | break; | ||
523 | case vid: | ||
524 | val = pmbus_reg2data_vid(data, sensor); | ||
525 | break; | ||
526 | case linear: | ||
527 | default: | ||
528 | val = pmbus_reg2data_linear(data, sensor); | ||
529 | break; | ||
530 | } | ||
531 | return val; | ||
532 | } | ||
533 | |||
534 | #define MAX_MANTISSA (1023 * 1000) | ||
535 | #define MIN_MANTISSA (511 * 1000) | ||
536 | |||
537 | static u16 pmbus_data2reg_linear(struct pmbus_data *data, | ||
538 | enum pmbus_sensor_classes class, long val) | ||
539 | { | ||
540 | s16 exponent = 0, mantissa; | ||
541 | bool negative = false; | ||
542 | |||
543 | /* simple case */ | ||
544 | if (val == 0) | ||
545 | return 0; | ||
546 | |||
547 | if (class == PSC_VOLTAGE_OUT) { | ||
548 | /* LINEAR16 does not support negative voltages */ | ||
549 | if (val < 0) | ||
550 | return 0; | ||
551 | |||
552 | /* | ||
553 | * For a static exponents, we don't have a choice | ||
554 | * but to adjust the value to it. | ||
555 | */ | ||
556 | if (data->exponent < 0) | ||
557 | val <<= -data->exponent; | ||
558 | else | ||
559 | val >>= data->exponent; | ||
560 | val = DIV_ROUND_CLOSEST(val, 1000); | ||
561 | return val & 0xffff; | ||
562 | } | ||
563 | |||
564 | if (val < 0) { | ||
565 | negative = true; | ||
566 | val = -val; | ||
567 | } | ||
568 | |||
569 | /* Power is in uW. Convert to mW before converting. */ | ||
570 | if (class == PSC_POWER) | ||
571 | val = DIV_ROUND_CLOSEST(val, 1000L); | ||
572 | |||
573 | /* | ||
574 | * For simplicity, convert fan data to milli-units | ||
575 | * before calculating the exponent. | ||
576 | */ | ||
577 | if (class == PSC_FAN) | ||
578 | val = val * 1000; | ||
579 | |||
580 | /* Reduce large mantissa until it fits into 10 bit */ | ||
581 | while (val >= MAX_MANTISSA && exponent < 15) { | ||
582 | exponent++; | ||
583 | val >>= 1; | ||
584 | } | ||
585 | /* Increase small mantissa to improve precision */ | ||
586 | while (val < MIN_MANTISSA && exponent > -15) { | ||
587 | exponent--; | ||
588 | val <<= 1; | ||
589 | } | ||
590 | |||
591 | /* Convert mantissa from milli-units to units */ | ||
592 | mantissa = DIV_ROUND_CLOSEST(val, 1000); | ||
593 | |||
594 | /* Ensure that resulting number is within range */ | ||
595 | if (mantissa > 0x3ff) | ||
596 | mantissa = 0x3ff; | ||
597 | |||
598 | /* restore sign */ | ||
599 | if (negative) | ||
600 | mantissa = -mantissa; | ||
601 | |||
602 | /* Convert to 5 bit exponent, 11 bit mantissa */ | ||
603 | return (mantissa & 0x7ff) | ((exponent << 11) & 0xf800); | ||
604 | } | ||
605 | |||
606 | static u16 pmbus_data2reg_direct(struct pmbus_data *data, | ||
607 | enum pmbus_sensor_classes class, long val) | ||
608 | { | ||
609 | long m, b, R; | ||
610 | |||
611 | m = data->info->m[class]; | ||
612 | b = data->info->b[class]; | ||
613 | R = data->info->R[class]; | ||
614 | |||
615 | /* Power is in uW. Adjust R and b. */ | ||
616 | if (class == PSC_POWER) { | ||
617 | R -= 3; | ||
618 | b *= 1000; | ||
619 | } | ||
620 | |||
621 | /* Calculate Y = (m * X + b) * 10^R */ | ||
622 | if (class != PSC_FAN) { | ||
623 | R -= 3; /* Adjust R and b for data in milli-units */ | ||
624 | b *= 1000; | ||
625 | } | ||
626 | val = val * m + b; | ||
627 | |||
628 | while (R > 0) { | ||
629 | val *= 10; | ||
630 | R--; | ||
631 | } | ||
632 | while (R < 0) { | ||
633 | val = DIV_ROUND_CLOSEST(val, 10); | ||
634 | R++; | ||
635 | } | ||
636 | |||
637 | return val; | ||
638 | } | ||
639 | |||
640 | static u16 pmbus_data2reg_vid(struct pmbus_data *data, | ||
641 | enum pmbus_sensor_classes class, long val) | ||
642 | { | ||
643 | val = SENSORS_LIMIT(val, 500, 1600); | ||
644 | |||
645 | return 2 + DIV_ROUND_CLOSEST((1600 - val) * 100, 625); | ||
646 | } | ||
647 | |||
648 | static u16 pmbus_data2reg(struct pmbus_data *data, | ||
649 | enum pmbus_sensor_classes class, long val) | ||
650 | { | ||
651 | u16 regval; | ||
652 | |||
653 | switch (data->info->format[class]) { | ||
654 | case direct: | ||
655 | regval = pmbus_data2reg_direct(data, class, val); | ||
656 | break; | ||
657 | case vid: | ||
658 | regval = pmbus_data2reg_vid(data, class, val); | ||
659 | break; | ||
660 | case linear: | ||
661 | default: | ||
662 | regval = pmbus_data2reg_linear(data, class, val); | ||
663 | break; | ||
664 | } | ||
665 | return regval; | ||
666 | } | ||
667 | |||
668 | /* | ||
669 | * Return boolean calculated from converted data. | ||
670 | * <index> defines a status register index and mask, and optionally | ||
671 | * two sensor indexes. | ||
672 | * The upper half-word references the two sensors, | ||
673 | * two sensor indices. | ||
674 | * The upper half-word references the two optional sensors, | ||
675 | * the lower half word references status register and mask. | ||
676 | * The function returns true if (status[reg] & mask) is true and, | ||
677 | * if specified, if v1 >= v2. | ||
678 | * To determine if an object exceeds upper limits, specify <v, limit>. | ||
679 | * To determine if an object exceeds lower limits, specify <limit, v>. | ||
680 | * | ||
681 | * For booleans created with pmbus_add_boolean_reg(), only the lower 16 bits of | ||
682 | * index are set. s1 and s2 (the sensor index values) are zero in this case. | ||
683 | * The function returns true if (status[reg] & mask) is true. | ||
684 | * | ||
685 | * If the boolean was created with pmbus_add_boolean_cmp(), a comparison against | ||
686 | * a specified limit has to be performed to determine the boolean result. | ||
687 | * In this case, the function returns true if v1 >= v2 (where v1 and v2 are | ||
688 | * sensor values referenced by sensor indices s1 and s2). | ||
689 | * | ||
690 | * To determine if an object exceeds upper limits, specify <s1,s2> = <v,limit>. | ||
691 | * To determine if an object exceeds lower limits, specify <s1,s2> = <limit,v>. | ||
692 | * | ||
693 | * If a negative value is stored in any of the referenced registers, this value | ||
694 | * reflects an error code which will be returned. | ||
695 | */ | ||
696 | static int pmbus_get_boolean(struct pmbus_data *data, int index, int *val) | ||
697 | { | ||
698 | u8 s1 = (index >> 24) & 0xff; | ||
699 | u8 s2 = (index >> 16) & 0xff; | ||
700 | u8 reg = (index >> 8) & 0xff; | ||
701 | u8 mask = index & 0xff; | ||
702 | int status; | ||
703 | u8 regval; | ||
704 | |||
705 | status = data->status[reg]; | ||
706 | if (status < 0) | ||
707 | return status; | ||
708 | |||
709 | regval = status & mask; | ||
710 | if (!s1 && !s2) | ||
711 | *val = !!regval; | ||
712 | else { | ||
713 | long v1, v2; | ||
714 | struct pmbus_sensor *sensor1, *sensor2; | ||
715 | |||
716 | sensor1 = &data->sensors[s1]; | ||
717 | if (sensor1->data < 0) | ||
718 | return sensor1->data; | ||
719 | sensor2 = &data->sensors[s2]; | ||
720 | if (sensor2->data < 0) | ||
721 | return sensor2->data; | ||
722 | |||
723 | v1 = pmbus_reg2data(data, sensor1); | ||
724 | v2 = pmbus_reg2data(data, sensor2); | ||
725 | *val = !!(regval && v1 >= v2); | ||
726 | } | ||
727 | return 0; | ||
728 | } | ||
729 | |||
730 | static ssize_t pmbus_show_boolean(struct device *dev, | ||
731 | struct device_attribute *da, char *buf) | ||
732 | { | ||
733 | struct sensor_device_attribute *attr = to_sensor_dev_attr(da); | ||
734 | struct pmbus_data *data = pmbus_update_device(dev); | ||
735 | int val; | ||
736 | int err; | ||
737 | |||
738 | err = pmbus_get_boolean(data, attr->index, &val); | ||
739 | if (err) | ||
740 | return err; | ||
741 | return snprintf(buf, PAGE_SIZE, "%d\n", val); | ||
742 | } | ||
743 | |||
744 | static ssize_t pmbus_show_sensor(struct device *dev, | ||
745 | struct device_attribute *da, char *buf) | ||
746 | { | ||
747 | struct sensor_device_attribute *attr = to_sensor_dev_attr(da); | ||
748 | struct pmbus_data *data = pmbus_update_device(dev); | ||
749 | struct pmbus_sensor *sensor; | ||
750 | |||
751 | sensor = &data->sensors[attr->index]; | ||
752 | if (sensor->data < 0) | ||
753 | return sensor->data; | ||
754 | |||
755 | return snprintf(buf, PAGE_SIZE, "%ld\n", pmbus_reg2data(data, sensor)); | ||
756 | } | ||
757 | |||
758 | static ssize_t pmbus_set_sensor(struct device *dev, | ||
759 | struct device_attribute *devattr, | ||
760 | const char *buf, size_t count) | ||
761 | { | ||
762 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
763 | struct i2c_client *client = to_i2c_client(dev); | ||
764 | struct pmbus_data *data = i2c_get_clientdata(client); | ||
765 | struct pmbus_sensor *sensor = &data->sensors[attr->index]; | ||
766 | ssize_t rv = count; | ||
767 | long val = 0; | ||
768 | int ret; | ||
769 | u16 regval; | ||
770 | |||
771 | if (strict_strtol(buf, 10, &val) < 0) | ||
772 | return -EINVAL; | ||
773 | |||
774 | mutex_lock(&data->update_lock); | ||
775 | regval = pmbus_data2reg(data, sensor->class, val); | ||
776 | ret = _pmbus_write_word_data(client, sensor->page, sensor->reg, regval); | ||
777 | if (ret < 0) | ||
778 | rv = ret; | ||
779 | else | ||
780 | data->sensors[attr->index].data = regval; | ||
781 | mutex_unlock(&data->update_lock); | ||
782 | return rv; | ||
783 | } | ||
784 | |||
785 | static ssize_t pmbus_show_label(struct device *dev, | ||
786 | struct device_attribute *da, char *buf) | ||
787 | { | ||
788 | struct i2c_client *client = to_i2c_client(dev); | ||
789 | struct pmbus_data *data = i2c_get_clientdata(client); | ||
790 | struct sensor_device_attribute *attr = to_sensor_dev_attr(da); | ||
791 | |||
792 | return snprintf(buf, PAGE_SIZE, "%s\n", | ||
793 | data->labels[attr->index].label); | ||
794 | } | ||
795 | |||
796 | #define PMBUS_ADD_ATTR(data, _name, _idx, _mode, _type, _show, _set) \ | ||
797 | do { \ | ||
798 | struct sensor_device_attribute *a \ | ||
799 | = &data->_type##s[data->num_##_type##s].attribute; \ | ||
800 | BUG_ON(data->num_attributes >= data->max_attributes); \ | ||
801 | sysfs_attr_init(&a->dev_attr.attr); \ | ||
802 | a->dev_attr.attr.name = _name; \ | ||
803 | a->dev_attr.attr.mode = _mode; \ | ||
804 | a->dev_attr.show = _show; \ | ||
805 | a->dev_attr.store = _set; \ | ||
806 | a->index = _idx; \ | ||
807 | data->attributes[data->num_attributes] = &a->dev_attr.attr; \ | ||
808 | data->num_attributes++; \ | ||
809 | } while (0) | ||
810 | |||
811 | #define PMBUS_ADD_GET_ATTR(data, _name, _type, _idx) \ | ||
812 | PMBUS_ADD_ATTR(data, _name, _idx, S_IRUGO, _type, \ | ||
813 | pmbus_show_##_type, NULL) | ||
814 | |||
815 | #define PMBUS_ADD_SET_ATTR(data, _name, _type, _idx) \ | ||
816 | PMBUS_ADD_ATTR(data, _name, _idx, S_IWUSR | S_IRUGO, _type, \ | ||
817 | pmbus_show_##_type, pmbus_set_##_type) | ||
818 | |||
819 | static void pmbus_add_boolean(struct pmbus_data *data, | ||
820 | const char *name, const char *type, int seq, | ||
821 | int idx) | ||
822 | { | ||
823 | struct pmbus_boolean *boolean; | ||
824 | |||
825 | BUG_ON(data->num_booleans >= data->max_booleans); | ||
826 | |||
827 | boolean = &data->booleans[data->num_booleans]; | ||
828 | |||
829 | snprintf(boolean->name, sizeof(boolean->name), "%s%d_%s", | ||
830 | name, seq, type); | ||
831 | PMBUS_ADD_GET_ATTR(data, boolean->name, boolean, idx); | ||
832 | data->num_booleans++; | ||
833 | } | ||
834 | |||
835 | static void pmbus_add_boolean_reg(struct pmbus_data *data, | ||
836 | const char *name, const char *type, | ||
837 | int seq, int reg, int bit) | ||
838 | { | ||
839 | pmbus_add_boolean(data, name, type, seq, (reg << 8) | bit); | ||
840 | } | ||
841 | |||
842 | static void pmbus_add_boolean_cmp(struct pmbus_data *data, | ||
843 | const char *name, const char *type, | ||
844 | int seq, int i1, int i2, int reg, int mask) | ||
845 | { | ||
846 | pmbus_add_boolean(data, name, type, seq, | ||
847 | (i1 << 24) | (i2 << 16) | (reg << 8) | mask); | ||
848 | } | ||
849 | |||
850 | static void pmbus_add_sensor(struct pmbus_data *data, | ||
851 | const char *name, const char *type, int seq, | ||
852 | int page, int reg, enum pmbus_sensor_classes class, | ||
853 | bool update, bool readonly) | ||
854 | { | ||
855 | struct pmbus_sensor *sensor; | ||
856 | |||
857 | BUG_ON(data->num_sensors >= data->max_sensors); | ||
858 | |||
859 | sensor = &data->sensors[data->num_sensors]; | ||
860 | snprintf(sensor->name, sizeof(sensor->name), "%s%d_%s", | ||
861 | name, seq, type); | ||
862 | sensor->page = page; | ||
863 | sensor->reg = reg; | ||
864 | sensor->class = class; | ||
865 | sensor->update = update; | ||
866 | if (readonly) | ||
867 | PMBUS_ADD_GET_ATTR(data, sensor->name, sensor, | ||
868 | data->num_sensors); | ||
869 | else | ||
870 | PMBUS_ADD_SET_ATTR(data, sensor->name, sensor, | ||
871 | data->num_sensors); | ||
872 | data->num_sensors++; | ||
873 | } | ||
874 | |||
875 | static void pmbus_add_label(struct pmbus_data *data, | ||
876 | const char *name, int seq, | ||
877 | const char *lstring, int index) | ||
878 | { | ||
879 | struct pmbus_label *label; | ||
880 | |||
881 | BUG_ON(data->num_labels >= data->max_labels); | ||
882 | |||
883 | label = &data->labels[data->num_labels]; | ||
884 | snprintf(label->name, sizeof(label->name), "%s%d_label", name, seq); | ||
885 | if (!index) | ||
886 | strncpy(label->label, lstring, sizeof(label->label) - 1); | ||
887 | else | ||
888 | snprintf(label->label, sizeof(label->label), "%s%d", lstring, | ||
889 | index); | ||
890 | |||
891 | PMBUS_ADD_GET_ATTR(data, label->name, label, data->num_labels); | ||
892 | data->num_labels++; | ||
893 | } | ||
894 | |||
895 | /* | ||
896 | * Determine maximum number of sensors, booleans, and labels. | ||
897 | * To keep things simple, only make a rough high estimate. | ||
898 | */ | ||
899 | static void pmbus_find_max_attr(struct i2c_client *client, | ||
900 | struct pmbus_data *data) | ||
901 | { | ||
902 | const struct pmbus_driver_info *info = data->info; | ||
903 | int page, max_sensors, max_booleans, max_labels; | ||
904 | |||
905 | max_sensors = PMBUS_MAX_INPUT_SENSORS; | ||
906 | max_booleans = PMBUS_MAX_INPUT_BOOLEANS; | ||
907 | max_labels = PMBUS_MAX_INPUT_LABELS; | ||
908 | |||
909 | for (page = 0; page < info->pages; page++) { | ||
910 | if (info->func[page] & PMBUS_HAVE_VOUT) { | ||
911 | max_sensors += PMBUS_VOUT_SENSORS_PER_PAGE; | ||
912 | max_booleans += PMBUS_VOUT_BOOLEANS_PER_PAGE; | ||
913 | max_labels++; | ||
914 | } | ||
915 | if (info->func[page] & PMBUS_HAVE_IOUT) { | ||
916 | max_sensors += PMBUS_IOUT_SENSORS_PER_PAGE; | ||
917 | max_booleans += PMBUS_IOUT_BOOLEANS_PER_PAGE; | ||
918 | max_labels++; | ||
919 | } | ||
920 | if (info->func[page] & PMBUS_HAVE_POUT) { | ||
921 | max_sensors += PMBUS_POUT_SENSORS_PER_PAGE; | ||
922 | max_booleans += PMBUS_POUT_BOOLEANS_PER_PAGE; | ||
923 | max_labels++; | ||
924 | } | ||
925 | if (info->func[page] & PMBUS_HAVE_FAN12) { | ||
926 | max_sensors += 2 * PMBUS_MAX_SENSORS_PER_FAN; | ||
927 | max_booleans += 2 * PMBUS_MAX_BOOLEANS_PER_FAN; | ||
928 | } | ||
929 | if (info->func[page] & PMBUS_HAVE_FAN34) { | ||
930 | max_sensors += 2 * PMBUS_MAX_SENSORS_PER_FAN; | ||
931 | max_booleans += 2 * PMBUS_MAX_BOOLEANS_PER_FAN; | ||
932 | } | ||
933 | if (info->func[page] & PMBUS_HAVE_TEMP) { | ||
934 | max_sensors += PMBUS_MAX_SENSORS_PER_TEMP; | ||
935 | max_booleans += PMBUS_MAX_BOOLEANS_PER_TEMP; | ||
936 | } | ||
937 | if (info->func[page] & PMBUS_HAVE_TEMP2) { | ||
938 | max_sensors += PMBUS_MAX_SENSORS_PER_TEMP; | ||
939 | max_booleans += PMBUS_MAX_BOOLEANS_PER_TEMP; | ||
940 | } | ||
941 | if (info->func[page] & PMBUS_HAVE_TEMP3) { | ||
942 | max_sensors += PMBUS_MAX_SENSORS_PER_TEMP; | ||
943 | max_booleans += PMBUS_MAX_BOOLEANS_PER_TEMP; | ||
944 | } | ||
945 | } | ||
946 | data->max_sensors = max_sensors; | ||
947 | data->max_booleans = max_booleans; | ||
948 | data->max_labels = max_labels; | ||
949 | data->max_attributes = max_sensors + max_booleans + max_labels; | ||
950 | } | ||
951 | |||
952 | /* | ||
953 | * Search for attributes. Allocate sensors, booleans, and labels as needed. | ||
954 | */ | ||
955 | |||
956 | /* | ||
957 | * The pmbus_limit_attr structure describes a single limit attribute | ||
958 | * and its associated alarm attribute. | ||
959 | */ | ||
960 | struct pmbus_limit_attr { | ||
961 | u16 reg; /* Limit register */ | ||
962 | bool update; /* True if register needs updates */ | ||
963 | const char *attr; /* Attribute name */ | ||
964 | const char *alarm; /* Alarm attribute name */ | ||
965 | u32 sbit; /* Alarm attribute status bit */ | ||
966 | }; | ||
967 | |||
968 | /* | ||
969 | * The pmbus_sensor_attr structure describes one sensor attribute. This | ||
970 | * description includes a reference to the associated limit attributes. | ||
971 | */ | ||
972 | struct pmbus_sensor_attr { | ||
973 | u8 reg; /* sensor register */ | ||
974 | enum pmbus_sensor_classes class;/* sensor class */ | ||
975 | const char *label; /* sensor label */ | ||
976 | bool paged; /* true if paged sensor */ | ||
977 | bool update; /* true if update needed */ | ||
978 | bool compare; /* true if compare function needed */ | ||
979 | u32 func; /* sensor mask */ | ||
980 | u32 sfunc; /* sensor status mask */ | ||
981 | int sbase; /* status base register */ | ||
982 | u32 gbit; /* generic status bit */ | ||
983 | const struct pmbus_limit_attr *limit;/* limit registers */ | ||
984 | int nlimit; /* # of limit registers */ | ||
985 | }; | ||
986 | |||
987 | /* | ||
988 | * Add a set of limit attributes and, if supported, the associated | ||
989 | * alarm attributes. | ||
990 | */ | ||
991 | static bool pmbus_add_limit_attrs(struct i2c_client *client, | ||
992 | struct pmbus_data *data, | ||
993 | const struct pmbus_driver_info *info, | ||
994 | const char *name, int index, int page, | ||
995 | int cbase, | ||
996 | const struct pmbus_sensor_attr *attr) | ||
997 | { | ||
998 | const struct pmbus_limit_attr *l = attr->limit; | ||
999 | int nlimit = attr->nlimit; | ||
1000 | bool have_alarm = false; | ||
1001 | int i, cindex; | ||
1002 | |||
1003 | for (i = 0; i < nlimit; i++) { | ||
1004 | if (pmbus_check_word_register(client, page, l->reg)) { | ||
1005 | cindex = data->num_sensors; | ||
1006 | pmbus_add_sensor(data, name, l->attr, index, page, | ||
1007 | l->reg, attr->class, | ||
1008 | attr->update || l->update, | ||
1009 | false); | ||
1010 | if (l->sbit && (info->func[page] & attr->sfunc)) { | ||
1011 | if (attr->compare) { | ||
1012 | pmbus_add_boolean_cmp(data, name, | ||
1013 | l->alarm, index, | ||
1014 | cbase, cindex, | ||
1015 | attr->sbase + page, l->sbit); | ||
1016 | } else { | ||
1017 | pmbus_add_boolean_reg(data, name, | ||
1018 | l->alarm, index, | ||
1019 | attr->sbase + page, l->sbit); | ||
1020 | } | ||
1021 | have_alarm = true; | ||
1022 | } | ||
1023 | } | ||
1024 | l++; | ||
1025 | } | ||
1026 | return have_alarm; | ||
1027 | } | ||
1028 | |||
1029 | static void pmbus_add_sensor_attrs_one(struct i2c_client *client, | ||
1030 | struct pmbus_data *data, | ||
1031 | const struct pmbus_driver_info *info, | ||
1032 | const char *name, | ||
1033 | int index, int page, | ||
1034 | const struct pmbus_sensor_attr *attr) | ||
1035 | { | ||
1036 | bool have_alarm; | ||
1037 | int cbase = data->num_sensors; | ||
1038 | |||
1039 | if (attr->label) | ||
1040 | pmbus_add_label(data, name, index, attr->label, | ||
1041 | attr->paged ? page + 1 : 0); | ||
1042 | pmbus_add_sensor(data, name, "input", index, page, attr->reg, | ||
1043 | attr->class, true, true); | ||
1044 | if (attr->sfunc) { | ||
1045 | have_alarm = pmbus_add_limit_attrs(client, data, info, name, | ||
1046 | index, page, cbase, attr); | ||
1047 | /* | ||
1048 | * Add generic alarm attribute only if there are no individual | ||
1049 | * alarm attributes, if there is a global alarm bit, and if | ||
1050 | * the generic status register for this page is accessible. | ||
1051 | */ | ||
1052 | if (!have_alarm && attr->gbit && | ||
1053 | pmbus_check_byte_register(client, page, PMBUS_STATUS_BYTE)) | ||
1054 | pmbus_add_boolean_reg(data, name, "alarm", index, | ||
1055 | PB_STATUS_BASE + page, | ||
1056 | attr->gbit); | ||
1057 | } | ||
1058 | } | ||
1059 | |||
1060 | static void pmbus_add_sensor_attrs(struct i2c_client *client, | ||
1061 | struct pmbus_data *data, | ||
1062 | const char *name, | ||
1063 | const struct pmbus_sensor_attr *attrs, | ||
1064 | int nattrs) | ||
1065 | { | ||
1066 | const struct pmbus_driver_info *info = data->info; | ||
1067 | int index, i; | ||
1068 | |||
1069 | index = 1; | ||
1070 | for (i = 0; i < nattrs; i++) { | ||
1071 | int page, pages; | ||
1072 | |||
1073 | pages = attrs->paged ? info->pages : 1; | ||
1074 | for (page = 0; page < pages; page++) { | ||
1075 | if (!(info->func[page] & attrs->func)) | ||
1076 | continue; | ||
1077 | pmbus_add_sensor_attrs_one(client, data, info, name, | ||
1078 | index, page, attrs); | ||
1079 | index++; | ||
1080 | } | ||
1081 | attrs++; | ||
1082 | } | ||
1083 | } | ||
1084 | |||
1085 | static const struct pmbus_limit_attr vin_limit_attrs[] = { | ||
1086 | { | ||
1087 | .reg = PMBUS_VIN_UV_WARN_LIMIT, | ||
1088 | .attr = "min", | ||
1089 | .alarm = "min_alarm", | ||
1090 | .sbit = PB_VOLTAGE_UV_WARNING, | ||
1091 | }, { | ||
1092 | .reg = PMBUS_VIN_UV_FAULT_LIMIT, | ||
1093 | .attr = "lcrit", | ||
1094 | .alarm = "lcrit_alarm", | ||
1095 | .sbit = PB_VOLTAGE_UV_FAULT, | ||
1096 | }, { | ||
1097 | .reg = PMBUS_VIN_OV_WARN_LIMIT, | ||
1098 | .attr = "max", | ||
1099 | .alarm = "max_alarm", | ||
1100 | .sbit = PB_VOLTAGE_OV_WARNING, | ||
1101 | }, { | ||
1102 | .reg = PMBUS_VIN_OV_FAULT_LIMIT, | ||
1103 | .attr = "crit", | ||
1104 | .alarm = "crit_alarm", | ||
1105 | .sbit = PB_VOLTAGE_OV_FAULT, | ||
1106 | }, { | ||
1107 | .reg = PMBUS_VIRT_READ_VIN_AVG, | ||
1108 | .update = true, | ||
1109 | .attr = "average", | ||
1110 | }, { | ||
1111 | .reg = PMBUS_VIRT_READ_VIN_MIN, | ||
1112 | .update = true, | ||
1113 | .attr = "lowest", | ||
1114 | }, { | ||
1115 | .reg = PMBUS_VIRT_READ_VIN_MAX, | ||
1116 | .update = true, | ||
1117 | .attr = "highest", | ||
1118 | }, { | ||
1119 | .reg = PMBUS_VIRT_RESET_VIN_HISTORY, | ||
1120 | .attr = "reset_history", | ||
1121 | }, | ||
1122 | }; | ||
1123 | |||
1124 | static const struct pmbus_limit_attr vout_limit_attrs[] = { | ||
1125 | { | ||
1126 | .reg = PMBUS_VOUT_UV_WARN_LIMIT, | ||
1127 | .attr = "min", | ||
1128 | .alarm = "min_alarm", | ||
1129 | .sbit = PB_VOLTAGE_UV_WARNING, | ||
1130 | }, { | ||
1131 | .reg = PMBUS_VOUT_UV_FAULT_LIMIT, | ||
1132 | .attr = "lcrit", | ||
1133 | .alarm = "lcrit_alarm", | ||
1134 | .sbit = PB_VOLTAGE_UV_FAULT, | ||
1135 | }, { | ||
1136 | .reg = PMBUS_VOUT_OV_WARN_LIMIT, | ||
1137 | .attr = "max", | ||
1138 | .alarm = "max_alarm", | ||
1139 | .sbit = PB_VOLTAGE_OV_WARNING, | ||
1140 | }, { | ||
1141 | .reg = PMBUS_VOUT_OV_FAULT_LIMIT, | ||
1142 | .attr = "crit", | ||
1143 | .alarm = "crit_alarm", | ||
1144 | .sbit = PB_VOLTAGE_OV_FAULT, | ||
1145 | }, { | ||
1146 | .reg = PMBUS_VIRT_READ_VOUT_AVG, | ||
1147 | .update = true, | ||
1148 | .attr = "average", | ||
1149 | }, { | ||
1150 | .reg = PMBUS_VIRT_READ_VOUT_MIN, | ||
1151 | .update = true, | ||
1152 | .attr = "lowest", | ||
1153 | }, { | ||
1154 | .reg = PMBUS_VIRT_READ_VOUT_MAX, | ||
1155 | .update = true, | ||
1156 | .attr = "highest", | ||
1157 | }, { | ||
1158 | .reg = PMBUS_VIRT_RESET_VOUT_HISTORY, | ||
1159 | .attr = "reset_history", | ||
1160 | } | ||
1161 | }; | ||
1162 | |||
1163 | static const struct pmbus_sensor_attr voltage_attributes[] = { | ||
1164 | { | ||
1165 | .reg = PMBUS_READ_VIN, | ||
1166 | .class = PSC_VOLTAGE_IN, | ||
1167 | .label = "vin", | ||
1168 | .func = PMBUS_HAVE_VIN, | ||
1169 | .sfunc = PMBUS_HAVE_STATUS_INPUT, | ||
1170 | .sbase = PB_STATUS_INPUT_BASE, | ||
1171 | .gbit = PB_STATUS_VIN_UV, | ||
1172 | .limit = vin_limit_attrs, | ||
1173 | .nlimit = ARRAY_SIZE(vin_limit_attrs), | ||
1174 | }, { | ||
1175 | .reg = PMBUS_READ_VCAP, | ||
1176 | .class = PSC_VOLTAGE_IN, | ||
1177 | .label = "vcap", | ||
1178 | .func = PMBUS_HAVE_VCAP, | ||
1179 | }, { | ||
1180 | .reg = PMBUS_READ_VOUT, | ||
1181 | .class = PSC_VOLTAGE_OUT, | ||
1182 | .label = "vout", | ||
1183 | .paged = true, | ||
1184 | .func = PMBUS_HAVE_VOUT, | ||
1185 | .sfunc = PMBUS_HAVE_STATUS_VOUT, | ||
1186 | .sbase = PB_STATUS_VOUT_BASE, | ||
1187 | .gbit = PB_STATUS_VOUT_OV, | ||
1188 | .limit = vout_limit_attrs, | ||
1189 | .nlimit = ARRAY_SIZE(vout_limit_attrs), | ||
1190 | } | ||
1191 | }; | ||
1192 | |||
1193 | /* Current attributes */ | ||
1194 | |||
1195 | static const struct pmbus_limit_attr iin_limit_attrs[] = { | ||
1196 | { | ||
1197 | .reg = PMBUS_IIN_OC_WARN_LIMIT, | ||
1198 | .attr = "max", | ||
1199 | .alarm = "max_alarm", | ||
1200 | .sbit = PB_IIN_OC_WARNING, | ||
1201 | }, { | ||
1202 | .reg = PMBUS_IIN_OC_FAULT_LIMIT, | ||
1203 | .attr = "crit", | ||
1204 | .alarm = "crit_alarm", | ||
1205 | .sbit = PB_IIN_OC_FAULT, | ||
1206 | }, { | ||
1207 | .reg = PMBUS_VIRT_READ_IIN_AVG, | ||
1208 | .update = true, | ||
1209 | .attr = "average", | ||
1210 | }, { | ||
1211 | .reg = PMBUS_VIRT_READ_IIN_MIN, | ||
1212 | .update = true, | ||
1213 | .attr = "lowest", | ||
1214 | }, { | ||
1215 | .reg = PMBUS_VIRT_READ_IIN_MAX, | ||
1216 | .update = true, | ||
1217 | .attr = "highest", | ||
1218 | }, { | ||
1219 | .reg = PMBUS_VIRT_RESET_IIN_HISTORY, | ||
1220 | .attr = "reset_history", | ||
1221 | } | ||
1222 | }; | ||
1223 | |||
1224 | static const struct pmbus_limit_attr iout_limit_attrs[] = { | ||
1225 | { | ||
1226 | .reg = PMBUS_IOUT_OC_WARN_LIMIT, | ||
1227 | .attr = "max", | ||
1228 | .alarm = "max_alarm", | ||
1229 | .sbit = PB_IOUT_OC_WARNING, | ||
1230 | }, { | ||
1231 | .reg = PMBUS_IOUT_UC_FAULT_LIMIT, | ||
1232 | .attr = "lcrit", | ||
1233 | .alarm = "lcrit_alarm", | ||
1234 | .sbit = PB_IOUT_UC_FAULT, | ||
1235 | }, { | ||
1236 | .reg = PMBUS_IOUT_OC_FAULT_LIMIT, | ||
1237 | .attr = "crit", | ||
1238 | .alarm = "crit_alarm", | ||
1239 | .sbit = PB_IOUT_OC_FAULT, | ||
1240 | }, { | ||
1241 | .reg = PMBUS_VIRT_READ_IOUT_AVG, | ||
1242 | .update = true, | ||
1243 | .attr = "average", | ||
1244 | }, { | ||
1245 | .reg = PMBUS_VIRT_READ_IOUT_MIN, | ||
1246 | .update = true, | ||
1247 | .attr = "lowest", | ||
1248 | }, { | ||
1249 | .reg = PMBUS_VIRT_READ_IOUT_MAX, | ||
1250 | .update = true, | ||
1251 | .attr = "highest", | ||
1252 | }, { | ||
1253 | .reg = PMBUS_VIRT_RESET_IOUT_HISTORY, | ||
1254 | .attr = "reset_history", | ||
1255 | } | ||
1256 | }; | ||
1257 | |||
1258 | static const struct pmbus_sensor_attr current_attributes[] = { | ||
1259 | { | ||
1260 | .reg = PMBUS_READ_IIN, | ||
1261 | .class = PSC_CURRENT_IN, | ||
1262 | .label = "iin", | ||
1263 | .func = PMBUS_HAVE_IIN, | ||
1264 | .sfunc = PMBUS_HAVE_STATUS_INPUT, | ||
1265 | .sbase = PB_STATUS_INPUT_BASE, | ||
1266 | .limit = iin_limit_attrs, | ||
1267 | .nlimit = ARRAY_SIZE(iin_limit_attrs), | ||
1268 | }, { | ||
1269 | .reg = PMBUS_READ_IOUT, | ||
1270 | .class = PSC_CURRENT_OUT, | ||
1271 | .label = "iout", | ||
1272 | .paged = true, | ||
1273 | .func = PMBUS_HAVE_IOUT, | ||
1274 | .sfunc = PMBUS_HAVE_STATUS_IOUT, | ||
1275 | .sbase = PB_STATUS_IOUT_BASE, | ||
1276 | .gbit = PB_STATUS_IOUT_OC, | ||
1277 | .limit = iout_limit_attrs, | ||
1278 | .nlimit = ARRAY_SIZE(iout_limit_attrs), | ||
1279 | } | ||
1280 | }; | ||
1281 | |||
1282 | /* Power attributes */ | ||
1283 | |||
1284 | static const struct pmbus_limit_attr pin_limit_attrs[] = { | ||
1285 | { | ||
1286 | .reg = PMBUS_PIN_OP_WARN_LIMIT, | ||
1287 | .attr = "max", | ||
1288 | .alarm = "alarm", | ||
1289 | .sbit = PB_PIN_OP_WARNING, | ||
1290 | }, { | ||
1291 | .reg = PMBUS_VIRT_READ_PIN_AVG, | ||
1292 | .update = true, | ||
1293 | .attr = "average", | ||
1294 | }, { | ||
1295 | .reg = PMBUS_VIRT_READ_PIN_MAX, | ||
1296 | .update = true, | ||
1297 | .attr = "input_highest", | ||
1298 | }, { | ||
1299 | .reg = PMBUS_VIRT_RESET_PIN_HISTORY, | ||
1300 | .attr = "reset_history", | ||
1301 | } | ||
1302 | }; | ||
1303 | |||
1304 | static const struct pmbus_limit_attr pout_limit_attrs[] = { | ||
1305 | { | ||
1306 | .reg = PMBUS_POUT_MAX, | ||
1307 | .attr = "cap", | ||
1308 | .alarm = "cap_alarm", | ||
1309 | .sbit = PB_POWER_LIMITING, | ||
1310 | }, { | ||
1311 | .reg = PMBUS_POUT_OP_WARN_LIMIT, | ||
1312 | .attr = "max", | ||
1313 | .alarm = "max_alarm", | ||
1314 | .sbit = PB_POUT_OP_WARNING, | ||
1315 | }, { | ||
1316 | .reg = PMBUS_POUT_OP_FAULT_LIMIT, | ||
1317 | .attr = "crit", | ||
1318 | .alarm = "crit_alarm", | ||
1319 | .sbit = PB_POUT_OP_FAULT, | ||
1320 | } | ||
1321 | }; | ||
1322 | |||
1323 | static const struct pmbus_sensor_attr power_attributes[] = { | ||
1324 | { | ||
1325 | .reg = PMBUS_READ_PIN, | ||
1326 | .class = PSC_POWER, | ||
1327 | .label = "pin", | ||
1328 | .func = PMBUS_HAVE_PIN, | ||
1329 | .sfunc = PMBUS_HAVE_STATUS_INPUT, | ||
1330 | .sbase = PB_STATUS_INPUT_BASE, | ||
1331 | .limit = pin_limit_attrs, | ||
1332 | .nlimit = ARRAY_SIZE(pin_limit_attrs), | ||
1333 | }, { | ||
1334 | .reg = PMBUS_READ_POUT, | ||
1335 | .class = PSC_POWER, | ||
1336 | .label = "pout", | ||
1337 | .paged = true, | ||
1338 | .func = PMBUS_HAVE_POUT, | ||
1339 | .sfunc = PMBUS_HAVE_STATUS_IOUT, | ||
1340 | .sbase = PB_STATUS_IOUT_BASE, | ||
1341 | .limit = pout_limit_attrs, | ||
1342 | .nlimit = ARRAY_SIZE(pout_limit_attrs), | ||
1343 | } | ||
1344 | }; | ||
1345 | |||
1346 | /* Temperature atributes */ | ||
1347 | |||
1348 | static const struct pmbus_limit_attr temp_limit_attrs[] = { | ||
1349 | { | ||
1350 | .reg = PMBUS_UT_WARN_LIMIT, | ||
1351 | .attr = "min", | ||
1352 | .alarm = "min_alarm", | ||
1353 | .sbit = PB_TEMP_UT_WARNING, | ||
1354 | }, { | ||
1355 | .reg = PMBUS_UT_FAULT_LIMIT, | ||
1356 | .attr = "lcrit", | ||
1357 | .alarm = "lcrit_alarm", | ||
1358 | .sbit = PB_TEMP_UT_FAULT, | ||
1359 | }, { | ||
1360 | .reg = PMBUS_OT_WARN_LIMIT, | ||
1361 | .attr = "max", | ||
1362 | .alarm = "max_alarm", | ||
1363 | .sbit = PB_TEMP_OT_WARNING, | ||
1364 | }, { | ||
1365 | .reg = PMBUS_OT_FAULT_LIMIT, | ||
1366 | .attr = "crit", | ||
1367 | .alarm = "crit_alarm", | ||
1368 | .sbit = PB_TEMP_OT_FAULT, | ||
1369 | }, { | ||
1370 | .reg = PMBUS_VIRT_READ_TEMP_MIN, | ||
1371 | .attr = "lowest", | ||
1372 | }, { | ||
1373 | .reg = PMBUS_VIRT_READ_TEMP_MAX, | ||
1374 | .attr = "highest", | ||
1375 | }, { | ||
1376 | .reg = PMBUS_VIRT_RESET_TEMP_HISTORY, | ||
1377 | .attr = "reset_history", | ||
1378 | } | ||
1379 | }; | ||
1380 | |||
1381 | static const struct pmbus_limit_attr temp_limit_attrs23[] = { | ||
1382 | { | ||
1383 | .reg = PMBUS_UT_WARN_LIMIT, | ||
1384 | .attr = "min", | ||
1385 | .alarm = "min_alarm", | ||
1386 | .sbit = PB_TEMP_UT_WARNING, | ||
1387 | }, { | ||
1388 | .reg = PMBUS_UT_FAULT_LIMIT, | ||
1389 | .attr = "lcrit", | ||
1390 | .alarm = "lcrit_alarm", | ||
1391 | .sbit = PB_TEMP_UT_FAULT, | ||
1392 | }, { | ||
1393 | .reg = PMBUS_OT_WARN_LIMIT, | ||
1394 | .attr = "max", | ||
1395 | .alarm = "max_alarm", | ||
1396 | .sbit = PB_TEMP_OT_WARNING, | ||
1397 | }, { | ||
1398 | .reg = PMBUS_OT_FAULT_LIMIT, | ||
1399 | .attr = "crit", | ||
1400 | .alarm = "crit_alarm", | ||
1401 | .sbit = PB_TEMP_OT_FAULT, | ||
1402 | } | ||
1403 | }; | ||
1404 | |||
1405 | static const struct pmbus_sensor_attr temp_attributes[] = { | ||
1406 | { | ||
1407 | .reg = PMBUS_READ_TEMPERATURE_1, | ||
1408 | .class = PSC_TEMPERATURE, | ||
1409 | .paged = true, | ||
1410 | .update = true, | ||
1411 | .compare = true, | ||
1412 | .func = PMBUS_HAVE_TEMP, | ||
1413 | .sfunc = PMBUS_HAVE_STATUS_TEMP, | ||
1414 | .sbase = PB_STATUS_TEMP_BASE, | ||
1415 | .gbit = PB_STATUS_TEMPERATURE, | ||
1416 | .limit = temp_limit_attrs, | ||
1417 | .nlimit = ARRAY_SIZE(temp_limit_attrs), | ||
1418 | }, { | ||
1419 | .reg = PMBUS_READ_TEMPERATURE_2, | ||
1420 | .class = PSC_TEMPERATURE, | ||
1421 | .paged = true, | ||
1422 | .update = true, | ||
1423 | .compare = true, | ||
1424 | .func = PMBUS_HAVE_TEMP2, | ||
1425 | .sfunc = PMBUS_HAVE_STATUS_TEMP, | ||
1426 | .sbase = PB_STATUS_TEMP_BASE, | ||
1427 | .gbit = PB_STATUS_TEMPERATURE, | ||
1428 | .limit = temp_limit_attrs23, | ||
1429 | .nlimit = ARRAY_SIZE(temp_limit_attrs23), | ||
1430 | }, { | ||
1431 | .reg = PMBUS_READ_TEMPERATURE_3, | ||
1432 | .class = PSC_TEMPERATURE, | ||
1433 | .paged = true, | ||
1434 | .update = true, | ||
1435 | .compare = true, | ||
1436 | .func = PMBUS_HAVE_TEMP3, | ||
1437 | .sfunc = PMBUS_HAVE_STATUS_TEMP, | ||
1438 | .sbase = PB_STATUS_TEMP_BASE, | ||
1439 | .gbit = PB_STATUS_TEMPERATURE, | ||
1440 | .limit = temp_limit_attrs23, | ||
1441 | .nlimit = ARRAY_SIZE(temp_limit_attrs23), | ||
1442 | } | ||
1443 | }; | ||
1444 | |||
1445 | static const int pmbus_fan_registers[] = { | ||
1446 | PMBUS_READ_FAN_SPEED_1, | ||
1447 | PMBUS_READ_FAN_SPEED_2, | ||
1448 | PMBUS_READ_FAN_SPEED_3, | ||
1449 | PMBUS_READ_FAN_SPEED_4 | ||
1450 | }; | ||
1451 | |||
1452 | static const int pmbus_fan_config_registers[] = { | ||
1453 | PMBUS_FAN_CONFIG_12, | ||
1454 | PMBUS_FAN_CONFIG_12, | ||
1455 | PMBUS_FAN_CONFIG_34, | ||
1456 | PMBUS_FAN_CONFIG_34 | ||
1457 | }; | ||
1458 | |||
1459 | static const int pmbus_fan_status_registers[] = { | ||
1460 | PMBUS_STATUS_FAN_12, | ||
1461 | PMBUS_STATUS_FAN_12, | ||
1462 | PMBUS_STATUS_FAN_34, | ||
1463 | PMBUS_STATUS_FAN_34 | ||
1464 | }; | ||
1465 | |||
1466 | static const u32 pmbus_fan_flags[] = { | ||
1467 | PMBUS_HAVE_FAN12, | ||
1468 | PMBUS_HAVE_FAN12, | ||
1469 | PMBUS_HAVE_FAN34, | ||
1470 | PMBUS_HAVE_FAN34 | ||
1471 | }; | ||
1472 | |||
1473 | static const u32 pmbus_fan_status_flags[] = { | ||
1474 | PMBUS_HAVE_STATUS_FAN12, | ||
1475 | PMBUS_HAVE_STATUS_FAN12, | ||
1476 | PMBUS_HAVE_STATUS_FAN34, | ||
1477 | PMBUS_HAVE_STATUS_FAN34 | ||
1478 | }; | ||
1479 | |||
1480 | /* Fans */ | ||
1481 | static void pmbus_add_fan_attributes(struct i2c_client *client, | ||
1482 | struct pmbus_data *data) | ||
1483 | { | ||
1484 | const struct pmbus_driver_info *info = data->info; | ||
1485 | int index = 1; | ||
1486 | int page; | ||
1487 | |||
1488 | for (page = 0; page < info->pages; page++) { | ||
1489 | int f; | ||
1490 | |||
1491 | for (f = 0; f < ARRAY_SIZE(pmbus_fan_registers); f++) { | ||
1492 | int regval; | ||
1493 | |||
1494 | if (!(info->func[page] & pmbus_fan_flags[f])) | ||
1495 | break; | ||
1496 | |||
1497 | if (!pmbus_check_word_register(client, page, | ||
1498 | pmbus_fan_registers[f])) | ||
1499 | break; | ||
1500 | |||
1501 | /* | ||
1502 | * Skip fan if not installed. | ||
1503 | * Each fan configuration register covers multiple fans, | ||
1504 | * so we have to do some magic. | ||
1505 | */ | ||
1506 | regval = _pmbus_read_byte_data(client, page, | ||
1507 | pmbus_fan_config_registers[f]); | ||
1508 | if (regval < 0 || | ||
1509 | (!(regval & (PB_FAN_1_INSTALLED >> ((f & 1) * 4))))) | ||
1510 | continue; | ||
1511 | |||
1512 | pmbus_add_sensor(data, "fan", "input", index, page, | ||
1513 | pmbus_fan_registers[f], PSC_FAN, true, | ||
1514 | true); | ||
1515 | |||
1516 | /* | ||
1517 | * Each fan status register covers multiple fans, | ||
1518 | * so we have to do some magic. | ||
1519 | */ | ||
1520 | if ((info->func[page] & pmbus_fan_status_flags[f]) && | ||
1521 | pmbus_check_byte_register(client, | ||
1522 | page, pmbus_fan_status_registers[f])) { | ||
1523 | int base; | ||
1524 | |||
1525 | if (f > 1) /* fan 3, 4 */ | ||
1526 | base = PB_STATUS_FAN34_BASE + page; | ||
1527 | else | ||
1528 | base = PB_STATUS_FAN_BASE + page; | ||
1529 | pmbus_add_boolean_reg(data, "fan", "alarm", | ||
1530 | index, base, | ||
1531 | PB_FAN_FAN1_WARNING >> (f & 1)); | ||
1532 | pmbus_add_boolean_reg(data, "fan", "fault", | ||
1533 | index, base, | ||
1534 | PB_FAN_FAN1_FAULT >> (f & 1)); | ||
1535 | } | ||
1536 | index++; | ||
1537 | } | ||
1538 | } | ||
1539 | } | ||
1540 | |||
1541 | static void pmbus_find_attributes(struct i2c_client *client, | ||
1542 | struct pmbus_data *data) | ||
1543 | { | ||
1544 | /* Voltage sensors */ | ||
1545 | pmbus_add_sensor_attrs(client, data, "in", voltage_attributes, | ||
1546 | ARRAY_SIZE(voltage_attributes)); | ||
1547 | |||
1548 | /* Current sensors */ | ||
1549 | pmbus_add_sensor_attrs(client, data, "curr", current_attributes, | ||
1550 | ARRAY_SIZE(current_attributes)); | ||
1551 | |||
1552 | /* Power sensors */ | ||
1553 | pmbus_add_sensor_attrs(client, data, "power", power_attributes, | ||
1554 | ARRAY_SIZE(power_attributes)); | ||
1555 | |||
1556 | /* Temperature sensors */ | ||
1557 | pmbus_add_sensor_attrs(client, data, "temp", temp_attributes, | ||
1558 | ARRAY_SIZE(temp_attributes)); | ||
1559 | |||
1560 | /* Fans */ | ||
1561 | pmbus_add_fan_attributes(client, data); | ||
1562 | } | ||
1563 | |||
1564 | /* | ||
1565 | * Identify chip parameters. | ||
1566 | * This function is called for all chips. | ||
1567 | */ | ||
1568 | static int pmbus_identify_common(struct i2c_client *client, | ||
1569 | struct pmbus_data *data) | ||
1570 | { | ||
1571 | int vout_mode = -1, exponent; | ||
1572 | |||
1573 | if (pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE)) | ||
1574 | vout_mode = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE); | ||
1575 | if (vout_mode >= 0 && vout_mode != 0xff) { | ||
1576 | /* | ||
1577 | * Not all chips support the VOUT_MODE command, | ||
1578 | * so a failure to read it is not an error. | ||
1579 | */ | ||
1580 | switch (vout_mode >> 5) { | ||
1581 | case 0: /* linear mode */ | ||
1582 | if (data->info->format[PSC_VOLTAGE_OUT] != linear) | ||
1583 | return -ENODEV; | ||
1584 | |||
1585 | exponent = vout_mode & 0x1f; | ||
1586 | /* and sign-extend it */ | ||
1587 | if (exponent & 0x10) | ||
1588 | exponent |= ~0x1f; | ||
1589 | data->exponent = exponent; | ||
1590 | break; | ||
1591 | case 1: /* VID mode */ | ||
1592 | if (data->info->format[PSC_VOLTAGE_OUT] != vid) | ||
1593 | return -ENODEV; | ||
1594 | break; | ||
1595 | case 2: /* direct mode */ | ||
1596 | if (data->info->format[PSC_VOLTAGE_OUT] != direct) | ||
1597 | return -ENODEV; | ||
1598 | break; | ||
1599 | default: | ||
1600 | return -ENODEV; | ||
1601 | } | ||
1602 | } | ||
1603 | |||
1604 | /* Determine maximum number of sensors, booleans, and labels */ | ||
1605 | pmbus_find_max_attr(client, data); | ||
1606 | pmbus_clear_fault_page(client, 0); | ||
1607 | return 0; | ||
1608 | } | ||
1609 | |||
1610 | int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, | ||
1611 | struct pmbus_driver_info *info) | ||
1612 | { | ||
1613 | const struct pmbus_platform_data *pdata = client->dev.platform_data; | ||
1614 | struct pmbus_data *data; | ||
1615 | int ret; | ||
1616 | |||
1617 | if (!info) { | ||
1618 | dev_err(&client->dev, "Missing chip information"); | ||
1619 | return -ENODEV; | ||
1620 | } | ||
1621 | |||
1622 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE | ||
1623 | | I2C_FUNC_SMBUS_BYTE_DATA | ||
1624 | | I2C_FUNC_SMBUS_WORD_DATA)) | ||
1625 | return -ENODEV; | ||
1626 | |||
1627 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
1628 | if (!data) { | ||
1629 | dev_err(&client->dev, "No memory to allocate driver data\n"); | ||
1630 | return -ENOMEM; | ||
1631 | } | ||
1632 | |||
1633 | i2c_set_clientdata(client, data); | ||
1634 | mutex_init(&data->update_lock); | ||
1635 | |||
1636 | /* Bail out if PMBus status register does not exist. */ | ||
1637 | if (i2c_smbus_read_byte_data(client, PMBUS_STATUS_BYTE) < 0) { | ||
1638 | dev_err(&client->dev, "PMBus status register not found\n"); | ||
1639 | ret = -ENODEV; | ||
1640 | goto out_data; | ||
1641 | } | ||
1642 | |||
1643 | if (pdata) | ||
1644 | data->flags = pdata->flags; | ||
1645 | data->info = info; | ||
1646 | |||
1647 | pmbus_clear_faults(client); | ||
1648 | |||
1649 | if (info->identify) { | ||
1650 | ret = (*info->identify)(client, info); | ||
1651 | if (ret < 0) { | ||
1652 | dev_err(&client->dev, "Chip identification failed\n"); | ||
1653 | goto out_data; | ||
1654 | } | ||
1655 | } | ||
1656 | |||
1657 | if (info->pages <= 0 || info->pages > PMBUS_PAGES) { | ||
1658 | dev_err(&client->dev, "Bad number of PMBus pages: %d\n", | ||
1659 | info->pages); | ||
1660 | ret = -EINVAL; | ||
1661 | goto out_data; | ||
1662 | } | ||
1663 | |||
1664 | ret = pmbus_identify_common(client, data); | ||
1665 | if (ret < 0) { | ||
1666 | dev_err(&client->dev, "Failed to identify chip capabilities\n"); | ||
1667 | goto out_data; | ||
1668 | } | ||
1669 | |||
1670 | ret = -ENOMEM; | ||
1671 | data->sensors = kzalloc(sizeof(struct pmbus_sensor) * data->max_sensors, | ||
1672 | GFP_KERNEL); | ||
1673 | if (!data->sensors) { | ||
1674 | dev_err(&client->dev, "No memory to allocate sensor data\n"); | ||
1675 | goto out_data; | ||
1676 | } | ||
1677 | |||
1678 | data->booleans = kzalloc(sizeof(struct pmbus_boolean) | ||
1679 | * data->max_booleans, GFP_KERNEL); | ||
1680 | if (!data->booleans) { | ||
1681 | dev_err(&client->dev, "No memory to allocate boolean data\n"); | ||
1682 | goto out_sensors; | ||
1683 | } | ||
1684 | |||
1685 | data->labels = kzalloc(sizeof(struct pmbus_label) * data->max_labels, | ||
1686 | GFP_KERNEL); | ||
1687 | if (!data->labels) { | ||
1688 | dev_err(&client->dev, "No memory to allocate label data\n"); | ||
1689 | goto out_booleans; | ||
1690 | } | ||
1691 | |||
1692 | data->attributes = kzalloc(sizeof(struct attribute *) | ||
1693 | * data->max_attributes, GFP_KERNEL); | ||
1694 | if (!data->attributes) { | ||
1695 | dev_err(&client->dev, "No memory to allocate attribute data\n"); | ||
1696 | goto out_labels; | ||
1697 | } | ||
1698 | |||
1699 | pmbus_find_attributes(client, data); | ||
1700 | |||
1701 | /* | ||
1702 | * If there are no attributes, something is wrong. | ||
1703 | * Bail out instead of trying to register nothing. | ||
1704 | */ | ||
1705 | if (!data->num_attributes) { | ||
1706 | dev_err(&client->dev, "No attributes found\n"); | ||
1707 | ret = -ENODEV; | ||
1708 | goto out_attributes; | ||
1709 | } | ||
1710 | |||
1711 | /* Register sysfs hooks */ | ||
1712 | data->group.attrs = data->attributes; | ||
1713 | ret = sysfs_create_group(&client->dev.kobj, &data->group); | ||
1714 | if (ret) { | ||
1715 | dev_err(&client->dev, "Failed to create sysfs entries\n"); | ||
1716 | goto out_attributes; | ||
1717 | } | ||
1718 | data->hwmon_dev = hwmon_device_register(&client->dev); | ||
1719 | if (IS_ERR(data->hwmon_dev)) { | ||
1720 | ret = PTR_ERR(data->hwmon_dev); | ||
1721 | dev_err(&client->dev, "Failed to register hwmon device\n"); | ||
1722 | goto out_hwmon_device_register; | ||
1723 | } | ||
1724 | return 0; | ||
1725 | |||
1726 | out_hwmon_device_register: | ||
1727 | sysfs_remove_group(&client->dev.kobj, &data->group); | ||
1728 | out_attributes: | ||
1729 | kfree(data->attributes); | ||
1730 | out_labels: | ||
1731 | kfree(data->labels); | ||
1732 | out_booleans: | ||
1733 | kfree(data->booleans); | ||
1734 | out_sensors: | ||
1735 | kfree(data->sensors); | ||
1736 | out_data: | ||
1737 | kfree(data); | ||
1738 | return ret; | ||
1739 | } | ||
1740 | EXPORT_SYMBOL_GPL(pmbus_do_probe); | ||
1741 | |||
1742 | int pmbus_do_remove(struct i2c_client *client) | ||
1743 | { | ||
1744 | struct pmbus_data *data = i2c_get_clientdata(client); | ||
1745 | hwmon_device_unregister(data->hwmon_dev); | ||
1746 | sysfs_remove_group(&client->dev.kobj, &data->group); | ||
1747 | kfree(data->attributes); | ||
1748 | kfree(data->labels); | ||
1749 | kfree(data->booleans); | ||
1750 | kfree(data->sensors); | ||
1751 | kfree(data); | ||
1752 | return 0; | ||
1753 | } | ||
1754 | EXPORT_SYMBOL_GPL(pmbus_do_remove); | ||
1755 | |||
1756 | MODULE_AUTHOR("Guenter Roeck"); | ||
1757 | MODULE_DESCRIPTION("PMBus core driver"); | ||
1758 | MODULE_LICENSE("GPL"); | ||