blob: 1d8bb591759435d5bca70cee52f81c6bbe81ed94 [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;
Mark Brown07ed8732012-06-18 21:08:44 +0100449 case SND_SOC_DAIFMT_I2S:
450 mode = 2;
451 break;
Mark Brown07ed8732012-06-18 21:08:44 +0100452 default:
453 arizona_aif_err(dai, "Unsupported DAI format %d\n",
454 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
455 return -EINVAL;
456 }
457
458 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
459 case SND_SOC_DAIFMT_CBS_CFS:
460 break;
461 case SND_SOC_DAIFMT_CBS_CFM:
462 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
463 break;
464 case SND_SOC_DAIFMT_CBM_CFS:
465 bclk |= ARIZONA_AIF1_BCLK_MSTR;
466 break;
467 case SND_SOC_DAIFMT_CBM_CFM:
468 bclk |= ARIZONA_AIF1_BCLK_MSTR;
469 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
470 break;
471 default:
472 arizona_aif_err(dai, "Unsupported master mode %d\n",
473 fmt & SND_SOC_DAIFMT_MASTER_MASK);
474 return -EINVAL;
475 }
476
477 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
478 case SND_SOC_DAIFMT_NB_NF:
479 break;
480 case SND_SOC_DAIFMT_IB_IF:
481 bclk |= ARIZONA_AIF1_BCLK_INV;
482 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
483 break;
484 case SND_SOC_DAIFMT_IB_NF:
485 bclk |= ARIZONA_AIF1_BCLK_INV;
486 break;
487 case SND_SOC_DAIFMT_NB_IF:
488 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
489 break;
490 default:
491 return -EINVAL;
492 }
493
494 snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
495 ARIZONA_AIF1_BCLK_INV | ARIZONA_AIF1_BCLK_MSTR,
496 bclk);
497 snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_PIN_CTRL,
498 ARIZONA_AIF1TX_LRCLK_INV |
499 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
500 snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_PIN_CTRL,
501 ARIZONA_AIF1RX_LRCLK_INV |
502 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
503 snd_soc_update_bits(codec, base + ARIZONA_AIF_FORMAT,
504 ARIZONA_AIF1_FMT_MASK, mode);
505
506 return 0;
507}
508
Mark Brown949e6bc2012-07-04 18:58:04 +0100509static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100510 -1,
511 48000,
512 64000,
513 96000,
514 128000,
515 192000,
516 256000,
517 384000,
518 512000,
519 768000,
520 1024000,
521 1536000,
522 2048000,
523 3072000,
524 4096000,
525 6144000,
526 8192000,
527 12288000,
528 24576000,
529};
530
Mark Brown5b2eec32012-07-04 17:32:05 +0100531static const unsigned int arizona_48k_rates[] = {
532 12000,
533 24000,
534 48000,
535 96000,
536 192000,
537 384000,
538 768000,
539 4000,
540 8000,
541 16000,
542 32000,
543 64000,
544 128000,
545 256000,
546 512000,
547};
548
549static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = {
550 .count = ARRAY_SIZE(arizona_48k_rates),
551 .list = arizona_48k_rates,
552};
553
Mark Brown949e6bc2012-07-04 18:58:04 +0100554static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100555 -1,
556 44100,
557 58800,
558 88200,
559 117600,
560 177640,
561 235200,
562 352800,
563 470400,
564 705600,
565 940800,
566 1411200,
567 1881600,
Heather Lomond4758be32012-09-05 05:02:10 -0400568 2822400,
Mark Brown07ed8732012-06-18 21:08:44 +0100569 3763200,
570 5644800,
571 7526400,
572 11289600,
573 22579200,
574};
575
Mark Brown5b2eec32012-07-04 17:32:05 +0100576static const unsigned int arizona_44k1_rates[] = {
577 11025,
578 22050,
579 44100,
580 88200,
581 176400,
582 352800,
583 705600,
584};
585
586static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = {
587 .count = ARRAY_SIZE(arizona_44k1_rates),
588 .list = arizona_44k1_rates,
589};
590
Mark Brown07ed8732012-06-18 21:08:44 +0100591static int arizona_sr_vals[] = {
592 0,
593 12000,
594 24000,
595 48000,
596 96000,
597 192000,
598 384000,
599 768000,
600 0,
601 11025,
602 22050,
603 44100,
604 88200,
605 176400,
606 352800,
607 705600,
608 4000,
609 8000,
610 16000,
611 32000,
612 64000,
613 128000,
614 256000,
615 512000,
616};
617
Mark Brown5b2eec32012-07-04 17:32:05 +0100618static int arizona_startup(struct snd_pcm_substream *substream,
619 struct snd_soc_dai *dai)
620{
621 struct snd_soc_codec *codec = dai->codec;
622 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
623 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
624 const struct snd_pcm_hw_constraint_list *constraint;
625 unsigned int base_rate;
626
627 switch (dai_priv->clk) {
628 case ARIZONA_CLK_SYSCLK:
629 base_rate = priv->sysclk;
630 break;
631 case ARIZONA_CLK_ASYNCCLK:
632 base_rate = priv->asyncclk;
633 break;
634 default:
635 return 0;
636 }
637
638 if (base_rate % 8000)
639 constraint = &arizona_44k1_constraint;
640 else
641 constraint = &arizona_48k_constraint;
642
643 return snd_pcm_hw_constraint_list(substream->runtime, 0,
644 SNDRV_PCM_HW_PARAM_RATE,
645 constraint);
646}
647
Mark Brown07ed8732012-06-18 21:08:44 +0100648static int arizona_hw_params(struct snd_pcm_substream *substream,
649 struct snd_pcm_hw_params *params,
650 struct snd_soc_dai *dai)
651{
652 struct snd_soc_codec *codec = dai->codec;
Mark Brownc013b272012-07-04 20:05:57 +0100653 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
654 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown07ed8732012-06-18 21:08:44 +0100655 int base = dai->driver->base;
656 const int *rates;
657 int i;
658 int bclk, lrclk, wl, frame, sr_val;
659
660 if (params_rate(params) % 8000)
Mark Brown949e6bc2012-07-04 18:58:04 +0100661 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +0100662 else
Mark Brown949e6bc2012-07-04 18:58:04 +0100663 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +0100664
Mark Brown949e6bc2012-07-04 18:58:04 +0100665 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brown50017652012-07-04 19:07:09 +0100666 if (rates[i] >= snd_soc_params_to_bclk(params) &&
667 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +0100668 bclk = i;
669 break;
670 }
671 }
Mark Brown949e6bc2012-07-04 18:58:04 +0100672 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +0100673 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
674 params_rate(params));
675 return -EINVAL;
676 }
677
Mark Brown07ed8732012-06-18 21:08:44 +0100678 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
679 if (arizona_sr_vals[i] == params_rate(params))
680 break;
681 if (i == ARRAY_SIZE(arizona_sr_vals)) {
682 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
683 params_rate(params));
684 return -EINVAL;
685 }
686 sr_val = i;
687
688 lrclk = snd_soc_params_to_bclk(params) / params_rate(params);
689
690 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
691 rates[bclk], rates[bclk] / lrclk);
692
693 wl = snd_pcm_format_width(params_format(params));
694 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl;
695
Mark Brownc013b272012-07-04 20:05:57 +0100696 /*
697 * We will need to be more flexible than this in future,
698 * currently we use a single sample rate for SYSCLK.
699 */
700 switch (dai_priv->clk) {
701 case ARIZONA_CLK_SYSCLK:
702 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
703 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
704 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
705 ARIZONA_AIF1_RATE_MASK, 0);
706 break;
707 case ARIZONA_CLK_ASYNCCLK:
708 snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
709 ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val);
710 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
Axel Lin7110a282012-12-20 23:29:42 +0800711 ARIZONA_AIF1_RATE_MASK,
712 8 << ARIZONA_AIF1_RATE_SHIFT);
Mark Brownc013b272012-07-04 20:05:57 +0100713 break;
714 default:
715 arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
716 return -EINVAL;
717 }
718
Mark Brown07ed8732012-06-18 21:08:44 +0100719 snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
720 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
721 snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_BCLK_RATE,
722 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
723 snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_BCLK_RATE,
724 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
725 snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_1,
726 ARIZONA_AIF1TX_WL_MASK |
727 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
728 snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_2,
729 ARIZONA_AIF1RX_WL_MASK |
730 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
731
732 return 0;
733}
734
Mark Brown410837a2012-07-05 17:26:59 +0100735static const char *arizona_dai_clk_str(int clk_id)
736{
737 switch (clk_id) {
738 case ARIZONA_CLK_SYSCLK:
739 return "SYSCLK";
740 case ARIZONA_CLK_ASYNCCLK:
741 return "ASYNCCLK";
742 default:
743 return "Unknown clock";
744 }
745}
746
Mark Brown5b2eec32012-07-04 17:32:05 +0100747static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
748 int clk_id, unsigned int freq, int dir)
749{
750 struct snd_soc_codec *codec = dai->codec;
751 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
752 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown410837a2012-07-05 17:26:59 +0100753 struct snd_soc_dapm_route routes[2];
Mark Brown5b2eec32012-07-04 17:32:05 +0100754
755 switch (clk_id) {
756 case ARIZONA_CLK_SYSCLK:
757 case ARIZONA_CLK_ASYNCCLK:
758 break;
759 default:
760 return -EINVAL;
761 }
762
Mark Brown410837a2012-07-05 17:26:59 +0100763 if (clk_id == dai_priv->clk)
764 return 0;
765
766 if (dai->active) {
Mark Brown5b2eec32012-07-04 17:32:05 +0100767 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
768 dai->id);
769 return -EBUSY;
770 }
771
Mark Brownc8d35a62012-12-07 12:49:40 +0900772 dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1,
773 arizona_dai_clk_str(clk_id));
774
Mark Brown410837a2012-07-05 17:26:59 +0100775 memset(&routes, 0, sizeof(routes));
776 routes[0].sink = dai->driver->capture.stream_name;
777 routes[1].sink = dai->driver->playback.stream_name;
Mark Brown5b2eec32012-07-04 17:32:05 +0100778
Mark Brown410837a2012-07-05 17:26:59 +0100779 routes[0].source = arizona_dai_clk_str(dai_priv->clk);
780 routes[1].source = arizona_dai_clk_str(dai_priv->clk);
781 snd_soc_dapm_del_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
782
783 routes[0].source = arizona_dai_clk_str(clk_id);
784 routes[1].source = arizona_dai_clk_str(clk_id);
785 snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
786
Mark Brown0c778e82012-12-06 18:22:25 +0900787 dai_priv->clk = clk_id;
788
Mark Brown410837a2012-07-05 17:26:59 +0100789 return snd_soc_dapm_sync(&codec->dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +0100790}
791
Mark Brown07ed8732012-06-18 21:08:44 +0100792const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +0100793 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +0100794 .set_fmt = arizona_set_fmt,
795 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +0100796 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown07ed8732012-06-18 21:08:44 +0100797};
Mark Browna8379872012-07-09 12:16:41 +0100798EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +0100799
Mark Brown5b2eec32012-07-04 17:32:05 +0100800int arizona_init_dai(struct arizona_priv *priv, int id)
801{
802 struct arizona_dai_priv *dai_priv = &priv->dai[id];
803
804 dai_priv->clk = ARIZONA_CLK_SYSCLK;
805
806 return 0;
807}
808EXPORT_SYMBOL_GPL(arizona_init_dai);
809
Mark Brown07ed8732012-06-18 21:08:44 +0100810static irqreturn_t arizona_fll_lock(int irq, void *data)
811{
812 struct arizona_fll *fll = data;
813
Mark Brown6b315952012-09-12 18:44:40 +0800814 arizona_fll_dbg(fll, "Lock status changed\n");
Mark Brown07ed8732012-06-18 21:08:44 +0100815
816 complete(&fll->lock);
817
818 return IRQ_HANDLED;
819}
820
821static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
822{
823 struct arizona_fll *fll = data;
824
825 arizona_fll_dbg(fll, "clock OK\n");
826
827 complete(&fll->ok);
828
829 return IRQ_HANDLED;
830}
831
832static struct {
833 unsigned int min;
834 unsigned int max;
835 u16 fratio;
836 int ratio;
837} fll_fratios[] = {
838 { 0, 64000, 4, 16 },
839 { 64000, 128000, 3, 8 },
840 { 128000, 256000, 2, 4 },
841 { 256000, 1000000, 1, 2 },
842 { 1000000, 13500000, 0, 1 },
843};
844
845struct arizona_fll_cfg {
846 int n;
847 int theta;
848 int lambda;
849 int refdiv;
850 int outdiv;
851 int fratio;
852};
853
854static int arizona_calc_fll(struct arizona_fll *fll,
855 struct arizona_fll_cfg *cfg,
856 unsigned int Fref,
857 unsigned int Fout)
858{
859 unsigned int target, div, gcd_fll;
860 int i, ratio;
861
862 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout);
863
864 /* Fref must be <=13.5MHz */
865 div = 1;
866 cfg->refdiv = 0;
867 while ((Fref / div) > 13500000) {
868 div *= 2;
869 cfg->refdiv++;
870
871 if (div > 8) {
872 arizona_fll_err(fll,
873 "Can't scale %dMHz in to <=13.5MHz\n",
874 Fref);
875 return -EINVAL;
876 }
877 }
878
879 /* Apply the division for our remaining calculations */
880 Fref /= div;
881
Mark Brown2b4d39f2012-07-10 17:03:46 +0100882 /* Fvco should be over the targt; don't check the upper bound */
Mark Brown07ed8732012-06-18 21:08:44 +0100883 div = 1;
Mark Brown2b4d39f2012-07-10 17:03:46 +0100884 while (Fout * div < 90000000 * fll->vco_mult) {
Mark Brown07ed8732012-06-18 21:08:44 +0100885 div++;
886 if (div > 7) {
887 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
888 Fout);
889 return -EINVAL;
890 }
891 }
Mark Brown2b4d39f2012-07-10 17:03:46 +0100892 target = Fout * div / fll->vco_mult;
Mark Brown07ed8732012-06-18 21:08:44 +0100893 cfg->outdiv = div;
894
895 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
896
897 /* Find an appropraite FLL_FRATIO and factor it out of the target */
898 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
899 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
900 cfg->fratio = fll_fratios[i].fratio;
901 ratio = fll_fratios[i].ratio;
902 break;
903 }
904 }
905 if (i == ARRAY_SIZE(fll_fratios)) {
906 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
907 Fref);
908 return -EINVAL;
909 }
910
911 cfg->n = target / (ratio * Fref);
912
913 if (target % Fref) {
914 gcd_fll = gcd(target, ratio * Fref);
915 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
916
917 cfg->theta = (target - (cfg->n * ratio * Fref))
918 / gcd_fll;
919 cfg->lambda = (ratio * Fref) / gcd_fll;
920 } else {
921 cfg->theta = 0;
922 cfg->lambda = 0;
923 }
924
925 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
926 cfg->n, cfg->theta, cfg->lambda);
927 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
928 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
929
930 return 0;
931
932}
933
934static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
935 struct arizona_fll_cfg *cfg, int source)
936{
937 regmap_update_bits(arizona->regmap, base + 3,
938 ARIZONA_FLL1_THETA_MASK, cfg->theta);
939 regmap_update_bits(arizona->regmap, base + 4,
940 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
941 regmap_update_bits(arizona->regmap, base + 5,
942 ARIZONA_FLL1_FRATIO_MASK,
943 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
944 regmap_update_bits(arizona->regmap, base + 6,
945 ARIZONA_FLL1_CLK_REF_DIV_MASK |
946 ARIZONA_FLL1_CLK_REF_SRC_MASK,
947 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
948 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
949
950 regmap_update_bits(arizona->regmap, base + 2,
951 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
952 ARIZONA_FLL1_CTRL_UPD | cfg->n);
953}
954
955int arizona_set_fll(struct arizona_fll *fll, int source,
956 unsigned int Fref, unsigned int Fout)
957{
958 struct arizona *arizona = fll->arizona;
959 struct arizona_fll_cfg cfg, sync;
960 unsigned int reg, val;
961 int syncsrc;
962 bool ena;
963 int ret;
964
Mark Brown1cbe4bc2012-11-21 14:12:22 +0900965 if (fll->fref == Fref && fll->fout == Fout)
966 return 0;
967
Mark Brown07ed8732012-06-18 21:08:44 +0100968 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
969 if (ret != 0) {
970 arizona_fll_err(fll, "Failed to read current state: %d\n",
971 ret);
972 return ret;
973 }
974 ena = reg & ARIZONA_FLL1_ENA;
975
976 if (Fout) {
977 /* Do we have a 32kHz reference? */
978 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
979 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
980 case ARIZONA_CLK_SRC_MCLK1:
981 case ARIZONA_CLK_SRC_MCLK2:
982 syncsrc = val & ARIZONA_CLK_32K_SRC_MASK;
983 break;
984 default:
985 syncsrc = -1;
986 }
987
988 if (source == syncsrc)
989 syncsrc = -1;
990
991 if (syncsrc >= 0) {
992 ret = arizona_calc_fll(fll, &sync, Fref, Fout);
993 if (ret != 0)
994 return ret;
995
996 ret = arizona_calc_fll(fll, &cfg, 32768, Fout);
997 if (ret != 0)
998 return ret;
999 } else {
1000 ret = arizona_calc_fll(fll, &cfg, Fref, Fout);
1001 if (ret != 0)
1002 return ret;
1003 }
1004 } else {
1005 regmap_update_bits(arizona->regmap, fll->base + 1,
1006 ARIZONA_FLL1_ENA, 0);
1007 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1008 ARIZONA_FLL1_SYNC_ENA, 0);
1009
1010 if (ena)
1011 pm_runtime_put_autosuspend(arizona->dev);
1012
Mark Brown50fcfe42012-11-28 11:50:34 +00001013 fll->fref = Fref;
1014 fll->fout = Fout;
1015
Mark Brown07ed8732012-06-18 21:08:44 +01001016 return 0;
1017 }
1018
1019 regmap_update_bits(arizona->regmap, fll->base + 5,
1020 ARIZONA_FLL1_OUTDIV_MASK,
1021 cfg.outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
1022
1023 if (syncsrc >= 0) {
1024 arizona_apply_fll(arizona, fll->base, &cfg, syncsrc);
1025 arizona_apply_fll(arizona, fll->base + 0x10, &sync, source);
1026 } else {
1027 arizona_apply_fll(arizona, fll->base, &cfg, source);
1028 }
1029
1030 if (!ena)
1031 pm_runtime_get(arizona->dev);
1032
1033 /* Clear any pending completions */
1034 try_wait_for_completion(&fll->ok);
1035
1036 regmap_update_bits(arizona->regmap, fll->base + 1,
1037 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
1038 if (syncsrc >= 0)
1039 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1040 ARIZONA_FLL1_SYNC_ENA,
1041 ARIZONA_FLL1_SYNC_ENA);
1042
1043 ret = wait_for_completion_timeout(&fll->ok,
Mark Brown09871a92012-12-06 15:29:34 +09001044 msecs_to_jiffies(250));
Mark Brown07ed8732012-06-18 21:08:44 +01001045 if (ret == 0)
1046 arizona_fll_warn(fll, "Timed out waiting for lock\n");
1047
Mark Brown1cbe4bc2012-11-21 14:12:22 +09001048 fll->fref = Fref;
1049 fll->fout = Fout;
1050
Mark Brown07ed8732012-06-18 21:08:44 +01001051 return 0;
1052}
1053EXPORT_SYMBOL_GPL(arizona_set_fll);
1054
1055int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
1056 int ok_irq, struct arizona_fll *fll)
1057{
1058 int ret;
1059
1060 init_completion(&fll->lock);
1061 init_completion(&fll->ok);
1062
1063 fll->id = id;
1064 fll->base = base;
1065 fll->arizona = arizona;
1066
1067 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
1068 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
1069 "FLL%d clock OK", id);
1070
1071 ret = arizona_request_irq(arizona, lock_irq, fll->lock_name,
1072 arizona_fll_lock, fll);
1073 if (ret != 0) {
1074 dev_err(arizona->dev, "Failed to get FLL%d lock IRQ: %d\n",
1075 id, ret);
1076 }
1077
1078 ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
1079 arizona_fll_clock_ok, fll);
1080 if (ret != 0) {
1081 dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
1082 id, ret);
1083 }
1084
1085 return 0;
1086}
1087EXPORT_SYMBOL_GPL(arizona_init_fll);
1088
1089MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
1090MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1091MODULE_LICENSE("GPL");