.. | .. |
---|
| 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) |
---|