Commit | Line | Data |
---|---|---|
23491b51 DC |
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> | |
23491b51 | 17 | #include <linux/iio/common/st_sensors.h> |
a9fd053b | 18 | #include "st_sensors_core.h" |
23491b51 | 19 | |
65925b65 LW |
20 | /** |
21 | * st_sensors_irq_handler() - top half of the IRQ-based triggers | |
22 | * @irq: irq number | |
23 | * @p: private handler data | |
24 | */ | |
25 | irqreturn_t st_sensors_irq_handler(int irq, void *p) | |
26 | { | |
27 | struct iio_trigger *trig = p; | |
28 | struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); | |
29 | struct st_sensor_data *sdata = iio_priv(indio_dev); | |
30 | ||
31 | /* Get the time stamp as close in time as possible */ | |
32 | sdata->hw_timestamp = iio_get_time_ns(); | |
33 | return IRQ_WAKE_THREAD; | |
34 | } | |
35 | ||
36 | /** | |
37 | * st_sensors_irq_thread() - bottom half of the IRQ-based triggers | |
38 | * @irq: irq number | |
39 | * @p: private handler data | |
40 | */ | |
41 | irqreturn_t st_sensors_irq_thread(int irq, void *p) | |
42 | { | |
43 | struct iio_trigger *trig = p; | |
44 | struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); | |
45 | struct st_sensor_data *sdata = iio_priv(indio_dev); | |
46 | int ret; | |
47 | ||
48 | /* | |
49 | * If this trigger is backed by a hardware interrupt and we have a | |
50 | * status register, check if this IRQ came from us | |
51 | */ | |
52 | if (sdata->sensor_settings->drdy_irq.addr_stat_drdy) { | |
53 | u8 status; | |
54 | ||
55 | ret = sdata->tf->read_byte(&sdata->tb, sdata->dev, | |
56 | sdata->sensor_settings->drdy_irq.addr_stat_drdy, | |
57 | &status); | |
58 | if (ret < 0) { | |
59 | dev_err(sdata->dev, "could not read channel status\n"); | |
60 | goto out_poll; | |
61 | } | |
62 | /* | |
63 | * the lower bits of .active_scan_mask[0] is directly mapped | |
64 | * to the channels on the sensor: either bit 0 for | |
65 | * one-dimensional sensors, or e.g. x,y,z for accelerometers, | |
66 | * gyroscopes or magnetometers. No sensor use more than 3 | |
67 | * channels, so cut the other status bits here. | |
68 | */ | |
69 | status &= 0x07; | |
70 | ||
71 | /* | |
72 | * If this was not caused by any channels on this sensor, | |
73 | * return IRQ_NONE | |
74 | */ | |
75 | if (!indio_dev->active_scan_mask) | |
76 | return IRQ_NONE; | |
77 | if (!(status & (u8)indio_dev->active_scan_mask[0])) | |
78 | return IRQ_NONE; | |
79 | } | |
80 | ||
81 | out_poll: | |
82 | /* It's our IRQ: proceed to handle the register polling */ | |
83 | iio_trigger_poll_chained(p); | |
84 | return IRQ_HANDLED; | |
85 | } | |
86 | ||
23491b51 DC |
87 | int st_sensors_allocate_trigger(struct iio_dev *indio_dev, |
88 | const struct iio_trigger_ops *trigger_ops) | |
89 | { | |
a9fd053b | 90 | int err, irq; |
23491b51 | 91 | struct st_sensor_data *sdata = iio_priv(indio_dev); |
a9fd053b | 92 | unsigned long irq_trig; |
23491b51 DC |
93 | |
94 | sdata->trig = iio_trigger_alloc("%s-trigger", indio_dev->name); | |
95 | if (sdata->trig == NULL) { | |
23491b51 | 96 | dev_err(&indio_dev->dev, "failed to allocate iio trigger.\n"); |
a9fd053b | 97 | return -ENOMEM; |
23491b51 DC |
98 | } |
99 | ||
a9fd053b LW |
100 | irq = sdata->get_irq_data_ready(indio_dev); |
101 | irq_trig = irqd_get_trigger_type(irq_get_irq_data(irq)); | |
102 | /* | |
103 | * If the IRQ is triggered on falling edge, we need to mark the | |
104 | * interrupt as active low, if the hardware supports this. | |
105 | */ | |
106 | if (irq_trig == IRQF_TRIGGER_FALLING) { | |
107 | if (!sdata->sensor_settings->drdy_irq.addr_ihl) { | |
108 | dev_err(&indio_dev->dev, | |
109 | "falling edge specified for IRQ but hardware " | |
110 | "only support rising edge, will request " | |
111 | "rising edge\n"); | |
112 | irq_trig = IRQF_TRIGGER_RISING; | |
113 | } else { | |
114 | /* Set up INT active low i.e. falling edge */ | |
115 | err = st_sensors_write_data_with_mask(indio_dev, | |
116 | sdata->sensor_settings->drdy_irq.addr_ihl, | |
117 | sdata->sensor_settings->drdy_irq.mask_ihl, 1); | |
118 | if (err < 0) | |
119 | goto iio_trigger_free; | |
120 | dev_info(&indio_dev->dev, | |
121 | "interrupts on the falling edge\n"); | |
122 | } | |
123 | } else if (irq_trig == IRQF_TRIGGER_RISING) { | |
124 | dev_info(&indio_dev->dev, | |
125 | "interrupts on the rising edge\n"); | |
126 | ||
127 | } else { | |
128 | dev_err(&indio_dev->dev, | |
129 | "unsupported IRQ trigger specified (%lx), only " | |
130 | "rising and falling edges supported, enforce " | |
131 | "rising edge\n", irq_trig); | |
132 | irq_trig = IRQF_TRIGGER_RISING; | |
133 | } | |
0e6f6871 LW |
134 | |
135 | /* | |
136 | * If the interrupt pin is Open Drain, by definition this | |
137 | * means that the interrupt line may be shared with other | |
138 | * peripherals. But to do this we also need to have a status | |
139 | * register and mask to figure out if this sensor was firing | |
140 | * the IRQ or not, so we can tell the interrupt handle that | |
141 | * it was "our" interrupt. | |
142 | */ | |
143 | if (sdata->int_pin_open_drain && | |
144 | sdata->sensor_settings->drdy_irq.addr_stat_drdy) | |
145 | irq_trig |= IRQF_SHARED; | |
146 | ||
65925b65 LW |
147 | /* Let's create an interrupt thread masking the hard IRQ here */ |
148 | irq_trig |= IRQF_ONESHOT; | |
149 | ||
150 | err = request_threaded_irq(sdata->get_irq_data_ready(indio_dev), | |
151 | st_sensors_irq_handler, | |
152 | st_sensors_irq_thread, | |
a9fd053b | 153 | irq_trig, |
23491b51 DC |
154 | sdata->trig->name, |
155 | sdata->trig); | |
3337c9ff LW |
156 | if (err) { |
157 | dev_err(&indio_dev->dev, "failed to request trigger IRQ.\n"); | |
a9fd053b | 158 | goto iio_trigger_free; |
3337c9ff | 159 | } |
23491b51 | 160 | |
1e9663c6 | 161 | iio_trigger_set_drvdata(sdata->trig, indio_dev); |
23491b51 DC |
162 | sdata->trig->ops = trigger_ops; |
163 | sdata->trig->dev.parent = sdata->dev; | |
164 | ||
165 | err = iio_trigger_register(sdata->trig); | |
166 | if (err < 0) { | |
167 | dev_err(&indio_dev->dev, "failed to register iio trigger.\n"); | |
168 | goto iio_trigger_register_error; | |
169 | } | |
f0e84acd | 170 | indio_dev->trig = iio_trigger_get(sdata->trig); |
23491b51 DC |
171 | |
172 | return 0; | |
173 | ||
174 | iio_trigger_register_error: | |
175 | free_irq(sdata->get_irq_data_ready(indio_dev), sdata->trig); | |
a9fd053b | 176 | iio_trigger_free: |
23491b51 | 177 | iio_trigger_free(sdata->trig); |
23491b51 DC |
178 | return err; |
179 | } | |
180 | EXPORT_SYMBOL(st_sensors_allocate_trigger); | |
181 | ||
182 | void st_sensors_deallocate_trigger(struct iio_dev *indio_dev) | |
183 | { | |
184 | struct st_sensor_data *sdata = iio_priv(indio_dev); | |
185 | ||
186 | iio_trigger_unregister(sdata->trig); | |
187 | free_irq(sdata->get_irq_data_ready(indio_dev), sdata->trig); | |
188 | iio_trigger_free(sdata->trig); | |
189 | } | |
190 | EXPORT_SYMBOL(st_sensors_deallocate_trigger); | |
191 | ||
65925b65 LW |
192 | int st_sensors_validate_device(struct iio_trigger *trig, |
193 | struct iio_dev *indio_dev) | |
194 | { | |
195 | struct iio_dev *indio = iio_trigger_get_drvdata(trig); | |
196 | ||
197 | if (indio != indio_dev) | |
198 | return -EINVAL; | |
199 | ||
200 | return 0; | |
201 | } | |
202 | EXPORT_SYMBOL(st_sensors_validate_device); | |
203 | ||
23491b51 DC |
204 | MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); |
205 | MODULE_DESCRIPTION("STMicroelectronics ST-sensors trigger"); | |
206 | MODULE_LICENSE("GPL v2"); |