Commit | Line | Data |
---|---|---|
16d60ba8 DM |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * max31827.c - Support for Maxim Low-Power Switch | |
4 | * | |
5 | * Copyright (c) 2023 Daniel Matyas <daniel.matyas@analog.com> | |
6 | */ | |
7 | ||
8 | #include <linux/bitfield.h> | |
9 | #include <linux/bitops.h> | |
10 | #include <linux/delay.h> | |
11 | #include <linux/hwmon.h> | |
12 | #include <linux/i2c.h> | |
13 | #include <linux/mutex.h> | |
88548710 | 14 | #include <linux/of_device.h> |
16d60ba8 | 15 | #include <linux/regmap.h> |
58ebe7fb | 16 | #include <linux/regulator/consumer.h> |
16d60ba8 DM |
17 | |
18 | #define MAX31827_T_REG 0x0 | |
19 | #define MAX31827_CONFIGURATION_REG 0x2 | |
20 | #define MAX31827_TH_REG 0x4 | |
21 | #define MAX31827_TL_REG 0x6 | |
22 | #define MAX31827_TH_HYST_REG 0x8 | |
23 | #define MAX31827_TL_HYST_REG 0xA | |
24 | ||
25 | #define MAX31827_CONFIGURATION_1SHOT_MASK BIT(0) | |
26 | #define MAX31827_CONFIGURATION_CNV_RATE_MASK GENMASK(3, 1) | |
88548710 DM |
27 | #define MAX31827_CONFIGURATION_TIMEOUT_MASK BIT(5) |
28 | #define MAX31827_CONFIGURATION_RESOLUTION_MASK GENMASK(7, 6) | |
29 | #define MAX31827_CONFIGURATION_ALRM_POL_MASK BIT(8) | |
30 | #define MAX31827_CONFIGURATION_COMP_INT_MASK BIT(9) | |
31 | #define MAX31827_CONFIGURATION_FLT_Q_MASK GENMASK(11, 10) | |
16d60ba8 DM |
32 | #define MAX31827_CONFIGURATION_U_TEMP_STAT_MASK BIT(14) |
33 | #define MAX31827_CONFIGURATION_O_TEMP_STAT_MASK BIT(15) | |
34 | ||
88548710 | 35 | #define MAX31827_ALRM_POL_LOW 0x0 |
cbeb1d2a | 36 | #define MAX31827_ALRM_POL_HIGH 0x1 |
88548710 | 37 | #define MAX31827_FLT_Q_1 0x0 |
cbeb1d2a | 38 | #define MAX31827_FLT_Q_4 0x2 |
88548710 | 39 | |
29a9ac64 DM |
40 | #define MAX31827_8_BIT_CNV_TIME 9 |
41 | #define MAX31827_9_BIT_CNV_TIME 18 | |
42 | #define MAX31827_10_BIT_CNV_TIME 35 | |
88245570 | 43 | #define MAX31827_12_BIT_CNV_TIME 140 |
16d60ba8 | 44 | |
16d60ba8 DM |
45 | #define MAX31827_16_BIT_TO_M_DGR(x) (sign_extend32(x, 15) * 1000 / 16) |
46 | #define MAX31827_M_DGR_TO_16_BIT(x) (((x) << 4) / 1000) | |
47 | #define MAX31827_DEVICE_ENABLE(x) ((x) ? 0xA : 0x0) | |
48 | ||
cbeb1d2a DM |
49 | enum chips { max31827 = 1, max31828, max31829 }; |
50 | ||
9ca66967 DM |
51 | enum max31827_cnv { |
52 | MAX31827_CNV_1_DIV_64_HZ = 1, | |
53 | MAX31827_CNV_1_DIV_32_HZ, | |
54 | MAX31827_CNV_1_DIV_16_HZ, | |
55 | MAX31827_CNV_1_DIV_4_HZ, | |
56 | MAX31827_CNV_1_HZ, | |
57 | MAX31827_CNV_4_HZ, | |
58 | MAX31827_CNV_8_HZ, | |
59 | }; | |
60 | ||
61 | static const u16 max31827_conversions[] = { | |
62 | [MAX31827_CNV_1_DIV_64_HZ] = 64000, | |
63 | [MAX31827_CNV_1_DIV_32_HZ] = 32000, | |
64 | [MAX31827_CNV_1_DIV_16_HZ] = 16000, | |
65 | [MAX31827_CNV_1_DIV_4_HZ] = 4000, | |
66 | [MAX31827_CNV_1_HZ] = 1000, | |
67 | [MAX31827_CNV_4_HZ] = 250, | |
68 | [MAX31827_CNV_8_HZ] = 125, | |
69 | }; | |
70 | ||
29a9ac64 DM |
71 | enum max31827_resolution { |
72 | MAX31827_RES_8_BIT = 0, | |
73 | MAX31827_RES_9_BIT, | |
74 | MAX31827_RES_10_BIT, | |
75 | MAX31827_RES_12_BIT, | |
76 | }; | |
77 | ||
78 | static const u16 max31827_resolutions[] = { | |
79 | [MAX31827_RES_8_BIT] = 1000, | |
80 | [MAX31827_RES_9_BIT] = 500, | |
81 | [MAX31827_RES_10_BIT] = 250, | |
82 | [MAX31827_RES_12_BIT] = 62, | |
83 | }; | |
84 | ||
85 | static const u16 max31827_conv_times[] = { | |
86 | [MAX31827_RES_8_BIT] = MAX31827_8_BIT_CNV_TIME, | |
87 | [MAX31827_RES_9_BIT] = MAX31827_9_BIT_CNV_TIME, | |
88 | [MAX31827_RES_10_BIT] = MAX31827_10_BIT_CNV_TIME, | |
89 | [MAX31827_RES_12_BIT] = MAX31827_12_BIT_CNV_TIME, | |
90 | }; | |
91 | ||
16d60ba8 DM |
92 | struct max31827_state { |
93 | /* | |
94 | * Prevent simultaneous access to the i2c client. | |
95 | */ | |
96 | struct mutex lock; | |
97 | struct regmap *regmap; | |
98 | bool enable; | |
29a9ac64 DM |
99 | unsigned int resolution; |
100 | unsigned int update_interval; | |
16d60ba8 DM |
101 | }; |
102 | ||
103 | static const struct regmap_config max31827_regmap = { | |
104 | .reg_bits = 8, | |
105 | .val_bits = 16, | |
106 | .max_register = 0xA, | |
107 | }; | |
108 | ||
9ca66967 | 109 | static int shutdown_write(struct max31827_state *st, unsigned int reg, |
8a0806df | 110 | unsigned int mask, unsigned int val) |
16d60ba8 DM |
111 | { |
112 | unsigned int cfg; | |
9ca66967 | 113 | unsigned int cnv_rate; |
16d60ba8 DM |
114 | int ret; |
115 | ||
16d60ba8 | 116 | /* |
29a9ac64 DM |
117 | * Before the Temperature Threshold Alarm, Alarm Hysteresis Threshold |
118 | * and Resolution bits from Configuration register are changed over I2C, | |
119 | * the part must be in shutdown mode. | |
16d60ba8 DM |
120 | * |
121 | * Mutex is used to ensure, that some other process doesn't change the | |
122 | * configuration register. | |
123 | */ | |
124 | mutex_lock(&st->lock); | |
125 | ||
126 | if (!st->enable) { | |
8a0806df DM |
127 | if (!mask) |
128 | ret = regmap_write(st->regmap, reg, val); | |
129 | else | |
130 | ret = regmap_update_bits(st->regmap, reg, mask, val); | |
16d60ba8 DM |
131 | goto unlock; |
132 | } | |
133 | ||
134 | ret = regmap_read(st->regmap, MAX31827_CONFIGURATION_REG, &cfg); | |
135 | if (ret) | |
136 | goto unlock; | |
137 | ||
9ca66967 DM |
138 | cnv_rate = MAX31827_CONFIGURATION_CNV_RATE_MASK & cfg; |
139 | cfg = cfg & ~(MAX31827_CONFIGURATION_1SHOT_MASK | | |
16d60ba8 | 140 | MAX31827_CONFIGURATION_CNV_RATE_MASK); |
9ca66967 | 141 | ret = regmap_write(st->regmap, MAX31827_CONFIGURATION_REG, cfg); |
16d60ba8 DM |
142 | if (ret) |
143 | goto unlock; | |
144 | ||
8a0806df DM |
145 | if (!mask) |
146 | ret = regmap_write(st->regmap, reg, val); | |
147 | else | |
148 | ret = regmap_update_bits(st->regmap, reg, mask, val); | |
149 | ||
16d60ba8 DM |
150 | if (ret) |
151 | goto unlock; | |
152 | ||
9ca66967 DM |
153 | ret = regmap_update_bits(st->regmap, MAX31827_CONFIGURATION_REG, |
154 | MAX31827_CONFIGURATION_CNV_RATE_MASK, | |
155 | cnv_rate); | |
16d60ba8 DM |
156 | |
157 | unlock: | |
158 | mutex_unlock(&st->lock); | |
159 | return ret; | |
160 | } | |
161 | ||
9ca66967 DM |
162 | static int write_alarm_val(struct max31827_state *st, unsigned int reg, |
163 | long val) | |
164 | { | |
165 | val = MAX31827_M_DGR_TO_16_BIT(val); | |
166 | ||
8a0806df | 167 | return shutdown_write(st, reg, 0, val); |
9ca66967 DM |
168 | } |
169 | ||
16d60ba8 DM |
170 | static umode_t max31827_is_visible(const void *state, |
171 | enum hwmon_sensor_types type, u32 attr, | |
172 | int channel) | |
173 | { | |
174 | if (type == hwmon_temp) { | |
175 | switch (attr) { | |
176 | case hwmon_temp_enable: | |
177 | case hwmon_temp_max: | |
178 | case hwmon_temp_min: | |
179 | case hwmon_temp_max_hyst: | |
180 | case hwmon_temp_min_hyst: | |
181 | return 0644; | |
182 | case hwmon_temp_input: | |
183 | case hwmon_temp_min_alarm: | |
184 | case hwmon_temp_max_alarm: | |
185 | return 0444; | |
186 | default: | |
187 | return 0; | |
188 | } | |
189 | } else if (type == hwmon_chip) { | |
190 | if (attr == hwmon_chip_update_interval) | |
191 | return 0644; | |
192 | } | |
193 | ||
194 | return 0; | |
195 | } | |
196 | ||
197 | static int max31827_read(struct device *dev, enum hwmon_sensor_types type, | |
198 | u32 attr, int channel, long *val) | |
199 | { | |
200 | struct max31827_state *st = dev_get_drvdata(dev); | |
201 | unsigned int uval; | |
202 | int ret = 0; | |
203 | ||
204 | switch (type) { | |
205 | case hwmon_temp: | |
206 | switch (attr) { | |
207 | case hwmon_temp_enable: | |
208 | ret = regmap_read(st->regmap, | |
209 | MAX31827_CONFIGURATION_REG, &uval); | |
210 | if (ret) | |
211 | break; | |
212 | ||
213 | uval = FIELD_GET(MAX31827_CONFIGURATION_1SHOT_MASK | | |
214 | MAX31827_CONFIGURATION_CNV_RATE_MASK, | |
215 | uval); | |
216 | *val = !!uval; | |
217 | ||
218 | break; | |
219 | case hwmon_temp_input: | |
220 | mutex_lock(&st->lock); | |
221 | ||
222 | if (!st->enable) { | |
223 | /* | |
224 | * This operation requires mutex protection, | |
225 | * because the chip configuration should not | |
226 | * be changed during the conversion process. | |
227 | */ | |
228 | ||
229 | ret = regmap_update_bits(st->regmap, | |
230 | MAX31827_CONFIGURATION_REG, | |
231 | MAX31827_CONFIGURATION_1SHOT_MASK, | |
232 | 1); | |
233 | if (ret) { | |
234 | mutex_unlock(&st->lock); | |
235 | return ret; | |
236 | } | |
29a9ac64 | 237 | msleep(max31827_conv_times[st->resolution]); |
16d60ba8 | 238 | } |
29a9ac64 DM |
239 | |
240 | /* | |
241 | * For 12-bit resolution the conversion time is 140 ms, | |
242 | * thus an additional 15 ms is needed to complete the | |
243 | * conversion: 125 ms + 15 ms = 140 ms | |
244 | */ | |
245 | if (max31827_resolutions[st->resolution] == 12 && | |
246 | st->update_interval == 125) | |
247 | usleep_range(15000, 20000); | |
248 | ||
16d60ba8 DM |
249 | ret = regmap_read(st->regmap, MAX31827_T_REG, &uval); |
250 | ||
251 | mutex_unlock(&st->lock); | |
252 | ||
253 | if (ret) | |
254 | break; | |
255 | ||
256 | *val = MAX31827_16_BIT_TO_M_DGR(uval); | |
257 | ||
258 | break; | |
259 | case hwmon_temp_max: | |
260 | ret = regmap_read(st->regmap, MAX31827_TH_REG, &uval); | |
261 | if (ret) | |
262 | break; | |
263 | ||
264 | *val = MAX31827_16_BIT_TO_M_DGR(uval); | |
265 | break; | |
266 | case hwmon_temp_max_hyst: | |
267 | ret = regmap_read(st->regmap, MAX31827_TH_HYST_REG, | |
268 | &uval); | |
269 | if (ret) | |
270 | break; | |
271 | ||
272 | *val = MAX31827_16_BIT_TO_M_DGR(uval); | |
273 | break; | |
274 | case hwmon_temp_max_alarm: | |
275 | ret = regmap_read(st->regmap, | |
276 | MAX31827_CONFIGURATION_REG, &uval); | |
277 | if (ret) | |
278 | break; | |
279 | ||
280 | *val = FIELD_GET(MAX31827_CONFIGURATION_O_TEMP_STAT_MASK, | |
281 | uval); | |
282 | break; | |
283 | case hwmon_temp_min: | |
284 | ret = regmap_read(st->regmap, MAX31827_TL_REG, &uval); | |
285 | if (ret) | |
286 | break; | |
287 | ||
288 | *val = MAX31827_16_BIT_TO_M_DGR(uval); | |
289 | break; | |
290 | case hwmon_temp_min_hyst: | |
291 | ret = regmap_read(st->regmap, MAX31827_TL_HYST_REG, | |
292 | &uval); | |
293 | if (ret) | |
294 | break; | |
295 | ||
296 | *val = MAX31827_16_BIT_TO_M_DGR(uval); | |
297 | break; | |
298 | case hwmon_temp_min_alarm: | |
299 | ret = regmap_read(st->regmap, | |
300 | MAX31827_CONFIGURATION_REG, &uval); | |
301 | if (ret) | |
302 | break; | |
303 | ||
304 | *val = FIELD_GET(MAX31827_CONFIGURATION_U_TEMP_STAT_MASK, | |
305 | uval); | |
306 | break; | |
307 | default: | |
308 | ret = -EOPNOTSUPP; | |
309 | break; | |
310 | } | |
311 | ||
312 | break; | |
313 | ||
314 | case hwmon_chip: | |
315 | if (attr == hwmon_chip_update_interval) { | |
316 | ret = regmap_read(st->regmap, | |
317 | MAX31827_CONFIGURATION_REG, &uval); | |
318 | if (ret) | |
319 | break; | |
320 | ||
321 | uval = FIELD_GET(MAX31827_CONFIGURATION_CNV_RATE_MASK, | |
322 | uval); | |
9ca66967 | 323 | *val = max31827_conversions[uval]; |
16d60ba8 DM |
324 | } |
325 | break; | |
326 | ||
327 | default: | |
328 | ret = -EOPNOTSUPP; | |
329 | break; | |
330 | } | |
331 | ||
332 | return ret; | |
333 | } | |
334 | ||
335 | static int max31827_write(struct device *dev, enum hwmon_sensor_types type, | |
336 | u32 attr, int channel, long val) | |
337 | { | |
338 | struct max31827_state *st = dev_get_drvdata(dev); | |
9ca66967 | 339 | int res = 1; |
16d60ba8 DM |
340 | int ret; |
341 | ||
342 | switch (type) { | |
343 | case hwmon_temp: | |
344 | switch (attr) { | |
345 | case hwmon_temp_enable: | |
346 | if (val >> 1) | |
347 | return -EINVAL; | |
348 | ||
349 | mutex_lock(&st->lock); | |
350 | /** | |
351 | * The chip should not be enabled while a conversion is | |
352 | * performed. Neither should the chip be enabled when | |
353 | * the alarm values are changed. | |
354 | */ | |
355 | ||
356 | st->enable = val; | |
357 | ||
358 | ret = regmap_update_bits(st->regmap, | |
359 | MAX31827_CONFIGURATION_REG, | |
360 | MAX31827_CONFIGURATION_1SHOT_MASK | | |
361 | MAX31827_CONFIGURATION_CNV_RATE_MASK, | |
362 | MAX31827_DEVICE_ENABLE(val)); | |
363 | ||
364 | mutex_unlock(&st->lock); | |
365 | ||
366 | return ret; | |
367 | ||
368 | case hwmon_temp_max: | |
369 | return write_alarm_val(st, MAX31827_TH_REG, val); | |
370 | ||
371 | case hwmon_temp_max_hyst: | |
372 | return write_alarm_val(st, MAX31827_TH_HYST_REG, val); | |
373 | ||
374 | case hwmon_temp_min: | |
375 | return write_alarm_val(st, MAX31827_TL_REG, val); | |
376 | ||
377 | case hwmon_temp_min_hyst: | |
378 | return write_alarm_val(st, MAX31827_TL_HYST_REG, val); | |
379 | ||
380 | default: | |
381 | return -EOPNOTSUPP; | |
382 | } | |
383 | ||
384 | case hwmon_chip: | |
385 | if (attr == hwmon_chip_update_interval) { | |
386 | if (!st->enable) | |
387 | return -EINVAL; | |
388 | ||
9ca66967 DM |
389 | /* |
390 | * Convert the desired conversion rate into register | |
391 | * bits. res is already initialized with 1. | |
392 | * | |
393 | * This was inspired by lm73 driver. | |
394 | */ | |
395 | while (res < ARRAY_SIZE(max31827_conversions) && | |
396 | val < max31827_conversions[res]) | |
397 | res++; | |
398 | ||
64176bde DM |
399 | if (res == ARRAY_SIZE(max31827_conversions)) |
400 | res = ARRAY_SIZE(max31827_conversions) - 1; | |
16d60ba8 | 401 | |
9ca66967 DM |
402 | res = FIELD_PREP(MAX31827_CONFIGURATION_CNV_RATE_MASK, |
403 | res); | |
16d60ba8 | 404 | |
29a9ac64 DM |
405 | ret = regmap_update_bits(st->regmap, |
406 | MAX31827_CONFIGURATION_REG, | |
407 | MAX31827_CONFIGURATION_CNV_RATE_MASK, | |
408 | res); | |
409 | if (ret) | |
410 | return ret; | |
411 | ||
412 | st->update_interval = val; | |
16d60ba8 DM |
413 | } |
414 | break; | |
415 | ||
416 | default: | |
417 | return -EOPNOTSUPP; | |
418 | } | |
419 | ||
29a9ac64 DM |
420 | return 0; |
421 | } | |
422 | ||
423 | static ssize_t temp1_resolution_show(struct device *dev, | |
424 | struct device_attribute *devattr, | |
425 | char *buf) | |
426 | { | |
427 | struct max31827_state *st = dev_get_drvdata(dev); | |
428 | unsigned int val; | |
429 | int ret; | |
430 | ||
431 | ret = regmap_read(st->regmap, MAX31827_CONFIGURATION_REG, &val); | |
432 | if (ret) | |
433 | return ret; | |
434 | ||
435 | val = FIELD_GET(MAX31827_CONFIGURATION_RESOLUTION_MASK, val); | |
436 | ||
437 | return scnprintf(buf, PAGE_SIZE, "%u\n", max31827_resolutions[val]); | |
438 | } | |
439 | ||
440 | static ssize_t temp1_resolution_store(struct device *dev, | |
441 | struct device_attribute *devattr, | |
442 | const char *buf, size_t count) | |
443 | { | |
444 | struct max31827_state *st = dev_get_drvdata(dev); | |
445 | unsigned int idx = 0; | |
446 | unsigned int val; | |
447 | int ret; | |
448 | ||
449 | ret = kstrtouint(buf, 10, &val); | |
450 | if (ret) | |
451 | return ret; | |
452 | ||
453 | /* | |
454 | * Convert the desired resolution into register | |
455 | * bits. idx is already initialized with 0. | |
456 | * | |
457 | * This was inspired by lm73 driver. | |
458 | */ | |
459 | while (idx < ARRAY_SIZE(max31827_resolutions) && | |
460 | val < max31827_resolutions[idx]) | |
461 | idx++; | |
462 | ||
463 | if (idx == ARRAY_SIZE(max31827_resolutions)) | |
464 | idx = ARRAY_SIZE(max31827_resolutions) - 1; | |
465 | ||
466 | st->resolution = idx; | |
467 | ||
468 | ret = shutdown_write(st, MAX31827_CONFIGURATION_REG, | |
469 | MAX31827_CONFIGURATION_RESOLUTION_MASK, | |
470 | FIELD_PREP(MAX31827_CONFIGURATION_RESOLUTION_MASK, | |
471 | idx)); | |
472 | ||
473 | return ret ? ret : count; | |
16d60ba8 DM |
474 | } |
475 | ||
29a9ac64 DM |
476 | static DEVICE_ATTR_RW(temp1_resolution); |
477 | ||
478 | static struct attribute *max31827_attrs[] = { | |
479 | &dev_attr_temp1_resolution.attr, | |
480 | NULL | |
481 | }; | |
482 | ATTRIBUTE_GROUPS(max31827); | |
483 | ||
cbeb1d2a DM |
484 | static const struct i2c_device_id max31827_i2c_ids[] = { |
485 | { "max31827", max31827 }, | |
486 | { "max31828", max31828 }, | |
487 | { "max31829", max31829 }, | |
488 | { } | |
489 | }; | |
490 | MODULE_DEVICE_TABLE(i2c, max31827_i2c_ids); | |
491 | ||
88548710 DM |
492 | static int max31827_init_client(struct max31827_state *st, |
493 | struct device *dev) | |
16d60ba8 | 494 | { |
88548710 DM |
495 | struct fwnode_handle *fwnode; |
496 | unsigned int res = 0; | |
497 | u32 data, lsb_idx; | |
cbeb1d2a | 498 | enum chips type; |
88548710 DM |
499 | bool prop; |
500 | int ret; | |
501 | ||
502 | fwnode = dev_fwnode(dev); | |
503 | ||
16d60ba8 | 504 | st->enable = true; |
88548710 DM |
505 | res |= MAX31827_DEVICE_ENABLE(1); |
506 | ||
507 | res |= MAX31827_CONFIGURATION_RESOLUTION_MASK; | |
508 | ||
509 | prop = fwnode_property_read_bool(fwnode, "adi,comp-int"); | |
510 | res |= FIELD_PREP(MAX31827_CONFIGURATION_COMP_INT_MASK, prop); | |
511 | ||
512 | prop = fwnode_property_read_bool(fwnode, "adi,timeout-enable"); | |
513 | res |= FIELD_PREP(MAX31827_CONFIGURATION_TIMEOUT_MASK, !prop); | |
514 | ||
cbeb1d2a DM |
515 | type = (enum chips)(uintptr_t)device_get_match_data(dev); |
516 | ||
88548710 DM |
517 | if (fwnode_property_present(fwnode, "adi,alarm-pol")) { |
518 | ret = fwnode_property_read_u32(fwnode, "adi,alarm-pol", &data); | |
519 | if (ret) | |
520 | return ret; | |
521 | ||
522 | res |= FIELD_PREP(MAX31827_CONFIGURATION_ALRM_POL_MASK, !!data); | |
523 | } else { | |
524 | /* | |
525 | * Set default value. | |
526 | */ | |
cbeb1d2a DM |
527 | switch (type) { |
528 | case max31827: | |
529 | case max31828: | |
530 | res |= FIELD_PREP(MAX31827_CONFIGURATION_ALRM_POL_MASK, | |
531 | MAX31827_ALRM_POL_LOW); | |
532 | break; | |
533 | case max31829: | |
534 | res |= FIELD_PREP(MAX31827_CONFIGURATION_ALRM_POL_MASK, | |
535 | MAX31827_ALRM_POL_HIGH); | |
536 | break; | |
537 | default: | |
538 | return -EOPNOTSUPP; | |
539 | } | |
88548710 DM |
540 | } |
541 | ||
542 | if (fwnode_property_present(fwnode, "adi,fault-q")) { | |
543 | ret = fwnode_property_read_u32(fwnode, "adi,fault-q", &data); | |
544 | if (ret) | |
545 | return ret; | |
546 | ||
547 | /* | |
548 | * Convert the desired fault queue into register bits. | |
549 | */ | |
550 | if (data != 0) | |
551 | lsb_idx = __ffs(data); | |
552 | ||
553 | if (hweight32(data) != 1 || lsb_idx > 4) { | |
554 | dev_err(dev, "Invalid data in adi,fault-q\n"); | |
555 | return -EINVAL; | |
556 | } | |
557 | ||
558 | res |= FIELD_PREP(MAX31827_CONFIGURATION_FLT_Q_MASK, lsb_idx); | |
559 | } else { | |
560 | /* | |
561 | * Set default value. | |
562 | */ | |
cbeb1d2a DM |
563 | switch (type) { |
564 | case max31827: | |
565 | res |= FIELD_PREP(MAX31827_CONFIGURATION_FLT_Q_MASK, | |
566 | MAX31827_FLT_Q_1); | |
567 | break; | |
568 | case max31828: | |
569 | case max31829: | |
570 | res |= FIELD_PREP(MAX31827_CONFIGURATION_FLT_Q_MASK, | |
571 | MAX31827_FLT_Q_4); | |
572 | break; | |
573 | default: | |
574 | return -EOPNOTSUPP; | |
575 | } | |
88548710 | 576 | } |
16d60ba8 | 577 | |
88548710 | 578 | return regmap_write(st->regmap, MAX31827_CONFIGURATION_REG, res); |
16d60ba8 DM |
579 | } |
580 | ||
581 | static const struct hwmon_channel_info *max31827_info[] = { | |
582 | HWMON_CHANNEL_INFO(temp, HWMON_T_ENABLE | HWMON_T_INPUT | HWMON_T_MIN | | |
583 | HWMON_T_MIN_HYST | HWMON_T_MIN_ALARM | | |
584 | HWMON_T_MAX | HWMON_T_MAX_HYST | | |
585 | HWMON_T_MAX_ALARM), | |
586 | HWMON_CHANNEL_INFO(chip, HWMON_C_UPDATE_INTERVAL), | |
587 | NULL, | |
588 | }; | |
589 | ||
590 | static const struct hwmon_ops max31827_hwmon_ops = { | |
591 | .is_visible = max31827_is_visible, | |
592 | .read = max31827_read, | |
593 | .write = max31827_write, | |
594 | }; | |
595 | ||
596 | static const struct hwmon_chip_info max31827_chip_info = { | |
597 | .ops = &max31827_hwmon_ops, | |
598 | .info = max31827_info, | |
599 | }; | |
600 | ||
601 | static int max31827_probe(struct i2c_client *client) | |
602 | { | |
603 | struct device *dev = &client->dev; | |
604 | struct device *hwmon_dev; | |
605 | struct max31827_state *st; | |
606 | int err; | |
607 | ||
608 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) | |
609 | return -EOPNOTSUPP; | |
610 | ||
611 | st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL); | |
612 | if (!st) | |
613 | return -ENOMEM; | |
614 | ||
615 | mutex_init(&st->lock); | |
616 | ||
617 | st->regmap = devm_regmap_init_i2c(client, &max31827_regmap); | |
618 | if (IS_ERR(st->regmap)) | |
619 | return dev_err_probe(dev, PTR_ERR(st->regmap), | |
620 | "Failed to allocate regmap.\n"); | |
621 | ||
6dbd3e04 AM |
622 | err = devm_regulator_get_enable(dev, "vref"); |
623 | if (err) | |
624 | return dev_err_probe(dev, err, "failed to enable regulator\n"); | |
625 | ||
88548710 | 626 | err = max31827_init_client(st, dev); |
16d60ba8 DM |
627 | if (err) |
628 | return err; | |
629 | ||
630 | hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, st, | |
631 | &max31827_chip_info, | |
29a9ac64 | 632 | max31827_groups); |
16d60ba8 DM |
633 | |
634 | return PTR_ERR_OR_ZERO(hwmon_dev); | |
635 | } | |
636 | ||
16d60ba8 | 637 | static const struct of_device_id max31827_of_match[] = { |
cbeb1d2a DM |
638 | { |
639 | .compatible = "adi,max31827", | |
640 | .data = (void *)max31827 | |
641 | }, | |
642 | { | |
643 | .compatible = "adi,max31828", | |
644 | .data = (void *)max31828 | |
645 | }, | |
646 | { | |
647 | .compatible = "adi,max31829", | |
648 | .data = (void *)max31829 | |
649 | }, | |
16d60ba8 DM |
650 | { } |
651 | }; | |
652 | MODULE_DEVICE_TABLE(of, max31827_of_match); | |
653 | ||
654 | static struct i2c_driver max31827_driver = { | |
655 | .class = I2C_CLASS_HWMON, | |
656 | .driver = { | |
657 | .name = "max31827", | |
658 | .of_match_table = max31827_of_match, | |
659 | }, | |
90fc660e | 660 | .probe = max31827_probe, |
16d60ba8 DM |
661 | .id_table = max31827_i2c_ids, |
662 | }; | |
663 | module_i2c_driver(max31827_driver); | |
664 | ||
665 | MODULE_AUTHOR("Daniel Matyas <daniel.matyas@analog.com>"); | |
666 | MODULE_DESCRIPTION("Maxim MAX31827 low-power temperature switch driver"); | |
667 | MODULE_LICENSE("GPL"); |