Commit | Line | Data |
---|---|---|
c942fddf | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
83f7649c GR |
2 | /* |
3 | * Hardware monitoring driver for Analog Devices ADM1275 Hot-Swap Controller | |
4 | * and Digital Power Monitor | |
5 | * | |
6 | * Copyright (c) 2011 Ericsson AB. | |
4ff0ce22 | 7 | * Copyright (c) 2018 Guenter Roeck |
83f7649c GR |
8 | */ |
9 | ||
10 | #include <linux/kernel.h> | |
11 | #include <linux/module.h> | |
12 | #include <linux/init.h> | |
13 | #include <linux/err.h> | |
14 | #include <linux/slab.h> | |
15 | #include <linux/i2c.h> | |
99b41608 | 16 | #include <linux/bitops.h> |
c83529c1 AKNPW |
17 | #include <linux/bitfield.h> |
18 | #include <linux/log2.h> | |
83f7649c GR |
19 | #include "pmbus.h" |
20 | ||
91630090 | 21 | enum chips { adm1075, adm1272, adm1275, adm1276, adm1278, adm1281, adm1293, adm1294 }; |
68a40382 GR |
22 | |
23 | #define ADM1275_MFR_STATUS_IOUT_WARN2 BIT(0) | |
24 | #define ADM1293_MFR_STATUS_VAUX_UV_WARN BIT(5) | |
25 | #define ADM1293_MFR_STATUS_VAUX_OV_WARN BIT(6) | |
5cf231a3 | 26 | |
c576e30c GR |
27 | #define ADM1275_PEAK_IOUT 0xd0 |
28 | #define ADM1275_PEAK_VIN 0xd1 | |
29 | #define ADM1275_PEAK_VOUT 0xd2 | |
dd5219ce | 30 | #define ADM1275_PMON_CONTROL 0xd3 |
83f7649c GR |
31 | #define ADM1275_PMON_CONFIG 0xd4 |
32 | ||
dd5219ce GR |
33 | #define ADM1275_CONVERT_EN BIT(0) |
34 | ||
99b41608 GR |
35 | #define ADM1275_VIN_VOUT_SELECT BIT(6) |
36 | #define ADM1275_VRANGE BIT(5) | |
37 | #define ADM1075_IRANGE_50 BIT(4) | |
38 | #define ADM1075_IRANGE_25 BIT(3) | |
39 | #define ADM1075_IRANGE_MASK (BIT(3) | BIT(4)) | |
83f7649c | 40 | |
4ff0ce22 GR |
41 | #define ADM1272_IRANGE BIT(0) |
42 | ||
b153a0bb | 43 | #define ADM1278_TSFILT BIT(15) |
709066ac GR |
44 | #define ADM1278_TEMP1_EN BIT(3) |
45 | #define ADM1278_VIN_EN BIT(2) | |
46 | #define ADM1278_VOUT_EN BIT(1) | |
47 | ||
b153a0bb GR |
48 | #define ADM1278_PMON_DEFCONFIG (ADM1278_VOUT_EN | ADM1278_TEMP1_EN | ADM1278_TSFILT) |
49 | ||
68a40382 GR |
50 | #define ADM1293_IRANGE_25 0 |
51 | #define ADM1293_IRANGE_50 BIT(6) | |
52 | #define ADM1293_IRANGE_100 BIT(7) | |
53 | #define ADM1293_IRANGE_200 (BIT(6) | BIT(7)) | |
54 | #define ADM1293_IRANGE_MASK (BIT(6) | BIT(7)) | |
55 | ||
56 | #define ADM1293_VIN_SEL_012 BIT(2) | |
57 | #define ADM1293_VIN_SEL_074 BIT(3) | |
58 | #define ADM1293_VIN_SEL_210 (BIT(2) | BIT(3)) | |
59 | #define ADM1293_VIN_SEL_MASK (BIT(2) | BIT(3)) | |
60 | ||
61 | #define ADM1293_VAUX_EN BIT(1) | |
62 | ||
709066ac | 63 | #define ADM1278_PEAK_TEMP 0xd7 |
c5e67636 GR |
64 | #define ADM1275_IOUT_WARN2_LIMIT 0xd7 |
65 | #define ADM1275_DEVICE_CONFIG 0xd8 | |
66 | ||
99b41608 | 67 | #define ADM1275_IOUT_WARN2_SELECT BIT(4) |
c5e67636 | 68 | |
5cf231a3 | 69 | #define ADM1276_PEAK_PIN 0xda |
92711269 GR |
70 | #define ADM1075_READ_VAUX 0xdd |
71 | #define ADM1075_VAUX_OV_WARN_LIMIT 0xde | |
72 | #define ADM1075_VAUX_UV_WARN_LIMIT 0xdf | |
68a40382 GR |
73 | #define ADM1293_IOUT_MIN 0xe3 |
74 | #define ADM1293_PIN_MIN 0xe4 | |
92711269 GR |
75 | #define ADM1075_VAUX_STATUS 0xf6 |
76 | ||
99b41608 GR |
77 | #define ADM1075_VAUX_OV_WARN BIT(7) |
78 | #define ADM1075_VAUX_UV_WARN BIT(6) | |
92711269 | 79 | |
7d45deb3 GR |
80 | #define ADM1275_VI_AVG_SHIFT 0 |
81 | #define ADM1275_VI_AVG_MASK GENMASK(ADM1275_VI_AVG_SHIFT + 2, \ | |
82 | ADM1275_VI_AVG_SHIFT) | |
83 | #define ADM1275_SAMPLES_AVG_MAX 128 | |
84 | ||
85 | #define ADM1278_PWR_AVG_SHIFT 11 | |
86 | #define ADM1278_PWR_AVG_MASK GENMASK(ADM1278_PWR_AVG_SHIFT + 2, \ | |
87 | ADM1278_PWR_AVG_SHIFT) | |
88 | #define ADM1278_VI_AVG_SHIFT 8 | |
89 | #define ADM1278_VI_AVG_MASK GENMASK(ADM1278_VI_AVG_SHIFT + 2, \ | |
90 | ADM1278_VI_AVG_SHIFT) | |
c83529c1 | 91 | |
c5e67636 | 92 | struct adm1275_data { |
5cf231a3 | 93 | int id; |
c5e67636 | 94 | bool have_oc_fault; |
9048539b GR |
95 | bool have_uc_fault; |
96 | bool have_vout; | |
97 | bool have_vaux_status; | |
68a40382 GR |
98 | bool have_mfr_vaux_status; |
99 | bool have_iout_min; | |
100 | bool have_pin_min; | |
9048539b | 101 | bool have_pin_max; |
709066ac | 102 | bool have_temp_max; |
7d45deb3 | 103 | bool have_power_sampling; |
c5e67636 GR |
104 | struct pmbus_driver_info info; |
105 | }; | |
106 | ||
107 | #define to_adm1275_data(x) container_of(x, struct adm1275_data, info) | |
108 | ||
904b296f GR |
109 | struct coefficients { |
110 | s16 m; | |
111 | s16 b; | |
112 | s16 R; | |
113 | }; | |
114 | ||
115 | static const struct coefficients adm1075_coefficients[] = { | |
116 | [0] = { 27169, 0, -1 }, /* voltage */ | |
117 | [1] = { 806, 20475, -1 }, /* current, irange25 */ | |
118 | [2] = { 404, 20475, -1 }, /* current, irange50 */ | |
6faecba0 SD |
119 | [3] = { 8549, 0, -1 }, /* power, irange25 */ |
120 | [4] = { 4279, 0, -1 }, /* power, irange50 */ | |
904b296f GR |
121 | }; |
122 | ||
4ff0ce22 GR |
123 | static const struct coefficients adm1272_coefficients[] = { |
124 | [0] = { 6770, 0, -2 }, /* voltage, vrange 60V */ | |
125 | [1] = { 4062, 0, -2 }, /* voltage, vrange 100V */ | |
126 | [2] = { 1326, 20480, -1 }, /* current, vsense range 15mV */ | |
127 | [3] = { 663, 20480, -1 }, /* current, vsense range 30mV */ | |
128 | [4] = { 3512, 0, -2 }, /* power, vrange 60V, irange 15mV */ | |
129 | [5] = { 21071, 0, -3 }, /* power, vrange 100V, irange 15mV */ | |
130 | [6] = { 17561, 0, -3 }, /* power, vrange 60V, irange 30mV */ | |
131 | [7] = { 10535, 0, -3 }, /* power, vrange 100V, irange 30mV */ | |
132 | [8] = { 42, 31871, -1 }, /* temperature */ | |
133 | ||
134 | }; | |
135 | ||
904b296f GR |
136 | static const struct coefficients adm1275_coefficients[] = { |
137 | [0] = { 19199, 0, -2 }, /* voltage, vrange set */ | |
138 | [1] = { 6720, 0, -1 }, /* voltage, vrange not set */ | |
139 | [2] = { 807, 20475, -1 }, /* current */ | |
140 | }; | |
141 | ||
142 | static const struct coefficients adm1276_coefficients[] = { | |
143 | [0] = { 19199, 0, -2 }, /* voltage, vrange set */ | |
144 | [1] = { 6720, 0, -1 }, /* voltage, vrange not set */ | |
145 | [2] = { 807, 20475, -1 }, /* current */ | |
146 | [3] = { 6043, 0, -2 }, /* power, vrange set */ | |
147 | [4] = { 2115, 0, -1 }, /* power, vrange not set */ | |
148 | }; | |
149 | ||
709066ac GR |
150 | static const struct coefficients adm1278_coefficients[] = { |
151 | [0] = { 19599, 0, -2 }, /* voltage */ | |
152 | [1] = { 800, 20475, -1 }, /* current */ | |
153 | [2] = { 6123, 0, -2 }, /* power */ | |
154 | [3] = { 42, 31880, -1 }, /* temperature */ | |
155 | }; | |
156 | ||
68a40382 GR |
157 | static const struct coefficients adm1293_coefficients[] = { |
158 | [0] = { 3333, -1, 0 }, /* voltage, vrange 1.2V */ | |
159 | [1] = { 5552, -5, -1 }, /* voltage, vrange 7.4V */ | |
160 | [2] = { 19604, -50, -2 }, /* voltage, vrange 21V */ | |
161 | [3] = { 8000, -100, -2 }, /* current, irange25 */ | |
162 | [4] = { 4000, -100, -2 }, /* current, irange50 */ | |
163 | [5] = { 20000, -1000, -3 }, /* current, irange100 */ | |
164 | [6] = { 10000, -1000, -3 }, /* current, irange200 */ | |
165 | [7] = { 10417, 0, -1 }, /* power, 1.2V, irange25 */ | |
166 | [8] = { 5208, 0, -1 }, /* power, 1.2V, irange50 */ | |
167 | [9] = { 26042, 0, -2 }, /* power, 1.2V, irange100 */ | |
168 | [10] = { 13021, 0, -2 }, /* power, 1.2V, irange200 */ | |
169 | [11] = { 17351, 0, -2 }, /* power, 7.4V, irange25 */ | |
170 | [12] = { 8676, 0, -2 }, /* power, 7.4V, irange50 */ | |
171 | [13] = { 4338, 0, -2 }, /* power, 7.4V, irange100 */ | |
172 | [14] = { 21689, 0, -3 }, /* power, 7.4V, irange200 */ | |
173 | [15] = { 6126, 0, -2 }, /* power, 21V, irange25 */ | |
174 | [16] = { 30631, 0, -3 }, /* power, 21V, irange50 */ | |
175 | [17] = { 15316, 0, -3 }, /* power, 21V, irange100 */ | |
176 | [18] = { 7658, 0, -3 }, /* power, 21V, irange200 */ | |
177 | }; | |
178 | ||
98ac8af4 GR |
179 | static int adm1275_read_samples(const struct adm1275_data *data, |
180 | struct i2c_client *client, bool is_power) | |
c83529c1 | 181 | { |
7d45deb3 GR |
182 | int shift, ret; |
183 | u16 mask; | |
184 | ||
185 | /* | |
186 | * The PMON configuration register is a 16-bit register only on chips | |
187 | * supporting power average sampling. On other chips it is an 8-bit | |
188 | * register. | |
189 | */ | |
190 | if (data->have_power_sampling) { | |
191 | ret = i2c_smbus_read_word_data(client, ADM1275_PMON_CONFIG); | |
192 | mask = is_power ? ADM1278_PWR_AVG_MASK : ADM1278_VI_AVG_MASK; | |
193 | shift = is_power ? ADM1278_PWR_AVG_SHIFT : ADM1278_VI_AVG_SHIFT; | |
194 | } else { | |
195 | ret = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG); | |
196 | mask = ADM1275_VI_AVG_MASK; | |
197 | shift = ADM1275_VI_AVG_SHIFT; | |
198 | } | |
c83529c1 AKNPW |
199 | if (ret < 0) |
200 | return ret; | |
201 | ||
7d45deb3 | 202 | return (ret & mask) >> shift; |
c83529c1 AKNPW |
203 | } |
204 | ||
7d45deb3 | 205 | static int adm1275_write_pmon_config(const struct adm1275_data *data, |
98ac8af4 GR |
206 | struct i2c_client *client, u16 word) |
207 | { | |
dd5219ce GR |
208 | int ret, ret2; |
209 | ||
210 | ret = i2c_smbus_write_byte_data(client, ADM1275_PMON_CONTROL, 0); | |
211 | if (ret) | |
212 | return ret; | |
98ac8af4 GR |
213 | |
214 | if (data->have_power_sampling) | |
215 | ret = i2c_smbus_write_word_data(client, ADM1275_PMON_CONFIG, | |
216 | word); | |
217 | else | |
218 | ret = i2c_smbus_write_byte_data(client, ADM1275_PMON_CONFIG, | |
219 | word); | |
220 | ||
dd5219ce GR |
221 | /* |
222 | * We still want to re-enable conversions if writing into | |
223 | * ADM1275_PMON_CONFIG failed. | |
224 | */ | |
225 | ret2 = i2c_smbus_write_byte_data(client, ADM1275_PMON_CONTROL, | |
226 | ADM1275_CONVERT_EN); | |
227 | if (!ret) | |
228 | ret = ret2; | |
229 | ||
98ac8af4 GR |
230 | return ret; |
231 | } | |
232 | ||
233 | static int adm1275_write_samples(const struct adm1275_data *data, | |
234 | struct i2c_client *client, | |
235 | bool is_power, u16 word) | |
c83529c1 | 236 | { |
7d45deb3 GR |
237 | int shift, ret; |
238 | u16 mask; | |
239 | ||
240 | if (data->have_power_sampling) { | |
241 | ret = i2c_smbus_read_word_data(client, ADM1275_PMON_CONFIG); | |
242 | mask = is_power ? ADM1278_PWR_AVG_MASK : ADM1278_VI_AVG_MASK; | |
243 | shift = is_power ? ADM1278_PWR_AVG_SHIFT : ADM1278_VI_AVG_SHIFT; | |
244 | } else { | |
245 | ret = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG); | |
246 | mask = ADM1275_VI_AVG_MASK; | |
247 | shift = ADM1275_VI_AVG_SHIFT; | |
248 | } | |
c83529c1 AKNPW |
249 | if (ret < 0) |
250 | return ret; | |
251 | ||
7d45deb3 | 252 | word = (ret & ~mask) | ((word << shift) & mask); |
c83529c1 | 253 | |
98ac8af4 | 254 | return adm1275_write_pmon_config(data, client, word); |
c83529c1 AKNPW |
255 | } |
256 | ||
43f33b6e GR |
257 | static int adm1275_read_word_data(struct i2c_client *client, int page, |
258 | int phase, int reg) | |
c576e30c | 259 | { |
c5e67636 GR |
260 | const struct pmbus_driver_info *info = pmbus_get_driver_info(client); |
261 | const struct adm1275_data *data = to_adm1275_data(info); | |
5cf231a3 | 262 | int ret = 0; |
c576e30c | 263 | |
ecb29abd | 264 | if (page > 0) |
c5e67636 | 265 | return -ENXIO; |
c576e30c GR |
266 | |
267 | switch (reg) { | |
c5e67636 | 268 | case PMBUS_IOUT_UC_FAULT_LIMIT: |
9048539b GR |
269 | if (!data->have_uc_fault) |
270 | return -ENXIO; | |
43f33b6e GR |
271 | ret = pmbus_read_word_data(client, 0, 0xff, |
272 | ADM1275_IOUT_WARN2_LIMIT); | |
c5e67636 GR |
273 | break; |
274 | case PMBUS_IOUT_OC_FAULT_LIMIT: | |
9048539b GR |
275 | if (!data->have_oc_fault) |
276 | return -ENXIO; | |
43f33b6e GR |
277 | ret = pmbus_read_word_data(client, 0, 0xff, |
278 | ADM1275_IOUT_WARN2_LIMIT); | |
c5e67636 | 279 | break; |
92711269 | 280 | case PMBUS_VOUT_OV_WARN_LIMIT: |
9048539b GR |
281 | if (data->have_vout) |
282 | return -ENODATA; | |
43f33b6e | 283 | ret = pmbus_read_word_data(client, 0, 0xff, |
92711269 GR |
284 | ADM1075_VAUX_OV_WARN_LIMIT); |
285 | break; | |
286 | case PMBUS_VOUT_UV_WARN_LIMIT: | |
9048539b GR |
287 | if (data->have_vout) |
288 | return -ENODATA; | |
43f33b6e | 289 | ret = pmbus_read_word_data(client, 0, 0xff, |
92711269 GR |
290 | ADM1075_VAUX_UV_WARN_LIMIT); |
291 | break; | |
292 | case PMBUS_READ_VOUT: | |
9048539b GR |
293 | if (data->have_vout) |
294 | return -ENODATA; | |
43f33b6e GR |
295 | ret = pmbus_read_word_data(client, 0, 0xff, |
296 | ADM1075_READ_VAUX); | |
92711269 | 297 | break; |
68a40382 GR |
298 | case PMBUS_VIRT_READ_IOUT_MIN: |
299 | if (!data->have_iout_min) | |
300 | return -ENXIO; | |
43f33b6e GR |
301 | ret = pmbus_read_word_data(client, 0, 0xff, |
302 | ADM1293_IOUT_MIN); | |
68a40382 | 303 | break; |
c576e30c | 304 | case PMBUS_VIRT_READ_IOUT_MAX: |
43f33b6e GR |
305 | ret = pmbus_read_word_data(client, 0, 0xff, |
306 | ADM1275_PEAK_IOUT); | |
c576e30c GR |
307 | break; |
308 | case PMBUS_VIRT_READ_VOUT_MAX: | |
43f33b6e GR |
309 | ret = pmbus_read_word_data(client, 0, 0xff, |
310 | ADM1275_PEAK_VOUT); | |
c576e30c GR |
311 | break; |
312 | case PMBUS_VIRT_READ_VIN_MAX: | |
43f33b6e GR |
313 | ret = pmbus_read_word_data(client, 0, 0xff, |
314 | ADM1275_PEAK_VIN); | |
c576e30c | 315 | break; |
68a40382 GR |
316 | case PMBUS_VIRT_READ_PIN_MIN: |
317 | if (!data->have_pin_min) | |
318 | return -ENXIO; | |
43f33b6e GR |
319 | ret = pmbus_read_word_data(client, 0, 0xff, |
320 | ADM1293_PIN_MIN); | |
68a40382 | 321 | break; |
5cf231a3 | 322 | case PMBUS_VIRT_READ_PIN_MAX: |
9048539b GR |
323 | if (!data->have_pin_max) |
324 | return -ENXIO; | |
43f33b6e GR |
325 | ret = pmbus_read_word_data(client, 0, 0xff, |
326 | ADM1276_PEAK_PIN); | |
5cf231a3 | 327 | break; |
709066ac GR |
328 | case PMBUS_VIRT_READ_TEMP_MAX: |
329 | if (!data->have_temp_max) | |
330 | return -ENXIO; | |
43f33b6e GR |
331 | ret = pmbus_read_word_data(client, 0, 0xff, |
332 | ADM1278_PEAK_TEMP); | |
709066ac | 333 | break; |
c576e30c GR |
334 | case PMBUS_VIRT_RESET_IOUT_HISTORY: |
335 | case PMBUS_VIRT_RESET_VOUT_HISTORY: | |
336 | case PMBUS_VIRT_RESET_VIN_HISTORY: | |
5cf231a3 GR |
337 | break; |
338 | case PMBUS_VIRT_RESET_PIN_HISTORY: | |
9048539b GR |
339 | if (!data->have_pin_max) |
340 | return -ENXIO; | |
c576e30c | 341 | break; |
709066ac GR |
342 | case PMBUS_VIRT_RESET_TEMP_HISTORY: |
343 | if (!data->have_temp_max) | |
344 | return -ENXIO; | |
345 | break; | |
c83529c1 | 346 | case PMBUS_VIRT_POWER_SAMPLES: |
7d45deb3 GR |
347 | if (!data->have_power_sampling) |
348 | return -ENXIO; | |
98ac8af4 | 349 | ret = adm1275_read_samples(data, client, true); |
c83529c1 AKNPW |
350 | if (ret < 0) |
351 | break; | |
352 | ret = BIT(ret); | |
353 | break; | |
354 | case PMBUS_VIRT_IN_SAMPLES: | |
355 | case PMBUS_VIRT_CURR_SAMPLES: | |
98ac8af4 | 356 | ret = adm1275_read_samples(data, client, false); |
c83529c1 AKNPW |
357 | if (ret < 0) |
358 | break; | |
359 | ret = BIT(ret); | |
360 | break; | |
c576e30c GR |
361 | default: |
362 | ret = -ENODATA; | |
363 | break; | |
364 | } | |
365 | return ret; | |
366 | } | |
367 | ||
368 | static int adm1275_write_word_data(struct i2c_client *client, int page, int reg, | |
369 | u16 word) | |
370 | { | |
68a40382 GR |
371 | const struct pmbus_driver_info *info = pmbus_get_driver_info(client); |
372 | const struct adm1275_data *data = to_adm1275_data(info); | |
c576e30c GR |
373 | int ret; |
374 | ||
ecb29abd | 375 | if (page > 0) |
c5e67636 | 376 | return -ENXIO; |
c576e30c GR |
377 | |
378 | switch (reg) { | |
c5e67636 GR |
379 | case PMBUS_IOUT_UC_FAULT_LIMIT: |
380 | case PMBUS_IOUT_OC_FAULT_LIMIT: | |
381 | ret = pmbus_write_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT, | |
382 | word); | |
383 | break; | |
c576e30c GR |
384 | case PMBUS_VIRT_RESET_IOUT_HISTORY: |
385 | ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_IOUT, 0); | |
68a40382 GR |
386 | if (!ret && data->have_iout_min) |
387 | ret = pmbus_write_word_data(client, 0, | |
388 | ADM1293_IOUT_MIN, 0); | |
c576e30c GR |
389 | break; |
390 | case PMBUS_VIRT_RESET_VOUT_HISTORY: | |
391 | ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VOUT, 0); | |
392 | break; | |
393 | case PMBUS_VIRT_RESET_VIN_HISTORY: | |
394 | ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VIN, 0); | |
395 | break; | |
5cf231a3 GR |
396 | case PMBUS_VIRT_RESET_PIN_HISTORY: |
397 | ret = pmbus_write_word_data(client, 0, ADM1276_PEAK_PIN, 0); | |
68a40382 GR |
398 | if (!ret && data->have_pin_min) |
399 | ret = pmbus_write_word_data(client, 0, | |
400 | ADM1293_PIN_MIN, 0); | |
5cf231a3 | 401 | break; |
709066ac GR |
402 | case PMBUS_VIRT_RESET_TEMP_HISTORY: |
403 | ret = pmbus_write_word_data(client, 0, ADM1278_PEAK_TEMP, 0); | |
404 | break; | |
c83529c1 | 405 | case PMBUS_VIRT_POWER_SAMPLES: |
7d45deb3 GR |
406 | if (!data->have_power_sampling) |
407 | return -ENXIO; | |
c83529c1 | 408 | word = clamp_val(word, 1, ADM1275_SAMPLES_AVG_MAX); |
98ac8af4 | 409 | ret = adm1275_write_samples(data, client, true, ilog2(word)); |
c83529c1 AKNPW |
410 | break; |
411 | case PMBUS_VIRT_IN_SAMPLES: | |
412 | case PMBUS_VIRT_CURR_SAMPLES: | |
413 | word = clamp_val(word, 1, ADM1275_SAMPLES_AVG_MAX); | |
98ac8af4 | 414 | ret = adm1275_write_samples(data, client, false, ilog2(word)); |
c83529c1 | 415 | break; |
c576e30c GR |
416 | default: |
417 | ret = -ENODATA; | |
418 | break; | |
419 | } | |
420 | return ret; | |
421 | } | |
422 | ||
c5e67636 GR |
423 | static int adm1275_read_byte_data(struct i2c_client *client, int page, int reg) |
424 | { | |
425 | const struct pmbus_driver_info *info = pmbus_get_driver_info(client); | |
426 | const struct adm1275_data *data = to_adm1275_data(info); | |
427 | int mfr_status, ret; | |
428 | ||
da8e48ab | 429 | if (page > 0) |
c5e67636 GR |
430 | return -ENXIO; |
431 | ||
432 | switch (reg) { | |
433 | case PMBUS_STATUS_IOUT: | |
434 | ret = pmbus_read_byte_data(client, page, PMBUS_STATUS_IOUT); | |
435 | if (ret < 0) | |
436 | break; | |
9048539b GR |
437 | if (!data->have_oc_fault && !data->have_uc_fault) |
438 | break; | |
c5e67636 GR |
439 | mfr_status = pmbus_read_byte_data(client, page, |
440 | PMBUS_STATUS_MFR_SPECIFIC); | |
9048539b GR |
441 | if (mfr_status < 0) |
442 | return mfr_status; | |
c5e67636 GR |
443 | if (mfr_status & ADM1275_MFR_STATUS_IOUT_WARN2) { |
444 | ret |= data->have_oc_fault ? | |
445 | PB_IOUT_OC_FAULT : PB_IOUT_UC_FAULT; | |
446 | } | |
447 | break; | |
92711269 | 448 | case PMBUS_STATUS_VOUT: |
9048539b GR |
449 | if (data->have_vout) |
450 | return -ENODATA; | |
92711269 | 451 | ret = 0; |
9048539b GR |
452 | if (data->have_vaux_status) { |
453 | mfr_status = pmbus_read_byte_data(client, 0, | |
454 | ADM1075_VAUX_STATUS); | |
455 | if (mfr_status < 0) | |
456 | return mfr_status; | |
457 | if (mfr_status & ADM1075_VAUX_OV_WARN) | |
458 | ret |= PB_VOLTAGE_OV_WARNING; | |
459 | if (mfr_status & ADM1075_VAUX_UV_WARN) | |
460 | ret |= PB_VOLTAGE_UV_WARNING; | |
68a40382 GR |
461 | } else if (data->have_mfr_vaux_status) { |
462 | mfr_status = pmbus_read_byte_data(client, page, | |
463 | PMBUS_STATUS_MFR_SPECIFIC); | |
464 | if (mfr_status < 0) | |
465 | return mfr_status; | |
466 | if (mfr_status & ADM1293_MFR_STATUS_VAUX_OV_WARN) | |
467 | ret |= PB_VOLTAGE_OV_WARNING; | |
468 | if (mfr_status & ADM1293_MFR_STATUS_VAUX_UV_WARN) | |
469 | ret |= PB_VOLTAGE_UV_WARNING; | |
9048539b | 470 | } |
92711269 | 471 | break; |
c5e67636 GR |
472 | default: |
473 | ret = -ENODATA; | |
474 | break; | |
475 | } | |
476 | return ret; | |
477 | } | |
478 | ||
87102808 | 479 | static const struct i2c_device_id adm1275_id[] = { |
92711269 | 480 | { "adm1075", adm1075 }, |
4ff0ce22 | 481 | { "adm1272", adm1272 }, |
87102808 GR |
482 | { "adm1275", adm1275 }, |
483 | { "adm1276", adm1276 }, | |
709066ac | 484 | { "adm1278", adm1278 }, |
91630090 | 485 | { "adm1281", adm1281 }, |
68a40382 GR |
486 | { "adm1293", adm1293 }, |
487 | { "adm1294", adm1294 }, | |
87102808 GR |
488 | { } |
489 | }; | |
490 | MODULE_DEVICE_TABLE(i2c, adm1275_id); | |
491 | ||
b153a0bb | 492 | /* Enable VOUT & TEMP1 if not enabled (disabled by default) */ |
98ac8af4 GR |
493 | static int adm1275_enable_vout_temp(struct adm1275_data *data, |
494 | struct i2c_client *client, int config) | |
b153a0bb GR |
495 | { |
496 | int ret; | |
497 | ||
498 | if ((config & ADM1278_PMON_DEFCONFIG) != ADM1278_PMON_DEFCONFIG) { | |
499 | config |= ADM1278_PMON_DEFCONFIG; | |
98ac8af4 | 500 | ret = adm1275_write_pmon_config(data, client, config); |
b153a0bb GR |
501 | if (ret < 0) { |
502 | dev_err(&client->dev, "Failed to enable VOUT/TEMP1 monitoring\n"); | |
503 | return ret; | |
504 | } | |
505 | } | |
506 | return 0; | |
507 | } | |
508 | ||
dd431939 | 509 | static int adm1275_probe(struct i2c_client *client) |
83f7649c | 510 | { |
6d1d41c0 | 511 | s32 (*config_read_fn)(const struct i2c_client *client, u8 reg); |
87102808 | 512 | u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1]; |
c5e67636 | 513 | int config, device_config; |
3b33ca41 | 514 | int ret; |
83f7649c | 515 | struct pmbus_driver_info *info; |
c5e67636 | 516 | struct adm1275_data *data; |
87102808 | 517 | const struct i2c_device_id *mid; |
904b296f | 518 | const struct coefficients *coefficients; |
68a40382 | 519 | int vindex = -1, voindex = -1, cindex = -1, pindex = -1; |
709066ac | 520 | int tindex = -1; |
6e5c06ad | 521 | u32 shunt; |
a3cd66d7 | 522 | u32 avg; |
83f7649c GR |
523 | |
524 | if (!i2c_check_functionality(client->adapter, | |
87102808 GR |
525 | I2C_FUNC_SMBUS_READ_BYTE_DATA |
526 | | I2C_FUNC_SMBUS_BLOCK_DATA)) | |
83f7649c GR |
527 | return -ENODEV; |
528 | ||
87102808 GR |
529 | ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, block_buffer); |
530 | if (ret < 0) { | |
531 | dev_err(&client->dev, "Failed to read Manufacturer ID\n"); | |
532 | return ret; | |
533 | } | |
534 | if (ret != 3 || strncmp(block_buffer, "ADI", 3)) { | |
535 | dev_err(&client->dev, "Unsupported Manufacturer ID\n"); | |
536 | return -ENODEV; | |
537 | } | |
83f7649c | 538 | |
87102808 GR |
539 | ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, block_buffer); |
540 | if (ret < 0) { | |
541 | dev_err(&client->dev, "Failed to read Manufacturer Model\n"); | |
542 | return ret; | |
543 | } | |
544 | for (mid = adm1275_id; mid->name[0]; mid++) { | |
545 | if (!strncasecmp(mid->name, block_buffer, strlen(mid->name))) | |
546 | break; | |
547 | } | |
548 | if (!mid->name[0]) { | |
549 | dev_err(&client->dev, "Unsupported device\n"); | |
550 | return -ENODEV; | |
3b33ca41 | 551 | } |
83f7649c | 552 | |
dd431939 | 553 | if (strcmp(client->name, mid->name) != 0) |
87102808 GR |
554 | dev_notice(&client->dev, |
555 | "Device mismatch: Configured %s, detected %s\n", | |
dd431939 | 556 | client->name, mid->name); |
87102808 | 557 | |
6d1d41c0 | 558 | if (mid->driver_data == adm1272 || mid->driver_data == adm1278 || |
91630090 JRSB |
559 | mid->driver_data == adm1281 || mid->driver_data == adm1293 || |
560 | mid->driver_data == adm1294) | |
6d1d41c0 CL |
561 | config_read_fn = i2c_smbus_read_word_data; |
562 | else | |
563 | config_read_fn = i2c_smbus_read_byte_data; | |
564 | config = config_read_fn(client, ADM1275_PMON_CONFIG); | |
87102808 GR |
565 | if (config < 0) |
566 | return config; | |
567 | ||
6d1d41c0 | 568 | device_config = config_read_fn(client, ADM1275_DEVICE_CONFIG); |
87102808 GR |
569 | if (device_config < 0) |
570 | return device_config; | |
571 | ||
8b313ca7 GR |
572 | data = devm_kzalloc(&client->dev, sizeof(struct adm1275_data), |
573 | GFP_KERNEL); | |
87102808 GR |
574 | if (!data) |
575 | return -ENOMEM; | |
576 | ||
6e5c06ad KY |
577 | if (of_property_read_u32(client->dev.of_node, |
578 | "shunt-resistor-micro-ohms", &shunt)) | |
579 | shunt = 1000; /* 1 mOhm if not set via DT */ | |
580 | ||
581 | if (shunt == 0) | |
582 | return -EINVAL; | |
583 | ||
87102808 | 584 | data->id = mid->driver_data; |
c5e67636 GR |
585 | |
586 | info = &data->info; | |
587 | ||
83f7649c | 588 | info->pages = 1; |
1061d851 GR |
589 | info->format[PSC_VOLTAGE_IN] = direct; |
590 | info->format[PSC_VOLTAGE_OUT] = direct; | |
591 | info->format[PSC_CURRENT_OUT] = direct; | |
904b296f | 592 | info->format[PSC_POWER] = direct; |
709066ac | 593 | info->format[PSC_TEMPERATURE] = direct; |
c83529c1 AKNPW |
594 | info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | |
595 | PMBUS_HAVE_SAMPLES; | |
83f7649c | 596 | |
c576e30c | 597 | info->read_word_data = adm1275_read_word_data; |
c5e67636 | 598 | info->read_byte_data = adm1275_read_byte_data; |
c576e30c GR |
599 | info->write_word_data = adm1275_write_word_data; |
600 | ||
87102808 | 601 | switch (data->id) { |
92711269 | 602 | case adm1075: |
9048539b GR |
603 | if (device_config & ADM1275_IOUT_WARN2_SELECT) |
604 | data->have_oc_fault = true; | |
605 | else | |
606 | data->have_uc_fault = true; | |
607 | data->have_pin_max = true; | |
608 | data->have_vaux_status = true; | |
609 | ||
904b296f GR |
610 | coefficients = adm1075_coefficients; |
611 | vindex = 0; | |
92711269 GR |
612 | switch (config & ADM1075_IRANGE_MASK) { |
613 | case ADM1075_IRANGE_25: | |
904b296f GR |
614 | cindex = 1; |
615 | pindex = 3; | |
92711269 GR |
616 | break; |
617 | case ADM1075_IRANGE_50: | |
904b296f GR |
618 | cindex = 2; |
619 | pindex = 4; | |
92711269 GR |
620 | break; |
621 | default: | |
622 | dev_err(&client->dev, "Invalid input current range"); | |
92711269 GR |
623 | break; |
624 | } | |
904b296f | 625 | |
92711269 GR |
626 | info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_PIN |
627 | | PMBUS_HAVE_STATUS_INPUT; | |
628 | if (config & ADM1275_VIN_VOUT_SELECT) | |
629 | info->func[0] |= | |
630 | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; | |
631 | break; | |
4ff0ce22 GR |
632 | case adm1272: |
633 | data->have_vout = true; | |
634 | data->have_pin_max = true; | |
635 | data->have_temp_max = true; | |
7d45deb3 | 636 | data->have_power_sampling = true; |
4ff0ce22 GR |
637 | |
638 | coefficients = adm1272_coefficients; | |
639 | vindex = (config & ADM1275_VRANGE) ? 1 : 0; | |
640 | cindex = (config & ADM1272_IRANGE) ? 3 : 2; | |
641 | /* pindex depends on the combination of the above */ | |
642 | switch (config & (ADM1275_VRANGE | ADM1272_IRANGE)) { | |
643 | case 0: | |
644 | default: | |
645 | pindex = 4; | |
646 | break; | |
647 | case ADM1275_VRANGE: | |
648 | pindex = 5; | |
649 | break; | |
650 | case ADM1272_IRANGE: | |
651 | pindex = 6; | |
652 | break; | |
653 | case ADM1275_VRANGE | ADM1272_IRANGE: | |
654 | pindex = 7; | |
655 | break; | |
656 | } | |
657 | tindex = 8; | |
658 | ||
659 | info->func[0] |= PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT | | |
9da9c2dc CL |
660 | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | |
661 | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; | |
4ff0ce22 | 662 | |
98ac8af4 | 663 | ret = adm1275_enable_vout_temp(data, client, config); |
b153a0bb GR |
664 | if (ret) |
665 | return ret; | |
666 | ||
4ff0ce22 GR |
667 | if (config & ADM1278_VIN_EN) |
668 | info->func[0] |= PMBUS_HAVE_VIN; | |
669 | break; | |
5cf231a3 | 670 | case adm1275: |
9048539b GR |
671 | if (device_config & ADM1275_IOUT_WARN2_SELECT) |
672 | data->have_oc_fault = true; | |
673 | else | |
674 | data->have_uc_fault = true; | |
675 | data->have_vout = true; | |
676 | ||
904b296f GR |
677 | coefficients = adm1275_coefficients; |
678 | vindex = (config & ADM1275_VRANGE) ? 0 : 1; | |
679 | cindex = 2; | |
680 | ||
5cf231a3 GR |
681 | if (config & ADM1275_VIN_VOUT_SELECT) |
682 | info->func[0] |= | |
683 | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; | |
684 | else | |
685 | info->func[0] |= | |
686 | PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT; | |
687 | break; | |
688 | case adm1276: | |
9048539b GR |
689 | if (device_config & ADM1275_IOUT_WARN2_SELECT) |
690 | data->have_oc_fault = true; | |
691 | else | |
692 | data->have_uc_fault = true; | |
693 | data->have_vout = true; | |
694 | data->have_pin_max = true; | |
695 | ||
904b296f GR |
696 | coefficients = adm1276_coefficients; |
697 | vindex = (config & ADM1275_VRANGE) ? 0 : 1; | |
698 | cindex = 2; | |
699 | pindex = (config & ADM1275_VRANGE) ? 3 : 4; | |
700 | ||
5cf231a3 GR |
701 | info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_PIN |
702 | | PMBUS_HAVE_STATUS_INPUT; | |
703 | if (config & ADM1275_VIN_VOUT_SELECT) | |
704 | info->func[0] |= | |
705 | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; | |
5cf231a3 | 706 | break; |
709066ac | 707 | case adm1278: |
91630090 | 708 | case adm1281: |
709066ac GR |
709 | data->have_vout = true; |
710 | data->have_pin_max = true; | |
711 | data->have_temp_max = true; | |
7d45deb3 | 712 | data->have_power_sampling = true; |
709066ac GR |
713 | |
714 | coefficients = adm1278_coefficients; | |
715 | vindex = 0; | |
716 | cindex = 1; | |
717 | pindex = 2; | |
718 | tindex = 3; | |
719 | ||
2b3d0c19 | 720 | info->func[0] |= PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT | |
a37881de ME |
721 | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | |
722 | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; | |
2b3d0c19 | 723 | |
98ac8af4 | 724 | ret = adm1275_enable_vout_temp(data, client, config); |
b153a0bb GR |
725 | if (ret) |
726 | return ret; | |
2b3d0c19 | 727 | |
709066ac GR |
728 | if (config & ADM1278_VIN_EN) |
729 | info->func[0] |= PMBUS_HAVE_VIN; | |
709066ac | 730 | break; |
68a40382 GR |
731 | case adm1293: |
732 | case adm1294: | |
733 | data->have_iout_min = true; | |
734 | data->have_pin_min = true; | |
735 | data->have_pin_max = true; | |
736 | data->have_mfr_vaux_status = true; | |
7d45deb3 | 737 | data->have_power_sampling = true; |
68a40382 GR |
738 | |
739 | coefficients = adm1293_coefficients; | |
740 | ||
741 | voindex = 0; | |
742 | switch (config & ADM1293_VIN_SEL_MASK) { | |
743 | case ADM1293_VIN_SEL_012: /* 1.2V */ | |
744 | vindex = 0; | |
745 | break; | |
746 | case ADM1293_VIN_SEL_074: /* 7.4V */ | |
747 | vindex = 1; | |
748 | break; | |
749 | case ADM1293_VIN_SEL_210: /* 21V */ | |
750 | vindex = 2; | |
751 | break; | |
752 | default: /* disabled */ | |
753 | break; | |
754 | } | |
755 | ||
756 | switch (config & ADM1293_IRANGE_MASK) { | |
757 | case ADM1293_IRANGE_25: | |
758 | cindex = 3; | |
759 | break; | |
760 | case ADM1293_IRANGE_50: | |
761 | cindex = 4; | |
762 | break; | |
763 | case ADM1293_IRANGE_100: | |
764 | cindex = 5; | |
765 | break; | |
766 | case ADM1293_IRANGE_200: | |
767 | cindex = 6; | |
768 | break; | |
769 | } | |
770 | ||
771 | if (vindex >= 0) | |
772 | pindex = 7 + vindex * 4 + (cindex - 3); | |
773 | ||
774 | if (config & ADM1293_VAUX_EN) | |
775 | info->func[0] |= | |
776 | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; | |
777 | ||
778 | info->func[0] |= PMBUS_HAVE_PIN | | |
779 | PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT; | |
780 | ||
781 | break; | |
904b296f GR |
782 | default: |
783 | dev_err(&client->dev, "Unsupported device\n"); | |
784 | return -ENODEV; | |
785 | } | |
68a40382 | 786 | |
a3cd66d7 PL |
787 | if (data->have_power_sampling && |
788 | of_property_read_u32(client->dev.of_node, | |
789 | "adi,power-sample-average", &avg) == 0) { | |
790 | if (!avg || avg > ADM1275_SAMPLES_AVG_MAX || | |
791 | BIT(__fls(avg)) != avg) { | |
792 | dev_err(&client->dev, | |
793 | "Invalid number of power samples"); | |
794 | return -EINVAL; | |
795 | } | |
98ac8af4 | 796 | ret = adm1275_write_samples(data, client, true, ilog2(avg)); |
a3cd66d7 PL |
797 | if (ret < 0) { |
798 | dev_err(&client->dev, | |
799 | "Setting power sample averaging failed with error %d", | |
800 | ret); | |
801 | return ret; | |
802 | } | |
803 | } | |
804 | ||
805 | if (of_property_read_u32(client->dev.of_node, | |
806 | "adi,volt-curr-sample-average", &avg) == 0) { | |
807 | if (!avg || avg > ADM1275_SAMPLES_AVG_MAX || | |
808 | BIT(__fls(avg)) != avg) { | |
809 | dev_err(&client->dev, | |
810 | "Invalid number of voltage/current samples"); | |
811 | return -EINVAL; | |
812 | } | |
98ac8af4 | 813 | ret = adm1275_write_samples(data, client, false, ilog2(avg)); |
a3cd66d7 PL |
814 | if (ret < 0) { |
815 | dev_err(&client->dev, | |
816 | "Setting voltage and current sample averaging failed with error %d", | |
817 | ret); | |
818 | return ret; | |
819 | } | |
820 | } | |
821 | ||
68a40382 GR |
822 | if (voindex < 0) |
823 | voindex = vindex; | |
904b296f GR |
824 | if (vindex >= 0) { |
825 | info->m[PSC_VOLTAGE_IN] = coefficients[vindex].m; | |
826 | info->b[PSC_VOLTAGE_IN] = coefficients[vindex].b; | |
827 | info->R[PSC_VOLTAGE_IN] = coefficients[vindex].R; | |
68a40382 GR |
828 | } |
829 | if (voindex >= 0) { | |
830 | info->m[PSC_VOLTAGE_OUT] = coefficients[voindex].m; | |
831 | info->b[PSC_VOLTAGE_OUT] = coefficients[voindex].b; | |
832 | info->R[PSC_VOLTAGE_OUT] = coefficients[voindex].R; | |
904b296f GR |
833 | } |
834 | if (cindex >= 0) { | |
6e5c06ad KY |
835 | /* Scale current with sense resistor value */ |
836 | info->m[PSC_CURRENT_OUT] = | |
837 | coefficients[cindex].m * shunt / 1000; | |
904b296f GR |
838 | info->b[PSC_CURRENT_OUT] = coefficients[cindex].b; |
839 | info->R[PSC_CURRENT_OUT] = coefficients[cindex].R; | |
840 | } | |
841 | if (pindex >= 0) { | |
6e5c06ad KY |
842 | info->m[PSC_POWER] = |
843 | coefficients[pindex].m * shunt / 1000; | |
904b296f GR |
844 | info->b[PSC_POWER] = coefficients[pindex].b; |
845 | info->R[PSC_POWER] = coefficients[pindex].R; | |
5cf231a3 | 846 | } |
709066ac GR |
847 | if (tindex >= 0) { |
848 | info->m[PSC_TEMPERATURE] = coefficients[tindex].m; | |
849 | info->b[PSC_TEMPERATURE] = coefficients[tindex].b; | |
850 | info->R[PSC_TEMPERATURE] = coefficients[tindex].R; | |
851 | } | |
83f7649c | 852 | |
dd431939 | 853 | return pmbus_do_probe(client, info); |
83f7649c GR |
854 | } |
855 | ||
83f7649c GR |
856 | static struct i2c_driver adm1275_driver = { |
857 | .driver = { | |
858 | .name = "adm1275", | |
859 | }, | |
1975d167 | 860 | .probe = adm1275_probe, |
83f7649c GR |
861 | .id_table = adm1275_id, |
862 | }; | |
863 | ||
f0967eea | 864 | module_i2c_driver(adm1275_driver); |
83f7649c GR |
865 | |
866 | MODULE_AUTHOR("Guenter Roeck"); | |
5cf231a3 | 867 | MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1275 and compatibles"); |
83f7649c | 868 | MODULE_LICENSE("GPL"); |
b94ca77e | 869 | MODULE_IMPORT_NS(PMBUS); |