blob: 78513ad32447e86b1eaadd889eb99e7081fd96f8 [file] [log] [blame]
/*
* Copyright (C) 2014 Marvell International Ltd.
* Xiang Wang <wangx@marvell.com>
* Yi Zhang <yizhang@marvell.com>
* Fenghang Yin <yinfh@marvell.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <malloc.h>
#include <power/pmic.h>
#include <power/battery.h>
#include <power/marvell88pm_pmic.h>
#include <asm/errno.h>
#include <power/power_chrg.h>
#include <asm/io.h>
#include <asm/arch/cpu.h>
#ifndef MARVELL_PMIC_GPADC
#define MARVELL_PMIC_GPADC "88pm801_gpadc"
#else
#undef MARVELL_PMIC_GPADC
#define MARVELL_PMIC_GPADC "88pm801_gpadc"
#endif
#define PM803_ADC0_RTC_REG (0xd4010020)
#define PM803_ADC1_RTC_REG (0xd4010024)
#define PM803_DUMMY_REG0 (0x15)
#define PM803_REBOOT_FLAG (0x50)
#define PM803_BAT_ADC_D2 (423)
#define PM803_BAT_ADC_D1 (357)
#define PM803_BAT_MVOLT_D2 (4124)
#define PM803_BAT_MVOLT_D1 (3070)
#define PM803_NTC_ADC_D2 (423)
#define PM803_NTC_ADC_D1 (357)
#define PM803_NTC_MVOLT_D2 (4124)
#define PM803_NTC_MVOLT_D1 (3070)
/* #define PM803_DEBUG_TEST_ADC (1) */
#define MAX_ADC_GROUP_CNT 10
struct adc_vbat{
u16 adc; /* rtx adc value */
u16 vbat; /* vbat value */
};
// Add by MBTK
#if defined(CONFIG_FG_PM803) || defined(CONFIG_PM803_GPADC)
#define ERROR_VBAT_COEF 900
/*Çë¸ù¾Ý¿Í»§µÄ°å×ÓÍâΧ·Öѹµç·ÉèÖÃCUSTOMER_VBAT_COEFFICIENTΪ·ÖѹϵÊýX1000,Èç¹ûĬÈÏÖµ900Ϊ´òÓ¡±¨¾¯log*/
#define CUSTOMER_VBAT_COEFFICIENT ERROR_VBAT_COEF
extern int asr1803_adc_caldata_init(struct adc_vbat *adcvbat_data0,
struct adc_vbat *adcvbat_data1);
static u32 rtp_adc_code1, rtp_adc_code2;
// Change by mbtk for ADC calibration
#if defined(CONFIG_MBTK_BUILD_PROJECT_L508)
static struct adc_vbat adc0_vbat_def_pair[MAX_ADC_GROUP_CNT] =
{
{251, 154},
{364, 551},
{420, 752},
{445, 842},
{486, 992},
{540, 1189},
{596, 1391},
{624, 1492},
{657, 1615},
{712, 1815}
};
static struct adc_vbat adc1_vbat_def_pair[MAX_ADC_GROUP_CNT] =
{
{251, 154},
{364, 551},
{420, 752},
{445, 842},
{486, 992},
{540, 1189},
{596, 1391},
{624, 1492},
{657, 1615},
{712, 1815}
};
#elif defined(CONFIG_MBTK_BUILD_PROJECT_PN1803)
static struct adc_vbat adc0_vbat_def_pair[MAX_ADC_GROUP_CNT] =
{
{262, 200},
{289, 300},
{342, 500},
{398, 700},
{454, 900},
{535, 1200},
{587, 1400},
{643, 1600},
{698, 1800},
{700, 1805},
};
static struct adc_vbat adc1_vbat_def_pair[MAX_ADC_GROUP_CNT] =
{
{512, 3200},
{531, 3400},
{541, 3500},
{550, 3600},
{560, 3700},
{569, 3800},
{578, 3900},
{588, 4000},
{597, 4100},
{607, 4200}
};
#else
static struct adc_vbat adc0_vbat_def_pair[MAX_ADC_GROUP_CNT] =
{
{355, 3217},
{362, 3323},
{367, 3404},
{373, 3505},
{379, 3605},
{387, 3732},
{393, 3835},
{399, 3941},
{405, 4020},
{413, 4170}
};
static struct adc_vbat adc1_vbat_def_pair[MAX_ADC_GROUP_CNT] =
{
{355, 3217},
{362, 3323},
{367, 3404},
{373, 3505},
{379, 3605},
{387, 3732},
{393, 3835},
{399, 3941},
{405, 4020},
{413, 4170}
};
#endif
#endif // defined(CONFIG_FG_PM803) || defined(CONFIG_PM803_GPADC)
#ifdef CONFIG_AUXADC
#define APBS_REG_12 (0x12c)
#define APBS_REG_2 (0x104)
#define APBS_REG_3 (0x108)
#define AUX_REG_BASE_OFFSET (0x80)
#define AUX_REG_DATA (0x80 - AUX_REG_BASE_OFFSET)
#define AUX_INT_CLR_REG (0xF0 - AUX_REG_BASE_OFFSET)
#define AUX_INT_STS_REG (0xA0 - AUX_REG_BASE_OFFSET)
#define OLD_AUXADC_REG_CTRL (0x0)
#define OLD_AUXADC_REG_CFG (0x4)
#define OLD_AUXADC_REG_INT_STATUS (0x8)
#define OLD_AUXADC_REG_ADCTIME_CTRL (0xC)
#define OLD_AUXADC_REG_DATA (0x10)
#define OLD_AUXADC_REG_CTRL2 (0x70)
#define APBS_REG_BASE (0xd4090000)
#ifdef CONFIG_ASR1901
#define AUX_REG_BASE (0xd4013400)
#define AUXADC_CLK_CTRL (0xd4015000 + 0xA8)
#define CONFIG_OLD_AUXADC 1
#else
#define AUX_REG_BASE (0xd4013380)
#define AUXADC_CLK_CTRL (0xd4015000 + 0x6C)
#define GEU_REG_BASE (0xD4201000)
#ifdef CONFIG_OLD_AUXADC
#undef CONFIG_OLD_AUXADC
#endif
#define FUSE_BANK3_223_192 0x41C
#define FUSE_BANK3_255_224 0x420
#define FUSE_BANK0_BG_REG 0x4A8
#define APBS_REG_1 0x104
#define ASR1903_GEU_FUSE_BANK0_239_208 0x414
#endif
struct asr_auxadc_fusedata {
u16 auxadc_gain_offset;
u16 auxadc_gain_error;
u16 fuse_bits;
u16 fuse_mask_all;
u16 fuse_mask_data;
};
struct asr_auxadc {
void *base;
void *adc_ctrl_reg;
struct asr_auxadc_fusedata fuse_data;
};
#endif
__weak void board_pmic_base_fixup(struct pmic *p_base) {}
__weak void board_pmic_power_fixup(struct pmic *p_power) {}
__weak void board_pmic_buck_fixup(struct pmic *p_buck) {}
__weak void board_pmic_ldo_fixup(struct pmic *p_ldo) {}
__weak void board_pmic_gpadc_fixup(struct pmic *p_gpadc) {}
__weak void board_pmic_battery_fixup(struct pmic *p_gpadc) {}
__weak void pmic_pm886_powerdown(struct pmic *p_base) {}
__weak void pmic_pm880_powerdown(struct pmic *p_base) {}
__weak void pmic_pm802_powerdown(struct pmic *p_base) {}
__weak void oled_display_off(void) {}
unsigned int pmic_power_status;
static u8 smpl_reboot_flag;
static u8 pmic_slave_addr = MARVELL88PM_I2C_ADDR;
static u8 g_pmic_id = 0x13;
static u32 pm803_dummy_reg0;
#ifdef CONFIG_AUXADC
static struct asr_auxadc *g_auxadc;
#ifdef CONFIG_ASR1901
static int asr_auxadc_fusedata_init(struct asr_auxadc *asr_auxadc)
{
u32 value;
value = asr_geu_read(BANK3_FUSE_63_32);
asr_auxadc->fuse_data.auxadc_gain_offset = ((value >> (44 - 32)) & (0xfff));
asr_auxadc->fuse_data.auxadc_gain_error = ((value >> (32 - 32)) & (0xfff));
asr_auxadc->fuse_data.fuse_bits = 12;
asr_auxadc->fuse_data.fuse_mask_data = 0x7ff;
asr_auxadc->fuse_data.fuse_mask_all = 0xfff;
printf("auxadc fusedata: %03x %03x, %08X, %08X\n",
asr_auxadc->fuse_data.auxadc_gain_offset,
asr_auxadc->fuse_data.auxadc_gain_error,
readl(APBS_REG_BASE + 0x10c), value);
return 0;
}
#else
static int asr_auxadc_fusedata_init(struct asr_auxadc *asr_auxadc)
{
u32 value;
if (cpu_is_asr1826s()) {
value = readl(GEU_REG_BASE + FUSE_BANK3_223_192);
printf("fs-192: %08X\n", value);
asr_auxadc->fuse_data.auxadc_gain_error = (value >> (208 - 192)) & 0xfff; /* 12 bits */
asr_auxadc->fuse_data.auxadc_gain_offset = (value >> 28) & 0xf; /* 4 bits */
value = readl(GEU_REG_BASE + FUSE_BANK3_255_224);
printf("fs-224: %08X\n", value);
asr_auxadc->fuse_data.auxadc_gain_offset |= ((value << 4) & 0xff0); /* 8 bits */
value = readl(GEU_REG_BASE + FUSE_BANK0_BG_REG);
printf("bg reg: %08X\n", value);
asr_auxadc->fuse_data.fuse_bits = 12;
asr_auxadc->fuse_data.fuse_mask_data = 0x7ff;
asr_auxadc->fuse_data.fuse_mask_all = 0xfff;
printf("auxadc fusedata: %03x %03x, %08X\n",
asr_auxadc->fuse_data.auxadc_gain_offset,
asr_auxadc->fuse_data.auxadc_gain_error,
readl(APBS_REG_BASE + 0x104));
} else {
if (cpu_is_asr1903()) { /* bank 0 bits 208 -> 217 */
value = readl(GEU_REG_BASE + ASR1903_GEU_FUSE_BANK0_239_208);
printf("bk0-208: %08X, bg: %01X,apb_sp2: %08X\n",
value, ((value >> (218 - 208)) & 0xf), readl(APBS_REG_BASE + APBS_REG_2));
asr_auxadc->fuse_data.auxadc_gain_offset = (value >> (208 - 208)) & 0x1f; /* 5 bits */
asr_auxadc->fuse_data.auxadc_gain_error = (value >> (213 - 208)) & 0x1f; /* 5 bits */
} else {
value = readl(GEU_REG_BASE + FUSE_BANK3_223_192);
printf("fs-192: %08X\n", value);
asr_auxadc->fuse_data.auxadc_gain_offset = (value >> 27) & 0x1f; /* 5 bits */
value = readl(GEU_REG_BASE + FUSE_BANK3_255_224);
printf("fs-224: %08X\n", value);
asr_auxadc->fuse_data.auxadc_gain_error = (value >> 0) & 0x1f; /* 5 bits */
}
asr_auxadc->fuse_data.fuse_bits = 5;
asr_auxadc->fuse_data.fuse_mask_data = 0xf;
asr_auxadc->fuse_data.fuse_mask_all = 0x1f;
printf("auxadc fusedata: %03x %03x, %08X\n",
asr_auxadc->fuse_data.auxadc_gain_offset,
asr_auxadc->fuse_data.auxadc_gain_error,
readl(APBS_REG_BASE + 0x104));
}
return 0;
}
#endif
static int asr_auxadc_base_init(void)
{
u32 value;
void __iomem *apbs_base = APBS_REG_BASE;
printf("asraux adc init, ");
g_auxadc = malloc(sizeof(struct asr_auxadc));
if (g_auxadc == NULL) {
printf("g_auxadc malloc failed\n");
return -ENOMEM;
}
memset(g_auxadc, 0x0, sizeof(struct asr_auxadc));
g_auxadc->base = AUX_REG_BASE;
#ifdef CONFIG_ASR1901
writel(0x5, AUXADC_CLK_CTRL);
udelay(10);
writel(0x1, AUXADC_CLK_CTRL);
#else
if (cpu_is_asr1826s() || cpu_is_asr1903())
g_auxadc->adc_ctrl_reg = APBS_REG_BASE + APBS_REG_3;
else
g_auxadc->adc_ctrl_reg = APBS_REG_BASE + APBS_REG_12;
writel(0x3, AUXADC_CLK_CTRL);
udelay(10);
writel(0x1, AUXADC_CLK_CTRL);
#endif
asr_auxadc_fusedata_init(g_auxadc);
if (cpu_is_asr1806()) {
value = readl(g_auxadc->adc_ctrl_reg);
value &= ~(0xffff0000);
value |= (0x1060 << 16); /* div4 and 2clks sample delay */
writel(value, g_auxadc->adc_ctrl_reg);
} else if (cpu_is_asr1903() || cpu_is_asr1826s()) {
value = readl(g_auxadc->adc_ctrl_reg);
value |= (0x1 << 22);
if (cpu_is_asr1826s())
value |= (0x3 << 24);
writel(value, g_auxadc->adc_ctrl_reg);
#ifdef CONFIG_ASR1901
} else if (cpu_is_asr1901() || cpu_is_asr1906()) {
value = readl(g_auxadc->base + OLD_AUXADC_REG_CFG);
value &= ~(0x1 << 19);
writel(value, g_auxadc->base + OLD_AUXADC_REG_CFG);
#endif
}
printf("done!\n");
return 0;
}
#ifdef CONFIG_OLD_AUXADC
int __extern_get_auxadc_volt(int adc_id)
{
u32 value;
u8 adc_channel;
int timeout, out_value, raw_value = 0;
void __iomem *base = g_auxadc->base;
int nr_avg = 0, sample_index = 0, nr_total_samples = (16 + 2);
int raw_min = 0xfffffff, raw_max = 0;
adc_channel = (adc_id - ASR_AUXADC1) & 0xf;
/* step 1. powerup adc */
value = readl(base + OLD_AUXADC_REG_CTRL2);
value |= (0x1 << 6);
writel(value, base + OLD_AUXADC_REG_CTRL2);
udelay(20);
/* step 2. clear CTRL and INT STATUS */
while (sample_index < nr_total_samples) {
writel(0x0, base + OLD_AUXADC_REG_CTRL);
writel(0x3ff, base + OLD_AUXADC_REG_INT_STATUS);
udelay(50);
/* step 3. start SOC */
value = readl(base + OLD_AUXADC_REG_CTRL);
value |= (0x1 | (0x1 << (adc_channel + 1)) | (0x1 << (adc_channel + 16)));
writel(value, base + OLD_AUXADC_REG_CTRL);
/* step 4. polling int status */
timeout = 1000;
while ((readl(base + OLD_AUXADC_REG_INT_STATUS) == 0) && timeout--)
udelay(1);
if (timeout <= 0) {
printf("aux adc%d timeout: 0x%x 0x%x\n",
adc_channel, readl(base + OLD_AUXADC_REG_CTRL), readl(base + OLD_AUXADC_REG_CFG));
out_value = -EINVAL;
goto err_out;
}
if (sample_index >= 2) {
out_value = readl(base + OLD_AUXADC_REG_DATA + (adc_channel << 2)) & 0xFFF;
if (raw_min > out_value)
raw_min = out_value;
if (raw_max < out_value)
raw_max = out_value;
raw_value += out_value;
nr_avg++;
}
sample_index++;
}
raw_value -= (raw_max + raw_min);
raw_value = raw_value / (nr_avg - 2);
debug("timeout: %d, raw_value: %x 0x%x\n", timeout, raw_value, readl(g_auxadc->base + OLD_AUXADC_REG_INT_STATUS));
if ((0x1 << 11) & g_auxadc->fuse_data.auxadc_gain_error)
raw_value = raw_value * (16384 - (1 * ((0x1 << 12) - ((g_auxadc->fuse_data.auxadc_gain_error & 0xfff)))));
else
raw_value = raw_value * (16384 + (1 * (g_auxadc->fuse_data.auxadc_gain_error & 0x7ff)));
raw_value = ((raw_value * 24) >> 12) * 50;
if ((0x1 << 11) & g_auxadc->fuse_data.auxadc_gain_offset)
raw_value = raw_value - (328 * ((0x1 << 12) - (g_auxadc->fuse_data.auxadc_gain_offset & 0xfff)));
else
raw_value = raw_value + (328 * (g_auxadc->fuse_data.auxadc_gain_offset & 0x7ff));
if (raw_value < 0) {
printf("aux neg: %d\n", raw_value);
raw_value = 0;
}
out_value = (raw_value >> 14);
err_out:
writel(0x0, base + OLD_AUXADC_REG_CTRL);
writel(0x3ff, base + OLD_AUXADC_REG_INT_STATUS);
/* power off adc */
value = readl(base + OLD_AUXADC_REG_CTRL2);
value &= ~(0x1 << 6);
writel(value, base + OLD_AUXADC_REG_CTRL2);
return out_value;
}
#else
int asr1826s_calc_adc_val(int raw_value)
{
int div_value;
if ((0x1 << (g_auxadc->fuse_data.fuse_bits - 1)) & g_auxadc->fuse_data.auxadc_gain_offset)
raw_value = raw_value + ((0x1 << g_auxadc->fuse_data.fuse_bits) - (g_auxadc->fuse_data.auxadc_gain_offset & g_auxadc->fuse_data.fuse_mask_all));
else
raw_value = raw_value - ((g_auxadc->fuse_data.auxadc_gain_offset & g_auxadc->fuse_data.fuse_mask_data));
if ((0x1 << (g_auxadc->fuse_data.fuse_bits - 1)) & g_auxadc->fuse_data.auxadc_gain_error)
div_value = (4800 + (((0x1 << g_auxadc->fuse_data.fuse_bits) - ((g_auxadc->fuse_data.auxadc_gain_error & g_auxadc->fuse_data.fuse_mask_all)))));
else
div_value = (4800 - ((g_auxadc->fuse_data.auxadc_gain_error & g_auxadc->fuse_data.fuse_mask_data)));
raw_value = (raw_value * 4800 * 60) >> 12;
raw_value = (raw_value * 20) / div_value;
if (raw_value < 0) {
printf("aux neg: %d\n", raw_value);
raw_value = 0;
}
return raw_value;
}
int __extern_get_auxadc_volt(int adc_id)
{
u32 value;
u8 adc_channel;
int timeout, out_value, raw_value = 0;
void __iomem *apbs_base = APBS_REG_BASE;
int nr_avg = 0, sample_index = 0, nr_total_samples = (3 + 16);
int raw_min = 0xfffffff, raw_max = 0;
/* step 1. powerup adc*/
value = readl(g_auxadc->adc_ctrl_reg);
if (value == 0)
BUG();
value |= (0x1 << 8);
writel(value, g_auxadc->adc_ctrl_reg);
if (cpu_is_asr1826s())
udelay(20);
adc_channel = (adc_id - ASR_AUXADC1 + 1) & 0x1f;
while (sample_index < nr_total_samples) {
/*
* step 2. set adc channel, clr soc and continous mode
* clear INT STATUS
*/
value = readl(g_auxadc->adc_ctrl_reg);
if (value == 0)
BUG();
value &= ~(0x7F << 9);
value |= (adc_channel << 11);
writel(value, g_auxadc->adc_ctrl_reg);
if (!cpu_is_asr1826s())
writel(0x1, g_auxadc->base + AUX_INT_CLR_REG);
/* clear the data reg */
if (cpu_is_asr1826s())
writel(0x0, g_auxadc->base + AUX_REG_DATA + (0 << 2));
/* step 3. set soc */
value = readl(g_auxadc->adc_ctrl_reg);
if (value == 0)
BUG();
value |= (0x1 << 9);
writel(value, g_auxadc->adc_ctrl_reg);
if (cpu_is_asr1826s()) {
/* step 4. polling adc value */
timeout = 10;
while (((readl(g_auxadc->base + AUX_REG_DATA + (0 << 2)) & 0xFFF0000) == 0) && (timeout--))
udelay(1);
if (timeout <= 0) {
printf("aux adc%d timeout: 0x%x\n", adc_channel, readl(g_auxadc->base + AUX_REG_DATA + (0 << 2)));
}
} else {
/* step 4. polling int status */
timeout = 1000;
while ((readl(g_auxadc->base + AUX_INT_STS_REG) == 0) && timeout--)
udelay(1);
if (timeout <= 0) {
printf("aux adc%d timeout: 0x%x\n",
adc_channel, readl(g_auxadc->adc_ctrl_reg));
out_value = -EINVAL;
goto err_out;
}
}
if (sample_index >= 3) {
if (cpu_is_asr1826s())
out_value = (readl(g_auxadc->base + AUX_REG_DATA + (0 << 2)) >> 16) & 0xFFF;
else
out_value = readl(g_auxadc->base + AUX_REG_DATA + (0 << 2)) & 0xFFF;
if (raw_min > out_value)
raw_min = out_value;
if (raw_max < out_value)
raw_max = out_value;
raw_value += out_value;
nr_avg++;
}
sample_index++;
}
raw_value -= (raw_max + raw_min);
raw_value = raw_value / (nr_avg - 2);
debug("timeout: %d, raw_value: %x 0x%x\n", timeout, raw_value, readl(g_auxadc->base + AUX_INT_STS_REG));
if (cpu_is_asr1826s()) {
out_value = asr1826s_calc_adc_val(raw_value);
goto err_out;
}
if ((0x1 << (g_auxadc->fuse_data.fuse_bits - 1)) & g_auxadc->fuse_data.auxadc_gain_error)
raw_value = raw_value * (6000 - (10 * ((0x1 << g_auxadc->fuse_data.fuse_bits) - ((g_auxadc->fuse_data.auxadc_gain_error & g_auxadc->fuse_data.fuse_mask_all)))));
else
raw_value = raw_value * (6000 + (10 * (g_auxadc->fuse_data.auxadc_gain_error & g_auxadc->fuse_data.fuse_mask_data)));
if ((0x1 << (g_auxadc->fuse_data.fuse_bits - 1)) & g_auxadc->fuse_data.auxadc_gain_offset)
raw_value = raw_value - (12000 * ((0x1 << g_auxadc->fuse_data.fuse_bits) - (g_auxadc->fuse_data.auxadc_gain_offset & g_auxadc->fuse_data.fuse_mask_all)));
else
raw_value = raw_value + (12000 * (g_auxadc->fuse_data.auxadc_gain_offset & g_auxadc->fuse_data.fuse_mask_data));
if (raw_value < 0) {
printf("aux neg: %d\n", raw_value);
raw_value = 0;
}
out_value = (raw_value >> 12) / 5;
err_out:
if (!cpu_is_asr1826s())
writel(0x1, g_auxadc->base + AUX_INT_CLR_REG);
/* power off adc */
value = readl(g_auxadc->adc_ctrl_reg);
if (value == 0)
BUG();
value &= ~(0xff << 8);
writel(value, g_auxadc->adc_ctrl_reg);
return out_value;
}
#endif
int auxadc_get_gpadc_volt(int gpadc_id)
{
return __extern_get_auxadc_volt(gpadc_id);
}
#endif
#ifdef CONFIG_ASR1901
u8 pmic_reg_raw_read(u8 addr, u8 reg)
{
int timeout;
u8 reg_val = 0x0;
u32 i2c_base = 0xd4018800;
writel(0x00000000, (i2c_base + 0x00));
writel(0x00000000, (i2c_base + 0x08));
writel(0x00206000, (i2c_base + 0x00));
writel(addr, (i2c_base + 0x0c));
writel(0x00206009, (i2c_base + 0x00));
timeout = 100000;
while (!(readl(i2c_base + 0x04) & (0x80000)) && timeout--);
writel((readl(i2c_base + 0x04) | 0x80000), (i2c_base + 0x04));
writel(reg, (i2c_base + 0x0c));
writel(0x00206008, (i2c_base + 0x00));
timeout = 100000;
while (!(readl(i2c_base + 0x04) & (0x80000)) && timeout--);
writel((readl(i2c_base + 0x04) | 0x80000), (i2c_base + 0x04));
writel((addr + 1), (i2c_base + 0x0c));
writel(0x00206009, (i2c_base + 0x00));
timeout = 100000;
while (!(readl(i2c_base + 0x04) & (0x80000)) && timeout--);
writel((readl(i2c_base + 0x04) | 0x80000), (i2c_base + 0x04));
writel(0x0020600E, (i2c_base + 0x00));
timeout = 100000;
while (!(readl(i2c_base + 0x04) & (0x100000)) && timeout--);
reg_val = readl(i2c_base + 0x0c);
writel((readl(i2c_base + 0x04) | 0x100000), (i2c_base + 0x04));
writel(0x00000000, (i2c_base + 0x00));
return reg_val;
}
static void pmic_reg_raw_write(u8 addr, u8 reg, u8 val)
{
int timeout;
u32 i2c_base = 0xd4018800;
writel(0x00000000, (i2c_base + 0x00));
writel(0x00000000, (i2c_base + 0x08));
writel(0x00206000, (i2c_base + 0x00));
writel(addr, (i2c_base + 0x0c));
writel(0x00206009, (i2c_base + 0x00));
timeout = 100000;
while (!(readl(i2c_base + 0x04) & (0x80000)) && timeout--);
writel((readl(i2c_base + 0x04) | 0x80000), (i2c_base + 0x04));
writel(reg, (i2c_base + 0x0c));
writel(0x00206008, (i2c_base + 0x00));
timeout = 100000;
while (!(readl(i2c_base + 0x04) & (0x80000)) && timeout--);
writel((readl(i2c_base + 0x04) | 0x80000), (i2c_base + 0x04));
writel(val, (i2c_base + 0x0c));
writel(0x0020600A, (i2c_base + 0x00));
timeout = 100000;
while (!(readl(i2c_base + 0x04) & (0x80000)) && timeout--);
writel((readl(i2c_base + 0x04) | 0x80000), (i2c_base + 0x04));
writel(0x00000000, (i2c_base + 0x00));
}
#else
u8 pmic_reg_raw_read(u8 addr, u8 reg)
{
int timeout;
u8 reg_val = 0x0;
#if defined(CONFIG_ASR1802S)
u32 i2c_base = 0xd4037000;
#elif defined(CONFIG_PXA182X)
u32 i2c_base = 0xd4010800;
#else
#error "I2C ADDR NOT DEFINED!!!"
#endif
writel(0x00000000, (i2c_base + 0x10));
writel(0x00000000, (i2c_base + 0x20));
writel(0x000000e0, (i2c_base + 0x10));
writel(addr, (i2c_base + 0x08));
writel(0x000000E9, (i2c_base + 0x10));
timeout = 100000;
while (!(readl(i2c_base + 0x18) & (0x40)) && timeout--);
writel((readl(i2c_base + 0x18) | 0x40), (i2c_base + 0x18));
writel(reg, (i2c_base + 0x08));
writel(0x000000E8, (i2c_base + 0x10));
timeout = 100000;
while (!(readl(i2c_base + 0x18) & (0x40)) && timeout--);
writel((readl(i2c_base + 0x18) | 0x40), (i2c_base + 0x18));
writel((addr + 1), (i2c_base + 0x08));
writel(0x000000E9, (i2c_base + 0x10));
timeout = 100000;
while (!(readl(i2c_base + 0x18) & (0x40)) && timeout--);
writel((readl(i2c_base + 0x18) | 0x40), (i2c_base + 0x18));
writel(0x000000EE, (i2c_base + 0x10));
timeout = 100000;
while (!(readl(i2c_base + 0x18) & (0x80)) && timeout--);
reg_val = readl(i2c_base + 0x08);
writel((readl(i2c_base + 0x18) | 0x80), (i2c_base + 0x18));
writel(0x00000000, (i2c_base + 0x10));
return reg_val;
}
static void pmic_reg_raw_write(u8 addr, u8 reg, u8 val)
{
int timeout;
#if defined(CONFIG_ASR1802S)
u32 i2c_base = 0xd4037000;
#elif defined(CONFIG_PXA182X)
u32 i2c_base = 0xd4010800;
#else
#error "I2C ADDR NOT DEFINED!!!"
#endif
writel(0x00000000, (i2c_base + 0x10));
writel(0x00000000, (i2c_base + 0x20));
writel(0x000000E0, (i2c_base + 0x10));
writel(addr, (i2c_base + 0x08));
writel(0x000000E9, (i2c_base + 0x10));
timeout = 100000;
while (!(readl(i2c_base + 0x18) & (0x40)) && timeout--);
writel((readl(i2c_base + 0x18) | 0x40), (i2c_base + 0x18));
writel(reg, (i2c_base + 0x08));
writel(0x000000E8, (i2c_base + 0x10));
timeout = 100000;
while (!(readl(i2c_base + 0x18) & (0x40)) && timeout--);
writel((readl(i2c_base + 0x18) | 0x40), (i2c_base + 0x18));
writel(val, (i2c_base + 0x08));
writel(0x000000EA, (i2c_base + 0x10));
timeout = 100000;
while (!(readl(i2c_base + 0x18) & (0x40)) && timeout--);
writel((readl(i2c_base + 0x18) | 0x40), (i2c_base + 0x18));
writel(0x00000000, (i2c_base + 0x10));
}
#endif
/* This is called from init_sequence of arch/arm/lib/board.c */
int pmic_32khz_early_init(void)
{
u8 regval, pmic_id = 0x0;
/* firstly read PMIC id */
pmic_id = g_pmic_id = pmic_reg_raw_read(0x60, 0x0);
/* only for PM802(s) */
if ((pmic_id >= 0x10 && pmic_id < 0x14) || (pmic_id == 0x08 || pmic_id == 0x09 || g_pmic_id == 0x0A)
|| (pmic_id == 0x3b) || (pmic_id == 0x21) || (pmic_id == 0x20)) {
/* enable 32khz clk */
regval = pmic_reg_raw_read(0x60, 0xe4);
regval &= ~(0x3 << 2);
regval |= (0x1 << 2);
pmic_reg_raw_write(0x60, 0xe4, regval);
/* disable sleep mode */
regval = pmic_reg_raw_read(0x62, 0x22);
regval |= (0x3 << 3);
/*
* set ilimt OTP value to 0x0:
* confirmed with PMIC DE that pm802 b0/b1 buck1 ilim OTP value
* should be set as 0x0, and we just hard code it here.
* Maybe there is B2 etc stepping in the future, we should also
* confirm with DE again for this value
*/
regval &= ~(0x7);
pmic_reg_raw_write(0x62, 0x22, regval);
}
#if defined(CONFIG_FG_PM803) || defined(CONFIG_PM803_GPADC)
if (pmic_id >= 0x18 && pmic_id < 0x1f) {
/* set buck1 asr 0.95v for tiny dsp */
pmic_reg_raw_write(0x62, 0x20, 0x9C);
pmic_reg_raw_write(0x62, 0x2B, 0x1C);
pmic_reg_raw_write(0x62, 0x2C, 0x1C);
pmic_reg_raw_write(0x62, 0x2D, 0x1C);
pmic_reg_raw_write(0x62, 0x2E, 0x1C);
}
#endif
return 0;
}
int pmic_is_pm812(void)
{
if (g_pmic_id == 0x64)
return 1;
else
return 0;
}
int pmic_is_pm801(void)
{
if (g_pmic_id == 0x69)
return 1;
else
return 0;
}
int pmic_is_pm802(void)
{
if ((g_pmic_id >= 0x10 && g_pmic_id < 0x14) || g_pmic_id == 0x08 || g_pmic_id == 0x09 || g_pmic_id == 0x0A)
return 1;
else
return 0;
}
int pmic_is_pm802s(void)
{
if (g_pmic_id == 0x08 || g_pmic_id == 0x09 || g_pmic_id == 0x0A)
return 1;
else
return 0;
}
int pmic_is_pm803(void)
{
if (g_pmic_id >= 0x18 && g_pmic_id < 0x1f)
return 1;
else
return 0;
}
int pmic_is_pm813(void)
{
if (g_pmic_id == 0x21 || g_pmic_id == 0x20 || g_pmic_id == 0x3b)
return 1;
else
return 0;
}
int pmic_is_pm813s(void)
{
if (g_pmic_id == 0x21 || g_pmic_id == 0x20)
return 1;
else
return 0;
}
int pmic_is_pm813_a2a3(void)
{
if (g_pmic_id == 0x3b)
return 1;
else
return 0;
}
void pmic_default_powerdown(struct pmic *p_base)
{
pmic_clear_pdown_log();
pmic_reg_write(p_base, PMIC_WAKE_UP, PMIC_SW_PDOWN);
}
void pmic_default_reset_bd(struct pmic *p_base)
{
pmic_reg_write(p_base, 0x0d, 0x20);
}
static u8 pmic_marvell_get_chip_id(u8 bus, u8 reg)
{
u8 data = 0, old_bus;
int ret;
old_bus = i2c_get_bus_num();
debug("---%s: old_bus = 0x%x\n", __func__, old_bus);
if (old_bus != bus)
i2c_set_bus_num(bus);
/* suppose all of the Marvell PMIC base page addres is 0x30 */
ret = i2c_read(0x30, reg, 1, &data, 1);
if (old_bus != bus)
i2c_set_bus_num(old_bus);
if (ret < 0)
return 0;
else
return data;
}
int pmic_marvell_register(unsigned char bus, struct pmic_chip_desc *chip)
{
int ret = 0;
#ifdef CONFIG_AUXADC
asr_auxadc_base_init();
#endif
if (!chip) {
printf("%s: chip desc empty!\n", __func__);
return -EINVAL;
}
/* set default reset bd function */
chip->reset_bd = pmic_default_reset_bd;
switch (chip->chip_id) {
#ifdef CONFIG_POWER_88PM800
case 0x3:
/* 88pm800 */
ret = pmic_88pm800_alloc(bus, chip);
if (ret < 0)
goto out;
ret = pmic_88pm800_init(chip);
if (ret < 0)
goto out;
break;
#endif
#ifdef CONFIG_POWER_88PM820
case 0x4:
/* 88pm822 */
ret = pmic_88pm820_alloc(bus, chip);
if (ret < 0)
goto out;
ret = pmic_88pm820_init(chip);
if (ret < 0)
goto out;
break;
#endif
#ifdef CONFIG_POWER_88PM801
case 0x69:
case 0x64:
case 0x10:
case 0x11:
case 0x12:
case 0x13:
case 0x14:
case 0x08:
case 0x09:
case 0x0A:
case 0x18:
case 0x19:
case 0x1A:
case 0x1B:
case 0x20:
case 0x21:
case 0x3B:
/* 88pm800 */
ret = pmic_88pm801_alloc(bus, chip);
if (ret < 0)
goto out;
ret = pmic_88pm801_init(chip);
if (ret < 0)
goto out;
break;
#endif
#ifdef CONFIG_POWER_88PM860
case 0x90:
case 0x91:
/* 88pm860 */
ret = pmic_88pm860_alloc(bus, chip);
if (ret < 0)
goto out;
ret = pmic_88pm860_init(chip);
if (ret < 0)
goto out;
break;
#endif
#ifdef CONFIG_POWER_88PM886
case 0x00:
case 0xa1:
/* 88pm886 */
ret = pmic_88pm886_alloc(bus, chip);
if (ret < 0)
goto out;
ret = pmic_88pm886_init(chip);
if (ret < 0)
goto out;
break;
#endif
#ifdef CONFIG_POWER_88PM880
case 0xb0:
/* 88pm880 */
ret = pmic_88pm880_alloc(bus, chip);
if (ret < 0)
goto out;
ret = pmic_88pm880_init(chip);
if (ret < 0)
goto out;
break;
#endif
default:
printf("%s: unknown PMIC: 0x%x\n",
__func__, chip->chip_id);
ret = -EINVAL;
break;
}
out:
if (ret < 0)
printf("%s: pmic: 0x%x fails\n", __func__, chip->chip_id);
return ret;
}
#if defined(CONFIG_FG_PM803) || defined(CONFIG_PM803_GPADC)
void pm803_gpadc_calibration_init(void)
{
if (pmic_is_pm803()) {
/* update adc/vbat pair based on calibration data */
asr1803_adc_caldata_init(adc0_vbat_def_pair, adc1_vbat_def_pair);
/* get_rtp_caldata(&rtp_adc_code1, &rtp_adc_code2); */
printf("0:[%d-%d] 1:[%d-%d] 2:[%d-%d] 3:[%d-%d] 4:[%d-%d]\n"
"5:[%d-%d] 6:[%d-%d] 7:[%d-%d] 8:[%d-%d] 9:[%d-%d]\n",
adc0_vbat_def_pair[0].adc, adc0_vbat_def_pair[0].vbat,
adc0_vbat_def_pair[1].adc, adc0_vbat_def_pair[1].vbat,
adc0_vbat_def_pair[2].adc, adc0_vbat_def_pair[2].vbat,
adc0_vbat_def_pair[3].adc, adc0_vbat_def_pair[3].vbat,
adc0_vbat_def_pair[4].adc, adc0_vbat_def_pair[4].vbat,
adc0_vbat_def_pair[5].adc, adc0_vbat_def_pair[5].vbat,
adc0_vbat_def_pair[6].adc, adc0_vbat_def_pair[6].vbat,
adc0_vbat_def_pair[7].adc, adc0_vbat_def_pair[7].vbat,
adc0_vbat_def_pair[8].adc, adc0_vbat_def_pair[8].vbat,
adc0_vbat_def_pair[9].adc, adc0_vbat_def_pair[9].vbat);
printf("0:[%d-%d] 1:[%d-%d] 2:[%d-%d] 3:[%d-%d] 4:[%d-%d]\n"
"5:[%d-%d] 6:[%d-%d] 7:[%d-%d] 8:[%d-%d] 9:[%d-%d]\n",
adc1_vbat_def_pair[0].adc, adc1_vbat_def_pair[0].vbat,
adc1_vbat_def_pair[1].adc, adc1_vbat_def_pair[1].vbat,
adc1_vbat_def_pair[2].adc, adc1_vbat_def_pair[2].vbat,
adc1_vbat_def_pair[3].adc, adc1_vbat_def_pair[3].vbat,
adc1_vbat_def_pair[4].adc, adc1_vbat_def_pair[4].vbat,
adc1_vbat_def_pair[5].adc, adc1_vbat_def_pair[5].vbat,
adc1_vbat_def_pair[6].adc, adc1_vbat_def_pair[6].vbat,
adc1_vbat_def_pair[7].adc, adc1_vbat_def_pair[7].vbat,
adc1_vbat_def_pair[8].adc, adc1_vbat_def_pair[8].vbat,
adc1_vbat_def_pair[9].adc, adc1_vbat_def_pair[9].vbat);
}
}
#endif
int pmic_marvell_init(unsigned char bus, struct pmic_chip_desc *chip)
{
int ret;
if (!chip) {
printf("%s: empty pmic ptr!\n", __func__);
return -EINVAL;
}
/* suppose all of the chip id register is 0x0, base page */
g_pmic_id = chip->chip_id = pmic_marvell_get_chip_id(bus, 0x0);
ret = pmic_marvell_register(bus, chip);
if (ret < 0)
printf("%s: pmic: 0x%x init fails.\n", __func__, chip->chip_id);
return ret;
}
void pmic_reset_bd(struct pmic_chip_desc *chip)
{
u32 data;
struct pmic *p_base, *p_test;
p_base = pmic_get(chip->base_name);
if (!p_base || pmic_probe(p_base)) {
printf("access pmic failed...\n");
return;
}
/* pm801, pm812 */
if (0x64 == chip->chip_id || 0x69 == chip->chip_id) {
/* SMPL wkrd: disable it */
pmic_reg_write(p_base, 0x1f, 0x01);
p_test = pmic_get(chip->test_name);
if (!p_test || pmic_probe(p_test)) {
printf("access test pg failed...\n");
return;
}
pmic_reg_write(p_test, 0x50, 0xe7);
pmic_reg_write(p_test, 0x51, 0x0d);
pmic_reg_write(p_test, 0x58, 0x00);
if (!p_base || pmic_probe(p_base)) {
printf("access pmic failed...\n");
return;
}
pmic_reg_write(p_base, 0x1f, 0x00);
}
if (pmic_is_pm803() || pmic_is_pm813s()) {
pmic_reg_read(p_base, 0xe7, &data);
data |= (0x1 << 0);
pmic_reg_write(p_base, 0xe7, data);
data |= (0x1 << 1);
pmic_reg_write(p_base, 0xe7, data);
} else if (pmic_is_pm813_a2a3()) {
pmic_reg_read(p_base, 0xe7, &data);
data |= (0x1 << 0);
pmic_reg_write(p_base, 0xe7, data);
data |= (0x1 << 3);
pmic_reg_write(p_base, 0xe7, data);
} else {
/* 1.Enable FAULT_WU and FAULT_WU_EN */
pmic_reg_read(p_base, 0xe7, &data);
data |= (0x1 << 2);
pmic_reg_write(p_base, 0xe7, data);
data |= (0x1 << 3);
pmic_reg_write(p_base, 0xe7, data);
}
/* pm801, pm812 */
if (0x60 == (chip->chip_id & 0xf0)) {
/* 2.Config short TO and Enable WDT
* to guaranty the quick-restart
* TO = WD_TIMER_ACT[5:3]: 000=1024ms or 001=2048ms
*/
data = 1 << 3;
pmic_reg_write(p_base, 0x0e, data);
data = 0x00;
pmic_reg_write(p_base, 0x1d, data);
} else {
/*
* The minimum value for discharge should be 1s per PMIC DE
*/
pmic_reg_read(p_base, 0xe2, &data);
data &= ~(0xf << 0);
if (pmic_is_pm813s() || pmic_is_pm802s())
data |= (0x3 << 0);
else
data |= (0x1 << 0);
pmic_reg_write(p_base, 0xe2, data);
pmic_reg_read(p_base, 0xe4, &data);
data &= ~(0x1 << 1);
pmic_reg_write(p_base, 0xe4, data);
}
/* 3.Issue SW power down */
data = 0x20;
pmic_reg_write(p_base, 0x0d, data);
/* Rebooting... */
}
static void pmic_read_bankup_pdown_log(struct pmic *p_base, u32 *powerD_l1, u32 *powerD_l2)
{
if (pmic_is_pm803()) {
pmic_reg_read(p_base, PM803_BASE_BLANK_REG7, powerD_l1);
pmic_reg_read(p_base, PM803_BASE_BLANK_REG8, powerD_l2);
} else if (pmic_is_pm802s()) {
pmic_reg_read(p_base, PM802S_BASE_BLANK_REGE, powerD_l1);
pmic_reg_read(p_base, PM802S_BASE_BLANK_REGF, powerD_l2);
} else if (pmic_is_pm813s()) {
pmic_reg_read(p_base, PM813S_BASE_BLANK_REGE, powerD_l1);
pmic_reg_read(p_base, PM813S_BASE_BLANK_REGF, powerD_l2);
} else {
printf("!!!warning: powerup log not in bankup\n");
}
}
/* get_powerup_down_log(void) function do following things:
* save power up/down log in DDR for debug,
* print them out
*/
void get_powerup_down_log(struct pmic_chip_desc *chip)
{
u32 val, powerup_l = 0, powerD_l1 = 0, powerD_l2 = 0, bit, rtc_misc5, bat_rm_timer;
struct pmic *p_base;
int pdown_log_is_saved = 0;
char *powerup_name[8] = {
"ONKEY_WKP ",
"CHG_WKP ",
"EXTON_WAKUP",
#if (defined CONFIG_POWER_88PM886) || (defined CONFIG_POWER_88PM880)
"SMPL_WU_LOG",
#else
"RSVD ",
#endif
"RTC_ALM_WKP",
"FLT_WKP ",
"BAT_WKP ",
#ifdef CONFIG_POWER_88PM880
"WCHG_WAKEUP",
#else
"RSVD ",
#endif
};
char *powerD1_name[8] = {
"OVER_TEMP ",
#if (defined CONFIG_POWER_88PM886) || (defined CONFIG_POWER_88PM880)
"UV_VANA5 ",
#else
"UV_VSYS1 ",
#endif
"SW_PWDWN ",
"FL_ALARM ",
"WD ",
"LONG_ONKEY ",
"OV_VSYS ",
"RTC_RESET "
};
char *powerD2_name[6] = {
"HYB_DONE ",
#if (defined CONFIG_POWER_88PM886) || (defined CONFIG_POWER_88PM880)
"UV_VBAT ",
#else
"UV_VSYS2 ",
#endif
#ifdef CONFIG_POWER_88PM880
"HW_RESET2 ",
#else
"HW_RESET ",
#endif
"PGOOD_PDOWN",
"LONKEY_RTC ",
#ifdef CONFIG_POWER_88PM880
"HW_RESET1 ",
#else
"RSVD ",
#endif
};
p_base = pmic_get(chip->base_name);
if (!p_base || pmic_probe(p_base)) {
printf("access pmic failed...\n");
return;
}
/*
* dump power up/down log
* save the power down log registers in pmic rtc expire registers
*/
pmic_reg_read(p_base, POWER_UP_LOG, &powerup_l);
pmic_reg_read(p_base, POWER_DOWN_LOG1, &powerD_l1);
pmic_reg_read(p_base, POWER_DOWN_LOG2, &powerD_l2);
if (powerD_l1 == 0 && powerD_l2 == 0) {
printf("!!!power down log in bankup regs\n");
pmic_read_bankup_pdown_log(p_base, &powerD_l1, &powerD_l2);
pdown_log_is_saved = 1;
}
if (pmic_is_pm803()) {
pmic_reg_read(p_base, PM803_DUMMY_REG0, &pm803_dummy_reg0);
printf("pm803 dummy0: 0x%02x\n", pm803_dummy_reg0);
}
smpl_reboot_flag = 0;
if ((chip->chip_id & 0xF0) == 0x60) {
pmic_reg_read(p_base, 0xe7, &rtc_misc5);
printf("rtc_misc5: 0x%02x\n", rtc_misc5);
bat_rm_timer = (rtc_misc5 & 0xf0) >> 4;
/*remove time: 125ms * x */
if (bat_rm_timer != 0 && bat_rm_timer < 0x6 &&
(powerD_l1 & 0x3) != 0x3)
smpl_reboot_flag = 1;
rtc_misc5 &= 0x0f;
pmic_reg_write(p_base, 0xe7, rtc_misc5);
}
printf("P_UP LOG:0x%x\n", powerup_l);
for (bit = 0; bit < 8; bit++)
printf("%s:%1d\n", powerup_name[bit], (powerup_l >> bit) & 1);
printf("-----------------\n");
/*printf(" ------------------------------------\n");
printf("| name(power up) | status |\n");
printf("|-------------------------|----------|\n");
for (bit = 0; bit < 8; bit++)
printf("| %s | %x |\n", powerup_name[bit], (powerup_l >> bit) & 1);
printf(" ------------------------------------\n"); */
printf("P_Down LOG1:0x%x\n", powerD_l1);
for (bit = 0; bit < 8; bit++)
printf("%s:%1d\n", powerD1_name[bit], (powerD_l1 >> bit) & 1);
printf("-----------------\n");
/* printf(" -------------------------------\n");
printf("| name(power down1) | status |\n");
printf("|--------------------|----------|\n");
for (bit = 0; bit < 8; bit++)
printf("| %s | %x |\n", powerD1_name[bit], (powerD_l1 >> bit) & 1);
printf(" -------------------------------\n"); */
printf("P_Down LOG2:0x%x\n", powerD_l2);
for (bit = 0; bit < 6; bit++)
printf("%s:%1d\n", powerD2_name[bit], (powerD_l2 >> bit) & 1);
printf("-----------------\n");
/*printf(" -------------------------------\n");
printf("| name(power down2) | status |\n");
printf("|--------------------|----------|\n");
for (bit = 0; bit < 6; bit++)
printf("| %s | %x |\n", powerD2_name[bit], (powerD_l2 >> bit) & 1);
printf(" -------------------------------\n"); */
printf("smpl: %d\n", smpl_reboot_flag);
/* write power up/down log to DDR*/
val = powerup_l | (powerD_l1 << 8) | (powerD_l2 << 16);
pmic_power_status = val;
/* store the pdown log */
if (pdown_log_is_saved == 0) {
if (pmic_is_pm803()) {
pmic_reg_write(p_base, PM803_BASE_BLANK_REG7, powerD_l1);
pmic_reg_write(p_base, PM803_BASE_BLANK_REG8, powerD_l2);
} else if (pmic_is_pm802s()) {
pmic_reg_write(p_base, PM802S_BASE_BLANK_REGE, powerD_l1);
pmic_reg_write(p_base, PM802S_BASE_BLANK_REGF, powerD_l2);
} else if (pmic_is_pm813s()) {
pmic_reg_write(p_base, PM813S_BASE_BLANK_REGE, powerD_l1);
pmic_reg_write(p_base, PM813S_BASE_BLANK_REGF, powerD_l2);
}
}
}
enum sys_boot_up_reason get_boot_up_reason(u32 *emmd_pmic_addr)
{
u32 pmic_log = *emmd_pmic_addr;
/* [power down log2: 0xe6][power down log1: 0xe5][power up log: 0x10] */
if (!(pmic_log & 0x1eff00)) {
if (!pmic_is_pm803())
return SYS_BR_REBOOT;
else if((pm803_dummy_reg0 & 0xf0) == PM803_REBOOT_FLAG)
return SYS_BR_REBOOT;
}
/* get power up log */
pmic_log &= 0xff;
if (pmic_is_pm803()) {
switch (pmic_log) {
case 0x1: return SYS_BR_ONKEY;
case 0x2: return SYS_BR_CHARGE;
case 0x4: return SYS_BR_RTC_ALARM;
case 0x8: return SYS_BR_BAT_WAKEUP;
case 0x10: return SYS_BR_FAULT_WAKEUP;
default: return SYS_BR_POWER_OFF;
}
}
switch (pmic_log) {
case 0x1: return SYS_BR_ONKEY;
case 0x2:
case 0x4: return SYS_BR_CHARGE;
case 0x10: return SYS_BR_RTC_ALARM;
case 0x20: return SYS_BR_FAULT_WAKEUP;
/* pm801 will never goto here, pm802 only */
case 0x8:
case 0x40:
if (smpl_reboot_flag)
return SYS_BR_REBOOT;
else
return SYS_BR_BAT_WAKEUP;
default: return SYS_BR_POWER_OFF;
}
}
void pmic_enter_powerdown(struct pmic_chip_desc *chip)
{
struct pmic *p_base;
oled_display_off();
p_base = pmic_get(chip->base_name);
if (!p_base || pmic_probe(p_base)) {
printf("access pmic failed...\n");
return;
}
/* wait before power off in order to complete console prints */
#ifdef CONFIG_POWEROFF_DELAY_USEC
udelay(CONFIG_POWEROFF_DELAY_USEC);
#endif
/* power down */
switch (chip->chip_id) {
#ifdef CONFIG_POWER_88PM886
case 0x00:
case 0xa1:
/* 88pm886 */
pmic_pm886_powerdown(p_base);
break;
#endif
#ifdef CONFIG_POWER_88PM880
case 0xb0:
/* 88pm880 */
pmic_pm880_powerdown(p_base);
break;
#endif
case 0x10:
case 0x11:
case 0x12:
case 0x13:
case 0x14:
case 0x08:
case 0x09:
case 0x0A:
case 0x18:
case 0x19:
case 0x1A:
case 0x1B:
case 0x20:
case 0x21:
case 0x3b:
/* pm802, pm802s, pm803, pm813, pm813s*/
pmic_pm802_powerdown(p_base);
break;
default:
pmic_default_powerdown(p_base);
break;
}
while(1);
}
/* marvell pmic operations */
int marvell88pm_set_buck_vol(struct pmic *p,
unsigned int buck, unsigned int uV, int level)
{
struct pmic_chip_desc *p_chip = get_marvell_pmic();
if (!p_chip || !p_chip->set_buck_vol) {
printf("can't set buck%d\n", buck);
return -1;
}
return p_chip->set_buck_vol(p, buck, uV, level);
}
int marvell88pm_set_ldo_vol(struct pmic *p, unsigned int ldo, unsigned int uV)
{
struct pmic_chip_desc *p_chip = get_marvell_pmic();
if (!p_chip || !p_chip->set_ldo_vol) {
printf("can't set ldo%d\n", ldo);
return -1;
}
return p_chip->set_ldo_vol(p, ldo, uV);
}
int marvell88pm_get_buck_vol(struct pmic *p, unsigned int buck, int level)
{
struct pmic_chip_desc *p_chip = get_marvell_pmic();
if (!p_chip || !p_chip->get_buck_vol) {
printf("can't get buck%d\n", buck);
return -1;
}
return p_chip->get_buck_vol(p, buck, level);
}
int marvell88pm_reg_update(struct pmic *p, int reg, unsigned int regval)
{
struct pmic_chip_desc *p_chip = get_marvell_pmic();
if (!p_chip || !p_chip->reg_update) {
printf("can't update reg 0x%x\n", reg);
return -1;
}
return p_chip->reg_update(p, reg, regval);
}
int get_powerup_mode(void)
{
struct pmic_chip_desc *p_chip = get_marvell_pmic();
if (!p_chip || !p_chip->get_powerup_mode) {
printf("can't get power up mode\n");
return -1;
}
return p_chip->get_powerup_mode();
}
void pmic_clear_bat_strdata(void)
{
struct pmic *p_base, *p_power;
struct pmic_chip_desc *p_chip;
u32 val;
p_chip = get_marvell_pmic();
if (!p_chip) {
printf("can't get pmic to clr bat data\n");
return;
}
p_base = pmic_get(p_chip->base_name);
if (!p_base || pmic_probe(p_base)) {
printf("access pmic failed...\n");
return;
}
if ((0xf0 & p_chip->chip_id) != 0x60)
return;
pmic_reg_write(p_base, 0xee, 0x00);
pmic_reg_write(p_base, 0xef, 0x00);
p_power = pmic_get(p_chip->power_name);
if (!p_power || pmic_probe(p_power)) {
printf("access pmic failed...\n");
return;
}
/* clear the slp_cnt */
pmic_reg_read(p_power, 0x71, &val);
val &= 0x0F;
pmic_reg_write(p_power, 0x71, val);
pmic_reg_read(p_power, 0x9A, &val);
val &= 0x0F;
pmic_reg_write(p_power, 0x9A, val);
}
/* power off charger famekwork init */
__weak int pm830_fg_alloc(unsigned char bus, struct pmic_chip_desc *chip) {return -1;}
__weak int pm830_chrg_alloc(unsigned char bus, struct pmic_chip_desc *chip) {return -1;}
__weak int pm830_bat_alloc(unsigned char bus, struct pmic_chip_desc *chip) {return -1;}
__weak int pm830_get_powerup_mode(void) {return INVALID_MODE; }
__weak int pm886_fg_alloc(unsigned char bus, struct pmic_chip_desc *chip) {return -1;}
__weak int pm886_chrg_alloc(unsigned char bus, struct pmic_chip_desc *chip) {return -1;}
__weak int pm886_bat_alloc(unsigned char bus, struct pmic_chip_desc *chip) {return -1;}
__weak int pm886_get_powerup_mode(void) {return INVALID_MODE; };
__weak int pm880_get_powerup_mode(void) {return INVALID_MODE; };
#ifdef CONFIG_PM80X_GPADC
#if defined(CONFIG_FG_PM803) || defined(CONFIG_PM803_GPADC)
#define CRASHKERNEL_OFFSET (0x380)
#define GEU_BASE 0xD4201000
#define APMU_GEU 0xd4282868
#define ASR1803_UIMANFUSE0_31_00 0x41C
#define ASR1803_UIMANFUSE0_63_32 0x420
int get_rtp_caldata(u32 *adc_code1, u32 *adc_code2)
{
u32 bank3_word6, bank3_word7;
writel((readl(APMU_GEU) | 0x09), APMU_GEU);
udelay(10);
bank3_word6 = readl(GEU_BASE + ASR1803_UIMANFUSE0_31_00);
bank3_word7 = readl(GEU_BASE + ASR1803_UIMANFUSE0_63_32);
*adc_code2 = ((bank3_word6 >> ( 219 - 192)) & (0x1f));
*adc_code1 = ((bank3_word6 >> ( 209 - 192)) & (0x3ff));
*adc_code2 = (*adc_code2) | (((bank3_word7 >> (224 - 224)) & (0x1f)) << 5);
printf("ADC code1: 0x%x, code2: 0x%x\n", *adc_code1, *adc_code2);
}
void pass_adcvbat_pair_to_kernel(void)
{
struct adc_vbat *adcvbat_data0 = adc0_vbat_def_pair;
struct adc_vbat *adcvbat_data1 = adc1_vbat_def_pair;
memcpy(CONFIG_CRASHKERNEL_INDICATOR + CRASHKERNEL_OFFSET,
adcvbat_data0,
sizeof(struct adc_vbat) * MAX_ADC_GROUP_CNT);
memcpy(CONFIG_CRASHKERNEL_INDICATOR + CRASHKERNEL_OFFSET
+ sizeof(struct adc_vbat) * MAX_ADC_GROUP_CNT,
adcvbat_data1,
sizeof(struct adc_vbat) * MAX_ADC_GROUP_CNT);
flush_cache((unsigned long)CONFIG_CRASHKERNEL_INDICATOR + CRASHKERNEL_OFFSET,
(unsigned long)(sizeof(struct adc_vbat) * MAX_ADC_GROUP_CNT));
}
int __convert_adc_to_mvolt(int adc_value,
struct adc_vbat *adc_vbat_def_pair)
{
int i, index = 0;
short y2, y1, x2, x1;
// Add by MBTK
int delta_x = 0;
int delta_y = 0;
int vbat_value = 0;
for (i = 1; i < MAX_ADC_GROUP_CNT; i++) {
if (adc_value < adc_vbat_def_pair[i].adc) {
index = i - 1;
break;
}
}
if (i == MAX_ADC_GROUP_CNT)
index = i - 2;
y2 = adc_vbat_def_pair[index+1].vbat;
y1 = adc_vbat_def_pair[index].vbat;
x2 = adc_vbat_def_pair[index+1].adc;
x1 = adc_vbat_def_pair[index].adc;
#if 1 //changed by mbtk_tanggaoyou, Integer operation division must be done at last
delta_x = x2-x1;
if(!delta_x)
return 1;
delta_y = y2-y1;
/*must divide at the last*/
vbat_value = (delta_y*(adc_value-x1)+delta_x*y1)/delta_x;
if(vbat_value <= 0)
vbat_value = 1;
return vbat_value;
#else
return (((y2-y1)/(x2-x1)) * adc_value)
+ y1 - (short)(((y2-y1)/(x2-x1))*x1);
#endif
}
int convert_adc_to_vbat(int adc_value)
{
return __convert_adc_to_mvolt(adc_value, adc0_vbat_def_pair);
}
static int convert_adc_to_tbat(int adc_value)
{
#if 0
int result;
int adc_code_delta = rtp_adc_code2 - rtp_adc_code1;
if (rtp_adc_code1 == 0 && rtp_adc_code2 == 0)
return 0;
result = 1600 + adc_value * 1200 / adc_code_delta
- rtp_adc_code2 * 1200 / adc_code_delta;
return result;
#endif
return __convert_adc_to_mvolt(adc_value, adc1_vbat_def_pair);
}
int pm803_get_convert_adc_value(int gpadc_id)
{
u32 val;
int mvolt, temp;
if (gpadc_id < 0 || gpadc_id > 1) {
printf("wrong adc id: %d\n", gpadc_id);
return 0;
}
val = readl(PM803_ADC0_RTC_REG + gpadc_id * 4);
val = (val & 0xffff);
/* convert it to real adc value */
temp = (int)val;
if (gpadc_id == 0)
mvolt = convert_adc_to_vbat(temp);
else
mvolt = convert_adc_to_tbat(temp);
if (mvolt < 0)
mvolt = 0;
#ifdef PM803_DEBUG_TEST_ADC
if (0 == gpadc_id)
return 4000;
else
return 500;
#else
return mvolt;
#endif
}
#endif
static void asr_pmic_sample_trigger(struct pmic *p, u32 adc_channel)
{
unsigned int value;
pmic_reg_read(p, 0x3b, &value);
value &= (~0x7);
value |= ((adc_channel >> 3) & 0x3);
pmic_reg_write(p, 0x3b, value);
pmic_reg_read(p, 0x3a, &value);
value &= ~(0x7 << 5);
value |= ((adc_channel & 0x7) << 5);
pmic_reg_write(p, 0x3a, value);
pmic_reg_read(p, 0x3b, &value);
value &= ~(0x3 << 2);
value |= (0x3 << 2);
pmic_reg_write(p, 0x3b, value);
udelay(50);
}
/* return gpadc voltage */
int pmic_get_gpadc_volt(struct pmic *p, int gpadc_id)
{
int volt;
unsigned int buf[2];
int gp_meas = 0x0;
u32 adc_channel;
int pmic_sample_offset, pmic_vref_offset;
#if defined(CONFIG_FG_PM803) || defined(CONFIG_PM803_GPADC)
if (pmic_is_pm803())
return pm803_get_convert_adc_value(gpadc_id);
#endif
switch (gpadc_id) {
case 0:
if (pmic_is_pm802() || pmic_is_pm813_a2a3()) {
gp_meas = 0x4c;
} else if (pmic_is_pm813s()) {
gp_meas = 0x7c;
} else {
gp_meas = 0x54;
}
if (pmic_is_pm813())
adc_channel = 28;
else
adc_channel = 7;
break;
case 1:
if (pmic_is_pm802()) {
gp_meas = 0x4e;
} else if (pmic_is_pm813s()) {
gp_meas = 0x54;
} else {
gp_meas = 0x56;
}
if (pmic_is_pm813())
adc_channel = 9;
else
adc_channel = 8;
break;
#ifdef CONFIG_AUXADC
case ASR_AUXADC1:
case ASR_AUXADC2:
case ASR_AUXADC3:
case ASR_AUXADC4:
case ASR_AUXADC5:
return __extern_get_auxadc_volt(gpadc_id);
#endif
default:
printf("%s: get GPADC failed!\n", __func__);
return -1;
}
if (pmic_is_pm802() || pmic_is_pm813())
asr_pmic_sample_trigger(p, adc_channel);
pmic_reg_read(p, gp_meas, &buf[0]);
pmic_reg_read(p, (gp_meas+1), &buf[1]);
pmic_get_calibration_data(&pmic_vref_offset, &pmic_sample_offset);
if (pmic_is_pm802()) {
volt = ((buf[1] & 0x0f) << 8) | (buf[0] & 0xff);
/* volt = ((volt & 0xfff) * 650) >> 11; */
volt = (volt - pmic_sample_offset) * (13000 + pmic_vref_offset);
volt = (volt >> 6) / (129 * 5);
if (volt > 1300)
volt = 1300;
if (volt < 0)
volt = 0;
} else if (pmic_is_pm813()) {
volt = ((buf[0] & 0xff) << 4) | (buf[1] & 0xf);
if (gpadc_id == 0) {
volt = (volt - pmic_sample_offset) * (13000 + pmic_vref_offset);
if (pmic_is_pm813s())
volt = (volt >> 6) / (128 * 5);
else
volt = (volt >> 6) / (129 * 5);
if (volt < 0)
volt = 0;
if (volt > 1300)
volt = 1300;
} else {
volt = (volt - pmic_sample_offset - 0x800) * (13000 + pmic_vref_offset);
if (pmic_is_pm813s())
volt = (volt >> 5) / (128 * 5);
else
volt = (volt >> 5) / (129 * 5);
if (volt < -1300)
volt = -1300;
if (volt > 1300)
volt = 1300;
}
} else {
volt = ((buf[0] & 0xff) << 4) | (buf[1] & 0x0f);
volt = ((volt & 0xfff) * 7 * 100) >> 11;
}
printf("GPADC%d: mvolt=%dmV\n", gpadc_id, volt);
return volt;
}
#if defined(CONFIG_AUXADC) && defined(CONFIG_ASR1802S)
#define ASR_SOC_BIAS_EN (0x1 << 26)
static int asr_soc_set_bias(int gpadc_id, int bias)
{
u32 bias_mask, bias_val, bias_shift, val2;
if (bias > 30 || bias < 0 || (bias % 2) || gpadc_id > ASR_AUXADC3) {
printf("error: error bias value!, gp: %d, bias: %d\n", gpadc_id, bias);
return -1;
}
bias_shift = 8 + (gpadc_id - ASR_AUXADC1) * 4;
bias_mask = 0xf << bias_shift;
bias_val = (bias / 2) << bias_shift;
val2 = readl(APB_SPARE14_REG);
val2 &= ~(bias_mask);
val2 |= bias_val;
val2 |= ASR_SOC_BIAS_EN;
writel(val2, APB_SPARE14_REG);
udelay(2000);
return 0;
}
static int asr_soc_clear_bias(int gpadc_id, int bias)
{
u32 bias_mask, bias_val, bias_shift, val2;
bias_shift = 8 + (gpadc_id - ASR_AUXADC1) * 4;
bias_mask = 0xf << bias_shift;
bias_val = 0;
val2 = readl(APB_SPARE14_REG);
val2 &= ~(bias_mask);
val2 |= bias_val;
val2 |= ASR_SOC_BIAS_EN;
writel(val2, APB_SPARE14_REG);
return 0;
}
#endif
/* return voltage via bias current from GPADC */
static int pmic_pm801_gpadc_bias_volt(struct pmic *p, int gpadc_id, int bias)
{
int volt, gp_bias, gp_bias_en = 0x14;
unsigned int data;
switch (gpadc_id) {
case 0:
gp_bias = 0xb;
break;
case 1:
gp_bias = 0xc;
break;
default:
printf("get GPADC%d failed!\n", gpadc_id);
return -1;
}
/* get the register value */
if (bias > 76)
bias = 76;
if (bias < 1)
bias = 1;
bias = (bias - 1) / 5;
pmic_reg_read(p, gp_bias, &data);
data &= 0xf0;
data |= bias;
pmic_reg_write(p, gp_bias, data);
pmic_reg_read(p, gp_bias_en, &data);
data |= (0x11 << gpadc_id);
pmic_reg_write(p, gp_bias_en, data);
udelay(2000);
volt = pmic_get_gpadc_volt(p, gpadc_id);
if ((volt < 0) || (volt > 1400)) {
printf("%s return %dmV\n", __func__, volt);
return -1;
}
pmic_reg_read(p, gp_bias_en, &data);
data &= ~(0x11 << gpadc_id);
pmic_reg_write(p, gp_bias_en, data);
return volt;
}
#if defined(CONFIG_AUXADC) && defined(CONFIG_ASR1802S)
/* return voltage via bias current from GPADC */
static int auxadc_get_bias_volt(struct pmic *p_fg, int gpadc_id, int bias)
{
int ret;
switch (gpadc_id) {
case ASR_AUXADC1:
case ASR_AUXADC2:
case ASR_AUXADC3:
case ASR_AUXADC4:
case ASR_AUXADC5:
if (!cpu_is_asr1903()) {
printf("error: auxadc bias is not support!, gp: %d\n", gpadc_id);
return -1;
}
if (asr_soc_set_bias(gpadc_id, bias) < 0)
return -1;
ret = __extern_get_auxadc_volt(gpadc_id);
asr_soc_clear_bias(gpadc_id, bias);
return ret;
default:
printf("%s: get GPADC%d failed!\n", __func__, gpadc_id);
return -1;
}
return -1;
}
#endif
/* return voltage via bias current from GPADC */
static int pmic_pm802_gpadc_bias_volt(struct pmic *p_fg, int gpadc_id, int bias)
{
int volt, gp_bias = 0x0c, gp_bias_en = 0x0d;
unsigned int data, mask, shift;
/* get the register value */
if (bias > 76)
bias = 76;
if (bias < 1)
bias = 1;
bias = (bias - 1) / 5;
switch (gpadc_id) {
case 0:
mask = 0x0f;
shift = 0;
break;
case 1:
mask = 0xf0;
shift = 4;
break;
default:
printf("get GPADC%d failed!\n", gpadc_id);
return -1;
}
pmic_reg_read(p_fg, gp_bias, &data);
data &= ~(mask);
data |= (bias << shift);
pmic_reg_write(p_fg, gp_bias, data);
pmic_reg_read(p_fg, gp_bias_en, &data);
data |= (0x1 << gpadc_id);
pmic_reg_write(p_fg, gp_bias_en, data);
udelay(2000);
volt = pmic_get_gpadc_volt(p_fg, gpadc_id);
if ((volt < 0) || (volt > 1300)) {
printf("%s return %dmV\n", __func__, volt);
return -1;
}
pmic_reg_read(p_fg, gp_bias_en, &data);
data &= ~(0x1 << gpadc_id);
pmic_reg_write(p_fg, gp_bias_en, data);
return volt;
}
// Add by MBTK
#if defined(CONFIG_FG_PM803) || defined(CONFIG_PM803_GPADC)
/*
this function is try convert adc value to customer's board voltage of batterry
input parameter: adc_ch is adc channel 0 or 1
coefficient is Conversion coefficient x 1000 to battery based the customer hardware board.
output/return : the real battery voltage mV
*/
int mbtk_customer_vbat_function(int adc_ch, int coefficient)
{
if(coefficient == ERROR_VBAT_COEF)
{
printf("[ERR]Please customize ADC for vbat,FIX vbat=4V !\n");
return 4000;
}
else
{
return (coefficient*pm803_get_convert_adc_value(adc_ch))/1000;
}
}
#endif
int pmic_get_gpadc_bias_volt(struct pmic *p_fg, int gpadc_id, int bias)
{
#if defined(CONFIG_AUXADC) && defined(CONFIG_ASR1802S)
if (gpadc_id >= ASR_AUXADC1)
return auxadc_get_bias_volt(p_fg, gpadc_id, bias);
#endif
#if defined(CONFIG_FG_PM803) || defined(CONFIG_PM803_GPADC)
if (pmic_is_pm803())
// Add by MBTK
{
#if 1
//TODO: based on board design to get bat voltage
return mbtk_customer_vbat_function(gpadc_id,CUSTOMER_VBAT_COEFFICIENT);
#else
return pm803_get_convert_adc_value(gpadc_id);
#endif
}
#endif
if (pmic_is_pm802())
return pmic_pm802_gpadc_bias_volt(p_fg, gpadc_id, bias);
else
return pmic_pm801_gpadc_bias_volt(p_fg, gpadc_id, bias);
}
#endif
int pmic_get_batt_vol(struct pmic *p_fg)
{
int ret, data, reg = 0xA2, mult = 700;
u32 buf[2] = {0};
int id;
int pmic_sample_offset, pmic_vref_offset;
int adc_channel;
#if !defined(CONFIG_FG_PM803) && !defined(CONFIG_PM803_GPADC)
if (pmic_is_pm803()) {
printf("%s, CONFIG_PM803_GPADC not defined\n", __func__);
return 4000;
}
#else
//TODO: based on board design to get bat voltage
if (pmic_is_pm803()) {
// Change by MBTK
return mbtk_customer_vbat_function(0,CUSTOMER_VBAT_COEFFICIENT);
}
#endif
pmic_reg_read(p_fg, 0x0, &id);
if (pmic_is_pm802() || pmic_is_pm813()) {
if (pmic_is_pm813())
adc_channel = 5;
else
adc_channel = 15;
if (pmic_is_pm813s())
reg = 0x68;
reg = 0x62;
mult = 813;
asr_pmic_sample_trigger(p_fg, adc_channel);
} else if (id == 0x69) {
reg = 0xA2;
mult = 700;
} else if (id == 0x64) {
reg = 0xA0;
mult = 700;
} else {
return 4000;
}
pmic_reg_read(p_fg, reg, &buf[0]);
pmic_reg_read(p_fg, (reg+1), &buf[1]);
pmic_reg_read(p_fg, 0x0, &id);
if (pmic_is_pm802())
data = ((buf[1] & 0x0f) << 8) | (buf[0] & 0xff);
else
data = ((buf[0] & 0xff) << 4) | (buf[1] & 0x0f);
if (pmic_is_pm802() || pmic_is_pm813()) {
pmic_get_calibration_data(&pmic_vref_offset, &pmic_sample_offset);
data = (data - pmic_sample_offset) * (13000 + pmic_vref_offset);
if (data < 0)
data = 0;
if (pmic_is_pm813s())
data = (data >> 6) / (128 * 1);
else
data = (data >> 6) / (129 * 1);
if (data > 6500)
data = 6500;
return data;
}
/* measure(mv) = value * 4 * 1.4 *1000/(2^12) */
data = ((data & 0xfff) * mult) >> 9;
return data;
}
int extern_pmic_get_batt_vol(void)
{
struct pmic *p_adc;
p_adc = pmic_get(MARVELL_PMIC_GPADC);
if (!p_adc) {
printf("can't get adc pmic\n");
return 4000;
}
return pmic_get_batt_vol(p_adc);
}
int extern_pmic_get_vol(int gpadc_id)
{
struct pmic *p_adc;
p_adc = pmic_get(MARVELL_PMIC_GPADC);
if (!p_adc) {
printf("can't get adc pmic\n");
return 4000;
}
return pmic_get_gpadc_volt(p_adc, gpadc_id);
}
int extern_pmic_get_bias_vol(int gpadc_id, int bias)
{
struct pmic *p_adc;
p_adc = pmic_get(MARVELL_PMIC_GPADC);
if (!p_adc) {
printf("can't get adc pmic\n");
return 4000;
}
return pmic_get_gpadc_bias_volt(p_adc, gpadc_id, bias);
}
int batt_marvell_init(struct pmic_chip_desc *chip,
u8 pmic_i2c_bus,
u8 chg_i2c_bus,
u8 fg_i2c_bus)
{
int ret;
struct pmic *p_fg, *p_chrg, *p_bat;
if (!chip) {
printf("--- %s: chip desc empty.\n", __func__);
return -EINVAL;
}
switch(chip->chip_id) {
case 0x0:
#ifdef CONFIG_POWER_88PM886
case 0xa1:
ret = pm886_chrg_alloc(chg_i2c_bus, chip);
if (ret) {
printf("init charger fails.\n");
return -1;
}
ret = pm886_fg_alloc(fg_i2c_bus, chip);
if (ret) {
printf("init fg fails.\n");
return -1;
}
ret = pm886_bat_alloc(pmic_i2c_bus, chip);
if (ret) {
printf("init charger/fuelgauge parent fails.\n");
return -1;
}
chip->get_powerup_mode = pm886_get_powerup_mode;
printf("%s: PMIC: 0x%x integrated with charger/fuelgauge\n",
__func__, chip->chip_id);
#endif
break;
#ifdef CONFIG_POWER_88PM880
case 0xb0:
/*
* TODO: add charger, fuelgauge, battery driver init here
* to avoid block booting, return 0 here
*/
chip->get_powerup_mode = pm880_get_powerup_mode;
return 0;
#endif
default:
/* let's use the name with 88pm830 first */
ret = pm830_chrg_alloc(chg_i2c_bus, chip);
if (ret) {
printf("init charger fails.\n");
return -1;
}
ret = pm830_fg_alloc(fg_i2c_bus, chip);
if (ret) {
printf("init fg fails.\n");
return -1;
}
ret = pm830_bat_alloc(pmic_i2c_bus, chip);
if (ret) {
printf("init charger/fg parent fails.\n");
return -1;
}
chip->get_powerup_mode = pm830_get_powerup_mode;
break;
}
p_chrg = pmic_get(chip->charger_name);
if (!p_chrg) {
printf("%s: access charger fails\n", chip->charger_name);
return -1;
}
p_fg = pmic_get(chip->fuelgauge_name);
if (!p_fg) {
printf("%s: access fg fails\n", chip->fuelgauge_name);
return -1;
}
p_bat = pmic_get(chip->battery_name);
if (!p_bat) {
printf("%s: access charger/fg parent fails\n",
chip->battery_name);
return -1;
}
p_fg->parent = p_bat;
p_chrg->parent = p_bat;
p_bat->pbat->battery_init(p_bat, p_fg, p_chrg, NULL);
return 0;
}
u8 pmic_get_slave_addr(void)
{
return pmic_slave_addr;
}
#ifdef CONFIG_HANDLE_ONKEY_BOOT
int handle_onkey_boot(u32 *emmd_pmic, u8 pmic_i2c, u8 chg_i2c)
{
int i, ret;
struct pmic_chip_desc *board_pmic_chip;
enum sys_boot_up_reason reason;
board_pmic_chip = get_marvell_pmic();
if (!board_pmic_chip) {
printf("--- %s: chip is NULL.\n", __func__);
goto out_boot_further;
}
reason = get_boot_up_reason(emmd_pmic);
printf("bootup reason: %d\n", reason);
switch (reason) {
case SYS_BR_ONKEY:
i = 100;
while (i > 0) {
i--;
udelay(ONKEY_BOOT_CHECK_USEC/100);
if (!marvell88pm_get_onkey())
goto out_power_down;
}
printf("%s: long onkey deteced, boot...\n", __func__);
goto out_boot_further;
break;
case SYS_BR_CHARGE:
case SYS_BR_RTC_ALARM:
case SYS_BR_FAULT_WAKEUP:
case SYS_BR_REBOOT:
goto out_boot_further;
break;
case SYS_BR_BAT_WAKEUP:
default:
goto out_power_down;
break;
}
out_power_down:
printf("power off now ...\n");
pmic_enter_powerdown(board_pmic_chip);
while(1);
out_boot_further:
return ret;
}
#endif