diff options
Diffstat (limited to 'drivers/iio/imu/adis_trigger.c')
| -rw-r--r-- | drivers/iio/imu/adis_trigger.c | 105 |
1 files changed, 61 insertions, 44 deletions
diff --git a/drivers/iio/imu/adis_trigger.c b/drivers/iio/imu/adis_trigger.c index e0017c22bb9c..d76e13cbac68 100644 --- a/drivers/iio/imu/adis_trigger.c +++ b/drivers/iio/imu/adis_trigger.c @@ -1,10 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Common library for ADIS16XXX devices * * Copyright 2012 Analog Devices Inc. * Author: Lars-Peter Clausen <lars@metafoo.de> - * - * Licensed under the GPL-2 or later. */ #include <linux/interrupt.h> @@ -16,8 +15,7 @@ #include <linux/iio/trigger.h> #include <linux/iio/imu/adis.h> -static int adis_data_rdy_trigger_set_state(struct iio_trigger *trig, - bool state) +static int adis_data_rdy_trigger_set_state(struct iio_trigger *trig, bool state) { struct adis *adis = iio_trigger_get_drvdata(trig); @@ -25,65 +23,84 @@ static int adis_data_rdy_trigger_set_state(struct iio_trigger *trig, } static const struct iio_trigger_ops adis_trigger_ops = { - .owner = THIS_MODULE, .set_trigger_state = &adis_data_rdy_trigger_set_state, }; +static int adis_validate_irq_flag(struct adis *adis) +{ + unsigned long direction = adis->irq_flag & IRQF_TRIGGER_MASK; + + /* We cannot mask the interrupt so ensure it's not enabled at request */ + if (adis->data->unmasked_drdy) + adis->irq_flag |= IRQF_NO_AUTOEN; + /* + * Typically adis devices without FIFO have data ready either on the + * rising edge or on the falling edge of the data ready pin. + * IMU devices with FIFO support have the watermark pin level driven + * either high or low when the FIFO is filled with the desired number + * of samples. + * It defaults to IRQF_TRIGGER_RISING for backward compatibility with + * devices that don't support changing the pin polarity. + */ + if (direction == IRQF_TRIGGER_NONE) { + adis->irq_flag |= IRQF_TRIGGER_RISING; + return 0; + } else if (direction != IRQF_TRIGGER_RISING && + direction != IRQF_TRIGGER_FALLING && !adis->data->has_fifo) { + dev_err(&adis->spi->dev, "Invalid IRQ mask: %08lx\n", + adis->irq_flag); + return -EINVAL; + } else if (direction != IRQF_TRIGGER_HIGH && + direction != IRQF_TRIGGER_LOW && adis->data->has_fifo) { + dev_err(&adis->spi->dev, "Invalid IRQ mask: %08lx\n", + adis->irq_flag); + return -EINVAL; + } + + return 0; +} + /** - * adis_probe_trigger() - Sets up trigger for a adis device + * devm_adis_probe_trigger() - Sets up trigger for a managed adis device * @adis: The adis device * @indio_dev: The IIO device * * Returns 0 on success or a negative error code - * - * adis_remove_trigger() should be used to free the trigger. */ -int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev) +int devm_adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev) { int ret; - adis->trig = iio_trigger_alloc("%s-dev%d", indio_dev->name, - indio_dev->id); - if (adis->trig == NULL) + adis->trig = devm_iio_trigger_alloc(&adis->spi->dev, "%s-dev%d", + indio_dev->name, + iio_device_id(indio_dev)); + if (!adis->trig) return -ENOMEM; - ret = request_irq(adis->spi->irq, - &iio_trigger_generic_data_rdy_poll, - IRQF_TRIGGER_RISING, - indio_dev->name, - adis->trig); - if (ret) - goto error_free_trig; - - adis->trig->dev.parent = &adis->spi->dev; adis->trig->ops = &adis_trigger_ops; iio_trigger_set_drvdata(adis->trig, adis); - ret = iio_trigger_register(adis->trig); - indio_dev->trig = adis->trig; + ret = adis_validate_irq_flag(adis); if (ret) - goto error_free_irq; + return ret; - return 0; + if (adis->data->has_fifo) + ret = devm_request_threaded_irq(&adis->spi->dev, adis->spi->irq, + NULL, + &iio_trigger_generic_data_rdy_poll, + adis->irq_flag | IRQF_ONESHOT, + indio_dev->name, + adis->trig); + else + ret = devm_request_irq(&adis->spi->dev, adis->spi->irq, + &iio_trigger_generic_data_rdy_poll, + adis->irq_flag, + indio_dev->name, + adis->trig); + if (ret) + return ret; -error_free_irq: - free_irq(adis->spi->irq, adis->trig); -error_free_trig: - iio_trigger_free(adis->trig); - return ret; + return devm_iio_trigger_register(&adis->spi->dev, adis->trig); } -EXPORT_SYMBOL_GPL(adis_probe_trigger); +EXPORT_SYMBOL_NS_GPL(devm_adis_probe_trigger, "IIO_ADISLIB"); -/** - * adis_remove_trigger() - Remove trigger for a adis devices - * @adis: The adis device - * - * Removes the trigger previously registered with adis_probe_trigger(). - */ -void adis_remove_trigger(struct adis *adis) -{ - iio_trigger_unregister(adis->trig); - free_irq(adis->spi->irq, adis->trig); - iio_trigger_free(adis->trig); -} -EXPORT_SYMBOL_GPL(adis_remove_trigger); |
