linux/arch/arm/mach-pxa/idp.c
<<
>>
Prefs
   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 "pxa25x.h"
  35#include "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