xref: /linux/drivers/iio/pressure/ms5611_core.c (revision c26f4fbd58375bd6ef74f95eb73d61762ad97c59)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * MS5611 pressure and temperature sensor driver
4  *
5  * Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
6  *
7  * Data sheet:
8  *  http://www.meas-spec.com/downloads/MS5611-01BA03.pdf
9  *  http://www.meas-spec.com/downloads/MS5607-02BA03.pdf
10  *
11  */
12 
13 #include <linux/module.h>
14 #include <linux/iio/iio.h>
15 #include <linux/delay.h>
16 #include <linux/regulator/consumer.h>
17 
18 #include <linux/iio/sysfs.h>
19 #include <linux/iio/buffer.h>
20 #include <linux/iio/triggered_buffer.h>
21 #include <linux/iio/trigger_consumer.h>
22 #include "ms5611.h"
23 
24 #define MS5611_INIT_OSR(_cmd, _conv_usec, _rate) \
25 	{ .cmd = _cmd, .conv_usec = _conv_usec, .rate = _rate }
26 
27 static const struct ms5611_osr ms5611_avail_pressure_osr[] = {
28 	MS5611_INIT_OSR(0x40, 600,  256),
29 	MS5611_INIT_OSR(0x42, 1170, 512),
30 	MS5611_INIT_OSR(0x44, 2280, 1024),
31 	MS5611_INIT_OSR(0x46, 4540, 2048),
32 	MS5611_INIT_OSR(0x48, 9040, 4096)
33 };
34 
35 static const struct ms5611_osr ms5611_avail_temp_osr[] = {
36 	MS5611_INIT_OSR(0x50, 600,  256),
37 	MS5611_INIT_OSR(0x52, 1170, 512),
38 	MS5611_INIT_OSR(0x54, 2280, 1024),
39 	MS5611_INIT_OSR(0x56, 4540, 2048),
40 	MS5611_INIT_OSR(0x58, 9040, 4096)
41 };
42 
43 static const char ms5611_show_osr[] = "256 512 1024 2048 4096";
44 
45 static IIO_CONST_ATTR(oversampling_ratio_available, ms5611_show_osr);
46 
47 static struct attribute *ms5611_attributes[] = {
48 	&iio_const_attr_oversampling_ratio_available.dev_attr.attr,
49 	NULL,
50 };
51 
52 static const struct attribute_group ms5611_attribute_group = {
53 	.attrs = ms5611_attributes,
54 };
55 
ms5611_prom_is_valid(u16 * prom,size_t len)56 static bool ms5611_prom_is_valid(u16 *prom, size_t len)
57 {
58 	int i, j;
59 	uint16_t crc = 0, crc_orig = prom[7] & 0x000F;
60 
61 	prom[7] &= 0xFF00;
62 
63 	for (i = 0; i < len * 2; i++) {
64 		if (i % 2 == 1)
65 			crc ^= prom[i >> 1] & 0x00FF;
66 		else
67 			crc ^= prom[i >> 1] >> 8;
68 
69 		for (j = 0; j < 8; j++) {
70 			if (crc & 0x8000)
71 				crc = (crc << 1) ^ 0x3000;
72 			else
73 				crc <<= 1;
74 		}
75 	}
76 
77 	crc = (crc >> 12) & 0x000F;
78 
79 	return crc == crc_orig;
80 }
81 
ms5611_read_prom(struct iio_dev * indio_dev)82 static int ms5611_read_prom(struct iio_dev *indio_dev)
83 {
84 	int ret, i;
85 	struct ms5611_state *st = iio_priv(indio_dev);
86 
87 	for (i = 0; i < MS5611_PROM_WORDS_NB; i++) {
88 		ret = st->read_prom_word(st, i, &st->prom[i]);
89 		if (ret < 0) {
90 			dev_err(&indio_dev->dev,
91 				"failed to read prom at %d\n", i);
92 			return ret;
93 		}
94 	}
95 
96 	if (!ms5611_prom_is_valid(st->prom, MS5611_PROM_WORDS_NB)) {
97 		dev_err(&indio_dev->dev, "PROM integrity check failed\n");
98 		return -ENODEV;
99 	}
100 
101 	return 0;
102 }
103 
ms5611_read_temp_and_pressure(struct iio_dev * indio_dev,s32 * temp,s32 * pressure)104 static int ms5611_read_temp_and_pressure(struct iio_dev *indio_dev,
105 					 s32 *temp, s32 *pressure)
106 {
107 	int ret;
108 	struct ms5611_state *st = iio_priv(indio_dev);
109 
110 	ret = st->read_adc_temp_and_pressure(st, temp, pressure);
111 	if (ret < 0) {
112 		dev_err(&indio_dev->dev,
113 			"failed to read temperature and pressure\n");
114 		return ret;
115 	}
116 
117 	return st->compensate_temp_and_pressure(st, temp, pressure);
118 }
119 
ms5611_temp_and_pressure_compensate(struct ms5611_state * st,s32 * temp,s32 * pressure)120 static int ms5611_temp_and_pressure_compensate(struct ms5611_state *st,
121 					       s32 *temp, s32 *pressure)
122 {
123 	s32 t = *temp, p = *pressure;
124 	s64 off, sens, dt;
125 
126 	dt = t - (st->prom[5] << 8);
127 	off = ((s64)st->prom[2] << 16) + ((st->prom[4] * dt) >> 7);
128 	sens = ((s64)st->prom[1] << 15) + ((st->prom[3] * dt) >> 8);
129 
130 	t = 2000 + ((st->prom[6] * dt) >> 23);
131 	if (t < 2000) {
132 		s64 off2, sens2, t2;
133 
134 		t2 = (dt * dt) >> 31;
135 		off2 = (5 * (t - 2000) * (t - 2000)) >> 1;
136 		sens2 = off2 >> 1;
137 
138 		if (t < -1500) {
139 			s64 tmp = (t + 1500) * (t + 1500);
140 
141 			off2 += 7 * tmp;
142 			sens2 += (11 * tmp) >> 1;
143 		}
144 
145 		t -= t2;
146 		off -= off2;
147 		sens -= sens2;
148 	}
149 
150 	*temp = t;
151 	*pressure = (((p * sens) >> 21) - off) >> 15;
152 
153 	return 0;
154 }
155 
ms5607_temp_and_pressure_compensate(struct ms5611_state * st,s32 * temp,s32 * pressure)156 static int ms5607_temp_and_pressure_compensate(struct ms5611_state *st,
157 					       s32 *temp, s32 *pressure)
158 {
159 	s32 t = *temp, p = *pressure;
160 	s64 off, sens, dt;
161 
162 	dt = t - (st->prom[5] << 8);
163 	off = ((s64)st->prom[2] << 17) + ((st->prom[4] * dt) >> 6);
164 	sens = ((s64)st->prom[1] << 16) + ((st->prom[3] * dt) >> 7);
165 
166 	t = 2000 + ((st->prom[6] * dt) >> 23);
167 	if (t < 2000) {
168 		s64 off2, sens2, t2, tmp;
169 
170 		t2 = (dt * dt) >> 31;
171 		tmp = (t - 2000) * (t - 2000);
172 		off2 = (61 * tmp) >> 4;
173 		sens2 = tmp << 1;
174 
175 		if (t < -1500) {
176 			tmp = (t + 1500) * (t + 1500);
177 			off2 += 15 * tmp;
178 			sens2 += 8 * tmp;
179 		}
180 
181 		t -= t2;
182 		off -= off2;
183 		sens -= sens2;
184 	}
185 
186 	*temp = t;
187 	*pressure = (((p * sens) >> 21) - off) >> 15;
188 
189 	return 0;
190 }
191 
ms5611_reset(struct iio_dev * indio_dev)192 static int ms5611_reset(struct iio_dev *indio_dev)
193 {
194 	int ret;
195 	struct ms5611_state *st = iio_priv(indio_dev);
196 
197 	ret = st->reset(st);
198 	if (ret < 0) {
199 		dev_err(&indio_dev->dev, "failed to reset device\n");
200 		return ret;
201 	}
202 
203 	usleep_range(3000, 4000);
204 
205 	return 0;
206 }
207 
ms5611_trigger_handler(int irq,void * p)208 static irqreturn_t ms5611_trigger_handler(int irq, void *p)
209 {
210 	struct iio_poll_func *pf = p;
211 	struct iio_dev *indio_dev = pf->indio_dev;
212 	struct ms5611_state *st = iio_priv(indio_dev);
213 	/* Ensure buffer elements are naturally aligned */
214 	struct {
215 		s32 channels[2];
216 		aligned_s64 ts;
217 	} scan;
218 	int ret;
219 
220 	mutex_lock(&st->lock);
221 	ret = ms5611_read_temp_and_pressure(indio_dev, &scan.channels[1],
222 					    &scan.channels[0]);
223 	mutex_unlock(&st->lock);
224 	if (ret < 0)
225 		goto err;
226 
227 	iio_push_to_buffers_with_timestamp(indio_dev, &scan,
228 					   iio_get_time_ns(indio_dev));
229 
230 err:
231 	iio_trigger_notify_done(indio_dev->trig);
232 
233 	return IRQ_HANDLED;
234 }
235 
ms5611_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)236 static int ms5611_read_raw(struct iio_dev *indio_dev,
237 			   struct iio_chan_spec const *chan,
238 			   int *val, int *val2, long mask)
239 {
240 	int ret;
241 	s32 temp, pressure;
242 	struct ms5611_state *st = iio_priv(indio_dev);
243 
244 	switch (mask) {
245 	case IIO_CHAN_INFO_PROCESSED:
246 		mutex_lock(&st->lock);
247 		ret = ms5611_read_temp_and_pressure(indio_dev,
248 						    &temp, &pressure);
249 		mutex_unlock(&st->lock);
250 		if (ret < 0)
251 			return ret;
252 
253 		switch (chan->type) {
254 		case IIO_TEMP:
255 			*val = temp * 10;
256 			return IIO_VAL_INT;
257 		case IIO_PRESSURE:
258 			*val = pressure / 1000;
259 			*val2 = (pressure % 1000) * 1000;
260 			return IIO_VAL_INT_PLUS_MICRO;
261 		default:
262 			return -EINVAL;
263 		}
264 	case IIO_CHAN_INFO_SCALE:
265 		switch (chan->type) {
266 		case IIO_TEMP:
267 			*val = 10;
268 			return IIO_VAL_INT;
269 		case IIO_PRESSURE:
270 			*val = 0;
271 			*val2 = 1000;
272 			return IIO_VAL_INT_PLUS_MICRO;
273 		default:
274 			return -EINVAL;
275 		}
276 	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
277 		if (chan->type != IIO_TEMP && chan->type != IIO_PRESSURE)
278 			break;
279 		mutex_lock(&st->lock);
280 		if (chan->type == IIO_TEMP)
281 			*val = (int)st->temp_osr->rate;
282 		else
283 			*val = (int)st->pressure_osr->rate;
284 		mutex_unlock(&st->lock);
285 		return IIO_VAL_INT;
286 	}
287 
288 	return -EINVAL;
289 }
290 
ms5611_find_osr(int rate,const struct ms5611_osr * osr,size_t count)291 static const struct ms5611_osr *ms5611_find_osr(int rate,
292 						const struct ms5611_osr *osr,
293 						size_t count)
294 {
295 	unsigned int r;
296 
297 	for (r = 0; r < count; r++)
298 		if ((unsigned short)rate == osr[r].rate)
299 			break;
300 	if (r >= count)
301 		return NULL;
302 	return &osr[r];
303 }
304 
ms5611_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)305 static int ms5611_write_raw(struct iio_dev *indio_dev,
306 			    struct iio_chan_spec const *chan,
307 			    int val, int val2, long mask)
308 {
309 	struct ms5611_state *st = iio_priv(indio_dev);
310 	const struct ms5611_osr *osr = NULL;
311 
312 	if (mask != IIO_CHAN_INFO_OVERSAMPLING_RATIO)
313 		return -EINVAL;
314 
315 	if (chan->type == IIO_TEMP)
316 		osr = ms5611_find_osr(val, ms5611_avail_temp_osr,
317 				      ARRAY_SIZE(ms5611_avail_temp_osr));
318 	else if (chan->type == IIO_PRESSURE)
319 		osr = ms5611_find_osr(val, ms5611_avail_pressure_osr,
320 				      ARRAY_SIZE(ms5611_avail_pressure_osr));
321 	if (!osr)
322 		return -EINVAL;
323 
324 	if (!iio_device_claim_direct(indio_dev))
325 		return -EBUSY;
326 
327 	mutex_lock(&st->lock);
328 
329 	if (chan->type == IIO_TEMP)
330 		st->temp_osr = osr;
331 	else
332 		st->pressure_osr = osr;
333 
334 	mutex_unlock(&st->lock);
335 	iio_device_release_direct(indio_dev);
336 
337 	return 0;
338 }
339 
340 static const unsigned long ms5611_scan_masks[] = {0x3, 0};
341 
342 static const struct iio_chan_spec ms5611_channels[] = {
343 	{
344 		.type = IIO_PRESSURE,
345 		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
346 			BIT(IIO_CHAN_INFO_SCALE) |
347 			BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
348 		.scan_index = 0,
349 		.scan_type = {
350 			.sign = 's',
351 			.realbits = 32,
352 			.storagebits = 32,
353 			.endianness = IIO_CPU,
354 		},
355 	},
356 	{
357 		.type = IIO_TEMP,
358 		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
359 			BIT(IIO_CHAN_INFO_SCALE) |
360 			BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
361 		.scan_index = 1,
362 		.scan_type = {
363 			.sign = 's',
364 			.realbits = 32,
365 			.storagebits = 32,
366 			.endianness = IIO_CPU,
367 		},
368 	},
369 	IIO_CHAN_SOFT_TIMESTAMP(2),
370 };
371 
372 static const struct iio_info ms5611_info = {
373 	.read_raw = &ms5611_read_raw,
374 	.write_raw = &ms5611_write_raw,
375 	.attrs = &ms5611_attribute_group,
376 };
377 
ms5611_init(struct iio_dev * indio_dev)378 static int ms5611_init(struct iio_dev *indio_dev)
379 {
380 	int ret;
381 
382 	/* Enable attached regulator if any. */
383 	ret = devm_regulator_get_enable(indio_dev->dev.parent, "vdd");
384 	if (ret)
385 		return ret;
386 
387 	ret = ms5611_reset(indio_dev);
388 	if (ret < 0)
389 		return ret;
390 
391 	ret = ms5611_read_prom(indio_dev);
392 	if (ret < 0)
393 		return ret;
394 
395 	return 0;
396 }
397 
ms5611_probe(struct iio_dev * indio_dev,struct device * dev,const char * name,int type)398 int ms5611_probe(struct iio_dev *indio_dev, struct device *dev,
399 		 const char *name, int type)
400 {
401 	int ret;
402 	struct ms5611_state *st = iio_priv(indio_dev);
403 
404 	mutex_init(&st->lock);
405 
406 	switch (type) {
407 	case MS5611:
408 		st->compensate_temp_and_pressure =
409 			ms5611_temp_and_pressure_compensate;
410 		break;
411 	case MS5607:
412 		st->compensate_temp_and_pressure =
413 			ms5607_temp_and_pressure_compensate;
414 		break;
415 	default:
416 		return -EINVAL;
417 	}
418 
419 	st->temp_osr =
420 		&ms5611_avail_temp_osr[ARRAY_SIZE(ms5611_avail_temp_osr) - 1];
421 	st->pressure_osr =
422 		&ms5611_avail_pressure_osr[ARRAY_SIZE(ms5611_avail_pressure_osr)
423 					   - 1];
424 	indio_dev->name = name;
425 	indio_dev->info = &ms5611_info;
426 	indio_dev->channels = ms5611_channels;
427 	indio_dev->num_channels = ARRAY_SIZE(ms5611_channels);
428 	indio_dev->modes = INDIO_DIRECT_MODE;
429 	indio_dev->available_scan_masks = ms5611_scan_masks;
430 
431 	ret = ms5611_init(indio_dev);
432 	if (ret < 0)
433 		return ret;
434 
435 	ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
436 					 ms5611_trigger_handler, NULL);
437 	if (ret < 0) {
438 		dev_err(dev, "iio triggered buffer setup failed\n");
439 		return ret;
440 	}
441 
442 	ret = devm_iio_device_register(dev, indio_dev);
443 	if (ret < 0) {
444 		dev_err(dev, "unable to register iio device\n");
445 		return ret;
446 	}
447 
448 	return 0;
449 }
450 EXPORT_SYMBOL_NS(ms5611_probe, "IIO_MS5611");
451 
452 MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
453 MODULE_DESCRIPTION("MS5611 core driver");
454 MODULE_LICENSE("GPL v2");
455