diff --git a/asoc/codecs/swr-haptics.c b/asoc/codecs/swr-haptics.c index c4a433fcfed3..4b2757466771 100644 --- a/asoc/codecs/swr-haptics.c +++ b/asoc/codecs/swr-haptics.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +42,14 @@ #define SWR_HAP_REG_MAX (SWR_HAP_ACCESS_BASE + 0xff) +enum pmic_type { + PM8350B = 1, +}; + +enum { + HAP_SSR_RECOVERY = BIT(0), +}; + static struct reg_default swr_hap_reg_defaults[] = { {FIFO_WR_READY_REG, 1}, {NUM_PAT_SMPL_REG, 8}, @@ -76,12 +85,14 @@ struct swr_haptics_dev { struct snd_soc_component *component; struct regmap *regmap; struct swr_port port; - struct regulator *vdd; - u32 enable_cnt; + struct regulator *slave_vdd; struct regulator *hpwr_vreg; u32 hpwr_voltage_mv; + bool slave_enabled; bool hpwr_vreg_enabled; + bool ssr_recovery; u8 vmax; + u8 flags; }; static bool swr_hap_volatile_register(struct device *dev, unsigned int reg) @@ -168,6 +179,44 @@ static int swr_hap_enable_hpwr_vreg(struct swr_haptics_dev *swr_hap, bool en) return 0; } +static int swr_haptics_slave_enable(struct swr_haptics_dev *swr_hap) +{ + int rc; + + if (swr_hap->slave_enabled) + return 0; + + rc = regulator_enable(swr_hap->slave_vdd); + if (rc < 0) { + dev_err(swr_hap->dev, "%s: enable swr-slave-vdd failed, rc=%d\n", + __func__, rc); + return rc; + } + + dev_dbg(swr_hap->dev, "%s: enable swr-slave-vdd success\n", __func__); + swr_hap->slave_enabled = true; + return 0; +} + +static int swr_haptics_slave_disable(struct swr_haptics_dev *swr_hap) +{ + int rc; + + if (!swr_hap->slave_enabled) + return 0; + + rc = regulator_disable(swr_hap->slave_vdd); + if (rc < 0) { + dev_err(swr_hap->dev, "%s: disable swr-slave-vdd failed, rc=%d\n", + __func__, rc); + return rc; + } + + dev_dbg(swr_hap->dev, "%s: disable swr-slave-vdd success\n", __func__); + swr_hap->slave_enabled = false; + return 0; +} + struct regmap_config swr_hap_regmap_config = { .reg_bits = 16, .val_bits = 8, @@ -219,6 +268,14 @@ static int hap_enable_swr_dac_port(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: + /* If SSR ever happened, toggle swr-slave-vdd for HW recovery */ + if ((swr_hap->flags & HAP_SSR_RECOVERY) + && swr_hap->ssr_recovery) { + swr_haptics_slave_disable(swr_hap); + swr_haptics_slave_enable(swr_hap); + swr_hap->ssr_recovery = false; + } + rc = regmap_write(swr_hap->regmap, SWR_VMAX_REG, swr_hap->vmax); if (rc) { dev_err(swr_hap->dev, "%s: SWR_VMAX update failed, rc=%d\n", @@ -426,6 +483,7 @@ static int swr_haptics_probe(struct swr_device *sdev) struct device_node *node = sdev->dev.of_node; int rc; u8 devnum; + u32 pmic_type; int retry = 5; swr_hap = devm_kzalloc(&sdev->dev, @@ -437,8 +495,11 @@ static int swr_haptics_probe(struct swr_device *sdev) swr_hap->vmax = 100; swr_hap->swr_slave = sdev; swr_hap->dev = &sdev->dev; + pmic_type = (uintptr_t)of_device_get_match_data(swr_hap->dev); + if (pmic_type == PM8350B) + swr_hap->flags |= HAP_SSR_RECOVERY; + swr_set_dev_data(sdev, swr_hap); - swr_hap->enable_cnt = 0; rc = swr_haptics_parse_port_mapping(sdev); if (rc < 0) { @@ -447,9 +508,9 @@ static int swr_haptics_probe(struct swr_device *sdev) goto clean; } - swr_hap->vdd = devm_regulator_get(swr_hap->dev, "swr-slave"); - if (IS_ERR(swr_hap->vdd)) { - rc = PTR_ERR(swr_hap->vdd); + swr_hap->slave_vdd = devm_regulator_get(swr_hap->dev, "swr-slave"); + if (IS_ERR(swr_hap->slave_vdd)) { + rc = PTR_ERR(swr_hap->slave_vdd); if (rc != -EPROBE_DEFER) dev_err(swr_hap->dev, "%s: get swr-slave-supply failed, rc=%d\n", __func__, rc); @@ -476,7 +537,7 @@ static int swr_haptics_probe(struct swr_device *sdev) } } - rc = regulator_enable(swr_hap->vdd); + rc = swr_haptics_slave_enable(swr_hap); if (rc < 0) { dev_err(swr_hap->dev, "%s: enable swr-slave-vdd failed, rc=%d\n", __func__, rc); @@ -492,7 +553,7 @@ static int swr_haptics_probe(struct swr_device *sdev) dev_err(swr_hap->dev, "%s: failed to get devnum for swr-haptics, rc=%d\n", __func__, rc); rc = -EPROBE_DEFER; - goto clean; + goto dev_err; } sdev->dev_num = devnum; @@ -514,7 +575,7 @@ static int swr_haptics_probe(struct swr_device *sdev) return 0; dev_err: - regulator_disable(swr_hap->vdd); + swr_haptics_slave_disable(swr_hap); swr_remove_device(sdev); clean: swr_set_dev_data(sdev, NULL); @@ -533,7 +594,7 @@ static int swr_haptics_remove(struct swr_device *sdev) goto clean; } - rc = regulator_disable(swr_hap->vdd); + rc = swr_haptics_slave_disable(swr_hap); if (rc < 0) { dev_err(swr_hap->dev, "%s: disable swr-slave failed, rc=%d\n", __func__, rc); @@ -548,7 +609,6 @@ clean: static int swr_haptics_device_up(struct swr_device *sdev) { struct swr_haptics_dev *swr_hap; - int rc; swr_hap = swr_get_dev_data(sdev); if (!swr_hap) { @@ -556,17 +616,11 @@ static int swr_haptics_device_up(struct swr_device *sdev) return -ENODEV; } - /* Take SWR slave out of reset */ - rc = regulator_enable(swr_hap->vdd); - if (rc < 0) { - dev_err(swr_hap->dev, "%s: enable swr-slave failed, rc=%d\n", - __func__, rc); - return rc; - } else { - swr_hap->enable_cnt++; - } + if (swr_hap->flags & HAP_SSR_RECOVERY) + swr_hap->ssr_recovery = true; - return 0; + /* Take SWR slave out of reset */ + return swr_haptics_slave_enable(swr_hap); } static int swr_haptics_device_down(struct swr_device *sdev) @@ -579,20 +633,6 @@ static int swr_haptics_device_down(struct swr_device *sdev) return -ENODEV; } - /* Put SWR slave into reset */ - if (swr_hap->enable_cnt > 0) { - rc = regulator_disable(swr_hap->vdd); - if (rc < 0) { - dev_err(swr_hap->dev, "%s: disable swr-slave failed, rc=%d\n", - __func__, rc); - return rc; - } else { - swr_hap->enable_cnt--; - } - } else { - swr_hap->enable_cnt = 0; - } - /* Disable HAP_PWR regulator */ rc = swr_hap_enable_hpwr_vreg(swr_hap, false); if (rc < 0) { @@ -601,7 +641,8 @@ static int swr_haptics_device_down(struct swr_device *sdev) return rc; } - return 0; + /* Put SWR slave into reset */ + return swr_haptics_slave_disable(swr_hap); } static int swr_haptics_suspend(struct device *dev) @@ -635,8 +676,14 @@ static int swr_haptics_resume(struct device *dev) } static const struct of_device_id swr_haptics_match_table[] = { - { .compatible = "qcom,swr-haptics", }, - { .compatible = "qcom,pm8350b-swr-haptics", }, + { + .compatible = "qcom,swr-haptics", + .data = NULL, + }, + { + .compatible = "qcom,pm8350b-swr-haptics", + .data = (void *)PM8350B, + }, { }, };