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, ®, 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, ®);
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, ®);
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