blob: d855a6c098d478b5bad650359e9691c5c5d81a6e [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",
Mark Brown91660bd2012-12-05 20:35:24 +0900144 "ISRC1INT1",
145 "ISRC1INT2",
146 "ISRC1INT3",
147 "ISRC1INT4",
148 "ISRC1DEC1",
149 "ISRC1DEC2",
150 "ISRC1DEC3",
151 "ISRC1DEC4",
152 "ISRC2INT1",
153 "ISRC2INT2",
154 "ISRC2INT3",
155 "ISRC2INT4",
156 "ISRC2DEC1",
157 "ISRC2DEC2",
158 "ISRC2DEC3",
159 "ISRC2DEC4",
160 "ISRC3INT1",
161 "ISRC3INT2",
162 "ISRC3INT3",
163 "ISRC3INT4",
164 "ISRC3DEC1",
165 "ISRC3DEC2",
166 "ISRC3DEC3",
167 "ISRC3DEC4",
Mark Brown07ed8732012-06-18 21:08:44 +0100168};
169EXPORT_SYMBOL_GPL(arizona_mixer_texts);
170
171int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
172 0x00, /* None */
173 0x04, /* Tone */
174 0x05,
175 0x06, /* Haptics */
176 0x08, /* AEC */
177 0x0c, /* Noise mixer */
178 0x0d, /* Comfort noise */
179 0x10, /* IN1L */
180 0x11,
181 0x12,
182 0x13,
183 0x14,
184 0x15,
Mark Brownc9c56fd2012-07-09 19:09:01 +0100185 0x16,
186 0x17,
Mark Brown07ed8732012-06-18 21:08:44 +0100187 0x20, /* AIF1RX1 */
188 0x21,
189 0x22,
190 0x23,
191 0x24,
192 0x25,
193 0x26,
194 0x27,
195 0x28, /* AIF2RX1 */
196 0x29,
197 0x30, /* AIF3RX1 */
198 0x31,
199 0x38, /* SLIMRX1 */
200 0x39,
201 0x3a,
202 0x3b,
203 0x3c,
204 0x3d,
205 0x3e,
206 0x3f,
207 0x50, /* EQ1 */
208 0x51,
209 0x52,
210 0x53,
211 0x58, /* DRC1L */
212 0x59,
213 0x5a,
214 0x5b,
215 0x60, /* LHPF1 */
216 0x61,
217 0x62,
218 0x63,
219 0x68, /* DSP1.1 */
220 0x69,
221 0x6a,
222 0x6b,
223 0x6c,
224 0x6d,
Mark Brownc922cc42012-09-26 16:43:44 +0100225 0x70, /* DSP2.1 */
226 0x71,
227 0x72,
228 0x73,
229 0x74,
230 0x75,
231 0x78, /* DSP3.1 */
232 0x79,
233 0x7a,
234 0x7b,
235 0x7c,
236 0x7d,
237 0x80, /* DSP4.1 */
238 0x81,
239 0x82,
240 0x83,
241 0x84,
242 0x85,
Mark Brown07ed8732012-06-18 21:08:44 +0100243 0x90, /* ASRC1L */
244 0x91,
245 0x92,
246 0x93,
Mark Brown91660bd2012-12-05 20:35:24 +0900247 0xa0, /* ISRC1INT1 */
248 0xa1,
249 0xa2,
250 0xa3,
251 0xa4, /* ISRC1DEC1 */
252 0xa5,
253 0xa6,
254 0xa7,
255 0xa8, /* ISRC2DEC1 */
256 0xa9,
257 0xaa,
258 0xab,
259 0xac, /* ISRC2INT1 */
260 0xad,
261 0xae,
262 0xaf,
263 0xb0, /* ISRC3DEC1 */
264 0xb1,
265 0xb2,
266 0xb3,
267 0xb4, /* ISRC3INT1 */
268 0xb5,
269 0xb6,
270 0xb7,
Mark Brown07ed8732012-06-18 21:08:44 +0100271};
272EXPORT_SYMBOL_GPL(arizona_mixer_values);
273
274const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
275EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
276
Mark Browne853a002012-12-09 12:25:52 +0900277static const char *arizona_vol_ramp_text[] = {
278 "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
279 "15ms/6dB", "30ms/6dB",
280};
281
282const struct soc_enum arizona_in_vd_ramp =
283 SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP,
284 ARIZONA_IN_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text);
285EXPORT_SYMBOL_GPL(arizona_in_vd_ramp);
286
287const struct soc_enum arizona_in_vi_ramp =
288 SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP,
289 ARIZONA_IN_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text);
290EXPORT_SYMBOL_GPL(arizona_in_vi_ramp);
291
292const struct soc_enum arizona_out_vd_ramp =
293 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP,
294 ARIZONA_OUT_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text);
295EXPORT_SYMBOL_GPL(arizona_out_vd_ramp);
296
297const struct soc_enum arizona_out_vi_ramp =
298 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP,
299 ARIZONA_OUT_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text);
300EXPORT_SYMBOL_GPL(arizona_out_vi_ramp);
301
Mark Brown07ed8732012-06-18 21:08:44 +0100302static const char *arizona_lhpf_mode_text[] = {
303 "Low-pass", "High-pass"
304};
305
306const struct soc_enum arizona_lhpf1_mode =
307 SOC_ENUM_SINGLE(ARIZONA_HPLPF1_1, ARIZONA_LHPF1_MODE_SHIFT, 2,
308 arizona_lhpf_mode_text);
309EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
310
311const struct soc_enum arizona_lhpf2_mode =
312 SOC_ENUM_SINGLE(ARIZONA_HPLPF2_1, ARIZONA_LHPF2_MODE_SHIFT, 2,
313 arizona_lhpf_mode_text);
314EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
315
316const struct soc_enum arizona_lhpf3_mode =
317 SOC_ENUM_SINGLE(ARIZONA_HPLPF3_1, ARIZONA_LHPF3_MODE_SHIFT, 2,
318 arizona_lhpf_mode_text);
319EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
320
321const struct soc_enum arizona_lhpf4_mode =
322 SOC_ENUM_SINGLE(ARIZONA_HPLPF4_1, ARIZONA_LHPF4_MODE_SHIFT, 2,
323 arizona_lhpf_mode_text);
324EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
325
Mark Brown845571c2012-12-18 13:47:57 +0000326static const char *arizona_ng_hold_text[] = {
327 "30ms", "120ms", "250ms", "500ms",
328};
329
330const struct soc_enum arizona_ng_hold =
331 SOC_ENUM_SINGLE(ARIZONA_NOISE_GATE_CONTROL, ARIZONA_NGATE_HOLD_SHIFT,
332 4, arizona_ng_hold_text);
333EXPORT_SYMBOL_GPL(arizona_ng_hold);
334
Mark Brown07ed8732012-06-18 21:08:44 +0100335int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
336 int event)
337{
338 return 0;
339}
340EXPORT_SYMBOL_GPL(arizona_in_ev);
341
342int arizona_out_ev(struct snd_soc_dapm_widget *w,
343 struct snd_kcontrol *kcontrol,
344 int event)
345{
346 return 0;
347}
348EXPORT_SYMBOL_GPL(arizona_out_ev);
349
Mark Browncbd840d2012-08-08 17:52:44 +0100350static unsigned int arizona_sysclk_48k_rates[] = {
351 6144000,
352 12288000,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000353 24576000,
Mark Browncbd840d2012-08-08 17:52:44 +0100354 49152000,
Mark Brownaeaeee12012-09-26 17:50:02 +0100355 73728000,
356 98304000,
357 147456000,
Mark Browncbd840d2012-08-08 17:52:44 +0100358};
359
360static unsigned int arizona_sysclk_44k1_rates[] = {
361 5644800,
362 11289600,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000363 22579200,
Mark Browncbd840d2012-08-08 17:52:44 +0100364 45158400,
Mark Brownaeaeee12012-09-26 17:50:02 +0100365 67737600,
366 90316800,
367 135475200,
Mark Browncbd840d2012-08-08 17:52:44 +0100368};
369
370static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
371 unsigned int freq)
372{
373 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
374 unsigned int reg;
375 unsigned int *rates;
376 int ref, div, refclk;
377
378 switch (clk) {
379 case ARIZONA_CLK_OPCLK:
380 reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
381 refclk = priv->sysclk;
382 break;
383 case ARIZONA_CLK_ASYNC_OPCLK:
384 reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
385 refclk = priv->asyncclk;
386 break;
387 default:
388 return -EINVAL;
389 }
390
391 if (refclk % 8000)
392 rates = arizona_sysclk_44k1_rates;
393 else
394 rates = arizona_sysclk_48k_rates;
395
396 for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) &&
397 rates[ref] <= refclk; ref++) {
398 div = 1;
399 while (rates[ref] / div >= freq && div < 32) {
400 if (rates[ref] / div == freq) {
401 dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
402 freq);
403 snd_soc_update_bits(codec, reg,
404 ARIZONA_OPCLK_DIV_MASK |
405 ARIZONA_OPCLK_SEL_MASK,
406 (div <<
407 ARIZONA_OPCLK_DIV_SHIFT) |
408 ref);
409 return 0;
410 }
411 div++;
412 }
413 }
414
415 dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
416 return -EINVAL;
417}
418
Mark Brown07ed8732012-06-18 21:08:44 +0100419int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
420 int source, unsigned int freq, int dir)
421{
422 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
423 struct arizona *arizona = priv->arizona;
424 char *name;
425 unsigned int reg;
426 unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
427 unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
428 unsigned int *clk;
429
430 switch (clk_id) {
431 case ARIZONA_CLK_SYSCLK:
432 name = "SYSCLK";
433 reg = ARIZONA_SYSTEM_CLOCK_1;
434 clk = &priv->sysclk;
435 mask |= ARIZONA_SYSCLK_FRAC;
436 break;
437 case ARIZONA_CLK_ASYNCCLK:
438 name = "ASYNCCLK";
439 reg = ARIZONA_ASYNC_CLOCK_1;
440 clk = &priv->asyncclk;
441 break;
Mark Browncbd840d2012-08-08 17:52:44 +0100442 case ARIZONA_CLK_OPCLK:
443 case ARIZONA_CLK_ASYNC_OPCLK:
444 return arizona_set_opclk(codec, clk_id, freq);
Mark Brown07ed8732012-06-18 21:08:44 +0100445 default:
446 return -EINVAL;
447 }
448
449 switch (freq) {
450 case 5644800:
451 case 6144000:
452 break;
453 case 11289600:
454 case 12288000:
455 val |= 1 << ARIZONA_SYSCLK_FREQ_SHIFT;
456 break;
457 case 22579200:
458 case 24576000:
459 val |= 2 << ARIZONA_SYSCLK_FREQ_SHIFT;
460 break;
461 case 45158400:
462 case 49152000:
463 val |= 3 << ARIZONA_SYSCLK_FREQ_SHIFT;
464 break;
Mark Brown38113362012-11-26 16:01:37 +0000465 case 67737600:
466 case 73728000:
467 val |= 4 << ARIZONA_SYSCLK_FREQ_SHIFT;
468 break;
469 case 90316800:
470 case 98304000:
471 val |= 5 << ARIZONA_SYSCLK_FREQ_SHIFT;
472 break;
473 case 135475200:
474 case 147456000:
475 val |= 6 << ARIZONA_SYSCLK_FREQ_SHIFT;
476 break;
Mark Brownf2c26d42013-01-21 16:09:36 +0900477 case 0:
478 dev_dbg(arizona->dev, "%s cleared\n", name);
479 *clk = freq;
480 return 0;
Mark Brown07ed8732012-06-18 21:08:44 +0100481 default:
482 return -EINVAL;
483 }
484
485 *clk = freq;
486
487 if (freq % 6144000)
488 val |= ARIZONA_SYSCLK_FRAC;
489
490 dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
491
492 return regmap_update_bits(arizona->regmap, reg, mask, val);
493}
494EXPORT_SYMBOL_GPL(arizona_set_sysclk);
495
496static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
497{
498 struct snd_soc_codec *codec = dai->codec;
499 int lrclk, bclk, mode, base;
500
501 base = dai->driver->base;
502
503 lrclk = 0;
504 bclk = 0;
505
506 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
507 case SND_SOC_DAIFMT_DSP_A:
508 mode = 0;
509 break;
Mark Brown07ed8732012-06-18 21:08:44 +0100510 case SND_SOC_DAIFMT_I2S:
511 mode = 2;
512 break;
Mark Brown07ed8732012-06-18 21:08:44 +0100513 default:
514 arizona_aif_err(dai, "Unsupported DAI format %d\n",
515 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
516 return -EINVAL;
517 }
518
519 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
520 case SND_SOC_DAIFMT_CBS_CFS:
521 break;
522 case SND_SOC_DAIFMT_CBS_CFM:
523 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
524 break;
525 case SND_SOC_DAIFMT_CBM_CFS:
526 bclk |= ARIZONA_AIF1_BCLK_MSTR;
527 break;
528 case SND_SOC_DAIFMT_CBM_CFM:
529 bclk |= ARIZONA_AIF1_BCLK_MSTR;
530 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
531 break;
532 default:
533 arizona_aif_err(dai, "Unsupported master mode %d\n",
534 fmt & SND_SOC_DAIFMT_MASTER_MASK);
535 return -EINVAL;
536 }
537
538 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
539 case SND_SOC_DAIFMT_NB_NF:
540 break;
541 case SND_SOC_DAIFMT_IB_IF:
542 bclk |= ARIZONA_AIF1_BCLK_INV;
543 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
544 break;
545 case SND_SOC_DAIFMT_IB_NF:
546 bclk |= ARIZONA_AIF1_BCLK_INV;
547 break;
548 case SND_SOC_DAIFMT_NB_IF:
549 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
550 break;
551 default:
552 return -EINVAL;
553 }
554
555 snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
556 ARIZONA_AIF1_BCLK_INV | ARIZONA_AIF1_BCLK_MSTR,
557 bclk);
558 snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_PIN_CTRL,
559 ARIZONA_AIF1TX_LRCLK_INV |
560 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
561 snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_PIN_CTRL,
562 ARIZONA_AIF1RX_LRCLK_INV |
563 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
564 snd_soc_update_bits(codec, base + ARIZONA_AIF_FORMAT,
565 ARIZONA_AIF1_FMT_MASK, mode);
566
567 return 0;
568}
569
Mark Brown949e6bc2012-07-04 18:58:04 +0100570static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100571 -1,
572 48000,
573 64000,
574 96000,
575 128000,
576 192000,
577 256000,
578 384000,
579 512000,
580 768000,
581 1024000,
582 1536000,
583 2048000,
584 3072000,
585 4096000,
586 6144000,
587 8192000,
588 12288000,
589 24576000,
590};
591
Mark Brown5b2eec32012-07-04 17:32:05 +0100592static const unsigned int arizona_48k_rates[] = {
593 12000,
594 24000,
595 48000,
596 96000,
597 192000,
598 384000,
599 768000,
600 4000,
601 8000,
602 16000,
603 32000,
604 64000,
605 128000,
606 256000,
607 512000,
608};
609
610static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = {
611 .count = ARRAY_SIZE(arizona_48k_rates),
612 .list = arizona_48k_rates,
613};
614
Mark Brown949e6bc2012-07-04 18:58:04 +0100615static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100616 -1,
617 44100,
618 58800,
619 88200,
620 117600,
621 177640,
622 235200,
623 352800,
624 470400,
625 705600,
626 940800,
627 1411200,
628 1881600,
Heather Lomond4758be32012-09-05 05:02:10 -0400629 2822400,
Mark Brown07ed8732012-06-18 21:08:44 +0100630 3763200,
631 5644800,
632 7526400,
633 11289600,
634 22579200,
635};
636
Mark Brown5b2eec32012-07-04 17:32:05 +0100637static const unsigned int arizona_44k1_rates[] = {
638 11025,
639 22050,
640 44100,
641 88200,
642 176400,
643 352800,
644 705600,
645};
646
647static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = {
648 .count = ARRAY_SIZE(arizona_44k1_rates),
649 .list = arizona_44k1_rates,
650};
651
Mark Brown07ed8732012-06-18 21:08:44 +0100652static int arizona_sr_vals[] = {
653 0,
654 12000,
655 24000,
656 48000,
657 96000,
658 192000,
659 384000,
660 768000,
661 0,
662 11025,
663 22050,
664 44100,
665 88200,
666 176400,
667 352800,
668 705600,
669 4000,
670 8000,
671 16000,
672 32000,
673 64000,
674 128000,
675 256000,
676 512000,
677};
678
Mark Brown5b2eec32012-07-04 17:32:05 +0100679static int arizona_startup(struct snd_pcm_substream *substream,
680 struct snd_soc_dai *dai)
681{
682 struct snd_soc_codec *codec = dai->codec;
683 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
684 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
685 const struct snd_pcm_hw_constraint_list *constraint;
686 unsigned int base_rate;
687
688 switch (dai_priv->clk) {
689 case ARIZONA_CLK_SYSCLK:
690 base_rate = priv->sysclk;
691 break;
692 case ARIZONA_CLK_ASYNCCLK:
693 base_rate = priv->asyncclk;
694 break;
695 default:
696 return 0;
697 }
698
Mark Brownf2c26d42013-01-21 16:09:36 +0900699 if (base_rate == 0)
700 return 0;
701
Mark Brown5b2eec32012-07-04 17:32:05 +0100702 if (base_rate % 8000)
703 constraint = &arizona_44k1_constraint;
704 else
705 constraint = &arizona_48k_constraint;
706
707 return snd_pcm_hw_constraint_list(substream->runtime, 0,
708 SNDRV_PCM_HW_PARAM_RATE,
709 constraint);
710}
711
Mark Brownb272efc2012-10-10 15:10:08 +0900712static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
713 struct snd_pcm_hw_params *params,
714 struct snd_soc_dai *dai)
Mark Brown07ed8732012-06-18 21:08:44 +0100715{
716 struct snd_soc_codec *codec = dai->codec;
Mark Brownc013b272012-07-04 20:05:57 +0100717 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
718 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown07ed8732012-06-18 21:08:44 +0100719 int base = dai->driver->base;
Mark Brownb272efc2012-10-10 15:10:08 +0900720 int i, sr_val;
721
722 /*
723 * We will need to be more flexible than this in future,
724 * currently we use a single sample rate for SYSCLK.
725 */
726 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
727 if (arizona_sr_vals[i] == params_rate(params))
728 break;
729 if (i == ARRAY_SIZE(arizona_sr_vals)) {
730 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
731 params_rate(params));
732 return -EINVAL;
733 }
734 sr_val = i;
735
736 switch (dai_priv->clk) {
737 case ARIZONA_CLK_SYSCLK:
738 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
739 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
740 if (base)
741 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
742 ARIZONA_AIF1_RATE_MASK, 0);
743 break;
744 case ARIZONA_CLK_ASYNCCLK:
745 snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
746 ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val);
747 if (base)
748 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
749 ARIZONA_AIF1_RATE_MASK,
750 8 << ARIZONA_AIF1_RATE_SHIFT);
751 break;
752 default:
753 arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
754 return -EINVAL;
755 }
756
757 return 0;
758}
759
760static int arizona_hw_params(struct snd_pcm_substream *substream,
761 struct snd_pcm_hw_params *params,
762 struct snd_soc_dai *dai)
763{
764 struct snd_soc_codec *codec = dai->codec;
Mark Brownc94aa302013-01-17 16:35:14 +0900765 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
766 struct arizona *arizona = priv->arizona;
Mark Brownb272efc2012-10-10 15:10:08 +0900767 int base = dai->driver->base;
Mark Brown07ed8732012-06-18 21:08:44 +0100768 const int *rates;
Mark Brownb272efc2012-10-10 15:10:08 +0900769 int i, ret;
Mark Brownc94aa302013-01-17 16:35:14 +0900770 int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
771 int bclk, lrclk, wl, frame, bclk_target;
Mark Brown07ed8732012-06-18 21:08:44 +0100772
773 if (params_rate(params) % 8000)
Mark Brown949e6bc2012-07-04 18:58:04 +0100774 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +0100775 else
Mark Brown949e6bc2012-07-04 18:58:04 +0100776 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +0100777
Mark Brownc94aa302013-01-17 16:35:14 +0900778 bclk_target = snd_soc_params_to_bclk(params);
779 if (chan_limit && chan_limit < params_channels(params)) {
780 arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
781 bclk_target /= params_channels(params);
782 bclk_target *= chan_limit;
783 }
784
Mark Brown949e6bc2012-07-04 18:58:04 +0100785 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brownc94aa302013-01-17 16:35:14 +0900786 if (rates[i] >= bclk_target &&
Mark Brown50017652012-07-04 19:07:09 +0100787 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +0100788 bclk = i;
789 break;
790 }
791 }
Mark Brown949e6bc2012-07-04 18:58:04 +0100792 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +0100793 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
794 params_rate(params));
795 return -EINVAL;
796 }
797
Mark Brownb59e0f82013-01-17 14:15:59 +0900798 lrclk = rates[bclk] / params_rate(params);
Mark Brown07ed8732012-06-18 21:08:44 +0100799
800 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
801 rates[bclk], rates[bclk] / lrclk);
802
803 wl = snd_pcm_format_width(params_format(params));
804 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl;
805
Mark Brownb272efc2012-10-10 15:10:08 +0900806 ret = arizona_hw_params_rate(substream, params, dai);
807 if (ret != 0)
808 return ret;
Mark Brownc013b272012-07-04 20:05:57 +0100809
Mark Brown07ed8732012-06-18 21:08:44 +0100810 snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
811 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
812 snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_BCLK_RATE,
813 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
814 snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_BCLK_RATE,
815 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
816 snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_1,
817 ARIZONA_AIF1TX_WL_MASK |
818 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
819 snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_2,
820 ARIZONA_AIF1RX_WL_MASK |
821 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
822
823 return 0;
824}
825
Mark Brown410837a2012-07-05 17:26:59 +0100826static const char *arizona_dai_clk_str(int clk_id)
827{
828 switch (clk_id) {
829 case ARIZONA_CLK_SYSCLK:
830 return "SYSCLK";
831 case ARIZONA_CLK_ASYNCCLK:
832 return "ASYNCCLK";
833 default:
834 return "Unknown clock";
835 }
836}
837
Mark Brown5b2eec32012-07-04 17:32:05 +0100838static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
839 int clk_id, unsigned int freq, int dir)
840{
841 struct snd_soc_codec *codec = dai->codec;
842 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
843 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown410837a2012-07-05 17:26:59 +0100844 struct snd_soc_dapm_route routes[2];
Mark Brown5b2eec32012-07-04 17:32:05 +0100845
846 switch (clk_id) {
847 case ARIZONA_CLK_SYSCLK:
848 case ARIZONA_CLK_ASYNCCLK:
849 break;
850 default:
851 return -EINVAL;
852 }
853
Mark Brown410837a2012-07-05 17:26:59 +0100854 if (clk_id == dai_priv->clk)
855 return 0;
856
857 if (dai->active) {
Mark Brown5b2eec32012-07-04 17:32:05 +0100858 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
859 dai->id);
860 return -EBUSY;
861 }
862
Mark Brownc8d35a62012-12-07 12:49:40 +0900863 dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1,
864 arizona_dai_clk_str(clk_id));
865
Mark Brown410837a2012-07-05 17:26:59 +0100866 memset(&routes, 0, sizeof(routes));
867 routes[0].sink = dai->driver->capture.stream_name;
868 routes[1].sink = dai->driver->playback.stream_name;
Mark Brown5b2eec32012-07-04 17:32:05 +0100869
Mark Brown410837a2012-07-05 17:26:59 +0100870 routes[0].source = arizona_dai_clk_str(dai_priv->clk);
871 routes[1].source = arizona_dai_clk_str(dai_priv->clk);
872 snd_soc_dapm_del_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
873
874 routes[0].source = arizona_dai_clk_str(clk_id);
875 routes[1].source = arizona_dai_clk_str(clk_id);
876 snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
877
Mark Brown0c778e82012-12-06 18:22:25 +0900878 dai_priv->clk = clk_id;
879
Mark Brown410837a2012-07-05 17:26:59 +0100880 return snd_soc_dapm_sync(&codec->dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +0100881}
882
Mark Brown01df2592012-12-12 16:22:08 +0900883static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
884{
885 struct snd_soc_codec *codec = dai->codec;
886 int base = dai->driver->base;
887 unsigned int reg;
888
889 if (tristate)
890 reg = ARIZONA_AIF1_TRI;
891 else
892 reg = 0;
893
894 return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
895 ARIZONA_AIF1_TRI, reg);
896}
897
Mark Brown07ed8732012-06-18 21:08:44 +0100898const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +0100899 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +0100900 .set_fmt = arizona_set_fmt,
901 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +0100902 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown01df2592012-12-12 16:22:08 +0900903 .set_tristate = arizona_set_tristate,
Mark Brown07ed8732012-06-18 21:08:44 +0100904};
Mark Browna8379872012-07-09 12:16:41 +0100905EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +0100906
Mark Brown5b2eec32012-07-04 17:32:05 +0100907int arizona_init_dai(struct arizona_priv *priv, int id)
908{
909 struct arizona_dai_priv *dai_priv = &priv->dai[id];
910
911 dai_priv->clk = ARIZONA_CLK_SYSCLK;
912
913 return 0;
914}
915EXPORT_SYMBOL_GPL(arizona_init_dai);
916
Mark Brown07ed8732012-06-18 21:08:44 +0100917static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
918{
919 struct arizona_fll *fll = data;
920
921 arizona_fll_dbg(fll, "clock OK\n");
922
923 complete(&fll->ok);
924
925 return IRQ_HANDLED;
926}
927
928static struct {
929 unsigned int min;
930 unsigned int max;
931 u16 fratio;
932 int ratio;
933} fll_fratios[] = {
934 { 0, 64000, 4, 16 },
935 { 64000, 128000, 3, 8 },
936 { 128000, 256000, 2, 4 },
937 { 256000, 1000000, 1, 2 },
938 { 1000000, 13500000, 0, 1 },
939};
940
941struct arizona_fll_cfg {
942 int n;
943 int theta;
944 int lambda;
945 int refdiv;
946 int outdiv;
947 int fratio;
948};
949
950static int arizona_calc_fll(struct arizona_fll *fll,
951 struct arizona_fll_cfg *cfg,
952 unsigned int Fref,
953 unsigned int Fout)
954{
955 unsigned int target, div, gcd_fll;
956 int i, ratio;
957
958 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout);
959
960 /* Fref must be <=13.5MHz */
961 div = 1;
962 cfg->refdiv = 0;
963 while ((Fref / div) > 13500000) {
964 div *= 2;
965 cfg->refdiv++;
966
967 if (div > 8) {
968 arizona_fll_err(fll,
969 "Can't scale %dMHz in to <=13.5MHz\n",
970 Fref);
971 return -EINVAL;
972 }
973 }
974
975 /* Apply the division for our remaining calculations */
976 Fref /= div;
977
Mark Brown2b4d39f2012-07-10 17:03:46 +0100978 /* Fvco should be over the targt; don't check the upper bound */
Mark Brown07ed8732012-06-18 21:08:44 +0100979 div = 1;
Mark Brown2b4d39f2012-07-10 17:03:46 +0100980 while (Fout * div < 90000000 * fll->vco_mult) {
Mark Brown07ed8732012-06-18 21:08:44 +0100981 div++;
982 if (div > 7) {
983 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
984 Fout);
985 return -EINVAL;
986 }
987 }
Mark Brown2b4d39f2012-07-10 17:03:46 +0100988 target = Fout * div / fll->vco_mult;
Mark Brown07ed8732012-06-18 21:08:44 +0100989 cfg->outdiv = div;
990
991 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
992
993 /* Find an appropraite FLL_FRATIO and factor it out of the target */
994 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
995 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
996 cfg->fratio = fll_fratios[i].fratio;
997 ratio = fll_fratios[i].ratio;
998 break;
999 }
1000 }
1001 if (i == ARRAY_SIZE(fll_fratios)) {
1002 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
1003 Fref);
1004 return -EINVAL;
1005 }
1006
1007 cfg->n = target / (ratio * Fref);
1008
1009 if (target % Fref) {
1010 gcd_fll = gcd(target, ratio * Fref);
1011 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
1012
1013 cfg->theta = (target - (cfg->n * ratio * Fref))
1014 / gcd_fll;
1015 cfg->lambda = (ratio * Fref) / gcd_fll;
1016 } else {
1017 cfg->theta = 0;
1018 cfg->lambda = 0;
1019 }
1020
1021 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
1022 cfg->n, cfg->theta, cfg->lambda);
1023 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
1024 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
1025
1026 return 0;
1027
1028}
1029
1030static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
1031 struct arizona_fll_cfg *cfg, int source)
1032{
1033 regmap_update_bits(arizona->regmap, base + 3,
1034 ARIZONA_FLL1_THETA_MASK, cfg->theta);
1035 regmap_update_bits(arizona->regmap, base + 4,
1036 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
1037 regmap_update_bits(arizona->regmap, base + 5,
1038 ARIZONA_FLL1_FRATIO_MASK,
1039 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
1040 regmap_update_bits(arizona->regmap, base + 6,
1041 ARIZONA_FLL1_CLK_REF_DIV_MASK |
1042 ARIZONA_FLL1_CLK_REF_SRC_MASK,
1043 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
1044 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
1045
1046 regmap_update_bits(arizona->regmap, base + 2,
1047 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
1048 ARIZONA_FLL1_CTRL_UPD | cfg->n);
1049}
1050
1051int arizona_set_fll(struct arizona_fll *fll, int source,
1052 unsigned int Fref, unsigned int Fout)
1053{
1054 struct arizona *arizona = fll->arizona;
1055 struct arizona_fll_cfg cfg, sync;
1056 unsigned int reg, val;
1057 int syncsrc;
1058 bool ena;
1059 int ret;
1060
Mark Brown1cbe4bc2012-11-21 14:12:22 +09001061 if (fll->fref == Fref && fll->fout == Fout)
1062 return 0;
1063
Mark Brown07ed8732012-06-18 21:08:44 +01001064 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
1065 if (ret != 0) {
1066 arizona_fll_err(fll, "Failed to read current state: %d\n",
1067 ret);
1068 return ret;
1069 }
1070 ena = reg & ARIZONA_FLL1_ENA;
1071
1072 if (Fout) {
1073 /* Do we have a 32kHz reference? */
1074 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
1075 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
1076 case ARIZONA_CLK_SRC_MCLK1:
1077 case ARIZONA_CLK_SRC_MCLK2:
1078 syncsrc = val & ARIZONA_CLK_32K_SRC_MASK;
1079 break;
1080 default:
1081 syncsrc = -1;
1082 }
1083
1084 if (source == syncsrc)
1085 syncsrc = -1;
1086
1087 if (syncsrc >= 0) {
1088 ret = arizona_calc_fll(fll, &sync, Fref, Fout);
1089 if (ret != 0)
1090 return ret;
1091
1092 ret = arizona_calc_fll(fll, &cfg, 32768, Fout);
1093 if (ret != 0)
1094 return ret;
1095 } else {
1096 ret = arizona_calc_fll(fll, &cfg, Fref, Fout);
1097 if (ret != 0)
1098 return ret;
1099 }
1100 } else {
1101 regmap_update_bits(arizona->regmap, fll->base + 1,
1102 ARIZONA_FLL1_ENA, 0);
1103 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1104 ARIZONA_FLL1_SYNC_ENA, 0);
1105
1106 if (ena)
1107 pm_runtime_put_autosuspend(arizona->dev);
1108
Mark Brown50fcfe42012-11-28 11:50:34 +00001109 fll->fref = Fref;
1110 fll->fout = Fout;
1111
Mark Brown07ed8732012-06-18 21:08:44 +01001112 return 0;
1113 }
1114
1115 regmap_update_bits(arizona->regmap, fll->base + 5,
1116 ARIZONA_FLL1_OUTDIV_MASK,
1117 cfg.outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
1118
1119 if (syncsrc >= 0) {
1120 arizona_apply_fll(arizona, fll->base, &cfg, syncsrc);
1121 arizona_apply_fll(arizona, fll->base + 0x10, &sync, source);
1122 } else {
1123 arizona_apply_fll(arizona, fll->base, &cfg, source);
1124 }
1125
1126 if (!ena)
1127 pm_runtime_get(arizona->dev);
1128
1129 /* Clear any pending completions */
1130 try_wait_for_completion(&fll->ok);
1131
1132 regmap_update_bits(arizona->regmap, fll->base + 1,
1133 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
1134 if (syncsrc >= 0)
1135 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1136 ARIZONA_FLL1_SYNC_ENA,
1137 ARIZONA_FLL1_SYNC_ENA);
1138
1139 ret = wait_for_completion_timeout(&fll->ok,
Mark Brown09871a92012-12-06 15:29:34 +09001140 msecs_to_jiffies(250));
Mark Brown07ed8732012-06-18 21:08:44 +01001141 if (ret == 0)
1142 arizona_fll_warn(fll, "Timed out waiting for lock\n");
1143
Mark Brown1cbe4bc2012-11-21 14:12:22 +09001144 fll->fref = Fref;
1145 fll->fout = Fout;
1146
Mark Brown07ed8732012-06-18 21:08:44 +01001147 return 0;
1148}
1149EXPORT_SYMBOL_GPL(arizona_set_fll);
1150
1151int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
1152 int ok_irq, struct arizona_fll *fll)
1153{
1154 int ret;
1155
Mark Brown07ed8732012-06-18 21:08:44 +01001156 init_completion(&fll->ok);
1157
1158 fll->id = id;
1159 fll->base = base;
1160 fll->arizona = arizona;
1161
1162 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
1163 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
1164 "FLL%d clock OK", id);
1165
Mark Brown07ed8732012-06-18 21:08:44 +01001166 ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
1167 arizona_fll_clock_ok, fll);
1168 if (ret != 0) {
1169 dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
1170 id, ret);
1171 }
1172
Charles Keepaxe31c1942013-01-07 16:41:45 +00001173 regmap_update_bits(arizona->regmap, fll->base + 1,
1174 ARIZONA_FLL1_FREERUN, 0);
1175
Mark Brown07ed8732012-06-18 21:08:44 +01001176 return 0;
1177}
1178EXPORT_SYMBOL_GPL(arizona_init_fll);
1179
Mark Brownbc9ab6d2013-01-04 19:31:00 +00001180/**
1181 * arizona_set_output_mode - Set the mode of the specified output
1182 *
1183 * @codec: Device to configure
1184 * @output: Output number
1185 * @diff: True to set the output to differential mode
1186 *
1187 * Some systems use external analogue switches to connect more
1188 * analogue devices to the CODEC than are supported by the device. In
1189 * some systems this requires changing the switched output from single
1190 * ended to differential mode dynamically at runtime, an operation
1191 * supported using this function.
1192 *
1193 * Most systems have a single static configuration and should use
1194 * platform data instead.
1195 */
1196int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
1197{
1198 unsigned int reg, val;
1199
1200 if (output < 1 || output > 6)
1201 return -EINVAL;
1202
1203 reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
1204
1205 if (diff)
1206 val = ARIZONA_OUT1_MONO;
1207 else
1208 val = 0;
1209
1210 return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val);
1211}
1212EXPORT_SYMBOL_GPL(arizona_set_output_mode);
1213
Mark Brown07ed8732012-06-18 21:08:44 +01001214MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
1215MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1216MODULE_LICENSE("GPL");