blob: 5e96a0a1669cb46c8b8d7a55101be1c3f3ea8146 [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",
122 "ASRC1L",
123 "ASRC1R",
124 "ASRC2L",
125 "ASRC2R",
126};
127EXPORT_SYMBOL_GPL(arizona_mixer_texts);
128
129int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
130 0x00, /* None */
131 0x04, /* Tone */
132 0x05,
133 0x06, /* Haptics */
134 0x08, /* AEC */
135 0x0c, /* Noise mixer */
136 0x0d, /* Comfort noise */
137 0x10, /* IN1L */
138 0x11,
139 0x12,
140 0x13,
141 0x14,
142 0x15,
Mark Brownc9c56fd2012-07-09 19:09:01 +0100143 0x16,
144 0x17,
Mark Brown07ed8732012-06-18 21:08:44 +0100145 0x20, /* AIF1RX1 */
146 0x21,
147 0x22,
148 0x23,
149 0x24,
150 0x25,
151 0x26,
152 0x27,
153 0x28, /* AIF2RX1 */
154 0x29,
155 0x30, /* AIF3RX1 */
156 0x31,
157 0x38, /* SLIMRX1 */
158 0x39,
159 0x3a,
160 0x3b,
161 0x3c,
162 0x3d,
163 0x3e,
164 0x3f,
165 0x50, /* EQ1 */
166 0x51,
167 0x52,
168 0x53,
169 0x58, /* DRC1L */
170 0x59,
171 0x5a,
172 0x5b,
173 0x60, /* LHPF1 */
174 0x61,
175 0x62,
176 0x63,
177 0x68, /* DSP1.1 */
178 0x69,
179 0x6a,
180 0x6b,
181 0x6c,
182 0x6d,
183 0x90, /* ASRC1L */
184 0x91,
185 0x92,
186 0x93,
187};
188EXPORT_SYMBOL_GPL(arizona_mixer_values);
189
190const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
191EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
192
193static const char *arizona_lhpf_mode_text[] = {
194 "Low-pass", "High-pass"
195};
196
197const struct soc_enum arizona_lhpf1_mode =
198 SOC_ENUM_SINGLE(ARIZONA_HPLPF1_1, ARIZONA_LHPF1_MODE_SHIFT, 2,
199 arizona_lhpf_mode_text);
200EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
201
202const struct soc_enum arizona_lhpf2_mode =
203 SOC_ENUM_SINGLE(ARIZONA_HPLPF2_1, ARIZONA_LHPF2_MODE_SHIFT, 2,
204 arizona_lhpf_mode_text);
205EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
206
207const struct soc_enum arizona_lhpf3_mode =
208 SOC_ENUM_SINGLE(ARIZONA_HPLPF3_1, ARIZONA_LHPF3_MODE_SHIFT, 2,
209 arizona_lhpf_mode_text);
210EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
211
212const struct soc_enum arizona_lhpf4_mode =
213 SOC_ENUM_SINGLE(ARIZONA_HPLPF4_1, ARIZONA_LHPF4_MODE_SHIFT, 2,
214 arizona_lhpf_mode_text);
215EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
216
217int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
218 int event)
219{
220 return 0;
221}
222EXPORT_SYMBOL_GPL(arizona_in_ev);
223
224int arizona_out_ev(struct snd_soc_dapm_widget *w,
225 struct snd_kcontrol *kcontrol,
226 int event)
227{
228 return 0;
229}
230EXPORT_SYMBOL_GPL(arizona_out_ev);
231
Mark Browncbd840d2012-08-08 17:52:44 +0100232static unsigned int arizona_sysclk_48k_rates[] = {
233 6144000,
234 12288000,
235 22579200,
236 49152000,
237};
238
239static unsigned int arizona_sysclk_44k1_rates[] = {
240 5644800,
241 11289600,
242 24576000,
243 45158400,
244};
245
246static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
247 unsigned int freq)
248{
249 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
250 unsigned int reg;
251 unsigned int *rates;
252 int ref, div, refclk;
253
254 switch (clk) {
255 case ARIZONA_CLK_OPCLK:
256 reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
257 refclk = priv->sysclk;
258 break;
259 case ARIZONA_CLK_ASYNC_OPCLK:
260 reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
261 refclk = priv->asyncclk;
262 break;
263 default:
264 return -EINVAL;
265 }
266
267 if (refclk % 8000)
268 rates = arizona_sysclk_44k1_rates;
269 else
270 rates = arizona_sysclk_48k_rates;
271
272 for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) &&
273 rates[ref] <= refclk; ref++) {
274 div = 1;
275 while (rates[ref] / div >= freq && div < 32) {
276 if (rates[ref] / div == freq) {
277 dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
278 freq);
279 snd_soc_update_bits(codec, reg,
280 ARIZONA_OPCLK_DIV_MASK |
281 ARIZONA_OPCLK_SEL_MASK,
282 (div <<
283 ARIZONA_OPCLK_DIV_SHIFT) |
284 ref);
285 return 0;
286 }
287 div++;
288 }
289 }
290
291 dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
292 return -EINVAL;
293}
294
Mark Brown07ed8732012-06-18 21:08:44 +0100295int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
296 int source, unsigned int freq, int dir)
297{
298 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
299 struct arizona *arizona = priv->arizona;
300 char *name;
301 unsigned int reg;
302 unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
303 unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
304 unsigned int *clk;
305
306 switch (clk_id) {
307 case ARIZONA_CLK_SYSCLK:
308 name = "SYSCLK";
309 reg = ARIZONA_SYSTEM_CLOCK_1;
310 clk = &priv->sysclk;
311 mask |= ARIZONA_SYSCLK_FRAC;
312 break;
313 case ARIZONA_CLK_ASYNCCLK:
314 name = "ASYNCCLK";
315 reg = ARIZONA_ASYNC_CLOCK_1;
316 clk = &priv->asyncclk;
317 break;
Mark Browncbd840d2012-08-08 17:52:44 +0100318 case ARIZONA_CLK_OPCLK:
319 case ARIZONA_CLK_ASYNC_OPCLK:
320 return arizona_set_opclk(codec, clk_id, freq);
Mark Brown07ed8732012-06-18 21:08:44 +0100321 default:
322 return -EINVAL;
323 }
324
325 switch (freq) {
326 case 5644800:
327 case 6144000:
328 break;
329 case 11289600:
330 case 12288000:
331 val |= 1 << ARIZONA_SYSCLK_FREQ_SHIFT;
332 break;
333 case 22579200:
334 case 24576000:
335 val |= 2 << ARIZONA_SYSCLK_FREQ_SHIFT;
336 break;
337 case 45158400:
338 case 49152000:
339 val |= 3 << ARIZONA_SYSCLK_FREQ_SHIFT;
340 break;
341 default:
342 return -EINVAL;
343 }
344
345 *clk = freq;
346
347 if (freq % 6144000)
348 val |= ARIZONA_SYSCLK_FRAC;
349
350 dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
351
352 return regmap_update_bits(arizona->regmap, reg, mask, val);
353}
354EXPORT_SYMBOL_GPL(arizona_set_sysclk);
355
356static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
357{
358 struct snd_soc_codec *codec = dai->codec;
359 int lrclk, bclk, mode, base;
360
361 base = dai->driver->base;
362
363 lrclk = 0;
364 bclk = 0;
365
366 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
367 case SND_SOC_DAIFMT_DSP_A:
368 mode = 0;
369 break;
370 case SND_SOC_DAIFMT_DSP_B:
371 mode = 1;
372 break;
373 case SND_SOC_DAIFMT_I2S:
374 mode = 2;
375 break;
376 case SND_SOC_DAIFMT_LEFT_J:
377 mode = 3;
378 break;
379 default:
380 arizona_aif_err(dai, "Unsupported DAI format %d\n",
381 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
382 return -EINVAL;
383 }
384
385 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
386 case SND_SOC_DAIFMT_CBS_CFS:
387 break;
388 case SND_SOC_DAIFMT_CBS_CFM:
389 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
390 break;
391 case SND_SOC_DAIFMT_CBM_CFS:
392 bclk |= ARIZONA_AIF1_BCLK_MSTR;
393 break;
394 case SND_SOC_DAIFMT_CBM_CFM:
395 bclk |= ARIZONA_AIF1_BCLK_MSTR;
396 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
397 break;
398 default:
399 arizona_aif_err(dai, "Unsupported master mode %d\n",
400 fmt & SND_SOC_DAIFMT_MASTER_MASK);
401 return -EINVAL;
402 }
403
404 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
405 case SND_SOC_DAIFMT_NB_NF:
406 break;
407 case SND_SOC_DAIFMT_IB_IF:
408 bclk |= ARIZONA_AIF1_BCLK_INV;
409 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
410 break;
411 case SND_SOC_DAIFMT_IB_NF:
412 bclk |= ARIZONA_AIF1_BCLK_INV;
413 break;
414 case SND_SOC_DAIFMT_NB_IF:
415 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
416 break;
417 default:
418 return -EINVAL;
419 }
420
421 snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
422 ARIZONA_AIF1_BCLK_INV | ARIZONA_AIF1_BCLK_MSTR,
423 bclk);
424 snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_PIN_CTRL,
425 ARIZONA_AIF1TX_LRCLK_INV |
426 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
427 snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_PIN_CTRL,
428 ARIZONA_AIF1RX_LRCLK_INV |
429 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
430 snd_soc_update_bits(codec, base + ARIZONA_AIF_FORMAT,
431 ARIZONA_AIF1_FMT_MASK, mode);
432
433 return 0;
434}
435
Mark Brown949e6bc2012-07-04 18:58:04 +0100436static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100437 -1,
438 48000,
439 64000,
440 96000,
441 128000,
442 192000,
443 256000,
444 384000,
445 512000,
446 768000,
447 1024000,
448 1536000,
449 2048000,
450 3072000,
451 4096000,
452 6144000,
453 8192000,
454 12288000,
455 24576000,
456};
457
Mark Brown5b2eec32012-07-04 17:32:05 +0100458static const unsigned int arizona_48k_rates[] = {
459 12000,
460 24000,
461 48000,
462 96000,
463 192000,
464 384000,
465 768000,
466 4000,
467 8000,
468 16000,
469 32000,
470 64000,
471 128000,
472 256000,
473 512000,
474};
475
476static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = {
477 .count = ARRAY_SIZE(arizona_48k_rates),
478 .list = arizona_48k_rates,
479};
480
Mark Brown949e6bc2012-07-04 18:58:04 +0100481static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100482 -1,
483 44100,
484 58800,
485 88200,
486 117600,
487 177640,
488 235200,
489 352800,
490 470400,
491 705600,
492 940800,
493 1411200,
494 1881600,
495 2882400,
496 3763200,
497 5644800,
498 7526400,
499 11289600,
500 22579200,
501};
502
Mark Brown5b2eec32012-07-04 17:32:05 +0100503static const unsigned int arizona_44k1_rates[] = {
504 11025,
505 22050,
506 44100,
507 88200,
508 176400,
509 352800,
510 705600,
511};
512
513static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = {
514 .count = ARRAY_SIZE(arizona_44k1_rates),
515 .list = arizona_44k1_rates,
516};
517
Mark Brown07ed8732012-06-18 21:08:44 +0100518static int arizona_sr_vals[] = {
519 0,
520 12000,
521 24000,
522 48000,
523 96000,
524 192000,
525 384000,
526 768000,
527 0,
528 11025,
529 22050,
530 44100,
531 88200,
532 176400,
533 352800,
534 705600,
535 4000,
536 8000,
537 16000,
538 32000,
539 64000,
540 128000,
541 256000,
542 512000,
543};
544
Mark Brown5b2eec32012-07-04 17:32:05 +0100545static int arizona_startup(struct snd_pcm_substream *substream,
546 struct snd_soc_dai *dai)
547{
548 struct snd_soc_codec *codec = dai->codec;
549 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
550 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
551 const struct snd_pcm_hw_constraint_list *constraint;
552 unsigned int base_rate;
553
554 switch (dai_priv->clk) {
555 case ARIZONA_CLK_SYSCLK:
556 base_rate = priv->sysclk;
557 break;
558 case ARIZONA_CLK_ASYNCCLK:
559 base_rate = priv->asyncclk;
560 break;
561 default:
562 return 0;
563 }
564
565 if (base_rate % 8000)
566 constraint = &arizona_44k1_constraint;
567 else
568 constraint = &arizona_48k_constraint;
569
570 return snd_pcm_hw_constraint_list(substream->runtime, 0,
571 SNDRV_PCM_HW_PARAM_RATE,
572 constraint);
573}
574
Mark Brown07ed8732012-06-18 21:08:44 +0100575static int arizona_hw_params(struct snd_pcm_substream *substream,
576 struct snd_pcm_hw_params *params,
577 struct snd_soc_dai *dai)
578{
579 struct snd_soc_codec *codec = dai->codec;
Mark Brownc013b272012-07-04 20:05:57 +0100580 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
581 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown07ed8732012-06-18 21:08:44 +0100582 int base = dai->driver->base;
583 const int *rates;
584 int i;
585 int bclk, lrclk, wl, frame, sr_val;
586
587 if (params_rate(params) % 8000)
Mark Brown949e6bc2012-07-04 18:58:04 +0100588 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +0100589 else
Mark Brown949e6bc2012-07-04 18:58:04 +0100590 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +0100591
Mark Brown949e6bc2012-07-04 18:58:04 +0100592 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brown50017652012-07-04 19:07:09 +0100593 if (rates[i] >= snd_soc_params_to_bclk(params) &&
594 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +0100595 bclk = i;
596 break;
597 }
598 }
Mark Brown949e6bc2012-07-04 18:58:04 +0100599 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +0100600 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
601 params_rate(params));
602 return -EINVAL;
603 }
604
Mark Brown07ed8732012-06-18 21:08:44 +0100605 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
606 if (arizona_sr_vals[i] == params_rate(params))
607 break;
608 if (i == ARRAY_SIZE(arizona_sr_vals)) {
609 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
610 params_rate(params));
611 return -EINVAL;
612 }
613 sr_val = i;
614
615 lrclk = snd_soc_params_to_bclk(params) / params_rate(params);
616
617 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
618 rates[bclk], rates[bclk] / lrclk);
619
620 wl = snd_pcm_format_width(params_format(params));
621 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl;
622
Mark Brownc013b272012-07-04 20:05:57 +0100623 /*
624 * We will need to be more flexible than this in future,
625 * currently we use a single sample rate for SYSCLK.
626 */
627 switch (dai_priv->clk) {
628 case ARIZONA_CLK_SYSCLK:
629 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
630 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
631 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
632 ARIZONA_AIF1_RATE_MASK, 0);
633 break;
634 case ARIZONA_CLK_ASYNCCLK:
635 snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
636 ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val);
637 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
638 ARIZONA_AIF1_RATE_MASK, 8);
639 break;
640 default:
641 arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
642 return -EINVAL;
643 }
644
Mark Brown07ed8732012-06-18 21:08:44 +0100645 snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
646 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
647 snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_BCLK_RATE,
648 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
649 snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_BCLK_RATE,
650 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
651 snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_1,
652 ARIZONA_AIF1TX_WL_MASK |
653 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
654 snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_2,
655 ARIZONA_AIF1RX_WL_MASK |
656 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
657
658 return 0;
659}
660
Mark Brown410837a2012-07-05 17:26:59 +0100661static const char *arizona_dai_clk_str(int clk_id)
662{
663 switch (clk_id) {
664 case ARIZONA_CLK_SYSCLK:
665 return "SYSCLK";
666 case ARIZONA_CLK_ASYNCCLK:
667 return "ASYNCCLK";
668 default:
669 return "Unknown clock";
670 }
671}
672
Mark Brown5b2eec32012-07-04 17:32:05 +0100673static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
674 int clk_id, unsigned int freq, int dir)
675{
676 struct snd_soc_codec *codec = dai->codec;
677 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
678 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown410837a2012-07-05 17:26:59 +0100679 struct snd_soc_dapm_route routes[2];
Mark Brown5b2eec32012-07-04 17:32:05 +0100680
681 switch (clk_id) {
682 case ARIZONA_CLK_SYSCLK:
683 case ARIZONA_CLK_ASYNCCLK:
684 break;
685 default:
686 return -EINVAL;
687 }
688
Mark Brown410837a2012-07-05 17:26:59 +0100689 if (clk_id == dai_priv->clk)
690 return 0;
691
692 if (dai->active) {
Mark Brown5b2eec32012-07-04 17:32:05 +0100693 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
694 dai->id);
695 return -EBUSY;
696 }
697
Mark Brown410837a2012-07-05 17:26:59 +0100698 memset(&routes, 0, sizeof(routes));
699 routes[0].sink = dai->driver->capture.stream_name;
700 routes[1].sink = dai->driver->playback.stream_name;
Mark Brown5b2eec32012-07-04 17:32:05 +0100701
Mark Brown410837a2012-07-05 17:26:59 +0100702 routes[0].source = arizona_dai_clk_str(dai_priv->clk);
703 routes[1].source = arizona_dai_clk_str(dai_priv->clk);
704 snd_soc_dapm_del_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
705
706 routes[0].source = arizona_dai_clk_str(clk_id);
707 routes[1].source = arizona_dai_clk_str(clk_id);
708 snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
709
710 return snd_soc_dapm_sync(&codec->dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +0100711}
712
Mark Brown07ed8732012-06-18 21:08:44 +0100713const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +0100714 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +0100715 .set_fmt = arizona_set_fmt,
716 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +0100717 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown07ed8732012-06-18 21:08:44 +0100718};
Mark Browna8379872012-07-09 12:16:41 +0100719EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +0100720
Mark Brown5b2eec32012-07-04 17:32:05 +0100721int arizona_init_dai(struct arizona_priv *priv, int id)
722{
723 struct arizona_dai_priv *dai_priv = &priv->dai[id];
724
725 dai_priv->clk = ARIZONA_CLK_SYSCLK;
726
727 return 0;
728}
729EXPORT_SYMBOL_GPL(arizona_init_dai);
730
Mark Brown07ed8732012-06-18 21:08:44 +0100731static irqreturn_t arizona_fll_lock(int irq, void *data)
732{
733 struct arizona_fll *fll = data;
734
735 arizona_fll_dbg(fll, "Locked\n");
736
737 complete(&fll->lock);
738
739 return IRQ_HANDLED;
740}
741
742static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
743{
744 struct arizona_fll *fll = data;
745
746 arizona_fll_dbg(fll, "clock OK\n");
747
748 complete(&fll->ok);
749
750 return IRQ_HANDLED;
751}
752
753static struct {
754 unsigned int min;
755 unsigned int max;
756 u16 fratio;
757 int ratio;
758} fll_fratios[] = {
759 { 0, 64000, 4, 16 },
760 { 64000, 128000, 3, 8 },
761 { 128000, 256000, 2, 4 },
762 { 256000, 1000000, 1, 2 },
763 { 1000000, 13500000, 0, 1 },
764};
765
766struct arizona_fll_cfg {
767 int n;
768 int theta;
769 int lambda;
770 int refdiv;
771 int outdiv;
772 int fratio;
773};
774
775static int arizona_calc_fll(struct arizona_fll *fll,
776 struct arizona_fll_cfg *cfg,
777 unsigned int Fref,
778 unsigned int Fout)
779{
780 unsigned int target, div, gcd_fll;
781 int i, ratio;
782
783 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout);
784
785 /* Fref must be <=13.5MHz */
786 div = 1;
787 cfg->refdiv = 0;
788 while ((Fref / div) > 13500000) {
789 div *= 2;
790 cfg->refdiv++;
791
792 if (div > 8) {
793 arizona_fll_err(fll,
794 "Can't scale %dMHz in to <=13.5MHz\n",
795 Fref);
796 return -EINVAL;
797 }
798 }
799
800 /* Apply the division for our remaining calculations */
801 Fref /= div;
802
Mark Brown2b4d39f2012-07-10 17:03:46 +0100803 /* Fvco should be over the targt; don't check the upper bound */
Mark Brown07ed8732012-06-18 21:08:44 +0100804 div = 1;
Mark Brown2b4d39f2012-07-10 17:03:46 +0100805 while (Fout * div < 90000000 * fll->vco_mult) {
Mark Brown07ed8732012-06-18 21:08:44 +0100806 div++;
807 if (div > 7) {
808 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
809 Fout);
810 return -EINVAL;
811 }
812 }
Mark Brown2b4d39f2012-07-10 17:03:46 +0100813 target = Fout * div / fll->vco_mult;
Mark Brown07ed8732012-06-18 21:08:44 +0100814 cfg->outdiv = div;
815
816 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
817
818 /* Find an appropraite FLL_FRATIO and factor it out of the target */
819 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
820 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
821 cfg->fratio = fll_fratios[i].fratio;
822 ratio = fll_fratios[i].ratio;
823 break;
824 }
825 }
826 if (i == ARRAY_SIZE(fll_fratios)) {
827 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
828 Fref);
829 return -EINVAL;
830 }
831
832 cfg->n = target / (ratio * Fref);
833
834 if (target % Fref) {
835 gcd_fll = gcd(target, ratio * Fref);
836 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
837
838 cfg->theta = (target - (cfg->n * ratio * Fref))
839 / gcd_fll;
840 cfg->lambda = (ratio * Fref) / gcd_fll;
841 } else {
842 cfg->theta = 0;
843 cfg->lambda = 0;
844 }
845
846 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
847 cfg->n, cfg->theta, cfg->lambda);
848 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
849 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
850
851 return 0;
852
853}
854
855static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
856 struct arizona_fll_cfg *cfg, int source)
857{
858 regmap_update_bits(arizona->regmap, base + 3,
859 ARIZONA_FLL1_THETA_MASK, cfg->theta);
860 regmap_update_bits(arizona->regmap, base + 4,
861 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
862 regmap_update_bits(arizona->regmap, base + 5,
863 ARIZONA_FLL1_FRATIO_MASK,
864 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
865 regmap_update_bits(arizona->regmap, base + 6,
866 ARIZONA_FLL1_CLK_REF_DIV_MASK |
867 ARIZONA_FLL1_CLK_REF_SRC_MASK,
868 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
869 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
870
871 regmap_update_bits(arizona->regmap, base + 2,
872 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
873 ARIZONA_FLL1_CTRL_UPD | cfg->n);
874}
875
876int arizona_set_fll(struct arizona_fll *fll, int source,
877 unsigned int Fref, unsigned int Fout)
878{
879 struct arizona *arizona = fll->arizona;
880 struct arizona_fll_cfg cfg, sync;
881 unsigned int reg, val;
882 int syncsrc;
883 bool ena;
884 int ret;
885
886 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
887 if (ret != 0) {
888 arizona_fll_err(fll, "Failed to read current state: %d\n",
889 ret);
890 return ret;
891 }
892 ena = reg & ARIZONA_FLL1_ENA;
893
894 if (Fout) {
895 /* Do we have a 32kHz reference? */
896 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
897 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
898 case ARIZONA_CLK_SRC_MCLK1:
899 case ARIZONA_CLK_SRC_MCLK2:
900 syncsrc = val & ARIZONA_CLK_32K_SRC_MASK;
901 break;
902 default:
903 syncsrc = -1;
904 }
905
906 if (source == syncsrc)
907 syncsrc = -1;
908
909 if (syncsrc >= 0) {
910 ret = arizona_calc_fll(fll, &sync, Fref, Fout);
911 if (ret != 0)
912 return ret;
913
914 ret = arizona_calc_fll(fll, &cfg, 32768, Fout);
915 if (ret != 0)
916 return ret;
917 } else {
918 ret = arizona_calc_fll(fll, &cfg, Fref, Fout);
919 if (ret != 0)
920 return ret;
921 }
922 } else {
923 regmap_update_bits(arizona->regmap, fll->base + 1,
924 ARIZONA_FLL1_ENA, 0);
925 regmap_update_bits(arizona->regmap, fll->base + 0x11,
926 ARIZONA_FLL1_SYNC_ENA, 0);
927
928 if (ena)
929 pm_runtime_put_autosuspend(arizona->dev);
930
931 return 0;
932 }
933
934 regmap_update_bits(arizona->regmap, fll->base + 5,
935 ARIZONA_FLL1_OUTDIV_MASK,
936 cfg.outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
937
938 if (syncsrc >= 0) {
939 arizona_apply_fll(arizona, fll->base, &cfg, syncsrc);
940 arizona_apply_fll(arizona, fll->base + 0x10, &sync, source);
941 } else {
942 arizona_apply_fll(arizona, fll->base, &cfg, source);
943 }
944
945 if (!ena)
946 pm_runtime_get(arizona->dev);
947
948 /* Clear any pending completions */
949 try_wait_for_completion(&fll->ok);
950
951 regmap_update_bits(arizona->regmap, fll->base + 1,
952 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
953 if (syncsrc >= 0)
954 regmap_update_bits(arizona->regmap, fll->base + 0x11,
955 ARIZONA_FLL1_SYNC_ENA,
956 ARIZONA_FLL1_SYNC_ENA);
957
958 ret = wait_for_completion_timeout(&fll->ok,
959 msecs_to_jiffies(25));
960 if (ret == 0)
961 arizona_fll_warn(fll, "Timed out waiting for lock\n");
962
963 return 0;
964}
965EXPORT_SYMBOL_GPL(arizona_set_fll);
966
967int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
968 int ok_irq, struct arizona_fll *fll)
969{
970 int ret;
971
972 init_completion(&fll->lock);
973 init_completion(&fll->ok);
974
975 fll->id = id;
976 fll->base = base;
977 fll->arizona = arizona;
978
979 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
980 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
981 "FLL%d clock OK", id);
982
983 ret = arizona_request_irq(arizona, lock_irq, fll->lock_name,
984 arizona_fll_lock, fll);
985 if (ret != 0) {
986 dev_err(arizona->dev, "Failed to get FLL%d lock IRQ: %d\n",
987 id, ret);
988 }
989
990 ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
991 arizona_fll_clock_ok, fll);
992 if (ret != 0) {
993 dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
994 id, ret);
995 }
996
997 return 0;
998}
999EXPORT_SYMBOL_GPL(arizona_init_fll);
1000
1001MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
1002MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1003MODULE_LICENSE("GPL");