blob: d49764388f1cfa70338f4c1cf846613daaee46c3 [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",
Mark Brownc9c56fd2012-07-09 19:09:01 +010082 "IN4L",
83 "IN4R",
Mark Brown07ed8732012-06-18 21:08:44 +010084 "AIF1RX1",
85 "AIF1RX2",
86 "AIF1RX3",
87 "AIF1RX4",
88 "AIF1RX5",
89 "AIF1RX6",
90 "AIF1RX7",
91 "AIF1RX8",
92 "AIF2RX1",
93 "AIF2RX2",
94 "AIF3RX1",
95 "AIF3RX2",
96 "SLIMRX1",
97 "SLIMRX2",
98 "SLIMRX3",
99 "SLIMRX4",
100 "SLIMRX5",
101 "SLIMRX6",
102 "SLIMRX7",
103 "SLIMRX8",
104 "EQ1",
105 "EQ2",
106 "EQ3",
107 "EQ4",
108 "DRC1L",
109 "DRC1R",
110 "DRC2L",
111 "DRC2R",
112 "LHPF1",
113 "LHPF2",
114 "LHPF3",
115 "LHPF4",
116 "DSP1.1",
117 "DSP1.2",
118 "DSP1.3",
119 "DSP1.4",
120 "DSP1.5",
121 "DSP1.6",
Mark Brownc922cc42012-09-26 16:43:44 +0100122 "DSP2.1",
123 "DSP2.2",
124 "DSP2.3",
125 "DSP2.4",
126 "DSP2.5",
127 "DSP2.6",
128 "DSP3.1",
129 "DSP3.2",
130 "DSP3.3",
131 "DSP3.4",
132 "DSP3.5",
133 "DSP3.6",
134 "DSP4.1",
135 "DSP4.2",
136 "DSP4.3",
137 "DSP4.4",
138 "DSP4.5",
139 "DSP4.6",
Mark Brown07ed8732012-06-18 21:08:44 +0100140 "ASRC1L",
141 "ASRC1R",
142 "ASRC2L",
143 "ASRC2R",
144};
145EXPORT_SYMBOL_GPL(arizona_mixer_texts);
146
147int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
148 0x00, /* None */
149 0x04, /* Tone */
150 0x05,
151 0x06, /* Haptics */
152 0x08, /* AEC */
153 0x0c, /* Noise mixer */
154 0x0d, /* Comfort noise */
155 0x10, /* IN1L */
156 0x11,
157 0x12,
158 0x13,
159 0x14,
160 0x15,
Mark Brownc9c56fd2012-07-09 19:09:01 +0100161 0x16,
162 0x17,
Mark Brown07ed8732012-06-18 21:08:44 +0100163 0x20, /* AIF1RX1 */
164 0x21,
165 0x22,
166 0x23,
167 0x24,
168 0x25,
169 0x26,
170 0x27,
171 0x28, /* AIF2RX1 */
172 0x29,
173 0x30, /* AIF3RX1 */
174 0x31,
175 0x38, /* SLIMRX1 */
176 0x39,
177 0x3a,
178 0x3b,
179 0x3c,
180 0x3d,
181 0x3e,
182 0x3f,
183 0x50, /* EQ1 */
184 0x51,
185 0x52,
186 0x53,
187 0x58, /* DRC1L */
188 0x59,
189 0x5a,
190 0x5b,
191 0x60, /* LHPF1 */
192 0x61,
193 0x62,
194 0x63,
195 0x68, /* DSP1.1 */
196 0x69,
197 0x6a,
198 0x6b,
199 0x6c,
200 0x6d,
Mark Brownc922cc42012-09-26 16:43:44 +0100201 0x70, /* DSP2.1 */
202 0x71,
203 0x72,
204 0x73,
205 0x74,
206 0x75,
207 0x78, /* DSP3.1 */
208 0x79,
209 0x7a,
210 0x7b,
211 0x7c,
212 0x7d,
213 0x80, /* DSP4.1 */
214 0x81,
215 0x82,
216 0x83,
217 0x84,
218 0x85,
Mark Brown07ed8732012-06-18 21:08:44 +0100219 0x90, /* ASRC1L */
220 0x91,
221 0x92,
222 0x93,
223};
224EXPORT_SYMBOL_GPL(arizona_mixer_values);
225
226const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
227EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
228
229static const char *arizona_lhpf_mode_text[] = {
230 "Low-pass", "High-pass"
231};
232
233const struct soc_enum arizona_lhpf1_mode =
234 SOC_ENUM_SINGLE(ARIZONA_HPLPF1_1, ARIZONA_LHPF1_MODE_SHIFT, 2,
235 arizona_lhpf_mode_text);
236EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
237
238const struct soc_enum arizona_lhpf2_mode =
239 SOC_ENUM_SINGLE(ARIZONA_HPLPF2_1, ARIZONA_LHPF2_MODE_SHIFT, 2,
240 arizona_lhpf_mode_text);
241EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
242
243const struct soc_enum arizona_lhpf3_mode =
244 SOC_ENUM_SINGLE(ARIZONA_HPLPF3_1, ARIZONA_LHPF3_MODE_SHIFT, 2,
245 arizona_lhpf_mode_text);
246EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
247
248const struct soc_enum arizona_lhpf4_mode =
249 SOC_ENUM_SINGLE(ARIZONA_HPLPF4_1, ARIZONA_LHPF4_MODE_SHIFT, 2,
250 arizona_lhpf_mode_text);
251EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
252
253int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
254 int event)
255{
256 return 0;
257}
258EXPORT_SYMBOL_GPL(arizona_in_ev);
259
260int arizona_out_ev(struct snd_soc_dapm_widget *w,
261 struct snd_kcontrol *kcontrol,
262 int event)
263{
264 return 0;
265}
266EXPORT_SYMBOL_GPL(arizona_out_ev);
267
Mark Browncbd840d2012-08-08 17:52:44 +0100268static unsigned int arizona_sysclk_48k_rates[] = {
269 6144000,
270 12288000,
271 22579200,
272 49152000,
Mark Brownaeaeee12012-09-26 17:50:02 +0100273 73728000,
274 98304000,
275 147456000,
Mark Browncbd840d2012-08-08 17:52:44 +0100276};
277
278static unsigned int arizona_sysclk_44k1_rates[] = {
279 5644800,
280 11289600,
281 24576000,
282 45158400,
Mark Brownaeaeee12012-09-26 17:50:02 +0100283 67737600,
284 90316800,
285 135475200,
Mark Browncbd840d2012-08-08 17:52:44 +0100286};
287
288static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
289 unsigned int freq)
290{
291 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
292 unsigned int reg;
293 unsigned int *rates;
294 int ref, div, refclk;
295
296 switch (clk) {
297 case ARIZONA_CLK_OPCLK:
298 reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
299 refclk = priv->sysclk;
300 break;
301 case ARIZONA_CLK_ASYNC_OPCLK:
302 reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
303 refclk = priv->asyncclk;
304 break;
305 default:
306 return -EINVAL;
307 }
308
309 if (refclk % 8000)
310 rates = arizona_sysclk_44k1_rates;
311 else
312 rates = arizona_sysclk_48k_rates;
313
314 for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) &&
315 rates[ref] <= refclk; ref++) {
316 div = 1;
317 while (rates[ref] / div >= freq && div < 32) {
318 if (rates[ref] / div == freq) {
319 dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
320 freq);
321 snd_soc_update_bits(codec, reg,
322 ARIZONA_OPCLK_DIV_MASK |
323 ARIZONA_OPCLK_SEL_MASK,
324 (div <<
325 ARIZONA_OPCLK_DIV_SHIFT) |
326 ref);
327 return 0;
328 }
329 div++;
330 }
331 }
332
333 dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
334 return -EINVAL;
335}
336
Mark Brown07ed8732012-06-18 21:08:44 +0100337int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
338 int source, unsigned int freq, int dir)
339{
340 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
341 struct arizona *arizona = priv->arizona;
342 char *name;
343 unsigned int reg;
344 unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
345 unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
346 unsigned int *clk;
347
348 switch (clk_id) {
349 case ARIZONA_CLK_SYSCLK:
350 name = "SYSCLK";
351 reg = ARIZONA_SYSTEM_CLOCK_1;
352 clk = &priv->sysclk;
353 mask |= ARIZONA_SYSCLK_FRAC;
354 break;
355 case ARIZONA_CLK_ASYNCCLK:
356 name = "ASYNCCLK";
357 reg = ARIZONA_ASYNC_CLOCK_1;
358 clk = &priv->asyncclk;
359 break;
Mark Browncbd840d2012-08-08 17:52:44 +0100360 case ARIZONA_CLK_OPCLK:
361 case ARIZONA_CLK_ASYNC_OPCLK:
362 return arizona_set_opclk(codec, clk_id, freq);
Mark Brown07ed8732012-06-18 21:08:44 +0100363 default:
364 return -EINVAL;
365 }
366
367 switch (freq) {
368 case 5644800:
369 case 6144000:
370 break;
371 case 11289600:
372 case 12288000:
373 val |= 1 << ARIZONA_SYSCLK_FREQ_SHIFT;
374 break;
375 case 22579200:
376 case 24576000:
377 val |= 2 << ARIZONA_SYSCLK_FREQ_SHIFT;
378 break;
379 case 45158400:
380 case 49152000:
381 val |= 3 << ARIZONA_SYSCLK_FREQ_SHIFT;
382 break;
Mark Brown38113362012-11-26 16:01:37 +0000383 case 67737600:
384 case 73728000:
385 val |= 4 << ARIZONA_SYSCLK_FREQ_SHIFT;
386 break;
387 case 90316800:
388 case 98304000:
389 val |= 5 << ARIZONA_SYSCLK_FREQ_SHIFT;
390 break;
391 case 135475200:
392 case 147456000:
393 val |= 6 << ARIZONA_SYSCLK_FREQ_SHIFT;
394 break;
Mark Brown07ed8732012-06-18 21:08:44 +0100395 default:
396 return -EINVAL;
397 }
398
399 *clk = freq;
400
401 if (freq % 6144000)
402 val |= ARIZONA_SYSCLK_FRAC;
403
404 dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
405
406 return regmap_update_bits(arizona->regmap, reg, mask, val);
407}
408EXPORT_SYMBOL_GPL(arizona_set_sysclk);
409
410static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
411{
412 struct snd_soc_codec *codec = dai->codec;
413 int lrclk, bclk, mode, base;
414
415 base = dai->driver->base;
416
417 lrclk = 0;
418 bclk = 0;
419
420 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
421 case SND_SOC_DAIFMT_DSP_A:
422 mode = 0;
423 break;
424 case SND_SOC_DAIFMT_DSP_B:
425 mode = 1;
426 break;
427 case SND_SOC_DAIFMT_I2S:
428 mode = 2;
429 break;
430 case SND_SOC_DAIFMT_LEFT_J:
431 mode = 3;
432 break;
433 default:
434 arizona_aif_err(dai, "Unsupported DAI format %d\n",
435 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
436 return -EINVAL;
437 }
438
439 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
440 case SND_SOC_DAIFMT_CBS_CFS:
441 break;
442 case SND_SOC_DAIFMT_CBS_CFM:
443 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
444 break;
445 case SND_SOC_DAIFMT_CBM_CFS:
446 bclk |= ARIZONA_AIF1_BCLK_MSTR;
447 break;
448 case SND_SOC_DAIFMT_CBM_CFM:
449 bclk |= ARIZONA_AIF1_BCLK_MSTR;
450 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
451 break;
452 default:
453 arizona_aif_err(dai, "Unsupported master mode %d\n",
454 fmt & SND_SOC_DAIFMT_MASTER_MASK);
455 return -EINVAL;
456 }
457
458 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
459 case SND_SOC_DAIFMT_NB_NF:
460 break;
461 case SND_SOC_DAIFMT_IB_IF:
462 bclk |= ARIZONA_AIF1_BCLK_INV;
463 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
464 break;
465 case SND_SOC_DAIFMT_IB_NF:
466 bclk |= ARIZONA_AIF1_BCLK_INV;
467 break;
468 case SND_SOC_DAIFMT_NB_IF:
469 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
470 break;
471 default:
472 return -EINVAL;
473 }
474
475 snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
476 ARIZONA_AIF1_BCLK_INV | ARIZONA_AIF1_BCLK_MSTR,
477 bclk);
478 snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_PIN_CTRL,
479 ARIZONA_AIF1TX_LRCLK_INV |
480 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
481 snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_PIN_CTRL,
482 ARIZONA_AIF1RX_LRCLK_INV |
483 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
484 snd_soc_update_bits(codec, base + ARIZONA_AIF_FORMAT,
485 ARIZONA_AIF1_FMT_MASK, mode);
486
487 return 0;
488}
489
Mark Brown949e6bc2012-07-04 18:58:04 +0100490static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100491 -1,
492 48000,
493 64000,
494 96000,
495 128000,
496 192000,
497 256000,
498 384000,
499 512000,
500 768000,
501 1024000,
502 1536000,
503 2048000,
504 3072000,
505 4096000,
506 6144000,
507 8192000,
508 12288000,
509 24576000,
510};
511
Mark Brown5b2eec32012-07-04 17:32:05 +0100512static const unsigned int arizona_48k_rates[] = {
513 12000,
514 24000,
515 48000,
516 96000,
517 192000,
518 384000,
519 768000,
520 4000,
521 8000,
522 16000,
523 32000,
524 64000,
525 128000,
526 256000,
527 512000,
528};
529
530static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = {
531 .count = ARRAY_SIZE(arizona_48k_rates),
532 .list = arizona_48k_rates,
533};
534
Mark Brown949e6bc2012-07-04 18:58:04 +0100535static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100536 -1,
537 44100,
538 58800,
539 88200,
540 117600,
541 177640,
542 235200,
543 352800,
544 470400,
545 705600,
546 940800,
547 1411200,
548 1881600,
Heather Lomond4758be32012-09-05 05:02:10 -0400549 2822400,
Mark Brown07ed8732012-06-18 21:08:44 +0100550 3763200,
551 5644800,
552 7526400,
553 11289600,
554 22579200,
555};
556
Mark Brown5b2eec32012-07-04 17:32:05 +0100557static const unsigned int arizona_44k1_rates[] = {
558 11025,
559 22050,
560 44100,
561 88200,
562 176400,
563 352800,
564 705600,
565};
566
567static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = {
568 .count = ARRAY_SIZE(arizona_44k1_rates),
569 .list = arizona_44k1_rates,
570};
571
Mark Brown07ed8732012-06-18 21:08:44 +0100572static int arizona_sr_vals[] = {
573 0,
574 12000,
575 24000,
576 48000,
577 96000,
578 192000,
579 384000,
580 768000,
581 0,
582 11025,
583 22050,
584 44100,
585 88200,
586 176400,
587 352800,
588 705600,
589 4000,
590 8000,
591 16000,
592 32000,
593 64000,
594 128000,
595 256000,
596 512000,
597};
598
Mark Brown5b2eec32012-07-04 17:32:05 +0100599static int arizona_startup(struct snd_pcm_substream *substream,
600 struct snd_soc_dai *dai)
601{
602 struct snd_soc_codec *codec = dai->codec;
603 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
604 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
605 const struct snd_pcm_hw_constraint_list *constraint;
606 unsigned int base_rate;
607
608 switch (dai_priv->clk) {
609 case ARIZONA_CLK_SYSCLK:
610 base_rate = priv->sysclk;
611 break;
612 case ARIZONA_CLK_ASYNCCLK:
613 base_rate = priv->asyncclk;
614 break;
615 default:
616 return 0;
617 }
618
619 if (base_rate % 8000)
620 constraint = &arizona_44k1_constraint;
621 else
622 constraint = &arizona_48k_constraint;
623
624 return snd_pcm_hw_constraint_list(substream->runtime, 0,
625 SNDRV_PCM_HW_PARAM_RATE,
626 constraint);
627}
628
Mark Brown07ed8732012-06-18 21:08:44 +0100629static int arizona_hw_params(struct snd_pcm_substream *substream,
630 struct snd_pcm_hw_params *params,
631 struct snd_soc_dai *dai)
632{
633 struct snd_soc_codec *codec = dai->codec;
Mark Brownc013b272012-07-04 20:05:57 +0100634 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
635 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown07ed8732012-06-18 21:08:44 +0100636 int base = dai->driver->base;
637 const int *rates;
638 int i;
639 int bclk, lrclk, wl, frame, sr_val;
640
641 if (params_rate(params) % 8000)
Mark Brown949e6bc2012-07-04 18:58:04 +0100642 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +0100643 else
Mark Brown949e6bc2012-07-04 18:58:04 +0100644 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +0100645
Mark Brown949e6bc2012-07-04 18:58:04 +0100646 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brown50017652012-07-04 19:07:09 +0100647 if (rates[i] >= snd_soc_params_to_bclk(params) &&
648 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +0100649 bclk = i;
650 break;
651 }
652 }
Mark Brown949e6bc2012-07-04 18:58:04 +0100653 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +0100654 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
655 params_rate(params));
656 return -EINVAL;
657 }
658
Mark Brown07ed8732012-06-18 21:08:44 +0100659 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
660 if (arizona_sr_vals[i] == params_rate(params))
661 break;
662 if (i == ARRAY_SIZE(arizona_sr_vals)) {
663 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
664 params_rate(params));
665 return -EINVAL;
666 }
667 sr_val = i;
668
669 lrclk = snd_soc_params_to_bclk(params) / params_rate(params);
670
671 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
672 rates[bclk], rates[bclk] / lrclk);
673
674 wl = snd_pcm_format_width(params_format(params));
675 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl;
676
Mark Brownc013b272012-07-04 20:05:57 +0100677 /*
678 * We will need to be more flexible than this in future,
679 * currently we use a single sample rate for SYSCLK.
680 */
681 switch (dai_priv->clk) {
682 case ARIZONA_CLK_SYSCLK:
683 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
684 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
685 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
686 ARIZONA_AIF1_RATE_MASK, 0);
687 break;
688 case ARIZONA_CLK_ASYNCCLK:
689 snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
690 ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val);
691 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
692 ARIZONA_AIF1_RATE_MASK, 8);
693 break;
694 default:
695 arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
696 return -EINVAL;
697 }
698
Mark Brown07ed8732012-06-18 21:08:44 +0100699 snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
700 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
701 snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_BCLK_RATE,
702 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
703 snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_BCLK_RATE,
704 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
705 snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_1,
706 ARIZONA_AIF1TX_WL_MASK |
707 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
708 snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_2,
709 ARIZONA_AIF1RX_WL_MASK |
710 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
711
712 return 0;
713}
714
Mark Brown410837a2012-07-05 17:26:59 +0100715static const char *arizona_dai_clk_str(int clk_id)
716{
717 switch (clk_id) {
718 case ARIZONA_CLK_SYSCLK:
719 return "SYSCLK";
720 case ARIZONA_CLK_ASYNCCLK:
721 return "ASYNCCLK";
722 default:
723 return "Unknown clock";
724 }
725}
726
Mark Brown5b2eec32012-07-04 17:32:05 +0100727static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
728 int clk_id, unsigned int freq, int dir)
729{
730 struct snd_soc_codec *codec = dai->codec;
731 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
732 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown410837a2012-07-05 17:26:59 +0100733 struct snd_soc_dapm_route routes[2];
Mark Brown5b2eec32012-07-04 17:32:05 +0100734
735 switch (clk_id) {
736 case ARIZONA_CLK_SYSCLK:
737 case ARIZONA_CLK_ASYNCCLK:
738 break;
739 default:
740 return -EINVAL;
741 }
742
Mark Brown410837a2012-07-05 17:26:59 +0100743 if (clk_id == dai_priv->clk)
744 return 0;
745
746 if (dai->active) {
Mark Brown5b2eec32012-07-04 17:32:05 +0100747 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
748 dai->id);
749 return -EBUSY;
750 }
751
Mark Brown410837a2012-07-05 17:26:59 +0100752 memset(&routes, 0, sizeof(routes));
753 routes[0].sink = dai->driver->capture.stream_name;
754 routes[1].sink = dai->driver->playback.stream_name;
Mark Brown5b2eec32012-07-04 17:32:05 +0100755
Mark Brown410837a2012-07-05 17:26:59 +0100756 routes[0].source = arizona_dai_clk_str(dai_priv->clk);
757 routes[1].source = arizona_dai_clk_str(dai_priv->clk);
758 snd_soc_dapm_del_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
759
760 routes[0].source = arizona_dai_clk_str(clk_id);
761 routes[1].source = arizona_dai_clk_str(clk_id);
762 snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
763
764 return snd_soc_dapm_sync(&codec->dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +0100765}
766
Mark Brown07ed8732012-06-18 21:08:44 +0100767const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +0100768 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +0100769 .set_fmt = arizona_set_fmt,
770 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +0100771 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown07ed8732012-06-18 21:08:44 +0100772};
Mark Browna8379872012-07-09 12:16:41 +0100773EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +0100774
Mark Brown5b2eec32012-07-04 17:32:05 +0100775int arizona_init_dai(struct arizona_priv *priv, int id)
776{
777 struct arizona_dai_priv *dai_priv = &priv->dai[id];
778
779 dai_priv->clk = ARIZONA_CLK_SYSCLK;
780
781 return 0;
782}
783EXPORT_SYMBOL_GPL(arizona_init_dai);
784
Mark Brown07ed8732012-06-18 21:08:44 +0100785static irqreturn_t arizona_fll_lock(int irq, void *data)
786{
787 struct arizona_fll *fll = data;
788
Mark Brown6b315952012-09-12 18:44:40 +0800789 arizona_fll_dbg(fll, "Lock status changed\n");
Mark Brown07ed8732012-06-18 21:08:44 +0100790
791 complete(&fll->lock);
792
793 return IRQ_HANDLED;
794}
795
796static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
797{
798 struct arizona_fll *fll = data;
799
800 arizona_fll_dbg(fll, "clock OK\n");
801
802 complete(&fll->ok);
803
804 return IRQ_HANDLED;
805}
806
807static struct {
808 unsigned int min;
809 unsigned int max;
810 u16 fratio;
811 int ratio;
812} fll_fratios[] = {
813 { 0, 64000, 4, 16 },
814 { 64000, 128000, 3, 8 },
815 { 128000, 256000, 2, 4 },
816 { 256000, 1000000, 1, 2 },
817 { 1000000, 13500000, 0, 1 },
818};
819
820struct arizona_fll_cfg {
821 int n;
822 int theta;
823 int lambda;
824 int refdiv;
825 int outdiv;
826 int fratio;
827};
828
829static int arizona_calc_fll(struct arizona_fll *fll,
830 struct arizona_fll_cfg *cfg,
831 unsigned int Fref,
832 unsigned int Fout)
833{
834 unsigned int target, div, gcd_fll;
835 int i, ratio;
836
837 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout);
838
839 /* Fref must be <=13.5MHz */
840 div = 1;
841 cfg->refdiv = 0;
842 while ((Fref / div) > 13500000) {
843 div *= 2;
844 cfg->refdiv++;
845
846 if (div > 8) {
847 arizona_fll_err(fll,
848 "Can't scale %dMHz in to <=13.5MHz\n",
849 Fref);
850 return -EINVAL;
851 }
852 }
853
854 /* Apply the division for our remaining calculations */
855 Fref /= div;
856
Mark Brown2b4d39f2012-07-10 17:03:46 +0100857 /* Fvco should be over the targt; don't check the upper bound */
Mark Brown07ed8732012-06-18 21:08:44 +0100858 div = 1;
Mark Brown2b4d39f2012-07-10 17:03:46 +0100859 while (Fout * div < 90000000 * fll->vco_mult) {
Mark Brown07ed8732012-06-18 21:08:44 +0100860 div++;
861 if (div > 7) {
862 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
863 Fout);
864 return -EINVAL;
865 }
866 }
Mark Brown2b4d39f2012-07-10 17:03:46 +0100867 target = Fout * div / fll->vco_mult;
Mark Brown07ed8732012-06-18 21:08:44 +0100868 cfg->outdiv = div;
869
870 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
871
872 /* Find an appropraite FLL_FRATIO and factor it out of the target */
873 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
874 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
875 cfg->fratio = fll_fratios[i].fratio;
876 ratio = fll_fratios[i].ratio;
877 break;
878 }
879 }
880 if (i == ARRAY_SIZE(fll_fratios)) {
881 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
882 Fref);
883 return -EINVAL;
884 }
885
886 cfg->n = target / (ratio * Fref);
887
888 if (target % Fref) {
889 gcd_fll = gcd(target, ratio * Fref);
890 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
891
892 cfg->theta = (target - (cfg->n * ratio * Fref))
893 / gcd_fll;
894 cfg->lambda = (ratio * Fref) / gcd_fll;
895 } else {
896 cfg->theta = 0;
897 cfg->lambda = 0;
898 }
899
900 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
901 cfg->n, cfg->theta, cfg->lambda);
902 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
903 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
904
905 return 0;
906
907}
908
909static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
910 struct arizona_fll_cfg *cfg, int source)
911{
912 regmap_update_bits(arizona->regmap, base + 3,
913 ARIZONA_FLL1_THETA_MASK, cfg->theta);
914 regmap_update_bits(arizona->regmap, base + 4,
915 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
916 regmap_update_bits(arizona->regmap, base + 5,
917 ARIZONA_FLL1_FRATIO_MASK,
918 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
919 regmap_update_bits(arizona->regmap, base + 6,
920 ARIZONA_FLL1_CLK_REF_DIV_MASK |
921 ARIZONA_FLL1_CLK_REF_SRC_MASK,
922 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
923 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
924
925 regmap_update_bits(arizona->regmap, base + 2,
926 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
927 ARIZONA_FLL1_CTRL_UPD | cfg->n);
928}
929
930int arizona_set_fll(struct arizona_fll *fll, int source,
931 unsigned int Fref, unsigned int Fout)
932{
933 struct arizona *arizona = fll->arizona;
934 struct arizona_fll_cfg cfg, sync;
935 unsigned int reg, val;
936 int syncsrc;
937 bool ena;
938 int ret;
939
Mark Brown1cbe4bc2012-11-21 14:12:22 +0900940 if (fll->fref == Fref && fll->fout == Fout)
941 return 0;
942
Mark Brown07ed8732012-06-18 21:08:44 +0100943 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
944 if (ret != 0) {
945 arizona_fll_err(fll, "Failed to read current state: %d\n",
946 ret);
947 return ret;
948 }
949 ena = reg & ARIZONA_FLL1_ENA;
950
951 if (Fout) {
952 /* Do we have a 32kHz reference? */
953 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
954 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
955 case ARIZONA_CLK_SRC_MCLK1:
956 case ARIZONA_CLK_SRC_MCLK2:
957 syncsrc = val & ARIZONA_CLK_32K_SRC_MASK;
958 break;
959 default:
960 syncsrc = -1;
961 }
962
963 if (source == syncsrc)
964 syncsrc = -1;
965
966 if (syncsrc >= 0) {
967 ret = arizona_calc_fll(fll, &sync, Fref, Fout);
968 if (ret != 0)
969 return ret;
970
971 ret = arizona_calc_fll(fll, &cfg, 32768, Fout);
972 if (ret != 0)
973 return ret;
974 } else {
975 ret = arizona_calc_fll(fll, &cfg, Fref, Fout);
976 if (ret != 0)
977 return ret;
978 }
979 } else {
980 regmap_update_bits(arizona->regmap, fll->base + 1,
981 ARIZONA_FLL1_ENA, 0);
982 regmap_update_bits(arizona->regmap, fll->base + 0x11,
983 ARIZONA_FLL1_SYNC_ENA, 0);
984
985 if (ena)
986 pm_runtime_put_autosuspend(arizona->dev);
987
988 return 0;
989 }
990
991 regmap_update_bits(arizona->regmap, fll->base + 5,
992 ARIZONA_FLL1_OUTDIV_MASK,
993 cfg.outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
994
995 if (syncsrc >= 0) {
996 arizona_apply_fll(arizona, fll->base, &cfg, syncsrc);
997 arizona_apply_fll(arizona, fll->base + 0x10, &sync, source);
998 } else {
999 arizona_apply_fll(arizona, fll->base, &cfg, source);
1000 }
1001
1002 if (!ena)
1003 pm_runtime_get(arizona->dev);
1004
1005 /* Clear any pending completions */
1006 try_wait_for_completion(&fll->ok);
1007
1008 regmap_update_bits(arizona->regmap, fll->base + 1,
1009 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
1010 if (syncsrc >= 0)
1011 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1012 ARIZONA_FLL1_SYNC_ENA,
1013 ARIZONA_FLL1_SYNC_ENA);
1014
1015 ret = wait_for_completion_timeout(&fll->ok,
1016 msecs_to_jiffies(25));
1017 if (ret == 0)
1018 arizona_fll_warn(fll, "Timed out waiting for lock\n");
1019
Mark Brown1cbe4bc2012-11-21 14:12:22 +09001020 fll->fref = Fref;
1021 fll->fout = Fout;
1022
Mark Brown07ed8732012-06-18 21:08:44 +01001023 return 0;
1024}
1025EXPORT_SYMBOL_GPL(arizona_set_fll);
1026
1027int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
1028 int ok_irq, struct arizona_fll *fll)
1029{
1030 int ret;
1031
1032 init_completion(&fll->lock);
1033 init_completion(&fll->ok);
1034
1035 fll->id = id;
1036 fll->base = base;
1037 fll->arizona = arizona;
1038
1039 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
1040 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
1041 "FLL%d clock OK", id);
1042
1043 ret = arizona_request_irq(arizona, lock_irq, fll->lock_name,
1044 arizona_fll_lock, fll);
1045 if (ret != 0) {
1046 dev_err(arizona->dev, "Failed to get FLL%d lock IRQ: %d\n",
1047 id, ret);
1048 }
1049
1050 ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
1051 arizona_fll_clock_ok, fll);
1052 if (ret != 0) {
1053 dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
1054 id, ret);
1055 }
1056
1057 return 0;
1058}
1059EXPORT_SYMBOL_GPL(arizona_init_fll);
1060
1061MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
1062MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1063MODULE_LICENSE("GPL");