1 /* 2 * mlx90614.c - Support for Melexis MLX90614 contactless IR temperature sensor 3 * 4 * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net> 5 * Copyright (c) 2015 Essensium NV 6 * 7 * This file is subject to the terms and conditions of version 2 of 8 * the GNU General Public License. See the file COPYING in the main 9 * directory of this archive for more details. 10 * 11 * Driver for the Melexis MLX90614 I2C 16-bit IR thermopile sensor 12 * 13 * (7-bit I2C slave address 0x5a, 100KHz bus speed only!) 14 * 15 * TODO: sleep mode, configuration EEPROM 16 */ 17 18 #include <linux/err.h> 19 #include <linux/i2c.h> 20 #include <linux/module.h> 21 22 #include <linux/iio/iio.h> 23 24 #define MLX90614_OP_RAM 0x00 25 #define MLX90614_OP_EEPROM 0x20 26 #define MLX90614_OP_SLEEP 0xff 27 28 /* RAM offsets with 16-bit data, MSB first */ 29 #define MLX90614_RAW1 (MLX90614_OP_RAM | 0x04) /* raw data IR channel 1 */ 30 #define MLX90614_RAW2 (MLX90614_OP_RAM | 0x05) /* raw data IR channel 2 */ 31 #define MLX90614_TA (MLX90614_OP_RAM | 0x06) /* ambient temperature */ 32 #define MLX90614_TOBJ1 (MLX90614_OP_RAM | 0x07) /* object 1 temperature */ 33 #define MLX90614_TOBJ2 (MLX90614_OP_RAM | 0x08) /* object 2 temperature */ 34 35 /* EEPROM offsets with 16-bit data, MSB first */ 36 #define MLX90614_EMISSIVITY (MLX90614_OP_EEPROM | 0x04) /* emissivity correction coefficient */ 37 #define MLX90614_CONFIG (MLX90614_OP_EEPROM | 0x05) /* configuration register */ 38 39 /* Control bits in configuration register */ 40 #define MLX90614_CONFIG_IIR_SHIFT 0 /* IIR coefficient */ 41 #define MLX90614_CONFIG_IIR_MASK (0x7 << MLX90614_CONFIG_IIR_SHIFT) 42 #define MLX90614_CONFIG_DUAL_SHIFT 6 /* single (0) or dual (1) IR sensor */ 43 #define MLX90614_CONFIG_DUAL_MASK (1 << MLX90614_CONFIG_DUAL_SHIFT) 44 #define MLX90614_CONFIG_FIR_SHIFT 8 /* FIR coefficient */ 45 #define MLX90614_CONFIG_FIR_MASK (0x7 << MLX90614_CONFIG_FIR_SHIFT) 46 #define MLX90614_CONFIG_GAIN_SHIFT 11 /* gain */ 47 #define MLX90614_CONFIG_GAIN_MASK (0x7 << MLX90614_CONFIG_GAIN_SHIFT) 48 49 /* Timings (in ms) */ 50 #define MLX90614_TIMING_EEPROM 20 /* time for EEPROM write/erase to complete */ 51 #define MLX90614_TIMING_WAKEUP 34 /* time to hold SDA low for wake-up */ 52 #define MLX90614_TIMING_STARTUP 250 /* time before first data after wake-up */ 53 54 struct mlx90614_data { 55 struct i2c_client *client; 56 }; 57 58 static int mlx90614_read_raw(struct iio_dev *indio_dev, 59 struct iio_chan_spec const *channel, int *val, 60 int *val2, long mask) 61 { 62 struct mlx90614_data *data = iio_priv(indio_dev); 63 u8 cmd; 64 s32 ret; 65 66 switch (mask) { 67 case IIO_CHAN_INFO_RAW: /* 0.02K / LSB */ 68 switch (channel->channel2) { 69 case IIO_MOD_TEMP_AMBIENT: 70 cmd = MLX90614_TA; 71 break; 72 case IIO_MOD_TEMP_OBJECT: 73 switch (channel->channel) { 74 case 0: 75 cmd = MLX90614_TOBJ1; 76 break; 77 case 1: 78 cmd = MLX90614_TOBJ2; 79 break; 80 default: 81 return -EINVAL; 82 } 83 break; 84 default: 85 return -EINVAL; 86 } 87 88 ret = i2c_smbus_read_word_data(data->client, cmd); 89 if (ret < 0) 90 return ret; 91 *val = ret; 92 return IIO_VAL_INT; 93 case IIO_CHAN_INFO_OFFSET: 94 *val = 13657; 95 *val2 = 500000; 96 return IIO_VAL_INT_PLUS_MICRO; 97 case IIO_CHAN_INFO_SCALE: 98 *val = 20; 99 return IIO_VAL_INT; 100 default: 101 return -EINVAL; 102 } 103 } 104 105 static const struct iio_chan_spec mlx90614_channels[] = { 106 { 107 .type = IIO_TEMP, 108 .modified = 1, 109 .channel2 = IIO_MOD_TEMP_AMBIENT, 110 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 111 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | 112 BIT(IIO_CHAN_INFO_SCALE), 113 }, 114 { 115 .type = IIO_TEMP, 116 .modified = 1, 117 .channel2 = IIO_MOD_TEMP_OBJECT, 118 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 119 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | 120 BIT(IIO_CHAN_INFO_SCALE), 121 }, 122 { 123 .type = IIO_TEMP, 124 .indexed = 1, 125 .modified = 1, 126 .channel = 1, 127 .channel2 = IIO_MOD_TEMP_OBJECT, 128 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 129 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | 130 BIT(IIO_CHAN_INFO_SCALE), 131 }, 132 }; 133 134 static const struct iio_info mlx90614_info = { 135 .read_raw = mlx90614_read_raw, 136 .driver_module = THIS_MODULE, 137 }; 138 139 /* Return 0 for single sensor, 1 for dual sensor, <0 on error. */ 140 static int mlx90614_probe_num_ir_sensors(struct i2c_client *client) 141 { 142 s32 ret; 143 144 ret = i2c_smbus_read_word_data(client, MLX90614_CONFIG); 145 146 if (ret < 0) 147 return ret; 148 149 return (ret & MLX90614_CONFIG_DUAL_MASK) ? 1 : 0; 150 } 151 152 static int mlx90614_probe(struct i2c_client *client, 153 const struct i2c_device_id *id) 154 { 155 struct iio_dev *indio_dev; 156 struct mlx90614_data *data; 157 int ret; 158 159 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) 160 return -ENODEV; 161 162 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 163 if (!indio_dev) 164 return -ENOMEM; 165 166 data = iio_priv(indio_dev); 167 i2c_set_clientdata(client, indio_dev); 168 data->client = client; 169 170 indio_dev->dev.parent = &client->dev; 171 indio_dev->name = id->name; 172 indio_dev->modes = INDIO_DIRECT_MODE; 173 indio_dev->info = &mlx90614_info; 174 175 ret = mlx90614_probe_num_ir_sensors(client); 176 switch (ret) { 177 case 0: 178 dev_dbg(&client->dev, "Found single sensor"); 179 indio_dev->channels = mlx90614_channels; 180 indio_dev->num_channels = 2; 181 break; 182 case 1: 183 dev_dbg(&client->dev, "Found dual sensor"); 184 indio_dev->channels = mlx90614_channels; 185 indio_dev->num_channels = 3; 186 break; 187 default: 188 return ret; 189 } 190 191 return iio_device_register(indio_dev); 192 } 193 194 static int mlx90614_remove(struct i2c_client *client) 195 { 196 iio_device_unregister(i2c_get_clientdata(client)); 197 198 return 0; 199 } 200 201 static const struct i2c_device_id mlx90614_id[] = { 202 { "mlx90614", 0 }, 203 { } 204 }; 205 MODULE_DEVICE_TABLE(i2c, mlx90614_id); 206 207 static struct i2c_driver mlx90614_driver = { 208 .driver = { 209 .name = "mlx90614", 210 .owner = THIS_MODULE, 211 }, 212 .probe = mlx90614_probe, 213 .remove = mlx90614_remove, 214 .id_table = mlx90614_id, 215 }; 216 module_i2c_driver(mlx90614_driver); 217 218 MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>"); 219 MODULE_AUTHOR("Vianney le Clément de Saint-Marcq <vianney.leclement@essensium.com>"); 220 MODULE_DESCRIPTION("Melexis MLX90614 contactless IR temperature sensor driver"); 221 MODULE_LICENSE("GPL"); 222