summaryrefslogtreecommitdiff
path: root/sound/soc/codecs/madera.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-01-28 16:26:57 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2020-01-28 16:26:57 -0800
commitfb95aae6e67c4e319a24b3eea32032d4246a5335 (patch)
treec310d68211634ef594d180fdd93844fec44de2fe /sound/soc/codecs/madera.c
parentbd2463ac7d7ec51d432f23bf0e893fb371a908cd (diff)
parent90fb04f890bcb7384b4d4c216dc2640b0a870df3 (diff)
Merge tag 'sound-5.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai: "As the diffstat shows we've had again a lot of works done for this cycle: the majority of changes are the continued componentization and code refactoring in ASoC, the tree-wide PCM API updates and cleanups and SOF updates while a few ASoC driver updates are seen, too. Here we go, some highlights: Core: - Finally y2038 support landed to ALSA ABI; some ioctls have been extended and lots of tricks were applied - Applying the new managed PCM buffer API to all drivers; the API itself was already merged in 5.5 - The already deprecated dimension support in ALSA control API is dropped completely now - Verification of ALSA control elements to catch API misuses ASoC: - Further code refactorings and moving things to the component level - Lots of updates and improvements on SOF / Intel drivers; now including common HDMI driver and SoundWire support - New driver support for Ingenic JZ4770, Mediatek MT6660, Qualcomm WCD934x and WSA881x, and Realtek RT700, RT711, RT715, RT1011, RT1015 and RT1308 HD-audio: - Improved ring-buffer communications using waitqueue - Drop the superfluous buffer preallocation on x86 Others: - Many code cleanups, mostly constifications over the whole tree - USB-audio: quirks for MOTU, Corsair Virtuoso, Line6 Helix - FireWire: code refactoring for oxfw and dice drivers" * tag 'sound-5.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (638 commits) ALSA: usb-audio: add quirks for Line6 Helix devices fw>=2.82 ALSA: hda: Add Clevo W65_67SB the power_save blacklist ASoC: soc-core: remove null_snd_soc_ops ASoC: soc-pcm: add soc_rtd_trigger() ASoC: soc-pcm: add soc_rtd_hw_free() ASoC: soc-pcm: add soc_rtd_hw_params() ASoC: soc-pcm: add soc_rtd_prepare() ASoC: soc-pcm: add soc_rtd_shutdown() ASoC: soc-pcm: add soc_rtd_startup() ASoC: rt1015: add rt1015 amplifier driver ASoC: madera: Correct some kernel doc ASoC: topology: fix soc_tplg_fe_link_create() - link->dobj initialization order ASoC: Intel: skl_hda_dsp_common: Fix global-out-of-bounds bug ASoC: madera: Correct DMIC only input hook ups ALSA: cs46xx: fix spelling mistake "to" -> "too" ALSA: hda - Add docking station support for Lenovo Thinkpad T420s ASoC: Add MediaTek MT6660 Speaker Amp Driver ASoC: dt-bindings: rt5645: add suppliers ASoC: max98090: fix deadlock in max98090_dapm_put_enum_double() ASoC: dapm: add snd_soc_dapm_put_enum_double_locked ...
Diffstat (limited to 'sound/soc/codecs/madera.c')
-rw-r--r--sound/soc/codecs/madera.c178
1 files changed, 163 insertions, 15 deletions
diff --git a/sound/soc/codecs/madera.c b/sound/soc/codecs/madera.c
index 52639811cc52..40de9d7811d1 100644
--- a/sound/soc/codecs/madera.c
+++ b/sound/soc/codecs/madera.c
@@ -163,6 +163,48 @@ static const int madera_dsp_bus_error_irqs[MADERA_MAX_ADSP] = {
MADERA_IRQ_DSP7_BUS_ERR,
};
+int madera_clk_ev(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct madera_priv *priv = snd_soc_component_get_drvdata(component);
+ struct madera *madera = priv->madera;
+ unsigned int val;
+ int clk_idx;
+ int ret;
+
+ ret = regmap_read(madera->regmap, w->reg, &val);
+ if (ret) {
+ dev_err(madera->dev, "Failed to check clock source: %d\n", ret);
+ return ret;
+ }
+
+ switch ((val & MADERA_SYSCLK_SRC_MASK) >> MADERA_SYSCLK_SRC_SHIFT) {
+ case MADERA_CLK_SRC_MCLK1:
+ clk_idx = MADERA_MCLK1;
+ break;
+ case MADERA_CLK_SRC_MCLK2:
+ clk_idx = MADERA_MCLK2;
+ break;
+ case MADERA_CLK_SRC_MCLK3:
+ clk_idx = MADERA_MCLK3;
+ break;
+ default:
+ return 0;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ return clk_prepare_enable(madera->mclk[clk_idx].clk);
+ case SND_SOC_DAPM_POST_PMD:
+ clk_disable_unprepare(madera->mclk[clk_idx].clk);
+ return 0;
+ default:
+ return 0;
+ }
+}
+EXPORT_SYMBOL_GPL(madera_clk_ev);
+
static void madera_spin_sysclk(struct madera_priv *priv)
{
struct madera *madera = priv->madera;
@@ -193,9 +235,16 @@ int madera_sysclk_ev(struct snd_soc_dapm_widget *w,
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct madera_priv *priv = snd_soc_component_get_drvdata(component);
- madera_spin_sysclk(priv);
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ case SND_SOC_DAPM_PRE_PMD:
+ madera_spin_sysclk(priv);
+ break;
+ default:
+ break;
+ }
- return 0;
+ return madera_clk_ev(w, kcontrol, event);
}
EXPORT_SYMBOL_GPL(madera_sysclk_ev);
@@ -526,6 +575,7 @@ int madera_out1_demux_put(struct snd_kcontrol *kcontrol,
usleep_range(2000, 3000); /* wait for wseq to complete */
/* change demux setting */
+ ret = 0;
if (madera->out_clamp[0])
ret = regmap_update_bits(madera->regmap,
MADERA_OUTPUT_ENABLES_1,
@@ -1162,7 +1212,9 @@ static const struct snd_soc_dapm_route madera_mono_routes[] = {
{ "OUT6R", NULL, "OUT6L" },
};
-int madera_init_outputs(struct snd_soc_component *component, int n_mono_routes)
+int madera_init_outputs(struct snd_soc_component *component,
+ const struct snd_soc_dapm_route *routes,
+ int n_mono_routes, int n_real)
{
struct snd_soc_dapm_context *dapm =
snd_soc_component_get_dapm(component);
@@ -1179,16 +1231,21 @@ int madera_init_outputs(struct snd_soc_component *component, int n_mono_routes)
n_mono_routes = MADERA_MAX_OUTPUT;
}
+ if (!routes)
+ routes = madera_mono_routes;
+
for (i = 0; i < n_mono_routes; i++) {
/* Default is 0 so noop with defaults */
if (pdata->out_mono[i]) {
val = MADERA_OUT1_MONO;
- snd_soc_dapm_add_routes(dapm,
- &madera_mono_routes[i], 1);
+ snd_soc_dapm_add_routes(dapm, &routes[i], 1);
} else {
val = 0;
}
+ if (i >= n_real)
+ continue;
+
regmap_update_bits(madera->regmap,
MADERA_OUTPUT_PATH_CONFIG_1L + (i * 8),
MADERA_OUT1_MONO, val);
@@ -3809,11 +3866,75 @@ static bool madera_set_fll_phase_integrator(struct madera_fll *fll,
return reg_change;
}
+static int madera_set_fll_clks_reg(struct madera_fll *fll, bool ena,
+ unsigned int reg, unsigned int mask,
+ unsigned int shift)
+{
+ struct madera *madera = fll->madera;
+ unsigned int src;
+ struct clk *clk;
+ int ret;
+
+ ret = regmap_read(madera->regmap, reg, &src);
+ if (ret != 0) {
+ madera_fll_err(fll, "Failed to read current source: %d\n",
+ ret);
+ return ret;
+ }
+
+ src = (src & mask) >> shift;
+
+ switch (src) {
+ case MADERA_FLL_SRC_MCLK1:
+ clk = madera->mclk[MADERA_MCLK1].clk;
+ break;
+ case MADERA_FLL_SRC_MCLK2:
+ clk = madera->mclk[MADERA_MCLK2].clk;
+ break;
+ case MADERA_FLL_SRC_MCLK3:
+ clk = madera->mclk[MADERA_MCLK3].clk;
+ break;
+ default:
+ return 0;
+ }
+
+ if (ena) {
+ return clk_prepare_enable(clk);
+ } else {
+ clk_disable_unprepare(clk);
+ return 0;
+ }
+}
+
+static inline int madera_set_fll_clks(struct madera_fll *fll, int base, bool ena)
+{
+ return madera_set_fll_clks_reg(fll, ena,
+ base + MADERA_FLL_CONTROL_6_OFFS,
+ MADERA_FLL1_REFCLK_SRC_MASK,
+ MADERA_FLL1_REFCLK_DIV_SHIFT);
+}
+
+static inline int madera_set_fllao_clks(struct madera_fll *fll, int base, bool ena)
+{
+ return madera_set_fll_clks_reg(fll, ena,
+ base + MADERA_FLLAO_CONTROL_6_OFFS,
+ MADERA_FLL_AO_REFCLK_SRC_MASK,
+ MADERA_FLL_AO_REFCLK_SRC_SHIFT);
+}
+
+static inline int madera_set_fllhj_clks(struct madera_fll *fll, int base, bool ena)
+{
+ return madera_set_fll_clks_reg(fll, ena,
+ base + MADERA_FLL_CONTROL_1_OFFS,
+ CS47L92_FLL1_REFCLK_SRC_MASK,
+ CS47L92_FLL1_REFCLK_SRC_SHIFT);
+}
+
static void madera_disable_fll(struct madera_fll *fll)
{
struct madera *madera = fll->madera;
unsigned int sync_base;
- bool change;
+ bool ref_change, sync_change;
switch (madera->type) {
case CS47L35:
@@ -3831,18 +3952,23 @@ static void madera_disable_fll(struct madera_fll *fll)
MADERA_FLL1_FREERUN, MADERA_FLL1_FREERUN);
regmap_update_bits_check(madera->regmap,
fll->base + MADERA_FLL_CONTROL_1_OFFS,
- MADERA_FLL1_ENA, 0, &change);
- regmap_update_bits(madera->regmap,
- sync_base + MADERA_FLL_SYNCHRONISER_1_OFFS,
- MADERA_FLL1_SYNC_ENA, 0);
+ MADERA_FLL1_ENA, 0, &ref_change);
+ regmap_update_bits_check(madera->regmap,
+ sync_base + MADERA_FLL_SYNCHRONISER_1_OFFS,
+ MADERA_FLL1_SYNC_ENA, 0, &sync_change);
regmap_update_bits(madera->regmap,
fll->base + MADERA_FLL_CONTROL_1_OFFS,
MADERA_FLL1_FREERUN, 0);
madera_wait_for_fll(fll, false);
- if (change)
+ if (sync_change)
+ madera_set_fll_clks(fll, sync_base, false);
+
+ if (ref_change) {
+ madera_set_fll_clks(fll, fll->base, false);
pm_runtime_put_autosuspend(madera->dev);
+ }
}
static int madera_enable_fll(struct madera_fll *fll)
@@ -3898,6 +4024,10 @@ static int madera_enable_fll(struct madera_fll *fll)
regmap_update_bits(fll->madera->regmap,
fll->base + MADERA_FLL_CONTROL_7_OFFS,
MADERA_FLL1_GAIN_MASK, 0);
+
+ if (sync_enabled > 0)
+ madera_set_fll_clks(fll, sync_base, false);
+ madera_set_fll_clks(fll, fll->base, false);
}
/* Apply SYNCCLK setting */
@@ -3976,11 +4106,15 @@ static int madera_enable_fll(struct madera_fll *fll)
if (!already_enabled)
pm_runtime_get_sync(madera->dev);
- if (have_sync)
+ if (have_sync) {
+ madera_set_fll_clks(fll, sync_base, true);
regmap_update_bits(madera->regmap,
sync_base + MADERA_FLL_SYNCHRONISER_1_OFFS,
MADERA_FLL1_SYNC_ENA,
MADERA_FLL1_SYNC_ENA);
+ }
+
+ madera_set_fll_clks(fll, fll->base, true);
regmap_update_bits(madera->regmap,
fll->base + MADERA_FLL_CONTROL_1_OFFS,
MADERA_FLL1_ENA, MADERA_FLL1_ENA);
@@ -4152,6 +4286,9 @@ static int madera_enable_fll_ao(struct madera_fll *fll,
fll->base + MADERA_FLLAO_CONTROL_1_OFFS,
MADERA_FLL_AO_HOLD, MADERA_FLL_AO_HOLD);
+ if (already_enabled)
+ madera_set_fllao_clks(fll, fll->base, false);
+
for (i = 0; i < patch_size; i++) {
val = patch[i].def;
@@ -4165,6 +4302,8 @@ static int madera_enable_fll_ao(struct madera_fll *fll,
regmap_write(madera->regmap, patch[i].reg, val);
}
+ madera_set_fllao_clks(fll, fll->base, true);
+
regmap_update_bits(madera->regmap,
fll->base + MADERA_FLLAO_CONTROL_1_OFFS,
MADERA_FLL_AO_ENA, MADERA_FLL_AO_ENA);
@@ -4208,8 +4347,10 @@ static int madera_disable_fll_ao(struct madera_fll *fll)
fll->base + MADERA_FLLAO_CONTROL_2_OFFS,
MADERA_FLL_AO_CTRL_UPD_MASK, 0);
- if (change)
+ if (change) {
+ madera_set_fllao_clks(fll, fll->base, false);
pm_runtime_put_autosuspend(madera->dev);
+ }
return 0;
}
@@ -4295,8 +4436,10 @@ static int madera_fllhj_disable(struct madera_fll *fll)
fll->base + MADERA_FLL_CONTROL_2_OFFS,
MADERA_FLL1_CTRL_UPD_MASK, 0);
- if (change)
+ if (change) {
+ madera_set_fllhj_clks(fll, fll->base, false);
pm_runtime_put_autosuspend(madera->dev);
+ }
return 0;
}
@@ -4468,6 +4611,9 @@ static int madera_fllhj_enable(struct madera_fll *fll)
MADERA_FLL1_HOLD_MASK,
MADERA_FLL1_HOLD_MASK);
+ if (already_enabled)
+ madera_set_fllhj_clks(fll, fll->base, false);
+
/* Apply refclk */
ret = madera_fllhj_apply(fll, fll->ref_freq);
if (ret) {
@@ -4479,6 +4625,8 @@ static int madera_fllhj_enable(struct madera_fll *fll)
CS47L92_FLL1_REFCLK_SRC_MASK,
fll->ref_src << CS47L92_FLL1_REFCLK_SRC_SHIFT);
+ madera_set_fllhj_clks(fll, fll->base, true);
+
regmap_update_bits(madera->regmap,
fll->base + MADERA_FLL_CONTROL_1_OFFS,
MADERA_FLL1_ENA_MASK,
@@ -4566,7 +4714,7 @@ EXPORT_SYMBOL_GPL(madera_fllhj_set_refclk);
*
* @component: Device to configure
* @output: Output number
- * @diff: True to set the output to differential mode
+ * @differential: True to set the output to differential mode
*
* Some systems use external analogue switches to connect more
* analogue devices to the CODEC than are supported by the device. In