Loading drivers/power/supply/qcom/smb1390-charger-psy.c +402 −57 Original line number Diff line number Diff line Loading @@ -94,6 +94,8 @@ #define SWITCHER_TOGGLE_VOTER "SWITCHER_TOGGLE_VOTER" #define SOC_LEVEL_VOTER "SOC_LEVEL_VOTER" #define CP_MASTER 0 #define CP_SLAVE 1 #define THERMAL_SUSPEND_DECIDEGC 1400 #define MAX_ILIM_UA 3200000 Loading @@ -119,6 +121,12 @@ enum { NUM_IRQS, }; enum isns_mode { ISNS_MODE_OFF = 0, ISNS_MODE_ACTIVE, ISNS_MODE_STANDBY, }; enum { SWITCHER_EN = 0, SMB_PIN_EN, Loading Loading @@ -157,8 +165,10 @@ struct smb1390 { struct votable *ilim_votable; struct votable *fcc_votable; struct votable *fv_votable; struct votable *cp_awake_votable; /* power supplies */ struct power_supply *cps_psy; struct power_supply *usb_psy; struct power_supply *batt_psy; struct power_supply *dc_psy; Loading @@ -179,6 +189,8 @@ struct smb1390 { u32 max_temp_alarm_degc; u32 max_cutoff_soc; u32 pl_output_mode; u32 cp_role; enum isns_mode current_capability; }; struct smb_irq { Loading Loading @@ -265,6 +277,46 @@ static bool is_psy_voter_available(struct smb1390 *chip) return true; } static int smb1390_isns_mode_control(struct smb1390 *chip, enum isns_mode mode) { int rc; u8 val; switch (mode) { case ISNS_MODE_ACTIVE: val = ATEST1_OUTPUT_ENABLE_BIT | ISNS_INT_VAL; break; case ISNS_MODE_STANDBY: val = ATEST1_OUTPUT_ENABLE_BIT; break; case ISNS_MODE_OFF: default: val = 0; break; } rc = smb1390_masked_write(chip, CORE_ATEST1_SEL_REG, ATEST1_OUTPUT_ENABLE_BIT | ATEST1_SEL_MASK, val); if (rc < 0) pr_err("Couldn't set CORE_ATEST1_SEL_REG, rc = %d\n", rc); return rc; } static bool is_cps_available(struct smb1390 *chip) { if (!chip->cps_psy) chip->cps_psy = power_supply_get_by_name("cp_slave"); else return true; if (!chip->cps_psy) return false; return true; } static void cp_toggle_switcher(struct smb1390 *chip) { int rc; Loading Loading @@ -320,6 +372,18 @@ static int smb1390_get_cp_en_status(struct smb1390 *chip, int id, bool *enable) return rc; } static int smb1390_set_ilim(struct smb1390 *chip, int ilim_ua) { int rc; rc = smb1390_masked_write(chip, CORE_FTRIM_ILIM_REG, CFG_ILIM_MASK, ilim_ua); if (rc < 0) pr_err("Failed to write ILIM Register, rc=%d\n", rc); return rc; } static irqreturn_t default_irq_handler(int irq, void *data) { struct smb1390 *chip = data; Loading Loading @@ -425,7 +489,13 @@ static int smb1390_get_die_temp(struct smb1390 *chip, return rc; } static int smb1390_get_isns(struct smb1390 *chip, static int smb1390_get_isns(int temp) { /* ISNS = 2 * (1496 - 1390_therm_input * 0.00356) * 1000 uA */ return ((1496 * 1000 - div_s64((s64)temp * 3560, 1000)) * 2); } static int smb1390_get_isns_master(struct smb1390 *chip, union power_supply_propval *val) { int temp = 0; Loading @@ -445,12 +515,105 @@ static int smb1390_get_isns(struct smb1390 *chip, if (!enable) return -ENODATA; /* * Since master and slave share temp_pin line * which is re-used to measure isns, configure the * master as follows: * 1. Put slave in standby mode * 2. Configure master to provide current reading * 3. Read current value * 4. Configure master back to report temperature */ mutex_lock(&chip->die_chan_lock); rc = smb1390_masked_write(chip, CORE_ATEST1_SEL_REG, ATEST1_OUTPUT_ENABLE_BIT | ATEST1_SEL_MASK, ATEST1_OUTPUT_ENABLE_BIT | ISNS_INT_VAL); if (is_cps_available(chip)) { val->intval = ISNS_MODE_STANDBY; rc = power_supply_set_property(chip->cps_psy, POWER_SUPPLY_PROP_CURRENT_CAPABILITY, val); if (rc < 0) { pr_err("Couldn't set CORE_ATEST1_SEL_REG, rc = %d\n", rc); pr_err("Couldn't change slave charging state rc=%d\n", rc); goto unlock; } } rc = smb1390_isns_mode_control(chip, ISNS_MODE_ACTIVE); if (rc < 0) { pr_err("Failed to set master in Active mode, rc=%d\n", rc); goto unlock; } rc = iio_read_channel_processed(chip->iio.die_temp_chan, &temp); if (rc < 0) { pr_err("Couldn't read die_temp chan for isns, rc = %d\n", rc); goto unlock; } rc = smb1390_isns_mode_control(chip, ISNS_MODE_OFF); if (rc < 0) pr_err("Couldn't set master to off mode, rc = %d\n", rc); if (is_cps_available(chip)) { val->intval = ISNS_MODE_OFF; rc = power_supply_set_property(chip->cps_psy, POWER_SUPPLY_PROP_CURRENT_CAPABILITY, val); if (rc < 0) pr_err("Couldn't change slave charging state rc=%d\n", rc); } unlock: mutex_unlock(&chip->die_chan_lock); if (rc >= 0) val->intval = smb1390_get_isns(temp); return rc; } static int smb1390_get_isns_slave(struct smb1390 *chip, union power_supply_propval *val) { int temp = 0; int rc; bool enable; if (!is_cps_available(chip)) { val->intval = 0; return 0; } /* * If SMB1390 chip is not enabled, adc channel read may render * erroneous value. Return error to signify, adc read is not admissible */ rc = smb1390_get_cp_en_status(chip, SMB_PIN_EN, &enable); if (rc < 0) { pr_err("Couldn't get SMB_PIN enable status, rc=%d\n", rc); return rc; } if (!enable) return -ENODATA; /* * Since master and slave share temp_pin line * which is re-used to measure isns, configure the * slave as follows: * 1. Put slave in standby mode * 2. Configure slave to in Active mode to provide current reading * 3. Read current value */ mutex_lock(&chip->die_chan_lock); rc = smb1390_isns_mode_control(chip, ISNS_MODE_STANDBY); if (rc < 0) goto unlock; val->intval = ISNS_MODE_ACTIVE; rc = power_supply_set_property(chip->cps_psy, POWER_SUPPLY_PROP_CURRENT_CAPABILITY, val); if (rc < 0) { pr_err("Couldn't change slave charging state rc=%d\n", rc); goto unlock; } Loading @@ -461,18 +624,23 @@ static int smb1390_get_isns(struct smb1390 *chip, goto unlock; } rc = smb1390_masked_write(chip, CORE_ATEST1_SEL_REG, ATEST1_OUTPUT_ENABLE_BIT | ATEST1_SEL_MASK, 0); val->intval = ISNS_MODE_OFF; rc = power_supply_set_property(chip->cps_psy, POWER_SUPPLY_PROP_CURRENT_CAPABILITY, val); if (rc < 0) pr_err("Couldn't change slave charging state rc=%d\n", rc); rc = smb1390_isns_mode_control(chip, ISNS_MODE_OFF); if (rc < 0) pr_err("Couldn't set CORE_ATEST1_SEL_REG, rc = %d\n", rc); unlock: mutex_unlock(&chip->die_chan_lock); /* ISNS = 2 * (1496 - 1390_therm_input * 0.00356) * 1000 uA */ if (rc >= 0) val->intval = (1496 * 1000 - div_s64((s64)temp * 3560, 1000)) * 2; val->intval = smb1390_get_isns(temp); return rc; } Loading Loading @@ -505,19 +673,17 @@ static int smb1390_disable_vote_cb(struct votable *votable, void *data, { struct smb1390 *chip = data; int rc = 0; u8 mask, val; if (!is_psy_voter_available(chip) || chip->suspended) return -EAGAIN; if (disable) { rc = smb1390_masked_write(chip, CORE_CONTROL1_REG, CMD_EN_SWITCHER_BIT, 0); if (rc < 0) return rc; } else { rc = smb1390_masked_write(chip, CORE_CONTROL1_REG, CMD_EN_SWITCHER_BIT, CMD_EN_SWITCHER_BIT); if (rc < 0) mask = CMD_EN_SWITCHER_BIT | CMD_EN_SL_BIT; val = is_cps_available(chip) ? mask : CMD_EN_SWITCHER_BIT; rc = smb1390_masked_write(chip, CORE_CONTROL1_REG, mask, disable ? 0 : val); if (rc < 0) { pr_err("Couldn't write CORE_CONTROL1_REG, rc=%d\n", rc); return rc; } Loading @@ -533,6 +699,7 @@ static int smb1390_ilim_vote_cb(struct votable *votable, void *data, int ilim_uA, const char *client) { struct smb1390 *chip = data; union power_supply_propval pval = {0, }; int rc = 0; if (!is_psy_voter_available(chip) || chip->suspended) Loading @@ -545,20 +712,31 @@ static int smb1390_ilim_vote_cb(struct votable *votable, void *data, } ilim_uA = min(ilim_uA, MAX_ILIM_UA); rc = smb1390_masked_write(chip, CORE_FTRIM_ILIM_REG, CFG_ILIM_MASK, DIV_ROUND_CLOSEST(max(ilim_uA, 500000) - 500000, 100000)); if (rc < 0) { pr_err("Failed to write ILIM Register, rc=%d\n", rc); return rc; } /* ILIM less than min_ilim_ua, disable charging */ if (ilim_uA < chip->min_ilim_ua) { smb1390_dbg(chip, PR_INFO, "ILIM %duA is too low to allow charging\n", ilim_uA); vote(chip->disable_votable, ILIM_VOTER, true, 0); } else { if (is_cps_available(chip)) { ilim_uA /= 2; pval.intval = DIV_ROUND_CLOSEST(ilim_uA - 500000, 100000); rc = power_supply_set_property(chip->cps_psy, POWER_SUPPLY_PROP_INPUT_CURRENT_MAX, &pval); if (rc < 0) pr_err("Couldn't change slave ilim rc=%d\n", rc); } rc = smb1390_set_ilim(chip, DIV_ROUND_CLOSEST(ilim_uA - 500000, 100000)); if (rc < 0) { pr_err("Failed to set ILIM, rc=%d\n", rc); return rc; } smb1390_dbg(chip, PR_INFO, "ILIM set to %duA\n", ilim_uA); vote(chip->disable_votable, ILIM_VOTER, false, 0); } Loading @@ -566,6 +744,21 @@ static int smb1390_ilim_vote_cb(struct votable *votable, void *data, return rc; } static int smb1390_awake_vote_cb(struct votable *votable, void *data, int awake, const char *client) { struct smb1390 *chip = data; if (awake) __pm_stay_awake(chip->cp_ws); else __pm_relax(chip->cp_ws); smb1390_dbg(chip, PR_INFO, "client: %s awake: %d\n", client, awake); return 0; } static int smb1390_notifier_cb(struct notifier_block *nb, unsigned long event, void *data) { Loading Loading @@ -761,6 +954,7 @@ static enum power_supply_property smb1390_charge_pump_props[] = { POWER_SUPPLY_PROP_CP_SWITCHER_EN, POWER_SUPPLY_PROP_CP_DIE_TEMP, POWER_SUPPLY_PROP_CP_ISNS, POWER_SUPPLY_PROP_CP_ISNS_SLAVE, POWER_SUPPLY_PROP_CP_TOGGLE_SWITCHER, POWER_SUPPLY_PROP_CP_IRQ_STATUS, POWER_SUPPLY_PROP_CP_ILIM, Loading Loading @@ -832,7 +1026,10 @@ static int smb1390_get_prop(struct power_supply *psy, } break; case POWER_SUPPLY_PROP_CP_ISNS: rc = smb1390_get_isns(chip, val); rc = smb1390_get_isns_master(chip, val); break; case POWER_SUPPLY_PROP_CP_ISNS_SLAVE: rc = smb1390_get_isns_slave(chip, val); break; case POWER_SUPPLY_PROP_CP_TOGGLE_SWITCHER: val->intval = 0; Loading Loading @@ -905,6 +1102,8 @@ static int smb1390_prop_is_writeable(struct power_supply *psy, case POWER_SUPPLY_PROP_CP_ENABLE: case POWER_SUPPLY_PROP_CP_TOGGLE_SWITCHER: case POWER_SUPPLY_PROP_CP_IRQ_STATUS: case POWER_SUPPLY_PROP_INPUT_CURRENT_MAX: case POWER_SUPPLY_PROP_CURRENT_CAPABILITY: return 1; default: break; Loading Loading @@ -990,6 +1189,8 @@ static void smb1390_release_channels(struct smb1390 *chip) static int smb1390_create_votables(struct smb1390 *chip) { chip->cp_awake_votable = create_votable("CP_AWAKE", VOTE_SET_ANY, smb1390_awake_vote_cb, chip); chip->disable_votable = create_votable("CP_DISABLE", VOTE_SET_ANY, smb1390_disable_vote_cb, chip); if (IS_ERR(chip->disable_votable)) Loading Loading @@ -1164,14 +1365,23 @@ static void smb1390_create_debugfs(struct smb1390 *chip) } #endif static int smb1390_probe(struct platform_device *pdev) static const struct of_device_id match_table[] = { { .compatible = "qcom,smb1390-charger-psy", .data = (void *)CP_MASTER }, { .compatible = "qcom,smb1390-slave", .data = (void *)CP_SLAVE }, { }, }; static int smb1390_master_probe(struct smb1390 *chip) { struct smb1390 *chip; int rc; struct device_node *revid_dev_node; struct pmic_revid_data *pmic_rev_id; int rc; revid_dev_node = of_parse_phandle(pdev->dev.of_node, revid_dev_node = of_parse_phandle(chip->dev->of_node, "qcom,pmic-revid", 0); if (!revid_dev_node) { pr_err("Missing qcom,pmic-revid property\n"); Loading @@ -1189,23 +1399,9 @@ static int smb1390_probe(struct platform_device *pdev) return -EPROBE_DEFER; } chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; chip->dev = &pdev->dev; chip->pmic_rev_id = pmic_rev_id; spin_lock_init(&chip->status_change_lock); mutex_init(&chip->die_chan_lock); chip->die_temp = -ENODATA; chip->pmic_rev_id = pmic_rev_id; chip->disabled = true; platform_set_drvdata(pdev, chip); chip->regmap = dev_get_regmap(chip->dev->parent, NULL); if (!chip->regmap) { pr_err("Couldn't get regmap\n"); return -EINVAL; } rc = smb1390_parse_dt(chip); if (rc < 0) { Loading Loading @@ -1252,9 +1448,6 @@ static int smb1390_probe(struct platform_device *pdev) } smb1390_create_debugfs(chip); pr_debug("smb1390 probed successfully chip_version=%d\n", chip->pmic_rev_id->rev4); return 0; out_notifier: Loading @@ -1268,10 +1461,166 @@ static int smb1390_probe(struct platform_device *pdev) return rc; } static enum power_supply_property smb1390_cp_slave_props[] = { POWER_SUPPLY_PROP_INPUT_CURRENT_MAX, POWER_SUPPLY_PROP_CURRENT_CAPABILITY, }; static int smb1390_cp_slave_get_prop(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { struct smb1390 *chip = power_supply_get_drvdata(psy); switch (psp) { case POWER_SUPPLY_PROP_INPUT_CURRENT_MAX: val->intval = 0; if (!chip->ilim_votable) chip->ilim_votable = find_votable("CP_ILIM"); if (chip->ilim_votable) val->intval = get_effective_result_locked(chip->ilim_votable); break; case POWER_SUPPLY_PROP_CURRENT_CAPABILITY: val->intval = (int)chip->current_capability; break; default: smb1390_dbg(chip, PR_MISC, "SMB 1390 slave power supply get prop %d not supported\n", psp); return -EINVAL; } return 0; } static int smb1390_cp_slave_set_prop(struct power_supply *psy, enum power_supply_property psp, const union power_supply_propval *val) { struct smb1390 *chip = power_supply_get_drvdata(psy); int rc = 0; switch (psp) { case POWER_SUPPLY_PROP_INPUT_CURRENT_MAX: rc = smb1390_set_ilim(chip, val->intval); break; case POWER_SUPPLY_PROP_CURRENT_CAPABILITY: chip->current_capability = (enum isns_mode)val->intval; rc = smb1390_isns_mode_control(chip, val->intval); break; default: smb1390_dbg(chip, PR_MISC, "SMB 1390 slave power supply set prop %d not supported\n", psp); return -EINVAL; } return 0; }; static const struct power_supply_desc cps_psy_desc = { .name = "cp_slave", .type = POWER_SUPPLY_TYPE_PARALLEL, .properties = smb1390_cp_slave_props, .num_properties = ARRAY_SIZE(smb1390_cp_slave_props), .get_property = smb1390_cp_slave_get_prop, .set_property = smb1390_cp_slave_set_prop, .property_is_writeable = smb1390_prop_is_writeable, }; static int smb1390_init_cps_psy(struct smb1390 *chip) { struct power_supply_config cps_cfg = {}; cps_cfg.drv_data = chip; cps_cfg.of_node = chip->dev->of_node; chip->cps_psy = devm_power_supply_register(chip->dev, &cps_psy_desc, &cps_cfg); if (IS_ERR(chip->cps_psy)) { pr_err("Couldn't register CP slave power supply\n"); return PTR_ERR(chip->cps_psy); } return 0; } static int smb1390_slave_probe(struct smb1390 *chip) { int stat, rc; /* a "hello" read to test the presence of the slave PMIC */ rc = smb1390_read(chip, CORE_STATUS1_REG, &stat); if (rc < 0) { pr_err("Couldn't find slave SMB1390\n"); return -EINVAL; } rc = smb1390_init_cps_psy(chip); if (rc < 0) pr_err("Couldn't initialize cps psy rc=%d\n", rc); return rc; } static int smb1390_probe(struct platform_device *pdev) { struct smb1390 *chip; int rc; chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; chip->dev = &pdev->dev; chip->die_temp = -ENODATA; chip->disabled = true; chip->regmap = dev_get_regmap(chip->dev->parent, NULL); if (!chip->regmap) { pr_err("Couldn't get regmap\n"); return -EINVAL; } platform_set_drvdata(pdev, chip); chip->cp_role = (int)of_device_get_match_data(chip->dev); switch (chip->cp_role) { case CP_MASTER: rc = smb1390_master_probe(chip); break; case CP_SLAVE: rc = smb1390_slave_probe(chip); break; default: pr_err("Couldn't find a matching role %d\n", chip->cp_role); rc = -EINVAL; goto cleanup; } if (rc < 0) { if (rc != -EPROBE_DEFER) pr_err("Couldn't probe SMB1390 %s rc=%d\n", chip->cp_role ? "Slave" : "Master", rc); goto cleanup; } pr_info("smb1390 %s probed successfully\n", chip->cp_role ? "Slave" : "Master"); return 0; cleanup: platform_set_drvdata(pdev, NULL); return rc; } static int smb1390_remove(struct platform_device *pdev) { struct smb1390 *chip = platform_get_drvdata(pdev); if (chip->cp_role != CP_MASTER) { platform_set_drvdata(pdev, NULL); return 0; } power_supply_unreg_notifier(&chip->nb); /* explicitly disable charging */ Loading @@ -1282,6 +1631,7 @@ static int smb1390_remove(struct platform_device *pdev) wakeup_source_unregister(chip->cp_ws); smb1390_destroy_votables(chip); smb1390_release_channels(chip); platform_set_drvdata(pdev, NULL); return 0; } Loading Loading @@ -1323,11 +1673,6 @@ static const struct dev_pm_ops smb1390_pm_ops = { .resume = smb1390_resume, }; static const struct of_device_id match_table[] = { { .compatible = "qcom,smb1390-charger-psy", }, { }, }; static struct platform_driver smb1390_driver = { .driver = { .name = "qcom,smb1390-charger-psy", Loading Loading
drivers/power/supply/qcom/smb1390-charger-psy.c +402 −57 Original line number Diff line number Diff line Loading @@ -94,6 +94,8 @@ #define SWITCHER_TOGGLE_VOTER "SWITCHER_TOGGLE_VOTER" #define SOC_LEVEL_VOTER "SOC_LEVEL_VOTER" #define CP_MASTER 0 #define CP_SLAVE 1 #define THERMAL_SUSPEND_DECIDEGC 1400 #define MAX_ILIM_UA 3200000 Loading @@ -119,6 +121,12 @@ enum { NUM_IRQS, }; enum isns_mode { ISNS_MODE_OFF = 0, ISNS_MODE_ACTIVE, ISNS_MODE_STANDBY, }; enum { SWITCHER_EN = 0, SMB_PIN_EN, Loading Loading @@ -157,8 +165,10 @@ struct smb1390 { struct votable *ilim_votable; struct votable *fcc_votable; struct votable *fv_votable; struct votable *cp_awake_votable; /* power supplies */ struct power_supply *cps_psy; struct power_supply *usb_psy; struct power_supply *batt_psy; struct power_supply *dc_psy; Loading @@ -179,6 +189,8 @@ struct smb1390 { u32 max_temp_alarm_degc; u32 max_cutoff_soc; u32 pl_output_mode; u32 cp_role; enum isns_mode current_capability; }; struct smb_irq { Loading Loading @@ -265,6 +277,46 @@ static bool is_psy_voter_available(struct smb1390 *chip) return true; } static int smb1390_isns_mode_control(struct smb1390 *chip, enum isns_mode mode) { int rc; u8 val; switch (mode) { case ISNS_MODE_ACTIVE: val = ATEST1_OUTPUT_ENABLE_BIT | ISNS_INT_VAL; break; case ISNS_MODE_STANDBY: val = ATEST1_OUTPUT_ENABLE_BIT; break; case ISNS_MODE_OFF: default: val = 0; break; } rc = smb1390_masked_write(chip, CORE_ATEST1_SEL_REG, ATEST1_OUTPUT_ENABLE_BIT | ATEST1_SEL_MASK, val); if (rc < 0) pr_err("Couldn't set CORE_ATEST1_SEL_REG, rc = %d\n", rc); return rc; } static bool is_cps_available(struct smb1390 *chip) { if (!chip->cps_psy) chip->cps_psy = power_supply_get_by_name("cp_slave"); else return true; if (!chip->cps_psy) return false; return true; } static void cp_toggle_switcher(struct smb1390 *chip) { int rc; Loading Loading @@ -320,6 +372,18 @@ static int smb1390_get_cp_en_status(struct smb1390 *chip, int id, bool *enable) return rc; } static int smb1390_set_ilim(struct smb1390 *chip, int ilim_ua) { int rc; rc = smb1390_masked_write(chip, CORE_FTRIM_ILIM_REG, CFG_ILIM_MASK, ilim_ua); if (rc < 0) pr_err("Failed to write ILIM Register, rc=%d\n", rc); return rc; } static irqreturn_t default_irq_handler(int irq, void *data) { struct smb1390 *chip = data; Loading Loading @@ -425,7 +489,13 @@ static int smb1390_get_die_temp(struct smb1390 *chip, return rc; } static int smb1390_get_isns(struct smb1390 *chip, static int smb1390_get_isns(int temp) { /* ISNS = 2 * (1496 - 1390_therm_input * 0.00356) * 1000 uA */ return ((1496 * 1000 - div_s64((s64)temp * 3560, 1000)) * 2); } static int smb1390_get_isns_master(struct smb1390 *chip, union power_supply_propval *val) { int temp = 0; Loading @@ -445,12 +515,105 @@ static int smb1390_get_isns(struct smb1390 *chip, if (!enable) return -ENODATA; /* * Since master and slave share temp_pin line * which is re-used to measure isns, configure the * master as follows: * 1. Put slave in standby mode * 2. Configure master to provide current reading * 3. Read current value * 4. Configure master back to report temperature */ mutex_lock(&chip->die_chan_lock); rc = smb1390_masked_write(chip, CORE_ATEST1_SEL_REG, ATEST1_OUTPUT_ENABLE_BIT | ATEST1_SEL_MASK, ATEST1_OUTPUT_ENABLE_BIT | ISNS_INT_VAL); if (is_cps_available(chip)) { val->intval = ISNS_MODE_STANDBY; rc = power_supply_set_property(chip->cps_psy, POWER_SUPPLY_PROP_CURRENT_CAPABILITY, val); if (rc < 0) { pr_err("Couldn't set CORE_ATEST1_SEL_REG, rc = %d\n", rc); pr_err("Couldn't change slave charging state rc=%d\n", rc); goto unlock; } } rc = smb1390_isns_mode_control(chip, ISNS_MODE_ACTIVE); if (rc < 0) { pr_err("Failed to set master in Active mode, rc=%d\n", rc); goto unlock; } rc = iio_read_channel_processed(chip->iio.die_temp_chan, &temp); if (rc < 0) { pr_err("Couldn't read die_temp chan for isns, rc = %d\n", rc); goto unlock; } rc = smb1390_isns_mode_control(chip, ISNS_MODE_OFF); if (rc < 0) pr_err("Couldn't set master to off mode, rc = %d\n", rc); if (is_cps_available(chip)) { val->intval = ISNS_MODE_OFF; rc = power_supply_set_property(chip->cps_psy, POWER_SUPPLY_PROP_CURRENT_CAPABILITY, val); if (rc < 0) pr_err("Couldn't change slave charging state rc=%d\n", rc); } unlock: mutex_unlock(&chip->die_chan_lock); if (rc >= 0) val->intval = smb1390_get_isns(temp); return rc; } static int smb1390_get_isns_slave(struct smb1390 *chip, union power_supply_propval *val) { int temp = 0; int rc; bool enable; if (!is_cps_available(chip)) { val->intval = 0; return 0; } /* * If SMB1390 chip is not enabled, adc channel read may render * erroneous value. Return error to signify, adc read is not admissible */ rc = smb1390_get_cp_en_status(chip, SMB_PIN_EN, &enable); if (rc < 0) { pr_err("Couldn't get SMB_PIN enable status, rc=%d\n", rc); return rc; } if (!enable) return -ENODATA; /* * Since master and slave share temp_pin line * which is re-used to measure isns, configure the * slave as follows: * 1. Put slave in standby mode * 2. Configure slave to in Active mode to provide current reading * 3. Read current value */ mutex_lock(&chip->die_chan_lock); rc = smb1390_isns_mode_control(chip, ISNS_MODE_STANDBY); if (rc < 0) goto unlock; val->intval = ISNS_MODE_ACTIVE; rc = power_supply_set_property(chip->cps_psy, POWER_SUPPLY_PROP_CURRENT_CAPABILITY, val); if (rc < 0) { pr_err("Couldn't change slave charging state rc=%d\n", rc); goto unlock; } Loading @@ -461,18 +624,23 @@ static int smb1390_get_isns(struct smb1390 *chip, goto unlock; } rc = smb1390_masked_write(chip, CORE_ATEST1_SEL_REG, ATEST1_OUTPUT_ENABLE_BIT | ATEST1_SEL_MASK, 0); val->intval = ISNS_MODE_OFF; rc = power_supply_set_property(chip->cps_psy, POWER_SUPPLY_PROP_CURRENT_CAPABILITY, val); if (rc < 0) pr_err("Couldn't change slave charging state rc=%d\n", rc); rc = smb1390_isns_mode_control(chip, ISNS_MODE_OFF); if (rc < 0) pr_err("Couldn't set CORE_ATEST1_SEL_REG, rc = %d\n", rc); unlock: mutex_unlock(&chip->die_chan_lock); /* ISNS = 2 * (1496 - 1390_therm_input * 0.00356) * 1000 uA */ if (rc >= 0) val->intval = (1496 * 1000 - div_s64((s64)temp * 3560, 1000)) * 2; val->intval = smb1390_get_isns(temp); return rc; } Loading Loading @@ -505,19 +673,17 @@ static int smb1390_disable_vote_cb(struct votable *votable, void *data, { struct smb1390 *chip = data; int rc = 0; u8 mask, val; if (!is_psy_voter_available(chip) || chip->suspended) return -EAGAIN; if (disable) { rc = smb1390_masked_write(chip, CORE_CONTROL1_REG, CMD_EN_SWITCHER_BIT, 0); if (rc < 0) return rc; } else { rc = smb1390_masked_write(chip, CORE_CONTROL1_REG, CMD_EN_SWITCHER_BIT, CMD_EN_SWITCHER_BIT); if (rc < 0) mask = CMD_EN_SWITCHER_BIT | CMD_EN_SL_BIT; val = is_cps_available(chip) ? mask : CMD_EN_SWITCHER_BIT; rc = smb1390_masked_write(chip, CORE_CONTROL1_REG, mask, disable ? 0 : val); if (rc < 0) { pr_err("Couldn't write CORE_CONTROL1_REG, rc=%d\n", rc); return rc; } Loading @@ -533,6 +699,7 @@ static int smb1390_ilim_vote_cb(struct votable *votable, void *data, int ilim_uA, const char *client) { struct smb1390 *chip = data; union power_supply_propval pval = {0, }; int rc = 0; if (!is_psy_voter_available(chip) || chip->suspended) Loading @@ -545,20 +712,31 @@ static int smb1390_ilim_vote_cb(struct votable *votable, void *data, } ilim_uA = min(ilim_uA, MAX_ILIM_UA); rc = smb1390_masked_write(chip, CORE_FTRIM_ILIM_REG, CFG_ILIM_MASK, DIV_ROUND_CLOSEST(max(ilim_uA, 500000) - 500000, 100000)); if (rc < 0) { pr_err("Failed to write ILIM Register, rc=%d\n", rc); return rc; } /* ILIM less than min_ilim_ua, disable charging */ if (ilim_uA < chip->min_ilim_ua) { smb1390_dbg(chip, PR_INFO, "ILIM %duA is too low to allow charging\n", ilim_uA); vote(chip->disable_votable, ILIM_VOTER, true, 0); } else { if (is_cps_available(chip)) { ilim_uA /= 2; pval.intval = DIV_ROUND_CLOSEST(ilim_uA - 500000, 100000); rc = power_supply_set_property(chip->cps_psy, POWER_SUPPLY_PROP_INPUT_CURRENT_MAX, &pval); if (rc < 0) pr_err("Couldn't change slave ilim rc=%d\n", rc); } rc = smb1390_set_ilim(chip, DIV_ROUND_CLOSEST(ilim_uA - 500000, 100000)); if (rc < 0) { pr_err("Failed to set ILIM, rc=%d\n", rc); return rc; } smb1390_dbg(chip, PR_INFO, "ILIM set to %duA\n", ilim_uA); vote(chip->disable_votable, ILIM_VOTER, false, 0); } Loading @@ -566,6 +744,21 @@ static int smb1390_ilim_vote_cb(struct votable *votable, void *data, return rc; } static int smb1390_awake_vote_cb(struct votable *votable, void *data, int awake, const char *client) { struct smb1390 *chip = data; if (awake) __pm_stay_awake(chip->cp_ws); else __pm_relax(chip->cp_ws); smb1390_dbg(chip, PR_INFO, "client: %s awake: %d\n", client, awake); return 0; } static int smb1390_notifier_cb(struct notifier_block *nb, unsigned long event, void *data) { Loading Loading @@ -761,6 +954,7 @@ static enum power_supply_property smb1390_charge_pump_props[] = { POWER_SUPPLY_PROP_CP_SWITCHER_EN, POWER_SUPPLY_PROP_CP_DIE_TEMP, POWER_SUPPLY_PROP_CP_ISNS, POWER_SUPPLY_PROP_CP_ISNS_SLAVE, POWER_SUPPLY_PROP_CP_TOGGLE_SWITCHER, POWER_SUPPLY_PROP_CP_IRQ_STATUS, POWER_SUPPLY_PROP_CP_ILIM, Loading Loading @@ -832,7 +1026,10 @@ static int smb1390_get_prop(struct power_supply *psy, } break; case POWER_SUPPLY_PROP_CP_ISNS: rc = smb1390_get_isns(chip, val); rc = smb1390_get_isns_master(chip, val); break; case POWER_SUPPLY_PROP_CP_ISNS_SLAVE: rc = smb1390_get_isns_slave(chip, val); break; case POWER_SUPPLY_PROP_CP_TOGGLE_SWITCHER: val->intval = 0; Loading Loading @@ -905,6 +1102,8 @@ static int smb1390_prop_is_writeable(struct power_supply *psy, case POWER_SUPPLY_PROP_CP_ENABLE: case POWER_SUPPLY_PROP_CP_TOGGLE_SWITCHER: case POWER_SUPPLY_PROP_CP_IRQ_STATUS: case POWER_SUPPLY_PROP_INPUT_CURRENT_MAX: case POWER_SUPPLY_PROP_CURRENT_CAPABILITY: return 1; default: break; Loading Loading @@ -990,6 +1189,8 @@ static void smb1390_release_channels(struct smb1390 *chip) static int smb1390_create_votables(struct smb1390 *chip) { chip->cp_awake_votable = create_votable("CP_AWAKE", VOTE_SET_ANY, smb1390_awake_vote_cb, chip); chip->disable_votable = create_votable("CP_DISABLE", VOTE_SET_ANY, smb1390_disable_vote_cb, chip); if (IS_ERR(chip->disable_votable)) Loading Loading @@ -1164,14 +1365,23 @@ static void smb1390_create_debugfs(struct smb1390 *chip) } #endif static int smb1390_probe(struct platform_device *pdev) static const struct of_device_id match_table[] = { { .compatible = "qcom,smb1390-charger-psy", .data = (void *)CP_MASTER }, { .compatible = "qcom,smb1390-slave", .data = (void *)CP_SLAVE }, { }, }; static int smb1390_master_probe(struct smb1390 *chip) { struct smb1390 *chip; int rc; struct device_node *revid_dev_node; struct pmic_revid_data *pmic_rev_id; int rc; revid_dev_node = of_parse_phandle(pdev->dev.of_node, revid_dev_node = of_parse_phandle(chip->dev->of_node, "qcom,pmic-revid", 0); if (!revid_dev_node) { pr_err("Missing qcom,pmic-revid property\n"); Loading @@ -1189,23 +1399,9 @@ static int smb1390_probe(struct platform_device *pdev) return -EPROBE_DEFER; } chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; chip->dev = &pdev->dev; chip->pmic_rev_id = pmic_rev_id; spin_lock_init(&chip->status_change_lock); mutex_init(&chip->die_chan_lock); chip->die_temp = -ENODATA; chip->pmic_rev_id = pmic_rev_id; chip->disabled = true; platform_set_drvdata(pdev, chip); chip->regmap = dev_get_regmap(chip->dev->parent, NULL); if (!chip->regmap) { pr_err("Couldn't get regmap\n"); return -EINVAL; } rc = smb1390_parse_dt(chip); if (rc < 0) { Loading Loading @@ -1252,9 +1448,6 @@ static int smb1390_probe(struct platform_device *pdev) } smb1390_create_debugfs(chip); pr_debug("smb1390 probed successfully chip_version=%d\n", chip->pmic_rev_id->rev4); return 0; out_notifier: Loading @@ -1268,10 +1461,166 @@ static int smb1390_probe(struct platform_device *pdev) return rc; } static enum power_supply_property smb1390_cp_slave_props[] = { POWER_SUPPLY_PROP_INPUT_CURRENT_MAX, POWER_SUPPLY_PROP_CURRENT_CAPABILITY, }; static int smb1390_cp_slave_get_prop(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { struct smb1390 *chip = power_supply_get_drvdata(psy); switch (psp) { case POWER_SUPPLY_PROP_INPUT_CURRENT_MAX: val->intval = 0; if (!chip->ilim_votable) chip->ilim_votable = find_votable("CP_ILIM"); if (chip->ilim_votable) val->intval = get_effective_result_locked(chip->ilim_votable); break; case POWER_SUPPLY_PROP_CURRENT_CAPABILITY: val->intval = (int)chip->current_capability; break; default: smb1390_dbg(chip, PR_MISC, "SMB 1390 slave power supply get prop %d not supported\n", psp); return -EINVAL; } return 0; } static int smb1390_cp_slave_set_prop(struct power_supply *psy, enum power_supply_property psp, const union power_supply_propval *val) { struct smb1390 *chip = power_supply_get_drvdata(psy); int rc = 0; switch (psp) { case POWER_SUPPLY_PROP_INPUT_CURRENT_MAX: rc = smb1390_set_ilim(chip, val->intval); break; case POWER_SUPPLY_PROP_CURRENT_CAPABILITY: chip->current_capability = (enum isns_mode)val->intval; rc = smb1390_isns_mode_control(chip, val->intval); break; default: smb1390_dbg(chip, PR_MISC, "SMB 1390 slave power supply set prop %d not supported\n", psp); return -EINVAL; } return 0; }; static const struct power_supply_desc cps_psy_desc = { .name = "cp_slave", .type = POWER_SUPPLY_TYPE_PARALLEL, .properties = smb1390_cp_slave_props, .num_properties = ARRAY_SIZE(smb1390_cp_slave_props), .get_property = smb1390_cp_slave_get_prop, .set_property = smb1390_cp_slave_set_prop, .property_is_writeable = smb1390_prop_is_writeable, }; static int smb1390_init_cps_psy(struct smb1390 *chip) { struct power_supply_config cps_cfg = {}; cps_cfg.drv_data = chip; cps_cfg.of_node = chip->dev->of_node; chip->cps_psy = devm_power_supply_register(chip->dev, &cps_psy_desc, &cps_cfg); if (IS_ERR(chip->cps_psy)) { pr_err("Couldn't register CP slave power supply\n"); return PTR_ERR(chip->cps_psy); } return 0; } static int smb1390_slave_probe(struct smb1390 *chip) { int stat, rc; /* a "hello" read to test the presence of the slave PMIC */ rc = smb1390_read(chip, CORE_STATUS1_REG, &stat); if (rc < 0) { pr_err("Couldn't find slave SMB1390\n"); return -EINVAL; } rc = smb1390_init_cps_psy(chip); if (rc < 0) pr_err("Couldn't initialize cps psy rc=%d\n", rc); return rc; } static int smb1390_probe(struct platform_device *pdev) { struct smb1390 *chip; int rc; chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; chip->dev = &pdev->dev; chip->die_temp = -ENODATA; chip->disabled = true; chip->regmap = dev_get_regmap(chip->dev->parent, NULL); if (!chip->regmap) { pr_err("Couldn't get regmap\n"); return -EINVAL; } platform_set_drvdata(pdev, chip); chip->cp_role = (int)of_device_get_match_data(chip->dev); switch (chip->cp_role) { case CP_MASTER: rc = smb1390_master_probe(chip); break; case CP_SLAVE: rc = smb1390_slave_probe(chip); break; default: pr_err("Couldn't find a matching role %d\n", chip->cp_role); rc = -EINVAL; goto cleanup; } if (rc < 0) { if (rc != -EPROBE_DEFER) pr_err("Couldn't probe SMB1390 %s rc=%d\n", chip->cp_role ? "Slave" : "Master", rc); goto cleanup; } pr_info("smb1390 %s probed successfully\n", chip->cp_role ? "Slave" : "Master"); return 0; cleanup: platform_set_drvdata(pdev, NULL); return rc; } static int smb1390_remove(struct platform_device *pdev) { struct smb1390 *chip = platform_get_drvdata(pdev); if (chip->cp_role != CP_MASTER) { platform_set_drvdata(pdev, NULL); return 0; } power_supply_unreg_notifier(&chip->nb); /* explicitly disable charging */ Loading @@ -1282,6 +1631,7 @@ static int smb1390_remove(struct platform_device *pdev) wakeup_source_unregister(chip->cp_ws); smb1390_destroy_votables(chip); smb1390_release_channels(chip); platform_set_drvdata(pdev, NULL); return 0; } Loading Loading @@ -1323,11 +1673,6 @@ static const struct dev_pm_ops smb1390_pm_ops = { .resume = smb1390_resume, }; static const struct of_device_id match_table[] = { { .compatible = "qcom,smb1390-charger-psy", }, { }, }; static struct platform_driver smb1390_driver = { .driver = { .name = "qcom,smb1390-charger-psy", Loading