summaryrefslogtreecommitdiff
path: root/drivers/power
diff options
context:
space:
mode:
authorAshay Jaiswal <ashayj@codeaurora.org>2017-10-11 00:39:29 +0530
committerJishnu Prakash <jprakash@codeaurora.org>2020-12-11 14:40:22 +0530
commitd81e600c586eefde2fe173ac4e6638dabf6c5500 (patch)
treece7c40c370e909f1dc0adbfefe09259178cef005 /drivers/power
parent46efbcbb8ab82cce0300beafe13d270ec1427915 (diff)
power: qpnp-fg-gen3: Add a property to reset FG BCL device
Add support to allow client to request FG to reset BCL device through a power supply property. Change-Id: I7c51adb1e9739c592c28943da8af8219661d38cc Signed-off-by: Ashay Jaiswal <ashayj@codeaurora.org>
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/supply/qcom/fg-core.h3
-rw-r--r--drivers/power/supply/qcom/fg-memif.c60
-rw-r--r--drivers/power/supply/qcom/fg-reg.h17
-rw-r--r--drivers/power/supply/qcom/fg-util.c6
-rw-r--r--drivers/power/supply/qcom/qpnp-fg-gen3.c105
5 files changed, 184 insertions, 7 deletions
diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h
index 076cd49e6dd5..f596f85a5b50 100644
--- a/drivers/power/supply/qcom/fg-core.h
+++ b/drivers/power/supply/qcom/fg-core.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, 2020, 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
@@ -522,4 +522,5 @@ extern void fg_circ_buf_clr(struct fg_circ_buf *);
extern int fg_circ_buf_avg(struct fg_circ_buf *, int *);
extern int fg_circ_buf_median(struct fg_circ_buf *, int *);
extern int fg_lerp(const struct fg_pt *, size_t, s32, s32 *);
+extern int fg_dma_mem_req(struct fg_chip *, bool);
#endif
diff --git a/drivers/power/supply/qcom/fg-memif.c b/drivers/power/supply/qcom/fg-memif.c
index 8a949bfe61d0..82fbfcaf667a 100644
--- a/drivers/power/supply/qcom/fg-memif.c
+++ b/drivers/power/supply/qcom/fg-memif.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, 2020, 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
@@ -746,6 +746,64 @@ out:
return rc;
}
+int fg_dma_mem_req(struct fg_chip *chip, bool request)
+{
+ int ret, rc = 0, retry_count = RETRY_COUNT;
+ u8 val;
+
+ if (request) {
+ /* configure for DMA access */
+ rc = fg_masked_write(chip, MEM_IF_MEM_INTF_CFG(chip),
+ MEM_ACCESS_REQ_BIT | IACS_SLCT_BIT,
+ MEM_ACCESS_REQ_BIT);
+ if (rc < 0) {
+ pr_err("failed to set mem_access bit rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = fg_masked_write(chip, MEM_IF_MEM_ARB_CFG(chip),
+ MEM_IF_ARB_REQ_BIT, MEM_IF_ARB_REQ_BIT);
+ if (rc < 0) {
+ pr_err("failed to set mem_arb bit rc=%d\n", rc);
+ goto release_mem;
+ }
+
+ while (retry_count--) {
+ rc = fg_read(chip, MEM_IF_INT_RT_STS(chip), &val, 1);
+ if (rc < 0) {
+ pr_err("failed to set ima_rt_sts rc=%d\n", rc);
+ goto release_mem;
+ }
+ if (val & MEM_GNT_BIT)
+ break;
+ msleep(20);
+ }
+ if (!retry_count && !(val & MEM_GNT_BIT)) {
+ pr_err("failed to get memory access\n");
+ rc = -ETIMEDOUT;
+ goto release_mem;
+ }
+
+ return 0;
+ }
+
+release_mem:
+ /* Release access */
+ 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 reset mem_access bit rc = %d\n", rc);
+
+ ret = fg_masked_write(chip, MEM_IF_MEM_ARB_CFG(chip),
+ MEM_IF_ARB_REQ_BIT, 0);
+ if (ret < 0) {
+ pr_err("failed to release mem_arb bit rc=%d\n", ret);
+ return ret;
+ }
+
+ return rc;
+}
+
int fg_ima_init(struct fg_chip *chip)
{
int rc;
diff --git a/drivers/power/supply/qcom/fg-reg.h b/drivers/power/supply/qcom/fg-reg.h
index cd0b2fb4391f..906792e1ed79 100644
--- a/drivers/power/supply/qcom/fg-reg.h
+++ b/drivers/power/supply/qcom/fg-reg.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, 2020, 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
@@ -29,6 +29,7 @@
#define BATT_SOC_STS_CLR(chip) (chip->batt_soc_base + 0x4A)
#define BATT_SOC_LOW_PWR_CFG(chip) (chip->batt_soc_base + 0x52)
#define BATT_SOC_LOW_PWR_STS(chip) (chip->batt_soc_base + 0x56)
+#define BATT_SOC_RST_CTRL0(chip) (chip->batt_soc_base + 0xBA)
/* BATT_SOC_INT_RT_STS */
#define MSOC_EMPTY_BIT BIT(5)
@@ -39,6 +40,9 @@
/* BATT_SOC_RESTART */
#define RESTART_GO_BIT BIT(0)
+/* BCL_RESET */
+#define BCL_RESET_BIT BIT(2)
+
/* FG_BATT_INFO register definitions */
#define BATT_INFO_BATT_TEMP_STS(chip) (chip->batt_info_base + 0x06)
#define BATT_INFO_SYS_BATT(chip) (chip->batt_info_base + 0x07)
@@ -58,7 +62,6 @@
#define BATT_INFO_JEITA_COLD(chip) (chip->batt_info_base + 0x63)
#define BATT_INFO_JEITA_HOT(chip) (chip->batt_info_base + 0x64)
#define BATT_INFO_JEITA_TOO_HOT(chip) (chip->batt_info_base + 0x65)
-
/* only for v1.1 */
#define BATT_INFO_ESR_CFG(chip) (chip->batt_info_base + 0x69)
/* starting from v2.0 */
@@ -95,6 +98,8 @@
#define BATT_INFO_IADC_MSB(chip) (chip->batt_info_base + 0xAF)
#define BATT_INFO_TM_MISC(chip) (chip->batt_info_base + 0xE5)
#define BATT_INFO_TM_MISC1(chip) (chip->batt_info_base + 0xE6)
+#define BATT_INFO_PEEK_MUX1(chip) (chip->batt_info_base + 0xEB)
+#define BATT_INFO_RDBACK(chip) (chip->batt_info_base + 0xEF)
/* BATT_INFO_BATT_TEMP_STS */
#define JEITA_TOO_HOT_STS_BIT BIT(7)
@@ -264,8 +269,12 @@
#define ESR_REQ_CTL_BIT BIT(1)
#define ESR_REQ_CTL_EN_BIT BIT(0)
+/* BATT_INFO_PEEK_MUX1 */
+#define PEEK_MUX1_BIT BIT(0)
+
/* FG_MEM_IF register and bit definitions */
#define MEM_IF_INT_RT_STS(chip) ((chip->mem_if_base) + 0x10)
+#define MEM_IF_MEM_ARB_CFG(chip) ((chip->mem_if_base) + 0x40)
#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_CFG(chip) ((chip->mem_if_base) + 0x52)
@@ -286,6 +295,7 @@
/* MEM_IF_INT_RT_STS */
#define MEM_XCP_BIT BIT(1)
+#define MEM_GNT_BIT BIT(2)
/* MEM_IF_MEM_INTF_CFG */
#define MEM_ACCESS_REQ_BIT BIT(7)
@@ -326,4 +336,7 @@
/* MEM_IF_DMA_CTL */
#define DMA_CLEAR_LOG_BIT BIT(0)
+
+/* MEM_IF_REQ */
+#define MEM_IF_ARB_REQ_BIT BIT(0)
#endif
diff --git a/drivers/power/supply/qcom/fg-util.c b/drivers/power/supply/qcom/fg-util.c
index 23dd9131d402..f074ffe6c274 100644
--- a/drivers/power/supply/qcom/fg-util.c
+++ b/drivers/power/supply/qcom/fg-util.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, 2020, 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
@@ -420,7 +420,7 @@ int fg_write(struct fg_chip *chip, int addr, u8 *val, int len)
return -ENXIO;
mutex_lock(&chip->bus_lock);
- sec_access = (addr & 0x00FF) > 0xD0;
+ sec_access = (addr & 0x00FF) >= 0xBA;
if (sec_access) {
rc = regmap_write(chip->regmap, (addr & 0xFF00) | 0xD0, 0xA5);
if (rc < 0) {
@@ -460,7 +460,7 @@ int fg_masked_write(struct fg_chip *chip, int addr, u8 mask, u8 val)
return -ENXIO;
mutex_lock(&chip->bus_lock);
- sec_access = (addr & 0x00FF) > 0xD0;
+ sec_access = (addr & 0x00FF) >= 0xBA;
if (sec_access) {
rc = regmap_write(chip->regmap, (addr & 0xFF00) | 0xD0, 0xA5);
if (rc < 0) {
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c
index 32fb0538cc8c..43b48d4878fd 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen3.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c
@@ -3850,6 +3850,9 @@ static int fg_psy_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_CC_STEP_SEL:
pval->intval = chip->ttf.cc_step.sel;
break;
+ case POWER_SUPPLY_PROP_FG_RESET_CLOCK:
+ pval->intval = 0;
+ break;
default:
pr_err("unsupported property %d\n", psp);
rc = -EINVAL;
@@ -3862,6 +3865,100 @@ static int fg_psy_get_property(struct power_supply *psy,
return 0;
}
+#define BCL_RESET_RETRY_COUNT 4
+static int fg_bcl_reset(struct fg_chip *chip)
+{
+ int i, ret, rc = 0;
+ u8 val, peek_mux;
+ bool success = false;
+
+ /* Read initial value of peek mux1 */
+ rc = fg_read(chip, BATT_INFO_PEEK_MUX1(chip), &peek_mux, 1);
+ if (rc < 0) {
+ pr_err("Error in writing peek mux1, rc=%d\n", rc);
+ return rc;
+ }
+
+ val = 0x83;
+ rc = fg_write(chip, BATT_INFO_PEEK_MUX1(chip), &val, 1);
+ if (rc < 0) {
+ pr_err("Error in writing peek mux1, rc=%d\n", rc);
+ return rc;
+ }
+
+ mutex_lock(&chip->sram_rw_lock);
+ for (i = 0; i < BCL_RESET_RETRY_COUNT; i++) {
+ rc = fg_dma_mem_req(chip, true);
+ if (rc < 0) {
+ pr_err("Error in locking memory, rc=%d\n", rc);
+ goto unlock;
+ }
+
+ rc = fg_read(chip, BATT_INFO_RDBACK(chip), &val, 1);
+ if (rc < 0) {
+ pr_err("Error in reading rdback, rc=%d\n", rc);
+ goto release_mem;
+ }
+
+ if (val & PEEK_MUX1_BIT) {
+ rc = fg_masked_write(chip, BATT_SOC_RST_CTRL0(chip),
+ BCL_RESET_BIT, BCL_RESET_BIT);
+ if (rc < 0) {
+ pr_err("Error in writing RST_CTRL0, rc=%d\n",
+ rc);
+ goto release_mem;
+ }
+
+ rc = fg_dma_mem_req(chip, false);
+ if (rc < 0)
+ pr_err("Error in unlocking memory, rc=%d\n",
+ rc);
+
+ /* Delay of 2ms */
+ usleep_range(2000, 3000);
+ ret = fg_masked_write(chip, BATT_SOC_RST_CTRL0(chip),
+ BCL_RESET_BIT, 0);
+ if (ret < 0)
+ pr_err("Error in writing RST_CTRL0, rc=%d\n",
+ rc);
+ if (!rc && !ret)
+ success = true;
+
+ goto unlock;
+ } else {
+ rc = fg_dma_mem_req(chip, false);
+ if (rc < 0) {
+ pr_err("Error in unlocking memory, rc=%d\n",
+ rc);
+ goto unlock;
+ }
+ success = false;
+ pr_err_ratelimited("PEEK_MUX1 not set retrying...\n");
+ msleep(1000);
+ }
+ }
+
+release_mem:
+ rc = fg_dma_mem_req(chip, false);
+ if (rc < 0)
+ pr_err("Error in unlocking memory, rc=%d\n", rc);
+
+unlock:
+ ret = fg_write(chip, BATT_INFO_PEEK_MUX1(chip), &peek_mux, 1);
+ if (ret < 0) {
+ pr_err("Error in writing peek mux1, rc=%d\n", rc);
+ mutex_unlock(&chip->sram_rw_lock);
+ return ret;
+ }
+
+ mutex_unlock(&chip->sram_rw_lock);
+
+ if (!success)
+ return -EAGAIN;
+ else
+ return rc;
+}
+
static int fg_psy_set_property(struct power_supply *psy,
enum power_supply_property psp,
const union power_supply_propval *pval)
@@ -3950,6 +4047,13 @@ static int fg_psy_set_property(struct power_supply *psy,
return rc;
}
break;
+ case POWER_SUPPLY_PROP_FG_RESET_CLOCK:
+ rc = fg_bcl_reset(chip);
+ if (rc < 0) {
+ pr_err("Error in resetting BCL clock, rc=%d\n", rc);
+ return rc;
+ }
+ break;
default:
break;
}
@@ -4047,6 +4151,7 @@ static enum power_supply_property fg_psy_props[] = {
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
POWER_SUPPLY_PROP_CC_STEP,
POWER_SUPPLY_PROP_CC_STEP_SEL,
+ POWER_SUPPLY_PROP_FG_RESET_CLOCK,
};
static const struct power_supply_desc fg_psy_desc = {