1fb55a513SParesh Chaudhary // SPDX-License-Identifier: GPL-2.0
2fb55a513SParesh Chaudhary /* max31856.c
3fb55a513SParesh Chaudhary *
4fb55a513SParesh Chaudhary * Maxim MAX31856 thermocouple sensor driver
5fb55a513SParesh Chaudhary *
6fb55a513SParesh Chaudhary * Copyright (C) 2018-2019 Rockwell Collins
7fb55a513SParesh Chaudhary */
8fb55a513SParesh Chaudhary
9ea410307SAndrea Merello #include <linux/ctype.h>
10*60a0548fSAndy Shevchenko #include <linux/mod_devicetable.h>
11fb55a513SParesh Chaudhary #include <linux/module.h>
12fb55a513SParesh Chaudhary #include <linux/init.h>
13fb55a513SParesh Chaudhary #include <linux/err.h>
14*60a0548fSAndy Shevchenko #include <linux/property.h>
15fb55a513SParesh Chaudhary #include <linux/spi/spi.h>
16fb55a513SParesh Chaudhary #include <linux/iio/iio.h>
17fb55a513SParesh Chaudhary #include <linux/iio/sysfs.h>
1857a4274cSAndrea Merello #include <linux/util_macros.h>
1992b7d5b7SAndy Shevchenko #include <asm/unaligned.h>
20fb55a513SParesh Chaudhary #include <dt-bindings/iio/temperature/thermocouple.h>
21fb55a513SParesh Chaudhary /*
22fb55a513SParesh Chaudhary * The MSB of the register value determines whether the following byte will
23fb55a513SParesh Chaudhary * be written or read. If it is 0, one or more byte reads will follow.
24fb55a513SParesh Chaudhary */
25fb55a513SParesh Chaudhary #define MAX31856_RD_WR_BIT BIT(7)
26fb55a513SParesh Chaudhary
27fb55a513SParesh Chaudhary #define MAX31856_CR0_AUTOCONVERT BIT(7)
28fb55a513SParesh Chaudhary #define MAX31856_CR0_1SHOT BIT(6)
29fb55a513SParesh Chaudhary #define MAX31856_CR0_OCFAULT BIT(4)
30fb55a513SParesh Chaudhary #define MAX31856_CR0_OCFAULT_MASK GENMASK(5, 4)
3176aa41c1SAndrea Merello #define MAX31856_CR0_FILTER_50HZ BIT(0)
3257a4274cSAndrea Merello #define MAX31856_AVERAGING_MASK GENMASK(6, 4)
3357a4274cSAndrea Merello #define MAX31856_AVERAGING_SHIFT 4
34fb55a513SParesh Chaudhary #define MAX31856_TC_TYPE_MASK GENMASK(3, 0)
35fb55a513SParesh Chaudhary #define MAX31856_FAULT_OVUV BIT(1)
36fb55a513SParesh Chaudhary #define MAX31856_FAULT_OPEN BIT(0)
37fb55a513SParesh Chaudhary
38fb55a513SParesh Chaudhary /* The MAX31856 registers */
39fb55a513SParesh Chaudhary #define MAX31856_CR0_REG 0x00
40fb55a513SParesh Chaudhary #define MAX31856_CR1_REG 0x01
41fb55a513SParesh Chaudhary #define MAX31856_MASK_REG 0x02
42fb55a513SParesh Chaudhary #define MAX31856_CJHF_REG 0x03
43fb55a513SParesh Chaudhary #define MAX31856_CJLF_REG 0x04
44fb55a513SParesh Chaudhary #define MAX31856_LTHFTH_REG 0x05
45fb55a513SParesh Chaudhary #define MAX31856_LTHFTL_REG 0x06
46fb55a513SParesh Chaudhary #define MAX31856_LTLFTH_REG 0x07
47fb55a513SParesh Chaudhary #define MAX31856_LTLFTL_REG 0x08
48fb55a513SParesh Chaudhary #define MAX31856_CJTO_REG 0x09
49fb55a513SParesh Chaudhary #define MAX31856_CJTH_REG 0x0A
50fb55a513SParesh Chaudhary #define MAX31856_CJTL_REG 0x0B
51fb55a513SParesh Chaudhary #define MAX31856_LTCBH_REG 0x0C
52fb55a513SParesh Chaudhary #define MAX31856_LTCBM_REG 0x0D
53fb55a513SParesh Chaudhary #define MAX31856_LTCBL_REG 0x0E
54fb55a513SParesh Chaudhary #define MAX31856_SR_REG 0x0F
55fb55a513SParesh Chaudhary
56fb55a513SParesh Chaudhary static const struct iio_chan_spec max31856_channels[] = {
57fb55a513SParesh Chaudhary { /* Thermocouple Temperature */
58fb55a513SParesh Chaudhary .type = IIO_TEMP,
59fb55a513SParesh Chaudhary .info_mask_separate =
60ea410307SAndrea Merello BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE) |
61ea410307SAndrea Merello BIT(IIO_CHAN_INFO_THERMOCOUPLE_TYPE),
6257a4274cSAndrea Merello .info_mask_shared_by_type =
6357a4274cSAndrea Merello BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO)
64fb55a513SParesh Chaudhary },
65fb55a513SParesh Chaudhary { /* Cold Junction Temperature */
66fb55a513SParesh Chaudhary .type = IIO_TEMP,
67fb55a513SParesh Chaudhary .channel2 = IIO_MOD_TEMP_AMBIENT,
68fb55a513SParesh Chaudhary .modified = 1,
69fb55a513SParesh Chaudhary .info_mask_separate =
70fb55a513SParesh Chaudhary BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
7157a4274cSAndrea Merello .info_mask_shared_by_type =
7257a4274cSAndrea Merello BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO)
73fb55a513SParesh Chaudhary },
74fb55a513SParesh Chaudhary };
75fb55a513SParesh Chaudhary
76fb55a513SParesh Chaudhary struct max31856_data {
77fb55a513SParesh Chaudhary struct spi_device *spi;
78fb55a513SParesh Chaudhary u32 thermocouple_type;
7976aa41c1SAndrea Merello bool filter_50hz;
8057a4274cSAndrea Merello int averaging;
81fb55a513SParesh Chaudhary };
82fb55a513SParesh Chaudhary
83ea410307SAndrea Merello static const char max31856_tc_types[] = {
84ea410307SAndrea Merello 'B', 'E', 'J', 'K', 'N', 'R', 'S', 'T'
85ea410307SAndrea Merello };
86ea410307SAndrea Merello
max31856_read(struct max31856_data * data,u8 reg,u8 val[],unsigned int read_size)87fb55a513SParesh Chaudhary static int max31856_read(struct max31856_data *data, u8 reg,
88fb55a513SParesh Chaudhary u8 val[], unsigned int read_size)
89fb55a513SParesh Chaudhary {
90fb55a513SParesh Chaudhary return spi_write_then_read(data->spi, ®, 1, val, read_size);
91fb55a513SParesh Chaudhary }
92fb55a513SParesh Chaudhary
max31856_write(struct max31856_data * data,u8 reg,unsigned int val)93fb55a513SParesh Chaudhary static int max31856_write(struct max31856_data *data, u8 reg,
94fb55a513SParesh Chaudhary unsigned int val)
95fb55a513SParesh Chaudhary {
96fb55a513SParesh Chaudhary u8 buf[2];
97fb55a513SParesh Chaudhary
98fb55a513SParesh Chaudhary buf[0] = reg | (MAX31856_RD_WR_BIT);
99fb55a513SParesh Chaudhary buf[1] = val;
100fb55a513SParesh Chaudhary
101fb55a513SParesh Chaudhary return spi_write(data->spi, buf, 2);
102fb55a513SParesh Chaudhary }
103fb55a513SParesh Chaudhary
max31856_init(struct max31856_data * data)104fb55a513SParesh Chaudhary static int max31856_init(struct max31856_data *data)
105fb55a513SParesh Chaudhary {
106fb55a513SParesh Chaudhary int ret;
107fb55a513SParesh Chaudhary u8 reg_cr0_val, reg_cr1_val;
108fb55a513SParesh Chaudhary
109fb55a513SParesh Chaudhary /* Start by changing to Off mode before making changes as
110fb55a513SParesh Chaudhary * some settings are recommended to be set only when the device
111fb55a513SParesh Chaudhary * is off
112fb55a513SParesh Chaudhary */
113fb55a513SParesh Chaudhary ret = max31856_read(data, MAX31856_CR0_REG, ®_cr0_val, 1);
114fb55a513SParesh Chaudhary if (ret)
115fb55a513SParesh Chaudhary return ret;
116fb55a513SParesh Chaudhary
117fb55a513SParesh Chaudhary reg_cr0_val &= ~MAX31856_CR0_AUTOCONVERT;
118fb55a513SParesh Chaudhary ret = max31856_write(data, MAX31856_CR0_REG, reg_cr0_val);
119fb55a513SParesh Chaudhary if (ret)
120fb55a513SParesh Chaudhary return ret;
121fb55a513SParesh Chaudhary
122fb55a513SParesh Chaudhary /* Set thermocouple type based on dts property */
123fb55a513SParesh Chaudhary ret = max31856_read(data, MAX31856_CR1_REG, ®_cr1_val, 1);
124fb55a513SParesh Chaudhary if (ret)
125fb55a513SParesh Chaudhary return ret;
126fb55a513SParesh Chaudhary
127fb55a513SParesh Chaudhary reg_cr1_val &= ~MAX31856_TC_TYPE_MASK;
128fb55a513SParesh Chaudhary reg_cr1_val |= data->thermocouple_type;
12957a4274cSAndrea Merello
13057a4274cSAndrea Merello reg_cr1_val &= ~MAX31856_AVERAGING_MASK;
13157a4274cSAndrea Merello reg_cr1_val |= data->averaging << MAX31856_AVERAGING_SHIFT;
13257a4274cSAndrea Merello
133fb55a513SParesh Chaudhary ret = max31856_write(data, MAX31856_CR1_REG, reg_cr1_val);
134fb55a513SParesh Chaudhary if (ret)
135fb55a513SParesh Chaudhary return ret;
136fb55a513SParesh Chaudhary
137fb55a513SParesh Chaudhary /*
138fb55a513SParesh Chaudhary * Enable Open circuit fault detection
139fb55a513SParesh Chaudhary * Read datasheet for more information: Table 4.
140fb55a513SParesh Chaudhary * Value 01 means : Enabled (Once every 16 conversions)
141fb55a513SParesh Chaudhary */
142fb55a513SParesh Chaudhary reg_cr0_val &= ~MAX31856_CR0_OCFAULT_MASK;
143fb55a513SParesh Chaudhary reg_cr0_val |= MAX31856_CR0_OCFAULT;
144fb55a513SParesh Chaudhary
145fb55a513SParesh Chaudhary /* Set Auto Conversion Mode */
146fb55a513SParesh Chaudhary reg_cr0_val &= ~MAX31856_CR0_1SHOT;
147fb55a513SParesh Chaudhary reg_cr0_val |= MAX31856_CR0_AUTOCONVERT;
148fb55a513SParesh Chaudhary
14976aa41c1SAndrea Merello if (data->filter_50hz)
15076aa41c1SAndrea Merello reg_cr0_val |= MAX31856_CR0_FILTER_50HZ;
15176aa41c1SAndrea Merello else
15276aa41c1SAndrea Merello reg_cr0_val &= ~MAX31856_CR0_FILTER_50HZ;
15376aa41c1SAndrea Merello
154fb55a513SParesh Chaudhary return max31856_write(data, MAX31856_CR0_REG, reg_cr0_val);
155fb55a513SParesh Chaudhary }
156fb55a513SParesh Chaudhary
max31856_thermocouple_read(struct max31856_data * data,struct iio_chan_spec const * chan,int * val)157fb55a513SParesh Chaudhary static int max31856_thermocouple_read(struct max31856_data *data,
158fb55a513SParesh Chaudhary struct iio_chan_spec const *chan,
159fb55a513SParesh Chaudhary int *val)
160fb55a513SParesh Chaudhary {
161fb55a513SParesh Chaudhary int ret, offset_cjto;
162fb55a513SParesh Chaudhary u8 reg_val[3];
163fb55a513SParesh Chaudhary
164fb55a513SParesh Chaudhary switch (chan->channel2) {
165fb55a513SParesh Chaudhary case IIO_NO_MOD:
166fb55a513SParesh Chaudhary /*
167fb55a513SParesh Chaudhary * Multibyte Read
168fb55a513SParesh Chaudhary * MAX31856_LTCBH_REG, MAX31856_LTCBM_REG, MAX31856_LTCBL_REG
169fb55a513SParesh Chaudhary */
170fb55a513SParesh Chaudhary ret = max31856_read(data, MAX31856_LTCBH_REG, reg_val, 3);
171fb55a513SParesh Chaudhary if (ret)
172fb55a513SParesh Chaudhary return ret;
173fb55a513SParesh Chaudhary /* Skip last 5 dead bits of LTCBL */
17492b7d5b7SAndy Shevchenko *val = get_unaligned_be24(®_val[0]) >> 5;
175fb55a513SParesh Chaudhary /* Check 7th bit of LTCBH reg. value for sign*/
176fb55a513SParesh Chaudhary if (reg_val[0] & 0x80)
177fb55a513SParesh Chaudhary *val -= 0x80000;
178fb55a513SParesh Chaudhary break;
179fb55a513SParesh Chaudhary
180fb55a513SParesh Chaudhary case IIO_MOD_TEMP_AMBIENT:
181fb55a513SParesh Chaudhary /*
182fb55a513SParesh Chaudhary * Multibyte Read
183fb55a513SParesh Chaudhary * MAX31856_CJTO_REG, MAX31856_CJTH_REG, MAX31856_CJTL_REG
184fb55a513SParesh Chaudhary */
185fb55a513SParesh Chaudhary ret = max31856_read(data, MAX31856_CJTO_REG, reg_val, 3);
186fb55a513SParesh Chaudhary if (ret)
187fb55a513SParesh Chaudhary return ret;
188fb55a513SParesh Chaudhary /* Get Cold Junction Temp. offset register value */
189fb55a513SParesh Chaudhary offset_cjto = reg_val[0];
190fb55a513SParesh Chaudhary /* Get CJTH and CJTL value and skip last 2 dead bits of CJTL */
19192b7d5b7SAndy Shevchenko *val = get_unaligned_be16(®_val[1]) >> 2;
192fb55a513SParesh Chaudhary /* As per datasheet add offset into CJTH and CJTL */
193fb55a513SParesh Chaudhary *val += offset_cjto;
194fb55a513SParesh Chaudhary /* Check 7th bit of CJTH reg. value for sign */
195fb55a513SParesh Chaudhary if (reg_val[1] & 0x80)
196fb55a513SParesh Chaudhary *val -= 0x4000;
197fb55a513SParesh Chaudhary break;
198fb55a513SParesh Chaudhary
199fb55a513SParesh Chaudhary default:
200fb55a513SParesh Chaudhary return -EINVAL;
201fb55a513SParesh Chaudhary }
202fb55a513SParesh Chaudhary
203fb55a513SParesh Chaudhary ret = max31856_read(data, MAX31856_SR_REG, reg_val, 1);
204fb55a513SParesh Chaudhary if (ret)
205fb55a513SParesh Chaudhary return ret;
206fb55a513SParesh Chaudhary /* Check for over/under voltage or open circuit fault */
207fb55a513SParesh Chaudhary if (reg_val[0] & (MAX31856_FAULT_OVUV | MAX31856_FAULT_OPEN))
208fb55a513SParesh Chaudhary return -EIO;
209fb55a513SParesh Chaudhary
210fb55a513SParesh Chaudhary return ret;
211fb55a513SParesh Chaudhary }
212fb55a513SParesh Chaudhary
max31856_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)213fb55a513SParesh Chaudhary static int max31856_read_raw(struct iio_dev *indio_dev,
214fb55a513SParesh Chaudhary struct iio_chan_spec const *chan,
215fb55a513SParesh Chaudhary int *val, int *val2, long mask)
216fb55a513SParesh Chaudhary {
217fb55a513SParesh Chaudhary struct max31856_data *data = iio_priv(indio_dev);
218fb55a513SParesh Chaudhary int ret;
219fb55a513SParesh Chaudhary
220fb55a513SParesh Chaudhary switch (mask) {
221fb55a513SParesh Chaudhary case IIO_CHAN_INFO_RAW:
222fb55a513SParesh Chaudhary ret = max31856_thermocouple_read(data, chan, val);
223fb55a513SParesh Chaudhary if (ret)
224fb55a513SParesh Chaudhary return ret;
225fb55a513SParesh Chaudhary return IIO_VAL_INT;
226fb55a513SParesh Chaudhary case IIO_CHAN_INFO_SCALE:
227fb55a513SParesh Chaudhary switch (chan->channel2) {
228fb55a513SParesh Chaudhary case IIO_MOD_TEMP_AMBIENT:
229fb55a513SParesh Chaudhary /* Cold junction Temp. Data resolution is 0.015625 */
230fb55a513SParesh Chaudhary *val = 15;
231fb55a513SParesh Chaudhary *val2 = 625000; /* 1000 * 0.015625 */
232fb55a513SParesh Chaudhary ret = IIO_VAL_INT_PLUS_MICRO;
233fb55a513SParesh Chaudhary break;
234fb55a513SParesh Chaudhary default:
235fb55a513SParesh Chaudhary /* Thermocouple Temp. Data resolution is 0.0078125 */
236fb55a513SParesh Chaudhary *val = 7;
237fb55a513SParesh Chaudhary *val2 = 812500; /* 1000 * 0.0078125) */
238fb55a513SParesh Chaudhary return IIO_VAL_INT_PLUS_MICRO;
239fb55a513SParesh Chaudhary }
240fb55a513SParesh Chaudhary break;
24157a4274cSAndrea Merello case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
24257a4274cSAndrea Merello *val = 1 << data->averaging;
24357a4274cSAndrea Merello return IIO_VAL_INT;
244ea410307SAndrea Merello case IIO_CHAN_INFO_THERMOCOUPLE_TYPE:
245ea410307SAndrea Merello *val = max31856_tc_types[data->thermocouple_type];
246ea410307SAndrea Merello return IIO_VAL_CHAR;
2478e4fefecSColin Ian King default:
2488e4fefecSColin Ian King ret = -EINVAL;
2498e4fefecSColin Ian King break;
250fb55a513SParesh Chaudhary }
251fb55a513SParesh Chaudhary
252fb55a513SParesh Chaudhary return ret;
253fb55a513SParesh Chaudhary }
254fb55a513SParesh Chaudhary
max31856_write_raw_get_fmt(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,long mask)255ea410307SAndrea Merello static int max31856_write_raw_get_fmt(struct iio_dev *indio_dev,
256ea410307SAndrea Merello struct iio_chan_spec const *chan,
257ea410307SAndrea Merello long mask)
258ea410307SAndrea Merello {
259ea410307SAndrea Merello switch (mask) {
260ea410307SAndrea Merello case IIO_CHAN_INFO_THERMOCOUPLE_TYPE:
261ea410307SAndrea Merello return IIO_VAL_CHAR;
262ea410307SAndrea Merello default:
263ea410307SAndrea Merello return IIO_VAL_INT;
264ea410307SAndrea Merello }
265ea410307SAndrea Merello }
266ea410307SAndrea Merello
max31856_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)26757a4274cSAndrea Merello static int max31856_write_raw(struct iio_dev *indio_dev,
26857a4274cSAndrea Merello struct iio_chan_spec const *chan,
26957a4274cSAndrea Merello int val, int val2, long mask)
27057a4274cSAndrea Merello {
27157a4274cSAndrea Merello struct max31856_data *data = iio_priv(indio_dev);
27257a4274cSAndrea Merello int msb;
27357a4274cSAndrea Merello
27457a4274cSAndrea Merello switch (mask) {
27557a4274cSAndrea Merello case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
27657a4274cSAndrea Merello if (val > 16 || val < 1)
27757a4274cSAndrea Merello return -EINVAL;
27857a4274cSAndrea Merello msb = fls(val) - 1;
27957a4274cSAndrea Merello /* Round up to next 2pow if needed */
28057a4274cSAndrea Merello if (BIT(msb) < val)
28157a4274cSAndrea Merello msb++;
28257a4274cSAndrea Merello
28357a4274cSAndrea Merello data->averaging = msb;
28457a4274cSAndrea Merello max31856_init(data);
28557a4274cSAndrea Merello break;
286ea410307SAndrea Merello case IIO_CHAN_INFO_THERMOCOUPLE_TYPE:
287ea410307SAndrea Merello {
288ea410307SAndrea Merello int tc_type = -1;
289ea410307SAndrea Merello int i;
29057a4274cSAndrea Merello
291ea410307SAndrea Merello for (i = 0; i < ARRAY_SIZE(max31856_tc_types); i++) {
292ea410307SAndrea Merello if (max31856_tc_types[i] == toupper(val)) {
293ea410307SAndrea Merello tc_type = i;
294ea410307SAndrea Merello break;
295ea410307SAndrea Merello }
296ea410307SAndrea Merello }
297ea410307SAndrea Merello if (tc_type < 0)
298ea410307SAndrea Merello return -EINVAL;
299ea410307SAndrea Merello
300ea410307SAndrea Merello data->thermocouple_type = tc_type;
301ea410307SAndrea Merello max31856_init(data);
302ea410307SAndrea Merello break;
303ea410307SAndrea Merello }
30457a4274cSAndrea Merello default:
30557a4274cSAndrea Merello return -EINVAL;
30657a4274cSAndrea Merello }
30757a4274cSAndrea Merello
30857a4274cSAndrea Merello return 0;
30957a4274cSAndrea Merello }
31057a4274cSAndrea Merello
show_fault(struct device * dev,u8 faultbit,char * buf)311fb55a513SParesh Chaudhary static ssize_t show_fault(struct device *dev, u8 faultbit, char *buf)
312fb55a513SParesh Chaudhary {
313fb55a513SParesh Chaudhary struct iio_dev *indio_dev = dev_to_iio_dev(dev);
314fb55a513SParesh Chaudhary struct max31856_data *data = iio_priv(indio_dev);
315fb55a513SParesh Chaudhary u8 reg_val;
316fb55a513SParesh Chaudhary int ret;
317fb55a513SParesh Chaudhary bool fault;
318fb55a513SParesh Chaudhary
319fb55a513SParesh Chaudhary ret = max31856_read(data, MAX31856_SR_REG, ®_val, 1);
320fb55a513SParesh Chaudhary if (ret)
321fb55a513SParesh Chaudhary return ret;
322fb55a513SParesh Chaudhary
323fb55a513SParesh Chaudhary fault = reg_val & faultbit;
324fb55a513SParesh Chaudhary
3259df24867SLars-Peter Clausen return sysfs_emit(buf, "%d\n", fault);
326fb55a513SParesh Chaudhary }
327fb55a513SParesh Chaudhary
show_fault_ovuv(struct device * dev,struct device_attribute * attr,char * buf)328fb55a513SParesh Chaudhary static ssize_t show_fault_ovuv(struct device *dev,
329fb55a513SParesh Chaudhary struct device_attribute *attr,
330fb55a513SParesh Chaudhary char *buf)
331fb55a513SParesh Chaudhary {
332fb55a513SParesh Chaudhary return show_fault(dev, MAX31856_FAULT_OVUV, buf);
333fb55a513SParesh Chaudhary }
334fb55a513SParesh Chaudhary
show_fault_oc(struct device * dev,struct device_attribute * attr,char * buf)335fb55a513SParesh Chaudhary static ssize_t show_fault_oc(struct device *dev,
336fb55a513SParesh Chaudhary struct device_attribute *attr,
337fb55a513SParesh Chaudhary char *buf)
338fb55a513SParesh Chaudhary {
339fb55a513SParesh Chaudhary return show_fault(dev, MAX31856_FAULT_OPEN, buf);
340fb55a513SParesh Chaudhary }
341fb55a513SParesh Chaudhary
show_filter(struct device * dev,struct device_attribute * attr,char * buf)34276aa41c1SAndrea Merello static ssize_t show_filter(struct device *dev,
34376aa41c1SAndrea Merello struct device_attribute *attr,
34476aa41c1SAndrea Merello char *buf)
34576aa41c1SAndrea Merello {
34676aa41c1SAndrea Merello struct iio_dev *indio_dev = dev_to_iio_dev(dev);
34776aa41c1SAndrea Merello struct max31856_data *data = iio_priv(indio_dev);
34876aa41c1SAndrea Merello
3499df24867SLars-Peter Clausen return sysfs_emit(buf, "%d\n", data->filter_50hz ? 50 : 60);
35076aa41c1SAndrea Merello }
35176aa41c1SAndrea Merello
set_filter(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)35276aa41c1SAndrea Merello static ssize_t set_filter(struct device *dev,
35376aa41c1SAndrea Merello struct device_attribute *attr,
35476aa41c1SAndrea Merello const char *buf,
35576aa41c1SAndrea Merello size_t len)
35676aa41c1SAndrea Merello {
35776aa41c1SAndrea Merello struct iio_dev *indio_dev = dev_to_iio_dev(dev);
35876aa41c1SAndrea Merello struct max31856_data *data = iio_priv(indio_dev);
35976aa41c1SAndrea Merello unsigned int freq;
36076aa41c1SAndrea Merello int ret;
36176aa41c1SAndrea Merello
36276aa41c1SAndrea Merello ret = kstrtouint(buf, 10, &freq);
36376aa41c1SAndrea Merello if (ret)
36476aa41c1SAndrea Merello return ret;
36576aa41c1SAndrea Merello
36676aa41c1SAndrea Merello switch (freq) {
36776aa41c1SAndrea Merello case 50:
36876aa41c1SAndrea Merello data->filter_50hz = true;
36976aa41c1SAndrea Merello break;
37076aa41c1SAndrea Merello case 60:
37176aa41c1SAndrea Merello data->filter_50hz = false;
37276aa41c1SAndrea Merello break;
37376aa41c1SAndrea Merello default:
37476aa41c1SAndrea Merello return -EINVAL;
37576aa41c1SAndrea Merello }
37676aa41c1SAndrea Merello
37776aa41c1SAndrea Merello max31856_init(data);
37876aa41c1SAndrea Merello return len;
37976aa41c1SAndrea Merello }
38076aa41c1SAndrea Merello
381fb55a513SParesh Chaudhary static IIO_DEVICE_ATTR(fault_ovuv, 0444, show_fault_ovuv, NULL, 0);
382fb55a513SParesh Chaudhary static IIO_DEVICE_ATTR(fault_oc, 0444, show_fault_oc, NULL, 0);
38376aa41c1SAndrea Merello static IIO_DEVICE_ATTR(in_temp_filter_notch_center_frequency, 0644,
38476aa41c1SAndrea Merello show_filter, set_filter, 0);
385fb55a513SParesh Chaudhary
386fb55a513SParesh Chaudhary static struct attribute *max31856_attributes[] = {
387fb55a513SParesh Chaudhary &iio_dev_attr_fault_ovuv.dev_attr.attr,
388fb55a513SParesh Chaudhary &iio_dev_attr_fault_oc.dev_attr.attr,
38976aa41c1SAndrea Merello &iio_dev_attr_in_temp_filter_notch_center_frequency.dev_attr.attr,
390fb55a513SParesh Chaudhary NULL,
391fb55a513SParesh Chaudhary };
392fb55a513SParesh Chaudhary
393fb55a513SParesh Chaudhary static const struct attribute_group max31856_group = {
394fb55a513SParesh Chaudhary .attrs = max31856_attributes,
395fb55a513SParesh Chaudhary };
396fb55a513SParesh Chaudhary
397fb55a513SParesh Chaudhary static const struct iio_info max31856_info = {
398fb55a513SParesh Chaudhary .read_raw = max31856_read_raw,
39957a4274cSAndrea Merello .write_raw = max31856_write_raw,
400ea410307SAndrea Merello .write_raw_get_fmt = max31856_write_raw_get_fmt,
401fb55a513SParesh Chaudhary .attrs = &max31856_group,
402fb55a513SParesh Chaudhary };
403fb55a513SParesh Chaudhary
max31856_probe(struct spi_device * spi)404fb55a513SParesh Chaudhary static int max31856_probe(struct spi_device *spi)
405fb55a513SParesh Chaudhary {
406fb55a513SParesh Chaudhary const struct spi_device_id *id = spi_get_device_id(spi);
407fb55a513SParesh Chaudhary struct iio_dev *indio_dev;
408fb55a513SParesh Chaudhary struct max31856_data *data;
409fb55a513SParesh Chaudhary int ret;
410fb55a513SParesh Chaudhary
411fb55a513SParesh Chaudhary indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*data));
412fb55a513SParesh Chaudhary if (!indio_dev)
413fb55a513SParesh Chaudhary return -ENOMEM;
414fb55a513SParesh Chaudhary
415fb55a513SParesh Chaudhary data = iio_priv(indio_dev);
416fb55a513SParesh Chaudhary data->spi = spi;
41776aa41c1SAndrea Merello data->filter_50hz = false;
418fb55a513SParesh Chaudhary
419fb55a513SParesh Chaudhary spi_set_drvdata(spi, indio_dev);
420fb55a513SParesh Chaudhary
421fb55a513SParesh Chaudhary indio_dev->info = &max31856_info;
422fb55a513SParesh Chaudhary indio_dev->name = id->name;
423fb55a513SParesh Chaudhary indio_dev->modes = INDIO_DIRECT_MODE;
424fb55a513SParesh Chaudhary indio_dev->channels = max31856_channels;
425fb55a513SParesh Chaudhary indio_dev->num_channels = ARRAY_SIZE(max31856_channels);
426fb55a513SParesh Chaudhary
427*60a0548fSAndy Shevchenko ret = device_property_read_u32(&spi->dev, "thermocouple-type", &data->thermocouple_type);
428fb55a513SParesh Chaudhary if (ret) {
429fb55a513SParesh Chaudhary dev_info(&spi->dev,
430fb55a513SParesh Chaudhary "Could not read thermocouple type DT property, configuring as a K-Type\n");
431fb55a513SParesh Chaudhary data->thermocouple_type = THERMOCOUPLE_TYPE_K;
432fb55a513SParesh Chaudhary }
433fb55a513SParesh Chaudhary
434fb55a513SParesh Chaudhary /*
435fb55a513SParesh Chaudhary * no need to translate values as the supported types
436fb55a513SParesh Chaudhary * have the same value as the #defines
437fb55a513SParesh Chaudhary */
438fb55a513SParesh Chaudhary switch (data->thermocouple_type) {
439fb55a513SParesh Chaudhary case THERMOCOUPLE_TYPE_B:
440fb55a513SParesh Chaudhary case THERMOCOUPLE_TYPE_E:
441fb55a513SParesh Chaudhary case THERMOCOUPLE_TYPE_J:
442fb55a513SParesh Chaudhary case THERMOCOUPLE_TYPE_K:
443fb55a513SParesh Chaudhary case THERMOCOUPLE_TYPE_N:
444fb55a513SParesh Chaudhary case THERMOCOUPLE_TYPE_R:
445fb55a513SParesh Chaudhary case THERMOCOUPLE_TYPE_S:
446fb55a513SParesh Chaudhary case THERMOCOUPLE_TYPE_T:
447fb55a513SParesh Chaudhary break;
448fb55a513SParesh Chaudhary default:
449fb55a513SParesh Chaudhary dev_err(&spi->dev,
450fb55a513SParesh Chaudhary "error: thermocouple-type %u not supported by max31856\n"
451fb55a513SParesh Chaudhary , data->thermocouple_type);
452fb55a513SParesh Chaudhary return -EINVAL;
453fb55a513SParesh Chaudhary }
454fb55a513SParesh Chaudhary
455fb55a513SParesh Chaudhary ret = max31856_init(data);
456fb55a513SParesh Chaudhary if (ret) {
457fb55a513SParesh Chaudhary dev_err(&spi->dev, "error: Failed to configure max31856\n");
458fb55a513SParesh Chaudhary return ret;
459fb55a513SParesh Chaudhary }
460fb55a513SParesh Chaudhary
461fb55a513SParesh Chaudhary return devm_iio_device_register(&spi->dev, indio_dev);
462fb55a513SParesh Chaudhary }
463fb55a513SParesh Chaudhary
464fb55a513SParesh Chaudhary static const struct spi_device_id max31856_id[] = {
465fb55a513SParesh Chaudhary { "max31856", 0 },
466fb55a513SParesh Chaudhary { }
467fb55a513SParesh Chaudhary };
468fb55a513SParesh Chaudhary MODULE_DEVICE_TABLE(spi, max31856_id);
469fb55a513SParesh Chaudhary
470fb55a513SParesh Chaudhary static const struct of_device_id max31856_of_match[] = {
471fb55a513SParesh Chaudhary { .compatible = "maxim,max31856" },
472fb55a513SParesh Chaudhary { }
473fb55a513SParesh Chaudhary };
474fb55a513SParesh Chaudhary MODULE_DEVICE_TABLE(of, max31856_of_match);
475fb55a513SParesh Chaudhary
476fb55a513SParesh Chaudhary static struct spi_driver max31856_driver = {
477fb55a513SParesh Chaudhary .driver = {
478fb55a513SParesh Chaudhary .name = "max31856",
479fb55a513SParesh Chaudhary .of_match_table = max31856_of_match,
480fb55a513SParesh Chaudhary },
481fb55a513SParesh Chaudhary .probe = max31856_probe,
482fb55a513SParesh Chaudhary .id_table = max31856_id,
483fb55a513SParesh Chaudhary };
484fb55a513SParesh Chaudhary module_spi_driver(max31856_driver);
485fb55a513SParesh Chaudhary
486fb55a513SParesh Chaudhary MODULE_AUTHOR("Paresh Chaudhary <paresh.chaudhary@rockwellcollins.com>");
487fb55a513SParesh Chaudhary MODULE_AUTHOR("Patrick Havelange <patrick.havelange@essensium.com>");
488fb55a513SParesh Chaudhary MODULE_DESCRIPTION("Maxim MAX31856 thermocouple sensor driver");
489fb55a513SParesh Chaudhary MODULE_LICENSE("GPL");
490