blob: 9550d7433ad0e391708a85c88a0adfc6fb2d1831 [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{
Mark Brown1a2c7d52013-03-24 22:50:23 +0000737 switch (event) {
738 case SND_SOC_DAPM_POST_PMU:
739 switch (w->shift) {
740 case ARIZONA_OUT1L_ENA_SHIFT:
741 case ARIZONA_OUT1R_ENA_SHIFT:
742 case ARIZONA_OUT2L_ENA_SHIFT:
743 case ARIZONA_OUT2R_ENA_SHIFT:
744 case ARIZONA_OUT3L_ENA_SHIFT:
745 case ARIZONA_OUT3R_ENA_SHIFT:
746 msleep(17);
747 break;
748
749 default:
750 break;
751 }
752 break;
753 }
754
Mark Brown07ed8732012-06-18 21:08:44 +0100755 return 0;
756}
757EXPORT_SYMBOL_GPL(arizona_out_ev);
758
Mark Brownf607e312013-02-22 18:36:53 +0000759int arizona_hp_ev(struct snd_soc_dapm_widget *w,
760 struct snd_kcontrol *kcontrol,
761 int event)
762{
763 struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
Mark Brown3c43c692013-12-12 00:49:22 +0000764 struct arizona *arizona = priv->arizona;
Mark Brownf607e312013-02-22 18:36:53 +0000765 unsigned int mask = 1 << w->shift;
766 unsigned int val;
767
768 switch (event) {
769 case SND_SOC_DAPM_POST_PMU:
770 val = mask;
771 break;
772 case SND_SOC_DAPM_PRE_PMD:
773 val = 0;
774 break;
775 default:
776 return -EINVAL;
777 }
778
779 /* Store the desired state for the HP outputs */
780 priv->arizona->hp_ena &= ~mask;
781 priv->arizona->hp_ena |= val;
782
783 /* Force off if HPDET magic is active */
784 if (priv->arizona->hpdet_magic)
785 val = 0;
786
Mark Brown3c43c692013-12-12 00:49:22 +0000787 regmap_update_bits_async(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1,
788 mask, val);
Mark Brownf607e312013-02-22 18:36:53 +0000789
790 return arizona_out_ev(w, kcontrol, event);
791}
792EXPORT_SYMBOL_GPL(arizona_hp_ev);
793
Mark Browncbd840d2012-08-08 17:52:44 +0100794static unsigned int arizona_sysclk_48k_rates[] = {
795 6144000,
796 12288000,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000797 24576000,
Mark Browncbd840d2012-08-08 17:52:44 +0100798 49152000,
Mark Brownaeaeee12012-09-26 17:50:02 +0100799 73728000,
800 98304000,
801 147456000,
Mark Browncbd840d2012-08-08 17:52:44 +0100802};
803
804static unsigned int arizona_sysclk_44k1_rates[] = {
805 5644800,
806 11289600,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000807 22579200,
Mark Browncbd840d2012-08-08 17:52:44 +0100808 45158400,
Mark Brownaeaeee12012-09-26 17:50:02 +0100809 67737600,
810 90316800,
811 135475200,
Mark Browncbd840d2012-08-08 17:52:44 +0100812};
813
814static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
815 unsigned int freq)
816{
817 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
818 unsigned int reg;
819 unsigned int *rates;
820 int ref, div, refclk;
821
822 switch (clk) {
823 case ARIZONA_CLK_OPCLK:
824 reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
825 refclk = priv->sysclk;
826 break;
827 case ARIZONA_CLK_ASYNC_OPCLK:
828 reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
829 refclk = priv->asyncclk;
830 break;
831 default:
832 return -EINVAL;
833 }
834
835 if (refclk % 8000)
836 rates = arizona_sysclk_44k1_rates;
837 else
838 rates = arizona_sysclk_48k_rates;
839
840 for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) &&
841 rates[ref] <= refclk; ref++) {
842 div = 1;
843 while (rates[ref] / div >= freq && div < 32) {
844 if (rates[ref] / div == freq) {
845 dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
846 freq);
847 snd_soc_update_bits(codec, reg,
848 ARIZONA_OPCLK_DIV_MASK |
849 ARIZONA_OPCLK_SEL_MASK,
850 (div <<
851 ARIZONA_OPCLK_DIV_SHIFT) |
852 ref);
853 return 0;
854 }
855 div++;
856 }
857 }
858
859 dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
860 return -EINVAL;
861}
862
Mark Brown07ed8732012-06-18 21:08:44 +0100863int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
864 int source, unsigned int freq, int dir)
865{
866 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
867 struct arizona *arizona = priv->arizona;
868 char *name;
869 unsigned int reg;
870 unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
871 unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
872 unsigned int *clk;
873
874 switch (clk_id) {
875 case ARIZONA_CLK_SYSCLK:
876 name = "SYSCLK";
877 reg = ARIZONA_SYSTEM_CLOCK_1;
878 clk = &priv->sysclk;
879 mask |= ARIZONA_SYSCLK_FRAC;
880 break;
881 case ARIZONA_CLK_ASYNCCLK:
882 name = "ASYNCCLK";
883 reg = ARIZONA_ASYNC_CLOCK_1;
884 clk = &priv->asyncclk;
885 break;
Mark Browncbd840d2012-08-08 17:52:44 +0100886 case ARIZONA_CLK_OPCLK:
887 case ARIZONA_CLK_ASYNC_OPCLK:
888 return arizona_set_opclk(codec, clk_id, freq);
Mark Brown07ed8732012-06-18 21:08:44 +0100889 default:
890 return -EINVAL;
891 }
892
893 switch (freq) {
894 case 5644800:
895 case 6144000:
896 break;
897 case 11289600:
898 case 12288000:
Mark Brown3f341f72013-03-08 15:22:29 +0800899 val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100900 break;
901 case 22579200:
902 case 24576000:
Mark Brown3f341f72013-03-08 15:22:29 +0800903 val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100904 break;
905 case 45158400:
906 case 49152000:
Mark Brown3f341f72013-03-08 15:22:29 +0800907 val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100908 break;
Mark Brown38113362012-11-26 16:01:37 +0000909 case 67737600:
910 case 73728000:
Mark Brown3f341f72013-03-08 15:22:29 +0800911 val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000912 break;
913 case 90316800:
914 case 98304000:
Mark Brown3f341f72013-03-08 15:22:29 +0800915 val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000916 break;
917 case 135475200:
918 case 147456000:
Mark Brown3f341f72013-03-08 15:22:29 +0800919 val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000920 break;
Mark Brownf2c26d42013-01-21 16:09:36 +0900921 case 0:
922 dev_dbg(arizona->dev, "%s cleared\n", name);
923 *clk = freq;
924 return 0;
Mark Brown07ed8732012-06-18 21:08:44 +0100925 default:
926 return -EINVAL;
927 }
928
929 *clk = freq;
930
931 if (freq % 6144000)
932 val |= ARIZONA_SYSCLK_FRAC;
933
934 dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
935
936 return regmap_update_bits(arizona->regmap, reg, mask, val);
937}
938EXPORT_SYMBOL_GPL(arizona_set_sysclk);
939
940static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
941{
942 struct snd_soc_codec *codec = dai->codec;
Mark Brown3c43c692013-12-12 00:49:22 +0000943 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
944 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +0100945 int lrclk, bclk, mode, base;
946
947 base = dai->driver->base;
948
949 lrclk = 0;
950 bclk = 0;
951
952 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
953 case SND_SOC_DAIFMT_DSP_A:
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +0000954 mode = ARIZONA_FMT_DSP_MODE_A;
955 break;
956 case SND_SOC_DAIFMT_DSP_B:
957 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
958 != SND_SOC_DAIFMT_CBM_CFM) {
959 arizona_aif_err(dai, "DSP_B not valid in slave mode\n");
960 return -EINVAL;
961 }
962 mode = ARIZONA_FMT_DSP_MODE_B;
Mark Brown07ed8732012-06-18 21:08:44 +0100963 break;
Mark Brown07ed8732012-06-18 21:08:44 +0100964 case SND_SOC_DAIFMT_I2S:
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +0000965 mode = ARIZONA_FMT_I2S_MODE;
966 break;
967 case SND_SOC_DAIFMT_LEFT_J:
968 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
969 != SND_SOC_DAIFMT_CBM_CFM) {
970 arizona_aif_err(dai, "LEFT_J not valid in slave mode\n");
971 return -EINVAL;
972 }
973 mode = ARIZONA_FMT_LEFT_JUSTIFIED_MODE;
Mark Brown07ed8732012-06-18 21:08:44 +0100974 break;
Mark Brown07ed8732012-06-18 21:08:44 +0100975 default:
976 arizona_aif_err(dai, "Unsupported DAI format %d\n",
977 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
978 return -EINVAL;
979 }
980
981 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
982 case SND_SOC_DAIFMT_CBS_CFS:
983 break;
984 case SND_SOC_DAIFMT_CBS_CFM:
985 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
986 break;
987 case SND_SOC_DAIFMT_CBM_CFS:
988 bclk |= ARIZONA_AIF1_BCLK_MSTR;
989 break;
990 case SND_SOC_DAIFMT_CBM_CFM:
991 bclk |= ARIZONA_AIF1_BCLK_MSTR;
992 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
993 break;
994 default:
995 arizona_aif_err(dai, "Unsupported master mode %d\n",
996 fmt & SND_SOC_DAIFMT_MASTER_MASK);
997 return -EINVAL;
998 }
999
1000 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1001 case SND_SOC_DAIFMT_NB_NF:
1002 break;
1003 case SND_SOC_DAIFMT_IB_IF:
1004 bclk |= ARIZONA_AIF1_BCLK_INV;
1005 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
1006 break;
1007 case SND_SOC_DAIFMT_IB_NF:
1008 bclk |= ARIZONA_AIF1_BCLK_INV;
1009 break;
1010 case SND_SOC_DAIFMT_NB_IF:
1011 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
1012 break;
1013 default:
1014 return -EINVAL;
1015 }
1016
Mark Brown3c43c692013-12-12 00:49:22 +00001017 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_BCLK_CTRL,
1018 ARIZONA_AIF1_BCLK_INV |
1019 ARIZONA_AIF1_BCLK_MSTR,
1020 bclk);
1021 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_TX_PIN_CTRL,
1022 ARIZONA_AIF1TX_LRCLK_INV |
1023 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
1024 regmap_update_bits_async(arizona->regmap,
1025 base + ARIZONA_AIF_RX_PIN_CTRL,
1026 ARIZONA_AIF1RX_LRCLK_INV |
1027 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
1028 regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FORMAT,
1029 ARIZONA_AIF1_FMT_MASK, mode);
Mark Brown07ed8732012-06-18 21:08:44 +01001030
1031 return 0;
1032}
1033
Mark Brown949e6bc2012-07-04 18:58:04 +01001034static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001035 -1,
1036 48000,
1037 64000,
1038 96000,
1039 128000,
1040 192000,
1041 256000,
1042 384000,
1043 512000,
1044 768000,
1045 1024000,
1046 1536000,
1047 2048000,
1048 3072000,
1049 4096000,
1050 6144000,
1051 8192000,
1052 12288000,
1053 24576000,
1054};
1055
Mark Brown5b2eec32012-07-04 17:32:05 +01001056static const unsigned int arizona_48k_rates[] = {
1057 12000,
1058 24000,
1059 48000,
1060 96000,
1061 192000,
1062 384000,
1063 768000,
1064 4000,
1065 8000,
1066 16000,
1067 32000,
1068 64000,
1069 128000,
1070 256000,
1071 512000,
1072};
1073
1074static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = {
1075 .count = ARRAY_SIZE(arizona_48k_rates),
1076 .list = arizona_48k_rates,
1077};
1078
Mark Brown949e6bc2012-07-04 18:58:04 +01001079static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001080 -1,
1081 44100,
1082 58800,
1083 88200,
1084 117600,
1085 177640,
1086 235200,
1087 352800,
1088 470400,
1089 705600,
1090 940800,
1091 1411200,
1092 1881600,
Heather Lomond4758be32012-09-05 05:02:10 -04001093 2822400,
Mark Brown07ed8732012-06-18 21:08:44 +01001094 3763200,
1095 5644800,
1096 7526400,
1097 11289600,
1098 22579200,
1099};
1100
Mark Brown5b2eec32012-07-04 17:32:05 +01001101static const unsigned int arizona_44k1_rates[] = {
1102 11025,
1103 22050,
1104 44100,
1105 88200,
1106 176400,
1107 352800,
1108 705600,
1109};
1110
1111static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = {
1112 .count = ARRAY_SIZE(arizona_44k1_rates),
1113 .list = arizona_44k1_rates,
1114};
1115
Mark Brown07ed8732012-06-18 21:08:44 +01001116static int arizona_sr_vals[] = {
1117 0,
1118 12000,
1119 24000,
1120 48000,
1121 96000,
1122 192000,
1123 384000,
1124 768000,
1125 0,
1126 11025,
1127 22050,
1128 44100,
1129 88200,
1130 176400,
1131 352800,
1132 705600,
1133 4000,
1134 8000,
1135 16000,
1136 32000,
1137 64000,
1138 128000,
1139 256000,
1140 512000,
1141};
1142
Mark Brown5b2eec32012-07-04 17:32:05 +01001143static int arizona_startup(struct snd_pcm_substream *substream,
1144 struct snd_soc_dai *dai)
1145{
1146 struct snd_soc_codec *codec = dai->codec;
1147 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1148 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
1149 const struct snd_pcm_hw_constraint_list *constraint;
1150 unsigned int base_rate;
1151
1152 switch (dai_priv->clk) {
1153 case ARIZONA_CLK_SYSCLK:
1154 base_rate = priv->sysclk;
1155 break;
1156 case ARIZONA_CLK_ASYNCCLK:
1157 base_rate = priv->asyncclk;
1158 break;
1159 default:
1160 return 0;
1161 }
1162
Mark Brownf2c26d42013-01-21 16:09:36 +09001163 if (base_rate == 0)
1164 return 0;
1165
Mark Brown5b2eec32012-07-04 17:32:05 +01001166 if (base_rate % 8000)
1167 constraint = &arizona_44k1_constraint;
1168 else
1169 constraint = &arizona_48k_constraint;
1170
1171 return snd_pcm_hw_constraint_list(substream->runtime, 0,
1172 SNDRV_PCM_HW_PARAM_RATE,
1173 constraint);
1174}
1175
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001176static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec,
1177 unsigned int rate)
1178{
1179 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1180 struct arizona *arizona = priv->arizona;
1181 struct reg_default dac_comp[] = {
1182 { 0x80, 0x3 },
1183 { ARIZONA_DAC_COMP_1, 0 },
1184 { ARIZONA_DAC_COMP_2, 0 },
1185 { 0x80, 0x0 },
1186 };
1187
Lars-Peter Clausend74bcaa2014-11-09 17:00:59 +01001188 mutex_lock(&arizona->dac_comp_lock);
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001189
1190 dac_comp[1].def = arizona->dac_comp_coeff;
1191 if (rate >= 176400)
1192 dac_comp[2].def = arizona->dac_comp_enabled;
1193
Lars-Peter Clausend74bcaa2014-11-09 17:00:59 +01001194 mutex_unlock(&arizona->dac_comp_lock);
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001195
1196 regmap_multi_reg_write(arizona->regmap,
1197 dac_comp,
1198 ARRAY_SIZE(dac_comp));
1199}
1200
Mark Brownb272efc2012-10-10 15:10:08 +09001201static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
1202 struct snd_pcm_hw_params *params,
1203 struct snd_soc_dai *dai)
Mark Brown07ed8732012-06-18 21:08:44 +01001204{
1205 struct snd_soc_codec *codec = dai->codec;
Mark Brownc013b272012-07-04 20:05:57 +01001206 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1207 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown07ed8732012-06-18 21:08:44 +01001208 int base = dai->driver->base;
Mark Brownb272efc2012-10-10 15:10:08 +09001209 int i, sr_val;
1210
1211 /*
1212 * We will need to be more flexible than this in future,
1213 * currently we use a single sample rate for SYSCLK.
1214 */
1215 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
1216 if (arizona_sr_vals[i] == params_rate(params))
1217 break;
1218 if (i == ARRAY_SIZE(arizona_sr_vals)) {
1219 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1220 params_rate(params));
1221 return -EINVAL;
1222 }
1223 sr_val = i;
1224
1225 switch (dai_priv->clk) {
1226 case ARIZONA_CLK_SYSCLK:
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001227 switch (priv->arizona->type) {
1228 case WM5102:
1229 arizona_wm5102_set_dac_comp(codec,
1230 params_rate(params));
1231 break;
1232 default:
1233 break;
1234 }
1235
Mark Brownb272efc2012-10-10 15:10:08 +09001236 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
1237 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
1238 if (base)
1239 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1240 ARIZONA_AIF1_RATE_MASK, 0);
1241 break;
1242 case ARIZONA_CLK_ASYNCCLK:
1243 snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
Charles Keepaxc24084d2014-09-01 15:48:52 +01001244 ARIZONA_ASYNC_SAMPLE_RATE_1_MASK, sr_val);
Mark Brownb272efc2012-10-10 15:10:08 +09001245 if (base)
1246 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1247 ARIZONA_AIF1_RATE_MASK,
1248 8 << ARIZONA_AIF1_RATE_SHIFT);
1249 break;
1250 default:
1251 arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
1252 return -EINVAL;
1253 }
1254
1255 return 0;
1256}
1257
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001258static bool arizona_aif_cfg_changed(struct snd_soc_codec *codec,
1259 int base, int bclk, int lrclk, int frame)
1260{
1261 int val;
1262
1263 val = snd_soc_read(codec, base + ARIZONA_AIF_BCLK_CTRL);
1264 if (bclk != (val & ARIZONA_AIF1_BCLK_FREQ_MASK))
1265 return true;
1266
1267 val = snd_soc_read(codec, base + ARIZONA_AIF_TX_BCLK_RATE);
1268 if (lrclk != (val & ARIZONA_AIF1TX_BCPF_MASK))
1269 return true;
1270
1271 val = snd_soc_read(codec, base + ARIZONA_AIF_FRAME_CTRL_1);
1272 if (frame != (val & (ARIZONA_AIF1TX_WL_MASK |
1273 ARIZONA_AIF1TX_SLOT_LEN_MASK)))
1274 return true;
1275
1276 return false;
1277}
1278
Mark Brown07ed8732012-06-18 21:08:44 +01001279static int arizona_hw_params(struct snd_pcm_substream *substream,
1280 struct snd_pcm_hw_params *params,
1281 struct snd_soc_dai *dai)
1282{
1283 struct snd_soc_codec *codec = dai->codec;
1284 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brownc94aa302013-01-17 16:35:14 +09001285 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +01001286 int base = dai->driver->base;
1287 const int *rates;
Mark Brown76bf9692013-03-05 14:17:47 +08001288 int i, ret, val;
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001289 int channels = params_channels(params);
Mark Brownc94aa302013-01-17 16:35:14 +09001290 int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001291 int tdm_width = arizona->tdm_width[dai->id - 1];
1292 int tdm_slots = arizona->tdm_slots[dai->id - 1];
Mark Brownc94aa302013-01-17 16:35:14 +09001293 int bclk, lrclk, wl, frame, bclk_target;
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001294 bool reconfig;
1295 unsigned int aif_tx_state, aif_rx_state;
Mark Brown07ed8732012-06-18 21:08:44 +01001296
1297 if (params_rate(params) % 8000)
Mark Brown949e6bc2012-07-04 18:58:04 +01001298 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001299 else
Mark Brown949e6bc2012-07-04 18:58:04 +01001300 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001301
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001302 wl = snd_pcm_format_width(params_format(params));
1303
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001304 if (tdm_slots) {
1305 arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n",
1306 tdm_slots, tdm_width);
1307 bclk_target = tdm_slots * tdm_width * params_rate(params);
1308 channels = tdm_slots;
1309 } else {
1310 bclk_target = snd_soc_params_to_bclk(params);
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001311 tdm_width = wl;
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001312 }
1313
1314 if (chan_limit && chan_limit < channels) {
Mark Brownc94aa302013-01-17 16:35:14 +09001315 arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001316 bclk_target /= channels;
Mark Brownc94aa302013-01-17 16:35:14 +09001317 bclk_target *= chan_limit;
1318 }
1319
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001320 /* Force multiple of 2 channels for I2S mode */
Mark Brown76bf9692013-03-05 14:17:47 +08001321 val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001322 val &= ARIZONA_AIF1_FMT_MASK;
1323 if ((channels & 1) && (val == ARIZONA_FMT_I2S_MODE)) {
Mark Brown76bf9692013-03-05 14:17:47 +08001324 arizona_aif_dbg(dai, "Forcing stereo mode\n");
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001325 bclk_target /= channels;
1326 bclk_target *= channels + 1;
Mark Brown76bf9692013-03-05 14:17:47 +08001327 }
1328
Mark Brown949e6bc2012-07-04 18:58:04 +01001329 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brownc94aa302013-01-17 16:35:14 +09001330 if (rates[i] >= bclk_target &&
Mark Brown50017652012-07-04 19:07:09 +01001331 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +01001332 bclk = i;
1333 break;
1334 }
1335 }
Mark Brown949e6bc2012-07-04 18:58:04 +01001336 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001337 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1338 params_rate(params));
1339 return -EINVAL;
1340 }
1341
Mark Brownb59e0f82013-01-17 14:15:59 +09001342 lrclk = rates[bclk] / params_rate(params);
Mark Brown07ed8732012-06-18 21:08:44 +01001343
1344 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
1345 rates[bclk], rates[bclk] / lrclk);
1346
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001347 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | tdm_width;
Mark Brown07ed8732012-06-18 21:08:44 +01001348
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001349 reconfig = arizona_aif_cfg_changed(codec, base, bclk, lrclk, frame);
1350
1351 if (reconfig) {
1352 /* Save AIF TX/RX state */
1353 aif_tx_state = snd_soc_read(codec,
1354 base + ARIZONA_AIF_TX_ENABLES);
1355 aif_rx_state = snd_soc_read(codec,
1356 base + ARIZONA_AIF_RX_ENABLES);
1357 /* Disable AIF TX/RX before reconfiguring it */
1358 regmap_update_bits_async(arizona->regmap,
1359 base + ARIZONA_AIF_TX_ENABLES, 0xff, 0x0);
1360 regmap_update_bits(arizona->regmap,
1361 base + ARIZONA_AIF_RX_ENABLES, 0xff, 0x0);
1362 }
1363
Mark Brownb272efc2012-10-10 15:10:08 +09001364 ret = arizona_hw_params_rate(substream, params, dai);
1365 if (ret != 0)
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001366 goto restore_aif;
Mark Brownc013b272012-07-04 20:05:57 +01001367
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001368 if (reconfig) {
1369 regmap_update_bits_async(arizona->regmap,
1370 base + ARIZONA_AIF_BCLK_CTRL,
1371 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
1372 regmap_update_bits_async(arizona->regmap,
1373 base + ARIZONA_AIF_TX_BCLK_RATE,
1374 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
1375 regmap_update_bits_async(arizona->regmap,
1376 base + ARIZONA_AIF_RX_BCLK_RATE,
1377 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
1378 regmap_update_bits_async(arizona->regmap,
1379 base + ARIZONA_AIF_FRAME_CTRL_1,
1380 ARIZONA_AIF1TX_WL_MASK |
1381 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
1382 regmap_update_bits(arizona->regmap,
1383 base + ARIZONA_AIF_FRAME_CTRL_2,
1384 ARIZONA_AIF1RX_WL_MASK |
1385 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
1386 }
Mark Brown07ed8732012-06-18 21:08:44 +01001387
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001388restore_aif:
1389 if (reconfig) {
1390 /* Restore AIF TX/RX state */
1391 regmap_update_bits_async(arizona->regmap,
1392 base + ARIZONA_AIF_TX_ENABLES,
1393 0xff, aif_tx_state);
1394 regmap_update_bits(arizona->regmap,
1395 base + ARIZONA_AIF_RX_ENABLES,
1396 0xff, aif_rx_state);
1397 }
1398 return ret;
Mark Brown07ed8732012-06-18 21:08:44 +01001399}
1400
Mark Brown410837a2012-07-05 17:26:59 +01001401static const char *arizona_dai_clk_str(int clk_id)
1402{
1403 switch (clk_id) {
1404 case ARIZONA_CLK_SYSCLK:
1405 return "SYSCLK";
1406 case ARIZONA_CLK_ASYNCCLK:
1407 return "ASYNCCLK";
1408 default:
1409 return "Unknown clock";
1410 }
1411}
1412
Mark Brown5b2eec32012-07-04 17:32:05 +01001413static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
1414 int clk_id, unsigned int freq, int dir)
1415{
1416 struct snd_soc_codec *codec = dai->codec;
1417 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1418 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown410837a2012-07-05 17:26:59 +01001419 struct snd_soc_dapm_route routes[2];
Mark Brown5b2eec32012-07-04 17:32:05 +01001420
1421 switch (clk_id) {
1422 case ARIZONA_CLK_SYSCLK:
1423 case ARIZONA_CLK_ASYNCCLK:
1424 break;
1425 default:
1426 return -EINVAL;
1427 }
1428
Mark Brown410837a2012-07-05 17:26:59 +01001429 if (clk_id == dai_priv->clk)
1430 return 0;
1431
1432 if (dai->active) {
Mark Brown5b2eec32012-07-04 17:32:05 +01001433 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
1434 dai->id);
1435 return -EBUSY;
1436 }
1437
Mark Brownc8d35a62012-12-07 12:49:40 +09001438 dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1,
1439 arizona_dai_clk_str(clk_id));
1440
Mark Brown410837a2012-07-05 17:26:59 +01001441 memset(&routes, 0, sizeof(routes));
1442 routes[0].sink = dai->driver->capture.stream_name;
1443 routes[1].sink = dai->driver->playback.stream_name;
Mark Brown5b2eec32012-07-04 17:32:05 +01001444
Mark Brown410837a2012-07-05 17:26:59 +01001445 routes[0].source = arizona_dai_clk_str(dai_priv->clk);
1446 routes[1].source = arizona_dai_clk_str(dai_priv->clk);
1447 snd_soc_dapm_del_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
1448
1449 routes[0].source = arizona_dai_clk_str(clk_id);
1450 routes[1].source = arizona_dai_clk_str(clk_id);
1451 snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
1452
Mark Brown0c778e82012-12-06 18:22:25 +09001453 dai_priv->clk = clk_id;
1454
Mark Brown410837a2012-07-05 17:26:59 +01001455 return snd_soc_dapm_sync(&codec->dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +01001456}
1457
Mark Brown01df2592012-12-12 16:22:08 +09001458static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
1459{
1460 struct snd_soc_codec *codec = dai->codec;
1461 int base = dai->driver->base;
1462 unsigned int reg;
1463
1464 if (tristate)
1465 reg = ARIZONA_AIF1_TRI;
1466 else
1467 reg = 0;
1468
1469 return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1470 ARIZONA_AIF1_TRI, reg);
1471}
1472
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001473static void arizona_set_channels_to_mask(struct snd_soc_dai *dai,
1474 unsigned int base,
1475 int channels, unsigned int mask)
1476{
1477 struct snd_soc_codec *codec = dai->codec;
1478 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1479 struct arizona *arizona = priv->arizona;
1480 int slot, i;
1481
1482 for (i = 0; i < channels; ++i) {
1483 slot = ffs(mask) - 1;
1484 if (slot < 0)
1485 return;
1486
1487 regmap_write(arizona->regmap, base + i, slot);
1488
1489 mask &= ~(1 << slot);
1490 }
1491
1492 if (mask)
1493 arizona_aif_warn(dai, "Too many channels in TDM mask\n");
1494}
1495
1496static int arizona_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
1497 unsigned int rx_mask, int slots, int slot_width)
1498{
1499 struct snd_soc_codec *codec = dai->codec;
1500 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1501 struct arizona *arizona = priv->arizona;
1502 int base = dai->driver->base;
1503 int rx_max_chan = dai->driver->playback.channels_max;
1504 int tx_max_chan = dai->driver->capture.channels_max;
1505
1506 /* Only support TDM for the physical AIFs */
1507 if (dai->id > ARIZONA_MAX_AIF)
1508 return -ENOTSUPP;
1509
1510 if (slots == 0) {
1511 tx_mask = (1 << tx_max_chan) - 1;
1512 rx_mask = (1 << rx_max_chan) - 1;
1513 }
1514
1515 arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_3,
1516 tx_max_chan, tx_mask);
1517 arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_11,
1518 rx_max_chan, rx_mask);
1519
1520 arizona->tdm_width[dai->id - 1] = slot_width;
1521 arizona->tdm_slots[dai->id - 1] = slots;
1522
1523 return 0;
1524}
1525
Mark Brown07ed8732012-06-18 21:08:44 +01001526const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +01001527 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +01001528 .set_fmt = arizona_set_fmt,
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001529 .set_tdm_slot = arizona_set_tdm_slot,
Mark Brown07ed8732012-06-18 21:08:44 +01001530 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +01001531 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown01df2592012-12-12 16:22:08 +09001532 .set_tristate = arizona_set_tristate,
Mark Brown07ed8732012-06-18 21:08:44 +01001533};
Mark Browna8379872012-07-09 12:16:41 +01001534EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +01001535
Mark Brownbd1dd882013-05-17 13:29:03 +01001536const struct snd_soc_dai_ops arizona_simple_dai_ops = {
1537 .startup = arizona_startup,
1538 .hw_params = arizona_hw_params_rate,
1539 .set_sysclk = arizona_dai_set_sysclk,
1540};
1541EXPORT_SYMBOL_GPL(arizona_simple_dai_ops);
1542
Mark Brown5b2eec32012-07-04 17:32:05 +01001543int arizona_init_dai(struct arizona_priv *priv, int id)
1544{
1545 struct arizona_dai_priv *dai_priv = &priv->dai[id];
1546
1547 dai_priv->clk = ARIZONA_CLK_SYSCLK;
1548
1549 return 0;
1550}
1551EXPORT_SYMBOL_GPL(arizona_init_dai);
1552
Mark Brown07ed8732012-06-18 21:08:44 +01001553static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
1554{
1555 struct arizona_fll *fll = data;
1556
1557 arizona_fll_dbg(fll, "clock OK\n");
1558
1559 complete(&fll->ok);
1560
1561 return IRQ_HANDLED;
1562}
1563
1564static struct {
1565 unsigned int min;
1566 unsigned int max;
1567 u16 fratio;
1568 int ratio;
1569} fll_fratios[] = {
1570 { 0, 64000, 4, 16 },
1571 { 64000, 128000, 3, 8 },
1572 { 128000, 256000, 2, 4 },
1573 { 256000, 1000000, 1, 2 },
1574 { 1000000, 13500000, 0, 1 },
1575};
1576
Mark Brown8f113d72013-03-05 12:08:57 +08001577static struct {
1578 unsigned int min;
1579 unsigned int max;
1580 u16 gain;
1581} fll_gains[] = {
1582 { 0, 256000, 0 },
1583 { 256000, 1000000, 2 },
1584 { 1000000, 13500000, 4 },
1585};
1586
Mark Brown07ed8732012-06-18 21:08:44 +01001587struct arizona_fll_cfg {
1588 int n;
1589 int theta;
1590 int lambda;
1591 int refdiv;
1592 int outdiv;
1593 int fratio;
Mark Brown8f113d72013-03-05 12:08:57 +08001594 int gain;
Mark Brown07ed8732012-06-18 21:08:44 +01001595};
1596
Charles Keepax23f785a82014-03-07 16:34:20 +00001597static int arizona_validate_fll(struct arizona_fll *fll,
1598 unsigned int Fref,
1599 unsigned int Fout)
1600{
1601 unsigned int Fvco_min;
1602
Charles Keepaxc8badda2014-07-09 17:41:49 +01001603 if (fll->fout && Fout != fll->fout) {
1604 arizona_fll_err(fll,
1605 "Can't change output on active FLL\n");
1606 return -EINVAL;
1607 }
1608
Charles Keepax23f785a82014-03-07 16:34:20 +00001609 if (Fref / ARIZONA_FLL_MAX_REFDIV > ARIZONA_FLL_MAX_FREF) {
1610 arizona_fll_err(fll,
1611 "Can't scale %dMHz in to <=13.5MHz\n",
1612 Fref);
1613 return -EINVAL;
1614 }
1615
1616 Fvco_min = ARIZONA_FLL_MIN_FVCO * fll->vco_mult;
1617 if (Fout * ARIZONA_FLL_MAX_OUTDIV < Fvco_min) {
1618 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
1619 Fout);
1620 return -EINVAL;
1621 }
1622
1623 return 0;
1624}
1625
Charles Keepaxd0800342014-03-07 16:34:25 +00001626static int arizona_find_fratio(unsigned int Fref, int *fratio)
1627{
1628 int i;
1629
1630 /* Find an appropriate FLL_FRATIO */
1631 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
1632 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
1633 if (fratio)
1634 *fratio = fll_fratios[i].fratio;
1635 return fll_fratios[i].ratio;
1636 }
1637 }
1638
1639 return -EINVAL;
1640}
1641
1642static int arizona_calc_fratio(struct arizona_fll *fll,
1643 struct arizona_fll_cfg *cfg,
1644 unsigned int target,
1645 unsigned int Fref, bool sync)
1646{
1647 int init_ratio, ratio;
1648 int refdiv, div;
1649
1650 /* Fref must be <=13.5MHz, find initial refdiv */
1651 div = 1;
1652 cfg->refdiv = 0;
1653 while (Fref > ARIZONA_FLL_MAX_FREF) {
1654 div *= 2;
1655 Fref /= 2;
1656 cfg->refdiv++;
1657
1658 if (div > ARIZONA_FLL_MAX_REFDIV)
1659 return -EINVAL;
1660 }
1661
1662 /* Find an appropriate FLL_FRATIO */
1663 init_ratio = arizona_find_fratio(Fref, &cfg->fratio);
1664 if (init_ratio < 0) {
1665 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
1666 Fref);
1667 return init_ratio;
1668 }
1669
1670 switch (fll->arizona->type) {
1671 case WM5110:
1672 if (fll->arizona->rev < 3 || sync)
1673 return init_ratio;
1674 break;
1675 default:
1676 return init_ratio;
1677 }
1678
1679 cfg->fratio = init_ratio - 1;
1680
1681 /* Adjust FRATIO/refdiv to avoid integer mode if possible */
1682 refdiv = cfg->refdiv;
1683
1684 while (div <= ARIZONA_FLL_MAX_REFDIV) {
1685 for (ratio = init_ratio; ratio <= ARIZONA_FLL_MAX_FRATIO;
1686 ratio++) {
Charles Keepax35a730a2014-07-09 17:41:45 +01001687 if ((ARIZONA_FLL_VCO_CORNER / 2) /
1688 (fll->vco_mult * ratio) < Fref)
Charles Keepax29fee822014-07-09 17:41:44 +01001689 break;
1690
Charles Keepaxd0800342014-03-07 16:34:25 +00001691 if (target % (ratio * Fref)) {
1692 cfg->refdiv = refdiv;
1693 cfg->fratio = ratio - 1;
1694 return ratio;
1695 }
1696 }
1697
Charles Keepax4714bc02014-07-09 17:41:43 +01001698 for (ratio = init_ratio - 1; ratio > 0; ratio--) {
Charles Keepaxd0800342014-03-07 16:34:25 +00001699 if (target % (ratio * Fref)) {
1700 cfg->refdiv = refdiv;
1701 cfg->fratio = ratio - 1;
1702 return ratio;
1703 }
1704 }
1705
1706 div *= 2;
1707 Fref /= 2;
1708 refdiv++;
1709 init_ratio = arizona_find_fratio(Fref, NULL);
1710 }
1711
1712 arizona_fll_warn(fll, "Falling back to integer mode operation\n");
1713 return cfg->fratio + 1;
1714}
1715
Mark Brown07ed8732012-06-18 21:08:44 +01001716static int arizona_calc_fll(struct arizona_fll *fll,
1717 struct arizona_fll_cfg *cfg,
Charles Keepaxd0800342014-03-07 16:34:25 +00001718 unsigned int Fref, bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01001719{
1720 unsigned int target, div, gcd_fll;
1721 int i, ratio;
1722
Charles Keepax8ccefcd2014-03-07 16:34:21 +00001723 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, fll->fout);
Mark Brown07ed8732012-06-18 21:08:44 +01001724
Mark Brown2b4d39f2012-07-10 17:03:46 +01001725 /* Fvco should be over the targt; don't check the upper bound */
Charles Keepaxf641aec2014-03-07 16:34:22 +00001726 div = ARIZONA_FLL_MIN_OUTDIV;
1727 while (fll->fout * div < ARIZONA_FLL_MIN_FVCO * fll->vco_mult) {
Mark Brown07ed8732012-06-18 21:08:44 +01001728 div++;
Charles Keepaxf641aec2014-03-07 16:34:22 +00001729 if (div > ARIZONA_FLL_MAX_OUTDIV)
Mark Brown07ed8732012-06-18 21:08:44 +01001730 return -EINVAL;
Mark Brown07ed8732012-06-18 21:08:44 +01001731 }
Charles Keepaxf641aec2014-03-07 16:34:22 +00001732 target = fll->fout * div / fll->vco_mult;
Mark Brown07ed8732012-06-18 21:08:44 +01001733 cfg->outdiv = div;
1734
1735 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
1736
Charles Keepaxd0800342014-03-07 16:34:25 +00001737 /* Find an appropriate FLL_FRATIO and refdiv */
1738 ratio = arizona_calc_fratio(fll, cfg, target, Fref, sync);
1739 if (ratio < 0)
1740 return ratio;
Mark Brown07ed8732012-06-18 21:08:44 +01001741
Mark Brown07ed8732012-06-18 21:08:44 +01001742 /* Apply the division for our remaining calculations */
Charles Keepaxd0800342014-03-07 16:34:25 +00001743 Fref = Fref / (1 << cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08001744
Mark Brown07ed8732012-06-18 21:08:44 +01001745 cfg->n = target / (ratio * Fref);
1746
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001747 if (target % (ratio * Fref)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001748 gcd_fll = gcd(target, ratio * Fref);
1749 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
1750
1751 cfg->theta = (target - (cfg->n * ratio * Fref))
1752 / gcd_fll;
1753 cfg->lambda = (ratio * Fref) / gcd_fll;
1754 } else {
1755 cfg->theta = 0;
1756 cfg->lambda = 0;
1757 }
1758
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001759 /* Round down to 16bit range with cost of accuracy lost.
1760 * Denominator must be bigger than numerator so we only
1761 * take care of it.
1762 */
1763 while (cfg->lambda >= (1 << 16)) {
1764 cfg->theta >>= 1;
1765 cfg->lambda >>= 1;
1766 }
1767
Charles Keepax5a3935c2014-03-07 16:34:23 +00001768 for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
1769 if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
1770 cfg->gain = fll_gains[i].gain;
1771 break;
1772 }
1773 }
1774 if (i == ARRAY_SIZE(fll_gains)) {
1775 arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
1776 Fref);
1777 return -EINVAL;
1778 }
1779
Mark Brown07ed8732012-06-18 21:08:44 +01001780 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
1781 cfg->n, cfg->theta, cfg->lambda);
1782 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
1783 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08001784 arizona_fll_dbg(fll, "GAIN=%d\n", cfg->gain);
Mark Brown07ed8732012-06-18 21:08:44 +01001785
1786 return 0;
1787
1788}
1789
1790static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
Mark Brown8f113d72013-03-05 12:08:57 +08001791 struct arizona_fll_cfg *cfg, int source,
1792 bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01001793{
Mark Brown3c43c692013-12-12 00:49:22 +00001794 regmap_update_bits_async(arizona->regmap, base + 3,
1795 ARIZONA_FLL1_THETA_MASK, cfg->theta);
1796 regmap_update_bits_async(arizona->regmap, base + 4,
1797 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
1798 regmap_update_bits_async(arizona->regmap, base + 5,
1799 ARIZONA_FLL1_FRATIO_MASK,
1800 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
1801 regmap_update_bits_async(arizona->regmap, base + 6,
1802 ARIZONA_FLL1_CLK_REF_DIV_MASK |
1803 ARIZONA_FLL1_CLK_REF_SRC_MASK,
1804 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
1805 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
Mark Brown07ed8732012-06-18 21:08:44 +01001806
Charles Keepax61719db2014-03-07 16:34:19 +00001807 if (sync) {
1808 regmap_update_bits(arizona->regmap, base + 0x7,
1809 ARIZONA_FLL1_GAIN_MASK,
1810 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
1811 } else {
1812 regmap_update_bits(arizona->regmap, base + 0x5,
1813 ARIZONA_FLL1_OUTDIV_MASK,
1814 cfg->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
1815 regmap_update_bits(arizona->regmap, base + 0x9,
1816 ARIZONA_FLL1_GAIN_MASK,
1817 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
1818 }
Mark Brown8f113d72013-03-05 12:08:57 +08001819
Mark Brown3c43c692013-12-12 00:49:22 +00001820 regmap_update_bits_async(arizona->regmap, base + 2,
1821 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
1822 ARIZONA_FLL1_CTRL_UPD | cfg->n);
Mark Brown07ed8732012-06-18 21:08:44 +01001823}
1824
Charles Keepaxc393aca2014-07-09 17:41:47 +01001825static int arizona_is_enabled_fll(struct arizona_fll *fll)
Charles Keepaxd122d6c2013-02-20 17:28:36 +00001826{
1827 struct arizona *arizona = fll->arizona;
1828 unsigned int reg;
1829 int ret;
1830
1831 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
1832 if (ret != 0) {
1833 arizona_fll_err(fll, "Failed to read current state: %d\n",
1834 ret);
1835 return ret;
1836 }
1837
1838 return reg & ARIZONA_FLL1_ENA;
1839}
1840
Charles Keepaxc393aca2014-07-09 17:41:47 +01001841static int arizona_enable_fll(struct arizona_fll *fll)
Charles Keepax35722812013-02-20 17:28:38 +00001842{
1843 struct arizona *arizona = fll->arizona;
1844 int ret;
Charles Keepax49c60542013-09-16 15:34:35 +01001845 bool use_sync = false;
Charles Keepaxc393aca2014-07-09 17:41:47 +01001846 int already_enabled = arizona_is_enabled_fll(fll);
Charles Keepax23f785a82014-03-07 16:34:20 +00001847 struct arizona_fll_cfg cfg;
Charles Keepax35722812013-02-20 17:28:38 +00001848
Charles Keepaxc393aca2014-07-09 17:41:47 +01001849 if (already_enabled < 0)
1850 return already_enabled;
1851
Charles Keepaxc8badda2014-07-09 17:41:49 +01001852 if (already_enabled) {
1853 /* Facilitate smooth refclk across the transition */
1854 regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x7,
1855 ARIZONA_FLL1_GAIN_MASK, 0);
1856 regmap_update_bits_async(fll->arizona->regmap, fll->base + 1,
1857 ARIZONA_FLL1_FREERUN,
1858 ARIZONA_FLL1_FREERUN);
1859 }
1860
Mark Brownff680a12013-03-04 16:00:19 +08001861 /*
1862 * If we have both REFCLK and SYNCCLK then enable both,
1863 * otherwise apply the SYNCCLK settings to REFCLK.
1864 */
Charles Keepax49c60542013-09-16 15:34:35 +01001865 if (fll->ref_src >= 0 && fll->ref_freq &&
1866 fll->ref_src != fll->sync_src) {
Charles Keepaxd0800342014-03-07 16:34:25 +00001867 arizona_calc_fll(fll, &cfg, fll->ref_freq, false);
Charles Keepax35722812013-02-20 17:28:38 +00001868
Charles Keepax23f785a82014-03-07 16:34:20 +00001869 arizona_apply_fll(arizona, fll->base, &cfg, fll->ref_src,
Mark Brown8f113d72013-03-05 12:08:57 +08001870 false);
Charles Keepax49c60542013-09-16 15:34:35 +01001871 if (fll->sync_src >= 0) {
Charles Keepaxd0800342014-03-07 16:34:25 +00001872 arizona_calc_fll(fll, &cfg, fll->sync_freq, true);
Charles Keepax23f785a82014-03-07 16:34:20 +00001873
1874 arizona_apply_fll(arizona, fll->base + 0x10, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08001875 fll->sync_src, true);
Charles Keepax49c60542013-09-16 15:34:35 +01001876 use_sync = true;
1877 }
Mark Brownff680a12013-03-04 16:00:19 +08001878 } else if (fll->sync_src >= 0) {
Charles Keepaxd0800342014-03-07 16:34:25 +00001879 arizona_calc_fll(fll, &cfg, fll->sync_freq, false);
Mark Brownff680a12013-03-04 16:00:19 +08001880
Charles Keepax23f785a82014-03-07 16:34:20 +00001881 arizona_apply_fll(arizona, fll->base, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08001882 fll->sync_src, false);
Mark Browneca2e8e2013-03-06 00:09:59 +08001883
Mark Brown3c43c692013-12-12 00:49:22 +00001884 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
1885 ARIZONA_FLL1_SYNC_ENA, 0);
Mark Brownff680a12013-03-04 16:00:19 +08001886 } else {
1887 arizona_fll_err(fll, "No clocks provided\n");
Charles Keepaxc393aca2014-07-09 17:41:47 +01001888 return -EINVAL;
Mark Brownff680a12013-03-04 16:00:19 +08001889 }
Charles Keepax35722812013-02-20 17:28:38 +00001890
Mark Brown576411be2013-03-05 12:07:16 +08001891 /*
1892 * Increase the bandwidth if we're not using a low frequency
1893 * sync source.
1894 */
Charles Keepax49c60542013-09-16 15:34:35 +01001895 if (use_sync && fll->sync_freq > 100000)
Mark Brown3c43c692013-12-12 00:49:22 +00001896 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
1897 ARIZONA_FLL1_SYNC_BW, 0);
Mark Brown576411be2013-03-05 12:07:16 +08001898 else
Mark Brown3c43c692013-12-12 00:49:22 +00001899 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
1900 ARIZONA_FLL1_SYNC_BW,
1901 ARIZONA_FLL1_SYNC_BW);
Mark Brown576411be2013-03-05 12:07:16 +08001902
Charles Keepaxc393aca2014-07-09 17:41:47 +01001903 if (!already_enabled)
Charles Keepax35722812013-02-20 17:28:38 +00001904 pm_runtime_get(arizona->dev);
1905
1906 /* Clear any pending completions */
1907 try_wait_for_completion(&fll->ok);
1908
Mark Brown3c43c692013-12-12 00:49:22 +00001909 regmap_update_bits_async(arizona->regmap, fll->base + 1,
Mark Brown3c43c692013-12-12 00:49:22 +00001910 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
Charles Keepax49c60542013-09-16 15:34:35 +01001911 if (use_sync)
Mark Brown3c43c692013-12-12 00:49:22 +00001912 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
1913 ARIZONA_FLL1_SYNC_ENA,
1914 ARIZONA_FLL1_SYNC_ENA);
Charles Keepax35722812013-02-20 17:28:38 +00001915
Charles Keepaxc8badda2014-07-09 17:41:49 +01001916 if (already_enabled)
1917 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1918 ARIZONA_FLL1_FREERUN, 0);
1919
Charles Keepax35722812013-02-20 17:28:38 +00001920 ret = wait_for_completion_timeout(&fll->ok,
1921 msecs_to_jiffies(250));
1922 if (ret == 0)
1923 arizona_fll_warn(fll, "Timed out waiting for lock\n");
Charles Keepaxc393aca2014-07-09 17:41:47 +01001924
1925 return 0;
Charles Keepax35722812013-02-20 17:28:38 +00001926}
1927
Charles Keepax76040542013-02-20 17:28:37 +00001928static void arizona_disable_fll(struct arizona_fll *fll)
1929{
1930 struct arizona *arizona = fll->arizona;
1931 bool change;
1932
Mark Brown3c43c692013-12-12 00:49:22 +00001933 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1934 ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
Charles Keepax76040542013-02-20 17:28:37 +00001935 regmap_update_bits_check(arizona->regmap, fll->base + 1,
1936 ARIZONA_FLL1_ENA, 0, &change);
1937 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1938 ARIZONA_FLL1_SYNC_ENA, 0);
Charles Keepax5e39a502014-07-09 17:41:48 +01001939 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1940 ARIZONA_FLL1_FREERUN, 0);
Charles Keepax76040542013-02-20 17:28:37 +00001941
1942 if (change)
1943 pm_runtime_put_autosuspend(arizona->dev);
1944}
1945
Charles Keepaxee929a92013-02-20 17:28:40 +00001946int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
1947 unsigned int Fref, unsigned int Fout)
1948{
Charles Keepaxc393aca2014-07-09 17:41:47 +01001949 int ret = 0;
Charles Keepaxee929a92013-02-20 17:28:40 +00001950
Charles Keepax1c5617f2013-02-22 17:10:37 +00001951 if (fll->ref_src == source && fll->ref_freq == Fref)
Charles Keepaxee929a92013-02-20 17:28:40 +00001952 return 0;
1953
Charles Keepax23f785a82014-03-07 16:34:20 +00001954 if (fll->fout && Fref > 0) {
1955 ret = arizona_validate_fll(fll, Fref, fll->fout);
1956 if (ret != 0)
1957 return ret;
Charles Keepaxee929a92013-02-20 17:28:40 +00001958 }
1959
1960 fll->ref_src = source;
1961 fll->ref_freq = Fref;
Charles Keepaxee929a92013-02-20 17:28:40 +00001962
Mark Brown86cd6842013-03-07 16:14:04 +08001963 if (fll->fout && Fref > 0) {
Charles Keepaxc393aca2014-07-09 17:41:47 +01001964 ret = arizona_enable_fll(fll);
Charles Keepaxee929a92013-02-20 17:28:40 +00001965 }
1966
Charles Keepaxc393aca2014-07-09 17:41:47 +01001967 return ret;
Charles Keepaxee929a92013-02-20 17:28:40 +00001968}
1969EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
1970
Mark Brown07ed8732012-06-18 21:08:44 +01001971int arizona_set_fll(struct arizona_fll *fll, int source,
1972 unsigned int Fref, unsigned int Fout)
1973{
Charles Keepaxc393aca2014-07-09 17:41:47 +01001974 int ret = 0;
Mark Brown07ed8732012-06-18 21:08:44 +01001975
Mark Brownff680a12013-03-04 16:00:19 +08001976 if (fll->sync_src == source &&
1977 fll->sync_freq == Fref && fll->fout == Fout)
1978 return 0;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00001979
Mark Brownff680a12013-03-04 16:00:19 +08001980 if (Fout) {
1981 if (fll->ref_src >= 0) {
Charles Keepax23f785a82014-03-07 16:34:20 +00001982 ret = arizona_validate_fll(fll, fll->ref_freq, Fout);
Charles Keepax9e359c62013-02-20 17:28:35 +00001983 if (ret != 0)
1984 return ret;
1985 }
1986
Charles Keepax23f785a82014-03-07 16:34:20 +00001987 ret = arizona_validate_fll(fll, Fref, Fout);
Mark Brownff680a12013-03-04 16:00:19 +08001988 if (ret != 0)
1989 return ret;
Charles Keepax9e359c62013-02-20 17:28:35 +00001990 }
Mark Brownff680a12013-03-04 16:00:19 +08001991
1992 fll->sync_src = source;
1993 fll->sync_freq = Fref;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00001994 fll->fout = Fout;
Charles Keepax9e359c62013-02-20 17:28:35 +00001995
Charles Keepax613124c2014-07-09 17:41:46 +01001996 if (Fout)
Charles Keepaxc393aca2014-07-09 17:41:47 +01001997 ret = arizona_enable_fll(fll);
Charles Keepax613124c2014-07-09 17:41:46 +01001998 else
Charles Keepax76040542013-02-20 17:28:37 +00001999 arizona_disable_fll(fll);
Mark Brown07ed8732012-06-18 21:08:44 +01002000
Charles Keepaxc393aca2014-07-09 17:41:47 +01002001 return ret;
Mark Brown07ed8732012-06-18 21:08:44 +01002002}
2003EXPORT_SYMBOL_GPL(arizona_set_fll);
2004
2005int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
2006 int ok_irq, struct arizona_fll *fll)
2007{
2008 int ret;
Charles Keepax19b34bd2013-02-20 17:28:34 +00002009 unsigned int val;
Mark Brown07ed8732012-06-18 21:08:44 +01002010
Mark Brown07ed8732012-06-18 21:08:44 +01002011 init_completion(&fll->ok);
2012
2013 fll->id = id;
2014 fll->base = base;
2015 fll->arizona = arizona;
Charles Keepaxf3f11632013-02-20 17:28:41 +00002016 fll->sync_src = ARIZONA_FLL_SRC_NONE;
Mark Brown07ed8732012-06-18 21:08:44 +01002017
Charles Keepax19b34bd2013-02-20 17:28:34 +00002018 /* Configure default refclk to 32kHz if we have one */
2019 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
2020 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
2021 case ARIZONA_CLK_SRC_MCLK1:
2022 case ARIZONA_CLK_SRC_MCLK2:
2023 fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK;
2024 break;
2025 default:
Charles Keepaxf3f11632013-02-20 17:28:41 +00002026 fll->ref_src = ARIZONA_FLL_SRC_NONE;
Charles Keepax19b34bd2013-02-20 17:28:34 +00002027 }
2028 fll->ref_freq = 32768;
2029
Mark Brown07ed8732012-06-18 21:08:44 +01002030 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
2031 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
2032 "FLL%d clock OK", id);
2033
Mark Brown07ed8732012-06-18 21:08:44 +01002034 ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
2035 arizona_fll_clock_ok, fll);
2036 if (ret != 0) {
2037 dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
2038 id, ret);
2039 }
2040
Charles Keepaxe31c1942013-01-07 16:41:45 +00002041 regmap_update_bits(arizona->regmap, fll->base + 1,
2042 ARIZONA_FLL1_FREERUN, 0);
2043
Mark Brown07ed8732012-06-18 21:08:44 +01002044 return 0;
2045}
2046EXPORT_SYMBOL_GPL(arizona_init_fll);
2047
Mark Brownbc9ab6d2013-01-04 19:31:00 +00002048/**
2049 * arizona_set_output_mode - Set the mode of the specified output
2050 *
2051 * @codec: Device to configure
2052 * @output: Output number
2053 * @diff: True to set the output to differential mode
2054 *
2055 * Some systems use external analogue switches to connect more
2056 * analogue devices to the CODEC than are supported by the device. In
2057 * some systems this requires changing the switched output from single
2058 * ended to differential mode dynamically at runtime, an operation
2059 * supported using this function.
2060 *
2061 * Most systems have a single static configuration and should use
2062 * platform data instead.
2063 */
2064int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
2065{
2066 unsigned int reg, val;
2067
2068 if (output < 1 || output > 6)
2069 return -EINVAL;
2070
2071 reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
2072
2073 if (diff)
2074 val = ARIZONA_OUT1_MONO;
2075 else
2076 val = 0;
2077
2078 return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val);
2079}
2080EXPORT_SYMBOL_GPL(arizona_set_output_mode);
2081
Mark Brown07ed8732012-06-18 21:08:44 +01002082MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
2083MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
2084MODULE_LICENSE("GPL");