root/drivers/iio/pressure/ms5611_core.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ms5611_prom_is_valid
  2. ms5611_read_prom
  3. ms5611_read_temp_and_pressure
  4. ms5611_temp_and_pressure_compensate
  5. ms5607_temp_and_pressure_compensate
  6. ms5611_reset
  7. ms5611_trigger_handler
  8. ms5611_read_raw
  9. ms5611_find_osr
  10. ms5611_write_raw
  11. ms5611_init
  12. ms5611_fini
  13. ms5611_probe
  14. ms5611_remove

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

/* [<][>][^][v][top][bottom][index][help] */