1/* 2 * linux/arch/arm/mach-pxa/cm-x2xx.c 3 * 4 * Copyright (C) 2008 CompuLab, Ltd. 5 * Mike Rapoport <mike@compulab.co.il> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 */ 11 12#include <linux/platform_device.h> 13#include <linux/sysdev.h> 14#include <linux/irq.h> 15#include <linux/gpio.h> 16 17#include <linux/dm9000.h> 18#include <linux/leds.h> 19 20#include <asm/mach/arch.h> 21#include <asm/mach-types.h> 22#include <asm/mach/map.h> 23 24#include <mach/pxa2xx-regs.h> 25#include <mach/audio.h> 26#include <mach/pxafb.h> 27 28#include <asm/hardware/it8152.h> 29 30#include "generic.h" 31#include "cm-x2xx-pci.h" 32 33extern void cmx255_init(void); 34extern void cmx270_init(void); 35 36/* virtual addresses for statically mapped regions */ 37#define CMX2XX_VIRT_BASE (0xe8000000) 38#define CMX2XX_IT8152_VIRT (CMX2XX_VIRT_BASE) 39 40/* physical address if local-bus attached devices */ 41#define CMX255_DM9000_PHYS_BASE (PXA_CS1_PHYS + (8 << 22)) 42#define CMX270_DM9000_PHYS_BASE (PXA_CS1_PHYS + (6 << 22)) 43 44/* leds */ 45#define CMX255_GPIO_RED (27) 46#define CMX255_GPIO_GREEN (32) 47#define CMX270_GPIO_RED (93) 48#define CMX270_GPIO_GREEN (94) 49 50/* GPIO IRQ usage */ 51#define GPIO22_ETHIRQ (22) 52#define GPIO10_ETHIRQ (10) 53#define CMX255_GPIO_IT8152_IRQ (0) 54#define CMX270_GPIO_IT8152_IRQ (22) 55 56#define CMX255_ETHIRQ IRQ_GPIO(GPIO22_ETHIRQ) 57#define CMX270_ETHIRQ IRQ_GPIO(GPIO10_ETHIRQ) 58 59#if defined(CONFIG_DM9000) || defined(CONFIG_DM9000_MODULE) 60static struct resource cmx255_dm9000_resource[] = { 61 [0] = { 62 .start = CMX255_DM9000_PHYS_BASE, 63 .end = CMX255_DM9000_PHYS_BASE + 3, 64 .flags = IORESOURCE_MEM, 65 }, 66 [1] = { 67 .start = CMX255_DM9000_PHYS_BASE + 4, 68 .end = CMX255_DM9000_PHYS_BASE + 4 + 500, 69 .flags = IORESOURCE_MEM, 70 }, 71 [2] = { 72 .start = CMX255_ETHIRQ, 73 .end = CMX255_ETHIRQ, 74 .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE, 75 } 76}; 77 78static struct resource cmx270_dm9000_resource[] = { 79 [0] = { 80 .start = CMX270_DM9000_PHYS_BASE, 81 .end = CMX270_DM9000_PHYS_BASE + 3, 82 .flags = IORESOURCE_MEM, 83 }, 84 [1] = { 85 .start = CMX270_DM9000_PHYS_BASE + 8, 86 .end = CMX270_DM9000_PHYS_BASE + 8 + 500, 87 .flags = IORESOURCE_MEM, 88 }, 89 [2] = { 90 .start = CMX270_ETHIRQ, 91 .end = CMX270_ETHIRQ, 92 .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE, 93 } 94}; 95 96static struct dm9000_plat_data cmx270_dm9000_platdata = { 97 .flags = DM9000_PLATF_32BITONLY | DM9000_PLATF_NO_EEPROM, 98}; 99 100static struct platform_device cmx2xx_dm9000_device = { 101 .name = "dm9000", 102 .id = 0, 103 .num_resources = ARRAY_SIZE(cmx270_dm9000_resource), 104 .dev = { 105 .platform_data = &cmx270_dm9000_platdata, 106 } 107}; 108 109static void __init cmx2xx_init_dm9000(void) 110{ 111 if (cpu_is_pxa25x()) 112 cmx2xx_dm9000_device.resource = cmx255_dm9000_resource; 113 else 114 cmx2xx_dm9000_device.resource = cmx270_dm9000_resource; 115 platform_device_register(&cmx2xx_dm9000_device); 116} 117#else 118static inline void cmx2xx_init_dm9000(void) {} 119#endif 120 121/* UCB1400 touchscreen controller */ 122#if defined(CONFIG_TOUCHSCREEN_UCB1400) || defined(CONFIG_TOUCHSCREEN_UCB1400_MODULE) 123static struct platform_device cmx2xx_ts_device = { 124 .name = "ucb1400_core", 125 .id = -1, 126}; 127 128static void __init cmx2xx_init_touchscreen(void) 129{ 130 platform_device_register(&cmx2xx_ts_device); 131} 132#else 133static inline void cmx2xx_init_touchscreen(void) {} 134#endif 135 136/* CM-X270 LEDs */ 137#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE) 138static struct gpio_led cmx2xx_leds[] = { 139 [0] = { 140 .name = "cm-x2xx:red", 141 .default_trigger = "nand-disk", 142 .active_low = 1, 143 }, 144 [1] = { 145 .name = "cm-x2xx:green", 146 .default_trigger = "heartbeat", 147 .active_low = 1, 148 }, 149}; 150 151static struct gpio_led_platform_data cmx2xx_gpio_led_pdata = { 152 .num_leds = ARRAY_SIZE(cmx2xx_leds), 153 .leds = cmx2xx_leds, 154}; 155 156static struct platform_device cmx2xx_led_device = { 157 .name = "leds-gpio", 158 .id = -1, 159 .dev = { 160 .platform_data = &cmx2xx_gpio_led_pdata, 161 }, 162}; 163 164static void __init cmx2xx_init_leds(void) 165{ 166 if (cpu_is_pxa25x()) { 167 cmx2xx_leds[0].gpio = CMX255_GPIO_RED; 168 cmx2xx_leds[1].gpio = CMX255_GPIO_GREEN; 169 } else { 170 cmx2xx_leds[0].gpio = CMX270_GPIO_RED; 171 cmx2xx_leds[1].gpio = CMX270_GPIO_GREEN; 172 } 173 platform_device_register(&cmx2xx_led_device); 174} 175#else 176static inline void cmx2xx_init_leds(void) {} 177#endif 178 179#if defined(CONFIG_FB_PXA) || defined(CONFIG_FB_PXA_MODULE) 180/* 181 Display definitions 182 keep these for backwards compatibility, although symbolic names (as 183 e.g. in lpd270.c) looks better 184*/ 185#define MTYPE_STN320x240 0 186#define MTYPE_TFT640x480 1 187#define MTYPE_CRT640x480 2 188#define MTYPE_CRT800x600 3 189#define MTYPE_TFT320x240 6 190#define MTYPE_STN640x480 7 191 192static struct pxafb_mode_info generic_stn_320x240_mode = { 193 .pixclock = 76923, 194 .bpp = 8, 195 .xres = 320, 196 .yres = 240, 197 .hsync_len = 3, 198 .vsync_len = 2, 199 .left_margin = 3, 200 .upper_margin = 0, 201 .right_margin = 3, 202 .lower_margin = 0, 203 .sync = (FB_SYNC_HOR_HIGH_ACT | 204 FB_SYNC_VERT_HIGH_ACT), 205 .cmap_greyscale = 0, 206}; 207 208static struct pxafb_mach_info generic_stn_320x240 = { 209 .modes = &generic_stn_320x240_mode, 210 .num_modes = 1, 211 .lcd_conn = LCD_COLOR_STN_8BPP | LCD_PCLK_EDGE_FALL |\ 212 LCD_AC_BIAS_FREQ(0xff), 213 .cmap_inverse = 0, 214 .cmap_static = 0, 215}; 216 217static struct pxafb_mode_info generic_tft_640x480_mode = { 218 .pixclock = 38461, 219 .bpp = 8, 220 .xres = 640, 221 .yres = 480, 222 .hsync_len = 60, 223 .vsync_len = 2, 224 .left_margin = 70, 225 .upper_margin = 10, 226 .right_margin = 70, 227 .lower_margin = 5, 228 .sync = 0, 229 .cmap_greyscale = 0, 230}; 231 232static struct pxafb_mach_info generic_tft_640x480 = { 233 .modes = &generic_tft_640x480_mode, 234 .num_modes = 1, 235 .lcd_conn = LCD_COLOR_TFT_8BPP | LCD_PCLK_EDGE_FALL |\ 236 LCD_AC_BIAS_FREQ(0xff), 237 .cmap_inverse = 0, 238 .cmap_static = 0, 239}; 240 241static struct pxafb_mode_info generic_crt_640x480_mode = { 242 .pixclock = 38461, 243 .bpp = 8, 244 .xres = 640, 245 .yres = 480, 246 .hsync_len = 63, 247 .vsync_len = 2, 248 .left_margin = 81, 249 .upper_margin = 33, 250 .right_margin = 16, 251 .lower_margin = 10, 252 .sync = (FB_SYNC_HOR_HIGH_ACT | 253 FB_SYNC_VERT_HIGH_ACT), 254 .cmap_greyscale = 0, 255}; 256 257static struct pxafb_mach_info generic_crt_640x480 = { 258 .modes = &generic_crt_640x480_mode, 259 .num_modes = 1, 260 .lcd_conn = LCD_COLOR_TFT_8BPP | LCD_AC_BIAS_FREQ(0xff), 261 .cmap_inverse = 0, 262 .cmap_static = 0, 263}; 264 265static struct pxafb_mode_info generic_crt_800x600_mode = { 266 .pixclock = 28846, 267 .bpp = 8, 268 .xres = 800, 269 .yres = 600, 270 .hsync_len = 63, 271 .vsync_len = 2, 272 .left_margin = 26, 273 .upper_margin = 21, 274 .right_margin = 26, 275 .lower_margin = 11, 276 .sync = (FB_SYNC_HOR_HIGH_ACT | 277 FB_SYNC_VERT_HIGH_ACT), 278 .cmap_greyscale = 0, 279}; 280 281static struct pxafb_mach_info generic_crt_800x600 = { 282 .modes = &generic_crt_800x600_mode, 283 .num_modes = 1, 284 .lcd_conn = LCD_COLOR_TFT_8BPP | LCD_AC_BIAS_FREQ(0xff), 285 .cmap_inverse = 0, 286 .cmap_static = 0, 287}; 288 289static struct pxafb_mode_info generic_tft_320x240_mode = { 290 .pixclock = 134615, 291 .bpp = 16, 292 .xres = 320, 293 .yres = 240, 294 .hsync_len = 63, 295 .vsync_len = 7, 296 .left_margin = 75, 297 .upper_margin = 0, 298 .right_margin = 15, 299 .lower_margin = 15, 300 .sync = 0, 301 .cmap_greyscale = 0, 302}; 303 304static struct pxafb_mach_info generic_tft_320x240 = { 305 .modes = &generic_tft_320x240_mode, 306 .num_modes = 1, 307 .lcd_conn = LCD_COLOR_TFT_16BPP | LCD_AC_BIAS_FREQ(0xff), 308 .cmap_inverse = 0, 309 .cmap_static = 0, 310}; 311 312static struct pxafb_mode_info generic_stn_640x480_mode = { 313 .pixclock = 57692, 314 .bpp = 8, 315 .xres = 640, 316 .yres = 480, 317 .hsync_len = 4, 318 .vsync_len = 2, 319 .left_margin = 10, 320 .upper_margin = 5, 321 .right_margin = 10, 322 .lower_margin = 5, 323 .sync = (FB_SYNC_HOR_HIGH_ACT | 324 FB_SYNC_VERT_HIGH_ACT), 325 .cmap_greyscale = 0, 326}; 327 328static struct pxafb_mach_info generic_stn_640x480 = { 329 .modes = &generic_stn_640x480_mode, 330 .num_modes = 1, 331 .lcd_conn = LCD_COLOR_STN_8BPP | LCD_AC_BIAS_FREQ(0xff), 332 .cmap_inverse = 0, 333 .cmap_static = 0, 334}; 335 336static struct pxafb_mach_info *cmx2xx_display = &generic_crt_640x480; 337 338static int __init cmx2xx_set_display(char *str) 339{ 340 int disp_type = simple_strtol(str, NULL, 0); 341 switch (disp_type) { 342 case MTYPE_STN320x240: 343 cmx2xx_display = &generic_stn_320x240; 344 break; 345 case MTYPE_TFT640x480: 346 cmx2xx_display = &generic_tft_640x480; 347 break; 348 case MTYPE_CRT640x480: 349 cmx2xx_display = &generic_crt_640x480; 350 break; 351 case MTYPE_CRT800x600: 352 cmx2xx_display = &generic_crt_800x600; 353 break; 354 case MTYPE_TFT320x240: 355 cmx2xx_display = &generic_tft_320x240; 356 break; 357 case MTYPE_STN640x480: 358 cmx2xx_display = &generic_stn_640x480; 359 break; 360 default: /* fallback to CRT 640x480 */ 361 cmx2xx_display = &generic_crt_640x480; 362 break; 363 } 364 return 1; 365} 366 367/* 368 This should be done really early to get proper configuration for 369 frame buffer. 370 Indeed, pxafb parameters can be used istead, but CM-X2XX bootloader 371 has limitied line length for kernel command line, and also it will 372 break compatibitlty with proprietary releases already in field. 373*/ 374__setup("monitor=", cmx2xx_set_display); 375 376static void __init cmx2xx_init_display(void) 377{ 378 set_pxa_fb_info(cmx2xx_display); 379} 380#else 381static inline void cmx2xx_init_display(void) {} 382#endif 383 384#ifdef CONFIG_PM 385static unsigned long sleep_save_msc[10]; 386 387static int cmx2xx_suspend(struct sys_device *dev, pm_message_t state) 388{ 389 cmx2xx_pci_suspend(); 390 391 /* save MSC registers */ 392 sleep_save_msc[0] = MSC0; 393 sleep_save_msc[1] = MSC1; 394 sleep_save_msc[2] = MSC2; 395 396 /* setup power saving mode registers */ 397 PCFR = 0x0; 398 PSLR = 0xff400000; 399 PMCR = 0x00000005; 400 PWER = 0x80000000; 401 PFER = 0x00000000; 402 PRER = 0x00000000; 403 PGSR0 = 0xC0018800; 404 PGSR1 = 0x004F0002; 405 PGSR2 = 0x6021C000; 406 PGSR3 = 0x00020000; 407 408 return 0; 409} 410 411static int cmx2xx_resume(struct sys_device *dev) 412{ 413 cmx2xx_pci_resume(); 414 415 /* restore MSC registers */ 416 MSC0 = sleep_save_msc[0]; 417 MSC1 = sleep_save_msc[1]; 418 MSC2 = sleep_save_msc[2]; 419 420 return 0; 421} 422 423static struct sysdev_class cmx2xx_pm_sysclass = { 424 .name = "pm", 425 .resume = cmx2xx_resume, 426 .suspend = cmx2xx_suspend, 427}; 428 429static struct sys_device cmx2xx_pm_device = { 430 .cls = &cmx2xx_pm_sysclass, 431}; 432 433static int __init cmx2xx_pm_init(void) 434{ 435 int error; 436 error = sysdev_class_register(&cmx2xx_pm_sysclass); 437 if (error == 0) 438 error = sysdev_register(&cmx2xx_pm_device); 439 return error; 440} 441#else 442static int __init cmx2xx_pm_init(void) { return 0; } 443#endif 444 445#if defined(CONFIG_SND_PXA2XX_AC97) || defined(CONFIG_SND_PXA2XX_AC97_MODULE) 446static void __init cmx2xx_init_ac97(void) 447{ 448 pxa_set_ac97_info(NULL); 449} 450#else 451static inline void cmx2xx_init_ac97(void) {} 452#endif 453 454static void __init cmx2xx_init(void) 455{ 456 pxa_set_ffuart_info(NULL); 457 pxa_set_btuart_info(NULL); 458 pxa_set_stuart_info(NULL); 459 460 cmx2xx_pm_init(); 461 462 if (cpu_is_pxa25x()) 463 cmx255_init(); 464 else 465 cmx270_init(); 466 467 cmx2xx_init_dm9000(); 468 cmx2xx_init_display(); 469 cmx2xx_init_ac97(); 470 cmx2xx_init_touchscreen(); 471 cmx2xx_init_leds(); 472} 473 474static void __init cmx2xx_init_irq(void) 475{ 476 pxa27x_init_irq(); 477 478 if (cpu_is_pxa25x()) { 479 pxa25x_init_irq(); 480 cmx2xx_pci_init_irq(CMX255_GPIO_IT8152_IRQ); 481 } else { 482 pxa27x_init_irq(); 483 cmx2xx_pci_init_irq(CMX270_GPIO_IT8152_IRQ); 484 } 485} 486 487#ifdef CONFIG_PCI 488/* Map PCI companion statically */ 489static struct map_desc cmx2xx_io_desc[] __initdata = { 490 [0] = { /* PCI bridge */ 491 .virtual = CMX2XX_IT8152_VIRT, 492 .pfn = __phys_to_pfn(PXA_CS4_PHYS), 493 .length = SZ_64M, 494 .type = MT_DEVICE 495 }, 496}; 497 498static void __init cmx2xx_map_io(void) 499{ 500 pxa_map_io(); 501 iotable_init(cmx2xx_io_desc, ARRAY_SIZE(cmx2xx_io_desc)); 502 503 it8152_base_address = CMX2XX_IT8152_VIRT; 504} 505#else 506static void __init cmx2xx_map_io(void) 507{ 508 pxa_map_io(); 509} 510#endif 511 512MACHINE_START(ARMCORE, "Compulab CM-X2XX") 513 .boot_params = 0xa0000100, 514 .phys_io = 0x40000000, 515 .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, 516 .map_io = cmx2xx_map_io, 517 .init_irq = cmx2xx_init_irq, 518 .timer = &pxa_timer, 519 .init_machine = cmx2xx_init, 520MACHINE_END 521