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: This driver assumes that the sensor has been calibrated beforehand 15 * 16 * TODO: ALERT irq, limit threshold events 17 * 18 */ 19 20 #include <linux/err.h> 21 #include <linux/i2c.h> 22 #include <linux/delay.h> 23 #include <linux/module.h> 24 #include <linux/pm.h> 25 #include <linux/bitops.h> 26 #include <linux/of.h> 27 28 #include <linux/iio/iio.h> 29 #include <linux/iio/sysfs.h> 30 31 #define TMP007_TDIE 0x01 32 #define TMP007_CONFIG 0x02 33 #define TMP007_TOBJECT 0x03 34 #define TMP007_STATUS 0x04 35 #define TMP007_STATUS_MASK 0x05 36 #define TMP007_MANUFACTURER_ID 0x1e 37 #define TMP007_DEVICE_ID 0x1f 38 39 #define TMP007_CONFIG_CONV_EN BIT(12) 40 #define TMP007_CONFIG_COMP_EN BIT(5) 41 #define TMP007_CONFIG_TC_EN BIT(6) 42 #define TMP007_CONFIG_CR_MASK GENMASK(11, 9) 43 #define TMP007_CONFIG_CR_SHIFT 9 44 45 #define TMP007_STATUS_CONV_READY BIT(14) 46 #define TMP007_STATUS_DATA_VALID BIT(9) 47 48 #define TMP007_MANUFACTURER_MAGIC 0x5449 49 #define TMP007_DEVICE_MAGIC 0x0078 50 51 #define TMP007_TEMP_SHIFT 2 52 53 struct tmp007_data { 54 struct i2c_client *client; 55 u16 config; 56 }; 57 58 static const int tmp007_avgs[5][2] = { {4, 0}, {2, 0}, {1, 0}, 59 {0, 500000}, {0, 250000} }; 60 61 static int tmp007_read_temperature(struct tmp007_data *data, u8 reg) 62 { 63 s32 ret; 64 int tries = 50; 65 66 while (tries-- > 0) { 67 ret = i2c_smbus_read_word_swapped(data->client, 68 TMP007_STATUS); 69 if (ret < 0) 70 return ret; 71 if ((ret & TMP007_STATUS_CONV_READY) && 72 !(ret & TMP007_STATUS_DATA_VALID)) 73 break; 74 msleep(100); 75 } 76 77 if (tries < 0) 78 return -EIO; 79 80 return i2c_smbus_read_word_swapped(data->client, reg); 81 } 82 83 static int tmp007_powerdown(struct tmp007_data *data) 84 { 85 return i2c_smbus_write_word_swapped(data->client, TMP007_CONFIG, 86 data->config & ~TMP007_CONFIG_CONV_EN); 87 } 88 89 static int tmp007_read_raw(struct iio_dev *indio_dev, 90 struct iio_chan_spec const *channel, int *val, 91 int *val2, long mask) 92 { 93 struct tmp007_data *data = iio_priv(indio_dev); 94 s32 ret; 95 int conv_rate; 96 97 switch (mask) { 98 case IIO_CHAN_INFO_RAW: 99 switch (channel->channel2) { 100 case IIO_MOD_TEMP_AMBIENT: /* LSB: 0.03125 degree Celsius */ 101 ret = i2c_smbus_read_word_swapped(data->client, TMP007_TDIE); 102 if (ret < 0) 103 return ret; 104 break; 105 case IIO_MOD_TEMP_OBJECT: 106 ret = tmp007_read_temperature(data, TMP007_TOBJECT); 107 if (ret < 0) 108 return ret; 109 break; 110 default: 111 return -EINVAL; 112 } 113 114 *val = sign_extend32(ret, 15) >> TMP007_TEMP_SHIFT; 115 116 return IIO_VAL_INT; 117 case IIO_CHAN_INFO_SCALE: 118 *val = 31; 119 *val2 = 250000; 120 121 return IIO_VAL_INT_PLUS_MICRO; 122 case IIO_CHAN_INFO_SAMP_FREQ: 123 conv_rate = (data->config & TMP007_CONFIG_CR_MASK) 124 >> TMP007_CONFIG_CR_SHIFT; 125 *val = tmp007_avgs[conv_rate][0]; 126 *val2 = tmp007_avgs[conv_rate][1]; 127 128 return IIO_VAL_INT_PLUS_MICRO; 129 default: 130 return -EINVAL; 131 } 132 } 133 134 static int tmp007_write_raw(struct iio_dev *indio_dev, 135 struct iio_chan_spec const *channel, int val, 136 int val2, long mask) 137 { 138 struct tmp007_data *data = iio_priv(indio_dev); 139 int i; 140 u16 tmp; 141 142 if (mask == IIO_CHAN_INFO_SAMP_FREQ) { 143 for (i = 0; i < ARRAY_SIZE(tmp007_avgs); i++) { 144 if ((val == tmp007_avgs[i][0]) && 145 (val2 == tmp007_avgs[i][1])) { 146 tmp = data->config & ~TMP007_CONFIG_CR_MASK; 147 tmp |= (i << TMP007_CONFIG_CR_SHIFT); 148 149 return i2c_smbus_write_word_swapped(data->client, 150 TMP007_CONFIG, 151 data->config = tmp); 152 } 153 } 154 } 155 156 return -EINVAL; 157 } 158 159 static IIO_CONST_ATTR(sampling_frequency_available, "4 2 1 0.5 0.25"); 160 161 static struct attribute *tmp007_attributes[] = { 162 &iio_const_attr_sampling_frequency_available.dev_attr.attr, 163 NULL 164 }; 165 166 static const struct attribute_group tmp007_attribute_group = { 167 .attrs = tmp007_attributes, 168 }; 169 170 static const struct iio_chan_spec tmp007_channels[] = { 171 { 172 .type = IIO_TEMP, 173 .modified = 1, 174 .channel2 = IIO_MOD_TEMP_AMBIENT, 175 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 176 BIT(IIO_CHAN_INFO_SCALE), 177 .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), 178 }, 179 { 180 .type = IIO_TEMP, 181 .modified = 1, 182 .channel2 = IIO_MOD_TEMP_OBJECT, 183 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 184 BIT(IIO_CHAN_INFO_SCALE), 185 .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), 186 } 187 }; 188 189 static const struct iio_info tmp007_info = { 190 .read_raw = tmp007_read_raw, 191 .write_raw = tmp007_write_raw, 192 .attrs = &tmp007_attribute_group, 193 .driver_module = THIS_MODULE, 194 }; 195 196 static bool tmp007_identify(struct i2c_client *client) 197 { 198 int manf_id, dev_id; 199 200 manf_id = i2c_smbus_read_word_swapped(client, TMP007_MANUFACTURER_ID); 201 if (manf_id < 0) 202 return false; 203 204 dev_id = i2c_smbus_read_word_swapped(client, TMP007_DEVICE_ID); 205 if (dev_id < 0) 206 return false; 207 208 return (manf_id == TMP007_MANUFACTURER_MAGIC && dev_id == TMP007_DEVICE_MAGIC); 209 } 210 211 static int tmp007_probe(struct i2c_client *client, 212 const struct i2c_device_id *tmp007_id) 213 { 214 struct tmp007_data *data; 215 struct iio_dev *indio_dev; 216 int ret; 217 u16 status; 218 219 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) 220 return -EOPNOTSUPP; 221 222 if (!tmp007_identify(client)) { 223 dev_err(&client->dev, "TMP007 not found\n"); 224 return -ENODEV; 225 } 226 227 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 228 if (!indio_dev) 229 return -ENOMEM; 230 231 data = iio_priv(indio_dev); 232 i2c_set_clientdata(client, indio_dev); 233 data->client = client; 234 235 indio_dev->dev.parent = &client->dev; 236 indio_dev->name = "tmp007"; 237 indio_dev->modes = INDIO_DIRECT_MODE; 238 indio_dev->info = &tmp007_info; 239 240 indio_dev->channels = tmp007_channels; 241 indio_dev->num_channels = ARRAY_SIZE(tmp007_channels); 242 243 /* 244 * Set Configuration register: 245 * 1. Conversion ON 246 * 2. Comparator mode 247 * 3. Transient correction enable 248 */ 249 250 ret = i2c_smbus_read_word_swapped(data->client, TMP007_CONFIG); 251 if (ret < 0) 252 return ret; 253 254 data->config = ret; 255 data->config |= (TMP007_CONFIG_CONV_EN | TMP007_CONFIG_COMP_EN | TMP007_CONFIG_TC_EN); 256 257 ret = i2c_smbus_write_word_swapped(data->client, TMP007_CONFIG, 258 data->config); 259 if (ret < 0) 260 return ret; 261 262 /* 263 * Set Status Mask register: 264 * 1. Conversion ready enable 265 * 2. Data valid enable 266 */ 267 268 ret = i2c_smbus_read_word_swapped(data->client, TMP007_STATUS_MASK); 269 if (ret < 0) 270 goto error_powerdown; 271 272 status = ret; 273 status |= (TMP007_STATUS_CONV_READY | TMP007_STATUS_DATA_VALID); 274 275 ret = i2c_smbus_write_word_swapped(data->client, TMP007_STATUS_MASK, status); 276 if (ret < 0) 277 goto error_powerdown; 278 279 return iio_device_register(indio_dev); 280 281 error_powerdown: 282 tmp007_powerdown(data); 283 284 return ret; 285 } 286 287 static int tmp007_remove(struct i2c_client *client) 288 { 289 struct iio_dev *indio_dev = i2c_get_clientdata(client); 290 struct tmp007_data *data = iio_priv(indio_dev); 291 292 iio_device_unregister(indio_dev); 293 tmp007_powerdown(data); 294 295 return 0; 296 } 297 298 #ifdef CONFIG_PM_SLEEP 299 static int tmp007_suspend(struct device *dev) 300 { 301 struct tmp007_data *data = iio_priv(i2c_get_clientdata( 302 to_i2c_client(dev))); 303 304 return tmp007_powerdown(data); 305 } 306 307 static int tmp007_resume(struct device *dev) 308 { 309 struct tmp007_data *data = iio_priv(i2c_get_clientdata( 310 to_i2c_client(dev))); 311 312 return i2c_smbus_write_word_swapped(data->client, TMP007_CONFIG, 313 data->config | TMP007_CONFIG_CONV_EN); 314 } 315 #endif 316 317 static SIMPLE_DEV_PM_OPS(tmp007_pm_ops, tmp007_suspend, tmp007_resume); 318 319 static const struct of_device_id tmp007_of_match[] = { 320 { .compatible = "ti,tmp007", }, 321 { }, 322 }; 323 MODULE_DEVICE_TABLE(of, tmp007_of_match); 324 325 static const struct i2c_device_id tmp007_id[] = { 326 { "tmp007", 0 }, 327 { } 328 }; 329 MODULE_DEVICE_TABLE(i2c, tmp007_id); 330 331 static struct i2c_driver tmp007_driver = { 332 .driver = { 333 .name = "tmp007", 334 .of_match_table = of_match_ptr(tmp007_of_match), 335 .pm = &tmp007_pm_ops, 336 }, 337 .probe = tmp007_probe, 338 .remove = tmp007_remove, 339 .id_table = tmp007_id, 340 }; 341 module_i2c_driver(tmp007_driver); 342 343 MODULE_AUTHOR("Manivannan Sadhasivam <manivannanece23@gmail.com>"); 344 MODULE_DESCRIPTION("TI TMP007 IR thermopile sensor driver"); 345 MODULE_LICENSE("GPL"); 346