blob: 9e203eff6860be9b28fa8a17109ae4f0e3daae45 [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) {
740 case SND_SOC_DAPM_POST_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 msleep(17);
749 break;
750
751 default:
752 break;
753 }
754 break;
Charles Keepax054e1b42015-01-20 16:31:50 +0000755 case SND_SOC_DAPM_PRE_PMD:
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:
763 priv->out_down_pending++;
764 priv->out_down_delay++;
765 break;
766 default:
767 break;
768 }
769 break;
770 case SND_SOC_DAPM_POST_PMD:
771 switch (w->shift) {
772 case ARIZONA_OUT1L_ENA_SHIFT:
773 case ARIZONA_OUT1R_ENA_SHIFT:
774 case ARIZONA_OUT2L_ENA_SHIFT:
775 case ARIZONA_OUT2R_ENA_SHIFT:
776 case ARIZONA_OUT3L_ENA_SHIFT:
777 case ARIZONA_OUT3R_ENA_SHIFT:
778 priv->out_down_pending--;
779 if (!priv->out_down_pending) {
780 msleep(priv->out_down_delay);
781 priv->out_down_delay = 0;
782 }
783 break;
784 default:
785 break;
786 }
787 break;
Mark Brown1a2c7d52013-03-24 22:50:23 +0000788 }
789
Mark Brown07ed8732012-06-18 21:08:44 +0100790 return 0;
791}
792EXPORT_SYMBOL_GPL(arizona_out_ev);
793
Mark Brownf607e312013-02-22 18:36:53 +0000794int arizona_hp_ev(struct snd_soc_dapm_widget *w,
795 struct snd_kcontrol *kcontrol,
796 int event)
797{
798 struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
Mark Brown3c43c692013-12-12 00:49:22 +0000799 struct arizona *arizona = priv->arizona;
Mark Brownf607e312013-02-22 18:36:53 +0000800 unsigned int mask = 1 << w->shift;
801 unsigned int val;
802
803 switch (event) {
804 case SND_SOC_DAPM_POST_PMU:
805 val = mask;
806 break;
807 case SND_SOC_DAPM_PRE_PMD:
808 val = 0;
809 break;
Charles Keepax054e1b42015-01-20 16:31:50 +0000810 case SND_SOC_DAPM_POST_PMD:
811 return arizona_out_ev(w, kcontrol, event);
Mark Brownf607e312013-02-22 18:36:53 +0000812 default:
813 return -EINVAL;
814 }
815
816 /* Store the desired state for the HP outputs */
817 priv->arizona->hp_ena &= ~mask;
818 priv->arizona->hp_ena |= val;
819
820 /* Force off if HPDET magic is active */
821 if (priv->arizona->hpdet_magic)
822 val = 0;
823
Mark Brown3c43c692013-12-12 00:49:22 +0000824 regmap_update_bits_async(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1,
825 mask, val);
Mark Brownf607e312013-02-22 18:36:53 +0000826
827 return arizona_out_ev(w, kcontrol, event);
828}
829EXPORT_SYMBOL_GPL(arizona_hp_ev);
830
Mark Browncbd840d2012-08-08 17:52:44 +0100831static unsigned int arizona_sysclk_48k_rates[] = {
832 6144000,
833 12288000,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000834 24576000,
Mark Browncbd840d2012-08-08 17:52:44 +0100835 49152000,
Mark Brownaeaeee12012-09-26 17:50:02 +0100836 73728000,
837 98304000,
838 147456000,
Mark Browncbd840d2012-08-08 17:52:44 +0100839};
840
841static unsigned int arizona_sysclk_44k1_rates[] = {
842 5644800,
843 11289600,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000844 22579200,
Mark Browncbd840d2012-08-08 17:52:44 +0100845 45158400,
Mark Brownaeaeee12012-09-26 17:50:02 +0100846 67737600,
847 90316800,
848 135475200,
Mark Browncbd840d2012-08-08 17:52:44 +0100849};
850
851static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
852 unsigned int freq)
853{
854 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
855 unsigned int reg;
856 unsigned int *rates;
857 int ref, div, refclk;
858
859 switch (clk) {
860 case ARIZONA_CLK_OPCLK:
861 reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
862 refclk = priv->sysclk;
863 break;
864 case ARIZONA_CLK_ASYNC_OPCLK:
865 reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
866 refclk = priv->asyncclk;
867 break;
868 default:
869 return -EINVAL;
870 }
871
872 if (refclk % 8000)
873 rates = arizona_sysclk_44k1_rates;
874 else
875 rates = arizona_sysclk_48k_rates;
876
877 for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) &&
878 rates[ref] <= refclk; ref++) {
879 div = 1;
880 while (rates[ref] / div >= freq && div < 32) {
881 if (rates[ref] / div == freq) {
882 dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
883 freq);
884 snd_soc_update_bits(codec, reg,
885 ARIZONA_OPCLK_DIV_MASK |
886 ARIZONA_OPCLK_SEL_MASK,
887 (div <<
888 ARIZONA_OPCLK_DIV_SHIFT) |
889 ref);
890 return 0;
891 }
892 div++;
893 }
894 }
895
896 dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
897 return -EINVAL;
898}
899
Mark Brown07ed8732012-06-18 21:08:44 +0100900int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
901 int source, unsigned int freq, int dir)
902{
903 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
904 struct arizona *arizona = priv->arizona;
905 char *name;
906 unsigned int reg;
907 unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
908 unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
909 unsigned int *clk;
910
911 switch (clk_id) {
912 case ARIZONA_CLK_SYSCLK:
913 name = "SYSCLK";
914 reg = ARIZONA_SYSTEM_CLOCK_1;
915 clk = &priv->sysclk;
916 mask |= ARIZONA_SYSCLK_FRAC;
917 break;
918 case ARIZONA_CLK_ASYNCCLK:
919 name = "ASYNCCLK";
920 reg = ARIZONA_ASYNC_CLOCK_1;
921 clk = &priv->asyncclk;
922 break;
Mark Browncbd840d2012-08-08 17:52:44 +0100923 case ARIZONA_CLK_OPCLK:
924 case ARIZONA_CLK_ASYNC_OPCLK:
925 return arizona_set_opclk(codec, clk_id, freq);
Mark Brown07ed8732012-06-18 21:08:44 +0100926 default:
927 return -EINVAL;
928 }
929
930 switch (freq) {
931 case 5644800:
932 case 6144000:
933 break;
934 case 11289600:
935 case 12288000:
Mark Brown3f341f72013-03-08 15:22:29 +0800936 val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100937 break;
938 case 22579200:
939 case 24576000:
Mark Brown3f341f72013-03-08 15:22:29 +0800940 val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100941 break;
942 case 45158400:
943 case 49152000:
Mark Brown3f341f72013-03-08 15:22:29 +0800944 val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100945 break;
Mark Brown38113362012-11-26 16:01:37 +0000946 case 67737600:
947 case 73728000:
Mark Brown3f341f72013-03-08 15:22:29 +0800948 val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000949 break;
950 case 90316800:
951 case 98304000:
Mark Brown3f341f72013-03-08 15:22:29 +0800952 val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000953 break;
954 case 135475200:
955 case 147456000:
Mark Brown3f341f72013-03-08 15:22:29 +0800956 val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000957 break;
Mark Brownf2c26d42013-01-21 16:09:36 +0900958 case 0:
959 dev_dbg(arizona->dev, "%s cleared\n", name);
960 *clk = freq;
961 return 0;
Mark Brown07ed8732012-06-18 21:08:44 +0100962 default:
963 return -EINVAL;
964 }
965
966 *clk = freq;
967
968 if (freq % 6144000)
969 val |= ARIZONA_SYSCLK_FRAC;
970
971 dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
972
973 return regmap_update_bits(arizona->regmap, reg, mask, val);
974}
975EXPORT_SYMBOL_GPL(arizona_set_sysclk);
976
977static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
978{
979 struct snd_soc_codec *codec = dai->codec;
Mark Brown3c43c692013-12-12 00:49:22 +0000980 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
981 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +0100982 int lrclk, bclk, mode, base;
983
984 base = dai->driver->base;
985
986 lrclk = 0;
987 bclk = 0;
988
989 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
990 case SND_SOC_DAIFMT_DSP_A:
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +0000991 mode = ARIZONA_FMT_DSP_MODE_A;
992 break;
993 case SND_SOC_DAIFMT_DSP_B:
994 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
995 != SND_SOC_DAIFMT_CBM_CFM) {
996 arizona_aif_err(dai, "DSP_B not valid in slave mode\n");
997 return -EINVAL;
998 }
999 mode = ARIZONA_FMT_DSP_MODE_B;
Mark Brown07ed8732012-06-18 21:08:44 +01001000 break;
Mark Brown07ed8732012-06-18 21:08:44 +01001001 case SND_SOC_DAIFMT_I2S:
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001002 mode = ARIZONA_FMT_I2S_MODE;
1003 break;
1004 case SND_SOC_DAIFMT_LEFT_J:
1005 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
1006 != SND_SOC_DAIFMT_CBM_CFM) {
1007 arizona_aif_err(dai, "LEFT_J not valid in slave mode\n");
1008 return -EINVAL;
1009 }
1010 mode = ARIZONA_FMT_LEFT_JUSTIFIED_MODE;
Mark Brown07ed8732012-06-18 21:08:44 +01001011 break;
Mark Brown07ed8732012-06-18 21:08:44 +01001012 default:
1013 arizona_aif_err(dai, "Unsupported DAI format %d\n",
1014 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
1015 return -EINVAL;
1016 }
1017
1018 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
1019 case SND_SOC_DAIFMT_CBS_CFS:
1020 break;
1021 case SND_SOC_DAIFMT_CBS_CFM:
1022 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
1023 break;
1024 case SND_SOC_DAIFMT_CBM_CFS:
1025 bclk |= ARIZONA_AIF1_BCLK_MSTR;
1026 break;
1027 case SND_SOC_DAIFMT_CBM_CFM:
1028 bclk |= ARIZONA_AIF1_BCLK_MSTR;
1029 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
1030 break;
1031 default:
1032 arizona_aif_err(dai, "Unsupported master mode %d\n",
1033 fmt & SND_SOC_DAIFMT_MASTER_MASK);
1034 return -EINVAL;
1035 }
1036
1037 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1038 case SND_SOC_DAIFMT_NB_NF:
1039 break;
1040 case SND_SOC_DAIFMT_IB_IF:
1041 bclk |= ARIZONA_AIF1_BCLK_INV;
1042 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
1043 break;
1044 case SND_SOC_DAIFMT_IB_NF:
1045 bclk |= ARIZONA_AIF1_BCLK_INV;
1046 break;
1047 case SND_SOC_DAIFMT_NB_IF:
1048 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
1049 break;
1050 default:
1051 return -EINVAL;
1052 }
1053
Mark Brown3c43c692013-12-12 00:49:22 +00001054 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_BCLK_CTRL,
1055 ARIZONA_AIF1_BCLK_INV |
1056 ARIZONA_AIF1_BCLK_MSTR,
1057 bclk);
1058 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_TX_PIN_CTRL,
1059 ARIZONA_AIF1TX_LRCLK_INV |
1060 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
1061 regmap_update_bits_async(arizona->regmap,
1062 base + ARIZONA_AIF_RX_PIN_CTRL,
1063 ARIZONA_AIF1RX_LRCLK_INV |
1064 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
1065 regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FORMAT,
1066 ARIZONA_AIF1_FMT_MASK, mode);
Mark Brown07ed8732012-06-18 21:08:44 +01001067
1068 return 0;
1069}
1070
Mark Brown949e6bc2012-07-04 18:58:04 +01001071static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001072 -1,
1073 48000,
1074 64000,
1075 96000,
1076 128000,
1077 192000,
1078 256000,
1079 384000,
1080 512000,
1081 768000,
1082 1024000,
1083 1536000,
1084 2048000,
1085 3072000,
1086 4096000,
1087 6144000,
1088 8192000,
1089 12288000,
1090 24576000,
1091};
1092
Mark Brown5b2eec32012-07-04 17:32:05 +01001093static const unsigned int arizona_48k_rates[] = {
1094 12000,
1095 24000,
1096 48000,
1097 96000,
1098 192000,
1099 384000,
1100 768000,
1101 4000,
1102 8000,
1103 16000,
1104 32000,
1105 64000,
1106 128000,
1107 256000,
1108 512000,
1109};
1110
1111static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = {
1112 .count = ARRAY_SIZE(arizona_48k_rates),
1113 .list = arizona_48k_rates,
1114};
1115
Mark Brown949e6bc2012-07-04 18:58:04 +01001116static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001117 -1,
1118 44100,
1119 58800,
1120 88200,
1121 117600,
1122 177640,
1123 235200,
1124 352800,
1125 470400,
1126 705600,
1127 940800,
1128 1411200,
1129 1881600,
Heather Lomond4758be32012-09-05 05:02:10 -04001130 2822400,
Mark Brown07ed8732012-06-18 21:08:44 +01001131 3763200,
1132 5644800,
1133 7526400,
1134 11289600,
1135 22579200,
1136};
1137
Mark Brown5b2eec32012-07-04 17:32:05 +01001138static const unsigned int arizona_44k1_rates[] = {
1139 11025,
1140 22050,
1141 44100,
1142 88200,
1143 176400,
1144 352800,
1145 705600,
1146};
1147
1148static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = {
1149 .count = ARRAY_SIZE(arizona_44k1_rates),
1150 .list = arizona_44k1_rates,
1151};
1152
Mark Brown07ed8732012-06-18 21:08:44 +01001153static int arizona_sr_vals[] = {
1154 0,
1155 12000,
1156 24000,
1157 48000,
1158 96000,
1159 192000,
1160 384000,
1161 768000,
1162 0,
1163 11025,
1164 22050,
1165 44100,
1166 88200,
1167 176400,
1168 352800,
1169 705600,
1170 4000,
1171 8000,
1172 16000,
1173 32000,
1174 64000,
1175 128000,
1176 256000,
1177 512000,
1178};
1179
Mark Brown5b2eec32012-07-04 17:32:05 +01001180static int arizona_startup(struct snd_pcm_substream *substream,
1181 struct snd_soc_dai *dai)
1182{
1183 struct snd_soc_codec *codec = dai->codec;
1184 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1185 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
1186 const struct snd_pcm_hw_constraint_list *constraint;
1187 unsigned int base_rate;
1188
1189 switch (dai_priv->clk) {
1190 case ARIZONA_CLK_SYSCLK:
1191 base_rate = priv->sysclk;
1192 break;
1193 case ARIZONA_CLK_ASYNCCLK:
1194 base_rate = priv->asyncclk;
1195 break;
1196 default:
1197 return 0;
1198 }
1199
Mark Brownf2c26d42013-01-21 16:09:36 +09001200 if (base_rate == 0)
1201 return 0;
1202
Mark Brown5b2eec32012-07-04 17:32:05 +01001203 if (base_rate % 8000)
1204 constraint = &arizona_44k1_constraint;
1205 else
1206 constraint = &arizona_48k_constraint;
1207
1208 return snd_pcm_hw_constraint_list(substream->runtime, 0,
1209 SNDRV_PCM_HW_PARAM_RATE,
1210 constraint);
1211}
1212
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001213static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec,
1214 unsigned int rate)
1215{
1216 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1217 struct arizona *arizona = priv->arizona;
1218 struct reg_default dac_comp[] = {
1219 { 0x80, 0x3 },
1220 { ARIZONA_DAC_COMP_1, 0 },
1221 { ARIZONA_DAC_COMP_2, 0 },
1222 { 0x80, 0x0 },
1223 };
1224
Lars-Peter Clausend74bcaa2014-11-09 17:00:59 +01001225 mutex_lock(&arizona->dac_comp_lock);
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001226
1227 dac_comp[1].def = arizona->dac_comp_coeff;
1228 if (rate >= 176400)
1229 dac_comp[2].def = arizona->dac_comp_enabled;
1230
Lars-Peter Clausend74bcaa2014-11-09 17:00:59 +01001231 mutex_unlock(&arizona->dac_comp_lock);
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001232
1233 regmap_multi_reg_write(arizona->regmap,
1234 dac_comp,
1235 ARRAY_SIZE(dac_comp));
1236}
1237
Mark Brownb272efc2012-10-10 15:10:08 +09001238static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
1239 struct snd_pcm_hw_params *params,
1240 struct snd_soc_dai *dai)
Mark Brown07ed8732012-06-18 21:08:44 +01001241{
1242 struct snd_soc_codec *codec = dai->codec;
Mark Brownc013b272012-07-04 20:05:57 +01001243 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1244 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown07ed8732012-06-18 21:08:44 +01001245 int base = dai->driver->base;
Mark Brownb272efc2012-10-10 15:10:08 +09001246 int i, sr_val;
1247
1248 /*
1249 * We will need to be more flexible than this in future,
1250 * currently we use a single sample rate for SYSCLK.
1251 */
1252 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
1253 if (arizona_sr_vals[i] == params_rate(params))
1254 break;
1255 if (i == ARRAY_SIZE(arizona_sr_vals)) {
1256 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1257 params_rate(params));
1258 return -EINVAL;
1259 }
1260 sr_val = i;
1261
1262 switch (dai_priv->clk) {
1263 case ARIZONA_CLK_SYSCLK:
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001264 switch (priv->arizona->type) {
1265 case WM5102:
1266 arizona_wm5102_set_dac_comp(codec,
1267 params_rate(params));
1268 break;
1269 default:
1270 break;
1271 }
1272
Mark Brownb272efc2012-10-10 15:10:08 +09001273 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
1274 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
1275 if (base)
1276 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1277 ARIZONA_AIF1_RATE_MASK, 0);
1278 break;
1279 case ARIZONA_CLK_ASYNCCLK:
1280 snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
Charles Keepaxc24084d2014-09-01 15:48:52 +01001281 ARIZONA_ASYNC_SAMPLE_RATE_1_MASK, sr_val);
Mark Brownb272efc2012-10-10 15:10:08 +09001282 if (base)
1283 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1284 ARIZONA_AIF1_RATE_MASK,
1285 8 << ARIZONA_AIF1_RATE_SHIFT);
1286 break;
1287 default:
1288 arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
1289 return -EINVAL;
1290 }
1291
1292 return 0;
1293}
1294
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001295static bool arizona_aif_cfg_changed(struct snd_soc_codec *codec,
1296 int base, int bclk, int lrclk, int frame)
1297{
1298 int val;
1299
1300 val = snd_soc_read(codec, base + ARIZONA_AIF_BCLK_CTRL);
1301 if (bclk != (val & ARIZONA_AIF1_BCLK_FREQ_MASK))
1302 return true;
1303
1304 val = snd_soc_read(codec, base + ARIZONA_AIF_TX_BCLK_RATE);
1305 if (lrclk != (val & ARIZONA_AIF1TX_BCPF_MASK))
1306 return true;
1307
1308 val = snd_soc_read(codec, base + ARIZONA_AIF_FRAME_CTRL_1);
1309 if (frame != (val & (ARIZONA_AIF1TX_WL_MASK |
1310 ARIZONA_AIF1TX_SLOT_LEN_MASK)))
1311 return true;
1312
1313 return false;
1314}
1315
Mark Brown07ed8732012-06-18 21:08:44 +01001316static int arizona_hw_params(struct snd_pcm_substream *substream,
1317 struct snd_pcm_hw_params *params,
1318 struct snd_soc_dai *dai)
1319{
1320 struct snd_soc_codec *codec = dai->codec;
1321 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brownc94aa302013-01-17 16:35:14 +09001322 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +01001323 int base = dai->driver->base;
1324 const int *rates;
Mark Brown76bf9692013-03-05 14:17:47 +08001325 int i, ret, val;
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001326 int channels = params_channels(params);
Mark Brownc94aa302013-01-17 16:35:14 +09001327 int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001328 int tdm_width = arizona->tdm_width[dai->id - 1];
1329 int tdm_slots = arizona->tdm_slots[dai->id - 1];
Mark Brownc94aa302013-01-17 16:35:14 +09001330 int bclk, lrclk, wl, frame, bclk_target;
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001331 bool reconfig;
1332 unsigned int aif_tx_state, aif_rx_state;
Mark Brown07ed8732012-06-18 21:08:44 +01001333
1334 if (params_rate(params) % 8000)
Mark Brown949e6bc2012-07-04 18:58:04 +01001335 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001336 else
Mark Brown949e6bc2012-07-04 18:58:04 +01001337 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001338
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001339 wl = snd_pcm_format_width(params_format(params));
1340
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001341 if (tdm_slots) {
1342 arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n",
1343 tdm_slots, tdm_width);
1344 bclk_target = tdm_slots * tdm_width * params_rate(params);
1345 channels = tdm_slots;
1346 } else {
1347 bclk_target = snd_soc_params_to_bclk(params);
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001348 tdm_width = wl;
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001349 }
1350
1351 if (chan_limit && chan_limit < channels) {
Mark Brownc94aa302013-01-17 16:35:14 +09001352 arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001353 bclk_target /= channels;
Mark Brownc94aa302013-01-17 16:35:14 +09001354 bclk_target *= chan_limit;
1355 }
1356
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001357 /* Force multiple of 2 channels for I2S mode */
Mark Brown76bf9692013-03-05 14:17:47 +08001358 val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001359 val &= ARIZONA_AIF1_FMT_MASK;
1360 if ((channels & 1) && (val == ARIZONA_FMT_I2S_MODE)) {
Mark Brown76bf9692013-03-05 14:17:47 +08001361 arizona_aif_dbg(dai, "Forcing stereo mode\n");
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001362 bclk_target /= channels;
1363 bclk_target *= channels + 1;
Mark Brown76bf9692013-03-05 14:17:47 +08001364 }
1365
Mark Brown949e6bc2012-07-04 18:58:04 +01001366 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brownc94aa302013-01-17 16:35:14 +09001367 if (rates[i] >= bclk_target &&
Mark Brown50017652012-07-04 19:07:09 +01001368 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +01001369 bclk = i;
1370 break;
1371 }
1372 }
Mark Brown949e6bc2012-07-04 18:58:04 +01001373 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001374 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1375 params_rate(params));
1376 return -EINVAL;
1377 }
1378
Mark Brownb59e0f82013-01-17 14:15:59 +09001379 lrclk = rates[bclk] / params_rate(params);
Mark Brown07ed8732012-06-18 21:08:44 +01001380
1381 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
1382 rates[bclk], rates[bclk] / lrclk);
1383
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001384 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | tdm_width;
Mark Brown07ed8732012-06-18 21:08:44 +01001385
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001386 reconfig = arizona_aif_cfg_changed(codec, base, bclk, lrclk, frame);
1387
1388 if (reconfig) {
1389 /* Save AIF TX/RX state */
1390 aif_tx_state = snd_soc_read(codec,
1391 base + ARIZONA_AIF_TX_ENABLES);
1392 aif_rx_state = snd_soc_read(codec,
1393 base + ARIZONA_AIF_RX_ENABLES);
1394 /* Disable AIF TX/RX before reconfiguring it */
1395 regmap_update_bits_async(arizona->regmap,
1396 base + ARIZONA_AIF_TX_ENABLES, 0xff, 0x0);
1397 regmap_update_bits(arizona->regmap,
1398 base + ARIZONA_AIF_RX_ENABLES, 0xff, 0x0);
1399 }
1400
Mark Brownb272efc2012-10-10 15:10:08 +09001401 ret = arizona_hw_params_rate(substream, params, dai);
1402 if (ret != 0)
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001403 goto restore_aif;
Mark Brownc013b272012-07-04 20:05:57 +01001404
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001405 if (reconfig) {
1406 regmap_update_bits_async(arizona->regmap,
1407 base + ARIZONA_AIF_BCLK_CTRL,
1408 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
1409 regmap_update_bits_async(arizona->regmap,
1410 base + ARIZONA_AIF_TX_BCLK_RATE,
1411 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
1412 regmap_update_bits_async(arizona->regmap,
1413 base + ARIZONA_AIF_RX_BCLK_RATE,
1414 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
1415 regmap_update_bits_async(arizona->regmap,
1416 base + ARIZONA_AIF_FRAME_CTRL_1,
1417 ARIZONA_AIF1TX_WL_MASK |
1418 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
1419 regmap_update_bits(arizona->regmap,
1420 base + ARIZONA_AIF_FRAME_CTRL_2,
1421 ARIZONA_AIF1RX_WL_MASK |
1422 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
1423 }
Mark Brown07ed8732012-06-18 21:08:44 +01001424
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001425restore_aif:
1426 if (reconfig) {
1427 /* Restore AIF TX/RX state */
1428 regmap_update_bits_async(arizona->regmap,
1429 base + ARIZONA_AIF_TX_ENABLES,
1430 0xff, aif_tx_state);
1431 regmap_update_bits(arizona->regmap,
1432 base + ARIZONA_AIF_RX_ENABLES,
1433 0xff, aif_rx_state);
1434 }
1435 return ret;
Mark Brown07ed8732012-06-18 21:08:44 +01001436}
1437
Mark Brown410837a2012-07-05 17:26:59 +01001438static const char *arizona_dai_clk_str(int clk_id)
1439{
1440 switch (clk_id) {
1441 case ARIZONA_CLK_SYSCLK:
1442 return "SYSCLK";
1443 case ARIZONA_CLK_ASYNCCLK:
1444 return "ASYNCCLK";
1445 default:
1446 return "Unknown clock";
1447 }
1448}
1449
Mark Brown5b2eec32012-07-04 17:32:05 +01001450static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
1451 int clk_id, unsigned int freq, int dir)
1452{
1453 struct snd_soc_codec *codec = dai->codec;
1454 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1455 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown410837a2012-07-05 17:26:59 +01001456 struct snd_soc_dapm_route routes[2];
Mark Brown5b2eec32012-07-04 17:32:05 +01001457
1458 switch (clk_id) {
1459 case ARIZONA_CLK_SYSCLK:
1460 case ARIZONA_CLK_ASYNCCLK:
1461 break;
1462 default:
1463 return -EINVAL;
1464 }
1465
Mark Brown410837a2012-07-05 17:26:59 +01001466 if (clk_id == dai_priv->clk)
1467 return 0;
1468
1469 if (dai->active) {
Mark Brown5b2eec32012-07-04 17:32:05 +01001470 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
1471 dai->id);
1472 return -EBUSY;
1473 }
1474
Mark Brownc8d35a62012-12-07 12:49:40 +09001475 dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1,
1476 arizona_dai_clk_str(clk_id));
1477
Mark Brown410837a2012-07-05 17:26:59 +01001478 memset(&routes, 0, sizeof(routes));
1479 routes[0].sink = dai->driver->capture.stream_name;
1480 routes[1].sink = dai->driver->playback.stream_name;
Mark Brown5b2eec32012-07-04 17:32:05 +01001481
Mark Brown410837a2012-07-05 17:26:59 +01001482 routes[0].source = arizona_dai_clk_str(dai_priv->clk);
1483 routes[1].source = arizona_dai_clk_str(dai_priv->clk);
1484 snd_soc_dapm_del_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
1485
1486 routes[0].source = arizona_dai_clk_str(clk_id);
1487 routes[1].source = arizona_dai_clk_str(clk_id);
1488 snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
1489
Mark Brown0c778e82012-12-06 18:22:25 +09001490 dai_priv->clk = clk_id;
1491
Mark Brown410837a2012-07-05 17:26:59 +01001492 return snd_soc_dapm_sync(&codec->dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +01001493}
1494
Mark Brown01df2592012-12-12 16:22:08 +09001495static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
1496{
1497 struct snd_soc_codec *codec = dai->codec;
1498 int base = dai->driver->base;
1499 unsigned int reg;
1500
1501 if (tristate)
1502 reg = ARIZONA_AIF1_TRI;
1503 else
1504 reg = 0;
1505
1506 return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1507 ARIZONA_AIF1_TRI, reg);
1508}
1509
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001510static void arizona_set_channels_to_mask(struct snd_soc_dai *dai,
1511 unsigned int base,
1512 int channels, unsigned int mask)
1513{
1514 struct snd_soc_codec *codec = dai->codec;
1515 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1516 struct arizona *arizona = priv->arizona;
1517 int slot, i;
1518
1519 for (i = 0; i < channels; ++i) {
1520 slot = ffs(mask) - 1;
1521 if (slot < 0)
1522 return;
1523
1524 regmap_write(arizona->regmap, base + i, slot);
1525
1526 mask &= ~(1 << slot);
1527 }
1528
1529 if (mask)
1530 arizona_aif_warn(dai, "Too many channels in TDM mask\n");
1531}
1532
1533static int arizona_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
1534 unsigned int rx_mask, int slots, int slot_width)
1535{
1536 struct snd_soc_codec *codec = dai->codec;
1537 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1538 struct arizona *arizona = priv->arizona;
1539 int base = dai->driver->base;
1540 int rx_max_chan = dai->driver->playback.channels_max;
1541 int tx_max_chan = dai->driver->capture.channels_max;
1542
1543 /* Only support TDM for the physical AIFs */
1544 if (dai->id > ARIZONA_MAX_AIF)
1545 return -ENOTSUPP;
1546
1547 if (slots == 0) {
1548 tx_mask = (1 << tx_max_chan) - 1;
1549 rx_mask = (1 << rx_max_chan) - 1;
1550 }
1551
1552 arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_3,
1553 tx_max_chan, tx_mask);
1554 arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_11,
1555 rx_max_chan, rx_mask);
1556
1557 arizona->tdm_width[dai->id - 1] = slot_width;
1558 arizona->tdm_slots[dai->id - 1] = slots;
1559
1560 return 0;
1561}
1562
Mark Brown07ed8732012-06-18 21:08:44 +01001563const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +01001564 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +01001565 .set_fmt = arizona_set_fmt,
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001566 .set_tdm_slot = arizona_set_tdm_slot,
Mark Brown07ed8732012-06-18 21:08:44 +01001567 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +01001568 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown01df2592012-12-12 16:22:08 +09001569 .set_tristate = arizona_set_tristate,
Mark Brown07ed8732012-06-18 21:08:44 +01001570};
Mark Browna8379872012-07-09 12:16:41 +01001571EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +01001572
Mark Brownbd1dd882013-05-17 13:29:03 +01001573const struct snd_soc_dai_ops arizona_simple_dai_ops = {
1574 .startup = arizona_startup,
1575 .hw_params = arizona_hw_params_rate,
1576 .set_sysclk = arizona_dai_set_sysclk,
1577};
1578EXPORT_SYMBOL_GPL(arizona_simple_dai_ops);
1579
Mark Brown5b2eec32012-07-04 17:32:05 +01001580int arizona_init_dai(struct arizona_priv *priv, int id)
1581{
1582 struct arizona_dai_priv *dai_priv = &priv->dai[id];
1583
1584 dai_priv->clk = ARIZONA_CLK_SYSCLK;
1585
1586 return 0;
1587}
1588EXPORT_SYMBOL_GPL(arizona_init_dai);
1589
Mark Brown07ed8732012-06-18 21:08:44 +01001590static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
1591{
1592 struct arizona_fll *fll = data;
1593
1594 arizona_fll_dbg(fll, "clock OK\n");
1595
1596 complete(&fll->ok);
1597
1598 return IRQ_HANDLED;
1599}
1600
1601static struct {
1602 unsigned int min;
1603 unsigned int max;
1604 u16 fratio;
1605 int ratio;
1606} fll_fratios[] = {
1607 { 0, 64000, 4, 16 },
1608 { 64000, 128000, 3, 8 },
1609 { 128000, 256000, 2, 4 },
1610 { 256000, 1000000, 1, 2 },
1611 { 1000000, 13500000, 0, 1 },
1612};
1613
Mark Brown8f113d72013-03-05 12:08:57 +08001614static struct {
1615 unsigned int min;
1616 unsigned int max;
1617 u16 gain;
1618} fll_gains[] = {
1619 { 0, 256000, 0 },
1620 { 256000, 1000000, 2 },
1621 { 1000000, 13500000, 4 },
1622};
1623
Mark Brown07ed8732012-06-18 21:08:44 +01001624struct arizona_fll_cfg {
1625 int n;
1626 int theta;
1627 int lambda;
1628 int refdiv;
1629 int outdiv;
1630 int fratio;
Mark Brown8f113d72013-03-05 12:08:57 +08001631 int gain;
Mark Brown07ed8732012-06-18 21:08:44 +01001632};
1633
Charles Keepax23f785a82014-03-07 16:34:20 +00001634static int arizona_validate_fll(struct arizona_fll *fll,
1635 unsigned int Fref,
1636 unsigned int Fout)
1637{
1638 unsigned int Fvco_min;
1639
Charles Keepaxc8badda2014-07-09 17:41:49 +01001640 if (fll->fout && Fout != fll->fout) {
1641 arizona_fll_err(fll,
1642 "Can't change output on active FLL\n");
1643 return -EINVAL;
1644 }
1645
Charles Keepax23f785a82014-03-07 16:34:20 +00001646 if (Fref / ARIZONA_FLL_MAX_REFDIV > ARIZONA_FLL_MAX_FREF) {
1647 arizona_fll_err(fll,
1648 "Can't scale %dMHz in to <=13.5MHz\n",
1649 Fref);
1650 return -EINVAL;
1651 }
1652
1653 Fvco_min = ARIZONA_FLL_MIN_FVCO * fll->vco_mult;
1654 if (Fout * ARIZONA_FLL_MAX_OUTDIV < Fvco_min) {
1655 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
1656 Fout);
1657 return -EINVAL;
1658 }
1659
1660 return 0;
1661}
1662
Charles Keepaxd0800342014-03-07 16:34:25 +00001663static int arizona_find_fratio(unsigned int Fref, int *fratio)
1664{
1665 int i;
1666
1667 /* Find an appropriate FLL_FRATIO */
1668 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
1669 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
1670 if (fratio)
1671 *fratio = fll_fratios[i].fratio;
1672 return fll_fratios[i].ratio;
1673 }
1674 }
1675
1676 return -EINVAL;
1677}
1678
1679static int arizona_calc_fratio(struct arizona_fll *fll,
1680 struct arizona_fll_cfg *cfg,
1681 unsigned int target,
1682 unsigned int Fref, bool sync)
1683{
1684 int init_ratio, ratio;
1685 int refdiv, div;
1686
1687 /* Fref must be <=13.5MHz, find initial refdiv */
1688 div = 1;
1689 cfg->refdiv = 0;
1690 while (Fref > ARIZONA_FLL_MAX_FREF) {
1691 div *= 2;
1692 Fref /= 2;
1693 cfg->refdiv++;
1694
1695 if (div > ARIZONA_FLL_MAX_REFDIV)
1696 return -EINVAL;
1697 }
1698
1699 /* Find an appropriate FLL_FRATIO */
1700 init_ratio = arizona_find_fratio(Fref, &cfg->fratio);
1701 if (init_ratio < 0) {
1702 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
1703 Fref);
1704 return init_ratio;
1705 }
1706
1707 switch (fll->arizona->type) {
1708 case WM5110:
1709 if (fll->arizona->rev < 3 || sync)
1710 return init_ratio;
1711 break;
1712 default:
1713 return init_ratio;
1714 }
1715
1716 cfg->fratio = init_ratio - 1;
1717
1718 /* Adjust FRATIO/refdiv to avoid integer mode if possible */
1719 refdiv = cfg->refdiv;
1720
1721 while (div <= ARIZONA_FLL_MAX_REFDIV) {
1722 for (ratio = init_ratio; ratio <= ARIZONA_FLL_MAX_FRATIO;
1723 ratio++) {
Charles Keepax35a730a2014-07-09 17:41:45 +01001724 if ((ARIZONA_FLL_VCO_CORNER / 2) /
1725 (fll->vco_mult * ratio) < Fref)
Charles Keepax29fee822014-07-09 17:41:44 +01001726 break;
1727
Charles Keepaxd0800342014-03-07 16:34:25 +00001728 if (target % (ratio * Fref)) {
1729 cfg->refdiv = refdiv;
1730 cfg->fratio = ratio - 1;
1731 return ratio;
1732 }
1733 }
1734
Charles Keepax4714bc02014-07-09 17:41:43 +01001735 for (ratio = init_ratio - 1; ratio > 0; ratio--) {
Charles Keepaxd0800342014-03-07 16:34:25 +00001736 if (target % (ratio * Fref)) {
1737 cfg->refdiv = refdiv;
1738 cfg->fratio = ratio - 1;
1739 return ratio;
1740 }
1741 }
1742
1743 div *= 2;
1744 Fref /= 2;
1745 refdiv++;
1746 init_ratio = arizona_find_fratio(Fref, NULL);
1747 }
1748
1749 arizona_fll_warn(fll, "Falling back to integer mode operation\n");
1750 return cfg->fratio + 1;
1751}
1752
Mark Brown07ed8732012-06-18 21:08:44 +01001753static int arizona_calc_fll(struct arizona_fll *fll,
1754 struct arizona_fll_cfg *cfg,
Charles Keepaxd0800342014-03-07 16:34:25 +00001755 unsigned int Fref, bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01001756{
1757 unsigned int target, div, gcd_fll;
1758 int i, ratio;
1759
Charles Keepax8ccefcd2014-03-07 16:34:21 +00001760 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, fll->fout);
Mark Brown07ed8732012-06-18 21:08:44 +01001761
Mark Brown2b4d39f2012-07-10 17:03:46 +01001762 /* Fvco should be over the targt; don't check the upper bound */
Charles Keepaxf641aec2014-03-07 16:34:22 +00001763 div = ARIZONA_FLL_MIN_OUTDIV;
1764 while (fll->fout * div < ARIZONA_FLL_MIN_FVCO * fll->vco_mult) {
Mark Brown07ed8732012-06-18 21:08:44 +01001765 div++;
Charles Keepaxf641aec2014-03-07 16:34:22 +00001766 if (div > ARIZONA_FLL_MAX_OUTDIV)
Mark Brown07ed8732012-06-18 21:08:44 +01001767 return -EINVAL;
Mark Brown07ed8732012-06-18 21:08:44 +01001768 }
Charles Keepaxf641aec2014-03-07 16:34:22 +00001769 target = fll->fout * div / fll->vco_mult;
Mark Brown07ed8732012-06-18 21:08:44 +01001770 cfg->outdiv = div;
1771
1772 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
1773
Charles Keepaxd0800342014-03-07 16:34:25 +00001774 /* Find an appropriate FLL_FRATIO and refdiv */
1775 ratio = arizona_calc_fratio(fll, cfg, target, Fref, sync);
1776 if (ratio < 0)
1777 return ratio;
Mark Brown07ed8732012-06-18 21:08:44 +01001778
Mark Brown07ed8732012-06-18 21:08:44 +01001779 /* Apply the division for our remaining calculations */
Charles Keepaxd0800342014-03-07 16:34:25 +00001780 Fref = Fref / (1 << cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08001781
Mark Brown07ed8732012-06-18 21:08:44 +01001782 cfg->n = target / (ratio * Fref);
1783
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001784 if (target % (ratio * Fref)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001785 gcd_fll = gcd(target, ratio * Fref);
1786 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
1787
1788 cfg->theta = (target - (cfg->n * ratio * Fref))
1789 / gcd_fll;
1790 cfg->lambda = (ratio * Fref) / gcd_fll;
1791 } else {
1792 cfg->theta = 0;
1793 cfg->lambda = 0;
1794 }
1795
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001796 /* Round down to 16bit range with cost of accuracy lost.
1797 * Denominator must be bigger than numerator so we only
1798 * take care of it.
1799 */
1800 while (cfg->lambda >= (1 << 16)) {
1801 cfg->theta >>= 1;
1802 cfg->lambda >>= 1;
1803 }
1804
Charles Keepax5a3935c2014-03-07 16:34:23 +00001805 for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
1806 if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
1807 cfg->gain = fll_gains[i].gain;
1808 break;
1809 }
1810 }
1811 if (i == ARRAY_SIZE(fll_gains)) {
1812 arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
1813 Fref);
1814 return -EINVAL;
1815 }
1816
Mark Brown07ed8732012-06-18 21:08:44 +01001817 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
1818 cfg->n, cfg->theta, cfg->lambda);
1819 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
1820 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08001821 arizona_fll_dbg(fll, "GAIN=%d\n", cfg->gain);
Mark Brown07ed8732012-06-18 21:08:44 +01001822
1823 return 0;
1824
1825}
1826
1827static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
Mark Brown8f113d72013-03-05 12:08:57 +08001828 struct arizona_fll_cfg *cfg, int source,
1829 bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01001830{
Mark Brown3c43c692013-12-12 00:49:22 +00001831 regmap_update_bits_async(arizona->regmap, base + 3,
1832 ARIZONA_FLL1_THETA_MASK, cfg->theta);
1833 regmap_update_bits_async(arizona->regmap, base + 4,
1834 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
1835 regmap_update_bits_async(arizona->regmap, base + 5,
1836 ARIZONA_FLL1_FRATIO_MASK,
1837 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
1838 regmap_update_bits_async(arizona->regmap, base + 6,
1839 ARIZONA_FLL1_CLK_REF_DIV_MASK |
1840 ARIZONA_FLL1_CLK_REF_SRC_MASK,
1841 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
1842 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
Mark Brown07ed8732012-06-18 21:08:44 +01001843
Charles Keepax61719db2014-03-07 16:34:19 +00001844 if (sync) {
1845 regmap_update_bits(arizona->regmap, base + 0x7,
1846 ARIZONA_FLL1_GAIN_MASK,
1847 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
1848 } else {
1849 regmap_update_bits(arizona->regmap, base + 0x5,
1850 ARIZONA_FLL1_OUTDIV_MASK,
1851 cfg->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
1852 regmap_update_bits(arizona->regmap, base + 0x9,
1853 ARIZONA_FLL1_GAIN_MASK,
1854 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
1855 }
Mark Brown8f113d72013-03-05 12:08:57 +08001856
Mark Brown3c43c692013-12-12 00:49:22 +00001857 regmap_update_bits_async(arizona->regmap, base + 2,
1858 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
1859 ARIZONA_FLL1_CTRL_UPD | cfg->n);
Mark Brown07ed8732012-06-18 21:08:44 +01001860}
1861
Charles Keepaxc393aca2014-07-09 17:41:47 +01001862static int arizona_is_enabled_fll(struct arizona_fll *fll)
Charles Keepaxd122d6c2013-02-20 17:28:36 +00001863{
1864 struct arizona *arizona = fll->arizona;
1865 unsigned int reg;
1866 int ret;
1867
1868 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
1869 if (ret != 0) {
1870 arizona_fll_err(fll, "Failed to read current state: %d\n",
1871 ret);
1872 return ret;
1873 }
1874
1875 return reg & ARIZONA_FLL1_ENA;
1876}
1877
Charles Keepaxc393aca2014-07-09 17:41:47 +01001878static int arizona_enable_fll(struct arizona_fll *fll)
Charles Keepax35722812013-02-20 17:28:38 +00001879{
1880 struct arizona *arizona = fll->arizona;
1881 int ret;
Charles Keepax49c60542013-09-16 15:34:35 +01001882 bool use_sync = false;
Charles Keepaxc393aca2014-07-09 17:41:47 +01001883 int already_enabled = arizona_is_enabled_fll(fll);
Charles Keepax23f785a82014-03-07 16:34:20 +00001884 struct arizona_fll_cfg cfg;
Charles Keepax35722812013-02-20 17:28:38 +00001885
Charles Keepaxc393aca2014-07-09 17:41:47 +01001886 if (already_enabled < 0)
1887 return already_enabled;
1888
Charles Keepaxc8badda2014-07-09 17:41:49 +01001889 if (already_enabled) {
1890 /* Facilitate smooth refclk across the transition */
1891 regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x7,
1892 ARIZONA_FLL1_GAIN_MASK, 0);
1893 regmap_update_bits_async(fll->arizona->regmap, fll->base + 1,
1894 ARIZONA_FLL1_FREERUN,
1895 ARIZONA_FLL1_FREERUN);
1896 }
1897
Mark Brownff680a12013-03-04 16:00:19 +08001898 /*
1899 * If we have both REFCLK and SYNCCLK then enable both,
1900 * otherwise apply the SYNCCLK settings to REFCLK.
1901 */
Charles Keepax49c60542013-09-16 15:34:35 +01001902 if (fll->ref_src >= 0 && fll->ref_freq &&
1903 fll->ref_src != fll->sync_src) {
Charles Keepaxd0800342014-03-07 16:34:25 +00001904 arizona_calc_fll(fll, &cfg, fll->ref_freq, false);
Charles Keepax35722812013-02-20 17:28:38 +00001905
Charles Keepax23f785a82014-03-07 16:34:20 +00001906 arizona_apply_fll(arizona, fll->base, &cfg, fll->ref_src,
Mark Brown8f113d72013-03-05 12:08:57 +08001907 false);
Charles Keepax49c60542013-09-16 15:34:35 +01001908 if (fll->sync_src >= 0) {
Charles Keepaxd0800342014-03-07 16:34:25 +00001909 arizona_calc_fll(fll, &cfg, fll->sync_freq, true);
Charles Keepax23f785a82014-03-07 16:34:20 +00001910
1911 arizona_apply_fll(arizona, fll->base + 0x10, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08001912 fll->sync_src, true);
Charles Keepax49c60542013-09-16 15:34:35 +01001913 use_sync = true;
1914 }
Mark Brownff680a12013-03-04 16:00:19 +08001915 } else if (fll->sync_src >= 0) {
Charles Keepaxd0800342014-03-07 16:34:25 +00001916 arizona_calc_fll(fll, &cfg, fll->sync_freq, false);
Mark Brownff680a12013-03-04 16:00:19 +08001917
Charles Keepax23f785a82014-03-07 16:34:20 +00001918 arizona_apply_fll(arizona, fll->base, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08001919 fll->sync_src, false);
Mark Browneca2e8e2013-03-06 00:09:59 +08001920
Mark Brown3c43c692013-12-12 00:49:22 +00001921 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
1922 ARIZONA_FLL1_SYNC_ENA, 0);
Mark Brownff680a12013-03-04 16:00:19 +08001923 } else {
1924 arizona_fll_err(fll, "No clocks provided\n");
Charles Keepaxc393aca2014-07-09 17:41:47 +01001925 return -EINVAL;
Mark Brownff680a12013-03-04 16:00:19 +08001926 }
Charles Keepax35722812013-02-20 17:28:38 +00001927
Mark Brown576411be2013-03-05 12:07:16 +08001928 /*
1929 * Increase the bandwidth if we're not using a low frequency
1930 * sync source.
1931 */
Charles Keepax49c60542013-09-16 15:34:35 +01001932 if (use_sync && fll->sync_freq > 100000)
Mark Brown3c43c692013-12-12 00:49:22 +00001933 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
1934 ARIZONA_FLL1_SYNC_BW, 0);
Mark Brown576411be2013-03-05 12:07:16 +08001935 else
Mark Brown3c43c692013-12-12 00:49:22 +00001936 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
1937 ARIZONA_FLL1_SYNC_BW,
1938 ARIZONA_FLL1_SYNC_BW);
Mark Brown576411be2013-03-05 12:07:16 +08001939
Charles Keepaxc393aca2014-07-09 17:41:47 +01001940 if (!already_enabled)
Charles Keepax35722812013-02-20 17:28:38 +00001941 pm_runtime_get(arizona->dev);
1942
1943 /* Clear any pending completions */
1944 try_wait_for_completion(&fll->ok);
1945
Mark Brown3c43c692013-12-12 00:49:22 +00001946 regmap_update_bits_async(arizona->regmap, fll->base + 1,
Mark Brown3c43c692013-12-12 00:49:22 +00001947 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
Charles Keepax49c60542013-09-16 15:34:35 +01001948 if (use_sync)
Mark Brown3c43c692013-12-12 00:49:22 +00001949 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
1950 ARIZONA_FLL1_SYNC_ENA,
1951 ARIZONA_FLL1_SYNC_ENA);
Charles Keepax35722812013-02-20 17:28:38 +00001952
Charles Keepaxc8badda2014-07-09 17:41:49 +01001953 if (already_enabled)
1954 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1955 ARIZONA_FLL1_FREERUN, 0);
1956
Charles Keepax35722812013-02-20 17:28:38 +00001957 ret = wait_for_completion_timeout(&fll->ok,
1958 msecs_to_jiffies(250));
1959 if (ret == 0)
1960 arizona_fll_warn(fll, "Timed out waiting for lock\n");
Charles Keepaxc393aca2014-07-09 17:41:47 +01001961
1962 return 0;
Charles Keepax35722812013-02-20 17:28:38 +00001963}
1964
Charles Keepax76040542013-02-20 17:28:37 +00001965static void arizona_disable_fll(struct arizona_fll *fll)
1966{
1967 struct arizona *arizona = fll->arizona;
1968 bool change;
1969
Mark Brown3c43c692013-12-12 00:49:22 +00001970 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1971 ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
Charles Keepax76040542013-02-20 17:28:37 +00001972 regmap_update_bits_check(arizona->regmap, fll->base + 1,
1973 ARIZONA_FLL1_ENA, 0, &change);
1974 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1975 ARIZONA_FLL1_SYNC_ENA, 0);
Charles Keepax5e39a502014-07-09 17:41:48 +01001976 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1977 ARIZONA_FLL1_FREERUN, 0);
Charles Keepax76040542013-02-20 17:28:37 +00001978
1979 if (change)
1980 pm_runtime_put_autosuspend(arizona->dev);
1981}
1982
Charles Keepaxee929a92013-02-20 17:28:40 +00001983int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
1984 unsigned int Fref, unsigned int Fout)
1985{
Charles Keepaxc393aca2014-07-09 17:41:47 +01001986 int ret = 0;
Charles Keepaxee929a92013-02-20 17:28:40 +00001987
Charles Keepax1c5617f2013-02-22 17:10:37 +00001988 if (fll->ref_src == source && fll->ref_freq == Fref)
Charles Keepaxee929a92013-02-20 17:28:40 +00001989 return 0;
1990
Charles Keepax23f785a82014-03-07 16:34:20 +00001991 if (fll->fout && Fref > 0) {
1992 ret = arizona_validate_fll(fll, Fref, fll->fout);
1993 if (ret != 0)
1994 return ret;
Charles Keepaxee929a92013-02-20 17:28:40 +00001995 }
1996
1997 fll->ref_src = source;
1998 fll->ref_freq = Fref;
Charles Keepaxee929a92013-02-20 17:28:40 +00001999
Mark Brown86cd6842013-03-07 16:14:04 +08002000 if (fll->fout && Fref > 0) {
Charles Keepaxc393aca2014-07-09 17:41:47 +01002001 ret = arizona_enable_fll(fll);
Charles Keepaxee929a92013-02-20 17:28:40 +00002002 }
2003
Charles Keepaxc393aca2014-07-09 17:41:47 +01002004 return ret;
Charles Keepaxee929a92013-02-20 17:28:40 +00002005}
2006EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
2007
Mark Brown07ed8732012-06-18 21:08:44 +01002008int arizona_set_fll(struct arizona_fll *fll, int source,
2009 unsigned int Fref, unsigned int Fout)
2010{
Charles Keepaxc393aca2014-07-09 17:41:47 +01002011 int ret = 0;
Mark Brown07ed8732012-06-18 21:08:44 +01002012
Mark Brownff680a12013-03-04 16:00:19 +08002013 if (fll->sync_src == source &&
2014 fll->sync_freq == Fref && fll->fout == Fout)
2015 return 0;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00002016
Mark Brownff680a12013-03-04 16:00:19 +08002017 if (Fout) {
2018 if (fll->ref_src >= 0) {
Charles Keepax23f785a82014-03-07 16:34:20 +00002019 ret = arizona_validate_fll(fll, fll->ref_freq, Fout);
Charles Keepax9e359c62013-02-20 17:28:35 +00002020 if (ret != 0)
2021 return ret;
2022 }
2023
Charles Keepax23f785a82014-03-07 16:34:20 +00002024 ret = arizona_validate_fll(fll, Fref, Fout);
Mark Brownff680a12013-03-04 16:00:19 +08002025 if (ret != 0)
2026 return ret;
Charles Keepax9e359c62013-02-20 17:28:35 +00002027 }
Mark Brownff680a12013-03-04 16:00:19 +08002028
2029 fll->sync_src = source;
2030 fll->sync_freq = Fref;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00002031 fll->fout = Fout;
Charles Keepax9e359c62013-02-20 17:28:35 +00002032
Charles Keepax613124c2014-07-09 17:41:46 +01002033 if (Fout)
Charles Keepaxc393aca2014-07-09 17:41:47 +01002034 ret = arizona_enable_fll(fll);
Charles Keepax613124c2014-07-09 17:41:46 +01002035 else
Charles Keepax76040542013-02-20 17:28:37 +00002036 arizona_disable_fll(fll);
Mark Brown07ed8732012-06-18 21:08:44 +01002037
Charles Keepaxc393aca2014-07-09 17:41:47 +01002038 return ret;
Mark Brown07ed8732012-06-18 21:08:44 +01002039}
2040EXPORT_SYMBOL_GPL(arizona_set_fll);
2041
2042int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
2043 int ok_irq, struct arizona_fll *fll)
2044{
2045 int ret;
Charles Keepax19b34bd2013-02-20 17:28:34 +00002046 unsigned int val;
Mark Brown07ed8732012-06-18 21:08:44 +01002047
Mark Brown07ed8732012-06-18 21:08:44 +01002048 init_completion(&fll->ok);
2049
2050 fll->id = id;
2051 fll->base = base;
2052 fll->arizona = arizona;
Charles Keepaxf3f11632013-02-20 17:28:41 +00002053 fll->sync_src = ARIZONA_FLL_SRC_NONE;
Mark Brown07ed8732012-06-18 21:08:44 +01002054
Charles Keepax19b34bd2013-02-20 17:28:34 +00002055 /* Configure default refclk to 32kHz if we have one */
2056 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
2057 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
2058 case ARIZONA_CLK_SRC_MCLK1:
2059 case ARIZONA_CLK_SRC_MCLK2:
2060 fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK;
2061 break;
2062 default:
Charles Keepaxf3f11632013-02-20 17:28:41 +00002063 fll->ref_src = ARIZONA_FLL_SRC_NONE;
Charles Keepax19b34bd2013-02-20 17:28:34 +00002064 }
2065 fll->ref_freq = 32768;
2066
Mark Brown07ed8732012-06-18 21:08:44 +01002067 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
2068 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
2069 "FLL%d clock OK", id);
2070
Mark Brown07ed8732012-06-18 21:08:44 +01002071 ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
2072 arizona_fll_clock_ok, fll);
2073 if (ret != 0) {
2074 dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
2075 id, ret);
2076 }
2077
Charles Keepaxe31c1942013-01-07 16:41:45 +00002078 regmap_update_bits(arizona->regmap, fll->base + 1,
2079 ARIZONA_FLL1_FREERUN, 0);
2080
Mark Brown07ed8732012-06-18 21:08:44 +01002081 return 0;
2082}
2083EXPORT_SYMBOL_GPL(arizona_init_fll);
2084
Mark Brownbc9ab6d2013-01-04 19:31:00 +00002085/**
2086 * arizona_set_output_mode - Set the mode of the specified output
2087 *
2088 * @codec: Device to configure
2089 * @output: Output number
2090 * @diff: True to set the output to differential mode
2091 *
2092 * Some systems use external analogue switches to connect more
2093 * analogue devices to the CODEC than are supported by the device. In
2094 * some systems this requires changing the switched output from single
2095 * ended to differential mode dynamically at runtime, an operation
2096 * supported using this function.
2097 *
2098 * Most systems have a single static configuration and should use
2099 * platform data instead.
2100 */
2101int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
2102{
2103 unsigned int reg, val;
2104
2105 if (output < 1 || output > 6)
2106 return -EINVAL;
2107
2108 reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
2109
2110 if (diff)
2111 val = ARIZONA_OUT1_MONO;
2112 else
2113 val = 0;
2114
2115 return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val);
2116}
2117EXPORT_SYMBOL_GPL(arizona_set_output_mode);
2118
Mark Brown07ed8732012-06-18 21:08:44 +01002119MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
2120MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
2121MODULE_LICENSE("GPL");