Loading Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt +5 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ Main node required properties: configured for AMOLED mode together. "stand-alone" means using LAB and IBB regulators as stand alone regulators. - qcom,pmic-revid: Specifies the phandle of the PMIC revid module. Used to identify the PMIC subtype. Main node optional properties: Loading @@ -31,6 +33,8 @@ Main node optional properties: - qpnp,swire-control: A bool property which indicates if the LAB/IBB is controlled by the SWIRE interface. Enable only if qpnp,qpnp-labibb-mode = "amoled". - qcom,labibb-ttw-force-lab-on: A boolean property which forces LAB to be always on during TTW mode. LAB subnode required properties: Loading Loading @@ -200,6 +204,7 @@ Example: #address-cells = <1>; #size-cells = <1>; qpnp,qpnp-labibb-mode = "lcd"; qcom,pmic-revid = <&pmi8994_revid>; lab_regulator: qcom,lab@de00 { reg = <0xde00 0x100>; Loading arch/arm/boot/dts/qcom/msm-pmi8950.dtsi +1 −0 Original line number Diff line number Diff line Loading @@ -428,6 +428,7 @@ compatible = "qcom,qpnp-labibb-regulator"; #address-cells = <1>; #size-cells = <1>; qcom,pmic-revid = <&pmi8950_revid>; ibb_regulator: qcom,ibb@dc00 { reg = <0xdc00 0x100>; Loading arch/arm/boot/dts/qcom/msm-pmi8994.dtsi +1 −0 Original line number Diff line number Diff line Loading @@ -452,6 +452,7 @@ compatible = "qcom,qpnp-labibb-regulator"; #address-cells = <1>; #size-cells = <1>; qcom,pmic-revid = <&pmi8994_revid>; ibb_regulator: qcom,ibb@dc00 { reg = <0xdc00 0x100>; Loading drivers/regulator/qpnp-labibb-regulator.c +292 −76 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> #include <linux/regulator/of_regulator.h> #include <linux/qpnp/qpnp-revid.h> #define QPNP_LABIBB_REGULATOR_DRIVER_NAME "qcom,qpnp-labibb-regulator" Loading Loading @@ -108,6 +109,8 @@ #define LAB_RDSON_MNGMNT_NFET_SHIFT 2 #define LAB_RDSON_MNGMNT_PFET_BITS 2 #define LAB_RDSON_MNGMNT_PFET_MASK ((1 << LAB_RDSON_MNGMNT_PFET_BITS) - 1) #define LAB_RDSON_NFET_SW_SIZE_QUARTER 0x0 #define LAB_RDSON_PFET_SW_SIZE_QUARTER 0x0 /* REG_LAB_PRECHARGE_CTL */ #define LAB_PRECHARGE_CTL_EN BIT(2) Loading Loading @@ -193,6 +196,9 @@ #define IBB_PFET_SW_SIZE_MASK ((1 << PFET_SW_SIZE_BITS) - 1) #define IBB_NFET_SW_SIZE_SHIFT 3 /* REG_IBB_SOFT_START_CTL */ #define IBB_SOFT_START_CHARGING_RESISTOR_16K 0x3 /* REG_IBB_SPARE_CTL */ #define IBB_BYPASS_PWRDN_DLY2_BIT BIT(5) #define IBB_FAST_STARTUP BIT(3) Loading Loading @@ -226,6 +232,12 @@ #define IBB_DIS_DLY_MASK ((1 << IBB_DIS_DLY_BITS) - 1) #define IBB_WAIT_MBG_OK BIT(2) enum pmic_subtype { PMI8994 = 10, PMI8950 = 17, PMI8996 = 19, }; /** * enum qpnp_labibb_mode - working mode of LAB/IBB regulators * %QPNP_LABIBB_STANDALONE_MODE: configure LAB/IBB regulator as a Loading Loading @@ -441,6 +453,7 @@ struct ibb_regulator { struct qpnp_labibb { struct device *dev; struct spmi_device *spmi; struct pmic_revid_data *pmic_rev_id; u16 lab_base; u16 ibb_base; struct lab_regulator lab_vreg; Loading @@ -450,6 +463,7 @@ struct qpnp_labibb { bool in_ttw_mode; bool ibb_settings_saved; bool swire_control; bool ttw_force_lab_on; }; enum ibb_settings_index { Loading @@ -458,11 +472,16 @@ enum ibb_settings_index { IBB_RDSON_MNGMNT, IBB_PWRUP_PWRDN_CTL_1, IBB_PWRUP_PWRDN_CTL_2, IBB_NLIMIT_DAC, IBB_PS_CTL, IBB_SOFT_START_CTL, IBB_SETTINGS_MAX, }; enum lab_settings_index { LAB_SOFT_START_CTL = 0, LAB_PS_CTL, LAB_RDSON_MNGMNT, LAB_SETTINGS_MAX, }; Loading @@ -484,10 +503,15 @@ static struct settings ibb_settings[IBB_SETTINGS_MAX] = { SETTING(IBB_RDSON_MNGMNT, false), SETTING(IBB_PWRUP_PWRDN_CTL_1, true), SETTING(IBB_PWRUP_PWRDN_CTL_2, true), SETTING(IBB_NLIMIT_DAC, false), SETTING(IBB_PS_CTL, false), SETTING(IBB_SOFT_START_CTL, false), }; static struct settings lab_settings[LAB_SETTINGS_MAX] = { SETTING(LAB_SOFT_START_CTL, false), SETTING(LAB_PS_CTL, false), SETTING(LAB_RDSON_MNGMNT, false), }; static int Loading Loading @@ -960,48 +984,11 @@ static int qpnp_labibb_save_settings(struct qpnp_labibb *labibb) return 0; } static int qpnp_labibb_regulator_ttw_mode_enter(struct qpnp_labibb *labibb) static int qpnp_labibb_ttw_enter_ibb_common(struct qpnp_labibb *labibb) { int rc = 0; u8 val; /* Save the IBB settings before they get modified for TTW mode */ if (!labibb->ibb_settings_saved) { rc = qpnp_labibb_save_settings(labibb); if (rc) { pr_err("Error in storing IBB setttings, rc=%d\n", rc); return rc; } labibb->ibb_settings_saved = true; } val = LAB_PD_CTL_DISABLE_PD; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_PD_CTL, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_PD_CTL, rc); return rc; } val = LAB_SPARE_TOUCH_WAKE_BIT | LAB_SPARE_DISABLE_SCP_BIT; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_SPARE_CTL, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_SPARE_CTL, rc); return rc; } val = 0; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_SOFT_START_CTL, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_SOFT_START_CTL, rc); return rc; } val = 0; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_PD_CTL, &val, 1); Loading Loading @@ -1044,18 +1031,171 @@ static int qpnp_labibb_regulator_ttw_mode_enter(struct qpnp_labibb *labibb) (IBB_ILIMIT_COUNT_CYC8 << IBB_CURRENT_LIMIT_DEBOUNCE_SHIFT); rc = qpnp_labibb_sec_write(labibb, labibb->ibb_base, REG_IBB_CURRENT_LIMIT, &val, 1); if (rc) { if (rc) pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_IBB_CURRENT_LIMIT, rc); return rc; } static int qpnp_labibb_ttw_enter_ibb_pmi8996(struct qpnp_labibb *labibb) { int rc; u8 val; val = IBB_BYPASS_PWRDN_DLY2_BIT | IBB_FAST_STARTUP; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_SPARE_CTL, &val, 1); if (rc) { if (rc) pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_IBB_SPARE_CTL, rc); return rc; } static int qpnp_labibb_ttw_enter_ibb_pmi8950(struct qpnp_labibb *labibb) { int rc; u8 val; val = 0; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_NLIMIT_DAC, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_IBB_NLIMIT_DAC, rc); return rc; } val = IBB_PS_CTL_EN; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_PS_CTL, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_IBB_PS_CTL, rc); return rc; } val = IBB_SOFT_START_CHARGING_RESISTOR_16K; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_SOFT_START_CTL, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_IBB_SOFT_START_CTL, rc); return rc; } val = IBB_MODULE_RDY_EN; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_IBB_MODULE_RDY, &val, 1); if (rc) pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_IBB_MODULE_RDY, rc); return rc; } static int qpnp_labibb_regulator_ttw_mode_enter(struct qpnp_labibb *labibb) { int rc = 0; u8 val; /* Save the IBB settings before they get modified for TTW mode */ if (!labibb->ibb_settings_saved) { rc = qpnp_labibb_save_settings(labibb); if (rc) { pr_err("Error in storing IBB setttings, rc=%d\n", rc); return rc; } labibb->ibb_settings_saved = true; } if (labibb->ttw_force_lab_on) { val = LAB_MODULE_RDY_EN; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_MODULE_RDY, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_MODULE_RDY, rc); return rc; } /* Prevents LAB being turned off by IBB */ val = LAB_ENABLE_CTL_EN; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_ENABLE_CTL, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_ENABLE_CTL, rc); return rc; } val = LAB_RDSON_MNGMNT_NFET_SLEW_EN | LAB_RDSON_MNGMNT_PFET_SLEW_EN | LAB_RDSON_NFET_SW_SIZE_QUARTER | LAB_RDSON_PFET_SW_SIZE_QUARTER; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_RDSON_MNGMNT, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_RDSON_MNGMNT, rc); return rc; } rc = qpnp_labibb_masked_write(labibb, labibb->lab_base + REG_LAB_PS_CTL, LAB_PS_CTL_EN, LAB_PS_CTL_EN); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_PS_CTL, rc); return rc; } } else { val = LAB_PD_CTL_DISABLE_PD; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_PD_CTL, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_PD_CTL, rc); return rc; } val = LAB_SPARE_DISABLE_SCP_BIT; if (labibb->pmic_rev_id->pmic_subtype != PMI8950) val |= LAB_SPARE_TOUCH_WAKE_BIT; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_SPARE_CTL, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_SPARE_CTL, rc); return rc; } val = 0; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_SOFT_START_CTL, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_SOFT_START_CTL, rc); return rc; } } rc = qpnp_labibb_ttw_enter_ibb_common(labibb); if (rc) { pr_err("Failed to apply TTW ibb common settings rc=%d\n", rc); return rc; } switch (labibb->pmic_rev_id->pmic_subtype) { case PMI8996: rc = qpnp_labibb_ttw_enter_ibb_pmi8996(labibb); break; case PMI8950: rc = qpnp_labibb_ttw_enter_ibb_pmi8950(labibb); break; } if (rc) { pr_err("Failed to configure TTW-enter for IBB rc=%d\n", rc); return rc; } Loading @@ -1068,6 +1208,21 @@ static int qpnp_labibb_regulator_ttw_mode_enter(struct qpnp_labibb *labibb) return 0; } static int qpnp_labibb_ttw_exit_ibb_pmi8996(struct qpnp_labibb *labibb) { int rc; u8 val; val = 0; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_SPARE_CTL, &val, 1); if (rc) pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_IBB_SPARE_CTL, rc); return rc; } static int qpnp_labibb_regulator_ttw_mode_exit(struct qpnp_labibb *labibb) { int rc = 0; Loading @@ -1085,9 +1240,19 @@ static int qpnp_labibb_regulator_ttw_mode_exit(struct qpnp_labibb *labibb) return rc; } if (labibb->ttw_force_lab_on) { val = 0; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_ENABLE_CTL, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_ENABLE_CTL, rc); return rc; } } else { val = LAB_PD_CTL_STRONG_PULL; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_PD_CTL, &val, 1); rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_PD_CTL, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_PD_CTL, rc); Loading @@ -1095,20 +1260,22 @@ static int qpnp_labibb_regulator_ttw_mode_exit(struct qpnp_labibb *labibb) } val = 0; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_SPARE_CTL, &val, 1); rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_SPARE_CTL, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_SPARE_CTL, rc); return rc; } } val = 0; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_SPARE_CTL, &val, 1); switch (labibb->pmic_rev_id->pmic_subtype) { case PMI8996: rc = qpnp_labibb_ttw_exit_ibb_pmi8996(labibb); break; } if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_IBB_SPARE_CTL, rc); pr_err("Failed to configure TTW-exit for IBB rc=%d\n", rc); return rc; } Loading Loading @@ -2171,20 +2338,6 @@ static int register_qpnp_ibb_regulator(struct qpnp_labibb *labibb, return rc; } rc = qpnp_labibb_read(labibb, &val, labibb->ibb_base + REG_IBB_REVISION4, 1); if (rc) { pr_err("qpnp_labibb_read register %x failed rc = %d\n", REG_IBB_REVISION4, rc); return rc; } /* PMI8996 has revision 1 */ if (val < 1 && labibb->ttw_en) { pr_err("TTW feature cannot be enabled for revision %d\n", val); labibb->ttw_en = false; } if (of_find_property(of_node, "qcom,output-voltage-one-pulse", NULL)) { if (!labibb->swire_control) { pr_err("Invalid property 'qcom,output-voltage-one-pulse', valid only in SWIRE config\n"); Loading Loading @@ -2359,11 +2512,49 @@ static int register_qpnp_ibb_regulator(struct qpnp_labibb *labibb, return 0; } static int qpnp_labibb_check_ttw_supported(struct qpnp_labibb *labibb) { int rc = 0; u8 val; switch (labibb->pmic_rev_id->pmic_subtype) { case PMI8996: rc = qpnp_labibb_read(labibb, &val, labibb->ibb_base + REG_IBB_REVISION4, 1); if (rc) { pr_err("qpnp_labibb_read register %x failed rc = %d\n", REG_IBB_REVISION4, rc); return rc; } /* PMI8996 has revision 1 */ if (val < 1) { pr_err("TTW feature cannot be enabled for revision %d\n", val); labibb->ttw_en = false; } /* FORCE_LAB_ON in TTW is not required for PMI8996 */ labibb->ttw_force_lab_on = false; break; case PMI8950: /* TTW supported for all revisions */ break; default: pr_info("TTW mode not supported for PMIC-subtype = %d\n", labibb->pmic_rev_id->pmic_subtype); labibb->ttw_en = false; break; } return rc; } static int qpnp_labibb_regulator_probe(struct spmi_device *spmi) { struct qpnp_labibb *labibb; struct resource *resource; struct spmi_resource *spmi_resource; struct device_node *revid_dev_node; const char *mode_name; u8 type; int rc = 0; Loading @@ -2378,6 +2569,19 @@ static int qpnp_labibb_regulator_probe(struct spmi_device *spmi) labibb->dev = &(spmi->dev); labibb->spmi = spmi; revid_dev_node = of_parse_phandle(spmi->dev.of_node, "qcom,pmic-revid", 0); if (!revid_dev_node) { pr_err("Missing qcom,pmic-revid property - driver failed\n"); return -EINVAL; } labibb->pmic_rev_id = get_revid_data(revid_dev_node); if (IS_ERR(labibb->pmic_rev_id)) { pr_debug("Unable to get revid data\n"); return -EPROBE_DEFER; } rc = of_property_read_string(labibb->dev->of_node, "qpnp,qpnp-labibb-mode", &mode_name); if (!rc) { Loading @@ -2404,6 +2608,9 @@ static int qpnp_labibb_regulator_probe(struct spmi_device *spmi) return -EINVAL; } labibb->ttw_force_lab_on = of_property_read_bool( labibb->dev->of_node, "qcom,labibb-ttw-force-lab-on"); labibb->swire_control = of_property_read_bool(labibb->dev->of_node, "qpnp,swire-control"); if (labibb->swire_control && labibb->mode != QPNP_LABIBB_AMOLED_MODE) { Loading Loading @@ -2457,6 +2664,15 @@ static int qpnp_labibb_regulator_probe(struct spmi_device *spmi) } } if (labibb->ttw_en) { rc = qpnp_labibb_check_ttw_supported(labibb); if (rc) { pr_err("pmic revision check failed for TTW rc=%d\n", rc); goto fail_registration; } } dev_set_drvdata(&spmi->dev, labibb); return 0; Loading Loading
Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt +5 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ Main node required properties: configured for AMOLED mode together. "stand-alone" means using LAB and IBB regulators as stand alone regulators. - qcom,pmic-revid: Specifies the phandle of the PMIC revid module. Used to identify the PMIC subtype. Main node optional properties: Loading @@ -31,6 +33,8 @@ Main node optional properties: - qpnp,swire-control: A bool property which indicates if the LAB/IBB is controlled by the SWIRE interface. Enable only if qpnp,qpnp-labibb-mode = "amoled". - qcom,labibb-ttw-force-lab-on: A boolean property which forces LAB to be always on during TTW mode. LAB subnode required properties: Loading Loading @@ -200,6 +204,7 @@ Example: #address-cells = <1>; #size-cells = <1>; qpnp,qpnp-labibb-mode = "lcd"; qcom,pmic-revid = <&pmi8994_revid>; lab_regulator: qcom,lab@de00 { reg = <0xde00 0x100>; Loading
arch/arm/boot/dts/qcom/msm-pmi8950.dtsi +1 −0 Original line number Diff line number Diff line Loading @@ -428,6 +428,7 @@ compatible = "qcom,qpnp-labibb-regulator"; #address-cells = <1>; #size-cells = <1>; qcom,pmic-revid = <&pmi8950_revid>; ibb_regulator: qcom,ibb@dc00 { reg = <0xdc00 0x100>; Loading
arch/arm/boot/dts/qcom/msm-pmi8994.dtsi +1 −0 Original line number Diff line number Diff line Loading @@ -452,6 +452,7 @@ compatible = "qcom,qpnp-labibb-regulator"; #address-cells = <1>; #size-cells = <1>; qcom,pmic-revid = <&pmi8994_revid>; ibb_regulator: qcom,ibb@dc00 { reg = <0xdc00 0x100>; Loading
drivers/regulator/qpnp-labibb-regulator.c +292 −76 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> #include <linux/regulator/of_regulator.h> #include <linux/qpnp/qpnp-revid.h> #define QPNP_LABIBB_REGULATOR_DRIVER_NAME "qcom,qpnp-labibb-regulator" Loading Loading @@ -108,6 +109,8 @@ #define LAB_RDSON_MNGMNT_NFET_SHIFT 2 #define LAB_RDSON_MNGMNT_PFET_BITS 2 #define LAB_RDSON_MNGMNT_PFET_MASK ((1 << LAB_RDSON_MNGMNT_PFET_BITS) - 1) #define LAB_RDSON_NFET_SW_SIZE_QUARTER 0x0 #define LAB_RDSON_PFET_SW_SIZE_QUARTER 0x0 /* REG_LAB_PRECHARGE_CTL */ #define LAB_PRECHARGE_CTL_EN BIT(2) Loading Loading @@ -193,6 +196,9 @@ #define IBB_PFET_SW_SIZE_MASK ((1 << PFET_SW_SIZE_BITS) - 1) #define IBB_NFET_SW_SIZE_SHIFT 3 /* REG_IBB_SOFT_START_CTL */ #define IBB_SOFT_START_CHARGING_RESISTOR_16K 0x3 /* REG_IBB_SPARE_CTL */ #define IBB_BYPASS_PWRDN_DLY2_BIT BIT(5) #define IBB_FAST_STARTUP BIT(3) Loading Loading @@ -226,6 +232,12 @@ #define IBB_DIS_DLY_MASK ((1 << IBB_DIS_DLY_BITS) - 1) #define IBB_WAIT_MBG_OK BIT(2) enum pmic_subtype { PMI8994 = 10, PMI8950 = 17, PMI8996 = 19, }; /** * enum qpnp_labibb_mode - working mode of LAB/IBB regulators * %QPNP_LABIBB_STANDALONE_MODE: configure LAB/IBB regulator as a Loading Loading @@ -441,6 +453,7 @@ struct ibb_regulator { struct qpnp_labibb { struct device *dev; struct spmi_device *spmi; struct pmic_revid_data *pmic_rev_id; u16 lab_base; u16 ibb_base; struct lab_regulator lab_vreg; Loading @@ -450,6 +463,7 @@ struct qpnp_labibb { bool in_ttw_mode; bool ibb_settings_saved; bool swire_control; bool ttw_force_lab_on; }; enum ibb_settings_index { Loading @@ -458,11 +472,16 @@ enum ibb_settings_index { IBB_RDSON_MNGMNT, IBB_PWRUP_PWRDN_CTL_1, IBB_PWRUP_PWRDN_CTL_2, IBB_NLIMIT_DAC, IBB_PS_CTL, IBB_SOFT_START_CTL, IBB_SETTINGS_MAX, }; enum lab_settings_index { LAB_SOFT_START_CTL = 0, LAB_PS_CTL, LAB_RDSON_MNGMNT, LAB_SETTINGS_MAX, }; Loading @@ -484,10 +503,15 @@ static struct settings ibb_settings[IBB_SETTINGS_MAX] = { SETTING(IBB_RDSON_MNGMNT, false), SETTING(IBB_PWRUP_PWRDN_CTL_1, true), SETTING(IBB_PWRUP_PWRDN_CTL_2, true), SETTING(IBB_NLIMIT_DAC, false), SETTING(IBB_PS_CTL, false), SETTING(IBB_SOFT_START_CTL, false), }; static struct settings lab_settings[LAB_SETTINGS_MAX] = { SETTING(LAB_SOFT_START_CTL, false), SETTING(LAB_PS_CTL, false), SETTING(LAB_RDSON_MNGMNT, false), }; static int Loading Loading @@ -960,48 +984,11 @@ static int qpnp_labibb_save_settings(struct qpnp_labibb *labibb) return 0; } static int qpnp_labibb_regulator_ttw_mode_enter(struct qpnp_labibb *labibb) static int qpnp_labibb_ttw_enter_ibb_common(struct qpnp_labibb *labibb) { int rc = 0; u8 val; /* Save the IBB settings before they get modified for TTW mode */ if (!labibb->ibb_settings_saved) { rc = qpnp_labibb_save_settings(labibb); if (rc) { pr_err("Error in storing IBB setttings, rc=%d\n", rc); return rc; } labibb->ibb_settings_saved = true; } val = LAB_PD_CTL_DISABLE_PD; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_PD_CTL, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_PD_CTL, rc); return rc; } val = LAB_SPARE_TOUCH_WAKE_BIT | LAB_SPARE_DISABLE_SCP_BIT; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_SPARE_CTL, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_SPARE_CTL, rc); return rc; } val = 0; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_SOFT_START_CTL, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_SOFT_START_CTL, rc); return rc; } val = 0; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_PD_CTL, &val, 1); Loading Loading @@ -1044,18 +1031,171 @@ static int qpnp_labibb_regulator_ttw_mode_enter(struct qpnp_labibb *labibb) (IBB_ILIMIT_COUNT_CYC8 << IBB_CURRENT_LIMIT_DEBOUNCE_SHIFT); rc = qpnp_labibb_sec_write(labibb, labibb->ibb_base, REG_IBB_CURRENT_LIMIT, &val, 1); if (rc) { if (rc) pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_IBB_CURRENT_LIMIT, rc); return rc; } static int qpnp_labibb_ttw_enter_ibb_pmi8996(struct qpnp_labibb *labibb) { int rc; u8 val; val = IBB_BYPASS_PWRDN_DLY2_BIT | IBB_FAST_STARTUP; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_SPARE_CTL, &val, 1); if (rc) { if (rc) pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_IBB_SPARE_CTL, rc); return rc; } static int qpnp_labibb_ttw_enter_ibb_pmi8950(struct qpnp_labibb *labibb) { int rc; u8 val; val = 0; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_NLIMIT_DAC, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_IBB_NLIMIT_DAC, rc); return rc; } val = IBB_PS_CTL_EN; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_PS_CTL, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_IBB_PS_CTL, rc); return rc; } val = IBB_SOFT_START_CHARGING_RESISTOR_16K; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_SOFT_START_CTL, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_IBB_SOFT_START_CTL, rc); return rc; } val = IBB_MODULE_RDY_EN; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_IBB_MODULE_RDY, &val, 1); if (rc) pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_IBB_MODULE_RDY, rc); return rc; } static int qpnp_labibb_regulator_ttw_mode_enter(struct qpnp_labibb *labibb) { int rc = 0; u8 val; /* Save the IBB settings before they get modified for TTW mode */ if (!labibb->ibb_settings_saved) { rc = qpnp_labibb_save_settings(labibb); if (rc) { pr_err("Error in storing IBB setttings, rc=%d\n", rc); return rc; } labibb->ibb_settings_saved = true; } if (labibb->ttw_force_lab_on) { val = LAB_MODULE_RDY_EN; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_MODULE_RDY, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_MODULE_RDY, rc); return rc; } /* Prevents LAB being turned off by IBB */ val = LAB_ENABLE_CTL_EN; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_ENABLE_CTL, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_ENABLE_CTL, rc); return rc; } val = LAB_RDSON_MNGMNT_NFET_SLEW_EN | LAB_RDSON_MNGMNT_PFET_SLEW_EN | LAB_RDSON_NFET_SW_SIZE_QUARTER | LAB_RDSON_PFET_SW_SIZE_QUARTER; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_RDSON_MNGMNT, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_RDSON_MNGMNT, rc); return rc; } rc = qpnp_labibb_masked_write(labibb, labibb->lab_base + REG_LAB_PS_CTL, LAB_PS_CTL_EN, LAB_PS_CTL_EN); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_PS_CTL, rc); return rc; } } else { val = LAB_PD_CTL_DISABLE_PD; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_PD_CTL, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_PD_CTL, rc); return rc; } val = LAB_SPARE_DISABLE_SCP_BIT; if (labibb->pmic_rev_id->pmic_subtype != PMI8950) val |= LAB_SPARE_TOUCH_WAKE_BIT; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_SPARE_CTL, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_SPARE_CTL, rc); return rc; } val = 0; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_SOFT_START_CTL, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_SOFT_START_CTL, rc); return rc; } } rc = qpnp_labibb_ttw_enter_ibb_common(labibb); if (rc) { pr_err("Failed to apply TTW ibb common settings rc=%d\n", rc); return rc; } switch (labibb->pmic_rev_id->pmic_subtype) { case PMI8996: rc = qpnp_labibb_ttw_enter_ibb_pmi8996(labibb); break; case PMI8950: rc = qpnp_labibb_ttw_enter_ibb_pmi8950(labibb); break; } if (rc) { pr_err("Failed to configure TTW-enter for IBB rc=%d\n", rc); return rc; } Loading @@ -1068,6 +1208,21 @@ static int qpnp_labibb_regulator_ttw_mode_enter(struct qpnp_labibb *labibb) return 0; } static int qpnp_labibb_ttw_exit_ibb_pmi8996(struct qpnp_labibb *labibb) { int rc; u8 val; val = 0; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_SPARE_CTL, &val, 1); if (rc) pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_IBB_SPARE_CTL, rc); return rc; } static int qpnp_labibb_regulator_ttw_mode_exit(struct qpnp_labibb *labibb) { int rc = 0; Loading @@ -1085,9 +1240,19 @@ static int qpnp_labibb_regulator_ttw_mode_exit(struct qpnp_labibb *labibb) return rc; } if (labibb->ttw_force_lab_on) { val = 0; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_ENABLE_CTL, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_ENABLE_CTL, rc); return rc; } } else { val = LAB_PD_CTL_STRONG_PULL; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_PD_CTL, &val, 1); rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_PD_CTL, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_PD_CTL, rc); Loading @@ -1095,20 +1260,22 @@ static int qpnp_labibb_regulator_ttw_mode_exit(struct qpnp_labibb *labibb) } val = 0; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_SPARE_CTL, &val, 1); rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_SPARE_CTL, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_LAB_SPARE_CTL, rc); return rc; } } val = 0; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_SPARE_CTL, &val, 1); switch (labibb->pmic_rev_id->pmic_subtype) { case PMI8996: rc = qpnp_labibb_ttw_exit_ibb_pmi8996(labibb); break; } if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_IBB_SPARE_CTL, rc); pr_err("Failed to configure TTW-exit for IBB rc=%d\n", rc); return rc; } Loading Loading @@ -2171,20 +2338,6 @@ static int register_qpnp_ibb_regulator(struct qpnp_labibb *labibb, return rc; } rc = qpnp_labibb_read(labibb, &val, labibb->ibb_base + REG_IBB_REVISION4, 1); if (rc) { pr_err("qpnp_labibb_read register %x failed rc = %d\n", REG_IBB_REVISION4, rc); return rc; } /* PMI8996 has revision 1 */ if (val < 1 && labibb->ttw_en) { pr_err("TTW feature cannot be enabled for revision %d\n", val); labibb->ttw_en = false; } if (of_find_property(of_node, "qcom,output-voltage-one-pulse", NULL)) { if (!labibb->swire_control) { pr_err("Invalid property 'qcom,output-voltage-one-pulse', valid only in SWIRE config\n"); Loading Loading @@ -2359,11 +2512,49 @@ static int register_qpnp_ibb_regulator(struct qpnp_labibb *labibb, return 0; } static int qpnp_labibb_check_ttw_supported(struct qpnp_labibb *labibb) { int rc = 0; u8 val; switch (labibb->pmic_rev_id->pmic_subtype) { case PMI8996: rc = qpnp_labibb_read(labibb, &val, labibb->ibb_base + REG_IBB_REVISION4, 1); if (rc) { pr_err("qpnp_labibb_read register %x failed rc = %d\n", REG_IBB_REVISION4, rc); return rc; } /* PMI8996 has revision 1 */ if (val < 1) { pr_err("TTW feature cannot be enabled for revision %d\n", val); labibb->ttw_en = false; } /* FORCE_LAB_ON in TTW is not required for PMI8996 */ labibb->ttw_force_lab_on = false; break; case PMI8950: /* TTW supported for all revisions */ break; default: pr_info("TTW mode not supported for PMIC-subtype = %d\n", labibb->pmic_rev_id->pmic_subtype); labibb->ttw_en = false; break; } return rc; } static int qpnp_labibb_regulator_probe(struct spmi_device *spmi) { struct qpnp_labibb *labibb; struct resource *resource; struct spmi_resource *spmi_resource; struct device_node *revid_dev_node; const char *mode_name; u8 type; int rc = 0; Loading @@ -2378,6 +2569,19 @@ static int qpnp_labibb_regulator_probe(struct spmi_device *spmi) labibb->dev = &(spmi->dev); labibb->spmi = spmi; revid_dev_node = of_parse_phandle(spmi->dev.of_node, "qcom,pmic-revid", 0); if (!revid_dev_node) { pr_err("Missing qcom,pmic-revid property - driver failed\n"); return -EINVAL; } labibb->pmic_rev_id = get_revid_data(revid_dev_node); if (IS_ERR(labibb->pmic_rev_id)) { pr_debug("Unable to get revid data\n"); return -EPROBE_DEFER; } rc = of_property_read_string(labibb->dev->of_node, "qpnp,qpnp-labibb-mode", &mode_name); if (!rc) { Loading @@ -2404,6 +2608,9 @@ static int qpnp_labibb_regulator_probe(struct spmi_device *spmi) return -EINVAL; } labibb->ttw_force_lab_on = of_property_read_bool( labibb->dev->of_node, "qcom,labibb-ttw-force-lab-on"); labibb->swire_control = of_property_read_bool(labibb->dev->of_node, "qpnp,swire-control"); if (labibb->swire_control && labibb->mode != QPNP_LABIBB_AMOLED_MODE) { Loading Loading @@ -2457,6 +2664,15 @@ static int qpnp_labibb_regulator_probe(struct spmi_device *spmi) } } if (labibb->ttw_en) { rc = qpnp_labibb_check_ttw_supported(labibb); if (rc) { pr_err("pmic revision check failed for TTW rc=%d\n", rc); goto fail_registration; } } dev_set_drvdata(&spmi->dev, labibb); return 0; Loading