From patchwork Mon Jul 18 17:20:18 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ray Jui X-Patchwork-Id: 649660 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3rtVLv05v6z9s6r for ; Tue, 19 Jul 2016 03:20:55 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=broadcom.com header.i=@broadcom.com header.b=D0Hjkrtl; dkim-atps=neutral Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751918AbcGRRUu (ORCPT ); Mon, 18 Jul 2016 13:20:50 -0400 Received: from mail-pf0-f170.google.com ([209.85.192.170]:33088 "EHLO mail-pf0-f170.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751840AbcGRRUt (ORCPT ); Mon, 18 Jul 2016 13:20:49 -0400 Received: by mail-pf0-f170.google.com with SMTP id y134so41416095pfg.0 for ; Mon, 18 Jul 2016 10:20:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=6plQ1grXMwxpoKyBvj9YC7hpFjQseNNe1sT59baPqBU=; b=D0HjkrtlSnWOBLEXUB+YNPb6RjSj44brE7W5GqQdROiF6f73+4NoTjc4ifSruSMCBf Kj0e1qaJ4OUx8eLgG5F6A0DCcAf5eNUOXPKqVgtsJWh4Xlj4JdHm4tAwqrBjjz+dTPdS Shc3zbhTSU1QeIpFGU2SW88ZUb/uRhLSlyj7U= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=6plQ1grXMwxpoKyBvj9YC7hpFjQseNNe1sT59baPqBU=; b=HrPwoeold2j9qHOZq2crEmLs17NzYi7UbLk0OcsyTRXINW6jdLCUlmTGGngz7DLCLy cccHhQL8S4n8mZcoz0uA7wPQfye6KhazebmgVXcwM1709DKE2R5yhEuwo2MRQa0uriL8 EI04NponVouHMMdvqpGxWehK+TnBHrVwA3X4kR5Y/vxd+6GCDyBPh149NILFpa1o4cMM 0AK09UAWOXvhEZKUHU/q0tyFXoJZ7/FibZuD4uXpXo693m2pTFkxGcdX1grt9gBYr3v0 Aqaxdym+44oUPKQ8Pr/p9UHZLK+9jpRv9a5L+2py2b8g+Mc4EWg6TgT9IE1eG1FcTfIi LstA== X-Gm-Message-State: ALyK8tIenjmPvAYB2vQ/FhKW/1WUaALOzKcJ0rWinL1+ANqufdIrreJ5t1Zc/Sv8p6XbA9nL X-Received: by 10.98.155.17 with SMTP id r17mr47444066pfd.24.1468862442680; Mon, 18 Jul 2016 10:20:42 -0700 (PDT) Received: from lbrmn-lnxub44-1.ric.broadcom.com ([216.31.219.19]) by smtp.gmail.com with ESMTPSA id p64sm6404808pfd.11.2016.07.18.10.20.40 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 18 Jul 2016 10:20:42 -0700 (PDT) From: Ray Jui To: Linus Walleij , Alexandre Courbot , Rob Herring Cc: linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org, bcm-kernel-feedback-list@broadcom.com, devicetree@vger.kernel.org, Ray Jui , Pramod Kumar Subject: [PATCH v4 2/2] pinctrl: iproc: Add NSP and Stingray GPIO support Date: Mon, 18 Jul 2016 10:20:18 -0700 Message-Id: <1468862418-31477-3-git-send-email-ray.jui@broadcom.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1468862418-31477-1-git-send-email-ray.jui@broadcom.com> References: <1468862418-31477-1-git-send-email-ray.jui@broadcom.com> Sender: linux-gpio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org The iProc GPIO controller is shared among multiple iProc based SoCs. In the NSP integration, the drive strength pinctrl function is disabled. In the integration of Stingray, pinctrl is handled by another block and this GPIO controller is solely used as a GPIO controller, and therefore should not be registered to the pinconf framework This patch introduces new SoC specific compatible strings "brcm,iproc-nsp-gpio" for NSP with drive strength feature disabled and "brcm,iproc-stingray-gpio" for Stingray with all PINCONF features disabled This patch is developed based on the initial work from Yendapally Reddy Dhananjaya who attempted to disable drive strength configuration for the iProc based NSP chip. In addition, Pramod Kumar also contributed to make the support more generic across all currently supported PINCONF functions in the iProc GPIO/PINCONF driver Signed-off-by: Pramod Kumar Signed-off-by: Ray Jui --- drivers/pinctrl/bcm/pinctrl-iproc-gpio.c | 118 +++++++++++++++++++++++++++++-- 1 file changed, 111 insertions(+), 7 deletions(-) diff --git a/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c b/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c index 3670f5e..7f77007 100644 --- a/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c +++ b/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c @@ -66,6 +66,14 @@ #define GPIO_DRV_STRENGTH_BITS 3 #define GPIO_DRV_STRENGTH_BIT_MASK ((1 << GPIO_DRV_STRENGTH_BITS) - 1) +enum iproc_pinconf_param { + IPROC_PINCONF_DRIVE_STRENGTH = 0, + IPROC_PINCONF_BIAS_DISABLE, + IPROC_PINCONF_BIAS_PULL_UP, + IPROC_PINCONF_BIAS_PULL_DOWN, + IPROC_PINCON_MAX, +}; + /* * Iproc GPIO core * @@ -78,6 +86,10 @@ * @num_banks: number of GPIO banks, each bank supports up to 32 GPIOs * @pinmux_is_supported: flag to indicate this GPIO controller contains pins * that can be individually muxed to GPIO + * @pinconf_disable: contains a list of PINCONF parameters that need to be + * disabled + * @nr_pinconf_disable: total number of PINCONF parameters that need to be + * disabled * @pctl: pointer to pinctrl_dev * @pctldesc: pinctrl descriptor */ @@ -94,6 +106,9 @@ struct iproc_gpio { bool pinmux_is_supported; + enum pin_config_param *pinconf_disable; + unsigned int nr_pinconf_disable; + struct pinctrl_dev *pctl; struct pinctrl_desc pctldesc; }; @@ -360,6 +375,65 @@ static int iproc_gpio_get(struct gpio_chip *gc, unsigned gpio) return !!(readl(chip->base + offset) & BIT(shift)); } +/* + * Mapping of the iProc PINCONF parameters to the generic pin configuration + * parameters + */ +static const enum pin_config_param iproc_pinconf_disable_map[] = { + [IPROC_PINCONF_DRIVE_STRENGTH] = PIN_CONFIG_DRIVE_STRENGTH, + [IPROC_PINCONF_BIAS_DISABLE] = PIN_CONFIG_BIAS_DISABLE, + [IPROC_PINCONF_BIAS_PULL_UP] = PIN_CONFIG_BIAS_PULL_UP, + [IPROC_PINCONF_BIAS_PULL_DOWN] = PIN_CONFIG_BIAS_PULL_DOWN, +}; + +static bool iproc_pinconf_param_is_disabled(struct iproc_gpio *chip, + enum pin_config_param param) +{ + unsigned int i; + + if (!chip->nr_pinconf_disable) + return false; + + for (i = 0; i < chip->nr_pinconf_disable; i++) + if (chip->pinconf_disable[i] == param) + return true; + + return false; +} + +static int iproc_pinconf_disable_map_create(struct iproc_gpio *chip, + unsigned long disable_mask) +{ + unsigned int map_size = ARRAY_SIZE(iproc_pinconf_disable_map); + unsigned int bit, nbits = 0; + + /* figure out total number of PINCONF parameters to disable */ + for_each_set_bit(bit, &disable_mask, map_size) + nbits++; + + if (!nbits) + return 0; + + /* + * Allocate an array to store PINCONF parameters that need to be + * disabled + */ + chip->pinconf_disable = devm_kcalloc(chip->dev, nbits, + sizeof(*chip->pinconf_disable), + GFP_KERNEL); + if (!chip->pinconf_disable) + return -ENOMEM; + + chip->nr_pinconf_disable = nbits; + + /* now store these parameters */ + nbits = 0; + for_each_set_bit(bit, &disable_mask, map_size) + chip->pinconf_disable[nbits++] = iproc_pinconf_disable_map[bit]; + + return 0; +} + static int iproc_get_groups_count(struct pinctrl_dev *pctldev) { return 1; @@ -500,6 +574,9 @@ static int iproc_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin, bool disable, pull_up; int ret; + if (iproc_pinconf_param_is_disabled(chip, param)) + return -ENOTSUPP; + switch (param) { case PIN_CONFIG_BIAS_DISABLE: iproc_gpio_get_pull(chip, gpio, &disable, &pull_up); @@ -548,6 +625,10 @@ static int iproc_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin, for (i = 0; i < num_configs; i++) { param = pinconf_to_config_param(configs[i]); + + if (iproc_pinconf_param_is_disabled(chip, param)) + return -ENOTSUPP; + arg = pinconf_to_config_argument(configs[i]); switch (param) { @@ -633,11 +714,13 @@ static int iproc_gpio_register_pinconf(struct iproc_gpio *chip) } static const struct of_device_id iproc_gpio_of_match[] = { + { .compatible = "brcm,iproc-gpio" }, { .compatible = "brcm,cygnus-ccm-gpio" }, { .compatible = "brcm,cygnus-asiu-gpio" }, { .compatible = "brcm,cygnus-crmu-gpio" }, - { .compatible = "brcm,iproc-gpio" }, - { } + { .compatible = "brcm,iproc-nsp-gpio" }, + { .compatible = "brcm,iproc-stingray-gpio" }, + { /* sentinel */ } }; static int iproc_gpio_probe(struct platform_device *pdev) @@ -646,8 +729,17 @@ static int iproc_gpio_probe(struct platform_device *pdev) struct resource *res; struct iproc_gpio *chip; struct gpio_chip *gc; - u32 ngpios; + u32 ngpios, pinconf_disable_mask = 0; int irq, ret; + bool no_pinconf = false; + + /* NSP does not support drive strength config */ + if (of_device_is_compatible(dev->of_node, "brcm,iproc-nsp-gpio")) + pinconf_disable_mask = BIT(IPROC_PINCONF_DRIVE_STRENGTH); + /* Stingray does not support pinconf in this controller */ + else if (of_device_is_compatible(dev->of_node, + "brcm,iproc-stingray-gpio")) + no_pinconf = true; chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); if (!chip) @@ -702,10 +794,22 @@ static int iproc_gpio_probe(struct platform_device *pdev) return ret; } - ret = iproc_gpio_register_pinconf(chip); - if (ret) { - dev_err(dev, "unable to register pinconf\n"); - goto err_rm_gpiochip; + if (!no_pinconf) { + ret = iproc_gpio_register_pinconf(chip); + if (ret) { + dev_err(dev, "unable to register pinconf\n"); + goto err_rm_gpiochip; + } + + if (pinconf_disable_mask) { + ret = iproc_pinconf_disable_map_create(chip, + pinconf_disable_mask); + if (ret) { + dev_err(dev, + "unable to create pinconf disable map\n"); + goto err_rm_gpiochip; + } + } } /* optional GPIO interrupt support */