Loading drivers/power/supply/qcom/fg-core.h +4 −1 Original line number Diff line number Diff line Loading @@ -57,6 +57,8 @@ /* Battery missing irq votable reasons */ #define BATT_MISS_IRQ_VOTER "fg_batt_miss_irq" #define ESR_FCC_VOTER "fg_esr_fcc" #define DEBUG_PRINT_BUFFER_SIZE 64 /* 3 byte address + 1 space character */ #define ADDR_LEN 4 Loading Loading @@ -403,6 +405,7 @@ struct fg_chip { struct votable *awake_votable; struct votable *delta_bsoc_irq_en_votable; struct votable *batt_miss_irq_en_votable; struct votable *pl_disable_votable; struct fg_sram_param *sp; struct fg_dma_address *addr_map; struct fg_alg_flag *alg_flags; Loading Loading @@ -455,11 +458,11 @@ struct fg_chip { bool qnovo_enable; struct completion soc_update; struct completion soc_ready; struct completion mem_grant; struct delayed_work profile_load_work; struct work_struct status_change_work; struct delayed_work ttf_work; struct delayed_work sram_dump_work; struct delayed_work pl_enable_work; }; /* Debugfs data structures are below */ Loading drivers/power/supply/qcom/fg-memif.c +38 −39 Original line number Diff line number Diff line /* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. /* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -746,15 +746,12 @@ int fg_interleaved_mem_write(struct fg_chip *chip, u16 address, u8 offset, return rc; } #define MEM_GRANT_WAIT_MS 200 #define MEM_GNT_WAIT_TIME_US 10000 #define MEM_GNT_RETRIES 50 static int fg_direct_mem_request(struct fg_chip *chip, bool request) { int rc, ret; int rc, ret, i = 0; u8 val, mask; bool tried_again = false; if (request) reinit_completion(&chip->mem_grant); mask = MEM_ACCESS_REQ_BIT | IACS_SLCT_BIT; val = request ? MEM_ACCESS_REQ_BIT : 0; Loading @@ -769,7 +766,7 @@ static int fg_direct_mem_request(struct fg_chip *chip, bool request) rc = fg_masked_write(chip, MEM_IF_MEM_ARB_CFG(chip), mask, val); if (rc < 0) { pr_err("failed to configure mem_if_mem_arb_cfg rc:%d\n", rc); return rc; goto release; } if (request) Loading @@ -780,43 +777,45 @@ static int fg_direct_mem_request(struct fg_chip *chip, bool request) if (!request) return 0; wait: ret = wait_for_completion_interruptible_timeout( &chip->mem_grant, msecs_to_jiffies(MEM_GRANT_WAIT_MS)); /* If we were interrupted wait again one more time. */ if (ret <= 0) { if ((ret == -ERESTARTSYS || ret == 0) && !tried_again) { pr_debug("trying again, ret=%d\n", ret); tried_again = true; goto wait; } else { pr_err("wait for mem_grant timed out ret=%d\n", ret); fg_dump_regs(chip); /* * HW takes 5 cycles (200 KHz clock) to grant access after requesting * for DMA. Wait for 40 us before polling for MEM_GNT first time. */ usleep_range(40, 41); while (i < MEM_GNT_RETRIES) { rc = fg_read(chip, MEM_IF_INT_RT_STS(chip), &val, 1); if (rc < 0) { pr_err("Error in reading MEM_IF_INT_RT_STS, rc=%d\n", rc); goto release; } if (val & MEM_GNT_BIT) return 0; usleep_range(MEM_GNT_WAIT_TIME_US, MEM_GNT_WAIT_TIME_US + 1); i++; } if (ret <= 0) { rc = -ETIMEDOUT; pr_err("wait for mem_grant timed out, val=0x%x\n", val); fg_dump_regs(chip); release: val = 0; mask = MEM_ACCESS_REQ_BIT | IACS_SLCT_BIT; rc = fg_masked_write(chip, MEM_IF_MEM_INTF_CFG(chip), mask, val); if (rc < 0) { pr_err("failed to configure mem_if_mem_intf_cfg rc=%d\n", rc); return rc; ret = fg_masked_write(chip, MEM_IF_MEM_INTF_CFG(chip), mask, val); if (ret < 0) { pr_err("failed to configure mem_if_mem_intf_cfg rc=%d\n", rc); return ret; } mask = MEM_ARB_LO_LATENCY_EN_BIT | MEM_ARB_REQ_BIT; rc = fg_masked_write(chip, MEM_IF_MEM_ARB_CFG(chip), mask, val); if (rc < 0) { pr_err("failed to configure mem_if_mem_arb_cfg rc:%d\n", rc); return rc; } return -ETIMEDOUT; ret = fg_masked_write(chip, MEM_IF_MEM_ARB_CFG(chip), mask, val); if (ret < 0) { pr_err("failed to configure mem_if_mem_arb_cfg rc:%d\n", rc); return ret; } return rc; Loading drivers/power/supply/qcom/qpnp-fg-gen3.c +113 −57 Original line number Diff line number Diff line /* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. /* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -881,7 +881,7 @@ static int fg_get_prop_capacity(struct fg_chip *chip, int *val) return 0; } if (chip->battery_missing) { if (chip->battery_missing || !chip->soc_reporting_ready) { *val = BATT_MISS_SOC; return 0; } Loading Loading @@ -2093,8 +2093,12 @@ static int fg_adjust_recharge_soc(struct fg_chip *chip) return 0; } } else { /* Charging, do nothing */ if (!chip->recharge_soc_adjusted) return 0; /* Restore the default value */ new_recharge_soc = recharge_soc; chip->recharge_soc_adjusted = false; } } else { /* Restore the default value */ Loading Loading @@ -2567,6 +2571,11 @@ static void status_change_work(struct work_struct *work) goto out; } if (!chip->soc_reporting_ready) { fg_dbg(chip, FG_STATUS, "Profile load is not complete yet\n"); goto out; } rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS, &prop); if (rc < 0) { Loading Loading @@ -2630,7 +2639,7 @@ static void status_change_work(struct work_struct *work) fg_ttf_update(chip); chip->prev_charge_status = chip->charge_status; out: fg_dbg(chip, FG_POWER_SUPPLY, "charge_status:%d charge_type:%d charge_done:%d\n", fg_dbg(chip, FG_STATUS, "charge_status:%d charge_type:%d charge_done:%d\n", chip->charge_status, chip->charge_type, chip->charge_done); pm_relax(chip->dev); } Loading Loading @@ -2733,6 +2742,49 @@ static bool is_profile_load_required(struct fg_chip *chip) return true; } static void fg_update_batt_profile(struct fg_chip *chip) { int rc, offset; u8 val; rc = fg_sram_read(chip, PROFILE_INTEGRITY_WORD, SW_CONFIG_OFFSET, &val, 1, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in reading SW_CONFIG_OFFSET, rc=%d\n", rc); return; } /* * If the RCONN had not been updated, no need to update battery * profile. Else, update the battery profile so that the profile * modified by bootloader or HLOS matches with the profile read * from device tree. */ if (!(val & RCONN_CONFIG_BIT)) return; rc = fg_sram_read(chip, ESR_RSLOW_CHG_WORD, ESR_RSLOW_CHG_OFFSET, &val, 1, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in reading ESR_RSLOW_CHG_OFFSET, rc=%d\n", rc); return; } offset = (ESR_RSLOW_CHG_WORD - PROFILE_LOAD_WORD) * 4 + ESR_RSLOW_CHG_OFFSET; chip->batt_profile[offset] = val; rc = fg_sram_read(chip, ESR_RSLOW_DISCHG_WORD, ESR_RSLOW_DISCHG_OFFSET, &val, 1, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in reading ESR_RSLOW_DISCHG_OFFSET, rc=%d\n", rc); return; } offset = (ESR_RSLOW_DISCHG_WORD - PROFILE_LOAD_WORD) * 4 + ESR_RSLOW_DISCHG_OFFSET; chip->batt_profile[offset] = val; } static void clear_battery_profile(struct fg_chip *chip) { u8 val = 0; Loading Loading @@ -2790,6 +2842,16 @@ static int __fg_restart(struct fg_chip *chip) return rc; } static void pl_enable_work(struct work_struct *work) { struct fg_chip *chip = container_of(work, struct fg_chip, pl_enable_work.work); vote(chip->pl_disable_votable, ESR_FCC_VOTER, false, 0); vote(chip->awake_votable, ESR_FCC_VOTER, false, 0); } static void profile_load_work(struct work_struct *work) { struct fg_chip *chip = container_of(work, Loading @@ -2816,6 +2878,8 @@ static void profile_load_work(struct work_struct *work) if (!chip->profile_available) goto out; fg_update_batt_profile(chip); if (!is_profile_load_required(chip)) goto done; Loading @@ -2841,14 +2905,6 @@ static void profile_load_work(struct work_struct *work) goto out; } rc = __fg_restart(chip); if (rc < 0) { pr_err("Error in restarting FG, rc=%d\n", rc); goto out; } fg_dbg(chip, FG_STATUS, "SOC is ready\n"); /* Set the profile integrity bit */ val = HLOS_RESTART_BIT | PROFILE_LOAD_BIT; rc = fg_sram_write(chip, PROFILE_INTEGRITY_WORD, Loading @@ -2858,6 +2914,13 @@ static void profile_load_work(struct work_struct *work) goto out; } rc = __fg_restart(chip); if (rc < 0) { pr_err("Error in restarting FG, rc=%d\n", rc); goto out; } fg_dbg(chip, FG_STATUS, "SOC is ready\n"); done: rc = fg_bp_params_config(chip); if (rc < 0) Loading @@ -2877,13 +2940,23 @@ static void profile_load_work(struct work_struct *work) rc); } rc = fg_rconn_config(chip); if (rc < 0) pr_err("Error in configuring Rconn, rc=%d\n", rc); batt_psy_initialized(chip); fg_notify_charger(chip); chip->profile_loaded = true; fg_dbg(chip, FG_STATUS, "profile loaded successfully"); out: chip->soc_reporting_ready = true; vote(chip->awake_votable, ESR_FCC_VOTER, true, 0); schedule_delayed_work(&chip->pl_enable_work, msecs_to_jiffies(5000)); vote(chip->awake_votable, PROFILE_LOAD, false, 0); if (!work_pending(&chip->status_change_work)) { pm_stay_awake(chip->dev); schedule_work(&chip->status_change_work); } } static void sram_dump_work(struct work_struct *work) Loading Loading @@ -4071,12 +4144,6 @@ static int fg_hw_init(struct fg_chip *chip) return rc; } rc = fg_rconn_config(chip); if (rc < 0) { pr_err("Error in configuring Rconn, rc=%d\n", rc); return rc; } fg_encode(chip->sp, FG_SRAM_ESR_TIGHT_FILTER, chip->dt.esr_tight_flt_upct, buf); rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_word, Loading Loading @@ -4172,25 +4239,6 @@ static int fg_adjust_timebase(struct fg_chip *chip) /* INTERRUPT HANDLERS STAY HERE */ static irqreturn_t fg_dma_grant_irq_handler(int irq, void *data) { struct fg_chip *chip = data; u8 status; int rc; rc = fg_read(chip, MEM_IF_INT_RT_STS(chip), &status, 1); if (rc < 0) { pr_err("failed to read addr=0x%04x, rc=%d\n", MEM_IF_INT_RT_STS(chip), rc); return IRQ_HANDLED; } fg_dbg(chip, FG_IRQ, "irq %d triggered, status:%d\n", irq, status); complete_all(&chip->mem_grant); return IRQ_HANDLED; } static irqreturn_t fg_mem_xcp_irq_handler(int irq, void *data) { struct fg_chip *chip = data; Loading Loading @@ -4250,6 +4298,8 @@ static irqreturn_t fg_batt_missing_irq_handler(int irq, void *data) chip->profile_loaded = false; chip->soc_reporting_ready = false; chip->batt_id_ohms = -EINVAL; cancel_delayed_work_sync(&chip->pl_enable_work); vote(chip->pl_disable_votable, ESR_FCC_VOTER, true, 0); return IRQ_HANDLED; } Loading Loading @@ -4476,7 +4526,7 @@ static struct fg_irq_info fg_irqs[FG_IRQ_MAX] = { /* MEM_IF irqs */ [DMA_GRANT_IRQ] = { .name = "dma-grant", .handler = fg_dma_grant_irq_handler, .handler = fg_dummy_irq_handler, .wakeable = true, }, [MEM_XCP_IRQ] = { Loading Loading @@ -5105,6 +5155,12 @@ static int fg_gen3_probe(struct platform_device *pdev) } } chip->pl_disable_votable = find_votable("PL_DISABLE"); if (chip->pl_disable_votable == NULL) { rc = -EPROBE_DEFER; goto exit; } chip->awake_votable = create_votable("FG_WS", VOTE_SET_ANY, fg_awake_cb, chip); if (IS_ERR(chip->awake_votable)) { Loading Loading @@ -5147,8 +5203,8 @@ static int fg_gen3_probe(struct platform_device *pdev) mutex_init(&chip->qnovo_esr_ctrl_lock); init_completion(&chip->soc_update); init_completion(&chip->soc_ready); init_completion(&chip->mem_grant); INIT_DELAYED_WORK(&chip->profile_load_work, profile_load_work); INIT_DELAYED_WORK(&chip->pl_enable_work, pl_enable_work); INIT_WORK(&chip->status_change_work, status_change_work); INIT_DELAYED_WORK(&chip->ttf_work, ttf_work); INIT_DELAYED_WORK(&chip->sram_dump_work, sram_dump_work); Loading @@ -5162,23 +5218,6 @@ static int fg_gen3_probe(struct platform_device *pdev) platform_set_drvdata(pdev, chip); rc = fg_register_interrupts(chip); if (rc < 0) { dev_err(chip->dev, "Error in registering interrupts, rc:%d\n", rc); goto exit; } /* Keep SOC_UPDATE irq disabled until we require it */ if (fg_irqs[SOC_UPDATE_IRQ].irq) disable_irq_nosync(fg_irqs[SOC_UPDATE_IRQ].irq); /* Keep BSOC_DELTA_IRQ disabled until we require it */ vote(chip->delta_bsoc_irq_en_votable, DELTA_BSOC_IRQ_VOTER, false, 0); /* Keep BATT_MISSING_IRQ disabled until we require it */ vote(chip->batt_miss_irq_en_votable, BATT_MISS_IRQ_VOTER, false, 0); rc = fg_hw_init(chip); if (rc < 0) { dev_err(chip->dev, "Error in initializing FG hardware, rc:%d\n", Loading Loading @@ -5206,6 +5245,23 @@ static int fg_gen3_probe(struct platform_device *pdev) goto exit; } rc = fg_register_interrupts(chip); if (rc < 0) { dev_err(chip->dev, "Error in registering interrupts, rc:%d\n", rc); goto exit; } /* Keep SOC_UPDATE irq disabled until we require it */ if (fg_irqs[SOC_UPDATE_IRQ].irq) disable_irq_nosync(fg_irqs[SOC_UPDATE_IRQ].irq); /* Keep BSOC_DELTA_IRQ disabled until we require it */ vote(chip->delta_bsoc_irq_en_votable, DELTA_BSOC_IRQ_VOTER, false, 0); /* Keep BATT_MISSING_IRQ disabled until we require it */ vote(chip->batt_miss_irq_en_votable, BATT_MISS_IRQ_VOTER, false, 0); rc = fg_debugfs_create(chip); if (rc < 0) { dev_err(chip->dev, "Error in creating debugfs entries, rc:%d\n", Loading Loading
drivers/power/supply/qcom/fg-core.h +4 −1 Original line number Diff line number Diff line Loading @@ -57,6 +57,8 @@ /* Battery missing irq votable reasons */ #define BATT_MISS_IRQ_VOTER "fg_batt_miss_irq" #define ESR_FCC_VOTER "fg_esr_fcc" #define DEBUG_PRINT_BUFFER_SIZE 64 /* 3 byte address + 1 space character */ #define ADDR_LEN 4 Loading Loading @@ -403,6 +405,7 @@ struct fg_chip { struct votable *awake_votable; struct votable *delta_bsoc_irq_en_votable; struct votable *batt_miss_irq_en_votable; struct votable *pl_disable_votable; struct fg_sram_param *sp; struct fg_dma_address *addr_map; struct fg_alg_flag *alg_flags; Loading Loading @@ -455,11 +458,11 @@ struct fg_chip { bool qnovo_enable; struct completion soc_update; struct completion soc_ready; struct completion mem_grant; struct delayed_work profile_load_work; struct work_struct status_change_work; struct delayed_work ttf_work; struct delayed_work sram_dump_work; struct delayed_work pl_enable_work; }; /* Debugfs data structures are below */ Loading
drivers/power/supply/qcom/fg-memif.c +38 −39 Original line number Diff line number Diff line /* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. /* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -746,15 +746,12 @@ int fg_interleaved_mem_write(struct fg_chip *chip, u16 address, u8 offset, return rc; } #define MEM_GRANT_WAIT_MS 200 #define MEM_GNT_WAIT_TIME_US 10000 #define MEM_GNT_RETRIES 50 static int fg_direct_mem_request(struct fg_chip *chip, bool request) { int rc, ret; int rc, ret, i = 0; u8 val, mask; bool tried_again = false; if (request) reinit_completion(&chip->mem_grant); mask = MEM_ACCESS_REQ_BIT | IACS_SLCT_BIT; val = request ? MEM_ACCESS_REQ_BIT : 0; Loading @@ -769,7 +766,7 @@ static int fg_direct_mem_request(struct fg_chip *chip, bool request) rc = fg_masked_write(chip, MEM_IF_MEM_ARB_CFG(chip), mask, val); if (rc < 0) { pr_err("failed to configure mem_if_mem_arb_cfg rc:%d\n", rc); return rc; goto release; } if (request) Loading @@ -780,43 +777,45 @@ static int fg_direct_mem_request(struct fg_chip *chip, bool request) if (!request) return 0; wait: ret = wait_for_completion_interruptible_timeout( &chip->mem_grant, msecs_to_jiffies(MEM_GRANT_WAIT_MS)); /* If we were interrupted wait again one more time. */ if (ret <= 0) { if ((ret == -ERESTARTSYS || ret == 0) && !tried_again) { pr_debug("trying again, ret=%d\n", ret); tried_again = true; goto wait; } else { pr_err("wait for mem_grant timed out ret=%d\n", ret); fg_dump_regs(chip); /* * HW takes 5 cycles (200 KHz clock) to grant access after requesting * for DMA. Wait for 40 us before polling for MEM_GNT first time. */ usleep_range(40, 41); while (i < MEM_GNT_RETRIES) { rc = fg_read(chip, MEM_IF_INT_RT_STS(chip), &val, 1); if (rc < 0) { pr_err("Error in reading MEM_IF_INT_RT_STS, rc=%d\n", rc); goto release; } if (val & MEM_GNT_BIT) return 0; usleep_range(MEM_GNT_WAIT_TIME_US, MEM_GNT_WAIT_TIME_US + 1); i++; } if (ret <= 0) { rc = -ETIMEDOUT; pr_err("wait for mem_grant timed out, val=0x%x\n", val); fg_dump_regs(chip); release: val = 0; mask = MEM_ACCESS_REQ_BIT | IACS_SLCT_BIT; rc = fg_masked_write(chip, MEM_IF_MEM_INTF_CFG(chip), mask, val); if (rc < 0) { pr_err("failed to configure mem_if_mem_intf_cfg rc=%d\n", rc); return rc; ret = fg_masked_write(chip, MEM_IF_MEM_INTF_CFG(chip), mask, val); if (ret < 0) { pr_err("failed to configure mem_if_mem_intf_cfg rc=%d\n", rc); return ret; } mask = MEM_ARB_LO_LATENCY_EN_BIT | MEM_ARB_REQ_BIT; rc = fg_masked_write(chip, MEM_IF_MEM_ARB_CFG(chip), mask, val); if (rc < 0) { pr_err("failed to configure mem_if_mem_arb_cfg rc:%d\n", rc); return rc; } return -ETIMEDOUT; ret = fg_masked_write(chip, MEM_IF_MEM_ARB_CFG(chip), mask, val); if (ret < 0) { pr_err("failed to configure mem_if_mem_arb_cfg rc:%d\n", rc); return ret; } return rc; Loading
drivers/power/supply/qcom/qpnp-fg-gen3.c +113 −57 Original line number Diff line number Diff line /* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. /* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -881,7 +881,7 @@ static int fg_get_prop_capacity(struct fg_chip *chip, int *val) return 0; } if (chip->battery_missing) { if (chip->battery_missing || !chip->soc_reporting_ready) { *val = BATT_MISS_SOC; return 0; } Loading Loading @@ -2093,8 +2093,12 @@ static int fg_adjust_recharge_soc(struct fg_chip *chip) return 0; } } else { /* Charging, do nothing */ if (!chip->recharge_soc_adjusted) return 0; /* Restore the default value */ new_recharge_soc = recharge_soc; chip->recharge_soc_adjusted = false; } } else { /* Restore the default value */ Loading Loading @@ -2567,6 +2571,11 @@ static void status_change_work(struct work_struct *work) goto out; } if (!chip->soc_reporting_ready) { fg_dbg(chip, FG_STATUS, "Profile load is not complete yet\n"); goto out; } rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_STATUS, &prop); if (rc < 0) { Loading Loading @@ -2630,7 +2639,7 @@ static void status_change_work(struct work_struct *work) fg_ttf_update(chip); chip->prev_charge_status = chip->charge_status; out: fg_dbg(chip, FG_POWER_SUPPLY, "charge_status:%d charge_type:%d charge_done:%d\n", fg_dbg(chip, FG_STATUS, "charge_status:%d charge_type:%d charge_done:%d\n", chip->charge_status, chip->charge_type, chip->charge_done); pm_relax(chip->dev); } Loading Loading @@ -2733,6 +2742,49 @@ static bool is_profile_load_required(struct fg_chip *chip) return true; } static void fg_update_batt_profile(struct fg_chip *chip) { int rc, offset; u8 val; rc = fg_sram_read(chip, PROFILE_INTEGRITY_WORD, SW_CONFIG_OFFSET, &val, 1, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in reading SW_CONFIG_OFFSET, rc=%d\n", rc); return; } /* * If the RCONN had not been updated, no need to update battery * profile. Else, update the battery profile so that the profile * modified by bootloader or HLOS matches with the profile read * from device tree. */ if (!(val & RCONN_CONFIG_BIT)) return; rc = fg_sram_read(chip, ESR_RSLOW_CHG_WORD, ESR_RSLOW_CHG_OFFSET, &val, 1, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in reading ESR_RSLOW_CHG_OFFSET, rc=%d\n", rc); return; } offset = (ESR_RSLOW_CHG_WORD - PROFILE_LOAD_WORD) * 4 + ESR_RSLOW_CHG_OFFSET; chip->batt_profile[offset] = val; rc = fg_sram_read(chip, ESR_RSLOW_DISCHG_WORD, ESR_RSLOW_DISCHG_OFFSET, &val, 1, FG_IMA_DEFAULT); if (rc < 0) { pr_err("Error in reading ESR_RSLOW_DISCHG_OFFSET, rc=%d\n", rc); return; } offset = (ESR_RSLOW_DISCHG_WORD - PROFILE_LOAD_WORD) * 4 + ESR_RSLOW_DISCHG_OFFSET; chip->batt_profile[offset] = val; } static void clear_battery_profile(struct fg_chip *chip) { u8 val = 0; Loading Loading @@ -2790,6 +2842,16 @@ static int __fg_restart(struct fg_chip *chip) return rc; } static void pl_enable_work(struct work_struct *work) { struct fg_chip *chip = container_of(work, struct fg_chip, pl_enable_work.work); vote(chip->pl_disable_votable, ESR_FCC_VOTER, false, 0); vote(chip->awake_votable, ESR_FCC_VOTER, false, 0); } static void profile_load_work(struct work_struct *work) { struct fg_chip *chip = container_of(work, Loading @@ -2816,6 +2878,8 @@ static void profile_load_work(struct work_struct *work) if (!chip->profile_available) goto out; fg_update_batt_profile(chip); if (!is_profile_load_required(chip)) goto done; Loading @@ -2841,14 +2905,6 @@ static void profile_load_work(struct work_struct *work) goto out; } rc = __fg_restart(chip); if (rc < 0) { pr_err("Error in restarting FG, rc=%d\n", rc); goto out; } fg_dbg(chip, FG_STATUS, "SOC is ready\n"); /* Set the profile integrity bit */ val = HLOS_RESTART_BIT | PROFILE_LOAD_BIT; rc = fg_sram_write(chip, PROFILE_INTEGRITY_WORD, Loading @@ -2858,6 +2914,13 @@ static void profile_load_work(struct work_struct *work) goto out; } rc = __fg_restart(chip); if (rc < 0) { pr_err("Error in restarting FG, rc=%d\n", rc); goto out; } fg_dbg(chip, FG_STATUS, "SOC is ready\n"); done: rc = fg_bp_params_config(chip); if (rc < 0) Loading @@ -2877,13 +2940,23 @@ static void profile_load_work(struct work_struct *work) rc); } rc = fg_rconn_config(chip); if (rc < 0) pr_err("Error in configuring Rconn, rc=%d\n", rc); batt_psy_initialized(chip); fg_notify_charger(chip); chip->profile_loaded = true; fg_dbg(chip, FG_STATUS, "profile loaded successfully"); out: chip->soc_reporting_ready = true; vote(chip->awake_votable, ESR_FCC_VOTER, true, 0); schedule_delayed_work(&chip->pl_enable_work, msecs_to_jiffies(5000)); vote(chip->awake_votable, PROFILE_LOAD, false, 0); if (!work_pending(&chip->status_change_work)) { pm_stay_awake(chip->dev); schedule_work(&chip->status_change_work); } } static void sram_dump_work(struct work_struct *work) Loading Loading @@ -4071,12 +4144,6 @@ static int fg_hw_init(struct fg_chip *chip) return rc; } rc = fg_rconn_config(chip); if (rc < 0) { pr_err("Error in configuring Rconn, rc=%d\n", rc); return rc; } fg_encode(chip->sp, FG_SRAM_ESR_TIGHT_FILTER, chip->dt.esr_tight_flt_upct, buf); rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_TIGHT_FILTER].addr_word, Loading Loading @@ -4172,25 +4239,6 @@ static int fg_adjust_timebase(struct fg_chip *chip) /* INTERRUPT HANDLERS STAY HERE */ static irqreturn_t fg_dma_grant_irq_handler(int irq, void *data) { struct fg_chip *chip = data; u8 status; int rc; rc = fg_read(chip, MEM_IF_INT_RT_STS(chip), &status, 1); if (rc < 0) { pr_err("failed to read addr=0x%04x, rc=%d\n", MEM_IF_INT_RT_STS(chip), rc); return IRQ_HANDLED; } fg_dbg(chip, FG_IRQ, "irq %d triggered, status:%d\n", irq, status); complete_all(&chip->mem_grant); return IRQ_HANDLED; } static irqreturn_t fg_mem_xcp_irq_handler(int irq, void *data) { struct fg_chip *chip = data; Loading Loading @@ -4250,6 +4298,8 @@ static irqreturn_t fg_batt_missing_irq_handler(int irq, void *data) chip->profile_loaded = false; chip->soc_reporting_ready = false; chip->batt_id_ohms = -EINVAL; cancel_delayed_work_sync(&chip->pl_enable_work); vote(chip->pl_disable_votable, ESR_FCC_VOTER, true, 0); return IRQ_HANDLED; } Loading Loading @@ -4476,7 +4526,7 @@ static struct fg_irq_info fg_irqs[FG_IRQ_MAX] = { /* MEM_IF irqs */ [DMA_GRANT_IRQ] = { .name = "dma-grant", .handler = fg_dma_grant_irq_handler, .handler = fg_dummy_irq_handler, .wakeable = true, }, [MEM_XCP_IRQ] = { Loading Loading @@ -5105,6 +5155,12 @@ static int fg_gen3_probe(struct platform_device *pdev) } } chip->pl_disable_votable = find_votable("PL_DISABLE"); if (chip->pl_disable_votable == NULL) { rc = -EPROBE_DEFER; goto exit; } chip->awake_votable = create_votable("FG_WS", VOTE_SET_ANY, fg_awake_cb, chip); if (IS_ERR(chip->awake_votable)) { Loading Loading @@ -5147,8 +5203,8 @@ static int fg_gen3_probe(struct platform_device *pdev) mutex_init(&chip->qnovo_esr_ctrl_lock); init_completion(&chip->soc_update); init_completion(&chip->soc_ready); init_completion(&chip->mem_grant); INIT_DELAYED_WORK(&chip->profile_load_work, profile_load_work); INIT_DELAYED_WORK(&chip->pl_enable_work, pl_enable_work); INIT_WORK(&chip->status_change_work, status_change_work); INIT_DELAYED_WORK(&chip->ttf_work, ttf_work); INIT_DELAYED_WORK(&chip->sram_dump_work, sram_dump_work); Loading @@ -5162,23 +5218,6 @@ static int fg_gen3_probe(struct platform_device *pdev) platform_set_drvdata(pdev, chip); rc = fg_register_interrupts(chip); if (rc < 0) { dev_err(chip->dev, "Error in registering interrupts, rc:%d\n", rc); goto exit; } /* Keep SOC_UPDATE irq disabled until we require it */ if (fg_irqs[SOC_UPDATE_IRQ].irq) disable_irq_nosync(fg_irqs[SOC_UPDATE_IRQ].irq); /* Keep BSOC_DELTA_IRQ disabled until we require it */ vote(chip->delta_bsoc_irq_en_votable, DELTA_BSOC_IRQ_VOTER, false, 0); /* Keep BATT_MISSING_IRQ disabled until we require it */ vote(chip->batt_miss_irq_en_votable, BATT_MISS_IRQ_VOTER, false, 0); rc = fg_hw_init(chip); if (rc < 0) { dev_err(chip->dev, "Error in initializing FG hardware, rc:%d\n", Loading Loading @@ -5206,6 +5245,23 @@ static int fg_gen3_probe(struct platform_device *pdev) goto exit; } rc = fg_register_interrupts(chip); if (rc < 0) { dev_err(chip->dev, "Error in registering interrupts, rc:%d\n", rc); goto exit; } /* Keep SOC_UPDATE irq disabled until we require it */ if (fg_irqs[SOC_UPDATE_IRQ].irq) disable_irq_nosync(fg_irqs[SOC_UPDATE_IRQ].irq); /* Keep BSOC_DELTA_IRQ disabled until we require it */ vote(chip->delta_bsoc_irq_en_votable, DELTA_BSOC_IRQ_VOTER, false, 0); /* Keep BATT_MISSING_IRQ disabled until we require it */ vote(chip->batt_miss_irq_en_votable, BATT_MISS_IRQ_VOTER, false, 0); rc = fg_debugfs_create(chip); if (rc < 0) { dev_err(chip->dev, "Error in creating debugfs entries, rc:%d\n", Loading