blob: 1f106abf1bb0b76751f20b8c01aad079c0f06d60 [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
Charles Keepax23f785a82014-03-07 16:34:20 +00001386static int arizona_validate_fll(struct arizona_fll *fll,
1387 unsigned int Fref,
1388 unsigned int Fout)
1389{
1390 unsigned int Fvco_min;
1391
1392 if (Fref / ARIZONA_FLL_MAX_REFDIV > ARIZONA_FLL_MAX_FREF) {
1393 arizona_fll_err(fll,
1394 "Can't scale %dMHz in to <=13.5MHz\n",
1395 Fref);
1396 return -EINVAL;
1397 }
1398
1399 Fvco_min = ARIZONA_FLL_MIN_FVCO * fll->vco_mult;
1400 if (Fout * ARIZONA_FLL_MAX_OUTDIV < Fvco_min) {
1401 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
1402 Fout);
1403 return -EINVAL;
1404 }
1405
1406 return 0;
1407}
1408
Mark Brown07ed8732012-06-18 21:08:44 +01001409static int arizona_calc_fll(struct arizona_fll *fll,
1410 struct arizona_fll_cfg *cfg,
Charles Keepax8ccefcd2014-03-07 16:34:21 +00001411 unsigned int Fref)
Mark Brown07ed8732012-06-18 21:08:44 +01001412{
1413 unsigned int target, div, gcd_fll;
1414 int i, ratio;
1415
Charles Keepax8ccefcd2014-03-07 16:34:21 +00001416 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, fll->fout);
Mark Brown07ed8732012-06-18 21:08:44 +01001417
Charles Keepaxf641aec2014-03-07 16:34:22 +00001418 /* Fvco should be over the targt; don't check the upper bound */
1419 div = ARIZONA_FLL_MIN_OUTDIV;
1420 while (fll->fout * div < ARIZONA_FLL_MIN_FVCO * fll->vco_mult) {
1421 div++;
1422 if (div > ARIZONA_FLL_MAX_OUTDIV)
1423 return -EINVAL;
1424 }
1425 target = fll->fout * div / fll->vco_mult;
1426 cfg->outdiv = div;
1427
1428 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
1429
Mark Brown07ed8732012-06-18 21:08:44 +01001430 /* Fref must be <=13.5MHz */
1431 div = 1;
1432 cfg->refdiv = 0;
Charles Keepax87383ac2014-03-07 16:34:18 +00001433 while ((Fref / div) > ARIZONA_FLL_MAX_FREF) {
Mark Brown07ed8732012-06-18 21:08:44 +01001434 div *= 2;
1435 cfg->refdiv++;
1436
Charles Keepax23f785a82014-03-07 16:34:20 +00001437 if (div > ARIZONA_FLL_MAX_REFDIV)
Mark Brown07ed8732012-06-18 21:08:44 +01001438 return -EINVAL;
Mark Brown07ed8732012-06-18 21:08:44 +01001439 }
1440
1441 /* Apply the division for our remaining calculations */
1442 Fref /= div;
1443
Mark Brown07ed8732012-06-18 21:08:44 +01001444 /* Find an appropraite FLL_FRATIO and factor it out of the target */
1445 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
1446 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
1447 cfg->fratio = fll_fratios[i].fratio;
1448 ratio = fll_fratios[i].ratio;
1449 break;
1450 }
1451 }
1452 if (i == ARRAY_SIZE(fll_fratios)) {
1453 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
1454 Fref);
1455 return -EINVAL;
1456 }
1457
Mark Brown8f113d72013-03-05 12:08:57 +08001458 for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
1459 if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
1460 cfg->gain = fll_gains[i].gain;
1461 break;
1462 }
1463 }
1464 if (i == ARRAY_SIZE(fll_gains)) {
1465 arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
1466 Fref);
1467 return -EINVAL;
1468 }
1469
Mark Brown07ed8732012-06-18 21:08:44 +01001470 cfg->n = target / (ratio * Fref);
1471
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001472 if (target % (ratio * Fref)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001473 gcd_fll = gcd(target, ratio * Fref);
1474 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
1475
1476 cfg->theta = (target - (cfg->n * ratio * Fref))
1477 / gcd_fll;
1478 cfg->lambda = (ratio * Fref) / gcd_fll;
1479 } else {
1480 cfg->theta = 0;
1481 cfg->lambda = 0;
1482 }
1483
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001484 /* Round down to 16bit range with cost of accuracy lost.
1485 * Denominator must be bigger than numerator so we only
1486 * take care of it.
1487 */
1488 while (cfg->lambda >= (1 << 16)) {
1489 cfg->theta >>= 1;
1490 cfg->lambda >>= 1;
1491 }
1492
Mark Brown07ed8732012-06-18 21:08:44 +01001493 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
1494 cfg->n, cfg->theta, cfg->lambda);
1495 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
1496 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08001497 arizona_fll_dbg(fll, "GAIN=%d\n", cfg->gain);
Mark Brown07ed8732012-06-18 21:08:44 +01001498
1499 return 0;
1500
1501}
1502
1503static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
Mark Brown8f113d72013-03-05 12:08:57 +08001504 struct arizona_fll_cfg *cfg, int source,
1505 bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01001506{
Mark Brown3c43c692013-12-12 00:49:22 +00001507 regmap_update_bits_async(arizona->regmap, base + 3,
1508 ARIZONA_FLL1_THETA_MASK, cfg->theta);
1509 regmap_update_bits_async(arizona->regmap, base + 4,
1510 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
1511 regmap_update_bits_async(arizona->regmap, base + 5,
1512 ARIZONA_FLL1_FRATIO_MASK,
1513 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
1514 regmap_update_bits_async(arizona->regmap, base + 6,
1515 ARIZONA_FLL1_CLK_REF_DIV_MASK |
1516 ARIZONA_FLL1_CLK_REF_SRC_MASK,
1517 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
1518 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
Mark Brown07ed8732012-06-18 21:08:44 +01001519
Charles Keepax61719db2014-03-07 16:34:19 +00001520 if (sync) {
1521 regmap_update_bits(arizona->regmap, base + 0x7,
1522 ARIZONA_FLL1_GAIN_MASK,
1523 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
1524 } else {
1525 regmap_update_bits(arizona->regmap, base + 0x5,
1526 ARIZONA_FLL1_OUTDIV_MASK,
1527 cfg->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
1528 regmap_update_bits(arizona->regmap, base + 0x9,
1529 ARIZONA_FLL1_GAIN_MASK,
1530 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
1531 }
Mark Brown8f113d72013-03-05 12:08:57 +08001532
Mark Brown3c43c692013-12-12 00:49:22 +00001533 regmap_update_bits_async(arizona->regmap, base + 2,
1534 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
1535 ARIZONA_FLL1_CTRL_UPD | cfg->n);
Mark Brown07ed8732012-06-18 21:08:44 +01001536}
1537
Charles Keepaxd122d6c2013-02-20 17:28:36 +00001538static bool arizona_is_enabled_fll(struct arizona_fll *fll)
1539{
1540 struct arizona *arizona = fll->arizona;
1541 unsigned int reg;
1542 int ret;
1543
1544 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
1545 if (ret != 0) {
1546 arizona_fll_err(fll, "Failed to read current state: %d\n",
1547 ret);
1548 return ret;
1549 }
1550
1551 return reg & ARIZONA_FLL1_ENA;
1552}
1553
Charles Keepax23f785a82014-03-07 16:34:20 +00001554static void arizona_enable_fll(struct arizona_fll *fll)
Charles Keepax35722812013-02-20 17:28:38 +00001555{
1556 struct arizona *arizona = fll->arizona;
1557 int ret;
Charles Keepax49c60542013-09-16 15:34:35 +01001558 bool use_sync = false;
Charles Keepax23f785a82014-03-07 16:34:20 +00001559 struct arizona_fll_cfg cfg;
Charles Keepax35722812013-02-20 17:28:38 +00001560
Mark Brownff680a12013-03-04 16:00:19 +08001561 /*
1562 * If we have both REFCLK and SYNCCLK then enable both,
1563 * otherwise apply the SYNCCLK settings to REFCLK.
1564 */
Charles Keepax49c60542013-09-16 15:34:35 +01001565 if (fll->ref_src >= 0 && fll->ref_freq &&
1566 fll->ref_src != fll->sync_src) {
Charles Keepax8ccefcd2014-03-07 16:34:21 +00001567 arizona_calc_fll(fll, &cfg, fll->ref_freq);
Charles Keepax23f785a82014-03-07 16:34:20 +00001568
1569 arizona_apply_fll(arizona, fll->base, &cfg, fll->ref_src,
Mark Brown8f113d72013-03-05 12:08:57 +08001570 false);
Charles Keepax49c60542013-09-16 15:34:35 +01001571 if (fll->sync_src >= 0) {
Charles Keepax8ccefcd2014-03-07 16:34:21 +00001572 arizona_calc_fll(fll, &cfg, fll->sync_freq);
Charles Keepax23f785a82014-03-07 16:34:20 +00001573
1574 arizona_apply_fll(arizona, fll->base + 0x10, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08001575 fll->sync_src, true);
Charles Keepax49c60542013-09-16 15:34:35 +01001576 use_sync = true;
1577 }
Mark Brownff680a12013-03-04 16:00:19 +08001578 } else if (fll->sync_src >= 0) {
Charles Keepax8ccefcd2014-03-07 16:34:21 +00001579 arizona_calc_fll(fll, &cfg, fll->sync_freq);
Charles Keepax23f785a82014-03-07 16:34:20 +00001580
1581 arizona_apply_fll(arizona, fll->base, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08001582 fll->sync_src, false);
Mark Browneca2e8e2013-03-06 00:09:59 +08001583
Mark Brown3c43c692013-12-12 00:49:22 +00001584 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
1585 ARIZONA_FLL1_SYNC_ENA, 0);
Mark Brownff680a12013-03-04 16:00:19 +08001586 } else {
1587 arizona_fll_err(fll, "No clocks provided\n");
1588 return;
1589 }
Charles Keepax35722812013-02-20 17:28:38 +00001590
Mark Brown576411be2013-03-05 12:07:16 +08001591 /*
1592 * Increase the bandwidth if we're not using a low frequency
1593 * sync source.
1594 */
Charles Keepax49c60542013-09-16 15:34:35 +01001595 if (use_sync && fll->sync_freq > 100000)
Mark Brown3c43c692013-12-12 00:49:22 +00001596 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
1597 ARIZONA_FLL1_SYNC_BW, 0);
Mark Brown576411be2013-03-05 12:07:16 +08001598 else
Mark Brown3c43c692013-12-12 00:49:22 +00001599 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
1600 ARIZONA_FLL1_SYNC_BW,
1601 ARIZONA_FLL1_SYNC_BW);
Mark Brown576411be2013-03-05 12:07:16 +08001602
Charles Keepax35722812013-02-20 17:28:38 +00001603 if (!arizona_is_enabled_fll(fll))
1604 pm_runtime_get(arizona->dev);
1605
1606 /* Clear any pending completions */
1607 try_wait_for_completion(&fll->ok);
1608
Mark Brown3c43c692013-12-12 00:49:22 +00001609 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1610 ARIZONA_FLL1_FREERUN, 0);
1611 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1612 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
Charles Keepax49c60542013-09-16 15:34:35 +01001613 if (use_sync)
Mark Brown3c43c692013-12-12 00:49:22 +00001614 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
1615 ARIZONA_FLL1_SYNC_ENA,
1616 ARIZONA_FLL1_SYNC_ENA);
Charles Keepax35722812013-02-20 17:28:38 +00001617
1618 ret = wait_for_completion_timeout(&fll->ok,
1619 msecs_to_jiffies(250));
1620 if (ret == 0)
1621 arizona_fll_warn(fll, "Timed out waiting for lock\n");
1622}
1623
Charles Keepax76040542013-02-20 17:28:37 +00001624static void arizona_disable_fll(struct arizona_fll *fll)
1625{
1626 struct arizona *arizona = fll->arizona;
1627 bool change;
1628
Mark Brown3c43c692013-12-12 00:49:22 +00001629 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1630 ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
Charles Keepax76040542013-02-20 17:28:37 +00001631 regmap_update_bits_check(arizona->regmap, fll->base + 1,
1632 ARIZONA_FLL1_ENA, 0, &change);
1633 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1634 ARIZONA_FLL1_SYNC_ENA, 0);
1635
1636 if (change)
1637 pm_runtime_put_autosuspend(arizona->dev);
1638}
1639
Charles Keepaxee929a92013-02-20 17:28:40 +00001640int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
1641 unsigned int Fref, unsigned int Fout)
1642{
Charles Keepaxee929a92013-02-20 17:28:40 +00001643 int ret;
1644
Charles Keepax1c5617f2013-02-22 17:10:37 +00001645 if (fll->ref_src == source && fll->ref_freq == Fref)
Charles Keepaxee929a92013-02-20 17:28:40 +00001646 return 0;
1647
Charles Keepax23f785a82014-03-07 16:34:20 +00001648 if (fll->fout && Fref > 0) {
1649 ret = arizona_validate_fll(fll, Fref, fll->fout);
1650 if (ret != 0)
1651 return ret;
Charles Keepaxee929a92013-02-20 17:28:40 +00001652 }
1653
1654 fll->ref_src = source;
1655 fll->ref_freq = Fref;
Charles Keepaxee929a92013-02-20 17:28:40 +00001656
Mark Brown86cd6842013-03-07 16:14:04 +08001657 if (fll->fout && Fref > 0) {
Charles Keepax23f785a82014-03-07 16:34:20 +00001658 arizona_enable_fll(fll);
Charles Keepaxee929a92013-02-20 17:28:40 +00001659 }
1660
1661 return 0;
1662}
1663EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
1664
Mark Brown07ed8732012-06-18 21:08:44 +01001665int arizona_set_fll(struct arizona_fll *fll, int source,
1666 unsigned int Fref, unsigned int Fout)
1667{
Mark Brown07ed8732012-06-18 21:08:44 +01001668 int ret;
1669
Mark Brownff680a12013-03-04 16:00:19 +08001670 if (fll->sync_src == source &&
1671 fll->sync_freq == Fref && fll->fout == Fout)
1672 return 0;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00001673
Mark Brownff680a12013-03-04 16:00:19 +08001674 if (Fout) {
1675 if (fll->ref_src >= 0) {
Charles Keepax23f785a82014-03-07 16:34:20 +00001676 ret = arizona_validate_fll(fll, fll->ref_freq, Fout);
Charles Keepax9e359c62013-02-20 17:28:35 +00001677 if (ret != 0)
1678 return ret;
1679 }
1680
Charles Keepax23f785a82014-03-07 16:34:20 +00001681 ret = arizona_validate_fll(fll, Fref, Fout);
Mark Brownff680a12013-03-04 16:00:19 +08001682 if (ret != 0)
1683 return ret;
Charles Keepax9e359c62013-02-20 17:28:35 +00001684 }
Mark Brownff680a12013-03-04 16:00:19 +08001685
1686 fll->sync_src = source;
1687 fll->sync_freq = Fref;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00001688 fll->fout = Fout;
Charles Keepax9e359c62013-02-20 17:28:35 +00001689
Mark Brown07ed8732012-06-18 21:08:44 +01001690 if (Fout) {
Charles Keepax23f785a82014-03-07 16:34:20 +00001691 arizona_enable_fll(fll);
Mark Brown07ed8732012-06-18 21:08:44 +01001692 } else {
Charles Keepax76040542013-02-20 17:28:37 +00001693 arizona_disable_fll(fll);
Mark Brown07ed8732012-06-18 21:08:44 +01001694 }
1695
Mark Brown07ed8732012-06-18 21:08:44 +01001696 return 0;
1697}
1698EXPORT_SYMBOL_GPL(arizona_set_fll);
1699
1700int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
1701 int ok_irq, struct arizona_fll *fll)
1702{
1703 int ret;
Charles Keepax19b34bd2013-02-20 17:28:34 +00001704 unsigned int val;
Mark Brown07ed8732012-06-18 21:08:44 +01001705
Mark Brown07ed8732012-06-18 21:08:44 +01001706 init_completion(&fll->ok);
1707
1708 fll->id = id;
1709 fll->base = base;
1710 fll->arizona = arizona;
Charles Keepaxf3f11632013-02-20 17:28:41 +00001711 fll->sync_src = ARIZONA_FLL_SRC_NONE;
Mark Brown07ed8732012-06-18 21:08:44 +01001712
Charles Keepax19b34bd2013-02-20 17:28:34 +00001713 /* Configure default refclk to 32kHz if we have one */
1714 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
1715 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
1716 case ARIZONA_CLK_SRC_MCLK1:
1717 case ARIZONA_CLK_SRC_MCLK2:
1718 fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK;
1719 break;
1720 default:
Charles Keepaxf3f11632013-02-20 17:28:41 +00001721 fll->ref_src = ARIZONA_FLL_SRC_NONE;
Charles Keepax19b34bd2013-02-20 17:28:34 +00001722 }
1723 fll->ref_freq = 32768;
1724
Mark Brown07ed8732012-06-18 21:08:44 +01001725 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
1726 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
1727 "FLL%d clock OK", id);
1728
Mark Brown07ed8732012-06-18 21:08:44 +01001729 ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
1730 arizona_fll_clock_ok, fll);
1731 if (ret != 0) {
1732 dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
1733 id, ret);
1734 }
1735
Charles Keepaxe31c1942013-01-07 16:41:45 +00001736 regmap_update_bits(arizona->regmap, fll->base + 1,
1737 ARIZONA_FLL1_FREERUN, 0);
1738
Mark Brown07ed8732012-06-18 21:08:44 +01001739 return 0;
1740}
1741EXPORT_SYMBOL_GPL(arizona_init_fll);
1742
Mark Brownbc9ab6d2013-01-04 19:31:00 +00001743/**
1744 * arizona_set_output_mode - Set the mode of the specified output
1745 *
1746 * @codec: Device to configure
1747 * @output: Output number
1748 * @diff: True to set the output to differential mode
1749 *
1750 * Some systems use external analogue switches to connect more
1751 * analogue devices to the CODEC than are supported by the device. In
1752 * some systems this requires changing the switched output from single
1753 * ended to differential mode dynamically at runtime, an operation
1754 * supported using this function.
1755 *
1756 * Most systems have a single static configuration and should use
1757 * platform data instead.
1758 */
1759int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
1760{
1761 unsigned int reg, val;
1762
1763 if (output < 1 || output > 6)
1764 return -EINVAL;
1765
1766 reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
1767
1768 if (diff)
1769 val = ARIZONA_OUT1_MONO;
1770 else
1771 val = 0;
1772
1773 return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val);
1774}
1775EXPORT_SYMBOL_GPL(arizona_set_output_mode);
1776
Mark Brown07ed8732012-06-18 21:08:44 +01001777MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
1778MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1779MODULE_LICENSE("GPL");