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