Loading Documentation/devicetree/bindings/power/supply/qcom/smb1355-charger.txt +12 −0 Original line number Diff line number Diff line Loading @@ -51,6 +51,18 @@ Charger specific properties: stacked one after the other and thus all the charge current (FCC) flows through main. In a non-stacked configuration each charger controls the charge current (FCC) separately. - qcom,die-temp-threshold-degc Usage: optional Value type: <u32> Definition: Specifies DIE temp threshold beyond which h/w starts mitigation. If not sepcified, 90 degrees centigrade is used. - qcom,hw-die-temp-mitigation Usage: optional Value type: bool Definition: Boolean property to enable h/w controlled die temp mitigation. ================================================ Second Level Nodes - SMB1355 Charger Peripherals ================================================ Loading drivers/power/supply/qcom/battery.c +103 −31 Original line number Diff line number Diff line /* Copyright (c) 2017 The Linux Foundation. All rights reserved. /* Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -47,6 +47,7 @@ struct pl_data { int pl_mode; int pl_batfet_mode; int slave_pct; int slave_fcc_ua; int restricted_current; Loading Loading @@ -155,12 +156,22 @@ static void split_settled(struct pl_data *chip) total_current_ua = pval.intval; } /* * If there is an increase in slave share * (Also handles parallel enable case) * Set Main ICL then slave ICL * else * (Also handles parallel disable case) * Set slave ICL then main ICL. */ if (slave_ua > chip->pl_settled_ua) { pval.intval = total_current_ua - slave_ua; /* Set ICL on main charger */ rc = power_supply_set_property(chip->main_psy, POWER_SUPPLY_PROP_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Couldn't change slave suspend state rc=%d\n", rc); pr_err("Couldn't change slave suspend state rc=%d\n", rc); return; } Loading @@ -172,6 +183,26 @@ static void split_settled(struct pl_data *chip) pr_err("Couldn't set parallel icl, rc=%d\n", rc); return; } } else { /* set parallel's ICL could be 0mA when pl is disabled */ pval.intval = slave_ua; rc = power_supply_set_property(chip->pl_psy, POWER_SUPPLY_PROP_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Couldn't set parallel icl, rc=%d\n", rc); return; } pval.intval = total_current_ua - slave_ua; /* Set ICL on main charger */ rc = power_supply_set_property(chip->main_psy, POWER_SUPPLY_PROP_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Couldn't change slave suspend state rc=%d\n", rc); return; } } chip->total_settled_ua = total_settled_ua; chip->pl_settled_ua = slave_ua; Loading Loading @@ -345,11 +376,11 @@ static void get_fcc_split(struct pl_data *chip, int total_ua, *slave_ua = (slave_limited_ua * chip->slave_pct) / 100; /* * In USBIN_USBIN configuration with internal rsense parallel * charger's current goes through main charger's BATFET, keep * the main charger's FCC to the votable result. * In stacked BATFET configuration charger's current goes * through main charger's BATFET, keep the main charger's FCC * to the votable result. */ if (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) if (chip->pl_batfet_mode == POWER_SUPPLY_PL_STACKED_BATFET) *master_ua = max(0, total_ua); else *master_ua = max(0, total_ua - *slave_ua); Loading Loading @@ -634,8 +665,15 @@ static int pl_disable_vote_callback(struct votable *votable, get_fcc_split(chip, total_fcc_ua, &master_fcc_ua, &slave_fcc_ua); chip->slave_fcc_ua = slave_fcc_ua; /* * If there is an increase in slave share * (Also handles parallel enable case) * Set Main ICL then slave FCC * else * (Also handles parallel disable case) * Set slave ICL then main FCC. */ if (slave_fcc_ua > chip->slave_fcc_ua) { pval.intval = master_fcc_ua; rc = power_supply_set_property(chip->main_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, Loading @@ -650,9 +688,34 @@ static int pl_disable_vote_callback(struct votable *votable, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Couldn't set parallel fcc, rc=%d\n", rc); pr_err("Couldn't set parallel fcc, rc=%d\n", rc); return rc; } chip->slave_fcc_ua = slave_fcc_ua; } else { pval.intval = slave_fcc_ua; rc = power_supply_set_property(chip->pl_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Couldn't set parallel fcc, rc=%d\n", rc); return rc; } chip->slave_fcc_ua = slave_fcc_ua; pval.intval = master_fcc_ua; rc = power_supply_set_property(chip->main_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Could not set main fcc, rc=%d\n", rc); return rc; } } /* * Enable will be called with a valid pl_psy always. The Loading Loading @@ -806,6 +869,15 @@ static bool is_parallel_available(struct pl_data *chip) return false; } rc = power_supply_get_property(chip->pl_psy, POWER_SUPPLY_PROP_PARALLEL_BATFET_MODE, &pval); if (rc < 0) { pr_err("Couldn't get parallel batfet mode rc=%d\n", rc); return false; } chip->pl_batfet_mode = pval.intval; vote(chip->pl_disable_votable, PARALLEL_PSY_VOTER, false, 0); return true; Loading drivers/power/supply/qcom/smb1355-charger.c +274 −30 Original line number Diff line number Diff line Loading @@ -28,16 +28,21 @@ #include <linux/power_supply.h> #include <linux/workqueue.h> #include <linux/pmic-voter.h> #include <linux/string.h> /* SMB1355 registers, different than mentioned in smb-reg.h */ #define REVID_BASE 0x0100 #define I2C_SS_DIG_BASE 0x0E00 #define CHGR_BASE 0x1000 #define ANA2_BASE 0x1100 #define BATIF_BASE 0x1200 #define USBIN_BASE 0x1300 #define ANA1_BASE 0x1400 #define MISC_BASE 0x1600 #define REVID_MFG_ID_SPARE_REG (REVID_BASE + 0xFF) #define I2C_SS_DIG_PMIC_SID_REG (I2C_SS_DIG_BASE + 0x45) #define PMIC_SID_MASK GENMASK(3, 0) #define PMIC_SID0_BIT BIT(0) Loading Loading @@ -80,28 +85,38 @@ #define BATIF_CFG_SMISC_BATID_REG (BATIF_BASE + 0x73) #define CFG_SMISC_RBIAS_EXT_CTRL_BIT BIT(2) #define SMB2CHGS_BATIF_ENG_SMISC_DIETEMP (BATIF_BASE + 0xC0) #define SMB2CHG_BATIF_ENG_SMISC_DIETEMP (BATIF_BASE + 0xC0) #define TDIE_COMPARATOR_THRESHOLD GENMASK(5, 0) #define DIE_LOW_RANGE_BASE_DEGC 34 #define DIE_LOW_RANGE_DELTA 16 #define DIE_LOW_RANGE_MAX_DEGC 97 #define DIE_LOW_RANGE_SHIFT 4 #define BATIF_ENG_SCMISC_SPARE1_REG (BATIF_BASE + 0xC2) #define EXT_BIAS_PIN_BIT BIT(2) #define DIE_TEMP_COMP_HYST_BIT BIT(1) #define ANA1_ENG_SREFGEN_CFG2_REG (ANA1_BASE + 0xC1) #define VALLEY_COMPARATOR_EN_BIT BIT(0) #define TEMP_COMP_STATUS_REG (MISC_BASE + 0x07) #define SKIN_TEMP_RST_HOT_BIT BIT(6) #define SKIN_TEMP_UB_HOT_BIT BIT(5) #define SKIN_TEMP_LB_HOT_BIT BIT(4) #define DIE_TEMP_TSD_HOT_BIT BIT(3) #define DIE_TEMP_RST_HOT_BIT BIT(2) #define DIE_TEMP_UB_HOT_BIT BIT(1) #define DIE_TEMP_LB_HOT_BIT BIT(0) #define TEMP_RST_HOT_BIT BIT(2) #define TEMP_UB_HOT_BIT BIT(1) #define TEMP_LB_HOT_BIT BIT(0) #define SKIN_TEMP_SHIFT 4 #define MISC_RT_STS_REG (MISC_BASE + 0x10) #define HARD_ILIMIT_RT_STS_BIT BIT(5) #define BANDGAP_ENABLE_REG (MISC_BASE + 0x42) #define BANDGAP_ENABLE_CMD_BIT BIT(0) #define BARK_BITE_WDOG_PET_REG (MISC_BASE + 0x43) #define BARK_BITE_WDOG_PET_BIT BIT(0) #define CLOCK_REQUEST_REG (MISC_BASE + 0x44) #define CLOCK_REQUEST_CMD_BIT BIT(0) #define WD_CFG_REG (MISC_BASE + 0x51) #define WATCHDOG_TRIGGER_AFP_EN_BIT BIT(7) #define BARK_WDOG_INT_EN_BIT BIT(6) Loading @@ -113,6 +128,10 @@ #define MISC_CUST_SDCDC_CLK_CFG_REG (MISC_BASE + 0xA0) #define SWITCHER_CLK_FREQ_MASK GENMASK(3, 0) #define MISC_CUST_SDCDC_ILIMIT_CFG_REG (MISC_BASE + 0xA1) #define LS_VALLEY_THRESH_PCT_BIT BIT(3) #define PCL_LIMIT_MASK GENMASK(1, 0) #define SNARL_BARK_BITE_WD_CFG_REG (MISC_BASE + 0x53) #define BITE_WDOG_DISABLE_CHARGING_CFG_BIT BIT(7) #define SNARL_WDOG_TIMEOUT_MASK GENMASK(6, 4) Loading Loading @@ -155,6 +174,8 @@ ((mode == POWER_SUPPLY_PL_USBIN_USBIN) \ || (mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) #define PARALLEL_ENABLE_VOTER "PARALLEL_ENABLE_VOTER" struct smb_chg_param { const char *name; u16 reg; Loading Loading @@ -204,6 +225,8 @@ struct smb_dt_props { bool disable_ctm; int pl_mode; int pl_batfet_mode; bool hw_die_temp_mitigation; u32 die_temp_threshold; }; struct smb1355 { Loading @@ -211,6 +234,8 @@ struct smb1355 { char *name; struct regmap *regmap; int max_fcc; struct smb_dt_props dt; struct smb_params param; Loading @@ -225,10 +250,20 @@ struct smb1355 { bool exit_die_temp; struct delayed_work die_temp_work; bool disabled; struct votable *irq_disable_votable; }; enum { CONNECTOR_TEMP = 0, DIE_TEMP, }; static bool is_secure(struct smb1355 *chip, int addr) { if (addr == CLOCK_REQUEST_REG) return true; /* assume everything above 0xA0 is secure */ return (addr & 0xFF) >= 0xA0; } Loading @@ -245,6 +280,25 @@ static int smb1355_read(struct smb1355 *chip, u16 addr, u8 *val) return rc; } static int smb1355_masked_force_write(struct smb1355 *chip, u16 addr, u8 mask, u8 val) { int rc; mutex_lock(&chip->write_lock); if (is_secure(chip, addr)) { rc = regmap_write(chip->regmap, (addr & 0xFF00) | 0xD0, 0xA5); if (rc < 0) goto unlock; } rc = regmap_write_bits(chip->regmap, addr, mask, val); unlock: mutex_unlock(&chip->write_lock); return rc; } static int smb1355_masked_write(struct smb1355 *chip, u16 addr, u8 mask, u8 val) { int rc; Loading Loading @@ -334,8 +388,7 @@ static void die_temp_work(struct work_struct *work) u8 temp_stat; for (i = 0; i < BIT(5); i++) { rc = smb1355_masked_write(chip, SMB2CHGS_BATIF_ENG_SMISC_DIETEMP, rc = smb1355_masked_write(chip, SMB2CHG_BATIF_ENG_SMISC_DIETEMP, TDIE_COMPARATOR_THRESHOLD, i); if (rc < 0) { pr_err("Couldn't set temp comp threshold rc=%d\n", rc); Loading @@ -354,7 +407,7 @@ static void die_temp_work(struct work_struct *work) continue; } if (!(temp_stat & DIE_TEMP_UB_HOT_BIT)) { if (!(temp_stat & TEMP_UB_HOT_BIT)) { /* found the temp */ break; } Loading Loading @@ -420,6 +473,7 @@ static int smb1355_determine_initial_status(struct smb1355 *chip) return 0; } #define DEFAULT_DIE_TEMP_LOW_THRESHOLD 90 static int smb1355_parse_dt(struct smb1355 *chip) { struct device_node *node = chip->dev->of_node; Loading Loading @@ -450,6 +504,15 @@ static int smb1355_parse_dt(struct smb1355 *chip) if (of_property_read_bool(node, "qcom,stacked-batfet")) chip->dt.pl_batfet_mode = POWER_SUPPLY_PL_STACKED_BATFET; chip->dt.hw_die_temp_mitigation = of_property_read_bool(node, "qcom,hw-die-temp-mitigation"); chip->dt.die_temp_threshold = DEFAULT_DIE_TEMP_LOW_THRESHOLD; of_property_read_u32(node, "qcom,die-temp-threshold-degc", &chip->dt.die_temp_threshold); if (chip->dt.die_temp_threshold > DIE_LOW_RANGE_MAX_DEGC) chip->dt.die_temp_threshold = DIE_LOW_RANGE_MAX_DEGC; return 0; } Loading @@ -470,9 +533,12 @@ static enum power_supply_property smb1355_parallel_props[] = { POWER_SUPPLY_PROP_PARALLEL_MODE, POWER_SUPPLY_PROP_CONNECTOR_HEALTH, POWER_SUPPLY_PROP_PARALLEL_BATFET_MODE, POWER_SUPPLY_PROP_PARALLEL_FCC_MAX, POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED, POWER_SUPPLY_PROP_MIN_ICL, POWER_SUPPLY_PROP_CURRENT_MAX, POWER_SUPPLY_PROP_SET_SHIP_MODE, POWER_SUPPLY_PROP_DIE_HEALTH, }; static int smb1355_get_prop_batt_charge_type(struct smb1355 *chip, Loading @@ -499,10 +565,13 @@ static int smb1355_get_prop_batt_charge_type(struct smb1355 *chip, return rc; } static int smb1355_get_prop_connector_health(struct smb1355 *chip) static int smb1355_get_prop_health(struct smb1355 *chip, int type) { u8 temp; int rc; int rc, shift; /* Connector-temp uses skin-temp configuration */ shift = (type == CONNECTOR_TEMP) ? SKIN_TEMP_SHIFT : 0; rc = smb1355_read(chip, TEMP_COMP_STATUS_REG, &temp); if (rc < 0) { Loading @@ -510,13 +579,13 @@ static int smb1355_get_prop_connector_health(struct smb1355 *chip) return POWER_SUPPLY_HEALTH_UNKNOWN; } if (temp & SKIN_TEMP_RST_HOT_BIT) if (temp & (TEMP_RST_HOT_BIT << shift)) return POWER_SUPPLY_HEALTH_OVERHEAT; if (temp & SKIN_TEMP_UB_HOT_BIT) if (temp & (TEMP_UB_HOT_BIT << shift)) return POWER_SUPPLY_HEALTH_HOT; if (temp & SKIN_TEMP_LB_HOT_BIT) if (temp & (TEMP_LB_HOT_BIT << shift)) return POWER_SUPPLY_HEALTH_WARM; return POWER_SUPPLY_HEALTH_COOL; Loading Loading @@ -549,6 +618,16 @@ static int smb1355_parallel_get_prop(struct power_supply *psy, val->intval = chip->die_temp_deciDegC; break; case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX: /* * In case of h/w controlled die_temp mitigation, * die_temp/die_temp_max can not be reported as this * requires run time manipulation of DIE_TEMP low * threshold which will interfere with h/w mitigation * scheme. */ if (chip->dt.hw_die_temp_mitigation) val->intval = -EINVAL; else val->intval = chip->c_charger_temp_max; break; case POWER_SUPPLY_PROP_INPUT_SUSPEND: Loading @@ -570,10 +649,14 @@ static int smb1355_parallel_get_prop(struct power_supply *psy, break; case POWER_SUPPLY_PROP_CONNECTOR_HEALTH: if (chip->c_health == -EINVAL) val->intval = smb1355_get_prop_connector_health(chip); val->intval = smb1355_get_prop_health(chip, CONNECTOR_TEMP); else val->intval = chip->c_health; break; case POWER_SUPPLY_PROP_DIE_HEALTH: val->intval = smb1355_get_prop_health(chip, DIE_TEMP); break; case POWER_SUPPLY_PROP_PARALLEL_BATFET_MODE: val->intval = chip->dt.pl_batfet_mode; break; Loading @@ -593,6 +676,13 @@ static int smb1355_parallel_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_MIN_ICL: val->intval = MIN_PARALLEL_ICL_UA; break; case POWER_SUPPLY_PROP_PARALLEL_FCC_MAX: val->intval = chip->max_fcc; break; case POWER_SUPPLY_PROP_SET_SHIP_MODE: /* Not in ship mode as long as device is active */ val->intval = 0; break; default: pr_err_ratelimited("parallel psy get prop %d not supported\n", prop); Loading Loading @@ -636,6 +726,8 @@ static int smb1355_set_parallel_charging(struct smb1355 *chip, bool disable) } chip->die_temp_deciDegC = -EINVAL; /* Only enable temperature measurement for s/w based mitigation */ if (!chip->dt.hw_die_temp_mitigation) { if (disable) { chip->exit_die_temp = true; cancel_delayed_work_sync(&chip->die_temp_work); Loading @@ -644,6 +736,19 @@ static int smb1355_set_parallel_charging(struct smb1355 *chip, bool disable) chip->exit_die_temp = false; schedule_delayed_work(&chip->die_temp_work, 0); } } if (chip->irq_disable_votable) vote(chip->irq_disable_votable, PARALLEL_ENABLE_VOTER, disable, 0); rc = smb1355_masked_write(chip, BANDGAP_ENABLE_REG, BANDGAP_ENABLE_CMD_BIT, disable ? 0 : BANDGAP_ENABLE_CMD_BIT); if (rc < 0) { pr_err("Couldn't configure bandgap enable rc=%d\n", rc); return rc; } chip->disabled = disable; Loading Loading @@ -672,6 +777,20 @@ static int smb1355_set_current_max(struct smb1355 *chip, int curr) return rc; } static int smb1355_clk_request(struct smb1355 *chip, bool enable) { int rc; rc = smb1355_masked_force_write(chip, CLOCK_REQUEST_REG, CLOCK_REQUEST_CMD_BIT, enable ? CLOCK_REQUEST_CMD_BIT : 0); if (rc < 0) pr_err("Couldn't %s clock rc=%d\n", enable ? "enable" : "disable", rc); return rc; } static int smb1355_parallel_set_prop(struct power_supply *psy, enum power_supply_property prop, const union power_supply_propval *val) Loading Loading @@ -700,6 +819,10 @@ static int smb1355_parallel_set_prop(struct power_supply *psy, break; case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX: chip->c_charger_temp_max = val->intval; case POWER_SUPPLY_PROP_SET_SHIP_MODE: if (!val->intval) break; rc = smb1355_clk_request(chip, false); break; default: pr_debug("parallel power supply set prop %d not supported\n", Loading Loading @@ -758,6 +881,38 @@ static int smb1355_init_parallel_psy(struct smb1355 *chip) * HARDWARE INITIALIZATION * ***************************/ #define MFG_ID_SMB1354 0x01 #define MFG_ID_SMB1355 0xFF #define SMB1354_MAX_PARALLEL_FCC_UA 2500000 #define SMB1355_MAX_PARALLEL_FCC_UA 6000000 static int smb1355_detect_version(struct smb1355 *chip) { int rc; u8 val; rc = smb1355_read(chip, REVID_MFG_ID_SPARE_REG, &val); if (rc < 0) { pr_err("Unable to read REVID rc=%d\n", rc); return rc; } switch (val) { case MFG_ID_SMB1354: chip->name = "smb1354"; chip->max_fcc = SMB1354_MAX_PARALLEL_FCC_UA; break; case MFG_ID_SMB1355: chip->name = "smb1355"; chip->max_fcc = SMB1355_MAX_PARALLEL_FCC_UA; break; default: pr_err("Invalid value of REVID val=%d", val); return -EINVAL; } return rc; } static int smb1355_tskin_sensor_config(struct smb1355 *chip) { int rc; Loading Loading @@ -847,6 +1002,12 @@ static int smb1355_tskin_sensor_config(struct smb1355 *chip) static int smb1355_init_hw(struct smb1355 *chip) { int rc; u8 val, range; /* request clock always on */ rc = smb1355_clk_request(chip, true); if (rc < 0) return rc; /* Change to let SMB1355 only respond to address 0x0C */ rc = smb1355_masked_write(chip, I2C_SS_DIG_PMIC_SID_REG, Loading Loading @@ -918,13 +1079,35 @@ static int smb1355_init_hw(struct smb1355 *chip) return rc; } /* Configure DIE temp Low threshold */ if (chip->dt.hw_die_temp_mitigation) { range = (chip->dt.die_temp_threshold - DIE_LOW_RANGE_BASE_DEGC) / (DIE_LOW_RANGE_DELTA); val = (chip->dt.die_temp_threshold - ((range * DIE_LOW_RANGE_DELTA) + DIE_LOW_RANGE_BASE_DEGC)) % DIE_LOW_RANGE_DELTA; rc = smb1355_masked_write(chip, SMB2CHG_BATIF_ENG_SMISC_DIETEMP, TDIE_COMPARATOR_THRESHOLD, (range << DIE_LOW_RANGE_SHIFT) | val); if (rc < 0) { pr_err("Couldn't set temp comp threshold rc=%d\n", rc); return rc; } } /* * Enable thermal Die temperature comparator source and disable hw * mitigation for skin/die * Enable thermal Die temperature comparator source and * enable hardware controlled current adjustment for die temp * if charger is configured in h/w controlled die temp mitigation. */ val = THERMREG_DIE_CMP_SRC_EN_BIT; if (!chip->dt.hw_die_temp_mitigation) val |= BYP_THERM_CHG_CURR_ADJUST_BIT; rc = smb1355_masked_write(chip, MISC_THERMREG_SRC_CFG_REG, THERMREG_DIE_CMP_SRC_EN_BIT | BYP_THERM_CHG_CURR_ADJUST_BIT, THERMREG_DIE_CMP_SRC_EN_BIT | BYP_THERM_CHG_CURR_ADJUST_BIT); val); if (rc < 0) { pr_err("Couldn't set Skin temperature comparator src rc=%d\n", rc); Loading @@ -935,13 +1118,40 @@ static int smb1355_init_hw(struct smb1355 *chip) * Disable hysterisis for die temperature. This is so that sw can run * stepping scheme quickly */ val = chip->dt.hw_die_temp_mitigation ? DIE_TEMP_COMP_HYST_BIT : 0; rc = smb1355_masked_write(chip, BATIF_ENG_SCMISC_SPARE1_REG, DIE_TEMP_COMP_HYST_BIT, 0); DIE_TEMP_COMP_HYST_BIT, val); if (rc < 0) { pr_err("Couldn't disable hyst. for die rc=%d\n", rc); return rc; } /* Enable valley current comparator all the time */ rc = smb1355_masked_write(chip, ANA1_ENG_SREFGEN_CFG2_REG, VALLEY_COMPARATOR_EN_BIT, VALLEY_COMPARATOR_EN_BIT); if (rc < 0) { pr_err("Couldn't enable valley current comparator rc=%d\n", rc); return rc; } /* Set LS_VALLEY threshold to 85% */ rc = smb1355_masked_write(chip, MISC_CUST_SDCDC_ILIMIT_CFG_REG, LS_VALLEY_THRESH_PCT_BIT, LS_VALLEY_THRESH_PCT_BIT); if (rc < 0) { pr_err("Couldn't set LS valley threshold to 85pc rc=%d\n", rc); return rc; } /* For SMB1354, set PCL to 8.6 A */ if (!strcmp(chip->name, "smb1354")) { rc = smb1355_masked_write(chip, MISC_CUST_SDCDC_ILIMIT_CFG_REG, PCL_LIMIT_MASK, PCL_LIMIT_MASK); if (rc < 0) { pr_err("Couldn't set PCL limit to 8.6A rc=%d\n", rc); return rc; } } rc = smb1355_tskin_sensor_config(chip); if (rc < 0) { pr_err("Couldn't configure tskin regs rc=%d\n", rc); Loading Loading @@ -1079,6 +1289,7 @@ static int smb1355_request_interrupt(struct smb1355 *chip, return rc; } smb1355_irqs[irq_index].irq = irq; if (smb1355_irqs[irq_index].wake) enable_irq_wake(irq); Loading Loading @@ -1107,6 +1318,23 @@ static int smb1355_request_interrupts(struct smb1355 *chip) return rc; } static int smb1355_irq_disable_callback(struct votable *votable, void *data, int disable, const char *client) { int i; for (i = 0; i < ARRAY_SIZE(smb1355_irqs); i++) { if (smb1355_irqs[i].irq) { if (disable) disable_irq(smb1355_irqs[i].irq); else enable_irq(smb1355_irqs[i].irq); } } return 0; } /********* * PROBE * Loading @@ -1132,7 +1360,6 @@ static int smb1355_probe(struct platform_device *pdev) chip->param = v1_params; chip->c_health = -EINVAL; chip->c_charger_temp_max = -EINVAL; chip->name = "smb1355"; mutex_init(&chip->write_lock); INIT_DELAYED_WORK(&chip->die_temp_work, die_temp_work); chip->disabled = true; Loading @@ -1150,6 +1377,12 @@ static int smb1355_probe(struct platform_device *pdev) return -ENODEV; } rc = smb1355_detect_version(chip); if (rc < 0) { pr_err("Couldn't detect SMB1355/1354 chip type rc=%d\n", rc); goto cleanup; } platform_set_drvdata(pdev, chip); rc = smb1355_parse_dt(chip); Loading Loading @@ -1183,6 +1416,15 @@ static int smb1355_probe(struct platform_device *pdev) goto cleanup; } chip->irq_disable_votable = create_votable("SMB1355_IRQ_DISABLE", VOTE_SET_ANY, smb1355_irq_disable_callback, chip); if (IS_ERR(chip->irq_disable_votable)) { rc = PTR_ERR(chip->irq_disable_votable); goto cleanup; } /* keep IRQ's disabled until parallel is enabled */ vote(chip->irq_disable_votable, PARALLEL_ENABLE_VOTER, true, 0); pr_info("%s probed successfully pl_mode=%s batfet_mode=%s\n", chip->name, IS_USBIN(chip->dt.pl_mode) ? "USBIN-USBIN" : "USBMID-USBMID", Loading Loading @@ -1210,6 +1452,8 @@ static void smb1355_shutdown(struct platform_device *pdev) rc = smb1355_set_parallel_charging(chip, true); if (rc < 0) pr_err("Couldn't disable parallel path rc=%d\n", rc); smb1355_clk_request(chip, false); } static struct platform_driver smb1355_driver = { Loading Loading
Documentation/devicetree/bindings/power/supply/qcom/smb1355-charger.txt +12 −0 Original line number Diff line number Diff line Loading @@ -51,6 +51,18 @@ Charger specific properties: stacked one after the other and thus all the charge current (FCC) flows through main. In a non-stacked configuration each charger controls the charge current (FCC) separately. - qcom,die-temp-threshold-degc Usage: optional Value type: <u32> Definition: Specifies DIE temp threshold beyond which h/w starts mitigation. If not sepcified, 90 degrees centigrade is used. - qcom,hw-die-temp-mitigation Usage: optional Value type: bool Definition: Boolean property to enable h/w controlled die temp mitigation. ================================================ Second Level Nodes - SMB1355 Charger Peripherals ================================================ Loading
drivers/power/supply/qcom/battery.c +103 −31 Original line number Diff line number Diff line /* Copyright (c) 2017 The Linux Foundation. All rights reserved. /* Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -47,6 +47,7 @@ struct pl_data { int pl_mode; int pl_batfet_mode; int slave_pct; int slave_fcc_ua; int restricted_current; Loading Loading @@ -155,12 +156,22 @@ static void split_settled(struct pl_data *chip) total_current_ua = pval.intval; } /* * If there is an increase in slave share * (Also handles parallel enable case) * Set Main ICL then slave ICL * else * (Also handles parallel disable case) * Set slave ICL then main ICL. */ if (slave_ua > chip->pl_settled_ua) { pval.intval = total_current_ua - slave_ua; /* Set ICL on main charger */ rc = power_supply_set_property(chip->main_psy, POWER_SUPPLY_PROP_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Couldn't change slave suspend state rc=%d\n", rc); pr_err("Couldn't change slave suspend state rc=%d\n", rc); return; } Loading @@ -172,6 +183,26 @@ static void split_settled(struct pl_data *chip) pr_err("Couldn't set parallel icl, rc=%d\n", rc); return; } } else { /* set parallel's ICL could be 0mA when pl is disabled */ pval.intval = slave_ua; rc = power_supply_set_property(chip->pl_psy, POWER_SUPPLY_PROP_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Couldn't set parallel icl, rc=%d\n", rc); return; } pval.intval = total_current_ua - slave_ua; /* Set ICL on main charger */ rc = power_supply_set_property(chip->main_psy, POWER_SUPPLY_PROP_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Couldn't change slave suspend state rc=%d\n", rc); return; } } chip->total_settled_ua = total_settled_ua; chip->pl_settled_ua = slave_ua; Loading Loading @@ -345,11 +376,11 @@ static void get_fcc_split(struct pl_data *chip, int total_ua, *slave_ua = (slave_limited_ua * chip->slave_pct) / 100; /* * In USBIN_USBIN configuration with internal rsense parallel * charger's current goes through main charger's BATFET, keep * the main charger's FCC to the votable result. * In stacked BATFET configuration charger's current goes * through main charger's BATFET, keep the main charger's FCC * to the votable result. */ if (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) if (chip->pl_batfet_mode == POWER_SUPPLY_PL_STACKED_BATFET) *master_ua = max(0, total_ua); else *master_ua = max(0, total_ua - *slave_ua); Loading Loading @@ -634,8 +665,15 @@ static int pl_disable_vote_callback(struct votable *votable, get_fcc_split(chip, total_fcc_ua, &master_fcc_ua, &slave_fcc_ua); chip->slave_fcc_ua = slave_fcc_ua; /* * If there is an increase in slave share * (Also handles parallel enable case) * Set Main ICL then slave FCC * else * (Also handles parallel disable case) * Set slave ICL then main FCC. */ if (slave_fcc_ua > chip->slave_fcc_ua) { pval.intval = master_fcc_ua; rc = power_supply_set_property(chip->main_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, Loading @@ -650,9 +688,34 @@ static int pl_disable_vote_callback(struct votable *votable, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Couldn't set parallel fcc, rc=%d\n", rc); pr_err("Couldn't set parallel fcc, rc=%d\n", rc); return rc; } chip->slave_fcc_ua = slave_fcc_ua; } else { pval.intval = slave_fcc_ua; rc = power_supply_set_property(chip->pl_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Couldn't set parallel fcc, rc=%d\n", rc); return rc; } chip->slave_fcc_ua = slave_fcc_ua; pval.intval = master_fcc_ua; rc = power_supply_set_property(chip->main_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Could not set main fcc, rc=%d\n", rc); return rc; } } /* * Enable will be called with a valid pl_psy always. The Loading Loading @@ -806,6 +869,15 @@ static bool is_parallel_available(struct pl_data *chip) return false; } rc = power_supply_get_property(chip->pl_psy, POWER_SUPPLY_PROP_PARALLEL_BATFET_MODE, &pval); if (rc < 0) { pr_err("Couldn't get parallel batfet mode rc=%d\n", rc); return false; } chip->pl_batfet_mode = pval.intval; vote(chip->pl_disable_votable, PARALLEL_PSY_VOTER, false, 0); return true; Loading
drivers/power/supply/qcom/smb1355-charger.c +274 −30 Original line number Diff line number Diff line Loading @@ -28,16 +28,21 @@ #include <linux/power_supply.h> #include <linux/workqueue.h> #include <linux/pmic-voter.h> #include <linux/string.h> /* SMB1355 registers, different than mentioned in smb-reg.h */ #define REVID_BASE 0x0100 #define I2C_SS_DIG_BASE 0x0E00 #define CHGR_BASE 0x1000 #define ANA2_BASE 0x1100 #define BATIF_BASE 0x1200 #define USBIN_BASE 0x1300 #define ANA1_BASE 0x1400 #define MISC_BASE 0x1600 #define REVID_MFG_ID_SPARE_REG (REVID_BASE + 0xFF) #define I2C_SS_DIG_PMIC_SID_REG (I2C_SS_DIG_BASE + 0x45) #define PMIC_SID_MASK GENMASK(3, 0) #define PMIC_SID0_BIT BIT(0) Loading Loading @@ -80,28 +85,38 @@ #define BATIF_CFG_SMISC_BATID_REG (BATIF_BASE + 0x73) #define CFG_SMISC_RBIAS_EXT_CTRL_BIT BIT(2) #define SMB2CHGS_BATIF_ENG_SMISC_DIETEMP (BATIF_BASE + 0xC0) #define SMB2CHG_BATIF_ENG_SMISC_DIETEMP (BATIF_BASE + 0xC0) #define TDIE_COMPARATOR_THRESHOLD GENMASK(5, 0) #define DIE_LOW_RANGE_BASE_DEGC 34 #define DIE_LOW_RANGE_DELTA 16 #define DIE_LOW_RANGE_MAX_DEGC 97 #define DIE_LOW_RANGE_SHIFT 4 #define BATIF_ENG_SCMISC_SPARE1_REG (BATIF_BASE + 0xC2) #define EXT_BIAS_PIN_BIT BIT(2) #define DIE_TEMP_COMP_HYST_BIT BIT(1) #define ANA1_ENG_SREFGEN_CFG2_REG (ANA1_BASE + 0xC1) #define VALLEY_COMPARATOR_EN_BIT BIT(0) #define TEMP_COMP_STATUS_REG (MISC_BASE + 0x07) #define SKIN_TEMP_RST_HOT_BIT BIT(6) #define SKIN_TEMP_UB_HOT_BIT BIT(5) #define SKIN_TEMP_LB_HOT_BIT BIT(4) #define DIE_TEMP_TSD_HOT_BIT BIT(3) #define DIE_TEMP_RST_HOT_BIT BIT(2) #define DIE_TEMP_UB_HOT_BIT BIT(1) #define DIE_TEMP_LB_HOT_BIT BIT(0) #define TEMP_RST_HOT_BIT BIT(2) #define TEMP_UB_HOT_BIT BIT(1) #define TEMP_LB_HOT_BIT BIT(0) #define SKIN_TEMP_SHIFT 4 #define MISC_RT_STS_REG (MISC_BASE + 0x10) #define HARD_ILIMIT_RT_STS_BIT BIT(5) #define BANDGAP_ENABLE_REG (MISC_BASE + 0x42) #define BANDGAP_ENABLE_CMD_BIT BIT(0) #define BARK_BITE_WDOG_PET_REG (MISC_BASE + 0x43) #define BARK_BITE_WDOG_PET_BIT BIT(0) #define CLOCK_REQUEST_REG (MISC_BASE + 0x44) #define CLOCK_REQUEST_CMD_BIT BIT(0) #define WD_CFG_REG (MISC_BASE + 0x51) #define WATCHDOG_TRIGGER_AFP_EN_BIT BIT(7) #define BARK_WDOG_INT_EN_BIT BIT(6) Loading @@ -113,6 +128,10 @@ #define MISC_CUST_SDCDC_CLK_CFG_REG (MISC_BASE + 0xA0) #define SWITCHER_CLK_FREQ_MASK GENMASK(3, 0) #define MISC_CUST_SDCDC_ILIMIT_CFG_REG (MISC_BASE + 0xA1) #define LS_VALLEY_THRESH_PCT_BIT BIT(3) #define PCL_LIMIT_MASK GENMASK(1, 0) #define SNARL_BARK_BITE_WD_CFG_REG (MISC_BASE + 0x53) #define BITE_WDOG_DISABLE_CHARGING_CFG_BIT BIT(7) #define SNARL_WDOG_TIMEOUT_MASK GENMASK(6, 4) Loading Loading @@ -155,6 +174,8 @@ ((mode == POWER_SUPPLY_PL_USBIN_USBIN) \ || (mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) #define PARALLEL_ENABLE_VOTER "PARALLEL_ENABLE_VOTER" struct smb_chg_param { const char *name; u16 reg; Loading Loading @@ -204,6 +225,8 @@ struct smb_dt_props { bool disable_ctm; int pl_mode; int pl_batfet_mode; bool hw_die_temp_mitigation; u32 die_temp_threshold; }; struct smb1355 { Loading @@ -211,6 +234,8 @@ struct smb1355 { char *name; struct regmap *regmap; int max_fcc; struct smb_dt_props dt; struct smb_params param; Loading @@ -225,10 +250,20 @@ struct smb1355 { bool exit_die_temp; struct delayed_work die_temp_work; bool disabled; struct votable *irq_disable_votable; }; enum { CONNECTOR_TEMP = 0, DIE_TEMP, }; static bool is_secure(struct smb1355 *chip, int addr) { if (addr == CLOCK_REQUEST_REG) return true; /* assume everything above 0xA0 is secure */ return (addr & 0xFF) >= 0xA0; } Loading @@ -245,6 +280,25 @@ static int smb1355_read(struct smb1355 *chip, u16 addr, u8 *val) return rc; } static int smb1355_masked_force_write(struct smb1355 *chip, u16 addr, u8 mask, u8 val) { int rc; mutex_lock(&chip->write_lock); if (is_secure(chip, addr)) { rc = regmap_write(chip->regmap, (addr & 0xFF00) | 0xD0, 0xA5); if (rc < 0) goto unlock; } rc = regmap_write_bits(chip->regmap, addr, mask, val); unlock: mutex_unlock(&chip->write_lock); return rc; } static int smb1355_masked_write(struct smb1355 *chip, u16 addr, u8 mask, u8 val) { int rc; Loading Loading @@ -334,8 +388,7 @@ static void die_temp_work(struct work_struct *work) u8 temp_stat; for (i = 0; i < BIT(5); i++) { rc = smb1355_masked_write(chip, SMB2CHGS_BATIF_ENG_SMISC_DIETEMP, rc = smb1355_masked_write(chip, SMB2CHG_BATIF_ENG_SMISC_DIETEMP, TDIE_COMPARATOR_THRESHOLD, i); if (rc < 0) { pr_err("Couldn't set temp comp threshold rc=%d\n", rc); Loading @@ -354,7 +407,7 @@ static void die_temp_work(struct work_struct *work) continue; } if (!(temp_stat & DIE_TEMP_UB_HOT_BIT)) { if (!(temp_stat & TEMP_UB_HOT_BIT)) { /* found the temp */ break; } Loading Loading @@ -420,6 +473,7 @@ static int smb1355_determine_initial_status(struct smb1355 *chip) return 0; } #define DEFAULT_DIE_TEMP_LOW_THRESHOLD 90 static int smb1355_parse_dt(struct smb1355 *chip) { struct device_node *node = chip->dev->of_node; Loading Loading @@ -450,6 +504,15 @@ static int smb1355_parse_dt(struct smb1355 *chip) if (of_property_read_bool(node, "qcom,stacked-batfet")) chip->dt.pl_batfet_mode = POWER_SUPPLY_PL_STACKED_BATFET; chip->dt.hw_die_temp_mitigation = of_property_read_bool(node, "qcom,hw-die-temp-mitigation"); chip->dt.die_temp_threshold = DEFAULT_DIE_TEMP_LOW_THRESHOLD; of_property_read_u32(node, "qcom,die-temp-threshold-degc", &chip->dt.die_temp_threshold); if (chip->dt.die_temp_threshold > DIE_LOW_RANGE_MAX_DEGC) chip->dt.die_temp_threshold = DIE_LOW_RANGE_MAX_DEGC; return 0; } Loading @@ -470,9 +533,12 @@ static enum power_supply_property smb1355_parallel_props[] = { POWER_SUPPLY_PROP_PARALLEL_MODE, POWER_SUPPLY_PROP_CONNECTOR_HEALTH, POWER_SUPPLY_PROP_PARALLEL_BATFET_MODE, POWER_SUPPLY_PROP_PARALLEL_FCC_MAX, POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED, POWER_SUPPLY_PROP_MIN_ICL, POWER_SUPPLY_PROP_CURRENT_MAX, POWER_SUPPLY_PROP_SET_SHIP_MODE, POWER_SUPPLY_PROP_DIE_HEALTH, }; static int smb1355_get_prop_batt_charge_type(struct smb1355 *chip, Loading @@ -499,10 +565,13 @@ static int smb1355_get_prop_batt_charge_type(struct smb1355 *chip, return rc; } static int smb1355_get_prop_connector_health(struct smb1355 *chip) static int smb1355_get_prop_health(struct smb1355 *chip, int type) { u8 temp; int rc; int rc, shift; /* Connector-temp uses skin-temp configuration */ shift = (type == CONNECTOR_TEMP) ? SKIN_TEMP_SHIFT : 0; rc = smb1355_read(chip, TEMP_COMP_STATUS_REG, &temp); if (rc < 0) { Loading @@ -510,13 +579,13 @@ static int smb1355_get_prop_connector_health(struct smb1355 *chip) return POWER_SUPPLY_HEALTH_UNKNOWN; } if (temp & SKIN_TEMP_RST_HOT_BIT) if (temp & (TEMP_RST_HOT_BIT << shift)) return POWER_SUPPLY_HEALTH_OVERHEAT; if (temp & SKIN_TEMP_UB_HOT_BIT) if (temp & (TEMP_UB_HOT_BIT << shift)) return POWER_SUPPLY_HEALTH_HOT; if (temp & SKIN_TEMP_LB_HOT_BIT) if (temp & (TEMP_LB_HOT_BIT << shift)) return POWER_SUPPLY_HEALTH_WARM; return POWER_SUPPLY_HEALTH_COOL; Loading Loading @@ -549,6 +618,16 @@ static int smb1355_parallel_get_prop(struct power_supply *psy, val->intval = chip->die_temp_deciDegC; break; case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX: /* * In case of h/w controlled die_temp mitigation, * die_temp/die_temp_max can not be reported as this * requires run time manipulation of DIE_TEMP low * threshold which will interfere with h/w mitigation * scheme. */ if (chip->dt.hw_die_temp_mitigation) val->intval = -EINVAL; else val->intval = chip->c_charger_temp_max; break; case POWER_SUPPLY_PROP_INPUT_SUSPEND: Loading @@ -570,10 +649,14 @@ static int smb1355_parallel_get_prop(struct power_supply *psy, break; case POWER_SUPPLY_PROP_CONNECTOR_HEALTH: if (chip->c_health == -EINVAL) val->intval = smb1355_get_prop_connector_health(chip); val->intval = smb1355_get_prop_health(chip, CONNECTOR_TEMP); else val->intval = chip->c_health; break; case POWER_SUPPLY_PROP_DIE_HEALTH: val->intval = smb1355_get_prop_health(chip, DIE_TEMP); break; case POWER_SUPPLY_PROP_PARALLEL_BATFET_MODE: val->intval = chip->dt.pl_batfet_mode; break; Loading @@ -593,6 +676,13 @@ static int smb1355_parallel_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_MIN_ICL: val->intval = MIN_PARALLEL_ICL_UA; break; case POWER_SUPPLY_PROP_PARALLEL_FCC_MAX: val->intval = chip->max_fcc; break; case POWER_SUPPLY_PROP_SET_SHIP_MODE: /* Not in ship mode as long as device is active */ val->intval = 0; break; default: pr_err_ratelimited("parallel psy get prop %d not supported\n", prop); Loading Loading @@ -636,6 +726,8 @@ static int smb1355_set_parallel_charging(struct smb1355 *chip, bool disable) } chip->die_temp_deciDegC = -EINVAL; /* Only enable temperature measurement for s/w based mitigation */ if (!chip->dt.hw_die_temp_mitigation) { if (disable) { chip->exit_die_temp = true; cancel_delayed_work_sync(&chip->die_temp_work); Loading @@ -644,6 +736,19 @@ static int smb1355_set_parallel_charging(struct smb1355 *chip, bool disable) chip->exit_die_temp = false; schedule_delayed_work(&chip->die_temp_work, 0); } } if (chip->irq_disable_votable) vote(chip->irq_disable_votable, PARALLEL_ENABLE_VOTER, disable, 0); rc = smb1355_masked_write(chip, BANDGAP_ENABLE_REG, BANDGAP_ENABLE_CMD_BIT, disable ? 0 : BANDGAP_ENABLE_CMD_BIT); if (rc < 0) { pr_err("Couldn't configure bandgap enable rc=%d\n", rc); return rc; } chip->disabled = disable; Loading Loading @@ -672,6 +777,20 @@ static int smb1355_set_current_max(struct smb1355 *chip, int curr) return rc; } static int smb1355_clk_request(struct smb1355 *chip, bool enable) { int rc; rc = smb1355_masked_force_write(chip, CLOCK_REQUEST_REG, CLOCK_REQUEST_CMD_BIT, enable ? CLOCK_REQUEST_CMD_BIT : 0); if (rc < 0) pr_err("Couldn't %s clock rc=%d\n", enable ? "enable" : "disable", rc); return rc; } static int smb1355_parallel_set_prop(struct power_supply *psy, enum power_supply_property prop, const union power_supply_propval *val) Loading Loading @@ -700,6 +819,10 @@ static int smb1355_parallel_set_prop(struct power_supply *psy, break; case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX: chip->c_charger_temp_max = val->intval; case POWER_SUPPLY_PROP_SET_SHIP_MODE: if (!val->intval) break; rc = smb1355_clk_request(chip, false); break; default: pr_debug("parallel power supply set prop %d not supported\n", Loading Loading @@ -758,6 +881,38 @@ static int smb1355_init_parallel_psy(struct smb1355 *chip) * HARDWARE INITIALIZATION * ***************************/ #define MFG_ID_SMB1354 0x01 #define MFG_ID_SMB1355 0xFF #define SMB1354_MAX_PARALLEL_FCC_UA 2500000 #define SMB1355_MAX_PARALLEL_FCC_UA 6000000 static int smb1355_detect_version(struct smb1355 *chip) { int rc; u8 val; rc = smb1355_read(chip, REVID_MFG_ID_SPARE_REG, &val); if (rc < 0) { pr_err("Unable to read REVID rc=%d\n", rc); return rc; } switch (val) { case MFG_ID_SMB1354: chip->name = "smb1354"; chip->max_fcc = SMB1354_MAX_PARALLEL_FCC_UA; break; case MFG_ID_SMB1355: chip->name = "smb1355"; chip->max_fcc = SMB1355_MAX_PARALLEL_FCC_UA; break; default: pr_err("Invalid value of REVID val=%d", val); return -EINVAL; } return rc; } static int smb1355_tskin_sensor_config(struct smb1355 *chip) { int rc; Loading Loading @@ -847,6 +1002,12 @@ static int smb1355_tskin_sensor_config(struct smb1355 *chip) static int smb1355_init_hw(struct smb1355 *chip) { int rc; u8 val, range; /* request clock always on */ rc = smb1355_clk_request(chip, true); if (rc < 0) return rc; /* Change to let SMB1355 only respond to address 0x0C */ rc = smb1355_masked_write(chip, I2C_SS_DIG_PMIC_SID_REG, Loading Loading @@ -918,13 +1079,35 @@ static int smb1355_init_hw(struct smb1355 *chip) return rc; } /* Configure DIE temp Low threshold */ if (chip->dt.hw_die_temp_mitigation) { range = (chip->dt.die_temp_threshold - DIE_LOW_RANGE_BASE_DEGC) / (DIE_LOW_RANGE_DELTA); val = (chip->dt.die_temp_threshold - ((range * DIE_LOW_RANGE_DELTA) + DIE_LOW_RANGE_BASE_DEGC)) % DIE_LOW_RANGE_DELTA; rc = smb1355_masked_write(chip, SMB2CHG_BATIF_ENG_SMISC_DIETEMP, TDIE_COMPARATOR_THRESHOLD, (range << DIE_LOW_RANGE_SHIFT) | val); if (rc < 0) { pr_err("Couldn't set temp comp threshold rc=%d\n", rc); return rc; } } /* * Enable thermal Die temperature comparator source and disable hw * mitigation for skin/die * Enable thermal Die temperature comparator source and * enable hardware controlled current adjustment for die temp * if charger is configured in h/w controlled die temp mitigation. */ val = THERMREG_DIE_CMP_SRC_EN_BIT; if (!chip->dt.hw_die_temp_mitigation) val |= BYP_THERM_CHG_CURR_ADJUST_BIT; rc = smb1355_masked_write(chip, MISC_THERMREG_SRC_CFG_REG, THERMREG_DIE_CMP_SRC_EN_BIT | BYP_THERM_CHG_CURR_ADJUST_BIT, THERMREG_DIE_CMP_SRC_EN_BIT | BYP_THERM_CHG_CURR_ADJUST_BIT); val); if (rc < 0) { pr_err("Couldn't set Skin temperature comparator src rc=%d\n", rc); Loading @@ -935,13 +1118,40 @@ static int smb1355_init_hw(struct smb1355 *chip) * Disable hysterisis for die temperature. This is so that sw can run * stepping scheme quickly */ val = chip->dt.hw_die_temp_mitigation ? DIE_TEMP_COMP_HYST_BIT : 0; rc = smb1355_masked_write(chip, BATIF_ENG_SCMISC_SPARE1_REG, DIE_TEMP_COMP_HYST_BIT, 0); DIE_TEMP_COMP_HYST_BIT, val); if (rc < 0) { pr_err("Couldn't disable hyst. for die rc=%d\n", rc); return rc; } /* Enable valley current comparator all the time */ rc = smb1355_masked_write(chip, ANA1_ENG_SREFGEN_CFG2_REG, VALLEY_COMPARATOR_EN_BIT, VALLEY_COMPARATOR_EN_BIT); if (rc < 0) { pr_err("Couldn't enable valley current comparator rc=%d\n", rc); return rc; } /* Set LS_VALLEY threshold to 85% */ rc = smb1355_masked_write(chip, MISC_CUST_SDCDC_ILIMIT_CFG_REG, LS_VALLEY_THRESH_PCT_BIT, LS_VALLEY_THRESH_PCT_BIT); if (rc < 0) { pr_err("Couldn't set LS valley threshold to 85pc rc=%d\n", rc); return rc; } /* For SMB1354, set PCL to 8.6 A */ if (!strcmp(chip->name, "smb1354")) { rc = smb1355_masked_write(chip, MISC_CUST_SDCDC_ILIMIT_CFG_REG, PCL_LIMIT_MASK, PCL_LIMIT_MASK); if (rc < 0) { pr_err("Couldn't set PCL limit to 8.6A rc=%d\n", rc); return rc; } } rc = smb1355_tskin_sensor_config(chip); if (rc < 0) { pr_err("Couldn't configure tskin regs rc=%d\n", rc); Loading Loading @@ -1079,6 +1289,7 @@ static int smb1355_request_interrupt(struct smb1355 *chip, return rc; } smb1355_irqs[irq_index].irq = irq; if (smb1355_irqs[irq_index].wake) enable_irq_wake(irq); Loading Loading @@ -1107,6 +1318,23 @@ static int smb1355_request_interrupts(struct smb1355 *chip) return rc; } static int smb1355_irq_disable_callback(struct votable *votable, void *data, int disable, const char *client) { int i; for (i = 0; i < ARRAY_SIZE(smb1355_irqs); i++) { if (smb1355_irqs[i].irq) { if (disable) disable_irq(smb1355_irqs[i].irq); else enable_irq(smb1355_irqs[i].irq); } } return 0; } /********* * PROBE * Loading @@ -1132,7 +1360,6 @@ static int smb1355_probe(struct platform_device *pdev) chip->param = v1_params; chip->c_health = -EINVAL; chip->c_charger_temp_max = -EINVAL; chip->name = "smb1355"; mutex_init(&chip->write_lock); INIT_DELAYED_WORK(&chip->die_temp_work, die_temp_work); chip->disabled = true; Loading @@ -1150,6 +1377,12 @@ static int smb1355_probe(struct platform_device *pdev) return -ENODEV; } rc = smb1355_detect_version(chip); if (rc < 0) { pr_err("Couldn't detect SMB1355/1354 chip type rc=%d\n", rc); goto cleanup; } platform_set_drvdata(pdev, chip); rc = smb1355_parse_dt(chip); Loading Loading @@ -1183,6 +1416,15 @@ static int smb1355_probe(struct platform_device *pdev) goto cleanup; } chip->irq_disable_votable = create_votable("SMB1355_IRQ_DISABLE", VOTE_SET_ANY, smb1355_irq_disable_callback, chip); if (IS_ERR(chip->irq_disable_votable)) { rc = PTR_ERR(chip->irq_disable_votable); goto cleanup; } /* keep IRQ's disabled until parallel is enabled */ vote(chip->irq_disable_votable, PARALLEL_ENABLE_VOTER, true, 0); pr_info("%s probed successfully pl_mode=%s batfet_mode=%s\n", chip->name, IS_USBIN(chip->dt.pl_mode) ? "USBIN-USBIN" : "USBMID-USBMID", Loading Loading @@ -1210,6 +1452,8 @@ static void smb1355_shutdown(struct platform_device *pdev) rc = smb1355_set_parallel_charging(chip, true); if (rc < 0) pr_err("Couldn't disable parallel path rc=%d\n", rc); smb1355_clk_request(chip, false); } static struct platform_driver smb1355_driver = { Loading