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