root/drivers/iio/pressure/hp03.c

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

DEFINITIONS

This source file includes following definitions.
  1. hp03_is_writeable_reg
  2. hp03_is_volatile_reg
  3. hp03_get_temp_pressure
  4. hp03_update_temp_pressure
  5. hp03_read_raw
  6. hp03_probe
  7. hp03_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (c) 2016 Marek Vasut <marex@denx.de>
   4  *
   5  * Driver for Hope RF HP03 digital temperature and pressure sensor.
   6  */
   7 
   8 #define pr_fmt(fmt) "hp03: " fmt
   9 
  10 #include <linux/module.h>
  11 #include <linux/delay.h>
  12 #include <linux/gpio/consumer.h>
  13 #include <linux/i2c.h>
  14 #include <linux/regmap.h>
  15 #include <linux/iio/iio.h>
  16 #include <linux/iio/sysfs.h>
  17 
  18 /*
  19  * The HP03 sensor occupies two fixed I2C addresses:
  20  *  0x50 ... read-only EEPROM with calibration data
  21  *  0x77 ... read-write ADC for pressure and temperature
  22  */
  23 #define HP03_EEPROM_ADDR                0x50
  24 #define HP03_ADC_ADDR                   0x77
  25 
  26 #define HP03_EEPROM_CX_OFFSET           0x10
  27 #define HP03_EEPROM_AB_OFFSET           0x1e
  28 #define HP03_EEPROM_CD_OFFSET           0x20
  29 
  30 #define HP03_ADC_WRITE_REG              0xff
  31 #define HP03_ADC_READ_REG               0xfd
  32 #define HP03_ADC_READ_PRESSURE          0xf0    /* D1 in datasheet */
  33 #define HP03_ADC_READ_TEMP              0xe8    /* D2 in datasheet */
  34 
  35 struct hp03_priv {
  36         struct i2c_client       *client;
  37         struct mutex            lock;
  38         struct gpio_desc        *xclr_gpio;
  39 
  40         struct i2c_client       *eeprom_client;
  41         struct regmap           *eeprom_regmap;
  42 
  43         s32                     pressure;       /* kPa */
  44         s32                     temp;           /* Deg. C */
  45 };
  46 
  47 static const struct iio_chan_spec hp03_channels[] = {
  48         {
  49                 .type = IIO_PRESSURE,
  50                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
  51                 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
  52         },
  53         {
  54                 .type = IIO_TEMP,
  55                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
  56                 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
  57         },
  58 };
  59 
  60 static bool hp03_is_writeable_reg(struct device *dev, unsigned int reg)
  61 {
  62         return false;
  63 }
  64 
  65 static bool hp03_is_volatile_reg(struct device *dev, unsigned int reg)
  66 {
  67         return false;
  68 }
  69 
  70 static const struct regmap_config hp03_regmap_config = {
  71         .reg_bits       = 8,
  72         .val_bits       = 8,
  73 
  74         .max_register   = HP03_EEPROM_CD_OFFSET + 1,
  75         .cache_type     = REGCACHE_RBTREE,
  76 
  77         .writeable_reg  = hp03_is_writeable_reg,
  78         .volatile_reg   = hp03_is_volatile_reg,
  79 };
  80 
  81 static int hp03_get_temp_pressure(struct hp03_priv *priv, const u8 reg)
  82 {
  83         int ret;
  84 
  85         ret = i2c_smbus_write_byte_data(priv->client, HP03_ADC_WRITE_REG, reg);
  86         if (ret < 0)
  87                 return ret;
  88 
  89         msleep(50);     /* Wait for conversion to finish */
  90 
  91         return i2c_smbus_read_word_data(priv->client, HP03_ADC_READ_REG);
  92 }
  93 
  94 static int hp03_update_temp_pressure(struct hp03_priv *priv)
  95 {
  96         struct device *dev = &priv->client->dev;
  97         u8 coefs[18];
  98         u16 cx_val[7];
  99         int ab_val, d1_val, d2_val, diff_val, dut, off, sens, x;
 100         int i, ret;
 101 
 102         /* Sample coefficients from EEPROM */
 103         ret = regmap_bulk_read(priv->eeprom_regmap, HP03_EEPROM_CX_OFFSET,
 104                                coefs, sizeof(coefs));
 105         if (ret < 0) {
 106                 dev_err(dev, "Failed to read EEPROM (reg=%02x)\n",
 107                         HP03_EEPROM_CX_OFFSET);
 108                 return ret;
 109         }
 110 
 111         /* Sample Temperature and Pressure */
 112         gpiod_set_value_cansleep(priv->xclr_gpio, 1);
 113 
 114         ret = hp03_get_temp_pressure(priv, HP03_ADC_READ_PRESSURE);
 115         if (ret < 0) {
 116                 dev_err(dev, "Failed to read pressure\n");
 117                 goto err_adc;
 118         }
 119         d1_val = ret;
 120 
 121         ret = hp03_get_temp_pressure(priv, HP03_ADC_READ_TEMP);
 122         if (ret < 0) {
 123                 dev_err(dev, "Failed to read temperature\n");
 124                 goto err_adc;
 125         }
 126         d2_val = ret;
 127 
 128         gpiod_set_value_cansleep(priv->xclr_gpio, 0);
 129 
 130         /* The Cx coefficients and Temp/Pressure values are MSB first. */
 131         for (i = 0; i < 7; i++)
 132                 cx_val[i] = (coefs[2 * i] << 8) | (coefs[(2 * i) + 1] << 0);
 133         d1_val = ((d1_val >> 8) & 0xff) | ((d1_val & 0xff) << 8);
 134         d2_val = ((d2_val >> 8) & 0xff) | ((d2_val & 0xff) << 8);
 135 
 136         /* Coefficient voodoo from the HP03 datasheet. */
 137         if (d2_val >= cx_val[4])
 138                 ab_val = coefs[14];     /* A-value */
 139         else
 140                 ab_val = coefs[15];     /* B-value */
 141 
 142         diff_val = d2_val - cx_val[4];
 143         dut = (ab_val * (diff_val >> 7) * (diff_val >> 7)) >> coefs[16];
 144         dut = diff_val - dut;
 145 
 146         off = (cx_val[1] + (((cx_val[3] - 1024) * dut) >> 14)) * 4;
 147         sens = cx_val[0] + ((cx_val[2] * dut) >> 10);
 148         x = ((sens * (d1_val - 7168)) >> 14) - off;
 149 
 150         priv->pressure = ((x * 100) >> 5) + (cx_val[6] * 10);
 151         priv->temp = 250 + ((dut * cx_val[5]) >> 16) - (dut >> coefs[17]);
 152 
 153         return 0;
 154 
 155 err_adc:
 156         gpiod_set_value_cansleep(priv->xclr_gpio, 0);
 157         return ret;
 158 }
 159 
 160 static int hp03_read_raw(struct iio_dev *indio_dev,
 161                          struct iio_chan_spec const *chan,
 162                          int *val, int *val2, long mask)
 163 {
 164         struct hp03_priv *priv = iio_priv(indio_dev);
 165         int ret;
 166 
 167         mutex_lock(&priv->lock);
 168         ret = hp03_update_temp_pressure(priv);
 169         mutex_unlock(&priv->lock);
 170 
 171         if (ret)
 172                 return ret;
 173 
 174         switch (mask) {
 175         case IIO_CHAN_INFO_RAW:
 176                 switch (chan->type) {
 177                 case IIO_PRESSURE:
 178                         *val = priv->pressure;
 179                         return IIO_VAL_INT;
 180                 case IIO_TEMP:
 181                         *val = priv->temp;
 182                         return IIO_VAL_INT;
 183                 default:
 184                         return -EINVAL;
 185                 }
 186                 break;
 187         case IIO_CHAN_INFO_SCALE:
 188                 switch (chan->type) {
 189                 case IIO_PRESSURE:
 190                         *val = 0;
 191                         *val2 = 1000;
 192                         return IIO_VAL_INT_PLUS_MICRO;
 193                 case IIO_TEMP:
 194                         *val = 10;
 195                         return IIO_VAL_INT;
 196                 default:
 197                         return -EINVAL;
 198                 }
 199                 break;
 200         default:
 201                 return -EINVAL;
 202         }
 203 
 204         return -EINVAL;
 205 }
 206 
 207 static const struct iio_info hp03_info = {
 208         .read_raw       = &hp03_read_raw,
 209 };
 210 
 211 static int hp03_probe(struct i2c_client *client,
 212                       const struct i2c_device_id *id)
 213 {
 214         struct device *dev = &client->dev;
 215         struct iio_dev *indio_dev;
 216         struct hp03_priv *priv;
 217         int ret;
 218 
 219         indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
 220         if (!indio_dev)
 221                 return -ENOMEM;
 222 
 223         priv = iio_priv(indio_dev);
 224         priv->client = client;
 225         mutex_init(&priv->lock);
 226 
 227         indio_dev->dev.parent = dev;
 228         indio_dev->name = id->name;
 229         indio_dev->channels = hp03_channels;
 230         indio_dev->num_channels = ARRAY_SIZE(hp03_channels);
 231         indio_dev->info = &hp03_info;
 232         indio_dev->modes = INDIO_DIRECT_MODE;
 233 
 234         priv->xclr_gpio = devm_gpiod_get_index(dev, "xclr", 0, GPIOD_OUT_HIGH);
 235         if (IS_ERR(priv->xclr_gpio)) {
 236                 dev_err(dev, "Failed to claim XCLR GPIO\n");
 237                 ret = PTR_ERR(priv->xclr_gpio);
 238                 return ret;
 239         }
 240 
 241         /*
 242          * Allocate another device for the on-sensor EEPROM,
 243          * which has it's dedicated I2C address and contains
 244          * the calibration constants for the sensor.
 245          */
 246         priv->eeprom_client = i2c_new_dummy_device(client->adapter, HP03_EEPROM_ADDR);
 247         if (IS_ERR(priv->eeprom_client)) {
 248                 dev_err(dev, "New EEPROM I2C device failed\n");
 249                 return PTR_ERR(priv->eeprom_client);
 250         }
 251 
 252         priv->eeprom_regmap = regmap_init_i2c(priv->eeprom_client,
 253                                               &hp03_regmap_config);
 254         if (IS_ERR(priv->eeprom_regmap)) {
 255                 dev_err(dev, "Failed to allocate EEPROM regmap\n");
 256                 ret = PTR_ERR(priv->eeprom_regmap);
 257                 goto err_cleanup_eeprom_client;
 258         }
 259 
 260         ret = iio_device_register(indio_dev);
 261         if (ret) {
 262                 dev_err(dev, "Failed to register IIO device\n");
 263                 goto err_cleanup_eeprom_regmap;
 264         }
 265 
 266         i2c_set_clientdata(client, indio_dev);
 267 
 268         return 0;
 269 
 270 err_cleanup_eeprom_regmap:
 271         regmap_exit(priv->eeprom_regmap);
 272 
 273 err_cleanup_eeprom_client:
 274         i2c_unregister_device(priv->eeprom_client);
 275         return ret;
 276 }
 277 
 278 static int hp03_remove(struct i2c_client *client)
 279 {
 280         struct iio_dev *indio_dev = i2c_get_clientdata(client);
 281         struct hp03_priv *priv = iio_priv(indio_dev);
 282 
 283         iio_device_unregister(indio_dev);
 284         regmap_exit(priv->eeprom_regmap);
 285         i2c_unregister_device(priv->eeprom_client);
 286 
 287         return 0;
 288 }
 289 
 290 static const struct i2c_device_id hp03_id[] = {
 291         { "hp03", 0 },
 292         { },
 293 };
 294 MODULE_DEVICE_TABLE(i2c, hp03_id);
 295 
 296 static const struct of_device_id hp03_of_match[] = {
 297         { .compatible = "hoperf,hp03" },
 298         { },
 299 };
 300 MODULE_DEVICE_TABLE(of, hp03_of_match);
 301 
 302 static struct i2c_driver hp03_driver = {
 303         .driver = {
 304                 .name   = "hp03",
 305                 .of_match_table = hp03_of_match,
 306         },
 307         .probe          = hp03_probe,
 308         .remove         = hp03_remove,
 309         .id_table       = hp03_id,
 310 };
 311 module_i2c_driver(hp03_driver);
 312 
 313 MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
 314 MODULE_DESCRIPTION("Driver for Hope RF HP03 pressure and temperature sensor");
 315 MODULE_LICENSE("GPL v2");

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