diff options
Diffstat (limited to 'sound/soc/codecs/da7213.c')
-rw-r--r-- | sound/soc/codecs/da7213.c | 102 |
1 files changed, 90 insertions, 12 deletions
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 925a03996db4..3e6ad996741b 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -19,6 +19,7 @@ #include <linux/module.h> #include <sound/pcm.h> #include <sound/pcm_params.h> +#include <linux/pm_runtime.h> #include <sound/soc.h> #include <sound/initval.h> #include <sound/tlv.h> @@ -807,6 +808,11 @@ static int da7213_dai_event(struct snd_soc_dapm_widget *w, static const struct snd_soc_dapm_widget da7213_dapm_widgets[] = { /* + * Power Supply + */ + SND_SOC_DAPM_REGULATOR_SUPPLY("VDDMIC", 0, 0), + + /* * Input & Output */ @@ -932,6 +938,9 @@ static const struct snd_soc_dapm_route da7213_audio_map[] = { /* Dest Connecting Widget source */ /* Input path */ + {"Mic Bias 1", NULL, "VDDMIC"}, + {"Mic Bias 2", NULL, "VDDMIC"}, + {"MIC1", NULL, "Mic Bias 1"}, {"MIC2", NULL, "Mic Bias 2"}, @@ -1334,10 +1343,10 @@ static int da7213_mute(struct snd_soc_dai *dai, int mute) #define DA7213_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) -static int da7213_set_dai_sysclk(struct snd_soc_dai *codec_dai, - int clk_id, unsigned int freq, int dir) +static int da7213_set_component_sysclk(struct snd_soc_component *component, + int clk_id, int source, + unsigned int freq, int dir) { - struct snd_soc_component *component = codec_dai->component; struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component); int ret = 0; @@ -1345,7 +1354,7 @@ static int da7213_set_dai_sysclk(struct snd_soc_dai *codec_dai, return 0; if (((freq < 5000000) && (freq != 32768)) || (freq > 54000000)) { - dev_err(codec_dai->dev, "Unsupported MCLK value %d\n", + dev_err(component->dev, "Unsupported MCLK value %d\n", freq); return -EINVAL; } @@ -1361,7 +1370,7 @@ static int da7213_set_dai_sysclk(struct snd_soc_dai *codec_dai, DA7213_PLL_MCLK_SQR_EN); break; default: - dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id); + dev_err(component->dev, "Unknown clock source %d\n", clk_id); return -EINVAL; } @@ -1371,7 +1380,7 @@ static int da7213_set_dai_sysclk(struct snd_soc_dai *codec_dai, freq = clk_round_rate(da7213->mclk, freq); ret = clk_set_rate(da7213->mclk, freq); if (ret) { - dev_err(codec_dai->dev, "Failed to set clock rate %d\n", + dev_err(component->dev, "Failed to set clock rate %d\n", freq); return ret; } @@ -1383,10 +1392,10 @@ static int da7213_set_dai_sysclk(struct snd_soc_dai *codec_dai, } /* Supported PLL input frequencies are 32KHz, 5MHz - 54MHz. */ -static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, - int source, unsigned int fref, unsigned int fout) +static int da7213_set_component_pll(struct snd_soc_component *component, + int pll_id, int source, + unsigned int fref, unsigned int fout) { - struct snd_soc_component *component = codec_dai->component; struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component); u8 pll_ctrl, indiv_bits, indiv; @@ -1498,8 +1507,6 @@ static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, static const struct snd_soc_dai_ops da7213_dai_ops = { .hw_params = da7213_hw_params, .set_fmt = da7213_set_dai_fmt, - .set_sysclk = da7213_set_dai_sysclk, - .set_pll = da7213_set_dai_pll, .digital_mute = da7213_mute, }; @@ -1571,6 +1578,7 @@ static int da7213_set_bias_level(struct snd_soc_component *component, #if defined(CONFIG_OF) /* DT */ static const struct of_device_id da7213_of_match[] = { + { .compatible = "dlg,da7212", }, { .compatible = "dlg,da7213", }, { } }; @@ -1690,6 +1698,8 @@ static int da7213_probe(struct snd_soc_component *component) { struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component); + pm_runtime_get_sync(component->dev); + /* Default to using ALC auto offset calibration mode. */ snd_soc_component_update_bits(component, DA7213_ALC_CTRL1, DA7213_ALC_CALIB_MODE_MAN, 0); @@ -1810,6 +1820,8 @@ static int da7213_probe(struct snd_soc_component *component) DA7213_DMIC_CLK_RATE_MASK, dmic_cfg); } + pm_runtime_put_sync(component->dev); + /* Check if MCLK provided */ da7213->mclk = devm_clk_get(component->dev, "mclk"); if (IS_ERR(da7213->mclk)) { @@ -1831,6 +1843,8 @@ static const struct snd_soc_component_driver soc_component_dev_da7213 = { .num_dapm_widgets = ARRAY_SIZE(da7213_dapm_widgets), .dapm_routes = da7213_audio_map, .num_dapm_routes = ARRAY_SIZE(da7213_audio_map), + .set_sysclk = da7213_set_component_sysclk, + .set_pll = da7213_set_component_pll, .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, @@ -1847,11 +1861,22 @@ static const struct regmap_config da7213_regmap_config = { .cache_type = REGCACHE_RBTREE, }; +static void da7213_power_off(void *data) +{ + struct da7213_priv *da7213 = data; + regulator_bulk_disable(DA7213_NUM_SUPPLIES, da7213->supplies); +} + +static const char *da7213_supply_names[DA7213_NUM_SUPPLIES] = { + [DA7213_SUPPLY_VDDA] = "VDDA", + [DA7213_SUPPLY_VDDIO] = "VDDIO", +}; + static int da7213_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct da7213_priv *da7213; - int ret; + int i, ret; da7213 = devm_kzalloc(&i2c->dev, sizeof(*da7213), GFP_KERNEL); if (!da7213) @@ -1859,6 +1884,25 @@ static int da7213_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, da7213); + /* Get required supplies */ + for (i = 0; i < DA7213_NUM_SUPPLIES; ++i) + da7213->supplies[i].supply = da7213_supply_names[i]; + + ret = devm_regulator_bulk_get(&i2c->dev, DA7213_NUM_SUPPLIES, + da7213->supplies); + if (ret) { + dev_err(&i2c->dev, "Failed to get supplies: %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(DA7213_NUM_SUPPLIES, da7213->supplies); + if (ret < 0) + return ret; + + ret = devm_add_action_or_reset(&i2c->dev, da7213_power_off, da7213); + if (ret < 0) + return ret; + da7213->regmap = devm_regmap_init_i2c(i2c, &da7213_regmap_config); if (IS_ERR(da7213->regmap)) { ret = PTR_ERR(da7213->regmap); @@ -1866,6 +1910,11 @@ static int da7213_i2c_probe(struct i2c_client *i2c, return ret; } + pm_runtime_set_autosuspend_delay(&i2c->dev, 100); + pm_runtime_use_autosuspend(&i2c->dev); + pm_runtime_set_active(&i2c->dev); + pm_runtime_enable(&i2c->dev); + ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_da7213, &da7213_dai, 1); if (ret < 0) { @@ -1875,6 +1924,34 @@ static int da7213_i2c_probe(struct i2c_client *i2c, return ret; } +static int __maybe_unused da7213_runtime_suspend(struct device *dev) +{ + struct da7213_priv *da7213 = dev_get_drvdata(dev); + + regcache_cache_only(da7213->regmap, true); + regcache_mark_dirty(da7213->regmap); + regulator_bulk_disable(DA7213_NUM_SUPPLIES, da7213->supplies); + + return 0; +} + +static int __maybe_unused da7213_runtime_resume(struct device *dev) +{ + struct da7213_priv *da7213 = dev_get_drvdata(dev); + int ret; + + ret = regulator_bulk_enable(DA7213_NUM_SUPPLIES, da7213->supplies); + if (ret < 0) + return ret; + regcache_cache_only(da7213->regmap, false); + regcache_sync(da7213->regmap); + return 0; +} + +static const struct dev_pm_ops da7213_pm = { + SET_RUNTIME_PM_OPS(da7213_runtime_suspend, da7213_runtime_resume, NULL) +}; + static const struct i2c_device_id da7213_i2c_id[] = { { "da7213", 0 }, { } @@ -1887,6 +1964,7 @@ static struct i2c_driver da7213_i2c_driver = { .name = "da7213", .of_match_table = of_match_ptr(da7213_of_match), .acpi_match_table = ACPI_PTR(da7213_acpi_match), + .pm = &da7213_pm, }, .probe = da7213_i2c_probe, .id_table = da7213_i2c_id, |