| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | | - * Copyright (c) 2012-2015, 2017, The Linux Foundation. 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. |
|---|
| 3 | + * Copyright (c) 2012-2015, 2017, 2021, The Linux Foundation. All rights reserved. |
|---|
| 12 | 4 | */ |
|---|
| 13 | 5 | #include <linux/bitmap.h> |
|---|
| 14 | 6 | #include <linux/delay.h> |
|---|
| .. | .. |
|---|
| 513 | 505 | static void periph_interrupt(struct spmi_pmic_arb *pmic_arb, u16 apid) |
|---|
| 514 | 506 | { |
|---|
| 515 | 507 | unsigned int irq; |
|---|
| 516 | | - u32 status; |
|---|
| 517 | | - int id; |
|---|
| 508 | + u32 status, id; |
|---|
| 518 | 509 | u8 sid = (pmic_arb->apid_data[apid].ppid >> 8) & 0xF; |
|---|
| 519 | 510 | u8 per = pmic_arb->apid_data[apid].ppid & 0xFF; |
|---|
| 520 | 511 | |
|---|
| .. | .. |
|---|
| 666 | 657 | return 0; |
|---|
| 667 | 658 | } |
|---|
| 668 | 659 | |
|---|
| 669 | | -static int qpnpint_irq_request_resources(struct irq_data *d) |
|---|
| 660 | +static int qpnpint_irq_domain_activate(struct irq_domain *domain, |
|---|
| 661 | + struct irq_data *d, bool reserve) |
|---|
| 670 | 662 | { |
|---|
| 671 | 663 | struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d); |
|---|
| 672 | 664 | u16 periph = hwirq_to_per(d->hwirq); |
|---|
| .. | .. |
|---|
| 692 | 684 | .irq_set_type = qpnpint_irq_set_type, |
|---|
| 693 | 685 | .irq_set_wake = qpnpint_irq_set_wake, |
|---|
| 694 | 686 | .irq_get_irqchip_state = qpnpint_get_irqchip_state, |
|---|
| 695 | | - .irq_request_resources = qpnpint_irq_request_resources, |
|---|
| 696 | 687 | .flags = IRQCHIP_MASK_ON_SUSPEND, |
|---|
| 697 | 688 | }; |
|---|
| 698 | 689 | |
|---|
| 699 | | -static int qpnpint_irq_domain_dt_translate(struct irq_domain *d, |
|---|
| 700 | | - struct device_node *controller, |
|---|
| 701 | | - const u32 *intspec, |
|---|
| 702 | | - unsigned int intsize, |
|---|
| 703 | | - unsigned long *out_hwirq, |
|---|
| 704 | | - unsigned int *out_type) |
|---|
| 690 | +static int qpnpint_irq_domain_translate(struct irq_domain *d, |
|---|
| 691 | + struct irq_fwspec *fwspec, |
|---|
| 692 | + unsigned long *out_hwirq, |
|---|
| 693 | + unsigned int *out_type) |
|---|
| 705 | 694 | { |
|---|
| 706 | 695 | struct spmi_pmic_arb *pmic_arb = d->host_data; |
|---|
| 696 | + u32 *intspec = fwspec->param; |
|---|
| 707 | 697 | u16 apid, ppid; |
|---|
| 708 | 698 | int rc; |
|---|
| 709 | 699 | |
|---|
| 710 | 700 | dev_dbg(&pmic_arb->spmic->dev, "intspec[0] 0x%1x intspec[1] 0x%02x intspec[2] 0x%02x\n", |
|---|
| 711 | 701 | intspec[0], intspec[1], intspec[2]); |
|---|
| 712 | 702 | |
|---|
| 713 | | - if (irq_domain_get_of_node(d) != controller) |
|---|
| 703 | + if (irq_domain_get_of_node(d) != pmic_arb->spmic->dev.of_node) |
|---|
| 714 | 704 | return -EINVAL; |
|---|
| 715 | | - if (intsize != 4) |
|---|
| 705 | + if (fwspec->param_count != 4) |
|---|
| 716 | 706 | return -EINVAL; |
|---|
| 717 | 707 | if (intspec[0] > 0xF || intspec[1] > 0xFF || intspec[2] > 0x7) |
|---|
| 718 | 708 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 740 | 730 | return 0; |
|---|
| 741 | 731 | } |
|---|
| 742 | 732 | |
|---|
| 743 | | -static int qpnpint_irq_domain_map(struct irq_domain *d, |
|---|
| 744 | | - unsigned int virq, |
|---|
| 745 | | - irq_hw_number_t hwirq) |
|---|
| 733 | +static struct lock_class_key qpnpint_irq_lock_class, qpnpint_irq_request_class; |
|---|
| 734 | + |
|---|
| 735 | +static void qpnpint_irq_domain_map(struct spmi_pmic_arb *pmic_arb, |
|---|
| 736 | + struct irq_domain *domain, unsigned int virq, |
|---|
| 737 | + irq_hw_number_t hwirq, unsigned int type) |
|---|
| 746 | 738 | { |
|---|
| 747 | | - struct spmi_pmic_arb *pmic_arb = d->host_data; |
|---|
| 739 | + irq_flow_handler_t handler; |
|---|
| 748 | 740 | |
|---|
| 749 | | - dev_dbg(&pmic_arb->spmic->dev, "virq = %u, hwirq = %lu\n", virq, hwirq); |
|---|
| 741 | + dev_dbg(&pmic_arb->spmic->dev, "virq = %u, hwirq = %lu, type = %u\n", |
|---|
| 742 | + virq, hwirq, type); |
|---|
| 750 | 743 | |
|---|
| 751 | | - irq_set_chip_and_handler(virq, &pmic_arb_irqchip, handle_level_irq); |
|---|
| 752 | | - irq_set_chip_data(virq, d->host_data); |
|---|
| 753 | | - irq_set_noprobe(virq); |
|---|
| 744 | + if (type & IRQ_TYPE_EDGE_BOTH) |
|---|
| 745 | + handler = handle_edge_irq; |
|---|
| 746 | + else |
|---|
| 747 | + handler = handle_level_irq; |
|---|
| 748 | + |
|---|
| 749 | + |
|---|
| 750 | + irq_set_lockdep_class(virq, &qpnpint_irq_lock_class, |
|---|
| 751 | + &qpnpint_irq_request_class); |
|---|
| 752 | + irq_domain_set_info(domain, virq, hwirq, &pmic_arb_irqchip, pmic_arb, |
|---|
| 753 | + handler, NULL, NULL); |
|---|
| 754 | +} |
|---|
| 755 | + |
|---|
| 756 | +static int qpnpint_irq_domain_alloc(struct irq_domain *domain, |
|---|
| 757 | + unsigned int virq, unsigned int nr_irqs, |
|---|
| 758 | + void *data) |
|---|
| 759 | +{ |
|---|
| 760 | + struct spmi_pmic_arb *pmic_arb = domain->host_data; |
|---|
| 761 | + struct irq_fwspec *fwspec = data; |
|---|
| 762 | + irq_hw_number_t hwirq; |
|---|
| 763 | + unsigned int type; |
|---|
| 764 | + int ret, i; |
|---|
| 765 | + |
|---|
| 766 | + ret = qpnpint_irq_domain_translate(domain, fwspec, &hwirq, &type); |
|---|
| 767 | + if (ret) |
|---|
| 768 | + return ret; |
|---|
| 769 | + |
|---|
| 770 | + for (i = 0; i < nr_irqs; i++) |
|---|
| 771 | + qpnpint_irq_domain_map(pmic_arb, domain, virq + i, hwirq + i, |
|---|
| 772 | + type); |
|---|
| 773 | + |
|---|
| 754 | 774 | return 0; |
|---|
| 755 | 775 | } |
|---|
| 756 | 776 | |
|---|
| .. | .. |
|---|
| 867 | 887 | * version 5, there is more than one APID mapped to each PPID. |
|---|
| 868 | 888 | * The owner field for each of these mappings specifies the EE which is |
|---|
| 869 | 889 | * allowed to write to the APID. The owner of the last (highest) APID |
|---|
| 870 | | - * for a given PPID will receive interrupts from the PPID. |
|---|
| 890 | + * which has the IRQ owner bit set for a given PPID will receive |
|---|
| 891 | + * interrupts from the PPID. |
|---|
| 871 | 892 | */ |
|---|
| 872 | 893 | for (i = 0; ; i++, apidd++) { |
|---|
| 873 | 894 | offset = pmic_arb->ver_ops->apid_map_offset(i); |
|---|
| .. | .. |
|---|
| 890 | 911 | apid = pmic_arb->ppid_to_apid[ppid] & ~PMIC_ARB_APID_VALID; |
|---|
| 891 | 912 | prev_apidd = &pmic_arb->apid_data[apid]; |
|---|
| 892 | 913 | |
|---|
| 893 | | - if (valid && is_irq_ee && |
|---|
| 894 | | - prev_apidd->write_ee == pmic_arb->ee) { |
|---|
| 914 | + if (!valid || apidd->write_ee == pmic_arb->ee) { |
|---|
| 915 | + /* First PPID mapping or one for this EE */ |
|---|
| 916 | + pmic_arb->ppid_to_apid[ppid] = i | PMIC_ARB_APID_VALID; |
|---|
| 917 | + } else if (valid && is_irq_ee && |
|---|
| 918 | + prev_apidd->write_ee == pmic_arb->ee) { |
|---|
| 895 | 919 | /* |
|---|
| 896 | 920 | * Duplicate PPID mapping after the one for this EE; |
|---|
| 897 | 921 | * override the irq owner |
|---|
| 898 | 922 | */ |
|---|
| 899 | 923 | prev_apidd->irq_ee = apidd->irq_ee; |
|---|
| 900 | | - } else if (!valid || is_irq_ee) { |
|---|
| 901 | | - /* First PPID mapping or duplicate for another EE */ |
|---|
| 902 | | - pmic_arb->ppid_to_apid[ppid] = i | PMIC_ARB_APID_VALID; |
|---|
| 903 | 924 | } |
|---|
| 904 | 925 | |
|---|
| 905 | 926 | apidd->ppid = ppid; |
|---|
| .. | .. |
|---|
| 1126 | 1147 | }; |
|---|
| 1127 | 1148 | |
|---|
| 1128 | 1149 | static const struct irq_domain_ops pmic_arb_irq_domain_ops = { |
|---|
| 1129 | | - .map = qpnpint_irq_domain_map, |
|---|
| 1130 | | - .xlate = qpnpint_irq_domain_dt_translate, |
|---|
| 1150 | + .activate = qpnpint_irq_domain_activate, |
|---|
| 1151 | + .alloc = qpnpint_irq_domain_alloc, |
|---|
| 1152 | + .free = irq_domain_free_irqs_common, |
|---|
| 1153 | + .translate = qpnpint_irq_domain_translate, |
|---|
| 1131 | 1154 | }; |
|---|
| 1132 | 1155 | |
|---|
| 1133 | 1156 | static int spmi_pmic_arb_probe(struct platform_device *pdev) |
|---|