Loading drivers/mfd/qcom-i2c-pmic.c +74 −1 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * Copyright (c) 2016-2017, 2020, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "I2C PMIC: %s: " fmt, __func__ Loading Loading @@ -61,6 +61,7 @@ struct i2c_pmic { int summary_irq; bool resume_completed; bool irq_waiting; bool toggle_stat; }; static void i2c_pmic_irq_bus_lock(struct irq_data *d) Loading Loading @@ -473,6 +474,9 @@ static int i2c_pmic_parse_dt(struct i2c_pmic *chip) of_property_read_string(node, "pinctrl-names", &chip->pinctrl_name); chip->toggle_stat = of_property_read_bool(node, "qcom,enable-toggle-stat"); return rc; } Loading Loading @@ -513,6 +517,69 @@ static int i2c_pmic_determine_initial_status(struct i2c_pmic *chip) return 0; } #define INT_TEST_OFFSET 0xE0 #define INT_TEST_MODE_EN_BIT BIT(7) #define INT_TEST_VAL_OFFSET 0xE1 #define INT_0_BIT BIT(0) static int i2c_pmic_toggle_stat(struct i2c_pmic *chip) { int rc = 0, i; if (!chip->toggle_stat || !chip->num_periphs) return 0; rc = regmap_write(chip->regmap, chip->periph[0].addr | INT_EN_SET_OFFSET, INT_0_BIT); if (rc < 0) { pr_err("Couldn't write to int_en_set rc=%d\n", rc); return rc; } rc = regmap_write(chip->regmap, chip->periph[0].addr | INT_TEST_OFFSET, INT_TEST_MODE_EN_BIT); if (rc < 0) { pr_err("Couldn't write to int_test rc=%d\n", rc); return rc; } for (i = 0; i < 5; i++) { rc = regmap_write(chip->regmap, chip->periph[0].addr | INT_TEST_VAL_OFFSET, INT_0_BIT); if (rc < 0) { pr_err("Couldn't write to int_test_val rc=%d\n", rc); goto exit; } usleep_range(10000, 11000); rc = regmap_write(chip->regmap, chip->periph[0].addr | INT_TEST_VAL_OFFSET, 0); if (rc < 0) { pr_err("Couldn't write to int_test_val rc=%d\n", rc); goto exit; } rc = regmap_write(chip->regmap, chip->periph[0].addr | INT_LATCHED_CLR_OFFSET, INT_0_BIT); if (rc < 0) { pr_err("Couldn't write to int_latched_clr rc=%d\n", rc); goto exit; } usleep_range(10000, 11000); } exit: regmap_write(chip->regmap, chip->periph[0].addr | INT_TEST_OFFSET, 0); regmap_write(chip->regmap, chip->periph[0].addr | INT_EN_CLR_OFFSET, INT_0_BIT); return rc; } static struct regmap_config i2c_pmic_regmap_config = { .reg_bits = 16, .val_bits = 8, Loading Loading @@ -571,6 +638,12 @@ static int i2c_pmic_probe(struct i2c_client *client, chip->resume_completed = true; mutex_init(&chip->irq_complete); rc = i2c_pmic_toggle_stat(chip); if (rc < 0) { pr_err("Couldn't toggle stat rc=%d\n", rc); goto cleanup; } rc = devm_request_threaded_irq(&client->dev, client->irq, NULL, i2c_pmic_irq_handler, IRQF_ONESHOT | IRQF_SHARED, Loading drivers/power/supply/qcom/qpnp-smb5.c +81 −1 Original line number Diff line number Diff line Loading @@ -724,6 +724,46 @@ static int smb5_parse_dt_voltages(struct smb5 *chip, struct device_node *node) return 0; } static int smb5_parse_sdam(struct smb5 *chip, struct device_node *node) { struct device_node *child; struct smb_charger *chg = &chip->chg; struct property *prop; const char *name; int rc; u32 base; u8 type; for_each_available_child_of_node(node, child) { of_property_for_each_string(child, "reg", prop, name) { rc = of_property_read_u32(child, "reg", &base); if (rc < 0) { pr_err("Failed to read base rc=%d\n", rc); return rc; } rc = smblib_read(chg, base + PERPH_TYPE_OFFSET, &type); if (rc < 0) { pr_err("Failed to read type rc=%d\n", rc); return rc; } switch (type) { case SDAM_TYPE: chg->sdam_base = base; break; default: break; } } } if (!chg->sdam_base) pr_debug("SDAM node not defined\n"); return 0; } static int smb5_parse_dt(struct smb5 *chip) { struct smb_charger *chg = &chip->chg; Loading Loading @@ -751,6 +791,10 @@ static int smb5_parse_dt(struct smb5 *chip) if (rc < 0) return rc; rc = smb5_parse_sdam(chip, node); if (rc < 0) return rc; return 0; } Loading Loading @@ -822,6 +866,8 @@ static enum power_supply_property smb5_usb_props[] = { POWER_SUPPLY_PROP_SKIN_HEALTH, POWER_SUPPLY_PROP_APSD_RERUN, POWER_SUPPLY_PROP_APSD_TIMEOUT, POWER_SUPPLY_PROP_CHARGER_STATUS, POWER_SUPPLY_PROP_INPUT_VOLTAGE_SETTLED, }; static int smb5_usb_get_prop(struct power_supply *psy, Loading @@ -831,6 +877,7 @@ static int smb5_usb_get_prop(struct power_supply *psy, struct smb5 *chip = power_supply_get_drvdata(psy); struct smb_charger *chg = &chip->chg; int rc = 0; u8 reg = 0, buff[2] = {0}; val->intval = 0; switch (psp) { Loading Loading @@ -971,6 +1018,24 @@ static int smb5_usb_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_APSD_TIMEOUT: val->intval = chg->apsd_ext_timeout; break; case POWER_SUPPLY_PROP_CHARGER_STATUS: val->intval = 0; if (chg->sdam_base) { rc = smblib_read(chg, chg->sdam_base + SDAM_QC_DET_STATUS_REG, ®); if (!rc) val->intval = reg; } break; case POWER_SUPPLY_PROP_INPUT_VOLTAGE_SETTLED: val->intval = 0; if (chg->sdam_base) { rc = smblib_batch_read(chg, chg->sdam_base + SDAM_QC_ADC_LSB_REG, buff, 2); if (!rc) val->intval = (buff[1] << 8 | buff[0]) * 1038; } break; default: pr_err("get prop %d is not supported in usb\n", psp); rc = -EINVAL; Loading Loading @@ -2568,11 +2633,23 @@ static int smb5_init_hw(struct smb5 *chip) { struct smb_charger *chg = &chip->chg; int rc; u8 val = 0, mask = 0; u8 val = 0, mask = 0, buf[2] = {0}; if (chip->dt.no_battery) chg->fake_capacity = 50; if (chg->sdam_base) { rc = smblib_write(chg, chg->sdam_base + SDAM_QC_DET_STATUS_REG, 0); if (rc < 0) pr_err("Couldn't clear SDAM QC status rc=%d\n", rc); rc = smblib_batch_write(chg, chg->sdam_base + SDAM_QC_ADC_LSB_REG, buf, 2); if (rc < 0) pr_err("Couldn't clear SDAM ADC status rc=%d\n", rc); } if (chip->dt.batt_profile_fcc_ua < 0) smblib_get_charge_param(chg, &chg->param.fcc, &chg->batt_profile_fcc_ua); Loading Loading @@ -3628,6 +3705,9 @@ static void smb5_shutdown(struct platform_device *pdev) /* disable all interrupts */ smb5_disable_interrupts(chg); /* disable the SMB_EN configuration */ smblib_masked_write(chg, MISC_SMB_EN_CMD_REG, EN_CP_CMD_BIT, 0); /* configure power role for UFP */ if (chg->connector_type == POWER_SUPPLY_CONNECTOR_TYPEC) smblib_masked_write(chg, TYPE_C_MODE_CFG_REG, Loading drivers/power/supply/qcom/smb5-lib.c +13 −0 Original line number Diff line number Diff line Loading @@ -5905,6 +5905,7 @@ static void typec_src_removal(struct smb_charger *chg) struct smb_irq_data *data; struct storm_watch *wdata; int sec_charger; u8 val[2] = {0}; sec_charger = chg->sec_pl_present ? POWER_SUPPLY_CHARGER_SEC_PL : POWER_SUPPLY_CHARGER_SEC_NONE; Loading Loading @@ -5995,6 +5996,18 @@ static void typec_src_removal(struct smb_charger *chg) smblib_err(chg, "Couldn't write float charger options rc=%d\n", rc); if (chg->sdam_base) { rc = smblib_write(chg, chg->sdam_base + SDAM_QC_DET_STATUS_REG, 0); if (rc < 0) pr_err("Couldn't clear SDAM QC status rc=%d\n", rc); rc = smblib_batch_write(chg, chg->sdam_base + SDAM_QC_ADC_LSB_REG, val, 2); if (rc < 0) pr_err("Couldn't clear SDAM ADC status rc=%d\n", rc); } if (!chg->pr_swap_in_progress) { rc = smblib_usb_pd_adapter_allowance_override(chg, FORCE_NULL); if (rc < 0) Loading drivers/power/supply/qcom/smb5-lib.h +1 −0 Original line number Diff line number Diff line Loading @@ -382,6 +382,7 @@ struct smb_charger { struct smb_chg_freq chg_freq; int otg_delay_ms; int weak_chg_icl_ua; u32 sdam_base; bool pd_not_supported; /* locks */ Loading drivers/power/supply/qcom/smb5-reg.h +5 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ #define PERPH_SUBTYPE_OFFSET 0x05 #define SUBTYPE_MASK GENMASK(7, 0) #define INT_RT_STS_OFFSET 0x10 #define SDAM_TYPE 0x2E /******************************** * CHGR Peripheral Registers * Loading Loading @@ -549,4 +550,8 @@ enum { /* SDAM regs */ #define MISC_PBS_RT_STS_REG (MISC_PBS_BASE + 0x10) #define PULSE_SKIP_IRQ_BIT BIT(4) #define SDAM_QC_DET_STATUS_REG 0x58 #define SDAM_QC_ADC_LSB_REG 0x54 #endif /* __SMB5_CHARGER_REG_H */ Loading
drivers/mfd/qcom-i2c-pmic.c +74 −1 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * Copyright (c) 2016-2017, 2020, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "I2C PMIC: %s: " fmt, __func__ Loading Loading @@ -61,6 +61,7 @@ struct i2c_pmic { int summary_irq; bool resume_completed; bool irq_waiting; bool toggle_stat; }; static void i2c_pmic_irq_bus_lock(struct irq_data *d) Loading Loading @@ -473,6 +474,9 @@ static int i2c_pmic_parse_dt(struct i2c_pmic *chip) of_property_read_string(node, "pinctrl-names", &chip->pinctrl_name); chip->toggle_stat = of_property_read_bool(node, "qcom,enable-toggle-stat"); return rc; } Loading Loading @@ -513,6 +517,69 @@ static int i2c_pmic_determine_initial_status(struct i2c_pmic *chip) return 0; } #define INT_TEST_OFFSET 0xE0 #define INT_TEST_MODE_EN_BIT BIT(7) #define INT_TEST_VAL_OFFSET 0xE1 #define INT_0_BIT BIT(0) static int i2c_pmic_toggle_stat(struct i2c_pmic *chip) { int rc = 0, i; if (!chip->toggle_stat || !chip->num_periphs) return 0; rc = regmap_write(chip->regmap, chip->periph[0].addr | INT_EN_SET_OFFSET, INT_0_BIT); if (rc < 0) { pr_err("Couldn't write to int_en_set rc=%d\n", rc); return rc; } rc = regmap_write(chip->regmap, chip->periph[0].addr | INT_TEST_OFFSET, INT_TEST_MODE_EN_BIT); if (rc < 0) { pr_err("Couldn't write to int_test rc=%d\n", rc); return rc; } for (i = 0; i < 5; i++) { rc = regmap_write(chip->regmap, chip->periph[0].addr | INT_TEST_VAL_OFFSET, INT_0_BIT); if (rc < 0) { pr_err("Couldn't write to int_test_val rc=%d\n", rc); goto exit; } usleep_range(10000, 11000); rc = regmap_write(chip->regmap, chip->periph[0].addr | INT_TEST_VAL_OFFSET, 0); if (rc < 0) { pr_err("Couldn't write to int_test_val rc=%d\n", rc); goto exit; } rc = regmap_write(chip->regmap, chip->periph[0].addr | INT_LATCHED_CLR_OFFSET, INT_0_BIT); if (rc < 0) { pr_err("Couldn't write to int_latched_clr rc=%d\n", rc); goto exit; } usleep_range(10000, 11000); } exit: regmap_write(chip->regmap, chip->periph[0].addr | INT_TEST_OFFSET, 0); regmap_write(chip->regmap, chip->periph[0].addr | INT_EN_CLR_OFFSET, INT_0_BIT); return rc; } static struct regmap_config i2c_pmic_regmap_config = { .reg_bits = 16, .val_bits = 8, Loading Loading @@ -571,6 +638,12 @@ static int i2c_pmic_probe(struct i2c_client *client, chip->resume_completed = true; mutex_init(&chip->irq_complete); rc = i2c_pmic_toggle_stat(chip); if (rc < 0) { pr_err("Couldn't toggle stat rc=%d\n", rc); goto cleanup; } rc = devm_request_threaded_irq(&client->dev, client->irq, NULL, i2c_pmic_irq_handler, IRQF_ONESHOT | IRQF_SHARED, Loading
drivers/power/supply/qcom/qpnp-smb5.c +81 −1 Original line number Diff line number Diff line Loading @@ -724,6 +724,46 @@ static int smb5_parse_dt_voltages(struct smb5 *chip, struct device_node *node) return 0; } static int smb5_parse_sdam(struct smb5 *chip, struct device_node *node) { struct device_node *child; struct smb_charger *chg = &chip->chg; struct property *prop; const char *name; int rc; u32 base; u8 type; for_each_available_child_of_node(node, child) { of_property_for_each_string(child, "reg", prop, name) { rc = of_property_read_u32(child, "reg", &base); if (rc < 0) { pr_err("Failed to read base rc=%d\n", rc); return rc; } rc = smblib_read(chg, base + PERPH_TYPE_OFFSET, &type); if (rc < 0) { pr_err("Failed to read type rc=%d\n", rc); return rc; } switch (type) { case SDAM_TYPE: chg->sdam_base = base; break; default: break; } } } if (!chg->sdam_base) pr_debug("SDAM node not defined\n"); return 0; } static int smb5_parse_dt(struct smb5 *chip) { struct smb_charger *chg = &chip->chg; Loading Loading @@ -751,6 +791,10 @@ static int smb5_parse_dt(struct smb5 *chip) if (rc < 0) return rc; rc = smb5_parse_sdam(chip, node); if (rc < 0) return rc; return 0; } Loading Loading @@ -822,6 +866,8 @@ static enum power_supply_property smb5_usb_props[] = { POWER_SUPPLY_PROP_SKIN_HEALTH, POWER_SUPPLY_PROP_APSD_RERUN, POWER_SUPPLY_PROP_APSD_TIMEOUT, POWER_SUPPLY_PROP_CHARGER_STATUS, POWER_SUPPLY_PROP_INPUT_VOLTAGE_SETTLED, }; static int smb5_usb_get_prop(struct power_supply *psy, Loading @@ -831,6 +877,7 @@ static int smb5_usb_get_prop(struct power_supply *psy, struct smb5 *chip = power_supply_get_drvdata(psy); struct smb_charger *chg = &chip->chg; int rc = 0; u8 reg = 0, buff[2] = {0}; val->intval = 0; switch (psp) { Loading Loading @@ -971,6 +1018,24 @@ static int smb5_usb_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_APSD_TIMEOUT: val->intval = chg->apsd_ext_timeout; break; case POWER_SUPPLY_PROP_CHARGER_STATUS: val->intval = 0; if (chg->sdam_base) { rc = smblib_read(chg, chg->sdam_base + SDAM_QC_DET_STATUS_REG, ®); if (!rc) val->intval = reg; } break; case POWER_SUPPLY_PROP_INPUT_VOLTAGE_SETTLED: val->intval = 0; if (chg->sdam_base) { rc = smblib_batch_read(chg, chg->sdam_base + SDAM_QC_ADC_LSB_REG, buff, 2); if (!rc) val->intval = (buff[1] << 8 | buff[0]) * 1038; } break; default: pr_err("get prop %d is not supported in usb\n", psp); rc = -EINVAL; Loading Loading @@ -2568,11 +2633,23 @@ static int smb5_init_hw(struct smb5 *chip) { struct smb_charger *chg = &chip->chg; int rc; u8 val = 0, mask = 0; u8 val = 0, mask = 0, buf[2] = {0}; if (chip->dt.no_battery) chg->fake_capacity = 50; if (chg->sdam_base) { rc = smblib_write(chg, chg->sdam_base + SDAM_QC_DET_STATUS_REG, 0); if (rc < 0) pr_err("Couldn't clear SDAM QC status rc=%d\n", rc); rc = smblib_batch_write(chg, chg->sdam_base + SDAM_QC_ADC_LSB_REG, buf, 2); if (rc < 0) pr_err("Couldn't clear SDAM ADC status rc=%d\n", rc); } if (chip->dt.batt_profile_fcc_ua < 0) smblib_get_charge_param(chg, &chg->param.fcc, &chg->batt_profile_fcc_ua); Loading Loading @@ -3628,6 +3705,9 @@ static void smb5_shutdown(struct platform_device *pdev) /* disable all interrupts */ smb5_disable_interrupts(chg); /* disable the SMB_EN configuration */ smblib_masked_write(chg, MISC_SMB_EN_CMD_REG, EN_CP_CMD_BIT, 0); /* configure power role for UFP */ if (chg->connector_type == POWER_SUPPLY_CONNECTOR_TYPEC) smblib_masked_write(chg, TYPE_C_MODE_CFG_REG, Loading
drivers/power/supply/qcom/smb5-lib.c +13 −0 Original line number Diff line number Diff line Loading @@ -5905,6 +5905,7 @@ static void typec_src_removal(struct smb_charger *chg) struct smb_irq_data *data; struct storm_watch *wdata; int sec_charger; u8 val[2] = {0}; sec_charger = chg->sec_pl_present ? POWER_SUPPLY_CHARGER_SEC_PL : POWER_SUPPLY_CHARGER_SEC_NONE; Loading Loading @@ -5995,6 +5996,18 @@ static void typec_src_removal(struct smb_charger *chg) smblib_err(chg, "Couldn't write float charger options rc=%d\n", rc); if (chg->sdam_base) { rc = smblib_write(chg, chg->sdam_base + SDAM_QC_DET_STATUS_REG, 0); if (rc < 0) pr_err("Couldn't clear SDAM QC status rc=%d\n", rc); rc = smblib_batch_write(chg, chg->sdam_base + SDAM_QC_ADC_LSB_REG, val, 2); if (rc < 0) pr_err("Couldn't clear SDAM ADC status rc=%d\n", rc); } if (!chg->pr_swap_in_progress) { rc = smblib_usb_pd_adapter_allowance_override(chg, FORCE_NULL); if (rc < 0) Loading
drivers/power/supply/qcom/smb5-lib.h +1 −0 Original line number Diff line number Diff line Loading @@ -382,6 +382,7 @@ struct smb_charger { struct smb_chg_freq chg_freq; int otg_delay_ms; int weak_chg_icl_ua; u32 sdam_base; bool pd_not_supported; /* locks */ Loading
drivers/power/supply/qcom/smb5-reg.h +5 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ #define PERPH_SUBTYPE_OFFSET 0x05 #define SUBTYPE_MASK GENMASK(7, 0) #define INT_RT_STS_OFFSET 0x10 #define SDAM_TYPE 0x2E /******************************** * CHGR Peripheral Registers * Loading Loading @@ -549,4 +550,8 @@ enum { /* SDAM regs */ #define MISC_PBS_RT_STS_REG (MISC_PBS_BASE + 0x10) #define PULSE_SKIP_IRQ_BIT BIT(4) #define SDAM_QC_DET_STATUS_REG 0x58 #define SDAM_QC_ADC_LSB_REG 0x54 #endif /* __SMB5_CHARGER_REG_H */