diff options
author | Teodora Baluta <teodora.baluta@intel.com> | 2015-08-20 10:37:33 -0400 |
---|---|---|
committer | Jonathan Cameron <jic23@kernel.org> | 2015-08-31 12:58:49 -0400 |
commit | 47196620c82f8d8cef0dc61b87b76f18278537dd (patch) | |
tree | 3f2feb9f2aba1c7be26d2811567047b047f32505 | |
parent | 1ce0eda0f75747b3131a9047aee19291f59c18c9 (diff) |
iio: mxc4005: add data ready trigger for mxc4005
Add iio trigger for the data ready interrupt that signals new
measurements for the X, Y and Z axes.
Signed-off-by: Teodora Baluta <teodora.baluta@intel.com>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
-rw-r--r-- | drivers/iio/accel/mxc4005.c | 142 |
1 files changed, 141 insertions, 1 deletions
diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c index 390eaf8cb2f8..e72e218c2696 100644 --- a/drivers/iio/accel/mxc4005.c +++ b/drivers/iio/accel/mxc4005.c | |||
@@ -17,13 +17,16 @@ | |||
17 | #include <linux/i2c.h> | 17 | #include <linux/i2c.h> |
18 | #include <linux/iio/iio.h> | 18 | #include <linux/iio/iio.h> |
19 | #include <linux/acpi.h> | 19 | #include <linux/acpi.h> |
20 | #include <linux/gpio/consumer.h> | ||
20 | #include <linux/regmap.h> | 21 | #include <linux/regmap.h> |
21 | #include <linux/iio/sysfs.h> | 22 | #include <linux/iio/sysfs.h> |
23 | #include <linux/iio/trigger.h> | ||
22 | #include <linux/iio/buffer.h> | 24 | #include <linux/iio/buffer.h> |
23 | #include <linux/iio/triggered_buffer.h> | 25 | #include <linux/iio/triggered_buffer.h> |
24 | #include <linux/iio/trigger_consumer.h> | 26 | #include <linux/iio/trigger_consumer.h> |
25 | 27 | ||
26 | #define MXC4005_DRV_NAME "mxc4005" | 28 | #define MXC4005_DRV_NAME "mxc4005" |
29 | #define MXC4005_IRQ_NAME "mxc4005_event" | ||
27 | #define MXC4005_REGMAP_NAME "mxc4005_regmap" | 30 | #define MXC4005_REGMAP_NAME "mxc4005_regmap" |
28 | 31 | ||
29 | #define MXC4005_REG_XOUT_UPPER 0x03 | 32 | #define MXC4005_REG_XOUT_UPPER 0x03 |
@@ -33,6 +36,12 @@ | |||
33 | #define MXC4005_REG_ZOUT_UPPER 0x07 | 36 | #define MXC4005_REG_ZOUT_UPPER 0x07 |
34 | #define MXC4005_REG_ZOUT_LOWER 0x08 | 37 | #define MXC4005_REG_ZOUT_LOWER 0x08 |
35 | 38 | ||
39 | #define MXC4005_REG_INT_MASK1 0x0B | ||
40 | #define MXC4005_REG_INT_MASK1_BIT_DRDYE 0x01 | ||
41 | |||
42 | #define MXC4005_REG_INT_CLR1 0x01 | ||
43 | #define MXC4005_REG_INT_CLR1_BIT_DRDYC 0x01 | ||
44 | |||
36 | #define MXC4005_REG_CONTROL 0x0D | 45 | #define MXC4005_REG_CONTROL 0x0D |
37 | #define MXC4005_REG_CONTROL_MASK_FSR GENMASK(6, 5) | 46 | #define MXC4005_REG_CONTROL_MASK_FSR GENMASK(6, 5) |
38 | #define MXC4005_CONTROL_FSR_SHIFT 5 | 47 | #define MXC4005_CONTROL_FSR_SHIFT 5 |
@@ -55,7 +64,9 @@ struct mxc4005_data { | |||
55 | struct device *dev; | 64 | struct device *dev; |
56 | struct mutex mutex; | 65 | struct mutex mutex; |
57 | struct regmap *regmap; | 66 | struct regmap *regmap; |
67 | struct iio_trigger *dready_trig; | ||
58 | __be16 buffer[8]; | 68 | __be16 buffer[8]; |
69 | bool trigger_enabled; | ||
59 | }; | 70 | }; |
60 | 71 | ||
61 | /* | 72 | /* |
@@ -107,6 +118,8 @@ static bool mxc4005_is_readable_reg(struct device *dev, unsigned int reg) | |||
107 | static bool mxc4005_is_writeable_reg(struct device *dev, unsigned int reg) | 118 | static bool mxc4005_is_writeable_reg(struct device *dev, unsigned int reg) |
108 | { | 119 | { |
109 | switch (reg) { | 120 | switch (reg) { |
121 | case MXC4005_REG_INT_CLR1: | ||
122 | case MXC4005_REG_INT_MASK1: | ||
110 | case MXC4005_REG_CONTROL: | 123 | case MXC4005_REG_CONTROL: |
111 | return true; | 124 | return true; |
112 | default: | 125 | default: |
@@ -307,6 +320,91 @@ err: | |||
307 | return IRQ_HANDLED; | 320 | return IRQ_HANDLED; |
308 | } | 321 | } |
309 | 322 | ||
323 | static int mxc4005_clr_intr(struct mxc4005_data *data) | ||
324 | { | ||
325 | int ret; | ||
326 | |||
327 | /* clear interrupt */ | ||
328 | ret = regmap_write(data->regmap, MXC4005_REG_INT_CLR1, | ||
329 | MXC4005_REG_INT_CLR1_BIT_DRDYC); | ||
330 | if (ret < 0) { | ||
331 | dev_err(data->dev, "failed to write to reg_int_clr1\n"); | ||
332 | return ret; | ||
333 | } | ||
334 | |||
335 | return 0; | ||
336 | } | ||
337 | |||
338 | static int mxc4005_set_trigger_state(struct iio_trigger *trig, | ||
339 | bool state) | ||
340 | { | ||
341 | struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); | ||
342 | struct mxc4005_data *data = iio_priv(indio_dev); | ||
343 | int ret; | ||
344 | |||
345 | mutex_lock(&data->mutex); | ||
346 | if (state) { | ||
347 | ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK1, | ||
348 | MXC4005_REG_INT_MASK1_BIT_DRDYE); | ||
349 | } else { | ||
350 | ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK1, | ||
351 | ~MXC4005_REG_INT_MASK1_BIT_DRDYE); | ||
352 | } | ||
353 | |||
354 | if (ret < 0) { | ||
355 | mutex_unlock(&data->mutex); | ||
356 | dev_err(data->dev, "failed to update reg_int_mask1"); | ||
357 | return ret; | ||
358 | } | ||
359 | |||
360 | data->trigger_enabled = state; | ||
361 | mutex_unlock(&data->mutex); | ||
362 | |||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | static int mxc4005_trigger_try_reen(struct iio_trigger *trig) | ||
367 | { | ||
368 | struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); | ||
369 | struct mxc4005_data *data = iio_priv(indio_dev); | ||
370 | |||
371 | if (!data->dready_trig) | ||
372 | return 0; | ||
373 | |||
374 | return mxc4005_clr_intr(data); | ||
375 | } | ||
376 | |||
377 | static const struct iio_trigger_ops mxc4005_trigger_ops = { | ||
378 | .set_trigger_state = mxc4005_set_trigger_state, | ||
379 | .try_reenable = mxc4005_trigger_try_reen, | ||
380 | .owner = THIS_MODULE, | ||
381 | }; | ||
382 | |||
383 | static int mxc4005_gpio_probe(struct i2c_client *client, | ||
384 | struct mxc4005_data *data) | ||
385 | { | ||
386 | struct device *dev; | ||
387 | struct gpio_desc *gpio; | ||
388 | int ret; | ||
389 | |||
390 | if (!client) | ||
391 | return -EINVAL; | ||
392 | |||
393 | dev = &client->dev; | ||
394 | |||
395 | gpio = devm_gpiod_get_index(dev, "mxc4005_int", 0, GPIOD_IN); | ||
396 | if (IS_ERR(gpio)) { | ||
397 | dev_err(dev, "failed to get acpi gpio index\n"); | ||
398 | return PTR_ERR(gpio); | ||
399 | } | ||
400 | |||
401 | ret = gpiod_to_irq(gpio); | ||
402 | |||
403 | dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); | ||
404 | |||
405 | return ret; | ||
406 | } | ||
407 | |||
310 | static int mxc4005_chip_init(struct mxc4005_data *data) | 408 | static int mxc4005_chip_init(struct mxc4005_data *data) |
311 | { | 409 | { |
312 | int ret; | 410 | int ret; |
@@ -363,7 +461,7 @@ static int mxc4005_probe(struct i2c_client *client, | |||
363 | indio_dev->info = &mxc4005_info; | 461 | indio_dev->info = &mxc4005_info; |
364 | 462 | ||
365 | ret = iio_triggered_buffer_setup(indio_dev, | 463 | ret = iio_triggered_buffer_setup(indio_dev, |
366 | &iio_pollfunc_store_time, | 464 | iio_pollfunc_store_time, |
367 | mxc4005_trigger_handler, | 465 | mxc4005_trigger_handler, |
368 | NULL); | 466 | NULL); |
369 | if (ret < 0) { | 467 | if (ret < 0) { |
@@ -372,6 +470,43 @@ static int mxc4005_probe(struct i2c_client *client, | |||
372 | return ret; | 470 | return ret; |
373 | } | 471 | } |
374 | 472 | ||
473 | if (client->irq < 0) | ||
474 | client->irq = mxc4005_gpio_probe(client, data); | ||
475 | |||
476 | if (client->irq > 0) { | ||
477 | data->dready_trig = devm_iio_trigger_alloc(&client->dev, | ||
478 | "%s-dev%d", | ||
479 | indio_dev->name, | ||
480 | indio_dev->id); | ||
481 | if (!data->dready_trig) | ||
482 | return -ENOMEM; | ||
483 | |||
484 | ret = devm_request_threaded_irq(&client->dev, client->irq, | ||
485 | iio_trigger_generic_data_rdy_poll, | ||
486 | NULL, | ||
487 | IRQF_TRIGGER_FALLING | | ||
488 | IRQF_ONESHOT, | ||
489 | MXC4005_IRQ_NAME, | ||
490 | data->dready_trig); | ||
491 | if (ret) { | ||
492 | dev_err(&client->dev, | ||
493 | "failed to init threaded irq\n"); | ||
494 | goto err_buffer_cleanup; | ||
495 | } | ||
496 | |||
497 | data->dready_trig->dev.parent = &client->dev; | ||
498 | data->dready_trig->ops = &mxc4005_trigger_ops; | ||
499 | iio_trigger_set_drvdata(data->dready_trig, indio_dev); | ||
500 | indio_dev->trig = data->dready_trig; | ||
501 | iio_trigger_get(indio_dev->trig); | ||
502 | ret = iio_trigger_register(data->dready_trig); | ||
503 | if (ret) { | ||
504 | dev_err(&client->dev, | ||
505 | "failed to register trigger\n"); | ||
506 | goto err_trigger_unregister; | ||
507 | } | ||
508 | } | ||
509 | |||
375 | ret = iio_device_register(indio_dev); | 510 | ret = iio_device_register(indio_dev); |
376 | if (ret < 0) { | 511 | if (ret < 0) { |
377 | dev_err(&client->dev, | 512 | dev_err(&client->dev, |
@@ -381,6 +516,8 @@ static int mxc4005_probe(struct i2c_client *client, | |||
381 | 516 | ||
382 | return 0; | 517 | return 0; |
383 | 518 | ||
519 | err_trigger_unregister: | ||
520 | iio_trigger_unregister(data->dready_trig); | ||
384 | err_buffer_cleanup: | 521 | err_buffer_cleanup: |
385 | iio_triggered_buffer_cleanup(indio_dev); | 522 | iio_triggered_buffer_cleanup(indio_dev); |
386 | 523 | ||
@@ -390,10 +527,13 @@ err_buffer_cleanup: | |||
390 | static int mxc4005_remove(struct i2c_client *client) | 527 | static int mxc4005_remove(struct i2c_client *client) |
391 | { | 528 | { |
392 | struct iio_dev *indio_dev = i2c_get_clientdata(client); | 529 | struct iio_dev *indio_dev = i2c_get_clientdata(client); |
530 | struct mxc4005_data *data = iio_priv(indio_dev); | ||
393 | 531 | ||
394 | iio_device_unregister(indio_dev); | 532 | iio_device_unregister(indio_dev); |
395 | 533 | ||
396 | iio_triggered_buffer_cleanup(indio_dev); | 534 | iio_triggered_buffer_cleanup(indio_dev); |
535 | if (data->dready_trig) | ||
536 | iio_trigger_unregister(data->dready_trig); | ||
397 | 537 | ||
398 | return 0; | 538 | return 0; |
399 | } | 539 | } |