aboutsummaryrefslogblamecommitdiffstats
path: root/arch/arm/mach-tegra/board-whistler-power.c
blob: 72389f181779c641eba550667d9c5d66a1dbf7f4 (plain) (tree)


































































































































































































































































































                                                                                   
/*
 * Copyright (C) 2010-2011 NVIDIA, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 * 02111-1307, USA
 */
#include <linux/i2c.h>
#include <linux/pda_power.h>
#include <linux/platform_device.h>
#include <linux/resource.h>
#include <linux/regulator/machine.h>
#include <linux/mfd/max8907c.h>
#include <linux/regulator/max8907c-regulator.h>
#include <linux/gpio.h>
#include <linux/io.h>

#include <mach/iomap.h>
#include <mach/irqs.h>

#include "gpio-names.h"
#include "fuse.h"
#include "pm.h"
#include "wakeups-t2.h"
#include "board.h"

#define PMC_CTRL		0x0
#define PMC_CTRL_INTR_LOW	(1 << 17)

static struct regulator_consumer_supply max8907c_SD1_supply[] = {
	REGULATOR_SUPPLY("vdd_cpu", NULL),
};

static struct regulator_consumer_supply max8907c_SD2_supply[] = {
	REGULATOR_SUPPLY("vdd_core", NULL),
	REGULATOR_SUPPLY("vdd_aon", NULL),
};

static struct regulator_consumer_supply max8907c_SD3_supply[] = {
	REGULATOR_SUPPLY("vddio_sys", NULL),
};

static struct regulator_consumer_supply max8907c_LDO1_supply[] = {
	REGULATOR_SUPPLY("vddio_rx_ddr", NULL),
};

static struct regulator_consumer_supply max8907c_LDO2_supply[] = {
	REGULATOR_SUPPLY("avdd_plla", NULL),
};

static struct regulator_consumer_supply max8907c_LDO3_supply[] = {
	REGULATOR_SUPPLY("vdd_vcom_1v8b", NULL),
};

static struct regulator_consumer_supply max8907c_LDO4_supply[] = {
	REGULATOR_SUPPLY("avdd_usb", NULL),
	REGULATOR_SUPPLY("avdd_usb_pll", NULL),
};

static struct regulator_consumer_supply max8907c_LDO5_supply[] = {
};

static struct regulator_consumer_supply max8907c_LDO6_supply[] = {
	REGULATOR_SUPPLY("avdd_hdmi_pll", NULL),
};

static struct regulator_consumer_supply max8907c_LDO7_supply[] = {
	REGULATOR_SUPPLY("avddio_audio", NULL),
};

static struct regulator_consumer_supply max8907c_LDO8_supply[] = {
	REGULATOR_SUPPLY("vdd_vcom_3v0", NULL),
};

static struct regulator_consumer_supply max8907c_LDO9_supply[] = {
	REGULATOR_SUPPLY("vdd_cam1", NULL),
};

static struct regulator_consumer_supply max8907c_LDO10_supply[] = {
	REGULATOR_SUPPLY("avdd_usb_ic", NULL),
};

static struct regulator_consumer_supply max8907c_LDO11_supply[] = {
	REGULATOR_SUPPLY("vddio_pex_clk", NULL),
	REGULATOR_SUPPLY("avdd_hdmi", NULL),
};

static struct regulator_consumer_supply max8907c_LDO12_supply[] = {
	REGULATOR_SUPPLY("vddio_sdio", NULL),
};

static struct regulator_consumer_supply max8907c_LDO13_supply[] = {
	REGULATOR_SUPPLY("vdd_vcore_phtn", NULL),
	REGULATOR_SUPPLY("vdd_vcore_af", NULL),
};

static struct regulator_consumer_supply max8907c_LDO14_supply[] = {
	REGULATOR_SUPPLY("avdd_vdac", NULL),
};

static struct regulator_consumer_supply max8907c_LDO15_supply[] = {
	REGULATOR_SUPPLY("vdd_vcore_temp", NULL),
	REGULATOR_SUPPLY("vdd_vcore_hdcp", NULL),
};

