Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * MS5611 pressure and temperature sensor driver
0004  *
0005  * Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
0006  *
0007  * Data sheet:
0008  *  http://www.meas-spec.com/downloads/MS5611-01BA03.pdf
0009  *  http://www.meas-spec.com/downloads/MS5607-02BA03.pdf
0010  *
0011  */
0012 
0013 #include <linux/module.h>
0014 #include <linux/iio/iio.h>
0015 #include <linux/delay.h>
0016 #include <linux/regulator/consumer.h>
0017 
0018 #include <linux/iio/sysfs.h>
0019 #include <linux/iio/buffer.h>
0020 #include <linux/iio/triggered_buffer.h>
0021 #include <linux/iio/trigger_consumer.h>
0022 #include "ms5611.h"
0023 
0024 #define MS5611_INIT_OSR(_cmd, _conv_usec, _rate) \
0025     { .cmd = _cmd, .conv_usec = _conv_usec, .rate = _rate }
0026 
0027 static const struct ms5611_osr ms5611_avail_pressure_osr[] = {
0028     MS5611_INIT_OSR(0x40, 600,  256),
0029     MS5611_INIT_OSR(0x42, 1170, 512),
0030     MS5611_INIT_OSR(0x44, 2280, 1024),
0031     MS5611_INIT_OSR(0x46, 4540, 2048),
0032     MS5611_INIT_OSR(0x48, 9040, 4096)
0033 };
0034 
0035 static const struct ms5611_osr ms5611_avail_temp_osr[] = {
0036     MS5611_INIT_OSR(0x50, 600,  256),
0037     MS5611_INIT_OSR(0x52, 1170, 512),
0038     MS5611_INIT_OSR(0x54, 2280, 1024),
0039     MS5611_INIT_OSR(0x56, 4540, 2048),
0040     MS5611_INIT_OSR(0x58, 9040, 4096)
0041 };
0042 
0043 static const char ms5611_show_osr[] = "256 512 1024 2048 4096";
0044 
0045 static IIO_CONST_ATTR(oversampling_ratio_available, ms5611_show_osr);
0046 
0047 static struct attribute *ms5611_attributes[] = {
0048     &iio_const_attr_oversampling_ratio_available.dev_attr.attr,
0049     NULL,
0050 };
0051 
0052 static const struct attribute_group ms5611_attribute_group = {
0053     .attrs = ms5611_attributes,
0054 };
0055 
0056 static bool ms5611_prom_is_valid(u16 *prom, size_t len)
0057 {
0058     int i, j;
0059     uint16_t crc = 0, crc_orig = prom[7] & 0x000F;
0060 
0061     prom[7] &= 0xFF00;
0062 
0063     for (i = 0; i < len * 2; i++) {
0064         if (i % 2 == 1)
0065             crc ^= prom[i >> 1] & 0x00FF;
0066         else
0067             crc ^= prom[i >> 1] >> 8;
0068 
0069         for (j = 0; j < 8; j++) {
0070             if (crc & 0x8000)
0071                 crc = (crc << 1) ^ 0x3000;
0072             else
0073                 crc <<= 1;
0074         }
0075     }
0076 
0077     crc = (crc >> 12) & 0x000F;
0078 
0079     return crc_orig != 0x0000 && crc == crc_orig;
0080 }
0081 
0082 static int ms5611_read_prom(struct iio_dev *indio_dev)
0083 {
0084     int ret, i;
0085     struct ms5611_state *st = iio_priv(indio_dev);
0086 
0087     for (i = 0; i < MS5611_PROM_WORDS_NB; i++) {
0088         ret = st->read_prom_word(st, i, &st->chip_info->prom[i]);
0089         if (ret < 0) {
0090             dev_err(&indio_dev->dev,
0091                 "failed to read prom at %d\n", i);
0092             return ret;
0093         }
0094     }
0095 
0096     if (!ms5611_prom_is_valid(st->chip_info->prom, MS5611_PROM_WORDS_NB)) {
0097         dev_err(&indio_dev->dev, "PROM integrity check failed\n");
0098         return -ENODEV;
0099     }
0100 
0101     return 0;
0102 }
0103 
0104 static int ms5611_read_temp_and_pressure(struct iio_dev *indio_dev,
0105                      s32 *temp, s32 *pressure)
0106 {
0107     int ret;
0108     struct ms5611_state *st = iio_priv(indio_dev);
0109 
0110     ret = st->read_adc_temp_and_pressure(st, temp, pressure);
0111     if (ret < 0) {
0112         dev_err(&indio_dev->dev,
0113             "failed to read temperature and pressure\n");
0114         return ret;
0115     }
0116 
0117     return st->chip_info->temp_and_pressure_compensate(st->chip_info,
0118                                temp, pressure);
0119 }
0120 
0121 static int ms5611_temp_and_pressure_compensate(struct ms5611_chip_info *chip_info,
0122                            s32 *temp, s32 *pressure)
0123 {
0124     s32 t = *temp, p = *pressure;
0125     s64 off, sens, dt;
0126 
0127     dt = t - (chip_info->prom[5] << 8);
0128     off = ((s64)chip_info->prom[2] << 16) + ((chip_info->prom[4] * dt) >> 7);
0129     sens = ((s64)chip_info->prom[1] << 15) + ((chip_info->prom[3] * dt) >> 8);
0130 
0131     t = 2000 + ((chip_info->prom[6] * dt) >> 23);
0132     if (t < 2000) {
0133         s64 off2, sens2, t2;
0134 
0135         t2 = (dt * dt) >> 31;
0136         off2 = (5 * (t - 2000) * (t - 2000)) >> 1;
0137         sens2 = off2 >> 1;
0138 
0139         if (t < -1500) {
0140             s64 tmp = (t + 1500) * (t + 1500);
0141 
0142             off2 += 7 * tmp;
0143             sens2 += (11 * tmp) >> 1;
0144         }
0145 
0146         t -= t2;
0147         off -= off2;
0148         sens -= sens2;
0149     }
0150 
0151     *temp = t;
0152     *pressure = (((p * sens) >> 21) - off) >> 15;
0153 
0154     return 0;
0155 }
0156 
0157 static int ms5607_temp_and_pressure_compensate(struct ms5611_chip_info *chip_info,
0158                            s32 *temp, s32 *pressure)
0159 {
0160     s32 t = *temp, p = *pressure;
0161     s64 off, sens, dt;
0162 
0163     dt = t - (chip_info->prom[5] << 8);
0164     off = ((s64)chip_info->prom[2] << 17) + ((chip_info->prom[4] * dt) >> 6);
0165     sens = ((s64)chip_info->prom[1] << 16) + ((chip_info->prom[3] * dt) >> 7);
0166 
0167     t = 2000 + ((chip_info->prom[6] * dt) >> 23);
0168     if (t < 2000) {
0169         s64 off2, sens2, t2, tmp;
0170 
0171         t2 = (dt * dt) >> 31;
0172         tmp = (t - 2000) * (t - 2000);
0173         off2 = (61 * tmp) >> 4;
0174         sens2 = tmp << 1;
0175 
0176         if (t < -1500) {
0177             tmp = (t + 1500) * (t + 1500);
0178             off2 += 15 * tmp;
0179             sens2 += 8 * tmp;
0180         }
0181 
0182         t -= t2;
0183         off -= off2;
0184         sens -= sens2;
0185     }
0186 
0187     *temp = t;
0188     *pressure = (((p * sens) >> 21) - off) >> 15;
0189 
0190     return 0;
0191 }
0192 
0193 static int ms5611_reset(struct iio_dev *indio_dev)
0194 {
0195     int ret;
0196     struct ms5611_state *st = iio_priv(indio_dev);
0197 
0198     ret = st->reset(st);
0199     if (ret < 0) {
0200         dev_err(&indio_dev->dev, "failed to reset device\n");
0201         return ret;
0202     }
0203 
0204     usleep_range(3000, 4000);
0205 
0206     return 0;
0207 }
0208 
0209 static irqreturn_t ms5611_trigger_handler(int irq, void *p)
0210 {
0211     struct iio_poll_func *pf = p;
0212     struct iio_dev *indio_dev = pf->indio_dev;
0213     struct ms5611_state *st = iio_priv(indio_dev);
0214     /* Ensure buffer elements are naturally aligned */
0215     struct {
0216         s32 channels[2];
0217         s64 ts __aligned(8);
0218     } scan;
0219     int ret;
0220 
0221     mutex_lock(&st->lock);
0222     ret = ms5611_read_temp_and_pressure(indio_dev, &scan.channels[1],
0223                         &scan.channels[0]);
0224     mutex_unlock(&st->lock);
0225     if (ret < 0)
0226         goto err;
0227 
0228     iio_push_to_buffers_with_timestamp(indio_dev, &scan,
0229                        iio_get_time_ns(indio_dev));
0230 
0231 err:
0232     iio_trigger_notify_done(indio_dev->trig);
0233 
0234     return IRQ_HANDLED;
0235 }
0236 
0237 static int ms5611_read_raw(struct iio_dev *indio_dev,
0238                struct iio_chan_spec const *chan,
0239                int *val, int *val2, long mask)
0240 {
0241     int ret;
0242     s32 temp, pressure;
0243     struct ms5611_state *st = iio_priv(indio_dev);
0244 
0245     switch (mask) {
0246     case IIO_CHAN_INFO_PROCESSED:
0247         mutex_lock(&st->lock);
0248         ret = ms5611_read_temp_and_pressure(indio_dev,
0249                             &temp, &pressure);
0250         mutex_unlock(&st->lock);
0251         if (ret < 0)
0252             return ret;
0253 
0254         switch (chan->type) {
0255         case IIO_TEMP:
0256             *val = temp * 10;
0257             return IIO_VAL_INT;
0258         case IIO_PRESSURE:
0259             *val = pressure / 1000;
0260             *val2 = (pressure % 1000) * 1000;
0261             return IIO_VAL_INT_PLUS_MICRO;
0262         default:
0263             return -EINVAL;
0264         }
0265     case IIO_CHAN_INFO_SCALE:
0266         switch (chan->type) {
0267         case IIO_TEMP:
0268             *val = 10;
0269             return IIO_VAL_INT;
0270         case IIO_PRESSURE:
0271             *val = 0;
0272             *val2 = 1000;
0273             return IIO_VAL_INT_PLUS_MICRO;
0274         default:
0275             return -EINVAL;
0276         }
0277     case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
0278         if (chan->type != IIO_TEMP && chan->type != IIO_PRESSURE)
0279             break;
0280         mutex_lock(&st->lock);
0281         if (chan->type == IIO_TEMP)
0282             *val = (int)st->temp_osr->rate;
0283         else
0284             *val = (int)st->pressure_osr->rate;
0285         mutex_unlock(&st->lock);
0286         return IIO_VAL_INT;
0287     }
0288 
0289     return -EINVAL;
0290 }
0291 
0292 static const struct ms5611_osr *ms5611_find_osr(int rate,
0293                         const struct ms5611_osr *osr,
0294                         size_t count)
0295 {
0296     unsigned int r;
0297 
0298     for (r = 0; r < count; r++)
0299         if ((unsigned short)rate == osr[r].rate)
0300             break;
0301     if (r >= count)
0302         return NULL;
0303     return &osr[r];
0304 }
0305 
0306 static int ms5611_write_raw(struct iio_dev *indio_dev,
0307                 struct iio_chan_spec const *chan,
0308                 int val, int val2, long mask)
0309 {
0310     struct ms5611_state *st = iio_priv(indio_dev);
0311     const struct ms5611_osr *osr = NULL;
0312     int ret;
0313 
0314     if (mask != IIO_CHAN_INFO_OVERSAMPLING_RATIO)
0315         return -EINVAL;
0316 
0317     if (chan->type == IIO_TEMP)
0318         osr = ms5611_find_osr(val, ms5611_avail_temp_osr,
0319                       ARRAY_SIZE(ms5611_avail_temp_osr));
0320     else if (chan->type == IIO_PRESSURE)
0321         osr = ms5611_find_osr(val, ms5611_avail_pressure_osr,
0322                       ARRAY_SIZE(ms5611_avail_pressure_osr));
0323     if (!osr)
0324         return -EINVAL;
0325 
0326     ret = iio_device_claim_direct_mode(indio_dev);
0327     if (ret)
0328         return ret;
0329 
0330     mutex_lock(&st->lock);
0331 
0332     if (chan->type == IIO_TEMP)
0333         st->temp_osr = osr;
0334     else
0335         st->pressure_osr = osr;
0336 
0337     mutex_unlock(&st->lock);
0338     iio_device_release_direct_mode(indio_dev);
0339 
0340     return 0;
0341 }
0342 
0343 static const unsigned long ms5611_scan_masks[] = {0x3, 0};
0344 
0345 static struct ms5611_chip_info chip_info_tbl[] = {
0346     [MS5611] = {
0347         .temp_and_pressure_compensate = ms5611_temp_and_pressure_compensate,
0348     },
0349     [MS5607] = {
0350         .temp_and_pressure_compensate = ms5607_temp_and_pressure_compensate,
0351     }
0352 };
0353 
0354 static const struct iio_chan_spec ms5611_channels[] = {
0355     {
0356         .type = IIO_PRESSURE,
0357         .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
0358             BIT(IIO_CHAN_INFO_SCALE) |
0359             BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
0360         .scan_index = 0,
0361         .scan_type = {
0362             .sign = 's',
0363             .realbits = 32,
0364             .storagebits = 32,
0365             .endianness = IIO_CPU,
0366         },
0367     },
0368     {
0369         .type = IIO_TEMP,
0370         .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
0371             BIT(IIO_CHAN_INFO_SCALE) |
0372             BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
0373         .scan_index = 1,
0374         .scan_type = {
0375             .sign = 's',
0376             .realbits = 32,
0377             .storagebits = 32,
0378             .endianness = IIO_CPU,
0379         },
0380     },
0381     IIO_CHAN_SOFT_TIMESTAMP(2),
0382 };
0383 
0384 static const struct iio_info ms5611_info = {
0385     .read_raw = &ms5611_read_raw,
0386     .write_raw = &ms5611_write_raw,
0387     .attrs = &ms5611_attribute_group,
0388 };
0389 
0390 static int ms5611_init(struct iio_dev *indio_dev)
0391 {
0392     int ret;
0393     struct ms5611_state *st = iio_priv(indio_dev);
0394 
0395     /* Enable attached regulator if any. */
0396     st->vdd = devm_regulator_get(indio_dev->dev.parent, "vdd");
0397     if (IS_ERR(st->vdd))
0398         return PTR_ERR(st->vdd);
0399 
0400     ret = regulator_enable(st->vdd);
0401     if (ret) {
0402         dev_err(indio_dev->dev.parent,
0403             "failed to enable Vdd supply: %d\n", ret);
0404         return ret;
0405     }
0406 
0407     ret = ms5611_reset(indio_dev);
0408     if (ret < 0)
0409         goto err_regulator_disable;
0410 
0411     ret = ms5611_read_prom(indio_dev);
0412     if (ret < 0)
0413         goto err_regulator_disable;
0414 
0415     return 0;
0416 
0417 err_regulator_disable:
0418     regulator_disable(st->vdd);
0419     return ret;
0420 }
0421 
0422 static void ms5611_fini(const struct iio_dev *indio_dev)
0423 {
0424     const struct ms5611_state *st = iio_priv(indio_dev);
0425 
0426     regulator_disable(st->vdd);
0427 }
0428 
0429 int ms5611_probe(struct iio_dev *indio_dev, struct device *dev,
0430          const char *name, int type)
0431 {
0432     int ret;
0433     struct ms5611_state *st = iio_priv(indio_dev);
0434 
0435     mutex_init(&st->lock);
0436     st->chip_info = &chip_info_tbl[type];
0437     st->temp_osr =
0438         &ms5611_avail_temp_osr[ARRAY_SIZE(ms5611_avail_temp_osr) - 1];
0439     st->pressure_osr =
0440         &ms5611_avail_pressure_osr[ARRAY_SIZE(ms5611_avail_pressure_osr)
0441                        - 1];
0442     indio_dev->name = name;
0443     indio_dev->info = &ms5611_info;
0444     indio_dev->channels = ms5611_channels;
0445     indio_dev->num_channels = ARRAY_SIZE(ms5611_channels);
0446     indio_dev->modes = INDIO_DIRECT_MODE;
0447     indio_dev->available_scan_masks = ms5611_scan_masks;
0448 
0449     ret = ms5611_init(indio_dev);
0450     if (ret < 0)
0451         return ret;
0452 
0453     ret = iio_triggered_buffer_setup(indio_dev, NULL,
0454                      ms5611_trigger_handler, NULL);
0455     if (ret < 0) {
0456         dev_err(dev, "iio triggered buffer setup failed\n");
0457         goto err_fini;
0458     }
0459 
0460     ret = iio_device_register(indio_dev);
0461     if (ret < 0) {
0462         dev_err(dev, "unable to register iio device\n");
0463         goto err_buffer_cleanup;
0464     }
0465 
0466     return 0;
0467 
0468 err_buffer_cleanup:
0469     iio_triggered_buffer_cleanup(indio_dev);
0470 err_fini:
0471     ms5611_fini(indio_dev);
0472     return ret;
0473 }
0474 EXPORT_SYMBOL_NS(ms5611_probe, IIO_MS5611);
0475 
0476 void ms5611_remove(struct iio_dev *indio_dev)
0477 {
0478     iio_device_unregister(indio_dev);
0479     iio_triggered_buffer_cleanup(indio_dev);
0480     ms5611_fini(indio_dev);
0481 }
0482 EXPORT_SYMBOL_NS(ms5611_remove, IIO_MS5611);
0483 
0484 MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
0485 MODULE_DESCRIPTION("MS5611 core driver");
0486 MODULE_LICENSE("GPL v2");