linux/drivers/iio/temperature/tmp006.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * tmp006.c - Support for TI TMP006 IR thermopile sensor
   4 *
   5 * Copyright (c) 2013 Peter Meerwald <pmeerw@pmeerw.net>
   6 *
   7 * Driver for the Texas Instruments I2C 16-bit IR thermopile sensor
   8 *
   9 * (7-bit I2C slave address 0x40, changeable via ADR pins)
  10 *
  11 * TODO: data ready irq
  12 */
  13
  14#include <linux/err.h>
  15#include <linux/i2c.h>
  16#include <linux/delay.h>
  17#include <linux/module.h>
  18#include <linux/pm.h>
  19#include <linux/bitops.h>
  20
  21#include <linux/iio/iio.h>
  22#include <linux/iio/sysfs.h>
  23
  24#define TMP006_VOBJECT 0x00
  25#define TMP006_TAMBIENT 0x01
  26#define TMP006_CONFIG 0x02
  27#define TMP006_MANUFACTURER_ID 0xfe
  28#define TMP006_DEVICE_ID 0xff
  29
  30#define TMP006_TAMBIENT_SHIFT 2
  31
  32#define TMP006_CONFIG_RESET BIT(15)
  33#define TMP006_CONFIG_DRDY_EN BIT(8)
  34#define TMP006_CONFIG_DRDY BIT(7)
  35
  36#define TMP006_CONFIG_MOD_MASK GENMASK(14, 12)
  37
  38#define TMP006_CONFIG_CR_MASK GENMASK(11, 9)
  39#define TMP006_CONFIG_CR_SHIFT 9
  40
  41#define TMP006_MANUFACTURER_MAGIC 0x5449
  42#define TMP006_DEVICE_MAGIC 0x0067
  43
  44struct tmp006_data {
  45        struct i2c_client *client;
  46        u16 config;
  47};
  48
  49static int tmp006_read_measurement(struct tmp006_data *data, u8 reg)
  50{
  51        s32 ret;
  52        int tries = 50;
  53
  54        while (tries-- > 0) {
  55                ret = i2c_smbus_read_word_swapped(data->client,
  56                        TMP006_CONFIG);
  57                if (ret < 0)
  58                        return ret;
  59                if (ret & TMP006_CONFIG_DRDY)
  60                        break;
  61                msleep(100);
  62        }
  63
  64        if (tries < 0)
  65                return -EIO;
  66
  67        return i2c_smbus_read_word_swapped(data->client, reg);
  68}
  69
  70static const int tmp006_freqs[5][2] = { {4, 0}, {2, 0}, {1, 0},
  71                                        {0, 500000}, {0, 250000} };
  72
  73static int tmp006_read_raw(struct iio_dev *indio_dev,
  74                            struct iio_chan_spec const *channel, int *val,
  75                            int *val2, long mask)
  76{
  77        struct tmp006_data *data = iio_priv(indio_dev);
  78        s32 ret;
  79        int cr;
  80
  81        switch (mask) {
  82        case IIO_CHAN_INFO_RAW:
  83                if (channel->type == IIO_VOLTAGE) {
  84                        /* LSB is 156.25 nV */
  85                        ret = tmp006_read_measurement(data, TMP006_VOBJECT);
  86                        if (ret < 0)
  87                                return ret;
  88                        *val = sign_extend32(ret, 15);
  89                } else if (channel->type == IIO_TEMP) {
  90                        /* LSB is 0.03125 degrees Celsius */
  91                        ret = tmp006_read_measurement(data, TMP006_TAMBIENT);
  92                        if (ret < 0)
  93                                return ret;
  94                        *val = sign_extend32(ret, 15) >> TMP006_TAMBIENT_SHIFT;
  95                } else {
  96                        break;
  97                }
  98                return IIO_VAL_INT;
  99        case IIO_CHAN_INFO_SCALE:
 100                if (channel->type == IIO_VOLTAGE) {
 101                        *val = 0;
 102                        *val2 = 156250;
 103                } else if (channel->type == IIO_TEMP) {
 104                        *val = 31;
 105                        *val2 = 250000;
 106                } else {
 107                        break;
 108                }
 109                return IIO_VAL_INT_PLUS_MICRO;
 110        case IIO_CHAN_INFO_SAMP_FREQ:
 111                cr = (data->config & TMP006_CONFIG_CR_MASK)
 112                        >> TMP006_CONFIG_CR_SHIFT;
 113                *val = tmp006_freqs[cr][0];
 114                *val2 = tmp006_freqs[cr][1];
 115                return IIO_VAL_INT_PLUS_MICRO;
 116        default:
 117                break;
 118        }
 119
 120        return -EINVAL;
 121}
 122
 123static int tmp006_write_raw(struct iio_dev *indio_dev,
 124                            struct iio_chan_spec const *chan,
 125                            int val,
 126                            int val2,
 127                            long mask)
 128{
 129        struct tmp006_data *data = iio_priv(indio_dev);
 130        int i;
 131
 132        if (mask != IIO_CHAN_INFO_SAMP_FREQ)
 133                return -EINVAL;
 134
 135        for (i = 0; i < ARRAY_SIZE(tmp006_freqs); i++)
 136                if ((val == tmp006_freqs[i][0]) &&
 137                    (val2 == tmp006_freqs[i][1])) {
 138                        data->config &= ~TMP006_CONFIG_CR_MASK;
 139                        data->config |= i << TMP006_CONFIG_CR_SHIFT;
 140
 141                        return i2c_smbus_write_word_swapped(data->client,
 142                                                            TMP006_CONFIG,
 143                                                            data->config);
 144
 145                }
 146        return -EINVAL;
 147}
 148
 149static IIO_CONST_ATTR(sampling_frequency_available, "4 2 1 0.5 0.25");
 150
 151static struct attribute *tmp006_attributes[] = {
 152        &iio_const_attr_sampling_frequency_available.dev_attr.attr,
 153        NULL
 154};
 155
 156static const struct attribute_group tmp006_attribute_group = {
 157        .attrs = tmp006_attributes,
 158};
 159
 160static const struct iio_chan_spec tmp006_channels[] = {
 161        {
 162                .type = IIO_VOLTAGE,
 163                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 164                        BIT(IIO_CHAN_INFO_SCALE),
 165                .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
 166        },
 167        {
 168                .type = IIO_TEMP,
 169                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 170                        BIT(IIO_CHAN_INFO_SCALE),
 171                .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
 172        }
 173};
 174
 175static const struct iio_info tmp006_info = {
 176        .read_raw = tmp006_read_raw,
 177        .write_raw = tmp006_write_raw,
 178        .attrs = &tmp006_attribute_group,
 179};
 180
 181static bool tmp006_check_identification(struct i2c_client *client)
 182{
 183        int mid, did;
 184
 185        mid = i2c_smbus_read_word_swapped(client, TMP006_MANUFACTURER_ID);
 186        if (mid < 0)
 187                return false;
 188
 189        did = i2c_smbus_read_word_swapped(client, TMP006_DEVICE_ID);
 190        if (did < 0)
 191                return false;
 192
 193        return mid == TMP006_MANUFACTURER_MAGIC && did == TMP006_DEVICE_MAGIC;
 194}
 195
 196static int tmp006_power(struct device *dev, bool up)
 197{
 198        struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
 199        struct tmp006_data *data = iio_priv(indio_dev);
 200
 201        if (up)
 202                data->config |= TMP006_CONFIG_MOD_MASK;
 203        else
 204                data->config &= ~TMP006_CONFIG_MOD_MASK;
 205
 206        return i2c_smbus_write_word_swapped(data->client, TMP006_CONFIG,
 207                data->config);
 208}
 209
 210static void tmp006_powerdown_cleanup(void *dev)
 211{
 212        tmp006_power(dev, false);
 213}
 214
 215static int tmp006_probe(struct i2c_client *client,
 216                         const struct i2c_device_id *id)
 217{
 218        struct iio_dev *indio_dev;
 219        struct tmp006_data *data;
 220        int ret;
 221
 222        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
 223                return -EOPNOTSUPP;
 224
 225        if (!tmp006_check_identification(client)) {
 226                dev_err(&client->dev, "no TMP006 sensor\n");
 227                return -ENODEV;
 228        }
 229
 230        indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
 231        if (!indio_dev)
 232                return -ENOMEM;
 233
 234        data = iio_priv(indio_dev);
 235        i2c_set_clientdata(client, indio_dev);
 236        data->client = client;
 237
 238        indio_dev->name = dev_name(&client->dev);
 239        indio_dev->modes = INDIO_DIRECT_MODE;
 240        indio_dev->info = &tmp006_info;
 241
 242        indio_dev->channels = tmp006_channels;
 243        indio_dev->num_channels = ARRAY_SIZE(tmp006_channels);
 244
 245        ret = i2c_smbus_read_word_swapped(data->client, TMP006_CONFIG);
 246        if (ret < 0)
 247                return ret;
 248        data->config = ret;
 249
 250        if ((ret & TMP006_CONFIG_MOD_MASK) != TMP006_CONFIG_MOD_MASK) {
 251                ret = tmp006_power(&client->dev, true);
 252                if (ret < 0)
 253                        return ret;
 254        }
 255
 256        ret = devm_add_action_or_reset(&client->dev, tmp006_powerdown_cleanup,
 257                                       &client->dev);
 258        if (ret < 0)
 259                return ret;
 260
 261        return devm_iio_device_register(&client->dev, indio_dev);
 262}
 263
 264#ifdef CONFIG_PM_SLEEP
 265static int tmp006_suspend(struct device *dev)
 266{
 267        return tmp006_power(dev, false);
 268}
 269
 270static int tmp006_resume(struct device *dev)
 271{
 272        return tmp006_power(dev, true);
 273}
 274#endif
 275
 276static SIMPLE_DEV_PM_OPS(tmp006_pm_ops, tmp006_suspend, tmp006_resume);
 277
 278static const struct i2c_device_id tmp006_id[] = {
 279        { "tmp006", 0 },
 280        { }
 281};
 282MODULE_DEVICE_TABLE(i2c, tmp006_id);
 283
 284static struct i2c_driver tmp006_driver = {
 285        .driver = {
 286                .name   = "tmp006",
 287                .pm     = &tmp006_pm_ops,
 288        },
 289        .probe = tmp006_probe,
 290        .id_table = tmp006_id,
 291};
 292module_i2c_driver(tmp006_driver);
 293
 294MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
 295MODULE_DESCRIPTION("TI TMP006 IR thermopile sensor driver");
 296MODULE_LICENSE("GPL");
 297