| /* |
| * 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 |
| |