Loading Documentation/devicetree/bindings/pinctrl/qcom,kona-pinctrl.txt +6 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,11 @@ KONA platform. Definition: must be 2. Specifying the pin number and flags, as defined in <dt-bindings/gpio/gpio.h> - wakeup-parent: Usage: optional Value type: <phandle> Definition: A phandle to the wakeup interrupt controller for the SoC. Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for a general description of GPIO and interrupt bindings. Loading Loading @@ -183,4 +188,5 @@ Example: #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; wakeup-parent = <&pdc>; }; drivers/irqchip/qcom-pdc.c +69 −3 Original line number Diff line number Diff line Loading @@ -13,12 +13,13 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_device.h> #include <linux/soc/qcom/irq.h> #include <linux/spinlock.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/types.h> #define PDC_MAX_IRQS 138 #define PDC_MAX_GPIO_IRQS 256 #define CLEAR_INTR(reg, intr) (reg & ~(1 << intr)) #define ENABLE_INTR(reg, intr) (reg | (1 << intr)) Loading Loading @@ -169,7 +170,6 @@ static irq_hw_number_t get_parent_hwirq(int pin) return (region->parent_base + pin - region->pin_base); } WARN_ON(1); return ~0UL; } Loading Loading @@ -232,6 +232,60 @@ static const struct irq_domain_ops qcom_pdc_ops = { .free = irq_domain_free_irqs_common, }; static int qcom_pdc_gpio_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *data) { struct qcom_irq_fwspec *qcom_fwspec = data; struct irq_fwspec *fwspec = &qcom_fwspec->fwspec; struct irq_fwspec parent_fwspec; irq_hw_number_t hwirq, parent_hwirq; unsigned int type; int ret; ret = qcom_pdc_translate(domain, fwspec, &hwirq, &type); if (ret) return -EINVAL; parent_hwirq = get_parent_hwirq(hwirq); if (parent_hwirq == ~0UL) return -EINVAL; ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, &qcom_pdc_gic_chip, NULL); if (ret) return ret; qcom_fwspec->mask = true; if (type & IRQ_TYPE_EDGE_BOTH) type = IRQ_TYPE_EDGE_RISING; if (type & IRQ_TYPE_LEVEL_MASK) type = IRQ_TYPE_LEVEL_HIGH; parent_fwspec.fwnode = domain->parent->fwnode; parent_fwspec.param_count = 3; parent_fwspec.param[0] = 0; parent_fwspec.param[1] = parent_hwirq; parent_fwspec.param[2] = type; return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &parent_fwspec); } static int qcom_pdc_gpio_domain_select(struct irq_domain *d, struct irq_fwspec *fwspec, enum irq_domain_bus_token bus_token) { return (bus_token == DOMAIN_BUS_WAKEUP); } static const struct irq_domain_ops qcom_pdc_gpio_ops = { .select = qcom_pdc_gpio_domain_select, .alloc = qcom_pdc_gpio_alloc, .free = irq_domain_free_irqs_common, }; static int pdc_setup_pin_mapping(struct device_node *np) { int ret, n; Loading Loading @@ -270,7 +324,7 @@ static int pdc_setup_pin_mapping(struct device_node *np) static int qcom_pdc_init(struct device_node *node, struct device_node *parent) { struct irq_domain *parent_domain, *pdc_domain; struct irq_domain *parent_domain, *pdc_domain, *pdc_gpio_domain; int ret; pdc_base = of_iomap(node, 0); Loading Loading @@ -301,6 +355,18 @@ static int qcom_pdc_init(struct device_node *node, struct device_node *parent) goto fail; } pdc_gpio_domain = irq_domain_create_hierarchy(parent_domain, 0, PDC_MAX_GPIO_IRQS, of_fwnode_handle(node), &qcom_pdc_gpio_ops, NULL); if (!pdc_gpio_domain) { pr_err("GIC domain add failed for GPIO domain\n"); ret = -ENOMEM; goto fail; } irq_domain_update_bus_token(pdc_gpio_domain, DOMAIN_BUS_WAKEUP); return 0; fail: Loading include/linux/soc/qcom/irq.h 0 → 100644 +26 −0 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2019, The Linux Foundation. All rights reserved. */ #ifndef __QCOM_IRQ_H #define __QCOM_IRQ_H #include <linux/irqdomain.h> /** * struct qcom_irq_fwspec - qcom specific irq fwspec wrapper * @fwspec: irq fwspec * @mask: if true, keep the irq masked in the gpio controller * * Use this structure to communicate between the parent irq chip, MPM or PDC, * to the gpio chip, TLMM, about the gpio being allocated in the parent * and if the gpio chip should keep the line masked because the parent irq * chip is handling everything about the irq line. */ struct qcom_irq_fwspec { struct irq_fwspec fwspec; bool mask; }; #endif Loading
Documentation/devicetree/bindings/pinctrl/qcom,kona-pinctrl.txt +6 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,11 @@ KONA platform. Definition: must be 2. Specifying the pin number and flags, as defined in <dt-bindings/gpio/gpio.h> - wakeup-parent: Usage: optional Value type: <phandle> Definition: A phandle to the wakeup interrupt controller for the SoC. Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for a general description of GPIO and interrupt bindings. Loading Loading @@ -183,4 +188,5 @@ Example: #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; wakeup-parent = <&pdc>; };
drivers/irqchip/qcom-pdc.c +69 −3 Original line number Diff line number Diff line Loading @@ -13,12 +13,13 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_device.h> #include <linux/soc/qcom/irq.h> #include <linux/spinlock.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/types.h> #define PDC_MAX_IRQS 138 #define PDC_MAX_GPIO_IRQS 256 #define CLEAR_INTR(reg, intr) (reg & ~(1 << intr)) #define ENABLE_INTR(reg, intr) (reg | (1 << intr)) Loading Loading @@ -169,7 +170,6 @@ static irq_hw_number_t get_parent_hwirq(int pin) return (region->parent_base + pin - region->pin_base); } WARN_ON(1); return ~0UL; } Loading Loading @@ -232,6 +232,60 @@ static const struct irq_domain_ops qcom_pdc_ops = { .free = irq_domain_free_irqs_common, }; static int qcom_pdc_gpio_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *data) { struct qcom_irq_fwspec *qcom_fwspec = data; struct irq_fwspec *fwspec = &qcom_fwspec->fwspec; struct irq_fwspec parent_fwspec; irq_hw_number_t hwirq, parent_hwirq; unsigned int type; int ret; ret = qcom_pdc_translate(domain, fwspec, &hwirq, &type); if (ret) return -EINVAL; parent_hwirq = get_parent_hwirq(hwirq); if (parent_hwirq == ~0UL) return -EINVAL; ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, &qcom_pdc_gic_chip, NULL); if (ret) return ret; qcom_fwspec->mask = true; if (type & IRQ_TYPE_EDGE_BOTH) type = IRQ_TYPE_EDGE_RISING; if (type & IRQ_TYPE_LEVEL_MASK) type = IRQ_TYPE_LEVEL_HIGH; parent_fwspec.fwnode = domain->parent->fwnode; parent_fwspec.param_count = 3; parent_fwspec.param[0] = 0; parent_fwspec.param[1] = parent_hwirq; parent_fwspec.param[2] = type; return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &parent_fwspec); } static int qcom_pdc_gpio_domain_select(struct irq_domain *d, struct irq_fwspec *fwspec, enum irq_domain_bus_token bus_token) { return (bus_token == DOMAIN_BUS_WAKEUP); } static const struct irq_domain_ops qcom_pdc_gpio_ops = { .select = qcom_pdc_gpio_domain_select, .alloc = qcom_pdc_gpio_alloc, .free = irq_domain_free_irqs_common, }; static int pdc_setup_pin_mapping(struct device_node *np) { int ret, n; Loading Loading @@ -270,7 +324,7 @@ static int pdc_setup_pin_mapping(struct device_node *np) static int qcom_pdc_init(struct device_node *node, struct device_node *parent) { struct irq_domain *parent_domain, *pdc_domain; struct irq_domain *parent_domain, *pdc_domain, *pdc_gpio_domain; int ret; pdc_base = of_iomap(node, 0); Loading Loading @@ -301,6 +355,18 @@ static int qcom_pdc_init(struct device_node *node, struct device_node *parent) goto fail; } pdc_gpio_domain = irq_domain_create_hierarchy(parent_domain, 0, PDC_MAX_GPIO_IRQS, of_fwnode_handle(node), &qcom_pdc_gpio_ops, NULL); if (!pdc_gpio_domain) { pr_err("GIC domain add failed for GPIO domain\n"); ret = -ENOMEM; goto fail; } irq_domain_update_bus_token(pdc_gpio_domain, DOMAIN_BUS_WAKEUP); return 0; fail: Loading
include/linux/soc/qcom/irq.h 0 → 100644 +26 −0 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2019, The Linux Foundation. All rights reserved. */ #ifndef __QCOM_IRQ_H #define __QCOM_IRQ_H #include <linux/irqdomain.h> /** * struct qcom_irq_fwspec - qcom specific irq fwspec wrapper * @fwspec: irq fwspec * @mask: if true, keep the irq masked in the gpio controller * * Use this structure to communicate between the parent irq chip, MPM or PDC, * to the gpio chip, TLMM, about the gpio being allocated in the parent * and if the gpio chip should keep the line masked because the parent irq * chip is handling everything about the irq line. */ struct qcom_irq_fwspec { struct irq_fwspec fwspec; bool mask; }; #endif