/*
* arch/arm/mach-tegra/board-vcm30_t124-power.c
*
* Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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, see .
*/
#include
#include
#include
#include
#include
#include
#include "pm.h"
#include "board.h"
#include "gpio-names.h"
#include "board-common.h"
#include "board-vcm30_t124.h"
#include "tegra_cl_dvfs.h"
#include "devices.h"
#include "tegra11_soctherm.h"
#include "tegra3_tsensor.h"
#define PMC_CTRL 0x0
#define PMC_CTRL_INTR_LOW (1 << 17)
static struct regulator_consumer_supply max77663_ldo5_supply[] = {
REGULATOR_SUPPLY("vddio_sdmmc", "sdhci-tegra.2"),
REGULATOR_SUPPLY("vddio_sd_slot", "sdhci-tegra.2"),
REGULATOR_SUPPLY("pwrdet_sdmmc3", NULL),
};
static struct max77663_regulator_fps_cfg max77663_fps_cfgs[] = {
{
.src = FPS_SRC_0,
.en_src = FPS_EN_SRC_EN0,
.time_period = FPS_TIME_PERIOD_DEF,
},
{
.src = FPS_SRC_1,
.en_src = FPS_EN_SRC_EN1,
.time_period = FPS_TIME_PERIOD_DEF,
},
{
.src = FPS_SRC_2,
.en_src = FPS_EN_SRC_EN0,
.time_period = FPS_TIME_PERIOD_DEF,
},
};
#define MAX77663_PDATA_INIT(_rid, _id, _min_uV, _max_uV, _supply_reg, \
_always_on, _boot_on, _apply_uV, \
_fps_src, _fps_pu_period, _fps_pd_period, _flags) \
static struct regulator_init_data max77663_regulator_idata_##_id = { \
.supply_regulator = _supply_reg, \
.constraints = { \
.name = max77663_rails(_id), \
.min_uV = _min_uV, \
.max_uV = _max_uV, \
.valid_modes_mask = (REGULATOR_MODE_NORMAL | \
REGULATOR_MODE_STANDBY), \
.valid_ops_mask = (REGULATOR_CHANGE_MODE | \
REGULATOR_CHANGE_STATUS | \
REGULATOR_CHANGE_VOLTAGE), \
.always_on = _always_on, \
.boot_on = _boot_on, \
.apply_uV = _apply_uV, \
}, \
.num_consumer_supplies = \
ARRAY_SIZE(max77663_##_id##_supply), \
.consumer_supplies = max77663_##_id##_supply, \
}; \
static struct max77663_regulator_platform_data \
max77663_regulator_pdata_##_id = \
{ \
.reg_init_data = &max77663_regulator_idata_##_id, \
.id = MAX77663_REGULATOR_ID_##_rid, \
.fps_src = _fps_src, \
.fps_pu_period = _fps_pu_period, \
.fps_pd_period = _fps_pd_period, \
.fps_cfgs = max77663_fps_cfgs, \
.flags = _flags, \
}
MAX77663_PDATA_INIT(LDO5, ldo5, 800000, 3950000, NULL, 0, 1, 0,
FPS_SRC_1, FPS_POWER_PERIOD_7, FPS_POWER_PERIOD_0, 0);
#define MAX77663_REG(_id, _data) (&max77663_regulator_pdata_##_data)
static struct max77663_regulator_platform_data *max77663_reg_pdata[] = {
MAX77663_REG(LDO5, ldo5),
};
static struct max77663_gpio_config max77663_gpio_cfgs[] = {
{
.gpio = MAX77663_GPIO5,
.dir = GPIO_DIR_OUT,
.dout = GPIO_DOUT_HIGH,
.out_drv = GPIO_OUT_DRV_PUSH_PULL,
.alternate = GPIO_ALT_DISABLE,
},
};
static struct max77663_platform_data max77663_pdata = {
.irq_base = MAX77663_IRQ_BASE,
.gpio_base = MAX77663_GPIO_BASE,
.num_gpio_cfgs = ARRAY_SIZE(max77663_gpio_cfgs),
.gpio_cfgs = max77663_gpio_cfgs,
.regulator_pdata = max77663_reg_pdata,
.num_regulator_pdata = ARRAY_SIZE(max77663_reg_pdata),
.rtc_i2c_addr = 0x68,
.use_power_off = false,
};
static struct i2c_board_info __initdata max77663_regulators[] = {
{
/* The I2C address was determined by OTP factory setting */
I2C_BOARD_INFO("max77663", 0x3c),
.irq = INT_EXTERNAL_PMU,
.platform_data = &max77663_pdata,
},
};
#ifdef CONFIG_ARCH_TEGRA_HAS_CL_DVFS
/* board parameters for cpu dfll */
static struct tegra_cl_dvfs_cfg_param vcm30_t124_cl_dvfs_param = {
.sample_rate = 12500,
.force_mode = TEGRA_CL_DVFS_FORCE_FIXED,
.cf = 10,
.ci = 0,
.cg = 2,
.droop_cut_value = 0xF,
.droop_restore_ramp = 0x0,
.scale_out_ramp = 0x0,
};
/* MAX15569: fixed 10mV steps from 600mV to 1400mV, with offset 0x0b */
#define PMU_CPU_VDD_MAP_SIZE ((1400000 - 600000) / 10000 + 1)
static struct voltage_reg_map pmu_cpu_vdd_map[PMU_CPU_VDD_MAP_SIZE];
static inline void fill_reg_map(void)
{
int i;
for (i = 0; i < PMU_CPU_VDD_MAP_SIZE; i++) {
pmu_cpu_vdd_map[i].reg_value = i + 0x0b;
pmu_cpu_vdd_map[i].reg_uV = 600000 + 10000 * i;
}
}
static struct tegra_cl_dvfs_platform_data vcm30_t124_cl_dvfs_data = {
.dfll_clk_name = "dfll_cpu",
.pmu_if = TEGRA_CL_DVFS_PMU_I2C,
.u.pmu_i2c = {
.fs_rate = 400000,
.slave_addr = 0x3a,
.reg = 0x07,
},
.vdd_map = pmu_cpu_vdd_map,
.vdd_map_size = PMU_CPU_VDD_MAP_SIZE,
.cfg_param = &vcm30_t124_cl_dvfs_param,
};
static int __init vcm30_t124_cl_dvfs_init(void)
{
fill_reg_map();
#if 0
if (tegra_revision < TEGRA_REVISION_A02)
vcm30_t124_cl_dvfs_data.out_quiet_then_disable = true;
#endif
tegra_cl_dvfs_device.dev.platform_data = &vcm30_t124_cl_dvfs_data;
platform_device_register(&tegra_cl_dvfs_device);
return 0;
}
#endif
static int __init vcm30_t124_max77663_regulator_init(void)
{
void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
u32 pmc_ctrl;
/* 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, max77663_regulators,
ARRAY_SIZE(max77663_regulators));
return 0;
}
int __init vcm30_t124_regulator_init(void)
{
#ifdef CONFIG_ARCH_TEGRA_HAS_CL_DVFS
vcm30_t124_cl_dvfs_init();
#endif
vcm30_t124_max77663_regulator_init();
return 0;
}
static struct tegra_suspend_platform_data vcm30_t124_suspend_data = {
.cpu_timer = 2000,
.cpu_off_timer = 2000,
.suspend_mode = TEGRA_SUSPEND_LP0,
.core_timer = 0xfefe,
.core_off_timer = 2000,
.corereq_high = true,
.sysclkreq_high = true,
.cpu_lp2_min_residency = 1000,
};
int __init vcm30_t124_suspend_init(void)
{
tegra_init_suspend(&vcm30_t124_suspend_data);
return 0;
}
/* FIXME: Should this be called? */
int __init vcm30_t124_edp_init(void)
{
unsigned int regulator_mA;
regulator_mA = get_maximum_cpu_current_supported();
if (!regulator_mA)
regulator_mA = 14000;
pr_info("%s: CPU regulator %d mA\n", __func__, regulator_mA);
tegra_init_cpu_edp_limits(regulator_mA);
regulator_mA = get_maximum_core_current_supported();
if (!regulator_mA)
regulator_mA = 14000;
pr_info("%s: core regulator %d mA\n", __func__, regulator_mA);
tegra_init_core_edp_limits(regulator_mA);
return 0;
}
static struct thermal_zone_params soctherm_tzp = {
.governor_name = "pid_thermal_gov",
};
static struct tegra_tsensor_pmu_data tpdata_palmas = {
.reset_tegra = 1,
.pmu_16bit_ops = 0,
.controller_type = 0,
.pmu_i2c_addr = 0x58,
.i2c_controller_id = 4,
.poweroff_reg_addr = 0xa0,
.poweroff_reg_data = 0x0,
};
static struct tegra_tsensor_pmu_data tpdata_max77663 = {
.reset_tegra = 1,
.pmu_16bit_ops = 0,
.controller_type = 0,
.pmu_i2c_addr = 0x3c,
.i2c_controller_id = 4,
.poweroff_reg_addr = 0x41,
.poweroff_reg_data = 0x80,
};
static struct soctherm_platform_data vcm30_t124_soctherm_data = {
.therm = {
[THERM_CPU] = {
.zone_enable = true,
.passive_delay = 1000,
.hotspot_offset = 6000,
.num_trips = 3,
.trips = {
{
.cdev_type = "tegra-balanced",
.trip_temp = 90000,
.trip_type = THERMAL_TRIP_PASSIVE,
.upper = THERMAL_NO_LIMIT,
.lower = THERMAL_NO_LIMIT,
},
{
.cdev_type = "tegra-heavy",
.trip_temp = 100000,
.trip_type = THERMAL_TRIP_HOT,
.upper = THERMAL_NO_LIMIT,
.lower = THERMAL_NO_LIMIT,
},
{
.cdev_type = "tegra-shutdown",
.trip_temp = 102000,
.trip_type = THERMAL_TRIP_CRITICAL,
.upper = THERMAL_NO_LIMIT,
.lower = THERMAL_NO_LIMIT,
},
},
.tzp = &soctherm_tzp,
},
[THERM_GPU] = {
.zone_enable = true,
.passive_delay = 1000,
.hotspot_offset = 6000,
.num_trips = 3,
.trips = {
{
.cdev_type = "tegra-balanced",
.trip_temp = 90000,
.trip_type = THERMAL_TRIP_PASSIVE,
.upper = THERMAL_NO_LIMIT,
.lower = THERMAL_NO_LIMIT,
},
{
.cdev_type = "tegra-heavy",
.trip_temp = 100000,
.trip_type = THERMAL_TRIP_HOT,
.upper = THERMAL_NO_LIMIT,
.lower = THERMAL_NO_LIMIT,
},
{
.cdev_type = "tegra-shutdown",
.trip_temp = 102000,
.trip_type = THERMAL_TRIP_CRITICAL,
.upper = THERMAL_NO_LIMIT,
.lower = THERMAL_NO_LIMIT,
},
},
.tzp = &soctherm_tzp,
},
[THERM_PLL] = {
.zone_enable = true,
},
},
.throttle = {
[THROTTLE_HEAVY] = {
.priority = 100,
.devs = {
[THROTTLE_DEV_CPU] = {
.enable = true,
.depth = 80,
},
},
},
},
.tshut_pmu_trip_data = &tpdata_palmas,
};
/* FIXME: Needed? */
int __init vcm30_t124_soctherm_init(void)
{
vcm30_t124_soctherm_data.tshut_pmu_trip_data = &tpdata_max77663;
tegra_platform_edp_init(vcm30_t124_soctherm_data.therm[THERM_CPU].trips,
&vcm30_t124_soctherm_data.therm[THERM_CPU].num_trips,
8000); /* edp temperature margin */
tegra_add_tj_trips(vcm30_t124_soctherm_data.therm[THERM_CPU].trips,
&vcm30_t124_soctherm_data.therm[THERM_CPU].num_trips);
/*tegra_add_vc_trips(vcm30_t124_soctherm_data.therm[THERM_CPU].trips,
&vcm30_t124_soctherm_data.therm[THERM_CPU].num_trips);
*/
return tegra11_soctherm_init(&vcm30_t124_soctherm_data);
}