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 | */ |
27 | static 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(map: sdata->regmap, |
41 | reg: sdata->sensor_settings->drdy_irq.stat_drdy.addr, |
42 | val: &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 | */ |
57 | static 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 | */ |
73 | static 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_nested(trig: 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_nested(trig: p); |
114 | } |
115 | |
116 | return IRQ_HANDLED; |
117 | } |
118 | |
119 | int 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(trig: sdata->trig, data: indio_dev); |
135 | sdata->trig->ops = trigger_ops; |
136 | |
137 | irq_trig = irqd_get_trigger_type(d: irq_get_irq_data(irq: 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 | reg_addr: sdata->sensor_settings->drdy_irq.addr_ihl, |
156 | mask: sdata->sensor_settings->drdy_irq.mask_ihl, data: 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(dev: parent, |
210 | irq: sdata->irq, |
211 | handler: st_sensors_irq_handler, |
212 | thread_fn: st_sensors_irq_thread, |
213 | irqflags: irq_trig, |
214 | devname: sdata->trig->name, |
215 | dev_id: 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(dev: parent, trig_info: 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(trig: sdata->trig); |
227 | |
228 | return 0; |
229 | } |
230 | EXPORT_SYMBOL_NS(st_sensors_allocate_trigger, IIO_ST_SENSORS); |
231 | |
232 | int 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 | } |
242 | EXPORT_SYMBOL_NS(st_sensors_validate_device, IIO_ST_SENSORS); |
243 | |