From d1b95607e1dde59e2ffae661732c8da34aba445c Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 13 Mar 2009 15:17:32 +0100 Subject: [ARM] pxa: add missing pin function for CS2 on GPIO1 Signed-off-by: Daniel Mack Signed-off-by: Eric Miao --- arch/arm/mach-pxa/include/mach/mfp-pxa300.h | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/arm/mach-pxa/include') diff --git a/arch/arm/mach-pxa/include/mach/mfp-pxa300.h b/arch/arm/mach-pxa/include/mach/mfp-pxa300.h index bc1fb33a6e7..928fbef9cbf 100644 --- a/arch/arm/mach-pxa/include/mach/mfp-pxa300.h +++ b/arch/arm/mach-pxa/include/mach/mfp-pxa300.h @@ -41,6 +41,7 @@ #endif /* Chip Select */ +#define GPIO1_nCS2 MFP_CFG(GPIO1, AF1) #define GPIO2_nCS3 MFP_CFG(GPIO2, AF1) /* AC97 */ -- cgit v1.2.3-70-g09d2 From 1efb71809fd47bc19b3ce05080e1d5085a8dfab1 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Thu, 19 Mar 2009 15:45:19 +0100 Subject: [ARM] pxa: add pxa320 missing pin function for CS2 on GPIO3 Signed-off-by: Daniel Mack Signed-off-by: Eric Miao --- arch/arm/mach-pxa/include/mach/mfp-pxa320.h | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/arm/mach-pxa/include') diff --git a/arch/arm/mach-pxa/include/mach/mfp-pxa320.h b/arch/arm/mach-pxa/include/mach/mfp-pxa320.h index 67f8385ea54..80a0da9e092 100644 --- a/arch/arm/mach-pxa/include/mach/mfp-pxa320.h +++ b/arch/arm/mach-pxa/include/mach/mfp-pxa320.h @@ -38,6 +38,7 @@ #define GPIO17_2_GPIO MFP_CFG(GPIO17_2, AF0) /* Chip Select */ +#define GPIO3_nCS2 MFP_CFG(GPIO3, AF1) #define GPIO4_nCS3 MFP_CFG(GPIO4, AF1) /* AC97 */ -- cgit v1.2.3-70-g09d2 From 5c0dbb8fc2b36619684cbb7486491ecac950a595 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 13 Mar 2009 16:37:08 +0100 Subject: [ARM] pxa: rename colibri.c to colibri-pxa270.c Namespace cleanup: rename colibri.c to colibri-pxa270.c and change some names in colibri.h. Signed-off-by: Daniel Mack Signed-off-by: Eric Miao --- arch/arm/mach-pxa/Kconfig | 2 +- arch/arm/mach-pxa/Makefile | 2 +- arch/arm/mach-pxa/colibri-pxa270.c | 145 +++++++++++++++++++++++++++++++ arch/arm/mach-pxa/colibri.c | 137 ----------------------------- arch/arm/mach-pxa/include/mach/colibri.h | 17 ++-- 5 files changed, 153 insertions(+), 150 deletions(-) create mode 100644 arch/arm/mach-pxa/colibri-pxa270.c delete mode 100644 arch/arm/mach-pxa/colibri.c (limited to 'arch/arm/mach-pxa/include') diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index d13282d773a..fd21bba6217 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig @@ -262,7 +262,7 @@ config MACH_EXEDA select PXA27x config MACH_COLIBRI - bool "Toradex Colibri PX27x" + bool "Toradex Colibri PXA270" select PXA27x config MACH_ZYLONITE diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index 8da8e63d048..fbbda93b73a 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile @@ -35,7 +35,7 @@ obj-$(CONFIG_MACH_MAINSTONE) += mainstone.o obj-$(CONFIG_MACH_MP900C) += mp900.o obj-$(CONFIG_ARCH_PXA_IDP) += idp.o obj-$(CONFIG_MACH_TRIZEPS4) += trizeps4.o -obj-$(CONFIG_MACH_COLIBRI) += colibri.o +obj-$(CONFIG_MACH_COLIBRI) += colibri-pxa270.o obj-$(CONFIG_MACH_H5000) += h5000.o obj-$(CONFIG_PXA_SHARP_C7xx) += corgi.o sharpsl_pm.o corgi_pm.o obj-$(CONFIG_PXA_SHARP_Cxx00) += spitz.o sharpsl_pm.o spitz_pm.o diff --git a/arch/arm/mach-pxa/colibri-pxa270.c b/arch/arm/mach-pxa/colibri-pxa270.c new file mode 100644 index 00000000000..01bcfaae75b --- /dev/null +++ b/arch/arm/mach-pxa/colibri-pxa270.c @@ -0,0 +1,145 @@ +/* + * linux/arch/arm/mach-pxa/colibri-pxa270.c + * + * Support for Toradex PXA270 based Colibri module + * Daniel Mack + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "generic.h" +#include "devices.h" + +/* + * GPIO configuration + */ +static mfp_cfg_t colibri_pxa270_pin_config[] __initdata = { + GPIO78_nCS_2, /* Ethernet CS */ + GPIO114_GPIO, /* Ethernet IRQ */ +}; + +/* + * NOR flash + */ +static struct mtd_partition colibri_partitions[] = { + { + .name = "Bootloader", + .offset = 0x00000000, + .size = 0x00040000, + .mask_flags = MTD_WRITEABLE /* force read-only */ + }, { + .name = "Kernel", + .offset = 0x00040000, + .size = 0x00400000, + .mask_flags = 0 + }, { + .name = "Rootfs", + .offset = 0x00440000, + .size = MTDPART_SIZ_FULL, + .mask_flags = 0 + } +}; + +static struct physmap_flash_data colibri_flash_data[] = { + { + .width = 4, /* bankwidth in bytes */ + .parts = colibri_partitions, + .nr_parts = ARRAY_SIZE(colibri_partitions) + } +}; + +static struct resource colibri_pxa270_flash_resource = { + .start = PXA_CS0_PHYS, + .end = PXA_CS0_PHYS + SZ_32M - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device colibri_pxa270_flash_device = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = colibri_flash_data, + }, + .resource = &colibri_pxa270_flash_resource, + .num_resources = 1, +}; + +/* + * DM9000 Ethernet + */ +#if defined(CONFIG_DM9000) +static struct resource dm9000_resources[] = { + [0] = { + .start = COLIBRI_PXA270_ETH_PHYS, + .end = COLIBRI_PXA270_ETH_PHYS + 3, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = COLIBRI_PXA270_ETH_PHYS + 4, + .end = COLIBRI_PXA270_ETH_PHYS + 4 + 500, + .flags = IORESOURCE_MEM, + }, + [2] = { + .start = COLIBRI_PXA270_ETH_IRQ, + .end = COLIBRI_PXA270_ETH_IRQ, + .flags = IORESOURCE_IRQ | IRQF_TRIGGER_RISING, + }, +}; + +static struct platform_device dm9000_device = { + .name = "dm9000", + .id = -1, + .num_resources = ARRAY_SIZE(dm9000_resources), + .resource = dm9000_resources, +}; +#endif /* CONFIG_DM9000 */ + +static struct platform_device *colibri_pxa270_devices[] __initdata = { + &colibri_pxa270_flash_device, +#if defined(CONFIG_DM9000) + &dm9000_device, +#endif +}; + +static void __init colibri_pxa270_init(void) +{ + pxa2xx_mfp_config(ARRAY_AND_SIZE(colibri_pxa270_pin_config)); + platform_add_devices(ARRAY_AND_SIZE(colibri_pxa270_devices)); +} + +MACHINE_START(COLIBRI, "Toradex Colibri PXA270") + .phys_io = 0x40000000, + .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, + .boot_params = COLIBRI_SDRAM_BASE + 0x100, + .init_machine = colibri_pxa270_init, + .map_io = pxa_map_io, + .init_irq = pxa27x_init_irq, + .timer = &pxa_timer, +MACHINE_END + diff --git a/arch/arm/mach-pxa/colibri.c b/arch/arm/mach-pxa/colibri.c deleted file mode 100644 index 26493ae2889..00000000000 --- a/arch/arm/mach-pxa/colibri.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * linux/arch/arm/mach-pxa/colibri.c - * - * Support for Toradex PXA27x based Colibri module - * Daniel Mack - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "generic.h" -#include "devices.h" - -static unsigned long colibri_pin_config[] __initdata = { - GPIO78_nCS_2, /* Ethernet CS */ - GPIO114_GPIO, /* Ethernet IRQ */ -}; - -/* - * Flash - */ -static struct mtd_partition colibri_partitions[] = { - { - .name = "Bootloader", - .offset = 0x00000000, - .size = 0x00040000, - .mask_flags = MTD_WRITEABLE /* force read-only */ - }, { - .name = "Kernel", - .offset = 0x00040000, - .size = 0x00400000, - .mask_flags = 0 - }, { - .name = "Rootfs", - .offset = 0x00440000, - .size = MTDPART_SIZ_FULL, - .mask_flags = 0 - } -}; - -static struct physmap_flash_data colibri_flash_data[] = { - { - .width = 4, /* bankwidth in bytes */ - .parts = colibri_partitions, - .nr_parts = ARRAY_SIZE(colibri_partitions) - } -}; - -static struct resource flash_resource = { - .start = PXA_CS0_PHYS, - .end = PXA_CS0_PHYS + SZ_32M - 1, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device flash_device = { - .name = "physmap-flash", - .id = 0, - .dev = { - .platform_data = colibri_flash_data, - }, - .resource = &flash_resource, - .num_resources = 1, -}; - -/* - * DM9000 Ethernet - */ -static struct resource dm9000_resources[] = { - [0] = { - .start = COLIBRI_ETH_PHYS, - .end = COLIBRI_ETH_PHYS + 3, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = COLIBRI_ETH_PHYS + 4, - .end = COLIBRI_ETH_PHYS + 4 + 500, - .flags = IORESOURCE_MEM, - }, - [2] = { - .start = COLIBRI_ETH_IRQ, - .end = COLIBRI_ETH_IRQ, - .flags = IORESOURCE_IRQ | IRQF_TRIGGER_RISING, - }, -}; - -static struct platform_device dm9000_device = { - .name = "dm9000", - .id = -1, - .num_resources = ARRAY_SIZE(dm9000_resources), - .resource = dm9000_resources, -}; - -static struct platform_device *colibri_devices[] __initdata = { - &flash_device, - &dm9000_device, -}; - -static void __init colibri_init(void) -{ - pxa2xx_mfp_config(ARRAY_AND_SIZE(colibri_pin_config)); - - platform_add_devices(colibri_devices, ARRAY_SIZE(colibri_devices)); -} - -MACHINE_START(COLIBRI, "Toradex Colibri PXA27x") - .phys_io = 0x40000000, - .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, - .boot_params = COLIBRI_SDRAM_BASE + 0x100, - .init_machine = colibri_init, - .map_io = pxa_map_io, - .init_irq = pxa27x_init_irq, - .timer = &pxa_timer, -MACHINE_END diff --git a/arch/arm/mach-pxa/include/mach/colibri.h b/arch/arm/mach-pxa/include/mach/colibri.h index 2ae373fb567..c7c99d07881 100644 --- a/arch/arm/mach-pxa/include/mach/colibri.h +++ b/arch/arm/mach-pxa/include/mach/colibri.h @@ -2,18 +2,13 @@ #define _COLIBRI_H_ /* physical memory regions */ -#define COLIBRI_FLASH_PHYS (PXA_CS0_PHYS) /* Flash region */ -#define COLIBRI_ETH_PHYS (PXA_CS2_PHYS) /* Ethernet DM9000 region */ #define COLIBRI_SDRAM_BASE 0xa0000000 /* SDRAM region */ -/* virtual memory regions */ -#define COLIBRI_DISK_VIRT 0xF0000000 /* Disk On Chip region */ - -/* size of flash */ -#define COLIBRI_FLASH_SIZE 0x02000000 /* Flash size 32 MB */ - -/* Ethernet Controller Davicom DM9000 */ -#define GPIO_DM9000 114 -#define COLIBRI_ETH_IRQ IRQ_GPIO(GPIO_DM9000) +#define COLIBRI_PXA270_FLASH_PHYS (PXA_CS0_PHYS) /* Flash region */ +#define COLIBRI_PXA270_ETH_PHYS (PXA_CS2_PHYS) /* Ethernet */ +#define COLIBRI_PXA270_ETH_IRQ_GPIO 114 +#define COLIBRI_PXA270_ETH_IRQ \ + gpio_to_irq(mfp_to_gpio(COLIBRI_PXA270_ETH_IRQ_GPIO)) #endif /* _COLIBRI_H_ */ + -- cgit v1.2.3-70-g09d2 From 5fc9f9a1deefc9999af721fba249cd58ee7e273b Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 13 Mar 2009 16:37:09 +0100 Subject: [ARM] pxa: add basic support for Colibri PXA300 module This patch add basic support for Toradex' Colibri PXA300 module. Ethernet is enabled conditionally, depdending on CONFIG_AX88796. Signed-off-by: Daniel Mack Signed-off-by: Eric Miao --- arch/arm/mach-pxa/Kconfig | 5 ++ arch/arm/mach-pxa/Makefile | 1 + arch/arm/mach-pxa/colibri-pxa300.c | 99 ++++++++++++++++++++++++++++++++ arch/arm/mach-pxa/include/mach/colibri.h | 17 ++++++ 4 files changed, 122 insertions(+) create mode 100644 arch/arm/mach-pxa/colibri-pxa300.c (limited to 'arch/arm/mach-pxa/include') diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index fd21bba6217..1a93888c68a 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig @@ -265,6 +265,11 @@ config MACH_COLIBRI bool "Toradex Colibri PXA270" select PXA27x +config MACH_COLIBRI300 + bool "Toradex Colibri PXA300" + select PXA3xx + select CPU_PXA300 + config MACH_ZYLONITE bool "PXA3xx Development Platform (aka Zylonite)" select PXA3xx diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index fbbda93b73a..df6534b49e3 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile @@ -36,6 +36,7 @@ obj-$(CONFIG_MACH_MP900C) += mp900.o obj-$(CONFIG_ARCH_PXA_IDP) += idp.o obj-$(CONFIG_MACH_TRIZEPS4) += trizeps4.o obj-$(CONFIG_MACH_COLIBRI) += colibri-pxa270.o +obj-$(CONFIG_MACH_COLIBRI300) += colibri-pxa300.o obj-$(CONFIG_MACH_H5000) += h5000.o obj-$(CONFIG_PXA_SHARP_C7xx) += corgi.o sharpsl_pm.o corgi_pm.o obj-$(CONFIG_PXA_SHARP_Cxx00) += spitz.o sharpsl_pm.o spitz_pm.o diff --git a/arch/arm/mach-pxa/colibri-pxa300.c b/arch/arm/mach-pxa/colibri-pxa300.c new file mode 100644 index 00000000000..b271e028da3 --- /dev/null +++ b/arch/arm/mach-pxa/colibri-pxa300.c @@ -0,0 +1,99 @@ +/* + * arch/arm/mach-pxa/colibri-pxa300.c + * + * Support for Toradex PXA300 based Colibri module + * Daniel Mack + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "generic.h" +#include "devices.h" + +/* + * GPIO configuration + */ +static mfp_cfg_t colibri_pxa300_pin_config[] __initdata = { + GPIO1_nCS2, /* AX88796 chip select */ + GPIO26_GPIO | MFP_PULL_HIGH, /* AX88796 IRQ */ +}; + +#if defined(CONFIG_AX88796) +/* + * Asix AX88796 Ethernet + */ +static struct ax_plat_data colibri_asix_platdata = { + .flags = AXFLG_MAC_FROMDEV, + .wordlength = 2, + .dcr_val = 0x01, + .rcr_val = 0x0e, + .gpoc_val = 0x19 +}; + +static struct resource colibri_asix_resource[] = { + [0] = { + .start = PXA3xx_CS2_PHYS, + .end = PXA3xx_CS2_PHYS + (0x18 * 0x2) - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = PXA3xx_CS2_PHYS + (1 << 11), + .end = PXA3xx_CS2_PHYS + (1 << 11) + 0x3fff, + .flags = IORESOURCE_MEM, + }, + [2] = { + .start = COLIBRI_PXA300_ETH_IRQ, + .end = COLIBRI_PXA300_ETH_IRQ, + .flags = IORESOURCE_IRQ + } +}; + +static struct platform_device asix_device = { + .name = "ax88796", + .id = 0, + .num_resources = ARRAY_SIZE(colibri_asix_resource), + .resource = colibri_asix_resource, + .dev = { + .platform_data = &colibri_asix_platdata + } +}; +#endif /* CONFIG_AX88796 */ + +static struct platform_device *colibri_pxa300_devices[] __initdata = { +#if defined(CONFIG_AX88796) + &asix_device +#endif +}; + +static void __init colibri_pxa300_init(void) +{ + set_irq_type(COLIBRI_PXA300_ETH_IRQ, IRQ_TYPE_EDGE_FALLING); + pxa3xx_mfp_config(ARRAY_AND_SIZE(colibri_pxa300_pin_config)); + platform_add_devices(ARRAY_AND_SIZE(colibri_pxa300_devices)); +} + +MACHINE_START(COLIBRI300, "Toradex Colibri PXA300") + .phys_io = 0x40000000, + .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, + .boot_params = COLIBRI_SDRAM_BASE + 0x100, + .init_machine = colibri_pxa300_init, + .map_io = pxa_map_io, + .init_irq = pxa3xx_init_irq, + .timer = &pxa_timer, +MACHINE_END + diff --git a/arch/arm/mach-pxa/include/mach/colibri.h b/arch/arm/mach-pxa/include/mach/colibri.h index c7c99d07881..e295e8df8d6 100644 --- a/arch/arm/mach-pxa/include/mach/colibri.h +++ b/arch/arm/mach-pxa/include/mach/colibri.h @@ -1,14 +1,31 @@ #ifndef _COLIBRI_H_ #define _COLIBRI_H_ +/* + * common settings for all modules + */ /* physical memory regions */ #define COLIBRI_SDRAM_BASE 0xa0000000 /* SDRAM region */ +/* definitions for Colibri PXA270 */ + #define COLIBRI_PXA270_FLASH_PHYS (PXA_CS0_PHYS) /* Flash region */ #define COLIBRI_PXA270_ETH_PHYS (PXA_CS2_PHYS) /* Ethernet */ #define COLIBRI_PXA270_ETH_IRQ_GPIO 114 #define COLIBRI_PXA270_ETH_IRQ \ gpio_to_irq(mfp_to_gpio(COLIBRI_PXA270_ETH_IRQ_GPIO)) +/* definitions for Colibri PXA300 */ + +#define COLIBRI_PXA300_ETH_IRQ_GPIO 26 +#define COLIBRI_PXA300_ETH_IRQ \ + gpio_to_irq(mfp_to_gpio(COLIBRI_PXA300_ETH_IRQ_GPIO)) + +/* definitions for Colibri PXA320 */ + +#define COLIBRI_PXA320_ETH_IRQ_GPIO 36 +#define COLIBRI_PXA320_ETH_IRQ \ + gpio_to_irq(mfp_to_gpio(COLIBRI_PXA320_ETH_IRQ_GPIO)) + #endif /* _COLIBRI_H_ */ -- cgit v1.2.3-70-g09d2 From acb3655973de30cb74549986e5e118a374967702 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 23 Mar 2009 02:04:17 +0100 Subject: [ARM] pxa: Refactor Colibri board support code - Move common function for all Colibri PXA3xx boards to the newly added colibri-pxa3xx.c - Drop some unnecessary defines from colibri.h - Make Kconfig reflect the fact that code for colibri 300 module does also work for the 310 model - Give up on the huge pin config table which was messed up with lots of #ifdefs and switch over to locally defined tables for configured functions Cc: Matthias Meier Signed-off-by: Daniel Mack Signed-off-by: Eric Miao --- arch/arm/mach-pxa/Kconfig | 2 +- arch/arm/mach-pxa/Makefile | 2 +- arch/arm/mach-pxa/colibri-pxa300.c | 116 ++++++++++--------------------- arch/arm/mach-pxa/colibri-pxa3xx.c | 75 ++++++++++++++++++++ arch/arm/mach-pxa/include/mach/colibri.h | 18 ++--- 5 files changed, 119 insertions(+), 94 deletions(-) create mode 100644 arch/arm/mach-pxa/colibri-pxa3xx.c (limited to 'arch/arm/mach-pxa/include') diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index 1a93888c68a..142fd59a40b 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig @@ -266,7 +266,7 @@ config MACH_COLIBRI select PXA27x config MACH_COLIBRI300 - bool "Toradex Colibri PXA300" + bool "Toradex Colibri PXA300/310" select PXA3xx select CPU_PXA300 diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index df6534b49e3..772569383b3 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile @@ -36,7 +36,7 @@ obj-$(CONFIG_MACH_MP900C) += mp900.o obj-$(CONFIG_ARCH_PXA_IDP) += idp.o obj-$(CONFIG_MACH_TRIZEPS4) += trizeps4.o obj-$(CONFIG_MACH_COLIBRI) += colibri-pxa270.o -obj-$(CONFIG_MACH_COLIBRI300) += colibri-pxa300.o +obj-$(CONFIG_MACH_COLIBRI300) += colibri-pxa3xx.o colibri-pxa300.o obj-$(CONFIG_MACH_H5000) += h5000.o obj-$(CONFIG_PXA_SHARP_C7xx) += corgi.o sharpsl_pm.o corgi_pm.o obj-$(CONFIG_PXA_SHARP_Cxx00) += spitz.o sharpsl_pm.o spitz_pm.o diff --git a/arch/arm/mach-pxa/colibri-pxa300.c b/arch/arm/mach-pxa/colibri-pxa300.c index a5c1f72d88c..14ef9bf094f 100644 --- a/arch/arm/mach-pxa/colibri-pxa300.c +++ b/arch/arm/mach-pxa/colibri-pxa300.c @@ -1,8 +1,10 @@ /* * arch/arm/mach-pxa/colibri-pxa300.c * - * Support for Toradex PXA300 based Colibri module + * Support for Toradex PXA300/310 based Colibri module + * * Daniel Mack + * Matthias Meier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -16,40 +18,19 @@ #include #include +#include #include #include #include #include -#include #include #include "generic.h" #include "devices.h" -/* - * GPIO configuration - */ -static mfp_cfg_t colibri_pxa300_pin_config[] __initdata = { - GPIO1_nCS2, /* AX88796 chip select */ - GPIO26_GPIO | MFP_PULL_HIGH, /* AX88796 IRQ */ - -#if defined(CONFIG_MMC_PXA) || defined(CONFIG_MMC_PXA_MODULE) - GPIO7_MMC1_CLK, - GPIO14_MMC1_CMD, - GPIO3_MMC1_DAT0, - GPIO4_MMC1_DAT1, - GPIO5_MMC1_DAT2, - GPIO6_MMC1_DAT3, -#endif - -#if defined (CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) - GPIO0_2_USBH_PEN, - GPIO1_2_USBH_PWR, -#endif -}; - #if defined(CONFIG_AX88796) +#define COLIBRI_ETH_IRQ_GPIO mfp_to_gpio(GPIO26_GPIO) /* * Asix AX88796 Ethernet */ @@ -65,8 +46,8 @@ static struct resource colibri_asix_resource[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = COLIBRI_PXA300_ETH_IRQ, - .end = COLIBRI_PXA300_ETH_IRQ, + .start = gpio_to_irq(COLIBRI_ETH_IRQ_GPIO), + .end = gpio_to_irq(COLIBRI_ETH_IRQ_GPIO), .flags = IORESOURCE_IRQ } }; @@ -80,82 +61,57 @@ static struct platform_device asix_device = { .platform_data = &colibri_asix_platdata } }; -#endif /* CONFIG_AX88796 */ - -static struct platform_device *colibri_pxa300_devices[] __initdata = { -#if defined(CONFIG_AX88796) - &asix_device -#endif -}; - -#if defined(CONFIG_MMC_PXA) || defined(CONFIG_MMC_PXA_MODULE) -#define MMC_DETECT_PIN mfp_to_gpio(MFP_PIN_GPIO13) - -static int colibri_pxa300_mci_init(struct device *dev, - irq_handler_t colibri_mmc_detect_int, - void *data) -{ - int ret; - - ret = gpio_request(MMC_DETECT_PIN, "mmc card detect"); - if (ret) - return ret; - - gpio_direction_input(MMC_DETECT_PIN); - ret = request_irq(gpio_to_irq(MMC_DETECT_PIN), colibri_mmc_detect_int, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - "MMC card detect", data); - if (ret) { - gpio_free(MMC_DETECT_PIN); - return ret; - } - - return 0; -} - -static void colibri_pxa300_mci_exit(struct device *dev, void *data) -{ - free_irq(MMC_DETECT_PIN, data); - gpio_free(gpio_to_irq(MMC_DETECT_PIN)); -} -static struct pxamci_platform_data colibri_pxa300_mci_platform_data = { - .detect_delay = 20, - .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, - .init = colibri_pxa300_mci_init, - .exit = colibri_pxa300_mci_exit, +static mfp_cfg_t colibri_pxa300_eth_pin_config[] __initdata = { + GPIO1_nCS2, /* AX88796 chip select */ + GPIO26_GPIO | MFP_PULL_HIGH /* AX88796 IRQ */ }; -static void __init colibri_pxa300_init_mmc(void) +static void __init colibri_pxa300_init_eth(void) { - pxa_set_mci_info(&colibri_pxa300_mci_platform_data); + pxa3xx_mfp_config(ARRAY_AND_SIZE(colibri_pxa300_eth_pin_config)); + set_irq_type(gpio_to_irq(COLIBRI_ETH_IRQ_GPIO), IRQ_TYPE_EDGE_FALLING); + platform_device_register(&asix_device); } - #else -static inline void colibri_pxa300_init_mmc(void) {} -#endif /* CONFIG_MMC_PXA */ +static inline void __init colibri_pxa300_init_eth(void) {} +#endif /* CONFIG_AX88796 */ #if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) +static mfp_cfg_t colibri_pxa300_usb_pin_config[] __initdata = { + GPIO0_2_USBH_PEN, + GPIO1_2_USBH_PWR, +}; + static struct pxaohci_platform_data colibri_pxa300_ohci_info = { .port_mode = PMM_GLOBAL_MODE, .flags = ENABLE_PORT1 | POWER_CONTROL_LOW | POWER_SENSE_LOW, }; -static void __init colibri_pxa300_init_ohci(void) +void __init colibri_pxa300_init_ohci(void) { + pxa3xx_mfp_config(ARRAY_AND_SIZE(colibri_pxa300_usb_pin_config)); pxa_set_ohci_info(&colibri_pxa300_ohci_info); } #else static inline void colibri_pxa300_init_ohci(void) {} #endif /* CONFIG_USB_OHCI_HCD || CONFIG_USB_OHCI_HCD_MODULE */ -static void __init colibri_pxa300_init(void) +static mfp_cfg_t colibri_pxa300_mmc_pin_config[] __initdata = { + GPIO7_MMC1_CLK, + GPIO14_MMC1_CMD, + GPIO3_MMC1_DAT0, + GPIO4_MMC1_DAT1, + GPIO5_MMC1_DAT2, + GPIO6_MMC1_DAT3, +}; + +void __init colibri_pxa300_init(void) { - set_irq_type(COLIBRI_PXA300_ETH_IRQ, IRQ_TYPE_EDGE_FALLING); - pxa3xx_mfp_config(ARRAY_AND_SIZE(colibri_pxa300_pin_config)); - platform_add_devices(ARRAY_AND_SIZE(colibri_pxa300_devices)); - colibri_pxa300_init_mmc(); + colibri_pxa300_init_eth(); colibri_pxa300_init_ohci(); + colibri_pxa3xx_init_mmc(ARRAY_AND_SIZE(colibri_pxa300_mmc_pin_config), + mfp_to_gpio(MFP_PIN_GPIO13)); } MACHINE_START(COLIBRI300, "Toradex Colibri PXA300") diff --git a/arch/arm/mach-pxa/colibri-pxa3xx.c b/arch/arm/mach-pxa/colibri-pxa3xx.c new file mode 100644 index 00000000000..cbaa8424fc8 --- /dev/null +++ b/arch/arm/mach-pxa/colibri-pxa3xx.c @@ -0,0 +1,75 @@ +/* + * arch/arm/mach-pxa/colibri-pxa3xx.c + * + * Common functions for all Toradex PXA3xx modules + * + * Daniel Mack + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "generic.h" +#include "devices.h" + +#if defined(CONFIG_MMC_PXA) || defined(CONFIG_MMC_PXA_MODULE) +static int mmc_detect_pin; + +static int colibri_pxa3xx_mci_init(struct device *dev, + irq_handler_t colibri_mmc_detect_int, + void *data) +{ + int ret; + + ret = gpio_request(mmc_detect_pin, "mmc card detect"); + if (ret) + return ret; + + gpio_direction_input(mmc_detect_pin); + ret = request_irq(gpio_to_irq(mmc_detect_pin), colibri_mmc_detect_int, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "MMC card detect", data); + if (ret) { + gpio_free(mmc_detect_pin); + return ret; + } + + return 0; +} + +static void colibri_pxa3xx_mci_exit(struct device *dev, void *data) +{ + free_irq(mmc_detect_pin, data); + gpio_free(gpio_to_irq(mmc_detect_pin)); +} + +static struct pxamci_platform_data colibri_pxa3xx_mci_platform_data = { + .detect_delay = 20, + .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, + .init = colibri_pxa3xx_mci_init, + .exit = colibri_pxa3xx_mci_exit, +}; + +void __init colibri_pxa3xx_init_mmc(mfp_cfg_t *pins, int len, int detect_pin) +{ + pxa3xx_mfp_config(pins, len); + mmc_detect_pin = detect_pin; + pxa_set_mci_info(&colibri_pxa3xx_mci_platform_data); +} +#endif /* CONFIG_MMC_PXA || CONFIG_MMC_PXA_MODULE */ + diff --git a/arch/arm/mach-pxa/include/mach/colibri.h b/arch/arm/mach-pxa/include/mach/colibri.h index e295e8df8d6..0becf6215c1 100644 --- a/arch/arm/mach-pxa/include/mach/colibri.h +++ b/arch/arm/mach-pxa/include/mach/colibri.h @@ -4,6 +4,12 @@ * common settings for all modules */ +#if defined(CONFIG_MMC_PXA) || defined(CONFIG_MMC_PXA_MODULE) +extern void colibri_pxa3xx_init_mmc(mfp_cfg_t *pins, int len, int detect_pin); +#else +static inline void colibri_pxa3xx_init_mmc(mfp_cfg_t *, int, int) {} +#endif + /* physical memory regions */ #define COLIBRI_SDRAM_BASE 0xa0000000 /* SDRAM region */ @@ -15,17 +21,5 @@ #define COLIBRI_PXA270_ETH_IRQ \ gpio_to_irq(mfp_to_gpio(COLIBRI_PXA270_ETH_IRQ_GPIO)) -/* definitions for Colibri PXA300 */ - -#define COLIBRI_PXA300_ETH_IRQ_GPIO 26 -#define COLIBRI_PXA300_ETH_IRQ \ - gpio_to_irq(mfp_to_gpio(COLIBRI_PXA300_ETH_IRQ_GPIO)) - -/* definitions for Colibri PXA320 */ - -#define COLIBRI_PXA320_ETH_IRQ_GPIO 36 -#define COLIBRI_PXA320_ETH_IRQ \ - gpio_to_irq(mfp_to_gpio(COLIBRI_PXA320_ETH_IRQ_GPIO)) - #endif /* _COLIBRI_H_ */ -- cgit v1.2.3-70-g09d2 From 91fcfb908d62038c3c2cdecb7fb8aa2c98cb70a2 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 23 Mar 2009 02:04:19 +0100 Subject: [ARM] pxa: Add Colibri LCD functions This adds LCD functions for Colibri PXA300 and Colibri PXA320 and configures a LQ043T3DX02 panel. Original-code-by: Matthias Meier Signed-off-by: Daniel Mack Signed-off-by: Eric Miao --- arch/arm/mach-pxa/colibri-pxa300.c | 40 +++++++++++++++++++++++++++ arch/arm/mach-pxa/colibri-pxa320.c | 39 +++++++++++++++++++++++++++ arch/arm/mach-pxa/colibri-pxa3xx.c | 46 ++++++++++++++++++++++++++++++++ arch/arm/mach-pxa/include/mach/colibri.h | 6 +++++ 4 files changed, 131 insertions(+) (limited to 'arch/arm/mach-pxa/include') diff --git a/arch/arm/mach-pxa/colibri-pxa300.c b/arch/arm/mach-pxa/colibri-pxa300.c index 14ef9bf094f..2858a597870 100644 --- a/arch/arm/mach-pxa/colibri-pxa300.c +++ b/arch/arm/mach-pxa/colibri-pxa300.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "generic.h" #include "devices.h" @@ -106,10 +107,49 @@ static mfp_cfg_t colibri_pxa300_mmc_pin_config[] __initdata = { GPIO6_MMC1_DAT3, }; +#if defined(CONFIG_FB_PXA) || defined(CONFIG_FB_PXA_MODULE) +static mfp_cfg_t colibri_pxa300_lcd_pin_config[] __initdata = { + GPIO54_LCD_LDD_0, + GPIO55_LCD_LDD_1, + GPIO56_LCD_LDD_2, + GPIO57_LCD_LDD_3, + GPIO58_LCD_LDD_4, + GPIO59_LCD_LDD_5, + GPIO60_LCD_LDD_6, + GPIO61_LCD_LDD_7, + GPIO62_LCD_LDD_8, + GPIO63_LCD_LDD_9, + GPIO64_LCD_LDD_10, + GPIO65_LCD_LDD_11, + GPIO66_LCD_LDD_12, + GPIO67_LCD_LDD_13, + GPIO68_LCD_LDD_14, + GPIO69_LCD_LDD_15, + GPIO70_LCD_LDD_16, + GPIO71_LCD_LDD_17, + GPIO62_LCD_CS_N, + GPIO72_LCD_FCLK, + GPIO73_LCD_LCLK, + GPIO74_LCD_PCLK, + GPIO75_LCD_BIAS, + GPIO76_LCD_VSYNC, +}; + +static void __init colibri_pxa300_init_lcd(void) +{ + pxa3xx_mfp_config(ARRAY_AND_SIZE(colibri_pxa300_lcd_pin_config)); +} + +#else +static inline void colibri_pxa300_init_lcd(void) {} +#endif /* CONFIG_FB_PXA || CONFIG_FB_PXA_MODULE */ + void __init colibri_pxa300_init(void) { colibri_pxa300_init_eth(); colibri_pxa300_init_ohci(); + colibri_pxa300_init_lcd(); + colibri_pxa3xx_init_lcd(mfp_to_gpio(GPIO49_GPIO)); colibri_pxa3xx_init_mmc(ARRAY_AND_SIZE(colibri_pxa300_mmc_pin_config), mfp_to_gpio(MFP_PIN_GPIO13)); } diff --git a/arch/arm/mach-pxa/colibri-pxa320.c b/arch/arm/mach-pxa/colibri-pxa320.c index 86cb202847e..b6773674351 100644 --- a/arch/arm/mach-pxa/colibri-pxa320.c +++ b/arch/arm/mach-pxa/colibri-pxa320.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include "generic.h" @@ -108,10 +109,48 @@ static mfp_cfg_t colibri_pxa320_mmc_pin_config[] __initdata = { GPIO21_MMC1_DAT3 }; +#if defined(CONFIG_FB_PXA) || defined(CONFIG_FB_PXA_MODULE) +static mfp_cfg_t colibri_pxa320_lcd_pin_config[] __initdata = { + GPIO6_2_LCD_LDD_0, + GPIO7_2_LCD_LDD_1, + GPIO8_2_LCD_LDD_2, + GPIO9_2_LCD_LDD_3, + GPIO10_2_LCD_LDD_4, + GPIO11_2_LCD_LDD_5, + GPIO12_2_LCD_LDD_6, + GPIO13_2_LCD_LDD_7, + GPIO63_LCD_LDD_8, + GPIO64_LCD_LDD_9, + GPIO65_LCD_LDD_10, + GPIO66_LCD_LDD_11, + GPIO67_LCD_LDD_12, + GPIO68_LCD_LDD_13, + GPIO69_LCD_LDD_14, + GPIO70_LCD_LDD_15, + GPIO71_LCD_LDD_16, + GPIO72_LCD_LDD_17, + GPIO73_LCD_CS_N, + GPIO74_LCD_VSYNC, + GPIO14_2_LCD_FCLK, + GPIO15_2_LCD_LCLK, + GPIO16_2_LCD_PCLK, + GPIO17_2_LCD_BIAS, +}; + +static void __init colibri_pxa320_init_lcd(void) +{ + pxa3xx_mfp_config(ARRAY_AND_SIZE(colibri_pxa320_lcd_pin_config)); +} +#else +static inline void colibri_pxa320_init_lcd(void) {} +#endif + void __init colibri_pxa320_init(void) { colibri_pxa320_init_eth(); colibri_pxa320_init_ohci(); + colibri_pxa320_init_lcd(); + colibri_pxa3xx_init_lcd(mfp_to_gpio(GPIO39_GPIO)); colibri_pxa3xx_init_mmc(ARRAY_AND_SIZE(colibri_pxa320_mmc_pin_config), mfp_to_gpio(MFP_PIN_GPIO28)); } diff --git a/arch/arm/mach-pxa/colibri-pxa3xx.c b/arch/arm/mach-pxa/colibri-pxa3xx.c index cbaa8424fc8..12d0afc54aa 100644 --- a/arch/arm/mach-pxa/colibri-pxa3xx.c +++ b/arch/arm/mach-pxa/colibri-pxa3xx.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "generic.h" #include "devices.h" @@ -73,3 +74,48 @@ void __init colibri_pxa3xx_init_mmc(mfp_cfg_t *pins, int len, int detect_pin) } #endif /* CONFIG_MMC_PXA || CONFIG_MMC_PXA_MODULE */ +#if defined(CONFIG_FB_PXA) || defined(CONFIG_FB_PXA_MODULE) +static int lcd_bl_pin; + +/* + * LCD panel (Sharp LQ043T3DX02) + */ +static void colibri_lcd_backlight(int on) +{ + gpio_set_value(lcd_bl_pin, !!on); +} + +static struct pxafb_mode_info sharp_lq43_mode = { + .pixclock = 101936, + .xres = 480, + .yres = 272, + .bpp = 32, + .depth = 18, + .hsync_len = 41, + .left_margin = 2, + .right_margin = 2, + .vsync_len = 10, + .upper_margin = 2, + .lower_margin = 2, + .sync = 0, + .cmap_greyscale = 0, +}; + +static struct pxafb_mach_info sharp_lq43_info = { + .modes = &sharp_lq43_mode, + .num_modes = 1, + .cmap_inverse = 0, + .cmap_static = 0, + .lcd_conn = LCD_COLOR_TFT_18BPP, + .pxafb_backlight_power = colibri_lcd_backlight, +}; + +void __init colibri_pxa3xx_init_lcd(int bl_pin) +{ + lcd_bl_pin = bl_pin; + gpio_request(bl_pin, "lcd backlight"); + gpio_direction_output(bl_pin, 0); + set_pxa_fb_info(&sharp_lq43_info); +} +#endif + diff --git a/arch/arm/mach-pxa/include/mach/colibri.h b/arch/arm/mach-pxa/include/mach/colibri.h index 0becf6215c1..3f2a01d6a03 100644 --- a/arch/arm/mach-pxa/include/mach/colibri.h +++ b/arch/arm/mach-pxa/include/mach/colibri.h @@ -10,6 +10,12 @@ extern void colibri_pxa3xx_init_mmc(mfp_cfg_t *pins, int len, int detect_pin); static inline void colibri_pxa3xx_init_mmc(mfp_cfg_t *, int, int) {} #endif +#if defined(CONFIG_FB_PXA) || defined(CONFIG_FB_PXA_MODULE) +extern void colibri_pxa3xx_init_lcd(int bl_pin); +#else +static inline void colibri_pxa3xx_init_lcd(int) {} +#endif + /* physical memory regions */ #define COLIBRI_SDRAM_BASE 0xa0000000 /* SDRAM region */ -- cgit v1.2.3-70-g09d2 From bd5ce4332328c1fe473690a86b2e6a4157be038f Mon Sep 17 00:00:00 2001 From: Eric Miao Date: Tue, 20 Jan 2009 12:06:01 +0800 Subject: [ARM] pxa: introduce plat-pxa for PXA common code and add DMA support 1. introduce folder of 'arch/arm/plat-pxa' for common code across different PXA processor families 2. initially moved DMA code into plat-pxa 3. common code in moved into , new processors should implement its own , provide the following required definitions and '#include ' in the end: - DMAC_REGS_VIRT for mapped virtual address of the DMA registers' physical I/O memory Signed-off-by: Eric Miao --- arch/arm/Kconfig | 5 ++ arch/arm/Makefile | 1 + arch/arm/mach-pxa/Makefile | 2 +- arch/arm/mach-pxa/dma.c | 144 ----------------------------------- arch/arm/mach-pxa/include/mach/dma.h | 83 +------------------- arch/arm/plat-pxa/Kconfig | 3 + arch/arm/plat-pxa/Makefile | 6 ++ arch/arm/plat-pxa/dma.c | 144 +++++++++++++++++++++++++++++++++++ arch/arm/plat-pxa/include/plat/dma.h | 85 +++++++++++++++++++++ 9 files changed, 246 insertions(+), 227 deletions(-) delete mode 100644 arch/arm/mach-pxa/dma.c create mode 100644 arch/arm/plat-pxa/Kconfig create mode 100644 arch/arm/plat-pxa/Makefile create mode 100644 arch/arm/plat-pxa/dma.c create mode 100644 arch/arm/plat-pxa/include/plat/dma.h (limited to 'arch/arm/mach-pxa/include') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 12abdd43201..5ba00358e80 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -481,6 +481,7 @@ config ARCH_PXA select GENERIC_TIME select GENERIC_CLOCKEVENTS select TICK_ONESHOT + select PLAT_PXA help Support for Intel/Marvell's PXA2xx/PXA3xx processor line. @@ -618,6 +619,7 @@ source "arch/arm/mach-loki/Kconfig" source "arch/arm/mach-mv78xx0/Kconfig" source "arch/arm/mach-pxa/Kconfig" +source "arch/arm/plat-pxa/Kconfig" source "arch/arm/mach-sa1100/Kconfig" @@ -687,6 +689,9 @@ config PLAT_IOP config PLAT_ORION bool +config PLAT_PXA + bool + source arch/arm/mm/Kconfig config IWMMXT diff --git a/arch/arm/Makefile b/arch/arm/Makefile index e7ef876e574..897f2830bc4 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -109,6 +109,7 @@ ifeq ($(CONFIG_ARCH_SA1100),y) textofs-$(CONFIG_SA1111) := 0x00208000 endif machine-$(CONFIG_ARCH_PXA) := pxa + plat-$(CONFIG_PLAT_PXA) := pxa machine-$(CONFIG_ARCH_L7200) := l7200 machine-$(CONFIG_ARCH_INTEGRATOR) := integrator textofs-$(CONFIG_ARCH_CLPS711X) := 0x00028000 diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index fc96e7d454b..70b46570c5c 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile @@ -3,7 +3,7 @@ # # Common support (must be linked before board specific support) -obj-y += clock.o devices.o generic.o irq.o dma.o \ +obj-y += clock.o devices.o generic.o irq.o \ time.o gpio.o reset.o obj-$(CONFIG_PM) += pm.o sleep.o standby.o diff --git a/arch/arm/mach-pxa/dma.c b/arch/arm/mach-pxa/dma.c deleted file mode 100644 index 01217e01f7d..00000000000 --- a/arch/arm/mach-pxa/dma.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * linux/arch/arm/mach-pxa/dma.c - * - * PXA DMA registration and IRQ dispatching - * - * Author: Nicolas Pitre - * Created: Nov 15, 2001 - * Copyright: MontaVista Software Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -struct dma_channel { - char *name; - pxa_dma_prio prio; - void (*irq_handler)(int, void *); - void *data; -}; - -static struct dma_channel *dma_channels; -static int num_dma_channels; - -int pxa_request_dma (char *name, pxa_dma_prio prio, - void (*irq_handler)(int, void *), - void *data) -{ - unsigned long flags; - int i, found = 0; - - /* basic sanity checks */ - if (!name || !irq_handler) - return -EINVAL; - - local_irq_save(flags); - - do { - /* try grabbing a DMA channel with the requested priority */ - for (i = 0; i < num_dma_channels; i++) { - if ((dma_channels[i].prio == prio) && - !dma_channels[i].name) { - found = 1; - break; - } - } - /* if requested prio group is full, try a hier priority */ - } while (!found && prio--); - - if (found) { - DCSR(i) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; - dma_channels[i].name = name; - dma_channels[i].irq_handler = irq_handler; - dma_channels[i].data = data; - } else { - printk (KERN_WARNING "No more available DMA channels for %s\n", name); - i = -ENODEV; - } - - local_irq_restore(flags); - return i; -} - -void pxa_free_dma (int dma_ch) -{ - unsigned long flags; - - if (!dma_channels[dma_ch].name) { - printk (KERN_CRIT - "%s: trying to free channel %d which is already freed\n", - __func__, dma_ch); - return; - } - - local_irq_save(flags); - DCSR(dma_ch) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; - dma_channels[dma_ch].name = NULL; - local_irq_restore(flags); -} - -static irqreturn_t dma_irq_handler(int irq, void *dev_id) -{ - int i, dint = DINT; - - for (i = 0; i < num_dma_channels; i++) { - if (dint & (1 << i)) { - struct dma_channel *channel = &dma_channels[i]; - if (channel->name && channel->irq_handler) { - channel->irq_handler(i, channel->data); - } else { - /* - * IRQ for an unregistered DMA channel: - * let's clear the interrupts and disable it. - */ - printk (KERN_WARNING "spurious IRQ for DMA channel %d\n", i); - DCSR(i) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; - } - } - } - return IRQ_HANDLED; -} - -int __init pxa_init_dma(int irq, int num_ch) -{ - int i, ret; - - dma_channels = kzalloc(sizeof(struct dma_channel) * num_ch, GFP_KERNEL); - if (dma_channels == NULL) - return -ENOMEM; - - /* dma channel priorities on pxa2xx processors: - * ch 0 - 3, 16 - 19 <--> (0) DMA_PRIO_HIGH - * ch 4 - 7, 20 - 23 <--> (1) DMA_PRIO_MEDIUM - * ch 8 - 15, 24 - 31 <--> (2) DMA_PRIO_LOW - */ - for (i = 0; i < num_ch; i++) { - DCSR(i) = 0; - dma_channels[i].prio = min((i & 0xf) >> 2, DMA_PRIO_LOW); - } - - ret = request_irq(irq, dma_irq_handler, IRQF_DISABLED, "DMA", NULL); - if (ret) { - printk (KERN_CRIT "Wow! Can't register IRQ for DMA\n"); - kfree(dma_channels); - return ret; - } - - num_dma_channels = num_ch; - return 0; -} - -EXPORT_SYMBOL(pxa_request_dma); -EXPORT_SYMBOL(pxa_free_dma); diff --git a/arch/arm/mach-pxa/include/mach/dma.h b/arch/arm/mach-pxa/include/mach/dma.h index b0812f59d3f..5bd55894a48 100644 --- a/arch/arm/mach-pxa/include/mach/dma.h +++ b/arch/arm/mach-pxa/include/mach/dma.h @@ -16,87 +16,6 @@ /* DMA Controller Registers Definitions */ #define DMAC_REGS_VIRT io_p2v(0x40000000) -#define DMAC_REG(x) (*((volatile u32 *)(DMAC_REGS_VIRT + (x)))) - -#define DCSR(n) DMAC_REG((n) << 2) -#define DALGN DMAC_REG(0x00a0) /* DMA Alignment Register */ -#define DINT DMAC_REG(0x00f0) /* DMA Interrupt Register */ -#define DDADR(n) DMAC_REG(0x0200 + ((n) << 4)) -#define DSADR(n) DMAC_REG(0x0204 + ((n) << 4)) -#define DTADR(n) DMAC_REG(0x0208 + ((n) << 4)) -#define DCMD(n) DMAC_REG(0x020c + ((n) << 4)) -#define DRCMR(n) DMAC_REG((((n) < 64) ? 0x0100 : 0x1100) + \ - (((n) & 0x3f) << 2)) - -#define DCSR_RUN (1 << 31) /* Run Bit (read / write) */ -#define DCSR_NODESC (1 << 30) /* No-Descriptor Fetch (read / write) */ -#define DCSR_STOPIRQEN (1 << 29) /* Stop Interrupt Enable (read / write) */ -#define DCSR_REQPEND (1 << 8) /* Request Pending (read-only) */ -#define DCSR_STOPSTATE (1 << 3) /* Stop State (read-only) */ -#define DCSR_ENDINTR (1 << 2) /* End Interrupt (read / write) */ -#define DCSR_STARTINTR (1 << 1) /* Start Interrupt (read / write) */ -#define DCSR_BUSERR (1 << 0) /* Bus Error Interrupt (read / write) */ - -#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx) -#define DCSR_EORIRQEN (1 << 28) /* End of Receive Interrupt Enable (R/W) */ -#define DCSR_EORJMPEN (1 << 27) /* Jump to next descriptor on EOR */ -#define DCSR_EORSTOPEN (1 << 26) /* STOP on an EOR */ -#define DCSR_SETCMPST (1 << 25) /* Set Descriptor Compare Status */ -#define DCSR_CLRCMPST (1 << 24) /* Clear Descriptor Compare Status */ -#define DCSR_CMPST (1 << 10) /* The Descriptor Compare Status */ -#define DCSR_EORINTR (1 << 9) /* The end of Receive */ -#endif - -#define DRCMR_MAPVLD (1 << 7) /* Map Valid (read / write) */ -#define DRCMR_CHLNUM 0x1f /* mask for Channel Number (read / write) */ - -#define DDADR_DESCADDR 0xfffffff0 /* Address of next descriptor (mask) */ -#define DDADR_STOP (1 << 0) /* Stop (read / write) */ - -#define DCMD_INCSRCADDR (1 << 31) /* Source Address Increment Setting. */ -#define DCMD_INCTRGADDR (1 << 30) /* Target Address Increment Setting. */ -#define DCMD_FLOWSRC (1 << 29) /* Flow Control by the source. */ -#define DCMD_FLOWTRG (1 << 28) /* Flow Control by the target. */ -#define DCMD_STARTIRQEN (1 << 22) /* Start Interrupt Enable */ -#define DCMD_ENDIRQEN (1 << 21) /* End Interrupt Enable */ -#define DCMD_ENDIAN (1 << 18) /* Device Endian-ness. */ -#define DCMD_BURST8 (1 << 16) /* 8 byte burst */ -#define DCMD_BURST16 (2 << 16) /* 16 byte burst */ -#define DCMD_BURST32 (3 << 16) /* 32 byte burst */ -#define DCMD_WIDTH1 (1 << 14) /* 1 byte width */ -#define DCMD_WIDTH2 (2 << 14) /* 2 byte width (HalfWord) */ -#define DCMD_WIDTH4 (3 << 14) /* 4 byte width (Word) */ -#define DCMD_LENGTH 0x01fff /* length mask (max = 8K - 1) */ - -/* - * Descriptor structure for PXA's DMA engine - * Note: this structure must always be aligned to a 16-byte boundary. - */ - -typedef struct pxa_dma_desc { - volatile u32 ddadr; /* Points to the next descriptor + flags */ - volatile u32 dsadr; /* DSADR value for the current transfer */ - volatile u32 dtadr; /* DTADR value for the current transfer */ - volatile u32 dcmd; /* DCMD value for the current transfer */ -} pxa_dma_desc; - -typedef enum { - DMA_PRIO_HIGH = 0, - DMA_PRIO_MEDIUM = 1, - DMA_PRIO_LOW = 2 -} pxa_dma_prio; - -/* - * DMA registration - */ - -int __init pxa_init_dma(int irq, int num_ch); - -int pxa_request_dma (char *name, - pxa_dma_prio prio, - void (*irq_handler)(int, void *), - void *data); - -void pxa_free_dma (int dma_ch); +#include #endif /* _ASM_ARCH_DMA_H */ diff --git a/arch/arm/plat-pxa/Kconfig b/arch/arm/plat-pxa/Kconfig new file mode 100644 index 00000000000..b158e98038e --- /dev/null +++ b/arch/arm/plat-pxa/Kconfig @@ -0,0 +1,3 @@ +if PLAT_PXA + +endif diff --git a/arch/arm/plat-pxa/Makefile b/arch/arm/plat-pxa/Makefile new file mode 100644 index 00000000000..dcc3ceaf717 --- /dev/null +++ b/arch/arm/plat-pxa/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for code common across different PXA processor families +# + +obj-y := dma.o + diff --git a/arch/arm/plat-pxa/dma.c b/arch/arm/plat-pxa/dma.c new file mode 100644 index 00000000000..70aeee407f7 --- /dev/null +++ b/arch/arm/plat-pxa/dma.c @@ -0,0 +1,144 @@ +/* + * linux/arch/arm/plat-pxa/dma.c + * + * PXA DMA registration and IRQ dispatching + * + * Author: Nicolas Pitre + * Created: Nov 15, 2001 + * Copyright: MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +struct dma_channel { + char *name; + pxa_dma_prio prio; + void (*irq_handler)(int, void *); + void *data; +}; + +static struct dma_channel *dma_channels; +static int num_dma_channels; + +int pxa_request_dma (char *name, pxa_dma_prio prio, + void (*irq_handler)(int, void *), + void *data) +{ + unsigned long flags; + int i, found = 0; + + /* basic sanity checks */ + if (!name || !irq_handler) + return -EINVAL; + + local_irq_save(flags); + + do { + /* try grabbing a DMA channel with the requested priority */ + for (i = 0; i < num_dma_channels; i++) { + if ((dma_channels[i].prio == prio) && + !dma_channels[i].name) { + found = 1; + break; + } + } + /* if requested prio group is full, try a hier priority */ + } while (!found && prio--); + + if (found) { + DCSR(i) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; + dma_channels[i].name = name; + dma_channels[i].irq_handler = irq_handler; + dma_channels[i].data = data; + } else { + printk (KERN_WARNING "No more available DMA channels for %s\n", name); + i = -ENODEV; + } + + local_irq_restore(flags); + return i; +} + +void pxa_free_dma (int dma_ch) +{ + unsigned long flags; + + if (!dma_channels[dma_ch].name) { + printk (KERN_CRIT + "%s: trying to free channel %d which is already freed\n", + __func__, dma_ch); + return; + } + + local_irq_save(flags); + DCSR(dma_ch) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; + dma_channels[dma_ch].name = NULL; + local_irq_restore(flags); +} + +static irqreturn_t dma_irq_handler(int irq, void *dev_id) +{ + int i, dint = DINT; + + for (i = 0; i < num_dma_channels; i++) { + if (dint & (1 << i)) { + struct dma_channel *channel = &dma_channels[i]; + if (channel->name && channel->irq_handler) { + channel->irq_handler(i, channel->data); + } else { + /* + * IRQ for an unregistered DMA channel: + * let's clear the interrupts and disable it. + */ + printk (KERN_WARNING "spurious IRQ for DMA channel %d\n", i); + DCSR(i) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; + } + } + } + return IRQ_HANDLED; +} + +int __init pxa_init_dma(int irq, int num_ch) +{ + int i, ret; + + dma_channels = kzalloc(sizeof(struct dma_channel) * num_ch, GFP_KERNEL); + if (dma_channels == NULL) + return -ENOMEM; + + /* dma channel priorities on pxa2xx processors: + * ch 0 - 3, 16 - 19 <--> (0) DMA_PRIO_HIGH + * ch 4 - 7, 20 - 23 <--> (1) DMA_PRIO_MEDIUM + * ch 8 - 15, 24 - 31 <--> (2) DMA_PRIO_LOW + */ + for (i = 0; i < num_ch; i++) { + DCSR(i) = 0; + dma_channels[i].prio = min((i & 0xf) >> 2, DMA_PRIO_LOW); + } + + ret = request_irq(irq, dma_irq_handler, IRQF_DISABLED, "DMA", NULL); + if (ret) { + printk (KERN_CRIT "Wow! Can't register IRQ for DMA\n"); + kfree(dma_channels); + return ret; + } + + num_dma_channels = num_ch; + return 0; +} + +EXPORT_SYMBOL(pxa_request_dma); +EXPORT_SYMBOL(pxa_free_dma); diff --git a/arch/arm/plat-pxa/include/plat/dma.h b/arch/arm/plat-pxa/include/plat/dma.h new file mode 100644 index 00000000000..a7b91dc0685 --- /dev/null +++ b/arch/arm/plat-pxa/include/plat/dma.h @@ -0,0 +1,85 @@ +#ifndef __PLAT_DMA_H +#define __PLAT_DMA_H + +#define DMAC_REG(x) (*((volatile u32 *)(DMAC_REGS_VIRT + (x)))) + +#define DCSR(n) DMAC_REG((n) << 2) +#define DALGN DMAC_REG(0x00a0) /* DMA Alignment Register */ +#define DINT DMAC_REG(0x00f0) /* DMA Interrupt Register */ +#define DDADR(n) DMAC_REG(0x0200 + ((n) << 4)) +#define DSADR(n) DMAC_REG(0x0204 + ((n) << 4)) +#define DTADR(n) DMAC_REG(0x0208 + ((n) << 4)) +#define DCMD(n) DMAC_REG(0x020c + ((n) << 4)) +#define DRCMR(n) DMAC_REG((((n) < 64) ? 0x0100 : 0x1100) + \ + (((n) & 0x3f) << 2)) + +#define DCSR_RUN (1 << 31) /* Run Bit (read / write) */ +#define DCSR_NODESC (1 << 30) /* No-Descriptor Fetch (read / write) */ +#define DCSR_STOPIRQEN (1 << 29) /* Stop Interrupt Enable (read / write) */ +#define DCSR_REQPEND (1 << 8) /* Request Pending (read-only) */ +#define DCSR_STOPSTATE (1 << 3) /* Stop State (read-only) */ +#define DCSR_ENDINTR (1 << 2) /* End Interrupt (read / write) */ +#define DCSR_STARTINTR (1 << 1) /* Start Interrupt (read / write) */ +#define DCSR_BUSERR (1 << 0) /* Bus Error Interrupt (read / write) */ + +#define DCSR_EORIRQEN (1 << 28) /* End of Receive Interrupt Enable (R/W) */ +#define DCSR_EORJMPEN (1 << 27) /* Jump to next descriptor on EOR */ +#define DCSR_EORSTOPEN (1 << 26) /* STOP on an EOR */ +#define DCSR_SETCMPST (1 << 25) /* Set Descriptor Compare Status */ +#define DCSR_CLRCMPST (1 << 24) /* Clear Descriptor Compare Status */ +#define DCSR_CMPST (1 << 10) /* The Descriptor Compare Status */ +#define DCSR_EORINTR (1 << 9) /* The end of Receive */ + +#define DRCMR_MAPVLD (1 << 7) /* Map Valid (read / write) */ +#define DRCMR_CHLNUM 0x1f /* mask for Channel Number (read / write) */ + +#define DDADR_DESCADDR 0xfffffff0 /* Address of next descriptor (mask) */ +#define DDADR_STOP (1 << 0) /* Stop (read / write) */ + +#define DCMD_INCSRCADDR (1 << 31) /* Source Address Increment Setting. */ +#define DCMD_INCTRGADDR (1 << 30) /* Target Address Increment Setting. */ +#define DCMD_FLOWSRC (1 << 29) /* Flow Control by the source. */ +#define DCMD_FLOWTRG (1 << 28) /* Flow Control by the target. */ +#define DCMD_STARTIRQEN (1 << 22) /* Start Interrupt Enable */ +#define DCMD_ENDIRQEN (1 << 21) /* End Interrupt Enable */ +#define DCMD_ENDIAN (1 << 18) /* Device Endian-ness. */ +#define DCMD_BURST8 (1 << 16) /* 8 byte burst */ +#define DCMD_BURST16 (2 << 16) /* 16 byte burst */ +#define DCMD_BURST32 (3 << 16) /* 32 byte burst */ +#define DCMD_WIDTH1 (1 << 14) /* 1 byte width */ +#define DCMD_WIDTH2 (2 << 14) /* 2 byte width (HalfWord) */ +#define DCMD_WIDTH4 (3 << 14) /* 4 byte width (Word) */ +#define DCMD_LENGTH 0x01fff /* length mask (max = 8K - 1) */ + +/* + * Descriptor structure for PXA's DMA engine + * Note: this structure must always be aligned to a 16-byte boundary. + */ + +typedef struct pxa_dma_desc { + volatile u32 ddadr; /* Points to the next descriptor + flags */ + volatile u32 dsadr; /* DSADR value for the current transfer */ + volatile u32 dtadr; /* DTADR value for the current transfer */ + volatile u32 dcmd; /* DCMD value for the current transfer */ +} pxa_dma_desc; + +typedef enum { + DMA_PRIO_HIGH = 0, + DMA_PRIO_MEDIUM = 1, + DMA_PRIO_LOW = 2 +} pxa_dma_prio; + +/* + * DMA registration + */ + +int __init pxa_init_dma(int irq, int num_ch); + +int pxa_request_dma (char *name, + pxa_dma_prio prio, + void (*irq_handler)(int, void *), + void *data); + +void pxa_free_dma (int dma_ch); + +#endif /* __PLAT_DMA_H */ -- cgit v1.2.3-70-g09d2 From 38f539a608c9a3b40b30f1892bd5f9a38f4e5ffe Mon Sep 17 00:00:00 2001 From: Eric Miao Date: Tue, 20 Jan 2009 12:09:06 +0800 Subject: [ARM] pxa: move common GPIO handling code into plat-pxa 1. add common GPIO handling code into [arch/arm/plat-pxa] 2. common code in moved into , new processors should implement its own , provide the following required definitions and '#include ' in the end: - GPIO_REGS_VIRT for mapped virtual address of the GPIO registers' physical I/O memory - macros of GPLR(), GPSR(), GPDR() for constant optimization for functions gpio_{set,get}_value() (so that bit-bang code can still have tolerable performance) - NR_BUILTIN_GPIO for the number of onchip GPIO - definitions of __gpio_is_inverted() and __gpio_is_occupied(), they can be either macros or inlined functions Signed-off-by: Eric Miao --- arch/arm/mach-pxa/Makefile | 2 +- arch/arm/mach-pxa/gpio.c | 365 ---------------------------------- arch/arm/mach-pxa/include/mach/gpio.h | 32 +-- arch/arm/plat-pxa/Makefile | 1 + arch/arm/plat-pxa/gpio.c | 337 +++++++++++++++++++++++++++++++ arch/arm/plat-pxa/include/plat/gpio.h | 62 ++++++ 6 files changed, 402 insertions(+), 397 deletions(-) delete mode 100644 arch/arm/mach-pxa/gpio.c create mode 100644 arch/arm/plat-pxa/gpio.c create mode 100644 arch/arm/plat-pxa/include/plat/gpio.h (limited to 'arch/arm/mach-pxa/include') diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index 70b46570c5c..c80e1bac494 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile @@ -4,7 +4,7 @@ # Common support (must be linked before board specific support) obj-y += clock.o devices.o generic.o irq.o \ - time.o gpio.o reset.o + time.o reset.o obj-$(CONFIG_PM) += pm.o sleep.o standby.o ifeq ($(CONFIG_CPU_FREQ),y) diff --git a/arch/arm/mach-pxa/gpio.c b/arch/arm/mach-pxa/gpio.c deleted file mode 100644 index 7c2267036bf..00000000000 --- a/arch/arm/mach-pxa/gpio.c +++ /dev/null @@ -1,365 +0,0 @@ -/* - * linux/arch/arm/mach-pxa/gpio.c - * - * Generic PXA GPIO handling - * - * Author: Nicolas Pitre - * Created: Jun 15, 2001 - * Copyright: MontaVista Software Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include - -#include - -int pxa_last_gpio; - -/* - * We handle the GPIOs by banks, each bank covers up to 32 GPIOs with - * one set of registers. The register offsets are organized below: - * - * GPLR GPDR GPSR GPCR GRER GFER GEDR - * BANK 0 - 0x0000 0x000C 0x0018 0x0024 0x0030 0x003C 0x0048 - * BANK 1 - 0x0004 0x0010 0x001C 0x0028 0x0034 0x0040 0x004C - * BANK 2 - 0x0008 0x0014 0x0020 0x002C 0x0038 0x0044 0x0050 - * - * BANK 3 - 0x0100 0x010C 0x0118 0x0124 0x0130 0x013C 0x0148 - * BANK 4 - 0x0104 0x0110 0x011C 0x0128 0x0134 0x0140 0x014C - * BANK 5 - 0x0108 0x0114 0x0120 0x012C 0x0138 0x0144 0x0150 - * - * NOTE: - * BANK 3 is only available on PXA27x and later processors. - * BANK 4 and 5 are only available on PXA935 - */ - -#define GPIO_BANK(n) (GPIO_REGS_VIRT + BANK_OFF(n)) - -#define GPLR_OFFSET 0x00 -#define GPDR_OFFSET 0x0C -#define GPSR_OFFSET 0x18 -#define GPCR_OFFSET 0x24 -#define GRER_OFFSET 0x30 -#define GFER_OFFSET 0x3C -#define GEDR_OFFSET 0x48 - -struct pxa_gpio_chip { - struct gpio_chip chip; - void __iomem *regbase; - char label[10]; - - unsigned long irq_mask; - unsigned long irq_edge_rise; - unsigned long irq_edge_fall; - -#ifdef CONFIG_PM - unsigned long saved_gplr; - unsigned long saved_gpdr; - unsigned long saved_grer; - unsigned long saved_gfer; -#endif -}; - -static DEFINE_SPINLOCK(gpio_lock); -static struct pxa_gpio_chip *pxa_gpio_chips; - -#define for_each_gpio_chip(i, c) \ - for (i = 0, c = &pxa_gpio_chips[0]; i <= pxa_last_gpio; i += 32, c++) - -static inline void __iomem *gpio_chip_base(struct gpio_chip *c) -{ - return container_of(c, struct pxa_gpio_chip, chip)->regbase; -} - -static inline struct pxa_gpio_chip *gpio_to_chip(unsigned gpio) -{ - return &pxa_gpio_chips[gpio_to_bank(gpio)]; -} - -static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset) -{ - void __iomem *base = gpio_chip_base(chip); - uint32_t value, mask = 1 << offset; - unsigned long flags; - - spin_lock_irqsave(&gpio_lock, flags); - - value = __raw_readl(base + GPDR_OFFSET); - if (__gpio_is_inverted(chip->base + offset)) - value |= mask; - else - value &= ~mask; - __raw_writel(value, base + GPDR_OFFSET); - - spin_unlock_irqrestore(&gpio_lock, flags); - return 0; -} - -static int pxa_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, int value) -{ - void __iomem *base = gpio_chip_base(chip); - uint32_t tmp, mask = 1 << offset; - unsigned long flags; - - __raw_writel(mask, base + (value ? GPSR_OFFSET : GPCR_OFFSET)); - - spin_lock_irqsave(&gpio_lock, flags); - - tmp = __raw_readl(base + GPDR_OFFSET); - if (__gpio_is_inverted(chip->base + offset)) - tmp &= ~mask; - else - tmp |= mask; - __raw_writel(tmp, base + GPDR_OFFSET); - - spin_unlock_irqrestore(&gpio_lock, flags); - return 0; -} - -static int pxa_gpio_get(struct gpio_chip *chip, unsigned offset) -{ - return __raw_readl(gpio_chip_base(chip) + GPLR_OFFSET) & (1 << offset); -} - -static void pxa_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -{ - __raw_writel(1 << offset, gpio_chip_base(chip) + - (value ? GPSR_OFFSET : GPCR_OFFSET)); -} - -static int __init pxa_init_gpio_chip(int gpio_end) -{ - int i, gpio, nbanks = gpio_to_bank(gpio_end) + 1; - struct pxa_gpio_chip *chips; - - /* this is early, we have to use bootmem allocator, and we really - * want this to be allocated dynamically for different 'gpio_end' - */ - chips = alloc_bootmem_low(nbanks * sizeof(struct pxa_gpio_chip)); - if (chips == NULL) { - pr_err("%s: failed to allocate GPIO chips\n", __func__); - return -ENOMEM; - } - - for (i = 0, gpio = 0; i < nbanks; i++, gpio += 32) { - struct gpio_chip *c = &chips[i].chip; - - sprintf(chips[i].label, "gpio-%d", i); - chips[i].regbase = (void __iomem *)GPIO_BANK(i); - - c->base = gpio; - c->label = chips[i].label; - - c->direction_input = pxa_gpio_direction_input; - c->direction_output = pxa_gpio_direction_output; - c->get = pxa_gpio_get; - c->set = pxa_gpio_set; - - /* number of GPIOs on last bank may be less than 32 */ - c->ngpio = (gpio + 31 > gpio_end) ? (gpio_end - gpio + 1) : 32; - gpiochip_add(c); - } - pxa_gpio_chips = chips; - return 0; -} - -static int pxa_gpio_irq_type(unsigned int irq, unsigned int type) -{ - struct pxa_gpio_chip *c; - int gpio = irq_to_gpio(irq); - unsigned long gpdr, mask = GPIO_bit(gpio); - - c = gpio_to_chip(gpio); - - if (type == IRQ_TYPE_PROBE) { - /* Don't mess with enabled GPIOs using preconfigured edges or - * GPIOs set to alternate function or to output during probe - */ - if ((c->irq_edge_rise | c->irq_edge_fall) & GPIO_bit(gpio)) - return 0; - - if (__gpio_is_occupied(gpio)) - return 0; - - type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; - } - - gpdr = __raw_readl(c->regbase + GPDR_OFFSET); - - if (__gpio_is_inverted(gpio)) - __raw_writel(gpdr | mask, c->regbase + GPDR_OFFSET); - else - __raw_writel(gpdr & ~mask, c->regbase + GPDR_OFFSET); - - if (type & IRQ_TYPE_EDGE_RISING) - c->irq_edge_rise |= mask; - else - c->irq_edge_rise &= ~mask; - - if (type & IRQ_TYPE_EDGE_FALLING) - c->irq_edge_fall |= mask; - else - c->irq_edge_fall &= ~mask; - - __raw_writel(c->irq_edge_rise & c->irq_mask, c->regbase + GRER_OFFSET); - __raw_writel(c->irq_edge_fall & c->irq_mask, c->regbase + GFER_OFFSET); - - pr_debug("%s: IRQ%d (GPIO%d) - edge%s%s\n", __func__, irq, gpio, - ((type & IRQ_TYPE_EDGE_RISING) ? " rising" : ""), - ((type & IRQ_TYPE_EDGE_FALLING) ? " falling" : "")); - return 0; -} - -static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc) -{ - struct pxa_gpio_chip *c; - int loop, gpio, gpio_base, n; - unsigned long gedr; - - do { - loop = 0; - for_each_gpio_chip(gpio, c) { - gpio_base = c->chip.base; - - gedr = __raw_readl(c->regbase + GEDR_OFFSET); - gedr = gedr & c->irq_mask; - __raw_writel(gedr, c->regbase + GEDR_OFFSET); - - n = find_first_bit(&gedr, BITS_PER_LONG); - while (n < BITS_PER_LONG) { - loop = 1; - - generic_handle_irq(gpio_to_irq(gpio_base + n)); - n = find_next_bit(&gedr, BITS_PER_LONG, n + 1); - } - } - } while (loop); -} - -static void pxa_ack_muxed_gpio(unsigned int irq) -{ - int gpio = irq_to_gpio(irq); - struct pxa_gpio_chip *c = gpio_to_chip(gpio); - - __raw_writel(GPIO_bit(gpio), c->regbase + GEDR_OFFSET); -} - -static void pxa_mask_muxed_gpio(unsigned int irq) -{ - int gpio = irq_to_gpio(irq); - struct pxa_gpio_chip *c = gpio_to_chip(gpio); - uint32_t grer, gfer; - - c->irq_mask &= ~GPIO_bit(gpio); - - grer = __raw_readl(c->regbase + GRER_OFFSET) & ~GPIO_bit(gpio); - gfer = __raw_readl(c->regbase + GFER_OFFSET) & ~GPIO_bit(gpio); - __raw_writel(grer, c->regbase + GRER_OFFSET); - __raw_writel(gfer, c->regbase + GFER_OFFSET); -} - -static void pxa_unmask_muxed_gpio(unsigned int irq) -{ - int gpio = irq_to_gpio(irq); - struct pxa_gpio_chip *c = gpio_to_chip(gpio); - - c->irq_mask |= GPIO_bit(gpio); - __raw_writel(c->irq_edge_rise & c->irq_mask, c->regbase + GRER_OFFSET); - __raw_writel(c->irq_edge_fall & c->irq_mask, c->regbase + GFER_OFFSET); -} - -static struct irq_chip pxa_muxed_gpio_chip = { - .name = "GPIO", - .ack = pxa_ack_muxed_gpio, - .mask = pxa_mask_muxed_gpio, - .unmask = pxa_unmask_muxed_gpio, - .set_type = pxa_gpio_irq_type, -}; - -void __init pxa_init_gpio(int mux_irq, int start, int end, set_wake_t fn) -{ - struct pxa_gpio_chip *c; - int gpio, irq; - - pxa_last_gpio = end; - - /* Initialize GPIO chips */ - pxa_init_gpio_chip(end); - - /* clear all GPIO edge detects */ - for_each_gpio_chip(gpio, c) { - __raw_writel(0, c->regbase + GFER_OFFSET); - __raw_writel(0, c->regbase + GRER_OFFSET); - __raw_writel(~0,c->regbase + GEDR_OFFSET); - } - - for (irq = gpio_to_irq(start); irq <= gpio_to_irq(end); irq++) { - set_irq_chip(irq, &pxa_muxed_gpio_chip); - set_irq_handler(irq, handle_edge_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); - } - - /* Install handler for GPIO>=2 edge detect interrupts */ - set_irq_chained_handler(mux_irq, pxa_gpio_demux_handler); - pxa_muxed_gpio_chip.set_wake = fn; -} - -#ifdef CONFIG_PM -static int pxa_gpio_suspend(struct sys_device *dev, pm_message_t state) -{ - struct pxa_gpio_chip *c; - int gpio; - - for_each_gpio_chip(gpio, c) { - c->saved_gplr = __raw_readl(c->regbase + GPLR_OFFSET); - c->saved_gpdr = __raw_readl(c->regbase + GPDR_OFFSET); - c->saved_grer = __raw_readl(c->regbase + GRER_OFFSET); - c->saved_gfer = __raw_readl(c->regbase + GFER_OFFSET); - - /* Clear GPIO transition detect bits */ - __raw_writel(0xffffffff, c->regbase + GEDR_OFFSET); - } - return 0; -} - -static int pxa_gpio_resume(struct sys_device *dev) -{ - struct pxa_gpio_chip *c; - int gpio; - - for_each_gpio_chip(gpio, c) { - /* restore level with set/clear */ - __raw_writel( c->saved_gplr, c->regbase + GPSR_OFFSET); - __raw_writel(~c->saved_gplr, c->regbase + GPCR_OFFSET); - - __raw_writel(c->saved_grer, c->regbase + GRER_OFFSET); - __raw_writel(c->saved_gfer, c->regbase + GFER_OFFSET); - __raw_writel(c->saved_gpdr, c->regbase + GPDR_OFFSET); - } - return 0; -} -#else -#define pxa_gpio_suspend NULL -#define pxa_gpio_resume NULL -#endif - -struct sysdev_class pxa_gpio_sysclass = { - .name = "gpio", - .suspend = pxa_gpio_suspend, - .resume = pxa_gpio_resume, -}; - -static int __init pxa_gpio_init(void) -{ - return sysdev_class_register(&pxa_gpio_sysclass); -} - -core_initcall(pxa_gpio_init); diff --git a/arch/arm/mach-pxa/include/mach/gpio.h b/arch/arm/mach-pxa/include/mach/gpio.h index c72c89a2285..b024a8b3743 100644 --- a/arch/arm/mach-pxa/include/mach/gpio.h +++ b/arch/arm/mach-pxa/include/mach/gpio.h @@ -99,40 +99,12 @@ #define GAFR(x) GPIO_REG(0x54 + (((x) & 0x70) >> 2)) -/* NOTE: some PXAs have fewer on-chip GPIOs (like PXA255, with 85). - * Those cases currently cause holes in the GPIO number space, the - * actual number of the last GPIO is recorded by 'pxa_last_gpio'. - */ -extern int pxa_last_gpio; - #define NR_BUILTIN_GPIO 128 -static inline int gpio_get_value(unsigned gpio) -{ - if (__builtin_constant_p(gpio) && (gpio < NR_BUILTIN_GPIO)) - return GPLR(gpio) & GPIO_bit(gpio); - else - return __gpio_get_value(gpio); -} - -static inline void gpio_set_value(unsigned gpio, int value) -{ - if (__builtin_constant_p(gpio) && (gpio < NR_BUILTIN_GPIO)) { - if (value) - GPSR(gpio) = GPIO_bit(gpio); - else - GPCR(gpio) = GPIO_bit(gpio); - } else { - __gpio_set_value(gpio, value); - } -} - -#define gpio_cansleep __gpio_cansleep #define gpio_to_bank(gpio) ((gpio) >> 5) #define gpio_to_irq(gpio) IRQ_GPIO(gpio) #define irq_to_gpio(irq) IRQ_TO_GPIO(irq) - #ifdef CONFIG_CPU_PXA26x /* GPIO86/87/88/89 on PXA26x have their direction bits in GPDR2 inverted, * as well as their Alternate Function value being '1' for GPIO in GAFRx. @@ -165,7 +137,5 @@ static inline int __gpio_is_occupied(unsigned gpio) return GPDR(gpio) & GPIO_bit(gpio); } -typedef int (*set_wake_t)(unsigned int irq, unsigned int on); - -extern void pxa_init_gpio(int mux_irq, int start, int end, set_wake_t fn); +#include #endif diff --git a/arch/arm/plat-pxa/Makefile b/arch/arm/plat-pxa/Makefile index dcc3ceaf717..b837df44048 100644 --- a/arch/arm/plat-pxa/Makefile +++ b/arch/arm/plat-pxa/Makefile @@ -4,3 +4,4 @@ obj-y := dma.o +obj-$(CONFIG_GENERIC_GPIO) += gpio.o diff --git a/arch/arm/plat-pxa/gpio.c b/arch/arm/plat-pxa/gpio.c new file mode 100644 index 00000000000..af819bf21b6 --- /dev/null +++ b/arch/arm/plat-pxa/gpio.c @@ -0,0 +1,337 @@ +/* + * linux/arch/arm/plat-pxa/gpio.c + * + * Generic PXA GPIO handling + * + * Author: Nicolas Pitre + * Created: Jun 15, 2001 + * Copyright: MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include + +int pxa_last_gpio; + +struct pxa_gpio_chip { + struct gpio_chip chip; + void __iomem *regbase; + char label[10]; + + unsigned long irq_mask; + unsigned long irq_edge_rise; + unsigned long irq_edge_fall; + +#ifdef CONFIG_PM + unsigned long saved_gplr; + unsigned long saved_gpdr; + unsigned long saved_grer; + unsigned long saved_gfer; +#endif +}; + +static DEFINE_SPINLOCK(gpio_lock); +static struct pxa_gpio_chip *pxa_gpio_chips; + +#define for_each_gpio_chip(i, c) \ + for (i = 0, c = &pxa_gpio_chips[0]; i <= pxa_last_gpio; i += 32, c++) + +static inline void __iomem *gpio_chip_base(struct gpio_chip *c) +{ + return container_of(c, struct pxa_gpio_chip, chip)->regbase; +} + +static inline struct pxa_gpio_chip *gpio_to_chip(unsigned gpio) +{ + return &pxa_gpio_chips[gpio_to_bank(gpio)]; +} + +static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + void __iomem *base = gpio_chip_base(chip); + uint32_t value, mask = 1 << offset; + unsigned long flags; + + spin_lock_irqsave(&gpio_lock, flags); + + value = __raw_readl(base + GPDR_OFFSET); + if (__gpio_is_inverted(chip->base + offset)) + value |= mask; + else + value &= ~mask; + __raw_writel(value, base + GPDR_OFFSET); + + spin_unlock_irqrestore(&gpio_lock, flags); + return 0; +} + +static int pxa_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + void __iomem *base = gpio_chip_base(chip); + uint32_t tmp, mask = 1 << offset; + unsigned long flags; + + __raw_writel(mask, base + (value ? GPSR_OFFSET : GPCR_OFFSET)); + + spin_lock_irqsave(&gpio_lock, flags); + + tmp = __raw_readl(base + GPDR_OFFSET); + if (__gpio_is_inverted(chip->base + offset)) + tmp &= ~mask; + else + tmp |= mask; + __raw_writel(tmp, base + GPDR_OFFSET); + + spin_unlock_irqrestore(&gpio_lock, flags); + return 0; +} + +static int pxa_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + return __raw_readl(gpio_chip_base(chip) + GPLR_OFFSET) & (1 << offset); +} + +static void pxa_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + __raw_writel(1 << offset, gpio_chip_base(chip) + + (value ? GPSR_OFFSET : GPCR_OFFSET)); +} + +static int __init pxa_init_gpio_chip(int gpio_end) +{ + int i, gpio, nbanks = gpio_to_bank(gpio_end) + 1; + struct pxa_gpio_chip *chips; + + /* this is early, we have to use bootmem allocator, and we really + * want this to be allocated dynamically for different 'gpio_end' + */ + chips = alloc_bootmem_low(nbanks * sizeof(struct pxa_gpio_chip)); + if (chips == NULL) { + pr_err("%s: failed to allocate GPIO chips\n", __func__); + return -ENOMEM; + } + + for (i = 0, gpio = 0; i < nbanks; i++, gpio += 32) { + struct gpio_chip *c = &chips[i].chip; + + sprintf(chips[i].label, "gpio-%d", i); + chips[i].regbase = (void __iomem *)GPIO_BANK(i); + + c->base = gpio; + c->label = chips[i].label; + + c->direction_input = pxa_gpio_direction_input; + c->direction_output = pxa_gpio_direction_output; + c->get = pxa_gpio_get; + c->set = pxa_gpio_set; + + /* number of GPIOs on last bank may be less than 32 */ + c->ngpio = (gpio + 31 > gpio_end) ? (gpio_end - gpio + 1) : 32; + gpiochip_add(c); + } + pxa_gpio_chips = chips; + return 0; +} + +static int pxa_gpio_irq_type(unsigned int irq, unsigned int type) +{ + struct pxa_gpio_chip *c; + int gpio = irq_to_gpio(irq); + unsigned long gpdr, mask = GPIO_bit(gpio); + + c = gpio_to_chip(gpio); + + if (type == IRQ_TYPE_PROBE) { + /* Don't mess with enabled GPIOs using preconfigured edges or + * GPIOs set to alternate function or to output during probe + */ + if ((c->irq_edge_rise | c->irq_edge_fall) & GPIO_bit(gpio)) + return 0; + + if (__gpio_is_occupied(gpio)) + return 0; + + type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; + } + + gpdr = __raw_readl(c->regbase + GPDR_OFFSET); + + if (__gpio_is_inverted(gpio)) + __raw_writel(gpdr | mask, c->regbase + GPDR_OFFSET); + else + __raw_writel(gpdr & ~mask, c->regbase + GPDR_OFFSET); + + if (type & IRQ_TYPE_EDGE_RISING) + c->irq_edge_rise |= mask; + else + c->irq_edge_rise &= ~mask; + + if (type & IRQ_TYPE_EDGE_FALLING) + c->irq_edge_fall |= mask; + else + c->irq_edge_fall &= ~mask; + + __raw_writel(c->irq_edge_rise & c->irq_mask, c->regbase + GRER_OFFSET); + __raw_writel(c->irq_edge_fall & c->irq_mask, c->regbase + GFER_OFFSET); + + pr_debug("%s: IRQ%d (GPIO%d) - edge%s%s\n", __func__, irq, gpio, + ((type & IRQ_TYPE_EDGE_RISING) ? " rising" : ""), + ((type & IRQ_TYPE_EDGE_FALLING) ? " falling" : "")); + return 0; +} + +static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc) +{ + struct pxa_gpio_chip *c; + int loop, gpio, gpio_base, n; + unsigned long gedr; + + do { + loop = 0; + for_each_gpio_chip(gpio, c) { + gpio_base = c->chip.base; + + gedr = __raw_readl(c->regbase + GEDR_OFFSET); + gedr = gedr & c->irq_mask; + __raw_writel(gedr, c->regbase + GEDR_OFFSET); + + n = find_first_bit(&gedr, BITS_PER_LONG); + while (n < BITS_PER_LONG) { + loop = 1; + + generic_handle_irq(gpio_to_irq(gpio_base + n)); + n = find_next_bit(&gedr, BITS_PER_LONG, n + 1); + } + } + } while (loop); +} + +static void pxa_ack_muxed_gpio(unsigned int irq) +{ + int gpio = irq_to_gpio(irq); + struct pxa_gpio_chip *c = gpio_to_chip(gpio); + + __raw_writel(GPIO_bit(gpio), c->regbase + GEDR_OFFSET); +} + +static void pxa_mask_muxed_gpio(unsigned int irq) +{ + int gpio = irq_to_gpio(irq); + struct pxa_gpio_chip *c = gpio_to_chip(gpio); + uint32_t grer, gfer; + + c->irq_mask &= ~GPIO_bit(gpio); + + grer = __raw_readl(c->regbase + GRER_OFFSET) & ~GPIO_bit(gpio); + gfer = __raw_readl(c->regbase + GFER_OFFSET) & ~GPIO_bit(gpio); + __raw_writel(grer, c->regbase + GRER_OFFSET); + __raw_writel(gfer, c->regbase + GFER_OFFSET); +} + +static void pxa_unmask_muxed_gpio(unsigned int irq) +{ + int gpio = irq_to_gpio(irq); + struct pxa_gpio_chip *c = gpio_to_chip(gpio); + + c->irq_mask |= GPIO_bit(gpio); + __raw_writel(c->irq_edge_rise & c->irq_mask, c->regbase + GRER_OFFSET); + __raw_writel(c->irq_edge_fall & c->irq_mask, c->regbase + GFER_OFFSET); +} + +static struct irq_chip pxa_muxed_gpio_chip = { + .name = "GPIO", + .ack = pxa_ack_muxed_gpio, + .mask = pxa_mask_muxed_gpio, + .unmask = pxa_unmask_muxed_gpio, + .set_type = pxa_gpio_irq_type, +}; + +void __init pxa_init_gpio(int mux_irq, int start, int end, set_wake_t fn) +{ + struct pxa_gpio_chip *c; + int gpio, irq; + + pxa_last_gpio = end; + + /* Initialize GPIO chips */ + pxa_init_gpio_chip(end); + + /* clear all GPIO edge detects */ + for_each_gpio_chip(gpio, c) { + __raw_writel(0, c->regbase + GFER_OFFSET); + __raw_writel(0, c->regbase + GRER_OFFSET); + __raw_writel(~0,c->regbase + GEDR_OFFSET); + } + + for (irq = gpio_to_irq(start); irq <= gpio_to_irq(end); irq++) { + set_irq_chip(irq, &pxa_muxed_gpio_chip); + set_irq_handler(irq, handle_edge_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } + + /* Install handler for GPIO>=2 edge detect interrupts */ + set_irq_chained_handler(mux_irq, pxa_gpio_demux_handler); + pxa_muxed_gpio_chip.set_wake = fn; +} + +#ifdef CONFIG_PM +static int pxa_gpio_suspend(struct sys_device *dev, pm_message_t state) +{ + struct pxa_gpio_chip *c; + int gpio; + + for_each_gpio_chip(gpio, c) { + c->saved_gplr = __raw_readl(c->regbase + GPLR_OFFSET); + c->saved_gpdr = __raw_readl(c->regbase + GPDR_OFFSET); + c->saved_grer = __raw_readl(c->regbase + GRER_OFFSET); + c->saved_gfer = __raw_readl(c->regbase + GFER_OFFSET); + + /* Clear GPIO transition detect bits */ + __raw_writel(0xffffffff, c->regbase + GEDR_OFFSET); + } + return 0; +} + +static int pxa_gpio_resume(struct sys_device *dev) +{ + struct pxa_gpio_chip *c; + int gpio; + + for_each_gpio_chip(gpio, c) { + /* restore level with set/clear */ + __raw_writel( c->saved_gplr, c->regbase + GPSR_OFFSET); + __raw_writel(~c->saved_gplr, c->regbase + GPCR_OFFSET); + + __raw_writel(c->saved_grer, c->regbase + GRER_OFFSET); + __raw_writel(c->saved_gfer, c->regbase + GFER_OFFSET); + __raw_writel(c->saved_gpdr, c->regbase + GPDR_OFFSET); + } + return 0; +} +#else +#define pxa_gpio_suspend NULL +#define pxa_gpio_resume NULL +#endif + +struct sysdev_class pxa_gpio_sysclass = { + .name = "gpio", + .suspend = pxa_gpio_suspend, + .resume = pxa_gpio_resume, +}; + +static int __init pxa_gpio_init(void) +{ + return sysdev_class_register(&pxa_gpio_sysclass); +} + +core_initcall(pxa_gpio_init); diff --git a/arch/arm/plat-pxa/include/plat/gpio.h b/arch/arm/plat-pxa/include/plat/gpio.h new file mode 100644 index 00000000000..44248cb926a --- /dev/null +++ b/arch/arm/plat-pxa/include/plat/gpio.h @@ -0,0 +1,62 @@ +#ifndef __PLAT_GPIO_H +#define __PLAT_GPIO_H + +/* + * We handle the GPIOs by banks, each bank covers up to 32 GPIOs with + * one set of registers. The register offsets are organized below: + * + * GPLR GPDR GPSR GPCR GRER GFER GEDR + * BANK 0 - 0x0000 0x000C 0x0018 0x0024 0x0030 0x003C 0x0048 + * BANK 1 - 0x0004 0x0010 0x001C 0x0028 0x0034 0x0040 0x004C + * BANK 2 - 0x0008 0x0014 0x0020 0x002C 0x0038 0x0044 0x0050 + * + * BANK 3 - 0x0100 0x010C 0x0118 0x0124 0x0130 0x013C 0x0148 + * BANK 4 - 0x0104 0x0110 0x011C 0x0128 0x0134 0x0140 0x014C + * BANK 5 - 0x0108 0x0114 0x0120 0x012C 0x0138 0x0144 0x0150 + * + * NOTE: + * BANK 3 is only available on PXA27x and later processors. + * BANK 4 and 5 are only available on PXA935 + */ + +#define GPIO_BANK(n) (GPIO_REGS_VIRT + BANK_OFF(n)) + +#define GPLR_OFFSET 0x00 +#define GPDR_OFFSET 0x0C +#define GPSR_OFFSET 0x18 +#define GPCR_OFFSET 0x24 +#define GRER_OFFSET 0x30 +#define GFER_OFFSET 0x3C +#define GEDR_OFFSET 0x48 + +static inline int gpio_get_value(unsigned gpio) +{ + if (__builtin_constant_p(gpio) && (gpio < NR_BUILTIN_GPIO)) + return GPLR(gpio) & GPIO_bit(gpio); + else + return __gpio_get_value(gpio); +} + +static inline void gpio_set_value(unsigned gpio, int value) +{ + if (__builtin_constant_p(gpio) && (gpio < NR_BUILTIN_GPIO)) { + if (value) + GPSR(gpio) = GPIO_bit(gpio); + else + GPCR(gpio) = GPIO_bit(gpio); + } else + __gpio_set_value(gpio, value); +} + +#define gpio_cansleep __gpio_cansleep + +/* NOTE: some PXAs have fewer on-chip GPIOs (like PXA255, with 85). + * Those cases currently cause holes in the GPIO number space, the + * actual number of the last GPIO is recorded by 'pxa_last_gpio'. + */ +extern int pxa_last_gpio; + +typedef int (*set_wake_t)(unsigned int irq, unsigned int on); + +extern void pxa_init_gpio(int mux_irq, int start, int end, set_wake_t fn); +#endif /* __PLAT_GPIO_H */ -- cgit v1.2.3-70-g09d2 From f8dec04d33b94a4cfa9358fd9666c01480bb164d Mon Sep 17 00:00:00 2001 From: Eric Miao Date: Thu, 15 Jan 2009 16:42:56 +0800 Subject: [ARM] pxa: move common MFP handling code into plat-pxa Signed-off-by: Eric Miao --- arch/arm/mach-pxa/include/mach/mfp-pxa25x.h | 1 - arch/arm/mach-pxa/include/mach/mfp-pxa27x.h | 1 - arch/arm/mach-pxa/include/mach/mfp-pxa2xx.h | 2 +- arch/arm/mach-pxa/include/mach/mfp-pxa300.h | 1 - arch/arm/mach-pxa/include/mach/mfp-pxa320.h | 1 - arch/arm/mach-pxa/include/mach/mfp-pxa3xx.h | 130 ++-------- arch/arm/mach-pxa/include/mach/mfp-pxa930.h | 1 - arch/arm/mach-pxa/mfp-pxa3xx.c | 189 +------------- arch/arm/mach-pxa/pxa300.c | 10 +- arch/arm/mach-pxa/pxa320.c | 6 +- arch/arm/mach-pxa/pxa930.c | 6 +- arch/arm/plat-pxa/Makefile | 2 +- arch/arm/plat-pxa/include/plat/mfp.h | 369 ++++++++++++++++++++++++++++ arch/arm/plat-pxa/mfp.c | 278 +++++++++++++++++++++ 14 files changed, 680 insertions(+), 317 deletions(-) create mode 100644 arch/arm/plat-pxa/include/plat/mfp.h create mode 100644 arch/arm/plat-pxa/mfp.c (limited to 'arch/arm/mach-pxa/include') diff --git a/arch/arm/mach-pxa/include/mach/mfp-pxa25x.h b/arch/arm/mach-pxa/include/mach/mfp-pxa25x.h index a72869b73ee..b13dc0269a6 100644 --- a/arch/arm/mach-pxa/include/mach/mfp-pxa25x.h +++ b/arch/arm/mach-pxa/include/mach/mfp-pxa25x.h @@ -1,7 +1,6 @@ #ifndef __ASM_ARCH_MFP_PXA25X_H #define __ASM_ARCH_MFP_PXA25X_H -#include #include /* GPIO */ diff --git a/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h b/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h index da4f85a4f99..6543c05f47e 100644 --- a/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h +++ b/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h @@ -8,7 +8,6 @@ * specific controller, and this should work in most cases. */ -#include #include /* Note: GPIO3/GPIO4 will be driven by Power I2C when PCFR/PI2C_EN diff --git a/arch/arm/mach-pxa/include/mach/mfp-pxa2xx.h b/arch/arm/mach-pxa/include/mach/mfp-pxa2xx.h index 3e9211591e2..658b28ed129 100644 --- a/arch/arm/mach-pxa/include/mach/mfp-pxa2xx.h +++ b/arch/arm/mach-pxa/include/mach/mfp-pxa2xx.h @@ -1,7 +1,7 @@ #ifndef __ASM_ARCH_MFP_PXA2XX_H #define __ASM_ARCH_MFP_PXA2XX_H -#include +#include /* * the following MFP_xxx bit definitions in mfp.h are re-used for pxa2xx: diff --git a/arch/arm/mach-pxa/include/mach/mfp-pxa300.h b/arch/arm/mach-pxa/include/mach/mfp-pxa300.h index 928fbef9cbf..ae8441192ef 100644 --- a/arch/arm/mach-pxa/include/mach/mfp-pxa300.h +++ b/arch/arm/mach-pxa/include/mach/mfp-pxa300.h @@ -15,7 +15,6 @@ #ifndef __ASM_ARCH_MFP_PXA300_H #define __ASM_ARCH_MFP_PXA300_H -#include #include /* GPIO */ diff --git a/arch/arm/mach-pxa/include/mach/mfp-pxa320.h b/arch/arm/mach-pxa/include/mach/mfp-pxa320.h index 80a0da9e092..07897e61d05 100644 --- a/arch/arm/mach-pxa/include/mach/mfp-pxa320.h +++ b/arch/arm/mach-pxa/include/mach/mfp-pxa320.h @@ -15,7 +15,6 @@ #ifndef __ASM_ARCH_MFP_PXA320_H #define __ASM_ARCH_MFP_PXA320_H -#include #include /* GPIO */ diff --git a/arch/arm/mach-pxa/include/mach/mfp-pxa3xx.h b/arch/arm/mach-pxa/include/mach/mfp-pxa3xx.h index 1f6b35c015d..d375195d982 100644 --- a/arch/arm/mach-pxa/include/mach/mfp-pxa3xx.h +++ b/arch/arm/mach-pxa/include/mach/mfp-pxa3xx.h @@ -1,68 +1,9 @@ #ifndef __ASM_ARCH_MFP_PXA3XX_H #define __ASM_ARCH_MFP_PXA3XX_H -#define MFPR_BASE (0x40e10000) -#define MFPR_SIZE (PAGE_SIZE) - -/* MFPR register bit definitions */ -#define MFPR_PULL_SEL (0x1 << 15) -#define MFPR_PULLUP_EN (0x1 << 14) -#define MFPR_PULLDOWN_EN (0x1 << 13) -#define MFPR_SLEEP_SEL (0x1 << 9) -#define MFPR_SLEEP_OE_N (0x1 << 7) -#define MFPR_EDGE_CLEAR (0x1 << 6) -#define MFPR_EDGE_FALL_EN (0x1 << 5) -#define MFPR_EDGE_RISE_EN (0x1 << 4) - -#define MFPR_SLEEP_DATA(x) ((x) << 8) -#define MFPR_DRIVE(x) (((x) & 0x7) << 10) -#define MFPR_AF_SEL(x) (((x) & 0x7) << 0) +#include -#define MFPR_EDGE_NONE (0) -#define MFPR_EDGE_RISE (MFPR_EDGE_RISE_EN) -#define MFPR_EDGE_FALL (MFPR_EDGE_FALL_EN) -#define MFPR_EDGE_BOTH (MFPR_EDGE_RISE | MFPR_EDGE_FALL) - -/* - * Table that determines the low power modes outputs, with actual settings - * used in parentheses for don't-care values. Except for the float output, - * the configured driven and pulled levels match, so if there is a need for - * non-LPM pulled output, the same configuration could probably be used. - * - * Output value sleep_oe_n sleep_data pullup_en pulldown_en pull_sel - * (bit 7) (bit 8) (bit 14) (bit 13) (bit 15) - * - * Input 0 X(0) X(0) X(0) 0 - * Drive 0 0 0 0 X(1) 0 - * Drive 1 0 1 X(1) 0 0 - * Pull hi (1) 1 X(1) 1 0 0 - * Pull lo (0) 1 X(0) 0 1 0 - * Z (float) 1 X(0) 0 0 0 - */ -#define MFPR_LPM_INPUT (0) -#define MFPR_LPM_DRIVE_LOW (MFPR_SLEEP_DATA(0) | MFPR_PULLDOWN_EN) -#define MFPR_LPM_DRIVE_HIGH (MFPR_SLEEP_DATA(1) | MFPR_PULLUP_EN) -#define MFPR_LPM_PULL_LOW (MFPR_LPM_DRIVE_LOW | MFPR_SLEEP_OE_N) -#define MFPR_LPM_PULL_HIGH (MFPR_LPM_DRIVE_HIGH | MFPR_SLEEP_OE_N) -#define MFPR_LPM_FLOAT (MFPR_SLEEP_OE_N) -#define MFPR_LPM_MASK (0xe080) - -/* - * The pullup and pulldown state of the MFP pin at run mode is by default - * determined by the selected alternate function. In case that some buggy - * devices need to override this default behavior, the definitions below - * indicates the setting of corresponding MFPR bits - * - * Definition pull_sel pullup_en pulldown_en - * MFPR_PULL_NONE 0 0 0 - * MFPR_PULL_LOW 1 0 1 - * MFPR_PULL_HIGH 1 1 0 - * MFPR_PULL_BOTH 1 1 1 - */ -#define MFPR_PULL_NONE (0) -#define MFPR_PULL_LOW (MFPR_PULL_SEL | MFPR_PULLDOWN_EN) -#define MFPR_PULL_BOTH (MFPR_PULL_LOW | MFPR_PULLUP_EN) -#define MFPR_PULL_HIGH (MFPR_PULL_SEL | MFPR_PULLUP_EN) +#define MFPR_BASE (0x40e10000) /* PXA3xx common MFP configurations - processor specific ones defined * in mfp-pxa300.h and mfp-pxa320.h @@ -197,56 +138,21 @@ #define GPIO5_2_GPIO MFP_CFG(GPIO5_2, AF0) #define GPIO6_2_GPIO MFP_CFG(GPIO6_2, AF0) -/* - * each MFP pin will have a MFPR register, since the offset of the - * register varies between processors, the processor specific code - * should initialize the pin offsets by pxa3xx_mfp_init_addr() - * - * pxa3xx_mfp_init_addr - accepts a table of "pxa3xx_mfp_addr_map" - * structure, which represents a range of MFP pins from "start" to - * "end", with the offset begining at "offset", to define a single - * pin, let "end" = -1 - * - * use - * - * MFP_ADDR_X() to define a range of pins - * MFP_ADDR() to define a single pin - * MFP_ADDR_END to signal the end of pin offset definitions - */ -struct pxa3xx_mfp_addr_map { - unsigned int start; - unsigned int end; - unsigned long offset; -}; - -#define MFP_ADDR_X(start, end, offset) \ - { MFP_PIN_##start, MFP_PIN_##end, offset } - -#define MFP_ADDR(pin, offset) \ - { MFP_PIN_##pin, -1, offset } - -#define MFP_ADDR_END { MFP_PIN_INVALID, 0 } - -/* - * pxa3xx_mfp_read()/pxa3xx_mfp_write() - for direct read/write access - * to the MFPR register - */ -unsigned long pxa3xx_mfp_read(int mfp); -void pxa3xx_mfp_write(int mfp, unsigned long mfpr_val); - -/* - * pxa3xx_mfp_config - configure the MFPR registers - * - * used by board specific initialization code - */ -void pxa3xx_mfp_config(unsigned long *mfp_cfgs, int num); - -/* - * pxa3xx_mfp_init_addr() - initialize the mapping between mfp pin - * index and MFPR register offset - * - * used by processor specific code +/* NOTE: usage of these two functions is not recommended, + * use pxa3xx_mfp_config() instead. */ -void __init pxa3xx_mfp_init_addr(struct pxa3xx_mfp_addr_map *); -void __init pxa3xx_init_mfp(void); +static inline unsigned long pxa3xx_mfp_read(int mfp) +{ + return mfp_read(mfp); +} + +static inline void pxa3xx_mfp_write(int mfp, unsigned long val) +{ + mfp_write(mfp, val); +} + +static inline void pxa3xx_mfp_config(unsigned long *mfp_cfg, int num) +{ + mfp_config(mfp_cfg, num); +} #endif /* __ASM_ARCH_MFP_PXA3XX_H */ diff --git a/arch/arm/mach-pxa/include/mach/mfp-pxa930.h b/arch/arm/mach-pxa/include/mach/mfp-pxa930.h index fa73f56a137..0d119d3b922 100644 --- a/arch/arm/mach-pxa/include/mach/mfp-pxa930.h +++ b/arch/arm/mach-pxa/include/mach/mfp-pxa930.h @@ -13,7 +13,6 @@ #ifndef __ASM_ARCH_MFP_PXA9xx_H #define __ASM_ARCH_MFP_PXA9xx_H -#include #include /* GPIO */ diff --git a/arch/arm/mach-pxa/mfp-pxa3xx.c b/arch/arm/mach-pxa/mfp-pxa3xx.c index eb197a6e8e9..7a270eecd48 100644 --- a/arch/arm/mach-pxa/mfp-pxa3xx.c +++ b/arch/arm/mach-pxa/mfp-pxa3xx.c @@ -20,183 +20,9 @@ #include #include -#include #include #include -/* mfp_spin_lock is used to ensure that MFP register configuration - * (most likely a read-modify-write operation) is atomic, and that - * mfp_table[] is consistent - */ -static DEFINE_SPINLOCK(mfp_spin_lock); - -static void __iomem *mfpr_mmio_base = (void __iomem *)&__REG(MFPR_BASE); - -struct pxa3xx_mfp_pin { - unsigned long config; /* -1 for not configured */ - unsigned long mfpr_off; /* MFPRxx Register offset */ - unsigned long mfpr_run; /* Run-Mode Register Value */ - unsigned long mfpr_lpm; /* Low Power Mode Register Value */ -}; - -static struct pxa3xx_mfp_pin mfp_table[MFP_PIN_MAX]; - -/* mapping of MFP_LPM_* definitions to MFPR_LPM_* register bits */ -static const unsigned long mfpr_lpm[] = { - MFPR_LPM_INPUT, - MFPR_LPM_DRIVE_LOW, - MFPR_LPM_DRIVE_HIGH, - MFPR_LPM_PULL_LOW, - MFPR_LPM_PULL_HIGH, - MFPR_LPM_FLOAT, -}; - -/* mapping of MFP_PULL_* definitions to MFPR_PULL_* register bits */ -static const unsigned long mfpr_pull[] = { - MFPR_PULL_NONE, - MFPR_PULL_LOW, - MFPR_PULL_HIGH, - MFPR_PULL_BOTH, -}; - -/* mapping of MFP_LPM_EDGE_* definitions to MFPR_EDGE_* register bits */ -static const unsigned long mfpr_edge[] = { - MFPR_EDGE_NONE, - MFPR_EDGE_RISE, - MFPR_EDGE_FALL, - MFPR_EDGE_BOTH, -}; - -#define mfpr_readl(off) \ - __raw_readl(mfpr_mmio_base + (off)) - -#define mfpr_writel(off, val) \ - __raw_writel(val, mfpr_mmio_base + (off)) - -#define mfp_configured(p) ((p)->config != -1) - -/* - * perform a read-back of any MFPR register to make sure the - * previous writings are finished - */ -#define mfpr_sync() (void)__raw_readl(mfpr_mmio_base + 0) - -static inline void __mfp_config_run(struct pxa3xx_mfp_pin *p) -{ - if (mfp_configured(p)) - mfpr_writel(p->mfpr_off, p->mfpr_run); -} - -static inline void __mfp_config_lpm(struct pxa3xx_mfp_pin *p) -{ - if (mfp_configured(p)) { - unsigned long mfpr_clr = (p->mfpr_run & ~MFPR_EDGE_BOTH) | MFPR_EDGE_CLEAR; - if (mfpr_clr != p->mfpr_run) - mfpr_writel(p->mfpr_off, mfpr_clr); - if (p->mfpr_lpm != mfpr_clr) - mfpr_writel(p->mfpr_off, p->mfpr_lpm); - } -} - -void pxa3xx_mfp_config(unsigned long *mfp_cfgs, int num) -{ - unsigned long flags; - int i; - - spin_lock_irqsave(&mfp_spin_lock, flags); - - for (i = 0; i < num; i++, mfp_cfgs++) { - unsigned long tmp, c = *mfp_cfgs; - struct pxa3xx_mfp_pin *p; - int pin, af, drv, lpm, edge, pull; - - pin = MFP_PIN(c); - BUG_ON(pin >= MFP_PIN_MAX); - p = &mfp_table[pin]; - - af = MFP_AF(c); - drv = MFP_DS(c); - lpm = MFP_LPM_STATE(c); - edge = MFP_LPM_EDGE(c); - pull = MFP_PULL(c); - - /* run-mode pull settings will conflict with MFPR bits of - * low power mode state, calculate mfpr_run and mfpr_lpm - * individually if pull != MFP_PULL_NONE - */ - tmp = MFPR_AF_SEL(af) | MFPR_DRIVE(drv); - - if (likely(pull == MFP_PULL_NONE)) { - p->mfpr_run = tmp | mfpr_lpm[lpm] | mfpr_edge[edge]; - p->mfpr_lpm = p->mfpr_run; - } else { - p->mfpr_lpm = tmp | mfpr_lpm[lpm] | mfpr_edge[edge]; - p->mfpr_run = tmp | mfpr_pull[pull]; - } - - p->config = c; __mfp_config_run(p); - } - - mfpr_sync(); - spin_unlock_irqrestore(&mfp_spin_lock, flags); -} - -unsigned long pxa3xx_mfp_read(int mfp) -{ - unsigned long val, flags; - - BUG_ON(mfp >= MFP_PIN_MAX); - - spin_lock_irqsave(&mfp_spin_lock, flags); - val = mfpr_readl(mfp_table[mfp].mfpr_off); - spin_unlock_irqrestore(&mfp_spin_lock, flags); - - return val; -} - -void pxa3xx_mfp_write(int mfp, unsigned long val) -{ - unsigned long flags; - - BUG_ON(mfp >= MFP_PIN_MAX); - - spin_lock_irqsave(&mfp_spin_lock, flags); - mfpr_writel(mfp_table[mfp].mfpr_off, val); - mfpr_sync(); - spin_unlock_irqrestore(&mfp_spin_lock, flags); -} - -void __init pxa3xx_mfp_init_addr(struct pxa3xx_mfp_addr_map *map) -{ - struct pxa3xx_mfp_addr_map *p; - unsigned long offset, flags; - int i; - - spin_lock_irqsave(&mfp_spin_lock, flags); - - for (p = map; p->start != MFP_PIN_INVALID; p++) { - offset = p->offset; - i = p->start; - - do { - mfp_table[i].mfpr_off = offset; - mfp_table[i].mfpr_run = 0; - mfp_table[i].mfpr_lpm = 0; - offset += 4; i++; - } while ((i <= p->end) && (p->end != -1)); - } - - spin_unlock_irqrestore(&mfp_spin_lock, flags); -} - -void __init pxa3xx_init_mfp(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(mfp_table); i++) - mfp_table[i].config = -1; -} - #ifdef CONFIG_PM /* * Configure the MFPs appropriately for suspend/resume. @@ -207,23 +33,13 @@ void __init pxa3xx_init_mfp(void) */ static int pxa3xx_mfp_suspend(struct sys_device *d, pm_message_t state) { - int pin; - - for (pin = 0; pin < ARRAY_SIZE(mfp_table); pin++) { - struct pxa3xx_mfp_pin *p = &mfp_table[pin]; - __mfp_config_lpm(p); - } + mfp_config_lpm(); return 0; } static int pxa3xx_mfp_resume(struct sys_device *d) { - int pin; - - for (pin = 0; pin < ARRAY_SIZE(mfp_table); pin++) { - struct pxa3xx_mfp_pin *p = &mfp_table[pin]; - __mfp_config_run(p); - } + mfp_config_run(); /* clear RDH bit when MFP settings are restored * @@ -231,7 +47,6 @@ static int pxa3xx_mfp_resume(struct sys_device *d) * preserve them here in case they will be referenced later */ ASCR &= ~(ASCR_RDH | ASCR_D1S | ASCR_D2S | ASCR_D3S); - return 0; } #else diff --git a/arch/arm/mach-pxa/pxa300.c b/arch/arm/mach-pxa/pxa300.c index 37bb12d13ca..4ba6d21f851 100644 --- a/arch/arm/mach-pxa/pxa300.c +++ b/arch/arm/mach-pxa/pxa300.c @@ -23,7 +23,7 @@ #include "devices.h" #include "clock.h" -static struct pxa3xx_mfp_addr_map pxa300_mfp_addr_map[] __initdata = { +static struct mfp_addr_map pxa300_mfp_addr_map[] __initdata = { MFP_ADDR_X(GPIO0, GPIO2, 0x00b4), MFP_ADDR_X(GPIO3, GPIO26, 0x027c), @@ -72,7 +72,7 @@ static struct pxa3xx_mfp_addr_map pxa300_mfp_addr_map[] __initdata = { }; /* override pxa300 MFP register addresses */ -static struct pxa3xx_mfp_addr_map pxa310_mfp_addr_map[] __initdata = { +static struct mfp_addr_map pxa310_mfp_addr_map[] __initdata = { MFP_ADDR_X(GPIO30, GPIO98, 0x0418), MFP_ADDR_X(GPIO7_2, GPIO12_2, 0x052C), @@ -98,13 +98,13 @@ static struct clk_lookup pxa310_clkregs[] = { static int __init pxa300_init(void) { if (cpu_is_pxa300() || cpu_is_pxa310()) { - pxa3xx_init_mfp(); - pxa3xx_mfp_init_addr(pxa300_mfp_addr_map); + mfp_init_base(io_p2v(MFPR_BASE)); + mfp_init_addr(pxa300_mfp_addr_map); clks_register(ARRAY_AND_SIZE(common_clkregs)); } if (cpu_is_pxa310()) { - pxa3xx_mfp_init_addr(pxa310_mfp_addr_map); + mfp_init_addr(pxa310_mfp_addr_map); clks_register(ARRAY_AND_SIZE(pxa310_clkregs)); } diff --git a/arch/arm/mach-pxa/pxa320.c b/arch/arm/mach-pxa/pxa320.c index e708f4e0eca..8b3d97efada 100644 --- a/arch/arm/mach-pxa/pxa320.c +++ b/arch/arm/mach-pxa/pxa320.c @@ -23,7 +23,7 @@ #include "devices.h" #include "clock.h" -static struct pxa3xx_mfp_addr_map pxa320_mfp_addr_map[] __initdata = { +static struct mfp_addr_map pxa320_mfp_addr_map[] __initdata = { MFP_ADDR_X(GPIO0, GPIO4, 0x0124), MFP_ADDR_X(GPIO5, GPIO9, 0x028C), @@ -86,8 +86,8 @@ static struct clk_lookup pxa320_clkregs[] = { static int __init pxa320_init(void) { if (cpu_is_pxa320()) { - pxa3xx_init_mfp(); - pxa3xx_mfp_init_addr(pxa320_mfp_addr_map); + mfp_init_base(io_p2v(MFPR_BASE)); + mfp_init_addr(pxa320_mfp_addr_map); clks_register(ARRAY_AND_SIZE(pxa320_clkregs)); } diff --git a/arch/arm/mach-pxa/pxa930.c b/arch/arm/mach-pxa/pxa930.c index f15dfa55f27..71131742fff 100644 --- a/arch/arm/mach-pxa/pxa930.c +++ b/arch/arm/mach-pxa/pxa930.c @@ -18,7 +18,7 @@ #include -static struct pxa3xx_mfp_addr_map pxa930_mfp_addr_map[] __initdata = { +static struct mfp_addr_map pxa930_mfp_addr_map[] __initdata = { MFP_ADDR(GPIO0, 0x02e0), MFP_ADDR(GPIO1, 0x02dc), @@ -179,8 +179,8 @@ static struct pxa3xx_mfp_addr_map pxa930_mfp_addr_map[] __initdata = { static int __init pxa930_init(void) { if (cpu_is_pxa930()) { - pxa3xx_init_mfp(); - pxa3xx_mfp_init_addr(pxa930_mfp_addr_map); + mfp_init_base(io_p2v(MFPR_BASE)); + mfp_init_addr(pxa930_mfp_addr_map); } return 0; diff --git a/arch/arm/plat-pxa/Makefile b/arch/arm/plat-pxa/Makefile index b837df44048..4be37235f57 100644 --- a/arch/arm/plat-pxa/Makefile +++ b/arch/arm/plat-pxa/Makefile @@ -2,6 +2,6 @@ # Makefile for code common across different PXA processor families # -obj-y := dma.o +obj-y := dma.o mfp.o obj-$(CONFIG_GENERIC_GPIO) += gpio.o diff --git a/arch/arm/plat-pxa/include/plat/mfp.h b/arch/arm/plat-pxa/include/plat/mfp.h new file mode 100644 index 00000000000..a22229cde09 --- /dev/null +++ b/arch/arm/plat-pxa/include/plat/mfp.h @@ -0,0 +1,369 @@ +/* + * arch/arm/plat-pxa/include/plat/mfp.h + * + * Common Multi-Function Pin Definitions + * + * Copyright (C) 2007 Marvell International Ltd. + * + * 2007-8-21: eric miao + * initial version + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __ASM_PLAT_MFP_H +#define __ASM_PLAT_MFP_H + +#define mfp_to_gpio(m) ((m) % 128) + +/* list of all the configurable MFP pins */ +enum { + MFP_PIN_INVALID = -1, + + MFP_PIN_GPIO0 = 0, + MFP_PIN_GPIO1, + MFP_PIN_GPIO2, + MFP_PIN_GPIO3, + MFP_PIN_GPIO4, + MFP_PIN_GPIO5, + MFP_PIN_GPIO6, + MFP_PIN_GPIO7, + MFP_PIN_GPIO8, + MFP_PIN_GPIO9, + MFP_PIN_GPIO10, + MFP_PIN_GPIO11, + MFP_PIN_GPIO12, + MFP_PIN_GPIO13, + MFP_PIN_GPIO14, + MFP_PIN_GPIO15, + MFP_PIN_GPIO16, + MFP_PIN_GPIO17, + MFP_PIN_GPIO18, + MFP_PIN_GPIO19, + MFP_PIN_GPIO20, + MFP_PIN_GPIO21, + MFP_PIN_GPIO22, + MFP_PIN_GPIO23, + MFP_PIN_GPIO24, + MFP_PIN_GPIO25, + MFP_PIN_GPIO26, + MFP_PIN_GPIO27, + MFP_PIN_GPIO28, + MFP_PIN_GPIO29, + MFP_PIN_GPIO30, + MFP_PIN_GPIO31, + MFP_PIN_GPIO32, + MFP_PIN_GPIO33, + MFP_PIN_GPIO34, + MFP_PIN_GPIO35, + MFP_PIN_GPIO36, + MFP_PIN_GPIO37, + MFP_PIN_GPIO38, + MFP_PIN_GPIO39, + MFP_PIN_GPIO40, + MFP_PIN_GPIO41, + MFP_PIN_GPIO42, + MFP_PIN_GPIO43, + MFP_PIN_GPIO44, + MFP_PIN_GPIO45, + MFP_PIN_GPIO46, + MFP_PIN_GPIO47, + MFP_PIN_GPIO48, + MFP_PIN_GPIO49, + MFP_PIN_GPIO50, + MFP_PIN_GPIO51, + MFP_PIN_GPIO52, + MFP_PIN_GPIO53, + MFP_PIN_GPIO54, + MFP_PIN_GPIO55, + MFP_PIN_GPIO56, + MFP_PIN_GPIO57, + MFP_PIN_GPIO58, + MFP_PIN_GPIO59, + MFP_PIN_GPIO60, + MFP_PIN_GPIO61, + MFP_PIN_GPIO62, + MFP_PIN_GPIO63, + MFP_PIN_GPIO64, + MFP_PIN_GPIO65, + MFP_PIN_GPIO66, + MFP_PIN_GPIO67, + MFP_PIN_GPIO68, + MFP_PIN_GPIO69, + MFP_PIN_GPIO70, + MFP_PIN_GPIO71, + MFP_PIN_GPIO72, + MFP_PIN_GPIO73, + MFP_PIN_GPIO74, + MFP_PIN_GPIO75, + MFP_PIN_GPIO76, + MFP_PIN_GPIO77, + MFP_PIN_GPIO78, + MFP_PIN_GPIO79, + MFP_PIN_GPIO80, + MFP_PIN_GPIO81, + MFP_PIN_GPIO82, + MFP_PIN_GPIO83, + MFP_PIN_GPIO84, + MFP_PIN_GPIO85, + MFP_PIN_GPIO86, + MFP_PIN_GPIO87, + MFP_PIN_GPIO88, + MFP_PIN_GPIO89, + MFP_PIN_GPIO90, + MFP_PIN_GPIO91, + MFP_PIN_GPIO92, + MFP_PIN_GPIO93, + MFP_PIN_GPIO94, + MFP_PIN_GPIO95, + MFP_PIN_GPIO96, + MFP_PIN_GPIO97, + MFP_PIN_GPIO98, + MFP_PIN_GPIO99, + MFP_PIN_GPIO100, + MFP_PIN_GPIO101, + MFP_PIN_GPIO102, + MFP_PIN_GPIO103, + MFP_PIN_GPIO104, + MFP_PIN_GPIO105, + MFP_PIN_GPIO106, + MFP_PIN_GPIO107, + MFP_PIN_GPIO108, + MFP_PIN_GPIO109, + MFP_PIN_GPIO110, + MFP_PIN_GPIO111, + MFP_PIN_GPIO112, + MFP_PIN_GPIO113, + MFP_PIN_GPIO114, + MFP_PIN_GPIO115, + MFP_PIN_GPIO116, + MFP_PIN_GPIO117, + MFP_PIN_GPIO118, + MFP_PIN_GPIO119, + MFP_PIN_GPIO120, + MFP_PIN_GPIO121, + MFP_PIN_GPIO122, + MFP_PIN_GPIO123, + MFP_PIN_GPIO124, + MFP_PIN_GPIO125, + MFP_PIN_GPIO126, + MFP_PIN_GPIO127, + MFP_PIN_GPIO0_2, + MFP_PIN_GPIO1_2, + MFP_PIN_GPIO2_2, + MFP_PIN_GPIO3_2, + MFP_PIN_GPIO4_2, + MFP_PIN_GPIO5_2, + MFP_PIN_GPIO6_2, + MFP_PIN_GPIO7_2, + MFP_PIN_GPIO8_2, + MFP_PIN_GPIO9_2, + MFP_PIN_GPIO10_2, + MFP_PIN_GPIO11_2, + MFP_PIN_GPIO12_2, + MFP_PIN_GPIO13_2, + MFP_PIN_GPIO14_2, + MFP_PIN_GPIO15_2, + MFP_PIN_GPIO16_2, + MFP_PIN_GPIO17_2, + + MFP_PIN_ULPI_STP, + MFP_PIN_ULPI_NXT, + MFP_PIN_ULPI_DIR, + + MFP_PIN_nXCVREN, + MFP_PIN_DF_CLE_nOE, + MFP_PIN_DF_nADV1_ALE, + MFP_PIN_DF_SCLK_E, + MFP_PIN_DF_SCLK_S, + MFP_PIN_nBE0, + MFP_PIN_nBE1, + MFP_PIN_DF_nADV2_ALE, + MFP_PIN_DF_INT_RnB, + MFP_PIN_DF_nCS0, + MFP_PIN_DF_nCS1, + MFP_PIN_nLUA, + MFP_PIN_nLLA, + MFP_PIN_DF_nWE, + MFP_PIN_DF_ALE_nWE, + MFP_PIN_DF_nRE_nOE, + MFP_PIN_DF_ADDR0, + MFP_PIN_DF_ADDR1, + MFP_PIN_DF_ADDR2, + MFP_PIN_DF_ADDR3, + MFP_PIN_DF_IO0, + MFP_PIN_DF_IO1, + MFP_PIN_DF_IO2, + MFP_PIN_DF_IO3, + MFP_PIN_DF_IO4, + MFP_PIN_DF_IO5, + MFP_PIN_DF_IO6, + MFP_PIN_DF_IO7, + MFP_PIN_DF_IO8, + MFP_PIN_DF_IO9, + MFP_PIN_DF_IO10, + MFP_PIN_DF_IO11, + MFP_PIN_DF_IO12, + MFP_PIN_DF_IO13, + MFP_PIN_DF_IO14, + MFP_PIN_DF_IO15, + + /* additional pins on PXA930 */ + MFP_PIN_GSIM_UIO, + MFP_PIN_GSIM_UCLK, + MFP_PIN_GSIM_UDET, + MFP_PIN_GSIM_nURST, + MFP_PIN_PMIC_INT, + MFP_PIN_RDY, + + MFP_PIN_MAX, +}; + +/* + * a possible MFP configuration is represented by a 32-bit integer + * + * bit 0.. 9 - MFP Pin Number (1024 Pins Maximum) + * bit 10..12 - Alternate Function Selection + * bit 13..15 - Drive Strength + * bit 16..18 - Low Power Mode State + * bit 19..20 - Low Power Mode Edge Detection + * bit 21..22 - Run Mode Pull State + * + * to facilitate the definition, the following macros are provided + * + * MFP_CFG_DEFAULT - default MFP configuration value, with + * alternate function = 0, + * drive strength = fast 3mA (MFP_DS03X) + * low power mode = default + * edge detection = none + * + * MFP_CFG - default MFPR value with alternate function + * MFP_CFG_DRV - default MFPR value with alternate function and + * pin drive strength + * MFP_CFG_LPM - default MFPR value with alternate function and + * low power mode + * MFP_CFG_X - default MFPR value with alternate function, + * pin drive strength and low power mode + */ + +typedef unsigned long mfp_cfg_t; + +#define MFP_PIN(x) ((x) & 0x3ff) + +#define MFP_AF0 (0x0 << 10) +#define MFP_AF1 (0x1 << 10) +#define MFP_AF2 (0x2 << 10) +#define MFP_AF3 (0x3 << 10) +#define MFP_AF4 (0x4 << 10) +#define MFP_AF5 (0x5 << 10) +#define MFP_AF6 (0x6 << 10) +#define MFP_AF7 (0x7 << 10) +#define MFP_AF_MASK (0x7 << 10) +#define MFP_AF(x) (((x) >> 10) & 0x7) + +#define MFP_DS01X (0x0 << 13) +#define MFP_DS02X (0x1 << 13) +#define MFP_DS03X (0x2 << 13) +#define MFP_DS04X (0x3 << 13) +#define MFP_DS06X (0x4 << 13) +#define MFP_DS08X (0x5 << 13) +#define MFP_DS10X (0x6 << 13) +#define MFP_DS13X (0x7 << 13) +#define MFP_DS_MASK (0x7 << 13) +#define MFP_DS(x) (((x) >> 13) & 0x7) + +#define MFP_LPM_DEFAULT (0x0 << 16) +#define MFP_LPM_DRIVE_LOW (0x1 << 16) +#define MFP_LPM_DRIVE_HIGH (0x2 << 16) +#define MFP_LPM_PULL_LOW (0x3 << 16) +#define MFP_LPM_PULL_HIGH (0x4 << 16) +#define MFP_LPM_FLOAT (0x5 << 16) +#define MFP_LPM_INPUT (0x6 << 16) +#define MFP_LPM_STATE_MASK (0x7 << 16) +#define MFP_LPM_STATE(x) (((x) >> 16) & 0x7) + +#define MFP_LPM_EDGE_NONE (0x0 << 19) +#define MFP_LPM_EDGE_RISE (0x1 << 19) +#define MFP_LPM_EDGE_FALL (0x2 << 19) +#define MFP_LPM_EDGE_BOTH (0x3 << 19) +#define MFP_LPM_EDGE_MASK (0x3 << 19) +#define MFP_LPM_EDGE(x) (((x) >> 19) & 0x3) + +#define MFP_PULL_NONE (0x0 << 21) +#define MFP_PULL_LOW (0x1 << 21) +#define MFP_PULL_HIGH (0x2 << 21) +#define MFP_PULL_BOTH (0x3 << 21) +#define MFP_PULL_MASK (0x3 << 21) +#define MFP_PULL(x) (((x) >> 21) & 0x3) + +#define MFP_CFG_DEFAULT (MFP_AF0 | MFP_DS03X | MFP_LPM_DEFAULT |\ + MFP_LPM_EDGE_NONE | MFP_PULL_NONE) + +#define MFP_CFG(pin, af) \ + ((MFP_CFG_DEFAULT & ~MFP_AF_MASK) |\ + (MFP_PIN(MFP_PIN_##pin) | MFP_##af)) + +#define MFP_CFG_DRV(pin, af, drv) \ + ((MFP_CFG_DEFAULT & ~(MFP_AF_MASK | MFP_DS_MASK)) |\ + (MFP_PIN(MFP_PIN_##pin) | MFP_##af | MFP_##drv)) + +#define MFP_CFG_LPM(pin, af, lpm) \ + ((MFP_CFG_DEFAULT & ~(MFP_AF_MASK | MFP_LPM_STATE_MASK)) |\ + (MFP_PIN(MFP_PIN_##pin) | MFP_##af | MFP_LPM_##lpm)) + +#define MFP_CFG_X(pin, af, drv, lpm) \ + ((MFP_CFG_DEFAULT & ~(MFP_AF_MASK | MFP_DS_MASK | MFP_LPM_STATE_MASK)) |\ + (MFP_PIN(MFP_PIN_##pin) | MFP_##af | MFP_##drv | MFP_LPM_##lpm)) + +#if defined(CONFIG_PXA3xx) || defined(CONFIG_ARCH_MMP) +/* + * each MFP pin will have a MFPR register, since the offset of the + * register varies between processors, the processor specific code + * should initialize the pin offsets by mfp_init() + * + * mfp_init_base() - accepts a virtual base for all MFPR registers and + * initialize the MFP table to a default state + * + * mfp_init_addr() - accepts a table of "mfp_addr_map" structure, which + * represents a range of MFP pins from "start" to "end", with the offset + * begining at "offset", to define a single pin, let "end" = -1. + * + * use + * + * MFP_ADDR_X() to define a range of pins + * MFP_ADDR() to define a single pin + * MFP_ADDR_END to signal the end of pin offset definitions + */ +struct mfp_addr_map { + unsigned int start; + unsigned int end; + unsigned long offset; +}; + +#define MFP_ADDR_X(start, end, offset) \ + { MFP_PIN_##start, MFP_PIN_##end, offset } + +#define MFP_ADDR(pin, offset) \ + { MFP_PIN_##pin, -1, offset } + +#define MFP_ADDR_END { MFP_PIN_INVALID, 0 } + +void __init mfp_init_base(unsigned long mfpr_base); +void __init mfp_init_addr(struct mfp_addr_map *map); + +/* + * mfp_{read, write}() - for direct read/write access to the MFPR register + * mfp_config() - for configuring a group of MFPR registers + * mfp_config_lpm() - configuring all low power MFPR registers for suspend + * mfp_config_run() - configuring all run time MFPR registers after resume + */ +unsigned long mfp_read(int mfp); +void mfp_write(int mfp, unsigned long mfpr_val); +void mfp_config(unsigned long *mfp_cfgs, int num); +void mfp_config_run(void); +void mfp_config_lpm(void); +#endif /* CONFIG_PXA3xx || CONFIG_ARCH_MMP */ + +#endif /* __ASM_PLAT_MFP_H */ diff --git a/arch/arm/plat-pxa/mfp.c b/arch/arm/plat-pxa/mfp.c new file mode 100644 index 00000000000..e716c622a17 --- /dev/null +++ b/arch/arm/plat-pxa/mfp.c @@ -0,0 +1,278 @@ +/* + * linux/arch/arm/plat-pxa/mfp.c + * + * Multi-Function Pin Support + * + * Copyright (C) 2007 Marvell Internation Ltd. + * + * 2007-08-21: eric miao + * initial version + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include + +#define MFPR_SIZE (PAGE_SIZE) + +/* MFPR register bit definitions */ +#define MFPR_PULL_SEL (0x1 << 15) +#define MFPR_PULLUP_EN (0x1 << 14) +#define MFPR_PULLDOWN_EN (0x1 << 13) +#define MFPR_SLEEP_SEL (0x1 << 9) +#define MFPR_SLEEP_OE_N (0x1 << 7) +#define MFPR_EDGE_CLEAR (0x1 << 6) +#define MFPR_EDGE_FALL_EN (0x1 << 5) +#define MFPR_EDGE_RISE_EN (0x1 << 4) + +#define MFPR_SLEEP_DATA(x) ((x) << 8) +#define MFPR_DRIVE(x) (((x) & 0x7) << 10) +#define MFPR_AF_SEL(x) (((x) & 0x7) << 0) + +#define MFPR_EDGE_NONE (0) +#define MFPR_EDGE_RISE (MFPR_EDGE_RISE_EN) +#define MFPR_EDGE_FALL (MFPR_EDGE_FALL_EN) +#define MFPR_EDGE_BOTH (MFPR_EDGE_RISE | MFPR_EDGE_FALL) + +/* + * Table that determines the low power modes outputs, with actual settings + * used in parentheses for don't-care values. Except for the float output, + * the configured driven and pulled levels match, so if there is a need for + * non-LPM pulled output, the same configuration could probably be used. + * + * Output value sleep_oe_n sleep_data pullup_en pulldown_en pull_sel + * (bit 7) (bit 8) (bit 14) (bit 13) (bit 15) + * + * Input 0 X(0) X(0) X(0) 0 + * Drive 0 0 0 0 X(1) 0 + * Drive 1 0 1 X(1) 0 0 + * Pull hi (1) 1 X(1) 1 0 0 + * Pull lo (0) 1 X(0) 0 1 0 + * Z (float) 1 X(0) 0 0 0 + */ +#define MFPR_LPM_INPUT (0) +#define MFPR_LPM_DRIVE_LOW (MFPR_SLEEP_DATA(0) | MFPR_PULLDOWN_EN) +#define MFPR_LPM_DRIVE_HIGH (MFPR_SLEEP_DATA(1) | MFPR_PULLUP_EN) +#define MFPR_LPM_PULL_LOW (MFPR_LPM_DRIVE_LOW | MFPR_SLEEP_OE_N) +#define MFPR_LPM_PULL_HIGH (MFPR_LPM_DRIVE_HIGH | MFPR_SLEEP_OE_N) +#define MFPR_LPM_FLOAT (MFPR_SLEEP_OE_N) +#define MFPR_LPM_MASK (0xe080) + +/* + * The pullup and pulldown state of the MFP pin at run mode is by default + * determined by the selected alternate function. In case that some buggy + * devices need to override this default behavior, the definitions below + * indicates the setting of corresponding MFPR bits + * + * Definition pull_sel pullup_en pulldown_en + * MFPR_PULL_NONE 0 0 0 + * MFPR_PULL_LOW 1 0 1 + * MFPR_PULL_HIGH 1 1 0 + * MFPR_PULL_BOTH 1 1 1 + */ +#define MFPR_PULL_NONE (0) +#define MFPR_PULL_LOW (MFPR_PULL_SEL | MFPR_PULLDOWN_EN) +#define MFPR_PULL_BOTH (MFPR_PULL_LOW | MFPR_PULLUP_EN) +#define MFPR_PULL_HIGH (MFPR_PULL_SEL | MFPR_PULLUP_EN) + +/* mfp_spin_lock is used to ensure that MFP register configuration + * (most likely a read-modify-write operation) is atomic, and that + * mfp_table[] is consistent + */ +static DEFINE_SPINLOCK(mfp_spin_lock); + +static void __iomem *mfpr_mmio_base; + +struct mfp_pin { + unsigned long config; /* -1 for not configured */ + unsigned long mfpr_off; /* MFPRxx Register offset */ + unsigned long mfpr_run; /* Run-Mode Register Value */ + unsigned long mfpr_lpm; /* Low Power Mode Register Value */ +}; + +static struct mfp_pin mfp_table[MFP_PIN_MAX]; + +/* mapping of MFP_LPM_* definitions to MFPR_LPM_* register bits */ +static const unsigned long mfpr_lpm[] = { + MFPR_LPM_INPUT, + MFPR_LPM_DRIVE_LOW, + MFPR_LPM_DRIVE_HIGH, + MFPR_LPM_PULL_LOW, + MFPR_LPM_PULL_HIGH, + MFPR_LPM_FLOAT, +}; + +/* mapping of MFP_PULL_* definitions to MFPR_PULL_* register bits */ +static const unsigned long mfpr_pull[] = { + MFPR_PULL_NONE, + MFPR_PULL_LOW, + MFPR_PULL_HIGH, + MFPR_PULL_BOTH, +}; + +/* mapping of MFP_LPM_EDGE_* definitions to MFPR_EDGE_* register bits */ +static const unsigned long mfpr_edge[] = { + MFPR_EDGE_NONE, + MFPR_EDGE_RISE, + MFPR_EDGE_FALL, + MFPR_EDGE_BOTH, +}; + +#define mfpr_readl(off) \ + __raw_readl(mfpr_mmio_base + (off)) + +#define mfpr_writel(off, val) \ + __raw_writel(val, mfpr_mmio_base + (off)) + +#define mfp_configured(p) ((p)->config != -1) + +/* + * perform a read-back of any MFPR register to make sure the + * previous writings are finished + */ +#define mfpr_sync() (void)__raw_readl(mfpr_mmio_base + 0) + +static inline void __mfp_config_run(struct mfp_pin *p) +{ + if (mfp_configured(p)) + mfpr_writel(p->mfpr_off, p->mfpr_run); +} + +static inline void __mfp_config_lpm(struct mfp_pin *p) +{ + if (mfp_configured(p)) { + unsigned long mfpr_clr = (p->mfpr_run & ~MFPR_EDGE_BOTH) | MFPR_EDGE_CLEAR; + if (mfpr_clr != p->mfpr_run) + mfpr_writel(p->mfpr_off, mfpr_clr); + if (p->mfpr_lpm != mfpr_clr) + mfpr_writel(p->mfpr_off, p->mfpr_lpm); + } +} + +void mfp_config(unsigned long *mfp_cfgs, int num) +{ + unsigned long flags; + int i; + + spin_lock_irqsave(&mfp_spin_lock, flags); + + for (i = 0; i < num; i++, mfp_cfgs++) { + unsigned long tmp, c = *mfp_cfgs; + struct mfp_pin *p; + int pin, af, drv, lpm, edge, pull; + + pin = MFP_PIN(c); + BUG_ON(pin >= MFP_PIN_MAX); + p = &mfp_table[pin]; + + af = MFP_AF(c); + drv = MFP_DS(c); + lpm = MFP_LPM_STATE(c); + edge = MFP_LPM_EDGE(c); + pull = MFP_PULL(c); + + /* run-mode pull settings will conflict with MFPR bits of + * low power mode state, calculate mfpr_run and mfpr_lpm + * individually if pull != MFP_PULL_NONE + */ + tmp = MFPR_AF_SEL(af) | MFPR_DRIVE(drv); + + if (likely(pull == MFP_PULL_NONE)) { + p->mfpr_run = tmp | mfpr_lpm[lpm] | mfpr_edge[edge]; + p->mfpr_lpm = p->mfpr_run; + } else { + p->mfpr_lpm = tmp | mfpr_lpm[lpm] | mfpr_edge[edge]; + p->mfpr_run = tmp | mfpr_pull[pull]; + } + + p->config = c; __mfp_config_run(p); + } + + mfpr_sync(); + spin_unlock_irqrestore(&mfp_spin_lock, flags); +} + +unsigned long mfp_read(int mfp) +{ + unsigned long val, flags; + + BUG_ON(mfp >= MFP_PIN_MAX); + + spin_lock_irqsave(&mfp_spin_lock, flags); + val = mfpr_readl(mfp_table[mfp].mfpr_off); + spin_unlock_irqrestore(&mfp_spin_lock, flags); + + return val; +} + +void mfp_write(int mfp, unsigned long val) +{ + unsigned long flags; + + BUG_ON(mfp >= MFP_PIN_MAX); + + spin_lock_irqsave(&mfp_spin_lock, flags); + mfpr_writel(mfp_table[mfp].mfpr_off, val); + mfpr_sync(); + spin_unlock_irqrestore(&mfp_spin_lock, flags); +} + +void __init mfp_init_base(unsigned long mfpr_base) +{ + int i; + + /* initialize the table with default - unconfigured */ + for (i = 0; i < ARRAY_SIZE(mfp_table); i++) + mfp_table[i].config = -1; + + mfpr_mmio_base = (void __iomem *)mfpr_base; +} + +void __init mfp_init_addr(struct mfp_addr_map *map) +{ + struct mfp_addr_map *p; + unsigned long offset, flags; + int i; + + spin_lock_irqsave(&mfp_spin_lock, flags); + + for (p = map; p->start != MFP_PIN_INVALID; p++) { + offset = p->offset; + i = p->start; + + do { + mfp_table[i].mfpr_off = offset; + mfp_table[i].mfpr_run = 0; + mfp_table[i].mfpr_lpm = 0; + offset += 4; i++; + } while ((i <= p->end) && (p->end != -1)); + } + + spin_unlock_irqrestore(&mfp_spin_lock, flags); +} + +void mfp_config_lpm(void) +{ + struct mfp_pin *p = &mfp_table[0]; + int pin; + + for (pin = 0; pin < ARRAY_SIZE(mfp_table); pin++, p++) + __mfp_config_lpm(p); +} + +void mfp_config_run(void) +{ + struct mfp_pin *p = &mfp_table[0]; + int pin; + + for (pin = 0; pin < ARRAY_SIZE(mfp_table); pin++, p++) + __mfp_config_run(p); +} -- cgit v1.2.3-70-g09d2