Received: by 2002:ac0:950c:0:0:0:0:0 with SMTP id f12csp3304937imc; Wed, 13 Mar 2019 14:20:31 -0700 (PDT) X-Google-Smtp-Source: APXvYqwG9JHLupSg6pw5XJNQuTzJIECvnTKeEnXmJfjSr62TsbY9222Hb5TX+/oFJylHo/E9+/1P X-Received: by 2002:a62:76d4:: with SMTP id r203mr46420519pfc.15.1552512031387; Wed, 13 Mar 2019 14:20:31 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1552512031; cv=none; d=google.com; s=arc-20160816; b=U5OpF+nOSPEkgsWmuhSulwLkC1lgM4wjuvZiBv8ALpjxfXemCCRLGmai2Ps/QeF78f az36CHMADI3dm22AJ91TamcVcY3jU3VQ4z+9/KI/G4sB71oIDak84Ukvgbk+tfmm+uRq lu8NeTlr8+J/oG9SocgEuO4MYV6W52on+zoz3/xsktUhuKNSEODsfqcposLWH4z9SNWA xUAYDhsZXZut9SZonHO0Owgym+QCuXMzFLjUaKYx5VwXa9kluols9DmFVL8epvMCwLdU BXMvOr1G91mHvnpw8aEfUMVxgS2Kmf0184cH6311Slly+xhX0Vt3u5MKFuFPq5QwNDSp HVUQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dmarc-filter:dkim-signature:dkim-signature; bh=sWOGa3Jjg2aVZJlMn49GwmNVtET7YIX8IyDpb0+7kRc=; b=U9SCpsmlXNVhtsqSCaWoNpA7KSkcWypMZX4j2sDEOIrIVBdaK1b5+d0XIciReS/x3t F9y35++zYmKNAwDiannkZ+FzcY0ManzwMiLOleO+I0+Nka8iXwqMr9U0IcUqDFljsWvg adAo96Ev5HG1Ym8HpGqx21X6wrmu3tNMonPWBBfFeDvpNAeEFJW7I22AdguDhypv8dqv RS4wB1viI5UoooX9fINAkqHdJgEi/qv83XzNj+WiLsFp+fPQNac06/PvR5JfSi2XzXXJ nHKHXgGWT3eRl0AQAkCDWHkqvjBrDlXQTOwaG+vLbXULpp92Xn6N0vuD+rIJm/QB9cl2 fxBw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@codeaurora.org header.s=default header.b=J2YZEvu8; dkim=pass header.i=@codeaurora.org header.s=default header.b=Z5jYeaVg; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id c16si11713988plo.412.2019.03.13.14.20.15; Wed, 13 Mar 2019 14:20:31 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@codeaurora.org header.s=default header.b=J2YZEvu8; dkim=pass header.i=@codeaurora.org header.s=default header.b=Z5jYeaVg; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727583AbfCMVTN (ORCPT + 99 others); Wed, 13 Mar 2019 17:19:13 -0400 Received: from smtp.codeaurora.org ([198.145.29.96]:46914 "EHLO smtp.codeaurora.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727570AbfCMVTL (ORCPT ); Wed, 13 Mar 2019 17:19:11 -0400 Received: by smtp.codeaurora.org (Postfix, from userid 1000) id 1846A61196; Wed, 13 Mar 2019 21:19:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1552511951; bh=xRjiiudR9CYZiAvvB4q1udaYQzh6RmaRwVhLwdws0YQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=J2YZEvu8rpJuAe3f1bWfHBRXGqYUr4LLx0YMe2GH6KYCO7bmP8aXEtcTD1ScLYAXW /V3SxJaYwcvJTTPvCIdtCyqSfI73AoOn1CKXJRASBTbsgLNdOVRt1jtLzmary+7/kA EC8+DxDOSew2b2+y7aj3HjPYRlvypYPlox2HVv5o= X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on pdx-caf-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.7 required=2.0 tests=ALL_TRUSTED,BAYES_00, DKIM_INVALID,DKIM_SIGNED autolearn=no autolearn_force=no version=3.4.0 Received: from codeaurora.org (i-global254.qualcomm.com [199.106.103.254]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (No client certificate requested) (Authenticated sender: ilina@smtp.codeaurora.org) by smtp.codeaurora.org (Postfix) with ESMTPSA id E94CF60DA8; Wed, 13 Mar 2019 21:19:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1552511946; bh=xRjiiudR9CYZiAvvB4q1udaYQzh6RmaRwVhLwdws0YQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Z5jYeaVg+A/YU3jWgDUu+Lji8fUmtmXSXg7OtGP4XEOqITy1N0/UWKGZaOFYXzHwW y9KhTQs9yWKQgO1JRabxtJzePtpobtG4JGuuqLIMsQjAwCScfc0RASTNMaYbjrCCe+ o7f1Fl21F6eg516apNPalBhq/rqnzhUctkF6rJUM= DMARC-Filter: OpenDMARC Filter v1.3.2 smtp.codeaurora.org E94CF60DA8 Authentication-Results: pdx-caf-mail.web.codeaurora.org; dmarc=none (p=none dis=none) header.from=codeaurora.org Authentication-Results: pdx-caf-mail.web.codeaurora.org; spf=none smtp.mailfrom=ilina@codeaurora.org From: Lina Iyer To: swboyd@chromium.org, evgreen@chromium.org, marc.zyngier@arm.com Cc: linux-kernel@vger.kernel.org, rplsssn@codeaurora.org, linux-arm-msm@vger.kernel.org, thierry.reding@gmail.com, bjorn.andersson@linaro.org, dianders@chromium.org, linus.walleij@linaro.org, Lina Iyer Subject: [PATCH v4 07/10] drivers: pinctrl: msm: setup GPIO irqchip hierarchy Date: Wed, 13 Mar 2019 15:18:41 -0600 Message-Id: <20190313211844.29416-8-ilina@codeaurora.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190313211844.29416-1-ilina@codeaurora.org> References: <20190313211844.29416-1-ilina@codeaurora.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org To allow GPIOs to wakeup the system from suspend or deep idle, the wakeup capable GPIOs are setup in hierarchy with interrupts from the wakeup-parent irqchip. In older SoC's, the TLMM will handover detection to the parent irqchip and in newer SoC's, the parent irqchip may also be active as well as the TLMM and therefore the GPIOs need to be masked at TLMM to avoid duplicate interrupts. To enable both these configurations to exist, allow the parent irqchip to dictate the TLMM irqchip's behavior when masking/unmasking the interrupt. Co-developed-by: Stephen Boyd Signed-off-by: Lina Iyer --- Changes in v4: - Remove irq_set_wake() on summary IRQ interrupt Changes in v3: - Use of_irq_domain_map() and pass PDC pin to parent irqdomain Changes in v2: - Call parent mask when masking GPIO interrupt Changes in v1: - Fix bug when unmasking PDC interrupt --- drivers/pinctrl/qcom/pinctrl-msm.c | 151 ++++++++++++++++++++++++----- 1 file changed, 128 insertions(+), 23 deletions(-) diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index ee8119879c4c..97e9000fa3c3 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -69,6 +71,7 @@ struct msm_pinctrl { DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO); DECLARE_BITMAP(enabled_irqs, MAX_NR_GPIO); + DECLARE_BITMAP(wakeup_masked_irqs, MAX_NR_GPIO); const struct msm_pinctrl_soc_data *soc; void __iomem *regs[MAX_NR_TILES]; @@ -703,6 +706,13 @@ static void msm_gpio_irq_mask(struct irq_data *d) g = &pctrl->soc->groups[d->hwirq]; + if (d->parent_data) + irq_chip_mask_parent(d); + + /* Monitored by parent wakeup controller?*/ + if (test_bit(d->hwirq, pctrl->wakeup_masked_irqs)) + return; + raw_spin_lock_irqsave(&pctrl->lock, flags); val = msm_readl_intr_cfg(pctrl, g); @@ -747,6 +757,13 @@ static void msm_gpio_irq_unmask(struct irq_data *d) g = &pctrl->soc->groups[d->hwirq]; + if (d->parent_data) + irq_chip_unmask_parent(d); + + /* Monitored by parent wakeup controller? Keep masked */ + if (test_bit(d->hwirq, pctrl->wakeup_masked_irqs)) + return; + raw_spin_lock_irqsave(&pctrl->lock, flags); val = msm_readl_intr_cfg(pctrl, g); @@ -767,6 +784,10 @@ static void msm_gpio_irq_ack(struct irq_data *d) unsigned long flags; u32 val; + /* Handled by parent wakeup controller? Do nothing */ + if (test_bit(d->hwirq, pctrl->wakeup_masked_irqs)) + return; + g = &pctrl->soc->groups[d->hwirq]; raw_spin_lock_irqsave(&pctrl->lock, flags); @@ -794,6 +815,13 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) g = &pctrl->soc->groups[d->hwirq]; + if (d->parent_data) + irq_chip_set_type_parent(d, type); + + /* Monitored by parent wakeup controller? Keep masked */ + if (test_bit(d->hwirq, pctrl->wakeup_masked_irqs)) + return 0; + raw_spin_lock_irqsave(&pctrl->lock, flags); /* @@ -880,17 +908,10 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) 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; + if (d->parent_data) + return irq_chip_set_wake_parent(d, on); - raw_spin_lock_irqsave(&pctrl->lock, flags); - - irq_set_irq_wake(pctrl->irq, on); - - raw_spin_unlock_irqrestore(&pctrl->lock, flags); - - return 0; + return -ENODEV; } static int msm_gpio_irq_reqres(struct irq_data *d) @@ -967,11 +988,87 @@ static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl) return device_property_read_u16_array(pctrl->dev, "gpios", NULL, 0) > 0; } +static int msm_gpio_domain_translate(struct irq_domain *d, + struct irq_fwspec *fwspec, + unsigned long *hwirq, unsigned int *type) +{ + if (is_of_node(fwspec->fwnode)) { + if (fwspec->param_count < 2) + return -EINVAL; + *hwirq = fwspec->param[0]; + *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK; + return 0; + } + + return -EINVAL; +} + +static int msm_gpio_domain_alloc(struct irq_domain *domain, unsigned int virq, + unsigned int nr_irqs, void *arg) +{ + int ret; + irq_hw_number_t hwirq; + struct gpio_chip *gc = domain->host_data; + struct msm_pinctrl *pctrl = gpiochip_get_data(gc); + struct irq_fwspec *fwspec = arg; + struct qcom_irq_fwspec parent = { }; + unsigned int type; + + ret = msm_gpio_domain_translate(domain, fwspec, &hwirq, &type); + if (ret) + return ret; + + ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, + &pctrl->irq_chip, gc); + if (ret < 0) + return ret; + + if (!domain->parent) + return 0; + + ret = of_irq_domain_map(fwspec, &parent.fwspec); + if (ret) + return ret; + + parent.fwspec.fwnode = domain->parent->fwnode; + + ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &parent); + if (ret) + return ret; + + if (parent.mask) + set_bit(hwirq, pctrl->wakeup_masked_irqs); + + return 0; +} + +/* + * TODO: Get rid of this and push it into gpiochip_to_irq() + */ +static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) +{ + struct irq_fwspec fwspec; + + fwspec.fwnode = of_node_to_fwnode(chip->of_node); + fwspec.param[0] = offset; + fwspec.param[1] = IRQ_TYPE_LEVEL_HIGH; + fwspec.param_count = 2; + + return irq_create_fwspec_mapping(&fwspec); +} + +static const struct irq_domain_ops msm_gpio_domain_ops = { + .translate = msm_gpio_domain_translate, + .alloc = msm_gpio_domain_alloc, + .free = irq_domain_free_irqs_top, +}; + static int msm_gpio_init(struct msm_pinctrl *pctrl) { struct gpio_chip *chip; int ret; unsigned ngpio = pctrl->soc->ngpios; + struct device_node *dn; if (WARN_ON(ngpio > MAX_NR_GPIO)) return -EINVAL; @@ -986,6 +1083,7 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) chip->need_valid_mask = msm_gpio_needs_valid_mask(pctrl); pctrl->irq_chip.name = "msmgpio"; + pctrl->irq_chip.irq_eoi = irq_chip_eoi_parent; 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; @@ -994,6 +1092,22 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) pctrl->irq_chip.irq_request_resources = msm_gpio_irq_reqres; pctrl->irq_chip.irq_release_resources = msm_gpio_irq_relres; + chip->irq.chip = &pctrl->irq_chip; + chip->irq.domain_ops = &msm_gpio_domain_ops; + chip->irq.handler = handle_edge_irq; + chip->irq.default_type = IRQ_TYPE_EDGE_RISING; + + dn = of_parse_phandle(pctrl->dev->of_node, "wakeup-parent", 0); + if (dn) { + 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->to_irq = msm_gpio_to_irq; + } + ret = gpiochip_add_data(&pctrl->chip, pctrl); if (ret) { dev_err(pctrl->dev, "Failed register gpiochip\n"); @@ -1015,26 +1129,17 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) dev_name(pctrl->dev), 0, 0, chip->ngpio); if (ret) { dev_err(pctrl->dev, "Failed to add pin range\n"); - gpiochip_remove(&pctrl->chip); - return ret; + goto fail; } } - ret = gpiochip_irqchip_add(chip, - &pctrl->irq_chip, - 0, - handle_edge_irq, - IRQ_TYPE_NONE); - if (ret) { - dev_err(pctrl->dev, "Failed to add irqchip to gpiochip\n"); - gpiochip_remove(&pctrl->chip); - return -ENOSYS; - } - gpiochip_set_chained_irqchip(chip, &pctrl->irq_chip, pctrl->irq, msm_gpio_irq_handler); return 0; +fail: + gpiochip_remove(&pctrl->chip); + return ret; } static int msm_ps_hold_restart(struct notifier_block *nb, unsigned long action, -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project