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