linux/drivers/iio/temperature/mlx90614.c
<<
>>
Prefs
   1/*
   2 * mlx90614.c - Support for Melexis MLX90614 contactless IR temperature sensor
   3 *
   4 * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net>
   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 Melexis MLX90614 I2C 16-bit IR thermopile sensor
  11 *
  12 * (7-bit I2C slave address 0x5a, 100KHz bus speed only!)
  13 *
  14 * TODO: sleep mode, configuration EEPROM
  15 */
  16
  17#include <linux/err.h>
  18#include <linux/i2c.h>
  19#include <linux/module.h>
  20
  21#include <linux/iio/iio.h>
  22
  23#define MLX90614_OP_RAM 0x00
  24
  25/* RAM offsets with 16-bit data, MSB first */
  26#define MLX90614_TA 0x06 /* ambient temperature */
  27#define MLX90614_TOBJ1 0x07 /* object temperature */
  28
  29struct mlx90614_data {
  30        struct i2c_client *client;
  31};
  32
  33static int mlx90614_read_raw(struct iio_dev *indio_dev,
  34                            struct iio_chan_spec const *channel, int *val,
  35                            int *val2, long mask)
  36{
  37        struct mlx90614_data *data = iio_priv(indio_dev);
  38        s32 ret;
  39
  40        switch (mask) {
  41        case IIO_CHAN_INFO_RAW: /* 0.02K / LSB */
  42                switch (channel->channel2) {
  43                case IIO_MOD_TEMP_AMBIENT:
  44                        ret = i2c_smbus_read_word_data(data->client,
  45                            MLX90614_OP_RAM | MLX90614_TA);
  46                        if (ret < 0)
  47                                return ret;
  48                        break;
  49                case IIO_MOD_TEMP_OBJECT:
  50                        ret = i2c_smbus_read_word_data(data->client,
  51                            MLX90614_OP_RAM | MLX90614_TOBJ1);
  52                        if (ret < 0)
  53                                return ret;
  54                        break;
  55                default:
  56                        return -EINVAL;
  57                }
  58                *val = ret;
  59                return IIO_VAL_INT;
  60        case IIO_CHAN_INFO_OFFSET:
  61                *val = 13657;
  62                *val2 = 500000;
  63                return IIO_VAL_INT_PLUS_MICRO;
  64        case IIO_CHAN_INFO_SCALE:
  65                *val = 20;
  66                return IIO_VAL_INT;
  67        default:
  68                return -EINVAL;
  69        }
  70}
  71
  72static const struct iio_chan_spec mlx90614_channels[] = {
  73        {
  74                .type = IIO_TEMP,
  75                .modified = 1,
  76                .channel2 = IIO_MOD_TEMP_AMBIENT,
  77                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
  78                .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
  79                    BIT(IIO_CHAN_INFO_SCALE),
  80        },
  81        {
  82                .type = IIO_TEMP,
  83                .modified = 1,
  84                .channel2 = IIO_MOD_TEMP_OBJECT,
  85                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
  86                .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
  87                    BIT(IIO_CHAN_INFO_SCALE),
  88        },
  89};
  90
  91static const struct iio_info mlx90614_info = {
  92        .read_raw = mlx90614_read_raw,
  93        .driver_module = THIS_MODULE,
  94};
  95
  96static int mlx90614_probe(struct i2c_client *client,
  97                         const struct i2c_device_id *id)
  98{
  99        struct iio_dev *indio_dev;
 100        struct mlx90614_data *data;
 101
 102        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
 103                return -ENODEV;
 104
 105        indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
 106        if (!indio_dev)
 107                return -ENOMEM;
 108
 109        data = iio_priv(indio_dev);
 110        i2c_set_clientdata(client, indio_dev);
 111        data->client = client;
 112
 113        indio_dev->dev.parent = &client->dev;
 114        indio_dev->name = id->name;
 115        indio_dev->modes = INDIO_DIRECT_MODE;
 116        indio_dev->info = &mlx90614_info;
 117
 118        indio_dev->channels = mlx90614_channels;
 119        indio_dev->num_channels = ARRAY_SIZE(mlx90614_channels);
 120
 121        return iio_device_register(indio_dev);
 122}
 123
 124static int mlx90614_remove(struct i2c_client *client)
 125{
 126        iio_device_unregister(i2c_get_clientdata(client));
 127
 128        return 0;
 129}
 130
 131static const struct i2c_device_id mlx90614_id[] = {
 132        { "mlx90614", 0 },
 133        { }
 134};
 135MODULE_DEVICE_TABLE(i2c, mlx90614_id);
 136
 137static struct i2c_driver mlx90614_driver = {
 138        .driver = {
 139                .name   = "mlx90614",
 140                .owner  = THIS_MODULE,
 141        },
 142        .probe = mlx90614_probe,
 143        .remove = mlx90614_remove,
 144        .id_table = mlx90614_id,
 145};
 146module_i2c_driver(mlx90614_driver);
 147
 148MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
 149MODULE_DESCRIPTION("Melexis MLX90614 contactless IR temperature sensor driver");
 150MODULE_LICENSE("GPL");
 151