From e7171feff3a65c0b79acc1626e3b745cdc7c43f3 Mon Sep 17 00:00:00 2001 From: Marek Roszko Date: Tue, 7 Jan 2014 01:53:05 -0500 Subject: [PATCH] pinctrl: at91: add drive strength config options The SAMA5 and SAMA92x5, SAM9G25 and SAM9G35 and others implement the ability to select the output drive strength for pins. The configuration typically allows low, medium and high power modes with predefined current limits. This patch reserves 3 bits in the pinctrl config(bits 5,6 and 7) for drive strength. The first bit enables setting the drive strength, the other two bits(6,7) set the drive strength to the specified level which is dependent on the chip. i.e. A9s: 00 = high 01 = medium 10 = low 11 = reserved/undefined the A5 does 00 = low 01 = low 10 = medium 11 = high Signed-off-by: Marek Roszko --- arch/arm/mach-at91/include/mach/at91_pio.h | 9 +++++ drivers/pinctrl/pinctrl-at91.c | 39 +++++++++++++++++++++- 2 files changed, 47 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 732b11c37f1a68..97c53e81853622 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 */ +#if defined(CONFIG_SOC_SAMA5D3) + #define PIO_DRIVER1 0x118 /* Drive Strength Register 1 */ + #define PIO_DRIVER2 0x11C /* Drive Strength Register 2 */ +#else + //SAMA9x5,SAM9G35, SAM9G25 + #define PIO_DRIVER1 0x114 /* Drive Strength Register 1 */ + #define PIO_DRIVER2 0x118 /* Drive Strength Register 2 */ +#endif + #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 9339d425d794e7..6c0364d4cf25b4 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -63,6 +63,9 @@ 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) @@ -149,6 +152,8 @@ struct at91_pinctrl_mux_ops { void (*set_deglitch)(void __iomem *pio, unsigned mask, bool in_on); bool (*get_debounce)(void __iomem *pio, unsigned pin, u32 *div); void (*set_debounce)(void __iomem *pio, unsigned mask, bool in_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 in_on); bool (*get_schmitt_trig)(void __iomem *pio, unsigned pin); @@ -448,6 +453,28 @@ static void at91_mux_pio3_set_debounce(void __iomem *pio, unsigned mask, } } +static int at91_mux_pio3_get_drivestrength(void __iomem *pio, unsigned pin) +{ + unsigned reg = pio + ( (pin > 15) ? PIO_DRIVER2 : PIO_DRIVER1 ); + unsigned shift = ( 2*( (pin >= 16) ? pin - 16 : pin ) ); + + return ( readl_relaxed(reg) >> shift ) & 0x3; +} + +static void at91_mux_pio3_set_drivestrength(void __iomem *pio, unsigned pin, u32 strength) +{ + unsigned shift = ( 2*( (pin >= 16) ? pin - 16 : pin ) ); + unsigned pinmask = 0x3 << shift; + unsigned strmask = strength << shift; + unsigned reg = pio + ( (pin > 15) ? PIO_DRIVER2 : PIO_DRIVER1 ); + + unsigned tmp = readl_relaxed(reg); + tmp &= ~pinmask; + tmp |= strmask; + + writel_relaxed( tmp, reg); +} + static bool at91_mux_pio3_get_pulldown(void __iomem *pio, unsigned pin) { return (__raw_readl(pio + PIO_PPDSR) >> pin) & 0x1; @@ -489,6 +516,8 @@ static struct at91_pinctrl_mux_ops at91sam9x5_ops = { .set_debounce = at91_mux_pio3_set_debounce, .get_pulldown = at91_mux_pio3_get_pulldown, .set_pulldown = at91_mux_pio3_set_pulldown, + .get_drivestrength = at91_mux_pio3_get_drivestrength, + .set_drivestrength = at91_mux_pio3_set_drivestrength, .get_schmitt_trig = at91_mux_pio3_get_schmitt_trig, .disable_schmitt_trig = at91_mux_pio3_disable_schmitt_trig, .irq_type = alt_gpio_irq_type, @@ -717,6 +746,7 @@ static int at91_pinconf_get(struct pinctrl_dev *pctldev, void __iomem *pio; unsigned pin; int div; + int strength; dev_dbg(info->dev, "%s:%d, pin_id=%d, config=0x%lx", __func__, __LINE__, pin_id, *config); pio = pin_to_controller(info, pin_to_bank(pin_id)); @@ -732,6 +762,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)) @@ -746,16 +778,21 @@ static int at91_pinconf_set(struct pinctrl_dev *pctldev, struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); unsigned mask; void __iomem *pio; + unsigned pin; dev_dbg(info->dev, "%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; at91_mux_set_pullup(pio, mask, config & PULL_UP); at91_mux_set_multidrive(pio, mask, config & MULTI_DRIVE); + 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_deglitch) info->ops->set_deglitch(pio, mask, config & DEGLITCH); if (info->ops->set_debounce)