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 int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
21 				const struct iio_trigger_ops *trigger_ops)
22 {
23 	int err, irq;
24 	struct st_sensor_data *sdata = iio_priv(indio_dev);
25 	unsigned long irq_trig;
26 
27 	sdata->trig = iio_trigger_alloc("%s-trigger", indio_dev->name);
28 	if (sdata->trig == NULL) {
29 		dev_err(&indio_dev->dev, "failed to allocate iio trigger.\n");
30 		return -ENOMEM;
31 	}
32 
33 	irq = sdata->get_irq_data_ready(indio_dev);
34 	irq_trig = irqd_get_trigger_type(irq_get_irq_data(irq));
35 	/*
36 	 * If the IRQ is triggered on falling edge, we need to mark the
37 	 * interrupt as active low, if the hardware supports this.
38 	 */
39 	if (irq_trig == IRQF_TRIGGER_FALLING) {
40 		if (!sdata->sensor_settings->drdy_irq.addr_ihl) {
41 			dev_err(&indio_dev->dev,
42 				"falling edge specified for IRQ but hardware "
43 				"only support rising edge, will request "
44 				"rising edge\n");
45 			irq_trig = IRQF_TRIGGER_RISING;
46 		} else {
47 			/* Set up INT active low i.e. falling edge */
48 			err = st_sensors_write_data_with_mask(indio_dev,
49 				sdata->sensor_settings->drdy_irq.addr_ihl,
50 				sdata->sensor_settings->drdy_irq.mask_ihl, 1);
51 			if (err < 0)
52 				goto iio_trigger_free;
53 			dev_info(&indio_dev->dev,
54 				 "interrupts on the falling edge\n");
55 		}
56 	} else if (irq_trig == IRQF_TRIGGER_RISING) {
57 		dev_info(&indio_dev->dev,
58 			 "interrupts on the rising edge\n");
59 
60 	} else {
61 		dev_err(&indio_dev->dev,
62 		"unsupported IRQ trigger specified (%lx), only "
63 			"rising and falling edges supported, enforce "
64 			"rising edge\n", irq_trig);
65 		irq_trig = IRQF_TRIGGER_RISING;
66 	}
67 	err = request_threaded_irq(irq,
68 			iio_trigger_generic_data_rdy_poll,
69 			NULL,
70 			irq_trig,
71 			sdata->trig->name,
72 			sdata->trig);
73 	if (err) {
74 		dev_err(&indio_dev->dev, "failed to request trigger IRQ.\n");
75 		goto iio_trigger_free;
76 	}
77 
78 	iio_trigger_set_drvdata(sdata->trig, indio_dev);
79 	sdata->trig->ops = trigger_ops;
80 	sdata->trig->dev.parent = sdata->dev;
81 
82 	err = iio_trigger_register(sdata->trig);
83 	if (err < 0) {
84 		dev_err(&indio_dev->dev, "failed to register iio trigger.\n");
85 		goto iio_trigger_register_error;
86 	}
87 	indio_dev->trig = iio_trigger_get(sdata->trig);
88 
89 	return 0;
90 
91 iio_trigger_register_error:
92 	free_irq(sdata->get_irq_data_ready(indio_dev), sdata->trig);
93 iio_trigger_free:
94 	iio_trigger_free(sdata->trig);
95 	return err;
96 }
97 EXPORT_SYMBOL(st_sensors_allocate_trigger);
98 
99 void st_sensors_deallocate_trigger(struct iio_dev *indio_dev)
100 {
101 	struct st_sensor_data *sdata = iio_priv(indio_dev);
102 
103 	iio_trigger_unregister(sdata->trig);
104 	free_irq(sdata->get_irq_data_ready(indio_dev), sdata->trig);
105 	iio_trigger_free(sdata->trig);
106 }
107 EXPORT_SYMBOL(st_sensors_deallocate_trigger);
108 
109 MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
110 MODULE_DESCRIPTION("STMicroelectronics ST-sensors trigger");
111 MODULE_LICENSE("GPL v2");
112