1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Renesas INTC External IRQ Pin Driver |
4 | * |
5 | * Copyright (C) 2013 Magnus Damm |
6 | */ |
7 | |
8 | #include <linux/init.h> |
9 | #include <linux/of.h> |
10 | #include <linux/platform_device.h> |
11 | #include <linux/spinlock.h> |
12 | #include <linux/interrupt.h> |
13 | #include <linux/ioport.h> |
14 | #include <linux/io.h> |
15 | #include <linux/irq.h> |
16 | #include <linux/irqdomain.h> |
17 | #include <linux/err.h> |
18 | #include <linux/slab.h> |
19 | #include <linux/module.h> |
20 | #include <linux/pm_runtime.h> |
21 | |
22 | #define INTC_IRQPIN_MAX 8 /* maximum 8 interrupts per driver instance */ |
23 | |
24 | #define INTC_IRQPIN_REG_SENSE 0 /* ICRn */ |
25 | #define INTC_IRQPIN_REG_PRIO 1 /* INTPRInn */ |
26 | #define INTC_IRQPIN_REG_SOURCE 2 /* INTREQnn */ |
27 | #define INTC_IRQPIN_REG_MASK 3 /* INTMSKnn */ |
28 | #define INTC_IRQPIN_REG_CLEAR 4 /* INTMSKCLRnn */ |
29 | #define INTC_IRQPIN_REG_NR_MANDATORY 5 |
30 | #define INTC_IRQPIN_REG_IRLM 5 /* ICR0 with IRLM bit (optional) */ |
31 | #define INTC_IRQPIN_REG_NR 6 |
32 | |
33 | /* INTC external IRQ PIN hardware register access: |
34 | * |
35 | * SENSE is read-write 32-bit with 2-bits or 4-bits per IRQ (*) |
36 | * PRIO is read-write 32-bit with 4-bits per IRQ (**) |
37 | * SOURCE is read-only 32-bit or 8-bit with 1-bit per IRQ (***) |
38 | * MASK is write-only 32-bit or 8-bit with 1-bit per IRQ (***) |
39 | * CLEAR is write-only 32-bit or 8-bit with 1-bit per IRQ (***) |
40 | * |
41 | * (*) May be accessed by more than one driver instance - lock needed |
42 | * (**) Read-modify-write access by one driver instance - lock needed |
43 | * (***) Accessed by one driver instance only - no locking needed |
44 | */ |
45 | |
46 | struct intc_irqpin_iomem { |
47 | void __iomem *iomem; |
48 | unsigned long (*read)(void __iomem *iomem); |
49 | void (*write)(void __iomem *iomem, unsigned long data); |
50 | int width; |
51 | }; |
52 | |
53 | struct intc_irqpin_irq { |
54 | int hw_irq; |
55 | int requested_irq; |
56 | int domain_irq; |
57 | struct intc_irqpin_priv *p; |
58 | }; |
59 | |
60 | struct intc_irqpin_priv { |
61 | struct intc_irqpin_iomem iomem[INTC_IRQPIN_REG_NR]; |
62 | struct intc_irqpin_irq irq[INTC_IRQPIN_MAX]; |
63 | unsigned int sense_bitfield_width; |
64 | struct platform_device *pdev; |
65 | struct irq_chip irq_chip; |
66 | struct irq_domain *irq_domain; |
67 | atomic_t wakeup_path; |
68 | unsigned shared_irqs:1; |
69 | u8 shared_irq_mask; |
70 | }; |
71 | |
72 | struct intc_irqpin_config { |
73 | int irlm_bit; /* -1 if non-existent */ |
74 | }; |
75 | |
76 | static unsigned long intc_irqpin_read32(void __iomem *iomem) |
77 | { |
78 | return ioread32(iomem); |
79 | } |
80 | |
81 | static unsigned long intc_irqpin_read8(void __iomem *iomem) |
82 | { |
83 | return ioread8(iomem); |
84 | } |
85 | |
86 | static void intc_irqpin_write32(void __iomem *iomem, unsigned long data) |
87 | { |
88 | iowrite32(data, iomem); |
89 | } |
90 | |
91 | static void intc_irqpin_write8(void __iomem *iomem, unsigned long data) |
92 | { |
93 | iowrite8(data, iomem); |
94 | } |
95 | |
96 | static inline unsigned long intc_irqpin_read(struct intc_irqpin_priv *p, |
97 | int reg) |
98 | { |
99 | struct intc_irqpin_iomem *i = &p->iomem[reg]; |
100 | |
101 | return i->read(i->iomem); |
102 | } |
103 | |
104 | static inline void intc_irqpin_write(struct intc_irqpin_priv *p, |
105 | int reg, unsigned long data) |
106 | { |
107 | struct intc_irqpin_iomem *i = &p->iomem[reg]; |
108 | |
109 | i->write(i->iomem, data); |
110 | } |
111 | |
112 | static inline unsigned long intc_irqpin_hwirq_mask(struct intc_irqpin_priv *p, |
113 | int reg, int hw_irq) |
114 | { |
115 | return BIT((p->iomem[reg].width - 1) - hw_irq); |
116 | } |
117 | |
118 | static inline void intc_irqpin_irq_write_hwirq(struct intc_irqpin_priv *p, |
119 | int reg, int hw_irq) |
120 | { |
121 | intc_irqpin_write(p, reg, data: intc_irqpin_hwirq_mask(p, reg, hw_irq)); |
122 | } |
123 | |
124 | static DEFINE_RAW_SPINLOCK(intc_irqpin_lock); /* only used by slow path */ |
125 | |
126 | static void intc_irqpin_read_modify_write(struct intc_irqpin_priv *p, |
127 | int reg, int shift, |
128 | int width, int value) |
129 | { |
130 | unsigned long flags; |
131 | unsigned long tmp; |
132 | |
133 | raw_spin_lock_irqsave(&intc_irqpin_lock, flags); |
134 | |
135 | tmp = intc_irqpin_read(p, reg); |
136 | tmp &= ~(((1 << width) - 1) << shift); |
137 | tmp |= value << shift; |
138 | intc_irqpin_write(p, reg, data: tmp); |
139 | |
140 | raw_spin_unlock_irqrestore(&intc_irqpin_lock, flags); |
141 | } |
142 | |
143 | static void intc_irqpin_mask_unmask_prio(struct intc_irqpin_priv *p, |
144 | int irq, int do_mask) |
145 | { |
146 | /* The PRIO register is assumed to be 32-bit with fixed 4-bit fields. */ |
147 | int bitfield_width = 4; |
148 | int shift = 32 - (irq + 1) * bitfield_width; |
149 | |
150 | intc_irqpin_read_modify_write(p, INTC_IRQPIN_REG_PRIO, |
151 | shift, width: bitfield_width, |
152 | value: do_mask ? 0 : (1 << bitfield_width) - 1); |
153 | } |
154 | |
155 | static int intc_irqpin_set_sense(struct intc_irqpin_priv *p, int irq, int value) |
156 | { |
157 | /* The SENSE register is assumed to be 32-bit. */ |
158 | int bitfield_width = p->sense_bitfield_width; |
159 | int shift = 32 - (irq + 1) * bitfield_width; |
160 | |
161 | dev_dbg(&p->pdev->dev, "sense irq = %d, mode = %d\n" , irq, value); |
162 | |
163 | if (value >= (1 << bitfield_width)) |
164 | return -EINVAL; |
165 | |
166 | intc_irqpin_read_modify_write(p, INTC_IRQPIN_REG_SENSE, shift, |
167 | width: bitfield_width, value); |
168 | return 0; |
169 | } |
170 | |
171 | static void intc_irqpin_dbg(struct intc_irqpin_irq *i, char *str) |
172 | { |
173 | dev_dbg(&i->p->pdev->dev, "%s (%d:%d:%d)\n" , |
174 | str, i->requested_irq, i->hw_irq, i->domain_irq); |
175 | } |
176 | |
177 | static void intc_irqpin_irq_enable(struct irq_data *d) |
178 | { |
179 | struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d); |
180 | int hw_irq = irqd_to_hwirq(d); |
181 | |
182 | intc_irqpin_dbg(i: &p->irq[hw_irq], str: "enable" ); |
183 | intc_irqpin_irq_write_hwirq(p, INTC_IRQPIN_REG_CLEAR, hw_irq); |
184 | } |
185 | |
186 | static void intc_irqpin_irq_disable(struct irq_data *d) |
187 | { |
188 | struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d); |
189 | int hw_irq = irqd_to_hwirq(d); |
190 | |
191 | intc_irqpin_dbg(i: &p->irq[hw_irq], str: "disable" ); |
192 | intc_irqpin_irq_write_hwirq(p, INTC_IRQPIN_REG_MASK, hw_irq); |
193 | } |
194 | |
195 | static void intc_irqpin_shared_irq_enable(struct irq_data *d) |
196 | { |
197 | struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d); |
198 | int hw_irq = irqd_to_hwirq(d); |
199 | |
200 | intc_irqpin_dbg(i: &p->irq[hw_irq], str: "shared enable" ); |
201 | intc_irqpin_irq_write_hwirq(p, INTC_IRQPIN_REG_CLEAR, hw_irq); |
202 | |
203 | p->shared_irq_mask &= ~BIT(hw_irq); |
204 | } |
205 | |
206 | static void intc_irqpin_shared_irq_disable(struct irq_data *d) |
207 | { |
208 | struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d); |
209 | int hw_irq = irqd_to_hwirq(d); |
210 | |
211 | intc_irqpin_dbg(i: &p->irq[hw_irq], str: "shared disable" ); |
212 | intc_irqpin_irq_write_hwirq(p, INTC_IRQPIN_REG_MASK, hw_irq); |
213 | |
214 | p->shared_irq_mask |= BIT(hw_irq); |
215 | } |
216 | |
217 | static void intc_irqpin_irq_enable_force(struct irq_data *d) |
218 | { |
219 | struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d); |
220 | int irq = p->irq[irqd_to_hwirq(d)].requested_irq; |
221 | |
222 | intc_irqpin_irq_enable(d); |
223 | |
224 | /* enable interrupt through parent interrupt controller, |
225 | * assumes non-shared interrupt with 1:1 mapping |
226 | * needed for busted IRQs on some SoCs like sh73a0 |
227 | */ |
228 | irq_get_chip(irq)->irq_unmask(irq_get_irq_data(irq)); |
229 | } |
230 | |
231 | static void intc_irqpin_irq_disable_force(struct irq_data *d) |
232 | { |
233 | struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d); |
234 | int irq = p->irq[irqd_to_hwirq(d)].requested_irq; |
235 | |
236 | /* disable interrupt through parent interrupt controller, |
237 | * assumes non-shared interrupt with 1:1 mapping |
238 | * needed for busted IRQs on some SoCs like sh73a0 |
239 | */ |
240 | irq_get_chip(irq)->irq_mask(irq_get_irq_data(irq)); |
241 | intc_irqpin_irq_disable(d); |
242 | } |
243 | |
244 | #define INTC_IRQ_SENSE_VALID 0x10 |
245 | #define INTC_IRQ_SENSE(x) (x + INTC_IRQ_SENSE_VALID) |
246 | |
247 | static unsigned char intc_irqpin_sense[IRQ_TYPE_SENSE_MASK + 1] = { |
248 | [IRQ_TYPE_EDGE_FALLING] = INTC_IRQ_SENSE(0x00), |
249 | [IRQ_TYPE_EDGE_RISING] = INTC_IRQ_SENSE(0x01), |
250 | [IRQ_TYPE_LEVEL_LOW] = INTC_IRQ_SENSE(0x02), |
251 | [IRQ_TYPE_LEVEL_HIGH] = INTC_IRQ_SENSE(0x03), |
252 | [IRQ_TYPE_EDGE_BOTH] = INTC_IRQ_SENSE(0x04), |
253 | }; |
254 | |
255 | static int intc_irqpin_irq_set_type(struct irq_data *d, unsigned int type) |
256 | { |
257 | unsigned char value = intc_irqpin_sense[type & IRQ_TYPE_SENSE_MASK]; |
258 | struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d); |
259 | |
260 | if (!(value & INTC_IRQ_SENSE_VALID)) |
261 | return -EINVAL; |
262 | |
263 | return intc_irqpin_set_sense(p, irq: irqd_to_hwirq(d), |
264 | value: value ^ INTC_IRQ_SENSE_VALID); |
265 | } |
266 | |
267 | static int intc_irqpin_irq_set_wake(struct irq_data *d, unsigned int on) |
268 | { |
269 | struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d); |
270 | int hw_irq = irqd_to_hwirq(d); |
271 | |
272 | irq_set_irq_wake(irq: p->irq[hw_irq].requested_irq, on); |
273 | if (on) |
274 | atomic_inc(v: &p->wakeup_path); |
275 | else |
276 | atomic_dec(v: &p->wakeup_path); |
277 | |
278 | return 0; |
279 | } |
280 | |
281 | static irqreturn_t intc_irqpin_irq_handler(int irq, void *dev_id) |
282 | { |
283 | struct intc_irqpin_irq *i = dev_id; |
284 | struct intc_irqpin_priv *p = i->p; |
285 | unsigned long bit; |
286 | |
287 | intc_irqpin_dbg(i, str: "demux1" ); |
288 | bit = intc_irqpin_hwirq_mask(p, INTC_IRQPIN_REG_SOURCE, hw_irq: i->hw_irq); |
289 | |
290 | if (intc_irqpin_read(p, INTC_IRQPIN_REG_SOURCE) & bit) { |
291 | intc_irqpin_write(p, INTC_IRQPIN_REG_SOURCE, data: ~bit); |
292 | intc_irqpin_dbg(i, str: "demux2" ); |
293 | generic_handle_irq(irq: i->domain_irq); |
294 | return IRQ_HANDLED; |
295 | } |
296 | return IRQ_NONE; |
297 | } |
298 | |
299 | static irqreturn_t intc_irqpin_shared_irq_handler(int irq, void *dev_id) |
300 | { |
301 | struct intc_irqpin_priv *p = dev_id; |
302 | unsigned int reg_source = intc_irqpin_read(p, INTC_IRQPIN_REG_SOURCE); |
303 | irqreturn_t status = IRQ_NONE; |
304 | int k; |
305 | |
306 | for (k = 0; k < 8; k++) { |
307 | if (reg_source & BIT(7 - k)) { |
308 | if (BIT(k) & p->shared_irq_mask) |
309 | continue; |
310 | |
311 | status |= intc_irqpin_irq_handler(irq, dev_id: &p->irq[k]); |
312 | } |
313 | } |
314 | |
315 | return status; |
316 | } |
317 | |
318 | /* |
319 | * This lock class tells lockdep that INTC External IRQ Pin irqs are in a |
320 | * different category than their parents, so it won't report false recursion. |
321 | */ |
322 | static struct lock_class_key intc_irqpin_irq_lock_class; |
323 | |
324 | /* And this is for the request mutex */ |
325 | static struct lock_class_key intc_irqpin_irq_request_class; |
326 | |
327 | static int intc_irqpin_irq_domain_map(struct irq_domain *h, unsigned int virq, |
328 | irq_hw_number_t hw) |
329 | { |
330 | struct intc_irqpin_priv *p = h->host_data; |
331 | |
332 | p->irq[hw].domain_irq = virq; |
333 | p->irq[hw].hw_irq = hw; |
334 | |
335 | intc_irqpin_dbg(i: &p->irq[hw], str: "map" ); |
336 | irq_set_chip_data(irq: virq, data: h->host_data); |
337 | irq_set_lockdep_class(irq: virq, lock_class: &intc_irqpin_irq_lock_class, |
338 | request_class: &intc_irqpin_irq_request_class); |
339 | irq_set_chip_and_handler(irq: virq, chip: &p->irq_chip, handle: handle_level_irq); |
340 | return 0; |
341 | } |
342 | |
343 | static const struct irq_domain_ops intc_irqpin_irq_domain_ops = { |
344 | .map = intc_irqpin_irq_domain_map, |
345 | .xlate = irq_domain_xlate_twocell, |
346 | }; |
347 | |
348 | static const struct intc_irqpin_config intc_irqpin_irlm_r8a777x = { |
349 | .irlm_bit = 23, /* ICR0.IRLM0 */ |
350 | }; |
351 | |
352 | static const struct intc_irqpin_config intc_irqpin_rmobile = { |
353 | .irlm_bit = -1, |
354 | }; |
355 | |
356 | static const struct of_device_id intc_irqpin_dt_ids[] = { |
357 | { .compatible = "renesas,intc-irqpin" , }, |
358 | { .compatible = "renesas,intc-irqpin-r8a7778" , |
359 | .data = &intc_irqpin_irlm_r8a777x }, |
360 | { .compatible = "renesas,intc-irqpin-r8a7779" , |
361 | .data = &intc_irqpin_irlm_r8a777x }, |
362 | { .compatible = "renesas,intc-irqpin-r8a7740" , |
363 | .data = &intc_irqpin_rmobile }, |
364 | { .compatible = "renesas,intc-irqpin-sh73a0" , |
365 | .data = &intc_irqpin_rmobile }, |
366 | {}, |
367 | }; |
368 | MODULE_DEVICE_TABLE(of, intc_irqpin_dt_ids); |
369 | |
370 | static int intc_irqpin_probe(struct platform_device *pdev) |
371 | { |
372 | const struct intc_irqpin_config *config; |
373 | struct device *dev = &pdev->dev; |
374 | struct intc_irqpin_priv *p; |
375 | struct intc_irqpin_iomem *i; |
376 | struct resource *io[INTC_IRQPIN_REG_NR]; |
377 | struct irq_chip *irq_chip; |
378 | void (*enable_fn)(struct irq_data *d); |
379 | void (*disable_fn)(struct irq_data *d); |
380 | const char *name = dev_name(dev); |
381 | bool control_parent; |
382 | unsigned int nirqs; |
383 | int ref_irq; |
384 | int ret; |
385 | int k; |
386 | |
387 | p = devm_kzalloc(dev, size: sizeof(*p), GFP_KERNEL); |
388 | if (!p) |
389 | return -ENOMEM; |
390 | |
391 | /* deal with driver instance configuration */ |
392 | of_property_read_u32(np: dev->of_node, propname: "sense-bitfield-width" , |
393 | out_value: &p->sense_bitfield_width); |
394 | control_parent = of_property_read_bool(np: dev->of_node, propname: "control-parent" ); |
395 | if (!p->sense_bitfield_width) |
396 | p->sense_bitfield_width = 4; /* default to 4 bits */ |
397 | |
398 | p->pdev = pdev; |
399 | platform_set_drvdata(pdev, data: p); |
400 | |
401 | config = of_device_get_match_data(dev); |
402 | |
403 | pm_runtime_enable(dev); |
404 | pm_runtime_get_sync(dev); |
405 | |
406 | /* get hold of register banks */ |
407 | memset(io, 0, sizeof(io)); |
408 | for (k = 0; k < INTC_IRQPIN_REG_NR; k++) { |
409 | io[k] = platform_get_resource(pdev, IORESOURCE_MEM, k); |
410 | if (!io[k] && k < INTC_IRQPIN_REG_NR_MANDATORY) { |
411 | dev_err(dev, "not enough IOMEM resources\n" ); |
412 | ret = -EINVAL; |
413 | goto err0; |
414 | } |
415 | } |
416 | |
417 | /* allow any number of IRQs between 1 and INTC_IRQPIN_MAX */ |
418 | for (k = 0; k < INTC_IRQPIN_MAX; k++) { |
419 | ret = platform_get_irq_optional(pdev, k); |
420 | if (ret == -ENXIO) |
421 | break; |
422 | if (ret < 0) |
423 | goto err0; |
424 | |
425 | p->irq[k].p = p; |
426 | p->irq[k].requested_irq = ret; |
427 | } |
428 | |
429 | nirqs = k; |
430 | if (nirqs < 1) { |
431 | dev_err(dev, "not enough IRQ resources\n" ); |
432 | ret = -EINVAL; |
433 | goto err0; |
434 | } |
435 | |
436 | /* ioremap IOMEM and setup read/write callbacks */ |
437 | for (k = 0; k < INTC_IRQPIN_REG_NR; k++) { |
438 | i = &p->iomem[k]; |
439 | |
440 | /* handle optional registers */ |
441 | if (!io[k]) |
442 | continue; |
443 | |
444 | switch (resource_size(res: io[k])) { |
445 | case 1: |
446 | i->width = 8; |
447 | i->read = intc_irqpin_read8; |
448 | i->write = intc_irqpin_write8; |
449 | break; |
450 | case 4: |
451 | i->width = 32; |
452 | i->read = intc_irqpin_read32; |
453 | i->write = intc_irqpin_write32; |
454 | break; |
455 | default: |
456 | dev_err(dev, "IOMEM size mismatch\n" ); |
457 | ret = -EINVAL; |
458 | goto err0; |
459 | } |
460 | |
461 | i->iomem = devm_ioremap(dev, offset: io[k]->start, |
462 | size: resource_size(res: io[k])); |
463 | if (!i->iomem) { |
464 | dev_err(dev, "failed to remap IOMEM\n" ); |
465 | ret = -ENXIO; |
466 | goto err0; |
467 | } |
468 | } |
469 | |
470 | /* configure "individual IRQ mode" where needed */ |
471 | if (config && config->irlm_bit >= 0) { |
472 | if (io[INTC_IRQPIN_REG_IRLM]) |
473 | intc_irqpin_read_modify_write(p, INTC_IRQPIN_REG_IRLM, |
474 | shift: config->irlm_bit, width: 1, value: 1); |
475 | else |
476 | dev_warn(dev, "unable to select IRLM mode\n" ); |
477 | } |
478 | |
479 | /* mask all interrupts using priority */ |
480 | for (k = 0; k < nirqs; k++) |
481 | intc_irqpin_mask_unmask_prio(p, irq: k, do_mask: 1); |
482 | |
483 | /* clear all pending interrupts */ |
484 | intc_irqpin_write(p, INTC_IRQPIN_REG_SOURCE, data: 0x0); |
485 | |
486 | /* scan for shared interrupt lines */ |
487 | ref_irq = p->irq[0].requested_irq; |
488 | p->shared_irqs = 1; |
489 | for (k = 1; k < nirqs; k++) { |
490 | if (ref_irq != p->irq[k].requested_irq) { |
491 | p->shared_irqs = 0; |
492 | break; |
493 | } |
494 | } |
495 | |
496 | /* use more severe masking method if requested */ |
497 | if (control_parent) { |
498 | enable_fn = intc_irqpin_irq_enable_force; |
499 | disable_fn = intc_irqpin_irq_disable_force; |
500 | } else if (!p->shared_irqs) { |
501 | enable_fn = intc_irqpin_irq_enable; |
502 | disable_fn = intc_irqpin_irq_disable; |
503 | } else { |
504 | enable_fn = intc_irqpin_shared_irq_enable; |
505 | disable_fn = intc_irqpin_shared_irq_disable; |
506 | } |
507 | |
508 | irq_chip = &p->irq_chip; |
509 | irq_chip->name = "intc-irqpin" ; |
510 | irq_chip->irq_mask = disable_fn; |
511 | irq_chip->irq_unmask = enable_fn; |
512 | irq_chip->irq_set_type = intc_irqpin_irq_set_type; |
513 | irq_chip->irq_set_wake = intc_irqpin_irq_set_wake; |
514 | irq_chip->flags = IRQCHIP_MASK_ON_SUSPEND; |
515 | |
516 | p->irq_domain = irq_domain_add_simple(of_node: dev->of_node, size: nirqs, first_irq: 0, |
517 | ops: &intc_irqpin_irq_domain_ops, host_data: p); |
518 | if (!p->irq_domain) { |
519 | ret = -ENXIO; |
520 | dev_err(dev, "cannot initialize irq domain\n" ); |
521 | goto err0; |
522 | } |
523 | |
524 | irq_domain_set_pm_device(d: p->irq_domain, dev); |
525 | |
526 | if (p->shared_irqs) { |
527 | /* request one shared interrupt */ |
528 | if (devm_request_irq(dev, irq: p->irq[0].requested_irq, |
529 | handler: intc_irqpin_shared_irq_handler, |
530 | IRQF_SHARED, devname: name, dev_id: p)) { |
531 | dev_err(dev, "failed to request low IRQ\n" ); |
532 | ret = -ENOENT; |
533 | goto err1; |
534 | } |
535 | } else { |
536 | /* request interrupts one by one */ |
537 | for (k = 0; k < nirqs; k++) { |
538 | if (devm_request_irq(dev, irq: p->irq[k].requested_irq, |
539 | handler: intc_irqpin_irq_handler, irqflags: 0, devname: name, |
540 | dev_id: &p->irq[k])) { |
541 | dev_err(dev, "failed to request low IRQ\n" ); |
542 | ret = -ENOENT; |
543 | goto err1; |
544 | } |
545 | } |
546 | } |
547 | |
548 | /* unmask all interrupts on prio level */ |
549 | for (k = 0; k < nirqs; k++) |
550 | intc_irqpin_mask_unmask_prio(p, irq: k, do_mask: 0); |
551 | |
552 | dev_info(dev, "driving %d irqs\n" , nirqs); |
553 | |
554 | return 0; |
555 | |
556 | err1: |
557 | irq_domain_remove(host: p->irq_domain); |
558 | err0: |
559 | pm_runtime_put(dev); |
560 | pm_runtime_disable(dev); |
561 | return ret; |
562 | } |
563 | |
564 | static void intc_irqpin_remove(struct platform_device *pdev) |
565 | { |
566 | struct intc_irqpin_priv *p = platform_get_drvdata(pdev); |
567 | |
568 | irq_domain_remove(host: p->irq_domain); |
569 | pm_runtime_put(dev: &pdev->dev); |
570 | pm_runtime_disable(dev: &pdev->dev); |
571 | } |
572 | |
573 | static int __maybe_unused intc_irqpin_suspend(struct device *dev) |
574 | { |
575 | struct intc_irqpin_priv *p = dev_get_drvdata(dev); |
576 | |
577 | if (atomic_read(v: &p->wakeup_path)) |
578 | device_set_wakeup_path(dev); |
579 | |
580 | return 0; |
581 | } |
582 | |
583 | static SIMPLE_DEV_PM_OPS(intc_irqpin_pm_ops, intc_irqpin_suspend, NULL); |
584 | |
585 | static struct platform_driver intc_irqpin_device_driver = { |
586 | .probe = intc_irqpin_probe, |
587 | .remove_new = intc_irqpin_remove, |
588 | .driver = { |
589 | .name = "renesas_intc_irqpin" , |
590 | .of_match_table = intc_irqpin_dt_ids, |
591 | .pm = &intc_irqpin_pm_ops, |
592 | } |
593 | }; |
594 | |
595 | static int __init intc_irqpin_init(void) |
596 | { |
597 | return platform_driver_register(&intc_irqpin_device_driver); |
598 | } |
599 | postcore_initcall(intc_irqpin_init); |
600 | |
601 | static void __exit intc_irqpin_exit(void) |
602 | { |
603 | platform_driver_unregister(&intc_irqpin_device_driver); |
604 | } |
605 | module_exit(intc_irqpin_exit); |
606 | |
607 | MODULE_AUTHOR("Magnus Damm" ); |
608 | MODULE_DESCRIPTION("Renesas INTC External IRQ Pin Driver" ); |
609 | |