brintos

brintos / linux-shallow public Read only

0
0
Text · 6.9 KiB · a0df925 Raw
243 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * STMicroelectronics sensors trigger library driver4 *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 in20 * @indio_dev: IIO device reference.21 * @sdata: Sensor data.22 *23 * returns:24 * false - no new samples available or read error25 * true - new samples available26 */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 triggers54 * @irq: irq number55 * @p: private handler data56 */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 triggers70 * @irq: irq number71 * @p: private handler data72 */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 a81	 * status register, check if this IRQ came from us. Notice that82	 * we will process also if st_sensors_new_samples_available()83	 * returns negative: if we can't check status, then poll84	 * unconditionally.85	 */86	if (sdata->hw_irq_trigger &&87	    st_sensors_new_samples_available(indio_dev, sdata)) {88		iio_trigger_poll_nested(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 if96	 * the line is still active, so return here and come back in through97	 * 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 processing104	 * the IRQ and those may be missed unless we pick them here, so poll105	 * again. If the sensor delivery frequency is very high, this thread106	 * 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_nested(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 the140	 * 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) we190		 * just mask off the IRQ, handle one interrupt, then191		 * if the line is still low, we return to the192		 * 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 this199	 * means that the interrupt line may be shared with other200	 * peripherals. But to do this we also need to have a status201	 * register and mask to figure out if this sensor was firing202	 * the IRQ or not, so we can tell the interrupt handle that203	 * 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);243