Loading drivers/power/qcom-charger/fg-core.h +2 −0 Original line number Original line Diff line number Diff line Loading @@ -342,6 +342,8 @@ extern int fg_read(struct fg_chip *chip, int addr, u8 *val, int len); extern int fg_write(struct fg_chip *chip, int addr, u8 *val, int len); extern int fg_write(struct fg_chip *chip, int addr, u8 *val, int len); extern int fg_masked_write(struct fg_chip *chip, int addr, u8 mask, u8 val); extern int fg_masked_write(struct fg_chip *chip, int addr, u8 mask, u8 val); extern int fg_ima_init(struct fg_chip *chip); extern int fg_ima_init(struct fg_chip *chip); extern int fg_clear_ima_errors_if_any(struct fg_chip *chip, bool check_hw_sts); extern int fg_clear_dma_errors_if_any(struct fg_chip *chip); extern int fg_debugfs_create(struct fg_chip *chip); extern int fg_debugfs_create(struct fg_chip *chip); extern void fill_string(char *str, size_t str_len, u8 *buf, int buf_len); extern void fill_string(char *str, size_t str_len, u8 *buf, int buf_len); extern int64_t twos_compliment_extend(int64_t val, int s_bit_pos); extern int64_t twos_compliment_extend(int64_t val, int s_bit_pos); Loading drivers/power/qcom-charger/fg-memif.c +156 −37 Original line number Original line Diff line number Diff line Loading @@ -64,44 +64,90 @@ static int fg_config_access_mode(struct fg_chip *chip, bool access, bool burst) static int fg_run_iacs_clear_sequence(struct fg_chip *chip) static int fg_run_iacs_clear_sequence(struct fg_chip *chip) { { u8 tmp; u8 val, hw_sts, exp_sts; int rc; int rc, tries = 250; /* /* * Values to write for running IACS clear sequence comes from * Values to write for running IACS clear sequence comes from * hardware documentation. * hardware documentation. */ */ rc = fg_masked_write(chip, MEM_IF_IMA_CFG(chip), IACS_CLR_BIT, rc = fg_masked_write(chip, MEM_IF_IMA_CFG(chip), IACS_CLR_BIT); IACS_CLR_BIT | STATIC_CLK_EN_BIT, IACS_CLR_BIT | STATIC_CLK_EN_BIT); if (rc < 0) { if (rc < 0) { pr_err("failed to write 0x%04x, rc=%d\n", MEM_IF_IMA_CFG(chip), pr_err("failed to write 0x%04x, rc=%d\n", MEM_IF_IMA_CFG(chip), rc); rc); return rc; return rc; } } tmp = 0x4; rc = fg_config_access_mode(chip, FG_READ, false); rc = fg_write(chip, MEM_IF_ADDR_MSB(chip), &tmp, 1); if (rc < 0) { if (rc < 0) { pr_err("failed to write 0x%04x, rc=%d\n", MEM_IF_ADDR_LSB(chip), pr_err("failed to write to 0x%04x, rc=%d\n", rc); MEM_IF_IMA_CTL(chip), rc); return rc; return rc; } } tmp = 0x0; rc = fg_masked_write(chip, MEM_IF_MEM_INTF_CFG(chip), rc = fg_write(chip, MEM_IF_WR_DATA3(chip), &tmp, 1); MEM_ACCESS_REQ_BIT | IACS_SLCT_BIT, MEM_ACCESS_REQ_BIT | IACS_SLCT_BIT); if (rc < 0) { if (rc < 0) { pr_err("failed to write 0x%04x, rc=%d\n", MEM_IF_WR_DATA3(chip), pr_err("failed to set ima_req_access bit rc=%d\n", rc); rc); return rc; } /* Delay for the clock to reach FG */ usleep_range(35, 40); while (1) { val = 0; rc = fg_write(chip, MEM_IF_ADDR_MSB(chip), &val, 1); if (rc < 0) { pr_err("failed to write 0x%04x, rc=%d\n", MEM_IF_ADDR_MSB(chip), rc); return rc; return rc; } } rc = fg_read(chip, MEM_IF_RD_DATA3(chip), &tmp, 1); val = 0; rc = fg_write(chip, MEM_IF_WR_DATA3(chip), &val, 1); if (rc < 0) { if (rc < 0) { pr_err("failed to read 0x%04x, rc=%d\n", MEM_IF_RD_DATA3(chip), pr_err("failed to write 0x%04x, rc=%d\n", rc); MEM_IF_WR_DATA3(chip), rc); return rc; return rc; } } rc = fg_read(chip, MEM_IF_RD_DATA3(chip), &val, 1); if (rc < 0) { pr_err("failed to read 0x%04x, rc=%d\n", MEM_IF_RD_DATA3(chip), rc); return rc; } /* Delay for IMA hardware to clear */ usleep_range(35, 40); rc = fg_read(chip, MEM_IF_IMA_HW_STS(chip), &hw_sts, 1); if (rc < 0) { pr_err("failed to read ima_hw_sts rc=%d\n", rc); return rc; } if (hw_sts != 0) continue; rc = fg_read(chip, MEM_IF_IMA_EXP_STS(chip), &exp_sts, 1); if (rc < 0) { pr_err("failed to read ima_exp_sts rc=%d\n", rc); return rc; } if (exp_sts == 0 || !(--tries)) break; } if (!tries) pr_err("Failed to clear the error? hw_sts: %x exp_sts: %d\n", hw_sts, exp_sts); rc = fg_masked_write(chip, MEM_IF_IMA_CFG(chip), IACS_CLR_BIT, 0); rc = fg_masked_write(chip, MEM_IF_IMA_CFG(chip), IACS_CLR_BIT, 0); if (rc < 0) { if (rc < 0) { pr_err("failed to write 0x%04x, rc=%d\n", MEM_IF_IMA_CFG(chip), pr_err("failed to write 0x%04x, rc=%d\n", MEM_IF_IMA_CFG(chip), Loading @@ -109,22 +155,54 @@ static int fg_run_iacs_clear_sequence(struct fg_chip *chip) return rc; return rc; } } udelay(5); rc = fg_masked_write(chip, MEM_IF_MEM_INTF_CFG(chip), MEM_ACCESS_REQ_BIT | IACS_SLCT_BIT, 0); if (rc < 0) { pr_err("failed to write to 0x%04x, rc=%d\n", MEM_IF_MEM_INTF_CFG(chip), rc); return rc; } /* Delay before next transaction is attempted */ usleep_range(35, 40); fg_dbg(chip, FG_SRAM_READ | FG_SRAM_WRITE, "IACS clear sequence complete\n"); fg_dbg(chip, FG_SRAM_READ | FG_SRAM_WRITE, "IACS clear sequence complete\n"); return rc; return rc; } } static int fg_check_for_ima_errors(struct fg_chip *chip) int fg_clear_dma_errors_if_any(struct fg_chip *chip) { { int rc = 0; int rc; u8 err_sts, exp_sts = 0, hw_sts = 0; u8 dma_sts; rc = fg_read(chip, MEM_IF_IMA_ERR_STS(chip), &err_sts, 1); rc = fg_read(chip, MEM_IF_DMA_STS(chip), &dma_sts, 1); if (rc < 0) { if (rc < 0) { pr_err("failed to read ima_err_sts rc=%d\n", rc); pr_err("failed to read addr=0x%04x, rc=%d\n", MEM_IF_DMA_STS(chip), rc); return rc; } fg_dbg(chip, FG_STATUS, "dma_sts: %x\n", dma_sts); if (dma_sts & (DMA_WRITE_ERROR_BIT | DMA_READ_ERROR_BIT)) { rc = fg_masked_write(chip, MEM_IF_DMA_CTL(chip), DMA_CLEAR_LOG_BIT, DMA_CLEAR_LOG_BIT); if (rc < 0) { pr_err("failed to write addr=0x%04x, rc=%d\n", MEM_IF_DMA_CTL(chip), rc); return rc; return rc; } } } return 0; } int fg_clear_ima_errors_if_any(struct fg_chip *chip, bool check_hw_sts) { int rc = 0; u8 err_sts, exp_sts = 0, hw_sts = 0; bool run_err_clr_seq = false; if (err_sts & (ADDR_STBL_ERR_BIT | WR_ACS_ERR_BIT | RD_ACS_ERR_BIT)) { rc = fg_read(chip, MEM_IF_IMA_EXP_STS(chip), &exp_sts, 1); rc = fg_read(chip, MEM_IF_IMA_EXP_STS(chip), &exp_sts, 1); if (rc < 0) { if (rc < 0) { pr_err("failed to read ima_exp_sts rc=%d\n", rc); pr_err("failed to read ima_exp_sts rc=%d\n", rc); Loading @@ -137,9 +215,36 @@ static int fg_check_for_ima_errors(struct fg_chip *chip) return rc; return rc; } } pr_err("ima_err_sts=%x ima_exp_sts=%x ima_hw_sts=%x\n", rc = fg_read(chip, MEM_IF_IMA_ERR_STS(chip), &err_sts, 1); if (rc < 0) { pr_err("failed to read ima_err_sts rc=%d\n", rc); return rc; } fg_dbg(chip, FG_STATUS, "ima_err_sts=%x ima_exp_sts=%x ima_hw_sts=%x\n", err_sts, exp_sts, hw_sts); err_sts, exp_sts, hw_sts); if (check_hw_sts) { /* * Lower nibble should be equal to upper nibble before SRAM * transactions begins from SW side. If they are unequal, then * the error clear sequence should be run irrespective of IMA * exception errors. */ if ((hw_sts & 0x0F) != hw_sts >> 4) { pr_err("IMA HW not in correct state, hw_sts=%x\n", hw_sts); run_err_clr_seq = true; } } if (exp_sts & (IACS_ERR_BIT | XCT_TYPE_ERR_BIT | DATA_RD_ERR_BIT | DATA_WR_ERR_BIT | ADDR_BURST_WRAP_BIT | ADDR_STABLE_ERR_BIT)) { pr_err("IMA exception bit set, exp_sts=%x\n", exp_sts); run_err_clr_seq = true; } if (run_err_clr_seq) { /* clear the error */ /* clear the error */ rc = fg_run_iacs_clear_sequence(chip); rc = fg_run_iacs_clear_sequence(chip); if (rc < 0) { if (rc < 0) { Loading @@ -156,7 +261,7 @@ static int fg_check_for_ima_errors(struct fg_chip *chip) static int fg_check_iacs_ready(struct fg_chip *chip) static int fg_check_iacs_ready(struct fg_chip *chip) { { int rc = 0, timeout = 250; int rc = 0, tries = 250; u8 ima_opr_sts = 0; u8 ima_opr_sts = 0; /* /* Loading @@ -176,17 +281,17 @@ static int fg_check_iacs_ready(struct fg_chip *chip) if (ima_opr_sts & IACS_RDY_BIT) if (ima_opr_sts & IACS_RDY_BIT) break; break; if (!(--timeout)) if (!(--tries)) break; break; /* delay for iacs_ready to be asserted */ /* delay for iacs_ready to be asserted */ usleep_range(5000, 7000); usleep_range(5000, 7000); } } if (!timeout) { if (!tries) { pr_err("IACS_RDY not set\n"); pr_err("IACS_RDY not set\n"); /* check for error condition */ rc = fg_check_for_ima_errors(chip); rc = fg_clear_ima_errors_if_any(chip, false); if (rc < 0) { if (rc < 0) { pr_err("Failed to check for ima errors rc=%d\n", rc); pr_err("Failed to check for ima errors rc=%d\n", rc); return rc; return rc; Loading Loading @@ -250,7 +355,7 @@ static int __fg_interleaved_mem_write(struct fg_chip *chip, u16 address, } } /* check for error condition */ /* check for error condition */ rc = fg_check_for_ima_errors(chip); rc = fg_clear_ima_errors_if_any(chip, false); if (rc < 0) { if (rc < 0) { pr_err("Failed to check for ima errors rc=%d\n", rc); pr_err("Failed to check for ima errors rc=%d\n", rc); return rc; return rc; Loading Loading @@ -296,7 +401,7 @@ static int __fg_interleaved_mem_read(struct fg_chip *chip, u16 address, offset = 0; offset = 0; /* check for error condition */ /* check for error condition */ rc = fg_check_for_ima_errors(chip); rc = fg_clear_ima_errors_if_any(chip, false); if (rc < 0) { if (rc < 0) { pr_err("Failed to check for ima errors rc=%d\n", rc); pr_err("Failed to check for ima errors rc=%d\n", rc); return rc; return rc; Loading Loading @@ -581,5 +686,19 @@ int fg_ima_init(struct fg_chip *chip) return rc; return rc; } } /* Clear DMA errors if any before clearing IMA errors */ rc = fg_clear_dma_errors_if_any(chip); if (rc < 0) { pr_err("Error in checking DMA errors rc:%d\n", rc); return rc; } /* Clear IMA errors if any before SRAM transactions can begin */ rc = fg_clear_ima_errors_if_any(chip, true); if (rc < 0 && rc != -EAGAIN) { pr_err("Error in checking IMA errors rc:%d\n", rc); return rc; } return 0; return 0; } } drivers/power/qcom-charger/fg-reg.h +22 −0 Original line number Original line Diff line number Diff line Loading @@ -258,6 +258,7 @@ #define ESR_REQ_CTL_EN_BIT BIT(0) #define ESR_REQ_CTL_EN_BIT BIT(0) /* FG_MEM_IF register and bit definitions */ /* FG_MEM_IF register and bit definitions */ #define MEM_IF_INT_RT_STS(chip) ((chip->mem_if_base) + 0x10) #define MEM_IF_MEM_INTF_CFG(chip) ((chip->mem_if_base) + 0x50) #define MEM_IF_MEM_INTF_CFG(chip) ((chip->mem_if_base) + 0x50) #define MEM_IF_IMA_CTL(chip) ((chip->mem_if_base) + 0x51) #define MEM_IF_IMA_CTL(chip) ((chip->mem_if_base) + 0x51) #define MEM_IF_IMA_CFG(chip) ((chip->mem_if_base) + 0x52) #define MEM_IF_IMA_CFG(chip) ((chip->mem_if_base) + 0x52) Loading @@ -273,6 +274,11 @@ #define MEM_IF_WR_DATA3(chip) ((chip->mem_if_base) + 0x66) #define MEM_IF_WR_DATA3(chip) ((chip->mem_if_base) + 0x66) #define MEM_IF_RD_DATA0(chip) ((chip->mem_if_base) + 0x67) #define MEM_IF_RD_DATA0(chip) ((chip->mem_if_base) + 0x67) #define MEM_IF_RD_DATA3(chip) ((chip->mem_if_base) + 0x6A) #define MEM_IF_RD_DATA3(chip) ((chip->mem_if_base) + 0x6A) #define MEM_IF_DMA_STS(chip) ((chip->mem_if_base) + 0x70) #define MEM_IF_DMA_CTL(chip) ((chip->mem_if_base) + 0x71) /* MEM_IF_INT_RT_STS */ #define MEM_XCP_BIT BIT(1) /* MEM_IF_MEM_INTF_CFG */ /* MEM_IF_MEM_INTF_CFG */ #define MEM_ACCESS_REQ_BIT BIT(7) #define MEM_ACCESS_REQ_BIT BIT(7) Loading @@ -286,10 +292,19 @@ /* MEM_IF_IMA_CFG */ /* MEM_IF_IMA_CFG */ #define IACS_CLR_BIT BIT(2) #define IACS_CLR_BIT BIT(2) #define IACS_INTR_SRC_SLCT_BIT BIT(3) #define IACS_INTR_SRC_SLCT_BIT BIT(3) #define STATIC_CLK_EN_BIT BIT(4) /* MEM_IF_IMA_OPR_STS */ /* MEM_IF_IMA_OPR_STS */ #define IACS_RDY_BIT BIT(1) #define IACS_RDY_BIT BIT(1) /* MEM_IF_IMA_EXP_STS */ #define IACS_ERR_BIT BIT(0) #define XCT_TYPE_ERR_BIT BIT(1) #define DATA_RD_ERR_BIT BIT(3) #define DATA_WR_ERR_BIT BIT(4) #define ADDR_BURST_WRAP_BIT BIT(5) #define ADDR_STABLE_ERR_BIT BIT(7) /* MEM_IF_IMA_ERR_STS */ /* MEM_IF_IMA_ERR_STS */ #define ADDR_STBL_ERR_BIT BIT(7) #define ADDR_STBL_ERR_BIT BIT(7) #define WR_ACS_ERR_BIT BIT(6) #define WR_ACS_ERR_BIT BIT(6) Loading @@ -297,4 +312,11 @@ /* MEM_IF_FG_BEAT_COUNT */ /* MEM_IF_FG_BEAT_COUNT */ #define BEAT_COUNT_MASK GENMASK(3, 0) #define BEAT_COUNT_MASK GENMASK(3, 0) /* MEM_IF_DMA_STS */ #define DMA_WRITE_ERROR_BIT BIT(1) #define DMA_READ_ERROR_BIT BIT(2) /* MEM_IF_DMA_CTL */ #define DMA_CLEAR_LOG_BIT BIT(0) #endif #endif drivers/power/qcom-charger/qpnp-fg-gen3.c +32 −1 Original line number Original line Diff line number Diff line Loading @@ -2267,6 +2267,37 @@ static int fg_memif_init(struct fg_chip *chip) /* INTERRUPT HANDLERS STAY HERE */ /* INTERRUPT HANDLERS STAY HERE */ static irqreturn_t fg_mem_xcp_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); if (status & MEM_XCP_BIT) { rc = fg_clear_dma_errors_if_any(chip); if (rc < 0) { pr_err("Error in clearing DMA error, rc=%d\n", rc); return IRQ_HANDLED; } mutex_lock(&chip->sram_rw_lock); rc = fg_clear_ima_errors_if_any(chip, true); if (rc < 0 && rc != -EAGAIN) pr_err("Error in checking IMA errors rc:%d\n", rc); mutex_unlock(&chip->sram_rw_lock); } return IRQ_HANDLED; } static irqreturn_t fg_vbatt_low_irq_handler(int irq, void *data) static irqreturn_t fg_vbatt_low_irq_handler(int irq, void *data) { { struct fg_chip *chip = data; struct fg_chip *chip = data; Loading Loading @@ -2483,7 +2514,7 @@ static struct fg_irq_info fg_irqs[FG_IRQ_MAX] = { }, }, [MEM_XCP_IRQ] = { [MEM_XCP_IRQ] = { .name = "mem-xcp", .name = "mem-xcp", .handler = fg_dummy_irq_handler, .handler = fg_mem_xcp_irq_handler, }, }, [IMA_RDY_IRQ] = { [IMA_RDY_IRQ] = { .name = "ima-rdy", .name = "ima-rdy", Loading Loading
drivers/power/qcom-charger/fg-core.h +2 −0 Original line number Original line Diff line number Diff line Loading @@ -342,6 +342,8 @@ extern int fg_read(struct fg_chip *chip, int addr, u8 *val, int len); extern int fg_write(struct fg_chip *chip, int addr, u8 *val, int len); extern int fg_write(struct fg_chip *chip, int addr, u8 *val, int len); extern int fg_masked_write(struct fg_chip *chip, int addr, u8 mask, u8 val); extern int fg_masked_write(struct fg_chip *chip, int addr, u8 mask, u8 val); extern int fg_ima_init(struct fg_chip *chip); extern int fg_ima_init(struct fg_chip *chip); extern int fg_clear_ima_errors_if_any(struct fg_chip *chip, bool check_hw_sts); extern int fg_clear_dma_errors_if_any(struct fg_chip *chip); extern int fg_debugfs_create(struct fg_chip *chip); extern int fg_debugfs_create(struct fg_chip *chip); extern void fill_string(char *str, size_t str_len, u8 *buf, int buf_len); extern void fill_string(char *str, size_t str_len, u8 *buf, int buf_len); extern int64_t twos_compliment_extend(int64_t val, int s_bit_pos); extern int64_t twos_compliment_extend(int64_t val, int s_bit_pos); Loading
drivers/power/qcom-charger/fg-memif.c +156 −37 Original line number Original line Diff line number Diff line Loading @@ -64,44 +64,90 @@ static int fg_config_access_mode(struct fg_chip *chip, bool access, bool burst) static int fg_run_iacs_clear_sequence(struct fg_chip *chip) static int fg_run_iacs_clear_sequence(struct fg_chip *chip) { { u8 tmp; u8 val, hw_sts, exp_sts; int rc; int rc, tries = 250; /* /* * Values to write for running IACS clear sequence comes from * Values to write for running IACS clear sequence comes from * hardware documentation. * hardware documentation. */ */ rc = fg_masked_write(chip, MEM_IF_IMA_CFG(chip), IACS_CLR_BIT, rc = fg_masked_write(chip, MEM_IF_IMA_CFG(chip), IACS_CLR_BIT); IACS_CLR_BIT | STATIC_CLK_EN_BIT, IACS_CLR_BIT | STATIC_CLK_EN_BIT); if (rc < 0) { if (rc < 0) { pr_err("failed to write 0x%04x, rc=%d\n", MEM_IF_IMA_CFG(chip), pr_err("failed to write 0x%04x, rc=%d\n", MEM_IF_IMA_CFG(chip), rc); rc); return rc; return rc; } } tmp = 0x4; rc = fg_config_access_mode(chip, FG_READ, false); rc = fg_write(chip, MEM_IF_ADDR_MSB(chip), &tmp, 1); if (rc < 0) { if (rc < 0) { pr_err("failed to write 0x%04x, rc=%d\n", MEM_IF_ADDR_LSB(chip), pr_err("failed to write to 0x%04x, rc=%d\n", rc); MEM_IF_IMA_CTL(chip), rc); return rc; return rc; } } tmp = 0x0; rc = fg_masked_write(chip, MEM_IF_MEM_INTF_CFG(chip), rc = fg_write(chip, MEM_IF_WR_DATA3(chip), &tmp, 1); MEM_ACCESS_REQ_BIT | IACS_SLCT_BIT, MEM_ACCESS_REQ_BIT | IACS_SLCT_BIT); if (rc < 0) { if (rc < 0) { pr_err("failed to write 0x%04x, rc=%d\n", MEM_IF_WR_DATA3(chip), pr_err("failed to set ima_req_access bit rc=%d\n", rc); rc); return rc; } /* Delay for the clock to reach FG */ usleep_range(35, 40); while (1) { val = 0; rc = fg_write(chip, MEM_IF_ADDR_MSB(chip), &val, 1); if (rc < 0) { pr_err("failed to write 0x%04x, rc=%d\n", MEM_IF_ADDR_MSB(chip), rc); return rc; return rc; } } rc = fg_read(chip, MEM_IF_RD_DATA3(chip), &tmp, 1); val = 0; rc = fg_write(chip, MEM_IF_WR_DATA3(chip), &val, 1); if (rc < 0) { if (rc < 0) { pr_err("failed to read 0x%04x, rc=%d\n", MEM_IF_RD_DATA3(chip), pr_err("failed to write 0x%04x, rc=%d\n", rc); MEM_IF_WR_DATA3(chip), rc); return rc; return rc; } } rc = fg_read(chip, MEM_IF_RD_DATA3(chip), &val, 1); if (rc < 0) { pr_err("failed to read 0x%04x, rc=%d\n", MEM_IF_RD_DATA3(chip), rc); return rc; } /* Delay for IMA hardware to clear */ usleep_range(35, 40); rc = fg_read(chip, MEM_IF_IMA_HW_STS(chip), &hw_sts, 1); if (rc < 0) { pr_err("failed to read ima_hw_sts rc=%d\n", rc); return rc; } if (hw_sts != 0) continue; rc = fg_read(chip, MEM_IF_IMA_EXP_STS(chip), &exp_sts, 1); if (rc < 0) { pr_err("failed to read ima_exp_sts rc=%d\n", rc); return rc; } if (exp_sts == 0 || !(--tries)) break; } if (!tries) pr_err("Failed to clear the error? hw_sts: %x exp_sts: %d\n", hw_sts, exp_sts); rc = fg_masked_write(chip, MEM_IF_IMA_CFG(chip), IACS_CLR_BIT, 0); rc = fg_masked_write(chip, MEM_IF_IMA_CFG(chip), IACS_CLR_BIT, 0); if (rc < 0) { if (rc < 0) { pr_err("failed to write 0x%04x, rc=%d\n", MEM_IF_IMA_CFG(chip), pr_err("failed to write 0x%04x, rc=%d\n", MEM_IF_IMA_CFG(chip), Loading @@ -109,22 +155,54 @@ static int fg_run_iacs_clear_sequence(struct fg_chip *chip) return rc; return rc; } } udelay(5); rc = fg_masked_write(chip, MEM_IF_MEM_INTF_CFG(chip), MEM_ACCESS_REQ_BIT | IACS_SLCT_BIT, 0); if (rc < 0) { pr_err("failed to write to 0x%04x, rc=%d\n", MEM_IF_MEM_INTF_CFG(chip), rc); return rc; } /* Delay before next transaction is attempted */ usleep_range(35, 40); fg_dbg(chip, FG_SRAM_READ | FG_SRAM_WRITE, "IACS clear sequence complete\n"); fg_dbg(chip, FG_SRAM_READ | FG_SRAM_WRITE, "IACS clear sequence complete\n"); return rc; return rc; } } static int fg_check_for_ima_errors(struct fg_chip *chip) int fg_clear_dma_errors_if_any(struct fg_chip *chip) { { int rc = 0; int rc; u8 err_sts, exp_sts = 0, hw_sts = 0; u8 dma_sts; rc = fg_read(chip, MEM_IF_IMA_ERR_STS(chip), &err_sts, 1); rc = fg_read(chip, MEM_IF_DMA_STS(chip), &dma_sts, 1); if (rc < 0) { if (rc < 0) { pr_err("failed to read ima_err_sts rc=%d\n", rc); pr_err("failed to read addr=0x%04x, rc=%d\n", MEM_IF_DMA_STS(chip), rc); return rc; } fg_dbg(chip, FG_STATUS, "dma_sts: %x\n", dma_sts); if (dma_sts & (DMA_WRITE_ERROR_BIT | DMA_READ_ERROR_BIT)) { rc = fg_masked_write(chip, MEM_IF_DMA_CTL(chip), DMA_CLEAR_LOG_BIT, DMA_CLEAR_LOG_BIT); if (rc < 0) { pr_err("failed to write addr=0x%04x, rc=%d\n", MEM_IF_DMA_CTL(chip), rc); return rc; return rc; } } } return 0; } int fg_clear_ima_errors_if_any(struct fg_chip *chip, bool check_hw_sts) { int rc = 0; u8 err_sts, exp_sts = 0, hw_sts = 0; bool run_err_clr_seq = false; if (err_sts & (ADDR_STBL_ERR_BIT | WR_ACS_ERR_BIT | RD_ACS_ERR_BIT)) { rc = fg_read(chip, MEM_IF_IMA_EXP_STS(chip), &exp_sts, 1); rc = fg_read(chip, MEM_IF_IMA_EXP_STS(chip), &exp_sts, 1); if (rc < 0) { if (rc < 0) { pr_err("failed to read ima_exp_sts rc=%d\n", rc); pr_err("failed to read ima_exp_sts rc=%d\n", rc); Loading @@ -137,9 +215,36 @@ static int fg_check_for_ima_errors(struct fg_chip *chip) return rc; return rc; } } pr_err("ima_err_sts=%x ima_exp_sts=%x ima_hw_sts=%x\n", rc = fg_read(chip, MEM_IF_IMA_ERR_STS(chip), &err_sts, 1); if (rc < 0) { pr_err("failed to read ima_err_sts rc=%d\n", rc); return rc; } fg_dbg(chip, FG_STATUS, "ima_err_sts=%x ima_exp_sts=%x ima_hw_sts=%x\n", err_sts, exp_sts, hw_sts); err_sts, exp_sts, hw_sts); if (check_hw_sts) { /* * Lower nibble should be equal to upper nibble before SRAM * transactions begins from SW side. If they are unequal, then * the error clear sequence should be run irrespective of IMA * exception errors. */ if ((hw_sts & 0x0F) != hw_sts >> 4) { pr_err("IMA HW not in correct state, hw_sts=%x\n", hw_sts); run_err_clr_seq = true; } } if (exp_sts & (IACS_ERR_BIT | XCT_TYPE_ERR_BIT | DATA_RD_ERR_BIT | DATA_WR_ERR_BIT | ADDR_BURST_WRAP_BIT | ADDR_STABLE_ERR_BIT)) { pr_err("IMA exception bit set, exp_sts=%x\n", exp_sts); run_err_clr_seq = true; } if (run_err_clr_seq) { /* clear the error */ /* clear the error */ rc = fg_run_iacs_clear_sequence(chip); rc = fg_run_iacs_clear_sequence(chip); if (rc < 0) { if (rc < 0) { Loading @@ -156,7 +261,7 @@ static int fg_check_for_ima_errors(struct fg_chip *chip) static int fg_check_iacs_ready(struct fg_chip *chip) static int fg_check_iacs_ready(struct fg_chip *chip) { { int rc = 0, timeout = 250; int rc = 0, tries = 250; u8 ima_opr_sts = 0; u8 ima_opr_sts = 0; /* /* Loading @@ -176,17 +281,17 @@ static int fg_check_iacs_ready(struct fg_chip *chip) if (ima_opr_sts & IACS_RDY_BIT) if (ima_opr_sts & IACS_RDY_BIT) break; break; if (!(--timeout)) if (!(--tries)) break; break; /* delay for iacs_ready to be asserted */ /* delay for iacs_ready to be asserted */ usleep_range(5000, 7000); usleep_range(5000, 7000); } } if (!timeout) { if (!tries) { pr_err("IACS_RDY not set\n"); pr_err("IACS_RDY not set\n"); /* check for error condition */ rc = fg_check_for_ima_errors(chip); rc = fg_clear_ima_errors_if_any(chip, false); if (rc < 0) { if (rc < 0) { pr_err("Failed to check for ima errors rc=%d\n", rc); pr_err("Failed to check for ima errors rc=%d\n", rc); return rc; return rc; Loading Loading @@ -250,7 +355,7 @@ static int __fg_interleaved_mem_write(struct fg_chip *chip, u16 address, } } /* check for error condition */ /* check for error condition */ rc = fg_check_for_ima_errors(chip); rc = fg_clear_ima_errors_if_any(chip, false); if (rc < 0) { if (rc < 0) { pr_err("Failed to check for ima errors rc=%d\n", rc); pr_err("Failed to check for ima errors rc=%d\n", rc); return rc; return rc; Loading Loading @@ -296,7 +401,7 @@ static int __fg_interleaved_mem_read(struct fg_chip *chip, u16 address, offset = 0; offset = 0; /* check for error condition */ /* check for error condition */ rc = fg_check_for_ima_errors(chip); rc = fg_clear_ima_errors_if_any(chip, false); if (rc < 0) { if (rc < 0) { pr_err("Failed to check for ima errors rc=%d\n", rc); pr_err("Failed to check for ima errors rc=%d\n", rc); return rc; return rc; Loading Loading @@ -581,5 +686,19 @@ int fg_ima_init(struct fg_chip *chip) return rc; return rc; } } /* Clear DMA errors if any before clearing IMA errors */ rc = fg_clear_dma_errors_if_any(chip); if (rc < 0) { pr_err("Error in checking DMA errors rc:%d\n", rc); return rc; } /* Clear IMA errors if any before SRAM transactions can begin */ rc = fg_clear_ima_errors_if_any(chip, true); if (rc < 0 && rc != -EAGAIN) { pr_err("Error in checking IMA errors rc:%d\n", rc); return rc; } return 0; return 0; } }
drivers/power/qcom-charger/fg-reg.h +22 −0 Original line number Original line Diff line number Diff line Loading @@ -258,6 +258,7 @@ #define ESR_REQ_CTL_EN_BIT BIT(0) #define ESR_REQ_CTL_EN_BIT BIT(0) /* FG_MEM_IF register and bit definitions */ /* FG_MEM_IF register and bit definitions */ #define MEM_IF_INT_RT_STS(chip) ((chip->mem_if_base) + 0x10) #define MEM_IF_MEM_INTF_CFG(chip) ((chip->mem_if_base) + 0x50) #define MEM_IF_MEM_INTF_CFG(chip) ((chip->mem_if_base) + 0x50) #define MEM_IF_IMA_CTL(chip) ((chip->mem_if_base) + 0x51) #define MEM_IF_IMA_CTL(chip) ((chip->mem_if_base) + 0x51) #define MEM_IF_IMA_CFG(chip) ((chip->mem_if_base) + 0x52) #define MEM_IF_IMA_CFG(chip) ((chip->mem_if_base) + 0x52) Loading @@ -273,6 +274,11 @@ #define MEM_IF_WR_DATA3(chip) ((chip->mem_if_base) + 0x66) #define MEM_IF_WR_DATA3(chip) ((chip->mem_if_base) + 0x66) #define MEM_IF_RD_DATA0(chip) ((chip->mem_if_base) + 0x67) #define MEM_IF_RD_DATA0(chip) ((chip->mem_if_base) + 0x67) #define MEM_IF_RD_DATA3(chip) ((chip->mem_if_base) + 0x6A) #define MEM_IF_RD_DATA3(chip) ((chip->mem_if_base) + 0x6A) #define MEM_IF_DMA_STS(chip) ((chip->mem_if_base) + 0x70) #define MEM_IF_DMA_CTL(chip) ((chip->mem_if_base) + 0x71) /* MEM_IF_INT_RT_STS */ #define MEM_XCP_BIT BIT(1) /* MEM_IF_MEM_INTF_CFG */ /* MEM_IF_MEM_INTF_CFG */ #define MEM_ACCESS_REQ_BIT BIT(7) #define MEM_ACCESS_REQ_BIT BIT(7) Loading @@ -286,10 +292,19 @@ /* MEM_IF_IMA_CFG */ /* MEM_IF_IMA_CFG */ #define IACS_CLR_BIT BIT(2) #define IACS_CLR_BIT BIT(2) #define IACS_INTR_SRC_SLCT_BIT BIT(3) #define IACS_INTR_SRC_SLCT_BIT BIT(3) #define STATIC_CLK_EN_BIT BIT(4) /* MEM_IF_IMA_OPR_STS */ /* MEM_IF_IMA_OPR_STS */ #define IACS_RDY_BIT BIT(1) #define IACS_RDY_BIT BIT(1) /* MEM_IF_IMA_EXP_STS */ #define IACS_ERR_BIT BIT(0) #define XCT_TYPE_ERR_BIT BIT(1) #define DATA_RD_ERR_BIT BIT(3) #define DATA_WR_ERR_BIT BIT(4) #define ADDR_BURST_WRAP_BIT BIT(5) #define ADDR_STABLE_ERR_BIT BIT(7) /* MEM_IF_IMA_ERR_STS */ /* MEM_IF_IMA_ERR_STS */ #define ADDR_STBL_ERR_BIT BIT(7) #define ADDR_STBL_ERR_BIT BIT(7) #define WR_ACS_ERR_BIT BIT(6) #define WR_ACS_ERR_BIT BIT(6) Loading @@ -297,4 +312,11 @@ /* MEM_IF_FG_BEAT_COUNT */ /* MEM_IF_FG_BEAT_COUNT */ #define BEAT_COUNT_MASK GENMASK(3, 0) #define BEAT_COUNT_MASK GENMASK(3, 0) /* MEM_IF_DMA_STS */ #define DMA_WRITE_ERROR_BIT BIT(1) #define DMA_READ_ERROR_BIT BIT(2) /* MEM_IF_DMA_CTL */ #define DMA_CLEAR_LOG_BIT BIT(0) #endif #endif
drivers/power/qcom-charger/qpnp-fg-gen3.c +32 −1 Original line number Original line Diff line number Diff line Loading @@ -2267,6 +2267,37 @@ static int fg_memif_init(struct fg_chip *chip) /* INTERRUPT HANDLERS STAY HERE */ /* INTERRUPT HANDLERS STAY HERE */ static irqreturn_t fg_mem_xcp_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); if (status & MEM_XCP_BIT) { rc = fg_clear_dma_errors_if_any(chip); if (rc < 0) { pr_err("Error in clearing DMA error, rc=%d\n", rc); return IRQ_HANDLED; } mutex_lock(&chip->sram_rw_lock); rc = fg_clear_ima_errors_if_any(chip, true); if (rc < 0 && rc != -EAGAIN) pr_err("Error in checking IMA errors rc:%d\n", rc); mutex_unlock(&chip->sram_rw_lock); } return IRQ_HANDLED; } static irqreturn_t fg_vbatt_low_irq_handler(int irq, void *data) static irqreturn_t fg_vbatt_low_irq_handler(int irq, void *data) { { struct fg_chip *chip = data; struct fg_chip *chip = data; Loading Loading @@ -2483,7 +2514,7 @@ static struct fg_irq_info fg_irqs[FG_IRQ_MAX] = { }, }, [MEM_XCP_IRQ] = { [MEM_XCP_IRQ] = { .name = "mem-xcp", .name = "mem-xcp", .handler = fg_dummy_irq_handler, .handler = fg_mem_xcp_irq_handler, }, }, [IMA_RDY_IRQ] = { [IMA_RDY_IRQ] = { .name = "ima-rdy", .name = "ima-rdy", Loading