blob: 5939ce467352fdbc4ac61df8c12605a3f1993149 [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>
22#include <linux/mfd/arizona/registers.h>
23
24#include "arizona.h"
25
26#define ARIZONA_AIF_BCLK_CTRL 0x00
27#define ARIZONA_AIF_TX_PIN_CTRL 0x01
28#define ARIZONA_AIF_RX_PIN_CTRL 0x02
29#define ARIZONA_AIF_RATE_CTRL 0x03
30#define ARIZONA_AIF_FORMAT 0x04
31#define ARIZONA_AIF_TX_BCLK_RATE 0x05
32#define ARIZONA_AIF_RX_BCLK_RATE 0x06
33#define ARIZONA_AIF_FRAME_CTRL_1 0x07
34#define ARIZONA_AIF_FRAME_CTRL_2 0x08
35#define ARIZONA_AIF_FRAME_CTRL_3 0x09
36#define ARIZONA_AIF_FRAME_CTRL_4 0x0A
37#define ARIZONA_AIF_FRAME_CTRL_5 0x0B
38#define ARIZONA_AIF_FRAME_CTRL_6 0x0C
39#define ARIZONA_AIF_FRAME_CTRL_7 0x0D
40#define ARIZONA_AIF_FRAME_CTRL_8 0x0E
41#define ARIZONA_AIF_FRAME_CTRL_9 0x0F
42#define ARIZONA_AIF_FRAME_CTRL_10 0x10
43#define ARIZONA_AIF_FRAME_CTRL_11 0x11
44#define ARIZONA_AIF_FRAME_CTRL_12 0x12
45#define ARIZONA_AIF_FRAME_CTRL_13 0x13
46#define ARIZONA_AIF_FRAME_CTRL_14 0x14
47#define ARIZONA_AIF_FRAME_CTRL_15 0x15
48#define ARIZONA_AIF_FRAME_CTRL_16 0x16
49#define ARIZONA_AIF_FRAME_CTRL_17 0x17
50#define ARIZONA_AIF_FRAME_CTRL_18 0x18
51#define ARIZONA_AIF_TX_ENABLES 0x19
52#define ARIZONA_AIF_RX_ENABLES 0x1A
53#define ARIZONA_AIF_FORCE_WRITE 0x1B
54
Charles Keepaxd0800342014-03-07 16:34:25 +000055#define ARIZONA_FLL_VCO_CORNER 141900000
Charles Keepax87383ac2014-03-07 16:34:18 +000056#define ARIZONA_FLL_MAX_FREF 13500000
57#define ARIZONA_FLL_MIN_FVCO 90000000
Charles Keepaxd0800342014-03-07 16:34:25 +000058#define ARIZONA_FLL_MAX_FRATIO 16
Charles Keepax87383ac2014-03-07 16:34:18 +000059#define ARIZONA_FLL_MAX_REFDIV 8
60#define ARIZONA_FLL_MIN_OUTDIV 2
61#define ARIZONA_FLL_MAX_OUTDIV 7
62
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +000063#define ARIZONA_FMT_DSP_MODE_A 0
64#define ARIZONA_FMT_DSP_MODE_B 1
65#define ARIZONA_FMT_I2S_MODE 2
66#define ARIZONA_FMT_LEFT_JUSTIFIED_MODE 3
67
Mark Brown07ed8732012-06-18 21:08:44 +010068#define arizona_fll_err(_fll, fmt, ...) \
69 dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
70#define arizona_fll_warn(_fll, fmt, ...) \
71 dev_warn(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
72#define arizona_fll_dbg(_fll, fmt, ...) \
Mark Brown9092a6e2013-02-06 17:58:57 +000073 dev_dbg(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
Mark Brown07ed8732012-06-18 21:08:44 +010074
75#define arizona_aif_err(_dai, fmt, ...) \
76 dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
77#define arizona_aif_warn(_dai, fmt, ...) \
78 dev_warn(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
79#define arizona_aif_dbg(_dai, fmt, ...) \
Mark Brown9092a6e2013-02-06 17:58:57 +000080 dev_dbg(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
Mark Brown07ed8732012-06-18 21:08:44 +010081
Mark Brown56447e12013-01-10 14:45:58 +000082static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
83 struct snd_kcontrol *kcontrol,
84 int event)
85{
Lars-Peter Clausen043123f2015-01-13 10:27:07 +010086 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
Mark Brown56447e12013-01-10 14:45:58 +000087 struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
88 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
89 bool manual_ena = false;
Mark Brownf4a76e72013-03-13 12:22:39 +000090 int val;
Mark Brown56447e12013-01-10 14:45:58 +000091
92 switch (arizona->type) {
93 case WM5102:
94 switch (arizona->rev) {
95 case 0:
96 break;
97 default:
98 manual_ena = true;
99 break;
100 }
101 default:
102 break;
103 }
104
105 switch (event) {
106 case SND_SOC_DAPM_PRE_PMU:
107 if (!priv->spk_ena && manual_ena) {
Mark Brown3c43c692013-12-12 00:49:22 +0000108 regmap_write_async(arizona->regmap, 0x4f5, 0x25a);
Mark Brown56447e12013-01-10 14:45:58 +0000109 priv->spk_ena_pending = true;
110 }
111 break;
112 case SND_SOC_DAPM_POST_PMU:
Mark Brownf4a76e72013-03-13 12:22:39 +0000113 val = snd_soc_read(codec, ARIZONA_INTERRUPT_RAW_STATUS_3);
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100114 if (val & ARIZONA_SPK_OVERHEAT_STS) {
Mark Brownf4a76e72013-03-13 12:22:39 +0000115 dev_crit(arizona->dev,
116 "Speaker not enabled due to temperature\n");
117 return -EBUSY;
118 }
119
Mark Brown3c43c692013-12-12 00:49:22 +0000120 regmap_update_bits_async(arizona->regmap,
121 ARIZONA_OUTPUT_ENABLES_1,
122 1 << w->shift, 1 << w->shift);
Mark Brownf4a76e72013-03-13 12:22:39 +0000123
Mark Brown56447e12013-01-10 14:45:58 +0000124 if (priv->spk_ena_pending) {
125 msleep(75);
Mark Brown3c43c692013-12-12 00:49:22 +0000126 regmap_write_async(arizona->regmap, 0x4f5, 0xda);
Mark Brown56447e12013-01-10 14:45:58 +0000127 priv->spk_ena_pending = false;
128 priv->spk_ena++;
129 }
130 break;
131 case SND_SOC_DAPM_PRE_PMD:
132 if (manual_ena) {
133 priv->spk_ena--;
134 if (!priv->spk_ena)
Mark Brown3c43c692013-12-12 00:49:22 +0000135 regmap_write_async(arizona->regmap,
136 0x4f5, 0x25a);
Mark Brown56447e12013-01-10 14:45:58 +0000137 }
Mark Brownf4a76e72013-03-13 12:22:39 +0000138
Mark Brown3c43c692013-12-12 00:49:22 +0000139 regmap_update_bits_async(arizona->regmap,
140 ARIZONA_OUTPUT_ENABLES_1,
141 1 << w->shift, 0);
Mark Brown56447e12013-01-10 14:45:58 +0000142 break;
143 case SND_SOC_DAPM_POST_PMD:
144 if (manual_ena) {
145 if (!priv->spk_ena)
Mark Brown3c43c692013-12-12 00:49:22 +0000146 regmap_write_async(arizona->regmap,
147 0x4f5, 0x0da);
Mark Brown56447e12013-01-10 14:45:58 +0000148 }
149 break;
150 }
151
152 return 0;
153}
154
Mark Brown899817e2013-03-13 12:32:10 +0000155static irqreturn_t arizona_thermal_warn(int irq, void *data)
156{
157 struct arizona *arizona = data;
158 unsigned int val;
159 int ret;
160
161 ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
162 &val);
163 if (ret != 0) {
164 dev_err(arizona->dev, "Failed to read thermal status: %d\n",
165 ret);
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100166 } else if (val & ARIZONA_SPK_OVERHEAT_WARN_STS) {
Mark Brown899817e2013-03-13 12:32:10 +0000167 dev_crit(arizona->dev, "Thermal warning\n");
168 }
169
170 return IRQ_HANDLED;
171}
172
173static irqreturn_t arizona_thermal_shutdown(int irq, void *data)
174{
175 struct arizona *arizona = data;
176 unsigned int val;
177 int ret;
178
179 ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
180 &val);
181 if (ret != 0) {
182 dev_err(arizona->dev, "Failed to read thermal status: %d\n",
183 ret);
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100184 } else if (val & ARIZONA_SPK_OVERHEAT_STS) {
Mark Brown899817e2013-03-13 12:32:10 +0000185 dev_crit(arizona->dev, "Thermal shutdown\n");
Mark Brownf4a76e72013-03-13 12:22:39 +0000186 ret = regmap_update_bits(arizona->regmap,
187 ARIZONA_OUTPUT_ENABLES_1,
188 ARIZONA_OUT4L_ENA |
189 ARIZONA_OUT4R_ENA, 0);
190 if (ret != 0)
191 dev_crit(arizona->dev,
192 "Failed to disable speaker outputs: %d\n",
193 ret);
Mark Brown899817e2013-03-13 12:32:10 +0000194 }
195
196 return IRQ_HANDLED;
197}
198
Mark Brown56447e12013-01-10 14:45:58 +0000199static const struct snd_soc_dapm_widget arizona_spkl =
Mark Brownf4a76e72013-03-13 12:22:39 +0000200 SND_SOC_DAPM_PGA_E("OUT4L", SND_SOC_NOPM,
Mark Brown56447e12013-01-10 14:45:58 +0000201 ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
202 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
203
204static const struct snd_soc_dapm_widget arizona_spkr =
Mark Brownf4a76e72013-03-13 12:22:39 +0000205 SND_SOC_DAPM_PGA_E("OUT4R", SND_SOC_NOPM,
Mark Brown56447e12013-01-10 14:45:58 +0000206 ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
207 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
208
209int arizona_init_spk(struct snd_soc_codec *codec)
210{
Mark Brown899817e2013-03-13 12:32:10 +0000211 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
212 struct arizona *arizona = priv->arizona;
Mark Brown56447e12013-01-10 14:45:58 +0000213 int ret;
214
215 ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkl, 1);
216 if (ret != 0)
217 return ret;
218
Charles Keepax40843ae2013-08-12 23:46:55 +0100219 switch (arizona->type) {
220 case WM8997:
221 break;
222 default:
223 ret = snd_soc_dapm_new_controls(&codec->dapm,
224 &arizona_spkr, 1);
225 if (ret != 0)
226 return ret;
227 break;
228 }
Mark Brown56447e12013-01-10 14:45:58 +0000229
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100230 ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN,
Mark Brown899817e2013-03-13 12:32:10 +0000231 "Thermal warning", arizona_thermal_warn,
232 arizona);
233 if (ret != 0)
234 dev_err(arizona->dev,
235 "Failed to get thermal warning IRQ: %d\n",
236 ret);
237
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100238 ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT,
Mark Brown899817e2013-03-13 12:32:10 +0000239 "Thermal shutdown", arizona_thermal_shutdown,
240 arizona);
241 if (ret != 0)
242 dev_err(arizona->dev,
243 "Failed to get thermal shutdown IRQ: %d\n",
244 ret);
245
Mark Brown56447e12013-01-10 14:45:58 +0000246 return 0;
247}
248EXPORT_SYMBOL_GPL(arizona_init_spk);
249
Charles Keepaxb60f3632014-06-10 18:41:02 +0100250static const struct snd_soc_dapm_route arizona_mono_routes[] = {
251 { "OUT1R", NULL, "OUT1L" },
252 { "OUT2R", NULL, "OUT2L" },
253 { "OUT3R", NULL, "OUT3L" },
254 { "OUT4R", NULL, "OUT4L" },
255 { "OUT5R", NULL, "OUT5L" },
256 { "OUT6R", NULL, "OUT6L" },
257};
258
259int arizona_init_mono(struct snd_soc_codec *codec)
260{
261 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
262 struct arizona *arizona = priv->arizona;
263 int i;
264
265 for (i = 0; i < ARIZONA_MAX_OUTPUT; ++i) {
266 if (arizona->pdata.out_mono[i])
267 snd_soc_dapm_add_routes(&codec->dapm,
268 &arizona_mono_routes[i], 1);
269 }
270
271 return 0;
272}
273EXPORT_SYMBOL_GPL(arizona_init_mono);
274
Charles Keepaxb63144e2013-07-04 08:56:28 +0100275int arizona_init_gpio(struct snd_soc_codec *codec)
276{
277 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
278 struct arizona *arizona = priv->arizona;
279 int i;
280
281 switch (arizona->type) {
282 case WM5110:
Richard Fitzgerald575ef7f2015-01-17 15:21:27 +0000283 case WM8280:
Charles Keepaxb63144e2013-07-04 08:56:28 +0100284 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{
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100695 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
696 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000697 unsigned int reg;
698
699 if (w->shift % 2)
700 reg = ARIZONA_ADC_DIGITAL_VOLUME_1L + ((w->shift / 2) * 8);
701 else
702 reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8);
703
704 switch (event) {
Mark Brownddbce972013-02-15 17:27:22 +0000705 case SND_SOC_DAPM_PRE_PMU:
706 priv->in_pending++;
707 break;
Mark Brown43cd8bf2013-02-06 16:57:29 +0000708 case SND_SOC_DAPM_POST_PMU:
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100709 snd_soc_update_bits(codec, reg, ARIZONA_IN1L_MUTE, 0);
Mark Brownddbce972013-02-15 17:27:22 +0000710
711 /* If this is the last input pending then allow VU */
712 priv->in_pending--;
713 if (priv->in_pending == 0) {
714 msleep(1);
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100715 arizona_in_set_vu(codec, 1);
Mark Brownddbce972013-02-15 17:27:22 +0000716 }
Mark Brown43cd8bf2013-02-06 16:57:29 +0000717 break;
718 case SND_SOC_DAPM_PRE_PMD:
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100719 snd_soc_update_bits(codec, reg,
Mark Brownddbce972013-02-15 17:27:22 +0000720 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU,
721 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000722 break;
Mark Brownddbce972013-02-15 17:27:22 +0000723 case SND_SOC_DAPM_POST_PMD:
724 /* Disable volume updates if no inputs are enabled */
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100725 reg = snd_soc_read(codec, ARIZONA_INPUT_ENABLES);
Mark Brownddbce972013-02-15 17:27:22 +0000726 if (reg == 0)
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100727 arizona_in_set_vu(codec, 0);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000728 }
729
Mark Brown07ed8732012-06-18 21:08:44 +0100730 return 0;
731}
732EXPORT_SYMBOL_GPL(arizona_in_ev);
733
734int arizona_out_ev(struct snd_soc_dapm_widget *w,
735 struct snd_kcontrol *kcontrol,
736 int event)
737{
Mark Brown60d66c92015-01-27 23:50:47 +0000738 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
739 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Charles Keepax054e1b42015-01-20 16:31:50 +0000740
Mark Brown1a2c7d52013-03-24 22:50:23 +0000741 switch (event) {
Charles Keepaxe1ae5fb2015-01-20 16:31:51 +0000742 case SND_SOC_DAPM_PRE_PMU:
743 switch (w->shift) {
744 case ARIZONA_OUT1L_ENA_SHIFT:
745 case ARIZONA_OUT1R_ENA_SHIFT:
746 case ARIZONA_OUT2L_ENA_SHIFT:
747 case ARIZONA_OUT2R_ENA_SHIFT:
748 case ARIZONA_OUT3L_ENA_SHIFT:
749 case ARIZONA_OUT3R_ENA_SHIFT:
750 priv->out_up_pending++;
751 priv->out_up_delay += 17;
752 break;
753 default:
754 break;
755 }
756 break;
Mark Brown1a2c7d52013-03-24 22:50:23 +0000757 case SND_SOC_DAPM_POST_PMU:
758 switch (w->shift) {
759 case ARIZONA_OUT1L_ENA_SHIFT:
760 case ARIZONA_OUT1R_ENA_SHIFT:
761 case ARIZONA_OUT2L_ENA_SHIFT:
762 case ARIZONA_OUT2R_ENA_SHIFT:
763 case ARIZONA_OUT3L_ENA_SHIFT:
764 case ARIZONA_OUT3R_ENA_SHIFT:
Charles Keepaxe1ae5fb2015-01-20 16:31:51 +0000765 priv->out_up_pending--;
766 if (!priv->out_up_pending) {
767 msleep(priv->out_up_delay);
768 priv->out_up_delay = 0;
769 }
Mark Brown1a2c7d52013-03-24 22:50:23 +0000770 break;
771
772 default:
773 break;
774 }
775 break;
Charles Keepax054e1b42015-01-20 16:31:50 +0000776 case SND_SOC_DAPM_PRE_PMD:
777 switch (w->shift) {
778 case ARIZONA_OUT1L_ENA_SHIFT:
779 case ARIZONA_OUT1R_ENA_SHIFT:
780 case ARIZONA_OUT2L_ENA_SHIFT:
781 case ARIZONA_OUT2R_ENA_SHIFT:
782 case ARIZONA_OUT3L_ENA_SHIFT:
783 case ARIZONA_OUT3R_ENA_SHIFT:
784 priv->out_down_pending++;
785 priv->out_down_delay++;
786 break;
787 default:
788 break;
789 }
790 break;
791 case SND_SOC_DAPM_POST_PMD:
792 switch (w->shift) {
793 case ARIZONA_OUT1L_ENA_SHIFT:
794 case ARIZONA_OUT1R_ENA_SHIFT:
795 case ARIZONA_OUT2L_ENA_SHIFT:
796 case ARIZONA_OUT2R_ENA_SHIFT:
797 case ARIZONA_OUT3L_ENA_SHIFT:
798 case ARIZONA_OUT3R_ENA_SHIFT:
799 priv->out_down_pending--;
800 if (!priv->out_down_pending) {
801 msleep(priv->out_down_delay);
802 priv->out_down_delay = 0;
803 }
804 break;
805 default:
806 break;
807 }
808 break;
Mark Brown1a2c7d52013-03-24 22:50:23 +0000809 }
810
Mark Brown07ed8732012-06-18 21:08:44 +0100811 return 0;
812}
813EXPORT_SYMBOL_GPL(arizona_out_ev);
814
Mark Brownf607e312013-02-22 18:36:53 +0000815int arizona_hp_ev(struct snd_soc_dapm_widget *w,
816 struct snd_kcontrol *kcontrol,
817 int event)
818{
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100819 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
820 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brown3c43c692013-12-12 00:49:22 +0000821 struct arizona *arizona = priv->arizona;
Mark Brownf607e312013-02-22 18:36:53 +0000822 unsigned int mask = 1 << w->shift;
823 unsigned int val;
824
825 switch (event) {
826 case SND_SOC_DAPM_POST_PMU:
827 val = mask;
828 break;
829 case SND_SOC_DAPM_PRE_PMD:
830 val = 0;
831 break;
Charles Keepaxe1ae5fb2015-01-20 16:31:51 +0000832 case SND_SOC_DAPM_PRE_PMU:
Charles Keepax054e1b42015-01-20 16:31:50 +0000833 case SND_SOC_DAPM_POST_PMD:
834 return arizona_out_ev(w, kcontrol, event);
Mark Brownf607e312013-02-22 18:36:53 +0000835 default:
836 return -EINVAL;
837 }
838
839 /* Store the desired state for the HP outputs */
840 priv->arizona->hp_ena &= ~mask;
841 priv->arizona->hp_ena |= val;
842
Charles Keepax112bdfa2015-02-16 15:41:02 +0000843 /* Force off if HPDET clamp is active */
844 if (priv->arizona->hpdet_clamp)
Mark Brownf607e312013-02-22 18:36:53 +0000845 val = 0;
846
Mark Brown3c43c692013-12-12 00:49:22 +0000847 regmap_update_bits_async(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1,
848 mask, val);
Mark Brownf607e312013-02-22 18:36:53 +0000849
850 return arizona_out_ev(w, kcontrol, event);
851}
852EXPORT_SYMBOL_GPL(arizona_hp_ev);
853
Richard Fitzgerald346d9682015-06-02 11:53:33 +0100854static int arizona_dvfs_enable(struct snd_soc_codec *codec)
855{
856 const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
857 struct arizona *arizona = priv->arizona;
858 int ret;
859
860 ret = regulator_set_voltage(arizona->dcvdd, 1800000, 1800000);
861 if (ret) {
862 dev_err(codec->dev, "Failed to boost DCVDD: %d\n", ret);
863 return ret;
864 }
865
866 ret = regmap_update_bits(arizona->regmap,
867 ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
868 ARIZONA_SUBSYS_MAX_FREQ,
869 ARIZONA_SUBSYS_MAX_FREQ);
870 if (ret) {
871 dev_err(codec->dev, "Failed to enable subsys max: %d\n", ret);
872 regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
873 return ret;
874 }
875
876 return 0;
877}
878
879static int arizona_dvfs_disable(struct snd_soc_codec *codec)
880{
881 const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
882 struct arizona *arizona = priv->arizona;
883 int ret;
884
885 ret = regmap_update_bits(arizona->regmap,
886 ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
887 ARIZONA_SUBSYS_MAX_FREQ, 0);
888 if (ret) {
889 dev_err(codec->dev, "Failed to disable subsys max: %d\n", ret);
890 return ret;
891 }
892
893 ret = regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
894 if (ret) {
895 dev_err(codec->dev, "Failed to unboost DCVDD: %d\n", ret);
896 return ret;
897 }
898
899 return 0;
900}
901
902int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags)
903{
904 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
905 int ret = 0;
906
907 mutex_lock(&priv->dvfs_lock);
908
909 if (!priv->dvfs_cached && !priv->dvfs_reqs) {
910 ret = arizona_dvfs_enable(codec);
911 if (ret)
912 goto err;
913 }
914
915 priv->dvfs_reqs |= flags;
916err:
917 mutex_unlock(&priv->dvfs_lock);
918 return ret;
919}
920EXPORT_SYMBOL_GPL(arizona_dvfs_up);
921
922int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags)
923{
924 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
925 unsigned int old_reqs;
926 int ret = 0;
927
928 mutex_lock(&priv->dvfs_lock);
929
930 old_reqs = priv->dvfs_reqs;
931 priv->dvfs_reqs &= ~flags;
932
933 if (!priv->dvfs_cached && old_reqs && !priv->dvfs_reqs)
934 ret = arizona_dvfs_disable(codec);
935
936 mutex_unlock(&priv->dvfs_lock);
937 return ret;
938}
939EXPORT_SYMBOL_GPL(arizona_dvfs_down);
940
941int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
942 struct snd_kcontrol *kcontrol, int event)
943{
944 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
945 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
946 int ret = 0;
947
948 mutex_lock(&priv->dvfs_lock);
949
950 switch (event) {
951 case SND_SOC_DAPM_POST_PMU:
952 if (priv->dvfs_reqs)
953 ret = arizona_dvfs_enable(codec);
954
955 priv->dvfs_cached = false;
956 break;
957 case SND_SOC_DAPM_PRE_PMD:
958 /* We must ensure DVFS is disabled before the codec goes into
959 * suspend so that we are never in an illegal state of DVFS
960 * enabled without enough DCVDD
961 */
962 priv->dvfs_cached = true;
963
964 if (priv->dvfs_reqs)
965 ret = arizona_dvfs_disable(codec);
966 break;
967 default:
968 break;
969 }
970
971 mutex_unlock(&priv->dvfs_lock);
972 return ret;
973}
974EXPORT_SYMBOL_GPL(arizona_dvfs_sysclk_ev);
975
976void arizona_init_dvfs(struct arizona_priv *priv)
977{
978 mutex_init(&priv->dvfs_lock);
979}
980EXPORT_SYMBOL_GPL(arizona_init_dvfs);
981
Mark Browncbd840d2012-08-08 17:52:44 +0100982static unsigned int arizona_sysclk_48k_rates[] = {
983 6144000,
984 12288000,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000985 24576000,
Mark Browncbd840d2012-08-08 17:52:44 +0100986 49152000,
Mark Brownaeaeee12012-09-26 17:50:02 +0100987 73728000,
988 98304000,
989 147456000,
Mark Browncbd840d2012-08-08 17:52:44 +0100990};
991
992static unsigned int arizona_sysclk_44k1_rates[] = {
993 5644800,
994 11289600,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000995 22579200,
Mark Browncbd840d2012-08-08 17:52:44 +0100996 45158400,
Mark Brownaeaeee12012-09-26 17:50:02 +0100997 67737600,
998 90316800,
999 135475200,
Mark Browncbd840d2012-08-08 17:52:44 +01001000};
1001
1002static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
1003 unsigned int freq)
1004{
1005 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1006 unsigned int reg;
1007 unsigned int *rates;
1008 int ref, div, refclk;
1009
1010 switch (clk) {
1011 case ARIZONA_CLK_OPCLK:
1012 reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
1013 refclk = priv->sysclk;
1014 break;
1015 case ARIZONA_CLK_ASYNC_OPCLK:
1016 reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
1017 refclk = priv->asyncclk;
1018 break;
1019 default:
1020 return -EINVAL;
1021 }
1022
1023 if (refclk % 8000)
1024 rates = arizona_sysclk_44k1_rates;
1025 else
1026 rates = arizona_sysclk_48k_rates;
1027
1028 for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) &&
1029 rates[ref] <= refclk; ref++) {
1030 div = 1;
1031 while (rates[ref] / div >= freq && div < 32) {
1032 if (rates[ref] / div == freq) {
1033 dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
1034 freq);
1035 snd_soc_update_bits(codec, reg,
1036 ARIZONA_OPCLK_DIV_MASK |
1037 ARIZONA_OPCLK_SEL_MASK,
1038 (div <<
1039 ARIZONA_OPCLK_DIV_SHIFT) |
1040 ref);
1041 return 0;
1042 }
1043 div++;
1044 }
1045 }
1046
1047 dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
1048 return -EINVAL;
1049}
1050
Mark Brown07ed8732012-06-18 21:08:44 +01001051int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
1052 int source, unsigned int freq, int dir)
1053{
1054 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1055 struct arizona *arizona = priv->arizona;
1056 char *name;
1057 unsigned int reg;
1058 unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
1059 unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
1060 unsigned int *clk;
1061
1062 switch (clk_id) {
1063 case ARIZONA_CLK_SYSCLK:
1064 name = "SYSCLK";
1065 reg = ARIZONA_SYSTEM_CLOCK_1;
1066 clk = &priv->sysclk;
1067 mask |= ARIZONA_SYSCLK_FRAC;
1068 break;
1069 case ARIZONA_CLK_ASYNCCLK:
1070 name = "ASYNCCLK";
1071 reg = ARIZONA_ASYNC_CLOCK_1;
1072 clk = &priv->asyncclk;
1073 break;
Mark Browncbd840d2012-08-08 17:52:44 +01001074 case ARIZONA_CLK_OPCLK:
1075 case ARIZONA_CLK_ASYNC_OPCLK:
1076 return arizona_set_opclk(codec, clk_id, freq);
Mark Brown07ed8732012-06-18 21:08:44 +01001077 default:
1078 return -EINVAL;
1079 }
1080
1081 switch (freq) {
1082 case 5644800:
1083 case 6144000:
1084 break;
1085 case 11289600:
1086 case 12288000:
Mark Brown3f341f72013-03-08 15:22:29 +08001087 val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +01001088 break;
1089 case 22579200:
1090 case 24576000:
Mark Brown3f341f72013-03-08 15:22:29 +08001091 val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +01001092 break;
1093 case 45158400:
1094 case 49152000:
Mark Brown3f341f72013-03-08 15:22:29 +08001095 val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +01001096 break;
Mark Brown38113362012-11-26 16:01:37 +00001097 case 67737600:
1098 case 73728000:
Mark Brown3f341f72013-03-08 15:22:29 +08001099 val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +00001100 break;
1101 case 90316800:
1102 case 98304000:
Mark Brown3f341f72013-03-08 15:22:29 +08001103 val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +00001104 break;
1105 case 135475200:
1106 case 147456000:
Mark Brown3f341f72013-03-08 15:22:29 +08001107 val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +00001108 break;
Mark Brownf2c26d42013-01-21 16:09:36 +09001109 case 0:
1110 dev_dbg(arizona->dev, "%s cleared\n", name);
1111 *clk = freq;
1112 return 0;
Mark Brown07ed8732012-06-18 21:08:44 +01001113 default:
1114 return -EINVAL;
1115 }
1116
1117 *clk = freq;
1118
1119 if (freq % 6144000)
1120 val |= ARIZONA_SYSCLK_FRAC;
1121
1122 dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
1123
1124 return regmap_update_bits(arizona->regmap, reg, mask, val);
1125}
1126EXPORT_SYMBOL_GPL(arizona_set_sysclk);
1127
1128static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
1129{
1130 struct snd_soc_codec *codec = dai->codec;
Mark Brown3c43c692013-12-12 00:49:22 +00001131 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1132 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +01001133 int lrclk, bclk, mode, base;
1134
1135 base = dai->driver->base;
1136
1137 lrclk = 0;
1138 bclk = 0;
1139
1140 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
1141 case SND_SOC_DAIFMT_DSP_A:
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001142 mode = ARIZONA_FMT_DSP_MODE_A;
1143 break;
1144 case SND_SOC_DAIFMT_DSP_B:
1145 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
1146 != SND_SOC_DAIFMT_CBM_CFM) {
1147 arizona_aif_err(dai, "DSP_B not valid in slave mode\n");
1148 return -EINVAL;
1149 }
1150 mode = ARIZONA_FMT_DSP_MODE_B;
Mark Brown07ed8732012-06-18 21:08:44 +01001151 break;
Mark Brown07ed8732012-06-18 21:08:44 +01001152 case SND_SOC_DAIFMT_I2S:
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001153 mode = ARIZONA_FMT_I2S_MODE;
1154 break;
1155 case SND_SOC_DAIFMT_LEFT_J:
1156 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
1157 != SND_SOC_DAIFMT_CBM_CFM) {
1158 arizona_aif_err(dai, "LEFT_J not valid in slave mode\n");
1159 return -EINVAL;
1160 }
1161 mode = ARIZONA_FMT_LEFT_JUSTIFIED_MODE;
Mark Brown07ed8732012-06-18 21:08:44 +01001162 break;
Mark Brown07ed8732012-06-18 21:08:44 +01001163 default:
1164 arizona_aif_err(dai, "Unsupported DAI format %d\n",
1165 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
1166 return -EINVAL;
1167 }
1168
1169 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
1170 case SND_SOC_DAIFMT_CBS_CFS:
1171 break;
1172 case SND_SOC_DAIFMT_CBS_CFM:
1173 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
1174 break;
1175 case SND_SOC_DAIFMT_CBM_CFS:
1176 bclk |= ARIZONA_AIF1_BCLK_MSTR;
1177 break;
1178 case SND_SOC_DAIFMT_CBM_CFM:
1179 bclk |= ARIZONA_AIF1_BCLK_MSTR;
1180 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
1181 break;
1182 default:
1183 arizona_aif_err(dai, "Unsupported master mode %d\n",
1184 fmt & SND_SOC_DAIFMT_MASTER_MASK);
1185 return -EINVAL;
1186 }
1187
1188 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1189 case SND_SOC_DAIFMT_NB_NF:
1190 break;
1191 case SND_SOC_DAIFMT_IB_IF:
1192 bclk |= ARIZONA_AIF1_BCLK_INV;
1193 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
1194 break;
1195 case SND_SOC_DAIFMT_IB_NF:
1196 bclk |= ARIZONA_AIF1_BCLK_INV;
1197 break;
1198 case SND_SOC_DAIFMT_NB_IF:
1199 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
1200 break;
1201 default:
1202 return -EINVAL;
1203 }
1204
Mark Brown3c43c692013-12-12 00:49:22 +00001205 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_BCLK_CTRL,
1206 ARIZONA_AIF1_BCLK_INV |
1207 ARIZONA_AIF1_BCLK_MSTR,
1208 bclk);
1209 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_TX_PIN_CTRL,
1210 ARIZONA_AIF1TX_LRCLK_INV |
1211 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
1212 regmap_update_bits_async(arizona->regmap,
1213 base + ARIZONA_AIF_RX_PIN_CTRL,
1214 ARIZONA_AIF1RX_LRCLK_INV |
1215 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
1216 regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FORMAT,
1217 ARIZONA_AIF1_FMT_MASK, mode);
Mark Brown07ed8732012-06-18 21:08:44 +01001218
1219 return 0;
1220}
1221
Mark Brown949e6bc2012-07-04 18:58:04 +01001222static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001223 -1,
1224 48000,
1225 64000,
1226 96000,
1227 128000,
1228 192000,
1229 256000,
1230 384000,
1231 512000,
1232 768000,
1233 1024000,
1234 1536000,
1235 2048000,
1236 3072000,
1237 4096000,
1238 6144000,
1239 8192000,
1240 12288000,
1241 24576000,
1242};
1243
Mark Brown5b2eec32012-07-04 17:32:05 +01001244static const unsigned int arizona_48k_rates[] = {
1245 12000,
1246 24000,
1247 48000,
1248 96000,
1249 192000,
1250 384000,
1251 768000,
1252 4000,
1253 8000,
1254 16000,
1255 32000,
1256 64000,
1257 128000,
1258 256000,
1259 512000,
1260};
1261
1262static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = {
1263 .count = ARRAY_SIZE(arizona_48k_rates),
1264 .list = arizona_48k_rates,
1265};
1266
Mark Brown949e6bc2012-07-04 18:58:04 +01001267static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001268 -1,
1269 44100,
1270 58800,
1271 88200,
1272 117600,
1273 177640,
1274 235200,
1275 352800,
1276 470400,
1277 705600,
1278 940800,
1279 1411200,
1280 1881600,
Heather Lomond4758be32012-09-05 05:02:10 -04001281 2822400,
Mark Brown07ed8732012-06-18 21:08:44 +01001282 3763200,
1283 5644800,
1284 7526400,
1285 11289600,
1286 22579200,
1287};
1288
Mark Brown5b2eec32012-07-04 17:32:05 +01001289static const unsigned int arizona_44k1_rates[] = {
1290 11025,
1291 22050,
1292 44100,
1293 88200,
1294 176400,
1295 352800,
1296 705600,
1297};
1298
1299static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = {
1300 .count = ARRAY_SIZE(arizona_44k1_rates),
1301 .list = arizona_44k1_rates,
1302};
1303
Mark Brown07ed8732012-06-18 21:08:44 +01001304static int arizona_sr_vals[] = {
1305 0,
1306 12000,
1307 24000,
1308 48000,
1309 96000,
1310 192000,
1311 384000,
1312 768000,
1313 0,
1314 11025,
1315 22050,
1316 44100,
1317 88200,
1318 176400,
1319 352800,
1320 705600,
1321 4000,
1322 8000,
1323 16000,
1324 32000,
1325 64000,
1326 128000,
1327 256000,
1328 512000,
1329};
1330
Mark Brown5b2eec32012-07-04 17:32:05 +01001331static int arizona_startup(struct snd_pcm_substream *substream,
1332 struct snd_soc_dai *dai)
1333{
1334 struct snd_soc_codec *codec = dai->codec;
1335 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1336 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
1337 const struct snd_pcm_hw_constraint_list *constraint;
1338 unsigned int base_rate;
1339
1340 switch (dai_priv->clk) {
1341 case ARIZONA_CLK_SYSCLK:
1342 base_rate = priv->sysclk;
1343 break;
1344 case ARIZONA_CLK_ASYNCCLK:
1345 base_rate = priv->asyncclk;
1346 break;
1347 default:
1348 return 0;
1349 }
1350
Mark Brownf2c26d42013-01-21 16:09:36 +09001351 if (base_rate == 0)
1352 return 0;
1353
Mark Brown5b2eec32012-07-04 17:32:05 +01001354 if (base_rate % 8000)
1355 constraint = &arizona_44k1_constraint;
1356 else
1357 constraint = &arizona_48k_constraint;
1358
1359 return snd_pcm_hw_constraint_list(substream->runtime, 0,
1360 SNDRV_PCM_HW_PARAM_RATE,
1361 constraint);
1362}
1363
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001364static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec,
1365 unsigned int rate)
1366{
1367 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1368 struct arizona *arizona = priv->arizona;
1369 struct reg_default dac_comp[] = {
1370 { 0x80, 0x3 },
1371 { ARIZONA_DAC_COMP_1, 0 },
1372 { ARIZONA_DAC_COMP_2, 0 },
1373 { 0x80, 0x0 },
1374 };
1375
Lars-Peter Clausend74bcaa2014-11-09 17:00:59 +01001376 mutex_lock(&arizona->dac_comp_lock);
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001377
1378 dac_comp[1].def = arizona->dac_comp_coeff;
1379 if (rate >= 176400)
1380 dac_comp[2].def = arizona->dac_comp_enabled;
1381
Lars-Peter Clausend74bcaa2014-11-09 17:00:59 +01001382 mutex_unlock(&arizona->dac_comp_lock);
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001383
1384 regmap_multi_reg_write(arizona->regmap,
1385 dac_comp,
1386 ARRAY_SIZE(dac_comp));
1387}
1388
Mark Brownb272efc2012-10-10 15:10:08 +09001389static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
1390 struct snd_pcm_hw_params *params,
1391 struct snd_soc_dai *dai)
Mark Brown07ed8732012-06-18 21:08:44 +01001392{
1393 struct snd_soc_codec *codec = dai->codec;
Mark Brownc013b272012-07-04 20:05:57 +01001394 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1395 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown07ed8732012-06-18 21:08:44 +01001396 int base = dai->driver->base;
Richard Fitzgerald2c118b42015-06-02 11:53:35 +01001397 int i, sr_val, ret;
Mark Brownb272efc2012-10-10 15:10:08 +09001398
1399 /*
1400 * We will need to be more flexible than this in future,
1401 * currently we use a single sample rate for SYSCLK.
1402 */
1403 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
1404 if (arizona_sr_vals[i] == params_rate(params))
1405 break;
1406 if (i == ARRAY_SIZE(arizona_sr_vals)) {
1407 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1408 params_rate(params));
1409 return -EINVAL;
1410 }
1411 sr_val = i;
1412
Richard Fitzgerald2c118b42015-06-02 11:53:35 +01001413 switch (priv->arizona->type) {
1414 case WM5102:
1415 case WM8997:
1416 if (arizona_sr_vals[sr_val] >= 88200)
1417 ret = arizona_dvfs_up(codec, ARIZONA_DVFS_SR1_RQ);
1418 else
1419 ret = arizona_dvfs_down(codec, ARIZONA_DVFS_SR1_RQ);
1420
1421 if (ret) {
1422 arizona_aif_err(dai, "Failed to change DVFS %d\n", ret);
1423 return ret;
1424 }
1425 break;
1426 default:
1427 break;
1428 }
1429
Mark Brownb272efc2012-10-10 15:10:08 +09001430 switch (dai_priv->clk) {
1431 case ARIZONA_CLK_SYSCLK:
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001432 switch (priv->arizona->type) {
1433 case WM5102:
1434 arizona_wm5102_set_dac_comp(codec,
1435 params_rate(params));
1436 break;
1437 default:
1438 break;
1439 }
1440
Mark Brownb272efc2012-10-10 15:10:08 +09001441 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
1442 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
1443 if (base)
1444 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1445 ARIZONA_AIF1_RATE_MASK, 0);
1446 break;
1447 case ARIZONA_CLK_ASYNCCLK:
1448 snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
Charles Keepaxc24084d2014-09-01 15:48:52 +01001449 ARIZONA_ASYNC_SAMPLE_RATE_1_MASK, sr_val);
Mark Brownb272efc2012-10-10 15:10:08 +09001450 if (base)
1451 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1452 ARIZONA_AIF1_RATE_MASK,
1453 8 << ARIZONA_AIF1_RATE_SHIFT);
1454 break;
1455 default:
1456 arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
1457 return -EINVAL;
1458 }
1459
1460 return 0;
1461}
1462
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001463static bool arizona_aif_cfg_changed(struct snd_soc_codec *codec,
1464 int base, int bclk, int lrclk, int frame)
1465{
1466 int val;
1467
1468 val = snd_soc_read(codec, base + ARIZONA_AIF_BCLK_CTRL);
1469 if (bclk != (val & ARIZONA_AIF1_BCLK_FREQ_MASK))
1470 return true;
1471
1472 val = snd_soc_read(codec, base + ARIZONA_AIF_TX_BCLK_RATE);
1473 if (lrclk != (val & ARIZONA_AIF1TX_BCPF_MASK))
1474 return true;
1475
1476 val = snd_soc_read(codec, base + ARIZONA_AIF_FRAME_CTRL_1);
1477 if (frame != (val & (ARIZONA_AIF1TX_WL_MASK |
1478 ARIZONA_AIF1TX_SLOT_LEN_MASK)))
1479 return true;
1480
1481 return false;
1482}
1483
Mark Brown07ed8732012-06-18 21:08:44 +01001484static int arizona_hw_params(struct snd_pcm_substream *substream,
1485 struct snd_pcm_hw_params *params,
1486 struct snd_soc_dai *dai)
1487{
1488 struct snd_soc_codec *codec = dai->codec;
1489 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brownc94aa302013-01-17 16:35:14 +09001490 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +01001491 int base = dai->driver->base;
1492 const int *rates;
Mark Brown76bf9692013-03-05 14:17:47 +08001493 int i, ret, val;
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001494 int channels = params_channels(params);
Mark Brownc94aa302013-01-17 16:35:14 +09001495 int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001496 int tdm_width = arizona->tdm_width[dai->id - 1];
1497 int tdm_slots = arizona->tdm_slots[dai->id - 1];
Mark Brownc94aa302013-01-17 16:35:14 +09001498 int bclk, lrclk, wl, frame, bclk_target;
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001499 bool reconfig;
1500 unsigned int aif_tx_state, aif_rx_state;
Mark Brown07ed8732012-06-18 21:08:44 +01001501
1502 if (params_rate(params) % 8000)
Mark Brown949e6bc2012-07-04 18:58:04 +01001503 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001504 else
Mark Brown949e6bc2012-07-04 18:58:04 +01001505 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001506
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001507 wl = snd_pcm_format_width(params_format(params));
1508
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001509 if (tdm_slots) {
1510 arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n",
1511 tdm_slots, tdm_width);
1512 bclk_target = tdm_slots * tdm_width * params_rate(params);
1513 channels = tdm_slots;
1514 } else {
1515 bclk_target = snd_soc_params_to_bclk(params);
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001516 tdm_width = wl;
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001517 }
1518
1519 if (chan_limit && chan_limit < channels) {
Mark Brownc94aa302013-01-17 16:35:14 +09001520 arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001521 bclk_target /= channels;
Mark Brownc94aa302013-01-17 16:35:14 +09001522 bclk_target *= chan_limit;
1523 }
1524
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001525 /* Force multiple of 2 channels for I2S mode */
Mark Brown76bf9692013-03-05 14:17:47 +08001526 val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001527 val &= ARIZONA_AIF1_FMT_MASK;
1528 if ((channels & 1) && (val == ARIZONA_FMT_I2S_MODE)) {
Mark Brown76bf9692013-03-05 14:17:47 +08001529 arizona_aif_dbg(dai, "Forcing stereo mode\n");
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001530 bclk_target /= channels;
1531 bclk_target *= channels + 1;
Mark Brown76bf9692013-03-05 14:17:47 +08001532 }
1533
Mark Brown949e6bc2012-07-04 18:58:04 +01001534 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brownc94aa302013-01-17 16:35:14 +09001535 if (rates[i] >= bclk_target &&
Mark Brown50017652012-07-04 19:07:09 +01001536 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +01001537 bclk = i;
1538 break;
1539 }
1540 }
Mark Brown949e6bc2012-07-04 18:58:04 +01001541 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001542 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1543 params_rate(params));
1544 return -EINVAL;
1545 }
1546
Mark Brownb59e0f82013-01-17 14:15:59 +09001547 lrclk = rates[bclk] / params_rate(params);
Mark Brown07ed8732012-06-18 21:08:44 +01001548
1549 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
1550 rates[bclk], rates[bclk] / lrclk);
1551
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001552 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | tdm_width;
Mark Brown07ed8732012-06-18 21:08:44 +01001553
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001554 reconfig = arizona_aif_cfg_changed(codec, base, bclk, lrclk, frame);
1555
1556 if (reconfig) {
1557 /* Save AIF TX/RX state */
1558 aif_tx_state = snd_soc_read(codec,
1559 base + ARIZONA_AIF_TX_ENABLES);
1560 aif_rx_state = snd_soc_read(codec,
1561 base + ARIZONA_AIF_RX_ENABLES);
1562 /* Disable AIF TX/RX before reconfiguring it */
1563 regmap_update_bits_async(arizona->regmap,
1564 base + ARIZONA_AIF_TX_ENABLES, 0xff, 0x0);
1565 regmap_update_bits(arizona->regmap,
1566 base + ARIZONA_AIF_RX_ENABLES, 0xff, 0x0);
1567 }
1568
Mark Brownb272efc2012-10-10 15:10:08 +09001569 ret = arizona_hw_params_rate(substream, params, dai);
1570 if (ret != 0)
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001571 goto restore_aif;
Mark Brownc013b272012-07-04 20:05:57 +01001572
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001573 if (reconfig) {
1574 regmap_update_bits_async(arizona->regmap,
1575 base + ARIZONA_AIF_BCLK_CTRL,
1576 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
1577 regmap_update_bits_async(arizona->regmap,
1578 base + ARIZONA_AIF_TX_BCLK_RATE,
1579 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
1580 regmap_update_bits_async(arizona->regmap,
1581 base + ARIZONA_AIF_RX_BCLK_RATE,
1582 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
1583 regmap_update_bits_async(arizona->regmap,
1584 base + ARIZONA_AIF_FRAME_CTRL_1,
1585 ARIZONA_AIF1TX_WL_MASK |
1586 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
1587 regmap_update_bits(arizona->regmap,
1588 base + ARIZONA_AIF_FRAME_CTRL_2,
1589 ARIZONA_AIF1RX_WL_MASK |
1590 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
1591 }
Mark Brown07ed8732012-06-18 21:08:44 +01001592
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001593restore_aif:
1594 if (reconfig) {
1595 /* Restore AIF TX/RX state */
1596 regmap_update_bits_async(arizona->regmap,
1597 base + ARIZONA_AIF_TX_ENABLES,
1598 0xff, aif_tx_state);
1599 regmap_update_bits(arizona->regmap,
1600 base + ARIZONA_AIF_RX_ENABLES,
1601 0xff, aif_rx_state);
1602 }
1603 return ret;
Mark Brown07ed8732012-06-18 21:08:44 +01001604}
1605
Mark Brown410837a2012-07-05 17:26:59 +01001606static const char *arizona_dai_clk_str(int clk_id)
1607{
1608 switch (clk_id) {
1609 case ARIZONA_CLK_SYSCLK:
1610 return "SYSCLK";
1611 case ARIZONA_CLK_ASYNCCLK:
1612 return "ASYNCCLK";
1613 default:
1614 return "Unknown clock";
1615 }
1616}
1617
Mark Brown5b2eec32012-07-04 17:32:05 +01001618static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
1619 int clk_id, unsigned int freq, int dir)
1620{
1621 struct snd_soc_codec *codec = dai->codec;
1622 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1623 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown410837a2012-07-05 17:26:59 +01001624 struct snd_soc_dapm_route routes[2];
Mark Brown5b2eec32012-07-04 17:32:05 +01001625
1626 switch (clk_id) {
1627 case ARIZONA_CLK_SYSCLK:
1628 case ARIZONA_CLK_ASYNCCLK:
1629 break;
1630 default:
1631 return -EINVAL;
1632 }
1633
Mark Brown410837a2012-07-05 17:26:59 +01001634 if (clk_id == dai_priv->clk)
1635 return 0;
1636
1637 if (dai->active) {
Mark Brown5b2eec32012-07-04 17:32:05 +01001638 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
1639 dai->id);
1640 return -EBUSY;
1641 }
1642
Mark Brownc8d35a62012-12-07 12:49:40 +09001643 dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1,
1644 arizona_dai_clk_str(clk_id));
1645
Mark Brown410837a2012-07-05 17:26:59 +01001646 memset(&routes, 0, sizeof(routes));
1647 routes[0].sink = dai->driver->capture.stream_name;
1648 routes[1].sink = dai->driver->playback.stream_name;
Mark Brown5b2eec32012-07-04 17:32:05 +01001649
Mark Brown410837a2012-07-05 17:26:59 +01001650 routes[0].source = arizona_dai_clk_str(dai_priv->clk);
1651 routes[1].source = arizona_dai_clk_str(dai_priv->clk);
1652 snd_soc_dapm_del_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
1653
1654 routes[0].source = arizona_dai_clk_str(clk_id);
1655 routes[1].source = arizona_dai_clk_str(clk_id);
1656 snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
1657
Mark Brown0c778e82012-12-06 18:22:25 +09001658 dai_priv->clk = clk_id;
1659
Mark Brown410837a2012-07-05 17:26:59 +01001660 return snd_soc_dapm_sync(&codec->dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +01001661}
1662
Mark Brown01df2592012-12-12 16:22:08 +09001663static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
1664{
1665 struct snd_soc_codec *codec = dai->codec;
1666 int base = dai->driver->base;
1667 unsigned int reg;
1668
1669 if (tristate)
1670 reg = ARIZONA_AIF1_TRI;
1671 else
1672 reg = 0;
1673
1674 return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1675 ARIZONA_AIF1_TRI, reg);
1676}
1677
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001678static void arizona_set_channels_to_mask(struct snd_soc_dai *dai,
1679 unsigned int base,
1680 int channels, unsigned int mask)
1681{
1682 struct snd_soc_codec *codec = dai->codec;
1683 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1684 struct arizona *arizona = priv->arizona;
1685 int slot, i;
1686
1687 for (i = 0; i < channels; ++i) {
1688 slot = ffs(mask) - 1;
1689 if (slot < 0)
1690 return;
1691
1692 regmap_write(arizona->regmap, base + i, slot);
1693
1694 mask &= ~(1 << slot);
1695 }
1696
1697 if (mask)
1698 arizona_aif_warn(dai, "Too many channels in TDM mask\n");
1699}
1700
1701static int arizona_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
1702 unsigned int rx_mask, int slots, int slot_width)
1703{
1704 struct snd_soc_codec *codec = dai->codec;
1705 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1706 struct arizona *arizona = priv->arizona;
1707 int base = dai->driver->base;
1708 int rx_max_chan = dai->driver->playback.channels_max;
1709 int tx_max_chan = dai->driver->capture.channels_max;
1710
1711 /* Only support TDM for the physical AIFs */
1712 if (dai->id > ARIZONA_MAX_AIF)
1713 return -ENOTSUPP;
1714
1715 if (slots == 0) {
1716 tx_mask = (1 << tx_max_chan) - 1;
1717 rx_mask = (1 << rx_max_chan) - 1;
1718 }
1719
1720 arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_3,
1721 tx_max_chan, tx_mask);
1722 arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_11,
1723 rx_max_chan, rx_mask);
1724
1725 arizona->tdm_width[dai->id - 1] = slot_width;
1726 arizona->tdm_slots[dai->id - 1] = slots;
1727
1728 return 0;
1729}
1730
Mark Brown07ed8732012-06-18 21:08:44 +01001731const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +01001732 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +01001733 .set_fmt = arizona_set_fmt,
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001734 .set_tdm_slot = arizona_set_tdm_slot,
Mark Brown07ed8732012-06-18 21:08:44 +01001735 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +01001736 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown01df2592012-12-12 16:22:08 +09001737 .set_tristate = arizona_set_tristate,
Mark Brown07ed8732012-06-18 21:08:44 +01001738};
Mark Browna8379872012-07-09 12:16:41 +01001739EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +01001740
Mark Brownbd1dd882013-05-17 13:29:03 +01001741const struct snd_soc_dai_ops arizona_simple_dai_ops = {
1742 .startup = arizona_startup,
1743 .hw_params = arizona_hw_params_rate,
1744 .set_sysclk = arizona_dai_set_sysclk,
1745};
1746EXPORT_SYMBOL_GPL(arizona_simple_dai_ops);
1747
Mark Brown5b2eec32012-07-04 17:32:05 +01001748int arizona_init_dai(struct arizona_priv *priv, int id)
1749{
1750 struct arizona_dai_priv *dai_priv = &priv->dai[id];
1751
1752 dai_priv->clk = ARIZONA_CLK_SYSCLK;
1753
1754 return 0;
1755}
1756EXPORT_SYMBOL_GPL(arizona_init_dai);
1757
Mark Brown07ed8732012-06-18 21:08:44 +01001758static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
1759{
1760 struct arizona_fll *fll = data;
1761
1762 arizona_fll_dbg(fll, "clock OK\n");
1763
1764 complete(&fll->ok);
1765
1766 return IRQ_HANDLED;
1767}
1768
1769static struct {
1770 unsigned int min;
1771 unsigned int max;
1772 u16 fratio;
1773 int ratio;
1774} fll_fratios[] = {
1775 { 0, 64000, 4, 16 },
1776 { 64000, 128000, 3, 8 },
1777 { 128000, 256000, 2, 4 },
1778 { 256000, 1000000, 1, 2 },
1779 { 1000000, 13500000, 0, 1 },
1780};
1781
Mark Brown8f113d72013-03-05 12:08:57 +08001782static struct {
1783 unsigned int min;
1784 unsigned int max;
1785 u16 gain;
1786} fll_gains[] = {
1787 { 0, 256000, 0 },
1788 { 256000, 1000000, 2 },
1789 { 1000000, 13500000, 4 },
1790};
1791
Mark Brown07ed8732012-06-18 21:08:44 +01001792struct arizona_fll_cfg {
1793 int n;
1794 int theta;
1795 int lambda;
1796 int refdiv;
1797 int outdiv;
1798 int fratio;
Mark Brown8f113d72013-03-05 12:08:57 +08001799 int gain;
Mark Brown07ed8732012-06-18 21:08:44 +01001800};
1801
Charles Keepax23f785a82014-03-07 16:34:20 +00001802static int arizona_validate_fll(struct arizona_fll *fll,
1803 unsigned int Fref,
1804 unsigned int Fout)
1805{
1806 unsigned int Fvco_min;
1807
Charles Keepaxc8badda2014-07-09 17:41:49 +01001808 if (fll->fout && Fout != fll->fout) {
1809 arizona_fll_err(fll,
1810 "Can't change output on active FLL\n");
1811 return -EINVAL;
1812 }
1813
Charles Keepax23f785a82014-03-07 16:34:20 +00001814 if (Fref / ARIZONA_FLL_MAX_REFDIV > ARIZONA_FLL_MAX_FREF) {
1815 arizona_fll_err(fll,
1816 "Can't scale %dMHz in to <=13.5MHz\n",
1817 Fref);
1818 return -EINVAL;
1819 }
1820
1821 Fvco_min = ARIZONA_FLL_MIN_FVCO * fll->vco_mult;
1822 if (Fout * ARIZONA_FLL_MAX_OUTDIV < Fvco_min) {
1823 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
1824 Fout);
1825 return -EINVAL;
1826 }
1827
1828 return 0;
1829}
1830
Charles Keepaxd0800342014-03-07 16:34:25 +00001831static int arizona_find_fratio(unsigned int Fref, int *fratio)
1832{
1833 int i;
1834
1835 /* Find an appropriate FLL_FRATIO */
1836 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
1837 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
1838 if (fratio)
1839 *fratio = fll_fratios[i].fratio;
1840 return fll_fratios[i].ratio;
1841 }
1842 }
1843
1844 return -EINVAL;
1845}
1846
1847static int arizona_calc_fratio(struct arizona_fll *fll,
1848 struct arizona_fll_cfg *cfg,
1849 unsigned int target,
1850 unsigned int Fref, bool sync)
1851{
1852 int init_ratio, ratio;
1853 int refdiv, div;
1854
1855 /* Fref must be <=13.5MHz, find initial refdiv */
1856 div = 1;
1857 cfg->refdiv = 0;
1858 while (Fref > ARIZONA_FLL_MAX_FREF) {
1859 div *= 2;
1860 Fref /= 2;
1861 cfg->refdiv++;
1862
1863 if (div > ARIZONA_FLL_MAX_REFDIV)
1864 return -EINVAL;
1865 }
1866
1867 /* Find an appropriate FLL_FRATIO */
1868 init_ratio = arizona_find_fratio(Fref, &cfg->fratio);
1869 if (init_ratio < 0) {
1870 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
1871 Fref);
1872 return init_ratio;
1873 }
1874
1875 switch (fll->arizona->type) {
1876 case WM5110:
Richard Fitzgerald575ef7f2015-01-17 15:21:27 +00001877 case WM8280:
Charles Keepaxd0800342014-03-07 16:34:25 +00001878 if (fll->arizona->rev < 3 || sync)
1879 return init_ratio;
1880 break;
1881 default:
1882 return init_ratio;
1883 }
1884
1885 cfg->fratio = init_ratio - 1;
1886
1887 /* Adjust FRATIO/refdiv to avoid integer mode if possible */
1888 refdiv = cfg->refdiv;
1889
1890 while (div <= ARIZONA_FLL_MAX_REFDIV) {
1891 for (ratio = init_ratio; ratio <= ARIZONA_FLL_MAX_FRATIO;
1892 ratio++) {
Charles Keepax35a730a2014-07-09 17:41:45 +01001893 if ((ARIZONA_FLL_VCO_CORNER / 2) /
1894 (fll->vco_mult * ratio) < Fref)
Charles Keepax29fee822014-07-09 17:41:44 +01001895 break;
1896
Charles Keepaxd0800342014-03-07 16:34:25 +00001897 if (target % (ratio * Fref)) {
1898 cfg->refdiv = refdiv;
1899 cfg->fratio = ratio - 1;
1900 return ratio;
1901 }
1902 }
1903
Charles Keepax4714bc02014-07-09 17:41:43 +01001904 for (ratio = init_ratio - 1; ratio > 0; ratio--) {
Charles Keepaxd0800342014-03-07 16:34:25 +00001905 if (target % (ratio * Fref)) {
1906 cfg->refdiv = refdiv;
1907 cfg->fratio = ratio - 1;
1908 return ratio;
1909 }
1910 }
1911
1912 div *= 2;
1913 Fref /= 2;
1914 refdiv++;
1915 init_ratio = arizona_find_fratio(Fref, NULL);
1916 }
1917
1918 arizona_fll_warn(fll, "Falling back to integer mode operation\n");
1919 return cfg->fratio + 1;
1920}
1921
Mark Brown07ed8732012-06-18 21:08:44 +01001922static int arizona_calc_fll(struct arizona_fll *fll,
1923 struct arizona_fll_cfg *cfg,
Charles Keepaxd0800342014-03-07 16:34:25 +00001924 unsigned int Fref, bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01001925{
1926 unsigned int target, div, gcd_fll;
1927 int i, ratio;
1928
Charles Keepax8ccefcd2014-03-07 16:34:21 +00001929 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, fll->fout);
Mark Brown07ed8732012-06-18 21:08:44 +01001930
Mark Brown2b4d39f2012-07-10 17:03:46 +01001931 /* Fvco should be over the targt; don't check the upper bound */
Charles Keepaxf641aec2014-03-07 16:34:22 +00001932 div = ARIZONA_FLL_MIN_OUTDIV;
1933 while (fll->fout * div < ARIZONA_FLL_MIN_FVCO * fll->vco_mult) {
Mark Brown07ed8732012-06-18 21:08:44 +01001934 div++;
Charles Keepaxf641aec2014-03-07 16:34:22 +00001935 if (div > ARIZONA_FLL_MAX_OUTDIV)
Mark Brown07ed8732012-06-18 21:08:44 +01001936 return -EINVAL;
Mark Brown07ed8732012-06-18 21:08:44 +01001937 }
Charles Keepaxf641aec2014-03-07 16:34:22 +00001938 target = fll->fout * div / fll->vco_mult;
Mark Brown07ed8732012-06-18 21:08:44 +01001939 cfg->outdiv = div;
1940
1941 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
1942
Charles Keepaxd0800342014-03-07 16:34:25 +00001943 /* Find an appropriate FLL_FRATIO and refdiv */
1944 ratio = arizona_calc_fratio(fll, cfg, target, Fref, sync);
1945 if (ratio < 0)
1946 return ratio;
Mark Brown07ed8732012-06-18 21:08:44 +01001947
Mark Brown07ed8732012-06-18 21:08:44 +01001948 /* Apply the division for our remaining calculations */
Charles Keepaxd0800342014-03-07 16:34:25 +00001949 Fref = Fref / (1 << cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08001950
Mark Brown07ed8732012-06-18 21:08:44 +01001951 cfg->n = target / (ratio * Fref);
1952
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001953 if (target % (ratio * Fref)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001954 gcd_fll = gcd(target, ratio * Fref);
1955 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
1956
1957 cfg->theta = (target - (cfg->n * ratio * Fref))
1958 / gcd_fll;
1959 cfg->lambda = (ratio * Fref) / gcd_fll;
1960 } else {
1961 cfg->theta = 0;
1962 cfg->lambda = 0;
1963 }
1964
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001965 /* Round down to 16bit range with cost of accuracy lost.
1966 * Denominator must be bigger than numerator so we only
1967 * take care of it.
1968 */
1969 while (cfg->lambda >= (1 << 16)) {
1970 cfg->theta >>= 1;
1971 cfg->lambda >>= 1;
1972 }
1973
Charles Keepax5a3935c2014-03-07 16:34:23 +00001974 for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
1975 if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
1976 cfg->gain = fll_gains[i].gain;
1977 break;
1978 }
1979 }
1980 if (i == ARRAY_SIZE(fll_gains)) {
1981 arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
1982 Fref);
1983 return -EINVAL;
1984 }
1985
Mark Brown07ed8732012-06-18 21:08:44 +01001986 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
1987 cfg->n, cfg->theta, cfg->lambda);
1988 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
1989 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08001990 arizona_fll_dbg(fll, "GAIN=%d\n", cfg->gain);
Mark Brown07ed8732012-06-18 21:08:44 +01001991
1992 return 0;
1993
1994}
1995
1996static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
Mark Brown8f113d72013-03-05 12:08:57 +08001997 struct arizona_fll_cfg *cfg, int source,
1998 bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01001999{
Mark Brown3c43c692013-12-12 00:49:22 +00002000 regmap_update_bits_async(arizona->regmap, base + 3,
2001 ARIZONA_FLL1_THETA_MASK, cfg->theta);
2002 regmap_update_bits_async(arizona->regmap, base + 4,
2003 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
2004 regmap_update_bits_async(arizona->regmap, base + 5,
2005 ARIZONA_FLL1_FRATIO_MASK,
2006 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
2007 regmap_update_bits_async(arizona->regmap, base + 6,
2008 ARIZONA_FLL1_CLK_REF_DIV_MASK |
2009 ARIZONA_FLL1_CLK_REF_SRC_MASK,
2010 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
2011 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
Mark Brown07ed8732012-06-18 21:08:44 +01002012
Charles Keepax61719db2014-03-07 16:34:19 +00002013 if (sync) {
2014 regmap_update_bits(arizona->regmap, base + 0x7,
2015 ARIZONA_FLL1_GAIN_MASK,
2016 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
2017 } else {
2018 regmap_update_bits(arizona->regmap, base + 0x5,
2019 ARIZONA_FLL1_OUTDIV_MASK,
2020 cfg->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
2021 regmap_update_bits(arizona->regmap, base + 0x9,
2022 ARIZONA_FLL1_GAIN_MASK,
2023 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
2024 }
Mark Brown8f113d72013-03-05 12:08:57 +08002025
Mark Brown3c43c692013-12-12 00:49:22 +00002026 regmap_update_bits_async(arizona->regmap, base + 2,
2027 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
2028 ARIZONA_FLL1_CTRL_UPD | cfg->n);
Mark Brown07ed8732012-06-18 21:08:44 +01002029}
2030
Charles Keepaxc393aca2014-07-09 17:41:47 +01002031static int arizona_is_enabled_fll(struct arizona_fll *fll)
Charles Keepaxd122d6c2013-02-20 17:28:36 +00002032{
2033 struct arizona *arizona = fll->arizona;
2034 unsigned int reg;
2035 int ret;
2036
2037 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
2038 if (ret != 0) {
2039 arizona_fll_err(fll, "Failed to read current state: %d\n",
2040 ret);
2041 return ret;
2042 }
2043
2044 return reg & ARIZONA_FLL1_ENA;
2045}
2046
Charles Keepaxc393aca2014-07-09 17:41:47 +01002047static int arizona_enable_fll(struct arizona_fll *fll)
Charles Keepax35722812013-02-20 17:28:38 +00002048{
2049 struct arizona *arizona = fll->arizona;
Nicholas Mc Guire17f4ad62015-03-08 09:16:49 -04002050 unsigned long time_left;
Charles Keepax49c60542013-09-16 15:34:35 +01002051 bool use_sync = false;
Charles Keepaxc393aca2014-07-09 17:41:47 +01002052 int already_enabled = arizona_is_enabled_fll(fll);
Charles Keepax23f785a82014-03-07 16:34:20 +00002053 struct arizona_fll_cfg cfg;
Charles Keepax35722812013-02-20 17:28:38 +00002054
Charles Keepaxc393aca2014-07-09 17:41:47 +01002055 if (already_enabled < 0)
2056 return already_enabled;
2057
Charles Keepaxc8badda2014-07-09 17:41:49 +01002058 if (already_enabled) {
2059 /* Facilitate smooth refclk across the transition */
2060 regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x7,
2061 ARIZONA_FLL1_GAIN_MASK, 0);
2062 regmap_update_bits_async(fll->arizona->regmap, fll->base + 1,
2063 ARIZONA_FLL1_FREERUN,
2064 ARIZONA_FLL1_FREERUN);
2065 }
2066
Mark Brownff680a12013-03-04 16:00:19 +08002067 /*
2068 * If we have both REFCLK and SYNCCLK then enable both,
2069 * otherwise apply the SYNCCLK settings to REFCLK.
2070 */
Charles Keepax49c60542013-09-16 15:34:35 +01002071 if (fll->ref_src >= 0 && fll->ref_freq &&
2072 fll->ref_src != fll->sync_src) {
Charles Keepaxd0800342014-03-07 16:34:25 +00002073 arizona_calc_fll(fll, &cfg, fll->ref_freq, false);
Charles Keepax35722812013-02-20 17:28:38 +00002074
Charles Keepax23f785a82014-03-07 16:34:20 +00002075 arizona_apply_fll(arizona, fll->base, &cfg, fll->ref_src,
Mark Brown8f113d72013-03-05 12:08:57 +08002076 false);
Charles Keepax49c60542013-09-16 15:34:35 +01002077 if (fll->sync_src >= 0) {
Charles Keepaxd0800342014-03-07 16:34:25 +00002078 arizona_calc_fll(fll, &cfg, fll->sync_freq, true);
Charles Keepax23f785a82014-03-07 16:34:20 +00002079
2080 arizona_apply_fll(arizona, fll->base + 0x10, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08002081 fll->sync_src, true);
Charles Keepax49c60542013-09-16 15:34:35 +01002082 use_sync = true;
2083 }
Mark Brownff680a12013-03-04 16:00:19 +08002084 } else if (fll->sync_src >= 0) {
Charles Keepaxd0800342014-03-07 16:34:25 +00002085 arizona_calc_fll(fll, &cfg, fll->sync_freq, false);
Mark Brownff680a12013-03-04 16:00:19 +08002086
Charles Keepax23f785a82014-03-07 16:34:20 +00002087 arizona_apply_fll(arizona, fll->base, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08002088 fll->sync_src, false);
Mark Browneca2e8e2013-03-06 00:09:59 +08002089
Mark Brown3c43c692013-12-12 00:49:22 +00002090 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
2091 ARIZONA_FLL1_SYNC_ENA, 0);
Mark Brownff680a12013-03-04 16:00:19 +08002092 } else {
2093 arizona_fll_err(fll, "No clocks provided\n");
Charles Keepaxc393aca2014-07-09 17:41:47 +01002094 return -EINVAL;
Mark Brownff680a12013-03-04 16:00:19 +08002095 }
Charles Keepax35722812013-02-20 17:28:38 +00002096
Mark Brown576411be2013-03-05 12:07:16 +08002097 /*
2098 * Increase the bandwidth if we're not using a low frequency
2099 * sync source.
2100 */
Charles Keepax49c60542013-09-16 15:34:35 +01002101 if (use_sync && fll->sync_freq > 100000)
Mark Brown3c43c692013-12-12 00:49:22 +00002102 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
2103 ARIZONA_FLL1_SYNC_BW, 0);
Mark Brown576411be2013-03-05 12:07:16 +08002104 else
Mark Brown3c43c692013-12-12 00:49:22 +00002105 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
2106 ARIZONA_FLL1_SYNC_BW,
2107 ARIZONA_FLL1_SYNC_BW);
Mark Brown576411be2013-03-05 12:07:16 +08002108
Charles Keepaxc393aca2014-07-09 17:41:47 +01002109 if (!already_enabled)
Charles Keepax35722812013-02-20 17:28:38 +00002110 pm_runtime_get(arizona->dev);
2111
2112 /* Clear any pending completions */
2113 try_wait_for_completion(&fll->ok);
2114
Mark Brown3c43c692013-12-12 00:49:22 +00002115 regmap_update_bits_async(arizona->regmap, fll->base + 1,
Mark Brown3c43c692013-12-12 00:49:22 +00002116 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
Charles Keepax49c60542013-09-16 15:34:35 +01002117 if (use_sync)
Mark Brown3c43c692013-12-12 00:49:22 +00002118 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
2119 ARIZONA_FLL1_SYNC_ENA,
2120 ARIZONA_FLL1_SYNC_ENA);
Charles Keepax35722812013-02-20 17:28:38 +00002121
Charles Keepaxc8badda2014-07-09 17:41:49 +01002122 if (already_enabled)
2123 regmap_update_bits_async(arizona->regmap, fll->base + 1,
2124 ARIZONA_FLL1_FREERUN, 0);
2125
Nicholas Mc Guire17f4ad62015-03-08 09:16:49 -04002126 time_left = wait_for_completion_timeout(&fll->ok,
Charles Keepax35722812013-02-20 17:28:38 +00002127 msecs_to_jiffies(250));
Nicholas Mc Guire17f4ad62015-03-08 09:16:49 -04002128 if (time_left == 0)
Charles Keepax35722812013-02-20 17:28:38 +00002129 arizona_fll_warn(fll, "Timed out waiting for lock\n");
Charles Keepaxc393aca2014-07-09 17:41:47 +01002130
2131 return 0;
Charles Keepax35722812013-02-20 17:28:38 +00002132}
2133
Charles Keepax76040542013-02-20 17:28:37 +00002134static void arizona_disable_fll(struct arizona_fll *fll)
2135{
2136 struct arizona *arizona = fll->arizona;
2137 bool change;
2138
Mark Brown3c43c692013-12-12 00:49:22 +00002139 regmap_update_bits_async(arizona->regmap, fll->base + 1,
2140 ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
Charles Keepax76040542013-02-20 17:28:37 +00002141 regmap_update_bits_check(arizona->regmap, fll->base + 1,
2142 ARIZONA_FLL1_ENA, 0, &change);
2143 regmap_update_bits(arizona->regmap, fll->base + 0x11,
2144 ARIZONA_FLL1_SYNC_ENA, 0);
Charles Keepax5e39a502014-07-09 17:41:48 +01002145 regmap_update_bits_async(arizona->regmap, fll->base + 1,
2146 ARIZONA_FLL1_FREERUN, 0);
Charles Keepax76040542013-02-20 17:28:37 +00002147
2148 if (change)
2149 pm_runtime_put_autosuspend(arizona->dev);
2150}
2151
Charles Keepaxee929a92013-02-20 17:28:40 +00002152int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
2153 unsigned int Fref, unsigned int Fout)
2154{
Charles Keepaxc393aca2014-07-09 17:41:47 +01002155 int ret = 0;
Charles Keepaxee929a92013-02-20 17:28:40 +00002156
Charles Keepax1c5617f2013-02-22 17:10:37 +00002157 if (fll->ref_src == source && fll->ref_freq == Fref)
Charles Keepaxee929a92013-02-20 17:28:40 +00002158 return 0;
2159
Charles Keepax23f785a82014-03-07 16:34:20 +00002160 if (fll->fout && Fref > 0) {
2161 ret = arizona_validate_fll(fll, Fref, fll->fout);
2162 if (ret != 0)
2163 return ret;
Charles Keepaxee929a92013-02-20 17:28:40 +00002164 }
2165
2166 fll->ref_src = source;
2167 fll->ref_freq = Fref;
Charles Keepaxee929a92013-02-20 17:28:40 +00002168
Mark Brown86cd6842013-03-07 16:14:04 +08002169 if (fll->fout && Fref > 0) {
Charles Keepaxc393aca2014-07-09 17:41:47 +01002170 ret = arizona_enable_fll(fll);
Charles Keepaxee929a92013-02-20 17:28:40 +00002171 }
2172
Charles Keepaxc393aca2014-07-09 17:41:47 +01002173 return ret;
Charles Keepaxee929a92013-02-20 17:28:40 +00002174}
2175EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
2176
Mark Brown07ed8732012-06-18 21:08:44 +01002177int arizona_set_fll(struct arizona_fll *fll, int source,
2178 unsigned int Fref, unsigned int Fout)
2179{
Charles Keepaxc393aca2014-07-09 17:41:47 +01002180 int ret = 0;
Mark Brown07ed8732012-06-18 21:08:44 +01002181
Mark Brownff680a12013-03-04 16:00:19 +08002182 if (fll->sync_src == source &&
2183 fll->sync_freq == Fref && fll->fout == Fout)
2184 return 0;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00002185
Mark Brownff680a12013-03-04 16:00:19 +08002186 if (Fout) {
2187 if (fll->ref_src >= 0) {
Charles Keepax23f785a82014-03-07 16:34:20 +00002188 ret = arizona_validate_fll(fll, fll->ref_freq, Fout);
Charles Keepax9e359c62013-02-20 17:28:35 +00002189 if (ret != 0)
2190 return ret;
2191 }
2192
Charles Keepax23f785a82014-03-07 16:34:20 +00002193 ret = arizona_validate_fll(fll, Fref, Fout);
Mark Brownff680a12013-03-04 16:00:19 +08002194 if (ret != 0)
2195 return ret;
Charles Keepax9e359c62013-02-20 17:28:35 +00002196 }
Mark Brownff680a12013-03-04 16:00:19 +08002197
2198 fll->sync_src = source;
2199 fll->sync_freq = Fref;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00002200 fll->fout = Fout;
Charles Keepax9e359c62013-02-20 17:28:35 +00002201
Charles Keepax613124c2014-07-09 17:41:46 +01002202 if (Fout)
Charles Keepaxc393aca2014-07-09 17:41:47 +01002203 ret = arizona_enable_fll(fll);
Charles Keepax613124c2014-07-09 17:41:46 +01002204 else
Charles Keepax76040542013-02-20 17:28:37 +00002205 arizona_disable_fll(fll);
Mark Brown07ed8732012-06-18 21:08:44 +01002206
Charles Keepaxc393aca2014-07-09 17:41:47 +01002207 return ret;
Mark Brown07ed8732012-06-18 21:08:44 +01002208}
2209EXPORT_SYMBOL_GPL(arizona_set_fll);
2210
2211int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
2212 int ok_irq, struct arizona_fll *fll)
2213{
2214 int ret;
Charles Keepax19b34bd2013-02-20 17:28:34 +00002215 unsigned int val;
Mark Brown07ed8732012-06-18 21:08:44 +01002216
Mark Brown07ed8732012-06-18 21:08:44 +01002217 init_completion(&fll->ok);
2218
2219 fll->id = id;
2220 fll->base = base;
2221 fll->arizona = arizona;
Charles Keepaxf3f11632013-02-20 17:28:41 +00002222 fll->sync_src = ARIZONA_FLL_SRC_NONE;
Mark Brown07ed8732012-06-18 21:08:44 +01002223
Charles Keepax19b34bd2013-02-20 17:28:34 +00002224 /* Configure default refclk to 32kHz if we have one */
2225 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
2226 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
2227 case ARIZONA_CLK_SRC_MCLK1:
2228 case ARIZONA_CLK_SRC_MCLK2:
2229 fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK;
2230 break;
2231 default:
Charles Keepaxf3f11632013-02-20 17:28:41 +00002232 fll->ref_src = ARIZONA_FLL_SRC_NONE;
Charles Keepax19b34bd2013-02-20 17:28:34 +00002233 }
2234 fll->ref_freq = 32768;
2235
Mark Brown07ed8732012-06-18 21:08:44 +01002236 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
2237 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
2238 "FLL%d clock OK", id);
2239
Mark Brown07ed8732012-06-18 21:08:44 +01002240 ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
2241 arizona_fll_clock_ok, fll);
2242 if (ret != 0) {
2243 dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
2244 id, ret);
2245 }
2246
Charles Keepaxe31c1942013-01-07 16:41:45 +00002247 regmap_update_bits(arizona->regmap, fll->base + 1,
2248 ARIZONA_FLL1_FREERUN, 0);
2249
Mark Brown07ed8732012-06-18 21:08:44 +01002250 return 0;
2251}
2252EXPORT_SYMBOL_GPL(arizona_init_fll);
2253
Mark Brownbc9ab6d2013-01-04 19:31:00 +00002254/**
2255 * arizona_set_output_mode - Set the mode of the specified output
2256 *
2257 * @codec: Device to configure
2258 * @output: Output number
2259 * @diff: True to set the output to differential mode
2260 *
2261 * Some systems use external analogue switches to connect more
2262 * analogue devices to the CODEC than are supported by the device. In
2263 * some systems this requires changing the switched output from single
2264 * ended to differential mode dynamically at runtime, an operation
2265 * supported using this function.
2266 *
2267 * Most systems have a single static configuration and should use
2268 * platform data instead.
2269 */
2270int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
2271{
2272 unsigned int reg, val;
2273
2274 if (output < 1 || output > 6)
2275 return -EINVAL;
2276
2277 reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
2278
2279 if (diff)
2280 val = ARIZONA_OUT1_MONO;
2281 else
2282 val = 0;
2283
2284 return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val);
2285}
2286EXPORT_SYMBOL_GPL(arizona_set_output_mode);
2287
Mark Brown07ed8732012-06-18 21:08:44 +01002288MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
2289MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
2290MODULE_LICENSE("GPL");