xref: /openbmc/linux/drivers/iio/accel/mxc4005.c (revision f68f3e3f)
12025cf9eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2077377fcSTeodora Baluta /*
3077377fcSTeodora Baluta  * 3-axis accelerometer driver for MXC4005XC Memsic sensor
4077377fcSTeodora Baluta  *
5077377fcSTeodora Baluta  * Copyright (c) 2014, Intel Corporation.
6077377fcSTeodora Baluta  */
7077377fcSTeodora Baluta 
8f68f3e3fSHans de Goede #include <linux/delay.h>
9077377fcSTeodora Baluta #include <linux/module.h>
10077377fcSTeodora Baluta #include <linux/i2c.h>
11077377fcSTeodora Baluta #include <linux/iio/iio.h>
12077377fcSTeodora Baluta #include <linux/acpi.h>
13077377fcSTeodora Baluta #include <linux/regmap.h>
14077377fcSTeodora Baluta #include <linux/iio/sysfs.h>
1547196620STeodora Baluta #include <linux/iio/trigger.h>
161ce0eda0STeodora Baluta #include <linux/iio/buffer.h>
171ce0eda0STeodora Baluta #include <linux/iio/triggered_buffer.h>
181ce0eda0STeodora Baluta #include <linux/iio/trigger_consumer.h>
19077377fcSTeodora Baluta 
20077377fcSTeodora Baluta #define MXC4005_DRV_NAME		"mxc4005"
2147196620STeodora Baluta #define MXC4005_IRQ_NAME		"mxc4005_event"
22077377fcSTeodora Baluta #define MXC4005_REGMAP_NAME		"mxc4005_regmap"
23077377fcSTeodora Baluta 
24077377fcSTeodora Baluta #define MXC4005_REG_XOUT_UPPER		0x03
25077377fcSTeodora Baluta #define MXC4005_REG_XOUT_LOWER		0x04
26077377fcSTeodora Baluta #define MXC4005_REG_YOUT_UPPER		0x05
27077377fcSTeodora Baluta #define MXC4005_REG_YOUT_LOWER		0x06
28077377fcSTeodora Baluta #define MXC4005_REG_ZOUT_UPPER		0x07
29077377fcSTeodora Baluta #define MXC4005_REG_ZOUT_LOWER		0x08
30077377fcSTeodora Baluta 
315eba2638SHans de Goede #define MXC4005_REG_INT_MASK0		0x0A
325eba2638SHans de Goede 
3347196620STeodora Baluta #define MXC4005_REG_INT_MASK1		0x0B
3447196620STeodora Baluta #define MXC4005_REG_INT_MASK1_BIT_DRDYE	0x01
3547196620STeodora Baluta 
365eba2638SHans de Goede #define MXC4005_REG_INT_CLR0		0x00
375eba2638SHans de Goede 
3847196620STeodora Baluta #define MXC4005_REG_INT_CLR1		0x01
3947196620STeodora Baluta #define MXC4005_REG_INT_CLR1_BIT_DRDYC	0x01
40f68f3e3fSHans de Goede #define MXC4005_REG_INT_CLR1_SW_RST	0x10
4147196620STeodora Baluta 
42077377fcSTeodora Baluta #define MXC4005_REG_CONTROL		0x0D
43077377fcSTeodora Baluta #define MXC4005_REG_CONTROL_MASK_FSR	GENMASK(6, 5)
44077377fcSTeodora Baluta #define MXC4005_CONTROL_FSR_SHIFT	5
45077377fcSTeodora Baluta 
46077377fcSTeodora Baluta #define MXC4005_REG_DEVICE_ID		0x0E
47077377fcSTeodora Baluta 
48f68f3e3fSHans de Goede /* Datasheet does not specify a reset time, this is a conservative guess */
49f68f3e3fSHans de Goede #define MXC4005_RESET_TIME_US		2000
50f68f3e3fSHans de Goede 
51077377fcSTeodora Baluta enum mxc4005_axis {
52077377fcSTeodora Baluta 	AXIS_X,
53077377fcSTeodora Baluta 	AXIS_Y,
54077377fcSTeodora Baluta 	AXIS_Z,
55077377fcSTeodora Baluta };
56077377fcSTeodora Baluta 
57077377fcSTeodora Baluta enum mxc4005_range {
58077377fcSTeodora Baluta 	MXC4005_RANGE_2G,
59077377fcSTeodora Baluta 	MXC4005_RANGE_4G,
60077377fcSTeodora Baluta 	MXC4005_RANGE_8G,
61077377fcSTeodora Baluta };
62077377fcSTeodora Baluta 
63077377fcSTeodora Baluta struct mxc4005_data {
64077377fcSTeodora Baluta 	struct device *dev;
65077377fcSTeodora Baluta 	struct mutex mutex;
66077377fcSTeodora Baluta 	struct regmap *regmap;
6747196620STeodora Baluta 	struct iio_trigger *dready_trig;
68f6580228SJonathan Cameron 	/* Ensure timestamp is naturally aligned */
69f6580228SJonathan Cameron 	struct {
70f6580228SJonathan Cameron 		__be16 chans[3];
71f6580228SJonathan Cameron 		s64 timestamp __aligned(8);
72f6580228SJonathan Cameron 	} scan;
7347196620STeodora Baluta 	bool trigger_enabled;
74f68f3e3fSHans de Goede 	unsigned int control;
75f68f3e3fSHans de Goede 	unsigned int int_mask1;
76077377fcSTeodora Baluta };
77077377fcSTeodora Baluta 
78077377fcSTeodora Baluta /*
79077377fcSTeodora Baluta  * MXC4005 can operate in the following ranges:
80077377fcSTeodora Baluta  * +/- 2G, 4G, 8G (the default +/-2G)
81077377fcSTeodora Baluta  *
82077377fcSTeodora Baluta  * (2 + 2) * 9.81 / (2^12 - 1) = 0.009582
83077377fcSTeodora Baluta  * (4 + 4) * 9.81 / (2^12 - 1) = 0.019164
84077377fcSTeodora Baluta  * (8 + 8) * 9.81 / (2^12 - 1) = 0.038329
85077377fcSTeodora Baluta  */
86077377fcSTeodora Baluta static const struct {
87077377fcSTeodora Baluta 	u8 range;
88077377fcSTeodora Baluta 	int scale;
89077377fcSTeodora Baluta } mxc4005_scale_table[] = {
90077377fcSTeodora Baluta 	{MXC4005_RANGE_2G, 9582},
91077377fcSTeodora Baluta 	{MXC4005_RANGE_4G, 19164},
92077377fcSTeodora Baluta 	{MXC4005_RANGE_8G, 38329},
93077377fcSTeodora Baluta };
94077377fcSTeodora Baluta 
95077377fcSTeodora Baluta 
96077377fcSTeodora Baluta static IIO_CONST_ATTR(in_accel_scale_available, "0.009582 0.019164 0.038329");
97077377fcSTeodora Baluta 
98077377fcSTeodora Baluta static struct attribute *mxc4005_attributes[] = {
99077377fcSTeodora Baluta 	&iio_const_attr_in_accel_scale_available.dev_attr.attr,
100077377fcSTeodora Baluta 	NULL,
101077377fcSTeodora Baluta };
102077377fcSTeodora Baluta 
103077377fcSTeodora Baluta static const struct attribute_group mxc4005_attrs_group = {
104077377fcSTeodora Baluta 	.attrs = mxc4005_attributes,
105077377fcSTeodora Baluta };
106077377fcSTeodora Baluta 
mxc4005_is_readable_reg(struct device * dev,unsigned int reg)107077377fcSTeodora Baluta static bool mxc4005_is_readable_reg(struct device *dev, unsigned int reg)
108077377fcSTeodora Baluta {
109077377fcSTeodora Baluta 	switch (reg) {
110077377fcSTeodora Baluta 	case MXC4005_REG_XOUT_UPPER:
111077377fcSTeodora Baluta 	case MXC4005_REG_XOUT_LOWER:
112077377fcSTeodora Baluta 	case MXC4005_REG_YOUT_UPPER:
113077377fcSTeodora Baluta 	case MXC4005_REG_YOUT_LOWER:
114077377fcSTeodora Baluta 	case MXC4005_REG_ZOUT_UPPER:
115077377fcSTeodora Baluta 	case MXC4005_REG_ZOUT_LOWER:
116077377fcSTeodora Baluta 	case MXC4005_REG_DEVICE_ID:
117077377fcSTeodora Baluta 	case MXC4005_REG_CONTROL:
118077377fcSTeodora Baluta 		return true;
119077377fcSTeodora Baluta 	default:
120077377fcSTeodora Baluta 		return false;
121077377fcSTeodora Baluta 	}
122077377fcSTeodora Baluta }
123077377fcSTeodora Baluta 
mxc4005_is_writeable_reg(struct device * dev,unsigned int reg)124077377fcSTeodora Baluta static bool mxc4005_is_writeable_reg(struct device *dev, unsigned int reg)
125077377fcSTeodora Baluta {
126077377fcSTeodora Baluta 	switch (reg) {
1275eba2638SHans de Goede 	case MXC4005_REG_INT_CLR0:
12847196620STeodora Baluta 	case MXC4005_REG_INT_CLR1:
1295eba2638SHans de Goede 	case MXC4005_REG_INT_MASK0:
13047196620STeodora Baluta 	case MXC4005_REG_INT_MASK1:
131077377fcSTeodora Baluta 	case MXC4005_REG_CONTROL:
132077377fcSTeodora Baluta 		return true;
133077377fcSTeodora Baluta 	default:
134077377fcSTeodora Baluta 		return false;
135077377fcSTeodora Baluta 	}
136077377fcSTeodora Baluta }
137077377fcSTeodora Baluta 
138077377fcSTeodora Baluta static const struct regmap_config mxc4005_regmap_config = {
139077377fcSTeodora Baluta 	.name = MXC4005_REGMAP_NAME,
140077377fcSTeodora Baluta 
141077377fcSTeodora Baluta 	.reg_bits = 8,
142077377fcSTeodora Baluta 	.val_bits = 8,
143077377fcSTeodora Baluta 
144077377fcSTeodora Baluta 	.max_register = MXC4005_REG_DEVICE_ID,
145077377fcSTeodora Baluta 
146077377fcSTeodora Baluta 	.readable_reg = mxc4005_is_readable_reg,
147077377fcSTeodora Baluta 	.writeable_reg = mxc4005_is_writeable_reg,
148077377fcSTeodora Baluta };
149077377fcSTeodora Baluta 
mxc4005_read_xyz(struct mxc4005_data * data)1501ce0eda0STeodora Baluta static int mxc4005_read_xyz(struct mxc4005_data *data)
1511ce0eda0STeodora Baluta {
1521ce0eda0STeodora Baluta 	int ret;
1531ce0eda0STeodora Baluta 
1541ce0eda0STeodora Baluta 	ret = regmap_bulk_read(data->regmap, MXC4005_REG_XOUT_UPPER,
155f6580228SJonathan Cameron 			       data->scan.chans, sizeof(data->scan.chans));
1561ce0eda0STeodora Baluta 	if (ret < 0) {
1571ce0eda0STeodora Baluta 		dev_err(data->dev, "failed to read axes\n");
1581ce0eda0STeodora Baluta 		return ret;
1591ce0eda0STeodora Baluta 	}
1601ce0eda0STeodora Baluta 
1611ce0eda0STeodora Baluta 	return 0;
1621ce0eda0STeodora Baluta }
1631ce0eda0STeodora Baluta 
mxc4005_read_axis(struct mxc4005_data * data,unsigned int addr)164077377fcSTeodora Baluta static int mxc4005_read_axis(struct mxc4005_data *data,
165077377fcSTeodora Baluta 			     unsigned int addr)
166077377fcSTeodora Baluta {
167077377fcSTeodora Baluta 	__be16 reg;
168077377fcSTeodora Baluta 	int ret;
169077377fcSTeodora Baluta 
170b01401a2SJonathan Cameron 	ret = regmap_bulk_read(data->regmap, addr, &reg, sizeof(reg));
171077377fcSTeodora Baluta 	if (ret < 0) {
172077377fcSTeodora Baluta 		dev_err(data->dev, "failed to read reg %02x\n", addr);
173077377fcSTeodora Baluta 		return ret;
174077377fcSTeodora Baluta 	}
175077377fcSTeodora Baluta 
176077377fcSTeodora Baluta 	return be16_to_cpu(reg);
177077377fcSTeodora Baluta }
178077377fcSTeodora Baluta 
mxc4005_read_scale(struct mxc4005_data * data)179077377fcSTeodora Baluta static int mxc4005_read_scale(struct mxc4005_data *data)
180077377fcSTeodora Baluta {
181077377fcSTeodora Baluta 	unsigned int reg;
182077377fcSTeodora Baluta 	int ret;
183077377fcSTeodora Baluta 	int i;
184077377fcSTeodora Baluta 
185077377fcSTeodora Baluta 	ret = regmap_read(data->regmap, MXC4005_REG_CONTROL, &reg);
186077377fcSTeodora Baluta 	if (ret < 0) {
187077377fcSTeodora Baluta 		dev_err(data->dev, "failed to read reg_control\n");
188077377fcSTeodora Baluta 		return ret;
189077377fcSTeodora Baluta 	}
190077377fcSTeodora Baluta 
191077377fcSTeodora Baluta 	i = reg >> MXC4005_CONTROL_FSR_SHIFT;
192077377fcSTeodora Baluta 
193077377fcSTeodora Baluta 	if (i < 0 || i >= ARRAY_SIZE(mxc4005_scale_table))
194077377fcSTeodora Baluta 		return -EINVAL;
195077377fcSTeodora Baluta 
196077377fcSTeodora Baluta 	return mxc4005_scale_table[i].scale;
197077377fcSTeodora Baluta }
198077377fcSTeodora Baluta 
mxc4005_set_scale(struct mxc4005_data * data,int val)199077377fcSTeodora Baluta static int mxc4005_set_scale(struct mxc4005_data *data, int val)
200077377fcSTeodora Baluta {
201077377fcSTeodora Baluta 	unsigned int reg;
202077377fcSTeodora Baluta 	int i;
203077377fcSTeodora Baluta 	int ret;
204077377fcSTeodora Baluta 
205077377fcSTeodora Baluta 	for (i = 0; i < ARRAY_SIZE(mxc4005_scale_table); i++) {
206077377fcSTeodora Baluta 		if (mxc4005_scale_table[i].scale == val) {
207077377fcSTeodora Baluta 			reg = i << MXC4005_CONTROL_FSR_SHIFT;
208077377fcSTeodora Baluta 			ret = regmap_update_bits(data->regmap,
209077377fcSTeodora Baluta 						 MXC4005_REG_CONTROL,
210077377fcSTeodora Baluta 						 MXC4005_REG_CONTROL_MASK_FSR,
211077377fcSTeodora Baluta 						 reg);
212077377fcSTeodora Baluta 			if (ret < 0)
213077377fcSTeodora Baluta 				dev_err(data->dev,
214077377fcSTeodora Baluta 					"failed to write reg_control\n");
215077377fcSTeodora Baluta 			return ret;
216077377fcSTeodora Baluta 		}
217077377fcSTeodora Baluta 	}
218077377fcSTeodora Baluta 
219077377fcSTeodora Baluta 	return -EINVAL;
220077377fcSTeodora Baluta }
221077377fcSTeodora Baluta 
mxc4005_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)222077377fcSTeodora Baluta static int mxc4005_read_raw(struct iio_dev *indio_dev,
223077377fcSTeodora Baluta 			    struct iio_chan_spec const *chan,
224077377fcSTeodora Baluta 			    int *val, int *val2, long mask)
225077377fcSTeodora Baluta {
226077377fcSTeodora Baluta 	struct mxc4005_data *data = iio_priv(indio_dev);
227077377fcSTeodora Baluta 	int ret;
228077377fcSTeodora Baluta 
229077377fcSTeodora Baluta 	switch (mask) {
230077377fcSTeodora Baluta 	case IIO_CHAN_INFO_RAW:
231077377fcSTeodora Baluta 		switch (chan->type) {
232077377fcSTeodora Baluta 		case IIO_ACCEL:
233077377fcSTeodora Baluta 			if (iio_buffer_enabled(indio_dev))
234077377fcSTeodora Baluta 				return -EBUSY;
235077377fcSTeodora Baluta 
236077377fcSTeodora Baluta 			ret = mxc4005_read_axis(data, chan->address);
237077377fcSTeodora Baluta 			if (ret < 0)
238077377fcSTeodora Baluta 				return ret;
2391ce0eda0STeodora Baluta 			*val = sign_extend32(ret >> chan->scan_type.shift,
2401ce0eda0STeodora Baluta 					     chan->scan_type.realbits - 1);
241077377fcSTeodora Baluta 			return IIO_VAL_INT;
242077377fcSTeodora Baluta 		default:
243077377fcSTeodora Baluta 			return -EINVAL;
244077377fcSTeodora Baluta 		}
245077377fcSTeodora Baluta 	case IIO_CHAN_INFO_SCALE:
246077377fcSTeodora Baluta 		ret = mxc4005_read_scale(data);
247077377fcSTeodora Baluta 		if (ret < 0)
248077377fcSTeodora Baluta 			return ret;
249077377fcSTeodora Baluta 
250077377fcSTeodora Baluta 		*val = 0;
251077377fcSTeodora Baluta 		*val2 = ret;
252077377fcSTeodora Baluta 		return IIO_VAL_INT_PLUS_MICRO;
253077377fcSTeodora Baluta 	default:
254077377fcSTeodora Baluta 		return -EINVAL;
255077377fcSTeodora Baluta 	}
256077377fcSTeodora Baluta }
257077377fcSTeodora Baluta 
mxc4005_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)258077377fcSTeodora Baluta static int mxc4005_write_raw(struct iio_dev *indio_dev,
259077377fcSTeodora Baluta 			     struct iio_chan_spec const *chan,
260077377fcSTeodora Baluta 			     int val, int val2, long mask)
261077377fcSTeodora Baluta {
262077377fcSTeodora Baluta 	struct mxc4005_data *data = iio_priv(indio_dev);
263077377fcSTeodora Baluta 
264077377fcSTeodora Baluta 	switch (mask) {
265077377fcSTeodora Baluta 	case IIO_CHAN_INFO_SCALE:
266077377fcSTeodora Baluta 		if (val != 0)
267077377fcSTeodora Baluta 			return -EINVAL;
268077377fcSTeodora Baluta 
269077377fcSTeodora Baluta 		return mxc4005_set_scale(data, val2);
270077377fcSTeodora Baluta 	default:
271077377fcSTeodora Baluta 		return -EINVAL;
272077377fcSTeodora Baluta 	}
273077377fcSTeodora Baluta }
274077377fcSTeodora Baluta 
275077377fcSTeodora Baluta static const struct iio_info mxc4005_info = {
276077377fcSTeodora Baluta 	.read_raw	= mxc4005_read_raw,
277077377fcSTeodora Baluta 	.write_raw	= mxc4005_write_raw,
278077377fcSTeodora Baluta 	.attrs		= &mxc4005_attrs_group,
279077377fcSTeodora Baluta };
280077377fcSTeodora Baluta 
2811ce0eda0STeodora Baluta static const unsigned long mxc4005_scan_masks[] = {
2821ce0eda0STeodora Baluta 	BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z),
2831ce0eda0STeodora Baluta 	0
2841ce0eda0STeodora Baluta };
2851ce0eda0STeodora Baluta 
286077377fcSTeodora Baluta #define MXC4005_CHANNEL(_axis, _addr) {				\
287077377fcSTeodora Baluta 	.type = IIO_ACCEL,					\
288077377fcSTeodora Baluta 	.modified = 1,						\
289077377fcSTeodora Baluta 	.channel2 = IIO_MOD_##_axis,				\
290077377fcSTeodora Baluta 	.address = _addr,					\
291077377fcSTeodora Baluta 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
292077377fcSTeodora Baluta 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
2931ce0eda0STeodora Baluta 	.scan_index = AXIS_##_axis,				\
2941ce0eda0STeodora Baluta 	.scan_type = {						\
2951ce0eda0STeodora Baluta 		.sign = 's',					\
2961ce0eda0STeodora Baluta 		.realbits = 12,					\
2971ce0eda0STeodora Baluta 		.storagebits = 16,				\
2981ce0eda0STeodora Baluta 		.shift = 4,					\
2991ce0eda0STeodora Baluta 		.endianness = IIO_BE,				\
3001ce0eda0STeodora Baluta 	},							\
301077377fcSTeodora Baluta }
302077377fcSTeodora Baluta 
303077377fcSTeodora Baluta static const struct iio_chan_spec mxc4005_channels[] = {
304077377fcSTeodora Baluta 	MXC4005_CHANNEL(X, MXC4005_REG_XOUT_UPPER),
305077377fcSTeodora Baluta 	MXC4005_CHANNEL(Y, MXC4005_REG_YOUT_UPPER),
306077377fcSTeodora Baluta 	MXC4005_CHANNEL(Z, MXC4005_REG_ZOUT_UPPER),
3071ce0eda0STeodora Baluta 	IIO_CHAN_SOFT_TIMESTAMP(3),
308077377fcSTeodora Baluta };
309077377fcSTeodora Baluta 
mxc4005_trigger_handler(int irq,void * private)3101ce0eda0STeodora Baluta static irqreturn_t mxc4005_trigger_handler(int irq, void *private)
3111ce0eda0STeodora Baluta {
3121ce0eda0STeodora Baluta 	struct iio_poll_func *pf = private;
3131ce0eda0STeodora Baluta 	struct iio_dev *indio_dev = pf->indio_dev;
3141ce0eda0STeodora Baluta 	struct mxc4005_data *data = iio_priv(indio_dev);
3151ce0eda0STeodora Baluta 	int ret;
3161ce0eda0STeodora Baluta 
3171ce0eda0STeodora Baluta 	ret = mxc4005_read_xyz(data);
3181ce0eda0STeodora Baluta 	if (ret < 0)
3191ce0eda0STeodora Baluta 		goto err;
3201ce0eda0STeodora Baluta 
321f6580228SJonathan Cameron 	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
3221ce0eda0STeodora Baluta 					   pf->timestamp);
3231ce0eda0STeodora Baluta 
3241ce0eda0STeodora Baluta err:
3251ce0eda0STeodora Baluta 	iio_trigger_notify_done(indio_dev->trig);
3261ce0eda0STeodora Baluta 
3271ce0eda0STeodora Baluta 	return IRQ_HANDLED;
3281ce0eda0STeodora Baluta }
3291ce0eda0STeodora Baluta 
mxc4005_clr_intr(struct mxc4005_data * data)330eca8523aSJonathan Cameron static void mxc4005_clr_intr(struct mxc4005_data *data)
33147196620STeodora Baluta {
33247196620STeodora Baluta 	int ret;
33347196620STeodora Baluta 
33447196620STeodora Baluta 	/* clear interrupt */
33547196620STeodora Baluta 	ret = regmap_write(data->regmap, MXC4005_REG_INT_CLR1,
33647196620STeodora Baluta 			   MXC4005_REG_INT_CLR1_BIT_DRDYC);
337eca8523aSJonathan Cameron 	if (ret < 0)
33847196620STeodora Baluta 		dev_err(data->dev, "failed to write to reg_int_clr1\n");
33947196620STeodora Baluta }
34047196620STeodora Baluta 
mxc4005_set_trigger_state(struct iio_trigger * trig,bool state)34147196620STeodora Baluta static int mxc4005_set_trigger_state(struct iio_trigger *trig,
34247196620STeodora Baluta 				     bool state)
34347196620STeodora Baluta {
34447196620STeodora Baluta 	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
34547196620STeodora Baluta 	struct mxc4005_data *data = iio_priv(indio_dev);
3465eba2638SHans de Goede 	unsigned int val;
34747196620STeodora Baluta 	int ret;
34847196620STeodora Baluta 
34947196620STeodora Baluta 	mutex_lock(&data->mutex);
35047196620STeodora Baluta 
3515eba2638SHans de Goede 	val = state ? MXC4005_REG_INT_MASK1_BIT_DRDYE : 0;
3525eba2638SHans de Goede 	ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK1, val);
35347196620STeodora Baluta 	if (ret < 0) {
35447196620STeodora Baluta 		mutex_unlock(&data->mutex);
35547196620STeodora Baluta 		dev_err(data->dev, "failed to update reg_int_mask1");
35647196620STeodora Baluta 		return ret;
35747196620STeodora Baluta 	}
35847196620STeodora Baluta 
359f68f3e3fSHans de Goede 	data->int_mask1 = val;
36047196620STeodora Baluta 	data->trigger_enabled = state;
36147196620STeodora Baluta 	mutex_unlock(&data->mutex);
36247196620STeodora Baluta 
36347196620STeodora Baluta 	return 0;
36447196620STeodora Baluta }
36547196620STeodora Baluta 
mxc4005_trigger_reen(struct iio_trigger * trig)366eca8523aSJonathan Cameron static void mxc4005_trigger_reen(struct iio_trigger *trig)
36747196620STeodora Baluta {
36847196620STeodora Baluta 	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
36947196620STeodora Baluta 	struct mxc4005_data *data = iio_priv(indio_dev);
37047196620STeodora Baluta 
37147196620STeodora Baluta 	if (!data->dready_trig)
372eca8523aSJonathan Cameron 		return;
37347196620STeodora Baluta 
374eca8523aSJonathan Cameron 	mxc4005_clr_intr(data);
37547196620STeodora Baluta }
37647196620STeodora Baluta 
37747196620STeodora Baluta static const struct iio_trigger_ops mxc4005_trigger_ops = {
37847196620STeodora Baluta 	.set_trigger_state = mxc4005_set_trigger_state,
379eca8523aSJonathan Cameron 	.reenable = mxc4005_trigger_reen,
38047196620STeodora Baluta };
38147196620STeodora Baluta 
mxc4005_chip_init(struct mxc4005_data * data)382077377fcSTeodora Baluta static int mxc4005_chip_init(struct mxc4005_data *data)
383077377fcSTeodora Baluta {
384077377fcSTeodora Baluta 	int ret;
385077377fcSTeodora Baluta 	unsigned int reg;
386077377fcSTeodora Baluta 
387077377fcSTeodora Baluta 	ret = regmap_read(data->regmap, MXC4005_REG_DEVICE_ID, &reg);
388077377fcSTeodora Baluta 	if (ret < 0) {
389077377fcSTeodora Baluta 		dev_err(data->dev, "failed to read chip id\n");
390077377fcSTeodora Baluta 		return ret;
391077377fcSTeodora Baluta 	}
392077377fcSTeodora Baluta 
393077377fcSTeodora Baluta 	dev_dbg(data->dev, "MXC4005 chip id %02x\n", reg);
394077377fcSTeodora Baluta 
395f68f3e3fSHans de Goede 	ret = regmap_write(data->regmap, MXC4005_REG_INT_CLR1,
396f68f3e3fSHans de Goede 			   MXC4005_REG_INT_CLR1_SW_RST);
397f68f3e3fSHans de Goede 	if (ret < 0)
398f68f3e3fSHans de Goede 		return dev_err_probe(data->dev, ret, "resetting chip\n");
399f68f3e3fSHans de Goede 
400f68f3e3fSHans de Goede 	fsleep(MXC4005_RESET_TIME_US);
401f68f3e3fSHans de Goede 
4025eba2638SHans de Goede 	ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK0, 0);
4035eba2638SHans de Goede 	if (ret < 0)
4045eba2638SHans de Goede 		return dev_err_probe(data->dev, ret, "writing INT_MASK0\n");
4055eba2638SHans de Goede 
4065eba2638SHans de Goede 	ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK1, 0);
4075eba2638SHans de Goede 	if (ret < 0)
4085eba2638SHans de Goede 		return dev_err_probe(data->dev, ret, "writing INT_MASK1\n");
4095eba2638SHans de Goede 
410077377fcSTeodora Baluta 	return 0;
411077377fcSTeodora Baluta }
412077377fcSTeodora Baluta 
mxc4005_probe(struct i2c_client * client)413a97d9d95SUwe Kleine-König static int mxc4005_probe(struct i2c_client *client)
414077377fcSTeodora Baluta {
415077377fcSTeodora Baluta 	struct mxc4005_data *data;
416077377fcSTeodora Baluta 	struct iio_dev *indio_dev;
417077377fcSTeodora Baluta 	struct regmap *regmap;
418077377fcSTeodora Baluta 	int ret;
419077377fcSTeodora Baluta 
420077377fcSTeodora Baluta 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
421077377fcSTeodora Baluta 	if (!indio_dev)
422077377fcSTeodora Baluta 		return -ENOMEM;
423077377fcSTeodora Baluta 
424077377fcSTeodora Baluta 	regmap = devm_regmap_init_i2c(client, &mxc4005_regmap_config);
425077377fcSTeodora Baluta 	if (IS_ERR(regmap)) {
426077377fcSTeodora Baluta 		dev_err(&client->dev, "failed to initialize regmap\n");
427077377fcSTeodora Baluta 		return PTR_ERR(regmap);
428077377fcSTeodora Baluta 	}
429077377fcSTeodora Baluta 
430077377fcSTeodora Baluta 	data = iio_priv(indio_dev);
431077377fcSTeodora Baluta 	i2c_set_clientdata(client, indio_dev);
432077377fcSTeodora Baluta 	data->dev = &client->dev;
433077377fcSTeodora Baluta 	data->regmap = regmap;
434077377fcSTeodora Baluta 
435077377fcSTeodora Baluta 	ret = mxc4005_chip_init(data);
436077377fcSTeodora Baluta 	if (ret < 0) {
437077377fcSTeodora Baluta 		dev_err(&client->dev, "failed to initialize chip\n");
438077377fcSTeodora Baluta 		return ret;
439077377fcSTeodora Baluta 	}
440077377fcSTeodora Baluta 
441077377fcSTeodora Baluta 	mutex_init(&data->mutex);
442077377fcSTeodora Baluta 
443077377fcSTeodora Baluta 	indio_dev->channels = mxc4005_channels;
444077377fcSTeodora Baluta 	indio_dev->num_channels = ARRAY_SIZE(mxc4005_channels);
4451ce0eda0STeodora Baluta 	indio_dev->available_scan_masks = mxc4005_scan_masks;
446077377fcSTeodora Baluta 	indio_dev->name = MXC4005_DRV_NAME;
447077377fcSTeodora Baluta 	indio_dev->modes = INDIO_DIRECT_MODE;
448077377fcSTeodora Baluta 	indio_dev->info = &mxc4005_info;
449077377fcSTeodora Baluta 
4506e4707edSChuhong Yuan 	ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev,
45147196620STeodora Baluta 					 iio_pollfunc_store_time,
4521ce0eda0STeodora Baluta 					 mxc4005_trigger_handler,
4531ce0eda0STeodora Baluta 					 NULL);
4541ce0eda0STeodora Baluta 	if (ret < 0) {
4551ce0eda0STeodora Baluta 		dev_err(&client->dev,
4561ce0eda0STeodora Baluta 			"failed to setup iio triggered buffer\n");
4571ce0eda0STeodora Baluta 		return ret;
4581ce0eda0STeodora Baluta 	}
4591ce0eda0STeodora Baluta 
46047196620STeodora Baluta 	if (client->irq > 0) {
46147196620STeodora Baluta 		data->dready_trig = devm_iio_trigger_alloc(&client->dev,
46247196620STeodora Baluta 							   "%s-dev%d",
46347196620STeodora Baluta 							   indio_dev->name,
46415ea2878SJonathan Cameron 							   iio_device_id(indio_dev));
46547196620STeodora Baluta 		if (!data->dready_trig)
46647196620STeodora Baluta 			return -ENOMEM;
46747196620STeodora Baluta 
46847196620STeodora Baluta 		ret = devm_request_threaded_irq(&client->dev, client->irq,
46947196620STeodora Baluta 						iio_trigger_generic_data_rdy_poll,
47047196620STeodora Baluta 						NULL,
47147196620STeodora Baluta 						IRQF_TRIGGER_FALLING |
47247196620STeodora Baluta 						IRQF_ONESHOT,
47347196620STeodora Baluta 						MXC4005_IRQ_NAME,
47447196620STeodora Baluta 						data->dready_trig);
47547196620STeodora Baluta 		if (ret) {
47647196620STeodora Baluta 			dev_err(&client->dev,
47747196620STeodora Baluta 				"failed to init threaded irq\n");
4786e4707edSChuhong Yuan 			return ret;
47947196620STeodora Baluta 		}
48047196620STeodora Baluta 
48147196620STeodora Baluta 		data->dready_trig->ops = &mxc4005_trigger_ops;
48247196620STeodora Baluta 		iio_trigger_set_drvdata(data->dready_trig, indio_dev);
4836e4707edSChuhong Yuan 		ret = devm_iio_trigger_register(&client->dev,
4846e4707edSChuhong Yuan 						data->dready_trig);
48547196620STeodora Baluta 		if (ret) {
48647196620STeodora Baluta 			dev_err(&client->dev,
48747196620STeodora Baluta 				"failed to register trigger\n");
4881ce0eda0STeodora Baluta 			return ret;
489077377fcSTeodora Baluta 		}
4909354c224SDmitry Rokosov 
4919354c224SDmitry Rokosov 		indio_dev->trig = iio_trigger_get(data->dready_trig);
4926e4707edSChuhong Yuan 	}
493077377fcSTeodora Baluta 
4946e4707edSChuhong Yuan 	return devm_iio_device_register(&client->dev, indio_dev);
495077377fcSTeodora Baluta }
496077377fcSTeodora Baluta 
mxc4005_suspend(struct device * dev)497f68f3e3fSHans de Goede static int mxc4005_suspend(struct device *dev)
498f68f3e3fSHans de Goede {
499f68f3e3fSHans de Goede 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
500f68f3e3fSHans de Goede 	struct mxc4005_data *data = iio_priv(indio_dev);
501f68f3e3fSHans de Goede 	int ret;
502f68f3e3fSHans de Goede 
503f68f3e3fSHans de Goede 	/* Save control to restore it on resume */
504f68f3e3fSHans de Goede 	ret = regmap_read(data->regmap, MXC4005_REG_CONTROL, &data->control);
505f68f3e3fSHans de Goede 	if (ret < 0)
506f68f3e3fSHans de Goede 		dev_err(data->dev, "failed to read reg_control\n");
507f68f3e3fSHans de Goede 
508f68f3e3fSHans de Goede 	return ret;
509f68f3e3fSHans de Goede }
510f68f3e3fSHans de Goede 
mxc4005_resume(struct device * dev)511f68f3e3fSHans de Goede static int mxc4005_resume(struct device *dev)
512f68f3e3fSHans de Goede {
513f68f3e3fSHans de Goede 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
514f68f3e3fSHans de Goede 	struct mxc4005_data *data = iio_priv(indio_dev);
515f68f3e3fSHans de Goede 	int ret;
516f68f3e3fSHans de Goede 
517f68f3e3fSHans de Goede 	ret = regmap_write(data->regmap, MXC4005_REG_INT_CLR1,
518f68f3e3fSHans de Goede 			   MXC4005_REG_INT_CLR1_SW_RST);
519f68f3e3fSHans de Goede 	if (ret) {
520f68f3e3fSHans de Goede 		dev_err(data->dev, "failed to reset chip: %d\n", ret);
521f68f3e3fSHans de Goede 		return ret;
522f68f3e3fSHans de Goede 	}
523f68f3e3fSHans de Goede 
524f68f3e3fSHans de Goede 	fsleep(MXC4005_RESET_TIME_US);
525f68f3e3fSHans de Goede 
526f68f3e3fSHans de Goede 	ret = regmap_write(data->regmap, MXC4005_REG_CONTROL, data->control);
527f68f3e3fSHans de Goede 	if (ret) {
528f68f3e3fSHans de Goede 		dev_err(data->dev, "failed to restore control register\n");
529f68f3e3fSHans de Goede 		return ret;
530f68f3e3fSHans de Goede 	}
531f68f3e3fSHans de Goede 
532f68f3e3fSHans de Goede 	ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK0, 0);
533f68f3e3fSHans de Goede 	if (ret) {
534f68f3e3fSHans de Goede 		dev_err(data->dev, "failed to restore interrupt 0 mask\n");
535f68f3e3fSHans de Goede 		return ret;
536f68f3e3fSHans de Goede 	}
537f68f3e3fSHans de Goede 
538f68f3e3fSHans de Goede 	ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK1, data->int_mask1);
539f68f3e3fSHans de Goede 	if (ret) {
540f68f3e3fSHans de Goede 		dev_err(data->dev, "failed to restore interrupt 1 mask\n");
541f68f3e3fSHans de Goede 		return ret;
542f68f3e3fSHans de Goede 	}
543f68f3e3fSHans de Goede 
544f68f3e3fSHans de Goede 	return 0;
545f68f3e3fSHans de Goede }
546f68f3e3fSHans de Goede 
547f68f3e3fSHans de Goede static DEFINE_SIMPLE_DEV_PM_OPS(mxc4005_pm_ops, mxc4005_suspend, mxc4005_resume);
548f68f3e3fSHans de Goede 
549077377fcSTeodora Baluta static const struct acpi_device_id mxc4005_acpi_match[] = {
550077377fcSTeodora Baluta 	{"MXC4005",	0},
55179846e33SChristian Oder 	{"MXC6655",	0},
552077377fcSTeodora Baluta 	{ },
553077377fcSTeodora Baluta };
554077377fcSTeodora Baluta MODULE_DEVICE_TABLE(acpi, mxc4005_acpi_match);
555077377fcSTeodora Baluta 
55643424f70SLuca Ceresoli static const struct of_device_id mxc4005_of_match[] = {
55743424f70SLuca Ceresoli 	{ .compatible = "memsic,mxc4005", },
55843424f70SLuca Ceresoli 	{ .compatible = "memsic,mxc6655", },
55943424f70SLuca Ceresoli 	{ },
56043424f70SLuca Ceresoli };
56143424f70SLuca Ceresoli MODULE_DEVICE_TABLE(of, mxc4005_of_match);
56243424f70SLuca Ceresoli 
563077377fcSTeodora Baluta static const struct i2c_device_id mxc4005_id[] = {
564077377fcSTeodora Baluta 	{"mxc4005",	0},
56579846e33SChristian Oder 	{"mxc6655",	0},
566077377fcSTeodora Baluta 	{ },
567077377fcSTeodora Baluta };
568077377fcSTeodora Baluta MODULE_DEVICE_TABLE(i2c, mxc4005_id);
569077377fcSTeodora Baluta 
570077377fcSTeodora Baluta static struct i2c_driver mxc4005_driver = {
571077377fcSTeodora Baluta 	.driver = {
572077377fcSTeodora Baluta 		.name = MXC4005_DRV_NAME,
573077377fcSTeodora Baluta 		.acpi_match_table = ACPI_PTR(mxc4005_acpi_match),
57443424f70SLuca Ceresoli 		.of_match_table = mxc4005_of_match,
575f68f3e3fSHans de Goede 		.pm = pm_sleep_ptr(&mxc4005_pm_ops),
576077377fcSTeodora Baluta 	},
5777cf15f42SUwe Kleine-König 	.probe		= mxc4005_probe,
578077377fcSTeodora Baluta 	.id_table	= mxc4005_id,
579077377fcSTeodora Baluta };
580077377fcSTeodora Baluta 
581077377fcSTeodora Baluta module_i2c_driver(mxc4005_driver);
582077377fcSTeodora Baluta 
583077377fcSTeodora Baluta MODULE_AUTHOR("Teodora Baluta <teodora.baluta@intel.com>");
584077377fcSTeodora Baluta MODULE_LICENSE("GPL v2");
585077377fcSTeodora Baluta MODULE_DESCRIPTION("MXC4005 3-axis accelerometer driver");
586