aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2012-08-08 12:52:44 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-08-09 14:34:28 -0400
commitcbd840dadeb03826b6cc074e38f380bbd4faaea5 (patch)
treee5de2e23bdd6afc14a6b9168f1fd5acdb3f02009 /sound/soc/codecs
parent28d528c8dbab5c6b3cf2fc4f0e91470a9a63dbc0 (diff)
ASoC: arizona: Implement OPCLK support
Arizona devices support two output system clocks. Provide support for configuring these via set_sysclk(). Once the clock API is more useful we should migrate over to that. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r--sound/soc/codecs/arizona.c66
-rw-r--r--sound/soc/codecs/arizona.h6
2 files changed, 70 insertions, 2 deletions
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index 5c9cacaf2d52..5e96a0a1669c 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -229,6 +229,69 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
229} 229}
230EXPORT_SYMBOL_GPL(arizona_out_ev); 230EXPORT_SYMBOL_GPL(arizona_out_ev);
231 231
232static unsigned int arizona_sysclk_48k_rates[] = {
233 6144000,
234 12288000,
235 22579200,
236 49152000,
237};
238
239static unsigned int arizona_sysclk_44k1_rates[] = {
240 5644800,
241 11289600,
242 24576000,
243 45158400,
244};
245
246static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
247 unsigned int freq)
248{
249 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
250 unsigned int reg;
251 unsigned int *rates;
252 int ref, div, refclk;
253
254 switch (clk) {
255 case ARIZONA_CLK_OPCLK:
256 reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
257 refclk = priv->sysclk;
258 break;
259 case ARIZONA_CLK_ASYNC_OPCLK:
260 reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
261 refclk = priv->asyncclk;
262 break;
263 default:
264 return -EINVAL;
265 }
266
267 if (refclk % 8000)
268 rates = arizona_sysclk_44k1_rates;
269 else
270 rates = arizona_sysclk_48k_rates;
271
272 for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) &&
273 rates[ref] <= refclk; ref++) {
274 div = 1;
275 while (rates[ref] / div >= freq && div < 32) {
276 if (rates[ref] / div == freq) {
277 dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
278 freq);
279 snd_soc_update_bits(codec, reg,
280 ARIZONA_OPCLK_DIV_MASK |
281 ARIZONA_OPCLK_SEL_MASK,
282 (div <<
283 ARIZONA_OPCLK_DIV_SHIFT) |
284 ref);
285 return 0;
286 }
287 div++;
288 }
289 }
290
291 dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
292 return -EINVAL;
293}
294
232int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, 295int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
233 int source, unsigned int freq, int dir) 296 int source, unsigned int freq, int dir)
234{ 297{
@@ -252,6 +315,9 @@ int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
252 reg = ARIZONA_ASYNC_CLOCK_1; 315 reg = ARIZONA_ASYNC_CLOCK_1;
253 clk = &priv->asyncclk; 316 clk = &priv->asyncclk;
254 break; 317 break;
318 case ARIZONA_CLK_OPCLK:
319 case ARIZONA_CLK_ASYNC_OPCLK:
320 return arizona_set_opclk(codec, clk_id, freq);
255 default: 321 default:
256 return -EINVAL; 322 return -EINVAL;
257 } 323 }
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h
index 59caca8865e8..eb66b52777c9 100644
--- a/sound/soc/codecs/arizona.h
+++ b/sound/soc/codecs/arizona.h
@@ -17,8 +17,10 @@
17 17
18#include <sound/soc.h> 18#include <sound/soc.h>
19 19
20#define ARIZONA_CLK_SYSCLK 1 20#define ARIZONA_CLK_SYSCLK 1
21#define ARIZONA_CLK_ASYNCCLK 2 21#define ARIZONA_CLK_ASYNCCLK 2
22#define ARIZONA_CLK_OPCLK 3
23#define ARIZONA_CLK_ASYNC_OPCLK 4
22 24
23#define ARIZONA_CLK_SRC_MCLK1 0x0 25#define ARIZONA_CLK_SRC_MCLK1 0x0
24#define ARIZONA_CLK_SRC_MCLK2 0x1 26#define ARIZONA_CLK_SRC_MCLK2 0x1