static struct regulator_consumer_supply max8907c_LDO16_supply[] = {
	REGULATOR_SUPPLY("vdd_vbrtr", NULL),
};

static struct regulator_consumer_supply max8907c_LDO17_supply[] = {
	REGULATOR_SUPPLY("vddio_mipi", NULL),
};

static struct regulator_consumer_supply max8907c_LDO18_supply[] = {
	REGULATOR_SUPPLY("vddio_vi", NULL),
	REGULATOR_SUPPLY("vcsi", "tegra_camera"),
};

static struct regulator_consumer_supply max8907c_LDO19_supply[] = {
	REGULATOR_SUPPLY("vddio_lx", NULL),
};

static struct regulator_consumer_supply max8907c_LDO20_supply[] = {
	REGULATOR_SUPPLY("vddio_ddr_1v2", NULL),
	REGULATOR_SUPPLY("vddio_hsic", NULL),
};

#define MAX8907C_REGULATOR_DEVICE(_id, _minmv, _maxmv)			\
static struct regulator_init_data max8907c_##_id##_data = {		\
	.constraints = {						\
		.min_uV = (_minmv),					\
		.max_uV = (_maxmv),					\
		.valid_modes_mask = (REGULATOR_MODE_NORMAL |		\
				     REGULATOR_MODE_STANDBY),		\
		.valid_ops_mask = (REGULATOR_CHANGE_MODE |		\
				   REGULATOR_CHANGE_STATUS |		\
				   REGULATOR_CHANGE_VOLTAGE),		\
	},								\
	.num_consumer_supplies = ARRAY_SIZE(max8907c_##_id##_supply),	\
	.consumer_supplies = max8907c_##_id##_supply,			\
};									\
static struct platform_device max8907c_##_id##_device = {		\
	.name	= "max8907c-regulator",					\
	.id	= MAX8907C_##_id,					\
	.dev	= {							\
		.platform_data = &max8907c_##_id##_data,		\
	},								\
}

MAX8907C_REGULATOR_DEVICE(SD1, 637500, 1425000);
MAX8907C_REGULATOR_DEVICE(SD2, 637500, 1425000);
MAX8907C_REGULATOR_DEVICE(SD3, 750000, 3900000);
MAX8907C_REGULATOR_DEVICE(LDO1, 750000, 3900000);
MAX8907C_REGULATOR_DEVICE(LDO2, 650000, 2225000);
MAX8907C_REGULATOR_DEVICE(LDO3, 650000, 2225000);
MAX8907C_REGULATOR_DEVICE(LDO4, 750000, 3900000);
MAX8907C_REGULATOR_DEVICE(LDO5, 750000, 3900000);
MAX8907C_REGULATOR_DEVICE(LDO6, 750000, 3900000);
MAX8907C_REGULATOR_DEVICE(LDO7, 750000, 3900000);
MAX8907C_REGULATOR_DEVICE(LDO8, 750000, 3900000);
MAX8907C_REGULATOR_DEVICE(LDO9, 750000, 3900000);
MAX8907C_REGULATOR_DEVICE(LDO10, 750000, 3900000);
MAX8907C_REGULATOR_DEVICE(LDO11, 750000, 3900000);
MAX8907C_REGULATOR_DEVICE(LDO12, 750000, 3900000);
MAX8907C_REGULATOR_DEVICE(LDO13, 750000, 3900000);
MAX8907C_REGULATOR_DEVICE(LDO14, 750000, 3900000);
MAX8907C_REGULATOR_DEVICE(LDO15, 750000, 3900000);
MAX8907C_REGULATOR_DEVICE(LDO16, 750000, 3900000);
MAX8907C_REGULATOR_DEVICE(LDO17, 650000, 2225000);
MAX8907C_REGULATOR_DEVICE(LDO18, 650000, 2225000);
MAX8907C_REGULATOR_DEVICE(LDO19, 750000, 3900000);
MAX8907C_REGULATOR_DEVICE(LDO20, 750000, 3900000);

