linux/drivers/iio/temperature/tmp007.c
<<
>>
Prefs
   1/*
   2 * tmp007.c - Support for TI TMP007 IR thermopile sensor with integrated math engine
   3 *
   4 * Copyright (c) 2017 Manivannan Sadhasivam <manivannanece23@gmail.com>
   5 *
   6 * This file is subject to the terms and conditions of version 2 of
   7 * the GNU General Public License.  See the file COPYING in the main
   8 * directory of this archive for more details.
   9 *
  10 * Driver for the Texas Instruments I2C 16-bit IR thermopile sensor
  11 *
  12 * (7-bit I2C slave address (0x40 - 0x47), changeable via ADR pins)
  13 *
  14 * Note:
  15 * 1. This driver assumes that the sensor has been calibrated beforehand
  16 * 2. Limit threshold events are enabled at the start
  17 * 3. Operating mode: INT
  18 *
  19 */
  20
  21#include <linux/err.h>
  22#include <linux/i2c.h>
  23#include <linux/delay.h>
  24#include <linux/module.h>
  25#include <linux/pm.h>
  26#include <linux/bitops.h>
  27#include <linux/of.h>
  28#include <linux/irq.h>
  29#include <linux/interrupt.h>
  30
  31#include <linux/iio/iio.h>
  32#include <linux/iio/sysfs.h>
  33#include <linux/iio/events.h>
  34
  35#define TMP007_TDIE 0x01
  36#define TMP007_CONFIG 0x02
  37#define TMP007_TOBJECT 0x03
  38#define TMP007_STATUS 0x04
  39#define TMP007_STATUS_MASK 0x05
  40#define TMP007_TOBJ_HIGH_LIMIT 0x06
  41#define TMP007_TOBJ_LOW_LIMIT 0x07
  42#define TMP007_TDIE_HIGH_LIMIT 0x08
  43#define TMP007_TDIE_LOW_LIMIT 0x09
  44#define TMP007_MANUFACTURER_ID 0x1e
  45#define TMP007_DEVICE_ID 0x1f
  46
  47#define TMP007_CONFIG_CONV_EN BIT(12)
  48#define TMP007_CONFIG_TC_EN BIT(6)
  49#define TMP007_CONFIG_CR_MASK GENMASK(11, 9)
  50#define TMP007_CONFIG_ALERT_EN BIT(8)
  51#define TMP007_CONFIG_CR_SHIFT 9
  52
  53/* Status register flags */
  54#define TMP007_STATUS_ALERT BIT(15)
  55#define TMP007_STATUS_CONV_READY BIT(14)
  56#define TMP007_STATUS_OHF BIT(13)
  57#define TMP007_STATUS_OLF BIT(12)
  58#define TMP007_STATUS_LHF BIT(11)
  59#define TMP007_STATUS_LLF BIT(10)
  60#define TMP007_STATUS_DATA_VALID BIT(9)
  61
  62#define TMP007_MANUFACTURER_MAGIC 0x5449
  63#define TMP007_DEVICE_MAGIC 0x0078
  64
  65#define TMP007_TEMP_SHIFT 2
  66
  67struct tmp007_data {
  68        struct i2c_client *client;
  69        struct mutex lock;
  70        u16 config;
  71        u16 status_mask;
  72};
  73
  74static const int tmp007_avgs[5][2] = { {4, 0}, {2, 0}, {1, 0},
  75                                        {0, 500000}, {0, 250000} };
  76
  77static int tmp007_read_temperature(struct tmp007_data *data, u8 reg)
  78{
  79        s32 ret;
  80        int tries = 50;
  81
  82        while (tries-- > 0) {
  83                ret = i2c_smbus_read_word_swapped(data->client,
  84                        TMP007_STATUS);
  85                if (ret < 0)
  86                        return ret;
  87                if ((ret & TMP007_STATUS_CONV_READY) &&
  88                        !(ret & TMP007_STATUS_DATA_VALID))
  89                                break;
  90                msleep(100);
  91        }
  92
  93        if (tries < 0)
  94                return -EIO;
  95
  96        return i2c_smbus_read_word_swapped(data->client, reg);
  97}
  98
  99static int tmp007_powerdown(struct tmp007_data *data)
 100{
 101        return i2c_smbus_write_word_swapped(data->client, TMP007_CONFIG,
 102                        data->config & ~TMP007_CONFIG_CONV_EN);
 103}
 104
 105static int tmp007_read_raw(struct iio_dev *indio_dev,
 106                struct iio_chan_spec const *channel, int *val,
 107                int *val2, long mask)
 108{
 109        struct tmp007_data *data = iio_priv(indio_dev);
 110        s32 ret;
 111        int conv_rate;
 112
 113        switch (mask) {
 114        case IIO_CHAN_INFO_RAW:
 115                switch (channel->channel2) {
 116                case IIO_MOD_TEMP_AMBIENT: /* LSB: 0.03125 degree Celsius */
 117                        ret = i2c_smbus_read_word_swapped(data->client, TMP007_TDIE);
 118                        if (ret < 0)
 119                                return ret;
 120                        break;
 121                case IIO_MOD_TEMP_OBJECT:
 122                        ret = tmp007_read_temperature(data, TMP007_TOBJECT);
 123                        if (ret < 0)
 124                                return ret;
 125                        break;
 126                default:
 127                        return -EINVAL;
 128                }
 129
 130                *val = sign_extend32(ret, 15) >> TMP007_TEMP_SHIFT;
 131
 132                return IIO_VAL_INT;
 133        case IIO_CHAN_INFO_SCALE:
 134                *val = 31;
 135                *val2 = 250000;
 136
 137                return IIO_VAL_INT_PLUS_MICRO;
 138        case IIO_CHAN_INFO_SAMP_FREQ:
 139                conv_rate = (data->config & TMP007_CONFIG_CR_MASK)
 140                                >> TMP007_CONFIG_CR_SHIFT;
 141                *val = tmp007_avgs[conv_rate][0];
 142                *val2 = tmp007_avgs[conv_rate][1];
 143
 144                return IIO_VAL_INT_PLUS_MICRO;
 145        default:
 146                return -EINVAL;
 147        }
 148}
 149
 150static int tmp007_write_raw(struct iio_dev *indio_dev,
 151                struct iio_chan_spec const *channel, int val,
 152                int val2, long mask)
 153{
 154        struct tmp007_data *data = iio_priv(indio_dev);
 155        int i;
 156        u16 tmp;
 157
 158        if (mask == IIO_CHAN_INFO_SAMP_FREQ) {
 159                for (i = 0; i < ARRAY_SIZE(tmp007_avgs); i++) {
 160                        if ((val == tmp007_avgs[i][0]) &&
 161                        (val2 == tmp007_avgs[i][1])) {
 162                                tmp = data->config & ~TMP007_CONFIG_CR_MASK;
 163                                tmp |= (i << TMP007_CONFIG_CR_SHIFT);
 164
 165                                return i2c_smbus_write_word_swapped(data->client,
 166                                                                TMP007_CONFIG,
 167                                                                data->config = tmp);
 168                        }
 169                }
 170        }
 171
 172        return -EINVAL;
 173}
 174
 175static irqreturn_t tmp007_interrupt_handler(int irq, void *private)
 176{
 177        struct iio_dev *indio_dev = private;
 178        struct tmp007_data *data = iio_priv(indio_dev);
 179        int ret;
 180
 181        ret = i2c_smbus_read_word_swapped(data->client, TMP007_STATUS);
 182        if ((ret < 0) || !(ret & (TMP007_STATUS_OHF | TMP007_STATUS_OLF |
 183                                TMP007_STATUS_LHF | TMP007_STATUS_LLF)))
 184                return IRQ_NONE;
 185
 186        if (ret & TMP007_STATUS_OHF)
 187                iio_push_event(indio_dev,
 188                                IIO_MOD_EVENT_CODE(IIO_TEMP, 0,
 189                                        IIO_MOD_TEMP_OBJECT,
 190                                        IIO_EV_TYPE_THRESH,
 191                                        IIO_EV_DIR_RISING),
 192                                iio_get_time_ns(indio_dev));
 193
 194        if (ret & TMP007_STATUS_OLF)
 195                iio_push_event(indio_dev,
 196                                IIO_MOD_EVENT_CODE(IIO_TEMP, 0,
 197                                        IIO_MOD_TEMP_OBJECT,
 198                                        IIO_EV_TYPE_THRESH,
 199                                        IIO_EV_DIR_FALLING),
 200                                iio_get_time_ns(indio_dev));
 201
 202        if (ret & TMP007_STATUS_LHF)
 203                iio_push_event(indio_dev,
 204                                IIO_MOD_EVENT_CODE(IIO_TEMP, 0,
 205                                        IIO_MOD_TEMP_AMBIENT,
 206                                        IIO_EV_TYPE_THRESH,
 207                                        IIO_EV_DIR_RISING),
 208                                iio_get_time_ns(indio_dev));
 209
 210        if (ret & TMP007_STATUS_LLF)
 211                iio_push_event(indio_dev,
 212                                IIO_MOD_EVENT_CODE(IIO_TEMP, 0,
 213                                        IIO_MOD_TEMP_AMBIENT,
 214                                        IIO_EV_TYPE_THRESH,
 215                                        IIO_EV_DIR_FALLING),
 216                                iio_get_time_ns(indio_dev));
 217
 218        return IRQ_HANDLED;
 219}
 220
 221static int tmp007_write_event_config(struct iio_dev *indio_dev,
 222                const struct iio_chan_spec *chan, enum iio_event_type type,
 223                enum iio_event_direction dir, int state)
 224{
 225        struct tmp007_data *data = iio_priv(indio_dev);
 226        unsigned int status_mask;
 227        int ret;
 228
 229        switch (chan->channel2) {
 230        case IIO_MOD_TEMP_AMBIENT:
 231        if (dir == IIO_EV_DIR_RISING)
 232                        status_mask = TMP007_STATUS_LHF;
 233                else
 234                        status_mask = TMP007_STATUS_LLF;
 235                break;
 236        case IIO_MOD_TEMP_OBJECT:
 237                if (dir == IIO_EV_DIR_RISING)
 238                        status_mask = TMP007_STATUS_OHF;
 239                else
 240                        status_mask = TMP007_STATUS_OLF;
 241                break;
 242        default:
 243                return -EINVAL;
 244        }
 245
 246        mutex_lock(&data->lock);
 247        ret = i2c_smbus_read_word_swapped(data->client, TMP007_STATUS_MASK);
 248        mutex_unlock(&data->lock);
 249        if (ret < 0)
 250                return ret;
 251
 252        if (state)
 253                ret |= status_mask;
 254        else
 255                ret &= ~status_mask;
 256
 257        return i2c_smbus_write_word_swapped(data->client, TMP007_STATUS_MASK,
 258                                        data->status_mask = ret);
 259}
 260
 261static int tmp007_read_event_config(struct iio_dev *indio_dev,
 262                const struct iio_chan_spec *chan, enum iio_event_type type,
 263                enum iio_event_direction dir)
 264{
 265        struct tmp007_data *data = iio_priv(indio_dev);
 266        unsigned int mask;
 267
 268        switch (chan->channel2) {
 269        case IIO_MOD_TEMP_AMBIENT:
 270                if (dir == IIO_EV_DIR_RISING)
 271                        mask = TMP007_STATUS_LHF;
 272                else
 273                        mask = TMP007_STATUS_LLF;
 274                break;
 275        case IIO_MOD_TEMP_OBJECT:
 276                if (dir == IIO_EV_DIR_RISING)
 277                        mask = TMP007_STATUS_OHF;
 278                else
 279                        mask = TMP007_STATUS_OLF;
 280                break;
 281        default:
 282                return -EINVAL;
 283        }
 284
 285        return !!(data->status_mask & mask);
 286}
 287
 288static int tmp007_read_thresh(struct iio_dev *indio_dev,
 289                const struct iio_chan_spec *chan, enum iio_event_type type,
 290                enum iio_event_direction dir, enum iio_event_info info,
 291                int *val, int *val2)
 292{
 293        struct tmp007_data *data = iio_priv(indio_dev);
 294        int ret;
 295        u8 reg;
 296
 297        switch (chan->channel2) {
 298        case IIO_MOD_TEMP_AMBIENT: /* LSB: 0.5 degree Celsius */
 299                if (dir == IIO_EV_DIR_RISING)
 300                        reg = TMP007_TDIE_HIGH_LIMIT;
 301                else
 302                        reg = TMP007_TDIE_LOW_LIMIT;
 303                break;
 304        case IIO_MOD_TEMP_OBJECT:
 305                if (dir == IIO_EV_DIR_RISING)
 306                        reg = TMP007_TOBJ_HIGH_LIMIT;
 307        else
 308                        reg = TMP007_TOBJ_LOW_LIMIT;
 309                break;
 310        default:
 311                return -EINVAL;
 312        }
 313
 314        ret = i2c_smbus_read_word_swapped(data->client, reg);
 315        if (ret < 0)
 316                return ret;
 317
 318        /* Shift length 7 bits = 6(15:6) + 1(0.5 LSB) */
 319        *val = sign_extend32(ret, 15) >> 7;
 320
 321        return IIO_VAL_INT;
 322}
 323
 324static int tmp007_write_thresh(struct iio_dev *indio_dev,
 325                const struct iio_chan_spec *chan, enum iio_event_type type,
 326                enum iio_event_direction dir, enum iio_event_info info,
 327                int val, int val2)
 328{
 329        struct tmp007_data *data = iio_priv(indio_dev);
 330        u8 reg;
 331
 332        switch (chan->channel2) {
 333        case IIO_MOD_TEMP_AMBIENT:
 334                if (dir == IIO_EV_DIR_RISING)
 335                        reg = TMP007_TDIE_HIGH_LIMIT;
 336                else
 337                        reg = TMP007_TDIE_LOW_LIMIT;
 338                break;
 339        case IIO_MOD_TEMP_OBJECT:
 340                if (dir == IIO_EV_DIR_RISING)
 341                        reg = TMP007_TOBJ_HIGH_LIMIT;
 342                else
 343                        reg = TMP007_TOBJ_LOW_LIMIT;
 344                break;
 345        default:
 346                return -EINVAL;
 347        }
 348
 349        /* Full scale threshold value is +/- 256 degree Celsius */
 350        if (val < -256 || val > 255)
 351                return -EINVAL;
 352
 353        /* Shift length 7 bits = 6(15:6) + 1(0.5 LSB) */
 354        return i2c_smbus_write_word_swapped(data->client, reg, (val << 7));
 355}
 356
 357static IIO_CONST_ATTR(sampling_frequency_available, "4 2 1 0.5 0.25");
 358
 359static struct attribute *tmp007_attributes[] = {
 360        &iio_const_attr_sampling_frequency_available.dev_attr.attr,
 361        NULL
 362};
 363
 364static const struct attribute_group tmp007_attribute_group = {
 365        .attrs = tmp007_attributes,
 366};
 367
 368static const struct iio_event_spec tmp007_obj_event[] = {
 369        {
 370                .type = IIO_EV_TYPE_THRESH,
 371                .dir = IIO_EV_DIR_RISING,
 372                .mask_separate = BIT(IIO_EV_INFO_VALUE) |
 373                        BIT(IIO_EV_INFO_ENABLE),
 374        },
 375        {
 376                .type = IIO_EV_TYPE_THRESH,
 377                .dir = IIO_EV_DIR_FALLING,
 378                .mask_separate = BIT(IIO_EV_INFO_VALUE) |
 379                        BIT(IIO_EV_INFO_ENABLE),
 380        },
 381};
 382
 383static const struct iio_event_spec tmp007_die_event[] = {
 384        {
 385                .type = IIO_EV_TYPE_THRESH,
 386                .dir = IIO_EV_DIR_RISING,
 387                .mask_separate = BIT(IIO_EV_INFO_VALUE) |
 388                        BIT(IIO_EV_INFO_ENABLE),
 389        },
 390        {
 391                .type = IIO_EV_TYPE_THRESH,
 392                .dir = IIO_EV_DIR_FALLING,
 393                .mask_separate = BIT(IIO_EV_INFO_VALUE) |
 394                        BIT(IIO_EV_INFO_ENABLE),
 395        },
 396};
 397
 398static const struct iio_chan_spec tmp007_channels[] = {
 399        {
 400                .type = IIO_TEMP,
 401                .modified = 1,
 402                .channel2 = IIO_MOD_TEMP_AMBIENT,
 403                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 404                                BIT(IIO_CHAN_INFO_SCALE),
 405                .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
 406                .event_spec = tmp007_die_event,
 407                .num_event_specs = ARRAY_SIZE(tmp007_die_event),
 408        },
 409        {
 410                .type = IIO_TEMP,
 411                .modified = 1,
 412                .channel2 = IIO_MOD_TEMP_OBJECT,
 413                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 414                                BIT(IIO_CHAN_INFO_SCALE),
 415                .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
 416                .event_spec = tmp007_obj_event,
 417                .num_event_specs = ARRAY_SIZE(tmp007_obj_event),
 418        }
 419};
 420
 421static const struct iio_info tmp007_info = {
 422        .read_raw = tmp007_read_raw,
 423        .write_raw = tmp007_write_raw,
 424        .read_event_config = tmp007_read_event_config,
 425        .write_event_config = tmp007_write_event_config,
 426        .read_event_value = tmp007_read_thresh,
 427        .write_event_value = tmp007_write_thresh,
 428        .attrs = &tmp007_attribute_group,
 429};
 430
 431static bool tmp007_identify(struct i2c_client *client)
 432{
 433        int manf_id, dev_id;
 434
 435        manf_id = i2c_smbus_read_word_swapped(client, TMP007_MANUFACTURER_ID);
 436        if (manf_id < 0)
 437                return false;
 438
 439        dev_id = i2c_smbus_read_word_swapped(client, TMP007_DEVICE_ID);
 440        if (dev_id < 0)
 441                return false;
 442
 443        return (manf_id == TMP007_MANUFACTURER_MAGIC && dev_id == TMP007_DEVICE_MAGIC);
 444}
 445
 446static int tmp007_probe(struct i2c_client *client,
 447                        const struct i2c_device_id *tmp007_id)
 448{
 449        struct tmp007_data *data;
 450        struct iio_dev *indio_dev;
 451        int ret;
 452
 453        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
 454                return -EOPNOTSUPP;
 455
 456        if (!tmp007_identify(client)) {
 457                dev_err(&client->dev, "TMP007 not found\n");
 458                return -ENODEV;
 459        }
 460
 461        indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
 462        if (!indio_dev)
 463                return -ENOMEM;
 464
 465        data = iio_priv(indio_dev);
 466        i2c_set_clientdata(client, indio_dev);
 467        data->client = client;
 468        mutex_init(&data->lock);
 469
 470        indio_dev->dev.parent = &client->dev;
 471        indio_dev->name = "tmp007";
 472        indio_dev->modes = INDIO_DIRECT_MODE;
 473        indio_dev->info = &tmp007_info;
 474
 475        indio_dev->channels = tmp007_channels;
 476        indio_dev->num_channels = ARRAY_SIZE(tmp007_channels);
 477
 478        /*
 479         * Set Configuration register:
 480         * 1. Conversion ON
 481         * 2. ALERT enable
 482         * 3. Transient correction enable
 483         */
 484
 485        ret = i2c_smbus_read_word_swapped(data->client, TMP007_CONFIG);
 486        if (ret < 0)
 487                return ret;
 488
 489        data->config = ret;
 490        data->config |= (TMP007_CONFIG_CONV_EN | TMP007_CONFIG_ALERT_EN | TMP007_CONFIG_TC_EN);
 491
 492        ret = i2c_smbus_write_word_swapped(data->client, TMP007_CONFIG,
 493                                        data->config);
 494        if (ret < 0)
 495                return ret;
 496
 497        /*
 498         * Only the following flags can activate ALERT pin. Data conversion/validity flags
 499         * flags can still be polled for getting temperature data
 500         *
 501         * Set Status Mask register:
 502         * 1. Object temperature high limit enable
 503         * 2. Object temperature low limit enable
 504         * 3. TDIE temperature high limit enable
 505         * 4. TDIE temperature low limit enable
 506         */
 507
 508        ret = i2c_smbus_read_word_swapped(data->client, TMP007_STATUS_MASK);
 509        if (ret < 0)
 510                goto error_powerdown;
 511
 512        data->status_mask = ret;
 513        data->status_mask |= (TMP007_STATUS_OHF | TMP007_STATUS_OLF
 514                                | TMP007_STATUS_LHF | TMP007_STATUS_LLF);
 515
 516        ret = i2c_smbus_write_word_swapped(data->client, TMP007_STATUS_MASK, data->status_mask);
 517        if (ret < 0)
 518                goto error_powerdown;
 519
 520        if (client->irq) {
 521                ret = devm_request_threaded_irq(&client->dev, client->irq,
 522                                NULL, tmp007_interrupt_handler,
 523                                IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
 524                                tmp007_id->name, indio_dev);
 525                if (ret) {
 526                        dev_err(&client->dev, "irq request error %d\n", -ret);
 527                        goto error_powerdown;
 528                }
 529        }
 530
 531        return iio_device_register(indio_dev);
 532
 533error_powerdown:
 534        tmp007_powerdown(data);
 535
 536        return ret;
 537}
 538
 539static int tmp007_remove(struct i2c_client *client)
 540{
 541        struct iio_dev *indio_dev = i2c_get_clientdata(client);
 542        struct tmp007_data *data = iio_priv(indio_dev);
 543
 544        iio_device_unregister(indio_dev);
 545        tmp007_powerdown(data);
 546
 547        return 0;
 548}
 549
 550#ifdef CONFIG_PM_SLEEP
 551static int tmp007_suspend(struct device *dev)
 552{
 553        struct tmp007_data *data = iio_priv(i2c_get_clientdata(
 554                        to_i2c_client(dev)));
 555
 556        return tmp007_powerdown(data);
 557}
 558
 559static int tmp007_resume(struct device *dev)
 560{
 561        struct tmp007_data *data = iio_priv(i2c_get_clientdata(
 562                        to_i2c_client(dev)));
 563
 564        return i2c_smbus_write_word_swapped(data->client, TMP007_CONFIG,
 565                        data->config | TMP007_CONFIG_CONV_EN);
 566}
 567#endif
 568
 569static SIMPLE_DEV_PM_OPS(tmp007_pm_ops, tmp007_suspend, tmp007_resume);
 570
 571static const struct of_device_id tmp007_of_match[] = {
 572        { .compatible = "ti,tmp007", },
 573        { },
 574};
 575MODULE_DEVICE_TABLE(of, tmp007_of_match);
 576
 577static const struct i2c_device_id tmp007_id[] = {
 578        { "tmp007", 0 },
 579        { }
 580};
 581MODULE_DEVICE_TABLE(i2c, tmp007_id);
 582
 583static struct i2c_driver tmp007_driver = {
 584        .driver = {
 585                .name   = "tmp007",
 586                .of_match_table = of_match_ptr(tmp007_of_match),
 587                .pm     = &tmp007_pm_ops,
 588        },
 589        .probe          = tmp007_probe,
 590        .remove         = tmp007_remove,
 591        .id_table       = tmp007_id,
 592};
 593module_i2c_driver(tmp007_driver);
 594
 595MODULE_AUTHOR("Manivannan Sadhasivam <manivannanece23@gmail.com>");
 596MODULE_DESCRIPTION("TI TMP007 IR thermopile sensor driver");
 597MODULE_LICENSE("GPL");
 598