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, &reg, 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, &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, &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(&reg_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(&reg_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, &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