1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * 3-axis accelerometer driver for MXC4005XC Memsic sensor |
4 | * |
5 | * Copyright (c) 2014, Intel Corporation. |
6 | */ |
7 | |
8 | #include <linux/module.h> |
9 | #include <linux/i2c.h> |
10 | #include <linux/iio/iio.h> |
11 | #include <linux/acpi.h> |
12 | #include <linux/regmap.h> |
13 | #include <linux/iio/sysfs.h> |
14 | #include <linux/iio/trigger.h> |
15 | #include <linux/iio/buffer.h> |
16 | #include <linux/iio/triggered_buffer.h> |
17 | #include <linux/iio/trigger_consumer.h> |
18 | |
19 | #define MXC4005_DRV_NAME "mxc4005" |
20 | #define MXC4005_IRQ_NAME "mxc4005_event" |
21 | #define MXC4005_REGMAP_NAME "mxc4005_regmap" |
22 | |
23 | #define MXC4005_REG_XOUT_UPPER 0x03 |
24 | #define MXC4005_REG_XOUT_LOWER 0x04 |
25 | #define MXC4005_REG_YOUT_UPPER 0x05 |
26 | #define MXC4005_REG_YOUT_LOWER 0x06 |
27 | #define MXC4005_REG_ZOUT_UPPER 0x07 |
28 | #define MXC4005_REG_ZOUT_LOWER 0x08 |
29 | |
30 | #define MXC4005_REG_INT_MASK1 0x0B |
31 | #define MXC4005_REG_INT_MASK1_BIT_DRDYE 0x01 |
32 | |
33 | #define MXC4005_REG_INT_CLR1 0x01 |
34 | #define MXC4005_REG_INT_CLR1_BIT_DRDYC 0x01 |
35 | |
36 | #define MXC4005_REG_CONTROL 0x0D |
37 | #define MXC4005_REG_CONTROL_MASK_FSR GENMASK(6, 5) |
38 | #define MXC4005_CONTROL_FSR_SHIFT 5 |
39 | |
40 | #define MXC4005_REG_DEVICE_ID 0x0E |
41 | |
42 | enum mxc4005_axis { |
43 | AXIS_X, |
44 | AXIS_Y, |
45 | AXIS_Z, |
46 | }; |
47 | |
48 | enum mxc4005_range { |
49 | MXC4005_RANGE_2G, |
50 | MXC4005_RANGE_4G, |
51 | MXC4005_RANGE_8G, |
52 | }; |
53 | |
54 | struct mxc4005_data { |
55 | struct device *dev; |
56 | struct mutex mutex; |
57 | struct regmap *regmap; |
58 | struct iio_trigger *dready_trig; |
59 | /* Ensure timestamp is naturally aligned */ |
60 | struct { |
61 | __be16 chans[3]; |
62 | s64 timestamp __aligned(8); |
63 | } scan; |
64 | bool trigger_enabled; |
65 | }; |
66 | |
67 | /* |
68 | * MXC4005 can operate in the following ranges: |
69 | * +/- 2G, 4G, 8G (the default +/-2G) |
70 | * |
71 | * (2 + 2) * 9.81 / (2^12 - 1) = 0.009582 |
72 | * (4 + 4) * 9.81 / (2^12 - 1) = 0.019164 |
73 | * (8 + 8) * 9.81 / (2^12 - 1) = 0.038329 |
74 | */ |
75 | static const struct { |
76 | u8 range; |
77 | int scale; |
78 | } mxc4005_scale_table[] = { |
79 | {MXC4005_RANGE_2G, 9582}, |
80 | {MXC4005_RANGE_4G, 19164}, |
81 | {MXC4005_RANGE_8G, 38329}, |
82 | }; |
83 | |
84 | |
85 | static IIO_CONST_ATTR(in_accel_scale_available, "0.009582 0.019164 0.038329" ); |
86 | |
87 | static struct attribute *mxc4005_attributes[] = { |
88 | &iio_const_attr_in_accel_scale_available.dev_attr.attr, |
89 | NULL, |
90 | }; |
91 | |
92 | static const struct attribute_group mxc4005_attrs_group = { |
93 | .attrs = mxc4005_attributes, |
94 | }; |
95 | |
96 | static bool mxc4005_is_readable_reg(struct device *dev, unsigned int reg) |
97 | { |
98 | switch (reg) { |
99 | case MXC4005_REG_XOUT_UPPER: |
100 | case MXC4005_REG_XOUT_LOWER: |
101 | case MXC4005_REG_YOUT_UPPER: |
102 | case MXC4005_REG_YOUT_LOWER: |
103 | case MXC4005_REG_ZOUT_UPPER: |
104 | case MXC4005_REG_ZOUT_LOWER: |
105 | case MXC4005_REG_DEVICE_ID: |
106 | case MXC4005_REG_CONTROL: |
107 | return true; |
108 | default: |
109 | return false; |
110 | } |
111 | } |
112 | |
113 | static bool mxc4005_is_writeable_reg(struct device *dev, unsigned int reg) |
114 | { |
115 | switch (reg) { |
116 | case MXC4005_REG_INT_CLR1: |
117 | case MXC4005_REG_INT_MASK1: |
118 | case MXC4005_REG_CONTROL: |
119 | return true; |
120 | default: |
121 | return false; |
122 | } |
123 | } |
124 | |
125 | static const struct regmap_config mxc4005_regmap_config = { |
126 | .name = MXC4005_REGMAP_NAME, |
127 | |
128 | .reg_bits = 8, |
129 | .val_bits = 8, |
130 | |
131 | .max_register = MXC4005_REG_DEVICE_ID, |
132 | |
133 | .readable_reg = mxc4005_is_readable_reg, |
134 | .writeable_reg = mxc4005_is_writeable_reg, |
135 | }; |
136 | |
137 | static int mxc4005_read_xyz(struct mxc4005_data *data) |
138 | { |
139 | int ret; |
140 | |
141 | ret = regmap_bulk_read(map: data->regmap, MXC4005_REG_XOUT_UPPER, |
142 | val: data->scan.chans, val_count: sizeof(data->scan.chans)); |
143 | if (ret < 0) { |
144 | dev_err(data->dev, "failed to read axes\n" ); |
145 | return ret; |
146 | } |
147 | |
148 | return 0; |
149 | } |
150 | |
151 | static int mxc4005_read_axis(struct mxc4005_data *data, |
152 | unsigned int addr) |
153 | { |
154 | __be16 reg; |
155 | int ret; |
156 | |
157 | ret = regmap_bulk_read(map: data->regmap, reg: addr, val: ®, val_count: sizeof(reg)); |
158 | if (ret < 0) { |
159 | dev_err(data->dev, "failed to read reg %02x\n" , addr); |
160 | return ret; |
161 | } |
162 | |
163 | return be16_to_cpu(reg); |
164 | } |
165 | |
166 | static int mxc4005_read_scale(struct mxc4005_data *data) |
167 | { |
168 | unsigned int reg; |
169 | int ret; |
170 | int i; |
171 | |
172 | ret = regmap_read(map: data->regmap, MXC4005_REG_CONTROL, val: ®); |
173 | if (ret < 0) { |
174 | dev_err(data->dev, "failed to read reg_control\n" ); |
175 | return ret; |
176 | } |
177 | |
178 | i = reg >> MXC4005_CONTROL_FSR_SHIFT; |
179 | |
180 | if (i < 0 || i >= ARRAY_SIZE(mxc4005_scale_table)) |
181 | return -EINVAL; |
182 | |
183 | return mxc4005_scale_table[i].scale; |
184 | } |
185 | |
186 | static int mxc4005_set_scale(struct mxc4005_data *data, int val) |
187 | { |
188 | unsigned int reg; |
189 | int i; |
190 | int ret; |
191 | |
192 | for (i = 0; i < ARRAY_SIZE(mxc4005_scale_table); i++) { |
193 | if (mxc4005_scale_table[i].scale == val) { |
194 | reg = i << MXC4005_CONTROL_FSR_SHIFT; |
195 | ret = regmap_update_bits(map: data->regmap, |
196 | MXC4005_REG_CONTROL, |
197 | MXC4005_REG_CONTROL_MASK_FSR, |
198 | val: reg); |
199 | if (ret < 0) |
200 | dev_err(data->dev, |
201 | "failed to write reg_control\n" ); |
202 | return ret; |
203 | } |
204 | } |
205 | |
206 | return -EINVAL; |
207 | } |
208 | |
209 | static int mxc4005_read_raw(struct iio_dev *indio_dev, |
210 | struct iio_chan_spec const *chan, |
211 | int *val, int *val2, long mask) |
212 | { |
213 | struct mxc4005_data *data = iio_priv(indio_dev); |
214 | int ret; |
215 | |
216 | switch (mask) { |
217 | case IIO_CHAN_INFO_RAW: |
218 | switch (chan->type) { |
219 | case IIO_ACCEL: |
220 | if (iio_buffer_enabled(indio_dev)) |
221 | return -EBUSY; |
222 | |
223 | ret = mxc4005_read_axis(data, addr: chan->address); |
224 | if (ret < 0) |
225 | return ret; |
226 | *val = sign_extend32(value: ret >> chan->scan_type.shift, |
227 | index: chan->scan_type.realbits - 1); |
228 | return IIO_VAL_INT; |
229 | default: |
230 | return -EINVAL; |
231 | } |
232 | case IIO_CHAN_INFO_SCALE: |
233 | ret = mxc4005_read_scale(data); |
234 | if (ret < 0) |
235 | return ret; |
236 | |
237 | *val = 0; |
238 | *val2 = ret; |
239 | return IIO_VAL_INT_PLUS_MICRO; |
240 | default: |
241 | return -EINVAL; |
242 | } |
243 | } |
244 | |
245 | static int mxc4005_write_raw(struct iio_dev *indio_dev, |
246 | struct iio_chan_spec const *chan, |
247 | int val, int val2, long mask) |
248 | { |
249 | struct mxc4005_data *data = iio_priv(indio_dev); |
250 | |
251 | switch (mask) { |
252 | case IIO_CHAN_INFO_SCALE: |
253 | if (val != 0) |
254 | return -EINVAL; |
255 | |
256 | return mxc4005_set_scale(data, val: val2); |
257 | default: |
258 | return -EINVAL; |
259 | } |
260 | } |
261 | |
262 | static const struct iio_info mxc4005_info = { |
263 | .read_raw = mxc4005_read_raw, |
264 | .write_raw = mxc4005_write_raw, |
265 | .attrs = &mxc4005_attrs_group, |
266 | }; |
267 | |
268 | static const unsigned long mxc4005_scan_masks[] = { |
269 | BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z), |
270 | 0 |
271 | }; |
272 | |
273 | #define MXC4005_CHANNEL(_axis, _addr) { \ |
274 | .type = IIO_ACCEL, \ |
275 | .modified = 1, \ |
276 | .channel2 = IIO_MOD_##_axis, \ |
277 | .address = _addr, \ |
278 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ |
279 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ |
280 | .scan_index = AXIS_##_axis, \ |
281 | .scan_type = { \ |
282 | .sign = 's', \ |
283 | .realbits = 12, \ |
284 | .storagebits = 16, \ |
285 | .shift = 4, \ |
286 | .endianness = IIO_BE, \ |
287 | }, \ |
288 | } |
289 | |
290 | static const struct iio_chan_spec mxc4005_channels[] = { |
291 | MXC4005_CHANNEL(X, MXC4005_REG_XOUT_UPPER), |
292 | MXC4005_CHANNEL(Y, MXC4005_REG_YOUT_UPPER), |
293 | MXC4005_CHANNEL(Z, MXC4005_REG_ZOUT_UPPER), |
294 | IIO_CHAN_SOFT_TIMESTAMP(3), |
295 | }; |
296 | |
297 | static irqreturn_t mxc4005_trigger_handler(int irq, void *private) |
298 | { |
299 | struct iio_poll_func *pf = private; |
300 | struct iio_dev *indio_dev = pf->indio_dev; |
301 | struct mxc4005_data *data = iio_priv(indio_dev); |
302 | int ret; |
303 | |
304 | ret = mxc4005_read_xyz(data); |
305 | if (ret < 0) |
306 | goto err; |
307 | |
308 | iio_push_to_buffers_with_timestamp(indio_dev, data: &data->scan, |
309 | timestamp: pf->timestamp); |
310 | |
311 | err: |
312 | iio_trigger_notify_done(trig: indio_dev->trig); |
313 | |
314 | return IRQ_HANDLED; |
315 | } |
316 | |
317 | static void mxc4005_clr_intr(struct mxc4005_data *data) |
318 | { |
319 | int ret; |
320 | |
321 | /* clear interrupt */ |
322 | ret = regmap_write(map: data->regmap, MXC4005_REG_INT_CLR1, |
323 | MXC4005_REG_INT_CLR1_BIT_DRDYC); |
324 | if (ret < 0) |
325 | dev_err(data->dev, "failed to write to reg_int_clr1\n" ); |
326 | } |
327 | |
328 | static int mxc4005_set_trigger_state(struct iio_trigger *trig, |
329 | bool state) |
330 | { |
331 | struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); |
332 | struct mxc4005_data *data = iio_priv(indio_dev); |
333 | int ret; |
334 | |
335 | mutex_lock(&data->mutex); |
336 | if (state) { |
337 | ret = regmap_write(map: data->regmap, MXC4005_REG_INT_MASK1, |
338 | MXC4005_REG_INT_MASK1_BIT_DRDYE); |
339 | } else { |
340 | ret = regmap_write(map: data->regmap, MXC4005_REG_INT_MASK1, |
341 | val: ~MXC4005_REG_INT_MASK1_BIT_DRDYE); |
342 | } |
343 | |
344 | if (ret < 0) { |
345 | mutex_unlock(lock: &data->mutex); |
346 | dev_err(data->dev, "failed to update reg_int_mask1" ); |
347 | return ret; |
348 | } |
349 | |
350 | data->trigger_enabled = state; |
351 | mutex_unlock(lock: &data->mutex); |
352 | |
353 | return 0; |
354 | } |
355 | |
356 | static void mxc4005_trigger_reen(struct iio_trigger *trig) |
357 | { |
358 | struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); |
359 | struct mxc4005_data *data = iio_priv(indio_dev); |
360 | |
361 | if (!data->dready_trig) |
362 | return; |
363 | |
364 | mxc4005_clr_intr(data); |
365 | } |
366 | |
367 | static const struct iio_trigger_ops mxc4005_trigger_ops = { |
368 | .set_trigger_state = mxc4005_set_trigger_state, |
369 | .reenable = mxc4005_trigger_reen, |
370 | }; |
371 | |
372 | static int mxc4005_chip_init(struct mxc4005_data *data) |
373 | { |
374 | int ret; |
375 | unsigned int reg; |
376 | |
377 | ret = regmap_read(map: data->regmap, MXC4005_REG_DEVICE_ID, val: ®); |
378 | if (ret < 0) { |
379 | dev_err(data->dev, "failed to read chip id\n" ); |
380 | return ret; |
381 | } |
382 | |
383 | dev_dbg(data->dev, "MXC4005 chip id %02x\n" , reg); |
384 | |
385 | return 0; |
386 | } |
387 | |
388 | static int mxc4005_probe(struct i2c_client *client) |
389 | { |
390 | struct mxc4005_data *data; |
391 | struct iio_dev *indio_dev; |
392 | struct regmap *regmap; |
393 | int ret; |
394 | |
395 | indio_dev = devm_iio_device_alloc(parent: &client->dev, sizeof_priv: sizeof(*data)); |
396 | if (!indio_dev) |
397 | return -ENOMEM; |
398 | |
399 | regmap = devm_regmap_init_i2c(client, &mxc4005_regmap_config); |
400 | if (IS_ERR(ptr: regmap)) { |
401 | dev_err(&client->dev, "failed to initialize regmap\n" ); |
402 | return PTR_ERR(ptr: regmap); |
403 | } |
404 | |
405 | data = iio_priv(indio_dev); |
406 | i2c_set_clientdata(client, data: indio_dev); |
407 | data->dev = &client->dev; |
408 | data->regmap = regmap; |
409 | |
410 | ret = mxc4005_chip_init(data); |
411 | if (ret < 0) { |
412 | dev_err(&client->dev, "failed to initialize chip\n" ); |
413 | return ret; |
414 | } |
415 | |
416 | mutex_init(&data->mutex); |
417 | |
418 | indio_dev->channels = mxc4005_channels; |
419 | indio_dev->num_channels = ARRAY_SIZE(mxc4005_channels); |
420 | indio_dev->available_scan_masks = mxc4005_scan_masks; |
421 | indio_dev->name = MXC4005_DRV_NAME; |
422 | indio_dev->modes = INDIO_DIRECT_MODE; |
423 | indio_dev->info = &mxc4005_info; |
424 | |
425 | ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, |
426 | iio_pollfunc_store_time, |
427 | mxc4005_trigger_handler, |
428 | NULL); |
429 | if (ret < 0) { |
430 | dev_err(&client->dev, |
431 | "failed to setup iio triggered buffer\n" ); |
432 | return ret; |
433 | } |
434 | |
435 | if (client->irq > 0) { |
436 | data->dready_trig = devm_iio_trigger_alloc(&client->dev, |
437 | "%s-dev%d" , |
438 | indio_dev->name, |
439 | iio_device_id(indio_dev)); |
440 | if (!data->dready_trig) |
441 | return -ENOMEM; |
442 | |
443 | ret = devm_request_threaded_irq(dev: &client->dev, irq: client->irq, |
444 | handler: iio_trigger_generic_data_rdy_poll, |
445 | NULL, |
446 | IRQF_TRIGGER_FALLING | |
447 | IRQF_ONESHOT, |
448 | MXC4005_IRQ_NAME, |
449 | dev_id: data->dready_trig); |
450 | if (ret) { |
451 | dev_err(&client->dev, |
452 | "failed to init threaded irq\n" ); |
453 | return ret; |
454 | } |
455 | |
456 | data->dready_trig->ops = &mxc4005_trigger_ops; |
457 | iio_trigger_set_drvdata(trig: data->dready_trig, data: indio_dev); |
458 | ret = devm_iio_trigger_register(dev: &client->dev, |
459 | trig_info: data->dready_trig); |
460 | if (ret) { |
461 | dev_err(&client->dev, |
462 | "failed to register trigger\n" ); |
463 | return ret; |
464 | } |
465 | |
466 | indio_dev->trig = iio_trigger_get(trig: data->dready_trig); |
467 | } |
468 | |
469 | return devm_iio_device_register(&client->dev, indio_dev); |
470 | } |
471 | |
472 | static const struct acpi_device_id mxc4005_acpi_match[] = { |
473 | {"MXC4005" , 0}, |
474 | {"MXC6655" , 0}, |
475 | { }, |
476 | }; |
477 | MODULE_DEVICE_TABLE(acpi, mxc4005_acpi_match); |
478 | |
479 | static const struct of_device_id mxc4005_of_match[] = { |
480 | { .compatible = "memsic,mxc4005" , }, |
481 | { .compatible = "memsic,mxc6655" , }, |
482 | { }, |
483 | }; |
484 | MODULE_DEVICE_TABLE(of, mxc4005_of_match); |
485 | |
486 | static const struct i2c_device_id mxc4005_id[] = { |
487 | {"mxc4005" , 0}, |
488 | {"mxc6655" , 0}, |
489 | { }, |
490 | }; |
491 | MODULE_DEVICE_TABLE(i2c, mxc4005_id); |
492 | |
493 | static struct i2c_driver mxc4005_driver = { |
494 | .driver = { |
495 | .name = MXC4005_DRV_NAME, |
496 | .acpi_match_table = ACPI_PTR(mxc4005_acpi_match), |
497 | .of_match_table = mxc4005_of_match, |
498 | }, |
499 | .probe = mxc4005_probe, |
500 | .id_table = mxc4005_id, |
501 | }; |
502 | |
503 | module_i2c_driver(mxc4005_driver); |
504 | |
505 | MODULE_AUTHOR("Teodora Baluta <teodora.baluta@intel.com>" ); |
506 | MODULE_LICENSE("GPL v2" ); |
507 | MODULE_DESCRIPTION("MXC4005 3-axis accelerometer driver" ); |
508 | |