blob: 901b53e1d7bc5161bf0c51233742e94a6b71f467 [file] [log] [blame]
Mark Brown07ed8732012-06-18 21:08:44 +01001/*
2 * arizona.c - Wolfson Arizona class device shared support
3 *
4 * Copyright 2012 Wolfson Microelectronics plc
5 *
6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/gcd.h>
14#include <linux/module.h>
15#include <linux/pm_runtime.h>
16#include <sound/pcm.h>
17#include <sound/pcm_params.h>
18#include <sound/tlv.h>
19
20#include <linux/mfd/arizona/core.h>
21#include <linux/mfd/arizona/registers.h>
22
23#include "arizona.h"
24
25#define ARIZONA_AIF_BCLK_CTRL 0x00
26#define ARIZONA_AIF_TX_PIN_CTRL 0x01
27#define ARIZONA_AIF_RX_PIN_CTRL 0x02
28#define ARIZONA_AIF_RATE_CTRL 0x03
29#define ARIZONA_AIF_FORMAT 0x04
30#define ARIZONA_AIF_TX_BCLK_RATE 0x05
31#define ARIZONA_AIF_RX_BCLK_RATE 0x06
32#define ARIZONA_AIF_FRAME_CTRL_1 0x07
33#define ARIZONA_AIF_FRAME_CTRL_2 0x08
34#define ARIZONA_AIF_FRAME_CTRL_3 0x09
35#define ARIZONA_AIF_FRAME_CTRL_4 0x0A
36#define ARIZONA_AIF_FRAME_CTRL_5 0x0B
37#define ARIZONA_AIF_FRAME_CTRL_6 0x0C
38#define ARIZONA_AIF_FRAME_CTRL_7 0x0D
39#define ARIZONA_AIF_FRAME_CTRL_8 0x0E
40#define ARIZONA_AIF_FRAME_CTRL_9 0x0F
41#define ARIZONA_AIF_FRAME_CTRL_10 0x10
42#define ARIZONA_AIF_FRAME_CTRL_11 0x11
43#define ARIZONA_AIF_FRAME_CTRL_12 0x12
44#define ARIZONA_AIF_FRAME_CTRL_13 0x13
45#define ARIZONA_AIF_FRAME_CTRL_14 0x14
46#define ARIZONA_AIF_FRAME_CTRL_15 0x15
47#define ARIZONA_AIF_FRAME_CTRL_16 0x16
48#define ARIZONA_AIF_FRAME_CTRL_17 0x17
49#define ARIZONA_AIF_FRAME_CTRL_18 0x18
50#define ARIZONA_AIF_TX_ENABLES 0x19
51#define ARIZONA_AIF_RX_ENABLES 0x1A
52#define ARIZONA_AIF_FORCE_WRITE 0x1B
53
54#define arizona_fll_err(_fll, fmt, ...) \
55 dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
56#define arizona_fll_warn(_fll, fmt, ...) \
57 dev_warn(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
58#define arizona_fll_dbg(_fll, fmt, ...) \
59 dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
60
61#define arizona_aif_err(_dai, fmt, ...) \
62 dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
63#define arizona_aif_warn(_dai, fmt, ...) \
64 dev_warn(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
65#define arizona_aif_dbg(_dai, fmt, ...) \
66 dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
67
68const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
69 "None",
70 "Tone Generator 1",
71 "Tone Generator 2",
72 "Haptics",
73 "AEC",
74 "Mic Mute Mixer",
75 "Noise Generator",
76 "IN1L",
77 "IN1R",
78 "IN2L",
79 "IN2R",
80 "IN3L",
81 "IN3R",
82 "AIF1RX1",
83 "AIF1RX2",
84 "AIF1RX3",
85 "AIF1RX4",
86 "AIF1RX5",
87 "AIF1RX6",
88 "AIF1RX7",
89 "AIF1RX8",
90 "AIF2RX1",
91 "AIF2RX2",
92 "AIF3RX1",
93 "AIF3RX2",
94 "SLIMRX1",
95 "SLIMRX2",
96 "SLIMRX3",
97 "SLIMRX4",
98 "SLIMRX5",
99 "SLIMRX6",
100 "SLIMRX7",
101 "SLIMRX8",
102 "EQ1",
103 "EQ2",
104 "EQ3",
105 "EQ4",
106 "DRC1L",
107 "DRC1R",
108 "DRC2L",
109 "DRC2R",
110 "LHPF1",
111 "LHPF2",
112 "LHPF3",
113 "LHPF4",
114 "DSP1.1",
115 "DSP1.2",
116 "DSP1.3",
117 "DSP1.4",
118 "DSP1.5",
119 "DSP1.6",
120 "ASRC1L",
121 "ASRC1R",
122 "ASRC2L",
123 "ASRC2R",
124};
125EXPORT_SYMBOL_GPL(arizona_mixer_texts);
126
127int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
128 0x00, /* None */
129 0x04, /* Tone */
130 0x05,
131 0x06, /* Haptics */
132 0x08, /* AEC */
133 0x0c, /* Noise mixer */
134 0x0d, /* Comfort noise */
135 0x10, /* IN1L */
136 0x11,
137 0x12,
138 0x13,
139 0x14,
140 0x15,
141 0x20, /* AIF1RX1 */
142 0x21,
143 0x22,
144 0x23,
145 0x24,
146 0x25,
147 0x26,
148 0x27,
149 0x28, /* AIF2RX1 */
150 0x29,
151 0x30, /* AIF3RX1 */
152 0x31,
153 0x38, /* SLIMRX1 */
154 0x39,
155 0x3a,
156 0x3b,
157 0x3c,
158 0x3d,
159 0x3e,
160 0x3f,
161 0x50, /* EQ1 */
162 0x51,
163 0x52,
164 0x53,
165 0x58, /* DRC1L */
166 0x59,
167 0x5a,
168 0x5b,
169 0x60, /* LHPF1 */
170 0x61,
171 0x62,
172 0x63,
173 0x68, /* DSP1.1 */
174 0x69,
175 0x6a,
176 0x6b,
177 0x6c,
178 0x6d,
179 0x90, /* ASRC1L */
180 0x91,
181 0x92,
182 0x93,
183};
184EXPORT_SYMBOL_GPL(arizona_mixer_values);
185
186const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
187EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
188
189static const char *arizona_lhpf_mode_text[] = {
190 "Low-pass", "High-pass"
191};
192
193const struct soc_enum arizona_lhpf1_mode =
194 SOC_ENUM_SINGLE(ARIZONA_HPLPF1_1, ARIZONA_LHPF1_MODE_SHIFT, 2,
195 arizona_lhpf_mode_text);
196EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
197
198const struct soc_enum arizona_lhpf2_mode =
199 SOC_ENUM_SINGLE(ARIZONA_HPLPF2_1, ARIZONA_LHPF2_MODE_SHIFT, 2,
200 arizona_lhpf_mode_text);
201EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
202
203const struct soc_enum arizona_lhpf3_mode =
204 SOC_ENUM_SINGLE(ARIZONA_HPLPF3_1, ARIZONA_LHPF3_MODE_SHIFT, 2,
205 arizona_lhpf_mode_text);
206EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
207
208const struct soc_enum arizona_lhpf4_mode =
209 SOC_ENUM_SINGLE(ARIZONA_HPLPF4_1, ARIZONA_LHPF4_MODE_SHIFT, 2,
210 arizona_lhpf_mode_text);
211EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
212
213int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
214 int event)
215{
216 return 0;
217}
218EXPORT_SYMBOL_GPL(arizona_in_ev);
219
220int arizona_out_ev(struct snd_soc_dapm_widget *w,
221 struct snd_kcontrol *kcontrol,
222 int event)
223{
224 return 0;
225}
226EXPORT_SYMBOL_GPL(arizona_out_ev);
227
228int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
229 int source, unsigned int freq, int dir)
230{
231 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
232 struct arizona *arizona = priv->arizona;
233 char *name;
234 unsigned int reg;
235 unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
236 unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
237 unsigned int *clk;
238
239 switch (clk_id) {
240 case ARIZONA_CLK_SYSCLK:
241 name = "SYSCLK";
242 reg = ARIZONA_SYSTEM_CLOCK_1;
243 clk = &priv->sysclk;
244 mask |= ARIZONA_SYSCLK_FRAC;
245 break;
246 case ARIZONA_CLK_ASYNCCLK:
247 name = "ASYNCCLK";
248 reg = ARIZONA_ASYNC_CLOCK_1;
249 clk = &priv->asyncclk;
250 break;
251 default:
252 return -EINVAL;
253 }
254
255 switch (freq) {
256 case 5644800:
257 case 6144000:
258 break;
259 case 11289600:
260 case 12288000:
261 val |= 1 << ARIZONA_SYSCLK_FREQ_SHIFT;
262 break;
263 case 22579200:
264 case 24576000:
265 val |= 2 << ARIZONA_SYSCLK_FREQ_SHIFT;
266 break;
267 case 45158400:
268 case 49152000:
269 val |= 3 << ARIZONA_SYSCLK_FREQ_SHIFT;
270 break;
271 default:
272 return -EINVAL;
273 }
274
275 *clk = freq;
276
277 if (freq % 6144000)
278 val |= ARIZONA_SYSCLK_FRAC;
279
280 dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
281
282 return regmap_update_bits(arizona->regmap, reg, mask, val);
283}
284EXPORT_SYMBOL_GPL(arizona_set_sysclk);
285
286static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
287{
288 struct snd_soc_codec *codec = dai->codec;
289 int lrclk, bclk, mode, base;
290
291 base = dai->driver->base;
292
293 lrclk = 0;
294 bclk = 0;
295
296 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
297 case SND_SOC_DAIFMT_DSP_A:
298 mode = 0;
299 break;
300 case SND_SOC_DAIFMT_DSP_B:
301 mode = 1;
302 break;
303 case SND_SOC_DAIFMT_I2S:
304 mode = 2;
305 break;
306 case SND_SOC_DAIFMT_LEFT_J:
307 mode = 3;
308 break;
309 default:
310 arizona_aif_err(dai, "Unsupported DAI format %d\n",
311 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
312 return -EINVAL;
313 }
314
315 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
316 case SND_SOC_DAIFMT_CBS_CFS:
317 break;
318 case SND_SOC_DAIFMT_CBS_CFM:
319 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
320 break;
321 case SND_SOC_DAIFMT_CBM_CFS:
322 bclk |= ARIZONA_AIF1_BCLK_MSTR;
323 break;
324 case SND_SOC_DAIFMT_CBM_CFM:
325 bclk |= ARIZONA_AIF1_BCLK_MSTR;
326 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
327 break;
328 default:
329 arizona_aif_err(dai, "Unsupported master mode %d\n",
330 fmt & SND_SOC_DAIFMT_MASTER_MASK);
331 return -EINVAL;
332 }
333
334 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
335 case SND_SOC_DAIFMT_NB_NF:
336 break;
337 case SND_SOC_DAIFMT_IB_IF:
338 bclk |= ARIZONA_AIF1_BCLK_INV;
339 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
340 break;
341 case SND_SOC_DAIFMT_IB_NF:
342 bclk |= ARIZONA_AIF1_BCLK_INV;
343 break;
344 case SND_SOC_DAIFMT_NB_IF:
345 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
346 break;
347 default:
348 return -EINVAL;
349 }
350
351 snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
352 ARIZONA_AIF1_BCLK_INV | ARIZONA_AIF1_BCLK_MSTR,
353 bclk);
354 snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_PIN_CTRL,
355 ARIZONA_AIF1TX_LRCLK_INV |
356 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
357 snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_PIN_CTRL,
358 ARIZONA_AIF1RX_LRCLK_INV |
359 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
360 snd_soc_update_bits(codec, base + ARIZONA_AIF_FORMAT,
361 ARIZONA_AIF1_FMT_MASK, mode);
362
363 return 0;
364}
365
Mark Brown949e6bc2012-07-04 18:58:04 +0100366static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100367 -1,
368 48000,
369 64000,
370 96000,
371 128000,
372 192000,
373 256000,
374 384000,
375 512000,
376 768000,
377 1024000,
378 1536000,
379 2048000,
380 3072000,
381 4096000,
382 6144000,
383 8192000,
384 12288000,
385 24576000,
386};
387
Mark Brown5b2eec32012-07-04 17:32:05 +0100388static const unsigned int arizona_48k_rates[] = {
389 12000,
390 24000,
391 48000,
392 96000,
393 192000,
394 384000,
395 768000,
396 4000,
397 8000,
398 16000,
399 32000,
400 64000,
401 128000,
402 256000,
403 512000,
404};
405
406static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = {
407 .count = ARRAY_SIZE(arizona_48k_rates),
408 .list = arizona_48k_rates,
409};
410
Mark Brown949e6bc2012-07-04 18:58:04 +0100411static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100412 -1,
413 44100,
414 58800,
415 88200,
416 117600,
417 177640,
418 235200,
419 352800,
420 470400,
421 705600,
422 940800,
423 1411200,
424 1881600,
425 2882400,
426 3763200,
427 5644800,
428 7526400,
429 11289600,
430 22579200,
431};
432
Mark Brown5b2eec32012-07-04 17:32:05 +0100433static const unsigned int arizona_44k1_rates[] = {
434 11025,
435 22050,
436 44100,
437 88200,
438 176400,
439 352800,
440 705600,
441};
442
443static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = {
444 .count = ARRAY_SIZE(arizona_44k1_rates),
445 .list = arizona_44k1_rates,
446};
447
Mark Brown07ed8732012-06-18 21:08:44 +0100448static int arizona_sr_vals[] = {
449 0,
450 12000,
451 24000,
452 48000,
453 96000,
454 192000,
455 384000,
456 768000,
457 0,
458 11025,
459 22050,
460 44100,
461 88200,
462 176400,
463 352800,
464 705600,
465 4000,
466 8000,
467 16000,
468 32000,
469 64000,
470 128000,
471 256000,
472 512000,
473};
474
Mark Brown5b2eec32012-07-04 17:32:05 +0100475static int arizona_startup(struct snd_pcm_substream *substream,
476 struct snd_soc_dai *dai)
477{
478 struct snd_soc_codec *codec = dai->codec;
479 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
480 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
481 const struct snd_pcm_hw_constraint_list *constraint;
482 unsigned int base_rate;
483
484 switch (dai_priv->clk) {
485 case ARIZONA_CLK_SYSCLK:
486 base_rate = priv->sysclk;
487 break;
488 case ARIZONA_CLK_ASYNCCLK:
489 base_rate = priv->asyncclk;
490 break;
491 default:
492 return 0;
493 }
494
495 if (base_rate % 8000)
496 constraint = &arizona_44k1_constraint;
497 else
498 constraint = &arizona_48k_constraint;
499
500 return snd_pcm_hw_constraint_list(substream->runtime, 0,
501 SNDRV_PCM_HW_PARAM_RATE,
502 constraint);
503}
504
Mark Brown07ed8732012-06-18 21:08:44 +0100505static int arizona_hw_params(struct snd_pcm_substream *substream,
506 struct snd_pcm_hw_params *params,
507 struct snd_soc_dai *dai)
508{
509 struct snd_soc_codec *codec = dai->codec;
Mark Brownc013b272012-07-04 20:05:57 +0100510 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
511 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown07ed8732012-06-18 21:08:44 +0100512 int base = dai->driver->base;
513 const int *rates;
514 int i;
515 int bclk, lrclk, wl, frame, sr_val;
516
517 if (params_rate(params) % 8000)
Mark Brown949e6bc2012-07-04 18:58:04 +0100518 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +0100519 else
Mark Brown949e6bc2012-07-04 18:58:04 +0100520 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +0100521
Mark Brown949e6bc2012-07-04 18:58:04 +0100522 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brown50017652012-07-04 19:07:09 +0100523 if (rates[i] >= snd_soc_params_to_bclk(params) &&
524 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +0100525 bclk = i;
526 break;
527 }
528 }
Mark Brown949e6bc2012-07-04 18:58:04 +0100529 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +0100530 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
531 params_rate(params));
532 return -EINVAL;
533 }
534
Mark Brown07ed8732012-06-18 21:08:44 +0100535 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
536 if (arizona_sr_vals[i] == params_rate(params))
537 break;
538 if (i == ARRAY_SIZE(arizona_sr_vals)) {
539 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
540 params_rate(params));
541 return -EINVAL;
542 }
543 sr_val = i;
544
545 lrclk = snd_soc_params_to_bclk(params) / params_rate(params);
546
547 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
548 rates[bclk], rates[bclk] / lrclk);
549
550 wl = snd_pcm_format_width(params_format(params));
551 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl;
552
Mark Brownc013b272012-07-04 20:05:57 +0100553 /*
554 * We will need to be more flexible than this in future,
555 * currently we use a single sample rate for SYSCLK.
556 */
557 switch (dai_priv->clk) {
558 case ARIZONA_CLK_SYSCLK:
559 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
560 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
561 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
562 ARIZONA_AIF1_RATE_MASK, 0);
563 break;
564 case ARIZONA_CLK_ASYNCCLK:
565 snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
566 ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val);
567 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
568 ARIZONA_AIF1_RATE_MASK, 8);
569 break;
570 default:
571 arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
572 return -EINVAL;
573 }
574
Mark Brown07ed8732012-06-18 21:08:44 +0100575 snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
576 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
577 snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_BCLK_RATE,
578 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
579 snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_BCLK_RATE,
580 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
581 snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_1,
582 ARIZONA_AIF1TX_WL_MASK |
583 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
584 snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_2,
585 ARIZONA_AIF1RX_WL_MASK |
586 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
587
588 return 0;
589}
590
Mark Brown410837a2012-07-05 17:26:59 +0100591static const char *arizona_dai_clk_str(int clk_id)
592{
593 switch (clk_id) {
594 case ARIZONA_CLK_SYSCLK:
595 return "SYSCLK";
596 case ARIZONA_CLK_ASYNCCLK:
597 return "ASYNCCLK";
598 default:
599 return "Unknown clock";
600 }
601}
602
Mark Brown5b2eec32012-07-04 17:32:05 +0100603static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
604 int clk_id, unsigned int freq, int dir)
605{
606 struct snd_soc_codec *codec = dai->codec;
607 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
608 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown410837a2012-07-05 17:26:59 +0100609 struct snd_soc_dapm_route routes[2];
Mark Brown5b2eec32012-07-04 17:32:05 +0100610
611 switch (clk_id) {
612 case ARIZONA_CLK_SYSCLK:
613 case ARIZONA_CLK_ASYNCCLK:
614 break;
615 default:
616 return -EINVAL;
617 }
618
Mark Brown410837a2012-07-05 17:26:59 +0100619 if (clk_id == dai_priv->clk)
620 return 0;
621
622 if (dai->active) {
Mark Brown5b2eec32012-07-04 17:32:05 +0100623 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
624 dai->id);
625 return -EBUSY;
626 }
627
Mark Brown410837a2012-07-05 17:26:59 +0100628 memset(&routes, 0, sizeof(routes));
629 routes[0].sink = dai->driver->capture.stream_name;
630 routes[1].sink = dai->driver->playback.stream_name;
Mark Brown5b2eec32012-07-04 17:32:05 +0100631
Mark Brown410837a2012-07-05 17:26:59 +0100632 routes[0].source = arizona_dai_clk_str(dai_priv->clk);
633 routes[1].source = arizona_dai_clk_str(dai_priv->clk);
634 snd_soc_dapm_del_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
635
636 routes[0].source = arizona_dai_clk_str(clk_id);
637 routes[1].source = arizona_dai_clk_str(clk_id);
638 snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
639
640 return snd_soc_dapm_sync(&codec->dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +0100641}
642
Mark Brown07ed8732012-06-18 21:08:44 +0100643const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +0100644 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +0100645 .set_fmt = arizona_set_fmt,
646 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +0100647 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown07ed8732012-06-18 21:08:44 +0100648};
649
Mark Brown5b2eec32012-07-04 17:32:05 +0100650int arizona_init_dai(struct arizona_priv *priv, int id)
651{
652 struct arizona_dai_priv *dai_priv = &priv->dai[id];
653
654 dai_priv->clk = ARIZONA_CLK_SYSCLK;
655
656 return 0;
657}
658EXPORT_SYMBOL_GPL(arizona_init_dai);
659
Mark Brown07ed8732012-06-18 21:08:44 +0100660static irqreturn_t arizona_fll_lock(int irq, void *data)
661{
662 struct arizona_fll *fll = data;
663
664 arizona_fll_dbg(fll, "Locked\n");
665
666 complete(&fll->lock);
667
668 return IRQ_HANDLED;
669}
670
671static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
672{
673 struct arizona_fll *fll = data;
674
675 arizona_fll_dbg(fll, "clock OK\n");
676
677 complete(&fll->ok);
678
679 return IRQ_HANDLED;
680}
681
682static struct {
683 unsigned int min;
684 unsigned int max;
685 u16 fratio;
686 int ratio;
687} fll_fratios[] = {
688 { 0, 64000, 4, 16 },
689 { 64000, 128000, 3, 8 },
690 { 128000, 256000, 2, 4 },
691 { 256000, 1000000, 1, 2 },
692 { 1000000, 13500000, 0, 1 },
693};
694
695struct arizona_fll_cfg {
696 int n;
697 int theta;
698 int lambda;
699 int refdiv;
700 int outdiv;
701 int fratio;
702};
703
704static int arizona_calc_fll(struct arizona_fll *fll,
705 struct arizona_fll_cfg *cfg,
706 unsigned int Fref,
707 unsigned int Fout)
708{
709 unsigned int target, div, gcd_fll;
710 int i, ratio;
711
712 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout);
713
714 /* Fref must be <=13.5MHz */
715 div = 1;
716 cfg->refdiv = 0;
717 while ((Fref / div) > 13500000) {
718 div *= 2;
719 cfg->refdiv++;
720
721 if (div > 8) {
722 arizona_fll_err(fll,
723 "Can't scale %dMHz in to <=13.5MHz\n",
724 Fref);
725 return -EINVAL;
726 }
727 }
728
729 /* Apply the division for our remaining calculations */
730 Fref /= div;
731
732 /* Fvco should be 90-100MHz; don't check the upper bound */
733 div = 1;
734 while (Fout * div < 90000000) {
735 div++;
736 if (div > 7) {
737 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
738 Fout);
739 return -EINVAL;
740 }
741 }
742 target = Fout * div;
743 cfg->outdiv = div;
744
745 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
746
747 /* Find an appropraite FLL_FRATIO and factor it out of the target */
748 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
749 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
750 cfg->fratio = fll_fratios[i].fratio;
751 ratio = fll_fratios[i].ratio;
752 break;
753 }
754 }
755 if (i == ARRAY_SIZE(fll_fratios)) {
756 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
757 Fref);
758 return -EINVAL;
759 }
760
761 cfg->n = target / (ratio * Fref);
762
763 if (target % Fref) {
764 gcd_fll = gcd(target, ratio * Fref);
765 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
766
767 cfg->theta = (target - (cfg->n * ratio * Fref))
768 / gcd_fll;
769 cfg->lambda = (ratio * Fref) / gcd_fll;
770 } else {
771 cfg->theta = 0;
772 cfg->lambda = 0;
773 }
774
775 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
776 cfg->n, cfg->theta, cfg->lambda);
777 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
778 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
779
780 return 0;
781
782}
783
784static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
785 struct arizona_fll_cfg *cfg, int source)
786{
787 regmap_update_bits(arizona->regmap, base + 3,
788 ARIZONA_FLL1_THETA_MASK, cfg->theta);
789 regmap_update_bits(arizona->regmap, base + 4,
790 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
791 regmap_update_bits(arizona->regmap, base + 5,
792 ARIZONA_FLL1_FRATIO_MASK,
793 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
794 regmap_update_bits(arizona->regmap, base + 6,
795 ARIZONA_FLL1_CLK_REF_DIV_MASK |
796 ARIZONA_FLL1_CLK_REF_SRC_MASK,
797 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
798 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
799
800 regmap_update_bits(arizona->regmap, base + 2,
801 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
802 ARIZONA_FLL1_CTRL_UPD | cfg->n);
803}
804
805int arizona_set_fll(struct arizona_fll *fll, int source,
806 unsigned int Fref, unsigned int Fout)
807{
808 struct arizona *arizona = fll->arizona;
809 struct arizona_fll_cfg cfg, sync;
810 unsigned int reg, val;
811 int syncsrc;
812 bool ena;
813 int ret;
814
815 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
816 if (ret != 0) {
817 arizona_fll_err(fll, "Failed to read current state: %d\n",
818 ret);
819 return ret;
820 }
821 ena = reg & ARIZONA_FLL1_ENA;
822
823 if (Fout) {
824 /* Do we have a 32kHz reference? */
825 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
826 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
827 case ARIZONA_CLK_SRC_MCLK1:
828 case ARIZONA_CLK_SRC_MCLK2:
829 syncsrc = val & ARIZONA_CLK_32K_SRC_MASK;
830 break;
831 default:
832 syncsrc = -1;
833 }
834
835 if (source == syncsrc)
836 syncsrc = -1;
837
838 if (syncsrc >= 0) {
839 ret = arizona_calc_fll(fll, &sync, Fref, Fout);
840 if (ret != 0)
841 return ret;
842
843 ret = arizona_calc_fll(fll, &cfg, 32768, Fout);
844 if (ret != 0)
845 return ret;
846 } else {
847 ret = arizona_calc_fll(fll, &cfg, Fref, Fout);
848 if (ret != 0)
849 return ret;
850 }
851 } else {
852 regmap_update_bits(arizona->regmap, fll->base + 1,
853 ARIZONA_FLL1_ENA, 0);
854 regmap_update_bits(arizona->regmap, fll->base + 0x11,
855 ARIZONA_FLL1_SYNC_ENA, 0);
856
857 if (ena)
858 pm_runtime_put_autosuspend(arizona->dev);
859
860 return 0;
861 }
862
863 regmap_update_bits(arizona->regmap, fll->base + 5,
864 ARIZONA_FLL1_OUTDIV_MASK,
865 cfg.outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
866
867 if (syncsrc >= 0) {
868 arizona_apply_fll(arizona, fll->base, &cfg, syncsrc);
869 arizona_apply_fll(arizona, fll->base + 0x10, &sync, source);
870 } else {
871 arizona_apply_fll(arizona, fll->base, &cfg, source);
872 }
873
874 if (!ena)
875 pm_runtime_get(arizona->dev);
876
877 /* Clear any pending completions */
878 try_wait_for_completion(&fll->ok);
879
880 regmap_update_bits(arizona->regmap, fll->base + 1,
881 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
882 if (syncsrc >= 0)
883 regmap_update_bits(arizona->regmap, fll->base + 0x11,
884 ARIZONA_FLL1_SYNC_ENA,
885 ARIZONA_FLL1_SYNC_ENA);
886
887 ret = wait_for_completion_timeout(&fll->ok,
888 msecs_to_jiffies(25));
889 if (ret == 0)
890 arizona_fll_warn(fll, "Timed out waiting for lock\n");
891
892 return 0;
893}
894EXPORT_SYMBOL_GPL(arizona_set_fll);
895
896int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
897 int ok_irq, struct arizona_fll *fll)
898{
899 int ret;
900
901 init_completion(&fll->lock);
902 init_completion(&fll->ok);
903
904 fll->id = id;
905 fll->base = base;
906 fll->arizona = arizona;
907
908 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
909 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
910 "FLL%d clock OK", id);
911
912 ret = arizona_request_irq(arizona, lock_irq, fll->lock_name,
913 arizona_fll_lock, fll);
914 if (ret != 0) {
915 dev_err(arizona->dev, "Failed to get FLL%d lock IRQ: %d\n",
916 id, ret);
917 }
918
919 ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
920 arizona_fll_clock_ok, fll);
921 if (ret != 0) {
922 dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
923 id, ret);
924 }
925
926 return 0;
927}
928EXPORT_SYMBOL_GPL(arizona_init_fll);
929
930MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
931MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
932MODULE_LICENSE("GPL");