blob: 149e44f42f84abf3203d5d74aa2d4fc3ae5ddcc8 [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, ...) \
Mark Brown9092a6e2013-02-06 17:58:57 +000059 dev_dbg(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
Mark Brown07ed8732012-06-18 21:08:44 +010060
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, ...) \
Mark Brown9092a6e2013-02-06 17:58:57 +000066 dev_dbg(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
Mark Brown07ed8732012-06-18 21:08:44 +010067
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{
Mark Brown43cd8bf2013-02-06 16:57:29 +0000338 unsigned int reg;
339
340 if (w->shift % 2)
341 reg = ARIZONA_ADC_DIGITAL_VOLUME_1L + ((w->shift / 2) * 8);
342 else
343 reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8);
344
345 switch (event) {
346 case SND_SOC_DAPM_POST_PMU:
347 snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, 0);
348 break;
349 case SND_SOC_DAPM_PRE_PMD:
350 snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE,
351 ARIZONA_IN1L_MUTE);
352 break;
353 }
354
Mark Brown07ed8732012-06-18 21:08:44 +0100355 return 0;
356}
357EXPORT_SYMBOL_GPL(arizona_in_ev);
358
359int arizona_out_ev(struct snd_soc_dapm_widget *w,
360 struct snd_kcontrol *kcontrol,
361 int event)
362{
363 return 0;
364}
365EXPORT_SYMBOL_GPL(arizona_out_ev);
366
Mark Browncbd840d2012-08-08 17:52:44 +0100367static unsigned int arizona_sysclk_48k_rates[] = {
368 6144000,
369 12288000,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000370 24576000,
Mark Browncbd840d2012-08-08 17:52:44 +0100371 49152000,
Mark Brownaeaeee12012-09-26 17:50:02 +0100372 73728000,
373 98304000,
374 147456000,
Mark Browncbd840d2012-08-08 17:52:44 +0100375};
376
377static unsigned int arizona_sysclk_44k1_rates[] = {
378 5644800,
379 11289600,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000380 22579200,
Mark Browncbd840d2012-08-08 17:52:44 +0100381 45158400,
Mark Brownaeaeee12012-09-26 17:50:02 +0100382 67737600,
383 90316800,
384 135475200,
Mark Browncbd840d2012-08-08 17:52:44 +0100385};
386
387static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
388 unsigned int freq)
389{
390 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
391 unsigned int reg;
392 unsigned int *rates;
393 int ref, div, refclk;
394
395 switch (clk) {
396 case ARIZONA_CLK_OPCLK:
397 reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
398 refclk = priv->sysclk;
399 break;
400 case ARIZONA_CLK_ASYNC_OPCLK:
401 reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
402 refclk = priv->asyncclk;
403 break;
404 default:
405 return -EINVAL;
406 }
407
408 if (refclk % 8000)
409 rates = arizona_sysclk_44k1_rates;
410 else
411 rates = arizona_sysclk_48k_rates;
412
413 for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) &&
414 rates[ref] <= refclk; ref++) {
415 div = 1;
416 while (rates[ref] / div >= freq && div < 32) {
417 if (rates[ref] / div == freq) {
418 dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
419 freq);
420 snd_soc_update_bits(codec, reg,
421 ARIZONA_OPCLK_DIV_MASK |
422 ARIZONA_OPCLK_SEL_MASK,
423 (div <<
424 ARIZONA_OPCLK_DIV_SHIFT) |
425 ref);
426 return 0;
427 }
428 div++;
429 }
430 }
431
432 dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
433 return -EINVAL;
434}
435
Mark Brown07ed8732012-06-18 21:08:44 +0100436int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
437 int source, unsigned int freq, int dir)
438{
439 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
440 struct arizona *arizona = priv->arizona;
441 char *name;
442 unsigned int reg;
443 unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
444 unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
445 unsigned int *clk;
446
447 switch (clk_id) {
448 case ARIZONA_CLK_SYSCLK:
449 name = "SYSCLK";
450 reg = ARIZONA_SYSTEM_CLOCK_1;
451 clk = &priv->sysclk;
452 mask |= ARIZONA_SYSCLK_FRAC;
453 break;
454 case ARIZONA_CLK_ASYNCCLK:
455 name = "ASYNCCLK";
456 reg = ARIZONA_ASYNC_CLOCK_1;
457 clk = &priv->asyncclk;
458 break;
Mark Browncbd840d2012-08-08 17:52:44 +0100459 case ARIZONA_CLK_OPCLK:
460 case ARIZONA_CLK_ASYNC_OPCLK:
461 return arizona_set_opclk(codec, clk_id, freq);
Mark Brown07ed8732012-06-18 21:08:44 +0100462 default:
463 return -EINVAL;
464 }
465
466 switch (freq) {
467 case 5644800:
468 case 6144000:
469 break;
470 case 11289600:
471 case 12288000:
472 val |= 1 << ARIZONA_SYSCLK_FREQ_SHIFT;
473 break;
474 case 22579200:
475 case 24576000:
476 val |= 2 << ARIZONA_SYSCLK_FREQ_SHIFT;
477 break;
478 case 45158400:
479 case 49152000:
480 val |= 3 << ARIZONA_SYSCLK_FREQ_SHIFT;
481 break;
Mark Brown38113362012-11-26 16:01:37 +0000482 case 67737600:
483 case 73728000:
484 val |= 4 << ARIZONA_SYSCLK_FREQ_SHIFT;
485 break;
486 case 90316800:
487 case 98304000:
488 val |= 5 << ARIZONA_SYSCLK_FREQ_SHIFT;
489 break;
490 case 135475200:
491 case 147456000:
492 val |= 6 << ARIZONA_SYSCLK_FREQ_SHIFT;
493 break;
Mark Brownf2c26d42013-01-21 16:09:36 +0900494 case 0:
495 dev_dbg(arizona->dev, "%s cleared\n", name);
496 *clk = freq;
497 return 0;
Mark Brown07ed8732012-06-18 21:08:44 +0100498 default:
499 return -EINVAL;
500 }
501
502 *clk = freq;
503
504 if (freq % 6144000)
505 val |= ARIZONA_SYSCLK_FRAC;
506
507 dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
508
509 return regmap_update_bits(arizona->regmap, reg, mask, val);
510}
511EXPORT_SYMBOL_GPL(arizona_set_sysclk);
512
513static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
514{
515 struct snd_soc_codec *codec = dai->codec;
516 int lrclk, bclk, mode, base;
517
518 base = dai->driver->base;
519
520 lrclk = 0;
521 bclk = 0;
522
523 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
524 case SND_SOC_DAIFMT_DSP_A:
525 mode = 0;
526 break;
Mark Brown07ed8732012-06-18 21:08:44 +0100527 case SND_SOC_DAIFMT_I2S:
528 mode = 2;
529 break;
Mark Brown07ed8732012-06-18 21:08:44 +0100530 default:
531 arizona_aif_err(dai, "Unsupported DAI format %d\n",
532 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
533 return -EINVAL;
534 }
535
536 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
537 case SND_SOC_DAIFMT_CBS_CFS:
538 break;
539 case SND_SOC_DAIFMT_CBS_CFM:
540 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
541 break;
542 case SND_SOC_DAIFMT_CBM_CFS:
543 bclk |= ARIZONA_AIF1_BCLK_MSTR;
544 break;
545 case SND_SOC_DAIFMT_CBM_CFM:
546 bclk |= ARIZONA_AIF1_BCLK_MSTR;
547 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
548 break;
549 default:
550 arizona_aif_err(dai, "Unsupported master mode %d\n",
551 fmt & SND_SOC_DAIFMT_MASTER_MASK);
552 return -EINVAL;
553 }
554
555 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
556 case SND_SOC_DAIFMT_NB_NF:
557 break;
558 case SND_SOC_DAIFMT_IB_IF:
559 bclk |= ARIZONA_AIF1_BCLK_INV;
560 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
561 break;
562 case SND_SOC_DAIFMT_IB_NF:
563 bclk |= ARIZONA_AIF1_BCLK_INV;
564 break;
565 case SND_SOC_DAIFMT_NB_IF:
566 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
567 break;
568 default:
569 return -EINVAL;
570 }
571
572 snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
573 ARIZONA_AIF1_BCLK_INV | ARIZONA_AIF1_BCLK_MSTR,
574 bclk);
575 snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_PIN_CTRL,
576 ARIZONA_AIF1TX_LRCLK_INV |
577 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
578 snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_PIN_CTRL,
579 ARIZONA_AIF1RX_LRCLK_INV |
580 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
581 snd_soc_update_bits(codec, base + ARIZONA_AIF_FORMAT,
582 ARIZONA_AIF1_FMT_MASK, mode);
583
584 return 0;
585}
586
Mark Brown949e6bc2012-07-04 18:58:04 +0100587static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100588 -1,
589 48000,
590 64000,
591 96000,
592 128000,
593 192000,
594 256000,
595 384000,
596 512000,
597 768000,
598 1024000,
599 1536000,
600 2048000,
601 3072000,
602 4096000,
603 6144000,
604 8192000,
605 12288000,
606 24576000,
607};
608
Mark Brown5b2eec32012-07-04 17:32:05 +0100609static const unsigned int arizona_48k_rates[] = {
610 12000,
611 24000,
612 48000,
613 96000,
614 192000,
615 384000,
616 768000,
617 4000,
618 8000,
619 16000,
620 32000,
621 64000,
622 128000,
623 256000,
624 512000,
625};
626
627static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = {
628 .count = ARRAY_SIZE(arizona_48k_rates),
629 .list = arizona_48k_rates,
630};
631
Mark Brown949e6bc2012-07-04 18:58:04 +0100632static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100633 -1,
634 44100,
635 58800,
636 88200,
637 117600,
638 177640,
639 235200,
640 352800,
641 470400,
642 705600,
643 940800,
644 1411200,
645 1881600,
Heather Lomond4758be32012-09-05 05:02:10 -0400646 2822400,
Mark Brown07ed8732012-06-18 21:08:44 +0100647 3763200,
648 5644800,
649 7526400,
650 11289600,
651 22579200,
652};
653
Mark Brown5b2eec32012-07-04 17:32:05 +0100654static const unsigned int arizona_44k1_rates[] = {
655 11025,
656 22050,
657 44100,
658 88200,
659 176400,
660 352800,
661 705600,
662};
663
664static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = {
665 .count = ARRAY_SIZE(arizona_44k1_rates),
666 .list = arizona_44k1_rates,
667};
668
Mark Brown07ed8732012-06-18 21:08:44 +0100669static int arizona_sr_vals[] = {
670 0,
671 12000,
672 24000,
673 48000,
674 96000,
675 192000,
676 384000,
677 768000,
678 0,
679 11025,
680 22050,
681 44100,
682 88200,
683 176400,
684 352800,
685 705600,
686 4000,
687 8000,
688 16000,
689 32000,
690 64000,
691 128000,
692 256000,
693 512000,
694};
695
Mark Brown5b2eec32012-07-04 17:32:05 +0100696static int arizona_startup(struct snd_pcm_substream *substream,
697 struct snd_soc_dai *dai)
698{
699 struct snd_soc_codec *codec = dai->codec;
700 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
701 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
702 const struct snd_pcm_hw_constraint_list *constraint;
703 unsigned int base_rate;
704
705 switch (dai_priv->clk) {
706 case ARIZONA_CLK_SYSCLK:
707 base_rate = priv->sysclk;
708 break;
709 case ARIZONA_CLK_ASYNCCLK:
710 base_rate = priv->asyncclk;
711 break;
712 default:
713 return 0;
714 }
715
Mark Brownf2c26d42013-01-21 16:09:36 +0900716 if (base_rate == 0)
717 return 0;
718
Mark Brown5b2eec32012-07-04 17:32:05 +0100719 if (base_rate % 8000)
720 constraint = &arizona_44k1_constraint;
721 else
722 constraint = &arizona_48k_constraint;
723
724 return snd_pcm_hw_constraint_list(substream->runtime, 0,
725 SNDRV_PCM_HW_PARAM_RATE,
726 constraint);
727}
728
Mark Brownb272efc2012-10-10 15:10:08 +0900729static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
730 struct snd_pcm_hw_params *params,
731 struct snd_soc_dai *dai)
Mark Brown07ed8732012-06-18 21:08:44 +0100732{
733 struct snd_soc_codec *codec = dai->codec;
Mark Brownc013b272012-07-04 20:05:57 +0100734 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
735 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown07ed8732012-06-18 21:08:44 +0100736 int base = dai->driver->base;
Mark Brownb272efc2012-10-10 15:10:08 +0900737 int i, sr_val;
738
739 /*
740 * We will need to be more flexible than this in future,
741 * currently we use a single sample rate for SYSCLK.
742 */
743 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
744 if (arizona_sr_vals[i] == params_rate(params))
745 break;
746 if (i == ARRAY_SIZE(arizona_sr_vals)) {
747 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
748 params_rate(params));
749 return -EINVAL;
750 }
751 sr_val = i;
752
753 switch (dai_priv->clk) {
754 case ARIZONA_CLK_SYSCLK:
755 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
756 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
757 if (base)
758 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
759 ARIZONA_AIF1_RATE_MASK, 0);
760 break;
761 case ARIZONA_CLK_ASYNCCLK:
762 snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
763 ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val);
764 if (base)
765 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
766 ARIZONA_AIF1_RATE_MASK,
767 8 << ARIZONA_AIF1_RATE_SHIFT);
768 break;
769 default:
770 arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
771 return -EINVAL;
772 }
773
774 return 0;
775}
776
Mark Brown07ed8732012-06-18 21:08:44 +0100777static int arizona_hw_params(struct snd_pcm_substream *substream,
778 struct snd_pcm_hw_params *params,
779 struct snd_soc_dai *dai)
780{
781 struct snd_soc_codec *codec = dai->codec;
782 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brownc94aa302013-01-17 16:35:14 +0900783 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +0100784 int base = dai->driver->base;
785 const int *rates;
Mark Brownb272efc2012-10-10 15:10:08 +0900786 int i, ret;
Mark Brownc94aa302013-01-17 16:35:14 +0900787 int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
788 int bclk, lrclk, wl, frame, bclk_target;
Mark Brown07ed8732012-06-18 21:08:44 +0100789
790 if (params_rate(params) % 8000)
Mark Brown949e6bc2012-07-04 18:58:04 +0100791 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +0100792 else
Mark Brown949e6bc2012-07-04 18:58:04 +0100793 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +0100794
Mark Brownc94aa302013-01-17 16:35:14 +0900795 bclk_target = snd_soc_params_to_bclk(params);
796 if (chan_limit && chan_limit < params_channels(params)) {
797 arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
798 bclk_target /= params_channels(params);
799 bclk_target *= chan_limit;
800 }
801
Mark Brown949e6bc2012-07-04 18:58:04 +0100802 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brownc94aa302013-01-17 16:35:14 +0900803 if (rates[i] >= bclk_target &&
Mark Brown50017652012-07-04 19:07:09 +0100804 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +0100805 bclk = i;
806 break;
807 }
808 }
Mark Brown949e6bc2012-07-04 18:58:04 +0100809 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +0100810 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
811 params_rate(params));
812 return -EINVAL;
813 }
814
Mark Brownb59e0f82013-01-17 14:15:59 +0900815 lrclk = rates[bclk] / params_rate(params);
Mark Brown07ed8732012-06-18 21:08:44 +0100816
817 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
818 rates[bclk], rates[bclk] / lrclk);
819
820 wl = snd_pcm_format_width(params_format(params));
821 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl;
822
Mark Brownb272efc2012-10-10 15:10:08 +0900823 ret = arizona_hw_params_rate(substream, params, dai);
824 if (ret != 0)
825 return ret;
Mark Brownc013b272012-07-04 20:05:57 +0100826
Mark Brown07ed8732012-06-18 21:08:44 +0100827 snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
828 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
829 snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_BCLK_RATE,
830 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
831 snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_BCLK_RATE,
832 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
833 snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_1,
834 ARIZONA_AIF1TX_WL_MASK |
835 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
836 snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_2,
837 ARIZONA_AIF1RX_WL_MASK |
838 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
839
840 return 0;
841}
842
Mark Brown410837a2012-07-05 17:26:59 +0100843static const char *arizona_dai_clk_str(int clk_id)
844{
845 switch (clk_id) {
846 case ARIZONA_CLK_SYSCLK:
847 return "SYSCLK";
848 case ARIZONA_CLK_ASYNCCLK:
849 return "ASYNCCLK";
850 default:
851 return "Unknown clock";
852 }
853}
854
Mark Brown5b2eec32012-07-04 17:32:05 +0100855static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
856 int clk_id, unsigned int freq, int dir)
857{
858 struct snd_soc_codec *codec = dai->codec;
859 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
860 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown410837a2012-07-05 17:26:59 +0100861 struct snd_soc_dapm_route routes[2];
Mark Brown5b2eec32012-07-04 17:32:05 +0100862
863 switch (clk_id) {
864 case ARIZONA_CLK_SYSCLK:
865 case ARIZONA_CLK_ASYNCCLK:
866 break;
867 default:
868 return -EINVAL;
869 }
870
Mark Brown410837a2012-07-05 17:26:59 +0100871 if (clk_id == dai_priv->clk)
872 return 0;
873
874 if (dai->active) {
Mark Brown5b2eec32012-07-04 17:32:05 +0100875 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
876 dai->id);
877 return -EBUSY;
878 }
879
Mark Brownc8d35a62012-12-07 12:49:40 +0900880 dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1,
881 arizona_dai_clk_str(clk_id));
882
Mark Brown410837a2012-07-05 17:26:59 +0100883 memset(&routes, 0, sizeof(routes));
884 routes[0].sink = dai->driver->capture.stream_name;
885 routes[1].sink = dai->driver->playback.stream_name;
Mark Brown5b2eec32012-07-04 17:32:05 +0100886
Mark Brown410837a2012-07-05 17:26:59 +0100887 routes[0].source = arizona_dai_clk_str(dai_priv->clk);
888 routes[1].source = arizona_dai_clk_str(dai_priv->clk);
889 snd_soc_dapm_del_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
890
891 routes[0].source = arizona_dai_clk_str(clk_id);
892 routes[1].source = arizona_dai_clk_str(clk_id);
893 snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
894
Mark Brown0c778e82012-12-06 18:22:25 +0900895 dai_priv->clk = clk_id;
896
Mark Brown410837a2012-07-05 17:26:59 +0100897 return snd_soc_dapm_sync(&codec->dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +0100898}
899
Mark Brown01df2592012-12-12 16:22:08 +0900900static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
901{
902 struct snd_soc_codec *codec = dai->codec;
903 int base = dai->driver->base;
904 unsigned int reg;
905
906 if (tristate)
907 reg = ARIZONA_AIF1_TRI;
908 else
909 reg = 0;
910
911 return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
912 ARIZONA_AIF1_TRI, reg);
913}
914
Mark Brown07ed8732012-06-18 21:08:44 +0100915const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +0100916 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +0100917 .set_fmt = arizona_set_fmt,
918 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +0100919 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown01df2592012-12-12 16:22:08 +0900920 .set_tristate = arizona_set_tristate,
Mark Brown07ed8732012-06-18 21:08:44 +0100921};
Mark Browna8379872012-07-09 12:16:41 +0100922EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +0100923
Mark Brown5b2eec32012-07-04 17:32:05 +0100924int arizona_init_dai(struct arizona_priv *priv, int id)
925{
926 struct arizona_dai_priv *dai_priv = &priv->dai[id];
927
928 dai_priv->clk = ARIZONA_CLK_SYSCLK;
929
930 return 0;
931}
932EXPORT_SYMBOL_GPL(arizona_init_dai);
933
Mark Brown07ed8732012-06-18 21:08:44 +0100934static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
935{
936 struct arizona_fll *fll = data;
937
938 arizona_fll_dbg(fll, "clock OK\n");
939
940 complete(&fll->ok);
941
942 return IRQ_HANDLED;
943}
944
945static struct {
946 unsigned int min;
947 unsigned int max;
948 u16 fratio;
949 int ratio;
950} fll_fratios[] = {
951 { 0, 64000, 4, 16 },
952 { 64000, 128000, 3, 8 },
953 { 128000, 256000, 2, 4 },
954 { 256000, 1000000, 1, 2 },
955 { 1000000, 13500000, 0, 1 },
956};
957
958struct arizona_fll_cfg {
959 int n;
960 int theta;
961 int lambda;
962 int refdiv;
963 int outdiv;
964 int fratio;
965};
966
967static int arizona_calc_fll(struct arizona_fll *fll,
968 struct arizona_fll_cfg *cfg,
969 unsigned int Fref,
970 unsigned int Fout)
971{
972 unsigned int target, div, gcd_fll;
973 int i, ratio;
974
975 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout);
976
977 /* Fref must be <=13.5MHz */
978 div = 1;
979 cfg->refdiv = 0;
980 while ((Fref / div) > 13500000) {
981 div *= 2;
982 cfg->refdiv++;
983
984 if (div > 8) {
985 arizona_fll_err(fll,
986 "Can't scale %dMHz in to <=13.5MHz\n",
987 Fref);
988 return -EINVAL;
989 }
990 }
991
992 /* Apply the division for our remaining calculations */
993 Fref /= div;
994
Mark Brown2b4d39f2012-07-10 17:03:46 +0100995 /* Fvco should be over the targt; don't check the upper bound */
Mark Brown07ed8732012-06-18 21:08:44 +0100996 div = 1;
Mark Brown2b4d39f2012-07-10 17:03:46 +0100997 while (Fout * div < 90000000 * fll->vco_mult) {
Mark Brown07ed8732012-06-18 21:08:44 +0100998 div++;
999 if (div > 7) {
1000 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
1001 Fout);
1002 return -EINVAL;
1003 }
1004 }
Mark Brown2b4d39f2012-07-10 17:03:46 +01001005 target = Fout * div / fll->vco_mult;
Mark Brown07ed8732012-06-18 21:08:44 +01001006 cfg->outdiv = div;
1007
1008 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
1009
1010 /* Find an appropraite FLL_FRATIO and factor it out of the target */
1011 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
1012 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
1013 cfg->fratio = fll_fratios[i].fratio;
1014 ratio = fll_fratios[i].ratio;
1015 break;
1016 }
1017 }
1018 if (i == ARRAY_SIZE(fll_fratios)) {
1019 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
1020 Fref);
1021 return -EINVAL;
1022 }
1023
1024 cfg->n = target / (ratio * Fref);
1025
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001026 if (target % (ratio * Fref)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001027 gcd_fll = gcd(target, ratio * Fref);
1028 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
1029
1030 cfg->theta = (target - (cfg->n * ratio * Fref))
1031 / gcd_fll;
1032 cfg->lambda = (ratio * Fref) / gcd_fll;
1033 } else {
1034 cfg->theta = 0;
1035 cfg->lambda = 0;
1036 }
1037
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001038 /* Round down to 16bit range with cost of accuracy lost.
1039 * Denominator must be bigger than numerator so we only
1040 * take care of it.
1041 */
1042 while (cfg->lambda >= (1 << 16)) {
1043 cfg->theta >>= 1;
1044 cfg->lambda >>= 1;
1045 }
1046
Mark Brown07ed8732012-06-18 21:08:44 +01001047 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
1048 cfg->n, cfg->theta, cfg->lambda);
1049 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
1050 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
1051
1052 return 0;
1053
1054}
1055
1056static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
1057 struct arizona_fll_cfg *cfg, int source)
1058{
1059 regmap_update_bits(arizona->regmap, base + 3,
1060 ARIZONA_FLL1_THETA_MASK, cfg->theta);
1061 regmap_update_bits(arizona->regmap, base + 4,
1062 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
1063 regmap_update_bits(arizona->regmap, base + 5,
1064 ARIZONA_FLL1_FRATIO_MASK,
1065 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
1066 regmap_update_bits(arizona->regmap, base + 6,
1067 ARIZONA_FLL1_CLK_REF_DIV_MASK |
1068 ARIZONA_FLL1_CLK_REF_SRC_MASK,
1069 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
1070 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
1071
1072 regmap_update_bits(arizona->regmap, base + 2,
1073 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
1074 ARIZONA_FLL1_CTRL_UPD | cfg->n);
1075}
1076
Charles Keepaxd122d6c2013-02-20 17:28:36 +00001077static bool arizona_is_enabled_fll(struct arizona_fll *fll)
1078{
1079 struct arizona *arizona = fll->arizona;
1080 unsigned int reg;
1081 int ret;
1082
1083 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
1084 if (ret != 0) {
1085 arizona_fll_err(fll, "Failed to read current state: %d\n",
1086 ret);
1087 return ret;
1088 }
1089
1090 return reg & ARIZONA_FLL1_ENA;
1091}
1092
Charles Keepax35722812013-02-20 17:28:38 +00001093static void arizona_enable_fll(struct arizona_fll *fll,
1094 struct arizona_fll_cfg *ref,
1095 struct arizona_fll_cfg *sync)
1096{
1097 struct arizona *arizona = fll->arizona;
1098 int ret;
1099
1100 regmap_update_bits(arizona->regmap, fll->base + 5,
1101 ARIZONA_FLL1_OUTDIV_MASK,
1102 ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
1103
1104 arizona_apply_fll(arizona, fll->base, ref, fll->ref_src);
1105 if (fll->sync_src >= 0)
1106 arizona_apply_fll(arizona, fll->base + 0x10, sync,
1107 fll->sync_src);
1108
1109 if (!arizona_is_enabled_fll(fll))
1110 pm_runtime_get(arizona->dev);
1111
1112 /* Clear any pending completions */
1113 try_wait_for_completion(&fll->ok);
1114
1115 regmap_update_bits(arizona->regmap, fll->base + 1,
1116 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
1117 if (fll->sync_src >= 0)
1118 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1119 ARIZONA_FLL1_SYNC_ENA,
1120 ARIZONA_FLL1_SYNC_ENA);
1121
1122 ret = wait_for_completion_timeout(&fll->ok,
1123 msecs_to_jiffies(250));
1124 if (ret == 0)
1125 arizona_fll_warn(fll, "Timed out waiting for lock\n");
1126}
1127
Charles Keepax76040542013-02-20 17:28:37 +00001128static void arizona_disable_fll(struct arizona_fll *fll)
1129{
1130 struct arizona *arizona = fll->arizona;
1131 bool change;
1132
1133 regmap_update_bits_check(arizona->regmap, fll->base + 1,
1134 ARIZONA_FLL1_ENA, 0, &change);
1135 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1136 ARIZONA_FLL1_SYNC_ENA, 0);
1137
1138 if (change)
1139 pm_runtime_put_autosuspend(arizona->dev);
1140}
1141
Mark Brown07ed8732012-06-18 21:08:44 +01001142int arizona_set_fll(struct arizona_fll *fll, int source,
1143 unsigned int Fref, unsigned int Fout)
1144{
Charles Keepax9e359c62013-02-20 17:28:35 +00001145 struct arizona_fll_cfg ref, sync;
Mark Brown07ed8732012-06-18 21:08:44 +01001146 int ret;
1147
Charles Keepax9e359c62013-02-20 17:28:35 +00001148 if (fll->ref_src < 0 || fll->ref_src == source) {
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00001149 if (fll->sync_src == -1 &&
1150 fll->ref_src == source && fll->ref_freq == Fref &&
1151 fll->fout == Fout)
1152 return 0;
1153
Charles Keepax9e359c62013-02-20 17:28:35 +00001154 if (Fout) {
1155 ret = arizona_calc_fll(fll, &ref, Fref, Fout);
1156 if (ret != 0)
1157 return ret;
1158 }
1159
1160 fll->sync_src = -1;
1161 fll->ref_src = source;
1162 fll->ref_freq = Fref;
1163 } else {
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00001164 if (fll->sync_src == source &&
1165 fll->sync_freq == Fref && fll->fout == Fout)
1166 return 0;
1167
Charles Keepax9e359c62013-02-20 17:28:35 +00001168 if (Fout) {
1169 ret = arizona_calc_fll(fll, &ref, fll->ref_freq, Fout);
1170 if (ret != 0)
1171 return ret;
1172
1173 ret = arizona_calc_fll(fll, &sync, Fref, Fout);
1174 if (ret != 0)
1175 return ret;
1176 }
1177
1178 fll->sync_src = source;
1179 fll->sync_freq = Fref;
1180 }
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00001181 fll->fout = Fout;
Charles Keepax9e359c62013-02-20 17:28:35 +00001182
Mark Brown07ed8732012-06-18 21:08:44 +01001183 if (Fout) {
Charles Keepax35722812013-02-20 17:28:38 +00001184 arizona_enable_fll(fll, &ref, &sync);
Mark Brown07ed8732012-06-18 21:08:44 +01001185 } else {
Charles Keepax76040542013-02-20 17:28:37 +00001186 arizona_disable_fll(fll);
Mark Brown07ed8732012-06-18 21:08:44 +01001187 }
1188
Mark Brown07ed8732012-06-18 21:08:44 +01001189 return 0;
1190}
1191EXPORT_SYMBOL_GPL(arizona_set_fll);
1192
1193int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
1194 int ok_irq, struct arizona_fll *fll)
1195{
1196 int ret;
Charles Keepax19b34bd2013-02-20 17:28:34 +00001197 unsigned int val;
Mark Brown07ed8732012-06-18 21:08:44 +01001198
Mark Brown07ed8732012-06-18 21:08:44 +01001199 init_completion(&fll->ok);
1200
1201 fll->id = id;
1202 fll->base = base;
1203 fll->arizona = arizona;
Charles Keepax9e359c62013-02-20 17:28:35 +00001204 fll->sync_src = -1;
Mark Brown07ed8732012-06-18 21:08:44 +01001205
Charles Keepax19b34bd2013-02-20 17:28:34 +00001206 /* Configure default refclk to 32kHz if we have one */
1207 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
1208 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
1209 case ARIZONA_CLK_SRC_MCLK1:
1210 case ARIZONA_CLK_SRC_MCLK2:
1211 fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK;
1212 break;
1213 default:
1214 fll->ref_src = -1;
1215 }
1216 fll->ref_freq = 32768;
1217
Mark Brown07ed8732012-06-18 21:08:44 +01001218 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
1219 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
1220 "FLL%d clock OK", id);
1221
Mark Brown07ed8732012-06-18 21:08:44 +01001222 ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
1223 arizona_fll_clock_ok, fll);
1224 if (ret != 0) {
1225 dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
1226 id, ret);
1227 }
1228
Charles Keepaxe31c1942013-01-07 16:41:45 +00001229 regmap_update_bits(arizona->regmap, fll->base + 1,
1230 ARIZONA_FLL1_FREERUN, 0);
1231
Mark Brown07ed8732012-06-18 21:08:44 +01001232 return 0;
1233}
1234EXPORT_SYMBOL_GPL(arizona_init_fll);
1235
Mark Brownbc9ab6d2013-01-04 19:31:00 +00001236/**
1237 * arizona_set_output_mode - Set the mode of the specified output
1238 *
1239 * @codec: Device to configure
1240 * @output: Output number
1241 * @diff: True to set the output to differential mode
1242 *
1243 * Some systems use external analogue switches to connect more
1244 * analogue devices to the CODEC than are supported by the device. In
1245 * some systems this requires changing the switched output from single
1246 * ended to differential mode dynamically at runtime, an operation
1247 * supported using this function.
1248 *
1249 * Most systems have a single static configuration and should use
1250 * platform data instead.
1251 */
1252int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
1253{
1254 unsigned int reg, val;
1255
1256 if (output < 1 || output > 6)
1257 return -EINVAL;
1258
1259 reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
1260
1261 if (diff)
1262 val = ARIZONA_OUT1_MONO;
1263 else
1264 val = 0;
1265
1266 return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val);
1267}
1268EXPORT_SYMBOL_GPL(arizona_set_output_mode);
1269
Mark Brown07ed8732012-06-18 21:08:44 +01001270MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
1271MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1272MODULE_LICENSE("GPL");