1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Hardware monitoring driver for ucd9200 series Digital PWM System Controllers |
4 | * |
5 | * Copyright (C) 2011 Ericsson AB. |
6 | */ |
7 | |
8 | #include <linux/kernel.h> |
9 | #include <linux/module.h> |
10 | #include <linux/of.h> |
11 | #include <linux/init.h> |
12 | #include <linux/err.h> |
13 | #include <linux/slab.h> |
14 | #include <linux/i2c.h> |
15 | #include <linux/pmbus.h> |
16 | #include "pmbus.h" |
17 | |
18 | #define UCD9200_PHASE_INFO 0xd2 |
19 | #define UCD9200_DEVICE_ID 0xfd |
20 | |
21 | enum chips { ucd9200, ucd9220, ucd9222, ucd9224, ucd9240, ucd9244, ucd9246, |
22 | ucd9248 }; |
23 | |
24 | static const struct i2c_device_id ucd9200_id[] = { |
25 | {"ucd9200" , ucd9200}, |
26 | {"ucd9220" , ucd9220}, |
27 | {"ucd9222" , ucd9222}, |
28 | {"ucd9224" , ucd9224}, |
29 | {"ucd9240" , ucd9240}, |
30 | {"ucd9244" , ucd9244}, |
31 | {"ucd9246" , ucd9246}, |
32 | {"ucd9248" , ucd9248}, |
33 | {} |
34 | }; |
35 | MODULE_DEVICE_TABLE(i2c, ucd9200_id); |
36 | |
37 | static const struct of_device_id __maybe_unused ucd9200_of_match[] = { |
38 | { |
39 | .compatible = "ti,cd9200" , |
40 | .data = (void *)ucd9200 |
41 | }, |
42 | { |
43 | .compatible = "ti,cd9220" , |
44 | .data = (void *)ucd9220 |
45 | }, |
46 | { |
47 | .compatible = "ti,cd9222" , |
48 | .data = (void *)ucd9222 |
49 | }, |
50 | { |
51 | .compatible = "ti,cd9224" , |
52 | .data = (void *)ucd9224 |
53 | }, |
54 | { |
55 | .compatible = "ti,cd9240" , |
56 | .data = (void *)ucd9240 |
57 | }, |
58 | { |
59 | .compatible = "ti,cd9244" , |
60 | .data = (void *)ucd9244 |
61 | }, |
62 | { |
63 | .compatible = "ti,cd9246" , |
64 | .data = (void *)ucd9246 |
65 | }, |
66 | { |
67 | .compatible = "ti,cd9248" , |
68 | .data = (void *)ucd9248 |
69 | }, |
70 | { }, |
71 | }; |
72 | MODULE_DEVICE_TABLE(of, ucd9200_of_match); |
73 | |
74 | static int ucd9200_probe(struct i2c_client *client) |
75 | { |
76 | u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1]; |
77 | struct pmbus_driver_info *info; |
78 | const struct i2c_device_id *mid; |
79 | enum chips chip; |
80 | int i, j, ret; |
81 | |
82 | if (!i2c_check_functionality(adap: client->adapter, |
83 | I2C_FUNC_SMBUS_BYTE_DATA | |
84 | I2C_FUNC_SMBUS_BLOCK_DATA)) |
85 | return -ENODEV; |
86 | |
87 | ret = i2c_smbus_read_block_data(client, UCD9200_DEVICE_ID, |
88 | values: block_buffer); |
89 | if (ret < 0) { |
90 | dev_err(&client->dev, "Failed to read device ID\n" ); |
91 | return ret; |
92 | } |
93 | block_buffer[ret] = '\0'; |
94 | dev_info(&client->dev, "Device ID %s\n" , block_buffer); |
95 | |
96 | for (mid = ucd9200_id; mid->name[0]; mid++) { |
97 | if (!strncasecmp(s1: mid->name, s2: block_buffer, strlen(mid->name))) |
98 | break; |
99 | } |
100 | if (!mid->name[0]) { |
101 | dev_err(&client->dev, "Unsupported device\n" ); |
102 | return -ENODEV; |
103 | } |
104 | |
105 | if (client->dev.of_node) |
106 | chip = (uintptr_t)of_device_get_match_data(dev: &client->dev); |
107 | else |
108 | chip = mid->driver_data; |
109 | |
110 | if (chip != ucd9200 && strcmp(client->name, mid->name) != 0) |
111 | dev_notice(&client->dev, |
112 | "Device mismatch: Configured %s, detected %s\n" , |
113 | client->name, mid->name); |
114 | |
115 | info = devm_kzalloc(dev: &client->dev, size: sizeof(struct pmbus_driver_info), |
116 | GFP_KERNEL); |
117 | if (!info) |
118 | return -ENOMEM; |
119 | |
120 | ret = i2c_smbus_read_block_data(client, UCD9200_PHASE_INFO, |
121 | values: block_buffer); |
122 | if (ret < 0) { |
123 | dev_err(&client->dev, "Failed to read phase information\n" ); |
124 | return ret; |
125 | } |
126 | |
127 | /* |
128 | * Calculate number of configured pages (rails) from PHASE_INFO |
129 | * register. |
130 | * Rails have to be sequential, so we can abort after finding |
131 | * the first unconfigured rail. |
132 | */ |
133 | info->pages = 0; |
134 | for (i = 0; i < ret; i++) { |
135 | if (!block_buffer[i]) |
136 | break; |
137 | info->pages++; |
138 | } |
139 | if (!info->pages) { |
140 | dev_err(&client->dev, "No rails configured\n" ); |
141 | return -ENODEV; |
142 | } |
143 | dev_info(&client->dev, "%d rails configured\n" , info->pages); |
144 | |
145 | /* |
146 | * Set PHASE registers on all pages to 0xff to ensure that phase |
147 | * specific commands will apply to all phases of a given page (rail). |
148 | * This only affects the READ_IOUT and READ_TEMPERATURE2 registers. |
149 | * READ_IOUT will return the sum of currents of all phases of a rail, |
150 | * and READ_TEMPERATURE2 will return the maximum temperature detected |
151 | * for the phases of the rail. |
152 | */ |
153 | for (i = 0; i < info->pages; i++) { |
154 | /* |
155 | * Setting PAGE & PHASE fails once in a while for no obvious |
156 | * reason, so we need to retry a couple of times. |
157 | */ |
158 | for (j = 0; j < 3; j++) { |
159 | ret = i2c_smbus_write_byte_data(client, command: PMBUS_PAGE, value: i); |
160 | if (ret < 0) |
161 | continue; |
162 | ret = i2c_smbus_write_byte_data(client, command: PMBUS_PHASE, |
163 | value: 0xff); |
164 | if (ret < 0) |
165 | continue; |
166 | break; |
167 | } |
168 | if (ret < 0) { |
169 | dev_err(&client->dev, |
170 | "Failed to initialize PHASE registers\n" ); |
171 | return ret; |
172 | } |
173 | } |
174 | if (info->pages > 1) |
175 | i2c_smbus_write_byte_data(client, command: PMBUS_PAGE, value: 0); |
176 | |
177 | info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT | |
178 | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | |
179 | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | |
180 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | |
181 | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP | |
182 | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP; |
183 | |
184 | for (i = 1; i < info->pages; i++) |
185 | info->func[i] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | |
186 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | |
187 | PMBUS_HAVE_POUT | |
188 | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP; |
189 | |
190 | /* ucd9240 supports a single fan */ |
191 | if (mid->driver_data == ucd9240) |
192 | info->func[0] |= PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12; |
193 | |
194 | return pmbus_do_probe(client, info); |
195 | } |
196 | |
197 | /* This is the driver that will be inserted */ |
198 | static struct i2c_driver ucd9200_driver = { |
199 | .driver = { |
200 | .name = "ucd9200" , |
201 | .of_match_table = of_match_ptr(ucd9200_of_match), |
202 | }, |
203 | .probe = ucd9200_probe, |
204 | .id_table = ucd9200_id, |
205 | }; |
206 | |
207 | module_i2c_driver(ucd9200_driver); |
208 | |
209 | MODULE_AUTHOR("Guenter Roeck" ); |
210 | MODULE_DESCRIPTION("PMBus driver for TI UCD922x, UCD924x" ); |
211 | MODULE_LICENSE("GPL" ); |
212 | MODULE_IMPORT_NS(PMBUS); |
213 | |