blob: 6c1be6cadc0bcc6f77684be15bac42fca51844a7 [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
Mark Brown0c778e82012-12-06 18:22:25 +0900764 dai_priv->clk = clk_id;
765
Mark Brown410837a2012-07-05 17:26:59 +0100766 return snd_soc_dapm_sync(&codec->dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +0100767}
768
Mark Brown07ed8732012-06-18 21:08:44 +0100769const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +0100770 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +0100771 .set_fmt = arizona_set_fmt,
772 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +0100773 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown07ed8732012-06-18 21:08:44 +0100774};
Mark Browna8379872012-07-09 12:16:41 +0100775EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +0100776
Mark Brown5b2eec32012-07-04 17:32:05 +0100777int arizona_init_dai(struct arizona_priv *priv, int id)
778{
779 struct arizona_dai_priv *dai_priv = &priv->dai[id];
780
781 dai_priv->clk = ARIZONA_CLK_SYSCLK;
782
783 return 0;
784}
785EXPORT_SYMBOL_GPL(arizona_init_dai);
786
Mark Brown07ed8732012-06-18 21:08:44 +0100787static irqreturn_t arizona_fll_lock(int irq, void *data)
788{
789 struct arizona_fll *fll = data;
790
Mark Brown6b315952012-09-12 18:44:40 +0800791 arizona_fll_dbg(fll, "Lock status changed\n");
Mark Brown07ed8732012-06-18 21:08:44 +0100792
793 complete(&fll->lock);
794
795 return IRQ_HANDLED;
796}
797
798static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
799{
800 struct arizona_fll *fll = data;
801
802 arizona_fll_dbg(fll, "clock OK\n");
803
804 complete(&fll->ok);
805
806 return IRQ_HANDLED;
807}
808
809static struct {
810 unsigned int min;
811 unsigned int max;
812 u16 fratio;
813 int ratio;
814} fll_fratios[] = {
815 { 0, 64000, 4, 16 },
816 { 64000, 128000, 3, 8 },
817 { 128000, 256000, 2, 4 },
818 { 256000, 1000000, 1, 2 },
819 { 1000000, 13500000, 0, 1 },
820};
821
822struct arizona_fll_cfg {
823 int n;
824 int theta;
825 int lambda;
826 int refdiv;
827 int outdiv;
828 int fratio;
829};
830
831static int arizona_calc_fll(struct arizona_fll *fll,
832 struct arizona_fll_cfg *cfg,
833 unsigned int Fref,
834 unsigned int Fout)
835{
836 unsigned int target, div, gcd_fll;
837 int i, ratio;
838
839 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout);
840
841 /* Fref must be <=13.5MHz */
842 div = 1;
843 cfg->refdiv = 0;
844 while ((Fref / div) > 13500000) {
845 div *= 2;
846 cfg->refdiv++;
847
848 if (div > 8) {
849 arizona_fll_err(fll,
850 "Can't scale %dMHz in to <=13.5MHz\n",
851 Fref);
852 return -EINVAL;
853 }
854 }
855
856 /* Apply the division for our remaining calculations */
857 Fref /= div;
858
Mark Brown2b4d39f2012-07-10 17:03:46 +0100859 /* Fvco should be over the targt; don't check the upper bound */
Mark Brown07ed8732012-06-18 21:08:44 +0100860 div = 1;
Mark Brown2b4d39f2012-07-10 17:03:46 +0100861 while (Fout * div < 90000000 * fll->vco_mult) {
Mark Brown07ed8732012-06-18 21:08:44 +0100862 div++;
863 if (div > 7) {
864 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
865 Fout);
866 return -EINVAL;
867 }
868 }
Mark Brown2b4d39f2012-07-10 17:03:46 +0100869 target = Fout * div / fll->vco_mult;
Mark Brown07ed8732012-06-18 21:08:44 +0100870 cfg->outdiv = div;
871
872 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
873
874 /* Find an appropraite FLL_FRATIO and factor it out of the target */
875 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
876 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
877 cfg->fratio = fll_fratios[i].fratio;
878 ratio = fll_fratios[i].ratio;
879 break;
880 }
881 }
882 if (i == ARRAY_SIZE(fll_fratios)) {
883 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
884 Fref);
885 return -EINVAL;
886 }
887
888 cfg->n = target / (ratio * Fref);
889
890 if (target % Fref) {
891 gcd_fll = gcd(target, ratio * Fref);
892 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
893
894 cfg->theta = (target - (cfg->n * ratio * Fref))
895 / gcd_fll;
896 cfg->lambda = (ratio * Fref) / gcd_fll;
897 } else {
898 cfg->theta = 0;
899 cfg->lambda = 0;
900 }
901
902 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
903 cfg->n, cfg->theta, cfg->lambda);
904 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
905 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
906
907 return 0;
908
909}
910
911static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
912 struct arizona_fll_cfg *cfg, int source)
913{
914 regmap_update_bits(arizona->regmap, base + 3,
915 ARIZONA_FLL1_THETA_MASK, cfg->theta);
916 regmap_update_bits(arizona->regmap, base + 4,
917 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
918 regmap_update_bits(arizona->regmap, base + 5,
919 ARIZONA_FLL1_FRATIO_MASK,
920 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
921 regmap_update_bits(arizona->regmap, base + 6,
922 ARIZONA_FLL1_CLK_REF_DIV_MASK |
923 ARIZONA_FLL1_CLK_REF_SRC_MASK,
924 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
925 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
926
927 regmap_update_bits(arizona->regmap, base + 2,
928 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
929 ARIZONA_FLL1_CTRL_UPD | cfg->n);
930}
931
932int arizona_set_fll(struct arizona_fll *fll, int source,
933 unsigned int Fref, unsigned int Fout)
934{
935 struct arizona *arizona = fll->arizona;
936 struct arizona_fll_cfg cfg, sync;
937 unsigned int reg, val;
938 int syncsrc;
939 bool ena;
940 int ret;
941
Mark Brown1cbe4bc2012-11-21 14:12:22 +0900942 if (fll->fref == Fref && fll->fout == Fout)
943 return 0;
944
Mark Brown07ed8732012-06-18 21:08:44 +0100945 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
946 if (ret != 0) {
947 arizona_fll_err(fll, "Failed to read current state: %d\n",
948 ret);
949 return ret;
950 }
951 ena = reg & ARIZONA_FLL1_ENA;
952
953 if (Fout) {
954 /* Do we have a 32kHz reference? */
955 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
956 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
957 case ARIZONA_CLK_SRC_MCLK1:
958 case ARIZONA_CLK_SRC_MCLK2:
959 syncsrc = val & ARIZONA_CLK_32K_SRC_MASK;
960 break;
961 default:
962 syncsrc = -1;
963 }
964
965 if (source == syncsrc)
966 syncsrc = -1;
967
968 if (syncsrc >= 0) {
969 ret = arizona_calc_fll(fll, &sync, Fref, Fout);
970 if (ret != 0)
971 return ret;
972
973 ret = arizona_calc_fll(fll, &cfg, 32768, Fout);
974 if (ret != 0)
975 return ret;
976 } else {
977 ret = arizona_calc_fll(fll, &cfg, Fref, Fout);
978 if (ret != 0)
979 return ret;
980 }
981 } else {
982 regmap_update_bits(arizona->regmap, fll->base + 1,
983 ARIZONA_FLL1_ENA, 0);
984 regmap_update_bits(arizona->regmap, fll->base + 0x11,
985 ARIZONA_FLL1_SYNC_ENA, 0);
986
987 if (ena)
988 pm_runtime_put_autosuspend(arizona->dev);
989
Mark Brown50fcfe42012-11-28 11:50:34 +0000990 fll->fref = Fref;
991 fll->fout = Fout;
992
Mark Brown07ed8732012-06-18 21:08:44 +0100993 return 0;
994 }
995
996 regmap_update_bits(arizona->regmap, fll->base + 5,
997 ARIZONA_FLL1_OUTDIV_MASK,
998 cfg.outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
999
1000 if (syncsrc >= 0) {
1001 arizona_apply_fll(arizona, fll->base, &cfg, syncsrc);
1002 arizona_apply_fll(arizona, fll->base + 0x10, &sync, source);
1003 } else {
1004 arizona_apply_fll(arizona, fll->base, &cfg, source);
1005 }
1006
1007 if (!ena)
1008 pm_runtime_get(arizona->dev);
1009
1010 /* Clear any pending completions */
1011 try_wait_for_completion(&fll->ok);
1012
1013 regmap_update_bits(arizona->regmap, fll->base + 1,
1014 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
1015 if (syncsrc >= 0)
1016 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1017 ARIZONA_FLL1_SYNC_ENA,
1018 ARIZONA_FLL1_SYNC_ENA);
1019
1020 ret = wait_for_completion_timeout(&fll->ok,
Mark Brown09871a92012-12-06 15:29:34 +09001021 msecs_to_jiffies(250));
Mark Brown07ed8732012-06-18 21:08:44 +01001022 if (ret == 0)
1023 arizona_fll_warn(fll, "Timed out waiting for lock\n");
1024
Mark Brown1cbe4bc2012-11-21 14:12:22 +09001025 fll->fref = Fref;
1026 fll->fout = Fout;
1027
Mark Brown07ed8732012-06-18 21:08:44 +01001028 return 0;
1029}
1030EXPORT_SYMBOL_GPL(arizona_set_fll);
1031
1032int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
1033 int ok_irq, struct arizona_fll *fll)
1034{
1035 int ret;
1036
1037 init_completion(&fll->lock);
1038 init_completion(&fll->ok);
1039
1040 fll->id = id;
1041 fll->base = base;
1042 fll->arizona = arizona;
1043
1044 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
1045 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
1046 "FLL%d clock OK", id);
1047
1048 ret = arizona_request_irq(arizona, lock_irq, fll->lock_name,
1049 arizona_fll_lock, fll);
1050 if (ret != 0) {
1051 dev_err(arizona->dev, "Failed to get FLL%d lock IRQ: %d\n",
1052 id, ret);
1053 }
1054
1055 ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
1056 arizona_fll_clock_ok, fll);
1057 if (ret != 0) {
1058 dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
1059 id, ret);
1060 }
1061
1062 return 0;
1063}
1064EXPORT_SYMBOL_GPL(arizona_init_fll);
1065
1066MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
1067MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1068MODULE_LICENSE("GPL");