diff options
| -rw-r--r-- | Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt | 18 | ||||
| -rw-r--r-- | arch/arm/boot/dts/qcom/msm-pmi8994.dtsi | 2 | ||||
| -rw-r--r-- | arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi | 5 | ||||
| -rw-r--r-- | drivers/regulator/qpnp-labibb-regulator.c | 187 |
4 files changed, 183 insertions, 29 deletions
diff --git a/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt b/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt index 0ac3a1f73fa9..0545f6b7b59a 100644 --- a/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt @@ -93,7 +93,18 @@ LAB subnode required properties: 1130, 1070, 1010, 960, 910. - qcom,qpnp-lab-limit-maximum-current: The maximum inductor current limit in mA of LAB regulator. Supported values - are 200, 400, 600 and 800. + are 200, 400, 600, 800, 1000, 1200, + 1400 and 1600. +- interrupts: Specify the interrupts as per the interrupt + encoding. + Currently "lab-vreg-ok" is required for + LCD mode in pmicobalt. For AMOLED mode, + "lab-vreg-ok" is required only when SWIRE + control is enabled and skipping 2nd SWIRE + pulse is required in pmi8952/8996. +- interrupt-names: Interrupt names to match up 1-to-1 with + the interrupts specified in 'interrupts' + property. LAB subnode optional properties: @@ -229,7 +240,8 @@ Example: reg = <0xde00 0x100>; reg-names = "lab"; - interrupts = <0x3 0xde 0x0>; + interrupts = <0x3 0xde 0x0 + IRQ_TYPE_EDGE_RISING>; interrupt-names = "lab-vreg-ok"; regulator-name = "lab_reg"; @@ -249,7 +261,7 @@ Example: qcom,qpnp-lab-full-pull-down; qcom,qpnp-lab-pull-down-enable; qcom,qpnp-lab-switching-clock-frequency = <1600>; - qcom,qpnp-lab-limit-maximum-current = <800>; + qcom,qpnp-lab-limit-maximum-current = <1600>; qcom,qpnp-lab-limit-max-current-enable; qcom,qpnp-lab-ps-threshold = <40>; qcom,qpnp-lab-ps-enable; diff --git a/arch/arm/boot/dts/qcom/msm-pmi8994.dtsi b/arch/arm/boot/dts/qcom/msm-pmi8994.dtsi index bba70329c819..c46c0963ff56 100644 --- a/arch/arm/boot/dts/qcom/msm-pmi8994.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pmi8994.dtsi @@ -497,7 +497,7 @@ qcom,qpnp-lab-pull-down-enable; qcom,qpnp-lab-switching-clock-frequency = <1600>; - qcom,qpnp-lab-limit-maximum-current = <800>; + qcom,qpnp-lab-limit-maximum-current = <1600>; qcom,qpnp-lab-limit-max-current-enable; qcom,qpnp-lab-ps-threshold = <20>; qcom,qpnp-lab-ps-enable; diff --git a/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi b/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi index 04333c7df309..b88b0e28c948 100644 --- a/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi @@ -555,6 +555,9 @@ regulator-min-microvolt = <4600000>; regulator-max-microvolt = <6000000>; + interrupts = <0x3 0xde 0x0 + IRQ_TYPE_EDGE_RISING>; + interrupt-names = "lab-vreg-ok"; qcom,qpnp-lab-min-voltage = <4600000>; qcom,qpnp-lab-step-size = <100000>; qcom,qpnp-lab-slew-rate = <5000>; @@ -569,7 +572,7 @@ qcom,qpnp-lab-pull-down-enable; qcom,qpnp-lab-switching-clock-frequency = <1600>; - qcom,qpnp-lab-limit-maximum-current = <800>; + qcom,qpnp-lab-limit-maximum-current = <1600>; qcom,qpnp-lab-limit-max-current-enable; qcom,qpnp-lab-ps-threshold = <20>; qcom,qpnp-lab-ps-enable; diff --git a/drivers/regulator/qpnp-labibb-regulator.c b/drivers/regulator/qpnp-labibb-regulator.c index 445dfa6fc513..3d0be1f8a5b5 100644 --- a/drivers/regulator/qpnp-labibb-regulator.c +++ b/drivers/regulator/qpnp-labibb-regulator.c @@ -32,6 +32,7 @@ #define QPNP_LABIBB_REGULATOR_DRIVER_NAME "qcom,qpnp-labibb-regulator" +#define REG_REVISION_2 0x01 #define REG_PERPH_TYPE 0x04 #define QPNP_LAB_TYPE 0x24 @@ -60,6 +61,7 @@ #define REG_LAB_PRECHARGE_CTL 0x5E #define REG_LAB_SOFT_START_CTL 0x5F #define REG_LAB_SPARE_CTL 0x60 +#define REG_LAB_PFM_CTL 0x62 /* LAB register bits definitions */ @@ -91,9 +93,9 @@ #define LAB_IBB_EN_RDY_EN BIT(7) /* REG_LAB_CURRENT_LIMIT */ -#define LAB_CURRENT_LIMIT_BITS 3 -#define LAB_CURRENT_LIMIT_MASK ((1 << LAB_CURRENT_LIMIT_BITS) - 1) -#define LAB_CURRENT_LIMIT_EN BIT(7) +#define LAB_CURRENT_LIMIT_MASK GENMASK(2, 0) +#define LAB_CURRENT_LIMIT_EN_BIT BIT(7) +#define LAB_OVERRIDE_CURRENT_MAX_BIT BIT(3) /* REG_LAB_CURRENT_SENSE */ #define LAB_CURRENT_SENSE_GAIN_BITS 2 @@ -129,6 +131,9 @@ #define LAB_SPARE_TOUCH_WAKE_BIT BIT(3) #define LAB_SPARE_DISABLE_SCP_BIT BIT(0) +/* REG_LAB_PFM_CTL */ +#define LAB_PFM_EN_BIT BIT(7) + /* IBB register offset definitions */ #define REG_IBB_REVISION4 0x03 #define REG_IBB_STATUS1 0x08 @@ -344,6 +349,10 @@ static const int lab_current_limit_plan[] = { 400, 600, 800, + 1000, + 1200, + 1400, + 1600, }; static const char * const lab_current_sense_plan[] = { @@ -471,6 +480,8 @@ struct qpnp_labibb { struct pmic_revid_data *pmic_rev_id; u16 lab_base; u16 ibb_base; + u8 lab_dig_major; + u8 ibb_dig_major; struct lab_regulator lab_vreg; struct ibb_regulator ibb_vreg; enum qpnp_labibb_mode mode; @@ -481,6 +492,7 @@ struct qpnp_labibb { bool swire_control; bool ttw_force_lab_on; bool skip_2nd_swire_cmd; + bool pfm_enable; u32 swire_2nd_cmd_delay; u32 swire_ibb_ps_enable_delay; }; @@ -783,7 +795,7 @@ static int qpnp_lab_dt_init(struct qpnp_labibb *labibb, if (of_property_read_bool(of_node, "qcom,qpnp-lab-limit-max-current-enable")) - val |= LAB_CURRENT_LIMIT_EN; + val |= LAB_CURRENT_LIMIT_EN_BIT; rc = qpnp_labibb_write(labibb, labibb->lab_base + REG_LAB_CURRENT_LIMIT, &val, 1); @@ -936,6 +948,88 @@ static int qpnp_lab_dt_init(struct qpnp_labibb *labibb, return rc; } +#define LAB_CURRENT_MAX_1600MA 0x7 +#define LAB_CURRENT_MAX_400MA 0x1 +static int qpnp_lab_pfm_disable(struct qpnp_labibb *labibb) +{ + int rc = 0; + u8 val, mask; + + mutex_lock(&(labibb->lab_vreg.lab_mutex)); + if (!labibb->pfm_enable) { + pr_debug("PFM already disabled\n"); + goto out; + } + + val = 0; + mask = LAB_PFM_EN_BIT; + rc = qpnp_labibb_masked_write(labibb, labibb->lab_base + + REG_LAB_PFM_CTL, mask, val); + if (rc < 0) { + pr_err("Write register %x failed rc = %d\n", + REG_LAB_PFM_CTL, rc); + goto out; + } + + val = LAB_CURRENT_MAX_1600MA; + mask = LAB_OVERRIDE_CURRENT_MAX_BIT | LAB_CURRENT_LIMIT_MASK; + rc = qpnp_labibb_masked_write(labibb, labibb->lab_base + + REG_LAB_CURRENT_LIMIT, mask, val); + if (rc < 0) { + pr_err("Write register %x failed rc = %d\n", + REG_LAB_CURRENT_LIMIT, rc); + goto out; + } + + labibb->pfm_enable = false; +out: + mutex_unlock(&(labibb->lab_vreg.lab_mutex)); + return rc; +} + +static int qpnp_lab_pfm_enable(struct qpnp_labibb *labibb) +{ + int rc = 0; + u8 val, mask; + + mutex_lock(&(labibb->lab_vreg.lab_mutex)); + if (labibb->pfm_enable) { + pr_debug("PFM already enabled\n"); + goto out; + } + + /* Wait for ~100uS */ + usleep_range(100, 105); + + val = LAB_OVERRIDE_CURRENT_MAX_BIT | LAB_CURRENT_MAX_400MA; + mask = LAB_OVERRIDE_CURRENT_MAX_BIT | LAB_CURRENT_LIMIT_MASK; + rc = qpnp_labibb_masked_write(labibb, labibb->lab_base + + REG_LAB_CURRENT_LIMIT, mask, val); + if (rc < 0) { + pr_err("Write register %x failed rc = %d\n", + REG_LAB_CURRENT_LIMIT, rc); + goto out; + } + + /* Wait for ~100uS */ + usleep_range(100, 105); + + val = LAB_PFM_EN_BIT; + mask = LAB_PFM_EN_BIT; + rc = qpnp_labibb_masked_write(labibb, labibb->lab_base + + REG_LAB_PFM_CTL, mask, val); + if (rc < 0) { + pr_err("Write register %x failed rc = %d\n", + REG_LAB_PFM_CTL, rc); + goto out; + } + + labibb->pfm_enable = true; +out: + mutex_unlock(&(labibb->lab_vreg.lab_mutex)); + return rc; +} + static int qpnp_labibb_restore_settings(struct qpnp_labibb *labibb) { int rc, i; @@ -1435,6 +1529,15 @@ static int qpnp_labibb_regulator_disable(struct qpnp_labibb *labibb) return -EINVAL; } + if (labibb->pmic_rev_id->pmic_subtype == PMICOBALT_SUBTYPE && + labibb->mode == QPNP_LABIBB_LCD_MODE) { + rc = qpnp_lab_pfm_disable(labibb); + if (rc < 0) { + pr_err("Error in disabling PFM, rc=%d\n", rc); + return rc; + } + } + labibb->lab_vreg.vreg_enabled = 0; labibb->ibb_vreg.vreg_enabled = 0; @@ -1644,9 +1747,17 @@ static irqreturn_t lab_vreg_ok_handler(int irq, void *_labibb) struct qpnp_labibb *labibb = _labibb; int rc; - rc = qpnp_skip_swire_command(labibb); - if (rc) - pr_err("Failed in 'qpnp_skip_swire_command' rc=%d\n", rc); + if (labibb->skip_2nd_swire_cmd && labibb->lab_dig_major < 2) { + rc = qpnp_skip_swire_command(labibb); + if (rc < 0) + pr_err("Failed in 'qpnp_skip_swire_command' rc=%d\n", + rc); + } else if (labibb->pmic_rev_id->pmic_subtype == PMICOBALT_SUBTYPE && + labibb->mode == QPNP_LABIBB_LCD_MODE) { + rc = qpnp_lab_pfm_enable(labibb); + if (rc < 0) + pr_err("Failed to config PFM, rc=%d\n", rc); + } return IRQ_HANDLED; } @@ -1661,6 +1772,23 @@ static int qpnp_lab_regulator_get_voltage(struct regulator_dev *rdev) return labibb->lab_vreg.curr_volt; } +static bool is_lab_vreg_ok_irq_available(struct qpnp_labibb *labibb) +{ + /* + * LAB VREG_OK interrupt is used only to skip 2nd SWIRE command in + * dig_major < 2 targets. For pmicobalt, it is used to enable PFM in + * LCD mode. + */ + if (labibb->skip_2nd_swire_cmd && labibb->lab_dig_major < 2) + return true; + + if (labibb->pmic_rev_id->pmic_subtype == PMICOBALT_SUBTYPE && + labibb->mode == QPNP_LABIBB_LCD_MODE) + return true; + + return false; +} + static struct regulator_ops qpnp_lab_ops = { .enable = qpnp_lab_regulator_enable, .disable = qpnp_lab_regulator_disable, @@ -1809,19 +1937,6 @@ static int register_qpnp_lab_regulator(struct qpnp_labibb *labibb, } } - if (labibb->skip_2nd_swire_cmd) { - rc = devm_request_threaded_irq(labibb->dev, - labibb->lab_vreg.lab_vreg_ok_irq, NULL, - lab_vreg_ok_handler, - IRQF_ONESHOT | IRQF_TRIGGER_RISING, - "lab-vreg-ok", labibb); - if (rc) { - pr_err("Failed to register 'lab-vreg-ok' irq rc=%d\n", - rc); - return rc; - } - } - val = (labibb->standalone) ? 0 : LAB_IBB_EN_RDY_EN; rc = qpnp_labibb_sec_write(labibb, labibb->lab_base, REG_LAB_IBB_EN_RDY, &val, 1); @@ -1899,6 +2014,19 @@ static int register_qpnp_lab_regulator(struct qpnp_labibb *labibb, labibb->lab_vreg.vreg_enabled = 1; } + if (is_lab_vreg_ok_irq_available(labibb)) { + rc = devm_request_threaded_irq(labibb->dev, + labibb->lab_vreg.lab_vreg_ok_irq, NULL, + lab_vreg_ok_handler, + IRQF_ONESHOT | IRQF_TRIGGER_RISING, + "lab-vreg-ok", labibb); + if (rc) { + pr_err("Failed to register 'lab-vreg-ok' irq rc=%d\n", + rc); + return rc; + } + } + rc = qpnp_labibb_read(labibb, &val, labibb->lab_base + REG_LAB_MODULE_RDY, 1); if (rc) { @@ -1953,7 +2081,6 @@ static int register_qpnp_lab_regulator(struct qpnp_labibb *labibb, return -EINVAL; } - mutex_init(&(labibb->lab_vreg.lab_mutex)); return 0; } @@ -2683,14 +2810,13 @@ static int register_qpnp_ibb_regulator(struct qpnp_labibb *labibb, return -EINVAL; } - mutex_init(&(labibb->ibb_vreg.ibb_mutex)); return 0; } static int qpnp_lab_register_irq(struct device_node *child, struct qpnp_labibb *labibb) { - if (labibb->skip_2nd_swire_cmd) { + if (is_lab_vreg_ok_irq_available(labibb)) { labibb->lab_vreg.lab_vreg_ok_irq = of_irq_get_byname(child, "lab-vreg-ok"); if (labibb->lab_vreg.lab_vreg_ok_irq < 0) { @@ -2745,7 +2871,7 @@ static int qpnp_labibb_regulator_probe(struct platform_device *pdev) unsigned int base; struct device_node *child, *revid_dev_node; const char *mode_name; - u8 type; + u8 type, revision; int rc = 0; labibb = devm_kzalloc(&pdev->dev, @@ -2763,6 +2889,9 @@ static int qpnp_labibb_regulator_probe(struct platform_device *pdev) labibb->dev = &(pdev->dev); labibb->pdev = pdev; + mutex_init(&(labibb->lab_vreg.lab_mutex)); + mutex_init(&(labibb->ibb_vreg.ibb_mutex)); + revid_dev_node = of_parse_phandle(labibb->dev->of_node, "qcom,pmic-revid", 0); if (!revid_dev_node) { @@ -2817,6 +2946,7 @@ static int qpnp_labibb_regulator_probe(struct platform_device *pdev) labibb->skip_2nd_swire_cmd = of_property_read_bool(labibb->dev->of_node, "qcom,skip-2nd-swire-cmd"); + rc = of_property_read_u32(labibb->dev->of_node, "qcom,swire-2nd-cmd-delay", &labibb->swire_2nd_cmd_delay); @@ -2846,6 +2976,13 @@ static int qpnp_labibb_regulator_probe(struct platform_device *pdev) return rc; } + rc = qpnp_labibb_read(labibb, &revision, base + REG_REVISION_2, + 1); + if (rc) { + pr_err("Reading REVISION_2 failed rc=%d\n", rc); + goto fail_registration; + } + rc = qpnp_labibb_read(labibb, &type, base + REG_PERPH_TYPE, 1); if (rc) { @@ -2856,6 +2993,7 @@ static int qpnp_labibb_regulator_probe(struct platform_device *pdev) switch (type) { case QPNP_LAB_TYPE: labibb->lab_base = base; + labibb->lab_dig_major = revision; rc = qpnp_lab_register_irq(child, labibb); if (rc) { pr_err("Failed to register LAB IRQ rc=%d\n", @@ -2869,6 +3007,7 @@ static int qpnp_labibb_regulator_probe(struct platform_device *pdev) case QPNP_IBB_TYPE: labibb->ibb_base = base; + labibb->ibb_dig_major = revision; rc = register_qpnp_ibb_regulator(labibb, child); if (rc) goto fail_registration; |
