From patchwork Thu Sep 7 15:33:28 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Timur Tabi X-Patchwork-Id: 9942465 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 13730604D7 for ; Thu, 7 Sep 2017 15:48:05 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0911428732 for ; Thu, 7 Sep 2017 15:48:05 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id F209B28735; Thu, 7 Sep 2017 15:48:04 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_MED autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [65.50.211.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 660DC28734 for ; Thu, 7 Sep 2017 15:48:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=cy7gB31+C2heVRt/EiUBNMYghy9nhxgqHjR0TLMPdjU=; b=XNCjzKhulshy4HwhBuEUgjSDON vKHWUqlH56yZsxKZGWTKiPIvTdicOFFRMu83C/8LAbkhJZfIxORJ3Ox1x/MDp/17+XkYxoYVap3/h CnCqVvtLLVjgBA+ct46/xkJ7A5MKuzSNMy+J9eAhml25wS6CoJYFf+ju7br5Wa5L5rwBHTMoDj3bf opPmtbDh9FoEzaENtxAMN7IUoJi4uyQzja1Ty65dgKhN8xy4JFBzzcv+7JdvkwiRU9QkCb8OcSRQF Wp8yAFZe24RUAw7TOwSEInYwbZKEmz9tGvDEWqQ3CBuNEHW9H6aCvasKts71qhQSM+YJEvrF5A5LZ FUZd1pDA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1dpz25-0002sZ-7C; Thu, 07 Sep 2017 15:47:57 +0000 Received: from casper.infradead.org ([2001:8b0:10b:1236::1]) by bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1dpz23-0002nb-OL for linux-arm-kernel@bombadil.infradead.org; Thu, 07 Sep 2017 15:47:55 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=References:In-Reply-To:Message-Id:Date: Subject:Cc:To:From:Sender:Reply-To:MIME-Version:Content-Type: Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id: List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive; bh=YmPopQ3hBrr4bsD0u4zW/tmNc1Xso0U0JPmYsaJjlY4=; b=bQhYcjikwMXPPxob0cp31kJWE 4TVczhcXJIfLaChwHq+b2Zvq6Q03I87bZU5+/L4TFZIVvEXtGy0LAPVuOSOwH9rllY/HYoiF6j7KK pTTfyC57V/2hy+6yjUYIXuXgfYY6HlRZV/ZEbY+HGzjzLBipqCvyRm5yOw3ENCIQ+Si26hIlfgmr1 xpC9kIhQpitMv/FdlB2EzHnTZ3WrU2lqKS5l/G3gpUFnFzvGHLv87SfBkrTCQHAxoLUTBUVbmZJzi o+SHWARCYK+C2O4yj0rERAtyf9F7dACdPli1plPUm7Qqtqqlwf24HcRnalu0cPUgJIdx5RRQjiNm6 Cq19unE3g==; Received: from smtp.codeaurora.org ([198.145.29.96]) by casper.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1dpyol-0000d7-Sr for linux-arm-kernel@lists.infradead.org; Thu, 07 Sep 2017 15:34:14 +0000 Received: by smtp.codeaurora.org (Postfix, from userid 1000) id 3170D61155; Thu, 7 Sep 2017 15:33:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1504798430; bh=oesfOqOwzo6xKcvVlcYc2Bf4qD/Q0M4gqAf6sA4aErw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=RwFWx/tovXwBDtAMk+PaLAe7PVQaOmGDpOTG33nRPBodPdf8UTTJbwoigiDPpbYO/ mRfdm6zzocKhoY+7N5WedWWOWfT6RIkiMJ3upxVmIUnMv+XtwiPFG9V/N39ycOlm1K suY0gBSBlBZ7MaV0NgLMVRFHIpKxvqvlq0X8yfMA= Received: from timur-ubuntu.qualcomm.com (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: timur@smtp.codeaurora.org) by smtp.codeaurora.org (Postfix) with ESMTPSA id 1A97560CA5; Thu, 7 Sep 2017 15:33:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1504798429; bh=oesfOqOwzo6xKcvVlcYc2Bf4qD/Q0M4gqAf6sA4aErw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=L9VYmaDTnxV6PlYXYk/pcbCwZwUfhVpEdUjPW380jK7pVOb2Hcbb8/AUQK1M6QaEK 4caZABpt59UyRfrDHC8pNHoO7mjrdg1Or8gWKJjRxGWWFneDnrv5I3MlHb7w02aEEx 45yQ/Z4nFRjmxku82Zuakse5TswrG2rYkck/JiCE= DMARC-Filter: OpenDMARC Filter v1.3.2 smtp.codeaurora.org 1A97560CA5 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=timur@codeaurora.org From: Timur Tabi To: Linus Walleij , andy.gross@linaro.org, david.brown@linaro.org, anjiandi@codeaurora.org, Bjorn Andersson , linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-arm-msm@vger.kernel.org Subject: [PATCH 1/2] [v5] pinctrl: qcom: disable GPIO groups with no pins Date: Thu, 7 Sep 2017 10:33:28 -0500 Message-Id: <1504798409-32041-2-git-send-email-timur@codeaurora.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1504798409-32041-1-git-send-email-timur@codeaurora.org> References: <1504798409-32041-1-git-send-email-timur@codeaurora.org> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20170907_163412_216626_29AB85D7 X-CRM114-Status: GOOD ( 36.18 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: timur@codeaurora.org MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP pinctrl-msm only accepts an array of GPIOs from 0 to n-1, and it expects each group to support have only one pin (npins == 1). We can support "sparse" GPIO maps if we allow for some groups to have zero pins (npins == 0). These pins are "hidden" from the rest of the driver and gpiolib. A new boolean 'sparse' indicates whether the GPIO map is sparse. If any GPIO has an 'npins' value of 0, then 'sparse' must be set to True. Most access to unavailable GPIOs can be blocked via the gpio_chip.request function. The one exception is when gpiochip_add_data() scans all of the GPIOs without "requesting" them. To cover this case, msm_gpio_get_direction() separately checks if the GPIO is available. Signed-off-by: Timur Tabi --- drivers/pinctrl/qcom/pinctrl-msm.c | 110 +++++++++++++++++++++++++++++++++++-- drivers/pinctrl/qcom/pinctrl-msm.h | 2 + 2 files changed, 106 insertions(+), 6 deletions(-) diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index ff491da64dab..ca4ae3d76eb4 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -443,6 +443,14 @@ static int msm_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) g = &pctrl->soc->groups[offset]; + /* + * During initialization, gpiolib may query all GPIOs for their + * initial direction, regardless if they exist, so block access + * to those that are unavailable. + */ + if (!g->npins) + return -ENODEV; + val = readl(pctrl->regs + g->ctl_reg); /* 0 = output, 1 = input */ @@ -507,6 +515,11 @@ static void msm_gpio_dbg_show_one(struct seq_file *s, }; g = &pctrl->soc->groups[offset]; + + /* If the GPIO group has no pins, then don't show it. */ + if (!g->npins) + return; + ctl_reg = readl(pctrl->regs + g->ctl_reg); is_out = !!(ctl_reg & BIT(g->oe_bit)); @@ -516,7 +529,7 @@ static void msm_gpio_dbg_show_one(struct seq_file *s, seq_printf(s, " %-8s: %-3s %d", g->name, is_out ? "out" : "in", func); seq_printf(s, " %dmA", msm_regval_to_drive(drive)); - seq_printf(s, " %s", pulls[pull]); + seq_printf(s, " %s\n", pulls[pull]); } static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) @@ -524,23 +537,36 @@ static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) unsigned gpio = chip->base; unsigned i; - for (i = 0; i < chip->ngpio; i++, gpio++) { + for (i = 0; i < chip->ngpio; i++, gpio++) msm_gpio_dbg_show_one(s, NULL, chip, i, gpio); - seq_puts(s, "\n"); - } } #else #define msm_gpio_dbg_show NULL #endif +/* + * If the requested GPIO has no pins, then treat it as unavailable. + * Otherwise, call the standard request function. + */ +static int msm_gpio_request(struct gpio_chip *chip, unsigned int offset) +{ + struct msm_pinctrl *pctrl = gpiochip_get_data(chip); + const struct msm_pingroup *g = &pctrl->soc->groups[offset]; + + if (!g->npins) + return -ENODEV; + + return gpiochip_generic_request(chip, offset); +} + static const struct gpio_chip msm_gpio_template = { .direction_input = msm_gpio_direction_input, .direction_output = msm_gpio_direction_output, .get_direction = msm_gpio_get_direction, .get = msm_gpio_get, .set = msm_gpio_set, - .request = gpiochip_generic_request, + .request = msm_gpio_request, .free = gpiochip_generic_free, .dbg_show = msm_gpio_dbg_show, }; @@ -808,11 +834,57 @@ static void msm_gpio_irq_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); } +/** + * msm_gpio_get_next_range() - find next range of consecutive gpios + * @pctrl: msm_pinctrl object + * @pstart: pointer to index of next starting position + * + * In a sparse GPIO map, available GPIOs are typically collected into blocks. + * Given a starting index into the groups[] array, this function will scan all + * the gpios until it finds the next block of available GPIOs. + * + * If groups[*pstart] already points to an available GPIO, then assume that + * it is the start of a block. + * + * The caller is responsible for moving *pstart to after the end of the + * previous block so that it this function can find the next block. + * + * Return: The count of the block starting at @pstart, or 0 if there are no + * more blocks. + */ +static unsigned int msm_gpio_get_next_range(struct msm_pinctrl *pctrl, + unsigned int *pstart) +{ + const struct msm_pingroup *groups = pctrl->soc->groups; + unsigned int ngpio = pctrl->soc->ngpios; + unsigned int count = 0; + unsigned int start = *pstart; + + /* Find the first available GPIO */ + while (!groups[start].npins) + if (++start == ngpio) + /* None found, so just exit */ + return 0; + + *pstart = start; + + /* Count the number of those GPIOs in a row */ + while (groups[start].npins) { + count++; + if (++start == ngpio) + break; + } + + return count; +} + static int msm_gpio_init(struct msm_pinctrl *pctrl) { struct gpio_chip *chip; int ret; unsigned ngpio = pctrl->soc->ngpios; + const struct msm_pingroup *groups = pctrl->soc->groups; + unsigned int i, start = 0, count; if (WARN_ON(ngpio > MAX_NR_GPIO)) return -EINVAL; @@ -825,13 +897,39 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) chip->owner = THIS_MODULE; chip->of_node = pctrl->dev->of_node; + /* If the GPIO map is sparse, then we need to disable specific IRQs */ + chip->irq_need_valid_mask = pctrl->soc->sparse; + ret = gpiochip_add_data(&pctrl->chip, pctrl); if (ret) { dev_err(pctrl->dev, "Failed register gpiochip\n"); return ret; } - ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), 0, 0, chip->ngpio); + /* + * If irq_need_valid_mask is true, then gpiochip_add_data() will + * initialize irq_valid_mask to all 1s. We need to clear all the + * GPIOs that are unavailable, and we need to find each block + * of consecutive available GPIOs are add them as pin ranges. + */ + if (chip->irq_need_valid_mask) { + for (i = 0; i < ngpio; i++) + if (!groups[i].npins) + clear_bit(i, pctrl->chip.irq_valid_mask); + + while ((count = msm_gpio_get_next_range(pctrl, &start))) { + ret = gpiochip_add_pin_range(&pctrl->chip, + dev_name(pctrl->dev), + start, start, count); + if (ret) + break; + start += count; + } + } else { + ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), + 0, 0, ngpio); + } + if (ret) { dev_err(pctrl->dev, "Failed to add pin range\n"); gpiochip_remove(&pctrl->chip); diff --git a/drivers/pinctrl/qcom/pinctrl-msm.h b/drivers/pinctrl/qcom/pinctrl-msm.h index 9b9feea540ff..70762bcb84cb 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.h +++ b/drivers/pinctrl/qcom/pinctrl-msm.h @@ -107,6 +107,7 @@ struct msm_pingroup { * @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. + * @sparse: The GPIO map is sparse (some GPIOs have npins == 0) */ struct msm_pinctrl_soc_data { const struct pinctrl_pin_desc *pins; @@ -117,6 +118,7 @@ struct msm_pinctrl_soc_data { unsigned ngroups; unsigned ngpios; bool pull_no_keeper; + bool sparse; }; int msm_pinctrl_probe(struct platform_device *pdev,