blob: e8e2077c7244b5623efc8cd07521a9105dfbe192 [file] [log] [blame]
Peter Meerwaldc7eeea92014-02-05 09:51:00 +00001/*
2 * mma8452.c - Support for Freescale MMA8452Q 3-axis 12-bit accelerometer
3 *
4 * Copyright 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 0x1c/0x1d (pin selectable)
11 *
Martin Fuzzey28e34272015-06-01 15:39:52 +020012 * TODO: orientation / freefall events, autosleep
Peter Meerwaldc7eeea92014-02-05 09:51:00 +000013 */
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/iio/trigger_consumer.h>
20#include <linux/iio/buffer.h>
Martin Fuzzeyae6d9ce2015-06-01 15:39:58 +020021#include <linux/iio/trigger.h>
22#include <linux/iio/trigger_consumer.h>
Peter Meerwaldc7eeea92014-02-05 09:51:00 +000023#include <linux/iio/triggered_buffer.h>
Martin Fuzzey28e34272015-06-01 15:39:52 +020024#include <linux/iio/events.h>
Peter Meerwaldc7eeea92014-02-05 09:51:00 +000025#include <linux/delay.h>
26
27#define MMA8452_STATUS 0x00
28#define MMA8452_OUT_X 0x01 /* MSB first, 12-bit */
29#define MMA8452_OUT_Y 0x03
30#define MMA8452_OUT_Z 0x05
Martin Fuzzey28e34272015-06-01 15:39:52 +020031#define MMA8452_INT_SRC 0x0c
Peter Meerwaldc7eeea92014-02-05 09:51:00 +000032#define MMA8452_WHO_AM_I 0x0d
33#define MMA8452_DATA_CFG 0x0e
Martin Fuzzey1e798412015-06-01 15:39:56 +020034#define MMA8452_HP_FILTER_CUTOFF 0x0f
35#define MMA8452_HP_FILTER_CUTOFF_SEL_MASK (BIT(0) | BIT(1))
Martin Fuzzey28e34272015-06-01 15:39:52 +020036#define MMA8452_TRANSIENT_CFG 0x1d
37#define MMA8452_TRANSIENT_CFG_ELE BIT(4)
38#define MMA8452_TRANSIENT_CFG_CHAN(chan) BIT(chan + 1)
Martin Fuzzey1e798412015-06-01 15:39:56 +020039#define MMA8452_TRANSIENT_CFG_HPF_BYP BIT(0)
Martin Fuzzey28e34272015-06-01 15:39:52 +020040#define MMA8452_TRANSIENT_SRC 0x1e
41#define MMA8452_TRANSIENT_SRC_XTRANSE BIT(1)
42#define MMA8452_TRANSIENT_SRC_YTRANSE BIT(3)
43#define MMA8452_TRANSIENT_SRC_ZTRANSE BIT(5)
44#define MMA8452_TRANSIENT_THS 0x1f
45#define MMA8452_TRANSIENT_THS_MASK 0x7f
Martin Fuzzey5dbbd192015-06-01 15:39:54 +020046#define MMA8452_TRANSIENT_COUNT 0x20
Peter Meerwaldc7eeea92014-02-05 09:51:00 +000047#define MMA8452_OFF_X 0x2f
48#define MMA8452_OFF_Y 0x30
49#define MMA8452_OFF_Z 0x31
50#define MMA8452_CTRL_REG1 0x2a
51#define MMA8452_CTRL_REG2 0x2b
Martin Fuzzeyecabae72015-05-13 12:26:38 +020052#define MMA8452_CTRL_REG2_RST BIT(6)
Martin Fuzzey28e34272015-06-01 15:39:52 +020053#define MMA8452_CTRL_REG4 0x2d
54#define MMA8452_CTRL_REG5 0x2e
Peter Meerwaldc7eeea92014-02-05 09:51:00 +000055
Martin Fuzzey2a17698c2015-05-13 12:26:40 +020056#define MMA8452_MAX_REG 0x31
57
Peter Meerwaldc7eeea92014-02-05 09:51:00 +000058#define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0))
59
60#define MMA8452_CTRL_DR_MASK (BIT(5) | BIT(4) | BIT(3))
61#define MMA8452_CTRL_DR_SHIFT 3
62#define MMA8452_CTRL_DR_DEFAULT 0x4 /* 50 Hz sample frequency */
63#define MMA8452_CTRL_ACTIVE BIT(0)
64
65#define MMA8452_DATA_CFG_FS_MASK (BIT(1) | BIT(0))
66#define MMA8452_DATA_CFG_FS_2G 0
67#define MMA8452_DATA_CFG_FS_4G 1
68#define MMA8452_DATA_CFG_FS_8G 2
Martin Fuzzey1e798412015-06-01 15:39:56 +020069#define MMA8452_DATA_CFG_HPF_MASK BIT(4)
Peter Meerwaldc7eeea92014-02-05 09:51:00 +000070
Martin Fuzzeyae6d9ce2015-06-01 15:39:58 +020071#define MMA8452_INT_DRDY BIT(0)
Martin Fuzzey28e34272015-06-01 15:39:52 +020072#define MMA8452_INT_TRANS BIT(5)
73
Peter Meerwaldc7eeea92014-02-05 09:51:00 +000074#define MMA8452_DEVICE_ID 0x2a
75
76struct mma8452_data {
77 struct i2c_client *client;
78 struct mutex lock;
79 u8 ctrl_reg1;
80 u8 data_cfg;
81};
82
83static int mma8452_drdy(struct mma8452_data *data)
84{
85 int tries = 150;
86
87 while (tries-- > 0) {
88 int ret = i2c_smbus_read_byte_data(data->client,
89 MMA8452_STATUS);
90 if (ret < 0)
91 return ret;
92 if ((ret & MMA8452_STATUS_DRDY) == MMA8452_STATUS_DRDY)
93 return 0;
94 msleep(20);
95 }
96
97 dev_err(&data->client->dev, "data not ready\n");
98 return -EIO;
99}
100
101static int mma8452_read(struct mma8452_data *data, __be16 buf[3])
102{
103 int ret = mma8452_drdy(data);
104 if (ret < 0)
105 return ret;
106 return i2c_smbus_read_i2c_block_data(data->client,
107 MMA8452_OUT_X, 3 * sizeof(__be16), (u8 *) buf);
108}
109
110static ssize_t mma8452_show_int_plus_micros(char *buf,
111 const int (*vals)[2], int n)
112{
113 size_t len = 0;
114
115 while (n-- > 0)
116 len += scnprintf(buf + len, PAGE_SIZE - len,
117 "%d.%06d ", vals[n][0], vals[n][1]);
118
119 /* replace trailing space by newline */
120 buf[len - 1] = '\n';
121
122 return len;
123}
124
125static int mma8452_get_int_plus_micros_index(const int (*vals)[2], int n,
126 int val, int val2)
127{
128 while (n-- > 0)
129 if (val == vals[n][0] && val2 == vals[n][1])
130 return n;
131
132 return -EINVAL;
133}
134
Martin Fuzzey5dbbd192015-06-01 15:39:54 +0200135static int mma8452_get_odr_index(struct mma8452_data *data)
136{
137 return (data->ctrl_reg1 & MMA8452_CTRL_DR_MASK) >>
138 MMA8452_CTRL_DR_SHIFT;
139}
140
Peter Meerwaldc7eeea92014-02-05 09:51:00 +0000141static const int mma8452_samp_freq[8][2] = {
142 {800, 0}, {400, 0}, {200, 0}, {100, 0}, {50, 0}, {12, 500000},
143 {6, 250000}, {1, 560000}
144};
145
Roberta Dobrescuc8761092014-12-30 20:57:54 +0200146/*
Martin Fuzzey71702e62014-11-07 13:54:00 +0000147 * Hardware has fullscale of -2G, -4G, -8G corresponding to raw value -2048
148 * The userspace interface uses m/s^2 and we declare micro units
149 * So scale factor is given by:
150 * g * N * 1000000 / 2048 for N = 2, 4, 8 and g=9.80665
151 */
Peter Meerwaldc7eeea92014-02-05 09:51:00 +0000152static const int mma8452_scales[3][2] = {
Martin Fuzzey71702e62014-11-07 13:54:00 +0000153 {0, 9577}, {0, 19154}, {0, 38307}
Peter Meerwaldc7eeea92014-02-05 09:51:00 +0000154};
155
Martin Fuzzey5dbbd192015-06-01 15:39:54 +0200156/* Datasheet table 35 (step time vs sample frequency) */
157static const int mma8452_transient_time_step_us[8] = {
158 1250,
159 2500,
160 5000,
161 10000,
162 20000,
163 20000,
164 20000,
165 20000
166};
167
Martin Fuzzey1e798412015-06-01 15:39:56 +0200168/* Datasheet table 18 (normal mode) */
169static const int mma8452_hp_filter_cutoff[8][4][2] = {
170 { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, /* 800 Hz sample */
171 { {16, 0}, {8, 0}, {4, 0}, {2, 0} }, /* 400 Hz sample */
172 { {8, 0}, {4, 0}, {2, 0}, {1, 0} }, /* 200 Hz sample */
173 { {4, 0}, {2, 0}, {1, 0}, {0, 500000} }, /* 100 Hz sample */
174 { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }, /* 50 Hz sample */
175 { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }, /* 12.5 Hz sample */
176 { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }, /* 6.25 Hz sample */
177 { {2, 0}, {1, 0}, {0, 500000}, {0, 250000} } /* 1.56 Hz sample */
178};
179
Peter Meerwaldc7eeea92014-02-05 09:51:00 +0000180static ssize_t mma8452_show_samp_freq_avail(struct device *dev,
181 struct device_attribute *attr, char *buf)
182{
183 return mma8452_show_int_plus_micros(buf, mma8452_samp_freq,
184 ARRAY_SIZE(mma8452_samp_freq));
185}
186
187static ssize_t mma8452_show_scale_avail(struct device *dev,
188 struct device_attribute *attr, char *buf)
189{
190 return mma8452_show_int_plus_micros(buf, mma8452_scales,
191 ARRAY_SIZE(mma8452_scales));
192}
193
Martin Fuzzey1e798412015-06-01 15:39:56 +0200194static ssize_t mma8452_show_hp_cutoff_avail(struct device *dev,
195 struct device_attribute *attr,
196 char *buf)
197{
198 struct iio_dev *indio_dev = dev_to_iio_dev(dev);
199 struct mma8452_data *data = iio_priv(indio_dev);
200 int i = mma8452_get_odr_index(data);
201
202 return mma8452_show_int_plus_micros(buf, mma8452_hp_filter_cutoff[i],
203 ARRAY_SIZE(mma8452_hp_filter_cutoff[0]));
204}
205
Peter Meerwaldc7eeea92014-02-05 09:51:00 +0000206static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(mma8452_show_samp_freq_avail);
207static IIO_DEVICE_ATTR(in_accel_scale_available, S_IRUGO,
208 mma8452_show_scale_avail, NULL, 0);
Martin Fuzzey1e798412015-06-01 15:39:56 +0200209static IIO_DEVICE_ATTR(in_accel_filter_high_pass_3db_frequency_available,
210 S_IRUGO, mma8452_show_hp_cutoff_avail, NULL, 0);
Peter Meerwaldc7eeea92014-02-05 09:51:00 +0000211
212static int mma8452_get_samp_freq_index(struct mma8452_data *data,
213 int val, int val2)
214{
215 return mma8452_get_int_plus_micros_index(mma8452_samp_freq,
216 ARRAY_SIZE(mma8452_samp_freq), val, val2);
217}
218
219static int mma8452_get_scale_index(struct mma8452_data *data,
220 int val, int val2)
221{
222 return mma8452_get_int_plus_micros_index(mma8452_scales,
223 ARRAY_SIZE(mma8452_scales), val, val2);
224}
225
Martin Fuzzey1e798412015-06-01 15:39:56 +0200226static int mma8452_get_hp_filter_index(struct mma8452_data *data,
227 int val, int val2)
228{
229 int i = mma8452_get_odr_index(data);
230
231 return mma8452_get_int_plus_micros_index(mma8452_hp_filter_cutoff[i],
232 ARRAY_SIZE(mma8452_scales[0]), val, val2);
233}
234
235static int mma8452_read_hp_filter(struct mma8452_data *data, int *hz, int *uHz)
236{
237 int i, ret;
238
239 ret = i2c_smbus_read_byte_data(data->client, MMA8452_HP_FILTER_CUTOFF);
240 if (ret < 0)
241 return ret;
242
243 i = mma8452_get_odr_index(data);
244 ret &= MMA8452_HP_FILTER_CUTOFF_SEL_MASK;
245 *hz = mma8452_hp_filter_cutoff[i][ret][0];
246 *uHz = mma8452_hp_filter_cutoff[i][ret][1];
247
248 return 0;
249}
250
Peter Meerwaldc7eeea92014-02-05 09:51:00 +0000251static int mma8452_read_raw(struct iio_dev *indio_dev,
252 struct iio_chan_spec const *chan,
253 int *val, int *val2, long mask)
254{
255 struct mma8452_data *data = iio_priv(indio_dev);
256 __be16 buffer[3];
257 int i, ret;
258
259 switch (mask) {
260 case IIO_CHAN_INFO_RAW:
261 if (iio_buffer_enabled(indio_dev))
262 return -EBUSY;
263
264 mutex_lock(&data->lock);
265 ret = mma8452_read(data, buffer);
266 mutex_unlock(&data->lock);
267 if (ret < 0)
268 return ret;
269 *val = sign_extend32(
270 be16_to_cpu(buffer[chan->scan_index]) >> 4, 11);
271 return IIO_VAL_INT;
272 case IIO_CHAN_INFO_SCALE:
273 i = data->data_cfg & MMA8452_DATA_CFG_FS_MASK;
274 *val = mma8452_scales[i][0];
275 *val2 = mma8452_scales[i][1];
276 return IIO_VAL_INT_PLUS_MICRO;
277 case IIO_CHAN_INFO_SAMP_FREQ:
Martin Fuzzey5dbbd192015-06-01 15:39:54 +0200278 i = mma8452_get_odr_index(data);
Peter Meerwaldc7eeea92014-02-05 09:51:00 +0000279 *val = mma8452_samp_freq[i][0];
280 *val2 = mma8452_samp_freq[i][1];
281 return IIO_VAL_INT_PLUS_MICRO;
282 case IIO_CHAN_INFO_CALIBBIAS:
283 ret = i2c_smbus_read_byte_data(data->client, MMA8452_OFF_X +
284 chan->scan_index);
285 if (ret < 0)
286 return ret;
287 *val = sign_extend32(ret, 7);
288 return IIO_VAL_INT;
Martin Fuzzey1e798412015-06-01 15:39:56 +0200289 case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
290 if (data->data_cfg & MMA8452_DATA_CFG_HPF_MASK) {
291 ret = mma8452_read_hp_filter(data, val, val2);
292 if (ret < 0)
293 return ret;
294 } else {
295 *val = 0;
296 *val2 = 0;
297 }
298 return IIO_VAL_INT_PLUS_MICRO;
Peter Meerwaldc7eeea92014-02-05 09:51:00 +0000299 }
300 return -EINVAL;
301}
302
303static int mma8452_standby(struct mma8452_data *data)
304{
305 return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1,
306 data->ctrl_reg1 & ~MMA8452_CTRL_ACTIVE);
307}
308
309static int mma8452_active(struct mma8452_data *data)
310{
311 return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1,
312 data->ctrl_reg1);
313}
314
315static int mma8452_change_config(struct mma8452_data *data, u8 reg, u8 val)
316{
317 int ret;
318
319 mutex_lock(&data->lock);
320
321 /* config can only be changed when in standby */
322 ret = mma8452_standby(data);
323 if (ret < 0)
324 goto fail;
325
326 ret = i2c_smbus_write_byte_data(data->client, reg, val);
327 if (ret < 0)
328 goto fail;
329
330 ret = mma8452_active(data);
331 if (ret < 0)
332 goto fail;
333
334 ret = 0;
335fail:
336 mutex_unlock(&data->lock);
337 return ret;
338}
339
Martin Fuzzey1e798412015-06-01 15:39:56 +0200340static int mma8452_set_hp_filter_frequency(struct mma8452_data *data,
341 int val, int val2)
342{
343 int i, reg;
344
345 i = mma8452_get_hp_filter_index(data, val, val2);
346 if (i < 0)
347 return -EINVAL;
348
349 reg = i2c_smbus_read_byte_data(data->client,
350 MMA8452_HP_FILTER_CUTOFF);
351 if (reg < 0)
352 return reg;
353 reg &= ~MMA8452_HP_FILTER_CUTOFF_SEL_MASK;
354 reg |= i;
355
356 return mma8452_change_config(data, MMA8452_HP_FILTER_CUTOFF, reg);
357}
358
Peter Meerwaldc7eeea92014-02-05 09:51:00 +0000359static int mma8452_write_raw(struct iio_dev *indio_dev,
360 struct iio_chan_spec const *chan,
361 int val, int val2, long mask)
362{
363 struct mma8452_data *data = iio_priv(indio_dev);
Martin Fuzzey1e798412015-06-01 15:39:56 +0200364 int i, ret;
Peter Meerwaldc7eeea92014-02-05 09:51:00 +0000365
366 if (iio_buffer_enabled(indio_dev))
367 return -EBUSY;
368
369 switch (mask) {
370 case IIO_CHAN_INFO_SAMP_FREQ:
371 i = mma8452_get_samp_freq_index(data, val, val2);
372 if (i < 0)
373 return -EINVAL;
374
375 data->ctrl_reg1 &= ~MMA8452_CTRL_DR_MASK;
376 data->ctrl_reg1 |= i << MMA8452_CTRL_DR_SHIFT;
377 return mma8452_change_config(data, MMA8452_CTRL_REG1,
378 data->ctrl_reg1);
379 case IIO_CHAN_INFO_SCALE:
380 i = mma8452_get_scale_index(data, val, val2);
381 if (i < 0)
382 return -EINVAL;
383 data->data_cfg &= ~MMA8452_DATA_CFG_FS_MASK;
384 data->data_cfg |= i;
385 return mma8452_change_config(data, MMA8452_DATA_CFG,
386 data->data_cfg);
387 case IIO_CHAN_INFO_CALIBBIAS:
388 if (val < -128 || val > 127)
389 return -EINVAL;
390 return mma8452_change_config(data, MMA8452_OFF_X +
391 chan->scan_index, val);
Martin Fuzzey1e798412015-06-01 15:39:56 +0200392
393 case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
394 if (val == 0 && val2 == 0) {
395 data->data_cfg &= ~MMA8452_DATA_CFG_HPF_MASK;
396 } else {
397 data->data_cfg |= MMA8452_DATA_CFG_HPF_MASK;
398 ret = mma8452_set_hp_filter_frequency(data, val, val2);
399 if (ret < 0)
400 return ret;
401 }
402 return mma8452_change_config(data, MMA8452_DATA_CFG,
403 data->data_cfg);
404
Peter Meerwaldc7eeea92014-02-05 09:51:00 +0000405 default:
406 return -EINVAL;
407 }
408}
409
Martin Fuzzey28e34272015-06-01 15:39:52 +0200410static int mma8452_read_thresh(struct iio_dev *indio_dev,
411 const struct iio_chan_spec *chan,
412 enum iio_event_type type,
413 enum iio_event_direction dir,
414 enum iio_event_info info,
415 int *val, int *val2)
416{
417 struct mma8452_data *data = iio_priv(indio_dev);
Martin Fuzzey5dbbd192015-06-01 15:39:54 +0200418 int ret, us;
Martin Fuzzey28e34272015-06-01 15:39:52 +0200419
Martin Fuzzey5dbbd192015-06-01 15:39:54 +0200420 switch (info) {
421 case IIO_EV_INFO_VALUE:
422 ret = i2c_smbus_read_byte_data(data->client,
423 MMA8452_TRANSIENT_THS);
424 if (ret < 0)
425 return ret;
Martin Fuzzey28e34272015-06-01 15:39:52 +0200426
Martin Fuzzey5dbbd192015-06-01 15:39:54 +0200427 *val = ret & MMA8452_TRANSIENT_THS_MASK;
428 return IIO_VAL_INT;
Martin Fuzzey28e34272015-06-01 15:39:52 +0200429
Martin Fuzzey5dbbd192015-06-01 15:39:54 +0200430 case IIO_EV_INFO_PERIOD:
431 ret = i2c_smbus_read_byte_data(data->client,
432 MMA8452_TRANSIENT_COUNT);
433 if (ret < 0)
434 return ret;
435
436 us = ret * mma8452_transient_time_step_us[
437 mma8452_get_odr_index(data)];
438 *val = us / USEC_PER_SEC;
439 *val2 = us % USEC_PER_SEC;
440 return IIO_VAL_INT_PLUS_MICRO;
441
Martin Fuzzey1e798412015-06-01 15:39:56 +0200442 case IIO_EV_INFO_HIGH_PASS_FILTER_3DB:
443 ret = i2c_smbus_read_byte_data(data->client,
444 MMA8452_TRANSIENT_CFG);
445 if (ret < 0)
446 return ret;
447
448 if (ret & MMA8452_TRANSIENT_CFG_HPF_BYP) {
449 *val = 0;
450 *val2 = 0;
451 } else {
452 ret = mma8452_read_hp_filter(data, val, val2);
453 if (ret < 0)
454 return ret;
455 }
456 return IIO_VAL_INT_PLUS_MICRO;
457
Martin Fuzzey5dbbd192015-06-01 15:39:54 +0200458 default:
459 return -EINVAL;
460 }
Martin Fuzzey28e34272015-06-01 15:39:52 +0200461}
462
463static int mma8452_write_thresh(struct iio_dev *indio_dev,
464 const struct iio_chan_spec *chan,
465 enum iio_event_type type,
466 enum iio_event_direction dir,
467 enum iio_event_info info,
468 int val, int val2)
469{
470 struct mma8452_data *data = iio_priv(indio_dev);
Martin Fuzzey1e798412015-06-01 15:39:56 +0200471 int ret, reg, steps;
Martin Fuzzey28e34272015-06-01 15:39:52 +0200472
Martin Fuzzey5dbbd192015-06-01 15:39:54 +0200473 switch (info) {
474 case IIO_EV_INFO_VALUE:
475 return mma8452_change_config(data, MMA8452_TRANSIENT_THS,
476 val & MMA8452_TRANSIENT_THS_MASK);
477
478 case IIO_EV_INFO_PERIOD:
479 steps = (val * USEC_PER_SEC + val2) /
480 mma8452_transient_time_step_us[
481 mma8452_get_odr_index(data)];
482
483 if (steps > 0xff)
484 return -EINVAL;
485
486 return mma8452_change_config(data, MMA8452_TRANSIENT_COUNT,
487 steps);
Martin Fuzzey1e798412015-06-01 15:39:56 +0200488 case IIO_EV_INFO_HIGH_PASS_FILTER_3DB:
489 reg = i2c_smbus_read_byte_data(data->client,
490 MMA8452_TRANSIENT_CFG);
491 if (reg < 0)
492 return reg;
493
494 if (val == 0 && val2 == 0) {
495 reg |= MMA8452_TRANSIENT_CFG_HPF_BYP;
496 } else {
497 reg &= ~MMA8452_TRANSIENT_CFG_HPF_BYP;
498 ret = mma8452_set_hp_filter_frequency(data, val, val2);
499 if (ret < 0)
500 return ret;
501 }
502 return mma8452_change_config(data, MMA8452_TRANSIENT_CFG, reg);
503
Martin Fuzzey5dbbd192015-06-01 15:39:54 +0200504 default:
505 return -EINVAL;
506 }
Martin Fuzzey28e34272015-06-01 15:39:52 +0200507}
508
509static int mma8452_read_event_config(struct iio_dev *indio_dev,
510 const struct iio_chan_spec *chan,
511 enum iio_event_type type,
512 enum iio_event_direction dir)
513{
514 struct mma8452_data *data = iio_priv(indio_dev);
515 int ret;
516
517 ret = i2c_smbus_read_byte_data(data->client, MMA8452_TRANSIENT_CFG);
518 if (ret < 0)
519 return ret;
520
521 return ret & MMA8452_TRANSIENT_CFG_CHAN(chan->scan_index) ? 1 : 0;
522}
523
524static int mma8452_write_event_config(struct iio_dev *indio_dev,
525 const struct iio_chan_spec *chan,
526 enum iio_event_type type,
527 enum iio_event_direction dir,
528 int state)
529{
530 struct mma8452_data *data = iio_priv(indio_dev);
531 int val;
532
533 val = i2c_smbus_read_byte_data(data->client, MMA8452_TRANSIENT_CFG);
534 if (val < 0)
535 return val;
536
537 if (state)
538 val |= MMA8452_TRANSIENT_CFG_CHAN(chan->scan_index);
539 else
540 val &= ~MMA8452_TRANSIENT_CFG_CHAN(chan->scan_index);
541
542 val |= MMA8452_TRANSIENT_CFG_ELE;
543
544 return mma8452_change_config(data, MMA8452_TRANSIENT_CFG, val);
545}
546
547static void mma8452_transient_interrupt(struct iio_dev *indio_dev)
548{
549 struct mma8452_data *data = iio_priv(indio_dev);
550 s64 ts = iio_get_time_ns();
551 int src;
552
553 src = i2c_smbus_read_byte_data(data->client, MMA8452_TRANSIENT_SRC);
554 if (src < 0)
555 return;
556
557 if (src & MMA8452_TRANSIENT_SRC_XTRANSE)
558 iio_push_event(indio_dev,
559 IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X,
560 IIO_EV_TYPE_THRESH,
561 IIO_EV_DIR_RISING),
562 ts);
563
564 if (src & MMA8452_TRANSIENT_SRC_YTRANSE)
565 iio_push_event(indio_dev,
566 IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Y,
567 IIO_EV_TYPE_THRESH,
568 IIO_EV_DIR_RISING),
569 ts);
570
571 if (src & MMA8452_TRANSIENT_SRC_ZTRANSE)
572 iio_push_event(indio_dev,
573 IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Z,
574 IIO_EV_TYPE_THRESH,
575 IIO_EV_DIR_RISING),
576 ts);
577}
578
579static irqreturn_t mma8452_interrupt(int irq, void *p)
580{
581 struct iio_dev *indio_dev = p;
582 struct mma8452_data *data = iio_priv(indio_dev);
Martin Fuzzeyae6d9ce2015-06-01 15:39:58 +0200583 int ret = IRQ_NONE;
Martin Fuzzey28e34272015-06-01 15:39:52 +0200584 int src;
585
586 src = i2c_smbus_read_byte_data(data->client, MMA8452_INT_SRC);
587 if (src < 0)
588 return IRQ_NONE;
589
Martin Fuzzeyae6d9ce2015-06-01 15:39:58 +0200590 if (src & MMA8452_INT_DRDY) {
591 iio_trigger_poll_chained(indio_dev->trig);
592 ret = IRQ_HANDLED;
Martin Fuzzey28e34272015-06-01 15:39:52 +0200593 }
594
Martin Fuzzeyae6d9ce2015-06-01 15:39:58 +0200595 if (src & MMA8452_INT_TRANS) {
596 mma8452_transient_interrupt(indio_dev);
597 ret = IRQ_HANDLED;
598 }
599
600 return ret;
Martin Fuzzey28e34272015-06-01 15:39:52 +0200601}
602
Peter Meerwaldc7eeea92014-02-05 09:51:00 +0000603static irqreturn_t mma8452_trigger_handler(int irq, void *p)
604{
605 struct iio_poll_func *pf = p;
606 struct iio_dev *indio_dev = pf->indio_dev;
607 struct mma8452_data *data = iio_priv(indio_dev);
608 u8 buffer[16]; /* 3 16-bit channels + padding + ts */
609 int ret;
610
611 ret = mma8452_read(data, (__be16 *) buffer);
612 if (ret < 0)
613 goto done;
614
615 iio_push_to_buffers_with_timestamp(indio_dev, buffer,
616 iio_get_time_ns());
617
618done:
619 iio_trigger_notify_done(indio_dev->trig);
620 return IRQ_HANDLED;
621}
622
Martin Fuzzey2a17698c2015-05-13 12:26:40 +0200623static int mma8452_reg_access_dbg(struct iio_dev *indio_dev,
624 unsigned reg, unsigned writeval,
625 unsigned *readval)
626{
627 int ret;
628 struct mma8452_data *data = iio_priv(indio_dev);
629
630 if (reg > MMA8452_MAX_REG)
631 return -EINVAL;
632
633 if (!readval)
634 return mma8452_change_config(data, reg, writeval);
635
636 ret = i2c_smbus_read_byte_data(data->client, reg);
637 if (ret < 0)
638 return ret;
639
640 *readval = ret;
641
642 return 0;
643}
644
Martin Fuzzey28e34272015-06-01 15:39:52 +0200645static const struct iio_event_spec mma8452_transient_event[] = {
646 {
647 .type = IIO_EV_TYPE_THRESH,
648 .dir = IIO_EV_DIR_RISING,
649 .mask_separate = BIT(IIO_EV_INFO_ENABLE),
Martin Fuzzey5dbbd192015-06-01 15:39:54 +0200650 .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
Martin Fuzzey1e798412015-06-01 15:39:56 +0200651 BIT(IIO_EV_INFO_PERIOD) |
652 BIT(IIO_EV_INFO_HIGH_PASS_FILTER_3DB)
Martin Fuzzey28e34272015-06-01 15:39:52 +0200653 },
654};
655
656/*
657 * Threshold is configured in fixed 8G/127 steps regardless of
658 * currently selected scale for measurement.
659 */
660static IIO_CONST_ATTR_NAMED(accel_transient_scale, in_accel_scale, "0.617742");
661
662static struct attribute *mma8452_event_attributes[] = {
663 &iio_const_attr_accel_transient_scale.dev_attr.attr,
664 NULL,
665};
666
667static struct attribute_group mma8452_event_attribute_group = {
668 .attrs = mma8452_event_attributes,
669 .name = "events",
670};
671
Peter Meerwaldc7eeea92014-02-05 09:51:00 +0000672#define MMA8452_CHANNEL(axis, idx) { \
673 .type = IIO_ACCEL, \
674 .modified = 1, \
675 .channel2 = IIO_MOD_##axis, \
676 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
677 BIT(IIO_CHAN_INFO_CALIBBIAS), \
678 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
Martin Fuzzey1e798412015-06-01 15:39:56 +0200679 BIT(IIO_CHAN_INFO_SCALE) | \
680 BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \
Peter Meerwaldc7eeea92014-02-05 09:51:00 +0000681 .scan_index = idx, \
682 .scan_type = { \
683 .sign = 's', \
684 .realbits = 12, \
685 .storagebits = 16, \
686 .shift = 4, \
687 .endianness = IIO_BE, \
688 }, \
Martin Fuzzey28e34272015-06-01 15:39:52 +0200689 .event_spec = mma8452_transient_event, \
690 .num_event_specs = ARRAY_SIZE(mma8452_transient_event), \
Peter Meerwaldc7eeea92014-02-05 09:51:00 +0000691}
692
693static const struct iio_chan_spec mma8452_channels[] = {
694 MMA8452_CHANNEL(X, 0),
695 MMA8452_CHANNEL(Y, 1),
696 MMA8452_CHANNEL(Z, 2),
697 IIO_CHAN_SOFT_TIMESTAMP(3),
698};
699
700static struct attribute *mma8452_attributes[] = {
701 &iio_dev_attr_sampling_frequency_available.dev_attr.attr,
702 &iio_dev_attr_in_accel_scale_available.dev_attr.attr,
Martin Fuzzey1e798412015-06-01 15:39:56 +0200703 &iio_dev_attr_in_accel_filter_high_pass_3db_frequency_available.dev_attr.attr,
Peter Meerwaldc7eeea92014-02-05 09:51:00 +0000704 NULL
705};
706
707static const struct attribute_group mma8452_group = {
708 .attrs = mma8452_attributes,
709};
710
711static const struct iio_info mma8452_info = {
712 .attrs = &mma8452_group,
713 .read_raw = &mma8452_read_raw,
714 .write_raw = &mma8452_write_raw,
Martin Fuzzey28e34272015-06-01 15:39:52 +0200715 .event_attrs = &mma8452_event_attribute_group,
716 .read_event_value = &mma8452_read_thresh,
717 .write_event_value = &mma8452_write_thresh,
718 .read_event_config = &mma8452_read_event_config,
719 .write_event_config = &mma8452_write_event_config,
Martin Fuzzey2a17698c2015-05-13 12:26:40 +0200720 .debugfs_reg_access = &mma8452_reg_access_dbg,
Peter Meerwaldc7eeea92014-02-05 09:51:00 +0000721 .driver_module = THIS_MODULE,
722};
723
724static const unsigned long mma8452_scan_masks[] = {0x7, 0};
725
Martin Fuzzeyae6d9ce2015-06-01 15:39:58 +0200726static int mma8452_data_rdy_trigger_set_state(struct iio_trigger *trig,
727 bool state)
728{
729 struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
730 struct mma8452_data *data = iio_priv(indio_dev);
731 int reg;
732
733 reg = i2c_smbus_read_byte_data(data->client, MMA8452_CTRL_REG4);
734 if (reg < 0)
735 return reg;
736
737 if (state)
738 reg |= MMA8452_INT_DRDY;
739 else
740 reg &= ~MMA8452_INT_DRDY;
741
742 return mma8452_change_config(data, MMA8452_CTRL_REG4, reg);
743}
744
745static int mma8452_validate_device(struct iio_trigger *trig,
746 struct iio_dev *indio_dev)
747{
748 struct iio_dev *indio = iio_trigger_get_drvdata(trig);
749
750 if (indio != indio_dev)
751 return -EINVAL;
752
753 return 0;
754}
755
756static const struct iio_trigger_ops mma8452_trigger_ops = {
757 .set_trigger_state = mma8452_data_rdy_trigger_set_state,
758 .validate_device = mma8452_validate_device,
759 .owner = THIS_MODULE,
760};
761
762static int mma8452_trigger_setup(struct iio_dev *indio_dev)
763{
764 struct mma8452_data *data = iio_priv(indio_dev);
765 struct iio_trigger *trig;
766 int ret;
767
768 trig = devm_iio_trigger_alloc(&data->client->dev, "%s-dev%d",
769 indio_dev->name,
770 indio_dev->id);
771 if (!trig)
772 return -ENOMEM;
773
774 trig->dev.parent = &data->client->dev;
775 trig->ops = &mma8452_trigger_ops;
776 iio_trigger_set_drvdata(trig, indio_dev);
777
778 ret = iio_trigger_register(trig);
779 if (ret)
780 return ret;
781
782 indio_dev->trig = trig;
783 return 0;
784}
785
786static void mma8452_trigger_cleanup(struct iio_dev *indio_dev)
787{
788 if (indio_dev->trig)
789 iio_trigger_unregister(indio_dev->trig);
790}
791
Martin Fuzzeyecabae72015-05-13 12:26:38 +0200792static int mma8452_reset(struct i2c_client *client)
793{
794 int i;
795 int ret;
796
797 ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG2,
798 MMA8452_CTRL_REG2_RST);
799 if (ret < 0)
800 return ret;
801
802 for (i = 0; i < 10; i++) {
803 usleep_range(100, 200);
804 ret = i2c_smbus_read_byte_data(client, MMA8452_CTRL_REG2);
805 if (ret == -EIO)
806 continue; /* I2C comm reset */
807 if (ret < 0)
808 return ret;
809 if (!(ret & MMA8452_CTRL_REG2_RST))
810 return 0;
811 }
812
813 return -ETIMEDOUT;
814}
815
Peter Meerwaldc7eeea92014-02-05 09:51:00 +0000816static int mma8452_probe(struct i2c_client *client,
817 const struct i2c_device_id *id)
818{
819 struct mma8452_data *data;
820 struct iio_dev *indio_dev;
821 int ret;
822
823 ret = i2c_smbus_read_byte_data(client, MMA8452_WHO_AM_I);
824 if (ret < 0)
825 return ret;
826 if (ret != MMA8452_DEVICE_ID)
827 return -ENODEV;
828
829 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
830 if (!indio_dev)
831 return -ENOMEM;
832
833 data = iio_priv(indio_dev);
834 data->client = client;
835 mutex_init(&data->lock);
836
837 i2c_set_clientdata(client, indio_dev);
838 indio_dev->info = &mma8452_info;
839 indio_dev->name = id->name;
840 indio_dev->dev.parent = &client->dev;
841 indio_dev->modes = INDIO_DIRECT_MODE;
842 indio_dev->channels = mma8452_channels;
843 indio_dev->num_channels = ARRAY_SIZE(mma8452_channels);
844 indio_dev->available_scan_masks = mma8452_scan_masks;
845
Martin Fuzzeyecabae72015-05-13 12:26:38 +0200846 ret = mma8452_reset(client);
Peter Meerwaldc7eeea92014-02-05 09:51:00 +0000847 if (ret < 0)
848 return ret;
849
850 data->data_cfg = MMA8452_DATA_CFG_FS_2G;
851 ret = i2c_smbus_write_byte_data(client, MMA8452_DATA_CFG,
852 data->data_cfg);
853 if (ret < 0)
854 return ret;
855
Martin Fuzzey28e34272015-06-01 15:39:52 +0200856 /*
857 * By default set transient threshold to max to avoid events if
858 * enabling without configuring threshold.
859 */
860 ret = i2c_smbus_write_byte_data(client, MMA8452_TRANSIENT_THS,
861 MMA8452_TRANSIENT_THS_MASK);
862 if (ret < 0)
863 return ret;
864
865 if (client->irq) {
866 /*
867 * Although we enable the transient interrupt source once and
868 * for all here the transient event detection itself is not
869 * enabled until userspace asks for it by
870 * mma8452_write_event_config()
871 */
Martin Fuzzeyae6d9ce2015-06-01 15:39:58 +0200872 int supported_interrupts = MMA8452_INT_DRDY | MMA8452_INT_TRANS;
873 int enabled_interrupts = MMA8452_INT_TRANS;
Martin Fuzzey28e34272015-06-01 15:39:52 +0200874
875 /* Assume wired to INT1 pin */
876 ret = i2c_smbus_write_byte_data(client,
877 MMA8452_CTRL_REG5,
878 supported_interrupts);
879 if (ret < 0)
880 return ret;
881
882 ret = i2c_smbus_write_byte_data(client,
883 MMA8452_CTRL_REG4,
Martin Fuzzeyae6d9ce2015-06-01 15:39:58 +0200884 enabled_interrupts);
885 if (ret < 0)
886 return ret;
887
888 ret = mma8452_trigger_setup(indio_dev);
Martin Fuzzey28e34272015-06-01 15:39:52 +0200889 if (ret < 0)
890 return ret;
891 }
892
Martin Fuzzeyecabae72015-05-13 12:26:38 +0200893 data->ctrl_reg1 = MMA8452_CTRL_ACTIVE |
894 (MMA8452_CTRL_DR_DEFAULT << MMA8452_CTRL_DR_SHIFT);
895 ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG1,
896 data->ctrl_reg1);
897 if (ret < 0)
Martin Fuzzeyae6d9ce2015-06-01 15:39:58 +0200898 goto trigger_cleanup;
Martin Fuzzeyecabae72015-05-13 12:26:38 +0200899
Peter Meerwaldc7eeea92014-02-05 09:51:00 +0000900 ret = iio_triggered_buffer_setup(indio_dev, NULL,
901 mma8452_trigger_handler, NULL);
902 if (ret < 0)
Martin Fuzzeyae6d9ce2015-06-01 15:39:58 +0200903 goto trigger_cleanup;
Peter Meerwaldc7eeea92014-02-05 09:51:00 +0000904
Martin Fuzzey28e34272015-06-01 15:39:52 +0200905 if (client->irq) {
906 ret = devm_request_threaded_irq(&client->dev,
907 client->irq,
908 NULL, mma8452_interrupt,
909 IRQF_TRIGGER_LOW | IRQF_ONESHOT,
910 client->name, indio_dev);
911 if (ret)
912 goto buffer_cleanup;
913 }
914
Peter Meerwaldc7eeea92014-02-05 09:51:00 +0000915 ret = iio_device_register(indio_dev);
916 if (ret < 0)
917 goto buffer_cleanup;
Martin Fuzzey28e34272015-06-01 15:39:52 +0200918
Peter Meerwaldc7eeea92014-02-05 09:51:00 +0000919 return 0;
920
921buffer_cleanup:
922 iio_triggered_buffer_cleanup(indio_dev);
Martin Fuzzeyae6d9ce2015-06-01 15:39:58 +0200923
924trigger_cleanup:
925 mma8452_trigger_cleanup(indio_dev);
926
Peter Meerwaldc7eeea92014-02-05 09:51:00 +0000927 return ret;
928}
929
930static int mma8452_remove(struct i2c_client *client)
931{
932 struct iio_dev *indio_dev = i2c_get_clientdata(client);
933
934 iio_device_unregister(indio_dev);
935 iio_triggered_buffer_cleanup(indio_dev);
Martin Fuzzeyae6d9ce2015-06-01 15:39:58 +0200936 mma8452_trigger_cleanup(indio_dev);
Peter Meerwaldc7eeea92014-02-05 09:51:00 +0000937 mma8452_standby(iio_priv(indio_dev));
938
939 return 0;
940}
941
942#ifdef CONFIG_PM_SLEEP
943static int mma8452_suspend(struct device *dev)
944{
945 return mma8452_standby(iio_priv(i2c_get_clientdata(
946 to_i2c_client(dev))));
947}
948
949static int mma8452_resume(struct device *dev)
950{
951 return mma8452_active(iio_priv(i2c_get_clientdata(
952 to_i2c_client(dev))));
953}
954
955static SIMPLE_DEV_PM_OPS(mma8452_pm_ops, mma8452_suspend, mma8452_resume);
956#define MMA8452_PM_OPS (&mma8452_pm_ops)
957#else
958#define MMA8452_PM_OPS NULL
959#endif
960
961static const struct i2c_device_id mma8452_id[] = {
962 { "mma8452", 0 },
963 { }
964};
965MODULE_DEVICE_TABLE(i2c, mma8452_id);
966
Martin Fuzzeya3fb96a2014-11-07 14:06:00 +0000967static const struct of_device_id mma8452_dt_ids[] = {
968 { .compatible = "fsl,mma8452" },
969 { }
970};
971
Peter Meerwaldc7eeea92014-02-05 09:51:00 +0000972static struct i2c_driver mma8452_driver = {
973 .driver = {
974 .name = "mma8452",
Martin Fuzzeya3fb96a2014-11-07 14:06:00 +0000975 .of_match_table = of_match_ptr(mma8452_dt_ids),
Peter Meerwaldc7eeea92014-02-05 09:51:00 +0000976 .pm = MMA8452_PM_OPS,
977 },
978 .probe = mma8452_probe,
979 .remove = mma8452_remove,
980 .id_table = mma8452_id,
981};
982module_i2c_driver(mma8452_driver);
983
984MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
985MODULE_DESCRIPTION("Freescale MMA8452 accelerometer driver");
986MODULE_LICENSE("GPL");