blob: 3d4408db075f543af5cb31a054f952f517b6b7c1 [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>
Charles Keepaxb63144e2013-07-04 08:56:28 +010022#include <linux/mfd/arizona/gpio.h>
Mark Brown07ed8732012-06-18 21:08:44 +010023#include <linux/mfd/arizona/registers.h>
24
25#include "arizona.h"
26
27#define ARIZONA_AIF_BCLK_CTRL 0x00
28#define ARIZONA_AIF_TX_PIN_CTRL 0x01
29#define ARIZONA_AIF_RX_PIN_CTRL 0x02
30#define ARIZONA_AIF_RATE_CTRL 0x03
31#define ARIZONA_AIF_FORMAT 0x04
32#define ARIZONA_AIF_TX_BCLK_RATE 0x05
33#define ARIZONA_AIF_RX_BCLK_RATE 0x06
34#define ARIZONA_AIF_FRAME_CTRL_1 0x07
35#define ARIZONA_AIF_FRAME_CTRL_2 0x08
36#define ARIZONA_AIF_FRAME_CTRL_3 0x09
37#define ARIZONA_AIF_FRAME_CTRL_4 0x0A
38#define ARIZONA_AIF_FRAME_CTRL_5 0x0B
39#define ARIZONA_AIF_FRAME_CTRL_6 0x0C
40#define ARIZONA_AIF_FRAME_CTRL_7 0x0D
41#define ARIZONA_AIF_FRAME_CTRL_8 0x0E
42#define ARIZONA_AIF_FRAME_CTRL_9 0x0F
43#define ARIZONA_AIF_FRAME_CTRL_10 0x10
44#define ARIZONA_AIF_FRAME_CTRL_11 0x11
45#define ARIZONA_AIF_FRAME_CTRL_12 0x12
46#define ARIZONA_AIF_FRAME_CTRL_13 0x13
47#define ARIZONA_AIF_FRAME_CTRL_14 0x14
48#define ARIZONA_AIF_FRAME_CTRL_15 0x15
49#define ARIZONA_AIF_FRAME_CTRL_16 0x16
50#define ARIZONA_AIF_FRAME_CTRL_17 0x17
51#define ARIZONA_AIF_FRAME_CTRL_18 0x18
52#define ARIZONA_AIF_TX_ENABLES 0x19
53#define ARIZONA_AIF_RX_ENABLES 0x1A
54#define ARIZONA_AIF_FORCE_WRITE 0x1B
55
Charles Keepax87383ac2014-03-07 16:34:18 +000056#define ARIZONA_FLL_MAX_FREF 13500000
57#define ARIZONA_FLL_MIN_FVCO 90000000
58#define ARIZONA_FLL_MAX_REFDIV 8
59#define ARIZONA_FLL_MIN_OUTDIV 2
60#define ARIZONA_FLL_MAX_OUTDIV 7
61
Mark Brown07ed8732012-06-18 21:08:44 +010062#define arizona_fll_err(_fll, fmt, ...) \
63 dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
64#define arizona_fll_warn(_fll, fmt, ...) \
65 dev_warn(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
66#define arizona_fll_dbg(_fll, fmt, ...) \
Mark Brown9092a6e2013-02-06 17:58:57 +000067 dev_dbg(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
Mark Brown07ed8732012-06-18 21:08:44 +010068
69#define arizona_aif_err(_dai, fmt, ...) \
70 dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
71#define arizona_aif_warn(_dai, fmt, ...) \
72 dev_warn(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
73#define arizona_aif_dbg(_dai, fmt, ...) \
Mark Brown9092a6e2013-02-06 17:58:57 +000074 dev_dbg(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
Mark Brown07ed8732012-06-18 21:08:44 +010075
Mark Brown56447e12013-01-10 14:45:58 +000076static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
77 struct snd_kcontrol *kcontrol,
78 int event)
79{
80 struct snd_soc_codec *codec = w->codec;
81 struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
82 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
83 bool manual_ena = false;
Mark Brownf4a76e72013-03-13 12:22:39 +000084 int val;
Mark Brown56447e12013-01-10 14:45:58 +000085
86 switch (arizona->type) {
87 case WM5102:
88 switch (arizona->rev) {
89 case 0:
90 break;
91 default:
92 manual_ena = true;
93 break;
94 }
95 default:
96 break;
97 }
98
99 switch (event) {
100 case SND_SOC_DAPM_PRE_PMU:
101 if (!priv->spk_ena && manual_ena) {
Mark Brown3c43c692013-12-12 00:49:22 +0000102 regmap_write_async(arizona->regmap, 0x4f5, 0x25a);
Mark Brown56447e12013-01-10 14:45:58 +0000103 priv->spk_ena_pending = true;
104 }
105 break;
106 case SND_SOC_DAPM_POST_PMU:
Mark Brownf4a76e72013-03-13 12:22:39 +0000107 val = snd_soc_read(codec, ARIZONA_INTERRUPT_RAW_STATUS_3);
108 if (val & ARIZONA_SPK_SHUTDOWN_STS) {
109 dev_crit(arizona->dev,
110 "Speaker not enabled due to temperature\n");
111 return -EBUSY;
112 }
113
Mark Brown3c43c692013-12-12 00:49:22 +0000114 regmap_update_bits_async(arizona->regmap,
115 ARIZONA_OUTPUT_ENABLES_1,
116 1 << w->shift, 1 << w->shift);
Mark Brownf4a76e72013-03-13 12:22:39 +0000117
Mark Brown56447e12013-01-10 14:45:58 +0000118 if (priv->spk_ena_pending) {
119 msleep(75);
Mark Brown3c43c692013-12-12 00:49:22 +0000120 regmap_write_async(arizona->regmap, 0x4f5, 0xda);
Mark Brown56447e12013-01-10 14:45:58 +0000121 priv->spk_ena_pending = false;
122 priv->spk_ena++;
123 }
124 break;
125 case SND_SOC_DAPM_PRE_PMD:
126 if (manual_ena) {
127 priv->spk_ena--;
128 if (!priv->spk_ena)
Mark Brown3c43c692013-12-12 00:49:22 +0000129 regmap_write_async(arizona->regmap,
130 0x4f5, 0x25a);
Mark Brown56447e12013-01-10 14:45:58 +0000131 }
Mark Brownf4a76e72013-03-13 12:22:39 +0000132
Mark Brown3c43c692013-12-12 00:49:22 +0000133 regmap_update_bits_async(arizona->regmap,
134 ARIZONA_OUTPUT_ENABLES_1,
135 1 << w->shift, 0);
Mark Brown56447e12013-01-10 14:45:58 +0000136 break;
137 case SND_SOC_DAPM_POST_PMD:
138 if (manual_ena) {
139 if (!priv->spk_ena)
Mark Brown3c43c692013-12-12 00:49:22 +0000140 regmap_write_async(arizona->regmap,
141 0x4f5, 0x0da);
Mark Brown56447e12013-01-10 14:45:58 +0000142 }
143 break;
144 }
145
146 return 0;
147}
148
Mark Brown899817e2013-03-13 12:32:10 +0000149static irqreturn_t arizona_thermal_warn(int irq, void *data)
150{
151 struct arizona *arizona = data;
152 unsigned int val;
153 int ret;
154
155 ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
156 &val);
157 if (ret != 0) {
158 dev_err(arizona->dev, "Failed to read thermal status: %d\n",
159 ret);
160 } else if (val & ARIZONA_SPK_SHUTDOWN_WARN_STS) {
161 dev_crit(arizona->dev, "Thermal warning\n");
162 }
163
164 return IRQ_HANDLED;
165}
166
167static irqreturn_t arizona_thermal_shutdown(int irq, void *data)
168{
169 struct arizona *arizona = data;
170 unsigned int val;
171 int ret;
172
173 ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
174 &val);
175 if (ret != 0) {
176 dev_err(arizona->dev, "Failed to read thermal status: %d\n",
177 ret);
178 } else if (val & ARIZONA_SPK_SHUTDOWN_STS) {
179 dev_crit(arizona->dev, "Thermal shutdown\n");
Mark Brownf4a76e72013-03-13 12:22:39 +0000180 ret = regmap_update_bits(arizona->regmap,
181 ARIZONA_OUTPUT_ENABLES_1,
182 ARIZONA_OUT4L_ENA |
183 ARIZONA_OUT4R_ENA, 0);
184 if (ret != 0)
185 dev_crit(arizona->dev,
186 "Failed to disable speaker outputs: %d\n",
187 ret);
Mark Brown899817e2013-03-13 12:32:10 +0000188 }
189
190 return IRQ_HANDLED;
191}
192
Mark Brown56447e12013-01-10 14:45:58 +0000193static const struct snd_soc_dapm_widget arizona_spkl =
Mark Brownf4a76e72013-03-13 12:22:39 +0000194 SND_SOC_DAPM_PGA_E("OUT4L", SND_SOC_NOPM,
Mark Brown56447e12013-01-10 14:45:58 +0000195 ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
196 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
197
198static const struct snd_soc_dapm_widget arizona_spkr =
Mark Brownf4a76e72013-03-13 12:22:39 +0000199 SND_SOC_DAPM_PGA_E("OUT4R", SND_SOC_NOPM,
Mark Brown56447e12013-01-10 14:45:58 +0000200 ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
201 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
202
203int arizona_init_spk(struct snd_soc_codec *codec)
204{
Mark Brown899817e2013-03-13 12:32:10 +0000205 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
206 struct arizona *arizona = priv->arizona;
Mark Brown56447e12013-01-10 14:45:58 +0000207 int ret;
208
209 ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkl, 1);
210 if (ret != 0)
211 return ret;
212
Charles Keepax40843ae2013-08-12 23:46:55 +0100213 switch (arizona->type) {
214 case WM8997:
215 break;
216 default:
217 ret = snd_soc_dapm_new_controls(&codec->dapm,
218 &arizona_spkr, 1);
219 if (ret != 0)
220 return ret;
221 break;
222 }
Mark Brown56447e12013-01-10 14:45:58 +0000223
Mark Brown899817e2013-03-13 12:32:10 +0000224 ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN_WARN,
225 "Thermal warning", arizona_thermal_warn,
226 arizona);
227 if (ret != 0)
228 dev_err(arizona->dev,
229 "Failed to get thermal warning IRQ: %d\n",
230 ret);
231
232 ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN,
233 "Thermal shutdown", arizona_thermal_shutdown,
234 arizona);
235 if (ret != 0)
236 dev_err(arizona->dev,
237 "Failed to get thermal shutdown IRQ: %d\n",
238 ret);
239
Mark Brown56447e12013-01-10 14:45:58 +0000240 return 0;
241}
242EXPORT_SYMBOL_GPL(arizona_init_spk);
243
Charles Keepaxb63144e2013-07-04 08:56:28 +0100244int arizona_init_gpio(struct snd_soc_codec *codec)
245{
246 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
247 struct arizona *arizona = priv->arizona;
248 int i;
249
250 switch (arizona->type) {
251 case WM5110:
252 snd_soc_dapm_disable_pin(&codec->dapm, "DRC2 Signal Activity");
Charles Keepaxb79fae62013-07-04 16:53:03 +0100253 break;
254 default:
255 break;
Charles Keepaxb63144e2013-07-04 08:56:28 +0100256 }
257
258 snd_soc_dapm_disable_pin(&codec->dapm, "DRC1 Signal Activity");
259
260 for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
261 switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) {
262 case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT:
263 snd_soc_dapm_enable_pin(&codec->dapm,
264 "DRC1 Signal Activity");
265 break;
266 case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT:
267 snd_soc_dapm_enable_pin(&codec->dapm,
268 "DRC2 Signal Activity");
269 break;
270 default:
271 break;
272 }
273 }
274
275 return 0;
276}
277EXPORT_SYMBOL_GPL(arizona_init_gpio);
278
Mark Brown07ed8732012-06-18 21:08:44 +0100279const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
280 "None",
281 "Tone Generator 1",
282 "Tone Generator 2",
283 "Haptics",
284 "AEC",
285 "Mic Mute Mixer",
286 "Noise Generator",
287 "IN1L",
288 "IN1R",
289 "IN2L",
290 "IN2R",
291 "IN3L",
292 "IN3R",
Mark Brownc9c56fd2012-07-09 19:09:01 +0100293 "IN4L",
294 "IN4R",
Mark Brown07ed8732012-06-18 21:08:44 +0100295 "AIF1RX1",
296 "AIF1RX2",
297 "AIF1RX3",
298 "AIF1RX4",
299 "AIF1RX5",
300 "AIF1RX6",
301 "AIF1RX7",
302 "AIF1RX8",
303 "AIF2RX1",
304 "AIF2RX2",
Richard Fitzgeralde64001e2013-11-20 13:17:07 +0000305 "AIF2RX3",
306 "AIF2RX4",
307 "AIF2RX5",
308 "AIF2RX6",
Mark Brown07ed8732012-06-18 21:08:44 +0100309 "AIF3RX1",
310 "AIF3RX2",
311 "SLIMRX1",
312 "SLIMRX2",
313 "SLIMRX3",
314 "SLIMRX4",
315 "SLIMRX5",
316 "SLIMRX6",
317 "SLIMRX7",
318 "SLIMRX8",
319 "EQ1",
320 "EQ2",
321 "EQ3",
322 "EQ4",
323 "DRC1L",
324 "DRC1R",
325 "DRC2L",
326 "DRC2R",
327 "LHPF1",
328 "LHPF2",
329 "LHPF3",
330 "LHPF4",
331 "DSP1.1",
332 "DSP1.2",
333 "DSP1.3",
334 "DSP1.4",
335 "DSP1.5",
336 "DSP1.6",
Mark Brownc922cc42012-09-26 16:43:44 +0100337 "DSP2.1",
338 "DSP2.2",
339 "DSP2.3",
340 "DSP2.4",
341 "DSP2.5",
342 "DSP2.6",
343 "DSP3.1",
344 "DSP3.2",
345 "DSP3.3",
346 "DSP3.4",
347 "DSP3.5",
348 "DSP3.6",
349 "DSP4.1",
350 "DSP4.2",
351 "DSP4.3",
352 "DSP4.4",
353 "DSP4.5",
354 "DSP4.6",
Mark Brown07ed8732012-06-18 21:08:44 +0100355 "ASRC1L",
356 "ASRC1R",
357 "ASRC2L",
358 "ASRC2R",
Mark Brown91660bd2012-12-05 20:35:24 +0900359 "ISRC1INT1",
360 "ISRC1INT2",
361 "ISRC1INT3",
362 "ISRC1INT4",
363 "ISRC1DEC1",
364 "ISRC1DEC2",
365 "ISRC1DEC3",
366 "ISRC1DEC4",
367 "ISRC2INT1",
368 "ISRC2INT2",
369 "ISRC2INT3",
370 "ISRC2INT4",
371 "ISRC2DEC1",
372 "ISRC2DEC2",
373 "ISRC2DEC3",
374 "ISRC2DEC4",
375 "ISRC3INT1",
376 "ISRC3INT2",
377 "ISRC3INT3",
378 "ISRC3INT4",
379 "ISRC3DEC1",
380 "ISRC3DEC2",
381 "ISRC3DEC3",
382 "ISRC3DEC4",
Mark Brown07ed8732012-06-18 21:08:44 +0100383};
384EXPORT_SYMBOL_GPL(arizona_mixer_texts);
385
386int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
387 0x00, /* None */
388 0x04, /* Tone */
389 0x05,
390 0x06, /* Haptics */
391 0x08, /* AEC */
392 0x0c, /* Noise mixer */
393 0x0d, /* Comfort noise */
394 0x10, /* IN1L */
395 0x11,
396 0x12,
397 0x13,
398 0x14,
399 0x15,
Mark Brownc9c56fd2012-07-09 19:09:01 +0100400 0x16,
401 0x17,
Mark Brown07ed8732012-06-18 21:08:44 +0100402 0x20, /* AIF1RX1 */
403 0x21,
404 0x22,
405 0x23,
406 0x24,
407 0x25,
408 0x26,
409 0x27,
410 0x28, /* AIF2RX1 */
411 0x29,
Richard Fitzgeralde64001e2013-11-20 13:17:07 +0000412 0x2a,
413 0x2b,
414 0x2c,
415 0x2d,
Mark Brown07ed8732012-06-18 21:08:44 +0100416 0x30, /* AIF3RX1 */
417 0x31,
418 0x38, /* SLIMRX1 */
419 0x39,
420 0x3a,
421 0x3b,
422 0x3c,
423 0x3d,
424 0x3e,
425 0x3f,
426 0x50, /* EQ1 */
427 0x51,
428 0x52,
429 0x53,
430 0x58, /* DRC1L */
431 0x59,
432 0x5a,
433 0x5b,
434 0x60, /* LHPF1 */
435 0x61,
436 0x62,
437 0x63,
438 0x68, /* DSP1.1 */
439 0x69,
440 0x6a,
441 0x6b,
442 0x6c,
443 0x6d,
Mark Brownc922cc42012-09-26 16:43:44 +0100444 0x70, /* DSP2.1 */
445 0x71,
446 0x72,
447 0x73,
448 0x74,
449 0x75,
450 0x78, /* DSP3.1 */
451 0x79,
452 0x7a,
453 0x7b,
454 0x7c,
455 0x7d,
456 0x80, /* DSP4.1 */
457 0x81,
458 0x82,
459 0x83,
460 0x84,
461 0x85,
Mark Brown07ed8732012-06-18 21:08:44 +0100462 0x90, /* ASRC1L */
463 0x91,
464 0x92,
465 0x93,
Mark Brown91660bd2012-12-05 20:35:24 +0900466 0xa0, /* ISRC1INT1 */
467 0xa1,
468 0xa2,
469 0xa3,
470 0xa4, /* ISRC1DEC1 */
471 0xa5,
472 0xa6,
473 0xa7,
474 0xa8, /* ISRC2DEC1 */
475 0xa9,
476 0xaa,
477 0xab,
478 0xac, /* ISRC2INT1 */
479 0xad,
480 0xae,
481 0xaf,
482 0xb0, /* ISRC3DEC1 */
483 0xb1,
484 0xb2,
485 0xb3,
486 0xb4, /* ISRC3INT1 */
487 0xb5,
488 0xb6,
489 0xb7,
Mark Brown07ed8732012-06-18 21:08:44 +0100490};
491EXPORT_SYMBOL_GPL(arizona_mixer_values);
492
493const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
494EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
495
Mark Browndc914282013-02-18 19:09:23 +0000496const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = {
497 "SYNCCLK rate", "8kHz", "16kHz", "ASYNCCLK rate",
498};
499EXPORT_SYMBOL_GPL(arizona_rate_text);
500
501const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
502 0, 1, 2, 8,
503};
504EXPORT_SYMBOL_GPL(arizona_rate_val);
505
506
Charles Keepaxfbedc8c2013-12-19 09:30:12 +0000507const struct soc_enum arizona_isrc_fsh[] = {
508 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_1,
509 ARIZONA_ISRC1_FSH_SHIFT, 0xf,
510 ARIZONA_RATE_ENUM_SIZE,
511 arizona_rate_text, arizona_rate_val),
512 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_1,
513 ARIZONA_ISRC2_FSH_SHIFT, 0xf,
514 ARIZONA_RATE_ENUM_SIZE,
515 arizona_rate_text, arizona_rate_val),
516 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_1,
517 ARIZONA_ISRC3_FSH_SHIFT, 0xf,
518 ARIZONA_RATE_ENUM_SIZE,
519 arizona_rate_text, arizona_rate_val),
520};
521EXPORT_SYMBOL_GPL(arizona_isrc_fsh);
522
Mark Browndc914282013-02-18 19:09:23 +0000523const struct soc_enum arizona_isrc_fsl[] = {
524 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2,
525 ARIZONA_ISRC1_FSL_SHIFT, 0xf,
526 ARIZONA_RATE_ENUM_SIZE,
527 arizona_rate_text, arizona_rate_val),
528 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_2,
529 ARIZONA_ISRC2_FSL_SHIFT, 0xf,
530 ARIZONA_RATE_ENUM_SIZE,
531 arizona_rate_text, arizona_rate_val),
532 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_2,
533 ARIZONA_ISRC3_FSL_SHIFT, 0xf,
534 ARIZONA_RATE_ENUM_SIZE,
535 arizona_rate_text, arizona_rate_val),
536};
537EXPORT_SYMBOL_GPL(arizona_isrc_fsl);
538
Charles Keepax56d37d82013-12-19 09:30:13 +0000539const struct soc_enum arizona_asrc_rate1 =
540 SOC_VALUE_ENUM_SINGLE(ARIZONA_ASRC_RATE1,
541 ARIZONA_ASRC_RATE1_SHIFT, 0xf,
542 ARIZONA_RATE_ENUM_SIZE - 1,
543 arizona_rate_text, arizona_rate_val);
544EXPORT_SYMBOL_GPL(arizona_asrc_rate1);
545
Mark Browne853a002012-12-09 12:25:52 +0900546static const char *arizona_vol_ramp_text[] = {
547 "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
548 "15ms/6dB", "30ms/6dB",
549};
550
551const struct soc_enum arizona_in_vd_ramp =
552 SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP,
553 ARIZONA_IN_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text);
554EXPORT_SYMBOL_GPL(arizona_in_vd_ramp);
555
556const struct soc_enum arizona_in_vi_ramp =
557 SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP,
558 ARIZONA_IN_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text);
559EXPORT_SYMBOL_GPL(arizona_in_vi_ramp);
560
561const struct soc_enum arizona_out_vd_ramp =
562 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP,
563 ARIZONA_OUT_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text);
564EXPORT_SYMBOL_GPL(arizona_out_vd_ramp);
565
566const struct soc_enum arizona_out_vi_ramp =
567 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP,
568 ARIZONA_OUT_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text);
569EXPORT_SYMBOL_GPL(arizona_out_vi_ramp);
570
Mark Brown07ed8732012-06-18 21:08:44 +0100571static const char *arizona_lhpf_mode_text[] = {
572 "Low-pass", "High-pass"
573};
574
575const struct soc_enum arizona_lhpf1_mode =
576 SOC_ENUM_SINGLE(ARIZONA_HPLPF1_1, ARIZONA_LHPF1_MODE_SHIFT, 2,
577 arizona_lhpf_mode_text);
578EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
579
580const struct soc_enum arizona_lhpf2_mode =
581 SOC_ENUM_SINGLE(ARIZONA_HPLPF2_1, ARIZONA_LHPF2_MODE_SHIFT, 2,
582 arizona_lhpf_mode_text);
583EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
584
585const struct soc_enum arizona_lhpf3_mode =
586 SOC_ENUM_SINGLE(ARIZONA_HPLPF3_1, ARIZONA_LHPF3_MODE_SHIFT, 2,
587 arizona_lhpf_mode_text);
588EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
589
590const struct soc_enum arizona_lhpf4_mode =
591 SOC_ENUM_SINGLE(ARIZONA_HPLPF4_1, ARIZONA_LHPF4_MODE_SHIFT, 2,
592 arizona_lhpf_mode_text);
593EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
594
Mark Brown845571c2012-12-18 13:47:57 +0000595static const char *arizona_ng_hold_text[] = {
596 "30ms", "120ms", "250ms", "500ms",
597};
598
599const struct soc_enum arizona_ng_hold =
600 SOC_ENUM_SINGLE(ARIZONA_NOISE_GATE_CONTROL, ARIZONA_NGATE_HOLD_SHIFT,
601 4, arizona_ng_hold_text);
602EXPORT_SYMBOL_GPL(arizona_ng_hold);
603
Charles Keepax254dc322013-11-19 16:04:03 +0000604static const char * const arizona_in_hpf_cut_text[] = {
605 "2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz"
606};
607
608const struct soc_enum arizona_in_hpf_cut_enum =
609 SOC_ENUM_SINGLE(ARIZONA_HPF_CONTROL, ARIZONA_IN_HPF_CUT_SHIFT,
610 ARRAY_SIZE(arizona_in_hpf_cut_text),
611 arizona_in_hpf_cut_text);
612EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum);
613
Charles Keepaxc7f38432013-08-06 17:03:55 +0100614static const char * const arizona_in_dmic_osr_text[] = {
615 "1.536MHz", "3.072MHz", "6.144MHz",
616};
617
618const struct soc_enum arizona_in_dmic_osr[] = {
619 SOC_ENUM_SINGLE(ARIZONA_IN1L_CONTROL, ARIZONA_IN1_OSR_SHIFT,
620 ARRAY_SIZE(arizona_in_dmic_osr_text),
621 arizona_in_dmic_osr_text),
622 SOC_ENUM_SINGLE(ARIZONA_IN2L_CONTROL, ARIZONA_IN2_OSR_SHIFT,
623 ARRAY_SIZE(arizona_in_dmic_osr_text),
624 arizona_in_dmic_osr_text),
625 SOC_ENUM_SINGLE(ARIZONA_IN3L_CONTROL, ARIZONA_IN3_OSR_SHIFT,
626 ARRAY_SIZE(arizona_in_dmic_osr_text),
627 arizona_in_dmic_osr_text),
628 SOC_ENUM_SINGLE(ARIZONA_IN4L_CONTROL, ARIZONA_IN4_OSR_SHIFT,
629 ARRAY_SIZE(arizona_in_dmic_osr_text),
630 arizona_in_dmic_osr_text),
631};
632EXPORT_SYMBOL_GPL(arizona_in_dmic_osr);
633
Mark Brownddbce972013-02-15 17:27:22 +0000634static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
635{
636 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
637 unsigned int val;
638 int i;
639
640 if (ena)
641 val = ARIZONA_IN_VU;
642 else
643 val = 0;
644
645 for (i = 0; i < priv->num_inputs; i++)
646 snd_soc_update_bits(codec,
647 ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 4),
648 ARIZONA_IN_VU, val);
649}
650
Mark Brown07ed8732012-06-18 21:08:44 +0100651int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
652 int event)
653{
Mark Brownddbce972013-02-15 17:27:22 +0000654 struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000655 unsigned int reg;
656
657 if (w->shift % 2)
658 reg = ARIZONA_ADC_DIGITAL_VOLUME_1L + ((w->shift / 2) * 8);
659 else
660 reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8);
661
662 switch (event) {
Mark Brownddbce972013-02-15 17:27:22 +0000663 case SND_SOC_DAPM_PRE_PMU:
664 priv->in_pending++;
665 break;
Mark Brown43cd8bf2013-02-06 16:57:29 +0000666 case SND_SOC_DAPM_POST_PMU:
667 snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, 0);
Mark Brownddbce972013-02-15 17:27:22 +0000668
669 /* If this is the last input pending then allow VU */
670 priv->in_pending--;
671 if (priv->in_pending == 0) {
672 msleep(1);
673 arizona_in_set_vu(w->codec, 1);
674 }
Mark Brown43cd8bf2013-02-06 16:57:29 +0000675 break;
676 case SND_SOC_DAPM_PRE_PMD:
Mark Brownddbce972013-02-15 17:27:22 +0000677 snd_soc_update_bits(w->codec, reg,
678 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU,
679 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000680 break;
Mark Brownddbce972013-02-15 17:27:22 +0000681 case SND_SOC_DAPM_POST_PMD:
682 /* Disable volume updates if no inputs are enabled */
683 reg = snd_soc_read(w->codec, ARIZONA_INPUT_ENABLES);
684 if (reg == 0)
685 arizona_in_set_vu(w->codec, 0);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000686 }
687
Mark Brown07ed8732012-06-18 21:08:44 +0100688 return 0;
689}
690EXPORT_SYMBOL_GPL(arizona_in_ev);
691
692int arizona_out_ev(struct snd_soc_dapm_widget *w,
693 struct snd_kcontrol *kcontrol,
694 int event)
695{
Mark Brown1a2c7d52013-03-24 22:50:23 +0000696 switch (event) {
697 case SND_SOC_DAPM_POST_PMU:
698 switch (w->shift) {
699 case ARIZONA_OUT1L_ENA_SHIFT:
700 case ARIZONA_OUT1R_ENA_SHIFT:
701 case ARIZONA_OUT2L_ENA_SHIFT:
702 case ARIZONA_OUT2R_ENA_SHIFT:
703 case ARIZONA_OUT3L_ENA_SHIFT:
704 case ARIZONA_OUT3R_ENA_SHIFT:
705 msleep(17);
706 break;
707
708 default:
709 break;
710 }
711 break;
712 }
713
Mark Brown07ed8732012-06-18 21:08:44 +0100714 return 0;
715}
716EXPORT_SYMBOL_GPL(arizona_out_ev);
717
Mark Brownf607e312013-02-22 18:36:53 +0000718int arizona_hp_ev(struct snd_soc_dapm_widget *w,
719 struct snd_kcontrol *kcontrol,
720 int event)
721{
722 struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
Mark Brown3c43c692013-12-12 00:49:22 +0000723 struct arizona *arizona = priv->arizona;
Mark Brownf607e312013-02-22 18:36:53 +0000724 unsigned int mask = 1 << w->shift;
725 unsigned int val;
726
727 switch (event) {
728 case SND_SOC_DAPM_POST_PMU:
729 val = mask;
730 break;
731 case SND_SOC_DAPM_PRE_PMD:
732 val = 0;
733 break;
734 default:
735 return -EINVAL;
736 }
737
738 /* Store the desired state for the HP outputs */
739 priv->arizona->hp_ena &= ~mask;
740 priv->arizona->hp_ena |= val;
741
742 /* Force off if HPDET magic is active */
743 if (priv->arizona->hpdet_magic)
744 val = 0;
745
Mark Brown3c43c692013-12-12 00:49:22 +0000746 regmap_update_bits_async(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1,
747 mask, val);
Mark Brownf607e312013-02-22 18:36:53 +0000748
749 return arizona_out_ev(w, kcontrol, event);
750}
751EXPORT_SYMBOL_GPL(arizona_hp_ev);
752
Mark Browncbd840d2012-08-08 17:52:44 +0100753static unsigned int arizona_sysclk_48k_rates[] = {
754 6144000,
755 12288000,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000756 24576000,
Mark Browncbd840d2012-08-08 17:52:44 +0100757 49152000,
Mark Brownaeaeee12012-09-26 17:50:02 +0100758 73728000,
759 98304000,
760 147456000,
Mark Browncbd840d2012-08-08 17:52:44 +0100761};
762
763static unsigned int arizona_sysclk_44k1_rates[] = {
764 5644800,
765 11289600,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000766 22579200,
Mark Browncbd840d2012-08-08 17:52:44 +0100767 45158400,
Mark Brownaeaeee12012-09-26 17:50:02 +0100768 67737600,
769 90316800,
770 135475200,
Mark Browncbd840d2012-08-08 17:52:44 +0100771};
772
773static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
774 unsigned int freq)
775{
776 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
777 unsigned int reg;
778 unsigned int *rates;
779 int ref, div, refclk;
780
781 switch (clk) {
782 case ARIZONA_CLK_OPCLK:
783 reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
784 refclk = priv->sysclk;
785 break;
786 case ARIZONA_CLK_ASYNC_OPCLK:
787 reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
788 refclk = priv->asyncclk;
789 break;
790 default:
791 return -EINVAL;
792 }
793
794 if (refclk % 8000)
795 rates = arizona_sysclk_44k1_rates;
796 else
797 rates = arizona_sysclk_48k_rates;
798
799 for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) &&
800 rates[ref] <= refclk; ref++) {
801 div = 1;
802 while (rates[ref] / div >= freq && div < 32) {
803 if (rates[ref] / div == freq) {
804 dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
805 freq);
806 snd_soc_update_bits(codec, reg,
807 ARIZONA_OPCLK_DIV_MASK |
808 ARIZONA_OPCLK_SEL_MASK,
809 (div <<
810 ARIZONA_OPCLK_DIV_SHIFT) |
811 ref);
812 return 0;
813 }
814 div++;
815 }
816 }
817
818 dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
819 return -EINVAL;
820}
821
Mark Brown07ed8732012-06-18 21:08:44 +0100822int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
823 int source, unsigned int freq, int dir)
824{
825 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
826 struct arizona *arizona = priv->arizona;
827 char *name;
828 unsigned int reg;
829 unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
830 unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
831 unsigned int *clk;
832
833 switch (clk_id) {
834 case ARIZONA_CLK_SYSCLK:
835 name = "SYSCLK";
836 reg = ARIZONA_SYSTEM_CLOCK_1;
837 clk = &priv->sysclk;
838 mask |= ARIZONA_SYSCLK_FRAC;
839 break;
840 case ARIZONA_CLK_ASYNCCLK:
841 name = "ASYNCCLK";
842 reg = ARIZONA_ASYNC_CLOCK_1;
843 clk = &priv->asyncclk;
844 break;
Mark Browncbd840d2012-08-08 17:52:44 +0100845 case ARIZONA_CLK_OPCLK:
846 case ARIZONA_CLK_ASYNC_OPCLK:
847 return arizona_set_opclk(codec, clk_id, freq);
Mark Brown07ed8732012-06-18 21:08:44 +0100848 default:
849 return -EINVAL;
850 }
851
852 switch (freq) {
853 case 5644800:
854 case 6144000:
855 break;
856 case 11289600:
857 case 12288000:
Mark Brown3f341f72013-03-08 15:22:29 +0800858 val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100859 break;
860 case 22579200:
861 case 24576000:
Mark Brown3f341f72013-03-08 15:22:29 +0800862 val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100863 break;
864 case 45158400:
865 case 49152000:
Mark Brown3f341f72013-03-08 15:22:29 +0800866 val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100867 break;
Mark Brown38113362012-11-26 16:01:37 +0000868 case 67737600:
869 case 73728000:
Mark Brown3f341f72013-03-08 15:22:29 +0800870 val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000871 break;
872 case 90316800:
873 case 98304000:
Mark Brown3f341f72013-03-08 15:22:29 +0800874 val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000875 break;
876 case 135475200:
877 case 147456000:
Mark Brown3f341f72013-03-08 15:22:29 +0800878 val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000879 break;
Mark Brownf2c26d42013-01-21 16:09:36 +0900880 case 0:
881 dev_dbg(arizona->dev, "%s cleared\n", name);
882 *clk = freq;
883 return 0;
Mark Brown07ed8732012-06-18 21:08:44 +0100884 default:
885 return -EINVAL;
886 }
887
888 *clk = freq;
889
890 if (freq % 6144000)
891 val |= ARIZONA_SYSCLK_FRAC;
892
893 dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
894
895 return regmap_update_bits(arizona->regmap, reg, mask, val);
896}
897EXPORT_SYMBOL_GPL(arizona_set_sysclk);
898
899static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
900{
901 struct snd_soc_codec *codec = dai->codec;
Mark Brown3c43c692013-12-12 00:49:22 +0000902 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
903 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +0100904 int lrclk, bclk, mode, base;
905
906 base = dai->driver->base;
907
908 lrclk = 0;
909 bclk = 0;
910
911 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
912 case SND_SOC_DAIFMT_DSP_A:
913 mode = 0;
914 break;
Mark Brown07ed8732012-06-18 21:08:44 +0100915 case SND_SOC_DAIFMT_I2S:
916 mode = 2;
917 break;
Mark Brown07ed8732012-06-18 21:08:44 +0100918 default:
919 arizona_aif_err(dai, "Unsupported DAI format %d\n",
920 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
921 return -EINVAL;
922 }
923
924 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
925 case SND_SOC_DAIFMT_CBS_CFS:
926 break;
927 case SND_SOC_DAIFMT_CBS_CFM:
928 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
929 break;
930 case SND_SOC_DAIFMT_CBM_CFS:
931 bclk |= ARIZONA_AIF1_BCLK_MSTR;
932 break;
933 case SND_SOC_DAIFMT_CBM_CFM:
934 bclk |= ARIZONA_AIF1_BCLK_MSTR;
935 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
936 break;
937 default:
938 arizona_aif_err(dai, "Unsupported master mode %d\n",
939 fmt & SND_SOC_DAIFMT_MASTER_MASK);
940 return -EINVAL;
941 }
942
943 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
944 case SND_SOC_DAIFMT_NB_NF:
945 break;
946 case SND_SOC_DAIFMT_IB_IF:
947 bclk |= ARIZONA_AIF1_BCLK_INV;
948 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
949 break;
950 case SND_SOC_DAIFMT_IB_NF:
951 bclk |= ARIZONA_AIF1_BCLK_INV;
952 break;
953 case SND_SOC_DAIFMT_NB_IF:
954 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
955 break;
956 default:
957 return -EINVAL;
958 }
959
Mark Brown3c43c692013-12-12 00:49:22 +0000960 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_BCLK_CTRL,
961 ARIZONA_AIF1_BCLK_INV |
962 ARIZONA_AIF1_BCLK_MSTR,
963 bclk);
964 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_TX_PIN_CTRL,
965 ARIZONA_AIF1TX_LRCLK_INV |
966 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
967 regmap_update_bits_async(arizona->regmap,
968 base + ARIZONA_AIF_RX_PIN_CTRL,
969 ARIZONA_AIF1RX_LRCLK_INV |
970 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
971 regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FORMAT,
972 ARIZONA_AIF1_FMT_MASK, mode);
Mark Brown07ed8732012-06-18 21:08:44 +0100973
974 return 0;
975}
976
Mark Brown949e6bc2012-07-04 18:58:04 +0100977static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100978 -1,
979 48000,
980 64000,
981 96000,
982 128000,
983 192000,
984 256000,
985 384000,
986 512000,
987 768000,
988 1024000,
989 1536000,
990 2048000,
991 3072000,
992 4096000,
993 6144000,
994 8192000,
995 12288000,
996 24576000,
997};
998
Mark Brown5b2eec32012-07-04 17:32:05 +0100999static const unsigned int arizona_48k_rates[] = {
1000 12000,
1001 24000,
1002 48000,
1003 96000,
1004 192000,
1005 384000,
1006 768000,
1007 4000,
1008 8000,
1009 16000,
1010 32000,
1011 64000,
1012 128000,
1013 256000,
1014 512000,
1015};
1016
1017static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = {
1018 .count = ARRAY_SIZE(arizona_48k_rates),
1019 .list = arizona_48k_rates,
1020};
1021
Mark Brown949e6bc2012-07-04 18:58:04 +01001022static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001023 -1,
1024 44100,
1025 58800,
1026 88200,
1027 117600,
1028 177640,
1029 235200,
1030 352800,
1031 470400,
1032 705600,
1033 940800,
1034 1411200,
1035 1881600,
Heather Lomond4758be32012-09-05 05:02:10 -04001036 2822400,
Mark Brown07ed8732012-06-18 21:08:44 +01001037 3763200,
1038 5644800,
1039 7526400,
1040 11289600,
1041 22579200,
1042};
1043
Mark Brown5b2eec32012-07-04 17:32:05 +01001044static const unsigned int arizona_44k1_rates[] = {
1045 11025,
1046 22050,
1047 44100,
1048 88200,
1049 176400,
1050 352800,
1051 705600,
1052};
1053
1054static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = {
1055 .count = ARRAY_SIZE(arizona_44k1_rates),
1056 .list = arizona_44k1_rates,
1057};
1058
Mark Brown07ed8732012-06-18 21:08:44 +01001059static int arizona_sr_vals[] = {
1060 0,
1061 12000,
1062 24000,
1063 48000,
1064 96000,
1065 192000,
1066 384000,
1067 768000,
1068 0,
1069 11025,
1070 22050,
1071 44100,
1072 88200,
1073 176400,
1074 352800,
1075 705600,
1076 4000,
1077 8000,
1078 16000,
1079 32000,
1080 64000,
1081 128000,
1082 256000,
1083 512000,
1084};
1085
Mark Brown5b2eec32012-07-04 17:32:05 +01001086static int arizona_startup(struct snd_pcm_substream *substream,
1087 struct snd_soc_dai *dai)
1088{
1089 struct snd_soc_codec *codec = dai->codec;
1090 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1091 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
1092 const struct snd_pcm_hw_constraint_list *constraint;
1093 unsigned int base_rate;
1094
1095 switch (dai_priv->clk) {
1096 case ARIZONA_CLK_SYSCLK:
1097 base_rate = priv->sysclk;
1098 break;
1099 case ARIZONA_CLK_ASYNCCLK:
1100 base_rate = priv->asyncclk;
1101 break;
1102 default:
1103 return 0;
1104 }
1105
Mark Brownf2c26d42013-01-21 16:09:36 +09001106 if (base_rate == 0)
1107 return 0;
1108
Mark Brown5b2eec32012-07-04 17:32:05 +01001109 if (base_rate % 8000)
1110 constraint = &arizona_44k1_constraint;
1111 else
1112 constraint = &arizona_48k_constraint;
1113
1114 return snd_pcm_hw_constraint_list(substream->runtime, 0,
1115 SNDRV_PCM_HW_PARAM_RATE,
1116 constraint);
1117}
1118
Mark Brownb272efc2012-10-10 15:10:08 +09001119static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
1120 struct snd_pcm_hw_params *params,
1121 struct snd_soc_dai *dai)
Mark Brown07ed8732012-06-18 21:08:44 +01001122{
1123 struct snd_soc_codec *codec = dai->codec;
Mark Brownc013b272012-07-04 20:05:57 +01001124 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1125 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown07ed8732012-06-18 21:08:44 +01001126 int base = dai->driver->base;
Mark Brownb272efc2012-10-10 15:10:08 +09001127 int i, sr_val;
1128
1129 /*
1130 * We will need to be more flexible than this in future,
1131 * currently we use a single sample rate for SYSCLK.
1132 */
1133 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
1134 if (arizona_sr_vals[i] == params_rate(params))
1135 break;
1136 if (i == ARRAY_SIZE(arizona_sr_vals)) {
1137 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1138 params_rate(params));
1139 return -EINVAL;
1140 }
1141 sr_val = i;
1142
1143 switch (dai_priv->clk) {
1144 case ARIZONA_CLK_SYSCLK:
1145 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
1146 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
1147 if (base)
1148 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1149 ARIZONA_AIF1_RATE_MASK, 0);
1150 break;
1151 case ARIZONA_CLK_ASYNCCLK:
1152 snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
1153 ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val);
1154 if (base)
1155 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1156 ARIZONA_AIF1_RATE_MASK,
1157 8 << ARIZONA_AIF1_RATE_SHIFT);
1158 break;
1159 default:
1160 arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
1161 return -EINVAL;
1162 }
1163
1164 return 0;
1165}
1166
Mark Brown07ed8732012-06-18 21:08:44 +01001167static int arizona_hw_params(struct snd_pcm_substream *substream,
1168 struct snd_pcm_hw_params *params,
1169 struct snd_soc_dai *dai)
1170{
1171 struct snd_soc_codec *codec = dai->codec;
1172 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brownc94aa302013-01-17 16:35:14 +09001173 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +01001174 int base = dai->driver->base;
1175 const int *rates;
Mark Brown76bf9692013-03-05 14:17:47 +08001176 int i, ret, val;
Mark Brownc94aa302013-01-17 16:35:14 +09001177 int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
1178 int bclk, lrclk, wl, frame, bclk_target;
Mark Brown07ed8732012-06-18 21:08:44 +01001179
1180 if (params_rate(params) % 8000)
Mark Brown949e6bc2012-07-04 18:58:04 +01001181 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001182 else
Mark Brown949e6bc2012-07-04 18:58:04 +01001183 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001184
Mark Brownc94aa302013-01-17 16:35:14 +09001185 bclk_target = snd_soc_params_to_bclk(params);
1186 if (chan_limit && chan_limit < params_channels(params)) {
1187 arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
1188 bclk_target /= params_channels(params);
1189 bclk_target *= chan_limit;
1190 }
1191
Mark Brown76bf9692013-03-05 14:17:47 +08001192 /* Force stereo for I2S mode */
1193 val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
1194 if (params_channels(params) == 1 && (val & ARIZONA_AIF1_FMT_MASK)) {
1195 arizona_aif_dbg(dai, "Forcing stereo mode\n");
1196 bclk_target *= 2;
1197 }
1198
Mark Brown949e6bc2012-07-04 18:58:04 +01001199 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brownc94aa302013-01-17 16:35:14 +09001200 if (rates[i] >= bclk_target &&
Mark Brown50017652012-07-04 19:07:09 +01001201 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +01001202 bclk = i;
1203 break;
1204 }
1205 }
Mark Brown949e6bc2012-07-04 18:58:04 +01001206 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001207 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1208 params_rate(params));
1209 return -EINVAL;
1210 }
1211
Mark Brownb59e0f82013-01-17 14:15:59 +09001212 lrclk = rates[bclk] / params_rate(params);
Mark Brown07ed8732012-06-18 21:08:44 +01001213
1214 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
1215 rates[bclk], rates[bclk] / lrclk);
1216
1217 wl = snd_pcm_format_width(params_format(params));
1218 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl;
1219
Mark Brownb272efc2012-10-10 15:10:08 +09001220 ret = arizona_hw_params_rate(substream, params, dai);
1221 if (ret != 0)
1222 return ret;
Mark Brownc013b272012-07-04 20:05:57 +01001223
Mark Brown3c43c692013-12-12 00:49:22 +00001224 regmap_update_bits_async(arizona->regmap,
1225 base + ARIZONA_AIF_BCLK_CTRL,
1226 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
1227 regmap_update_bits_async(arizona->regmap,
1228 base + ARIZONA_AIF_TX_BCLK_RATE,
1229 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
1230 regmap_update_bits_async(arizona->regmap,
1231 base + ARIZONA_AIF_RX_BCLK_RATE,
1232 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
1233 regmap_update_bits_async(arizona->regmap,
1234 base + ARIZONA_AIF_FRAME_CTRL_1,
1235 ARIZONA_AIF1TX_WL_MASK |
1236 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
1237 regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FRAME_CTRL_2,
1238 ARIZONA_AIF1RX_WL_MASK |
1239 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
Mark Brown07ed8732012-06-18 21:08:44 +01001240
1241 return 0;
1242}
1243
Mark Brown410837a2012-07-05 17:26:59 +01001244static const char *arizona_dai_clk_str(int clk_id)
1245{
1246 switch (clk_id) {
1247 case ARIZONA_CLK_SYSCLK:
1248 return "SYSCLK";
1249 case ARIZONA_CLK_ASYNCCLK:
1250 return "ASYNCCLK";
1251 default:
1252 return "Unknown clock";
1253 }
1254}
1255
Mark Brown5b2eec32012-07-04 17:32:05 +01001256static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
1257 int clk_id, unsigned int freq, int dir)
1258{
1259 struct snd_soc_codec *codec = dai->codec;
1260 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1261 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown410837a2012-07-05 17:26:59 +01001262 struct snd_soc_dapm_route routes[2];
Mark Brown5b2eec32012-07-04 17:32:05 +01001263
1264 switch (clk_id) {
1265 case ARIZONA_CLK_SYSCLK:
1266 case ARIZONA_CLK_ASYNCCLK:
1267 break;
1268 default:
1269 return -EINVAL;
1270 }
1271
Mark Brown410837a2012-07-05 17:26:59 +01001272 if (clk_id == dai_priv->clk)
1273 return 0;
1274
1275 if (dai->active) {
Mark Brown5b2eec32012-07-04 17:32:05 +01001276 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
1277 dai->id);
1278 return -EBUSY;
1279 }
1280
Mark Brownc8d35a62012-12-07 12:49:40 +09001281 dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1,
1282 arizona_dai_clk_str(clk_id));
1283
Mark Brown410837a2012-07-05 17:26:59 +01001284 memset(&routes, 0, sizeof(routes));
1285 routes[0].sink = dai->driver->capture.stream_name;
1286 routes[1].sink = dai->driver->playback.stream_name;
Mark Brown5b2eec32012-07-04 17:32:05 +01001287
Mark Brown410837a2012-07-05 17:26:59 +01001288 routes[0].source = arizona_dai_clk_str(dai_priv->clk);
1289 routes[1].source = arizona_dai_clk_str(dai_priv->clk);
1290 snd_soc_dapm_del_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
1291
1292 routes[0].source = arizona_dai_clk_str(clk_id);
1293 routes[1].source = arizona_dai_clk_str(clk_id);
1294 snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
1295
Mark Brown0c778e82012-12-06 18:22:25 +09001296 dai_priv->clk = clk_id;
1297
Mark Brown410837a2012-07-05 17:26:59 +01001298 return snd_soc_dapm_sync(&codec->dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +01001299}
1300
Mark Brown01df2592012-12-12 16:22:08 +09001301static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
1302{
1303 struct snd_soc_codec *codec = dai->codec;
1304 int base = dai->driver->base;
1305 unsigned int reg;
1306
1307 if (tristate)
1308 reg = ARIZONA_AIF1_TRI;
1309 else
1310 reg = 0;
1311
1312 return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1313 ARIZONA_AIF1_TRI, reg);
1314}
1315
Mark Brown07ed8732012-06-18 21:08:44 +01001316const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +01001317 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +01001318 .set_fmt = arizona_set_fmt,
1319 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +01001320 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown01df2592012-12-12 16:22:08 +09001321 .set_tristate = arizona_set_tristate,
Mark Brown07ed8732012-06-18 21:08:44 +01001322};
Mark Browna8379872012-07-09 12:16:41 +01001323EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +01001324
Mark Brownbd1dd882013-05-17 13:29:03 +01001325const struct snd_soc_dai_ops arizona_simple_dai_ops = {
1326 .startup = arizona_startup,
1327 .hw_params = arizona_hw_params_rate,
1328 .set_sysclk = arizona_dai_set_sysclk,
1329};
1330EXPORT_SYMBOL_GPL(arizona_simple_dai_ops);
1331
Mark Brown5b2eec32012-07-04 17:32:05 +01001332int arizona_init_dai(struct arizona_priv *priv, int id)
1333{
1334 struct arizona_dai_priv *dai_priv = &priv->dai[id];
1335
1336 dai_priv->clk = ARIZONA_CLK_SYSCLK;
1337
1338 return 0;
1339}
1340EXPORT_SYMBOL_GPL(arizona_init_dai);
1341
Mark Brown07ed8732012-06-18 21:08:44 +01001342static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
1343{
1344 struct arizona_fll *fll = data;
1345
1346 arizona_fll_dbg(fll, "clock OK\n");
1347
1348 complete(&fll->ok);
1349
1350 return IRQ_HANDLED;
1351}
1352
1353static struct {
1354 unsigned int min;
1355 unsigned int max;
1356 u16 fratio;
1357 int ratio;
1358} fll_fratios[] = {
1359 { 0, 64000, 4, 16 },
1360 { 64000, 128000, 3, 8 },
1361 { 128000, 256000, 2, 4 },
1362 { 256000, 1000000, 1, 2 },
1363 { 1000000, 13500000, 0, 1 },
1364};
1365
Mark Brown8f113d72013-03-05 12:08:57 +08001366static struct {
1367 unsigned int min;
1368 unsigned int max;
1369 u16 gain;
1370} fll_gains[] = {
1371 { 0, 256000, 0 },
1372 { 256000, 1000000, 2 },
1373 { 1000000, 13500000, 4 },
1374};
1375
Mark Brown07ed8732012-06-18 21:08:44 +01001376struct arizona_fll_cfg {
1377 int n;
1378 int theta;
1379 int lambda;
1380 int refdiv;
1381 int outdiv;
1382 int fratio;
Mark Brown8f113d72013-03-05 12:08:57 +08001383 int gain;
Mark Brown07ed8732012-06-18 21:08:44 +01001384};
1385
1386static int arizona_calc_fll(struct arizona_fll *fll,
1387 struct arizona_fll_cfg *cfg,
1388 unsigned int Fref,
1389 unsigned int Fout)
1390{
1391 unsigned int target, div, gcd_fll;
1392 int i, ratio;
1393
1394 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout);
1395
1396 /* Fref must be <=13.5MHz */
1397 div = 1;
1398 cfg->refdiv = 0;
Charles Keepax87383ac2014-03-07 16:34:18 +00001399 while ((Fref / div) > ARIZONA_FLL_MAX_FREF) {
Mark Brown07ed8732012-06-18 21:08:44 +01001400 div *= 2;
1401 cfg->refdiv++;
1402
Charles Keepax87383ac2014-03-07 16:34:18 +00001403 if (div > ARIZONA_FLL_MAX_REFDIV) {
Mark Brown07ed8732012-06-18 21:08:44 +01001404 arizona_fll_err(fll,
1405 "Can't scale %dMHz in to <=13.5MHz\n",
1406 Fref);
1407 return -EINVAL;
1408 }
1409 }
1410
1411 /* Apply the division for our remaining calculations */
1412 Fref /= div;
1413
Mark Brown2b4d39f2012-07-10 17:03:46 +01001414 /* Fvco should be over the targt; don't check the upper bound */
Charles Keepax87383ac2014-03-07 16:34:18 +00001415 div = ARIZONA_FLL_MIN_OUTDIV;
1416 while (Fout * div < ARIZONA_FLL_MIN_FVCO * fll->vco_mult) {
Mark Brown07ed8732012-06-18 21:08:44 +01001417 div++;
Charles Keepax87383ac2014-03-07 16:34:18 +00001418 if (div > ARIZONA_FLL_MAX_OUTDIV) {
Mark Brown07ed8732012-06-18 21:08:44 +01001419 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
1420 Fout);
1421 return -EINVAL;
1422 }
1423 }
Mark Brown2b4d39f2012-07-10 17:03:46 +01001424 target = Fout * div / fll->vco_mult;
Mark Brown07ed8732012-06-18 21:08:44 +01001425 cfg->outdiv = div;
1426
1427 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
1428
1429 /* Find an appropraite FLL_FRATIO and factor it out of the target */
1430 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
1431 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
1432 cfg->fratio = fll_fratios[i].fratio;
1433 ratio = fll_fratios[i].ratio;
1434 break;
1435 }
1436 }
1437 if (i == ARRAY_SIZE(fll_fratios)) {
1438 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
1439 Fref);
1440 return -EINVAL;
1441 }
1442
Mark Brown8f113d72013-03-05 12:08:57 +08001443 for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
1444 if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
1445 cfg->gain = fll_gains[i].gain;
1446 break;
1447 }
1448 }
1449 if (i == ARRAY_SIZE(fll_gains)) {
1450 arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
1451 Fref);
1452 return -EINVAL;
1453 }
1454
Mark Brown07ed8732012-06-18 21:08:44 +01001455 cfg->n = target / (ratio * Fref);
1456
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001457 if (target % (ratio * Fref)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001458 gcd_fll = gcd(target, ratio * Fref);
1459 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
1460
1461 cfg->theta = (target - (cfg->n * ratio * Fref))
1462 / gcd_fll;
1463 cfg->lambda = (ratio * Fref) / gcd_fll;
1464 } else {
1465 cfg->theta = 0;
1466 cfg->lambda = 0;
1467 }
1468
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001469 /* Round down to 16bit range with cost of accuracy lost.
1470 * Denominator must be bigger than numerator so we only
1471 * take care of it.
1472 */
1473 while (cfg->lambda >= (1 << 16)) {
1474 cfg->theta >>= 1;
1475 cfg->lambda >>= 1;
1476 }
1477
Mark Brown07ed8732012-06-18 21:08:44 +01001478 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
1479 cfg->n, cfg->theta, cfg->lambda);
1480 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
1481 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08001482 arizona_fll_dbg(fll, "GAIN=%d\n", cfg->gain);
Mark Brown07ed8732012-06-18 21:08:44 +01001483
1484 return 0;
1485
1486}
1487
1488static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
Mark Brown8f113d72013-03-05 12:08:57 +08001489 struct arizona_fll_cfg *cfg, int source,
1490 bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01001491{
Mark Brown3c43c692013-12-12 00:49:22 +00001492 regmap_update_bits_async(arizona->regmap, base + 3,
1493 ARIZONA_FLL1_THETA_MASK, cfg->theta);
1494 regmap_update_bits_async(arizona->regmap, base + 4,
1495 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
1496 regmap_update_bits_async(arizona->regmap, base + 5,
1497 ARIZONA_FLL1_FRATIO_MASK,
1498 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
1499 regmap_update_bits_async(arizona->regmap, base + 6,
1500 ARIZONA_FLL1_CLK_REF_DIV_MASK |
1501 ARIZONA_FLL1_CLK_REF_SRC_MASK,
1502 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
1503 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
Mark Brown07ed8732012-06-18 21:08:44 +01001504
Mark Brown8f113d72013-03-05 12:08:57 +08001505 if (sync)
Mark Brown3c43c692013-12-12 00:49:22 +00001506 regmap_update_bits_async(arizona->regmap, base + 0x7,
1507 ARIZONA_FLL1_GAIN_MASK,
1508 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
Mark Brown8f113d72013-03-05 12:08:57 +08001509 else
Mark Brown3c43c692013-12-12 00:49:22 +00001510 regmap_update_bits_async(arizona->regmap, base + 0x9,
1511 ARIZONA_FLL1_GAIN_MASK,
1512 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
Mark Brown8f113d72013-03-05 12:08:57 +08001513
Mark Brown3c43c692013-12-12 00:49:22 +00001514 regmap_update_bits_async(arizona->regmap, base + 2,
1515 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
1516 ARIZONA_FLL1_CTRL_UPD | cfg->n);
Mark Brown07ed8732012-06-18 21:08:44 +01001517}
1518
Charles Keepaxd122d6c2013-02-20 17:28:36 +00001519static bool arizona_is_enabled_fll(struct arizona_fll *fll)
1520{
1521 struct arizona *arizona = fll->arizona;
1522 unsigned int reg;
1523 int ret;
1524
1525 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
1526 if (ret != 0) {
1527 arizona_fll_err(fll, "Failed to read current state: %d\n",
1528 ret);
1529 return ret;
1530 }
1531
1532 return reg & ARIZONA_FLL1_ENA;
1533}
1534
Charles Keepax35722812013-02-20 17:28:38 +00001535static void arizona_enable_fll(struct arizona_fll *fll,
1536 struct arizona_fll_cfg *ref,
1537 struct arizona_fll_cfg *sync)
1538{
1539 struct arizona *arizona = fll->arizona;
1540 int ret;
Charles Keepax49c60542013-09-16 15:34:35 +01001541 bool use_sync = false;
Charles Keepax35722812013-02-20 17:28:38 +00001542
Mark Brownff680a12013-03-04 16:00:19 +08001543 /*
1544 * If we have both REFCLK and SYNCCLK then enable both,
1545 * otherwise apply the SYNCCLK settings to REFCLK.
1546 */
Charles Keepax49c60542013-09-16 15:34:35 +01001547 if (fll->ref_src >= 0 && fll->ref_freq &&
1548 fll->ref_src != fll->sync_src) {
Mark Brown3c43c692013-12-12 00:49:22 +00001549 regmap_update_bits_async(arizona->regmap, fll->base + 5,
1550 ARIZONA_FLL1_OUTDIV_MASK,
1551 ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
Charles Keepax35722812013-02-20 17:28:38 +00001552
Mark Brown8f113d72013-03-05 12:08:57 +08001553 arizona_apply_fll(arizona, fll->base, ref, fll->ref_src,
1554 false);
Charles Keepax49c60542013-09-16 15:34:35 +01001555 if (fll->sync_src >= 0) {
Mark Brownff680a12013-03-04 16:00:19 +08001556 arizona_apply_fll(arizona, fll->base + 0x10, sync,
Mark Brown8f113d72013-03-05 12:08:57 +08001557 fll->sync_src, true);
Charles Keepax49c60542013-09-16 15:34:35 +01001558 use_sync = true;
1559 }
Mark Brownff680a12013-03-04 16:00:19 +08001560 } else if (fll->sync_src >= 0) {
Mark Brown3c43c692013-12-12 00:49:22 +00001561 regmap_update_bits_async(arizona->regmap, fll->base + 5,
1562 ARIZONA_FLL1_OUTDIV_MASK,
1563 sync->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
Mark Brownff680a12013-03-04 16:00:19 +08001564
1565 arizona_apply_fll(arizona, fll->base, sync,
Mark Brown8f113d72013-03-05 12:08:57 +08001566 fll->sync_src, false);
Mark Browneca2e8e2013-03-06 00:09:59 +08001567
Mark Brown3c43c692013-12-12 00:49:22 +00001568 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
1569 ARIZONA_FLL1_SYNC_ENA, 0);
Mark Brownff680a12013-03-04 16:00:19 +08001570 } else {
1571 arizona_fll_err(fll, "No clocks provided\n");
1572 return;
1573 }
Charles Keepax35722812013-02-20 17:28:38 +00001574
Mark Brown576411be2013-03-05 12:07:16 +08001575 /*
1576 * Increase the bandwidth if we're not using a low frequency
1577 * sync source.
1578 */
Charles Keepax49c60542013-09-16 15:34:35 +01001579 if (use_sync && fll->sync_freq > 100000)
Mark Brown3c43c692013-12-12 00:49:22 +00001580 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
1581 ARIZONA_FLL1_SYNC_BW, 0);
Mark Brown576411be2013-03-05 12:07:16 +08001582 else
Mark Brown3c43c692013-12-12 00:49:22 +00001583 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
1584 ARIZONA_FLL1_SYNC_BW,
1585 ARIZONA_FLL1_SYNC_BW);
Mark Brown576411be2013-03-05 12:07:16 +08001586
Charles Keepax35722812013-02-20 17:28:38 +00001587 if (!arizona_is_enabled_fll(fll))
1588 pm_runtime_get(arizona->dev);
1589
1590 /* Clear any pending completions */
1591 try_wait_for_completion(&fll->ok);
1592
Mark Brown3c43c692013-12-12 00:49:22 +00001593 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1594 ARIZONA_FLL1_FREERUN, 0);
1595 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1596 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
Charles Keepax49c60542013-09-16 15:34:35 +01001597 if (use_sync)
Mark Brown3c43c692013-12-12 00:49:22 +00001598 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
1599 ARIZONA_FLL1_SYNC_ENA,
1600 ARIZONA_FLL1_SYNC_ENA);
Charles Keepax35722812013-02-20 17:28:38 +00001601
1602 ret = wait_for_completion_timeout(&fll->ok,
1603 msecs_to_jiffies(250));
1604 if (ret == 0)
1605 arizona_fll_warn(fll, "Timed out waiting for lock\n");
1606}
1607
Charles Keepax76040542013-02-20 17:28:37 +00001608static void arizona_disable_fll(struct arizona_fll *fll)
1609{
1610 struct arizona *arizona = fll->arizona;
1611 bool change;
1612
Mark Brown3c43c692013-12-12 00:49:22 +00001613 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1614 ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
Charles Keepax76040542013-02-20 17:28:37 +00001615 regmap_update_bits_check(arizona->regmap, fll->base + 1,
1616 ARIZONA_FLL1_ENA, 0, &change);
1617 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1618 ARIZONA_FLL1_SYNC_ENA, 0);
1619
1620 if (change)
1621 pm_runtime_put_autosuspend(arizona->dev);
1622}
1623
Charles Keepaxee929a92013-02-20 17:28:40 +00001624int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
1625 unsigned int Fref, unsigned int Fout)
1626{
1627 struct arizona_fll_cfg ref, sync;
1628 int ret;
1629
Charles Keepax1c5617f2013-02-22 17:10:37 +00001630 if (fll->ref_src == source && fll->ref_freq == Fref)
Charles Keepaxee929a92013-02-20 17:28:40 +00001631 return 0;
1632
Charles Keepax49c60542013-09-16 15:34:35 +01001633 if (fll->fout) {
1634 if (Fref > 0) {
1635 ret = arizona_calc_fll(fll, &ref, Fref, fll->fout);
1636 if (ret != 0)
1637 return ret;
1638 }
Charles Keepaxee929a92013-02-20 17:28:40 +00001639
1640 if (fll->sync_src >= 0) {
Charles Keepax1c5617f2013-02-22 17:10:37 +00001641 ret = arizona_calc_fll(fll, &sync, fll->sync_freq,
1642 fll->fout);
Charles Keepaxee929a92013-02-20 17:28:40 +00001643 if (ret != 0)
1644 return ret;
1645 }
1646 }
1647
1648 fll->ref_src = source;
1649 fll->ref_freq = Fref;
Charles Keepaxee929a92013-02-20 17:28:40 +00001650
Mark Brown86cd6842013-03-07 16:14:04 +08001651 if (fll->fout && Fref > 0) {
Charles Keepaxee929a92013-02-20 17:28:40 +00001652 arizona_enable_fll(fll, &ref, &sync);
Charles Keepaxee929a92013-02-20 17:28:40 +00001653 }
1654
1655 return 0;
1656}
1657EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
1658
Mark Brown07ed8732012-06-18 21:08:44 +01001659int arizona_set_fll(struct arizona_fll *fll, int source,
1660 unsigned int Fref, unsigned int Fout)
1661{
Charles Keepax9e359c62013-02-20 17:28:35 +00001662 struct arizona_fll_cfg ref, sync;
Mark Brown07ed8732012-06-18 21:08:44 +01001663 int ret;
1664
Mark Brownff680a12013-03-04 16:00:19 +08001665 if (fll->sync_src == source &&
1666 fll->sync_freq == Fref && fll->fout == Fout)
1667 return 0;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00001668
Mark Brownff680a12013-03-04 16:00:19 +08001669 if (Fout) {
1670 if (fll->ref_src >= 0) {
1671 ret = arizona_calc_fll(fll, &ref, fll->ref_freq,
1672 Fout);
Charles Keepax9e359c62013-02-20 17:28:35 +00001673 if (ret != 0)
1674 return ret;
1675 }
1676
Mark Brownff680a12013-03-04 16:00:19 +08001677 ret = arizona_calc_fll(fll, &sync, Fref, Fout);
1678 if (ret != 0)
1679 return ret;
Charles Keepax9e359c62013-02-20 17:28:35 +00001680 }
Mark Brownff680a12013-03-04 16:00:19 +08001681
1682 fll->sync_src = source;
1683 fll->sync_freq = Fref;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00001684 fll->fout = Fout;
Charles Keepax9e359c62013-02-20 17:28:35 +00001685
Mark Brown07ed8732012-06-18 21:08:44 +01001686 if (Fout) {
Charles Keepax35722812013-02-20 17:28:38 +00001687 arizona_enable_fll(fll, &ref, &sync);
Mark Brown07ed8732012-06-18 21:08:44 +01001688 } else {
Charles Keepax76040542013-02-20 17:28:37 +00001689 arizona_disable_fll(fll);
Mark Brown07ed8732012-06-18 21:08:44 +01001690 }
1691
Mark Brown07ed8732012-06-18 21:08:44 +01001692 return 0;
1693}
1694EXPORT_SYMBOL_GPL(arizona_set_fll);
1695
1696int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
1697 int ok_irq, struct arizona_fll *fll)
1698{
1699 int ret;
Charles Keepax19b34bd2013-02-20 17:28:34 +00001700 unsigned int val;
Mark Brown07ed8732012-06-18 21:08:44 +01001701
Mark Brown07ed8732012-06-18 21:08:44 +01001702 init_completion(&fll->ok);
1703
1704 fll->id = id;
1705 fll->base = base;
1706 fll->arizona = arizona;
Charles Keepaxf3f11632013-02-20 17:28:41 +00001707 fll->sync_src = ARIZONA_FLL_SRC_NONE;
Mark Brown07ed8732012-06-18 21:08:44 +01001708
Charles Keepax19b34bd2013-02-20 17:28:34 +00001709 /* Configure default refclk to 32kHz if we have one */
1710 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
1711 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
1712 case ARIZONA_CLK_SRC_MCLK1:
1713 case ARIZONA_CLK_SRC_MCLK2:
1714 fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK;
1715 break;
1716 default:
Charles Keepaxf3f11632013-02-20 17:28:41 +00001717 fll->ref_src = ARIZONA_FLL_SRC_NONE;
Charles Keepax19b34bd2013-02-20 17:28:34 +00001718 }
1719 fll->ref_freq = 32768;
1720
Mark Brown07ed8732012-06-18 21:08:44 +01001721 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
1722 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
1723 "FLL%d clock OK", id);
1724
Mark Brown07ed8732012-06-18 21:08:44 +01001725 ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
1726 arizona_fll_clock_ok, fll);
1727 if (ret != 0) {
1728 dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
1729 id, ret);
1730 }
1731
Charles Keepaxe31c1942013-01-07 16:41:45 +00001732 regmap_update_bits(arizona->regmap, fll->base + 1,
1733 ARIZONA_FLL1_FREERUN, 0);
1734
Mark Brown07ed8732012-06-18 21:08:44 +01001735 return 0;
1736}
1737EXPORT_SYMBOL_GPL(arizona_init_fll);
1738
Mark Brownbc9ab6d2013-01-04 19:31:00 +00001739/**
1740 * arizona_set_output_mode - Set the mode of the specified output
1741 *
1742 * @codec: Device to configure
1743 * @output: Output number
1744 * @diff: True to set the output to differential mode
1745 *
1746 * Some systems use external analogue switches to connect more
1747 * analogue devices to the CODEC than are supported by the device. In
1748 * some systems this requires changing the switched output from single
1749 * ended to differential mode dynamically at runtime, an operation
1750 * supported using this function.
1751 *
1752 * Most systems have a single static configuration and should use
1753 * platform data instead.
1754 */
1755int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
1756{
1757 unsigned int reg, val;
1758
1759 if (output < 1 || output > 6)
1760 return -EINVAL;
1761
1762 reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
1763
1764 if (diff)
1765 val = ARIZONA_OUT1_MONO;
1766 else
1767 val = 0;
1768
1769 return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val);
1770}
1771EXPORT_SYMBOL_GPL(arizona_set_output_mode);
1772
Mark Brown07ed8732012-06-18 21:08:44 +01001773MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
1774MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1775MODULE_LICENSE("GPL");