static struct platform_device *whistler_max8907c_power_devices[] = {
	&max8907c_SD1_device,
	&max8907c_SD2_device,
	&max8907c_SD3_device,
	&max8907c_LDO1_device,
	&max8907c_LDO2_device,
	&max8907c_LDO3_device,
	&max8907c_LDO4_device,
	&max8907c_LDO5_device,
	&max8907c_LDO6_device,
	&max8907c_LDO7_device,
	&max8907c_LDO8_device,
	&max8907c_LDO9_device,
	&max8907c_LDO10_device,
	&max8907c_LDO11_device,
	&max8907c_LDO12_device,
	&max8907c_LDO13_device,
	&max8907c_LDO14_device,
	&max8907c_LDO15_device,
	&max8907c_LDO16_device,
	&max8907c_LDO17_device,
	&max8907c_LDO18_device,
	&max8907c_LDO19_device,
	&max8907c_LDO20_device,
};

static int whistler_max8907c_setup(void)
{
	int ret;

	/*
	 * Configure PWREN, and attach CPU V1 rail to it.
	 * TODO: h/w events (power cycle, reset, battery low) auto-disables PWREN.
	 * Only soft reset (not supported) requires s/w to disable PWREN explicitly
	 */
	ret = max8907c_pwr_en_config();
	if (ret != 0)
		return ret;

	return max8907c_pwr_en_attach();
}

static struct max8907c_platform_data max8907c_pdata = {
	.num_subdevs = ARRAY_SIZE(whistler_max8907c_power_devices),
	.subdevs = whistler_max8907c_power_devices,
	.irq_base = TEGRA_NR_IRQS,
	.max8907c_setup = whistler_max8907c_setup,
	.use_power_off = true,
};

static struct i2c_board_info __initdata whistler_regulators[] = {
	{
		I2C_BOARD_INFO("max8907c", 0x3C),
		.irq = INT_EXTERNAL_PMU,
		.platform_data	= &max8907c_pdata,
	},
};

static void whistler_board_suspend(int lp_state, enum suspend_stage stg)
{
	if ((lp_state == TEGRA_SUSPEND_LP1) && (stg == TEGRA_SUSPEND_BEFORE_CPU))
		tegra_console_uart_suspend();
}

static void whistler_board_resume(int lp_state, enum resume_stage stg)
{
	if ((lp_state == TEGRA_SUSPEND_LP1) && (stg == TEGRA_RESUME_AFTER_CPU))
		tegra_console_uart_resume();
}

static struct tegra_suspend_platform_data whistler_suspend_data = {
	.cpu_timer	= 2000,
	.cpu_off_timer	= 1000,
	.suspend_mode	= TEGRA_SUSPEND_LP0,
	.core_timer	= 0x7e,
	.core_off_timer = 0xc00,
	.corereq_high	= true,
	.sysclkreq_high	= true,
	.combined_req   = true,
	.board_suspend = whistler_board_suspend,
	.board_resume = whistler_board_resume,
};

int __init whistler_regulator_init(void)
{
	void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
	void __iomem *chip_id = IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804;
	u32 pmc_ctrl;
	u32 minor;

	minor = (readl(chip_id) >> 16) & 0xf;
	/* A03 (but not A03p) chips do not support LP0 */
	if (minor == 3 && !(tegra_spare_fuse(18) || tegra_spare_fuse(19)))
		whistler_suspend_data.suspend_mode = TEGRA_SUSPEND_LP1;

	/* configure the power management controller to trigger PMU
	 * interrupts when low */
	pmc_ctrl = readl(pmc + PMC_CTRL);
	writel(pmc_ctrl | PMC_CTRL_INTR_LOW, pmc + PMC_CTRL);

	i2c_register_board_info(4, whistler_regulators, 1);

	tegra_deep_sleep = max8907c_deep_sleep;

	tegra_init_suspend(&whistler_suspend_data);

	return 0;
}