From 66b47fdb851924956b6e4696fb43a3496ae2c462 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 8 Jul 2010 11:25:43 +0900 Subject: ASoC: Implement WM8994 OPCLK support The WM8994 can output a clock derived from its internal SYSCLK, called OPCLK. The rate can be selected as a sysclk, with a division from the SYSCLK rate specified (multiplied by 10 since a division of 5.5 is supported) and the clock can be disabled by specifying a divisor of zero. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm8994.c | 23 +++++++++++++++++++++++ sound/soc/codecs/wm8994.h | 3 +++ 2 files changed, 26 insertions(+) diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index ed8be9d..c41cf47 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -2492,6 +2492,7 @@ static const struct snd_kcontrol_new aif3adc_mux = static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = { SND_SOC_DAPM_INPUT("DMIC1DAT"), SND_SOC_DAPM_INPUT("DMIC2DAT"), +SND_SOC_DAPM_INPUT("Clock"), SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), @@ -2966,11 +2967,14 @@ static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src, return 0; } +static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 }; + static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) { struct snd_soc_codec *codec = dai->codec; struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + int i; switch (dai->id) { case 1: @@ -3008,6 +3012,25 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, dev_dbg(dai->dev, "AIF%d using FLL2\n", dai->id); break; + case WM8994_SYSCLK_OPCLK: + /* Special case - a division (times 10) is given and + * no effect on main clocking. + */ + if (freq) { + for (i = 0; i < ARRAY_SIZE(opclk_divs); i++) + if (opclk_divs[i] == freq) + break; + if (i == ARRAY_SIZE(opclk_divs)) + return -EINVAL; + snd_soc_update_bits(codec, WM8994_CLOCKING_2, + WM8994_OPCLK_DIV_MASK, i); + snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_2, + WM8994_OPCLK_ENA, WM8994_OPCLK_ENA); + } else { + snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_2, + WM8994_OPCLK_ENA, 0); + } + default: return -EINVAL; } diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h index 7072dc5..2e0ca67 100644 --- a/sound/soc/codecs/wm8994.h +++ b/sound/soc/codecs/wm8994.h @@ -20,6 +20,9 @@ extern struct snd_soc_dai wm8994_dai[]; #define WM8994_SYSCLK_FLL1 3 #define WM8994_SYSCLK_FLL2 4 +/* OPCLK is also configured with set_dai_sysclk, specify division*10 as rate. */ +#define WM8994_SYSCLK_OPCLK 5 + #define WM8994_FLL1 1 #define WM8994_FLL2 2 -- cgit v1.1