diff options
author | Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> | 2012-03-30 06:58:47 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2012-04-02 10:31:23 +0200 |
commit | 8d8d6f6ac930c6056952fa28d0da7431d47c08af (patch) | |
tree | d9257847bb3d3efad24cd155aebb30bca4161a0e /arch/arm/mach-at91/gpio.c | |
parent | 28bdc0e3dafaf59df908f6271d28a976817d81bb (diff) | |
download | barebox-8d8d6f6ac930c6056952fa28d0da7431d47c08af.tar.gz barebox-8d8d6f6ac930c6056952fa28d0da7431d47c08af.tar.xz |
ARM: at91/pio: add new PIO3 features
This patch adds the support for new PIO controller found on some at91sam SOCs.
- more peripheral multiplexing
- more features to configure on a PIO (pull-down, Schmitt trigger, debouncer)
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'arch/arm/mach-at91/gpio.c')
-rw-r--r-- | arch/arm/mach-at91/gpio.c | 129 |
1 files changed, 127 insertions, 2 deletions
diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c index 06da5af2f8..ef2d20e650 100644 --- a/arch/arm/mach-at91/gpio.c +++ b/arch/arm/mach-at91/gpio.c @@ -26,11 +26,20 @@ #include <errno.h> #include <io.h> #include <mach/gpio.h> +#include <mach/io.h> +#include <mach/cpu.h> #include <gpio.h> static int gpio_banks; +static int cpu_has_pio3; static struct at91_gpio_bank *gpio; +/* + * Functionnality can change with newer chips + */ + + + static inline void __iomem *pin_to_controller(unsigned pin) { pin -= PIN_BASE; @@ -77,7 +86,14 @@ int at91_set_A_periph(unsigned pin, int use_pullup) __raw_writel(mask, pio + PIO_IDR); __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR)); - __raw_writel(mask, pio + PIO_ASR); + if (cpu_has_pio3) { + __raw_writel(__raw_readl(pio + PIO_ABCDSR1) & ~mask, + pio + PIO_ABCDSR1); + __raw_writel(__raw_readl(pio + PIO_ABCDSR2) & ~mask, + pio + PIO_ABCDSR2); + } else { + __raw_writel(mask, pio + PIO_ASR); + } __raw_writel(mask, pio + PIO_PDR); return 0; } @@ -96,13 +112,60 @@ int at91_set_B_periph(unsigned pin, int use_pullup) __raw_writel(mask, pio + PIO_IDR); __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR)); - __raw_writel(mask, pio + PIO_BSR); + if (cpu_has_pio3) { + __raw_writel(__raw_readl(pio + PIO_ABCDSR1) | mask, + pio + PIO_ABCDSR1); + __raw_writel(__raw_readl(pio + PIO_ABCDSR2) & ~mask, + pio + PIO_ABCDSR2); + } else { + __raw_writel(mask, pio + PIO_BSR); + } __raw_writel(mask, pio + PIO_PDR); return 0; } EXPORT_SYMBOL(at91_set_B_periph); /* + * mux the pin to the "C" internal peripheral role. + */ +int at91_set_C_periph(unsigned pin, int use_pullup) +{ + void __iomem *pio = pin_to_controller(pin); + unsigned mask = pin_to_mask(pin); + + if (!pio || !cpu_has_pio3) + return -EINVAL; + + __raw_writel(mask, pio + PIO_IDR); + __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR)); + __raw_writel(__raw_readl(pio + PIO_ABCDSR1) & ~mask, pio + PIO_ABCDSR1); + __raw_writel(__raw_readl(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2); + __raw_writel(mask, pio + PIO_PDR); + return 0; +} +EXPORT_SYMBOL(at91_set_C_periph); + +/* + * mux the pin to the "C" internal peripheral role. + */ +int at91_set_D_periph(unsigned pin, int use_pullup) +{ + void __iomem *pio = pin_to_controller(pin); + unsigned mask = pin_to_mask(pin); + + if (!pio || !cpu_has_pio3) + return -EINVAL; + + __raw_writel(mask, pio + PIO_IDR); + __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR)); + __raw_writel(__raw_readl(pio + PIO_ABCDSR1) | mask, pio + PIO_ABCDSR1); + __raw_writel(__raw_readl(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2); + __raw_writel(mask, pio + PIO_PDR); + return 0; +} +EXPORT_SYMBOL(at91_set_D_periph); + +/* * mux the pin to the gpio controller (instead of "A" or "B" peripheral), and * configure it for an input. */ @@ -153,12 +216,37 @@ int at91_set_deglitch(unsigned pin, int is_on) if (!pio) return -EINVAL; + + if (cpu_has_pio3 && is_on) + __raw_writel(mask, pio + PIO_IFSCDR); __raw_writel(mask, pio + (is_on ? PIO_IFER : PIO_IFDR)); return 0; } EXPORT_SYMBOL(at91_set_deglitch); /* + * enable/disable the debounce filter; + */ +int at91_set_debounce(unsigned pin, int is_on, int div) +{ + void __iomem *pio = pin_to_controller(pin); + unsigned mask = pin_to_mask(pin); + + if (!pio || !cpu_has_pio3) + return -EINVAL; + + if (is_on) { + __raw_writel(mask, pio + PIO_IFSCER); + __raw_writel(div & PIO_SCDR_DIV, pio + PIO_SCDR); + __raw_writel(mask, pio + PIO_IFER); + } else { + __raw_writel(mask, pio + PIO_IFDR); + } + return 0; +} +EXPORT_SYMBOL(at91_set_debounce); + +/* * enable/disable the multi-driver; This is only valid for output and * allows the output pin to run as an open collector output. */ @@ -176,6 +264,41 @@ int at91_set_multi_drive(unsigned pin, int is_on) EXPORT_SYMBOL(at91_set_multi_drive); /* + * enable/disable the pull-down. + * If pull-up already enabled while calling the function, we disable it. + */ +int at91_set_pulldown(unsigned pin, int is_on) +{ + void __iomem *pio = pin_to_controller(pin); + unsigned mask = pin_to_mask(pin); + + if (!pio || !cpu_has_pio3) + return -EINVAL; + + /* Disable pull-up anyway */ + __raw_writel(mask, pio + PIO_PUDR); + __raw_writel(mask, pio + (is_on ? PIO_PPDER : PIO_PPDDR)); + return 0; +} +EXPORT_SYMBOL(at91_set_pulldown); + +/* + * disable Schmitt trigger + */ +int at91_disable_schmitt_trig(unsigned pin) +{ + void __iomem *pio = pin_to_controller(pin); + unsigned mask = pin_to_mask(pin); + + if (!pio || !cpu_has_pio3) + return -EINVAL; + + __raw_writel(__raw_readl(pio + PIO_SCHMITT) | mask, pio + PIO_SCHMITT); + return 0; +} +EXPORT_SYMBOL(at91_disable_schmitt_trig); + +/* * assuming the pin is muxed as a gpio output, set its value. */ int at91_set_gpio_value(unsigned pin, int value) @@ -245,5 +368,7 @@ int at91_gpio_init(struct at91_gpio_bank *data, int nr_banks) clk_enable(data->clock); } + cpu_has_pio3 = cpu_is_at91sam9x5(); + return 0; } |