1/* 2 * linux/arch/arm/mach-pxa/idp.c 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 * 8 * Copyright (c) 2001 Cliff Brake, Accelent Systems Inc. 9 * 10 * 2001-09-13: Cliff Brake <cbrake@accelent.com> 11 * Initial code 12 * 13 * 2005-02-15: Cliff Brake <cliff.brake@gmail.com> 14 * <http://www.vibren.com> <http://bec-systems.com> 15 * Updated for 2.6 kernel 16 * 17 */ 18 19#include <linux/init.h> 20#include <linux/interrupt.h> 21#include <linux/irq.h> 22#include <linux/platform_device.h> 23#include <linux/fb.h> 24 25#include <asm/setup.h> 26#include <asm/memory.h> 27#include <asm/mach-types.h> 28#include <mach/hardware.h> 29#include <asm/irq.h> 30 31#include <asm/mach/arch.h> 32#include <asm/mach/map.h> 33 34#include <mach/pxa25x.h> 35#include <mach/idp.h> 36#include <linux/platform_data/video-pxafb.h> 37#include <mach/bitfield.h> 38#include <linux/platform_data/mmc-pxamci.h> 39#include <linux/smc91x.h> 40 41#include "generic.h" 42#include "devices.h" 43 44/* TODO: 45 * - add pxa2xx_audio_ops_t device structure 46 * - Ethernet interrupt 47 */ 48 49static unsigned long idp_pin_config[] __initdata = { 50 /* LCD */ 51 GPIOxx_LCD_DSTN_16BPP, 52 53 /* BTUART */ 54 GPIO42_BTUART_RXD, 55 GPIO43_BTUART_TXD, 56 GPIO44_BTUART_CTS, 57 GPIO45_BTUART_RTS, 58 59 /* STUART */ 60 GPIO46_STUART_RXD, 61 GPIO47_STUART_TXD, 62 63 /* MMC */ 64 GPIO6_MMC_CLK, 65 GPIO8_MMC_CS0, 66 67 /* Ethernet */ 68 GPIO33_nCS_5, /* Ethernet CS */ 69 GPIO4_GPIO, /* Ethernet IRQ */ 70}; 71 72static struct resource smc91x_resources[] = { 73 [0] = { 74 .start = (IDP_ETH_PHYS + 0x300), 75 .end = (IDP_ETH_PHYS + 0xfffff), 76 .flags = IORESOURCE_MEM, 77 }, 78 [1] = { 79 .start = PXA_GPIO_TO_IRQ(4), 80 .end = PXA_GPIO_TO_IRQ(4), 81 .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE, 82 } 83}; 84 85static struct smc91x_platdata smc91x_platdata = { 86 .flags = SMC91X_USE_32BIT | SMC91X_USE_DMA | SMC91X_NOWAIT, 87}; 88 89static struct platform_device smc91x_device = { 90 .name = "smc91x", 91 .id = 0, 92 .num_resources = ARRAY_SIZE(smc91x_resources), 93 .resource = smc91x_resources, 94 .dev.platform_data = &smc91x_platdata, 95}; 96 97static void idp_backlight_power(int on) 98{ 99 if (on) { 100 IDP_CPLD_LCD |= (1<<1); 101 } else { 102 IDP_CPLD_LCD &= ~(1<<1); 103 } 104} 105 106static void idp_vlcd(int on) 107{ 108 if (on) { 109 IDP_CPLD_LCD |= (1<<2); 110 } else { 111 IDP_CPLD_LCD &= ~(1<<2); 112 } 113} 114 115static void idp_lcd_power(int on, struct fb_var_screeninfo *var) 116{ 117 if (on) { 118 IDP_CPLD_LCD |= (1<<0); 119 } else { 120 IDP_CPLD_LCD &= ~(1<<0); 121 } 122 123 /* call idp_vlcd for now as core driver does not support 124 * both power and vlcd hooks. Note, this is not technically 125 * the correct sequence, but seems to work. Disclaimer: 126 * this may eventually damage the display. 127 */ 128 129 idp_vlcd(on); 130} 131 132static struct pxafb_mode_info sharp_lm8v31_mode = { 133 .pixclock = 270000, 134 .xres = 640, 135 .yres = 480, 136 .bpp = 16, 137 .hsync_len = 1, 138 .left_margin = 3, 139 .right_margin = 3, 140 .vsync_len = 1, 141 .upper_margin = 0, 142 .lower_margin = 0, 143 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 144 .cmap_greyscale = 0, 145}; 146 147static struct pxafb_mach_info sharp_lm8v31 = { 148 .modes = &sharp_lm8v31_mode, 149 .num_modes = 1, 150 .cmap_inverse = 0, 151 .cmap_static = 0, 152 .lcd_conn = LCD_COLOR_DSTN_16BPP | LCD_PCLK_EDGE_FALL | 153 LCD_AC_BIAS_FREQ(255), 154 .pxafb_backlight_power = &idp_backlight_power, 155 .pxafb_lcd_power = &idp_lcd_power 156}; 157 158static struct pxamci_platform_data idp_mci_platform_data = { 159 .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, 160 .gpio_card_detect = -1, 161 .gpio_card_ro = -1, 162 .gpio_power = -1, 163}; 164 165static void __init idp_init(void) 166{ 167 printk("idp_init()\n"); 168 169 pxa2xx_mfp_config(ARRAY_AND_SIZE(idp_pin_config)); 170 pxa_set_ffuart_info(NULL); 171 pxa_set_btuart_info(NULL); 172 pxa_set_stuart_info(NULL); 173 174 platform_device_register(&smc91x_device); 175 //platform_device_register(&mst_audio_device); 176 pxa_set_fb_info(NULL, &sharp_lm8v31); 177 pxa_set_mci_info(&idp_mci_platform_data); 178} 179 180static struct map_desc idp_io_desc[] __initdata = { 181 { 182 .virtual = IDP_COREVOLT_VIRT, 183 .pfn = __phys_to_pfn(IDP_COREVOLT_PHYS), 184 .length = IDP_COREVOLT_SIZE, 185 .type = MT_DEVICE 186 }, { 187 .virtual = IDP_CPLD_VIRT, 188 .pfn = __phys_to_pfn(IDP_CPLD_PHYS), 189 .length = IDP_CPLD_SIZE, 190 .type = MT_DEVICE 191 } 192}; 193 194static void __init idp_map_io(void) 195{ 196 pxa25x_map_io(); 197 iotable_init(idp_io_desc, ARRAY_SIZE(idp_io_desc)); 198} 199 200/* LEDs */ 201#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) 202struct idp_led { 203 struct led_classdev cdev; 204 u8 mask; 205}; 206 207/* 208 * The triggers lines up below will only be used if the 209 * LED triggers are compiled in. 210 */ 211static const struct { 212 const char *name; 213 const char *trigger; 214} idp_leds[] = { 215 { "idp:green", "heartbeat", }, 216 { "idp:red", "cpu0", }, 217}; 218 219static void idp_led_set(struct led_classdev *cdev, 220 enum led_brightness b) 221{ 222 struct idp_led *led = container_of(cdev, 223 struct idp_led, cdev); 224 u32 reg = IDP_CPLD_LED_CONTROL; 225 226 if (b != LED_OFF) 227 reg &= ~led->mask; 228 else 229 reg |= led->mask; 230 231 IDP_CPLD_LED_CONTROL = reg; 232} 233 234static enum led_brightness idp_led_get(struct led_classdev *cdev) 235{ 236 struct idp_led *led = container_of(cdev, 237 struct idp_led, cdev); 238 239 return (IDP_CPLD_LED_CONTROL & led->mask) ? LED_OFF : LED_FULL; 240} 241 242static int __init idp_leds_init(void) 243{ 244 int i; 245 246 if (!machine_is_pxa_idp()) 247 return -ENODEV; 248 249 for (i = 0; i < ARRAY_SIZE(idp_leds); i++) { 250 struct idp_led *led; 251 252 led = kzalloc(sizeof(*led), GFP_KERNEL); 253 if (!led) 254 break; 255 256 led->cdev.name = idp_leds[i].name; 257 led->cdev.brightness_set = idp_led_set; 258 led->cdev.brightness_get = idp_led_get; 259 led->cdev.default_trigger = idp_leds[i].trigger; 260 261 if (i == 0) 262 led->mask = IDP_HB_LED; 263 else 264 led->mask = IDP_BUSY_LED; 265 266 if (led_classdev_register(NULL, &led->cdev) < 0) { 267 kfree(led); 268 break; 269 } 270 } 271 272 return 0; 273} 274 275/* 276 * Since we may have triggers on any subsystem, defer registration 277 * until after subsystem_init. 278 */ 279fs_initcall(idp_leds_init); 280#endif 281 282MACHINE_START(PXA_IDP, "Vibren PXA255 IDP") 283 /* Maintainer: Vibren Technologies */ 284 .map_io = idp_map_io, 285 .nr_irqs = PXA_NR_IRQS, 286 .init_irq = pxa25x_init_irq, 287 .handle_irq = pxa25x_handle_irq, 288 .init_time = pxa_timer_init, 289 .init_machine = idp_init, 290 .restart = pxa_restart, 291MACHINE_END 292