1a2d8be68SPeter Meerwald /* 2a2d8be68SPeter Meerwald * t5403.c - Support for EPCOS T5403 pressure/temperature sensor 3a2d8be68SPeter Meerwald * 4a2d8be68SPeter Meerwald * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net> 5a2d8be68SPeter Meerwald * 6a2d8be68SPeter Meerwald * This file is subject to the terms and conditions of version 2 of 7a2d8be68SPeter Meerwald * the GNU General Public License. See the file COPYING in the main 8a2d8be68SPeter Meerwald * directory of this archive for more details. 9a2d8be68SPeter Meerwald * 10a2d8be68SPeter Meerwald * (7-bit I2C slave address 0x77) 11a2d8be68SPeter Meerwald * 12a2d8be68SPeter Meerwald * TODO: end-of-conversion irq 13a2d8be68SPeter Meerwald */ 14a2d8be68SPeter Meerwald 15a2d8be68SPeter Meerwald #include <linux/module.h> 16a2d8be68SPeter Meerwald #include <linux/i2c.h> 17a2d8be68SPeter Meerwald #include <linux/iio/iio.h> 18a2d8be68SPeter Meerwald #include <linux/iio/sysfs.h> 19a2d8be68SPeter Meerwald #include <linux/delay.h> 20a2d8be68SPeter Meerwald 21a2d8be68SPeter Meerwald #define T5403_DATA 0xf5 /* data, LSB first, 16 bit */ 22a2d8be68SPeter Meerwald #define T5403_CALIB_DATA 0x8e /* 10 calibration coeff., LSB first, 16 bit */ 23a2d8be68SPeter Meerwald #define T5403_SLAVE_ADDR 0x88 /* I2C slave address, 0x77 */ 24a2d8be68SPeter Meerwald #define T5403_COMMAND 0xf1 25a2d8be68SPeter Meerwald 26a2d8be68SPeter Meerwald /* command bits */ 27a2d8be68SPeter Meerwald #define T5403_MODE_SHIFT 3 /* conversion time: 2, 8, 16, 66 ms */ 28a2d8be68SPeter Meerwald #define T5403_PT BIT(1) /* 0 .. pressure, 1 .. temperature measurement */ 29a2d8be68SPeter Meerwald #define T5403_SCO BIT(0) /* start conversion */ 30a2d8be68SPeter Meerwald 31a2d8be68SPeter Meerwald #define T5403_MODE_LOW 0 32a2d8be68SPeter Meerwald #define T5403_MODE_STANDARD 1 33a2d8be68SPeter Meerwald #define T5403_MODE_HIGH 2 34a2d8be68SPeter Meerwald #define T5403_MODE_ULTRA_HIGH 3 35a2d8be68SPeter Meerwald 36a2d8be68SPeter Meerwald #define T5403_I2C_MASK (~BIT(7)) 37a2d8be68SPeter Meerwald #define T5403_I2C_ADDR 0x77 38a2d8be68SPeter Meerwald 39a2d8be68SPeter Meerwald static const int t5403_pressure_conv_ms[] = {2, 8, 16, 66}; 40a2d8be68SPeter Meerwald 41a2d8be68SPeter Meerwald struct t5403_data { 42a2d8be68SPeter Meerwald struct i2c_client *client; 43a2d8be68SPeter Meerwald struct mutex lock; 44a2d8be68SPeter Meerwald int mode; 45a2d8be68SPeter Meerwald __le16 c[10]; 46a2d8be68SPeter Meerwald }; 47a2d8be68SPeter Meerwald 48a2d8be68SPeter Meerwald #define T5403_C_U16(i) le16_to_cpu(data->c[(i) - 1]) 49a2d8be68SPeter Meerwald #define T5403_C(i) sign_extend32(T5403_C_U16(i), 15) 50a2d8be68SPeter Meerwald 51a2d8be68SPeter Meerwald static int t5403_read(struct t5403_data *data, bool pressure) 52a2d8be68SPeter Meerwald { 53a2d8be68SPeter Meerwald int wait_time = 3; /* wakeup time in ms */ 54a2d8be68SPeter Meerwald 55a2d8be68SPeter Meerwald int ret = i2c_smbus_write_byte_data(data->client, T5403_COMMAND, 56a2d8be68SPeter Meerwald (pressure ? (data->mode << T5403_MODE_SHIFT) : T5403_PT) | 57a2d8be68SPeter Meerwald T5403_SCO); 58a2d8be68SPeter Meerwald if (ret < 0) 59a2d8be68SPeter Meerwald return ret; 60a2d8be68SPeter Meerwald 61a2d8be68SPeter Meerwald wait_time += pressure ? t5403_pressure_conv_ms[data->mode] : 2; 62a2d8be68SPeter Meerwald 63a2d8be68SPeter Meerwald msleep(wait_time); 64a2d8be68SPeter Meerwald 65a2d8be68SPeter Meerwald return i2c_smbus_read_word_data(data->client, T5403_DATA); 66a2d8be68SPeter Meerwald } 67a2d8be68SPeter Meerwald 68a2d8be68SPeter Meerwald static int t5403_comp_pressure(struct t5403_data *data, int *val, int *val2) 69a2d8be68SPeter Meerwald { 70a2d8be68SPeter Meerwald int ret; 71a2d8be68SPeter Meerwald s16 t_r; 72a2d8be68SPeter Meerwald u16 p_r; 73a2d8be68SPeter Meerwald s32 S, O, X; 74a2d8be68SPeter Meerwald 75a2d8be68SPeter Meerwald mutex_lock(&data->lock); 76a2d8be68SPeter Meerwald 77a2d8be68SPeter Meerwald ret = t5403_read(data, false); 78a2d8be68SPeter Meerwald if (ret < 0) 79a2d8be68SPeter Meerwald goto done; 80a2d8be68SPeter Meerwald t_r = ret; 81a2d8be68SPeter Meerwald 82a2d8be68SPeter Meerwald ret = t5403_read(data, true); 83a2d8be68SPeter Meerwald if (ret < 0) 84a2d8be68SPeter Meerwald goto done; 85a2d8be68SPeter Meerwald p_r = ret; 86a2d8be68SPeter Meerwald 87a2d8be68SPeter Meerwald /* see EPCOS application note */ 88a2d8be68SPeter Meerwald S = T5403_C_U16(3) + (s32) T5403_C_U16(4) * t_r / 0x20000 + 89a2d8be68SPeter Meerwald T5403_C(5) * t_r / 0x8000 * t_r / 0x80000 + 90a2d8be68SPeter Meerwald T5403_C(9) * t_r / 0x8000 * t_r / 0x8000 * t_r / 0x10000; 91a2d8be68SPeter Meerwald 92a2d8be68SPeter Meerwald O = T5403_C(6) * 0x4000 + T5403_C(7) * t_r / 8 + 93a2d8be68SPeter Meerwald T5403_C(8) * t_r / 0x8000 * t_r / 16 + 94a2d8be68SPeter Meerwald T5403_C(9) * t_r / 0x8000 * t_r / 0x10000 * t_r; 95a2d8be68SPeter Meerwald 96a2d8be68SPeter Meerwald X = (S * p_r + O) / 0x4000; 97a2d8be68SPeter Meerwald 98a2d8be68SPeter Meerwald X += ((X - 75000) * (X - 75000) / 0x10000 - 9537) * 99a2d8be68SPeter Meerwald T5403_C(10) / 0x10000; 100a2d8be68SPeter Meerwald 101a2d8be68SPeter Meerwald *val = X / 1000; 102a2d8be68SPeter Meerwald *val2 = (X % 1000) * 1000; 103a2d8be68SPeter Meerwald 104a2d8be68SPeter Meerwald done: 105a2d8be68SPeter Meerwald mutex_unlock(&data->lock); 106a2d8be68SPeter Meerwald return ret; 107a2d8be68SPeter Meerwald } 108a2d8be68SPeter Meerwald 109a2d8be68SPeter Meerwald static int t5403_comp_temp(struct t5403_data *data, int *val) 110a2d8be68SPeter Meerwald { 111a2d8be68SPeter Meerwald int ret; 112a2d8be68SPeter Meerwald s16 t_r; 113a2d8be68SPeter Meerwald 114a2d8be68SPeter Meerwald mutex_lock(&data->lock); 115a2d8be68SPeter Meerwald ret = t5403_read(data, false); 116a2d8be68SPeter Meerwald if (ret < 0) 117a2d8be68SPeter Meerwald goto done; 118a2d8be68SPeter Meerwald t_r = ret; 119a2d8be68SPeter Meerwald 120a2d8be68SPeter Meerwald /* see EPCOS application note */ 121a2d8be68SPeter Meerwald *val = ((s32) T5403_C_U16(1) * t_r / 0x100 + 122a2d8be68SPeter Meerwald (s32) T5403_C_U16(2) * 0x40) * 1000 / 0x10000; 123a2d8be68SPeter Meerwald 124a2d8be68SPeter Meerwald done: 125a2d8be68SPeter Meerwald mutex_unlock(&data->lock); 126a2d8be68SPeter Meerwald return ret; 127a2d8be68SPeter Meerwald } 128a2d8be68SPeter Meerwald 129a2d8be68SPeter Meerwald static int t5403_read_raw(struct iio_dev *indio_dev, 130a2d8be68SPeter Meerwald struct iio_chan_spec const *chan, 131a2d8be68SPeter Meerwald int *val, int *val2, long mask) 132a2d8be68SPeter Meerwald { 133a2d8be68SPeter Meerwald struct t5403_data *data = iio_priv(indio_dev); 134a2d8be68SPeter Meerwald int ret; 135a2d8be68SPeter Meerwald 136a2d8be68SPeter Meerwald switch (mask) { 137a2d8be68SPeter Meerwald case IIO_CHAN_INFO_PROCESSED: 138a2d8be68SPeter Meerwald switch (chan->type) { 139a2d8be68SPeter Meerwald case IIO_PRESSURE: 140a2d8be68SPeter Meerwald ret = t5403_comp_pressure(data, val, val2); 141a2d8be68SPeter Meerwald if (ret < 0) 142a2d8be68SPeter Meerwald return ret; 143a2d8be68SPeter Meerwald return IIO_VAL_INT_PLUS_MICRO; 144a2d8be68SPeter Meerwald case IIO_TEMP: 145a2d8be68SPeter Meerwald ret = t5403_comp_temp(data, val); 146a2d8be68SPeter Meerwald if (ret < 0) 147a2d8be68SPeter Meerwald return ret; 148a2d8be68SPeter Meerwald return IIO_VAL_INT; 149a2d8be68SPeter Meerwald default: 150a2d8be68SPeter Meerwald return -EINVAL; 151a2d8be68SPeter Meerwald } 152a2d8be68SPeter Meerwald case IIO_CHAN_INFO_INT_TIME: 153a2d8be68SPeter Meerwald *val = 0; 154a2d8be68SPeter Meerwald *val2 = t5403_pressure_conv_ms[data->mode] * 1000; 155a2d8be68SPeter Meerwald return IIO_VAL_INT_PLUS_MICRO; 156a2d8be68SPeter Meerwald default: 157a2d8be68SPeter Meerwald return -EINVAL; 158a2d8be68SPeter Meerwald } 159a2d8be68SPeter Meerwald } 160a2d8be68SPeter Meerwald 161a2d8be68SPeter Meerwald static int t5403_write_raw(struct iio_dev *indio_dev, 162a2d8be68SPeter Meerwald struct iio_chan_spec const *chan, 163a2d8be68SPeter Meerwald int val, int val2, long mask) 164a2d8be68SPeter Meerwald { 165a2d8be68SPeter Meerwald struct t5403_data *data = iio_priv(indio_dev); 166a2d8be68SPeter Meerwald int i; 167a2d8be68SPeter Meerwald 168a2d8be68SPeter Meerwald switch (mask) { 169a2d8be68SPeter Meerwald case IIO_CHAN_INFO_INT_TIME: 170a2d8be68SPeter Meerwald if (val != 0) 171a2d8be68SPeter Meerwald return -EINVAL; 172a2d8be68SPeter Meerwald for (i = 0; i < ARRAY_SIZE(t5403_pressure_conv_ms); i++) 173a2d8be68SPeter Meerwald if (val2 == t5403_pressure_conv_ms[i] * 1000) { 174a2d8be68SPeter Meerwald mutex_lock(&data->lock); 175a2d8be68SPeter Meerwald data->mode = i; 176a2d8be68SPeter Meerwald mutex_unlock(&data->lock); 177a2d8be68SPeter Meerwald return 0; 178a2d8be68SPeter Meerwald } 179a2d8be68SPeter Meerwald return -EINVAL; 180a2d8be68SPeter Meerwald default: 181a2d8be68SPeter Meerwald return -EINVAL; 182a2d8be68SPeter Meerwald } 183a2d8be68SPeter Meerwald } 184a2d8be68SPeter Meerwald 185a2d8be68SPeter Meerwald static const struct iio_chan_spec t5403_channels[] = { 186a2d8be68SPeter Meerwald { 187a2d8be68SPeter Meerwald .type = IIO_PRESSURE, 188a2d8be68SPeter Meerwald .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | 189a2d8be68SPeter Meerwald BIT(IIO_CHAN_INFO_INT_TIME), 190a2d8be68SPeter Meerwald }, 191a2d8be68SPeter Meerwald { 192a2d8be68SPeter Meerwald .type = IIO_TEMP, 193a2d8be68SPeter Meerwald .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), 194a2d8be68SPeter Meerwald }, 195a2d8be68SPeter Meerwald }; 196a2d8be68SPeter Meerwald 197a2d8be68SPeter Meerwald static IIO_CONST_ATTR_INT_TIME_AVAIL("0.002 0.008 0.016 0.066"); 198a2d8be68SPeter Meerwald 199a2d8be68SPeter Meerwald static struct attribute *t5403_attributes[] = { 200a2d8be68SPeter Meerwald &iio_const_attr_integration_time_available.dev_attr.attr, 201a2d8be68SPeter Meerwald NULL 202a2d8be68SPeter Meerwald }; 203a2d8be68SPeter Meerwald 204a2d8be68SPeter Meerwald static const struct attribute_group t5403_attribute_group = { 205a2d8be68SPeter Meerwald .attrs = t5403_attributes, 206a2d8be68SPeter Meerwald }; 207a2d8be68SPeter Meerwald 208a2d8be68SPeter Meerwald static const struct iio_info t5403_info = { 209a2d8be68SPeter Meerwald .read_raw = &t5403_read_raw, 210a2d8be68SPeter Meerwald .write_raw = &t5403_write_raw, 211a2d8be68SPeter Meerwald .attrs = &t5403_attribute_group, 212a2d8be68SPeter Meerwald .driver_module = THIS_MODULE, 213a2d8be68SPeter Meerwald }; 214a2d8be68SPeter Meerwald 215a2d8be68SPeter Meerwald static int t5403_probe(struct i2c_client *client, 216a2d8be68SPeter Meerwald const struct i2c_device_id *id) 217a2d8be68SPeter Meerwald { 218a2d8be68SPeter Meerwald struct t5403_data *data; 219a2d8be68SPeter Meerwald struct iio_dev *indio_dev; 220a2d8be68SPeter Meerwald int ret; 221a2d8be68SPeter Meerwald 222a2d8be68SPeter Meerwald if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA | 223a2d8be68SPeter Meerwald I2C_FUNC_SMBUS_I2C_BLOCK)) 224*f8d9d3b4SMatt Ranostay return -EOPNOTSUPP; 225a2d8be68SPeter Meerwald 226a2d8be68SPeter Meerwald ret = i2c_smbus_read_byte_data(client, T5403_SLAVE_ADDR); 227a2d8be68SPeter Meerwald if (ret < 0) 228a2d8be68SPeter Meerwald return ret; 229a2d8be68SPeter Meerwald if ((ret & T5403_I2C_MASK) != T5403_I2C_ADDR) 230a2d8be68SPeter Meerwald return -ENODEV; 231a2d8be68SPeter Meerwald 232a2d8be68SPeter Meerwald indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 233a2d8be68SPeter Meerwald if (!indio_dev) 234a2d8be68SPeter Meerwald return -ENOMEM; 235a2d8be68SPeter Meerwald 236a2d8be68SPeter Meerwald data = iio_priv(indio_dev); 237a2d8be68SPeter Meerwald data->client = client; 238a2d8be68SPeter Meerwald mutex_init(&data->lock); 239a2d8be68SPeter Meerwald 240a2d8be68SPeter Meerwald i2c_set_clientdata(client, indio_dev); 241a2d8be68SPeter Meerwald indio_dev->info = &t5403_info; 242a2d8be68SPeter Meerwald indio_dev->name = id->name; 243a2d8be68SPeter Meerwald indio_dev->dev.parent = &client->dev; 244a2d8be68SPeter Meerwald indio_dev->modes = INDIO_DIRECT_MODE; 245a2d8be68SPeter Meerwald indio_dev->channels = t5403_channels; 246a2d8be68SPeter Meerwald indio_dev->num_channels = ARRAY_SIZE(t5403_channels); 247a2d8be68SPeter Meerwald 248a2d8be68SPeter Meerwald data->mode = T5403_MODE_STANDARD; 249a2d8be68SPeter Meerwald 250a2d8be68SPeter Meerwald ret = i2c_smbus_read_i2c_block_data(data->client, T5403_CALIB_DATA, 251a2d8be68SPeter Meerwald sizeof(data->c), (u8 *) data->c); 252a2d8be68SPeter Meerwald if (ret < 0) 253a2d8be68SPeter Meerwald return ret; 254a2d8be68SPeter Meerwald 255a2d8be68SPeter Meerwald return devm_iio_device_register(&client->dev, indio_dev); 256a2d8be68SPeter Meerwald } 257a2d8be68SPeter Meerwald 258a2d8be68SPeter Meerwald static const struct i2c_device_id t5403_id[] = { 259a2d8be68SPeter Meerwald { "t5403", 0 }, 260a2d8be68SPeter Meerwald { } 261a2d8be68SPeter Meerwald }; 262a2d8be68SPeter Meerwald MODULE_DEVICE_TABLE(i2c, t5403_id); 263a2d8be68SPeter Meerwald 264a2d8be68SPeter Meerwald static struct i2c_driver t5403_driver = { 265a2d8be68SPeter Meerwald .driver = { 266a2d8be68SPeter Meerwald .name = "t5403", 267a2d8be68SPeter Meerwald }, 268a2d8be68SPeter Meerwald .probe = t5403_probe, 269a2d8be68SPeter Meerwald .id_table = t5403_id, 270a2d8be68SPeter Meerwald }; 271a2d8be68SPeter Meerwald module_i2c_driver(t5403_driver); 272a2d8be68SPeter Meerwald 273a2d8be68SPeter Meerwald MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>"); 274a2d8be68SPeter Meerwald MODULE_DESCRIPTION("EPCOS T5403 pressure/temperature sensor driver"); 275a2d8be68SPeter Meerwald MODULE_LICENSE("GPL"); 276