pandora: mark problematic supplies as always-on
[pandora-kernel.git] / arch / arm / mach-omap2 / board-omap3pandora.c
index f2eb88a..d82abbf 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/nand.h>
 #include <linux/leds.h>
+#include <linux/leds_pwm.h>
 #include <linux/input.h>
 #include <linux/input/matrix_keypad.h>
 #include <linux/gpio.h>
@@ -35,6 +36,9 @@
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
 #include <linux/regulator/fixed.h>
+#include <linux/i2c/vsense.h>
+#include <linux/dma-mapping.h>
+#include <linux/dma-contiguous.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
 #include "mux.h"
 #include "sdram-micron-mt46h32m32lf-6.h"
+#include "sdram-micron-mt29c4g96mazapcjg-5.h"
 #include "hsmmc.h"
 #include "common-board-devices.h"
 
 #define PANDORA_WIFI_IRQ_GPIO          21
 #define PANDORA_WIFI_NRESET_GPIO       23
 #define OMAP3_PANDORA_TS_GPIO          94
+#define PANDORA_EN_USB_5V_GPIO         164
 
 static struct mtd_partition omap3pandora_nand_partitions[] = {
        {
@@ -88,6 +94,7 @@ static struct omap_nand_platform_data pandora_nand_data = {
        .xfer_type      = NAND_OMAP_PREFETCH_DMA,
        .parts          = omap3pandora_nand_partitions,
        .nr_parts       = ARRAY_SIZE(omap3pandora_nand_partitions),
+       .dev_ready      = true,
 };
 
 static struct gpio_led pandora_gpio_leds[] = {
@@ -121,6 +128,39 @@ static struct platform_device pandora_leds_gpio = {
        },
 };
 
+static struct led_pwm pandora_pwm_leds[] = {
+       {
+               .name                   = "pandora::keypad_bl",
+               .pwm_id                 = 0, /* LEDA */
+       }, {
+               .name                   = "pandora::power",
+               .default_trigger        = "default-on",
+               .pwm_id                 = 1, /* LEDB */
+       }, {
+               .name                   = "pandora::charger",
+               .default_trigger        = "twl4030_bci-charging",
+               .pwm_id                 = 3, /* PWM1 */
+       }
+};
+
+static struct led_pwm_platform_data pandora_pwm_led_data = {
+       .leds           = pandora_pwm_leds,
+       .num_leds       = ARRAY_SIZE(pandora_pwm_leds),
+};
+
+static struct platform_device pandora_leds_pwm = {
+       .name   = "leds-twl4030-pwm",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &pandora_pwm_led_data,
+       },
+};
+
+static struct platform_device pandora_bl = {
+       .name   = "pandora-backlight",
+       .id     = -1,
+};
+
 #define GPIO_BUTTON(gpio_num, ev_type, ev_code, act_low, descr)        \
 {                                                              \
        .gpio           = gpio_num,                             \
@@ -167,6 +207,9 @@ static struct platform_device pandora_keys_gpio = {
        },
 };
 
+/* HACK: this requires patched twl4030_keypad driver */
+#define FNKEY(row, col, code) KEY((row + 8), col, code)
+
 static const uint32_t board_keymap[] = {
        /* row, col, code */
        KEY(0, 0, KEY_9),
@@ -212,6 +255,50 @@ static const uint32_t board_keymap[] = {
        KEY(7, 2, KEY_Q),
        KEY(7, 3, KEY_LEFTSHIFT),
        KEY(7, 4, KEY_COMMA),
+       /* Fn keys */
+       FNKEY(0, 0, KEY_F9),
+       FNKEY(0, 1, KEY_F8),
+       FNKEY(0, 2, KEY_BRIGHTNESSUP),
+       FNKEY(0, 3, KEY_F13),           /* apostrophe, differs from Fn-A? */
+       FNKEY(0, 4, KEY_F22),
+       FNKEY(0, 5, KEY_F23),
+       FNKEY(1, 0, KEY_F10),
+       FNKEY(1, 1, KEY_F7),
+       FNKEY(1, 2, KEY_BRIGHTNESSDOWN),
+       FNKEY(1, 3, KEY_GRAVE),
+       FNKEY(1, 4, KEY_F14),           /* pipe/bar */
+       FNKEY(1, 5, KEY_TAB),
+       FNKEY(2, 0, KEY_INSERT),
+       FNKEY(2, 1, KEY_F6),
+       FNKEY(2, 2, KEY_F15),           /* dash */
+       FNKEY(2, 3, KEY_EQUAL),
+       FNKEY(2, 4, KEY_F16),           /* # (pound/hash) */
+       FNKEY(2, 5, KEY_FN),
+       FNKEY(3, 0, KEY_F11),
+       FNKEY(3, 1, KEY_F5),
+       FNKEY(3, 2, KEY_F17),           /* ! */
+       FNKEY(3, 3, KEY_KPPLUS),
+       FNKEY(3, 4, KEY_BACKSLASH),
+       FNKEY(4, 0, KEY_F12),
+       FNKEY(4, 1, KEY_F4),
+       FNKEY(4, 2, KEY_RIGHTBRACE),
+       FNKEY(4, 3, KEY_KPMINUS),
+       FNKEY(4, 4, KEY_QUESTION),
+       FNKEY(5, 0, KEY_F18),           /* £ (pound) */
+       FNKEY(5, 1, KEY_F3),
+       FNKEY(5, 2, KEY_LEFTBRACE),
+       FNKEY(5, 3, KEY_F19),           /* " */
+       FNKEY(5, 4, KEY_SLASH),
+       FNKEY(6, 0, KEY_YEN),
+       FNKEY(6, 1, KEY_F2),
+       FNKEY(6, 2, KEY_F20),           /* @ */
+       FNKEY(6, 3, KEY_APOSTROPHE),
+       FNKEY(6, 4, KEY_F21),           /* : */
+       FNKEY(7, 0, KEY_ENTER),
+       FNKEY(7, 1, KEY_F1),
+       FNKEY(7, 2, KEY_ESC),
+       FNKEY(7, 3, KEY_CAPSLOCK),
+       FNKEY(7, 4, KEY_SEMICOLON),
 };
 
 static struct matrix_keymap_data board_map_data = {
@@ -263,7 +350,7 @@ static void pandora_wl1251_init_card(struct mmc_card *card)
        card->cis.vendor = 0x104c;
        card->cis.device = 0x9066;
        card->cis.blksize = 512;
-       card->cis.max_dtr = 20000000;
+       card->cis.max_dtr = 24000000;
 }
 
 static struct omap2_hsmmc_info omap3pandora_mmc[] = {
@@ -271,14 +358,16 @@ static struct omap2_hsmmc_info omap3pandora_mmc[] = {
                .mmc            = 1,
                .caps           = MMC_CAP_4_BIT_DATA,
                .gpio_cd        = -EINVAL,
-               .gpio_wp        = 126,
+               //.gpio_wp      = 126,
+               .gpio_wp        = -EINVAL,
                .ext_clock      = 0,
        },
        {
                .mmc            = 2,
                .caps           = MMC_CAP_4_BIT_DATA,
                .gpio_cd        = -EINVAL,
-               .gpio_wp        = 127,
+               //.gpio_wp      = 127,
+               .gpio_wp        = -EINVAL,
                .ext_clock      = 1,
                .transceiver    = true,
        },
@@ -318,6 +407,9 @@ static struct twl4030_gpio_platform_data omap3pandora_gpio_data = {
        .irq_base       = TWL4030_GPIO_IRQ_BASE,
        .irq_end        = TWL4030_GPIO_IRQ_END,
        .setup          = omap3pandora_twl_gpio_setup,
+       /* note: never set PU/PD for gpio2, it's connected to vaux2 */
+       .pulldowns      = BIT(8) | BIT(15) | BIT(16) | BIT(17),
+       .debounce       = BIT(0) | BIT(1),
 };
 
 static struct regulator_consumer_supply pandora_vmmc1_supply[] = {
@@ -340,10 +432,16 @@ static struct regulator_consumer_supply pandora_vdds_supplies[] = {
 
 static struct regulator_consumer_supply pandora_vcc_lcd_supply[] = {
        REGULATOR_SUPPLY("vcc", "display0"),
+       /* on non-CC units only, must be last */
+       REGULATOR_SUPPLY("vdd", "display0"),
 };
 
 static struct regulator_consumer_supply pandora_usb_phy_supply[] = {
-       REGULATOR_SUPPLY("hsusb0", "ehci-omap.0"),
+       REGULATOR_SUPPLY("hsusb1", "ehci-omap.0"),
+};
+
+static struct regulator_consumer_supply pandora_exp_supply[] = {
+       REGULATOR_SUPPLY("exp", NULL),
 };
 
 /* ads7846 on SPI and 2 nub controllers on I2C */
@@ -355,6 +453,14 @@ static struct regulator_consumer_supply pandora_vaux4_supplies[] = {
 
 static struct regulator_consumer_supply pandora_adac_supply[] = {
        REGULATOR_SUPPLY("vcc", "soc-audio"),
+       REGULATOR_SUPPLY("lidsw", NULL),
+};
+
+static struct regulator_consumer_supply pandora_5v_supplies[] = {
+       REGULATOR_SUPPLY("v5v_force", NULL),
+       REGULATOR_SUPPLY("vdd_amp", "soc-audio"),
+       REGULATOR_SUPPLY("hsusb1_vbus", "ehci-omap.0"),
+       REGULATOR_SUPPLY("vdd", "display0"), /* on CC units, must be last */
 };
 
 /* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */
@@ -412,21 +518,40 @@ static struct regulator_init_data pandora_vaux2 = {
                                        | REGULATOR_MODE_STANDBY,
                .valid_ops_mask         = REGULATOR_CHANGE_MODE
                                        | REGULATOR_CHANGE_STATUS,
+               /* turning it off wastes power for unknown reason */
+               .always_on              = true,
        },
        .num_consumer_supplies  = ARRAY_SIZE(pandora_usb_phy_supply),
        .consumer_supplies      = pandora_usb_phy_supply,
 };
 
+/* VAUX3 goes to the expansion port */
+static struct regulator_init_data pandora_vaux3 = {
+       .constraints = {
+               .min_uV                 = 1500000,
+               .max_uV                 = 3000000,
+               .valid_modes_mask       = REGULATOR_MODE_NORMAL
+                                       | REGULATOR_MODE_STANDBY,
+               .valid_ops_mask         = REGULATOR_CHANGE_VOLTAGE
+                                       | REGULATOR_CHANGE_MODE
+                                       | REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies  = ARRAY_SIZE(pandora_exp_supply),
+       .consumer_supplies      = pandora_exp_supply,
+};
+
 /* VAUX4 for ads7846 and nubs */
 static struct regulator_init_data pandora_vaux4 = {
        .constraints = {
-               .min_uV                 = 2800000,
-               .max_uV                 = 2800000,
+               .min_uV                 = 3000000,
+               .max_uV                 = 3000000,
                .apply_uV               = true,
                .valid_modes_mask       = REGULATOR_MODE_NORMAL
                                        | REGULATOR_MODE_STANDBY,
                .valid_ops_mask         = REGULATOR_CHANGE_MODE
                                        | REGULATOR_CHANGE_STATUS,
+               /* turning it off wastes power for unknown reason */
+               .always_on              = true,
        },
        .num_consumer_supplies  = ARRAY_SIZE(pandora_vaux4_supplies),
        .consumer_supplies      = pandora_vaux4_supplies,
@@ -447,6 +572,40 @@ static struct regulator_init_data pandora_vsim = {
        .consumer_supplies      = pandora_adac_supply,
 };
 
+/* REGEN enables the 5V supply */
+static struct regulator_init_data pandora_regen = {
+       .constraints = {
+               .valid_modes_mask       = REGULATOR_MODE_NORMAL
+                                       | REGULATOR_MODE_STANDBY,
+               .valid_ops_mask         = REGULATOR_CHANGE_MODE
+                                       | REGULATOR_CHANGE_STATUS,
+       },
+};
+
+/* 5V supply that feeds EHCI VBUS, audio amp, and (on CC only) the LCD */
+static struct regulator_init_data pandora_v5v_data = {
+       .supply_regulator       = "REGEN",
+       .num_consumer_supplies  = ARRAY_SIZE(pandora_5v_supplies),
+       .consumer_supplies      = pandora_5v_supplies,
+};
+
+static struct fixed_voltage_config pandora_v5v = {
+       .supply_name            = "v5v",
+       .microvolts             = 5000000,
+       .gpio                   = -EINVAL,
+       .startup_delay          = 5000, /* just a guess */
+       .enabled_at_boot        = 1,
+       .init_data              = &pandora_v5v_data,
+};
+
+static struct platform_device pandora_v5v_device = {
+       .name           = "reg-fixed-voltage",
+       .id             = 0,
+       .dev = {
+               .platform_data = &pandora_v5v,
+       },
+};
+
 /* Fixed regulator internal to Wifi module */
 static struct regulator_init_data pandora_vmmc3 = {
        .constraints = {
@@ -474,7 +633,59 @@ static struct platform_device pandora_vwlan_device = {
        },
 };
 
-static struct twl4030_bci_platform_data pandora_bci_data;
+static char *pandora_power_supplied_to[] = {
+       "bq27500-0",
+};
+
+static struct twl4030_bci_platform_data pandora_bci_data = {
+       .supplied_to            = pandora_power_supplied_to,
+       .num_supplicants        = ARRAY_SIZE(pandora_power_supplied_to),
+};
+
+static struct twl4030_ins sleep_on_seq[] = {
+       { MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, 1, 0, RES_STATE_SLEEP), 2 },
+};
+
+static struct twl4030_script sleep_on_script = {
+       .script = sleep_on_seq,
+       .size   = ARRAY_SIZE(sleep_on_seq),
+       .flags  = TWL4030_SLEEP_SCRIPT,
+};
+
+static struct twl4030_ins wakeup_p3_seq[] = {
+       { MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, 1, 0, RES_STATE_ACTIVE), 2 },
+};
+
+static struct twl4030_script wakeup_p3_script = {
+       .script = wakeup_p3_seq,
+       .size   = ARRAY_SIZE(wakeup_p3_seq),
+       .flags  = TWL4030_WAKEUP3_SCRIPT,
+};
+
+static struct twl4030_script *twl4030_scripts[] = {
+       /* wakeup script should be loaded before sleep script, otherwise a
+          board might hit retention before loading of wakeup script is
+          completed. This can cause boot failures depending on timing issues.
+       */
+       &wakeup_p3_script,
+       &sleep_on_script,
+};
+
+static struct twl4030_resconfig twl4030_rconfig[] = {
+       {
+               .resource = RES_HFCLKOUT, .devgroup = DEV_GRP_P3,
+               .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
+       },
+       { 0, 0},
+};
+
+static struct twl4030_power_data pandora_power_data = {
+       .scripts        = twl4030_scripts,
+       .num            = ARRAY_SIZE(twl4030_scripts),
+       .resource_config = twl4030_rconfig,
+
+       .use_poweroff   = 1,
+};
 
 static struct twl4030_platform_data omap3pandora_twldata = {
        .gpio           = &omap3pandora_gpio_data,
@@ -482,14 +693,37 @@ static struct twl4030_platform_data omap3pandora_twldata = {
        .vmmc2          = &pandora_vmmc2,
        .vaux1          = &pandora_vaux1,
        .vaux2          = &pandora_vaux2,
+       .vaux3          = &pandora_vaux3,
        .vaux4          = &pandora_vaux4,
        .vsim           = &pandora_vsim,
+       .regen          = &pandora_regen,
        .keypad         = &pandora_kp_data,
        .bci            = &pandora_bci_data,
+       .power          = &pandora_power_data,
+
+       .dep_device     = &pandora_v5v_device,
+};
+
+static struct vsense_platform_data omap3pandora_nub1_data = {
+       .gpio_irq       = 161,
+       .gpio_reset     = 156,
+};
+
+static struct vsense_platform_data omap3pandora_nub2_data = {
+       .gpio_irq       = 162,
+       .gpio_reset     = 156,
 };
 
 static struct i2c_board_info __initdata omap3pandora_i2c3_boardinfo[] = {
        {
+               I2C_BOARD_INFO("vsense", 0x66),
+               .flags = I2C_CLIENT_WAKE,
+               .platform_data = &omap3pandora_nub1_data,
+       }, {
+               I2C_BOARD_INFO("vsense", 0x67),
+               .flags = I2C_CLIENT_WAKE,
+               .platform_data = &omap3pandora_nub2_data,
+       }, {
                I2C_BOARD_INFO("bq27500", 0x55),
                .flags = I2C_CLIENT_WAKE,
        },
@@ -508,6 +742,12 @@ static int __init omap3pandora_i2c_init(void)
                                        ARRAY_SIZE(pandora_vdds_supplies);
        omap3pandora_twldata.vpll2->consumer_supplies = pandora_vdds_supplies;
 
+       /* LCD vdd is connected differently on CC */
+       if (cpu_is_omap3630() || omap_rev() >= OMAP3430_REV_ES3_0)
+               pandora_v5v_data.num_consumer_supplies--;
+       else
+               pandora_vaux1.num_consumer_supplies--;
+
        omap3_pmic_init("tps65950", &omap3pandora_twldata);
        /* i2c2 pins are not connected */
        omap_register_i2c_bus(3, 100, omap3pandora_i2c3_boardinfo,
@@ -553,44 +793,278 @@ fail:
        printk(KERN_ERR "wl1251 board initialisation failed\n");
 }
 
+static void __init pandora_usb_host_init(void)
+{
+       int ret;
+
+       ret = gpio_request_one(PANDORA_EN_USB_5V_GPIO, GPIOF_OUT_INIT_HIGH,
+               "ehci vbus");
+       if (ret < 0)
+               pr_err("Cannot set vbus GPIO, ret=%d\n", ret);
+}
+
+#include <linux/spi/ads7846.h>
+#include <asm/system.h>
+
+static DECLARE_COMPLETION(ts_completion);
+static struct timespec ts_last_framedone;
+static int pendown_state;
+
+static void vsync_irq_wait_handler(void *data, u32 mask)
+{
+       getnstimeofday(&ts_last_framedone);
+
+       /* reliable to read here */
+       pendown_state = !gpio_get_value(OMAP3_PANDORA_TS_GPIO);
+
+       complete(&ts_completion);
+}
+
+static void ads7846_wait_for_sync(void)
+{
+       struct timespec now, diff;
+       u32 diff_us;
+
+       getnstimeofday(&now);
+       diff = timespec_sub(now, ts_last_framedone);
+       diff_us = diff.tv_nsec / NSEC_PER_USEC + diff.tv_sec * USEC_PER_SEC;
+       if (diff_us < 1023 || diff_us > 40000)
+               /* still blanking or display inactive */
+               return;
+
+       /* wait for blanking period */
+       disable_hlt();
+       wait_for_completion_timeout(&ts_completion, HZ / 30);
+       enable_hlt();
+}
+
+static int pandora_pendown_state(void)
+{
+       static int val_old;
+       struct timespec now, diff;
+       u32 diff_us;
+       int val;
+       int ret;
+       
+       /* This line is a noisy mess. It doesn't trigger spuriously, i.e.
+        * there is no signal when pen is up, but when it's down we have
+        * white noise of sorts. */
+       val = !gpio_get_value(OMAP3_PANDORA_TS_GPIO);
+       pendown_state |= val;
+
+       if (in_irq() || in_atomic())
+               /* no time to fight noise.. */
+               return val | pendown_state;
+
+       if (val == 0) {
+               getnstimeofday(&now);
+               diff = timespec_sub(now, ts_last_framedone);
+               diff_us = diff.tv_nsec / NSEC_PER_USEC + diff.tv_sec * USEC_PER_SEC;
+
+               if (diff_us < 40000)
+                       /* assume pendown_state is up-to-date */
+                       val = pendown_state;
+               else
+                       pendown_state = 0;
+       }
+
+       if (val != val_old) {
+               init_completion(&ts_completion);
+               dispc_runtime_get();
+               if (val)
+                       ret = omap_dispc_register_isr(vsync_irq_wait_handler,
+                               NULL, DISPC_IRQ_VSYNC);
+               else
+                       ret = omap_dispc_unregister_isr(vsync_irq_wait_handler,
+                               NULL, DISPC_IRQ_VSYNC);
+               dispc_runtime_put();
+               if (ret != 0)
+                       pr_err("%s: can't (un)register isr: %d %d\n",
+                               __func__, val, ret);
+               val_old = val;
+       }
+
+       return val;
+}
+
+static struct ads7846_platform_data pandora_ads7846_cfg = {
+       .x_max                  = 0x0fff,
+       .y_max                  = 0x0fff,
+       .x_plate_ohms           = 180,
+       .pressure_max           = 255,
+       .debounce_max           = 10,
+       .debounce_tol           = 3,
+       .debounce_rep           = 1,
+       .gpio_pendown           = OMAP3_PANDORA_TS_GPIO,
+       .keep_vref_on           = 1,
+       .wait_for_sync          = ads7846_wait_for_sync,
+       .get_pendown_state      = pandora_pendown_state,
+};
+
+static struct platform_device pandora_ram_console = {
+       .name   = "ram_console",
+       .id     = -1,
+};
+
+static struct platform_device pandora_c64_tools = {
+       .name   = "c64_tools",
+       .dev    = {
+               .coherent_dma_mask = DMA_BIT_MASK(32),
+       },
+};
+
 static struct platform_device *omap3pandora_devices[] __initdata = {
        &pandora_leds_gpio,
+       &pandora_leds_pwm,
+       &pandora_bl,
        &pandora_keys_gpio,
        &pandora_vwlan_device,
+       &pandora_ram_console,
+       &pandora_c64_tools,
 };
 
 static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
 
-       .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
-       .port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED,
+       .port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED,
+       .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
        .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
 
        .phy_reset  = true,
-       .reset_gpio_port[0]  = 16,
-       .reset_gpio_port[1]  = -EINVAL,
+       .reset_gpio_port[0]  = -EINVAL,
+       .reset_gpio_port[1]  = 16,
        .reset_gpio_port[2]  = -EINVAL
 };
 
 #ifdef CONFIG_OMAP_MUX
 static struct omap_board_mux board_mux[] __initdata = {
+       /* enable wakeup for pandora button (GPIO99) */
+       OMAP3_MUX(CAM_D0, OMAP_INPUT_EN | OMAP_WAKEUP_EN | OMAP_MUX_MODE4),
+       /* noisy unused signal from LCD cable */
+       OMAP3_MUX(CAM_VS, OMAP_INPUT_EN | OMAP_PULL_ENA | OMAP_PULL_UP | OMAP_MUX_MODE7),
        { .reg_offset = OMAP_MUX_TERMINATOR },
 };
 #endif
 
+static struct regulator *lid_switch_power;
+static struct regulator *v5v_power;
+static struct regulator *exp_power;
+static bool v5v_power_disable_needed;
+static bool exp_power_disable_needed;
+static struct delayed_work disable_regulators_work;
+
+#ifdef CONFIG_PM_SLEEP
+static int pandora_pm_suspend(struct device *dev)
+{
+       if (!IS_ERR_OR_NULL(lid_switch_power))
+               regulator_disable(lid_switch_power);
+
+       return 0;
+}
+
+static int pandora_pm_resume(struct device *dev)
+{
+       if (!IS_ERR_OR_NULL(lid_switch_power))
+               regulator_enable(lid_switch_power);
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pandora_pm, pandora_pm_suspend, pandora_pm_resume);
+
+static void pandora_disable_regulators(struct work_struct *work)
+{
+       if (v5v_power_disable_needed)
+               regulator_disable(v5v_power);
+
+       if (exp_power_disable_needed)
+               regulator_disable(exp_power);
+}
+
+static int __devinit pandora_pm_probe(struct platform_device *pdev)
+{
+       lid_switch_power = regulator_get(NULL, "lidsw");
+       if (!IS_ERR(lid_switch_power))
+               regulator_enable(lid_switch_power);
+       else
+               dev_err(&pdev->dev, "regulator_get lidsw: %ld\n",
+                       PTR_ERR(lid_switch_power));
+
+       /* if regulators are enabled by the bootloaders, take a reference and
+        * disable them later, after the boot scripts have a chance to
+        * reconfigure things if they want to, otherwise leave them off */
+       v5v_power = regulator_get(NULL, "v5v_force");
+       if (!IS_ERR(v5v_power)) {
+               if (regulator_is_enabled(v5v_power) > 0) {
+                       v5v_power_disable_needed = true;
+                       regulator_enable(v5v_power);
+               }
+       }
+       else {
+               dev_err(&pdev->dev, "regulator_get v5v_force: %ld\n",
+                       PTR_ERR(v5v_power));
+       }
+
+       exp_power = regulator_get(NULL, "exp");
+       if (!IS_ERR(exp_power)) {
+               if (regulator_is_enabled(exp_power) > 0) {
+                       exp_power_disable_needed = true;
+                       regulator_enable(exp_power);
+               }
+       }
+       else {
+               dev_err(&pdev->dev, "regulator_get exp: %ld\n",
+                       PTR_ERR(exp_power));
+       }
+
+       INIT_DELAYED_WORK(&disable_regulators_work,
+               pandora_disable_regulators);
+       schedule_delayed_work(&disable_regulators_work, 30 * HZ);
+
+       return 0;
+}
+
+static struct platform_driver pandora_pm_driver = {
+       .probe          = pandora_pm_probe,
+       .driver         = {
+               .name   = "pandora-pm",
+               .pm     = &pandora_pm,
+       },
+};
+
+static struct platform_device pandora_pm_dev = {
+       .name   = "pandora-pm",
+       .id     = -1,
+};
+
+static int __init pandora_pm_drv_reg(void)
+{
+       platform_device_register(&pandora_pm_dev);
+       return platform_driver_register(&pandora_pm_driver);
+}
+late_initcall(pandora_pm_drv_reg);
+
 static void __init omap3pandora_init(void)
 {
+       struct omap_sdrc_params *sdrc_params;
+
        omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+       pandora_usb_host_init();
        omap3pandora_i2c_init();
        pandora_wl1251_init();
        platform_add_devices(omap3pandora_devices,
                        ARRAY_SIZE(omap3pandora_devices));
        omap_display_init(&pandora_dss_data);
        omap_serial_init();
-       omap_sdrc_init(mt46h32m32lf6_sdrc_params,
-                                 mt46h32m32lf6_sdrc_params);
+
+       sdrc_params = mt46h32m32lf6_sdrc_params;
+       if (cpu_is_omap3630() || omap_rev() >= OMAP3430_REV_ES3_0)
+               sdrc_params = mt29c4g96mazapcjg5_sdrc_params;
+       omap_sdrc_init(sdrc_params, sdrc_params);
+
        spi_register_board_info(omap3pandora_spi_board_info,
                        ARRAY_SIZE(omap3pandora_spi_board_info));
-       omap_ads7846_init(1, OMAP3_PANDORA_TS_GPIO, 0, NULL);
+       omap_ads7846_init(1, OMAP3_PANDORA_TS_GPIO, 31, &pandora_ads7846_cfg);
        usbhs_init(&usbhs_bdata);
        usb_musb_init(NULL);
        gpmc_nand_init(&pandora_nand_data);
@@ -600,25 +1074,166 @@ static void __init omap3pandora_init(void)
        omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT);
 }
 
-/* HACK: create it here, so that others don't need to bother */
 #ifdef CONFIG_PROC_FS
 #include <linux/proc_fs.h>
+#include <linux/uaccess.h>
+
+static bool v5v_power_proc_enabled;
+static bool exp_power_proc_enabled;
+
+static int v5v_enable_read(char *page, char **start, off_t off,
+               int count, int *eof, void *data)
+{
+       if (IS_ERR_OR_NULL(v5v_power))
+               return -ENODEV;
+
+       *eof = 1;
+       return sprintf(page, "%d\n", v5v_power_proc_enabled);
+}
+
+static int v5v_enable_write(struct file *file, const char __user *buffer,
+               unsigned long count, void *data)
+{
+       char buff[32];
+       long val;
+       int ret;
+
+       if (IS_ERR_OR_NULL(v5v_power))
+               return -ENODEV;
+
+       count = strncpy_from_user(buff, buffer,
+                       count < sizeof(buff) ? count : sizeof(buff) - 1);
+       buff[count] = 0;
+
+       ret = strict_strtol(buff, 0, &val);
+       if (ret < 0)
+               return ret;
+
+       val = !!val;
+       if (val == v5v_power_proc_enabled)
+               return count;
+       if (val)
+               ret = regulator_enable(v5v_power);
+       else
+               ret = regulator_disable(v5v_power);
+       if (ret < 0)
+               return ret;
+
+       v5v_power_proc_enabled = val;
+       return count;
+}
+
+static int exp_power_read(char *page, char **start, off_t off,
+               int count, int *eof, void *data)
+{
+       int ret = 0;
+
+       if (IS_ERR_OR_NULL(exp_power))
+               return -ENODEV;
+
+       if (regulator_is_enabled(exp_power) > 0) {
+               ret = regulator_get_voltage(exp_power);
+               if (ret < 0)
+                       return ret;
+               ret /= 1000;
+       }
+
+       *eof = 1;
+       return sprintf(page, "%d\n", ret);
+}
+
+static int exp_power_write(struct file *file, const char __user *buffer,
+               unsigned long count, void *data)
+{
+       char buff[32];
+       bool enable;
+       long val;
+       int ret;
+
+       if (IS_ERR_OR_NULL(exp_power))
+               return -ENODEV;
+
+       count = strncpy_from_user(buff, buffer,
+                       count < sizeof(buff) ? count : sizeof(buff) - 1);
+       buff[count] = 0;
+
+       ret = strict_strtol(buff, 0, &val);
+       if (ret < 0)
+               return ret;
+
+       if (val != 0) {
+               val *= 1000;
+               ret = regulator_set_voltage(exp_power, val, val);
+               if (ret < 0)
+                       return ret;
+       }
+       enable = !!val;
+       if (enable == exp_power_proc_enabled)
+               return count;
+       if (enable)
+               ret = regulator_enable(exp_power);
+       else
+               ret = regulator_disable(exp_power);
+       if (ret < 0)
+               return ret;
+
+       exp_power_proc_enabled = enable;
+       return count;
+}
 
 static int __init proc_pandora_init(void)
 {
-       struct proc_dir_entry *ret;
+       struct proc_dir_entry *root, *ret;
 
-       ret = proc_mkdir("pandora", NULL);
-       if (!ret)
+       /* HACK: create it here, so that others don't need to bother */
+       root = proc_mkdir("pandora", NULL);
+       if (root == NULL)
                return -ENOMEM;
+
+       ret = create_proc_entry("always_enable_5v", S_IWUSR | S_IRUGO, root);
+       if (ret != NULL) {
+               ret->read_proc = v5v_enable_read;
+               ret->write_proc = v5v_enable_write;
+       }
+
+       ret = create_proc_entry("exp_power_mv", S_IWUSR | S_IRUGO, root);
+       if (ret != NULL) {
+               ret->read_proc = exp_power_read;
+               ret->write_proc = exp_power_write;
+       }
+
        return 0;
 }
 fs_initcall(proc_pandora_init);
 #endif
 
+/* for debug.. */
+#include <../drivers/staging/android/persistent_ram.h>
+
+struct persistent_ram_descriptor ram_console_desc = {
+       .name           = "ram_console",
+       .size           = 0x20000,
+};
+
+struct persistent_ram ram_console_ram = {
+       .start          = 0x80fe0000,
+       .size           = 0x20000,
+       .num_descs      = 1,
+       .descs          = &ram_console_desc,
+};
+
+void __init pandora_reserve(void)
+{
+       omap_reserve();
+       dma_declare_contiguous(&pandora_c64_tools.dev, 4 * SZ_1M, 0x86000000, 0);
+#ifdef CONFIG_ANDROID_PERSISTENT_RAM
+       persistent_ram_early_init(&ram_console_ram);
+#endif
+}
+
 MACHINE_START(OMAP3_PANDORA, "Pandora Handheld Console")
        .atag_offset    = 0x100,
-       .reserve        = omap_reserve,
+       .reserve        = pandora_reserve,
        .map_io         = omap3_map_io,
        .init_early     = omap35xx_init_early,
        .init_irq       = omap3_init_irq,