[PATCH 8/9] lpc2k: Add UART, SSP, and MCI devices

Ithamar R. Adema ithamar.adema at team-embedded.nl
Thu Mar 17 11:54:23 EDT 2011


Adds devices for which the drivers are already in the tree. For
the relevant devices, let the lpc2478oem board set them up.

Signed-off-by: Ithamar R. Adema <ithamar.adema at team-embedded.nl>
---
 arch/arm/Kconfig                            |    1 +
 arch/arm/mach-lpc2k/Makefile                |    2 +-
 arch/arm/mach-lpc2k/common.h                |    4 +
 arch/arm/mach-lpc2k/devices.c               |  174 +++++++++++++++++++++++++++
 arch/arm/mach-lpc2k/include/mach/hardware.h |    6 +
 arch/arm/mach-lpc2k/mach-lpc2478oem.c       |   20 +++
 6 files changed, 206 insertions(+), 1 deletions(-)
 create mode 100644 arch/arm/mach-lpc2k/devices.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index fce855d..1735b02 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -496,6 +496,7 @@ config ARCH_LPC2K
 	depends on !MMU
 	select CPU_ARM7TDMI
 	select ARM_VIC
+	select ARM_AMBA
 	select CLKDEV_LOOKUP
 	select GENERIC_TIME
 	select GENERIC_CLOCKEVENTS
diff --git a/arch/arm/mach-lpc2k/Makefile b/arch/arm/mach-lpc2k/Makefile
index a969f44..af6a1c2 100644
--- a/arch/arm/mach-lpc2k/Makefile
+++ b/arch/arm/mach-lpc2k/Makefile
@@ -1,3 +1,3 @@
 obj-y	:= clock.o irq.o gpio.o mfp.o time.o
 
-obj-$(CONFIG_MACH_LPC2478OEM) += mach-lpc2478oem.o
+obj-$(CONFIG_MACH_LPC2478OEM) += mach-lpc2478oem.o devices.o
diff --git a/arch/arm/mach-lpc2k/common.h b/arch/arm/mach-lpc2k/common.h
index 6b775d9..1d4c21e 100644
--- a/arch/arm/mach-lpc2k/common.h
+++ b/arch/arm/mach-lpc2k/common.h
@@ -16,6 +16,10 @@ extern void lpc2k_init_clocks(unsigned long xtal, unsigned long rtc);
 extern void lpc2k_mfp_config(unsigned long *mfp_cfgs, int num);
 extern void lpc2k_init_irq(void);
 
+extern void lpc2k_add_uart(int nr);
+extern void lpc2k_add_ssp(int nr, void *platform_data);
+extern void lpc2k_add_mci(void *platform_data, int pwr_high);
+
 extern struct sys_timer lpc2k_timer;
 
 #endif /* LPC2K_COMMON_H */
