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