1/*
2 * linux/arch/arm/mach-w90x900/dev.c
3 *
4 * Copyright (C) 2009 Nuvoton corporation.
5 *
6 * Wan ZongShun <mcuos.com@gmail.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation;version 2 of the License.
11 *
12 */
13
14#include <linux/kernel.h>
15#include <linux/types.h>
16#include <linux/interrupt.h>
17#include <linux/list.h>
18#include <linux/timer.h>
19#include <linux/init.h>
20#include <linux/platform_device.h>
21#include <linux/slab.h>
22#include <linux/cpu.h>
23
24#include <linux/mtd/physmap.h>
25#include <linux/mtd/mtd.h>
26#include <linux/mtd/partitions.h>
27
28#include <linux/spi/spi.h>
29#include <linux/spi/flash.h>
30
31#include <asm/system_misc.h>
32#include <asm/mach/arch.h>
33#include <asm/mach/map.h>
34#include <asm/mach/irq.h>
35#include <asm/mach-types.h>
36
37#include <mach/regs-serial.h>
38#include <linux/platform_data/spi-nuc900.h>
39#include <mach/map.h>
40#include <linux/platform_data/video-nuc900fb.h>
41#include <mach/regs-ldm.h>
42#include <linux/platform_data/keypad-w90p910.h>
43
44#include "cpu.h"
45
46/*NUC900 evb norflash driver data */
47
48#define NUC900_FLASH_BASE	0xA0000000
49#define NUC900_FLASH_SIZE	0x400000
50#define SPIOFFSET		0x200
51#define SPIOREG_SIZE		0x100
52
53static struct mtd_partition nuc900_flash_partitions[] = {
54	{
55		.name	=	"NOR Partition 1 for kernel (960K)",
56		.size	=	0xF0000,
57		.offset	=	0x10000,
58	},
59	{
60		.name	=	"NOR Partition 2 for image (1M)",
61		.size	=	0x100000,
62		.offset	=	0x100000,
63	},
64	{
65		.name	=	"NOR Partition 3 for user (2M)",
66		.size	=	0x200000,
67		.offset	=	0x00200000,
68	}
69};
70
71static struct physmap_flash_data nuc900_flash_data = {
72	.width		=	2,
73	.parts		=	nuc900_flash_partitions,
74	.nr_parts	=	ARRAY_SIZE(nuc900_flash_partitions),
75};
76
77static struct resource nuc900_flash_resources[] = {
78	{
79		.start	=	NUC900_FLASH_BASE,
80		.end	=	NUC900_FLASH_BASE + NUC900_FLASH_SIZE - 1,
81		.flags	=	IORESOURCE_MEM,
82	}
83};
84
85static struct platform_device nuc900_flash_device = {
86	.name		=	"physmap-flash",
87	.id		=	0,
88	.dev		= {
89				.platform_data = &nuc900_flash_data,
90			},
91	.resource	=	nuc900_flash_resources,
92	.num_resources	=	ARRAY_SIZE(nuc900_flash_resources),
93};
94
95/* USB EHCI Host Controller */
96
97static struct resource nuc900_usb_ehci_resource[] = {
98	[0] = {
99		.start = W90X900_PA_USBEHCIHOST,
100		.end   = W90X900_PA_USBEHCIHOST + W90X900_SZ_USBEHCIHOST - 1,
101		.flags = IORESOURCE_MEM,
102	},
103	[1] = {
104		.start = IRQ_USBH,
105		.end   = IRQ_USBH,
106		.flags = IORESOURCE_IRQ,
107	}
108};
109
110static u64 nuc900_device_usb_ehci_dmamask = 0xffffffffUL;
111
112static struct platform_device nuc900_device_usb_ehci = {
113	.name		  = "nuc900-ehci",
114	.id		  = -1,
115	.num_resources	  = ARRAY_SIZE(nuc900_usb_ehci_resource),
116	.resource	  = nuc900_usb_ehci_resource,
117	.dev              = {
118		.dma_mask = &nuc900_device_usb_ehci_dmamask,
119		.coherent_dma_mask = 0xffffffffUL
120	}
121};
122
123/* USB OHCI Host Controller */
124
125static struct resource nuc900_usb_ohci_resource[] = {
126	[0] = {
127		.start = W90X900_PA_USBOHCIHOST,
128		.end   = W90X900_PA_USBOHCIHOST + W90X900_SZ_USBOHCIHOST - 1,
129		.flags = IORESOURCE_MEM,
130	},
131	[1] = {
132		.start = IRQ_USBH,
133		.end   = IRQ_USBH,
134		.flags = IORESOURCE_IRQ,
135	}
136};
137
138static u64 nuc900_device_usb_ohci_dmamask = 0xffffffffUL;
139static struct platform_device nuc900_device_usb_ohci = {
140	.name		  = "nuc900-ohci",
141	.id		  = -1,
142	.num_resources	  = ARRAY_SIZE(nuc900_usb_ohci_resource),
143	.resource	  = nuc900_usb_ohci_resource,
144	.dev              = {
145		.dma_mask = &nuc900_device_usb_ohci_dmamask,
146		.coherent_dma_mask = 0xffffffffUL
147	}
148};
149
150/* USB Device (Gadget)*/
151
152static struct resource nuc900_usbgadget_resource[] = {
153	[0] = {
154		.start = W90X900_PA_USBDEV,
155		.end   = W90X900_PA_USBDEV + W90X900_SZ_USBDEV - 1,
156		.flags = IORESOURCE_MEM,
157	},
158	[1] = {
159		.start = IRQ_USBD,
160		.end   = IRQ_USBD,
161		.flags = IORESOURCE_IRQ,
162	}
163};
164
165static struct platform_device nuc900_device_usbgadget = {
166	.name		= "nuc900-usbgadget",
167	.id		= -1,
168	.num_resources	= ARRAY_SIZE(nuc900_usbgadget_resource),
169	.resource	= nuc900_usbgadget_resource,
170};
171
172/* MAC device */
173
174static struct resource nuc900_emc_resource[] = {
175	[0] = {
176		.start = W90X900_PA_EMC,
177		.end   = W90X900_PA_EMC + W90X900_SZ_EMC - 1,
178		.flags = IORESOURCE_MEM,
179	},
180	[1] = {
181		.start = IRQ_EMCTX,
182		.end   = IRQ_EMCTX,
183		.flags = IORESOURCE_IRQ,
184	},
185	[2] = {
186		.start = IRQ_EMCRX,
187		.end   = IRQ_EMCRX,
188		.flags = IORESOURCE_IRQ,
189	}
190};
191
192static u64 nuc900_device_emc_dmamask = 0xffffffffUL;
193static struct platform_device nuc900_device_emc = {
194	.name		= "nuc900-emc",
195	.id		= -1,
196	.num_resources	= ARRAY_SIZE(nuc900_emc_resource),
197	.resource	= nuc900_emc_resource,
198	.dev              = {
199		.dma_mask = &nuc900_device_emc_dmamask,
200		.coherent_dma_mask = 0xffffffffUL
201	}
202};
203
204/* SPI device */
205
206static struct nuc900_spi_info nuc900_spiflash_data = {
207	.num_cs		= 1,
208	.lsb		= 0,
209	.txneg		= 1,
210	.rxneg		= 0,
211	.divider	= 24,
212	.sleep		= 0,
213	.txnum		= 0,
214	.txbitlen	= 8,
215	.bus_num	= 0,
216};
217
218static struct resource nuc900_spi_resource[] = {
219	[0] = {
220		.start = W90X900_PA_I2C + SPIOFFSET,
221		.end   = W90X900_PA_I2C + SPIOFFSET + SPIOREG_SIZE - 1,
222		.flags = IORESOURCE_MEM,
223	},
224	[1] = {
225		.start = IRQ_SSP,
226		.end   = IRQ_SSP,
227		.flags = IORESOURCE_IRQ,
228	}
229};
230
231static struct platform_device nuc900_device_spi = {
232	.name		= "nuc900-spi",
233	.id		= -1,
234	.num_resources	= ARRAY_SIZE(nuc900_spi_resource),
235	.resource	= nuc900_spi_resource,
236	.dev		= {
237				.platform_data = &nuc900_spiflash_data,
238			}
239};
240
241/* spi device, spi flash info */
242
243static struct mtd_partition nuc900_spi_flash_partitions[] = {
244	{
245		.name = "bootloader(spi)",
246		.size = 0x0100000,
247		.offset = 0,
248	},
249};
250
251static struct flash_platform_data nuc900_spi_flash_data = {
252	.name = "m25p80",
253	.parts =  nuc900_spi_flash_partitions,
254	.nr_parts = ARRAY_SIZE(nuc900_spi_flash_partitions),
255	.type = "w25x16",
256};
257
258static struct spi_board_info nuc900_spi_board_info[] __initdata = {
259	{
260		.modalias = "m25p80",
261		.max_speed_hz = 20000000,
262		.bus_num = 0,
263		.chip_select = 0,
264		.platform_data = &nuc900_spi_flash_data,
265		.mode = SPI_MODE_0,
266	},
267};
268
269/* WDT Device */
270
271static struct resource nuc900_wdt_resource[] = {
272	[0] = {
273		.start = W90X900_PA_TIMER,
274		.end   = W90X900_PA_TIMER + W90X900_SZ_TIMER - 1,
275		.flags = IORESOURCE_MEM,
276	},
277	[1] = {
278		.start = IRQ_WDT,
279		.end   = IRQ_WDT,
280		.flags = IORESOURCE_IRQ,
281	}
282};
283
284static struct platform_device nuc900_device_wdt = {
285	.name		= "nuc900-wdt",
286	.id		= -1,
287	.num_resources	= ARRAY_SIZE(nuc900_wdt_resource),
288	.resource	= nuc900_wdt_resource,
289};
290
291/*
292 * public device definition between 910 and 920, or 910
293 * and 950 or 950 and 960...,their dev platform register
294 * should be in specific file such as nuc950, nuc960 c
295 * files rather than the public dev.c file here. so the
296 * corresponding platform_device definition should not be
297 * static.
298*/
299
300/* RTC controller*/
301
302static struct resource nuc900_rtc_resource[] = {
303	[0] = {
304		.start = W90X900_PA_RTC,
305		.end   = W90X900_PA_RTC + 0xff,
306		.flags = IORESOURCE_MEM,
307	},
308	[1] = {
309		.start = IRQ_RTC,
310		.end   = IRQ_RTC,
311		.flags = IORESOURCE_IRQ,
312	},
313};
314
315struct platform_device nuc900_device_rtc = {
316	.name		= "nuc900-rtc",
317	.id		= -1,
318	.num_resources	= ARRAY_SIZE(nuc900_rtc_resource),
319	.resource	= nuc900_rtc_resource,
320};
321
322/*TouchScreen controller*/
323
324static struct resource nuc900_ts_resource[] = {
325	[0] = {
326		.start = W90X900_PA_ADC,
327		.end   = W90X900_PA_ADC + W90X900_SZ_ADC-1,
328		.flags = IORESOURCE_MEM,
329	},
330	[1] = {
331		.start = IRQ_ADC,
332		.end   = IRQ_ADC,
333		.flags = IORESOURCE_IRQ,
334	},
335};
336
337struct platform_device nuc900_device_ts = {
338	.name		= "nuc900-ts",
339	.id		= -1,
340	.resource	= nuc900_ts_resource,
341	.num_resources	= ARRAY_SIZE(nuc900_ts_resource),
342};
343
344/* FMI Device */
345
346static struct resource nuc900_fmi_resource[] = {
347	[0] = {
348		.start = W90X900_PA_FMI,
349		.end   = W90X900_PA_FMI + W90X900_SZ_FMI - 1,
350		.flags = IORESOURCE_MEM,
351	},
352	[1] = {
353		.start = IRQ_FMI,
354		.end   = IRQ_FMI,
355		.flags = IORESOURCE_IRQ,
356	}
357};
358
359struct platform_device nuc900_device_fmi = {
360	.name		= "nuc900-fmi",
361	.id		= -1,
362	.num_resources	= ARRAY_SIZE(nuc900_fmi_resource),
363	.resource	= nuc900_fmi_resource,
364};
365
366/* KPI controller*/
367
368static int nuc900_keymap[] = {
369	KEY(0, 0, KEY_A),
370	KEY(0, 1, KEY_B),
371	KEY(0, 2, KEY_C),
372	KEY(0, 3, KEY_D),
373
374	KEY(1, 0, KEY_E),
375	KEY(1, 1, KEY_F),
376	KEY(1, 2, KEY_G),
377	KEY(1, 3, KEY_H),
378
379	KEY(2, 0, KEY_I),
380	KEY(2, 1, KEY_J),
381	KEY(2, 2, KEY_K),
382	KEY(2, 3, KEY_L),
383
384	KEY(3, 0, KEY_M),
385	KEY(3, 1, KEY_N),
386	KEY(3, 2, KEY_O),
387	KEY(3, 3, KEY_P),
388};
389
390static struct matrix_keymap_data nuc900_map_data = {
391	.keymap			= nuc900_keymap,
392	.keymap_size		= ARRAY_SIZE(nuc900_keymap),
393};
394
395struct w90p910_keypad_platform_data nuc900_keypad_info = {
396	.keymap_data	= &nuc900_map_data,
397	.prescale	= 0xfa,
398	.debounce	= 0x50,
399};
400
401static struct resource nuc900_kpi_resource[] = {
402	[0] = {
403		.start = W90X900_PA_KPI,
404		.end   = W90X900_PA_KPI + W90X900_SZ_KPI - 1,
405		.flags = IORESOURCE_MEM,
406	},
407	[1] = {
408		.start = IRQ_KPI,
409		.end   = IRQ_KPI,
410		.flags = IORESOURCE_IRQ,
411	}
412
413};
414
415struct platform_device nuc900_device_kpi = {
416	.name		= "nuc900-kpi",
417	.id		= -1,
418	.num_resources	= ARRAY_SIZE(nuc900_kpi_resource),
419	.resource	= nuc900_kpi_resource,
420	.dev		= {
421				.platform_data = &nuc900_keypad_info,
422			}
423};
424
425/* LCD controller*/
426
427static struct nuc900fb_display nuc900_lcd_info[] = {
428	/* Giantplus Technology GPM1040A0 320x240 Color TFT LCD */
429	[0] = {
430		.type		= LCM_DCCS_VA_SRC_RGB565,
431		.width		= 320,
432		.height		= 240,
433		.xres		= 320,
434		.yres		= 240,
435		.bpp		= 16,
436		.pixclock	= 200000,
437		.left_margin	= 34,
438		.right_margin   = 54,
439		.hsync_len	= 10,
440		.upper_margin	= 18,
441		.lower_margin	= 4,
442		.vsync_len	= 1,
443		.dccs		= 0x8e00041a,
444		.devctl		= 0x060800c0,
445		.fbctrl		= 0x00a000a0,
446		.scale		= 0x04000400,
447	},
448};
449
450static struct nuc900fb_mach_info nuc900_fb_info = {
451#if defined(CONFIG_GPM1040A0_320X240)
452	.displays		= &nuc900_lcd_info[0],
453#else
454	.displays		= nuc900_lcd_info,
455#endif
456	.num_displays		= ARRAY_SIZE(nuc900_lcd_info),
457	.default_display	= 0,
458	.gpio_dir		= 0x00000004,
459	.gpio_dir_mask		= 0xFFFFFFFD,
460	.gpio_data		= 0x00000004,
461	.gpio_data_mask		= 0xFFFFFFFD,
462};
463
464static struct resource nuc900_lcd_resource[] = {
465	[0] = {
466		.start = W90X900_PA_LCD,
467		.end   = W90X900_PA_LCD + W90X900_SZ_LCD - 1,
468		.flags = IORESOURCE_MEM,
469	},
470	[1] = {
471		.start = IRQ_LCD,
472		.end   = IRQ_LCD,
473		.flags = IORESOURCE_IRQ,
474	}
475};
476
477static u64 nuc900_device_lcd_dmamask = -1;
478struct platform_device nuc900_device_lcd = {
479	.name             = "nuc900-lcd",
480	.id               = -1,
481	.num_resources    = ARRAY_SIZE(nuc900_lcd_resource),
482	.resource         = nuc900_lcd_resource,
483	.dev              = {
484		.dma_mask               = &nuc900_device_lcd_dmamask,
485		.coherent_dma_mask      = -1,
486		.platform_data = &nuc900_fb_info,
487	}
488};
489
490/* AUDIO controller*/
491static u64 nuc900_device_audio_dmamask = -1;
492static struct resource nuc900_ac97_resource[] = {
493	[0] = {
494		.start = W90X900_PA_ACTL,
495		.end   = W90X900_PA_ACTL + W90X900_SZ_ACTL - 1,
496		.flags = IORESOURCE_MEM,
497	},
498	[1] = {
499		.start = IRQ_ACTL,
500		.end   = IRQ_ACTL,
501		.flags = IORESOURCE_IRQ,
502	}
503
504};
505
506struct platform_device nuc900_device_ac97 = {
507	.name		= "nuc900-ac97",
508	.id		= -1,
509	.num_resources	= ARRAY_SIZE(nuc900_ac97_resource),
510	.resource	= nuc900_ac97_resource,
511	.dev              = {
512		.dma_mask               = &nuc900_device_audio_dmamask,
513		.coherent_dma_mask      = -1,
514	}
515};
516
517/*Here should be your evb resourse,such as LCD*/
518
519static struct platform_device *nuc900_public_dev[] __initdata = {
520	&nuc900_serial_device,
521	&nuc900_flash_device,
522	&nuc900_device_usb_ehci,
523	&nuc900_device_usb_ohci,
524	&nuc900_device_usbgadget,
525	&nuc900_device_emc,
526	&nuc900_device_spi,
527	&nuc900_device_wdt,
528	&nuc900_device_ac97,
529};
530
531/* Provide adding specific CPU platform devices API */
532
533void __init nuc900_board_init(struct platform_device **device, int size)
534{
535	cpu_idle_poll_ctrl(true);
536	platform_add_devices(device, size);
537	platform_add_devices(nuc900_public_dev, ARRAY_SIZE(nuc900_public_dev));
538	spi_register_board_info(nuc900_spi_board_info,
539					ARRAY_SIZE(nuc900_spi_board_info));
540}
541
542