linux/drivers/iio/common/st_sensors/st_sensors_trigger.c
<<
>>
Prefs
   1/*
   2 * STMicroelectronics sensors trigger library driver
   3 *
   4 * Copyright 2012-2013 STMicroelectronics Inc.
   5 *
   6 * Denis Ciocca <denis.ciocca@st.com>
   7 *
   8 * Licensed under the GPL-2.
   9 */
  10
  11#include <linux/kernel.h>
  12#include <linux/module.h>
  13#include <linux/slab.h>
  14#include <linux/iio/iio.h>
  15#include <linux/iio/trigger.h>
  16#include <linux/interrupt.h>
  17#include <linux/iio/common/st_sensors.h>
  18#include "st_sensors_core.h"
  19
  20/**
  21 * st_sensors_new_samples_available() - check if more samples came in
  22 * returns:
  23 * 0 - no new samples available
  24 * 1 - new samples available
  25 * negative - error or unknown
  26 */
  27static int st_sensors_new_samples_available(struct iio_dev *indio_dev,
  28                                            struct st_sensor_data *sdata)
  29{
  30        u8 status;
  31        int ret;
  32
  33        /* How would I know if I can't check it? */
  34        if (!sdata->sensor_settings->drdy_irq.stat_drdy.addr)
  35                return -EINVAL;
  36
  37        /* No scan mask, no interrupt */
  38        if (!indio_dev->active_scan_mask)
  39                return 0;
  40
  41        ret = sdata->tf->read_byte(&sdata->tb, sdata->dev,
  42                        sdata->sensor_settings->drdy_irq.stat_drdy.addr,
  43                        &status);
  44        if (ret < 0) {
  45                dev_err(sdata->dev,
  46                        "error checking samples available\n");
  47                return ret;
  48        }
  49
  50        if (status & sdata->sensor_settings->drdy_irq.stat_drdy.mask)
  51                return 1;
  52
  53        return 0;
  54}
  55
  56/**
  57 * st_sensors_irq_handler() - top half of the IRQ-based triggers
  58 * @irq: irq number
  59 * @p: private handler data
  60 */
  61static irqreturn_t st_sensors_irq_handler(int irq, void *p)
  62{
  63        struct iio_trigger *trig = p;
  64        struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
  65        struct st_sensor_data *sdata = iio_priv(indio_dev);
  66
  67        /* Get the time stamp as close in time as possible */
  68        sdata->hw_timestamp = iio_get_time_ns(indio_dev);
  69        return IRQ_WAKE_THREAD;
  70}
  71
  72/**
  73 * st_sensors_irq_thread() - bottom half of the IRQ-based triggers
  74 * @irq: irq number
  75 * @p: private handler data
  76 */
  77static irqreturn_t st_sensors_irq_thread(int irq, void *p)
  78{
  79        struct iio_trigger *trig = p;
  80        struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
  81        struct st_sensor_data *sdata = iio_priv(indio_dev);
  82
  83        /*
  84         * If this trigger is backed by a hardware interrupt and we have a
  85         * status register, check if this IRQ came from us. Notice that
  86         * we will process also if st_sensors_new_samples_available()
  87         * returns negative: if we can't check status, then poll
  88         * unconditionally.
  89         */
  90        if (sdata->hw_irq_trigger &&
  91            st_sensors_new_samples_available(indio_dev, sdata)) {
  92                iio_trigger_poll_chained(p);
  93        } else {
  94                dev_dbg(sdata->dev, "spurious IRQ\n");
  95                return IRQ_NONE;
  96        }
  97
  98        /*
  99         * If we have proper level IRQs the handler will be re-entered if
 100         * the line is still active, so return here and come back in through
 101         * the top half if need be.
 102         */
 103        if (!sdata->edge_irq)
 104                return IRQ_HANDLED;
 105
 106        /*
 107         * If we are using egde IRQs, new samples arrived while processing
 108         * the IRQ and those may be missed unless we pick them here, so poll
 109         * again. If the sensor delivery frequency is very high, this thread
 110         * turns into a polled loop handler.
 111         */
 112        while (sdata->hw_irq_trigger &&
 113               st_sensors_new_samples_available(indio_dev, sdata)) {
 114                dev_dbg(sdata->dev, "more samples came in during polling\n");
 115                sdata->hw_timestamp = iio_get_time_ns(indio_dev);
 116                iio_trigger_poll_chained(p);
 117        }
 118
 119        return IRQ_HANDLED;
 120}
 121
 122int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
 123                                const struct iio_trigger_ops *trigger_ops)
 124{
 125        int err, irq;
 126        struct st_sensor_data *sdata = iio_priv(indio_dev);
 127        unsigned long irq_trig;
 128
 129        sdata->trig = iio_trigger_alloc("%s-trigger", indio_dev->name);
 130        if (sdata->trig == NULL) {
 131                dev_err(&indio_dev->dev, "failed to allocate iio trigger.\n");
 132                return -ENOMEM;
 133        }
 134
 135        iio_trigger_set_drvdata(sdata->trig, indio_dev);
 136        sdata->trig->ops = trigger_ops;
 137        sdata->trig->dev.parent = sdata->dev;
 138
 139        irq = sdata->get_irq_data_ready(indio_dev);
 140        irq_trig = irqd_get_trigger_type(irq_get_irq_data(irq));
 141        /*
 142         * If the IRQ is triggered on falling edge, we need to mark the
 143         * interrupt as active low, if the hardware supports this.
 144         */
 145        switch(irq_trig) {
 146        case IRQF_TRIGGER_FALLING:
 147        case IRQF_TRIGGER_LOW:
 148                if (!sdata->sensor_settings->drdy_irq.addr_ihl) {
 149                        dev_err(&indio_dev->dev,
 150                                "falling/low specified for IRQ "
 151                                "but hardware only support rising/high: "
 152                                "will request rising/high\n");
 153                        if (irq_trig == IRQF_TRIGGER_FALLING)
 154                                irq_trig = IRQF_TRIGGER_RISING;
 155                        if (irq_trig == IRQF_TRIGGER_LOW)
 156                                irq_trig = IRQF_TRIGGER_HIGH;
 157                } else {
 158                        /* Set up INT active low i.e. falling edge */
 159                        err = st_sensors_write_data_with_mask(indio_dev,
 160                                sdata->sensor_settings->drdy_irq.addr_ihl,
 161                                sdata->sensor_settings->drdy_irq.mask_ihl, 1);
 162                        if (err < 0)
 163                                goto iio_trigger_free;
 164                        dev_info(&indio_dev->dev,
 165                                 "interrupts on the falling edge or "
 166                                 "active low level\n");
 167                }
 168                break;
 169        case IRQF_TRIGGER_RISING:
 170                dev_info(&indio_dev->dev,
 171                         "interrupts on the rising edge\n");
 172                break;
 173        case IRQF_TRIGGER_HIGH:
 174                dev_info(&indio_dev->dev,
 175                         "interrupts active high level\n");
 176                break;
 177        default:
 178                /* This is the most preferred mode, if possible */
 179                dev_err(&indio_dev->dev,
 180                        "unsupported IRQ trigger specified (%lx), enforce "
 181                        "rising edge\n", irq_trig);
 182                irq_trig = IRQF_TRIGGER_RISING;
 183        }
 184
 185        /* Tell the interrupt handler that we're dealing with edges */
 186        if (irq_trig == IRQF_TRIGGER_FALLING ||
 187            irq_trig == IRQF_TRIGGER_RISING)
 188                sdata->edge_irq = true;
 189        else
 190                /*
 191                 * If we're not using edges (i.e. level interrupts) we
 192                 * just mask off the IRQ, handle one interrupt, then
 193                 * if the line is still low, we return to the
 194                 * interrupt handler top half again and start over.
 195                 */
 196                irq_trig |= IRQF_ONESHOT;
 197
 198        /*
 199         * If the interrupt pin is Open Drain, by definition this
 200         * means that the interrupt line may be shared with other
 201         * peripherals. But to do this we also need to have a status
 202         * register and mask to figure out if this sensor was firing
 203         * the IRQ or not, so we can tell the interrupt handle that
 204         * it was "our" interrupt.
 205         */
 206        if (sdata->int_pin_open_drain &&
 207            sdata->sensor_settings->drdy_irq.stat_drdy.addr)
 208                irq_trig |= IRQF_SHARED;
 209
 210        err = request_threaded_irq(sdata->get_irq_data_ready(indio_dev),
 211                        st_sensors_irq_handler,
 212                        st_sensors_irq_thread,
 213                        irq_trig,
 214                        sdata->trig->name,
 215                        sdata->trig);
 216        if (err) {
 217                dev_err(&indio_dev->dev, "failed to request trigger IRQ.\n");
 218                goto iio_trigger_free;
 219        }
 220
 221        err = iio_trigger_register(sdata->trig);
 222        if (err < 0) {
 223                dev_err(&indio_dev->dev, "failed to register iio trigger.\n");
 224                goto iio_trigger_register_error;
 225        }
 226        indio_dev->trig = iio_trigger_get(sdata->trig);
 227
 228        return 0;
 229
 230iio_trigger_register_error:
 231        free_irq(sdata->get_irq_data_ready(indio_dev), sdata->trig);
 232iio_trigger_free:
 233        iio_trigger_free(sdata->trig);
 234        return err;
 235}
 236EXPORT_SYMBOL(st_sensors_allocate_trigger);
 237
 238void st_sensors_deallocate_trigger(struct iio_dev *indio_dev)
 239{
 240        struct st_sensor_data *sdata = iio_priv(indio_dev);
 241
 242        iio_trigger_unregister(sdata->trig);
 243        free_irq(sdata->get_irq_data_ready(indio_dev), sdata->trig);
 244        iio_trigger_free(sdata->trig);
 245}
 246EXPORT_SYMBOL(st_sensors_deallocate_trigger);
 247
 248int st_sensors_validate_device(struct iio_trigger *trig,
 249                               struct iio_dev *indio_dev)
 250{
 251        struct iio_dev *indio = iio_trigger_get_drvdata(trig);
 252
 253        if (indio != indio_dev)
 254                return -EINVAL;
 255
 256        return 0;
 257}
 258EXPORT_SYMBOL(st_sensors_validate_device);
 259
 260MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
 261MODULE_DESCRIPTION("STMicroelectronics ST-sensors trigger");
 262MODULE_LICENSE("GPL v2");
 263