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