| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (c) 2011, Code Aurora Forum. All rights reserved. |
|---|
| 3 | | - * |
|---|
| 4 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 5 | | - * it under the terms of the GNU General Public License version 2 and |
|---|
| 6 | | - * only version 2 as published by the Free Software Foundation. |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 9 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 10 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 11 | | - * GNU General Public License for more details. |
|---|
| 12 | 4 | */ |
|---|
| 13 | 5 | |
|---|
| 14 | 6 | #define pr_fmt(fmt) "%s: " fmt, __func__ |
|---|
| .. | .. |
|---|
| 70 | 62 | #define PM8XXX_NR_IRQS 256 |
|---|
| 71 | 63 | #define PM8821_NR_IRQS 112 |
|---|
| 72 | 64 | |
|---|
| 65 | +struct pm_irq_data { |
|---|
| 66 | + int num_irqs; |
|---|
| 67 | + struct irq_chip *irq_chip; |
|---|
| 68 | + void (*irq_handler)(struct irq_desc *desc); |
|---|
| 69 | +}; |
|---|
| 70 | + |
|---|
| 73 | 71 | struct pm_irq_chip { |
|---|
| 74 | 72 | struct regmap *regmap; |
|---|
| 75 | 73 | spinlock_t pm_irq_lock; |
|---|
| 76 | 74 | struct irq_domain *irqdomain; |
|---|
| 77 | | - unsigned int num_irqs; |
|---|
| 78 | 75 | unsigned int num_blocks; |
|---|
| 79 | 76 | unsigned int num_masters; |
|---|
| 80 | | - u8 config[0]; |
|---|
| 81 | | -}; |
|---|
| 82 | | - |
|---|
| 83 | | -struct pm_irq_data { |
|---|
| 84 | | - int num_irqs; |
|---|
| 85 | | - const struct irq_domain_ops *irq_domain_ops; |
|---|
| 86 | | - void (*irq_handler)(struct irq_desc *desc); |
|---|
| 77 | + const struct pm_irq_data *pm_irq_data; |
|---|
| 78 | + /* MUST BE AT THE END OF THIS STRUCT */ |
|---|
| 79 | + u8 config[]; |
|---|
| 87 | 80 | }; |
|---|
| 88 | 81 | |
|---|
| 89 | 82 | static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, unsigned int bp, |
|---|
| .. | .. |
|---|
| 375 | 368 | .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE, |
|---|
| 376 | 369 | }; |
|---|
| 377 | 370 | |
|---|
| 378 | | -static int pm8xxx_irq_domain_map(struct irq_domain *d, unsigned int irq, |
|---|
| 379 | | - irq_hw_number_t hwirq) |
|---|
| 371 | +static void pm8xxx_irq_domain_map(struct pm_irq_chip *chip, |
|---|
| 372 | + struct irq_domain *domain, unsigned int irq, |
|---|
| 373 | + irq_hw_number_t hwirq, unsigned int type) |
|---|
| 380 | 374 | { |
|---|
| 381 | | - struct pm_irq_chip *chip = d->host_data; |
|---|
| 382 | | - |
|---|
| 383 | | - irq_set_chip_and_handler(irq, &pm8xxx_irq_chip, handle_level_irq); |
|---|
| 384 | | - irq_set_chip_data(irq, chip); |
|---|
| 375 | + irq_domain_set_info(domain, irq, hwirq, chip->pm_irq_data->irq_chip, |
|---|
| 376 | + chip, handle_level_irq, NULL, NULL); |
|---|
| 385 | 377 | irq_set_noprobe(irq); |
|---|
| 378 | +} |
|---|
| 379 | + |
|---|
| 380 | +static int pm8xxx_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, |
|---|
| 381 | + unsigned int nr_irqs, void *data) |
|---|
| 382 | +{ |
|---|
| 383 | + struct pm_irq_chip *chip = domain->host_data; |
|---|
| 384 | + struct irq_fwspec *fwspec = data; |
|---|
| 385 | + irq_hw_number_t hwirq; |
|---|
| 386 | + unsigned int type; |
|---|
| 387 | + int ret, i; |
|---|
| 388 | + |
|---|
| 389 | + ret = irq_domain_translate_twocell(domain, fwspec, &hwirq, &type); |
|---|
| 390 | + if (ret) |
|---|
| 391 | + return ret; |
|---|
| 392 | + |
|---|
| 393 | + for (i = 0; i < nr_irqs; i++) |
|---|
| 394 | + pm8xxx_irq_domain_map(chip, domain, virq + i, hwirq + i, type); |
|---|
| 386 | 395 | |
|---|
| 387 | 396 | return 0; |
|---|
| 388 | 397 | } |
|---|
| 389 | 398 | |
|---|
| 390 | 399 | static const struct irq_domain_ops pm8xxx_irq_domain_ops = { |
|---|
| 391 | | - .xlate = irq_domain_xlate_twocell, |
|---|
| 392 | | - .map = pm8xxx_irq_domain_map, |
|---|
| 400 | + .alloc = pm8xxx_irq_domain_alloc, |
|---|
| 401 | + .free = irq_domain_free_irqs_common, |
|---|
| 402 | + .translate = irq_domain_translate_twocell, |
|---|
| 393 | 403 | }; |
|---|
| 394 | 404 | |
|---|
| 395 | 405 | static void pm8821_irq_mask_ack(struct irq_data *d) |
|---|
| .. | .. |
|---|
| 473 | 483 | .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE, |
|---|
| 474 | 484 | }; |
|---|
| 475 | 485 | |
|---|
| 476 | | -static int pm8821_irq_domain_map(struct irq_domain *d, unsigned int irq, |
|---|
| 477 | | - irq_hw_number_t hwirq) |
|---|
| 478 | | -{ |
|---|
| 479 | | - struct pm_irq_chip *chip = d->host_data; |
|---|
| 480 | | - |
|---|
| 481 | | - irq_set_chip_and_handler(irq, &pm8821_irq_chip, handle_level_irq); |
|---|
| 482 | | - irq_set_chip_data(irq, chip); |
|---|
| 483 | | - irq_set_noprobe(irq); |
|---|
| 484 | | - |
|---|
| 485 | | - return 0; |
|---|
| 486 | | -} |
|---|
| 487 | | - |
|---|
| 488 | | -static const struct irq_domain_ops pm8821_irq_domain_ops = { |
|---|
| 489 | | - .xlate = irq_domain_xlate_twocell, |
|---|
| 490 | | - .map = pm8821_irq_domain_map, |
|---|
| 491 | | -}; |
|---|
| 492 | | - |
|---|
| 493 | 486 | static const struct regmap_config ssbi_regmap_config = { |
|---|
| 494 | 487 | .reg_bits = 16, |
|---|
| 495 | 488 | .val_bits = 8, |
|---|
| .. | .. |
|---|
| 501 | 494 | |
|---|
| 502 | 495 | static const struct pm_irq_data pm8xxx_data = { |
|---|
| 503 | 496 | .num_irqs = PM8XXX_NR_IRQS, |
|---|
| 504 | | - .irq_domain_ops = &pm8xxx_irq_domain_ops, |
|---|
| 497 | + .irq_chip = &pm8xxx_irq_chip, |
|---|
| 505 | 498 | .irq_handler = pm8xxx_irq_handler, |
|---|
| 506 | 499 | }; |
|---|
| 507 | 500 | |
|---|
| 508 | 501 | static const struct pm_irq_data pm8821_data = { |
|---|
| 509 | 502 | .num_irqs = PM8821_NR_IRQS, |
|---|
| 510 | | - .irq_domain_ops = &pm8821_irq_domain_ops, |
|---|
| 503 | + .irq_chip = &pm8821_irq_chip, |
|---|
| 511 | 504 | .irq_handler = pm8821_irq_handler, |
|---|
| 512 | 505 | }; |
|---|
| 513 | 506 | |
|---|
| .. | .. |
|---|
| 571 | 564 | |
|---|
| 572 | 565 | platform_set_drvdata(pdev, chip); |
|---|
| 573 | 566 | chip->regmap = regmap; |
|---|
| 574 | | - chip->num_irqs = data->num_irqs; |
|---|
| 575 | | - chip->num_blocks = DIV_ROUND_UP(chip->num_irqs, 8); |
|---|
| 567 | + chip->num_blocks = DIV_ROUND_UP(data->num_irqs, 8); |
|---|
| 576 | 568 | chip->num_masters = DIV_ROUND_UP(chip->num_blocks, 8); |
|---|
| 569 | + chip->pm_irq_data = data; |
|---|
| 577 | 570 | spin_lock_init(&chip->pm_irq_lock); |
|---|
| 578 | 571 | |
|---|
| 579 | 572 | chip->irqdomain = irq_domain_add_linear(pdev->dev.of_node, |
|---|
| 580 | 573 | data->num_irqs, |
|---|
| 581 | | - data->irq_domain_ops, |
|---|
| 574 | + &pm8xxx_irq_domain_ops, |
|---|
| 582 | 575 | chip); |
|---|
| 583 | 576 | if (!chip->irqdomain) |
|---|
| 584 | 577 | return -ENODEV; |
|---|