blob: 5764960087bcda93dc384a92b5377eee55684bf4 [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,
273};
274
275static unsigned int arizona_sysclk_44k1_rates[] = {
276 5644800,
277 11289600,
278 24576000,
279 45158400,
280};
281
282static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
283 unsigned int freq)
284{
285 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
286 unsigned int reg;
287 unsigned int *rates;
288 int ref, div, refclk;
289
290 switch (clk) {
291 case ARIZONA_CLK_OPCLK:
292 reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
293 refclk = priv->sysclk;
294 break;
295 case ARIZONA_CLK_ASYNC_OPCLK:
296 reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
297 refclk = priv->asyncclk;
298 break;
299 default:
300 return -EINVAL;
301 }
302
303 if (refclk % 8000)
304 rates = arizona_sysclk_44k1_rates;
305 else
306 rates = arizona_sysclk_48k_rates;
307
308 for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) &&
309 rates[ref] <= refclk; ref++) {
310 div = 1;
311 while (rates[ref] / div >= freq && div < 32) {
312 if (rates[ref] / div == freq) {
313 dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
314 freq);
315 snd_soc_update_bits(codec, reg,
316 ARIZONA_OPCLK_DIV_MASK |
317 ARIZONA_OPCLK_SEL_MASK,
318 (div <<
319 ARIZONA_OPCLK_DIV_SHIFT) |
320 ref);
321 return 0;
322 }
323 div++;
324 }
325 }
326
327 dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
328 return -EINVAL;
329}
330
Mark Brown07ed8732012-06-18 21:08:44 +0100331int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
332 int source, unsigned int freq, int dir)
333{
334 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
335 struct arizona *arizona = priv->arizona;
336 char *name;
337 unsigned int reg;
338 unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
339 unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
340 unsigned int *clk;
341
342 switch (clk_id) {
343 case ARIZONA_CLK_SYSCLK:
344 name = "SYSCLK";
345 reg = ARIZONA_SYSTEM_CLOCK_1;
346 clk = &priv->sysclk;
347 mask |= ARIZONA_SYSCLK_FRAC;
348 break;
349 case ARIZONA_CLK_ASYNCCLK:
350 name = "ASYNCCLK";
351 reg = ARIZONA_ASYNC_CLOCK_1;
352 clk = &priv->asyncclk;
353 break;
Mark Browncbd840d2012-08-08 17:52:44 +0100354 case ARIZONA_CLK_OPCLK:
355 case ARIZONA_CLK_ASYNC_OPCLK:
356 return arizona_set_opclk(codec, clk_id, freq);
Mark Brown07ed8732012-06-18 21:08:44 +0100357 default:
358 return -EINVAL;
359 }
360
361 switch (freq) {
362 case 5644800:
363 case 6144000:
364 break;
365 case 11289600:
366 case 12288000:
367 val |= 1 << ARIZONA_SYSCLK_FREQ_SHIFT;
368 break;
369 case 22579200:
370 case 24576000:
371 val |= 2 << ARIZONA_SYSCLK_FREQ_SHIFT;
372 break;
373 case 45158400:
374 case 49152000:
375 val |= 3 << ARIZONA_SYSCLK_FREQ_SHIFT;
376 break;
377 default:
378 return -EINVAL;
379 }
380
381 *clk = freq;
382
383 if (freq % 6144000)
384 val |= ARIZONA_SYSCLK_FRAC;
385
386 dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
387
388 return regmap_update_bits(arizona->regmap, reg, mask, val);
389}
390EXPORT_SYMBOL_GPL(arizona_set_sysclk);
391
392static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
393{
394 struct snd_soc_codec *codec = dai->codec;
395 int lrclk, bclk, mode, base;
396
397 base = dai->driver->base;
398
399 lrclk = 0;
400 bclk = 0;
401
402 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
403 case SND_SOC_DAIFMT_DSP_A:
404 mode = 0;
405 break;
406 case SND_SOC_DAIFMT_DSP_B:
407 mode = 1;
408 break;
409 case SND_SOC_DAIFMT_I2S:
410 mode = 2;
411 break;
412 case SND_SOC_DAIFMT_LEFT_J:
413 mode = 3;
414 break;
415 default:
416 arizona_aif_err(dai, "Unsupported DAI format %d\n",
417 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
418 return -EINVAL;
419 }
420
421 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
422 case SND_SOC_DAIFMT_CBS_CFS:
423 break;
424 case SND_SOC_DAIFMT_CBS_CFM:
425 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
426 break;
427 case SND_SOC_DAIFMT_CBM_CFS:
428 bclk |= ARIZONA_AIF1_BCLK_MSTR;
429 break;
430 case SND_SOC_DAIFMT_CBM_CFM:
431 bclk |= ARIZONA_AIF1_BCLK_MSTR;
432 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
433 break;
434 default:
435 arizona_aif_err(dai, "Unsupported master mode %d\n",
436 fmt & SND_SOC_DAIFMT_MASTER_MASK);
437 return -EINVAL;
438 }
439
440 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
441 case SND_SOC_DAIFMT_NB_NF:
442 break;
443 case SND_SOC_DAIFMT_IB_IF:
444 bclk |= ARIZONA_AIF1_BCLK_INV;
445 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
446 break;
447 case SND_SOC_DAIFMT_IB_NF:
448 bclk |= ARIZONA_AIF1_BCLK_INV;
449 break;
450 case SND_SOC_DAIFMT_NB_IF:
451 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
452 break;
453 default:
454 return -EINVAL;
455 }
456
457 snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
458 ARIZONA_AIF1_BCLK_INV | ARIZONA_AIF1_BCLK_MSTR,
459 bclk);
460 snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_PIN_CTRL,
461 ARIZONA_AIF1TX_LRCLK_INV |
462 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
463 snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_PIN_CTRL,
464 ARIZONA_AIF1RX_LRCLK_INV |
465 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
466 snd_soc_update_bits(codec, base + ARIZONA_AIF_FORMAT,
467 ARIZONA_AIF1_FMT_MASK, mode);
468
469 return 0;
470}
471
Mark Brown949e6bc2012-07-04 18:58:04 +0100472static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100473 -1,
474 48000,
475 64000,
476 96000,
477 128000,
478 192000,
479 256000,
480 384000,
481 512000,
482 768000,
483 1024000,
484 1536000,
485 2048000,
486 3072000,
487 4096000,
488 6144000,
489 8192000,
490 12288000,
491 24576000,
492};
493
Mark Brown5b2eec32012-07-04 17:32:05 +0100494static const unsigned int arizona_48k_rates[] = {
495 12000,
496 24000,
497 48000,
498 96000,
499 192000,
500 384000,
501 768000,
502 4000,
503 8000,
504 16000,
505 32000,
506 64000,
507 128000,
508 256000,
509 512000,
510};
511
512static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = {
513 .count = ARRAY_SIZE(arizona_48k_rates),
514 .list = arizona_48k_rates,
515};
516
Mark Brown949e6bc2012-07-04 18:58:04 +0100517static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100518 -1,
519 44100,
520 58800,
521 88200,
522 117600,
523 177640,
524 235200,
525 352800,
526 470400,
527 705600,
528 940800,
529 1411200,
530 1881600,
Heather Lomond4758be32012-09-05 05:02:10 -0400531 2822400,
Mark Brown07ed8732012-06-18 21:08:44 +0100532 3763200,
533 5644800,
534 7526400,
535 11289600,
536 22579200,
537};
538
Mark Brown5b2eec32012-07-04 17:32:05 +0100539static const unsigned int arizona_44k1_rates[] = {
540 11025,
541 22050,
542 44100,
543 88200,
544 176400,
545 352800,
546 705600,
547};
548
549static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = {
550 .count = ARRAY_SIZE(arizona_44k1_rates),
551 .list = arizona_44k1_rates,
552};
553
Mark Brown07ed8732012-06-18 21:08:44 +0100554static int arizona_sr_vals[] = {
555 0,
556 12000,
557 24000,
558 48000,
559 96000,
560 192000,
561 384000,
562 768000,
563 0,
564 11025,
565 22050,
566 44100,
567 88200,
568 176400,
569 352800,
570 705600,
571 4000,
572 8000,
573 16000,
574 32000,
575 64000,
576 128000,
577 256000,
578 512000,
579};
580
Mark Brown5b2eec32012-07-04 17:32:05 +0100581static int arizona_startup(struct snd_pcm_substream *substream,
582 struct snd_soc_dai *dai)
583{
584 struct snd_soc_codec *codec = dai->codec;
585 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
586 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
587 const struct snd_pcm_hw_constraint_list *constraint;
588 unsigned int base_rate;
589
590 switch (dai_priv->clk) {
591 case ARIZONA_CLK_SYSCLK:
592 base_rate = priv->sysclk;
593 break;
594 case ARIZONA_CLK_ASYNCCLK:
595 base_rate = priv->asyncclk;
596 break;
597 default:
598 return 0;
599 }
600
601 if (base_rate % 8000)
602 constraint = &arizona_44k1_constraint;
603 else
604 constraint = &arizona_48k_constraint;
605
606 return snd_pcm_hw_constraint_list(substream->runtime, 0,
607 SNDRV_PCM_HW_PARAM_RATE,
608 constraint);
609}
610
Mark Brown07ed8732012-06-18 21:08:44 +0100611static int arizona_hw_params(struct snd_pcm_substream *substream,
612 struct snd_pcm_hw_params *params,
613 struct snd_soc_dai *dai)
614{
615 struct snd_soc_codec *codec = dai->codec;
Mark Brownc013b272012-07-04 20:05:57 +0100616 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
617 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown07ed8732012-06-18 21:08:44 +0100618 int base = dai->driver->base;
619 const int *rates;
620 int i;
621 int bclk, lrclk, wl, frame, sr_val;
622
623 if (params_rate(params) % 8000)
Mark Brown949e6bc2012-07-04 18:58:04 +0100624 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +0100625 else
Mark Brown949e6bc2012-07-04 18:58:04 +0100626 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +0100627
Mark Brown949e6bc2012-07-04 18:58:04 +0100628 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brown50017652012-07-04 19:07:09 +0100629 if (rates[i] >= snd_soc_params_to_bclk(params) &&
630 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +0100631 bclk = i;
632 break;
633 }
634 }
Mark Brown949e6bc2012-07-04 18:58:04 +0100635 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +0100636 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
637 params_rate(params));
638 return -EINVAL;
639 }
640
Mark Brown07ed8732012-06-18 21:08:44 +0100641 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
642 if (arizona_sr_vals[i] == params_rate(params))
643 break;
644 if (i == ARRAY_SIZE(arizona_sr_vals)) {
645 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
646 params_rate(params));
647 return -EINVAL;
648 }
649 sr_val = i;
650
651 lrclk = snd_soc_params_to_bclk(params) / params_rate(params);
652
653 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
654 rates[bclk], rates[bclk] / lrclk);
655
656 wl = snd_pcm_format_width(params_format(params));
657 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl;
658
Mark Brownc013b272012-07-04 20:05:57 +0100659 /*
660 * We will need to be more flexible than this in future,
661 * currently we use a single sample rate for SYSCLK.
662 */
663 switch (dai_priv->clk) {
664 case ARIZONA_CLK_SYSCLK:
665 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
666 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
667 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
668 ARIZONA_AIF1_RATE_MASK, 0);
669 break;
670 case ARIZONA_CLK_ASYNCCLK:
671 snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
672 ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val);
673 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
674 ARIZONA_AIF1_RATE_MASK, 8);
675 break;
676 default:
677 arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
678 return -EINVAL;
679 }
680
Mark Brown07ed8732012-06-18 21:08:44 +0100681 snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
682 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
683 snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_BCLK_RATE,
684 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
685 snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_BCLK_RATE,
686 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
687 snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_1,
688 ARIZONA_AIF1TX_WL_MASK |
689 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
690 snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_2,
691 ARIZONA_AIF1RX_WL_MASK |
692 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
693
694 return 0;
695}
696
Mark Brown410837a2012-07-05 17:26:59 +0100697static const char *arizona_dai_clk_str(int clk_id)
698{
699 switch (clk_id) {
700 case ARIZONA_CLK_SYSCLK:
701 return "SYSCLK";
702 case ARIZONA_CLK_ASYNCCLK:
703 return "ASYNCCLK";
704 default:
705 return "Unknown clock";
706 }
707}
708
Mark Brown5b2eec32012-07-04 17:32:05 +0100709static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
710 int clk_id, unsigned int freq, int dir)
711{
712 struct snd_soc_codec *codec = dai->codec;
713 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
714 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown410837a2012-07-05 17:26:59 +0100715 struct snd_soc_dapm_route routes[2];
Mark Brown5b2eec32012-07-04 17:32:05 +0100716
717 switch (clk_id) {
718 case ARIZONA_CLK_SYSCLK:
719 case ARIZONA_CLK_ASYNCCLK:
720 break;
721 default:
722 return -EINVAL;
723 }
724
Mark Brown410837a2012-07-05 17:26:59 +0100725 if (clk_id == dai_priv->clk)
726 return 0;
727
728 if (dai->active) {
Mark Brown5b2eec32012-07-04 17:32:05 +0100729 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
730 dai->id);
731 return -EBUSY;
732 }
733
Mark Brown410837a2012-07-05 17:26:59 +0100734 memset(&routes, 0, sizeof(routes));
735 routes[0].sink = dai->driver->capture.stream_name;
736 routes[1].sink = dai->driver->playback.stream_name;
Mark Brown5b2eec32012-07-04 17:32:05 +0100737
Mark Brown410837a2012-07-05 17:26:59 +0100738 routes[0].source = arizona_dai_clk_str(dai_priv->clk);
739 routes[1].source = arizona_dai_clk_str(dai_priv->clk);
740 snd_soc_dapm_del_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
741
742 routes[0].source = arizona_dai_clk_str(clk_id);
743 routes[1].source = arizona_dai_clk_str(clk_id);
744 snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
745
746 return snd_soc_dapm_sync(&codec->dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +0100747}
748
Mark Brown07ed8732012-06-18 21:08:44 +0100749const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +0100750 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +0100751 .set_fmt = arizona_set_fmt,
752 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +0100753 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown07ed8732012-06-18 21:08:44 +0100754};
Mark Browna8379872012-07-09 12:16:41 +0100755EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +0100756
Mark Brown5b2eec32012-07-04 17:32:05 +0100757int arizona_init_dai(struct arizona_priv *priv, int id)
758{
759 struct arizona_dai_priv *dai_priv = &priv->dai[id];
760
761 dai_priv->clk = ARIZONA_CLK_SYSCLK;
762
763 return 0;
764}
765EXPORT_SYMBOL_GPL(arizona_init_dai);
766
Mark Brown07ed8732012-06-18 21:08:44 +0100767static irqreturn_t arizona_fll_lock(int irq, void *data)
768{
769 struct arizona_fll *fll = data;
770
Mark Brown6b315952012-09-12 18:44:40 +0800771 arizona_fll_dbg(fll, "Lock status changed\n");
Mark Brown07ed8732012-06-18 21:08:44 +0100772
773 complete(&fll->lock);
774
775 return IRQ_HANDLED;
776}
777
778static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
779{
780 struct arizona_fll *fll = data;
781
782 arizona_fll_dbg(fll, "clock OK\n");
783
784 complete(&fll->ok);
785
786 return IRQ_HANDLED;
787}
788
789static struct {
790 unsigned int min;
791 unsigned int max;
792 u16 fratio;
793 int ratio;
794} fll_fratios[] = {
795 { 0, 64000, 4, 16 },
796 { 64000, 128000, 3, 8 },
797 { 128000, 256000, 2, 4 },
798 { 256000, 1000000, 1, 2 },
799 { 1000000, 13500000, 0, 1 },
800};
801
802struct arizona_fll_cfg {
803 int n;
804 int theta;
805 int lambda;
806 int refdiv;
807 int outdiv;
808 int fratio;
809};
810
811static int arizona_calc_fll(struct arizona_fll *fll,
812 struct arizona_fll_cfg *cfg,
813 unsigned int Fref,
814 unsigned int Fout)
815{
816 unsigned int target, div, gcd_fll;
817 int i, ratio;
818
819 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout);
820
821 /* Fref must be <=13.5MHz */
822 div = 1;
823 cfg->refdiv = 0;
824 while ((Fref / div) > 13500000) {
825 div *= 2;
826 cfg->refdiv++;
827
828 if (div > 8) {
829 arizona_fll_err(fll,
830 "Can't scale %dMHz in to <=13.5MHz\n",
831 Fref);
832 return -EINVAL;
833 }
834 }
835
836 /* Apply the division for our remaining calculations */
837 Fref /= div;
838
Mark Brown2b4d39f2012-07-10 17:03:46 +0100839 /* Fvco should be over the targt; don't check the upper bound */
Mark Brown07ed8732012-06-18 21:08:44 +0100840 div = 1;
Mark Brown2b4d39f2012-07-10 17:03:46 +0100841 while (Fout * div < 90000000 * fll->vco_mult) {
Mark Brown07ed8732012-06-18 21:08:44 +0100842 div++;
843 if (div > 7) {
844 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
845 Fout);
846 return -EINVAL;
847 }
848 }
Mark Brown2b4d39f2012-07-10 17:03:46 +0100849 target = Fout * div / fll->vco_mult;
Mark Brown07ed8732012-06-18 21:08:44 +0100850 cfg->outdiv = div;
851
852 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
853
854 /* Find an appropraite FLL_FRATIO and factor it out of the target */
855 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
856 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
857 cfg->fratio = fll_fratios[i].fratio;
858 ratio = fll_fratios[i].ratio;
859 break;
860 }
861 }
862 if (i == ARRAY_SIZE(fll_fratios)) {
863 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
864 Fref);
865 return -EINVAL;
866 }
867
868 cfg->n = target / (ratio * Fref);
869
870 if (target % Fref) {
871 gcd_fll = gcd(target, ratio * Fref);
872 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
873
874 cfg->theta = (target - (cfg->n * ratio * Fref))
875 / gcd_fll;
876 cfg->lambda = (ratio * Fref) / gcd_fll;
877 } else {
878 cfg->theta = 0;
879 cfg->lambda = 0;
880 }
881
882 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
883 cfg->n, cfg->theta, cfg->lambda);
884 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
885 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
886
887 return 0;
888
889}
890
891static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
892 struct arizona_fll_cfg *cfg, int source)
893{
894 regmap_update_bits(arizona->regmap, base + 3,
895 ARIZONA_FLL1_THETA_MASK, cfg->theta);
896 regmap_update_bits(arizona->regmap, base + 4,
897 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
898 regmap_update_bits(arizona->regmap, base + 5,
899 ARIZONA_FLL1_FRATIO_MASK,
900 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
901 regmap_update_bits(arizona->regmap, base + 6,
902 ARIZONA_FLL1_CLK_REF_DIV_MASK |
903 ARIZONA_FLL1_CLK_REF_SRC_MASK,
904 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
905 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
906
907 regmap_update_bits(arizona->regmap, base + 2,
908 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
909 ARIZONA_FLL1_CTRL_UPD | cfg->n);
910}
911
912int arizona_set_fll(struct arizona_fll *fll, int source,
913 unsigned int Fref, unsigned int Fout)
914{
915 struct arizona *arizona = fll->arizona;
916 struct arizona_fll_cfg cfg, sync;
917 unsigned int reg, val;
918 int syncsrc;
919 bool ena;
920 int ret;
921
922 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
923 if (ret != 0) {
924 arizona_fll_err(fll, "Failed to read current state: %d\n",
925 ret);
926 return ret;
927 }
928 ena = reg & ARIZONA_FLL1_ENA;
929
930 if (Fout) {
931 /* Do we have a 32kHz reference? */
932 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
933 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
934 case ARIZONA_CLK_SRC_MCLK1:
935 case ARIZONA_CLK_SRC_MCLK2:
936 syncsrc = val & ARIZONA_CLK_32K_SRC_MASK;
937 break;
938 default:
939 syncsrc = -1;
940 }
941
942 if (source == syncsrc)
943 syncsrc = -1;
944
945 if (syncsrc >= 0) {
946 ret = arizona_calc_fll(fll, &sync, Fref, Fout);
947 if (ret != 0)
948 return ret;
949
950 ret = arizona_calc_fll(fll, &cfg, 32768, Fout);
951 if (ret != 0)
952 return ret;
953 } else {
954 ret = arizona_calc_fll(fll, &cfg, Fref, Fout);
955 if (ret != 0)
956 return ret;
957 }
958 } else {
959 regmap_update_bits(arizona->regmap, fll->base + 1,
960 ARIZONA_FLL1_ENA, 0);
961 regmap_update_bits(arizona->regmap, fll->base + 0x11,
962 ARIZONA_FLL1_SYNC_ENA, 0);
963
964 if (ena)
965 pm_runtime_put_autosuspend(arizona->dev);
966
967 return 0;
968 }
969
970 regmap_update_bits(arizona->regmap, fll->base + 5,
971 ARIZONA_FLL1_OUTDIV_MASK,
972 cfg.outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
973
974 if (syncsrc >= 0) {
975 arizona_apply_fll(arizona, fll->base, &cfg, syncsrc);
976 arizona_apply_fll(arizona, fll->base + 0x10, &sync, source);
977 } else {
978 arizona_apply_fll(arizona, fll->base, &cfg, source);
979 }
980
981 if (!ena)
982 pm_runtime_get(arizona->dev);
983
984 /* Clear any pending completions */
985 try_wait_for_completion(&fll->ok);
986
987 regmap_update_bits(arizona->regmap, fll->base + 1,
988 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
989 if (syncsrc >= 0)
990 regmap_update_bits(arizona->regmap, fll->base + 0x11,
991 ARIZONA_FLL1_SYNC_ENA,
992 ARIZONA_FLL1_SYNC_ENA);
993
994 ret = wait_for_completion_timeout(&fll->ok,
995 msecs_to_jiffies(25));
996 if (ret == 0)
997 arizona_fll_warn(fll, "Timed out waiting for lock\n");
998
999 return 0;
1000}
1001EXPORT_SYMBOL_GPL(arizona_set_fll);
1002
1003int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
1004 int ok_irq, struct arizona_fll *fll)
1005{
1006 int ret;
1007
1008 init_completion(&fll->lock);
1009 init_completion(&fll->ok);
1010
1011 fll->id = id;
1012 fll->base = base;
1013 fll->arizona = arizona;
1014
1015 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
1016 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
1017 "FLL%d clock OK", id);
1018
1019 ret = arizona_request_irq(arizona, lock_irq, fll->lock_name,
1020 arizona_fll_lock, fll);
1021 if (ret != 0) {
1022 dev_err(arizona->dev, "Failed to get FLL%d lock IRQ: %d\n",
1023 id, ret);
1024 }
1025
1026 ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
1027 arizona_fll_clock_ok, fll);
1028 if (ret != 0) {
1029 dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
1030 id, ret);
1031 }
1032
1033 return 0;
1034}
1035EXPORT_SYMBOL_GPL(arizona_init_fll);
1036
1037MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
1038MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1039MODULE_LICENSE("GPL");