diff options
| author | Anirudh Ghayal <aghayal@codeaurora.org> | 2016-02-15 16:49:46 +0530 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 21:23:09 -0700 |
| commit | 9be974698de0a7e2c7ace97fc3a78340f6bf385e (patch) | |
| tree | c6325a8915e3558c2ca58d273bdcb113e1da032f /drivers/regulator | |
| parent | 09a0e43d7804f95189834ab14150ad76a91a766e (diff) | |
regulator: qpnp-labibb: Add support for TTW on PMI8950
Add TTW configuration for PMI8950. Also, add a DT property
(qcom,labibb-ttw-force-lab-on) to keep LAB always-on in TTW mode.
Presently, this property is only required for PMI8950.
CRs-Fixed: 958285 962662
Change-Id: Iec79a6f752067d96fc62a8e9d629c39f4db5ab9f
Signed-off-by: Anirudh Ghayal <aghayal@codeaurora.org>
Signed-off-by: Subbaraman Narayanamurthy <subbaram@codeaurora.org>
Diffstat (limited to 'drivers/regulator')
| -rw-r--r-- | drivers/regulator/qpnp-labibb-regulator.c | 369 |
1 files changed, 292 insertions, 77 deletions
diff --git a/drivers/regulator/qpnp-labibb-regulator.c b/drivers/regulator/qpnp-labibb-regulator.c index de4614d4d1ef..83c309bb9089 100644 --- a/drivers/regulator/qpnp-labibb-regulator.c +++ b/drivers/regulator/qpnp-labibb-regulator.c @@ -26,6 +26,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" @@ -110,6 +111,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) @@ -195,6 +198,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) @@ -228,6 +234,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 @@ -444,6 +456,7 @@ struct qpnp_labibb { struct device *dev; struct platform_device *pdev; struct regmap *regmap; + struct pmic_revid_data *pmic_rev_id; u16 lab_base; u16 ibb_base; struct lab_regulator lab_vreg; @@ -453,6 +466,7 @@ struct qpnp_labibb { bool in_ttw_mode; bool ibb_settings_saved; bool swire_control; + bool ttw_force_lab_on; }; enum ibb_settings_index { @@ -461,11 +475,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, }; @@ -487,10 +506,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 @@ -950,48 +974,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); @@ -1034,18 +1021,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; - } + + 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; } @@ -1058,6 +1198,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; @@ -1075,30 +1230,42 @@ static int qpnp_labibb_regulator_ttw_mode_exit(struct qpnp_labibb *labibb) return rc; } - val = LAB_PD_CTL_STRONG_PULL; - 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; - } + 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); + if (rc) { + pr_err("qpnp_labibb_write register %x failed rc = %d\n", + REG_LAB_PD_CTL, rc); + return rc; + } - val = 0; - 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_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; } @@ -2138,20 +2305,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"); @@ -2317,11 +2470,48 @@ 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 platform_device *pdev) { struct qpnp_labibb *labibb; unsigned int base; - struct device_node *child; + struct device_node *child, *revid_dev_node; const char *mode_name; u8 type; int rc = 0; @@ -2341,6 +2531,19 @@ static int qpnp_labibb_regulator_probe(struct platform_device *pdev) labibb->dev = &(pdev->dev); labibb->pdev = pdev; + revid_dev_node = of_parse_phandle(labibb->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) { @@ -2367,6 +2570,9 @@ static int qpnp_labibb_regulator_probe(struct platform_device *pdev) 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) { @@ -2417,7 +2623,16 @@ static int qpnp_labibb_regulator_probe(struct platform_device *pdev) } } + 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(&pdev->dev, labibb); + return 0; fail_registration: |
