xref: /openbmc/linux/drivers/iio/pressure/ms5611_core.c (revision a477e3a76be740a1be844635d572c83f4c10002c)
16cfdb150STomasz Duszynski // SPDX-License-Identifier: GPL-2.0
2c0644160STomasz Duszynski /*
3c0644160STomasz Duszynski  * MS5611 pressure and temperature sensor driver
4c0644160STomasz Duszynski  *
5c0644160STomasz Duszynski  * Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
6c0644160STomasz Duszynski  *
7c0644160STomasz Duszynski  * Data sheet:
8c0644160STomasz Duszynski  *  http://www.meas-spec.com/downloads/MS5611-01BA03.pdf
99690d81aSTomasz Duszynski  *  http://www.meas-spec.com/downloads/MS5607-02BA03.pdf
10c0644160STomasz Duszynski  *
11c0644160STomasz Duszynski  */
12c0644160STomasz Duszynski 
13c0644160STomasz Duszynski #include <linux/module.h>
14c0644160STomasz Duszynski #include <linux/iio/iio.h>
15c0644160STomasz Duszynski #include <linux/delay.h>
163145229fSGrégor Boirie #include <linux/regulator/consumer.h>
17c0644160STomasz Duszynski 
18033691a9SGregor Boirie #include <linux/iio/sysfs.h>
19713bbb4eSDaniel Baluta #include <linux/iio/buffer.h>
20713bbb4eSDaniel Baluta #include <linux/iio/triggered_buffer.h>
21713bbb4eSDaniel Baluta #include <linux/iio/trigger_consumer.h>
22c0644160STomasz Duszynski #include "ms5611.h"
23c0644160STomasz Duszynski 
24033691a9SGregor Boirie #define MS5611_INIT_OSR(_cmd, _conv_usec, _rate) \
25033691a9SGregor Boirie 	{ .cmd = _cmd, .conv_usec = _conv_usec, .rate = _rate }
26033691a9SGregor Boirie 
27033691a9SGregor Boirie static const struct ms5611_osr ms5611_avail_pressure_osr[] = {
28033691a9SGregor Boirie 	MS5611_INIT_OSR(0x40, 600,  256),
29033691a9SGregor Boirie 	MS5611_INIT_OSR(0x42, 1170, 512),
30033691a9SGregor Boirie 	MS5611_INIT_OSR(0x44, 2280, 1024),
31033691a9SGregor Boirie 	MS5611_INIT_OSR(0x46, 4540, 2048),
32033691a9SGregor Boirie 	MS5611_INIT_OSR(0x48, 9040, 4096)
33033691a9SGregor Boirie };
34033691a9SGregor Boirie 
35033691a9SGregor Boirie static const struct ms5611_osr ms5611_avail_temp_osr[] = {
36033691a9SGregor Boirie 	MS5611_INIT_OSR(0x50, 600,  256),
37033691a9SGregor Boirie 	MS5611_INIT_OSR(0x52, 1170, 512),
38033691a9SGregor Boirie 	MS5611_INIT_OSR(0x54, 2280, 1024),
39033691a9SGregor Boirie 	MS5611_INIT_OSR(0x56, 4540, 2048),
40033691a9SGregor Boirie 	MS5611_INIT_OSR(0x58, 9040, 4096)
41033691a9SGregor Boirie };
42033691a9SGregor Boirie 
43033691a9SGregor Boirie static const char ms5611_show_osr[] = "256 512 1024 2048 4096";
44033691a9SGregor Boirie 
45033691a9SGregor Boirie static IIO_CONST_ATTR(oversampling_ratio_available, ms5611_show_osr);
46033691a9SGregor Boirie 
47033691a9SGregor Boirie static struct attribute *ms5611_attributes[] = {
48033691a9SGregor Boirie 	&iio_const_attr_oversampling_ratio_available.dev_attr.attr,
49033691a9SGregor Boirie 	NULL,
50033691a9SGregor Boirie };
51033691a9SGregor Boirie 
52033691a9SGregor Boirie static const struct attribute_group ms5611_attribute_group = {
53033691a9SGregor Boirie 	.attrs = ms5611_attributes,
54033691a9SGregor Boirie };
55033691a9SGregor Boirie 
ms5611_prom_is_valid(u16 * prom,size_t len)56c0644160STomasz Duszynski static bool ms5611_prom_is_valid(u16 *prom, size_t len)
57c0644160STomasz Duszynski {
58c0644160STomasz Duszynski 	int i, j;
59c0644160STomasz Duszynski 	uint16_t crc = 0, crc_orig = prom[7] & 0x000F;
60c0644160STomasz Duszynski 
61c0644160STomasz Duszynski 	prom[7] &= 0xFF00;
62c0644160STomasz Duszynski 
63c0644160STomasz Duszynski 	for (i = 0; i < len * 2; i++) {
64c0644160STomasz Duszynski 		if (i % 2 == 1)
65c0644160STomasz Duszynski 			crc ^= prom[i >> 1] & 0x00FF;
66c0644160STomasz Duszynski 		else
67c0644160STomasz Duszynski 			crc ^= prom[i >> 1] >> 8;
68c0644160STomasz Duszynski 
69c0644160STomasz Duszynski 		for (j = 0; j < 8; j++) {
70c0644160STomasz Duszynski 			if (crc & 0x8000)
71c0644160STomasz Duszynski 				crc = (crc << 1) ^ 0x3000;
72c0644160STomasz Duszynski 			else
73c0644160STomasz Duszynski 				crc <<= 1;
74c0644160STomasz Duszynski 		}
75c0644160STomasz Duszynski 	}
76c0644160STomasz Duszynski 
77c0644160STomasz Duszynski 	crc = (crc >> 12) & 0x000F;
78c0644160STomasz Duszynski 
79*fd39d966SAlexander Zangerl 	return crc == crc_orig;
80c0644160STomasz Duszynski }
81c0644160STomasz Duszynski 
ms5611_read_prom(struct iio_dev * indio_dev)82c0644160STomasz Duszynski static int ms5611_read_prom(struct iio_dev *indio_dev)
83c0644160STomasz Duszynski {
84c0644160STomasz Duszynski 	int ret, i;
85c0644160STomasz Duszynski 	struct ms5611_state *st = iio_priv(indio_dev);
86c0644160STomasz Duszynski 
87c0644160STomasz Duszynski 	for (i = 0; i < MS5611_PROM_WORDS_NB; i++) {
8817f442e7SMitja Spes 		ret = st->read_prom_word(st, i, &st->prom[i]);
89c0644160STomasz Duszynski 		if (ret < 0) {
90c0644160STomasz Duszynski 			dev_err(&indio_dev->dev,
91c0644160STomasz Duszynski 				"failed to read prom at %d\n", i);
92c0644160STomasz Duszynski 			return ret;
93c0644160STomasz Duszynski 		}
94c0644160STomasz Duszynski 	}
95c0644160STomasz Duszynski 
9617f442e7SMitja Spes 	if (!ms5611_prom_is_valid(st->prom, MS5611_PROM_WORDS_NB)) {
97c0644160STomasz Duszynski 		dev_err(&indio_dev->dev, "PROM integrity check failed\n");
98c0644160STomasz Duszynski 		return -ENODEV;
99c0644160STomasz Duszynski 	}
100c0644160STomasz Duszynski 
101c0644160STomasz Duszynski 	return 0;
102c0644160STomasz Duszynski }
103c0644160STomasz Duszynski 
ms5611_read_temp_and_pressure(struct iio_dev * indio_dev,s32 * temp,s32 * pressure)104c0644160STomasz Duszynski static int ms5611_read_temp_and_pressure(struct iio_dev *indio_dev,
105c0644160STomasz Duszynski 					 s32 *temp, s32 *pressure)
106c0644160STomasz Duszynski {
107c0644160STomasz Duszynski 	int ret;
108c0644160STomasz Duszynski 	struct ms5611_state *st = iio_priv(indio_dev);
109c0644160STomasz Duszynski 
110dc19fa63SLars-Peter Clausen 	ret = st->read_adc_temp_and_pressure(st, temp, pressure);
111c0644160STomasz Duszynski 	if (ret < 0) {
112c0644160STomasz Duszynski 		dev_err(&indio_dev->dev,
113c0644160STomasz Duszynski 			"failed to read temperature and pressure\n");
114c0644160STomasz Duszynski 		return ret;
115c0644160STomasz Duszynski 	}
116c0644160STomasz Duszynski 
11717f442e7SMitja Spes 	return st->compensate_temp_and_pressure(st, temp, pressure);
1189690d81aSTomasz Duszynski }
119c0644160STomasz Duszynski 
ms5611_temp_and_pressure_compensate(struct ms5611_state * st,s32 * temp,s32 * pressure)12017f442e7SMitja Spes static int ms5611_temp_and_pressure_compensate(struct ms5611_state *st,
1219690d81aSTomasz Duszynski 					       s32 *temp, s32 *pressure)
1229690d81aSTomasz Duszynski {
1239690d81aSTomasz Duszynski 	s32 t = *temp, p = *pressure;
1249690d81aSTomasz Duszynski 	s64 off, sens, dt;
1259690d81aSTomasz Duszynski 
12617f442e7SMitja Spes 	dt = t - (st->prom[5] << 8);
12717f442e7SMitja Spes 	off = ((s64)st->prom[2] << 16) + ((st->prom[4] * dt) >> 7);
12817f442e7SMitja Spes 	sens = ((s64)st->prom[1] << 15) + ((st->prom[3] * dt) >> 8);
1299690d81aSTomasz Duszynski 
13017f442e7SMitja Spes 	t = 2000 + ((st->prom[6] * dt) >> 23);
131c0644160STomasz Duszynski 	if (t < 2000) {
132c0644160STomasz Duszynski 		s64 off2, sens2, t2;
133c0644160STomasz Duszynski 
134c0644160STomasz Duszynski 		t2 = (dt * dt) >> 31;
135c0644160STomasz Duszynski 		off2 = (5 * (t - 2000) * (t - 2000)) >> 1;
136c0644160STomasz Duszynski 		sens2 = off2 >> 1;
137c0644160STomasz Duszynski 
138c0644160STomasz Duszynski 		if (t < -1500) {
139c0644160STomasz Duszynski 			s64 tmp = (t + 1500) * (t + 1500);
140c0644160STomasz Duszynski 
141c0644160STomasz Duszynski 			off2 += 7 * tmp;
142c0644160STomasz Duszynski 			sens2 += (11 * tmp) >> 1;
143c0644160STomasz Duszynski 		}
144c0644160STomasz Duszynski 
145c0644160STomasz Duszynski 		t -= t2;
146c0644160STomasz Duszynski 		off -= off2;
147c0644160STomasz Duszynski 		sens -= sens2;
148c0644160STomasz Duszynski 	}
149c0644160STomasz Duszynski 
150c0644160STomasz Duszynski 	*temp = t;
151c0644160STomasz Duszynski 	*pressure = (((p * sens) >> 21) - off) >> 15;
152c0644160STomasz Duszynski 
153c0644160STomasz Duszynski 	return 0;
154c0644160STomasz Duszynski }
155c0644160STomasz Duszynski 
ms5607_temp_and_pressure_compensate(struct ms5611_state * st,s32 * temp,s32 * pressure)15617f442e7SMitja Spes static int ms5607_temp_and_pressure_compensate(struct ms5611_state *st,
1579690d81aSTomasz Duszynski 					       s32 *temp, s32 *pressure)
1589690d81aSTomasz Duszynski {
1599690d81aSTomasz Duszynski 	s32 t = *temp, p = *pressure;
1609690d81aSTomasz Duszynski 	s64 off, sens, dt;
1619690d81aSTomasz Duszynski 
16217f442e7SMitja Spes 	dt = t - (st->prom[5] << 8);
16317f442e7SMitja Spes 	off = ((s64)st->prom[2] << 17) + ((st->prom[4] * dt) >> 6);
16417f442e7SMitja Spes 	sens = ((s64)st->prom[1] << 16) + ((st->prom[3] * dt) >> 7);
1659690d81aSTomasz Duszynski 
16617f442e7SMitja Spes 	t = 2000 + ((st->prom[6] * dt) >> 23);
1679690d81aSTomasz Duszynski 	if (t < 2000) {
168ce5b8fc1SGregor Boirie 		s64 off2, sens2, t2, tmp;
1699690d81aSTomasz Duszynski 
1709690d81aSTomasz Duszynski 		t2 = (dt * dt) >> 31;
171ce5b8fc1SGregor Boirie 		tmp = (t - 2000) * (t - 2000);
172ce5b8fc1SGregor Boirie 		off2 = (61 * tmp) >> 4;
173ce5b8fc1SGregor Boirie 		sens2 = tmp << 1;
1749690d81aSTomasz Duszynski 
1759690d81aSTomasz Duszynski 		if (t < -1500) {
176ce5b8fc1SGregor Boirie 			tmp = (t + 1500) * (t + 1500);
1779690d81aSTomasz Duszynski 			off2 += 15 * tmp;
178ce5b8fc1SGregor Boirie 			sens2 += 8 * tmp;
1799690d81aSTomasz Duszynski 		}
1809690d81aSTomasz Duszynski 
1819690d81aSTomasz Duszynski 		t -= t2;
1829690d81aSTomasz Duszynski 		off -= off2;
1839690d81aSTomasz Duszynski 		sens -= sens2;
1849690d81aSTomasz Duszynski 	}
1859690d81aSTomasz Duszynski 
1869690d81aSTomasz Duszynski 	*temp = t;
1879690d81aSTomasz Duszynski 	*pressure = (((p * sens) >> 21) - off) >> 15;
1889690d81aSTomasz Duszynski 
1899690d81aSTomasz Duszynski 	return 0;
1909690d81aSTomasz Duszynski }
1919690d81aSTomasz Duszynski 
ms5611_reset(struct iio_dev * indio_dev)192c0644160STomasz Duszynski static int ms5611_reset(struct iio_dev *indio_dev)
193c0644160STomasz Duszynski {
194c0644160STomasz Duszynski 	int ret;
195c0644160STomasz Duszynski 	struct ms5611_state *st = iio_priv(indio_dev);
196c0644160STomasz Duszynski 
197dc19fa63SLars-Peter Clausen 	ret = st->reset(st);
198c0644160STomasz Duszynski 	if (ret < 0) {
199c0644160STomasz Duszynski 		dev_err(&indio_dev->dev, "failed to reset device\n");
200c0644160STomasz Duszynski 		return ret;
201c0644160STomasz Duszynski 	}
202c0644160STomasz Duszynski 
203c0644160STomasz Duszynski 	usleep_range(3000, 4000);
204c0644160STomasz Duszynski 
205c0644160STomasz Duszynski 	return 0;
206c0644160STomasz Duszynski }
207c0644160STomasz Duszynski 
ms5611_trigger_handler(int irq,void * p)208713bbb4eSDaniel Baluta static irqreturn_t ms5611_trigger_handler(int irq, void *p)
209713bbb4eSDaniel Baluta {
210713bbb4eSDaniel Baluta 	struct iio_poll_func *pf = p;
211713bbb4eSDaniel Baluta 	struct iio_dev *indio_dev = pf->indio_dev;
212713bbb4eSDaniel Baluta 	struct ms5611_state *st = iio_priv(indio_dev);
2138db4afe1SJonathan Cameron 	/* Ensure buffer elements are naturally aligned */
2148db4afe1SJonathan Cameron 	struct {
2158db4afe1SJonathan Cameron 		s32 channels[2];
2168db4afe1SJonathan Cameron 		s64 ts __aligned(8);
2178db4afe1SJonathan Cameron 	} scan;
218713bbb4eSDaniel Baluta 	int ret;
219713bbb4eSDaniel Baluta 
220713bbb4eSDaniel Baluta 	mutex_lock(&st->lock);
2218db4afe1SJonathan Cameron 	ret = ms5611_read_temp_and_pressure(indio_dev, &scan.channels[1],
2228db4afe1SJonathan Cameron 					    &scan.channels[0]);
223713bbb4eSDaniel Baluta 	mutex_unlock(&st->lock);
224713bbb4eSDaniel Baluta 	if (ret < 0)
225713bbb4eSDaniel Baluta 		goto err;
226713bbb4eSDaniel Baluta 
2278db4afe1SJonathan Cameron 	iio_push_to_buffers_with_timestamp(indio_dev, &scan,
228bc2b7dabSGregor Boirie 					   iio_get_time_ns(indio_dev));
229713bbb4eSDaniel Baluta 
230713bbb4eSDaniel Baluta err:
231713bbb4eSDaniel Baluta 	iio_trigger_notify_done(indio_dev->trig);
232713bbb4eSDaniel Baluta 
233713bbb4eSDaniel Baluta 	return IRQ_HANDLED;
234713bbb4eSDaniel Baluta }
235713bbb4eSDaniel Baluta 
ms5611_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)236c0644160STomasz Duszynski static int ms5611_read_raw(struct iio_dev *indio_dev,
237c0644160STomasz Duszynski 			   struct iio_chan_spec const *chan,
238c0644160STomasz Duszynski 			   int *val, int *val2, long mask)
239c0644160STomasz Duszynski {
240c0644160STomasz Duszynski 	int ret;
241c0644160STomasz Duszynski 	s32 temp, pressure;
242c0644160STomasz Duszynski 	struct ms5611_state *st = iio_priv(indio_dev);
243c0644160STomasz Duszynski 
244c0644160STomasz Duszynski 	switch (mask) {
245c0644160STomasz Duszynski 	case IIO_CHAN_INFO_PROCESSED:
246c0644160STomasz Duszynski 		mutex_lock(&st->lock);
247c0644160STomasz Duszynski 		ret = ms5611_read_temp_and_pressure(indio_dev,
248c0644160STomasz Duszynski 						    &temp, &pressure);
249c0644160STomasz Duszynski 		mutex_unlock(&st->lock);
250c0644160STomasz Duszynski 		if (ret < 0)
251c0644160STomasz Duszynski 			return ret;
252c0644160STomasz Duszynski 
253c0644160STomasz Duszynski 		switch (chan->type) {
254c0644160STomasz Duszynski 		case IIO_TEMP:
255c0644160STomasz Duszynski 			*val = temp * 10;
256c0644160STomasz Duszynski 			return IIO_VAL_INT;
257c0644160STomasz Duszynski 		case IIO_PRESSURE:
258c0644160STomasz Duszynski 			*val = pressure / 1000;
259c0644160STomasz Duszynski 			*val2 = (pressure % 1000) * 1000;
260c0644160STomasz Duszynski 			return IIO_VAL_INT_PLUS_MICRO;
261c0644160STomasz Duszynski 		default:
262c0644160STomasz Duszynski 			return -EINVAL;
263c0644160STomasz Duszynski 		}
2641ad1ce9bSDaniel Baluta 	case IIO_CHAN_INFO_SCALE:
2651ad1ce9bSDaniel Baluta 		switch (chan->type) {
2661ad1ce9bSDaniel Baluta 		case IIO_TEMP:
2671ad1ce9bSDaniel Baluta 			*val = 10;
2681ad1ce9bSDaniel Baluta 			return IIO_VAL_INT;
2691ad1ce9bSDaniel Baluta 		case IIO_PRESSURE:
2701ad1ce9bSDaniel Baluta 			*val = 0;
2711ad1ce9bSDaniel Baluta 			*val2 = 1000;
2721ad1ce9bSDaniel Baluta 			return IIO_VAL_INT_PLUS_MICRO;
2731ad1ce9bSDaniel Baluta 		default:
2741ad1ce9bSDaniel Baluta 			return -EINVAL;
2751ad1ce9bSDaniel Baluta 		}
276033691a9SGregor Boirie 	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
277033691a9SGregor Boirie 		if (chan->type != IIO_TEMP && chan->type != IIO_PRESSURE)
278033691a9SGregor Boirie 			break;
279033691a9SGregor Boirie 		mutex_lock(&st->lock);
280033691a9SGregor Boirie 		if (chan->type == IIO_TEMP)
281033691a9SGregor Boirie 			*val = (int)st->temp_osr->rate;
282033691a9SGregor Boirie 		else
283033691a9SGregor Boirie 			*val = (int)st->pressure_osr->rate;
284033691a9SGregor Boirie 		mutex_unlock(&st->lock);
285033691a9SGregor Boirie 		return IIO_VAL_INT;
286c0644160STomasz Duszynski 	}
287c0644160STomasz Duszynski 
288c0644160STomasz Duszynski 	return -EINVAL;
289c0644160STomasz Duszynski }
290c0644160STomasz Duszynski 
ms5611_find_osr(int rate,const struct ms5611_osr * osr,size_t count)291033691a9SGregor Boirie static const struct ms5611_osr *ms5611_find_osr(int rate,
292033691a9SGregor Boirie 						const struct ms5611_osr *osr,
293033691a9SGregor Boirie 						size_t count)
294033691a9SGregor Boirie {
295033691a9SGregor Boirie 	unsigned int r;
296033691a9SGregor Boirie 
297033691a9SGregor Boirie 	for (r = 0; r < count; r++)
298033691a9SGregor Boirie 		if ((unsigned short)rate == osr[r].rate)
299033691a9SGregor Boirie 			break;
300033691a9SGregor Boirie 	if (r >= count)
301033691a9SGregor Boirie 		return NULL;
302033691a9SGregor Boirie 	return &osr[r];
303033691a9SGregor Boirie }
304033691a9SGregor Boirie 
ms5611_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)305033691a9SGregor Boirie static int ms5611_write_raw(struct iio_dev *indio_dev,
306033691a9SGregor Boirie 			    struct iio_chan_spec const *chan,
307033691a9SGregor Boirie 			    int val, int val2, long mask)
308033691a9SGregor Boirie {
309033691a9SGregor Boirie 	struct ms5611_state *st = iio_priv(indio_dev);
310033691a9SGregor Boirie 	const struct ms5611_osr *osr = NULL;
3113bc1abcdSAlison Schofield 	int ret;
312033691a9SGregor Boirie 
313033691a9SGregor Boirie 	if (mask != IIO_CHAN_INFO_OVERSAMPLING_RATIO)
314033691a9SGregor Boirie 		return -EINVAL;
315033691a9SGregor Boirie 
316033691a9SGregor Boirie 	if (chan->type == IIO_TEMP)
317033691a9SGregor Boirie 		osr = ms5611_find_osr(val, ms5611_avail_temp_osr,
318033691a9SGregor Boirie 				      ARRAY_SIZE(ms5611_avail_temp_osr));
319033691a9SGregor Boirie 	else if (chan->type == IIO_PRESSURE)
320033691a9SGregor Boirie 		osr = ms5611_find_osr(val, ms5611_avail_pressure_osr,
321033691a9SGregor Boirie 				      ARRAY_SIZE(ms5611_avail_pressure_osr));
322033691a9SGregor Boirie 	if (!osr)
323033691a9SGregor Boirie 		return -EINVAL;
324033691a9SGregor Boirie 
3253bc1abcdSAlison Schofield 	ret = iio_device_claim_direct_mode(indio_dev);
3263bc1abcdSAlison Schofield 	if (ret)
3273bc1abcdSAlison Schofield 		return ret;
328033691a9SGregor Boirie 
3293bc1abcdSAlison Schofield 	mutex_lock(&st->lock);
330033691a9SGregor Boirie 
331033691a9SGregor Boirie 	if (chan->type == IIO_TEMP)
332033691a9SGregor Boirie 		st->temp_osr = osr;
333033691a9SGregor Boirie 	else
334033691a9SGregor Boirie 		st->pressure_osr = osr;
335033691a9SGregor Boirie 
336033691a9SGregor Boirie 	mutex_unlock(&st->lock);
3373bc1abcdSAlison Schofield 	iio_device_release_direct_mode(indio_dev);
3383bc1abcdSAlison Schofield 
339033691a9SGregor Boirie 	return 0;
340033691a9SGregor Boirie }
341033691a9SGregor Boirie 
342713bbb4eSDaniel Baluta static const unsigned long ms5611_scan_masks[] = {0x3, 0};
343713bbb4eSDaniel Baluta 
344c0644160STomasz Duszynski static const struct iio_chan_spec ms5611_channels[] = {
345c0644160STomasz Duszynski 	{
346c0644160STomasz Duszynski 		.type = IIO_PRESSURE,
3471ad1ce9bSDaniel Baluta 		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
348033691a9SGregor Boirie 			BIT(IIO_CHAN_INFO_SCALE) |
349033691a9SGregor Boirie 			BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
350713bbb4eSDaniel Baluta 		.scan_index = 0,
351713bbb4eSDaniel Baluta 		.scan_type = {
352713bbb4eSDaniel Baluta 			.sign = 's',
353713bbb4eSDaniel Baluta 			.realbits = 32,
354713bbb4eSDaniel Baluta 			.storagebits = 32,
355713bbb4eSDaniel Baluta 			.endianness = IIO_CPU,
356713bbb4eSDaniel Baluta 		},
357c0644160STomasz Duszynski 	},
358c0644160STomasz Duszynski 	{
359c0644160STomasz Duszynski 		.type = IIO_TEMP,
3601ad1ce9bSDaniel Baluta 		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
361033691a9SGregor Boirie 			BIT(IIO_CHAN_INFO_SCALE) |
362033691a9SGregor Boirie 			BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
363713bbb4eSDaniel Baluta 		.scan_index = 1,
364713bbb4eSDaniel Baluta 		.scan_type = {
365713bbb4eSDaniel Baluta 			.sign = 's',
366713bbb4eSDaniel Baluta 			.realbits = 32,
367713bbb4eSDaniel Baluta 			.storagebits = 32,
368713bbb4eSDaniel Baluta 			.endianness = IIO_CPU,
369713bbb4eSDaniel Baluta 		},
370713bbb4eSDaniel Baluta 	},
371713bbb4eSDaniel Baluta 	IIO_CHAN_SOFT_TIMESTAMP(2),
372c0644160STomasz Duszynski };
373c0644160STomasz Duszynski 
374c0644160STomasz Duszynski static const struct iio_info ms5611_info = {
375c0644160STomasz Duszynski 	.read_raw = &ms5611_read_raw,
376033691a9SGregor Boirie 	.write_raw = &ms5611_write_raw,
377033691a9SGregor Boirie 	.attrs = &ms5611_attribute_group,
378c0644160STomasz Duszynski };
379c0644160STomasz Duszynski 
ms5611_init(struct iio_dev * indio_dev)380c0644160STomasz Duszynski static int ms5611_init(struct iio_dev *indio_dev)
381c0644160STomasz Duszynski {
382c0644160STomasz Duszynski 	int ret;
3833145229fSGrégor Boirie 
3843145229fSGrégor Boirie 	/* Enable attached regulator if any. */
385122ef59aSJonathan Cameron 	ret = devm_regulator_get_enable(indio_dev->dev.parent, "vdd");
386122ef59aSJonathan Cameron 	if (ret)
3873145229fSGrégor Boirie 		return ret;
388c0644160STomasz Duszynski 
389c0644160STomasz Duszynski 	ret = ms5611_reset(indio_dev);
390c0644160STomasz Duszynski 	if (ret < 0)
391122ef59aSJonathan Cameron 		return ret;
392c0644160STomasz Duszynski 
393334ecdd0SGregor Boirie 	ret = ms5611_read_prom(indio_dev);
394334ecdd0SGregor Boirie 	if (ret < 0)
395122ef59aSJonathan Cameron 		return ret;
396334ecdd0SGregor Boirie 
397334ecdd0SGregor Boirie 	return 0;
398c0644160STomasz Duszynski }
399c0644160STomasz Duszynski 
ms5611_probe(struct iio_dev * indio_dev,struct device * dev,const char * name,int type)400eac635ebSGrégor Boirie int ms5611_probe(struct iio_dev *indio_dev, struct device *dev,
401eac635ebSGrégor Boirie 		 const char *name, int type)
402c0644160STomasz Duszynski {
403c0644160STomasz Duszynski 	int ret;
404c0644160STomasz Duszynski 	struct ms5611_state *st = iio_priv(indio_dev);
405c0644160STomasz Duszynski 
406c0644160STomasz Duszynski 	mutex_init(&st->lock);
40717f442e7SMitja Spes 
40817f442e7SMitja Spes 	switch (type) {
40917f442e7SMitja Spes 	case MS5611:
41017f442e7SMitja Spes 		st->compensate_temp_and_pressure =
41117f442e7SMitja Spes 			ms5611_temp_and_pressure_compensate;
41217f442e7SMitja Spes 		break;
41317f442e7SMitja Spes 	case MS5607:
41417f442e7SMitja Spes 		st->compensate_temp_and_pressure =
41517f442e7SMitja Spes 			ms5607_temp_and_pressure_compensate;
41617f442e7SMitja Spes 		break;
41717f442e7SMitja Spes 	default:
41817f442e7SMitja Spes 		return -EINVAL;
41917f442e7SMitja Spes 	}
42017f442e7SMitja Spes 
421033691a9SGregor Boirie 	st->temp_osr =
422033691a9SGregor Boirie 		&ms5611_avail_temp_osr[ARRAY_SIZE(ms5611_avail_temp_osr) - 1];
423033691a9SGregor Boirie 	st->pressure_osr =
424033691a9SGregor Boirie 		&ms5611_avail_pressure_osr[ARRAY_SIZE(ms5611_avail_pressure_osr)
425033691a9SGregor Boirie 					   - 1];
426eac635ebSGrégor Boirie 	indio_dev->name = name;
427c0644160STomasz Duszynski 	indio_dev->info = &ms5611_info;
428c0644160STomasz Duszynski 	indio_dev->channels = ms5611_channels;
429c0644160STomasz Duszynski 	indio_dev->num_channels = ARRAY_SIZE(ms5611_channels);
430c0644160STomasz Duszynski 	indio_dev->modes = INDIO_DIRECT_MODE;
431713bbb4eSDaniel Baluta 	indio_dev->available_scan_masks = ms5611_scan_masks;
432c0644160STomasz Duszynski 
433c0644160STomasz Duszynski 	ret = ms5611_init(indio_dev);
434c0644160STomasz Duszynski 	if (ret < 0)
435c0644160STomasz Duszynski 		return ret;
436c0644160STomasz Duszynski 
437caa6693eSJonathan Cameron 	ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
438713bbb4eSDaniel Baluta 					 ms5611_trigger_handler, NULL);
439713bbb4eSDaniel Baluta 	if (ret < 0) {
440713bbb4eSDaniel Baluta 		dev_err(dev, "iio triggered buffer setup failed\n");
441122ef59aSJonathan Cameron 		return ret;
442713bbb4eSDaniel Baluta 	}
443713bbb4eSDaniel Baluta 
444caa6693eSJonathan Cameron 	ret = devm_iio_device_register(dev, indio_dev);
445713bbb4eSDaniel Baluta 	if (ret < 0) {
446713bbb4eSDaniel Baluta 		dev_err(dev, "unable to register iio device\n");
447caa6693eSJonathan Cameron 		return ret;
448713bbb4eSDaniel Baluta 	}
449713bbb4eSDaniel Baluta 
450713bbb4eSDaniel Baluta 	return 0;
451c0644160STomasz Duszynski }
4521980d4a1SJonathan Cameron EXPORT_SYMBOL_NS(ms5611_probe, IIO_MS5611);
453c0644160STomasz Duszynski 
454c0644160STomasz Duszynski MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
455c0644160STomasz Duszynski MODULE_DESCRIPTION("MS5611 core driver");
456c0644160STomasz Duszynski MODULE_LICENSE("GPL v2");
457