diff --git a/arch/arm/mach-lpc2k/devices.c b/arch/arm/mach-lpc2k/devices.c
new file mode 100644
index 0000000..8855e8a
--- /dev/null
+++ b/arch/arm/mach-lpc2k/devices.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2011 Team Embeded VOF
+ *     Ithamar R. Adema <ihamar.adema at team-embedded.nl>
+ *
+ * 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 <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/serial_8250.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <linux/amba/bus.h>
+#include <linux/amba/mmci.h>
+#include <linux/amba/pl022.h>
+
+#include <mach/hardware.h>
+
+/* System Control Block - System Controls and Status register */
+#define SCS		0x1a0
+
+#define __IORESOURCE_MEM_16K(x)	{	\
+	.start = x,			\
+	.end   = x + SZ_16K - 1,	\
+	.flags = IORESOURCE_MEM,	\
+	}
+
+#define __IORESOURCE_IRQ(x)	{	\
+	.start = x,			\
+	. end  = x,			\
+	}
+
+/* UARTs
+ *   0/1 are available on all LPC2Ks
+ *   2/3 are available on LPC23XX and up.
+ *
+ * NOTE: the dev.init_name assignment is there so we can use the clk API to
+ *       retrieve and enable the clock, since dev_name() is called from
+ *       the clk_get implementation before the platform device is registered.
+ */
+
+#define LPC2K_UART(uartnum) \
+	static struct plat_serial8250_port lpc2k_pdata_uart##uartnum[] = { \
+		{ \
+			.mapbase	= APB_UART##uartnum##_BASE, \
+			.membase	= (void __iomem *) \
+						APB_UART##uartnum##_BASE, \
+			.irq		= IRQ_LPC2K_UART##uartnum, \
+			.flags		= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, \
+			.iotype		= UPIO_MEM, \
+			.regshift	= 2, \
+			.uartclk	= 0, \
+		}, \
+		{ }, \
+	}; \
+	static struct resource lpc2k_resources_uart##uartnum[] = { \
+		[0] = __IORESOURCE_MEM_16K(APB_UART##uartnum##_BASE), \
+		[1] = __IORESOURCE_IRQ(IRQ_LPC2K_UART##uartnum), \
+	}; \
+	static struct platform_device lpc2k_device_uart##uartnum = { \
+		.dev = { \
+			.init_name = "serial8250." __stringify(uartnum), \
+			.platform_data = lpc2k_pdata_uart##uartnum, \
+		}, \
+		.name		= "serial8250", \
+		.id		= uartnum, \
+		.resource	= lpc2k_resources_uart##uartnum, \
+		.num_resources	= ARRAY_SIZE(lpc2k_resources_uart##uartnum), \
+	}
+
+
+LPC2K_UART(0);
+LPC2K_UART(1);
+LPC2K_UART(2);
+LPC2K_UART(3);
+
+static struct platform_device *uarts[] __initdata = {
+	&lpc2k_device_uart0,
+	&lpc2k_device_uart1,
+	&lpc2k_device_uart2,
+	&lpc2k_device_uart3,
+};
+
+void __init lpc2k_add_uart(int nr)
+{
+	struct platform_device *pdev;
+	struct clk *clk;
+	int res;
+
+	BUG_ON(nr < 0 || nr > ARRAY_SIZE(uarts));
+	pdev = uarts[nr];
+
+	clk = clk_get(&pdev->dev, NULL);
+	BUG_ON(IS_ERR(clk));
+	clk_enable(clk);
+	((struct plat_serial8250_port *)pdev->dev.platform_data)->uartclk =
+		clk_get_rate(clk);
+	clk_put(clk);
+
+	res = platform_device_register(pdev);
+	if (res)
+		dev_err(&pdev->dev, "Unable to register: %d\n", res);
+}
+
+/* SSP, aka pl022
+ *
+ * 1-only available on enhanced LPC21XX and LPC22XX.
+ * 0/1 available on LPC23XX and up.
+ */
+
+static struct amba_device lpc2k_device_ssp0 = {
+	.dev = {
+		.coherent_dma_mask = ~0,
+		.init_name = "ssp0",
+	},
+	.res = __IORESOURCE_MEM_16K(APB_SSP0_BASE),
+	.irq = { IRQ_LPC2K_SPI0, NO_IRQ },
+};
+
+static struct amba_device lpc2k_device_ssp1 = {
+	.dev = {
+		.coherent_dma_mask = ~0,
+		.init_name = "ssp1",
+	},
+	.res = __IORESOURCE_MEM_16K(APB_SSP1_BASE),
+	.irq = { IRQ_LPC2K_SPI1, NO_IRQ },
+};
+
+void __init lpc2k_add_ssp(int nr, void *platform_data)
+{
+	struct amba_device *adev;
+	int res;
+
+	BUG_ON(nr < 0 || nr > 1);
+	adev = nr ? &lpc2k_device_ssp1 : &lpc2k_device_ssp0;
+	adev->dev.platform_data = platform_data;
+
+	res = amba_device_register(adev, &iomem_resource);
+	if (res)
+		dev_err(&adev->dev, "Unable to register: %d\n", res);
+}
+
+/* SD/MMC, aka pl180/1
+ *
+ * Available on LPC23XX and up.
+ */
+
+static struct amba_device lpc2k_device_mci = {
+	.dev = {
+		.coherent_dma_mask = ~0,
+		.init_name = "mci",
+	},
+	.res = __IORESOURCE_MEM_16K(APB_MCI_BASE),
+	.irq = { IRQ_LPC2K_MCI, NO_IRQ },
+};
+
+void __init lpc2k_add_mci(void *platform_data, int pwr_high)
+{
+	int res;
+	u32 scs;
+
+	/* Set MCIPWR pin to be active high or low */
+	scs = ioread32(APB_SCB_BASE + SCS);
+	scs = pwr_high ? scs | (1 << 3) : scs & ~(1 << 3);
+	iowrite32(scs, APB_SCB_BASE + SCS);
+
+	lpc2k_device_mci.dev.platform_data = platform_data;
+	res = amba_device_register(&lpc2k_device_mci, &iomem_resource);
+	if (res)
+		dev_err(&lpc2k_device_mci.dev, "Unable to register: %d\n", res);
+}
diff --git a/arch/arm/mach-lpc2k/include/mach/hardware.h b/arch/arm/mach-lpc2k/include/mach/hardware.h
index 29c561a..3054a9e 100644
--- a/arch/arm/mach-lpc2k/include/mach/hardware.h
+++ b/arch/arm/mach-lpc2k/include/mach/hardware.h
@@ -19,8 +19,14 @@
 #define APB_TIMER0_BASE		0xe0004000
 #define APB_TIMER1_BASE		0xe0008000
 #define APB_UART0_BASE		0xe000c000
+#define APB_UART1_BASE		0xe0010000
 #define APB_GPIO_BASE		0xe0028000
 #define APB_PINSEL_BASE		0xe002c000
+#define APB_SSP1_BASE		0xe0030000
+#define APB_SSP0_BASE		0xe0068000
+#define APB_UART2_BASE		0xe0078000
+#define APB_UART3_BASE		0xe007c000
+#define APB_MCI_BASE		0xe008c000
 #define APB_SCB_BASE		0xe01fc000
 #define APH_VIC_BASE		0xfffff000
 
diff --git a/arch/arm/mach-lpc2k/mach-lpc2478oem.c b/arch/arm/mach-lpc2k/mach-lpc2478oem.c
index fec98e2..9261574 100644
--- a/arch/arm/mach-lpc2k/mach-lpc2478oem.c
+++ b/arch/arm/mach-lpc2k/mach-lpc2478oem.c
@@ -8,6 +8,8 @@
  */
 
 #include <linux/module.h>
+#include <linux/amba/pl022.h>
+#include <linux/amba/mmci.h>
 #include <linux/io.h>
 
 #include <asm/mach/arch.h>
@@ -95,9 +97,27 @@ static unsigned long mfp_cfgs[] = {
 	GPIO44_MCIDAT3,
 };
 
+static struct pl022_ssp_controller ssp0_plat_data = {
+	.bus_id = 0,
+	.enable_dma = 0,
+	.num_chipselect = 1,
+};
+
+static struct mmci_platform_data mci_plat_data = {
+	.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
+	.capabilities = MMC_CAP_4_BIT_DATA,
+	.f_max = 200000,
+	.gpio_cd = -1,
+	.gpio_wp = -1,
+};
+
 void __init lpc2478oem_init_machine(void)
 {
 	lpc2k_mfp_config(mfp_cfgs, ARRAY_SIZE(mfp_cfgs));
+
+	lpc2k_add_uart(0);
+	lpc2k_add_ssp(0, &ssp0_plat_data);
+	lpc2k_add_mci(&mci_plat_data, 0 /* active low */);
 }
 
 static void __init lpc2478oem_init_irq(void)
-- 
1.7.1




More information about the linux-arm-kernel mailing list