From cb6a5e60dadf5f6fd56f7e56ee7b7cba1749a8ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nahuel=20G=C3=B3mez?= Date: Tue, 17 Dec 2024 15:44:15 -0300 Subject: [PATCH] battery: nuke sm5451_charger driver from a53x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nahuel Gómez --- .../battery/charger/sm5451_charger/Kconfig | 8 - .../battery/charger/sm5451_charger/Makefile | 4 - .../charger/sm5451_charger/sm5451_charger.c | 2213 ----------------- .../sm5451_charger/sm5451_charger.dtsi | 13 - .../charger/sm5451_charger/sm5451_charger.h | 222 -- .../sm5451_charger/sm5451_direct_charger.c | 2133 ---------------- .../sm5451_charger/sm5451_direct_charger.h | 241 -- 7 files changed, 4834 deletions(-) delete mode 100755 drivers/battery/charger/sm5451_charger/Kconfig delete mode 100755 drivers/battery/charger/sm5451_charger/Makefile delete mode 100755 drivers/battery/charger/sm5451_charger/sm5451_charger.c delete mode 100755 drivers/battery/charger/sm5451_charger/sm5451_charger.dtsi delete mode 100755 drivers/battery/charger/sm5451_charger/sm5451_charger.h delete mode 100755 drivers/battery/charger/sm5451_charger/sm5451_direct_charger.c delete mode 100755 drivers/battery/charger/sm5451_charger/sm5451_direct_charger.h diff --git a/drivers/battery/charger/sm5451_charger/Kconfig b/drivers/battery/charger/sm5451_charger/Kconfig deleted file mode 100755 index f2ad215d6..000000000 --- a/drivers/battery/charger/sm5451_charger/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -config CHARGER_SM5451 - tristate "SM5451 direct charger support" - depends on I2C - help - Say Y here to enable support for the SM5451 direct charger. - SM5451 is a direct charging IC. - SM5451 is dependent on I2C - so it needs to be defined. \ No newline at end of file diff --git a/drivers/battery/charger/sm5451_charger/Makefile b/drivers/battery/charger/sm5451_charger/Makefile deleted file mode 100755 index 8df71c019..000000000 --- a/drivers/battery/charger/sm5451_charger/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -obj-$(CONFIG_CHARGER_SM5451) += sm5451-charger.o -sm5451-charger-$(CONFIG_CHARGER_SM5451) += sm5451_charger.o sm5451_direct_charger.o - -ccflags-y := -Wformat diff --git a/drivers/battery/charger/sm5451_charger/sm5451_charger.c b/drivers/battery/charger/sm5451_charger/sm5451_charger.c deleted file mode 100755 index 1c1c7f2b4..000000000 --- a/drivers/battery/charger/sm5451_charger/sm5451_charger.c +++ /dev/null @@ -1,2213 +0,0 @@ -/* - * sm5451_charger.c - SM5451 Charger device driver for SAMSUNG platform - * - * Copyright (C) 2022 SiliconMitus Co.Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#if defined(CONFIG_OF) -#include -#include -#include -#include -#endif /* CONFIG_OF */ -#if IS_ENABLED(CONFIG_BATTERY_SAMSUNG) -#include "../../common/sec_charging_common.h" -#include "../../common/sec_direct_charger.h" -#endif -#include "sm5451_charger.h" -#if IS_ENABLED(CONFIG_SEC_ABC) -#include -#endif - -#define SM5451_DC_VERSION "WD1" - -static u32 SM5451_freq_val[] = { - 200, 375, 500, 750, 1000, 1250, 1500 -}; - -static int sm5451_read_reg(struct sm5451_charger *sm5451, u8 reg, u8 *dest) -{ - int cnt, ret; - - for (cnt = 0; cnt < 3; ++cnt) { - ret = i2c_smbus_read_byte_data(sm5451->i2c, reg); - if (ret < 0) - dev_err(sm5451->dev, "%s: fail to i2c_read(ret=%d)\n", __func__, ret); - else - break; - - if (cnt == 0) - msleep(30); - } - - if (ret < 0) { -#if IS_ENABLED(CONFIG_SEC_ABC) && !defined(CONFIG_SEC_FACTORY) - sec_abc_send_event("MODULE=battery@WARN=dc_i2c_fail"); -#endif - return ret; - } else { - *dest = (ret & 0xff); - } - - return 0; -} - -int sm5451_bulk_read(struct sm5451_charger *sm5451, u8 reg, int count, u8 *buf) -{ - int cnt, ret; - - for (cnt = 0; cnt < 3; ++cnt) { - ret = i2c_smbus_read_i2c_block_data(sm5451->i2c, reg, count, buf); - if (ret < 0) - dev_err(sm5451->dev, "%s: fail to i2c_bulk_read(ret=%d)\n", __func__, ret); - else - break; - - if (cnt == 0) - msleep(30); - } - -#if IS_ENABLED(CONFIG_SEC_ABC) && !defined(CONFIG_SEC_FACTORY) - if (ret < 0) - sec_abc_send_event("MODULE=battery@WARN=dc_i2c_fail"); -#endif - - return ret; -} - -static int sm5451_write_reg(struct sm5451_charger *sm5451, u8 reg, u8 value) -{ - int cnt, ret; - - for (cnt = 0; cnt < 3; ++cnt) { - ret = i2c_smbus_write_byte_data(sm5451->i2c, reg, value); - if (ret < 0) - dev_err(sm5451->dev, "%s: fail to i2c_write(ret=%d)\n", __func__, ret); - else - break; - - if (cnt == 0) - msleep(30); - } - -#if IS_ENABLED(CONFIG_SEC_ABC) && !defined(CONFIG_SEC_FACTORY) - if (ret < 0) - sec_abc_send_event("MODULE=battery@WARN=dc_i2c_fail"); -#endif - - return ret; -} - -static int sm5451_update_reg(struct sm5451_charger *sm5451, u8 reg, - u8 val, u8 mask, u8 pos) -{ - int ret; - u8 old_val; - - mutex_lock(&sm5451->i2c_lock); - - ret = sm5451_read_reg(sm5451, reg, &old_val); - if (ret == 0) { - u8 new_val = (val & mask) << pos | (old_val & ~(mask << pos)); - - ret = sm5451_write_reg(sm5451, reg, new_val); - } - - mutex_unlock(&sm5451->i2c_lock); - - return ret; -} - -static u8 sm5451_get_flag_status(struct sm5451_charger *sm5451, u8 flag_addr) -{ - u8 reg; - - /* read twice to get correct value */ - mutex_lock(&sm5451->i2c_lock); - sm5451_read_reg(sm5451, flag_addr, ®); - sm5451_read_reg(sm5451, flag_addr, ®); - mutex_unlock(&sm5451->i2c_lock); - - return reg; -} - -static u32 sm5451_get_vbatreg(struct sm5451_charger *sm5451) -{ - u8 reg; - u32 vbatovp, offset; - - sm5451_read_reg(sm5451, SM5451_REG_VBAT_OVP, ®); - vbatovp = 4000 + ((reg & 0x7F) * 10); - sm5451_read_reg(sm5451, SM5451_REG_REG1, ®); - offset = ((reg & 0x3) * 50) + 50; - - dev_info(sm5451->dev, "%s: vbatovp=%d, offset=%d\n", - __func__, vbatovp, offset); - - return (vbatovp - offset); -} - -static int sm5451_set_vbatreg(struct sm5451_charger *sm5451, u32 vbatreg) -{ - u8 reg; - u32 vbatovp, offset; - - sm5451_read_reg(sm5451, SM5451_REG_REG1, ®); - offset = ((reg & 0x3) * 50) + 50; - vbatovp = vbatreg + offset; - if (vbatovp < 4000) - reg = 0; - else - reg = (vbatovp - 4000) / 10; - - dev_info(sm5451->dev, "%s: vbatovp=%d, offset=%d reg=0x%x\n", - __func__, vbatovp, offset, reg); - - return sm5451_update_reg(sm5451, SM5451_REG_VBAT_OVP, reg, 0x7F, 0); -} - -static u32 sm5451_get_ibuslim(struct sm5451_charger *sm5451) -{ - u8 reg; - u32 ibusocp, offset; - - sm5451_read_reg(sm5451, SM5451_REG_IBUS_PROT, ®); - ibusocp = 500 + ((reg & 0x3F) * 100); - sm5451_read_reg(sm5451, SM5451_REG_CNTL5, ®); - offset = ((reg & 0x3) * 100) + 100; - - dev_info(sm5451->dev, "%s: ibusocp=%d, offset=%d\n", - __func__, ibusocp, offset); - - return ibusocp - offset; -} - -static int sm5451_set_ibuslim(struct sm5451_charger *sm5451, u32 ibuslim) -{ - u8 reg; - u32 ibusocp, offset; - - sm5451_read_reg(sm5451, SM5451_REG_CNTL5, ®); - offset = ((reg & 0x3) * 100) + 100; - ibusocp = ibuslim + offset; - reg = (ibusocp - 500) / 100; - - dev_info(sm5451->dev, "%s: ibusocp=%d, offset=%d reg=0x%x\n", - __func__, ibusocp, offset, reg); - - return sm5451_update_reg(sm5451, SM5451_REG_IBUS_PROT, reg, 0x3F, 0); -} - -static int sm5451_set_freq(struct sm5451_charger *sm5451, u8 freq) -{ - return sm5451_update_reg(sm5451, SM5451_REG_CNTL2, freq, 0x7, 5); -} - -static int sm5451_set_op_mode(struct sm5451_charger *sm5451, u8 op_mode) -{ - return sm5451_update_reg(sm5451, SM5451_REG_CNTL1, op_mode, 0x7, 4); -} - -static u8 sm5451_get_op_mode(struct sm5451_charger *sm5451) -{ - u8 reg; - - sm5451_read_reg(sm5451, SM5451_REG_CNTL1, ®); - - return (reg >> 4) & 0x7; -} - -static int sm5451_set_wdt_timer(struct sm5451_charger *sm5451, u8 tmr) -{ - return sm5451_update_reg(sm5451, SM5451_REG_CNTL1, tmr, 0x7, 0); -} - -static u8 sm5451_get_wdt_timer(struct sm5451_charger *sm5451) -{ - u8 reg = 0x0; - - sm5451_read_reg(sm5451, SM5451_REG_CNTL1, ®); - - return reg & 0x7; -} - -static int sm5451_kick_wdt(struct sm5451_charger *sm5451) -{ - return sm5451_update_reg(sm5451, SM5451_REG_CNTL2, 0x1, 0x1, 0); -} - -static int sm5451_set_adcmode(struct sm5451_charger *sm5451, u8 mode) -{ - return sm5451_update_reg(sm5451, SM5451_REG_ADC_CNTL, mode, 0x1, 6); -} - -static int sm5451_enable_adc(struct sm5451_charger *sm5451, bool enable) -{ - return sm5451_update_reg(sm5451, SM5451_REG_ADC_CNTL, enable, 0x1, 7); -} - -static int sm5451_enable_adc_oneshot(struct sm5451_charger *sm5451, u8 enable) -{ - int ret, cnt; - u8 reg; - - if (enable) { - for (cnt = 0; cnt < 3; ++cnt) { - ret = sm5451_write_reg(sm5451, SM5451_REG_ADC_CNTL, 0xC0); - /* ADC update time */ - msleep(25); - sm5451_read_reg(sm5451, SM5451_REG_FLAG3, ®); - if ((reg & SM5451_FLAG3_ADCDONE) == 0) - dev_info(sm5451->dev, "%s: fail to adc done(FLAG3=0x%02X)\n", __func__, reg); - else - break; - } - } else { - msleep(30); - ret = sm5451_write_reg(sm5451, SM5451_REG_ADC_CNTL, 0x0); - } - - return ret; -} - -static int sm5451_get_enadc(struct sm5451_charger *sm5451) -{ - u8 reg = 0x0; - - sm5451_read_reg(sm5451, SM5451_REG_ADC_CNTL, ®); - - return (reg >> 7) & 0x1; -} - -static int sm5451_sw_reset(struct sm5451_charger *sm5451) -{ - u8 i, reg; - - sm5451_update_reg(sm5451, SM5451_REG_CNTL1, 1, 0x1, 7); /* Do SW Reset */ - - for (i = 0; i < 0xff; ++i) { - usleep_range(1000, 2000); - sm5451_read_reg(sm5451, SM5451_REG_CNTL1, ®); - if (!((reg >> 7) & 0x1)) - break; - } - - if (i == 0xff) { - dev_err(sm5451->dev, "%s: didn't clear reset bit\n", __func__); - return -EBUSY; - } - return 0; -} - -static u8 sm5451_get_reverse_boost_ocp(struct sm5451_charger *sm5451) -{ - u8 reg, op_mode; - u8 revbsocp = 0; - - op_mode = sm5451_get_op_mode(sm5451); - if (op_mode == OP_MODE_INIT) { - sm5451_read_reg(sm5451, SM5451_REG_FLAG4, ®); - dev_info(sm5451->dev, "%s: FLAG4=0x%x\n", __func__, reg); - if (reg & SM5451_FLAG4_IBUSOCP_RVS) { - revbsocp = 1; - dev_err(sm5451->dev, "%s: detect reverse_boost_ocp\n", __func__); - } - } - return revbsocp; -} - -static void sm5451_init_reg_param(struct sm5451_charger *sm5451) -{ - sm5451_set_wdt_timer(sm5451, WDT_TIMER_S_40); - sm5451_set_freq(sm5451, sm5451->pdata->freq); /* FREQ : 500kHz */ - sm5451_update_reg(sm5451, SM5451_REG_IBUS_PROT, 0x1, 0x1, 7); /* IBUSUCP = on */ - sm5451_write_reg(sm5451, SM5451_REG_VBUSOVP, 0xC6); /* VBUS_OVP=11V */ - sm5451_write_reg(sm5451, SM5451_REG_IBAT_OCP, 0x7C); /* IBATOCP = off */ - sm5451_write_reg(sm5451, SM5451_REG_CNTL3, 0xA3); /* RLTVOVP = off, RLTVUVP = 1.01x */ - sm5451_write_reg(sm5451, SM5451_REG_CNTL4, 0x00); /* VDSQRBP = off */ - sm5451_write_reg(sm5451, SM5451_REG_IBATOCP_DG, 0x88); /* Deglitch for IBATOCP & IBUSOCP = 8ms */ - sm5451_write_reg(sm5451, SM5451_REG_VDSQRB_DG, 0x05); /* Deglitch for VDSQRB = 200ms */ - sm5451_write_reg(sm5451, SM5451_REG_CNTL5, 0x3F); /* IBUSOCP_RVS = on, threshold = 4.5A */ - if (sm5451->pdata->en_vbatreg) - sm5451_write_reg(sm5451, SM5451_REG_REG1, 0x07); /* IBATREG = off, VBATREG = VBATOVP - 200mV */ - else - sm5451_write_reg(sm5451, SM5451_REG_REG1, 0x03); /* IBATOCP & IBATREG & VBATREG = off */ - - if (sm5451->pdata->x2bat_mode) { - if (sm5451->chip_id == SM5451_SUB) - sm5451_write_reg(sm5451, SM5451_REG_REG1, 0x07); /* IBATREG = off, VBATREG = VBATOVP - 200mV */ - } else { - if (sm5451->chip_id == SM5451_SUB) - sm5451_update_reg(sm5451, SM5451_REG_IBUS_PROT, 0x1, 0x1, 6); /* IBUSUCP = 250mA */ - } -} - -static struct sm_dc_info *select_sm_dc_info(struct sm5451_charger *sm5451) -{ - if (sm5451->pdata->x2bat_mode) - return sm5451->x2bat_dc; - else - return sm5451->pps_dc; -} - -static int sm5451_get_vnow(struct sm5451_charger *sm5451) -{ - struct sm_dc_info *sm_dc = select_sm_dc_info(sm5451); - union power_supply_propval value = {0, }; - int ret; - - if (sm5451->pdata->en_vbatreg) - return 0; - - value.intval = SEC_BATTERY_VOLTAGE_MV; - ret = psy_do_property(sm5451->pdata->battery.fuelgauge_name, get, - POWER_SUPPLY_PROP_VOLTAGE_NOW, value); - if (ret < 0) { - dev_err(sm5451->dev, "%s: cannot get vnow from fg\n", __func__); - return -EINVAL; - } - pr_info("%s %s: vnow=%dmV, target_vbat=%dmV\n", sm_dc->name, - __func__, value.intval, sm_dc->target_vbat); - - return value.intval; -} - -static int sm5451_convert_adc(struct sm5451_charger *sm5451, u8 index) -{ - u8 regs[4] = {0x0, }; - u8 ret = 0x0; - int adc, cnt; - -/* User binary only check ADC block during CHG-ON status and Factory binary/Dual Battery feature check ADC block all the time */ -#if !defined(CONFIG_SEC_FACTORY) && !defined(CONFIG_DUAL_BATTERY) - struct sm_dc_info *sm_dc = select_sm_dc_info(sm5451); - - if (sm_dc_get_current_state(sm_dc) < SM_DC_CHECK_VBAT - && !(sm5451->rev_boost) && (sm_dc->chip_id != SM5451_SUB) && !(sm5451->force_adc_on)) { - /* Didn't worked ADC block during on CHG-OFF status */ - return 0; - } -#endif - - for (cnt = 0; cnt < 2; ++cnt) { - if (sm5451_get_enadc(sm5451) == 0) - sm5451_enable_adc_oneshot(sm5451, 1); - - switch (index) { - case SM5451_ADC_THEM: /* unit - mV */ - sm5451_bulk_read(sm5451, SM5451_REG_THEM_ADC_H, 2, regs); - adc = (((int)(regs[0] & 0x0F) << 8) + regs[1] + 1) >> 1; - break; - case SM5451_ADC_TDIE: /* unit - C */ - sm5451_read_reg(sm5451, SM5451_REG_TDIE_ADC, regs); - adc = -40 + regs[0]; - break; - case SM5451_ADC_VBUS: - sm5451_bulk_read(sm5451, SM5451_REG_VBUS_ADC_H, 2, regs); - adc = (((int)(regs[0] & 0x0F) << 8) + regs[1]) * 4; - break; - case SM5451_ADC_IBUS: - sm5451_bulk_read(sm5451, SM5451_REG_IBUS_ADC_H, 2, regs); - adc = (((int)(regs[0] & 0x0F) << 8) + regs[1]) * 2; - break; - case SM5451_ADC_VBAT: - sm5451_bulk_read(sm5451, SM5451_REG_VBAT_ADC_H, 2, regs); - adc = (((int)(regs[0] & 0x0F) << 8) + regs[1]) * 2; - break; - case SM5451_ADC_IBAT: - sm5451_bulk_read(sm5451, SM5451_REG_IBAT_ADC_H, 2, regs); - adc = (((int)(regs[0] & 0x0F) << 8) + regs[1]) * 2; - break; - default: - adc = 0; - } - - /* prevent for reset of register */ - ret = sm5451_get_wdt_timer(sm5451); - if (ret != WDT_TIMER_S_40) { - dev_err(sm5451->dev, "%s: detected REG Reset condition(ret=0x%x)\n", __func__, ret); - sm5451_init_reg_param(sm5451); - } else { - break; - } - } - dev_info(sm5451->dev, "%s: index(%d)=[0x%02X,0x%02X], adc=%d\n", - __func__, index, regs[0], regs[1], adc); - - return adc; -} - -static int sm5451_set_adc_mode(struct i2c_client *i2c, u8 mode) -{ - struct sm5451_charger *sm5451 = i2c_get_clientdata(i2c); - - switch (mode) { - case SM_DC_ADC_MODE_ONESHOT: - /* covered by continuous mode */ - case SM_DC_ADC_MODE_CONTINUOUS: - /* SM5451 continuous mode reflash time : 200ms */ - sm5451_set_adcmode(sm5451, 0); - sm5451_enable_adc(sm5451, 1); - break; - case SM_DC_ADC_MODE_OFF: - default: - sm5451_set_adcmode(sm5451, 0); - sm5451_enable_adc(sm5451, 0); - break; - } - - return 0; -} - -static void sm5451_print_regmap(struct sm5451_charger *sm5451) -{ - u8 print_reg_num, regs[64] = {0x0, }; - char temp_buf[128] = {0,}; - char reg_addr[16] = {0x0C, 0x0E, 0x10, 0x11, 0x60, 0x61, 0x62, 0x64, }; - u8 reg_data; - int i; - - print_reg_num = SM5451_REG_FLAG1 - SM5451_REG_CNTL1; - sm5451_bulk_read(sm5451, SM5451_REG_CNTL1, print_reg_num, regs); - for (i = 0; i < print_reg_num; ++i) - sprintf(temp_buf+strlen(temp_buf), "0x%02X[0x%02X],", SM5451_REG_CNTL1 + i, regs[i]); - - pr_info("sm5451-charger: regmap: %s\n", temp_buf); - memset(temp_buf, 0x0, sizeof(temp_buf)); - - print_reg_num = 8; - for (i = 0; i < print_reg_num; ++i) { - sm5451_read_reg(sm5451, reg_addr[i], ®_data); - sprintf(temp_buf+strlen(temp_buf), "0x%02X[0x%02X],", reg_addr[i], reg_data); - } - pr_info("sm5451-charger: regmap: %s\n", temp_buf); - memset(temp_buf, 0x0, sizeof(temp_buf)); -} - -static int sm5451_reverse_boost_enable(struct sm5451_charger *sm5451, bool enable) -{ - u8 i, flag1, flag2, flag3, flag4; - - if (enable && !sm5451->rev_boost) { - for (i = 0; i < 2; ++i) { - flag3 = sm5451_get_flag_status(sm5451, SM5451_REG_FLAG3); - dev_info(sm5451->dev, "%s: FLAG3:0x%x i=%d\n", __func__, flag3, i); - if (flag3 & (SM5451_FLAG3_VBUSUVLO | SM5451_FLAG3_VBUSPOK)) - msleep(20); - else - break; - } - - sm5451_set_op_mode(sm5451, OP_MODE_REV_BOOST); - for (i = 0; i < 12; ++i) { - usleep_range(10000, 11000); - sm5451_read_reg(sm5451, SM5451_REG_FLAG1, &flag1); - sm5451_read_reg(sm5451, SM5451_REG_FLAG2, &flag2); - sm5451_read_reg(sm5451, SM5451_REG_FLAG3, &flag3); - sm5451_read_reg(sm5451, SM5451_REG_FLAG4, &flag4); - dev_info(sm5451->dev, "%s: FLAG:0x%x:0x%x:0x%x:0x%x i=%d\n", - __func__, flag1, flag2, flag3, flag4, i); - if (flag4 & SM5451_FLAG4_RVSRDY) - break; - } - if (i == 12) { - dev_err(sm5451->dev, "%s: fail to reverse boost enable\n", __func__); - sm5451_set_op_mode(sm5451, OP_MODE_INIT); - sm5451->rev_boost = false; - return -EINVAL; - } - sm5451_set_adc_mode(sm5451->i2c, SM_DC_ADC_MODE_CONTINUOUS); - dev_info(sm5451->dev, "%s: ON\n", __func__); - } else if (!enable) { - sm5451_set_op_mode(sm5451, OP_MODE_INIT); - sm5451_set_adc_mode(sm5451->i2c, SM_DC_ADC_MODE_OFF); - dev_info(sm5451->dev, "%s: OFF\n", __func__); - } - sm5451->rev_boost = enable; - - return 0; -} - -static bool sm5451_check_charging_enable(struct sm5451_charger *sm5451) -{ - u8 reg; - - reg = sm5451_get_op_mode(sm5451); - if (reg == OP_MODE_FW_BOOST || reg == OP_MODE_FW_BYPASS) - return true; - else - return false; -} - -static int sm5451_prechg_enable(struct sm5451_charger *sm5451, bool enable) -{ - struct sm_dc_info *sm_dc = select_sm_dc_info(sm5451); - int state = sm_dc_get_current_state(sm_dc); - u8 reg, i; - - if (enable) { - if (state > SM_DC_EOC || sm5451_check_charging_enable(sm5451)) { - dev_info(sm5451->dev, "%s: charging state (state=%d)\n", __func__, state); - } else { - dev_info(sm5451->dev, "%s: ON\n", __func__); - for (i = 0; i < 2; ++i) { - sm5451_write_reg(sm5451, SM5451_REG_PRECHG_MODE, 0xEA); - sm5451_write_reg(sm5451, SM5451_REG_PRECHG_MODE, 0xAE); - sm5451_write_reg(sm5451, SM5451_REG_CTRL_STM_0, 0xB0); - sm5451_write_reg(sm5451, SM5451_REG_CTRL_STM_3, 0x80); - sm5451_write_reg(sm5451, SM5451_REG_CTRL_STM_5, 0x08); - sm5451_write_reg(sm5451, SM5451_REG_CTRL_STM_2, 0x08); - sm5451_read_reg(sm5451, SM5451_REG_CTRL_STM_0, ®); - if (reg != 0xB0) - sm5451_write_reg(sm5451, SM5451_REG_PRECHG_MODE, 0x00); - else - break; - dev_info(sm5451->dev, "%s: fail to pre-charging\n", __func__); - } - usleep_range(10000, 11000); - } - } else { - dev_info(sm5451->dev, "%s: OFF\n", __func__); - sm5451_write_reg(sm5451, SM5451_REG_PRECHG_MODE, 0x00); - } - - return 0; -} - -static int sm5451_start_charging(struct sm5451_charger *sm5451) -{ - struct sm_dc_info *sm_dc = select_sm_dc_info(sm5451); - int state = sm_dc_get_current_state(sm_dc); - struct power_supply *psy_dc_sub = NULL; - struct sm5451_charger *sm5451_sub = NULL; - int ret; - - if (sm5451->cable_online < 1) { - dev_err(sm5451->dev, "%s: can't detect valid cable connection(online=%d)\n", - __func__, sm5451->cable_online); - return -ENODEV; - } - - /* Check dc mode */ - if (sm_dc->chip_id != SM5451_SUB) { - psy_dc_sub = power_supply_get_by_name("sm5451-charger-sub"); - if (!psy_dc_sub) { - sm_dc->i2c_sub = NULL; - dev_info(sm5451->dev, "%s: start single dc mode\n", __func__); - } else { - sm5451_sub = power_supply_get_drvdata(psy_dc_sub); - sm_dc->i2c_sub = sm5451_sub->i2c; - dev_info(sm5451->dev, "%s: start dual dc mode\n", __func__); - } - } else { - dev_info(sm5451->dev, "%s: unable to start sub dc standalone\n", __func__); - return -EINVAL; - } - - if (state < SM_DC_CHECK_VBAT) { - dev_info(sm5451->dev, "%s: charging off state (state=%d)\n", __func__, state); - ret = sm5451_sw_reset(sm5451); - if (ret < 0) { - dev_err(sm5451->dev, "%s: fail to sw reset(ret=%d)\n", __func__, ret); - return ret; - } - sm5451_init_reg_param(sm5451); - sm5451_prechg_enable(sm5451, 1); - - if (sm5451_sub) { - ret = sm5451_sw_reset(sm5451_sub); - if (ret < 0) { - dev_err(sm5451_sub->dev, "%s: fail to sw reset(ret=%d)\n", __func__, ret); - return ret; - } - sm5451_init_reg_param(sm5451_sub); - sm5451_prechg_enable(sm5451_sub, 1); - } - } else if (state == SM_DC_CV_MAN) { - dev_info(sm5451->dev, "%s: skip start charging (state=%d)\n", __func__, state); - return 0; - } - - ret = sm_dc_start_charging(sm_dc); - if (ret < 0) { - dev_err(sm5451->dev, "%s: fail to start direct-charging\n", __func__); - return ret; - } - __pm_stay_awake(sm5451->chg_ws); - - return 0; -} - -static int sm5451_stop_charging(struct sm5451_charger *sm5451) -{ - struct sm_dc_info *sm_dc = select_sm_dc_info(sm5451); - - msleep(30); - sm_dc_stop_charging(sm_dc); - - __pm_relax(sm5451->chg_ws); - - return 0; -} - -static int sm5451_start_pass_through_charging(struct sm5451_charger *sm5451) -{ - struct sm_dc_info *sm_dc = select_sm_dc_info(sm5451); - int state = sm_dc_get_current_state(sm_dc); - int ret; - - if (sm5451->cable_online < 1) { - dev_err(sm5451->dev, "%s: can't detect valid cable connection(online=%d)\n", - __func__, sm5451->cable_online); - return -ENODEV; - } - - if (state < SM_DC_PRESET) { - pr_err("%s %s: charging off state (state=%d)\n", sm_dc->name, __func__, sm_dc->state); - return -ENODEV; - } - - sm5451_stop_charging(sm5451); - sm5451_prechg_enable(sm5451, 1); - msleep(200); - - /* Disable IBUSUCP & Set freq*/ - sm5451_set_freq(sm5451, sm5451->pdata->freq_byp); /* FREQ */ - sm5451_write_reg(sm5451, SM5451_REG_CNTL3, 0x83); /* RLTVOVP = disabled, RLTVUVP = disabled */ - sm5451_update_reg(sm5451, SM5451_REG_IBUS_PROT, 0, 0x1, 7); /* IBUSUCP = disabled */ - - ret = sm_dc_start_manual_charging(sm_dc); - if (ret < 0) { - dev_err(sm5451->dev, "%s: fail to start direct-charging\n", __func__); - return ret; - } - __pm_stay_awake(sm5451->chg_ws); - - return 0; -} - -static int sm5451_set_pass_through_ta_vol(struct sm5451_charger *sm5451, int delta_soc) -{ - struct sm_dc_info *sm_dc = select_sm_dc_info(sm5451); - int state = sm_dc_get_current_state(sm_dc); - - if (sm5451->cable_online < 1) { - dev_err(sm5451->dev, "%s: can't detect valid cable connection(online=%d)\n", - __func__, sm5451->cable_online); - return -ENODEV; - } - - if (state != SM_DC_CV_MAN) { - pr_err("%s %s: pass-through mode was not set.(dc state = %d)\n", sm_dc->name, __func__, sm_dc->state); - return -ENODEV; - } - - return sm_dc_set_ta_volt_by_soc(sm_dc, delta_soc); -} - -static int psy_chg_get_online(struct sm5451_charger *sm5451) -{ - u8 flag, vbus_pok, cable_online; - - cable_online = sm5451->cable_online < 1 ? 0 : 1; - flag = sm5451_get_flag_status(sm5451, SM5451_REG_FLAG3); - dev_info(sm5451->dev, "%s: FLAG3=0x%x\n", __func__, flag); - vbus_pok = (flag >> 7) & 0x1; - - if (vbus_pok != cable_online) { - dev_err(sm5451->dev, "%s: mismatched vbus state(vbus_pok:%d cable_online:%d)\n", - __func__, vbus_pok, sm5451->cable_online); - } - - return sm5451->cable_online; -} - -static int psy_chg_get_status(struct sm5451_charger *sm5451) -{ - int status = POWER_SUPPLY_STATUS_UNKNOWN; - u8 flag1, flag2, flag3, flag4; - - flag1 = sm5451_get_flag_status(sm5451, SM5451_REG_FLAG1); - flag2 = sm5451_get_flag_status(sm5451, SM5451_REG_FLAG2); - flag3 = sm5451_get_flag_status(sm5451, SM5451_REG_FLAG3); - flag4 = sm5451_get_flag_status(sm5451, SM5451_REG_FLAG4); - dev_info(sm5451->dev, "%s: FLAG:0x%x:0x%x:0x%x:0x%x\n", - __func__, flag1, flag2, flag3, flag4); - - if (sm5451_check_charging_enable(sm5451)) { - status = POWER_SUPPLY_STATUS_CHARGING; - } else { - if ((flag3 >> 7) & 0x1) { /* check vbus-pok */ - status = POWER_SUPPLY_STATUS_NOT_CHARGING; - } else { - status = POWER_SUPPLY_STATUS_DISCHARGING; - } - } - - return status; -} - -static int psy_chg_get_health(struct sm5451_charger *sm5451) -{ - struct sm_dc_info *sm_dc = select_sm_dc_info(sm5451); - int state = sm_dc_get_current_state(sm_dc); - int health = POWER_SUPPLY_HEALTH_GOOD; - u8 flag, chg_on; - - if (state == SM_DC_ERR) { - health = POWER_SUPPLY_EXT_HEALTH_DC_ERR; - dev_info(sm5451->dev, "%s: chg_state=%d, health=%d\n", - __func__, state, health); - } else if (state >= SM_DC_PRE_CC && state <= SM_DC_CV) { - chg_on = sm5451_check_charging_enable(sm5451); - flag = sm5451_get_flag_status(sm5451, SM5451_REG_FLAG3); - if (chg_on == false) { - health = POWER_SUPPLY_EXT_HEALTH_DC_ERR; - } else if (((flag >> 7) & 0x1) == 0x0) { /* VBUS_POK status is disabled */ - health = POWER_SUPPLY_EXT_HEALTH_DC_ERR; - } - - dev_info(sm5451->dev, "%s: chg_on=%d, flag3=0x%x, health=%d\n", - __func__, chg_on, flag, health); - } - - return health; -} - -static int psy_chg_get_chg_vol(struct sm5451_charger *sm5451) -{ - u32 chg_vol = sm5451_get_vbatreg(sm5451); - - dev_info(sm5451->dev, "%s: VBAT_REG=%dmV\n", __func__, chg_vol); - - return chg_vol; -} - -static int psy_chg_get_input_curr(struct sm5451_charger *sm5451) -{ - u32 input_curr = sm5451_get_ibuslim(sm5451); - - dev_info(sm5451->dev, "%s: IBUSLIM=%dmA\n", __func__, input_curr); - - return input_curr; -} - -static int psy_chg_get_ext_monitor_work(struct sm5451_charger *sm5451) -{ - struct sm_dc_info *sm_dc = select_sm_dc_info(sm5451); - int state = sm_dc_get_current_state(sm_dc); - int adc_vbus, adc_ibus, adc_vbat, adc_ibat, adc_them, adc_tdie; - - if (state < SM_DC_CHECK_VBAT && (sm_dc->chip_id != SM5451_SUB)) { - dev_info(sm5451->dev, "%s: charging off state (state=%d)\n", __func__, state); - return -EINVAL; - } - - adc_vbus = sm5451_convert_adc(sm5451, SM5451_ADC_VBUS); - adc_ibus = sm5451_convert_adc(sm5451, SM5451_ADC_IBUS); - adc_vbat = sm5451_convert_adc(sm5451, SM5451_ADC_VBAT); - adc_ibat = sm5451_convert_adc(sm5451, SM5451_ADC_IBAT); - adc_them = sm5451_convert_adc(sm5451, SM5451_ADC_THEM); - adc_tdie = sm5451_convert_adc(sm5451, SM5451_ADC_TDIE); - - pr_info("sm5451-charger: adc_monitor: vbus:%d:ibus:%d:vbat:%d:ibat:%d:them:%d:tdie:%d\n", - adc_vbus, adc_ibus, adc_vbat, adc_ibat, adc_them, adc_tdie); - sm5451_print_regmap(sm5451); - - return 0; -} - -static int psy_chg_get_ext_measure_input(struct sm5451_charger *sm5451, int index) -{ - struct sm5451_charger *sm5451_sub = NULL; - struct power_supply *psy_dc_sub = NULL; - int adc = 0; - - if (sm5451->chip_id != SM5451_SUB) { - psy_dc_sub = power_supply_get_by_name("sm5451-charger-sub"); - if (!psy_dc_sub) - sm5451_sub = NULL; - else - sm5451_sub = power_supply_get_drvdata(psy_dc_sub); - } - - switch (index) { - case SEC_BATTERY_IIN_MA: - if (sm5451_sub) - adc = sm5451_convert_adc(sm5451_sub, SM5451_ADC_IBUS); - adc += sm5451_convert_adc(sm5451, SM5451_ADC_IBUS); - break; - case SEC_BATTERY_IIN_UA: - if (sm5451_sub) - adc = sm5451_convert_adc(sm5451_sub, SM5451_ADC_IBUS) * 1000; - adc += sm5451_convert_adc(sm5451, SM5451_ADC_IBUS) * 1000; - break; - case SEC_BATTERY_VIN_MA: - adc = sm5451_convert_adc(sm5451, SM5451_ADC_VBUS); - break; - case SEC_BATTERY_VIN_UA: - adc = sm5451_convert_adc(sm5451, SM5451_ADC_VBUS) * 1000; - break; - default: - adc = 0; - break; - } - - dev_info(sm5451->dev, "%s: index=%d, adc=%d\n", __func__, index, adc); - - return adc; -} - -static const char * const sm5451_dc_state_str[] = { - "NO_CHARGING", "DC_ERR", "CHARGING_DONE", "CHECK_VBAT", "PRESET_DC", - "ADJUST_CC", "UPDATE_BAT", "CC_MODE", "CV_MODE", "CV_MAN_MODE" -}; -static int psy_chg_get_ext_direct_charger_chg_status( - struct sm5451_charger *sm5451, union power_supply_propval *val) -{ - struct sm_dc_info *sm_dc = select_sm_dc_info(sm5451); - int state = sm_dc_get_current_state(sm_dc); - - val->strval = sm5451_dc_state_str[state]; - pr_info("%s: CHARGER_STATUS(%s)\n", __func__, val->strval); - - return 0; -} - -static int sm5451_chg_get_property(struct power_supply *psy, - enum power_supply_property psp, union power_supply_propval *val) -{ - struct sm5451_charger *sm5451 = power_supply_get_drvdata(psy); - enum power_supply_ext_property ext_psp = - (enum power_supply_ext_property)psp; - int adc_them; - - dev_info(sm5451->dev, "%s: psp=%d\n", __func__, psp); - - switch ((int)psp) { - case POWER_SUPPLY_PROP_ONLINE: - val->intval = psy_chg_get_online(sm5451); - break; - case POWER_SUPPLY_PROP_STATUS: - val->intval = psy_chg_get_status(sm5451); - break; - case POWER_SUPPLY_PROP_HEALTH: - val->intval = psy_chg_get_health(sm5451); - break; - case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: - val->intval = psy_chg_get_chg_vol(sm5451); - break; - case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: - val->intval = psy_chg_get_input_curr(sm5451); - break; - case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: - val->intval = sm5451->target_ibat; - break; - case POWER_SUPPLY_PROP_TEMP: - adc_them = sm5451_convert_adc(sm5451, SM5451_ADC_THEM); - val->intval = adc_them; - break; -#if IS_ENABLED(CONFIG_DUAL_BATTERY) - case POWER_SUPPLY_PROP_VOLTAGE_NOW: - val->intval = sm5451_convert_adc(sm5451, SM5451_ADC_VBAT); - break; -#endif - case POWER_SUPPLY_EXT_PROP_MIN ... POWER_SUPPLY_EXT_PROP_MAX: - switch (ext_psp) { - case POWER_SUPPLY_EXT_PROP_CHARGING_ENABLED: - val->intval = sm5451_check_charging_enable(sm5451); - break; - case POWER_SUPPLY_EXT_PROP_MONITOR_WORK: - psy_chg_get_ext_monitor_work(sm5451); - break; - case POWER_SUPPLY_EXT_PROP_MEASURE_INPUT: - val->intval = psy_chg_get_ext_measure_input(sm5451, val->intval); - break; - case POWER_SUPPLY_EXT_PROP_MEASURE_SYS: - dev_err(sm5451->dev, "%s: need to works\n", __func__); - /* - * Need to check operation details.. by SEC. - */ - val->intval = -EINVAL; - break; - case POWER_SUPPLY_EXT_PROP_DIRECT_CHARGER_CHG_STATUS: - psy_chg_get_ext_direct_charger_chg_status(sm5451, val); - break; - - case POWER_SUPPLY_EXT_PROP_PASS_THROUGH_MODE: - break; - - case POWER_SUPPLY_EXT_PROP_PASS_THROUGH_MODE_TA_VOL: - break; - - case POWER_SUPPLY_EXT_PROP_D2D_REVERSE_VOLTAGE: - val->intval = sm5451->rev_boost ? 1 : 0; - break; - - case POWER_SUPPLY_EXT_PROP_D2D_REVERSE_OCP: - val->intval = sm5451_get_reverse_boost_ocp(sm5451); - break; - - case POWER_SUPPLY_EXT_PROP_D2D_REVERSE_VBUS: - val->intval = sm5451_convert_adc(sm5451, SM5451_ADC_VBUS); - break; - - case POWER_SUPPLY_EXT_PROP_DC_OP_MODE: - val->intval = sm5451_get_op_mode(sm5451); - break; - default: - return -EINVAL; - } - break; - default: - return -EINVAL; - } - - return 0; -} - -static int psy_chg_set_online(struct sm5451_charger *sm5451, int online) -{ - struct sm_dc_info *sm_dc = select_sm_dc_info(sm5451); - int ret = 0; - - dev_info(sm5451->dev, "%s: online=%d\n", __func__, online); - - if (online < 2) { - if (sm_dc_get_current_state(sm_dc) > SM_DC_EOC) - sm5451_stop_charging(sm5451); - } - sm5451->cable_online = online; - - sm5451->vbus_in = sm5451->cable_online > 2 ? true : false; - - return ret; -} - -static int psy_chg_set_const_chg_voltage(struct sm5451_charger *sm5451, int vbat) -{ - struct sm_dc_info *sm_dc = select_sm_dc_info(sm5451); - int state = sm_dc_get_current_state(sm_dc); - int ret = 0; - - dev_info(sm5451->dev, "%s: [%dmV] to [%dmV]\n", __func__, sm5451->target_vbat, vbat); - - if (sm5451->target_vbat != vbat || state < SM_DC_CHECK_VBAT) { - sm5451->target_vbat = vbat; - ret = sm_dc_set_target_vbat(sm_dc, sm5451->target_vbat); - } - - return ret; -} - -static int psy_chg_set_chg_curr(struct sm5451_charger *sm5451, int ibat) -{ - int ret = 0; - - dev_info(sm5451->dev, "%s: dldn't support cc_loop\n", __func__); - sm5451->target_ibat = ibat; - - return ret; -} - -static int psy_chg_set_input_curr(struct sm5451_charger *sm5451, int ibus) -{ - struct sm_dc_info *sm_dc = select_sm_dc_info(sm5451); - int state = sm_dc_get_current_state(sm_dc); - int ret = 0; - - dev_info(sm5451->dev, "%s: ibus [%dmA] to [%dmA]\n", __func__, sm5451->target_ibus, ibus); - - if (sm5451->target_ibus != ibus || state < SM_DC_CHECK_VBAT) { - sm5451->target_ibus = ibus; - if (sm5451->target_ibus < SM5451_TA_MIN_CURRENT) { - dev_info(sm5451->dev, "%s: can't used less then ta_min_current(%dmA)\n", - __func__, SM5451_TA_MIN_CURRENT); - sm5451->target_ibus = SM5451_TA_MIN_CURRENT; - } - ret = sm_dc_set_target_ibus(sm_dc, sm5451->target_ibus); - } - - return ret; -} - -static int psy_chg_set_const_chg_voltage_max(struct sm5451_charger *sm5451, int max_vbat) -{ - struct sm_dc_info *sm_dc = select_sm_dc_info(sm5451); - - dev_info(sm5451->dev, "%s: max_vbat [%dmA] to [%dmA]\n", - __func__, sm5451->max_vbat, max_vbat); - - sm5451->max_vbat = max_vbat; - sm_dc->config.chg_float_voltage = max_vbat; - - return 0; - -} - -static int psy_chg_ext_wdt_control(struct sm5451_charger *sm5451, int wdt_control) -{ - if (wdt_control) - sm5451->wdt_disable = 1; - else - sm5451->wdt_disable = 0; - - dev_info(sm5451->dev, "%s: wdt_disable=%d\n", __func__, sm5451->wdt_disable); - - return 0; -} - -static int sm5451_chg_set_property(struct power_supply *psy, - enum power_supply_property psp, const union power_supply_propval *val) -{ - struct sm5451_charger *sm5451 = power_supply_get_drvdata(psy); - enum power_supply_ext_property ext_psp = - (enum power_supply_ext_property) psp; - - int ret = 0; - - dev_info(sm5451->dev, "%s: psp=%d, val-intval=%d\n", __func__, psp, val->intval); - - switch ((int)psp) { - case POWER_SUPPLY_PROP_ONLINE: - psy_chg_set_online(sm5451, val->intval); - break; - case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: - ret = psy_chg_set_const_chg_voltage(sm5451, val->intval); - break; - case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: - ret = psy_chg_set_const_chg_voltage_max(sm5451, val->intval); - break; - case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: - ret = psy_chg_set_chg_curr(sm5451, val->intval); - break; - case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: - ret = psy_chg_set_input_curr(sm5451, val->intval); - break; - case POWER_SUPPLY_EXT_PROP_MIN ... POWER_SUPPLY_EXT_PROP_MAX: - switch (ext_psp) { - case POWER_SUPPLY_EXT_PROP_DIRECT_WDT_CONTROL: - ret = psy_chg_ext_wdt_control(sm5451, val->intval); - break; - case POWER_SUPPLY_EXT_PROP_CHARGING_ENABLED: - if (val->intval) - ret = sm5451_start_charging(sm5451); - else - ret = sm5451_stop_charging(sm5451); - - sm5451_print_regmap(sm5451); - break; - case POWER_SUPPLY_EXT_PROP_DIRECT_CURRENT_MAX: - ret = psy_chg_set_input_curr(sm5451, val->intval); - break; - case POWER_SUPPLY_EXT_PROP_DIRECT_ADC_CTRL: - if (val->intval) - sm5451_enable_adc_oneshot(sm5451, 1); - else - sm5451_enable_adc_oneshot(sm5451, 0); - sm5451->force_adc_on = val->intval; - pr_info("%s: ADC_CTRL : %d\n", __func__, val->intval); - break; - - case POWER_SUPPLY_EXT_PROP_PASS_THROUGH_MODE: - pr_info("[PASS_THROUGH] %s: called\n", __func__); - if (val->intval) - ret = sm5451_start_pass_through_charging(sm5451); - else - ret = sm5451_stop_charging(sm5451); - break; - - case POWER_SUPPLY_EXT_PROP_PASS_THROUGH_MODE_TA_VOL: - pr_info("[PASS_THROUGH_VOL] %s: called\n", __func__); - sm5451_set_pass_through_ta_vol(sm5451, val->intval); - break; - - case POWER_SUPPLY_EXT_PROP_D2D_REVERSE_VOLTAGE: - sm5451_reverse_boost_enable(sm5451, val->intval); - break; - - case POWER_SUPPLY_EXT_PROP_ADC_MODE: - if (val->intval) - sm5451_set_adc_mode(sm5451->i2c, SM_DC_ADC_MODE_CONTINUOUS); - else - sm5451_set_adc_mode(sm5451->i2c, SM_DC_ADC_MODE_OFF); - break; - - case POWER_SUPPLY_EXT_PROP_DC_OP_MODE: - if (val->intval == 1) - sm5451_set_op_mode(sm5451, OP_MODE_REV_BOOST); - else if (val->intval == 0) - sm5451_set_op_mode(sm5451, OP_MODE_INIT); - break; - - default: - return -EINVAL; - } - break; - default: - return -EINVAL; - } - - if (ret < 0) - return ret; - - return 0; -} - -static char *sm5451_supplied_to[] = { - "sm5451-charger", -}; - -static enum power_supply_property sm5451_charger_props[] = { - POWER_SUPPLY_PROP_ONLINE, -}; - -static const struct power_supply_desc sm5451_charger_power_supply_desc = { - .name = "sm5451-charger", - .type = POWER_SUPPLY_TYPE_UNKNOWN, - .get_property = sm5451_chg_get_property, - .set_property = sm5451_chg_set_property, - .properties = sm5451_charger_props, - .num_properties = ARRAY_SIZE(sm5451_charger_props), -}; - -static const struct power_supply_desc sm5451_charger_power_supply_sub_desc = { - .name = "sm5451-charger-sub", - .type = POWER_SUPPLY_TYPE_UNKNOWN, - .get_property = sm5451_chg_get_property, - .set_property = sm5451_chg_set_property, - .properties = sm5451_charger_props, - .num_properties = ARRAY_SIZE(sm5451_charger_props), -}; - -static int sm5451_get_adc_value(struct i2c_client *i2c, u8 adc_ch) -{ - struct sm5451_charger *sm5451 = i2c_get_clientdata(i2c); - int adc; - - switch (adc_ch) { - case SM_DC_ADC_THEM: - adc = sm5451_convert_adc(sm5451, SM5451_ADC_THEM); - break; - case SM_DC_ADC_DIETEMP: - adc = sm5451_convert_adc(sm5451, SM5451_ADC_TDIE); - break; - case SM_DC_ADC_VBAT: - adc = sm5451_convert_adc(sm5451, SM5451_ADC_VBAT); - break; - case SM_DC_ADC_IBAT: - adc = sm5451_convert_adc(sm5451, SM5451_ADC_IBAT); - break; - case SM_DC_ADC_VBUS: - adc = sm5451_convert_adc(sm5451, SM5451_ADC_VBUS); - break; - case SM_DC_ADC_IBUS: - adc = sm5451_convert_adc(sm5451, SM5451_ADC_IBUS); - break; - case SM_DC_ADC_VOUT: - default: - adc = 0; - break; - } - - return adc; -} - -static int sm5451_get_charging_enable(struct i2c_client *i2c) -{ - struct sm5451_charger *sm5451 = i2c_get_clientdata(i2c); - - return sm5451_check_charging_enable(sm5451); -} - -static int sm5451_set_charging_enable(struct i2c_client *i2c, bool enable) -{ - struct sm5451_charger *sm5451 = i2c_get_clientdata(i2c); - struct sm_dc_info *sm_dc = select_sm_dc_info(sm5451); - - sm5451_prechg_enable(sm5451, 0); - if (enable) { - if (sm_dc->ta.v_max < SM_DC_BYPASS_TA_MAX_VOL) - sm5451_set_op_mode(sm5451, OP_MODE_FW_BYPASS); - else - sm5451_set_op_mode(sm5451, OP_MODE_FW_BOOST); - } else { - sm5451_set_op_mode(sm5451, OP_MODE_INIT); - } - - sm5451_print_regmap(sm5451); - - return 0; -} - -static int sm5451_dc_set_charging_config(struct i2c_client *i2c, u32 cv_gl, u32 ci_gl, u32 cc_gl) -{ - struct sm5451_charger *sm5451 = i2c_get_clientdata(i2c); - struct sm_dc_info *sm_dc = select_sm_dc_info(sm5451); - u32 vbatreg, ibuslim, freq; - - vbatreg = cv_gl + SM5451_CV_OFFSET; - if (ci_gl <= SM5451_TA_MIN_CURRENT) - ibuslim = ci_gl + (SM5451_CI_OFFSET * 2); - else - ibuslim = ci_gl + SM5451_CI_OFFSET; - - if (ibuslim % 100) - ibuslim = ((ibuslim / 100) * 100) + 100; - - if (ci_gl <= SM5451_SIOP_LEV1) - freq = sm5451->pdata->freq_siop[0]; - else if (ci_gl <= SM5451_SIOP_LEV2) - freq = sm5451->pdata->freq_siop[1]; - else - freq = sm5451->pdata->freq; - - sm5451_set_ibuslim(sm5451, ibuslim); - sm5451_set_vbatreg(sm5451, vbatreg); - sm5451_set_freq(sm5451, freq); - - pr_info("%s %s: vbat_reg=%dmV, ibus_lim=%dmA, freq=%dkHz\n", sm_dc->name, - __func__, vbatreg, ibuslim, SM5451_freq_val[freq]); - - return 0; -} - -static int sm5451_x2bat_dc_set_charging_config(struct i2c_client *i2c, u32 cv_gl, u32 ci_gl, u32 cc_gl) -{ - struct sm5451_charger *sm5451 = i2c_get_clientdata(i2c); - struct sm_dc_info *sm_dc = select_sm_dc_info(sm5451); - u32 vbatreg, ibuslim, freq; - - vbatreg = cv_gl + SM5451_CV_OFFSET; - - if (sm_dc->chip_id == SM5451_SUB) { - if (ci_gl <= SM5451_TA_MIN_CURRENT) - ibuslim = ci_gl + SM_DC_CI_OFFSET_X2BAT + SM5451_CI_OFFSET; - else - ibuslim = ci_gl + SM_DC_CI_OFFSET_X2BAT; - - if (ibuslim % 100) - ibuslim = ((ibuslim / 100) * 100) + 100; - } else { - ibuslim = ((ci_gl - 100) / 100) * 100; - } - - if (ci_gl <= SM5451_SIOP_LEV1) - freq = sm5451->pdata->freq_siop[0]; - else if (ci_gl <= SM5451_SIOP_LEV2) - freq = sm5451->pdata->freq_siop[1]; - else - freq = sm5451->pdata->freq; - - sm5451_set_ibuslim(sm5451, ibuslim); - sm5451_set_vbatreg(sm5451, vbatreg); - sm5451_set_freq(sm5451, freq); - - pr_info("%s %s: vbat_reg=%dmV, ibus_lim=%dmA, freq=%dkHz\n", sm_dc->name, - __func__, vbatreg, ibuslim, SM5451_freq_val[freq]); - - return 0; -} - -static u32 sm5451_get_dc_error_status(struct i2c_client *i2c) -{ - struct sm5451_charger *sm5451 = i2c_get_clientdata(i2c); - struct sm_dc_info *sm_dc = select_sm_dc_info(sm5451); - u8 flag1, flag2, flag3, flag4, op_mode; - u8 flag1_s, flag2_s, flag3_s, flag4_s; - u32 err = SM_DC_ERR_NONE; - int vnow = 0; - - mutex_lock(&sm5451->i2c_lock); - sm5451_read_reg(sm5451, SM5451_REG_FLAG1, &flag1); - sm5451_read_reg(sm5451, SM5451_REG_FLAG2, &flag2); - sm5451_read_reg(sm5451, SM5451_REG_FLAG3, &flag3); - sm5451_read_reg(sm5451, SM5451_REG_FLAG4, &flag4); - pr_info("%s %s: FLAG:0x%x:0x%x:0x%x:0x%x\n", sm_dc->name, - __func__, flag1, flag2, flag3, flag4); - - sm5451_read_reg(sm5451, SM5451_REG_FLAG1, &flag1_s); - sm5451_read_reg(sm5451, SM5451_REG_FLAG2, &flag2_s); - sm5451_read_reg(sm5451, SM5451_REG_FLAG3, &flag3_s); - sm5451_read_reg(sm5451, SM5451_REG_FLAG4, &flag4_s); - op_mode = sm5451_get_op_mode(sm5451); - pr_info("%s %s: FLAG:0x%x:0x%x:0x%x:0x%x op_mode=0x%x\n", sm_dc->name, - __func__, flag1_s, flag2_s, flag3_s, flag4_s, op_mode); - mutex_unlock(&sm5451->i2c_lock); - - if (sm_dc->chip_id != SM5451_SUB) - vnow = sm5451_get_vnow(sm5451); - - if ((op_mode == OP_MODE_INIT) && (sm_dc->wq.retry_cnt < 3) && (sm_dc->chip_id != SM5451_SUB)) { - pr_info("%s %s: try to retry, cnt:%d\n", sm_dc->name, __func__, sm_dc->wq.retry_cnt); - sm_dc->wq.retry_cnt++; - err = SM_DC_ERR_RETRY; - } else if (op_mode == OP_MODE_INIT) { - if ((flag1 & SM5451_FLAG1_IBUSUCP) || (flag1_s & SM5451_FLAG1_IBUSUCP)) - err += SM_DC_ERR_IBUSUCP; - if ((flag3 & SM5451_FLAG3_VBUSUVLO) || (flag3_s & SM5451_FLAG3_VBUSUVLO)) - err += SM_DC_ERR_VBUSUVLO; - if ((flag1 & SM5451_FLAG1_VBUSOVP) || (flag1_s & SM5451_FLAG1_VBUSOVP)) - err += SM_DC_ERR_VBUSOVP; - if ((flag1 & SM5451_FLAG1_IBUSOCP) || (flag1_s & SM5451_FLAG1_IBUSOCP)) - err += SM_DC_ERR_IBUSOCP; - if ((flag2 & SM5451_FLAG2_CNSHTP) || (flag2_s & SM5451_FLAG2_CNSHTP)) - err += SM_DC_ERR_CN_SHORT; - if ((flag3 & SM5451_FLAG3_CFLYSHTP) || (flag3_s & SM5451_FLAG3_CFLYSHTP)) - err += SM_DC_ERR_CFLY_SHORT; - - if (err == SM_DC_ERR_NONE) - err += SM_DC_ERR_UNKNOWN; - - if (err == SM_DC_ERR_UNKNOWN && sm_dc->chip_id == SM5451_SUB) - pr_info("%s %s: SM_DC_ERR_NONE\n", sm_dc->name, __func__); - else - pr_info("%s %s: SM_DC_ERR(err=0x%x)\n", sm_dc->name, __func__, err); - } else { - if (flag3_s & SM5451_FLAG3_VBUSUVLO) { - pr_info("%s %s: vbus uvlo detected, try to retry\n", sm_dc->name, __func__); - err = SM_DC_ERR_RETRY; - } else if ((flag2 & SM5451_FLAG2_VBATREG) || (flag2_s & SM5451_FLAG2_VBATREG) || - (sm_dc->target_vbat <= vnow)) { - pr_info("%s %s: VBATREG detected\n", sm_dc->name, __func__); - err = SM_DC_ERR_VBATREG; - } else if (flag4_s & SM5451_FLAG4_IBUSREG) { - pr_info("%s %s: IBUSREG detected\n", sm_dc->name, __func__); - err = SM_DC_ERR_IBUSREG; - } else if (vnow < 0) { - err = SM_DC_ERR_INVAL_VBAT; - pr_info("%s %s: SM_DC_ERR(err=0x%x)\n", sm_dc->name, __func__, err); - } - } - - if (!sm5451->wdt_disable) - sm5451_kick_wdt(sm5451); - - return err; -} - -static int sm5451_send_pd_msg(struct i2c_client *i2c, struct sm_dc_power_source_info *ta) -{ - struct sm5451_charger *sm5451 = i2c_get_clientdata(i2c); - struct sm_dc_info *sm_dc = select_sm_dc_info(sm5451); - int ret; - - mutex_lock(&sm5451->pd_lock); - - ret = sec_pd_select_pps(ta->pdo_pos, ta->v, ta->c); - if (ret == -EBUSY) { - pr_info("%s %s: request again\n", sm_dc->name, __func__); - msleep(100); - ret = sec_pd_select_pps(ta->pdo_pos, ta->v, ta->c); - } - - mutex_unlock(&sm5451->pd_lock); - - return ret; - } - -static int sm5451_get_apdo_max_power(struct i2c_client *i2c, struct sm_dc_power_source_info *ta) -{ - struct sm5451_charger *sm5451 = i2c_get_clientdata(i2c); - struct sm_dc_info *sm_dc = select_sm_dc_info(sm5451); - int ret; - - ta->pdo_pos = 0; /* set '0' else return error */ - ta->v_max = 10000; /* request voltage level */ - ta->c_max = 0; - ta->p_max = 0; - - ret = sec_pd_get_apdo_max_power(&ta->pdo_pos, &ta->v_max, &ta->c_max, &ta->p_max); - if (ret < 0) { - dev_err(sm5451->dev, "%s: error:sec_pd_get_apdo_max_power\n", __func__); - } else { - sm_dc->ta.pdo_pos = ta->pdo_pos; - sm_dc->ta.v_max = ta->v_max; - sm_dc->ta.c_max = ta->c_max; - sm_dc->ta.p_max = ta->p_max; - } - - dev_info(sm5451->dev, "%s: pdo_pos:%d, max_vol:%dmV, max_cur:%dmA, max_pwr:%dmW\n", - __func__, ta->pdo_pos, ta->v_max, ta->c_max, ta->p_max); - return ret; -} - - -static u32 sm5451_get_target_ibus(struct i2c_client *i2c) -{ - struct sm5451_charger *sm5451 = i2c_get_clientdata(i2c); - - dev_info(sm5451->dev, "%s: %dmA\n", __func__, sm5451->target_ibus); - return sm5451->target_ibus; -} - -static const struct sm_dc_ops sm5451_dc_pps_ops = { - .get_adc_value = sm5451_get_adc_value, - .set_adc_mode = sm5451_set_adc_mode, - .get_charging_enable = sm5451_get_charging_enable, - .get_dc_error_status = sm5451_get_dc_error_status, - .set_charging_enable = sm5451_set_charging_enable, - .set_charging_config = sm5451_dc_set_charging_config, - .send_power_source_msg = sm5451_send_pd_msg, - .get_apdo_max_power = sm5451_get_apdo_max_power, - .get_target_ibus = sm5451_get_target_ibus, -}; - -static const struct sm_dc_ops sm5451_x2bat_dc_pps_ops = { - .get_adc_value = sm5451_get_adc_value, - .set_adc_mode = sm5451_set_adc_mode, - .get_charging_enable = sm5451_get_charging_enable, - .get_dc_error_status = sm5451_get_dc_error_status, - .set_charging_enable = sm5451_set_charging_enable, - .set_charging_config = sm5451_x2bat_dc_set_charging_config, - .send_power_source_msg = sm5451_send_pd_msg, - .get_apdo_max_power = sm5451_get_apdo_max_power, - .get_target_ibus = sm5451_get_target_ibus, -}; - -static irqreturn_t sm5451_irq_thread(int irq, void *data) -{ - struct sm5451_charger *sm5451 = (struct sm5451_charger *)data; - struct sm_dc_info *sm_dc = select_sm_dc_info(sm5451); - u8 op_mode = sm5451_get_op_mode(sm5451); - u8 flag1, flag2, flag3, flag4; - u32 err = 0x0; - - sm5451_read_reg(sm5451, SM5451_REG_FLAG1, &flag1); - sm5451_read_reg(sm5451, SM5451_REG_FLAG2, &flag2); - sm5451_read_reg(sm5451, SM5451_REG_FLAG3, &flag3); - sm5451_read_reg(sm5451, SM5451_REG_FLAG4, &flag4); - dev_info(sm5451->dev, "%s: FLAG:0x%x:0x%x:0x%x:0x%x\n", - __func__, flag1, flag2, flag3, flag4); - - /* check forced CUT-OFF status */ - if (sm_dc_get_current_state(sm_dc) > SM_DC_PRESET && - op_mode == OP_MODE_INIT) { - if (flag1 & SM5451_FLAG1_VBUSOVP) - err += SM_DC_ERR_VBUSOVP; - - if (flag1 & SM5451_FLAG1_IBUSOCP) - err += SM_DC_ERR_IBUSOCP; - - if (flag1 & SM5451_FLAG1_IBUSUCP) - err += SM_DC_ERR_IBUSUCP; - - if (flag2 & SM5451_FLAG2_VBATOVP) - err += SM_DC_ERR_VBATOVP; - -/* un-used IBATOCP protection - * if (flag2 & SM5451_FLAG2_IBATOCP) - * err += SM_DC_ERR_IBATOCP; - */ - if (flag2 & SM5451_FLAG2_TSD) - err += SM_DC_ERR_TSD; - - if (flag2 & SM5451_FLAG2_RLTVOVP) - err += SM_DC_ERR_STUP_FAIL; - - if (flag2 & SM5451_FLAG2_RLTVUVP) - err += SM_DC_ERR_STUP_FAIL; - - if (flag2 & SM5451_FLAG2_CNSHTP) - err += SM_DC_ERR_CN_SHORT; - - if (flag3 & SM5451_FLAG3_VBUSUVLO) - err += SM_DC_ERR_VBUSUVLO; - - if (flag3 & SM5451_FLAG3_CFLYSHTP) - err += SM_DC_ERR_CFLY_SHORT; - - dev_err(sm5451->dev, "%s: forced charge cut-off(err=0x%x)\n", __func__, err); - sm_dc_report_error_status(sm_dc, err); - } - - if (flag2 & SM5451_FLAG2_VBATREG) { - dev_info(sm5451->dev, "%s: VBATREG detected\n", __func__); - sm_dc_report_interrupt_event(sm_dc, SM_DC_INT_VBATREG); - } - if (flag2 & SM5451_FLAG2_IBATREG) - dev_info(sm5451->dev, "%s: IBATREG detected\n", __func__); - - if (flag4 & SM5451_FLAG4_IBUSREG) - dev_info(sm5451->dev, "%s: IBUSREG detected\n", __func__); - - if (flag3 & SM5451_FLAG3_VBUSPOK) - dev_info(sm5451->dev, "%s: VBUSPOK detected\n", __func__); - - if (flag3 & SM5451_FLAG3_VBUSUVLO) - dev_info(sm5451->dev, "%s: VBUSUVLO detected\n", __func__); - - if (flag3 & SM5451_FLAG3_WTDTMR) { - dev_info(sm5451->dev, "%s: Watchdog Timer expired\n", __func__); - sm_dc_report_interrupt_event(sm_dc, SM_DC_INT_WDTOFF); - } - - dev_info(sm5451->dev, "closed %s\n", __func__); - - return IRQ_HANDLED; -} - -static int sm5451_irq_init(struct sm5451_charger *sm5451) -{ - int ret; - u8 reg; - - sm5451->irq = gpio_to_irq(sm5451->pdata->irq_gpio); - dev_info(sm5451->dev, "%s: irq_gpio=%d, irq=%d\n", __func__, - sm5451->pdata->irq_gpio, sm5451->irq); - - ret = gpio_request(sm5451->pdata->irq_gpio, "sm5540_irq"); - if (ret) { - dev_err(sm5451->dev, "%s: fail to request gpio(ret=%d)\n", - __func__, ret); - return ret; - } - gpio_direction_input(sm5451->pdata->irq_gpio); - gpio_free(sm5451->pdata->irq_gpio); - - sm5451_write_reg(sm5451, SM5451_REG_FLAGMSK1, 0xE2); - sm5451_write_reg(sm5451, SM5451_REG_FLAGMSK2, 0x00); - sm5451_write_reg(sm5451, SM5451_REG_FLAGMSK3, 0xD6); - sm5451_write_reg(sm5451, SM5451_REG_FLAGMSK4, 0xDA); - sm5451_read_reg(sm5451, SM5451_REG_FLAG1, ®); - sm5451_read_reg(sm5451, SM5451_REG_FLAG2, ®); - sm5451_read_reg(sm5451, SM5451_REG_FLAG3, ®); - sm5451_read_reg(sm5451, SM5451_REG_FLAG4, ®); - - ret = request_threaded_irq(sm5451->irq, NULL, sm5451_irq_thread, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, - "sm5451-irq", sm5451); - if (ret) { - dev_err(sm5451->dev, "%s: fail to request irq(ret=%d)\n", - __func__, ret); - return ret; - } - - return 0; -} - -static void sm5451_hw_init_config(struct sm5451_charger *sm5451) -{ - int ret; - u8 reg; - - /* check to valid I2C transfer & register control */ - ret = sm5451_read_reg(sm5451, SM5451_REG_DEVICE_ID, ®); - if (ret < 0 || (reg & 0xF) != 0x1) { - dev_err(sm5451->dev, "%s: device not found on this channel (reg=0x%x)\n", - __func__, reg); - } - sm5451->pdata->rev_id = (reg >> 4) & 0xf; - - sm5451_init_reg_param(sm5451); - -#if IS_ENABLED(CONFIG_BATTERY_SAMSUNG) - psy_chg_set_const_chg_voltage(sm5451, sm5451->pdata->battery.chg_float_voltage); - sm5451_reverse_boost_enable(sm5451, false); -#endif -} - -#if defined(CONFIG_OF) -static int sm5451_charger_parse_dt(struct device *dev, - struct sm5451_platform_data *pdata) -{ - struct device_node *np_sm5451 = dev->of_node; - struct device_node *np_battery; - int ret; - - /* Parse: sm5451 node */ - if (!np_sm5451) { - dev_err(dev, "%s: empty of_node for sm5451_dev\n", __func__); - return -EINVAL; - } - pdata->irq_gpio = of_get_named_gpio(np_sm5451, "sm5451,irq-gpio", 0); - dev_info(dev, "parse_dt: irq_gpio=%d\n", pdata->irq_gpio); - - ret = of_property_read_u32(np_sm5451, "sm5451,pps_lr", &pdata->pps_lr); - if (ret) { - dev_info(dev, "%s: sm5451,pps_lr is Empty\n", __func__); - pdata->pps_lr = 340000; - } - dev_info(dev, "parse_dt: pps_lr=%d\n", pdata->pps_lr); - - ret = of_property_read_u32(np_sm5451, "sm5451,rpcm", &pdata->rpcm); - if (ret) { - dev_info(dev, "%s: sm5451,rpcm is Empty\n", __func__); - pdata->rpcm = 55000; - } - dev_info(dev, "parse_dt: rpcm=%d\n", pdata->rpcm); - - ret = of_property_read_u32(np_sm5451, "sm5451,r_ttl", &pdata->r_ttl); - if (ret) { - dev_info(dev, "%s: sm5451,r_ttl is Empty\n", __func__); - pdata->r_ttl = 99000; - } - dev_info(dev, "parse_dt: r_ttl=%d\n", pdata->r_ttl); - - ret = of_property_read_u32(np_sm5451, "sm5451,freq", &pdata->freq); - if (ret) { - dev_info(dev, "%s: sm5451,freq is Empty\n", __func__); - pdata->freq = SM5451_FREQ_750KHZ; - } - dev_info(dev, "parse_dt: freq=%dkHz\n", SM5451_freq_val[pdata->freq]); - - ret = of_property_read_u32(np_sm5451, "sm5451,freq_byp", &pdata->freq_byp); - if (ret) { - dev_info(dev, "%s: sm5451,freq_byp is Empty\n", __func__); - pdata->freq_byp = SM5451_FREQ_375KHZ; - } - dev_info(dev, "parse_dt: freq_byp=%dkHz\n", SM5451_freq_val[pdata->freq_byp]); - - ret = of_property_read_u32_array(np_sm5451, "sm5451,freq_siop", pdata->freq_siop, 2); - if (ret) { - dev_info(dev, "%s: sm5451,freq_siop is Empty\n", __func__); - pdata->freq_siop[0] = SM5451_FREQ_200KHZ; - pdata->freq_siop[1] = SM5451_FREQ_375KHZ; - } - dev_info(dev, "parse_dt: freq_siop=%dkHz, %dkHz\n", - SM5451_freq_val[pdata->freq_siop[0]], SM5451_freq_val[pdata->freq_siop[1]]); - - ret = of_property_read_u32(np_sm5451, "sm5451,topoff", &pdata->topoff); - if (ret) { - dev_info(dev, "%s: sm5451,topoff is Empty\n", __func__); - pdata->topoff = 900; - } - dev_info(dev, "parse_dt: topoff=%d\n", pdata->topoff); - - ret = of_property_read_u32(np_sm5451, "sm5451,x2bat_mode", &pdata->x2bat_mode); - if (ret) { - dev_info(dev, "%s: sm5451,x2bat_mode is Empty\n", __func__); - pdata->x2bat_mode = 0; - } - dev_info(dev, "parse_dt: x2bat_mode=%d\n", pdata->x2bat_mode); - - ret = of_property_read_u32(np_sm5451, "sm5451,en_vbatreg", &pdata->en_vbatreg); - if (ret) { - dev_info(dev, "%s: sm5451,en_vbatreg is Empty\n", __func__); - pdata->en_vbatreg = 0; - } - dev_info(dev, "parse_dt: en_vbatreg=%d\n", pdata->en_vbatreg); - - /* Parse: battery node */ - np_battery = of_find_node_by_name(NULL, "battery"); - if (!np_battery) { - dev_err(dev, "%s: empty of_node for battery\n", __func__); - return -EINVAL; - } - ret = of_property_read_u32(np_battery, "battery,chg_float_voltage", - &pdata->battery.chg_float_voltage); - if (ret) { - dev_info(dev, "%s: battery,chg_float_voltage is Empty\n", __func__); - pdata->battery.chg_float_voltage = 4200; - } - ret = of_property_read_string(np_battery, "battery,charger_name", - (char const **)&pdata->battery.sec_dc_name); - if (ret) { - dev_info(dev, "%s: battery,charger_name is Empty\n", __func__); - pdata->battery.sec_dc_name = "sec-direct-charger"; - } - ret = of_property_read_string(np_battery, "battery,fuelgauge_name", - (char const **)&pdata->battery.fuelgauge_name); - if (ret) { - dev_info(dev, "%s: battery,fuelgauge_name is Empty\n", __func__); - pdata->battery.fuelgauge_name = "sec-fuelgauge"; - } - - dev_info(dev, "parse_dt: float_v=%d, sec_dc_name=%s, fuelgauge_name=%s\n", - pdata->battery.chg_float_voltage, pdata->battery.sec_dc_name, - pdata->battery.fuelgauge_name); - - return 0; -} -#endif /* CONFIG_OF */ - -enum { - ADDR = 0, - SIZE, - DATA, - UPDATE, - TA_MIN, -}; -static ssize_t chg_show_attrs(struct device *dev, - struct device_attribute *attr, char *buf); -static ssize_t chg_store_attrs(struct device *dev, - struct device_attribute *attr, -const char *buf, size_t count); -#define CHARGER_ATTR(_name) \ -{ \ - .attr = {.name = #_name, .mode = 0660}, \ - .show = chg_show_attrs, \ - .store = chg_store_attrs, \ -} -static struct device_attribute charger_attrs[] = { - CHARGER_ATTR(addr), - CHARGER_ATTR(size), - CHARGER_ATTR(data), - CHARGER_ATTR(update), - CHARGER_ATTR(ta_min_v), -}; -static int chg_create_attrs(struct device *dev) -{ - int i, rc; - - for (i = 0; i < (int)ARRAY_SIZE(charger_attrs); i++) { - rc = device_create_file(dev, &charger_attrs[i]); - if (rc) - goto create_attrs_failed; - } - return rc; - -create_attrs_failed: - dev_err(dev, "%s: failed (%d)\n", __func__, rc); - while (i--) - device_remove_file(dev, &charger_attrs[i]); - return rc; -} - -static ssize_t chg_show_attrs(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct sm5451_charger *sm5451 = dev_get_drvdata(dev->parent); - struct sm_dc_info *sm_dc = select_sm_dc_info(sm5451); - const ptrdiff_t offset = attr - charger_attrs; - int i = 0; - u8 addr; - u8 val; - - switch (offset) { - case ADDR: - i += sprintf(buf, "0x%x\n", sm5451->addr); - break; - case SIZE: - i += sprintf(buf, "0x%x\n", sm5451->size); - break; - case DATA: - for (addr = sm5451->addr; addr < (sm5451->addr+sm5451->size); addr++) { - sm5451_read_reg(sm5451, addr, &val); - i += scnprintf(buf + i, PAGE_SIZE - i, - "0x%04x : 0x%02x\n", addr, val); - } - break; - case TA_MIN: - i += sprintf(buf, "%d\n", sm_dc->config.ta_min_voltage); - break; - default: - return -EINVAL; - } - return i; -} - -static ssize_t chg_store_attrs(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sm5451_charger *sm5451 = dev_get_drvdata(dev->parent); - struct sm_dc_info *sm_dc = select_sm_dc_info(sm5451); - const ptrdiff_t offset = attr - charger_attrs; - int ret = 0; - int x, y, z, k; - - switch (offset) { - case ADDR: - if (sscanf(buf, "0x%4x\n", &x) == 1) - sm5451->addr = x; - ret = count; - break; - case SIZE: - if (sscanf(buf, "%5d\n", &x) == 1) - sm5451->size = x; - ret = count; - break; - case DATA: - if (sscanf(buf, "0x%8x 0x%8x", &x, &y) == 2) { - if ((x >= SM5451_REG_CNTL1 && x <= SM5451_REG_REG1) || - (x >= SM5451_REG_ADC_CNTL && x <= SM5451_REG_TOPOFF)) { - u8 addr = x; - u8 data = y; - - if (sm5451_write_reg(sm5451, addr, data) < 0) { - dev_info(sm5451->dev, - "%s: addr: 0x%x write fail\n", __func__, addr); - } - } else { - dev_info(sm5451->dev, - "%s: addr: 0x%x is wrong\n", __func__, x); - } - } - ret = count; - break; - case UPDATE: - if (sscanf(buf, "0x%8x 0x%8x 0x%8x %d", &x, &y, &z, &k) == 4) { - if ((x >= SM5451_REG_CNTL1 && x <= SM5451_REG_REG1) || - (x >= SM5451_REG_ADC_CNTL && x <= SM5451_REG_TOPOFF)) { - u8 addr = x, data = y, val = z, pos = k; - - if (sm5451_update_reg(sm5451, addr, data, val, pos)) { - dev_info(sm5451->dev, - "%s: addr: 0x%x write fail\n", __func__, addr); - } - } else { - dev_info(sm5451->dev, - "%s: addr: 0x%x is wrong\n", __func__, x); - } - } - ret = count; - break; - case TA_MIN: - if (sscanf(buf, "%5d\n", &x) == 1) - sm_dc->config.ta_min_voltage = x; - ret = count; - break; - default: - ret = -EINVAL; - } - return ret; -} - -static int sm5451_dbg_read_reg(void *data, u64 *val) -{ - struct sm5451_charger *sm5451 = data; - int ret; - u8 reg; - - ret = sm5451_read_reg(sm5451, sm5451->debug_address, ®); - if (ret < 0) { - dev_err(sm5451->dev, "%s: failed read 0x%02x\n", - __func__, sm5451->debug_address); - return ret; - } - *val = reg; - - return 0; -} - -static int sm5451_dbg_write_reg(void *data, u64 val) -{ - struct sm5451_charger *sm5451 = data; - int ret; - - ret = sm5451_write_reg(sm5451, sm5451->debug_address, (u8)val); - if (ret < 0) { - dev_err(sm5451->dev, "%s: failed write 0x%02x to 0x%02x\n", - __func__, (u8)val, sm5451->debug_address); - return ret; - } - - return 0; -} -DEFINE_SIMPLE_ATTRIBUTE(register_debug_ops, sm5451_dbg_read_reg, - sm5451_dbg_write_reg, "0x%02llx\n"); - -static int sm5451_create_debugfs_entries(struct sm5451_charger *sm5451) -{ - struct dentry *ent; - - sm5451->debug_root = debugfs_create_dir("charger-sm5451", NULL); - if (!sm5451->debug_root) { - dev_err(sm5451->dev, "%s: can't create dir\n", __func__); - return -ENOENT; - } - - debugfs_create_x32("address", 0644, - sm5451->debug_root, &(sm5451->debug_address)); - - ent = debugfs_create_file("data", 0644, - sm5451->debug_root, sm5451, ®ister_debug_ops); - if (!ent) { - dev_err(sm5451->dev, "%s: can't create data\n", __func__); - return -ENOENT; - } - - return 0; -} - -static const struct i2c_device_id sm5451_charger_id_table[] = { - { "sm5451-charger", .driver_data = SM5451_MAIN }, - { "sm5451-charger-sub", .driver_data = SM5451_SUB}, - { } -}; -MODULE_DEVICE_TABLE(i2c, sm5451_charger_id_table); - -#if defined(CONFIG_OF) -static const struct of_device_id sm5451_of_match_table[] = { - { .compatible = "siliconmitus,sm5451", .data = (void *)SM5451_MAIN }, - { .compatible = "siliconmitus,sm5451-sub", .data = (void *)SM5451_SUB }, - { }, -}; -MODULE_DEVICE_TABLE(of, sm5451_of_match_table); -#endif /* CONFIG_OF */ - -static int sm5451_charger_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) -{ - struct sm5451_charger *sm5451; - struct sm_dc_info *pps_dc, *x2bat_dc; - struct sm5451_platform_data *pdata; - struct power_supply_config psy_cfg = {}; - const struct of_device_id *of_id; - int ret, chip; - - dev_info(&i2c->dev, "%s: probe start\n", __func__); - - of_id = of_match_device(sm5451_of_match_table, &i2c->dev); - if (!of_id) { - dev_info(&i2c->dev, "sm5451-Charger matching on node name, compatible is preferred\n"); - chip = (enum sm5451_chip_id)id->driver_data; - } else { - chip = (enum sm5451_chip_id)of_id->data; - } - dev_info(&i2c->dev, "%s: chip:%d\n", __func__, chip); - - sm5451 = devm_kzalloc(&i2c->dev, sizeof(struct sm5451_charger), GFP_KERNEL); - if (!sm5451) - return -ENOMEM; - -#if defined(CONFIG_OF) - pdata = devm_kzalloc(&i2c->dev, sizeof(struct sm5451_platform_data), GFP_KERNEL); - if (!pdata) - return -ENOMEM; - - ret = sm5451_charger_parse_dt(&i2c->dev, pdata); - if (ret < 0) { - dev_err(&i2c->dev, "%s: fail to parse_dt\n", __func__); - pdata = NULL; - } -#else /* CONFIG_OF */ - pdata = NULL; -#endif /* CONFIG_OF */ - if (!pdata) { - dev_err(&i2c->dev, "%s: we didn't support fixed platform_data yet\n", __func__); - return -EINVAL; - } - - /* create sm direct-charging instance for PD3.0(PPS) */ - if (chip == SM5451_SUB) - pps_dc = sm_dc_create_pd_instance("sm5451-sub-DC", i2c); - else - pps_dc = sm_dc_create_pd_instance("sm5451-PD-DC", i2c); - if (IS_ERR(pps_dc)) { - dev_err(&i2c->dev, "%s: fail to create PD-DC module\n", __func__); - return -ENOMEM; - } - pps_dc->config.ta_min_current = SM5451_TA_MIN_CURRENT; - pps_dc->config.ta_min_voltage = 8200; - pps_dc->config.dc_min_vbat = 3100; - pps_dc->config.dc_vbus_ovp_th = 11000; - pps_dc->config.pps_lr = pdata->pps_lr; - pps_dc->config.rpara = 150000; - pps_dc->config.rsns = 0; - pps_dc->config.rpcm = pdata->rpcm; - pps_dc->config.r_ttl = pdata->r_ttl; - pps_dc->config.topoff_current = pdata->topoff; - pps_dc->config.need_to_sw_ocp = 0; - pps_dc->config.support_pd_remain = 1; /* if pdic can't support PPS remaining, plz activate it. */ - pps_dc->config.chg_float_voltage = pdata->battery.chg_float_voltage; - pps_dc->config.sec_dc_name = pdata->battery.sec_dc_name; - pps_dc->ops = &sm5451_dc_pps_ops; - pps_dc->chip_id = chip; - ret = sm_dc_verify_configuration(pps_dc); - if (ret < 0) { - dev_err(&i2c->dev, "%s: fail to verify sm_dc(ret=%d)\n", __func__, ret); - goto err_devmem; - } - sm5451->pps_dc = pps_dc; - - if (pdata->x2bat_mode) { - if (chip == SM5451_SUB) - x2bat_dc = sm_dc_create_x2bat_instance("sm5451-x2sub-DC", i2c); - else - x2bat_dc = sm_dc_create_x2bat_instance("sm5451-x2PD-DC", i2c); - if (IS_ERR(x2bat_dc)) { - dev_err(&i2c->dev, "%s: fail to create PD-DC module\n", __func__); - return -ENOMEM; - } - x2bat_dc->config.ta_min_current = SM5451_TA_MIN_CURRENT; - x2bat_dc->config.ta_min_voltage = 8200; - x2bat_dc->config.dc_min_vbat = 3100; - x2bat_dc->config.dc_vbus_ovp_th = 11000; - x2bat_dc->config.r_ttl = pdata->r_ttl; - x2bat_dc->config.topoff_current = pdata->topoff; - x2bat_dc->config.need_to_sw_ocp = 0; - x2bat_dc->config.support_pd_remain = 1; /* if pdic can't support PPS remaining, plz activate it. */ - x2bat_dc->config.chg_float_voltage = pdata->battery.chg_float_voltage; - x2bat_dc->config.sec_dc_name = pdata->battery.sec_dc_name; - x2bat_dc->ops = &sm5451_x2bat_dc_pps_ops; - x2bat_dc->chip_id = chip; - ret = sm_dc_verify_configuration(x2bat_dc); - if (ret < 0) { - dev_err(&i2c->dev, "%s: fail to verify sm_dc(ret=%d)\n", __func__, ret); - goto err_devmem; - } - } else { - x2bat_dc = NULL; - } - sm5451->x2bat_dc = x2bat_dc; - - sm5451->dev = &i2c->dev; - sm5451->i2c = i2c; - sm5451->pdata = pdata; - sm5451->chip_id = chip; - mutex_init(&sm5451->i2c_lock); - mutex_init(&sm5451->pd_lock); - sm5451->chg_ws = wakeup_source_register(&i2c->dev, "sm5451-charger"); - i2c_set_clientdata(i2c, sm5451); - - sm5451_hw_init_config(sm5451); - - psy_cfg.drv_data = sm5451; - psy_cfg.supplied_to = sm5451_supplied_to; - psy_cfg.num_supplicants = ARRAY_SIZE(sm5451_supplied_to); - if (chip == SM5451_SUB) - sm5451->psy_chg = power_supply_register(sm5451->dev, - &sm5451_charger_power_supply_sub_desc, &psy_cfg); - else - sm5451->psy_chg = power_supply_register(sm5451->dev, - &sm5451_charger_power_supply_desc, &psy_cfg); - if (IS_ERR(sm5451->psy_chg)) { - dev_err(sm5451->dev, "%s: fail to register psy_chg\n", __func__); - ret = PTR_ERR(sm5451->psy_chg); - goto err_devmem; - } - sec_chg_set_dev_init(SC_DEV_DIR_CHG); - - if (sm5451->pdata->irq_gpio >= 0) { - ret = sm5451_irq_init(sm5451); - if (ret < 0) { - dev_err(sm5451->dev, "%s: fail to init irq(ret=%d)\n", __func__, ret); - goto err_psy_chg; - } - } else { - dev_warn(sm5451->dev, "%s: didn't assigned irq_gpio\n", __func__); - } - - ret = chg_create_attrs(&sm5451->psy_chg->dev); - if (ret) - dev_err(sm5451->dev, "%s : Failed to create_attrs\n", __func__); - - ret = sm5451_create_debugfs_entries(sm5451); - if (ret < 0) { - dev_err(sm5451->dev, "%s: fail to create debugfs(ret=%d)\n", __func__, ret); - goto err_psy_chg; - } - - dev_info(sm5451->dev, "%s: done. (rev_id=0x%x)[%s]\n", __func__, - sm5451->pdata->rev_id, SM5451_DC_VERSION); - - return 0; - -err_psy_chg: - power_supply_unregister(sm5451->psy_chg); - -err_devmem: - mutex_destroy(&sm5451->i2c_lock); - mutex_destroy(&sm5451->pd_lock); - wakeup_source_unregister(sm5451->chg_ws); - sm_dc_destroy_instance(sm5451->pps_dc); - sm_dc_destroy_instance(sm5451->x2bat_dc); - - return ret; -} - -static int sm5451_charger_remove(struct i2c_client *i2c) -{ - struct sm5451_charger *sm5451 = i2c_get_clientdata(i2c); - - sm5451_stop_charging(sm5451); - sm5451_sw_reset(sm5451); - - power_supply_unregister(sm5451->psy_chg); - mutex_destroy(&sm5451->i2c_lock); - mutex_destroy(&sm5451->pd_lock); - wakeup_source_unregister(sm5451->chg_ws); - sm_dc_destroy_instance(sm5451->pps_dc); - sm_dc_destroy_instance(sm5451->x2bat_dc); - - return 0; -} - -static void sm5451_charger_shutdown(struct i2c_client *i2c) -{ - struct sm5451_charger *sm5451 = i2c_get_clientdata(i2c); - - sm5451_stop_charging(sm5451); - sm5451_reverse_boost_enable(sm5451, false); -} - -#if defined(CONFIG_PM) -static int sm5451_charger_suspend(struct device *dev) -{ - struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); - struct sm5451_charger *sm5451 = i2c_get_clientdata(i2c); - - if (device_may_wakeup(dev)) - enable_irq_wake(sm5451->irq); - - disable_irq(sm5451->irq); - - return 0; -} - -static int sm5451_charger_resume(struct device *dev) -{ - struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); - struct sm5451_charger *sm5451 = i2c_get_clientdata(i2c); - - if (device_may_wakeup(dev)) - disable_irq_wake(sm5451->irq); - - enable_irq(sm5451->irq); - - return 0; -} -#else /* CONFIG_PM */ -#define sm5451_charger_suspend NULL -#define sm5451_charger_resume NULL -#endif /* CONFIG_PM */ - -const struct dev_pm_ops sm5451_pm_ops = { - .suspend = sm5451_charger_suspend, - .resume = sm5451_charger_resume, -}; - -static struct i2c_driver sm5451_charger_driver = { - .driver = { - .name = "sm5451-charger", - .owner = THIS_MODULE, -#if defined(CONFIG_OF) - .of_match_table = sm5451_of_match_table, -#endif /* CONFIG_OF */ -#if defined(CONFIG_PM) - .pm = &sm5451_pm_ops, -#endif /* CONFIG_PM */ - }, - .probe = sm5451_charger_probe, - .remove = sm5451_charger_remove, - .shutdown = sm5451_charger_shutdown, - .id_table = sm5451_charger_id_table, -}; - -static int __init sm5451_i2c_init(void) -{ - pr_info("sm5451-charger: %s\n", __func__); - return i2c_add_driver(&sm5451_charger_driver); -} -module_init(sm5451_i2c_init); - -static void __exit sm5451_i2c_exit(void) -{ - i2c_del_driver(&sm5451_charger_driver); -} -module_exit(sm5451_i2c_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("SiliconMitus "); -MODULE_DESCRIPTION("Charger driver for SM5451"); -MODULE_VERSION(SM5451_DC_VERSION); diff --git a/drivers/battery/charger/sm5451_charger/sm5451_charger.dtsi b/drivers/battery/charger/sm5451_charger/sm5451_charger.dtsi deleted file mode 100755 index c2b3bd4db..000000000 --- a/drivers/battery/charger/sm5451_charger/sm5451_charger.dtsi +++ /dev/null @@ -1,13 +0,0 @@ -&hsi2c_5 { - status = "okay"; - - sm5451_charger: sm5451@63 { - compatible = "siliconmitus,sm5451"; - reg = <0x63>; - }; -}; - -/* /home/dpi/qb5_8814/workspace/P4_1716/android/kernel/kmodule/battery/suwon/charger/sm5451/sm5451_charger.a53x.dtsi */ -&sm5451_charger { - sm5451,freq_byp = <0x1>; /* 375kHz */ -}; diff --git a/drivers/battery/charger/sm5451_charger/sm5451_charger.h b/drivers/battery/charger/sm5451_charger/sm5451_charger.h deleted file mode 100755 index 32b688e44..000000000 --- a/drivers/battery/charger/sm5451_charger/sm5451_charger.h +++ /dev/null @@ -1,222 +0,0 @@ -/* - * sm5451_charger.h - SM5451 Charger device driver for SAMSUNG platform - * - * Copyright (C) 2020 SiliconMitus Co.Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include "sm5451_direct_charger.h" - -#ifndef __SM5451_CHARGER_H__ -#define __SM5451_CHARGER_H__ - -#define SM5451_TA_MIN_CURRENT 1000 -#define SM5451_CV_OFFSET 0 -#define SM5451_CI_OFFSET 300 -#define SM5451_SIOP_LEV1 1100 -#define SM5451_SIOP_LEV2 1700 - -enum SM5451_flag1_desc { - SM5451_FLAG1_VBUSPD = 1 << 5, - SM5451_FLAG1_VDSQRB = 1 << 4, - SM5451_FLAG1_VBUSOVP = 1 << 3, - SM5451_FLAG1_IBUSOCP = 1 << 2, - SM5451_FLAG1_CHGON = 1 << 1, - SM5451_FLAG1_IBUSUCP = 1 << 0, -}; - -enum SM5451_flag2_desc { - SM5451_FLAG2_VBATOVP = 1 << 7, - SM5451_FLAG2_IBATOCP = 1 << 6, - SM5451_FLAG2_VBATREG = 1 << 5, - SM5451_FLAG2_IBATREG = 1 << 4, - SM5451_FLAG2_TSD = 1 << 3, - SM5451_FLAG2_RLTVUVP = 1 << 2, - SM5451_FLAG2_RLTVOVP = 1 << 1, - SM5451_FLAG2_CNSHTP = 1 << 0, -}; - -enum SM5451_flag3_desc { - SM5451_FLAG3_VBUSPOK = 1 << 7, - SM5451_FLAG3_VOUTPOK = 1 << 6, - SM5451_FLAG3_WTDTMR = 1 << 5, - SM5451_FLAG3_VBUSUVLO = 1 << 3, - SM5451_FLAG3_CHGONTMR = 1 << 2, - SM5451_FLAG3_ADCDONE = 1 << 1, - SM5451_FLAG3_CFLYSHTP = 1 << 0, -}; - -enum SM5451_flag4_desc { - SM5451_FLAG4_IBUSOCP_RVS = 1 << 5, - SM5451_FLAG4_RVSRDY = 1 << 4, - SM5451_FLAG4_THEMP = 1 << 3, - SM5451_FLAG4_IBUSREG = 1 << 2, - SM5451_FLAG4_TOPOFF = 1 << 1, - SM5451_FLAG4_DONE = 1 << 0, -}; - -enum SM5451_reg_addr { - SM5451_REG_CNTL1 = 0x00, - SM5451_REG_CNTL2 = 0x01, - SM5451_REG_CNTL3 = 0x02, - SM5451_REG_DEVICE_ID = 0x03, - SM5451_REG_CNTL4 = 0x05, - SM5451_REG_VBUSOVP = 0x06, - SM5451_REG_IBUS_PROT = 0x07, - SM5451_REG_VBAT_OVP = 0x08, - SM5451_REG_IBAT_OCP = 0x09, - SM5451_REG_REG1 = 0x0A, - SM5451_REG_FLAG1 = 0x0B, - SM5451_REG_FLAGMSK1 = 0x0C, - SM5451_REG_FLAG2 = 0x0D, - SM5451_REG_FLAGMSK2 = 0x0E, - SM5451_REG_FLAG3 = 0x0F, - SM5451_REG_FLAGMSK3 = 0x10, - SM5451_REG_ADC_CNTL = 0x11, - SM5451_REG_VBUS_ADC_H = 0x12, - SM5451_REG_VBUS_ADC_L = 0x13, - SM5451_REG_IBUS_ADC_H = 0x14, - SM5451_REG_IBUS_ADC_L = 0x15, - SM5451_REG_VBAT_ADC_H = 0x16, - SM5451_REG_VBAT_ADC_L = 0x17, - SM5451_REG_IBAT_ADC_H = 0x18, - SM5451_REG_IBAT_ADC_L = 0x19, - SM5451_REG_TDIE_ADC = 0x1A, - SM5451_REG_THEM = 0x60, - SM5451_REG_CNTL5 = 0x61, - SM5451_REG_TOPOFF = 0x62, - SM5451_REG_FLAG4 = 0x63, - SM5451_REG_FLAGMSK4 = 0x64, - SM5451_REG_THEM_ADC_H = 0x65, - SM5451_REG_THEM_ADC_L = 0x66, - SM5451_REG_IBATOCP_DG = 0x92, - SM5451_REG_VDSQRB_DG = 0x95, - SM5451_REG_PRECHG_MODE = 0xA0, - SM5451_REG_CTRL_STM_0 = 0xBA, - SM5451_REG_CTRL_STM_1 = 0xBB, - SM5451_REG_CTRL_STM_2 = 0xBC, - SM5451_REG_CTRL_STM_3 = 0xBD, - SM5451_REG_CTRL_STM_5 = 0xBF, -}; - -enum SM5451_vbatovp_offset { - SM5451_VBATOVP_50 = 0x0, - SM5451_VBATOVP_100 = 0x1, - SM5451_VBATOVP_150 = 0x2, - SM5451_VBATOVP_200 = 0x3, -}; - -enum SM5451_ibatocp_offset { - SM5451_IBATOCP_200 = 0x0, - SM5451_IBATOCP_300 = 0x1, - SM5451_IBATOCP_400 = 0x2, - SM5451_IBATOCP_500 = 0x3, -}; - -enum SM5451_ibusocp_offset { - SM5451_IBUSOCP_100 = 0x0, - SM5451_IBUSOCP_200 = 0x1, - SM5451_IBUSOCP_300 = 0x2, - SM5451_IBUSOCP_400 = 0x3, -}; - -enum SM5451_adc_channel { - SM5451_ADC_THEM = 0x0, - SM5451_ADC_TDIE, - SM5451_ADC_VBUS, - SM5451_ADC_IBUS, - SM5451_ADC_VBAT, - SM5451_ADC_IBAT, -}; - -enum SM5451_wdt_tmr { - WDT_TIMER_S_0P5 = 0x0, - WDT_TIMER_S_1 = 0x1, - WDT_TIMER_S_2 = 0x2, - WDT_TIMER_S_5 = 0x3, - WDT_TIMER_S_10 = 0x4, - WDT_TIMER_S_20 = 0x5, - WDT_TIMER_S_40 = 0x6, - WDT_TIMER_S_80 = 0x7, -}; - -enum SM5451_op_mode { - OP_MODE_INIT = 0x0, - OP_MODE_FW_BYPASS = 0x1, - OP_MODE_FW_BOOST = 0x2, - OP_MODE_REV_BYPASS = 0x3, - OP_MODE_REV_BOOST = 0x4, -}; - -enum sm5451_chip_id { - SM5451_ALONE = 0x0, - SM5451_MAIN = 0x1, - SM5451_SUB = 0x3, -}; - -enum SM5451_freq { - SM5451_FREQ_200KHZ = 0x0, - SM5451_FREQ_375KHZ = 0x1, - SM5451_FREQ_500KHZ = 0x2, - SM5451_FREQ_750KHZ = 0x3, - SM5451_FREQ_1000KHZ = 0x4, - SM5451_FREQ_1250KHZ = 0x5, - SM5451_FREQ_1500KHZ = 0x6, -}; - -struct sm5451_platform_data { - u8 rev_id; - int irq_gpio; - u32 r_ttl; - u32 pps_lr; - u32 rpcm; - u32 freq; - u32 freq_byp; - u32 freq_siop[2]; - u32 topoff; - u32 x2bat_mode; - u32 en_vbatreg; - - struct { - u32 chg_float_voltage; - char *sec_dc_name; - char *fuelgauge_name; - } battery; -}; - -struct sm5451_charger { - struct device *dev; - struct i2c_client *i2c; - struct sm5451_platform_data *pdata; - struct power_supply *psy_chg; - struct sm_dc_info *pps_dc; - struct sm_dc_info *x2bat_dc; - int chip_id; - - struct mutex i2c_lock; - struct mutex pd_lock; - struct wakeup_source *chg_ws; - - int irq; - int cable_online; - bool vbus_in; - bool rev_boost; - u8 force_adc_on; - u32 max_vbat; - u32 target_vbat; - u32 target_ibus; - u32 target_ibat; - - bool wdt_disable; - - /* debug */ - struct dentry *debug_root; - u32 debug_address; - int addr; - int size; -}; - -#endif /* __SM5451_CHARGER_H__ */ diff --git a/drivers/battery/charger/sm5451_charger/sm5451_direct_charger.c b/drivers/battery/charger/sm5451_charger/sm5451_direct_charger.c deleted file mode 100755 index 36375fbfd..000000000 --- a/drivers/battery/charger/sm5451_charger/sm5451_direct_charger.c +++ /dev/null @@ -1,2133 +0,0 @@ - -/* - * sm5451_direct_charger.c - Direct charging module on the SM ICs - * - * Copyright (C) 2022 SiliconMitus Co.Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#if IS_ENABLED(CONFIG_BATTERY_SAMSUNG) -#include "../../common/sec_charging_common.h" -#include "../../common/sec_direct_charger.h" -#endif -#include "sm5451_direct_charger.h" - -/** - * Internal support functions for Direct-charging - * - used sharing PD3.0 - */ -static u32 pps_v(u32 vol) -{ - if ((vol%PPS_V_STEP) >= (PPS_V_STEP / 2)) - vol += PPS_V_STEP; - - return (vol / PPS_V_STEP) * PPS_V_STEP; -} - -static u32 pps_c(u32 cur) -{ - if ((cur % PPS_C_STEP) >= (PPS_C_STEP / 2)) - cur += PPS_C_STEP; - - return (cur / PPS_C_STEP) * PPS_C_STEP; -} - -static int report_dc_state(struct sm_dc_info *sm_dc) -{ - union power_supply_propval val = {0,}; - static int prev_val = SEC_DIRECT_CHG_MODE_DIRECT_OFF; - - switch (sm_dc->state) { - case SM_DC_CHG_OFF: - case SM_DC_ERR: - val.intval = SEC_DIRECT_CHG_MODE_DIRECT_OFF; - break; - case SM_DC_EOC: - val.intval = SEC_DIRECT_CHG_MODE_DIRECT_DONE; - break; - case SM_DC_CHECK_VBAT: - val.intval = SEC_DIRECT_CHG_MODE_DIRECT_CHECK_VBAT; - break; - case SM_DC_PRESET: - val.intval = SEC_DIRECT_CHG_MODE_DIRECT_PRESET; - break; - case SM_DC_PRE_CC: - case SM_DC_UPDAT_BAT: - val.intval = SEC_DIRECT_CHG_MODE_DIRECT_ON_ADJUST; - break; - case SM_DC_CC: - case SM_DC_CV: - val.intval = SEC_DIRECT_CHG_MODE_DIRECT_ON; - break; - case SM_DC_CV_MAN: - val.intval = SEC_DIRECT_CHG_MODE_DIRECT_BYPASS; - break; - default: - return -EINVAL; - } - - if (prev_val != val.intval) { - psy_do_property(sm_dc->config.sec_dc_name, set, - POWER_SUPPLY_EXT_PROP_DIRECT_CHARGER_MODE, val); - } - - return 0; -} - -static int request_state_work(struct sm_dc_info *sm_dc, u8 state, u32 delay) -{ - int ret = 0; - - mutex_lock(&sm_dc->st_lock); - - switch (state) { - case SM_DC_CHECK_VBAT: - queue_delayed_work(sm_dc->dc_wqueue, &sm_dc->check_vbat_work, - msecs_to_jiffies(delay)); - break; - case SM_DC_PRESET: - queue_delayed_work(sm_dc->dc_wqueue, &sm_dc->preset_dc_work, - msecs_to_jiffies(delay)); - break; - case SM_DC_PRE_CC: - queue_delayed_work(sm_dc->dc_wqueue, &sm_dc->pre_cc_work, - msecs_to_jiffies(delay)); - break; - case SM_DC_CC: - queue_delayed_work(sm_dc->dc_wqueue, &sm_dc->cc_work, - msecs_to_jiffies(delay)); - break; - case SM_DC_CV: - queue_delayed_work(sm_dc->dc_wqueue, &sm_dc->cv_work, - msecs_to_jiffies(delay)); - break; - case SM_DC_CV_MAN: - queue_delayed_work(sm_dc->dc_wqueue, &sm_dc->cv_man_work, - msecs_to_jiffies(delay)); - break; - case SM_DC_UPDAT_BAT: - queue_delayed_work(sm_dc->dc_wqueue, &sm_dc->update_bat_work, - msecs_to_jiffies(delay)); - break; - case SM_DC_ERR: - queue_delayed_work(sm_dc->dc_wqueue, &sm_dc->error_work, - msecs_to_jiffies(delay)); - break; - default: - pr_err("%s %s: invalid state(%d)\n", sm_dc->name, __func__, state); - ret = -EINVAL; - break; - } - - mutex_unlock(&sm_dc->st_lock); - - return ret; -} - -static int update_work_state(struct sm_dc_info *sm_dc, u8 state) -{ - int ret = 0; - - if (sm_dc->state == SM_DC_CHG_OFF) { - pr_err("%s %s: detected chg_off, terminate work\n", sm_dc->name, __func__); - return -EBUSY; - } - - pr_info("%s %s: sm_dc->state=%d, state=%d, update(%d,%d,%d)\n", - sm_dc->name, __func__, sm_dc->state, state, sm_dc->req_update_vbat, - sm_dc->req_update_ibus, sm_dc->req_update_ibat); - - if (sm_dc->state > SM_DC_PRESET && state > SM_DC_PRESET) { /* going on charging-cycle */ - if (sm_dc->req_update_vbat || sm_dc->req_update_ibus || sm_dc->req_update_ibat) { - pr_info("%s %s: changed chg param, request: update_bat\n", sm_dc->name, __func__); - request_state_work(sm_dc, SM_DC_UPDAT_BAT, DELAY_NONE); - ret = -EINVAL; - } - } - - if (sm_dc->state != state) { - mutex_lock(&sm_dc->st_lock); - sm_dc->state = state; - mutex_unlock(&sm_dc->st_lock); - report_dc_state(sm_dc); - } - - return ret; -} - -static int send_power_source_msg(struct sm_dc_info *sm_dc) -{ - int ret; - - if (sm_dc->state < SM_DC_CHECK_VBAT) - return -EINVAL; - - if (sm_dc->ta.v > sm_dc->ta.v_max || sm_dc->ta.c > sm_dc->ta.c_max) { - pr_err("%s %s: ERROR: out of bounce v=%dmV(max=%dmV) c=%dmA(max=%dmA)\n", - sm_dc->name, __func__, sm_dc->ta.v, sm_dc->ta.v_max, - sm_dc->ta.c, sm_dc->ta.c_max); - - sm_dc->err = SM_DC_ERR_SEND_PD_MSG; - request_state_work(sm_dc, SM_DC_ERR, DELAY_NONE); - return -EINVAL; - } - - - pr_info("%s %s: [send PWR_MSG] pdo=%d, v=%dmV(max=%dmV) c=%dmA(max=%dmA)\n", - sm_dc->name, __func__, sm_dc->ta.pdo_pos, sm_dc->ta.v, - sm_dc->ta.v_max, sm_dc->ta.c, sm_dc->ta.c_max); - - - ret = sm_dc->ops->send_power_source_msg(sm_dc->i2c, &sm_dc->ta); - if (ret < 0) { - pr_err("%s %s: fail to send msg(ret=%d)\n", sm_dc->name, __func__, ret); - sm_dc->err = SM_DC_ERR_SEND_PD_MSG; - request_state_work(sm_dc, SM_DC_ERR, DELAY_NONE); - } - - return ret; -} - -static int setup_direct_charging_work_config(struct sm_dc_info *sm_dc) -{ - sm_dc->wq.pps_cl = 0; - sm_dc->wq.c_down = 0; - sm_dc->wq.c_up = 0; - sm_dc->wq.v_down = 0; - sm_dc->wq.v_up = 0; - sm_dc->wq.prev_adc_ibus = 0; - sm_dc->wq.prev_adc_vbus = 0; - sm_dc->wq.cc_limit = 0; - sm_dc->wq.cv_cnt = 0; - sm_dc->wq.cv_gl = sm_dc->target_vbat; - sm_dc->wq.ci_gl = MIN(sm_dc->ta.c_max, ((sm_dc->target_ibus * 100) / 100)); - sm_dc->wq.cc_gl = sm_dc->wq.ci_gl * 2; - sm_dc->wq.retry_cnt = 0; - sm_dc->wq.cc_cnt = 0; - sm_dc->wq.pps_vcm = 0; - - pr_info("%s %s: CV_GL=%dmV, CI_GL=%dmA, CC_GL=%dmA\n", sm_dc->name, __func__, - sm_dc->wq.cv_gl, sm_dc->wq.ci_gl, sm_dc->wq.cc_gl); - sm_dc->ops->set_charging_config(sm_dc->i2c, sm_dc->wq.cv_gl, sm_dc->wq.ci_gl, sm_dc->wq.cc_gl); - if (sm_dc->i2c_sub) - sm_dc->ops->set_charging_config(sm_dc->i2c_sub, sm_dc->wq.cv_gl, sm_dc->wq.ci_gl, sm_dc->wq.cc_gl); - return 0; -} - -static int check_error_state(struct sm_dc_info *sm_dc, u8 retry_state) -{ - int adc_vbat, adc_ibus; - u32 sub_err; - - if (sm_dc->state == SM_DC_ERR) { - pr_err("%s %s: already occurred error (err=0x%x)\n", sm_dc->name, __func__, sm_dc->err); - return -EINVAL; - } - - sm_dc->err = sm_dc->ops->get_dc_error_status(sm_dc->i2c); - if (sm_dc->err == SM_DC_ERR_RETRY) { - pr_err("%s %s: error status retry, wait 2sec\n", sm_dc->name, __func__); - request_state_work(sm_dc, retry_state, DELAY_RETRY); - return -EAGAIN; - } else if (sm_dc->err == SM_DC_ERR_VBATREG || sm_dc->err == SM_DC_ERR_IBUSREG) { - return sm_dc->err; - } else if (sm_dc->err > SM_DC_ERR_NONE) { - pr_err("%s %s: error status:0x%x\n", sm_dc->name, __func__, sm_dc->err); - request_state_work(sm_dc, SM_DC_ERR, DELAY_NONE); - return -EPERM; - } - - if (sm_dc->i2c_sub) { - sub_err = sm_dc->ops->get_dc_error_status(sm_dc->i2c_sub); - if (sub_err == SM_DC_ERR_IBUSREG) { - sm_dc->err = sub_err; - return sm_dc->err; - } - - if (sm_dc->ops->get_charging_enable(sm_dc->i2c_sub) == 0x0) { - adc_ibus = sm_dc->ops->get_adc_value(sm_dc->i2c, SM_DC_ADC_IBUS); - if (adc_ibus > SM_DC_DUAL_STOP_IBUS) { - sm_dc->err = SM_DC_ERR_FAIL_ADJUST; - pr_err("%s %s: error status:0x%x\n", sm_dc->name, __func__, sm_dc->err); - request_state_work(sm_dc, SM_DC_ERR, DELAY_NONE); - return -ERANGE; - } - } - } - - adc_vbat = sm_dc->ops->get_adc_value(sm_dc->i2c, SM_DC_ADC_VBAT); - if (adc_vbat <= sm_dc->config.dc_min_vbat) { - pr_err("%s %s: abnormal adc_vbat(%d)\n", sm_dc->name, __func__, adc_vbat); - sm_dc->err = SM_DC_ERR_INVAL_VBAT; - request_state_work(sm_dc, SM_DC_ERR, DELAY_NONE); - return -ERANGE; - } - - return 0; -} - -static int get_adc_values(struct sm_dc_info *sm_dc, const char *str, int *vbus, int *ibus, int *vout, - int *vbat, int *ibat, int *them, int *dietemp) -{ - int adc_vbus, adc_ibus, adc_vout, adc_vbat, adc_ibat, adc_them, adc_dietemp; - int adc_vbus2, adc_ibus2, adc_vout2, adc_vbat2, adc_ibat2, adc_them2, adc_dietemp2; - - adc_vbus = sm_dc->ops->get_adc_value(sm_dc->i2c, SM_DC_ADC_VBUS); - adc_ibus = sm_dc->ops->get_adc_value(sm_dc->i2c, SM_DC_ADC_IBUS); - adc_vout = sm_dc->ops->get_adc_value(sm_dc->i2c, SM_DC_ADC_VOUT); - adc_vbat = sm_dc->ops->get_adc_value(sm_dc->i2c, SM_DC_ADC_VBAT); - adc_ibat = sm_dc->ops->get_adc_value(sm_dc->i2c, SM_DC_ADC_IBAT); - adc_them = sm_dc->ops->get_adc_value(sm_dc->i2c, SM_DC_ADC_THEM); - adc_dietemp = sm_dc->ops->get_adc_value(sm_dc->i2c, SM_DC_ADC_DIETEMP); - - pr_info("%s %s:vbus:%d:ibus:%d:vout:%d:vbat:%d:ibat:%d:them:%d:dietemp:%d\n", - sm_dc->name, str, adc_vbus, adc_ibus, adc_vout, - adc_vbat, adc_ibat, adc_them, adc_dietemp); - - if (sm_dc->i2c_sub) { - if (sm_dc->ops->get_charging_enable(sm_dc->i2c_sub)) { - adc_vbus2 = sm_dc->ops->get_adc_value(sm_dc->i2c_sub, SM_DC_ADC_VBUS); - adc_ibus2 = sm_dc->ops->get_adc_value(sm_dc->i2c_sub, SM_DC_ADC_IBUS); - adc_vout2 = sm_dc->ops->get_adc_value(sm_dc->i2c_sub, SM_DC_ADC_VOUT); - adc_vbat2 = sm_dc->ops->get_adc_value(sm_dc->i2c_sub, SM_DC_ADC_VBAT); - adc_ibat2 = sm_dc->ops->get_adc_value(sm_dc->i2c_sub, SM_DC_ADC_IBAT); - adc_them2 = sm_dc->ops->get_adc_value(sm_dc->i2c_sub, SM_DC_ADC_THEM); - adc_dietemp2 = sm_dc->ops->get_adc_value(sm_dc->i2c_sub, SM_DC_ADC_DIETEMP); - adc_ibus += adc_ibus2; - pr_info("%s %s(s):vbus:%d:ibus:%d:ibus_t:%d:vout:%d:vbat:%d:ibat:%d:them:%d:dietemp:%d\n", - sm_dc->name, str, adc_vbus2, adc_ibus2, adc_ibus, adc_vout2, - adc_vbat2, adc_ibat2, adc_them2, adc_dietemp2); - } - } - - if (vbus) - *vbus = adc_vbus; - - if (ibus) - *ibus = adc_ibus; - - if (vout) - *vout = adc_vout; - - if (vbat) - *vbat = adc_vbat; - - if (ibat) - *ibat = adc_ibat; - - if (them) - *them = adc_them; - - if (dietemp) - *dietemp = adc_dietemp; - - return 0; -} - -static int terminate_charging_work(struct sm_dc_info *sm_dc) -{ - flush_workqueue(sm_dc->dc_wqueue); - - cancel_delayed_work_sync(&sm_dc->check_vbat_work); - cancel_delayed_work_sync(&sm_dc->preset_dc_work); - cancel_delayed_work_sync(&sm_dc->pre_cc_work); - cancel_delayed_work_sync(&sm_dc->cc_work); - cancel_delayed_work_sync(&sm_dc->cv_work); - cancel_delayed_work_sync(&sm_dc->cv_man_work); - cancel_delayed_work_sync(&sm_dc->update_bat_work); - cancel_delayed_work_sync(&sm_dc->error_work); - - sm_dc->ops->set_charging_enable(sm_dc->i2c, 0); - if (sm_dc->i2c_sub) - sm_dc->ops->set_charging_enable(sm_dc->i2c_sub, 0); - - return 0; -} - -/** - * PD3.0 PPS Direct-charging work functions - */ -static inline u32 _calc_pps_v_init_offset(struct sm_dc_info *sm_dc) -{ - u32 offset; - - if (sm_dc->config.r_ttl < 100000) { - offset = (sm_dc->ta.c * (sm_dc->config.pps_lr + sm_dc->config.rpara + - (sm_dc->config.rsns * 2) + (sm_dc->config.rpcm * 2))) / 1000000; - } else { - offset = (sm_dc->ta.c * sm_dc->config.r_ttl) / 1000000; - } - offset += 200; /* add to extra initial offset */ - pr_info("%s %s: pps_c=%dmA, v_init_offset=%dmV\n", sm_dc->name, __func__, sm_dc->ta.c, offset); - - return offset; -} - -static inline int _adjust_pps_v(struct sm_dc_info *sm_dc, int pps_v_original) -{ - int adc_vbus; - - adc_vbus = sm_dc->ops->get_adc_value(sm_dc->i2c, SM_DC_ADC_VBUS); - msleep(DELAY_PPS_UPDATE); - pr_info("%s %s: adc_vbus=%dmV, pps_v_original=%dmV\n", - sm_dc->name, __func__, adc_vbus, pps_v_original); - - sm_dc->wq.v_offset = 0; - return 0; -} - -static inline int _pd_pre_cc_check_limitation(struct sm_dc_info *sm_dc, int adc_ibus, int adc_vbus) -{ - u32 calc_pps_v, calc_reg_v; - int ret = 0; - - if (adc_ibus == sm_dc->wq.prev_adc_ibus && adc_vbus == sm_dc->wq.prev_adc_vbus) { - pr_info("%s %s: adc didn't update yet\n", sm_dc->name, __func__); - /* if continuos adc didn't update yet */ - return 0; - } - - if ((adc_vbus < sm_dc->wq.prev_adc_vbus + (PPS_V_STEP/2)) && - (adc_ibus < sm_dc->wq.prev_adc_ibus + (PPS_C_STEP)) && - (sm_dc->wq.v_down == 0 && sm_dc->wq.pps_cl == 0)) { - ret = 1; - } else if (sm_dc->wq.ci_gl == sm_dc->config.ta_min_current) { /* Case: didn't reduce PPS_C than TA_MIN_C */ - ret = 1; - } - -#if defined(CONFIG_SEC_FACTORY) - if (sm_dc->wq.c_down == 0 && sm_dc->wq.pps_cl == 0) - ret = 1; -#endif - - if (ret) { - if (sm_dc->config.r_ttl < 100000) { - calc_reg_v = (sm_dc->wq.ci_gl * (sm_dc->config.pps_lr + sm_dc->config.rpara + - sm_dc->config.rsns * 2 + sm_dc->config.rpcm * 2)) / 1000000; - } else { - calc_reg_v = (sm_dc->wq.ci_gl * sm_dc->config.r_ttl) / 1000000; - } - if (sm_dc->ta.v_max < SM_DC_BYPASS_TA_MAX_VOL) { - calc_pps_v = (sm_dc->target_vbat) + calc_reg_v + sm_dc->wq.v_offset; - calc_pps_v = MIN(calc_pps_v, sm_dc->ta.v_max); - } else { - calc_pps_v = (sm_dc->target_vbat * 2) + calc_reg_v + sm_dc->wq.v_offset; - if ((pps_v(calc_pps_v) * sm_dc->wq.ci_gl) > sm_dc->ta.p_max) { - pr_info("%s %s: calc_pps_v(%dmV) will be reduced\n", sm_dc->name, __func__, calc_pps_v); - calc_pps_v = ((sm_dc->ta.p_max / sm_dc->wq.ci_gl) - PPS_V_STEP) < 0 ? - 0 : ((sm_dc->ta.p_max / sm_dc->wq.ci_gl) - PPS_V_STEP); - } - } - sm_dc->ta.v = pps_v(MIN(calc_pps_v, sm_dc->config.dc_vbus_ovp_th - 350)); - pr_info("%s %s: PPS_LR=%d, RPARA=%d, RSNS=%d, RPCM=%d, R_TTL=%d, calc_reg_v=%dmV, calc_pps_v=%dmV\n", - sm_dc->name, __func__, sm_dc->config.pps_lr, sm_dc->config.rpara, - sm_dc->config.rsns, sm_dc->config.rpcm, sm_dc->config.r_ttl, calc_reg_v, calc_pps_v); - sm_dc->ta.c = sm_dc->ta.c; - sm_dc->wq.pps_cl = 1; - } - - return ret; -} - -static inline int _try_to_adjust_cc_up(struct sm_dc_info *sm_dc) -{ - sm_dc->wq.cc_cnt += 1; - - if ((sm_dc->wq.cc_cnt % 2) && (sm_dc->ta.c <= sm_dc->wq.ci_gl + (PPS_C_STEP * 4)) - && (sm_dc->ta.c != sm_dc->ta.c_max)) { - if ((sm_dc->ta.v * (sm_dc->ta.c + PPS_C_STEP) <= (sm_dc->ta.p_max / 100) * 107)) { - sm_dc->ta.c += PPS_C_STEP; - if (sm_dc->ta.c > sm_dc->ta.c_max) - sm_dc->ta.c = sm_dc->ta.c_max; - } - } else { - /* TA P_MAX + 7% */ - if ((sm_dc->ta.v + (PPS_V_STEP * 2)) * sm_dc->ta.c <= (sm_dc->ta.p_max / 100) * 107) { - sm_dc->ta.v += PPS_V_STEP * 2; - if (sm_dc->ta.v > MIN(sm_dc->ta.v_max, sm_dc->config.dc_vbus_ovp_th - 350)) - sm_dc->ta.v = pps_v(MIN(sm_dc->ta.v_max, sm_dc->config.dc_vbus_ovp_th - 350)); - } else { - pr_info("%s %s: PPS-TA has been reached limitation(v=%dmV, c=%dmA)\n", - sm_dc->name, __func__, sm_dc->ta.v, sm_dc->ta.c); - sm_dc->wq.cc_limit = 1; - return -EINVAL; - } - } - - return 0; -} - -static inline void _try_to_adjust_cc_down(struct sm_dc_info *sm_dc) -{ - sm_dc->wq.cc_cnt += 1; - - if ((sm_dc->wq.cc_cnt % 2) && (sm_dc->ta.c >= sm_dc->wq.ci_gl - (PPS_C_STEP * 4))) { - if (sm_dc->ta.c - PPS_C_STEP >= sm_dc->config.ta_min_current) - sm_dc->ta.c -= PPS_C_STEP; - } else { - if (sm_dc->ta.v > sm_dc->config.ta_min_voltage) - sm_dc->ta.v -= PPS_V_STEP; - } -} - -static void pd_check_vbat_work(struct work_struct *work) -{ - struct sm_dc_info *sm_dc = container_of(work, struct sm_dc_info, check_vbat_work.work); - struct sm_dc_power_source_info ta; - union power_supply_propval val; - int adc_vbat; - int ret; - - ret = update_work_state(sm_dc, SM_DC_CHECK_VBAT); - if (ret < 0) - return; - - ret = psy_do_property(sm_dc->config.sec_dc_name, get, - POWER_SUPPLY_EXT_PROP_CHARGING_ENABLED_DC, val); - if (ret < 0) { - pr_err("%s %s: is not ready to work (wait 1sec)\n", sm_dc->name, __func__); - request_state_work(sm_dc, SM_DC_CHECK_VBAT, DELAY_ADC_UPDATE); - return; - } - - ret = sm_dc->ops->get_apdo_max_power(sm_dc->i2c, &ta); - if (ret < 0) { - if (sm_dc->ta.retry_cnt < 3) { - pr_err("%s %s: get_apdo_max_power, RETRY=%d\n", - sm_dc->name, __func__, sm_dc->ta.retry_cnt); - sm_dc->ta.retry_cnt++; - request_state_work(sm_dc, SM_DC_CHECK_VBAT, DELAY_PPS_UPDATE); - } else { - pr_err("%s %s: fail to get APDO(ret=%d)\n", sm_dc->name, __func__, ret); - sm_dc->err = SM_DC_ERR_SEND_PD_MSG; - request_state_work(sm_dc, SM_DC_ERR, DELAY_NONE); - } - return; - } - - if (sm_dc->i2c_sub) { - ret = sm_dc->ops->get_apdo_max_power(sm_dc->i2c_sub, &ta); - if (ret < 0) { - pr_err("%s %s: fail to get APDO(ret=%d)\n", sm_dc->name, __func__, ret); - return; - } - } - - val.intval = 0; - - if (val.intval == 0) { /* already disabled switching charger */ - pr_info("%s %s: [request] check_vbat -> preset\n", sm_dc->name, __func__); - request_state_work(sm_dc, SM_DC_PRESET, DELAY_NONE); - - psy_do_property(sm_dc->config.sec_dc_name, set, - POWER_SUPPLY_EXT_PROP_CHARGING_ENABLED_DC, val); - } else { - adc_vbat = sm_dc->ops->get_adc_value(sm_dc->i2c, SM_DC_ADC_VBAT); - pr_info("%s %s: adc:vbat=%dmV\n", sm_dc->name, __func__, adc_vbat); - - if (adc_vbat > sm_dc->config.dc_min_vbat) { - pr_info("%s %s: set_prop - disable sw_chg\n", sm_dc->name, __func__); - val.intval = 0; - psy_do_property(sm_dc->config.sec_dc_name, set, - POWER_SUPPLY_EXT_PROP_CHARGING_ENABLED_DC, val); - } - pr_err("%s %s: sw_chg not disabled yet (wait 1sec)\n", sm_dc->name, __func__); - request_state_work(sm_dc, SM_DC_CHECK_VBAT, DELAY_ADC_UPDATE); - } -} - -static void pd_preset_dc_work(struct work_struct *work) -{ - struct sm_dc_info *sm_dc = container_of(work, struct sm_dc_info, preset_dc_work.work); - int adc_vbat, ret, delay = DELAY_PPS_UPDATE; - - ret = update_work_state(sm_dc, SM_DC_PRESET); - if (ret < 0) - return; - - adc_vbat = sm_dc->ops->get_adc_value(sm_dc->i2c, SM_DC_ADC_VBAT); - if (adc_vbat > sm_dc->target_vbat + PPS_V_STEP) { /* Debounce ADC accuracy */ - pr_err("%s %s: adc_vbat(%dmV) > target_v, can't start dc\n", sm_dc->name, __func__, adc_vbat); - sm_dc->err = SM_DC_ERR_INVAL_VBAT; - request_state_work(sm_dc, SM_DC_ERR, DELAY_NONE); - return; - } - pr_info("%s %s: adc_vbat=%dmV, ta_min_v=%dmV, v_max=%dmA, c_max=%dmA, target_ibus=%dmA\n", - sm_dc->name, __func__, adc_vbat, sm_dc->config.ta_min_voltage, sm_dc->ta.v_max, - sm_dc->ta.c_max, sm_dc->target_ibus); - - sm_dc->ta.c = MIN(sm_dc->ta.c_max, ((sm_dc->target_ibus * 50) / 100)); - sm_dc->ta.c = pps_c(MAX(sm_dc->ta.c, sm_dc->config.ta_min_current)); - if (sm_dc->ta.v_max < SM_DC_BYPASS_TA_MAX_VOL) { - sm_dc->ta.v = adc_vbat + _calc_pps_v_init_offset(sm_dc); - sm_dc->ta.v = pps_v(MAX(sm_dc->ta.v, sm_dc->config.ta_min_voltage / 2)); - } else { - sm_dc->ta.v = (2 * adc_vbat) + _calc_pps_v_init_offset(sm_dc); - sm_dc->ta.v = pps_v(MAX(sm_dc->ta.v, sm_dc->config.ta_min_voltage)); - } - ret = send_power_source_msg(sm_dc); - if (ret < 0) - return; - - msleep(DELAY_PPS_UPDATE); - - if (sm_dc->ops->get_charging_enable(sm_dc->i2c) == 0x0) - _adjust_pps_v(sm_dc, sm_dc->ta.v); - - - if (sm_dc->target_ibus < sm_dc->wq.ci_gl) - delay = DELAY_ADC_UPDATE; - - setup_direct_charging_work_config(sm_dc); - if (sm_dc->i2c_sub) - sm_dc->ops->set_charging_enable(sm_dc->i2c_sub, 1); - sm_dc->ops->set_charging_enable(sm_dc->i2c, 1); - pr_info("%s %s: enable Direct-charging\n", sm_dc->name, __func__); - /* Pre-update PRE_CC state. for check to charging initial error case */ - ret = update_work_state(sm_dc, SM_DC_PRE_CC); - if (ret < 0) - return; - - pr_info("%s %s: [request] preset -> pre_cc\n", sm_dc->name, __func__); - request_state_work(sm_dc, SM_DC_PRE_CC, delay); -} - -static void pd_pre_cc_work(struct work_struct *work) -{ - struct sm_dc_info *sm_dc = container_of(work, struct sm_dc_info, pre_cc_work.work); - int ret, adc_ibus, adc_vbus, adc_vbat; - int delay_time = DELAY_PPS_UPDATE; - u8 loop_status = LOOP_INACTIVE; - - pr_info("%s %s: (CI_GL=%dmA)\n", sm_dc->name, __func__, sm_dc->wq.ci_gl); - ret = check_error_state(sm_dc, SM_DC_PRE_CC); - if (ret < 0) - return; - if (ret == SM_DC_ERR_VBATREG) - loop_status = LOOP_VBATREG; - else if (ret == SM_DC_ERR_IBUSREG) - loop_status = LOOP_IBUSREG; - - ret = update_work_state(sm_dc, SM_DC_PRE_CC); - if (ret < 0) - return; - - get_adc_values(sm_dc, "[adc-values]:pre_cc_work", &adc_vbus, &adc_ibus, NULL, - &adc_vbat, NULL, NULL, NULL); - - switch (loop_status) { - case LOOP_VBATREG: - sm_dc->wq.cv_cnt = 0; - pr_info("%s %s: [request] pre-cc -> cv\n", sm_dc->name, __func__); - sm_dc->ops->set_adc_mode(sm_dc->i2c, SM_DC_ADC_MODE_CONTINUOUS); - if (sm_dc->i2c_sub) - sm_dc->ops->set_adc_mode(sm_dc->i2c_sub, SM_DC_ADC_MODE_CONTINUOUS); - request_state_work(sm_dc, SM_DC_CV, DELAY_ADC_UPDATE); - return; - case LOOP_IBUSREG: - if (sm_dc->config.need_to_sw_ocp && sm_dc->wq.v_down == 1) { - pr_info("%s %s: call check_sw_ocp\n", sm_dc->name, __func__); - ret = sm_dc->ops->check_sw_ocp(sm_dc->i2c); - if (ret < 0) - return; - } - sm_dc->wq.c_offset = 0; - if (sm_dc->ta.v - (PPS_V_STEP * 2) >= sm_dc->config.ta_min_voltage) { - sm_dc->ta.v -= PPS_V_STEP * 2; - sm_dc->wq.v_down = 1; - sm_dc->wq.v_up = 0; - } else { - sm_dc->ta.v = sm_dc->config.ta_min_voltage; - pr_info("%s %s: can't use less then ta_min_voltage\n", sm_dc->name, __func__); - pr_info("%s %s: [request] pre_cc -> cc\n", sm_dc->name, __func__); - sm_dc->wq.v_down = 0; - sm_dc->wq.pps_vcm = 1; - sm_dc->wq.pps_cl = 0; - sm_dc->wq.cc_limit = 0; - sm_dc->ops->set_adc_mode(sm_dc->i2c, SM_DC_ADC_MODE_CONTINUOUS); - if (sm_dc->i2c_sub) - sm_dc->ops->set_adc_mode(sm_dc->i2c_sub, SM_DC_ADC_MODE_CONTINUOUS); - request_state_work(sm_dc, SM_DC_CC, DELAY_ADC_UPDATE); - return; - } - ret = send_power_source_msg(sm_dc); - if (ret < 0) - return; - sm_dc->ops->set_adc_mode(sm_dc->i2c, SM_DC_ADC_MODE_CONTINUOUS); - if (sm_dc->i2c_sub) - sm_dc->ops->set_adc_mode(sm_dc->i2c_sub, SM_DC_ADC_MODE_CONTINUOUS); - request_state_work(sm_dc, SM_DC_PRE_CC, DELAY_PPS_UPDATE); - return; - } - - _pd_pre_cc_check_limitation(sm_dc, adc_ibus, adc_vbus); - - if (adc_ibus > sm_dc->wq.ci_gl) { - sm_dc->wq.cc_limit = 0; - if (sm_dc->wq.ci_gl > sm_dc->ta.c) - sm_dc->wq.c_offset = sm_dc->wq.ci_gl - sm_dc->ta.c; - else - sm_dc->wq.c_offset = 0; - - if (!sm_dc->wq.pps_cl) - sm_dc->wq.pps_vcm = 1; - - pr_info("%s %s: [request] pre_cc -> cc (c_offset=%d, pps_cl=%d)\n", sm_dc->name, - __func__, sm_dc->wq.c_offset, sm_dc->wq.pps_cl); - sm_dc->ops->set_adc_mode(sm_dc->i2c, SM_DC_ADC_MODE_CONTINUOUS); - if (sm_dc->i2c_sub) - sm_dc->ops->set_adc_mode(sm_dc->i2c_sub, SM_DC_ADC_MODE_CONTINUOUS); - request_state_work(sm_dc, SM_DC_CC, DELAY_ADC_UPDATE); - return; - } - - if ((sm_dc->wq.pps_cl) && - ((sm_dc->ta.v * (sm_dc->ta.c + PPS_C_STEP) > sm_dc->ta.p_max) || - ((sm_dc->ta.c + PPS_C_STEP) > sm_dc->ta.c_max) || - (sm_dc->ta.c > sm_dc->wq.ci_gl + PRE_CC_ST_IBUS_OFFSET))) { - sm_dc->wq.c_offset = 0; - sm_dc->wq.cc_limit = 0; - pr_info("%s %s: [request] pre_cc -> cc\n", sm_dc->name, __func__); - sm_dc->ops->set_adc_mode(sm_dc->i2c, SM_DC_ADC_MODE_CONTINUOUS); - if (sm_dc->i2c_sub) - sm_dc->ops->set_adc_mode(sm_dc->i2c_sub, SM_DC_ADC_MODE_CONTINUOUS); - request_state_work(sm_dc, SM_DC_CC, DELAY_ADC_UPDATE); - return; - } - - if (sm_dc->wq.pps_cl) { - if ((adc_ibus < sm_dc->wq.ci_gl - (PPS_C_STEP * 6)) && - (sm_dc->ta.c < ((sm_dc->wq.ci_gl * 85)/100))) - sm_dc->ta.c += (PPS_C_STEP * 3); - else - sm_dc->ta.c += PPS_C_STEP; - - if (sm_dc->ta.c > sm_dc->ta.c_max) - sm_dc->ta.c = sm_dc->ta.c_max; - ret = send_power_source_msg(sm_dc); - if (ret < 0) - return; - - sm_dc->wq.c_up = 1; - sm_dc->wq.c_down = 0; - } else { - sm_dc->ta.v += PPS_V_STEP; - if (sm_dc->ta.v > MIN(sm_dc->ta.v_max, sm_dc->config.dc_vbus_ovp_th - 350)) { - pr_info("%s %s: can't increase voltage(v:%d, v_max:%d)\n", - sm_dc->name, __func__, sm_dc->ta.v, sm_dc->ta.v_max); - sm_dc->ta.v = pps_v(MIN(sm_dc->ta.v_max, sm_dc->config.dc_vbus_ovp_th - 350)); - sm_dc->wq.pps_cl = 1; - } - - ret = send_power_source_msg(sm_dc); - if (ret < 0) - return; - - sm_dc->wq.v_up = 1; - sm_dc->wq.v_down = 0; - } - - sm_dc->wq.prev_adc_vbus = adc_vbus; - sm_dc->wq.prev_adc_ibus = adc_ibus; - request_state_work(sm_dc, SM_DC_PRE_CC, delay_time); -} - -static void pd_cc_work(struct work_struct *work) -{ - struct sm_dc_info *sm_dc = container_of(work, struct sm_dc_info, cc_work.work); - int ret, adc_ibus, adc_vbus, adc_vbat; - u8 loop_status = LOOP_INACTIVE; -#if IS_ENABLED(CONFIG_DUAL_BATTERY) - union power_supply_propval value = {0,}; -#endif - - pr_info("%s %s\n", sm_dc->name, __func__); - - ret = check_error_state(sm_dc, SM_DC_CC); - if (ret < 0) - return; - if (ret == SM_DC_ERR_VBATREG) - loop_status = LOOP_VBATREG; - else if (ret == SM_DC_ERR_IBUSREG) - loop_status = LOOP_IBUSREG; - - ret = update_work_state(sm_dc, SM_DC_CC); - if (ret < 0) - return; - - get_adc_values(sm_dc, "[adc-values]:cc_work", &adc_vbus, &adc_ibus, NULL, - &adc_vbat, NULL, NULL, NULL); - -#if IS_ENABLED(CONFIG_DUAL_BATTERY) - psy_do_property("battery", get, - POWER_SUPPLY_EXT_PROP_DIRECT_VBAT_CHECK, value); - if (value.intval) { - pr_info("%s: CC MODE will be done by vcell\n", __func__); - loop_status = LOOP_VBATREG; - } -#endif - switch (loop_status) { - case LOOP_VBATREG: - sm_dc->wq.cv_cnt = 0; - pr_info("%s %s: [request] cc -> cv\n", sm_dc->name, __func__); - request_state_work(sm_dc, SM_DC_CV, DELAY_ADC_UPDATE); - return; - case LOOP_IBUSREG: - if (sm_dc->config.need_to_sw_ocp) { - pr_info("%s %s: call check_sw_ocp\n", sm_dc->name, __func__); - ret = sm_dc->ops->check_sw_ocp(sm_dc->i2c); - if (ret < 0) - return; - } - break; - } - - /* CC_STEP_DOWN */ - if (sm_dc->wq.ci_gl < adc_ibus) { - _try_to_adjust_cc_down(sm_dc); - if (sm_dc->config.support_pd_remain) { - ret = send_power_source_msg(sm_dc); - if (ret < 0) - return; - } - request_state_work(sm_dc, SM_DC_CC, DELAY_ADC_UPDATE); - return; - } - - if (adc_ibus >= sm_dc->wq.ci_gl - CC_ST_IBUS_OFFSET || sm_dc->wq.cc_limit) { - if (sm_dc->config.support_pd_remain) { - ret = send_power_source_msg(sm_dc); - if (ret < 0) - return; - } - request_state_work(sm_dc, SM_DC_CC, DELAY_CHG_LOOP); - return; - } - - /* CC_STEP_UP */ - ret = _try_to_adjust_cc_up(sm_dc); - if (ret < 0) { - if (sm_dc->config.support_pd_remain) { - ret = send_power_source_msg(sm_dc); - if (ret < 0) - return; - } - request_state_work(sm_dc, SM_DC_CC, DELAY_CHG_LOOP); - } else { - ret = send_power_source_msg(sm_dc); - if (ret < 0) - return; - - request_state_work(sm_dc, SM_DC_CC, DELAY_ADC_UPDATE); - } -} - -static void pd_cv_work(struct work_struct *work) -{ - struct sm_dc_info *sm_dc = container_of(work, struct sm_dc_info, cv_work.work); - int ret, adc_ibus, adc_vbus, adc_vbat, delay = DELAY_CHG_LOOP; - u8 loop_status = LOOP_INACTIVE; -#if IS_ENABLED(CONFIG_DUAL_BATTERY) - union power_supply_propval value = {0,}; -#endif - - pr_info("%s %s\n", sm_dc->name, __func__); - - ret = check_error_state(sm_dc, SM_DC_CV); - if (ret < 0) - return; - if (ret == SM_DC_ERR_VBATREG) - loop_status = LOOP_VBATREG; - else if (ret == SM_DC_ERR_IBUSREG) - loop_status = LOOP_IBUSREG; - - ret = update_work_state(sm_dc, SM_DC_CV); - if (ret < 0) - return; - - get_adc_values(sm_dc, "[adc-values]:cv_work", &adc_vbus, &adc_ibus, NULL, - &adc_vbat, NULL, NULL, NULL); - - if ((sm_dc->wq.cv_cnt == 0) && (loop_status & (LOOP_VBATREG | LOOP_IBUSREG))) - sm_dc->wq.cv_cnt = 1; - else if ((sm_dc->wq.cv_cnt == 1) && (loop_status == LOOP_INACTIVE)) - sm_dc->wq.cv_cnt = 2; - - switch (loop_status) { - case LOOP_VBATREG: - case LOOP_IBUSREG: - if (sm_dc->wq.cv_cnt == 1) - /* fast decrease PPS_V during on the first vbatreg loop */ - sm_dc->ta.v -= PPS_V_STEP * 2; - else - sm_dc->ta.v -= PPS_V_STEP; - - ret = send_power_source_msg(sm_dc); - if (ret < 0) - return; - - delay = DELAY_PPS_UPDATE; - break; - case LOOP_THEMREG: - if (sm_dc->config.support_pd_remain) { - ret = send_power_source_msg(sm_dc); - if (ret < 0) - return; - } - delay = DELAY_PPS_UPDATE; - break; - case LOOP_IBATREG: - /* un-used IBATREG*/ - loop_status = LOOP_INACTIVE; - break; - } - -#if IS_ENABLED(CONFIG_DUAL_BATTERY) - psy_do_property("battery", get, - POWER_SUPPLY_EXT_PROP_DIRECT_VBAT_CHECK, value); - if (value.intval) { - pr_info("%s %s: CV MODE will be done by vcell\n", sm_dc->name, __func__); - schedule_delayed_work(&sm_dc->done_event_work, msecs_to_jiffies(50)); - return; - } -#endif - - /* occurred abnormal CV status */ - if (adc_vbat < sm_dc->target_vbat - 100) { - pr_info("%s %s: adnormal cv, [request] cv -> pre_cc\n", sm_dc->name, __func__); - sm_dc->ops->set_adc_mode(sm_dc->i2c, SM_DC_ADC_MODE_ONESHOT); - if (sm_dc->i2c_sub) - sm_dc->ops->set_adc_mode(sm_dc->i2c_sub, SM_DC_ADC_MODE_ONESHOT); - request_state_work(sm_dc, SM_DC_PRE_CC, DELAY_ADC_UPDATE); - return; - } - -#if defined(CONFIG_DUAL_BATTERY_CELL_SENSING) - psy_do_property("battery", get, - POWER_SUPPLY_EXT_PROP_DIRECT_VBAT_CHECK, value); - if (value.intval) { - pr_info("%s %s: CV MODE will be done by vcell\n", sm_dc->name, __func__); - schedule_delayed_work(&sm_dc->done_event_work, msecs_to_jiffies(50)); - } -#endif - - /* Support to "POWER_SUPPLY_EXT_PROP_DIRECT_DONE" used ADC_IBUS */ - if (sm_dc->config.topoff_current > 0) { - if ((sm_dc->target_vbat == sm_dc->config.chg_float_voltage) && - (adc_ibus < sm_dc->config.topoff_current)) { - pr_info("%s %s: dc done!!\n", sm_dc->name, __func__); - schedule_delayed_work(&sm_dc->done_event_work, msecs_to_jiffies(50)); - } - } - - /* case IBUS_T < 1A than sub DC done */ - if (adc_ibus < CV_ST_SUB_DC_OFF_IBUS) { - if (sm_dc->i2c_sub) { - if (sm_dc->ops->get_charging_enable(sm_dc->i2c_sub)) { - sm_dc->ops->set_charging_enable(sm_dc->i2c_sub, 0); - pr_info("%s %s: sub dc done!!\n", sm_dc->name, __func__); - } - } - } - - if (loop_status == LOOP_INACTIVE && sm_dc->config.support_pd_remain) { - ret = send_power_source_msg(sm_dc); - if (ret < 0) - return; - } - request_state_work(sm_dc, SM_DC_CV, delay); -} - -static void pd_cv_man_work(struct work_struct *work) -{ - struct sm_dc_info *sm_dc = container_of(work, struct sm_dc_info, cv_man_work.work); - int ret, adc_ibus, adc_vbus, adc_vbat, delay = DELAY_ADC_UPDATE; - u8 loop_status = LOOP_INACTIVE; - - pr_info("%s %s\n", sm_dc->name, __func__); - - ret = check_error_state(sm_dc, SM_DC_CV_MAN); - if (ret < 0) - return; - if (ret == SM_DC_ERR_VBATREG) - loop_status = LOOP_VBATREG; - else if (ret == SM_DC_ERR_IBUSREG) - loop_status = LOOP_IBUSREG; - - get_adc_values(sm_dc, "[adc-values]:cv_man_work", &adc_vbus, &adc_ibus, NULL, - &adc_vbat, NULL, NULL, NULL); - - switch (loop_status) { - case LOOP_VBATREG: - case LOOP_IBUSREG: - if (sm_dc->ta.v > (2 * adc_vbat) + (PPS_V_STEP * 2)) - sm_dc->ta.v -= PPS_V_STEP; - - ret = send_power_source_msg(sm_dc); - if (ret < 0) - return; - delay = DELAY_PPS_UPDATE; - break; - } - - if (loop_status == LOOP_INACTIVE && sm_dc->config.support_pd_remain) { - ret = send_power_source_msg(sm_dc); - if (ret < 0) - return; - } - - request_state_work(sm_dc, SM_DC_CV_MAN, delay); -} - -static void pd_update_bat_work(struct work_struct *work) -{ - struct sm_dc_info *sm_dc = container_of(work, struct sm_dc_info, update_bat_work.work); - int index, ret, cnt; - bool need_to_preset = 1; - - pr_info("%s %s\n", sm_dc->name, __func__); - - ret = check_error_state(sm_dc, SM_DC_UPDAT_BAT); - if (ret < 0) - return; - - /* waiting for step change event */ - for (cnt = 0; cnt < 1; ++cnt) { - if (sm_dc->req_update_vbat && sm_dc->req_update_ibus) - break; - - pr_info("%s %s: wait 1sec for step changed\n", sm_dc->name, __func__); - msleep(1000); - } - - mutex_lock(&sm_dc->st_lock); - index = (sm_dc->req_update_vbat << 2) | (sm_dc->req_update_ibus << 1) | sm_dc->req_update_ibat; - sm_dc->req_update_vbat = 0; - sm_dc->req_update_ibus = 0; - sm_dc->req_update_ibat = 0; - mutex_unlock(&sm_dc->st_lock); - - ret = update_work_state(sm_dc, SM_DC_UPDAT_BAT); - if (ret < 0) - return; - - if (index & (0x1 << 2)) - pr_info("%s %s: vbat changed (%dmV)\n", sm_dc->name, __func__, sm_dc->target_vbat); - - if (index & (0x1 << 1)) - pr_info("%s %s: ibus changed (%dmA)\n", sm_dc->name, __func__, sm_dc->target_ibus); - - if (index & 0x1) - pr_info("%s %s: ibat changed (%dmA)\n", sm_dc->name, __func__, sm_dc->target_ibat); - - /* check step change event */ - if ((index & (0x1 << 2)) && (index & (0x1 << 1))) { - if ((sm_dc->target_vbat > sm_dc->wq.cv_gl) && (sm_dc->target_ibus < sm_dc->wq.ci_gl)) - need_to_preset = 0; - } - - sm_dc->ops->set_adc_mode(sm_dc->i2c, SM_DC_ADC_MODE_ONESHOT); - - if (need_to_preset) { - pr_info("%s %s: [request] update_bat -> preset\n", sm_dc->name, __func__); - request_state_work(sm_dc, SM_DC_PRESET, DELAY_NONE); - } else { - setup_direct_charging_work_config(sm_dc); - sm_dc->ta.c = pps_c(sm_dc->wq.ci_gl - 200 - sm_dc->wq.c_offset); - ret = send_power_source_msg(sm_dc); - if (ret < 0) - return; - - pr_info("%s %s: [request] update_bat -> pre_cc\n", sm_dc->name, __func__); - request_state_work(sm_dc, SM_DC_PRE_CC, DELAY_ADC_UPDATE); - } -} - -static void pd_error_work(struct work_struct *work) -{ - struct sm_dc_info *sm_dc = container_of(work, struct sm_dc_info, error_work.work); - int ret; - - pr_info("%s %s: err=0x%x\n", sm_dc->name, __func__, sm_dc->err); - - ret = update_work_state(sm_dc, SM_DC_ERR); - if (ret < 0) - return; - - sm_dc->ops->set_adc_mode(sm_dc->i2c, SM_DC_ADC_MODE_OFF); - sm_dc->ops->set_charging_enable(sm_dc->i2c, 0); -} - -static void sec_done_event_work(struct work_struct *work) -{ - struct sm_dc_info *sm_dc = container_of(work, struct sm_dc_info, done_event_work.work); - union power_supply_propval value = {0, }; - - pr_info("%s called\n", __func__); - - value.intval = 1; - psy_do_property(sm_dc->config.sec_dc_name, set, POWER_SUPPLY_EXT_PROP_DIRECT_DONE, value); -} - -/** - * Dual battery Direct-charging work functions - */ -static inline u32 _x2bat_calc_v_init_offset(struct sm_dc_info *sm_dc) -{ - u32 offset; - - offset = (((sm_dc->wq.ci_gl * 50) / 100) * sm_dc->config.r_ttl) / 1000000; - pr_info("%s %s: ci_gl=%dmA, v_init_offset=%d\n", sm_dc->name, - __func__, sm_dc->wq.ci_gl, offset); - - return offset; -} - -static inline void _x2bat_try_to_adjust_cc_down(struct sm_dc_info *sm_dc) -{ - if (sm_dc->ta.v >= sm_dc->config.ta_min_voltage) { - sm_dc->ta.v -= PPS_V_STEP; - } else { - sm_dc->ta.v = sm_dc->config.ta_min_voltage; - pr_info("%s %s: can't use less then ta_min_voltage\n", sm_dc->name, __func__); - } -} - -static inline void _x2bat_try_to_adjust_cc_up(struct sm_dc_info *sm_dc) -{ - if (sm_dc->ta.v >= - MIN(((sm_dc->ta.p_max * 100) / sm_dc->ta.c) / 100, sm_dc->config.dc_vbus_ovp_th - 350)) { - pr_info("%s %s: can't increase voltage(v:%d, v_max:%d)\n", - sm_dc->name, __func__, sm_dc->ta.v, sm_dc->ta.v_max); - } else { - sm_dc->ta.v += PPS_V_STEP; - } -} - -static int _x2bat_set_ibusreg_m_down(struct sm_dc_info *sm_dc) -{ - sm_dc->wq.ci_gl_m = MIN(sm_dc->ta.c_max, ((sm_dc->wq.ci_gl_m * 100) / 100) - 100); - sm_dc->wq.ci_gl = MIN(sm_dc->ta.c_max, sm_dc->wq.ci_gl_m + sm_dc->wq.ci_gl_s); - sm_dc->wq.cc_gl = sm_dc->wq.ci_gl * 2; - - pr_info("%s %s: CV_GL=%dmV, CI_GL=%dmA, CI_GL_M=%dmA, CI_GL_S=%dmA, CC_GL=%dmA\n", sm_dc->name, - __func__, sm_dc->wq.cv_gl, sm_dc->wq.ci_gl, - sm_dc->wq.ci_gl_m, sm_dc->wq.ci_gl_s, sm_dc->wq.cc_gl); - sm_dc->ops->set_charging_config(sm_dc->i2c, sm_dc->wq.cv_gl, sm_dc->wq.ci_gl_m, sm_dc->wq.cc_gl); - - return 0; -} - -static int x2bat_get_adc_values(struct sm_dc_info *sm_dc, const char *str, int *vbus, int *ibus, - int *ibus_m, int *ibus_s, int *vout, int *vbat_m, int *vbat_s, int *ibat, int *them, int *dietemp) -{ - int adc_vbus = 0, adc_ibus = 0, adc_vout = 0, adc_vbat = 0, adc_ibat = 0, adc_them = 0, adc_dietemp = 0, adc_ibus_t = 0; - int adc_vbus2 = 0, adc_ibus2 = 0, adc_vout2 = 0, adc_vbat2 = 0, adc_ibat2 = 0, adc_them2 = 0, adc_dietemp2 = 0; - - adc_vbus = sm_dc->ops->get_adc_value(sm_dc->i2c, SM_DC_ADC_VBUS); - adc_ibus = sm_dc->ops->get_adc_value(sm_dc->i2c, SM_DC_ADC_IBUS); - adc_vout = sm_dc->ops->get_adc_value(sm_dc->i2c, SM_DC_ADC_VOUT); - adc_vbat = sm_dc->ops->get_adc_value(sm_dc->i2c, SM_DC_ADC_VBAT); - adc_ibat = sm_dc->ops->get_adc_value(sm_dc->i2c, SM_DC_ADC_IBAT); - adc_them = sm_dc->ops->get_adc_value(sm_dc->i2c, SM_DC_ADC_THEM); - adc_dietemp = sm_dc->ops->get_adc_value(sm_dc->i2c, SM_DC_ADC_DIETEMP); - - pr_info("%s %s:vbus:%d:ibus:%d:vout:%d:vbat:%d:ibat:%d:them:%d:dietemp:%d\n", - sm_dc->name, str, adc_vbus, adc_ibus, adc_vout, - adc_vbat, adc_ibat, adc_them, adc_dietemp); - - if (sm_dc->i2c_sub) { - if (sm_dc->ops->get_charging_enable(sm_dc->i2c_sub)) { - adc_vbus2 = sm_dc->ops->get_adc_value(sm_dc->i2c_sub, SM_DC_ADC_VBUS); - adc_ibus2 = sm_dc->ops->get_adc_value(sm_dc->i2c_sub, SM_DC_ADC_IBUS); - adc_vout2 = sm_dc->ops->get_adc_value(sm_dc->i2c_sub, SM_DC_ADC_VOUT); - adc_vbat2 = sm_dc->ops->get_adc_value(sm_dc->i2c_sub, SM_DC_ADC_VBAT); - adc_ibat2 = sm_dc->ops->get_adc_value(sm_dc->i2c_sub, SM_DC_ADC_IBAT); - adc_them2 = sm_dc->ops->get_adc_value(sm_dc->i2c_sub, SM_DC_ADC_THEM); - adc_dietemp2 = sm_dc->ops->get_adc_value(sm_dc->i2c_sub, SM_DC_ADC_DIETEMP); - adc_ibus_t = adc_ibus + adc_ibus2; - pr_info("%s %s(s):vbus:%d:ibus:%d:ibus_t:%d:vout:%d:vbat:%d:ibat:%d:them:%d:dietemp:%d\n", - sm_dc->name, str, adc_vbus2, adc_ibus2, adc_ibus_t, adc_vout2, - adc_vbat2, adc_ibat2, adc_them2, adc_dietemp2); - } else { - adc_ibus_t = adc_ibus; - } - } else { - adc_ibus_t = adc_ibus; - } - - if (vbus) - *vbus = adc_vbus; - - if (ibus) - *ibus = adc_ibus_t; - - if (ibus_m) - *ibus_m = adc_ibus; - - if (ibus_s) - *ibus_s = adc_ibus2; - - if (vout) - *vout = adc_vout; - - if (vbat_m) - *vbat_m = adc_vbat; - - if (vbat_s) - *vbat_s = adc_vbat2; - - if (ibat) - *ibat = adc_ibat; - - if (them) - *them = adc_them; - - if (dietemp) - *dietemp = adc_dietemp; - - return 0; -} - -static int x2bat_setup_direct_charging_work_config(struct sm_dc_info *sm_dc) -{ - u32 target_ibus_sub = 0; - - if (sm_dc->i2c_sub) - target_ibus_sub = sm_dc->ops->get_target_ibus(sm_dc->i2c_sub); - - sm_dc->wq.cv_cnt = 0; - sm_dc->wq.cv_gl = sm_dc->target_vbat; - sm_dc->wq.ci_gl_s = MIN(sm_dc->ta.c_max, ((target_ibus_sub * 100) / 100)); - sm_dc->wq.ci_gl_m = MIN(sm_dc->ta.c_max, ((sm_dc->target_ibus * 100) / 100)); - sm_dc->wq.ci_gl = MIN(sm_dc->ta.c_max, sm_dc->target_ibus + target_ibus_sub); - sm_dc->wq.cc_gl = sm_dc->wq.ci_gl * 2; - sm_dc->wq.retry_cnt = 0; - sm_dc->wq.cc_cnt = 0; - sm_dc->wq.topoff_m = 0; - sm_dc->wq.topoff_s = 0; - - pr_info("%s %s: CV_GL=%dmV, CI_GL=%dmA, CI_GL_M=%dmA, CI_GL_S=%dmA, CC_GL=%dmA\n", sm_dc->name, - __func__, sm_dc->wq.cv_gl, sm_dc->wq.ci_gl, - sm_dc->wq.ci_gl_m, sm_dc->wq.ci_gl_s, sm_dc->wq.cc_gl); - sm_dc->ops->set_charging_config(sm_dc->i2c, sm_dc->wq.cv_gl, sm_dc->wq.ci_gl_m, sm_dc->wq.cc_gl); - if (sm_dc->i2c_sub) - sm_dc->ops->set_charging_config(sm_dc->i2c_sub, sm_dc->wq.cv_gl, sm_dc->wq.ci_gl_s, sm_dc->wq.cc_gl); - return 0; -} - -static int x2bat_check_error_state(struct sm_dc_info *sm_dc, u8 retry_state) -{ - int adc_vbat, adc_ibus, chgon_m, chgon_s; - u32 sub_err; - - if (sm_dc->state == SM_DC_ERR) { - pr_err("%s %s: already occurred error (err=0x%x)\n", sm_dc->name, __func__, sm_dc->err); - return -EINVAL; - } - - sm_dc->err = sm_dc->ops->get_dc_error_status(sm_dc->i2c); - if (sm_dc->err == SM_DC_ERR_RETRY) { - pr_err("%s %s: error status retry, wait 2sec\n", sm_dc->name, __func__); - request_state_work(sm_dc, retry_state, DELAY_RETRY); - return -EAGAIN; - } else if (sm_dc->err == SM_DC_ERR_VBATREG) { - sm_dc->err = SM_DC_ERR_VBATREG; - } else if (sm_dc->err == SM_DC_ERR_IBUSREG) { - sm_dc->err = SM_DC_ERR_IBUSREG; - } else if (sm_dc->err > SM_DC_ERR_NONE) { - pr_err("%s %s: error status:0x%x\n", sm_dc->name, __func__, sm_dc->err); - // request_state_work(sm_dc, SM_DC_ERR, DELAY_NONE); - // return -EPERM; - } - - if (sm_dc->i2c_sub) { - chgon_m = sm_dc->ops->get_charging_enable(sm_dc->i2c); - chgon_s = sm_dc->ops->get_charging_enable(sm_dc->i2c_sub); - if (chgon_s == 0 && chgon_m == 0) { - sm_dc->err = SM_DC_ERR_FAIL_ADJUST; - } else if (chgon_s == 0x0) { // CHG_S == 0 && IBUS_M >= 1500 than DC err - adc_ibus = sm_dc->ops->get_adc_value(sm_dc->i2c, SM_DC_ADC_IBUS); - if (adc_ibus > SM_DC_DUAL_STOP_IBUS) - sm_dc->err = SM_DC_ERR_FAIL_ADJUST; - } else if (chgon_m == 0x0) { // CHG_M == 0 && IBUS_S >= 1500 than DC err - adc_ibus = sm_dc->ops->get_adc_value(sm_dc->i2c_sub, SM_DC_ADC_IBUS); - if (adc_ibus > SM_DC_DUAL_STOP_IBUS) - sm_dc->err = SM_DC_ERR_FAIL_ADJUST; - } - if (sm_dc->err == SM_DC_ERR_FAIL_ADJUST) { - pr_err("%s %s: error status:0x%x\n", sm_dc->name, __func__, sm_dc->err); - request_state_work(sm_dc, SM_DC_ERR, DELAY_NONE); - return -ERANGE; - } - - sub_err = sm_dc->ops->get_dc_error_status(sm_dc->i2c_sub); - if (sub_err == SM_DC_ERR_VBATREG) { - sm_dc->err = SM_DC_ERR_VBATREG_S; - return sm_dc->err; - } else if (sm_dc->err == SM_DC_ERR_VBATREG) { - sm_dc->err = SM_DC_ERR_VBATREG; - return sm_dc->err; - } else if (sm_dc->err == SM_DC_ERR_IBUSREG && sub_err == SM_DC_ERR_IBUSREG) { - sm_dc->err = SM_DC_ERR_IBUSREG; - return sm_dc->err; - } else if (sm_dc->err == SM_DC_ERR_IBUSREG) { - sm_dc->err = SM_DC_ERR_IBUSREG_M; - return sm_dc->err; - } else if (sm_dc->err > SM_DC_ERR_NONE) { - pr_err("%s %s: error status:0x%x\n", sm_dc->name, __func__, sm_dc->err); - } - } else { - if (sm_dc->err == SM_DC_ERR_IBUSREG || sm_dc->err == SM_DC_ERR_VBATREG) - return sm_dc->err; - } - - adc_vbat = sm_dc->ops->get_adc_value(sm_dc->i2c, SM_DC_ADC_VBAT); - if (adc_vbat <= sm_dc->config.dc_min_vbat) { - pr_err("%s %s: abnormal adc_vbat(%d)\n", sm_dc->name, __func__, adc_vbat); - sm_dc->err = SM_DC_ERR_INVAL_VBAT; - request_state_work(sm_dc, SM_DC_ERR, DELAY_NONE); - return -ERANGE; - } - - return 0; -} - -static void x2bat_check_vbat_work(struct work_struct *work) -{ - struct sm_dc_info *sm_dc = container_of(work, struct sm_dc_info, check_vbat_work.work); - struct sm_dc_power_source_info ta; - union power_supply_propval val = {0, }; - int adc_vbat; - int ret; - - ret = update_work_state(sm_dc, SM_DC_CHECK_VBAT); - if (ret < 0) - return; - - ret = psy_do_property(sm_dc->config.sec_dc_name, get, - POWER_SUPPLY_EXT_PROP_CHARGING_ENABLED_DC, val); - if (ret < 0) { - pr_err("%s %s: is not ready to work (wait 1sec)\n", sm_dc->name, __func__); - request_state_work(sm_dc, SM_DC_CHECK_VBAT, DELAY_ADC_UPDATE); - return; - } - - ret = sm_dc->ops->get_apdo_max_power(sm_dc->i2c, &ta); - if (ret < 0) { - if (sm_dc->ta.retry_cnt < 3) { - pr_err("%s %s: get_apdo_max_power, RETRY=%d\n", - sm_dc->name, __func__, sm_dc->ta.retry_cnt); - sm_dc->ta.retry_cnt++; - request_state_work(sm_dc, SM_DC_CHECK_VBAT, DELAY_PPS_UPDATE); - } else { - pr_err("%s %s: fail to get APDO(ret=%d)\n", sm_dc->name, __func__, ret); - sm_dc->err = SM_DC_ERR_SEND_PD_MSG; - request_state_work(sm_dc, SM_DC_ERR, DELAY_NONE); - } - return; - } - - if (sm_dc->i2c_sub) { - ret = sm_dc->ops->get_apdo_max_power(sm_dc->i2c_sub, &ta); - if (ret < 0) { - pr_err("%s %s: fail to get APDO(ret=%d)\n", sm_dc->name, __func__, ret); - return; - } - } - - val.intval = 0; - - if (val.intval == 0) { /* already disabled switching charger */ - pr_info("%s %s: [request] check_vbat -> preset\n", sm_dc->name, __func__); - request_state_work(sm_dc, SM_DC_PRESET, DELAY_NONE); - - psy_do_property(sm_dc->config.sec_dc_name, set, - POWER_SUPPLY_EXT_PROP_CHARGING_ENABLED_DC, val); - } else { - adc_vbat = sm_dc->ops->get_adc_value(sm_dc->i2c, SM_DC_ADC_VBAT); - pr_info("%s %s: adc:vbat=%dmV\n", sm_dc->name, __func__, adc_vbat); - - if (adc_vbat > sm_dc->config.dc_min_vbat) { - pr_info("%s %s: set_prop - disable sw_chg\n", sm_dc->name, __func__); - val.intval = 0; - psy_do_property(sm_dc->config.sec_dc_name, set, - POWER_SUPPLY_EXT_PROP_CHARGING_ENABLED_DC, val); - } - pr_err("%s %s: sw_chg not disabled yet (wait 1sec)\n", sm_dc->name, __func__); - request_state_work(sm_dc, SM_DC_CHECK_VBAT, DELAY_ADC_UPDATE); - } -} - -static void x2bat_preset_dc_work(struct work_struct *work) -{ - struct sm_dc_info *sm_dc = container_of(work, struct sm_dc_info, preset_dc_work.work); - u32 target_ibus_sub = 0; - int adc_vbat, ret, delay = DELAY_PPS_UPDATE; - - ret = update_work_state(sm_dc, SM_DC_PRESET); - if (ret < 0) - return; - - adc_vbat = sm_dc->ops->get_adc_value(sm_dc->i2c, SM_DC_ADC_VBAT); - if (adc_vbat > sm_dc->target_vbat + PPS_V_STEP) { /* Debounce ADC accuracy */ - pr_err("%s %s: adc_vbat(%dmV) > target_v, can't start dc\n", sm_dc->name, __func__, adc_vbat); - sm_dc->err = SM_DC_ERR_INVAL_VBAT; - request_state_work(sm_dc, SM_DC_ERR, DELAY_NONE); - return; - } - if (sm_dc->i2c_sub) - target_ibus_sub = sm_dc->ops->get_target_ibus(sm_dc->i2c_sub); - - pr_info("%s %s: adc_vbat=%dmV, ta_min_v=%dmV, v_max=%dmA, c_max=%dmA, target_ibus=%dmA\n", - sm_dc->name, __func__, adc_vbat, sm_dc->config.ta_min_voltage, sm_dc->ta.v_max, - sm_dc->ta.c_max, sm_dc->target_ibus + target_ibus_sub); - - sm_dc->wq.ci_gl = MIN(sm_dc->ta.c_max, sm_dc->target_ibus + target_ibus_sub); - sm_dc->ta.c = pps_c(MAX(MIN(sm_dc->ta.c_max, sm_dc->wq.ci_gl + 200), - sm_dc->config.ta_min_current)); - if (sm_dc->ta.v_max < SM_DC_BYPASS_TA_MAX_VOL) { - sm_dc->ta.v = adc_vbat + _x2bat_calc_v_init_offset(sm_dc); - sm_dc->ta.v = pps_v(MAX(sm_dc->ta.v, sm_dc->config.ta_min_voltage / 2)); - } else { - sm_dc->ta.v = (2 * adc_vbat) + _x2bat_calc_v_init_offset(sm_dc); - sm_dc->ta.v = pps_v(MAX(sm_dc->ta.v, sm_dc->config.ta_min_voltage)); - } - ret = send_power_source_msg(sm_dc); - if (ret < 0) - return; - - msleep(DELAY_PPS_UPDATE); - - if (sm_dc->ops->get_charging_enable(sm_dc->i2c) == 0x0) - _adjust_pps_v(sm_dc, sm_dc->ta.v); - - if (sm_dc->target_ibus < sm_dc->wq.ci_gl) - delay = DELAY_ADC_UPDATE; - - x2bat_setup_direct_charging_work_config(sm_dc); - if (sm_dc->i2c_sub) - sm_dc->ops->set_charging_enable(sm_dc->i2c_sub, 1); - sm_dc->ops->set_charging_enable(sm_dc->i2c, 1); - pr_info("%s %s: enable Direct-charging\n", sm_dc->name, __func__); - /* Pre-update PRE_CC state. for check to charging initial error case */ - ret = update_work_state(sm_dc, SM_DC_PRE_CC); - if (ret < 0) - return; - - pr_info("%s %s: [request] preset -> pre_cc\n", sm_dc->name, __func__); - request_state_work(sm_dc, SM_DC_PRE_CC, delay); -} - -static void x2bat_pre_cc_work(struct work_struct *work) -{ - struct sm_dc_info *sm_dc = container_of(work, struct sm_dc_info, pre_cc_work.work); - int ret, adc_ibus, adc_ibus_s, adc_vbus, adc_vbat; - u8 loop_status = LOOP_INACTIVE; - - pr_info("%s %s: (CI_GL=%dmA)\n", sm_dc->name, __func__, sm_dc->wq.ci_gl); - ret = x2bat_check_error_state(sm_dc, SM_DC_PRE_CC); - if (ret < 0) - return; - if (ret == SM_DC_ERR_VBATREG) - loop_status = LOOP_VBATREG; - else if (ret == SM_DC_ERR_VBATREG_S) - loop_status = LOOP_VBATREG_S; - else if (ret == SM_DC_ERR_IBUSREG) - loop_status = LOOP_IBUSREG; - else if (ret == SM_DC_ERR_IBUSREG_M) - loop_status = LOOP_IBUSREG_M; - - ret = update_work_state(sm_dc, SM_DC_PRE_CC); - if (ret < 0) - return; - - x2bat_get_adc_values(sm_dc, "[adc-values]:pre_cc_work", &adc_vbus, &adc_ibus, NULL, - &adc_ibus_s, NULL, &adc_vbat, NULL, NULL, NULL, NULL); - - switch (loop_status) { - case LOOP_VBATREG: - case LOOP_VBATREG_S: - sm_dc->wq.cv_cnt = 0; - sm_dc->wq.topoff_m = 0; - sm_dc->wq.topoff_s = 0; - pr_info("%s %s: [request] pre-cc -> cv\n", sm_dc->name, __func__); - sm_dc->ops->set_adc_mode(sm_dc->i2c, SM_DC_ADC_MODE_CONTINUOUS); - if (sm_dc->i2c_sub) - sm_dc->ops->set_adc_mode(sm_dc->i2c_sub, SM_DC_ADC_MODE_CONTINUOUS); - request_state_work(sm_dc, SM_DC_CV, DELAY_ADC_UPDATE); - return; - case LOOP_IBUSREG: - if (sm_dc->config.need_to_sw_ocp && sm_dc->wq.c_down == 1) { - pr_info("%s %s: call check_sw_ocp\n", sm_dc->name, __func__); - ret = sm_dc->ops->check_sw_ocp(sm_dc->i2c); - if (ret < 0) - return; - } - _x2bat_try_to_adjust_cc_down(sm_dc); - ret = send_power_source_msg(sm_dc); - if (ret < 0) - return; - sm_dc->ops->set_adc_mode(sm_dc->i2c, SM_DC_ADC_MODE_CONTINUOUS); - if (sm_dc->i2c_sub) - sm_dc->ops->set_adc_mode(sm_dc->i2c_sub, SM_DC_ADC_MODE_CONTINUOUS); - request_state_work(sm_dc, SM_DC_PRE_CC, DELAY_PPS_UPDATE); - return; - case LOOP_IBUSREG_M: - if (adc_ibus_s > sm_dc->wq.ci_gl_s - PPS_C_STEP) { - pr_info("%s %s: [request] pre_cc -> cc\n", sm_dc->name, __func__); - sm_dc->ops->set_adc_mode(sm_dc->i2c, SM_DC_ADC_MODE_CONTINUOUS); - if (sm_dc->i2c_sub) - sm_dc->ops->set_adc_mode(sm_dc->i2c_sub, SM_DC_ADC_MODE_CONTINUOUS); - request_state_work(sm_dc, SM_DC_CC, DELAY_ADC_UPDATE); - return; - } - break; - } - - if (sm_dc->ta.v >= - MIN(((sm_dc->ta.p_max * 100) / sm_dc->ta.c) / 100, sm_dc->config.dc_vbus_ovp_th - 350)) { - pr_info("%s %s: [request] pre_cc -> cc\n", sm_dc->name, __func__); - sm_dc->ops->set_adc_mode(sm_dc->i2c, SM_DC_ADC_MODE_CONTINUOUS); - if (sm_dc->i2c_sub) - sm_dc->ops->set_adc_mode(sm_dc->i2c_sub, SM_DC_ADC_MODE_CONTINUOUS); - request_state_work(sm_dc, SM_DC_CC, DELAY_ADC_UPDATE); - } - - if (adc_ibus_s < sm_dc->wq.ci_gl_s - 500) - sm_dc->ta.v += PPS_V_STEP * 2; - else - sm_dc->ta.v += PPS_V_STEP; - ret = send_power_source_msg(sm_dc); - if (ret < 0) - return; - sm_dc->ops->set_adc_mode(sm_dc->i2c, SM_DC_ADC_MODE_CONTINUOUS); - if (sm_dc->i2c_sub) - sm_dc->ops->set_adc_mode(sm_dc->i2c_sub, SM_DC_ADC_MODE_CONTINUOUS); - request_state_work(sm_dc, SM_DC_PRE_CC, DELAY_PPS_UPDATE); -} - -static void x2bat_cc_work(struct work_struct *work) -{ - struct sm_dc_info *sm_dc = container_of(work, struct sm_dc_info, pre_cc_work.work); - int ret, adc_ibus, adc_ibus_s, adc_vbus, adc_vbat; - u8 loop_status = LOOP_INACTIVE; - - pr_info("%s %s: (CI_GL=%dmA)\n", sm_dc->name, __func__, sm_dc->wq.ci_gl); - ret = x2bat_check_error_state(sm_dc, SM_DC_PRE_CC); - if (ret < 0) - return; - if (ret == SM_DC_ERR_VBATREG) - loop_status = LOOP_VBATREG; - else if (ret == SM_DC_ERR_VBATREG_S) - loop_status = LOOP_VBATREG_S; - else if (ret == SM_DC_ERR_IBUSREG) - loop_status = LOOP_IBUSREG; - else if (ret == SM_DC_ERR_IBUSREG_M) - loop_status = LOOP_IBUSREG_M; - - ret = update_work_state(sm_dc, SM_DC_PRE_CC); - if (ret < 0) - return; - - x2bat_get_adc_values(sm_dc, "[adc-values]:cc_work", &adc_vbus, &adc_ibus, NULL, - &adc_ibus_s, NULL, &adc_vbat, NULL, NULL, NULL, NULL); - - switch (loop_status) { - case LOOP_VBATREG: - case LOOP_VBATREG_S: - sm_dc->wq.cv_cnt = 0; - sm_dc->wq.topoff_m = 0; - sm_dc->wq.topoff_s = 0; - pr_info("%s %s: [request] pre-cc -> cv\n", sm_dc->name, __func__); - sm_dc->ops->set_adc_mode(sm_dc->i2c, SM_DC_ADC_MODE_CONTINUOUS); - if (sm_dc->i2c_sub) - sm_dc->ops->set_adc_mode(sm_dc->i2c_sub, SM_DC_ADC_MODE_CONTINUOUS); - request_state_work(sm_dc, SM_DC_CV, DELAY_ADC_UPDATE); - return; - case LOOP_IBUSREG: - if (sm_dc->config.need_to_sw_ocp && sm_dc->wq.v_down == 1) { - pr_info("%s %s: call check_sw_ocp\n", sm_dc->name, __func__); - ret = sm_dc->ops->check_sw_ocp(sm_dc->i2c); - if (ret < 0) - return; - } - _x2bat_try_to_adjust_cc_down(sm_dc); - ret = send_power_source_msg(sm_dc); - if (ret < 0) - return; - sm_dc->ops->set_adc_mode(sm_dc->i2c, SM_DC_ADC_MODE_CONTINUOUS); - if (sm_dc->i2c_sub) - sm_dc->ops->set_adc_mode(sm_dc->i2c_sub, SM_DC_ADC_MODE_CONTINUOUS); - request_state_work(sm_dc, SM_DC_CC, DELAY_ADC_UPDATE); - return; - case LOOP_IBUSREG_M: - if (adc_ibus_s < sm_dc->wq.ci_gl_s + (CC_ST_IBUS_OFFSET) && - adc_ibus_s > sm_dc->wq.ci_gl_s - CC_ST_IBUS_OFFSET) { - if (sm_dc->config.support_pd_remain) { - ret = send_power_source_msg(sm_dc); - if (ret < 0) - return; - } - sm_dc->ops->set_adc_mode(sm_dc->i2c, SM_DC_ADC_MODE_CONTINUOUS); - if (sm_dc->i2c_sub) - sm_dc->ops->set_adc_mode(sm_dc->i2c_sub, SM_DC_ADC_MODE_CONTINUOUS); - request_state_work(sm_dc, SM_DC_CC, DELAY_CHG_LOOP); - return; - } else if (adc_ibus_s > sm_dc->wq.ci_gl_s + (CC_ST_IBUS_OFFSET / 2)) { - _x2bat_try_to_adjust_cc_down(sm_dc); - ret = send_power_source_msg(sm_dc); - if (ret < 0) - return; - sm_dc->ops->set_adc_mode(sm_dc->i2c, SM_DC_ADC_MODE_CONTINUOUS); - if (sm_dc->i2c_sub) - sm_dc->ops->set_adc_mode(sm_dc->i2c_sub, SM_DC_ADC_MODE_CONTINUOUS); - request_state_work(sm_dc, SM_DC_CC, DELAY_ADC_UPDATE); - } - break; - } - - _x2bat_try_to_adjust_cc_up(sm_dc); - ret = send_power_source_msg(sm_dc); - if (ret < 0) - return; - sm_dc->ops->set_adc_mode(sm_dc->i2c, SM_DC_ADC_MODE_CONTINUOUS); - if (sm_dc->i2c_sub) - sm_dc->ops->set_adc_mode(sm_dc->i2c_sub, SM_DC_ADC_MODE_CONTINUOUS); - request_state_work(sm_dc, SM_DC_CC, DELAY_ADC_UPDATE); -} - -static void x2bat_cv_work(struct work_struct *work) -{ - struct sm_dc_info *sm_dc = container_of(work, struct sm_dc_info, cv_work.work); - int ret, adc_ibus, adc_vbus, adc_ibus_s, adc_vbat_m, adc_vbat_s; - u8 loop_status = LOOP_INACTIVE; - - pr_info("%s %s\n", sm_dc->name, __func__); - - ret = x2bat_check_error_state(sm_dc, SM_DC_CV); - if (ret < 0) - return; - if (ret == SM_DC_ERR_VBATREG) - loop_status = LOOP_VBATREG; - else if (ret == SM_DC_ERR_VBATREG_S) - loop_status = LOOP_VBATREG_S; - else if (ret == SM_DC_ERR_IBUSREG) - loop_status = LOOP_IBUSREG; - else if (ret == SM_DC_ERR_IBUSREG_M) - loop_status = LOOP_IBUSREG_M; - - ret = update_work_state(sm_dc, SM_DC_CV); - if (ret < 0) - return; - - x2bat_get_adc_values(sm_dc, "[adc-values]:cv_work", &adc_vbus, &adc_ibus, NULL, - &adc_ibus_s, NULL, &adc_vbat_m, &adc_vbat_s, NULL, NULL, NULL); - - /* main off */ - if (((sm_dc->wq.ci_gl_m - 100) / 100) * 100 <= SM_DC_CI_OFFSET_X2BAT) { - sm_dc->wq.topoff_m = 1; - sm_dc->ops->set_charging_enable(sm_dc->i2c, 0); - pr_info("%s %s: main dc done!!\n", sm_dc->name, __func__); - } - - /* sub DC off */ - if (sm_dc->config.topoff_current > 0) { - if ((sm_dc->target_vbat == sm_dc->config.chg_float_voltage) && - (adc_ibus_s < sm_dc->config.topoff_current)) { - sm_dc->wq.topoff_s = 1; - if (sm_dc->i2c_sub) { - if (sm_dc->ops->get_charging_enable(sm_dc->i2c_sub)) { - sm_dc->ops->set_charging_enable(sm_dc->i2c_sub, 0); - pr_info("%s %s: sub dc done!!\n", sm_dc->name, __func__); - } - } - } - } - - /* Support to "POWER_SUPPLY_EXT_PROP_DIRECT_DONE" used TOPOFF flag */ - if (sm_dc->wq.topoff_m && sm_dc->wq.topoff_s) { - pr_info("%s : dc done!!\n", __func__); - schedule_delayed_work(&sm_dc->done_event_work, msecs_to_jiffies(50)); - } - - if (!sm_dc->wq.topoff_s) { - if (loop_status == LOOP_VBATREG_S) { - _x2bat_try_to_adjust_cc_down(sm_dc); - ret = send_power_source_msg(sm_dc); - if (ret < 0) - return; - sm_dc->ops->set_adc_mode(sm_dc->i2c, SM_DC_ADC_MODE_CONTINUOUS); - if (sm_dc->i2c_sub) - sm_dc->ops->set_adc_mode(sm_dc->i2c_sub, SM_DC_ADC_MODE_CONTINUOUS); - request_state_work(sm_dc, SM_DC_CV, DELAY_ADC_UPDATE); - return; - } - } - - if (!sm_dc->wq.topoff_m) { - if (loop_status == LOOP_VBATREG) { - _x2bat_set_ibusreg_m_down(sm_dc); // ci_gl = ci_gl - 100mA - ret = send_power_source_msg(sm_dc); - if (ret < 0) - return; - sm_dc->ops->set_adc_mode(sm_dc->i2c, SM_DC_ADC_MODE_CONTINUOUS); - if (sm_dc->i2c_sub) - sm_dc->ops->set_adc_mode(sm_dc->i2c_sub, SM_DC_ADC_MODE_CONTINUOUS); - request_state_work(sm_dc, SM_DC_CV, DELAY_ADC_UPDATE); - } - } - - /* occurred abnormal CV status */ - if (loop_status == LOOP_IBUSREG || - adc_vbat_m < sm_dc->wq.ci_gl_m - 100 || adc_vbat_s < sm_dc->wq.ci_gl_s - 100) { - pr_info("%s %s: adnormal cv, [request] cv -> pre_cc\n", sm_dc->name, __func__); - sm_dc->ops->set_adc_mode(sm_dc->i2c, SM_DC_ADC_MODE_ONESHOT); - if (sm_dc->i2c_sub) - sm_dc->ops->set_adc_mode(sm_dc->i2c_sub, SM_DC_ADC_MODE_ONESHOT); - request_state_work(sm_dc, SM_DC_PRE_CC, DELAY_ADC_UPDATE); - return; - } - - if (loop_status == LOOP_INACTIVE && sm_dc->config.support_pd_remain) { - ret = send_power_source_msg(sm_dc); - if (ret < 0) - return; - } - request_state_work(sm_dc, SM_DC_CV, DELAY_CHG_LOOP); -} - -static void x2bat_update_bat_work(struct work_struct *work) -{ - struct sm_dc_info *sm_dc = container_of(work, struct sm_dc_info, update_bat_work.work); - int index, ret, cnt; - bool need_to_preset = 1; - - pr_info("%s %s\n", sm_dc->name, __func__); - - ret = check_error_state(sm_dc, SM_DC_UPDAT_BAT); - if (ret < 0) - return; - - /* waiting for step change event */ - for (cnt = 0; cnt < 1; ++cnt) { - if (sm_dc->req_update_vbat && sm_dc->req_update_ibus) - break; - - pr_info("%s %s: wait 1sec for step changed\n", sm_dc->name, __func__); - msleep(DELAY_PPS_UPDATE); - } - - mutex_lock(&sm_dc->st_lock); - index = (sm_dc->req_update_vbat << 2) | (sm_dc->req_update_ibus << 1) | sm_dc->req_update_ibat; - sm_dc->req_update_vbat = 0; - sm_dc->req_update_ibus = 0; - sm_dc->req_update_ibat = 0; - mutex_unlock(&sm_dc->st_lock); - - ret = update_work_state(sm_dc, SM_DC_UPDAT_BAT); - if (ret < 0) - return; - - if (index & (0x1 << 2)) - pr_info("%s %s: vbat changed (%dmV)\n", sm_dc->name, __func__, sm_dc->target_vbat); - - if (index & (0x1 << 1)) - pr_info("%s %s: ibus changed (%dmA)\n", sm_dc->name, __func__, sm_dc->target_ibus); - - if (index & 0x1) - pr_info("%s %s: ibat changed (%dmA)\n", sm_dc->name, __func__, sm_dc->target_ibat); - - /* check step change event */ - if ((index & (0x1 << 2)) && (index & (0x1 << 1))) { - if ((sm_dc->target_vbat > sm_dc->wq.cv_gl) && (sm_dc->target_ibus < sm_dc->wq.ci_gl)) - need_to_preset = 0; - } - - sm_dc->ops->set_adc_mode(sm_dc->i2c, SM_DC_ADC_MODE_ONESHOT); - - if (need_to_preset) { - pr_info("%s %s: [request] update_bat -> preset\n", sm_dc->name, __func__); - request_state_work(sm_dc, SM_DC_PRESET, DELAY_NONE); - } else { - x2bat_setup_direct_charging_work_config(sm_dc); - sm_dc->ta.c = pps_c(MAX(MIN(sm_dc->ta.c_max, sm_dc->wq.ci_gl + 200), - sm_dc->config.ta_min_current)); - ret = send_power_source_msg(sm_dc); - if (ret < 0) - return; - - pr_info("%s %s: [request] update_bat -> pre_cc\n", sm_dc->name, __func__); - request_state_work(sm_dc, SM_DC_PRE_CC, DELAY_ADC_UPDATE); - } -} - -static void x2bat_error_work(struct work_struct *work) -{ - struct sm_dc_info *sm_dc = container_of(work, struct sm_dc_info, error_work.work); - int ret; - - pr_info("%s %s: err=0x%x\n", sm_dc->name, __func__, sm_dc->err); - - ret = update_work_state(sm_dc, SM_DC_ERR); - if (ret < 0) - return; - - sm_dc->ops->set_adc_mode(sm_dc->i2c, SM_DC_ADC_MODE_OFF); - sm_dc->ops->set_charging_enable(sm_dc->i2c, 0); -} - -/** - * SM Direct-charging module management APIs - */ -struct sm_dc_info *sm_dc_create_pd_instance(const char *name, struct i2c_client *i2c) -{ - struct sm_dc_info *sm_dc; - int ret; - - sm_dc = kzalloc(sizeof(struct sm_dc_info), GFP_KERNEL); - if (!sm_dc) - return ERR_PTR(-ENOMEM); - - sm_dc->name = name; - sm_dc->i2c = i2c; - sm_dc->i2c_sub = NULL; - mutex_init(&sm_dc->st_lock); - - /* create work queue */ - sm_dc->state = SM_DC_CHG_OFF; - sm_dc->dc_wqueue = create_singlethread_workqueue(name); - if (!sm_dc->dc_wqueue) { - pr_err("%s %s: fail to crearte workqueue\n", name, __func__); - ret = -ENOMEM; - goto err_kmem; - } - INIT_DELAYED_WORK(&sm_dc->check_vbat_work, pd_check_vbat_work); - INIT_DELAYED_WORK(&sm_dc->preset_dc_work, pd_preset_dc_work); - INIT_DELAYED_WORK(&sm_dc->pre_cc_work, pd_pre_cc_work); - INIT_DELAYED_WORK(&sm_dc->cc_work, pd_cc_work); - INIT_DELAYED_WORK(&sm_dc->cv_work, pd_cv_work); - INIT_DELAYED_WORK(&sm_dc->cv_man_work, pd_cv_man_work); - INIT_DELAYED_WORK(&sm_dc->update_bat_work, pd_update_bat_work); - INIT_DELAYED_WORK(&sm_dc->error_work, pd_error_work); - /* for SEC_BATTERY done event process */ - INIT_DELAYED_WORK(&sm_dc->done_event_work, sec_done_event_work); - pr_info("%s %s: done.\n", name, __func__); - - return sm_dc; - -err_kmem: - mutex_destroy(&sm_dc->st_lock); - kfree(sm_dc); - - return ERR_PTR(ret); -} -EXPORT_SYMBOL(sm_dc_create_pd_instance); - -struct sm_dc_info *sm_dc_create_x2bat_instance(const char *name, struct i2c_client *i2c) -{ - struct sm_dc_info *sm_dc; - int ret; - - sm_dc = kzalloc(sizeof(struct sm_dc_info), GFP_KERNEL); - if (!sm_dc) - return ERR_PTR(-ENOMEM); - - sm_dc->name = name; - sm_dc->i2c = i2c; - sm_dc->i2c_sub = NULL; - mutex_init(&sm_dc->st_lock); - - /* create work queue */ - sm_dc->state = SM_DC_CHG_OFF; - sm_dc->dc_wqueue = create_singlethread_workqueue(name); - if (!sm_dc->dc_wqueue) { - pr_err("%s %s: fail to crearte workqueue\n", name, __func__); - ret = -ENOMEM; - goto err_kmem; - } - INIT_DELAYED_WORK(&sm_dc->check_vbat_work, x2bat_check_vbat_work); - INIT_DELAYED_WORK(&sm_dc->preset_dc_work, x2bat_preset_dc_work); - INIT_DELAYED_WORK(&sm_dc->pre_cc_work, x2bat_pre_cc_work); - INIT_DELAYED_WORK(&sm_dc->cc_work, x2bat_cc_work); - INIT_DELAYED_WORK(&sm_dc->cv_work, x2bat_cv_work); - INIT_DELAYED_WORK(&sm_dc->update_bat_work, x2bat_update_bat_work); - INIT_DELAYED_WORK(&sm_dc->error_work, x2bat_error_work); - INIT_DELAYED_WORK(&sm_dc->done_event_work, sec_done_event_work); - pr_info("%s %s: done.\n", name, __func__); - - return sm_dc; - -err_kmem: - mutex_destroy(&sm_dc->st_lock); - kfree(sm_dc); - - return ERR_PTR(ret); -} -EXPORT_SYMBOL(sm_dc_create_x2bat_instance); - -int sm_dc_verify_configuration(struct sm_dc_info *sm_dc) -{ - if (sm_dc == NULL) - return -EINVAL; - - if (sm_dc->ops == NULL) - return -EINVAL; - - return 0; -} -EXPORT_SYMBOL(sm_dc_verify_configuration); - -void sm_dc_destroy_instance(struct sm_dc_info *sm_dc) -{ - if (sm_dc != NULL) { - destroy_workqueue(sm_dc->dc_wqueue); - mutex_destroy(&sm_dc->st_lock); - kfree(sm_dc); - } -} -EXPORT_SYMBOL(sm_dc_destroy_instance); - -int sm_dc_report_error_status(struct sm_dc_info *sm_dc, u32 err) -{ - terminate_charging_work(sm_dc); - mutex_lock(&sm_dc->st_lock); - sm_dc->state = SM_DC_ERR; - mutex_unlock(&sm_dc->st_lock); - sm_dc->err = err; - report_dc_state(sm_dc); - - return 0; -} -EXPORT_SYMBOL(sm_dc_report_error_status); - -int sm_dc_report_interrupt_event(struct sm_dc_info *sm_dc, u32 interrupt) -{ - if ((sm_dc->state == SM_DC_CC) && (interrupt == SM_DC_INT_VBATREG)) { - if (delayed_work_pending(&sm_dc->cc_work)) { - cancel_delayed_work(&sm_dc->cc_work); - pr_info("%s %s: cancel CC_work, direct request work\n", sm_dc->name, __func__); - request_state_work(sm_dc, SM_DC_CC, DELAY_NONE); - } - } - - return 0; -} -EXPORT_SYMBOL(sm_dc_report_interrupt_event); - -int sm_dc_get_current_state(struct sm_dc_info *sm_dc) -{ - return sm_dc->state; -} -EXPORT_SYMBOL(sm_dc_get_current_state); - -int sm_dc_start_charging(struct sm_dc_info *sm_dc) -{ - if (sm_dc->state >= SM_DC_CHECK_VBAT) { - pr_err("%s %s: already work on dc (state=%d)\n", sm_dc->name, __func__, sm_dc->state); - return -EBUSY; - } - - sm_dc->ta.pdo_pos = 0; /* set '0' else return error */ - sm_dc->ta.v_max = 10000; /* request voltage level */ - sm_dc->ta.c_max = 0; - sm_dc->ta.p_max = 0; - sm_dc->ta.retry_cnt = 0; - - sm_dc->ops->set_adc_mode(sm_dc->i2c, SM_DC_ADC_MODE_ONESHOT); - if (sm_dc->i2c_sub) - sm_dc->ops->set_adc_mode(sm_dc->i2c_sub, SM_DC_ADC_MODE_ONESHOT); - - mutex_lock(&sm_dc->st_lock); - sm_dc->state = SM_DC_CHECK_VBAT; /* Pre-update chg.state */ - mutex_unlock(&sm_dc->st_lock); - request_state_work(sm_dc, SM_DC_CHECK_VBAT, DELAY_PPS_UPDATE); - - pr_info("%s %s: done\n", sm_dc->name, __func__); - - return 0; -} -EXPORT_SYMBOL(sm_dc_start_charging); - -int sm_dc_stop_charging(struct sm_dc_info *sm_dc) -{ - mutex_lock(&sm_dc->st_lock); - sm_dc->state = SM_DC_CHG_OFF; - mutex_unlock(&sm_dc->st_lock); - terminate_charging_work(sm_dc); - sm_dc->ops->set_adc_mode(sm_dc->i2c, SM_DC_ADC_MODE_OFF); - if (sm_dc->i2c_sub) - sm_dc->ops->set_adc_mode(sm_dc->i2c_sub, SM_DC_ADC_MODE_OFF); - - report_dc_state(sm_dc); - - return 0; -} -EXPORT_SYMBOL(sm_dc_stop_charging); - -int sm_dc_start_manual_charging(struct sm_dc_info *sm_dc) -{ - struct sm_dc_power_source_info ta; - int ret = 0; - int adc_vbat, cnt; - - sm_dc->ta.pdo_pos = 0; - sm_dc->ta.v_max = 10000; - sm_dc->ta.c_max = 0; - sm_dc->ta.p_max = 0; - - for (cnt = 0; cnt < 3; ++cnt) { - ret = sm_dc->ops->get_apdo_max_power(sm_dc->i2c, &ta); - if (ret < 0) - pr_err("%s %s: fail to get APDO(ret=%d)\n", sm_dc->name, __func__, ret); - else - break; - msleep(DELAY_PPS_UPDATE); - } - if (ret < 0) - return ret; - - mutex_lock(&sm_dc->st_lock); - sm_dc->state = SM_DC_CV_MAN; /* direct change the chg.state */ - mutex_unlock(&sm_dc->st_lock); - - for (cnt = 0; cnt < 3; ++cnt) { - sm_dc->ops->set_adc_mode(sm_dc->i2c, SM_DC_ADC_MODE_ONESHOT); - msleep(DELAY_PPS_UPDATE); - adc_vbat = sm_dc->ops->get_adc_value(sm_dc->i2c, SM_DC_ADC_VBAT); - - if (adc_vbat < sm_dc->config.dc_min_vbat) - pr_err("%s %s: adc_vbat=%dmV, RETRY=%d\n", sm_dc->name, __func__, adc_vbat, cnt); - else - break; - - if (cnt == 2) { - pr_err("%s %s: adc_vbat(%dmV) less then dc_min_vbat(%dmV)\n", - sm_dc->name, __func__, adc_vbat, sm_dc->config.dc_min_vbat); - ret = -EINVAL; - } - } - if (ret < 0) { - mutex_lock(&sm_dc->st_lock); - sm_dc->state = SM_DC_ERR; - mutex_unlock(&sm_dc->st_lock); - return ret; - } - - sm_dc->target_vbat = pps_v(adc_vbat + (PPS_V_STEP * 10)); /* VBAT_ADC + 200mV */ - sm_dc->target_ibus = SM_DC_MANUAL_TA_MAX_CUR; - sm_dc->ta.c = pps_c(MIN(sm_dc->ta.c_max, sm_dc->target_ibus)); - sm_dc->ta.v = pps_v((2 * adc_vbat) + (PPS_V_STEP * 4)); /* VBAT_ADC + 80mV */ - - pr_info("%s %s: adc_vbat=%dmV, ta_min_v=%dmV, v_max=%dmV, c_max=%dmA, target_ibus=%dmA, target_vbat=%dmV\n", - sm_dc->name, __func__, adc_vbat, sm_dc->config.ta_min_voltage, sm_dc->ta.v_max, - sm_dc->ta.c_max, sm_dc->target_ibus, sm_dc->target_vbat); - - setup_direct_charging_work_config(sm_dc); - - ret = send_power_source_msg(sm_dc); - if (ret < 0) { - mutex_lock(&sm_dc->st_lock); - sm_dc->state = SM_DC_ERR; - mutex_unlock(&sm_dc->st_lock); - return ret; - } - sm_dc->ops->set_charging_enable(sm_dc->i2c, 1); - pr_info("%s %s: enable Direct-charging\n", sm_dc->name, __func__); - - request_state_work(sm_dc, SM_DC_CV_MAN, DELAY_PPS_UPDATE); - pr_info("%s %s: done\n", sm_dc->name, __func__); - - return 0; -} -EXPORT_SYMBOL(sm_dc_start_manual_charging); - -/* Set TA voltage for bypass mode */ -int sm_dc_set_ta_volt_by_soc(struct sm_dc_info *sm_dc, int delta_soc) -{ - int ret = 0; - unsigned int prev_ta_vol = sm_dc->ta.v; - - if (delta_soc < 0) { // increase soc (soc_now - ref_soc) - sm_dc->ta.v += PPS_V_STEP; - } else if (delta_soc > 0) { // decrease soc (soc_now - ref_soc) - sm_dc->ta.v -= PPS_V_STEP; - } else { - pr_info("%s: abnormal delta_soc=%d\n", __func__, delta_soc); - return -1; - } - - pr_info("%s: delta_soc=%d, prev_ta_vol=%d, ta_vol=%d, ta_cur=%d\n", - __func__, delta_soc, prev_ta_vol, sm_dc->ta.v, sm_dc->ta.c); - - ret = send_power_source_msg(sm_dc); - if (ret < 0) - return ret; - - request_state_work(sm_dc, SM_DC_CV_MAN, DELAY_PPS_UPDATE); - - return ret; -} -EXPORT_SYMBOL(sm_dc_set_ta_volt_by_soc); - -int sm_dc_set_target_vbat(struct sm_dc_info *sm_dc, u32 target_vbat) -{ - int ret = 0; - int adc_vbat; - - pr_info("%s %s: [%dmV] to [%dmV]\n", sm_dc->name, __func__, sm_dc->target_vbat, target_vbat); - - sm_dc->target_vbat = target_vbat; - if (sm_dc->state > SM_DC_CHECK_VBAT) { - adc_vbat = sm_dc->ops->get_adc_value(sm_dc->i2c, SM_DC_ADC_VBAT); - if (sm_dc->target_vbat > adc_vbat) { - mutex_lock(&sm_dc->st_lock); - sm_dc->req_update_vbat = 1; - mutex_unlock(&sm_dc->st_lock); - pr_info("%s %s: request VBAT update on DC work\n", sm_dc->name, __func__); - } else { - pr_err("%s %s: target_vbat(%dmV) less then adc_vbat(%dmV)\n", sm_dc->name, __func__, - sm_dc->target_vbat, adc_vbat); - ret = -EINVAL; - } - } - - return ret; -} -EXPORT_SYMBOL(sm_dc_set_target_vbat); - -int sm_dc_set_target_ibus(struct sm_dc_info *sm_dc, u32 target_ibus) -{ - pr_info("%s %s: [%dmA] to [%dmA]\n", sm_dc->name, __func__, sm_dc->target_ibus, target_ibus); - - sm_dc->target_ibus = target_ibus; - if (sm_dc->state > SM_DC_CHECK_VBAT) { - mutex_lock(&sm_dc->st_lock); - sm_dc->req_update_ibus = 1; - mutex_unlock(&sm_dc->st_lock); - pr_info("%s %s: request IBUS update on DC work\n", sm_dc->name, __func__); - } - - return 0; - -} -EXPORT_SYMBOL(sm_dc_set_target_ibus); - -int sm_dc_set_target_ibat(struct sm_dc_info *sm_dc, u32 target_ibat) -{ - /* if need to it, we need to improve direct-charging module for cc_loop */ - - return 0; -} -EXPORT_SYMBOL(sm_dc_set_target_ibat); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("SiliconMitus "); -MODULE_DESCRIPTION("Direct-charger module for SM ICs"); diff --git a/drivers/battery/charger/sm5451_charger/sm5451_direct_charger.h b/drivers/battery/charger/sm5451_charger/sm5451_direct_charger.h deleted file mode 100755 index e8dc70107..000000000 --- a/drivers/battery/charger/sm5451_charger/sm5451_direct_charger.h +++ /dev/null @@ -1,241 +0,0 @@ - -/* - * sm5451_direct_charger.h - Direct charging module for Silicon Mitus ICs - * - * Copyright (C) 2022 Silicon Mitus Co.Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include - -#ifndef __SM_DC_H__ -#define __SM_DC_H__ - -#define SM_DC_BYPASS_TA_MAX_VOL 7000 -#define SM_DC_MANUAL_TA_MAX_CUR 3000 -#define SM_DC_DUAL_STOP_IBUS 1500 -#define SM_DC_CI_OFFSET_X2BAT 500 - -#define PPS_V_STEP 20 -#define PPS_C_STEP 50 - -#define PRE_CC_ST_IBUS_OFFSET 150 -#define CC_ST_IBUS_OFFSET 100 -#define CV_ST_SUB_DC_OFF_IBUS 1000 - -#define MAX(a, b) ((a > b) ? (a):(b)) -#define MIN(a, b) ((a < b) ? (a):(b)) - -enum sm_dc_charging_loop { - LOOP_IBUSREG = (0x1 << 7), - LOOP_IBUSREG_M = (0x1 << 6), - LOOP_IBATREG = (0x1 << 5), - LOOP_VBATREG = (0x1 << 3), - LOOP_VBATREG_S = (0x1 << 2), - LOOP_THEMREG = (0x1 << 1), - LOOP_INACTIVE = (0x0), -}; - -enum sm_dc_work_delay_type { - DELAY_NONE = 0, - DELAY_PPS_UPDATE = 250, - DELAY_ADC_UPDATE = 1100, - DELAY_RETRY = 2000, - DELAY_CHG_LOOP = 2500, -}; - -enum sm_dc_power_supply_type { - SM_DC_POWER_SUPPLY_PD = 0x0, - SM_DC_POWER_SUPPLY_2XBAT = 0x1, -}; - -enum sm_dc_state { - /* SEC_DIRECT_CHG_MODE_DIRECT_OFF */ - SM_DC_CHG_OFF = 0x0, - SM_DC_ERR, - /* SEC_DIRECT_CHG_MODE_DIRECT_DONE */ - SM_DC_EOC, - /* SEC_DIRECT_CHG_MODE_DIRECT_CHECK_VBAT */ - SM_DC_CHECK_VBAT, - /* SEC_DIRECT_CHG_MODE_DIRECT_PRESET */ - SM_DC_PRESET, - /* SEC_DIRECT_CHG_MODE_DIRECT_ON_ADJUST */ - SM_DC_PRE_CC, - SM_DC_UPDAT_BAT, - /* SEC_DIRECT_CHG_MODE_DIRECT_ON */ - SM_DC_CC, - SM_DC_CV, - SM_DC_CV_MAN, -}; -enum sm_dc_err_index { - SM_DC_ERR_NONE = (0x0), - SM_DC_ERR_VBATREG = (0x1 << 0), - SM_DC_ERR_IBUSREG = (0x1 << 1), - SM_DC_ERR_TSD = (0x1 << 2), - SM_DC_ERR_VBATOVP = (0x1 << 3), - SM_DC_ERR_VOUTOVP = (0x1 << 4), - SM_DC_ERR_IBUSUCP = (0x1 << 5), - SM_DC_ERR_IBATOCP = (0x1 << 6), - SM_DC_ERR_IBUSOCP = (0x1 << 7), - SM_DC_ERR_CFLY_SHORT = (0x1 << 8), - SM_DC_ERR_REVBLK = (0x1 << 9), - SM_DC_ERR_STUP_FAIL = (0x1 << 10), - SM_DC_ERR_CN_SHORT = (0x1 << 11), - SM_DC_ERR_IBUSREG_M = (0x1 << 12), - SM_DC_ERR_VBATREG_S = (0x1 << 13), - SM_DC_ERR_VBUSUVLO = (0x1 << 14), - SM_DC_ERR_VBUSOVP = (0x1 << 15), - SM_DC_ERR_INVAL_VBAT = (0x1 << 16), - SM_DC_ERR_SEND_PD_MSG = (0x1 << 17), - SM_DC_ERR_FAIL_ADJUST = (0x1 << 18), - SM_DC_ERR_RETRY = (0x1 << 30), - SM_DC_ERR_UNKNOWN = (0x1 << 31), -}; - -enum sm_dc_interrupt_index { - SM_DC_INT_VBATREG = (0x1 << 0), - SM_DC_INT_WDTOFF = (0x1 << 1), -}; - -enum sm_dc_adc_channel { - SM_DC_ADC_THEM = 0x0, - SM_DC_ADC_DIETEMP, - SM_DC_ADC_VBAT, - SM_DC_ADC_IBAT, - SM_DC_ADC_VOUT, - SM_DC_ADC_VBUS, - SM_DC_ADC_IBUS, -}; - -enum sm_dc_adc_mode { - SM_DC_ADC_MODE_ONESHOT = 0x0, - SM_DC_ADC_MODE_CONTINUOUS = 0x1, - SM_DC_ADC_MODE_OFF = 0x2, -}; - -struct sm_dc_power_source_info { - u32 pdo_pos; - u32 v_max; - u32 c_max; - u32 p_max; - u32 v; - u32 c; - u32 retry_cnt; -}; - -struct sm_dc_ops { - int (*get_adc_value)(struct i2c_client *i2c, u8 adc_ch); - int (*set_adc_mode)(struct i2c_client *i2c, u8 mode); - int (*get_charging_enable)(struct i2c_client *i2c); - int (*set_charging_enable)(struct i2c_client *i2c, bool enable); - int (*set_charging_config)(struct i2c_client *i2c, u32 cv_gl, u32 ci_gl, u32 cc_gl); - u32 (*get_dc_error_status)(struct i2c_client *i2c); - int (*send_power_source_msg)(struct i2c_client *i2c, struct sm_dc_power_source_info *ta); - int (*get_apdo_max_power)(struct i2c_client *i2c, struct sm_dc_power_source_info *ta); - u32 (*get_target_ibus)(struct i2c_client *i2c); - int (*check_sw_ocp)(struct i2c_client *i2c); -}; - -struct sm_dc_info { - const char *name; - struct i2c_client *i2c; - struct i2c_client *i2c_sub; - struct mutex st_lock; - const struct sm_dc_ops *ops; - int chip_id; - - /* for direct-charging state machine */ - struct workqueue_struct *dc_wqueue; - struct delayed_work check_vbat_work; - struct delayed_work preset_dc_work; - struct delayed_work pre_cc_work; - struct delayed_work cc_work; - struct delayed_work cv_work; - struct delayed_work cv_man_work; - struct delayed_work update_bat_work; - struct delayed_work error_work; - - /* for SEC-BATTERY done event process */ - struct delayed_work done_event_work; - - u8 state; - u32 err; - bool req_update_vbat; - bool req_update_ibus; - bool req_update_ibat; - u32 target_vbat; - u32 target_ibat; - u32 target_ibus; - - struct sm_dc_power_source_info ta; - - /* for state machine control */ - struct { - bool pps_cl; - bool c_up; - bool c_down; - bool v_up; - bool v_down; - bool pps_vcm; - bool topoff_m; - bool topoff_s; - int v_offset; - int c_offset; - u16 prev_adc_ibus; - u16 prev_adc_vbus; - bool cc_limit; - int cc_cnt; - int cv_cnt; - u32 cv_gl; - u32 ci_gl; - u32 ci_gl_m; - u32 ci_gl_s; - u32 cc_gl; - int retry_cnt; - } wq; - - struct { - u32 ta_min_current; - u32 ta_min_voltage; - u32 dc_min_vbat; - u32 dc_vbus_ovp_th; - u32 pps_lr; - u32 rpara; - u32 rsns; - u32 rpcm; - u32 r_ttl; - u32 topoff_current; - bool need_to_sw_ocp; - bool support_pd_remain; - /* sec_battery info */ - u32 chg_float_voltage; - char *sec_dc_name; - } config; -}; - -extern struct sm_dc_info *sm_dc_create_pd_instance(const char *name, struct i2c_client *i2c); -extern struct sm_dc_info *sm_dc_create_x2bat_instance(const char *name, struct i2c_client *i2c); -extern int sm_dc_verify_configuration(struct sm_dc_info *sm_dc); -extern void sm_dc_destroy_instance(struct sm_dc_info *sm_dc); - -extern int sm_dc_report_error_status(struct sm_dc_info *sm_dc, u32 err); -extern int sm_dc_report_interrupt_event(struct sm_dc_info *sm_dc, u32 interrupt); - -extern int sm_dc_get_current_state(struct sm_dc_info *sm_dc); -extern int sm_dc_start_charging(struct sm_dc_info *sm_dc); -extern int sm_dc_stop_charging(struct sm_dc_info *sm_dc); -extern int sm_dc_start_manual_charging(struct sm_dc_info *sm_dc); -extern int sm_dc_set_ta_volt_by_soc(struct sm_dc_info *sm_dc, int delta_soc); -extern int sm_dc_set_target_vbat(struct sm_dc_info *sm_dc, u32 target_vbat); -extern int sm_dc_set_target_ibus(struct sm_dc_info *sm_dc, u32 target_ibus); - -#endif /* __SM_DC_H__ */