xref: /linux/drivers/iio/accel/mma8452.c (revision cd327b0047698950d9a8285de8cf9587bca59b00)
1c7eeea93SPeter Meerwald /*
2f26ab1aaSMartin Kepplinger  * mma8452.c - Support for following Freescale / NXP 3-axis accelerometers:
3c5ea1b58SMartin Kepplinger  *
416df666aSMartin Kepplinger  * device name	digital output	7-bit I2C slave address (pin selectable)
516df666aSMartin Kepplinger  * ---------------------------------------------------------------------
616df666aSMartin Kepplinger  * MMA8451Q	14 bit		0x1c / 0x1d
716df666aSMartin Kepplinger  * MMA8452Q	12 bit		0x1c / 0x1d
816df666aSMartin Kepplinger  * MMA8453Q	10 bit		0x1c / 0x1d
916df666aSMartin Kepplinger  * MMA8652FC	12 bit		0x1d
1016df666aSMartin Kepplinger  * MMA8653FC	10 bit		0x1d
1116df666aSMartin Kepplinger  * FXLS8471Q	14 bit		0x1e / 0x1d / 0x1c / 0x1f
12c7eeea93SPeter Meerwald  *
1340836bc3SMartin Kepplinger  * Copyright 2015 Martin Kepplinger <martink@posteo.de>
14c7eeea93SPeter Meerwald  * Copyright 2014 Peter Meerwald <pmeerw@pmeerw.net>
15c7eeea93SPeter Meerwald  *
16c7eeea93SPeter Meerwald  * This file is subject to the terms and conditions of version 2 of
17c7eeea93SPeter Meerwald  * the GNU General Public License.  See the file COPYING in the main
18c7eeea93SPeter Meerwald  * directory of this archive for more details.
19c7eeea93SPeter Meerwald  *
20bce59b60SMartin Kepplinger  * TODO: orientation events
21c7eeea93SPeter Meerwald  */
22c7eeea93SPeter Meerwald 
23c7eeea93SPeter Meerwald #include <linux/module.h>
24c7eeea93SPeter Meerwald #include <linux/i2c.h>
25c7eeea93SPeter Meerwald #include <linux/iio/iio.h>
26c7eeea93SPeter Meerwald #include <linux/iio/sysfs.h>
27c7eeea93SPeter Meerwald #include <linux/iio/buffer.h>
28ae6d9ce0SMartin Fuzzey #include <linux/iio/trigger.h>
29ae6d9ce0SMartin Fuzzey #include <linux/iio/trigger_consumer.h>
30c7eeea93SPeter Meerwald #include <linux/iio/triggered_buffer.h>
3128e34278SMartin Fuzzey #include <linux/iio/events.h>
32c7eeea93SPeter Meerwald #include <linux/delay.h>
33c3cdd6e4SMartin Kepplinger #include <linux/of_device.h>
34d2a3e093SMartin Kepplinger #include <linux/of_irq.h>
3596c0cb2bSMartin Kepplinger #include <linux/pm_runtime.h>
36c7eeea93SPeter Meerwald 
37c7eeea93SPeter Meerwald #define MMA8452_STATUS				0x00
3869abff81SHartmut Knaack #define  MMA8452_STATUS_DRDY			(BIT(2) | BIT(1) | BIT(0))
39c5ea1b58SMartin Kepplinger #define MMA8452_OUT_X				0x01 /* MSB first */
40c7eeea93SPeter Meerwald #define MMA8452_OUT_Y				0x03
41c7eeea93SPeter Meerwald #define MMA8452_OUT_Z				0x05
4228e34278SMartin Fuzzey #define MMA8452_INT_SRC				0x0c
43c7eeea93SPeter Meerwald #define MMA8452_WHO_AM_I			0x0d
44c7eeea93SPeter Meerwald #define MMA8452_DATA_CFG			0x0e
4569abff81SHartmut Knaack #define  MMA8452_DATA_CFG_FS_MASK		GENMASK(1, 0)
4669abff81SHartmut Knaack #define  MMA8452_DATA_CFG_FS_2G			0
4769abff81SHartmut Knaack #define  MMA8452_DATA_CFG_FS_4G			1
4869abff81SHartmut Knaack #define  MMA8452_DATA_CFG_FS_8G			2
4969abff81SHartmut Knaack #define  MMA8452_DATA_CFG_HPF_MASK		BIT(4)
501e79841aSMartin Fuzzey #define MMA8452_HP_FILTER_CUTOFF		0x0f
5169abff81SHartmut Knaack #define  MMA8452_HP_FILTER_CUTOFF_SEL_MASK	GENMASK(1, 0)
5260f562e7SMartin Kepplinger #define MMA8452_FF_MT_CFG			0x15
5360f562e7SMartin Kepplinger #define  MMA8452_FF_MT_CFG_OAE			BIT(6)
5460f562e7SMartin Kepplinger #define  MMA8452_FF_MT_CFG_ELE			BIT(7)
5560f562e7SMartin Kepplinger #define MMA8452_FF_MT_SRC			0x16
5660f562e7SMartin Kepplinger #define  MMA8452_FF_MT_SRC_XHE			BIT(1)
5760f562e7SMartin Kepplinger #define  MMA8452_FF_MT_SRC_YHE			BIT(3)
5860f562e7SMartin Kepplinger #define  MMA8452_FF_MT_SRC_ZHE			BIT(5)
5960f562e7SMartin Kepplinger #define MMA8452_FF_MT_THS			0x17
6060f562e7SMartin Kepplinger #define  MMA8452_FF_MT_THS_MASK			0x7f
6160f562e7SMartin Kepplinger #define MMA8452_FF_MT_COUNT			0x18
62605f72deSHarinath Nampally #define MMA8452_FF_MT_CHAN_SHIFT	3
6328e34278SMartin Fuzzey #define MMA8452_TRANSIENT_CFG			0x1d
64605f72deSHarinath Nampally #define  MMA8452_TRANSIENT_CFG_CHAN(chan)	BIT(chan + 1)
651e79841aSMartin Fuzzey #define  MMA8452_TRANSIENT_CFG_HPF_BYP		BIT(0)
6669abff81SHartmut Knaack #define  MMA8452_TRANSIENT_CFG_ELE		BIT(4)
6728e34278SMartin Fuzzey #define MMA8452_TRANSIENT_SRC			0x1e
6828e34278SMartin Fuzzey #define  MMA8452_TRANSIENT_SRC_XTRANSE		BIT(1)
6928e34278SMartin Fuzzey #define  MMA8452_TRANSIENT_SRC_YTRANSE		BIT(3)
7028e34278SMartin Fuzzey #define  MMA8452_TRANSIENT_SRC_ZTRANSE		BIT(5)
7128e34278SMartin Fuzzey #define MMA8452_TRANSIENT_THS			0x1f
7269abff81SHartmut Knaack #define  MMA8452_TRANSIENT_THS_MASK		GENMASK(6, 0)
735dbbd19fSMartin Fuzzey #define MMA8452_TRANSIENT_COUNT			0x20
74605f72deSHarinath Nampally #define MMA8452_TRANSIENT_CHAN_SHIFT 1
75c7eeea93SPeter Meerwald #define MMA8452_CTRL_REG1			0x2a
7669abff81SHartmut Knaack #define  MMA8452_CTRL_ACTIVE			BIT(0)
7769abff81SHartmut Knaack #define  MMA8452_CTRL_DR_MASK			GENMASK(5, 3)
7869abff81SHartmut Knaack #define  MMA8452_CTRL_DR_SHIFT			3
7969abff81SHartmut Knaack #define  MMA8452_CTRL_DR_DEFAULT		0x4 /* 50 Hz sample frequency */
80c7eeea93SPeter Meerwald #define MMA8452_CTRL_REG2			0x2b
81ecabae71SMartin Fuzzey #define  MMA8452_CTRL_REG2_RST			BIT(6)
82ed859fc1SMartin Kepplinger #define  MMA8452_CTRL_REG2_MODS_SHIFT		3
83ed859fc1SMartin Kepplinger #define  MMA8452_CTRL_REG2_MODS_MASK		0x1b
8428e34278SMartin Fuzzey #define MMA8452_CTRL_REG4			0x2d
8528e34278SMartin Fuzzey #define MMA8452_CTRL_REG5			0x2e
8669abff81SHartmut Knaack #define MMA8452_OFF_X				0x2f
8769abff81SHartmut Knaack #define MMA8452_OFF_Y				0x30
8869abff81SHartmut Knaack #define MMA8452_OFF_Z				0x31
89c7eeea93SPeter Meerwald 
902a17698cSMartin Fuzzey #define MMA8452_MAX_REG				0x31
912a17698cSMartin Fuzzey 
92ae6d9ce0SMartin Fuzzey #define  MMA8452_INT_DRDY			BIT(0)
9360f562e7SMartin Kepplinger #define  MMA8452_INT_FF_MT			BIT(2)
9428e34278SMartin Fuzzey #define  MMA8452_INT_TRANS			BIT(5)
9528e34278SMartin Fuzzey 
96244a93f6SMartin Kepplinger #define MMA8451_DEVICE_ID			0x1a
97c7eeea93SPeter Meerwald #define MMA8452_DEVICE_ID			0x2a
98c5ea1b58SMartin Kepplinger #define MMA8453_DEVICE_ID			0x3a
99417e008bSMartin Kepplinger #define MMA8652_DEVICE_ID			0x4a
100417e008bSMartin Kepplinger #define MMA8653_DEVICE_ID			0x5a
101e8731180SMartin Kepplinger #define FXLS8471_DEVICE_ID			0x6a
102c7eeea93SPeter Meerwald 
10396c0cb2bSMartin Kepplinger #define MMA8452_AUTO_SUSPEND_DELAY_MS		2000
10496c0cb2bSMartin Kepplinger 
105c7eeea93SPeter Meerwald struct mma8452_data {
106c7eeea93SPeter Meerwald 	struct i2c_client *client;
107c7eeea93SPeter Meerwald 	struct mutex lock;
108c7eeea93SPeter Meerwald 	u8 ctrl_reg1;
109c7eeea93SPeter Meerwald 	u8 data_cfg;
110c3cdd6e4SMartin Kepplinger 	const struct mma_chip_info *chip_info;
111c3cdd6e4SMartin Kepplinger };
112c3cdd6e4SMartin Kepplinger 
113c3cdd6e4SMartin Kepplinger  /**
114605f72deSHarinath Nampally   * struct mma8452_event_regs - chip specific data related to events
115c3cdd6e4SMartin Kepplinger   * @ev_cfg:			event config register address
116c3cdd6e4SMartin Kepplinger   * @ev_cfg_ele:			latch bit in event config register
117c3cdd6e4SMartin Kepplinger   * @ev_cfg_chan_shift:		number of the bit to enable events in X
118c3cdd6e4SMartin Kepplinger   *				direction; in event config register
119c3cdd6e4SMartin Kepplinger   * @ev_src:			event source register address
120c3cdd6e4SMartin Kepplinger   * @ev_ths:			event threshold register address
121c3cdd6e4SMartin Kepplinger   * @ev_ths_mask:		mask for the threshold value
122c3cdd6e4SMartin Kepplinger   * @ev_count:			event count (period) register address
123c3cdd6e4SMartin Kepplinger   *
124c3cdd6e4SMartin Kepplinger   * Since not all chips supported by the driver support comparing high pass
125c3cdd6e4SMartin Kepplinger   * filtered data for events (interrupts), different interrupt sources are
126c3cdd6e4SMartin Kepplinger   * used for different chips and the relevant registers are included here.
127c3cdd6e4SMartin Kepplinger   */
128605f72deSHarinath Nampally struct mma8452_event_regs {
129605f72deSHarinath Nampally 		u8 ev_cfg;
130605f72deSHarinath Nampally 		u8 ev_cfg_ele;
131605f72deSHarinath Nampally 		u8 ev_cfg_chan_shift;
132605f72deSHarinath Nampally 		u8 ev_src;
133605f72deSHarinath Nampally 		u8 ev_ths;
134605f72deSHarinath Nampally 		u8 ev_ths_mask;
135605f72deSHarinath Nampally 		u8 ev_count;
136605f72deSHarinath Nampally };
137605f72deSHarinath Nampally 
138605f72deSHarinath Nampally static const struct mma8452_event_regs ev_regs_accel_falling = {
139605f72deSHarinath Nampally 		.ev_cfg = MMA8452_FF_MT_CFG,
140605f72deSHarinath Nampally 		.ev_cfg_ele = MMA8452_FF_MT_CFG_ELE,
141605f72deSHarinath Nampally 		.ev_cfg_chan_shift = MMA8452_FF_MT_CHAN_SHIFT,
142605f72deSHarinath Nampally 		.ev_src = MMA8452_FF_MT_SRC,
143605f72deSHarinath Nampally 		.ev_ths = MMA8452_FF_MT_THS,
144605f72deSHarinath Nampally 		.ev_ths_mask = MMA8452_FF_MT_THS_MASK,
145605f72deSHarinath Nampally 		.ev_count = MMA8452_FF_MT_COUNT
146605f72deSHarinath Nampally };
147605f72deSHarinath Nampally 
148605f72deSHarinath Nampally static const struct mma8452_event_regs ev_regs_accel_rising = {
149605f72deSHarinath Nampally 		.ev_cfg = MMA8452_TRANSIENT_CFG,
150605f72deSHarinath Nampally 		.ev_cfg_ele = MMA8452_TRANSIENT_CFG_ELE,
151605f72deSHarinath Nampally 		.ev_cfg_chan_shift = MMA8452_TRANSIENT_CHAN_SHIFT,
152605f72deSHarinath Nampally 		.ev_src = MMA8452_TRANSIENT_SRC,
153605f72deSHarinath Nampally 		.ev_ths = MMA8452_TRANSIENT_THS,
154605f72deSHarinath Nampally 		.ev_ths_mask = MMA8452_TRANSIENT_THS_MASK,
155605f72deSHarinath Nampally 		.ev_count = MMA8452_TRANSIENT_COUNT,
156605f72deSHarinath Nampally };
157605f72deSHarinath Nampally 
158605f72deSHarinath Nampally /**
159605f72deSHarinath Nampally  * struct mma_chip_info - chip specific data
160605f72deSHarinath Nampally  * @chip_id:			WHO_AM_I register's value
161605f72deSHarinath Nampally  * @channels:			struct iio_chan_spec matching the device's
162605f72deSHarinath Nampally  *				capabilities
163605f72deSHarinath Nampally  * @num_channels:		number of channels
164605f72deSHarinath Nampally  * @mma_scales:			scale factors for converting register values
165605f72deSHarinath Nampally  *				to m/s^2; 3 modes: 2g, 4g, 8g; 2 integers
166605f72deSHarinath Nampally  *				per mode: m/s^2 and micro m/s^2
167605f72deSHarinath Nampally  * @all_events:			all events supported by this chip
168605f72deSHarinath Nampally  * @enabled_events:		event flags enabled and handled by this driver
169605f72deSHarinath Nampally  */
170c3cdd6e4SMartin Kepplinger struct mma_chip_info {
171c3cdd6e4SMartin Kepplinger 	u8 chip_id;
172c3cdd6e4SMartin Kepplinger 	const struct iio_chan_spec *channels;
173c3cdd6e4SMartin Kepplinger 	int num_channels;
174c3cdd6e4SMartin Kepplinger 	const int mma_scales[3][2];
175605f72deSHarinath Nampally 	int all_events;
176605f72deSHarinath Nampally 	int enabled_events;
177c7eeea93SPeter Meerwald };
178c7eeea93SPeter Meerwald 
179e60378c1SMartin Kepplinger enum {
180e60378c1SMartin Kepplinger 	idx_x,
181e60378c1SMartin Kepplinger 	idx_y,
182e60378c1SMartin Kepplinger 	idx_z,
183e60378c1SMartin Kepplinger 	idx_ts,
184e60378c1SMartin Kepplinger };
185e60378c1SMartin Kepplinger 
186c7eeea93SPeter Meerwald static int mma8452_drdy(struct mma8452_data *data)
187c7eeea93SPeter Meerwald {
188c7eeea93SPeter Meerwald 	int tries = 150;
189c7eeea93SPeter Meerwald 
190c7eeea93SPeter Meerwald 	while (tries-- > 0) {
191c7eeea93SPeter Meerwald 		int ret = i2c_smbus_read_byte_data(data->client,
192c7eeea93SPeter Meerwald 			MMA8452_STATUS);
193c7eeea93SPeter Meerwald 		if (ret < 0)
194c7eeea93SPeter Meerwald 			return ret;
195c7eeea93SPeter Meerwald 		if ((ret & MMA8452_STATUS_DRDY) == MMA8452_STATUS_DRDY)
196c7eeea93SPeter Meerwald 			return 0;
197686027fbSHartmut Knaack 
198c7eeea93SPeter Meerwald 		msleep(20);
199c7eeea93SPeter Meerwald 	}
200c7eeea93SPeter Meerwald 
201c7eeea93SPeter Meerwald 	dev_err(&data->client->dev, "data not ready\n");
202686027fbSHartmut Knaack 
203c7eeea93SPeter Meerwald 	return -EIO;
204c7eeea93SPeter Meerwald }
205c7eeea93SPeter Meerwald 
20696c0cb2bSMartin Kepplinger static int mma8452_set_runtime_pm_state(struct i2c_client *client, bool on)
20796c0cb2bSMartin Kepplinger {
20896c0cb2bSMartin Kepplinger #ifdef CONFIG_PM
20996c0cb2bSMartin Kepplinger 	int ret;
21096c0cb2bSMartin Kepplinger 
21196c0cb2bSMartin Kepplinger 	if (on) {
21296c0cb2bSMartin Kepplinger 		ret = pm_runtime_get_sync(&client->dev);
21396c0cb2bSMartin Kepplinger 	} else {
21496c0cb2bSMartin Kepplinger 		pm_runtime_mark_last_busy(&client->dev);
21596c0cb2bSMartin Kepplinger 		ret = pm_runtime_put_autosuspend(&client->dev);
21696c0cb2bSMartin Kepplinger 	}
21796c0cb2bSMartin Kepplinger 
21896c0cb2bSMartin Kepplinger 	if (ret < 0) {
21996c0cb2bSMartin Kepplinger 		dev_err(&client->dev,
22096c0cb2bSMartin Kepplinger 			"failed to change power state to %d\n", on);
22196c0cb2bSMartin Kepplinger 		if (on)
22296c0cb2bSMartin Kepplinger 			pm_runtime_put_noidle(&client->dev);
22396c0cb2bSMartin Kepplinger 
22496c0cb2bSMartin Kepplinger 		return ret;
22596c0cb2bSMartin Kepplinger 	}
22696c0cb2bSMartin Kepplinger #endif
22796c0cb2bSMartin Kepplinger 
22896c0cb2bSMartin Kepplinger 	return 0;
22996c0cb2bSMartin Kepplinger }
23096c0cb2bSMartin Kepplinger 
231c7eeea93SPeter Meerwald static int mma8452_read(struct mma8452_data *data, __be16 buf[3])
232c7eeea93SPeter Meerwald {
233c7eeea93SPeter Meerwald 	int ret = mma8452_drdy(data);
234686027fbSHartmut Knaack 
235c7eeea93SPeter Meerwald 	if (ret < 0)
236c7eeea93SPeter Meerwald 		return ret;
237686027fbSHartmut Knaack 
23896c0cb2bSMartin Kepplinger 	ret = mma8452_set_runtime_pm_state(data->client, true);
23996c0cb2bSMartin Kepplinger 	if (ret)
24096c0cb2bSMartin Kepplinger 		return ret;
24196c0cb2bSMartin Kepplinger 
24296c0cb2bSMartin Kepplinger 	ret = i2c_smbus_read_i2c_block_data(data->client, MMA8452_OUT_X,
243686027fbSHartmut Knaack 					    3 * sizeof(__be16), (u8 *)buf);
24496c0cb2bSMartin Kepplinger 
24596c0cb2bSMartin Kepplinger 	ret = mma8452_set_runtime_pm_state(data->client, false);
24696c0cb2bSMartin Kepplinger 
24796c0cb2bSMartin Kepplinger 	return ret;
248c7eeea93SPeter Meerwald }
249c7eeea93SPeter Meerwald 
250686027fbSHartmut Knaack static ssize_t mma8452_show_int_plus_micros(char *buf, const int (*vals)[2],
251686027fbSHartmut Knaack 					    int n)
252c7eeea93SPeter Meerwald {
253c7eeea93SPeter Meerwald 	size_t len = 0;
254c7eeea93SPeter Meerwald 
255c7eeea93SPeter Meerwald 	while (n-- > 0)
256686027fbSHartmut Knaack 		len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06d ",
257686027fbSHartmut Knaack 				 vals[n][0], vals[n][1]);
258c7eeea93SPeter Meerwald 
259c7eeea93SPeter Meerwald 	/* replace trailing space by newline */
260c7eeea93SPeter Meerwald 	buf[len - 1] = '\n';
261c7eeea93SPeter Meerwald 
262c7eeea93SPeter Meerwald 	return len;
263c7eeea93SPeter Meerwald }
264c7eeea93SPeter Meerwald 
265c7eeea93SPeter Meerwald static int mma8452_get_int_plus_micros_index(const int (*vals)[2], int n,
266c7eeea93SPeter Meerwald 					     int val, int val2)
267c7eeea93SPeter Meerwald {
268c7eeea93SPeter Meerwald 	while (n-- > 0)
269c7eeea93SPeter Meerwald 		if (val == vals[n][0] && val2 == vals[n][1])
270c7eeea93SPeter Meerwald 			return n;
271c7eeea93SPeter Meerwald 
272c7eeea93SPeter Meerwald 	return -EINVAL;
273c7eeea93SPeter Meerwald }
274c7eeea93SPeter Meerwald 
27532b28076SMartin Kepplinger static unsigned int mma8452_get_odr_index(struct mma8452_data *data)
2765dbbd19fSMartin Fuzzey {
2775dbbd19fSMartin Fuzzey 	return (data->ctrl_reg1 & MMA8452_CTRL_DR_MASK) >>
2785dbbd19fSMartin Fuzzey 			MMA8452_CTRL_DR_SHIFT;
2795dbbd19fSMartin Fuzzey }
2805dbbd19fSMartin Fuzzey 
281c7eeea93SPeter Meerwald static const int mma8452_samp_freq[8][2] = {
282c7eeea93SPeter Meerwald 	{800, 0}, {400, 0}, {200, 0}, {100, 0}, {50, 0}, {12, 500000},
283c7eeea93SPeter Meerwald 	{6, 250000}, {1, 560000}
284c7eeea93SPeter Meerwald };
285c7eeea93SPeter Meerwald 
286ed859fc1SMartin Kepplinger /* Datasheet table: step time "Relationship with the ODR" (sample frequency) */
28732b28076SMartin Kepplinger static const unsigned int mma8452_transient_time_step_us[4][8] = {
288ed859fc1SMartin Kepplinger 	{ 1250, 2500, 5000, 10000, 20000, 20000, 20000, 20000 },  /* normal */
289ed859fc1SMartin Kepplinger 	{ 1250, 2500, 5000, 10000, 20000, 80000, 80000, 80000 },  /* l p l n */
290ed859fc1SMartin Kepplinger 	{ 1250, 2500, 2500, 2500, 2500, 2500, 2500, 2500 },	  /* high res*/
291ed859fc1SMartin Kepplinger 	{ 1250, 2500, 5000, 10000, 20000, 80000, 160000, 160000 } /* l p */
2925dbbd19fSMartin Fuzzey };
2935dbbd19fSMartin Fuzzey 
294ed859fc1SMartin Kepplinger /* Datasheet table "High-Pass Filter Cutoff Options" */
295ed859fc1SMartin Kepplinger static const int mma8452_hp_filter_cutoff[4][8][4][2] = {
296ed859fc1SMartin Kepplinger 	{ /* normal */
2971e79841aSMartin Fuzzey 	{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },		/* 800 Hz sample */
2981e79841aSMartin Fuzzey 	{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },		/* 400 Hz sample */
2991e79841aSMartin Fuzzey 	{ {8, 0}, {4, 0}, {2, 0}, {1, 0} },		/* 200 Hz sample */
3001e79841aSMartin Fuzzey 	{ {4, 0}, {2, 0}, {1, 0}, {0, 500000} },	/* 100 Hz sample */
3011e79841aSMartin Fuzzey 	{ {2, 0}, {1, 0}, {0, 500000}, {0, 250000} },	/* 50 Hz sample */
3021e79841aSMartin Fuzzey 	{ {2, 0}, {1, 0}, {0, 500000}, {0, 250000} },	/* 12.5 Hz sample */
3031e79841aSMartin Fuzzey 	{ {2, 0}, {1, 0}, {0, 500000}, {0, 250000} },	/* 6.25 Hz sample */
3041e79841aSMartin Fuzzey 	{ {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }	/* 1.56 Hz sample */
305ed859fc1SMartin Kepplinger 	},
306ed859fc1SMartin Kepplinger 	{ /* low noise low power */
307ed859fc1SMartin Kepplinger 	{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },
308ed859fc1SMartin Kepplinger 	{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },
309ed859fc1SMartin Kepplinger 	{ {8, 0}, {4, 0}, {2, 0}, {1, 0} },
310ed859fc1SMartin Kepplinger 	{ {4, 0}, {2, 0}, {1, 0}, {0, 500000} },
311ed859fc1SMartin Kepplinger 	{ {2, 0}, {1, 0}, {0, 500000}, {0, 250000} },
312ed859fc1SMartin Kepplinger 	{ {0, 500000}, {0, 250000}, {0, 125000}, {0, 063000} },
313ed859fc1SMartin Kepplinger 	{ {0, 500000}, {0, 250000}, {0, 125000}, {0, 063000} },
314ed859fc1SMartin Kepplinger 	{ {0, 500000}, {0, 250000}, {0, 125000}, {0, 063000} }
315ed859fc1SMartin Kepplinger 	},
316ed859fc1SMartin Kepplinger 	{ /* high resolution */
317ed859fc1SMartin Kepplinger 	{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },
318ed859fc1SMartin Kepplinger 	{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },
319ed859fc1SMartin Kepplinger 	{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },
320ed859fc1SMartin Kepplinger 	{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },
321ed859fc1SMartin Kepplinger 	{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },
322ed859fc1SMartin Kepplinger 	{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },
323ed859fc1SMartin Kepplinger 	{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },
324ed859fc1SMartin Kepplinger 	{ {16, 0}, {8, 0}, {4, 0}, {2, 0} }
325ed859fc1SMartin Kepplinger 	},
326ed859fc1SMartin Kepplinger 	{ /* low power */
327ed859fc1SMartin Kepplinger 	{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },
328ed859fc1SMartin Kepplinger 	{ {8, 0}, {4, 0}, {2, 0}, {1, 0} },
329ed859fc1SMartin Kepplinger 	{ {4, 0}, {2, 0}, {1, 0}, {0, 500000} },
330ed859fc1SMartin Kepplinger 	{ {2, 0}, {1, 0}, {0, 500000}, {0, 250000} },
331ed859fc1SMartin Kepplinger 	{ {1, 0}, {0, 500000}, {0, 250000}, {0, 125000} },
332ed859fc1SMartin Kepplinger 	{ {0, 250000}, {0, 125000}, {0, 063000}, {0, 031000} },
333ed859fc1SMartin Kepplinger 	{ {0, 250000}, {0, 125000}, {0, 063000}, {0, 031000} },
334ed859fc1SMartin Kepplinger 	{ {0, 250000}, {0, 125000}, {0, 063000}, {0, 031000} }
335ed859fc1SMartin Kepplinger 	}
3361e79841aSMartin Fuzzey };
3371e79841aSMartin Fuzzey 
338ed859fc1SMartin Kepplinger /* Datasheet table "MODS Oversampling modes averaging values at each ODR" */
339ed859fc1SMartin Kepplinger static const u16 mma8452_os_ratio[4][8] = {
340ed859fc1SMartin Kepplinger 	/* 800 Hz, 400 Hz, ... , 1.56 Hz */
341ed859fc1SMartin Kepplinger 	{ 2, 4, 4, 4, 4, 16, 32, 128 },		/* normal */
342ed859fc1SMartin Kepplinger 	{ 2, 4, 4, 4, 4, 4, 8, 32 },		/* low power low noise */
343ed859fc1SMartin Kepplinger 	{ 2, 4, 8, 16, 32, 128, 256, 1024 },	/* high resolution */
344ed859fc1SMartin Kepplinger 	{ 2, 2, 2, 2, 2, 2, 4, 16 }		/* low power */
345ed859fc1SMartin Kepplinger };
346ed859fc1SMartin Kepplinger 
347ed859fc1SMartin Kepplinger static int mma8452_get_power_mode(struct mma8452_data *data)
348ed859fc1SMartin Kepplinger {
349ed859fc1SMartin Kepplinger 	int reg;
350ed859fc1SMartin Kepplinger 
351ed859fc1SMartin Kepplinger 	reg = i2c_smbus_read_byte_data(data->client,
352ed859fc1SMartin Kepplinger 				       MMA8452_CTRL_REG2);
353ed859fc1SMartin Kepplinger 	if (reg < 0)
354ed859fc1SMartin Kepplinger 		return reg;
355ed859fc1SMartin Kepplinger 
356ed859fc1SMartin Kepplinger 	return ((reg & MMA8452_CTRL_REG2_MODS_MASK) >>
357ed859fc1SMartin Kepplinger 		MMA8452_CTRL_REG2_MODS_SHIFT);
358ed859fc1SMartin Kepplinger }
359ed859fc1SMartin Kepplinger 
360c7eeea93SPeter Meerwald static ssize_t mma8452_show_samp_freq_avail(struct device *dev,
361686027fbSHartmut Knaack 					    struct device_attribute *attr,
362686027fbSHartmut Knaack 					    char *buf)
363c7eeea93SPeter Meerwald {
364c7eeea93SPeter Meerwald 	return mma8452_show_int_plus_micros(buf, mma8452_samp_freq,
365c7eeea93SPeter Meerwald 					    ARRAY_SIZE(mma8452_samp_freq));
366c7eeea93SPeter Meerwald }
367c7eeea93SPeter Meerwald 
368c7eeea93SPeter Meerwald static ssize_t mma8452_show_scale_avail(struct device *dev,
369686027fbSHartmut Knaack 					struct device_attribute *attr,
370686027fbSHartmut Knaack 					char *buf)
371c7eeea93SPeter Meerwald {
372c3cdd6e4SMartin Kepplinger 	struct mma8452_data *data = iio_priv(i2c_get_clientdata(
373c3cdd6e4SMartin Kepplinger 					     to_i2c_client(dev)));
374c3cdd6e4SMartin Kepplinger 
375c3cdd6e4SMartin Kepplinger 	return mma8452_show_int_plus_micros(buf, data->chip_info->mma_scales,
376c3cdd6e4SMartin Kepplinger 		ARRAY_SIZE(data->chip_info->mma_scales));
377c7eeea93SPeter Meerwald }
378c7eeea93SPeter Meerwald 
3791e79841aSMartin Fuzzey static ssize_t mma8452_show_hp_cutoff_avail(struct device *dev,
3801e79841aSMartin Fuzzey 					    struct device_attribute *attr,
3811e79841aSMartin Fuzzey 					    char *buf)
3821e79841aSMartin Fuzzey {
3831e79841aSMartin Fuzzey 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
3841e79841aSMartin Fuzzey 	struct mma8452_data *data = iio_priv(indio_dev);
385ed859fc1SMartin Kepplinger 	int i, j;
3861e79841aSMartin Fuzzey 
387ed859fc1SMartin Kepplinger 	i = mma8452_get_odr_index(data);
388ed859fc1SMartin Kepplinger 	j = mma8452_get_power_mode(data);
389ed859fc1SMartin Kepplinger 	if (j < 0)
390ed859fc1SMartin Kepplinger 		return j;
391ed859fc1SMartin Kepplinger 
392ed859fc1SMartin Kepplinger 	return mma8452_show_int_plus_micros(buf, mma8452_hp_filter_cutoff[j][i],
393ed859fc1SMartin Kepplinger 		ARRAY_SIZE(mma8452_hp_filter_cutoff[0][0]));
394ed859fc1SMartin Kepplinger }
395ed859fc1SMartin Kepplinger 
396ed859fc1SMartin Kepplinger static ssize_t mma8452_show_os_ratio_avail(struct device *dev,
397ed859fc1SMartin Kepplinger 					   struct device_attribute *attr,
398ed859fc1SMartin Kepplinger 					   char *buf)
399ed859fc1SMartin Kepplinger {
400ed859fc1SMartin Kepplinger 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
401ed859fc1SMartin Kepplinger 	struct mma8452_data *data = iio_priv(indio_dev);
402ed859fc1SMartin Kepplinger 	int i = mma8452_get_odr_index(data);
403ed859fc1SMartin Kepplinger 	int j;
404ed859fc1SMartin Kepplinger 	u16 val = 0;
405ed859fc1SMartin Kepplinger 	size_t len = 0;
406ed859fc1SMartin Kepplinger 
407ed859fc1SMartin Kepplinger 	for (j = 0; j < ARRAY_SIZE(mma8452_os_ratio); j++) {
408ed859fc1SMartin Kepplinger 		if (val == mma8452_os_ratio[j][i])
409ed859fc1SMartin Kepplinger 			continue;
410ed859fc1SMartin Kepplinger 
411ed859fc1SMartin Kepplinger 		val = mma8452_os_ratio[j][i];
412ed859fc1SMartin Kepplinger 
413ed859fc1SMartin Kepplinger 		len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", val);
414ed859fc1SMartin Kepplinger 	}
415ed859fc1SMartin Kepplinger 	buf[len - 1] = '\n';
416ed859fc1SMartin Kepplinger 
417ed859fc1SMartin Kepplinger 	return len;
4181e79841aSMartin Fuzzey }
4191e79841aSMartin Fuzzey 
420c7eeea93SPeter Meerwald static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(mma8452_show_samp_freq_avail);
421*cd327b00SHarinath Nampally static IIO_DEVICE_ATTR(in_accel_scale_available, 0444,
422c7eeea93SPeter Meerwald 		       mma8452_show_scale_avail, NULL, 0);
4231e79841aSMartin Fuzzey static IIO_DEVICE_ATTR(in_accel_filter_high_pass_3db_frequency_available,
424*cd327b00SHarinath Nampally 		       0444, mma8452_show_hp_cutoff_avail, NULL, 0);
425*cd327b00SHarinath Nampally static IIO_DEVICE_ATTR(in_accel_oversampling_ratio_available, 0444,
426ed859fc1SMartin Kepplinger 		       mma8452_show_os_ratio_avail, NULL, 0);
427c7eeea93SPeter Meerwald 
428c7eeea93SPeter Meerwald static int mma8452_get_samp_freq_index(struct mma8452_data *data,
429c7eeea93SPeter Meerwald 				       int val, int val2)
430c7eeea93SPeter Meerwald {
431c7eeea93SPeter Meerwald 	return mma8452_get_int_plus_micros_index(mma8452_samp_freq,
432686027fbSHartmut Knaack 						 ARRAY_SIZE(mma8452_samp_freq),
433686027fbSHartmut Knaack 						 val, val2);
434c7eeea93SPeter Meerwald }
435c7eeea93SPeter Meerwald 
436686027fbSHartmut Knaack static int mma8452_get_scale_index(struct mma8452_data *data, int val, int val2)
437c7eeea93SPeter Meerwald {
438c3cdd6e4SMartin Kepplinger 	return mma8452_get_int_plus_micros_index(data->chip_info->mma_scales,
439c3cdd6e4SMartin Kepplinger 			ARRAY_SIZE(data->chip_info->mma_scales), val, val2);
440c7eeea93SPeter Meerwald }
441c7eeea93SPeter Meerwald 
4421e79841aSMartin Fuzzey static int mma8452_get_hp_filter_index(struct mma8452_data *data,
4431e79841aSMartin Fuzzey 				       int val, int val2)
4441e79841aSMartin Fuzzey {
445ed859fc1SMartin Kepplinger 	int i, j;
4461e79841aSMartin Fuzzey 
447ed859fc1SMartin Kepplinger 	i = mma8452_get_odr_index(data);
448ed859fc1SMartin Kepplinger 	j = mma8452_get_power_mode(data);
449ed859fc1SMartin Kepplinger 	if (j < 0)
450ed859fc1SMartin Kepplinger 		return j;
451ed859fc1SMartin Kepplinger 
452ed859fc1SMartin Kepplinger 	return mma8452_get_int_plus_micros_index(mma8452_hp_filter_cutoff[j][i],
453ed859fc1SMartin Kepplinger 		ARRAY_SIZE(mma8452_hp_filter_cutoff[0][0]), val, val2);
4541e79841aSMartin Fuzzey }
4551e79841aSMartin Fuzzey 
4561e79841aSMartin Fuzzey static int mma8452_read_hp_filter(struct mma8452_data *data, int *hz, int *uHz)
4571e79841aSMartin Fuzzey {
458ed859fc1SMartin Kepplinger 	int j, i, ret;
4591e79841aSMartin Fuzzey 
4601e79841aSMartin Fuzzey 	ret = i2c_smbus_read_byte_data(data->client, MMA8452_HP_FILTER_CUTOFF);
4611e79841aSMartin Fuzzey 	if (ret < 0)
4621e79841aSMartin Fuzzey 		return ret;
4631e79841aSMartin Fuzzey 
4641e79841aSMartin Fuzzey 	i = mma8452_get_odr_index(data);
465ed859fc1SMartin Kepplinger 	j = mma8452_get_power_mode(data);
466ed859fc1SMartin Kepplinger 	if (j < 0)
467ed859fc1SMartin Kepplinger 		return j;
468ed859fc1SMartin Kepplinger 
4691e79841aSMartin Fuzzey 	ret &= MMA8452_HP_FILTER_CUTOFF_SEL_MASK;
470ed859fc1SMartin Kepplinger 	*hz = mma8452_hp_filter_cutoff[j][i][ret][0];
471ed859fc1SMartin Kepplinger 	*uHz = mma8452_hp_filter_cutoff[j][i][ret][1];
4721e79841aSMartin Fuzzey 
4731e79841aSMartin Fuzzey 	return 0;
4741e79841aSMartin Fuzzey }
4751e79841aSMartin Fuzzey 
476c7eeea93SPeter Meerwald static int mma8452_read_raw(struct iio_dev *indio_dev,
477c7eeea93SPeter Meerwald 			    struct iio_chan_spec const *chan,
478c7eeea93SPeter Meerwald 			    int *val, int *val2, long mask)
479c7eeea93SPeter Meerwald {
480c7eeea93SPeter Meerwald 	struct mma8452_data *data = iio_priv(indio_dev);
481c7eeea93SPeter Meerwald 	__be16 buffer[3];
482c7eeea93SPeter Meerwald 	int i, ret;
483c7eeea93SPeter Meerwald 
484c7eeea93SPeter Meerwald 	switch (mask) {
485c7eeea93SPeter Meerwald 	case IIO_CHAN_INFO_RAW:
4864d9b0413SAlison Schofield 		ret = iio_device_claim_direct_mode(indio_dev);
4874d9b0413SAlison Schofield 		if (ret)
4884d9b0413SAlison Schofield 			return ret;
489c7eeea93SPeter Meerwald 
490c7eeea93SPeter Meerwald 		mutex_lock(&data->lock);
491c7eeea93SPeter Meerwald 		ret = mma8452_read(data, buffer);
492c7eeea93SPeter Meerwald 		mutex_unlock(&data->lock);
4934d9b0413SAlison Schofield 		iio_device_release_direct_mode(indio_dev);
494c7eeea93SPeter Meerwald 		if (ret < 0)
495c7eeea93SPeter Meerwald 			return ret;
496686027fbSHartmut Knaack 
497c3cdd6e4SMartin Kepplinger 		*val = sign_extend32(be16_to_cpu(
498c3cdd6e4SMartin Kepplinger 			buffer[chan->scan_index]) >> chan->scan_type.shift,
499c3cdd6e4SMartin Kepplinger 			chan->scan_type.realbits - 1);
500686027fbSHartmut Knaack 
501c7eeea93SPeter Meerwald 		return IIO_VAL_INT;
502c7eeea93SPeter Meerwald 	case IIO_CHAN_INFO_SCALE:
503c7eeea93SPeter Meerwald 		i = data->data_cfg & MMA8452_DATA_CFG_FS_MASK;
504c3cdd6e4SMartin Kepplinger 		*val = data->chip_info->mma_scales[i][0];
505c3cdd6e4SMartin Kepplinger 		*val2 = data->chip_info->mma_scales[i][1];
506686027fbSHartmut Knaack 
507c7eeea93SPeter Meerwald 		return IIO_VAL_INT_PLUS_MICRO;
508c7eeea93SPeter Meerwald 	case IIO_CHAN_INFO_SAMP_FREQ:
5095dbbd19fSMartin Fuzzey 		i = mma8452_get_odr_index(data);
510c7eeea93SPeter Meerwald 		*val = mma8452_samp_freq[i][0];
511c7eeea93SPeter Meerwald 		*val2 = mma8452_samp_freq[i][1];
512686027fbSHartmut Knaack 
513c7eeea93SPeter Meerwald 		return IIO_VAL_INT_PLUS_MICRO;
514c7eeea93SPeter Meerwald 	case IIO_CHAN_INFO_CALIBBIAS:
515686027fbSHartmut Knaack 		ret = i2c_smbus_read_byte_data(data->client,
5168b8ff3a6SMartin Kepplinger 					       MMA8452_OFF_X +
5178b8ff3a6SMartin Kepplinger 					       chan->scan_index);
518c7eeea93SPeter Meerwald 		if (ret < 0)
519c7eeea93SPeter Meerwald 			return ret;
520686027fbSHartmut Knaack 
521c7eeea93SPeter Meerwald 		*val = sign_extend32(ret, 7);
522686027fbSHartmut Knaack 
523c7eeea93SPeter Meerwald 		return IIO_VAL_INT;
5241e79841aSMartin Fuzzey 	case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
5251e79841aSMartin Fuzzey 		if (data->data_cfg & MMA8452_DATA_CFG_HPF_MASK) {
5261e79841aSMartin Fuzzey 			ret = mma8452_read_hp_filter(data, val, val2);
5271e79841aSMartin Fuzzey 			if (ret < 0)
5281e79841aSMartin Fuzzey 				return ret;
5291e79841aSMartin Fuzzey 		} else {
5301e79841aSMartin Fuzzey 			*val = 0;
5311e79841aSMartin Fuzzey 			*val2 = 0;
5321e79841aSMartin Fuzzey 		}
533686027fbSHartmut Knaack 
5341e79841aSMartin Fuzzey 		return IIO_VAL_INT_PLUS_MICRO;
535ed859fc1SMartin Kepplinger 	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
536ed859fc1SMartin Kepplinger 		ret = mma8452_get_power_mode(data);
537ed859fc1SMartin Kepplinger 		if (ret < 0)
538ed859fc1SMartin Kepplinger 			return ret;
539ed859fc1SMartin Kepplinger 
540ed859fc1SMartin Kepplinger 		i = mma8452_get_odr_index(data);
541ed859fc1SMartin Kepplinger 
542ed859fc1SMartin Kepplinger 		*val = mma8452_os_ratio[ret][i];
543ed859fc1SMartin Kepplinger 		return IIO_VAL_INT;
544c7eeea93SPeter Meerwald 	}
545686027fbSHartmut Knaack 
546c7eeea93SPeter Meerwald 	return -EINVAL;
547c7eeea93SPeter Meerwald }
548c7eeea93SPeter Meerwald 
549c7eeea93SPeter Meerwald static int mma8452_standby(struct mma8452_data *data)
550c7eeea93SPeter Meerwald {
551c7eeea93SPeter Meerwald 	return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1,
552c7eeea93SPeter Meerwald 					data->ctrl_reg1 & ~MMA8452_CTRL_ACTIVE);
553c7eeea93SPeter Meerwald }
554c7eeea93SPeter Meerwald 
555c7eeea93SPeter Meerwald static int mma8452_active(struct mma8452_data *data)
556c7eeea93SPeter Meerwald {
557c7eeea93SPeter Meerwald 	return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1,
558c7eeea93SPeter Meerwald 					 data->ctrl_reg1);
559c7eeea93SPeter Meerwald }
560c7eeea93SPeter Meerwald 
561e866853dSMartin Kepplinger /* returns >0 if active, 0 if in standby and <0 on error */
562e866853dSMartin Kepplinger static int mma8452_is_active(struct mma8452_data *data)
563e866853dSMartin Kepplinger {
564e866853dSMartin Kepplinger 	int reg;
565e866853dSMartin Kepplinger 
566e866853dSMartin Kepplinger 	reg = i2c_smbus_read_byte_data(data->client, MMA8452_CTRL_REG1);
567e866853dSMartin Kepplinger 	if (reg < 0)
568e866853dSMartin Kepplinger 		return reg;
569e866853dSMartin Kepplinger 
570e866853dSMartin Kepplinger 	return reg & MMA8452_CTRL_ACTIVE;
571e866853dSMartin Kepplinger }
572e866853dSMartin Kepplinger 
573c7eeea93SPeter Meerwald static int mma8452_change_config(struct mma8452_data *data, u8 reg, u8 val)
574c7eeea93SPeter Meerwald {
575c7eeea93SPeter Meerwald 	int ret;
576e866853dSMartin Kepplinger 	int is_active;
577c7eeea93SPeter Meerwald 
578c7eeea93SPeter Meerwald 	mutex_lock(&data->lock);
579c7eeea93SPeter Meerwald 
580e866853dSMartin Kepplinger 	is_active = mma8452_is_active(data);
581e866853dSMartin Kepplinger 	if (is_active < 0) {
582e866853dSMartin Kepplinger 		ret = is_active;
583e866853dSMartin Kepplinger 		goto fail;
584e866853dSMartin Kepplinger 	}
585e866853dSMartin Kepplinger 
586c7eeea93SPeter Meerwald 	/* config can only be changed when in standby */
587e866853dSMartin Kepplinger 	if (is_active > 0) {
588c7eeea93SPeter Meerwald 		ret = mma8452_standby(data);
589c7eeea93SPeter Meerwald 		if (ret < 0)
590c7eeea93SPeter Meerwald 			goto fail;
591e866853dSMartin Kepplinger 	}
592c7eeea93SPeter Meerwald 
593c7eeea93SPeter Meerwald 	ret = i2c_smbus_write_byte_data(data->client, reg, val);
594c7eeea93SPeter Meerwald 	if (ret < 0)
595c7eeea93SPeter Meerwald 		goto fail;
596c7eeea93SPeter Meerwald 
597e866853dSMartin Kepplinger 	if (is_active > 0) {
598c7eeea93SPeter Meerwald 		ret = mma8452_active(data);
599c7eeea93SPeter Meerwald 		if (ret < 0)
600c7eeea93SPeter Meerwald 			goto fail;
601e866853dSMartin Kepplinger 	}
602c7eeea93SPeter Meerwald 
603c7eeea93SPeter Meerwald 	ret = 0;
604c7eeea93SPeter Meerwald fail:
605c7eeea93SPeter Meerwald 	mutex_unlock(&data->lock);
606686027fbSHartmut Knaack 
607c7eeea93SPeter Meerwald 	return ret;
608c7eeea93SPeter Meerwald }
609c7eeea93SPeter Meerwald 
610ed859fc1SMartin Kepplinger static int mma8452_set_power_mode(struct mma8452_data *data, u8 mode)
611ed859fc1SMartin Kepplinger {
612ed859fc1SMartin Kepplinger 	int reg;
613ed859fc1SMartin Kepplinger 
614ed859fc1SMartin Kepplinger 	reg = i2c_smbus_read_byte_data(data->client,
615ed859fc1SMartin Kepplinger 				       MMA8452_CTRL_REG2);
616ed859fc1SMartin Kepplinger 	if (reg < 0)
617ed859fc1SMartin Kepplinger 		return reg;
618ed859fc1SMartin Kepplinger 
619ed859fc1SMartin Kepplinger 	reg &= ~MMA8452_CTRL_REG2_MODS_MASK;
620ed859fc1SMartin Kepplinger 	reg |= mode << MMA8452_CTRL_REG2_MODS_SHIFT;
621ed859fc1SMartin Kepplinger 
622ed859fc1SMartin Kepplinger 	return mma8452_change_config(data, MMA8452_CTRL_REG2, reg);
623ed859fc1SMartin Kepplinger }
624ed859fc1SMartin Kepplinger 
6258b8ff3a6SMartin Kepplinger /* returns >0 if in freefall mode, 0 if not or <0 if an error occurred */
6264b04266aSMartin Kepplinger static int mma8452_freefall_mode_enabled(struct mma8452_data *data)
6274b04266aSMartin Kepplinger {
6284b04266aSMartin Kepplinger 	int val;
6294b04266aSMartin Kepplinger 
630605f72deSHarinath Nampally 	val = i2c_smbus_read_byte_data(data->client, MMA8452_FF_MT_CFG);
6314b04266aSMartin Kepplinger 	if (val < 0)
6324b04266aSMartin Kepplinger 		return val;
6334b04266aSMartin Kepplinger 
6344b04266aSMartin Kepplinger 	return !(val & MMA8452_FF_MT_CFG_OAE);
6354b04266aSMartin Kepplinger }
6364b04266aSMartin Kepplinger 
6374b04266aSMartin Kepplinger static int mma8452_set_freefall_mode(struct mma8452_data *data, bool state)
6384b04266aSMartin Kepplinger {
6394b04266aSMartin Kepplinger 	int val;
6404b04266aSMartin Kepplinger 
6414b04266aSMartin Kepplinger 	if ((state && mma8452_freefall_mode_enabled(data)) ||
6424b04266aSMartin Kepplinger 	    (!state && !(mma8452_freefall_mode_enabled(data))))
6434b04266aSMartin Kepplinger 		return 0;
6444b04266aSMartin Kepplinger 
645605f72deSHarinath Nampally 	val = i2c_smbus_read_byte_data(data->client, MMA8452_FF_MT_CFG);
6464b04266aSMartin Kepplinger 	if (val < 0)
6474b04266aSMartin Kepplinger 		return val;
6484b04266aSMartin Kepplinger 
6494b04266aSMartin Kepplinger 	if (state) {
650605f72deSHarinath Nampally 		val |= BIT(idx_x + MMA8452_FF_MT_CHAN_SHIFT);
651605f72deSHarinath Nampally 		val |= BIT(idx_y + MMA8452_FF_MT_CHAN_SHIFT);
652605f72deSHarinath Nampally 		val |= BIT(idx_z + MMA8452_FF_MT_CHAN_SHIFT);
6534b04266aSMartin Kepplinger 		val &= ~MMA8452_FF_MT_CFG_OAE;
6544b04266aSMartin Kepplinger 	} else {
655605f72deSHarinath Nampally 		val &= ~BIT(idx_x + MMA8452_FF_MT_CHAN_SHIFT);
656605f72deSHarinath Nampally 		val &= ~BIT(idx_y + MMA8452_FF_MT_CHAN_SHIFT);
657605f72deSHarinath Nampally 		val &= ~BIT(idx_z + MMA8452_FF_MT_CHAN_SHIFT);
6584b04266aSMartin Kepplinger 		val |= MMA8452_FF_MT_CFG_OAE;
6594b04266aSMartin Kepplinger 	}
6604b04266aSMartin Kepplinger 
661605f72deSHarinath Nampally 	return mma8452_change_config(data, MMA8452_FF_MT_CFG, val);
6624b04266aSMartin Kepplinger }
6634b04266aSMartin Kepplinger 
6641e79841aSMartin Fuzzey static int mma8452_set_hp_filter_frequency(struct mma8452_data *data,
6651e79841aSMartin Fuzzey 					   int val, int val2)
6661e79841aSMartin Fuzzey {
6671e79841aSMartin Fuzzey 	int i, reg;
6681e79841aSMartin Fuzzey 
6691e79841aSMartin Fuzzey 	i = mma8452_get_hp_filter_index(data, val, val2);
6701e79841aSMartin Fuzzey 	if (i < 0)
671b9fddcdbSHartmut Knaack 		return i;
6721e79841aSMartin Fuzzey 
6731e79841aSMartin Fuzzey 	reg = i2c_smbus_read_byte_data(data->client,
6741e79841aSMartin Fuzzey 				       MMA8452_HP_FILTER_CUTOFF);
6751e79841aSMartin Fuzzey 	if (reg < 0)
6761e79841aSMartin Fuzzey 		return reg;
677686027fbSHartmut Knaack 
6781e79841aSMartin Fuzzey 	reg &= ~MMA8452_HP_FILTER_CUTOFF_SEL_MASK;
6791e79841aSMartin Fuzzey 	reg |= i;
6801e79841aSMartin Fuzzey 
6811e79841aSMartin Fuzzey 	return mma8452_change_config(data, MMA8452_HP_FILTER_CUTOFF, reg);
6821e79841aSMartin Fuzzey }
6831e79841aSMartin Fuzzey 
684c7eeea93SPeter Meerwald static int mma8452_write_raw(struct iio_dev *indio_dev,
685c7eeea93SPeter Meerwald 			     struct iio_chan_spec const *chan,
686c7eeea93SPeter Meerwald 			     int val, int val2, long mask)
687c7eeea93SPeter Meerwald {
688c7eeea93SPeter Meerwald 	struct mma8452_data *data = iio_priv(indio_dev);
6891e79841aSMartin Fuzzey 	int i, ret;
690c7eeea93SPeter Meerwald 
69179de2ee4SJonathan Cameron 	ret = iio_device_claim_direct_mode(indio_dev);
69279de2ee4SJonathan Cameron 	if (ret)
69379de2ee4SJonathan Cameron 		return ret;
694c7eeea93SPeter Meerwald 
695c7eeea93SPeter Meerwald 	switch (mask) {
696c7eeea93SPeter Meerwald 	case IIO_CHAN_INFO_SAMP_FREQ:
697c7eeea93SPeter Meerwald 		i = mma8452_get_samp_freq_index(data, val, val2);
69879de2ee4SJonathan Cameron 		if (i < 0) {
69979de2ee4SJonathan Cameron 			ret = i;
70079de2ee4SJonathan Cameron 			break;
70179de2ee4SJonathan Cameron 		}
702c7eeea93SPeter Meerwald 		data->ctrl_reg1 &= ~MMA8452_CTRL_DR_MASK;
703c7eeea93SPeter Meerwald 		data->ctrl_reg1 |= i << MMA8452_CTRL_DR_SHIFT;
704686027fbSHartmut Knaack 
70579de2ee4SJonathan Cameron 		ret = mma8452_change_config(data, MMA8452_CTRL_REG1,
706c7eeea93SPeter Meerwald 					    data->ctrl_reg1);
70779de2ee4SJonathan Cameron 		break;
708c7eeea93SPeter Meerwald 	case IIO_CHAN_INFO_SCALE:
709c7eeea93SPeter Meerwald 		i = mma8452_get_scale_index(data, val, val2);
71079de2ee4SJonathan Cameron 		if (i < 0) {
71179de2ee4SJonathan Cameron 			ret = i;
71279de2ee4SJonathan Cameron 			break;
71379de2ee4SJonathan Cameron 		}
714686027fbSHartmut Knaack 
715c7eeea93SPeter Meerwald 		data->data_cfg &= ~MMA8452_DATA_CFG_FS_MASK;
716c7eeea93SPeter Meerwald 		data->data_cfg |= i;
717686027fbSHartmut Knaack 
71879de2ee4SJonathan Cameron 		ret = mma8452_change_config(data, MMA8452_DATA_CFG,
719c7eeea93SPeter Meerwald 					    data->data_cfg);
72079de2ee4SJonathan Cameron 		break;
721c7eeea93SPeter Meerwald 	case IIO_CHAN_INFO_CALIBBIAS:
72279de2ee4SJonathan Cameron 		if (val < -128 || val > 127) {
72379de2ee4SJonathan Cameron 			ret = -EINVAL;
72479de2ee4SJonathan Cameron 			break;
72579de2ee4SJonathan Cameron 		}
726686027fbSHartmut Knaack 
72779de2ee4SJonathan Cameron 		ret = mma8452_change_config(data,
728686027fbSHartmut Knaack 					    MMA8452_OFF_X + chan->scan_index,
729686027fbSHartmut Knaack 					    val);
73079de2ee4SJonathan Cameron 		break;
7311e79841aSMartin Fuzzey 
7321e79841aSMartin Fuzzey 	case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
7331e79841aSMartin Fuzzey 		if (val == 0 && val2 == 0) {
7341e79841aSMartin Fuzzey 			data->data_cfg &= ~MMA8452_DATA_CFG_HPF_MASK;
7351e79841aSMartin Fuzzey 		} else {
7361e79841aSMartin Fuzzey 			data->data_cfg |= MMA8452_DATA_CFG_HPF_MASK;
7371e79841aSMartin Fuzzey 			ret = mma8452_set_hp_filter_frequency(data, val, val2);
7381e79841aSMartin Fuzzey 			if (ret < 0)
73979de2ee4SJonathan Cameron 				break;
7401e79841aSMartin Fuzzey 		}
741686027fbSHartmut Knaack 
74279de2ee4SJonathan Cameron 		ret = mma8452_change_config(data, MMA8452_DATA_CFG,
7431e79841aSMartin Fuzzey 					     data->data_cfg);
74479de2ee4SJonathan Cameron 		break;
7451e79841aSMartin Fuzzey 
746ed859fc1SMartin Kepplinger 	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
747ed859fc1SMartin Kepplinger 		ret = mma8452_get_odr_index(data);
748ed859fc1SMartin Kepplinger 
749ed859fc1SMartin Kepplinger 		for (i = 0; i < ARRAY_SIZE(mma8452_os_ratio); i++) {
75079de2ee4SJonathan Cameron 			if (mma8452_os_ratio[i][ret] == val) {
75179de2ee4SJonathan Cameron 				ret = mma8452_set_power_mode(data, i);
75279de2ee4SJonathan Cameron 				break;
75379de2ee4SJonathan Cameron 			}
75479de2ee4SJonathan Cameron 		}
75579de2ee4SJonathan Cameron 		break;
75679de2ee4SJonathan Cameron 	default:
75779de2ee4SJonathan Cameron 		ret = -EINVAL;
75879de2ee4SJonathan Cameron 		break;
759ed859fc1SMartin Kepplinger 	}
760ed859fc1SMartin Kepplinger 
76179de2ee4SJonathan Cameron 	iio_device_release_direct_mode(indio_dev);
76279de2ee4SJonathan Cameron 	return ret;
763c7eeea93SPeter Meerwald }
764c7eeea93SPeter Meerwald 
765605f72deSHarinath Nampally static int mma8452_get_event_regs(struct mma8452_data *data,
766605f72deSHarinath Nampally 		const struct iio_chan_spec *chan, enum iio_event_direction dir,
767605f72deSHarinath Nampally 		const struct mma8452_event_regs **ev_reg)
768605f72deSHarinath Nampally {
769605f72deSHarinath Nampally 	if (!chan)
770605f72deSHarinath Nampally 		return -EINVAL;
771605f72deSHarinath Nampally 
772605f72deSHarinath Nampally 	switch (chan->type) {
773605f72deSHarinath Nampally 	case IIO_ACCEL:
774605f72deSHarinath Nampally 		switch (dir) {
775605f72deSHarinath Nampally 		case IIO_EV_DIR_RISING:
776605f72deSHarinath Nampally 			if ((data->chip_info->all_events
777605f72deSHarinath Nampally 					& MMA8452_INT_TRANS) &&
778605f72deSHarinath Nampally 				(data->chip_info->enabled_events
779605f72deSHarinath Nampally 					& MMA8452_INT_TRANS))
780605f72deSHarinath Nampally 				*ev_reg = &ev_regs_accel_rising;
781605f72deSHarinath Nampally 			else
782605f72deSHarinath Nampally 				*ev_reg = &ev_regs_accel_falling;
783605f72deSHarinath Nampally 			return 0;
784605f72deSHarinath Nampally 		case IIO_EV_DIR_FALLING:
785605f72deSHarinath Nampally 			*ev_reg = &ev_regs_accel_falling;
786605f72deSHarinath Nampally 			return 0;
787605f72deSHarinath Nampally 		default:
788605f72deSHarinath Nampally 			return -EINVAL;
789605f72deSHarinath Nampally 		}
790605f72deSHarinath Nampally 	default:
791605f72deSHarinath Nampally 		return -EINVAL;
792605f72deSHarinath Nampally 	}
793605f72deSHarinath Nampally }
794605f72deSHarinath Nampally 
79528e34278SMartin Fuzzey static int mma8452_read_thresh(struct iio_dev *indio_dev,
79628e34278SMartin Fuzzey 			       const struct iio_chan_spec *chan,
79728e34278SMartin Fuzzey 			       enum iio_event_type type,
79828e34278SMartin Fuzzey 			       enum iio_event_direction dir,
79928e34278SMartin Fuzzey 			       enum iio_event_info info,
80028e34278SMartin Fuzzey 			       int *val, int *val2)
80128e34278SMartin Fuzzey {
80228e34278SMartin Fuzzey 	struct mma8452_data *data = iio_priv(indio_dev);
803ed859fc1SMartin Kepplinger 	int ret, us, power_mode;
804605f72deSHarinath Nampally 	const struct mma8452_event_regs *ev_regs;
805605f72deSHarinath Nampally 
806605f72deSHarinath Nampally 	ret = mma8452_get_event_regs(data, chan, dir, &ev_regs);
807605f72deSHarinath Nampally 	if (ret)
808605f72deSHarinath Nampally 		return ret;
80928e34278SMartin Fuzzey 
8105dbbd19fSMartin Fuzzey 	switch (info) {
8115dbbd19fSMartin Fuzzey 	case IIO_EV_INFO_VALUE:
812605f72deSHarinath Nampally 		ret = i2c_smbus_read_byte_data(data->client, ev_regs->ev_ths);
81328e34278SMartin Fuzzey 		if (ret < 0)
81428e34278SMartin Fuzzey 			return ret;
81528e34278SMartin Fuzzey 
816605f72deSHarinath Nampally 		*val = ret & ev_regs->ev_ths_mask;
817686027fbSHartmut Knaack 
81828e34278SMartin Fuzzey 		return IIO_VAL_INT;
8195dbbd19fSMartin Fuzzey 
8205dbbd19fSMartin Fuzzey 	case IIO_EV_INFO_PERIOD:
821605f72deSHarinath Nampally 		ret = i2c_smbus_read_byte_data(data->client, ev_regs->ev_count);
8225dbbd19fSMartin Fuzzey 		if (ret < 0)
8235dbbd19fSMartin Fuzzey 			return ret;
8245dbbd19fSMartin Fuzzey 
825ed859fc1SMartin Kepplinger 		power_mode = mma8452_get_power_mode(data);
826ed859fc1SMartin Kepplinger 		if (power_mode < 0)
827ed859fc1SMartin Kepplinger 			return power_mode;
828ed859fc1SMartin Kepplinger 
829ed859fc1SMartin Kepplinger 		us = ret * mma8452_transient_time_step_us[power_mode][
8305dbbd19fSMartin Fuzzey 				mma8452_get_odr_index(data)];
8315dbbd19fSMartin Fuzzey 		*val = us / USEC_PER_SEC;
8325dbbd19fSMartin Fuzzey 		*val2 = us % USEC_PER_SEC;
833686027fbSHartmut Knaack 
8345dbbd19fSMartin Fuzzey 		return IIO_VAL_INT_PLUS_MICRO;
8355dbbd19fSMartin Fuzzey 
8361e79841aSMartin Fuzzey 	case IIO_EV_INFO_HIGH_PASS_FILTER_3DB:
8371e79841aSMartin Fuzzey 		ret = i2c_smbus_read_byte_data(data->client,
8381e79841aSMartin Fuzzey 					       MMA8452_TRANSIENT_CFG);
8391e79841aSMartin Fuzzey 		if (ret < 0)
8401e79841aSMartin Fuzzey 			return ret;
8411e79841aSMartin Fuzzey 
8421e79841aSMartin Fuzzey 		if (ret & MMA8452_TRANSIENT_CFG_HPF_BYP) {
8431e79841aSMartin Fuzzey 			*val = 0;
8441e79841aSMartin Fuzzey 			*val2 = 0;
8451e79841aSMartin Fuzzey 		} else {
8461e79841aSMartin Fuzzey 			ret = mma8452_read_hp_filter(data, val, val2);
8471e79841aSMartin Fuzzey 			if (ret < 0)
8481e79841aSMartin Fuzzey 				return ret;
8491e79841aSMartin Fuzzey 		}
850686027fbSHartmut Knaack 
8511e79841aSMartin Fuzzey 		return IIO_VAL_INT_PLUS_MICRO;
8521e79841aSMartin Fuzzey 
8535dbbd19fSMartin Fuzzey 	default:
8545dbbd19fSMartin Fuzzey 		return -EINVAL;
8555dbbd19fSMartin Fuzzey 	}
85628e34278SMartin Fuzzey }
85728e34278SMartin Fuzzey 
85828e34278SMartin Fuzzey static int mma8452_write_thresh(struct iio_dev *indio_dev,
85928e34278SMartin Fuzzey 				const struct iio_chan_spec *chan,
86028e34278SMartin Fuzzey 				enum iio_event_type type,
86128e34278SMartin Fuzzey 				enum iio_event_direction dir,
86228e34278SMartin Fuzzey 				enum iio_event_info info,
86328e34278SMartin Fuzzey 				int val, int val2)
86428e34278SMartin Fuzzey {
86528e34278SMartin Fuzzey 	struct mma8452_data *data = iio_priv(indio_dev);
8661e79841aSMartin Fuzzey 	int ret, reg, steps;
867605f72deSHarinath Nampally 	const struct mma8452_event_regs *ev_regs;
868605f72deSHarinath Nampally 
869605f72deSHarinath Nampally 	ret = mma8452_get_event_regs(data, chan, dir, &ev_regs);
870605f72deSHarinath Nampally 	if (ret)
871605f72deSHarinath Nampally 		return ret;
87228e34278SMartin Fuzzey 
8735dbbd19fSMartin Fuzzey 	switch (info) {
8745dbbd19fSMartin Fuzzey 	case IIO_EV_INFO_VALUE:
875605f72deSHarinath Nampally 		if (val < 0 || val > ev_regs->ev_ths_mask)
87611218226SHartmut Knaack 			return -EINVAL;
87711218226SHartmut Knaack 
878605f72deSHarinath Nampally 		return mma8452_change_config(data, ev_regs->ev_ths, val);
8795dbbd19fSMartin Fuzzey 
8805dbbd19fSMartin Fuzzey 	case IIO_EV_INFO_PERIOD:
881ed859fc1SMartin Kepplinger 		ret = mma8452_get_power_mode(data);
882ed859fc1SMartin Kepplinger 		if (ret < 0)
883ed859fc1SMartin Kepplinger 			return ret;
884ed859fc1SMartin Kepplinger 
8855dbbd19fSMartin Fuzzey 		steps = (val * USEC_PER_SEC + val2) /
886ed859fc1SMartin Kepplinger 				mma8452_transient_time_step_us[ret][
8875dbbd19fSMartin Fuzzey 					mma8452_get_odr_index(data)];
8885dbbd19fSMartin Fuzzey 
88911218226SHartmut Knaack 		if (steps < 0 || steps > 0xff)
8905dbbd19fSMartin Fuzzey 			return -EINVAL;
8915dbbd19fSMartin Fuzzey 
892605f72deSHarinath Nampally 		return mma8452_change_config(data, ev_regs->ev_count, steps);
893686027fbSHartmut Knaack 
8941e79841aSMartin Fuzzey 	case IIO_EV_INFO_HIGH_PASS_FILTER_3DB:
8951e79841aSMartin Fuzzey 		reg = i2c_smbus_read_byte_data(data->client,
8961e79841aSMartin Fuzzey 					       MMA8452_TRANSIENT_CFG);
8971e79841aSMartin Fuzzey 		if (reg < 0)
8981e79841aSMartin Fuzzey 			return reg;
8991e79841aSMartin Fuzzey 
9001e79841aSMartin Fuzzey 		if (val == 0 && val2 == 0) {
9011e79841aSMartin Fuzzey 			reg |= MMA8452_TRANSIENT_CFG_HPF_BYP;
9021e79841aSMartin Fuzzey 		} else {
9031e79841aSMartin Fuzzey 			reg &= ~MMA8452_TRANSIENT_CFG_HPF_BYP;
9041e79841aSMartin Fuzzey 			ret = mma8452_set_hp_filter_frequency(data, val, val2);
9051e79841aSMartin Fuzzey 			if (ret < 0)
9061e79841aSMartin Fuzzey 				return ret;
9071e79841aSMartin Fuzzey 		}
908686027fbSHartmut Knaack 
9091e79841aSMartin Fuzzey 		return mma8452_change_config(data, MMA8452_TRANSIENT_CFG, reg);
9101e79841aSMartin Fuzzey 
9115dbbd19fSMartin Fuzzey 	default:
9125dbbd19fSMartin Fuzzey 		return -EINVAL;
9135dbbd19fSMartin Fuzzey 	}
91428e34278SMartin Fuzzey }
91528e34278SMartin Fuzzey 
91628e34278SMartin Fuzzey static int mma8452_read_event_config(struct iio_dev *indio_dev,
91728e34278SMartin Fuzzey 				     const struct iio_chan_spec *chan,
91828e34278SMartin Fuzzey 				     enum iio_event_type type,
91928e34278SMartin Fuzzey 				     enum iio_event_direction dir)
92028e34278SMartin Fuzzey {
92128e34278SMartin Fuzzey 	struct mma8452_data *data = iio_priv(indio_dev);
92228e34278SMartin Fuzzey 	int ret;
923605f72deSHarinath Nampally 	const struct mma8452_event_regs *ev_regs;
924605f72deSHarinath Nampally 
925605f72deSHarinath Nampally 	ret = mma8452_get_event_regs(data, chan, dir, &ev_regs);
926605f72deSHarinath Nampally 	if (ret)
927605f72deSHarinath Nampally 		return ret;
92828e34278SMartin Fuzzey 
9294b04266aSMartin Kepplinger 	switch (dir) {
9304b04266aSMartin Kepplinger 	case IIO_EV_DIR_FALLING:
9314b04266aSMartin Kepplinger 		return mma8452_freefall_mode_enabled(data);
9324b04266aSMartin Kepplinger 	case IIO_EV_DIR_RISING:
933c3cdd6e4SMartin Kepplinger 		ret = i2c_smbus_read_byte_data(data->client,
934605f72deSHarinath Nampally 				ev_regs->ev_cfg);
93528e34278SMartin Fuzzey 		if (ret < 0)
93628e34278SMartin Fuzzey 			return ret;
93728e34278SMartin Fuzzey 
9388b8ff3a6SMartin Kepplinger 		return !!(ret & BIT(chan->scan_index +
939605f72deSHarinath Nampally 				ev_regs->ev_cfg_chan_shift));
9404b04266aSMartin Kepplinger 	default:
9414b04266aSMartin Kepplinger 		return -EINVAL;
9424b04266aSMartin Kepplinger 	}
94328e34278SMartin Fuzzey }
94428e34278SMartin Fuzzey 
94528e34278SMartin Fuzzey static int mma8452_write_event_config(struct iio_dev *indio_dev,
94628e34278SMartin Fuzzey 				      const struct iio_chan_spec *chan,
94728e34278SMartin Fuzzey 				      enum iio_event_type type,
94828e34278SMartin Fuzzey 				      enum iio_event_direction dir,
94928e34278SMartin Fuzzey 				      int state)
95028e34278SMartin Fuzzey {
95128e34278SMartin Fuzzey 	struct mma8452_data *data = iio_priv(indio_dev);
95296c0cb2bSMartin Kepplinger 	int val, ret;
953605f72deSHarinath Nampally 	const struct mma8452_event_regs *ev_regs;
954605f72deSHarinath Nampally 
955605f72deSHarinath Nampally 	ret = mma8452_get_event_regs(data, chan, dir, &ev_regs);
956605f72deSHarinath Nampally 	if (ret)
957605f72deSHarinath Nampally 		return ret;
95896c0cb2bSMartin Kepplinger 
95996c0cb2bSMartin Kepplinger 	ret = mma8452_set_runtime_pm_state(data->client, state);
96096c0cb2bSMartin Kepplinger 	if (ret)
96196c0cb2bSMartin Kepplinger 		return ret;
96228e34278SMartin Fuzzey 
9634b04266aSMartin Kepplinger 	switch (dir) {
9644b04266aSMartin Kepplinger 	case IIO_EV_DIR_FALLING:
9654b04266aSMartin Kepplinger 		return mma8452_set_freefall_mode(data, state);
9664b04266aSMartin Kepplinger 	case IIO_EV_DIR_RISING:
967605f72deSHarinath Nampally 		val = i2c_smbus_read_byte_data(data->client, ev_regs->ev_cfg);
96828e34278SMartin Fuzzey 		if (val < 0)
96928e34278SMartin Fuzzey 			return val;
97028e34278SMartin Fuzzey 
9714b04266aSMartin Kepplinger 		if (state) {
9724b04266aSMartin Kepplinger 			if (mma8452_freefall_mode_enabled(data)) {
973605f72deSHarinath Nampally 				val &= ~BIT(idx_x + ev_regs->ev_cfg_chan_shift);
974605f72deSHarinath Nampally 				val &= ~BIT(idx_y + ev_regs->ev_cfg_chan_shift);
975605f72deSHarinath Nampally 				val &= ~BIT(idx_z + ev_regs->ev_cfg_chan_shift);
9764b04266aSMartin Kepplinger 				val |= MMA8452_FF_MT_CFG_OAE;
9774b04266aSMartin Kepplinger 			}
978605f72deSHarinath Nampally 			val |= BIT(chan->scan_index +
979605f72deSHarinath Nampally 					ev_regs->ev_cfg_chan_shift);
9804b04266aSMartin Kepplinger 		} else {
9814b04266aSMartin Kepplinger 			if (mma8452_freefall_mode_enabled(data))
9824b04266aSMartin Kepplinger 				return 0;
9834b04266aSMartin Kepplinger 
984605f72deSHarinath Nampally 			val &= ~BIT(chan->scan_index +
985605f72deSHarinath Nampally 					ev_regs->ev_cfg_chan_shift);
9864b04266aSMartin Kepplinger 		}
98728e34278SMartin Fuzzey 
988605f72deSHarinath Nampally 		val |= ev_regs->ev_cfg_ele;
98928e34278SMartin Fuzzey 
990605f72deSHarinath Nampally 		return mma8452_change_config(data, ev_regs->ev_cfg, val);
9914b04266aSMartin Kepplinger 	default:
9924b04266aSMartin Kepplinger 		return -EINVAL;
9934b04266aSMartin Kepplinger 	}
99428e34278SMartin Fuzzey }
99528e34278SMartin Fuzzey 
99628e34278SMartin Fuzzey static void mma8452_transient_interrupt(struct iio_dev *indio_dev)
99728e34278SMartin Fuzzey {
99828e34278SMartin Fuzzey 	struct mma8452_data *data = iio_priv(indio_dev);
999bc2b7dabSGregor Boirie 	s64 ts = iio_get_time_ns(indio_dev);
100028e34278SMartin Fuzzey 	int src;
100128e34278SMartin Fuzzey 
1002605f72deSHarinath Nampally 	src = i2c_smbus_read_byte_data(data->client, MMA8452_TRANSIENT_SRC);
100328e34278SMartin Fuzzey 	if (src < 0)
100428e34278SMartin Fuzzey 		return;
100528e34278SMartin Fuzzey 
1006605f72deSHarinath Nampally 	if (src & MMA8452_TRANSIENT_SRC_XTRANSE)
100728e34278SMartin Fuzzey 		iio_push_event(indio_dev,
100828e34278SMartin Fuzzey 			       IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X,
1009c5d0db06SMartin Kepplinger 						  IIO_EV_TYPE_MAG,
101028e34278SMartin Fuzzey 						  IIO_EV_DIR_RISING),
101128e34278SMartin Fuzzey 			       ts);
101228e34278SMartin Fuzzey 
1013605f72deSHarinath Nampally 	if (src & MMA8452_TRANSIENT_SRC_YTRANSE)
101428e34278SMartin Fuzzey 		iio_push_event(indio_dev,
101528e34278SMartin Fuzzey 			       IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Y,
1016c5d0db06SMartin Kepplinger 						  IIO_EV_TYPE_MAG,
101728e34278SMartin Fuzzey 						  IIO_EV_DIR_RISING),
101828e34278SMartin Fuzzey 			       ts);
101928e34278SMartin Fuzzey 
1020605f72deSHarinath Nampally 	if (src & MMA8452_TRANSIENT_SRC_ZTRANSE)
102128e34278SMartin Fuzzey 		iio_push_event(indio_dev,
102228e34278SMartin Fuzzey 			       IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Z,
1023c5d0db06SMartin Kepplinger 						  IIO_EV_TYPE_MAG,
102428e34278SMartin Fuzzey 						  IIO_EV_DIR_RISING),
102528e34278SMartin Fuzzey 			       ts);
102628e34278SMartin Fuzzey }
102728e34278SMartin Fuzzey 
102828e34278SMartin Fuzzey static irqreturn_t mma8452_interrupt(int irq, void *p)
102928e34278SMartin Fuzzey {
103028e34278SMartin Fuzzey 	struct iio_dev *indio_dev = p;
103128e34278SMartin Fuzzey 	struct mma8452_data *data = iio_priv(indio_dev);
1032ae6d9ce0SMartin Fuzzey 	int ret = IRQ_NONE;
103328e34278SMartin Fuzzey 	int src;
103428e34278SMartin Fuzzey 
103528e34278SMartin Fuzzey 	src = i2c_smbus_read_byte_data(data->client, MMA8452_INT_SRC);
103628e34278SMartin Fuzzey 	if (src < 0)
103728e34278SMartin Fuzzey 		return IRQ_NONE;
103828e34278SMartin Fuzzey 
1039605f72deSHarinath Nampally 	if (!(src & data->chip_info->enabled_events))
1040605f72deSHarinath Nampally 		return IRQ_NONE;
1041605f72deSHarinath Nampally 
1042ae6d9ce0SMartin Fuzzey 	if (src & MMA8452_INT_DRDY) {
1043ae6d9ce0SMartin Fuzzey 		iio_trigger_poll_chained(indio_dev->trig);
1044ae6d9ce0SMartin Fuzzey 		ret = IRQ_HANDLED;
104528e34278SMartin Fuzzey 	}
104628e34278SMartin Fuzzey 
1047605f72deSHarinath Nampally 	if (src & MMA8452_INT_FF_MT) {
1048605f72deSHarinath Nampally 		if (mma8452_freefall_mode_enabled(data)) {
1049605f72deSHarinath Nampally 			s64 ts = iio_get_time_ns(indio_dev);
1050605f72deSHarinath Nampally 
1051605f72deSHarinath Nampally 			iio_push_event(indio_dev,
1052605f72deSHarinath Nampally 				       IIO_MOD_EVENT_CODE(IIO_ACCEL, 0,
1053605f72deSHarinath Nampally 							  IIO_MOD_X_AND_Y_AND_Z,
1054605f72deSHarinath Nampally 							  IIO_EV_TYPE_MAG,
1055605f72deSHarinath Nampally 							  IIO_EV_DIR_FALLING),
1056605f72deSHarinath Nampally 					ts);
1057605f72deSHarinath Nampally 		}
1058605f72deSHarinath Nampally 		ret = IRQ_HANDLED;
1059605f72deSHarinath Nampally 	}
1060605f72deSHarinath Nampally 
1061605f72deSHarinath Nampally 	if (src & MMA8452_INT_TRANS) {
1062ae6d9ce0SMartin Fuzzey 		mma8452_transient_interrupt(indio_dev);
1063ae6d9ce0SMartin Fuzzey 		ret = IRQ_HANDLED;
1064ae6d9ce0SMartin Fuzzey 	}
1065ae6d9ce0SMartin Fuzzey 
1066ae6d9ce0SMartin Fuzzey 	return ret;
106728e34278SMartin Fuzzey }
106828e34278SMartin Fuzzey 
1069c7eeea93SPeter Meerwald static irqreturn_t mma8452_trigger_handler(int irq, void *p)
1070c7eeea93SPeter Meerwald {
1071c7eeea93SPeter Meerwald 	struct iio_poll_func *pf = p;
1072c7eeea93SPeter Meerwald 	struct iio_dev *indio_dev = pf->indio_dev;
1073c7eeea93SPeter Meerwald 	struct mma8452_data *data = iio_priv(indio_dev);
1074c7eeea93SPeter Meerwald 	u8 buffer[16]; /* 3 16-bit channels + padding + ts */
1075c7eeea93SPeter Meerwald 	int ret;
1076c7eeea93SPeter Meerwald 
1077c7eeea93SPeter Meerwald 	ret = mma8452_read(data, (__be16 *)buffer);
1078c7eeea93SPeter Meerwald 	if (ret < 0)
1079c7eeea93SPeter Meerwald 		goto done;
1080c7eeea93SPeter Meerwald 
1081c7eeea93SPeter Meerwald 	iio_push_to_buffers_with_timestamp(indio_dev, buffer,
1082bc2b7dabSGregor Boirie 					   iio_get_time_ns(indio_dev));
1083c7eeea93SPeter Meerwald 
1084c7eeea93SPeter Meerwald done:
1085c7eeea93SPeter Meerwald 	iio_trigger_notify_done(indio_dev->trig);
1086686027fbSHartmut Knaack 
1087c7eeea93SPeter Meerwald 	return IRQ_HANDLED;
1088c7eeea93SPeter Meerwald }
1089c7eeea93SPeter Meerwald 
10902a17698cSMartin Fuzzey static int mma8452_reg_access_dbg(struct iio_dev *indio_dev,
10912a17698cSMartin Fuzzey 				  unsigned reg, unsigned writeval,
10922a17698cSMartin Fuzzey 				  unsigned *readval)
10932a17698cSMartin Fuzzey {
10942a17698cSMartin Fuzzey 	int ret;
10952a17698cSMartin Fuzzey 	struct mma8452_data *data = iio_priv(indio_dev);
10962a17698cSMartin Fuzzey 
10972a17698cSMartin Fuzzey 	if (reg > MMA8452_MAX_REG)
10982a17698cSMartin Fuzzey 		return -EINVAL;
10992a17698cSMartin Fuzzey 
11002a17698cSMartin Fuzzey 	if (!readval)
11012a17698cSMartin Fuzzey 		return mma8452_change_config(data, reg, writeval);
11022a17698cSMartin Fuzzey 
11032a17698cSMartin Fuzzey 	ret = i2c_smbus_read_byte_data(data->client, reg);
11042a17698cSMartin Fuzzey 	if (ret < 0)
11052a17698cSMartin Fuzzey 		return ret;
11062a17698cSMartin Fuzzey 
11072a17698cSMartin Fuzzey 	*readval = ret;
11082a17698cSMartin Fuzzey 
11092a17698cSMartin Fuzzey 	return 0;
11102a17698cSMartin Fuzzey }
11112a17698cSMartin Fuzzey 
11124b04266aSMartin Kepplinger static const struct iio_event_spec mma8452_freefall_event[] = {
11134b04266aSMartin Kepplinger 	{
11144b04266aSMartin Kepplinger 		.type = IIO_EV_TYPE_MAG,
11154b04266aSMartin Kepplinger 		.dir = IIO_EV_DIR_FALLING,
11164b04266aSMartin Kepplinger 		.mask_separate = BIT(IIO_EV_INFO_ENABLE),
11174b04266aSMartin Kepplinger 		.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
11184b04266aSMartin Kepplinger 					BIT(IIO_EV_INFO_PERIOD) |
11194b04266aSMartin Kepplinger 					BIT(IIO_EV_INFO_HIGH_PASS_FILTER_3DB)
11204b04266aSMartin Kepplinger 	},
11214b04266aSMartin Kepplinger };
11224b04266aSMartin Kepplinger 
11234b04266aSMartin Kepplinger static const struct iio_event_spec mma8652_freefall_event[] = {
11244b04266aSMartin Kepplinger 	{
11254b04266aSMartin Kepplinger 		.type = IIO_EV_TYPE_MAG,
11264b04266aSMartin Kepplinger 		.dir = IIO_EV_DIR_FALLING,
11274b04266aSMartin Kepplinger 		.mask_separate = BIT(IIO_EV_INFO_ENABLE),
11284b04266aSMartin Kepplinger 		.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
11294b04266aSMartin Kepplinger 					BIT(IIO_EV_INFO_PERIOD)
11304b04266aSMartin Kepplinger 	},
11314b04266aSMartin Kepplinger };
11324b04266aSMartin Kepplinger 
113328e34278SMartin Fuzzey static const struct iio_event_spec mma8452_transient_event[] = {
113428e34278SMartin Fuzzey 	{
1135c5d0db06SMartin Kepplinger 		.type = IIO_EV_TYPE_MAG,
113628e34278SMartin Fuzzey 		.dir = IIO_EV_DIR_RISING,
113728e34278SMartin Fuzzey 		.mask_separate = BIT(IIO_EV_INFO_ENABLE),
11385dbbd19fSMartin Fuzzey 		.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
11391e79841aSMartin Fuzzey 					BIT(IIO_EV_INFO_PERIOD) |
11401e79841aSMartin Fuzzey 					BIT(IIO_EV_INFO_HIGH_PASS_FILTER_3DB)
114128e34278SMartin Fuzzey 	},
114228e34278SMartin Fuzzey };
114328e34278SMartin Fuzzey 
114460f562e7SMartin Kepplinger static const struct iio_event_spec mma8452_motion_event[] = {
114560f562e7SMartin Kepplinger 	{
114660f562e7SMartin Kepplinger 		.type = IIO_EV_TYPE_MAG,
114760f562e7SMartin Kepplinger 		.dir = IIO_EV_DIR_RISING,
114860f562e7SMartin Kepplinger 		.mask_separate = BIT(IIO_EV_INFO_ENABLE),
114960f562e7SMartin Kepplinger 		.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
115060f562e7SMartin Kepplinger 					BIT(IIO_EV_INFO_PERIOD)
115160f562e7SMartin Kepplinger 	},
115260f562e7SMartin Kepplinger };
115360f562e7SMartin Kepplinger 
115428e34278SMartin Fuzzey /*
115528e34278SMartin Fuzzey  * Threshold is configured in fixed 8G/127 steps regardless of
115628e34278SMartin Fuzzey  * currently selected scale for measurement.
115728e34278SMartin Fuzzey  */
115828e34278SMartin Fuzzey static IIO_CONST_ATTR_NAMED(accel_transient_scale, in_accel_scale, "0.617742");
115928e34278SMartin Fuzzey 
116028e34278SMartin Fuzzey static struct attribute *mma8452_event_attributes[] = {
116128e34278SMartin Fuzzey 	&iio_const_attr_accel_transient_scale.dev_attr.attr,
116228e34278SMartin Fuzzey 	NULL,
116328e34278SMartin Fuzzey };
116428e34278SMartin Fuzzey 
116528e34278SMartin Fuzzey static struct attribute_group mma8452_event_attribute_group = {
116628e34278SMartin Fuzzey 	.attrs = mma8452_event_attributes,
116728e34278SMartin Fuzzey };
116828e34278SMartin Fuzzey 
11694b04266aSMartin Kepplinger #define MMA8452_FREEFALL_CHANNEL(modifier) { \
11704b04266aSMartin Kepplinger 	.type = IIO_ACCEL, \
11714b04266aSMartin Kepplinger 	.modified = 1, \
11724b04266aSMartin Kepplinger 	.channel2 = modifier, \
11734b04266aSMartin Kepplinger 	.scan_index = -1, \
11744b04266aSMartin Kepplinger 	.event_spec = mma8452_freefall_event, \
11754b04266aSMartin Kepplinger 	.num_event_specs = ARRAY_SIZE(mma8452_freefall_event), \
11764b04266aSMartin Kepplinger }
11774b04266aSMartin Kepplinger 
11784b04266aSMartin Kepplinger #define MMA8652_FREEFALL_CHANNEL(modifier) { \
11794b04266aSMartin Kepplinger 	.type = IIO_ACCEL, \
11804b04266aSMartin Kepplinger 	.modified = 1, \
11814b04266aSMartin Kepplinger 	.channel2 = modifier, \
11824b04266aSMartin Kepplinger 	.scan_index = -1, \
11834b04266aSMartin Kepplinger 	.event_spec = mma8652_freefall_event, \
11844b04266aSMartin Kepplinger 	.num_event_specs = ARRAY_SIZE(mma8652_freefall_event), \
11854b04266aSMartin Kepplinger }
11864b04266aSMartin Kepplinger 
1187c3cdd6e4SMartin Kepplinger #define MMA8452_CHANNEL(axis, idx, bits) { \
1188c7eeea93SPeter Meerwald 	.type = IIO_ACCEL, \
1189c7eeea93SPeter Meerwald 	.modified = 1, \
1190c7eeea93SPeter Meerwald 	.channel2 = IIO_MOD_##axis, \
1191c7eeea93SPeter Meerwald 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
1192c7eeea93SPeter Meerwald 			      BIT(IIO_CHAN_INFO_CALIBBIAS), \
1193c7eeea93SPeter Meerwald 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
11941e79841aSMartin Fuzzey 			BIT(IIO_CHAN_INFO_SCALE) | \
1195ed859fc1SMartin Kepplinger 			BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY) | \
1196ed859fc1SMartin Kepplinger 			BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
1197c7eeea93SPeter Meerwald 	.scan_index = idx, \
1198c7eeea93SPeter Meerwald 	.scan_type = { \
1199c7eeea93SPeter Meerwald 		.sign = 's', \
1200c3cdd6e4SMartin Kepplinger 		.realbits = (bits), \
1201c7eeea93SPeter Meerwald 		.storagebits = 16, \
1202c3cdd6e4SMartin Kepplinger 		.shift = 16 - (bits), \
1203c7eeea93SPeter Meerwald 		.endianness = IIO_BE, \
1204c7eeea93SPeter Meerwald 	}, \
120528e34278SMartin Fuzzey 	.event_spec = mma8452_transient_event, \
120628e34278SMartin Fuzzey 	.num_event_specs = ARRAY_SIZE(mma8452_transient_event), \
1207c7eeea93SPeter Meerwald }
1208c7eeea93SPeter Meerwald 
1209417e008bSMartin Kepplinger #define MMA8652_CHANNEL(axis, idx, bits) { \
1210417e008bSMartin Kepplinger 	.type = IIO_ACCEL, \
1211417e008bSMartin Kepplinger 	.modified = 1, \
1212417e008bSMartin Kepplinger 	.channel2 = IIO_MOD_##axis, \
1213417e008bSMartin Kepplinger 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
1214417e008bSMartin Kepplinger 		BIT(IIO_CHAN_INFO_CALIBBIAS), \
1215417e008bSMartin Kepplinger 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
1216ed859fc1SMartin Kepplinger 		BIT(IIO_CHAN_INFO_SCALE) | \
1217ed859fc1SMartin Kepplinger 		BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
1218417e008bSMartin Kepplinger 	.scan_index = idx, \
1219417e008bSMartin Kepplinger 	.scan_type = { \
1220417e008bSMartin Kepplinger 		.sign = 's', \
1221417e008bSMartin Kepplinger 		.realbits = (bits), \
1222417e008bSMartin Kepplinger 		.storagebits = 16, \
1223417e008bSMartin Kepplinger 		.shift = 16 - (bits), \
1224417e008bSMartin Kepplinger 		.endianness = IIO_BE, \
1225417e008bSMartin Kepplinger 	}, \
1226417e008bSMartin Kepplinger 	.event_spec = mma8452_motion_event, \
1227417e008bSMartin Kepplinger 	.num_event_specs = ARRAY_SIZE(mma8452_motion_event), \
1228417e008bSMartin Kepplinger }
1229417e008bSMartin Kepplinger 
1230244a93f6SMartin Kepplinger static const struct iio_chan_spec mma8451_channels[] = {
1231244a93f6SMartin Kepplinger 	MMA8452_CHANNEL(X, idx_x, 14),
1232244a93f6SMartin Kepplinger 	MMA8452_CHANNEL(Y, idx_y, 14),
1233244a93f6SMartin Kepplinger 	MMA8452_CHANNEL(Z, idx_z, 14),
1234244a93f6SMartin Kepplinger 	IIO_CHAN_SOFT_TIMESTAMP(idx_ts),
1235244a93f6SMartin Kepplinger 	MMA8452_FREEFALL_CHANNEL(IIO_MOD_X_AND_Y_AND_Z),
1236244a93f6SMartin Kepplinger };
1237244a93f6SMartin Kepplinger 
1238c7eeea93SPeter Meerwald static const struct iio_chan_spec mma8452_channels[] = {
1239e60378c1SMartin Kepplinger 	MMA8452_CHANNEL(X, idx_x, 12),
1240e60378c1SMartin Kepplinger 	MMA8452_CHANNEL(Y, idx_y, 12),
1241e60378c1SMartin Kepplinger 	MMA8452_CHANNEL(Z, idx_z, 12),
1242e60378c1SMartin Kepplinger 	IIO_CHAN_SOFT_TIMESTAMP(idx_ts),
12434b04266aSMartin Kepplinger 	MMA8452_FREEFALL_CHANNEL(IIO_MOD_X_AND_Y_AND_Z),
1244c7eeea93SPeter Meerwald };
1245c7eeea93SPeter Meerwald 
1246c5ea1b58SMartin Kepplinger static const struct iio_chan_spec mma8453_channels[] = {
1247e60378c1SMartin Kepplinger 	MMA8452_CHANNEL(X, idx_x, 10),
1248e60378c1SMartin Kepplinger 	MMA8452_CHANNEL(Y, idx_y, 10),
1249e60378c1SMartin Kepplinger 	MMA8452_CHANNEL(Z, idx_z, 10),
1250e60378c1SMartin Kepplinger 	IIO_CHAN_SOFT_TIMESTAMP(idx_ts),
12514b04266aSMartin Kepplinger 	MMA8452_FREEFALL_CHANNEL(IIO_MOD_X_AND_Y_AND_Z),
1252c5ea1b58SMartin Kepplinger };
1253c5ea1b58SMartin Kepplinger 
1254417e008bSMartin Kepplinger static const struct iio_chan_spec mma8652_channels[] = {
1255e60378c1SMartin Kepplinger 	MMA8652_CHANNEL(X, idx_x, 12),
1256e60378c1SMartin Kepplinger 	MMA8652_CHANNEL(Y, idx_y, 12),
1257e60378c1SMartin Kepplinger 	MMA8652_CHANNEL(Z, idx_z, 12),
1258e60378c1SMartin Kepplinger 	IIO_CHAN_SOFT_TIMESTAMP(idx_ts),
12594b04266aSMartin Kepplinger 	MMA8652_FREEFALL_CHANNEL(IIO_MOD_X_AND_Y_AND_Z),
1260417e008bSMartin Kepplinger };
1261417e008bSMartin Kepplinger 
1262417e008bSMartin Kepplinger static const struct iio_chan_spec mma8653_channels[] = {
1263e60378c1SMartin Kepplinger 	MMA8652_CHANNEL(X, idx_x, 10),
1264e60378c1SMartin Kepplinger 	MMA8652_CHANNEL(Y, idx_y, 10),
1265e60378c1SMartin Kepplinger 	MMA8652_CHANNEL(Z, idx_z, 10),
1266e60378c1SMartin Kepplinger 	IIO_CHAN_SOFT_TIMESTAMP(idx_ts),
12674b04266aSMartin Kepplinger 	MMA8652_FREEFALL_CHANNEL(IIO_MOD_X_AND_Y_AND_Z),
1268417e008bSMartin Kepplinger };
1269417e008bSMartin Kepplinger 
1270c3cdd6e4SMartin Kepplinger enum {
1271244a93f6SMartin Kepplinger 	mma8451,
1272c3cdd6e4SMartin Kepplinger 	mma8452,
1273c5ea1b58SMartin Kepplinger 	mma8453,
1274417e008bSMartin Kepplinger 	mma8652,
1275417e008bSMartin Kepplinger 	mma8653,
1276e8731180SMartin Kepplinger 	fxls8471,
1277c3cdd6e4SMartin Kepplinger };
1278c3cdd6e4SMartin Kepplinger 
1279c3cdd6e4SMartin Kepplinger static const struct mma_chip_info mma_chip_info_table[] = {
1280244a93f6SMartin Kepplinger 	[mma8451] = {
1281244a93f6SMartin Kepplinger 		.chip_id = MMA8451_DEVICE_ID,
1282244a93f6SMartin Kepplinger 		.channels = mma8451_channels,
1283244a93f6SMartin Kepplinger 		.num_channels = ARRAY_SIZE(mma8451_channels),
1284c3cdd6e4SMartin Kepplinger 		/*
1285c3cdd6e4SMartin Kepplinger 		 * Hardware has fullscale of -2G, -4G, -8G corresponding to
1286244a93f6SMartin Kepplinger 		 * raw value -8192 for 14 bit, -2048 for 12 bit or -512 for 10
1287244a93f6SMartin Kepplinger 		 * bit.
1288c3cdd6e4SMartin Kepplinger 		 * The userspace interface uses m/s^2 and we declare micro units
1289c3cdd6e4SMartin Kepplinger 		 * So scale factor for 12 bit here is given by:
1290c3cdd6e4SMartin Kepplinger 		 *	g * N * 1000000 / 2048 for N = 2, 4, 8 and g=9.80665
1291c3cdd6e4SMartin Kepplinger 		 */
1292244a93f6SMartin Kepplinger 		.mma_scales = { {0, 2394}, {0, 4788}, {0, 9577} },
1293605f72deSHarinath Nampally 		/*
1294605f72deSHarinath Nampally 		 * Although we enable the interrupt sources once and for
1295605f72deSHarinath Nampally 		 * all here the event detection itself is not enabled until
1296605f72deSHarinath Nampally 		 * userspace asks for it by mma8452_write_event_config()
1297605f72deSHarinath Nampally 		 */
1298605f72deSHarinath Nampally 		.all_events = MMA8452_INT_DRDY |
1299605f72deSHarinath Nampally 					MMA8452_INT_TRANS |
1300605f72deSHarinath Nampally 					MMA8452_INT_FF_MT,
1301605f72deSHarinath Nampally 		.enabled_events = MMA8452_INT_TRANS |
1302605f72deSHarinath Nampally 					MMA8452_INT_FF_MT,
1303244a93f6SMartin Kepplinger 	},
1304244a93f6SMartin Kepplinger 	[mma8452] = {
1305244a93f6SMartin Kepplinger 		.chip_id = MMA8452_DEVICE_ID,
1306244a93f6SMartin Kepplinger 		.channels = mma8452_channels,
1307244a93f6SMartin Kepplinger 		.num_channels = ARRAY_SIZE(mma8452_channels),
1308c3cdd6e4SMartin Kepplinger 		.mma_scales = { {0, 9577}, {0, 19154}, {0, 38307} },
1309605f72deSHarinath Nampally 		/*
1310605f72deSHarinath Nampally 		 * Although we enable the interrupt sources once and for
1311605f72deSHarinath Nampally 		 * all here the event detection itself is not enabled until
1312605f72deSHarinath Nampally 		 * userspace asks for it by mma8452_write_event_config()
1313605f72deSHarinath Nampally 		 */
1314605f72deSHarinath Nampally 		.all_events = MMA8452_INT_DRDY |
1315605f72deSHarinath Nampally 					MMA8452_INT_TRANS |
1316605f72deSHarinath Nampally 					MMA8452_INT_FF_MT,
1317605f72deSHarinath Nampally 		.enabled_events = MMA8452_INT_TRANS |
1318605f72deSHarinath Nampally 					MMA8452_INT_FF_MT,
1319c3cdd6e4SMartin Kepplinger 	},
1320c5ea1b58SMartin Kepplinger 	[mma8453] = {
1321c5ea1b58SMartin Kepplinger 		.chip_id = MMA8453_DEVICE_ID,
1322c5ea1b58SMartin Kepplinger 		.channels = mma8453_channels,
1323c5ea1b58SMartin Kepplinger 		.num_channels = ARRAY_SIZE(mma8453_channels),
1324c5ea1b58SMartin Kepplinger 		.mma_scales = { {0, 38307}, {0, 76614}, {0, 153228} },
1325605f72deSHarinath Nampally 		/*
1326605f72deSHarinath Nampally 		 * Although we enable the interrupt sources once and for
1327605f72deSHarinath Nampally 		 * all here the event detection itself is not enabled until
1328605f72deSHarinath Nampally 		 * userspace asks for it by mma8452_write_event_config()
1329605f72deSHarinath Nampally 		 */
1330605f72deSHarinath Nampally 		.all_events = MMA8452_INT_DRDY |
1331605f72deSHarinath Nampally 					MMA8452_INT_TRANS |
1332605f72deSHarinath Nampally 					MMA8452_INT_FF_MT,
1333605f72deSHarinath Nampally 		.enabled_events = MMA8452_INT_TRANS |
1334605f72deSHarinath Nampally 					MMA8452_INT_FF_MT,
1335c5ea1b58SMartin Kepplinger 	},
1336417e008bSMartin Kepplinger 	[mma8652] = {
1337417e008bSMartin Kepplinger 		.chip_id = MMA8652_DEVICE_ID,
1338417e008bSMartin Kepplinger 		.channels = mma8652_channels,
1339417e008bSMartin Kepplinger 		.num_channels = ARRAY_SIZE(mma8652_channels),
1340417e008bSMartin Kepplinger 		.mma_scales = { {0, 9577}, {0, 19154}, {0, 38307} },
1341605f72deSHarinath Nampally 		.all_events = MMA8452_INT_DRDY |
1342605f72deSHarinath Nampally 					MMA8452_INT_FF_MT,
1343605f72deSHarinath Nampally 		.enabled_events = MMA8452_INT_FF_MT,
1344417e008bSMartin Kepplinger 	},
1345417e008bSMartin Kepplinger 	[mma8653] = {
1346417e008bSMartin Kepplinger 		.chip_id = MMA8653_DEVICE_ID,
1347417e008bSMartin Kepplinger 		.channels = mma8653_channels,
1348417e008bSMartin Kepplinger 		.num_channels = ARRAY_SIZE(mma8653_channels),
1349417e008bSMartin Kepplinger 		.mma_scales = { {0, 38307}, {0, 76614}, {0, 153228} },
1350605f72deSHarinath Nampally 		/*
1351605f72deSHarinath Nampally 		 * Although we enable the interrupt sources once and for
1352605f72deSHarinath Nampally 		 * all here the event detection itself is not enabled until
1353605f72deSHarinath Nampally 		 * userspace asks for it by mma8452_write_event_config()
1354605f72deSHarinath Nampally 		 */
1355605f72deSHarinath Nampally 		.all_events = MMA8452_INT_DRDY |
1356605f72deSHarinath Nampally 					MMA8452_INT_FF_MT,
1357605f72deSHarinath Nampally 		.enabled_events = MMA8452_INT_FF_MT,
1358417e008bSMartin Kepplinger 	},
1359e8731180SMartin Kepplinger 	[fxls8471] = {
1360e8731180SMartin Kepplinger 		.chip_id = FXLS8471_DEVICE_ID,
1361e8731180SMartin Kepplinger 		.channels = mma8451_channels,
1362e8731180SMartin Kepplinger 		.num_channels = ARRAY_SIZE(mma8451_channels),
1363e8731180SMartin Kepplinger 		.mma_scales = { {0, 2394}, {0, 4788}, {0, 9577} },
1364605f72deSHarinath Nampally 		/*
1365605f72deSHarinath Nampally 		 * Although we enable the interrupt sources once and for
1366605f72deSHarinath Nampally 		 * all here the event detection itself is not enabled until
1367605f72deSHarinath Nampally 		 * userspace asks for it by mma8452_write_event_config()
1368605f72deSHarinath Nampally 		 */
1369605f72deSHarinath Nampally 		.all_events = MMA8452_INT_DRDY |
1370605f72deSHarinath Nampally 					MMA8452_INT_TRANS |
1371605f72deSHarinath Nampally 					MMA8452_INT_FF_MT,
1372605f72deSHarinath Nampally 		.enabled_events = MMA8452_INT_TRANS |
1373605f72deSHarinath Nampally 					MMA8452_INT_FF_MT,
1374e8731180SMartin Kepplinger 	},
1375c3cdd6e4SMartin Kepplinger };
1376c3cdd6e4SMartin Kepplinger 
1377c7eeea93SPeter Meerwald static struct attribute *mma8452_attributes[] = {
1378c7eeea93SPeter Meerwald 	&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
1379c7eeea93SPeter Meerwald 	&iio_dev_attr_in_accel_scale_available.dev_attr.attr,
13801e79841aSMartin Fuzzey 	&iio_dev_attr_in_accel_filter_high_pass_3db_frequency_available.dev_attr.attr,
1381ed859fc1SMartin Kepplinger 	&iio_dev_attr_in_accel_oversampling_ratio_available.dev_attr.attr,
1382c7eeea93SPeter Meerwald 	NULL
1383c7eeea93SPeter Meerwald };
1384c7eeea93SPeter Meerwald 
1385c7eeea93SPeter Meerwald static const struct attribute_group mma8452_group = {
1386c7eeea93SPeter Meerwald 	.attrs = mma8452_attributes,
1387c7eeea93SPeter Meerwald };
1388c7eeea93SPeter Meerwald 
1389c7eeea93SPeter Meerwald static const struct iio_info mma8452_info = {
1390c7eeea93SPeter Meerwald 	.attrs = &mma8452_group,
1391c7eeea93SPeter Meerwald 	.read_raw = &mma8452_read_raw,
1392c7eeea93SPeter Meerwald 	.write_raw = &mma8452_write_raw,
139328e34278SMartin Fuzzey 	.event_attrs = &mma8452_event_attribute_group,
139428e34278SMartin Fuzzey 	.read_event_value = &mma8452_read_thresh,
139528e34278SMartin Fuzzey 	.write_event_value = &mma8452_write_thresh,
139628e34278SMartin Fuzzey 	.read_event_config = &mma8452_read_event_config,
139728e34278SMartin Fuzzey 	.write_event_config = &mma8452_write_event_config,
13982a17698cSMartin Fuzzey 	.debugfs_reg_access = &mma8452_reg_access_dbg,
1399c7eeea93SPeter Meerwald };
1400c7eeea93SPeter Meerwald 
1401c7eeea93SPeter Meerwald static const unsigned long mma8452_scan_masks[] = {0x7, 0};
1402c7eeea93SPeter Meerwald 
1403ae6d9ce0SMartin Fuzzey static int mma8452_data_rdy_trigger_set_state(struct iio_trigger *trig,
1404ae6d9ce0SMartin Fuzzey 					      bool state)
1405ae6d9ce0SMartin Fuzzey {
1406ae6d9ce0SMartin Fuzzey 	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
1407ae6d9ce0SMartin Fuzzey 	struct mma8452_data *data = iio_priv(indio_dev);
140896c0cb2bSMartin Kepplinger 	int reg, ret;
140996c0cb2bSMartin Kepplinger 
141096c0cb2bSMartin Kepplinger 	ret = mma8452_set_runtime_pm_state(data->client, state);
141196c0cb2bSMartin Kepplinger 	if (ret)
141296c0cb2bSMartin Kepplinger 		return ret;
1413ae6d9ce0SMartin Fuzzey 
1414ae6d9ce0SMartin Fuzzey 	reg = i2c_smbus_read_byte_data(data->client, MMA8452_CTRL_REG4);
1415ae6d9ce0SMartin Fuzzey 	if (reg < 0)
1416ae6d9ce0SMartin Fuzzey 		return reg;
1417ae6d9ce0SMartin Fuzzey 
1418ae6d9ce0SMartin Fuzzey 	if (state)
1419ae6d9ce0SMartin Fuzzey 		reg |= MMA8452_INT_DRDY;
1420ae6d9ce0SMartin Fuzzey 	else
1421ae6d9ce0SMartin Fuzzey 		reg &= ~MMA8452_INT_DRDY;
1422ae6d9ce0SMartin Fuzzey 
1423ae6d9ce0SMartin Fuzzey 	return mma8452_change_config(data, MMA8452_CTRL_REG4, reg);
1424ae6d9ce0SMartin Fuzzey }
1425ae6d9ce0SMartin Fuzzey 
1426ae6d9ce0SMartin Fuzzey static const struct iio_trigger_ops mma8452_trigger_ops = {
1427ae6d9ce0SMartin Fuzzey 	.set_trigger_state = mma8452_data_rdy_trigger_set_state,
142819808e04SLars-Peter Clausen 	.validate_device = iio_trigger_validate_own_device,
1429ae6d9ce0SMartin Fuzzey };
1430ae6d9ce0SMartin Fuzzey 
1431ae6d9ce0SMartin Fuzzey static int mma8452_trigger_setup(struct iio_dev *indio_dev)
1432ae6d9ce0SMartin Fuzzey {
1433ae6d9ce0SMartin Fuzzey 	struct mma8452_data *data = iio_priv(indio_dev);
1434ae6d9ce0SMartin Fuzzey 	struct iio_trigger *trig;
1435ae6d9ce0SMartin Fuzzey 	int ret;
1436ae6d9ce0SMartin Fuzzey 
1437ae6d9ce0SMartin Fuzzey 	trig = devm_iio_trigger_alloc(&data->client->dev, "%s-dev%d",
1438ae6d9ce0SMartin Fuzzey 				      indio_dev->name,
1439ae6d9ce0SMartin Fuzzey 				      indio_dev->id);
1440ae6d9ce0SMartin Fuzzey 	if (!trig)
1441ae6d9ce0SMartin Fuzzey 		return -ENOMEM;
1442ae6d9ce0SMartin Fuzzey 
1443ae6d9ce0SMartin Fuzzey 	trig->dev.parent = &data->client->dev;
1444ae6d9ce0SMartin Fuzzey 	trig->ops = &mma8452_trigger_ops;
1445ae6d9ce0SMartin Fuzzey 	iio_trigger_set_drvdata(trig, indio_dev);
1446ae6d9ce0SMartin Fuzzey 
1447ae6d9ce0SMartin Fuzzey 	ret = iio_trigger_register(trig);
1448ae6d9ce0SMartin Fuzzey 	if (ret)
1449ae6d9ce0SMartin Fuzzey 		return ret;
1450ae6d9ce0SMartin Fuzzey 
1451ae6d9ce0SMartin Fuzzey 	indio_dev->trig = trig;
1452686027fbSHartmut Knaack 
1453ae6d9ce0SMartin Fuzzey 	return 0;
1454ae6d9ce0SMartin Fuzzey }
1455ae6d9ce0SMartin Fuzzey 
1456ae6d9ce0SMartin Fuzzey static void mma8452_trigger_cleanup(struct iio_dev *indio_dev)
1457ae6d9ce0SMartin Fuzzey {
1458ae6d9ce0SMartin Fuzzey 	if (indio_dev->trig)
1459ae6d9ce0SMartin Fuzzey 		iio_trigger_unregister(indio_dev->trig);
1460ae6d9ce0SMartin Fuzzey }
1461ae6d9ce0SMartin Fuzzey 
1462ecabae71SMartin Fuzzey static int mma8452_reset(struct i2c_client *client)
1463ecabae71SMartin Fuzzey {
1464ecabae71SMartin Fuzzey 	int i;
1465ecabae71SMartin Fuzzey 	int ret;
1466ecabae71SMartin Fuzzey 
1467ecabae71SMartin Fuzzey 	ret = i2c_smbus_write_byte_data(client,	MMA8452_CTRL_REG2,
1468ecabae71SMartin Fuzzey 					MMA8452_CTRL_REG2_RST);
1469ecabae71SMartin Fuzzey 	if (ret < 0)
1470ecabae71SMartin Fuzzey 		return ret;
1471ecabae71SMartin Fuzzey 
1472ecabae71SMartin Fuzzey 	for (i = 0; i < 10; i++) {
1473ecabae71SMartin Fuzzey 		usleep_range(100, 200);
1474ecabae71SMartin Fuzzey 		ret = i2c_smbus_read_byte_data(client, MMA8452_CTRL_REG2);
1475ecabae71SMartin Fuzzey 		if (ret == -EIO)
1476ecabae71SMartin Fuzzey 			continue; /* I2C comm reset */
1477ecabae71SMartin Fuzzey 		if (ret < 0)
1478ecabae71SMartin Fuzzey 			return ret;
1479ecabae71SMartin Fuzzey 		if (!(ret & MMA8452_CTRL_REG2_RST))
1480ecabae71SMartin Fuzzey 			return 0;
1481ecabae71SMartin Fuzzey 	}
1482ecabae71SMartin Fuzzey 
1483ecabae71SMartin Fuzzey 	return -ETIMEDOUT;
1484ecabae71SMartin Fuzzey }
1485ecabae71SMartin Fuzzey 
1486c3cdd6e4SMartin Kepplinger static const struct of_device_id mma8452_dt_ids[] = {
1487244a93f6SMartin Kepplinger 	{ .compatible = "fsl,mma8451", .data = &mma_chip_info_table[mma8451] },
1488c3cdd6e4SMartin Kepplinger 	{ .compatible = "fsl,mma8452", .data = &mma_chip_info_table[mma8452] },
1489c5ea1b58SMartin Kepplinger 	{ .compatible = "fsl,mma8453", .data = &mma_chip_info_table[mma8453] },
1490417e008bSMartin Kepplinger 	{ .compatible = "fsl,mma8652", .data = &mma_chip_info_table[mma8652] },
1491417e008bSMartin Kepplinger 	{ .compatible = "fsl,mma8653", .data = &mma_chip_info_table[mma8653] },
1492e8731180SMartin Kepplinger 	{ .compatible = "fsl,fxls8471", .data = &mma_chip_info_table[fxls8471] },
1493c3cdd6e4SMartin Kepplinger 	{ }
1494c3cdd6e4SMartin Kepplinger };
1495c3cdd6e4SMartin Kepplinger MODULE_DEVICE_TABLE(of, mma8452_dt_ids);
1496c3cdd6e4SMartin Kepplinger 
1497c7eeea93SPeter Meerwald static int mma8452_probe(struct i2c_client *client,
1498c7eeea93SPeter Meerwald 			 const struct i2c_device_id *id)
1499c7eeea93SPeter Meerwald {
1500c7eeea93SPeter Meerwald 	struct mma8452_data *data;
1501c7eeea93SPeter Meerwald 	struct iio_dev *indio_dev;
1502c7eeea93SPeter Meerwald 	int ret;
1503c3cdd6e4SMartin Kepplinger 	const struct of_device_id *match;
1504c7eeea93SPeter Meerwald 
1505c3cdd6e4SMartin Kepplinger 	match = of_match_device(mma8452_dt_ids, &client->dev);
1506c3cdd6e4SMartin Kepplinger 	if (!match) {
1507c3cdd6e4SMartin Kepplinger 		dev_err(&client->dev, "unknown device model\n");
1508c3cdd6e4SMartin Kepplinger 		return -ENODEV;
1509c3cdd6e4SMartin Kepplinger 	}
1510c3cdd6e4SMartin Kepplinger 
1511c7eeea93SPeter Meerwald 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
1512c7eeea93SPeter Meerwald 	if (!indio_dev)
1513c7eeea93SPeter Meerwald 		return -ENOMEM;
1514c7eeea93SPeter Meerwald 
1515c7eeea93SPeter Meerwald 	data = iio_priv(indio_dev);
1516c7eeea93SPeter Meerwald 	data->client = client;
1517c7eeea93SPeter Meerwald 	mutex_init(&data->lock);
1518c3cdd6e4SMartin Kepplinger 	data->chip_info = match->data;
1519c3cdd6e4SMartin Kepplinger 
1520417e008bSMartin Kepplinger 	ret = i2c_smbus_read_byte_data(client, MMA8452_WHO_AM_I);
1521417e008bSMartin Kepplinger 	if (ret < 0)
1522417e008bSMartin Kepplinger 		return ret;
1523417e008bSMartin Kepplinger 
1524417e008bSMartin Kepplinger 	switch (ret) {
1525244a93f6SMartin Kepplinger 	case MMA8451_DEVICE_ID:
1526417e008bSMartin Kepplinger 	case MMA8452_DEVICE_ID:
1527417e008bSMartin Kepplinger 	case MMA8453_DEVICE_ID:
1528417e008bSMartin Kepplinger 	case MMA8652_DEVICE_ID:
1529417e008bSMartin Kepplinger 	case MMA8653_DEVICE_ID:
1530e8731180SMartin Kepplinger 	case FXLS8471_DEVICE_ID:
1531417e008bSMartin Kepplinger 		if (ret == data->chip_info->chip_id)
1532417e008bSMartin Kepplinger 			break;
1533417e008bSMartin Kepplinger 	default:
1534417e008bSMartin Kepplinger 		return -ENODEV;
1535417e008bSMartin Kepplinger 	}
1536417e008bSMartin Kepplinger 
1537c3cdd6e4SMartin Kepplinger 	dev_info(&client->dev, "registering %s accelerometer; ID 0x%x\n",
1538c3cdd6e4SMartin Kepplinger 		 match->compatible, data->chip_info->chip_id);
1539c7eeea93SPeter Meerwald 
1540c7eeea93SPeter Meerwald 	i2c_set_clientdata(client, indio_dev);
1541c7eeea93SPeter Meerwald 	indio_dev->info = &mma8452_info;
1542c7eeea93SPeter Meerwald 	indio_dev->name = id->name;
1543c7eeea93SPeter Meerwald 	indio_dev->dev.parent = &client->dev;
1544c7eeea93SPeter Meerwald 	indio_dev->modes = INDIO_DIRECT_MODE;
1545c3cdd6e4SMartin Kepplinger 	indio_dev->channels = data->chip_info->channels;
1546c3cdd6e4SMartin Kepplinger 	indio_dev->num_channels = data->chip_info->num_channels;
1547c7eeea93SPeter Meerwald 	indio_dev->available_scan_masks = mma8452_scan_masks;
1548c7eeea93SPeter Meerwald 
1549ecabae71SMartin Fuzzey 	ret = mma8452_reset(client);
1550c7eeea93SPeter Meerwald 	if (ret < 0)
1551c7eeea93SPeter Meerwald 		return ret;
1552c7eeea93SPeter Meerwald 
1553c7eeea93SPeter Meerwald 	data->data_cfg = MMA8452_DATA_CFG_FS_2G;
1554c7eeea93SPeter Meerwald 	ret = i2c_smbus_write_byte_data(client, MMA8452_DATA_CFG,
1555c7eeea93SPeter Meerwald 					data->data_cfg);
1556c7eeea93SPeter Meerwald 	if (ret < 0)
1557c7eeea93SPeter Meerwald 		return ret;
1558c7eeea93SPeter Meerwald 
155928e34278SMartin Fuzzey 	/*
156028e34278SMartin Fuzzey 	 * By default set transient threshold to max to avoid events if
156128e34278SMartin Fuzzey 	 * enabling without configuring threshold.
156228e34278SMartin Fuzzey 	 */
156328e34278SMartin Fuzzey 	ret = i2c_smbus_write_byte_data(client, MMA8452_TRANSIENT_THS,
156428e34278SMartin Fuzzey 					MMA8452_TRANSIENT_THS_MASK);
156528e34278SMartin Fuzzey 	if (ret < 0)
156628e34278SMartin Fuzzey 		return ret;
156728e34278SMartin Fuzzey 
156828e34278SMartin Fuzzey 	if (client->irq) {
1569d2a3e093SMartin Kepplinger 		int irq2;
157028e34278SMartin Fuzzey 
1571d2a3e093SMartin Kepplinger 		irq2 = of_irq_get_byname(client->dev.of_node, "INT2");
1572d2a3e093SMartin Kepplinger 
1573d2a3e093SMartin Kepplinger 		if (irq2 == client->irq) {
1574d2a3e093SMartin Kepplinger 			dev_dbg(&client->dev, "using interrupt line INT2\n");
1575d2a3e093SMartin Kepplinger 		} else {
157628e34278SMartin Fuzzey 			ret = i2c_smbus_write_byte_data(client,
157728e34278SMartin Fuzzey 						MMA8452_CTRL_REG5,
1578605f72deSHarinath Nampally 						data->chip_info->all_events);
157928e34278SMartin Fuzzey 			if (ret < 0)
158028e34278SMartin Fuzzey 				return ret;
158128e34278SMartin Fuzzey 
1582d2a3e093SMartin Kepplinger 			dev_dbg(&client->dev, "using interrupt line INT1\n");
1583d2a3e093SMartin Kepplinger 		}
1584d2a3e093SMartin Kepplinger 
158528e34278SMartin Fuzzey 		ret = i2c_smbus_write_byte_data(client,
158628e34278SMartin Fuzzey 					MMA8452_CTRL_REG4,
1587605f72deSHarinath Nampally 					data->chip_info->enabled_events);
1588ae6d9ce0SMartin Fuzzey 		if (ret < 0)
1589ae6d9ce0SMartin Fuzzey 			return ret;
1590ae6d9ce0SMartin Fuzzey 
1591ae6d9ce0SMartin Fuzzey 		ret = mma8452_trigger_setup(indio_dev);
159228e34278SMartin Fuzzey 		if (ret < 0)
159328e34278SMartin Fuzzey 			return ret;
159428e34278SMartin Fuzzey 	}
159528e34278SMartin Fuzzey 
1596ecabae71SMartin Fuzzey 	data->ctrl_reg1 = MMA8452_CTRL_ACTIVE |
1597ecabae71SMartin Fuzzey 			  (MMA8452_CTRL_DR_DEFAULT << MMA8452_CTRL_DR_SHIFT);
1598ecabae71SMartin Fuzzey 	ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG1,
1599ecabae71SMartin Fuzzey 					data->ctrl_reg1);
1600ecabae71SMartin Fuzzey 	if (ret < 0)
1601ae6d9ce0SMartin Fuzzey 		goto trigger_cleanup;
1602ecabae71SMartin Fuzzey 
1603c7eeea93SPeter Meerwald 	ret = iio_triggered_buffer_setup(indio_dev, NULL,
1604c7eeea93SPeter Meerwald 					 mma8452_trigger_handler, NULL);
1605c7eeea93SPeter Meerwald 	if (ret < 0)
1606ae6d9ce0SMartin Fuzzey 		goto trigger_cleanup;
1607c7eeea93SPeter Meerwald 
160828e34278SMartin Fuzzey 	if (client->irq) {
160928e34278SMartin Fuzzey 		ret = devm_request_threaded_irq(&client->dev,
161028e34278SMartin Fuzzey 						client->irq,
161128e34278SMartin Fuzzey 						NULL, mma8452_interrupt,
161228e34278SMartin Fuzzey 						IRQF_TRIGGER_LOW | IRQF_ONESHOT,
161328e34278SMartin Fuzzey 						client->name, indio_dev);
161428e34278SMartin Fuzzey 		if (ret)
161528e34278SMartin Fuzzey 			goto buffer_cleanup;
161628e34278SMartin Fuzzey 	}
161728e34278SMartin Fuzzey 
161896c0cb2bSMartin Kepplinger 	ret = pm_runtime_set_active(&client->dev);
161996c0cb2bSMartin Kepplinger 	if (ret < 0)
162096c0cb2bSMartin Kepplinger 		goto buffer_cleanup;
162196c0cb2bSMartin Kepplinger 
162296c0cb2bSMartin Kepplinger 	pm_runtime_enable(&client->dev);
162396c0cb2bSMartin Kepplinger 	pm_runtime_set_autosuspend_delay(&client->dev,
162496c0cb2bSMartin Kepplinger 					 MMA8452_AUTO_SUSPEND_DELAY_MS);
162596c0cb2bSMartin Kepplinger 	pm_runtime_use_autosuspend(&client->dev);
162696c0cb2bSMartin Kepplinger 
1627c7eeea93SPeter Meerwald 	ret = iio_device_register(indio_dev);
1628c7eeea93SPeter Meerwald 	if (ret < 0)
1629c7eeea93SPeter Meerwald 		goto buffer_cleanup;
163028e34278SMartin Fuzzey 
16314b04266aSMartin Kepplinger 	ret = mma8452_set_freefall_mode(data, false);
16321a965d40SBijosh Thykkoottathil 	if (ret < 0)
16331a965d40SBijosh Thykkoottathil 		goto buffer_cleanup;
16344b04266aSMartin Kepplinger 
1635c7eeea93SPeter Meerwald 	return 0;
1636c7eeea93SPeter Meerwald 
1637c7eeea93SPeter Meerwald buffer_cleanup:
1638c7eeea93SPeter Meerwald 	iio_triggered_buffer_cleanup(indio_dev);
1639ae6d9ce0SMartin Fuzzey 
1640ae6d9ce0SMartin Fuzzey trigger_cleanup:
1641ae6d9ce0SMartin Fuzzey 	mma8452_trigger_cleanup(indio_dev);
1642ae6d9ce0SMartin Fuzzey 
1643c7eeea93SPeter Meerwald 	return ret;
1644c7eeea93SPeter Meerwald }
1645c7eeea93SPeter Meerwald 
1646c7eeea93SPeter Meerwald static int mma8452_remove(struct i2c_client *client)
1647c7eeea93SPeter Meerwald {
1648c7eeea93SPeter Meerwald 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
1649c7eeea93SPeter Meerwald 
1650c7eeea93SPeter Meerwald 	iio_device_unregister(indio_dev);
165196c0cb2bSMartin Kepplinger 
165296c0cb2bSMartin Kepplinger 	pm_runtime_disable(&client->dev);
165396c0cb2bSMartin Kepplinger 	pm_runtime_set_suspended(&client->dev);
165496c0cb2bSMartin Kepplinger 	pm_runtime_put_noidle(&client->dev);
165596c0cb2bSMartin Kepplinger 
1656c7eeea93SPeter Meerwald 	iio_triggered_buffer_cleanup(indio_dev);
1657ae6d9ce0SMartin Fuzzey 	mma8452_trigger_cleanup(indio_dev);
1658c7eeea93SPeter Meerwald 	mma8452_standby(iio_priv(indio_dev));
1659c7eeea93SPeter Meerwald 
1660c7eeea93SPeter Meerwald 	return 0;
1661c7eeea93SPeter Meerwald }
1662c7eeea93SPeter Meerwald 
166396c0cb2bSMartin Kepplinger #ifdef CONFIG_PM
166496c0cb2bSMartin Kepplinger static int mma8452_runtime_suspend(struct device *dev)
166596c0cb2bSMartin Kepplinger {
166696c0cb2bSMartin Kepplinger 	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
166796c0cb2bSMartin Kepplinger 	struct mma8452_data *data = iio_priv(indio_dev);
166896c0cb2bSMartin Kepplinger 	int ret;
166996c0cb2bSMartin Kepplinger 
167096c0cb2bSMartin Kepplinger 	mutex_lock(&data->lock);
167196c0cb2bSMartin Kepplinger 	ret = mma8452_standby(data);
167296c0cb2bSMartin Kepplinger 	mutex_unlock(&data->lock);
167396c0cb2bSMartin Kepplinger 	if (ret < 0) {
167496c0cb2bSMartin Kepplinger 		dev_err(&data->client->dev, "powering off device failed\n");
167596c0cb2bSMartin Kepplinger 		return -EAGAIN;
167696c0cb2bSMartin Kepplinger 	}
167796c0cb2bSMartin Kepplinger 
167896c0cb2bSMartin Kepplinger 	return 0;
167996c0cb2bSMartin Kepplinger }
168096c0cb2bSMartin Kepplinger 
168196c0cb2bSMartin Kepplinger static int mma8452_runtime_resume(struct device *dev)
168296c0cb2bSMartin Kepplinger {
168396c0cb2bSMartin Kepplinger 	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
168496c0cb2bSMartin Kepplinger 	struct mma8452_data *data = iio_priv(indio_dev);
168596c0cb2bSMartin Kepplinger 	int ret, sleep_val;
168696c0cb2bSMartin Kepplinger 
168796c0cb2bSMartin Kepplinger 	ret = mma8452_active(data);
168896c0cb2bSMartin Kepplinger 	if (ret < 0)
168996c0cb2bSMartin Kepplinger 		return ret;
169096c0cb2bSMartin Kepplinger 
169196c0cb2bSMartin Kepplinger 	ret = mma8452_get_odr_index(data);
169296c0cb2bSMartin Kepplinger 	sleep_val = 1000 / mma8452_samp_freq[ret][0];
169396c0cb2bSMartin Kepplinger 	if (sleep_val < 20)
169496c0cb2bSMartin Kepplinger 		usleep_range(sleep_val * 1000, 20000);
169596c0cb2bSMartin Kepplinger 	else
169696c0cb2bSMartin Kepplinger 		msleep_interruptible(sleep_val);
169796c0cb2bSMartin Kepplinger 
169896c0cb2bSMartin Kepplinger 	return 0;
169996c0cb2bSMartin Kepplinger }
170096c0cb2bSMartin Kepplinger #endif
170196c0cb2bSMartin Kepplinger 
1702c7eeea93SPeter Meerwald #ifdef CONFIG_PM_SLEEP
1703c7eeea93SPeter Meerwald static int mma8452_suspend(struct device *dev)
1704c7eeea93SPeter Meerwald {
1705c7eeea93SPeter Meerwald 	return mma8452_standby(iio_priv(i2c_get_clientdata(
1706c7eeea93SPeter Meerwald 		to_i2c_client(dev))));
1707c7eeea93SPeter Meerwald }
1708c7eeea93SPeter Meerwald 
1709c7eeea93SPeter Meerwald static int mma8452_resume(struct device *dev)
1710c7eeea93SPeter Meerwald {
1711c7eeea93SPeter Meerwald 	return mma8452_active(iio_priv(i2c_get_clientdata(
1712c7eeea93SPeter Meerwald 		to_i2c_client(dev))));
1713c7eeea93SPeter Meerwald }
1714c7eeea93SPeter Meerwald #endif
1715c7eeea93SPeter Meerwald 
171696c0cb2bSMartin Kepplinger static const struct dev_pm_ops mma8452_pm_ops = {
171796c0cb2bSMartin Kepplinger 	SET_SYSTEM_SLEEP_PM_OPS(mma8452_suspend, mma8452_resume)
171896c0cb2bSMartin Kepplinger 	SET_RUNTIME_PM_OPS(mma8452_runtime_suspend,
171996c0cb2bSMartin Kepplinger 			   mma8452_runtime_resume, NULL)
172096c0cb2bSMartin Kepplinger };
172196c0cb2bSMartin Kepplinger 
1722c7eeea93SPeter Meerwald static const struct i2c_device_id mma8452_id[] = {
1723ddb851afSMartin Kepplinger 	{ "mma8451", mma8451 },
1724c3cdd6e4SMartin Kepplinger 	{ "mma8452", mma8452 },
1725c5ea1b58SMartin Kepplinger 	{ "mma8453", mma8453 },
1726417e008bSMartin Kepplinger 	{ "mma8652", mma8652 },
1727417e008bSMartin Kepplinger 	{ "mma8653", mma8653 },
1728e8731180SMartin Kepplinger 	{ "fxls8471", fxls8471 },
1729c7eeea93SPeter Meerwald 	{ }
1730c7eeea93SPeter Meerwald };
1731c7eeea93SPeter Meerwald MODULE_DEVICE_TABLE(i2c, mma8452_id);
1732c7eeea93SPeter Meerwald 
1733c7eeea93SPeter Meerwald static struct i2c_driver mma8452_driver = {
1734c7eeea93SPeter Meerwald 	.driver = {
1735c7eeea93SPeter Meerwald 		.name	= "mma8452",
1736a3fb96a8SMartin Fuzzey 		.of_match_table = of_match_ptr(mma8452_dt_ids),
173796c0cb2bSMartin Kepplinger 		.pm	= &mma8452_pm_ops,
1738c7eeea93SPeter Meerwald 	},
1739c7eeea93SPeter Meerwald 	.probe = mma8452_probe,
1740c7eeea93SPeter Meerwald 	.remove = mma8452_remove,
1741c7eeea93SPeter Meerwald 	.id_table = mma8452_id,
1742c7eeea93SPeter Meerwald };
1743c7eeea93SPeter Meerwald module_i2c_driver(mma8452_driver);
1744c7eeea93SPeter Meerwald 
1745c7eeea93SPeter Meerwald MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
1746f26ab1aaSMartin Kepplinger MODULE_DESCRIPTION("Freescale / NXP MMA8452 accelerometer driver");
1747c7eeea93SPeter Meerwald MODULE_LICENSE("GPL");
1748