Loading Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt +5 −0 Original line number Original line Diff line number Diff line Loading @@ -56,6 +56,10 @@ Optional properties: reset through qcom,system-reset property. reset through qcom,system-reset property. This should not be defined along with the This should not be defined along with the qcom,system-reset property. qcom,system-reset property. - qcom,store-hard-reset-reason Boolean property which if set will store the hardware reset reason to SOFT_RB_SPARE register of the core PMIC PON peripheral. All the below properties are in the sub-node section (properties of the child All the below properties are in the sub-node section (properties of the child node). node). Loading Loading @@ -113,6 +117,7 @@ Example: qcom,s3-debounce = <32>; qcom,s3-debounce = <32>; qcom,s3-src = "resin"; qcom,s3-src = "resin"; qcom,clear-warm-reset; qcom,clear-warm-reset; qcom,store-hard-reset-reason; qcom,pon_1 { qcom,pon_1 { qcom,pon-type = <0>; qcom,pon-type = <0>; Loading drivers/platform/msm/qpnp-power-on.c +65 −1 Original line number Original line Diff line number Diff line Loading @@ -27,6 +27,11 @@ #include <linux/log2.h> #include <linux/log2.h> #include <linux/qpnp/power-on.h> #include <linux/qpnp/power-on.h> #define CREATE_MASK(NUM_BITS, POS) \ ((unsigned char) (((1 << (NUM_BITS)) - 1) << (POS))) #define PON_MASK(MSB_BIT, LSB_BIT) \ CREATE_MASK(MSB_BIT - LSB_BIT + 1, LSB_BIT) #define PMIC_VER_8941 0x01 #define PMIC_VER_8941 0x01 #define PMIC_VERSION_REG 0x0105 #define PMIC_VERSION_REG 0x0105 #define PMIC_VERSION_REV4_REG 0x0103 #define PMIC_VERSION_REV4_REG 0x0103 Loading Loading @@ -68,6 +73,7 @@ #define QPNP_PON_S3_DBC_CTL(base) (base + 0x75) #define QPNP_PON_S3_DBC_CTL(base) (base + 0x75) #define QPNP_PON_TRIGGER_EN(base) (base + 0x80) #define QPNP_PON_TRIGGER_EN(base) (base + 0x80) #define QPNP_PON_XVDD_RB_SPARE(base) (base + 0x8E) #define QPNP_PON_XVDD_RB_SPARE(base) (base + 0x8E) #define QPNP_PON_SOFT_RB_SPARE(base) (base + 0x8F) #define QPNP_PON_SEC_ACCESS(base) (base + 0xD0) #define QPNP_PON_SEC_ACCESS(base) (base + 0xD0) #define QPNP_PON_SEC_UNLOCK 0xA5 #define QPNP_PON_SEC_UNLOCK 0xA5 Loading Loading @@ -101,6 +107,7 @@ #define QPNP_PON_S3_SRC_KPDPWR_AND_RESIN 2 #define QPNP_PON_S3_SRC_KPDPWR_AND_RESIN 2 #define QPNP_PON_S3_SRC_KPDPWR_OR_RESIN 3 #define QPNP_PON_S3_SRC_KPDPWR_OR_RESIN 3 #define QPNP_PON_S3_SRC_MASK 0x3 #define QPNP_PON_S3_SRC_MASK 0x3 #define QPNP_PON_HARD_RESET_MASK PON_MASK(7, 5) #define QPNP_PON_UVLO_DLOAD_EN BIT(7) #define QPNP_PON_UVLO_DLOAD_EN BIT(7) Loading Loading @@ -160,6 +167,7 @@ struct qpnp_pon { u8 warm_reset_reason1; u8 warm_reset_reason1; u8 warm_reset_reason2; u8 warm_reset_reason2; bool is_spon; bool is_spon; bool store_hard_reset_reason; }; }; static struct qpnp_pon *sys_reset_dev; static struct qpnp_pon *sys_reset_dev; Loading Loading @@ -235,6 +243,56 @@ qpnp_pon_masked_write(struct qpnp_pon *pon, u16 addr, u8 mask, u8 val) return rc; return rc; } } /** * qpnp_pon_set_restart_reason - Store device restart reason in PMIC register. * * Returns = 0 if PMIC feature is not available or store restart reason * successfully. * Returns > 0 for errors * * This function is used to store device restart reason in PMIC register. * It checks here to see if the restart reason register has been specified. * If it hasn't, this function should immediately return 0 */ int qpnp_pon_set_restart_reason(enum pon_restart_reason reason) { int rc = 0; struct qpnp_pon *pon = sys_reset_dev; if (!pon) return 0; if (!pon->store_hard_reset_reason) return 0; rc = qpnp_pon_masked_write(pon, QPNP_PON_SOFT_RB_SPARE(pon->base), PON_MASK(7, 5), (reason << 5)); if (rc) dev_err(&pon->spmi->dev, "Unable to write to addr=%x, rc(%d)\n", QPNP_PON_SOFT_RB_SPARE(pon->base), rc); return rc; } EXPORT_SYMBOL(qpnp_pon_set_restart_reason); /* * qpnp_pon_check_hard_reset_stored - Checks if the PMIC need to * store hard reset reason. * * Returns true if reset reason can be stored, false if it cannot be stored * */ bool qpnp_pon_check_hard_reset_stored(void) { struct qpnp_pon *pon = sys_reset_dev; if (!pon) return false; return pon->store_hard_reset_reason; } EXPORT_SYMBOL(qpnp_pon_check_hard_reset_stored); static int qpnp_pon_set_dbc(struct qpnp_pon *pon, u32 delay) static int qpnp_pon_set_dbc(struct qpnp_pon *pon, u32 delay) { { int rc = 0; int rc = 0; Loading Loading @@ -1564,7 +1622,6 @@ static int qpnp_pon_probe(struct spmi_device *spmi) return rc; return rc; } } boot_reason = ffs(pon_sts); index = ffs(pon_sts) - 1; index = ffs(pon_sts) - 1; cold_boot = !qpnp_pon_is_warm_reset(); cold_boot = !qpnp_pon_is_warm_reset(); Loading Loading @@ -1720,8 +1777,15 @@ static int qpnp_pon_probe(struct spmi_device *spmi) list_add(&pon->list, &spon_dev_list); list_add(&pon->list, &spon_dev_list); mutex_unlock(&spon_list_mutex); mutex_unlock(&spon_list_mutex); pon->is_spon = true; pon->is_spon = true; } else { boot_reason = ffs(pon_sts); } } /* config whether store the hard reset reason */ pon->store_hard_reset_reason = of_property_read_bool( spmi->dev.of_node, "qcom,store-hard-reset-reason"); qpnp_pon_debugfs_init(spmi); qpnp_pon_debugfs_init(spmi); return 0; return 0; } } Loading drivers/power/qpnp-fg.c +225 −2 Original line number Original line Diff line number Diff line Loading @@ -100,6 +100,15 @@ enum pmic_subtype { PMI8950 = 17, PMI8950 = 17, }; }; enum wa_flags { IADC_GAIN_COMP_WA = BIT(0), }; enum current_sense_type { INTERNAL_CURRENT_SENSE, EXTERNAL_CURRENT_SENSE, }; struct fg_mem_setting { struct fg_mem_setting { u16 address; u16 address; u8 offset; u8 offset; Loading Loading @@ -151,6 +160,12 @@ struct fg_cyc_ctr_data { struct mutex lock; struct mutex lock; }; }; struct fg_iadc_comp_data { u8 dfl_gain_reg[2]; bool gain_active; int64_t dfl_gain; }; /* FG_MEMIF setting index */ /* FG_MEMIF setting index */ enum fg_mem_setting_index { enum fg_mem_setting_index { FG_MEM_SOFT_COLD = 0, FG_MEM_SOFT_COLD = 0, Loading Loading @@ -373,6 +388,7 @@ struct fg_chip { u16 vbat_adc_addr; u16 vbat_adc_addr; u16 ibat_adc_addr; u16 ibat_adc_addr; u16 tp_rev_addr; u16 tp_rev_addr; u32 wa_flag; atomic_t memif_user_cnt; atomic_t memif_user_cnt; struct fg_irq soc_irq[FG_SOC_IRQ_COUNT]; struct fg_irq soc_irq[FG_SOC_IRQ_COUNT]; struct fg_irq batt_irq[FG_BATT_IRQ_COUNT]; struct fg_irq batt_irq[FG_BATT_IRQ_COUNT]; Loading @@ -394,6 +410,7 @@ struct fg_chip { struct work_struct sysfs_restart_work; struct work_struct sysfs_restart_work; struct work_struct init_work; struct work_struct init_work; struct work_struct charge_full_work; struct work_struct charge_full_work; struct work_struct gain_comp_work; struct power_supply *batt_psy; struct power_supply *batt_psy; struct power_supply *usb_psy; struct power_supply *usb_psy; struct power_supply *dc_psy; struct power_supply *dc_psy; Loading @@ -401,6 +418,7 @@ struct fg_chip { struct fg_wakeup_source profile_wakeup_source; struct fg_wakeup_source profile_wakeup_source; struct fg_wakeup_source empty_check_wakeup_source; struct fg_wakeup_source empty_check_wakeup_source; struct fg_wakeup_source resume_soc_wakeup_source; struct fg_wakeup_source resume_soc_wakeup_source; struct fg_wakeup_source gain_comp_wakeup_source; bool first_profile_loaded; bool first_profile_loaded; struct fg_wakeup_source update_temp_wakeup_source; struct fg_wakeup_source update_temp_wakeup_source; struct fg_wakeup_source update_sram_wakeup_source; struct fg_wakeup_source update_sram_wakeup_source; Loading @@ -417,6 +435,8 @@ struct fg_chip { bool vbat_low_irq_enabled; bool vbat_low_irq_enabled; bool charge_full; bool charge_full; bool hold_soc_while_full; bool hold_soc_while_full; bool input_present; bool otg_present; struct delayed_work update_jeita_setting; struct delayed_work update_jeita_setting; struct delayed_work update_sram_data; struct delayed_work update_sram_data; struct delayed_work update_temp_work; struct delayed_work update_temp_work; Loading Loading @@ -449,9 +469,12 @@ struct fg_chip { struct fg_rslow_data rslow_comp; struct fg_rslow_data rslow_comp; /* cycle counter */ /* cycle counter */ struct fg_cyc_ctr_data cyc_ctr; struct fg_cyc_ctr_data cyc_ctr; /* iadc compensation */ struct fg_iadc_comp_data iadc_comp_data; /* interleaved memory access */ /* interleaved memory access */ u16 *offset; u16 *offset; bool ima_supported; bool ima_supported; bool init_done; }; }; /* FG_MEMIF DEBUGFS structures */ /* FG_MEMIF DEBUGFS structures */ Loading Loading @@ -1876,6 +1899,8 @@ static int64_t twos_compliment_extend(int64_t val, int nbytes) return val; return val; } } #define LSB_24B_NUMRTR 596046 #define LSB_24B_DENMTR 1000000 #define LSB_16B_NUMRTR 152587 #define LSB_16B_NUMRTR 152587 #define LSB_16B_DENMTR 1000 #define LSB_16B_DENMTR 1000 #define LSB_8B 9800 #define LSB_8B 9800 Loading Loading @@ -3021,6 +3046,19 @@ static bool is_input_present(struct fg_chip *chip) return is_usb_present(chip) || is_dc_present(chip); return is_usb_present(chip) || is_dc_present(chip); } } static bool is_otg_present(struct fg_chip *chip) { union power_supply_propval prop = {0,}; if (!chip->usb_psy) chip->usb_psy = power_supply_get_by_name("usb"); if (chip->usb_psy) chip->usb_psy->get_property(chip->usb_psy, POWER_SUPPLY_PROP_USB_OTG, &prop); return prop.intval != 0; } static void status_change_work(struct work_struct *work) static void status_change_work(struct work_struct *work) { { struct fg_chip *chip = container_of(work, struct fg_chip *chip = container_of(work, Loading Loading @@ -3073,6 +3111,26 @@ static void status_change_work(struct work_struct *work) } } } } /* * Check for change in the status of input or OTG and schedule * IADC gain compensation work. */ static void check_gain_compensation(struct fg_chip *chip) { bool input_present = is_input_present(chip); bool otg_present = is_otg_present(chip); if ((chip->wa_flag & IADC_GAIN_COMP_WA) && ((chip->input_present ^ input_present) || (chip->otg_present ^ otg_present))) { fg_stay_awake(&chip->gain_comp_wakeup_source); chip->input_present = input_present; chip->otg_present = otg_present; cancel_work_sync(&chip->gain_comp_work); schedule_work(&chip->gain_comp_work); } } static int fg_power_set_property(struct power_supply *psy, static int fg_power_set_property(struct power_supply *psy, enum power_supply_property psp, enum power_supply_property psp, const union power_supply_propval *val) const union power_supply_propval *val) Loading @@ -3095,6 +3153,7 @@ static int fg_power_set_property(struct power_supply *psy, chip->prev_status = chip->status; chip->prev_status = chip->status; chip->status = val->intval; chip->status = val->intval; schedule_work(&chip->status_change_work); schedule_work(&chip->status_change_work); check_gain_compensation(chip); break; break; case POWER_SUPPLY_PROP_HEALTH: case POWER_SUPPLY_PROP_HEALTH: chip->health = val->intval; chip->health = val->intval; Loading Loading @@ -3242,6 +3301,96 @@ static void update_esr_value(struct work_struct *work) } } } } #define TEMP_COUNTER_REG 0x580 #define VBAT_FILTERED_OFFSET 1 #define GAIN_REG 0x424 #define GAIN_OFFSET 1 #define K_VCOR_REG 0x484 #define DEF_GAIN_OFFSET 2 #define PICO_UNIT 0xE8D4A51000LL #define ATTO_UNIT 0xDE0B6B3A7640000LL #define VBAT_REF 3800000 /* * IADC Gain compensation steps: * If Input/OTG absent: * - read VBAT_FILTERED, KVCOR, GAIN * - calculate the gain compensation using following formula: * gain = (1 + gain) * (1 + kvcor * (vbat_filtered - 3800000)) - 1; * else * - reset to the default gain compensation */ static void iadc_gain_comp_work(struct work_struct *work) { u8 reg[4]; int rc; uint64_t vbat_filtered; int64_t gain, kvcor, temp, numerator; struct fg_chip *chip = container_of(work, struct fg_chip, gain_comp_work); bool input_present = is_input_present(chip); bool otg_present = is_otg_present(chip); if (!chip->init_done) goto done; if (!input_present && !otg_present) { /* read VBAT_FILTERED */ rc = fg_mem_read(chip, reg, TEMP_COUNTER_REG, 3, VBAT_FILTERED_OFFSET, 0); if (rc) { pr_err("Failed to read VBAT: rc=%d\n", rc); goto done; } temp = (reg[2] << 16) | (reg[1] << 8) | reg[0]; vbat_filtered = div_u64((u64)temp * LSB_24B_NUMRTR, LSB_24B_DENMTR); /* read K_VCOR */ rc = fg_mem_read(chip, reg, K_VCOR_REG, 2, 0, 0); if (rc) { pr_err("Failed to KVCOR rc=%d\n", rc); goto done; } kvcor = half_float(reg); /* calculate gain */ numerator = (MICRO_UNIT + chip->iadc_comp_data.dfl_gain) * (PICO_UNIT + kvcor * (vbat_filtered - VBAT_REF)) - ATTO_UNIT; gain = div64_s64(numerator, PICO_UNIT); /* write back gain */ half_float_to_buffer(gain, reg); rc = fg_mem_write(chip, reg, GAIN_REG, 2, GAIN_OFFSET, 0); if (rc) { pr_err("Failed to write gain reg rc=%d\n", rc); goto done; } if (fg_debug_mask & FG_STATUS) pr_info("IADC gain update [%x %x]\n", reg[1], reg[0]); chip->iadc_comp_data.gain_active = true; } else { /* reset gain register */ rc = fg_mem_write(chip, chip->iadc_comp_data.dfl_gain_reg, GAIN_REG, GAIN_OFFSET, 2, 0); if (rc) { pr_err("unable to write gain comp: %d\n", rc); goto done; } if (fg_debug_mask & FG_STATUS) pr_info("IADC gain reset [%x %x]\n", chip->iadc_comp_data.dfl_gain_reg[1], chip->iadc_comp_data.dfl_gain_reg[0]); chip->iadc_comp_data.gain_active = false; } done: fg_relax(&chip->gain_comp_wakeup_source); } #define BATT_MISSING_STS BIT(6) #define BATT_MISSING_STS BIT(6) static bool is_battery_missing(struct fg_chip *chip) static bool is_battery_missing(struct fg_chip *chip) { { Loading Loading @@ -3385,6 +3534,12 @@ static irqreturn_t fg_soc_irq_handler(int irq, void *_chip) schedule_work(&chip->update_esr_work); schedule_work(&chip->update_esr_work); if (chip->charge_full) if (chip->charge_full) schedule_work(&chip->charge_full_work); schedule_work(&chip->charge_full_work); if (chip->wa_flag & IADC_GAIN_COMP_WA && chip->iadc_comp_data.gain_active) { fg_stay_awake(&chip->resume_soc_wakeup_source); schedule_work(&chip->gain_comp_work); } return IRQ_HANDLED; return IRQ_HANDLED; } } Loading Loading @@ -4435,9 +4590,9 @@ static int fg_of_init(struct fg_chip *chip) fg_sense_type = sense_type; fg_sense_type = sense_type; if (fg_debug_mask & FG_STATUS) { if (fg_debug_mask & FG_STATUS) { if (fg_sense_type == 0) if (fg_sense_type == INTERNAL_CURRENT_SENSE) pr_info("Using internal sense\n"); pr_info("Using internal sense\n"); else if (fg_sense_type == 1) else if (fg_sense_type == EXTERNAL_CURRENT_SENSE) pr_info("Using external sense\n"); pr_info("Using external sense\n"); else else pr_info("Using default sense\n"); pr_info("Using default sense\n"); Loading Loading @@ -4650,6 +4805,7 @@ static void fg_cleanup(struct fg_chip *chip) cancel_work_sync(&chip->cycle_count_work); cancel_work_sync(&chip->cycle_count_work); cancel_work_sync(&chip->update_esr_work); cancel_work_sync(&chip->update_esr_work); cancel_work_sync(&chip->sysfs_restart_work); cancel_work_sync(&chip->sysfs_restart_work); cancel_work_sync(&chip->gain_comp_work); cancel_work_sync(&chip->init_work); cancel_work_sync(&chip->init_work); cancel_work_sync(&chip->charge_full_work); cancel_work_sync(&chip->charge_full_work); power_supply_unregister(&chip->bms_psy); power_supply_unregister(&chip->bms_psy); Loading @@ -4664,6 +4820,7 @@ static void fg_cleanup(struct fg_chip *chip) wakeup_source_trash(&chip->profile_wakeup_source.source); wakeup_source_trash(&chip->profile_wakeup_source.source); wakeup_source_trash(&chip->update_temp_wakeup_source.source); wakeup_source_trash(&chip->update_temp_wakeup_source.source); wakeup_source_trash(&chip->update_sram_wakeup_source.source); wakeup_source_trash(&chip->update_sram_wakeup_source.source); wakeup_source_trash(&chip->gain_comp_wakeup_source.source); } } static int fg_remove(struct spmi_device *spmi) static int fg_remove(struct spmi_device *spmi) Loading Loading @@ -5301,11 +5458,16 @@ static int fg_hw_init(struct fg_chip *chip) break; break; case PMI8950: case PMI8950: rc = fg_8950_hw_init(chip); rc = fg_8950_hw_init(chip); /* Setup workaround flag based on PMIC type */ if (fg_sense_type == INTERNAL_CURRENT_SENSE) chip->wa_flag |= IADC_GAIN_COMP_WA; break; break; } } if (rc) if (rc) pr_err("Unable to initialize PMIC specific FG HW rc=%d\n", rc); pr_err("Unable to initialize PMIC specific FG HW rc=%d\n", rc); pr_debug("wa_flag=0x%x\n", chip->wa_flag); return rc; return rc; } } Loading Loading @@ -5399,6 +5561,7 @@ static int fg_detect_pmic_type(struct fg_chip *chip) static void delayed_init_work(struct work_struct *work) static void delayed_init_work(struct work_struct *work) { { u8 reg[2]; int rc; int rc; struct fg_chip *chip = container_of(work, struct fg_chip *chip = container_of(work, struct fg_chip, struct fg_chip, Loading Loading @@ -5430,7 +5593,62 @@ static void delayed_init_work(struct work_struct *work) if (!chip->use_otp_profile) if (!chip->use_otp_profile) schedule_work(&chip->batt_profile_init); schedule_work(&chip->batt_profile_init); if (chip->wa_flag & IADC_GAIN_COMP_WA) { /* read default gain config */ rc = fg_mem_read(chip, reg, K_VCOR_REG, 2, DEF_GAIN_OFFSET, 0); if (rc) { pr_err("Failed to read default gain rc=%d\n", rc); goto done; } if (reg[1] || reg[0]) { /* * Default gain register has valid value: * - write to gain register. */ rc = fg_mem_write(chip, reg, GAIN_REG, 2, GAIN_OFFSET, 0); if (rc) { pr_err("Failed to write gain rc=%d\n", rc); goto done; } } else { /* * Default gain register is invalid: * - read gain register for default gain value * - write to default gain register. */ rc = fg_mem_read(chip, reg, GAIN_REG, 2, GAIN_OFFSET, 0); if (rc) { pr_err("Failed to read gain rc=%d\n", rc); goto done; } rc = fg_mem_write(chip, reg, K_VCOR_REG, 2, DEF_GAIN_OFFSET, 0); if (rc) { pr_err("Failed to write default gain rc=%d\n", rc); goto done; } } chip->iadc_comp_data.dfl_gain_reg[0] = reg[0]; chip->iadc_comp_data.dfl_gain_reg[1] = reg[1]; chip->iadc_comp_data.dfl_gain = half_float(reg); chip->input_present = is_input_present(chip); chip->otg_present = is_otg_present(chip); chip->init_done = true; pr_debug("IADC gain initial config reg_val 0x%x%x gain %lld\n", reg[1], reg[0], chip->iadc_comp_data.dfl_gain); } pr_debug("FG: HW_init success\n"); pr_debug("FG: HW_init success\n"); return; done: fg_cleanup(chip); } } static int fg_probe(struct spmi_device *spmi) static int fg_probe(struct spmi_device *spmi) Loading Loading @@ -5473,6 +5691,8 @@ static int fg_probe(struct spmi_device *spmi) "qpnp_fg_update_sram"); "qpnp_fg_update_sram"); wakeup_source_init(&chip->resume_soc_wakeup_source.source, wakeup_source_init(&chip->resume_soc_wakeup_source.source, "qpnp_fg_set_resume_soc"); "qpnp_fg_set_resume_soc"); wakeup_source_init(&chip->gain_comp_wakeup_source.source, "qpnp_fg_gain_comp"); mutex_init(&chip->rw_lock); mutex_init(&chip->rw_lock); mutex_init(&chip->cyc_ctr.lock); mutex_init(&chip->cyc_ctr.lock); mutex_init(&chip->learning_data.learning_lock); mutex_init(&chip->learning_data.learning_lock); Loading @@ -5494,6 +5714,7 @@ static int fg_probe(struct spmi_device *spmi) INIT_WORK(&chip->sysfs_restart_work, sysfs_restart_work); INIT_WORK(&chip->sysfs_restart_work, sysfs_restart_work); INIT_WORK(&chip->init_work, delayed_init_work); INIT_WORK(&chip->init_work, delayed_init_work); INIT_WORK(&chip->charge_full_work, charge_full_work); INIT_WORK(&chip->charge_full_work, charge_full_work); INIT_WORK(&chip->gain_comp_work, iadc_gain_comp_work); alarm_init(&chip->fg_cap_learning_alarm, ALARM_BOOTTIME, alarm_init(&chip->fg_cap_learning_alarm, ALARM_BOOTTIME, fg_cap_learning_alarm_cb); fg_cap_learning_alarm_cb); init_completion(&chip->sram_access_granted); init_completion(&chip->sram_access_granted); Loading Loading @@ -5645,6 +5866,7 @@ cancel_work: cancel_work_sync(&chip->update_esr_work); cancel_work_sync(&chip->update_esr_work); cancel_work_sync(&chip->rslow_comp_work); cancel_work_sync(&chip->rslow_comp_work); cancel_work_sync(&chip->sysfs_restart_work); cancel_work_sync(&chip->sysfs_restart_work); cancel_work_sync(&chip->gain_comp_work); cancel_work_sync(&chip->init_work); cancel_work_sync(&chip->init_work); cancel_work_sync(&chip->charge_full_work); cancel_work_sync(&chip->charge_full_work); of_init_fail: of_init_fail: Loading @@ -5659,6 +5881,7 @@ of_init_fail: wakeup_source_trash(&chip->profile_wakeup_source.source); wakeup_source_trash(&chip->profile_wakeup_source.source); wakeup_source_trash(&chip->update_temp_wakeup_source.source); wakeup_source_trash(&chip->update_temp_wakeup_source.source); wakeup_source_trash(&chip->update_sram_wakeup_source.source); wakeup_source_trash(&chip->update_sram_wakeup_source.source); wakeup_source_trash(&chip->gain_comp_wakeup_source.source); return rc; return rc; } } Loading drivers/power/qpnp-smbcharger.c +14 −7 Original line number Original line Diff line number Diff line Loading @@ -264,6 +264,7 @@ enum pmic_subtype { enum smbchg_wa { enum smbchg_wa { SMBCHG_AICL_DEGLITCH_WA = BIT(0), SMBCHG_AICL_DEGLITCH_WA = BIT(0), SMBCHG_HVDCP_9V_EN_WA = BIT(1), SMBCHG_HVDCP_9V_EN_WA = BIT(1), SMBCHG_USB100_WA = BIT(2), }; }; enum print_reason { enum print_reason { Loading Loading @@ -741,6 +742,10 @@ static int get_prop_batt_status(struct smbchg_chip *chip) u8 reg = 0, chg_type; u8 reg = 0, chg_type; bool charger_present, chg_inhibit; bool charger_present, chg_inhibit; charger_present = is_usb_present(chip) | is_dc_present(chip); if (!charger_present) return POWER_SUPPLY_STATUS_DISCHARGING; rc = smbchg_read(chip, ®, chip->chgr_base + RT_STS, 1); rc = smbchg_read(chip, ®, chip->chgr_base + RT_STS, 1); if (rc < 0) { if (rc < 0) { dev_err(chip->dev, "Unable to read RT_STS rc = %d\n", rc); dev_err(chip->dev, "Unable to read RT_STS rc = %d\n", rc); Loading @@ -750,10 +755,6 @@ static int get_prop_batt_status(struct smbchg_chip *chip) if (reg & BAT_TCC_REACHED_BIT) if (reg & BAT_TCC_REACHED_BIT) return POWER_SUPPLY_STATUS_FULL; return POWER_SUPPLY_STATUS_FULL; charger_present = is_usb_present(chip) | is_dc_present(chip); if (!charger_present) return POWER_SUPPLY_STATUS_DISCHARGING; chg_inhibit = reg & CHG_INHIBIT_BIT; chg_inhibit = reg & CHG_INHIBIT_BIT; if (chg_inhibit) if (chg_inhibit) return POWER_SUPPLY_STATUS_FULL; return POWER_SUPPLY_STATUS_FULL; Loading Loading @@ -1420,6 +1421,10 @@ static int smbchg_set_usb_current_max(struct smbchg_chip *chip, switch (usb_supply_type) { switch (usb_supply_type) { case POWER_SUPPLY_TYPE_USB: case POWER_SUPPLY_TYPE_USB: if ((current_ma < CURRENT_150_MA) && (chip->wa_flags & SMBCHG_USB100_WA)) current_ma = CURRENT_150_MA; if (current_ma < CURRENT_150_MA) { if (current_ma < CURRENT_150_MA) { /* force 100mA */ /* force 100mA */ rc = smbchg_sec_masked_write(chip, rc = smbchg_sec_masked_write(chip, Loading Loading @@ -6629,10 +6634,12 @@ static int smbchg_wa_config(struct smbchg_chip *chip) case PMI8994: case PMI8994: chip->wa_flags |= SMBCHG_AICL_DEGLITCH_WA; chip->wa_flags |= SMBCHG_AICL_DEGLITCH_WA; case PMI8950: case PMI8950: if (pmic_rev_id->rev4 < 2) /* PMI8950 1.0 */ if (pmic_rev_id->rev4 < 2) /* PMI8950 1.0 */ { chip->wa_flags |= SMBCHG_AICL_DEGLITCH_WA; chip->wa_flags |= SMBCHG_AICL_DEGLITCH_WA; else /* rev > PMI8950 v1.0 */ } else { /* rev > PMI8950 v1.0 */ chip->wa_flags |= SMBCHG_HVDCP_9V_EN_WA; chip->wa_flags |= SMBCHG_HVDCP_9V_EN_WA | SMBCHG_USB100_WA; } break; break; default: default: pr_err("PMIC subtype %d not supported, WA flags not set\n", pr_err("PMIC subtype %d not supported, WA flags not set\n", Loading drivers/regulator/cpr-regulator.c +23 −0 Original line number Original line Diff line number Diff line Loading @@ -1117,12 +1117,35 @@ static int cpr_regulator_get_voltage(struct regulator_dev *rdev) return cpr_vreg->corner; return cpr_vreg->corner; } } /** * cpr_regulator_list_corner_voltage() - return the ceiling voltage mapped to * the specified voltage corner * @rdev: Regulator device pointer for the cpr-regulator * @corner: Voltage corner * * This function is passed as a callback function into the regulator ops that * are registered for each cpr-regulator device. * * Return: voltage value in microvolts or -EINVAL if the corner is out of range */ static int cpr_regulator_list_corner_voltage(struct regulator_dev *rdev, int corner) { struct cpr_regulator *cpr_vreg = rdev_get_drvdata(rdev); if (corner >= CPR_CORNER_MIN && corner <= cpr_vreg->num_corners) return cpr_vreg->ceiling_volt[corner]; else return -EINVAL; } static struct regulator_ops cpr_corner_ops = { static struct regulator_ops cpr_corner_ops = { .enable = cpr_regulator_enable, .enable = cpr_regulator_enable, .disable = cpr_regulator_disable, .disable = cpr_regulator_disable, .is_enabled = cpr_regulator_is_enabled, .is_enabled = cpr_regulator_is_enabled, .set_voltage = cpr_regulator_set_voltage_op, .set_voltage = cpr_regulator_set_voltage_op, .get_voltage = cpr_regulator_get_voltage, .get_voltage = cpr_regulator_get_voltage, .list_corner_voltage = cpr_regulator_list_corner_voltage, }; }; #ifdef CONFIG_PM #ifdef CONFIG_PM Loading Loading
Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt +5 −0 Original line number Original line Diff line number Diff line Loading @@ -56,6 +56,10 @@ Optional properties: reset through qcom,system-reset property. reset through qcom,system-reset property. This should not be defined along with the This should not be defined along with the qcom,system-reset property. qcom,system-reset property. - qcom,store-hard-reset-reason Boolean property which if set will store the hardware reset reason to SOFT_RB_SPARE register of the core PMIC PON peripheral. All the below properties are in the sub-node section (properties of the child All the below properties are in the sub-node section (properties of the child node). node). Loading Loading @@ -113,6 +117,7 @@ Example: qcom,s3-debounce = <32>; qcom,s3-debounce = <32>; qcom,s3-src = "resin"; qcom,s3-src = "resin"; qcom,clear-warm-reset; qcom,clear-warm-reset; qcom,store-hard-reset-reason; qcom,pon_1 { qcom,pon_1 { qcom,pon-type = <0>; qcom,pon-type = <0>; Loading
drivers/platform/msm/qpnp-power-on.c +65 −1 Original line number Original line Diff line number Diff line Loading @@ -27,6 +27,11 @@ #include <linux/log2.h> #include <linux/log2.h> #include <linux/qpnp/power-on.h> #include <linux/qpnp/power-on.h> #define CREATE_MASK(NUM_BITS, POS) \ ((unsigned char) (((1 << (NUM_BITS)) - 1) << (POS))) #define PON_MASK(MSB_BIT, LSB_BIT) \ CREATE_MASK(MSB_BIT - LSB_BIT + 1, LSB_BIT) #define PMIC_VER_8941 0x01 #define PMIC_VER_8941 0x01 #define PMIC_VERSION_REG 0x0105 #define PMIC_VERSION_REG 0x0105 #define PMIC_VERSION_REV4_REG 0x0103 #define PMIC_VERSION_REV4_REG 0x0103 Loading Loading @@ -68,6 +73,7 @@ #define QPNP_PON_S3_DBC_CTL(base) (base + 0x75) #define QPNP_PON_S3_DBC_CTL(base) (base + 0x75) #define QPNP_PON_TRIGGER_EN(base) (base + 0x80) #define QPNP_PON_TRIGGER_EN(base) (base + 0x80) #define QPNP_PON_XVDD_RB_SPARE(base) (base + 0x8E) #define QPNP_PON_XVDD_RB_SPARE(base) (base + 0x8E) #define QPNP_PON_SOFT_RB_SPARE(base) (base + 0x8F) #define QPNP_PON_SEC_ACCESS(base) (base + 0xD0) #define QPNP_PON_SEC_ACCESS(base) (base + 0xD0) #define QPNP_PON_SEC_UNLOCK 0xA5 #define QPNP_PON_SEC_UNLOCK 0xA5 Loading Loading @@ -101,6 +107,7 @@ #define QPNP_PON_S3_SRC_KPDPWR_AND_RESIN 2 #define QPNP_PON_S3_SRC_KPDPWR_AND_RESIN 2 #define QPNP_PON_S3_SRC_KPDPWR_OR_RESIN 3 #define QPNP_PON_S3_SRC_KPDPWR_OR_RESIN 3 #define QPNP_PON_S3_SRC_MASK 0x3 #define QPNP_PON_S3_SRC_MASK 0x3 #define QPNP_PON_HARD_RESET_MASK PON_MASK(7, 5) #define QPNP_PON_UVLO_DLOAD_EN BIT(7) #define QPNP_PON_UVLO_DLOAD_EN BIT(7) Loading Loading @@ -160,6 +167,7 @@ struct qpnp_pon { u8 warm_reset_reason1; u8 warm_reset_reason1; u8 warm_reset_reason2; u8 warm_reset_reason2; bool is_spon; bool is_spon; bool store_hard_reset_reason; }; }; static struct qpnp_pon *sys_reset_dev; static struct qpnp_pon *sys_reset_dev; Loading Loading @@ -235,6 +243,56 @@ qpnp_pon_masked_write(struct qpnp_pon *pon, u16 addr, u8 mask, u8 val) return rc; return rc; } } /** * qpnp_pon_set_restart_reason - Store device restart reason in PMIC register. * * Returns = 0 if PMIC feature is not available or store restart reason * successfully. * Returns > 0 for errors * * This function is used to store device restart reason in PMIC register. * It checks here to see if the restart reason register has been specified. * If it hasn't, this function should immediately return 0 */ int qpnp_pon_set_restart_reason(enum pon_restart_reason reason) { int rc = 0; struct qpnp_pon *pon = sys_reset_dev; if (!pon) return 0; if (!pon->store_hard_reset_reason) return 0; rc = qpnp_pon_masked_write(pon, QPNP_PON_SOFT_RB_SPARE(pon->base), PON_MASK(7, 5), (reason << 5)); if (rc) dev_err(&pon->spmi->dev, "Unable to write to addr=%x, rc(%d)\n", QPNP_PON_SOFT_RB_SPARE(pon->base), rc); return rc; } EXPORT_SYMBOL(qpnp_pon_set_restart_reason); /* * qpnp_pon_check_hard_reset_stored - Checks if the PMIC need to * store hard reset reason. * * Returns true if reset reason can be stored, false if it cannot be stored * */ bool qpnp_pon_check_hard_reset_stored(void) { struct qpnp_pon *pon = sys_reset_dev; if (!pon) return false; return pon->store_hard_reset_reason; } EXPORT_SYMBOL(qpnp_pon_check_hard_reset_stored); static int qpnp_pon_set_dbc(struct qpnp_pon *pon, u32 delay) static int qpnp_pon_set_dbc(struct qpnp_pon *pon, u32 delay) { { int rc = 0; int rc = 0; Loading Loading @@ -1564,7 +1622,6 @@ static int qpnp_pon_probe(struct spmi_device *spmi) return rc; return rc; } } boot_reason = ffs(pon_sts); index = ffs(pon_sts) - 1; index = ffs(pon_sts) - 1; cold_boot = !qpnp_pon_is_warm_reset(); cold_boot = !qpnp_pon_is_warm_reset(); Loading Loading @@ -1720,8 +1777,15 @@ static int qpnp_pon_probe(struct spmi_device *spmi) list_add(&pon->list, &spon_dev_list); list_add(&pon->list, &spon_dev_list); mutex_unlock(&spon_list_mutex); mutex_unlock(&spon_list_mutex); pon->is_spon = true; pon->is_spon = true; } else { boot_reason = ffs(pon_sts); } } /* config whether store the hard reset reason */ pon->store_hard_reset_reason = of_property_read_bool( spmi->dev.of_node, "qcom,store-hard-reset-reason"); qpnp_pon_debugfs_init(spmi); qpnp_pon_debugfs_init(spmi); return 0; return 0; } } Loading
drivers/power/qpnp-fg.c +225 −2 Original line number Original line Diff line number Diff line Loading @@ -100,6 +100,15 @@ enum pmic_subtype { PMI8950 = 17, PMI8950 = 17, }; }; enum wa_flags { IADC_GAIN_COMP_WA = BIT(0), }; enum current_sense_type { INTERNAL_CURRENT_SENSE, EXTERNAL_CURRENT_SENSE, }; struct fg_mem_setting { struct fg_mem_setting { u16 address; u16 address; u8 offset; u8 offset; Loading Loading @@ -151,6 +160,12 @@ struct fg_cyc_ctr_data { struct mutex lock; struct mutex lock; }; }; struct fg_iadc_comp_data { u8 dfl_gain_reg[2]; bool gain_active; int64_t dfl_gain; }; /* FG_MEMIF setting index */ /* FG_MEMIF setting index */ enum fg_mem_setting_index { enum fg_mem_setting_index { FG_MEM_SOFT_COLD = 0, FG_MEM_SOFT_COLD = 0, Loading Loading @@ -373,6 +388,7 @@ struct fg_chip { u16 vbat_adc_addr; u16 vbat_adc_addr; u16 ibat_adc_addr; u16 ibat_adc_addr; u16 tp_rev_addr; u16 tp_rev_addr; u32 wa_flag; atomic_t memif_user_cnt; atomic_t memif_user_cnt; struct fg_irq soc_irq[FG_SOC_IRQ_COUNT]; struct fg_irq soc_irq[FG_SOC_IRQ_COUNT]; struct fg_irq batt_irq[FG_BATT_IRQ_COUNT]; struct fg_irq batt_irq[FG_BATT_IRQ_COUNT]; Loading @@ -394,6 +410,7 @@ struct fg_chip { struct work_struct sysfs_restart_work; struct work_struct sysfs_restart_work; struct work_struct init_work; struct work_struct init_work; struct work_struct charge_full_work; struct work_struct charge_full_work; struct work_struct gain_comp_work; struct power_supply *batt_psy; struct power_supply *batt_psy; struct power_supply *usb_psy; struct power_supply *usb_psy; struct power_supply *dc_psy; struct power_supply *dc_psy; Loading @@ -401,6 +418,7 @@ struct fg_chip { struct fg_wakeup_source profile_wakeup_source; struct fg_wakeup_source profile_wakeup_source; struct fg_wakeup_source empty_check_wakeup_source; struct fg_wakeup_source empty_check_wakeup_source; struct fg_wakeup_source resume_soc_wakeup_source; struct fg_wakeup_source resume_soc_wakeup_source; struct fg_wakeup_source gain_comp_wakeup_source; bool first_profile_loaded; bool first_profile_loaded; struct fg_wakeup_source update_temp_wakeup_source; struct fg_wakeup_source update_temp_wakeup_source; struct fg_wakeup_source update_sram_wakeup_source; struct fg_wakeup_source update_sram_wakeup_source; Loading @@ -417,6 +435,8 @@ struct fg_chip { bool vbat_low_irq_enabled; bool vbat_low_irq_enabled; bool charge_full; bool charge_full; bool hold_soc_while_full; bool hold_soc_while_full; bool input_present; bool otg_present; struct delayed_work update_jeita_setting; struct delayed_work update_jeita_setting; struct delayed_work update_sram_data; struct delayed_work update_sram_data; struct delayed_work update_temp_work; struct delayed_work update_temp_work; Loading Loading @@ -449,9 +469,12 @@ struct fg_chip { struct fg_rslow_data rslow_comp; struct fg_rslow_data rslow_comp; /* cycle counter */ /* cycle counter */ struct fg_cyc_ctr_data cyc_ctr; struct fg_cyc_ctr_data cyc_ctr; /* iadc compensation */ struct fg_iadc_comp_data iadc_comp_data; /* interleaved memory access */ /* interleaved memory access */ u16 *offset; u16 *offset; bool ima_supported; bool ima_supported; bool init_done; }; }; /* FG_MEMIF DEBUGFS structures */ /* FG_MEMIF DEBUGFS structures */ Loading Loading @@ -1876,6 +1899,8 @@ static int64_t twos_compliment_extend(int64_t val, int nbytes) return val; return val; } } #define LSB_24B_NUMRTR 596046 #define LSB_24B_DENMTR 1000000 #define LSB_16B_NUMRTR 152587 #define LSB_16B_NUMRTR 152587 #define LSB_16B_DENMTR 1000 #define LSB_16B_DENMTR 1000 #define LSB_8B 9800 #define LSB_8B 9800 Loading Loading @@ -3021,6 +3046,19 @@ static bool is_input_present(struct fg_chip *chip) return is_usb_present(chip) || is_dc_present(chip); return is_usb_present(chip) || is_dc_present(chip); } } static bool is_otg_present(struct fg_chip *chip) { union power_supply_propval prop = {0,}; if (!chip->usb_psy) chip->usb_psy = power_supply_get_by_name("usb"); if (chip->usb_psy) chip->usb_psy->get_property(chip->usb_psy, POWER_SUPPLY_PROP_USB_OTG, &prop); return prop.intval != 0; } static void status_change_work(struct work_struct *work) static void status_change_work(struct work_struct *work) { { struct fg_chip *chip = container_of(work, struct fg_chip *chip = container_of(work, Loading Loading @@ -3073,6 +3111,26 @@ static void status_change_work(struct work_struct *work) } } } } /* * Check for change in the status of input or OTG and schedule * IADC gain compensation work. */ static void check_gain_compensation(struct fg_chip *chip) { bool input_present = is_input_present(chip); bool otg_present = is_otg_present(chip); if ((chip->wa_flag & IADC_GAIN_COMP_WA) && ((chip->input_present ^ input_present) || (chip->otg_present ^ otg_present))) { fg_stay_awake(&chip->gain_comp_wakeup_source); chip->input_present = input_present; chip->otg_present = otg_present; cancel_work_sync(&chip->gain_comp_work); schedule_work(&chip->gain_comp_work); } } static int fg_power_set_property(struct power_supply *psy, static int fg_power_set_property(struct power_supply *psy, enum power_supply_property psp, enum power_supply_property psp, const union power_supply_propval *val) const union power_supply_propval *val) Loading @@ -3095,6 +3153,7 @@ static int fg_power_set_property(struct power_supply *psy, chip->prev_status = chip->status; chip->prev_status = chip->status; chip->status = val->intval; chip->status = val->intval; schedule_work(&chip->status_change_work); schedule_work(&chip->status_change_work); check_gain_compensation(chip); break; break; case POWER_SUPPLY_PROP_HEALTH: case POWER_SUPPLY_PROP_HEALTH: chip->health = val->intval; chip->health = val->intval; Loading Loading @@ -3242,6 +3301,96 @@ static void update_esr_value(struct work_struct *work) } } } } #define TEMP_COUNTER_REG 0x580 #define VBAT_FILTERED_OFFSET 1 #define GAIN_REG 0x424 #define GAIN_OFFSET 1 #define K_VCOR_REG 0x484 #define DEF_GAIN_OFFSET 2 #define PICO_UNIT 0xE8D4A51000LL #define ATTO_UNIT 0xDE0B6B3A7640000LL #define VBAT_REF 3800000 /* * IADC Gain compensation steps: * If Input/OTG absent: * - read VBAT_FILTERED, KVCOR, GAIN * - calculate the gain compensation using following formula: * gain = (1 + gain) * (1 + kvcor * (vbat_filtered - 3800000)) - 1; * else * - reset to the default gain compensation */ static void iadc_gain_comp_work(struct work_struct *work) { u8 reg[4]; int rc; uint64_t vbat_filtered; int64_t gain, kvcor, temp, numerator; struct fg_chip *chip = container_of(work, struct fg_chip, gain_comp_work); bool input_present = is_input_present(chip); bool otg_present = is_otg_present(chip); if (!chip->init_done) goto done; if (!input_present && !otg_present) { /* read VBAT_FILTERED */ rc = fg_mem_read(chip, reg, TEMP_COUNTER_REG, 3, VBAT_FILTERED_OFFSET, 0); if (rc) { pr_err("Failed to read VBAT: rc=%d\n", rc); goto done; } temp = (reg[2] << 16) | (reg[1] << 8) | reg[0]; vbat_filtered = div_u64((u64)temp * LSB_24B_NUMRTR, LSB_24B_DENMTR); /* read K_VCOR */ rc = fg_mem_read(chip, reg, K_VCOR_REG, 2, 0, 0); if (rc) { pr_err("Failed to KVCOR rc=%d\n", rc); goto done; } kvcor = half_float(reg); /* calculate gain */ numerator = (MICRO_UNIT + chip->iadc_comp_data.dfl_gain) * (PICO_UNIT + kvcor * (vbat_filtered - VBAT_REF)) - ATTO_UNIT; gain = div64_s64(numerator, PICO_UNIT); /* write back gain */ half_float_to_buffer(gain, reg); rc = fg_mem_write(chip, reg, GAIN_REG, 2, GAIN_OFFSET, 0); if (rc) { pr_err("Failed to write gain reg rc=%d\n", rc); goto done; } if (fg_debug_mask & FG_STATUS) pr_info("IADC gain update [%x %x]\n", reg[1], reg[0]); chip->iadc_comp_data.gain_active = true; } else { /* reset gain register */ rc = fg_mem_write(chip, chip->iadc_comp_data.dfl_gain_reg, GAIN_REG, GAIN_OFFSET, 2, 0); if (rc) { pr_err("unable to write gain comp: %d\n", rc); goto done; } if (fg_debug_mask & FG_STATUS) pr_info("IADC gain reset [%x %x]\n", chip->iadc_comp_data.dfl_gain_reg[1], chip->iadc_comp_data.dfl_gain_reg[0]); chip->iadc_comp_data.gain_active = false; } done: fg_relax(&chip->gain_comp_wakeup_source); } #define BATT_MISSING_STS BIT(6) #define BATT_MISSING_STS BIT(6) static bool is_battery_missing(struct fg_chip *chip) static bool is_battery_missing(struct fg_chip *chip) { { Loading Loading @@ -3385,6 +3534,12 @@ static irqreturn_t fg_soc_irq_handler(int irq, void *_chip) schedule_work(&chip->update_esr_work); schedule_work(&chip->update_esr_work); if (chip->charge_full) if (chip->charge_full) schedule_work(&chip->charge_full_work); schedule_work(&chip->charge_full_work); if (chip->wa_flag & IADC_GAIN_COMP_WA && chip->iadc_comp_data.gain_active) { fg_stay_awake(&chip->resume_soc_wakeup_source); schedule_work(&chip->gain_comp_work); } return IRQ_HANDLED; return IRQ_HANDLED; } } Loading Loading @@ -4435,9 +4590,9 @@ static int fg_of_init(struct fg_chip *chip) fg_sense_type = sense_type; fg_sense_type = sense_type; if (fg_debug_mask & FG_STATUS) { if (fg_debug_mask & FG_STATUS) { if (fg_sense_type == 0) if (fg_sense_type == INTERNAL_CURRENT_SENSE) pr_info("Using internal sense\n"); pr_info("Using internal sense\n"); else if (fg_sense_type == 1) else if (fg_sense_type == EXTERNAL_CURRENT_SENSE) pr_info("Using external sense\n"); pr_info("Using external sense\n"); else else pr_info("Using default sense\n"); pr_info("Using default sense\n"); Loading Loading @@ -4650,6 +4805,7 @@ static void fg_cleanup(struct fg_chip *chip) cancel_work_sync(&chip->cycle_count_work); cancel_work_sync(&chip->cycle_count_work); cancel_work_sync(&chip->update_esr_work); cancel_work_sync(&chip->update_esr_work); cancel_work_sync(&chip->sysfs_restart_work); cancel_work_sync(&chip->sysfs_restart_work); cancel_work_sync(&chip->gain_comp_work); cancel_work_sync(&chip->init_work); cancel_work_sync(&chip->init_work); cancel_work_sync(&chip->charge_full_work); cancel_work_sync(&chip->charge_full_work); power_supply_unregister(&chip->bms_psy); power_supply_unregister(&chip->bms_psy); Loading @@ -4664,6 +4820,7 @@ static void fg_cleanup(struct fg_chip *chip) wakeup_source_trash(&chip->profile_wakeup_source.source); wakeup_source_trash(&chip->profile_wakeup_source.source); wakeup_source_trash(&chip->update_temp_wakeup_source.source); wakeup_source_trash(&chip->update_temp_wakeup_source.source); wakeup_source_trash(&chip->update_sram_wakeup_source.source); wakeup_source_trash(&chip->update_sram_wakeup_source.source); wakeup_source_trash(&chip->gain_comp_wakeup_source.source); } } static int fg_remove(struct spmi_device *spmi) static int fg_remove(struct spmi_device *spmi) Loading Loading @@ -5301,11 +5458,16 @@ static int fg_hw_init(struct fg_chip *chip) break; break; case PMI8950: case PMI8950: rc = fg_8950_hw_init(chip); rc = fg_8950_hw_init(chip); /* Setup workaround flag based on PMIC type */ if (fg_sense_type == INTERNAL_CURRENT_SENSE) chip->wa_flag |= IADC_GAIN_COMP_WA; break; break; } } if (rc) if (rc) pr_err("Unable to initialize PMIC specific FG HW rc=%d\n", rc); pr_err("Unable to initialize PMIC specific FG HW rc=%d\n", rc); pr_debug("wa_flag=0x%x\n", chip->wa_flag); return rc; return rc; } } Loading Loading @@ -5399,6 +5561,7 @@ static int fg_detect_pmic_type(struct fg_chip *chip) static void delayed_init_work(struct work_struct *work) static void delayed_init_work(struct work_struct *work) { { u8 reg[2]; int rc; int rc; struct fg_chip *chip = container_of(work, struct fg_chip *chip = container_of(work, struct fg_chip, struct fg_chip, Loading Loading @@ -5430,7 +5593,62 @@ static void delayed_init_work(struct work_struct *work) if (!chip->use_otp_profile) if (!chip->use_otp_profile) schedule_work(&chip->batt_profile_init); schedule_work(&chip->batt_profile_init); if (chip->wa_flag & IADC_GAIN_COMP_WA) { /* read default gain config */ rc = fg_mem_read(chip, reg, K_VCOR_REG, 2, DEF_GAIN_OFFSET, 0); if (rc) { pr_err("Failed to read default gain rc=%d\n", rc); goto done; } if (reg[1] || reg[0]) { /* * Default gain register has valid value: * - write to gain register. */ rc = fg_mem_write(chip, reg, GAIN_REG, 2, GAIN_OFFSET, 0); if (rc) { pr_err("Failed to write gain rc=%d\n", rc); goto done; } } else { /* * Default gain register is invalid: * - read gain register for default gain value * - write to default gain register. */ rc = fg_mem_read(chip, reg, GAIN_REG, 2, GAIN_OFFSET, 0); if (rc) { pr_err("Failed to read gain rc=%d\n", rc); goto done; } rc = fg_mem_write(chip, reg, K_VCOR_REG, 2, DEF_GAIN_OFFSET, 0); if (rc) { pr_err("Failed to write default gain rc=%d\n", rc); goto done; } } chip->iadc_comp_data.dfl_gain_reg[0] = reg[0]; chip->iadc_comp_data.dfl_gain_reg[1] = reg[1]; chip->iadc_comp_data.dfl_gain = half_float(reg); chip->input_present = is_input_present(chip); chip->otg_present = is_otg_present(chip); chip->init_done = true; pr_debug("IADC gain initial config reg_val 0x%x%x gain %lld\n", reg[1], reg[0], chip->iadc_comp_data.dfl_gain); } pr_debug("FG: HW_init success\n"); pr_debug("FG: HW_init success\n"); return; done: fg_cleanup(chip); } } static int fg_probe(struct spmi_device *spmi) static int fg_probe(struct spmi_device *spmi) Loading Loading @@ -5473,6 +5691,8 @@ static int fg_probe(struct spmi_device *spmi) "qpnp_fg_update_sram"); "qpnp_fg_update_sram"); wakeup_source_init(&chip->resume_soc_wakeup_source.source, wakeup_source_init(&chip->resume_soc_wakeup_source.source, "qpnp_fg_set_resume_soc"); "qpnp_fg_set_resume_soc"); wakeup_source_init(&chip->gain_comp_wakeup_source.source, "qpnp_fg_gain_comp"); mutex_init(&chip->rw_lock); mutex_init(&chip->rw_lock); mutex_init(&chip->cyc_ctr.lock); mutex_init(&chip->cyc_ctr.lock); mutex_init(&chip->learning_data.learning_lock); mutex_init(&chip->learning_data.learning_lock); Loading @@ -5494,6 +5714,7 @@ static int fg_probe(struct spmi_device *spmi) INIT_WORK(&chip->sysfs_restart_work, sysfs_restart_work); INIT_WORK(&chip->sysfs_restart_work, sysfs_restart_work); INIT_WORK(&chip->init_work, delayed_init_work); INIT_WORK(&chip->init_work, delayed_init_work); INIT_WORK(&chip->charge_full_work, charge_full_work); INIT_WORK(&chip->charge_full_work, charge_full_work); INIT_WORK(&chip->gain_comp_work, iadc_gain_comp_work); alarm_init(&chip->fg_cap_learning_alarm, ALARM_BOOTTIME, alarm_init(&chip->fg_cap_learning_alarm, ALARM_BOOTTIME, fg_cap_learning_alarm_cb); fg_cap_learning_alarm_cb); init_completion(&chip->sram_access_granted); init_completion(&chip->sram_access_granted); Loading Loading @@ -5645,6 +5866,7 @@ cancel_work: cancel_work_sync(&chip->update_esr_work); cancel_work_sync(&chip->update_esr_work); cancel_work_sync(&chip->rslow_comp_work); cancel_work_sync(&chip->rslow_comp_work); cancel_work_sync(&chip->sysfs_restart_work); cancel_work_sync(&chip->sysfs_restart_work); cancel_work_sync(&chip->gain_comp_work); cancel_work_sync(&chip->init_work); cancel_work_sync(&chip->init_work); cancel_work_sync(&chip->charge_full_work); cancel_work_sync(&chip->charge_full_work); of_init_fail: of_init_fail: Loading @@ -5659,6 +5881,7 @@ of_init_fail: wakeup_source_trash(&chip->profile_wakeup_source.source); wakeup_source_trash(&chip->profile_wakeup_source.source); wakeup_source_trash(&chip->update_temp_wakeup_source.source); wakeup_source_trash(&chip->update_temp_wakeup_source.source); wakeup_source_trash(&chip->update_sram_wakeup_source.source); wakeup_source_trash(&chip->update_sram_wakeup_source.source); wakeup_source_trash(&chip->gain_comp_wakeup_source.source); return rc; return rc; } } Loading
drivers/power/qpnp-smbcharger.c +14 −7 Original line number Original line Diff line number Diff line Loading @@ -264,6 +264,7 @@ enum pmic_subtype { enum smbchg_wa { enum smbchg_wa { SMBCHG_AICL_DEGLITCH_WA = BIT(0), SMBCHG_AICL_DEGLITCH_WA = BIT(0), SMBCHG_HVDCP_9V_EN_WA = BIT(1), SMBCHG_HVDCP_9V_EN_WA = BIT(1), SMBCHG_USB100_WA = BIT(2), }; }; enum print_reason { enum print_reason { Loading Loading @@ -741,6 +742,10 @@ static int get_prop_batt_status(struct smbchg_chip *chip) u8 reg = 0, chg_type; u8 reg = 0, chg_type; bool charger_present, chg_inhibit; bool charger_present, chg_inhibit; charger_present = is_usb_present(chip) | is_dc_present(chip); if (!charger_present) return POWER_SUPPLY_STATUS_DISCHARGING; rc = smbchg_read(chip, ®, chip->chgr_base + RT_STS, 1); rc = smbchg_read(chip, ®, chip->chgr_base + RT_STS, 1); if (rc < 0) { if (rc < 0) { dev_err(chip->dev, "Unable to read RT_STS rc = %d\n", rc); dev_err(chip->dev, "Unable to read RT_STS rc = %d\n", rc); Loading @@ -750,10 +755,6 @@ static int get_prop_batt_status(struct smbchg_chip *chip) if (reg & BAT_TCC_REACHED_BIT) if (reg & BAT_TCC_REACHED_BIT) return POWER_SUPPLY_STATUS_FULL; return POWER_SUPPLY_STATUS_FULL; charger_present = is_usb_present(chip) | is_dc_present(chip); if (!charger_present) return POWER_SUPPLY_STATUS_DISCHARGING; chg_inhibit = reg & CHG_INHIBIT_BIT; chg_inhibit = reg & CHG_INHIBIT_BIT; if (chg_inhibit) if (chg_inhibit) return POWER_SUPPLY_STATUS_FULL; return POWER_SUPPLY_STATUS_FULL; Loading Loading @@ -1420,6 +1421,10 @@ static int smbchg_set_usb_current_max(struct smbchg_chip *chip, switch (usb_supply_type) { switch (usb_supply_type) { case POWER_SUPPLY_TYPE_USB: case POWER_SUPPLY_TYPE_USB: if ((current_ma < CURRENT_150_MA) && (chip->wa_flags & SMBCHG_USB100_WA)) current_ma = CURRENT_150_MA; if (current_ma < CURRENT_150_MA) { if (current_ma < CURRENT_150_MA) { /* force 100mA */ /* force 100mA */ rc = smbchg_sec_masked_write(chip, rc = smbchg_sec_masked_write(chip, Loading Loading @@ -6629,10 +6634,12 @@ static int smbchg_wa_config(struct smbchg_chip *chip) case PMI8994: case PMI8994: chip->wa_flags |= SMBCHG_AICL_DEGLITCH_WA; chip->wa_flags |= SMBCHG_AICL_DEGLITCH_WA; case PMI8950: case PMI8950: if (pmic_rev_id->rev4 < 2) /* PMI8950 1.0 */ if (pmic_rev_id->rev4 < 2) /* PMI8950 1.0 */ { chip->wa_flags |= SMBCHG_AICL_DEGLITCH_WA; chip->wa_flags |= SMBCHG_AICL_DEGLITCH_WA; else /* rev > PMI8950 v1.0 */ } else { /* rev > PMI8950 v1.0 */ chip->wa_flags |= SMBCHG_HVDCP_9V_EN_WA; chip->wa_flags |= SMBCHG_HVDCP_9V_EN_WA | SMBCHG_USB100_WA; } break; break; default: default: pr_err("PMIC subtype %d not supported, WA flags not set\n", pr_err("PMIC subtype %d not supported, WA flags not set\n", Loading
drivers/regulator/cpr-regulator.c +23 −0 Original line number Original line Diff line number Diff line Loading @@ -1117,12 +1117,35 @@ static int cpr_regulator_get_voltage(struct regulator_dev *rdev) return cpr_vreg->corner; return cpr_vreg->corner; } } /** * cpr_regulator_list_corner_voltage() - return the ceiling voltage mapped to * the specified voltage corner * @rdev: Regulator device pointer for the cpr-regulator * @corner: Voltage corner * * This function is passed as a callback function into the regulator ops that * are registered for each cpr-regulator device. * * Return: voltage value in microvolts or -EINVAL if the corner is out of range */ static int cpr_regulator_list_corner_voltage(struct regulator_dev *rdev, int corner) { struct cpr_regulator *cpr_vreg = rdev_get_drvdata(rdev); if (corner >= CPR_CORNER_MIN && corner <= cpr_vreg->num_corners) return cpr_vreg->ceiling_volt[corner]; else return -EINVAL; } static struct regulator_ops cpr_corner_ops = { static struct regulator_ops cpr_corner_ops = { .enable = cpr_regulator_enable, .enable = cpr_regulator_enable, .disable = cpr_regulator_disable, .disable = cpr_regulator_disable, .is_enabled = cpr_regulator_is_enabled, .is_enabled = cpr_regulator_is_enabled, .set_voltage = cpr_regulator_set_voltage_op, .set_voltage = cpr_regulator_set_voltage_op, .get_voltage = cpr_regulator_get_voltage, .get_voltage = cpr_regulator_get_voltage, .list_corner_voltage = cpr_regulator_list_corner_voltage, }; }; #ifdef CONFIG_PM #ifdef CONFIG_PM Loading