• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/arch/arm/mach-s3c2440/
1/* linux/arch/arm/mach-s3c2440/mach-rx1950.c
2 *
3 * Copyright (c) 2006-2009 Victor Chukhantsev, Denis Grigoriev,
4 * Copyright (c) 2007-2010 Vasily Khoruzhick
5 *
6 * based on smdk2440 written by Ben Dooks
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 version 2 as
10 * published by the Free Software Foundation.
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/memblock.h>
19#include <linux/delay.h>
20#include <linux/timer.h>
21#include <linux/init.h>
22#include <linux/gpio.h>
23#include <linux/platform_device.h>
24#include <linux/serial_core.h>
25#include <linux/input.h>
26#include <linux/gpio_keys.h>
27#include <linux/sysdev.h>
28#include <linux/pwm_backlight.h>
29#include <linux/pwm.h>
30
31#include <linux/mtd/mtd.h>
32#include <linux/mtd/partitions.h>
33
34#include <linux/mmc/host.h>
35
36#include <asm/mach/arch.h>
37#include <asm/mach/map.h>
38#include <asm/mach-types.h>
39
40#include <mach/regs-gpio.h>
41#include <mach/regs-gpioj.h>
42#include <mach/h1940.h>
43#include <mach/fb.h>
44
45#include <plat/clock.h>
46#include <plat/regs-serial.h>
47#include <plat/regs-iic.h>
48#include <plat/mci.h>
49#include <plat/udc.h>
50#include <plat/nand.h>
51#include <plat/iic.h>
52#include <plat/devs.h>
53#include <plat/cpu.h>
54#include <plat/pm.h>
55#include <plat/irq.h>
56#include <plat/ts.h>
57
58#define LCD_PWM_PERIOD 192960
59#define LCD_PWM_DUTY 127353
60
61static struct map_desc rx1950_iodesc[] __initdata = {
62};
63
64static struct s3c24xx_uart_clksrc rx1950_serial_clocks[] = {
65	[0] = {
66	       .name = "fclk",
67	       .divisor = 0x0a,
68	       .min_baud = 0,
69	       .max_baud = 0,
70	},
71};
72
73static struct s3c2410_uartcfg rx1950_uartcfgs[] __initdata = {
74	[0] = {
75	       .hwport = 0,
76	       .flags = 0,
77	       .ucon = 0x3c5,
78	       .ulcon = 0x03,
79	       .ufcon = 0x51,
80	       .clocks = rx1950_serial_clocks,
81	       .clocks_size = ARRAY_SIZE(rx1950_serial_clocks),
82	},
83	[1] = {
84	       .hwport = 1,
85	       .flags = 0,
86	       .ucon = 0x3c5,
87	       .ulcon = 0x03,
88	       .ufcon = 0x51,
89	       .clocks = rx1950_serial_clocks,
90	       .clocks_size = ARRAY_SIZE(rx1950_serial_clocks),
91	},
92	/* IR port */
93	[2] = {
94	       .hwport = 2,
95	       .flags = 0,
96	       .ucon = 0x3c5,
97	       .ulcon = 0x43,
98	       .ufcon = 0xf1,
99	       .clocks = rx1950_serial_clocks,
100	       .clocks_size = ARRAY_SIZE(rx1950_serial_clocks),
101	},
102};
103
104static struct s3c2410fb_display rx1950_display = {
105	.type = S3C2410_LCDCON1_TFT,
106	.width = 240,
107	.height = 320,
108	.xres = 240,
109	.yres = 320,
110	.bpp = 16,
111
112	.pixclock = 260000,
113	.left_margin = 10,
114	.right_margin = 20,
115	.hsync_len = 10,
116	.upper_margin = 2,
117	.lower_margin = 2,
118	.vsync_len = 2,
119
120	.lcdcon5 = S3C2410_LCDCON5_FRM565 |
121			   S3C2410_LCDCON5_INVVCLK |
122			   S3C2410_LCDCON5_INVVLINE |
123			   S3C2410_LCDCON5_INVVFRAME |
124			   S3C2410_LCDCON5_HWSWP |
125			   (0x02 << 13) |
126			   (0x02 << 15),
127
128};
129
130static struct s3c2410fb_mach_info rx1950_lcd_cfg = {
131	.displays = &rx1950_display,
132	.num_displays = 1,
133	.default_display = 0,
134
135	.lpcsel = 0x02,
136	.gpccon = 0xaa9556a9,
137	.gpccon_mask = 0xffc003fc,
138	.gpcup = 0x0000ffff,
139	.gpcup_mask = 0xffffffff,
140
141	.gpdcon = 0xaa90aaa1,
142	.gpdcon_mask = 0xffc0fff0,
143	.gpdup = 0x0000fcfd,
144	.gpdup_mask = 0xffffffff,
145
146};
147
148static struct pwm_device *lcd_pwm;
149
150void rx1950_lcd_power(int enable)
151{
152	int i;
153	static int enabled;
154	if (enabled == enable)
155		return;
156	if (!enable) {
157
158		/* GPC11-GPC15->OUTPUT */
159		for (i = 11; i < 16; i++)
160			gpio_direction_output(S3C2410_GPC(i), 1);
161
162		/* Wait a bit here... */
163		mdelay(100);
164
165		/* GPD2-GPD7->OUTPUT */
166		/* GPD11-GPD15->OUTPUT */
167		/* GPD2-GPD7->1, GPD11-GPD15->1 */
168		for (i = 2; i < 8; i++)
169			gpio_direction_output(S3C2410_GPD(i), 1);
170		for (i = 11; i < 16; i++)
171			gpio_direction_output(S3C2410_GPD(i), 1);
172
173		/* Wait a bit here...*/
174		mdelay(100);
175
176		/* GPB0->OUTPUT, GPB0->0 */
177		gpio_direction_output(S3C2410_GPB(0), 0);
178
179		/* GPC1-GPC4->OUTPUT, GPC1-4->0 */
180		for (i = 1; i < 5; i++)
181			gpio_direction_output(S3C2410_GPC(i), 0);
182
183		/* GPC15-GPC11->0 */
184		for (i = 11; i < 16; i++)
185			gpio_direction_output(S3C2410_GPC(i), 0);
186
187		/* GPD15-GPD11->0, GPD2->GPD7->0 */
188		for (i = 11; i < 16; i++)
189			gpio_direction_output(S3C2410_GPD(i), 0);
190
191		for (i = 2; i < 8; i++)
192			gpio_direction_output(S3C2410_GPD(i), 0);
193
194		/* GPC6->0, GPC7->0, GPC5->0 */
195		gpio_direction_output(S3C2410_GPC(6), 0);
196		gpio_direction_output(S3C2410_GPC(7), 0);
197		gpio_direction_output(S3C2410_GPC(5), 0);
198
199		/* GPB1->OUTPUT, GPB1->0 */
200		gpio_direction_output(S3C2410_GPB(1), 0);
201		pwm_config(lcd_pwm, 0, LCD_PWM_PERIOD);
202		pwm_disable(lcd_pwm);
203
204		/* GPC0->0, GPC10->0 */
205		gpio_direction_output(S3C2410_GPC(0), 0);
206		gpio_direction_output(S3C2410_GPC(10), 0);
207	} else {
208		pwm_config(lcd_pwm, LCD_PWM_DUTY, LCD_PWM_PERIOD);
209		pwm_enable(lcd_pwm);
210
211		gpio_direction_output(S3C2410_GPC(0), 1);
212		gpio_direction_output(S3C2410_GPC(5), 1);
213
214		s3c_gpio_cfgpin(S3C2410_GPB(1), S3C2410_GPB1_TOUT1);
215		gpio_direction_output(S3C2410_GPC(7), 1);
216
217		for (i = 1; i < 5; i++)
218			s3c_gpio_cfgpin(S3C2410_GPC(i), S3C_GPIO_SFN(2));
219
220		for (i = 11; i < 16; i++)
221			s3c_gpio_cfgpin(S3C2410_GPC(i), S3C_GPIO_SFN(2));
222
223		for (i = 2; i < 8; i++)
224			s3c_gpio_cfgpin(S3C2410_GPD(i), S3C_GPIO_SFN(2));
225
226		for (i = 11; i < 16; i++)
227			s3c_gpio_cfgpin(S3C2410_GPD(i), S3C_GPIO_SFN(2));
228
229		gpio_direction_output(S3C2410_GPC(10), 1);
230		gpio_direction_output(S3C2410_GPC(6), 1);
231	}
232	enabled = enable;
233}
234
235static void rx1950_bl_power(int enable)
236{
237	static int enabled;
238	if (enabled == enable)
239		return;
240	if (!enable) {
241			gpio_direction_output(S3C2410_GPB(0), 0);
242	} else {
243			/* LED driver need a "push" to power on */
244			gpio_direction_output(S3C2410_GPB(0), 1);
245			/* Warm up backlight for one period of PWM.
246			 * Without this trick its almost impossible to
247			 * enable backlight with low brightness value
248			 */
249			ndelay(48000);
250			s3c_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPB0_TOUT0);
251	}
252	enabled = enable;
253}
254
255static int rx1950_backlight_init(struct device *dev)
256{
257	WARN_ON(gpio_request(S3C2410_GPB(0), "Backlight"));
258	lcd_pwm = pwm_request(1, "RX1950 LCD");
259	if (IS_ERR(lcd_pwm)) {
260		dev_err(dev, "Unable to request PWM for LCD power!\n");
261		return PTR_ERR(lcd_pwm);
262	}
263
264	rx1950_lcd_power(1);
265	rx1950_bl_power(1);
266
267	return 0;
268}
269
270static void rx1950_backlight_exit(struct device *dev)
271{
272	rx1950_bl_power(0);
273	rx1950_lcd_power(0);
274
275	pwm_free(lcd_pwm);
276	gpio_free(S3C2410_GPB(0));
277}
278
279
280static int rx1950_backlight_notify(struct device *dev, int brightness)
281{
282	if (!brightness) {
283		rx1950_bl_power(0);
284		rx1950_lcd_power(0);
285	} else {
286		rx1950_lcd_power(1);
287		rx1950_bl_power(1);
288	}
289	return brightness;
290}
291
292static struct platform_pwm_backlight_data rx1950_backlight_data = {
293	.pwm_id = 0,
294	.max_brightness = 24,
295	.dft_brightness = 4,
296	.pwm_period_ns = 48000,
297	.init = rx1950_backlight_init,
298	.notify = rx1950_backlight_notify,
299	.exit = rx1950_backlight_exit,
300};
301
302static struct platform_device rx1950_backlight = {
303	.name = "pwm-backlight",
304	.dev = {
305		.parent = &s3c_device_timer[0].dev,
306		.platform_data = &rx1950_backlight_data,
307	},
308};
309
310static void rx1950_set_mmc_power(unsigned char power_mode, unsigned short vdd)
311{
312	switch (power_mode) {
313	case MMC_POWER_OFF:
314		gpio_direction_output(S3C2410_GPJ(1), 0);
315		break;
316	case MMC_POWER_UP:
317	case MMC_POWER_ON:
318		gpio_direction_output(S3C2410_GPJ(1), 1);
319		break;
320	default:
321		break;
322	}
323}
324
325static struct s3c24xx_mci_pdata rx1950_mmc_cfg __initdata = {
326	.gpio_detect = S3C2410_GPF(5),
327	.gpio_wprotect = S3C2410_GPH(8),
328	.set_power = rx1950_set_mmc_power,
329	.ocr_avail = MMC_VDD_32_33,
330};
331
332static struct mtd_partition rx1950_nand_part[] = {
333	[0] = {
334			.name = "Boot0",
335			.offset = 0,
336			.size = 0x4000,
337			.mask_flags = MTD_WRITEABLE,
338	},
339	[1] = {
340			.name = "Boot1",
341			.offset = MTDPART_OFS_APPEND,
342			.size = 0x40000,
343			.mask_flags = MTD_WRITEABLE,
344	},
345	[2] = {
346			.name = "Kernel",
347			.offset = MTDPART_OFS_APPEND,
348			.size = 0x300000,
349			.mask_flags = 0,
350	},
351	[3] = {
352			.name = "Filesystem",
353			.offset = MTDPART_OFS_APPEND,
354			.size = MTDPART_SIZ_FULL,
355			.mask_flags = 0,
356	},
357};
358
359static struct s3c2410_nand_set rx1950_nand_sets[] = {
360	[0] = {
361			.name = "Internal",
362			.nr_chips = 1,
363			.nr_partitions = ARRAY_SIZE(rx1950_nand_part),
364			.partitions = rx1950_nand_part,
365	},
366};
367
368static struct s3c2410_platform_nand rx1950_nand_info = {
369	.tacls = 25,
370	.twrph0 = 50,
371	.twrph1 = 15,
372	.nr_sets = ARRAY_SIZE(rx1950_nand_sets),
373	.sets = rx1950_nand_sets,
374};
375
376static void rx1950_udc_pullup(enum s3c2410_udc_cmd_e cmd)
377{
378	switch (cmd) {
379	case S3C2410_UDC_P_ENABLE:
380		gpio_direction_output(S3C2410_GPJ(5), 1);
381		break;
382	case S3C2410_UDC_P_DISABLE:
383		gpio_direction_output(S3C2410_GPJ(5), 0);
384		break;
385	case S3C2410_UDC_P_RESET:
386		break;
387	default:
388		break;
389	}
390}
391
392static struct s3c2410_udc_mach_info rx1950_udc_cfg __initdata = {
393	.udc_command = rx1950_udc_pullup,
394	.vbus_pin = S3C2410_GPG(5),
395	.vbus_pin_inverted = 1,
396};
397
398static struct s3c2410_ts_mach_info rx1950_ts_cfg __initdata = {
399	.delay = 10000,
400	.presc = 49,
401	.oversampling_shift = 3,
402};
403
404static struct gpio_keys_button rx1950_gpio_keys_table[] = {
405	{
406		.code		= KEY_POWER,
407		.gpio		= S3C2410_GPF(0),
408		.active_low	= 1,
409		.desc		= "Power button",
410		.wakeup		= 1,
411	},
412	{
413		.code		= KEY_F5,
414		.gpio		= S3C2410_GPF(7),
415		.active_low	= 1,
416		.desc		= "Record button",
417	},
418	{
419		.code		= KEY_F1,
420		.gpio		= S3C2410_GPG(0),
421		.active_low	= 1,
422		.desc		= "Calendar button",
423	},
424	{
425		.code		= KEY_F2,
426		.gpio		= S3C2410_GPG(2),
427		.active_low	= 1,
428		.desc		= "Contacts button",
429	},
430	{
431		.code		= KEY_F3,
432		.gpio		= S3C2410_GPG(3),
433		.active_low	= 1,
434		.desc		= "Mail button",
435	},
436	{
437		.code		= KEY_F4,
438		.gpio		= S3C2410_GPG(7),
439		.active_low	= 1,
440		.desc		= "WLAN button",
441	},
442	{
443		.code		= KEY_LEFT,
444		.gpio		= S3C2410_GPG(10),
445		.active_low	= 1,
446		.desc		= "Left button",
447	},
448	{
449		.code		= KEY_RIGHT,
450		.gpio		= S3C2410_GPG(11),
451		.active_low	= 1,
452		.desc		= "Right button",
453	},
454	{
455		.code		= KEY_UP,
456		.gpio		= S3C2410_GPG(4),
457		.active_low	= 1,
458		.desc		= "Up button",
459	},
460	{
461		.code		= KEY_DOWN,
462		.gpio		= S3C2410_GPG(6),
463		.active_low	= 1,
464		.desc		= "Down button",
465	},
466	{
467		.code		= KEY_ENTER,
468		.gpio		= S3C2410_GPG(9),
469		.active_low	= 1,
470		.desc		= "Ok button"
471	},
472};
473
474static struct gpio_keys_platform_data rx1950_gpio_keys_data = {
475	.buttons = rx1950_gpio_keys_table,
476	.nbuttons = ARRAY_SIZE(rx1950_gpio_keys_table),
477};
478
479static struct platform_device rx1950_device_gpiokeys = {
480	.name = "gpio-keys",
481	.dev.platform_data = &rx1950_gpio_keys_data,
482};
483
484static struct s3c2410_platform_i2c rx1950_i2c_data = {
485	.flags = 0,
486	.slave_addr = 0x42,
487	.frequency = 400 * 1000,
488	.sda_delay = S3C2410_IICLC_SDA_DELAY5 | S3C2410_IICLC_FILTER_ON,
489};
490
491static struct platform_device *rx1950_devices[] __initdata = {
492	&s3c_device_lcd,
493	&s3c_device_wdt,
494	&s3c_device_i2c0,
495	&s3c_device_iis,
496	&s3c_device_usbgadget,
497	&s3c_device_rtc,
498	&s3c_device_nand,
499	&s3c_device_sdi,
500	&s3c_device_adc,
501	&s3c_device_ts,
502	&s3c_device_timer[0],
503	&s3c_device_timer[1],
504	&rx1950_backlight,
505	&rx1950_device_gpiokeys,
506};
507
508static struct clk *rx1950_clocks[] __initdata = {
509	&s3c24xx_clkout0,
510	&s3c24xx_clkout1,
511};
512
513static void __init rx1950_map_io(void)
514{
515	s3c24xx_clkout0.parent  = &clk_h;
516	s3c24xx_clkout1.parent  = &clk_f;
517
518	s3c24xx_register_clocks(rx1950_clocks, ARRAY_SIZE(rx1950_clocks));
519
520	s3c24xx_init_io(rx1950_iodesc, ARRAY_SIZE(rx1950_iodesc));
521	s3c24xx_init_clocks(16934000);
522	s3c24xx_init_uarts(rx1950_uartcfgs, ARRAY_SIZE(rx1950_uartcfgs));
523
524	/* setup PM */
525
526#ifdef CONFIG_PM_H1940
527	memcpy(phys_to_virt(H1940_SUSPEND_RESUMEAT), h1940_pm_return, 8);
528#endif
529
530	s3c_pm_init();
531}
532
533static void __init rx1950_init_machine(void)
534{
535	int i;
536
537	s3c24xx_fb_set_platdata(&rx1950_lcd_cfg);
538	s3c24xx_udc_set_platdata(&rx1950_udc_cfg);
539	s3c24xx_ts_set_platdata(&rx1950_ts_cfg);
540	s3c24xx_mci_set_platdata(&rx1950_mmc_cfg);
541	s3c_i2c0_set_platdata(&rx1950_i2c_data);
542	s3c_nand_set_platdata(&rx1950_nand_info);
543
544	/* Turn off suspend on both USB ports, and switch the
545	 * selectable USB port to USB device mode. */
546	s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
547						S3C2410_MISCCR_USBSUSPND0 |
548						S3C2410_MISCCR_USBSUSPND1, 0x0);
549
550	WARN_ON(gpio_request(S3C2410_GPJ(5), "UDC pullup"));
551	gpio_direction_output(S3C2410_GPJ(5), 0);
552
553	/* mmc power is disabled by default */
554	WARN_ON(gpio_request(S3C2410_GPJ(1), "MMC power"));
555	gpio_direction_output(S3C2410_GPJ(1), 0);
556
557	for (i = 0; i < 8; i++)
558		WARN_ON(gpio_request(S3C2410_GPC(i), "LCD power"));
559
560	for (i = 10; i < 16; i++)
561		WARN_ON(gpio_request(S3C2410_GPC(i), "LCD power"));
562
563	for (i = 2; i < 8; i++)
564		WARN_ON(gpio_request(S3C2410_GPD(i), "LCD power"));
565
566	for (i = 11; i < 16; i++)
567		WARN_ON(gpio_request(S3C2410_GPD(i), "LCD power"));
568
569	WARN_ON(gpio_request(S3C2410_GPB(1), "LCD power"));
570
571	platform_add_devices(rx1950_devices, ARRAY_SIZE(rx1950_devices));
572}
573
574/* H1940 and RX3715 need to reserve this for suspend */
575static void __init rx1950_reserve(void)
576{
577	memblock_reserve(0x30003000, 0x1000);
578	memblock_reserve(0x30081000, 0x1000);
579}
580
581MACHINE_START(RX1950, "HP iPAQ RX1950")
582    /* Maintainers: Vasily Khoruzhick */
583    .phys_io = S3C2410_PA_UART,
584	.io_pg_offst = (((u32) S3C24XX_VA_UART) >> 18) & 0xfffc,
585	.boot_params = S3C2410_SDRAM_PA + 0x100,
586	.map_io = rx1950_map_io,
587	.reserve	= rx1950_reserve,
588	.init_irq = s3c24xx_init_irq,
589	.init_machine = rx1950_init_machine,
590	.timer = &s3c24xx_timer,
591MACHINE_END
592