1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * mpl3115.c - Support for Freescale MPL3115A2 pressure/temperature sensor |
4 | * |
5 | * Copyright (c) 2013 Peter Meerwald <pmeerw@pmeerw.net> |
6 | * |
7 | * (7-bit I2C slave address 0x60) |
8 | * |
9 | * TODO: FIFO buffer, altimeter mode, oversampling, continuous mode, |
10 | * interrupts, user offset correction, raw mode |
11 | */ |
12 | |
13 | #include <linux/module.h> |
14 | #include <linux/i2c.h> |
15 | #include <linux/iio/iio.h> |
16 | #include <linux/iio/sysfs.h> |
17 | #include <linux/iio/trigger_consumer.h> |
18 | #include <linux/iio/buffer.h> |
19 | #include <linux/iio/triggered_buffer.h> |
20 | #include <linux/delay.h> |
21 | |
22 | #define MPL3115_STATUS 0x00 |
23 | #define MPL3115_OUT_PRESS 0x01 /* MSB first, 20 bit */ |
24 | #define MPL3115_OUT_TEMP 0x04 /* MSB first, 12 bit */ |
25 | #define MPL3115_WHO_AM_I 0x0c |
26 | #define MPL3115_CTRL_REG1 0x26 |
27 | |
28 | #define MPL3115_DEVICE_ID 0xc4 |
29 | |
30 | #define MPL3115_STATUS_PRESS_RDY BIT(2) |
31 | #define MPL3115_STATUS_TEMP_RDY BIT(1) |
32 | |
33 | #define MPL3115_CTRL_RESET BIT(2) /* software reset */ |
34 | #define MPL3115_CTRL_OST BIT(1) /* initiate measurement */ |
35 | #define MPL3115_CTRL_ACTIVE BIT(0) /* continuous measurement */ |
36 | #define MPL3115_CTRL_OS_258MS (BIT(5) | BIT(4)) /* 64x oversampling */ |
37 | |
38 | struct mpl3115_data { |
39 | struct i2c_client *client; |
40 | struct mutex lock; |
41 | u8 ctrl_reg1; |
42 | }; |
43 | |
44 | static int mpl3115_request(struct mpl3115_data *data) |
45 | { |
46 | int ret, tries = 15; |
47 | |
48 | /* trigger measurement */ |
49 | ret = i2c_smbus_write_byte_data(client: data->client, MPL3115_CTRL_REG1, |
50 | value: data->ctrl_reg1 | MPL3115_CTRL_OST); |
51 | if (ret < 0) |
52 | return ret; |
53 | |
54 | while (tries-- > 0) { |
55 | ret = i2c_smbus_read_byte_data(client: data->client, MPL3115_CTRL_REG1); |
56 | if (ret < 0) |
57 | return ret; |
58 | /* wait for data ready, i.e. OST cleared */ |
59 | if (!(ret & MPL3115_CTRL_OST)) |
60 | break; |
61 | msleep(msecs: 20); |
62 | } |
63 | |
64 | if (tries < 0) { |
65 | dev_err(&data->client->dev, "data not ready\n" ); |
66 | return -EIO; |
67 | } |
68 | |
69 | return 0; |
70 | } |
71 | |
72 | static int mpl3115_read_raw(struct iio_dev *indio_dev, |
73 | struct iio_chan_spec const *chan, |
74 | int *val, int *val2, long mask) |
75 | { |
76 | struct mpl3115_data *data = iio_priv(indio_dev); |
77 | int ret; |
78 | |
79 | switch (mask) { |
80 | case IIO_CHAN_INFO_RAW: |
81 | ret = iio_device_claim_direct_mode(indio_dev); |
82 | if (ret) |
83 | return ret; |
84 | |
85 | switch (chan->type) { |
86 | case IIO_PRESSURE: { /* in 0.25 pascal / LSB */ |
87 | __be32 tmp = 0; |
88 | |
89 | mutex_lock(&data->lock); |
90 | ret = mpl3115_request(data); |
91 | if (ret < 0) { |
92 | mutex_unlock(lock: &data->lock); |
93 | break; |
94 | } |
95 | ret = i2c_smbus_read_i2c_block_data(client: data->client, |
96 | MPL3115_OUT_PRESS, length: 3, values: (u8 *) &tmp); |
97 | mutex_unlock(lock: &data->lock); |
98 | if (ret < 0) |
99 | break; |
100 | *val = be32_to_cpu(tmp) >> chan->scan_type.shift; |
101 | ret = IIO_VAL_INT; |
102 | break; |
103 | } |
104 | case IIO_TEMP: { /* in 0.0625 celsius / LSB */ |
105 | __be16 tmp; |
106 | |
107 | mutex_lock(&data->lock); |
108 | ret = mpl3115_request(data); |
109 | if (ret < 0) { |
110 | mutex_unlock(lock: &data->lock); |
111 | break; |
112 | } |
113 | ret = i2c_smbus_read_i2c_block_data(client: data->client, |
114 | MPL3115_OUT_TEMP, length: 2, values: (u8 *) &tmp); |
115 | mutex_unlock(lock: &data->lock); |
116 | if (ret < 0) |
117 | break; |
118 | *val = sign_extend32(be16_to_cpu(tmp) >> chan->scan_type.shift, |
119 | index: chan->scan_type.realbits - 1); |
120 | ret = IIO_VAL_INT; |
121 | break; |
122 | } |
123 | default: |
124 | ret = -EINVAL; |
125 | break; |
126 | } |
127 | |
128 | iio_device_release_direct_mode(indio_dev); |
129 | return ret; |
130 | |
131 | case IIO_CHAN_INFO_SCALE: |
132 | switch (chan->type) { |
133 | case IIO_PRESSURE: |
134 | *val = 0; |
135 | *val2 = 250; /* want kilopascal */ |
136 | return IIO_VAL_INT_PLUS_MICRO; |
137 | case IIO_TEMP: |
138 | *val = 0; |
139 | *val2 = 62500; |
140 | return IIO_VAL_INT_PLUS_MICRO; |
141 | default: |
142 | return -EINVAL; |
143 | } |
144 | } |
145 | return -EINVAL; |
146 | } |
147 | |
148 | static irqreturn_t mpl3115_trigger_handler(int irq, void *p) |
149 | { |
150 | struct iio_poll_func *pf = p; |
151 | struct iio_dev *indio_dev = pf->indio_dev; |
152 | struct mpl3115_data *data = iio_priv(indio_dev); |
153 | /* |
154 | * 32-bit channel + 16-bit channel + padding + ts |
155 | * Note that it is possible for only one of the first 2 |
156 | * channels to be enabled. If that happens, the first element |
157 | * of the buffer may be either 16 or 32-bits. As such we cannot |
158 | * use a simple structure definition to express this data layout. |
159 | */ |
160 | u8 buffer[16] __aligned(8); |
161 | int ret, pos = 0; |
162 | |
163 | mutex_lock(&data->lock); |
164 | ret = mpl3115_request(data); |
165 | if (ret < 0) { |
166 | mutex_unlock(lock: &data->lock); |
167 | goto done; |
168 | } |
169 | |
170 | memset(buffer, 0, sizeof(buffer)); |
171 | if (test_bit(0, indio_dev->active_scan_mask)) { |
172 | ret = i2c_smbus_read_i2c_block_data(client: data->client, |
173 | MPL3115_OUT_PRESS, length: 3, values: &buffer[pos]); |
174 | if (ret < 0) { |
175 | mutex_unlock(lock: &data->lock); |
176 | goto done; |
177 | } |
178 | pos += 4; |
179 | } |
180 | |
181 | if (test_bit(1, indio_dev->active_scan_mask)) { |
182 | ret = i2c_smbus_read_i2c_block_data(client: data->client, |
183 | MPL3115_OUT_TEMP, length: 2, values: &buffer[pos]); |
184 | if (ret < 0) { |
185 | mutex_unlock(lock: &data->lock); |
186 | goto done; |
187 | } |
188 | } |
189 | mutex_unlock(lock: &data->lock); |
190 | |
191 | iio_push_to_buffers_with_timestamp(indio_dev, data: buffer, |
192 | timestamp: iio_get_time_ns(indio_dev)); |
193 | |
194 | done: |
195 | iio_trigger_notify_done(trig: indio_dev->trig); |
196 | return IRQ_HANDLED; |
197 | } |
198 | |
199 | static const struct iio_chan_spec mpl3115_channels[] = { |
200 | { |
201 | .type = IIO_PRESSURE, |
202 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), |
203 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), |
204 | .scan_index = 0, |
205 | .scan_type = { |
206 | .sign = 'u', |
207 | .realbits = 20, |
208 | .storagebits = 32, |
209 | .shift = 12, |
210 | .endianness = IIO_BE, |
211 | } |
212 | }, |
213 | { |
214 | .type = IIO_TEMP, |
215 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), |
216 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), |
217 | .scan_index = 1, |
218 | .scan_type = { |
219 | .sign = 's', |
220 | .realbits = 12, |
221 | .storagebits = 16, |
222 | .shift = 4, |
223 | .endianness = IIO_BE, |
224 | } |
225 | }, |
226 | IIO_CHAN_SOFT_TIMESTAMP(2), |
227 | }; |
228 | |
229 | static const struct iio_info mpl3115_info = { |
230 | .read_raw = &mpl3115_read_raw, |
231 | }; |
232 | |
233 | static int mpl3115_probe(struct i2c_client *client) |
234 | { |
235 | const struct i2c_device_id *id = i2c_client_get_device_id(client); |
236 | struct mpl3115_data *data; |
237 | struct iio_dev *indio_dev; |
238 | int ret; |
239 | |
240 | ret = i2c_smbus_read_byte_data(client, MPL3115_WHO_AM_I); |
241 | if (ret < 0) |
242 | return ret; |
243 | if (ret != MPL3115_DEVICE_ID) |
244 | return -ENODEV; |
245 | |
246 | indio_dev = devm_iio_device_alloc(parent: &client->dev, sizeof_priv: sizeof(*data)); |
247 | if (!indio_dev) |
248 | return -ENOMEM; |
249 | |
250 | data = iio_priv(indio_dev); |
251 | data->client = client; |
252 | mutex_init(&data->lock); |
253 | |
254 | i2c_set_clientdata(client, data: indio_dev); |
255 | indio_dev->info = &mpl3115_info; |
256 | indio_dev->name = id->name; |
257 | indio_dev->modes = INDIO_DIRECT_MODE; |
258 | indio_dev->channels = mpl3115_channels; |
259 | indio_dev->num_channels = ARRAY_SIZE(mpl3115_channels); |
260 | |
261 | /* software reset, I2C transfer is aborted (fails) */ |
262 | i2c_smbus_write_byte_data(client, MPL3115_CTRL_REG1, |
263 | MPL3115_CTRL_RESET); |
264 | msleep(msecs: 50); |
265 | |
266 | data->ctrl_reg1 = MPL3115_CTRL_OS_258MS; |
267 | ret = i2c_smbus_write_byte_data(client, MPL3115_CTRL_REG1, |
268 | value: data->ctrl_reg1); |
269 | if (ret < 0) |
270 | return ret; |
271 | |
272 | ret = iio_triggered_buffer_setup(indio_dev, NULL, |
273 | mpl3115_trigger_handler, NULL); |
274 | if (ret < 0) |
275 | return ret; |
276 | |
277 | ret = iio_device_register(indio_dev); |
278 | if (ret < 0) |
279 | goto buffer_cleanup; |
280 | return 0; |
281 | |
282 | buffer_cleanup: |
283 | iio_triggered_buffer_cleanup(indio_dev); |
284 | return ret; |
285 | } |
286 | |
287 | static int mpl3115_standby(struct mpl3115_data *data) |
288 | { |
289 | return i2c_smbus_write_byte_data(client: data->client, MPL3115_CTRL_REG1, |
290 | value: data->ctrl_reg1 & ~MPL3115_CTRL_ACTIVE); |
291 | } |
292 | |
293 | static void mpl3115_remove(struct i2c_client *client) |
294 | { |
295 | struct iio_dev *indio_dev = i2c_get_clientdata(client); |
296 | |
297 | iio_device_unregister(indio_dev); |
298 | iio_triggered_buffer_cleanup(indio_dev); |
299 | mpl3115_standby(data: iio_priv(indio_dev)); |
300 | } |
301 | |
302 | static int mpl3115_suspend(struct device *dev) |
303 | { |
304 | return mpl3115_standby(data: iio_priv(indio_dev: i2c_get_clientdata( |
305 | to_i2c_client(dev)))); |
306 | } |
307 | |
308 | static int mpl3115_resume(struct device *dev) |
309 | { |
310 | struct mpl3115_data *data = iio_priv(indio_dev: i2c_get_clientdata( |
311 | to_i2c_client(dev))); |
312 | |
313 | return i2c_smbus_write_byte_data(client: data->client, MPL3115_CTRL_REG1, |
314 | value: data->ctrl_reg1); |
315 | } |
316 | |
317 | static DEFINE_SIMPLE_DEV_PM_OPS(mpl3115_pm_ops, mpl3115_suspend, |
318 | mpl3115_resume); |
319 | |
320 | static const struct i2c_device_id mpl3115_id[] = { |
321 | { "mpl3115" , 0 }, |
322 | { } |
323 | }; |
324 | MODULE_DEVICE_TABLE(i2c, mpl3115_id); |
325 | |
326 | static const struct of_device_id mpl3115_of_match[] = { |
327 | { .compatible = "fsl,mpl3115" }, |
328 | { } |
329 | }; |
330 | MODULE_DEVICE_TABLE(of, mpl3115_of_match); |
331 | |
332 | static struct i2c_driver mpl3115_driver = { |
333 | .driver = { |
334 | .name = "mpl3115" , |
335 | .of_match_table = mpl3115_of_match, |
336 | .pm = pm_sleep_ptr(&mpl3115_pm_ops), |
337 | }, |
338 | .probe = mpl3115_probe, |
339 | .remove = mpl3115_remove, |
340 | .id_table = mpl3115_id, |
341 | }; |
342 | module_i2c_driver(mpl3115_driver); |
343 | |
344 | MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>" ); |
345 | MODULE_DESCRIPTION("Freescale MPL3115 pressure/temperature driver" ); |
346 | MODULE_LICENSE("GPL" ); |
347 | |