1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* max31856.c |
3 | * |
4 | * Maxim MAX31856 thermocouple sensor driver |
5 | * |
6 | * Copyright (C) 2018-2019 Rockwell Collins |
7 | */ |
8 | |
9 | #include <linux/ctype.h> |
10 | #include <linux/mod_devicetable.h> |
11 | #include <linux/module.h> |
12 | #include <linux/init.h> |
13 | #include <linux/err.h> |
14 | #include <linux/property.h> |
15 | #include <linux/spi/spi.h> |
16 | #include <linux/iio/iio.h> |
17 | #include <linux/iio/sysfs.h> |
18 | #include <linux/util_macros.h> |
19 | #include <asm/unaligned.h> |
20 | #include <dt-bindings/iio/temperature/thermocouple.h> |
21 | /* |
22 | * The MSB of the register value determines whether the following byte will |
23 | * be written or read. If it is 0, one or more byte reads will follow. |
24 | */ |
25 | #define MAX31856_RD_WR_BIT BIT(7) |
26 | |
27 | #define MAX31856_CR0_AUTOCONVERT BIT(7) |
28 | #define MAX31856_CR0_1SHOT BIT(6) |
29 | #define MAX31856_CR0_OCFAULT BIT(4) |
30 | #define MAX31856_CR0_OCFAULT_MASK GENMASK(5, 4) |
31 | #define MAX31856_CR0_FILTER_50HZ BIT(0) |
32 | #define MAX31856_AVERAGING_MASK GENMASK(6, 4) |
33 | #define MAX31856_AVERAGING_SHIFT 4 |
34 | #define MAX31856_TC_TYPE_MASK GENMASK(3, 0) |
35 | #define MAX31856_FAULT_OVUV BIT(1) |
36 | #define MAX31856_FAULT_OPEN BIT(0) |
37 | |
38 | /* The MAX31856 registers */ |
39 | #define MAX31856_CR0_REG 0x00 |
40 | #define MAX31856_CR1_REG 0x01 |
41 | #define MAX31856_MASK_REG 0x02 |
42 | #define MAX31856_CJHF_REG 0x03 |
43 | #define MAX31856_CJLF_REG 0x04 |
44 | #define MAX31856_LTHFTH_REG 0x05 |
45 | #define MAX31856_LTHFTL_REG 0x06 |
46 | #define MAX31856_LTLFTH_REG 0x07 |
47 | #define MAX31856_LTLFTL_REG 0x08 |
48 | #define MAX31856_CJTO_REG 0x09 |
49 | #define MAX31856_CJTH_REG 0x0A |
50 | #define MAX31856_CJTL_REG 0x0B |
51 | #define MAX31856_LTCBH_REG 0x0C |
52 | #define MAX31856_LTCBM_REG 0x0D |
53 | #define MAX31856_LTCBL_REG 0x0E |
54 | #define MAX31856_SR_REG 0x0F |
55 | |
56 | static const struct iio_chan_spec max31856_channels[] = { |
57 | { /* Thermocouple Temperature */ |
58 | .type = IIO_TEMP, |
59 | .info_mask_separate = |
60 | BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE) | |
61 | BIT(IIO_CHAN_INFO_THERMOCOUPLE_TYPE), |
62 | .info_mask_shared_by_type = |
63 | BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) |
64 | }, |
65 | { /* Cold Junction Temperature */ |
66 | .type = IIO_TEMP, |
67 | .channel2 = IIO_MOD_TEMP_AMBIENT, |
68 | .modified = 1, |
69 | .info_mask_separate = |
70 | BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), |
71 | .info_mask_shared_by_type = |
72 | BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) |
73 | }, |
74 | }; |
75 | |
76 | struct max31856_data { |
77 | struct spi_device *spi; |
78 | u32 thermocouple_type; |
79 | bool filter_50hz; |
80 | int averaging; |
81 | }; |
82 | |
83 | static const char max31856_tc_types[] = { |
84 | 'B', 'E', 'J', 'K', 'N', 'R', 'S', 'T' |
85 | }; |
86 | |
87 | static int max31856_read(struct max31856_data *data, u8 reg, |
88 | u8 val[], unsigned int read_size) |
89 | { |
90 | return spi_write_then_read(spi: data->spi, txbuf: ®, n_tx: 1, rxbuf: val, n_rx: read_size); |
91 | } |
92 | |
93 | static int max31856_write(struct max31856_data *data, u8 reg, |
94 | unsigned int val) |
95 | { |
96 | u8 buf[2]; |
97 | |
98 | buf[0] = reg | (MAX31856_RD_WR_BIT); |
99 | buf[1] = val; |
100 | |
101 | return spi_write(spi: data->spi, buf, len: 2); |
102 | } |
103 | |
104 | static int max31856_init(struct max31856_data *data) |
105 | { |
106 | int ret; |
107 | u8 reg_cr0_val, reg_cr1_val; |
108 | |
109 | /* Start by changing to Off mode before making changes as |
110 | * some settings are recommended to be set only when the device |
111 | * is off |
112 | */ |
113 | ret = max31856_read(data, MAX31856_CR0_REG, val: ®_cr0_val, read_size: 1); |
114 | if (ret) |
115 | return ret; |
116 | |
117 | reg_cr0_val &= ~MAX31856_CR0_AUTOCONVERT; |
118 | ret = max31856_write(data, MAX31856_CR0_REG, val: reg_cr0_val); |
119 | if (ret) |
120 | return ret; |
121 | |
122 | /* Set thermocouple type based on dts property */ |
123 | ret = max31856_read(data, MAX31856_CR1_REG, val: ®_cr1_val, read_size: 1); |
124 | if (ret) |
125 | return ret; |
126 | |
127 | reg_cr1_val &= ~MAX31856_TC_TYPE_MASK; |
128 | reg_cr1_val |= data->thermocouple_type; |
129 | |
130 | reg_cr1_val &= ~MAX31856_AVERAGING_MASK; |
131 | reg_cr1_val |= data->averaging << MAX31856_AVERAGING_SHIFT; |
132 | |
133 | ret = max31856_write(data, MAX31856_CR1_REG, val: reg_cr1_val); |
134 | if (ret) |
135 | return ret; |
136 | |
137 | /* |
138 | * Enable Open circuit fault detection |
139 | * Read datasheet for more information: Table 4. |
140 | * Value 01 means : Enabled (Once every 16 conversions) |
141 | */ |
142 | reg_cr0_val &= ~MAX31856_CR0_OCFAULT_MASK; |
143 | reg_cr0_val |= MAX31856_CR0_OCFAULT; |
144 | |
145 | /* Set Auto Conversion Mode */ |
146 | reg_cr0_val &= ~MAX31856_CR0_1SHOT; |
147 | reg_cr0_val |= MAX31856_CR0_AUTOCONVERT; |
148 | |
149 | if (data->filter_50hz) |
150 | reg_cr0_val |= MAX31856_CR0_FILTER_50HZ; |
151 | else |
152 | reg_cr0_val &= ~MAX31856_CR0_FILTER_50HZ; |
153 | |
154 | return max31856_write(data, MAX31856_CR0_REG, val: reg_cr0_val); |
155 | } |
156 | |
157 | static int max31856_thermocouple_read(struct max31856_data *data, |
158 | struct iio_chan_spec const *chan, |
159 | int *val) |
160 | { |
161 | int ret, offset_cjto; |
162 | u8 reg_val[3]; |
163 | |
164 | switch (chan->channel2) { |
165 | case IIO_NO_MOD: |
166 | /* |
167 | * Multibyte Read |
168 | * MAX31856_LTCBH_REG, MAX31856_LTCBM_REG, MAX31856_LTCBL_REG |
169 | */ |
170 | ret = max31856_read(data, MAX31856_LTCBH_REG, val: reg_val, read_size: 3); |
171 | if (ret) |
172 | return ret; |
173 | /* Skip last 5 dead bits of LTCBL */ |
174 | *val = get_unaligned_be24(p: ®_val[0]) >> 5; |
175 | /* Check 7th bit of LTCBH reg. value for sign*/ |
176 | if (reg_val[0] & 0x80) |
177 | *val -= 0x80000; |
178 | break; |
179 | |
180 | case IIO_MOD_TEMP_AMBIENT: |
181 | /* |
182 | * Multibyte Read |
183 | * MAX31856_CJTO_REG, MAX31856_CJTH_REG, MAX31856_CJTL_REG |
184 | */ |
185 | ret = max31856_read(data, MAX31856_CJTO_REG, val: reg_val, read_size: 3); |
186 | if (ret) |
187 | return ret; |
188 | /* Get Cold Junction Temp. offset register value */ |
189 | offset_cjto = reg_val[0]; |
190 | /* Get CJTH and CJTL value and skip last 2 dead bits of CJTL */ |
191 | *val = get_unaligned_be16(p: ®_val[1]) >> 2; |
192 | /* As per datasheet add offset into CJTH and CJTL */ |
193 | *val += offset_cjto; |
194 | /* Check 7th bit of CJTH reg. value for sign */ |
195 | if (reg_val[1] & 0x80) |
196 | *val -= 0x4000; |
197 | break; |
198 | |
199 | default: |
200 | return -EINVAL; |
201 | } |
202 | |
203 | ret = max31856_read(data, MAX31856_SR_REG, val: reg_val, read_size: 1); |
204 | if (ret) |
205 | return ret; |
206 | /* Check for over/under voltage or open circuit fault */ |
207 | if (reg_val[0] & (MAX31856_FAULT_OVUV | MAX31856_FAULT_OPEN)) |
208 | return -EIO; |
209 | |
210 | return ret; |
211 | } |
212 | |
213 | static int max31856_read_raw(struct iio_dev *indio_dev, |
214 | struct iio_chan_spec const *chan, |
215 | int *val, int *val2, long mask) |
216 | { |
217 | struct max31856_data *data = iio_priv(indio_dev); |
218 | int ret; |
219 | |
220 | switch (mask) { |
221 | case IIO_CHAN_INFO_RAW: |
222 | ret = max31856_thermocouple_read(data, chan, val); |
223 | if (ret) |
224 | return ret; |
225 | return IIO_VAL_INT; |
226 | case IIO_CHAN_INFO_SCALE: |
227 | switch (chan->channel2) { |
228 | case IIO_MOD_TEMP_AMBIENT: |
229 | /* Cold junction Temp. Data resolution is 0.015625 */ |
230 | *val = 15; |
231 | *val2 = 625000; /* 1000 * 0.015625 */ |
232 | ret = IIO_VAL_INT_PLUS_MICRO; |
233 | break; |
234 | default: |
235 | /* Thermocouple Temp. Data resolution is 0.0078125 */ |
236 | *val = 7; |
237 | *val2 = 812500; /* 1000 * 0.0078125) */ |
238 | return IIO_VAL_INT_PLUS_MICRO; |
239 | } |
240 | break; |
241 | case IIO_CHAN_INFO_OVERSAMPLING_RATIO: |
242 | *val = 1 << data->averaging; |
243 | return IIO_VAL_INT; |
244 | case IIO_CHAN_INFO_THERMOCOUPLE_TYPE: |
245 | *val = max31856_tc_types[data->thermocouple_type]; |
246 | return IIO_VAL_CHAR; |
247 | default: |
248 | ret = -EINVAL; |
249 | break; |
250 | } |
251 | |
252 | return ret; |
253 | } |
254 | |
255 | static int max31856_write_raw_get_fmt(struct iio_dev *indio_dev, |
256 | struct iio_chan_spec const *chan, |
257 | long mask) |
258 | { |
259 | switch (mask) { |
260 | case IIO_CHAN_INFO_THERMOCOUPLE_TYPE: |
261 | return IIO_VAL_CHAR; |
262 | default: |
263 | return IIO_VAL_INT; |
264 | } |
265 | } |
266 | |
267 | static int max31856_write_raw(struct iio_dev *indio_dev, |
268 | struct iio_chan_spec const *chan, |
269 | int val, int val2, long mask) |
270 | { |
271 | struct max31856_data *data = iio_priv(indio_dev); |
272 | int msb; |
273 | |
274 | switch (mask) { |
275 | case IIO_CHAN_INFO_OVERSAMPLING_RATIO: |
276 | if (val > 16 || val < 1) |
277 | return -EINVAL; |
278 | msb = fls(x: val) - 1; |
279 | /* Round up to next 2pow if needed */ |
280 | if (BIT(msb) < val) |
281 | msb++; |
282 | |
283 | data->averaging = msb; |
284 | max31856_init(data); |
285 | break; |
286 | case IIO_CHAN_INFO_THERMOCOUPLE_TYPE: |
287 | { |
288 | int tc_type = -1; |
289 | int i; |
290 | |
291 | for (i = 0; i < ARRAY_SIZE(max31856_tc_types); i++) { |
292 | if (max31856_tc_types[i] == toupper(val)) { |
293 | tc_type = i; |
294 | break; |
295 | } |
296 | } |
297 | if (tc_type < 0) |
298 | return -EINVAL; |
299 | |
300 | data->thermocouple_type = tc_type; |
301 | max31856_init(data); |
302 | break; |
303 | } |
304 | default: |
305 | return -EINVAL; |
306 | } |
307 | |
308 | return 0; |
309 | } |
310 | |
311 | static ssize_t show_fault(struct device *dev, u8 faultbit, char *buf) |
312 | { |
313 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); |
314 | struct max31856_data *data = iio_priv(indio_dev); |
315 | u8 reg_val; |
316 | int ret; |
317 | bool fault; |
318 | |
319 | ret = max31856_read(data, MAX31856_SR_REG, val: ®_val, read_size: 1); |
320 | if (ret) |
321 | return ret; |
322 | |
323 | fault = reg_val & faultbit; |
324 | |
325 | return sysfs_emit(buf, fmt: "%d\n" , fault); |
326 | } |
327 | |
328 | static ssize_t show_fault_ovuv(struct device *dev, |
329 | struct device_attribute *attr, |
330 | char *buf) |
331 | { |
332 | return show_fault(dev, MAX31856_FAULT_OVUV, buf); |
333 | } |
334 | |
335 | static ssize_t show_fault_oc(struct device *dev, |
336 | struct device_attribute *attr, |
337 | char *buf) |
338 | { |
339 | return show_fault(dev, MAX31856_FAULT_OPEN, buf); |
340 | } |
341 | |
342 | static ssize_t show_filter(struct device *dev, |
343 | struct device_attribute *attr, |
344 | char *buf) |
345 | { |
346 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); |
347 | struct max31856_data *data = iio_priv(indio_dev); |
348 | |
349 | return sysfs_emit(buf, fmt: "%d\n" , data->filter_50hz ? 50 : 60); |
350 | } |
351 | |
352 | static ssize_t set_filter(struct device *dev, |
353 | struct device_attribute *attr, |
354 | const char *buf, |
355 | size_t len) |
356 | { |
357 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); |
358 | struct max31856_data *data = iio_priv(indio_dev); |
359 | unsigned int freq; |
360 | int ret; |
361 | |
362 | ret = kstrtouint(s: buf, base: 10, res: &freq); |
363 | if (ret) |
364 | return ret; |
365 | |
366 | switch (freq) { |
367 | case 50: |
368 | data->filter_50hz = true; |
369 | break; |
370 | case 60: |
371 | data->filter_50hz = false; |
372 | break; |
373 | default: |
374 | return -EINVAL; |
375 | } |
376 | |
377 | max31856_init(data); |
378 | return len; |
379 | } |
380 | |
381 | static IIO_DEVICE_ATTR(fault_ovuv, 0444, show_fault_ovuv, NULL, 0); |
382 | static IIO_DEVICE_ATTR(fault_oc, 0444, show_fault_oc, NULL, 0); |
383 | static IIO_DEVICE_ATTR(in_temp_filter_notch_center_frequency, 0644, |
384 | show_filter, set_filter, 0); |
385 | |
386 | static struct attribute *max31856_attributes[] = { |
387 | &iio_dev_attr_fault_ovuv.dev_attr.attr, |
388 | &iio_dev_attr_fault_oc.dev_attr.attr, |
389 | &iio_dev_attr_in_temp_filter_notch_center_frequency.dev_attr.attr, |
390 | NULL, |
391 | }; |
392 | |
393 | static const struct attribute_group max31856_group = { |
394 | .attrs = max31856_attributes, |
395 | }; |
396 | |
397 | static const struct iio_info max31856_info = { |
398 | .read_raw = max31856_read_raw, |
399 | .write_raw = max31856_write_raw, |
400 | .write_raw_get_fmt = max31856_write_raw_get_fmt, |
401 | .attrs = &max31856_group, |
402 | }; |
403 | |
404 | static int max31856_probe(struct spi_device *spi) |
405 | { |
406 | const struct spi_device_id *id = spi_get_device_id(sdev: spi); |
407 | struct iio_dev *indio_dev; |
408 | struct max31856_data *data; |
409 | int ret; |
410 | |
411 | indio_dev = devm_iio_device_alloc(parent: &spi->dev, sizeof_priv: sizeof(*data)); |
412 | if (!indio_dev) |
413 | return -ENOMEM; |
414 | |
415 | data = iio_priv(indio_dev); |
416 | data->spi = spi; |
417 | data->filter_50hz = false; |
418 | |
419 | spi_set_drvdata(spi, data: indio_dev); |
420 | |
421 | indio_dev->info = &max31856_info; |
422 | indio_dev->name = id->name; |
423 | indio_dev->modes = INDIO_DIRECT_MODE; |
424 | indio_dev->channels = max31856_channels; |
425 | indio_dev->num_channels = ARRAY_SIZE(max31856_channels); |
426 | |
427 | ret = device_property_read_u32(dev: &spi->dev, propname: "thermocouple-type" , val: &data->thermocouple_type); |
428 | if (ret) { |
429 | dev_info(&spi->dev, |
430 | "Could not read thermocouple type DT property, configuring as a K-Type\n" ); |
431 | data->thermocouple_type = THERMOCOUPLE_TYPE_K; |
432 | } |
433 | |
434 | /* |
435 | * no need to translate values as the supported types |
436 | * have the same value as the #defines |
437 | */ |
438 | switch (data->thermocouple_type) { |
439 | case THERMOCOUPLE_TYPE_B: |
440 | case THERMOCOUPLE_TYPE_E: |
441 | case THERMOCOUPLE_TYPE_J: |
442 | case THERMOCOUPLE_TYPE_K: |
443 | case THERMOCOUPLE_TYPE_N: |
444 | case THERMOCOUPLE_TYPE_R: |
445 | case THERMOCOUPLE_TYPE_S: |
446 | case THERMOCOUPLE_TYPE_T: |
447 | break; |
448 | default: |
449 | dev_err(&spi->dev, |
450 | "error: thermocouple-type %u not supported by max31856\n" |
451 | , data->thermocouple_type); |
452 | return -EINVAL; |
453 | } |
454 | |
455 | ret = max31856_init(data); |
456 | if (ret) { |
457 | dev_err(&spi->dev, "error: Failed to configure max31856\n" ); |
458 | return ret; |
459 | } |
460 | |
461 | return devm_iio_device_register(&spi->dev, indio_dev); |
462 | } |
463 | |
464 | static const struct spi_device_id max31856_id[] = { |
465 | { "max31856" , 0 }, |
466 | { } |
467 | }; |
468 | MODULE_DEVICE_TABLE(spi, max31856_id); |
469 | |
470 | static const struct of_device_id max31856_of_match[] = { |
471 | { .compatible = "maxim,max31856" }, |
472 | { } |
473 | }; |
474 | MODULE_DEVICE_TABLE(of, max31856_of_match); |
475 | |
476 | static struct spi_driver max31856_driver = { |
477 | .driver = { |
478 | .name = "max31856" , |
479 | .of_match_table = max31856_of_match, |
480 | }, |
481 | .probe = max31856_probe, |
482 | .id_table = max31856_id, |
483 | }; |
484 | module_spi_driver(max31856_driver); |
485 | |
486 | MODULE_AUTHOR("Paresh Chaudhary <paresh.chaudhary@rockwellcollins.com>" ); |
487 | MODULE_AUTHOR("Patrick Havelange <patrick.havelange@essensium.com>" ); |
488 | MODULE_DESCRIPTION("Maxim MAX31856 thermocouple sensor driver" ); |
489 | MODULE_LICENSE("GPL" ); |
490 | |