Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2016 Marek Vasut <marex@denx.de>
0004  *
0005  * Driver for Hope RF HP03 digital temperature and pressure sensor.
0006  */
0007 
0008 #define pr_fmt(fmt) "hp03: " fmt
0009 
0010 #include <linux/module.h>
0011 #include <linux/delay.h>
0012 #include <linux/gpio/consumer.h>
0013 #include <linux/i2c.h>
0014 #include <linux/regmap.h>
0015 #include <linux/iio/iio.h>
0016 #include <linux/iio/sysfs.h>
0017 
0018 /*
0019  * The HP03 sensor occupies two fixed I2C addresses:
0020  *  0x50 ... read-only EEPROM with calibration data
0021  *  0x77 ... read-write ADC for pressure and temperature
0022  */
0023 #define HP03_EEPROM_ADDR        0x50
0024 #define HP03_ADC_ADDR           0x77
0025 
0026 #define HP03_EEPROM_CX_OFFSET       0x10
0027 #define HP03_EEPROM_AB_OFFSET       0x1e
0028 #define HP03_EEPROM_CD_OFFSET       0x20
0029 
0030 #define HP03_ADC_WRITE_REG      0xff
0031 #define HP03_ADC_READ_REG       0xfd
0032 #define HP03_ADC_READ_PRESSURE      0xf0    /* D1 in datasheet */
0033 #define HP03_ADC_READ_TEMP      0xe8    /* D2 in datasheet */
0034 
0035 struct hp03_priv {
0036     struct i2c_client   *client;
0037     struct mutex        lock;
0038     struct gpio_desc    *xclr_gpio;
0039 
0040     struct i2c_client   *eeprom_client;
0041     struct regmap       *eeprom_regmap;
0042 
0043     s32         pressure;   /* kPa */
0044     s32         temp;       /* Deg. C */
0045 };
0046 
0047 static const struct iio_chan_spec hp03_channels[] = {
0048     {
0049         .type = IIO_PRESSURE,
0050         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
0051         .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
0052     },
0053     {
0054         .type = IIO_TEMP,
0055         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
0056         .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
0057     },
0058 };
0059 
0060 static bool hp03_is_writeable_reg(struct device *dev, unsigned int reg)
0061 {
0062     return false;
0063 }
0064 
0065 static bool hp03_is_volatile_reg(struct device *dev, unsigned int reg)
0066 {
0067     return false;
0068 }
0069 
0070 static const struct regmap_config hp03_regmap_config = {
0071     .reg_bits   = 8,
0072     .val_bits   = 8,
0073 
0074     .max_register   = HP03_EEPROM_CD_OFFSET + 1,
0075     .cache_type = REGCACHE_RBTREE,
0076 
0077     .writeable_reg  = hp03_is_writeable_reg,
0078     .volatile_reg   = hp03_is_volatile_reg,
0079 };
0080 
0081 static int hp03_get_temp_pressure(struct hp03_priv *priv, const u8 reg)
0082 {
0083     int ret;
0084 
0085     ret = i2c_smbus_write_byte_data(priv->client, HP03_ADC_WRITE_REG, reg);
0086     if (ret < 0)
0087         return ret;
0088 
0089     msleep(50); /* Wait for conversion to finish */
0090 
0091     return i2c_smbus_read_word_data(priv->client, HP03_ADC_READ_REG);
0092 }
0093 
0094 static int hp03_update_temp_pressure(struct hp03_priv *priv)
0095 {
0096     struct device *dev = &priv->client->dev;
0097     u8 coefs[18];
0098     u16 cx_val[7];
0099     int ab_val, d1_val, d2_val, diff_val, dut, off, sens, x;
0100     int i, ret;
0101 
0102     /* Sample coefficients from EEPROM */
0103     ret = regmap_bulk_read(priv->eeprom_regmap, HP03_EEPROM_CX_OFFSET,
0104                    coefs, sizeof(coefs));
0105     if (ret < 0) {
0106         dev_err(dev, "Failed to read EEPROM (reg=%02x)\n",
0107             HP03_EEPROM_CX_OFFSET);
0108         return ret;
0109     }
0110 
0111     /* Sample Temperature and Pressure */
0112     gpiod_set_value_cansleep(priv->xclr_gpio, 1);
0113 
0114     ret = hp03_get_temp_pressure(priv, HP03_ADC_READ_PRESSURE);
0115     if (ret < 0) {
0116         dev_err(dev, "Failed to read pressure\n");
0117         goto err_adc;
0118     }
0119     d1_val = ret;
0120 
0121     ret = hp03_get_temp_pressure(priv, HP03_ADC_READ_TEMP);
0122     if (ret < 0) {
0123         dev_err(dev, "Failed to read temperature\n");
0124         goto err_adc;
0125     }
0126     d2_val = ret;
0127 
0128     gpiod_set_value_cansleep(priv->xclr_gpio, 0);
0129 
0130     /* The Cx coefficients and Temp/Pressure values are MSB first. */
0131     for (i = 0; i < 7; i++)
0132         cx_val[i] = (coefs[2 * i] << 8) | (coefs[(2 * i) + 1] << 0);
0133     d1_val = ((d1_val >> 8) & 0xff) | ((d1_val & 0xff) << 8);
0134     d2_val = ((d2_val >> 8) & 0xff) | ((d2_val & 0xff) << 8);
0135 
0136     /* Coefficient voodoo from the HP03 datasheet. */
0137     if (d2_val >= cx_val[4])
0138         ab_val = coefs[14]; /* A-value */
0139     else
0140         ab_val = coefs[15]; /* B-value */
0141 
0142     diff_val = d2_val - cx_val[4];
0143     dut = (ab_val * (diff_val >> 7) * (diff_val >> 7)) >> coefs[16];
0144     dut = diff_val - dut;
0145 
0146     off = (cx_val[1] + (((cx_val[3] - 1024) * dut) >> 14)) * 4;
0147     sens = cx_val[0] + ((cx_val[2] * dut) >> 10);
0148     x = ((sens * (d1_val - 7168)) >> 14) - off;
0149 
0150     priv->pressure = ((x * 100) >> 5) + (cx_val[6] * 10);
0151     priv->temp = 250 + ((dut * cx_val[5]) >> 16) - (dut >> coefs[17]);
0152 
0153     return 0;
0154 
0155 err_adc:
0156     gpiod_set_value_cansleep(priv->xclr_gpio, 0);
0157     return ret;
0158 }
0159 
0160 static int hp03_read_raw(struct iio_dev *indio_dev,
0161              struct iio_chan_spec const *chan,
0162              int *val, int *val2, long mask)
0163 {
0164     struct hp03_priv *priv = iio_priv(indio_dev);
0165     int ret;
0166 
0167     mutex_lock(&priv->lock);
0168     ret = hp03_update_temp_pressure(priv);
0169     mutex_unlock(&priv->lock);
0170 
0171     if (ret)
0172         return ret;
0173 
0174     switch (mask) {
0175     case IIO_CHAN_INFO_RAW:
0176         switch (chan->type) {
0177         case IIO_PRESSURE:
0178             *val = priv->pressure;
0179             return IIO_VAL_INT;
0180         case IIO_TEMP:
0181             *val = priv->temp;
0182             return IIO_VAL_INT;
0183         default:
0184             return -EINVAL;
0185         }
0186         break;
0187     case IIO_CHAN_INFO_SCALE:
0188         switch (chan->type) {
0189         case IIO_PRESSURE:
0190             *val = 0;
0191             *val2 = 1000;
0192             return IIO_VAL_INT_PLUS_MICRO;
0193         case IIO_TEMP:
0194             *val = 10;
0195             return IIO_VAL_INT;
0196         default:
0197             return -EINVAL;
0198         }
0199         break;
0200     default:
0201         return -EINVAL;
0202     }
0203 
0204     return -EINVAL;
0205 }
0206 
0207 static const struct iio_info hp03_info = {
0208     .read_raw   = &hp03_read_raw,
0209 };
0210 
0211 static int hp03_probe(struct i2c_client *client,
0212               const struct i2c_device_id *id)
0213 {
0214     struct device *dev = &client->dev;
0215     struct iio_dev *indio_dev;
0216     struct hp03_priv *priv;
0217     int ret;
0218 
0219     indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
0220     if (!indio_dev)
0221         return -ENOMEM;
0222 
0223     priv = iio_priv(indio_dev);
0224     priv->client = client;
0225     mutex_init(&priv->lock);
0226 
0227     indio_dev->name = id->name;
0228     indio_dev->channels = hp03_channels;
0229     indio_dev->num_channels = ARRAY_SIZE(hp03_channels);
0230     indio_dev->info = &hp03_info;
0231     indio_dev->modes = INDIO_DIRECT_MODE;
0232 
0233     priv->xclr_gpio = devm_gpiod_get_index(dev, "xclr", 0, GPIOD_OUT_HIGH);
0234     if (IS_ERR(priv->xclr_gpio)) {
0235         dev_err(dev, "Failed to claim XCLR GPIO\n");
0236         ret = PTR_ERR(priv->xclr_gpio);
0237         return ret;
0238     }
0239 
0240     /*
0241      * Allocate another device for the on-sensor EEPROM,
0242      * which has it's dedicated I2C address and contains
0243      * the calibration constants for the sensor.
0244      */
0245     priv->eeprom_client = devm_i2c_new_dummy_device(dev, client->adapter,
0246                             HP03_EEPROM_ADDR);
0247     if (IS_ERR(priv->eeprom_client)) {
0248         dev_err(dev, "New EEPROM I2C device failed\n");
0249         return PTR_ERR(priv->eeprom_client);
0250     }
0251 
0252     priv->eeprom_regmap = devm_regmap_init_i2c(priv->eeprom_client,
0253                            &hp03_regmap_config);
0254     if (IS_ERR(priv->eeprom_regmap)) {
0255         dev_err(dev, "Failed to allocate EEPROM regmap\n");
0256         return PTR_ERR(priv->eeprom_regmap);
0257     }
0258 
0259     ret = devm_iio_device_register(dev, indio_dev);
0260     if (ret) {
0261         dev_err(dev, "Failed to register IIO device\n");
0262         return ret;
0263     }
0264 
0265     return 0;
0266 }
0267 
0268 static const struct i2c_device_id hp03_id[] = {
0269     { "hp03", 0 },
0270     { },
0271 };
0272 MODULE_DEVICE_TABLE(i2c, hp03_id);
0273 
0274 static const struct of_device_id hp03_of_match[] = {
0275     { .compatible = "hoperf,hp03" },
0276     { },
0277 };
0278 MODULE_DEVICE_TABLE(of, hp03_of_match);
0279 
0280 static struct i2c_driver hp03_driver = {
0281     .driver = {
0282         .name   = "hp03",
0283         .of_match_table = hp03_of_match,
0284     },
0285     .probe      = hp03_probe,
0286     .id_table   = hp03_id,
0287 };
0288 module_i2c_driver(hp03_driver);
0289 
0290 MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
0291 MODULE_DESCRIPTION("Driver for Hope RF HP03 pressure and temperature sensor");
0292 MODULE_LICENSE("GPL v2");