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