// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2022 Southchip Semiconductor Technology(Shanghai) Co., Ltd. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define CONFIG_MTK_CLASS //drv mod by liuruiqian,20240327 #ifdef CONFIG_MTK_CLASS #include "charger_class.h" #include "mtk_charger.h" #endif /*CONFIG_MTK_CLASS */ #define SC8989X_DRV_VERSION "1.1.0_G" struct tag_bootmode { u32 size; u32 tag; u32 bootmode; u32 boottype; }; enum sc8960x_part_no { SC89890H_PN_NUM = 0x04, SC89895_PN_NUM = 0x04, SC8950_PN_NUM = 0x02, SC89890W_PN_NUM = 0x07, }; #define SC8989X_VINDPM_MAX 15300 //mV #define SC8989X_REG7D 0x7D #define SC8989X_KEY1 0x48 #define SC8989X_KEY2 0x54 #define SC8989X_KEY3 0x53 #define SC8989X_KEY4 0x38 #define SC8989X_REG7E 0x7E #define SC8989X_OWN_KEY1 0x48 #define SC8989X_OWN_KEY2 0x54 #define SC8989X_OWN_KEY3 0x53 #define SC8989X_OWN_KEY4 0x39 #define SC8989X_ADC_EN 0x87 #define SC8989X_DPDM3 0x88 #define SC8989X_PRIVATE 0xF9 #define PHY_MODE_BC11_SET 1 #define PHY_MODE_BC11_CLR 2 static const char *const sc8989x_attach_trig_names[] = { "ignore", "pwr_rdy", "typec", }; enum attach_type { ATTACH_TYPE_NONE, ATTACH_TYPE_PWR_RDY, ATTACH_TYPE_TYPEC, ATTACH_TYPE_PD, ATTACH_TYPE_PD_SDP, ATTACH_TYPE_PD_DCP, ATTACH_TYPE_PD_NONSTD, }; enum sc8989x_attach_trigger { ATTACH_TRIG_IGNORE, ATTACH_TRIG_PWR_RDY, ATTACH_TRIG_TYPEC, }; enum sc8989x_usbsw { USBSW_CHG = 0, USBSW_USB, }; enum sc8989x_vbus_stat { VBUS_STAT_NO_INPUT = 0, VBUS_STAT_SDP, VBUS_STAT_CDP, VBUS_STAT_DCP, VBUS_STAT_HVDCP, VBUS_STAT_UNKOWN, VBUS_STAT_NONSTAND, VBUS_STAT_OTG, }; static const char *const sc8989x_port_stat_names[] = { [VBUS_STAT_NO_INPUT] = "No Info", [VBUS_STAT_SDP] = "SDP", [VBUS_STAT_CDP] = "CDP", [VBUS_STAT_DCP] = "DCP", [VBUS_STAT_HVDCP] = "HVDCP", [VBUS_STAT_UNKOWN] = "Unknown", [VBUS_STAT_NONSTAND] = "Nonstand", [VBUS_STAT_OTG] = "otg", }; enum sc8989x_chg_stat { CHG_STAT_NOT_CHARGE = 0, CHG_STAT_PRE_CHARGE, CHG_STAT_FAST_CHARGE, CHG_STAT_CHARGE_DONE, }; enum sc8989x_adc_channel { SC8989X_ADC_VBAT, SC8989X_ADC_VSYS, SC8989X_ADC_VBUS, SC8989X_ADC_ICC, SC8989X_ADC_IBUS, }; enum vindpm_track { SC8989X_TRACK_DIS, SC8989X_TRACK_200, SC8989X_TRACK_250, SC8989X_TRACK_300, }; enum { SC8989X_VBUSSTAT_NOINPUT = 0, SC8989X_VBUSSTAT_SDP, SC8989X_VBUSSTAT_CDP, SC8989X_VBUSSTAT_DCP, SC8989X_VBUSSTAT_HVDCP, SC8989X_VBUSSTAT_FLOAT, SC8989X_VBUSSTAT_NON_STD, SC8989X_VBUSSTAT_OTG, }; enum sc8989x_fields { F_EN_HIZ, F_EN_ILIM, F_IINDPM, F_DP_DRIVE, F_DM_DRIVE, F_VINDPM_OS, F_CONV_START, F_CONV_RATE, F_BOOST_FRE, F_ICO_EN, F_HVDCP_EN, F_FORCE_DPDM, F_AUTO_DPDM_EN, F_FORCE_DSEL, F_WD_RST, F_OTG_CFG, F_CHG_CFG, F_VSYS_MIN, F_VBATMIN_SEL, F_EN_PUMPX, F_ICC, F_ITC, F_ITERM, F_CV, F_VBAT_LOW, F_VRECHG, F_EN_ITERM, F_STAT_DIS, F_TWD, F_EN_TIMER, F_TCHG, F_JEITA_ISET, F_BAT_COMP, F_VCLAMP, F_TJREG, F_FORCE_ICO, F_TMR2X_EN, F_BATFET_DIS, F_JETTA_VSET_WARM, F_BATFET_DLY, F_BATFET_RST_EN, F_PUMPX_UP, F_PUMPX_DN, F_V_OTG, F_PFM_OTG_DIS, F_IBOOST_LIM, F_VBUS_STAT, F_CHG_STAT, F_PG_STAT, F_VSYS_STAT, F_FORCE_VINDPM, F_VINDPM, F_ADC_VBAT, F_ADC_VSYS, F_VBUS_GD,F_ADC_VBUS, F_ADC_ICC, F_VINDPM_STAT, F_IINDPM_STAT, F_REG_RST, F_ICO_STAT, F_PN, F_NTC_PROFILE, F_DEV_VERSION, F_VBAT_REG_LSB, F_ADC_IBUS, F_DP3P3V_DM0V_EN, F_VINDPM_TRACK, F_MAX_FIELDS, }; enum sc8989x_reg_range { SC8989X_IINDPM, SC8989X_ICHG, SC8989X_IBOOST, SC8989X_VBAT_REG, SC8989X_VINDPM, SC8989X_ITERM, SC8989X_VBAT, SC8989X_VSYS, SC8989X_VBUS, SC8989X_IBUS, }; struct reg_range { u32 min; u32 max; u32 step; u32 offset; const u32 *table; u16 num_table; bool round_up; }; struct sc8989x_cfg_e { const char *chg_name; int ico_en; int hvdcp_en; int auto_dpdm_en; int vsys_min; int vbatmin_sel; int itrick; int iterm; int vbat_cv; int vbat_low; int vrechg; int en_term; int stat_dis; int wd_time; int en_timer; int charge_timer; int bat_comp; int vclamp; int votg; int iboost; int force_vindpm; int vindpm; }; /* These default values will be applied if there's no property in dts */ static struct sc8989x_cfg_e sc8989x_default_cfg = { .chg_name = "primary_chg", .ico_en = 0, .hvdcp_en = 1, .auto_dpdm_en = 1, .vsys_min = 5, .vbatmin_sel = 0, .itrick = 3, .iterm = 4, .vbat_cv = 23, .vbat_low = 1, .vrechg = 0, .en_term = 1, .stat_dis = 0, .wd_time = 0, .en_timer = 1, .charge_timer = 2, .bat_comp = 0, .vclamp = 0, .votg = 12, .iboost = 7, .force_vindpm = 0, .vindpm = 18, }; struct sc8989x_chip { struct device *dev; struct i2c_client *client; struct regmap *regmap; struct regmap_field *rmap_fields[F_MAX_FIELDS]; struct charger_device *chg_dev; struct delayed_work psy_dwork; int bc12_en; int chg_type; int psy_usb_type; int irq_gpio; int irq; struct delayed_work force_detect_dwork; int force_detect_count; bool pr_swap; int power_good; int vbus_good; uint8_t dev_id; struct mutex request_dpdm_lock; struct regulator *dpdm_reg; bool dpdm_enabled; struct power_supply_desc psy_desc; struct sc8989x_cfg_e *cfg; struct power_supply *psy; struct power_supply *chg_psy; struct power_supply *pmic; //drv add by liuhai 20240416 struct regulator_desc otg_rdesc; struct regulator_dev *otg_rdev; u32 bootmode; u32 boottype; // drv add tankaikun, add external charger type detect, 20231213 start enum sc8989x_attach_trigger attach_trig; struct mutex attach_lock; bool bc12_dn; bool pwr_rdy; atomic_t attach; struct work_struct bc12_work; struct workqueue_struct *wq; // drv add tankaikun, add external charger type detect, 20231213 end }; static const u32 sc8989x_iboost[] = { 500, 750, 1200, 1400, 1650, 1875, 2150, 2450, }; #define SC8989X_CHG_RANGE(_min, _max, _step, _offset, _ru) \ { \ .min = _min, \ .max = _max, \ .step = _step, \ .offset = _offset, \ .round_up = _ru, \ } #define SC8989X_CHG_RANGE_T(_table, _ru) \ { .table = _table, .num_table = ARRAY_SIZE(_table), .round_up = _ru, } static const struct reg_range sc8989x_reg_range_ary[] = { [SC8989X_IINDPM] = SC8989X_CHG_RANGE(100, 3250, 50, 100, false), [SC8989X_ICHG] = SC8989X_CHG_RANGE(0, 5040, 60, 0, false), [SC8989X_ITERM] = SC8989X_CHG_RANGE(30, 930, 60, 30, false), [SC8989X_VBAT_REG] = SC8989X_CHG_RANGE(3840, 4848, 16, 3840, false), [SC8989X_VINDPM] = SC8989X_CHG_RANGE(3900, 15300, 100, 2600, false), [SC8989X_IBOOST] = SC8989X_CHG_RANGE_T(sc8989x_iboost, false), [SC8989X_VBAT] = SC8989X_CHG_RANGE(2304, 4848, 20, 2304, false), [SC8989X_VSYS] = SC8989X_CHG_RANGE(2304, 4848, 20, 2304, false), [SC8989X_VBUS] = SC8989X_CHG_RANGE(2600, 15300, 100, 2600, false), [SC8989X_IBUS] = SC8989X_CHG_RANGE(0, 6350, 50, 0, false), }; //REGISTER static const struct reg_field sc8989x_reg_fields[] = { /*reg00 */ [F_EN_HIZ] = REG_FIELD(0x00, 7, 7), [F_EN_ILIM] = REG_FIELD(0x00, 6, 6), [F_IINDPM] = REG_FIELD(0x00, 0, 5), /*reg01 */ [F_DP_DRIVE] = REG_FIELD(0x01, 5, 7), [F_DM_DRIVE] = REG_FIELD(0x01, 2, 4), [F_VINDPM_OS] = REG_FIELD(0x01, 0, 0), /*reg02 */ [F_CONV_START] = REG_FIELD(0x02, 7, 7), [F_CONV_RATE] = REG_FIELD(0x02, 6, 6), [F_BOOST_FRE] = REG_FIELD(0x02, 5, 5), [F_ICO_EN] = REG_FIELD(0x02, 4, 4), [F_HVDCP_EN] = REG_FIELD(0x02, 3, 3), [F_FORCE_DPDM] = REG_FIELD(0x02, 1, 1), [F_AUTO_DPDM_EN] = REG_FIELD(0x02, 0, 0), /*reg03 */ [F_FORCE_DSEL] = REG_FIELD(0x03, 7, 7), [F_WD_RST] = REG_FIELD(0x03, 6, 6), [F_OTG_CFG] = REG_FIELD(0x03, 5, 5), [F_CHG_CFG] = REG_FIELD(0x03, 4, 4), [F_VSYS_MIN] = REG_FIELD(0x03, 1, 3), [F_VBATMIN_SEL] = REG_FIELD(0x03, 0, 0), /*reg04 */ [F_EN_PUMPX] = REG_FIELD(0x04, 7, 7), [F_ICC] = REG_FIELD(0x04, 0, 6), /*reg05 */ [F_ITC] = REG_FIELD(0x05, 4, 7), [F_ITERM] = REG_FIELD(0x05, 0, 3), /*reg06 */ [F_CV] = REG_FIELD(0x06, 2, 7), [F_VBAT_LOW] = REG_FIELD(0x06, 1, 1), [F_VRECHG] = REG_FIELD(0x06, 0, 0), /*reg07 */ [F_EN_ITERM] = REG_FIELD(0x07, 7, 7), [F_STAT_DIS] = REG_FIELD(0x07, 6, 6), [F_TWD] = REG_FIELD(0x07, 4, 5), [F_EN_TIMER] = REG_FIELD(0x07, 3, 3), [F_TCHG] = REG_FIELD(0x07, 1, 2), [F_JEITA_ISET] = REG_FIELD(0x07, 0, 0), /*reg08 */ [F_BAT_COMP] = REG_FIELD(0x08, 5, 7), [F_VCLAMP] = REG_FIELD(0x08, 2, 4), [F_TJREG] = REG_FIELD(0x08, 0, 1), /*reg09 */ [F_FORCE_ICO] = REG_FIELD(0x09, 7, 7), [F_TMR2X_EN] = REG_FIELD(0x09, 6, 6), [F_BATFET_DIS] = REG_FIELD(0x09, 5, 5), [F_JETTA_VSET_WARM] = REG_FIELD(0x09, 4, 4), [F_BATFET_DLY] = REG_FIELD(0x09, 3, 3), [F_BATFET_RST_EN] = REG_FIELD(0x09, 2, 2), [F_PUMPX_UP] = REG_FIELD(0x09, 1, 1), [F_PUMPX_DN] = REG_FIELD(0x09, 0, 0), /*reg0A */ [F_V_OTG] = REG_FIELD(0x0A, 4, 7), [F_PFM_OTG_DIS] = REG_FIELD(0x0A, 3, 3), [F_IBOOST_LIM] = REG_FIELD(0x0A, 0, 2), /*reg0B */ [F_VBUS_STAT] = REG_FIELD(0x0B, 5, 7), [F_CHG_STAT] = REG_FIELD(0x0B, 3, 4), [F_PG_STAT] = REG_FIELD(0x0B, 2, 2), [F_VSYS_STAT] = REG_FIELD(0x0B, 0, 0), /*reg0D */ [F_FORCE_VINDPM] = REG_FIELD(0x0D, 7, 7), [F_VINDPM] = REG_FIELD(0x0D, 0, 6), /*reg0E */ [F_ADC_VBAT] = REG_FIELD(0x0E, 0, 6), /*reg0F */ [F_ADC_VSYS] = REG_FIELD(0x0F, 0, 6), /*reg11 */ [F_VBUS_GD] = REG_FIELD(0x11, 7, 7), [F_ADC_VBUS] = REG_FIELD(0x11, 0, 6), /*reg12 */ [F_ADC_ICC] = REG_FIELD(0x12, 0, 6), /*reg13 */ [F_VINDPM_STAT] = REG_FIELD(0x13, 7, 7), [F_IINDPM_STAT] = REG_FIELD(0x13, 6, 6), /*reg14 */ [F_REG_RST] = REG_FIELD(0x14, 7, 7), [F_ICO_STAT] = REG_FIELD(0x14, 6, 6), [F_PN] = REG_FIELD(0x14, 3, 5), [F_NTC_PROFILE] = REG_FIELD(0x14, 2, 2), [F_DEV_VERSION] = REG_FIELD(0x14, 0, 1), /*reg40 */ [F_VBAT_REG_LSB] = REG_FIELD(0x40, 6, 6), /*reg86 */ [F_ADC_IBUS] = REG_FIELD(0x86, 1, 7), /*reg83 */ [F_DP3P3V_DM0V_EN] = REG_FIELD(0x83, 5, 5), [F_VINDPM_TRACK] = REG_FIELD(0x85, 1, 2), }; static const struct regmap_config sc8989x_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = 0xFF, }; /********************COMMON API***********************/ static u8 val2reg(enum sc8989x_reg_range id, u32 val) { int i; u8 reg; const struct reg_range *range = &sc8989x_reg_range_ary[id]; if (!range) return val; if (range->table) { if (val <= range->table[0]) return 0; for (i = 1; i < range->num_table - 1; i++) { if (val == range->table[i]) return i; if (val > range->table[i] && val < range->table[i + 1]) return range->round_up ? i + 1 : i; } return range->num_table - 1; } if (val <= range->min) reg = (range->min - range->offset) / range->step; else if (val >= range->max) reg = (range->max - range->offset) / range->step; else if (range->round_up) reg = (val - range->offset) / range->step + 1; else reg = (val - range->offset) / range->step; return reg; } static u32 reg2val(enum sc8989x_reg_range id, u8 reg) { const struct reg_range *range = &sc8989x_reg_range_ary[id]; if (!range) return reg; return range->table ? range->table[reg] : range->offset + range->step * reg; } /*********************I2C API*********************/ static int sc8989x_field_read(struct sc8989x_chip *sc, enum sc8989x_fields field_id, int *val) { int ret; ret = regmap_field_read(sc->rmap_fields[field_id], val); if (ret < 0) { dev_err(sc->dev, "sc8989x read field %d fail: %d\n", field_id, ret); } return ret; } static int sc8989x_field_write(struct sc8989x_chip *sc, enum sc8989x_fields field_id, int val) { int ret; ret = regmap_field_write(sc->rmap_fields[field_id], val); if (ret < 0) { dev_err(sc->dev, "sc8989x read field %d fail: %d\n", field_id, ret); } return ret; } /*********************CHIP API*********************/ static int sc8989x_set_key(struct sc8989x_chip *sc) { regmap_write(sc->regmap, SC8989X_REG7D, SC8989X_KEY1); regmap_write(sc->regmap, SC8989X_REG7D, SC8989X_KEY2); regmap_write(sc->regmap, SC8989X_REG7D, SC8989X_KEY3); return regmap_write(sc->regmap, SC8989X_REG7D, SC8989X_KEY4); } __maybe_unused static int sc8989x_set_key_own(struct sc8989x_chip *sc) { regmap_write(sc->regmap, SC8989X_REG7E, SC8989X_OWN_KEY1); regmap_write(sc->regmap, SC8989X_REG7E, SC8989X_OWN_KEY2); regmap_write(sc->regmap, SC8989X_REG7E, SC8989X_OWN_KEY3); return regmap_write(sc->regmap, SC8989X_REG7E, SC8989X_OWN_KEY4); } /* static int sc8989x_set_wa(struct sc8989x_chip *sc) { int ret; int val; ret = regmap_read(sc->regmap, SC8989X_DPDM3, &val); if (ret < 0) { sc8989x_set_key(sc); } regmap_write(sc->regmap, SC8989X_DPDM3, SC8989X_PRIVATE); return sc8989x_set_key(sc); } */ __maybe_unused static int sc8989x_set_vbat_lsb(struct sc8989x_chip *sc, bool en) { int ret; int val; ret = sc8989x_field_read(sc, F_VBAT_REG_LSB, &val); if (ret < 0) { sc8989x_set_key(sc); } sc8989x_field_write(sc, F_VBAT_REG_LSB, en); return sc8989x_set_key(sc); } __maybe_unused static int sc8989x_set_vindpm_track(struct sc8989x_chip *sc, enum vindpm_track track) { int ret; int val; ret = sc8989x_field_read(sc, F_VINDPM_TRACK, &val); if (ret < 0) { sc8989x_set_key(sc); } sc8989x_field_write(sc, F_VINDPM_TRACK, track); return sc8989x_set_key(sc); } static int sc8989x_get_adc_en(struct sc8989x_chip *sc) { int reg_val = 0; sc8989x_field_read(sc, F_CONV_RATE, ®_val); return reg_val; } //Start 1s Continuous Conversion static int sc8989x_adc_en(struct sc8989x_chip *sc, bool en) { int reg_val = en; return sc8989x_field_write(sc, F_CONV_RATE, reg_val); } __maybe_unused static int sc8989x_adc_ibus_en(struct sc8989x_chip *sc, bool en) { int ret; int val; ret = regmap_read(sc->regmap, SC8989X_ADC_EN, &val); if (ret < 0) { sc8989x_set_key(sc); } ret = regmap_read(sc->regmap, SC8989X_ADC_EN, &val); val = en ? val | BIT(2) : val & ~BIT(2); regmap_write(sc->regmap, SC8989X_ADC_EN, val); return sc8989x_set_key(sc); } __maybe_unused static int sc8989x_get_adc_ibus(struct sc8989x_chip *sc, int *val) { int ret; int reg = 0; ret = sc8989x_field_read(sc, F_ADC_IBUS, ®); if (ret < 0) { sc8989x_set_key(sc); } ret = sc8989x_field_read(sc, F_ADC_IBUS, ®); *val = reg2val(SC8989X_IBUS, (u8)reg); return sc8989x_set_key(sc); } __maybe_unused static int __sc8989x_get_adc(struct sc8989x_chip *sc, enum sc8989x_adc_channel chan, int *val) { int reg_val, ret = 0; enum sc8989x_fields field_id; enum sc8989x_reg_range range_id; bool pre_adc_en = !! sc8989x_get_adc_en(sc); //close adc 1s Continuous Conversion sc8989x_adc_en(sc, false); //stat adc conversion default: one shot sc8989x_field_write(sc, F_CONV_START, true); msleep(20); switch (chan) { case SC8989X_ADC_VBAT: field_id = F_ADC_VBAT; range_id = SC8989X_VBAT; break; case SC8989X_ADC_VSYS: field_id = F_ADC_VSYS; range_id = SC8989X_VSYS; break; case SC8989X_ADC_VBUS: field_id = F_ADC_VBUS; range_id = SC8989X_VBUS; break; case SC8989X_ADC_ICC: field_id = F_ADC_ICC; range_id = SC8989X_ICHG; break; case SC8989X_ADC_IBUS: sc8989x_get_adc_ibus(sc, val); dev_info(sc->dev, "get_adc channel: %d val: %d", chan, *val); return 0; default: goto err; } ret = sc8989x_field_read(sc, field_id, ®_val); if (ret < 0) goto err; *val = reg2val(range_id, reg_val); sc8989x_adc_en(sc, pre_adc_en); dev_info(sc->dev, "get_adc channel: %d val: %d", chan, *val); return 0; err: dev_err(sc->dev, "get_adc fail channel: %d", chan); return -EINVAL; } static int sc8989x_set_iindpm(struct sc8989x_chip *sc, int curr_ma) { int reg_val = val2reg(SC8989X_IINDPM, curr_ma); return sc8989x_field_write(sc, F_IINDPM, reg_val); } static int sc8989x_get_iindpm(struct sc8989x_chip *sc, int *curr_ma) { int ret, reg_val; ret = sc8989x_field_read(sc, F_IINDPM, ®_val); if (ret) { dev_err(sc->dev, "read iindpm failed(%d)\n", ret); return ret; } *curr_ma = reg2val(SC8989X_IINDPM, reg_val); return ret; } static int sc8989x_set_dpdm_hiz(struct sc8989x_chip *sc) { int ret = 0; ret = sc8989x_field_write(sc, F_DP_DRIVE, 0); ret |= sc8989x_field_write(sc, F_DM_DRIVE, 0); return ret; } __maybe_unused static int sc8989x_reset_wdt(struct sc8989x_chip *sc) { return sc8989x_field_write(sc, F_WD_RST, 1); } static int sc8989x_set_chg_enable(struct sc8989x_chip *sc, bool enable) { int reg_val = enable ? 1 : 0; return sc8989x_field_write(sc, F_CHG_CFG, reg_val); } __maybe_unused static int sc8989x_check_chg_enabled(struct sc8989x_chip *sc, bool * enable) { int ret, reg_val; ret = sc8989x_field_read(sc, F_CHG_CFG, ®_val); if (ret) { dev_err(sc->dev, "read charge enable failed(%d)\n", ret); return ret; } *enable = !!reg_val; return ret; } __maybe_unused static int sc8989x_set_otg_enable(struct sc8989x_chip *sc, bool enable) { int reg_val = enable ? 1 : 0; return sc8989x_field_write(sc, F_OTG_CFG, reg_val); } __maybe_unused static int sc8989x_batfet_rst_en(struct sc8989x_chip *sc, bool enable) { int reg_val = enable ? 1 : 0; return sc8989x_field_write(sc, F_BATFET_RST_EN, reg_val); } __maybe_unused static int sc8989x_set_iboost(struct sc8989x_chip *sc, int curr_ma) { int reg_val = val2reg(SC8989X_IBOOST, curr_ma); return sc8989x_field_write(sc, F_IBOOST_LIM, reg_val); } static int sc8989x_set_ichg(struct sc8989x_chip *sc, int curr_ma) { int reg_val = val2reg(SC8989X_ICHG, curr_ma); return sc8989x_field_write(sc, F_ICC, reg_val); } static int sc8989x_get_ichg(struct sc8989x_chip *sc, int *curr_ma) { int ret, reg_val; ret = sc8989x_field_read(sc, F_ICC, ®_val); if (ret) { dev_err(sc->dev, "read F_ICC failed(%d)\n", ret); return ret; } *curr_ma = reg2val(SC8989X_ICHG, reg_val); return ret; } static int sc8989x_set_term_curr(struct sc8989x_chip *sc, int curr_ma) { int reg_val = val2reg(SC8989X_ITERM, curr_ma); return sc8989x_field_write(sc, F_ITERM, reg_val); } static int sc8989x_get_term_curr(struct sc8989x_chip *sc, int *curr_ma) { int ret, reg_val; ret = sc8989x_field_read(sc, F_ITERM, ®_val); if (ret) return ret; *curr_ma = reg2val(SC8989X_ITERM, reg_val); return ret; } __maybe_unused static int sc8989x_set_safet_timer(struct sc8989x_chip *sc, bool enable) { int reg_val = enable ? 1 : 0; return sc8989x_field_write(sc, F_EN_TIMER, reg_val); } __maybe_unused static int sc8989x_check_safet_timer(struct sc8989x_chip *sc, bool * enabled) { int ret, reg_val; ret = sc8989x_field_read(sc, F_EN_TIMER, ®_val); if (ret) { dev_err(sc->dev, "read ICEN_TIMERC failed(%d)\n", ret); return ret; } *enabled = reg_val ? true : false; return ret; } static int sc8989x_set_vbat(struct sc8989x_chip *sc, int volt_mv) { int reg_val = val2reg(SC8989X_VBAT_REG, volt_mv); return sc8989x_field_write(sc, F_CV, reg_val); } static int sc8989x_get_vbat(struct sc8989x_chip *sc, int *volt_mv) { int ret, reg_val; ret = sc8989x_field_read(sc, F_CV, ®_val); if (ret) { dev_err(sc->dev, "read vbat reg failed(%d)\n", ret); return ret; } *volt_mv = reg2val(SC8989X_VBAT_REG, reg_val); return ret; } static int sc8989x_set_vindpm(struct sc8989x_chip *sc, int volt_mv) { int reg_val = val2reg(SC8989X_VINDPM, volt_mv); sc8989x_field_write(sc, F_FORCE_VINDPM, 1); return sc8989x_field_write(sc, F_VINDPM, reg_val); } /* static int sc8989x_get_vindpm(struct sc8989x_chip *sc, int *volt_mv) { int ret, reg_val; ret = sc8989x_field_read(sc, F_VINDPM, ®_val); if (ret) return ret; *volt_mv = reg2val(SC8989X_VINDPM, reg_val); return ret; } */ __maybe_unused static int sc8989x_set_hiz(struct sc8989x_chip *sc, bool enable) { int reg_val = enable ? 1 : 0; sc8989x_set_iindpm(sc, 500); sc8989x_set_ichg(sc, 500); return sc8989x_field_write(sc, F_EN_HIZ, reg_val); } static int sc8989x_force_dpdm(struct sc8989x_chip *sc) { int ret; int val; dev_err(sc->dev, "sc8989x_force_dpdm\n"); ret = regmap_read(sc->regmap, 0x02, &val); if (ret < 0) { return ret; } val |= 0x02; ret = regmap_write(sc->regmap, 0x02, val); sc->power_good = 0; return ret; } static int sc8989x_get_charge_stat(struct sc8989x_chip *sc) { int ret; int chg_stat, vbus_stat; ret = sc8989x_field_read(sc, F_CHG_STAT, &chg_stat); if (ret) return ret; ret = sc8989x_field_read(sc, F_VBUS_STAT, &vbus_stat); if (ret) return ret; if (vbus_stat == VBUS_STAT_OTG) { return POWER_SUPPLY_STATUS_DISCHARGING; } else { switch (chg_stat) { case CHG_STAT_NOT_CHARGE: return POWER_SUPPLY_STATUS_NOT_CHARGING; case CHG_STAT_PRE_CHARGE: case CHG_STAT_FAST_CHARGE: return POWER_SUPPLY_STATUS_CHARGING; case CHG_STAT_CHARGE_DONE: return POWER_SUPPLY_STATUS_FULL; } } return POWER_SUPPLY_STATUS_UNKNOWN; } __maybe_unused static int sc8989x_check_charge_done(struct sc8989x_chip *sc, bool * chg_done) { int ret, reg_val; ret = sc8989x_field_read(sc, F_CHG_STAT, ®_val); if (ret) { dev_err(sc->dev, "read charge stat failed(%d)\n", ret); return ret; } *chg_done = (reg_val == CHG_STAT_CHARGE_DONE) ? true : false; return ret; } static bool sc8989x_detect_device(struct sc8989x_chip *sc) { int ret; int val; ret = sc8989x_field_read(sc, F_PN, &val); if (ret < 0 || !(val == SC89890H_PN_NUM || val == SC89895_PN_NUM || val == SC8950_PN_NUM || val == SC89890W_PN_NUM)) { dev_err(sc->dev, "not find sc8989x, part_no = %d\n", val); return false; } sc->dev_id = val; return true; } __maybe_unused static int sc8989x_request_dpdm(struct sc8989x_chip *sc, bool enable) { int ret = 0; if (mutex_trylock(&sc->request_dpdm_lock) == 0){ dev_err(sc->dev, "%s: sc8989x_request_dpdm is working\n", __func__); return -EBUSY; } if (!sc->dpdm_reg) { sc->dpdm_reg = devm_regulator_get(sc->dev, "dpdm"); if (IS_ERR(sc->dpdm_reg)) { ret = PTR_ERR(sc->dpdm_reg); dev_err(sc->dev, "Couldn't get dpdm regulator ret=%d\n", ret); sc->dpdm_reg = NULL; mutex_unlock(&sc->request_dpdm_lock); return ret; } } if (enable) { if (sc->dpdm_reg && !sc->dpdm_enabled) { dev_info(sc->dev, "enabling DPDM regulator\n"); ret = regulator_enable(sc->dpdm_reg); if (ret < 0) dev_err(sc->dev, "Couldn't enable dpdm regulator ret=%d\n", ret); else sc->dpdm_enabled = true; } } else { if (sc->dpdm_reg && sc->dpdm_enabled) { dev_info(sc->dev, "disabling DPDM regulator\n"); ret = regulator_disable(sc->dpdm_reg); if (ret < 0) pr_err("Couldn't disable dpdm regulator ret=%d\n", ret); else sc->dpdm_enabled = false; } } mutex_unlock(&sc->request_dpdm_lock); return ret; } static int sc8989x_dump_register(struct sc8989x_chip *sc) { int ret; int i; int val; for (i = 0; i <= 0x14; i++) { ret = regmap_read(sc->regmap, i, &val); if (ret < 0) { return ret; } dev_info(sc->dev, "%s reg[0x%02x] = 0x%02x\n", __func__, i, val); } return 0; } #ifdef CONFIG_MTK_CLASS /********************MTK OPS***********************/ static int sc8989x_plug_in(struct charger_device *chg_dev) { int ret = 0; struct sc8989x_chip *sc = dev_get_drvdata(&chg_dev->dev); dev_info(sc->dev, "%s\n", __func__); /* Enable charging */ // ret = sc8989x_set_chg_enable(sc, true); // if (ret) { // dev_err(sc->dev, "Failed to enable charging:%d\n", ret); // } return ret; } static int sc8989x_plug_out(struct charger_device *chg_dev) { int ret = 0; struct sc8989x_chip *sc = dev_get_drvdata(&chg_dev->dev); dev_info(sc->dev, "%s\n", __func__); // ret = sc8989x_set_chg_enable(sc, false); // if (ret) { // dev_err(sc->dev, "Failed to disable charging:%d\n", ret); // } return ret; } static int sc8989x_enable(struct charger_device *chg_dev, bool en) { int ret = 0; struct sc8989x_chip *sc = dev_get_drvdata(&chg_dev->dev); ret = sc8989x_set_chg_enable(sc, en); dev_info(sc->dev, "%s charger %s\n", en ? "enable" : "disable", !ret ? "successfully" : "failed"); return ret; } static int sc8989x_is_enabled(struct charger_device *chg_dev, bool * enabled) { int ret; struct sc8989x_chip *sc = dev_get_drvdata(&chg_dev->dev); ret = sc8989x_check_chg_enabled(sc, enabled); dev_info(sc->dev, "charger is %s\n", *enabled ? "charging" : "not charging"); return ret; } static int sc8989x_get_charging_current(struct charger_device *chg_dev, u32 * curr) { int ret = 0; int curr_ma; struct sc8989x_chip *sc = dev_get_drvdata(&chg_dev->dev); ret = sc8989x_get_ichg(sc, &curr_ma); if (!ret) { *curr = curr_ma * 1000; } return ret; } static int sc8989x_set_charging_current(struct charger_device *chg_dev, u32 curr) { struct sc8989x_chip *sc = dev_get_drvdata(&chg_dev->dev); dev_info(sc->dev, "%s: charge curr = %duA\n", __func__, curr); return sc8989x_set_ichg(sc, curr / 1000); } static int sc8989x_get_input_current(struct charger_device *chg_dev, u32 * curr) { struct sc8989x_chip *sc = dev_get_drvdata(&chg_dev->dev); int curr_ma; int ret; dev_info(sc->dev, "%s\n", __func__); ret = sc8989x_get_iindpm(sc, &curr_ma); if (!ret) { *curr = curr_ma * 1000; } return ret; } static int sc8989x_set_input_current(struct charger_device *chg_dev, u32 curr) { struct sc8989x_chip *sc = dev_get_drvdata(&chg_dev->dev); dev_info(sc->dev, "%s: iindpm curr = %duA\n", __func__, curr); return sc8989x_set_iindpm(sc, curr / 1000); } static int sc8989x_get_constant_voltage(struct charger_device *chg_dev, u32 * volt) { struct sc8989x_chip *sc = dev_get_drvdata(&chg_dev->dev); int volt_mv; int ret; dev_info(sc->dev, "%s\n", __func__); ret = sc8989x_get_vbat(sc, &volt_mv); if (!ret) { *volt = volt_mv * 1000; } return ret; } static int sc8989x_set_constant_voltage(struct charger_device *chg_dev, u32 volt) { struct sc8989x_chip *sc = dev_get_drvdata(&chg_dev->dev); dev_info(sc->dev, "%s: charge volt = %duV\n", __func__, volt); return sc8989x_set_vbat(sc, volt / 1000); } static int sc8989x_kick_wdt(struct charger_device *chg_dev) { struct sc8989x_chip *sc = dev_get_drvdata(&chg_dev->dev); dev_info(sc->dev, "%s\n", __func__); return sc8989x_reset_wdt(sc); } static int sc8989x_set_ivl(struct charger_device *chg_dev, u32 volt) { struct sc8989x_chip *sc = dev_get_drvdata(&chg_dev->dev); dev_info(sc->dev, "%s: vindpm volt = %d\n", __func__, volt); return sc8989x_set_vindpm(sc, volt / 1000); } static int sc8989x_is_charging_done(struct charger_device *chg_dev, bool * done) { struct sc8989x_chip *sc = dev_get_drvdata(&chg_dev->dev); int ret; ret = sc8989x_check_charge_done(sc, done); dev_info(sc->dev, "%s: charge %s done\n", __func__, *done ? "is" : "not"); return ret; } static int sc8989x_get_min_ichg(struct charger_device *chg_dev, u32 * curr) { struct sc8989x_chip *sc = dev_get_drvdata(&chg_dev->dev); *curr = 60 * 1000; dev_err(sc->dev, "%s\n", __func__); return 0; } static int sc8989x_dump_registers(struct charger_device *chg_dev) { struct sc8989x_chip *sc = dev_get_drvdata(&chg_dev->dev); dev_info(sc->dev, "%s\n", __func__); return sc8989x_dump_register(sc); } static int sc8989x_send_ta_current_pattern(struct charger_device *chg_dev, bool is_increase) { struct sc8989x_chip *sc = dev_get_drvdata(&chg_dev->dev); int ret; int i; dev_info(sc->dev, "%s: %s\n", __func__, is_increase ? "pumpx up" : "pumpx dn"); //pumpx start ret = sc8989x_set_iindpm(sc, 100); if (ret) return ret; msleep(10); for (i = 0; i < 6; i++) { if (i < 3) { sc8989x_set_iindpm(sc, 800); is_increase ? msleep(100) : msleep(300); } else { sc8989x_set_iindpm(sc, 800); is_increase ? msleep(300) : msleep(100); } sc8989x_set_iindpm(sc, 100); msleep(100); } //pumpx stop sc8989x_set_iindpm(sc, 800); msleep(500); //pumpx wdt, max 240ms sc8989x_set_iindpm(sc, 100); msleep(100); return sc8989x_set_iindpm(sc, 1500); } static int sc8989x_send_ta20_current_pattern(struct charger_device *chg_dev, u32 uV) { struct sc8989x_chip *sc = dev_get_drvdata(&chg_dev->dev); u8 val = 0; int i; if (uV < 5500000) { uV = 5500000; } else if (uV > 15000000) { uV = 15000000; } val = (uV - 5500000) / 500000; dev_info(sc->dev, "%s ta20 vol=%duV, val=%d\n", __func__, uV, val); sc8989x_set_iindpm(sc, 100); msleep(150); for (i = 4; i >= 0; i--) { sc8989x_set_iindpm(sc, 800); (val & (1 << i)) ? msleep(100) : msleep(50); sc8989x_set_iindpm(sc, 100); (val & (1 << i)) ? msleep(50) : msleep(100); } sc8989x_set_iindpm(sc, 800); msleep(150); sc8989x_set_iindpm(sc, 100); msleep(240); return sc8989x_set_iindpm(sc, 800); } static int sc8989x_set_ta20_reset(struct charger_device *chg_dev) { struct sc8989x_chip *sc = dev_get_drvdata(&chg_dev->dev); int curr; int ret; ret = sc8989x_get_iindpm(sc, &curr); ret = sc8989x_set_iindpm(sc, 100); msleep(300); return sc8989x_set_iindpm(sc, curr); } static int sc8989x_get_adc(struct charger_device *chg_dev, enum adc_channel chan, int *min, int *max) { struct sc8989x_chip *sc = dev_get_drvdata(&chg_dev->dev); enum sc8989x_adc_channel sc_chan; switch (chan) { case ADC_CHANNEL_VBAT: sc_chan = SC8989X_ADC_VBAT; break; case ADC_CHANNEL_VSYS: sc_chan = SC8989X_ADC_VSYS; break; case ADC_CHANNEL_VBUS: sc_chan = SC8989X_ADC_VBUS; break; case ADC_CHANNEL_IBUS: sc_chan = SC8989X_ADC_IBUS; break; default: return -95; } __sc8989x_get_adc(sc, sc_chan, min); *min = *min * 1000; *max = *min; return 0; } static int sc8989x_get_vbus(struct charger_device *chg_dev, u32 *vbus) { struct sc8989x_chip *sc = dev_get_drvdata(&chg_dev->dev); return __sc8989x_get_adc(sc, SC8989X_ADC_VBUS, vbus); } static int sc8989x_get_ibat(struct charger_device *chg_dev, u32 *ibat) { struct sc8989x_chip *sc = dev_get_drvdata(&chg_dev->dev); return __sc8989x_get_adc(sc, SC8989X_ADC_ICC, ibat); } static int sc8989x_get_ibus(struct charger_device *chg_dev, u32 *ibus) { struct sc8989x_chip *sc = dev_get_drvdata(&chg_dev->dev); return __sc8989x_get_adc(sc, SC8989X_ADC_IBUS, ibus); } static int sc8989x_set_otg(struct charger_device *chg_dev, bool enable) { int ret; struct sc8989x_chip *sc = dev_get_drvdata(&chg_dev->dev); ret = sc8989x_set_otg_enable(sc, enable); ret |= sc8989x_set_chg_enable(sc, !enable); dev_info(sc->dev, "%s OTG %s\n", enable ? "enable" : "disable", !ret ? "successfully" : "failed"); return ret; } static int sc8989x_set_safety_timer(struct charger_device *chg_dev, bool enable) { struct sc8989x_chip *sc = dev_get_drvdata(&chg_dev->dev); dev_info(sc->dev, "%s %s\n", __func__, enable ? "enable" : "disable"); return sc8989x_set_safet_timer(sc, enable); } static int sc8989x_is_safety_timer_enabled(struct charger_device *chg_dev, bool * enabled) { struct sc8989x_chip *sc = dev_get_drvdata(&chg_dev->dev); return sc8989x_check_safet_timer(sc, enabled); } static int sc8989x_set_boost_ilmt(struct charger_device *chg_dev, u32 curr) { struct sc8989x_chip *sc = dev_get_drvdata(&chg_dev->dev); dev_info(sc->dev, "%s otg curr = %d\n", __func__, curr); return sc8989x_set_iboost(sc, curr / 1000); } static int sc8989x_do_event(struct charger_device *chg_dev, u32 event, u32 args) { struct sc8989x_chip *sc = dev_get_drvdata(&chg_dev->dev); dev_info(sc->dev, "%s\n", __func__); switch (event) { case EVENT_FULL: case EVENT_DISCHARGE: charger_dev_notify(chg_dev, CHARGER_DEV_NOTIFY_EOC); break; case EVENT_RECHARGE: charger_dev_notify(chg_dev, CHARGER_DEV_NOTIFY_RECHG); break; default: break; } return 0; } /* static int sc8989x_enable_hz(struct charger_device *chg_dev, bool enable) { struct sc8989x_chip *sc = dev_get_drvdata(&chg_dev->dev); dev_info(sc->dev, "%s %s\n", __func__, enable ? "enable" : "disable"); return sc8989x_set_hiz(sc, enable); } */ static int sc8989x_enable_powerpath(struct charger_device *chg_dev, bool en) { struct sc8989x_chip *sc = dev_get_drvdata(&chg_dev->dev); dev_info(sc->dev, "%s en = %d\n", __func__, en); return sc8989x_set_chg_enable(sc, en); } static int sc8989x_is_powerpath_enabled(struct charger_device *chg_dev, bool * en) { struct sc8989x_chip *sc = dev_get_drvdata(&chg_dev->dev); return sc8989x_check_chg_enabled(sc, en); } static void sc8989x_chg_attach_pre_process(struct sc8989x_chip *sc, enum sc8989x_attach_trigger trig, int attach) { bool bc12_dn; pr_err("trig=%s,attach=%d\n", sc8989x_attach_trig_names[trig], attach); /* if attach trigger is not match, ignore it */ if (sc->attach_trig != trig) { dev_info(sc->dev, "trig=%s ignored\n", sc8989x_attach_trig_names[trig]); return; } mutex_lock(&sc->attach_lock); if (attach == ATTACH_TYPE_NONE) sc->bc12_dn = false; bc12_dn = sc->bc12_dn; if (!bc12_dn) atomic_set(&sc->attach, attach); mutex_unlock(&sc->attach_lock); if (attach > ATTACH_TYPE_PD && bc12_dn) return; if (!queue_work(sc->wq, &sc->bc12_work)) dev_notice(sc->dev, "%s bc12 work already queued\n", __func__); } static void sc8989x_chg_pwr_rdy_process(struct sc8989x_chip *sc) { int ret; u32 val; ret = sc8989x_field_read(sc, F_VBUS_STAT, &val); if (ret < 0 || sc->pwr_rdy == val) return; sc->pwr_rdy = val; dev_dbg(sc->dev, "pwr_rdy=%d\n", val); sc8989x_chg_attach_pre_process(sc, ATTACH_TRIG_PWR_RDY, val ? ATTACH_TYPE_PWR_RDY : ATTACH_TYPE_NONE); } static int sc8989x_chg_set_usbsw(struct sc8989x_chip *sc, enum sc8989x_usbsw usbsw) { struct phy *phy; int ret, mode = (usbsw == USBSW_CHG) ? PHY_MODE_BC11_SET : PHY_MODE_BC11_CLR; dev_dbg(sc->dev, "usbsw=%d\n", usbsw); phy = phy_get(sc->dev, "usb2-phy"); if (IS_ERR_OR_NULL(phy)) { dev_err(sc->dev, "failed to get usb2-phy\n"); return -ENODEV; } ret = phy_set_mode_ext(phy, PHY_MODE_USB_DEVICE, mode); if (ret) dev_err(sc->dev, "failed to set phy ext mode\n"); phy_put(sc->dev, phy); return ret; } static bool is_usb_rdy(struct device *dev) { bool ready = true; struct device_node *node; node = of_parse_phandle(dev->of_node, "usb", 0); if (node) { ready = !of_property_read_bool(node, "cdp-block"); dev_dbg(dev, "usb ready = %d\n", ready); } else dev_warn(dev, "usb node missing or invalid\n"); return ready; } static int sc8989x_chg_enable_bc12(struct sc8989x_chip *sc, bool en) { int i, ret, attach; static const int max_wait_cnt = 250; dev_dbg(sc->dev, "en=%d\n", en); if (en) { /* CDP port specific process */ dev_info(sc->dev, "check CDP block\n"); for (i = 0; i < max_wait_cnt; i++) { if (is_usb_rdy(sc->dev)) break; attach = atomic_read(&sc->attach); if (attach == ATTACH_TYPE_TYPEC) msleep(100); else { dev_notice(sc->dev, "%s: change attach:%d, disable bc12\n", __func__, attach); en = false; break; } } if (i == max_wait_cnt) dev_notice(sc->dev, "CDP timeout\n", __func__); else dev_info(sc->dev, "CDP free\n", __func__); } ret = sc8989x_chg_set_usbsw(sc, en ? USBSW_CHG : USBSW_USB); if (ret) return ret; return sc8989x_force_dpdm(sc); } static void sc8989x_chg_bc12_work_func(struct work_struct *work) { struct sc8989x_chip *sc = container_of(work, struct sc8989x_chip, bc12_work); bool bc12_ctrl = true, bc12_en = false, rpt_psy = true; int ret, attach; u32 val = 0; mutex_lock(&sc->attach_lock); attach = atomic_read(&sc->attach); dev_dbg(sc->dev, "attach=%d\n", attach); if (attach > ATTACH_TYPE_NONE && sc->bootmode == 5) { /* skip bc12 to speed up ADVMETA_BOOT */ dev_notice(sc->dev, "force SDP in meta mode\n"); sc->psy_desc.type = POWER_SUPPLY_TYPE_USB; sc->psy_usb_type = POWER_SUPPLY_USB_TYPE_SDP; goto out; } switch (attach) { case ATTACH_TYPE_NONE: sc->psy_desc.type = POWER_SUPPLY_TYPE_USB; sc->psy_usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN; goto out; case ATTACH_TYPE_TYPEC: if (!sc->bc12_dn) { bc12_en = true; rpt_psy = false; goto out; } ret = sc8989x_field_read(sc, F_VBUS_STAT, &val); if (ret < 0) { dev_err(sc->dev, "failed to get port stat\n"); rpt_psy = false; goto out; } break; case ATTACH_TYPE_PD_SDP: val = VBUS_STAT_SDP; break; case ATTACH_TYPE_PD_DCP: /* not to enable bc12 */ sc->psy_desc.type = POWER_SUPPLY_TYPE_USB_DCP; sc->psy_usb_type = POWER_SUPPLY_USB_TYPE_DCP; goto out; case ATTACH_TYPE_PD_NONSTD: val = VBUS_STAT_NONSTAND; break; default: dev_info(sc->dev, "%s: using tradtional bc12 flow!\n", __func__); break; } switch (val) { case VBUS_STAT_NO_INPUT: bc12_ctrl = false; rpt_psy = false; dev_info(sc->dev, "%s no info\n", __func__); goto out; case VBUS_STAT_DCP: case VBUS_STAT_HVDCP: sc->psy_desc.type = POWER_SUPPLY_TYPE_USB_DCP; sc->psy_usb_type = POWER_SUPPLY_USB_TYPE_DCP; bc12_en = true; break; case VBUS_STAT_SDP: sc->psy_desc.type = POWER_SUPPLY_TYPE_USB; sc->psy_usb_type = POWER_SUPPLY_USB_TYPE_SDP; break; case VBUS_STAT_CDP: sc->psy_desc.type = POWER_SUPPLY_TYPE_USB_CDP; sc->psy_usb_type = POWER_SUPPLY_USB_TYPE_CDP; break; case VBUS_STAT_NONSTAND: sc->psy_desc.type = POWER_SUPPLY_TYPE_USB; sc->psy_usb_type = POWER_SUPPLY_USB_TYPE_DCP; break; default: bc12_ctrl = false; rpt_psy = false; dev_info(sc->dev, "Unknown port stat %d\n", val); goto out; } dev_dbg(sc->dev, "port stat = %s\n", sc8989x_port_stat_names[val]); out: mutex_unlock(&sc->attach_lock); if (bc12_ctrl && (sc8989x_chg_enable_bc12(sc, bc12_en) < 0)) dev_err(sc->dev, "failed to set bc12 = %d\n", bc12_en); if (rpt_psy) power_supply_changed(sc->psy); } static int sc8989x_enable_chg_type_det(struct charger_device *chg_dev, bool en) { struct sc8989x_chip *sc = dev_get_drvdata(&chg_dev->dev); int attach = en ? ATTACH_TYPE_TYPEC : ATTACH_TYPE_NONE; dev_dbg(sc->dev, "en=%d\n", en); sc8989x_chg_attach_pre_process(sc, ATTACH_TRIG_TYPEC, attach); return 0; } static struct charger_ops sc8989x_chg_ops = { /* Normal charging */ .plug_in = sc8989x_plug_in, .plug_out = sc8989x_plug_out, .enable = sc8989x_enable, .is_enabled = sc8989x_is_enabled, .get_charging_current = sc8989x_get_charging_current, .set_charging_current = sc8989x_set_charging_current, .get_input_current = sc8989x_get_input_current, .set_input_current = sc8989x_set_input_current, .get_constant_voltage = sc8989x_get_constant_voltage, .set_constant_voltage = sc8989x_set_constant_voltage, .kick_wdt = sc8989x_kick_wdt, .set_mivr = sc8989x_set_ivl, .is_charging_done = sc8989x_is_charging_done, .get_min_charging_current = sc8989x_get_min_ichg, .dump_registers = sc8989x_dump_registers, /* Safety timer */ .enable_safety_timer = sc8989x_set_safety_timer, .is_safety_timer_enabled = sc8989x_is_safety_timer_enabled, /* Power path */ .enable_powerpath = sc8989x_enable_powerpath, .is_powerpath_enabled = sc8989x_is_powerpath_enabled, /* OTG */ .enable_otg = sc8989x_set_otg, .set_boost_current_limit = sc8989x_set_boost_ilmt, .enable_discharge = NULL, /* PE+/PE+20 */ .send_ta_current_pattern = sc8989x_send_ta_current_pattern, .set_pe20_efficiency_table = NULL, .send_ta20_current_pattern = sc8989x_send_ta20_current_pattern, .reset_ta = sc8989x_set_ta20_reset, .enable_cable_drop_comp = NULL, /* ADC */ .get_adc = sc8989x_get_adc, .get_vbus_adc = sc8989x_get_vbus, .get_ibus_adc = sc8989x_get_ibus, .get_ibat_adc = sc8989x_get_ibat, .event = sc8989x_do_event, /* charger type detection */ .enable_chg_type_det = sc8989x_enable_chg_type_det, }; static const struct charger_properties sc8989x_chg_props = { .alias_name = "sc8989x_chg", }; static void sc8989x_inform_psy_dwork_handler(struct work_struct *work) { int ret = 0; union power_supply_propval propval; struct sc8989x_chip *sc = container_of(work, struct sc8989x_chip, psy_dwork.work); if (!sc->chg_psy) { sc->chg_psy = power_supply_get_by_name("charger"); if (!sc->chg_psy) { pr_err("%s get power supply fail\n", __func__); mod_delayed_work(system_wq, &sc->psy_dwork, msecs_to_jiffies(2000)); return ; } } if (sc->psy_usb_type != POWER_SUPPLY_USB_TYPE_UNKNOWN) propval.intval = 1; else propval.intval = 0; ret = power_supply_set_property(sc->chg_psy, POWER_SUPPLY_PROP_ONLINE, &propval); if (ret < 0) pr_notice("inform power supply online failed:%d\n", ret); propval.intval = sc->psy_usb_type; ret = power_supply_set_property(sc->chg_psy, POWER_SUPPLY_PROP_CHARGE_TYPE, &propval); if (ret < 0) pr_notice("inform power supply charge type failed:%d\n", ret); } #endif /*CONFIG_MTK_CLASS */ /**********************interrupt*********************/ static void sc8989x_force_detection_dwork_handler(struct work_struct *work) { int ret; struct sc8989x_chip *sc = container_of(work, struct sc8989x_chip, force_detect_dwork.work); ret = sc8989x_force_dpdm(sc); if (ret) { dev_err(sc->dev, "%s: force dpdm failed(%d)\n", __func__, ret); return; } sc->force_detect_count++; } static void sc8989x_inserted_irq(struct sc8989x_chip *sc) { dev_info(sc->dev, "%s: adapter/usb inserted\n", __func__); if (sc->pr_swap){ dev_info(sc->dev, "%s: pr_swap\n", __func__); return; } sc8989x_field_write(sc, F_CONV_RATE, true); } static void sc8989x_removed_irq(struct sc8989x_chip *sc) { dev_info(sc->dev, "%s: adapter/usb removed\n", __func__); //sc8989x_request_dpdm(sc, false); //cancel_delayed_work_sync(&sc->force_detect_dwork); sc8989x_set_dpdm_hiz(sc); sc8989x_set_iindpm(sc, 500); sc8989x_set_ichg(sc, 500); sc8989x_field_write(sc, F_CONV_RATE, false); } static irqreturn_t sc8989x_irq_handler(int irq, void *data) { int ret; int reg_val; bool prev_pg; bool prev_vbus_gd; int attach; struct sc8989x_chip *sc = (struct sc8989x_chip *)data; dev_info(sc->dev, "%s: sc8989x_irq_handler\n", __func__); attach = atomic_read(&sc->attach); sc->bc12_dn = (attach == ATTACH_TYPE_NONE) ? false : true; ret = sc8989x_field_read(sc, F_VBUS_GD, ®_val); if (ret) { return IRQ_HANDLED; } prev_vbus_gd = sc->vbus_good; sc->vbus_good = !!reg_val; ret = sc8989x_field_read(sc, F_PG_STAT, ®_val); if (ret) { return IRQ_HANDLED; } prev_pg = sc->power_good; sc->power_good = !!reg_val; if (!prev_vbus_gd && sc->vbus_good) { sc8989x_inserted_irq(sc); } else if (prev_vbus_gd && !sc->vbus_good) { sc8989x_removed_irq(sc); } if (!prev_pg && sc->power_good) { if (!queue_work(sc->wq, &sc->bc12_work)) dev_notice(sc->dev, "%s bc12 work already queued\n", __func__); } power_supply_changed(sc->psy); sc8989x_dump_register(sc); return IRQ_HANDLED; } /**********************system*********************/ static int sc8989x_parse_dt(struct sc8989x_chip *sc) { struct device_node *np = sc->dev->of_node; int i; int ret = 0; struct device_node *boot_node = NULL; struct tag_bootmode *tag = NULL; struct { char *name; int *conv_data; } props[] = { {"sc,sc8989x,ico-en", &(sc->cfg->ico_en)}, {"sc,sc8989x,hvdcp-en", &(sc->cfg->hvdcp_en)}, {"sc,sc8989x,auto-dpdm-en", &(sc->cfg->auto_dpdm_en)}, {"sc,sc8989x,vsys-min", &(sc->cfg->vsys_min)}, {"sc,sc8989x,vbatmin-sel", &(sc->cfg->vbatmin_sel)}, {"sc,sc8989x,itrick", &(sc->cfg->itrick)}, {"sc,sc8989x,iterm", &(sc->cfg->iterm)}, {"sc,sc8989x,vbat-cv", &(sc->cfg->vbat_cv)}, {"sc,sc8989x,vbat-low", &(sc->cfg->vbat_low)}, {"sc,sc8989x,vrechg", &(sc->cfg->vrechg)}, {"sc,sc8989x,en-term", &(sc->cfg->en_term)}, {"sc,sc8989x,stat-dis", &(sc->cfg->stat_dis)}, {"sc,sc8989x,wd-time", &(sc->cfg->wd_time)}, {"sc,sc8989x,en-timer", &(sc->cfg->en_timer)}, {"sc,sc8989x,charge-timer", &(sc->cfg->charge_timer)}, {"sc,sc8989x,bat-comp", &(sc->cfg->bat_comp)}, {"sc,sc8989x,vclamp", &(sc->cfg->vclamp)}, {"sc,sc8989x,votg", &(sc->cfg->votg)}, {"sc,sc8989x,iboost", &(sc->cfg->iboost)}, {"sc,sc8989x,vindpm", &(sc->cfg->vindpm)},}; sc->irq_gpio = of_get_named_gpio(np, "sc,intr-gpio", 0); if (sc->irq_gpio < 0) dev_err(sc->dev, "%s sc,intr-gpio is not available\n", __func__); if (of_property_read_string(np, "charger_name", &sc->cfg->chg_name) < 0) dev_err(sc->dev, "%s no charger name\n", __func__); ret = of_property_read_u32(np, "bc12_en", &sc->bc12_en); dev_info(sc->dev, "%s: bc12_en = %d\n", __func__, sc->bc12_en); /* initialize data for optional properties */ for (i = 0; i < ARRAY_SIZE(props); i++) { ret = of_property_read_u32(np, props[i].name, props[i].conv_data); if (ret < 0) { dev_err(sc->dev, "%s not find\n", props[i].name); continue; } } boot_node = of_parse_phandle(sc->dev->of_node, "bootmode", 0); if (!boot_node) pr_err("%s: failed to get boot mode phandle\n", __func__); else { tag = (struct tag_bootmode *)of_get_property(boot_node, "atag,boot", NULL); if (!tag) pr_err("%s: failed to get atag,boot\n", __func__); else { pr_err("%s: size:0x%x tag:0x%x bootmode:0x%x boottype:0x%x\n", __func__, tag->size, tag->tag, tag->bootmode, tag->boottype); sc->bootmode = tag->bootmode; sc->boottype = tag->boottype; } } sc->attach_trig = ATTACH_TRIG_TYPEC; return 0; } static int sc8989x_init_device(struct sc8989x_chip *sc) { int ret = 0; int i; struct { enum sc8989x_fields field_id; int conv_data; } props[] = { {F_ICO_EN, sc->cfg->ico_en}, {F_HVDCP_EN, sc->cfg->hvdcp_en}, {F_AUTO_DPDM_EN, sc->cfg->auto_dpdm_en}, {F_VSYS_MIN, sc->cfg->vsys_min}, {F_VBATMIN_SEL, sc->cfg->vbatmin_sel}, {F_ITC, sc->cfg->itrick}, {F_ITERM, sc->cfg->iterm}, {F_CV, sc->cfg->vbat_cv}, {F_VBAT_LOW, sc->cfg->vbat_low}, {F_VRECHG, sc->cfg->vrechg}, {F_EN_ITERM, sc->cfg->en_term}, {F_STAT_DIS, sc->cfg->stat_dis}, {F_TWD, sc->cfg->wd_time}, {F_EN_TIMER, sc->cfg->en_timer}, {F_TCHG, sc->cfg->charge_timer}, {F_BAT_COMP, sc->cfg->bat_comp}, {F_VCLAMP, sc->cfg->vclamp}, {F_V_OTG, sc->cfg->votg}, {F_IBOOST_LIM, sc->cfg->iboost}, {F_VINDPM, sc->cfg->vindpm},}; //reg reset; sc8989x_field_write(sc, F_REG_RST, 1); for (i = 0; i < ARRAY_SIZE(props); i++) { dev_info(sc->dev, "%d--->%d\n", props[i].field_id, props[i].conv_data); ret = sc8989x_field_write(sc, props[i].field_id, props[i].conv_data); } //sc8989x_adc_ibus_en(sc, true);//DRV sc8989x i2c ack err //sc8989x_set_wa(sc);//DRV sc8989x i2c ack err sc8989x_set_iindpm(sc, 500); sc8989x_set_ichg(sc, 500); return sc8989x_dump_register(sc); } static int sc8989x_register_interrupt(struct sc8989x_chip *sc) { int ret = 0; ret = devm_gpio_request(sc->dev, sc->irq_gpio, "chr-irq"); if (ret < 0) { dev_err(sc->dev, "failed to request GPIO%d ; ret = %d", sc->irq_gpio, ret); return ret; } ret = gpio_direction_input(sc->irq_gpio); if (ret < 0) { dev_err(sc->dev, "failed to set GPIO%d ; ret = %d", sc->irq_gpio, ret); return ret; } sc->irq = gpio_to_irq(sc->irq_gpio); if (ret < 0) { dev_err(sc->dev, "failed gpio to irq GPIO%d ; ret = %d", sc->irq_gpio, ret); return ret; } ret = devm_request_threaded_irq(sc->dev, sc->irq, NULL, sc8989x_irq_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "chr_irq", sc); if (ret < 0) { dev_err(sc->dev, "request thread irq failed:%d\n", ret); return ret; } else { dev_err(sc->dev, "request thread irq pass:%d sc->irq =%d\n", ret, sc->irq); } enable_irq_wake(sc->irq); return 0; } static void determine_initial_status(struct sc8989x_chip *sc) { sc8989x_irq_handler(sc->irq, (void *)sc); } //reigster static ssize_t sc8989x_show_registers(struct device *dev, struct device_attribute *attr, char *buf) { struct sc8989x_chip *sc = dev_get_drvdata(dev); uint8_t addr; unsigned int val; uint8_t tmpbuf[300]; int len; int idx = 0; int ret; idx = snprintf(buf, PAGE_SIZE, "%s:\n", "sc8989x"); for (addr = 0x0; addr <= 0x14; addr++) { ret = regmap_read(sc->regmap, addr, &val); if (ret == 0) { len = snprintf(tmpbuf, PAGE_SIZE - idx, "Reg[%.2X] = 0x%.2x\n", addr, val); memcpy(&buf[idx], tmpbuf, len); idx += len; } } return idx; } static ssize_t sc8989x_store_register(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct sc8989x_chip *sc = dev_get_drvdata(dev); int ret; unsigned int val; unsigned int reg; ret = sscanf(buf, "%x %x", ®, &val); if (ret == 2 && reg <= 0x14) regmap_write(sc->regmap, (unsigned char)reg, (unsigned char)val); return count; } static DEVICE_ATTR(registers, 0660, sc8989x_show_registers, sc8989x_store_register); static void sc8989x_create_device_node(struct device *dev) { device_create_file(dev, &dev_attr_registers); } static enum power_supply_property sc8989x_chg_psy_properties[] = { POWER_SUPPLY_PROP_MANUFACTURER, POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, //POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT, // kernel4.19 none POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, POWER_SUPPLY_PROP_USB_TYPE, POWER_SUPPLY_PROP_CURRENT_MAX, POWER_SUPPLY_PROP_VOLTAGE_MAX, }; static enum power_supply_usb_type sc8989x_chg_psy_usb_types[] = { POWER_SUPPLY_USB_TYPE_UNKNOWN, POWER_SUPPLY_USB_TYPE_SDP, POWER_SUPPLY_USB_TYPE_CDP, POWER_SUPPLY_USB_TYPE_DCP, }; static int sc8989x_chg_property_is_writeable(struct power_supply *psy, enum power_supply_property psp) { int ret; switch (psp) { case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: //case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: case POWER_SUPPLY_PROP_STATUS: case POWER_SUPPLY_PROP_ONLINE: case POWER_SUPPLY_PROP_ENERGY_EMPTY: ret = 1; break; default: ret = 0; } return ret; } static int sc8989x_chg_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { struct sc8989x_chip *sc = power_supply_get_drvdata(psy); int ret = 0; int data = 0; if (!sc) { dev_err(sc->dev, "%s:line%d: NULL pointer!!!\n", __func__, __LINE__); return ret; } switch (psp) { case POWER_SUPPLY_PROP_MANUFACTURER: val->strval = "SouthChip"; break; case POWER_SUPPLY_PROP_ONLINE: val->intval = sc->vbus_good; break; /* drv midified by liuhai 20240416 end */ case POWER_SUPPLY_PROP_STATUS: ret = sc8989x_get_charge_stat(sc); if (ret < 0) break; val->intval = ret; break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: ret = sc8989x_get_ichg(sc, &data); if (ret) break; val->intval = data * 1000; break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: ret = sc8989x_get_vbat(sc, &data); if (ret < 0) break; val->intval = data * 1000; break; case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: ret = sc8989x_get_iindpm(sc, &data); if (ret < 0) break; val->intval = data * 1000; break; /* case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: ret = sc8989x_get_vindpm(sc, &data); if (ret < 0) break; val->intval = data * 1000; break; */ case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: ret = sc8989x_get_term_curr(sc, &data); if (ret < 0) break; val->intval = data * 1000; break; case POWER_SUPPLY_PROP_USB_TYPE: val->intval = sc->psy_usb_type; break; case POWER_SUPPLY_PROP_CURRENT_MAX: if (sc->psy_usb_type == POWER_SUPPLY_USB_TYPE_SDP) val->intval = 500000; else val->intval = 1500000; break; case POWER_SUPPLY_PROP_VOLTAGE_MAX: if (sc->psy_usb_type == POWER_SUPPLY_USB_TYPE_SDP) val->intval = 5000000; else val->intval = 12000000; break; case POWER_SUPPLY_PROP_TYPE: val->intval = sc->psy_desc.type; break; /* drv midified by liuhai 20240416 end */ default: ret = -EINVAL; break; } return ret; } static int sc8989x_chg_set_property(struct power_supply *psy, enum power_supply_property psp, const union power_supply_propval *val) { struct sc8989x_chip *sc = power_supply_get_drvdata(psy); int ret = 0; switch (psp) { case POWER_SUPPLY_PROP_ONLINE: sc8989x_chg_attach_pre_process(sc, ATTACH_TRIG_TYPEC, val->intval); break; case POWER_SUPPLY_PROP_STATUS: ret = sc8989x_set_chg_enable(sc, !!val->intval); if (val->intval == POWER_SUPPLY_STATUS_DISCHARGING){ sc8989x_set_otg_enable(sc, true); sc8989x_set_chg_enable(sc, false); } break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: ret = sc8989x_set_ichg(sc, val->intval / 1000); break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: ret = sc8989x_set_vbat(sc, val->intval / 1000); break; case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: ret = sc8989x_set_iindpm(sc, val->intval / 1000); break; /* case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: ret = sc8989x_set_vindpm(sc, val->intval / 1000); break; */ case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: ret = sc8989x_set_term_curr(sc, val->intval / 1000); break; default: ret = -EINVAL; break; } return ret; } static char *sc8989x_psy_supplied_to[] = { "battery", "mtk-master-charger", }; static const struct power_supply_desc sc8989x_psy_desc = { .name = "primary_chg", .type = POWER_SUPPLY_TYPE_USB, .usb_types = sc8989x_chg_psy_usb_types, .num_usb_types = ARRAY_SIZE(sc8989x_chg_psy_usb_types), .properties = sc8989x_chg_psy_properties, .num_properties = ARRAY_SIZE(sc8989x_chg_psy_properties), .property_is_writeable = sc8989x_chg_property_is_writeable, .get_property = sc8989x_chg_get_property, .set_property = sc8989x_chg_set_property, }; static int sc8989x_psy_register(struct sc8989x_chip *sc) { struct power_supply_config cfg = { .drv_data = sc, .of_node = sc->dev->of_node, .supplied_to = sc8989x_psy_supplied_to, .num_supplicants = ARRAY_SIZE(sc8989x_psy_supplied_to), }; memcpy(&sc->psy_desc, &sc8989x_psy_desc, sizeof(sc->psy_desc)); sc->psy = devm_power_supply_register(sc->dev, &sc->psy_desc, &cfg); return IS_ERR(sc->psy) ? PTR_ERR(sc->psy) : 0; } static const struct regulator_ops sc8989x_chg_otg_ops = { .list_voltage = regulator_list_voltage_linear, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, }; static const struct regulator_desc sc8989x_otg_rdesc = { .of_match = "usb-otg-vbus", .name = "usb-otg-vbus", .ops = &sc8989x_chg_otg_ops, .owner = THIS_MODULE, .type = REGULATOR_VOLTAGE, .min_uV = 3900000, .uV_step = 100000, /* step 100mV */ .n_voltages = 16, /* 3900mV to 5400mV */ .vsel_reg = 0x0a, .vsel_mask = 0xf0, .enable_reg = 0x03, .enable_mask = 0x30, .disable_val = 0x10, .enable_val = 0x20, }; static struct of_device_id sc8989x_of_device_id[] = { //{.compatible = "southchip,sc89890h",}, //{.compatible = "southchip,sc89890w",}, //{.compatible = "southchip,sc89895",}, //{.compatible = "southchip,sc8950",}, {.compatible = "southchip,sc8989x",}, {}, }; MODULE_DEVICE_TABLE(of, sc8989x_of_device_id); static int sc8989x_charger_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct sc8989x_chip *sc; int ret = 0; int i; struct regulator_config config = { }; dev_err(&client->dev, "%s (%s)\n", __func__, SC8989X_DRV_VERSION); sc = devm_kzalloc(&client->dev, sizeof(struct sc8989x_chip), GFP_KERNEL); if (!sc) return -ENOMEM; sc->dev = &client->dev; sc->client = client; sc->regmap = devm_regmap_init_i2c(client, &sc8989x_regmap_config); if (IS_ERR(sc->regmap)) { dev_err(sc->dev, "Failed to initialize regmap\n"); return -EINVAL; } for (i = 0; i < ARRAY_SIZE(sc8989x_reg_fields); i++) { sc->rmap_fields[i] = devm_regmap_field_alloc(sc->dev, sc->regmap, sc8989x_reg_fields[i]); if (IS_ERR(sc->rmap_fields[i])) { dev_err(sc->dev, "cannot allocate regmap field\n"); return PTR_ERR(sc->rmap_fields[i]); } } i2c_set_clientdata(client, sc); if (!sc8989x_detect_device(sc)) { ret = -ENODEV; goto err_nodev; } sc8989x_create_device_node(&(client->dev)); INIT_DELAYED_WORK(&sc->force_detect_dwork, sc8989x_force_detection_dwork_handler); sc->cfg = &sc8989x_default_cfg; ret = sc8989x_parse_dt(sc); if (ret < 0) { dev_err(sc->dev, "parse dt fail(%d)\n", ret); goto err_parse_dt; } mutex_init(&sc->request_dpdm_lock); ret = sc8989x_init_device(sc); if (ret < 0) { dev_err(sc->dev, "init device fail(%d)\n", ret); goto err_init_dev; } ret = sc8989x_psy_register(sc); if (ret) { dev_err(sc->dev, "%s psy register fail(%d)\n", __func__, ret); goto err_psy; } ret = sc8989x_register_interrupt(sc); if (ret < 0) { dev_err(sc->dev, "%s register irq fail(%d)\n", __func__, ret); goto err_register_irq; } mutex_init(&sc->attach_lock); atomic_set(&sc->attach, 0); sc->wq = create_singlethread_workqueue(dev_name(sc->dev)); if (!sc->wq) { pr_err( "failed to create workqueue\n"); ret = -ENOMEM; goto err_wq; } INIT_WORK(&sc->bc12_work, sc8989x_chg_bc12_work_func); #ifdef CONFIG_MTK_CLASS INIT_DELAYED_WORK(&sc->psy_dwork, sc8989x_inform_psy_dwork_handler); /* Register charger device */ sc->chg_dev = charger_device_register(sc->cfg->chg_name, sc->dev, sc, &sc8989x_chg_ops, &sc8989x_chg_props); if (IS_ERR_OR_NULL(sc->chg_dev)) { ret = PTR_ERR(sc->chg_dev); dev_notice(sc->dev, "%s register chg dev fail(%d)\n", __func__, ret); goto err_register_chg_dev; } #endif /*CONFIG_MTK_CLASS */ device_init_wakeup(sc->dev, 1); /* otg regulator */ config.dev = sc->dev; config.regmap = sc->regmap; sc->otg_rdev = devm_regulator_register(sc->dev, &sc8989x_otg_rdesc, &config); if (IS_ERR(sc->otg_rdev)) return PTR_ERR(sc->otg_rdev); determine_initial_status(sc); sc8989x_dump_register(sc); sc8989x_chg_pwr_rdy_process(sc); dev_info(sc->dev, "sc8989x probe successfully\n!"); return 0; err_register_irq: #ifdef CONFIG_MTK_CLASS err_register_chg_dev: #endif /*CONFIG_MTK_CLASS */ err_psy: err_init_dev: err_parse_dt: err_nodev: err_wq: dev_err(sc->dev, "sc8989x probe failed!\n"); devm_kfree(&client->dev, sc); return -ENODEV; } static int sc8989x_charger_remove(struct i2c_client *client) { struct sc8989x_chip *sc = i2c_get_clientdata(client); if (sc) { dev_info(sc->dev, "%s\n", __func__); #ifdef CONFIG_MTK_CLASS charger_device_unregister(sc->chg_dev); #endif /*CONFIG_MTK_CLASS */ power_supply_put(sc->psy); } return 0; } #ifdef CONFIG_PM_SLEEP static int sc8989x_suspend(struct device *dev) { struct sc8989x_chip *sc = dev_get_drvdata(dev); dev_info(dev, "%s\n", __func__); if (device_may_wakeup(dev)) enable_irq_wake(sc->irq); disable_irq(sc->irq); return 0; } static int sc8989x_resume(struct device *dev) { struct sc8989x_chip *sc = dev_get_drvdata(dev); dev_info(dev, "%s\n", __func__); enable_irq(sc->irq); if (device_may_wakeup(dev)) disable_irq_wake(sc->irq); return 0; } static const struct dev_pm_ops sc8989x_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(sc8989x_suspend, sc8989x_resume) }; #endif /* CONFIG_PM_SLEEP */ static struct i2c_driver sc8989x_charger_driver = { .driver = { .name = "sc8989x", .owner = THIS_MODULE, .of_match_table = of_match_ptr(sc8989x_of_device_id), #ifdef CONFIG_PM_SLEEP .pm = &sc8989x_pm_ops, #endif }, .probe = sc8989x_charger_probe, .remove = sc8989x_charger_remove, }; module_i2c_driver(sc8989x_charger_driver); MODULE_DESCRIPTION("SC SC8989X Charger Driver"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("South Chip ");