blob: de625813c0e65c7aff7807d6904c53d2c581249d [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
Mark Brownddbce972013-02-15 17:27:22 +000013#include <linux/delay.h>
Mark Brown07ed8732012-06-18 21:08:44 +010014#include <linux/gcd.h>
15#include <linux/module.h>
16#include <linux/pm_runtime.h>
17#include <sound/pcm.h>
18#include <sound/pcm_params.h>
19#include <sound/tlv.h>
20
21#include <linux/mfd/arizona/core.h>
22#include <linux/mfd/arizona/registers.h>
23
24#include "arizona.h"
25
26#define ARIZONA_AIF_BCLK_CTRL 0x00
27#define ARIZONA_AIF_TX_PIN_CTRL 0x01
28#define ARIZONA_AIF_RX_PIN_CTRL 0x02
29#define ARIZONA_AIF_RATE_CTRL 0x03
30#define ARIZONA_AIF_FORMAT 0x04
31#define ARIZONA_AIF_TX_BCLK_RATE 0x05
32#define ARIZONA_AIF_RX_BCLK_RATE 0x06
33#define ARIZONA_AIF_FRAME_CTRL_1 0x07
34#define ARIZONA_AIF_FRAME_CTRL_2 0x08
35#define ARIZONA_AIF_FRAME_CTRL_3 0x09
36#define ARIZONA_AIF_FRAME_CTRL_4 0x0A
37#define ARIZONA_AIF_FRAME_CTRL_5 0x0B
38#define ARIZONA_AIF_FRAME_CTRL_6 0x0C
39#define ARIZONA_AIF_FRAME_CTRL_7 0x0D
40#define ARIZONA_AIF_FRAME_CTRL_8 0x0E
41#define ARIZONA_AIF_FRAME_CTRL_9 0x0F
42#define ARIZONA_AIF_FRAME_CTRL_10 0x10
43#define ARIZONA_AIF_FRAME_CTRL_11 0x11
44#define ARIZONA_AIF_FRAME_CTRL_12 0x12
45#define ARIZONA_AIF_FRAME_CTRL_13 0x13
46#define ARIZONA_AIF_FRAME_CTRL_14 0x14
47#define ARIZONA_AIF_FRAME_CTRL_15 0x15
48#define ARIZONA_AIF_FRAME_CTRL_16 0x16
49#define ARIZONA_AIF_FRAME_CTRL_17 0x17
50#define ARIZONA_AIF_FRAME_CTRL_18 0x18
51#define ARIZONA_AIF_TX_ENABLES 0x19
52#define ARIZONA_AIF_RX_ENABLES 0x1A
53#define ARIZONA_AIF_FORCE_WRITE 0x1B
54
55#define arizona_fll_err(_fll, fmt, ...) \
56 dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
57#define arizona_fll_warn(_fll, fmt, ...) \
58 dev_warn(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
59#define arizona_fll_dbg(_fll, fmt, ...) \
Mark Brown9092a6e2013-02-06 17:58:57 +000060 dev_dbg(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
Mark Brown07ed8732012-06-18 21:08:44 +010061
62#define arizona_aif_err(_dai, fmt, ...) \
63 dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
64#define arizona_aif_warn(_dai, fmt, ...) \
65 dev_warn(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
66#define arizona_aif_dbg(_dai, fmt, ...) \
Mark Brown9092a6e2013-02-06 17:58:57 +000067 dev_dbg(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
Mark Brown07ed8732012-06-18 21:08:44 +010068
Mark Brown56447e12013-01-10 14:45:58 +000069static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
70 struct snd_kcontrol *kcontrol,
71 int event)
72{
73 struct snd_soc_codec *codec = w->codec;
74 struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
75 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
76 bool manual_ena = false;
Mark Brownf4a76e72013-03-13 12:22:39 +000077 int val;
Mark Brown56447e12013-01-10 14:45:58 +000078
79 switch (arizona->type) {
80 case WM5102:
81 switch (arizona->rev) {
82 case 0:
83 break;
84 default:
85 manual_ena = true;
86 break;
87 }
88 default:
89 break;
90 }
91
92 switch (event) {
93 case SND_SOC_DAPM_PRE_PMU:
94 if (!priv->spk_ena && manual_ena) {
95 snd_soc_write(codec, 0x4f5, 0x25a);
96 priv->spk_ena_pending = true;
97 }
98 break;
99 case SND_SOC_DAPM_POST_PMU:
Mark Brownf4a76e72013-03-13 12:22:39 +0000100 val = snd_soc_read(codec, ARIZONA_INTERRUPT_RAW_STATUS_3);
101 if (val & ARIZONA_SPK_SHUTDOWN_STS) {
102 dev_crit(arizona->dev,
103 "Speaker not enabled due to temperature\n");
104 return -EBUSY;
105 }
106
107 snd_soc_update_bits(codec, ARIZONA_OUTPUT_ENABLES_1,
108 1 << w->shift, 1 << w->shift);
109
Mark Brown56447e12013-01-10 14:45:58 +0000110 if (priv->spk_ena_pending) {
111 msleep(75);
112 snd_soc_write(codec, 0x4f5, 0xda);
113 priv->spk_ena_pending = false;
114 priv->spk_ena++;
115 }
116 break;
117 case SND_SOC_DAPM_PRE_PMD:
118 if (manual_ena) {
119 priv->spk_ena--;
120 if (!priv->spk_ena)
121 snd_soc_write(codec, 0x4f5, 0x25a);
122 }
Mark Brownf4a76e72013-03-13 12:22:39 +0000123
124 snd_soc_update_bits(codec, ARIZONA_OUTPUT_ENABLES_1,
125 1 << w->shift, 0);
Mark Brown56447e12013-01-10 14:45:58 +0000126 break;
127 case SND_SOC_DAPM_POST_PMD:
128 if (manual_ena) {
129 if (!priv->spk_ena)
130 snd_soc_write(codec, 0x4f5, 0x0da);
131 }
132 break;
133 }
134
135 return 0;
136}
137
Mark Brown899817e2013-03-13 12:32:10 +0000138static irqreturn_t arizona_thermal_warn(int irq, void *data)
139{
140 struct arizona *arizona = data;
141 unsigned int val;
142 int ret;
143
144 ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
145 &val);
146 if (ret != 0) {
147 dev_err(arizona->dev, "Failed to read thermal status: %d\n",
148 ret);
149 } else if (val & ARIZONA_SPK_SHUTDOWN_WARN_STS) {
150 dev_crit(arizona->dev, "Thermal warning\n");
151 }
152
153 return IRQ_HANDLED;
154}
155
156static irqreturn_t arizona_thermal_shutdown(int irq, void *data)
157{
158 struct arizona *arizona = data;
159 unsigned int val;
160 int ret;
161
162 ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
163 &val);
164 if (ret != 0) {
165 dev_err(arizona->dev, "Failed to read thermal status: %d\n",
166 ret);
167 } else if (val & ARIZONA_SPK_SHUTDOWN_STS) {
168 dev_crit(arizona->dev, "Thermal shutdown\n");
Mark Brownf4a76e72013-03-13 12:22:39 +0000169 ret = regmap_update_bits(arizona->regmap,
170 ARIZONA_OUTPUT_ENABLES_1,
171 ARIZONA_OUT4L_ENA |
172 ARIZONA_OUT4R_ENA, 0);
173 if (ret != 0)
174 dev_crit(arizona->dev,
175 "Failed to disable speaker outputs: %d\n",
176 ret);
Mark Brown899817e2013-03-13 12:32:10 +0000177 }
178
179 return IRQ_HANDLED;
180}
181
Mark Brown56447e12013-01-10 14:45:58 +0000182static const struct snd_soc_dapm_widget arizona_spkl =
Mark Brownf4a76e72013-03-13 12:22:39 +0000183 SND_SOC_DAPM_PGA_E("OUT4L", SND_SOC_NOPM,
Mark Brown56447e12013-01-10 14:45:58 +0000184 ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
185 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
186
187static const struct snd_soc_dapm_widget arizona_spkr =
Mark Brownf4a76e72013-03-13 12:22:39 +0000188 SND_SOC_DAPM_PGA_E("OUT4R", SND_SOC_NOPM,
Mark Brown56447e12013-01-10 14:45:58 +0000189 ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
190 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
191
192int arizona_init_spk(struct snd_soc_codec *codec)
193{
Mark Brown899817e2013-03-13 12:32:10 +0000194 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
195 struct arizona *arizona = priv->arizona;
Mark Brown56447e12013-01-10 14:45:58 +0000196 int ret;
197
198 ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkl, 1);
199 if (ret != 0)
200 return ret;
201
202 ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkr, 1);
203 if (ret != 0)
204 return ret;
205
Mark Brown899817e2013-03-13 12:32:10 +0000206 ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN_WARN,
207 "Thermal warning", arizona_thermal_warn,
208 arizona);
209 if (ret != 0)
210 dev_err(arizona->dev,
211 "Failed to get thermal warning IRQ: %d\n",
212 ret);
213
214 ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN,
215 "Thermal shutdown", arizona_thermal_shutdown,
216 arizona);
217 if (ret != 0)
218 dev_err(arizona->dev,
219 "Failed to get thermal shutdown IRQ: %d\n",
220 ret);
221
Mark Brown56447e12013-01-10 14:45:58 +0000222 return 0;
223}
224EXPORT_SYMBOL_GPL(arizona_init_spk);
225
Mark Brown07ed8732012-06-18 21:08:44 +0100226const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
227 "None",
228 "Tone Generator 1",
229 "Tone Generator 2",
230 "Haptics",
231 "AEC",
232 "Mic Mute Mixer",
233 "Noise Generator",
234 "IN1L",
235 "IN1R",
236 "IN2L",
237 "IN2R",
238 "IN3L",
239 "IN3R",
Mark Brownc9c56fd2012-07-09 19:09:01 +0100240 "IN4L",
241 "IN4R",
Mark Brown07ed8732012-06-18 21:08:44 +0100242 "AIF1RX1",
243 "AIF1RX2",
244 "AIF1RX3",
245 "AIF1RX4",
246 "AIF1RX5",
247 "AIF1RX6",
248 "AIF1RX7",
249 "AIF1RX8",
250 "AIF2RX1",
251 "AIF2RX2",
252 "AIF3RX1",
253 "AIF3RX2",
254 "SLIMRX1",
255 "SLIMRX2",
256 "SLIMRX3",
257 "SLIMRX4",
258 "SLIMRX5",
259 "SLIMRX6",
260 "SLIMRX7",
261 "SLIMRX8",
262 "EQ1",
263 "EQ2",
264 "EQ3",
265 "EQ4",
266 "DRC1L",
267 "DRC1R",
268 "DRC2L",
269 "DRC2R",
270 "LHPF1",
271 "LHPF2",
272 "LHPF3",
273 "LHPF4",
274 "DSP1.1",
275 "DSP1.2",
276 "DSP1.3",
277 "DSP1.4",
278 "DSP1.5",
279 "DSP1.6",
Mark Brownc922cc42012-09-26 16:43:44 +0100280 "DSP2.1",
281 "DSP2.2",
282 "DSP2.3",
283 "DSP2.4",
284 "DSP2.5",
285 "DSP2.6",
286 "DSP3.1",
287 "DSP3.2",
288 "DSP3.3",
289 "DSP3.4",
290 "DSP3.5",
291 "DSP3.6",
292 "DSP4.1",
293 "DSP4.2",
294 "DSP4.3",
295 "DSP4.4",
296 "DSP4.5",
297 "DSP4.6",
Mark Brown07ed8732012-06-18 21:08:44 +0100298 "ASRC1L",
299 "ASRC1R",
300 "ASRC2L",
301 "ASRC2R",
Mark Brown91660bd2012-12-05 20:35:24 +0900302 "ISRC1INT1",
303 "ISRC1INT2",
304 "ISRC1INT3",
305 "ISRC1INT4",
306 "ISRC1DEC1",
307 "ISRC1DEC2",
308 "ISRC1DEC3",
309 "ISRC1DEC4",
310 "ISRC2INT1",
311 "ISRC2INT2",
312 "ISRC2INT3",
313 "ISRC2INT4",
314 "ISRC2DEC1",
315 "ISRC2DEC2",
316 "ISRC2DEC3",
317 "ISRC2DEC4",
318 "ISRC3INT1",
319 "ISRC3INT2",
320 "ISRC3INT3",
321 "ISRC3INT4",
322 "ISRC3DEC1",
323 "ISRC3DEC2",
324 "ISRC3DEC3",
325 "ISRC3DEC4",
Mark Brown07ed8732012-06-18 21:08:44 +0100326};
327EXPORT_SYMBOL_GPL(arizona_mixer_texts);
328
329int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
330 0x00, /* None */
331 0x04, /* Tone */
332 0x05,
333 0x06, /* Haptics */
334 0x08, /* AEC */
335 0x0c, /* Noise mixer */
336 0x0d, /* Comfort noise */
337 0x10, /* IN1L */
338 0x11,
339 0x12,
340 0x13,
341 0x14,
342 0x15,
Mark Brownc9c56fd2012-07-09 19:09:01 +0100343 0x16,
344 0x17,
Mark Brown07ed8732012-06-18 21:08:44 +0100345 0x20, /* AIF1RX1 */
346 0x21,
347 0x22,
348 0x23,
349 0x24,
350 0x25,
351 0x26,
352 0x27,
353 0x28, /* AIF2RX1 */
354 0x29,
355 0x30, /* AIF3RX1 */
356 0x31,
357 0x38, /* SLIMRX1 */
358 0x39,
359 0x3a,
360 0x3b,
361 0x3c,
362 0x3d,
363 0x3e,
364 0x3f,
365 0x50, /* EQ1 */
366 0x51,
367 0x52,
368 0x53,
369 0x58, /* DRC1L */
370 0x59,
371 0x5a,
372 0x5b,
373 0x60, /* LHPF1 */
374 0x61,
375 0x62,
376 0x63,
377 0x68, /* DSP1.1 */
378 0x69,
379 0x6a,
380 0x6b,
381 0x6c,
382 0x6d,
Mark Brownc922cc42012-09-26 16:43:44 +0100383 0x70, /* DSP2.1 */
384 0x71,
385 0x72,
386 0x73,
387 0x74,
388 0x75,
389 0x78, /* DSP3.1 */
390 0x79,
391 0x7a,
392 0x7b,
393 0x7c,
394 0x7d,
395 0x80, /* DSP4.1 */
396 0x81,
397 0x82,
398 0x83,
399 0x84,
400 0x85,
Mark Brown07ed8732012-06-18 21:08:44 +0100401 0x90, /* ASRC1L */
402 0x91,
403 0x92,
404 0x93,
Mark Brown91660bd2012-12-05 20:35:24 +0900405 0xa0, /* ISRC1INT1 */
406 0xa1,
407 0xa2,
408 0xa3,
409 0xa4, /* ISRC1DEC1 */
410 0xa5,
411 0xa6,
412 0xa7,
413 0xa8, /* ISRC2DEC1 */
414 0xa9,
415 0xaa,
416 0xab,
417 0xac, /* ISRC2INT1 */
418 0xad,
419 0xae,
420 0xaf,
421 0xb0, /* ISRC3DEC1 */
422 0xb1,
423 0xb2,
424 0xb3,
425 0xb4, /* ISRC3INT1 */
426 0xb5,
427 0xb6,
428 0xb7,
Mark Brown07ed8732012-06-18 21:08:44 +0100429};
430EXPORT_SYMBOL_GPL(arizona_mixer_values);
431
432const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
433EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
434
Mark Browndc914282013-02-18 19:09:23 +0000435const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = {
436 "SYNCCLK rate", "8kHz", "16kHz", "ASYNCCLK rate",
437};
438EXPORT_SYMBOL_GPL(arizona_rate_text);
439
440const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
441 0, 1, 2, 8,
442};
443EXPORT_SYMBOL_GPL(arizona_rate_val);
444
445
446const struct soc_enum arizona_isrc_fsl[] = {
447 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2,
448 ARIZONA_ISRC1_FSL_SHIFT, 0xf,
449 ARIZONA_RATE_ENUM_SIZE,
450 arizona_rate_text, arizona_rate_val),
451 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_2,
452 ARIZONA_ISRC2_FSL_SHIFT, 0xf,
453 ARIZONA_RATE_ENUM_SIZE,
454 arizona_rate_text, arizona_rate_val),
455 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_2,
456 ARIZONA_ISRC3_FSL_SHIFT, 0xf,
457 ARIZONA_RATE_ENUM_SIZE,
458 arizona_rate_text, arizona_rate_val),
459};
460EXPORT_SYMBOL_GPL(arizona_isrc_fsl);
461
Mark Browne853a002012-12-09 12:25:52 +0900462static const char *arizona_vol_ramp_text[] = {
463 "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
464 "15ms/6dB", "30ms/6dB",
465};
466
467const struct soc_enum arizona_in_vd_ramp =
468 SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP,
469 ARIZONA_IN_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text);
470EXPORT_SYMBOL_GPL(arizona_in_vd_ramp);
471
472const struct soc_enum arizona_in_vi_ramp =
473 SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP,
474 ARIZONA_IN_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text);
475EXPORT_SYMBOL_GPL(arizona_in_vi_ramp);
476
477const struct soc_enum arizona_out_vd_ramp =
478 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP,
479 ARIZONA_OUT_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text);
480EXPORT_SYMBOL_GPL(arizona_out_vd_ramp);
481
482const struct soc_enum arizona_out_vi_ramp =
483 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP,
484 ARIZONA_OUT_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text);
485EXPORT_SYMBOL_GPL(arizona_out_vi_ramp);
486
Mark Brown07ed8732012-06-18 21:08:44 +0100487static const char *arizona_lhpf_mode_text[] = {
488 "Low-pass", "High-pass"
489};
490
491const struct soc_enum arizona_lhpf1_mode =
492 SOC_ENUM_SINGLE(ARIZONA_HPLPF1_1, ARIZONA_LHPF1_MODE_SHIFT, 2,
493 arizona_lhpf_mode_text);
494EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
495
496const struct soc_enum arizona_lhpf2_mode =
497 SOC_ENUM_SINGLE(ARIZONA_HPLPF2_1, ARIZONA_LHPF2_MODE_SHIFT, 2,
498 arizona_lhpf_mode_text);
499EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
500
501const struct soc_enum arizona_lhpf3_mode =
502 SOC_ENUM_SINGLE(ARIZONA_HPLPF3_1, ARIZONA_LHPF3_MODE_SHIFT, 2,
503 arizona_lhpf_mode_text);
504EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
505
506const struct soc_enum arizona_lhpf4_mode =
507 SOC_ENUM_SINGLE(ARIZONA_HPLPF4_1, ARIZONA_LHPF4_MODE_SHIFT, 2,
508 arizona_lhpf_mode_text);
509EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
510
Mark Brown845571c2012-12-18 13:47:57 +0000511static const char *arizona_ng_hold_text[] = {
512 "30ms", "120ms", "250ms", "500ms",
513};
514
515const struct soc_enum arizona_ng_hold =
516 SOC_ENUM_SINGLE(ARIZONA_NOISE_GATE_CONTROL, ARIZONA_NGATE_HOLD_SHIFT,
517 4, arizona_ng_hold_text);
518EXPORT_SYMBOL_GPL(arizona_ng_hold);
519
Mark Brownddbce972013-02-15 17:27:22 +0000520static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
521{
522 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
523 unsigned int val;
524 int i;
525
526 if (ena)
527 val = ARIZONA_IN_VU;
528 else
529 val = 0;
530
531 for (i = 0; i < priv->num_inputs; i++)
532 snd_soc_update_bits(codec,
533 ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 4),
534 ARIZONA_IN_VU, val);
535}
536
Mark Brown07ed8732012-06-18 21:08:44 +0100537int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
538 int event)
539{
Mark Brownddbce972013-02-15 17:27:22 +0000540 struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000541 unsigned int reg;
542
543 if (w->shift % 2)
544 reg = ARIZONA_ADC_DIGITAL_VOLUME_1L + ((w->shift / 2) * 8);
545 else
546 reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8);
547
548 switch (event) {
Mark Brownddbce972013-02-15 17:27:22 +0000549 case SND_SOC_DAPM_PRE_PMU:
550 priv->in_pending++;
551 break;
Mark Brown43cd8bf2013-02-06 16:57:29 +0000552 case SND_SOC_DAPM_POST_PMU:
553 snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, 0);
Mark Brownddbce972013-02-15 17:27:22 +0000554
555 /* If this is the last input pending then allow VU */
556 priv->in_pending--;
557 if (priv->in_pending == 0) {
558 msleep(1);
559 arizona_in_set_vu(w->codec, 1);
560 }
Mark Brown43cd8bf2013-02-06 16:57:29 +0000561 break;
562 case SND_SOC_DAPM_PRE_PMD:
Mark Brownddbce972013-02-15 17:27:22 +0000563 snd_soc_update_bits(w->codec, reg,
564 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU,
565 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000566 break;
Mark Brownddbce972013-02-15 17:27:22 +0000567 case SND_SOC_DAPM_POST_PMD:
568 /* Disable volume updates if no inputs are enabled */
569 reg = snd_soc_read(w->codec, ARIZONA_INPUT_ENABLES);
570 if (reg == 0)
571 arizona_in_set_vu(w->codec, 0);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000572 }
573
Mark Brown07ed8732012-06-18 21:08:44 +0100574 return 0;
575}
576EXPORT_SYMBOL_GPL(arizona_in_ev);
577
578int arizona_out_ev(struct snd_soc_dapm_widget *w,
579 struct snd_kcontrol *kcontrol,
580 int event)
581{
Mark Brown1a2c7d52013-03-24 22:50:23 +0000582 switch (event) {
583 case SND_SOC_DAPM_POST_PMU:
584 switch (w->shift) {
585 case ARIZONA_OUT1L_ENA_SHIFT:
586 case ARIZONA_OUT1R_ENA_SHIFT:
587 case ARIZONA_OUT2L_ENA_SHIFT:
588 case ARIZONA_OUT2R_ENA_SHIFT:
589 case ARIZONA_OUT3L_ENA_SHIFT:
590 case ARIZONA_OUT3R_ENA_SHIFT:
591 msleep(17);
592 break;
593
594 default:
595 break;
596 }
597 break;
598 }
599
Mark Brown07ed8732012-06-18 21:08:44 +0100600 return 0;
601}
602EXPORT_SYMBOL_GPL(arizona_out_ev);
603
Mark Brownf607e312013-02-22 18:36:53 +0000604int arizona_hp_ev(struct snd_soc_dapm_widget *w,
605 struct snd_kcontrol *kcontrol,
606 int event)
607{
608 struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
609 unsigned int mask = 1 << w->shift;
610 unsigned int val;
611
612 switch (event) {
613 case SND_SOC_DAPM_POST_PMU:
614 val = mask;
615 break;
616 case SND_SOC_DAPM_PRE_PMD:
617 val = 0;
618 break;
619 default:
620 return -EINVAL;
621 }
622
623 /* Store the desired state for the HP outputs */
624 priv->arizona->hp_ena &= ~mask;
625 priv->arizona->hp_ena |= val;
626
627 /* Force off if HPDET magic is active */
628 if (priv->arizona->hpdet_magic)
629 val = 0;
630
631 snd_soc_update_bits(w->codec, ARIZONA_OUTPUT_ENABLES_1, mask, val);
632
633 return arizona_out_ev(w, kcontrol, event);
634}
635EXPORT_SYMBOL_GPL(arizona_hp_ev);
636
Mark Browncbd840d2012-08-08 17:52:44 +0100637static unsigned int arizona_sysclk_48k_rates[] = {
638 6144000,
639 12288000,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000640 24576000,
Mark Browncbd840d2012-08-08 17:52:44 +0100641 49152000,
Mark Brownaeaeee12012-09-26 17:50:02 +0100642 73728000,
643 98304000,
644 147456000,
Mark Browncbd840d2012-08-08 17:52:44 +0100645};
646
647static unsigned int arizona_sysclk_44k1_rates[] = {
648 5644800,
649 11289600,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000650 22579200,
Mark Browncbd840d2012-08-08 17:52:44 +0100651 45158400,
Mark Brownaeaeee12012-09-26 17:50:02 +0100652 67737600,
653 90316800,
654 135475200,
Mark Browncbd840d2012-08-08 17:52:44 +0100655};
656
657static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
658 unsigned int freq)
659{
660 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
661 unsigned int reg;
662 unsigned int *rates;
663 int ref, div, refclk;
664
665 switch (clk) {
666 case ARIZONA_CLK_OPCLK:
667 reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
668 refclk = priv->sysclk;
669 break;
670 case ARIZONA_CLK_ASYNC_OPCLK:
671 reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
672 refclk = priv->asyncclk;
673 break;
674 default:
675 return -EINVAL;
676 }
677
678 if (refclk % 8000)
679 rates = arizona_sysclk_44k1_rates;
680 else
681 rates = arizona_sysclk_48k_rates;
682
683 for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) &&
684 rates[ref] <= refclk; ref++) {
685 div = 1;
686 while (rates[ref] / div >= freq && div < 32) {
687 if (rates[ref] / div == freq) {
688 dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
689 freq);
690 snd_soc_update_bits(codec, reg,
691 ARIZONA_OPCLK_DIV_MASK |
692 ARIZONA_OPCLK_SEL_MASK,
693 (div <<
694 ARIZONA_OPCLK_DIV_SHIFT) |
695 ref);
696 return 0;
697 }
698 div++;
699 }
700 }
701
702 dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
703 return -EINVAL;
704}
705
Mark Brown07ed8732012-06-18 21:08:44 +0100706int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
707 int source, unsigned int freq, int dir)
708{
709 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
710 struct arizona *arizona = priv->arizona;
711 char *name;
712 unsigned int reg;
713 unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
714 unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
715 unsigned int *clk;
716
717 switch (clk_id) {
718 case ARIZONA_CLK_SYSCLK:
719 name = "SYSCLK";
720 reg = ARIZONA_SYSTEM_CLOCK_1;
721 clk = &priv->sysclk;
722 mask |= ARIZONA_SYSCLK_FRAC;
723 break;
724 case ARIZONA_CLK_ASYNCCLK:
725 name = "ASYNCCLK";
726 reg = ARIZONA_ASYNC_CLOCK_1;
727 clk = &priv->asyncclk;
728 break;
Mark Browncbd840d2012-08-08 17:52:44 +0100729 case ARIZONA_CLK_OPCLK:
730 case ARIZONA_CLK_ASYNC_OPCLK:
731 return arizona_set_opclk(codec, clk_id, freq);
Mark Brown07ed8732012-06-18 21:08:44 +0100732 default:
733 return -EINVAL;
734 }
735
736 switch (freq) {
737 case 5644800:
738 case 6144000:
739 break;
740 case 11289600:
741 case 12288000:
Mark Brown3f341f72013-03-08 15:22:29 +0800742 val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100743 break;
744 case 22579200:
745 case 24576000:
Mark Brown3f341f72013-03-08 15:22:29 +0800746 val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100747 break;
748 case 45158400:
749 case 49152000:
Mark Brown3f341f72013-03-08 15:22:29 +0800750 val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100751 break;
Mark Brown38113362012-11-26 16:01:37 +0000752 case 67737600:
753 case 73728000:
Mark Brown3f341f72013-03-08 15:22:29 +0800754 val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000755 break;
756 case 90316800:
757 case 98304000:
Mark Brown3f341f72013-03-08 15:22:29 +0800758 val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000759 break;
760 case 135475200:
761 case 147456000:
Mark Brown3f341f72013-03-08 15:22:29 +0800762 val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000763 break;
Mark Brownf2c26d42013-01-21 16:09:36 +0900764 case 0:
765 dev_dbg(arizona->dev, "%s cleared\n", name);
766 *clk = freq;
767 return 0;
Mark Brown07ed8732012-06-18 21:08:44 +0100768 default:
769 return -EINVAL;
770 }
771
772 *clk = freq;
773
774 if (freq % 6144000)
775 val |= ARIZONA_SYSCLK_FRAC;
776
777 dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
778
779 return regmap_update_bits(arizona->regmap, reg, mask, val);
780}
781EXPORT_SYMBOL_GPL(arizona_set_sysclk);
782
783static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
784{
785 struct snd_soc_codec *codec = dai->codec;
786 int lrclk, bclk, mode, base;
787
788 base = dai->driver->base;
789
790 lrclk = 0;
791 bclk = 0;
792
793 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
794 case SND_SOC_DAIFMT_DSP_A:
795 mode = 0;
796 break;
Mark Brown07ed8732012-06-18 21:08:44 +0100797 case SND_SOC_DAIFMT_I2S:
798 mode = 2;
799 break;
Mark Brown07ed8732012-06-18 21:08:44 +0100800 default:
801 arizona_aif_err(dai, "Unsupported DAI format %d\n",
802 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
803 return -EINVAL;
804 }
805
806 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
807 case SND_SOC_DAIFMT_CBS_CFS:
808 break;
809 case SND_SOC_DAIFMT_CBS_CFM:
810 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
811 break;
812 case SND_SOC_DAIFMT_CBM_CFS:
813 bclk |= ARIZONA_AIF1_BCLK_MSTR;
814 break;
815 case SND_SOC_DAIFMT_CBM_CFM:
816 bclk |= ARIZONA_AIF1_BCLK_MSTR;
817 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
818 break;
819 default:
820 arizona_aif_err(dai, "Unsupported master mode %d\n",
821 fmt & SND_SOC_DAIFMT_MASTER_MASK);
822 return -EINVAL;
823 }
824
825 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
826 case SND_SOC_DAIFMT_NB_NF:
827 break;
828 case SND_SOC_DAIFMT_IB_IF:
829 bclk |= ARIZONA_AIF1_BCLK_INV;
830 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
831 break;
832 case SND_SOC_DAIFMT_IB_NF:
833 bclk |= ARIZONA_AIF1_BCLK_INV;
834 break;
835 case SND_SOC_DAIFMT_NB_IF:
836 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
837 break;
838 default:
839 return -EINVAL;
840 }
841
842 snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
843 ARIZONA_AIF1_BCLK_INV | ARIZONA_AIF1_BCLK_MSTR,
844 bclk);
845 snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_PIN_CTRL,
846 ARIZONA_AIF1TX_LRCLK_INV |
847 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
848 snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_PIN_CTRL,
849 ARIZONA_AIF1RX_LRCLK_INV |
850 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
851 snd_soc_update_bits(codec, base + ARIZONA_AIF_FORMAT,
852 ARIZONA_AIF1_FMT_MASK, mode);
853
854 return 0;
855}
856
Mark Brown949e6bc2012-07-04 18:58:04 +0100857static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100858 -1,
859 48000,
860 64000,
861 96000,
862 128000,
863 192000,
864 256000,
865 384000,
866 512000,
867 768000,
868 1024000,
869 1536000,
870 2048000,
871 3072000,
872 4096000,
873 6144000,
874 8192000,
875 12288000,
876 24576000,
877};
878
Mark Brown5b2eec32012-07-04 17:32:05 +0100879static const unsigned int arizona_48k_rates[] = {
880 12000,
881 24000,
882 48000,
883 96000,
884 192000,
885 384000,
886 768000,
887 4000,
888 8000,
889 16000,
890 32000,
891 64000,
892 128000,
893 256000,
894 512000,
895};
896
897static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = {
898 .count = ARRAY_SIZE(arizona_48k_rates),
899 .list = arizona_48k_rates,
900};
901
Mark Brown949e6bc2012-07-04 18:58:04 +0100902static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100903 -1,
904 44100,
905 58800,
906 88200,
907 117600,
908 177640,
909 235200,
910 352800,
911 470400,
912 705600,
913 940800,
914 1411200,
915 1881600,
Heather Lomond4758be32012-09-05 05:02:10 -0400916 2822400,
Mark Brown07ed8732012-06-18 21:08:44 +0100917 3763200,
918 5644800,
919 7526400,
920 11289600,
921 22579200,
922};
923
Mark Brown5b2eec32012-07-04 17:32:05 +0100924static const unsigned int arizona_44k1_rates[] = {
925 11025,
926 22050,
927 44100,
928 88200,
929 176400,
930 352800,
931 705600,
932};
933
934static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = {
935 .count = ARRAY_SIZE(arizona_44k1_rates),
936 .list = arizona_44k1_rates,
937};
938
Mark Brown07ed8732012-06-18 21:08:44 +0100939static int arizona_sr_vals[] = {
940 0,
941 12000,
942 24000,
943 48000,
944 96000,
945 192000,
946 384000,
947 768000,
948 0,
949 11025,
950 22050,
951 44100,
952 88200,
953 176400,
954 352800,
955 705600,
956 4000,
957 8000,
958 16000,
959 32000,
960 64000,
961 128000,
962 256000,
963 512000,
964};
965
Mark Brown5b2eec32012-07-04 17:32:05 +0100966static int arizona_startup(struct snd_pcm_substream *substream,
967 struct snd_soc_dai *dai)
968{
969 struct snd_soc_codec *codec = dai->codec;
970 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
971 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
972 const struct snd_pcm_hw_constraint_list *constraint;
973 unsigned int base_rate;
974
975 switch (dai_priv->clk) {
976 case ARIZONA_CLK_SYSCLK:
977 base_rate = priv->sysclk;
978 break;
979 case ARIZONA_CLK_ASYNCCLK:
980 base_rate = priv->asyncclk;
981 break;
982 default:
983 return 0;
984 }
985
Mark Brownf2c26d42013-01-21 16:09:36 +0900986 if (base_rate == 0)
987 return 0;
988
Mark Brown5b2eec32012-07-04 17:32:05 +0100989 if (base_rate % 8000)
990 constraint = &arizona_44k1_constraint;
991 else
992 constraint = &arizona_48k_constraint;
993
994 return snd_pcm_hw_constraint_list(substream->runtime, 0,
995 SNDRV_PCM_HW_PARAM_RATE,
996 constraint);
997}
998
Mark Brownb272efc2012-10-10 15:10:08 +0900999static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
1000 struct snd_pcm_hw_params *params,
1001 struct snd_soc_dai *dai)
Mark Brown07ed8732012-06-18 21:08:44 +01001002{
1003 struct snd_soc_codec *codec = dai->codec;
Mark Brownc013b272012-07-04 20:05:57 +01001004 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1005 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown07ed8732012-06-18 21:08:44 +01001006 int base = dai->driver->base;
Mark Brownb272efc2012-10-10 15:10:08 +09001007 int i, sr_val;
1008
1009 /*
1010 * We will need to be more flexible than this in future,
1011 * currently we use a single sample rate for SYSCLK.
1012 */
1013 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
1014 if (arizona_sr_vals[i] == params_rate(params))
1015 break;
1016 if (i == ARRAY_SIZE(arizona_sr_vals)) {
1017 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1018 params_rate(params));
1019 return -EINVAL;
1020 }
1021 sr_val = i;
1022
1023 switch (dai_priv->clk) {
1024 case ARIZONA_CLK_SYSCLK:
1025 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
1026 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
1027 if (base)
1028 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1029 ARIZONA_AIF1_RATE_MASK, 0);
1030 break;
1031 case ARIZONA_CLK_ASYNCCLK:
1032 snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
1033 ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val);
1034 if (base)
1035 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1036 ARIZONA_AIF1_RATE_MASK,
1037 8 << ARIZONA_AIF1_RATE_SHIFT);
1038 break;
1039 default:
1040 arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
1041 return -EINVAL;
1042 }
1043
1044 return 0;
1045}
1046
Mark Brown07ed8732012-06-18 21:08:44 +01001047static int arizona_hw_params(struct snd_pcm_substream *substream,
1048 struct snd_pcm_hw_params *params,
1049 struct snd_soc_dai *dai)
1050{
1051 struct snd_soc_codec *codec = dai->codec;
1052 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brownc94aa302013-01-17 16:35:14 +09001053 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +01001054 int base = dai->driver->base;
1055 const int *rates;
Mark Brown76bf9692013-03-05 14:17:47 +08001056 int i, ret, val;
Mark Brownc94aa302013-01-17 16:35:14 +09001057 int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
1058 int bclk, lrclk, wl, frame, bclk_target;
Mark Brown07ed8732012-06-18 21:08:44 +01001059
1060 if (params_rate(params) % 8000)
Mark Brown949e6bc2012-07-04 18:58:04 +01001061 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001062 else
Mark Brown949e6bc2012-07-04 18:58:04 +01001063 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001064
Mark Brownc94aa302013-01-17 16:35:14 +09001065 bclk_target = snd_soc_params_to_bclk(params);
1066 if (chan_limit && chan_limit < params_channels(params)) {
1067 arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
1068 bclk_target /= params_channels(params);
1069 bclk_target *= chan_limit;
1070 }
1071
Mark Brown76bf9692013-03-05 14:17:47 +08001072 /* Force stereo for I2S mode */
1073 val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
1074 if (params_channels(params) == 1 && (val & ARIZONA_AIF1_FMT_MASK)) {
1075 arizona_aif_dbg(dai, "Forcing stereo mode\n");
1076 bclk_target *= 2;
1077 }
1078
Mark Brown949e6bc2012-07-04 18:58:04 +01001079 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brownc94aa302013-01-17 16:35:14 +09001080 if (rates[i] >= bclk_target &&
Mark Brown50017652012-07-04 19:07:09 +01001081 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +01001082 bclk = i;
1083 break;
1084 }
1085 }
Mark Brown949e6bc2012-07-04 18:58:04 +01001086 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001087 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1088 params_rate(params));
1089 return -EINVAL;
1090 }
1091
Mark Brownb59e0f82013-01-17 14:15:59 +09001092 lrclk = rates[bclk] / params_rate(params);
Mark Brown07ed8732012-06-18 21:08:44 +01001093
1094 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
1095 rates[bclk], rates[bclk] / lrclk);
1096
1097 wl = snd_pcm_format_width(params_format(params));
1098 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl;
1099
Mark Brownb272efc2012-10-10 15:10:08 +09001100 ret = arizona_hw_params_rate(substream, params, dai);
1101 if (ret != 0)
1102 return ret;
Mark Brownc013b272012-07-04 20:05:57 +01001103
Mark Brown07ed8732012-06-18 21:08:44 +01001104 snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
1105 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
1106 snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_BCLK_RATE,
1107 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
1108 snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_BCLK_RATE,
1109 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
1110 snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_1,
1111 ARIZONA_AIF1TX_WL_MASK |
1112 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
1113 snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_2,
1114 ARIZONA_AIF1RX_WL_MASK |
1115 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
1116
1117 return 0;
1118}
1119
Mark Brown410837a2012-07-05 17:26:59 +01001120static const char *arizona_dai_clk_str(int clk_id)
1121{
1122 switch (clk_id) {
1123 case ARIZONA_CLK_SYSCLK:
1124 return "SYSCLK";
1125 case ARIZONA_CLK_ASYNCCLK:
1126 return "ASYNCCLK";
1127 default:
1128 return "Unknown clock";
1129 }
1130}
1131
Mark Brown5b2eec32012-07-04 17:32:05 +01001132static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
1133 int clk_id, unsigned int freq, int dir)
1134{
1135 struct snd_soc_codec *codec = dai->codec;
1136 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1137 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown410837a2012-07-05 17:26:59 +01001138 struct snd_soc_dapm_route routes[2];
Mark Brown5b2eec32012-07-04 17:32:05 +01001139
1140 switch (clk_id) {
1141 case ARIZONA_CLK_SYSCLK:
1142 case ARIZONA_CLK_ASYNCCLK:
1143 break;
1144 default:
1145 return -EINVAL;
1146 }
1147
Mark Brown410837a2012-07-05 17:26:59 +01001148 if (clk_id == dai_priv->clk)
1149 return 0;
1150
1151 if (dai->active) {
Mark Brown5b2eec32012-07-04 17:32:05 +01001152 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
1153 dai->id);
1154 return -EBUSY;
1155 }
1156
Mark Brownc8d35a62012-12-07 12:49:40 +09001157 dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1,
1158 arizona_dai_clk_str(clk_id));
1159
Mark Brown410837a2012-07-05 17:26:59 +01001160 memset(&routes, 0, sizeof(routes));
1161 routes[0].sink = dai->driver->capture.stream_name;
1162 routes[1].sink = dai->driver->playback.stream_name;
Mark Brown5b2eec32012-07-04 17:32:05 +01001163
Mark Brown410837a2012-07-05 17:26:59 +01001164 routes[0].source = arizona_dai_clk_str(dai_priv->clk);
1165 routes[1].source = arizona_dai_clk_str(dai_priv->clk);
1166 snd_soc_dapm_del_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
1167
1168 routes[0].source = arizona_dai_clk_str(clk_id);
1169 routes[1].source = arizona_dai_clk_str(clk_id);
1170 snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
1171
Mark Brown0c778e82012-12-06 18:22:25 +09001172 dai_priv->clk = clk_id;
1173
Mark Brown410837a2012-07-05 17:26:59 +01001174 return snd_soc_dapm_sync(&codec->dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +01001175}
1176
Mark Brown01df2592012-12-12 16:22:08 +09001177static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
1178{
1179 struct snd_soc_codec *codec = dai->codec;
1180 int base = dai->driver->base;
1181 unsigned int reg;
1182
1183 if (tristate)
1184 reg = ARIZONA_AIF1_TRI;
1185 else
1186 reg = 0;
1187
1188 return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1189 ARIZONA_AIF1_TRI, reg);
1190}
1191
Mark Brown07ed8732012-06-18 21:08:44 +01001192const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +01001193 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +01001194 .set_fmt = arizona_set_fmt,
1195 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +01001196 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown01df2592012-12-12 16:22:08 +09001197 .set_tristate = arizona_set_tristate,
Mark Brown07ed8732012-06-18 21:08:44 +01001198};
Mark Browna8379872012-07-09 12:16:41 +01001199EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +01001200
Mark Brownbd1dd882013-05-17 13:29:03 +01001201const struct snd_soc_dai_ops arizona_simple_dai_ops = {
1202 .startup = arizona_startup,
1203 .hw_params = arizona_hw_params_rate,
1204 .set_sysclk = arizona_dai_set_sysclk,
1205};
1206EXPORT_SYMBOL_GPL(arizona_simple_dai_ops);
1207
Mark Brown5b2eec32012-07-04 17:32:05 +01001208int arizona_init_dai(struct arizona_priv *priv, int id)
1209{
1210 struct arizona_dai_priv *dai_priv = &priv->dai[id];
1211
1212 dai_priv->clk = ARIZONA_CLK_SYSCLK;
1213
1214 return 0;
1215}
1216EXPORT_SYMBOL_GPL(arizona_init_dai);
1217
Mark Brown07ed8732012-06-18 21:08:44 +01001218static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
1219{
1220 struct arizona_fll *fll = data;
1221
1222 arizona_fll_dbg(fll, "clock OK\n");
1223
1224 complete(&fll->ok);
1225
1226 return IRQ_HANDLED;
1227}
1228
1229static struct {
1230 unsigned int min;
1231 unsigned int max;
1232 u16 fratio;
1233 int ratio;
1234} fll_fratios[] = {
1235 { 0, 64000, 4, 16 },
1236 { 64000, 128000, 3, 8 },
1237 { 128000, 256000, 2, 4 },
1238 { 256000, 1000000, 1, 2 },
1239 { 1000000, 13500000, 0, 1 },
1240};
1241
Mark Brown8f113d72013-03-05 12:08:57 +08001242static struct {
1243 unsigned int min;
1244 unsigned int max;
1245 u16 gain;
1246} fll_gains[] = {
1247 { 0, 256000, 0 },
1248 { 256000, 1000000, 2 },
1249 { 1000000, 13500000, 4 },
1250};
1251
Mark Brown07ed8732012-06-18 21:08:44 +01001252struct arizona_fll_cfg {
1253 int n;
1254 int theta;
1255 int lambda;
1256 int refdiv;
1257 int outdiv;
1258 int fratio;
Mark Brown8f113d72013-03-05 12:08:57 +08001259 int gain;
Mark Brown07ed8732012-06-18 21:08:44 +01001260};
1261
1262static int arizona_calc_fll(struct arizona_fll *fll,
1263 struct arizona_fll_cfg *cfg,
1264 unsigned int Fref,
1265 unsigned int Fout)
1266{
1267 unsigned int target, div, gcd_fll;
1268 int i, ratio;
1269
1270 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout);
1271
1272 /* Fref must be <=13.5MHz */
1273 div = 1;
1274 cfg->refdiv = 0;
1275 while ((Fref / div) > 13500000) {
1276 div *= 2;
1277 cfg->refdiv++;
1278
1279 if (div > 8) {
1280 arizona_fll_err(fll,
1281 "Can't scale %dMHz in to <=13.5MHz\n",
1282 Fref);
1283 return -EINVAL;
1284 }
1285 }
1286
1287 /* Apply the division for our remaining calculations */
1288 Fref /= div;
1289
Mark Brown2b4d39f2012-07-10 17:03:46 +01001290 /* Fvco should be over the targt; don't check the upper bound */
Mark Brown07ed8732012-06-18 21:08:44 +01001291 div = 1;
Mark Brown2b4d39f2012-07-10 17:03:46 +01001292 while (Fout * div < 90000000 * fll->vco_mult) {
Mark Brown07ed8732012-06-18 21:08:44 +01001293 div++;
1294 if (div > 7) {
1295 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
1296 Fout);
1297 return -EINVAL;
1298 }
1299 }
Mark Brown2b4d39f2012-07-10 17:03:46 +01001300 target = Fout * div / fll->vco_mult;
Mark Brown07ed8732012-06-18 21:08:44 +01001301 cfg->outdiv = div;
1302
1303 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
1304
1305 /* Find an appropraite FLL_FRATIO and factor it out of the target */
1306 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
1307 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
1308 cfg->fratio = fll_fratios[i].fratio;
1309 ratio = fll_fratios[i].ratio;
1310 break;
1311 }
1312 }
1313 if (i == ARRAY_SIZE(fll_fratios)) {
1314 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
1315 Fref);
1316 return -EINVAL;
1317 }
1318
Mark Brown8f113d72013-03-05 12:08:57 +08001319 for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
1320 if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
1321 cfg->gain = fll_gains[i].gain;
1322 break;
1323 }
1324 }
1325 if (i == ARRAY_SIZE(fll_gains)) {
1326 arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
1327 Fref);
1328 return -EINVAL;
1329 }
1330
Mark Brown07ed8732012-06-18 21:08:44 +01001331 cfg->n = target / (ratio * Fref);
1332
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001333 if (target % (ratio * Fref)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001334 gcd_fll = gcd(target, ratio * Fref);
1335 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
1336
1337 cfg->theta = (target - (cfg->n * ratio * Fref))
1338 / gcd_fll;
1339 cfg->lambda = (ratio * Fref) / gcd_fll;
1340 } else {
1341 cfg->theta = 0;
1342 cfg->lambda = 0;
1343 }
1344
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001345 /* Round down to 16bit range with cost of accuracy lost.
1346 * Denominator must be bigger than numerator so we only
1347 * take care of it.
1348 */
1349 while (cfg->lambda >= (1 << 16)) {
1350 cfg->theta >>= 1;
1351 cfg->lambda >>= 1;
1352 }
1353
Mark Brown07ed8732012-06-18 21:08:44 +01001354 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
1355 cfg->n, cfg->theta, cfg->lambda);
1356 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
1357 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08001358 arizona_fll_dbg(fll, "GAIN=%d\n", cfg->gain);
Mark Brown07ed8732012-06-18 21:08:44 +01001359
1360 return 0;
1361
1362}
1363
1364static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
Mark Brown8f113d72013-03-05 12:08:57 +08001365 struct arizona_fll_cfg *cfg, int source,
1366 bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01001367{
1368 regmap_update_bits(arizona->regmap, base + 3,
1369 ARIZONA_FLL1_THETA_MASK, cfg->theta);
1370 regmap_update_bits(arizona->regmap, base + 4,
1371 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
1372 regmap_update_bits(arizona->regmap, base + 5,
1373 ARIZONA_FLL1_FRATIO_MASK,
1374 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
1375 regmap_update_bits(arizona->regmap, base + 6,
1376 ARIZONA_FLL1_CLK_REF_DIV_MASK |
1377 ARIZONA_FLL1_CLK_REF_SRC_MASK,
1378 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
1379 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
1380
Mark Brown8f113d72013-03-05 12:08:57 +08001381 if (sync)
1382 regmap_update_bits(arizona->regmap, base + 0x7,
1383 ARIZONA_FLL1_GAIN_MASK,
1384 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
1385 else
1386 regmap_update_bits(arizona->regmap, base + 0x9,
1387 ARIZONA_FLL1_GAIN_MASK,
1388 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
1389
Mark Brown07ed8732012-06-18 21:08:44 +01001390 regmap_update_bits(arizona->regmap, base + 2,
1391 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
1392 ARIZONA_FLL1_CTRL_UPD | cfg->n);
1393}
1394
Charles Keepaxd122d6c2013-02-20 17:28:36 +00001395static bool arizona_is_enabled_fll(struct arizona_fll *fll)
1396{
1397 struct arizona *arizona = fll->arizona;
1398 unsigned int reg;
1399 int ret;
1400
1401 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
1402 if (ret != 0) {
1403 arizona_fll_err(fll, "Failed to read current state: %d\n",
1404 ret);
1405 return ret;
1406 }
1407
1408 return reg & ARIZONA_FLL1_ENA;
1409}
1410
Charles Keepax35722812013-02-20 17:28:38 +00001411static void arizona_enable_fll(struct arizona_fll *fll,
1412 struct arizona_fll_cfg *ref,
1413 struct arizona_fll_cfg *sync)
1414{
1415 struct arizona *arizona = fll->arizona;
1416 int ret;
1417
Mark Brownff680a12013-03-04 16:00:19 +08001418 /*
1419 * If we have both REFCLK and SYNCCLK then enable both,
1420 * otherwise apply the SYNCCLK settings to REFCLK.
1421 */
1422 if (fll->ref_src >= 0 && fll->ref_src != fll->sync_src) {
1423 regmap_update_bits(arizona->regmap, fll->base + 5,
1424 ARIZONA_FLL1_OUTDIV_MASK,
1425 ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
Charles Keepax35722812013-02-20 17:28:38 +00001426
Mark Brown8f113d72013-03-05 12:08:57 +08001427 arizona_apply_fll(arizona, fll->base, ref, fll->ref_src,
1428 false);
Mark Brownff680a12013-03-04 16:00:19 +08001429 if (fll->sync_src >= 0)
1430 arizona_apply_fll(arizona, fll->base + 0x10, sync,
Mark Brown8f113d72013-03-05 12:08:57 +08001431 fll->sync_src, true);
Mark Brownff680a12013-03-04 16:00:19 +08001432 } else if (fll->sync_src >= 0) {
1433 regmap_update_bits(arizona->regmap, fll->base + 5,
1434 ARIZONA_FLL1_OUTDIV_MASK,
1435 sync->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
1436
1437 arizona_apply_fll(arizona, fll->base, sync,
Mark Brown8f113d72013-03-05 12:08:57 +08001438 fll->sync_src, false);
Mark Browneca2e8e2013-03-06 00:09:59 +08001439
1440 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1441 ARIZONA_FLL1_SYNC_ENA, 0);
Mark Brownff680a12013-03-04 16:00:19 +08001442 } else {
1443 arizona_fll_err(fll, "No clocks provided\n");
1444 return;
1445 }
Charles Keepax35722812013-02-20 17:28:38 +00001446
Mark Brown576411be2013-03-05 12:07:16 +08001447 /*
1448 * Increase the bandwidth if we're not using a low frequency
1449 * sync source.
1450 */
1451 if (fll->sync_src >= 0 && fll->sync_freq > 100000)
1452 regmap_update_bits(arizona->regmap, fll->base + 0x17,
1453 ARIZONA_FLL1_SYNC_BW, 0);
1454 else
1455 regmap_update_bits(arizona->regmap, fll->base + 0x17,
1456 ARIZONA_FLL1_SYNC_BW, ARIZONA_FLL1_SYNC_BW);
1457
Charles Keepax35722812013-02-20 17:28:38 +00001458 if (!arizona_is_enabled_fll(fll))
1459 pm_runtime_get(arizona->dev);
1460
1461 /* Clear any pending completions */
1462 try_wait_for_completion(&fll->ok);
1463
1464 regmap_update_bits(arizona->regmap, fll->base + 1,
1465 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
Mark Brownff680a12013-03-04 16:00:19 +08001466 if (fll->ref_src >= 0 && fll->sync_src >= 0 &&
1467 fll->ref_src != fll->sync_src)
Charles Keepax35722812013-02-20 17:28:38 +00001468 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1469 ARIZONA_FLL1_SYNC_ENA,
1470 ARIZONA_FLL1_SYNC_ENA);
1471
1472 ret = wait_for_completion_timeout(&fll->ok,
1473 msecs_to_jiffies(250));
1474 if (ret == 0)
1475 arizona_fll_warn(fll, "Timed out waiting for lock\n");
1476}
1477
Charles Keepax76040542013-02-20 17:28:37 +00001478static void arizona_disable_fll(struct arizona_fll *fll)
1479{
1480 struct arizona *arizona = fll->arizona;
1481 bool change;
1482
1483 regmap_update_bits_check(arizona->regmap, fll->base + 1,
1484 ARIZONA_FLL1_ENA, 0, &change);
1485 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1486 ARIZONA_FLL1_SYNC_ENA, 0);
1487
1488 if (change)
1489 pm_runtime_put_autosuspend(arizona->dev);
1490}
1491
Charles Keepaxee929a92013-02-20 17:28:40 +00001492int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
1493 unsigned int Fref, unsigned int Fout)
1494{
1495 struct arizona_fll_cfg ref, sync;
1496 int ret;
1497
Charles Keepax1c5617f2013-02-22 17:10:37 +00001498 if (fll->ref_src == source && fll->ref_freq == Fref)
Charles Keepaxee929a92013-02-20 17:28:40 +00001499 return 0;
1500
Mark Brown86cd6842013-03-07 16:14:04 +08001501 if (fll->fout && Fref > 0) {
Charles Keepax1c5617f2013-02-22 17:10:37 +00001502 ret = arizona_calc_fll(fll, &ref, Fref, fll->fout);
Charles Keepaxee929a92013-02-20 17:28:40 +00001503 if (ret != 0)
1504 return ret;
1505
1506 if (fll->sync_src >= 0) {
Charles Keepax1c5617f2013-02-22 17:10:37 +00001507 ret = arizona_calc_fll(fll, &sync, fll->sync_freq,
1508 fll->fout);
Charles Keepaxee929a92013-02-20 17:28:40 +00001509 if (ret != 0)
1510 return ret;
1511 }
1512 }
1513
1514 fll->ref_src = source;
1515 fll->ref_freq = Fref;
Charles Keepaxee929a92013-02-20 17:28:40 +00001516
Mark Brown86cd6842013-03-07 16:14:04 +08001517 if (fll->fout && Fref > 0) {
Charles Keepaxee929a92013-02-20 17:28:40 +00001518 arizona_enable_fll(fll, &ref, &sync);
Charles Keepaxee929a92013-02-20 17:28:40 +00001519 }
1520
1521 return 0;
1522}
1523EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
1524
Mark Brown07ed8732012-06-18 21:08:44 +01001525int arizona_set_fll(struct arizona_fll *fll, int source,
1526 unsigned int Fref, unsigned int Fout)
1527{
Charles Keepax9e359c62013-02-20 17:28:35 +00001528 struct arizona_fll_cfg ref, sync;
Mark Brown07ed8732012-06-18 21:08:44 +01001529 int ret;
1530
Mark Brownff680a12013-03-04 16:00:19 +08001531 if (fll->sync_src == source &&
1532 fll->sync_freq == Fref && fll->fout == Fout)
1533 return 0;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00001534
Mark Brownff680a12013-03-04 16:00:19 +08001535 if (Fout) {
1536 if (fll->ref_src >= 0) {
1537 ret = arizona_calc_fll(fll, &ref, fll->ref_freq,
1538 Fout);
Charles Keepax9e359c62013-02-20 17:28:35 +00001539 if (ret != 0)
1540 return ret;
1541 }
1542
Mark Brownff680a12013-03-04 16:00:19 +08001543 ret = arizona_calc_fll(fll, &sync, Fref, Fout);
1544 if (ret != 0)
1545 return ret;
Charles Keepax9e359c62013-02-20 17:28:35 +00001546 }
Mark Brownff680a12013-03-04 16:00:19 +08001547
1548 fll->sync_src = source;
1549 fll->sync_freq = Fref;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00001550 fll->fout = Fout;
Charles Keepax9e359c62013-02-20 17:28:35 +00001551
Mark Brown07ed8732012-06-18 21:08:44 +01001552 if (Fout) {
Charles Keepax35722812013-02-20 17:28:38 +00001553 arizona_enable_fll(fll, &ref, &sync);
Mark Brown07ed8732012-06-18 21:08:44 +01001554 } else {
Charles Keepax76040542013-02-20 17:28:37 +00001555 arizona_disable_fll(fll);
Mark Brown07ed8732012-06-18 21:08:44 +01001556 }
1557
Mark Brown07ed8732012-06-18 21:08:44 +01001558 return 0;
1559}
1560EXPORT_SYMBOL_GPL(arizona_set_fll);
1561
1562int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
1563 int ok_irq, struct arizona_fll *fll)
1564{
1565 int ret;
Charles Keepax19b34bd2013-02-20 17:28:34 +00001566 unsigned int val;
Mark Brown07ed8732012-06-18 21:08:44 +01001567
Mark Brown07ed8732012-06-18 21:08:44 +01001568 init_completion(&fll->ok);
1569
1570 fll->id = id;
1571 fll->base = base;
1572 fll->arizona = arizona;
Charles Keepaxf3f11632013-02-20 17:28:41 +00001573 fll->sync_src = ARIZONA_FLL_SRC_NONE;
Mark Brown07ed8732012-06-18 21:08:44 +01001574
Charles Keepax19b34bd2013-02-20 17:28:34 +00001575 /* Configure default refclk to 32kHz if we have one */
1576 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
1577 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
1578 case ARIZONA_CLK_SRC_MCLK1:
1579 case ARIZONA_CLK_SRC_MCLK2:
1580 fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK;
1581 break;
1582 default:
Charles Keepaxf3f11632013-02-20 17:28:41 +00001583 fll->ref_src = ARIZONA_FLL_SRC_NONE;
Charles Keepax19b34bd2013-02-20 17:28:34 +00001584 }
1585 fll->ref_freq = 32768;
1586
Mark Brown07ed8732012-06-18 21:08:44 +01001587 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
1588 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
1589 "FLL%d clock OK", id);
1590
Mark Brown07ed8732012-06-18 21:08:44 +01001591 ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
1592 arizona_fll_clock_ok, fll);
1593 if (ret != 0) {
1594 dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
1595 id, ret);
1596 }
1597
Charles Keepaxe31c1942013-01-07 16:41:45 +00001598 regmap_update_bits(arizona->regmap, fll->base + 1,
1599 ARIZONA_FLL1_FREERUN, 0);
1600
Mark Brown07ed8732012-06-18 21:08:44 +01001601 return 0;
1602}
1603EXPORT_SYMBOL_GPL(arizona_init_fll);
1604
Mark Brownbc9ab6d2013-01-04 19:31:00 +00001605/**
1606 * arizona_set_output_mode - Set the mode of the specified output
1607 *
1608 * @codec: Device to configure
1609 * @output: Output number
1610 * @diff: True to set the output to differential mode
1611 *
1612 * Some systems use external analogue switches to connect more
1613 * analogue devices to the CODEC than are supported by the device. In
1614 * some systems this requires changing the switched output from single
1615 * ended to differential mode dynamically at runtime, an operation
1616 * supported using this function.
1617 *
1618 * Most systems have a single static configuration and should use
1619 * platform data instead.
1620 */
1621int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
1622{
1623 unsigned int reg, val;
1624
1625 if (output < 1 || output > 6)
1626 return -EINVAL;
1627
1628 reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
1629
1630 if (diff)
1631 val = ARIZONA_OUT1_MONO;
1632 else
1633 val = 0;
1634
1635 return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val);
1636}
1637EXPORT_SYMBOL_GPL(arizona_set_output_mode);
1638
Mark Brown07ed8732012-06-18 21:08:44 +01001639MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
1640MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1641MODULE_LICENSE("GPL");