1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Renesas RZ/V2H(P) ICU Driver
4 *
5 * Based on irq-renesas-rzg2l.c
6 *
7 * Copyright (C) 2024 Renesas Electronics Corporation.
8 *
9 * Author: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
10 */
11
12 #include <linux/bitfield.h>
13 #include <linux/cleanup.h>
14 #include <linux/clk.h>
15 #include <linux/err.h>
16 #include <linux/io.h>
17 #include <linux/irqchip.h>
18 #include <linux/irqchip/irq-renesas-rzv2h.h>
19 #include <linux/irqdomain.h>
20 #include <linux/of_address.h>
21 #include <linux/of_platform.h>
22 #include <linux/pm_runtime.h>
23 #include <linux/reset.h>
24 #include <linux/spinlock.h>
25 #include <linux/syscore_ops.h>
26
27 /* DT "interrupts" indexes */
28 #define ICU_IRQ_START 1
29 #define ICU_IRQ_COUNT 16
30 #define ICU_TINT_START (ICU_IRQ_START + ICU_IRQ_COUNT)
31 #define ICU_TINT_COUNT 32
32 #define ICU_NUM_IRQ (ICU_TINT_START + ICU_TINT_COUNT)
33
34 /* Registers */
35 #define ICU_NSCNT 0x00
36 #define ICU_NSCLR 0x04
37 #define ICU_NITSR 0x08
38 #define ICU_ISCTR 0x10
39 #define ICU_ISCLR 0x14
40 #define ICU_IITSR 0x18
41 #define ICU_TSCTR 0x20
42 #define ICU_TSCLR 0x24
43 #define ICU_TITSR(k) (0x28 + (k) * 4)
44 #define ICU_TSSR(k) (0x30 + (k) * 4)
45 #define ICU_DMkSELy(k, y) (0x420 + (k) * 0x20 + (y) * 4)
46 #define ICU_DMACKSELk(k) (0x500 + (k) * 4)
47
48 /* NMI */
49 #define ICU_NMI_EDGE_FALLING 0
50 #define ICU_NMI_EDGE_RISING 1
51
52 #define ICU_NSCLR_NCLR BIT(0)
53
54 /* IRQ */
55 #define ICU_IRQ_LEVEL_LOW 0
56 #define ICU_IRQ_EDGE_FALLING 1
57 #define ICU_IRQ_EDGE_RISING 2
58 #define ICU_IRQ_EDGE_BOTH 3
59
60 #define ICU_IITSR_IITSEL_PREP(iitsel, n) ((iitsel) << ((n) * 2))
61 #define ICU_IITSR_IITSEL_GET(iitsr, n) (((iitsr) >> ((n) * 2)) & 0x03)
62 #define ICU_IITSR_IITSEL_MASK(n) ICU_IITSR_IITSEL_PREP(0x03, n)
63
64 /* TINT */
65 #define ICU_TINT_EDGE_RISING 0
66 #define ICU_TINT_EDGE_FALLING 1
67 #define ICU_TINT_LEVEL_HIGH 2
68 #define ICU_TINT_LEVEL_LOW 3
69
70 #define ICU_TSSR_TSSEL_PREP(tssel, n, field_width) ((tssel) << ((n) * (field_width)))
71 #define ICU_TSSR_TSSEL_MASK(n, field_width) \
72 ({\
73 typeof(field_width) (_field_width) = (field_width); \
74 ICU_TSSR_TSSEL_PREP((GENMASK(((_field_width) - 2), 0)), (n), _field_width); \
75 })
76
77 #define ICU_TSSR_TIEN(n, field_width) \
78 ({\
79 typeof(field_width) (_field_width) = (field_width); \
80 BIT((_field_width) - 1) << ((n) * (_field_width)); \
81 })
82
83 #define ICU_TITSR_K(tint_nr) ((tint_nr) / 16)
84 #define ICU_TITSR_TITSEL_N(tint_nr) ((tint_nr) % 16)
85 #define ICU_TITSR_TITSEL_PREP(titsel, n) ICU_IITSR_IITSEL_PREP(titsel, n)
86 #define ICU_TITSR_TITSEL_MASK(n) ICU_IITSR_IITSEL_MASK(n)
87 #define ICU_TITSR_TITSEL_GET(titsr, n) ICU_IITSR_IITSEL_GET(titsr, n)
88
89 #define ICU_TINT_EXTRACT_HWIRQ(x) FIELD_GET(GENMASK(15, 0), (x))
90 #define ICU_TINT_EXTRACT_GPIOINT(x) FIELD_GET(GENMASK(31, 16), (x))
91 #define ICU_RZG3E_TINT_OFFSET 0x800
92 #define ICU_RZG3E_TSSEL_MAX_VAL 0x8c
93 #define ICU_RZV2H_TSSEL_MAX_VAL 0x55
94
95 /**
96 * struct rzv2h_hw_info - Interrupt Control Unit controller hardware info structure.
97 * @tssel_lut: TINT lookup table
98 * @t_offs: TINT offset
99 * @max_tssel: TSSEL max value
100 * @field_width: TSSR field width
101 */
102 struct rzv2h_hw_info {
103 const u8 *tssel_lut;
104 u16 t_offs;
105 u8 max_tssel;
106 u8 field_width;
107 };
108
109 /* DMAC */
110 #define ICU_DMAC_DkRQ_SEL_MASK GENMASK(9, 0)
111
112 #define ICU_DMAC_DMAREQ_SHIFT(up) ((up) * 16)
113 #define ICU_DMAC_DMAREQ_MASK(up) (ICU_DMAC_DkRQ_SEL_MASK \
114 << ICU_DMAC_DMAREQ_SHIFT(up))
115 #define ICU_DMAC_PREP_DMAREQ(sel, up) (FIELD_PREP(ICU_DMAC_DkRQ_SEL_MASK, (sel)) \
116 << ICU_DMAC_DMAREQ_SHIFT(up))
117
118 /**
119 * struct rzv2h_icu_priv - Interrupt Control Unit controller private data structure.
120 * @base: Controller's base address
121 * @fwspec: IRQ firmware specific data
122 * @lock: Lock to serialize access to hardware registers
123 * @info: Pointer to struct rzv2h_hw_info
124 */
125 struct rzv2h_icu_priv {
126 void __iomem *base;
127 struct irq_fwspec fwspec[ICU_NUM_IRQ];
128 raw_spinlock_t lock;
129 const struct rzv2h_hw_info *info;
130 };
131
rzv2h_icu_register_dma_req(struct platform_device * icu_dev,u8 dmac_index,u8 dmac_channel,u16 req_no)132 void rzv2h_icu_register_dma_req(struct platform_device *icu_dev, u8 dmac_index, u8 dmac_channel,
133 u16 req_no)
134 {
135 struct rzv2h_icu_priv *priv = platform_get_drvdata(icu_dev);
136 u32 icu_dmksely, dmareq, dmareq_mask;
137 u8 y, upper;
138
139 y = dmac_channel / 2;
140 upper = dmac_channel % 2;
141
142 dmareq = ICU_DMAC_PREP_DMAREQ(req_no, upper);
143 dmareq_mask = ICU_DMAC_DMAREQ_MASK(upper);
144
145 guard(raw_spinlock_irqsave)(&priv->lock);
146
147 icu_dmksely = readl(priv->base + ICU_DMkSELy(dmac_index, y));
148 icu_dmksely = (icu_dmksely & ~dmareq_mask) | dmareq;
149 writel(icu_dmksely, priv->base + ICU_DMkSELy(dmac_index, y));
150 }
151 EXPORT_SYMBOL_GPL(rzv2h_icu_register_dma_req);
152
irq_data_to_priv(struct irq_data * data)153 static inline struct rzv2h_icu_priv *irq_data_to_priv(struct irq_data *data)
154 {
155 return data->domain->host_data;
156 }
157
rzv2h_icu_eoi(struct irq_data * d)158 static void rzv2h_icu_eoi(struct irq_data *d)
159 {
160 struct rzv2h_icu_priv *priv = irq_data_to_priv(d);
161 unsigned int hw_irq = irqd_to_hwirq(d);
162 unsigned int tintirq_nr;
163 u32 bit;
164
165 scoped_guard(raw_spinlock, &priv->lock) {
166 if (hw_irq >= ICU_TINT_START) {
167 tintirq_nr = hw_irq - ICU_TINT_START;
168 bit = BIT(tintirq_nr);
169 if (!irqd_is_level_type(d))
170 writel_relaxed(bit, priv->base + priv->info->t_offs + ICU_TSCLR);
171 } else if (hw_irq >= ICU_IRQ_START) {
172 tintirq_nr = hw_irq - ICU_IRQ_START;
173 bit = BIT(tintirq_nr);
174 if (!irqd_is_level_type(d))
175 writel_relaxed(bit, priv->base + ICU_ISCLR);
176 } else {
177 writel_relaxed(ICU_NSCLR_NCLR, priv->base + ICU_NSCLR);
178 }
179 }
180
181 irq_chip_eoi_parent(d);
182 }
183
rzv2h_tint_irq_endisable(struct irq_data * d,bool enable)184 static void rzv2h_tint_irq_endisable(struct irq_data *d, bool enable)
185 {
186 struct rzv2h_icu_priv *priv = irq_data_to_priv(d);
187 unsigned int hw_irq = irqd_to_hwirq(d);
188 u32 tint_nr, tssel_n, k, tssr;
189 u8 nr_tint;
190
191 if (hw_irq < ICU_TINT_START)
192 return;
193
194 tint_nr = hw_irq - ICU_TINT_START;
195 nr_tint = 32 / priv->info->field_width;
196 k = tint_nr / nr_tint;
197 tssel_n = tint_nr % nr_tint;
198
199 guard(raw_spinlock)(&priv->lock);
200 tssr = readl_relaxed(priv->base + priv->info->t_offs + ICU_TSSR(k));
201 if (enable)
202 tssr |= ICU_TSSR_TIEN(tssel_n, priv->info->field_width);
203 else
204 tssr &= ~ICU_TSSR_TIEN(tssel_n, priv->info->field_width);
205 writel_relaxed(tssr, priv->base + priv->info->t_offs + ICU_TSSR(k));
206
207 /*
208 * A glitch in the edge detection circuit can cause a spurious
209 * interrupt. Clear the status flag after setting the ICU_TSSRk
210 * registers, which is recommended by the hardware manual as a
211 * countermeasure.
212 */
213 writel_relaxed(BIT(tint_nr), priv->base + priv->info->t_offs + ICU_TSCLR);
214 }
215
rzv2h_icu_irq_disable(struct irq_data * d)216 static void rzv2h_icu_irq_disable(struct irq_data *d)
217 {
218 irq_chip_disable_parent(d);
219 rzv2h_tint_irq_endisable(d, false);
220 }
221
rzv2h_icu_irq_enable(struct irq_data * d)222 static void rzv2h_icu_irq_enable(struct irq_data *d)
223 {
224 rzv2h_tint_irq_endisable(d, true);
225 irq_chip_enable_parent(d);
226 }
227
rzv2h_nmi_set_type(struct irq_data * d,unsigned int type)228 static int rzv2h_nmi_set_type(struct irq_data *d, unsigned int type)
229 {
230 struct rzv2h_icu_priv *priv = irq_data_to_priv(d);
231 u32 sense;
232
233 switch (type & IRQ_TYPE_SENSE_MASK) {
234 case IRQ_TYPE_EDGE_FALLING:
235 sense = ICU_NMI_EDGE_FALLING;
236 break;
237
238 case IRQ_TYPE_EDGE_RISING:
239 sense = ICU_NMI_EDGE_RISING;
240 break;
241
242 default:
243 return -EINVAL;
244 }
245
246 writel_relaxed(sense, priv->base + ICU_NITSR);
247
248 return 0;
249 }
250
rzv2h_clear_irq_int(struct rzv2h_icu_priv * priv,unsigned int hwirq)251 static void rzv2h_clear_irq_int(struct rzv2h_icu_priv *priv, unsigned int hwirq)
252 {
253 unsigned int irq_nr = hwirq - ICU_IRQ_START;
254 u32 isctr, iitsr, iitsel;
255 u32 bit = BIT(irq_nr);
256
257 isctr = readl_relaxed(priv->base + ICU_ISCTR);
258 iitsr = readl_relaxed(priv->base + ICU_IITSR);
259 iitsel = ICU_IITSR_IITSEL_GET(iitsr, irq_nr);
260
261 /*
262 * When level sensing is used, the interrupt flag gets automatically cleared when the
263 * interrupt signal is de-asserted by the source of the interrupt request, therefore clear
264 * the interrupt only for edge triggered interrupts.
265 */
266 if ((isctr & bit) && (iitsel != ICU_IRQ_LEVEL_LOW))
267 writel_relaxed(bit, priv->base + ICU_ISCLR);
268 }
269
rzv2h_irq_set_type(struct irq_data * d,unsigned int type)270 static int rzv2h_irq_set_type(struct irq_data *d, unsigned int type)
271 {
272 struct rzv2h_icu_priv *priv = irq_data_to_priv(d);
273 unsigned int hwirq = irqd_to_hwirq(d);
274 u32 irq_nr = hwirq - ICU_IRQ_START;
275 u32 iitsr, sense;
276
277 switch (type & IRQ_TYPE_SENSE_MASK) {
278 case IRQ_TYPE_LEVEL_LOW:
279 sense = ICU_IRQ_LEVEL_LOW;
280 break;
281
282 case IRQ_TYPE_EDGE_FALLING:
283 sense = ICU_IRQ_EDGE_FALLING;
284 break;
285
286 case IRQ_TYPE_EDGE_RISING:
287 sense = ICU_IRQ_EDGE_RISING;
288 break;
289
290 case IRQ_TYPE_EDGE_BOTH:
291 sense = ICU_IRQ_EDGE_BOTH;
292 break;
293
294 default:
295 return -EINVAL;
296 }
297
298 guard(raw_spinlock)(&priv->lock);
299 iitsr = readl_relaxed(priv->base + ICU_IITSR);
300 iitsr &= ~ICU_IITSR_IITSEL_MASK(irq_nr);
301 iitsr |= ICU_IITSR_IITSEL_PREP(sense, irq_nr);
302 rzv2h_clear_irq_int(priv, hwirq);
303 writel_relaxed(iitsr, priv->base + ICU_IITSR);
304
305 return 0;
306 }
307
rzv2h_clear_tint_int(struct rzv2h_icu_priv * priv,unsigned int hwirq)308 static void rzv2h_clear_tint_int(struct rzv2h_icu_priv *priv, unsigned int hwirq)
309 {
310 unsigned int tint_nr = hwirq - ICU_TINT_START;
311 int titsel_n = ICU_TITSR_TITSEL_N(tint_nr);
312 u32 tsctr, titsr, titsel;
313 u32 bit = BIT(tint_nr);
314 int k = tint_nr / 16;
315
316 tsctr = readl_relaxed(priv->base + priv->info->t_offs + ICU_TSCTR);
317 titsr = readl_relaxed(priv->base + priv->info->t_offs + ICU_TITSR(k));
318 titsel = ICU_TITSR_TITSEL_GET(titsr, titsel_n);
319
320 /*
321 * Writing 1 to the corresponding flag from register ICU_TSCTR only has effect if
322 * TSTATn = 1b and if it's a rising edge or a falling edge interrupt.
323 */
324 if ((tsctr & bit) && ((titsel == ICU_TINT_EDGE_RISING) ||
325 (titsel == ICU_TINT_EDGE_FALLING)))
326 writel_relaxed(bit, priv->base + priv->info->t_offs + ICU_TSCLR);
327 }
328
rzv2h_tint_set_type(struct irq_data * d,unsigned int type)329 static int rzv2h_tint_set_type(struct irq_data *d, unsigned int type)
330 {
331 u32 titsr, titsr_k, titsel_n, tien;
332 struct rzv2h_icu_priv *priv;
333 u32 tssr, tssr_k, tssel_n;
334 unsigned int hwirq;
335 u32 tint, sense;
336 int tint_nr;
337 u8 nr_tint;
338
339 switch (type & IRQ_TYPE_SENSE_MASK) {
340 case IRQ_TYPE_LEVEL_LOW:
341 sense = ICU_TINT_LEVEL_LOW;
342 break;
343
344 case IRQ_TYPE_LEVEL_HIGH:
345 sense = ICU_TINT_LEVEL_HIGH;
346 break;
347
348 case IRQ_TYPE_EDGE_RISING:
349 sense = ICU_TINT_EDGE_RISING;
350 break;
351
352 case IRQ_TYPE_EDGE_FALLING:
353 sense = ICU_TINT_EDGE_FALLING;
354 break;
355
356 default:
357 return -EINVAL;
358 }
359
360 priv = irq_data_to_priv(d);
361 tint = (u32)(uintptr_t)irq_data_get_irq_chip_data(d);
362 if (tint > priv->info->max_tssel)
363 return -EINVAL;
364
365 if (priv->info->tssel_lut)
366 tint = priv->info->tssel_lut[tint];
367
368 hwirq = irqd_to_hwirq(d);
369 tint_nr = hwirq - ICU_TINT_START;
370
371 nr_tint = 32 / priv->info->field_width;
372 tssr_k = tint_nr / nr_tint;
373 tssel_n = tint_nr % nr_tint;
374 tien = ICU_TSSR_TIEN(tssel_n, priv->info->field_width);
375
376 titsr_k = ICU_TITSR_K(tint_nr);
377 titsel_n = ICU_TITSR_TITSEL_N(tint_nr);
378
379 guard(raw_spinlock)(&priv->lock);
380
381 tssr = readl_relaxed(priv->base + priv->info->t_offs + ICU_TSSR(tssr_k));
382 tssr &= ~(ICU_TSSR_TSSEL_MASK(tssel_n, priv->info->field_width) | tien);
383 tssr |= ICU_TSSR_TSSEL_PREP(tint, tssel_n, priv->info->field_width);
384
385 writel_relaxed(tssr, priv->base + priv->info->t_offs + ICU_TSSR(tssr_k));
386
387 titsr = readl_relaxed(priv->base + priv->info->t_offs + ICU_TITSR(titsr_k));
388 titsr &= ~ICU_TITSR_TITSEL_MASK(titsel_n);
389 titsr |= ICU_TITSR_TITSEL_PREP(sense, titsel_n);
390
391 writel_relaxed(titsr, priv->base + priv->info->t_offs + ICU_TITSR(titsr_k));
392
393 rzv2h_clear_tint_int(priv, hwirq);
394
395 writel_relaxed(tssr | tien, priv->base + priv->info->t_offs + ICU_TSSR(tssr_k));
396
397 return 0;
398 }
399
rzv2h_icu_set_type(struct irq_data * d,unsigned int type)400 static int rzv2h_icu_set_type(struct irq_data *d, unsigned int type)
401 {
402 unsigned int hw_irq = irqd_to_hwirq(d);
403 int ret;
404
405 if (hw_irq >= ICU_TINT_START)
406 ret = rzv2h_tint_set_type(d, type);
407 else if (hw_irq >= ICU_IRQ_START)
408 ret = rzv2h_irq_set_type(d, type);
409 else
410 ret = rzv2h_nmi_set_type(d, type);
411
412 if (ret)
413 return ret;
414
415 return irq_chip_set_type_parent(d, IRQ_TYPE_LEVEL_HIGH);
416 }
417
418 static const struct irq_chip rzv2h_icu_chip = {
419 .name = "rzv2h-icu",
420 .irq_eoi = rzv2h_icu_eoi,
421 .irq_mask = irq_chip_mask_parent,
422 .irq_unmask = irq_chip_unmask_parent,
423 .irq_disable = rzv2h_icu_irq_disable,
424 .irq_enable = rzv2h_icu_irq_enable,
425 .irq_get_irqchip_state = irq_chip_get_parent_state,
426 .irq_set_irqchip_state = irq_chip_set_parent_state,
427 .irq_retrigger = irq_chip_retrigger_hierarchy,
428 .irq_set_type = rzv2h_icu_set_type,
429 .irq_set_affinity = irq_chip_set_affinity_parent,
430 .flags = IRQCHIP_SET_TYPE_MASKED,
431 };
432
rzv2h_icu_alloc(struct irq_domain * domain,unsigned int virq,unsigned int nr_irqs,void * arg)433 static int rzv2h_icu_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs,
434 void *arg)
435 {
436 struct rzv2h_icu_priv *priv = domain->host_data;
437 unsigned long tint = 0;
438 irq_hw_number_t hwirq;
439 unsigned int type;
440 int ret;
441
442 ret = irq_domain_translate_twocell(domain, arg, &hwirq, &type);
443 if (ret)
444 return ret;
445
446 /*
447 * For TINT interrupts the hwirq and TINT are encoded in
448 * fwspec->param[0].
449 * hwirq is embedded in bits 0-15.
450 * TINT is embedded in bits 16-31.
451 */
452 if (hwirq >= ICU_TINT_START) {
453 tint = ICU_TINT_EXTRACT_GPIOINT(hwirq);
454 hwirq = ICU_TINT_EXTRACT_HWIRQ(hwirq);
455
456 if (hwirq < ICU_TINT_START)
457 return -EINVAL;
458 }
459
460 if (hwirq > (ICU_NUM_IRQ - 1))
461 return -EINVAL;
462
463 ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, &rzv2h_icu_chip,
464 (void *)(uintptr_t)tint);
465 if (ret)
466 return ret;
467
468 return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &priv->fwspec[hwirq]);
469 }
470
471 static const struct irq_domain_ops rzv2h_icu_domain_ops = {
472 .alloc = rzv2h_icu_alloc,
473 .free = irq_domain_free_irqs_common,
474 .translate = irq_domain_translate_twocell,
475 };
476
rzv2h_icu_parse_interrupts(struct rzv2h_icu_priv * priv,struct device_node * np)477 static int rzv2h_icu_parse_interrupts(struct rzv2h_icu_priv *priv, struct device_node *np)
478 {
479 struct of_phandle_args map;
480 unsigned int i;
481 int ret;
482
483 for (i = 0; i < ICU_NUM_IRQ; i++) {
484 ret = of_irq_parse_one(np, i, &map);
485 if (ret)
486 return ret;
487
488 of_phandle_args_to_fwspec(np, map.args, map.args_count, &priv->fwspec[i]);
489 }
490
491 return 0;
492 }
493
rzv2h_icu_put_device(void * data)494 static void rzv2h_icu_put_device(void *data)
495 {
496 put_device(data);
497 }
498
rzv2h_icu_init_common(struct device_node * node,struct device_node * parent,const struct rzv2h_hw_info * hw_info)499 static int rzv2h_icu_init_common(struct device_node *node, struct device_node *parent,
500 const struct rzv2h_hw_info *hw_info)
501 {
502 struct irq_domain *irq_domain, *parent_domain;
503 struct rzv2h_icu_priv *rzv2h_icu_data;
504 struct platform_device *pdev;
505 struct reset_control *resetn;
506 int ret;
507
508 pdev = of_find_device_by_node(node);
509 if (!pdev)
510 return -ENODEV;
511
512 ret = devm_add_action_or_reset(&pdev->dev, rzv2h_icu_put_device,
513 &pdev->dev);
514 if (ret < 0)
515 return ret;
516
517 parent_domain = irq_find_host(parent);
518 if (!parent_domain) {
519 dev_err(&pdev->dev, "cannot find parent domain\n");
520 return -ENODEV;
521 }
522
523 rzv2h_icu_data = devm_kzalloc(&pdev->dev, sizeof(*rzv2h_icu_data), GFP_KERNEL);
524 if (!rzv2h_icu_data)
525 return -ENOMEM;
526
527 platform_set_drvdata(pdev, rzv2h_icu_data);
528
529 rzv2h_icu_data->base = devm_of_iomap(&pdev->dev, pdev->dev.of_node, 0, NULL);
530 if (IS_ERR(rzv2h_icu_data->base))
531 return PTR_ERR(rzv2h_icu_data->base);
532
533 ret = rzv2h_icu_parse_interrupts(rzv2h_icu_data, node);
534 if (ret) {
535 dev_err(&pdev->dev, "cannot parse interrupts: %d\n", ret);
536 return ret;
537 }
538
539 resetn = devm_reset_control_get_exclusive_deasserted(&pdev->dev, NULL);
540 if (IS_ERR(resetn)) {
541 ret = PTR_ERR(resetn);
542 dev_err(&pdev->dev, "failed to acquire deasserted reset: %d\n", ret);
543 return ret;
544 }
545
546 ret = devm_pm_runtime_enable(&pdev->dev);
547 if (ret < 0) {
548 dev_err(&pdev->dev, "devm_pm_runtime_enable failed, %d\n", ret);
549 return ret;
550 }
551
552 ret = pm_runtime_resume_and_get(&pdev->dev);
553 if (ret < 0) {
554 dev_err(&pdev->dev, "pm_runtime_resume_and_get failed: %d\n", ret);
555 return ret;
556 }
557
558 raw_spin_lock_init(&rzv2h_icu_data->lock);
559
560 irq_domain = irq_domain_create_hierarchy(parent_domain, 0, ICU_NUM_IRQ,
561 of_fwnode_handle(node), &rzv2h_icu_domain_ops,
562 rzv2h_icu_data);
563 if (!irq_domain) {
564 dev_err(&pdev->dev, "failed to add irq domain\n");
565 ret = -ENOMEM;
566 goto pm_put;
567 }
568
569 rzv2h_icu_data->info = hw_info;
570
571 /*
572 * coccicheck complains about a missing put_device call before returning, but it's a false
573 * positive. We still need &pdev->dev after successfully returning from this function.
574 */
575 return 0;
576
577 pm_put:
578 pm_runtime_put(&pdev->dev);
579
580 return ret;
581 }
582
583 /* Mapping based on port index on Table 4.2-6 and TSSEL bits on Table 4.6-4 */
584 static const u8 rzg3e_tssel_lut[] = {
585 81, 82, 83, 84, 85, 86, 87, 88, /* P00-P07 */
586 89, 90, 91, 92, 93, 94, 95, 96, /* P10-P17 */
587 111, 112, /* P20-P21 */
588 97, 98, 99, 100, 101, 102, 103, 104, /* P30-P37 */
589 105, 106, 107, 108, 109, 110, /* P40-P45 */
590 113, 114, 115, 116, 117, 118, 119, /* P50-P56 */
591 120, 121, 122, 123, 124, 125, 126, /* P60-P66 */
592 127, 128, 129, 130, 131, 132, 133, 134, /* P70-P77 */
593 135, 136, 137, 138, 139, 140, /* P80-P85 */
594 43, 44, 45, 46, 47, 48, 49, 50, /* PA0-PA7 */
595 51, 52, 53, 54, 55, 56, 57, 58, /* PB0-PB7 */
596 59, 60, 61, /* PC0-PC2 */
597 62, 63, 64, 65, 66, 67, 68, 69, /* PD0-PD7 */
598 70, 71, 72, 73, 74, 75, 76, 77, /* PE0-PE7 */
599 78, 79, 80, /* PF0-PF2 */
600 25, 26, 27, 28, 29, 30, 31, 32, /* PG0-PG7 */
601 33, 34, 35, 36, 37, 38, /* PH0-PH5 */
602 4, 5, 6, 7, 8, /* PJ0-PJ4 */
603 39, 40, 41, 42, /* PK0-PK3 */
604 9, 10, 11, 12, 21, 22, 23, 24, /* PL0-PL7 */
605 13, 14, 15, 16, 17, 18, 19, 20, /* PM0-PM7 */
606 0, 1, 2, 3 /* PS0-PS3 */
607 };
608
609 static const struct rzv2h_hw_info rzg3e_hw_params = {
610 .tssel_lut = rzg3e_tssel_lut,
611 .t_offs = ICU_RZG3E_TINT_OFFSET,
612 .max_tssel = ICU_RZG3E_TSSEL_MAX_VAL,
613 .field_width = 16,
614 };
615
616 static const struct rzv2h_hw_info rzv2h_hw_params = {
617 .t_offs = 0,
618 .max_tssel = ICU_RZV2H_TSSEL_MAX_VAL,
619 .field_width = 8,
620 };
621
rzg3e_icu_init(struct device_node * node,struct device_node * parent)622 static int rzg3e_icu_init(struct device_node *node, struct device_node *parent)
623 {
624 return rzv2h_icu_init_common(node, parent, &rzg3e_hw_params);
625 }
626
rzv2h_icu_init(struct device_node * node,struct device_node * parent)627 static int rzv2h_icu_init(struct device_node *node, struct device_node *parent)
628 {
629 return rzv2h_icu_init_common(node, parent, &rzv2h_hw_params);
630 }
631
632 IRQCHIP_PLATFORM_DRIVER_BEGIN(rzv2h_icu)
633 IRQCHIP_MATCH("renesas,r9a09g047-icu", rzg3e_icu_init)
634 IRQCHIP_MATCH("renesas,r9a09g057-icu", rzv2h_icu_init)
635 IRQCHIP_PLATFORM_DRIVER_END(rzv2h_icu)
636 MODULE_AUTHOR("Fabrizio Castro <fabrizio.castro.jz@renesas.com>");
637 MODULE_DESCRIPTION("Renesas RZ/V2H(P) ICU Driver");
638