Loading drivers/regulator/qpnp-labibb-regulator.c +72 −54 Original line number Diff line number Diff line /* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2014-2016, 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 @@ -160,6 +160,7 @@ #define IBB_MODULE_RDY_EN BIT(7) /* REG_IBB_ENABLE_CTL */ #define IBB_ENABLE_CTL_MASK (BIT(7) | BIT(6)) #define IBB_ENABLE_CTL_SWIRE_RDY BIT(6) #define IBB_ENABLE_CTL_MODULE_EN BIT(7) Loading Loading @@ -243,6 +244,17 @@ enum qpnp_labibb_mode { QPNP_LABIBB_MAX_MODE, }; /** * IBB_SW_CONTROL_EN: Specifies IBB is enabled through software. * IBB_SW_CONTROL_DIS: Specifies IBB is disabled through software. * IBB_HW_CONTROL: Specifies IBB is controlled through SWIRE (hardware). */ enum ibb_mode { IBB_SW_CONTROL_EN, IBB_SW_CONTROL_DIS, IBB_HW_CONTROL, }; static const int ibb_discharge_resistor_plan[] = { 300, 64, Loading Loading @@ -606,6 +618,29 @@ static int qpnp_labibb_get_matching_idx(const char *val) return -EINVAL; } static int qpnp_ibb_set_mode(struct qpnp_labibb *labibb, enum ibb_mode mode) { int rc; u8 val; if (mode == IBB_SW_CONTROL_EN) val = IBB_ENABLE_CTL_MODULE_EN; else if (mode == IBB_HW_CONTROL) val = IBB_ENABLE_CTL_SWIRE_RDY; else if (mode == IBB_SW_CONTROL_DIS) val = 0; else return -EINVAL; rc = qpnp_labibb_masked_write(labibb, labibb->ibb_base + REG_IBB_ENABLE_CTL, IBB_ENABLE_CTL_MASK, val); if (rc) pr_err("Unable to configure IBB_ENABLE_CTL rc=%d\n", rc); return rc; } static int qpnp_lab_dt_init(struct qpnp_labibb *labibb, struct device_node *of_node) { Loading Loading @@ -847,9 +882,7 @@ static int qpnp_lab_dt_init(struct qpnp_labibb *labibb, } if (labibb->swire_control) { val = IBB_ENABLE_CTL_SWIRE_RDY; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_ENABLE_CTL, &val, 1); rc = qpnp_ibb_set_mode(labibb, IBB_HW_CONTROL); if (rc) pr_err("Unable to set SWIRE_RDY rc=%d\n", rc); } Loading Loading @@ -1026,12 +1059,9 @@ static int qpnp_labibb_regulator_ttw_mode_enter(struct qpnp_labibb *labibb) return rc; } val = IBB_ENABLE_CTL_SWIRE_RDY; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_ENABLE_CTL, &val, 1); rc = qpnp_ibb_set_mode(labibb, IBB_HW_CONTROL); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_IBB_ENABLE_CTL, rc); pr_err("Unable to set SWIRE_RDY rc = %d\n", rc); return rc; } labibb->in_ttw_mode = true; Loading Loading @@ -1082,16 +1112,6 @@ static int qpnp_labibb_regulator_ttw_mode_exit(struct qpnp_labibb *labibb) return rc; } val = 0; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_ENABLE_CTL, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_IBB_ENABLE_CTL, rc); return rc; } labibb->in_ttw_mode = false; return rc; } Loading @@ -1099,7 +1119,7 @@ static int qpnp_labibb_regulator_ttw_mode_exit(struct qpnp_labibb *labibb) static int qpnp_labibb_regulator_enable(struct qpnp_labibb *labibb) { int rc; u8 val = IBB_ENABLE_CTL_MODULE_EN; u8 val; int dly; int retries; bool enabled = false; Loading @@ -1113,12 +1133,9 @@ static int qpnp_labibb_regulator_enable(struct qpnp_labibb *labibb) } } rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_ENABLE_CTL, &val, 1); rc = qpnp_ibb_set_mode(labibb, IBB_SW_CONTROL_EN); if (rc) { pr_err("write register %x failed rc = %d\n", REG_IBB_ENABLE_CTL, rc); pr_err("Unable to set IBB_MODULE_EN rc = %d\n", rc); return rc; } Loading Loading @@ -1174,12 +1191,11 @@ static int qpnp_labibb_regulator_enable(struct qpnp_labibb *labibb) return 0; err_out: val = 0; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_ENABLE_CTL, &val, 1); if (rc) pr_err("write register %x failed rc = %d\n", REG_IBB_ENABLE_CTL, rc); rc = qpnp_ibb_set_mode(labibb, IBB_SW_CONTROL_DIS); if (rc) { pr_err("Unable to set IBB_MODULE_EN rc = %d\n", rc); return rc; } return -EINVAL; } Loading @@ -1191,12 +1207,28 @@ static int qpnp_labibb_regulator_disable(struct qpnp_labibb *labibb) int retries; bool disabled = false; val = 0; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_ENABLE_CTL, &val, 1); /* * When TTW mode is enabled and LABIBB regulators are disabled, it is * recommended not to disable IBB through IBB_ENABLE_CTL when switching * to SWIRE control on entering TTW mode. Hence, just enter TTW mode * and mark the regulators disabled. When we exit TTW mode, normal * mode settings will be restored anyways and regulators will be * enabled as before. */ if (labibb->ttw_en && !labibb->in_ttw_mode) { rc = qpnp_labibb_regulator_ttw_mode_enter(labibb); if (rc) { pr_err("write register %x failed rc = %d\n", REG_IBB_ENABLE_CTL, rc); pr_err("Error in entering TTW mode rc = %d\n", rc); return rc; } labibb->lab_vreg.vreg_enabled = 0; labibb->ibb_vreg.vreg_enabled = 0; return 0; } rc = qpnp_ibb_set_mode(labibb, IBB_SW_CONTROL_DIS); if (rc) { pr_err("Unable to set IBB_MODULE_EN rc = %d\n", rc); return rc; } Loading Loading @@ -1227,13 +1259,6 @@ static int qpnp_labibb_regulator_disable(struct qpnp_labibb *labibb) labibb->lab_vreg.vreg_enabled = 0; labibb->ibb_vreg.vreg_enabled = 0; if (labibb->ttw_en && !labibb->in_ttw_mode) { rc = qpnp_labibb_regulator_ttw_mode_enter(labibb); if (rc) { pr_err("Error in entering TTW mode rc = %d\n", rc); return rc; } } return 0; } Loading Loading @@ -1938,12 +1963,9 @@ static int qpnp_ibb_regulator_enable(struct regulator_dev *rdev) if (labibb->mode != QPNP_LABIBB_STANDALONE_MODE) return qpnp_labibb_regulator_enable(labibb); val = IBB_ENABLE_CTL_MODULE_EN; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_ENABLE_CTL, &val, 1); rc = qpnp_ibb_set_mode(labibb, IBB_SW_CONTROL_EN); if (rc) { pr_err("qpnp_ibb_regulator_enable write register %x failed rc = %d\n", REG_IBB_ENABLE_CTL, rc); pr_err("Unable to set IBB_MODULE_EN rc = %d\n", rc); return rc; } Loading @@ -1970,7 +1992,6 @@ static int qpnp_ibb_regulator_enable(struct regulator_dev *rdev) static int qpnp_ibb_regulator_disable(struct regulator_dev *rdev) { int rc; u8 val; struct qpnp_labibb *labibb = rdev_get_drvdata(rdev); if (labibb->ibb_vreg.vreg_enabled && !labibb->swire_control) { Loading @@ -1978,12 +1999,9 @@ static int qpnp_ibb_regulator_disable(struct regulator_dev *rdev) if (labibb->mode != QPNP_LABIBB_STANDALONE_MODE) return qpnp_labibb_regulator_disable(labibb); val = 0; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_ENABLE_CTL, &val, 1); rc = qpnp_ibb_set_mode(labibb, IBB_SW_CONTROL_DIS); if (rc) { pr_err("qpnp_ibb_regulator_enable write register %x failed rc = %d\n", REG_IBB_ENABLE_CTL, rc); pr_err("Unable to set IBB_MODULE_EN rc = %d\n", rc); return rc; } Loading Loading
drivers/regulator/qpnp-labibb-regulator.c +72 −54 Original line number Diff line number Diff line /* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2014-2016, 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 @@ -160,6 +160,7 @@ #define IBB_MODULE_RDY_EN BIT(7) /* REG_IBB_ENABLE_CTL */ #define IBB_ENABLE_CTL_MASK (BIT(7) | BIT(6)) #define IBB_ENABLE_CTL_SWIRE_RDY BIT(6) #define IBB_ENABLE_CTL_MODULE_EN BIT(7) Loading Loading @@ -243,6 +244,17 @@ enum qpnp_labibb_mode { QPNP_LABIBB_MAX_MODE, }; /** * IBB_SW_CONTROL_EN: Specifies IBB is enabled through software. * IBB_SW_CONTROL_DIS: Specifies IBB is disabled through software. * IBB_HW_CONTROL: Specifies IBB is controlled through SWIRE (hardware). */ enum ibb_mode { IBB_SW_CONTROL_EN, IBB_SW_CONTROL_DIS, IBB_HW_CONTROL, }; static const int ibb_discharge_resistor_plan[] = { 300, 64, Loading Loading @@ -606,6 +618,29 @@ static int qpnp_labibb_get_matching_idx(const char *val) return -EINVAL; } static int qpnp_ibb_set_mode(struct qpnp_labibb *labibb, enum ibb_mode mode) { int rc; u8 val; if (mode == IBB_SW_CONTROL_EN) val = IBB_ENABLE_CTL_MODULE_EN; else if (mode == IBB_HW_CONTROL) val = IBB_ENABLE_CTL_SWIRE_RDY; else if (mode == IBB_SW_CONTROL_DIS) val = 0; else return -EINVAL; rc = qpnp_labibb_masked_write(labibb, labibb->ibb_base + REG_IBB_ENABLE_CTL, IBB_ENABLE_CTL_MASK, val); if (rc) pr_err("Unable to configure IBB_ENABLE_CTL rc=%d\n", rc); return rc; } static int qpnp_lab_dt_init(struct qpnp_labibb *labibb, struct device_node *of_node) { Loading Loading @@ -847,9 +882,7 @@ static int qpnp_lab_dt_init(struct qpnp_labibb *labibb, } if (labibb->swire_control) { val = IBB_ENABLE_CTL_SWIRE_RDY; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_ENABLE_CTL, &val, 1); rc = qpnp_ibb_set_mode(labibb, IBB_HW_CONTROL); if (rc) pr_err("Unable to set SWIRE_RDY rc=%d\n", rc); } Loading Loading @@ -1026,12 +1059,9 @@ static int qpnp_labibb_regulator_ttw_mode_enter(struct qpnp_labibb *labibb) return rc; } val = IBB_ENABLE_CTL_SWIRE_RDY; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_ENABLE_CTL, &val, 1); rc = qpnp_ibb_set_mode(labibb, IBB_HW_CONTROL); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_IBB_ENABLE_CTL, rc); pr_err("Unable to set SWIRE_RDY rc = %d\n", rc); return rc; } labibb->in_ttw_mode = true; Loading Loading @@ -1082,16 +1112,6 @@ static int qpnp_labibb_regulator_ttw_mode_exit(struct qpnp_labibb *labibb) return rc; } val = 0; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_ENABLE_CTL, &val, 1); if (rc) { pr_err("qpnp_labibb_write register %x failed rc = %d\n", REG_IBB_ENABLE_CTL, rc); return rc; } labibb->in_ttw_mode = false; return rc; } Loading @@ -1099,7 +1119,7 @@ static int qpnp_labibb_regulator_ttw_mode_exit(struct qpnp_labibb *labibb) static int qpnp_labibb_regulator_enable(struct qpnp_labibb *labibb) { int rc; u8 val = IBB_ENABLE_CTL_MODULE_EN; u8 val; int dly; int retries; bool enabled = false; Loading @@ -1113,12 +1133,9 @@ static int qpnp_labibb_regulator_enable(struct qpnp_labibb *labibb) } } rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_ENABLE_CTL, &val, 1); rc = qpnp_ibb_set_mode(labibb, IBB_SW_CONTROL_EN); if (rc) { pr_err("write register %x failed rc = %d\n", REG_IBB_ENABLE_CTL, rc); pr_err("Unable to set IBB_MODULE_EN rc = %d\n", rc); return rc; } Loading Loading @@ -1174,12 +1191,11 @@ static int qpnp_labibb_regulator_enable(struct qpnp_labibb *labibb) return 0; err_out: val = 0; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_ENABLE_CTL, &val, 1); if (rc) pr_err("write register %x failed rc = %d\n", REG_IBB_ENABLE_CTL, rc); rc = qpnp_ibb_set_mode(labibb, IBB_SW_CONTROL_DIS); if (rc) { pr_err("Unable to set IBB_MODULE_EN rc = %d\n", rc); return rc; } return -EINVAL; } Loading @@ -1191,12 +1207,28 @@ static int qpnp_labibb_regulator_disable(struct qpnp_labibb *labibb) int retries; bool disabled = false; val = 0; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_ENABLE_CTL, &val, 1); /* * When TTW mode is enabled and LABIBB regulators are disabled, it is * recommended not to disable IBB through IBB_ENABLE_CTL when switching * to SWIRE control on entering TTW mode. Hence, just enter TTW mode * and mark the regulators disabled. When we exit TTW mode, normal * mode settings will be restored anyways and regulators will be * enabled as before. */ if (labibb->ttw_en && !labibb->in_ttw_mode) { rc = qpnp_labibb_regulator_ttw_mode_enter(labibb); if (rc) { pr_err("write register %x failed rc = %d\n", REG_IBB_ENABLE_CTL, rc); pr_err("Error in entering TTW mode rc = %d\n", rc); return rc; } labibb->lab_vreg.vreg_enabled = 0; labibb->ibb_vreg.vreg_enabled = 0; return 0; } rc = qpnp_ibb_set_mode(labibb, IBB_SW_CONTROL_DIS); if (rc) { pr_err("Unable to set IBB_MODULE_EN rc = %d\n", rc); return rc; } Loading Loading @@ -1227,13 +1259,6 @@ static int qpnp_labibb_regulator_disable(struct qpnp_labibb *labibb) labibb->lab_vreg.vreg_enabled = 0; labibb->ibb_vreg.vreg_enabled = 0; if (labibb->ttw_en && !labibb->in_ttw_mode) { rc = qpnp_labibb_regulator_ttw_mode_enter(labibb); if (rc) { pr_err("Error in entering TTW mode rc = %d\n", rc); return rc; } } return 0; } Loading Loading @@ -1938,12 +1963,9 @@ static int qpnp_ibb_regulator_enable(struct regulator_dev *rdev) if (labibb->mode != QPNP_LABIBB_STANDALONE_MODE) return qpnp_labibb_regulator_enable(labibb); val = IBB_ENABLE_CTL_MODULE_EN; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_ENABLE_CTL, &val, 1); rc = qpnp_ibb_set_mode(labibb, IBB_SW_CONTROL_EN); if (rc) { pr_err("qpnp_ibb_regulator_enable write register %x failed rc = %d\n", REG_IBB_ENABLE_CTL, rc); pr_err("Unable to set IBB_MODULE_EN rc = %d\n", rc); return rc; } Loading @@ -1970,7 +1992,6 @@ static int qpnp_ibb_regulator_enable(struct regulator_dev *rdev) static int qpnp_ibb_regulator_disable(struct regulator_dev *rdev) { int rc; u8 val; struct qpnp_labibb *labibb = rdev_get_drvdata(rdev); if (labibb->ibb_vreg.vreg_enabled && !labibb->swire_control) { Loading @@ -1978,12 +1999,9 @@ static int qpnp_ibb_regulator_disable(struct regulator_dev *rdev) if (labibb->mode != QPNP_LABIBB_STANDALONE_MODE) return qpnp_labibb_regulator_disable(labibb); val = 0; rc = qpnp_labibb_write(labibb, labibb->ibb_base + REG_IBB_ENABLE_CTL, &val, 1); rc = qpnp_ibb_set_mode(labibb, IBB_SW_CONTROL_DIS); if (rc) { pr_err("qpnp_ibb_regulator_enable write register %x failed rc = %d\n", REG_IBB_ENABLE_CTL, rc); pr_err("Unable to set IBB_MODULE_EN rc = %d\n", rc); return rc; } Loading