xref: /linux/drivers/iio/accel/mma8452.c (revision 69abff81d7fa59a0dfca5c72a7f1006f17a06d11)
1c7eeea93SPeter Meerwald /*
2c7eeea93SPeter Meerwald  * mma8452.c - Support for Freescale MMA8452Q 3-axis 12-bit accelerometer
3c7eeea93SPeter Meerwald  *
4c7eeea93SPeter Meerwald  * Copyright 2014 Peter Meerwald <pmeerw@pmeerw.net>
5c7eeea93SPeter Meerwald  *
6c7eeea93SPeter Meerwald  * This file is subject to the terms and conditions of version 2 of
7c7eeea93SPeter Meerwald  * the GNU General Public License.  See the file COPYING in the main
8c7eeea93SPeter Meerwald  * directory of this archive for more details.
9c7eeea93SPeter Meerwald  *
10c7eeea93SPeter Meerwald  * 7-bit I2C slave address 0x1c/0x1d (pin selectable)
11c7eeea93SPeter Meerwald  *
1228e34278SMartin Fuzzey  * TODO: orientation / freefall events, autosleep
13c7eeea93SPeter Meerwald  */
14c7eeea93SPeter Meerwald 
15c7eeea93SPeter Meerwald #include <linux/module.h>
16c7eeea93SPeter Meerwald #include <linux/i2c.h>
17c7eeea93SPeter Meerwald #include <linux/iio/iio.h>
18c7eeea93SPeter Meerwald #include <linux/iio/sysfs.h>
19c7eeea93SPeter Meerwald #include <linux/iio/buffer.h>
20ae6d9ce0SMartin Fuzzey #include <linux/iio/trigger.h>
21ae6d9ce0SMartin Fuzzey #include <linux/iio/trigger_consumer.h>
22c7eeea93SPeter Meerwald #include <linux/iio/triggered_buffer.h>
2328e34278SMartin Fuzzey #include <linux/iio/events.h>
24c7eeea93SPeter Meerwald #include <linux/delay.h>
25c7eeea93SPeter Meerwald 
26c7eeea93SPeter Meerwald #define MMA8452_STATUS				0x00
27*69abff81SHartmut Knaack #define  MMA8452_STATUS_DRDY			(BIT(2) | BIT(1) | BIT(0))
28c7eeea93SPeter Meerwald #define MMA8452_OUT_X				0x01 /* MSB first, 12-bit  */
29c7eeea93SPeter Meerwald #define MMA8452_OUT_Y				0x03
30c7eeea93SPeter Meerwald #define MMA8452_OUT_Z				0x05
3128e34278SMartin Fuzzey #define MMA8452_INT_SRC				0x0c
32c7eeea93SPeter Meerwald #define MMA8452_WHO_AM_I			0x0d
33c7eeea93SPeter Meerwald #define MMA8452_DATA_CFG			0x0e
34*69abff81SHartmut Knaack #define  MMA8452_DATA_CFG_FS_MASK		GENMASK(1, 0)
35*69abff81SHartmut Knaack #define  MMA8452_DATA_CFG_FS_2G			0
36*69abff81SHartmut Knaack #define  MMA8452_DATA_CFG_FS_4G			1
37*69abff81SHartmut Knaack #define  MMA8452_DATA_CFG_FS_8G			2
38*69abff81SHartmut Knaack #define  MMA8452_DATA_CFG_HPF_MASK		BIT(4)
391e79841aSMartin Fuzzey #define MMA8452_HP_FILTER_CUTOFF		0x0f
40*69abff81SHartmut Knaack #define  MMA8452_HP_FILTER_CUTOFF_SEL_MASK	GENMASK(1, 0)
4128e34278SMartin Fuzzey #define MMA8452_TRANSIENT_CFG			0x1d
421e79841aSMartin Fuzzey #define  MMA8452_TRANSIENT_CFG_HPF_BYP		BIT(0)
43*69abff81SHartmut Knaack #define  MMA8452_TRANSIENT_CFG_CHAN(chan)	BIT(chan + 1)
44*69abff81SHartmut Knaack #define  MMA8452_TRANSIENT_CFG_ELE		BIT(4)
4528e34278SMartin Fuzzey #define MMA8452_TRANSIENT_SRC			0x1e
4628e34278SMartin Fuzzey #define  MMA8452_TRANSIENT_SRC_XTRANSE		BIT(1)
4728e34278SMartin Fuzzey #define  MMA8452_TRANSIENT_SRC_YTRANSE		BIT(3)
4828e34278SMartin Fuzzey #define  MMA8452_TRANSIENT_SRC_ZTRANSE		BIT(5)
4928e34278SMartin Fuzzey #define MMA8452_TRANSIENT_THS			0x1f
50*69abff81SHartmut Knaack #define  MMA8452_TRANSIENT_THS_MASK		GENMASK(6, 0)
515dbbd19fSMartin Fuzzey #define MMA8452_TRANSIENT_COUNT			0x20
52c7eeea93SPeter Meerwald #define MMA8452_CTRL_REG1			0x2a
53*69abff81SHartmut Knaack #define  MMA8452_CTRL_ACTIVE			BIT(0)
54*69abff81SHartmut Knaack #define  MMA8452_CTRL_DR_MASK			GENMASK(5, 3)
55*69abff81SHartmut Knaack #define  MMA8452_CTRL_DR_SHIFT			3
56*69abff81SHartmut Knaack #define  MMA8452_CTRL_DR_DEFAULT		0x4 /* 50 Hz sample frequency */
57c7eeea93SPeter Meerwald #define MMA8452_CTRL_REG2			0x2b
58ecabae71SMartin Fuzzey #define  MMA8452_CTRL_REG2_RST			BIT(6)
5928e34278SMartin Fuzzey #define MMA8452_CTRL_REG4			0x2d
6028e34278SMartin Fuzzey #define MMA8452_CTRL_REG5			0x2e
61*69abff81SHartmut Knaack #define MMA8452_OFF_X				0x2f
62*69abff81SHartmut Knaack #define MMA8452_OFF_Y				0x30
63*69abff81SHartmut Knaack #define MMA8452_OFF_Z				0x31
64c7eeea93SPeter Meerwald 
652a17698cSMartin Fuzzey #define MMA8452_MAX_REG				0x31
662a17698cSMartin Fuzzey 
67ae6d9ce0SMartin Fuzzey #define  MMA8452_INT_DRDY			BIT(0)
6828e34278SMartin Fuzzey #define  MMA8452_INT_TRANS			BIT(5)
6928e34278SMartin Fuzzey 
70c7eeea93SPeter Meerwald #define  MMA8452_DEVICE_ID			0x2a
71c7eeea93SPeter Meerwald 
72c7eeea93SPeter Meerwald struct mma8452_data {
73c7eeea93SPeter Meerwald 	struct i2c_client *client;
74c7eeea93SPeter Meerwald 	struct mutex lock;
75c7eeea93SPeter Meerwald 	u8 ctrl_reg1;
76c7eeea93SPeter Meerwald 	u8 data_cfg;
77c7eeea93SPeter Meerwald };
78c7eeea93SPeter Meerwald 
79c7eeea93SPeter Meerwald static int mma8452_drdy(struct mma8452_data *data)
80c7eeea93SPeter Meerwald {
81c7eeea93SPeter Meerwald 	int tries = 150;
82c7eeea93SPeter Meerwald 
83c7eeea93SPeter Meerwald 	while (tries-- > 0) {
84c7eeea93SPeter Meerwald 		int ret = i2c_smbus_read_byte_data(data->client,
85c7eeea93SPeter Meerwald 			MMA8452_STATUS);
86c7eeea93SPeter Meerwald 		if (ret < 0)
87c7eeea93SPeter Meerwald 			return ret;
88c7eeea93SPeter Meerwald 		if ((ret & MMA8452_STATUS_DRDY) == MMA8452_STATUS_DRDY)
89c7eeea93SPeter Meerwald 			return 0;
90c7eeea93SPeter Meerwald 		msleep(20);
91c7eeea93SPeter Meerwald 	}
92c7eeea93SPeter Meerwald 
93c7eeea93SPeter Meerwald 	dev_err(&data->client->dev, "data not ready\n");
94c7eeea93SPeter Meerwald 	return -EIO;
95c7eeea93SPeter Meerwald }
96c7eeea93SPeter Meerwald 
97c7eeea93SPeter Meerwald static int mma8452_read(struct mma8452_data *data, __be16 buf[3])
98c7eeea93SPeter Meerwald {
99c7eeea93SPeter Meerwald 	int ret = mma8452_drdy(data);
100c7eeea93SPeter Meerwald 	if (ret < 0)
101c7eeea93SPeter Meerwald 		return ret;
102c7eeea93SPeter Meerwald 	return i2c_smbus_read_i2c_block_data(data->client,
103c7eeea93SPeter Meerwald 		MMA8452_OUT_X, 3 * sizeof(__be16), (u8 *) buf);
104c7eeea93SPeter Meerwald }
105c7eeea93SPeter Meerwald 
106c7eeea93SPeter Meerwald static ssize_t mma8452_show_int_plus_micros(char *buf,
107c7eeea93SPeter Meerwald 	const int (*vals)[2], int n)
108c7eeea93SPeter Meerwald {
109c7eeea93SPeter Meerwald 	size_t len = 0;
110c7eeea93SPeter Meerwald 
111c7eeea93SPeter Meerwald 	while (n-- > 0)
112c7eeea93SPeter Meerwald 		len += scnprintf(buf + len, PAGE_SIZE - len,
113c7eeea93SPeter Meerwald 			"%d.%06d ", vals[n][0], vals[n][1]);
114c7eeea93SPeter Meerwald 
115c7eeea93SPeter Meerwald 	/* replace trailing space by newline */
116c7eeea93SPeter Meerwald 	buf[len - 1] = '\n';
117c7eeea93SPeter Meerwald 
118c7eeea93SPeter Meerwald 	return len;
119c7eeea93SPeter Meerwald }
120c7eeea93SPeter Meerwald 
121c7eeea93SPeter Meerwald static int mma8452_get_int_plus_micros_index(const int (*vals)[2], int n,
122c7eeea93SPeter Meerwald 					int val, int val2)
123c7eeea93SPeter Meerwald {
124c7eeea93SPeter Meerwald 	while (n-- > 0)
125c7eeea93SPeter Meerwald 		if (val == vals[n][0] && val2 == vals[n][1])
126c7eeea93SPeter Meerwald 			return n;
127c7eeea93SPeter Meerwald 
128c7eeea93SPeter Meerwald 	return -EINVAL;
129c7eeea93SPeter Meerwald }
130c7eeea93SPeter Meerwald 
1315dbbd19fSMartin Fuzzey static int mma8452_get_odr_index(struct mma8452_data *data)
1325dbbd19fSMartin Fuzzey {
1335dbbd19fSMartin Fuzzey 	return (data->ctrl_reg1 & MMA8452_CTRL_DR_MASK) >>
1345dbbd19fSMartin Fuzzey 			MMA8452_CTRL_DR_SHIFT;
1355dbbd19fSMartin Fuzzey }
1365dbbd19fSMartin Fuzzey 
137c7eeea93SPeter Meerwald static const int mma8452_samp_freq[8][2] = {
138c7eeea93SPeter Meerwald 	{800, 0}, {400, 0}, {200, 0}, {100, 0}, {50, 0}, {12, 500000},
139c7eeea93SPeter Meerwald 	{6, 250000}, {1, 560000}
140c7eeea93SPeter Meerwald };
141c7eeea93SPeter Meerwald 
14271702e6eSMartin Fuzzey /*
14371702e6eSMartin Fuzzey  * Hardware has fullscale of -2G, -4G, -8G corresponding to raw value -2048
14471702e6eSMartin Fuzzey  * The userspace interface uses m/s^2 and we declare micro units
14571702e6eSMartin Fuzzey  * So scale factor is given by:
14671702e6eSMartin Fuzzey  * 	g * N * 1000000 / 2048 for N = 2, 4, 8 and g=9.80665
14771702e6eSMartin Fuzzey  */
148c7eeea93SPeter Meerwald static const int mma8452_scales[3][2] = {
14971702e6eSMartin Fuzzey 	{0, 9577}, {0, 19154}, {0, 38307}
150c7eeea93SPeter Meerwald };
151c7eeea93SPeter Meerwald 
1525dbbd19fSMartin Fuzzey /* Datasheet table 35  (step time vs sample frequency) */
1535dbbd19fSMartin Fuzzey static const int mma8452_transient_time_step_us[8] = {
1545dbbd19fSMartin Fuzzey 	1250,
1555dbbd19fSMartin Fuzzey 	2500,
1565dbbd19fSMartin Fuzzey 	5000,
1575dbbd19fSMartin Fuzzey 	10000,
1585dbbd19fSMartin Fuzzey 	20000,
1595dbbd19fSMartin Fuzzey 	20000,
1605dbbd19fSMartin Fuzzey 	20000,
1615dbbd19fSMartin Fuzzey 	20000
1625dbbd19fSMartin Fuzzey };
1635dbbd19fSMartin Fuzzey 
1641e79841aSMartin Fuzzey /* Datasheet table 18 (normal mode) */
1651e79841aSMartin Fuzzey static const int mma8452_hp_filter_cutoff[8][4][2] = {
1661e79841aSMartin Fuzzey 	{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },		/* 800 Hz sample */
1671e79841aSMartin Fuzzey 	{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },		/* 400 Hz sample */
1681e79841aSMartin Fuzzey 	{ {8, 0}, {4, 0}, {2, 0}, {1, 0} },		/* 200 Hz sample */
1691e79841aSMartin Fuzzey 	{ {4, 0}, {2, 0}, {1, 0}, {0, 500000} },	/* 100 Hz sample */
1701e79841aSMartin Fuzzey 	{ {2, 0}, {1, 0}, {0, 500000}, {0, 250000} },	/* 50 Hz sample */
1711e79841aSMartin Fuzzey 	{ {2, 0}, {1, 0}, {0, 500000}, {0, 250000} },	/* 12.5 Hz sample */
1721e79841aSMartin Fuzzey 	{ {2, 0}, {1, 0}, {0, 500000}, {0, 250000} },	/* 6.25 Hz sample */
1731e79841aSMartin Fuzzey 	{ {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }	/* 1.56 Hz sample */
1741e79841aSMartin Fuzzey };
1751e79841aSMartin Fuzzey 
176c7eeea93SPeter Meerwald static ssize_t mma8452_show_samp_freq_avail(struct device *dev,
177c7eeea93SPeter Meerwald 				struct device_attribute *attr, char *buf)
178c7eeea93SPeter Meerwald {
179c7eeea93SPeter Meerwald 	return mma8452_show_int_plus_micros(buf, mma8452_samp_freq,
180c7eeea93SPeter Meerwald 		ARRAY_SIZE(mma8452_samp_freq));
181c7eeea93SPeter Meerwald }
182c7eeea93SPeter Meerwald 
183c7eeea93SPeter Meerwald static ssize_t mma8452_show_scale_avail(struct device *dev,
184c7eeea93SPeter Meerwald 				struct device_attribute *attr, char *buf)
185c7eeea93SPeter Meerwald {
186c7eeea93SPeter Meerwald 	return mma8452_show_int_plus_micros(buf, mma8452_scales,
187c7eeea93SPeter Meerwald 		ARRAY_SIZE(mma8452_scales));
188c7eeea93SPeter Meerwald }
189c7eeea93SPeter Meerwald 
1901e79841aSMartin Fuzzey static ssize_t mma8452_show_hp_cutoff_avail(struct device *dev,
1911e79841aSMartin Fuzzey 					    struct device_attribute *attr,
1921e79841aSMartin Fuzzey 					    char *buf)
1931e79841aSMartin Fuzzey {
1941e79841aSMartin Fuzzey 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
1951e79841aSMartin Fuzzey 	struct mma8452_data *data = iio_priv(indio_dev);
1961e79841aSMartin Fuzzey 	int i = mma8452_get_odr_index(data);
1971e79841aSMartin Fuzzey 
1981e79841aSMartin Fuzzey 	return mma8452_show_int_plus_micros(buf, mma8452_hp_filter_cutoff[i],
1991e79841aSMartin Fuzzey 		ARRAY_SIZE(mma8452_hp_filter_cutoff[0]));
2001e79841aSMartin Fuzzey }
2011e79841aSMartin Fuzzey 
202c7eeea93SPeter Meerwald static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(mma8452_show_samp_freq_avail);
203c7eeea93SPeter Meerwald static IIO_DEVICE_ATTR(in_accel_scale_available, S_IRUGO,
204c7eeea93SPeter Meerwald 	mma8452_show_scale_avail, NULL, 0);
2051e79841aSMartin Fuzzey static IIO_DEVICE_ATTR(in_accel_filter_high_pass_3db_frequency_available,
2061e79841aSMartin Fuzzey 			S_IRUGO, mma8452_show_hp_cutoff_avail, NULL, 0);
207c7eeea93SPeter Meerwald 
208c7eeea93SPeter Meerwald static int mma8452_get_samp_freq_index(struct mma8452_data *data,
209c7eeea93SPeter Meerwald 	int val, int val2)
210c7eeea93SPeter Meerwald {
211c7eeea93SPeter Meerwald 	return mma8452_get_int_plus_micros_index(mma8452_samp_freq,
212c7eeea93SPeter Meerwald 		ARRAY_SIZE(mma8452_samp_freq), val, val2);
213c7eeea93SPeter Meerwald }
214c7eeea93SPeter Meerwald 
215c7eeea93SPeter Meerwald static int mma8452_get_scale_index(struct mma8452_data *data,
216c7eeea93SPeter Meerwald 	int val, int val2)
217c7eeea93SPeter Meerwald {
218c7eeea93SPeter Meerwald 	return mma8452_get_int_plus_micros_index(mma8452_scales,
219c7eeea93SPeter Meerwald 		ARRAY_SIZE(mma8452_scales), val, val2);
220c7eeea93SPeter Meerwald }
221c7eeea93SPeter Meerwald 
2221e79841aSMartin Fuzzey static int mma8452_get_hp_filter_index(struct mma8452_data *data,
2231e79841aSMartin Fuzzey 				       int val, int val2)
2241e79841aSMartin Fuzzey {
2251e79841aSMartin Fuzzey 	int i = mma8452_get_odr_index(data);
2261e79841aSMartin Fuzzey 
2271e79841aSMartin Fuzzey 	return mma8452_get_int_plus_micros_index(mma8452_hp_filter_cutoff[i],
228001fceb9SHartmut Knaack 		ARRAY_SIZE(mma8452_hp_filter_cutoff[0]), val, val2);
2291e79841aSMartin Fuzzey }
2301e79841aSMartin Fuzzey 
2311e79841aSMartin Fuzzey static int mma8452_read_hp_filter(struct mma8452_data *data, int *hz, int *uHz)
2321e79841aSMartin Fuzzey {
2331e79841aSMartin Fuzzey 	int i, ret;
2341e79841aSMartin Fuzzey 
2351e79841aSMartin Fuzzey 	ret = i2c_smbus_read_byte_data(data->client, MMA8452_HP_FILTER_CUTOFF);
2361e79841aSMartin Fuzzey 	if (ret < 0)
2371e79841aSMartin Fuzzey 		return ret;
2381e79841aSMartin Fuzzey 
2391e79841aSMartin Fuzzey 	i = mma8452_get_odr_index(data);
2401e79841aSMartin Fuzzey 	ret &= MMA8452_HP_FILTER_CUTOFF_SEL_MASK;
2411e79841aSMartin Fuzzey 	*hz = mma8452_hp_filter_cutoff[i][ret][0];
2421e79841aSMartin Fuzzey 	*uHz = mma8452_hp_filter_cutoff[i][ret][1];
2431e79841aSMartin Fuzzey 
2441e79841aSMartin Fuzzey 	return 0;
2451e79841aSMartin Fuzzey }
2461e79841aSMartin Fuzzey 
247c7eeea93SPeter Meerwald static int mma8452_read_raw(struct iio_dev *indio_dev,
248c7eeea93SPeter Meerwald 			    struct iio_chan_spec const *chan,
249c7eeea93SPeter Meerwald 			    int *val, int *val2, long mask)
250c7eeea93SPeter Meerwald {
251c7eeea93SPeter Meerwald 	struct mma8452_data *data = iio_priv(indio_dev);
252c7eeea93SPeter Meerwald 	__be16 buffer[3];
253c7eeea93SPeter Meerwald 	int i, ret;
254c7eeea93SPeter Meerwald 
255c7eeea93SPeter Meerwald 	switch (mask) {
256c7eeea93SPeter Meerwald 	case IIO_CHAN_INFO_RAW:
257c7eeea93SPeter Meerwald 		if (iio_buffer_enabled(indio_dev))
258c7eeea93SPeter Meerwald 			return -EBUSY;
259c7eeea93SPeter Meerwald 
260c7eeea93SPeter Meerwald 		mutex_lock(&data->lock);
261c7eeea93SPeter Meerwald 		ret = mma8452_read(data, buffer);
262c7eeea93SPeter Meerwald 		mutex_unlock(&data->lock);
263c7eeea93SPeter Meerwald 		if (ret < 0)
264c7eeea93SPeter Meerwald 			return ret;
265c7eeea93SPeter Meerwald 		*val = sign_extend32(
266c7eeea93SPeter Meerwald 			be16_to_cpu(buffer[chan->scan_index]) >> 4, 11);
267c7eeea93SPeter Meerwald 		return IIO_VAL_INT;
268c7eeea93SPeter Meerwald 	case IIO_CHAN_INFO_SCALE:
269c7eeea93SPeter Meerwald 		i = data->data_cfg & MMA8452_DATA_CFG_FS_MASK;
270c7eeea93SPeter Meerwald 		*val = mma8452_scales[i][0];
271c7eeea93SPeter Meerwald 		*val2 = mma8452_scales[i][1];
272c7eeea93SPeter Meerwald 		return IIO_VAL_INT_PLUS_MICRO;
273c7eeea93SPeter Meerwald 	case IIO_CHAN_INFO_SAMP_FREQ:
2745dbbd19fSMartin Fuzzey 		i = mma8452_get_odr_index(data);
275c7eeea93SPeter Meerwald 		*val = mma8452_samp_freq[i][0];
276c7eeea93SPeter Meerwald 		*val2 = mma8452_samp_freq[i][1];
277c7eeea93SPeter Meerwald 		return IIO_VAL_INT_PLUS_MICRO;
278c7eeea93SPeter Meerwald 	case IIO_CHAN_INFO_CALIBBIAS:
279c7eeea93SPeter Meerwald 		ret = i2c_smbus_read_byte_data(data->client, MMA8452_OFF_X +
280c7eeea93SPeter Meerwald 			chan->scan_index);
281c7eeea93SPeter Meerwald 		if (ret < 0)
282c7eeea93SPeter Meerwald 			return ret;
283c7eeea93SPeter Meerwald 		*val = sign_extend32(ret, 7);
284c7eeea93SPeter Meerwald 		return IIO_VAL_INT;
2851e79841aSMartin Fuzzey 	case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
2861e79841aSMartin Fuzzey 		if (data->data_cfg & MMA8452_DATA_CFG_HPF_MASK) {
2871e79841aSMartin Fuzzey 			ret = mma8452_read_hp_filter(data, val, val2);
2881e79841aSMartin Fuzzey 			if (ret < 0)
2891e79841aSMartin Fuzzey 				return ret;
2901e79841aSMartin Fuzzey 		} else {
2911e79841aSMartin Fuzzey 			*val = 0;
2921e79841aSMartin Fuzzey 			*val2 = 0;
2931e79841aSMartin Fuzzey 		}
2941e79841aSMartin Fuzzey 		return IIO_VAL_INT_PLUS_MICRO;
295c7eeea93SPeter Meerwald 	}
296c7eeea93SPeter Meerwald 	return -EINVAL;
297c7eeea93SPeter Meerwald }
298c7eeea93SPeter Meerwald 
299c7eeea93SPeter Meerwald static int mma8452_standby(struct mma8452_data *data)
300c7eeea93SPeter Meerwald {
301c7eeea93SPeter Meerwald 	return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1,
302c7eeea93SPeter Meerwald 		data->ctrl_reg1 & ~MMA8452_CTRL_ACTIVE);
303c7eeea93SPeter Meerwald }
304c7eeea93SPeter Meerwald 
305c7eeea93SPeter Meerwald static int mma8452_active(struct mma8452_data *data)
306c7eeea93SPeter Meerwald {
307c7eeea93SPeter Meerwald 	return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1,
308c7eeea93SPeter Meerwald 		data->ctrl_reg1);
309c7eeea93SPeter Meerwald }
310c7eeea93SPeter Meerwald 
311c7eeea93SPeter Meerwald static int mma8452_change_config(struct mma8452_data *data, u8 reg, u8 val)
312c7eeea93SPeter Meerwald {
313c7eeea93SPeter Meerwald 	int ret;
314c7eeea93SPeter Meerwald 
315c7eeea93SPeter Meerwald 	mutex_lock(&data->lock);
316c7eeea93SPeter Meerwald 
317c7eeea93SPeter Meerwald 	/* config can only be changed when in standby */
318c7eeea93SPeter Meerwald 	ret = mma8452_standby(data);
319c7eeea93SPeter Meerwald 	if (ret < 0)
320c7eeea93SPeter Meerwald 		goto fail;
321c7eeea93SPeter Meerwald 
322c7eeea93SPeter Meerwald 	ret = i2c_smbus_write_byte_data(data->client, reg, val);
323c7eeea93SPeter Meerwald 	if (ret < 0)
324c7eeea93SPeter Meerwald 		goto fail;
325c7eeea93SPeter Meerwald 
326c7eeea93SPeter Meerwald 	ret = mma8452_active(data);
327c7eeea93SPeter Meerwald 	if (ret < 0)
328c7eeea93SPeter Meerwald 		goto fail;
329c7eeea93SPeter Meerwald 
330c7eeea93SPeter Meerwald 	ret = 0;
331c7eeea93SPeter Meerwald fail:
332c7eeea93SPeter Meerwald 	mutex_unlock(&data->lock);
333c7eeea93SPeter Meerwald 	return ret;
334c7eeea93SPeter Meerwald }
335c7eeea93SPeter Meerwald 
3361e79841aSMartin Fuzzey static int mma8452_set_hp_filter_frequency(struct mma8452_data *data,
3371e79841aSMartin Fuzzey 					   int val, int val2)
3381e79841aSMartin Fuzzey {
3391e79841aSMartin Fuzzey 	int i, reg;
3401e79841aSMartin Fuzzey 
3411e79841aSMartin Fuzzey 	i = mma8452_get_hp_filter_index(data, val, val2);
3421e79841aSMartin Fuzzey 	if (i < 0)
343b9fddcdbSHartmut Knaack 		return i;
3441e79841aSMartin Fuzzey 
3451e79841aSMartin Fuzzey 	reg = i2c_smbus_read_byte_data(data->client,
3461e79841aSMartin Fuzzey 				       MMA8452_HP_FILTER_CUTOFF);
3471e79841aSMartin Fuzzey 	if (reg < 0)
3481e79841aSMartin Fuzzey 		return reg;
3491e79841aSMartin Fuzzey 	reg &= ~MMA8452_HP_FILTER_CUTOFF_SEL_MASK;
3501e79841aSMartin Fuzzey 	reg |= i;
3511e79841aSMartin Fuzzey 
3521e79841aSMartin Fuzzey 	return mma8452_change_config(data, MMA8452_HP_FILTER_CUTOFF, reg);
3531e79841aSMartin Fuzzey }
3541e79841aSMartin Fuzzey 
355c7eeea93SPeter Meerwald static int mma8452_write_raw(struct iio_dev *indio_dev,
356c7eeea93SPeter Meerwald 			     struct iio_chan_spec const *chan,
357c7eeea93SPeter Meerwald 			     int val, int val2, long mask)
358c7eeea93SPeter Meerwald {
359c7eeea93SPeter Meerwald 	struct mma8452_data *data = iio_priv(indio_dev);
3601e79841aSMartin Fuzzey 	int i, ret;
361c7eeea93SPeter Meerwald 
362c7eeea93SPeter Meerwald 	if (iio_buffer_enabled(indio_dev))
363c7eeea93SPeter Meerwald 		return -EBUSY;
364c7eeea93SPeter Meerwald 
365c7eeea93SPeter Meerwald 	switch (mask) {
366c7eeea93SPeter Meerwald 	case IIO_CHAN_INFO_SAMP_FREQ:
367c7eeea93SPeter Meerwald 		i = mma8452_get_samp_freq_index(data, val, val2);
368c7eeea93SPeter Meerwald 		if (i < 0)
369b9fddcdbSHartmut Knaack 			return i;
370c7eeea93SPeter Meerwald 
371c7eeea93SPeter Meerwald 		data->ctrl_reg1 &= ~MMA8452_CTRL_DR_MASK;
372c7eeea93SPeter Meerwald 		data->ctrl_reg1 |= i << MMA8452_CTRL_DR_SHIFT;
373c7eeea93SPeter Meerwald 		return mma8452_change_config(data, MMA8452_CTRL_REG1,
374c7eeea93SPeter Meerwald 			data->ctrl_reg1);
375c7eeea93SPeter Meerwald 	case IIO_CHAN_INFO_SCALE:
376c7eeea93SPeter Meerwald 		i = mma8452_get_scale_index(data, val, val2);
377c7eeea93SPeter Meerwald 		if (i < 0)
378b9fddcdbSHartmut Knaack 			return i;
379c7eeea93SPeter Meerwald 		data->data_cfg &= ~MMA8452_DATA_CFG_FS_MASK;
380c7eeea93SPeter Meerwald 		data->data_cfg |= i;
381c7eeea93SPeter Meerwald 		return mma8452_change_config(data, MMA8452_DATA_CFG,
382c7eeea93SPeter Meerwald 			data->data_cfg);
383c7eeea93SPeter Meerwald 	case IIO_CHAN_INFO_CALIBBIAS:
384c7eeea93SPeter Meerwald 		if (val < -128 || val > 127)
385c7eeea93SPeter Meerwald 			return -EINVAL;
386c7eeea93SPeter Meerwald 		return mma8452_change_config(data, MMA8452_OFF_X +
387c7eeea93SPeter Meerwald 			chan->scan_index, val);
3881e79841aSMartin Fuzzey 
3891e79841aSMartin Fuzzey 	case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
3901e79841aSMartin Fuzzey 		if (val == 0 && val2 == 0) {
3911e79841aSMartin Fuzzey 			data->data_cfg &= ~MMA8452_DATA_CFG_HPF_MASK;
3921e79841aSMartin Fuzzey 		} else {
3931e79841aSMartin Fuzzey 			data->data_cfg |= MMA8452_DATA_CFG_HPF_MASK;
3941e79841aSMartin Fuzzey 			ret = mma8452_set_hp_filter_frequency(data, val, val2);
3951e79841aSMartin Fuzzey 			if (ret < 0)
3961e79841aSMartin Fuzzey 				return ret;
3971e79841aSMartin Fuzzey 		}
3981e79841aSMartin Fuzzey 		return mma8452_change_config(data, MMA8452_DATA_CFG,
3991e79841aSMartin Fuzzey 						data->data_cfg);
4001e79841aSMartin Fuzzey 
401c7eeea93SPeter Meerwald 	default:
402c7eeea93SPeter Meerwald 		return -EINVAL;
403c7eeea93SPeter Meerwald 	}
404c7eeea93SPeter Meerwald }
405c7eeea93SPeter Meerwald 
40628e34278SMartin Fuzzey static int mma8452_read_thresh(struct iio_dev *indio_dev,
40728e34278SMartin Fuzzey 			       const struct iio_chan_spec *chan,
40828e34278SMartin Fuzzey 			       enum iio_event_type type,
40928e34278SMartin Fuzzey 			       enum iio_event_direction dir,
41028e34278SMartin Fuzzey 			       enum iio_event_info info,
41128e34278SMartin Fuzzey 			       int *val, int *val2)
41228e34278SMartin Fuzzey {
41328e34278SMartin Fuzzey 	struct mma8452_data *data = iio_priv(indio_dev);
4145dbbd19fSMartin Fuzzey 	int ret, us;
41528e34278SMartin Fuzzey 
4165dbbd19fSMartin Fuzzey 	switch (info) {
4175dbbd19fSMartin Fuzzey 	case IIO_EV_INFO_VALUE:
4185dbbd19fSMartin Fuzzey 		ret = i2c_smbus_read_byte_data(data->client,
4195dbbd19fSMartin Fuzzey 					       MMA8452_TRANSIENT_THS);
42028e34278SMartin Fuzzey 		if (ret < 0)
42128e34278SMartin Fuzzey 			return ret;
42228e34278SMartin Fuzzey 
42328e34278SMartin Fuzzey 		*val = ret & MMA8452_TRANSIENT_THS_MASK;
42428e34278SMartin Fuzzey 		return IIO_VAL_INT;
4255dbbd19fSMartin Fuzzey 
4265dbbd19fSMartin Fuzzey 	case IIO_EV_INFO_PERIOD:
4275dbbd19fSMartin Fuzzey 		ret = i2c_smbus_read_byte_data(data->client,
4285dbbd19fSMartin Fuzzey 					       MMA8452_TRANSIENT_COUNT);
4295dbbd19fSMartin Fuzzey 		if (ret < 0)
4305dbbd19fSMartin Fuzzey 			return ret;
4315dbbd19fSMartin Fuzzey 
4325dbbd19fSMartin Fuzzey 		us = ret * mma8452_transient_time_step_us[
4335dbbd19fSMartin Fuzzey 				mma8452_get_odr_index(data)];
4345dbbd19fSMartin Fuzzey 		*val = us / USEC_PER_SEC;
4355dbbd19fSMartin Fuzzey 		*val2 = us % USEC_PER_SEC;
4365dbbd19fSMartin Fuzzey 		return IIO_VAL_INT_PLUS_MICRO;
4375dbbd19fSMartin Fuzzey 
4381e79841aSMartin Fuzzey 	case IIO_EV_INFO_HIGH_PASS_FILTER_3DB:
4391e79841aSMartin Fuzzey 		ret = i2c_smbus_read_byte_data(data->client,
4401e79841aSMartin Fuzzey 					       MMA8452_TRANSIENT_CFG);
4411e79841aSMartin Fuzzey 		if (ret < 0)
4421e79841aSMartin Fuzzey 			return ret;
4431e79841aSMartin Fuzzey 
4441e79841aSMartin Fuzzey 		if (ret & MMA8452_TRANSIENT_CFG_HPF_BYP) {
4451e79841aSMartin Fuzzey 			*val = 0;
4461e79841aSMartin Fuzzey 			*val2 = 0;
4471e79841aSMartin Fuzzey 		} else {
4481e79841aSMartin Fuzzey 			ret = mma8452_read_hp_filter(data, val, val2);
4491e79841aSMartin Fuzzey 			if (ret < 0)
4501e79841aSMartin Fuzzey 				return ret;
4511e79841aSMartin Fuzzey 		}
4521e79841aSMartin Fuzzey 		return IIO_VAL_INT_PLUS_MICRO;
4531e79841aSMartin Fuzzey 
4545dbbd19fSMartin Fuzzey 	default:
4555dbbd19fSMartin Fuzzey 		return -EINVAL;
4565dbbd19fSMartin Fuzzey 	}
45728e34278SMartin Fuzzey }
45828e34278SMartin Fuzzey 
45928e34278SMartin Fuzzey static int mma8452_write_thresh(struct iio_dev *indio_dev,
46028e34278SMartin Fuzzey 				const struct iio_chan_spec *chan,
46128e34278SMartin Fuzzey 				enum iio_event_type type,
46228e34278SMartin Fuzzey 				enum iio_event_direction dir,
46328e34278SMartin Fuzzey 				enum iio_event_info info,
46428e34278SMartin Fuzzey 				int val, int val2)
46528e34278SMartin Fuzzey {
46628e34278SMartin Fuzzey 	struct mma8452_data *data = iio_priv(indio_dev);
4671e79841aSMartin Fuzzey 	int ret, reg, steps;
46828e34278SMartin Fuzzey 
4695dbbd19fSMartin Fuzzey 	switch (info) {
4705dbbd19fSMartin Fuzzey 	case IIO_EV_INFO_VALUE:
47111218226SHartmut Knaack 		if (val < 0 || val > MMA8452_TRANSIENT_THS_MASK)
47211218226SHartmut Knaack 			return -EINVAL;
47311218226SHartmut Knaack 
47411218226SHartmut Knaack 		return mma8452_change_config(data, MMA8452_TRANSIENT_THS, val);
4755dbbd19fSMartin Fuzzey 
4765dbbd19fSMartin Fuzzey 	case IIO_EV_INFO_PERIOD:
4775dbbd19fSMartin Fuzzey 		steps = (val * USEC_PER_SEC + val2) /
4785dbbd19fSMartin Fuzzey 				mma8452_transient_time_step_us[
4795dbbd19fSMartin Fuzzey 					mma8452_get_odr_index(data)];
4805dbbd19fSMartin Fuzzey 
48111218226SHartmut Knaack 		if (steps < 0 || steps > 0xff)
4825dbbd19fSMartin Fuzzey 			return -EINVAL;
4835dbbd19fSMartin Fuzzey 
4845dbbd19fSMartin Fuzzey 		return mma8452_change_config(data, MMA8452_TRANSIENT_COUNT,
4855dbbd19fSMartin Fuzzey 					     steps);
4861e79841aSMartin Fuzzey 	case IIO_EV_INFO_HIGH_PASS_FILTER_3DB:
4871e79841aSMartin Fuzzey 		reg = i2c_smbus_read_byte_data(data->client,
4881e79841aSMartin Fuzzey 					       MMA8452_TRANSIENT_CFG);
4891e79841aSMartin Fuzzey 		if (reg < 0)
4901e79841aSMartin Fuzzey 			return reg;
4911e79841aSMartin Fuzzey 
4921e79841aSMartin Fuzzey 		if (val == 0 && val2 == 0) {
4931e79841aSMartin Fuzzey 			reg |= MMA8452_TRANSIENT_CFG_HPF_BYP;
4941e79841aSMartin Fuzzey 		} else {
4951e79841aSMartin Fuzzey 			reg &= ~MMA8452_TRANSIENT_CFG_HPF_BYP;
4961e79841aSMartin Fuzzey 			ret = mma8452_set_hp_filter_frequency(data, val, val2);
4971e79841aSMartin Fuzzey 			if (ret < 0)
4981e79841aSMartin Fuzzey 				return ret;
4991e79841aSMartin Fuzzey 		}
5001e79841aSMartin Fuzzey 		return mma8452_change_config(data, MMA8452_TRANSIENT_CFG, reg);
5011e79841aSMartin Fuzzey 
5025dbbd19fSMartin Fuzzey 	default:
5035dbbd19fSMartin Fuzzey 		return -EINVAL;
5045dbbd19fSMartin Fuzzey 	}
50528e34278SMartin Fuzzey }
50628e34278SMartin Fuzzey 
50728e34278SMartin Fuzzey static int mma8452_read_event_config(struct iio_dev *indio_dev,
50828e34278SMartin Fuzzey 				     const struct iio_chan_spec *chan,
50928e34278SMartin Fuzzey 				     enum iio_event_type type,
51028e34278SMartin Fuzzey 				     enum iio_event_direction dir)
51128e34278SMartin Fuzzey {
51228e34278SMartin Fuzzey 	struct mma8452_data *data = iio_priv(indio_dev);
51328e34278SMartin Fuzzey 	int ret;
51428e34278SMartin Fuzzey 
51528e34278SMartin Fuzzey 	ret = i2c_smbus_read_byte_data(data->client, MMA8452_TRANSIENT_CFG);
51628e34278SMartin Fuzzey 	if (ret < 0)
51728e34278SMartin Fuzzey 		return ret;
51828e34278SMartin Fuzzey 
51928e34278SMartin Fuzzey 	return ret & MMA8452_TRANSIENT_CFG_CHAN(chan->scan_index) ? 1 : 0;
52028e34278SMartin Fuzzey }
52128e34278SMartin Fuzzey 
52228e34278SMartin Fuzzey static int mma8452_write_event_config(struct iio_dev *indio_dev,
52328e34278SMartin Fuzzey 				      const struct iio_chan_spec *chan,
52428e34278SMartin Fuzzey 				      enum iio_event_type type,
52528e34278SMartin Fuzzey 				      enum iio_event_direction dir,
52628e34278SMartin Fuzzey 				      int state)
52728e34278SMartin Fuzzey {
52828e34278SMartin Fuzzey 	struct mma8452_data *data = iio_priv(indio_dev);
52928e34278SMartin Fuzzey 	int val;
53028e34278SMartin Fuzzey 
53128e34278SMartin Fuzzey 	val = i2c_smbus_read_byte_data(data->client, MMA8452_TRANSIENT_CFG);
53228e34278SMartin Fuzzey 	if (val < 0)
53328e34278SMartin Fuzzey 		return val;
53428e34278SMartin Fuzzey 
53528e34278SMartin Fuzzey 	if (state)
53628e34278SMartin Fuzzey 		val |= MMA8452_TRANSIENT_CFG_CHAN(chan->scan_index);
53728e34278SMartin Fuzzey 	else
53828e34278SMartin Fuzzey 		val &= ~MMA8452_TRANSIENT_CFG_CHAN(chan->scan_index);
53928e34278SMartin Fuzzey 
54028e34278SMartin Fuzzey 	val |= MMA8452_TRANSIENT_CFG_ELE;
54128e34278SMartin Fuzzey 
54228e34278SMartin Fuzzey 	return mma8452_change_config(data, MMA8452_TRANSIENT_CFG, val);
54328e34278SMartin Fuzzey }
54428e34278SMartin Fuzzey 
54528e34278SMartin Fuzzey static void mma8452_transient_interrupt(struct iio_dev *indio_dev)
54628e34278SMartin Fuzzey {
54728e34278SMartin Fuzzey 	struct mma8452_data *data = iio_priv(indio_dev);
54828e34278SMartin Fuzzey 	s64 ts = iio_get_time_ns();
54928e34278SMartin Fuzzey 	int src;
55028e34278SMartin Fuzzey 
55128e34278SMartin Fuzzey 	src = i2c_smbus_read_byte_data(data->client, MMA8452_TRANSIENT_SRC);
55228e34278SMartin Fuzzey 	if (src < 0)
55328e34278SMartin Fuzzey 		return;
55428e34278SMartin Fuzzey 
55528e34278SMartin Fuzzey 	if (src & MMA8452_TRANSIENT_SRC_XTRANSE)
55628e34278SMartin Fuzzey 		iio_push_event(indio_dev,
55728e34278SMartin Fuzzey 			       IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X,
55828e34278SMartin Fuzzey 						  IIO_EV_TYPE_THRESH,
55928e34278SMartin Fuzzey 						  IIO_EV_DIR_RISING),
56028e34278SMartin Fuzzey 			       ts);
56128e34278SMartin Fuzzey 
56228e34278SMartin Fuzzey 	if (src & MMA8452_TRANSIENT_SRC_YTRANSE)
56328e34278SMartin Fuzzey 		iio_push_event(indio_dev,
56428e34278SMartin Fuzzey 			       IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Y,
56528e34278SMartin Fuzzey 						  IIO_EV_TYPE_THRESH,
56628e34278SMartin Fuzzey 						  IIO_EV_DIR_RISING),
56728e34278SMartin Fuzzey 			       ts);
56828e34278SMartin Fuzzey 
56928e34278SMartin Fuzzey 	if (src & MMA8452_TRANSIENT_SRC_ZTRANSE)
57028e34278SMartin Fuzzey 		iio_push_event(indio_dev,
57128e34278SMartin Fuzzey 			       IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Z,
57228e34278SMartin Fuzzey 						  IIO_EV_TYPE_THRESH,
57328e34278SMartin Fuzzey 						  IIO_EV_DIR_RISING),
57428e34278SMartin Fuzzey 			       ts);
57528e34278SMartin Fuzzey }
57628e34278SMartin Fuzzey 
57728e34278SMartin Fuzzey static irqreturn_t mma8452_interrupt(int irq, void *p)
57828e34278SMartin Fuzzey {
57928e34278SMartin Fuzzey 	struct iio_dev *indio_dev = p;
58028e34278SMartin Fuzzey 	struct mma8452_data *data = iio_priv(indio_dev);
581ae6d9ce0SMartin Fuzzey 	int ret = IRQ_NONE;
58228e34278SMartin Fuzzey 	int src;
58328e34278SMartin Fuzzey 
58428e34278SMartin Fuzzey 	src = i2c_smbus_read_byte_data(data->client, MMA8452_INT_SRC);
58528e34278SMartin Fuzzey 	if (src < 0)
58628e34278SMartin Fuzzey 		return IRQ_NONE;
58728e34278SMartin Fuzzey 
588ae6d9ce0SMartin Fuzzey 	if (src & MMA8452_INT_DRDY) {
589ae6d9ce0SMartin Fuzzey 		iio_trigger_poll_chained(indio_dev->trig);
590ae6d9ce0SMartin Fuzzey 		ret = IRQ_HANDLED;
59128e34278SMartin Fuzzey 	}
59228e34278SMartin Fuzzey 
593ae6d9ce0SMartin Fuzzey 	if (src & MMA8452_INT_TRANS) {
594ae6d9ce0SMartin Fuzzey 		mma8452_transient_interrupt(indio_dev);
595ae6d9ce0SMartin Fuzzey 		ret = IRQ_HANDLED;
596ae6d9ce0SMartin Fuzzey 	}
597ae6d9ce0SMartin Fuzzey 
598ae6d9ce0SMartin Fuzzey 	return ret;
59928e34278SMartin Fuzzey }
60028e34278SMartin Fuzzey 
601c7eeea93SPeter Meerwald static irqreturn_t mma8452_trigger_handler(int irq, void *p)
602c7eeea93SPeter Meerwald {
603c7eeea93SPeter Meerwald 	struct iio_poll_func *pf = p;
604c7eeea93SPeter Meerwald 	struct iio_dev *indio_dev = pf->indio_dev;
605c7eeea93SPeter Meerwald 	struct mma8452_data *data = iio_priv(indio_dev);
606c7eeea93SPeter Meerwald 	u8 buffer[16]; /* 3 16-bit channels + padding + ts */
607c7eeea93SPeter Meerwald 	int ret;
608c7eeea93SPeter Meerwald 
609c7eeea93SPeter Meerwald 	ret = mma8452_read(data, (__be16 *) buffer);
610c7eeea93SPeter Meerwald 	if (ret < 0)
611c7eeea93SPeter Meerwald 		goto done;
612c7eeea93SPeter Meerwald 
613c7eeea93SPeter Meerwald 	iio_push_to_buffers_with_timestamp(indio_dev, buffer,
614c7eeea93SPeter Meerwald 		iio_get_time_ns());
615c7eeea93SPeter Meerwald 
616c7eeea93SPeter Meerwald done:
617c7eeea93SPeter Meerwald 	iio_trigger_notify_done(indio_dev->trig);
618c7eeea93SPeter Meerwald 	return IRQ_HANDLED;
619c7eeea93SPeter Meerwald }
620c7eeea93SPeter Meerwald 
6212a17698cSMartin Fuzzey static int mma8452_reg_access_dbg(struct iio_dev *indio_dev,
6222a17698cSMartin Fuzzey 				  unsigned reg, unsigned writeval,
6232a17698cSMartin Fuzzey 				  unsigned *readval)
6242a17698cSMartin Fuzzey {
6252a17698cSMartin Fuzzey 	int ret;
6262a17698cSMartin Fuzzey 	struct mma8452_data *data = iio_priv(indio_dev);
6272a17698cSMartin Fuzzey 
6282a17698cSMartin Fuzzey 	if (reg > MMA8452_MAX_REG)
6292a17698cSMartin Fuzzey 		return -EINVAL;
6302a17698cSMartin Fuzzey 
6312a17698cSMartin Fuzzey 	if (!readval)
6322a17698cSMartin Fuzzey 		return mma8452_change_config(data, reg, writeval);
6332a17698cSMartin Fuzzey 
6342a17698cSMartin Fuzzey 	ret = i2c_smbus_read_byte_data(data->client, reg);
6352a17698cSMartin Fuzzey 	if (ret < 0)
6362a17698cSMartin Fuzzey 		return ret;
6372a17698cSMartin Fuzzey 
6382a17698cSMartin Fuzzey 	*readval = ret;
6392a17698cSMartin Fuzzey 
6402a17698cSMartin Fuzzey 	return 0;
6412a17698cSMartin Fuzzey }
6422a17698cSMartin Fuzzey 
64328e34278SMartin Fuzzey static const struct iio_event_spec mma8452_transient_event[] = {
64428e34278SMartin Fuzzey 	{
64528e34278SMartin Fuzzey 		.type = IIO_EV_TYPE_THRESH,
64628e34278SMartin Fuzzey 		.dir = IIO_EV_DIR_RISING,
64728e34278SMartin Fuzzey 		.mask_separate = BIT(IIO_EV_INFO_ENABLE),
6485dbbd19fSMartin Fuzzey 		.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
6491e79841aSMartin Fuzzey 					BIT(IIO_EV_INFO_PERIOD) |
6501e79841aSMartin Fuzzey 					BIT(IIO_EV_INFO_HIGH_PASS_FILTER_3DB)
65128e34278SMartin Fuzzey 	},
65228e34278SMartin Fuzzey };
65328e34278SMartin Fuzzey 
65428e34278SMartin Fuzzey /*
65528e34278SMartin Fuzzey  * Threshold is configured in fixed 8G/127 steps regardless of
65628e34278SMartin Fuzzey  * currently selected scale for measurement.
65728e34278SMartin Fuzzey  */
65828e34278SMartin Fuzzey static IIO_CONST_ATTR_NAMED(accel_transient_scale, in_accel_scale, "0.617742");
65928e34278SMartin Fuzzey 
66028e34278SMartin Fuzzey static struct attribute *mma8452_event_attributes[] = {
66128e34278SMartin Fuzzey 	&iio_const_attr_accel_transient_scale.dev_attr.attr,
66228e34278SMartin Fuzzey 	NULL,
66328e34278SMartin Fuzzey };
66428e34278SMartin Fuzzey 
66528e34278SMartin Fuzzey static struct attribute_group mma8452_event_attribute_group = {
66628e34278SMartin Fuzzey 	.attrs = mma8452_event_attributes,
66728e34278SMartin Fuzzey 	.name = "events",
66828e34278SMartin Fuzzey };
66928e34278SMartin Fuzzey 
670c7eeea93SPeter Meerwald #define MMA8452_CHANNEL(axis, idx) { \
671c7eeea93SPeter Meerwald 	.type = IIO_ACCEL, \
672c7eeea93SPeter Meerwald 	.modified = 1, \
673c7eeea93SPeter Meerwald 	.channel2 = IIO_MOD_##axis, \
674c7eeea93SPeter Meerwald 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
675c7eeea93SPeter Meerwald 		BIT(IIO_CHAN_INFO_CALIBBIAS), \
676c7eeea93SPeter Meerwald 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
6771e79841aSMartin Fuzzey 		BIT(IIO_CHAN_INFO_SCALE) | \
6781e79841aSMartin Fuzzey 		BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \
679c7eeea93SPeter Meerwald 	.scan_index = idx, \
680c7eeea93SPeter Meerwald 	.scan_type = { \
681c7eeea93SPeter Meerwald 		.sign = 's', \
682c7eeea93SPeter Meerwald 		.realbits = 12, \
683c7eeea93SPeter Meerwald 		.storagebits = 16, \
684c7eeea93SPeter Meerwald 		.shift = 4, \
685c7eeea93SPeter Meerwald 		.endianness = IIO_BE, \
686c7eeea93SPeter Meerwald 	}, \
68728e34278SMartin Fuzzey 	.event_spec = mma8452_transient_event, \
68828e34278SMartin Fuzzey 	.num_event_specs = ARRAY_SIZE(mma8452_transient_event), \
689c7eeea93SPeter Meerwald }
690c7eeea93SPeter Meerwald 
691c7eeea93SPeter Meerwald static const struct iio_chan_spec mma8452_channels[] = {
692c7eeea93SPeter Meerwald 	MMA8452_CHANNEL(X, 0),
693c7eeea93SPeter Meerwald 	MMA8452_CHANNEL(Y, 1),
694c7eeea93SPeter Meerwald 	MMA8452_CHANNEL(Z, 2),
695c7eeea93SPeter Meerwald 	IIO_CHAN_SOFT_TIMESTAMP(3),
696c7eeea93SPeter Meerwald };
697c7eeea93SPeter Meerwald 
698c7eeea93SPeter Meerwald static struct attribute *mma8452_attributes[] = {
699c7eeea93SPeter Meerwald 	&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
700c7eeea93SPeter Meerwald 	&iio_dev_attr_in_accel_scale_available.dev_attr.attr,
7011e79841aSMartin Fuzzey 	&iio_dev_attr_in_accel_filter_high_pass_3db_frequency_available.dev_attr.attr,
702c7eeea93SPeter Meerwald 	NULL
703c7eeea93SPeter Meerwald };
704c7eeea93SPeter Meerwald 
705c7eeea93SPeter Meerwald static const struct attribute_group mma8452_group = {
706c7eeea93SPeter Meerwald 	.attrs = mma8452_attributes,
707c7eeea93SPeter Meerwald };
708c7eeea93SPeter Meerwald 
709c7eeea93SPeter Meerwald static const struct iio_info mma8452_info = {
710c7eeea93SPeter Meerwald 	.attrs = &mma8452_group,
711c7eeea93SPeter Meerwald 	.read_raw = &mma8452_read_raw,
712c7eeea93SPeter Meerwald 	.write_raw = &mma8452_write_raw,
71328e34278SMartin Fuzzey 	.event_attrs = &mma8452_event_attribute_group,
71428e34278SMartin Fuzzey 	.read_event_value = &mma8452_read_thresh,
71528e34278SMartin Fuzzey 	.write_event_value = &mma8452_write_thresh,
71628e34278SMartin Fuzzey 	.read_event_config = &mma8452_read_event_config,
71728e34278SMartin Fuzzey 	.write_event_config = &mma8452_write_event_config,
7182a17698cSMartin Fuzzey 	.debugfs_reg_access = &mma8452_reg_access_dbg,
719c7eeea93SPeter Meerwald 	.driver_module = THIS_MODULE,
720c7eeea93SPeter Meerwald };
721c7eeea93SPeter Meerwald 
722c7eeea93SPeter Meerwald static const unsigned long mma8452_scan_masks[] = {0x7, 0};
723c7eeea93SPeter Meerwald 
724ae6d9ce0SMartin Fuzzey static int mma8452_data_rdy_trigger_set_state(struct iio_trigger *trig,
725ae6d9ce0SMartin Fuzzey 					      bool state)
726ae6d9ce0SMartin Fuzzey {
727ae6d9ce0SMartin Fuzzey 	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
728ae6d9ce0SMartin Fuzzey 	struct mma8452_data *data = iio_priv(indio_dev);
729ae6d9ce0SMartin Fuzzey 	int reg;
730ae6d9ce0SMartin Fuzzey 
731ae6d9ce0SMartin Fuzzey 	reg = i2c_smbus_read_byte_data(data->client, MMA8452_CTRL_REG4);
732ae6d9ce0SMartin Fuzzey 	if (reg < 0)
733ae6d9ce0SMartin Fuzzey 		return reg;
734ae6d9ce0SMartin Fuzzey 
735ae6d9ce0SMartin Fuzzey 	if (state)
736ae6d9ce0SMartin Fuzzey 		reg |= MMA8452_INT_DRDY;
737ae6d9ce0SMartin Fuzzey 	else
738ae6d9ce0SMartin Fuzzey 		reg &= ~MMA8452_INT_DRDY;
739ae6d9ce0SMartin Fuzzey 
740ae6d9ce0SMartin Fuzzey 	return mma8452_change_config(data, MMA8452_CTRL_REG4, reg);
741ae6d9ce0SMartin Fuzzey }
742ae6d9ce0SMartin Fuzzey 
743ae6d9ce0SMartin Fuzzey static int mma8452_validate_device(struct iio_trigger *trig,
744ae6d9ce0SMartin Fuzzey 				   struct iio_dev *indio_dev)
745ae6d9ce0SMartin Fuzzey {
746ae6d9ce0SMartin Fuzzey 	struct iio_dev *indio = iio_trigger_get_drvdata(trig);
747ae6d9ce0SMartin Fuzzey 
748ae6d9ce0SMartin Fuzzey 	if (indio != indio_dev)
749ae6d9ce0SMartin Fuzzey 		return -EINVAL;
750ae6d9ce0SMartin Fuzzey 
751ae6d9ce0SMartin Fuzzey 	return 0;
752ae6d9ce0SMartin Fuzzey }
753ae6d9ce0SMartin Fuzzey 
754ae6d9ce0SMartin Fuzzey static const struct iio_trigger_ops mma8452_trigger_ops = {
755ae6d9ce0SMartin Fuzzey 	.set_trigger_state = mma8452_data_rdy_trigger_set_state,
756ae6d9ce0SMartin Fuzzey 	.validate_device = mma8452_validate_device,
757ae6d9ce0SMartin Fuzzey 	.owner = THIS_MODULE,
758ae6d9ce0SMartin Fuzzey };
759ae6d9ce0SMartin Fuzzey 
760ae6d9ce0SMartin Fuzzey static int mma8452_trigger_setup(struct iio_dev *indio_dev)
761ae6d9ce0SMartin Fuzzey {
762ae6d9ce0SMartin Fuzzey 	struct mma8452_data *data = iio_priv(indio_dev);
763ae6d9ce0SMartin Fuzzey 	struct iio_trigger *trig;
764ae6d9ce0SMartin Fuzzey 	int ret;
765ae6d9ce0SMartin Fuzzey 
766ae6d9ce0SMartin Fuzzey 	trig = devm_iio_trigger_alloc(&data->client->dev, "%s-dev%d",
767ae6d9ce0SMartin Fuzzey 				      indio_dev->name,
768ae6d9ce0SMartin Fuzzey 				      indio_dev->id);
769ae6d9ce0SMartin Fuzzey 	if (!trig)
770ae6d9ce0SMartin Fuzzey 		return -ENOMEM;
771ae6d9ce0SMartin Fuzzey 
772ae6d9ce0SMartin Fuzzey 	trig->dev.parent = &data->client->dev;
773ae6d9ce0SMartin Fuzzey 	trig->ops = &mma8452_trigger_ops;
774ae6d9ce0SMartin Fuzzey 	iio_trigger_set_drvdata(trig, indio_dev);
775ae6d9ce0SMartin Fuzzey 
776ae6d9ce0SMartin Fuzzey 	ret = iio_trigger_register(trig);
777ae6d9ce0SMartin Fuzzey 	if (ret)
778ae6d9ce0SMartin Fuzzey 		return ret;
779ae6d9ce0SMartin Fuzzey 
780ae6d9ce0SMartin Fuzzey 	indio_dev->trig = trig;
781ae6d9ce0SMartin Fuzzey 	return 0;
782ae6d9ce0SMartin Fuzzey }
783ae6d9ce0SMartin Fuzzey 
784ae6d9ce0SMartin Fuzzey static void mma8452_trigger_cleanup(struct iio_dev *indio_dev)
785ae6d9ce0SMartin Fuzzey {
786ae6d9ce0SMartin Fuzzey 	if (indio_dev->trig)
787ae6d9ce0SMartin Fuzzey 		iio_trigger_unregister(indio_dev->trig);
788ae6d9ce0SMartin Fuzzey }
789ae6d9ce0SMartin Fuzzey 
790ecabae71SMartin Fuzzey static int mma8452_reset(struct i2c_client *client)
791ecabae71SMartin Fuzzey {
792ecabae71SMartin Fuzzey 	int i;
793ecabae71SMartin Fuzzey 	int ret;
794ecabae71SMartin Fuzzey 
795ecabae71SMartin Fuzzey 	ret = i2c_smbus_write_byte_data(client,	MMA8452_CTRL_REG2,
796ecabae71SMartin Fuzzey 					MMA8452_CTRL_REG2_RST);
797ecabae71SMartin Fuzzey 	if (ret < 0)
798ecabae71SMartin Fuzzey 		return ret;
799ecabae71SMartin Fuzzey 
800ecabae71SMartin Fuzzey 	for (i = 0; i < 10; i++) {
801ecabae71SMartin Fuzzey 		usleep_range(100, 200);
802ecabae71SMartin Fuzzey 		ret = i2c_smbus_read_byte_data(client, MMA8452_CTRL_REG2);
803ecabae71SMartin Fuzzey 		if (ret == -EIO)
804ecabae71SMartin Fuzzey 			continue; /* I2C comm reset */
805ecabae71SMartin Fuzzey 		if (ret < 0)
806ecabae71SMartin Fuzzey 			return ret;
807ecabae71SMartin Fuzzey 		if (!(ret & MMA8452_CTRL_REG2_RST))
808ecabae71SMartin Fuzzey 			return 0;
809ecabae71SMartin Fuzzey 	}
810ecabae71SMartin Fuzzey 
811ecabae71SMartin Fuzzey 	return -ETIMEDOUT;
812ecabae71SMartin Fuzzey }
813ecabae71SMartin Fuzzey 
814c7eeea93SPeter Meerwald static int mma8452_probe(struct i2c_client *client,
815c7eeea93SPeter Meerwald 			 const struct i2c_device_id *id)
816c7eeea93SPeter Meerwald {
817c7eeea93SPeter Meerwald 	struct mma8452_data *data;
818c7eeea93SPeter Meerwald 	struct iio_dev *indio_dev;
819c7eeea93SPeter Meerwald 	int ret;
820c7eeea93SPeter Meerwald 
821c7eeea93SPeter Meerwald 	ret = i2c_smbus_read_byte_data(client, MMA8452_WHO_AM_I);
822c7eeea93SPeter Meerwald 	if (ret < 0)
823c7eeea93SPeter Meerwald 		return ret;
824c7eeea93SPeter Meerwald 	if (ret != MMA8452_DEVICE_ID)
825c7eeea93SPeter Meerwald 		return -ENODEV;
826c7eeea93SPeter Meerwald 
827c7eeea93SPeter Meerwald 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
828c7eeea93SPeter Meerwald 	if (!indio_dev)
829c7eeea93SPeter Meerwald 		return -ENOMEM;
830c7eeea93SPeter Meerwald 
831c7eeea93SPeter Meerwald 	data = iio_priv(indio_dev);
832c7eeea93SPeter Meerwald 	data->client = client;
833c7eeea93SPeter Meerwald 	mutex_init(&data->lock);
834c7eeea93SPeter Meerwald 
835c7eeea93SPeter Meerwald 	i2c_set_clientdata(client, indio_dev);
836c7eeea93SPeter Meerwald 	indio_dev->info = &mma8452_info;
837c7eeea93SPeter Meerwald 	indio_dev->name = id->name;
838c7eeea93SPeter Meerwald 	indio_dev->dev.parent = &client->dev;
839c7eeea93SPeter Meerwald 	indio_dev->modes = INDIO_DIRECT_MODE;
840c7eeea93SPeter Meerwald 	indio_dev->channels = mma8452_channels;
841c7eeea93SPeter Meerwald 	indio_dev->num_channels = ARRAY_SIZE(mma8452_channels);
842c7eeea93SPeter Meerwald 	indio_dev->available_scan_masks = mma8452_scan_masks;
843c7eeea93SPeter Meerwald 
844ecabae71SMartin Fuzzey 	ret = mma8452_reset(client);
845c7eeea93SPeter Meerwald 	if (ret < 0)
846c7eeea93SPeter Meerwald 		return ret;
847c7eeea93SPeter Meerwald 
848c7eeea93SPeter Meerwald 	data->data_cfg = MMA8452_DATA_CFG_FS_2G;
849c7eeea93SPeter Meerwald 	ret = i2c_smbus_write_byte_data(client, MMA8452_DATA_CFG,
850c7eeea93SPeter Meerwald 		data->data_cfg);
851c7eeea93SPeter Meerwald 	if (ret < 0)
852c7eeea93SPeter Meerwald 		return ret;
853c7eeea93SPeter Meerwald 
85428e34278SMartin Fuzzey 	/*
85528e34278SMartin Fuzzey 	 * By default set transient threshold to max to avoid events if
85628e34278SMartin Fuzzey 	 * enabling without configuring threshold.
85728e34278SMartin Fuzzey 	 */
85828e34278SMartin Fuzzey 	ret = i2c_smbus_write_byte_data(client, MMA8452_TRANSIENT_THS,
85928e34278SMartin Fuzzey 					MMA8452_TRANSIENT_THS_MASK);
86028e34278SMartin Fuzzey 	if (ret < 0)
86128e34278SMartin Fuzzey 		return ret;
86228e34278SMartin Fuzzey 
86328e34278SMartin Fuzzey 	if (client->irq) {
86428e34278SMartin Fuzzey 		/*
86528e34278SMartin Fuzzey 		 * Although we enable the transient interrupt source once and
86628e34278SMartin Fuzzey 		 * for all here the transient event detection itself is not
86728e34278SMartin Fuzzey 		 * enabled until userspace asks for it by
86828e34278SMartin Fuzzey 		 * mma8452_write_event_config()
86928e34278SMartin Fuzzey 		 */
870ae6d9ce0SMartin Fuzzey 		int supported_interrupts = MMA8452_INT_DRDY | MMA8452_INT_TRANS;
871ae6d9ce0SMartin Fuzzey 		int enabled_interrupts = MMA8452_INT_TRANS;
87228e34278SMartin Fuzzey 
87328e34278SMartin Fuzzey 		/* Assume wired to INT1 pin */
87428e34278SMartin Fuzzey 		ret = i2c_smbus_write_byte_data(client,
87528e34278SMartin Fuzzey 						MMA8452_CTRL_REG5,
87628e34278SMartin Fuzzey 						supported_interrupts);
87728e34278SMartin Fuzzey 		if (ret < 0)
87828e34278SMartin Fuzzey 			return ret;
87928e34278SMartin Fuzzey 
88028e34278SMartin Fuzzey 		ret = i2c_smbus_write_byte_data(client,
88128e34278SMartin Fuzzey 						MMA8452_CTRL_REG4,
882ae6d9ce0SMartin Fuzzey 						enabled_interrupts);
883ae6d9ce0SMartin Fuzzey 		if (ret < 0)
884ae6d9ce0SMartin Fuzzey 			return ret;
885ae6d9ce0SMartin Fuzzey 
886ae6d9ce0SMartin Fuzzey 		ret = mma8452_trigger_setup(indio_dev);
88728e34278SMartin Fuzzey 		if (ret < 0)
88828e34278SMartin Fuzzey 			return ret;
88928e34278SMartin Fuzzey 	}
89028e34278SMartin Fuzzey 
891ecabae71SMartin Fuzzey 	data->ctrl_reg1 = MMA8452_CTRL_ACTIVE |
892ecabae71SMartin Fuzzey 		(MMA8452_CTRL_DR_DEFAULT << MMA8452_CTRL_DR_SHIFT);
893ecabae71SMartin Fuzzey 	ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG1,
894ecabae71SMartin Fuzzey 					data->ctrl_reg1);
895ecabae71SMartin Fuzzey 	if (ret < 0)
896ae6d9ce0SMartin Fuzzey 		goto trigger_cleanup;
897ecabae71SMartin Fuzzey 
898c7eeea93SPeter Meerwald 	ret = iio_triggered_buffer_setup(indio_dev, NULL,
899c7eeea93SPeter Meerwald 		mma8452_trigger_handler, NULL);
900c7eeea93SPeter Meerwald 	if (ret < 0)
901ae6d9ce0SMartin Fuzzey 		goto trigger_cleanup;
902c7eeea93SPeter Meerwald 
90328e34278SMartin Fuzzey 	if (client->irq) {
90428e34278SMartin Fuzzey 		ret = devm_request_threaded_irq(&client->dev,
90528e34278SMartin Fuzzey 						client->irq,
90628e34278SMartin Fuzzey 						NULL, mma8452_interrupt,
90728e34278SMartin Fuzzey 						IRQF_TRIGGER_LOW | IRQF_ONESHOT,
90828e34278SMartin Fuzzey 						client->name, indio_dev);
90928e34278SMartin Fuzzey 		if (ret)
91028e34278SMartin Fuzzey 			goto buffer_cleanup;
91128e34278SMartin Fuzzey 	}
91228e34278SMartin Fuzzey 
913c7eeea93SPeter Meerwald 	ret = iio_device_register(indio_dev);
914c7eeea93SPeter Meerwald 	if (ret < 0)
915c7eeea93SPeter Meerwald 		goto buffer_cleanup;
91628e34278SMartin Fuzzey 
917c7eeea93SPeter Meerwald 	return 0;
918c7eeea93SPeter Meerwald 
919c7eeea93SPeter Meerwald buffer_cleanup:
920c7eeea93SPeter Meerwald 	iio_triggered_buffer_cleanup(indio_dev);
921ae6d9ce0SMartin Fuzzey 
922ae6d9ce0SMartin Fuzzey trigger_cleanup:
923ae6d9ce0SMartin Fuzzey 	mma8452_trigger_cleanup(indio_dev);
924ae6d9ce0SMartin Fuzzey 
925c7eeea93SPeter Meerwald 	return ret;
926c7eeea93SPeter Meerwald }
927c7eeea93SPeter Meerwald 
928c7eeea93SPeter Meerwald static int mma8452_remove(struct i2c_client *client)
929c7eeea93SPeter Meerwald {
930c7eeea93SPeter Meerwald 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
931c7eeea93SPeter Meerwald 
932c7eeea93SPeter Meerwald 	iio_device_unregister(indio_dev);
933c7eeea93SPeter Meerwald 	iio_triggered_buffer_cleanup(indio_dev);
934ae6d9ce0SMartin Fuzzey 	mma8452_trigger_cleanup(indio_dev);
935c7eeea93SPeter Meerwald 	mma8452_standby(iio_priv(indio_dev));
936c7eeea93SPeter Meerwald 
937c7eeea93SPeter Meerwald 	return 0;
938c7eeea93SPeter Meerwald }
939c7eeea93SPeter Meerwald 
940c7eeea93SPeter Meerwald #ifdef CONFIG_PM_SLEEP
941c7eeea93SPeter Meerwald static int mma8452_suspend(struct device *dev)
942c7eeea93SPeter Meerwald {
943c7eeea93SPeter Meerwald 	return mma8452_standby(iio_priv(i2c_get_clientdata(
944c7eeea93SPeter Meerwald 		to_i2c_client(dev))));
945c7eeea93SPeter Meerwald }
946c7eeea93SPeter Meerwald 
947c7eeea93SPeter Meerwald static int mma8452_resume(struct device *dev)
948c7eeea93SPeter Meerwald {
949c7eeea93SPeter Meerwald 	return mma8452_active(iio_priv(i2c_get_clientdata(
950c7eeea93SPeter Meerwald 		to_i2c_client(dev))));
951c7eeea93SPeter Meerwald }
952c7eeea93SPeter Meerwald 
953c7eeea93SPeter Meerwald static SIMPLE_DEV_PM_OPS(mma8452_pm_ops, mma8452_suspend, mma8452_resume);
954c7eeea93SPeter Meerwald #define MMA8452_PM_OPS (&mma8452_pm_ops)
955c7eeea93SPeter Meerwald #else
956c7eeea93SPeter Meerwald #define MMA8452_PM_OPS NULL
957c7eeea93SPeter Meerwald #endif
958c7eeea93SPeter Meerwald 
959c7eeea93SPeter Meerwald static const struct i2c_device_id mma8452_id[] = {
960c7eeea93SPeter Meerwald 	{ "mma8452", 0 },
961c7eeea93SPeter Meerwald 	{ }
962c7eeea93SPeter Meerwald };
963c7eeea93SPeter Meerwald MODULE_DEVICE_TABLE(i2c, mma8452_id);
964c7eeea93SPeter Meerwald 
965a3fb96a8SMartin Fuzzey static const struct of_device_id mma8452_dt_ids[] = {
966a3fb96a8SMartin Fuzzey 	{ .compatible = "fsl,mma8452" },
967a3fb96a8SMartin Fuzzey 	{ }
968a3fb96a8SMartin Fuzzey };
969119c4fceSJavier Martinez Canillas MODULE_DEVICE_TABLE(of, mma8452_dt_ids);
970a3fb96a8SMartin Fuzzey 
971c7eeea93SPeter Meerwald static struct i2c_driver mma8452_driver = {
972c7eeea93SPeter Meerwald 	.driver = {
973c7eeea93SPeter Meerwald 		.name	= "mma8452",
974a3fb96a8SMartin Fuzzey 		.of_match_table = of_match_ptr(mma8452_dt_ids),
975c7eeea93SPeter Meerwald 		.pm	= MMA8452_PM_OPS,
976c7eeea93SPeter Meerwald 	},
977c7eeea93SPeter Meerwald 	.probe = mma8452_probe,
978c7eeea93SPeter Meerwald 	.remove = mma8452_remove,
979c7eeea93SPeter Meerwald 	.id_table = mma8452_id,
980c7eeea93SPeter Meerwald };
981c7eeea93SPeter Meerwald module_i2c_driver(mma8452_driver);
982c7eeea93SPeter Meerwald 
983c7eeea93SPeter Meerwald MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
984c7eeea93SPeter Meerwald MODULE_DESCRIPTION("Freescale MMA8452 accelerometer driver");
985c7eeea93SPeter Meerwald MODULE_LICENSE("GPL");
986