root/drivers/iio/pressure/hp206c.c

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

DEFINITIONS

This source file includes following definitions.
  1. hp206c_read_reg
  2. hp206c_write_reg
  3. hp206c_read_20bit
  4. hp206c_wait_dev_rdy
  5. hp206c_set_compensation
  6. hp206c_soft_reset
  7. hp206c_conv_and_read
  8. hp206c_read_raw
  9. hp206c_write_raw
  10. hp206c_probe

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * hp206c.c - HOPERF HP206C precision barometer and altimeter sensor
   4  *
   5  * Copyright (c) 2016, Intel Corporation.
   6  *
   7  * (7-bit I2C slave address 0x76)
   8  *
   9  * Datasheet:
  10  *  http://www.hoperf.com/upload/sensor/HP206C_DataSheet_EN_V2.0.pdf
  11  */
  12 
  13 #include <linux/module.h>
  14 #include <linux/i2c.h>
  15 #include <linux/iio/iio.h>
  16 #include <linux/iio/sysfs.h>
  17 #include <linux/delay.h>
  18 #include <linux/util_macros.h>
  19 #include <linux/acpi.h>
  20 
  21 /* I2C commands: */
  22 #define HP206C_CMD_SOFT_RST     0x06
  23 
  24 #define HP206C_CMD_ADC_CVT      0x40
  25 
  26 #define HP206C_CMD_ADC_CVT_OSR_4096     0x00
  27 #define HP206C_CMD_ADC_CVT_OSR_2048     0x04
  28 #define HP206C_CMD_ADC_CVT_OSR_1024     0x08
  29 #define HP206C_CMD_ADC_CVT_OSR_512      0x0c
  30 #define HP206C_CMD_ADC_CVT_OSR_256      0x10
  31 #define HP206C_CMD_ADC_CVT_OSR_128      0x14
  32 
  33 #define HP206C_CMD_ADC_CVT_CHNL_PT      0x00
  34 #define HP206C_CMD_ADC_CVT_CHNL_T       0x02
  35 
  36 #define HP206C_CMD_READ_P       0x30
  37 #define HP206C_CMD_READ_T       0x32
  38 
  39 #define HP206C_CMD_READ_REG     0x80
  40 #define HP206C_CMD_WRITE_REG    0xc0
  41 
  42 #define HP206C_REG_INT_EN       0x0b
  43 #define HP206C_REG_INT_CFG      0x0c
  44 
  45 #define HP206C_REG_INT_SRC      0x0d
  46 #define HP206C_FLAG_DEV_RDY     0x40
  47 
  48 #define HP206C_REG_PARA         0x0f
  49 #define HP206C_FLAG_CMPS_EN     0x80
  50 
  51 /* Maximum spin for DEV_RDY */
  52 #define HP206C_MAX_DEV_RDY_WAIT_COUNT 20
  53 #define HP206C_DEV_RDY_WAIT_US    20000
  54 
  55 struct hp206c_data {
  56         struct mutex mutex;
  57         struct i2c_client *client;
  58         int temp_osr_index;
  59         int pres_osr_index;
  60 };
  61 
  62 struct hp206c_osr_setting {
  63         u8 osr_mask;
  64         unsigned int temp_conv_time_us;
  65         unsigned int pres_conv_time_us;
  66 };
  67 
  68 /* Data from Table 5 in datasheet. */
  69 static const struct hp206c_osr_setting hp206c_osr_settings[] = {
  70         { HP206C_CMD_ADC_CVT_OSR_4096,  65600,  131100  },
  71         { HP206C_CMD_ADC_CVT_OSR_2048,  32800,  65600   },
  72         { HP206C_CMD_ADC_CVT_OSR_1024,  16400,  32800   },
  73         { HP206C_CMD_ADC_CVT_OSR_512,   8200,   16400   },
  74         { HP206C_CMD_ADC_CVT_OSR_256,   4100,   8200    },
  75         { HP206C_CMD_ADC_CVT_OSR_128,   2100,   4100    },
  76 };
  77 static const int hp206c_osr_rates[] = { 4096, 2048, 1024, 512, 256, 128 };
  78 static const char hp206c_osr_rates_str[] = "4096 2048 1024 512 256 128";
  79 
  80 static inline int hp206c_read_reg(struct i2c_client *client, u8 reg)
  81 {
  82         return i2c_smbus_read_byte_data(client, HP206C_CMD_READ_REG | reg);
  83 }
  84 
  85 static inline int hp206c_write_reg(struct i2c_client *client, u8 reg, u8 val)
  86 {
  87         return i2c_smbus_write_byte_data(client,
  88                         HP206C_CMD_WRITE_REG | reg, val);
  89 }
  90 
  91 static int hp206c_read_20bit(struct i2c_client *client, u8 cmd)
  92 {
  93         int ret;
  94         u8 values[3];
  95 
  96         ret = i2c_smbus_read_i2c_block_data(client, cmd, 3, values);
  97         if (ret < 0)
  98                 return ret;
  99         if (ret != 3)
 100                 return -EIO;
 101         return ((values[0] & 0xF) << 16) | (values[1] << 8) | (values[2]);
 102 }
 103 
 104 /* Spin for max 160ms until DEV_RDY is 1, or return error. */
 105 static int hp206c_wait_dev_rdy(struct iio_dev *indio_dev)
 106 {
 107         int ret;
 108         int count = 0;
 109         struct hp206c_data *data = iio_priv(indio_dev);
 110         struct i2c_client *client = data->client;
 111 
 112         while (++count <= HP206C_MAX_DEV_RDY_WAIT_COUNT) {
 113                 ret = hp206c_read_reg(client, HP206C_REG_INT_SRC);
 114                 if (ret < 0) {
 115                         dev_err(&indio_dev->dev, "Failed READ_REG INT_SRC: %d\n", ret);
 116                         return ret;
 117                 }
 118                 if (ret & HP206C_FLAG_DEV_RDY)
 119                         return 0;
 120                 usleep_range(HP206C_DEV_RDY_WAIT_US, HP206C_DEV_RDY_WAIT_US * 3 / 2);
 121         }
 122         return -ETIMEDOUT;
 123 }
 124 
 125 static int hp206c_set_compensation(struct i2c_client *client, bool enabled)
 126 {
 127         int val;
 128 
 129         val = hp206c_read_reg(client, HP206C_REG_PARA);
 130         if (val < 0)
 131                 return val;
 132         if (enabled)
 133                 val |= HP206C_FLAG_CMPS_EN;
 134         else
 135                 val &= ~HP206C_FLAG_CMPS_EN;
 136 
 137         return hp206c_write_reg(client, HP206C_REG_PARA, val);
 138 }
 139 
 140 /* Do a soft reset */
 141 static int hp206c_soft_reset(struct iio_dev *indio_dev)
 142 {
 143         int ret;
 144         struct hp206c_data *data = iio_priv(indio_dev);
 145         struct i2c_client *client = data->client;
 146 
 147         ret = i2c_smbus_write_byte(client, HP206C_CMD_SOFT_RST);
 148         if (ret) {
 149                 dev_err(&client->dev, "Failed to reset device: %d\n", ret);
 150                 return ret;
 151         }
 152 
 153         usleep_range(400, 600);
 154 
 155         ret = hp206c_wait_dev_rdy(indio_dev);
 156         if (ret) {
 157                 dev_err(&client->dev, "Device not ready after soft reset: %d\n", ret);
 158                 return ret;
 159         }
 160 
 161         ret = hp206c_set_compensation(client, true);
 162         if (ret)
 163                 dev_err(&client->dev, "Failed to enable compensation: %d\n", ret);
 164         return ret;
 165 }
 166 
 167 static int hp206c_conv_and_read(struct iio_dev *indio_dev,
 168                                 u8 conv_cmd, u8 read_cmd,
 169                                 unsigned int sleep_us)
 170 {
 171         int ret;
 172         struct hp206c_data *data = iio_priv(indio_dev);
 173         struct i2c_client *client = data->client;
 174 
 175         ret = hp206c_wait_dev_rdy(indio_dev);
 176         if (ret < 0) {
 177                 dev_err(&indio_dev->dev, "Device not ready: %d\n", ret);
 178                 return ret;
 179         }
 180 
 181         ret = i2c_smbus_write_byte(client, conv_cmd);
 182         if (ret < 0) {
 183                 dev_err(&indio_dev->dev, "Failed convert: %d\n", ret);
 184                 return ret;
 185         }
 186 
 187         usleep_range(sleep_us, sleep_us * 3 / 2);
 188 
 189         ret = hp206c_wait_dev_rdy(indio_dev);
 190         if (ret < 0) {
 191                 dev_err(&indio_dev->dev, "Device not ready: %d\n", ret);
 192                 return ret;
 193         }
 194 
 195         ret = hp206c_read_20bit(client, read_cmd);
 196         if (ret < 0)
 197                 dev_err(&indio_dev->dev, "Failed read: %d\n", ret);
 198 
 199         return ret;
 200 }
 201 
 202 static int hp206c_read_raw(struct iio_dev *indio_dev,
 203                            struct iio_chan_spec const *chan, int *val,
 204                            int *val2, long mask)
 205 {
 206         int ret;
 207         struct hp206c_data *data = iio_priv(indio_dev);
 208         const struct hp206c_osr_setting *osr_setting;
 209         u8 conv_cmd;
 210 
 211         mutex_lock(&data->mutex);
 212 
 213         switch (mask) {
 214         case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
 215                 switch (chan->type) {
 216                 case IIO_TEMP:
 217                         *val = hp206c_osr_rates[data->temp_osr_index];
 218                         ret = IIO_VAL_INT;
 219                         break;
 220 
 221                 case IIO_PRESSURE:
 222                         *val = hp206c_osr_rates[data->pres_osr_index];
 223                         ret = IIO_VAL_INT;
 224                         break;
 225                 default:
 226                         ret = -EINVAL;
 227                 }
 228                 break;
 229 
 230         case IIO_CHAN_INFO_RAW:
 231                 switch (chan->type) {
 232                 case IIO_TEMP:
 233                         osr_setting = &hp206c_osr_settings[data->temp_osr_index];
 234                         conv_cmd = HP206C_CMD_ADC_CVT |
 235                                         osr_setting->osr_mask |
 236                                         HP206C_CMD_ADC_CVT_CHNL_T;
 237                         ret = hp206c_conv_and_read(indio_dev,
 238                                         conv_cmd,
 239                                         HP206C_CMD_READ_T,
 240                                         osr_setting->temp_conv_time_us);
 241                         if (ret >= 0) {
 242                                 /* 20 significant bits are provided.
 243                                  * Extend sign over the rest.
 244                                  */
 245                                 *val = sign_extend32(ret, 19);
 246                                 ret = IIO_VAL_INT;
 247                         }
 248                         break;
 249 
 250                 case IIO_PRESSURE:
 251                         osr_setting = &hp206c_osr_settings[data->pres_osr_index];
 252                         conv_cmd = HP206C_CMD_ADC_CVT |
 253                                         osr_setting->osr_mask |
 254                                         HP206C_CMD_ADC_CVT_CHNL_PT;
 255                         ret = hp206c_conv_and_read(indio_dev,
 256                                         conv_cmd,
 257                                         HP206C_CMD_READ_P,
 258                                         osr_setting->pres_conv_time_us);
 259                         if (ret >= 0) {
 260                                 *val = ret;
 261                                 ret = IIO_VAL_INT;
 262                         }
 263                         break;
 264                 default:
 265                         ret = -EINVAL;
 266                 }
 267                 break;
 268 
 269         case IIO_CHAN_INFO_SCALE:
 270                 switch (chan->type) {
 271                 case IIO_TEMP:
 272                         *val = 0;
 273                         *val2 = 10000;
 274                         ret = IIO_VAL_INT_PLUS_MICRO;
 275                         break;
 276 
 277                 case IIO_PRESSURE:
 278                         *val = 0;
 279                         *val2 = 1000;
 280                         ret = IIO_VAL_INT_PLUS_MICRO;
 281                         break;
 282                 default:
 283                         ret = -EINVAL;
 284                 }
 285                 break;
 286 
 287         default:
 288                 ret = -EINVAL;
 289         }
 290 
 291         mutex_unlock(&data->mutex);
 292         return ret;
 293 }
 294 
 295 static int hp206c_write_raw(struct iio_dev *indio_dev,
 296                             struct iio_chan_spec const *chan,
 297                             int val, int val2, long mask)
 298 {
 299         int ret = 0;
 300         struct hp206c_data *data = iio_priv(indio_dev);
 301 
 302         if (mask != IIO_CHAN_INFO_OVERSAMPLING_RATIO)
 303                 return -EINVAL;
 304         mutex_lock(&data->mutex);
 305         switch (chan->type) {
 306         case IIO_TEMP:
 307                 data->temp_osr_index = find_closest_descending(val,
 308                         hp206c_osr_rates, ARRAY_SIZE(hp206c_osr_rates));
 309                 break;
 310         case IIO_PRESSURE:
 311                 data->pres_osr_index = find_closest_descending(val,
 312                         hp206c_osr_rates, ARRAY_SIZE(hp206c_osr_rates));
 313                 break;
 314         default:
 315                 ret = -EINVAL;
 316         }
 317         mutex_unlock(&data->mutex);
 318         return ret;
 319 }
 320 
 321 static const struct iio_chan_spec hp206c_channels[] = {
 322         {
 323                 .type = IIO_TEMP,
 324                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 325                                       BIT(IIO_CHAN_INFO_SCALE) |
 326                                       BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
 327         },
 328         {
 329                 .type = IIO_PRESSURE,
 330                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 331                                       BIT(IIO_CHAN_INFO_SCALE) |
 332                                       BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
 333         }
 334 };
 335 
 336 static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(hp206c_osr_rates_str);
 337 
 338 static struct attribute *hp206c_attributes[] = {
 339         &iio_const_attr_sampling_frequency_available.dev_attr.attr,
 340         NULL,
 341 };
 342 
 343 static const struct attribute_group hp206c_attribute_group = {
 344         .attrs = hp206c_attributes,
 345 };
 346 
 347 static const struct iio_info hp206c_info = {
 348         .attrs = &hp206c_attribute_group,
 349         .read_raw = hp206c_read_raw,
 350         .write_raw = hp206c_write_raw,
 351 };
 352 
 353 static int hp206c_probe(struct i2c_client *client,
 354                         const struct i2c_device_id *id)
 355 {
 356         struct iio_dev *indio_dev;
 357         struct hp206c_data *data;
 358         int ret;
 359 
 360         if (!i2c_check_functionality(client->adapter,
 361                                      I2C_FUNC_SMBUS_BYTE |
 362                                      I2C_FUNC_SMBUS_BYTE_DATA |
 363                                      I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
 364                 dev_err(&client->dev, "Adapter does not support "
 365                                 "all required i2c functionality\n");
 366                 return -ENODEV;
 367         }
 368 
 369         indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
 370         if (!indio_dev)
 371                 return -ENOMEM;
 372 
 373         data = iio_priv(indio_dev);
 374         data->client = client;
 375         mutex_init(&data->mutex);
 376 
 377         indio_dev->info = &hp206c_info;
 378         indio_dev->name = id->name;
 379         indio_dev->dev.parent = &client->dev;
 380         indio_dev->modes = INDIO_DIRECT_MODE;
 381         indio_dev->channels = hp206c_channels;
 382         indio_dev->num_channels = ARRAY_SIZE(hp206c_channels);
 383 
 384         i2c_set_clientdata(client, indio_dev);
 385 
 386         /* Do a soft reset on probe */
 387         ret = hp206c_soft_reset(indio_dev);
 388         if (ret) {
 389                 dev_err(&client->dev, "Failed to reset on startup: %d\n", ret);
 390                 return -ENODEV;
 391         }
 392 
 393         return devm_iio_device_register(&client->dev, indio_dev);
 394 }
 395 
 396 static const struct i2c_device_id hp206c_id[] = {
 397         {"hp206c"},
 398         {}
 399 };
 400 MODULE_DEVICE_TABLE(i2c, hp206c_id);
 401 
 402 #ifdef CONFIG_ACPI
 403 static const struct acpi_device_id hp206c_acpi_match[] = {
 404         {"HOP206C", 0},
 405         { },
 406 };
 407 MODULE_DEVICE_TABLE(acpi, hp206c_acpi_match);
 408 #endif
 409 
 410 static struct i2c_driver hp206c_driver = {
 411         .probe = hp206c_probe,
 412         .id_table = hp206c_id,
 413         .driver = {
 414                 .name = "hp206c",
 415                 .acpi_match_table = ACPI_PTR(hp206c_acpi_match),
 416         },
 417 };
 418 
 419 module_i2c_driver(hp206c_driver);
 420 
 421 MODULE_DESCRIPTION("HOPERF HP206C precision barometer and altimeter sensor");
 422 MODULE_AUTHOR("Leonard Crestez <leonard.crestez@intel.com>");
 423 MODULE_LICENSE("GPL v2");

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