Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * hp206c.c - HOPERF HP206C precision barometer and altimeter sensor
0004  *
0005  * Copyright (c) 2016, Intel Corporation.
0006  *
0007  * (7-bit I2C slave address 0x76)
0008  *
0009  * Datasheet:
0010  *  http://www.hoperf.com/upload/sensor/HP206C_DataSheet_EN_V2.0.pdf
0011  */
0012 
0013 #include <linux/module.h>
0014 #include <linux/i2c.h>
0015 #include <linux/iio/iio.h>
0016 #include <linux/iio/sysfs.h>
0017 #include <linux/delay.h>
0018 #include <linux/util_macros.h>
0019 #include <linux/acpi.h>
0020 
0021 #include <asm/unaligned.h>
0022 
0023 /* I2C commands: */
0024 #define HP206C_CMD_SOFT_RST 0x06
0025 
0026 #define HP206C_CMD_ADC_CVT  0x40
0027 
0028 #define HP206C_CMD_ADC_CVT_OSR_4096 0x00
0029 #define HP206C_CMD_ADC_CVT_OSR_2048 0x04
0030 #define HP206C_CMD_ADC_CVT_OSR_1024 0x08
0031 #define HP206C_CMD_ADC_CVT_OSR_512  0x0c
0032 #define HP206C_CMD_ADC_CVT_OSR_256  0x10
0033 #define HP206C_CMD_ADC_CVT_OSR_128  0x14
0034 
0035 #define HP206C_CMD_ADC_CVT_CHNL_PT  0x00
0036 #define HP206C_CMD_ADC_CVT_CHNL_T   0x02
0037 
0038 #define HP206C_CMD_READ_P   0x30
0039 #define HP206C_CMD_READ_T   0x32
0040 
0041 #define HP206C_CMD_READ_REG 0x80
0042 #define HP206C_CMD_WRITE_REG    0xc0
0043 
0044 #define HP206C_REG_INT_EN   0x0b
0045 #define HP206C_REG_INT_CFG  0x0c
0046 
0047 #define HP206C_REG_INT_SRC  0x0d
0048 #define HP206C_FLAG_DEV_RDY 0x40
0049 
0050 #define HP206C_REG_PARA     0x0f
0051 #define HP206C_FLAG_CMPS_EN 0x80
0052 
0053 /* Maximum spin for DEV_RDY */
0054 #define HP206C_MAX_DEV_RDY_WAIT_COUNT 20
0055 #define HP206C_DEV_RDY_WAIT_US    20000
0056 
0057 struct hp206c_data {
0058     struct mutex mutex;
0059     struct i2c_client *client;
0060     int temp_osr_index;
0061     int pres_osr_index;
0062 };
0063 
0064 struct hp206c_osr_setting {
0065     u8 osr_mask;
0066     unsigned int temp_conv_time_us;
0067     unsigned int pres_conv_time_us;
0068 };
0069 
0070 /* Data from Table 5 in datasheet. */
0071 static const struct hp206c_osr_setting hp206c_osr_settings[] = {
0072     { HP206C_CMD_ADC_CVT_OSR_4096,  65600,  131100  },
0073     { HP206C_CMD_ADC_CVT_OSR_2048,  32800,  65600   },
0074     { HP206C_CMD_ADC_CVT_OSR_1024,  16400,  32800   },
0075     { HP206C_CMD_ADC_CVT_OSR_512,   8200,   16400   },
0076     { HP206C_CMD_ADC_CVT_OSR_256,   4100,   8200    },
0077     { HP206C_CMD_ADC_CVT_OSR_128,   2100,   4100    },
0078 };
0079 static const int hp206c_osr_rates[] = { 4096, 2048, 1024, 512, 256, 128 };
0080 static const char hp206c_osr_rates_str[] = "4096 2048 1024 512 256 128";
0081 
0082 static inline int hp206c_read_reg(struct i2c_client *client, u8 reg)
0083 {
0084     return i2c_smbus_read_byte_data(client, HP206C_CMD_READ_REG | reg);
0085 }
0086 
0087 static inline int hp206c_write_reg(struct i2c_client *client, u8 reg, u8 val)
0088 {
0089     return i2c_smbus_write_byte_data(client,
0090             HP206C_CMD_WRITE_REG | reg, val);
0091 }
0092 
0093 static int hp206c_read_20bit(struct i2c_client *client, u8 cmd)
0094 {
0095     int ret;
0096     u8 values[3];
0097 
0098     ret = i2c_smbus_read_i2c_block_data(client, cmd, sizeof(values), values);
0099     if (ret < 0)
0100         return ret;
0101     if (ret != sizeof(values))
0102         return -EIO;
0103     return get_unaligned_be24(&values[0]) & GENMASK(19, 0);
0104 }
0105 
0106 /* Spin for max 160ms until DEV_RDY is 1, or return error. */
0107 static int hp206c_wait_dev_rdy(struct iio_dev *indio_dev)
0108 {
0109     int ret;
0110     int count = 0;
0111     struct hp206c_data *data = iio_priv(indio_dev);
0112     struct i2c_client *client = data->client;
0113 
0114     while (++count <= HP206C_MAX_DEV_RDY_WAIT_COUNT) {
0115         ret = hp206c_read_reg(client, HP206C_REG_INT_SRC);
0116         if (ret < 0) {
0117             dev_err(&indio_dev->dev, "Failed READ_REG INT_SRC: %d\n", ret);
0118             return ret;
0119         }
0120         if (ret & HP206C_FLAG_DEV_RDY)
0121             return 0;
0122         usleep_range(HP206C_DEV_RDY_WAIT_US, HP206C_DEV_RDY_WAIT_US * 3 / 2);
0123     }
0124     return -ETIMEDOUT;
0125 }
0126 
0127 static int hp206c_set_compensation(struct i2c_client *client, bool enabled)
0128 {
0129     int val;
0130 
0131     val = hp206c_read_reg(client, HP206C_REG_PARA);
0132     if (val < 0)
0133         return val;
0134     if (enabled)
0135         val |= HP206C_FLAG_CMPS_EN;
0136     else
0137         val &= ~HP206C_FLAG_CMPS_EN;
0138 
0139     return hp206c_write_reg(client, HP206C_REG_PARA, val);
0140 }
0141 
0142 /* Do a soft reset */
0143 static int hp206c_soft_reset(struct iio_dev *indio_dev)
0144 {
0145     int ret;
0146     struct hp206c_data *data = iio_priv(indio_dev);
0147     struct i2c_client *client = data->client;
0148 
0149     ret = i2c_smbus_write_byte(client, HP206C_CMD_SOFT_RST);
0150     if (ret) {
0151         dev_err(&client->dev, "Failed to reset device: %d\n", ret);
0152         return ret;
0153     }
0154 
0155     usleep_range(400, 600);
0156 
0157     ret = hp206c_wait_dev_rdy(indio_dev);
0158     if (ret) {
0159         dev_err(&client->dev, "Device not ready after soft reset: %d\n", ret);
0160         return ret;
0161     }
0162 
0163     ret = hp206c_set_compensation(client, true);
0164     if (ret)
0165         dev_err(&client->dev, "Failed to enable compensation: %d\n", ret);
0166     return ret;
0167 }
0168 
0169 static int hp206c_conv_and_read(struct iio_dev *indio_dev,
0170                 u8 conv_cmd, u8 read_cmd,
0171                 unsigned int sleep_us)
0172 {
0173     int ret;
0174     struct hp206c_data *data = iio_priv(indio_dev);
0175     struct i2c_client *client = data->client;
0176 
0177     ret = hp206c_wait_dev_rdy(indio_dev);
0178     if (ret < 0) {
0179         dev_err(&indio_dev->dev, "Device not ready: %d\n", ret);
0180         return ret;
0181     }
0182 
0183     ret = i2c_smbus_write_byte(client, conv_cmd);
0184     if (ret < 0) {
0185         dev_err(&indio_dev->dev, "Failed convert: %d\n", ret);
0186         return ret;
0187     }
0188 
0189     usleep_range(sleep_us, sleep_us * 3 / 2);
0190 
0191     ret = hp206c_wait_dev_rdy(indio_dev);
0192     if (ret < 0) {
0193         dev_err(&indio_dev->dev, "Device not ready: %d\n", ret);
0194         return ret;
0195     }
0196 
0197     ret = hp206c_read_20bit(client, read_cmd);
0198     if (ret < 0)
0199         dev_err(&indio_dev->dev, "Failed read: %d\n", ret);
0200 
0201     return ret;
0202 }
0203 
0204 static int hp206c_read_raw(struct iio_dev *indio_dev,
0205                struct iio_chan_spec const *chan, int *val,
0206                int *val2, long mask)
0207 {
0208     int ret;
0209     struct hp206c_data *data = iio_priv(indio_dev);
0210     const struct hp206c_osr_setting *osr_setting;
0211     u8 conv_cmd;
0212 
0213     mutex_lock(&data->mutex);
0214 
0215     switch (mask) {
0216     case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
0217         switch (chan->type) {
0218         case IIO_TEMP:
0219             *val = hp206c_osr_rates[data->temp_osr_index];
0220             ret = IIO_VAL_INT;
0221             break;
0222 
0223         case IIO_PRESSURE:
0224             *val = hp206c_osr_rates[data->pres_osr_index];
0225             ret = IIO_VAL_INT;
0226             break;
0227         default:
0228             ret = -EINVAL;
0229         }
0230         break;
0231 
0232     case IIO_CHAN_INFO_RAW:
0233         switch (chan->type) {
0234         case IIO_TEMP:
0235             osr_setting = &hp206c_osr_settings[data->temp_osr_index];
0236             conv_cmd = HP206C_CMD_ADC_CVT |
0237                     osr_setting->osr_mask |
0238                     HP206C_CMD_ADC_CVT_CHNL_T;
0239             ret = hp206c_conv_and_read(indio_dev,
0240                     conv_cmd,
0241                     HP206C_CMD_READ_T,
0242                     osr_setting->temp_conv_time_us);
0243             if (ret >= 0) {
0244                 /* 20 significant bits are provided.
0245                  * Extend sign over the rest.
0246                  */
0247                 *val = sign_extend32(ret, 19);
0248                 ret = IIO_VAL_INT;
0249             }
0250             break;
0251 
0252         case IIO_PRESSURE:
0253             osr_setting = &hp206c_osr_settings[data->pres_osr_index];
0254             conv_cmd = HP206C_CMD_ADC_CVT |
0255                     osr_setting->osr_mask |
0256                     HP206C_CMD_ADC_CVT_CHNL_PT;
0257             ret = hp206c_conv_and_read(indio_dev,
0258                     conv_cmd,
0259                     HP206C_CMD_READ_P,
0260                     osr_setting->pres_conv_time_us);
0261             if (ret >= 0) {
0262                 *val = ret;
0263                 ret = IIO_VAL_INT;
0264             }
0265             break;
0266         default:
0267             ret = -EINVAL;
0268         }
0269         break;
0270 
0271     case IIO_CHAN_INFO_SCALE:
0272         switch (chan->type) {
0273         case IIO_TEMP:
0274             *val = 0;
0275             *val2 = 10000;
0276             ret = IIO_VAL_INT_PLUS_MICRO;
0277             break;
0278 
0279         case IIO_PRESSURE:
0280             *val = 0;
0281             *val2 = 1000;
0282             ret = IIO_VAL_INT_PLUS_MICRO;
0283             break;
0284         default:
0285             ret = -EINVAL;
0286         }
0287         break;
0288 
0289     default:
0290         ret = -EINVAL;
0291     }
0292 
0293     mutex_unlock(&data->mutex);
0294     return ret;
0295 }
0296 
0297 static int hp206c_write_raw(struct iio_dev *indio_dev,
0298                 struct iio_chan_spec const *chan,
0299                 int val, int val2, long mask)
0300 {
0301     int ret = 0;
0302     struct hp206c_data *data = iio_priv(indio_dev);
0303 
0304     if (mask != IIO_CHAN_INFO_OVERSAMPLING_RATIO)
0305         return -EINVAL;
0306     mutex_lock(&data->mutex);
0307     switch (chan->type) {
0308     case IIO_TEMP:
0309         data->temp_osr_index = find_closest_descending(val,
0310             hp206c_osr_rates, ARRAY_SIZE(hp206c_osr_rates));
0311         break;
0312     case IIO_PRESSURE:
0313         data->pres_osr_index = find_closest_descending(val,
0314             hp206c_osr_rates, ARRAY_SIZE(hp206c_osr_rates));
0315         break;
0316     default:
0317         ret = -EINVAL;
0318     }
0319     mutex_unlock(&data->mutex);
0320     return ret;
0321 }
0322 
0323 static const struct iio_chan_spec hp206c_channels[] = {
0324     {
0325         .type = IIO_TEMP,
0326         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
0327                       BIT(IIO_CHAN_INFO_SCALE) |
0328                       BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
0329     },
0330     {
0331         .type = IIO_PRESSURE,
0332         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
0333                       BIT(IIO_CHAN_INFO_SCALE) |
0334                       BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
0335     }
0336 };
0337 
0338 static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(hp206c_osr_rates_str);
0339 
0340 static struct attribute *hp206c_attributes[] = {
0341     &iio_const_attr_sampling_frequency_available.dev_attr.attr,
0342     NULL,
0343 };
0344 
0345 static const struct attribute_group hp206c_attribute_group = {
0346     .attrs = hp206c_attributes,
0347 };
0348 
0349 static const struct iio_info hp206c_info = {
0350     .attrs = &hp206c_attribute_group,
0351     .read_raw = hp206c_read_raw,
0352     .write_raw = hp206c_write_raw,
0353 };
0354 
0355 static int hp206c_probe(struct i2c_client *client,
0356             const struct i2c_device_id *id)
0357 {
0358     struct iio_dev *indio_dev;
0359     struct hp206c_data *data;
0360     int ret;
0361 
0362     if (!i2c_check_functionality(client->adapter,
0363                      I2C_FUNC_SMBUS_BYTE |
0364                      I2C_FUNC_SMBUS_BYTE_DATA |
0365                      I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
0366         dev_err(&client->dev, "Adapter does not support "
0367                 "all required i2c functionality\n");
0368         return -ENODEV;
0369     }
0370 
0371     indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
0372     if (!indio_dev)
0373         return -ENOMEM;
0374 
0375     data = iio_priv(indio_dev);
0376     data->client = client;
0377     mutex_init(&data->mutex);
0378 
0379     indio_dev->info = &hp206c_info;
0380     indio_dev->name = id->name;
0381     indio_dev->modes = INDIO_DIRECT_MODE;
0382     indio_dev->channels = hp206c_channels;
0383     indio_dev->num_channels = ARRAY_SIZE(hp206c_channels);
0384 
0385     i2c_set_clientdata(client, indio_dev);
0386 
0387     /* Do a soft reset on probe */
0388     ret = hp206c_soft_reset(indio_dev);
0389     if (ret) {
0390         dev_err(&client->dev, "Failed to reset on startup: %d\n", ret);
0391         return -ENODEV;
0392     }
0393 
0394     return devm_iio_device_register(&client->dev, indio_dev);
0395 }
0396 
0397 static const struct i2c_device_id hp206c_id[] = {
0398     {"hp206c"},
0399     {}
0400 };
0401 MODULE_DEVICE_TABLE(i2c, hp206c_id);
0402 
0403 #ifdef CONFIG_ACPI
0404 static const struct acpi_device_id hp206c_acpi_match[] = {
0405     {"HOP206C", 0},
0406     { },
0407 };
0408 MODULE_DEVICE_TABLE(acpi, hp206c_acpi_match);
0409 #endif
0410 
0411 static struct i2c_driver hp206c_driver = {
0412     .probe = hp206c_probe,
0413     .id_table = hp206c_id,
0414     .driver = {
0415         .name = "hp206c",
0416         .acpi_match_table = ACPI_PTR(hp206c_acpi_match),
0417     },
0418 };
0419 
0420 module_i2c_driver(hp206c_driver);
0421 
0422 MODULE_DESCRIPTION("HOPERF HP206C precision barometer and altimeter sensor");
0423 MODULE_AUTHOR("Leonard Crestez <leonard.crestez@intel.com>");
0424 MODULE_LICENSE("GPL v2");