diff options
author | Kevin Wells <wellsk40@gmail.com> | 2010-07-27 11:44:37 -0400 |
---|---|---|
committer | Kevin Wells <wellsk40@gmail.com> | 2010-07-27 11:44:37 -0400 |
commit | 19d95e1afae11b1a414491fd62e89a47cceadea9 (patch) | |
tree | 19b2e37066cc0950dc0a40929c54103dbbdc2f3e /arch | |
parent | fc982e1ceaeb4dea3f3f8ceba5b934cee292944a (diff) |
ARM: LPC32XX: Phytec 3250 platform support
Platform support file for the PHY3250 mach id
Signed-off-by: Kevin Wells <wellsk40@gmail.com>
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-lpc32xx/phy3250.c | 397 |
1 files changed, 397 insertions, 0 deletions
diff --git a/arch/arm/mach-lpc32xx/phy3250.c b/arch/arm/mach-lpc32xx/phy3250.c new file mode 100644 index 000000000000..bc9a42da2145 --- /dev/null +++ b/arch/arm/mach-lpc32xx/phy3250.c | |||
@@ -0,0 +1,397 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-lpc32xx/phy3250.c | ||
3 | * | ||
4 | * Author: Kevin Wells <kevin.wells@nxp.com> | ||
5 | * | ||
6 | * Copyright (C) 2010 NXP Semiconductors | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | */ | ||
18 | |||
19 | #include <linux/init.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/sysdev.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/irq.h> | ||
24 | #include <linux/dma-mapping.h> | ||
25 | #include <linux/device.h> | ||
26 | #include <linux/spi/spi.h> | ||
27 | #include <linux/spi/eeprom.h> | ||
28 | #include <linux/leds.h> | ||
29 | #include <linux/gpio.h> | ||
30 | #include <linux/amba/bus.h> | ||
31 | #include <linux/amba/clcd.h> | ||
32 | #include <linux/amba/pl022.h> | ||
33 | |||
34 | #include <asm/setup.h> | ||
35 | #include <asm/mach-types.h> | ||
36 | #include <asm/mach/arch.h> | ||
37 | |||
38 | #include <mach/hardware.h> | ||
39 | #include <mach/platform.h> | ||
40 | #include "common.h" | ||
41 | |||
42 | /* | ||
43 | * Mapped GPIOLIB GPIOs | ||
44 | */ | ||
45 | #define SPI0_CS_GPIO LPC32XX_GPIO(LPC32XX_GPIO_P3_GRP, 5) | ||
46 | #define LCD_POWER_GPIO LPC32XX_GPIO(LPC32XX_GPO_P3_GRP, 0) | ||
47 | #define BKL_POWER_GPIO LPC32XX_GPIO(LPC32XX_GPO_P3_GRP, 4) | ||
48 | #define LED_GPIO LPC32XX_GPIO(LPC32XX_GPO_P3_GRP, 1) | ||
49 | |||
50 | /* | ||
51 | * AMBA LCD controller | ||
52 | */ | ||
53 | static struct clcd_panel conn_lcd_panel = { | ||
54 | .mode = { | ||
55 | .name = "QVGA portrait", | ||
56 | .refresh = 60, | ||
57 | .xres = 240, | ||
58 | .yres = 320, | ||
59 | .pixclock = 191828, | ||
60 | .left_margin = 22, | ||
61 | .right_margin = 11, | ||
62 | .upper_margin = 2, | ||
63 | .lower_margin = 1, | ||
64 | .hsync_len = 5, | ||
65 | .vsync_len = 2, | ||
66 | .sync = 0, | ||
67 | .vmode = FB_VMODE_NONINTERLACED, | ||
68 | }, | ||
69 | .width = -1, | ||
70 | .height = -1, | ||
71 | .tim2 = (TIM2_IVS | TIM2_IHS), | ||
72 | .cntl = (CNTL_BGR | CNTL_LCDTFT | CNTL_LCDVCOMP(1) | | ||
73 | CNTL_LCDBPP16_565), | ||
74 | .bpp = 16, | ||
75 | }; | ||
76 | #define PANEL_SIZE (3 * SZ_64K) | ||
77 | |||
78 | static int lpc32xx_clcd_setup(struct clcd_fb *fb) | ||
79 | { | ||
80 | dma_addr_t dma; | ||
81 | |||
82 | fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, | ||
83 | PANEL_SIZE, &dma, GFP_KERNEL); | ||
84 | if (!fb->fb.screen_base) { | ||
85 | printk(KERN_ERR "CLCD: unable to map framebuffer\n"); | ||
86 | return -ENOMEM; | ||
87 | } | ||
88 | |||
89 | fb->fb.fix.smem_start = dma; | ||
90 | fb->fb.fix.smem_len = PANEL_SIZE; | ||
91 | fb->panel = &conn_lcd_panel; | ||
92 | |||
93 | if (gpio_request(LCD_POWER_GPIO, "LCD power")) | ||
94 | printk(KERN_ERR "Error requesting gpio %u", | ||
95 | LCD_POWER_GPIO); | ||
96 | else if (gpio_direction_output(LCD_POWER_GPIO, 1)) | ||
97 | printk(KERN_ERR "Error setting gpio %u to output", | ||
98 | LCD_POWER_GPIO); | ||
99 | |||
100 | if (gpio_request(BKL_POWER_GPIO, "LCD backlight power")) | ||
101 | printk(KERN_ERR "Error requesting gpio %u", | ||
102 | BKL_POWER_GPIO); | ||
103 | else if (gpio_direction_output(BKL_POWER_GPIO, 1)) | ||
104 | printk(KERN_ERR "Error setting gpio %u to output", | ||
105 | BKL_POWER_GPIO); | ||
106 | |||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | static int lpc32xx_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma) | ||
111 | { | ||
112 | return dma_mmap_writecombine(&fb->dev->dev, vma, | ||
113 | fb->fb.screen_base, fb->fb.fix.smem_start, | ||
114 | fb->fb.fix.smem_len); | ||
115 | } | ||
116 | |||
117 | static void lpc32xx_clcd_remove(struct clcd_fb *fb) | ||
118 | { | ||
119 | dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len, | ||
120 | fb->fb.screen_base, fb->fb.fix.smem_start); | ||
121 | } | ||
122 | |||
123 | /* | ||
124 | * On some early LCD modules (1307.0), the backlight logic is inverted. | ||
125 | * For those board variants, swap the disable and enable states for | ||
126 | * BKL_POWER_GPIO. | ||
127 | */ | ||
128 | static void clcd_disable(struct clcd_fb *fb) | ||
129 | { | ||
130 | gpio_set_value(BKL_POWER_GPIO, 0); | ||
131 | gpio_set_value(LCD_POWER_GPIO, 0); | ||
132 | } | ||
133 | |||
134 | static void clcd_enable(struct clcd_fb *fb) | ||
135 | { | ||
136 | gpio_set_value(BKL_POWER_GPIO, 1); | ||
137 | gpio_set_value(LCD_POWER_GPIO, 1); | ||
138 | } | ||
139 | |||
140 | static struct clcd_board lpc32xx_clcd_data = { | ||
141 | .name = "Phytec LCD", | ||
142 | .check = clcdfb_check, | ||
143 | .decode = clcdfb_decode, | ||
144 | .disable = clcd_disable, | ||
145 | .enable = clcd_enable, | ||
146 | .setup = lpc32xx_clcd_setup, | ||
147 | .mmap = lpc32xx_clcd_mmap, | ||
148 | .remove = lpc32xx_clcd_remove, | ||
149 | }; | ||
150 | |||
151 | static struct amba_device lpc32xx_clcd_device = { | ||
152 | .dev = { | ||
153 | .coherent_dma_mask = ~0, | ||
154 | .init_name = "dev:clcd", | ||
155 | .platform_data = &lpc32xx_clcd_data, | ||
156 | }, | ||
157 | .res = { | ||
158 | .start = LPC32XX_LCD_BASE, | ||
159 | .end = (LPC32XX_LCD_BASE + SZ_4K - 1), | ||
160 | .flags = IORESOURCE_MEM, | ||
161 | }, | ||
162 | .dma_mask = ~0, | ||
163 | .irq = {IRQ_LPC32XX_LCD, NO_IRQ}, | ||
164 | }; | ||
165 | |||
166 | /* | ||
167 | * AMBA SSP (SPI) | ||
168 | */ | ||
169 | static void phy3250_spi_cs_set(u32 control) | ||
170 | { | ||
171 | gpio_set_value(SPI0_CS_GPIO, (int) control); | ||
172 | } | ||
173 | |||
174 | static struct pl022_config_chip spi0_chip_info = { | ||
175 | .lbm = LOOPBACK_DISABLED, | ||
176 | .com_mode = INTERRUPT_TRANSFER, | ||
177 | .iface = SSP_INTERFACE_MOTOROLA_SPI, | ||
178 | .hierarchy = SSP_MASTER, | ||
179 | .slave_tx_disable = 0, | ||
180 | .endian_tx = SSP_TX_LSB, | ||
181 | .endian_rx = SSP_RX_LSB, | ||
182 | .data_size = SSP_DATA_BITS_8, | ||
183 | .rx_lev_trig = SSP_RX_4_OR_MORE_ELEM, | ||
184 | .tx_lev_trig = SSP_TX_4_OR_MORE_EMPTY_LOC, | ||
185 | .clk_phase = SSP_CLK_FIRST_EDGE, | ||
186 | .clk_pol = SSP_CLK_POL_IDLE_LOW, | ||
187 | .ctrl_len = SSP_BITS_8, | ||
188 | .wait_state = SSP_MWIRE_WAIT_ZERO, | ||
189 | .duplex = SSP_MICROWIRE_CHANNEL_FULL_DUPLEX, | ||
190 | .cs_control = phy3250_spi_cs_set, | ||
191 | }; | ||
192 | |||
193 | static struct pl022_ssp_controller lpc32xx_ssp0_data = { | ||
194 | .bus_id = 0, | ||
195 | .num_chipselect = 1, | ||
196 | .enable_dma = 0, | ||
197 | }; | ||
198 | |||
199 | static struct amba_device lpc32xx_ssp0_device = { | ||
200 | .dev = { | ||
201 | .coherent_dma_mask = ~0, | ||
202 | .init_name = "dev:ssp0", | ||
203 | .platform_data = &lpc32xx_ssp0_data, | ||
204 | }, | ||
205 | .res = { | ||
206 | .start = LPC32XX_SSP0_BASE, | ||
207 | .end = (LPC32XX_SSP0_BASE + SZ_4K - 1), | ||
208 | .flags = IORESOURCE_MEM, | ||
209 | }, | ||
210 | .dma_mask = ~0, | ||
211 | .irq = {IRQ_LPC32XX_SSP0, NO_IRQ}, | ||
212 | }; | ||
213 | |||
214 | /* AT25 driver registration */ | ||
215 | static int __init phy3250_spi_board_register(void) | ||
216 | { | ||
217 | #if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE) | ||
218 | static struct spi_board_info info[] = { | ||
219 | { | ||
220 | .modalias = "spidev", | ||
221 | .max_speed_hz = 5000000, | ||
222 | .bus_num = 0, | ||
223 | .chip_select = 0, | ||
224 | .controller_data = &spi0_chip_info, | ||
225 | }, | ||
226 | }; | ||
227 | |||
228 | #else | ||
229 | static struct spi_eeprom eeprom = { | ||
230 | .name = "at25256a", | ||
231 | .byte_len = 0x8000, | ||
232 | .page_size = 64, | ||
233 | .flags = EE_ADDR2, | ||
234 | }; | ||
235 | |||
236 | static struct spi_board_info info[] = { | ||
237 | { | ||
238 | .modalias = "at25", | ||
239 | .max_speed_hz = 5000000, | ||
240 | .bus_num = 0, | ||
241 | .chip_select = 0, | ||
242 | .platform_data = &eeprom, | ||
243 | .controller_data = &spi0_chip_info, | ||
244 | }, | ||
245 | }; | ||
246 | #endif | ||
247 | return spi_register_board_info(info, ARRAY_SIZE(info)); | ||
248 | } | ||
249 | arch_initcall(phy3250_spi_board_register); | ||
250 | |||
251 | static struct i2c_board_info __initdata phy3250_i2c_board_info[] = { | ||
252 | { | ||
253 | I2C_BOARD_INFO("pcf8563", 0x51), | ||
254 | }, | ||
255 | }; | ||
256 | |||
257 | static struct gpio_led phy_leds[] = { | ||
258 | { | ||
259 | .name = "led0", | ||
260 | .gpio = LED_GPIO, | ||
261 | .active_low = 1, | ||
262 | .default_trigger = "heartbeat", | ||
263 | }, | ||
264 | }; | ||
265 | |||
266 | static struct gpio_led_platform_data led_data = { | ||
267 | .leds = phy_leds, | ||
268 | .num_leds = ARRAY_SIZE(phy_leds), | ||
269 | }; | ||
270 | |||
271 | static struct platform_device lpc32xx_gpio_led_device = { | ||
272 | .name = "leds-gpio", | ||
273 | .id = -1, | ||
274 | .dev.platform_data = &led_data, | ||
275 | }; | ||
276 | |||
277 | static struct platform_device *phy3250_devs[] __initdata = { | ||
278 | &lpc32xx_i2c0_device, | ||
279 | &lpc32xx_i2c1_device, | ||
280 | &lpc32xx_i2c2_device, | ||
281 | &lpc32xx_watchdog_device, | ||
282 | &lpc32xx_gpio_led_device, | ||
283 | }; | ||
284 | |||
285 | static struct amba_device *amba_devs[] __initdata = { | ||
286 | &lpc32xx_clcd_device, | ||
287 | &lpc32xx_ssp0_device, | ||
288 | }; | ||
289 | |||
290 | /* | ||
291 | * Board specific functions | ||
292 | */ | ||
293 | static void __init phy3250_board_init(void) | ||
294 | { | ||
295 | u32 tmp; | ||
296 | int i; | ||
297 | |||
298 | lpc32xx_gpio_init(); | ||
299 | |||
300 | /* Register GPIOs used on this board */ | ||
301 | if (gpio_request(SPI0_CS_GPIO, "spi0 cs")) | ||
302 | printk(KERN_ERR "Error requesting gpio %u", | ||
303 | SPI0_CS_GPIO); | ||
304 | else if (gpio_direction_output(SPI0_CS_GPIO, 1)) | ||
305 | printk(KERN_ERR "Error setting gpio %u to output", | ||
306 | SPI0_CS_GPIO); | ||
307 | |||
308 | /* Setup network interface for RMII mode */ | ||
309 | tmp = __raw_readl(LPC32XX_CLKPWR_MACCLK_CTRL); | ||
310 | tmp &= ~LPC32XX_CLKPWR_MACCTRL_PINS_MSK; | ||
311 | tmp |= LPC32XX_CLKPWR_MACCTRL_USE_RMII_PINS; | ||
312 | __raw_writel(tmp, LPC32XX_CLKPWR_MACCLK_CTRL); | ||
313 | |||
314 | /* Setup SLC NAND controller muxing */ | ||
315 | __raw_writel(LPC32XX_CLKPWR_NANDCLK_SEL_SLC, | ||
316 | LPC32XX_CLKPWR_NAND_CLK_CTRL); | ||
317 | |||
318 | /* Setup LCD muxing to RGB565 */ | ||
319 | tmp = __raw_readl(LPC32XX_CLKPWR_LCDCLK_CTRL) & | ||
320 | ~(LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_MSK | | ||
321 | LPC32XX_CLKPWR_LCDCTRL_PSCALE_MSK); | ||
322 | tmp |= LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_TFT16; | ||
323 | __raw_writel(tmp, LPC32XX_CLKPWR_LCDCLK_CTRL); | ||
324 | |||
325 | /* Set up I2C pull levels */ | ||
326 | tmp = __raw_readl(LPC32XX_CLKPWR_I2C_CLK_CTRL); | ||
327 | tmp |= LPC32XX_CLKPWR_I2CCLK_USBI2CHI_DRIVE | | ||
328 | LPC32XX_CLKPWR_I2CCLK_I2C2HI_DRIVE; | ||
329 | __raw_writel(tmp, LPC32XX_CLKPWR_I2C_CLK_CTRL); | ||
330 | |||
331 | /* Disable IrDA pulsing support on UART6 */ | ||
332 | tmp = __raw_readl(LPC32XX_UARTCTL_CTRL); | ||
333 | tmp |= LPC32XX_UART_UART6_IRDAMOD_BYPASS; | ||
334 | __raw_writel(tmp, LPC32XX_UARTCTL_CTRL); | ||
335 | |||
336 | /* Enable DMA for I2S1 channel */ | ||
337 | tmp = __raw_readl(LPC32XX_CLKPWR_I2S_CLK_CTRL); | ||
338 | tmp = LPC32XX_CLKPWR_I2SCTRL_I2S1_USE_DMA; | ||
339 | __raw_writel(tmp, LPC32XX_CLKPWR_I2S_CLK_CTRL); | ||
340 | |||
341 | lpc32xx_serial_init(); | ||
342 | |||
343 | /* | ||
344 | * AMBA peripheral clocks need to be enabled prior to AMBA device | ||
345 | * detection or a data fault will occur, so enable the clocks | ||
346 | * here. However, we don't want to enable them if the peripheral | ||
347 | * isn't included in the image | ||
348 | */ | ||
349 | #ifdef CONFIG_FB_ARMCLCD | ||
350 | tmp = __raw_readl(LPC32XX_CLKPWR_LCDCLK_CTRL); | ||
351 | __raw_writel((tmp | LPC32XX_CLKPWR_LCDCTRL_CLK_EN), | ||
352 | LPC32XX_CLKPWR_LCDCLK_CTRL); | ||
353 | #endif | ||
354 | #ifdef CONFIG_SPI_PL022 | ||
355 | tmp = __raw_readl(LPC32XX_CLKPWR_SSP_CLK_CTRL); | ||
356 | __raw_writel((tmp | LPC32XX_CLKPWR_SSPCTRL_SSPCLK0_EN), | ||
357 | LPC32XX_CLKPWR_SSP_CLK_CTRL); | ||
358 | #endif | ||
359 | |||
360 | platform_add_devices(phy3250_devs, ARRAY_SIZE(phy3250_devs)); | ||
361 | for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { | ||
362 | struct amba_device *d = amba_devs[i]; | ||
363 | amba_device_register(d, &iomem_resource); | ||
364 | } | ||
365 | |||
366 | /* Test clock needed for UDA1380 initial init */ | ||
367 | __raw_writel(LPC32XX_CLKPWR_TESTCLK2_SEL_MOSC | | ||
368 | LPC32XX_CLKPWR_TESTCLK_TESTCLK2_EN, | ||
369 | LPC32XX_CLKPWR_TEST_CLK_SEL); | ||
370 | |||
371 | i2c_register_board_info(0, phy3250_i2c_board_info, | ||
372 | ARRAY_SIZE(phy3250_i2c_board_info)); | ||
373 | } | ||
374 | |||
375 | static int __init lpc32xx_display_uid(void) | ||
376 | { | ||
377 | u32 uid[4]; | ||
378 | |||
379 | lpc32xx_get_uid(uid); | ||
380 | |||
381 | printk(KERN_INFO "LPC32XX unique ID: %08x%08x%08x%08x\n", | ||
382 | uid[3], uid[2], uid[1], uid[0]); | ||
383 | |||
384 | return 1; | ||
385 | } | ||
386 | arch_initcall(lpc32xx_display_uid); | ||
387 | |||
388 | MACHINE_START(PHY3250, "Phytec 3250 board with the LPC3250 Microcontroller") | ||
389 | /* Maintainer: Kevin Wells, NXP Semiconductors */ | ||
390 | .phys_io = LPC32XX_UART5_BASE, | ||
391 | .io_pg_offst = ((IO_ADDRESS(LPC32XX_UART5_BASE))>>18) & 0xfffc, | ||
392 | .boot_params = 0x80000100, | ||
393 | .map_io = lpc32xx_map_io, | ||
394 | .init_irq = lpc32xx_init_irq, | ||
395 | .timer = &lpc32xx_timer, | ||
396 | .init_machine = phy3250_board_init, | ||
397 | MACHINE_END | ||