blob: 38248a7a95e3e38777578fe7bf98970246edaead [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
Mark Browne853a002012-12-09 12:25:52 +0900229static const char *arizona_vol_ramp_text[] = {
230 "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
231 "15ms/6dB", "30ms/6dB",
232};
233
234const struct soc_enum arizona_in_vd_ramp =
235 SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP,
236 ARIZONA_IN_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text);
237EXPORT_SYMBOL_GPL(arizona_in_vd_ramp);
238
239const struct soc_enum arizona_in_vi_ramp =
240 SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP,
241 ARIZONA_IN_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text);
242EXPORT_SYMBOL_GPL(arizona_in_vi_ramp);
243
244const struct soc_enum arizona_out_vd_ramp =
245 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP,
246 ARIZONA_OUT_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text);
247EXPORT_SYMBOL_GPL(arizona_out_vd_ramp);
248
249const struct soc_enum arizona_out_vi_ramp =
250 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP,
251 ARIZONA_OUT_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text);
252EXPORT_SYMBOL_GPL(arizona_out_vi_ramp);
253
Mark Brown07ed8732012-06-18 21:08:44 +0100254static const char *arizona_lhpf_mode_text[] = {
255 "Low-pass", "High-pass"
256};
257
258const struct soc_enum arizona_lhpf1_mode =
259 SOC_ENUM_SINGLE(ARIZONA_HPLPF1_1, ARIZONA_LHPF1_MODE_SHIFT, 2,
260 arizona_lhpf_mode_text);
261EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
262
263const struct soc_enum arizona_lhpf2_mode =
264 SOC_ENUM_SINGLE(ARIZONA_HPLPF2_1, ARIZONA_LHPF2_MODE_SHIFT, 2,
265 arizona_lhpf_mode_text);
266EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
267
268const struct soc_enum arizona_lhpf3_mode =
269 SOC_ENUM_SINGLE(ARIZONA_HPLPF3_1, ARIZONA_LHPF3_MODE_SHIFT, 2,
270 arizona_lhpf_mode_text);
271EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
272
273const struct soc_enum arizona_lhpf4_mode =
274 SOC_ENUM_SINGLE(ARIZONA_HPLPF4_1, ARIZONA_LHPF4_MODE_SHIFT, 2,
275 arizona_lhpf_mode_text);
276EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
277
278int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
279 int event)
280{
281 return 0;
282}
283EXPORT_SYMBOL_GPL(arizona_in_ev);
284
285int arizona_out_ev(struct snd_soc_dapm_widget *w,
286 struct snd_kcontrol *kcontrol,
287 int event)
288{
289 return 0;
290}
291EXPORT_SYMBOL_GPL(arizona_out_ev);
292
Mark Browncbd840d2012-08-08 17:52:44 +0100293static unsigned int arizona_sysclk_48k_rates[] = {
294 6144000,
295 12288000,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000296 24576000,
Mark Browncbd840d2012-08-08 17:52:44 +0100297 49152000,
Mark Brownaeaeee12012-09-26 17:50:02 +0100298 73728000,
299 98304000,
300 147456000,
Mark Browncbd840d2012-08-08 17:52:44 +0100301};
302
303static unsigned int arizona_sysclk_44k1_rates[] = {
304 5644800,
305 11289600,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000306 22579200,
Mark Browncbd840d2012-08-08 17:52:44 +0100307 45158400,
Mark Brownaeaeee12012-09-26 17:50:02 +0100308 67737600,
309 90316800,
310 135475200,
Mark Browncbd840d2012-08-08 17:52:44 +0100311};
312
313static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
314 unsigned int freq)
315{
316 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
317 unsigned int reg;
318 unsigned int *rates;
319 int ref, div, refclk;
320
321 switch (clk) {
322 case ARIZONA_CLK_OPCLK:
323 reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
324 refclk = priv->sysclk;
325 break;
326 case ARIZONA_CLK_ASYNC_OPCLK:
327 reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
328 refclk = priv->asyncclk;
329 break;
330 default:
331 return -EINVAL;
332 }
333
334 if (refclk % 8000)
335 rates = arizona_sysclk_44k1_rates;
336 else
337 rates = arizona_sysclk_48k_rates;
338
339 for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) &&
340 rates[ref] <= refclk; ref++) {
341 div = 1;
342 while (rates[ref] / div >= freq && div < 32) {
343 if (rates[ref] / div == freq) {
344 dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
345 freq);
346 snd_soc_update_bits(codec, reg,
347 ARIZONA_OPCLK_DIV_MASK |
348 ARIZONA_OPCLK_SEL_MASK,
349 (div <<
350 ARIZONA_OPCLK_DIV_SHIFT) |
351 ref);
352 return 0;
353 }
354 div++;
355 }
356 }
357
358 dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
359 return -EINVAL;
360}
361
Mark Brown07ed8732012-06-18 21:08:44 +0100362int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
363 int source, unsigned int freq, int dir)
364{
365 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
366 struct arizona *arizona = priv->arizona;
367 char *name;
368 unsigned int reg;
369 unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
370 unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
371 unsigned int *clk;
372
373 switch (clk_id) {
374 case ARIZONA_CLK_SYSCLK:
375 name = "SYSCLK";
376 reg = ARIZONA_SYSTEM_CLOCK_1;
377 clk = &priv->sysclk;
378 mask |= ARIZONA_SYSCLK_FRAC;
379 break;
380 case ARIZONA_CLK_ASYNCCLK:
381 name = "ASYNCCLK";
382 reg = ARIZONA_ASYNC_CLOCK_1;
383 clk = &priv->asyncclk;
384 break;
Mark Browncbd840d2012-08-08 17:52:44 +0100385 case ARIZONA_CLK_OPCLK:
386 case ARIZONA_CLK_ASYNC_OPCLK:
387 return arizona_set_opclk(codec, clk_id, freq);
Mark Brown07ed8732012-06-18 21:08:44 +0100388 default:
389 return -EINVAL;
390 }
391
392 switch (freq) {
393 case 5644800:
394 case 6144000:
395 break;
396 case 11289600:
397 case 12288000:
398 val |= 1 << ARIZONA_SYSCLK_FREQ_SHIFT;
399 break;
400 case 22579200:
401 case 24576000:
402 val |= 2 << ARIZONA_SYSCLK_FREQ_SHIFT;
403 break;
404 case 45158400:
405 case 49152000:
406 val |= 3 << ARIZONA_SYSCLK_FREQ_SHIFT;
407 break;
Mark Brown38113362012-11-26 16:01:37 +0000408 case 67737600:
409 case 73728000:
410 val |= 4 << ARIZONA_SYSCLK_FREQ_SHIFT;
411 break;
412 case 90316800:
413 case 98304000:
414 val |= 5 << ARIZONA_SYSCLK_FREQ_SHIFT;
415 break;
416 case 135475200:
417 case 147456000:
418 val |= 6 << ARIZONA_SYSCLK_FREQ_SHIFT;
419 break;
Mark Brown07ed8732012-06-18 21:08:44 +0100420 default:
421 return -EINVAL;
422 }
423
424 *clk = freq;
425
426 if (freq % 6144000)
427 val |= ARIZONA_SYSCLK_FRAC;
428
429 dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
430
431 return regmap_update_bits(arizona->regmap, reg, mask, val);
432}
433EXPORT_SYMBOL_GPL(arizona_set_sysclk);
434
435static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
436{
437 struct snd_soc_codec *codec = dai->codec;
438 int lrclk, bclk, mode, base;
439
440 base = dai->driver->base;
441
442 lrclk = 0;
443 bclk = 0;
444
445 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
446 case SND_SOC_DAIFMT_DSP_A:
447 mode = 0;
448 break;
449 case SND_SOC_DAIFMT_DSP_B:
450 mode = 1;
451 break;
452 case SND_SOC_DAIFMT_I2S:
453 mode = 2;
454 break;
455 case SND_SOC_DAIFMT_LEFT_J:
456 mode = 3;
457 break;
458 default:
459 arizona_aif_err(dai, "Unsupported DAI format %d\n",
460 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
461 return -EINVAL;
462 }
463
464 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
465 case SND_SOC_DAIFMT_CBS_CFS:
466 break;
467 case SND_SOC_DAIFMT_CBS_CFM:
468 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
469 break;
470 case SND_SOC_DAIFMT_CBM_CFS:
471 bclk |= ARIZONA_AIF1_BCLK_MSTR;
472 break;
473 case SND_SOC_DAIFMT_CBM_CFM:
474 bclk |= ARIZONA_AIF1_BCLK_MSTR;
475 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
476 break;
477 default:
478 arizona_aif_err(dai, "Unsupported master mode %d\n",
479 fmt & SND_SOC_DAIFMT_MASTER_MASK);
480 return -EINVAL;
481 }
482
483 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
484 case SND_SOC_DAIFMT_NB_NF:
485 break;
486 case SND_SOC_DAIFMT_IB_IF:
487 bclk |= ARIZONA_AIF1_BCLK_INV;
488 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
489 break;
490 case SND_SOC_DAIFMT_IB_NF:
491 bclk |= ARIZONA_AIF1_BCLK_INV;
492 break;
493 case SND_SOC_DAIFMT_NB_IF:
494 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
495 break;
496 default:
497 return -EINVAL;
498 }
499
500 snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
501 ARIZONA_AIF1_BCLK_INV | ARIZONA_AIF1_BCLK_MSTR,
502 bclk);
503 snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_PIN_CTRL,
504 ARIZONA_AIF1TX_LRCLK_INV |
505 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
506 snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_PIN_CTRL,
507 ARIZONA_AIF1RX_LRCLK_INV |
508 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
509 snd_soc_update_bits(codec, base + ARIZONA_AIF_FORMAT,
510 ARIZONA_AIF1_FMT_MASK, mode);
511
512 return 0;
513}
514
Mark Brown949e6bc2012-07-04 18:58:04 +0100515static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100516 -1,
517 48000,
518 64000,
519 96000,
520 128000,
521 192000,
522 256000,
523 384000,
524 512000,
525 768000,
526 1024000,
527 1536000,
528 2048000,
529 3072000,
530 4096000,
531 6144000,
532 8192000,
533 12288000,
534 24576000,
535};
536
Mark Brown5b2eec32012-07-04 17:32:05 +0100537static const unsigned int arizona_48k_rates[] = {
538 12000,
539 24000,
540 48000,
541 96000,
542 192000,
543 384000,
544 768000,
545 4000,
546 8000,
547 16000,
548 32000,
549 64000,
550 128000,
551 256000,
552 512000,
553};
554
555static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = {
556 .count = ARRAY_SIZE(arizona_48k_rates),
557 .list = arizona_48k_rates,
558};
559
Mark Brown949e6bc2012-07-04 18:58:04 +0100560static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100561 -1,
562 44100,
563 58800,
564 88200,
565 117600,
566 177640,
567 235200,
568 352800,
569 470400,
570 705600,
571 940800,
572 1411200,
573 1881600,
Heather Lomond4758be32012-09-05 05:02:10 -0400574 2822400,
Mark Brown07ed8732012-06-18 21:08:44 +0100575 3763200,
576 5644800,
577 7526400,
578 11289600,
579 22579200,
580};
581
Mark Brown5b2eec32012-07-04 17:32:05 +0100582static const unsigned int arizona_44k1_rates[] = {
583 11025,
584 22050,
585 44100,
586 88200,
587 176400,
588 352800,
589 705600,
590};
591
592static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = {
593 .count = ARRAY_SIZE(arizona_44k1_rates),
594 .list = arizona_44k1_rates,
595};
596
Mark Brown07ed8732012-06-18 21:08:44 +0100597static int arizona_sr_vals[] = {
598 0,
599 12000,
600 24000,
601 48000,
602 96000,
603 192000,
604 384000,
605 768000,
606 0,
607 11025,
608 22050,
609 44100,
610 88200,
611 176400,
612 352800,
613 705600,
614 4000,
615 8000,
616 16000,
617 32000,
618 64000,
619 128000,
620 256000,
621 512000,
622};
623
Mark Brown5b2eec32012-07-04 17:32:05 +0100624static int arizona_startup(struct snd_pcm_substream *substream,
625 struct snd_soc_dai *dai)
626{
627 struct snd_soc_codec *codec = dai->codec;
628 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
629 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
630 const struct snd_pcm_hw_constraint_list *constraint;
631 unsigned int base_rate;
632
633 switch (dai_priv->clk) {
634 case ARIZONA_CLK_SYSCLK:
635 base_rate = priv->sysclk;
636 break;
637 case ARIZONA_CLK_ASYNCCLK:
638 base_rate = priv->asyncclk;
639 break;
640 default:
641 return 0;
642 }
643
644 if (base_rate % 8000)
645 constraint = &arizona_44k1_constraint;
646 else
647 constraint = &arizona_48k_constraint;
648
649 return snd_pcm_hw_constraint_list(substream->runtime, 0,
650 SNDRV_PCM_HW_PARAM_RATE,
651 constraint);
652}
653
Mark Brown07ed8732012-06-18 21:08:44 +0100654static int arizona_hw_params(struct snd_pcm_substream *substream,
655 struct snd_pcm_hw_params *params,
656 struct snd_soc_dai *dai)
657{
658 struct snd_soc_codec *codec = dai->codec;
Mark Brownc013b272012-07-04 20:05:57 +0100659 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
660 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown07ed8732012-06-18 21:08:44 +0100661 int base = dai->driver->base;
662 const int *rates;
663 int i;
664 int bclk, lrclk, wl, frame, sr_val;
665
666 if (params_rate(params) % 8000)
Mark Brown949e6bc2012-07-04 18:58:04 +0100667 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +0100668 else
Mark Brown949e6bc2012-07-04 18:58:04 +0100669 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +0100670
Mark Brown949e6bc2012-07-04 18:58:04 +0100671 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brown50017652012-07-04 19:07:09 +0100672 if (rates[i] >= snd_soc_params_to_bclk(params) &&
673 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +0100674 bclk = i;
675 break;
676 }
677 }
Mark Brown949e6bc2012-07-04 18:58:04 +0100678 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +0100679 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
680 params_rate(params));
681 return -EINVAL;
682 }
683
Mark Brown07ed8732012-06-18 21:08:44 +0100684 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
685 if (arizona_sr_vals[i] == params_rate(params))
686 break;
687 if (i == ARRAY_SIZE(arizona_sr_vals)) {
688 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
689 params_rate(params));
690 return -EINVAL;
691 }
692 sr_val = i;
693
694 lrclk = snd_soc_params_to_bclk(params) / params_rate(params);
695
696 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
697 rates[bclk], rates[bclk] / lrclk);
698
699 wl = snd_pcm_format_width(params_format(params));
700 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl;
701
Mark Brownc013b272012-07-04 20:05:57 +0100702 /*
703 * We will need to be more flexible than this in future,
704 * currently we use a single sample rate for SYSCLK.
705 */
706 switch (dai_priv->clk) {
707 case ARIZONA_CLK_SYSCLK:
708 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
709 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
710 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
711 ARIZONA_AIF1_RATE_MASK, 0);
712 break;
713 case ARIZONA_CLK_ASYNCCLK:
714 snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
715 ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val);
716 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
Axel Lin7110a282012-12-20 23:29:42 +0800717 ARIZONA_AIF1_RATE_MASK,
718 8 << ARIZONA_AIF1_RATE_SHIFT);
Mark Brownc013b272012-07-04 20:05:57 +0100719 break;
720 default:
721 arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
722 return -EINVAL;
723 }
724
Mark Brown07ed8732012-06-18 21:08:44 +0100725 snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
726 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
727 snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_BCLK_RATE,
728 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
729 snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_BCLK_RATE,
730 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
731 snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_1,
732 ARIZONA_AIF1TX_WL_MASK |
733 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
734 snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_2,
735 ARIZONA_AIF1RX_WL_MASK |
736 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
737
738 return 0;
739}
740
Mark Brown410837a2012-07-05 17:26:59 +0100741static const char *arizona_dai_clk_str(int clk_id)
742{
743 switch (clk_id) {
744 case ARIZONA_CLK_SYSCLK:
745 return "SYSCLK";
746 case ARIZONA_CLK_ASYNCCLK:
747 return "ASYNCCLK";
748 default:
749 return "Unknown clock";
750 }
751}
752
Mark Brown5b2eec32012-07-04 17:32:05 +0100753static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
754 int clk_id, unsigned int freq, int dir)
755{
756 struct snd_soc_codec *codec = dai->codec;
757 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
758 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown410837a2012-07-05 17:26:59 +0100759 struct snd_soc_dapm_route routes[2];
Mark Brown5b2eec32012-07-04 17:32:05 +0100760
761 switch (clk_id) {
762 case ARIZONA_CLK_SYSCLK:
763 case ARIZONA_CLK_ASYNCCLK:
764 break;
765 default:
766 return -EINVAL;
767 }
768
Mark Brown410837a2012-07-05 17:26:59 +0100769 if (clk_id == dai_priv->clk)
770 return 0;
771
772 if (dai->active) {
Mark Brown5b2eec32012-07-04 17:32:05 +0100773 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
774 dai->id);
775 return -EBUSY;
776 }
777
Mark Brownc8d35a62012-12-07 12:49:40 +0900778 dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1,
779 arizona_dai_clk_str(clk_id));
780
Mark Brown410837a2012-07-05 17:26:59 +0100781 memset(&routes, 0, sizeof(routes));
782 routes[0].sink = dai->driver->capture.stream_name;
783 routes[1].sink = dai->driver->playback.stream_name;
Mark Brown5b2eec32012-07-04 17:32:05 +0100784
Mark Brown410837a2012-07-05 17:26:59 +0100785 routes[0].source = arizona_dai_clk_str(dai_priv->clk);
786 routes[1].source = arizona_dai_clk_str(dai_priv->clk);
787 snd_soc_dapm_del_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
788
789 routes[0].source = arizona_dai_clk_str(clk_id);
790 routes[1].source = arizona_dai_clk_str(clk_id);
791 snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
792
Mark Brown0c778e82012-12-06 18:22:25 +0900793 dai_priv->clk = clk_id;
794
Mark Brown410837a2012-07-05 17:26:59 +0100795 return snd_soc_dapm_sync(&codec->dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +0100796}
797
Mark Brown07ed8732012-06-18 21:08:44 +0100798const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +0100799 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +0100800 .set_fmt = arizona_set_fmt,
801 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +0100802 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown07ed8732012-06-18 21:08:44 +0100803};
Mark Browna8379872012-07-09 12:16:41 +0100804EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +0100805
Mark Brown5b2eec32012-07-04 17:32:05 +0100806int arizona_init_dai(struct arizona_priv *priv, int id)
807{
808 struct arizona_dai_priv *dai_priv = &priv->dai[id];
809
810 dai_priv->clk = ARIZONA_CLK_SYSCLK;
811
812 return 0;
813}
814EXPORT_SYMBOL_GPL(arizona_init_dai);
815
Mark Brown07ed8732012-06-18 21:08:44 +0100816static irqreturn_t arizona_fll_lock(int irq, void *data)
817{
818 struct arizona_fll *fll = data;
819
Mark Brown6b315952012-09-12 18:44:40 +0800820 arizona_fll_dbg(fll, "Lock status changed\n");
Mark Brown07ed8732012-06-18 21:08:44 +0100821
822 complete(&fll->lock);
823
824 return IRQ_HANDLED;
825}
826
827static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
828{
829 struct arizona_fll *fll = data;
830
831 arizona_fll_dbg(fll, "clock OK\n");
832
833 complete(&fll->ok);
834
835 return IRQ_HANDLED;
836}
837
838static struct {
839 unsigned int min;
840 unsigned int max;
841 u16 fratio;
842 int ratio;
843} fll_fratios[] = {
844 { 0, 64000, 4, 16 },
845 { 64000, 128000, 3, 8 },
846 { 128000, 256000, 2, 4 },
847 { 256000, 1000000, 1, 2 },
848 { 1000000, 13500000, 0, 1 },
849};
850
851struct arizona_fll_cfg {
852 int n;
853 int theta;
854 int lambda;
855 int refdiv;
856 int outdiv;
857 int fratio;
858};
859
860static int arizona_calc_fll(struct arizona_fll *fll,
861 struct arizona_fll_cfg *cfg,
862 unsigned int Fref,
863 unsigned int Fout)
864{
865 unsigned int target, div, gcd_fll;
866 int i, ratio;
867
868 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout);
869
870 /* Fref must be <=13.5MHz */
871 div = 1;
872 cfg->refdiv = 0;
873 while ((Fref / div) > 13500000) {
874 div *= 2;
875 cfg->refdiv++;
876
877 if (div > 8) {
878 arizona_fll_err(fll,
879 "Can't scale %dMHz in to <=13.5MHz\n",
880 Fref);
881 return -EINVAL;
882 }
883 }
884
885 /* Apply the division for our remaining calculations */
886 Fref /= div;
887
Mark Brown2b4d39f2012-07-10 17:03:46 +0100888 /* Fvco should be over the targt; don't check the upper bound */
Mark Brown07ed8732012-06-18 21:08:44 +0100889 div = 1;
Mark Brown2b4d39f2012-07-10 17:03:46 +0100890 while (Fout * div < 90000000 * fll->vco_mult) {
Mark Brown07ed8732012-06-18 21:08:44 +0100891 div++;
892 if (div > 7) {
893 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
894 Fout);
895 return -EINVAL;
896 }
897 }
Mark Brown2b4d39f2012-07-10 17:03:46 +0100898 target = Fout * div / fll->vco_mult;
Mark Brown07ed8732012-06-18 21:08:44 +0100899 cfg->outdiv = div;
900
901 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
902
903 /* Find an appropraite FLL_FRATIO and factor it out of the target */
904 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
905 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
906 cfg->fratio = fll_fratios[i].fratio;
907 ratio = fll_fratios[i].ratio;
908 break;
909 }
910 }
911 if (i == ARRAY_SIZE(fll_fratios)) {
912 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
913 Fref);
914 return -EINVAL;
915 }
916
917 cfg->n = target / (ratio * Fref);
918
919 if (target % Fref) {
920 gcd_fll = gcd(target, ratio * Fref);
921 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
922
923 cfg->theta = (target - (cfg->n * ratio * Fref))
924 / gcd_fll;
925 cfg->lambda = (ratio * Fref) / gcd_fll;
926 } else {
927 cfg->theta = 0;
928 cfg->lambda = 0;
929 }
930
931 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
932 cfg->n, cfg->theta, cfg->lambda);
933 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
934 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
935
936 return 0;
937
938}
939
940static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
941 struct arizona_fll_cfg *cfg, int source)
942{
943 regmap_update_bits(arizona->regmap, base + 3,
944 ARIZONA_FLL1_THETA_MASK, cfg->theta);
945 regmap_update_bits(arizona->regmap, base + 4,
946 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
947 regmap_update_bits(arizona->regmap, base + 5,
948 ARIZONA_FLL1_FRATIO_MASK,
949 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
950 regmap_update_bits(arizona->regmap, base + 6,
951 ARIZONA_FLL1_CLK_REF_DIV_MASK |
952 ARIZONA_FLL1_CLK_REF_SRC_MASK,
953 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
954 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
955
956 regmap_update_bits(arizona->regmap, base + 2,
957 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
958 ARIZONA_FLL1_CTRL_UPD | cfg->n);
959}
960
961int arizona_set_fll(struct arizona_fll *fll, int source,
962 unsigned int Fref, unsigned int Fout)
963{
964 struct arizona *arizona = fll->arizona;
965 struct arizona_fll_cfg cfg, sync;
966 unsigned int reg, val;
967 int syncsrc;
968 bool ena;
969 int ret;
970
Mark Brown1cbe4bc2012-11-21 14:12:22 +0900971 if (fll->fref == Fref && fll->fout == Fout)
972 return 0;
973
Mark Brown07ed8732012-06-18 21:08:44 +0100974 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
975 if (ret != 0) {
976 arizona_fll_err(fll, "Failed to read current state: %d\n",
977 ret);
978 return ret;
979 }
980 ena = reg & ARIZONA_FLL1_ENA;
981
982 if (Fout) {
983 /* Do we have a 32kHz reference? */
984 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
985 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
986 case ARIZONA_CLK_SRC_MCLK1:
987 case ARIZONA_CLK_SRC_MCLK2:
988 syncsrc = val & ARIZONA_CLK_32K_SRC_MASK;
989 break;
990 default:
991 syncsrc = -1;
992 }
993
994 if (source == syncsrc)
995 syncsrc = -1;
996
997 if (syncsrc >= 0) {
998 ret = arizona_calc_fll(fll, &sync, Fref, Fout);
999 if (ret != 0)
1000 return ret;
1001
1002 ret = arizona_calc_fll(fll, &cfg, 32768, Fout);
1003 if (ret != 0)
1004 return ret;
1005 } else {
1006 ret = arizona_calc_fll(fll, &cfg, Fref, Fout);
1007 if (ret != 0)
1008 return ret;
1009 }
1010 } else {
1011 regmap_update_bits(arizona->regmap, fll->base + 1,
1012 ARIZONA_FLL1_ENA, 0);
1013 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1014 ARIZONA_FLL1_SYNC_ENA, 0);
1015
1016 if (ena)
1017 pm_runtime_put_autosuspend(arizona->dev);
1018
Mark Brown50fcfe42012-11-28 11:50:34 +00001019 fll->fref = Fref;
1020 fll->fout = Fout;
1021
Mark Brown07ed8732012-06-18 21:08:44 +01001022 return 0;
1023 }
1024
1025 regmap_update_bits(arizona->regmap, fll->base + 5,
1026 ARIZONA_FLL1_OUTDIV_MASK,
1027 cfg.outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
1028
1029 if (syncsrc >= 0) {
1030 arizona_apply_fll(arizona, fll->base, &cfg, syncsrc);
1031 arizona_apply_fll(arizona, fll->base + 0x10, &sync, source);
1032 } else {
1033 arizona_apply_fll(arizona, fll->base, &cfg, source);
1034 }
1035
1036 if (!ena)
1037 pm_runtime_get(arizona->dev);
1038
1039 /* Clear any pending completions */
1040 try_wait_for_completion(&fll->ok);
1041
1042 regmap_update_bits(arizona->regmap, fll->base + 1,
1043 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
1044 if (syncsrc >= 0)
1045 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1046 ARIZONA_FLL1_SYNC_ENA,
1047 ARIZONA_FLL1_SYNC_ENA);
1048
1049 ret = wait_for_completion_timeout(&fll->ok,
Mark Brown09871a92012-12-06 15:29:34 +09001050 msecs_to_jiffies(250));
Mark Brown07ed8732012-06-18 21:08:44 +01001051 if (ret == 0)
1052 arizona_fll_warn(fll, "Timed out waiting for lock\n");
1053
Mark Brown1cbe4bc2012-11-21 14:12:22 +09001054 fll->fref = Fref;
1055 fll->fout = Fout;
1056
Mark Brown07ed8732012-06-18 21:08:44 +01001057 return 0;
1058}
1059EXPORT_SYMBOL_GPL(arizona_set_fll);
1060
1061int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
1062 int ok_irq, struct arizona_fll *fll)
1063{
1064 int ret;
1065
1066 init_completion(&fll->lock);
1067 init_completion(&fll->ok);
1068
1069 fll->id = id;
1070 fll->base = base;
1071 fll->arizona = arizona;
1072
1073 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
1074 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
1075 "FLL%d clock OK", id);
1076
1077 ret = arizona_request_irq(arizona, lock_irq, fll->lock_name,
1078 arizona_fll_lock, fll);
1079 if (ret != 0) {
1080 dev_err(arizona->dev, "Failed to get FLL%d lock IRQ: %d\n",
1081 id, ret);
1082 }
1083
1084 ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
1085 arizona_fll_clock_ok, fll);
1086 if (ret != 0) {
1087 dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
1088 id, ret);
1089 }
1090
1091 return 0;
1092}
1093EXPORT_SYMBOL_GPL(arizona_init_fll);
1094
1095MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
1096MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1097MODULE_LICENSE("GPL");