linux/drivers/iio/common/ms_sensors/ms_sensors_i2c.c
<<
>>
Prefs
   1/*
   2 * Measurements Specialties driver common i2c functions
   3 *
   4 * Copyright (c) 2015 Measurement-Specialties
   5 *
   6 * Licensed under the GPL-2.
   7 */
   8
   9#include <linux/module.h>
  10#include <linux/iio/iio.h>
  11#include <linux/device.h>
  12#include <linux/delay.h>
  13
  14#include "ms_sensors_i2c.h"
  15
  16/* Conversion times in us */
  17static const u16 ms_sensors_ht_t_conversion_time[] = { 50000, 25000,
  18                                                       13000, 7000 };
  19static const u16 ms_sensors_ht_h_conversion_time[] = { 16000, 3000,
  20                                                       5000, 8000 };
  21static const u16 ms_sensors_tp_conversion_time[] = { 500, 1100, 2100,
  22                                                     4100, 8220, 16440 };
  23
  24#define MS_SENSORS_SERIAL_READ_MSB              0xFA0F
  25#define MS_SENSORS_SERIAL_READ_LSB              0xFCC9
  26#define MS_SENSORS_CONFIG_REG_WRITE             0xE6
  27#define MS_SENSORS_CONFIG_REG_READ              0xE7
  28#define MS_SENSORS_HT_T_CONVERSION_START        0xF3
  29#define MS_SENSORS_HT_H_CONVERSION_START        0xF5
  30
  31#define MS_SENSORS_TP_PROM_READ                 0xA0
  32#define MS_SENSORS_TP_T_CONVERSION_START        0x50
  33#define MS_SENSORS_TP_P_CONVERSION_START        0x40
  34#define MS_SENSORS_TP_ADC_READ                  0x00
  35
  36#define MS_SENSORS_NO_READ_CMD                  0xFF
  37
  38/**
  39 * ms_sensors_reset() - Reset function
  40 * @cli:        pointer to device client
  41 * @cmd:        reset cmd. Depends on device in use
  42 * @delay:      usleep minimal delay after reset command is issued
  43 *
  44 * Generic I2C reset function for Measurement Specialties devices.
  45 *
  46 * Return: 0 on success, negative errno otherwise.
  47 */
  48int ms_sensors_reset(void *cli, u8 cmd, unsigned int delay)
  49{
  50        int ret;
  51        struct i2c_client *client = cli;
  52
  53        ret = i2c_smbus_write_byte(client, cmd);
  54        if (ret) {
  55                dev_err(&client->dev, "Failed to reset device\n");
  56                return ret;
  57        }
  58        usleep_range(delay, delay + 1000);
  59
  60        return 0;
  61}
  62EXPORT_SYMBOL(ms_sensors_reset);
  63
  64/**
  65 * ms_sensors_read_prom_word() - PROM word read function
  66 * @cli:        pointer to device client
  67 * @cmd:        PROM read cmd. Depends on device and prom id
  68 * @word:       pointer to word destination value
  69 *
  70 * Generic i2c prom word read function for Measurement Specialties devices.
  71 *
  72 * Return: 0 on success, negative errno otherwise.
  73 */
  74int ms_sensors_read_prom_word(void *cli, int cmd, u16 *word)
  75{
  76        int ret;
  77        struct i2c_client *client = cli;
  78
  79        ret = i2c_smbus_read_word_swapped(client, cmd);
  80        if (ret < 0) {
  81                dev_err(&client->dev, "Failed to read prom word\n");
  82                return ret;
  83        }
  84        *word = ret;
  85
  86        return 0;
  87}
  88EXPORT_SYMBOL(ms_sensors_read_prom_word);
  89
  90/**
  91 * ms_sensors_convert_and_read() - ADC conversion & read function
  92 * @cli:        pointer to device client
  93 * @conv:       ADC conversion command. Depends on device in use
  94 * @rd:         ADC read command. Depends on device in use
  95 * @delay:      usleep minimal delay after conversion command is issued
  96 * @adc:        pointer to ADC destination value
  97 *
  98 * Generic ADC conversion & read function for Measurement Specialties
  99 * devices.
 100 * The function will issue conversion command, sleep appopriate delay, and
 101 * issue command to read ADC.
 102 *
 103 * Return: 0 on success, negative errno otherwise.
 104 */
 105int ms_sensors_convert_and_read(void *cli, u8 conv, u8 rd,
 106                                unsigned int delay, u32 *adc)
 107{
 108        int ret;
 109        __be32 buf = 0;
 110        struct i2c_client *client = cli;
 111
 112        /* Trigger conversion */
 113        ret = i2c_smbus_write_byte(client, conv);
 114        if (ret)
 115                goto err;
 116        usleep_range(delay, delay + 1000);
 117
 118        /* Retrieve ADC value */
 119        if (rd != MS_SENSORS_NO_READ_CMD)
 120                ret = i2c_smbus_read_i2c_block_data(client, rd, 3, (u8 *)&buf);
 121        else
 122                ret = i2c_master_recv(client, (u8 *)&buf, 3);
 123        if (ret < 0)
 124                goto err;
 125
 126        dev_dbg(&client->dev, "ADC raw value : %x\n", be32_to_cpu(buf) >> 8);
 127        *adc = be32_to_cpu(buf) >> 8;
 128
 129        return 0;
 130err:
 131        dev_err(&client->dev, "Unable to make sensor adc conversion\n");
 132        return ret;
 133}
 134EXPORT_SYMBOL(ms_sensors_convert_and_read);
 135
 136/**
 137 * ms_sensors_crc_valid() - CRC check function
 138 * @value:      input and CRC compare value
 139 *
 140 * Cyclic Redundancy Check function used in TSYS02D, HTU21, MS8607.
 141 * This function performs a x^8 + x^5 + x^4 + 1 polynomial CRC.
 142 * The argument contains CRC value in LSB byte while the bytes 1 and 2
 143 * are used for CRC computation.
 144 *
 145 * Return: 1 if CRC is valid, 0 otherwise.
 146 */
 147static bool ms_sensors_crc_valid(u32 value)
 148{
 149        u32 polynom = 0x988000; /* x^8 + x^5 + x^4 + 1 */
 150        u32 msb = 0x800000;
 151        u32 mask = 0xFF8000;
 152        u32 result = value & 0xFFFF00;
 153        u8 crc = value & 0xFF;
 154
 155        while (msb != 0x80) {
 156                if (result & msb)
 157                        result = ((result ^ polynom) & mask)
 158                                | (result & ~mask);
 159                msb >>= 1;
 160                mask >>= 1;
 161                polynom >>= 1;
 162        }
 163
 164        return result == crc;
 165}
 166
 167/**
 168 * ms_sensors_read_serial() - Serial number read function
 169 * @cli:        pointer to i2c client
 170 * @sn:         pointer to 64-bits destination value
 171 *
 172 * Generic i2c serial number read function for Measurement Specialties devices.
 173 * This function is used for TSYS02d, HTU21, MS8607 chipset.
 174 * Refer to datasheet:
 175 *      http://www.meas-spec.com/downloads/HTU2X_Serial_Number_Reading.pdf
 176 *
 177 * Sensor raw MSB serial number format is the following :
 178 *      [ SNB3, CRC, SNB2, CRC, SNB1, CRC, SNB0, CRC]
 179 * Sensor raw LSB serial number format is the following :
 180 *      [ X, X, SNC1, SNC0, CRC, SNA1, SNA0, CRC]
 181 * The resulting serial number is following :
 182 *      [ SNA1, SNA0, SNB3, SNB2, SNB1, SNB0, SNC1, SNC0]
 183 *
 184 * Return: 0 on success, negative errno otherwise.
 185 */
 186int ms_sensors_read_serial(struct i2c_client *client, u64 *sn)
 187{
 188        u8 i;
 189        __be64 rcv_buf = 0;
 190        u64 rcv_val;
 191        __be16 send_buf;
 192        int ret;
 193
 194        struct i2c_msg msg[2] = {
 195                {
 196                 .addr = client->addr,
 197                 .flags = client->flags,
 198                 .len = 2,
 199                 .buf = (__u8 *)&send_buf,
 200                 },
 201                {
 202                 .addr = client->addr,
 203                 .flags = client->flags | I2C_M_RD,
 204                 .buf = (__u8 *)&rcv_buf,
 205                 },
 206        };
 207
 208        /* Read MSB part of serial number */
 209        send_buf = cpu_to_be16(MS_SENSORS_SERIAL_READ_MSB);
 210        msg[1].len = 8;
 211        ret = i2c_transfer(client->adapter, msg, 2);
 212        if (ret < 0) {
 213                dev_err(&client->dev, "Unable to read device serial number");
 214                return ret;
 215        }
 216
 217        rcv_val = be64_to_cpu(rcv_buf);
 218        dev_dbg(&client->dev, "Serial MSB raw : %llx\n", rcv_val);
 219
 220        for (i = 0; i < 64; i += 16) {
 221                if (!ms_sensors_crc_valid((rcv_val >> i) & 0xFFFF))
 222                        return -ENODEV;
 223        }
 224
 225        *sn = (((rcv_val >> 32) & 0xFF000000) |
 226               ((rcv_val >> 24) & 0x00FF0000) |
 227               ((rcv_val >> 16) & 0x0000FF00) |
 228               ((rcv_val >> 8) & 0x000000FF)) << 16;
 229
 230        /* Read LSB part of serial number */
 231        send_buf = cpu_to_be16(MS_SENSORS_SERIAL_READ_LSB);
 232        msg[1].len = 6;
 233        rcv_buf = 0;
 234        ret = i2c_transfer(client->adapter, msg, 2);
 235        if (ret < 0) {
 236                dev_err(&client->dev, "Unable to read device serial number");
 237                return ret;
 238        }
 239
 240        rcv_val = be64_to_cpu(rcv_buf) >> 16;
 241        dev_dbg(&client->dev, "Serial MSB raw : %llx\n", rcv_val);
 242
 243        for (i = 0; i < 48; i += 24) {
 244                if (!ms_sensors_crc_valid((rcv_val >> i) & 0xFFFFFF))
 245                        return -ENODEV;
 246        }
 247
 248        *sn |= (rcv_val & 0xFFFF00) << 40 | (rcv_val >> 32);
 249
 250        return 0;
 251}
 252EXPORT_SYMBOL(ms_sensors_read_serial);
 253
 254static int ms_sensors_read_config_reg(struct i2c_client *client,
 255                                      u8 *config_reg)
 256{
 257        int ret;
 258
 259        ret = i2c_smbus_write_byte(client, MS_SENSORS_CONFIG_REG_READ);
 260        if (ret) {
 261                dev_err(&client->dev, "Unable to read config register");
 262                return ret;
 263        }
 264
 265        ret = i2c_master_recv(client, config_reg, 1);
 266        if (ret < 0) {
 267                dev_err(&client->dev, "Unable to read config register");
 268                return ret;
 269        }
 270        dev_dbg(&client->dev, "Config register :%x\n", *config_reg);
 271
 272        return 0;
 273}
 274
 275/**
 276 * ms_sensors_write_resolution() - Set resolution function
 277 * @dev_data:   pointer to temperature/humidity device data
 278 * @i:          resolution index to set
 279 *
 280 * This function will program the appropriate resolution based on the index
 281 * provided when user space will set samp_freq channel.
 282 * This function is used for TSYS02D, HTU21 and MS8607 chipsets.
 283 *
 284 * Return: 0 on success, negative errno otherwise.
 285 */
 286ssize_t ms_sensors_write_resolution(struct ms_ht_dev *dev_data,
 287                                    u8 i)
 288{
 289        u8 config_reg;
 290        int ret;
 291
 292        ret = ms_sensors_read_config_reg(dev_data->client, &config_reg);
 293        if (ret)
 294                return ret;
 295
 296        config_reg &= 0x7E;
 297        config_reg |= ((i & 1) << 7) + ((i & 2) >> 1);
 298
 299        return i2c_smbus_write_byte_data(dev_data->client,
 300                                         MS_SENSORS_CONFIG_REG_WRITE,
 301                                         config_reg);
 302}
 303EXPORT_SYMBOL(ms_sensors_write_resolution);
 304
 305/**
 306 * ms_sensors_show_battery_low() - Show device battery low indicator
 307 * @dev_data:   pointer to temperature/humidity device data
 308 * @buf:        pointer to char buffer to write result
 309 *
 310 * This function will read battery indicator value in the device and
 311 * return 1 if the device voltage is below 2.25V.
 312 * This function is used for TSYS02D, HTU21 and MS8607 chipsets.
 313 *
 314 * Return: length of sprintf on success, negative errno otherwise.
 315 */
 316ssize_t ms_sensors_show_battery_low(struct ms_ht_dev *dev_data,
 317                                    char *buf)
 318{
 319        int ret;
 320        u8 config_reg;
 321
 322        mutex_lock(&dev_data->lock);
 323        ret = ms_sensors_read_config_reg(dev_data->client, &config_reg);
 324        mutex_unlock(&dev_data->lock);
 325        if (ret)
 326                return ret;
 327
 328        return sprintf(buf, "%d\n", (config_reg & 0x40) >> 6);
 329}
 330EXPORT_SYMBOL(ms_sensors_show_battery_low);
 331
 332/**
 333 * ms_sensors_show_heater() - Show device heater
 334 * @dev_data:   pointer to temperature/humidity device data
 335 * @buf:        pointer to char buffer to write result
 336 *
 337 * This function will read heater enable value in the device and
 338 * return 1 if the heater is enabled.
 339 * This function is used for HTU21 and MS8607 chipsets.
 340 *
 341 * Return: length of sprintf on success, negative errno otherwise.
 342 */
 343ssize_t ms_sensors_show_heater(struct ms_ht_dev *dev_data,
 344                               char *buf)
 345{
 346        u8 config_reg;
 347        int ret;
 348
 349        mutex_lock(&dev_data->lock);
 350        ret = ms_sensors_read_config_reg(dev_data->client, &config_reg);
 351        mutex_unlock(&dev_data->lock);
 352        if (ret)
 353                return ret;
 354
 355        return sprintf(buf, "%d\n", (config_reg & 0x4) >> 2);
 356}
 357EXPORT_SYMBOL(ms_sensors_show_heater);
 358
 359/**
 360 * ms_sensors_write_heater() - Write device heater
 361 * @dev_data:   pointer to temperature/humidity device data
 362 * @buf:        pointer to char buffer from user space
 363 * @len:        length of buf
 364 *
 365 * This function will write 1 or 0 value in the device
 366 * to enable or disable heater.
 367 * This function is used for HTU21 and MS8607 chipsets.
 368 *
 369 * Return: length of buffer, negative errno otherwise.
 370 */
 371ssize_t ms_sensors_write_heater(struct ms_ht_dev *dev_data,
 372                                const char *buf, size_t len)
 373{
 374        u8 val, config_reg;
 375        int ret;
 376
 377        ret = kstrtou8(buf, 10, &val);
 378        if (ret)
 379                return ret;
 380
 381        if (val > 1)
 382                return -EINVAL;
 383
 384        mutex_lock(&dev_data->lock);
 385        ret = ms_sensors_read_config_reg(dev_data->client, &config_reg);
 386        if (ret) {
 387                mutex_unlock(&dev_data->lock);
 388                return ret;
 389        }
 390
 391        config_reg &= 0xFB;
 392        config_reg |= val << 2;
 393
 394        ret = i2c_smbus_write_byte_data(dev_data->client,
 395                                        MS_SENSORS_CONFIG_REG_WRITE,
 396                                        config_reg);
 397        mutex_unlock(&dev_data->lock);
 398        if (ret) {
 399                dev_err(&dev_data->client->dev, "Unable to write config register\n");
 400                return ret;
 401        }
 402
 403        return len;
 404}
 405EXPORT_SYMBOL(ms_sensors_write_heater);
 406
 407/**
 408 * ms_sensors_ht_read_temperature() - Read temperature
 409 * @dev_data:   pointer to temperature/humidity device data
 410 * @temperature:pointer to temperature destination value
 411 *
 412 * This function will get temperature ADC value from the device,
 413 * check the CRC and compute the temperature value.
 414 * This function is used for TSYS02D, HTU21 and MS8607 chipsets.
 415 *
 416 * Return: 0 on success, negative errno otherwise.
 417 */
 418int ms_sensors_ht_read_temperature(struct ms_ht_dev *dev_data,
 419                                   s32 *temperature)
 420{
 421        int ret;
 422        u32 adc;
 423        u16 delay;
 424
 425        mutex_lock(&dev_data->lock);
 426        delay = ms_sensors_ht_t_conversion_time[dev_data->res_index];
 427        ret = ms_sensors_convert_and_read(dev_data->client,
 428                                          MS_SENSORS_HT_T_CONVERSION_START,
 429                                          MS_SENSORS_NO_READ_CMD,
 430                                          delay, &adc);
 431        mutex_unlock(&dev_data->lock);
 432        if (ret)
 433                return ret;
 434
 435        if (!ms_sensors_crc_valid(adc)) {
 436                dev_err(&dev_data->client->dev,
 437                        "Temperature read crc check error\n");
 438                return -ENODEV;
 439        }
 440
 441        /* Temperature algorithm */
 442        *temperature = (((s64)(adc >> 8) * 175720) >> 16) - 46850;
 443
 444        return 0;
 445}
 446EXPORT_SYMBOL(ms_sensors_ht_read_temperature);
 447
 448/**
 449 * ms_sensors_ht_read_humidity() - Read humidity
 450 * @dev_data:   pointer to temperature/humidity device data
 451 * @humidity:   pointer to humidity destination value
 452 *
 453 * This function will get humidity ADC value from the device,
 454 * check the CRC and compute the temperature value.
 455 * This function is used for HTU21 and MS8607 chipsets.
 456 *
 457 * Return: 0 on success, negative errno otherwise.
 458 */
 459int ms_sensors_ht_read_humidity(struct ms_ht_dev *dev_data,
 460                                u32 *humidity)
 461{
 462        int ret;
 463        u32 adc;
 464        u16 delay;
 465
 466        mutex_lock(&dev_data->lock);
 467        delay = ms_sensors_ht_h_conversion_time[dev_data->res_index];
 468        ret = ms_sensors_convert_and_read(dev_data->client,
 469                                          MS_SENSORS_HT_H_CONVERSION_START,
 470                                          MS_SENSORS_NO_READ_CMD,
 471                                          delay, &adc);
 472        mutex_unlock(&dev_data->lock);
 473        if (ret)
 474                return ret;
 475
 476        if (!ms_sensors_crc_valid(adc)) {
 477                dev_err(&dev_data->client->dev,
 478                        "Humidity read crc check error\n");
 479                return -ENODEV;
 480        }
 481
 482        /* Humidity algorithm */
 483        *humidity = (((s32)(adc >> 8) * 12500) >> 16) * 10 - 6000;
 484        if (*humidity >= 100000)
 485                *humidity = 100000;
 486
 487        return 0;
 488}
 489EXPORT_SYMBOL(ms_sensors_ht_read_humidity);
 490
 491/**
 492 * ms_sensors_tp_crc_valid() - CRC check function for
 493 *     Temperature and pressure devices.
 494 *     This function is only used when reading PROM coefficients
 495 *
 496 * @prom:       pointer to PROM coefficients array
 497 * @len:        length of PROM coefficients array
 498 *
 499 * Return: True if CRC is ok.
 500 */
 501static bool ms_sensors_tp_crc_valid(u16 *prom, u8 len)
 502{
 503        unsigned int cnt, n_bit;
 504        u16 n_rem = 0x0000, crc_read = prom[0], crc = (*prom & 0xF000) >> 12;
 505
 506        prom[len - 1] = 0;
 507        prom[0] &= 0x0FFF;      /* Clear the CRC computation part */
 508
 509        for (cnt = 0; cnt < len * 2; cnt++) {
 510                if (cnt % 2 == 1)
 511                        n_rem ^= prom[cnt >> 1] & 0x00FF;
 512                else
 513                        n_rem ^= prom[cnt >> 1] >> 8;
 514
 515                for (n_bit = 8; n_bit > 0; n_bit--) {
 516                        if (n_rem & 0x8000)
 517                                n_rem = (n_rem << 1) ^ 0x3000;
 518                        else
 519                                n_rem <<= 1;
 520                }
 521        }
 522        n_rem >>= 12;
 523        prom[0] = crc_read;
 524
 525        return n_rem == crc;
 526}
 527
 528/**
 529 * ms_sensors_tp_read_prom() - prom coeff read function
 530 * @dev_data:   pointer to temperature/pressure device data
 531 *
 532 * This function will read prom coefficients and check CRC.
 533 * This function is used for MS5637 and MS8607 chipsets.
 534 *
 535 * Return: 0 on success, negative errno otherwise.
 536 */
 537int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data)
 538{
 539        int i, ret;
 540
 541        for (i = 0; i < MS_SENSORS_TP_PROM_WORDS_NB; i++) {
 542                ret = ms_sensors_read_prom_word(
 543                        dev_data->client,
 544                        MS_SENSORS_TP_PROM_READ + (i << 1),
 545                        &dev_data->prom[i]);
 546
 547                if (ret)
 548                        return ret;
 549        }
 550
 551        if (!ms_sensors_tp_crc_valid(dev_data->prom,
 552                                     MS_SENSORS_TP_PROM_WORDS_NB + 1)) {
 553                dev_err(&dev_data->client->dev,
 554                        "Calibration coefficients crc check error\n");
 555                return -ENODEV;
 556        }
 557
 558        return 0;
 559}
 560EXPORT_SYMBOL(ms_sensors_tp_read_prom);
 561
 562/**
 563 * ms_sensors_read_temp_and_pressure() - read temp and pressure
 564 * @dev_data:   pointer to temperature/pressure device data
 565 * @temperature:pointer to temperature destination value
 566 * @pressure:   pointer to pressure destination value
 567 *
 568 * This function will read ADC and compute pressure and temperature value.
 569 * This function is used for MS5637 and MS8607 chipsets.
 570 *
 571 * Return: 0 on success, negative errno otherwise.
 572 */
 573int ms_sensors_read_temp_and_pressure(struct ms_tp_dev *dev_data,
 574                                      int *temperature,
 575                                      unsigned int *pressure)
 576{
 577        int ret;
 578        u32 t_adc, p_adc;
 579        s32 dt, temp;
 580        s64 off, sens, t2, off2, sens2;
 581        u16 *prom = dev_data->prom, delay;
 582
 583        mutex_lock(&dev_data->lock);
 584        delay = ms_sensors_tp_conversion_time[dev_data->res_index];
 585
 586        ret = ms_sensors_convert_and_read(
 587                                        dev_data->client,
 588                                        MS_SENSORS_TP_T_CONVERSION_START +
 589                                                dev_data->res_index * 2,
 590                                        MS_SENSORS_TP_ADC_READ,
 591                                        delay, &t_adc);
 592        if (ret) {
 593                mutex_unlock(&dev_data->lock);
 594                return ret;
 595        }
 596
 597        ret = ms_sensors_convert_and_read(
 598                                        dev_data->client,
 599                                        MS_SENSORS_TP_P_CONVERSION_START +
 600                                                dev_data->res_index * 2,
 601                                        MS_SENSORS_TP_ADC_READ,
 602                                        delay, &p_adc);
 603        mutex_unlock(&dev_data->lock);
 604        if (ret)
 605                return ret;
 606
 607        dt = (s32)t_adc - (prom[5] << 8);
 608
 609        /* Actual temperature = 2000 + dT * TEMPSENS */
 610        temp = 2000 + (((s64)dt * prom[6]) >> 23);
 611
 612        /* Second order temperature compensation */
 613        if (temp < 2000) {
 614                s64 tmp = (s64)temp - 2000;
 615
 616                t2 = (3 * ((s64)dt * (s64)dt)) >> 33;
 617                off2 = (61 * tmp * tmp) >> 4;
 618                sens2 = (29 * tmp * tmp) >> 4;
 619
 620                if (temp < -1500) {
 621                        s64 tmp = (s64)temp + 1500;
 622
 623                        off2 += 17 * tmp * tmp;
 624                        sens2 += 9 * tmp * tmp;
 625                }
 626        } else {
 627                t2 = (5 * ((s64)dt * (s64)dt)) >> 38;
 628                off2 = 0;
 629                sens2 = 0;
 630        }
 631
 632        /* OFF = OFF_T1 + TCO * dT */
 633        off = (((s64)prom[2]) << 17) + ((((s64)prom[4]) * (s64)dt) >> 6);
 634        off -= off2;
 635
 636        /* Sensitivity at actual temperature = SENS_T1 + TCS * dT */
 637        sens = (((s64)prom[1]) << 16) + (((s64)prom[3] * dt) >> 7);
 638        sens -= sens2;
 639
 640        /* Temperature compensated pressure = D1 * SENS - OFF */
 641        *temperature = (temp - t2) * 10;
 642        *pressure = (u32)(((((s64)p_adc * sens) >> 21) - off) >> 15);
 643
 644        return 0;
 645}
 646EXPORT_SYMBOL(ms_sensors_read_temp_and_pressure);
 647
 648MODULE_DESCRIPTION("Measurement-Specialties common i2c driver");
 649MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
 650MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
 651MODULE_LICENSE("GPL v2");
 652
 653