Loading drivers/regulator/qpnp-lcdb-regulator.c +227 −64 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 @@ -50,6 +50,8 @@ #define ATTW_MAX_MS 32 #define LCDB_BST_OUTPUT_VOLTAGE_REG 0x41 #define PM660_BST_OUTPUT_VOLTAGE_MASK GENMASK(4, 0) #define BST_OUTPUT_VOLTAGE_MASK GENMASK(5, 0) #define LCDB_MODULE_RDY_REG 0x45 #define MODULE_RDY_BIT BIT(7) Loading @@ -71,7 +73,8 @@ #define LCDB_PS_CTL_REG 0x50 #define EN_PS_BIT BIT(7) #define PS_THRESHOLD_MASK GENMASK(1, 0) #define PM660_PS_THRESH_MASK GENMASK(1, 0) #define PS_THRESH_MASK GENMASK(2, 0) #define MIN_BST_PS_MA 50 #define MAX_BST_PS_MA 80 Loading @@ -83,6 +86,20 @@ #define LCDB_BST_VREG_OK_CTL_REG 0x55 #define BST_VREG_OK_DEB_MASK GENMASK(1, 0) #define LCDB_BST_SS_CTL_REG 0x5B #define BST_SS_TIME_MASK GENMASK(1, 0) #define BST_PRECHG_SHORT_ALARM_SHIFT 2 #define BST_PRECHARGE_DONE_DEB_BIT BIT(4) #define BST_SS_TIME_OVERRIDE_SHIFT 5 #define BST_SS_TIME_OVERRIDE_0MS 0 #define BST_SS_TIME_OVERRIDE_0P5_MS 1 #define BST_SS_TIME_OVERRIDE_1MS 2 #define BST_SS_TIME_OVERRIDE_2MS 3 #define EN_BST_PRECHG_SHORT_ALARM 0 #define DIS_BST_PRECHG_SHORT_ALARM 1 #define LCDB_SOFT_START_CTL_REG 0x5F #define LCDB_MISC_CTL_REG 0x60 Loading Loading @@ -147,7 +164,8 @@ #define MIN_SOFT_START_US 0 #define MAX_SOFT_START_US 2000 #define BST_HEADROOM_DEFAULT_MV 200 #define PM660_BST_HEADROOM_DEFAULT_MV 200 #define BST_HEADROOM_DEFAULT_MV 150 struct ldo_regulator { struct regulator_desc rdesc; Loading Loading @@ -222,6 +240,7 @@ struct settings { u16 address; u8 value; bool sec_access; bool valid; }; enum lcdb_module { Loading Loading @@ -262,6 +281,8 @@ enum lcdb_settings_index { LCDB_LDO_SOFT_START_CTL, LCDB_NCP_PD_CTL, LCDB_NCP_SOFT_START_CTL, LCDB_BST_SS_CTL, LCDB_LDO_VREG_OK_CTL, LCDB_SETTING_MAX, }; Loading @@ -286,10 +307,11 @@ static u32 ncp_ilim_ma[] = { 810, }; #define SETTING(_id, _sec_access) \ #define SETTING(_id, _sec_access, _valid) \ [_id] = { \ .address = _id##_REG, \ .sec_access = _sec_access, \ .valid = _valid \ } \ static bool is_between(int value, int min, int max) Loading Loading @@ -334,13 +356,17 @@ static int qpnp_lcdb_secure_write(struct qpnp_lcdb *lcdb, { int rc; u8 val = SECURE_UNLOCK_VALUE; u8 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype; mutex_lock(&lcdb->read_write_mutex); rc = regmap_write(lcdb->regmap, lcdb->base + SEC_ADDRESS_REG, val); if (pmic_subtype == PM660L_SUBTYPE) { rc = regmap_write(lcdb->regmap, lcdb->base + SEC_ADDRESS_REG, val); if (rc < 0) { pr_err("Failed to unlock register rc=%d\n", rc); goto fail_write; } } rc = regmap_write(lcdb->regmap, addr, value); if (rc < 0) pr_err("Failed to write to addr=0x%02x rc=%d\n", addr, rc); Loading Loading @@ -397,58 +423,100 @@ static int dump_status_registers(struct qpnp_lcdb *lcdb) return rc; } static struct settings lcdb_settings_pm660l[] = { SETTING(LCDB_BST_PD_CTL, false, true), SETTING(LCDB_RDSON_MGMNT, false, true), SETTING(LCDB_MISC_CTL, false, true), SETTING(LCDB_SOFT_START_CTL, false, true), SETTING(LCDB_PFM_CTL, false, true), SETTING(LCDB_PWRUP_PWRDN_CTL, true, true), SETTING(LCDB_LDO_PD_CTL, false, true), SETTING(LCDB_LDO_SOFT_START_CTL, false, true), SETTING(LCDB_NCP_PD_CTL, false, true), SETTING(LCDB_NCP_SOFT_START_CTL, false, true), SETTING(LCDB_BST_SS_CTL, false, false), SETTING(LCDB_LDO_VREG_OK_CTL, false, false), }; /* For PMICs like pmi632/pm855L */ static struct settings lcdb_settings[] = { SETTING(LCDB_BST_PD_CTL, false), SETTING(LCDB_RDSON_MGMNT, false), SETTING(LCDB_MISC_CTL, false), SETTING(LCDB_SOFT_START_CTL, false), SETTING(LCDB_PFM_CTL, false), SETTING(LCDB_PWRUP_PWRDN_CTL, true), SETTING(LCDB_LDO_PD_CTL, false), SETTING(LCDB_LDO_SOFT_START_CTL, false), SETTING(LCDB_NCP_PD_CTL, false), SETTING(LCDB_NCP_SOFT_START_CTL, false), SETTING(LCDB_BST_PD_CTL, false, true), SETTING(LCDB_RDSON_MGMNT, false, false), SETTING(LCDB_MISC_CTL, false, false), SETTING(LCDB_SOFT_START_CTL, false, false), SETTING(LCDB_PFM_CTL, false, false), SETTING(LCDB_PWRUP_PWRDN_CTL, false, true), SETTING(LCDB_LDO_PD_CTL, false, true), SETTING(LCDB_LDO_SOFT_START_CTL, false, true), SETTING(LCDB_NCP_PD_CTL, false, true), SETTING(LCDB_NCP_SOFT_START_CTL, false, true), SETTING(LCDB_BST_SS_CTL, false, true), SETTING(LCDB_LDO_VREG_OK_CTL, false, true), }; static int qpnp_lcdb_save_settings(struct qpnp_lcdb *lcdb) { int i, rc = 0; int i, size, rc = 0; struct settings *setting; u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype; for (i = 0; i < ARRAY_SIZE(lcdb_settings); i++) { if (pmic_subtype == PM660L_SUBTYPE) { setting = lcdb_settings_pm660l; size = ARRAY_SIZE(lcdb_settings_pm660l); } else { setting = lcdb_settings; size = ARRAY_SIZE(lcdb_settings); } for (i = 0; i < size; i++) { if (setting[i].valid) { rc = qpnp_lcdb_read(lcdb, lcdb->base + lcdb_settings[i].address, &lcdb_settings[i].value, 1); setting[i].address, &setting[i].value, 1); if (rc < 0) { pr_err("Failed to read lcdb register address=%x\n", lcdb_settings[i].address); setting[i].address); return rc; } } } return rc; return 0; } static int qpnp_lcdb_restore_settings(struct qpnp_lcdb *lcdb) { int i, rc = 0; int i, size, rc = 0; struct settings *setting; u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype; for (i = 0; i < ARRAY_SIZE(lcdb_settings); i++) { if (lcdb_settings[i].sec_access) if (pmic_subtype == PM660L_SUBTYPE) { setting = lcdb_settings_pm660l; size = ARRAY_SIZE(lcdb_settings_pm660l); } else { setting = lcdb_settings; size = ARRAY_SIZE(lcdb_settings); } for (i = 0; i < size; i++) { if (setting[i].valid) { if (setting[i].sec_access) rc = qpnp_lcdb_secure_write(lcdb, lcdb->base + lcdb_settings[i].address, lcdb_settings[i].value); setting[i].address, setting[i].value); else rc = qpnp_lcdb_write(lcdb, lcdb->base + lcdb_settings[i].address, &lcdb_settings[i].value, 1); setting[i].address, &setting[i].value, 1); if (rc < 0) { pr_err("Failed to write register address=%x\n", lcdb_settings[i].address); setting[i].address); return rc; } } } return rc; return 0; } static int qpnp_lcdb_ttw_enter(struct qpnp_lcdb *lcdb) Loading @@ -465,6 +533,77 @@ static int qpnp_lcdb_ttw_enter(struct qpnp_lcdb *lcdb) lcdb->settings_saved = true; } val = HWEN_RDY_BIT; rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG, &val, 1); if (rc < 0) { pr_err("Failed to hw_enable lcdb rc= %d\n", rc); return rc; } val = (BST_SS_TIME_OVERRIDE_1MS << BST_SS_TIME_OVERRIDE_SHIFT) | (DIS_BST_PRECHG_SHORT_ALARM << BST_PRECHG_SHORT_ALARM_SHIFT); rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_BST_SS_CTL_REG, &val, 1); if (rc < 0) return rc; val = 0; rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_LDO_SOFT_START_CTL_REG, &val, 1); if (rc < 0) return rc; val = 0; rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_NCP_SOFT_START_CTL_REG, &val, 1); if (rc < 0) return rc; val = BOOST_DIS_PULLDOWN_BIT | BOOST_PD_STRENGTH_BIT; rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_BST_PD_CTL_REG, &val, 1); if (rc < 0) return rc; val = LDO_DIS_PULLDOWN_BIT | LDO_PD_STRENGTH_BIT; rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_LDO_PD_CTL_REG, &val, 1); if (rc < 0) return rc; val = NCP_DIS_PULLDOWN_BIT | NCP_PD_STRENGTH_BIT; rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_NCP_PD_CTL_REG, &val, 1); if (rc < 0) return rc; val = 0; rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_PWRUP_PWRDN_CTL_REG, &val, 1); if (rc < 0) return rc; val = 0; rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_BST_VREG_OK_CTL_REG, &val, 1); return rc; } static int qpnp_lcdb_ttw_enter_pm660l(struct qpnp_lcdb *lcdb) { int rc; u8 val; if (!lcdb->settings_saved) { rc = qpnp_lcdb_save_settings(lcdb); if (rc < 0) { pr_err("Failed to save LCDB settings rc=%d\n", rc); return rc; } lcdb->settings_saved = true; } val = BOOST_DIS_PULLDOWN_BIT; rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_BST_PD_CTL_REG, &val, 1); Loading Loading @@ -715,12 +854,17 @@ static int qpnp_lcdb_disable(struct qpnp_lcdb *lcdb) { int rc = 0; u8 val; u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype; if (!lcdb->lcdb_enabled) return 0; if (lcdb->ttw_enable) { if (pmic_subtype == PM660L_SUBTYPE) rc = qpnp_lcdb_ttw_enter_pm660l(lcdb); else rc = qpnp_lcdb_ttw_enter(lcdb); if (rc < 0) { pr_err("Failed to enable TTW mode rc=%d\n", rc); return rc; Loading Loading @@ -859,8 +1003,9 @@ static int qpnp_lcdb_set_bst_voltage(struct qpnp_lcdb *lcdb, int voltage_mv, u8 type) { int rc = 0; u8 val = 0; u8 val, mask = 0; int bst_voltage_mv; u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype; struct ldo_regulator *ldo = &lcdb->ldo; struct ncp_regulator *ncp = &lcdb->ncp; struct bst_params *bst = &lcdb->bst; Loading @@ -877,10 +1022,11 @@ static int qpnp_lcdb_set_bst_voltage(struct qpnp_lcdb *lcdb, if (bst_voltage_mv != bst->voltage_mv) { val = DIV_ROUND_UP(bst_voltage_mv - MIN_BST_VOLTAGE_MV, VOLTAGE_STEP_50_MV); mask = (pmic_subtype == PM660L_SUBTYPE) ? PM660_BST_OUTPUT_VOLTAGE_MASK : BST_OUTPUT_VOLTAGE_MASK; rc = qpnp_lcdb_masked_write(lcdb, lcdb->base + LCDB_BST_OUTPUT_VOLTAGE_REG, SET_OUTPUT_VOLTAGE_MASK, val); mask, val); if (rc < 0) { pr_err("Failed to set boost voltage %d mv rc=%d\n", bst_voltage_mv, rc); Loading @@ -898,7 +1044,8 @@ static int qpnp_lcdb_get_bst_voltage(struct qpnp_lcdb *lcdb, int *voltage_mv) { int rc; u8 val = 0; u8 val, mask = 0; u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype; rc = qpnp_lcdb_read(lcdb, lcdb->base + LCDB_BST_OUTPUT_VOLTAGE_REG, &val, 1); Loading @@ -907,7 +1054,9 @@ static int qpnp_lcdb_get_bst_voltage(struct qpnp_lcdb *lcdb, return rc; } val &= SET_OUTPUT_VOLTAGE_MASK; mask = (pmic_subtype == PM660L_SUBTYPE) ? PM660_BST_OUTPUT_VOLTAGE_MASK : BST_OUTPUT_VOLTAGE_MASK; val &= mask; *voltage_mv = (val * VOLTAGE_STEP_50_MV) + MIN_BST_VOLTAGE_MV; return 0; Loading Loading @@ -1369,6 +1518,8 @@ static int qpnp_lcdb_bst_dt_init(struct qpnp_lcdb *lcdb) { int rc = 0; struct device_node *node = lcdb->bst.node; u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype; u16 default_headroom_mv; /* Boost PD configuration */ lcdb->bst.pd = -EINVAL; Loading Loading @@ -1402,11 +1553,14 @@ static int qpnp_lcdb_bst_dt_init(struct qpnp_lcdb *lcdb) return -EINVAL; } default_headroom_mv = (pmic_subtype == PM660L_SUBTYPE) ? PM660_BST_HEADROOM_DEFAULT_MV : BST_HEADROOM_DEFAULT_MV; /* Boost head room configuration */ of_property_read_u16(node, "qcom,bst-headroom-mv", &lcdb->bst.headroom_mv); if (lcdb->bst.headroom_mv < BST_HEADROOM_DEFAULT_MV) lcdb->bst.headroom_mv = BST_HEADROOM_DEFAULT_MV; if (lcdb->bst.headroom_mv < default_headroom_mv) lcdb->bst.headroom_mv = default_headroom_mv; return 0; } Loading Loading @@ -1624,7 +1778,8 @@ static int qpnp_lcdb_init_ncp(struct qpnp_lcdb *lcdb) static int qpnp_lcdb_init_bst(struct qpnp_lcdb *lcdb) { int rc = 0; u8 val = 0; u8 val, mask = 0; u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype; /* configure parameters only if LCDB is disabled */ if (!is_lcdb_enabled(lcdb)) { Loading Loading @@ -1677,13 +1832,13 @@ static int qpnp_lcdb_init_bst(struct qpnp_lcdb *lcdb) } if (lcdb->bst.ps_threshold != -EINVAL) { mask = (pmic_subtype == PM660L_SUBTYPE) ? PM660_PS_THRESH_MASK : PS_THRESH_MASK; val = (lcdb->bst.ps_threshold - MIN_BST_PS_MA) / 10; val = (lcdb->bst.ps_threshold & PS_THRESHOLD_MASK) | EN_PS_BIT; val = (lcdb->bst.ps_threshold & mask) | EN_PS_BIT; rc = qpnp_lcdb_masked_write(lcdb, lcdb->base + LCDB_PS_CTL_REG, PS_THRESHOLD_MASK | EN_PS_BIT, val); mask | EN_PS_BIT, val); if (rc < 0) { pr_err("Failed to configure BST PS threshold rc=%d", rc); Loading @@ -1706,16 +1861,24 @@ static int qpnp_lcdb_init_bst(struct qpnp_lcdb *lcdb) } lcdb->bst.vreg_ok_dbc_us = dbc_us[val & VREG_OK_DEB_MASK]; if (pmic_subtype == PM660L_SUBTYPE) { rc = qpnp_lcdb_read(lcdb, lcdb->base + LCDB_SOFT_START_CTL_REG, &val, 1); if (rc < 0) { pr_err("Failed to read ncp_soft_start_ctl rc=%d\n", rc); pr_err("Failed to read lcdb_soft_start_ctl rc=%d\n", rc); return rc; } lcdb->bst.soft_start_us = (val & SOFT_START_MASK) * 200 + 200; if (!lcdb->bst.headroom_mv) lcdb->bst.headroom_mv = BST_HEADROOM_DEFAULT_MV; } else { rc = qpnp_lcdb_read(lcdb, lcdb->base + LCDB_BST_SS_CTL_REG, &val, 1); if (rc < 0) { pr_err("Failed to read bst_soft_start_ctl rc=%d\n", rc); return rc; } lcdb->bst.soft_start_us = soft_start_us[val & SOFT_START_MASK]; } return 0; } Loading Loading
drivers/regulator/qpnp-lcdb-regulator.c +227 −64 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 @@ -50,6 +50,8 @@ #define ATTW_MAX_MS 32 #define LCDB_BST_OUTPUT_VOLTAGE_REG 0x41 #define PM660_BST_OUTPUT_VOLTAGE_MASK GENMASK(4, 0) #define BST_OUTPUT_VOLTAGE_MASK GENMASK(5, 0) #define LCDB_MODULE_RDY_REG 0x45 #define MODULE_RDY_BIT BIT(7) Loading @@ -71,7 +73,8 @@ #define LCDB_PS_CTL_REG 0x50 #define EN_PS_BIT BIT(7) #define PS_THRESHOLD_MASK GENMASK(1, 0) #define PM660_PS_THRESH_MASK GENMASK(1, 0) #define PS_THRESH_MASK GENMASK(2, 0) #define MIN_BST_PS_MA 50 #define MAX_BST_PS_MA 80 Loading @@ -83,6 +86,20 @@ #define LCDB_BST_VREG_OK_CTL_REG 0x55 #define BST_VREG_OK_DEB_MASK GENMASK(1, 0) #define LCDB_BST_SS_CTL_REG 0x5B #define BST_SS_TIME_MASK GENMASK(1, 0) #define BST_PRECHG_SHORT_ALARM_SHIFT 2 #define BST_PRECHARGE_DONE_DEB_BIT BIT(4) #define BST_SS_TIME_OVERRIDE_SHIFT 5 #define BST_SS_TIME_OVERRIDE_0MS 0 #define BST_SS_TIME_OVERRIDE_0P5_MS 1 #define BST_SS_TIME_OVERRIDE_1MS 2 #define BST_SS_TIME_OVERRIDE_2MS 3 #define EN_BST_PRECHG_SHORT_ALARM 0 #define DIS_BST_PRECHG_SHORT_ALARM 1 #define LCDB_SOFT_START_CTL_REG 0x5F #define LCDB_MISC_CTL_REG 0x60 Loading Loading @@ -147,7 +164,8 @@ #define MIN_SOFT_START_US 0 #define MAX_SOFT_START_US 2000 #define BST_HEADROOM_DEFAULT_MV 200 #define PM660_BST_HEADROOM_DEFAULT_MV 200 #define BST_HEADROOM_DEFAULT_MV 150 struct ldo_regulator { struct regulator_desc rdesc; Loading Loading @@ -222,6 +240,7 @@ struct settings { u16 address; u8 value; bool sec_access; bool valid; }; enum lcdb_module { Loading Loading @@ -262,6 +281,8 @@ enum lcdb_settings_index { LCDB_LDO_SOFT_START_CTL, LCDB_NCP_PD_CTL, LCDB_NCP_SOFT_START_CTL, LCDB_BST_SS_CTL, LCDB_LDO_VREG_OK_CTL, LCDB_SETTING_MAX, }; Loading @@ -286,10 +307,11 @@ static u32 ncp_ilim_ma[] = { 810, }; #define SETTING(_id, _sec_access) \ #define SETTING(_id, _sec_access, _valid) \ [_id] = { \ .address = _id##_REG, \ .sec_access = _sec_access, \ .valid = _valid \ } \ static bool is_between(int value, int min, int max) Loading Loading @@ -334,13 +356,17 @@ static int qpnp_lcdb_secure_write(struct qpnp_lcdb *lcdb, { int rc; u8 val = SECURE_UNLOCK_VALUE; u8 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype; mutex_lock(&lcdb->read_write_mutex); rc = regmap_write(lcdb->regmap, lcdb->base + SEC_ADDRESS_REG, val); if (pmic_subtype == PM660L_SUBTYPE) { rc = regmap_write(lcdb->regmap, lcdb->base + SEC_ADDRESS_REG, val); if (rc < 0) { pr_err("Failed to unlock register rc=%d\n", rc); goto fail_write; } } rc = regmap_write(lcdb->regmap, addr, value); if (rc < 0) pr_err("Failed to write to addr=0x%02x rc=%d\n", addr, rc); Loading Loading @@ -397,58 +423,100 @@ static int dump_status_registers(struct qpnp_lcdb *lcdb) return rc; } static struct settings lcdb_settings_pm660l[] = { SETTING(LCDB_BST_PD_CTL, false, true), SETTING(LCDB_RDSON_MGMNT, false, true), SETTING(LCDB_MISC_CTL, false, true), SETTING(LCDB_SOFT_START_CTL, false, true), SETTING(LCDB_PFM_CTL, false, true), SETTING(LCDB_PWRUP_PWRDN_CTL, true, true), SETTING(LCDB_LDO_PD_CTL, false, true), SETTING(LCDB_LDO_SOFT_START_CTL, false, true), SETTING(LCDB_NCP_PD_CTL, false, true), SETTING(LCDB_NCP_SOFT_START_CTL, false, true), SETTING(LCDB_BST_SS_CTL, false, false), SETTING(LCDB_LDO_VREG_OK_CTL, false, false), }; /* For PMICs like pmi632/pm855L */ static struct settings lcdb_settings[] = { SETTING(LCDB_BST_PD_CTL, false), SETTING(LCDB_RDSON_MGMNT, false), SETTING(LCDB_MISC_CTL, false), SETTING(LCDB_SOFT_START_CTL, false), SETTING(LCDB_PFM_CTL, false), SETTING(LCDB_PWRUP_PWRDN_CTL, true), SETTING(LCDB_LDO_PD_CTL, false), SETTING(LCDB_LDO_SOFT_START_CTL, false), SETTING(LCDB_NCP_PD_CTL, false), SETTING(LCDB_NCP_SOFT_START_CTL, false), SETTING(LCDB_BST_PD_CTL, false, true), SETTING(LCDB_RDSON_MGMNT, false, false), SETTING(LCDB_MISC_CTL, false, false), SETTING(LCDB_SOFT_START_CTL, false, false), SETTING(LCDB_PFM_CTL, false, false), SETTING(LCDB_PWRUP_PWRDN_CTL, false, true), SETTING(LCDB_LDO_PD_CTL, false, true), SETTING(LCDB_LDO_SOFT_START_CTL, false, true), SETTING(LCDB_NCP_PD_CTL, false, true), SETTING(LCDB_NCP_SOFT_START_CTL, false, true), SETTING(LCDB_BST_SS_CTL, false, true), SETTING(LCDB_LDO_VREG_OK_CTL, false, true), }; static int qpnp_lcdb_save_settings(struct qpnp_lcdb *lcdb) { int i, rc = 0; int i, size, rc = 0; struct settings *setting; u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype; for (i = 0; i < ARRAY_SIZE(lcdb_settings); i++) { if (pmic_subtype == PM660L_SUBTYPE) { setting = lcdb_settings_pm660l; size = ARRAY_SIZE(lcdb_settings_pm660l); } else { setting = lcdb_settings; size = ARRAY_SIZE(lcdb_settings); } for (i = 0; i < size; i++) { if (setting[i].valid) { rc = qpnp_lcdb_read(lcdb, lcdb->base + lcdb_settings[i].address, &lcdb_settings[i].value, 1); setting[i].address, &setting[i].value, 1); if (rc < 0) { pr_err("Failed to read lcdb register address=%x\n", lcdb_settings[i].address); setting[i].address); return rc; } } } return rc; return 0; } static int qpnp_lcdb_restore_settings(struct qpnp_lcdb *lcdb) { int i, rc = 0; int i, size, rc = 0; struct settings *setting; u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype; for (i = 0; i < ARRAY_SIZE(lcdb_settings); i++) { if (lcdb_settings[i].sec_access) if (pmic_subtype == PM660L_SUBTYPE) { setting = lcdb_settings_pm660l; size = ARRAY_SIZE(lcdb_settings_pm660l); } else { setting = lcdb_settings; size = ARRAY_SIZE(lcdb_settings); } for (i = 0; i < size; i++) { if (setting[i].valid) { if (setting[i].sec_access) rc = qpnp_lcdb_secure_write(lcdb, lcdb->base + lcdb_settings[i].address, lcdb_settings[i].value); setting[i].address, setting[i].value); else rc = qpnp_lcdb_write(lcdb, lcdb->base + lcdb_settings[i].address, &lcdb_settings[i].value, 1); setting[i].address, &setting[i].value, 1); if (rc < 0) { pr_err("Failed to write register address=%x\n", lcdb_settings[i].address); setting[i].address); return rc; } } } return rc; return 0; } static int qpnp_lcdb_ttw_enter(struct qpnp_lcdb *lcdb) Loading @@ -465,6 +533,77 @@ static int qpnp_lcdb_ttw_enter(struct qpnp_lcdb *lcdb) lcdb->settings_saved = true; } val = HWEN_RDY_BIT; rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG, &val, 1); if (rc < 0) { pr_err("Failed to hw_enable lcdb rc= %d\n", rc); return rc; } val = (BST_SS_TIME_OVERRIDE_1MS << BST_SS_TIME_OVERRIDE_SHIFT) | (DIS_BST_PRECHG_SHORT_ALARM << BST_PRECHG_SHORT_ALARM_SHIFT); rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_BST_SS_CTL_REG, &val, 1); if (rc < 0) return rc; val = 0; rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_LDO_SOFT_START_CTL_REG, &val, 1); if (rc < 0) return rc; val = 0; rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_NCP_SOFT_START_CTL_REG, &val, 1); if (rc < 0) return rc; val = BOOST_DIS_PULLDOWN_BIT | BOOST_PD_STRENGTH_BIT; rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_BST_PD_CTL_REG, &val, 1); if (rc < 0) return rc; val = LDO_DIS_PULLDOWN_BIT | LDO_PD_STRENGTH_BIT; rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_LDO_PD_CTL_REG, &val, 1); if (rc < 0) return rc; val = NCP_DIS_PULLDOWN_BIT | NCP_PD_STRENGTH_BIT; rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_NCP_PD_CTL_REG, &val, 1); if (rc < 0) return rc; val = 0; rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_PWRUP_PWRDN_CTL_REG, &val, 1); if (rc < 0) return rc; val = 0; rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_BST_VREG_OK_CTL_REG, &val, 1); return rc; } static int qpnp_lcdb_ttw_enter_pm660l(struct qpnp_lcdb *lcdb) { int rc; u8 val; if (!lcdb->settings_saved) { rc = qpnp_lcdb_save_settings(lcdb); if (rc < 0) { pr_err("Failed to save LCDB settings rc=%d\n", rc); return rc; } lcdb->settings_saved = true; } val = BOOST_DIS_PULLDOWN_BIT; rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_BST_PD_CTL_REG, &val, 1); Loading Loading @@ -715,12 +854,17 @@ static int qpnp_lcdb_disable(struct qpnp_lcdb *lcdb) { int rc = 0; u8 val; u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype; if (!lcdb->lcdb_enabled) return 0; if (lcdb->ttw_enable) { if (pmic_subtype == PM660L_SUBTYPE) rc = qpnp_lcdb_ttw_enter_pm660l(lcdb); else rc = qpnp_lcdb_ttw_enter(lcdb); if (rc < 0) { pr_err("Failed to enable TTW mode rc=%d\n", rc); return rc; Loading Loading @@ -859,8 +1003,9 @@ static int qpnp_lcdb_set_bst_voltage(struct qpnp_lcdb *lcdb, int voltage_mv, u8 type) { int rc = 0; u8 val = 0; u8 val, mask = 0; int bst_voltage_mv; u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype; struct ldo_regulator *ldo = &lcdb->ldo; struct ncp_regulator *ncp = &lcdb->ncp; struct bst_params *bst = &lcdb->bst; Loading @@ -877,10 +1022,11 @@ static int qpnp_lcdb_set_bst_voltage(struct qpnp_lcdb *lcdb, if (bst_voltage_mv != bst->voltage_mv) { val = DIV_ROUND_UP(bst_voltage_mv - MIN_BST_VOLTAGE_MV, VOLTAGE_STEP_50_MV); mask = (pmic_subtype == PM660L_SUBTYPE) ? PM660_BST_OUTPUT_VOLTAGE_MASK : BST_OUTPUT_VOLTAGE_MASK; rc = qpnp_lcdb_masked_write(lcdb, lcdb->base + LCDB_BST_OUTPUT_VOLTAGE_REG, SET_OUTPUT_VOLTAGE_MASK, val); mask, val); if (rc < 0) { pr_err("Failed to set boost voltage %d mv rc=%d\n", bst_voltage_mv, rc); Loading @@ -898,7 +1044,8 @@ static int qpnp_lcdb_get_bst_voltage(struct qpnp_lcdb *lcdb, int *voltage_mv) { int rc; u8 val = 0; u8 val, mask = 0; u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype; rc = qpnp_lcdb_read(lcdb, lcdb->base + LCDB_BST_OUTPUT_VOLTAGE_REG, &val, 1); Loading @@ -907,7 +1054,9 @@ static int qpnp_lcdb_get_bst_voltage(struct qpnp_lcdb *lcdb, return rc; } val &= SET_OUTPUT_VOLTAGE_MASK; mask = (pmic_subtype == PM660L_SUBTYPE) ? PM660_BST_OUTPUT_VOLTAGE_MASK : BST_OUTPUT_VOLTAGE_MASK; val &= mask; *voltage_mv = (val * VOLTAGE_STEP_50_MV) + MIN_BST_VOLTAGE_MV; return 0; Loading Loading @@ -1369,6 +1518,8 @@ static int qpnp_lcdb_bst_dt_init(struct qpnp_lcdb *lcdb) { int rc = 0; struct device_node *node = lcdb->bst.node; u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype; u16 default_headroom_mv; /* Boost PD configuration */ lcdb->bst.pd = -EINVAL; Loading Loading @@ -1402,11 +1553,14 @@ static int qpnp_lcdb_bst_dt_init(struct qpnp_lcdb *lcdb) return -EINVAL; } default_headroom_mv = (pmic_subtype == PM660L_SUBTYPE) ? PM660_BST_HEADROOM_DEFAULT_MV : BST_HEADROOM_DEFAULT_MV; /* Boost head room configuration */ of_property_read_u16(node, "qcom,bst-headroom-mv", &lcdb->bst.headroom_mv); if (lcdb->bst.headroom_mv < BST_HEADROOM_DEFAULT_MV) lcdb->bst.headroom_mv = BST_HEADROOM_DEFAULT_MV; if (lcdb->bst.headroom_mv < default_headroom_mv) lcdb->bst.headroom_mv = default_headroom_mv; return 0; } Loading Loading @@ -1624,7 +1778,8 @@ static int qpnp_lcdb_init_ncp(struct qpnp_lcdb *lcdb) static int qpnp_lcdb_init_bst(struct qpnp_lcdb *lcdb) { int rc = 0; u8 val = 0; u8 val, mask = 0; u16 pmic_subtype = lcdb->pmic_rev_id->pmic_subtype; /* configure parameters only if LCDB is disabled */ if (!is_lcdb_enabled(lcdb)) { Loading Loading @@ -1677,13 +1832,13 @@ static int qpnp_lcdb_init_bst(struct qpnp_lcdb *lcdb) } if (lcdb->bst.ps_threshold != -EINVAL) { mask = (pmic_subtype == PM660L_SUBTYPE) ? PM660_PS_THRESH_MASK : PS_THRESH_MASK; val = (lcdb->bst.ps_threshold - MIN_BST_PS_MA) / 10; val = (lcdb->bst.ps_threshold & PS_THRESHOLD_MASK) | EN_PS_BIT; val = (lcdb->bst.ps_threshold & mask) | EN_PS_BIT; rc = qpnp_lcdb_masked_write(lcdb, lcdb->base + LCDB_PS_CTL_REG, PS_THRESHOLD_MASK | EN_PS_BIT, val); mask | EN_PS_BIT, val); if (rc < 0) { pr_err("Failed to configure BST PS threshold rc=%d", rc); Loading @@ -1706,16 +1861,24 @@ static int qpnp_lcdb_init_bst(struct qpnp_lcdb *lcdb) } lcdb->bst.vreg_ok_dbc_us = dbc_us[val & VREG_OK_DEB_MASK]; if (pmic_subtype == PM660L_SUBTYPE) { rc = qpnp_lcdb_read(lcdb, lcdb->base + LCDB_SOFT_START_CTL_REG, &val, 1); if (rc < 0) { pr_err("Failed to read ncp_soft_start_ctl rc=%d\n", rc); pr_err("Failed to read lcdb_soft_start_ctl rc=%d\n", rc); return rc; } lcdb->bst.soft_start_us = (val & SOFT_START_MASK) * 200 + 200; if (!lcdb->bst.headroom_mv) lcdb->bst.headroom_mv = BST_HEADROOM_DEFAULT_MV; } else { rc = qpnp_lcdb_read(lcdb, lcdb->base + LCDB_BST_SS_CTL_REG, &val, 1); if (rc < 0) { pr_err("Failed to read bst_soft_start_ctl rc=%d\n", rc); return rc; } lcdb->bst.soft_start_us = soft_start_us[val & SOFT_START_MASK]; } return 0; } Loading