input: misc: hbtp_input: Add digital regulator support

Add support for the digital regulator in hbtp_input driver.

Signed-off-by: Alex Sarraf <asarraf@codeaurora.org>
Change-Id: I315d4b4c985917e55823a3c3951f2bffb20b39e6
This commit is contained in:
Alex Sarraf 2015-09-16 15:51:50 -07:00 committed by David Keitel
parent d42befffb2
commit d42067104f
2 changed files with 139 additions and 51 deletions

View file

@ -12,17 +12,24 @@ Required properties:
Optional properties:
- vcc_ana-supply : Analog power supply needed to power device
- qcom,afe-load : AFE load in uA
- qcom,afe-vtg-min : AFE minimum voltage in uV
- qcom,afe-vtg-max : AFE maximum voltage in uV
- qcom,afe-load : AFE/Analog supply load in uA
- qcom,afe-vtg-min : AFE/Analog minimum voltage in uV
- qcom,afe-vtg-max : AFE/Analog maximum voltage in uV
- qcom,dig-load : Digital supply load in uA
- qcom,dig-vtg-min : Digital supply minimum voltage in uV
- qcom,dig-vtg-max : Digital supply maximum voltage in uV
Example:
&soc {
hbtp {
compatible = "qcom,hbtp-input";
vcc_ana-supply = <&pm8941_l18>;
qcom,afe-load = <150000>;
qcom,afe-vtg-min = <2700000>;
qcom,afe-vtg-max = <3300000>;
vcc_ana-supply = <&pm8941_l17>;
vcc_dig-supply = <&pm8950_l16>;
qcom,afe-load = <50000>;
qcom,afe-vtg-min = <2850000>;
qcom,afe-vtg-max = <2850000>;
qcom,dig-load = <15000>;
qcom,dig-vtg-min = <1800000>;
qcom,dig-vtg-max = <1800000>;
};
};

View file

