From patchwork Tue May 8 09:45:02 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Linus Walleij X-Patchwork-Id: 8451 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 51F3623E20 for ; Tue, 8 May 2012 09:45:53 +0000 (UTC) Received: from mail-yx0-f180.google.com (mail-yx0-f180.google.com [209.85.213.180]) by fiordland.canonical.com (Postfix) with ESMTP id 21921A18370 for ; Tue, 8 May 2012 09:45:53 +0000 (UTC) Received: by mail-yx0-f180.google.com with SMTP id q6so173733yen.11 for ; Tue, 08 May 2012 02:45:53 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-forwarded-to:x-forwarded-for:delivered-to:received-spf:from:to:cc :subject:date:message-id:x-mailer:mime-version:content-type :x-gm-message-state; bh=PGvsa8ljz/xxSJ1C8agpp63UPDZT5EDUHxMiNoVuAD8=; b=Fc3ylII4+ljvS0i3TF7Gye/pMzAuPTBJjjU8O6t8pKYBKnOXJjKUjsCr4gUGI/O0Zg tzKPwtI8maQ+RnrSYNkVtdS0CNDn4+qcTPbDYylmRD3yKg9qhDeOJ2CtiF8lLCMRK3Cy m9utzKLvtJvWxPD40G4n+ESEB0sMIU5nYSqPKWeLTAz9Tx05v1hfRL3d7h6xVLSQcgZU mjCrMeagDep/ulLtri77LfDabibmL1i5hCUF2Leevjocz3OGNuJObP9BWAoO9B2p+ma5 T3ew+OkAH++Ij7d7XJR/FyfXqDJ2AF4+uV+vEdDDZqrIzAs8g+MAPjF9xc8F9q4ymLEG w9nQ== Received: by 10.50.220.136 with SMTP id pw8mr10491940igc.1.1336470352409; Tue, 08 May 2012 02:45:52 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.231.73.147 with SMTP id q19csp187535ibj; Tue, 8 May 2012 02:45:51 -0700 (PDT) Received: by 10.14.100.66 with SMTP id y42mr3236945eef.29.1336470351131; Tue, 08 May 2012 02:45:51 -0700 (PDT) Received: from eu1sys200aog115.obsmtp.com (eu1sys200aog115.obsmtp.com. [207.126.144.139]) by mx.google.com with SMTP id b14si5982016een.35.2012.05.08.02.45.09 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 08 May 2012 02:45:51 -0700 (PDT) Received-SPF: neutral (google.com: 207.126.144.139 is neither permitted nor denied by best guess record for domain of linus.walleij@stericsson.com) client-ip=207.126.144.139; Authentication-Results: mx.google.com; spf=neutral (google.com: 207.126.144.139 is neither permitted nor denied by best guess record for domain of linus.walleij@stericsson.com) smtp.mail=linus.walleij@stericsson.com Received: from beta.dmz-eu.st.com ([164.129.1.35]) (using TLSv1) by eu1sys200aob115.postini.com ([207.126.147.11]) with SMTP ID DSNKT6jrJH8F5/oef2fG52SFdRhllou/rAHc@postini.com; Tue, 08 May 2012 09:45:17 UTC Received: from zeta.dmz-eu.st.com (zeta.dmz-eu.st.com [164.129.230.9]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id B57B685; Tue, 8 May 2012 09:45:06 +0000 (GMT) Received: from relay2.stm.gmessaging.net (unknown [10.230.100.18]) by zeta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 2A7752671; Tue, 8 May 2012 09:45:06 +0000 (GMT) Received: from exdcvycastm022.EQ1STM.local (alteon-source-exch [10.230.100.61]) (using TLSv1 with cipher RC4-MD5 (128/128 bits)) (Client CN "exdcvycastm022", Issuer "exdcvycastm022" (not verified)) by relay2.stm.gmessaging.net (Postfix) with ESMTPS id 79886A807B; Tue, 8 May 2012 11:45:01 +0200 (CEST) Received: from steludxu4075.lud.stericsson.com (10.230.100.153) by smtp.stericsson.com (10.230.100.30) with Microsoft SMTP Server (TLS) id 8.3.83.0; Tue, 8 May 2012 11:45:05 +0200 From: Linus Walleij To: , Cc: Stephen Warren , Shawn Guo , Thomas Abraham , Dong Aisheng , Rajendra Nayak , Haojian Zhuang , Linus Walleij Subject: [PATCH 06/12] pinctrl/nomadik: implement pin configuration Date: Tue, 8 May 2012 11:45:02 +0200 Message-ID: <1336470302-23670-1-git-send-email-linus.walleij@stericsson.com> X-Mailer: git-send-email 1.7.9.2 MIME-Version: 1.0 X-Gm-Message-State: ALoCoQnIkR0O1K+ALfbzI+d7nZIxqHykTlXDAS/5/7QNEgSbeQ3cVGcgy2u7Rzbo4UwHyppQD2wc From: Linus Walleij This implements the pin configuration interface for the Nomadik pin controller. As part of the exercise we add a bit in the pin_cfg_t for the Nomadik pinctrl driver that indicates if the pin should be forced into GPIO mode. This is not done to go behind the back of the GPIO subsystem, but to ensure that default modes can be set by hogs on boot and system suspend/resume states. It was used implicitly by the old code defining all config settings and modes in a single config word but we now have a split between pinmux and pinconf leading to the need to have this. We also add a bit for explicitly setting sleepmode of the pin. This was previously handled by custom calls with the _sleep() suffix, but we now have one single interface into the configuration so we replace this with a bit indicating that the pin shall be configured into sleep mode. Some of the configuration can be refactored later to use less custom fields on the pin_cfg_t but we are currently leaving the old function calls in place so we stay compatible. Signed-off-by: Linus Walleij --- arch/arm/plat-nomadik/include/plat/pincfg.h | 13 +++ drivers/pinctrl/Kconfig | 1 + drivers/pinctrl/pinctrl-nomadik.c | 116 ++++++++++++++++++++++++++- 3 files changed, 129 insertions(+), 1 deletion(-) diff --git a/arch/arm/plat-nomadik/include/plat/pincfg.h b/arch/arm/plat-nomadik/include/plat/pincfg.h index c015133..9c949c7 100644 --- a/arch/arm/plat-nomadik/include/plat/pincfg.h +++ b/arch/arm/plat-nomadik/include/plat/pincfg.h @@ -124,6 +124,19 @@ typedef unsigned long pin_cfg_t; #define PIN_LOWEMI_DISABLED (0 << PIN_LOWEMI_SHIFT) #define PIN_LOWEMI_ENABLED (1 << PIN_LOWEMI_SHIFT) +#define PIN_GPIOMODE_SHIFT 26 +#define PIN_GPIOMODE_MASK (0x1 << PIN_GPIOMODE_SHIFT) +#define PIN_GPIOMODE(x) (((x) & PIN_GPIOMODE_MASK) >> PIN_GPIOMODE_SHIFT) +#define PIN_GPIOMODE_DISABLED (0 << PIN_GPIOMODE_SHIFT) +#define PIN_GPIOMODE_ENABLED (1 << PIN_GPIOMODE_SHIFT) + +#define PIN_SLEEPMODE_SHIFT 27 +#define PIN_SLEEPMODE_MASK (0x1 << PIN_SLEEPMODE_SHIFT) +#define PIN_SLEEPMODE(x) (((x) & PIN_SLEEPMODE_MASK) >> PIN_SLEEPMODE_SHIFT) +#define PIN_SLEEPMODE_DISABLED (0 << PIN_SLEEPMODE_SHIFT) +#define PIN_SLEEPMODE_ENABLED (1 << PIN_SLEEPMODE_SHIFT) + + /* Shortcuts. Use these instead of separate DIR, PULL, and VAL. */ #define PIN_INPUT_PULLDOWN (PIN_DIR_INPUT | PIN_PULL_DOWN) #define PIN_INPUT_PULLUP (PIN_DIR_INPUT | PIN_PULL_UP) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 0c738fd..7a3e34c 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -41,6 +41,7 @@ config PINCTRL_NOMADIK bool "Nomadik pin controller driver" depends on ARCH_U8500 select PINMUX + select PINCONF config PINCTRL_DB8500 bool "DB8500 pin controller driver" diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c index 5f0db60..ff20d97 100644 --- a/drivers/pinctrl/pinctrl-nomadik.c +++ b/drivers/pinctrl/pinctrl-nomadik.c @@ -26,6 +26,7 @@ #include #include #include +#include /* Since we request GPIOs from ourself */ #include @@ -1561,7 +1562,8 @@ int nmk_gpio_request_enable(struct pinctrl_dev *pctldev, clk_enable(nmk_chip->clk); bit = offset % NMK_GPIO_PER_CHIP; - __nmk_gpio_set_mode_safe(nmk_chip, bit, NMK_GPIO_ALT_GPIO, false); + /* There is no glitch when converting any pin to GPIO */ + __nmk_gpio_set_mode(nmk_chip, bit, NMK_GPIO_ALT_GPIO); clk_disable(nmk_chip->clk); return 0; @@ -1587,10 +1589,122 @@ static struct pinmux_ops nmk_pinmux_ops = { .gpio_disable_free = nmk_gpio_disable_free, }; +int nmk_pin_config_get(struct pinctrl_dev *pctldev, + unsigned pin, + unsigned long *config) +{ + /* Not implemented */ + return -EINVAL; +} + +int nmk_pin_config_set(struct pinctrl_dev *pctldev, + unsigned pin, + unsigned long config) +{ + static const char *pullnames[] = { + [NMK_GPIO_PULL_NONE] = "none", + [NMK_GPIO_PULL_UP] = "up", + [NMK_GPIO_PULL_DOWN] = "down", + [3] /* illegal */ = "??" + }; + static const char *slpmnames[] = { + [NMK_GPIO_SLPM_INPUT] = "input/wakeup", + [NMK_GPIO_SLPM_NOCHANGE] = "no-change/no-wakeup", + }; + struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + struct nmk_gpio_chip *nmk_chip; + struct pinctrl_gpio_range *range; + struct gpio_chip *chip; + unsigned bit; + + /* + * The pin config contains pin number and altfunction fields, here + * we just ignore that part. It's being handled by the framework and + * pinmux callback respectively. + */ + pin_cfg_t cfg = (pin_cfg_t) config; + int pull = PIN_PULL(cfg); + int slpm = PIN_SLPM(cfg); + int output = PIN_DIR(cfg); + int val = PIN_VAL(cfg); + bool lowemi = PIN_LOWEMI(cfg); + bool gpiomode = PIN_GPIOMODE(cfg); + bool sleep = PIN_SLEEPMODE(cfg); + + range = nmk_match_gpio_range(pctldev, pin); + if (!range) { + dev_err(npct->dev, "invalid pin offset %d\n", pin); + return -EINVAL; + } + if (!range->gc) { + dev_err(npct->dev, "GPIO chip missing in range for pin %d\n", + pin); + return -EINVAL; + } + chip = range->gc; + nmk_chip = container_of(chip, struct nmk_gpio_chip, chip); + + if (sleep) { + int slpm_pull = PIN_SLPM_PULL(cfg); + int slpm_output = PIN_SLPM_DIR(cfg); + int slpm_val = PIN_SLPM_VAL(cfg); + + /* All pins go into GPIO mode at sleep */ + gpiomode = true; + + /* + * The SLPM_* values are normal values + 1 to allow zero to + * mean "same as normal". + */ + if (slpm_pull) + pull = slpm_pull - 1; + if (slpm_output) + output = slpm_output - 1; + if (slpm_val) + val = slpm_val - 1; + + dev_dbg(nmk_chip->chip.dev, "pin %d: sleep pull %s, dir %s, val %s\n", + pin, + slpm_pull ? pullnames[pull] : "same", + slpm_output ? (output ? "output" : "input") : "same", + slpm_val ? (val ? "high" : "low") : "same"); + } + + dev_dbg(nmk_chip->chip.dev, "pin %d [%#lx]: pull %s, slpm %s (%s%s), lowemi %s\n", + pin, cfg, pullnames[pull], slpmnames[slpm], + output ? "output " : "input", + output ? (val ? "high" : "low") : "", + lowemi ? "on" : "off" ); + + clk_enable(nmk_chip->clk); + bit = pin % NMK_GPIO_PER_CHIP; + if (gpiomode) + /* No glitch when going to GPIO mode */ + __nmk_gpio_set_mode(nmk_chip, bit, NMK_GPIO_ALT_GPIO); + if (output) + __nmk_gpio_make_output(nmk_chip, bit, val); + else { + __nmk_gpio_make_input(nmk_chip, bit); + __nmk_gpio_set_pull(nmk_chip, bit, pull); + } + /* TODO: isn't this only applicable on output pins? */ + __nmk_gpio_set_lowemi(nmk_chip, bit, lowemi); + + __nmk_gpio_set_slpm(nmk_chip, bit, slpm); + clk_disable(nmk_chip->clk); + return 0; +} + +static struct pinconf_ops nmk_pinconf_ops = { + .pin_config_get = nmk_pin_config_get, + .pin_config_set = nmk_pin_config_set, +}; + static struct pinctrl_desc nmk_pinctrl_desc = { .name = "pinctrl-nomadik", .pctlops = &nmk_pinctrl_ops, .pmxops = &nmk_pinmux_ops, + .confops = &nmk_pinconf_ops, .owner = THIS_MODULE, };