u-boot/drivers/power/twl4030.c
Adam Ford 4c2fb5fcc8 power: twl4030: Add CONFIG_CMD_POWEROFF support
With the addition of twl4030_power_off(), let's allow the 'poweroff' command
to run this function when CONFIG_CMD_POWEROFF is enabled.

Tested on a DM3730 with twl4030 PMIC.

Signed-off-by: Adam Ford <aford173@gmail.com>
Reviewed-by: Tom Rini <trini@konsulko.com>
Reviewed-by: Jaehoon Chung <jh80.chung@samsung.com>
2017-05-09 20:35:38 -04:00

183 lines
5.0 KiB
C

/*
* Copyright (c) 2009 Wind River Systems, Inc.
* Tom Rix <Tom.Rix at windriver.com>
*
* SPDX-License-Identifier: GPL-2.0+
*
* twl4030_power_reset_init is derived from code on omapzoom,
* git://git.omapzoom.com/repo/u-boot.git
*
* Copyright (C) 2007-2009 Texas Instruments, Inc.
*
* twl4030_power_init is from cpu/omap3/common.c, power_init_r
*
* (C) Copyright 2004-2008
* Texas Instruments, <www.ti.com>
*
* Author :
* Sunil Kumar <sunilsaini05 at gmail.com>
* Shashi Ranjan <shashiranjanmca05 at gmail.com>
*
* Derived from Beagle Board and 3430 SDP code by
* Richard Woodruff <r-woodruff2 at ti.com>
* Syed Mohammed Khasim <khasim at ti.com>
*/
#include <twl4030.h>
/*
* Power Reset
*/
void twl4030_power_reset_init(void)
{
u8 val = 0;
if (twl4030_i2c_read_u8(TWL4030_CHIP_PM_MASTER,
TWL4030_PM_MASTER_P1_SW_EVENTS, &val)) {
printf("Error:TWL4030: failed to read the power register\n");
printf("Could not initialize hardware reset\n");
} else {
val |= TWL4030_PM_MASTER_SW_EVENTS_STOPON_PWRON;
if (twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER,
TWL4030_PM_MASTER_P1_SW_EVENTS, val)) {
printf("Error:TWL4030: failed to write the power register\n");
printf("Could not initialize hardware reset\n");
}
}
}
/*
* Power off
*/
void twl4030_power_off(void)
{
u8 data;
/* PM master unlock (CFG and TST keys) */
data = 0xCE;
twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER,
TWL4030_PM_MASTER_PROTECT_KEY, data);
data = 0xEC;
twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER,
TWL4030_PM_MASTER_PROTECT_KEY, data);
/* VBAT start disable */
twl4030_i2c_read_u8(TWL4030_CHIP_PM_MASTER,
TWL4030_PM_MASTER_CFG_P1_TRANSITION, &data);
data &= ~TWL4030_PM_MASTER_CFG_TRANSITION_STARTON_VBAT;
twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER,
TWL4030_PM_MASTER_CFG_P1_TRANSITION, data);
twl4030_i2c_read_u8(TWL4030_CHIP_PM_MASTER,
TWL4030_PM_MASTER_CFG_P2_TRANSITION, &data);
data &= ~TWL4030_PM_MASTER_CFG_TRANSITION_STARTON_VBAT;
twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER,
TWL4030_PM_MASTER_CFG_P2_TRANSITION, data);
twl4030_i2c_read_u8(TWL4030_CHIP_PM_MASTER,
TWL4030_PM_MASTER_CFG_P3_TRANSITION, &data);
data &= ~TWL4030_PM_MASTER_CFG_TRANSITION_STARTON_VBAT;
twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER,
TWL4030_PM_MASTER_CFG_P3_TRANSITION, data);
/* High jitter for PWRANA2 */
twl4030_i2c_read_u8(TWL4030_CHIP_PM_MASTER,
TWL4030_PM_MASTER_CFG_PWRANA2, &data);
data &= ~(TWL4030_PM_MASTER_CFG_PWRANA2_LOJIT0_LOWV |
TWL4030_PM_MASTER_CFG_PWRANA2_LOJIT1_LOWV);
twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER,
TWL4030_PM_MASTER_CFG_PWRANA2, data);
/* PM master lock */
data = 0xFF;
twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER,
TWL4030_PM_MASTER_PROTECT_KEY, data);
/* Power off */
twl4030_i2c_read_u8(TWL4030_CHIP_PM_MASTER,
TWL4030_PM_MASTER_P1_SW_EVENTS, &data);
data |= TWL4030_PM_MASTER_SW_EVENTS_DEVOFF;
twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER,
TWL4030_PM_MASTER_P1_SW_EVENTS, data);
}
/*
* Set Device Group and Voltage
*/
void twl4030_pmrecv_vsel_cfg(u8 vsel_reg, u8 vsel_val,
u8 dev_grp, u8 dev_grp_sel)
{
int ret;
/* Select the Voltage */
ret = twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, vsel_reg,
vsel_val);
if (ret != 0) {
printf("Could not write vsel to reg %02x (%d)\n",
vsel_reg, ret);
return;
}
/* Select the Device Group (enable the supply if dev_grp_sel != 0) */
ret = twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, dev_grp,
dev_grp_sel);
if (ret != 0)
printf("Could not write grp_sel to reg %02x (%d)\n",
dev_grp, ret);
}
void twl4030_power_init(void)
{
/* set VAUX3 to 2.8V */
twl4030_pmrecv_vsel_cfg(TWL4030_PM_RECEIVER_VAUX3_DEDICATED,
TWL4030_PM_RECEIVER_VAUX3_VSEL_28,
TWL4030_PM_RECEIVER_VAUX3_DEV_GRP,
TWL4030_PM_RECEIVER_DEV_GRP_P1);
/* set VPLL2 to 1.8V */
twl4030_pmrecv_vsel_cfg(TWL4030_PM_RECEIVER_VPLL2_DEDICATED,
TWL4030_PM_RECEIVER_VPLL2_VSEL_18,
TWL4030_PM_RECEIVER_VPLL2_DEV_GRP,
TWL4030_PM_RECEIVER_DEV_GRP_ALL);
/* set VDAC to 1.8V */
twl4030_pmrecv_vsel_cfg(TWL4030_PM_RECEIVER_VDAC_DEDICATED,
TWL4030_PM_RECEIVER_VDAC_VSEL_18,
TWL4030_PM_RECEIVER_VDAC_DEV_GRP,
TWL4030_PM_RECEIVER_DEV_GRP_P1);
}
void twl4030_power_mmc_init(int dev_index)
{
if (dev_index == 0) {
/* Set VMMC1 to 3.15 Volts */
twl4030_pmrecv_vsel_cfg(TWL4030_PM_RECEIVER_VMMC1_DEDICATED,
TWL4030_PM_RECEIVER_VMMC1_VSEL_32,
TWL4030_PM_RECEIVER_VMMC1_DEV_GRP,
TWL4030_PM_RECEIVER_DEV_GRP_P1);
mdelay(100); /* ramp-up delay from Linux code */
} else if (dev_index == 1) {
/* Set VMMC2 to 3.15 Volts */
twl4030_pmrecv_vsel_cfg(TWL4030_PM_RECEIVER_VMMC2_DEDICATED,
TWL4030_PM_RECEIVER_VMMC2_VSEL_32,
TWL4030_PM_RECEIVER_VMMC2_DEV_GRP,
TWL4030_PM_RECEIVER_DEV_GRP_P1);
mdelay(100); /* ramp-up delay from Linux code */
}
}
#ifdef CONFIG_CMD_POWEROFF
int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
twl4030_power_off();
return 0;
}
#endif