blob: 33caebdc5e132d2989ac739a5c2c00e10761a1c8 [file] [log] [blame]
/*
* Copyright (C) 2014 Marvell International Ltd.
* Hongyan Song <hysong@marvell.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <i2c.h>
#include <power/pmic.h>
#include <power/marvell88pm_pmic.h>
#include <power/88pm801.h>
#include <power/pm802.h>
#include <errno.h>
#include <asm/arch/cpu.h>
#define MARVELL_PMIC_BASE "88pm801_base"
#define MARVELL_PMIC_POWER "88pm801_power"
#define MARVELL_PMIC_GPADC "88pm801_gpadc"
#define MARVELL_PMIC_TEST "88pm801_test"
#define PM803_DUMMY_REG0 (0x15)
#define PM803_REBOOT_FLAG (0x50)
enum {
PM800_ID_LDO1 = 0x08,
PM800_ID_LDO2 = 0x0b,
PM800_ID_LDO3,
PM800_ID_LDO4,
PM800_ID_LDO5,
PM800_ID_LDO6,
PM800_ID_LDO7,
PM800_ID_LDO8,
PM800_ID_LDO9,
PM800_ID_LDO10,
PM800_ID_LDO11,
PM800_ID_LDO12,
PM800_ID_LDO13,
PM800_ID_LDO14,
PM800_ID_LDO15,
PM800_ID_LDO16,
PM800_ID_LDO17,
PM800_ID_LDO18,
PM800_ID_LDO19 = 0x1c,
PM800_ID_BUCK1 = 0x3c,
PM800_ID_BUCK2 = 0x40,
PM800_ID_BUCK3 = 0x41,
PM800_ID_BUCK4 = 0x42,
PM800_ID_BUCK5 = 0x43,
PM800_BUCK_EN1 = 0x50,
PM800_LDO1_8_EN1 = 0x51,
PM800_LDO9_16_EN1 = 0x52,
PM800_LDO17_19_EN1 = 0x53,
};
static struct pmic_chip_desc *g_chip;
static const unsigned int ldo1_voltage_table[] = {
600000, 650000, 700000, 750000, 800000, 850000, 900000, 950000,
1000000, 1050000, 1100000, 1150000, 1200000, 1300000, 1400000, 1500000,
};
static const unsigned int ldo2_voltage_table[] = {
1700000, 1800000, 1900000, 2000000, 2100000, 2500000, 2700000, 2800000,
};
static const unsigned int ldo3_to_17_voltage_table[] = {
1200000, 1250000, 1700000, 1800000, 1850000, 1900000, 2500000, 2600000,
2700000, 2750000, 2800000, 2850000, 2900000, 3000000, 3100000, 3300000,
};
static const unsigned int ldo18_19_voltage_table[] = {
1700000, 1800000, 1900000, 2500000, 2800000, 2900000, 3100000, 3300000,
};
static const unsigned int pm803_ldo1_5_voltage_table[] = {
1600000, 1700000, 1800000, 1900000, 2000000, 2700000, 2800000, 2900000,
};
static const unsigned int pm803_ldo_1v2_3v3_voltage_table[] = {
1200000, 1250000, 1600000, 1700000, 1800000, 1900000, 2000000, 2500000,
2600000, 2700000, 2800000, 2850000, 2900000, 3000000, 3100000, 3300000,
};
static const unsigned int pm802s_ldo_volt_table[] = {
1200000, 1250000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000,
1900000, 2750000, 2800000, 2850000, 2900000, 3000000, 3100000, 3300000,
};
static u8 pm801_slp_cnt;
static u8 asrpmic_gpadc_otp = 0;
static int pmic_sample_offset = 0;
static int pmic_vref_offset = 0;
struct pmic *g_p_base;
static int vref_offset_table[] = {
(-1 * 2) - 1,
(-4 * 2) - 1,
(-7 * 2) - 1,
(-10* 2) - 1,
(1 * 2) + 1,
(4 * 2) + 1,
(7 * 2) + 1,
(10 * 2) + 1,
};
static int pm813s_vref_offset_table[] = {
(-1 * 2),
(-3 * 2),
(-5 * 2),
(-7 * 2),
(-9 * 2),
(-11* 2),
(-13* 2),
(-15* 2),
( 1 * 2),
( 3 * 2),
( 5 * 2),
( 7 * 2),
( 9 * 2),
( 11* 2),
( 13* 2),
( 15* 2),
};
void pmic_clear_pdown_log(void)
{
/* clear power down log */
pmic_reg_write(g_p_base, POWER_DOWN_LOG1, 0xff);
pmic_reg_write(g_p_base, POWER_DOWN_LOG2, 0xff);
if (pmic_is_pm803()) {
pmic_reg_write(g_p_base, PM803_BASE_BLANK_REG7, 0x0);
pmic_reg_write(g_p_base, PM803_BASE_BLANK_REG8, 0x0);
} else if (pmic_is_pm802s()) {
pmic_reg_write(g_p_base, PM802S_BASE_BLANK_REGE, 0x0);
pmic_reg_write(g_p_base, PM802S_BASE_BLANK_REGF, 0x0);
} else if (pmic_is_pm813s()) {
pmic_reg_write(g_p_base, PM813S_BASE_BLANK_REGE, 0x0);
pmic_reg_write(g_p_base, PM813S_BASE_BLANK_REGF, 0x0);
} else {
printf("!!!warning: powerup log not in bankup\n");
}
}
void pmic_prepare_for_soc_reboot(void)
{
pmic_clear_pdown_log();
if (pmic_is_pm803()) {
pmic_reg_write(g_p_base, PM803_DUMMY_REG0, PM803_REBOOT_FLAG);
}
printf("pmic prepare for soc reset\n");
}
int marvell88pm801_reg_update(struct pmic *p, int reg, unsigned int regval)
{
u32 val;
int ret = 0;
ret = pmic_reg_read(p, reg, &val);
if (ret) {
debug("%s: PMIC %d register read failed\n", __func__, reg);
return -1;
}
val |= regval;
ret = pmic_reg_write(p, reg, val);
if (ret) {
debug("%s: PMIC %d register write failed\n", __func__, reg);
return -1;
}
return 0;
}
static int pm801_buck_volt2hex(unsigned int buck, unsigned int uV)
{
unsigned int hex = 0;
switch (buck) {
case 1:
if (uV > 1800000) {
debug("%d is wrong voltage for BUCK%d\n", uV, buck);
return 0;
}
break;
case 2:
case 3:
case 4:
case 5:
if (uV > 3300000) {
debug("%d is wrong voltage for BUCK%d\n", uV, buck);
return 0;
}
break;
default:
debug("%d is wrong voltage for BUCK%d\n", uV, buck);
return -EINVAL;
}
if (uV <= 1600000)
hex = (uV - 600000) / 12500;
else
hex = 0x50 + (uV - 1600000) / 50000;
debug("%s: buck=%d, uV=%d, hex= %d\n", __func__, buck, uV, hex);
return hex;
}
int marvell88pm801_set_buck_vol(struct pmic *p,
unsigned int buck, unsigned int uV, int level)
{
unsigned int val, ret, adr = 0;
int hex = 0;
if (buck < 1 || buck > 5) {
printf("%s: wrong buck%d\n\n", __func__, buck);
return -1;
}
if (level < 0)
level = 0;
if (level > 3)
level = 3;
if (buck == 1 && uV > (1300 * 1000)) {
uV = 1300 * 1000;
printf("buck1 shouldn't > 1300mV\n");
}
switch (buck) {
case 1:
adr = PM801_ID_BUCK1;
adr += level;
break;
case 2:
adr = PM801_ID_BUCK2;
break;
case 3:
adr = PM801_ID_BUCK3;
break;
case 4:
adr = PM801_ID_BUCK4;
adr += level;
break;
case 5:
adr = PM801_ID_BUCK5;
break;
default:
printf("%s: wrong buck%d\n\n", __func__, buck);
return -EINVAL;
}
hex = pm801_buck_volt2hex(buck, uV);
if (hex < 0)
return -1;
ret = pmic_reg_read(p, adr, &val);
if (ret)
return ret;
val &= ~MARVELL88PM_BUCK_VOLT_MASK;
val |= hex;
ret = pmic_reg_write(p, adr, val);
return ret;
}
int pm802_set_buck_vol(struct pmic *p,
unsigned int buck, unsigned int uV, int level)
{
unsigned int val, ret, adr = 0;
int hex = 0;
if (buck < 1 || buck > 5 || (pmic_is_pm803() && buck > 1)
|| (pmic_is_pm813() && buck > 3)) {
printf("%s: wrong buck%d\n", __func__, buck);
return -1;
}
if (level < 0)
level = 0;
if (level > 3)
level = 3;
#ifdef CONFIG_ASR1802S
if (buck == 1 && uV > (1100 * 1000)) {
uV = 1100 * 1000;
printf("buck1 shouldn't > 1100mV\n");
}
#endif
#ifdef CONFIG_PXA182X
if (buck == 1 && uV > (1300 * 1000)) {
uV = 1300 * 1000;
printf("buck1 should not be set bigger than 1300mV\n");
}
#endif
switch (buck) {
case 1:
adr = PM802_ID_BUCK1;
if (pmic_is_pm803() || pmic_is_pm802s())
adr = PM803_ID_BUCK1;
else if (pmic_is_pm813())
adr = PM813_ID_BUCK1;
adr += level;
break;
case 2:
adr = PM802_ID_BUCK2;
break;
case 3:
adr = PM802_ID_BUCK3;
break;
case 4:
adr = PM802_ID_BUCK4;
adr += level;
break;
case 5:
adr = PM802_ID_BUCK5;
break;
default:
printf("%s: wrong buck%d\n", __func__, buck);
return -EINVAL;
}
hex = pm801_buck_volt2hex(buck, uV);
if (hex < 0)
return -1;
ret = pmic_reg_read(p, adr, &val);
if (ret)
return ret;
val &= ~MARVELL88PM_BUCK_VOLT_MASK;
val |= hex;
ret = pmic_reg_write(p, adr, val);
return ret;
}
static int pm801_buck_hex2volt(unsigned int buck, unsigned int hex)
{
unsigned int uV = 0;
if (hex <= 0x50)
uV = hex * 12500 + 600000;
else
uV = 1600000 + (hex - 0x50) * 50000;
debug("%s: buck=%d, uV=%d, hex= %d\n", __func__, buck, uV, hex);
return uV;
}
int marvell88pm801_get_buck_vol(struct pmic *p, unsigned int buck, int level)
{
unsigned int val, ret, adr = 0;
int uV;
if (buck < 1 || buck > 5) {
printf("%s: wrong buck%d\n", __func__, buck);
return -1;
}
if (level < 0)
level = 0;
if (level > 3)
level = 3;
switch (buck) {
case 1:
adr = PM801_ID_BUCK1;
adr += level;
break;
case 2:
adr = PM801_ID_BUCK2;
break;
case 3:
adr = PM801_ID_BUCK3;
break;
case 4:
adr = PM801_ID_BUCK4;
adr += level;
break;
case 5:
adr = PM801_ID_BUCK5;
break;
default:
printf("%s: wrong buck%d\n", __func__, buck);
return -EINVAL;
}
ret = pmic_reg_read(p, adr, &val);
if (ret)
return ret;
uV = pm801_buck_hex2volt(buck, val);
if (uV < 0)
return -1;
return uV;
}
int pm802_get_buck_vol(struct pmic *p, unsigned int buck, int level)
{
unsigned int val, ret, adr = 0;
int uV;
if (buck < 1 || buck > 5) {
printf("%s: wrong buck%d\n", __func__, buck);
return -1;
}
if (level < 0)
level = 0;
if (level > 3)
level = 3;
switch (buck) {
case 1:
adr = PM802_ID_BUCK1;
if (pmic_is_pm803() || pmic_is_pm802s())
adr = PM803_ID_BUCK1;
else if (pmic_is_pm813())
adr = PM813_ID_BUCK1;
adr += level;
break;
case 2:
adr = PM802_ID_BUCK2;
break;
case 3:
adr = PM802_ID_BUCK3;
break;
case 4:
adr = PM802_ID_BUCK4;
adr += level;
break;
case 5:
adr = PM802_ID_BUCK5;
break;
default:
printf("%s: wrong buck%d\n", __func__, buck);
return -EINVAL;
}
ret = pmic_reg_read(p, adr, &val);
if (ret)
return ret;
val &= 0x7f;
uV = pm801_buck_hex2volt(buck, val);
if (uV < 0)
return -1;
return uV;
}
static int pm800_ldo_volt2hex(unsigned int ldo, unsigned int uV)
{
unsigned int table_size = 0, hex = 0;
const unsigned int *voltage_table = NULL;
/*choose ldo voltage table*/
switch (ldo) {
case 1:
voltage_table = ldo1_voltage_table;
table_size = ARRAY_SIZE(ldo1_voltage_table);
break;
case 2:
voltage_table = ldo2_voltage_table;
table_size = ARRAY_SIZE(ldo2_voltage_table);
break;
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
case 16:
case 17:
voltage_table = ldo3_to_17_voltage_table;
table_size = ARRAY_SIZE(ldo3_to_17_voltage_table);
break;
case 18:
case 19:
voltage_table = ldo18_19_voltage_table;
table_size = ARRAY_SIZE(ldo18_19_voltage_table);
break;
default:
debug("%s: wrong ldo%d\n", __func__, ldo);
return -EINVAL;
}
for (hex = 0; hex < table_size; hex++) {
if (uV <= voltage_table[hex]) {
debug("ldo %d, voltage %d, reg value 0x%x\n", ldo, uV, hex);
return hex;
}
}
return table_size - 1;
}
static int pm801_pm802_ldo_volt2hex(unsigned int ldo, unsigned int uV)
{
unsigned int table_size = 0, hex = 0;
const unsigned int *voltage_table = NULL;
if (pmic_is_pm803()) {
/*choose ldo voltage table*/
switch (ldo) {
case 1:
case 5:
voltage_table = pm803_ldo1_5_voltage_table;
table_size = ARRAY_SIZE(pm803_ldo1_5_voltage_table);
break;
case 2:
case 3:
case 4:
case 6:
case 7:
case 8:
voltage_table = pm803_ldo_1v2_3v3_voltage_table;
table_size = ARRAY_SIZE(pm803_ldo_1v2_3v3_voltage_table);
break;
default:
debug("%s: %d is wrong LDO number\n", __func__, ldo);
return -EINVAL;
}
} else if (pmic_is_pm813()) {
/*choose ldo voltage table*/
switch (ldo) {
case 5:
case 13:
voltage_table = ldo18_19_voltage_table;
table_size = ARRAY_SIZE(ldo18_19_voltage_table);
break;
case 1 ... 4:
case 6 ... 12:
voltage_table = ldo3_to_17_voltage_table;
table_size = ARRAY_SIZE(ldo3_to_17_voltage_table);
break;
default:
debug("%s: %d is wrong LDO number\n", __func__, ldo);
return -EINVAL;
}
} else if (pmic_is_pm802s()) {
/*choose ldo voltage table*/
switch (ldo) {
case 1 ... 6:
voltage_table = pm802s_ldo_volt_table;
table_size = ARRAY_SIZE(pm802s_ldo_volt_table);
break;
default:
debug("%s: %d is wrong LDO number\n", __func__, ldo);
return -EINVAL;
}
} else {
/*choose ldo voltage table*/
switch (ldo) {
case 1:
case 2:
case 3:
case 4:
voltage_table = ldo3_to_17_voltage_table;
table_size = ARRAY_SIZE(ldo3_to_17_voltage_table);
break;
case 5:
case 6:
voltage_table = ldo18_19_voltage_table;
table_size = ARRAY_SIZE(ldo18_19_voltage_table);
break;
default:
debug("%s: %d is wrong LDO number\n", __func__, ldo);
return -EINVAL;
}
}
for (hex = 0; hex < table_size; hex++) {
if (uV <= voltage_table[hex]) {
debug("ldo %d, voltage %d, reg value 0x%x\n", ldo, uV, hex);
return hex;
}
}
return table_size - 1;
}
int marvell88pm801_set_ldo_vol(struct pmic *p, unsigned int ldo, unsigned int uV)
{
unsigned int val, ret, adr, ldo_en_mask;
int hex = 0;
if (ldo < 1 || ldo > 6) {
printf("%s: wrong ldo%d\n", __func__, ldo);
return -1;
}
hex = pm801_pm802_ldo_volt2hex(ldo, uV);
if (hex < 0)
return -1;
switch (ldo) {
case 1:
adr = PM801_ID_LDO1;
break;
case 2:
adr = PM801_ID_LDO2;
break;
case 3:
adr = PM801_ID_LDO3;
break;
case 4:
adr = PM801_ID_LDO4;
break;
case 5:
adr = PM801_ID_LDO5;
break;
case 6:
adr = PM801_ID_LDO6;
break;
default:
break;
}
ret = pmic_reg_read(p, adr, &val);
if (ret)
return ret;
val &= ~MARVELL88PM_LDO_VOLT_MASK;
val |= hex;
ret = pmic_reg_write(p, adr, val);
switch (ldo) {
case 1:
adr = PM801_LDO1_2_EN1;
ldo_en_mask = 2;
break;
case 2:
adr = PM801_LDO1_2_EN1;
ldo_en_mask = 4;
break;
case 3:
adr = PM801_LDO3_4_EN1;
ldo_en_mask = 8;
break;
case 4:
adr = PM801_LDO3_4_EN1;
ldo_en_mask = 3;
break;
case 5:
adr = PM801_LDO5_6_EN1;
ldo_en_mask = 1;
break;
case 6:
adr = PM801_LDO5_6_EN1;
ldo_en_mask = 2;
break;
default:
break;
}
ret = pmic_reg_read(p, adr, &val);
if (ret)
return ret;
val |= (1 << ldo_en_mask);
ret = pmic_reg_write(p, adr, val);
return ret;
}
int pm802_set_ldo_vol(struct pmic *p, unsigned int ldo, unsigned int uV)
{
unsigned int val, ret, adr, ldo_en_mask;
int hex = 0;
if (ldo < 1 || (pmic_is_pm802() && ldo > 6) || (pmic_is_pm803() && ldo > 8)
|| (pmic_is_pm813() && ldo > 13)) {
printf("%s: wrong ldo%d\n", __func__, ldo);
return -1;
}
hex = pm801_pm802_ldo_volt2hex(ldo, uV);
if (hex < 0)
return -1;
if (pmic_is_pm802())
adr = PM802_ID_LDO1 + (ldo - 1) * 3;
else
adr = PM803_ID_LDO1 + (ldo - 1) * 3;
ret = pmic_reg_read(p, adr, &val);
if (ret)
return ret;
if ((pmic_is_pm802() && (!pmic_is_pm802s())) || pmic_is_pm813()) {
val &= ~(0xf << 2);
val |= (hex << 2);
ret = pmic_reg_write(p, adr, val);
ldo_en_mask = (0x1 << 6);
} else {
val &= ~(0xf << 0);
val |= (hex << 0);
ret = pmic_reg_write(p, adr, val);
ldo_en_mask = (0x1 << 7);
}
ret = pmic_reg_read(p, adr, &val);
if (ret)
return ret;
val |= ldo_en_mask;
ret = pmic_reg_write(p, adr, val);
return ret;
}
int marvell88pm800_set_ldo_vol(struct pmic *p, unsigned int ldo, unsigned int uV)
{
unsigned int val, ret, adr, ldo_en_mask;
int hex = 0;
if (ldo < 1 || ldo > 19) {
printf("%s: %d wrong ldo\n", __func__, ldo);
return -1;
}
if (ldo == 1)
adr = PM800_ID_LDO1;
else if (ldo == 2)
adr = PM800_ID_LDO2;
else
adr = PM800_ID_LDO2 + ldo - 2;
hex = pm800_ldo_volt2hex(ldo, uV);
if (hex < 0)
return -1;
ret = pmic_reg_read(p, adr, &val);
if (ret)
return ret;
val &= ~MARVELL88PM_LDO_VOLT_MASK;
val |= hex;
ret = pmic_reg_write(p, adr, val);
/* check whether the LDO is enabled, if not enable it.*/
adr = PM800_LDO1_8_EN1 + (ldo - 1)/8;
ldo_en_mask = (ldo - 1)%8;
ret = pmic_reg_read(p, adr, &val);
if (ret)
return ret;
val |= (1 << ldo_en_mask);
ret = pmic_reg_write(p, adr, val);
return ret;
}
void marvell88pm_power_off(void)
{
int ret;
unsigned int val;
struct pmic *p_base;
p_base = pmic_get(MARVELL_PMIC_BASE);
if (!p_base) {
printf("can't get base pmic\n");
return;
}
ret = pmic_reg_read(p_base, 0xe7, &val);
if (ret) {
printf("88pm801 read 0xe7 failed\n");
return;
}
if (!(pmic_is_pm802() || pmic_is_pm803() || pmic_is_pm813())) {
val |= 0x1;
pmic_reg_write(p_base, 0xe7, val);
} else {
pmic_reg_read(p_base, 0xe2, &val);
val &= ~(0xf << 0);
if (pmic_is_pm813s() || pmic_is_pm802s())
val |= (0x3 << 0);
else
val |= (0x1 << 0);
pmic_reg_write(p_base, 0xe2, val);
pmic_reg_read(p_base, 0xe4, &val);
val &= ~(0x1 << 1);
pmic_reg_write(p_base, 0xe4, val);
}
ret = pmic_reg_read(p_base, 0x0d, &val);
if (ret) {
printf("88pm801 read 0x0d failed\n");
return;
}
val |= 0x20;
pmic_reg_write(p_base, 0x0d, val);
while(1);
}
int pmic_get_slp_cnt(void)
{
int ret = pm801_slp_cnt << 3;
return ret;
}
int marvell88pm_get_onkey(void)
{
int ret;
unsigned int val;
struct pmic *p_base;
p_base = pmic_get(MARVELL_PMIC_BASE);
if (!p_base) {
printf("can't get base pmic\n");
return -1;
}
/* Status1: ON_KEY=b0 */
ret = pmic_reg_read(p_base, 0x01, &val);
if (ret) {
printf("88pm801 read 0x1 failed\n");
return ret;
}
return val & 0x1;
}
int pmic_88pm801_alloc(unsigned char bus, struct pmic_chip_desc *chip)
{
struct pmic *p_base = pmic_alloc();
struct pmic *p_power = pmic_alloc();
struct pmic *p_gpadc = pmic_alloc();
struct pmic *p_test = pmic_alloc();
unsigned char addr = pmic_get_slave_addr();
if (!p_base || !p_power || !p_gpadc || !p_test) {
printf("%s: pmic alloc error!\n", __func__);
return -ENOMEM;
}
if (!chip) {
printf("%s: chip desc empty!\n", __func__);
return -EINVAL;
}
/* sanity check for pmic slave address */
if (MARVELL88PM_I2C_ADDR != addr && ASR88PM_I2C_ADDR != addr) {
printf("%s: i2c addr %02x wrong!\n", __func__, addr);
return -EINVAL;
}
if ((ASR88PM_I2C_ADDR == addr) && (0x10 != (chip->chip_id & 0xf0))) {
printf("%s: i2c addr %02x not match pmic\n", __func__, addr);
return -EINVAL;
}
chip->base_name = MARVELL_PMIC_BASE;
chip->power_name = MARVELL_PMIC_POWER;
chip->gpadc_name = MARVELL_PMIC_GPADC;
chip->test_name = MARVELL_PMIC_TEST;
chip->charger_name = NULL;
chip->fuelgauge_name = NULL;
chip->battery_name = NULL;
p_base->bus = bus;
p_base->hw.i2c.addr = addr;
p_base->name = MARVELL_PMIC_BASE;
p_base->interface = PMIC_I2C;
p_base->number_of_regs = PMIC_NUM_OF_REGS;
p_base->hw.i2c.tx_num = 1;
p_power->bus = bus;
p_power->hw.i2c.addr = addr + 1;
p_power->name = MARVELL_PMIC_POWER;
p_power->interface = PMIC_I2C;
p_power->number_of_regs = PMIC_NUM_OF_REGS;
p_power->hw.i2c.tx_num = 1;
p_gpadc->bus = bus;
p_gpadc->hw.i2c.addr = addr + 2;
p_gpadc->name = MARVELL_PMIC_GPADC;
p_gpadc->interface = PMIC_I2C;
p_gpadc->number_of_regs = PMIC_NUM_OF_REGS;
p_gpadc->hw.i2c.tx_num = 1;
p_test->bus = bus;
p_test->hw.i2c.addr = addr + 7;
p_test->name = MARVELL_PMIC_TEST;
p_test->interface = PMIC_I2C;
p_test->number_of_regs = PMIC_NUM_OF_REGS;
p_test->hw.i2c.tx_num = 1;
if (pmic_is_pm802() || pmic_is_pm803() || pmic_is_pm813()) {
/* get functions */
chip->set_buck_vol = pm802_set_buck_vol;
chip->set_ldo_vol = pm802_set_ldo_vol;
chip->get_buck_vol = pm802_get_buck_vol;
} else if(chip->chip_id == 0x64) { /* PM812 */
/* get functions */
chip->set_buck_vol = marvell88pm801_set_buck_vol;
chip->set_ldo_vol = marvell88pm800_set_ldo_vol;
chip->get_buck_vol = marvell88pm801_get_buck_vol;
} else { /* PM801 */
/* get functions */
chip->set_buck_vol = marvell88pm801_set_buck_vol;
chip->set_ldo_vol = marvell88pm801_set_ldo_vol;
chip->get_buck_vol = marvell88pm801_get_buck_vol;
}
chip->reg_update = marvell88pm801_reg_update;
puts("PMIC init\n");
g_chip = chip;
return 0;
}
void pmic_88pm801_base_init(struct pmic *p_base, struct pmic *p_test)
{
u32 val;
/* set internal cap sel to 22pf */
val = 0x70;
pmic_reg_write(p_base, 0xE8, val);
pmic_reg_read(p_base, 0xe9, &val);
pm801_slp_cnt = val & 0xff;
printf("pm801_slp_cnt: 0x%x\n", pm801_slp_cnt);
#if 0 /* disable smpl workaround */
/* open test page */
pmic_reg_write(p_base, 0x1f, 0x01);
if (pmic_probe(p_test))
return;
pmic_reg_read(p_test, 0x74, &val);
printf("bat_wu_mask: 0x%x\n", val >> 7);
if (pmic_probe(p_base))
return;
/* bat_wu_debounce:16ms */
pmic_reg_read(p_base, 0xe4, &val);
val |= 0x0c;
pmic_reg_write(p_base, 0xe4, val);
if (pmic_probe(p_test))
return;
pmic_reg_write(p_test, 0x50, 0xe7);
pmic_reg_write(p_test, 0x51, 0x01);
pmic_reg_write(p_test, 0x58, 0x00);
if (pmic_probe(p_base))
return;
/* close test page */
pmic_reg_write(p_base, 0x1f, 0x00);
#endif
/* 0xe2 and 0xd0 registers need to set at the same time to
* make 32k clock work. there are two options:
* 1) 0xd0 = 0, 0xe2 = 0x05 or 0x06
* 2) 0xd0 bit 7 is 1 , 0xe2 = 0x2a (the formal one we use)
*/
/*base page:reg 0xd0.7 = 1 32kHZ generated from XO */
pmic_reg_read(p_base, 0xd0, &val);
val |= (1 << 7);
pmic_reg_write(p_base, 0xd0, val);
/* enable DVC function */
pmic_reg_read(p_base, 0x0d, &val);
val |= (1 << 7);
pmic_reg_write(p_base, 0x0d, val);
/* Disable PMIC watchdog */
val = 0x01;
pmic_reg_write(p_base, 0x1d, val);
/* Enable external 32KHZ clock in pmic */
pmic_reg_read(p_base, 0xe2, &val);
val = (val & (~0x3f)) | 0x2a;
pmic_reg_write(p_base, 0xe2, val);
/* set oscillator running locked to 32kHZ*/
pmic_reg_read(p_base, 0x50, &val);
val &= ~(1 << 1);
pmic_reg_write(p_base, 0x50, val);
/* Enable 32Khz-out-2 low jitter XO_LJ = 1 */
val = 0x20;
pmic_reg_write(p_base, 0x21, val);
pmic_reg_read(p_base, 0x55, &val);
val &= ~(1 << 1);
pmic_reg_write(p_base, 0x55, val);
/*
* print out power up/down log
* save it in EMMD
*/
get_powerup_down_log(g_chip);
}
void pmic_pm802_base_init(struct pmic *p_base, struct pmic *p_test)
{
u32 val, id;
pmic_reg_read(p_base, 0x0, &id);
pmic_reg_read(p_base, 0x5, &val);
if (pmic_is_pm802s()) {
/* disable i2c timeout */
pmic_reg_read(p_base, 0x1d, &val);
val |= (1 << 3);
pmic_reg_write(p_base, 0x1d, val);
}
/* 0xe2 and 0xd0 registers need to set at the same time to
* make 32k clock work. there are two options:
* 1) 0xd0 = 0, 0xe2 = 0x05 or 0x06
* 2) 0xd0 bit 7 is 1 , 0xe2 = 0x2a (the formal one we use)
*/
/*base page:reg 0xd0.7 = 1 32kHZ generated from XO */
#ifndef CONFIG_ASR1802S
pmic_reg_read(p_base, 0xd0, &val);
val |= (1 << 7);
pmic_reg_write(p_base, 0xd0, val);
#else
pmic_reg_read(p_base, 0xd0, &val);
/* clear use_x for scs mode */
if ((cpu_is_asr1803() || cpu_is_asr1806() || cpu_is_asr1903()) && board_is_scs_mode()) {
printf("scs mode\n");
val &= ~(1 << 7);
} else {
val |= (1 << 7);
}
pmic_reg_write(p_base, 0xd0, val);
#endif
/* enable DVC function */
pmic_reg_read(p_base, 0x0d, &val);
val |= (1 << 7);
pmic_reg_write(p_base, 0x0d, val);
/* config xo cap for b0+ */
if (0x10 != id && 0x11 != id) {
pmic_reg_read(p_base, 0xF0, &val);
val &= ~(0x7 << 5);
val |= (0x3 << 5);
pmic_reg_write(p_base, 0xF0, val);
}
#ifndef CONFIG_ASR1802S
/* enable use_xo for none-A0 chips */
pmic_reg_read(p_base, 0xF1, &val);
val |= (0x1 << 2);
pmic_reg_write(p_base, 0xF1, val);
/* Enable external 32KHZ clock in pmic */
pmic_reg_read(p_base, 0xe4, &val);
val = (val & (~(0x3 << 2))) | (0x1 << 2);
pmic_reg_write(p_base, 0xe4, val);
#else
/* enable use_xo for none-A0 chips */
pmic_reg_read(p_base, 0xF1, &val);
/* clear use_x for scs mode */
if ((cpu_is_asr1803() || cpu_is_asr1806() || cpu_is_asr1903()) && board_is_scs_mode())
val &= ~(1 << 2);
else
val |= (1 << 2);
pmic_reg_write(p_base, 0xF1, val);
/* Enable external 32KHZ clock in pmic */
pmic_reg_read(p_base, 0xe4, &val);
if ((cpu_is_asr1803() || cpu_is_asr1806() || cpu_is_asr1903()) && board_is_scs_mode())
val = (val & (~(0x3 << 2)));
else
val = (val & (~(0x3 << 2))) | (0x1 << 2);
pmic_reg_write(p_base, 0xe4, val);
#endif
/* clear fault wakeup */
pmic_reg_read(p_base, 0xe7, &val);
val &= ~(0x3 << 2);
pmic_reg_write(p_base, 0xe7, val);
/* exton1 db time 16ms */
pmic_reg_read(p_base, 0xe3, &val);
val |= 0xf;
pmic_reg_write(p_base, 0xe3, val);
/* set default discharge time */
pmic_reg_read(p_base, 0xe2, &val);
val &= ~(0xf << 0);
if (pmic_is_pm813s() || pmic_is_pm802s())
val |= (0x3 << 0);
else
val |= (0x1 << 0);
pmic_reg_write(p_base, 0xe2, val);
/* disable rtc rtp reload */
if (pmic_is_pm802s()) {
pmic_reg_read(p_base, 0xe1, &val);
val |= (0x1 << 2);
pmic_reg_write(p_base, 0xe1, val);
}
/*
* print out power up/down log
* save it in EMMD
*/
get_powerup_down_log(g_chip);
/* open test page */
pmic_reg_write(p_base, 0x1f, 0x01);
if (pmic_probe(p_test)) {
printf("open testpage failed\n");
return;
}
asrpmic_gpadc_otp = 0;
if (pmic_is_pm802s()) {
pmic_reg_read(p_test, 0x6d, &val);
printf("otp6d:0x%02x\n", val);
asrpmic_gpadc_otp |= ((val >> 5) & 0x7);
pmic_reg_read(p_test, 0x68, &val);
printf("otp68:0x%02x\n", val);
asrpmic_gpadc_otp |= ((val >> (6-3)) & (0x3 << 3));
pmic_reg_read(p_test, 0x67, &val);
printf("otp67:0x%02x\n", val);
asrpmic_gpadc_otp |= ((val >> (7-5)) & (0x1 << 5));
printf("vref:0x%02x\n", asrpmic_gpadc_otp);
} else {
pmic_reg_read(p_test, 0x6d, &val);
printf("otp6d:0x%02x\n", val);
asrpmic_gpadc_otp |= ((val >> 4) & 0x1);
pmic_reg_read(p_test, 0x6e, &val);
printf("otp6e:0x%02x\n", val);
asrpmic_gpadc_otp |= ((val << 1) & (0x3 << 1));
printf("vref:0x%02x\n", asrpmic_gpadc_otp);
}
/* close test page */
pmic_reg_write(p_base, 0x1f, 0x00);
}
void pmic_pm813_base_init(struct pmic *p_base, struct pmic *p_test)
{
u32 val;
pmic_reg_read(p_base, 0x6, &val);
/* 0xe2 and 0xd0 registers need to set at the same time to
* make 32k clock work. there are two options:
* 1) 0xd0 = 0, 0xe2 = 0x05 or 0x06
* 2) 0xd0 bit 7 is 1 , 0xe2 = 0x2a (the formal one we use)
*/
/*base page:reg 0xd0.7 = 1 32kHZ generated from XO */
#ifndef CONFIG_ASR1802S
pmic_reg_read(p_base, 0xd0, &val);
val |= (1 << 7);
pmic_reg_write(p_base, 0xd0, val);
#else
pmic_reg_read(p_base, 0xd0, &val);
/* clear use_x for scs mode */
if ((cpu_is_asr1803() || cpu_is_asr1806() || cpu_is_asr1903()) && board_is_scs_mode())
val &= ~(1 << 7);
else
val |= (1 << 7);
pmic_reg_write(p_base, 0xd0, val);
#endif
/* enable DVC function */
pmic_reg_read(p_base, 0x0d, &val);
val |= (1 << 7);
pmic_reg_write(p_base, 0x0d, val);
/* config xo cap, obm config it to 10pf */
pmic_reg_read(p_base, 0xF0, &val);
val &= ~(0x7 << 5);
val |= (0x3 << 5);
pmic_reg_write(p_base, 0xF0, val);
#ifndef CONFIG_ASR1802S
/* enable use_xo for none-A0 chips */
pmic_reg_read(p_base, 0xF1, &val);
val |= (0x1 << 2);
pmic_reg_write(p_base, 0xF1, val);
/* Enable external 32KHZ clock in pmic */
pmic_reg_read(p_base, 0xe4, &val);
val = (val & (~(0x3 << 2))) | (0x1 << 2);
pmic_reg_write(p_base, 0xe4, val);
#else
/* enable use_xo for none-A0 chips */
pmic_reg_read(p_base, 0xF1, &val);
/* clear use_x for scs mode */
if ((cpu_is_asr1803() || cpu_is_asr1806() || cpu_is_asr1903()) && board_is_scs_mode())
val &= ~(1 << 2);
else
val |= (1 << 2);
pmic_reg_write(p_base, 0xF1, val);
/* Enable external 32KHZ clock in pmic */
pmic_reg_read(p_base, 0xe4, &val);
if ((cpu_is_asr1803() || cpu_is_asr1806() || cpu_is_asr1903()) && board_is_scs_mode())
val = (val & (~(0x3 << 2)));
else
val = (val & (~(0x3 << 2))) | (0x1 << 2);
pmic_reg_write(p_base, 0xe4, val);
#endif
/* clear fault wakeup */
pmic_reg_read(p_base, 0xe7, &val);
val &= ~(0xf << 0);
pmic_reg_write(p_base, 0xe7, val);
/* exton1 db time 16ms */
pmic_reg_read(p_base, 0xe3, &val);
val |= 0x7;
pmic_reg_write(p_base, 0xe3, val);
/* disable RTC rtp reload */
if (pmic_is_pm813s()) {
pmic_reg_read(p_base, 0xf7, &val);
val |= (0x1 << 5);
pmic_reg_write(p_base, 0xf7, val);
} else {
pmic_reg_read(p_base, 0xd0, &val);
val |= (0x1 << 6);
pmic_reg_write(p_base, 0xd0, val);
}
/*
* print out power up/down log
* save it in EMMD
*/
get_powerup_down_log(g_chip);
/* open test page */
pmic_reg_write(p_base, 0x1f, 0x01);
if (pmic_probe(p_test)) {
printf("open testpage failed\n");
return;
}
asrpmic_gpadc_otp = 0;
if (pmic_is_pm813s()) {
pmic_reg_read(p_test, 0x6a, &val);
printf("otp6a:0x%02x\n", val);
asrpmic_gpadc_otp |= ((val >> 7) & 0x1);
pmic_reg_read(p_test, 0x6b, &val);
printf("otp6b:0x%02x\n", val);
asrpmic_gpadc_otp |= ((val >> (6)) & (0x2));
pmic_reg_read(p_test, 0x6c, &val);
printf("otp6c:0x%02x\n", val);
asrpmic_gpadc_otp |= ((val >> (5)) & (0x4));
pmic_reg_read(p_test, 0x6f, &val);
printf("otp6f:0x%02x\n", val);
asrpmic_gpadc_otp |= ((val >> (4)) & (0x8));
printf("vref:0x%02x\n", asrpmic_gpadc_otp);
}
/* close test page */
pmic_reg_write(p_base, 0x1f, 0x00);
}
void pmic_pm803_base_init(struct pmic *p_base, struct pmic *p_test)
{
u32 val, id;
pmic_reg_read(p_base, 0x0, &id);
pmic_reg_read(p_base, 0x5, &val);
/*
* print out power up/down log
* save it in EMMD
*/
get_powerup_down_log(g_chip);
/* disable ALARM PULL DOWN DISABLE
* and disable rtc_otp_reload
*/
pmic_reg_read(p_base, 0xd0, &val);
val |= ((1 << 7) | (0x1 << 6));
pmic_reg_write(p_base, 0xd0, val);
/* enable DVC function */
pmic_reg_read(p_base, 0x0d, &val);
val |= (1 << 7);
pmic_reg_write(p_base, 0x0d, val);
/* clear fault wakeup */
pmic_reg_read(p_base, 0xe7, &val);
val &= ~(0x3 << 0);
pmic_reg_write(p_base, 0xe7, val);
/* exton1 db time 16ms */
pmic_reg_read(p_base, 0xe3, &val);
val |= 0xf;
pmic_reg_write(p_base, 0xe3, val);
pmic_reg_read(p_base, 0xe2, &val);
val &= ~(0xf << 0);
val |= (0x1 << 0);
pmic_reg_write(p_base, 0xe2, val);
}
void pmic_88pm801_gpadc_init(struct pmic *p_gpadc)
{
/* TODO: enable battery detection: board specific */
u32 val;
/* enable GPADC MEAS_EN_SLP mode, 2x meas_off slot */
pmic_reg_write(p_gpadc, 0x06, 0x33);
pmic_reg_write(p_gpadc, 0x01, 0x0e);
pmic_reg_read(p_gpadc, 0x02, &val);
val |= 0x0c;
pmic_reg_write(p_gpadc, 0x02, val);
/* disable bias by default */
pmic_reg_write(p_gpadc, 0x14, 0x00);
}
static pmic_pm802_gpadc_calbration(struct pmic *p_gpadc)
{
int i, val, sum = 0;
int buf[2];
char data;
/* select cleanvref 1p2 */
/* pmic_reg_write(g_p_base, 0x0d, 0x88); */
/* set avg to 0*/
if (pmic_is_pm813s())
pmic_reg_write(p_gpadc, 0x38, 0x0);
/* sample adc */
if (pmic_is_pm813()) {
pmic_reg_write(p_gpadc, 0x3a, 0x80);
pmic_reg_write(p_gpadc, 0x39, 0x8f);
pmic_reg_write(p_gpadc, 0x3b, 0x0b);
} else {
pmic_reg_write(p_gpadc, 0x3a, 0xf8);
pmic_reg_write(p_gpadc, 0x39, 0x81);
pmic_reg_write(p_gpadc, 0x3b, 0x18);
}
for (i = 0; i < 10; i++) {
if (pmic_is_pm802()) {
pmic_reg_write(p_gpadc, 0x3b, 0x1c);
udelay(1000);
pmic_reg_read(p_gpadc, 0x4c, &buf[0]);
pmic_reg_read(p_gpadc, 0x4d, &buf[1]);
val = ((buf[1] & 0x0f) << 8) | (buf[0] & 0xff);
} else if (pmic_is_pm813()) {
pmic_reg_write(p_gpadc, 0x3b, 0x0f);
udelay(1000);
pmic_reg_read(p_gpadc, 0x54, &buf[0]);
pmic_reg_read(p_gpadc, 0x55, &buf[1]);
val = ((buf[0] & 0xff) << 4) | (buf[1] & 0xf);
} else {
pmic_reg_write(p_gpadc, 0x3b, 0x1c);
udelay(1000);
pmic_reg_read(p_gpadc, 0x4c, &buf[0]);
pmic_reg_read(p_gpadc, 0x4d, &buf[1]);
val = ((buf[0] & 0xff) << 4) | (buf[1] & 0xf);
}
if (pmic_is_pm813()) {
if (pmic_is_pm813s())
sum += (val - 1024);
else
sum += (val - 1032);
pmic_reg_write(p_gpadc, 0x3b, 0x0b);
} else {
sum += (val - 1032);
pmic_reg_write(p_gpadc, 0x3b, 0x18);
}
}
pmic_sample_offset = sum / 10;
if (pmic_is_pm802s()) {
if (asrpmic_gpadc_otp & (0x1 << 5)) {
data = (asrpmic_gpadc_otp & 0x3f) | (0x3 << 6);
pmic_vref_offset = 0xffffff00 | data;
} else {
pmic_vref_offset = data = asrpmic_gpadc_otp;
}
} else if (pmic_is_pm802()) {
pmic_vref_offset = vref_offset_table[asrpmic_gpadc_otp];
} else if (pmic_is_pm813s()) {
pmic_vref_offset = pm813s_vref_offset_table[asrpmic_gpadc_otp];
} else {
pmic_vref_offset = 0;
}
if (pmic_vref_offset > 127 || pmic_vref_offset < -128) {
printf("!!!pmic_vref_offset: %d\n", pmic_vref_offset);
pmic_vref_offset = 0;
}
if (pmic_sample_offset > 127 || pmic_sample_offset < -128) {
printf("!!!pmic sp offset: %d\n", pmic_sample_offset);
pmic_sample_offset = 0;
}
printf("vrefotp: 0x%02x,offset: %d\n", asrpmic_gpadc_otp, pmic_vref_offset);
printf("sample offset: %d\n", pmic_sample_offset);
val = pmic_vref_offset & 0xff;
pmic_reg_write(p_gpadc, 0x13, (u32)val);
val = pmic_sample_offset & 0xff;
pmic_reg_write(p_gpadc, 0x14, (u32)val);
}
void pmic_get_calibration_data(int *vref_offset, int *sample_offset)
{
*vref_offset = (pmic_vref_offset * 5);
*sample_offset = pmic_sample_offset;
}
void pmic_pm802_gpadc_init(struct pmic *p_gpadc)
{
u32 val;
/* TODO: enable battery detection: board specific */
/* disable gpadc normal mode by default */
pmic_reg_write(p_gpadc, 0x06, 0x00);
/* begin for default state */
/* clear gpadc_soc and gpadc_en */
pmic_reg_read(p_gpadc, 0x3B, &val);
val &= ~(0x3 << 2);
pmic_reg_write(p_gpadc, 0x3B, val);
pmic_reg_write(p_gpadc, 0x0A, 0x00);
/* enable use_100k, enable testmode */
pmic_reg_write(p_gpadc, 0x0A, 0x03);
/* disable bias by default */
pmic_reg_write(p_gpadc, 0x0D, 0x00);
/* update vinldo meas config */
if (!(pmic_is_pm802s() || pmic_is_pm813()))
pmic_reg_write(p_gpadc, 0x10, 0x40);
/* gpadc calibration */
pmic_pm802_gpadc_calbration(p_gpadc);
pmic_reg_write(p_gpadc, 0x39, 0x0);
/* 16 cycles of GPADC SAMPLE time, single conv mode */
pmic_reg_read(p_gpadc, 0x3A, &val);
val &= ~0x1;
val |= 0x18;
pmic_reg_write(p_gpadc, 0x3A, val);
/* set gpadc_soc and gpadc_en */
pmic_reg_read(p_gpadc, 0x3B, &val);
val &= ~(0x3 << 2);
val |= (0x3 << 2);
pmic_reg_write(p_gpadc, 0x3B, val);
}
void pmic_88pm801_power_init(struct pmic *p_power)
{
u32 val, id;
pmic_reg_read(p_power, 0x0, &id);
#ifdef CONFIG_ASR1802S
/* set vbuck1 sleep vol to 0.65v for 1802s,
* 0.6v for 1803 and 1828, and 1806
*/
pmic_reg_write(p_power, 0x30, 0x4);
#endif
#ifdef CONFIG_PXA182X
/* set vbuck1 sleep vol to 0.7v */
pmic_reg_write(p_power, 0x30, 0x8);
#endif
/* change drive selection from half to full */
val = 0xff;
pmic_reg_write(p_power, 0x3a, val);
/* store the slp_cnt */
pmic_reg_read(p_power, 0x71, &val);
val &= 0x0F;
val |= ((pm801_slp_cnt & 0x0f) << 4);
pmic_reg_write(p_power, 0x71, val);
pmic_reg_read(p_power, 0x9A, &val);
val &= 0x0F;
val |= (pm801_slp_cnt & 0xF0);
pmic_reg_write(p_power, 0x9A, val);
}
void pmic_pm802_power_init(struct pmic *p_power)
{
u32 val;
#ifdef CONFIG_ASR1802S
if (cpu_is_asr1903_a0() || cpu_is_asr1903_b0()) {
/* set vbuck1 sleep vol to 0.60v for:
* asr1903a0,asr1903b0
*/
pmic_reg_write(p_power, 0x21, 0x0);
} else {
/* set vbuck1 sleep vol to 0.65v for 1802s,
* 1803 and 1828, and 1806
*/
pmic_reg_write(p_power, 0x21, 0x4);
}
#endif
#ifdef CONFIG_PXA182X
/* set vbuck1 sleep vol to 0.7v */
pmic_reg_write(p_power, 0x21, 0x8);
#endif
#ifdef CONFIG_ASR1901
/* set vbuck1 sleep vol to 1.1v */
pmic_reg_write(p_power, 0x21, 0x28);
/* disable dvc for asr1901 */
pmic_reg_read(p_power, 0x21, &val);
val &= ~(0x1 << 7);
pmic_reg_write(p_power, 0x21, val);
#else
pmic_reg_read(p_power, 0x21, &val);
val |= (0x1 << 7);
pmic_reg_write(p_power, 0x21, val);
#endif
/* other misc config for pm802s */
if (pmic_is_pm802s()) {
pmic_reg_read(p_power, 0x22, &val);
val |= (0x1 << 7);
pmic_reg_write(p_power, 0x22, val);
pmic_reg_read(p_power, 0x24, &val);
val |= ((0x1 << 0) | (0x3 << 3));
pmic_reg_write(p_power, 0x24, val);
pmic_reg_read(p_power, 0x29, &val);
val |= 0x38;
pmic_reg_write(p_power, 0x29, val);
pmic_reg_read(p_power, 0x32, &val);
val |= (0x1 << 7);
pmic_reg_write(p_power, 0x32, val);
pmic_reg_read(p_power, 0x34, &val);
val |= (0x1 << 0);
pmic_reg_write(p_power, 0x34, val);
pmic_reg_read(p_power, 0x39, &val);
val |= 0x28;
pmic_reg_write(p_power, 0x39, val);
pmic_reg_read(p_power, 0x44, &val);
val |= 0x19;
pmic_reg_write(p_power, 0x44, val);
pmic_reg_read(p_power, 0x49, &val);
val |= 0x30;
pmic_reg_write(p_power, 0x49, val);
}
/* enable pmic skip mode */
pmic_reg_read(p_power, 0x24, &val);
val |= (0x1 << 7);
if (!pmic_is_pm802s())
val &= ~(0x1 << 3);
pmic_reg_write(p_power, 0x24, val);
pmic_reg_read(p_power, 0x27, &val);
val &= (~(0x7 << 5));
if (pmic_is_pm802s())
val |= (0x2 << 5);
else
val |= (0x3 << 5);
pmic_reg_write(p_power, 0x27, val);
/* clear fpwm */
pmic_reg_read(p_power, 0x25, &val);
val &= (~(0x1 << 3));
val |= (0x1 << 2);
pmic_reg_write(p_power, 0x25, val);
pmic_reg_read(p_power, 0x22, &val);
val &= (~0x7);
if (pmic_is_pm802s())
val |= (0x1 << 5);
else
val |= (0x1 << 5 | (0x5 << 0));
pmic_reg_write(p_power, 0x22, val);
/* buck2 low ripple config for auto mode */
if (!pmic_is_pm802s()) {
pmic_reg_read(p_power, 0x37, &val);
val &= (~(0x7 << 5));
val |= (0x3 << 5);
pmic_reg_write(p_power, 0x37, val);
pmic_reg_read(p_power, 0x34, &val);
val &= ~(0x1 << 3);
pmic_reg_write(p_power, 0x34, val);
pmic_reg_read(p_power, 0x32, &val);
val &= (~0x7);
val |= (0x5 << 0);
pmic_reg_write(p_power, 0x32, val);
} else {
pmic_reg_read(p_power, 0x37, &val);
val |= (0x1 << 6);
pmic_reg_write(p_power, 0x37, val);
}
/* disable BUCK2 skip mode and use automode */
#if 0
pmic_reg_read(p_power, 0x34, &val);
val |= (0x1 << 7);
pmic_reg_write(p_power, 0x34, val);
pmic_reg_read(p_power, 0x37, &val);
val &= (~(0x7 << 5));
val |= (0x3 << 5);
pmic_reg_write(p_power, 0x37, val);
pmic_reg_read(p_power, 0x35, &val);
val &= (~(0x1 << 3));
val |= (0x1 << 2);
pmic_reg_write(p_power, 0x35, val);
pmic_reg_read(p_power, 0x32, &val);
val &= (~0x7);
val |= (0x1 << 5 | (0x5 << 0));
pmic_reg_write(p_power, 0x32, val);
#endif
}
void pmic_pm803_power_init(struct pmic *p_power)
{
u32 val;
#ifdef CONFIG_ASR1802S
if (cpu_is_asr1903_a0() || cpu_is_asr1903_b0()) {
/* set vbuck1 sleep vol to 0.60v for:
* asr1903a0,asr1903b0
*/
pmic_reg_write(p_power, 0x21, 0x4);
} else {
/* set vbuck1 sleep vol to 0.65v for 1802s,
* 1803 and 1828, and 1806
*/
pmic_reg_write(p_power, 0x21, 0x4);
}
#endif
#ifdef CONFIG_PXA182X
/* set vbuck1 sleep vol to 0.7v */
pmic_reg_write(p_power, 0x21, 0x8);
#endif
pmic_reg_read(p_power, 0x21, &val);
val |= (0x1 << 7);
pmic_reg_write(p_power, 0x21, val);
#if 0 /* keep it for easy restore of fpwm mode if needed */
pmic_reg_read(p_power, 0x24, &val);
val &= ~(0x1 << 7);
pmic_reg_write(p_power, 0x24, val);
#else
/* enable pmic skip mode */
pmic_reg_read(p_power, 0x24, &val);
val |= (0x1 << 7);
pmic_reg_write(p_power, 0x24, val);
pmic_reg_read(p_power, 0x27, &val);
val &= (~(0x7 << 5));
val |= (0x0 << 5);
pmic_reg_write(p_power, 0x27, val);
/* clear fpwm */
pmic_reg_read(p_power, 0x25, &val);
val &= (~(0x1 << 3));
val |= (0x1 << 2);
pmic_reg_write(p_power, 0x25, val);
pmic_reg_read(p_power, 0x22, &val);
val &= (~0x7);
val |= (0x1 << 5 | (0x0 << 0));
pmic_reg_write(p_power, 0x22, val);
#endif
}
void pmic_88pm801_power_preinit(struct pmic *p_power)
{
/*
* set buck4 dvl01/10/11 as 1.8v before DVC is enabled
* don't set dvl00 as its default value is 1.8v
* buck4 need to be stable to supply RF
*/
pmic_reg_write(p_power, 0x43, 0x54);
pmic_reg_write(p_power, 0x44, 0x54);
pmic_reg_write(p_power, 0x45, 0x54);
}
void pmic_pm802_power_preinit(struct pmic *p_power) {}
void pmic_pm803_power_preinit(struct pmic *p_power) {}
int pmic_88pm801_init(struct pmic_chip_desc *chip)
{
struct pmic *p_base, *p_power, *p_gpadc, *p_test;
if (!chip) {
printf("---%s: chip is empty.\n", __func__);
return -EINVAL;
}
/*------------power page pre-setting -----------*/
p_power = pmic_get(chip->power_name);
if (!p_power)
return -1;
if (pmic_probe(p_power))
return -1;
if (pmic_is_pm802() || pmic_is_pm813())
pmic_pm802_power_preinit(p_power);
else if (pmic_is_pm803())
pmic_pm803_power_preinit(p_power);
else
pmic_88pm801_power_preinit(p_power);
/*------------base page setting-----------*/
p_base = pmic_get(chip->base_name);
if (!p_base)
return -1;
p_test = pmic_get(chip->test_name);
if (!p_test)
return -1;
if (pmic_probe(p_base))
return -1;
g_p_base = p_base;
if (pmic_is_pm802())
pmic_pm802_base_init(p_base, p_test);
else if (pmic_is_pm803())
pmic_pm803_base_init(p_base, p_test);
else if (pmic_is_pm813())
pmic_pm813_base_init(p_base, p_test);
else
pmic_88pm801_base_init(p_base, p_test);
board_pmic_base_fixup(p_base);
/*------------gpadc page setting -----------*/
p_gpadc = pmic_get(chip->gpadc_name);
if (!p_gpadc)
return -1;
if (pmic_probe(p_gpadc))
return -1;
if (pmic_is_pm802() || pmic_is_pm813())
pmic_pm802_gpadc_init(p_gpadc);
else if (!pmic_is_pm803())
pmic_88pm801_gpadc_init(p_gpadc);
if (!pmic_is_pm803())
board_pmic_gpadc_fixup(p_gpadc);
/*------------power page setting -----------*/
p_power = pmic_get(chip->power_name);
if (!p_power)
return -1;
if (pmic_probe(p_power))
return -1;
if (pmic_is_pm802() || pmic_is_pm813())
pmic_pm802_power_init(p_power);
else if (pmic_is_pm803())
pmic_pm803_power_init(p_power);
else
pmic_88pm801_power_init(p_power);
board_pmic_power_fixup(p_power);
return 0;
}
void pmic_pm802_powerdown(struct pmic *p_base)
{
u32 val;
printf("pm802 power down\n");
pmic_clear_pdown_log();
pmic_reg_read(p_base, 0xe2, &val);
val &= ~(0xf << 0);
if (pmic_is_pm813s() || pmic_is_pm802s())
val |= (0x3 << 0);
else
val |= (0x1 << 0);
pmic_reg_write(p_base, 0xe2, val);
pmic_reg_read(p_base, 0xe4, &val);
val &= ~(0x1 << 1);
pmic_reg_write(p_base, 0xe4, val);
pmic_reg_read(p_base, 0x0d, &val);
val |= (0x1 << 5);
pmic_reg_write(p_base, 0x0d, val);
while(1);
}