Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

1018 lines (876 sloc) 30.405 kb
/*
*
* @Component OMAPCONF
* @Filename twl603x.c
* @Description OMAP4 TWL603x Power Companion Chip Library
* @Author Patrick Titiano (p-titiano@ti.com)
* @Date 2010
* @Copyright Texas Instruments Incorporated
*
*
* Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <string.h>
#include <twl603x.h>
#include <i2c-tools.h>
#include <stdio.h>
#include <lib.h>
#include <cpuinfo.h>
#include <twl603x_lib.h>
#include <help.h>
#include <lib_android.h>
/* #define TWL603X_DEBUG */
#ifdef TWL603X_DEBUG
#define dprintf(format, ...) printf(format, ## __VA_ARGS__)
#else
#define dprintf(format, ...)
#endif
#define TWL6030_VSEL_LEN 6
#define TWL6030_VSTEP_UV 12660
#define TWL6030_VOFFSET_0_UV 608000
#define TWL6030_VOFFSET_1_UV 709000
#define TWL6030_SMPS_VOLTAGE0_UV 1367400
#define TWL6030_SMPS_VOLTAGE1_UV 1519300
#define TWL6030_SMPS_VOLTAGE2_UV 1823100
#define TWL6030_SMPS_VOLTAGE3_UV 1924400
#define TWL6030_SMPS_VOLTAGE4_UV 2127000
#define TWL6035_I2C_BUS 1
#define TWL6035_ID0_ADDR 0x12
#define TWL6035_ID1_ADDR 0x48
#define TWL6035_ID2_ADDR 0x49
#define TWL6035_VOFFSET_UV 500000
#define TWL6035_VSTEP_UV 10000
#define TWL6035_VSEL_LEN 8
#define TWL6035_SMPS_LOW_RANGE_UVMIN TWL6035_VOFFSET_UV
#define TWL6035_SMPS_LOW_RANGE_UVMAX 1650000
#define TWL6035_SMPS_HIGH_RANGE_UVMIN 1650000
#define TWL6035_SMPS_HIGH_RANGE_UVMAX 3300000
static const char
twl_603x_chip_name[TWL603X_TYPE_MAX + 1][TWL603x_NAME_MAX_LEN] = {
"TWL6030",
"TWL6032",
"TWL6035",
"FIXME"};
typedef struct {
twl603x_type chip_type;
float chip_revision;
float eprom_revision;
int vsel_len; /* width of vsel command (in bits) */
long int vstep; /* voltage step, in microvolts */
long int voffset[3]; /* voltage offset (per rail), in microvolts */
unsigned long smps_voltage_uv[5];
} t_twl603x_data;
static t_twl603x_data twl603x_data = {
.chip_type = TWL603X_TYPE_MAX,
.chip_revision = -1.0,
.eprom_revision = -1.0,
.vsel_len = TWL6030_VSEL_LEN,
.vstep = TWL6030_VSTEP_UV,
.voffset = {-1.0, -1.0, -1.0},
.smps_voltage_uv = {
TWL6030_SMPS_VOLTAGE0_UV,
TWL6030_SMPS_VOLTAGE1_UV,
TWL6030_SMPS_VOLTAGE2_UV,
TWL6030_SMPS_VOLTAGE3_UV,
TWL6030_SMPS_VOLTAGE4_UV} };
typedef struct {
int ctrl;
int tstep;
int force;
int voltage;
} twl6035_smps_registers;
static const twl6035_smps_registers twl035_smps12 = {
.ctrl = 0x20,
.tstep = 0x21,
.force = 0x22,
.voltage = 0x23};
static const twl6035_smps_registers twl035_smps3 = {
.ctrl = 0x24,
.tstep = -1,
.force = -1,
.voltage = 0x27};
static const twl6035_smps_registers twl035_smps45 = {
.ctrl = 0x28,
.tstep = 0x29,
.force = 0x2A,
.voltage = 0x2B};
static const twl6035_smps_registers twl035_smps6 = {
.ctrl = 0x2C,
.tstep = 0x2D,
.force = 0x2E,
.voltage = 0x2F};
static const twl6035_smps_registers twl035_smps7 = {
.ctrl = 0x30,
.tstep = -1,
.force = -1,
.voltage = 0x33};
static const twl6035_smps_registers twl035_smps8 = {
.ctrl = 0x34,
.tstep = 0x35,
.force = 0x36,
.voltage = 0x37};
static const twl6035_smps_registers twl035_smps9 = {
.ctrl = 0x38,
.tstep = -1,
.force = -1,
.voltage = 0x3B};
static const twl6035_smps_registers twl035_smps10 = {
.ctrl = 0x3C,
.tstep = -1,
.force = -1,
.voltage = -1};
static const twl6035_smps_registers *twl6035_smps_vdd54xx_mpu = &twl035_smps12;
static const twl6035_smps_registers *twl6035_smps_vdd54xx_mm = &twl035_smps45;
static const twl6035_smps_registers *twl6035_smps_vdd54xx_core = &twl035_smps8;
static const twl6035_smps_registers **twl6035_smps_vdd54xx[3] = {
(const twl6035_smps_registers **) &twl6035_smps_vdd54xx_mpu,
(const twl6035_smps_registers **) &twl6035_smps_vdd54xx_mm,
(const twl6035_smps_registers **) &twl6035_smps_vdd54xx_core};
/* ------------------------------------------------------------------------*//**
* @FUNCTION twl603x_is_twl6030
* @BRIEF return 1 if PMIC chip is TWL6030, 0 otherwise.
* @RETURNS 1 PMIC chip is TWL6030
* 0 otherwise
* @DESCRIPTION return 1 if PMIC chip is TWL6030, 0 otherwise.
*//*------------------------------------------------------------------------ */
unsigned short twl603x_is_twl6030(void)
{
int ret;
unsigned int val1, val2;
if (cpu_get() == DRA_75X)
return 0;
if (twl603x_data.chip_type != TWL603X_TYPE_MAX) {
dprintf("%s(): flag=%d\n", __func__,
(twl603x_data.chip_type == TWL6030));
return twl603x_data.chip_type == TWL6030;
}
ret = i2cget(TWL6030_I2C_BUS, 0x49, 0x02, &val2);
if (ret != 0)
goto twl603x_is_twl6030_end;
ret = i2cget(TWL6030_I2C_BUS, 0x49, 0x03, &val1);
if (ret != 0)
goto twl603x_is_twl6030_end;
if ((val1 == 0xC0) && (val2 == 0x30))
twl603x_data.chip_type = TWL6030;
twl603x_is_twl6030_end:
dprintf("%s(): val1=0x%02X val2=0x%02X flag=%d\n",
__func__, val1, val2, (twl603x_data.chip_type == TWL6030));
return twl603x_data.chip_type == TWL6030;
}
/* ------------------------------------------------------------------------*//**
* @FUNCTION twl603x_is_twl6032
* @BRIEF return 1 if PMIC chip is TWL6032, 0 otherwise.
* @RETURNS 1 PMIC chip is TWL6032
* 0 otherwise
* @DESCRIPTION return 1 if PMIC chip is TWL6032, 0 otherwise.
*//*------------------------------------------------------------------------ */
unsigned short twl603x_is_twl6032(void)
{
int ret;
unsigned int val1, val2;
if (cpu_get() == DRA_75X)
return 0;
if (twl603x_data.chip_type != TWL603X_TYPE_MAX) {
dprintf("%s(): flag=%d\n", __func__,
(twl603x_data.chip_type == TWL6032));
return twl603x_data.chip_type == TWL6032;
}
ret = i2cget(TWL6030_I2C_BUS, 0x49, 0x02, &val2);
if (ret != 0)
goto twl603x_is_twl6032_end;
ret = i2cget(TWL6030_I2C_BUS, 0x49, 0x03, &val1);
if (ret != 0)
goto twl603x_is_twl6032_end;
if ((val1 == 0xC0) && (val2 == 0x32))
twl603x_data.chip_type = TWL6032;
twl603x_is_twl6032_end:
dprintf("%s(): val1=0x%02X val2=0x%02X flag=%d\n",
__func__, val1, val2, (twl603x_data.chip_type == TWL6032));
return twl603x_data.chip_type == TWL6032;
}
/* ------------------------------------------------------------------------*//**
* @FUNCTION twl603x_is_twl6034
* @BRIEF return 1 if PMIC chip is TWL6034, 0 otherwise.
* @RETURNS 1 PMIC chip is TWL6034
* 0 otherwise
* @DESCRIPTION return 1 if PMIC chip is TWL6034, 0 otherwise.
*//*------------------------------------------------------------------------ */
unsigned short twl603x_is_twl6034(void)
{
int ret;
unsigned int val1, val2;
if (cpu_get() == DRA_75X)
return 0;
if (twl603x_data.chip_type != TWL603X_TYPE_MAX) {
dprintf("%s(): flag=%d\n", __func__,
(twl603x_data.chip_type == TWL6034));
return twl603x_data.chip_type == TWL6034;
}
ret = i2cget(TWL6030_I2C_BUS, 0x49, 0x02, &val2);
if (ret != 0)
goto twl603x_is_twl6034_end;
ret = i2cget(TWL6030_I2C_BUS, 0x49, 0x03, &val1);
if (ret != 0)
goto twl603x_is_twl6034_end;
if ((val1 == 0x00) && (val2 == 0x00))
twl603x_data.chip_type = TWL6034;
twl603x_is_twl6034_end:
dprintf("%s(): val1=0x%02X val2=0x%02X flag=%d\n",
__func__, val1, val2, (twl603x_data.chip_type == TWL6034));
return twl603x_data.chip_type == TWL6034;
}
/* ------------------------------------------------------------------------*//**
* @FUNCTION twl603x_is_twl6035
* @BRIEF return 1 if PMIC chip is TWL6035, 0 otherwise.
* @RETURNS 1 PMIC chip is TWL6035
* 0 otherwise
* @DESCRIPTION return 1 if PMIC chip is TWL6035, 0 otherwise.
*//*------------------------------------------------------------------------ */
unsigned short twl603x_is_twl6035(void)
{
#if 0 /* FIXME: implement true detection when ID data available */
int ret;
unsigned int val1, val2;
if (twl603x_data.chip_type != TWL603X_TYPE_MAX) {
dprintf("%s(): flag=%d\n", __func__,
(twl603x_data.chip_type == TWL6035));
return twl603x_data.chip_type == TWL6035;
}
ret = i2cget(TWL6030_I2C_BUS, 0x49, 0x02, &val2);
if (ret != 0)
goto twl603x_is_twl6035_end;
ret = i2cget(TWL6030_I2C_BUS, 0x49, 0x03, &val1);
if (ret != 0)
goto twl603x_is_twl6035_end;
if ((val1 == 0xC0) && (val2 == 0x35))
twl603x_data.chip_type = TWL6035;
twl603x_is_twl6035_end:
dprintf("%s(): val1=0x%02X val2=0x%02X flag=%d\n",
__func__, val1, val2, (twl603x_data.chip_type == TWL6035));
return twl603x_data.chip_type == TWL6035;
#else
/* FIXME: implement true detection when ID data available */
if (cpu_is_omap54xx())
return 1;
else
return 0;
#endif
}
/* ------------------------------------------------------------------------*//**
* @FUNCTION twl603x_chip_revision_get
* @BRIEF return TWL6030 chip revision
* @RETURNS > 0.0 valid TWL6030 chip revision
* OMAPCONF_ERR_NOT_AVAILABLE
* OMAPCONF_ERR_UNEXPECTED
* @DESCRIPTION return TWL6030 chip revision
*//*------------------------------------------------------------------------ */
float twl603x_chip_revision_get(void)
{
int ret;
unsigned int rev;
if (twl603x_data.chip_revision > 0)
goto twl603x_chip_revision_get_end;
ret = i2cget(TWL6030_I2C_BUS, 0x4A, 0x87, &rev);
if (ret != 0) {
fprintf(stderr, "%s(): could not read register! (%d)\n",
__func__, ret);
twl603x_data.chip_revision = (float) OMAPCONF_ERR_NOT_AVAILABLE;
goto twl603x_chip_revision_get_end;
}
dprintf("%s(): rev=%u\n", __func__, rev);
switch (rev) {
case 0x0:
twl603x_data.chip_revision = 1.0;
break;
case 0x01:
if (twl603x_data.chip_type == TWL6032)
twl603x_data.chip_revision = 1.1;
else
twl603x_data.chip_revision = 2.0;
break;
case 0x02:
twl603x_data.chip_revision = 2.1;
break;
default:
twl603x_data.chip_revision = (float) OMAPCONF_ERR_UNEXPECTED;
}
twl603x_chip_revision_get_end:
dprintf("%s(): chip_revision = %f\n", __func__,
twl603x_data.chip_revision);
return twl603x_data.chip_revision;
}
/* ------------------------------------------------------------------------*//**
* @FUNCTION twl603x_eprom_revision_get
* @BRIEF return TWL603x EPROM revision
* @RETURNS >0 .0 valid TWL6030 EPROM revision
* OMAPCONF_ERR_NOT_AVAILABLE
* @DESCRIPTION return TWL603x EPROM revision
*//*------------------------------------------------------------------------ */
float twl603x_eprom_revision_get(void)
{
int ret;
unsigned int rev;
if (twl603x_data.eprom_revision > 0)
goto twl603x_eprom_revision_get_end;
ret = i2cget(TWL6030_I2C_BUS, 0x4A, 0xDF, &rev);
if (ret != 0) {
fprintf(stderr, "%s(): could not read register! (%d)\n",
__func__, ret);
twl603x_data.eprom_revision =
(float) OMAPCONF_ERR_NOT_AVAILABLE;
goto twl603x_eprom_revision_get_end;
}
dprintf("%s(): rev=%u\n", __func__, rev);
twl603x_data.eprom_revision = (float) (rev);
twl603x_eprom_revision_get_end:
dprintf("%s(): eprom_revision = %f\n", __func__,
twl603x_data.eprom_revision);
return twl603x_data.eprom_revision;
}
/* ------------------------------------------------------------------------*//**
* @FUNCTION twl603x_smps_offset_get
* @BRIEF return SMPS regulator offset for a given rail
* @RETURNS >0 voltage offset in microvolts
* OMAPCONF_ERR_NOT_AVAILABLE
* @param[in] vdd_id: voltage rail
* @DESCRIPTION return SMPS regulator offset for a given rail
*//*------------------------------------------------------------------------ */
unsigned long twl603x_smps_offset_get(voltdm44xx_id vdd_id)
{
int ret;
unsigned int val;
char product_name[256];
if (twl603x_is_twl6035())
return TWL6035_VOFFSET_UV;
if (twl603x_data.voffset[vdd_id - 1] >= 0)
goto twl603x_smps_offset_get_end;
/*
* TWL6030:
* Starting ES2.x, Phoenix PMIC may use 709mV offset instead of 608mV
* depending on setting: OFFSET=1: 709mV, OFFSET=0: 608mV.
*/
if (twl603x_is_twl6030() && twl603x_chip_revision_get() == 1.0) {
dprintf("%s(%u): TWL60ES1 => TWL6030_VOFFSET_0_UV\n",
__func__, vdd_id);
twl603x_data.voffset[vdd_id - 1] = TWL6030_VOFFSET_0_UV;
goto twl603x_smps_offset_get_end;
}
ret = i2cget(TWL6030_I2C_BUS, 0x48, 0xE0, &val);
if (ret != 0) {
fprintf(stderr, "%s(%u): could not read register! (%d)\n",
__func__, vdd_id, ret);
twl603x_data.voffset[vdd_id - 1] = TWL6030_VOFFSET_1_UV;
goto twl603x_smps_offset_get_end;
}
dprintf("%s(%u): val=0x%02X\n", __func__, vdd_id, val);
switch (vdd_id) {
case OMAP4_VDD_MPU:
if (cpu_is_omap4460()) {
android_product_name_get(product_name);
if (strstr(product_name, "Kindle") == NULL)
fprintf(stderr,
"%s(%u): invalid vdd_id! omap4460 uses TPS62361 for VDD_MPU\n",
__func__, vdd_id);
}
val &= 0x08;
break;
case OMAP4_VDD_IVA:
if (cpu_is_omap4470())
val &= 0x02;
else
val &= 0x10;
break;
case OMAP4_VDD_CORE:
if (cpu_is_omap4460())
val &= 0x08;
else if (cpu_is_omap4470())
val &= 0x10;
else
val &= 0x20;
break;
default:
fprintf(stderr, "%s(%u): invalid vdd_id!\n", __func__, vdd_id);
return TWL6030_VOFFSET_1_UV;
}
if (val != 0)
twl603x_data.voffset[vdd_id - 1] = TWL6030_VOFFSET_1_UV;
else
twl603x_data.voffset[vdd_id - 1] = TWL6030_VOFFSET_0_UV;
twl603x_smps_offset_get_end:
dprintf("%s(%u): voffset=%lduV\n", __func__,
vdd_id, twl603x_data.voffset[vdd_id - 1]);
return twl603x_data.voffset[vdd_id - 1];
}
/* ------------------------------------------------------------------------*//**
* @FUNCTION twl603x_smps_step_get
* @BRIEF return SMPS regulator voltage step for a given rail
* (in microvolts)
* @RETURNS voltage step in microvolts
* @DESCRIPTION return SMPS regulator voltage step for a given rail
* (in microvolts)
*//*------------------------------------------------------------------------ */
long twl603x_smps_step_get(void)
{
if (twl603x_is_twl6035())
return TWL6035_VSTEP_UV;
return twl603x_data.vstep;
}
/* ------------------------------------------------------------------------*//**
* @FUNCTION twl603x_vsel_len_get
* @BRIEF return the size of the vsel command
* @RETURNS SMPS regulator size of the vsel command
* @DESCRIPTION return the size of the vsel command
*//*------------------------------------------------------------------------ */
int twl603x_vsel_len_get(void)
{
if (twl603x_is_twl6035())
return TWL6035_VSEL_LEN;
return twl603x_data.vsel_len;
}
/* ------------------------------------------------------------------------*//**
* @FUNCTION twl603x_uv_to_vsel
* @BRIEF for a given rail, convert voltage in microvolts into
* vsel command. Take into account voltage offset.
* @RETURNS SMPS vsel command corresponding to uv
* @param[in] vdd_id: voltage rail
* @param[in] uv: voltage to be converted (in microvolts)
* @DESCRIPTION for a given rail, convert voltage in microvolts into
* vsel command. Take into account voltage offset.
*//*------------------------------------------------------------------------ */
unsigned char twl603x_uv_to_vsel(unsigned int vdd_id, unsigned long uv)
{
unsigned long smps_offset;
unsigned char vsel, range;
if (!twl603x_is_twl6035()) {
smps_offset = twl603x_smps_offset_get(vdd_id);
if (uv < smps_offset)
vsel = 0;
else if (uv == smps_offset)
vsel = 0x01;
else if (uv >= twl603x_data.smps_voltage_uv[4])
vsel = 0x3E;
else if (uv == twl603x_data.smps_voltage_uv[3])
vsel = 0x3D;
else if (uv == twl603x_data.smps_voltage_uv[2])
vsel = 0x3C;
else if (uv == twl603x_data.smps_voltage_uv[1])
vsel = 0x3B;
else if (uv == twl603x_data.smps_voltage_uv[0])
vsel = 0x3A;
else
vsel = DIV_ROUND_UP(uv - smps_offset,
twl603x_data.vstep) + 1;
} else {
if (uv == 0) {
range = 0;
vsel = 0;
} else if (uv <= TWL6035_SMPS_LOW_RANGE_UVMIN) {
range = 0;
vsel = 0x01;
} else if (uv <= TWL6035_SMPS_LOW_RANGE_UVMAX) {
range = 0;
vsel = 6 + DIV_ROUND_UP(uv - TWL6035_VOFFSET_UV,
TWL6035_VSTEP_UV);
} else if (uv <= 3300000) {
range = 1;
vsel = 6 + DIV_ROUND_UP(uv - (TWL6035_VOFFSET_UV * 2),
2 * TWL6035_VSTEP_UV);
} else { /* > 3.3V */
range = 1;
vsel = 0x79;
}
vsel = vsel | (range << 7);
}
dprintf("%s(%d, %lduV)=0x%02X\n", __func__, vdd_id, uv, vsel);
return vsel;
}
/* ------------------------------------------------------------------------*//**
* @FUNCTION twl603x_vsel_to_uv
* @BRIEF for a given rail, convert SMPS vsel command into voltage
* in microvolts. Take into account SMPS voltage offset.
* @RETURNS voltage in microvolts corresponding to SMPS vsel command
* @param[in] vdd_id: voltage rail
* @param[in] vsel: SMPS vsel command (in microvolts)
* @DESCRIPTION for a given rail, convert SMPS vsel command into voltage
* in microvolts. Take into account SMPS voltage offset.
*//*------------------------------------------------------------------------ */
unsigned long twl603x_vsel_to_uv(unsigned int vdd_id, unsigned char vsel)
{
unsigned long smps_offset, uv;
unsigned int range;
if (!twl603x_is_twl6035()) {
if (vsel == 0) {
uv = 0;
} else if (vsel > 0x3E) {
fprintf(stderr, "%s(): warning vsel (0x%02X) "
"is reserved value, use max (0x3E) instead!\n",
__func__, vsel);
vsel = 0x3E;
}
smps_offset = twl603x_smps_offset_get(vdd_id);
if (vsel >= 0x3A)
uv = twl603x_data.smps_voltage_uv[vsel - 0x3A];
else
uv = smps_offset + ((vsel - 1) * twl603x_data.vstep);
} else {
/* VSEL = 7-bit + range (MSB) */
range = extract_bit(vsel, 7);
vsel = extract_bitfield(vsel, 0, 7);
if (vsel == 0) {
uv = 0;
} else if (vsel <= 0x06) {
uv = TWL6035_VOFFSET_UV;
} else if (vsel >= 0x79) {
uv = 1650000;
} else {
uv = TWL6035_VOFFSET_UV +
(TWL6035_VSTEP_UV * (vsel - 6));
}
/* Apply range multiplier */
uv = uv << range;
}
dprintf("%s(%d, %d (0x%02X))=%lduV\n", __func__,
vdd_id, vsel, vsel, uv);
return uv;
}
/* ------------------------------------------------------------------------*//**
* @FUNCTION twl603x_vsel_to_volt
* @BRIEF for a given rail, convert SMPS vsel command into voltage
* (in VOLTS). Take into account SMPS voltage offset.
* @RETURNS voltage in VOLTS corresponding to SMPS vsel command
* @param[in] vdd_id: voltage rail
* @param[in] vsel: SMPS vsel command (in microvolts)
* @DESCRIPTION for a given rail, convert SMPS vsel command into voltage
* (in VOLTS). Take into account SMPS voltage offset.
*//*------------------------------------------------------------------------ */
double twl603x_vsel_to_volt(unsigned int vdd_id, unsigned char vsel)
{
double volt;
volt = (double) twl603x_vsel_to_uv(vdd_id, vsel);
volt /= (double) 1000000.0;
dprintf("%s(%u, 0x%X) = %lfV\n", __func__, vdd_id, vsel, volt);
return volt;
}
/* ------------------------------------------------------------------------*//**
* @FUNCTION twl603x_vsel_get
* @BRIEF return vsel-encoded voltage of a given SMPS voltage rail
* @RETURNS VSEL-encoded voltage (8-bit, >= 0) in case of success
* OMAPCONF_ERR_CPU
* OMAPCONF_ERR_ARG
* OMAPCONF_ERR_NOT_AVAILABLE
* OMAPCONF_ERR_REG_ACCESS
* OMAPCONF_ERR_INTERNAL
* @param[in] vdd_id: voltage domain ID
* @DESCRIPTION return vsel-encoded voltage of a given SMPS voltage rail
* NB: not supported by TWL6030/TWL6032.
*//*------------------------------------------------------------------------ */
int twl603x_vsel_get(unsigned int vdd_id)
{
int ret;
unsigned int val, vsel_addr, vsel, range;
const twl6035_smps_registers **vdd_smps_regs;
const twl6035_smps_registers *smps_regs;
if (!twl603x_is_twl6035())
return OMAPCONF_ERR_CPU;
CHECK_ARG_LESS_THAN(vdd_id, 3, OMAPCONF_ERR_ARG);
/* Retrive SMPS registers addresses */
vdd_smps_regs = twl6035_smps_vdd54xx[vdd_id];
if (vdd_smps_regs == NULL)
return OMAPCONF_ERR_INTERNAL;
smps_regs = *vdd_smps_regs;
if (smps_regs == NULL)
return OMAPCONF_ERR_INTERNAL;
dprintf("%s(): vdd_id=%u ADDR: ctrl=0x%02X tstep=0x%02X force=0x%02X "
"voltage=0x%02X\n", __func__, vdd_id, smps_regs->ctrl,
smps_regs->tstep, smps_regs->force, smps_regs->voltage);
/* Check SMPS Status */
/* FIXME: create dedicated API */
if (smps_regs->ctrl == -1) {
dprintf("%s(): SMPSxx_CTRL addr=-1!!!\n", __func__);
return OMAPCONF_ERR_INTERNAL;
}
ret = i2cget(TWL6035_I2C_BUS, TWL6035_ID1_ADDR,
smps_regs->ctrl, &val);
if (ret != 0)
return OMAPCONF_ERR_REG_ACCESS;
dprintf("%s(): SMPSxx_CTRL=0x%02X\n", __func__, val);
if (extract_bitfield(val, 4, 2) == 0) {
dprintf("(%s(): warning SMPS is OFF\n", __func__);
return 0;
}
/* Check SMPS voltage controlled by registers, not resource pins */
/* FIXME: create dedicated API */
if (extract_bit(val, 6) == 1) {
dprintf("%s(): SMPS voltage controlled by resource pins\n",
__func__);
return OMAPCONF_ERR_NOT_AVAILABLE;
}
/*
* Retrieve if voltage is controlled via
* SMPSxx_FORCE.VSEL or SMPSxx_VOLTAGE.VSEL
*/
if (smps_regs->force == -1) {
dprintf("%s(): SMPSxx_FORCE register does not exist, "
"use SMPSxx_VOLTAGE register.\n", __func__);
vsel_addr = smps_regs->voltage;
} else {
ret = i2cget(TWL6035_I2C_BUS, TWL6035_ID1_ADDR,
smps_regs->force, &val);
if (ret != 0)
return OMAPCONF_ERR_REG_ACCESS;
dprintf("%s(): SMPSxx_FORCE=0x%02X\n", __func__, val);
if (extract_bit(val, 7) == 1) {
dprintf("%s(): CMD=1 => use SMPSxx_VOLTAGE register.\n",
__func__);
vsel_addr = smps_regs->voltage;
} else {
dprintf("%s(): CMD=0 => use SMPSxx_FORCE register.\n",
__func__);
vsel_addr = smps_regs->force;
}
}
/* Retrieve VSEL (7-bit LSB) from relevant register */
if (vsel_addr == (unsigned int) smps_regs->voltage) {
if (smps_regs->voltage == -1) {
dprintf("%s(): SMPSxx_VOLTAGE addr=-1!!!\n", __func__);
return OMAPCONF_ERR_INTERNAL;
}
ret = i2cget(TWL6035_I2C_BUS, TWL6035_ID1_ADDR,
smps_regs->voltage, &val);
if (ret != 0)
return OMAPCONF_ERR_REG_ACCESS;
dprintf("%s(): SMPSxx_VOLTAGE=0x%02X\n", __func__, val);
}
vsel = extract_bitfield(val, 0, 7);
dprintf("%s(): SMPSxx_VOLTAGE=0x%02X SMPSxx_VOLTAGE.VSEL=0x%02X\n",
__func__, val, vsel);
/* Retrieve VSEL range from SMPSxx_VOLTAGE register (bit 7) */
if (vsel_addr != (unsigned int) smps_regs->voltage) {
if (smps_regs->voltage == -1) {
dprintf("%s(): SMPSxx_VOLTAGE addr=-1!!!\n", __func__);
return OMAPCONF_ERR_INTERNAL;
}
ret = i2cget(TWL6035_I2C_BUS, TWL6035_ID1_ADDR,
smps_regs->voltage, &val);
if (ret != 0)
return OMAPCONF_ERR_REG_ACCESS;
}
range = extract_bit(val, 7);
dprintf("%s(): SMPSxx_VOLTAGE=0x%02X SMPSxx_VOLTAGE.RANGE=%u\n",
__func__, val, range);
/* Return VSEL (7-bit LSB), including range (MSB) */
vsel = vsel | (range << 7);
dprintf("%s(): vsel=0x%02X\n", __func__, vsel);
return vsel;
}
/* ------------------------------------------------------------------------*//**
* @FUNCTION twl603x_uvoltage_get
* @BRIEF return voltage of a given SMPS voltage rail.
* @RETURNS voltage of a given SMPS voltage rail, in micro-volt.
* @param[in] vdd_id: voltage domain ID
* @DESCRIPTION return voltage of a given SMPS voltage rail,
* in millivolt.
* NB: not supported by TWL6030/TWL6032.
*//*------------------------------------------------------------------------ */
unsigned long twl603x_uvoltage_get(unsigned int vdd_id)
{
int vsel;
vsel = twl603x_vsel_get(vdd_id);
if (vsel < 0)
return 0;
return twl603x_vsel_to_uv(vdd_id, vsel);
}
/* ------------------------------------------------------------------------*//**
* @FUNCTION twl603x_voltage_get
* @BRIEF return voltage of a given SMPS voltage rail.
* @RETURNS voltage of a given SMPS voltage rail, in volt.
* @param[in] vdd_id: voltage domain ID
* @DESCRIPTION return voltage of a given SMPS voltage rail,
* in volt.
* NB: not supported by TWL6030/TWL6032.
*//*------------------------------------------------------------------------ */
double twl603x_voltage_get(unsigned int vdd_id)
{
int vsel;
vsel = twl603x_vsel_get(vdd_id);
if (vsel < 0)
return 0;
return (double) twl603x_vsel_to_uv(vdd_id, vsel) / 1000000.0;
}
/* ------------------------------------------------------------------------*//**
* @FUNCTION twl603x_uvoltage_set
* @BRIEF set voltage of a given SMPS voltage rail.
* @RETURNS 0 in case of success
* OMAPCONF_ERR_CPU
* OMAPCONF_ERR_ARG
* OMAPCONF_ERR_NOT_AVAILABLE
* OMAPCONF_ERR_REG_ACCESS
* OMAPCONF_ERR_INTERNAL
* @param[in] vdd_id: voltage domain ID
* @param[in] uv: voltage to be set (in micro-volt)
* @DESCRIPTION set voltage of a given SMPS voltage rail, in micro-volt.
* NB: not supported by TWL6030/TWL6032.
*//*------------------------------------------------------------------------ */
int twl603x_uvoltage_set(unsigned int vdd_id, unsigned long uv)
{
int ret;
unsigned int val;
unsigned char vsel;
const twl6035_smps_registers **vdd_smps_regs;
const twl6035_smps_registers *smps_regs;
if (!twl603x_is_twl6035())
return OMAPCONF_ERR_CPU;
CHECK_ARG_LESS_THAN(vdd_id, 3, OMAPCONF_ERR_ARG);
/* Retrive SMPS registers addresses */
vdd_smps_regs = twl6035_smps_vdd54xx[vdd_id];
if (vdd_smps_regs == NULL)
return OMAPCONF_ERR_INTERNAL;
smps_regs = *vdd_smps_regs;
if (smps_regs == NULL)
return OMAPCONF_ERR_INTERNAL;
dprintf("%s(): vdd_id=%u ADDR: ctrl=0x%02X tstep=0x%02X force=0x%02X "
"voltage=0x%02X\n", __func__, vdd_id, smps_regs->ctrl,
smps_regs->tstep, smps_regs->force, smps_regs->voltage);
/* Check SMPS Status */
/* FIXME: create dedicated API */
if (smps_regs->ctrl == -1) {
dprintf("%s(): SMPSxx_CTRL addr=-1!!!\n", __func__);
return OMAPCONF_ERR_INTERNAL;
}
ret = i2cget(TWL6035_I2C_BUS, TWL6035_ID1_ADDR,
smps_regs->ctrl, &val);
if (ret != 0)
return OMAPCONF_ERR_REG_ACCESS;
dprintf("%s(): SMPSxx_CTRL=0x%02X\n", __func__, val);
if (extract_bitfield(val, 4, 2) == 0) {
dprintf("(%s(): SMPS is OFF\n", __func__);
return OMAPCONF_ERR_NOT_AVAILABLE;
}
/* Make sure SMPSxx_CTRL.ROOF_FLOOR_EN=0 */
/* FIXME: create dedicated API */
if (extract_bit(val, 6) == 1) {
dprintf("%s(): SMPS voltage controlled by resource pins, "
"clearing ROOF_FLOOR_EN bit.\n", __func__);
/* Clear ROOF_FLOOR_EN bit (6) */
val = val & 0xBF;
ret = i2cset(TWL6035_I2C_BUS, TWL6035_ID1_ADDR,
smps_regs->ctrl, (unsigned int) val);
if (ret != 0)
return OMAPCONF_ERR_REG_ACCESS;
dprintf("%s(): SMPS voltage now controlled by "
"SMPS12_FORCE.CMD bit.\n", __func__);
} else {
dprintf("%s(): SMPS voltage controlled by "
"SMPS12_FORCE.CMD bit.\n", __func__);
}
/* Convert voltage to VSEL */
vsel = twl603x_uv_to_vsel(vdd_id, uv);
dprintf("%s(): uv=%lu vsel=0x%02X\n", __func__, uv, vsel);
/* Write VSEL to SMPSxx_VOLTAGE */
ret = i2cset(TWL6035_I2C_BUS, TWL6035_ID1_ADDR,
smps_regs->voltage, (unsigned int) vsel);
if (ret != 0)
return OMAPCONF_ERR_REG_ACCESS;
/*
* Try to switch voltage control to SMPSxx_FORCE register (if exists)
* so that voltage will not be overriden by kernel during
* DVFS, AVS or power transition.
*/
if (smps_regs->force != -1) {
dprintf("%s(): SMPSxx_FORCE exists, switching control.\n",
__func__);
/* Clear bit 7 (CMD) */
val = vsel & 0x7F;
ret = i2cset(TWL6035_I2C_BUS, TWL6035_ID1_ADDR,
smps_regs->force, (unsigned int) val);
} else {
dprintf("%s(): SMPSxx_FORCE does not exist.\n", __func__);
ret = 0;
}
return ret;
}
/* ------------------------------------------------------------------------*//**
* @FUNCTION twl603x_main
* @BRIEF TWL603x menu
* ### DEPRECATED, DO NOT USE ANYMORE ###
* @RETURNS 0 in case of success
* OMAPCONF_ERR_ARG
* OMAPCONF_ERR_CPU
* OMAPCONF_ERR_INTERNAL
* @param[in] argc: shell input argument number
* @param[in] argv: shell input argument(s)
* @DESCRIPTION TWL603x menu
* ### DEPRECATED, DO NOT USE ANYMORE ###
*//*------------------------------------------------------------------------ */
int twl603x_main(int argc, char *argv[])
{
int ret;
if (!cpu_is_omap44xx() && !cpu_is_omap54xx())
return OMAPCONF_ERR_CPU;
if (argc == 2) {
static unsigned char init_done = 0;
if (!init_done) {
twl603x_init_regtable();
init_done = 1;
}
if (strcmp(argv[1], "dump") == 0)
ret = twl603x_dumpregs(stdout);
else if (cpu_is_omap54xx())
ret = OMAPCONF_ERR_ARG;
else if (strcmp(argv[1], "cfg") == 0)
ret = twl603x_config(stdout);
else if (strcmp(argv[1], "ldocfg") == 0)
ret = twl603x_config_ldo(stdout);
else if (strcmp(argv[1], "smpscfg") == 0)
ret = twl603x_config_smps(stdout);
else if (strcmp(argv[1], "rescfg") == 0)
ret = twl603x_config_resources(stdout);
else if (strcmp(argv[1], "devpwrgrpstat") == 0)
ret = twl603x_config_devpwrgrp_status(stdout);
else if (strcmp(argv[1], "reset") == 0)
ret = twl603x_reset(stdout);
else
ret = OMAPCONF_ERR_ARG;
} else if (argc == 4) {
if (strcmp(argv[1], "setpwrgrp") == 0) {
ret = twl603x_pwrgrp_set(stdout, argv[2], argv[3]);
} else {
ret = OMAPCONF_ERR_ARG;
}
} else {
ret = OMAPCONF_ERR_ARG;
}
if (ret == OMAPCONF_ERR_ARG)
help(HELP_PMIC);
return ret;
}
Jump to Line
Something went wrong with that request. Please try again.