.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[] = {
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("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 */
static struct regulator_consumer_supply pandora_vaux4_supplies[] = {
REGULATOR_SUPPLY("vcc", "spi1.0"),
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) */
static struct regulator_init_data pandora_vmmc1 = {
.constraints = {
| 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 = {
| 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,
.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 = {
.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 = {
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,
#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)
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;
}
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);