]>
Commit | Line | Data |
---|---|---|
36edc939 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
cc26ad45 PM |
2 | /* |
3 | * mpl3115.c - Support for Freescale MPL3115A2 pressure/temperature sensor | |
4 | * | |
5 | * Copyright (c) 2013 Peter Meerwald <pmeerw@pmeerw.net> | |
6 | * | |
cc26ad45 PM |
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(data->client, MPL3115_CTRL_REG1, | |
50 | 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(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(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); | |
4a2bbdb4 | 77 | __be32 tmp = 0; |
cc26ad45 PM |
78 | int ret; |
79 | ||
80 | switch (mask) { | |
81 | case IIO_CHAN_INFO_RAW: | |
ac139805 AS |
82 | ret = iio_device_claim_direct_mode(indio_dev); |
83 | if (ret) | |
84 | return ret; | |
cc26ad45 PM |
85 | |
86 | switch (chan->type) { | |
87 | case IIO_PRESSURE: /* in 0.25 pascal / LSB */ | |
88 | mutex_lock(&data->lock); | |
89 | ret = mpl3115_request(data); | |
90 | if (ret < 0) { | |
91 | mutex_unlock(&data->lock); | |
ac139805 | 92 | break; |
cc26ad45 PM |
93 | } |
94 | ret = i2c_smbus_read_i2c_block_data(data->client, | |
95 | MPL3115_OUT_PRESS, 3, (u8 *) &tmp); | |
96 | mutex_unlock(&data->lock); | |
97 | if (ret < 0) | |
ac139805 | 98 | break; |
d29f5929 | 99 | *val = be32_to_cpu(tmp) >> 12; |
ac139805 AS |
100 | ret = IIO_VAL_INT; |
101 | break; | |
cc26ad45 PM |
102 | case IIO_TEMP: /* in 0.0625 celsius / LSB */ |
103 | mutex_lock(&data->lock); | |
104 | ret = mpl3115_request(data); | |
105 | if (ret < 0) { | |
106 | mutex_unlock(&data->lock); | |
ac139805 | 107 | break; |
cc26ad45 PM |
108 | } |
109 | ret = i2c_smbus_read_i2c_block_data(data->client, | |
110 | MPL3115_OUT_TEMP, 2, (u8 *) &tmp); | |
111 | mutex_unlock(&data->lock); | |
112 | if (ret < 0) | |
ac139805 | 113 | break; |
d29f5929 | 114 | *val = sign_extend32(be32_to_cpu(tmp) >> 20, 11); |
ac139805 AS |
115 | ret = IIO_VAL_INT; |
116 | break; | |
cc26ad45 | 117 | default: |
ac139805 AS |
118 | ret = -EINVAL; |
119 | break; | |
cc26ad45 | 120 | } |
ac139805 AS |
121 | |
122 | iio_device_release_direct_mode(indio_dev); | |
123 | return ret; | |
124 | ||
cc26ad45 PM |
125 | case IIO_CHAN_INFO_SCALE: |
126 | switch (chan->type) { | |
127 | case IIO_PRESSURE: | |
128 | *val = 0; | |
129 | *val2 = 250; /* want kilopascal */ | |
130 | return IIO_VAL_INT_PLUS_MICRO; | |
131 | case IIO_TEMP: | |
132 | *val = 0; | |
133 | *val2 = 62500; | |
134 | return IIO_VAL_INT_PLUS_MICRO; | |
135 | default: | |
136 | return -EINVAL; | |
137 | } | |
138 | } | |
139 | return -EINVAL; | |
140 | } | |
141 | ||
142 | static irqreturn_t mpl3115_trigger_handler(int irq, void *p) | |
143 | { | |
144 | struct iio_poll_func *pf = p; | |
145 | struct iio_dev *indio_dev = pf->indio_dev; | |
146 | struct mpl3115_data *data = iio_priv(indio_dev); | |
147 | u8 buffer[16]; /* 32-bit channel + 16-bit channel + padding + ts */ | |
148 | int ret, pos = 0; | |
149 | ||
150 | mutex_lock(&data->lock); | |
151 | ret = mpl3115_request(data); | |
152 | if (ret < 0) { | |
153 | mutex_unlock(&data->lock); | |
154 | goto done; | |
155 | } | |
156 | ||
157 | memset(buffer, 0, sizeof(buffer)); | |
158 | if (test_bit(0, indio_dev->active_scan_mask)) { | |
159 | ret = i2c_smbus_read_i2c_block_data(data->client, | |
160 | MPL3115_OUT_PRESS, 3, &buffer[pos]); | |
161 | if (ret < 0) { | |
162 | mutex_unlock(&data->lock); | |
163 | goto done; | |
164 | } | |
165 | pos += 4; | |
166 | } | |
167 | ||
168 | if (test_bit(1, indio_dev->active_scan_mask)) { | |
169 | ret = i2c_smbus_read_i2c_block_data(data->client, | |
170 | MPL3115_OUT_TEMP, 2, &buffer[pos]); | |
171 | if (ret < 0) { | |
172 | mutex_unlock(&data->lock); | |
173 | goto done; | |
174 | } | |
175 | } | |
176 | mutex_unlock(&data->lock); | |
177 | ||
178 | iio_push_to_buffers_with_timestamp(indio_dev, buffer, | |
bc2b7dab | 179 | iio_get_time_ns(indio_dev)); |
cc26ad45 PM |
180 | |
181 | done: | |
182 | iio_trigger_notify_done(indio_dev->trig); | |
183 | return IRQ_HANDLED; | |
184 | } | |
185 | ||
186 | static const struct iio_chan_spec mpl3115_channels[] = { | |
187 | { | |
188 | .type = IIO_PRESSURE, | |
189 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), | |
9cf6cdba | 190 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), |
cc26ad45 PM |
191 | .scan_index = 0, |
192 | .scan_type = { | |
d29f5929 | 193 | .sign = 'u', |
cc26ad45 PM |
194 | .realbits = 20, |
195 | .storagebits = 32, | |
196 | .shift = 12, | |
197 | .endianness = IIO_BE, | |
198 | } | |
199 | }, | |
200 | { | |
201 | .type = IIO_TEMP, | |
202 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), | |
9cf6cdba | 203 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), |
cc26ad45 PM |
204 | .scan_index = 1, |
205 | .scan_type = { | |
206 | .sign = 's', | |
207 | .realbits = 12, | |
208 | .storagebits = 16, | |
209 | .shift = 4, | |
210 | .endianness = IIO_BE, | |
211 | } | |
212 | }, | |
213 | IIO_CHAN_SOFT_TIMESTAMP(2), | |
214 | }; | |
215 | ||
216 | static const struct iio_info mpl3115_info = { | |
217 | .read_raw = &mpl3115_read_raw, | |
cc26ad45 PM |
218 | }; |
219 | ||
220 | static int mpl3115_probe(struct i2c_client *client, | |
221 | const struct i2c_device_id *id) | |
222 | { | |
223 | struct mpl3115_data *data; | |
224 | struct iio_dev *indio_dev; | |
225 | int ret; | |
226 | ||
227 | ret = i2c_smbus_read_byte_data(client, MPL3115_WHO_AM_I); | |
228 | if (ret < 0) | |
229 | return ret; | |
230 | if (ret != MPL3115_DEVICE_ID) | |
231 | return -ENODEV; | |
232 | ||
233 | indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); | |
234 | if (!indio_dev) | |
235 | return -ENOMEM; | |
236 | ||
237 | data = iio_priv(indio_dev); | |
238 | data->client = client; | |
239 | mutex_init(&data->lock); | |
240 | ||
241 | i2c_set_clientdata(client, indio_dev); | |
242 | indio_dev->info = &mpl3115_info; | |
243 | indio_dev->name = id->name; | |
244 | indio_dev->dev.parent = &client->dev; | |
245 | indio_dev->modes = INDIO_DIRECT_MODE; | |
246 | indio_dev->channels = mpl3115_channels; | |
247 | indio_dev->num_channels = ARRAY_SIZE(mpl3115_channels); | |
248 | ||
249 | /* software reset, I2C transfer is aborted (fails) */ | |
250 | i2c_smbus_write_byte_data(client, MPL3115_CTRL_REG1, | |
251 | MPL3115_CTRL_RESET); | |
252 | msleep(50); | |
253 | ||
254 | data->ctrl_reg1 = MPL3115_CTRL_OS_258MS; | |
255 | ret = i2c_smbus_write_byte_data(client, MPL3115_CTRL_REG1, | |
256 | data->ctrl_reg1); | |
257 | if (ret < 0) | |
258 | return ret; | |
259 | ||
260 | ret = iio_triggered_buffer_setup(indio_dev, NULL, | |
261 | mpl3115_trigger_handler, NULL); | |
262 | if (ret < 0) | |
263 | return ret; | |
264 | ||
265 | ret = iio_device_register(indio_dev); | |
266 | if (ret < 0) | |
267 | goto buffer_cleanup; | |
268 | return 0; | |
269 | ||
270 | buffer_cleanup: | |
271 | iio_triggered_buffer_cleanup(indio_dev); | |
272 | return ret; | |
273 | } | |
274 | ||
275 | static int mpl3115_standby(struct mpl3115_data *data) | |
276 | { | |
277 | return i2c_smbus_write_byte_data(data->client, MPL3115_CTRL_REG1, | |
278 | data->ctrl_reg1 & ~MPL3115_CTRL_ACTIVE); | |
279 | } | |
280 | ||
281 | static int mpl3115_remove(struct i2c_client *client) | |
282 | { | |
283 | struct iio_dev *indio_dev = i2c_get_clientdata(client); | |
284 | ||
285 | iio_device_unregister(indio_dev); | |
286 | iio_triggered_buffer_cleanup(indio_dev); | |
287 | mpl3115_standby(iio_priv(indio_dev)); | |
288 | ||
289 | return 0; | |
290 | } | |
291 | ||
292 | #ifdef CONFIG_PM_SLEEP | |
293 | static int mpl3115_suspend(struct device *dev) | |
294 | { | |
295 | return mpl3115_standby(iio_priv(i2c_get_clientdata( | |
296 | to_i2c_client(dev)))); | |
297 | } | |
298 | ||
299 | static int mpl3115_resume(struct device *dev) | |
300 | { | |
301 | struct mpl3115_data *data = iio_priv(i2c_get_clientdata( | |
302 | to_i2c_client(dev))); | |
303 | ||
304 | return i2c_smbus_write_byte_data(data->client, MPL3115_CTRL_REG1, | |
305 | data->ctrl_reg1); | |
306 | } | |
307 | ||
308 | static SIMPLE_DEV_PM_OPS(mpl3115_pm_ops, mpl3115_suspend, mpl3115_resume); | |
309 | #define MPL3115_PM_OPS (&mpl3115_pm_ops) | |
310 | #else | |
311 | #define MPL3115_PM_OPS NULL | |
312 | #endif | |
313 | ||
314 | static const struct i2c_device_id mpl3115_id[] = { | |
315 | { "mpl3115", 0 }, | |
316 | { } | |
317 | }; | |
318 | MODULE_DEVICE_TABLE(i2c, mpl3115_id); | |
319 | ||
77496c07 JMC |
320 | static const struct of_device_id mpl3115_of_match[] = { |
321 | { .compatible = "fsl,mpl3115" }, | |
322 | { } | |
323 | }; | |
324 | MODULE_DEVICE_TABLE(of, mpl3115_of_match); | |
325 | ||
cc26ad45 PM |
326 | static struct i2c_driver mpl3115_driver = { |
327 | .driver = { | |
328 | .name = "mpl3115", | |
77496c07 | 329 | .of_match_table = mpl3115_of_match, |
cc26ad45 PM |
330 | .pm = MPL3115_PM_OPS, |
331 | }, | |
332 | .probe = mpl3115_probe, | |
333 | .remove = mpl3115_remove, | |
334 | .id_table = mpl3115_id, | |
335 | }; | |
336 | module_i2c_driver(mpl3115_driver); | |
337 | ||
338 | MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>"); | |
339 | MODULE_DESCRIPTION("Freescale MPL3115 pressure/temperature driver"); | |
340 | MODULE_LICENSE("GPL"); |