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 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 153 static inline struct rzv2h_icu_priv *irq_data_to_priv(struct irq_data *data) 154 { 155 return data->domain->host_data; 156 } 157 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 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 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 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 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 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 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 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 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 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 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 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 494 static void rzv2h_icu_put_device(void *data) 495 { 496 put_device(data); 497 } 498 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 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 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