Merge git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6
[pandora-kernel.git] / arch / arm / mach-s3c2440 / mach-rx1950.c
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
61 static struct map_desc rx1950_iodesc[] __initdata = {
62 };
63
64 static 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
73 static 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
104 static 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
130 static 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
148 static struct pwm_device *lcd_pwm;
149
150 void 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
235 static 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
255 static 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
270 static 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
280 static 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
292 static 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
302 static 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
310 static 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
325 static 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
332 static 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
359 static 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
368 static 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
376 static 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
392 static 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
398 static struct s3c2410_ts_mach_info rx1950_ts_cfg __initdata = {
399         .delay = 10000,
400         .presc = 49,
401         .oversampling_shift = 3,
402 };
403
404 static 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
474 static 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
479 static struct platform_device rx1950_device_gpiokeys = {
480         .name = "gpio-keys",
481         .dev.platform_data = &rx1950_gpio_keys_data,
482 };
483
484 static 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
491 static 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
508 static struct clk *rx1950_clocks[] __initdata = {
509         &s3c24xx_clkout0,
510         &s3c24xx_clkout1,
511 };
512
513 static 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
533 static 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 */
575 static void __init rx1950_reserve(void)
576 {
577         memblock_reserve(0x30003000, 0x1000);
578         memblock_reserve(0x30081000, 0x1000);
579 }
580
581 MACHINE_START(RX1950, "HP iPAQ RX1950")
582     /* Maintainers: Vasily Khoruzhick */
583         .boot_params = S3C2410_SDRAM_PA + 0x100,
584         .map_io = rx1950_map_io,
585         .reserve        = rx1950_reserve,
586         .init_irq = s3c24xx_init_irq,
587         .init_machine = rx1950_init_machine,
588         .timer = &s3c24xx_timer,
589 MACHINE_END