@ -41,10 +41,15 @@ struct hbtp_data {
struct notifier_block fb_notif;
#endif
struct regulator *vcc_ana;
struct regulator *vcc_dig;
int afe_load_ua;
int afe_vtg_min_uv;
int afe_vtg_max_uv;
bool manage_afe_power;
int dig_load_ua;
int dig_vtg_min_uv;
int dig_vtg_max_uv;
bool manage_afe_power_ana;
bool manage_power_dig;
};
static struct hbtp_data *hbtp;
@ -204,40 +209,68 @@ static int reg_set_optimum_mode_check(struct regulator *reg, int load_uA)
static int hbtp_pdev_power_on(struct hbtp_data *hbtp, bool on)
{
int ret, error;
int ret;
if (!hbtp->vcc_ana) {
pr_err("%s: regulator is not available\n", __func__);
if (!hbtp->vcc_ana)
pr_err("%s: analog regulator is not available\n", __func__);
if (!hbtp->vcc_dig)
pr_err("%s: digital regulator is not available\n", __func__);
if (!hbtp->vcc_ana && !hbtp->vcc_dig) {
pr_err("%s: no regulators available\n", __func__);
return -EINVAL;
}
if (!on)
goto reg_off;
ret = reg_set_optimum_mode_check(hbtp->vcc_ana, hbtp->afe_load_ua);
if (ret < 0) {
pr_err("%s: Regulator vcc_ana set_opt failed rc=%d\n",
__func__, ret);
return -EINVAL;
}
if (hbtp->vcc_ana) {
ret = reg_set_optimum_mode_check(hbtp->vcc_ana,
hbtp->afe_load_ua);
if (ret < 0) {
pr_err("%s: Regulator vcc_ana set_opt failed rc=%d\n",
__func__, ret);
return ret;
}
ret = regulator_enable(hbtp->vcc_ana);
if (ret) {
pr_err("%s: Regulator vcc_ana enable failed rc=%d\n",
__func__, ret);
error = -EINVAL;
goto error_reg_en_vcc_ana;
ret = regulator_enable(hbtp->vcc_ana);
if (ret) {
pr_err("%s: Regulator vcc_ana enable failed rc=%d\n",
__func__, ret);
reg_set_optimum_mode_check(hbtp->vcc_ana, 0);
return ret;
}
}
if (hbtp->vcc_dig) {
ret = reg_set_optimum_mode_check(hbtp->vcc_dig,
hbtp->dig_load_ua);
if (ret < 0) {
pr_err("%s: Regulator vcc_dig set_opt failed rc=%d\n",
__func__, ret);
return ret;
}
ret = regulator_enable(hbtp->vcc_dig);
if (ret) {
pr_err("%s: Regulator vcc_dig enable failed rc=%d\n",
__func__, ret);
reg_set_optimum_mode_check(hbtp->vcc_dig, 0);
return ret;
}
}
return 0;
error_reg_en_vcc_ana:
reg_set_optimum_mode_check(hbtp->vcc_ana, 0);
return error;
reg_off:
reg_set_optimum_mode_check(hbtp->vcc_ana, 0);
regulator_disable(hbtp->vcc_ana);
if (hbtp->vcc_ana) {
reg_set_optimum_mode_check(hbtp->vcc_ana, 0);
regulator_disable(hbtp->vcc_ana);
}
if (hbtp->vcc_dig) {
reg_set_optimum_mode_check(hbtp->vcc_dig, 0);
regulator_disable(hbtp->vcc_dig);
}
return 0;
}
@ -387,9 +420,12 @@ static int hbtp_parse_dt(struct device *dev)
struct device_node *np = dev->of_node;
u32 temp_val;
if (of_find_property(np, "vcc_ana-supply", NULL)) {
hbtp->manage_afe_power = true;
if (of_find_property(np, "vcc_ana-supply", NULL))
hbtp->manage_afe_power_ana = true;
if (of_find_property(np, "vcc_dig-supply", NULL))
hbtp->manage_power_dig = true;
if (hbtp->manage_afe_power_ana) {
rc = of_property_read_u32(np, "qcom,afe-load", &temp_val);
if (!rc) {
hbtp->afe_load_ua = (int) temp_val;
@ -414,6 +450,31 @@ static int hbtp_parse_dt(struct device *dev)
return rc;
}
}
if (hbtp->manage_power_dig) {
rc = of_property_read_u32(np, "qcom,dig-load", &temp_val);
if (!rc) {
hbtp->dig_load_ua = (int) temp_val;
} else {
dev_err(dev, "Unable to read digital load\n");
return rc;
}
rc = of_property_read_u32(np, "qcom,dig-vtg-min", &temp_val);
if (!rc) {
hbtp->dig_vtg_min_uv = (int) temp_val;
} else {
dev_err(dev, "Unable to read digital min voltage\n");
return rc;
}
rc = of_property_read_u32(np, "qcom,dig-vtg-max", &temp_val);
if (!rc) {
hbtp->dig_vtg_max_uv = (int) temp_val;
} else {
dev_err(dev, "Unable to read digital max voltage\n");
return rc;
}
}
return 0;
}
@ -426,8 +487,8 @@ static int hbtp_parse_dt(struct device *dev)
static int hbtp_pdev_probe(struct platform_device *pdev)
{
int error, ret;
struct regulator *vcc_ana;
int error;
struct regulator *vcc_ana, *vcc_dig;
if (pdev->dev.of_node) {
error = hbtp_parse_dt(&pdev->dev);
@ -437,43 +498,63 @@ static int hbtp_pdev_probe(struct platform_device *pdev)
}
}
if (hbtp->manage_afe_power) {
if (hbtp->manage_afe_power_ana) {
vcc_ana = regulator_get(&pdev->dev, "vcc_ana");
if (IS_ERR(vcc_ana)) {
ret = PTR_ERR(vcc_ana);
error = PTR_ERR(vcc_ana);
pr_err("%s: regulator get failed vcc_ana rc=%d\n",
__func__, ret);
return -EINVAL;
__func__, error);
return error;
}
if (regulator_count_voltages(vcc_ana) > 0) {
ret = regulator_set_voltage(vcc_ana,
error = regulator_set_voltage(vcc_ana,
hbtp->afe_vtg_min_uv, hbtp->afe_vtg_max_uv);
if (ret) {
pr_err("%s: regulator set vtg failed rc=%d\n",
__func__, ret);
error = -EINVAL;
goto error_set_vtg_vcc_ana;
if (error) {
pr_err("%s: regulator set vtg failed vcc_ana rc=%d\n",
__func__, error);
regulator_put(vcc_ana);
return error;
}
}
hbtp->vcc_ana = vcc_ana;
}
if (hbtp->manage_power_dig) {
vcc_dig = regulator_get(&pdev->dev, "vcc_dig");
if (IS_ERR(vcc_dig)) {
error = PTR_ERR(vcc_dig);
pr_err("%s: regulator get failed vcc_dig rc=%d\n",
__func__, error);
return error;
}
if (regulator_count_voltages(vcc_dig) > 0) {
error = regulator_set_voltage(vcc_dig,
hbtp->dig_vtg_min_uv, hbtp->dig_vtg_max_uv);
if (error) {
pr_err("%s: regulator set vtg failed vcc_dig rc=%d\n",
__func__, error);
regulator_put(vcc_dig);
return error;
}
}
hbtp->vcc_dig = vcc_dig;
}
hbtp->pdev = pdev;
return 0;
error_set_vtg_vcc_ana:
regulator_put(vcc_ana);
return error;
};
}
static int hbtp_pdev_remove(struct platform_device *pdev)
{
if (hbtp->vcc_ana) {
if (hbtp->vcc_ana || hbtp->vcc_dig) {
hbtp_pdev_power_on(hbtp, false);
regulator_put(hbtp->vcc_ana);
if (hbtp->vcc_ana)
regulator_put(hbtp->vcc_ana);
if (hbtp->vcc_dig)
regulator_put(hbtp->vcc_dig);
}
return 0;