.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Hardware monitoring driver for UCD90xxx Sequencer and System Health |
---|
3 | 4 | * Controller series |
---|
4 | 5 | * |
---|
5 | 6 | * Copyright (C) 2011 Ericsson AB. |
---|
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> |
---|
| 10 | +#include <linux/delay.h> |
---|
23 | 11 | #include <linux/kernel.h> |
---|
24 | 12 | #include <linux/module.h> |
---|
25 | 13 | #include <linux/of_device.h> |
---|
.. | .. |
---|
28 | 16 | #include <linux/slab.h> |
---|
29 | 17 | #include <linux/i2c.h> |
---|
30 | 18 | #include <linux/pmbus.h> |
---|
31 | | -#include <linux/gpio.h> |
---|
32 | 19 | #include <linux/gpio/driver.h> |
---|
| 20 | +#include <linux/timekeeping.h> |
---|
33 | 21 | #include "pmbus.h" |
---|
34 | 22 | |
---|
35 | | -enum chips { ucd9000, ucd90120, ucd90124, ucd90160, ucd9090, ucd90910 }; |
---|
| 23 | +enum chips { ucd9000, ucd90120, ucd90124, ucd90160, ucd90320, ucd9090, |
---|
| 24 | + ucd90910 }; |
---|
36 | 25 | |
---|
37 | 26 | #define UCD9000_MONITOR_CONFIG 0xd5 |
---|
38 | 27 | #define UCD9000_NUM_PAGES 0xd6 |
---|
.. | .. |
---|
52 | 41 | #define UCD9000_GPIO_OUTPUT 1 |
---|
53 | 42 | |
---|
54 | 43 | #define UCD9000_MON_TYPE(x) (((x) >> 5) & 0x07) |
---|
55 | | -#define UCD9000_MON_PAGE(x) ((x) & 0x0f) |
---|
| 44 | +#define UCD9000_MON_PAGE(x) ((x) & 0x1f) |
---|
56 | 45 | |
---|
57 | 46 | #define UCD9000_MON_VOLTAGE 1 |
---|
58 | 47 | #define UCD9000_MON_TEMPERATURE 2 |
---|
.. | .. |
---|
64 | 53 | #define UCD9000_GPIO_NAME_LEN 16 |
---|
65 | 54 | #define UCD9090_NUM_GPIOS 23 |
---|
66 | 55 | #define UCD901XX_NUM_GPIOS 26 |
---|
| 56 | +#define UCD90320_NUM_GPIOS 84 |
---|
67 | 57 | #define UCD90910_NUM_GPIOS 26 |
---|
68 | 58 | |
---|
69 | 59 | #define UCD9000_DEBUGFS_NAME_LEN 24 |
---|
70 | 60 | #define UCD9000_GPI_COUNT 8 |
---|
| 61 | +#define UCD90320_GPI_COUNT 32 |
---|
71 | 62 | |
---|
72 | 63 | struct ucd9000_data { |
---|
73 | 64 | u8 fan_data[UCD9000_NUM_FAN][I2C_SMBUS_BLOCK_MAX]; |
---|
.. | .. |
---|
76 | 67 | struct gpio_chip gpio; |
---|
77 | 68 | #endif |
---|
78 | 69 | struct dentry *debugfs; |
---|
| 70 | + ktime_t write_time; |
---|
79 | 71 | }; |
---|
80 | 72 | #define to_ucd9000_data(_info) container_of(_info, struct ucd9000_data, info) |
---|
81 | 73 | |
---|
.. | .. |
---|
83 | 75 | struct i2c_client *client; |
---|
84 | 76 | u8 index; |
---|
85 | 77 | }; |
---|
| 78 | + |
---|
| 79 | +/* |
---|
| 80 | + * It has been observed that the UCD90320 randomly fails register access when |
---|
| 81 | + * doing another access right on the back of a register write. To mitigate this |
---|
| 82 | + * make sure that there is a minimum delay between a write access and the |
---|
| 83 | + * following access. The 250us is based on experimental data. At a delay of |
---|
| 84 | + * 200us the issue seems to go away. Add a bit of extra margin to allow for |
---|
| 85 | + * system to system differences. |
---|
| 86 | + */ |
---|
| 87 | +#define UCD90320_WAIT_DELAY_US 250 |
---|
| 88 | + |
---|
| 89 | +static inline void ucd90320_wait(const struct ucd9000_data *data) |
---|
| 90 | +{ |
---|
| 91 | + s64 delta = ktime_us_delta(ktime_get(), data->write_time); |
---|
| 92 | + |
---|
| 93 | + if (delta < UCD90320_WAIT_DELAY_US) |
---|
| 94 | + udelay(UCD90320_WAIT_DELAY_US - delta); |
---|
| 95 | +} |
---|
| 96 | + |
---|
| 97 | +static int ucd90320_read_word_data(struct i2c_client *client, int page, |
---|
| 98 | + int phase, int reg) |
---|
| 99 | +{ |
---|
| 100 | + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); |
---|
| 101 | + struct ucd9000_data *data = to_ucd9000_data(info); |
---|
| 102 | + |
---|
| 103 | + if (reg >= PMBUS_VIRT_BASE) |
---|
| 104 | + return -ENXIO; |
---|
| 105 | + |
---|
| 106 | + ucd90320_wait(data); |
---|
| 107 | + return pmbus_read_word_data(client, page, phase, reg); |
---|
| 108 | +} |
---|
| 109 | + |
---|
| 110 | +static int ucd90320_read_byte_data(struct i2c_client *client, int page, int reg) |
---|
| 111 | +{ |
---|
| 112 | + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); |
---|
| 113 | + struct ucd9000_data *data = to_ucd9000_data(info); |
---|
| 114 | + |
---|
| 115 | + ucd90320_wait(data); |
---|
| 116 | + return pmbus_read_byte_data(client, page, reg); |
---|
| 117 | +} |
---|
| 118 | + |
---|
| 119 | +static int ucd90320_write_word_data(struct i2c_client *client, int page, |
---|
| 120 | + int reg, u16 word) |
---|
| 121 | +{ |
---|
| 122 | + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); |
---|
| 123 | + struct ucd9000_data *data = to_ucd9000_data(info); |
---|
| 124 | + int ret; |
---|
| 125 | + |
---|
| 126 | + ucd90320_wait(data); |
---|
| 127 | + ret = pmbus_write_word_data(client, page, reg, word); |
---|
| 128 | + data->write_time = ktime_get(); |
---|
| 129 | + |
---|
| 130 | + return ret; |
---|
| 131 | +} |
---|
| 132 | + |
---|
| 133 | +static int ucd90320_write_byte(struct i2c_client *client, int page, u8 value) |
---|
| 134 | +{ |
---|
| 135 | + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); |
---|
| 136 | + struct ucd9000_data *data = to_ucd9000_data(info); |
---|
| 137 | + int ret; |
---|
| 138 | + |
---|
| 139 | + ucd90320_wait(data); |
---|
| 140 | + ret = pmbus_write_byte(client, page, value); |
---|
| 141 | + data->write_time = ktime_get(); |
---|
| 142 | + |
---|
| 143 | + return ret; |
---|
| 144 | +} |
---|
86 | 145 | |
---|
87 | 146 | static int ucd9000_get_fan_config(struct i2c_client *client, int fan) |
---|
88 | 147 | { |
---|
.. | .. |
---|
145 | 204 | {"ucd90120", ucd90120}, |
---|
146 | 205 | {"ucd90124", ucd90124}, |
---|
147 | 206 | {"ucd90160", ucd90160}, |
---|
| 207 | + {"ucd90320", ucd90320}, |
---|
148 | 208 | {"ucd9090", ucd9090}, |
---|
149 | 209 | {"ucd90910", ucd90910}, |
---|
150 | 210 | {} |
---|
151 | 211 | }; |
---|
152 | 212 | MODULE_DEVICE_TABLE(i2c, ucd9000_id); |
---|
153 | 213 | |
---|
154 | | -static const struct of_device_id ucd9000_of_match[] = { |
---|
| 214 | +static const struct of_device_id __maybe_unused ucd9000_of_match[] = { |
---|
155 | 215 | { |
---|
156 | 216 | .compatible = "ti,ucd9000", |
---|
157 | 217 | .data = (void *)ucd9000 |
---|
.. | .. |
---|
167 | 227 | { |
---|
168 | 228 | .compatible = "ti,ucd90160", |
---|
169 | 229 | .data = (void *)ucd90160 |
---|
| 230 | + }, |
---|
| 231 | + { |
---|
| 232 | + .compatible = "ti,ucd90320", |
---|
| 233 | + .data = (void *)ucd90320 |
---|
170 | 234 | }, |
---|
171 | 235 | { |
---|
172 | 236 | .compatible = "ti,ucd9090", |
---|
.. | .. |
---|
336 | 400 | case ucd90160: |
---|
337 | 401 | data->gpio.ngpio = UCD901XX_NUM_GPIOS; |
---|
338 | 402 | break; |
---|
| 403 | + case ucd90320: |
---|
| 404 | + data->gpio.ngpio = UCD90320_NUM_GPIOS; |
---|
| 405 | + break; |
---|
339 | 406 | case ucd90910: |
---|
340 | 407 | data->gpio.ngpio = UCD90910_NUM_GPIOS; |
---|
341 | 408 | break; |
---|
.. | .. |
---|
373 | 440 | #ifdef CONFIG_DEBUG_FS |
---|
374 | 441 | static int ucd9000_get_mfr_status(struct i2c_client *client, u8 *buffer) |
---|
375 | 442 | { |
---|
376 | | - int ret = pmbus_set_page(client, 0); |
---|
| 443 | + int ret = pmbus_set_page(client, 0, 0xff); |
---|
377 | 444 | |
---|
378 | 445 | if (ret < 0) |
---|
379 | 446 | return ret; |
---|
.. | .. |
---|
386 | 453 | struct ucd9000_debugfs_entry *entry = data; |
---|
387 | 454 | struct i2c_client *client = entry->client; |
---|
388 | 455 | u8 buffer[I2C_SMBUS_BLOCK_MAX]; |
---|
389 | | - int ret; |
---|
| 456 | + int ret, i; |
---|
390 | 457 | |
---|
391 | 458 | ret = ucd9000_get_mfr_status(client, buffer); |
---|
392 | 459 | if (ret < 0) |
---|
393 | 460 | return ret; |
---|
394 | 461 | |
---|
395 | 462 | /* |
---|
396 | | - * Attribute only created for devices with gpi fault bits at bits |
---|
397 | | - * 16-23, which is the second byte of the response. |
---|
| 463 | + * GPI fault bits are in sets of 8, two bytes from end of response. |
---|
398 | 464 | */ |
---|
399 | | - *val = !!(buffer[1] & BIT(entry->index)); |
---|
| 465 | + i = ret - 3 - entry->index / 8; |
---|
| 466 | + if (i >= 0) |
---|
| 467 | + *val = !!(buffer[i] & BIT(entry->index % 8)); |
---|
400 | 468 | |
---|
401 | 469 | return 0; |
---|
402 | 470 | } |
---|
.. | .. |
---|
436 | 504 | { |
---|
437 | 505 | struct dentry *debugfs; |
---|
438 | 506 | struct ucd9000_debugfs_entry *entries; |
---|
439 | | - int i; |
---|
| 507 | + int i, gpi_count; |
---|
440 | 508 | char name[UCD9000_DEBUGFS_NAME_LEN]; |
---|
441 | 509 | |
---|
442 | 510 | debugfs = pmbus_get_debugfs_dir(client); |
---|
.. | .. |
---|
449 | 517 | |
---|
450 | 518 | /* |
---|
451 | 519 | * Of the chips this driver supports, only the UCD9090, UCD90160, |
---|
452 | | - * and UCD90910 report GPI faults in their MFR_STATUS register, so only |
---|
453 | | - * create the GPI fault debugfs attributes for those chips. |
---|
| 520 | + * UCD90320, and UCD90910 report GPI faults in their MFR_STATUS |
---|
| 521 | + * register, so only create the GPI fault debugfs attributes for those |
---|
| 522 | + * chips. |
---|
454 | 523 | */ |
---|
455 | 524 | if (mid->driver_data == ucd9090 || mid->driver_data == ucd90160 || |
---|
456 | | - mid->driver_data == ucd90910) { |
---|
| 525 | + mid->driver_data == ucd90320 || mid->driver_data == ucd90910) { |
---|
| 526 | + gpi_count = mid->driver_data == ucd90320 ? UCD90320_GPI_COUNT |
---|
| 527 | + : UCD9000_GPI_COUNT; |
---|
457 | 528 | entries = devm_kcalloc(&client->dev, |
---|
458 | | - UCD9000_GPI_COUNT, sizeof(*entries), |
---|
| 529 | + gpi_count, sizeof(*entries), |
---|
459 | 530 | GFP_KERNEL); |
---|
460 | 531 | if (!entries) |
---|
461 | 532 | return -ENOMEM; |
---|
462 | 533 | |
---|
463 | | - for (i = 0; i < UCD9000_GPI_COUNT; i++) { |
---|
| 534 | + for (i = 0; i < gpi_count; i++) { |
---|
464 | 535 | entries[i].client = client; |
---|
465 | 536 | entries[i].index = i; |
---|
466 | 537 | scnprintf(name, UCD9000_DEBUGFS_NAME_LEN, |
---|
.. | .. |
---|
486 | 557 | } |
---|
487 | 558 | #endif /* CONFIG_DEBUG_FS */ |
---|
488 | 559 | |
---|
489 | | -static int ucd9000_probe(struct i2c_client *client, |
---|
490 | | - const struct i2c_device_id *id) |
---|
| 560 | +static int ucd9000_probe(struct i2c_client *client) |
---|
491 | 561 | { |
---|
492 | 562 | u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1]; |
---|
493 | 563 | struct ucd9000_data *data; |
---|
.. | .. |
---|
522 | 592 | if (client->dev.of_node) |
---|
523 | 593 | chip = (enum chips)of_device_get_match_data(&client->dev); |
---|
524 | 594 | else |
---|
525 | | - chip = id->driver_data; |
---|
| 595 | + chip = mid->driver_data; |
---|
526 | 596 | |
---|
527 | | - if (chip != ucd9000 && chip != mid->driver_data) |
---|
| 597 | + if (chip != ucd9000 && strcmp(client->name, mid->name) != 0) |
---|
528 | 598 | dev_notice(&client->dev, |
---|
529 | 599 | "Device mismatch: Configured %s, detected %s\n", |
---|
530 | | - id->name, mid->name); |
---|
| 600 | + client->name, mid->name); |
---|
531 | 601 | |
---|
532 | 602 | data = devm_kzalloc(&client->dev, sizeof(struct ucd9000_data), |
---|
533 | 603 | GFP_KERNEL); |
---|
.. | .. |
---|
598 | 668 | info->read_byte_data = ucd9000_read_byte_data; |
---|
599 | 669 | info->func[0] |= PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12 |
---|
600 | 670 | | PMBUS_HAVE_FAN34 | PMBUS_HAVE_STATUS_FAN34; |
---|
| 671 | + } else if (mid->driver_data == ucd90320) { |
---|
| 672 | + info->read_byte_data = ucd90320_read_byte_data; |
---|
| 673 | + info->read_word_data = ucd90320_read_word_data; |
---|
| 674 | + info->write_byte = ucd90320_write_byte; |
---|
| 675 | + info->write_word_data = ucd90320_write_word_data; |
---|
601 | 676 | } |
---|
602 | 677 | |
---|
603 | 678 | ucd9000_probe_gpio(client, mid, data); |
---|
604 | 679 | |
---|
605 | | - ret = pmbus_do_probe(client, mid, info); |
---|
| 680 | + ret = pmbus_do_probe(client, info); |
---|
606 | 681 | if (ret) |
---|
607 | 682 | return ret; |
---|
608 | 683 | |
---|
.. | .. |
---|
620 | 695 | .name = "ucd9000", |
---|
621 | 696 | .of_match_table = of_match_ptr(ucd9000_of_match), |
---|
622 | 697 | }, |
---|
623 | | - .probe = ucd9000_probe, |
---|
| 698 | + .probe_new = ucd9000_probe, |
---|
624 | 699 | .remove = pmbus_do_remove, |
---|
625 | 700 | .id_table = ucd9000_id, |
---|
626 | 701 | }; |
---|