xref: /linux/drivers/iio/accel/mma8452.c (revision c3cdd6e48e35b7a02f28e301ef30a87ff3cd6527)
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>
25*c3cdd6e4SMartin Kepplinger #include <linux/of_device.h>
26c7eeea93SPeter Meerwald 
27c7eeea93SPeter Meerwald #define MMA8452_STATUS				0x00
2869abff81SHartmut Knaack #define  MMA8452_STATUS_DRDY			(BIT(2) | BIT(1) | BIT(0))
29c7eeea93SPeter Meerwald #define MMA8452_OUT_X				0x01 /* MSB first, 12-bit  */
30c7eeea93SPeter Meerwald #define MMA8452_OUT_Y				0x03
31c7eeea93SPeter Meerwald #define MMA8452_OUT_Z				0x05
3228e34278SMartin Fuzzey #define MMA8452_INT_SRC				0x0c
33c7eeea93SPeter Meerwald #define MMA8452_WHO_AM_I			0x0d
34c7eeea93SPeter Meerwald #define MMA8452_DATA_CFG			0x0e
3569abff81SHartmut Knaack #define  MMA8452_DATA_CFG_FS_MASK		GENMASK(1, 0)
3669abff81SHartmut Knaack #define  MMA8452_DATA_CFG_FS_2G			0
3769abff81SHartmut Knaack #define  MMA8452_DATA_CFG_FS_4G			1
3869abff81SHartmut Knaack #define  MMA8452_DATA_CFG_FS_8G			2
3969abff81SHartmut Knaack #define  MMA8452_DATA_CFG_HPF_MASK		BIT(4)
401e79841aSMartin Fuzzey #define MMA8452_HP_FILTER_CUTOFF		0x0f
4169abff81SHartmut Knaack #define  MMA8452_HP_FILTER_CUTOFF_SEL_MASK	GENMASK(1, 0)
4228e34278SMartin Fuzzey #define MMA8452_TRANSIENT_CFG			0x1d
431e79841aSMartin Fuzzey #define  MMA8452_TRANSIENT_CFG_HPF_BYP		BIT(0)
4469abff81SHartmut Knaack #define  MMA8452_TRANSIENT_CFG_CHAN(chan)	BIT(chan + 1)
4569abff81SHartmut Knaack #define  MMA8452_TRANSIENT_CFG_ELE		BIT(4)
4628e34278SMartin Fuzzey #define MMA8452_TRANSIENT_SRC			0x1e
4728e34278SMartin Fuzzey #define  MMA8452_TRANSIENT_SRC_XTRANSE		BIT(1)
4828e34278SMartin Fuzzey #define  MMA8452_TRANSIENT_SRC_YTRANSE		BIT(3)
4928e34278SMartin Fuzzey #define  MMA8452_TRANSIENT_SRC_ZTRANSE		BIT(5)
5028e34278SMartin Fuzzey #define MMA8452_TRANSIENT_THS			0x1f
5169abff81SHartmut Knaack #define  MMA8452_TRANSIENT_THS_MASK		GENMASK(6, 0)
525dbbd19fSMartin Fuzzey #define MMA8452_TRANSIENT_COUNT			0x20
53c7eeea93SPeter Meerwald #define MMA8452_CTRL_REG1			0x2a
5469abff81SHartmut Knaack #define  MMA8452_CTRL_ACTIVE			BIT(0)
5569abff81SHartmut Knaack #define  MMA8452_CTRL_DR_MASK			GENMASK(5, 3)
5669abff81SHartmut Knaack #define  MMA8452_CTRL_DR_SHIFT			3
5769abff81SHartmut Knaack #define  MMA8452_CTRL_DR_DEFAULT		0x4 /* 50 Hz sample frequency */
58c7eeea93SPeter Meerwald #define MMA8452_CTRL_REG2			0x2b
59ecabae71SMartin Fuzzey #define  MMA8452_CTRL_REG2_RST			BIT(6)
6028e34278SMartin Fuzzey #define MMA8452_CTRL_REG4			0x2d
6128e34278SMartin Fuzzey #define MMA8452_CTRL_REG5			0x2e
6269abff81SHartmut Knaack #define MMA8452_OFF_X				0x2f
6369abff81SHartmut Knaack #define MMA8452_OFF_Y				0x30
6469abff81SHartmut Knaack #define MMA8452_OFF_Z				0x31
65c7eeea93SPeter Meerwald 
662a17698cSMartin Fuzzey #define MMA8452_MAX_REG				0x31
672a17698cSMartin Fuzzey 
68ae6d9ce0SMartin Fuzzey #define  MMA8452_INT_DRDY			BIT(0)
6928e34278SMartin Fuzzey #define  MMA8452_INT_TRANS			BIT(5)
7028e34278SMartin Fuzzey 
71c7eeea93SPeter Meerwald #define  MMA8452_DEVICE_ID			0x2a
72c7eeea93SPeter Meerwald 
73c7eeea93SPeter Meerwald struct mma8452_data {
74c7eeea93SPeter Meerwald 	struct i2c_client *client;
75c7eeea93SPeter Meerwald 	struct mutex lock;
76c7eeea93SPeter Meerwald 	u8 ctrl_reg1;
77c7eeea93SPeter Meerwald 	u8 data_cfg;
78*c3cdd6e4SMartin Kepplinger 	const struct mma_chip_info *chip_info;
79*c3cdd6e4SMartin Kepplinger };
80*c3cdd6e4SMartin Kepplinger 
81*c3cdd6e4SMartin Kepplinger /**
82*c3cdd6e4SMartin Kepplinger  * struct mma_chip_info - chip specific data for Freescale's accelerometers
83*c3cdd6e4SMartin Kepplinger  * @chip_id:			WHO_AM_I register's value
84*c3cdd6e4SMartin Kepplinger  * @channels:			struct iio_chan_spec matching the device's
85*c3cdd6e4SMartin Kepplinger  *				capabilities
86*c3cdd6e4SMartin Kepplinger  * @num_channels:		number of channels
87*c3cdd6e4SMartin Kepplinger  * @mma_scales:			scale factors for converting register values
88*c3cdd6e4SMartin Kepplinger  *				to m/s^2; 3 modes: 2g, 4g, 8g; 2 integers
89*c3cdd6e4SMartin Kepplinger  *				per mode: m/s^2 and micro m/s^2
90*c3cdd6e4SMartin Kepplinger  * @ev_cfg:			event config register address
91*c3cdd6e4SMartin Kepplinger  * @ev_cfg_ele:			latch bit in event config register
92*c3cdd6e4SMartin Kepplinger  * @ev_cfg_chan_shift:		number of the bit to enable events in X
93*c3cdd6e4SMartin Kepplinger  *				direction; in event config register
94*c3cdd6e4SMartin Kepplinger  * @ev_src:			event source register address
95*c3cdd6e4SMartin Kepplinger  * @ev_src_xe:			bit in event source register that indicates
96*c3cdd6e4SMartin Kepplinger  *				an event in X direction
97*c3cdd6e4SMartin Kepplinger  * @ev_src_ye:			bit in event source register that indicates
98*c3cdd6e4SMartin Kepplinger  *				an event in Y direction
99*c3cdd6e4SMartin Kepplinger  * @ev_src_ze:			bit in event source register that indicates
100*c3cdd6e4SMartin Kepplinger  *				an event in Z direction
101*c3cdd6e4SMartin Kepplinger  * @ev_ths:			event threshold register address
102*c3cdd6e4SMartin Kepplinger  * @ev_ths_mask:		mask for the threshold value
103*c3cdd6e4SMartin Kepplinger  * @ev_count:			event count (period) register address
104*c3cdd6e4SMartin Kepplinger  *
105*c3cdd6e4SMartin Kepplinger  * Since not all chips supported by the driver support comparing high pass
106*c3cdd6e4SMartin Kepplinger  * filtered data for events (interrupts), different interrupt sources are
107*c3cdd6e4SMartin Kepplinger  * used for different chips and the relevant registers are included here.
108*c3cdd6e4SMartin Kepplinger  */
109*c3cdd6e4SMartin Kepplinger struct mma_chip_info {
110*c3cdd6e4SMartin Kepplinger 	u8 chip_id;
111*c3cdd6e4SMartin Kepplinger 	const struct iio_chan_spec *channels;
112*c3cdd6e4SMartin Kepplinger 	int num_channels;
113*c3cdd6e4SMartin Kepplinger 	const int mma_scales[3][2];
114*c3cdd6e4SMartin Kepplinger 	u8 ev_cfg;
115*c3cdd6e4SMartin Kepplinger 	u8 ev_cfg_ele;
116*c3cdd6e4SMartin Kepplinger 	u8 ev_cfg_chan_shift;
117*c3cdd6e4SMartin Kepplinger 	u8 ev_src;
118*c3cdd6e4SMartin Kepplinger 	u8 ev_src_xe;
119*c3cdd6e4SMartin Kepplinger 	u8 ev_src_ye;
120*c3cdd6e4SMartin Kepplinger 	u8 ev_src_ze;
121*c3cdd6e4SMartin Kepplinger 	u8 ev_ths;
122*c3cdd6e4SMartin Kepplinger 	u8 ev_ths_mask;
123*c3cdd6e4SMartin Kepplinger 	u8 ev_count;
124c7eeea93SPeter Meerwald };
125c7eeea93SPeter Meerwald 
126c7eeea93SPeter Meerwald static int mma8452_drdy(struct mma8452_data *data)
127c7eeea93SPeter Meerwald {
128c7eeea93SPeter Meerwald 	int tries = 150;
129c7eeea93SPeter Meerwald 
130c7eeea93SPeter Meerwald 	while (tries-- > 0) {
131c7eeea93SPeter Meerwald 		int ret = i2c_smbus_read_byte_data(data->client,
132c7eeea93SPeter Meerwald 			MMA8452_STATUS);
133c7eeea93SPeter Meerwald 		if (ret < 0)
134c7eeea93SPeter Meerwald 			return ret;
135c7eeea93SPeter Meerwald 		if ((ret & MMA8452_STATUS_DRDY) == MMA8452_STATUS_DRDY)
136c7eeea93SPeter Meerwald 			return 0;
137686027fbSHartmut Knaack 
138c7eeea93SPeter Meerwald 		msleep(20);
139c7eeea93SPeter Meerwald 	}
140c7eeea93SPeter Meerwald 
141c7eeea93SPeter Meerwald 	dev_err(&data->client->dev, "data not ready\n");
142686027fbSHartmut Knaack 
143c7eeea93SPeter Meerwald 	return -EIO;
144c7eeea93SPeter Meerwald }
145c7eeea93SPeter Meerwald 
146c7eeea93SPeter Meerwald static int mma8452_read(struct mma8452_data *data, __be16 buf[3])
147c7eeea93SPeter Meerwald {
148c7eeea93SPeter Meerwald 	int ret = mma8452_drdy(data);
149686027fbSHartmut Knaack 
150c7eeea93SPeter Meerwald 	if (ret < 0)
151c7eeea93SPeter Meerwald 		return ret;
152686027fbSHartmut Knaack 
153686027fbSHartmut Knaack 	return i2c_smbus_read_i2c_block_data(data->client, MMA8452_OUT_X,
154686027fbSHartmut Knaack 					     3 * sizeof(__be16), (u8 *)buf);
155c7eeea93SPeter Meerwald }
156c7eeea93SPeter Meerwald 
157686027fbSHartmut Knaack static ssize_t mma8452_show_int_plus_micros(char *buf, const int (*vals)[2],
158686027fbSHartmut Knaack 					    int n)
159c7eeea93SPeter Meerwald {
160c7eeea93SPeter Meerwald 	size_t len = 0;
161c7eeea93SPeter Meerwald 
162c7eeea93SPeter Meerwald 	while (n-- > 0)
163686027fbSHartmut Knaack 		len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06d ",
164686027fbSHartmut Knaack 				 vals[n][0], vals[n][1]);
165c7eeea93SPeter Meerwald 
166c7eeea93SPeter Meerwald 	/* replace trailing space by newline */
167c7eeea93SPeter Meerwald 	buf[len - 1] = '\n';
168c7eeea93SPeter Meerwald 
169c7eeea93SPeter Meerwald 	return len;
170c7eeea93SPeter Meerwald }
171c7eeea93SPeter Meerwald 
172c7eeea93SPeter Meerwald static int mma8452_get_int_plus_micros_index(const int (*vals)[2], int n,
173c7eeea93SPeter Meerwald 					     int val, int val2)
174c7eeea93SPeter Meerwald {
175c7eeea93SPeter Meerwald 	while (n-- > 0)
176c7eeea93SPeter Meerwald 		if (val == vals[n][0] && val2 == vals[n][1])
177c7eeea93SPeter Meerwald 			return n;
178c7eeea93SPeter Meerwald 
179c7eeea93SPeter Meerwald 	return -EINVAL;
180c7eeea93SPeter Meerwald }
181c7eeea93SPeter Meerwald 
1825dbbd19fSMartin Fuzzey static int mma8452_get_odr_index(struct mma8452_data *data)
1835dbbd19fSMartin Fuzzey {
1845dbbd19fSMartin Fuzzey 	return (data->ctrl_reg1 & MMA8452_CTRL_DR_MASK) >>
1855dbbd19fSMartin Fuzzey 			MMA8452_CTRL_DR_SHIFT;
1865dbbd19fSMartin Fuzzey }
1875dbbd19fSMartin Fuzzey 
188c7eeea93SPeter Meerwald static const int mma8452_samp_freq[8][2] = {
189c7eeea93SPeter Meerwald 	{800, 0}, {400, 0}, {200, 0}, {100, 0}, {50, 0}, {12, 500000},
190c7eeea93SPeter Meerwald 	{6, 250000}, {1, 560000}
191c7eeea93SPeter Meerwald };
192c7eeea93SPeter Meerwald 
1935dbbd19fSMartin Fuzzey /* Datasheet table 35  (step time vs sample frequency) */
1945dbbd19fSMartin Fuzzey static const int mma8452_transient_time_step_us[8] = {
1955dbbd19fSMartin Fuzzey 	1250,
1965dbbd19fSMartin Fuzzey 	2500,
1975dbbd19fSMartin Fuzzey 	5000,
1985dbbd19fSMartin Fuzzey 	10000,
1995dbbd19fSMartin Fuzzey 	20000,
2005dbbd19fSMartin Fuzzey 	20000,
2015dbbd19fSMartin Fuzzey 	20000,
2025dbbd19fSMartin Fuzzey 	20000
2035dbbd19fSMartin Fuzzey };
2045dbbd19fSMartin Fuzzey 
2051e79841aSMartin Fuzzey /* Datasheet table 18 (normal mode) */
2061e79841aSMartin Fuzzey static const int mma8452_hp_filter_cutoff[8][4][2] = {
2071e79841aSMartin Fuzzey 	{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },		/* 800 Hz sample */
2081e79841aSMartin Fuzzey 	{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },		/* 400 Hz sample */
2091e79841aSMartin Fuzzey 	{ {8, 0}, {4, 0}, {2, 0}, {1, 0} },		/* 200 Hz sample */
2101e79841aSMartin Fuzzey 	{ {4, 0}, {2, 0}, {1, 0}, {0, 500000} },	/* 100 Hz sample */
2111e79841aSMartin Fuzzey 	{ {2, 0}, {1, 0}, {0, 500000}, {0, 250000} },	/* 50 Hz sample */
2121e79841aSMartin Fuzzey 	{ {2, 0}, {1, 0}, {0, 500000}, {0, 250000} },	/* 12.5 Hz sample */
2131e79841aSMartin Fuzzey 	{ {2, 0}, {1, 0}, {0, 500000}, {0, 250000} },	/* 6.25 Hz sample */
2141e79841aSMartin Fuzzey 	{ {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }	/* 1.56 Hz sample */
2151e79841aSMartin Fuzzey };
2161e79841aSMartin Fuzzey 
217c7eeea93SPeter Meerwald static ssize_t mma8452_show_samp_freq_avail(struct device *dev,
218686027fbSHartmut Knaack 					    struct device_attribute *attr,
219686027fbSHartmut Knaack 					    char *buf)
220c7eeea93SPeter Meerwald {
221c7eeea93SPeter Meerwald 	return mma8452_show_int_plus_micros(buf, mma8452_samp_freq,
222c7eeea93SPeter Meerwald 					    ARRAY_SIZE(mma8452_samp_freq));
223c7eeea93SPeter Meerwald }
224c7eeea93SPeter Meerwald 
225c7eeea93SPeter Meerwald static ssize_t mma8452_show_scale_avail(struct device *dev,
226686027fbSHartmut Knaack 					struct device_attribute *attr,
227686027fbSHartmut Knaack 					char *buf)
228c7eeea93SPeter Meerwald {
229*c3cdd6e4SMartin Kepplinger 	struct mma8452_data *data = iio_priv(i2c_get_clientdata(
230*c3cdd6e4SMartin Kepplinger 					     to_i2c_client(dev)));
231*c3cdd6e4SMartin Kepplinger 
232*c3cdd6e4SMartin Kepplinger 	return mma8452_show_int_plus_micros(buf, data->chip_info->mma_scales,
233*c3cdd6e4SMartin Kepplinger 		ARRAY_SIZE(data->chip_info->mma_scales));
234c7eeea93SPeter Meerwald }
235c7eeea93SPeter Meerwald 
2361e79841aSMartin Fuzzey static ssize_t mma8452_show_hp_cutoff_avail(struct device *dev,
2371e79841aSMartin Fuzzey 					    struct device_attribute *attr,
2381e79841aSMartin Fuzzey 					    char *buf)
2391e79841aSMartin Fuzzey {
2401e79841aSMartin Fuzzey 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
2411e79841aSMartin Fuzzey 	struct mma8452_data *data = iio_priv(indio_dev);
2421e79841aSMartin Fuzzey 	int i = mma8452_get_odr_index(data);
2431e79841aSMartin Fuzzey 
2441e79841aSMartin Fuzzey 	return mma8452_show_int_plus_micros(buf, mma8452_hp_filter_cutoff[i],
2451e79841aSMartin Fuzzey 		ARRAY_SIZE(mma8452_hp_filter_cutoff[0]));
2461e79841aSMartin Fuzzey }
2471e79841aSMartin Fuzzey 
248c7eeea93SPeter Meerwald static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(mma8452_show_samp_freq_avail);
249c7eeea93SPeter Meerwald static IIO_DEVICE_ATTR(in_accel_scale_available, S_IRUGO,
250c7eeea93SPeter Meerwald 		       mma8452_show_scale_avail, NULL, 0);
2511e79841aSMartin Fuzzey static IIO_DEVICE_ATTR(in_accel_filter_high_pass_3db_frequency_available,
2521e79841aSMartin Fuzzey 		       S_IRUGO, mma8452_show_hp_cutoff_avail, NULL, 0);
253c7eeea93SPeter Meerwald 
254c7eeea93SPeter Meerwald static int mma8452_get_samp_freq_index(struct mma8452_data *data,
255c7eeea93SPeter Meerwald 				       int val, int val2)
256c7eeea93SPeter Meerwald {
257c7eeea93SPeter Meerwald 	return mma8452_get_int_plus_micros_index(mma8452_samp_freq,
258686027fbSHartmut Knaack 						 ARRAY_SIZE(mma8452_samp_freq),
259686027fbSHartmut Knaack 						 val, val2);
260c7eeea93SPeter Meerwald }
261c7eeea93SPeter Meerwald 
262686027fbSHartmut Knaack static int mma8452_get_scale_index(struct mma8452_data *data, int val, int val2)
263c7eeea93SPeter Meerwald {
264*c3cdd6e4SMartin Kepplinger 	return mma8452_get_int_plus_micros_index(data->chip_info->mma_scales,
265*c3cdd6e4SMartin Kepplinger 			ARRAY_SIZE(data->chip_info->mma_scales), val, val2);
266c7eeea93SPeter Meerwald }
267c7eeea93SPeter Meerwald 
2681e79841aSMartin Fuzzey static int mma8452_get_hp_filter_index(struct mma8452_data *data,
2691e79841aSMartin Fuzzey 				       int val, int val2)
2701e79841aSMartin Fuzzey {
2711e79841aSMartin Fuzzey 	int i = mma8452_get_odr_index(data);
2721e79841aSMartin Fuzzey 
2731e79841aSMartin Fuzzey 	return mma8452_get_int_plus_micros_index(mma8452_hp_filter_cutoff[i],
274001fceb9SHartmut Knaack 		ARRAY_SIZE(mma8452_hp_filter_cutoff[0]), val, val2);
2751e79841aSMartin Fuzzey }
2761e79841aSMartin Fuzzey 
2771e79841aSMartin Fuzzey static int mma8452_read_hp_filter(struct mma8452_data *data, int *hz, int *uHz)
2781e79841aSMartin Fuzzey {
2791e79841aSMartin Fuzzey 	int i, ret;
2801e79841aSMartin Fuzzey 
2811e79841aSMartin Fuzzey 	ret = i2c_smbus_read_byte_data(data->client, MMA8452_HP_FILTER_CUTOFF);
2821e79841aSMartin Fuzzey 	if (ret < 0)
2831e79841aSMartin Fuzzey 		return ret;
2841e79841aSMartin Fuzzey 
2851e79841aSMartin Fuzzey 	i = mma8452_get_odr_index(data);
2861e79841aSMartin Fuzzey 	ret &= MMA8452_HP_FILTER_CUTOFF_SEL_MASK;
2871e79841aSMartin Fuzzey 	*hz = mma8452_hp_filter_cutoff[i][ret][0];
2881e79841aSMartin Fuzzey 	*uHz = mma8452_hp_filter_cutoff[i][ret][1];
2891e79841aSMartin Fuzzey 
2901e79841aSMartin Fuzzey 	return 0;
2911e79841aSMartin Fuzzey }
2921e79841aSMartin Fuzzey 
293c7eeea93SPeter Meerwald static int mma8452_read_raw(struct iio_dev *indio_dev,
294c7eeea93SPeter Meerwald 			    struct iio_chan_spec const *chan,
295c7eeea93SPeter Meerwald 			    int *val, int *val2, long mask)
296c7eeea93SPeter Meerwald {
297c7eeea93SPeter Meerwald 	struct mma8452_data *data = iio_priv(indio_dev);
298c7eeea93SPeter Meerwald 	__be16 buffer[3];
299c7eeea93SPeter Meerwald 	int i, ret;
300c7eeea93SPeter Meerwald 
301c7eeea93SPeter Meerwald 	switch (mask) {
302c7eeea93SPeter Meerwald 	case IIO_CHAN_INFO_RAW:
303c7eeea93SPeter Meerwald 		if (iio_buffer_enabled(indio_dev))
304c7eeea93SPeter Meerwald 			return -EBUSY;
305c7eeea93SPeter Meerwald 
306c7eeea93SPeter Meerwald 		mutex_lock(&data->lock);
307c7eeea93SPeter Meerwald 		ret = mma8452_read(data, buffer);
308c7eeea93SPeter Meerwald 		mutex_unlock(&data->lock);
309c7eeea93SPeter Meerwald 		if (ret < 0)
310c7eeea93SPeter Meerwald 			return ret;
311686027fbSHartmut Knaack 
312*c3cdd6e4SMartin Kepplinger 		*val = sign_extend32(be16_to_cpu(
313*c3cdd6e4SMartin Kepplinger 			buffer[chan->scan_index]) >> chan->scan_type.shift,
314*c3cdd6e4SMartin Kepplinger 			chan->scan_type.realbits - 1);
315686027fbSHartmut Knaack 
316c7eeea93SPeter Meerwald 		return IIO_VAL_INT;
317c7eeea93SPeter Meerwald 	case IIO_CHAN_INFO_SCALE:
318c7eeea93SPeter Meerwald 		i = data->data_cfg & MMA8452_DATA_CFG_FS_MASK;
319*c3cdd6e4SMartin Kepplinger 		*val = data->chip_info->mma_scales[i][0];
320*c3cdd6e4SMartin Kepplinger 		*val2 = data->chip_info->mma_scales[i][1];
321686027fbSHartmut Knaack 
322c7eeea93SPeter Meerwald 		return IIO_VAL_INT_PLUS_MICRO;
323c7eeea93SPeter Meerwald 	case IIO_CHAN_INFO_SAMP_FREQ:
3245dbbd19fSMartin Fuzzey 		i = mma8452_get_odr_index(data);
325c7eeea93SPeter Meerwald 		*val = mma8452_samp_freq[i][0];
326c7eeea93SPeter Meerwald 		*val2 = mma8452_samp_freq[i][1];
327686027fbSHartmut Knaack 
328c7eeea93SPeter Meerwald 		return IIO_VAL_INT_PLUS_MICRO;
329c7eeea93SPeter Meerwald 	case IIO_CHAN_INFO_CALIBBIAS:
330686027fbSHartmut Knaack 		ret = i2c_smbus_read_byte_data(data->client,
331686027fbSHartmut Knaack 					      MMA8452_OFF_X + chan->scan_index);
332c7eeea93SPeter Meerwald 		if (ret < 0)
333c7eeea93SPeter Meerwald 			return ret;
334686027fbSHartmut Knaack 
335c7eeea93SPeter Meerwald 		*val = sign_extend32(ret, 7);
336686027fbSHartmut Knaack 
337c7eeea93SPeter Meerwald 		return IIO_VAL_INT;
3381e79841aSMartin Fuzzey 	case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
3391e79841aSMartin Fuzzey 		if (data->data_cfg & MMA8452_DATA_CFG_HPF_MASK) {
3401e79841aSMartin Fuzzey 			ret = mma8452_read_hp_filter(data, val, val2);
3411e79841aSMartin Fuzzey 			if (ret < 0)
3421e79841aSMartin Fuzzey 				return ret;
3431e79841aSMartin Fuzzey 		} else {
3441e79841aSMartin Fuzzey 			*val = 0;
3451e79841aSMartin Fuzzey 			*val2 = 0;
3461e79841aSMartin Fuzzey 		}
347686027fbSHartmut Knaack 
3481e79841aSMartin Fuzzey 		return IIO_VAL_INT_PLUS_MICRO;
349c7eeea93SPeter Meerwald 	}
350686027fbSHartmut Knaack 
351c7eeea93SPeter Meerwald 	return -EINVAL;
352c7eeea93SPeter Meerwald }
353c7eeea93SPeter Meerwald 
354c7eeea93SPeter Meerwald static int mma8452_standby(struct mma8452_data *data)
355c7eeea93SPeter Meerwald {
356c7eeea93SPeter Meerwald 	return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1,
357c7eeea93SPeter Meerwald 					data->ctrl_reg1 & ~MMA8452_CTRL_ACTIVE);
358c7eeea93SPeter Meerwald }
359c7eeea93SPeter Meerwald 
360c7eeea93SPeter Meerwald static int mma8452_active(struct mma8452_data *data)
361c7eeea93SPeter Meerwald {
362c7eeea93SPeter Meerwald 	return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1,
363c7eeea93SPeter Meerwald 					 data->ctrl_reg1);
364c7eeea93SPeter Meerwald }
365c7eeea93SPeter Meerwald 
366c7eeea93SPeter Meerwald static int mma8452_change_config(struct mma8452_data *data, u8 reg, u8 val)
367c7eeea93SPeter Meerwald {
368c7eeea93SPeter Meerwald 	int ret;
369c7eeea93SPeter Meerwald 
370c7eeea93SPeter Meerwald 	mutex_lock(&data->lock);
371c7eeea93SPeter Meerwald 
372c7eeea93SPeter Meerwald 	/* config can only be changed when in standby */
373c7eeea93SPeter Meerwald 	ret = mma8452_standby(data);
374c7eeea93SPeter Meerwald 	if (ret < 0)
375c7eeea93SPeter Meerwald 		goto fail;
376c7eeea93SPeter Meerwald 
377c7eeea93SPeter Meerwald 	ret = i2c_smbus_write_byte_data(data->client, reg, val);
378c7eeea93SPeter Meerwald 	if (ret < 0)
379c7eeea93SPeter Meerwald 		goto fail;
380c7eeea93SPeter Meerwald 
381c7eeea93SPeter Meerwald 	ret = mma8452_active(data);
382c7eeea93SPeter Meerwald 	if (ret < 0)
383c7eeea93SPeter Meerwald 		goto fail;
384c7eeea93SPeter Meerwald 
385c7eeea93SPeter Meerwald 	ret = 0;
386c7eeea93SPeter Meerwald fail:
387c7eeea93SPeter Meerwald 	mutex_unlock(&data->lock);
388686027fbSHartmut Knaack 
389c7eeea93SPeter Meerwald 	return ret;
390c7eeea93SPeter Meerwald }
391c7eeea93SPeter Meerwald 
3921e79841aSMartin Fuzzey static int mma8452_set_hp_filter_frequency(struct mma8452_data *data,
3931e79841aSMartin Fuzzey 					   int val, int val2)
3941e79841aSMartin Fuzzey {
3951e79841aSMartin Fuzzey 	int i, reg;
3961e79841aSMartin Fuzzey 
3971e79841aSMartin Fuzzey 	i = mma8452_get_hp_filter_index(data, val, val2);
3981e79841aSMartin Fuzzey 	if (i < 0)
399b9fddcdbSHartmut Knaack 		return i;
4001e79841aSMartin Fuzzey 
4011e79841aSMartin Fuzzey 	reg = i2c_smbus_read_byte_data(data->client,
4021e79841aSMartin Fuzzey 				       MMA8452_HP_FILTER_CUTOFF);
4031e79841aSMartin Fuzzey 	if (reg < 0)
4041e79841aSMartin Fuzzey 		return reg;
405686027fbSHartmut Knaack 
4061e79841aSMartin Fuzzey 	reg &= ~MMA8452_HP_FILTER_CUTOFF_SEL_MASK;
4071e79841aSMartin Fuzzey 	reg |= i;
4081e79841aSMartin Fuzzey 
4091e79841aSMartin Fuzzey 	return mma8452_change_config(data, MMA8452_HP_FILTER_CUTOFF, reg);
4101e79841aSMartin Fuzzey }
4111e79841aSMartin Fuzzey 
412c7eeea93SPeter Meerwald static int mma8452_write_raw(struct iio_dev *indio_dev,
413c7eeea93SPeter Meerwald 			     struct iio_chan_spec const *chan,
414c7eeea93SPeter Meerwald 			     int val, int val2, long mask)
415c7eeea93SPeter Meerwald {
416c7eeea93SPeter Meerwald 	struct mma8452_data *data = iio_priv(indio_dev);
4171e79841aSMartin Fuzzey 	int i, ret;
418c7eeea93SPeter Meerwald 
419c7eeea93SPeter Meerwald 	if (iio_buffer_enabled(indio_dev))
420c7eeea93SPeter Meerwald 		return -EBUSY;
421c7eeea93SPeter Meerwald 
422c7eeea93SPeter Meerwald 	switch (mask) {
423c7eeea93SPeter Meerwald 	case IIO_CHAN_INFO_SAMP_FREQ:
424c7eeea93SPeter Meerwald 		i = mma8452_get_samp_freq_index(data, val, val2);
425c7eeea93SPeter Meerwald 		if (i < 0)
426b9fddcdbSHartmut Knaack 			return i;
427c7eeea93SPeter Meerwald 
428c7eeea93SPeter Meerwald 		data->ctrl_reg1 &= ~MMA8452_CTRL_DR_MASK;
429c7eeea93SPeter Meerwald 		data->ctrl_reg1 |= i << MMA8452_CTRL_DR_SHIFT;
430686027fbSHartmut Knaack 
431c7eeea93SPeter Meerwald 		return mma8452_change_config(data, MMA8452_CTRL_REG1,
432c7eeea93SPeter Meerwald 					     data->ctrl_reg1);
433c7eeea93SPeter Meerwald 	case IIO_CHAN_INFO_SCALE:
434c7eeea93SPeter Meerwald 		i = mma8452_get_scale_index(data, val, val2);
435c7eeea93SPeter Meerwald 		if (i < 0)
436b9fddcdbSHartmut Knaack 			return i;
437686027fbSHartmut Knaack 
438c7eeea93SPeter Meerwald 		data->data_cfg &= ~MMA8452_DATA_CFG_FS_MASK;
439c7eeea93SPeter Meerwald 		data->data_cfg |= i;
440686027fbSHartmut Knaack 
441c7eeea93SPeter Meerwald 		return mma8452_change_config(data, MMA8452_DATA_CFG,
442c7eeea93SPeter Meerwald 					     data->data_cfg);
443c7eeea93SPeter Meerwald 	case IIO_CHAN_INFO_CALIBBIAS:
444c7eeea93SPeter Meerwald 		if (val < -128 || val > 127)
445c7eeea93SPeter Meerwald 			return -EINVAL;
446686027fbSHartmut Knaack 
447686027fbSHartmut Knaack 		return mma8452_change_config(data,
448686027fbSHartmut Knaack 					     MMA8452_OFF_X + chan->scan_index,
449686027fbSHartmut Knaack 					     val);
4501e79841aSMartin Fuzzey 
4511e79841aSMartin Fuzzey 	case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
4521e79841aSMartin Fuzzey 		if (val == 0 && val2 == 0) {
4531e79841aSMartin Fuzzey 			data->data_cfg &= ~MMA8452_DATA_CFG_HPF_MASK;
4541e79841aSMartin Fuzzey 		} else {
4551e79841aSMartin Fuzzey 			data->data_cfg |= MMA8452_DATA_CFG_HPF_MASK;
4561e79841aSMartin Fuzzey 			ret = mma8452_set_hp_filter_frequency(data, val, val2);
4571e79841aSMartin Fuzzey 			if (ret < 0)
4581e79841aSMartin Fuzzey 				return ret;
4591e79841aSMartin Fuzzey 		}
460686027fbSHartmut Knaack 
4611e79841aSMartin Fuzzey 		return mma8452_change_config(data, MMA8452_DATA_CFG,
4621e79841aSMartin Fuzzey 					     data->data_cfg);
4631e79841aSMartin Fuzzey 
464c7eeea93SPeter Meerwald 	default:
465c7eeea93SPeter Meerwald 		return -EINVAL;
466c7eeea93SPeter Meerwald 	}
467c7eeea93SPeter Meerwald }
468c7eeea93SPeter Meerwald 
46928e34278SMartin Fuzzey static int mma8452_read_thresh(struct iio_dev *indio_dev,
47028e34278SMartin Fuzzey 			       const struct iio_chan_spec *chan,
47128e34278SMartin Fuzzey 			       enum iio_event_type type,
47228e34278SMartin Fuzzey 			       enum iio_event_direction dir,
47328e34278SMartin Fuzzey 			       enum iio_event_info info,
47428e34278SMartin Fuzzey 			       int *val, int *val2)
47528e34278SMartin Fuzzey {
47628e34278SMartin Fuzzey 	struct mma8452_data *data = iio_priv(indio_dev);
4775dbbd19fSMartin Fuzzey 	int ret, us;
47828e34278SMartin Fuzzey 
4795dbbd19fSMartin Fuzzey 	switch (info) {
4805dbbd19fSMartin Fuzzey 	case IIO_EV_INFO_VALUE:
4815dbbd19fSMartin Fuzzey 		ret = i2c_smbus_read_byte_data(data->client,
482*c3cdd6e4SMartin Kepplinger 					       data->chip_info->ev_ths);
48328e34278SMartin Fuzzey 		if (ret < 0)
48428e34278SMartin Fuzzey 			return ret;
48528e34278SMartin Fuzzey 
486*c3cdd6e4SMartin Kepplinger 		*val = ret & data->chip_info->ev_ths_mask;
487686027fbSHartmut Knaack 
48828e34278SMartin Fuzzey 		return IIO_VAL_INT;
4895dbbd19fSMartin Fuzzey 
4905dbbd19fSMartin Fuzzey 	case IIO_EV_INFO_PERIOD:
4915dbbd19fSMartin Fuzzey 		ret = i2c_smbus_read_byte_data(data->client,
492*c3cdd6e4SMartin Kepplinger 					       data->chip_info->ev_count);
4935dbbd19fSMartin Fuzzey 		if (ret < 0)
4945dbbd19fSMartin Fuzzey 			return ret;
4955dbbd19fSMartin Fuzzey 
4965dbbd19fSMartin Fuzzey 		us = ret * mma8452_transient_time_step_us[
4975dbbd19fSMartin Fuzzey 				mma8452_get_odr_index(data)];
4985dbbd19fSMartin Fuzzey 		*val = us / USEC_PER_SEC;
4995dbbd19fSMartin Fuzzey 		*val2 = us % USEC_PER_SEC;
500686027fbSHartmut Knaack 
5015dbbd19fSMartin Fuzzey 		return IIO_VAL_INT_PLUS_MICRO;
5025dbbd19fSMartin Fuzzey 
5031e79841aSMartin Fuzzey 	case IIO_EV_INFO_HIGH_PASS_FILTER_3DB:
5041e79841aSMartin Fuzzey 		ret = i2c_smbus_read_byte_data(data->client,
5051e79841aSMartin Fuzzey 					       MMA8452_TRANSIENT_CFG);
5061e79841aSMartin Fuzzey 		if (ret < 0)
5071e79841aSMartin Fuzzey 			return ret;
5081e79841aSMartin Fuzzey 
5091e79841aSMartin Fuzzey 		if (ret & MMA8452_TRANSIENT_CFG_HPF_BYP) {
5101e79841aSMartin Fuzzey 			*val = 0;
5111e79841aSMartin Fuzzey 			*val2 = 0;
5121e79841aSMartin Fuzzey 		} else {
5131e79841aSMartin Fuzzey 			ret = mma8452_read_hp_filter(data, val, val2);
5141e79841aSMartin Fuzzey 			if (ret < 0)
5151e79841aSMartin Fuzzey 				return ret;
5161e79841aSMartin Fuzzey 		}
517686027fbSHartmut Knaack 
5181e79841aSMartin Fuzzey 		return IIO_VAL_INT_PLUS_MICRO;
5191e79841aSMartin Fuzzey 
5205dbbd19fSMartin Fuzzey 	default:
5215dbbd19fSMartin Fuzzey 		return -EINVAL;
5225dbbd19fSMartin Fuzzey 	}
52328e34278SMartin Fuzzey }
52428e34278SMartin Fuzzey 
52528e34278SMartin Fuzzey static int mma8452_write_thresh(struct iio_dev *indio_dev,
52628e34278SMartin Fuzzey 				const struct iio_chan_spec *chan,
52728e34278SMartin Fuzzey 				enum iio_event_type type,
52828e34278SMartin Fuzzey 				enum iio_event_direction dir,
52928e34278SMartin Fuzzey 				enum iio_event_info info,
53028e34278SMartin Fuzzey 				int val, int val2)
53128e34278SMartin Fuzzey {
53228e34278SMartin Fuzzey 	struct mma8452_data *data = iio_priv(indio_dev);
5331e79841aSMartin Fuzzey 	int ret, reg, steps;
53428e34278SMartin Fuzzey 
5355dbbd19fSMartin Fuzzey 	switch (info) {
5365dbbd19fSMartin Fuzzey 	case IIO_EV_INFO_VALUE:
53711218226SHartmut Knaack 		if (val < 0 || val > MMA8452_TRANSIENT_THS_MASK)
53811218226SHartmut Knaack 			return -EINVAL;
53911218226SHartmut Knaack 
540*c3cdd6e4SMartin Kepplinger 		return mma8452_change_config(data, data->chip_info->ev_ths,
541*c3cdd6e4SMartin Kepplinger 					     val);
5425dbbd19fSMartin Fuzzey 
5435dbbd19fSMartin Fuzzey 	case IIO_EV_INFO_PERIOD:
5445dbbd19fSMartin Fuzzey 		steps = (val * USEC_PER_SEC + val2) /
5455dbbd19fSMartin Fuzzey 				mma8452_transient_time_step_us[
5465dbbd19fSMartin Fuzzey 					mma8452_get_odr_index(data)];
5475dbbd19fSMartin Fuzzey 
54811218226SHartmut Knaack 		if (steps < 0 || steps > 0xff)
5495dbbd19fSMartin Fuzzey 			return -EINVAL;
5505dbbd19fSMartin Fuzzey 
551*c3cdd6e4SMartin Kepplinger 		return mma8452_change_config(data, data->chip_info->ev_count,
5525dbbd19fSMartin Fuzzey 					     steps);
553686027fbSHartmut Knaack 
5541e79841aSMartin Fuzzey 	case IIO_EV_INFO_HIGH_PASS_FILTER_3DB:
5551e79841aSMartin Fuzzey 		reg = i2c_smbus_read_byte_data(data->client,
5561e79841aSMartin Fuzzey 					       MMA8452_TRANSIENT_CFG);
5571e79841aSMartin Fuzzey 		if (reg < 0)
5581e79841aSMartin Fuzzey 			return reg;
5591e79841aSMartin Fuzzey 
5601e79841aSMartin Fuzzey 		if (val == 0 && val2 == 0) {
5611e79841aSMartin Fuzzey 			reg |= MMA8452_TRANSIENT_CFG_HPF_BYP;
5621e79841aSMartin Fuzzey 		} else {
5631e79841aSMartin Fuzzey 			reg &= ~MMA8452_TRANSIENT_CFG_HPF_BYP;
5641e79841aSMartin Fuzzey 			ret = mma8452_set_hp_filter_frequency(data, val, val2);
5651e79841aSMartin Fuzzey 			if (ret < 0)
5661e79841aSMartin Fuzzey 				return ret;
5671e79841aSMartin Fuzzey 		}
568686027fbSHartmut Knaack 
5691e79841aSMartin Fuzzey 		return mma8452_change_config(data, MMA8452_TRANSIENT_CFG, reg);
5701e79841aSMartin Fuzzey 
5715dbbd19fSMartin Fuzzey 	default:
5725dbbd19fSMartin Fuzzey 		return -EINVAL;
5735dbbd19fSMartin Fuzzey 	}
57428e34278SMartin Fuzzey }
57528e34278SMartin Fuzzey 
57628e34278SMartin Fuzzey static int mma8452_read_event_config(struct iio_dev *indio_dev,
57728e34278SMartin Fuzzey 				     const struct iio_chan_spec *chan,
57828e34278SMartin Fuzzey 				     enum iio_event_type type,
57928e34278SMartin Fuzzey 				     enum iio_event_direction dir)
58028e34278SMartin Fuzzey {
58128e34278SMartin Fuzzey 	struct mma8452_data *data = iio_priv(indio_dev);
582*c3cdd6e4SMartin Kepplinger 	const struct mma_chip_info *chip = data->chip_info;
58328e34278SMartin Fuzzey 	int ret;
58428e34278SMartin Fuzzey 
585*c3cdd6e4SMartin Kepplinger 	ret = i2c_smbus_read_byte_data(data->client,
586*c3cdd6e4SMartin Kepplinger 				       data->chip_info->ev_cfg);
58728e34278SMartin Fuzzey 	if (ret < 0)
58828e34278SMartin Fuzzey 		return ret;
58928e34278SMartin Fuzzey 
590*c3cdd6e4SMartin Kepplinger 	return !!(ret & BIT(chan->scan_index + chip->ev_cfg_chan_shift));
59128e34278SMartin Fuzzey }
59228e34278SMartin Fuzzey 
59328e34278SMartin Fuzzey static int mma8452_write_event_config(struct iio_dev *indio_dev,
59428e34278SMartin Fuzzey 				      const struct iio_chan_spec *chan,
59528e34278SMartin Fuzzey 				      enum iio_event_type type,
59628e34278SMartin Fuzzey 				      enum iio_event_direction dir,
59728e34278SMartin Fuzzey 				      int state)
59828e34278SMartin Fuzzey {
59928e34278SMartin Fuzzey 	struct mma8452_data *data = iio_priv(indio_dev);
600*c3cdd6e4SMartin Kepplinger 	const struct mma_chip_info *chip = data->chip_info;
60128e34278SMartin Fuzzey 	int val;
60228e34278SMartin Fuzzey 
603*c3cdd6e4SMartin Kepplinger 	val = i2c_smbus_read_byte_data(data->client, chip->ev_cfg);
60428e34278SMartin Fuzzey 	if (val < 0)
60528e34278SMartin Fuzzey 		return val;
60628e34278SMartin Fuzzey 
60728e34278SMartin Fuzzey 	if (state)
608*c3cdd6e4SMartin Kepplinger 		val |= BIT(chan->scan_index + chip->ev_cfg_chan_shift);
60928e34278SMartin Fuzzey 	else
610*c3cdd6e4SMartin Kepplinger 		val &= ~BIT(chan->scan_index + chip->ev_cfg_chan_shift);
61128e34278SMartin Fuzzey 
61228e34278SMartin Fuzzey 	val |= MMA8452_TRANSIENT_CFG_ELE;
61328e34278SMartin Fuzzey 
614*c3cdd6e4SMartin Kepplinger 	return mma8452_change_config(data, chip->ev_cfg, val);
61528e34278SMartin Fuzzey }
61628e34278SMartin Fuzzey 
61728e34278SMartin Fuzzey static void mma8452_transient_interrupt(struct iio_dev *indio_dev)
61828e34278SMartin Fuzzey {
61928e34278SMartin Fuzzey 	struct mma8452_data *data = iio_priv(indio_dev);
62028e34278SMartin Fuzzey 	s64 ts = iio_get_time_ns();
62128e34278SMartin Fuzzey 	int src;
62228e34278SMartin Fuzzey 
623*c3cdd6e4SMartin Kepplinger 	src = i2c_smbus_read_byte_data(data->client, data->chip_info->ev_src);
62428e34278SMartin Fuzzey 	if (src < 0)
62528e34278SMartin Fuzzey 		return;
62628e34278SMartin Fuzzey 
627*c3cdd6e4SMartin Kepplinger 	if (src & data->chip_info->ev_src_xe)
62828e34278SMartin Fuzzey 		iio_push_event(indio_dev,
62928e34278SMartin Fuzzey 			       IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X,
630c5d0db06SMartin Kepplinger 						  IIO_EV_TYPE_MAG,
63128e34278SMartin Fuzzey 						  IIO_EV_DIR_RISING),
63228e34278SMartin Fuzzey 			       ts);
63328e34278SMartin Fuzzey 
634*c3cdd6e4SMartin Kepplinger 	if (src & data->chip_info->ev_src_ye)
63528e34278SMartin Fuzzey 		iio_push_event(indio_dev,
63628e34278SMartin Fuzzey 			       IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Y,
637c5d0db06SMartin Kepplinger 						  IIO_EV_TYPE_MAG,
63828e34278SMartin Fuzzey 						  IIO_EV_DIR_RISING),
63928e34278SMartin Fuzzey 			       ts);
64028e34278SMartin Fuzzey 
641*c3cdd6e4SMartin Kepplinger 	if (src & data->chip_info->ev_src_ze)
64228e34278SMartin Fuzzey 		iio_push_event(indio_dev,
64328e34278SMartin Fuzzey 			       IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Z,
644c5d0db06SMartin Kepplinger 						  IIO_EV_TYPE_MAG,
64528e34278SMartin Fuzzey 						  IIO_EV_DIR_RISING),
64628e34278SMartin Fuzzey 			       ts);
64728e34278SMartin Fuzzey }
64828e34278SMartin Fuzzey 
64928e34278SMartin Fuzzey static irqreturn_t mma8452_interrupt(int irq, void *p)
65028e34278SMartin Fuzzey {
65128e34278SMartin Fuzzey 	struct iio_dev *indio_dev = p;
65228e34278SMartin Fuzzey 	struct mma8452_data *data = iio_priv(indio_dev);
653ae6d9ce0SMartin Fuzzey 	int ret = IRQ_NONE;
65428e34278SMartin Fuzzey 	int src;
65528e34278SMartin Fuzzey 
65628e34278SMartin Fuzzey 	src = i2c_smbus_read_byte_data(data->client, MMA8452_INT_SRC);
65728e34278SMartin Fuzzey 	if (src < 0)
65828e34278SMartin Fuzzey 		return IRQ_NONE;
65928e34278SMartin Fuzzey 
660ae6d9ce0SMartin Fuzzey 	if (src & MMA8452_INT_DRDY) {
661ae6d9ce0SMartin Fuzzey 		iio_trigger_poll_chained(indio_dev->trig);
662ae6d9ce0SMartin Fuzzey 		ret = IRQ_HANDLED;
66328e34278SMartin Fuzzey 	}
66428e34278SMartin Fuzzey 
665ae6d9ce0SMartin Fuzzey 	if (src & MMA8452_INT_TRANS) {
666ae6d9ce0SMartin Fuzzey 		mma8452_transient_interrupt(indio_dev);
667ae6d9ce0SMartin Fuzzey 		ret = IRQ_HANDLED;
668ae6d9ce0SMartin Fuzzey 	}
669ae6d9ce0SMartin Fuzzey 
670ae6d9ce0SMartin Fuzzey 	return ret;
67128e34278SMartin Fuzzey }
67228e34278SMartin Fuzzey 
673c7eeea93SPeter Meerwald static irqreturn_t mma8452_trigger_handler(int irq, void *p)
674c7eeea93SPeter Meerwald {
675c7eeea93SPeter Meerwald 	struct iio_poll_func *pf = p;
676c7eeea93SPeter Meerwald 	struct iio_dev *indio_dev = pf->indio_dev;
677c7eeea93SPeter Meerwald 	struct mma8452_data *data = iio_priv(indio_dev);
678c7eeea93SPeter Meerwald 	u8 buffer[16]; /* 3 16-bit channels + padding + ts */
679c7eeea93SPeter Meerwald 	int ret;
680c7eeea93SPeter Meerwald 
681c7eeea93SPeter Meerwald 	ret = mma8452_read(data, (__be16 *)buffer);
682c7eeea93SPeter Meerwald 	if (ret < 0)
683c7eeea93SPeter Meerwald 		goto done;
684c7eeea93SPeter Meerwald 
685c7eeea93SPeter Meerwald 	iio_push_to_buffers_with_timestamp(indio_dev, buffer,
686c7eeea93SPeter Meerwald 					   iio_get_time_ns());
687c7eeea93SPeter Meerwald 
688c7eeea93SPeter Meerwald done:
689c7eeea93SPeter Meerwald 	iio_trigger_notify_done(indio_dev->trig);
690686027fbSHartmut Knaack 
691c7eeea93SPeter Meerwald 	return IRQ_HANDLED;
692c7eeea93SPeter Meerwald }
693c7eeea93SPeter Meerwald 
6942a17698cSMartin Fuzzey static int mma8452_reg_access_dbg(struct iio_dev *indio_dev,
6952a17698cSMartin Fuzzey 				  unsigned reg, unsigned writeval,
6962a17698cSMartin Fuzzey 				  unsigned *readval)
6972a17698cSMartin Fuzzey {
6982a17698cSMartin Fuzzey 	int ret;
6992a17698cSMartin Fuzzey 	struct mma8452_data *data = iio_priv(indio_dev);
7002a17698cSMartin Fuzzey 
7012a17698cSMartin Fuzzey 	if (reg > MMA8452_MAX_REG)
7022a17698cSMartin Fuzzey 		return -EINVAL;
7032a17698cSMartin Fuzzey 
7042a17698cSMartin Fuzzey 	if (!readval)
7052a17698cSMartin Fuzzey 		return mma8452_change_config(data, reg, writeval);
7062a17698cSMartin Fuzzey 
7072a17698cSMartin Fuzzey 	ret = i2c_smbus_read_byte_data(data->client, reg);
7082a17698cSMartin Fuzzey 	if (ret < 0)
7092a17698cSMartin Fuzzey 		return ret;
7102a17698cSMartin Fuzzey 
7112a17698cSMartin Fuzzey 	*readval = ret;
7122a17698cSMartin Fuzzey 
7132a17698cSMartin Fuzzey 	return 0;
7142a17698cSMartin Fuzzey }
7152a17698cSMartin Fuzzey 
71628e34278SMartin Fuzzey static const struct iio_event_spec mma8452_transient_event[] = {
71728e34278SMartin Fuzzey 	{
718c5d0db06SMartin Kepplinger 		.type = IIO_EV_TYPE_MAG,
71928e34278SMartin Fuzzey 		.dir = IIO_EV_DIR_RISING,
72028e34278SMartin Fuzzey 		.mask_separate = BIT(IIO_EV_INFO_ENABLE),
7215dbbd19fSMartin Fuzzey 		.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
7221e79841aSMartin Fuzzey 					BIT(IIO_EV_INFO_PERIOD) |
7231e79841aSMartin Fuzzey 					BIT(IIO_EV_INFO_HIGH_PASS_FILTER_3DB)
72428e34278SMartin Fuzzey 	},
72528e34278SMartin Fuzzey };
72628e34278SMartin Fuzzey 
72728e34278SMartin Fuzzey /*
72828e34278SMartin Fuzzey  * Threshold is configured in fixed 8G/127 steps regardless of
72928e34278SMartin Fuzzey  * currently selected scale for measurement.
73028e34278SMartin Fuzzey  */
73128e34278SMartin Fuzzey static IIO_CONST_ATTR_NAMED(accel_transient_scale, in_accel_scale, "0.617742");
73228e34278SMartin Fuzzey 
73328e34278SMartin Fuzzey static struct attribute *mma8452_event_attributes[] = {
73428e34278SMartin Fuzzey 	&iio_const_attr_accel_transient_scale.dev_attr.attr,
73528e34278SMartin Fuzzey 	NULL,
73628e34278SMartin Fuzzey };
73728e34278SMartin Fuzzey 
73828e34278SMartin Fuzzey static struct attribute_group mma8452_event_attribute_group = {
73928e34278SMartin Fuzzey 	.attrs = mma8452_event_attributes,
74028e34278SMartin Fuzzey 	.name = "events",
74128e34278SMartin Fuzzey };
74228e34278SMartin Fuzzey 
743*c3cdd6e4SMartin Kepplinger #define MMA8452_CHANNEL(axis, idx, bits) { \
744c7eeea93SPeter Meerwald 	.type = IIO_ACCEL, \
745c7eeea93SPeter Meerwald 	.modified = 1, \
746c7eeea93SPeter Meerwald 	.channel2 = IIO_MOD_##axis, \
747c7eeea93SPeter Meerwald 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
748c7eeea93SPeter Meerwald 			      BIT(IIO_CHAN_INFO_CALIBBIAS), \
749c7eeea93SPeter Meerwald 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
7501e79841aSMartin Fuzzey 			BIT(IIO_CHAN_INFO_SCALE) | \
7511e79841aSMartin Fuzzey 			BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \
752c7eeea93SPeter Meerwald 	.scan_index = idx, \
753c7eeea93SPeter Meerwald 	.scan_type = { \
754c7eeea93SPeter Meerwald 		.sign = 's', \
755*c3cdd6e4SMartin Kepplinger 		.realbits = (bits), \
756c7eeea93SPeter Meerwald 		.storagebits = 16, \
757*c3cdd6e4SMartin Kepplinger 		.shift = 16 - (bits), \
758c7eeea93SPeter Meerwald 		.endianness = IIO_BE, \
759c7eeea93SPeter Meerwald 	}, \
76028e34278SMartin Fuzzey 	.event_spec = mma8452_transient_event, \
76128e34278SMartin Fuzzey 	.num_event_specs = ARRAY_SIZE(mma8452_transient_event), \
762c7eeea93SPeter Meerwald }
763c7eeea93SPeter Meerwald 
764c7eeea93SPeter Meerwald static const struct iio_chan_spec mma8452_channels[] = {
765*c3cdd6e4SMartin Kepplinger 	MMA8452_CHANNEL(X, 0, 12),
766*c3cdd6e4SMartin Kepplinger 	MMA8452_CHANNEL(Y, 1, 12),
767*c3cdd6e4SMartin Kepplinger 	MMA8452_CHANNEL(Z, 2, 12),
768c7eeea93SPeter Meerwald 	IIO_CHAN_SOFT_TIMESTAMP(3),
769c7eeea93SPeter Meerwald };
770c7eeea93SPeter Meerwald 
771*c3cdd6e4SMartin Kepplinger enum {
772*c3cdd6e4SMartin Kepplinger 	mma8452,
773*c3cdd6e4SMartin Kepplinger };
774*c3cdd6e4SMartin Kepplinger 
775*c3cdd6e4SMartin Kepplinger static const struct mma_chip_info mma_chip_info_table[] = {
776*c3cdd6e4SMartin Kepplinger 	[mma8452] = {
777*c3cdd6e4SMartin Kepplinger 		.chip_id = MMA8452_DEVICE_ID,
778*c3cdd6e4SMartin Kepplinger 		.channels = mma8452_channels,
779*c3cdd6e4SMartin Kepplinger 		.num_channels = ARRAY_SIZE(mma8452_channels),
780*c3cdd6e4SMartin Kepplinger 		/*
781*c3cdd6e4SMartin Kepplinger 		 * Hardware has fullscale of -2G, -4G, -8G corresponding to
782*c3cdd6e4SMartin Kepplinger 		 * raw value -2048 for 12 bit or -512 for 10 bit.
783*c3cdd6e4SMartin Kepplinger 		 * The userspace interface uses m/s^2 and we declare micro units
784*c3cdd6e4SMartin Kepplinger 		 * So scale factor for 12 bit here is given by:
785*c3cdd6e4SMartin Kepplinger 		 *	g * N * 1000000 / 2048 for N = 2, 4, 8 and g=9.80665
786*c3cdd6e4SMartin Kepplinger 		 */
787*c3cdd6e4SMartin Kepplinger 		.mma_scales = { {0, 9577}, {0, 19154}, {0, 38307} },
788*c3cdd6e4SMartin Kepplinger 		.ev_cfg = MMA8452_TRANSIENT_CFG,
789*c3cdd6e4SMartin Kepplinger 		.ev_cfg_ele = MMA8452_TRANSIENT_CFG_ELE,
790*c3cdd6e4SMartin Kepplinger 		.ev_cfg_chan_shift = 1,
791*c3cdd6e4SMartin Kepplinger 		.ev_src = MMA8452_TRANSIENT_SRC,
792*c3cdd6e4SMartin Kepplinger 		.ev_src_xe = MMA8452_TRANSIENT_SRC_XTRANSE,
793*c3cdd6e4SMartin Kepplinger 		.ev_src_ye = MMA8452_TRANSIENT_SRC_YTRANSE,
794*c3cdd6e4SMartin Kepplinger 		.ev_src_ze = MMA8452_TRANSIENT_SRC_ZTRANSE,
795*c3cdd6e4SMartin Kepplinger 		.ev_ths = MMA8452_TRANSIENT_THS,
796*c3cdd6e4SMartin Kepplinger 		.ev_ths_mask = MMA8452_TRANSIENT_THS_MASK,
797*c3cdd6e4SMartin Kepplinger 		.ev_count = MMA8452_TRANSIENT_COUNT,
798*c3cdd6e4SMartin Kepplinger 	},
799*c3cdd6e4SMartin Kepplinger };
800*c3cdd6e4SMartin Kepplinger 
801c7eeea93SPeter Meerwald static struct attribute *mma8452_attributes[] = {
802c7eeea93SPeter Meerwald 	&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
803c7eeea93SPeter Meerwald 	&iio_dev_attr_in_accel_scale_available.dev_attr.attr,
8041e79841aSMartin Fuzzey 	&iio_dev_attr_in_accel_filter_high_pass_3db_frequency_available.dev_attr.attr,
805c7eeea93SPeter Meerwald 	NULL
806c7eeea93SPeter Meerwald };
807c7eeea93SPeter Meerwald 
808c7eeea93SPeter Meerwald static const struct attribute_group mma8452_group = {
809c7eeea93SPeter Meerwald 	.attrs = mma8452_attributes,
810c7eeea93SPeter Meerwald };
811c7eeea93SPeter Meerwald 
812c7eeea93SPeter Meerwald static const struct iio_info mma8452_info = {
813c7eeea93SPeter Meerwald 	.attrs = &mma8452_group,
814c7eeea93SPeter Meerwald 	.read_raw = &mma8452_read_raw,
815c7eeea93SPeter Meerwald 	.write_raw = &mma8452_write_raw,
81628e34278SMartin Fuzzey 	.event_attrs = &mma8452_event_attribute_group,
81728e34278SMartin Fuzzey 	.read_event_value = &mma8452_read_thresh,
81828e34278SMartin Fuzzey 	.write_event_value = &mma8452_write_thresh,
81928e34278SMartin Fuzzey 	.read_event_config = &mma8452_read_event_config,
82028e34278SMartin Fuzzey 	.write_event_config = &mma8452_write_event_config,
8212a17698cSMartin Fuzzey 	.debugfs_reg_access = &mma8452_reg_access_dbg,
822c7eeea93SPeter Meerwald 	.driver_module = THIS_MODULE,
823c7eeea93SPeter Meerwald };
824c7eeea93SPeter Meerwald 
825c7eeea93SPeter Meerwald static const unsigned long mma8452_scan_masks[] = {0x7, 0};
826c7eeea93SPeter Meerwald 
827ae6d9ce0SMartin Fuzzey static int mma8452_data_rdy_trigger_set_state(struct iio_trigger *trig,
828ae6d9ce0SMartin Fuzzey 					      bool state)
829ae6d9ce0SMartin Fuzzey {
830ae6d9ce0SMartin Fuzzey 	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
831ae6d9ce0SMartin Fuzzey 	struct mma8452_data *data = iio_priv(indio_dev);
832ae6d9ce0SMartin Fuzzey 	int reg;
833ae6d9ce0SMartin Fuzzey 
834ae6d9ce0SMartin Fuzzey 	reg = i2c_smbus_read_byte_data(data->client, MMA8452_CTRL_REG4);
835ae6d9ce0SMartin Fuzzey 	if (reg < 0)
836ae6d9ce0SMartin Fuzzey 		return reg;
837ae6d9ce0SMartin Fuzzey 
838ae6d9ce0SMartin Fuzzey 	if (state)
839ae6d9ce0SMartin Fuzzey 		reg |= MMA8452_INT_DRDY;
840ae6d9ce0SMartin Fuzzey 	else
841ae6d9ce0SMartin Fuzzey 		reg &= ~MMA8452_INT_DRDY;
842ae6d9ce0SMartin Fuzzey 
843ae6d9ce0SMartin Fuzzey 	return mma8452_change_config(data, MMA8452_CTRL_REG4, reg);
844ae6d9ce0SMartin Fuzzey }
845ae6d9ce0SMartin Fuzzey 
846ae6d9ce0SMartin Fuzzey static int mma8452_validate_device(struct iio_trigger *trig,
847ae6d9ce0SMartin Fuzzey 				   struct iio_dev *indio_dev)
848ae6d9ce0SMartin Fuzzey {
849ae6d9ce0SMartin Fuzzey 	struct iio_dev *indio = iio_trigger_get_drvdata(trig);
850ae6d9ce0SMartin Fuzzey 
851ae6d9ce0SMartin Fuzzey 	if (indio != indio_dev)
852ae6d9ce0SMartin Fuzzey 		return -EINVAL;
853ae6d9ce0SMartin Fuzzey 
854ae6d9ce0SMartin Fuzzey 	return 0;
855ae6d9ce0SMartin Fuzzey }
856ae6d9ce0SMartin Fuzzey 
857ae6d9ce0SMartin Fuzzey static const struct iio_trigger_ops mma8452_trigger_ops = {
858ae6d9ce0SMartin Fuzzey 	.set_trigger_state = mma8452_data_rdy_trigger_set_state,
859ae6d9ce0SMartin Fuzzey 	.validate_device = mma8452_validate_device,
860ae6d9ce0SMartin Fuzzey 	.owner = THIS_MODULE,
861ae6d9ce0SMartin Fuzzey };
862ae6d9ce0SMartin Fuzzey 
863ae6d9ce0SMartin Fuzzey static int mma8452_trigger_setup(struct iio_dev *indio_dev)
864ae6d9ce0SMartin Fuzzey {
865ae6d9ce0SMartin Fuzzey 	struct mma8452_data *data = iio_priv(indio_dev);
866ae6d9ce0SMartin Fuzzey 	struct iio_trigger *trig;
867ae6d9ce0SMartin Fuzzey 	int ret;
868ae6d9ce0SMartin Fuzzey 
869ae6d9ce0SMartin Fuzzey 	trig = devm_iio_trigger_alloc(&data->client->dev, "%s-dev%d",
870ae6d9ce0SMartin Fuzzey 				      indio_dev->name,
871ae6d9ce0SMartin Fuzzey 				      indio_dev->id);
872ae6d9ce0SMartin Fuzzey 	if (!trig)
873ae6d9ce0SMartin Fuzzey 		return -ENOMEM;
874ae6d9ce0SMartin Fuzzey 
875ae6d9ce0SMartin Fuzzey 	trig->dev.parent = &data->client->dev;
876ae6d9ce0SMartin Fuzzey 	trig->ops = &mma8452_trigger_ops;
877ae6d9ce0SMartin Fuzzey 	iio_trigger_set_drvdata(trig, indio_dev);
878ae6d9ce0SMartin Fuzzey 
879ae6d9ce0SMartin Fuzzey 	ret = iio_trigger_register(trig);
880ae6d9ce0SMartin Fuzzey 	if (ret)
881ae6d9ce0SMartin Fuzzey 		return ret;
882ae6d9ce0SMartin Fuzzey 
883ae6d9ce0SMartin Fuzzey 	indio_dev->trig = trig;
884686027fbSHartmut Knaack 
885ae6d9ce0SMartin Fuzzey 	return 0;
886ae6d9ce0SMartin Fuzzey }
887ae6d9ce0SMartin Fuzzey 
888ae6d9ce0SMartin Fuzzey static void mma8452_trigger_cleanup(struct iio_dev *indio_dev)
889ae6d9ce0SMartin Fuzzey {
890ae6d9ce0SMartin Fuzzey 	if (indio_dev->trig)
891ae6d9ce0SMartin Fuzzey 		iio_trigger_unregister(indio_dev->trig);
892ae6d9ce0SMartin Fuzzey }
893ae6d9ce0SMartin Fuzzey 
894ecabae71SMartin Fuzzey static int mma8452_reset(struct i2c_client *client)
895ecabae71SMartin Fuzzey {
896ecabae71SMartin Fuzzey 	int i;
897ecabae71SMartin Fuzzey 	int ret;
898ecabae71SMartin Fuzzey 
899ecabae71SMartin Fuzzey 	ret = i2c_smbus_write_byte_data(client,	MMA8452_CTRL_REG2,
900ecabae71SMartin Fuzzey 					MMA8452_CTRL_REG2_RST);
901ecabae71SMartin Fuzzey 	if (ret < 0)
902ecabae71SMartin Fuzzey 		return ret;
903ecabae71SMartin Fuzzey 
904ecabae71SMartin Fuzzey 	for (i = 0; i < 10; i++) {
905ecabae71SMartin Fuzzey 		usleep_range(100, 200);
906ecabae71SMartin Fuzzey 		ret = i2c_smbus_read_byte_data(client, MMA8452_CTRL_REG2);
907ecabae71SMartin Fuzzey 		if (ret == -EIO)
908ecabae71SMartin Fuzzey 			continue; /* I2C comm reset */
909ecabae71SMartin Fuzzey 		if (ret < 0)
910ecabae71SMartin Fuzzey 			return ret;
911ecabae71SMartin Fuzzey 		if (!(ret & MMA8452_CTRL_REG2_RST))
912ecabae71SMartin Fuzzey 			return 0;
913ecabae71SMartin Fuzzey 	}
914ecabae71SMartin Fuzzey 
915ecabae71SMartin Fuzzey 	return -ETIMEDOUT;
916ecabae71SMartin Fuzzey }
917ecabae71SMartin Fuzzey 
918*c3cdd6e4SMartin Kepplinger static const struct of_device_id mma8452_dt_ids[] = {
919*c3cdd6e4SMartin Kepplinger 	{ .compatible = "fsl,mma8452", .data = &mma_chip_info_table[mma8452] },
920*c3cdd6e4SMartin Kepplinger 	{ }
921*c3cdd6e4SMartin Kepplinger };
922*c3cdd6e4SMartin Kepplinger MODULE_DEVICE_TABLE(of, mma8452_dt_ids);
923*c3cdd6e4SMartin Kepplinger 
924c7eeea93SPeter Meerwald static int mma8452_probe(struct i2c_client *client,
925c7eeea93SPeter Meerwald 			 const struct i2c_device_id *id)
926c7eeea93SPeter Meerwald {
927c7eeea93SPeter Meerwald 	struct mma8452_data *data;
928c7eeea93SPeter Meerwald 	struct iio_dev *indio_dev;
929c7eeea93SPeter Meerwald 	int ret;
930*c3cdd6e4SMartin Kepplinger 	const struct of_device_id *match;
931c7eeea93SPeter Meerwald 
932c7eeea93SPeter Meerwald 	ret = i2c_smbus_read_byte_data(client, MMA8452_WHO_AM_I);
933c7eeea93SPeter Meerwald 	if (ret < 0)
934c7eeea93SPeter Meerwald 		return ret;
935c7eeea93SPeter Meerwald 	if (ret != MMA8452_DEVICE_ID)
936c7eeea93SPeter Meerwald 		return -ENODEV;
937c7eeea93SPeter Meerwald 
938*c3cdd6e4SMartin Kepplinger 	match = of_match_device(mma8452_dt_ids, &client->dev);
939*c3cdd6e4SMartin Kepplinger 	if (!match) {
940*c3cdd6e4SMartin Kepplinger 		dev_err(&client->dev, "unknown device model\n");
941*c3cdd6e4SMartin Kepplinger 		return -ENODEV;
942*c3cdd6e4SMartin Kepplinger 	}
943*c3cdd6e4SMartin Kepplinger 
944c7eeea93SPeter Meerwald 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
945c7eeea93SPeter Meerwald 	if (!indio_dev)
946c7eeea93SPeter Meerwald 		return -ENOMEM;
947c7eeea93SPeter Meerwald 
948c7eeea93SPeter Meerwald 	data = iio_priv(indio_dev);
949c7eeea93SPeter Meerwald 	data->client = client;
950c7eeea93SPeter Meerwald 	mutex_init(&data->lock);
951*c3cdd6e4SMartin Kepplinger 	data->chip_info = match->data;
952*c3cdd6e4SMartin Kepplinger 
953*c3cdd6e4SMartin Kepplinger 	dev_info(&client->dev, "registering %s accelerometer; ID 0x%x\n",
954*c3cdd6e4SMartin Kepplinger 		 match->compatible, data->chip_info->chip_id);
955c7eeea93SPeter Meerwald 
956c7eeea93SPeter Meerwald 	i2c_set_clientdata(client, indio_dev);
957c7eeea93SPeter Meerwald 	indio_dev->info = &mma8452_info;
958c7eeea93SPeter Meerwald 	indio_dev->name = id->name;
959c7eeea93SPeter Meerwald 	indio_dev->dev.parent = &client->dev;
960c7eeea93SPeter Meerwald 	indio_dev->modes = INDIO_DIRECT_MODE;
961*c3cdd6e4SMartin Kepplinger 	indio_dev->channels = data->chip_info->channels;
962*c3cdd6e4SMartin Kepplinger 	indio_dev->num_channels = data->chip_info->num_channels;
963c7eeea93SPeter Meerwald 	indio_dev->available_scan_masks = mma8452_scan_masks;
964c7eeea93SPeter Meerwald 
965ecabae71SMartin Fuzzey 	ret = mma8452_reset(client);
966c7eeea93SPeter Meerwald 	if (ret < 0)
967c7eeea93SPeter Meerwald 		return ret;
968c7eeea93SPeter Meerwald 
969c7eeea93SPeter Meerwald 	data->data_cfg = MMA8452_DATA_CFG_FS_2G;
970c7eeea93SPeter Meerwald 	ret = i2c_smbus_write_byte_data(client, MMA8452_DATA_CFG,
971c7eeea93SPeter Meerwald 					data->data_cfg);
972c7eeea93SPeter Meerwald 	if (ret < 0)
973c7eeea93SPeter Meerwald 		return ret;
974c7eeea93SPeter Meerwald 
97528e34278SMartin Fuzzey 	/*
97628e34278SMartin Fuzzey 	 * By default set transient threshold to max to avoid events if
97728e34278SMartin Fuzzey 	 * enabling without configuring threshold.
97828e34278SMartin Fuzzey 	 */
97928e34278SMartin Fuzzey 	ret = i2c_smbus_write_byte_data(client, MMA8452_TRANSIENT_THS,
98028e34278SMartin Fuzzey 					MMA8452_TRANSIENT_THS_MASK);
98128e34278SMartin Fuzzey 	if (ret < 0)
98228e34278SMartin Fuzzey 		return ret;
98328e34278SMartin Fuzzey 
98428e34278SMartin Fuzzey 	if (client->irq) {
98528e34278SMartin Fuzzey 		/*
98628e34278SMartin Fuzzey 		 * Although we enable the transient interrupt source once and
98728e34278SMartin Fuzzey 		 * for all here the transient event detection itself is not
98828e34278SMartin Fuzzey 		 * enabled until userspace asks for it by
98928e34278SMartin Fuzzey 		 * mma8452_write_event_config()
99028e34278SMartin Fuzzey 		 */
991ae6d9ce0SMartin Fuzzey 		int supported_interrupts = MMA8452_INT_DRDY | MMA8452_INT_TRANS;
992ae6d9ce0SMartin Fuzzey 		int enabled_interrupts = MMA8452_INT_TRANS;
99328e34278SMartin Fuzzey 
99428e34278SMartin Fuzzey 		/* Assume wired to INT1 pin */
99528e34278SMartin Fuzzey 		ret = i2c_smbus_write_byte_data(client,
99628e34278SMartin Fuzzey 						MMA8452_CTRL_REG5,
99728e34278SMartin Fuzzey 						supported_interrupts);
99828e34278SMartin Fuzzey 		if (ret < 0)
99928e34278SMartin Fuzzey 			return ret;
100028e34278SMartin Fuzzey 
100128e34278SMartin Fuzzey 		ret = i2c_smbus_write_byte_data(client,
100228e34278SMartin Fuzzey 						MMA8452_CTRL_REG4,
1003ae6d9ce0SMartin Fuzzey 						enabled_interrupts);
1004ae6d9ce0SMartin Fuzzey 		if (ret < 0)
1005ae6d9ce0SMartin Fuzzey 			return ret;
1006ae6d9ce0SMartin Fuzzey 
1007ae6d9ce0SMartin Fuzzey 		ret = mma8452_trigger_setup(indio_dev);
100828e34278SMartin Fuzzey 		if (ret < 0)
100928e34278SMartin Fuzzey 			return ret;
101028e34278SMartin Fuzzey 	}
101128e34278SMartin Fuzzey 
1012ecabae71SMartin Fuzzey 	data->ctrl_reg1 = MMA8452_CTRL_ACTIVE |
1013ecabae71SMartin Fuzzey 			  (MMA8452_CTRL_DR_DEFAULT << MMA8452_CTRL_DR_SHIFT);
1014ecabae71SMartin Fuzzey 	ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG1,
1015ecabae71SMartin Fuzzey 					data->ctrl_reg1);
1016ecabae71SMartin Fuzzey 	if (ret < 0)
1017ae6d9ce0SMartin Fuzzey 		goto trigger_cleanup;
1018ecabae71SMartin Fuzzey 
1019c7eeea93SPeter Meerwald 	ret = iio_triggered_buffer_setup(indio_dev, NULL,
1020c7eeea93SPeter Meerwald 					 mma8452_trigger_handler, NULL);
1021c7eeea93SPeter Meerwald 	if (ret < 0)
1022ae6d9ce0SMartin Fuzzey 		goto trigger_cleanup;
1023c7eeea93SPeter Meerwald 
102428e34278SMartin Fuzzey 	if (client->irq) {
102528e34278SMartin Fuzzey 		ret = devm_request_threaded_irq(&client->dev,
102628e34278SMartin Fuzzey 						client->irq,
102728e34278SMartin Fuzzey 						NULL, mma8452_interrupt,
102828e34278SMartin Fuzzey 						IRQF_TRIGGER_LOW | IRQF_ONESHOT,
102928e34278SMartin Fuzzey 						client->name, indio_dev);
103028e34278SMartin Fuzzey 		if (ret)
103128e34278SMartin Fuzzey 			goto buffer_cleanup;
103228e34278SMartin Fuzzey 	}
103328e34278SMartin Fuzzey 
1034c7eeea93SPeter Meerwald 	ret = iio_device_register(indio_dev);
1035c7eeea93SPeter Meerwald 	if (ret < 0)
1036c7eeea93SPeter Meerwald 		goto buffer_cleanup;
103728e34278SMartin Fuzzey 
1038c7eeea93SPeter Meerwald 	return 0;
1039c7eeea93SPeter Meerwald 
1040c7eeea93SPeter Meerwald buffer_cleanup:
1041c7eeea93SPeter Meerwald 	iio_triggered_buffer_cleanup(indio_dev);
1042ae6d9ce0SMartin Fuzzey 
1043ae6d9ce0SMartin Fuzzey trigger_cleanup:
1044ae6d9ce0SMartin Fuzzey 	mma8452_trigger_cleanup(indio_dev);
1045ae6d9ce0SMartin Fuzzey 
1046c7eeea93SPeter Meerwald 	return ret;
1047c7eeea93SPeter Meerwald }
1048c7eeea93SPeter Meerwald 
1049c7eeea93SPeter Meerwald static int mma8452_remove(struct i2c_client *client)
1050c7eeea93SPeter Meerwald {
1051c7eeea93SPeter Meerwald 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
1052c7eeea93SPeter Meerwald 
1053c7eeea93SPeter Meerwald 	iio_device_unregister(indio_dev);
1054c7eeea93SPeter Meerwald 	iio_triggered_buffer_cleanup(indio_dev);
1055ae6d9ce0SMartin Fuzzey 	mma8452_trigger_cleanup(indio_dev);
1056c7eeea93SPeter Meerwald 	mma8452_standby(iio_priv(indio_dev));
1057c7eeea93SPeter Meerwald 
1058c7eeea93SPeter Meerwald 	return 0;
1059c7eeea93SPeter Meerwald }
1060c7eeea93SPeter Meerwald 
1061c7eeea93SPeter Meerwald #ifdef CONFIG_PM_SLEEP
1062c7eeea93SPeter Meerwald static int mma8452_suspend(struct device *dev)
1063c7eeea93SPeter Meerwald {
1064c7eeea93SPeter Meerwald 	return mma8452_standby(iio_priv(i2c_get_clientdata(
1065c7eeea93SPeter Meerwald 		to_i2c_client(dev))));
1066c7eeea93SPeter Meerwald }
1067c7eeea93SPeter Meerwald 
1068c7eeea93SPeter Meerwald static int mma8452_resume(struct device *dev)
1069c7eeea93SPeter Meerwald {
1070c7eeea93SPeter Meerwald 	return mma8452_active(iio_priv(i2c_get_clientdata(
1071c7eeea93SPeter Meerwald 		to_i2c_client(dev))));
1072c7eeea93SPeter Meerwald }
1073c7eeea93SPeter Meerwald 
1074c7eeea93SPeter Meerwald static SIMPLE_DEV_PM_OPS(mma8452_pm_ops, mma8452_suspend, mma8452_resume);
1075c7eeea93SPeter Meerwald #define MMA8452_PM_OPS (&mma8452_pm_ops)
1076c7eeea93SPeter Meerwald #else
1077c7eeea93SPeter Meerwald #define MMA8452_PM_OPS NULL
1078c7eeea93SPeter Meerwald #endif
1079c7eeea93SPeter Meerwald 
1080c7eeea93SPeter Meerwald static const struct i2c_device_id mma8452_id[] = {
1081*c3cdd6e4SMartin Kepplinger 	{ "mma8452", mma8452 },
1082c7eeea93SPeter Meerwald 	{ }
1083c7eeea93SPeter Meerwald };
1084c7eeea93SPeter Meerwald MODULE_DEVICE_TABLE(i2c, mma8452_id);
1085c7eeea93SPeter Meerwald 
1086c7eeea93SPeter Meerwald static struct i2c_driver mma8452_driver = {
1087c7eeea93SPeter Meerwald 	.driver = {
1088c7eeea93SPeter Meerwald 		.name	= "mma8452",
1089a3fb96a8SMartin Fuzzey 		.of_match_table = of_match_ptr(mma8452_dt_ids),
1090c7eeea93SPeter Meerwald 		.pm	= MMA8452_PM_OPS,
1091c7eeea93SPeter Meerwald 	},
1092c7eeea93SPeter Meerwald 	.probe = mma8452_probe,
1093c7eeea93SPeter Meerwald 	.remove = mma8452_remove,
1094c7eeea93SPeter Meerwald 	.id_table = mma8452_id,
1095c7eeea93SPeter Meerwald };
1096c7eeea93SPeter Meerwald module_i2c_driver(mma8452_driver);
1097c7eeea93SPeter Meerwald 
1098c7eeea93SPeter Meerwald MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
1099c7eeea93SPeter Meerwald MODULE_DESCRIPTION("Freescale MMA8452 accelerometer driver");
1100c7eeea93SPeter Meerwald MODULE_LICENSE("GPL");
1101