From patchwork Tue Jan 21 06:33:11 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Roszko X-Patchwork-Id: 3515511 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id ABFF89F2E9 for ; Tue, 21 Jan 2014 06:41:11 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 6D8AB2015A for ; Tue, 21 Jan 2014 06:41:10 +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 A6AD420155 for ; Tue, 21 Jan 2014 06:41:08 +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 1W5V0x-000669-Li; Tue, 21 Jan 2014 06:40:47 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1W5V0p-0003b0-Cq; Tue, 21 Jan 2014 06:40:39 +0000 Received: from mail-qc0-x233.google.com ([2607:f8b0:400d:c01::233]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1W5V0d-0003YU-UA for linux-arm-kernel@lists.infradead.org; Tue, 21 Jan 2014 06:40:29 +0000 Received: by mail-qc0-f179.google.com with SMTP id e16so6836458qcx.10 for ; Mon, 20 Jan 2014 22:40:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=m7qpMkq8tunUJJ1oPKT7rF6GNR0yQxnG3k2s+GN6bHQ=; b=MHIt26Yt+4Kb1n8xo/MOfIZonnmoig/3KCc9oHedoZt5ke/6cYzplql+9M2Uz19MJR yMuSu1auz2XdndQrgxRqDymhWJYdYOPwULKCZ3z2I6d8NVuxUyZ5Rga1K/bVYNxcVM25 IMrnepcaCLWvBhDPaAGdKcQvOwHFbaq/rl6ul/mIDbwJ5aNn1vbs+6MES5H9C8jtX3XH YN87jwUVBPORdPWG42q8yLDGECdcttv07bMb+Uyy3bwXHhkRlNzskbriLjbqxtg7P/cz CcPPCO2Mxuwb9678Lo1n9td3KQRIhrpAybRtYDWGdOVOwpjc+R+bZXlMtivdD8M9ZDZu Kh1g== X-Received: by 10.140.88.112 with SMTP id s103mr32651348qgd.47.1390286012407; Mon, 20 Jan 2014 22:33:32 -0800 (PST) Received: from localhost.localdomain (ool-18e4a8f6.dyn.optonline.net. [24.228.168.246]) by mx.google.com with ESMTPSA id d7sm5347786qam.5.2014.01.20.22.33.31 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 20 Jan 2014 22:33:31 -0800 (PST) From: Marek Roszko To: plagnioj@jcrosoft.com, nicolas.ferre@atmel.com, linux-arm-kernel@lists.infradead.org Subject: [PATCH] pinctrl:at91:add drive strength configuration Date: Tue, 21 Jan 2014 01:33:11 -0500 Message-Id: <1390285991-1634-1-git-send-email-mark.roszko@gmail.com> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <20140121060637.GP9558@ns203013.ovh.net> References: <20140121060637.GP9558@ns203013.ovh.net> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140121_014028_116701_2B9B3AB7 X-CRM114-Status: GOOD ( 20.15 ) X-Spam-Score: -2.0 (--) Cc: Marek Roszko 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: , MIME-Version: 1.0 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 The SAMA5 and most SAM9xGs(baring a few exceptions like the SAM945G) have drive control registers that allow configuring the output current of the gpio pins between three predefined levels of low,medium and high drive. This patch adds four new dt-bindings that allow setting the strength via the device tree. Added set/get drive strength to pinctrl ops table. A sama5d3-gpio of id entry was made to set the set/get drive strength function for the sam5d3s which unforunately have different register addresses and strength-to-value map than the sam9s. Added PIO_DRIVER1/2 defines in at91_pio.h prefixed with the target SoC. Acked-by: Jean-Christophe PLAGNIOL-VILLARD --- arch/arm/boot/dts/sama5d3.dtsi | 10 +-- arch/arm/mach-at91/include/mach/at91_pio.h | 7 ++ drivers/pinctrl/pinctrl-at91.c | 131 +++++++++++++++++++++++++++- include/dt-bindings/pinctrl/at91.h | 5 ++ 4 files changed, 147 insertions(+), 6 deletions(-) diff --git a/arch/arm/boot/dts/sama5d3.dtsi b/arch/arm/boot/dts/sama5d3.dtsi index 5cdaba4..5576330 100644 --- a/arch/arm/boot/dts/sama5d3.dtsi +++ b/arch/arm/boot/dts/sama5d3.dtsi @@ -619,7 +619,7 @@ pioA: gpio@fffff200 { - compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio"; + compatible = "atmel,sama5d3-gpio", "atmel,at91rm9200-gpio"; reg = <0xfffff200 0x100>; interrupts = <6 IRQ_TYPE_LEVEL_HIGH 1>; #gpio-cells = <2>; @@ -629,7 +629,7 @@ }; pioB: gpio@fffff400 { - compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio"; + compatible = "atmel,sama5d3-gpio", "atmel,at91rm9200-gpio"; reg = <0xfffff400 0x100>; interrupts = <7 IRQ_TYPE_LEVEL_HIGH 1>; #gpio-cells = <2>; @@ -639,7 +639,7 @@ }; pioC: gpio@fffff600 { - compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio"; + compatible = "atmel,sama5d3-gpio", "atmel,at91rm9200-gpio"; reg = <0xfffff600 0x100>; interrupts = <8 IRQ_TYPE_LEVEL_HIGH 1>; #gpio-cells = <2>; @@ -649,7 +649,7 @@ }; pioD: gpio@fffff800 { - compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio"; + compatible = "atmel,sama5d3-gpio", "atmel,at91rm9200-gpio"; reg = <0xfffff800 0x100>; interrupts = <9 IRQ_TYPE_LEVEL_HIGH 1>; #gpio-cells = <2>; @@ -659,7 +659,7 @@ }; pioE: gpio@fffffa00 { - compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio"; + compatible = "atmel,sama5d3-gpio", "atmel,at91rm9200-gpio"; reg = <0xfffffa00 0x100>; interrupts = <10 IRQ_TYPE_LEVEL_HIGH 1>; #gpio-cells = <2>; diff --git a/arch/arm/mach-at91/include/mach/at91_pio.h b/arch/arm/mach-at91/include/mach/at91_pio.h index 732b11c..b1e6380 100644 --- a/arch/arm/mach-at91/include/mach/at91_pio.h +++ b/arch/arm/mach-at91/include/mach/at91_pio.h @@ -66,6 +66,13 @@ #define PIO_FRLHSR 0xd8 /* Fall/Rise - Low/High Status Register */ #define PIO_SCHMITT 0x100 /* Schmitt Trigger Register */ + +#define SAMA5D3_PIO_DRIVER1 0x118 /*PIO Driver 1 register offset*/ +#define SAMA5D3_PIO_DRIVER2 0x11C /*PIO Driver 2 register offset*/ + +#define AT91SAM9X5_PIO_DRIVER1 0x114 /*PIO Driver 1 register offset*/ +#define AT91SAM9X5_PIO_DRIVER2 0x118 /*PIO Driver 2 register offset*/ + #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..d79e085 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -62,10 +62,21 @@ static int gpio_banks; #define DEGLITCH (1 << 2) #define PULL_DOWN (1 << 3) #define DIS_SCHMIT (1 << 4) +#define DRIVE_STRENGTH_SHIFT 5 +#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_DEFAULT (0x0 << 5) +#define DRIVE_STRENGTH_LOW (0x1 << 5) +#define DRIVE_STRENGTH_MED (0x2 << 5) +#define DRIVE_STRENGTH_HI (0x3 << 5) + + +#define DRIVE_STRENGTH_MASK 0x3 +#define NUM_PINS_PER_DIVIDED_REGS 16 + /** * struct at91_pmx_func - describes AT91 pinmux functions * @name: the name of this specific function @@ -148,6 +159,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); + unsigned (*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); @@ -319,6 +332,24 @@ static unsigned pin_to_mask(unsigned int pin) return 1 << pin; } +static inline int two_bit_pin_value_shift(unsigned pin) +{ + return 2*((pin >= NUM_PINS_PER_DIVIDED_REGS) + ? pin - NUM_PINS_PER_DIVIDED_REGS : pin); +} + +static unsigned sama5d3_get_drive_register(unsigned int pin) +{ + return (pin > NUM_PINS_PER_DIVIDED_REGS-1) + ? SAMA5D3_PIO_DRIVER2: SAMA5D3_PIO_DRIVER1; +} + +static unsigned at91sam9x5_get_drive_register(unsigned int pin) +{ + return (pin > NUM_PINS_PER_DIVIDED_REGS-1) + ? AT91SAM9X5_PIO_DRIVER2: AT91SAM9X5_PIO_DRIVER1; +} + static void at91_mux_disable_interrupt(void __iomem *pio, unsigned mask) { writel_relaxed(mask, pio + PIO_IDR); @@ -462,6 +493,73 @@ 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 inline u32 read_drive_strength(void __iomem *reg, unsigned pin) +{ + unsigned tmp = __raw_readl(reg); + tmp = tmp >> two_bit_pin_value_shift(pin) + + return tmp & DRIVE_STRENGTH_MASK; +} + +static unsigned at91_mux_sama5d3_get_drivestrength(void __iomem *pio, unsigned pin) +{ + unsigned tmp = read_drive_strength(pio + sama5d3_get_drive_register(pin), pin); + + /*value of 0 = low, all other values are 1 to 1*/ + if (!tmp) + tmp = DRIVE_STRENGTH_LOW; + + return tmp; +} + +static unsigned at91_mux_sam9x5_get_drivestrength(void __iomem *pio, unsigned pin) +{ + unsigned tmp = read_drive_strength(pio + at91sam9x5_get_drive_register(pin), pin); + + /* + * inverse the setting for dt defines + * 0 = hi, 1 = med, 2 = low, 3 = rsvd + */ + tmp = DRIVE_STRENGTH_HI - tmp; + + return tmp; +} + +static void set_drive_strength(void __iomem *reg, unsigned pin, u32 strength) +{ + unsigned tmp = __raw_readl(reg); + + tmp &= ~(DRIVE_STRENGTH_MASK << two_bit_pin_value_shift(pin)); + tmp |= strength << two_bit_pin_value_shift(pin); + + __raw_writel(tmp, reg); +} + +static void at91_mux_sama5d3_set_drivestrength(void __iomem *pio, unsigned pin, + u32 setting) +{ + /* do nothing if setting is zero */ + if (!setting) + return; + + /* strength is 1 to 1 with setting for SAMA5 */ + set_drive_strength(pio + sama5d3_get_drive_register(pin), pin, setting); +} + +static void at91_mux_sam9x5_set_drivestrength(void __iomem *pio, unsigned pin, + u32 setting) +{ + /* do nothing if setting is zero */ + if (!setting) + return; + + /* strength is inverse on SAM9s, 0 = hi, 1 = med, 2 = low, 3 = rsvd */ + setting = DRIVE_STRENGTH_HI - setting; + + set_drive_strength(pio + at91sam9x5_get_drive_register(pin), pin, setting); +} + + 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 +589,27 @@ 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_sam9x5_get_drivestrength, + .set_drivestrength = at91_mux_sam9x5_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, + .disable_schmitt_trig = at91_mux_pio3_disable_schmitt_trig, + .irq_type = alt_gpio_irq_type, +}; + +static struct at91_pinctrl_mux_ops sama5d3_ops = { + .get_periph = at91_mux_pio3_get_periph, + .mux_A_periph = at91_mux_pio3_set_A_periph, + .mux_B_periph = at91_mux_pio3_set_B_periph, + .mux_C_periph = at91_mux_pio3_set_C_periph, + .mux_D_periph = at91_mux_pio3_set_D_periph, + .get_deglitch = at91_mux_pio3_get_deglitch, + .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_sama5d3_get_drivestrength, + .set_drivestrength = at91_mux_sama5d3_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, @@ -498,6 +617,7 @@ static struct at91_pinctrl_mux_ops at91sam9x5_ops = { .irq_type = alt_gpio_irq_type, }; + static void at91_pin_dbg(const struct device *dev, const struct at91_pmx_pin *pin) { if (pin->mux) { @@ -736,6 +856,9 @@ 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 +876,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 +885,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 +898,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) + 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) @@ -1551,6 +1679,7 @@ static void at91_gpio_probe_fixup(void) static struct of_device_id at91_gpio_of_match[] = { { .compatible = "atmel,at91sam9x5-gpio", .data = &at91sam9x5_ops, }, + { .compatible = "atmel,sama5d3-gpio", .data = &sama5d3_ops, }, { .compatible = "atmel,at91rm9200-gpio", .data = &at91rm9200_ops }, { /* sentinel */ } }; diff --git a/include/dt-bindings/pinctrl/at91.h b/include/dt-bindings/pinctrl/at91.h index 0fee6ff..af71ebb 100644 --- a/include/dt-bindings/pinctrl/at91.h +++ b/include/dt-bindings/pinctrl/at91.h @@ -20,6 +20,11 @@ #define AT91_PINCTRL_PULL_UP_DEGLITCH (AT91_PINCTRL_PULL_UP | AT91_PINCTRL_DEGLITCH) +#define AT91_PINCTRL_DRIVE_STRENGTH_DEFAULT (0x0 << 5) +#define AT91_PINCTRL_DRIVE_STRENGTH_LOW (0x1 << 5) +#define AT91_PINCTRL_DRIVE_STRENGTH_MED (0x2 << 5) +#define AT91_PINCTRL_DRIVE_STRENGTH_HI (0x3 << 5) + #define AT91_PIOA 0 #define AT91_PIOB 1 #define AT91_PIOC 2