aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorPeter Meerwald <pmeerw@pmeerw.net>2014-02-06 15:44:00 -0500
committerJonathan Cameron <jic23@kernel.org>2014-06-14 08:15:30 -0400
commita2d8be6823017ccdde8db8b0f4fbe6a29580dd40 (patch)
tree1da722c1b5c38d0670a86c9081d992f62595cd04 /drivers
parent6c0690ecb682c94b958e0328c46bfcfd95c7698c (diff)
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/iio/pressure/Kconfig10
-rw-r--r--drivers/iio/pressure/Makefile1
-rw-r--r--drivers/iio/pressure/t5403.c275
3 files changed, 286 insertions, 0 deletions
diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig
index ffac8ac1efca..15afbc919521 100644
--- a/drivers/iio/pressure/Kconfig
+++ b/drivers/iio/pressure/Kconfig
@@ -70,4 +70,14 @@ config IIO_ST_PRESS_SPI
70 depends on IIO_ST_PRESS 70 depends on IIO_ST_PRESS
71 depends on IIO_ST_SENSORS_SPI 71 depends on IIO_ST_SENSORS_SPI
72 72
73config 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
73endmenu 83endmenu
diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile
index c53d2500737a..90a37e85cf21 100644
--- a/drivers/iio/pressure/Makefile
+++ b/drivers/iio/pressure/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_MPL3115) += mpl3115.o
9obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o 9obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o
10st_pressure-y := st_pressure_core.o 10st_pressure-y := st_pressure_core.o
11st_pressure-$(CONFIG_IIO_BUFFER) += st_pressure_buffer.o 11st_pressure-$(CONFIG_IIO_BUFFER) += st_pressure_buffer.o
12obj-$(CONFIG_T5403) += t5403.o
12 13
13obj-$(CONFIG_IIO_ST_PRESS_I2C) += st_pressure_i2c.o 14obj-$(CONFIG_IIO_ST_PRESS_I2C) += st_pressure_i2c.o
14obj-$(CONFIG_IIO_ST_PRESS_SPI) += st_pressure_spi.o 15obj-$(CONFIG_IIO_ST_PRESS_SPI) += st_pressure_spi.o
diff --git a/drivers/iio/pressure/t5403.c b/drivers/iio/pressure/t5403.c
new file mode 100644
index 000000000000..e11cd3938d67
--- /dev/null
+++ b/drivers/iio/pressure/t5403.c
@@ -0,0 +1,275 @@
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
39static const int t5403_pressure_conv_ms[] = {2, 8, 16, 66};
40
41struct 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
51static 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
68static 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
104done:
105 mutex_unlock(&data->lock);
106 return ret;
107}
108
109static 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
124done:
125 mutex_unlock(&data->lock);
126 return ret;
127}
128
129static 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
161static 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
185static 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
197static IIO_CONST_ATTR_INT_TIME_AVAIL("0.002 0.008 0.016 0.066");
198
199static struct attribute *t5403_attributes[] = {
200 &iio_const_attr_integration_time_available.dev_attr.attr,
201 NULL
202};
203
204static const struct attribute_group t5403_attribute_group = {
205 .attrs = t5403_attributes,
206};
207
208static 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
215static 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
258static const struct i2c_device_id t5403_id[] = {
259 { "t5403", 0 },
260 { }
261};
262MODULE_DEVICE_TABLE(i2c, t5403_id);
263
264static struct i2c_driver t5403_driver = {
265 .driver = {
266 .name = "t5403",
267 },
268 .probe = t5403_probe,
269 .id_table = t5403_id,
270};
271module_i2c_driver(t5403_driver);
272
273MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
274MODULE_DESCRIPTION("EPCOS T5403 pressure/temperature sensor driver");
275MODULE_LICENSE("GPL");