Wakeup GPIO support for SDM845
Subsystems (6)
v3 cover Wakeup GPIO support for SDM845
Hi,
Changes in v3:
- Release memory allocated for IRQ anme
- Minor fixes as suggested by Mathias, Bjorn, Evan
Changes in v2:
- Compile and test on 4.18 on SDM845
- Fix IRQ map in patch #3
- Address review comments
(I still need to find a way to free memory allocated for PDC IRQ.)
- Specify type for IRQ in DT
- This series needs V3 of the PDC DT bingings [4]
- gic-v3 settings are also needed [5]
Changes in v1:
- Avoid GPIO-PDC map in .c file
- Trigger GPIO by writing to the hardware
- Hooked up to suspend/resume callbacks
- Dropped PDC DT bindings (see dependencies)
This is an attempt at a solution to enable wake up from suspend and deep idle using GPIO as a wakeup source. The 845 uses a new interrupt controller (PDC) that lies in the always-on domain and can sense interrupts that are routed to it, when the GIC is powered off. It would then wakeup the GIC and replay the interrupt which would then be relayed to the AP. The PDC interrupt controller driver is merged upstream [1],[2]. The following set of patches extends the wakeup capability to GPIOs using the PDC. The TLMM pinctrl driver for the SoC available at [3].
The complexity with the solution stems from the fact that only a selected few GPIO lines are routed to the PDC in addition the TLMMs. They are also from different banks on the pinctrl and the TLMM summary line is not routed to the PDC. Hence the PDC cannot be considered as parent of the TLMM irqchip (or can we ?). This is what it looks like -
[ PIN ] -----[ TLMM ]---------------> [ GIC ] ---> [ CPU ]
| <summary IRQ> ^
| |
----------------------------------> [ PDC ]
<wakeup IRQs>I had a brief discussion with Linus on this and the idea implemented is based on his suggestion.
When an IRQ (let's call this latent IRQ) for a GPIO is requested, the ->irq_request_resources() is used by the TLMM driver to request a PDC pin. The PDC pin associated with the GPIO is read from a static map available in the pinctrl-sdm845.c. (I think there should be a better location than a static map, more on that later). Knowing the PDC pin from the map, we could look up the DT bindings and request the PDC interrupt with the same trigger mask as the interrupt requested. The ->set_type and ->set_wake are also trapped to set the PDC IRQ's polarity and enable it when the latent IRQ is requested. When the PDC detects the interrupt at suspend, it wakes up the GIC and replays the wakeup IRQ. The GPIO handler function for the latent IRQ is invoked in turn.
Please review these patches and your inputs would be greatly appreciated and (kindly) let me know if I have committed any blunders with this approach. There is definitely opportunity to improve the location of the static GPIO-PDC pin map. We could possibly put it as an data argument in the interrupts definition of the PDC or with interrupt names. Also, I am still sorting out some issues with the IRQ handling part of these patches. And I am unsure of how to set the polarity of the PDC pin without locking, since we are not in hierarchy with the PDC interrupt controller. Again, your inputs on these would be greatly helpful.
Thanks,
Lina
[1]. drivers/irqchip/qcom-pdc.c
[2]. Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.txt [3]. drivers/pinctrl/qcom/pinctrl-msm.c
[4]. https://lore.kernel.org/patchwork/patch/977589/
[5]. https://lore.kernel.org/patchwork/patch/975425/
Lina Iyer (5):
drivers: pinctrl: qcom: add wakeup capability to GPIO
dt-bindings: pinctrl: add wakeup capable GPIOs for SDM845
drivers: pinctrl: msm: enable PDC interrupt only during suspend
drivers: pinctrl: qcom: sdm845: support GPIO wakeup from suspend
arm64: dts: qcom: add wake up interrupts for GPIOs for SDM845
.../bindings/pinctrl/qcom,sdm845-pinctrl.txt | 104 ++++++++++- arch/arm64/boot/dts/qcom/sdm845.dtsi | 152 ++++++++++++++- drivers/pinctrl/qcom/pinctrl-msm.c | 174 ++++++++++++++++++ drivers/pinctrl/qcom/pinctrl-msm.h | 5 + drivers/pinctrl/qcom/pinctrl-sdm845.c | 1 + 5 files changed, 432 insertions(+), 4 deletions(-)
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH v3 1/5 drivers: pinctrl: qcom: add wakeup capability to GPIO
QCOM SoC's that have Power Domain Controller (PDC) chip in the always-on domain can wakeup the SoC, when interrupts and GPIOs are routed to its interrupt controller. Only select GPIOs that are deemed wakeup capable are routed to specific PDC pins. During low power state, the pinmux interrupt controller may be non-functional but the PDC would be. The PDC can detect the wakeup GPIO is triggered and bring the TLMM to an operational state.
Interrupts that are level triggered will be detected at the TLMM when the controller becomes operational. Edge interrupts however need to be replayed again.
Request the corresponding PDC IRQ, when the GPIO is requested as an IRQ, but keep it disabled. During suspend, we can enable the PDC IRQ instead of the GPIO IRQ, which may or not be detected.
---
Changes in v3:
- free action->name
Changes in v2:
- Remove IRQF_NO_SUSPEND and IRQF_ONE_SHOT from PDC IRQ
Changes in v1:
- Trigger GPIO in h/w from PDC IRQ handler
- Avoid big tables for GPIO-PDC map, pick from DT instead
- Use handler_data
--- drivers/pinctrl/qcom/pinctrl-msm.c | 98 ++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+)
drivers/pinctrl/qcom/pinctrl-msm.c +98 -0
@@ -687,11 +687,15 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)const struct msm_pingroup *g;unsigned long flags;u32 val; +struct irq_data *pdc_irqd =irq_get_handler_data (d->irq); g = &pctrl->soc->groups[d->hwirq];raw_spin_lock_irqsave (&pctrl->lock, flags); +if (pdc_irqd) +irq_set_irq_type (pdc_irqd->irq, type); +/* * For hw without possibility of detecting both edges */
@@ -779,9 +783,13 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)struct gpio_chip *gc =irq_data_get_irq_chip_data (d);struct msm_pinctrl *pctrl =gpiochip_get_data (gc);unsigned long flags; +struct irq_data *pdc_irqd =irq_get_handler_data (d->irq);raw_spin_lock_irqsave (&pctrl->lock, flags); +if (pdc_irqd) +irq_set_irq_wake (pdc_irqd->irq, on); +irq_set_irq_wake (pctrl->irq, on);raw_spin_unlock_irqrestore (&pctrl->lock, flags);
@@ -863,6 +871,94 @@ static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl)return device_property_read_u16_array (pctrl->dev,"gpios" ,NULL ,0 ) >0 ; } +static irqreturn_t wake_irq_gpio_handler (int irq,void *data) +{ +struct irq_data *irqd = data; +struct gpio_chip *gc =irq_data_get_irq_chip_data (irqd); +struct msm_pinctrl *pctrl =gpiochip_get_data (gc); +const struct msm_pingroup *g; +unsigned long flags; +u32 val; + +if (!irqd_is_level_type (irqd)) { + g = &pctrl->soc->groups[irqd->hwirq]; +raw_spin_lock_irqsave (&pctrl->lock, flags); + val =BIT (g->intr_status_bit); +writel (val, pctrl->regs + g->intr_status_reg); +raw_spin_unlock_irqrestore (&pctrl->lock, flags); + } + +return IRQ_HANDLED ; +} + +static int msm_gpio_pdc_pin_request (struct irq_data *d) +{ +struct gpio_chip *gc =irq_data_get_irq_chip_data (d); +struct msm_pinctrl *pctrl =gpiochip_get_data (gc); +struct platform_device *pdev =to_platform_device (pctrl->dev); +const char *pin_name; +int irq; +int ret; + + pin_name =kasprintf (GFP_KERNEL ,"gpio%lu" , d->hwirq); +if (!pin_name) +return -ENOMEM ; + + irq =platform_get_irq_byname (pdev, pin_name); +if (irq <0 ) { +kfree (pin_name); +return 0 ; + } + + ret =request_irq (irq, wake_irq_gpio_handler,irqd_get_trigger_type (d), + pin_name, d); +if (ret) { +pr_warn ("GPIO-%lu could not be set up as wakeup" , d->hwirq); +kfree (pin_name); +return ret; + } + +irq_set_handler_data (d->irq,irq_get_irq_data (irq)); +disable_irq (irq); + +return 0 ; +} + +static int msm_gpio_pdc_pin_release (struct irq_data *d) +{ +struct irq_data *pdc_irqd =irq_get_handler_data (d->irq); +const void *name; + +if (pdc_irqd) { +irq_set_handler_data (d->irq,NULL ); + name =free_irq (pdc_irqd->irq, d); +kfree (name); + } + +return 0 ; +} + +static int msm_gpio_irq_reqres (struct irq_data *d) +{ +struct gpio_chip *gc =irq_data_get_irq_chip_data (d); + +if (gpiochip_lock_as_irq (gc,irqd_to_hwirq (d))) { +dev_err (gc->parent,"unable to lock HW IRQ %lu for IRQ\n" , +irqd_to_hwirq (d)); +return -EINVAL ; + } + +return msm_gpio_pdc_pin_request (d); +} + +static void msm_gpio_irq_relres (struct irq_data *d) +{ +struct gpio_chip *gc =irq_data_get_irq_chip_data (d); + +msm_gpio_pdc_pin_release (d); +gpiochip_unlock_as_irq (gc,irqd_to_hwirq (d)); +} +static int msm_gpio_init (struct msm_pinctrl *pctrl) {struct gpio_chip *chip;
@@ -887,6 +983,8 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) pctrl->irq_chip.irq_ack = msm_gpio_irq_ack; 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; ret =gpiochip_add_data (&pctrl->chip, pctrl);if (ret) {
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
Re: [PATCH v3 1/5] drivers: pinctrl: qcom: add wakeup capability to GPIO
Quoted 101 lines · Lina Iyer
QCOM SoC's that have Power Domain Controller (PDC) chip in the always-on domain can wakeup the SoC, when interrupts and GPIOs are routed to its interrupt controller. Only select GPIOs that are deemed wakeup capable are routed to specific PDC pins. During low power state, the pinmux interrupt controller may be non-functional but the PDC would be. The PDC can detect the wakeup GPIO is triggered and bring the TLMM to an operational state.
Interrupts that are level triggered will be detected at the TLMM when the controller becomes operational. Edge interrupts however need to be replayed again.
Request the corresponding PDC IRQ, when the GPIO is requested as an IRQ, but keep it disabled. During suspend, we can enable the PDC IRQ instead of the GPIO IRQ, which may or not be detected.
Signed-off-by Lina Iyer <[email protected]>---
Changes in v3:
- freeaction->name
Changes in v2:
- RemoveIRQF_NO_SUSPENDandIRQF_ONE_SHOTfrom PDC IRQ
Changes in v1:
- Trigger GPIO in h/w from PDC IRQ handler
- Avoid big tables for GPIO-PDC map, pick from DT instead
- Usehandler_data
---drivers/pinctrl/qcom/pinctrl-msm.c| 98 ++++++++++++++++++++++++++++++1 file changed, 98 insertions(+)drivers/pinctrl/qcom/pinctrl-msm.c +41
-0@@ -687,11 +687,15 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)const struct msm_pingroup *g;unsigned long flags;u32 val; +struct irq_data *pdc_irqd =irq_get_handler_data (d->irq); g = &pctrl->soc->groups[d->hwirq];raw_spin_lock_irqsave (&pctrl->lock, flags); +if (pdc_irqd) +irq_set_irq_type (pdc_irqd->irq, type); +/* * For hw without possibility of detecting both edges */ @@ -779,9 +783,13 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)struct gpio_chip *gc =irq_data_get_irq_chip_data (d);struct msm_pinctrl *pctrl =gpiochip_get_data (gc);unsigned long flags; +struct irq_data *pdc_irqd =irq_get_handler_data (d->irq);raw_spin_lock_irqsave (&pctrl->lock, flags); +if (pdc_irqd) +irq_set_irq_wake (pdc_irqd->irq, on); +irq_set_irq_wake (pctrl->irq, on);raw_spin_unlock_irqrestore (&pctrl->lock, flags);@@ -863,6 +871,94 @@ static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl)return device_property_read_u16_array (pctrl->dev,"gpios" ,NULL ,0 ) >0 ; } +static irqreturn_t wake_irq_gpio_handler (int irq,void *data) +{ +struct irq_data *irqd = data; +struct gpio_chip *gc =irq_data_get_irq_chip_data (irqd); +struct msm_pinctrl *pctrl =gpiochip_get_data (gc); +const struct msm_pingroup *g; +unsigned long flags; +u32 val; + +if (!irqd_is_level_type (irqd)) { + g = &pctrl->soc->groups[irqd->hwirq]; +raw_spin_lock_irqsave (&pctrl->lock, flags); + val =BIT (g->intr_status_bit); +writel (val, pctrl->regs + g->intr_status_reg); +raw_spin_unlock_irqrestore (&pctrl->lock, flags); + } + +return IRQ_HANDLED ; +} + +static int msm_gpio_pdc_pin_request (struct irq_data *d) +{ +struct gpio_chip *gc =irq_data_get_irq_chip_data (d); +struct msm_pinctrl *pctrl =gpiochip_get_data (gc); +struct platform_device *pdev =to_platform_device (pctrl->dev); +const char *pin_name; +int irq; +int ret; + + pin_name =kasprintf (GFP_KERNEL ,"gpio%lu" , d->hwirq); +if (!pin_name) +return -ENOMEM ; +
drivers/pinctrl/qcom/pinctrl-msm.c static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl) · line 916
Quoted 10 lines
drivers/pinctrl/qcom/pinctrl-msm.c +10
-0+ irq =platform_get_irq_byname (pdev, pin_name); +if (irq <0 ) { +kfree (pin_name); +return 0 ; + } + + ret =request_irq (irq, wake_irq_gpio_handler,irqd_get_trigger_type (d), + pin_name, d); +if (ret) { +pr_warn ("GPIO-%lu could not be set up as wakeup" , d->hwirq);
Need to end with '\n'.
Quoted 61 lines
drivers/pinctrl/qcom/pinctrl-msm.c +47
-1+kfree (pin_name); +return ret; + } + +irq_set_handler_data (d->irq,irq_get_irq_data (irq)); +disable_irq (irq); + +return 0 ; +} + +static int msm_gpio_pdc_pin_release (struct irq_data *d) +{ +struct irq_data *pdc_irqd =irq_get_handler_data (d->irq); +const void *name; + +if (pdc_irqd) { +irq_set_handler_data (d->irq,NULL ); + name =free_irq (pdc_irqd->irq, d); +kfree (name); + } + +return 0 ; +} + +static int msm_gpio_irq_reqres (struct irq_data *d) +{ +struct gpio_chip *gc =irq_data_get_irq_chip_data (d); + +if (gpiochip_lock_as_irq (gc,irqd_to_hwirq (d))) { +dev_err (gc->parent,"unable to lock HW IRQ %lu for IRQ\n" , +irqd_to_hwirq (d)); +return -EINVAL ; + } + +return msm_gpio_pdc_pin_request (d); +} + +static void msm_gpio_irq_relres (struct irq_data *d) +{ +struct gpio_chip *gc =irq_data_get_irq_chip_data (d); + +msm_gpio_pdc_pin_release (d); +gpiochip_unlock_as_irq (gc,irqd_to_hwirq (d)); +} +static int msm_gpio_init (struct msm_pinctrl *pctrl) {struct gpio_chip *chip;@@ -887,6 +983,8 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) pctrl->irq_chip.irq_ack = msm_gpio_irq_ack; 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; ret =gpiochip_add_data (&pctrl->chip, pctrl);if (ret) { --The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
Re: [PATCH v3 1/5] drivers: pinctrl: qcom: add wakeup capability to GPIO
In reply to Lina IyerHi Lina,
Quoted 73 lines · Lina Iyer
QCOM SoC's that have Power Domain Controller (PDC) chip in the always-on domain can wakeup the SoC, when interrupts and GPIOs are routed to its interrupt controller. Only select GPIOs that are deemed wakeup capable are routed to specific PDC pins. During low power state, the pinmux interrupt controller may be non-functional but the PDC would be. The PDC can detect the wakeup GPIO is triggered and bring the TLMM to an operational state.
Interrupts that are level triggered will be detected at the TLMM when the controller becomes operational. Edge interrupts however need to be replayed again.
Request the corresponding PDC IRQ, when the GPIO is requested as an IRQ, but keep it disabled. During suspend, we can enable the PDC IRQ instead of the GPIO IRQ, which may or not be detected.
Signed-off-by Lina Iyer <[email protected]>---
Changes in v3:
- freeaction->name
Changes in v2:
- RemoveIRQF_NO_SUSPENDandIRQF_ONE_SHOTfrom PDC IRQ
Changes in v1:
- Trigger GPIO in h/w from PDC IRQ handler
- Avoid big tables for GPIO-PDC map, pick from DT instead
- Usehandler_data--- drivers/pinctrl/qcom/pinctrl-msm.c | 98 ++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+)drivers/pinctrl/qcom/pinctrl-msm.c +12
-0@@ -687,11 +687,15 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)const struct msm_pingroup *g;unsigned long flags;u32 val; +struct irq_data *pdc_irqd =irq_get_handler_data (d->irq); g = &pctrl->soc->groups[d->hwirq];raw_spin_lock_irqsave (&pctrl->lock, flags); +if (pdc_irqd) +irq_set_irq_type (pdc_irqd->irq, type); +/* * For hw without possibility of detecting both edges */ @@ -779,9 +783,13 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)struct gpio_chip *gc =irq_data_get_irq_chip_data (d);struct msm_pinctrl *pctrl =gpiochip_get_data (gc);unsigned long flags; +struct irq_data *pdc_irqd =irq_get_handler_data (d->irq);raw_spin_lock_irqsave (&pctrl->lock, flags); +if (pdc_irqd) +irq_set_irq_wake (pdc_irqd->irq, on); +irq_set_irq_wake (pctrl->irq, on);raw_spin_unlock_irqrestore (&pctrl->lock, flags);@@ -863,6 +871,94 @@ static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl)return device_property_read_u16_array (pctrl->dev,"gpios" ,NULL ,0 ) >0 ; } +static irqreturn_t wake_irq_gpio_handler (int irq,void *data) +{ +struct irq_data *irqd = data; +struct gpio_chip *gc =irq_data_get_irq_chip_data (irqd);
drivers/pinctrl/qcom/pinctrl-msm.c static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl) · line 887
Quoted 10 lines
drivers/pinctrl/qcom/pinctrl-msm.c +10
-0+struct msm_pinctrl *pctrl =gpiochip_get_data (gc); +const struct msm_pingroup *g; +unsigned long flags; +u32 val; + +if (!irqd_is_level_type (irqd)) { + g = &pctrl->soc->groups[irqd->hwirq]; +raw_spin_lock_irqsave (&pctrl->lock, flags); + val =BIT (g->intr_status_bit); +writel (val, pctrl->regs + g->intr_status_reg);
write_relaxed, please.
drivers/pinctrl/qcom/pinctrl-msm.c static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl) · line 889
Quoted 2 lines
drivers/pinctrl/qcom/pinctrl-msm.c +2
-0+raw_spin_unlock_irqrestore (&pctrl->lock, flags); + }
Overall, this requires some form of documentation (I'll have forgotten about the whole thing quickly enough).
Quoted 17 lines
drivers/pinctrl/qcom/pinctrl-msm.c +17
-0+ +return IRQ_HANDLED ; +} + +static int msm_gpio_pdc_pin_request (struct irq_data *d) +{ +struct gpio_chip *gc =irq_data_get_irq_chip_data (d); +struct msm_pinctrl *pctrl =gpiochip_get_data (gc); +struct platform_device *pdev =to_platform_device (pctrl->dev); +const char *pin_name; +int irq; +int ret; + + pin_name =kasprintf (GFP_KERNEL ,"gpio%lu" , d->hwirq); +if (!pin_name) +return -ENOMEM ; +
drivers/pinctrl/qcom/pinctrl-msm.c static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl) · line 916
Quoted 10 lines
drivers/pinctrl/qcom/pinctrl-msm.c +10
-0+ irq =platform_get_irq_byname (pdev, pin_name); +if (irq <0 ) { +kfree (pin_name); +return 0 ; + } + + ret =request_irq (irq, wake_irq_gpio_handler,irqd_get_trigger_type (d), + pin_name, d); +if (ret) { +pr_warn ("GPIO-%lu could not be set up as wakeup" , d->hwirq);
This message doesn't correspond to what you're doing here.
drivers/pinctrl/qcom/pinctrl-msm.c static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl) · line 922
Quoted 6 lines
drivers/pinctrl/qcom/pinctrl-msm.c +6
-0+kfree (pin_name); +return ret; + } + +irq_set_handler_data (d->irq,irq_get_irq_data (irq)); +disable_irq (irq);
Who enables this interrupt?
There is a gap between request_irq and disable_irq, where you can take the interrupt, and not having set the handler data. Horrible things will happen in this situation.
A slightly better way of doing that would be:
// Prevent the interrupt from being enabled on request irq_set_status_flags(d->irq, IRQ_NOAUTOEN); ret = request_irq(...); irq_set_handler(...);
and let the enable_irq() do its thing when it happens (where?).
Quoted 55 lines
drivers/pinctrl/qcom/pinctrl-msm.c +41
-0+ +return 0 ; +} + +static int msm_gpio_pdc_pin_release (struct irq_data *d) +{ +struct irq_data *pdc_irqd =irq_get_handler_data (d->irq); +const void *name; + +if (pdc_irqd) { +irq_set_handler_data (d->irq,NULL ); + name =free_irq (pdc_irqd->irq, d); +kfree (name); + } + +return 0 ; +} + +static int msm_gpio_irq_reqres (struct irq_data *d) +{ +struct gpio_chip *gc =irq_data_get_irq_chip_data (d); + +if (gpiochip_lock_as_irq (gc,irqd_to_hwirq (d))) { +dev_err (gc->parent,"unable to lock HW IRQ %lu for IRQ\n" , +irqd_to_hwirq (d)); +return -EINVAL ; + } + +return msm_gpio_pdc_pin_request (d); +} + +static void msm_gpio_irq_relres (struct irq_data *d) +{ +struct gpio_chip *gc =irq_data_get_irq_chip_data (d); + +msm_gpio_pdc_pin_release (d); +gpiochip_unlock_as_irq (gc,irqd_to_hwirq (d)); +} +static int msm_gpio_init (struct msm_pinctrl *pctrl) {struct gpio_chip *chip;@@ -887,6 +983,8 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) pctrl->irq_chip.irq_ack = msm_gpio_irq_ack; 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; ret =gpiochip_add_data (&pctrl->chip, pctrl);if (ret) {Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
Thanks,
M.
Signature · 1 line
Jazz is not dead, it just smell funny.
Re: [PATCH v3 1/5] drivers: pinctrl: qcom: add wakeup capability to GPIO
Quoted 4 lines · Marc Zyngier
Hi Lina,
On Tue, 04 Sep 2018 22:18:06 +0100,
Lina Iyer <[email protected]> wrote:
[...]
Quoted 17 lines
Quoted 4 lines
drivers/pinctrl/qcom/pinctrl-msm.c +4
-0+static irqreturn_t wake_irq_gpio_handler (int irq,void *data) +{ +struct irq_data *irqd = data; +struct gpio_chip *gc =irq_data_get_irq_chip_data (irqd);drivers/pinctrl/qcom/pinctrl-msm.c static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl) · line 887
Quoted 10 lines
drivers/pinctrl/qcom/pinctrl-msm.c +10
-0+struct msm_pinctrl *pctrl =gpiochip_get_data (gc); +const struct msm_pingroup *g; +unsigned long flags; +u32 val; + +if (!irqd_is_level_type (irqd)) { + g = &pctrl->soc->groups[irqd->hwirq]; +raw_spin_lock_irqsave (&pctrl->lock, flags); + val =BIT (g->intr_status_bit); +writel (val, pctrl->regs + g->intr_status_reg);
write_relaxed, please.
Quoted 6 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ raw_spin_unlock_irqrestore(&pctrl->lock, flags); + }Overall, this requires some form of documentation (I'll have forgotten about the whole thing quickly enough).
Sure, I will address them both.
Quoted 21 lines
Quoted 21 lines
drivers/pinctrl/qcom/pinctrl-msm.c +21
-0+ +return IRQ_HANDLED ; +} + +static int msm_gpio_pdc_pin_request (struct irq_data *d) +{ +struct gpio_chip *gc =irq_data_get_irq_chip_data (d); +struct msm_pinctrl *pctrl =gpiochip_get_data (gc); +struct platform_device *pdev =to_platform_device (pctrl->dev); +const char *pin_name; +int irq; +int ret; + + pin_name =kasprintf (GFP_KERNEL ,"gpio%lu" , d->hwirq); +if (!pin_name) +return -ENOMEM ; + + irq =platform_get_irq_byname (pdev, pin_name); +if (irq <0 ) { +kfree (pin_name); +return 0 ;
Quoted 9 lines
drivers/pinctrl/qcom/pinctrl-msm.c static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl) · line 916
Quoted 6 lines
drivers/pinctrl/qcom/pinctrl-msm.c +6
-0+ } + + ret =request_irq (irq, wake_irq_gpio_handler,irqd_get_trigger_type (d), + pin_name, d); +if (ret) { +pr_warn ("GPIO-%lu could not be set up as wakeup" , d->hwirq);This message doesn't correspond to what you're doing here.
Well, I thought the message is most relevant because, we will not be able to wake up from this GPIO IRQ. But, I will change it.
Quoted 9 lines
drivers/pinctrl/qcom/pinctrl-msm.c static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl) · line 922
Quoted 6 lines
drivers/pinctrl/qcom/pinctrl-msm.c +6
-0+kfree (pin_name); +return ret; + } + +irq_set_handler_data (d->irq,irq_get_irq_data (irq)); +disable_irq (irq);Who enables this interrupt?
Suspend/resume code does the swap of enable/disable of PDC IRQ vs GPIO IRQ in patch #4.
Quoted 4 lines
There is a gap between
request_irqanddisable_irq, where you can take the interrupt, and not having set the handler data. Horrible things will happen in this situation.
Quoted 9 lines
A slightly better way of doing that would be:
// Prevent the interrupt from being enabled on request irq_set_status_flags(d->irq, IRQ_NOAUTOEN); ret = request_irq(...); irq_set_handler(...);and let the
enable_irq()do its thing when it happens (where?).
Oh. This is better. Will amend.
Thanks for the review.
-- Lina
Quoted 62 lines
Quoted 52 lines
drivers/pinctrl/qcom/pinctrl-msm.c +41
-1+ +return 0 ; +} + +static int msm_gpio_pdc_pin_release (struct irq_data *d) +{ +struct irq_data *pdc_irqd =irq_get_handler_data (d->irq); +const void *name; + +if (pdc_irqd) { +irq_set_handler_data (d->irq,NULL ); + name =free_irq (pdc_irqd->irq, d); +kfree (name); + } + +return 0 ; +} + +static int msm_gpio_irq_reqres (struct irq_data *d) +{ +struct gpio_chip *gc =irq_data_get_irq_chip_data (d); + +if (gpiochip_lock_as_irq (gc,irqd_to_hwirq (d))) { +dev_err (gc->parent,"unable to lock HW IRQ %lu for IRQ\n" , +irqd_to_hwirq (d)); +return -EINVAL ; + } + +return msm_gpio_pdc_pin_request (d); +} + +static void msm_gpio_irq_relres (struct irq_data *d) +{ +struct gpio_chip *gc =irq_data_get_irq_chip_data (d); + +msm_gpio_pdc_pin_release (d); +gpiochip_unlock_as_irq (gc,irqd_to_hwirq (d)); +} +static int msm_gpio_init (struct msm_pinctrl *pctrl) {struct gpio_chip *chip;@@ -887,6 +983,8 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) pctrl->irq_chip.irq_ack = msm_gpio_irq_ack; 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; ret =gpiochip_add_data (&pctrl->chip, pctrl);if (ret) { --Quoted 3 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
Thanks,
M.--
Jazz is not dead, it just smell funny.
Re: [PATCH v3 1/5] drivers: pinctrl: qcom: add wakeup capability to GPIO
In reply to Lina IyerMarc,
I am exploring an option where we don't do this enable/disable every suspend/resume and in that process, I was able to just use the PDC interrupt instead of the TLMM for triggering the GPIO. The PDC interrupt (which takes over for the GPIO) has an handler like this -
Quoted 37 lines · Lina Iyer
QCOM SoC's that have Power Domain Controller (PDC) chip in the always-on domain can wakeup the SoC, when interrupts and GPIOs are routed to its interrupt controller. Only select GPIOs that are deemed wakeup capable are routed to specific PDC pins. During low power state, the pinmux interrupt controller may be non-functional but the PDC would be. The PDC can detect the wakeup GPIO is triggered and bring the TLMM to an operational state.
Interrupts that are level triggered will be detected at the TLMM when the controller becomes operational. Edge interrupts however need to be replayed again.
Request the corresponding PDC IRQ, when the GPIO is requested as an IRQ, but keep it disabled. During suspend, we can enable the PDC IRQ instead of the GPIO IRQ, which may or not be detected.
Signed-off-by Lina Iyer <[email protected]>---
Changes in v3:
- freeaction->name
Changes in v2:
- RemoveIRQF_NO_SUSPENDandIRQF_ONE_SHOTfrom PDC IRQ
Changes in v1:
- Trigger GPIO in h/w from PDC IRQ handler
- Avoid big tables for GPIO-PDC map, pick from DT instead
- Usehandler_data
---drivers/pinctrl/qcom/pinctrl-msm.c| 98 ++++++++++++++++++++++++++++++1 file changed, 98 insertions(+)drivers/pinctrl/qcom/pinctrl-msm.c +0
-0@@ -687,11 +687,15 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)const struct msm_pingroup *g;unsigned long flags;
drivers/pinctrl/qcom/pinctrl-msm.c static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) · line 698
Quoted 10 lines
drivers/pinctrl/qcom/pinctrl-msm.c +4
-0u32 val; +struct irq_data *pdc_irqd =irq_get_handler_data (d->irq); g = &pctrl->soc->groups[d->hwirq];raw_spin_lock_irqsave (&pctrl->lock, flags); +if (pdc_irqd) +irq_set_irq_type (pdc_irqd->irq, type); +
I skip over the TLMM configuration for the GPIO interrupt and just set the IRQ handler for the GPIO interrupt here..
Quoted 31 lines
drivers/pinctrl/qcom/pinctrl-msm.c +14
-0/* * For hw without possibility of detecting both edges */ @@ -779,9 +783,13 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)struct gpio_chip *gc =irq_data_get_irq_chip_data (d);struct msm_pinctrl *pctrl =gpiochip_get_data (gc);unsigned long flags; +struct irq_data *pdc_irqd =irq_get_handler_data (d->irq);raw_spin_lock_irqsave (&pctrl->lock, flags); +if (pdc_irqd) +irq_set_irq_wake (pdc_irqd->irq, on); +irq_set_irq_wake (pctrl->irq, on);raw_spin_unlock_irqrestore (&pctrl->lock, flags);@@ -863,6 +871,94 @@ static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl)return device_property_read_u16_array (pctrl->dev,"gpios" ,NULL ,0 ) >0 ; } +static irqreturn_t wake_irq_gpio_handler (int irq,void *data) +{ +struct irq_data *irqd = data; +struct gpio_chip *gc =irq_data_get_irq_chip_data (irqd); +struct msm_pinctrl *pctrl =gpiochip_get_data (gc); +const struct msm_pingroup *g; +unsigned long flags; +u32 val; + +if (!irqd_is_level_type (irqd)) {
drivers/pinctrl/qcom/pinctrl-msm.c static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl) · line 893
Quoted 10 lines
drivers/pinctrl/qcom/pinctrl-msm.c +10
-0+ g = &pctrl->soc->groups[irqd->hwirq]; +raw_spin_lock_irqsave (&pctrl->lock, flags); + val =BIT (g->intr_status_bit); +writel (val, pctrl->regs + g->intr_status_reg); +raw_spin_unlock_irqrestore (&pctrl->lock, flags); + } + +return IRQ_HANDLED ; +} +
Then ...
static irqreturn_t wake_irq_gpio_handler(int irq, void *data)
{
struct irq_data *irqd = data;
struct irq_desc *desc = irq_to_desc(irqd->irq);
desc->handle_irq(desc);
return IRQ_HANDLED;
}I am following check_irq_resend() but I need to call the handler for both level and edge interrupts. Firstly, is it okay to call the handler_irq() directly?
My other question is check_irq_resend() indicates that it should be called with desc->lock held. Since we are invoking the handler directly and not modifying any core state of the irq_desc, is it safe here? (Also the locking API are not exposed, I am sure there must be a reason for it).
Thoughts?
Thanks,
Lina
Quoted 84 lines
drivers/pinctrl/qcom/pinctrl-msm.c +70
-1+static int msm_gpio_pdc_pin_request (struct irq_data *d) +{ +struct gpio_chip *gc =irq_data_get_irq_chip_data (d); +struct msm_pinctrl *pctrl =gpiochip_get_data (gc); +struct platform_device *pdev =to_platform_device (pctrl->dev); +const char *pin_name; +int irq; +int ret; + + pin_name =kasprintf (GFP_KERNEL ,"gpio%lu" , d->hwirq); +if (!pin_name) +return -ENOMEM ; + + irq =platform_get_irq_byname (pdev, pin_name); +if (irq <0 ) { +kfree (pin_name); +return 0 ; + } + + ret =request_irq (irq, wake_irq_gpio_handler,irqd_get_trigger_type (d), + pin_name, d); +if (ret) { +pr_warn ("GPIO-%lu could not be set up as wakeup" , d->hwirq); +kfree (pin_name); +return ret; + } + +irq_set_handler_data (d->irq,irq_get_irq_data (irq)); +disable_irq (irq); + +return 0 ; +} + +static int msm_gpio_pdc_pin_release (struct irq_data *d) +{ +struct irq_data *pdc_irqd =irq_get_handler_data (d->irq); +const void *name; + +if (pdc_irqd) { +irq_set_handler_data (d->irq,NULL ); + name =free_irq (pdc_irqd->irq, d); +kfree (name); + } + +return 0 ; +} + +static int msm_gpio_irq_reqres (struct irq_data *d) +{ +struct gpio_chip *gc =irq_data_get_irq_chip_data (d); + +if (gpiochip_lock_as_irq (gc,irqd_to_hwirq (d))) { +dev_err (gc->parent,"unable to lock HW IRQ %lu for IRQ\n" , +irqd_to_hwirq (d)); +return -EINVAL ; + } + +return msm_gpio_pdc_pin_request (d); +} + +static void msm_gpio_irq_relres (struct irq_data *d) +{ +struct gpio_chip *gc =irq_data_get_irq_chip_data (d); + +msm_gpio_pdc_pin_release (d); +gpiochip_unlock_as_irq (gc,irqd_to_hwirq (d)); +} +static int msm_gpio_init (struct msm_pinctrl *pctrl) {struct gpio_chip *chip;@@ -887,6 +983,8 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) pctrl->irq_chip.irq_ack = msm_gpio_irq_ack; 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; ret =gpiochip_add_data (&pctrl->chip, pctrl);if (ret) { --The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
Re: [PATCH v3 1/5] drivers: pinctrl: qcom: add wakeup capability to GPIO
Quoted 116 lines · Lina Iyer
Marc,
I am exploring an option where we don't do this enable/disable every suspend/resume and in that process, I was able to just use the PDC interrupt instead of the TLMM for triggering the GPIO. The PDC interrupt (which takes over for the GPIO) has an handler like this -
Quoted 37 lines · Lina Iyer
QCOM SoC's that have Power Domain Controller (PDC) chip in the always-on domain can wakeup the SoC, when interrupts and GPIOs are routed to its interrupt controller. Only select GPIOs that are deemed wakeup capable are routed to specific PDC pins. During low power state, the pinmux interrupt controller may be non-functional but the PDC would be. The PDC can detect the wakeup GPIO is triggered and bring the TLMM to an operational state.
Interrupts that are level triggered will be detected at the TLMM when the controller becomes operational. Edge interrupts however need to be replayed again.
Request the corresponding PDC IRQ, when the GPIO is requested as an IRQ, but keep it disabled. During suspend, we can enable the PDC IRQ instead of the GPIO IRQ, which may or not be detected.
Signed-off-by Lina Iyer <[email protected]>---
Changes in v3:
- freeaction->name
Changes in v2:
- RemoveIRQF_NO_SUSPENDandIRQF_ONE_SHOTfrom PDC IRQ
Changes in v1:
- Trigger GPIO in h/w from PDC IRQ handler
- Avoid big tables for GPIO-PDC map, pick from DT instead
- Usehandler_data
---drivers/pinctrl/qcom/pinctrl-msm.c| 98 ++++++++++++++++++++++++++++++1 file changed, 98 insertions(+)drivers/pinctrl/qcom/pinctrl-msm.c +0
-0@@ -687,11 +687,15 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)const struct msm_pingroup *g;unsigned long flags;drivers/pinctrl/qcom/pinctrl-msm.c static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) · line 698
Quoted 10 lines
drivers/pinctrl/qcom/pinctrl-msm.c +4
-0u32 val; +struct irq_data *pdc_irqd =irq_get_handler_data (d->irq); g = &pctrl->soc->groups[d->hwirq];raw_spin_lock_irqsave (&pctrl->lock, flags); +if (pdc_irqd) +irq_set_irq_type (pdc_irqd->irq, type); +I skip over the TLMM configuration for the GPIO interrupt and just set the IRQ handler for the GPIO interrupt here..
Quoted 31 lines
drivers/pinctrl/qcom/pinctrl-msm.c +14
-0/* * For hw without possibility of detecting both edges */ @@ -779,9 +783,13 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)struct gpio_chip *gc =irq_data_get_irq_chip_data (d);struct msm_pinctrl *pctrl =gpiochip_get_data (gc);unsigned long flags; +struct irq_data *pdc_irqd =irq_get_handler_data (d->irq);raw_spin_lock_irqsave (&pctrl->lock, flags); +if (pdc_irqd) +irq_set_irq_wake (pdc_irqd->irq, on); +irq_set_irq_wake (pctrl->irq, on);raw_spin_unlock_irqrestore (&pctrl->lock, flags);@@ -863,6 +871,94 @@ static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl)return device_property_read_u16_array (pctrl->dev,"gpios" ,NULL ,0 ) >0 ; } +static irqreturn_t wake_irq_gpio_handler (int irq,void *data) +{ +struct irq_data *irqd = data; +struct gpio_chip *gc =irq_data_get_irq_chip_data (irqd); +struct msm_pinctrl *pctrl =gpiochip_get_data (gc); +const struct msm_pingroup *g; +unsigned long flags; +u32 val; + +if (!irqd_is_level_type (irqd)) {drivers/pinctrl/qcom/pinctrl-msm.c static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl) · line 893
Quoted 10 lines
drivers/pinctrl/qcom/pinctrl-msm.c +10
-0+ g = &pctrl->soc->groups[irqd->hwirq]; +raw_spin_lock_irqsave (&pctrl->lock, flags); + val =BIT (g->intr_status_bit); +writel (val, pctrl->regs + g->intr_status_reg); +raw_spin_unlock_irqrestore (&pctrl->lock, flags); + } + +return IRQ_HANDLED ; +} +Then ...
static
irqreturn_twake_irq_gpio_handler(int irq, void *data){ struct irq_data *irqd = data; struct irq_desc *desc = irq_to_desc(irqd->irq); desc->handle_irq(desc); return IRQ_HANDLED; }I am following
check_irq_resend()but I need to call the handler for both level and edge interrupts. Firstly, is it okay to call thehandler_irq()directly?
Quoted 7 lines
My other question is
check_irq_resend()indicates that it should be called withdesc->lockheld. Since we are invoking the handler directly and not modifying any core state of theirq_desc, is it safe here? (Also the locking API are not exposed, I am sure there must be a reason for it).Thoughts?
Would it help if I submit a RFC patch based on this idea?
Quoted 87 lines
Thanks,
LinaQuoted 84 lines
drivers/pinctrl/qcom/pinctrl-msm.c +70
-1+static int msm_gpio_pdc_pin_request (struct irq_data *d) +{ +struct gpio_chip *gc =irq_data_get_irq_chip_data (d); +struct msm_pinctrl *pctrl =gpiochip_get_data (gc); +struct platform_device *pdev =to_platform_device (pctrl->dev); +const char *pin_name; +int irq; +int ret; + + pin_name =kasprintf (GFP_KERNEL ,"gpio%lu" , d->hwirq); +if (!pin_name) +return -ENOMEM ; + + irq =platform_get_irq_byname (pdev, pin_name); +if (irq <0 ) { +kfree (pin_name); +return 0 ; + } + + ret =request_irq (irq, wake_irq_gpio_handler,irqd_get_trigger_type (d), + pin_name, d); +if (ret) { +pr_warn ("GPIO-%lu could not be set up as wakeup" , d->hwirq); +kfree (pin_name); +return ret; + } + +irq_set_handler_data (d->irq,irq_get_irq_data (irq)); +disable_irq (irq); + +return 0 ; +} + +static int msm_gpio_pdc_pin_release (struct irq_data *d) +{ +struct irq_data *pdc_irqd =irq_get_handler_data (d->irq); +const void *name; + +if (pdc_irqd) { +irq_set_handler_data (d->irq,NULL ); + name =free_irq (pdc_irqd->irq, d); +kfree (name); + } + +return 0 ; +} + +static int msm_gpio_irq_reqres (struct irq_data *d) +{ +struct gpio_chip *gc =irq_data_get_irq_chip_data (d); + +if (gpiochip_lock_as_irq (gc,irqd_to_hwirq (d))) { +dev_err (gc->parent,"unable to lock HW IRQ %lu for IRQ\n" , +irqd_to_hwirq (d)); +return -EINVAL ; + } + +return msm_gpio_pdc_pin_request (d); +} + +static void msm_gpio_irq_relres (struct irq_data *d) +{ +struct gpio_chip *gc =irq_data_get_irq_chip_data (d); + +msm_gpio_pdc_pin_release (d); +gpiochip_unlock_as_irq (gc,irqd_to_hwirq (d)); +} +static int msm_gpio_init (struct msm_pinctrl *pctrl) {struct gpio_chip *chip;@@ -887,6 +983,8 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) pctrl->irq_chip.irq_ack = msm_gpio_irq_ack; 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; ret =gpiochip_add_data (&pctrl->chip, pctrl);if (ret) { --The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
Re: [PATCH v3 1/5] drivers: pinctrl: qcom: add wakeup capability to GPIO
Quoted 117 lines · Lina Iyer
Quoted 116 lines · Lina Iyer
Marc,
I am exploring an option where we don't do this enable/disable every suspend/resume and in that process, I was able to just use the PDC interrupt instead of the TLMM for triggering the GPIO. The PDC interrupt (which takes over for the GPIO) has an handler like this -
Quoted 37 lines · Lina Iyer
QCOM SoC's that have Power Domain Controller (PDC) chip in the always-on domain can wakeup the SoC, when interrupts and GPIOs are routed to its interrupt controller. Only select GPIOs that are deemed wakeup capable are routed to specific PDC pins. During low power state, the pinmux interrupt controller may be non-functional but the PDC would be. The PDC can detect the wakeup GPIO is triggered and bring the TLMM to an operational state.
Interrupts that are level triggered will be detected at the TLMM when the controller becomes operational. Edge interrupts however need to be replayed again.
Request the corresponding PDC IRQ, when the GPIO is requested as an IRQ, but keep it disabled. During suspend, we can enable the PDC IRQ instead of the GPIO IRQ, which may or not be detected.
Signed-off-by Lina Iyer <[email protected]>---
Changes in v3:
- freeaction->name
Changes in v2:
- RemoveIRQF_NO_SUSPENDandIRQF_ONE_SHOTfrom PDC IRQ
Changes in v1:
- Trigger GPIO in h/w from PDC IRQ handler
- Avoid big tables for GPIO-PDC map, pick from DT instead
- Usehandler_data
---drivers/pinctrl/qcom/pinctrl-msm.c| 98 ++++++++++++++++++++++++++++++1 file changed, 98 insertions(+)drivers/pinctrl/qcom/pinctrl-msm.c +0
-0@@ -687,11 +687,15 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)const struct msm_pingroup *g;unsigned long flags;drivers/pinctrl/qcom/pinctrl-msm.c static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) · line 698
Quoted 10 lines
drivers/pinctrl/qcom/pinctrl-msm.c +4
-0u32 val; +struct irq_data *pdc_irqd =irq_get_handler_data (d->irq); g = &pctrl->soc->groups[d->hwirq];raw_spin_lock_irqsave (&pctrl->lock, flags); +if (pdc_irqd) +irq_set_irq_type (pdc_irqd->irq, type); +I skip over the TLMM configuration for the GPIO interrupt and just set the IRQ handler for the GPIO interrupt here..
Quoted 31 lines
drivers/pinctrl/qcom/pinctrl-msm.c +14
-0/* * For hw without possibility of detecting both edges */ @@ -779,9 +783,13 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)struct gpio_chip *gc =irq_data_get_irq_chip_data (d);struct msm_pinctrl *pctrl =gpiochip_get_data (gc);unsigned long flags; +struct irq_data *pdc_irqd =irq_get_handler_data (d->irq);raw_spin_lock_irqsave (&pctrl->lock, flags); +if (pdc_irqd) +irq_set_irq_wake (pdc_irqd->irq, on); +irq_set_irq_wake (pctrl->irq, on);raw_spin_unlock_irqrestore (&pctrl->lock, flags);@@ -863,6 +871,94 @@ static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl)return device_property_read_u16_array (pctrl->dev,"gpios" ,NULL ,0 ) >0 ; } +static irqreturn_t wake_irq_gpio_handler (int irq,void *data) +{ +struct irq_data *irqd = data; +struct gpio_chip *gc =irq_data_get_irq_chip_data (irqd); +struct msm_pinctrl *pctrl =gpiochip_get_data (gc); +const struct msm_pingroup *g; +unsigned long flags; +u32 val; + +if (!irqd_is_level_type (irqd)) {drivers/pinctrl/qcom/pinctrl-msm.c static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl) · line 893
Quoted 10 lines
drivers/pinctrl/qcom/pinctrl-msm.c +10
-0+ g = &pctrl->soc->groups[irqd->hwirq]; +raw_spin_lock_irqsave (&pctrl->lock, flags); + val =BIT (g->intr_status_bit); +writel (val, pctrl->regs + g->intr_status_reg); +raw_spin_unlock_irqrestore (&pctrl->lock, flags); + } + +return IRQ_HANDLED ; +} +Then ...
static
irqreturn_twake_irq_gpio_handler(int irq, void *data){ struct irq_data *irqd = data; struct irq_desc *desc = irq_to_desc(irqd->irq); desc->handle_irq(desc); return IRQ_HANDLED; }I am following
check_irq_resend()but I need to call the handler for both level and edge interrupts. Firstly, is it okay to call thehandler_irq()directly?
Quoted 8 lines
Quoted 7 lines
My other question is
check_irq_resend()indicates that it should be called withdesc->lockheld. Since we are invoking the handler directly and not modifying any core state of theirq_desc, is it safe here? (Also the locking API are not exposed, I am sure there must be a reason for it).Thoughts?
Would it help if I submit a RFC patch based on this idea?
Yes please. At this stage, I've completely lost track of the various ideas, and I'd like to restart with a clean slate.
Thanks,
M.
Signature · 1 line
Jazz is not dead. It just smells funny...
PATCH v3 2/5 dt-bindings: pinctrl: add wakeup capable GPIOs for SDM845
In reply to Lina IyerUpdate the documentation to use interrupts-extended format for specifying the TLMM summary IRQ line that is requested from GIC and the PDC interrupts corresponding to the wakeup capable GPIOs.
Update the example to show PDC interrupts for the wakeup capable GPIOs for SDM845.
---
Changes in v2:
- Fix PDC IRQ number in example
- Describe IRQ trigger type in example
--- .../bindings/pinctrl/qcom,sdm845-pinctrl.txt | 104 +++++++++++++++++- 1 file changed, 101 insertions(+), 3 deletions(-)
Documentation/devicetree/bindings/pinctrl/qcom,sdm845-pinctrl.txt +101 -3
@@ -13,10 +13,21 @@ SDM845 platform. Value type: <prop-encoded-array> Definition: the base address and size of the TLMM register space. -- interrupts: +- interrupts-extended: Usage: required Value type: <prop-encoded-array> - Definition: should specify the TLMM summary IRQ. + Definition: should specify the TLMM summary IRQ as the first + interrupt. Optionally, wake up capable GPIOs may list + their corresponding PDC interrupts here. + +- interrupt-names: + Usage: required + Value type: <string> + Definition: the names matching the interrupt definition in the + interrupts-extended property. The first interrupt name + must be "summary-irq" for the TLMM summary IRQ. PDC + interrupts must be described by "gpioN", where N is the + GPIO line corresponding to the PDC IRQ. - interrupt-controller: Usage: required
@@ -155,11 +166,98 @@ Example: tlmm: pinctrl@3400000 { compatible = "qcom,sdm845-pinctrl"; reg = <0x03400000 0xc00000>; - interrupts = <GIC_SPI 208 0>; gpio-controller; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; + interrupts-extended = + <&intc GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 30 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 31 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 32 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 33 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 34 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 35 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 36 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 37 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 38 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 39 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 41 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 42 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 43 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 44 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 45 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 46 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 47 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 49 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 50 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 51 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 52 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 54 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 55 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 56 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 57 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 58 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 59 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 60 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 61 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 62 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 63 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 64 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 65 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 66 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 67 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 68 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 69 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 70 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 71 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 72 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 73 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 74 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 75 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 76 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 77 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 79 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 80 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 81 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 82 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 83 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 84 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 85 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 86 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 90 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 91 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 92 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 95 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 96 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 97 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 98 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 99 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 100 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 102 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 103 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 104 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 105 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 106 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 107 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 108 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "summary-irq", + "gpio1", "gpio3", "gpio5", "gpio10", "gpio11", + "gpio20", "gpio22", "gpio24", "gpio26", "gpio30", + "gpio32", "gpio34", "gpio36", "gpio37", "gpio38", + "gpio39", "gpio40", "gpio43", "gpio44", "gpio46", + "gpio48", "gpio52", "gpio53", "gpio54", "gpio56", + "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", + "gpio62", "gpio63", "gpio64", "gpio66", "gpio68", + "gpio71", "gpio73", "gpio77", "gpio78", "gpio79", + "gpio80", "gpio84", "gpio85", "gpio86", "gpio88", + "gpio91", "gpio92", "gpio95", "gpio96", "gpio97", + "gpio101", "gpio103", "gpio104", "gpio115", "gpio116", + "gpio117", "gpio118", "gpio119", "gpio120", "gpio121", + "gpio122", "gpio123", "gpio124", "gpio125", "gpio127", + "gpio128", "gpio129", "gpio130", "gpio132", "gpio133", + "gpio145", "gpio41", "gpio89", "gpio31", "gpio49", + "gpio41", "gpio89", "gpio31", "gpio49"; qup9_active: qup9-active { mux {
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
Rob Herring
maintainerRe: [PATCH v3 2/5] dt-bindings: pinctrl: add wakeup capable GPIOs for SDM845
Quoted 9 lines · Lina Iyer
Update the documentation to use interrupts-extended format for specifying the TLMM summary IRQ line that is requested from GIC and the PDC interrupts corresponding to the wakeup capable GPIOs.
Update the example to show PDC interrupts for the wakeup capable GPIOs for SDM845.
Signed-off-by Lina Iyer <[email protected]>
Quoted 7 lines
---
Changes in v2:
- Fix PDC IRQ number in example
- Describe IRQ trigger type in example--- .../bindings/pinctrl/qcom,sdm845-pinctrl.txt | 104 +++++++++++++++++- 1 file changed, 101 insertions(+), 3 deletions(-)
As I also mentioned in v2. Please add acks/reviewed-bys when posting new versions.
Rob
Re: [PATCH v3 2/5] dt-bindings: pinctrl: add wakeup capable GPIOs for SDM845
Quoted 18 lines · Rob Herring
Quoted 9 lines · Lina Iyer
Update the documentation to use interrupts-extended format for specifying the TLMM summary IRQ line that is requested from GIC and the PDC interrupts corresponding to the wakeup capable GPIOs.
Update the example to show PDC interrupts for the wakeup capable GPIOs for SDM845.
Signed-off-by Lina Iyer <[email protected]>Quoted 7 lines
---
Changes in v2:
- Fix PDC IRQ number in example
- Describe IRQ trigger type in example--- .../bindings/pinctrl/qcom,sdm845-pinctrl.txt | 104 +++++++++++++++++- 1 file changed, 101 insertions(+), 3 deletions(-)
Quoted 3 lines
As I also mentioned in v2. Please add acks/reviewed-bys when posting new versions.
Sorry Rob. I added to patch 5, but forgot this one. Thanks for pointing out. Will add it in the next spin. Sorry for wasting your time.
-- Lina
PATCH v3 3/5 drivers: pinctrl: msm: enable PDC interrupt only during suspend
In reply to Lina IyerDuring suspend the system may power down some of the system rails. As a result, the TLMM hw block may not be operational anymore and wakeup capable GPIOs will not be detected. The PDC however will be operational and the GPIOs that are routed to the PDC as IRQs can wake the system up.
To avoid being interrupted twice (for TLMM and once for PDC IRQ) when a GPIO trips, use TLMM for active and switch to PDC for suspend. When entering suspend, disable the TLMM wakeup interrupt and instead enable the PDC IRQ and revert upon resume.
---
Changes in v3:
- Enable PDC-IRQ swap only for edge interrupts
Changes in v2:
- Fix PDC IRQ max port, 126 is the max supported in h/w
- Use PDC hwirq in bitmap, linux numbers could be large
- Setup DISABLE_UNLAZY for both TLMM and PDC IRQs
--- drivers/pinctrl/qcom/pinctrl-msm.c | 73 +++++++++++++++++++++++++++++- drivers/pinctrl/qcom/pinctrl-msm.h | 3 ++ 2 files changed, 75 insertions(+), 1 deletion(-)
drivers/pinctrl/qcom/pinctrl-msm.c +72 -1
@@ -37,6 +37,7 @@#include "../pinctrl-utils.h" #define MAX_NR_GPIO 300 +#define MAX_PDC_HWIRQ 126#define PS_HOLD_OFFSET 0x820/**
@@ -51,6 +52,7 @@* @enabled_irqs: Bitmap of currently enabled irqs. * @dual_edge_irqs: Bitmap of irqs that need sw emulated dual edge * detection. +* @pdc_hwirqs: Bitmap of wakeup capable irqs. * @soc; Reference to soc_data of platform specific data. * @regs: Base address for the TLMM register map. */
@@ -68,11 +70,15 @@ struct msm_pinctrl {DECLARE_BITMAP (dual_edge_irqs,MAX_NR_GPIO );DECLARE_BITMAP (enabled_irqs,MAX_NR_GPIO ); +DECLARE_BITMAP (pdc_hwirqs,MAX_PDC_HWIRQ );const struct msm_pinctrl_soc_data *soc;void __iomem *regs; +struct irq_domain *pdc_irq_domain; }; +static bool in_suspend; +static int msm_get_groups_count (struct pinctrl_dev *pctldev) {struct msm_pinctrl *pctrl =pinctrl_dev_get_drvdata (pctldev);
@@ -787,8 +793,13 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)raw_spin_lock_irqsave (&pctrl->lock, flags); -if (pdc_irqd) +if (pdc_irqd && !in_suspend) {irq_set_irq_wake (pdc_irqd->irq, on); +if (on) +set_bit (pdc_irqd->hwirq, pctrl->pdc_hwirqs); +else +clear_bit (pdc_irqd->hwirq, pctrl->pdc_hwirqs); + }irq_set_irq_wake (pctrl->irq, on);
@@ -919,7 +930,12 @@ static int msm_gpio_pdc_pin_request(struct irq_data *d) }irq_set_handler_data (d->irq,irq_get_irq_data (irq)); +irq_set_handler_data (irq, d); +irq_set_status_flags (irq,IRQ_DISABLE_UNLAZY ); +irq_set_status_flags (d->irq,IRQ_DISABLE_UNLAZY );disable_irq (irq); +if (!pctrl->pdc_irq_domain) + pctrl->pdc_irq_domain =irq_get_irq_data (irq)->domain;return 0 ; }
@@ -1071,6 +1087,61 @@ static void msm_pinctrl_setup_pm_reset(struct msm_pinctrl *pctrl) } } +int __maybe_unused msm_pinctrl_suspend_late (struct device *dev) +{ +struct msm_pinctrl *pctrl =dev_get_drvdata (dev); +struct irq_data *irqd; +unsigned int irq; +int i; + + in_suspend = true; +for_each_set_bit (i, pctrl->pdc_hwirqs,MAX_PDC_HWIRQ ) { + irq =irq_find_mapping (pctrl->pdc_irq_domain, i); + irqd =irq_get_handler_data (irq); +/* +* We don't know if the TLMM will be functional +* or not, during the suspend. If its functional, +* we do not want duplicate interrupts from PDC. +* Hence disable the GPIO IRQ and enable PDC IRQ +* for edge interrupt only. +*/ +if (irqd_is_wakeup_set (irqd) && !irqd_is_level_type (irqd)) { +disable_irq_wake (irqd->irq); +disable_irq (irqd->irq); +enable_irq (irq); + } + } + +return 0 ; +} + +int __maybe_unused msm_pinctrl_resume_late (struct device *dev) +{ +struct msm_pinctrl *pctrl =dev_get_drvdata (dev); +struct irq_data *irqd, *pdc_irqd; +unsigned int irq; +int i; + +for_each_set_bit (i, pctrl->pdc_hwirqs,MAX_PDC_HWIRQ ) { + irq =irq_find_mapping (pctrl->pdc_irq_domain, i); + irqd =irq_get_handler_data (irq); + pdc_irqd =irq_get_irq_data (irq); +/* +* The TLMM will be operational now, so disable +* the PDC IRQ for edge interrupts only. +*/ +if (irqd_is_wakeup_set (pdc_irqd) && + !irqd_is_level_type (pdc_irqd)) { +disable_irq_nosync (irq); +enable_irq_wake (irqd->irq); +enable_irq (irqd->irq); + } + } + in_suspend = false; + +return 0 ; +} +int msm_pinctrl_probe (struct platform_device *pdev,const struct msm_pinctrl_soc_data *soc_data) {
drivers/pinctrl/qcom/pinctrl-msm.h +3 -0
@@ -123,4 +123,7 @@ int msm_pinctrl_probe(struct platform_device *pdev, const struct msm_pinctrl_soc_data *soc_data);int msm_pinctrl_remove (struct platform_device *pdev); +int msm_pinctrl_suspend_late (struct device *dev); +int msm_pinctrl_resume_late (struct device *dev); +#endif
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
Re: [PATCH v3 3/5] drivers: pinctrl: msm: enable PDC interrupt only during suspend
Hi Lina,
Quoted 102 lines · Lina Iyer
During suspend the system may power down some of the system rails. As a result, the TLMM hw block may not be operational anymore and wakeup capable GPIOs will not be detected. The PDC however will be operational and the GPIOs that are routed to the PDC as IRQs can wake the system up.
To avoid being interrupted twice (for TLMM and once for PDC IRQ) when a GPIO trips, use TLMM for active and switch to PDC for suspend. When entering suspend, disable the TLMM wakeup interrupt and instead enable the PDC IRQ and revert upon resume.
Signed-off-by Lina Iyer <[email protected]>---
Changes in v3:
- Enable PDC-IRQ swap only for edge interrupts
Changes in v2:
- Fix PDC IRQ max port, 126 is the max supported in h/w
- Use PDC hwirq in bitmap, linux numbers could be large
- SetupDISABLE_UNLAZYfor both TLMM and PDC IRQs--- drivers/pinctrl/qcom/pinctrl-msm.c | 73 +++++++++++++++++++++++++++++- drivers/pinctrl/qcom/pinctrl-msm.h | 3 ++ 2 files changed, 75 insertions(+), 1 deletion(-)drivers/pinctrl/qcom/pinctrl-msm.c +27
-1@@ -37,6 +37,7 @@#include "../pinctrl-utils.h" #define MAX_NR_GPIO 300 +#define MAX_PDC_HWIRQ 126#define PS_HOLD_OFFSET 0x820/** @@ -51,6 +52,7 @@* @enabled_irqs: Bitmap of currently enabled irqs. * @dual_edge_irqs: Bitmap of irqs that need sw emulated dual edge * detection. +* @pdc_hwirqs: Bitmap of wakeup capable irqs. * @soc; Reference to soc_data of platform specific data. * @regs: Base address for the TLMM register map. */ @@ -68,11 +70,15 @@ struct msm_pinctrl {DECLARE_BITMAP (dual_edge_irqs,MAX_NR_GPIO );DECLARE_BITMAP (enabled_irqs,MAX_NR_GPIO ); +DECLARE_BITMAP (pdc_hwirqs,MAX_PDC_HWIRQ );const struct msm_pinctrl_soc_data *soc;void __iomem *regs; +struct irq_domain *pdc_irq_domain; }; +static bool in_suspend; +static int msm_get_groups_count (struct pinctrl_dev *pctldev) {struct msm_pinctrl *pctrl =pinctrl_dev_get_drvdata (pctldev);@@ -787,8 +793,13 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)raw_spin_lock_irqsave (&pctrl->lock, flags); -if (pdc_irqd) +if (pdc_irqd && !in_suspend) {irq_set_irq_wake (pdc_irqd->irq, on); +if (on) +set_bit (pdc_irqd->hwirq, pctrl->pdc_hwirqs); +else +clear_bit (pdc_irqd->hwirq, pctrl->pdc_hwirqs); + }irq_set_irq_wake (pctrl->irq, on);@@ -919,7 +930,12 @@ static int msm_gpio_pdc_pin_request(struct irq_data *d) }irq_set_handler_data (d->irq,irq_get_irq_data (irq)); +irq_set_handler_data (irq, d); +irq_set_status_flags (irq,IRQ_DISABLE_UNLAZY ); +irq_set_status_flags (d->irq,IRQ_DISABLE_UNLAZY );disable_irq (irq); +if (!pctrl->pdc_irq_domain) + pctrl->pdc_irq_domain =irq_get_irq_data (irq)->domain;return 0 ; }@@ -1071,6 +1087,61 @@ static void msm_pinctrl_setup_pm_reset(struct msm_pinctrl *pctrl) } } +int __maybe_unused msm_pinctrl_suspend_late (struct device *dev) +{ +struct msm_pinctrl *pctrl =dev_get_drvdata (dev); +struct irq_data *irqd; +unsigned int irq; +int i; + + in_suspend = true; +for_each_set_bit (i, pctrl->pdc_hwirqs,MAX_PDC_HWIRQ ) { + irq =irq_find_mapping (pctrl->pdc_irq_domain, i);
drivers/pinctrl/qcom/pinctrl-msm.c static void msm_pinctrl_setup_pm_reset(struct msm_pinctrl *pctrl) · line 1109
Quoted 10 lines
drivers/pinctrl/qcom/pinctrl-msm.c +10
-0+ irqd =irq_get_handler_data (irq); +/* +* We don't know if the TLMM will be functional +* or not, during the suspend. If its functional, +* we do not want duplicate interrupts from PDC. +* Hence disable the GPIO IRQ and enable PDC IRQ +* for edge interrupt only. +*/ +if (irqd_is_wakeup_set (irqd) && !irqd_is_level_type (irqd)) { +disable_irq_wake (irqd->irq);
There is something I don't quite get here. If the PDC is used to wake up the platform, why is the TLMM interrupt configured as a wakeup source the first place? Or is it just to keep things simple and not have to track it in the TLMM driver itself?
drivers/pinctrl/qcom/pinctrl-msm.c static void msm_pinctrl_setup_pm_reset(struct msm_pinctrl *pctrl) · line 1113
Quoted 4 lines
drivers/pinctrl/qcom/pinctrl-msm.c +4
-0+disable_irq (irqd->irq); +enable_irq (irq); + } + }
Given that you're changing in_suspend and parsing the bitmap, shouldn't take the pdc spinlock?
Quoted 17 lines
drivers/pinctrl/qcom/pinctrl-msm.c +17
-0+ +return 0 ; +} + +int __maybe_unused msm_pinctrl_resume_late (struct device *dev) +{ +struct msm_pinctrl *pctrl =dev_get_drvdata (dev); +struct irq_data *irqd, *pdc_irqd; +unsigned int irq; +int i; + +for_each_set_bit (i, pctrl->pdc_hwirqs,MAX_PDC_HWIRQ ) { + irq =irq_find_mapping (pctrl->pdc_irq_domain, i); + irqd =irq_get_handler_data (irq); + pdc_irqd =irq_get_irq_data (irq); +/* +* The TLMM will be operational now, so disable
drivers/pinctrl/qcom/pinctrl-msm.c static void msm_pinctrl_setup_pm_reset(struct msm_pinctrl *pctrl) · line 1140
Quoted 10 lines
drivers/pinctrl/qcom/pinctrl-msm.c +10
-0+* the PDC IRQ for edge interrupts only. +*/ +if (irqd_is_wakeup_set (pdc_irqd) && + !irqd_is_level_type (pdc_irqd)) { +disable_irq_nosync (irq); +enable_irq_wake (irqd->irq); +enable_irq (irqd->irq); + } + } + in_suspend = false;
Same remark about the lock.
Quoted 23 lines
drivers/pinctrl/qcom/pinctrl-msm.c +4
-0+ +return 0 ; +} +int msm_pinctrl_probe (struct platform_device *pdev,const struct msm_pinctrl_soc_data *soc_data) {drivers/pinctrl/qcom/pinctrl-msm.h +3
-0@@ -123,4 +123,7 @@ int msm_pinctrl_probe(struct platform_device *pdev, const struct msm_pinctrl_soc_data *soc_data);int msm_pinctrl_remove (struct platform_device *pdev); +int msm_pinctrl_suspend_late (struct device *dev); +int msm_pinctrl_resume_late (struct device *dev); +#endif Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
Thanks,
M.
Signature · 1 line
Jazz is not dead, it just smell funny.
Re: [PATCH v3 3/5] drivers: pinctrl: msm: enable PDC interrupt only during suspend
Quoted 24 lines · Marc Zyngier
Hi Lina,
Quoted 20 lines · Lina Iyer
During suspend the system may power down some of the system rails. As a result, the TLMM hw block may not be operational anymore and wakeup capable GPIOs will not be detected. The PDC however will be operational and the GPIOs that are routed to the PDC as IRQs can wake the system up.
To avoid being interrupted twice (for TLMM and once for PDC IRQ) when a GPIO trips, use TLMM for active and switch to PDC for suspend. When entering suspend, disable the TLMM wakeup interrupt and instead enable the PDC IRQ and revert upon resume.
Signed-off-by Lina Iyer <[email protected]>---
Changes in v3:
- Enable PDC-IRQ swap only for edge interrupts
Changes in v2:
- Fix PDC IRQ max port, 126 is the max supported in h/w
- Use PDC hwirq in bitmap, linux numbers could be large
- SetupDISABLE_UNLAZYfor both TLMM and PDC IRQs
---
[...]
Quoted 17 lines
Quoted 17 lines
drivers/pinctrl/qcom/pinctrl-msm.c +17
-0+int __maybe_unused msm_pinctrl_suspend_late (struct device *dev) +{ +struct msm_pinctrl *pctrl =dev_get_drvdata (dev); +struct irq_data *irqd; +unsigned int irq; +int i; + + in_suspend = true; +for_each_set_bit (i, pctrl->pdc_hwirqs,MAX_PDC_HWIRQ ) { + irq =irq_find_mapping (pctrl->pdc_irq_domain, i); + irqd =irq_get_handler_data (irq); +/* +* We don't know if the TLMM will be functional +* or not, during the suspend. If its functional, +* we do not want duplicate interrupts from PDC. +* Hence disable the GPIO IRQ and enable PDC IRQ +* for edge interrupt only.
Quoted 9 lines
drivers/pinctrl/qcom/pinctrl-msm.c static void msm_pinctrl_setup_pm_reset(struct msm_pinctrl *pctrl) · line 1109
Quoted 3 lines
drivers/pinctrl/qcom/pinctrl-msm.c +3
-0+*/ +if (irqd_is_wakeup_set (irqd) && !irqd_is_level_type (irqd)) { +disable_irq_wake (irqd->irq);There is something I don't quite get here. If the PDC is used to wake up the platform, why is the TLMM interrupt configured as a wakeup source the first place? Or is it just to keep things simple and not have to track it in the TLMM driver itself?
True, it need not be. I could just avoid setting the wakeup on the TLMM and just use the PDC interrupt as wakeup.
Also, I am exploring an option that was suggested by Stephen [1] to just use the PDC interrupt as a parent of the GPIO IRQ and use a different irqchip for the PDC interrupt. I ran into some issue with accessing irqchip and irqdata of the PDC interrupt, since the irqchip was not in hierarchy with the GPIO's irqchip. I haven't been able to find time to resolve the issue that the set_parent_ functions, because of the hierarchy.
Essentially, we have two different mechanisms for GPIO IRQs based on whether they can be woken up by the PDC interrupt.
GPIO-IRQ --> PDC --> GIC GPIO-IRQ --> TLMM SUMMARY --> GIC
Do you think the idea is feasible? It would avoid doing all this enable/disable at every suspend and even during idle, when the TLMM could be powered off.
Quoted 8 lines
drivers/pinctrl/qcom/pinctrl-msm.c static void msm_pinctrl_setup_pm_reset(struct msm_pinctrl *pctrl) · line 1113
Quoted 4 lines
drivers/pinctrl/qcom/pinctrl-msm.c +4
-0+disable_irq (irqd->irq); +enable_irq (irq); + } + }Given that you're changing
in_suspendand parsing the bitmap, shouldn't take the pdc spinlock?
Since we are the the only CPU running and suspend/resume (and even idle) would be serialized I didn't see a reason for needing a lock.
Quoted 21 lines
Quoted 21 lines
drivers/pinctrl/qcom/pinctrl-msm.c +21
-0+ +return 0 ; +} + +int __maybe_unused msm_pinctrl_resume_late (struct device *dev) +{ +struct msm_pinctrl *pctrl =dev_get_drvdata (dev); +struct irq_data *irqd, *pdc_irqd; +unsigned int irq; +int i; + +for_each_set_bit (i, pctrl->pdc_hwirqs,MAX_PDC_HWIRQ ) { + irq =irq_find_mapping (pctrl->pdc_irq_domain, i); + irqd =irq_get_handler_data (irq); + pdc_irqd =irq_get_irq_data (irq); +/* +* The TLMM will be operational now, so disable +* the PDC IRQ for edge interrupts only. +*/ +if (irqd_is_wakeup_set (pdc_irqd) && + !irqd_is_level_type (pdc_irqd)) {
Quoted 9 lines
drivers/pinctrl/qcom/pinctrl-msm.c static void msm_pinctrl_setup_pm_reset(struct msm_pinctrl *pctrl) · line 1140
Quoted 6 lines
drivers/pinctrl/qcom/pinctrl-msm.c +6
-0+disable_irq_nosync (irq); +enable_irq_wake (irqd->irq); +enable_irq (irqd->irq); + } + } + in_suspend = false;Same remark about the lock.
Thanks,
Lina
Re: [PATCH v3 3/5] drivers: pinctrl: msm: enable PDC interrupt only during suspend
Quoted 68 lines · Lina Iyer
Quoted 24 lines · Marc Zyngier
Hi Lina,
Quoted 20 lines · Lina Iyer
During suspend the system may power down some of the system rails. As a result, the TLMM hw block may not be operational anymore and wakeup capable GPIOs will not be detected. The PDC however will be operational and the GPIOs that are routed to the PDC as IRQs can wake the system up.
To avoid being interrupted twice (for TLMM and once for PDC IRQ) when a GPIO trips, use TLMM for active and switch to PDC for suspend. When entering suspend, disable the TLMM wakeup interrupt and instead enable the PDC IRQ and revert upon resume.
Signed-off-by Lina Iyer <[email protected]>---
Changes in v3:
- Enable PDC-IRQ swap only for edge interrupts
Changes in v2:
- Fix PDC IRQ max port, 126 is the max supported in h/w
- Use PDC hwirq in bitmap, linux numbers could be large
- SetupDISABLE_UNLAZYfor both TLMM and PDC IRQs
---[...]
Quoted 17 lines
Quoted 17 lines
drivers/pinctrl/qcom/pinctrl-msm.c +17
-0+int __maybe_unused msm_pinctrl_suspend_late (struct device *dev) +{ +struct msm_pinctrl *pctrl =dev_get_drvdata (dev); +struct irq_data *irqd; +unsigned int irq; +int i; + + in_suspend = true; +for_each_set_bit (i, pctrl->pdc_hwirqs,MAX_PDC_HWIRQ ) { + irq =irq_find_mapping (pctrl->pdc_irq_domain, i); + irqd =irq_get_handler_data (irq); +/* +* We don't know if the TLMM will be functional +* or not, during the suspend. If its functional, +* we do not want duplicate interrupts from PDC. +* Hence disable the GPIO IRQ and enable PDC IRQ +* for edge interrupt only. Quoted 9 lines
drivers/pinctrl/qcom/pinctrl-msm.c static void msm_pinctrl_setup_pm_reset(struct msm_pinctrl *pctrl) · line 1109
Quoted 3 lines
drivers/pinctrl/qcom/pinctrl-msm.c +3
-0+*/ +if (irqd_is_wakeup_set (irqd) && !irqd_is_level_type (irqd)) { +disable_irq_wake (irqd->irq);There is something I don't quite get here. If the PDC is used to wake up the platform, why is the TLMM interrupt configured as a wakeup source the first place? Or is it just to keep things simple and not have to track it in the TLMM driver itself?
True, it need not be. I could just avoid setting the wakeup on the TLMM and just use the PDC interrupt as wakeup.
Also, I am exploring an option that was suggested by Stephen [1] to just use the PDC interrupt as a parent of the GPIO IRQ and use a different irqchip for the PDC interrupt. I ran into some issue with accessing irqchip and irqdata of the PDC interrupt, since the irqchip was not in hierarchy with the GPIO's irqchip. I haven't been able to find time to resolve the issue that the
set_parent_functions, because of the hierarchy.Essentially, we have two different mechanisms for GPIO IRQs based on whether they can be woken up by the PDC interrupt.
Quoted 7 lines
GPIO-IRQ --> PDC --> GIC GPIO-IRQ --> TLMM SUMMARY --> GICDo you think the idea is feasible? It would avoid doing all this enable/disable at every suspend and even during idle, when the TLMM could be powered off.
[me tries to page it all in again]
You could have the PDC as part of the GPIO hierarchy:
GPIO -> PDC -> TLMM -> GIC
and always configure the PDC as a wake-up source. I just wonder if you can do that without setting up a parallel hierarchy between the PDC and the GIC. We already have similar things in the tree (see OMAP's wakeupgen), and it may be worth having a look. The lack of interrupt replaying on the PDC is quite annoying (I have much stronger words in mind though), and I'm not sure we can easily fix that one without this parallel interrupt hack (you need something to inject edge interrupts in the TLMM).
Quoted 10 lines
Quoted 10 lines
drivers/pinctrl/qcom/pinctrl-msm.c static void msm_pinctrl_setup_pm_reset(struct msm_pinctrl *pctrl) · line 1113
Quoted 6 lines
drivers/pinctrl/qcom/pinctrl-msm.c +4
-0+disable_irq (irqd->irq); +enable_irq (irq); + } + }Given that you're changing
in_suspendand parsing the bitmap, shouldn't take the pdc spinlock?
Quoted 2 lines
Since we are the the only CPU running and suspend/resume (and even idle) would be serialized I didn't see a reason for needing a lock.
In that case, what is the purpose of 'in_suspend' if msm_gpio_irq_set_wake cannot happen during the suspend/resume phases? It all seems a bit inconsistent.
Thanks,
N,
Signature · 1 line
Jazz is not dead, it just smell funny.
Re: [PATCH v3 3/5] drivers: pinctrl: msm: enable PDC interrupt only during suspend
Quoted 28 lines · Marc Zyngier
Quoted 18 lines · Lina Iyer
Quoted 4 lines · Marc Zyngier
Hi Lina,
On Tue, 04 Sep 2018 22:18:08 +0100,
Lina Iyer <[email protected]> wrote:Also, I am exploring an option that was suggested by Stephen [1] to just use the PDC interrupt as a parent of the GPIO IRQ and use a different irqchip for the PDC interrupt. I ran into some issue with accessing irqchip and irqdata of the PDC interrupt, since the irqchip was not in hierarchy with the GPIO's irqchip. I haven't been able to find time to resolve the issue that the
set_parent_functions, because of the hierarchy.Essentially, we have two different mechanisms for GPIO IRQs based on whether they can be woken up by the PDC interrupt.
Quoted 7 lines
GPIO-IRQ --> PDC --> GIC GPIO-IRQ --> TLMM SUMMARY --> GICDo you think the idea is feasible? It would avoid doing all this enable/disable at every suspend and even during idle, when the TLMM could be powered off.
Quoted 6 lines
[me tries to page it all in again]
You could have the PDC as part of the GPIO hierarchy:
GPIO -> PDC -> TLMM -> GIC
The PDC irqchip's parent is the GIC as set up in drivers/irqchip/qcom-pdc.c. Wouldn't that conflict with the established hierarchy?
Quoted 4 lines
and always configure the PDC as a wake-up source. I just wonder if you can do that without setting up a parallel hierarchy between the PDC and the GIC. We already have similar things in the tree (see OMAP's wakeupgen), and it may be worth having a look.
Sure, will take a look.
Quoted 6 lines
The lack of interrupt
replaying on the PDC is quite annoying (I have much stronger words in mind though), and I'm not sure we can easily fix that one without this parallel interrupt hack (you need something to inject edge interrupts in the TLMM).
The PDC replays the intterupt at the GIC, not the at the TLMM. So the hierachy you recommended may not work as well here.
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
drivers/pinctrl/qcom/pinctrl-msm.c static void msm_pinctrl_setup_pm_reset(struct msm_pinctrl *pctrl) · line 1113
Quoted 6 lines
drivers/pinctrl/qcom/pinctrl-msm.c +4
-0+disable_irq (irqd->irq); +enable_irq (irq); + } + }Given that you're changing
in_suspendand parsing the bitmap, shouldn't take the pdc spinlock?
Quoted 7 lines
Quoted 2 lines
Since we are the the only CPU running and suspend/resume (and even idle) would be serialized I didn't see a reason for needing a lock.
In that case, what is the purpose of '
in_suspend' ifmsm_gpio_irq_set_wakecannot happen during the suspend/resume phases? It all seems a bit inconsistent.
Well the disable_irq_wake that I call here, calls into the set_wake callbacks. Hence the flag to indicate that we should ignore the PDC interrupt configuration at that time. Let me see if I need to disable the disable_irq_wake at all.
Thanks,
Lina
PATCH v3 4/5 drivers: pinctrl: qcom: sdm845: support GPIO wakeup from suspend
In reply to Lina IyerEnable TLMM IRQs to be sensed by PDC when we enter suspend. It is possible that the TLMM may be powered off and not detect GPIOs that are configured as wake up interrupts. By hooking into suspend callbacks, we allow PDC IRQs to take over and wake up the system if wakeup interrupts are triggered.
---
Changes in v3:
- Move the common suspend ops definition to pinctrl-msm.c
--- drivers/pinctrl/qcom/pinctrl-msm.c | 5 +++++ drivers/pinctrl/qcom/pinctrl-msm.h | 2 ++ drivers/pinctrl/qcom/pinctrl-sdm845.c | 1 + 3 files changed, 8 insertions(+)
drivers/pinctrl/qcom/pinctrl-msm.c +5 -0
@@ -1142,6 +1142,11 @@ int __maybe_unused msm_pinctrl_resume_late(struct device *dev)return 0 ; } +const struct dev_pm_ops msm_pinctrl_dev_pm_ops = { +SET_LATE_SYSTEM_SLEEP_PM_OPS (msm_pinctrl_suspend_late, + msm_pinctrl_resume_late) +}; +int msm_pinctrl_probe (struct platform_device *pdev,const struct msm_pinctrl_soc_data *soc_data) {
drivers/pinctrl/qcom/pinctrl-msm.h +2 -0
@@ -126,4 +126,6 @@ int msm_pinctrl_remove(struct platform_device *pdev);int msm_pinctrl_suspend_late (struct device *dev);int msm_pinctrl_resume_late (struct device *dev); +extern const struct dev_pm_ops msm_pinctrl_dev_pm_ops; +#endif
drivers/pinctrl/qcom/pinctrl-sdm845.c +1 -0
@@ -1301,6 +1301,7 @@ static struct platform_driver sdm845_pinctrl_driver = { .driver = { .name = "sdm845-pinctrl", .of_match_table = sdm845_pinctrl_of_match, + .pm = &msm_pinctrl_dev_pm_ops, }, .probe = sdm845_pinctrl_probe, .remove = msm_pinctrl_remove,
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH v3 5/5 arm64: dts: qcom: add wake up interrupts for GPIOs for SDM845
In reply to Lina IyerGPIOs that are wakeup capable have interrupt lines that are routed to the always-on interrupt controller (PDC) in parallel to the pinctrl. The interrupts listed here are the wake up lines corresponding to GPIOs.
---
Changes in v2:
- Define IRQ trigger type in DT
Changes in v1:
- Use interrupt-extended for all TLMM interrupts
- Define GPIO-PDC map using interrupt-names
--- arch/arm64/boot/dts/qcom/sdm845.dtsi | 152 ++++++++++++++++++++++++++- 1 file changed, 151 insertions(+), 1 deletion(-)
arch/arm64/boot/dts/qcom/sdm845.dtsi +151 -1
@@ -712,11 +712,161 @@ tlmm: pinctrl@3400000 { compatible = "qcom,sdm845-pinctrl"; reg = <0x03400000 0xc00000>; - interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>; gpio-controller; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; + interrupts-extended = + <&intc GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 30 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 31 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 32 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 33 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 34 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 35 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 36 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 37 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 38 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 39 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 41 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 42 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 43 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 44 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 45 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 46 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 47 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 49 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 50 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 51 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 52 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 54 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 55 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 56 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 57 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 58 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 59 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 60 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 61 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 62 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 63 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 64 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 65 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 66 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 67 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 68 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 69 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 70 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 71 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 72 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 73 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 74 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 75 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 76 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 77 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 79 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 80 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 81 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 82 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 83 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 84 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 85 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 86 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 90 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 91 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 92 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 95 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 96 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 97 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 98 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 99 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 100 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 102 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 103 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 104 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 105 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 106 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 107 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 108 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "summary-irq", + "gpio1", + "gpio3", + "gpio5", + "gpio10", + "gpio11", + "gpio20", + "gpio22", + "gpio24", + "gpio26", + "gpio30", + "gpio32", + "gpio34", + "gpio36", + "gpio37", + "gpio38", + "gpio39", + "gpio40", + "gpio43", + "gpio44", + "gpio46", + "gpio48", + "gpio52", + "gpio53", + "gpio54", + "gpio56", + "gpio57", + "gpio58", + "gpio59", + "gpio60", + "gpio61", + "gpio62", + "gpio63", + "gpio64", + "gpio66", + "gpio68", + "gpio71", + "gpio73", + "gpio77", + "gpio78", + "gpio79", + "gpio80", + "gpio84", + "gpio85", + "gpio86", + "gpio88", + "gpio91", + "gpio92", + "gpio95", + "gpio96", + "gpio97", + "gpio101", + "gpio103", + "gpio104", + "gpio115", + "gpio116", + "gpio117", + "gpio118", + "gpio119", + "gpio120", + "gpio121", + "gpio122", + "gpio123", + "gpio124", + "gpio125", + "gpio127", + "gpio128", + "gpio129", + "gpio130", + "gpio132", + "gpio133", + "gpio145", + "gpio41", + "gpio89", + "gpio31", + "gpio49", + "gpio41", + "gpio89", + "gpio31", + "gpio49"; qup_i2c0_default: qup-i2c0-default { pinmux {
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project