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
t5403_read(struct t5403_data * data,bool pressure)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
t5403_comp_pressure(struct t5403_data * data,int * val,int * val2)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
t5403_comp_temp(struct t5403_data * data,int * val)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
t5403_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)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
t5403_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)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
t5403_probe(struct i2c_client * client)211aa9b3321SUwe Kleine-König static int t5403_probe(struct i2c_client *client)
212a2d8be68SPeter Meerwald {
213aa9b3321SUwe 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*7cf15f42SUwe Kleine-König .probe = 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