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