xref: /linux/drivers/iio/pressure/ms5611_core.c (revision cdd30ebb1b9f36159d66f088b61aee264e649d7a)
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 		s64 ts __aligned(8);
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 	int ret;
312 
313 	if (mask != IIO_CHAN_INFO_OVERSAMPLING_RATIO)
314 		return -EINVAL;
315 
316 	if (chan->type == IIO_TEMP)
317 		osr = ms5611_find_osr(val, ms5611_avail_temp_osr,
318 				      ARRAY_SIZE(ms5611_avail_temp_osr));
319 	else if (chan->type == IIO_PRESSURE)
320 		osr = ms5611_find_osr(val, ms5611_avail_pressure_osr,
321 				      ARRAY_SIZE(ms5611_avail_pressure_osr));
322 	if (!osr)
323 		return -EINVAL;
324 
325 	ret = iio_device_claim_direct_mode(indio_dev);
326 	if (ret)
327 		return ret;
328 
329 	mutex_lock(&st->lock);
330 
331 	if (chan->type == IIO_TEMP)
332 		st->temp_osr = osr;
333 	else
334 		st->pressure_osr = osr;
335 
336 	mutex_unlock(&st->lock);
337 	iio_device_release_direct_mode(indio_dev);
338 
339 	return 0;
340 }
341 
342 static const unsigned long ms5611_scan_masks[] = {0x3, 0};
343 
344 static const struct iio_chan_spec ms5611_channels[] = {
345 	{
346 		.type = IIO_PRESSURE,
347 		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
348 			BIT(IIO_CHAN_INFO_SCALE) |
349 			BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
350 		.scan_index = 0,
351 		.scan_type = {
352 			.sign = 's',
353 			.realbits = 32,
354 			.storagebits = 32,
355 			.endianness = IIO_CPU,
356 		},
357 	},
358 	{
359 		.type = IIO_TEMP,
360 		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
361 			BIT(IIO_CHAN_INFO_SCALE) |
362 			BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
363 		.scan_index = 1,
364 		.scan_type = {
365 			.sign = 's',
366 			.realbits = 32,
367 			.storagebits = 32,
368 			.endianness = IIO_CPU,
369 		},
370 	},
371 	IIO_CHAN_SOFT_TIMESTAMP(2),
372 };
373 
374 static const struct iio_info ms5611_info = {
375 	.read_raw = &ms5611_read_raw,
376 	.write_raw = &ms5611_write_raw,
377 	.attrs = &ms5611_attribute_group,
378 };
379 
ms5611_init(struct iio_dev * indio_dev)380 static int ms5611_init(struct iio_dev *indio_dev)
381 {
382 	int ret;
383 
384 	/* Enable attached regulator if any. */
385 	ret = devm_regulator_get_enable(indio_dev->dev.parent, "vdd");
386 	if (ret)
387 		return ret;
388 
389 	ret = ms5611_reset(indio_dev);
390 	if (ret < 0)
391 		return ret;
392 
393 	ret = ms5611_read_prom(indio_dev);
394 	if (ret < 0)
395 		return ret;
396 
397 	return 0;
398 }
399 
ms5611_probe(struct iio_dev * indio_dev,struct device * dev,const char * name,int type)400 int ms5611_probe(struct iio_dev *indio_dev, struct device *dev,
401 		 const char *name, int type)
402 {
403 	int ret;
404 	struct ms5611_state *st = iio_priv(indio_dev);
405 
406 	mutex_init(&st->lock);
407 
408 	switch (type) {
409 	case MS5611:
410 		st->compensate_temp_and_pressure =
411 			ms5611_temp_and_pressure_compensate;
412 		break;
413 	case MS5607:
414 		st->compensate_temp_and_pressure =
415 			ms5607_temp_and_pressure_compensate;
416 		break;
417 	default:
418 		return -EINVAL;
419 	}
420 
421 	st->temp_osr =
422 		&ms5611_avail_temp_osr[ARRAY_SIZE(ms5611_avail_temp_osr) - 1];
423 	st->pressure_osr =
424 		&ms5611_avail_pressure_osr[ARRAY_SIZE(ms5611_avail_pressure_osr)
425 					   - 1];
426 	indio_dev->name = name;
427 	indio_dev->info = &ms5611_info;
428 	indio_dev->channels = ms5611_channels;
429 	indio_dev->num_channels = ARRAY_SIZE(ms5611_channels);
430 	indio_dev->modes = INDIO_DIRECT_MODE;
431 	indio_dev->available_scan_masks = ms5611_scan_masks;
432 
433 	ret = ms5611_init(indio_dev);
434 	if (ret < 0)
435 		return ret;
436 
437 	ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
438 					 ms5611_trigger_handler, NULL);
439 	if (ret < 0) {
440 		dev_err(dev, "iio triggered buffer setup failed\n");
441 		return ret;
442 	}
443 
444 	ret = devm_iio_device_register(dev, indio_dev);
445 	if (ret < 0) {
446 		dev_err(dev, "unable to register iio device\n");
447 		return ret;
448 	}
449 
450 	return 0;
451 }
452 EXPORT_SYMBOL_NS(ms5611_probe, "IIO_MS5611");
453 
454 MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
455 MODULE_DESCRIPTION("MS5611 core driver");
456 MODULE_LICENSE("GPL v2");
457