From patchwork Tue Jan 21 01:07:50 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Roszko X-Patchwork-Id: 3514951 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 2B6EBC02DC for ; Tue, 21 Jan 2014 01:08:31 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id E529D20125 for ; Tue, 21 Jan 2014 01:08:29 +0000 (UTC) Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 9167720109 for ; Tue, 21 Jan 2014 01:08:28 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1W5PpI-000524-7x; Tue, 21 Jan 2014 01:08:24 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1W5PpF-0000KM-Vb; Tue, 21 Jan 2014 01:08:21 +0000 Received: from mail-qc0-x230.google.com ([2607:f8b0:400d:c01::230]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1W5PpC-0000K2-A5 for linux-arm-kernel@lists.infradead.org; Tue, 21 Jan 2014 01:08:20 +0000 Received: by mail-qc0-f176.google.com with SMTP id e16so6464478qcx.21 for ; Mon, 20 Jan 2014 17:07:55 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=message-id:subject:from:to:cc:date:content-type:mime-version :content-transfer-encoding; bh=+Ls6QNPDE6PmjIbwJKWVoCLsHIVEXqDEmtdL1ETo0tA=; b=V9kM+ILPebNMWMFo1BkHJcGf5pyV2njhljn7n1Xb6e6PGo9EDs/NyqC6Eq6B2djVk+ izQzsF8OytiUPOs1YQ7G4UmsOlKZWVElF2Ddz07NLiUreQ8EJlHHkWHS2GFhchsh5iBO 4rIf+0/Yi54dnetr+hdveh+ftj5PQ0iM4Nl3p9rOD5bkcqHIaRVASQMFL1+KuhImNt8U 5OH4daNOuweXkdajUa9i2FL1VmoPsSDOhcKdWmfwO6makNSCdb3j9ALbNt0zMKSl66JX g+a3+Uj6iIi3iQbWyrDChLj/lcCqsey5OZbZBgyC/7Ow7O/ZMyazkbvsAqmwSIkj90Qf XdMw== X-Received: by 10.140.101.104 with SMTP id t95mr30981145qge.106.1390266475612; Mon, 20 Jan 2014 17:07:55 -0800 (PST) Received: from [10.0.2.15] (ool-18e4a8f6.dyn.optonline.net. [24.228.168.246]) by mx.google.com with ESMTPSA id js9sm2923484qeb.9.2014.01.20.17.07.54 for (version=SSLv3 cipher=RC4-SHA bits=128/128); Mon, 20 Jan 2014 17:07:54 -0800 (PST) Message-ID: <1390266470.26159.1.camel@bb> Subject: pinctrl: at91: drive strength control From: Marek Roszko To: plagnioj@jcrosoft.com, Nicolas Ferre Date: Mon, 20 Jan 2014 20:07:50 -0500 X-Mailer: Evolution 3.4.4-3 Mime-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140120_200818_432732_09732832 X-CRM114-Status: GOOD ( 19.04 ) X-Spam-Score: -2.0 (--) Cc: linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.6 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Hello Nick and Jean-Christophe, I submit a idea/patch for comments. The current pintctrl driver is missing the ability to set the drive strength in the SAMA5D3s and a few of the SAM9s. A little feature I myself need for the SAMA5D3s because somebody let an analog engineer do the hardware design. Issues with this patch I need help with: 1. Atmel for some reason shifted the PIO_DRIVER1 and PIO_DRIVER2 registers by one register address between the SAM9 chips and the SAMA5D3s i.e. this is the SAM9s #define PIO_DRIVER1_V1 0x114 #define PIO_DRIVER2_V1 0x118 this is the SAMA5D3s #define PIO_DRIVER1_V2 0x118 #define PIO_DRIVER2_V2 0x11C 2. Atmel changed the meaning of value of "low", "medium" and "high" drive strengths between the two sets of chips as well. SAM9s do: 00 = high 01 = medium 10 = low 11 = reserved/undefined SAMA5D3s do: 00 = low 01 = low 10 = medium 11 = high 3. The SAM9G25, SAM9G35 have the PIO_DRIVER but the SAM9G45 does not have the PIO_DRIVER register as an example of how oddly the behavior doesn't appear everywhere. This could also be because the datasheets for the G45 and G46 are not updated to the new style while the others already have been? Side note: The SAMA5D3 datasheet says the default drive strength is "low" with register values 0x00000000, in reality the default is "medium" with 0xAAAAAAAA as the default value. Confirmed with the JLINK debugger and by Atmel support. Not an real issue, just a note when testing. So the only simple way I see is to #ifdef the SOC type/chip. There's probably better far better ways I don't know. --- arch/arm/mach-at91/include/mach/at91_pio.h | 9 +++++ drivers/pinctrl/pinctrl-at91.c | 54 +++++++++++++++++++++++++++- include/dt-bindings/pinctrl/at91.h | 13 +++++++ 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-at91/include/mach/at91_pio.h b/arch/arm/mach-at91/include/mach/at91_pio.h index 732b11c..28e8801 100644 --- a/arch/arm/mach-at91/include/mach/at91_pio.h +++ b/arch/arm/mach-at91/include/mach/at91_pio.h @@ -66,6 +66,15 @@ #define PIO_FRLHSR 0xd8 /* Fall/Rise - Low/High Status Register */ #define PIO_SCHMITT 0x100 /* Schmitt Trigger Register */ +/* + * SoC Specific PIO Address Offsets + */ +#define PIO_DRIVER1_V1 0x114 +#define PIO_DRIVER2_V1 0x118 + +#define PIO_DRIVER1_V2 0x118 +#define PIO_DRIVER2_V2 0x11C + #define ABCDSR_PERIPH_A 0x0 #define ABCDSR_PERIPH_B 0x1 #define ABCDSR_PERIPH_C 0x2 diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index a7549c4..ccf456e 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -62,10 +62,37 @@ static int gpio_banks; #define DEGLITCH (1 << 2) #define PULL_DOWN (1 << 3) #define DIS_SCHMIT (1 << 4) +#define SET_DRIVE_STRENGTH (1 << 5) +#define DRIVE_STRENGTH_SHIFT 6 +#define DRIVE_STRENGTH (0x3 << DRIVE_STRENGTH_SHIFT) #define DEBOUNCE (1 << 16) #define DEBOUNCE_VAL_SHIFT 17 #define DEBOUNCE_VAL (0x3fff << DEBOUNCE_VAL_SHIFT) +#define DRIVE_STRENGTH_MASK 0x3 + +#define NUM_PINS_PER_DRIVE_STRENGTH_REG 16 + +#define TWO_BIT_PIN_TO_SHIFT(pin)\ + (2*((pin >= NUM_PINS_PER_DRIVE_STRENGTH_REG) ? \ + pin - NUM_PINS_PER_DRIVE_STRENGTH_REG : pin)) + +#define TWO_BIT_PIN_TO_MASK(pin)\ + (DRIVE_STRENGTH_MASK << TWO_BIT_PIN_TO_SHIFT(pin)) + +#if defined(CONFIG_SOC_SAMA5D3) + #define PIO_DRIVER1 PIO_DRIVER1_V2 /* Drive Strength Register 1 */ + #define PIO_DRIVER2 PIO_DRIVER2_V2 /* Drive Strength Register 2 */ +#elif defined(CONFIG_SOC_AT91SAM9X5) || defined(SOC_AT91SAM9G35) || defined(SOC_AT91SAM9G25) + #define PIO_DRIVER1 PIO_DRIVER1_V1 /* Drive Strength Register 1 */ + #define PIO_DRIVER2 PIO_DRIVER2_V1 /* Drive Strength Register 2 */ +#endif + +#if defined(PIO_DRIVER1) && defined(PIO_DRIVER2) + #define PIO_DRIVER(pin)\ + ((pin > NUM_PINS_PER_DRIVE_STRENGTH_REG-1) ? PIO_DRIVER2 : PIO_DRIVER1) +#endif + /** * struct at91_pmx_func - describes AT91 pinmux functions * @name: the name of this specific function @@ -148,6 +175,8 @@ struct at91_pinctrl_mux_ops { void (*set_deglitch)(void __iomem *pio, unsigned mask, bool is_on); bool (*get_debounce)(void __iomem *pio, unsigned pin, u32 *div); void (*set_debounce)(void __iomem *pio, unsigned mask, bool is_on, u32 div); + int (*get_drivestrength)(void __iomem *pio, unsigned pin); + void (*set_drivestrength)(void __iomem *pio, unsigned pin, u32 strength); bool (*get_pulldown)(void __iomem *pio, unsigned pin); void (*set_pulldown)(void __iomem *pio, unsigned mask, bool is_on); bool (*get_schmitt_trig)(void __iomem *pio, unsigned pin); @@ -462,6 +491,20 @@ static void at91_mux_pio3_set_pulldown(void __iomem *pio, unsigned mask, bool is __raw_writel(mask, pio + (is_on ? PIO_PPDER : PIO_PPDDR)); } +static int at91_mux_pio3_get_drivestrength(void __iomem *pio, unsigned pin) +{ + return (__raw_readl(pio + PIO_DRIVER(pin)) >> TWO_BIT_PIN_TO_SHIFT(pin)) & DRIVE_STRENGTH_MASK; +} + +static void at91_mux_pio3_set_drivestrength(void __iomem *pio, unsigned pin, u32 strength) +{ + unsigned tmp = __raw_readl(pio + PIO_DRIVER(pin)); + tmp &= ~TWO_BIT_PIN_TO_MASK(pin); + tmp |= strength << TWO_BIT_PIN_TO_SHIFT(pin); + + __raw_writel(tmp, pio + PIO_DRIVER(pin)); +} + static void at91_mux_pio3_disable_schmitt_trig(void __iomem *pio, unsigned mask) { __raw_writel(__raw_readl(pio + PIO_SCHMITT) | mask, pio + PIO_SCHMITT); @@ -491,6 +534,8 @@ static struct at91_pinctrl_mux_ops at91sam9x5_ops = { .set_deglitch = at91_mux_pio3_set_deglitch, .get_debounce = at91_mux_pio3_get_debounce, .set_debounce = at91_mux_pio3_set_debounce, + .get_drivestrength = at91_mux_pio3_get_drivestrength, + .set_drivestrength = at91_mux_pio3_set_drivestrength, .get_pulldown = at91_mux_pio3_get_pulldown, .set_pulldown = at91_mux_pio3_set_pulldown, .get_schmitt_trig = at91_mux_pio3_get_schmitt_trig, @@ -736,6 +781,8 @@ static int at91_pinconf_get(struct pinctrl_dev *pctldev, *config |= DEGLITCH; if (info->ops->get_debounce && info->ops->get_debounce(pio, pin, &div)) *config |= DEBOUNCE | (div << DEBOUNCE_VAL_SHIFT); + if (info->ops->get_drivestrength) + *config |= DRIVE_STRENGTH | (info->ops->get_drivestrength(pio, pin) << DRIVE_STRENGTH_SHIFT); if (info->ops->get_pulldown && info->ops->get_pulldown(pio, pin)) *config |= PULL_DOWN; if (info->ops->get_schmitt_trig && info->ops->get_schmitt_trig(pio, pin)) @@ -753,6 +800,7 @@ static int at91_pinconf_set(struct pinctrl_dev *pctldev, void __iomem *pio; int i; unsigned long config; + unsigned pin; for (i = 0; i < num_configs; i++) { config = configs[i]; @@ -761,7 +809,8 @@ static int at91_pinconf_set(struct pinctrl_dev *pctldev, "%s:%d, pin_id=%d, config=0x%lx", __func__, __LINE__, pin_id, config); pio = pin_to_controller(info, pin_to_bank(pin_id)); - mask = pin_to_mask(pin_id % MAX_NB_GPIO_PER_BANK); + pin = pin_id % MAX_NB_GPIO_PER_BANK; + mask = pin_to_mask(pin); if (config & PULL_UP && config & PULL_DOWN) return -EINVAL; @@ -773,6 +822,9 @@ static int at91_pinconf_set(struct pinctrl_dev *pctldev, if (info->ops->set_debounce) info->ops->set_debounce(pio, mask, config & DEBOUNCE, (config & DEBOUNCE_VAL) >> DEBOUNCE_VAL_SHIFT); + if (info->ops->set_drivestrength && config & SET_DRIVE_STRENGTH) + info->ops->set_drivestrength(pio, pin, + (config & DRIVE_STRENGTH) >> DRIVE_STRENGTH_SHIFT); if (info->ops->set_pulldown) info->ops->set_pulldown(pio, mask, config & PULL_DOWN); if (info->ops->disable_schmitt_trig && config & DIS_SCHMIT) diff --git a/include/dt-bindings/pinctrl/at91.h b/include/dt-bindings/pinctrl/at91.h index 0fee6ff..78621a4 100644 --- a/include/dt-bindings/pinctrl/at91.h +++ b/include/dt-bindings/pinctrl/at91.h @@ -20,6 +20,19 @@ #define AT91_PINCTRL_PULL_UP_DEGLITCH (AT91_PINCTRL_PULL_UP | AT91_PINCTRL_DEGLITCH) +#define AT91_PINCTRL_SET_DRIVE_STRENGTH (1 << 5) + +#if defined(CONFIG_SOC_SAMA5D3) + #define AT91_PINCTRL_DRIVE_STRENGTH_LOW (0x2 << 6) + #define AT91_PINCTRL_DRIVE_STRENGTH_MED (0x1 << 6) + #define AT91_PINCTRL_DRIVE_STRENGTH_HI (0x0 << 6) +#elif defined(CONFIG_SOC_AT91SAM9X5) || defined(SOC_AT91SAM9G35) || defined(SOC_AT91SAM9G25) + #define AT91_PINCTRL_DRIVE_STRENGTH_LOW (0x1 << 6) + #define AT91_PINCTRL_DRIVE_STRENGTH_MED (0x2 << 6) + #define AT91_PINCTRL_DRIVE_STRENGTH_HI (0x3 << 6) +#endif + + #define AT91_PIOA 0 #define AT91_PIOB 1 #define AT91_PIOC 2