cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

st_sensors_trigger.c (7074B)


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