Loading drivers/pinctrl/qcom/pinctrl-msm.c +124 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,8 @@ #include <linux/log2.h> #include <linux/bitmap.h> #include <linux/soc/qcom/irq.h> #include "../core.h" #include "../pinconf.h" #include "pinctrl-msm.h" Loading @@ -46,6 +48,7 @@ * @enabled_irqs: Bitmap of currently enabled irqs. * @dual_edge_irqs: Bitmap of irqs that need sw emulated dual edge * detection. * @skip_wake_irqs: Skip IRQs that are handled by wakeup interrupt contrroller * @soc; Reference to soc_data of platform specific data. * @regs: Base addresses for the TLMM tiles. */ Loading @@ -63,6 +66,7 @@ struct msm_pinctrl { DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO); DECLARE_BITMAP(enabled_irqs, MAX_NR_GPIO); DECLARE_BITMAP(skip_wake_irqs, MAX_NR_GPIO); const struct msm_pinctrl_soc_data *soc; void __iomem *regs[MAX_NR_TILES]; Loading Loading @@ -715,6 +719,12 @@ static void msm_gpio_irq_mask(struct irq_data *d) unsigned long flags; u32 val; if (d->parent_data) irq_chip_mask_parent(d); if (test_bit(d->hwirq, pctrl->skip_wake_irqs)) return; g = &pctrl->soc->groups[d->hwirq]; raw_spin_lock_irqsave(&pctrl->lock, flags); Loading Loading @@ -759,6 +769,12 @@ static void msm_gpio_irq_clear_unmask(struct irq_data *d, bool status_clear) unsigned long flags; u32 val; if (d->parent_data) irq_chip_unmask_parent(d); if (test_bit(d->hwirq, pctrl->skip_wake_irqs)) return; g = &pctrl->soc->groups[d->hwirq]; raw_spin_lock_irqsave(&pctrl->lock, flags); Loading Loading @@ -786,10 +802,43 @@ static void msm_gpio_irq_clear_unmask(struct irq_data *d, bool status_clear) static void msm_gpio_irq_enable(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct msm_pinctrl *pctrl = gpiochip_get_data(gc); /* * Clear the interrupt that may be pending before we enable * the line. * This is especially a problem with the GPIOs routed to the * PDC. These GPIOs are direct-connect interrupts to the GIC. * Disabling the interrupt line at the PDC does not prevent * the interrupt from being latched at the GIC. The state at * GIC needs to be cleared before enabling. */ if (d->parent_data) { irq_chip_set_parent_state(d, IRQCHIP_STATE_PENDING, 0); irq_chip_enable_parent(d); } if (test_bit(d->hwirq, pctrl->skip_wake_irqs)) return; msm_gpio_irq_clear_unmask(d, true); } static void msm_gpio_irq_disable(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct msm_pinctrl *pctrl = gpiochip_get_data(gc); if (d->parent_data) irq_chip_disable_parent(d); if (test_bit(d->hwirq, pctrl->skip_wake_irqs)) return; msm_gpio_irq_mask(d); } static void msm_gpio_irq_unmask(struct irq_data *d) { msm_gpio_irq_clear_unmask(d, false); Loading @@ -803,6 +852,9 @@ static void msm_gpio_irq_ack(struct irq_data *d) unsigned long flags; u32 val; if (test_bit(d->hwirq, pctrl->skip_wake_irqs)) return; g = &pctrl->soc->groups[d->hwirq]; raw_spin_lock_irqsave(&pctrl->lock, flags); Loading @@ -828,6 +880,12 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) unsigned long flags; u32 val; if (d->parent_data) irq_chip_set_type_parent(d, type); if (test_bit(d->hwirq, pctrl->skip_wake_irqs)) return 0; g = &pctrl->soc->groups[d->hwirq]; raw_spin_lock_irqsave(&pctrl->lock, flags); Loading Loading @@ -920,6 +978,15 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on) struct msm_pinctrl *pctrl = gpiochip_get_data(gc); unsigned long flags; if (d->parent_data) irq_chip_set_wake_parent(d, on); /* * While they may not wake up when the TLMM is powered off, * some GPIOs would like to wakeup the system from suspend * when TLMM is powered on. To allow that, enable the GPIO * summary line to be wakeup capable at GIC. */ raw_spin_lock_irqsave(&pctrl->lock, flags); irq_set_irq_wake(pctrl->irq, on); Loading Loading @@ -998,6 +1065,30 @@ static void msm_gpio_irq_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); } static int msm_gpio_wakeirq(struct gpio_chip *gc, unsigned int child, unsigned int child_type, unsigned int *parent, unsigned int *parent_type) { struct msm_pinctrl *pctrl = gpiochip_get_data(gc); const struct msm_gpio_wakeirq_map *map; int i; *parent = GPIO_NO_WAKE_IRQ; *parent_type = IRQ_TYPE_EDGE_RISING; for (i = 0; i < pctrl->soc->nwakeirq_map; i++) { map = &pctrl->soc->wakeirq_map[i]; if (map->gpio == child) { *parent = map->wakeirq; break; } } return 0; } static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl) { if (pctrl->soc->reserved_gpios) Loading @@ -1012,6 +1103,7 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) struct gpio_irq_chip *girq; int ret; unsigned ngpio = pctrl->soc->ngpios; struct device_node *dn; if (WARN_ON(ngpio > MAX_NR_GPIO)) return -EINVAL; Loading @@ -1028,14 +1120,36 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) pctrl->irq_chip.name = "msmgpio"; pctrl->irq_chip.irq_enable = msm_gpio_irq_enable; pctrl->irq_chip.irq_disable = msm_gpio_irq_disable; pctrl->irq_chip.irq_mask = msm_gpio_irq_mask; pctrl->irq_chip.irq_unmask = msm_gpio_irq_unmask; pctrl->irq_chip.irq_ack = msm_gpio_irq_ack; pctrl->irq_chip.irq_eoi = irq_chip_eoi_parent; pctrl->irq_chip.irq_set_type = msm_gpio_irq_set_type; pctrl->irq_chip.irq_set_wake = msm_gpio_irq_set_wake; pctrl->irq_chip.irq_request_resources = msm_gpio_irq_reqres; pctrl->irq_chip.irq_release_resources = msm_gpio_irq_relres; dn = of_parse_phandle(pctrl->dev->of_node, "wakeup-parent", 0); if (dn) { int i; bool skip; unsigned int gpio; chip->irq.parent_domain = irq_find_matching_host(dn, DOMAIN_BUS_WAKEUP); of_node_put(dn); if (!chip->irq.parent_domain) return -EPROBE_DEFER; chip->irq.child_to_parent_hwirq = msm_gpio_wakeirq; skip = irq_domain_qcom_handle_wakeup(chip->irq.parent_domain); for (i = 0; skip && i < pctrl->soc->nwakeirq_map; i++) { gpio = pctrl->soc->wakeirq_map[i].gpio; set_bit(gpio, pctrl->skip_wake_irqs); } } girq = &chip->irq; girq->chip = &pctrl->irq_chip; girq->parent_handler = msm_gpio_irq_handler; Loading Loading @@ -1074,6 +1188,16 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) } } /* * Since we are chained to the GIC using the TLMM summary line * and in hierarchy with the wakeup parent interrupt controller, * explicitly set the chained summary line. We need to do this because * the summary line is not routed to the wakeup parent but directly * to the GIC. */ gpiochip_set_chained_irqchip(chip, &pctrl->irq_chip, pctrl->irq, msm_gpio_irq_handler); return 0; } Loading drivers/pinctrl/qcom/pinctrl-msm.h +15 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ #define __PINCTRL_MSM_H__ #include <linux/pinctrl/qcom-pinctrl.h> #include <linux/gpio/driver.h> struct pinctrl_pin_desc; Loading Loading @@ -110,6 +111,16 @@ struct pinctrl_qup { u32 offset; }; /** * struct msm_gpio_wakeirq_map - Map of GPIOs and their wakeup pins * @gpio: The GPIOs that are wakeup capable * @wakeirq: The interrupt at the always-on interrupt controller */ struct msm_gpio_wakeirq_map { unsigned int gpio; unsigned int wakeirq; }; /** * struct msm_pinctrl_soc_data - Qualcomm pin controller driver configuration * @pins: An array describing all pins the pin controller affects. Loading @@ -120,6 +131,8 @@ struct pinctrl_qup { * @ngroups: The numbmer of entries in @groups. * @ngpio: The number of pingroups the driver should expose as GPIOs. * @pull_no_keeper: The SoC does not support keeper bias. * @wakeirq_map: The map of wakeup capable GPIOs and the pin at PDC/MPM * @nwakeirq_map: The number of entries in @hierarchy_map */ struct msm_pinctrl_soc_data { const struct pinctrl_pin_desc *pins; Loading @@ -135,6 +148,8 @@ struct msm_pinctrl_soc_data { const int *reserved_gpios; struct pinctrl_qup *qup_regs; unsigned int nqup_regs; const struct msm_gpio_wakeirq_map *wakeirq_map; unsigned int nwakeirq_map; }; extern const struct dev_pm_ops msm_pinctrl_dev_pm_ops; Loading Loading
drivers/pinctrl/qcom/pinctrl-msm.c +124 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,8 @@ #include <linux/log2.h> #include <linux/bitmap.h> #include <linux/soc/qcom/irq.h> #include "../core.h" #include "../pinconf.h" #include "pinctrl-msm.h" Loading @@ -46,6 +48,7 @@ * @enabled_irqs: Bitmap of currently enabled irqs. * @dual_edge_irqs: Bitmap of irqs that need sw emulated dual edge * detection. * @skip_wake_irqs: Skip IRQs that are handled by wakeup interrupt contrroller * @soc; Reference to soc_data of platform specific data. * @regs: Base addresses for the TLMM tiles. */ Loading @@ -63,6 +66,7 @@ struct msm_pinctrl { DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO); DECLARE_BITMAP(enabled_irqs, MAX_NR_GPIO); DECLARE_BITMAP(skip_wake_irqs, MAX_NR_GPIO); const struct msm_pinctrl_soc_data *soc; void __iomem *regs[MAX_NR_TILES]; Loading Loading @@ -715,6 +719,12 @@ static void msm_gpio_irq_mask(struct irq_data *d) unsigned long flags; u32 val; if (d->parent_data) irq_chip_mask_parent(d); if (test_bit(d->hwirq, pctrl->skip_wake_irqs)) return; g = &pctrl->soc->groups[d->hwirq]; raw_spin_lock_irqsave(&pctrl->lock, flags); Loading Loading @@ -759,6 +769,12 @@ static void msm_gpio_irq_clear_unmask(struct irq_data *d, bool status_clear) unsigned long flags; u32 val; if (d->parent_data) irq_chip_unmask_parent(d); if (test_bit(d->hwirq, pctrl->skip_wake_irqs)) return; g = &pctrl->soc->groups[d->hwirq]; raw_spin_lock_irqsave(&pctrl->lock, flags); Loading Loading @@ -786,10 +802,43 @@ static void msm_gpio_irq_clear_unmask(struct irq_data *d, bool status_clear) static void msm_gpio_irq_enable(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct msm_pinctrl *pctrl = gpiochip_get_data(gc); /* * Clear the interrupt that may be pending before we enable * the line. * This is especially a problem with the GPIOs routed to the * PDC. These GPIOs are direct-connect interrupts to the GIC. * Disabling the interrupt line at the PDC does not prevent * the interrupt from being latched at the GIC. The state at * GIC needs to be cleared before enabling. */ if (d->parent_data) { irq_chip_set_parent_state(d, IRQCHIP_STATE_PENDING, 0); irq_chip_enable_parent(d); } if (test_bit(d->hwirq, pctrl->skip_wake_irqs)) return; msm_gpio_irq_clear_unmask(d, true); } static void msm_gpio_irq_disable(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct msm_pinctrl *pctrl = gpiochip_get_data(gc); if (d->parent_data) irq_chip_disable_parent(d); if (test_bit(d->hwirq, pctrl->skip_wake_irqs)) return; msm_gpio_irq_mask(d); } static void msm_gpio_irq_unmask(struct irq_data *d) { msm_gpio_irq_clear_unmask(d, false); Loading @@ -803,6 +852,9 @@ static void msm_gpio_irq_ack(struct irq_data *d) unsigned long flags; u32 val; if (test_bit(d->hwirq, pctrl->skip_wake_irqs)) return; g = &pctrl->soc->groups[d->hwirq]; raw_spin_lock_irqsave(&pctrl->lock, flags); Loading @@ -828,6 +880,12 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) unsigned long flags; u32 val; if (d->parent_data) irq_chip_set_type_parent(d, type); if (test_bit(d->hwirq, pctrl->skip_wake_irqs)) return 0; g = &pctrl->soc->groups[d->hwirq]; raw_spin_lock_irqsave(&pctrl->lock, flags); Loading Loading @@ -920,6 +978,15 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on) struct msm_pinctrl *pctrl = gpiochip_get_data(gc); unsigned long flags; if (d->parent_data) irq_chip_set_wake_parent(d, on); /* * While they may not wake up when the TLMM is powered off, * some GPIOs would like to wakeup the system from suspend * when TLMM is powered on. To allow that, enable the GPIO * summary line to be wakeup capable at GIC. */ raw_spin_lock_irqsave(&pctrl->lock, flags); irq_set_irq_wake(pctrl->irq, on); Loading Loading @@ -998,6 +1065,30 @@ static void msm_gpio_irq_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); } static int msm_gpio_wakeirq(struct gpio_chip *gc, unsigned int child, unsigned int child_type, unsigned int *parent, unsigned int *parent_type) { struct msm_pinctrl *pctrl = gpiochip_get_data(gc); const struct msm_gpio_wakeirq_map *map; int i; *parent = GPIO_NO_WAKE_IRQ; *parent_type = IRQ_TYPE_EDGE_RISING; for (i = 0; i < pctrl->soc->nwakeirq_map; i++) { map = &pctrl->soc->wakeirq_map[i]; if (map->gpio == child) { *parent = map->wakeirq; break; } } return 0; } static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl) { if (pctrl->soc->reserved_gpios) Loading @@ -1012,6 +1103,7 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) struct gpio_irq_chip *girq; int ret; unsigned ngpio = pctrl->soc->ngpios; struct device_node *dn; if (WARN_ON(ngpio > MAX_NR_GPIO)) return -EINVAL; Loading @@ -1028,14 +1120,36 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) pctrl->irq_chip.name = "msmgpio"; pctrl->irq_chip.irq_enable = msm_gpio_irq_enable; pctrl->irq_chip.irq_disable = msm_gpio_irq_disable; pctrl->irq_chip.irq_mask = msm_gpio_irq_mask; pctrl->irq_chip.irq_unmask = msm_gpio_irq_unmask; pctrl->irq_chip.irq_ack = msm_gpio_irq_ack; pctrl->irq_chip.irq_eoi = irq_chip_eoi_parent; pctrl->irq_chip.irq_set_type = msm_gpio_irq_set_type; pctrl->irq_chip.irq_set_wake = msm_gpio_irq_set_wake; pctrl->irq_chip.irq_request_resources = msm_gpio_irq_reqres; pctrl->irq_chip.irq_release_resources = msm_gpio_irq_relres; dn = of_parse_phandle(pctrl->dev->of_node, "wakeup-parent", 0); if (dn) { int i; bool skip; unsigned int gpio; chip->irq.parent_domain = irq_find_matching_host(dn, DOMAIN_BUS_WAKEUP); of_node_put(dn); if (!chip->irq.parent_domain) return -EPROBE_DEFER; chip->irq.child_to_parent_hwirq = msm_gpio_wakeirq; skip = irq_domain_qcom_handle_wakeup(chip->irq.parent_domain); for (i = 0; skip && i < pctrl->soc->nwakeirq_map; i++) { gpio = pctrl->soc->wakeirq_map[i].gpio; set_bit(gpio, pctrl->skip_wake_irqs); } } girq = &chip->irq; girq->chip = &pctrl->irq_chip; girq->parent_handler = msm_gpio_irq_handler; Loading Loading @@ -1074,6 +1188,16 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) } } /* * Since we are chained to the GIC using the TLMM summary line * and in hierarchy with the wakeup parent interrupt controller, * explicitly set the chained summary line. We need to do this because * the summary line is not routed to the wakeup parent but directly * to the GIC. */ gpiochip_set_chained_irqchip(chip, &pctrl->irq_chip, pctrl->irq, msm_gpio_irq_handler); return 0; } Loading
drivers/pinctrl/qcom/pinctrl-msm.h +15 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ #define __PINCTRL_MSM_H__ #include <linux/pinctrl/qcom-pinctrl.h> #include <linux/gpio/driver.h> struct pinctrl_pin_desc; Loading Loading @@ -110,6 +111,16 @@ struct pinctrl_qup { u32 offset; }; /** * struct msm_gpio_wakeirq_map - Map of GPIOs and their wakeup pins * @gpio: The GPIOs that are wakeup capable * @wakeirq: The interrupt at the always-on interrupt controller */ struct msm_gpio_wakeirq_map { unsigned int gpio; unsigned int wakeirq; }; /** * struct msm_pinctrl_soc_data - Qualcomm pin controller driver configuration * @pins: An array describing all pins the pin controller affects. Loading @@ -120,6 +131,8 @@ struct pinctrl_qup { * @ngroups: The numbmer of entries in @groups. * @ngpio: The number of pingroups the driver should expose as GPIOs. * @pull_no_keeper: The SoC does not support keeper bias. * @wakeirq_map: The map of wakeup capable GPIOs and the pin at PDC/MPM * @nwakeirq_map: The number of entries in @hierarchy_map */ struct msm_pinctrl_soc_data { const struct pinctrl_pin_desc *pins; Loading @@ -135,6 +148,8 @@ struct msm_pinctrl_soc_data { const int *reserved_gpios; struct pinctrl_qup *qup_regs; unsigned int nqup_regs; const struct msm_gpio_wakeirq_map *wakeirq_map; unsigned int nwakeirq_map; }; extern const struct dev_pm_ops msm_pinctrl_dev_pm_ops; Loading