ms5611_core.c (11094B)
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 27static 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 35static 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 43static const char ms5611_show_osr[] = "256 512 1024 2048 4096"; 44 45static IIO_CONST_ATTR(oversampling_ratio_available, ms5611_show_osr); 46 47static struct attribute *ms5611_attributes[] = { 48 &iio_const_attr_oversampling_ratio_available.dev_attr.attr, 49 NULL, 50}; 51 52static const struct attribute_group ms5611_attribute_group = { 53 .attrs = ms5611_attributes, 54}; 55 56static 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_orig != 0x0000 && crc == crc_orig; 80} 81 82static 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->chip_info->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->chip_info->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 104static 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->chip_info->temp_and_pressure_compensate(st->chip_info, 118 temp, pressure); 119} 120 121static int ms5611_temp_and_pressure_compensate(struct ms5611_chip_info *chip_info, 122 s32 *temp, s32 *pressure) 123{ 124 s32 t = *temp, p = *pressure; 125 s64 off, sens, dt; 126 127 dt = t - (chip_info->prom[5] << 8); 128 off = ((s64)chip_info->prom[2] << 16) + ((chip_info->prom[4] * dt) >> 7); 129 sens = ((s64)chip_info->prom[1] << 15) + ((chip_info->prom[3] * dt) >> 8); 130 131 t = 2000 + ((chip_info->prom[6] * dt) >> 23); 132 if (t < 2000) { 133 s64 off2, sens2, t2; 134 135 t2 = (dt * dt) >> 31; 136 off2 = (5 * (t - 2000) * (t - 2000)) >> 1; 137 sens2 = off2 >> 1; 138 139 if (t < -1500) { 140 s64 tmp = (t + 1500) * (t + 1500); 141 142 off2 += 7 * tmp; 143 sens2 += (11 * tmp) >> 1; 144 } 145 146 t -= t2; 147 off -= off2; 148 sens -= sens2; 149 } 150 151 *temp = t; 152 *pressure = (((p * sens) >> 21) - off) >> 15; 153 154 return 0; 155} 156 157static int ms5607_temp_and_pressure_compensate(struct ms5611_chip_info *chip_info, 158 s32 *temp, s32 *pressure) 159{ 160 s32 t = *temp, p = *pressure; 161 s64 off, sens, dt; 162 163 dt = t - (chip_info->prom[5] << 8); 164 off = ((s64)chip_info->prom[2] << 17) + ((chip_info->prom[4] * dt) >> 6); 165 sens = ((s64)chip_info->prom[1] << 16) + ((chip_info->prom[3] * dt) >> 7); 166 167 t = 2000 + ((chip_info->prom[6] * dt) >> 23); 168 if (t < 2000) { 169 s64 off2, sens2, t2, tmp; 170 171 t2 = (dt * dt) >> 31; 172 tmp = (t - 2000) * (t - 2000); 173 off2 = (61 * tmp) >> 4; 174 sens2 = tmp << 1; 175 176 if (t < -1500) { 177 tmp = (t + 1500) * (t + 1500); 178 off2 += 15 * tmp; 179 sens2 += 8 * tmp; 180 } 181 182 t -= t2; 183 off -= off2; 184 sens -= sens2; 185 } 186 187 *temp = t; 188 *pressure = (((p * sens) >> 21) - off) >> 15; 189 190 return 0; 191} 192 193static int ms5611_reset(struct iio_dev *indio_dev) 194{ 195 int ret; 196 struct ms5611_state *st = iio_priv(indio_dev); 197 198 ret = st->reset(st); 199 if (ret < 0) { 200 dev_err(&indio_dev->dev, "failed to reset device\n"); 201 return ret; 202 } 203 204 usleep_range(3000, 4000); 205 206 return 0; 207} 208 209static irqreturn_t ms5611_trigger_handler(int irq, void *p) 210{ 211 struct iio_poll_func *pf = p; 212 struct iio_dev *indio_dev = pf->indio_dev; 213 struct ms5611_state *st = iio_priv(indio_dev); 214 /* Ensure buffer elements are naturally aligned */ 215 struct { 216 s32 channels[2]; 217 s64 ts __aligned(8); 218 } scan; 219 int ret; 220 221 mutex_lock(&st->lock); 222 ret = ms5611_read_temp_and_pressure(indio_dev, &scan.channels[1], 223 &scan.channels[0]); 224 mutex_unlock(&st->lock); 225 if (ret < 0) 226 goto err; 227 228 iio_push_to_buffers_with_timestamp(indio_dev, &scan, 229 iio_get_time_ns(indio_dev)); 230 231err: 232 iio_trigger_notify_done(indio_dev->trig); 233 234 return IRQ_HANDLED; 235} 236 237static int ms5611_read_raw(struct iio_dev *indio_dev, 238 struct iio_chan_spec const *chan, 239 int *val, int *val2, long mask) 240{ 241 int ret; 242 s32 temp, pressure; 243 struct ms5611_state *st = iio_priv(indio_dev); 244 245 switch (mask) { 246 case IIO_CHAN_INFO_PROCESSED: 247 mutex_lock(&st->lock); 248 ret = ms5611_read_temp_and_pressure(indio_dev, 249 &temp, &pressure); 250 mutex_unlock(&st->lock); 251 if (ret < 0) 252 return ret; 253 254 switch (chan->type) { 255 case IIO_TEMP: 256 *val = temp * 10; 257 return IIO_VAL_INT; 258 case IIO_PRESSURE: 259 *val = pressure / 1000; 260 *val2 = (pressure % 1000) * 1000; 261 return IIO_VAL_INT_PLUS_MICRO; 262 default: 263 return -EINVAL; 264 } 265 case IIO_CHAN_INFO_SCALE: 266 switch (chan->type) { 267 case IIO_TEMP: 268 *val = 10; 269 return IIO_VAL_INT; 270 case IIO_PRESSURE: 271 *val = 0; 272 *val2 = 1000; 273 return IIO_VAL_INT_PLUS_MICRO; 274 default: 275 return -EINVAL; 276 } 277 case IIO_CHAN_INFO_OVERSAMPLING_RATIO: 278 if (chan->type != IIO_TEMP && chan->type != IIO_PRESSURE) 279 break; 280 mutex_lock(&st->lock); 281 if (chan->type == IIO_TEMP) 282 *val = (int)st->temp_osr->rate; 283 else 284 *val = (int)st->pressure_osr->rate; 285 mutex_unlock(&st->lock); 286 return IIO_VAL_INT; 287 } 288 289 return -EINVAL; 290} 291 292static const struct ms5611_osr *ms5611_find_osr(int rate, 293 const struct ms5611_osr *osr, 294 size_t count) 295{ 296 unsigned int r; 297 298 for (r = 0; r < count; r++) 299 if ((unsigned short)rate == osr[r].rate) 300 break; 301 if (r >= count) 302 return NULL; 303 return &osr[r]; 304} 305 306static int ms5611_write_raw(struct iio_dev *indio_dev, 307 struct iio_chan_spec const *chan, 308 int val, int val2, long mask) 309{ 310 struct ms5611_state *st = iio_priv(indio_dev); 311 const struct ms5611_osr *osr = NULL; 312 int ret; 313 314 if (mask != IIO_CHAN_INFO_OVERSAMPLING_RATIO) 315 return -EINVAL; 316 317 if (chan->type == IIO_TEMP) 318 osr = ms5611_find_osr(val, ms5611_avail_temp_osr, 319 ARRAY_SIZE(ms5611_avail_temp_osr)); 320 else if (chan->type == IIO_PRESSURE) 321 osr = ms5611_find_osr(val, ms5611_avail_pressure_osr, 322 ARRAY_SIZE(ms5611_avail_pressure_osr)); 323 if (!osr) 324 return -EINVAL; 325 326 ret = iio_device_claim_direct_mode(indio_dev); 327 if (ret) 328 return ret; 329 330 mutex_lock(&st->lock); 331 332 if (chan->type == IIO_TEMP) 333 st->temp_osr = osr; 334 else 335 st->pressure_osr = osr; 336 337 mutex_unlock(&st->lock); 338 iio_device_release_direct_mode(indio_dev); 339 340 return 0; 341} 342 343static const unsigned long ms5611_scan_masks[] = {0x3, 0}; 344 345static struct ms5611_chip_info chip_info_tbl[] = { 346 [MS5611] = { 347 .temp_and_pressure_compensate = ms5611_temp_and_pressure_compensate, 348 }, 349 [MS5607] = { 350 .temp_and_pressure_compensate = ms5607_temp_and_pressure_compensate, 351 } 352}; 353 354static const struct iio_chan_spec ms5611_channels[] = { 355 { 356 .type = IIO_PRESSURE, 357 .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | 358 BIT(IIO_CHAN_INFO_SCALE) | 359 BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), 360 .scan_index = 0, 361 .scan_type = { 362 .sign = 's', 363 .realbits = 32, 364 .storagebits = 32, 365 .endianness = IIO_CPU, 366 }, 367 }, 368 { 369 .type = IIO_TEMP, 370 .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | 371 BIT(IIO_CHAN_INFO_SCALE) | 372 BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), 373 .scan_index = 1, 374 .scan_type = { 375 .sign = 's', 376 .realbits = 32, 377 .storagebits = 32, 378 .endianness = IIO_CPU, 379 }, 380 }, 381 IIO_CHAN_SOFT_TIMESTAMP(2), 382}; 383 384static const struct iio_info ms5611_info = { 385 .read_raw = &ms5611_read_raw, 386 .write_raw = &ms5611_write_raw, 387 .attrs = &ms5611_attribute_group, 388}; 389 390static int ms5611_init(struct iio_dev *indio_dev) 391{ 392 int ret; 393 struct ms5611_state *st = iio_priv(indio_dev); 394 395 /* Enable attached regulator if any. */ 396 st->vdd = devm_regulator_get(indio_dev->dev.parent, "vdd"); 397 if (IS_ERR(st->vdd)) 398 return PTR_ERR(st->vdd); 399 400 ret = regulator_enable(st->vdd); 401 if (ret) { 402 dev_err(indio_dev->dev.parent, 403 "failed to enable Vdd supply: %d\n", ret); 404 return ret; 405 } 406 407 ret = ms5611_reset(indio_dev); 408 if (ret < 0) 409 goto err_regulator_disable; 410 411 ret = ms5611_read_prom(indio_dev); 412 if (ret < 0) 413 goto err_regulator_disable; 414 415 return 0; 416 417err_regulator_disable: 418 regulator_disable(st->vdd); 419 return ret; 420} 421 422static void ms5611_fini(const struct iio_dev *indio_dev) 423{ 424 const struct ms5611_state *st = iio_priv(indio_dev); 425 426 regulator_disable(st->vdd); 427} 428 429int ms5611_probe(struct iio_dev *indio_dev, struct device *dev, 430 const char *name, int type) 431{ 432 int ret; 433 struct ms5611_state *st = iio_priv(indio_dev); 434 435 mutex_init(&st->lock); 436 st->chip_info = &chip_info_tbl[type]; 437 st->temp_osr = 438 &ms5611_avail_temp_osr[ARRAY_SIZE(ms5611_avail_temp_osr) - 1]; 439 st->pressure_osr = 440 &ms5611_avail_pressure_osr[ARRAY_SIZE(ms5611_avail_pressure_osr) 441 - 1]; 442 indio_dev->name = name; 443 indio_dev->info = &ms5611_info; 444 indio_dev->channels = ms5611_channels; 445 indio_dev->num_channels = ARRAY_SIZE(ms5611_channels); 446 indio_dev->modes = INDIO_DIRECT_MODE; 447 indio_dev->available_scan_masks = ms5611_scan_masks; 448 449 ret = ms5611_init(indio_dev); 450 if (ret < 0) 451 return ret; 452 453 ret = iio_triggered_buffer_setup(indio_dev, NULL, 454 ms5611_trigger_handler, NULL); 455 if (ret < 0) { 456 dev_err(dev, "iio triggered buffer setup failed\n"); 457 goto err_fini; 458 } 459 460 ret = iio_device_register(indio_dev); 461 if (ret < 0) { 462 dev_err(dev, "unable to register iio device\n"); 463 goto err_buffer_cleanup; 464 } 465 466 return 0; 467 468err_buffer_cleanup: 469 iio_triggered_buffer_cleanup(indio_dev); 470err_fini: 471 ms5611_fini(indio_dev); 472 return ret; 473} 474EXPORT_SYMBOL_NS(ms5611_probe, IIO_MS5611); 475 476void ms5611_remove(struct iio_dev *indio_dev) 477{ 478 iio_device_unregister(indio_dev); 479 iio_triggered_buffer_cleanup(indio_dev); 480 ms5611_fini(indio_dev); 481} 482EXPORT_SYMBOL_NS(ms5611_remove, IIO_MS5611); 483 484MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>"); 485MODULE_DESCRIPTION("MS5611 core driver"); 486MODULE_LICENSE("GPL v2");