xref: /openbmc/linux/drivers/iio/imu/kmx61.c (revision d32fd6bb9f2bc8178cdd65ebec1ad670a8bfa241)
136edc939SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
220ffac27SDaniel Baluta /*
320ffac27SDaniel Baluta  * KMX61 - Kionix 6-axis Accelerometer/Magnetometer
420ffac27SDaniel Baluta  *
520ffac27SDaniel Baluta  * Copyright (c) 2014, Intel Corporation.
620ffac27SDaniel Baluta  *
720ffac27SDaniel Baluta  * IIO driver for KMX61 (7-bit I2C slave address 0x0E or 0x0F).
820ffac27SDaniel Baluta  */
920ffac27SDaniel Baluta 
1020ffac27SDaniel Baluta #include <linux/module.h>
1120ffac27SDaniel Baluta #include <linux/i2c.h>
12b25862c5SDaniel Baluta #include <linux/acpi.h>
13aff8609aSDaniel Baluta #include <linux/interrupt.h>
143b9c40e6SDaniel Baluta #include <linux/pm.h>
15aff8609aSDaniel Baluta #include <linux/pm_runtime.h>
1620ffac27SDaniel Baluta #include <linux/iio/iio.h>
1720ffac27SDaniel Baluta #include <linux/iio/sysfs.h>
18fd3ae7a9SDaniel Baluta #include <linux/iio/events.h>
19c3a23eccSDaniel Baluta #include <linux/iio/trigger.h>
20c3a23eccSDaniel Baluta #include <linux/iio/buffer.h>
21c3a23eccSDaniel Baluta #include <linux/iio/triggered_buffer.h>
22c3a23eccSDaniel Baluta #include <linux/iio/trigger_consumer.h>
2320ffac27SDaniel Baluta 
2420ffac27SDaniel Baluta #define KMX61_DRV_NAME "kmx61"
25c3a23eccSDaniel Baluta #define KMX61_IRQ_NAME "kmx61_event"
2620ffac27SDaniel Baluta 
2720ffac27SDaniel Baluta #define KMX61_REG_WHO_AM_I	0x00
28fd3ae7a9SDaniel Baluta #define KMX61_REG_INS1		0x01
29fd3ae7a9SDaniel Baluta #define KMX61_REG_INS2		0x02
3020ffac27SDaniel Baluta 
3120ffac27SDaniel Baluta /*
3220ffac27SDaniel Baluta  * three 16-bit accelerometer output registers for X/Y/Z axis
3320ffac27SDaniel Baluta  * we use only XOUT_L as a base register, all other addresses
3420ffac27SDaniel Baluta  * can be obtained by applying an offset and are provided here
3520ffac27SDaniel Baluta  * only for clarity.
3620ffac27SDaniel Baluta  */
3720ffac27SDaniel Baluta #define KMX61_ACC_XOUT_L	0x0A
3820ffac27SDaniel Baluta #define KMX61_ACC_XOUT_H	0x0B
3920ffac27SDaniel Baluta #define KMX61_ACC_YOUT_L	0x0C
4020ffac27SDaniel Baluta #define KMX61_ACC_YOUT_H	0x0D
4120ffac27SDaniel Baluta #define KMX61_ACC_ZOUT_L	0x0E
4220ffac27SDaniel Baluta #define KMX61_ACC_ZOUT_H	0x0F
4320ffac27SDaniel Baluta 
4420ffac27SDaniel Baluta /*
4520ffac27SDaniel Baluta  * one 16-bit temperature output register
4620ffac27SDaniel Baluta  */
4720ffac27SDaniel Baluta #define KMX61_TEMP_L		0x10
4820ffac27SDaniel Baluta #define KMX61_TEMP_H		0x11
4920ffac27SDaniel Baluta 
5020ffac27SDaniel Baluta /*
5120ffac27SDaniel Baluta  * three 16-bit magnetometer output registers for X/Y/Z axis
5220ffac27SDaniel Baluta  */
5320ffac27SDaniel Baluta #define KMX61_MAG_XOUT_L	0x12
5420ffac27SDaniel Baluta #define KMX61_MAG_XOUT_H	0x13
5520ffac27SDaniel Baluta #define KMX61_MAG_YOUT_L	0x14
5620ffac27SDaniel Baluta #define KMX61_MAG_YOUT_H	0x15
5720ffac27SDaniel Baluta #define KMX61_MAG_ZOUT_L	0x16
5820ffac27SDaniel Baluta #define KMX61_MAG_ZOUT_H	0x17
5920ffac27SDaniel Baluta 
60c3a23eccSDaniel Baluta #define KMX61_REG_INL		0x28
6120ffac27SDaniel Baluta #define KMX61_REG_STBY		0x29
6220ffac27SDaniel Baluta #define KMX61_REG_CTRL1		0x2A
63fd3ae7a9SDaniel Baluta #define KMX61_REG_CTRL2		0x2B
6420ffac27SDaniel Baluta #define KMX61_REG_ODCNTL	0x2C
65c3a23eccSDaniel Baluta #define KMX61_REG_INC1		0x2D
6620ffac27SDaniel Baluta 
67fd3ae7a9SDaniel Baluta #define KMX61_REG_WUF_THRESH	0x3D
68fd3ae7a9SDaniel Baluta #define KMX61_REG_WUF_TIMER	0x3E
69fd3ae7a9SDaniel Baluta 
7020ffac27SDaniel Baluta #define KMX61_ACC_STBY_BIT	BIT(0)
7120ffac27SDaniel Baluta #define KMX61_MAG_STBY_BIT	BIT(1)
7220ffac27SDaniel Baluta #define KMX61_ACT_STBY_BIT	BIT(7)
7320ffac27SDaniel Baluta 
7420ffac27SDaniel Baluta #define KMX61_ALL_STBY		(KMX61_ACC_STBY_BIT | KMX61_MAG_STBY_BIT)
7520ffac27SDaniel Baluta 
76fd3ae7a9SDaniel Baluta #define KMX61_REG_INS1_BIT_WUFS		BIT(1)
77fd3ae7a9SDaniel Baluta 
78fd3ae7a9SDaniel Baluta #define KMX61_REG_INS2_BIT_ZP		BIT(0)
79fd3ae7a9SDaniel Baluta #define KMX61_REG_INS2_BIT_ZN		BIT(1)
80fd3ae7a9SDaniel Baluta #define KMX61_REG_INS2_BIT_YP		BIT(2)
81fd3ae7a9SDaniel Baluta #define KMX61_REG_INS2_BIT_YN		BIT(3)
82fd3ae7a9SDaniel Baluta #define KMX61_REG_INS2_BIT_XP		BIT(4)
83fd3ae7a9SDaniel Baluta #define KMX61_REG_INS2_BIT_XN		BIT(5)
84fd3ae7a9SDaniel Baluta 
8520ffac27SDaniel Baluta #define KMX61_REG_CTRL1_GSEL_MASK	0x03
8620ffac27SDaniel Baluta 
87c3a23eccSDaniel Baluta #define KMX61_REG_CTRL1_BIT_RES		BIT(4)
88c3a23eccSDaniel Baluta #define KMX61_REG_CTRL1_BIT_DRDYE	BIT(5)
89fd3ae7a9SDaniel Baluta #define KMX61_REG_CTRL1_BIT_WUFE	BIT(6)
90fd3ae7a9SDaniel Baluta #define KMX61_REG_CTRL1_BIT_BTSE	BIT(7)
91c3a23eccSDaniel Baluta 
92fd3ae7a9SDaniel Baluta #define KMX61_REG_INC1_BIT_WUFS		BIT(0)
93c3a23eccSDaniel Baluta #define KMX61_REG_INC1_BIT_DRDYM	BIT(1)
94c3a23eccSDaniel Baluta #define KMX61_REG_INC1_BIT_DRDYA	BIT(2)
95c3a23eccSDaniel Baluta #define KMX61_REG_INC1_BIT_IEN		BIT(5)
96c3a23eccSDaniel Baluta 
9720ffac27SDaniel Baluta #define KMX61_ACC_ODR_SHIFT	0
9820ffac27SDaniel Baluta #define KMX61_MAG_ODR_SHIFT	4
9920ffac27SDaniel Baluta #define KMX61_ACC_ODR_MASK	0x0F
10020ffac27SDaniel Baluta #define KMX61_MAG_ODR_MASK	0xF0
10120ffac27SDaniel Baluta 
102fd3ae7a9SDaniel Baluta #define KMX61_OWUF_MASK		0x7
103fd3ae7a9SDaniel Baluta 
104fd3ae7a9SDaniel Baluta #define KMX61_DEFAULT_WAKE_THRESH	1
105fd3ae7a9SDaniel Baluta #define KMX61_DEFAULT_WAKE_DURATION	1
106fd3ae7a9SDaniel Baluta 
107aff8609aSDaniel Baluta #define KMX61_SLEEP_DELAY_MS	2000
108aff8609aSDaniel Baluta 
10920ffac27SDaniel Baluta #define KMX61_CHIP_ID		0x12
11020ffac27SDaniel Baluta 
11120ffac27SDaniel Baluta /* KMX61 devices */
11220ffac27SDaniel Baluta #define KMX61_ACC	0x01
11320ffac27SDaniel Baluta #define KMX61_MAG	0x02
11420ffac27SDaniel Baluta 
11520ffac27SDaniel Baluta struct kmx61_data {
11620ffac27SDaniel Baluta 	struct i2c_client *client;
11720ffac27SDaniel Baluta 
11820ffac27SDaniel Baluta 	/* serialize access to non-atomic ops, e.g set_mode */
11920ffac27SDaniel Baluta 	struct mutex lock;
12020ffac27SDaniel Baluta 
12120ffac27SDaniel Baluta 	/* standby state */
12220ffac27SDaniel Baluta 	bool acc_stby;
12320ffac27SDaniel Baluta 	bool mag_stby;
12420ffac27SDaniel Baluta 
125aff8609aSDaniel Baluta 	/* power state */
126aff8609aSDaniel Baluta 	bool acc_ps;
127aff8609aSDaniel Baluta 	bool mag_ps;
128aff8609aSDaniel Baluta 
12920ffac27SDaniel Baluta 	/* config bits */
13020ffac27SDaniel Baluta 	u8 range;
13120ffac27SDaniel Baluta 	u8 odr_bits;
132fd3ae7a9SDaniel Baluta 	u8 wake_thresh;
133fd3ae7a9SDaniel Baluta 	u8 wake_duration;
13420ffac27SDaniel Baluta 
13520ffac27SDaniel Baluta 	/* accelerometer specific data */
13620ffac27SDaniel Baluta 	struct iio_dev *acc_indio_dev;
137c3a23eccSDaniel Baluta 	struct iio_trigger *acc_dready_trig;
138fd3ae7a9SDaniel Baluta 	struct iio_trigger *motion_trig;
139c3a23eccSDaniel Baluta 	bool acc_dready_trig_on;
140fd3ae7a9SDaniel Baluta 	bool motion_trig_on;
141fd3ae7a9SDaniel Baluta 	bool ev_enable_state;
14220ffac27SDaniel Baluta 
14320ffac27SDaniel Baluta 	/* magnetometer specific data */
14420ffac27SDaniel Baluta 	struct iio_dev *mag_indio_dev;
145c3a23eccSDaniel Baluta 	struct iio_trigger *mag_dready_trig;
146c3a23eccSDaniel Baluta 	bool mag_dready_trig_on;
14720ffac27SDaniel Baluta };
14820ffac27SDaniel Baluta 
14920ffac27SDaniel Baluta enum kmx61_range {
15020ffac27SDaniel Baluta 	KMX61_RANGE_2G,
15120ffac27SDaniel Baluta 	KMX61_RANGE_4G,
15220ffac27SDaniel Baluta 	KMX61_RANGE_8G,
15320ffac27SDaniel Baluta };
15420ffac27SDaniel Baluta 
15520ffac27SDaniel Baluta enum kmx61_axis {
15620ffac27SDaniel Baluta 	KMX61_AXIS_X,
15720ffac27SDaniel Baluta 	KMX61_AXIS_Y,
15820ffac27SDaniel Baluta 	KMX61_AXIS_Z,
15920ffac27SDaniel Baluta };
16020ffac27SDaniel Baluta 
16120ffac27SDaniel Baluta static const u16 kmx61_uscale_table[] = {9582, 19163, 38326};
16220ffac27SDaniel Baluta 
16320ffac27SDaniel Baluta static const struct {
16420ffac27SDaniel Baluta 	int val;
16520ffac27SDaniel Baluta 	int val2;
166a36385a2SDaniel Baluta } kmx61_samp_freq_table[] = { {12, 500000},
167a36385a2SDaniel Baluta 			{25, 0},
168a36385a2SDaniel Baluta 			{50, 0},
169a36385a2SDaniel Baluta 			{100, 0},
170a36385a2SDaniel Baluta 			{200, 0},
171a36385a2SDaniel Baluta 			{400, 0},
172a36385a2SDaniel Baluta 			{800, 0},
173a36385a2SDaniel Baluta 			{1600, 0},
174a36385a2SDaniel Baluta 			{0, 781000},
175a36385a2SDaniel Baluta 			{1, 563000},
176a36385a2SDaniel Baluta 			{3, 125000},
177a36385a2SDaniel Baluta 			{6, 250000} };
17820ffac27SDaniel Baluta 
179fd3ae7a9SDaniel Baluta static const struct {
180fd3ae7a9SDaniel Baluta 	int val;
181fd3ae7a9SDaniel Baluta 	int val2;
182fd3ae7a9SDaniel Baluta 	int odr_bits;
183fd3ae7a9SDaniel Baluta } kmx61_wake_up_odr_table[] = { {0, 781000, 0x00},
184fd3ae7a9SDaniel Baluta 				 {1, 563000, 0x01},
185fd3ae7a9SDaniel Baluta 				 {3, 125000, 0x02},
186fd3ae7a9SDaniel Baluta 				 {6, 250000, 0x03},
187fd3ae7a9SDaniel Baluta 				 {12, 500000, 0x04},
188fd3ae7a9SDaniel Baluta 				 {25, 0, 0x05},
189fd3ae7a9SDaniel Baluta 				 {50, 0, 0x06},
190fd3ae7a9SDaniel Baluta 				 {100, 0, 0x06},
191fd3ae7a9SDaniel Baluta 				 {200, 0, 0x06},
192fd3ae7a9SDaniel Baluta 				 {400, 0, 0x06},
193fd3ae7a9SDaniel Baluta 				 {800, 0, 0x06},
194fd3ae7a9SDaniel Baluta 				 {1600, 0, 0x06} };
195fd3ae7a9SDaniel Baluta 
19620ffac27SDaniel Baluta static IIO_CONST_ATTR(accel_scale_available, "0.009582 0.019163 0.038326");
19720ffac27SDaniel Baluta static IIO_CONST_ATTR(magn_scale_available, "0.001465");
19820ffac27SDaniel Baluta static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
19920ffac27SDaniel Baluta 	"0.781000 1.563000 3.125000 6.250000 12.500000 25 50 100 200 400 800");
20020ffac27SDaniel Baluta 
20120ffac27SDaniel Baluta static struct attribute *kmx61_acc_attributes[] = {
20220ffac27SDaniel Baluta 	&iio_const_attr_accel_scale_available.dev_attr.attr,
20320ffac27SDaniel Baluta 	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
20420ffac27SDaniel Baluta 	NULL,
20520ffac27SDaniel Baluta };
20620ffac27SDaniel Baluta 
20720ffac27SDaniel Baluta static struct attribute *kmx61_mag_attributes[] = {
20820ffac27SDaniel Baluta 	&iio_const_attr_magn_scale_available.dev_attr.attr,
20920ffac27SDaniel Baluta 	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
21020ffac27SDaniel Baluta 	NULL,
21120ffac27SDaniel Baluta };
21220ffac27SDaniel Baluta 
21320ffac27SDaniel Baluta static const struct attribute_group kmx61_acc_attribute_group = {
21420ffac27SDaniel Baluta 	.attrs = kmx61_acc_attributes,
21520ffac27SDaniel Baluta };
21620ffac27SDaniel Baluta 
21720ffac27SDaniel Baluta static const struct attribute_group kmx61_mag_attribute_group = {
21820ffac27SDaniel Baluta 	.attrs = kmx61_mag_attributes,
21920ffac27SDaniel Baluta };
22020ffac27SDaniel Baluta 
221fd3ae7a9SDaniel Baluta static const struct iio_event_spec kmx61_event = {
222fd3ae7a9SDaniel Baluta 	.type = IIO_EV_TYPE_THRESH,
223fd3ae7a9SDaniel Baluta 	.dir = IIO_EV_DIR_EITHER,
224fd3ae7a9SDaniel Baluta 	.mask_separate = BIT(IIO_EV_INFO_VALUE) |
225fd3ae7a9SDaniel Baluta 			 BIT(IIO_EV_INFO_ENABLE) |
226fd3ae7a9SDaniel Baluta 			 BIT(IIO_EV_INFO_PERIOD),
227fd3ae7a9SDaniel Baluta };
228fd3ae7a9SDaniel Baluta 
22920ffac27SDaniel Baluta #define KMX61_ACC_CHAN(_axis) { \
23020ffac27SDaniel Baluta 	.type = IIO_ACCEL, \
23120ffac27SDaniel Baluta 	.modified = 1, \
23220ffac27SDaniel Baluta 	.channel2 = IIO_MOD_ ## _axis, \
23320ffac27SDaniel Baluta 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
23420ffac27SDaniel Baluta 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
23520ffac27SDaniel Baluta 				BIT(IIO_CHAN_INFO_SAMP_FREQ), \
23620ffac27SDaniel Baluta 	.address = KMX61_ACC, \
23720ffac27SDaniel Baluta 	.scan_index = KMX61_AXIS_ ## _axis, \
23820ffac27SDaniel Baluta 	.scan_type = { \
23920ffac27SDaniel Baluta 		.sign = 's', \
24020ffac27SDaniel Baluta 		.realbits = 12, \
24120ffac27SDaniel Baluta 		.storagebits = 16, \
24220ffac27SDaniel Baluta 		.shift = 4, \
24320ffac27SDaniel Baluta 		.endianness = IIO_LE, \
24420ffac27SDaniel Baluta 	}, \
245fd3ae7a9SDaniel Baluta 	.event_spec = &kmx61_event, \
246fd3ae7a9SDaniel Baluta 	.num_event_specs = 1 \
24720ffac27SDaniel Baluta }
24820ffac27SDaniel Baluta 
24920ffac27SDaniel Baluta #define KMX61_MAG_CHAN(_axis) { \
25020ffac27SDaniel Baluta 	.type = IIO_MAGN, \
25120ffac27SDaniel Baluta 	.modified = 1, \
25220ffac27SDaniel Baluta 	.channel2 = IIO_MOD_ ## _axis, \
25320ffac27SDaniel Baluta 	.address = KMX61_MAG, \
25420ffac27SDaniel Baluta 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
25520ffac27SDaniel Baluta 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
25620ffac27SDaniel Baluta 				BIT(IIO_CHAN_INFO_SAMP_FREQ), \
25720ffac27SDaniel Baluta 	.scan_index = KMX61_AXIS_ ## _axis, \
25820ffac27SDaniel Baluta 	.scan_type = { \
25920ffac27SDaniel Baluta 		.sign = 's', \
26020ffac27SDaniel Baluta 		.realbits = 14, \
26120ffac27SDaniel Baluta 		.storagebits = 16, \
26220ffac27SDaniel Baluta 		.shift = 2, \
26320ffac27SDaniel Baluta 		.endianness = IIO_LE, \
26420ffac27SDaniel Baluta 	}, \
26520ffac27SDaniel Baluta }
26620ffac27SDaniel Baluta 
26720ffac27SDaniel Baluta static const struct iio_chan_spec kmx61_acc_channels[] = {
26820ffac27SDaniel Baluta 	KMX61_ACC_CHAN(X),
26920ffac27SDaniel Baluta 	KMX61_ACC_CHAN(Y),
27020ffac27SDaniel Baluta 	KMX61_ACC_CHAN(Z),
27120ffac27SDaniel Baluta };
27220ffac27SDaniel Baluta 
27320ffac27SDaniel Baluta static const struct iio_chan_spec kmx61_mag_channels[] = {
27420ffac27SDaniel Baluta 	KMX61_MAG_CHAN(X),
27520ffac27SDaniel Baluta 	KMX61_MAG_CHAN(Y),
27620ffac27SDaniel Baluta 	KMX61_MAG_CHAN(Z),
27720ffac27SDaniel Baluta };
27820ffac27SDaniel Baluta 
kmx61_set_data(struct iio_dev * indio_dev,struct kmx61_data * data)27920ffac27SDaniel Baluta static void kmx61_set_data(struct iio_dev *indio_dev, struct kmx61_data *data)
28020ffac27SDaniel Baluta {
28120ffac27SDaniel Baluta 	struct kmx61_data **priv = iio_priv(indio_dev);
28220ffac27SDaniel Baluta 
28320ffac27SDaniel Baluta 	*priv = data;
28420ffac27SDaniel Baluta }
28520ffac27SDaniel Baluta 
kmx61_get_data(struct iio_dev * indio_dev)28620ffac27SDaniel Baluta static struct kmx61_data *kmx61_get_data(struct iio_dev *indio_dev)
28720ffac27SDaniel Baluta {
28820ffac27SDaniel Baluta 	return *(struct kmx61_data **)iio_priv(indio_dev);
28920ffac27SDaniel Baluta }
29020ffac27SDaniel Baluta 
kmx61_convert_freq_to_bit(int val,int val2)29120ffac27SDaniel Baluta static int kmx61_convert_freq_to_bit(int val, int val2)
29220ffac27SDaniel Baluta {
29320ffac27SDaniel Baluta 	int i;
29420ffac27SDaniel Baluta 
29520ffac27SDaniel Baluta 	for (i = 0; i < ARRAY_SIZE(kmx61_samp_freq_table); i++)
29620ffac27SDaniel Baluta 		if (val == kmx61_samp_freq_table[i].val &&
29720ffac27SDaniel Baluta 		    val2 == kmx61_samp_freq_table[i].val2)
298a36385a2SDaniel Baluta 			return i;
29920ffac27SDaniel Baluta 	return -EINVAL;
30020ffac27SDaniel Baluta }
30120ffac27SDaniel Baluta 
kmx61_convert_wake_up_odr_to_bit(int val,int val2)302fd3ae7a9SDaniel Baluta static int kmx61_convert_wake_up_odr_to_bit(int val, int val2)
303fd3ae7a9SDaniel Baluta {
304fd3ae7a9SDaniel Baluta 	int i;
305fd3ae7a9SDaniel Baluta 
306fd3ae7a9SDaniel Baluta 	for (i = 0; i < ARRAY_SIZE(kmx61_wake_up_odr_table); ++i)
307fd3ae7a9SDaniel Baluta 		if (kmx61_wake_up_odr_table[i].val == val &&
308fd3ae7a9SDaniel Baluta 			kmx61_wake_up_odr_table[i].val2 == val2)
309fd3ae7a9SDaniel Baluta 				return kmx61_wake_up_odr_table[i].odr_bits;
310fd3ae7a9SDaniel Baluta 	return -EINVAL;
311fd3ae7a9SDaniel Baluta }
312fd3ae7a9SDaniel Baluta 
31320ffac27SDaniel Baluta /**
31420ffac27SDaniel Baluta  * kmx61_set_mode() - set KMX61 device operating mode
3150d674449SLee Jones  * @data: kmx61 device private data pointer
3160d674449SLee Jones  * @mode: bitmask, indicating operating mode for @device
3170d674449SLee Jones  * @device: bitmask, indicating device for which @mode needs to be set
3180d674449SLee Jones  * @update: update stby bits stored in device's private  @data
31920ffac27SDaniel Baluta  *
32020ffac27SDaniel Baluta  * For each sensor (accelerometer/magnetometer) there are two operating modes
32120ffac27SDaniel Baluta  * STANDBY and OPERATION. Neither accel nor magn can be disabled independently
32220ffac27SDaniel Baluta  * if they are both enabled. Internal sensors state is saved in acc_stby and
32320ffac27SDaniel Baluta  * mag_stby members of driver's private @data.
32420ffac27SDaniel Baluta  */
kmx61_set_mode(struct kmx61_data * data,u8 mode,u8 device,bool update)32520ffac27SDaniel Baluta static int kmx61_set_mode(struct kmx61_data *data, u8 mode, u8 device,
32620ffac27SDaniel Baluta 			  bool update)
32720ffac27SDaniel Baluta {
32820ffac27SDaniel Baluta 	int ret;
32920ffac27SDaniel Baluta 	int acc_stby = -1, mag_stby = -1;
33020ffac27SDaniel Baluta 
33120ffac27SDaniel Baluta 	ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_STBY);
33220ffac27SDaniel Baluta 	if (ret < 0) {
33320ffac27SDaniel Baluta 		dev_err(&data->client->dev, "Error reading reg_stby\n");
33420ffac27SDaniel Baluta 		return ret;
33520ffac27SDaniel Baluta 	}
33620ffac27SDaniel Baluta 	if (device & KMX61_ACC) {
33720ffac27SDaniel Baluta 		if (mode & KMX61_ACC_STBY_BIT) {
33820ffac27SDaniel Baluta 			ret |= KMX61_ACC_STBY_BIT;
33920ffac27SDaniel Baluta 			acc_stby = 1;
34020ffac27SDaniel Baluta 		} else {
34120ffac27SDaniel Baluta 			ret &= ~KMX61_ACC_STBY_BIT;
34220ffac27SDaniel Baluta 			acc_stby = 0;
34320ffac27SDaniel Baluta 		}
34420ffac27SDaniel Baluta 	}
34520ffac27SDaniel Baluta 
34620ffac27SDaniel Baluta 	if (device & KMX61_MAG) {
34720ffac27SDaniel Baluta 		if (mode & KMX61_MAG_STBY_BIT) {
34820ffac27SDaniel Baluta 			ret |= KMX61_MAG_STBY_BIT;
34920ffac27SDaniel Baluta 			mag_stby = 1;
35020ffac27SDaniel Baluta 		} else {
35120ffac27SDaniel Baluta 			ret &= ~KMX61_MAG_STBY_BIT;
35220ffac27SDaniel Baluta 			mag_stby = 0;
35320ffac27SDaniel Baluta 		}
35420ffac27SDaniel Baluta 	}
35520ffac27SDaniel Baluta 
35620ffac27SDaniel Baluta 	if (mode & KMX61_ACT_STBY_BIT)
35720ffac27SDaniel Baluta 		ret |= KMX61_ACT_STBY_BIT;
35820ffac27SDaniel Baluta 
35920ffac27SDaniel Baluta 	ret = i2c_smbus_write_byte_data(data->client, KMX61_REG_STBY, ret);
36020ffac27SDaniel Baluta 	if (ret < 0) {
36120ffac27SDaniel Baluta 		dev_err(&data->client->dev, "Error writing reg_stby\n");
36220ffac27SDaniel Baluta 		return ret;
36320ffac27SDaniel Baluta 	}
36420ffac27SDaniel Baluta 
36520ffac27SDaniel Baluta 	if (acc_stby != -1 && update)
36620ffac27SDaniel Baluta 		data->acc_stby = acc_stby;
36720ffac27SDaniel Baluta 	if (mag_stby != -1 && update)
36820ffac27SDaniel Baluta 		data->mag_stby = mag_stby;
36920ffac27SDaniel Baluta 
37020ffac27SDaniel Baluta 	return 0;
37120ffac27SDaniel Baluta }
37220ffac27SDaniel Baluta 
kmx61_get_mode(struct kmx61_data * data,u8 * mode,u8 device)37320ffac27SDaniel Baluta static int kmx61_get_mode(struct kmx61_data *data, u8 *mode, u8 device)
37420ffac27SDaniel Baluta {
37520ffac27SDaniel Baluta 	int ret;
37620ffac27SDaniel Baluta 
37720ffac27SDaniel Baluta 	ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_STBY);
37820ffac27SDaniel Baluta 	if (ret < 0) {
37920ffac27SDaniel Baluta 		dev_err(&data->client->dev, "Error reading reg_stby\n");
38020ffac27SDaniel Baluta 		return ret;
38120ffac27SDaniel Baluta 	}
38220ffac27SDaniel Baluta 	*mode = 0;
38320ffac27SDaniel Baluta 
38420ffac27SDaniel Baluta 	if (device & KMX61_ACC) {
38520ffac27SDaniel Baluta 		if (ret & KMX61_ACC_STBY_BIT)
38620ffac27SDaniel Baluta 			*mode |= KMX61_ACC_STBY_BIT;
38720ffac27SDaniel Baluta 		else
38820ffac27SDaniel Baluta 			*mode &= ~KMX61_ACC_STBY_BIT;
38920ffac27SDaniel Baluta 	}
39020ffac27SDaniel Baluta 
39120ffac27SDaniel Baluta 	if (device & KMX61_MAG) {
39220ffac27SDaniel Baluta 		if (ret & KMX61_MAG_STBY_BIT)
39320ffac27SDaniel Baluta 			*mode |= KMX61_MAG_STBY_BIT;
39420ffac27SDaniel Baluta 		else
39520ffac27SDaniel Baluta 			*mode &= ~KMX61_MAG_STBY_BIT;
39620ffac27SDaniel Baluta 	}
39720ffac27SDaniel Baluta 
39820ffac27SDaniel Baluta 	return 0;
39920ffac27SDaniel Baluta }
40020ffac27SDaniel Baluta 
kmx61_set_wake_up_odr(struct kmx61_data * data,int val,int val2)401ebd16366Skbuild test robot static int kmx61_set_wake_up_odr(struct kmx61_data *data, int val, int val2)
402fd3ae7a9SDaniel Baluta {
403fd3ae7a9SDaniel Baluta 	int ret, odr_bits;
404fd3ae7a9SDaniel Baluta 
405fd3ae7a9SDaniel Baluta 	odr_bits = kmx61_convert_wake_up_odr_to_bit(val, val2);
406fd3ae7a9SDaniel Baluta 	if (odr_bits < 0)
407fd3ae7a9SDaniel Baluta 		return odr_bits;
408fd3ae7a9SDaniel Baluta 
409fd3ae7a9SDaniel Baluta 	ret = i2c_smbus_write_byte_data(data->client, KMX61_REG_CTRL2,
410fd3ae7a9SDaniel Baluta 					odr_bits);
411fd3ae7a9SDaniel Baluta 	if (ret < 0)
412fd3ae7a9SDaniel Baluta 		dev_err(&data->client->dev, "Error writing reg_ctrl2\n");
413fd3ae7a9SDaniel Baluta 	return ret;
414fd3ae7a9SDaniel Baluta }
415fd3ae7a9SDaniel Baluta 
kmx61_set_odr(struct kmx61_data * data,int val,int val2,u8 device)41620ffac27SDaniel Baluta static int kmx61_set_odr(struct kmx61_data *data, int val, int val2, u8 device)
41720ffac27SDaniel Baluta {
41820ffac27SDaniel Baluta 	int ret;
41920ffac27SDaniel Baluta 	u8 mode;
42020ffac27SDaniel Baluta 	int lodr_bits, odr_bits;
42120ffac27SDaniel Baluta 
42220ffac27SDaniel Baluta 	ret = kmx61_get_mode(data, &mode, KMX61_ACC | KMX61_MAG);
42320ffac27SDaniel Baluta 	if (ret < 0)
42420ffac27SDaniel Baluta 		return ret;
42520ffac27SDaniel Baluta 
42620ffac27SDaniel Baluta 	lodr_bits = kmx61_convert_freq_to_bit(val, val2);
42720ffac27SDaniel Baluta 	if (lodr_bits < 0)
42820ffac27SDaniel Baluta 		return lodr_bits;
42920ffac27SDaniel Baluta 
43020ffac27SDaniel Baluta 	/* To change ODR, accel and magn must be in STDBY */
43120ffac27SDaniel Baluta 	ret = kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG,
43220ffac27SDaniel Baluta 			     true);
43320ffac27SDaniel Baluta 	if (ret < 0)
43420ffac27SDaniel Baluta 		return ret;
43520ffac27SDaniel Baluta 
43620ffac27SDaniel Baluta 	odr_bits = 0;
43720ffac27SDaniel Baluta 	if (device & KMX61_ACC)
43820ffac27SDaniel Baluta 		odr_bits |= lodr_bits << KMX61_ACC_ODR_SHIFT;
43920ffac27SDaniel Baluta 	if (device & KMX61_MAG)
44020ffac27SDaniel Baluta 		odr_bits |= lodr_bits << KMX61_MAG_ODR_SHIFT;
44120ffac27SDaniel Baluta 
44220ffac27SDaniel Baluta 	ret = i2c_smbus_write_byte_data(data->client, KMX61_REG_ODCNTL,
44320ffac27SDaniel Baluta 					odr_bits);
44420ffac27SDaniel Baluta 	if (ret < 0)
44520ffac27SDaniel Baluta 		return ret;
44620ffac27SDaniel Baluta 
4474e843977SDaniel Baluta 	data->odr_bits = odr_bits;
4484e843977SDaniel Baluta 
449fd3ae7a9SDaniel Baluta 	if (device & KMX61_ACC) {
450fd3ae7a9SDaniel Baluta 		ret = kmx61_set_wake_up_odr(data, val, val2);
451fd3ae7a9SDaniel Baluta 		if (ret)
452fd3ae7a9SDaniel Baluta 			return ret;
453fd3ae7a9SDaniel Baluta 	}
454fd3ae7a9SDaniel Baluta 
45520ffac27SDaniel Baluta 	return kmx61_set_mode(data, mode, KMX61_ACC | KMX61_MAG, true);
45620ffac27SDaniel Baluta }
45720ffac27SDaniel Baluta 
kmx61_get_odr(struct kmx61_data * data,int * val,int * val2,u8 device)45820ffac27SDaniel Baluta static int kmx61_get_odr(struct kmx61_data *data, int *val, int *val2,
45920ffac27SDaniel Baluta 			 u8 device)
460a36385a2SDaniel Baluta {
46120ffac27SDaniel Baluta 	u8 lodr_bits;
46220ffac27SDaniel Baluta 
46320ffac27SDaniel Baluta 	if (device & KMX61_ACC)
46420ffac27SDaniel Baluta 		lodr_bits = (data->odr_bits >> KMX61_ACC_ODR_SHIFT) &
46520ffac27SDaniel Baluta 			     KMX61_ACC_ODR_MASK;
46620ffac27SDaniel Baluta 	else if (device & KMX61_MAG)
46720ffac27SDaniel Baluta 		lodr_bits = (data->odr_bits >> KMX61_MAG_ODR_SHIFT) &
46820ffac27SDaniel Baluta 			     KMX61_MAG_ODR_MASK;
46920ffac27SDaniel Baluta 	else
47020ffac27SDaniel Baluta 		return -EINVAL;
47120ffac27SDaniel Baluta 
472a36385a2SDaniel Baluta 	if (lodr_bits >= ARRAY_SIZE(kmx61_samp_freq_table))
47320ffac27SDaniel Baluta 		return -EINVAL;
474a36385a2SDaniel Baluta 
475a36385a2SDaniel Baluta 	*val = kmx61_samp_freq_table[lodr_bits].val;
476a36385a2SDaniel Baluta 	*val2 = kmx61_samp_freq_table[lodr_bits].val2;
477a36385a2SDaniel Baluta 
478a36385a2SDaniel Baluta 	return 0;
47920ffac27SDaniel Baluta }
48020ffac27SDaniel Baluta 
kmx61_set_range(struct kmx61_data * data,u8 range)48120ffac27SDaniel Baluta static int kmx61_set_range(struct kmx61_data *data, u8 range)
48220ffac27SDaniel Baluta {
48320ffac27SDaniel Baluta 	int ret;
48420ffac27SDaniel Baluta 
48520ffac27SDaniel Baluta 	ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_CTRL1);
48620ffac27SDaniel Baluta 	if (ret < 0) {
48720ffac27SDaniel Baluta 		dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
48820ffac27SDaniel Baluta 		return ret;
48920ffac27SDaniel Baluta 	}
49020ffac27SDaniel Baluta 
49120ffac27SDaniel Baluta 	ret &= ~KMX61_REG_CTRL1_GSEL_MASK;
49220ffac27SDaniel Baluta 	ret |= range & KMX61_REG_CTRL1_GSEL_MASK;
49320ffac27SDaniel Baluta 
49420ffac27SDaniel Baluta 	ret = i2c_smbus_write_byte_data(data->client, KMX61_REG_CTRL1, ret);
49520ffac27SDaniel Baluta 	if (ret < 0) {
49620ffac27SDaniel Baluta 		dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
49720ffac27SDaniel Baluta 		return ret;
49820ffac27SDaniel Baluta 	}
49920ffac27SDaniel Baluta 
50020ffac27SDaniel Baluta 	data->range = range;
50120ffac27SDaniel Baluta 
50220ffac27SDaniel Baluta 	return 0;
50320ffac27SDaniel Baluta }
50420ffac27SDaniel Baluta 
kmx61_set_scale(struct kmx61_data * data,u16 uscale)50520ffac27SDaniel Baluta static int kmx61_set_scale(struct kmx61_data *data, u16 uscale)
50620ffac27SDaniel Baluta {
50720ffac27SDaniel Baluta 	int ret, i;
50820ffac27SDaniel Baluta 	u8  mode;
50920ffac27SDaniel Baluta 
51020ffac27SDaniel Baluta 	for (i = 0; i < ARRAY_SIZE(kmx61_uscale_table); i++) {
51120ffac27SDaniel Baluta 		if (kmx61_uscale_table[i] == uscale) {
51220ffac27SDaniel Baluta 			ret = kmx61_get_mode(data, &mode,
51320ffac27SDaniel Baluta 					     KMX61_ACC | KMX61_MAG);
51420ffac27SDaniel Baluta 			if (ret < 0)
51520ffac27SDaniel Baluta 				return ret;
51620ffac27SDaniel Baluta 
51720ffac27SDaniel Baluta 			ret = kmx61_set_mode(data, KMX61_ALL_STBY,
51820ffac27SDaniel Baluta 					     KMX61_ACC | KMX61_MAG, true);
51920ffac27SDaniel Baluta 			if (ret < 0)
52020ffac27SDaniel Baluta 				return ret;
52120ffac27SDaniel Baluta 
52220ffac27SDaniel Baluta 			ret = kmx61_set_range(data, i);
52320ffac27SDaniel Baluta 			if (ret < 0)
52420ffac27SDaniel Baluta 				return ret;
52520ffac27SDaniel Baluta 
52620ffac27SDaniel Baluta 			return  kmx61_set_mode(data, mode,
52720ffac27SDaniel Baluta 					       KMX61_ACC | KMX61_MAG, true);
52820ffac27SDaniel Baluta 		}
52920ffac27SDaniel Baluta 	}
53020ffac27SDaniel Baluta 	return -EINVAL;
53120ffac27SDaniel Baluta }
53220ffac27SDaniel Baluta 
kmx61_chip_init(struct kmx61_data * data)53320ffac27SDaniel Baluta static int kmx61_chip_init(struct kmx61_data *data)
53420ffac27SDaniel Baluta {
535fd3ae7a9SDaniel Baluta 	int ret, val, val2;
53620ffac27SDaniel Baluta 
53720ffac27SDaniel Baluta 	ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_WHO_AM_I);
53820ffac27SDaniel Baluta 	if (ret < 0) {
53920ffac27SDaniel Baluta 		dev_err(&data->client->dev, "Error reading who_am_i\n");
54020ffac27SDaniel Baluta 		return ret;
54120ffac27SDaniel Baluta 	}
54220ffac27SDaniel Baluta 
54320ffac27SDaniel Baluta 	if (ret != KMX61_CHIP_ID) {
54420ffac27SDaniel Baluta 		dev_err(&data->client->dev,
54520ffac27SDaniel Baluta 			"Wrong chip id, got %x expected %x\n",
54620ffac27SDaniel Baluta 			 ret, KMX61_CHIP_ID);
54720ffac27SDaniel Baluta 		return -EINVAL;
54820ffac27SDaniel Baluta 	}
54920ffac27SDaniel Baluta 
55020ffac27SDaniel Baluta 	/* set accel 12bit, 4g range */
55120ffac27SDaniel Baluta 	ret = kmx61_set_range(data, KMX61_RANGE_4G);
55220ffac27SDaniel Baluta 	if (ret < 0)
55320ffac27SDaniel Baluta 		return ret;
55420ffac27SDaniel Baluta 
55520ffac27SDaniel Baluta 	ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_ODCNTL);
55620ffac27SDaniel Baluta 	if (ret < 0) {
55720ffac27SDaniel Baluta 		dev_err(&data->client->dev, "Error reading reg_odcntl\n");
55820ffac27SDaniel Baluta 		return ret;
55920ffac27SDaniel Baluta 	}
56020ffac27SDaniel Baluta 	data->odr_bits = ret;
56120ffac27SDaniel Baluta 
562a36385a2SDaniel Baluta 	/*
563a36385a2SDaniel Baluta 	 * set output data rate for wake up (motion detection) function
564a36385a2SDaniel Baluta 	 * to match data rate for accelerometer sampling
565a36385a2SDaniel Baluta 	 */
566a36385a2SDaniel Baluta 	ret = kmx61_get_odr(data, &val, &val2, KMX61_ACC);
567fd3ae7a9SDaniel Baluta 	if (ret < 0)
568fd3ae7a9SDaniel Baluta 		return ret;
569fd3ae7a9SDaniel Baluta 
570fd3ae7a9SDaniel Baluta 	ret = kmx61_set_wake_up_odr(data, val, val2);
571fd3ae7a9SDaniel Baluta 	if (ret < 0)
572fd3ae7a9SDaniel Baluta 		return ret;
573fd3ae7a9SDaniel Baluta 
57420ffac27SDaniel Baluta 	/* set acc/magn to OPERATION mode */
57520ffac27SDaniel Baluta 	ret = kmx61_set_mode(data, 0, KMX61_ACC | KMX61_MAG, true);
57620ffac27SDaniel Baluta 	if (ret < 0)
57720ffac27SDaniel Baluta 		return ret;
57820ffac27SDaniel Baluta 
579fd3ae7a9SDaniel Baluta 	data->wake_thresh = KMX61_DEFAULT_WAKE_THRESH;
580fd3ae7a9SDaniel Baluta 	data->wake_duration = KMX61_DEFAULT_WAKE_DURATION;
581fd3ae7a9SDaniel Baluta 
58220ffac27SDaniel Baluta 	return 0;
58320ffac27SDaniel Baluta }
58420ffac27SDaniel Baluta 
kmx61_setup_new_data_interrupt(struct kmx61_data * data,bool status,u8 device)585c3a23eccSDaniel Baluta static int kmx61_setup_new_data_interrupt(struct kmx61_data *data,
586c3a23eccSDaniel Baluta 					  bool status, u8 device)
587c3a23eccSDaniel Baluta {
588c3a23eccSDaniel Baluta 	u8 mode;
589c3a23eccSDaniel Baluta 	int ret;
590c3a23eccSDaniel Baluta 
591c3a23eccSDaniel Baluta 	ret = kmx61_get_mode(data, &mode, KMX61_ACC | KMX61_MAG);
592c3a23eccSDaniel Baluta 	if (ret < 0)
593c3a23eccSDaniel Baluta 		return ret;
594c3a23eccSDaniel Baluta 
595c3a23eccSDaniel Baluta 	ret = kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, true);
596c3a23eccSDaniel Baluta 	if (ret < 0)
597c3a23eccSDaniel Baluta 		return ret;
598c3a23eccSDaniel Baluta 
599c3a23eccSDaniel Baluta 	ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_INC1);
600c3a23eccSDaniel Baluta 	if (ret < 0) {
601c3a23eccSDaniel Baluta 		dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
602c3a23eccSDaniel Baluta 		return ret;
603c3a23eccSDaniel Baluta 	}
604c3a23eccSDaniel Baluta 
605c3a23eccSDaniel Baluta 	if (status) {
606c3a23eccSDaniel Baluta 		ret |= KMX61_REG_INC1_BIT_IEN;
607c3a23eccSDaniel Baluta 		if (device & KMX61_ACC)
608c3a23eccSDaniel Baluta 			ret |= KMX61_REG_INC1_BIT_DRDYA;
609c3a23eccSDaniel Baluta 		if (device & KMX61_MAG)
610c3a23eccSDaniel Baluta 			ret |=  KMX61_REG_INC1_BIT_DRDYM;
611c3a23eccSDaniel Baluta 	} else {
612c3a23eccSDaniel Baluta 		ret &= ~KMX61_REG_INC1_BIT_IEN;
613c3a23eccSDaniel Baluta 		if (device & KMX61_ACC)
614c3a23eccSDaniel Baluta 			ret &= ~KMX61_REG_INC1_BIT_DRDYA;
615c3a23eccSDaniel Baluta 		if (device & KMX61_MAG)
616c3a23eccSDaniel Baluta 			ret &= ~KMX61_REG_INC1_BIT_DRDYM;
617c3a23eccSDaniel Baluta 	}
618c3a23eccSDaniel Baluta 	ret = i2c_smbus_write_byte_data(data->client, KMX61_REG_INC1, ret);
619c3a23eccSDaniel Baluta 	if (ret < 0) {
620c3a23eccSDaniel Baluta 		dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n");
621c3a23eccSDaniel Baluta 		return ret;
622c3a23eccSDaniel Baluta 	}
623c3a23eccSDaniel Baluta 
624c3a23eccSDaniel Baluta 	ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_CTRL1);
625c3a23eccSDaniel Baluta 	if (ret < 0) {
626c3a23eccSDaniel Baluta 		dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
627c3a23eccSDaniel Baluta 		return ret;
628c3a23eccSDaniel Baluta 	}
629c3a23eccSDaniel Baluta 
630c3a23eccSDaniel Baluta 	if (status)
631c3a23eccSDaniel Baluta 		ret |= KMX61_REG_CTRL1_BIT_DRDYE;
632c3a23eccSDaniel Baluta 	else
633c3a23eccSDaniel Baluta 		ret &= ~KMX61_REG_CTRL1_BIT_DRDYE;
634c3a23eccSDaniel Baluta 
635c3a23eccSDaniel Baluta 	ret = i2c_smbus_write_byte_data(data->client, KMX61_REG_CTRL1, ret);
636c3a23eccSDaniel Baluta 	if (ret < 0) {
637c3a23eccSDaniel Baluta 		dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
638c3a23eccSDaniel Baluta 		return ret;
639c3a23eccSDaniel Baluta 	}
640c3a23eccSDaniel Baluta 
64128ff344eSDaniel Baluta 	return kmx61_set_mode(data, mode, KMX61_ACC | KMX61_MAG, true);
642c3a23eccSDaniel Baluta }
643c3a23eccSDaniel Baluta 
kmx61_chip_update_thresholds(struct kmx61_data * data)644fd3ae7a9SDaniel Baluta static int kmx61_chip_update_thresholds(struct kmx61_data *data)
645fd3ae7a9SDaniel Baluta {
646fd3ae7a9SDaniel Baluta 	int ret;
647fd3ae7a9SDaniel Baluta 
648fd3ae7a9SDaniel Baluta 	ret = i2c_smbus_write_byte_data(data->client,
649fd3ae7a9SDaniel Baluta 					KMX61_REG_WUF_TIMER,
650fd3ae7a9SDaniel Baluta 					data->wake_duration);
651fd3ae7a9SDaniel Baluta 	if (ret < 0) {
6525d1c74b1SColin Ian King 		dev_err(&data->client->dev, "Error writing reg_wuf_timer\n");
653fd3ae7a9SDaniel Baluta 		return ret;
654fd3ae7a9SDaniel Baluta 	}
655fd3ae7a9SDaniel Baluta 
656fd3ae7a9SDaniel Baluta 	ret = i2c_smbus_write_byte_data(data->client,
657fd3ae7a9SDaniel Baluta 					KMX61_REG_WUF_THRESH,
658fd3ae7a9SDaniel Baluta 					data->wake_thresh);
65928ff344eSDaniel Baluta 	if (ret < 0)
660fd3ae7a9SDaniel Baluta 		dev_err(&data->client->dev, "Error writing reg_wuf_thresh\n");
661fd3ae7a9SDaniel Baluta 
66228ff344eSDaniel Baluta 	return ret;
663fd3ae7a9SDaniel Baluta }
664fd3ae7a9SDaniel Baluta 
kmx61_setup_any_motion_interrupt(struct kmx61_data * data,bool status)665fd3ae7a9SDaniel Baluta static int kmx61_setup_any_motion_interrupt(struct kmx61_data *data,
6660475c685SDaniel Baluta 					    bool status)
667fd3ae7a9SDaniel Baluta {
668fd3ae7a9SDaniel Baluta 	u8 mode;
669fd3ae7a9SDaniel Baluta 	int ret;
670fd3ae7a9SDaniel Baluta 
671fd3ae7a9SDaniel Baluta 	ret = kmx61_get_mode(data, &mode, KMX61_ACC | KMX61_MAG);
672fd3ae7a9SDaniel Baluta 	if (ret < 0)
673fd3ae7a9SDaniel Baluta 		return ret;
674fd3ae7a9SDaniel Baluta 
675fd3ae7a9SDaniel Baluta 	ret = kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, true);
676fd3ae7a9SDaniel Baluta 	if (ret < 0)
677fd3ae7a9SDaniel Baluta 		return ret;
678fd3ae7a9SDaniel Baluta 
679fd3ae7a9SDaniel Baluta 	ret = kmx61_chip_update_thresholds(data);
680fd3ae7a9SDaniel Baluta 	if (ret < 0)
681fd3ae7a9SDaniel Baluta 		return ret;
682fd3ae7a9SDaniel Baluta 
683fd3ae7a9SDaniel Baluta 	ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_INC1);
684fd3ae7a9SDaniel Baluta 	if (ret < 0) {
685fd3ae7a9SDaniel Baluta 		dev_err(&data->client->dev, "Error reading reg_inc1\n");
686fd3ae7a9SDaniel Baluta 		return ret;
687fd3ae7a9SDaniel Baluta 	}
688fd3ae7a9SDaniel Baluta 	if (status)
689fd3ae7a9SDaniel Baluta 		ret |= (KMX61_REG_INC1_BIT_IEN | KMX61_REG_INC1_BIT_WUFS);
690fd3ae7a9SDaniel Baluta 	else
691fd3ae7a9SDaniel Baluta 		ret &= ~(KMX61_REG_INC1_BIT_IEN | KMX61_REG_INC1_BIT_WUFS);
692fd3ae7a9SDaniel Baluta 
693fd3ae7a9SDaniel Baluta 	ret = i2c_smbus_write_byte_data(data->client, KMX61_REG_INC1, ret);
694fd3ae7a9SDaniel Baluta 	if (ret < 0) {
695fd3ae7a9SDaniel Baluta 		dev_err(&data->client->dev, "Error writing reg_inc1\n");
696fd3ae7a9SDaniel Baluta 		return ret;
697fd3ae7a9SDaniel Baluta 	}
698fd3ae7a9SDaniel Baluta 
699fd3ae7a9SDaniel Baluta 	ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_CTRL1);
700fd3ae7a9SDaniel Baluta 	if (ret < 0) {
701fd3ae7a9SDaniel Baluta 		dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
702fd3ae7a9SDaniel Baluta 		return ret;
703fd3ae7a9SDaniel Baluta 	}
704fd3ae7a9SDaniel Baluta 
705fd3ae7a9SDaniel Baluta 	if (status)
706fd3ae7a9SDaniel Baluta 		ret |= KMX61_REG_CTRL1_BIT_WUFE | KMX61_REG_CTRL1_BIT_BTSE;
707fd3ae7a9SDaniel Baluta 	else
708fd3ae7a9SDaniel Baluta 		ret &= ~(KMX61_REG_CTRL1_BIT_WUFE | KMX61_REG_CTRL1_BIT_BTSE);
709fd3ae7a9SDaniel Baluta 
710fd3ae7a9SDaniel Baluta 	ret = i2c_smbus_write_byte_data(data->client, KMX61_REG_CTRL1, ret);
711fd3ae7a9SDaniel Baluta 	if (ret < 0) {
712fd3ae7a9SDaniel Baluta 		dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
713fd3ae7a9SDaniel Baluta 		return ret;
714fd3ae7a9SDaniel Baluta 	}
715fd3ae7a9SDaniel Baluta 	mode |= KMX61_ACT_STBY_BIT;
71628ff344eSDaniel Baluta 	return kmx61_set_mode(data, mode, KMX61_ACC | KMX61_MAG, true);
717fd3ae7a9SDaniel Baluta }
718fd3ae7a9SDaniel Baluta 
719aff8609aSDaniel Baluta /**
720aff8609aSDaniel Baluta  * kmx61_set_power_state() - set power state for kmx61 @device
7210d674449SLee Jones  * @data: kmx61 device private pointer
7220d674449SLee Jones  * @on: power state to be set for @device
7230d674449SLee Jones  * @device: bitmask indicating device for which @on state needs to be set
724aff8609aSDaniel Baluta  *
725aff8609aSDaniel Baluta  * Notice that when ACC power state needs to be set to ON and MAG is in
726aff8609aSDaniel Baluta  * OPERATION then we know that kmx61_runtime_resume was already called
727aff8609aSDaniel Baluta  * so we must set ACC OPERATION mode here. The same happens when MAG power
728aff8609aSDaniel Baluta  * state needs to be set to ON and ACC is in OPERATION.
729aff8609aSDaniel Baluta  */
kmx61_set_power_state(struct kmx61_data * data,bool on,u8 device)730aff8609aSDaniel Baluta static int kmx61_set_power_state(struct kmx61_data *data, bool on, u8 device)
731aff8609aSDaniel Baluta {
732df1fad80SDaniel Baluta #ifdef CONFIG_PM
733aff8609aSDaniel Baluta 	int ret;
734aff8609aSDaniel Baluta 
735aff8609aSDaniel Baluta 	if (device & KMX61_ACC) {
736aff8609aSDaniel Baluta 		if (on && !data->acc_ps && !data->mag_stby) {
737aff8609aSDaniel Baluta 			ret = kmx61_set_mode(data, 0, KMX61_ACC, true);
738aff8609aSDaniel Baluta 			if (ret < 0)
739aff8609aSDaniel Baluta 				return ret;
740aff8609aSDaniel Baluta 		}
741aff8609aSDaniel Baluta 		data->acc_ps = on;
742aff8609aSDaniel Baluta 	}
743aff8609aSDaniel Baluta 	if (device & KMX61_MAG) {
744aff8609aSDaniel Baluta 		if (on && !data->mag_ps && !data->acc_stby) {
745aff8609aSDaniel Baluta 			ret = kmx61_set_mode(data, 0, KMX61_MAG, true);
746aff8609aSDaniel Baluta 			if (ret < 0)
747aff8609aSDaniel Baluta 				return ret;
748aff8609aSDaniel Baluta 		}
749aff8609aSDaniel Baluta 		data->mag_ps = on;
750aff8609aSDaniel Baluta 	}
751aff8609aSDaniel Baluta 
752aff8609aSDaniel Baluta 	if (on) {
7532d082b6eSJonathan Cameron 		ret = pm_runtime_resume_and_get(&data->client->dev);
754aff8609aSDaniel Baluta 	} else {
755aff8609aSDaniel Baluta 		pm_runtime_mark_last_busy(&data->client->dev);
756aff8609aSDaniel Baluta 		ret = pm_runtime_put_autosuspend(&data->client->dev);
757aff8609aSDaniel Baluta 	}
758aff8609aSDaniel Baluta 	if (ret < 0) {
759aff8609aSDaniel Baluta 		dev_err(&data->client->dev,
760aff8609aSDaniel Baluta 			"Failed: kmx61_set_power_state for %d, ret %d\n",
761aff8609aSDaniel Baluta 			on, ret);
762aff8609aSDaniel Baluta 
763aff8609aSDaniel Baluta 		return ret;
764aff8609aSDaniel Baluta 	}
765aff8609aSDaniel Baluta #endif
766aff8609aSDaniel Baluta 	return 0;
767aff8609aSDaniel Baluta }
768aff8609aSDaniel Baluta 
kmx61_read_measurement(struct kmx61_data * data,u8 base,u8 offset)76920ffac27SDaniel Baluta static int kmx61_read_measurement(struct kmx61_data *data, u8 base, u8 offset)
77020ffac27SDaniel Baluta {
77120ffac27SDaniel Baluta 	int ret;
77220ffac27SDaniel Baluta 	u8 reg = base + offset * 2;
77320ffac27SDaniel Baluta 
77420ffac27SDaniel Baluta 	ret = i2c_smbus_read_word_data(data->client, reg);
77520ffac27SDaniel Baluta 	if (ret < 0)
77620ffac27SDaniel Baluta 		dev_err(&data->client->dev, "failed to read reg at %x\n", reg);
77720ffac27SDaniel Baluta 
77820ffac27SDaniel Baluta 	return ret;
77920ffac27SDaniel Baluta }
78020ffac27SDaniel Baluta 
kmx61_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)78120ffac27SDaniel Baluta static int kmx61_read_raw(struct iio_dev *indio_dev,
78220ffac27SDaniel Baluta 			  struct iio_chan_spec const *chan, int *val,
78320ffac27SDaniel Baluta 			  int *val2, long mask)
78420ffac27SDaniel Baluta {
78520ffac27SDaniel Baluta 	int ret;
78620ffac27SDaniel Baluta 	u8 base_reg;
78720ffac27SDaniel Baluta 	struct kmx61_data *data = kmx61_get_data(indio_dev);
78820ffac27SDaniel Baluta 
78920ffac27SDaniel Baluta 	switch (mask) {
79020ffac27SDaniel Baluta 	case IIO_CHAN_INFO_RAW:
79120ffac27SDaniel Baluta 		switch (chan->type) {
79220ffac27SDaniel Baluta 		case IIO_ACCEL:
79320ffac27SDaniel Baluta 			base_reg = KMX61_ACC_XOUT_L;
79420ffac27SDaniel Baluta 			break;
79520ffac27SDaniel Baluta 		case IIO_MAGN:
79620ffac27SDaniel Baluta 			base_reg = KMX61_MAG_XOUT_L;
79720ffac27SDaniel Baluta 			break;
79820ffac27SDaniel Baluta 		default:
79920ffac27SDaniel Baluta 			return -EINVAL;
80020ffac27SDaniel Baluta 		}
80120ffac27SDaniel Baluta 		mutex_lock(&data->lock);
80220ffac27SDaniel Baluta 
803a3da4fa3SDaniel Baluta 		ret = kmx61_set_power_state(data, true, chan->address);
804a3da4fa3SDaniel Baluta 		if (ret) {
805a3da4fa3SDaniel Baluta 			mutex_unlock(&data->lock);
806a3da4fa3SDaniel Baluta 			return ret;
807a3da4fa3SDaniel Baluta 		}
808a3da4fa3SDaniel Baluta 
80920ffac27SDaniel Baluta 		ret = kmx61_read_measurement(data, base_reg, chan->scan_index);
81020ffac27SDaniel Baluta 		if (ret < 0) {
811aff8609aSDaniel Baluta 			kmx61_set_power_state(data, false, chan->address);
81220ffac27SDaniel Baluta 			mutex_unlock(&data->lock);
81320ffac27SDaniel Baluta 			return ret;
81420ffac27SDaniel Baluta 		}
81520ffac27SDaniel Baluta 		*val = sign_extend32(ret >> chan->scan_type.shift,
81620ffac27SDaniel Baluta 				     chan->scan_type.realbits - 1);
817a3da4fa3SDaniel Baluta 		ret = kmx61_set_power_state(data, false, chan->address);
81820ffac27SDaniel Baluta 
81920ffac27SDaniel Baluta 		mutex_unlock(&data->lock);
820a3da4fa3SDaniel Baluta 		if (ret)
821a3da4fa3SDaniel Baluta 			return ret;
82220ffac27SDaniel Baluta 		return IIO_VAL_INT;
82320ffac27SDaniel Baluta 	case IIO_CHAN_INFO_SCALE:
82420ffac27SDaniel Baluta 		switch (chan->type) {
82520ffac27SDaniel Baluta 		case IIO_ACCEL:
82620ffac27SDaniel Baluta 			*val = 0;
82720ffac27SDaniel Baluta 			*val2 = kmx61_uscale_table[data->range];
82820ffac27SDaniel Baluta 			return IIO_VAL_INT_PLUS_MICRO;
82920ffac27SDaniel Baluta 		case IIO_MAGN:
83020ffac27SDaniel Baluta 			/* 14 bits res, 1465 microGauss per magn count */
83120ffac27SDaniel Baluta 			*val = 0;
83220ffac27SDaniel Baluta 			*val2 = 1465;
83320ffac27SDaniel Baluta 			return IIO_VAL_INT_PLUS_MICRO;
83420ffac27SDaniel Baluta 		default:
83520ffac27SDaniel Baluta 			return -EINVAL;
83620ffac27SDaniel Baluta 		}
83720ffac27SDaniel Baluta 	case IIO_CHAN_INFO_SAMP_FREQ:
83820ffac27SDaniel Baluta 		if (chan->type != IIO_ACCEL && chan->type != IIO_MAGN)
83920ffac27SDaniel Baluta 			return -EINVAL;
84020ffac27SDaniel Baluta 
84120ffac27SDaniel Baluta 		mutex_lock(&data->lock);
84220ffac27SDaniel Baluta 		ret = kmx61_get_odr(data, val, val2, chan->address);
84320ffac27SDaniel Baluta 		mutex_unlock(&data->lock);
84420ffac27SDaniel Baluta 		if (ret)
84520ffac27SDaniel Baluta 			return -EINVAL;
84620ffac27SDaniel Baluta 		return IIO_VAL_INT_PLUS_MICRO;
84720ffac27SDaniel Baluta 	}
84820ffac27SDaniel Baluta 	return -EINVAL;
84920ffac27SDaniel Baluta }
85020ffac27SDaniel Baluta 
kmx61_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)85120ffac27SDaniel Baluta static int kmx61_write_raw(struct iio_dev *indio_dev,
85220ffac27SDaniel Baluta 			   struct iio_chan_spec const *chan, int val,
85320ffac27SDaniel Baluta 			   int val2, long mask)
85420ffac27SDaniel Baluta {
85520ffac27SDaniel Baluta 	int ret;
85620ffac27SDaniel Baluta 	struct kmx61_data *data = kmx61_get_data(indio_dev);
85720ffac27SDaniel Baluta 
85820ffac27SDaniel Baluta 	switch (mask) {
85920ffac27SDaniel Baluta 	case IIO_CHAN_INFO_SAMP_FREQ:
86020ffac27SDaniel Baluta 		if (chan->type != IIO_ACCEL && chan->type != IIO_MAGN)
86120ffac27SDaniel Baluta 			return -EINVAL;
86220ffac27SDaniel Baluta 
86320ffac27SDaniel Baluta 		mutex_lock(&data->lock);
86420ffac27SDaniel Baluta 		ret = kmx61_set_odr(data, val, val2, chan->address);
86520ffac27SDaniel Baluta 		mutex_unlock(&data->lock);
86620ffac27SDaniel Baluta 		return ret;
86720ffac27SDaniel Baluta 	case IIO_CHAN_INFO_SCALE:
86820ffac27SDaniel Baluta 		switch (chan->type) {
86920ffac27SDaniel Baluta 		case IIO_ACCEL:
87020ffac27SDaniel Baluta 			if (val != 0)
87120ffac27SDaniel Baluta 				return -EINVAL;
87220ffac27SDaniel Baluta 			mutex_lock(&data->lock);
87320ffac27SDaniel Baluta 			ret = kmx61_set_scale(data, val2);
87420ffac27SDaniel Baluta 			mutex_unlock(&data->lock);
87520ffac27SDaniel Baluta 			return ret;
87620ffac27SDaniel Baluta 		default:
87720ffac27SDaniel Baluta 			return -EINVAL;
87820ffac27SDaniel Baluta 		}
87920ffac27SDaniel Baluta 	default:
88020ffac27SDaniel Baluta 		return -EINVAL;
88120ffac27SDaniel Baluta 	}
88220ffac27SDaniel Baluta }
88320ffac27SDaniel Baluta 
kmx61_read_event(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,enum iio_event_type type,enum iio_event_direction dir,enum iio_event_info info,int * val,int * val2)884fd3ae7a9SDaniel Baluta static int kmx61_read_event(struct iio_dev *indio_dev,
885fd3ae7a9SDaniel Baluta 			    const struct iio_chan_spec *chan,
886fd3ae7a9SDaniel Baluta 			    enum iio_event_type type,
887fd3ae7a9SDaniel Baluta 			    enum iio_event_direction dir,
888fd3ae7a9SDaniel Baluta 			    enum iio_event_info info,
889fd3ae7a9SDaniel Baluta 			    int *val, int *val2)
890fd3ae7a9SDaniel Baluta {
891fd3ae7a9SDaniel Baluta 	struct kmx61_data *data = kmx61_get_data(indio_dev);
892fd3ae7a9SDaniel Baluta 
893fd3ae7a9SDaniel Baluta 	*val2 = 0;
894fd3ae7a9SDaniel Baluta 	switch (info) {
895fd3ae7a9SDaniel Baluta 	case IIO_EV_INFO_VALUE:
896fd3ae7a9SDaniel Baluta 		*val = data->wake_thresh;
89728ff344eSDaniel Baluta 		return IIO_VAL_INT;
898fd3ae7a9SDaniel Baluta 	case IIO_EV_INFO_PERIOD:
899fd3ae7a9SDaniel Baluta 		*val = data->wake_duration;
90028ff344eSDaniel Baluta 		return IIO_VAL_INT;
901fd3ae7a9SDaniel Baluta 	default:
902fd3ae7a9SDaniel Baluta 		return -EINVAL;
903fd3ae7a9SDaniel Baluta 	}
904fd3ae7a9SDaniel Baluta }
905fd3ae7a9SDaniel Baluta 
kmx61_write_event(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,enum iio_event_type type,enum iio_event_direction dir,enum iio_event_info info,int val,int val2)906fd3ae7a9SDaniel Baluta static int kmx61_write_event(struct iio_dev *indio_dev,
907fd3ae7a9SDaniel Baluta 			     const struct iio_chan_spec *chan,
908fd3ae7a9SDaniel Baluta 			     enum iio_event_type type,
909fd3ae7a9SDaniel Baluta 			     enum iio_event_direction dir,
910fd3ae7a9SDaniel Baluta 			     enum iio_event_info info,
911fd3ae7a9SDaniel Baluta 			     int val, int val2)
912fd3ae7a9SDaniel Baluta {
913fd3ae7a9SDaniel Baluta 	struct kmx61_data *data = kmx61_get_data(indio_dev);
914fd3ae7a9SDaniel Baluta 
915fd3ae7a9SDaniel Baluta 	if (data->ev_enable_state)
916fd3ae7a9SDaniel Baluta 		return -EBUSY;
917fd3ae7a9SDaniel Baluta 
918fd3ae7a9SDaniel Baluta 	switch (info) {
919fd3ae7a9SDaniel Baluta 	case IIO_EV_INFO_VALUE:
920fd3ae7a9SDaniel Baluta 		data->wake_thresh = val;
92128ff344eSDaniel Baluta 		return IIO_VAL_INT;
922fd3ae7a9SDaniel Baluta 	case IIO_EV_INFO_PERIOD:
923fd3ae7a9SDaniel Baluta 		data->wake_duration = val;
92428ff344eSDaniel Baluta 		return IIO_VAL_INT;
925fd3ae7a9SDaniel Baluta 	default:
926fd3ae7a9SDaniel Baluta 		return -EINVAL;
927fd3ae7a9SDaniel Baluta 	}
928fd3ae7a9SDaniel Baluta }
929fd3ae7a9SDaniel Baluta 
kmx61_read_event_config(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,enum iio_event_type type,enum iio_event_direction dir)930fd3ae7a9SDaniel Baluta static int kmx61_read_event_config(struct iio_dev *indio_dev,
931fd3ae7a9SDaniel Baluta 				   const struct iio_chan_spec *chan,
932fd3ae7a9SDaniel Baluta 				   enum iio_event_type type,
933fd3ae7a9SDaniel Baluta 				   enum iio_event_direction dir)
934fd3ae7a9SDaniel Baluta {
935fd3ae7a9SDaniel Baluta 	struct kmx61_data *data = kmx61_get_data(indio_dev);
936fd3ae7a9SDaniel Baluta 
937fd3ae7a9SDaniel Baluta 	return data->ev_enable_state;
938fd3ae7a9SDaniel Baluta }
939fd3ae7a9SDaniel Baluta 
kmx61_write_event_config(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,enum iio_event_type type,enum iio_event_direction dir,int state)940fd3ae7a9SDaniel Baluta static int kmx61_write_event_config(struct iio_dev *indio_dev,
941fd3ae7a9SDaniel Baluta 				    const struct iio_chan_spec *chan,
942fd3ae7a9SDaniel Baluta 				    enum iio_event_type type,
943fd3ae7a9SDaniel Baluta 				    enum iio_event_direction dir,
944fd3ae7a9SDaniel Baluta 				    int state)
945fd3ae7a9SDaniel Baluta {
946fd3ae7a9SDaniel Baluta 	struct kmx61_data *data = kmx61_get_data(indio_dev);
94728ff344eSDaniel Baluta 	int ret = 0;
948fd3ae7a9SDaniel Baluta 
949fd3ae7a9SDaniel Baluta 	if (state && data->ev_enable_state)
950fd3ae7a9SDaniel Baluta 		return 0;
951fd3ae7a9SDaniel Baluta 
952fd3ae7a9SDaniel Baluta 	mutex_lock(&data->lock);
953fd3ae7a9SDaniel Baluta 
954fd3ae7a9SDaniel Baluta 	if (!state && data->motion_trig_on) {
955d4a4ae04SDaniel Baluta 		data->ev_enable_state = false;
95628ff344eSDaniel Baluta 		goto err_unlock;
957fd3ae7a9SDaniel Baluta 	}
958fd3ae7a9SDaniel Baluta 
959fd3ae7a9SDaniel Baluta 	ret = kmx61_set_power_state(data, state, KMX61_ACC);
96028ff344eSDaniel Baluta 	if (ret < 0)
96128ff344eSDaniel Baluta 		goto err_unlock;
962fd3ae7a9SDaniel Baluta 
9630475c685SDaniel Baluta 	ret = kmx61_setup_any_motion_interrupt(data, state);
964fd3ae7a9SDaniel Baluta 	if (ret < 0) {
965fd3ae7a9SDaniel Baluta 		kmx61_set_power_state(data, false, KMX61_ACC);
96628ff344eSDaniel Baluta 		goto err_unlock;
967fd3ae7a9SDaniel Baluta 	}
968fd3ae7a9SDaniel Baluta 
969fd3ae7a9SDaniel Baluta 	data->ev_enable_state = state;
97028ff344eSDaniel Baluta 
97128ff344eSDaniel Baluta err_unlock:
972fd3ae7a9SDaniel Baluta 	mutex_unlock(&data->lock);
973fd3ae7a9SDaniel Baluta 
97428ff344eSDaniel Baluta 	return ret;
975fd3ae7a9SDaniel Baluta }
976fd3ae7a9SDaniel Baluta 
kmx61_acc_validate_trigger(struct iio_dev * indio_dev,struct iio_trigger * trig)977c3a23eccSDaniel Baluta static int kmx61_acc_validate_trigger(struct iio_dev *indio_dev,
978c3a23eccSDaniel Baluta 				      struct iio_trigger *trig)
979c3a23eccSDaniel Baluta {
980c3a23eccSDaniel Baluta 	struct kmx61_data *data = kmx61_get_data(indio_dev);
981c3a23eccSDaniel Baluta 
982fd3ae7a9SDaniel Baluta 	if (data->acc_dready_trig != trig && data->motion_trig != trig)
983c3a23eccSDaniel Baluta 		return -EINVAL;
984c3a23eccSDaniel Baluta 
985c3a23eccSDaniel Baluta 	return 0;
986c3a23eccSDaniel Baluta }
987c3a23eccSDaniel Baluta 
kmx61_mag_validate_trigger(struct iio_dev * indio_dev,struct iio_trigger * trig)988c3a23eccSDaniel Baluta static int kmx61_mag_validate_trigger(struct iio_dev *indio_dev,
989c3a23eccSDaniel Baluta 				      struct iio_trigger *trig)
990c3a23eccSDaniel Baluta {
991c3a23eccSDaniel Baluta 	struct kmx61_data *data = kmx61_get_data(indio_dev);
992c3a23eccSDaniel Baluta 
993c3a23eccSDaniel Baluta 	if (data->mag_dready_trig != trig)
994c3a23eccSDaniel Baluta 		return -EINVAL;
995c3a23eccSDaniel Baluta 
996c3a23eccSDaniel Baluta 	return 0;
997c3a23eccSDaniel Baluta }
998c3a23eccSDaniel Baluta 
99920ffac27SDaniel Baluta static const struct iio_info kmx61_acc_info = {
100020ffac27SDaniel Baluta 	.read_raw		= kmx61_read_raw,
100120ffac27SDaniel Baluta 	.write_raw		= kmx61_write_raw,
100220ffac27SDaniel Baluta 	.attrs			= &kmx61_acc_attribute_group,
1003fd3ae7a9SDaniel Baluta 	.read_event_value	= kmx61_read_event,
1004fd3ae7a9SDaniel Baluta 	.write_event_value	= kmx61_write_event,
1005fd3ae7a9SDaniel Baluta 	.read_event_config	= kmx61_read_event_config,
1006fd3ae7a9SDaniel Baluta 	.write_event_config	= kmx61_write_event_config,
1007c3a23eccSDaniel Baluta 	.validate_trigger	= kmx61_acc_validate_trigger,
100820ffac27SDaniel Baluta };
100920ffac27SDaniel Baluta 
101020ffac27SDaniel Baluta static const struct iio_info kmx61_mag_info = {
101120ffac27SDaniel Baluta 	.read_raw		= kmx61_read_raw,
101220ffac27SDaniel Baluta 	.write_raw		= kmx61_write_raw,
101320ffac27SDaniel Baluta 	.attrs			= &kmx61_mag_attribute_group,
1014c3a23eccSDaniel Baluta 	.validate_trigger	= kmx61_mag_validate_trigger,
101520ffac27SDaniel Baluta };
101620ffac27SDaniel Baluta 
1017c3a23eccSDaniel Baluta 
kmx61_data_rdy_trigger_set_state(struct iio_trigger * trig,bool state)1018c3a23eccSDaniel Baluta static int kmx61_data_rdy_trigger_set_state(struct iio_trigger *trig,
1019c3a23eccSDaniel Baluta 					    bool state)
1020c3a23eccSDaniel Baluta {
1021c3a23eccSDaniel Baluta 	int ret = 0;
1022c3a23eccSDaniel Baluta 	u8 device;
1023c3a23eccSDaniel Baluta 
1024c3a23eccSDaniel Baluta 	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
1025fd3ae7a9SDaniel Baluta 	struct kmx61_data *data = kmx61_get_data(indio_dev);
1026c3a23eccSDaniel Baluta 
1027c3a23eccSDaniel Baluta 	mutex_lock(&data->lock);
1028c3a23eccSDaniel Baluta 
1029fd3ae7a9SDaniel Baluta 	if (!state && data->ev_enable_state && data->motion_trig_on) {
1030fd3ae7a9SDaniel Baluta 		data->motion_trig_on = false;
103128ff344eSDaniel Baluta 		goto err_unlock;
1032fd3ae7a9SDaniel Baluta 	}
1033fd3ae7a9SDaniel Baluta 
1034dbdd0e2dSDaniel Baluta 	if (data->acc_dready_trig == trig || data->motion_trig == trig)
1035c3a23eccSDaniel Baluta 		device = KMX61_ACC;
1036c3a23eccSDaniel Baluta 	else
1037c3a23eccSDaniel Baluta 		device = KMX61_MAG;
1038c3a23eccSDaniel Baluta 
1039c3a23eccSDaniel Baluta 	ret = kmx61_set_power_state(data, state, device);
104028ff344eSDaniel Baluta 	if (ret < 0)
104128ff344eSDaniel Baluta 		goto err_unlock;
1042c3a23eccSDaniel Baluta 
1043fd3ae7a9SDaniel Baluta 	if (data->acc_dready_trig == trig || data->mag_dready_trig == trig)
1044c3a23eccSDaniel Baluta 		ret = kmx61_setup_new_data_interrupt(data, state, device);
1045fd3ae7a9SDaniel Baluta 	else
10460475c685SDaniel Baluta 		ret = kmx61_setup_any_motion_interrupt(data, state);
1047c3a23eccSDaniel Baluta 	if (ret < 0) {
1048c3a23eccSDaniel Baluta 		kmx61_set_power_state(data, false, device);
104928ff344eSDaniel Baluta 		goto err_unlock;
1050c3a23eccSDaniel Baluta 	}
1051c3a23eccSDaniel Baluta 
1052c3a23eccSDaniel Baluta 	if (data->acc_dready_trig == trig)
1053c3a23eccSDaniel Baluta 		data->acc_dready_trig_on = state;
1054fd3ae7a9SDaniel Baluta 	else if (data->mag_dready_trig == trig)
1055c3a23eccSDaniel Baluta 		data->mag_dready_trig_on = state;
1056fd3ae7a9SDaniel Baluta 	else
1057fd3ae7a9SDaniel Baluta 		data->motion_trig_on = state;
105828ff344eSDaniel Baluta err_unlock:
1059c3a23eccSDaniel Baluta 	mutex_unlock(&data->lock);
1060c3a23eccSDaniel Baluta 
106128ff344eSDaniel Baluta 	return ret;
1062c3a23eccSDaniel Baluta }
1063c3a23eccSDaniel Baluta 
kmx61_trig_reenable(struct iio_trigger * trig)1064eca8523aSJonathan Cameron static void kmx61_trig_reenable(struct iio_trigger *trig)
1065c3a23eccSDaniel Baluta {
1066c3a23eccSDaniel Baluta 	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
1067c3a23eccSDaniel Baluta 	struct kmx61_data *data = kmx61_get_data(indio_dev);
1068c3a23eccSDaniel Baluta 	int ret;
1069c3a23eccSDaniel Baluta 
1070c3a23eccSDaniel Baluta 	ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_INL);
1071eca8523aSJonathan Cameron 	if (ret < 0)
1072c3a23eccSDaniel Baluta 		dev_err(&data->client->dev, "Error reading reg_inl\n");
1073c3a23eccSDaniel Baluta }
1074c3a23eccSDaniel Baluta 
1075c3a23eccSDaniel Baluta static const struct iio_trigger_ops kmx61_trigger_ops = {
1076c3a23eccSDaniel Baluta 	.set_trigger_state = kmx61_data_rdy_trigger_set_state,
1077eca8523aSJonathan Cameron 	.reenable = kmx61_trig_reenable,
1078c3a23eccSDaniel Baluta };
1079c3a23eccSDaniel Baluta 
kmx61_event_handler(int irq,void * private)1080fd3ae7a9SDaniel Baluta static irqreturn_t kmx61_event_handler(int irq, void *private)
1081fd3ae7a9SDaniel Baluta {
1082fd3ae7a9SDaniel Baluta 	struct kmx61_data *data = private;
1083fd3ae7a9SDaniel Baluta 	struct iio_dev *indio_dev = data->acc_indio_dev;
1084fd3ae7a9SDaniel Baluta 	int ret;
1085fd3ae7a9SDaniel Baluta 
1086fd3ae7a9SDaniel Baluta 	ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_INS1);
1087fd3ae7a9SDaniel Baluta 	if (ret < 0) {
1088fd3ae7a9SDaniel Baluta 		dev_err(&data->client->dev, "Error reading reg_ins1\n");
1089fd3ae7a9SDaniel Baluta 		goto ack_intr;
1090fd3ae7a9SDaniel Baluta 	}
1091fd3ae7a9SDaniel Baluta 
1092fd3ae7a9SDaniel Baluta 	if (ret & KMX61_REG_INS1_BIT_WUFS) {
1093fd3ae7a9SDaniel Baluta 		ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_INS2);
1094fd3ae7a9SDaniel Baluta 		if (ret < 0) {
1095fd3ae7a9SDaniel Baluta 			dev_err(&data->client->dev, "Error reading reg_ins2\n");
1096fd3ae7a9SDaniel Baluta 			goto ack_intr;
1097fd3ae7a9SDaniel Baluta 		}
1098fd3ae7a9SDaniel Baluta 
1099fd3ae7a9SDaniel Baluta 		if (ret & KMX61_REG_INS2_BIT_XN)
1100fd3ae7a9SDaniel Baluta 			iio_push_event(indio_dev,
1101fd3ae7a9SDaniel Baluta 				       IIO_MOD_EVENT_CODE(IIO_ACCEL,
1102fd3ae7a9SDaniel Baluta 				       0,
1103fd3ae7a9SDaniel Baluta 				       IIO_MOD_X,
1104fd3ae7a9SDaniel Baluta 				       IIO_EV_TYPE_THRESH,
1105fd3ae7a9SDaniel Baluta 				       IIO_EV_DIR_FALLING),
1106fd3ae7a9SDaniel Baluta 				       0);
1107fd3ae7a9SDaniel Baluta 
1108fd3ae7a9SDaniel Baluta 		if (ret & KMX61_REG_INS2_BIT_XP)
1109fd3ae7a9SDaniel Baluta 			iio_push_event(indio_dev,
1110fd3ae7a9SDaniel Baluta 				       IIO_MOD_EVENT_CODE(IIO_ACCEL,
1111fd3ae7a9SDaniel Baluta 				       0,
1112fd3ae7a9SDaniel Baluta 				       IIO_MOD_X,
1113fd3ae7a9SDaniel Baluta 				       IIO_EV_TYPE_THRESH,
1114fd3ae7a9SDaniel Baluta 				       IIO_EV_DIR_RISING),
1115fd3ae7a9SDaniel Baluta 				       0);
1116fd3ae7a9SDaniel Baluta 
1117fd3ae7a9SDaniel Baluta 		if (ret & KMX61_REG_INS2_BIT_YN)
1118fd3ae7a9SDaniel Baluta 			iio_push_event(indio_dev,
1119fd3ae7a9SDaniel Baluta 				       IIO_MOD_EVENT_CODE(IIO_ACCEL,
1120fd3ae7a9SDaniel Baluta 				       0,
1121fd3ae7a9SDaniel Baluta 				       IIO_MOD_Y,
1122fd3ae7a9SDaniel Baluta 				       IIO_EV_TYPE_THRESH,
1123fd3ae7a9SDaniel Baluta 				       IIO_EV_DIR_FALLING),
1124fd3ae7a9SDaniel Baluta 				       0);
1125fd3ae7a9SDaniel Baluta 
1126fd3ae7a9SDaniel Baluta 		if (ret & KMX61_REG_INS2_BIT_YP)
1127fd3ae7a9SDaniel Baluta 			iio_push_event(indio_dev,
1128fd3ae7a9SDaniel Baluta 				       IIO_MOD_EVENT_CODE(IIO_ACCEL,
1129fd3ae7a9SDaniel Baluta 				       0,
1130fd3ae7a9SDaniel Baluta 				       IIO_MOD_Y,
1131fd3ae7a9SDaniel Baluta 				       IIO_EV_TYPE_THRESH,
1132fd3ae7a9SDaniel Baluta 				       IIO_EV_DIR_RISING),
1133fd3ae7a9SDaniel Baluta 				       0);
1134fd3ae7a9SDaniel Baluta 
1135fd3ae7a9SDaniel Baluta 		if (ret & KMX61_REG_INS2_BIT_ZN)
1136fd3ae7a9SDaniel Baluta 			iio_push_event(indio_dev,
1137fd3ae7a9SDaniel Baluta 				       IIO_MOD_EVENT_CODE(IIO_ACCEL,
1138fd3ae7a9SDaniel Baluta 				       0,
1139fd3ae7a9SDaniel Baluta 				       IIO_MOD_Z,
1140fd3ae7a9SDaniel Baluta 				       IIO_EV_TYPE_THRESH,
1141fd3ae7a9SDaniel Baluta 				       IIO_EV_DIR_FALLING),
1142fd3ae7a9SDaniel Baluta 				       0);
1143fd3ae7a9SDaniel Baluta 
1144fd3ae7a9SDaniel Baluta 		if (ret & KMX61_REG_INS2_BIT_ZP)
1145fd3ae7a9SDaniel Baluta 			iio_push_event(indio_dev,
1146fd3ae7a9SDaniel Baluta 				       IIO_MOD_EVENT_CODE(IIO_ACCEL,
1147fd3ae7a9SDaniel Baluta 				       0,
1148fd3ae7a9SDaniel Baluta 				       IIO_MOD_Z,
1149fd3ae7a9SDaniel Baluta 				       IIO_EV_TYPE_THRESH,
1150fd3ae7a9SDaniel Baluta 				       IIO_EV_DIR_RISING),
1151fd3ae7a9SDaniel Baluta 				       0);
1152fd3ae7a9SDaniel Baluta 	}
1153fd3ae7a9SDaniel Baluta 
1154fd3ae7a9SDaniel Baluta ack_intr:
1155fd3ae7a9SDaniel Baluta 	ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_CTRL1);
1156fd3ae7a9SDaniel Baluta 	if (ret < 0)
1157fd3ae7a9SDaniel Baluta 		dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
1158fd3ae7a9SDaniel Baluta 
1159fd3ae7a9SDaniel Baluta 	ret |= KMX61_REG_CTRL1_BIT_RES;
1160fd3ae7a9SDaniel Baluta 	ret = i2c_smbus_write_byte_data(data->client, KMX61_REG_CTRL1, ret);
1161fd3ae7a9SDaniel Baluta 	if (ret < 0)
116228ff344eSDaniel Baluta 		dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
1163fd3ae7a9SDaniel Baluta 
1164fd3ae7a9SDaniel Baluta 	ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_INL);
1165fd3ae7a9SDaniel Baluta 	if (ret < 0)
1166fd3ae7a9SDaniel Baluta 		dev_err(&data->client->dev, "Error reading reg_inl\n");
1167fd3ae7a9SDaniel Baluta 
1168fd3ae7a9SDaniel Baluta 	return IRQ_HANDLED;
1169fd3ae7a9SDaniel Baluta }
1170fd3ae7a9SDaniel Baluta 
kmx61_data_rdy_trig_poll(int irq,void * private)1171c3a23eccSDaniel Baluta static irqreturn_t kmx61_data_rdy_trig_poll(int irq, void *private)
1172c3a23eccSDaniel Baluta {
1173c3a23eccSDaniel Baluta 	struct kmx61_data *data = private;
1174c3a23eccSDaniel Baluta 
1175c3a23eccSDaniel Baluta 	if (data->acc_dready_trig_on)
1176c3a23eccSDaniel Baluta 		iio_trigger_poll(data->acc_dready_trig);
1177c3a23eccSDaniel Baluta 	if (data->mag_dready_trig_on)
1178c3a23eccSDaniel Baluta 		iio_trigger_poll(data->mag_dready_trig);
1179c3a23eccSDaniel Baluta 
1180fd3ae7a9SDaniel Baluta 	if (data->motion_trig_on)
1181fd3ae7a9SDaniel Baluta 		iio_trigger_poll(data->motion_trig);
1182fd3ae7a9SDaniel Baluta 
1183fd3ae7a9SDaniel Baluta 	if (data->ev_enable_state)
1184fd3ae7a9SDaniel Baluta 		return IRQ_WAKE_THREAD;
1185c3a23eccSDaniel Baluta 	return IRQ_HANDLED;
1186c3a23eccSDaniel Baluta }
1187c3a23eccSDaniel Baluta 
kmx61_trigger_handler(int irq,void * p)1188c3a23eccSDaniel Baluta static irqreturn_t kmx61_trigger_handler(int irq, void *p)
1189c3a23eccSDaniel Baluta {
1190c3a23eccSDaniel Baluta 	struct iio_poll_func *pf = p;
1191c3a23eccSDaniel Baluta 	struct iio_dev *indio_dev = pf->indio_dev;
1192c3a23eccSDaniel Baluta 	struct kmx61_data *data = kmx61_get_data(indio_dev);
1193c3a23eccSDaniel Baluta 	int bit, ret, i = 0;
11946a191c70SDaniel Baluta 	u8 base;
1195*cde312e2SJavier Carrasco 	s16 buffer[8] = { };
1196c3a23eccSDaniel Baluta 
11976a191c70SDaniel Baluta 	if (indio_dev == data->acc_indio_dev)
11986a191c70SDaniel Baluta 		base = KMX61_ACC_XOUT_L;
11996a191c70SDaniel Baluta 	else
12006a191c70SDaniel Baluta 		base = KMX61_MAG_XOUT_L;
12016a191c70SDaniel Baluta 
1202c3a23eccSDaniel Baluta 	mutex_lock(&data->lock);
120370dddeeeSOctavian Purdila 	for_each_set_bit(bit, indio_dev->active_scan_mask,
1204c3a23eccSDaniel Baluta 			 indio_dev->masklength) {
12056a191c70SDaniel Baluta 		ret = kmx61_read_measurement(data, base, bit);
1206c3a23eccSDaniel Baluta 		if (ret < 0) {
1207c3a23eccSDaniel Baluta 			mutex_unlock(&data->lock);
1208c3a23eccSDaniel Baluta 			goto err;
1209c3a23eccSDaniel Baluta 		}
1210c3a23eccSDaniel Baluta 		buffer[i++] = ret;
1211c3a23eccSDaniel Baluta 	}
1212c3a23eccSDaniel Baluta 	mutex_unlock(&data->lock);
1213c3a23eccSDaniel Baluta 
1214c3a23eccSDaniel Baluta 	iio_push_to_buffers(indio_dev, buffer);
1215c3a23eccSDaniel Baluta err:
1216c3a23eccSDaniel Baluta 	iio_trigger_notify_done(indio_dev->trig);
1217c3a23eccSDaniel Baluta 
1218c3a23eccSDaniel Baluta 	return IRQ_HANDLED;
1219c3a23eccSDaniel Baluta }
1220c3a23eccSDaniel Baluta 
kmx61_match_acpi_device(struct device * dev)1221b25862c5SDaniel Baluta static const char *kmx61_match_acpi_device(struct device *dev)
1222b25862c5SDaniel Baluta {
1223b25862c5SDaniel Baluta 	const struct acpi_device_id *id;
1224b25862c5SDaniel Baluta 
1225b25862c5SDaniel Baluta 	id = acpi_match_device(dev->driver->acpi_match_table, dev);
1226b25862c5SDaniel Baluta 	if (!id)
1227b25862c5SDaniel Baluta 		return NULL;
1228b25862c5SDaniel Baluta 	return dev_name(dev);
1229b25862c5SDaniel Baluta }
1230b25862c5SDaniel Baluta 
kmx61_indiodev_setup(struct kmx61_data * data,const struct iio_info * info,const struct iio_chan_spec * chan,int num_channels,const char * name)123120ffac27SDaniel Baluta static struct iio_dev *kmx61_indiodev_setup(struct kmx61_data *data,
123220ffac27SDaniel Baluta 					    const struct iio_info *info,
123320ffac27SDaniel Baluta 					    const struct iio_chan_spec *chan,
123420ffac27SDaniel Baluta 					    int num_channels,
123520ffac27SDaniel Baluta 					    const char *name)
123620ffac27SDaniel Baluta {
123720ffac27SDaniel Baluta 	struct iio_dev *indio_dev;
123820ffac27SDaniel Baluta 
123920ffac27SDaniel Baluta 	indio_dev = devm_iio_device_alloc(&data->client->dev, sizeof(data));
124020ffac27SDaniel Baluta 	if (!indio_dev)
124120ffac27SDaniel Baluta 		return ERR_PTR(-ENOMEM);
124220ffac27SDaniel Baluta 
124320ffac27SDaniel Baluta 	kmx61_set_data(indio_dev, data);
124420ffac27SDaniel Baluta 
124520ffac27SDaniel Baluta 	indio_dev->channels = chan;
124620ffac27SDaniel Baluta 	indio_dev->num_channels = num_channels;
124720ffac27SDaniel Baluta 	indio_dev->name = name;
124820ffac27SDaniel Baluta 	indio_dev->modes = INDIO_DIRECT_MODE;
124920ffac27SDaniel Baluta 	indio_dev->info = info;
125020ffac27SDaniel Baluta 
125120ffac27SDaniel Baluta 	return indio_dev;
125220ffac27SDaniel Baluta }
125320ffac27SDaniel Baluta 
kmx61_trigger_setup(struct kmx61_data * data,struct iio_dev * indio_dev,const char * tag)1254c3a23eccSDaniel Baluta static struct iio_trigger *kmx61_trigger_setup(struct kmx61_data *data,
1255c3a23eccSDaniel Baluta 					       struct iio_dev *indio_dev,
1256c3a23eccSDaniel Baluta 					       const char *tag)
1257c3a23eccSDaniel Baluta {
1258c3a23eccSDaniel Baluta 	struct iio_trigger *trig;
1259c3a23eccSDaniel Baluta 	int ret;
1260c3a23eccSDaniel Baluta 
1261c3a23eccSDaniel Baluta 	trig = devm_iio_trigger_alloc(&data->client->dev,
1262c3a23eccSDaniel Baluta 				      "%s-%s-dev%d",
1263c3a23eccSDaniel Baluta 				      indio_dev->name,
1264c3a23eccSDaniel Baluta 				      tag,
126515ea2878SJonathan Cameron 				      iio_device_id(indio_dev));
1266c3a23eccSDaniel Baluta 	if (!trig)
1267c3a23eccSDaniel Baluta 		return ERR_PTR(-ENOMEM);
1268c3a23eccSDaniel Baluta 
1269c3a23eccSDaniel Baluta 	trig->ops = &kmx61_trigger_ops;
1270c3a23eccSDaniel Baluta 	iio_trigger_set_drvdata(trig, indio_dev);
1271c3a23eccSDaniel Baluta 
1272c3a23eccSDaniel Baluta 	ret = iio_trigger_register(trig);
1273c3a23eccSDaniel Baluta 	if (ret)
1274c3a23eccSDaniel Baluta 		return ERR_PTR(ret);
1275c3a23eccSDaniel Baluta 
1276c3a23eccSDaniel Baluta 	return trig;
1277c3a23eccSDaniel Baluta }
1278c3a23eccSDaniel Baluta 
kmx61_probe(struct i2c_client * client)12794bf718bcSUwe Kleine-König static int kmx61_probe(struct i2c_client *client)
128020ffac27SDaniel Baluta {
12814bf718bcSUwe Kleine-König 	const struct i2c_device_id *id = i2c_client_get_device_id(client);
128220ffac27SDaniel Baluta 	int ret;
128320ffac27SDaniel Baluta 	struct kmx61_data *data;
128420ffac27SDaniel Baluta 	const char *name = NULL;
128520ffac27SDaniel Baluta 
128620ffac27SDaniel Baluta 	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
128720ffac27SDaniel Baluta 	if (!data)
128820ffac27SDaniel Baluta 		return -ENOMEM;
128920ffac27SDaniel Baluta 
129020ffac27SDaniel Baluta 	i2c_set_clientdata(client, data);
129120ffac27SDaniel Baluta 	data->client = client;
129220ffac27SDaniel Baluta 
129320ffac27SDaniel Baluta 	mutex_init(&data->lock);
129420ffac27SDaniel Baluta 
1295b25862c5SDaniel Baluta 	if (id)
1296b25862c5SDaniel Baluta 		name = id->name;
1297b25862c5SDaniel Baluta 	else if (ACPI_HANDLE(&client->dev))
1298b25862c5SDaniel Baluta 		name = kmx61_match_acpi_device(&client->dev);
1299b25862c5SDaniel Baluta 	else
1300b25862c5SDaniel Baluta 		return -ENODEV;
1301b25862c5SDaniel Baluta 
130220ffac27SDaniel Baluta 	data->acc_indio_dev =
130320ffac27SDaniel Baluta 		kmx61_indiodev_setup(data, &kmx61_acc_info,
130420ffac27SDaniel Baluta 				     kmx61_acc_channels,
130520ffac27SDaniel Baluta 				     ARRAY_SIZE(kmx61_acc_channels),
130620ffac27SDaniel Baluta 				     name);
130720ffac27SDaniel Baluta 	if (IS_ERR(data->acc_indio_dev))
130820ffac27SDaniel Baluta 		return PTR_ERR(data->acc_indio_dev);
130920ffac27SDaniel Baluta 
131020ffac27SDaniel Baluta 	data->mag_indio_dev =
131120ffac27SDaniel Baluta 		kmx61_indiodev_setup(data, &kmx61_mag_info,
131220ffac27SDaniel Baluta 				     kmx61_mag_channels,
131320ffac27SDaniel Baluta 				     ARRAY_SIZE(kmx61_mag_channels),
131420ffac27SDaniel Baluta 				     name);
131520ffac27SDaniel Baluta 	if (IS_ERR(data->mag_indio_dev))
131620ffac27SDaniel Baluta 		return PTR_ERR(data->mag_indio_dev);
131720ffac27SDaniel Baluta 
131820ffac27SDaniel Baluta 	ret = kmx61_chip_init(data);
131920ffac27SDaniel Baluta 	if (ret < 0)
132020ffac27SDaniel Baluta 		return ret;
132120ffac27SDaniel Baluta 
1322c176becdSOctavian Purdila 	if (client->irq > 0) {
1323c3a23eccSDaniel Baluta 		ret = devm_request_threaded_irq(&client->dev, client->irq,
1324c3a23eccSDaniel Baluta 						kmx61_data_rdy_trig_poll,
1325fd3ae7a9SDaniel Baluta 						kmx61_event_handler,
1326c3a23eccSDaniel Baluta 						IRQF_TRIGGER_RISING,
1327c3a23eccSDaniel Baluta 						KMX61_IRQ_NAME,
1328c3a23eccSDaniel Baluta 						data);
1329c3a23eccSDaniel Baluta 		if (ret)
1330c3a23eccSDaniel Baluta 			goto err_chip_uninit;
1331c3a23eccSDaniel Baluta 
1332c3a23eccSDaniel Baluta 		data->acc_dready_trig =
1333c3a23eccSDaniel Baluta 			kmx61_trigger_setup(data, data->acc_indio_dev,
1334c3a23eccSDaniel Baluta 					    "dready");
133528ff344eSDaniel Baluta 		if (IS_ERR(data->acc_dready_trig)) {
133628ff344eSDaniel Baluta 			ret = PTR_ERR(data->acc_dready_trig);
133728ff344eSDaniel Baluta 			goto err_chip_uninit;
133828ff344eSDaniel Baluta 		}
1339c3a23eccSDaniel Baluta 
1340c3a23eccSDaniel Baluta 		data->mag_dready_trig =
1341c3a23eccSDaniel Baluta 			kmx61_trigger_setup(data, data->mag_indio_dev,
1342c3a23eccSDaniel Baluta 					    "dready");
1343c3a23eccSDaniel Baluta 		if (IS_ERR(data->mag_dready_trig)) {
1344c3a23eccSDaniel Baluta 			ret = PTR_ERR(data->mag_dready_trig);
134528ff344eSDaniel Baluta 			goto err_trigger_unregister_acc_dready;
1346c3a23eccSDaniel Baluta 		}
1347c3a23eccSDaniel Baluta 
1348fd3ae7a9SDaniel Baluta 		data->motion_trig =
1349fd3ae7a9SDaniel Baluta 			kmx61_trigger_setup(data, data->acc_indio_dev,
1350fd3ae7a9SDaniel Baluta 					    "any-motion");
1351fd3ae7a9SDaniel Baluta 		if (IS_ERR(data->motion_trig)) {
1352fd3ae7a9SDaniel Baluta 			ret = PTR_ERR(data->motion_trig);
135328ff344eSDaniel Baluta 			goto err_trigger_unregister_mag_dready;
1354fd3ae7a9SDaniel Baluta 		}
1355fd3ae7a9SDaniel Baluta 
1356c3a23eccSDaniel Baluta 		ret = iio_triggered_buffer_setup(data->acc_indio_dev,
1357c3a23eccSDaniel Baluta 						 &iio_pollfunc_store_time,
1358c3a23eccSDaniel Baluta 						 kmx61_trigger_handler,
1359c3a23eccSDaniel Baluta 						 NULL);
1360c3a23eccSDaniel Baluta 		if (ret < 0) {
1361c3a23eccSDaniel Baluta 			dev_err(&data->client->dev,
1362c3a23eccSDaniel Baluta 				"Failed to setup acc triggered buffer\n");
136328ff344eSDaniel Baluta 			goto err_trigger_unregister_motion;
1364c3a23eccSDaniel Baluta 		}
1365c3a23eccSDaniel Baluta 
1366c3a23eccSDaniel Baluta 		ret = iio_triggered_buffer_setup(data->mag_indio_dev,
1367c3a23eccSDaniel Baluta 						 &iio_pollfunc_store_time,
1368c3a23eccSDaniel Baluta 						 kmx61_trigger_handler,
1369c3a23eccSDaniel Baluta 						 NULL);
1370c3a23eccSDaniel Baluta 		if (ret < 0) {
1371c3a23eccSDaniel Baluta 			dev_err(&data->client->dev,
1372c3a23eccSDaniel Baluta 				"Failed to setup mag triggered buffer\n");
137328ff344eSDaniel Baluta 			goto err_buffer_cleanup_acc;
1374c3a23eccSDaniel Baluta 		}
1375c3a23eccSDaniel Baluta 	}
1376c3a23eccSDaniel Baluta 
13777d0ead5cSAdriana Reus 	ret = pm_runtime_set_active(&client->dev);
13787d0ead5cSAdriana Reus 	if (ret < 0)
13797d0ead5cSAdriana Reus 		goto err_buffer_cleanup_mag;
13807d0ead5cSAdriana Reus 
13817d0ead5cSAdriana Reus 	pm_runtime_enable(&client->dev);
13827d0ead5cSAdriana Reus 	pm_runtime_set_autosuspend_delay(&client->dev, KMX61_SLEEP_DELAY_MS);
13837d0ead5cSAdriana Reus 	pm_runtime_use_autosuspend(&client->dev);
13847d0ead5cSAdriana Reus 
138520ffac27SDaniel Baluta 	ret = iio_device_register(data->acc_indio_dev);
138620ffac27SDaniel Baluta 	if (ret < 0) {
138720ffac27SDaniel Baluta 		dev_err(&client->dev, "Failed to register acc iio device\n");
1388632fe0bbSMiaoqian Lin 		goto err_pm_cleanup;
138920ffac27SDaniel Baluta 	}
139020ffac27SDaniel Baluta 
139120ffac27SDaniel Baluta 	ret = iio_device_register(data->mag_indio_dev);
139220ffac27SDaniel Baluta 	if (ret < 0) {
139320ffac27SDaniel Baluta 		dev_err(&client->dev, "Failed to register mag iio device\n");
1394aff8609aSDaniel Baluta 		goto err_iio_unregister_acc;
139520ffac27SDaniel Baluta 	}
139620ffac27SDaniel Baluta 
139720ffac27SDaniel Baluta 	return 0;
139820ffac27SDaniel Baluta 
1399aff8609aSDaniel Baluta err_iio_unregister_acc:
140020ffac27SDaniel Baluta 	iio_device_unregister(data->acc_indio_dev);
1401632fe0bbSMiaoqian Lin err_pm_cleanup:
1402632fe0bbSMiaoqian Lin 	pm_runtime_dont_use_autosuspend(&client->dev);
1403632fe0bbSMiaoqian Lin 	pm_runtime_disable(&client->dev);
140428ff344eSDaniel Baluta err_buffer_cleanup_mag:
1405c176becdSOctavian Purdila 	if (client->irq > 0)
1406c3a23eccSDaniel Baluta 		iio_triggered_buffer_cleanup(data->mag_indio_dev);
140728ff344eSDaniel Baluta err_buffer_cleanup_acc:
1408c176becdSOctavian Purdila 	if (client->irq > 0)
140928ff344eSDaniel Baluta 		iio_triggered_buffer_cleanup(data->acc_indio_dev);
141028ff344eSDaniel Baluta err_trigger_unregister_motion:
1411fd3ae7a9SDaniel Baluta 	iio_trigger_unregister(data->motion_trig);
141228ff344eSDaniel Baluta err_trigger_unregister_mag_dready:
141328ff344eSDaniel Baluta 	iio_trigger_unregister(data->mag_dready_trig);
141428ff344eSDaniel Baluta err_trigger_unregister_acc_dready:
141528ff344eSDaniel Baluta 	iio_trigger_unregister(data->acc_dready_trig);
141620ffac27SDaniel Baluta err_chip_uninit:
141720ffac27SDaniel Baluta 	kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, true);
141820ffac27SDaniel Baluta 	return ret;
141920ffac27SDaniel Baluta }
142020ffac27SDaniel Baluta 
kmx61_remove(struct i2c_client * client)1421ed5c2f5fSUwe Kleine-König static void kmx61_remove(struct i2c_client *client)
142220ffac27SDaniel Baluta {
142320ffac27SDaniel Baluta 	struct kmx61_data *data = i2c_get_clientdata(client);
142420ffac27SDaniel Baluta 
14257d0ead5cSAdriana Reus 	iio_device_unregister(data->acc_indio_dev);
14267d0ead5cSAdriana Reus 	iio_device_unregister(data->mag_indio_dev);
14277d0ead5cSAdriana Reus 
1428aff8609aSDaniel Baluta 	pm_runtime_disable(&client->dev);
1429aff8609aSDaniel Baluta 	pm_runtime_set_suspended(&client->dev);
1430aff8609aSDaniel Baluta 
1431c176becdSOctavian Purdila 	if (client->irq > 0) {
1432c3a23eccSDaniel Baluta 		iio_triggered_buffer_cleanup(data->acc_indio_dev);
1433c3a23eccSDaniel Baluta 		iio_triggered_buffer_cleanup(data->mag_indio_dev);
1434c3a23eccSDaniel Baluta 		iio_trigger_unregister(data->acc_dready_trig);
1435c3a23eccSDaniel Baluta 		iio_trigger_unregister(data->mag_dready_trig);
1436fd3ae7a9SDaniel Baluta 		iio_trigger_unregister(data->motion_trig);
1437c3a23eccSDaniel Baluta 	}
1438c3a23eccSDaniel Baluta 
143920ffac27SDaniel Baluta 	mutex_lock(&data->lock);
144020ffac27SDaniel Baluta 	kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, true);
144120ffac27SDaniel Baluta 	mutex_unlock(&data->lock);
144220ffac27SDaniel Baluta }
144320ffac27SDaniel Baluta 
kmx61_suspend(struct device * dev)14443b9c40e6SDaniel Baluta static int kmx61_suspend(struct device *dev)
14453b9c40e6SDaniel Baluta {
14463b9c40e6SDaniel Baluta 	int ret;
14473b9c40e6SDaniel Baluta 	struct kmx61_data *data = i2c_get_clientdata(to_i2c_client(dev));
14483b9c40e6SDaniel Baluta 
14493b9c40e6SDaniel Baluta 	mutex_lock(&data->lock);
14503b9c40e6SDaniel Baluta 	ret = kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG,
14513b9c40e6SDaniel Baluta 			     false);
14523b9c40e6SDaniel Baluta 	mutex_unlock(&data->lock);
14533b9c40e6SDaniel Baluta 
14543b9c40e6SDaniel Baluta 	return ret;
14553b9c40e6SDaniel Baluta }
14563b9c40e6SDaniel Baluta 
kmx61_resume(struct device * dev)14573b9c40e6SDaniel Baluta static int kmx61_resume(struct device *dev)
14583b9c40e6SDaniel Baluta {
14593b9c40e6SDaniel Baluta 	u8 stby = 0;
14603b9c40e6SDaniel Baluta 	struct kmx61_data *data = i2c_get_clientdata(to_i2c_client(dev));
14613b9c40e6SDaniel Baluta 
14623b9c40e6SDaniel Baluta 	if (data->acc_stby)
14633b9c40e6SDaniel Baluta 		stby |= KMX61_ACC_STBY_BIT;
14643b9c40e6SDaniel Baluta 	if (data->mag_stby)
14653b9c40e6SDaniel Baluta 		stby |= KMX61_MAG_STBY_BIT;
14663b9c40e6SDaniel Baluta 
14673b9c40e6SDaniel Baluta 	return kmx61_set_mode(data, stby, KMX61_ACC | KMX61_MAG, true);
14683b9c40e6SDaniel Baluta }
1469aff8609aSDaniel Baluta 
kmx61_runtime_suspend(struct device * dev)1470aff8609aSDaniel Baluta static int kmx61_runtime_suspend(struct device *dev)
1471aff8609aSDaniel Baluta {
1472aff8609aSDaniel Baluta 	struct kmx61_data *data = i2c_get_clientdata(to_i2c_client(dev));
1473aff8609aSDaniel Baluta 	int ret;
1474aff8609aSDaniel Baluta 
1475aff8609aSDaniel Baluta 	mutex_lock(&data->lock);
1476aff8609aSDaniel Baluta 	ret = kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, true);
1477aff8609aSDaniel Baluta 	mutex_unlock(&data->lock);
1478aff8609aSDaniel Baluta 
1479aff8609aSDaniel Baluta 	return ret;
1480aff8609aSDaniel Baluta }
1481aff8609aSDaniel Baluta 
kmx61_runtime_resume(struct device * dev)1482aff8609aSDaniel Baluta static int kmx61_runtime_resume(struct device *dev)
1483aff8609aSDaniel Baluta {
1484aff8609aSDaniel Baluta 	struct kmx61_data *data = i2c_get_clientdata(to_i2c_client(dev));
1485aff8609aSDaniel Baluta 	u8 stby = 0;
1486aff8609aSDaniel Baluta 
1487aff8609aSDaniel Baluta 	if (!data->acc_ps)
1488aff8609aSDaniel Baluta 		stby |= KMX61_ACC_STBY_BIT;
1489aff8609aSDaniel Baluta 	if (!data->mag_ps)
1490aff8609aSDaniel Baluta 		stby |= KMX61_MAG_STBY_BIT;
1491aff8609aSDaniel Baluta 
1492aff8609aSDaniel Baluta 	return kmx61_set_mode(data, stby, KMX61_ACC | KMX61_MAG, true);
1493aff8609aSDaniel Baluta }
1494aff8609aSDaniel Baluta 
1495aff8609aSDaniel Baluta static const struct dev_pm_ops kmx61_pm_ops = {
1496da123e29SJonathan Cameron 	SYSTEM_SLEEP_PM_OPS(kmx61_suspend, kmx61_resume)
1497da123e29SJonathan Cameron 	RUNTIME_PM_OPS(kmx61_runtime_suspend, kmx61_runtime_resume, NULL)
1498aff8609aSDaniel Baluta };
1499aff8609aSDaniel Baluta 
1500b25862c5SDaniel Baluta static const struct acpi_device_id kmx61_acpi_match[] = {
1501b25862c5SDaniel Baluta 	{"KMX61021", 0},
1502b25862c5SDaniel Baluta 	{}
1503b25862c5SDaniel Baluta };
1504b25862c5SDaniel Baluta 
1505b25862c5SDaniel Baluta MODULE_DEVICE_TABLE(acpi, kmx61_acpi_match);
1506b25862c5SDaniel Baluta 
150720ffac27SDaniel Baluta static const struct i2c_device_id kmx61_id[] = {
150820ffac27SDaniel Baluta 	{"kmx611021", 0},
150920ffac27SDaniel Baluta 	{}
151020ffac27SDaniel Baluta };
151120ffac27SDaniel Baluta 
151220ffac27SDaniel Baluta MODULE_DEVICE_TABLE(i2c, kmx61_id);
151320ffac27SDaniel Baluta 
151420ffac27SDaniel Baluta static struct i2c_driver kmx61_driver = {
151520ffac27SDaniel Baluta 	.driver = {
151620ffac27SDaniel Baluta 		.name = KMX61_DRV_NAME,
1517b25862c5SDaniel Baluta 		.acpi_match_table = ACPI_PTR(kmx61_acpi_match),
1518da123e29SJonathan Cameron 		.pm = pm_ptr(&kmx61_pm_ops),
151920ffac27SDaniel Baluta 	},
15207cf15f42SUwe Kleine-König 	.probe		= kmx61_probe,
152120ffac27SDaniel Baluta 	.remove		= kmx61_remove,
152220ffac27SDaniel Baluta 	.id_table	= kmx61_id,
152320ffac27SDaniel Baluta };
152420ffac27SDaniel Baluta 
152520ffac27SDaniel Baluta module_i2c_driver(kmx61_driver);
152620ffac27SDaniel Baluta 
152720ffac27SDaniel Baluta MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");
152820ffac27SDaniel Baluta MODULE_DESCRIPTION("KMX61 accelerometer/magnetometer driver");
152920ffac27SDaniel Baluta MODULE_LICENSE("GPL v2");
1530