Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

iio: Add t5403 barometric pressure sensor driver

16-bit pressure and temperature sensor

the chip can do I2C and SPI, only the I2C interface is supported
by the driver at the moment

datasheet: http://www.epcos.com/inf/57/ds/T5400.pdf
application note: http://www.epcos.com/blob/993154/download/1/t5403-applicationnote.pdf

an out-of-tree driver targetting the input subsystem is at
https://github.com/unixphere/t5400, it was rejected here:
http://comments.gmane.org/gmane.linux.kernel.input/28107

v2: (thanks Hartmut Knaack)
* fix MODE_HIGH, equals 2
* check INT_TIME mask in write_raw()

Signed-off-by: Peter Meerwald <pmeerw@pmeerw.net>
Cc: Stefan Nilsson <stefan.nilsson@unixphere.com>
Reviewed-by: Hartmut Knaack <knaack.h@gmx.de>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>

authored by

Peter Meerwald and committed by
Jonathan Cameron
a2d8be68 6c0690ec

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