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