blob: 32bc609f23e44bcaf7d3c299e7f625d9953154a9 [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 Keepaxd0800342014-03-07 16:34:25 +000056#define ARIZONA_FLL_VCO_CORNER 141900000
Charles Keepax87383ac2014-03-07 16:34:18 +000057#define ARIZONA_FLL_MAX_FREF 13500000
58#define ARIZONA_FLL_MIN_FVCO 90000000
Charles Keepaxd0800342014-03-07 16:34:25 +000059#define ARIZONA_FLL_MAX_FRATIO 16
Charles Keepax87383ac2014-03-07 16:34:18 +000060#define ARIZONA_FLL_MAX_REFDIV 8
61#define ARIZONA_FLL_MIN_OUTDIV 2
62#define ARIZONA_FLL_MAX_OUTDIV 7
63
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +000064#define ARIZONA_FMT_DSP_MODE_A 0
65#define ARIZONA_FMT_DSP_MODE_B 1
66#define ARIZONA_FMT_I2S_MODE 2
67#define ARIZONA_FMT_LEFT_JUSTIFIED_MODE 3
68
Mark Brown07ed8732012-06-18 21:08:44 +010069#define arizona_fll_err(_fll, fmt, ...) \
70 dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
71#define arizona_fll_warn(_fll, fmt, ...) \
72 dev_warn(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
73#define arizona_fll_dbg(_fll, fmt, ...) \
Mark Brown9092a6e2013-02-06 17:58:57 +000074 dev_dbg(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
Mark Brown07ed8732012-06-18 21:08:44 +010075
76#define arizona_aif_err(_dai, fmt, ...) \
77 dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
78#define arizona_aif_warn(_dai, fmt, ...) \
79 dev_warn(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
80#define arizona_aif_dbg(_dai, fmt, ...) \
Mark Brown9092a6e2013-02-06 17:58:57 +000081 dev_dbg(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
Mark Brown07ed8732012-06-18 21:08:44 +010082
Mark Brown56447e12013-01-10 14:45:58 +000083static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
84 struct snd_kcontrol *kcontrol,
85 int event)
86{
87 struct snd_soc_codec *codec = w->codec;
88 struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
89 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
90 bool manual_ena = false;
Mark Brownf4a76e72013-03-13 12:22:39 +000091 int val;
Mark Brown56447e12013-01-10 14:45:58 +000092
93 switch (arizona->type) {
94 case WM5102:
95 switch (arizona->rev) {
96 case 0:
97 break;
98 default:
99 manual_ena = true;
100 break;
101 }
102 default:
103 break;
104 }
105
106 switch (event) {
107 case SND_SOC_DAPM_PRE_PMU:
108 if (!priv->spk_ena && manual_ena) {
Mark Brown3c43c692013-12-12 00:49:22 +0000109 regmap_write_async(arizona->regmap, 0x4f5, 0x25a);
Mark Brown56447e12013-01-10 14:45:58 +0000110 priv->spk_ena_pending = true;
111 }
112 break;
113 case SND_SOC_DAPM_POST_PMU:
Mark Brownf4a76e72013-03-13 12:22:39 +0000114 val = snd_soc_read(codec, ARIZONA_INTERRUPT_RAW_STATUS_3);
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100115 if (val & ARIZONA_SPK_OVERHEAT_STS) {
Mark Brownf4a76e72013-03-13 12:22:39 +0000116 dev_crit(arizona->dev,
117 "Speaker not enabled due to temperature\n");
118 return -EBUSY;
119 }
120
Mark Brown3c43c692013-12-12 00:49:22 +0000121 regmap_update_bits_async(arizona->regmap,
122 ARIZONA_OUTPUT_ENABLES_1,
123 1 << w->shift, 1 << w->shift);
Mark Brownf4a76e72013-03-13 12:22:39 +0000124
Mark Brown56447e12013-01-10 14:45:58 +0000125 if (priv->spk_ena_pending) {
126 msleep(75);
Mark Brown3c43c692013-12-12 00:49:22 +0000127 regmap_write_async(arizona->regmap, 0x4f5, 0xda);
Mark Brown56447e12013-01-10 14:45:58 +0000128 priv->spk_ena_pending = false;
129 priv->spk_ena++;
130 }
131 break;
132 case SND_SOC_DAPM_PRE_PMD:
133 if (manual_ena) {
134 priv->spk_ena--;
135 if (!priv->spk_ena)
Mark Brown3c43c692013-12-12 00:49:22 +0000136 regmap_write_async(arizona->regmap,
137 0x4f5, 0x25a);
Mark Brown56447e12013-01-10 14:45:58 +0000138 }
Mark Brownf4a76e72013-03-13 12:22:39 +0000139
Mark Brown3c43c692013-12-12 00:49:22 +0000140 regmap_update_bits_async(arizona->regmap,
141 ARIZONA_OUTPUT_ENABLES_1,
142 1 << w->shift, 0);
Mark Brown56447e12013-01-10 14:45:58 +0000143 break;
144 case SND_SOC_DAPM_POST_PMD:
145 if (manual_ena) {
146 if (!priv->spk_ena)
Mark Brown3c43c692013-12-12 00:49:22 +0000147 regmap_write_async(arizona->regmap,
148 0x4f5, 0x0da);
Mark Brown56447e12013-01-10 14:45:58 +0000149 }
150 break;
151 }
152
153 return 0;
154}
155
Mark Brown899817e2013-03-13 12:32:10 +0000156static irqreturn_t arizona_thermal_warn(int irq, void *data)
157{
158 struct arizona *arizona = data;
159 unsigned int val;
160 int ret;
161
162 ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
163 &val);
164 if (ret != 0) {
165 dev_err(arizona->dev, "Failed to read thermal status: %d\n",
166 ret);
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100167 } else if (val & ARIZONA_SPK_OVERHEAT_WARN_STS) {
Mark Brown899817e2013-03-13 12:32:10 +0000168 dev_crit(arizona->dev, "Thermal warning\n");
169 }
170
171 return IRQ_HANDLED;
172}
173
174static irqreturn_t arizona_thermal_shutdown(int irq, void *data)
175{
176 struct arizona *arizona = data;
177 unsigned int val;
178 int ret;
179
180 ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
181 &val);
182 if (ret != 0) {
183 dev_err(arizona->dev, "Failed to read thermal status: %d\n",
184 ret);
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100185 } else if (val & ARIZONA_SPK_OVERHEAT_STS) {
Mark Brown899817e2013-03-13 12:32:10 +0000186 dev_crit(arizona->dev, "Thermal shutdown\n");
Mark Brownf4a76e72013-03-13 12:22:39 +0000187 ret = regmap_update_bits(arizona->regmap,
188 ARIZONA_OUTPUT_ENABLES_1,
189 ARIZONA_OUT4L_ENA |
190 ARIZONA_OUT4R_ENA, 0);
191 if (ret != 0)
192 dev_crit(arizona->dev,
193 "Failed to disable speaker outputs: %d\n",
194 ret);
Mark Brown899817e2013-03-13 12:32:10 +0000195 }
196
197 return IRQ_HANDLED;
198}
199
Mark Brown56447e12013-01-10 14:45:58 +0000200static const struct snd_soc_dapm_widget arizona_spkl =
Mark Brownf4a76e72013-03-13 12:22:39 +0000201 SND_SOC_DAPM_PGA_E("OUT4L", SND_SOC_NOPM,
Mark Brown56447e12013-01-10 14:45:58 +0000202 ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
203 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
204
205static const struct snd_soc_dapm_widget arizona_spkr =
Mark Brownf4a76e72013-03-13 12:22:39 +0000206 SND_SOC_DAPM_PGA_E("OUT4R", SND_SOC_NOPM,
Mark Brown56447e12013-01-10 14:45:58 +0000207 ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
208 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
209
210int arizona_init_spk(struct snd_soc_codec *codec)
211{
Mark Brown899817e2013-03-13 12:32:10 +0000212 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
213 struct arizona *arizona = priv->arizona;
Mark Brown56447e12013-01-10 14:45:58 +0000214 int ret;
215
216 ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkl, 1);
217 if (ret != 0)
218 return ret;
219
Charles Keepax40843ae2013-08-12 23:46:55 +0100220 switch (arizona->type) {
221 case WM8997:
222 break;
223 default:
224 ret = snd_soc_dapm_new_controls(&codec->dapm,
225 &arizona_spkr, 1);
226 if (ret != 0)
227 return ret;
228 break;
229 }
Mark Brown56447e12013-01-10 14:45:58 +0000230
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100231 ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN,
Mark Brown899817e2013-03-13 12:32:10 +0000232 "Thermal warning", arizona_thermal_warn,
233 arizona);
234 if (ret != 0)
235 dev_err(arizona->dev,
236 "Failed to get thermal warning IRQ: %d\n",
237 ret);
238
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100239 ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT,
Mark Brown899817e2013-03-13 12:32:10 +0000240 "Thermal shutdown", arizona_thermal_shutdown,
241 arizona);
242 if (ret != 0)
243 dev_err(arizona->dev,
244 "Failed to get thermal shutdown IRQ: %d\n",
245 ret);
246
Mark Brown56447e12013-01-10 14:45:58 +0000247 return 0;
248}
249EXPORT_SYMBOL_GPL(arizona_init_spk);
250
Charles Keepaxb60f3632014-06-10 18:41:02 +0100251static const struct snd_soc_dapm_route arizona_mono_routes[] = {
252 { "OUT1R", NULL, "OUT1L" },
253 { "OUT2R", NULL, "OUT2L" },
254 { "OUT3R", NULL, "OUT3L" },
255 { "OUT4R", NULL, "OUT4L" },
256 { "OUT5R", NULL, "OUT5L" },
257 { "OUT6R", NULL, "OUT6L" },
258};
259
260int arizona_init_mono(struct snd_soc_codec *codec)
261{
262 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
263 struct arizona *arizona = priv->arizona;
264 int i;
265
266 for (i = 0; i < ARIZONA_MAX_OUTPUT; ++i) {
267 if (arizona->pdata.out_mono[i])
268 snd_soc_dapm_add_routes(&codec->dapm,
269 &arizona_mono_routes[i], 1);
270 }
271
272 return 0;
273}
274EXPORT_SYMBOL_GPL(arizona_init_mono);
275
Charles Keepaxb63144e2013-07-04 08:56:28 +0100276int arizona_init_gpio(struct snd_soc_codec *codec)
277{
278 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
279 struct arizona *arizona = priv->arizona;
280 int i;
281
282 switch (arizona->type) {
283 case WM5110:
284 snd_soc_dapm_disable_pin(&codec->dapm, "DRC2 Signal Activity");
Charles Keepaxb79fae62013-07-04 16:53:03 +0100285 break;
286 default:
287 break;
Charles Keepaxb63144e2013-07-04 08:56:28 +0100288 }
289
290 snd_soc_dapm_disable_pin(&codec->dapm, "DRC1 Signal Activity");
291
292 for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
293 switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) {
294 case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT:
295 snd_soc_dapm_enable_pin(&codec->dapm,
296 "DRC1 Signal Activity");
297 break;
298 case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT:
299 snd_soc_dapm_enable_pin(&codec->dapm,
300 "DRC2 Signal Activity");
301 break;
302 default:
303 break;
304 }
305 }
306
307 return 0;
308}
309EXPORT_SYMBOL_GPL(arizona_init_gpio);
310
Mark Brown07ed8732012-06-18 21:08:44 +0100311const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
312 "None",
313 "Tone Generator 1",
314 "Tone Generator 2",
315 "Haptics",
316 "AEC",
317 "Mic Mute Mixer",
318 "Noise Generator",
319 "IN1L",
320 "IN1R",
321 "IN2L",
322 "IN2R",
323 "IN3L",
324 "IN3R",
Mark Brownc9c56fd2012-07-09 19:09:01 +0100325 "IN4L",
326 "IN4R",
Mark Brown07ed8732012-06-18 21:08:44 +0100327 "AIF1RX1",
328 "AIF1RX2",
329 "AIF1RX3",
330 "AIF1RX4",
331 "AIF1RX5",
332 "AIF1RX6",
333 "AIF1RX7",
334 "AIF1RX8",
335 "AIF2RX1",
336 "AIF2RX2",
Richard Fitzgeralde64001e2013-11-20 13:17:07 +0000337 "AIF2RX3",
338 "AIF2RX4",
339 "AIF2RX5",
340 "AIF2RX6",
Mark Brown07ed8732012-06-18 21:08:44 +0100341 "AIF3RX1",
342 "AIF3RX2",
343 "SLIMRX1",
344 "SLIMRX2",
345 "SLIMRX3",
346 "SLIMRX4",
347 "SLIMRX5",
348 "SLIMRX6",
349 "SLIMRX7",
350 "SLIMRX8",
351 "EQ1",
352 "EQ2",
353 "EQ3",
354 "EQ4",
355 "DRC1L",
356 "DRC1R",
357 "DRC2L",
358 "DRC2R",
359 "LHPF1",
360 "LHPF2",
361 "LHPF3",
362 "LHPF4",
363 "DSP1.1",
364 "DSP1.2",
365 "DSP1.3",
366 "DSP1.4",
367 "DSP1.5",
368 "DSP1.6",
Mark Brownc922cc42012-09-26 16:43:44 +0100369 "DSP2.1",
370 "DSP2.2",
371 "DSP2.3",
372 "DSP2.4",
373 "DSP2.5",
374 "DSP2.6",
375 "DSP3.1",
376 "DSP3.2",
377 "DSP3.3",
378 "DSP3.4",
379 "DSP3.5",
380 "DSP3.6",
381 "DSP4.1",
382 "DSP4.2",
383 "DSP4.3",
384 "DSP4.4",
385 "DSP4.5",
386 "DSP4.6",
Mark Brown07ed8732012-06-18 21:08:44 +0100387 "ASRC1L",
388 "ASRC1R",
389 "ASRC2L",
390 "ASRC2R",
Mark Brown91660bd2012-12-05 20:35:24 +0900391 "ISRC1INT1",
392 "ISRC1INT2",
393 "ISRC1INT3",
394 "ISRC1INT4",
395 "ISRC1DEC1",
396 "ISRC1DEC2",
397 "ISRC1DEC3",
398 "ISRC1DEC4",
399 "ISRC2INT1",
400 "ISRC2INT2",
401 "ISRC2INT3",
402 "ISRC2INT4",
403 "ISRC2DEC1",
404 "ISRC2DEC2",
405 "ISRC2DEC3",
406 "ISRC2DEC4",
407 "ISRC3INT1",
408 "ISRC3INT2",
409 "ISRC3INT3",
410 "ISRC3INT4",
411 "ISRC3DEC1",
412 "ISRC3DEC2",
413 "ISRC3DEC3",
414 "ISRC3DEC4",
Mark Brown07ed8732012-06-18 21:08:44 +0100415};
416EXPORT_SYMBOL_GPL(arizona_mixer_texts);
417
418int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
419 0x00, /* None */
420 0x04, /* Tone */
421 0x05,
422 0x06, /* Haptics */
423 0x08, /* AEC */
424 0x0c, /* Noise mixer */
425 0x0d, /* Comfort noise */
426 0x10, /* IN1L */
427 0x11,
428 0x12,
429 0x13,
430 0x14,
431 0x15,
Mark Brownc9c56fd2012-07-09 19:09:01 +0100432 0x16,
433 0x17,
Mark Brown07ed8732012-06-18 21:08:44 +0100434 0x20, /* AIF1RX1 */
435 0x21,
436 0x22,
437 0x23,
438 0x24,
439 0x25,
440 0x26,
441 0x27,
442 0x28, /* AIF2RX1 */
443 0x29,
Richard Fitzgeralde64001e2013-11-20 13:17:07 +0000444 0x2a,
445 0x2b,
446 0x2c,
447 0x2d,
Mark Brown07ed8732012-06-18 21:08:44 +0100448 0x30, /* AIF3RX1 */
449 0x31,
450 0x38, /* SLIMRX1 */
451 0x39,
452 0x3a,
453 0x3b,
454 0x3c,
455 0x3d,
456 0x3e,
457 0x3f,
458 0x50, /* EQ1 */
459 0x51,
460 0x52,
461 0x53,
462 0x58, /* DRC1L */
463 0x59,
464 0x5a,
465 0x5b,
466 0x60, /* LHPF1 */
467 0x61,
468 0x62,
469 0x63,
470 0x68, /* DSP1.1 */
471 0x69,
472 0x6a,
473 0x6b,
474 0x6c,
475 0x6d,
Mark Brownc922cc42012-09-26 16:43:44 +0100476 0x70, /* DSP2.1 */
477 0x71,
478 0x72,
479 0x73,
480 0x74,
481 0x75,
482 0x78, /* DSP3.1 */
483 0x79,
484 0x7a,
485 0x7b,
486 0x7c,
487 0x7d,
488 0x80, /* DSP4.1 */
489 0x81,
490 0x82,
491 0x83,
492 0x84,
493 0x85,
Mark Brown07ed8732012-06-18 21:08:44 +0100494 0x90, /* ASRC1L */
495 0x91,
496 0x92,
497 0x93,
Mark Brown91660bd2012-12-05 20:35:24 +0900498 0xa0, /* ISRC1INT1 */
499 0xa1,
500 0xa2,
501 0xa3,
502 0xa4, /* ISRC1DEC1 */
503 0xa5,
504 0xa6,
505 0xa7,
506 0xa8, /* ISRC2DEC1 */
507 0xa9,
508 0xaa,
509 0xab,
510 0xac, /* ISRC2INT1 */
511 0xad,
512 0xae,
513 0xaf,
514 0xb0, /* ISRC3DEC1 */
515 0xb1,
516 0xb2,
517 0xb3,
518 0xb4, /* ISRC3INT1 */
519 0xb5,
520 0xb6,
521 0xb7,
Mark Brown07ed8732012-06-18 21:08:44 +0100522};
523EXPORT_SYMBOL_GPL(arizona_mixer_values);
524
525const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
526EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
527
Mark Browndc914282013-02-18 19:09:23 +0000528const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = {
529 "SYNCCLK rate", "8kHz", "16kHz", "ASYNCCLK rate",
530};
531EXPORT_SYMBOL_GPL(arizona_rate_text);
532
533const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
534 0, 1, 2, 8,
535};
536EXPORT_SYMBOL_GPL(arizona_rate_val);
537
538
Charles Keepaxfbedc8c2013-12-19 09:30:12 +0000539const struct soc_enum arizona_isrc_fsh[] = {
540 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_1,
541 ARIZONA_ISRC1_FSH_SHIFT, 0xf,
542 ARIZONA_RATE_ENUM_SIZE,
543 arizona_rate_text, arizona_rate_val),
544 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_1,
545 ARIZONA_ISRC2_FSH_SHIFT, 0xf,
546 ARIZONA_RATE_ENUM_SIZE,
547 arizona_rate_text, arizona_rate_val),
548 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_1,
549 ARIZONA_ISRC3_FSH_SHIFT, 0xf,
550 ARIZONA_RATE_ENUM_SIZE,
551 arizona_rate_text, arizona_rate_val),
552};
553EXPORT_SYMBOL_GPL(arizona_isrc_fsh);
554
Mark Browndc914282013-02-18 19:09:23 +0000555const struct soc_enum arizona_isrc_fsl[] = {
556 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2,
557 ARIZONA_ISRC1_FSL_SHIFT, 0xf,
558 ARIZONA_RATE_ENUM_SIZE,
559 arizona_rate_text, arizona_rate_val),
560 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_2,
561 ARIZONA_ISRC2_FSL_SHIFT, 0xf,
562 ARIZONA_RATE_ENUM_SIZE,
563 arizona_rate_text, arizona_rate_val),
564 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_2,
565 ARIZONA_ISRC3_FSL_SHIFT, 0xf,
566 ARIZONA_RATE_ENUM_SIZE,
567 arizona_rate_text, arizona_rate_val),
568};
569EXPORT_SYMBOL_GPL(arizona_isrc_fsl);
570
Charles Keepax56d37d82013-12-19 09:30:13 +0000571const struct soc_enum arizona_asrc_rate1 =
572 SOC_VALUE_ENUM_SINGLE(ARIZONA_ASRC_RATE1,
573 ARIZONA_ASRC_RATE1_SHIFT, 0xf,
574 ARIZONA_RATE_ENUM_SIZE - 1,
575 arizona_rate_text, arizona_rate_val);
576EXPORT_SYMBOL_GPL(arizona_asrc_rate1);
577
Mark Browne853a002012-12-09 12:25:52 +0900578static const char *arizona_vol_ramp_text[] = {
579 "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
580 "15ms/6dB", "30ms/6dB",
581};
582
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100583SOC_ENUM_SINGLE_DECL(arizona_in_vd_ramp,
584 ARIZONA_INPUT_VOLUME_RAMP,
585 ARIZONA_IN_VD_RAMP_SHIFT,
586 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900587EXPORT_SYMBOL_GPL(arizona_in_vd_ramp);
588
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100589SOC_ENUM_SINGLE_DECL(arizona_in_vi_ramp,
590 ARIZONA_INPUT_VOLUME_RAMP,
591 ARIZONA_IN_VI_RAMP_SHIFT,
592 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900593EXPORT_SYMBOL_GPL(arizona_in_vi_ramp);
594
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100595SOC_ENUM_SINGLE_DECL(arizona_out_vd_ramp,
596 ARIZONA_OUTPUT_VOLUME_RAMP,
597 ARIZONA_OUT_VD_RAMP_SHIFT,
598 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900599EXPORT_SYMBOL_GPL(arizona_out_vd_ramp);
600
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100601SOC_ENUM_SINGLE_DECL(arizona_out_vi_ramp,
602 ARIZONA_OUTPUT_VOLUME_RAMP,
603 ARIZONA_OUT_VI_RAMP_SHIFT,
604 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900605EXPORT_SYMBOL_GPL(arizona_out_vi_ramp);
606
Mark Brown07ed8732012-06-18 21:08:44 +0100607static const char *arizona_lhpf_mode_text[] = {
608 "Low-pass", "High-pass"
609};
610
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100611SOC_ENUM_SINGLE_DECL(arizona_lhpf1_mode,
612 ARIZONA_HPLPF1_1,
613 ARIZONA_LHPF1_MODE_SHIFT,
614 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100615EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
616
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100617SOC_ENUM_SINGLE_DECL(arizona_lhpf2_mode,
618 ARIZONA_HPLPF2_1,
619 ARIZONA_LHPF2_MODE_SHIFT,
620 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100621EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
622
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100623SOC_ENUM_SINGLE_DECL(arizona_lhpf3_mode,
624 ARIZONA_HPLPF3_1,
625 ARIZONA_LHPF3_MODE_SHIFT,
626 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100627EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
628
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100629SOC_ENUM_SINGLE_DECL(arizona_lhpf4_mode,
630 ARIZONA_HPLPF4_1,
631 ARIZONA_LHPF4_MODE_SHIFT,
632 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100633EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
634
Mark Brown845571c2012-12-18 13:47:57 +0000635static const char *arizona_ng_hold_text[] = {
636 "30ms", "120ms", "250ms", "500ms",
637};
638
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100639SOC_ENUM_SINGLE_DECL(arizona_ng_hold,
640 ARIZONA_NOISE_GATE_CONTROL,
641 ARIZONA_NGATE_HOLD_SHIFT,
642 arizona_ng_hold_text);
Mark Brown845571c2012-12-18 13:47:57 +0000643EXPORT_SYMBOL_GPL(arizona_ng_hold);
644
Charles Keepax254dc322013-11-19 16:04:03 +0000645static const char * const arizona_in_hpf_cut_text[] = {
646 "2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz"
647};
648
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100649SOC_ENUM_SINGLE_DECL(arizona_in_hpf_cut_enum,
650 ARIZONA_HPF_CONTROL,
651 ARIZONA_IN_HPF_CUT_SHIFT,
652 arizona_in_hpf_cut_text);
Charles Keepax254dc322013-11-19 16:04:03 +0000653EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum);
654
Charles Keepaxc7f38432013-08-06 17:03:55 +0100655static const char * const arizona_in_dmic_osr_text[] = {
Charles Keepaxef326f42014-11-12 14:55:26 +0000656 "1.536MHz", "3.072MHz", "6.144MHz", "768kHz",
Charles Keepaxc7f38432013-08-06 17:03:55 +0100657};
658
659const struct soc_enum arizona_in_dmic_osr[] = {
660 SOC_ENUM_SINGLE(ARIZONA_IN1L_CONTROL, ARIZONA_IN1_OSR_SHIFT,
661 ARRAY_SIZE(arizona_in_dmic_osr_text),
662 arizona_in_dmic_osr_text),
663 SOC_ENUM_SINGLE(ARIZONA_IN2L_CONTROL, ARIZONA_IN2_OSR_SHIFT,
664 ARRAY_SIZE(arizona_in_dmic_osr_text),
665 arizona_in_dmic_osr_text),
666 SOC_ENUM_SINGLE(ARIZONA_IN3L_CONTROL, ARIZONA_IN3_OSR_SHIFT,
667 ARRAY_SIZE(arizona_in_dmic_osr_text),
668 arizona_in_dmic_osr_text),
669 SOC_ENUM_SINGLE(ARIZONA_IN4L_CONTROL, ARIZONA_IN4_OSR_SHIFT,
670 ARRAY_SIZE(arizona_in_dmic_osr_text),
671 arizona_in_dmic_osr_text),
672};
673EXPORT_SYMBOL_GPL(arizona_in_dmic_osr);
674
Mark Brownddbce972013-02-15 17:27:22 +0000675static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
676{
677 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
678 unsigned int val;
679 int i;
680
681 if (ena)
682 val = ARIZONA_IN_VU;
683 else
684 val = 0;
685
686 for (i = 0; i < priv->num_inputs; i++)
687 snd_soc_update_bits(codec,
688 ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 4),
689 ARIZONA_IN_VU, val);
690}
691
Mark Brown07ed8732012-06-18 21:08:44 +0100692int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
693 int event)
694{
Mark Brownddbce972013-02-15 17:27:22 +0000695 struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000696 unsigned int reg;
697
698 if (w->shift % 2)
699 reg = ARIZONA_ADC_DIGITAL_VOLUME_1L + ((w->shift / 2) * 8);
700 else
701 reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8);
702
703 switch (event) {
Mark Brownddbce972013-02-15 17:27:22 +0000704 case SND_SOC_DAPM_PRE_PMU:
705 priv->in_pending++;
706 break;
Mark Brown43cd8bf2013-02-06 16:57:29 +0000707 case SND_SOC_DAPM_POST_PMU:
708 snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, 0);
Mark Brownddbce972013-02-15 17:27:22 +0000709
710 /* If this is the last input pending then allow VU */
711 priv->in_pending--;
712 if (priv->in_pending == 0) {
713 msleep(1);
714 arizona_in_set_vu(w->codec, 1);
715 }
Mark Brown43cd8bf2013-02-06 16:57:29 +0000716 break;
717 case SND_SOC_DAPM_PRE_PMD:
Mark Brownddbce972013-02-15 17:27:22 +0000718 snd_soc_update_bits(w->codec, reg,
719 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU,
720 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000721 break;
Mark Brownddbce972013-02-15 17:27:22 +0000722 case SND_SOC_DAPM_POST_PMD:
723 /* Disable volume updates if no inputs are enabled */
724 reg = snd_soc_read(w->codec, ARIZONA_INPUT_ENABLES);
725 if (reg == 0)
726 arizona_in_set_vu(w->codec, 0);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000727 }
728
Mark Brown07ed8732012-06-18 21:08:44 +0100729 return 0;
730}
731EXPORT_SYMBOL_GPL(arizona_in_ev);
732
733int arizona_out_ev(struct snd_soc_dapm_widget *w,
734 struct snd_kcontrol *kcontrol,
735 int event)
736{
Charles Keepax054e1b42015-01-20 16:31:50 +0000737 struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
738
Mark Brown1a2c7d52013-03-24 22:50:23 +0000739 switch (event) {
Charles Keepaxe1ae5fb2015-01-20 16:31:51 +0000740 case SND_SOC_DAPM_PRE_PMU:
741 switch (w->shift) {
742 case ARIZONA_OUT1L_ENA_SHIFT:
743 case ARIZONA_OUT1R_ENA_SHIFT:
744 case ARIZONA_OUT2L_ENA_SHIFT:
745 case ARIZONA_OUT2R_ENA_SHIFT:
746 case ARIZONA_OUT3L_ENA_SHIFT:
747 case ARIZONA_OUT3R_ENA_SHIFT:
748 priv->out_up_pending++;
749 priv->out_up_delay += 17;
750 break;
751 default:
752 break;
753 }
754 break;
Mark Brown1a2c7d52013-03-24 22:50:23 +0000755 case SND_SOC_DAPM_POST_PMU:
756 switch (w->shift) {
757 case ARIZONA_OUT1L_ENA_SHIFT:
758 case ARIZONA_OUT1R_ENA_SHIFT:
759 case ARIZONA_OUT2L_ENA_SHIFT:
760 case ARIZONA_OUT2R_ENA_SHIFT:
761 case ARIZONA_OUT3L_ENA_SHIFT:
762 case ARIZONA_OUT3R_ENA_SHIFT:
Charles Keepaxe1ae5fb2015-01-20 16:31:51 +0000763 priv->out_up_pending--;
764 if (!priv->out_up_pending) {
765 msleep(priv->out_up_delay);
766 priv->out_up_delay = 0;
767 }
Mark Brown1a2c7d52013-03-24 22:50:23 +0000768 break;
769
770 default:
771 break;
772 }
773 break;
Charles Keepax054e1b42015-01-20 16:31:50 +0000774 case SND_SOC_DAPM_PRE_PMD:
775 switch (w->shift) {
776 case ARIZONA_OUT1L_ENA_SHIFT:
777 case ARIZONA_OUT1R_ENA_SHIFT:
778 case ARIZONA_OUT2L_ENA_SHIFT:
779 case ARIZONA_OUT2R_ENA_SHIFT:
780 case ARIZONA_OUT3L_ENA_SHIFT:
781 case ARIZONA_OUT3R_ENA_SHIFT:
782 priv->out_down_pending++;
783 priv->out_down_delay++;
784 break;
785 default:
786 break;
787 }
788 break;
789 case SND_SOC_DAPM_POST_PMD:
790 switch (w->shift) {
791 case ARIZONA_OUT1L_ENA_SHIFT:
792 case ARIZONA_OUT1R_ENA_SHIFT:
793 case ARIZONA_OUT2L_ENA_SHIFT:
794 case ARIZONA_OUT2R_ENA_SHIFT:
795 case ARIZONA_OUT3L_ENA_SHIFT:
796 case ARIZONA_OUT3R_ENA_SHIFT:
797 priv->out_down_pending--;
798 if (!priv->out_down_pending) {
799 msleep(priv->out_down_delay);
800 priv->out_down_delay = 0;
801 }
802 break;
803 default:
804 break;
805 }
806 break;
Mark Brown1a2c7d52013-03-24 22:50:23 +0000807 }
808
Mark Brown07ed8732012-06-18 21:08:44 +0100809 return 0;
810}
811EXPORT_SYMBOL_GPL(arizona_out_ev);
812
Mark Brownf607e312013-02-22 18:36:53 +0000813int arizona_hp_ev(struct snd_soc_dapm_widget *w,
814 struct snd_kcontrol *kcontrol,
815 int event)
816{
817 struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
Mark Brown3c43c692013-12-12 00:49:22 +0000818 struct arizona *arizona = priv->arizona;
Mark Brownf607e312013-02-22 18:36:53 +0000819 unsigned int mask = 1 << w->shift;
820 unsigned int val;
821
822 switch (event) {
823 case SND_SOC_DAPM_POST_PMU:
824 val = mask;
825 break;
826 case SND_SOC_DAPM_PRE_PMD:
827 val = 0;
828 break;
Charles Keepaxe1ae5fb2015-01-20 16:31:51 +0000829 case SND_SOC_DAPM_PRE_PMU:
Charles Keepax054e1b42015-01-20 16:31:50 +0000830 case SND_SOC_DAPM_POST_PMD:
831 return arizona_out_ev(w, kcontrol, event);
Mark Brownf607e312013-02-22 18:36:53 +0000832 default:
833 return -EINVAL;
834 }
835
836 /* Store the desired state for the HP outputs */
837 priv->arizona->hp_ena &= ~mask;
838 priv->arizona->hp_ena |= val;
839
840 /* Force off if HPDET magic is active */
841 if (priv->arizona->hpdet_magic)
842 val = 0;
843
Mark Brown3c43c692013-12-12 00:49:22 +0000844 regmap_update_bits_async(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1,
845 mask, val);
Mark Brownf607e312013-02-22 18:36:53 +0000846
847 return arizona_out_ev(w, kcontrol, event);
848}
849EXPORT_SYMBOL_GPL(arizona_hp_ev);
850
Mark Browncbd840d2012-08-08 17:52:44 +0100851static unsigned int arizona_sysclk_48k_rates[] = {
852 6144000,
853 12288000,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000854 24576000,
Mark Browncbd840d2012-08-08 17:52:44 +0100855 49152000,
Mark Brownaeaeee12012-09-26 17:50:02 +0100856 73728000,
857 98304000,
858 147456000,
Mark Browncbd840d2012-08-08 17:52:44 +0100859};
860
861static unsigned int arizona_sysclk_44k1_rates[] = {
862 5644800,
863 11289600,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000864 22579200,
Mark Browncbd840d2012-08-08 17:52:44 +0100865 45158400,
Mark Brownaeaeee12012-09-26 17:50:02 +0100866 67737600,
867 90316800,
868 135475200,
Mark Browncbd840d2012-08-08 17:52:44 +0100869};
870
871static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
872 unsigned int freq)
873{
874 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
875 unsigned int reg;
876 unsigned int *rates;
877 int ref, div, refclk;
878
879 switch (clk) {
880 case ARIZONA_CLK_OPCLK:
881 reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
882 refclk = priv->sysclk;
883 break;
884 case ARIZONA_CLK_ASYNC_OPCLK:
885 reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
886 refclk = priv->asyncclk;
887 break;
888 default:
889 return -EINVAL;
890 }
891
892 if (refclk % 8000)
893 rates = arizona_sysclk_44k1_rates;
894 else
895 rates = arizona_sysclk_48k_rates;
896
897 for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) &&
898 rates[ref] <= refclk; ref++) {
899 div = 1;
900 while (rates[ref] / div >= freq && div < 32) {
901 if (rates[ref] / div == freq) {
902 dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
903 freq);
904 snd_soc_update_bits(codec, reg,
905 ARIZONA_OPCLK_DIV_MASK |
906 ARIZONA_OPCLK_SEL_MASK,
907 (div <<
908 ARIZONA_OPCLK_DIV_SHIFT) |
909 ref);
910 return 0;
911 }
912 div++;
913 }
914 }
915
916 dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
917 return -EINVAL;
918}
919
Mark Brown07ed8732012-06-18 21:08:44 +0100920int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
921 int source, unsigned int freq, int dir)
922{
923 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
924 struct arizona *arizona = priv->arizona;
925 char *name;
926 unsigned int reg;
927 unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
928 unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
929 unsigned int *clk;
930
931 switch (clk_id) {
932 case ARIZONA_CLK_SYSCLK:
933 name = "SYSCLK";
934 reg = ARIZONA_SYSTEM_CLOCK_1;
935 clk = &priv->sysclk;
936 mask |= ARIZONA_SYSCLK_FRAC;
937 break;
938 case ARIZONA_CLK_ASYNCCLK:
939 name = "ASYNCCLK";
940 reg = ARIZONA_ASYNC_CLOCK_1;
941 clk = &priv->asyncclk;
942 break;
Mark Browncbd840d2012-08-08 17:52:44 +0100943 case ARIZONA_CLK_OPCLK:
944 case ARIZONA_CLK_ASYNC_OPCLK:
945 return arizona_set_opclk(codec, clk_id, freq);
Mark Brown07ed8732012-06-18 21:08:44 +0100946 default:
947 return -EINVAL;
948 }
949
950 switch (freq) {
951 case 5644800:
952 case 6144000:
953 break;
954 case 11289600:
955 case 12288000:
Mark Brown3f341f72013-03-08 15:22:29 +0800956 val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100957 break;
958 case 22579200:
959 case 24576000:
Mark Brown3f341f72013-03-08 15:22:29 +0800960 val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100961 break;
962 case 45158400:
963 case 49152000:
Mark Brown3f341f72013-03-08 15:22:29 +0800964 val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100965 break;
Mark Brown38113362012-11-26 16:01:37 +0000966 case 67737600:
967 case 73728000:
Mark Brown3f341f72013-03-08 15:22:29 +0800968 val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000969 break;
970 case 90316800:
971 case 98304000:
Mark Brown3f341f72013-03-08 15:22:29 +0800972 val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000973 break;
974 case 135475200:
975 case 147456000:
Mark Brown3f341f72013-03-08 15:22:29 +0800976 val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000977 break;
Mark Brownf2c26d42013-01-21 16:09:36 +0900978 case 0:
979 dev_dbg(arizona->dev, "%s cleared\n", name);
980 *clk = freq;
981 return 0;
Mark Brown07ed8732012-06-18 21:08:44 +0100982 default:
983 return -EINVAL;
984 }
985
986 *clk = freq;
987
988 if (freq % 6144000)
989 val |= ARIZONA_SYSCLK_FRAC;
990
991 dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
992
993 return regmap_update_bits(arizona->regmap, reg, mask, val);
994}
995EXPORT_SYMBOL_GPL(arizona_set_sysclk);
996
997static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
998{
999 struct snd_soc_codec *codec = dai->codec;
Mark Brown3c43c692013-12-12 00:49:22 +00001000 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1001 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +01001002 int lrclk, bclk, mode, base;
1003
1004 base = dai->driver->base;
1005
1006 lrclk = 0;
1007 bclk = 0;
1008
1009 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
1010 case SND_SOC_DAIFMT_DSP_A:
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001011 mode = ARIZONA_FMT_DSP_MODE_A;
1012 break;
1013 case SND_SOC_DAIFMT_DSP_B:
1014 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
1015 != SND_SOC_DAIFMT_CBM_CFM) {
1016 arizona_aif_err(dai, "DSP_B not valid in slave mode\n");
1017 return -EINVAL;
1018 }
1019 mode = ARIZONA_FMT_DSP_MODE_B;
Mark Brown07ed8732012-06-18 21:08:44 +01001020 break;
Mark Brown07ed8732012-06-18 21:08:44 +01001021 case SND_SOC_DAIFMT_I2S:
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001022 mode = ARIZONA_FMT_I2S_MODE;
1023 break;
1024 case SND_SOC_DAIFMT_LEFT_J:
1025 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
1026 != SND_SOC_DAIFMT_CBM_CFM) {
1027 arizona_aif_err(dai, "LEFT_J not valid in slave mode\n");
1028 return -EINVAL;
1029 }
1030 mode = ARIZONA_FMT_LEFT_JUSTIFIED_MODE;
Mark Brown07ed8732012-06-18 21:08:44 +01001031 break;
Mark Brown07ed8732012-06-18 21:08:44 +01001032 default:
1033 arizona_aif_err(dai, "Unsupported DAI format %d\n",
1034 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
1035 return -EINVAL;
1036 }
1037
1038 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
1039 case SND_SOC_DAIFMT_CBS_CFS:
1040 break;
1041 case SND_SOC_DAIFMT_CBS_CFM:
1042 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
1043 break;
1044 case SND_SOC_DAIFMT_CBM_CFS:
1045 bclk |= ARIZONA_AIF1_BCLK_MSTR;
1046 break;
1047 case SND_SOC_DAIFMT_CBM_CFM:
1048 bclk |= ARIZONA_AIF1_BCLK_MSTR;
1049 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
1050 break;
1051 default:
1052 arizona_aif_err(dai, "Unsupported master mode %d\n",
1053 fmt & SND_SOC_DAIFMT_MASTER_MASK);
1054 return -EINVAL;
1055 }
1056
1057 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1058 case SND_SOC_DAIFMT_NB_NF:
1059 break;
1060 case SND_SOC_DAIFMT_IB_IF:
1061 bclk |= ARIZONA_AIF1_BCLK_INV;
1062 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
1063 break;
1064 case SND_SOC_DAIFMT_IB_NF:
1065 bclk |= ARIZONA_AIF1_BCLK_INV;
1066 break;
1067 case SND_SOC_DAIFMT_NB_IF:
1068 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
1069 break;
1070 default:
1071 return -EINVAL;
1072 }
1073
Mark Brown3c43c692013-12-12 00:49:22 +00001074 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_BCLK_CTRL,
1075 ARIZONA_AIF1_BCLK_INV |
1076 ARIZONA_AIF1_BCLK_MSTR,
1077 bclk);
1078 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_TX_PIN_CTRL,
1079 ARIZONA_AIF1TX_LRCLK_INV |
1080 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
1081 regmap_update_bits_async(arizona->regmap,
1082 base + ARIZONA_AIF_RX_PIN_CTRL,
1083 ARIZONA_AIF1RX_LRCLK_INV |
1084 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
1085 regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FORMAT,
1086 ARIZONA_AIF1_FMT_MASK, mode);
Mark Brown07ed8732012-06-18 21:08:44 +01001087
1088 return 0;
1089}
1090
Mark Brown949e6bc2012-07-04 18:58:04 +01001091static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001092 -1,
1093 48000,
1094 64000,
1095 96000,
1096 128000,
1097 192000,
1098 256000,
1099 384000,
1100 512000,
1101 768000,
1102 1024000,
1103 1536000,
1104 2048000,
1105 3072000,
1106 4096000,
1107 6144000,
1108 8192000,
1109 12288000,
1110 24576000,
1111};
1112
Mark Brown5b2eec32012-07-04 17:32:05 +01001113static const unsigned int arizona_48k_rates[] = {
1114 12000,
1115 24000,
1116 48000,
1117 96000,
1118 192000,
1119 384000,
1120 768000,
1121 4000,
1122 8000,
1123 16000,
1124 32000,
1125 64000,
1126 128000,
1127 256000,
1128 512000,
1129};
1130
1131static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = {
1132 .count = ARRAY_SIZE(arizona_48k_rates),
1133 .list = arizona_48k_rates,
1134};
1135
Mark Brown949e6bc2012-07-04 18:58:04 +01001136static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001137 -1,
1138 44100,
1139 58800,
1140 88200,
1141 117600,
1142 177640,
1143 235200,
1144 352800,
1145 470400,
1146 705600,
1147 940800,
1148 1411200,
1149 1881600,
Heather Lomond4758be32012-09-05 05:02:10 -04001150 2822400,
Mark Brown07ed8732012-06-18 21:08:44 +01001151 3763200,
1152 5644800,
1153 7526400,
1154 11289600,
1155 22579200,
1156};
1157
Mark Brown5b2eec32012-07-04 17:32:05 +01001158static const unsigned int arizona_44k1_rates[] = {
1159 11025,
1160 22050,
1161 44100,
1162 88200,
1163 176400,
1164 352800,
1165 705600,
1166};
1167
1168static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = {
1169 .count = ARRAY_SIZE(arizona_44k1_rates),
1170 .list = arizona_44k1_rates,
1171};
1172
Mark Brown07ed8732012-06-18 21:08:44 +01001173static int arizona_sr_vals[] = {
1174 0,
1175 12000,
1176 24000,
1177 48000,
1178 96000,
1179 192000,
1180 384000,
1181 768000,
1182 0,
1183 11025,
1184 22050,
1185 44100,
1186 88200,
1187 176400,
1188 352800,
1189 705600,
1190 4000,
1191 8000,
1192 16000,
1193 32000,
1194 64000,
1195 128000,
1196 256000,
1197 512000,
1198};
1199
Mark Brown5b2eec32012-07-04 17:32:05 +01001200static int arizona_startup(struct snd_pcm_substream *substream,
1201 struct snd_soc_dai *dai)
1202{
1203 struct snd_soc_codec *codec = dai->codec;
1204 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1205 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
1206 const struct snd_pcm_hw_constraint_list *constraint;
1207 unsigned int base_rate;
1208
1209 switch (dai_priv->clk) {
1210 case ARIZONA_CLK_SYSCLK:
1211 base_rate = priv->sysclk;
1212 break;
1213 case ARIZONA_CLK_ASYNCCLK:
1214 base_rate = priv->asyncclk;
1215 break;
1216 default:
1217 return 0;
1218 }
1219
Mark Brownf2c26d42013-01-21 16:09:36 +09001220 if (base_rate == 0)
1221 return 0;
1222
Mark Brown5b2eec32012-07-04 17:32:05 +01001223 if (base_rate % 8000)
1224 constraint = &arizona_44k1_constraint;
1225 else
1226 constraint = &arizona_48k_constraint;
1227
1228 return snd_pcm_hw_constraint_list(substream->runtime, 0,
1229 SNDRV_PCM_HW_PARAM_RATE,
1230 constraint);
1231}
1232
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001233static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec,
1234 unsigned int rate)
1235{
1236 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1237 struct arizona *arizona = priv->arizona;
1238 struct reg_default dac_comp[] = {
1239 { 0x80, 0x3 },
1240 { ARIZONA_DAC_COMP_1, 0 },
1241 { ARIZONA_DAC_COMP_2, 0 },
1242 { 0x80, 0x0 },
1243 };
1244
Lars-Peter Clausend74bcaa2014-11-09 17:00:59 +01001245 mutex_lock(&arizona->dac_comp_lock);
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001246
1247 dac_comp[1].def = arizona->dac_comp_coeff;
1248 if (rate >= 176400)
1249 dac_comp[2].def = arizona->dac_comp_enabled;
1250
Lars-Peter Clausend74bcaa2014-11-09 17:00:59 +01001251 mutex_unlock(&arizona->dac_comp_lock);
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001252
1253 regmap_multi_reg_write(arizona->regmap,
1254 dac_comp,
1255 ARRAY_SIZE(dac_comp));
1256}
1257
Mark Brownb272efc2012-10-10 15:10:08 +09001258static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
1259 struct snd_pcm_hw_params *params,
1260 struct snd_soc_dai *dai)
Mark Brown07ed8732012-06-18 21:08:44 +01001261{
1262 struct snd_soc_codec *codec = dai->codec;
Mark Brownc013b272012-07-04 20:05:57 +01001263 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1264 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown07ed8732012-06-18 21:08:44 +01001265 int base = dai->driver->base;
Mark Brownb272efc2012-10-10 15:10:08 +09001266 int i, sr_val;
1267
1268 /*
1269 * We will need to be more flexible than this in future,
1270 * currently we use a single sample rate for SYSCLK.
1271 */
1272 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
1273 if (arizona_sr_vals[i] == params_rate(params))
1274 break;
1275 if (i == ARRAY_SIZE(arizona_sr_vals)) {
1276 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1277 params_rate(params));
1278 return -EINVAL;
1279 }
1280 sr_val = i;
1281
1282 switch (dai_priv->clk) {
1283 case ARIZONA_CLK_SYSCLK:
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001284 switch (priv->arizona->type) {
1285 case WM5102:
1286 arizona_wm5102_set_dac_comp(codec,
1287 params_rate(params));
1288 break;
1289 default:
1290 break;
1291 }
1292
Mark Brownb272efc2012-10-10 15:10:08 +09001293 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
1294 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
1295 if (base)
1296 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1297 ARIZONA_AIF1_RATE_MASK, 0);
1298 break;
1299 case ARIZONA_CLK_ASYNCCLK:
1300 snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
Charles Keepaxc24084d2014-09-01 15:48:52 +01001301 ARIZONA_ASYNC_SAMPLE_RATE_1_MASK, sr_val);
Mark Brownb272efc2012-10-10 15:10:08 +09001302 if (base)
1303 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1304 ARIZONA_AIF1_RATE_MASK,
1305 8 << ARIZONA_AIF1_RATE_SHIFT);
1306 break;
1307 default:
1308 arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
1309 return -EINVAL;
1310 }
1311
1312 return 0;
1313}
1314
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001315static bool arizona_aif_cfg_changed(struct snd_soc_codec *codec,
1316 int base, int bclk, int lrclk, int frame)
1317{
1318 int val;
1319
1320 val = snd_soc_read(codec, base + ARIZONA_AIF_BCLK_CTRL);
1321 if (bclk != (val & ARIZONA_AIF1_BCLK_FREQ_MASK))
1322 return true;
1323
1324 val = snd_soc_read(codec, base + ARIZONA_AIF_TX_BCLK_RATE);
1325 if (lrclk != (val & ARIZONA_AIF1TX_BCPF_MASK))
1326 return true;
1327
1328 val = snd_soc_read(codec, base + ARIZONA_AIF_FRAME_CTRL_1);
1329 if (frame != (val & (ARIZONA_AIF1TX_WL_MASK |
1330 ARIZONA_AIF1TX_SLOT_LEN_MASK)))
1331 return true;
1332
1333 return false;
1334}
1335
Mark Brown07ed8732012-06-18 21:08:44 +01001336static int arizona_hw_params(struct snd_pcm_substream *substream,
1337 struct snd_pcm_hw_params *params,
1338 struct snd_soc_dai *dai)
1339{
1340 struct snd_soc_codec *codec = dai->codec;
1341 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brownc94aa302013-01-17 16:35:14 +09001342 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +01001343 int base = dai->driver->base;
1344 const int *rates;
Mark Brown76bf9692013-03-05 14:17:47 +08001345 int i, ret, val;
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001346 int channels = params_channels(params);
Mark Brownc94aa302013-01-17 16:35:14 +09001347 int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001348 int tdm_width = arizona->tdm_width[dai->id - 1];
1349 int tdm_slots = arizona->tdm_slots[dai->id - 1];
Mark Brownc94aa302013-01-17 16:35:14 +09001350 int bclk, lrclk, wl, frame, bclk_target;
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001351 bool reconfig;
1352 unsigned int aif_tx_state, aif_rx_state;
Mark Brown07ed8732012-06-18 21:08:44 +01001353
1354 if (params_rate(params) % 8000)
Mark Brown949e6bc2012-07-04 18:58:04 +01001355 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001356 else
Mark Brown949e6bc2012-07-04 18:58:04 +01001357 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001358
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001359 wl = snd_pcm_format_width(params_format(params));
1360
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001361 if (tdm_slots) {
1362 arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n",
1363 tdm_slots, tdm_width);
1364 bclk_target = tdm_slots * tdm_width * params_rate(params);
1365 channels = tdm_slots;
1366 } else {
1367 bclk_target = snd_soc_params_to_bclk(params);
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001368 tdm_width = wl;
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001369 }
1370
1371 if (chan_limit && chan_limit < channels) {
Mark Brownc94aa302013-01-17 16:35:14 +09001372 arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001373 bclk_target /= channels;
Mark Brownc94aa302013-01-17 16:35:14 +09001374 bclk_target *= chan_limit;
1375 }
1376
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001377 /* Force multiple of 2 channels for I2S mode */
Mark Brown76bf9692013-03-05 14:17:47 +08001378 val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001379 val &= ARIZONA_AIF1_FMT_MASK;
1380 if ((channels & 1) && (val == ARIZONA_FMT_I2S_MODE)) {
Mark Brown76bf9692013-03-05 14:17:47 +08001381 arizona_aif_dbg(dai, "Forcing stereo mode\n");
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001382 bclk_target /= channels;
1383 bclk_target *= channels + 1;
Mark Brown76bf9692013-03-05 14:17:47 +08001384 }
1385
Mark Brown949e6bc2012-07-04 18:58:04 +01001386 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brownc94aa302013-01-17 16:35:14 +09001387 if (rates[i] >= bclk_target &&
Mark Brown50017652012-07-04 19:07:09 +01001388 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +01001389 bclk = i;
1390 break;
1391 }
1392 }
Mark Brown949e6bc2012-07-04 18:58:04 +01001393 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001394 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1395 params_rate(params));
1396 return -EINVAL;
1397 }
1398
Mark Brownb59e0f82013-01-17 14:15:59 +09001399 lrclk = rates[bclk] / params_rate(params);
Mark Brown07ed8732012-06-18 21:08:44 +01001400
1401 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
1402 rates[bclk], rates[bclk] / lrclk);
1403
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001404 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | tdm_width;
Mark Brown07ed8732012-06-18 21:08:44 +01001405
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001406 reconfig = arizona_aif_cfg_changed(codec, base, bclk, lrclk, frame);
1407
1408 if (reconfig) {
1409 /* Save AIF TX/RX state */
1410 aif_tx_state = snd_soc_read(codec,
1411 base + ARIZONA_AIF_TX_ENABLES);
1412 aif_rx_state = snd_soc_read(codec,
1413 base + ARIZONA_AIF_RX_ENABLES);
1414 /* Disable AIF TX/RX before reconfiguring it */
1415 regmap_update_bits_async(arizona->regmap,
1416 base + ARIZONA_AIF_TX_ENABLES, 0xff, 0x0);
1417 regmap_update_bits(arizona->regmap,
1418 base + ARIZONA_AIF_RX_ENABLES, 0xff, 0x0);
1419 }
1420
Mark Brownb272efc2012-10-10 15:10:08 +09001421 ret = arizona_hw_params_rate(substream, params, dai);
1422 if (ret != 0)
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001423 goto restore_aif;
Mark Brownc013b272012-07-04 20:05:57 +01001424
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001425 if (reconfig) {
1426 regmap_update_bits_async(arizona->regmap,
1427 base + ARIZONA_AIF_BCLK_CTRL,
1428 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
1429 regmap_update_bits_async(arizona->regmap,
1430 base + ARIZONA_AIF_TX_BCLK_RATE,
1431 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
1432 regmap_update_bits_async(arizona->regmap,
1433 base + ARIZONA_AIF_RX_BCLK_RATE,
1434 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
1435 regmap_update_bits_async(arizona->regmap,
1436 base + ARIZONA_AIF_FRAME_CTRL_1,
1437 ARIZONA_AIF1TX_WL_MASK |
1438 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
1439 regmap_update_bits(arizona->regmap,
1440 base + ARIZONA_AIF_FRAME_CTRL_2,
1441 ARIZONA_AIF1RX_WL_MASK |
1442 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
1443 }
Mark Brown07ed8732012-06-18 21:08:44 +01001444
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001445restore_aif:
1446 if (reconfig) {
1447 /* Restore AIF TX/RX state */
1448 regmap_update_bits_async(arizona->regmap,
1449 base + ARIZONA_AIF_TX_ENABLES,
1450 0xff, aif_tx_state);
1451 regmap_update_bits(arizona->regmap,
1452 base + ARIZONA_AIF_RX_ENABLES,
1453 0xff, aif_rx_state);
1454 }
1455 return ret;
Mark Brown07ed8732012-06-18 21:08:44 +01001456}
1457
Mark Brown410837a2012-07-05 17:26:59 +01001458static const char *arizona_dai_clk_str(int clk_id)
1459{
1460 switch (clk_id) {
1461 case ARIZONA_CLK_SYSCLK:
1462 return "SYSCLK";
1463 case ARIZONA_CLK_ASYNCCLK:
1464 return "ASYNCCLK";
1465 default:
1466 return "Unknown clock";
1467 }
1468}
1469
Mark Brown5b2eec32012-07-04 17:32:05 +01001470static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
1471 int clk_id, unsigned int freq, int dir)
1472{
1473 struct snd_soc_codec *codec = dai->codec;
1474 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1475 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown410837a2012-07-05 17:26:59 +01001476 struct snd_soc_dapm_route routes[2];
Mark Brown5b2eec32012-07-04 17:32:05 +01001477
1478 switch (clk_id) {
1479 case ARIZONA_CLK_SYSCLK:
1480 case ARIZONA_CLK_ASYNCCLK:
1481 break;
1482 default:
1483 return -EINVAL;
1484 }
1485
Mark Brown410837a2012-07-05 17:26:59 +01001486 if (clk_id == dai_priv->clk)
1487 return 0;
1488
1489 if (dai->active) {
Mark Brown5b2eec32012-07-04 17:32:05 +01001490 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
1491 dai->id);
1492 return -EBUSY;
1493 }
1494
Mark Brownc8d35a62012-12-07 12:49:40 +09001495 dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1,
1496 arizona_dai_clk_str(clk_id));
1497
Mark Brown410837a2012-07-05 17:26:59 +01001498 memset(&routes, 0, sizeof(routes));
1499 routes[0].sink = dai->driver->capture.stream_name;
1500 routes[1].sink = dai->driver->playback.stream_name;
Mark Brown5b2eec32012-07-04 17:32:05 +01001501
Mark Brown410837a2012-07-05 17:26:59 +01001502 routes[0].source = arizona_dai_clk_str(dai_priv->clk);
1503 routes[1].source = arizona_dai_clk_str(dai_priv->clk);
1504 snd_soc_dapm_del_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
1505
1506 routes[0].source = arizona_dai_clk_str(clk_id);
1507 routes[1].source = arizona_dai_clk_str(clk_id);
1508 snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
1509
Mark Brown0c778e82012-12-06 18:22:25 +09001510 dai_priv->clk = clk_id;
1511
Mark Brown410837a2012-07-05 17:26:59 +01001512 return snd_soc_dapm_sync(&codec->dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +01001513}
1514
Mark Brown01df2592012-12-12 16:22:08 +09001515static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
1516{
1517 struct snd_soc_codec *codec = dai->codec;
1518 int base = dai->driver->base;
1519 unsigned int reg;
1520
1521 if (tristate)
1522 reg = ARIZONA_AIF1_TRI;
1523 else
1524 reg = 0;
1525
1526 return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1527 ARIZONA_AIF1_TRI, reg);
1528}
1529
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001530static void arizona_set_channels_to_mask(struct snd_soc_dai *dai,
1531 unsigned int base,
1532 int channels, unsigned int mask)
1533{
1534 struct snd_soc_codec *codec = dai->codec;
1535 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1536 struct arizona *arizona = priv->arizona;
1537 int slot, i;
1538
1539 for (i = 0; i < channels; ++i) {
1540 slot = ffs(mask) - 1;
1541 if (slot < 0)
1542 return;
1543
1544 regmap_write(arizona->regmap, base + i, slot);
1545
1546 mask &= ~(1 << slot);
1547 }
1548
1549 if (mask)
1550 arizona_aif_warn(dai, "Too many channels in TDM mask\n");
1551}
1552
1553static int arizona_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
1554 unsigned int rx_mask, int slots, int slot_width)
1555{
1556 struct snd_soc_codec *codec = dai->codec;
1557 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1558 struct arizona *arizona = priv->arizona;
1559 int base = dai->driver->base;
1560 int rx_max_chan = dai->driver->playback.channels_max;
1561 int tx_max_chan = dai->driver->capture.channels_max;
1562
1563 /* Only support TDM for the physical AIFs */
1564 if (dai->id > ARIZONA_MAX_AIF)
1565 return -ENOTSUPP;
1566
1567 if (slots == 0) {
1568 tx_mask = (1 << tx_max_chan) - 1;
1569 rx_mask = (1 << rx_max_chan) - 1;
1570 }
1571
1572 arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_3,
1573 tx_max_chan, tx_mask);
1574 arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_11,
1575 rx_max_chan, rx_mask);
1576
1577 arizona->tdm_width[dai->id - 1] = slot_width;
1578 arizona->tdm_slots[dai->id - 1] = slots;
1579
1580 return 0;
1581}
1582
Mark Brown07ed8732012-06-18 21:08:44 +01001583const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +01001584 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +01001585 .set_fmt = arizona_set_fmt,
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001586 .set_tdm_slot = arizona_set_tdm_slot,
Mark Brown07ed8732012-06-18 21:08:44 +01001587 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +01001588 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown01df2592012-12-12 16:22:08 +09001589 .set_tristate = arizona_set_tristate,
Mark Brown07ed8732012-06-18 21:08:44 +01001590};
Mark Browna8379872012-07-09 12:16:41 +01001591EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +01001592
Mark Brownbd1dd882013-05-17 13:29:03 +01001593const struct snd_soc_dai_ops arizona_simple_dai_ops = {
1594 .startup = arizona_startup,
1595 .hw_params = arizona_hw_params_rate,
1596 .set_sysclk = arizona_dai_set_sysclk,
1597};
1598EXPORT_SYMBOL_GPL(arizona_simple_dai_ops);
1599
Mark Brown5b2eec32012-07-04 17:32:05 +01001600int arizona_init_dai(struct arizona_priv *priv, int id)
1601{
1602 struct arizona_dai_priv *dai_priv = &priv->dai[id];
1603
1604 dai_priv->clk = ARIZONA_CLK_SYSCLK;
1605
1606 return 0;
1607}
1608EXPORT_SYMBOL_GPL(arizona_init_dai);
1609
Mark Brown07ed8732012-06-18 21:08:44 +01001610static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
1611{
1612 struct arizona_fll *fll = data;
1613
1614 arizona_fll_dbg(fll, "clock OK\n");
1615
1616 complete(&fll->ok);
1617
1618 return IRQ_HANDLED;
1619}
1620
1621static struct {
1622 unsigned int min;
1623 unsigned int max;
1624 u16 fratio;
1625 int ratio;
1626} fll_fratios[] = {
1627 { 0, 64000, 4, 16 },
1628 { 64000, 128000, 3, 8 },
1629 { 128000, 256000, 2, 4 },
1630 { 256000, 1000000, 1, 2 },
1631 { 1000000, 13500000, 0, 1 },
1632};
1633
Mark Brown8f113d72013-03-05 12:08:57 +08001634static struct {
1635 unsigned int min;
1636 unsigned int max;
1637 u16 gain;
1638} fll_gains[] = {
1639 { 0, 256000, 0 },
1640 { 256000, 1000000, 2 },
1641 { 1000000, 13500000, 4 },
1642};
1643
Mark Brown07ed8732012-06-18 21:08:44 +01001644struct arizona_fll_cfg {
1645 int n;
1646 int theta;
1647 int lambda;
1648 int refdiv;
1649 int outdiv;
1650 int fratio;
Mark Brown8f113d72013-03-05 12:08:57 +08001651 int gain;
Mark Brown07ed8732012-06-18 21:08:44 +01001652};
1653
Charles Keepax23f785a82014-03-07 16:34:20 +00001654static int arizona_validate_fll(struct arizona_fll *fll,
1655 unsigned int Fref,
1656 unsigned int Fout)
1657{
1658 unsigned int Fvco_min;
1659
Charles Keepaxc8badda2014-07-09 17:41:49 +01001660 if (fll->fout && Fout != fll->fout) {
1661 arizona_fll_err(fll,
1662 "Can't change output on active FLL\n");
1663 return -EINVAL;
1664 }
1665
Charles Keepax23f785a82014-03-07 16:34:20 +00001666 if (Fref / ARIZONA_FLL_MAX_REFDIV > ARIZONA_FLL_MAX_FREF) {
1667 arizona_fll_err(fll,
1668 "Can't scale %dMHz in to <=13.5MHz\n",
1669 Fref);
1670 return -EINVAL;
1671 }
1672
1673 Fvco_min = ARIZONA_FLL_MIN_FVCO * fll->vco_mult;
1674 if (Fout * ARIZONA_FLL_MAX_OUTDIV < Fvco_min) {
1675 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
1676 Fout);
1677 return -EINVAL;
1678 }
1679
1680 return 0;
1681}
1682
Charles Keepaxd0800342014-03-07 16:34:25 +00001683static int arizona_find_fratio(unsigned int Fref, int *fratio)
1684{
1685 int i;
1686
1687 /* Find an appropriate FLL_FRATIO */
1688 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
1689 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
1690 if (fratio)
1691 *fratio = fll_fratios[i].fratio;
1692 return fll_fratios[i].ratio;
1693 }
1694 }
1695
1696 return -EINVAL;
1697}
1698
1699static int arizona_calc_fratio(struct arizona_fll *fll,
1700 struct arizona_fll_cfg *cfg,
1701 unsigned int target,
1702 unsigned int Fref, bool sync)
1703{
1704 int init_ratio, ratio;
1705 int refdiv, div;
1706
1707 /* Fref must be <=13.5MHz, find initial refdiv */
1708 div = 1;
1709 cfg->refdiv = 0;
1710 while (Fref > ARIZONA_FLL_MAX_FREF) {
1711 div *= 2;
1712 Fref /= 2;
1713 cfg->refdiv++;
1714
1715 if (div > ARIZONA_FLL_MAX_REFDIV)
1716 return -EINVAL;
1717 }
1718
1719 /* Find an appropriate FLL_FRATIO */
1720 init_ratio = arizona_find_fratio(Fref, &cfg->fratio);
1721 if (init_ratio < 0) {
1722 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
1723 Fref);
1724 return init_ratio;
1725 }
1726
1727 switch (fll->arizona->type) {
1728 case WM5110:
1729 if (fll->arizona->rev < 3 || sync)
1730 return init_ratio;
1731 break;
1732 default:
1733 return init_ratio;
1734 }
1735
1736 cfg->fratio = init_ratio - 1;
1737
1738 /* Adjust FRATIO/refdiv to avoid integer mode if possible */
1739 refdiv = cfg->refdiv;
1740
1741 while (div <= ARIZONA_FLL_MAX_REFDIV) {
1742 for (ratio = init_ratio; ratio <= ARIZONA_FLL_MAX_FRATIO;
1743 ratio++) {
Charles Keepax35a730a2014-07-09 17:41:45 +01001744 if ((ARIZONA_FLL_VCO_CORNER / 2) /
1745 (fll->vco_mult * ratio) < Fref)
Charles Keepax29fee822014-07-09 17:41:44 +01001746 break;
1747
Charles Keepaxd0800342014-03-07 16:34:25 +00001748 if (target % (ratio * Fref)) {
1749 cfg->refdiv = refdiv;
1750 cfg->fratio = ratio - 1;
1751 return ratio;
1752 }
1753 }
1754
Charles Keepax4714bc02014-07-09 17:41:43 +01001755 for (ratio = init_ratio - 1; ratio > 0; ratio--) {
Charles Keepaxd0800342014-03-07 16:34:25 +00001756 if (target % (ratio * Fref)) {
1757 cfg->refdiv = refdiv;
1758 cfg->fratio = ratio - 1;
1759 return ratio;
1760 }
1761 }
1762
1763 div *= 2;
1764 Fref /= 2;
1765 refdiv++;
1766 init_ratio = arizona_find_fratio(Fref, NULL);
1767 }
1768
1769 arizona_fll_warn(fll, "Falling back to integer mode operation\n");
1770 return cfg->fratio + 1;
1771}
1772
Mark Brown07ed8732012-06-18 21:08:44 +01001773static int arizona_calc_fll(struct arizona_fll *fll,
1774 struct arizona_fll_cfg *cfg,
Charles Keepaxd0800342014-03-07 16:34:25 +00001775 unsigned int Fref, bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01001776{
1777 unsigned int target, div, gcd_fll;
1778 int i, ratio;
1779
Charles Keepax8ccefcd2014-03-07 16:34:21 +00001780 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, fll->fout);
Mark Brown07ed8732012-06-18 21:08:44 +01001781
Mark Brown2b4d39f2012-07-10 17:03:46 +01001782 /* Fvco should be over the targt; don't check the upper bound */
Charles Keepaxf641aec2014-03-07 16:34:22 +00001783 div = ARIZONA_FLL_MIN_OUTDIV;
1784 while (fll->fout * div < ARIZONA_FLL_MIN_FVCO * fll->vco_mult) {
Mark Brown07ed8732012-06-18 21:08:44 +01001785 div++;
Charles Keepaxf641aec2014-03-07 16:34:22 +00001786 if (div > ARIZONA_FLL_MAX_OUTDIV)
Mark Brown07ed8732012-06-18 21:08:44 +01001787 return -EINVAL;
Mark Brown07ed8732012-06-18 21:08:44 +01001788 }
Charles Keepaxf641aec2014-03-07 16:34:22 +00001789 target = fll->fout * div / fll->vco_mult;
Mark Brown07ed8732012-06-18 21:08:44 +01001790 cfg->outdiv = div;
1791
1792 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
1793
Charles Keepaxd0800342014-03-07 16:34:25 +00001794 /* Find an appropriate FLL_FRATIO and refdiv */
1795 ratio = arizona_calc_fratio(fll, cfg, target, Fref, sync);
1796 if (ratio < 0)
1797 return ratio;
Mark Brown07ed8732012-06-18 21:08:44 +01001798
Mark Brown07ed8732012-06-18 21:08:44 +01001799 /* Apply the division for our remaining calculations */
Charles Keepaxd0800342014-03-07 16:34:25 +00001800 Fref = Fref / (1 << cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08001801
Mark Brown07ed8732012-06-18 21:08:44 +01001802 cfg->n = target / (ratio * Fref);
1803
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001804 if (target % (ratio * Fref)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001805 gcd_fll = gcd(target, ratio * Fref);
1806 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
1807
1808 cfg->theta = (target - (cfg->n * ratio * Fref))
1809 / gcd_fll;
1810 cfg->lambda = (ratio * Fref) / gcd_fll;
1811 } else {
1812 cfg->theta = 0;
1813 cfg->lambda = 0;
1814 }
1815
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001816 /* Round down to 16bit range with cost of accuracy lost.
1817 * Denominator must be bigger than numerator so we only
1818 * take care of it.
1819 */
1820 while (cfg->lambda >= (1 << 16)) {
1821 cfg->theta >>= 1;
1822 cfg->lambda >>= 1;
1823 }
1824
Charles Keepax5a3935c2014-03-07 16:34:23 +00001825 for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
1826 if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
1827 cfg->gain = fll_gains[i].gain;
1828 break;
1829 }
1830 }
1831 if (i == ARRAY_SIZE(fll_gains)) {
1832 arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
1833 Fref);
1834 return -EINVAL;
1835 }
1836
Mark Brown07ed8732012-06-18 21:08:44 +01001837 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
1838 cfg->n, cfg->theta, cfg->lambda);
1839 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
1840 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08001841 arizona_fll_dbg(fll, "GAIN=%d\n", cfg->gain);
Mark Brown07ed8732012-06-18 21:08:44 +01001842
1843 return 0;
1844
1845}
1846
1847static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
Mark Brown8f113d72013-03-05 12:08:57 +08001848 struct arizona_fll_cfg *cfg, int source,
1849 bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01001850{
Mark Brown3c43c692013-12-12 00:49:22 +00001851 regmap_update_bits_async(arizona->regmap, base + 3,
1852 ARIZONA_FLL1_THETA_MASK, cfg->theta);
1853 regmap_update_bits_async(arizona->regmap, base + 4,
1854 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
1855 regmap_update_bits_async(arizona->regmap, base + 5,
1856 ARIZONA_FLL1_FRATIO_MASK,
1857 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
1858 regmap_update_bits_async(arizona->regmap, base + 6,
1859 ARIZONA_FLL1_CLK_REF_DIV_MASK |
1860 ARIZONA_FLL1_CLK_REF_SRC_MASK,
1861 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
1862 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
Mark Brown07ed8732012-06-18 21:08:44 +01001863
Charles Keepax61719db2014-03-07 16:34:19 +00001864 if (sync) {
1865 regmap_update_bits(arizona->regmap, base + 0x7,
1866 ARIZONA_FLL1_GAIN_MASK,
1867 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
1868 } else {
1869 regmap_update_bits(arizona->regmap, base + 0x5,
1870 ARIZONA_FLL1_OUTDIV_MASK,
1871 cfg->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
1872 regmap_update_bits(arizona->regmap, base + 0x9,
1873 ARIZONA_FLL1_GAIN_MASK,
1874 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
1875 }
Mark Brown8f113d72013-03-05 12:08:57 +08001876
Mark Brown3c43c692013-12-12 00:49:22 +00001877 regmap_update_bits_async(arizona->regmap, base + 2,
1878 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
1879 ARIZONA_FLL1_CTRL_UPD | cfg->n);
Mark Brown07ed8732012-06-18 21:08:44 +01001880}
1881
Charles Keepaxc393aca2014-07-09 17:41:47 +01001882static int arizona_is_enabled_fll(struct arizona_fll *fll)
Charles Keepaxd122d6c2013-02-20 17:28:36 +00001883{
1884 struct arizona *arizona = fll->arizona;
1885 unsigned int reg;
1886 int ret;
1887
1888 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
1889 if (ret != 0) {
1890 arizona_fll_err(fll, "Failed to read current state: %d\n",
1891 ret);
1892 return ret;
1893 }
1894
1895 return reg & ARIZONA_FLL1_ENA;
1896}
1897
Charles Keepaxc393aca2014-07-09 17:41:47 +01001898static int arizona_enable_fll(struct arizona_fll *fll)
Charles Keepax35722812013-02-20 17:28:38 +00001899{
1900 struct arizona *arizona = fll->arizona;
1901 int ret;
Charles Keepax49c60542013-09-16 15:34:35 +01001902 bool use_sync = false;
Charles Keepaxc393aca2014-07-09 17:41:47 +01001903 int already_enabled = arizona_is_enabled_fll(fll);
Charles Keepax23f785a82014-03-07 16:34:20 +00001904 struct arizona_fll_cfg cfg;
Charles Keepax35722812013-02-20 17:28:38 +00001905
Charles Keepaxc393aca2014-07-09 17:41:47 +01001906 if (already_enabled < 0)
1907 return already_enabled;
1908
Charles Keepaxc8badda2014-07-09 17:41:49 +01001909 if (already_enabled) {
1910 /* Facilitate smooth refclk across the transition */
1911 regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x7,
1912 ARIZONA_FLL1_GAIN_MASK, 0);
1913 regmap_update_bits_async(fll->arizona->regmap, fll->base + 1,
1914 ARIZONA_FLL1_FREERUN,
1915 ARIZONA_FLL1_FREERUN);
1916 }
1917
Mark Brownff680a12013-03-04 16:00:19 +08001918 /*
1919 * If we have both REFCLK and SYNCCLK then enable both,
1920 * otherwise apply the SYNCCLK settings to REFCLK.
1921 */
Charles Keepax49c60542013-09-16 15:34:35 +01001922 if (fll->ref_src >= 0 && fll->ref_freq &&
1923 fll->ref_src != fll->sync_src) {
Charles Keepaxd0800342014-03-07 16:34:25 +00001924 arizona_calc_fll(fll, &cfg, fll->ref_freq, false);
Charles Keepax35722812013-02-20 17:28:38 +00001925
Charles Keepax23f785a82014-03-07 16:34:20 +00001926 arizona_apply_fll(arizona, fll->base, &cfg, fll->ref_src,
Mark Brown8f113d72013-03-05 12:08:57 +08001927 false);
Charles Keepax49c60542013-09-16 15:34:35 +01001928 if (fll->sync_src >= 0) {
Charles Keepaxd0800342014-03-07 16:34:25 +00001929 arizona_calc_fll(fll, &cfg, fll->sync_freq, true);
Charles Keepax23f785a82014-03-07 16:34:20 +00001930
1931 arizona_apply_fll(arizona, fll->base + 0x10, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08001932 fll->sync_src, true);
Charles Keepax49c60542013-09-16 15:34:35 +01001933 use_sync = true;
1934 }
Mark Brownff680a12013-03-04 16:00:19 +08001935 } else if (fll->sync_src >= 0) {
Charles Keepaxd0800342014-03-07 16:34:25 +00001936 arizona_calc_fll(fll, &cfg, fll->sync_freq, false);
Mark Brownff680a12013-03-04 16:00:19 +08001937
Charles Keepax23f785a82014-03-07 16:34:20 +00001938 arizona_apply_fll(arizona, fll->base, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08001939 fll->sync_src, false);
Mark Browneca2e8e2013-03-06 00:09:59 +08001940
Mark Brown3c43c692013-12-12 00:49:22 +00001941 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
1942 ARIZONA_FLL1_SYNC_ENA, 0);
Mark Brownff680a12013-03-04 16:00:19 +08001943 } else {
1944 arizona_fll_err(fll, "No clocks provided\n");
Charles Keepaxc393aca2014-07-09 17:41:47 +01001945 return -EINVAL;
Mark Brownff680a12013-03-04 16:00:19 +08001946 }
Charles Keepax35722812013-02-20 17:28:38 +00001947
Mark Brown576411be2013-03-05 12:07:16 +08001948 /*
1949 * Increase the bandwidth if we're not using a low frequency
1950 * sync source.
1951 */
Charles Keepax49c60542013-09-16 15:34:35 +01001952 if (use_sync && fll->sync_freq > 100000)
Mark Brown3c43c692013-12-12 00:49:22 +00001953 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
1954 ARIZONA_FLL1_SYNC_BW, 0);
Mark Brown576411be2013-03-05 12:07:16 +08001955 else
Mark Brown3c43c692013-12-12 00:49:22 +00001956 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
1957 ARIZONA_FLL1_SYNC_BW,
1958 ARIZONA_FLL1_SYNC_BW);
Mark Brown576411be2013-03-05 12:07:16 +08001959
Charles Keepaxc393aca2014-07-09 17:41:47 +01001960 if (!already_enabled)
Charles Keepax35722812013-02-20 17:28:38 +00001961 pm_runtime_get(arizona->dev);
1962
1963 /* Clear any pending completions */
1964 try_wait_for_completion(&fll->ok);
1965
Mark Brown3c43c692013-12-12 00:49:22 +00001966 regmap_update_bits_async(arizona->regmap, fll->base + 1,
Mark Brown3c43c692013-12-12 00:49:22 +00001967 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
Charles Keepax49c60542013-09-16 15:34:35 +01001968 if (use_sync)
Mark Brown3c43c692013-12-12 00:49:22 +00001969 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
1970 ARIZONA_FLL1_SYNC_ENA,
1971 ARIZONA_FLL1_SYNC_ENA);
Charles Keepax35722812013-02-20 17:28:38 +00001972
Charles Keepaxc8badda2014-07-09 17:41:49 +01001973 if (already_enabled)
1974 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1975 ARIZONA_FLL1_FREERUN, 0);
1976
Charles Keepax35722812013-02-20 17:28:38 +00001977 ret = wait_for_completion_timeout(&fll->ok,
1978 msecs_to_jiffies(250));
1979 if (ret == 0)
1980 arizona_fll_warn(fll, "Timed out waiting for lock\n");
Charles Keepaxc393aca2014-07-09 17:41:47 +01001981
1982 return 0;
Charles Keepax35722812013-02-20 17:28:38 +00001983}
1984
Charles Keepax76040542013-02-20 17:28:37 +00001985static void arizona_disable_fll(struct arizona_fll *fll)
1986{
1987 struct arizona *arizona = fll->arizona;
1988 bool change;
1989
Mark Brown3c43c692013-12-12 00:49:22 +00001990 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1991 ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
Charles Keepax76040542013-02-20 17:28:37 +00001992 regmap_update_bits_check(arizona->regmap, fll->base + 1,
1993 ARIZONA_FLL1_ENA, 0, &change);
1994 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1995 ARIZONA_FLL1_SYNC_ENA, 0);
Charles Keepax5e39a502014-07-09 17:41:48 +01001996 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1997 ARIZONA_FLL1_FREERUN, 0);
Charles Keepax76040542013-02-20 17:28:37 +00001998
1999 if (change)
2000 pm_runtime_put_autosuspend(arizona->dev);
2001}
2002
Charles Keepaxee929a92013-02-20 17:28:40 +00002003int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
2004 unsigned int Fref, unsigned int Fout)
2005{
Charles Keepaxc393aca2014-07-09 17:41:47 +01002006 int ret = 0;
Charles Keepaxee929a92013-02-20 17:28:40 +00002007
Charles Keepax1c5617f2013-02-22 17:10:37 +00002008 if (fll->ref_src == source && fll->ref_freq == Fref)
Charles Keepaxee929a92013-02-20 17:28:40 +00002009 return 0;
2010
Charles Keepax23f785a82014-03-07 16:34:20 +00002011 if (fll->fout && Fref > 0) {
2012 ret = arizona_validate_fll(fll, Fref, fll->fout);
2013 if (ret != 0)
2014 return ret;
Charles Keepaxee929a92013-02-20 17:28:40 +00002015 }
2016
2017 fll->ref_src = source;
2018 fll->ref_freq = Fref;
Charles Keepaxee929a92013-02-20 17:28:40 +00002019
Mark Brown86cd6842013-03-07 16:14:04 +08002020 if (fll->fout && Fref > 0) {
Charles Keepaxc393aca2014-07-09 17:41:47 +01002021 ret = arizona_enable_fll(fll);
Charles Keepaxee929a92013-02-20 17:28:40 +00002022 }
2023
Charles Keepaxc393aca2014-07-09 17:41:47 +01002024 return ret;
Charles Keepaxee929a92013-02-20 17:28:40 +00002025}
2026EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
2027
Mark Brown07ed8732012-06-18 21:08:44 +01002028int arizona_set_fll(struct arizona_fll *fll, int source,
2029 unsigned int Fref, unsigned int Fout)
2030{
Charles Keepaxc393aca2014-07-09 17:41:47 +01002031 int ret = 0;
Mark Brown07ed8732012-06-18 21:08:44 +01002032
Mark Brownff680a12013-03-04 16:00:19 +08002033 if (fll->sync_src == source &&
2034 fll->sync_freq == Fref && fll->fout == Fout)
2035 return 0;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00002036
Mark Brownff680a12013-03-04 16:00:19 +08002037 if (Fout) {
2038 if (fll->ref_src >= 0) {
Charles Keepax23f785a82014-03-07 16:34:20 +00002039 ret = arizona_validate_fll(fll, fll->ref_freq, Fout);
Charles Keepax9e359c62013-02-20 17:28:35 +00002040 if (ret != 0)
2041 return ret;
2042 }
2043
Charles Keepax23f785a82014-03-07 16:34:20 +00002044 ret = arizona_validate_fll(fll, Fref, Fout);
Mark Brownff680a12013-03-04 16:00:19 +08002045 if (ret != 0)
2046 return ret;
Charles Keepax9e359c62013-02-20 17:28:35 +00002047 }
Mark Brownff680a12013-03-04 16:00:19 +08002048
2049 fll->sync_src = source;
2050 fll->sync_freq = Fref;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00002051 fll->fout = Fout;
Charles Keepax9e359c62013-02-20 17:28:35 +00002052
Charles Keepax613124c2014-07-09 17:41:46 +01002053 if (Fout)
Charles Keepaxc393aca2014-07-09 17:41:47 +01002054 ret = arizona_enable_fll(fll);
Charles Keepax613124c2014-07-09 17:41:46 +01002055 else
Charles Keepax76040542013-02-20 17:28:37 +00002056 arizona_disable_fll(fll);
Mark Brown07ed8732012-06-18 21:08:44 +01002057
Charles Keepaxc393aca2014-07-09 17:41:47 +01002058 return ret;
Mark Brown07ed8732012-06-18 21:08:44 +01002059}
2060EXPORT_SYMBOL_GPL(arizona_set_fll);
2061
2062int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
2063 int ok_irq, struct arizona_fll *fll)
2064{
2065 int ret;
Charles Keepax19b34bd2013-02-20 17:28:34 +00002066 unsigned int val;
Mark Brown07ed8732012-06-18 21:08:44 +01002067
Mark Brown07ed8732012-06-18 21:08:44 +01002068 init_completion(&fll->ok);
2069
2070 fll->id = id;
2071 fll->base = base;
2072 fll->arizona = arizona;
Charles Keepaxf3f11632013-02-20 17:28:41 +00002073 fll->sync_src = ARIZONA_FLL_SRC_NONE;
Mark Brown07ed8732012-06-18 21:08:44 +01002074
Charles Keepax19b34bd2013-02-20 17:28:34 +00002075 /* Configure default refclk to 32kHz if we have one */
2076 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
2077 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
2078 case ARIZONA_CLK_SRC_MCLK1:
2079 case ARIZONA_CLK_SRC_MCLK2:
2080 fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK;
2081 break;
2082 default:
Charles Keepaxf3f11632013-02-20 17:28:41 +00002083 fll->ref_src = ARIZONA_FLL_SRC_NONE;
Charles Keepax19b34bd2013-02-20 17:28:34 +00002084 }
2085 fll->ref_freq = 32768;
2086
Mark Brown07ed8732012-06-18 21:08:44 +01002087 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
2088 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
2089 "FLL%d clock OK", id);
2090
Mark Brown07ed8732012-06-18 21:08:44 +01002091 ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
2092 arizona_fll_clock_ok, fll);
2093 if (ret != 0) {
2094 dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
2095 id, ret);
2096 }
2097
Charles Keepaxe31c1942013-01-07 16:41:45 +00002098 regmap_update_bits(arizona->regmap, fll->base + 1,
2099 ARIZONA_FLL1_FREERUN, 0);
2100
Mark Brown07ed8732012-06-18 21:08:44 +01002101 return 0;
2102}
2103EXPORT_SYMBOL_GPL(arizona_init_fll);
2104
Mark Brownbc9ab6d2013-01-04 19:31:00 +00002105/**
2106 * arizona_set_output_mode - Set the mode of the specified output
2107 *
2108 * @codec: Device to configure
2109 * @output: Output number
2110 * @diff: True to set the output to differential mode
2111 *
2112 * Some systems use external analogue switches to connect more
2113 * analogue devices to the CODEC than are supported by the device. In
2114 * some systems this requires changing the switched output from single
2115 * ended to differential mode dynamically at runtime, an operation
2116 * supported using this function.
2117 *
2118 * Most systems have a single static configuration and should use
2119 * platform data instead.
2120 */
2121int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
2122{
2123 unsigned int reg, val;
2124
2125 if (output < 1 || output > 6)
2126 return -EINVAL;
2127
2128 reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
2129
2130 if (diff)
2131 val = ARIZONA_OUT1_MONO;
2132 else
2133 val = 0;
2134
2135 return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val);
2136}
2137EXPORT_SYMBOL_GPL(arizona_set_output_mode);
2138
Mark Brown07ed8732012-06-18 21:08:44 +01002139MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
2140MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
2141MODULE_LICENSE("GPL");