blob: 0be04b52658887dc0fbdcc01f8ca26591dcce0b4 [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};
Mark Browna8379872012-07-09 12:16:41 +0100649EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +0100650
Mark Brown5b2eec32012-07-04 17:32:05 +0100651int arizona_init_dai(struct arizona_priv *priv, int id)
652{
653 struct arizona_dai_priv *dai_priv = &priv->dai[id];
654
655 dai_priv->clk = ARIZONA_CLK_SYSCLK;
656
657 return 0;
658}
659EXPORT_SYMBOL_GPL(arizona_init_dai);
660
Mark Brown07ed8732012-06-18 21:08:44 +0100661static irqreturn_t arizona_fll_lock(int irq, void *data)
662{
663 struct arizona_fll *fll = data;
664
665 arizona_fll_dbg(fll, "Locked\n");
666
667 complete(&fll->lock);
668
669 return IRQ_HANDLED;
670}
671
672static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
673{
674 struct arizona_fll *fll = data;
675
676 arizona_fll_dbg(fll, "clock OK\n");
677
678 complete(&fll->ok);
679
680 return IRQ_HANDLED;
681}
682
683static struct {
684 unsigned int min;
685 unsigned int max;
686 u16 fratio;
687 int ratio;
688} fll_fratios[] = {
689 { 0, 64000, 4, 16 },
690 { 64000, 128000, 3, 8 },
691 { 128000, 256000, 2, 4 },
692 { 256000, 1000000, 1, 2 },
693 { 1000000, 13500000, 0, 1 },
694};
695
696struct arizona_fll_cfg {
697 int n;
698 int theta;
699 int lambda;
700 int refdiv;
701 int outdiv;
702 int fratio;
703};
704
705static int arizona_calc_fll(struct arizona_fll *fll,
706 struct arizona_fll_cfg *cfg,
707 unsigned int Fref,
708 unsigned int Fout)
709{
710 unsigned int target, div, gcd_fll;
711 int i, ratio;
712
713 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout);
714
715 /* Fref must be <=13.5MHz */
716 div = 1;
717 cfg->refdiv = 0;
718 while ((Fref / div) > 13500000) {
719 div *= 2;
720 cfg->refdiv++;
721
722 if (div > 8) {
723 arizona_fll_err(fll,
724 "Can't scale %dMHz in to <=13.5MHz\n",
725 Fref);
726 return -EINVAL;
727 }
728 }
729
730 /* Apply the division for our remaining calculations */
731 Fref /= div;
732
733 /* Fvco should be 90-100MHz; don't check the upper bound */
734 div = 1;
735 while (Fout * div < 90000000) {
736 div++;
737 if (div > 7) {
738 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
739 Fout);
740 return -EINVAL;
741 }
742 }
743 target = Fout * div;
744 cfg->outdiv = div;
745
746 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
747
748 /* Find an appropraite FLL_FRATIO and factor it out of the target */
749 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
750 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
751 cfg->fratio = fll_fratios[i].fratio;
752 ratio = fll_fratios[i].ratio;
753 break;
754 }
755 }
756 if (i == ARRAY_SIZE(fll_fratios)) {
757 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
758 Fref);
759 return -EINVAL;
760 }
761
762 cfg->n = target / (ratio * Fref);
763
764 if (target % Fref) {
765 gcd_fll = gcd(target, ratio * Fref);
766 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
767
768 cfg->theta = (target - (cfg->n * ratio * Fref))
769 / gcd_fll;
770 cfg->lambda = (ratio * Fref) / gcd_fll;
771 } else {
772 cfg->theta = 0;
773 cfg->lambda = 0;
774 }
775
776 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
777 cfg->n, cfg->theta, cfg->lambda);
778 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
779 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
780
781 return 0;
782
783}
784
785static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
786 struct arizona_fll_cfg *cfg, int source)
787{
788 regmap_update_bits(arizona->regmap, base + 3,
789 ARIZONA_FLL1_THETA_MASK, cfg->theta);
790 regmap_update_bits(arizona->regmap, base + 4,
791 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
792 regmap_update_bits(arizona->regmap, base + 5,
793 ARIZONA_FLL1_FRATIO_MASK,
794 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
795 regmap_update_bits(arizona->regmap, base + 6,
796 ARIZONA_FLL1_CLK_REF_DIV_MASK |
797 ARIZONA_FLL1_CLK_REF_SRC_MASK,
798 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
799 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
800
801 regmap_update_bits(arizona->regmap, base + 2,
802 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
803 ARIZONA_FLL1_CTRL_UPD | cfg->n);
804}
805
806int arizona_set_fll(struct arizona_fll *fll, int source,
807 unsigned int Fref, unsigned int Fout)
808{
809 struct arizona *arizona = fll->arizona;
810 struct arizona_fll_cfg cfg, sync;
811 unsigned int reg, val;
812 int syncsrc;
813 bool ena;
814 int ret;
815
816 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
817 if (ret != 0) {
818 arizona_fll_err(fll, "Failed to read current state: %d\n",
819 ret);
820 return ret;
821 }
822 ena = reg & ARIZONA_FLL1_ENA;
823
824 if (Fout) {
825 /* Do we have a 32kHz reference? */
826 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
827 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
828 case ARIZONA_CLK_SRC_MCLK1:
829 case ARIZONA_CLK_SRC_MCLK2:
830 syncsrc = val & ARIZONA_CLK_32K_SRC_MASK;
831 break;
832 default:
833 syncsrc = -1;
834 }
835
836 if (source == syncsrc)
837 syncsrc = -1;
838
839 if (syncsrc >= 0) {
840 ret = arizona_calc_fll(fll, &sync, Fref, Fout);
841 if (ret != 0)
842 return ret;
843
844 ret = arizona_calc_fll(fll, &cfg, 32768, Fout);
845 if (ret != 0)
846 return ret;
847 } else {
848 ret = arizona_calc_fll(fll, &cfg, Fref, Fout);
849 if (ret != 0)
850 return ret;
851 }
852 } else {
853 regmap_update_bits(arizona->regmap, fll->base + 1,
854 ARIZONA_FLL1_ENA, 0);
855 regmap_update_bits(arizona->regmap, fll->base + 0x11,
856 ARIZONA_FLL1_SYNC_ENA, 0);
857
858 if (ena)
859 pm_runtime_put_autosuspend(arizona->dev);
860
861 return 0;
862 }
863
864 regmap_update_bits(arizona->regmap, fll->base + 5,
865 ARIZONA_FLL1_OUTDIV_MASK,
866 cfg.outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
867
868 if (syncsrc >= 0) {
869 arizona_apply_fll(arizona, fll->base, &cfg, syncsrc);
870 arizona_apply_fll(arizona, fll->base + 0x10, &sync, source);
871 } else {
872 arizona_apply_fll(arizona, fll->base, &cfg, source);
873 }
874
875 if (!ena)
876 pm_runtime_get(arizona->dev);
877
878 /* Clear any pending completions */
879 try_wait_for_completion(&fll->ok);
880
881 regmap_update_bits(arizona->regmap, fll->base + 1,
882 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
883 if (syncsrc >= 0)
884 regmap_update_bits(arizona->regmap, fll->base + 0x11,
885 ARIZONA_FLL1_SYNC_ENA,
886 ARIZONA_FLL1_SYNC_ENA);
887
888 ret = wait_for_completion_timeout(&fll->ok,
889 msecs_to_jiffies(25));
890 if (ret == 0)
891 arizona_fll_warn(fll, "Timed out waiting for lock\n");
892
893 return 0;
894}
895EXPORT_SYMBOL_GPL(arizona_set_fll);
896
897int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
898 int ok_irq, struct arizona_fll *fll)
899{
900 int ret;
901
902 init_completion(&fll->lock);
903 init_completion(&fll->ok);
904
905 fll->id = id;
906 fll->base = base;
907 fll->arizona = arizona;
908
909 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
910 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
911 "FLL%d clock OK", id);
912
913 ret = arizona_request_irq(arizona, lock_irq, fll->lock_name,
914 arizona_fll_lock, fll);
915 if (ret != 0) {
916 dev_err(arizona->dev, "Failed to get FLL%d lock IRQ: %d\n",
917 id, ret);
918 }
919
920 ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
921 arizona_fll_clock_ok, fll);
922 if (ret != 0) {
923 dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
924 id, ret);
925 }
926
927 return 0;
928}
929EXPORT_SYMBOL_GPL(arizona_init_fll);
930
931MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
932MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
933MODULE_LICENSE("GPL");