.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Hardware monitoring driver for PMBus devices |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (c) 2010, 2011 Ericsson AB. |
---|
5 | 6 | * Copyright (c) 2012 Guenter Roeck |
---|
6 | | - * |
---|
7 | | - * This program is free software; you can redistribute it and/or modify |
---|
8 | | - * it under the terms of the GNU General Public License as published by |
---|
9 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
10 | | - * (at your option) any later version. |
---|
11 | | - * |
---|
12 | | - * This program is distributed in the hope that it will be useful, |
---|
13 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
14 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
15 | | - * GNU General Public License for more details. |
---|
16 | | - * |
---|
17 | | - * You should have received a copy of the GNU General Public License |
---|
18 | | - * along with this program; if not, write to the Free Software |
---|
19 | | - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
---|
20 | 7 | */ |
---|
21 | 8 | |
---|
22 | 9 | #include <linux/debugfs.h> |
---|
.. | .. |
---|
29 | 16 | #include <linux/i2c.h> |
---|
30 | 17 | #include <linux/hwmon.h> |
---|
31 | 18 | #include <linux/hwmon-sysfs.h> |
---|
32 | | -#include <linux/jiffies.h> |
---|
33 | 19 | #include <linux/pmbus.h> |
---|
34 | 20 | #include <linux/regulator/driver.h> |
---|
35 | 21 | #include <linux/regulator/machine.h> |
---|
.. | .. |
---|
40 | 26 | * with each call to krealloc |
---|
41 | 27 | */ |
---|
42 | 28 | #define PMBUS_ATTR_ALLOC_SIZE 32 |
---|
43 | | - |
---|
44 | | -/* |
---|
45 | | - * Index into status register array, per status register group |
---|
46 | | - */ |
---|
47 | | -#define PB_STATUS_BASE 0 |
---|
48 | | -#define PB_STATUS_VOUT_BASE (PB_STATUS_BASE + PMBUS_PAGES) |
---|
49 | | -#define PB_STATUS_IOUT_BASE (PB_STATUS_VOUT_BASE + PMBUS_PAGES) |
---|
50 | | -#define PB_STATUS_FAN_BASE (PB_STATUS_IOUT_BASE + PMBUS_PAGES) |
---|
51 | | -#define PB_STATUS_FAN34_BASE (PB_STATUS_FAN_BASE + PMBUS_PAGES) |
---|
52 | | -#define PB_STATUS_TEMP_BASE (PB_STATUS_FAN34_BASE + PMBUS_PAGES) |
---|
53 | | -#define PB_STATUS_INPUT_BASE (PB_STATUS_TEMP_BASE + PMBUS_PAGES) |
---|
54 | | -#define PB_STATUS_VMON_BASE (PB_STATUS_INPUT_BASE + 1) |
---|
55 | | - |
---|
56 | | -#define PB_NUM_STATUS_REG (PB_STATUS_VMON_BASE + 1) |
---|
57 | | - |
---|
58 | 29 | #define PMBUS_NAME_SIZE 24 |
---|
59 | 30 | |
---|
60 | 31 | struct pmbus_sensor { |
---|
.. | .. |
---|
62 | 33 | char name[PMBUS_NAME_SIZE]; /* sysfs sensor name */ |
---|
63 | 34 | struct device_attribute attribute; |
---|
64 | 35 | u8 page; /* page number */ |
---|
| 36 | + u8 phase; /* phase number, 0xff for all phases */ |
---|
65 | 37 | u16 reg; /* register */ |
---|
66 | 38 | enum pmbus_sensor_classes class; /* sensor class */ |
---|
67 | 39 | bool update; /* runtime sensor update needed */ |
---|
.. | .. |
---|
89 | 61 | #define to_pmbus_label(_attr) \ |
---|
90 | 62 | container_of(_attr, struct pmbus_label, attribute) |
---|
91 | 63 | |
---|
| 64 | +/* Macros for converting between sensor index and register/page/status mask */ |
---|
| 65 | + |
---|
| 66 | +#define PB_STATUS_MASK 0xffff |
---|
| 67 | +#define PB_REG_SHIFT 16 |
---|
| 68 | +#define PB_REG_MASK 0x3ff |
---|
| 69 | +#define PB_PAGE_SHIFT 26 |
---|
| 70 | +#define PB_PAGE_MASK 0x3f |
---|
| 71 | + |
---|
| 72 | +#define pb_reg_to_index(page, reg, mask) (((page) << PB_PAGE_SHIFT) | \ |
---|
| 73 | + ((reg) << PB_REG_SHIFT) | (mask)) |
---|
| 74 | + |
---|
| 75 | +#define pb_index_to_page(index) (((index) >> PB_PAGE_SHIFT) & PB_PAGE_MASK) |
---|
| 76 | +#define pb_index_to_reg(index) (((index) >> PB_REG_SHIFT) & PB_REG_MASK) |
---|
| 77 | +#define pb_index_to_mask(index) ((index) & PB_STATUS_MASK) |
---|
| 78 | + |
---|
92 | 79 | struct pmbus_data { |
---|
93 | 80 | struct device *dev; |
---|
94 | 81 | struct device *hwmon_dev; |
---|
.. | .. |
---|
103 | 90 | int max_attributes; |
---|
104 | 91 | int num_attributes; |
---|
105 | 92 | struct attribute_group group; |
---|
106 | | - const struct attribute_group *groups[2]; |
---|
| 93 | + const struct attribute_group **groups; |
---|
107 | 94 | struct dentry *debugfs; /* debugfs device directory */ |
---|
108 | 95 | |
---|
109 | 96 | struct pmbus_sensor *sensors; |
---|
110 | 97 | |
---|
111 | 98 | struct mutex update_lock; |
---|
112 | | - bool valid; |
---|
113 | | - unsigned long last_updated; /* in jiffies */ |
---|
114 | | - |
---|
115 | | - /* |
---|
116 | | - * A single status register covers multiple attributes, |
---|
117 | | - * so we keep them all together. |
---|
118 | | - */ |
---|
119 | | - u16 status[PB_NUM_STATUS_REG]; |
---|
120 | 99 | |
---|
121 | 100 | bool has_status_word; /* device uses STATUS_WORD register */ |
---|
122 | 101 | int (*read_status)(struct i2c_client *client, int page); |
---|
123 | 102 | |
---|
124 | | - u8 currpage; |
---|
| 103 | + s16 currpage; /* current page, -1 for unknown/unset */ |
---|
| 104 | + s16 currphase; /* current phase, 0xff for all, -1 for unknown/unset */ |
---|
125 | 105 | }; |
---|
126 | 106 | |
---|
127 | 107 | struct pmbus_debugfs_entry { |
---|
.. | .. |
---|
154 | 134 | void pmbus_clear_cache(struct i2c_client *client) |
---|
155 | 135 | { |
---|
156 | 136 | struct pmbus_data *data = i2c_get_clientdata(client); |
---|
| 137 | + struct pmbus_sensor *sensor; |
---|
157 | 138 | |
---|
158 | | - data->valid = false; |
---|
| 139 | + for (sensor = data->sensors; sensor; sensor = sensor->next) |
---|
| 140 | + sensor->data = -ENODATA; |
---|
159 | 141 | } |
---|
160 | 142 | EXPORT_SYMBOL_GPL(pmbus_clear_cache); |
---|
161 | 143 | |
---|
162 | | -int pmbus_set_page(struct i2c_client *client, int page) |
---|
| 144 | +int pmbus_set_page(struct i2c_client *client, int page, int phase) |
---|
163 | 145 | { |
---|
164 | 146 | struct pmbus_data *data = i2c_get_clientdata(client); |
---|
165 | 147 | int rv; |
---|
166 | 148 | |
---|
167 | | - if (page < 0 || page == data->currpage) |
---|
| 149 | + if (page < 0) |
---|
168 | 150 | return 0; |
---|
169 | 151 | |
---|
170 | | - if (!(data->info->func[page] & PMBUS_PAGE_VIRTUAL)) { |
---|
| 152 | + if (!(data->info->func[page] & PMBUS_PAGE_VIRTUAL) && |
---|
| 153 | + data->info->pages > 1 && page != data->currpage) { |
---|
171 | 154 | rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page); |
---|
172 | 155 | if (rv < 0) |
---|
173 | 156 | return rv; |
---|
.. | .. |
---|
179 | 162 | if (rv != page) |
---|
180 | 163 | return -EIO; |
---|
181 | 164 | } |
---|
182 | | - |
---|
183 | 165 | data->currpage = page; |
---|
| 166 | + |
---|
| 167 | + if (data->info->phases[page] && data->currphase != phase && |
---|
| 168 | + !(data->info->func[page] & PMBUS_PHASE_VIRTUAL)) { |
---|
| 169 | + rv = i2c_smbus_write_byte_data(client, PMBUS_PHASE, |
---|
| 170 | + phase); |
---|
| 171 | + if (rv) |
---|
| 172 | + return rv; |
---|
| 173 | + } |
---|
| 174 | + data->currphase = phase; |
---|
184 | 175 | |
---|
185 | 176 | return 0; |
---|
186 | 177 | } |
---|
.. | .. |
---|
190 | 181 | { |
---|
191 | 182 | int rv; |
---|
192 | 183 | |
---|
193 | | - rv = pmbus_set_page(client, page); |
---|
| 184 | + rv = pmbus_set_page(client, page, 0xff); |
---|
194 | 185 | if (rv < 0) |
---|
195 | 186 | return rv; |
---|
196 | 187 | |
---|
.. | .. |
---|
221 | 212 | { |
---|
222 | 213 | int rv; |
---|
223 | 214 | |
---|
224 | | - rv = pmbus_set_page(client, page); |
---|
| 215 | + rv = pmbus_set_page(client, page, 0xff); |
---|
225 | 216 | if (rv < 0) |
---|
226 | 217 | return rv; |
---|
227 | 218 | |
---|
.. | .. |
---|
299 | 290 | } |
---|
300 | 291 | EXPORT_SYMBOL_GPL(pmbus_update_fan); |
---|
301 | 292 | |
---|
302 | | -int pmbus_read_word_data(struct i2c_client *client, int page, u8 reg) |
---|
| 293 | +int pmbus_read_word_data(struct i2c_client *client, int page, int phase, u8 reg) |
---|
303 | 294 | { |
---|
304 | 295 | int rv; |
---|
305 | 296 | |
---|
306 | | - rv = pmbus_set_page(client, page); |
---|
| 297 | + rv = pmbus_set_page(client, page, phase); |
---|
307 | 298 | if (rv < 0) |
---|
308 | 299 | return rv; |
---|
309 | 300 | |
---|
.. | .. |
---|
333 | 324 | * _pmbus_read_word_data() is similar to pmbus_read_word_data(), but checks if |
---|
334 | 325 | * a device specific mapping function exists and calls it if necessary. |
---|
335 | 326 | */ |
---|
336 | | -static int _pmbus_read_word_data(struct i2c_client *client, int page, int reg) |
---|
| 327 | +static int _pmbus_read_word_data(struct i2c_client *client, int page, |
---|
| 328 | + int phase, int reg) |
---|
337 | 329 | { |
---|
338 | 330 | struct pmbus_data *data = i2c_get_clientdata(client); |
---|
339 | 331 | const struct pmbus_driver_info *info = data->info; |
---|
340 | 332 | int status; |
---|
341 | 333 | |
---|
342 | 334 | if (info->read_word_data) { |
---|
343 | | - status = info->read_word_data(client, page, reg); |
---|
| 335 | + status = info->read_word_data(client, page, phase, reg); |
---|
344 | 336 | if (status != -ENODATA) |
---|
345 | 337 | return status; |
---|
346 | 338 | } |
---|
.. | .. |
---|
348 | 340 | if (reg >= PMBUS_VIRT_BASE) |
---|
349 | 341 | return pmbus_read_virt_reg(client, page, reg); |
---|
350 | 342 | |
---|
351 | | - return pmbus_read_word_data(client, page, reg); |
---|
| 343 | + return pmbus_read_word_data(client, page, phase, reg); |
---|
| 344 | +} |
---|
| 345 | + |
---|
| 346 | +/* Same as above, but without phase parameter, for use in check functions */ |
---|
| 347 | +static int __pmbus_read_word_data(struct i2c_client *client, int page, int reg) |
---|
| 348 | +{ |
---|
| 349 | + return _pmbus_read_word_data(client, page, 0xff, reg); |
---|
352 | 350 | } |
---|
353 | 351 | |
---|
354 | 352 | int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg) |
---|
355 | 353 | { |
---|
356 | 354 | int rv; |
---|
357 | 355 | |
---|
358 | | - rv = pmbus_set_page(client, page); |
---|
| 356 | + rv = pmbus_set_page(client, page, 0xff); |
---|
359 | 357 | if (rv < 0) |
---|
360 | 358 | return rv; |
---|
361 | 359 | |
---|
.. | .. |
---|
367 | 365 | { |
---|
368 | 366 | int rv; |
---|
369 | 367 | |
---|
370 | | - rv = pmbus_set_page(client, page); |
---|
| 368 | + rv = pmbus_set_page(client, page, 0xff); |
---|
371 | 369 | if (rv < 0) |
---|
372 | 370 | return rv; |
---|
373 | 371 | |
---|
.. | .. |
---|
453 | 451 | |
---|
454 | 452 | have_rpm = !!(config & pmbus_fan_rpm_mask[id]); |
---|
455 | 453 | if (want_rpm == have_rpm) |
---|
456 | | - return pmbus_read_word_data(client, page, |
---|
| 454 | + return pmbus_read_word_data(client, page, 0xff, |
---|
457 | 455 | pmbus_fan_command_registers[id]); |
---|
458 | 456 | |
---|
459 | 457 | /* Can't sensibly map between RPM and PWM, just return zero */ |
---|
.. | .. |
---|
543 | 541 | |
---|
544 | 542 | bool pmbus_check_word_register(struct i2c_client *client, int page, int reg) |
---|
545 | 543 | { |
---|
546 | | - return pmbus_check_register(client, _pmbus_read_word_data, page, reg); |
---|
| 544 | + return pmbus_check_register(client, __pmbus_read_word_data, page, reg); |
---|
547 | 545 | } |
---|
548 | 546 | EXPORT_SYMBOL_GPL(pmbus_check_word_register); |
---|
549 | 547 | |
---|
.. | .. |
---|
555 | 553 | } |
---|
556 | 554 | EXPORT_SYMBOL_GPL(pmbus_get_driver_info); |
---|
557 | 555 | |
---|
558 | | -static struct _pmbus_status { |
---|
559 | | - u32 func; |
---|
560 | | - u16 base; |
---|
561 | | - u16 reg; |
---|
562 | | -} pmbus_status[] = { |
---|
563 | | - { PMBUS_HAVE_STATUS_VOUT, PB_STATUS_VOUT_BASE, PMBUS_STATUS_VOUT }, |
---|
564 | | - { PMBUS_HAVE_STATUS_IOUT, PB_STATUS_IOUT_BASE, PMBUS_STATUS_IOUT }, |
---|
565 | | - { PMBUS_HAVE_STATUS_TEMP, PB_STATUS_TEMP_BASE, |
---|
566 | | - PMBUS_STATUS_TEMPERATURE }, |
---|
567 | | - { PMBUS_HAVE_STATUS_FAN12, PB_STATUS_FAN_BASE, PMBUS_STATUS_FAN_12 }, |
---|
568 | | - { PMBUS_HAVE_STATUS_FAN34, PB_STATUS_FAN34_BASE, PMBUS_STATUS_FAN_34 }, |
---|
569 | | -}; |
---|
570 | | - |
---|
571 | | -static struct pmbus_data *pmbus_update_device(struct device *dev) |
---|
| 556 | +static int pmbus_get_status(struct i2c_client *client, int page, int reg) |
---|
572 | 557 | { |
---|
573 | | - struct i2c_client *client = to_i2c_client(dev->parent); |
---|
574 | 558 | struct pmbus_data *data = i2c_get_clientdata(client); |
---|
575 | | - const struct pmbus_driver_info *info = data->info; |
---|
576 | | - struct pmbus_sensor *sensor; |
---|
| 559 | + int status; |
---|
577 | 560 | |
---|
578 | | - mutex_lock(&data->update_lock); |
---|
579 | | - if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { |
---|
580 | | - int i, j; |
---|
581 | | - |
---|
582 | | - for (i = 0; i < info->pages; i++) { |
---|
583 | | - data->status[PB_STATUS_BASE + i] |
---|
584 | | - = data->read_status(client, i); |
---|
585 | | - for (j = 0; j < ARRAY_SIZE(pmbus_status); j++) { |
---|
586 | | - struct _pmbus_status *s = &pmbus_status[j]; |
---|
587 | | - |
---|
588 | | - if (!(info->func[i] & s->func)) |
---|
589 | | - continue; |
---|
590 | | - data->status[s->base + i] |
---|
591 | | - = _pmbus_read_byte_data(client, i, |
---|
592 | | - s->reg); |
---|
593 | | - } |
---|
594 | | - } |
---|
595 | | - |
---|
596 | | - if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) |
---|
597 | | - data->status[PB_STATUS_INPUT_BASE] |
---|
598 | | - = _pmbus_read_byte_data(client, 0, |
---|
599 | | - PMBUS_STATUS_INPUT); |
---|
600 | | - |
---|
601 | | - if (info->func[0] & PMBUS_HAVE_STATUS_VMON) |
---|
602 | | - data->status[PB_STATUS_VMON_BASE] |
---|
603 | | - = _pmbus_read_byte_data(client, 0, |
---|
604 | | - PMBUS_VIRT_STATUS_VMON); |
---|
605 | | - |
---|
606 | | - for (sensor = data->sensors; sensor; sensor = sensor->next) { |
---|
607 | | - if (!data->valid || sensor->update) |
---|
608 | | - sensor->data |
---|
609 | | - = _pmbus_read_word_data(client, |
---|
610 | | - sensor->page, |
---|
611 | | - sensor->reg); |
---|
612 | | - } |
---|
613 | | - pmbus_clear_faults(client); |
---|
614 | | - data->last_updated = jiffies; |
---|
615 | | - data->valid = 1; |
---|
| 561 | + switch (reg) { |
---|
| 562 | + case PMBUS_STATUS_WORD: |
---|
| 563 | + status = data->read_status(client, page); |
---|
| 564 | + break; |
---|
| 565 | + default: |
---|
| 566 | + status = _pmbus_read_byte_data(client, page, reg); |
---|
| 567 | + break; |
---|
616 | 568 | } |
---|
617 | | - mutex_unlock(&data->update_lock); |
---|
618 | | - return data; |
---|
| 569 | + if (status < 0) |
---|
| 570 | + pmbus_clear_faults(client); |
---|
| 571 | + return status; |
---|
| 572 | +} |
---|
| 573 | + |
---|
| 574 | +static void pmbus_update_sensor_data(struct i2c_client *client, struct pmbus_sensor *sensor) |
---|
| 575 | +{ |
---|
| 576 | + if (sensor->data < 0 || sensor->update) |
---|
| 577 | + sensor->data = _pmbus_read_word_data(client, sensor->page, |
---|
| 578 | + sensor->phase, sensor->reg); |
---|
619 | 579 | } |
---|
620 | 580 | |
---|
621 | 581 | /* |
---|
622 | 582 | * Convert linear sensor values to milli- or micro-units |
---|
623 | 583 | * depending on sensor type. |
---|
624 | 584 | */ |
---|
625 | | -static long pmbus_reg2data_linear(struct pmbus_data *data, |
---|
626 | | - struct pmbus_sensor *sensor) |
---|
| 585 | +static s64 pmbus_reg2data_linear(struct pmbus_data *data, |
---|
| 586 | + struct pmbus_sensor *sensor) |
---|
627 | 587 | { |
---|
628 | 588 | s16 exponent; |
---|
629 | 589 | s32 mantissa; |
---|
630 | | - long val; |
---|
| 590 | + s64 val; |
---|
631 | 591 | |
---|
632 | 592 | if (sensor->class == PSC_VOLTAGE_OUT) { /* LINEAR16 */ |
---|
633 | 593 | exponent = data->exponent[sensor->page]; |
---|
.. | .. |
---|
641 | 601 | |
---|
642 | 602 | /* scale result to milli-units for all sensors except fans */ |
---|
643 | 603 | if (sensor->class != PSC_FAN) |
---|
644 | | - val = val * 1000L; |
---|
| 604 | + val = val * 1000LL; |
---|
645 | 605 | |
---|
646 | 606 | /* scale result to micro-units for power sensors */ |
---|
647 | 607 | if (sensor->class == PSC_POWER) |
---|
648 | | - val = val * 1000L; |
---|
| 608 | + val = val * 1000LL; |
---|
649 | 609 | |
---|
650 | 610 | if (exponent >= 0) |
---|
651 | 611 | val <<= exponent; |
---|
.. | .. |
---|
659 | 619 | * Convert direct sensor values to milli- or micro-units |
---|
660 | 620 | * depending on sensor type. |
---|
661 | 621 | */ |
---|
662 | | -static long pmbus_reg2data_direct(struct pmbus_data *data, |
---|
663 | | - struct pmbus_sensor *sensor) |
---|
| 622 | +static s64 pmbus_reg2data_direct(struct pmbus_data *data, |
---|
| 623 | + struct pmbus_sensor *sensor) |
---|
664 | 624 | { |
---|
665 | 625 | s64 b, val = (s16)sensor->data; |
---|
666 | 626 | s32 m, R; |
---|
.. | .. |
---|
696 | 656 | } |
---|
697 | 657 | |
---|
698 | 658 | val = div_s64(val - b, m); |
---|
699 | | - return clamp_val(val, LONG_MIN, LONG_MAX); |
---|
| 659 | + return val; |
---|
700 | 660 | } |
---|
701 | 661 | |
---|
702 | 662 | /* |
---|
703 | 663 | * Convert VID sensor values to milli- or micro-units |
---|
704 | 664 | * depending on sensor type. |
---|
705 | 665 | */ |
---|
706 | | -static long pmbus_reg2data_vid(struct pmbus_data *data, |
---|
707 | | - struct pmbus_sensor *sensor) |
---|
| 666 | +static s64 pmbus_reg2data_vid(struct pmbus_data *data, |
---|
| 667 | + struct pmbus_sensor *sensor) |
---|
708 | 668 | { |
---|
709 | 669 | long val = sensor->data; |
---|
710 | 670 | long rv = 0; |
---|
711 | 671 | |
---|
712 | | - switch (data->info->vrm_version) { |
---|
| 672 | + switch (data->info->vrm_version[sensor->page]) { |
---|
713 | 673 | case vr11: |
---|
714 | 674 | if (val >= 0x02 && val <= 0xb2) |
---|
715 | 675 | rv = DIV_ROUND_CLOSEST(160000 - (val - 2) * 625, 100); |
---|
.. | .. |
---|
722 | 682 | if (val >= 0x01) |
---|
723 | 683 | rv = 500 + (val - 1) * 10; |
---|
724 | 684 | break; |
---|
| 685 | + case imvp9: |
---|
| 686 | + if (val >= 0x01) |
---|
| 687 | + rv = 200 + (val - 1) * 10; |
---|
| 688 | + break; |
---|
| 689 | + case amd625mv: |
---|
| 690 | + if (val >= 0x0 && val <= 0xd8) |
---|
| 691 | + rv = DIV_ROUND_CLOSEST(155000 - val * 625, 100); |
---|
| 692 | + break; |
---|
725 | 693 | } |
---|
726 | 694 | return rv; |
---|
727 | 695 | } |
---|
728 | 696 | |
---|
729 | | -static long pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor) |
---|
| 697 | +static s64 pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor) |
---|
730 | 698 | { |
---|
731 | | - long val; |
---|
| 699 | + s64 val; |
---|
732 | 700 | |
---|
733 | 701 | if (!sensor->convert) |
---|
734 | 702 | return sensor->data; |
---|
.. | .. |
---|
752 | 720 | #define MIN_MANTISSA (511 * 1000) |
---|
753 | 721 | |
---|
754 | 722 | static u16 pmbus_data2reg_linear(struct pmbus_data *data, |
---|
755 | | - struct pmbus_sensor *sensor, long val) |
---|
| 723 | + struct pmbus_sensor *sensor, s64 val) |
---|
756 | 724 | { |
---|
757 | 725 | s16 exponent = 0, mantissa; |
---|
758 | 726 | bool negative = false; |
---|
.. | .. |
---|
774 | 742 | val <<= -data->exponent[sensor->page]; |
---|
775 | 743 | else |
---|
776 | 744 | val >>= data->exponent[sensor->page]; |
---|
777 | | - val = DIV_ROUND_CLOSEST(val, 1000); |
---|
778 | | - return val & 0xffff; |
---|
| 745 | + val = DIV_ROUND_CLOSEST_ULL(val, 1000); |
---|
| 746 | + return clamp_val(val, 0, 0xffff); |
---|
779 | 747 | } |
---|
780 | 748 | |
---|
781 | 749 | if (val < 0) { |
---|
.. | .. |
---|
785 | 753 | |
---|
786 | 754 | /* Power is in uW. Convert to mW before converting. */ |
---|
787 | 755 | if (sensor->class == PSC_POWER) |
---|
788 | | - val = DIV_ROUND_CLOSEST(val, 1000L); |
---|
| 756 | + val = DIV_ROUND_CLOSEST_ULL(val, 1000); |
---|
789 | 757 | |
---|
790 | 758 | /* |
---|
791 | 759 | * For simplicity, convert fan data to milli-units |
---|
792 | 760 | * before calculating the exponent. |
---|
793 | 761 | */ |
---|
794 | 762 | if (sensor->class == PSC_FAN) |
---|
795 | | - val = val * 1000; |
---|
| 763 | + val = val * 1000LL; |
---|
796 | 764 | |
---|
797 | 765 | /* Reduce large mantissa until it fits into 10 bit */ |
---|
798 | 766 | while (val >= MAX_MANTISSA && exponent < 15) { |
---|
.. | .. |
---|
806 | 774 | } |
---|
807 | 775 | |
---|
808 | 776 | /* Convert mantissa from milli-units to units */ |
---|
809 | | - mantissa = DIV_ROUND_CLOSEST(val, 1000); |
---|
810 | | - |
---|
811 | | - /* Ensure that resulting number is within range */ |
---|
812 | | - if (mantissa > 0x3ff) |
---|
813 | | - mantissa = 0x3ff; |
---|
| 777 | + mantissa = clamp_val(DIV_ROUND_CLOSEST_ULL(val, 1000), 0, 0x3ff); |
---|
814 | 778 | |
---|
815 | 779 | /* restore sign */ |
---|
816 | 780 | if (negative) |
---|
.. | .. |
---|
821 | 785 | } |
---|
822 | 786 | |
---|
823 | 787 | static u16 pmbus_data2reg_direct(struct pmbus_data *data, |
---|
824 | | - struct pmbus_sensor *sensor, long val) |
---|
| 788 | + struct pmbus_sensor *sensor, s64 val) |
---|
825 | 789 | { |
---|
826 | | - s64 b, val64 = val; |
---|
| 790 | + s64 b; |
---|
827 | 791 | s32 m, R; |
---|
828 | 792 | |
---|
829 | 793 | m = data->info->m[sensor->class]; |
---|
.. | .. |
---|
841 | 805 | R -= 3; /* Adjust R and b for data in milli-units */ |
---|
842 | 806 | b *= 1000; |
---|
843 | 807 | } |
---|
844 | | - val64 = val64 * m + b; |
---|
| 808 | + val = val * m + b; |
---|
845 | 809 | |
---|
846 | 810 | while (R > 0) { |
---|
847 | | - val64 *= 10; |
---|
| 811 | + val *= 10; |
---|
848 | 812 | R--; |
---|
849 | 813 | } |
---|
850 | 814 | while (R < 0) { |
---|
851 | | - val64 = div_s64(val64 + 5LL, 10L); /* round closest */ |
---|
| 815 | + val = div_s64(val + 5LL, 10L); /* round closest */ |
---|
852 | 816 | R++; |
---|
853 | 817 | } |
---|
854 | 818 | |
---|
855 | | - return (u16)clamp_val(val64, S16_MIN, S16_MAX); |
---|
| 819 | + return (u16)clamp_val(val, S16_MIN, S16_MAX); |
---|
856 | 820 | } |
---|
857 | 821 | |
---|
858 | 822 | static u16 pmbus_data2reg_vid(struct pmbus_data *data, |
---|
859 | | - struct pmbus_sensor *sensor, long val) |
---|
| 823 | + struct pmbus_sensor *sensor, s64 val) |
---|
860 | 824 | { |
---|
861 | 825 | val = clamp_val(val, 500, 1600); |
---|
862 | 826 | |
---|
863 | | - return 2 + DIV_ROUND_CLOSEST((1600 - val) * 100, 625); |
---|
| 827 | + return 2 + DIV_ROUND_CLOSEST_ULL((1600LL - val) * 100LL, 625); |
---|
864 | 828 | } |
---|
865 | 829 | |
---|
866 | 830 | static u16 pmbus_data2reg(struct pmbus_data *data, |
---|
867 | | - struct pmbus_sensor *sensor, long val) |
---|
| 831 | + struct pmbus_sensor *sensor, s64 val) |
---|
868 | 832 | { |
---|
869 | 833 | u16 regval; |
---|
870 | 834 | |
---|
.. | .. |
---|
909 | 873 | * If a negative value is stored in any of the referenced registers, this value |
---|
910 | 874 | * reflects an error code which will be returned. |
---|
911 | 875 | */ |
---|
912 | | -static int pmbus_get_boolean(struct pmbus_data *data, struct pmbus_boolean *b, |
---|
| 876 | +static int pmbus_get_boolean(struct i2c_client *client, struct pmbus_boolean *b, |
---|
913 | 877 | int index) |
---|
914 | 878 | { |
---|
| 879 | + struct pmbus_data *data = i2c_get_clientdata(client); |
---|
915 | 880 | struct pmbus_sensor *s1 = b->s1; |
---|
916 | 881 | struct pmbus_sensor *s2 = b->s2; |
---|
917 | | - u16 reg = (index >> 16) & 0xffff; |
---|
918 | | - u16 mask = index & 0xffff; |
---|
| 882 | + u16 mask = pb_index_to_mask(index); |
---|
| 883 | + u8 page = pb_index_to_page(index); |
---|
| 884 | + u16 reg = pb_index_to_reg(index); |
---|
919 | 885 | int ret, status; |
---|
920 | 886 | u16 regval; |
---|
921 | 887 | |
---|
922 | | - status = data->status[reg]; |
---|
923 | | - if (status < 0) |
---|
924 | | - return status; |
---|
| 888 | + mutex_lock(&data->update_lock); |
---|
| 889 | + status = pmbus_get_status(client, page, reg); |
---|
| 890 | + if (status < 0) { |
---|
| 891 | + ret = status; |
---|
| 892 | + goto unlock; |
---|
| 893 | + } |
---|
| 894 | + |
---|
| 895 | + if (s1) |
---|
| 896 | + pmbus_update_sensor_data(client, s1); |
---|
| 897 | + if (s2) |
---|
| 898 | + pmbus_update_sensor_data(client, s2); |
---|
925 | 899 | |
---|
926 | 900 | regval = status & mask; |
---|
927 | | - if (!s1 && !s2) { |
---|
928 | | - ret = !!regval; |
---|
929 | | - } else if (!s1 || !s2) { |
---|
930 | | - WARN(1, "Bad boolean descriptor %p: s1=%p, s2=%p\n", b, s1, s2); |
---|
931 | | - return 0; |
---|
932 | | - } else { |
---|
933 | | - long v1, v2; |
---|
| 901 | + if (regval) { |
---|
| 902 | + ret = pmbus_write_byte_data(client, page, reg, regval); |
---|
| 903 | + if (ret) |
---|
| 904 | + goto unlock; |
---|
| 905 | + } |
---|
| 906 | + if (s1 && s2) { |
---|
| 907 | + s64 v1, v2; |
---|
934 | 908 | |
---|
935 | | - if (s1->data < 0) |
---|
936 | | - return s1->data; |
---|
937 | | - if (s2->data < 0) |
---|
938 | | - return s2->data; |
---|
| 909 | + if (s1->data < 0) { |
---|
| 910 | + ret = s1->data; |
---|
| 911 | + goto unlock; |
---|
| 912 | + } |
---|
| 913 | + if (s2->data < 0) { |
---|
| 914 | + ret = s2->data; |
---|
| 915 | + goto unlock; |
---|
| 916 | + } |
---|
939 | 917 | |
---|
940 | 918 | v1 = pmbus_reg2data(data, s1); |
---|
941 | 919 | v2 = pmbus_reg2data(data, s2); |
---|
942 | 920 | ret = !!(regval && v1 >= v2); |
---|
| 921 | + } else { |
---|
| 922 | + ret = !!regval; |
---|
943 | 923 | } |
---|
| 924 | +unlock: |
---|
| 925 | + mutex_unlock(&data->update_lock); |
---|
944 | 926 | return ret; |
---|
945 | 927 | } |
---|
946 | 928 | |
---|
.. | .. |
---|
949 | 931 | { |
---|
950 | 932 | struct sensor_device_attribute *attr = to_sensor_dev_attr(da); |
---|
951 | 933 | struct pmbus_boolean *boolean = to_pmbus_boolean(attr); |
---|
952 | | - struct pmbus_data *data = pmbus_update_device(dev); |
---|
| 934 | + struct i2c_client *client = to_i2c_client(dev->parent); |
---|
953 | 935 | int val; |
---|
954 | 936 | |
---|
955 | | - val = pmbus_get_boolean(data, boolean, attr->index); |
---|
| 937 | + val = pmbus_get_boolean(client, boolean, attr->index); |
---|
956 | 938 | if (val < 0) |
---|
957 | 939 | return val; |
---|
958 | 940 | return snprintf(buf, PAGE_SIZE, "%d\n", val); |
---|
.. | .. |
---|
961 | 943 | static ssize_t pmbus_show_sensor(struct device *dev, |
---|
962 | 944 | struct device_attribute *devattr, char *buf) |
---|
963 | 945 | { |
---|
964 | | - struct pmbus_data *data = pmbus_update_device(dev); |
---|
| 946 | + struct i2c_client *client = to_i2c_client(dev->parent); |
---|
965 | 947 | struct pmbus_sensor *sensor = to_pmbus_sensor(devattr); |
---|
| 948 | + struct pmbus_data *data = i2c_get_clientdata(client); |
---|
| 949 | + ssize_t ret; |
---|
966 | 950 | |
---|
| 951 | + mutex_lock(&data->update_lock); |
---|
| 952 | + pmbus_update_sensor_data(client, sensor); |
---|
967 | 953 | if (sensor->data < 0) |
---|
968 | | - return sensor->data; |
---|
969 | | - |
---|
970 | | - return snprintf(buf, PAGE_SIZE, "%ld\n", pmbus_reg2data(data, sensor)); |
---|
| 954 | + ret = sensor->data; |
---|
| 955 | + else |
---|
| 956 | + ret = snprintf(buf, PAGE_SIZE, "%lld\n", pmbus_reg2data(data, sensor)); |
---|
| 957 | + mutex_unlock(&data->update_lock); |
---|
| 958 | + return ret; |
---|
971 | 959 | } |
---|
972 | 960 | |
---|
973 | 961 | static ssize_t pmbus_set_sensor(struct device *dev, |
---|
.. | .. |
---|
978 | 966 | struct pmbus_data *data = i2c_get_clientdata(client); |
---|
979 | 967 | struct pmbus_sensor *sensor = to_pmbus_sensor(devattr); |
---|
980 | 968 | ssize_t rv = count; |
---|
981 | | - long val = 0; |
---|
| 969 | + s64 val; |
---|
982 | 970 | int ret; |
---|
983 | 971 | u16 regval; |
---|
984 | 972 | |
---|
985 | | - if (kstrtol(buf, 10, &val) < 0) |
---|
| 973 | + if (kstrtos64(buf, 10, &val) < 0) |
---|
986 | 974 | return -EINVAL; |
---|
987 | 975 | |
---|
988 | 976 | mutex_lock(&data->update_lock); |
---|
.. | .. |
---|
1008 | 996 | { |
---|
1009 | 997 | if (data->num_attributes >= data->max_attributes - 1) { |
---|
1010 | 998 | int new_max_attrs = data->max_attributes + PMBUS_ATTR_ALLOC_SIZE; |
---|
1011 | | - void *new_attrs = krealloc(data->group.attrs, |
---|
1012 | | - new_max_attrs * sizeof(void *), |
---|
1013 | | - GFP_KERNEL); |
---|
| 999 | + void *new_attrs = devm_krealloc(data->dev, data->group.attrs, |
---|
| 1000 | + new_max_attrs * sizeof(void *), |
---|
| 1001 | + GFP_KERNEL); |
---|
1014 | 1002 | if (!new_attrs) |
---|
1015 | 1003 | return -ENOMEM; |
---|
1016 | 1004 | data->group.attrs = new_attrs; |
---|
.. | .. |
---|
1058 | 1046 | const char *name, const char *type, int seq, |
---|
1059 | 1047 | struct pmbus_sensor *s1, |
---|
1060 | 1048 | struct pmbus_sensor *s2, |
---|
1061 | | - u16 reg, u16 mask) |
---|
| 1049 | + u8 page, u16 reg, u16 mask) |
---|
1062 | 1050 | { |
---|
1063 | 1051 | struct pmbus_boolean *boolean; |
---|
1064 | 1052 | struct sensor_device_attribute *a; |
---|
| 1053 | + |
---|
| 1054 | + if (WARN((s1 && !s2) || (!s1 && s2), "Bad s1/s2 parameters\n")) |
---|
| 1055 | + return -EINVAL; |
---|
1065 | 1056 | |
---|
1066 | 1057 | boolean = devm_kzalloc(data->dev, sizeof(*boolean), GFP_KERNEL); |
---|
1067 | 1058 | if (!boolean) |
---|
.. | .. |
---|
1073 | 1064 | name, seq, type); |
---|
1074 | 1065 | boolean->s1 = s1; |
---|
1075 | 1066 | boolean->s2 = s2; |
---|
1076 | | - pmbus_attr_init(a, boolean->name, S_IRUGO, pmbus_show_boolean, NULL, |
---|
1077 | | - (reg << 16) | mask); |
---|
| 1067 | + pmbus_attr_init(a, boolean->name, 0444, pmbus_show_boolean, NULL, |
---|
| 1068 | + pb_reg_to_index(page, reg, mask)); |
---|
1078 | 1069 | |
---|
1079 | 1070 | return pmbus_add_attribute(data, &a->dev_attr.attr); |
---|
1080 | 1071 | } |
---|
1081 | 1072 | |
---|
1082 | 1073 | static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data, |
---|
1083 | 1074 | const char *name, const char *type, |
---|
1084 | | - int seq, int page, int reg, |
---|
| 1075 | + int seq, int page, int phase, |
---|
| 1076 | + int reg, |
---|
1085 | 1077 | enum pmbus_sensor_classes class, |
---|
1086 | 1078 | bool update, bool readonly, |
---|
1087 | 1079 | bool convert) |
---|
.. | .. |
---|
1101 | 1093 | snprintf(sensor->name, sizeof(sensor->name), "%s%d", |
---|
1102 | 1094 | name, seq); |
---|
1103 | 1095 | |
---|
| 1096 | + if (data->flags & PMBUS_WRITE_PROTECTED) |
---|
| 1097 | + readonly = true; |
---|
| 1098 | + |
---|
1104 | 1099 | sensor->page = page; |
---|
| 1100 | + sensor->phase = phase; |
---|
1105 | 1101 | sensor->reg = reg; |
---|
1106 | 1102 | sensor->class = class; |
---|
1107 | 1103 | sensor->update = update; |
---|
1108 | 1104 | sensor->convert = convert; |
---|
| 1105 | + sensor->data = -ENODATA; |
---|
1109 | 1106 | pmbus_dev_attr_init(a, sensor->name, |
---|
1110 | | - readonly ? S_IRUGO : S_IRUGO | S_IWUSR, |
---|
| 1107 | + readonly ? 0444 : 0644, |
---|
1111 | 1108 | pmbus_show_sensor, pmbus_set_sensor); |
---|
1112 | 1109 | |
---|
1113 | 1110 | if (pmbus_add_attribute(data, &a->attr)) |
---|
.. | .. |
---|
1121 | 1118 | |
---|
1122 | 1119 | static int pmbus_add_label(struct pmbus_data *data, |
---|
1123 | 1120 | const char *name, int seq, |
---|
1124 | | - const char *lstring, int index) |
---|
| 1121 | + const char *lstring, int index, int phase) |
---|
1125 | 1122 | { |
---|
1126 | 1123 | struct pmbus_label *label; |
---|
1127 | 1124 | struct device_attribute *a; |
---|
.. | .. |
---|
1133 | 1130 | a = &label->attribute; |
---|
1134 | 1131 | |
---|
1135 | 1132 | snprintf(label->name, sizeof(label->name), "%s%d_label", name, seq); |
---|
1136 | | - if (!index) |
---|
1137 | | - strncpy(label->label, lstring, sizeof(label->label) - 1); |
---|
1138 | | - else |
---|
1139 | | - snprintf(label->label, sizeof(label->label), "%s%d", lstring, |
---|
1140 | | - index); |
---|
| 1133 | + if (!index) { |
---|
| 1134 | + if (phase == 0xff) |
---|
| 1135 | + strncpy(label->label, lstring, |
---|
| 1136 | + sizeof(label->label) - 1); |
---|
| 1137 | + else |
---|
| 1138 | + snprintf(label->label, sizeof(label->label), "%s.%d", |
---|
| 1139 | + lstring, phase); |
---|
| 1140 | + } else { |
---|
| 1141 | + if (phase == 0xff) |
---|
| 1142 | + snprintf(label->label, sizeof(label->label), "%s%d", |
---|
| 1143 | + lstring, index); |
---|
| 1144 | + else |
---|
| 1145 | + snprintf(label->label, sizeof(label->label), "%s%d.%d", |
---|
| 1146 | + lstring, index, phase); |
---|
| 1147 | + } |
---|
1141 | 1148 | |
---|
1142 | | - pmbus_dev_attr_init(a, label->name, S_IRUGO, pmbus_show_label, NULL); |
---|
| 1149 | + pmbus_dev_attr_init(a, label->name, 0444, pmbus_show_label, NULL); |
---|
1143 | 1150 | return pmbus_add_attribute(data, &a->attr); |
---|
1144 | 1151 | } |
---|
1145 | 1152 | |
---|
.. | .. |
---|
1176 | 1183 | bool compare; /* true if compare function needed */ |
---|
1177 | 1184 | u32 func; /* sensor mask */ |
---|
1178 | 1185 | u32 sfunc; /* sensor status mask */ |
---|
1179 | | - int sbase; /* status base register */ |
---|
| 1186 | + int sreg; /* status register */ |
---|
1180 | 1187 | const struct pmbus_limit_attr *limit;/* limit registers */ |
---|
1181 | 1188 | }; |
---|
1182 | 1189 | |
---|
.. | .. |
---|
1202 | 1209 | for (i = 0; i < nlimit; i++) { |
---|
1203 | 1210 | if (pmbus_check_word_register(client, page, l->reg)) { |
---|
1204 | 1211 | curr = pmbus_add_sensor(data, name, l->attr, index, |
---|
1205 | | - page, l->reg, attr->class, |
---|
| 1212 | + page, 0xff, l->reg, attr->class, |
---|
1206 | 1213 | attr->update || l->update, |
---|
1207 | 1214 | false, true); |
---|
1208 | 1215 | if (!curr) |
---|
.. | .. |
---|
1214 | 1221 | : NULL, |
---|
1215 | 1222 | attr->compare ? l->low ? base : curr |
---|
1216 | 1223 | : NULL, |
---|
1217 | | - attr->sbase + page, l->sbit); |
---|
| 1224 | + page, attr->sreg, l->sbit); |
---|
1218 | 1225 | if (ret) |
---|
1219 | 1226 | return ret; |
---|
1220 | 1227 | have_alarm = 1; |
---|
.. | .. |
---|
1229 | 1236 | struct pmbus_data *data, |
---|
1230 | 1237 | const struct pmbus_driver_info *info, |
---|
1231 | 1238 | const char *name, |
---|
1232 | | - int index, int page, |
---|
| 1239 | + int index, int page, int phase, |
---|
1233 | 1240 | const struct pmbus_sensor_attr *attr, |
---|
1234 | 1241 | bool paged) |
---|
1235 | 1242 | { |
---|
.. | .. |
---|
1239 | 1246 | |
---|
1240 | 1247 | if (attr->label) { |
---|
1241 | 1248 | ret = pmbus_add_label(data, name, index, attr->label, |
---|
1242 | | - paged ? page + 1 : 0); |
---|
| 1249 | + paged ? page + 1 : 0, phase); |
---|
1243 | 1250 | if (ret) |
---|
1244 | 1251 | return ret; |
---|
1245 | 1252 | } |
---|
1246 | | - base = pmbus_add_sensor(data, name, "input", index, page, attr->reg, |
---|
1247 | | - attr->class, true, true, true); |
---|
| 1253 | + base = pmbus_add_sensor(data, name, "input", index, page, phase, |
---|
| 1254 | + attr->reg, attr->class, true, true, true); |
---|
1248 | 1255 | if (!base) |
---|
1249 | 1256 | return -ENOMEM; |
---|
1250 | | - if (attr->sfunc) { |
---|
| 1257 | + /* No limit and alarm attributes for phase specific sensors */ |
---|
| 1258 | + if (attr->sfunc && phase == 0xff) { |
---|
1251 | 1259 | ret = pmbus_add_limit_attrs(client, data, info, name, |
---|
1252 | 1260 | index, page, base, attr); |
---|
1253 | 1261 | if (ret < 0) |
---|
.. | .. |
---|
1263 | 1271 | pmbus_check_status_register(client, page)) { |
---|
1264 | 1272 | ret = pmbus_add_boolean(data, name, "alarm", index, |
---|
1265 | 1273 | NULL, NULL, |
---|
1266 | | - PB_STATUS_BASE + page, |
---|
| 1274 | + page, PMBUS_STATUS_WORD, |
---|
1267 | 1275 | attr->gbit); |
---|
1268 | 1276 | if (ret) |
---|
1269 | 1277 | return ret; |
---|
.. | .. |
---|
1317 | 1325 | continue; |
---|
1318 | 1326 | ret = pmbus_add_sensor_attrs_one(client, data, info, |
---|
1319 | 1327 | name, index, page, |
---|
1320 | | - attrs, paged); |
---|
| 1328 | + 0xff, attrs, paged); |
---|
1321 | 1329 | if (ret) |
---|
1322 | 1330 | return ret; |
---|
1323 | 1331 | index++; |
---|
| 1332 | + if (info->phases[page]) { |
---|
| 1333 | + int phase; |
---|
| 1334 | + |
---|
| 1335 | + for (phase = 0; phase < info->phases[page]; |
---|
| 1336 | + phase++) { |
---|
| 1337 | + if (!(info->pfunc[phase] & attrs->func)) |
---|
| 1338 | + continue; |
---|
| 1339 | + ret = pmbus_add_sensor_attrs_one(client, |
---|
| 1340 | + data, info, name, index, page, |
---|
| 1341 | + phase, attrs, paged); |
---|
| 1342 | + if (ret) |
---|
| 1343 | + return ret; |
---|
| 1344 | + index++; |
---|
| 1345 | + } |
---|
| 1346 | + } |
---|
1324 | 1347 | } |
---|
1325 | 1348 | attrs++; |
---|
1326 | 1349 | } |
---|
.. | .. |
---|
1337 | 1360 | .reg = PMBUS_VIN_UV_FAULT_LIMIT, |
---|
1338 | 1361 | .attr = "lcrit", |
---|
1339 | 1362 | .alarm = "lcrit_alarm", |
---|
1340 | | - .sbit = PB_VOLTAGE_UV_FAULT, |
---|
| 1363 | + .sbit = PB_VOLTAGE_UV_FAULT | PB_VOLTAGE_VIN_OFF, |
---|
1341 | 1364 | }, { |
---|
1342 | 1365 | .reg = PMBUS_VIN_OV_WARN_LIMIT, |
---|
1343 | 1366 | .attr = "max", |
---|
.. | .. |
---|
1363 | 1386 | }, { |
---|
1364 | 1387 | .reg = PMBUS_VIRT_RESET_VIN_HISTORY, |
---|
1365 | 1388 | .attr = "reset_history", |
---|
| 1389 | + }, { |
---|
| 1390 | + .reg = PMBUS_MFR_VIN_MIN, |
---|
| 1391 | + .attr = "rated_min", |
---|
| 1392 | + }, { |
---|
| 1393 | + .reg = PMBUS_MFR_VIN_MAX, |
---|
| 1394 | + .attr = "rated_max", |
---|
1366 | 1395 | }, |
---|
1367 | 1396 | }; |
---|
1368 | 1397 | |
---|
.. | .. |
---|
1426 | 1455 | }, { |
---|
1427 | 1456 | .reg = PMBUS_VIRT_RESET_VOUT_HISTORY, |
---|
1428 | 1457 | .attr = "reset_history", |
---|
1429 | | - } |
---|
| 1458 | + }, { |
---|
| 1459 | + .reg = PMBUS_MFR_VOUT_MIN, |
---|
| 1460 | + .attr = "rated_min", |
---|
| 1461 | + }, { |
---|
| 1462 | + .reg = PMBUS_MFR_VOUT_MAX, |
---|
| 1463 | + .attr = "rated_max", |
---|
| 1464 | + }, |
---|
1430 | 1465 | }; |
---|
1431 | 1466 | |
---|
1432 | 1467 | static const struct pmbus_sensor_attr voltage_attributes[] = { |
---|
.. | .. |
---|
1436 | 1471 | .label = "vin", |
---|
1437 | 1472 | .func = PMBUS_HAVE_VIN, |
---|
1438 | 1473 | .sfunc = PMBUS_HAVE_STATUS_INPUT, |
---|
1439 | | - .sbase = PB_STATUS_INPUT_BASE, |
---|
| 1474 | + .sreg = PMBUS_STATUS_INPUT, |
---|
1440 | 1475 | .gbit = PB_STATUS_VIN_UV, |
---|
1441 | 1476 | .limit = vin_limit_attrs, |
---|
1442 | 1477 | .nlimit = ARRAY_SIZE(vin_limit_attrs), |
---|
.. | .. |
---|
1446 | 1481 | .label = "vmon", |
---|
1447 | 1482 | .func = PMBUS_HAVE_VMON, |
---|
1448 | 1483 | .sfunc = PMBUS_HAVE_STATUS_VMON, |
---|
1449 | | - .sbase = PB_STATUS_VMON_BASE, |
---|
| 1484 | + .sreg = PMBUS_VIRT_STATUS_VMON, |
---|
1450 | 1485 | .limit = vmon_limit_attrs, |
---|
1451 | 1486 | .nlimit = ARRAY_SIZE(vmon_limit_attrs), |
---|
1452 | 1487 | }, { |
---|
.. | .. |
---|
1461 | 1496 | .paged = true, |
---|
1462 | 1497 | .func = PMBUS_HAVE_VOUT, |
---|
1463 | 1498 | .sfunc = PMBUS_HAVE_STATUS_VOUT, |
---|
1464 | | - .sbase = PB_STATUS_VOUT_BASE, |
---|
| 1499 | + .sreg = PMBUS_STATUS_VOUT, |
---|
1465 | 1500 | .gbit = PB_STATUS_VOUT_OV, |
---|
1466 | 1501 | .limit = vout_limit_attrs, |
---|
1467 | 1502 | .nlimit = ARRAY_SIZE(vout_limit_attrs), |
---|
.. | .. |
---|
1496 | 1531 | }, { |
---|
1497 | 1532 | .reg = PMBUS_VIRT_RESET_IIN_HISTORY, |
---|
1498 | 1533 | .attr = "reset_history", |
---|
1499 | | - } |
---|
| 1534 | + }, { |
---|
| 1535 | + .reg = PMBUS_MFR_IIN_MAX, |
---|
| 1536 | + .attr = "rated_max", |
---|
| 1537 | + }, |
---|
1500 | 1538 | }; |
---|
1501 | 1539 | |
---|
1502 | 1540 | static const struct pmbus_limit_attr iout_limit_attrs[] = { |
---|
.. | .. |
---|
1530 | 1568 | }, { |
---|
1531 | 1569 | .reg = PMBUS_VIRT_RESET_IOUT_HISTORY, |
---|
1532 | 1570 | .attr = "reset_history", |
---|
1533 | | - } |
---|
| 1571 | + }, { |
---|
| 1572 | + .reg = PMBUS_MFR_IOUT_MAX, |
---|
| 1573 | + .attr = "rated_max", |
---|
| 1574 | + }, |
---|
1534 | 1575 | }; |
---|
1535 | 1576 | |
---|
1536 | 1577 | static const struct pmbus_sensor_attr current_attributes[] = { |
---|
.. | .. |
---|
1540 | 1581 | .label = "iin", |
---|
1541 | 1582 | .func = PMBUS_HAVE_IIN, |
---|
1542 | 1583 | .sfunc = PMBUS_HAVE_STATUS_INPUT, |
---|
1543 | | - .sbase = PB_STATUS_INPUT_BASE, |
---|
| 1584 | + .sreg = PMBUS_STATUS_INPUT, |
---|
1544 | 1585 | .gbit = PB_STATUS_INPUT, |
---|
1545 | 1586 | .limit = iin_limit_attrs, |
---|
1546 | 1587 | .nlimit = ARRAY_SIZE(iin_limit_attrs), |
---|
.. | .. |
---|
1551 | 1592 | .paged = true, |
---|
1552 | 1593 | .func = PMBUS_HAVE_IOUT, |
---|
1553 | 1594 | .sfunc = PMBUS_HAVE_STATUS_IOUT, |
---|
1554 | | - .sbase = PB_STATUS_IOUT_BASE, |
---|
| 1595 | + .sreg = PMBUS_STATUS_IOUT, |
---|
1555 | 1596 | .gbit = PB_STATUS_IOUT_OC, |
---|
1556 | 1597 | .limit = iout_limit_attrs, |
---|
1557 | 1598 | .nlimit = ARRAY_SIZE(iout_limit_attrs), |
---|
.. | .. |
---|
1581 | 1622 | }, { |
---|
1582 | 1623 | .reg = PMBUS_VIRT_RESET_PIN_HISTORY, |
---|
1583 | 1624 | .attr = "reset_history", |
---|
1584 | | - } |
---|
| 1625 | + }, { |
---|
| 1626 | + .reg = PMBUS_MFR_PIN_MAX, |
---|
| 1627 | + .attr = "rated_max", |
---|
| 1628 | + }, |
---|
1585 | 1629 | }; |
---|
1586 | 1630 | |
---|
1587 | 1631 | static const struct pmbus_limit_attr pout_limit_attrs[] = { |
---|
.. | .. |
---|
1615 | 1659 | }, { |
---|
1616 | 1660 | .reg = PMBUS_VIRT_RESET_POUT_HISTORY, |
---|
1617 | 1661 | .attr = "reset_history", |
---|
1618 | | - } |
---|
| 1662 | + }, { |
---|
| 1663 | + .reg = PMBUS_MFR_POUT_MAX, |
---|
| 1664 | + .attr = "rated_max", |
---|
| 1665 | + }, |
---|
1619 | 1666 | }; |
---|
1620 | 1667 | |
---|
1621 | 1668 | static const struct pmbus_sensor_attr power_attributes[] = { |
---|
.. | .. |
---|
1625 | 1672 | .label = "pin", |
---|
1626 | 1673 | .func = PMBUS_HAVE_PIN, |
---|
1627 | 1674 | .sfunc = PMBUS_HAVE_STATUS_INPUT, |
---|
1628 | | - .sbase = PB_STATUS_INPUT_BASE, |
---|
| 1675 | + .sreg = PMBUS_STATUS_INPUT, |
---|
1629 | 1676 | .gbit = PB_STATUS_INPUT, |
---|
1630 | 1677 | .limit = pin_limit_attrs, |
---|
1631 | 1678 | .nlimit = ARRAY_SIZE(pin_limit_attrs), |
---|
.. | .. |
---|
1636 | 1683 | .paged = true, |
---|
1637 | 1684 | .func = PMBUS_HAVE_POUT, |
---|
1638 | 1685 | .sfunc = PMBUS_HAVE_STATUS_IOUT, |
---|
1639 | | - .sbase = PB_STATUS_IOUT_BASE, |
---|
| 1686 | + .sreg = PMBUS_STATUS_IOUT, |
---|
1640 | 1687 | .limit = pout_limit_attrs, |
---|
1641 | 1688 | .nlimit = ARRAY_SIZE(pout_limit_attrs), |
---|
1642 | 1689 | } |
---|
.. | .. |
---|
1679 | 1726 | }, { |
---|
1680 | 1727 | .reg = PMBUS_VIRT_RESET_TEMP_HISTORY, |
---|
1681 | 1728 | .attr = "reset_history", |
---|
1682 | | - } |
---|
| 1729 | + }, { |
---|
| 1730 | + .reg = PMBUS_MFR_MAX_TEMP_1, |
---|
| 1731 | + .attr = "rated_max", |
---|
| 1732 | + }, |
---|
1683 | 1733 | }; |
---|
1684 | 1734 | |
---|
1685 | 1735 | static const struct pmbus_limit_attr temp_limit_attrs2[] = { |
---|
.. | .. |
---|
1717 | 1767 | }, { |
---|
1718 | 1768 | .reg = PMBUS_VIRT_RESET_TEMP2_HISTORY, |
---|
1719 | 1769 | .attr = "reset_history", |
---|
1720 | | - } |
---|
| 1770 | + }, { |
---|
| 1771 | + .reg = PMBUS_MFR_MAX_TEMP_2, |
---|
| 1772 | + .attr = "rated_max", |
---|
| 1773 | + }, |
---|
1721 | 1774 | }; |
---|
1722 | 1775 | |
---|
1723 | 1776 | static const struct pmbus_limit_attr temp_limit_attrs3[] = { |
---|
.. | .. |
---|
1743 | 1796 | .attr = "crit", |
---|
1744 | 1797 | .alarm = "crit_alarm", |
---|
1745 | 1798 | .sbit = PB_TEMP_OT_FAULT, |
---|
1746 | | - } |
---|
| 1799 | + }, { |
---|
| 1800 | + .reg = PMBUS_MFR_MAX_TEMP_3, |
---|
| 1801 | + .attr = "rated_max", |
---|
| 1802 | + }, |
---|
1747 | 1803 | }; |
---|
1748 | 1804 | |
---|
1749 | 1805 | static const struct pmbus_sensor_attr temp_attributes[] = { |
---|
.. | .. |
---|
1755 | 1811 | .compare = true, |
---|
1756 | 1812 | .func = PMBUS_HAVE_TEMP, |
---|
1757 | 1813 | .sfunc = PMBUS_HAVE_STATUS_TEMP, |
---|
1758 | | - .sbase = PB_STATUS_TEMP_BASE, |
---|
| 1814 | + .sreg = PMBUS_STATUS_TEMPERATURE, |
---|
1759 | 1815 | .gbit = PB_STATUS_TEMPERATURE, |
---|
1760 | 1816 | .limit = temp_limit_attrs, |
---|
1761 | 1817 | .nlimit = ARRAY_SIZE(temp_limit_attrs), |
---|
.. | .. |
---|
1767 | 1823 | .compare = true, |
---|
1768 | 1824 | .func = PMBUS_HAVE_TEMP2, |
---|
1769 | 1825 | .sfunc = PMBUS_HAVE_STATUS_TEMP, |
---|
1770 | | - .sbase = PB_STATUS_TEMP_BASE, |
---|
| 1826 | + .sreg = PMBUS_STATUS_TEMPERATURE, |
---|
1771 | 1827 | .gbit = PB_STATUS_TEMPERATURE, |
---|
1772 | 1828 | .limit = temp_limit_attrs2, |
---|
1773 | 1829 | .nlimit = ARRAY_SIZE(temp_limit_attrs2), |
---|
.. | .. |
---|
1779 | 1835 | .compare = true, |
---|
1780 | 1836 | .func = PMBUS_HAVE_TEMP3, |
---|
1781 | 1837 | .sfunc = PMBUS_HAVE_STATUS_TEMP, |
---|
1782 | | - .sbase = PB_STATUS_TEMP_BASE, |
---|
| 1838 | + .sreg = PMBUS_STATUS_TEMPERATURE, |
---|
1783 | 1839 | .gbit = PB_STATUS_TEMPERATURE, |
---|
1784 | 1840 | .limit = temp_limit_attrs3, |
---|
1785 | 1841 | .nlimit = ARRAY_SIZE(temp_limit_attrs3), |
---|
.. | .. |
---|
1824 | 1880 | struct pmbus_sensor *sensor; |
---|
1825 | 1881 | |
---|
1826 | 1882 | sensor = pmbus_add_sensor(data, "fan", "target", index, page, |
---|
1827 | | - PMBUS_VIRT_FAN_TARGET_1 + id, PSC_FAN, |
---|
| 1883 | + 0xff, PMBUS_VIRT_FAN_TARGET_1 + id, PSC_FAN, |
---|
1828 | 1884 | false, false, true); |
---|
1829 | 1885 | |
---|
1830 | 1886 | if (!sensor) |
---|
.. | .. |
---|
1835 | 1891 | return 0; |
---|
1836 | 1892 | |
---|
1837 | 1893 | sensor = pmbus_add_sensor(data, "pwm", NULL, index, page, |
---|
1838 | | - PMBUS_VIRT_PWM_1 + id, PSC_PWM, |
---|
| 1894 | + 0xff, PMBUS_VIRT_PWM_1 + id, PSC_PWM, |
---|
1839 | 1895 | false, false, true); |
---|
1840 | 1896 | |
---|
1841 | 1897 | if (!sensor) |
---|
1842 | 1898 | return -ENOMEM; |
---|
1843 | 1899 | |
---|
1844 | 1900 | sensor = pmbus_add_sensor(data, "pwm", "enable", index, page, |
---|
1845 | | - PMBUS_VIRT_PWM_ENABLE_1 + id, PSC_PWM, |
---|
| 1901 | + 0xff, PMBUS_VIRT_PWM_ENABLE_1 + id, PSC_PWM, |
---|
1846 | 1902 | true, false, false); |
---|
1847 | 1903 | |
---|
1848 | 1904 | if (!sensor) |
---|
.. | .. |
---|
1884 | 1940 | continue; |
---|
1885 | 1941 | |
---|
1886 | 1942 | if (pmbus_add_sensor(data, "fan", "input", index, |
---|
1887 | | - page, pmbus_fan_registers[f], |
---|
| 1943 | + page, 0xff, pmbus_fan_registers[f], |
---|
1888 | 1944 | PSC_FAN, true, true, true) == NULL) |
---|
1889 | 1945 | return -ENOMEM; |
---|
1890 | 1946 | |
---|
.. | .. |
---|
1904 | 1960 | if ((info->func[page] & pmbus_fan_status_flags[f]) && |
---|
1905 | 1961 | pmbus_check_byte_register(client, |
---|
1906 | 1962 | page, pmbus_fan_status_registers[f])) { |
---|
1907 | | - int base; |
---|
| 1963 | + int reg; |
---|
1908 | 1964 | |
---|
1909 | 1965 | if (f > 1) /* fan 3, 4 */ |
---|
1910 | | - base = PB_STATUS_FAN34_BASE + page; |
---|
| 1966 | + reg = PMBUS_STATUS_FAN_34; |
---|
1911 | 1967 | else |
---|
1912 | | - base = PB_STATUS_FAN_BASE + page; |
---|
| 1968 | + reg = PMBUS_STATUS_FAN_12; |
---|
1913 | 1969 | ret = pmbus_add_boolean(data, "fan", |
---|
1914 | | - "alarm", index, NULL, NULL, base, |
---|
| 1970 | + "alarm", index, NULL, NULL, page, reg, |
---|
1915 | 1971 | PB_FAN_FAN1_WARNING >> (f & 1)); |
---|
1916 | 1972 | if (ret) |
---|
1917 | 1973 | return ret; |
---|
1918 | 1974 | ret = pmbus_add_boolean(data, "fan", |
---|
1919 | | - "fault", index, NULL, NULL, base, |
---|
| 1975 | + "fault", index, NULL, NULL, page, reg, |
---|
1920 | 1976 | PB_FAN_FAN1_FAULT >> (f & 1)); |
---|
1921 | 1977 | if (ret) |
---|
1922 | 1978 | return ret; |
---|
.. | .. |
---|
1924 | 1980 | index++; |
---|
1925 | 1981 | } |
---|
1926 | 1982 | } |
---|
| 1983 | + return 0; |
---|
| 1984 | +} |
---|
| 1985 | + |
---|
| 1986 | +struct pmbus_samples_attr { |
---|
| 1987 | + int reg; |
---|
| 1988 | + char *name; |
---|
| 1989 | +}; |
---|
| 1990 | + |
---|
| 1991 | +struct pmbus_samples_reg { |
---|
| 1992 | + int page; |
---|
| 1993 | + struct pmbus_samples_attr *attr; |
---|
| 1994 | + struct device_attribute dev_attr; |
---|
| 1995 | +}; |
---|
| 1996 | + |
---|
| 1997 | +static struct pmbus_samples_attr pmbus_samples_registers[] = { |
---|
| 1998 | + { |
---|
| 1999 | + .reg = PMBUS_VIRT_SAMPLES, |
---|
| 2000 | + .name = "samples", |
---|
| 2001 | + }, { |
---|
| 2002 | + .reg = PMBUS_VIRT_IN_SAMPLES, |
---|
| 2003 | + .name = "in_samples", |
---|
| 2004 | + }, { |
---|
| 2005 | + .reg = PMBUS_VIRT_CURR_SAMPLES, |
---|
| 2006 | + .name = "curr_samples", |
---|
| 2007 | + }, { |
---|
| 2008 | + .reg = PMBUS_VIRT_POWER_SAMPLES, |
---|
| 2009 | + .name = "power_samples", |
---|
| 2010 | + }, { |
---|
| 2011 | + .reg = PMBUS_VIRT_TEMP_SAMPLES, |
---|
| 2012 | + .name = "temp_samples", |
---|
| 2013 | + } |
---|
| 2014 | +}; |
---|
| 2015 | + |
---|
| 2016 | +#define to_samples_reg(x) container_of(x, struct pmbus_samples_reg, dev_attr) |
---|
| 2017 | + |
---|
| 2018 | +static ssize_t pmbus_show_samples(struct device *dev, |
---|
| 2019 | + struct device_attribute *devattr, char *buf) |
---|
| 2020 | +{ |
---|
| 2021 | + int val; |
---|
| 2022 | + struct i2c_client *client = to_i2c_client(dev->parent); |
---|
| 2023 | + struct pmbus_samples_reg *reg = to_samples_reg(devattr); |
---|
| 2024 | + struct pmbus_data *data = i2c_get_clientdata(client); |
---|
| 2025 | + |
---|
| 2026 | + mutex_lock(&data->update_lock); |
---|
| 2027 | + val = _pmbus_read_word_data(client, reg->page, 0xff, reg->attr->reg); |
---|
| 2028 | + mutex_unlock(&data->update_lock); |
---|
| 2029 | + if (val < 0) |
---|
| 2030 | + return val; |
---|
| 2031 | + |
---|
| 2032 | + return snprintf(buf, PAGE_SIZE, "%d\n", val); |
---|
| 2033 | +} |
---|
| 2034 | + |
---|
| 2035 | +static ssize_t pmbus_set_samples(struct device *dev, |
---|
| 2036 | + struct device_attribute *devattr, |
---|
| 2037 | + const char *buf, size_t count) |
---|
| 2038 | +{ |
---|
| 2039 | + int ret; |
---|
| 2040 | + long val; |
---|
| 2041 | + struct i2c_client *client = to_i2c_client(dev->parent); |
---|
| 2042 | + struct pmbus_samples_reg *reg = to_samples_reg(devattr); |
---|
| 2043 | + struct pmbus_data *data = i2c_get_clientdata(client); |
---|
| 2044 | + |
---|
| 2045 | + if (kstrtol(buf, 0, &val) < 0) |
---|
| 2046 | + return -EINVAL; |
---|
| 2047 | + |
---|
| 2048 | + mutex_lock(&data->update_lock); |
---|
| 2049 | + ret = _pmbus_write_word_data(client, reg->page, reg->attr->reg, val); |
---|
| 2050 | + mutex_unlock(&data->update_lock); |
---|
| 2051 | + |
---|
| 2052 | + return ret ? : count; |
---|
| 2053 | +} |
---|
| 2054 | + |
---|
| 2055 | +static int pmbus_add_samples_attr(struct pmbus_data *data, int page, |
---|
| 2056 | + struct pmbus_samples_attr *attr) |
---|
| 2057 | +{ |
---|
| 2058 | + struct pmbus_samples_reg *reg; |
---|
| 2059 | + |
---|
| 2060 | + reg = devm_kzalloc(data->dev, sizeof(*reg), GFP_KERNEL); |
---|
| 2061 | + if (!reg) |
---|
| 2062 | + return -ENOMEM; |
---|
| 2063 | + |
---|
| 2064 | + reg->attr = attr; |
---|
| 2065 | + reg->page = page; |
---|
| 2066 | + |
---|
| 2067 | + pmbus_dev_attr_init(®->dev_attr, attr->name, 0644, |
---|
| 2068 | + pmbus_show_samples, pmbus_set_samples); |
---|
| 2069 | + |
---|
| 2070 | + return pmbus_add_attribute(data, ®->dev_attr.attr); |
---|
| 2071 | +} |
---|
| 2072 | + |
---|
| 2073 | +static int pmbus_add_samples_attributes(struct i2c_client *client, |
---|
| 2074 | + struct pmbus_data *data) |
---|
| 2075 | +{ |
---|
| 2076 | + const struct pmbus_driver_info *info = data->info; |
---|
| 2077 | + int s; |
---|
| 2078 | + |
---|
| 2079 | + if (!(info->func[0] & PMBUS_HAVE_SAMPLES)) |
---|
| 2080 | + return 0; |
---|
| 2081 | + |
---|
| 2082 | + for (s = 0; s < ARRAY_SIZE(pmbus_samples_registers); s++) { |
---|
| 2083 | + struct pmbus_samples_attr *attr; |
---|
| 2084 | + int ret; |
---|
| 2085 | + |
---|
| 2086 | + attr = &pmbus_samples_registers[s]; |
---|
| 2087 | + if (!pmbus_check_word_register(client, 0, attr->reg)) |
---|
| 2088 | + continue; |
---|
| 2089 | + |
---|
| 2090 | + ret = pmbus_add_samples_attr(data, 0, attr); |
---|
| 2091 | + if (ret) |
---|
| 2092 | + return ret; |
---|
| 2093 | + } |
---|
| 2094 | + |
---|
1927 | 2095 | return 0; |
---|
1928 | 2096 | } |
---|
1929 | 2097 | |
---|
.. | .. |
---|
1958 | 2126 | |
---|
1959 | 2127 | /* Fans */ |
---|
1960 | 2128 | ret = pmbus_add_fan_attributes(client, data); |
---|
| 2129 | + if (ret) |
---|
| 2130 | + return ret; |
---|
| 2131 | + |
---|
| 2132 | + ret = pmbus_add_samples_attributes(client, data); |
---|
1961 | 2133 | return ret; |
---|
1962 | 2134 | } |
---|
1963 | 2135 | |
---|
.. | .. |
---|
2009 | 2181 | |
---|
2010 | 2182 | static int pmbus_read_status_word(struct i2c_client *client, int page) |
---|
2011 | 2183 | { |
---|
2012 | | - return _pmbus_read_word_data(client, page, PMBUS_STATUS_WORD); |
---|
| 2184 | + return _pmbus_read_word_data(client, page, 0xff, PMBUS_STATUS_WORD); |
---|
2013 | 2185 | } |
---|
2014 | 2186 | |
---|
2015 | 2187 | static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data, |
---|
.. | .. |
---|
2040 | 2212 | ret = i2c_smbus_read_byte_data(client, PMBUS_CAPABILITY); |
---|
2041 | 2213 | if (ret >= 0 && (ret & PB_CAPABILITY_ERROR_CHECK)) |
---|
2042 | 2214 | client->flags |= I2C_CLIENT_PEC; |
---|
| 2215 | + |
---|
| 2216 | + /* |
---|
| 2217 | + * Check if the chip is write protected. If it is, we can not clear |
---|
| 2218 | + * faults, and we should not try it. Also, in that case, writes into |
---|
| 2219 | + * limit registers need to be disabled. |
---|
| 2220 | + */ |
---|
| 2221 | + ret = i2c_smbus_read_byte_data(client, PMBUS_WRITE_PROTECT); |
---|
| 2222 | + if (ret > 0 && (ret & PB_WP_ANY)) |
---|
| 2223 | + data->flags |= PMBUS_WRITE_PROTECTED | PMBUS_SKIP_STATUS_CHECK; |
---|
2043 | 2224 | |
---|
2044 | 2225 | if (data->info->pages) |
---|
2045 | 2226 | pmbus_clear_faults(client); |
---|
.. | .. |
---|
2074 | 2255 | { |
---|
2075 | 2256 | struct device *dev = rdev_get_dev(rdev); |
---|
2076 | 2257 | struct i2c_client *client = to_i2c_client(dev->parent); |
---|
| 2258 | + struct pmbus_data *data = i2c_get_clientdata(client); |
---|
2077 | 2259 | u8 page = rdev_get_id(rdev); |
---|
2078 | 2260 | int ret; |
---|
2079 | 2261 | |
---|
| 2262 | + mutex_lock(&data->update_lock); |
---|
2080 | 2263 | ret = pmbus_read_byte_data(client, page, PMBUS_OPERATION); |
---|
| 2264 | + mutex_unlock(&data->update_lock); |
---|
| 2265 | + |
---|
2081 | 2266 | if (ret < 0) |
---|
2082 | 2267 | return ret; |
---|
2083 | 2268 | |
---|
.. | .. |
---|
2088 | 2273 | { |
---|
2089 | 2274 | struct device *dev = rdev_get_dev(rdev); |
---|
2090 | 2275 | struct i2c_client *client = to_i2c_client(dev->parent); |
---|
| 2276 | + struct pmbus_data *data = i2c_get_clientdata(client); |
---|
2091 | 2277 | u8 page = rdev_get_id(rdev); |
---|
| 2278 | + int ret; |
---|
2092 | 2279 | |
---|
2093 | | - return pmbus_update_byte_data(client, page, PMBUS_OPERATION, |
---|
2094 | | - PB_OPERATION_CONTROL_ON, |
---|
2095 | | - enable ? PB_OPERATION_CONTROL_ON : 0); |
---|
| 2280 | + mutex_lock(&data->update_lock); |
---|
| 2281 | + ret = pmbus_update_byte_data(client, page, PMBUS_OPERATION, |
---|
| 2282 | + PB_OPERATION_CONTROL_ON, |
---|
| 2283 | + enable ? PB_OPERATION_CONTROL_ON : 0); |
---|
| 2284 | + mutex_unlock(&data->update_lock); |
---|
| 2285 | + |
---|
| 2286 | + return ret; |
---|
2096 | 2287 | } |
---|
2097 | 2288 | |
---|
2098 | 2289 | static int pmbus_regulator_enable(struct regulator_dev *rdev) |
---|
.. | .. |
---|
2183 | 2374 | DEFINE_DEBUGFS_ATTRIBUTE(pmbus_debugfs_ops_status, pmbus_debugfs_get_status, |
---|
2184 | 2375 | NULL, "0x%04llx\n"); |
---|
2185 | 2376 | |
---|
| 2377 | +static int pmbus_debugfs_get_pec(void *data, u64 *val) |
---|
| 2378 | +{ |
---|
| 2379 | + struct i2c_client *client = data; |
---|
| 2380 | + |
---|
| 2381 | + *val = !!(client->flags & I2C_CLIENT_PEC); |
---|
| 2382 | + |
---|
| 2383 | + return 0; |
---|
| 2384 | +} |
---|
| 2385 | + |
---|
| 2386 | +static int pmbus_debugfs_set_pec(void *data, u64 val) |
---|
| 2387 | +{ |
---|
| 2388 | + int rc; |
---|
| 2389 | + struct i2c_client *client = data; |
---|
| 2390 | + |
---|
| 2391 | + if (!val) { |
---|
| 2392 | + client->flags &= ~I2C_CLIENT_PEC; |
---|
| 2393 | + return 0; |
---|
| 2394 | + } |
---|
| 2395 | + |
---|
| 2396 | + if (val != 1) |
---|
| 2397 | + return -EINVAL; |
---|
| 2398 | + |
---|
| 2399 | + rc = i2c_smbus_read_byte_data(client, PMBUS_CAPABILITY); |
---|
| 2400 | + if (rc < 0) |
---|
| 2401 | + return rc; |
---|
| 2402 | + |
---|
| 2403 | + if (!(rc & PB_CAPABILITY_ERROR_CHECK)) |
---|
| 2404 | + return -EOPNOTSUPP; |
---|
| 2405 | + |
---|
| 2406 | + client->flags |= I2C_CLIENT_PEC; |
---|
| 2407 | + |
---|
| 2408 | + return 0; |
---|
| 2409 | +} |
---|
| 2410 | +DEFINE_DEBUGFS_ATTRIBUTE(pmbus_debugfs_ops_pec, pmbus_debugfs_get_pec, |
---|
| 2411 | + pmbus_debugfs_set_pec, "%llu\n"); |
---|
| 2412 | + |
---|
2186 | 2413 | static int pmbus_init_debugfs(struct i2c_client *client, |
---|
2187 | 2414 | struct pmbus_data *data) |
---|
2188 | 2415 | { |
---|
.. | .. |
---|
2210 | 2437 | GFP_KERNEL); |
---|
2211 | 2438 | if (!entries) |
---|
2212 | 2439 | return -ENOMEM; |
---|
| 2440 | + |
---|
| 2441 | + debugfs_create_file("pec", 0664, data->debugfs, client, |
---|
| 2442 | + &pmbus_debugfs_ops_pec); |
---|
2213 | 2443 | |
---|
2214 | 2444 | for (i = 0; i < data->info->pages; ++i) { |
---|
2215 | 2445 | /* Check accessibility of status register if it's not page 0 */ |
---|
.. | .. |
---|
2325 | 2555 | } |
---|
2326 | 2556 | #endif /* IS_ENABLED(CONFIG_DEBUG_FS) */ |
---|
2327 | 2557 | |
---|
2328 | | -int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, |
---|
2329 | | - struct pmbus_driver_info *info) |
---|
| 2558 | +int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info) |
---|
2330 | 2559 | { |
---|
2331 | 2560 | struct device *dev = &client->dev; |
---|
2332 | 2561 | const struct pmbus_platform_data *pdata = dev_get_platdata(dev); |
---|
2333 | 2562 | struct pmbus_data *data; |
---|
| 2563 | + size_t groups_num = 0; |
---|
2334 | 2564 | int ret; |
---|
2335 | 2565 | |
---|
2336 | 2566 | if (!info) |
---|
.. | .. |
---|
2345 | 2575 | if (!data) |
---|
2346 | 2576 | return -ENOMEM; |
---|
2347 | 2577 | |
---|
| 2578 | + if (info->groups) |
---|
| 2579 | + while (info->groups[groups_num]) |
---|
| 2580 | + groups_num++; |
---|
| 2581 | + |
---|
| 2582 | + data->groups = devm_kcalloc(dev, groups_num + 2, sizeof(void *), |
---|
| 2583 | + GFP_KERNEL); |
---|
| 2584 | + if (!data->groups) |
---|
| 2585 | + return -ENOMEM; |
---|
| 2586 | + |
---|
2348 | 2587 | i2c_set_clientdata(client, data); |
---|
2349 | 2588 | mutex_init(&data->update_lock); |
---|
2350 | 2589 | data->dev = dev; |
---|
.. | .. |
---|
2352 | 2591 | if (pdata) |
---|
2353 | 2592 | data->flags = pdata->flags; |
---|
2354 | 2593 | data->info = info; |
---|
| 2594 | + data->currpage = -1; |
---|
| 2595 | + data->currphase = -1; |
---|
2355 | 2596 | |
---|
2356 | 2597 | ret = pmbus_init_common(client, data, info); |
---|
2357 | 2598 | if (ret < 0) |
---|
.. | .. |
---|
2359 | 2600 | |
---|
2360 | 2601 | ret = pmbus_find_attributes(client, data); |
---|
2361 | 2602 | if (ret) |
---|
2362 | | - goto out_kfree; |
---|
| 2603 | + return ret; |
---|
2363 | 2604 | |
---|
2364 | 2605 | /* |
---|
2365 | 2606 | * If there are no attributes, something is wrong. |
---|
.. | .. |
---|
2367 | 2608 | */ |
---|
2368 | 2609 | if (!data->num_attributes) { |
---|
2369 | 2610 | dev_err(dev, "No attributes found\n"); |
---|
2370 | | - ret = -ENODEV; |
---|
2371 | | - goto out_kfree; |
---|
| 2611 | + return -ENODEV; |
---|
2372 | 2612 | } |
---|
2373 | 2613 | |
---|
2374 | 2614 | data->groups[0] = &data->group; |
---|
2375 | | - data->hwmon_dev = hwmon_device_register_with_groups(dev, client->name, |
---|
2376 | | - data, data->groups); |
---|
| 2615 | + memcpy(data->groups + 1, info->groups, sizeof(void *) * groups_num); |
---|
| 2616 | + data->hwmon_dev = devm_hwmon_device_register_with_groups(dev, |
---|
| 2617 | + client->name, data, data->groups); |
---|
2377 | 2618 | if (IS_ERR(data->hwmon_dev)) { |
---|
2378 | | - ret = PTR_ERR(data->hwmon_dev); |
---|
2379 | 2619 | dev_err(dev, "Failed to register hwmon device\n"); |
---|
2380 | | - goto out_kfree; |
---|
| 2620 | + return PTR_ERR(data->hwmon_dev); |
---|
2381 | 2621 | } |
---|
2382 | 2622 | |
---|
2383 | 2623 | ret = pmbus_regulator_register(data); |
---|
2384 | 2624 | if (ret) |
---|
2385 | | - goto out_unregister; |
---|
| 2625 | + return ret; |
---|
2386 | 2626 | |
---|
2387 | 2627 | ret = pmbus_init_debugfs(client, data); |
---|
2388 | 2628 | if (ret) |
---|
2389 | 2629 | dev_warn(dev, "Failed to register debugfs\n"); |
---|
2390 | 2630 | |
---|
2391 | 2631 | return 0; |
---|
2392 | | - |
---|
2393 | | -out_unregister: |
---|
2394 | | - hwmon_device_unregister(data->hwmon_dev); |
---|
2395 | | -out_kfree: |
---|
2396 | | - kfree(data->group.attrs); |
---|
2397 | | - return ret; |
---|
2398 | 2632 | } |
---|
2399 | 2633 | EXPORT_SYMBOL_GPL(pmbus_do_probe); |
---|
2400 | 2634 | |
---|
.. | .. |
---|
2404 | 2638 | |
---|
2405 | 2639 | debugfs_remove_recursive(data->debugfs); |
---|
2406 | 2640 | |
---|
2407 | | - hwmon_device_unregister(data->hwmon_dev); |
---|
2408 | | - kfree(data->group.attrs); |
---|
2409 | 2641 | return 0; |
---|
2410 | 2642 | } |
---|
2411 | 2643 | EXPORT_SYMBOL_GPL(pmbus_do_remove); |
---|