diff --git a/asoc/codecs/swr-haptics.c b/asoc/codecs/swr-haptics.c index 20657d57200a..29681cef4f82 100644 --- a/asoc/codecs/swr-haptics.c +++ b/asoc/codecs/swr-haptics.c @@ -78,6 +78,9 @@ struct swr_haptics_dev { struct swr_port port; struct regulator *vdd; u32 enable_cnt; + struct regulator *hpwr_vreg; + u32 hpwr_voltage_mv; + bool hpwr_vreg_enabled; }; static bool swr_hap_volatile_register(struct device *dev, unsigned int reg) @@ -119,6 +122,51 @@ static bool swr_hap_writeable_register(struct device *dev, unsigned int reg) return 1; } +static int swr_hap_enable_hpwr_vreg(struct swr_haptics_dev *swr_hap, bool en) +{ + int rc; + + if (swr_hap->hpwr_vreg == NULL || swr_hap->hpwr_vreg_enabled == en) + return 0; + + if (en) { + rc = regulator_set_voltage(swr_hap->hpwr_vreg, + swr_hap->hpwr_voltage_mv * 1000, INT_MAX); + if (rc < 0) { + dev_err(swr_hap->dev, "%s: Set hpwr voltage failed, rc=%d\n", + __func__, rc); + return rc; + } + + rc = regulator_enable(swr_hap->hpwr_vreg); + if (rc < 0) { + dev_err(swr_hap->dev, "%s: Enable hpwr failed, rc=%d\n", + __func__, rc); + regulator_set_voltage(swr_hap->hpwr_vreg, 0, INT_MAX); + return rc; + } + } else { + rc = regulator_disable(swr_hap->hpwr_vreg); + if (rc < 0) { + dev_err(swr_hap->dev, "%s: Disable hpwr failed, rc=%d\n", + __func__, rc); + return rc; + } + + rc = regulator_set_voltage(swr_hap->hpwr_vreg, 0, INT_MAX); + if (rc < 0) { + dev_err(swr_hap->dev, "%s: Set hpwr voltage failed, rc=%d\n", + __func__, rc); + return rc; + } + } + + dev_dbg(swr_hap->dev, "%s: swr-haptics: %s hpwr_regulator\n", + __func__, en ? "enabled" : "disabled"); + swr_hap->hpwr_vreg_enabled = en; + return 0; +} + struct regmap_config swr_hap_regmap_config = { .reg_bits = 16, .val_bits = 8, @@ -175,6 +223,13 @@ static int hap_enable_swr_dac_port(struct snd_soc_dapm_widget *w, &ch_mask, &ch_rate, &num_ch, &port_type); break; case SND_SOC_DAPM_POST_PMU: + rc = swr_hap_enable_hpwr_vreg(swr_hap, true); + if (rc < 0) { + dev_err(swr_hap->dev, "%s: Enable hpwr_vreg failed, rc=%d\n", + __func__, rc); + return rc; + } + swr_slvdev_datapath_control(swr_hap->swr_slave, swr_hap->swr_slave->dev_num, true); /* trigger SWR play */ @@ -183,6 +238,9 @@ static int hap_enable_swr_dac_port(struct snd_soc_dapm_widget *w, if (rc) { dev_err(swr_hap->dev, "%s: Enable SWR_PLAY failed, rc=%d\n", __func__, rc); + swr_slvdev_datapath_control(swr_hap->swr_slave, + swr_hap->swr_slave->dev_num, false); + swr_hap_enable_hpwr_vreg(swr_hap, false); return rc; } break; @@ -195,6 +253,13 @@ static int hap_enable_swr_dac_port(struct snd_soc_dapm_widget *w, __func__, rc); return rc; } + + rc = swr_hap_enable_hpwr_vreg(swr_hap, false); + if (rc < 0) { + dev_err(swr_hap->dev, "%s: Disable hpwr_vreg failed, rc=%d\n", + __func__, rc); + return rc; + } break; case SND_SOC_DAPM_POST_PMD: swr_disconnect_port(swr_hap->swr_slave, &port_id, num_port, @@ -313,6 +378,7 @@ static int swr_haptics_parse_port_mapping(struct swr_device *sdev) static int swr_haptics_probe(struct swr_device *sdev) { struct swr_haptics_dev *swr_hap; + struct device_node *node = sdev->dev.of_node; int rc; u8 devnum; int retry = 5; @@ -343,6 +409,26 @@ static int swr_haptics_probe(struct swr_device *sdev) goto clean; } + if (of_find_property(node, "qcom,hpwr-supply", NULL)) { + swr_hap->hpwr_vreg = devm_regulator_get(swr_hap->dev, + "qcom,hpwr"); + if (IS_ERR(swr_hap->hpwr_vreg)) { + rc = PTR_ERR(swr_hap->hpwr_vreg); + if (rc != -EPROBE_DEFER) + dev_err(swr_hap->dev, "%s: Get qcom,hpwr-supply failed, rc=%d\n", + __func__, rc); + goto clean; + } + + rc = of_property_read_u32(node, "qcom,hpwr-voltage-mv", + &swr_hap->hpwr_voltage_mv); + if (rc < 0) { + dev_err(swr_hap->dev, "%s: Failed to read qcom,hpwr-voltage-mv, rc=%d\n", + __func__, rc); + goto clean; + } + } + rc = regulator_enable(swr_hap->vdd); if (rc < 0) { dev_err(swr_hap->dev, "%s: enable swr-slave-vdd failed, rc=%d\n", @@ -459,6 +545,15 @@ static int swr_haptics_device_down(struct swr_device *sdev) } else { swr_hap->enable_cnt = 0; } + + /* Disable HAP_PWR regulator */ + rc = swr_hap_enable_hpwr_vreg(swr_hap, false); + if (rc < 0) { + dev_err(swr_hap->dev, "Disable hpwr_vreg failed, rc=%d\n", + rc); + return rc; + } + return 0; }