blob: eff4b4d512b7b8fbd8bfa31c3c0ee3a79474a478 [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
Mark Browncbd840d2012-08-08 17:52:44 +0100854static unsigned int arizona_sysclk_48k_rates[] = {
855 6144000,
856 12288000,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000857 24576000,
Mark Browncbd840d2012-08-08 17:52:44 +0100858 49152000,
Mark Brownaeaeee12012-09-26 17:50:02 +0100859 73728000,
860 98304000,
861 147456000,
Mark Browncbd840d2012-08-08 17:52:44 +0100862};
863
864static unsigned int arizona_sysclk_44k1_rates[] = {
865 5644800,
866 11289600,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000867 22579200,
Mark Browncbd840d2012-08-08 17:52:44 +0100868 45158400,
Mark Brownaeaeee12012-09-26 17:50:02 +0100869 67737600,
870 90316800,
871 135475200,
Mark Browncbd840d2012-08-08 17:52:44 +0100872};
873
874static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
875 unsigned int freq)
876{
877 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
878 unsigned int reg;
879 unsigned int *rates;
880 int ref, div, refclk;
881
882 switch (clk) {
883 case ARIZONA_CLK_OPCLK:
884 reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
885 refclk = priv->sysclk;
886 break;
887 case ARIZONA_CLK_ASYNC_OPCLK:
888 reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
889 refclk = priv->asyncclk;
890 break;
891 default:
892 return -EINVAL;
893 }
894
895 if (refclk % 8000)
896 rates = arizona_sysclk_44k1_rates;
897 else
898 rates = arizona_sysclk_48k_rates;
899
900 for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) &&
901 rates[ref] <= refclk; ref++) {
902 div = 1;
903 while (rates[ref] / div >= freq && div < 32) {
904 if (rates[ref] / div == freq) {
905 dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
906 freq);
907 snd_soc_update_bits(codec, reg,
908 ARIZONA_OPCLK_DIV_MASK |
909 ARIZONA_OPCLK_SEL_MASK,
910 (div <<
911 ARIZONA_OPCLK_DIV_SHIFT) |
912 ref);
913 return 0;
914 }
915 div++;
916 }
917 }
918
919 dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
920 return -EINVAL;
921}
922
Mark Brown07ed8732012-06-18 21:08:44 +0100923int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
924 int source, unsigned int freq, int dir)
925{
926 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
927 struct arizona *arizona = priv->arizona;
928 char *name;
929 unsigned int reg;
930 unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
931 unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
932 unsigned int *clk;
933
934 switch (clk_id) {
935 case ARIZONA_CLK_SYSCLK:
936 name = "SYSCLK";
937 reg = ARIZONA_SYSTEM_CLOCK_1;
938 clk = &priv->sysclk;
939 mask |= ARIZONA_SYSCLK_FRAC;
940 break;
941 case ARIZONA_CLK_ASYNCCLK:
942 name = "ASYNCCLK";
943 reg = ARIZONA_ASYNC_CLOCK_1;
944 clk = &priv->asyncclk;
945 break;
Mark Browncbd840d2012-08-08 17:52:44 +0100946 case ARIZONA_CLK_OPCLK:
947 case ARIZONA_CLK_ASYNC_OPCLK:
948 return arizona_set_opclk(codec, clk_id, freq);
Mark Brown07ed8732012-06-18 21:08:44 +0100949 default:
950 return -EINVAL;
951 }
952
953 switch (freq) {
954 case 5644800:
955 case 6144000:
956 break;
957 case 11289600:
958 case 12288000:
Mark Brown3f341f72013-03-08 15:22:29 +0800959 val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100960 break;
961 case 22579200:
962 case 24576000:
Mark Brown3f341f72013-03-08 15:22:29 +0800963 val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100964 break;
965 case 45158400:
966 case 49152000:
Mark Brown3f341f72013-03-08 15:22:29 +0800967 val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100968 break;
Mark Brown38113362012-11-26 16:01:37 +0000969 case 67737600:
970 case 73728000:
Mark Brown3f341f72013-03-08 15:22:29 +0800971 val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000972 break;
973 case 90316800:
974 case 98304000:
Mark Brown3f341f72013-03-08 15:22:29 +0800975 val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000976 break;
977 case 135475200:
978 case 147456000:
Mark Brown3f341f72013-03-08 15:22:29 +0800979 val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000980 break;
Mark Brownf2c26d42013-01-21 16:09:36 +0900981 case 0:
982 dev_dbg(arizona->dev, "%s cleared\n", name);
983 *clk = freq;
984 return 0;
Mark Brown07ed8732012-06-18 21:08:44 +0100985 default:
986 return -EINVAL;
987 }
988
989 *clk = freq;
990
991 if (freq % 6144000)
992 val |= ARIZONA_SYSCLK_FRAC;
993
994 dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
995
996 return regmap_update_bits(arizona->regmap, reg, mask, val);
997}
998EXPORT_SYMBOL_GPL(arizona_set_sysclk);
999
1000static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
1001{
1002 struct snd_soc_codec *codec = dai->codec;
Mark Brown3c43c692013-12-12 00:49:22 +00001003 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1004 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +01001005 int lrclk, bclk, mode, base;
1006
1007 base = dai->driver->base;
1008
1009 lrclk = 0;
1010 bclk = 0;
1011
1012 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
1013 case SND_SOC_DAIFMT_DSP_A:
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001014 mode = ARIZONA_FMT_DSP_MODE_A;
1015 break;
1016 case SND_SOC_DAIFMT_DSP_B:
1017 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
1018 != SND_SOC_DAIFMT_CBM_CFM) {
1019 arizona_aif_err(dai, "DSP_B not valid in slave mode\n");
1020 return -EINVAL;
1021 }
1022 mode = ARIZONA_FMT_DSP_MODE_B;
Mark Brown07ed8732012-06-18 21:08:44 +01001023 break;
Mark Brown07ed8732012-06-18 21:08:44 +01001024 case SND_SOC_DAIFMT_I2S:
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001025 mode = ARIZONA_FMT_I2S_MODE;
1026 break;
1027 case SND_SOC_DAIFMT_LEFT_J:
1028 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
1029 != SND_SOC_DAIFMT_CBM_CFM) {
1030 arizona_aif_err(dai, "LEFT_J not valid in slave mode\n");
1031 return -EINVAL;
1032 }
1033 mode = ARIZONA_FMT_LEFT_JUSTIFIED_MODE;
Mark Brown07ed8732012-06-18 21:08:44 +01001034 break;
Mark Brown07ed8732012-06-18 21:08:44 +01001035 default:
1036 arizona_aif_err(dai, "Unsupported DAI format %d\n",
1037 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
1038 return -EINVAL;
1039 }
1040
1041 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
1042 case SND_SOC_DAIFMT_CBS_CFS:
1043 break;
1044 case SND_SOC_DAIFMT_CBS_CFM:
1045 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
1046 break;
1047 case SND_SOC_DAIFMT_CBM_CFS:
1048 bclk |= ARIZONA_AIF1_BCLK_MSTR;
1049 break;
1050 case SND_SOC_DAIFMT_CBM_CFM:
1051 bclk |= ARIZONA_AIF1_BCLK_MSTR;
1052 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
1053 break;
1054 default:
1055 arizona_aif_err(dai, "Unsupported master mode %d\n",
1056 fmt & SND_SOC_DAIFMT_MASTER_MASK);
1057 return -EINVAL;
1058 }
1059
1060 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1061 case SND_SOC_DAIFMT_NB_NF:
1062 break;
1063 case SND_SOC_DAIFMT_IB_IF:
1064 bclk |= ARIZONA_AIF1_BCLK_INV;
1065 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
1066 break;
1067 case SND_SOC_DAIFMT_IB_NF:
1068 bclk |= ARIZONA_AIF1_BCLK_INV;
1069 break;
1070 case SND_SOC_DAIFMT_NB_IF:
1071 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
1072 break;
1073 default:
1074 return -EINVAL;
1075 }
1076
Mark Brown3c43c692013-12-12 00:49:22 +00001077 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_BCLK_CTRL,
1078 ARIZONA_AIF1_BCLK_INV |
1079 ARIZONA_AIF1_BCLK_MSTR,
1080 bclk);
1081 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_TX_PIN_CTRL,
1082 ARIZONA_AIF1TX_LRCLK_INV |
1083 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
1084 regmap_update_bits_async(arizona->regmap,
1085 base + ARIZONA_AIF_RX_PIN_CTRL,
1086 ARIZONA_AIF1RX_LRCLK_INV |
1087 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
1088 regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FORMAT,
1089 ARIZONA_AIF1_FMT_MASK, mode);
Mark Brown07ed8732012-06-18 21:08:44 +01001090
1091 return 0;
1092}
1093
Mark Brown949e6bc2012-07-04 18:58:04 +01001094static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001095 -1,
1096 48000,
1097 64000,
1098 96000,
1099 128000,
1100 192000,
1101 256000,
1102 384000,
1103 512000,
1104 768000,
1105 1024000,
1106 1536000,
1107 2048000,
1108 3072000,
1109 4096000,
1110 6144000,
1111 8192000,
1112 12288000,
1113 24576000,
1114};
1115
Mark Brown5b2eec32012-07-04 17:32:05 +01001116static const unsigned int arizona_48k_rates[] = {
1117 12000,
1118 24000,
1119 48000,
1120 96000,
1121 192000,
1122 384000,
1123 768000,
1124 4000,
1125 8000,
1126 16000,
1127 32000,
1128 64000,
1129 128000,
1130 256000,
1131 512000,
1132};
1133
1134static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = {
1135 .count = ARRAY_SIZE(arizona_48k_rates),
1136 .list = arizona_48k_rates,
1137};
1138
Mark Brown949e6bc2012-07-04 18:58:04 +01001139static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001140 -1,
1141 44100,
1142 58800,
1143 88200,
1144 117600,
1145 177640,
1146 235200,
1147 352800,
1148 470400,
1149 705600,
1150 940800,
1151 1411200,
1152 1881600,
Heather Lomond4758be32012-09-05 05:02:10 -04001153 2822400,
Mark Brown07ed8732012-06-18 21:08:44 +01001154 3763200,
1155 5644800,
1156 7526400,
1157 11289600,
1158 22579200,
1159};
1160
Mark Brown5b2eec32012-07-04 17:32:05 +01001161static const unsigned int arizona_44k1_rates[] = {
1162 11025,
1163 22050,
1164 44100,
1165 88200,
1166 176400,
1167 352800,
1168 705600,
1169};
1170
1171static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = {
1172 .count = ARRAY_SIZE(arizona_44k1_rates),
1173 .list = arizona_44k1_rates,
1174};
1175
Mark Brown07ed8732012-06-18 21:08:44 +01001176static int arizona_sr_vals[] = {
1177 0,
1178 12000,
1179 24000,
1180 48000,
1181 96000,
1182 192000,
1183 384000,
1184 768000,
1185 0,
1186 11025,
1187 22050,
1188 44100,
1189 88200,
1190 176400,
1191 352800,
1192 705600,
1193 4000,
1194 8000,
1195 16000,
1196 32000,
1197 64000,
1198 128000,
1199 256000,
1200 512000,
1201};
1202
Mark Brown5b2eec32012-07-04 17:32:05 +01001203static int arizona_startup(struct snd_pcm_substream *substream,
1204 struct snd_soc_dai *dai)
1205{
1206 struct snd_soc_codec *codec = dai->codec;
1207 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1208 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
1209 const struct snd_pcm_hw_constraint_list *constraint;
1210 unsigned int base_rate;
1211
1212 switch (dai_priv->clk) {
1213 case ARIZONA_CLK_SYSCLK:
1214 base_rate = priv->sysclk;
1215 break;
1216 case ARIZONA_CLK_ASYNCCLK:
1217 base_rate = priv->asyncclk;
1218 break;
1219 default:
1220 return 0;
1221 }
1222
Mark Brownf2c26d42013-01-21 16:09:36 +09001223 if (base_rate == 0)
1224 return 0;
1225
Mark Brown5b2eec32012-07-04 17:32:05 +01001226 if (base_rate % 8000)
1227 constraint = &arizona_44k1_constraint;
1228 else
1229 constraint = &arizona_48k_constraint;
1230
1231 return snd_pcm_hw_constraint_list(substream->runtime, 0,
1232 SNDRV_PCM_HW_PARAM_RATE,
1233 constraint);
1234}
1235
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001236static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec,
1237 unsigned int rate)
1238{
1239 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1240 struct arizona *arizona = priv->arizona;
1241 struct reg_default dac_comp[] = {
1242 { 0x80, 0x3 },
1243 { ARIZONA_DAC_COMP_1, 0 },
1244 { ARIZONA_DAC_COMP_2, 0 },
1245 { 0x80, 0x0 },
1246 };
1247
Lars-Peter Clausend74bcaa2014-11-09 17:00:59 +01001248 mutex_lock(&arizona->dac_comp_lock);
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001249
1250 dac_comp[1].def = arizona->dac_comp_coeff;
1251 if (rate >= 176400)
1252 dac_comp[2].def = arizona->dac_comp_enabled;
1253
Lars-Peter Clausend74bcaa2014-11-09 17:00:59 +01001254 mutex_unlock(&arizona->dac_comp_lock);
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001255
1256 regmap_multi_reg_write(arizona->regmap,
1257 dac_comp,
1258 ARRAY_SIZE(dac_comp));
1259}
1260
Mark Brownb272efc2012-10-10 15:10:08 +09001261static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
1262 struct snd_pcm_hw_params *params,
1263 struct snd_soc_dai *dai)
Mark Brown07ed8732012-06-18 21:08:44 +01001264{
1265 struct snd_soc_codec *codec = dai->codec;
Mark Brownc013b272012-07-04 20:05:57 +01001266 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1267 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown07ed8732012-06-18 21:08:44 +01001268 int base = dai->driver->base;
Mark Brownb272efc2012-10-10 15:10:08 +09001269 int i, sr_val;
1270
1271 /*
1272 * We will need to be more flexible than this in future,
1273 * currently we use a single sample rate for SYSCLK.
1274 */
1275 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
1276 if (arizona_sr_vals[i] == params_rate(params))
1277 break;
1278 if (i == ARRAY_SIZE(arizona_sr_vals)) {
1279 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1280 params_rate(params));
1281 return -EINVAL;
1282 }
1283 sr_val = i;
1284
1285 switch (dai_priv->clk) {
1286 case ARIZONA_CLK_SYSCLK:
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001287 switch (priv->arizona->type) {
1288 case WM5102:
1289 arizona_wm5102_set_dac_comp(codec,
1290 params_rate(params));
1291 break;
1292 default:
1293 break;
1294 }
1295
Mark Brownb272efc2012-10-10 15:10:08 +09001296 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
1297 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
1298 if (base)
1299 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1300 ARIZONA_AIF1_RATE_MASK, 0);
1301 break;
1302 case ARIZONA_CLK_ASYNCCLK:
1303 snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
Charles Keepaxc24084d2014-09-01 15:48:52 +01001304 ARIZONA_ASYNC_SAMPLE_RATE_1_MASK, sr_val);
Mark Brownb272efc2012-10-10 15:10:08 +09001305 if (base)
1306 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1307 ARIZONA_AIF1_RATE_MASK,
1308 8 << ARIZONA_AIF1_RATE_SHIFT);
1309 break;
1310 default:
1311 arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
1312 return -EINVAL;
1313 }
1314
1315 return 0;
1316}
1317
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001318static bool arizona_aif_cfg_changed(struct snd_soc_codec *codec,
1319 int base, int bclk, int lrclk, int frame)
1320{
1321 int val;
1322
1323 val = snd_soc_read(codec, base + ARIZONA_AIF_BCLK_CTRL);
1324 if (bclk != (val & ARIZONA_AIF1_BCLK_FREQ_MASK))
1325 return true;
1326
1327 val = snd_soc_read(codec, base + ARIZONA_AIF_TX_BCLK_RATE);
1328 if (lrclk != (val & ARIZONA_AIF1TX_BCPF_MASK))
1329 return true;
1330
1331 val = snd_soc_read(codec, base + ARIZONA_AIF_FRAME_CTRL_1);
1332 if (frame != (val & (ARIZONA_AIF1TX_WL_MASK |
1333 ARIZONA_AIF1TX_SLOT_LEN_MASK)))
1334 return true;
1335
1336 return false;
1337}
1338
Mark Brown07ed8732012-06-18 21:08:44 +01001339static int arizona_hw_params(struct snd_pcm_substream *substream,
1340 struct snd_pcm_hw_params *params,
1341 struct snd_soc_dai *dai)
1342{
1343 struct snd_soc_codec *codec = dai->codec;
1344 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brownc94aa302013-01-17 16:35:14 +09001345 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +01001346 int base = dai->driver->base;
1347 const int *rates;
Mark Brown76bf9692013-03-05 14:17:47 +08001348 int i, ret, val;
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001349 int channels = params_channels(params);
Mark Brownc94aa302013-01-17 16:35:14 +09001350 int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001351 int tdm_width = arizona->tdm_width[dai->id - 1];
1352 int tdm_slots = arizona->tdm_slots[dai->id - 1];
Mark Brownc94aa302013-01-17 16:35:14 +09001353 int bclk, lrclk, wl, frame, bclk_target;
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001354 bool reconfig;
1355 unsigned int aif_tx_state, aif_rx_state;
Mark Brown07ed8732012-06-18 21:08:44 +01001356
1357 if (params_rate(params) % 8000)
Mark Brown949e6bc2012-07-04 18:58:04 +01001358 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001359 else
Mark Brown949e6bc2012-07-04 18:58:04 +01001360 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001361
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001362 wl = snd_pcm_format_width(params_format(params));
1363
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001364 if (tdm_slots) {
1365 arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n",
1366 tdm_slots, tdm_width);
1367 bclk_target = tdm_slots * tdm_width * params_rate(params);
1368 channels = tdm_slots;
1369 } else {
1370 bclk_target = snd_soc_params_to_bclk(params);
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001371 tdm_width = wl;
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001372 }
1373
1374 if (chan_limit && chan_limit < channels) {
Mark Brownc94aa302013-01-17 16:35:14 +09001375 arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001376 bclk_target /= channels;
Mark Brownc94aa302013-01-17 16:35:14 +09001377 bclk_target *= chan_limit;
1378 }
1379
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001380 /* Force multiple of 2 channels for I2S mode */
Mark Brown76bf9692013-03-05 14:17:47 +08001381 val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001382 val &= ARIZONA_AIF1_FMT_MASK;
1383 if ((channels & 1) && (val == ARIZONA_FMT_I2S_MODE)) {
Mark Brown76bf9692013-03-05 14:17:47 +08001384 arizona_aif_dbg(dai, "Forcing stereo mode\n");
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001385 bclk_target /= channels;
1386 bclk_target *= channels + 1;
Mark Brown76bf9692013-03-05 14:17:47 +08001387 }
1388
Mark Brown949e6bc2012-07-04 18:58:04 +01001389 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brownc94aa302013-01-17 16:35:14 +09001390 if (rates[i] >= bclk_target &&
Mark Brown50017652012-07-04 19:07:09 +01001391 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +01001392 bclk = i;
1393 break;
1394 }
1395 }
Mark Brown949e6bc2012-07-04 18:58:04 +01001396 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001397 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1398 params_rate(params));
1399 return -EINVAL;
1400 }
1401
Mark Brownb59e0f82013-01-17 14:15:59 +09001402 lrclk = rates[bclk] / params_rate(params);
Mark Brown07ed8732012-06-18 21:08:44 +01001403
1404 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
1405 rates[bclk], rates[bclk] / lrclk);
1406
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001407 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | tdm_width;
Mark Brown07ed8732012-06-18 21:08:44 +01001408
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001409 reconfig = arizona_aif_cfg_changed(codec, base, bclk, lrclk, frame);
1410
1411 if (reconfig) {
1412 /* Save AIF TX/RX state */
1413 aif_tx_state = snd_soc_read(codec,
1414 base + ARIZONA_AIF_TX_ENABLES);
1415 aif_rx_state = snd_soc_read(codec,
1416 base + ARIZONA_AIF_RX_ENABLES);
1417 /* Disable AIF TX/RX before reconfiguring it */
1418 regmap_update_bits_async(arizona->regmap,
1419 base + ARIZONA_AIF_TX_ENABLES, 0xff, 0x0);
1420 regmap_update_bits(arizona->regmap,
1421 base + ARIZONA_AIF_RX_ENABLES, 0xff, 0x0);
1422 }
1423
Mark Brownb272efc2012-10-10 15:10:08 +09001424 ret = arizona_hw_params_rate(substream, params, dai);
1425 if (ret != 0)
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001426 goto restore_aif;
Mark Brownc013b272012-07-04 20:05:57 +01001427
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001428 if (reconfig) {
1429 regmap_update_bits_async(arizona->regmap,
1430 base + ARIZONA_AIF_BCLK_CTRL,
1431 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
1432 regmap_update_bits_async(arizona->regmap,
1433 base + ARIZONA_AIF_TX_BCLK_RATE,
1434 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
1435 regmap_update_bits_async(arizona->regmap,
1436 base + ARIZONA_AIF_RX_BCLK_RATE,
1437 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
1438 regmap_update_bits_async(arizona->regmap,
1439 base + ARIZONA_AIF_FRAME_CTRL_1,
1440 ARIZONA_AIF1TX_WL_MASK |
1441 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
1442 regmap_update_bits(arizona->regmap,
1443 base + ARIZONA_AIF_FRAME_CTRL_2,
1444 ARIZONA_AIF1RX_WL_MASK |
1445 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
1446 }
Mark Brown07ed8732012-06-18 21:08:44 +01001447
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001448restore_aif:
1449 if (reconfig) {
1450 /* Restore AIF TX/RX state */
1451 regmap_update_bits_async(arizona->regmap,
1452 base + ARIZONA_AIF_TX_ENABLES,
1453 0xff, aif_tx_state);
1454 regmap_update_bits(arizona->regmap,
1455 base + ARIZONA_AIF_RX_ENABLES,
1456 0xff, aif_rx_state);
1457 }
1458 return ret;
Mark Brown07ed8732012-06-18 21:08:44 +01001459}
1460
Mark Brown410837a2012-07-05 17:26:59 +01001461static const char *arizona_dai_clk_str(int clk_id)
1462{
1463 switch (clk_id) {
1464 case ARIZONA_CLK_SYSCLK:
1465 return "SYSCLK";
1466 case ARIZONA_CLK_ASYNCCLK:
1467 return "ASYNCCLK";
1468 default:
1469 return "Unknown clock";
1470 }
1471}
1472
Mark Brown5b2eec32012-07-04 17:32:05 +01001473static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
1474 int clk_id, unsigned int freq, int dir)
1475{
1476 struct snd_soc_codec *codec = dai->codec;
1477 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1478 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown410837a2012-07-05 17:26:59 +01001479 struct snd_soc_dapm_route routes[2];
Mark Brown5b2eec32012-07-04 17:32:05 +01001480
1481 switch (clk_id) {
1482 case ARIZONA_CLK_SYSCLK:
1483 case ARIZONA_CLK_ASYNCCLK:
1484 break;
1485 default:
1486 return -EINVAL;
1487 }
1488
Mark Brown410837a2012-07-05 17:26:59 +01001489 if (clk_id == dai_priv->clk)
1490 return 0;
1491
1492 if (dai->active) {
Mark Brown5b2eec32012-07-04 17:32:05 +01001493 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
1494 dai->id);
1495 return -EBUSY;
1496 }
1497
Mark Brownc8d35a62012-12-07 12:49:40 +09001498 dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1,
1499 arizona_dai_clk_str(clk_id));
1500
Mark Brown410837a2012-07-05 17:26:59 +01001501 memset(&routes, 0, sizeof(routes));
1502 routes[0].sink = dai->driver->capture.stream_name;
1503 routes[1].sink = dai->driver->playback.stream_name;
Mark Brown5b2eec32012-07-04 17:32:05 +01001504
Mark Brown410837a2012-07-05 17:26:59 +01001505 routes[0].source = arizona_dai_clk_str(dai_priv->clk);
1506 routes[1].source = arizona_dai_clk_str(dai_priv->clk);
1507 snd_soc_dapm_del_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
1508
1509 routes[0].source = arizona_dai_clk_str(clk_id);
1510 routes[1].source = arizona_dai_clk_str(clk_id);
1511 snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
1512
Mark Brown0c778e82012-12-06 18:22:25 +09001513 dai_priv->clk = clk_id;
1514
Mark Brown410837a2012-07-05 17:26:59 +01001515 return snd_soc_dapm_sync(&codec->dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +01001516}
1517
Mark Brown01df2592012-12-12 16:22:08 +09001518static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
1519{
1520 struct snd_soc_codec *codec = dai->codec;
1521 int base = dai->driver->base;
1522 unsigned int reg;
1523
1524 if (tristate)
1525 reg = ARIZONA_AIF1_TRI;
1526 else
1527 reg = 0;
1528
1529 return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1530 ARIZONA_AIF1_TRI, reg);
1531}
1532
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001533static void arizona_set_channels_to_mask(struct snd_soc_dai *dai,
1534 unsigned int base,
1535 int channels, unsigned int mask)
1536{
1537 struct snd_soc_codec *codec = dai->codec;
1538 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1539 struct arizona *arizona = priv->arizona;
1540 int slot, i;
1541
1542 for (i = 0; i < channels; ++i) {
1543 slot = ffs(mask) - 1;
1544 if (slot < 0)
1545 return;
1546
1547 regmap_write(arizona->regmap, base + i, slot);
1548
1549 mask &= ~(1 << slot);
1550 }
1551
1552 if (mask)
1553 arizona_aif_warn(dai, "Too many channels in TDM mask\n");
1554}
1555
1556static int arizona_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
1557 unsigned int rx_mask, int slots, int slot_width)
1558{
1559 struct snd_soc_codec *codec = dai->codec;
1560 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1561 struct arizona *arizona = priv->arizona;
1562 int base = dai->driver->base;
1563 int rx_max_chan = dai->driver->playback.channels_max;
1564 int tx_max_chan = dai->driver->capture.channels_max;
1565
1566 /* Only support TDM for the physical AIFs */
1567 if (dai->id > ARIZONA_MAX_AIF)
1568 return -ENOTSUPP;
1569
1570 if (slots == 0) {
1571 tx_mask = (1 << tx_max_chan) - 1;
1572 rx_mask = (1 << rx_max_chan) - 1;
1573 }
1574
1575 arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_3,
1576 tx_max_chan, tx_mask);
1577 arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_11,
1578 rx_max_chan, rx_mask);
1579
1580 arizona->tdm_width[dai->id - 1] = slot_width;
1581 arizona->tdm_slots[dai->id - 1] = slots;
1582
1583 return 0;
1584}
1585
Mark Brown07ed8732012-06-18 21:08:44 +01001586const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +01001587 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +01001588 .set_fmt = arizona_set_fmt,
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001589 .set_tdm_slot = arizona_set_tdm_slot,
Mark Brown07ed8732012-06-18 21:08:44 +01001590 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +01001591 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown01df2592012-12-12 16:22:08 +09001592 .set_tristate = arizona_set_tristate,
Mark Brown07ed8732012-06-18 21:08:44 +01001593};
Mark Browna8379872012-07-09 12:16:41 +01001594EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +01001595
Mark Brownbd1dd882013-05-17 13:29:03 +01001596const struct snd_soc_dai_ops arizona_simple_dai_ops = {
1597 .startup = arizona_startup,
1598 .hw_params = arizona_hw_params_rate,
1599 .set_sysclk = arizona_dai_set_sysclk,
1600};
1601EXPORT_SYMBOL_GPL(arizona_simple_dai_ops);
1602
Mark Brown5b2eec32012-07-04 17:32:05 +01001603int arizona_init_dai(struct arizona_priv *priv, int id)
1604{
1605 struct arizona_dai_priv *dai_priv = &priv->dai[id];
1606
1607 dai_priv->clk = ARIZONA_CLK_SYSCLK;
1608
1609 return 0;
1610}
1611EXPORT_SYMBOL_GPL(arizona_init_dai);
1612
Mark Brown07ed8732012-06-18 21:08:44 +01001613static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
1614{
1615 struct arizona_fll *fll = data;
1616
1617 arizona_fll_dbg(fll, "clock OK\n");
1618
1619 complete(&fll->ok);
1620
1621 return IRQ_HANDLED;
1622}
1623
1624static struct {
1625 unsigned int min;
1626 unsigned int max;
1627 u16 fratio;
1628 int ratio;
1629} fll_fratios[] = {
1630 { 0, 64000, 4, 16 },
1631 { 64000, 128000, 3, 8 },
1632 { 128000, 256000, 2, 4 },
1633 { 256000, 1000000, 1, 2 },
1634 { 1000000, 13500000, 0, 1 },
1635};
1636
Mark Brown8f113d72013-03-05 12:08:57 +08001637static struct {
1638 unsigned int min;
1639 unsigned int max;
1640 u16 gain;
1641} fll_gains[] = {
1642 { 0, 256000, 0 },
1643 { 256000, 1000000, 2 },
1644 { 1000000, 13500000, 4 },
1645};
1646
Mark Brown07ed8732012-06-18 21:08:44 +01001647struct arizona_fll_cfg {
1648 int n;
1649 int theta;
1650 int lambda;
1651 int refdiv;
1652 int outdiv;
1653 int fratio;
Mark Brown8f113d72013-03-05 12:08:57 +08001654 int gain;
Mark Brown07ed8732012-06-18 21:08:44 +01001655};
1656
Charles Keepax23f785a82014-03-07 16:34:20 +00001657static int arizona_validate_fll(struct arizona_fll *fll,
1658 unsigned int Fref,
1659 unsigned int Fout)
1660{
1661 unsigned int Fvco_min;
1662
Charles Keepaxc8badda2014-07-09 17:41:49 +01001663 if (fll->fout && Fout != fll->fout) {
1664 arizona_fll_err(fll,
1665 "Can't change output on active FLL\n");
1666 return -EINVAL;
1667 }
1668
Charles Keepax23f785a82014-03-07 16:34:20 +00001669 if (Fref / ARIZONA_FLL_MAX_REFDIV > ARIZONA_FLL_MAX_FREF) {
1670 arizona_fll_err(fll,
1671 "Can't scale %dMHz in to <=13.5MHz\n",
1672 Fref);
1673 return -EINVAL;
1674 }
1675
1676 Fvco_min = ARIZONA_FLL_MIN_FVCO * fll->vco_mult;
1677 if (Fout * ARIZONA_FLL_MAX_OUTDIV < Fvco_min) {
1678 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
1679 Fout);
1680 return -EINVAL;
1681 }
1682
1683 return 0;
1684}
1685
Charles Keepaxd0800342014-03-07 16:34:25 +00001686static int arizona_find_fratio(unsigned int Fref, int *fratio)
1687{
1688 int i;
1689
1690 /* Find an appropriate FLL_FRATIO */
1691 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
1692 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
1693 if (fratio)
1694 *fratio = fll_fratios[i].fratio;
1695 return fll_fratios[i].ratio;
1696 }
1697 }
1698
1699 return -EINVAL;
1700}
1701
1702static int arizona_calc_fratio(struct arizona_fll *fll,
1703 struct arizona_fll_cfg *cfg,
1704 unsigned int target,
1705 unsigned int Fref, bool sync)
1706{
1707 int init_ratio, ratio;
1708 int refdiv, div;
1709
1710 /* Fref must be <=13.5MHz, find initial refdiv */
1711 div = 1;
1712 cfg->refdiv = 0;
1713 while (Fref > ARIZONA_FLL_MAX_FREF) {
1714 div *= 2;
1715 Fref /= 2;
1716 cfg->refdiv++;
1717
1718 if (div > ARIZONA_FLL_MAX_REFDIV)
1719 return -EINVAL;
1720 }
1721
1722 /* Find an appropriate FLL_FRATIO */
1723 init_ratio = arizona_find_fratio(Fref, &cfg->fratio);
1724 if (init_ratio < 0) {
1725 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
1726 Fref);
1727 return init_ratio;
1728 }
1729
1730 switch (fll->arizona->type) {
1731 case WM5110:
Richard Fitzgerald575ef7f2015-01-17 15:21:27 +00001732 case WM8280:
Charles Keepaxd0800342014-03-07 16:34:25 +00001733 if (fll->arizona->rev < 3 || sync)
1734 return init_ratio;
1735 break;
1736 default:
1737 return init_ratio;
1738 }
1739
1740 cfg->fratio = init_ratio - 1;
1741
1742 /* Adjust FRATIO/refdiv to avoid integer mode if possible */
1743 refdiv = cfg->refdiv;
1744
1745 while (div <= ARIZONA_FLL_MAX_REFDIV) {
1746 for (ratio = init_ratio; ratio <= ARIZONA_FLL_MAX_FRATIO;
1747 ratio++) {
Charles Keepax35a730a2014-07-09 17:41:45 +01001748 if ((ARIZONA_FLL_VCO_CORNER / 2) /
1749 (fll->vco_mult * ratio) < Fref)
Charles Keepax29fee822014-07-09 17:41:44 +01001750 break;
1751
Charles Keepaxd0800342014-03-07 16:34:25 +00001752 if (target % (ratio * Fref)) {
1753 cfg->refdiv = refdiv;
1754 cfg->fratio = ratio - 1;
1755 return ratio;
1756 }
1757 }
1758
Charles Keepax4714bc02014-07-09 17:41:43 +01001759 for (ratio = init_ratio - 1; ratio > 0; ratio--) {
Charles Keepaxd0800342014-03-07 16:34:25 +00001760 if (target % (ratio * Fref)) {
1761 cfg->refdiv = refdiv;
1762 cfg->fratio = ratio - 1;
1763 return ratio;
1764 }
1765 }
1766
1767 div *= 2;
1768 Fref /= 2;
1769 refdiv++;
1770 init_ratio = arizona_find_fratio(Fref, NULL);
1771 }
1772
1773 arizona_fll_warn(fll, "Falling back to integer mode operation\n");
1774 return cfg->fratio + 1;
1775}
1776
Mark Brown07ed8732012-06-18 21:08:44 +01001777static int arizona_calc_fll(struct arizona_fll *fll,
1778 struct arizona_fll_cfg *cfg,
Charles Keepaxd0800342014-03-07 16:34:25 +00001779 unsigned int Fref, bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01001780{
1781 unsigned int target, div, gcd_fll;
1782 int i, ratio;
1783
Charles Keepax8ccefcd2014-03-07 16:34:21 +00001784 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, fll->fout);
Mark Brown07ed8732012-06-18 21:08:44 +01001785
Mark Brown2b4d39f2012-07-10 17:03:46 +01001786 /* Fvco should be over the targt; don't check the upper bound */
Charles Keepaxf641aec2014-03-07 16:34:22 +00001787 div = ARIZONA_FLL_MIN_OUTDIV;
1788 while (fll->fout * div < ARIZONA_FLL_MIN_FVCO * fll->vco_mult) {
Mark Brown07ed8732012-06-18 21:08:44 +01001789 div++;
Charles Keepaxf641aec2014-03-07 16:34:22 +00001790 if (div > ARIZONA_FLL_MAX_OUTDIV)
Mark Brown07ed8732012-06-18 21:08:44 +01001791 return -EINVAL;
Mark Brown07ed8732012-06-18 21:08:44 +01001792 }
Charles Keepaxf641aec2014-03-07 16:34:22 +00001793 target = fll->fout * div / fll->vco_mult;
Mark Brown07ed8732012-06-18 21:08:44 +01001794 cfg->outdiv = div;
1795
1796 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
1797
Charles Keepaxd0800342014-03-07 16:34:25 +00001798 /* Find an appropriate FLL_FRATIO and refdiv */
1799 ratio = arizona_calc_fratio(fll, cfg, target, Fref, sync);
1800 if (ratio < 0)
1801 return ratio;
Mark Brown07ed8732012-06-18 21:08:44 +01001802
Mark Brown07ed8732012-06-18 21:08:44 +01001803 /* Apply the division for our remaining calculations */
Charles Keepaxd0800342014-03-07 16:34:25 +00001804 Fref = Fref / (1 << cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08001805
Mark Brown07ed8732012-06-18 21:08:44 +01001806 cfg->n = target / (ratio * Fref);
1807
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001808 if (target % (ratio * Fref)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001809 gcd_fll = gcd(target, ratio * Fref);
1810 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
1811
1812 cfg->theta = (target - (cfg->n * ratio * Fref))
1813 / gcd_fll;
1814 cfg->lambda = (ratio * Fref) / gcd_fll;
1815 } else {
1816 cfg->theta = 0;
1817 cfg->lambda = 0;
1818 }
1819
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001820 /* Round down to 16bit range with cost of accuracy lost.
1821 * Denominator must be bigger than numerator so we only
1822 * take care of it.
1823 */
1824 while (cfg->lambda >= (1 << 16)) {
1825 cfg->theta >>= 1;
1826 cfg->lambda >>= 1;
1827 }
1828
Charles Keepax5a3935c2014-03-07 16:34:23 +00001829 for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
1830 if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
1831 cfg->gain = fll_gains[i].gain;
1832 break;
1833 }
1834 }
1835 if (i == ARRAY_SIZE(fll_gains)) {
1836 arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
1837 Fref);
1838 return -EINVAL;
1839 }
1840
Mark Brown07ed8732012-06-18 21:08:44 +01001841 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
1842 cfg->n, cfg->theta, cfg->lambda);
1843 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
1844 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08001845 arizona_fll_dbg(fll, "GAIN=%d\n", cfg->gain);
Mark Brown07ed8732012-06-18 21:08:44 +01001846
1847 return 0;
1848
1849}
1850
1851static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
Mark Brown8f113d72013-03-05 12:08:57 +08001852 struct arizona_fll_cfg *cfg, int source,
1853 bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01001854{
Mark Brown3c43c692013-12-12 00:49:22 +00001855 regmap_update_bits_async(arizona->regmap, base + 3,
1856 ARIZONA_FLL1_THETA_MASK, cfg->theta);
1857 regmap_update_bits_async(arizona->regmap, base + 4,
1858 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
1859 regmap_update_bits_async(arizona->regmap, base + 5,
1860 ARIZONA_FLL1_FRATIO_MASK,
1861 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
1862 regmap_update_bits_async(arizona->regmap, base + 6,
1863 ARIZONA_FLL1_CLK_REF_DIV_MASK |
1864 ARIZONA_FLL1_CLK_REF_SRC_MASK,
1865 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
1866 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
Mark Brown07ed8732012-06-18 21:08:44 +01001867
Charles Keepax61719db2014-03-07 16:34:19 +00001868 if (sync) {
1869 regmap_update_bits(arizona->regmap, base + 0x7,
1870 ARIZONA_FLL1_GAIN_MASK,
1871 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
1872 } else {
1873 regmap_update_bits(arizona->regmap, base + 0x5,
1874 ARIZONA_FLL1_OUTDIV_MASK,
1875 cfg->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
1876 regmap_update_bits(arizona->regmap, base + 0x9,
1877 ARIZONA_FLL1_GAIN_MASK,
1878 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
1879 }
Mark Brown8f113d72013-03-05 12:08:57 +08001880
Mark Brown3c43c692013-12-12 00:49:22 +00001881 regmap_update_bits_async(arizona->regmap, base + 2,
1882 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
1883 ARIZONA_FLL1_CTRL_UPD | cfg->n);
Mark Brown07ed8732012-06-18 21:08:44 +01001884}
1885
Charles Keepaxc393aca2014-07-09 17:41:47 +01001886static int arizona_is_enabled_fll(struct arizona_fll *fll)
Charles Keepaxd122d6c2013-02-20 17:28:36 +00001887{
1888 struct arizona *arizona = fll->arizona;
1889 unsigned int reg;
1890 int ret;
1891
1892 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
1893 if (ret != 0) {
1894 arizona_fll_err(fll, "Failed to read current state: %d\n",
1895 ret);
1896 return ret;
1897 }
1898
1899 return reg & ARIZONA_FLL1_ENA;
1900}
1901
Charles Keepaxc393aca2014-07-09 17:41:47 +01001902static int arizona_enable_fll(struct arizona_fll *fll)
Charles Keepax35722812013-02-20 17:28:38 +00001903{
1904 struct arizona *arizona = fll->arizona;
Nicholas Mc Guire17f4ad62015-03-08 09:16:49 -04001905 unsigned long time_left;
Charles Keepax49c60542013-09-16 15:34:35 +01001906 bool use_sync = false;
Charles Keepaxc393aca2014-07-09 17:41:47 +01001907 int already_enabled = arizona_is_enabled_fll(fll);
Charles Keepax23f785a82014-03-07 16:34:20 +00001908 struct arizona_fll_cfg cfg;
Charles Keepax35722812013-02-20 17:28:38 +00001909
Charles Keepaxc393aca2014-07-09 17:41:47 +01001910 if (already_enabled < 0)
1911 return already_enabled;
1912
Charles Keepaxc8badda2014-07-09 17:41:49 +01001913 if (already_enabled) {
1914 /* Facilitate smooth refclk across the transition */
1915 regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x7,
1916 ARIZONA_FLL1_GAIN_MASK, 0);
1917 regmap_update_bits_async(fll->arizona->regmap, fll->base + 1,
1918 ARIZONA_FLL1_FREERUN,
1919 ARIZONA_FLL1_FREERUN);
1920 }
1921
Mark Brownff680a12013-03-04 16:00:19 +08001922 /*
1923 * If we have both REFCLK and SYNCCLK then enable both,
1924 * otherwise apply the SYNCCLK settings to REFCLK.
1925 */
Charles Keepax49c60542013-09-16 15:34:35 +01001926 if (fll->ref_src >= 0 && fll->ref_freq &&
1927 fll->ref_src != fll->sync_src) {
Charles Keepaxd0800342014-03-07 16:34:25 +00001928 arizona_calc_fll(fll, &cfg, fll->ref_freq, false);
Charles Keepax35722812013-02-20 17:28:38 +00001929
Charles Keepax23f785a82014-03-07 16:34:20 +00001930 arizona_apply_fll(arizona, fll->base, &cfg, fll->ref_src,
Mark Brown8f113d72013-03-05 12:08:57 +08001931 false);
Charles Keepax49c60542013-09-16 15:34:35 +01001932 if (fll->sync_src >= 0) {
Charles Keepaxd0800342014-03-07 16:34:25 +00001933 arizona_calc_fll(fll, &cfg, fll->sync_freq, true);
Charles Keepax23f785a82014-03-07 16:34:20 +00001934
1935 arizona_apply_fll(arizona, fll->base + 0x10, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08001936 fll->sync_src, true);
Charles Keepax49c60542013-09-16 15:34:35 +01001937 use_sync = true;
1938 }
Mark Brownff680a12013-03-04 16:00:19 +08001939 } else if (fll->sync_src >= 0) {
Charles Keepaxd0800342014-03-07 16:34:25 +00001940 arizona_calc_fll(fll, &cfg, fll->sync_freq, false);
Mark Brownff680a12013-03-04 16:00:19 +08001941
Charles Keepax23f785a82014-03-07 16:34:20 +00001942 arizona_apply_fll(arizona, fll->base, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08001943 fll->sync_src, false);
Mark Browneca2e8e2013-03-06 00:09:59 +08001944
Mark Brown3c43c692013-12-12 00:49:22 +00001945 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
1946 ARIZONA_FLL1_SYNC_ENA, 0);
Mark Brownff680a12013-03-04 16:00:19 +08001947 } else {
1948 arizona_fll_err(fll, "No clocks provided\n");
Charles Keepaxc393aca2014-07-09 17:41:47 +01001949 return -EINVAL;
Mark Brownff680a12013-03-04 16:00:19 +08001950 }
Charles Keepax35722812013-02-20 17:28:38 +00001951
Mark Brown576411be2013-03-05 12:07:16 +08001952 /*
1953 * Increase the bandwidth if we're not using a low frequency
1954 * sync source.
1955 */
Charles Keepax49c60542013-09-16 15:34:35 +01001956 if (use_sync && fll->sync_freq > 100000)
Mark Brown3c43c692013-12-12 00:49:22 +00001957 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
1958 ARIZONA_FLL1_SYNC_BW, 0);
Mark Brown576411be2013-03-05 12:07:16 +08001959 else
Mark Brown3c43c692013-12-12 00:49:22 +00001960 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
1961 ARIZONA_FLL1_SYNC_BW,
1962 ARIZONA_FLL1_SYNC_BW);
Mark Brown576411be2013-03-05 12:07:16 +08001963
Charles Keepaxc393aca2014-07-09 17:41:47 +01001964 if (!already_enabled)
Charles Keepax35722812013-02-20 17:28:38 +00001965 pm_runtime_get(arizona->dev);
1966
1967 /* Clear any pending completions */
1968 try_wait_for_completion(&fll->ok);
1969
Mark Brown3c43c692013-12-12 00:49:22 +00001970 regmap_update_bits_async(arizona->regmap, fll->base + 1,
Mark Brown3c43c692013-12-12 00:49:22 +00001971 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
Charles Keepax49c60542013-09-16 15:34:35 +01001972 if (use_sync)
Mark Brown3c43c692013-12-12 00:49:22 +00001973 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
1974 ARIZONA_FLL1_SYNC_ENA,
1975 ARIZONA_FLL1_SYNC_ENA);
Charles Keepax35722812013-02-20 17:28:38 +00001976
Charles Keepaxc8badda2014-07-09 17:41:49 +01001977 if (already_enabled)
1978 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1979 ARIZONA_FLL1_FREERUN, 0);
1980
Nicholas Mc Guire17f4ad62015-03-08 09:16:49 -04001981 time_left = wait_for_completion_timeout(&fll->ok,
Charles Keepax35722812013-02-20 17:28:38 +00001982 msecs_to_jiffies(250));
Nicholas Mc Guire17f4ad62015-03-08 09:16:49 -04001983 if (time_left == 0)
Charles Keepax35722812013-02-20 17:28:38 +00001984 arizona_fll_warn(fll, "Timed out waiting for lock\n");
Charles Keepaxc393aca2014-07-09 17:41:47 +01001985
1986 return 0;
Charles Keepax35722812013-02-20 17:28:38 +00001987}
1988
Charles Keepax76040542013-02-20 17:28:37 +00001989static void arizona_disable_fll(struct arizona_fll *fll)
1990{
1991 struct arizona *arizona = fll->arizona;
1992 bool change;
1993
Mark Brown3c43c692013-12-12 00:49:22 +00001994 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1995 ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
Charles Keepax76040542013-02-20 17:28:37 +00001996 regmap_update_bits_check(arizona->regmap, fll->base + 1,
1997 ARIZONA_FLL1_ENA, 0, &change);
1998 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1999 ARIZONA_FLL1_SYNC_ENA, 0);
Charles Keepax5e39a502014-07-09 17:41:48 +01002000 regmap_update_bits_async(arizona->regmap, fll->base + 1,
2001 ARIZONA_FLL1_FREERUN, 0);
Charles Keepax76040542013-02-20 17:28:37 +00002002
2003 if (change)
2004 pm_runtime_put_autosuspend(arizona->dev);
2005}
2006
Charles Keepaxee929a92013-02-20 17:28:40 +00002007int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
2008 unsigned int Fref, unsigned int Fout)
2009{
Charles Keepaxc393aca2014-07-09 17:41:47 +01002010 int ret = 0;
Charles Keepaxee929a92013-02-20 17:28:40 +00002011
Charles Keepax1c5617f2013-02-22 17:10:37 +00002012 if (fll->ref_src == source && fll->ref_freq == Fref)
Charles Keepaxee929a92013-02-20 17:28:40 +00002013 return 0;
2014
Charles Keepax23f785a82014-03-07 16:34:20 +00002015 if (fll->fout && Fref > 0) {
2016 ret = arizona_validate_fll(fll, Fref, fll->fout);
2017 if (ret != 0)
2018 return ret;
Charles Keepaxee929a92013-02-20 17:28:40 +00002019 }
2020
2021 fll->ref_src = source;
2022 fll->ref_freq = Fref;
Charles Keepaxee929a92013-02-20 17:28:40 +00002023
Mark Brown86cd6842013-03-07 16:14:04 +08002024 if (fll->fout && Fref > 0) {
Charles Keepaxc393aca2014-07-09 17:41:47 +01002025 ret = arizona_enable_fll(fll);
Charles Keepaxee929a92013-02-20 17:28:40 +00002026 }
2027
Charles Keepaxc393aca2014-07-09 17:41:47 +01002028 return ret;
Charles Keepaxee929a92013-02-20 17:28:40 +00002029}
2030EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
2031
Mark Brown07ed8732012-06-18 21:08:44 +01002032int arizona_set_fll(struct arizona_fll *fll, int source,
2033 unsigned int Fref, unsigned int Fout)
2034{
Charles Keepaxc393aca2014-07-09 17:41:47 +01002035 int ret = 0;
Mark Brown07ed8732012-06-18 21:08:44 +01002036
Mark Brownff680a12013-03-04 16:00:19 +08002037 if (fll->sync_src == source &&
2038 fll->sync_freq == Fref && fll->fout == Fout)
2039 return 0;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00002040
Mark Brownff680a12013-03-04 16:00:19 +08002041 if (Fout) {
2042 if (fll->ref_src >= 0) {
Charles Keepax23f785a82014-03-07 16:34:20 +00002043 ret = arizona_validate_fll(fll, fll->ref_freq, Fout);
Charles Keepax9e359c62013-02-20 17:28:35 +00002044 if (ret != 0)
2045 return ret;
2046 }
2047
Charles Keepax23f785a82014-03-07 16:34:20 +00002048 ret = arizona_validate_fll(fll, Fref, Fout);
Mark Brownff680a12013-03-04 16:00:19 +08002049 if (ret != 0)
2050 return ret;
Charles Keepax9e359c62013-02-20 17:28:35 +00002051 }
Mark Brownff680a12013-03-04 16:00:19 +08002052
2053 fll->sync_src = source;
2054 fll->sync_freq = Fref;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00002055 fll->fout = Fout;
Charles Keepax9e359c62013-02-20 17:28:35 +00002056
Charles Keepax613124c2014-07-09 17:41:46 +01002057 if (Fout)
Charles Keepaxc393aca2014-07-09 17:41:47 +01002058 ret = arizona_enable_fll(fll);
Charles Keepax613124c2014-07-09 17:41:46 +01002059 else
Charles Keepax76040542013-02-20 17:28:37 +00002060 arizona_disable_fll(fll);
Mark Brown07ed8732012-06-18 21:08:44 +01002061
Charles Keepaxc393aca2014-07-09 17:41:47 +01002062 return ret;
Mark Brown07ed8732012-06-18 21:08:44 +01002063}
2064EXPORT_SYMBOL_GPL(arizona_set_fll);
2065
2066int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
2067 int ok_irq, struct arizona_fll *fll)
2068{
2069 int ret;
Charles Keepax19b34bd2013-02-20 17:28:34 +00002070 unsigned int val;
Mark Brown07ed8732012-06-18 21:08:44 +01002071
Mark Brown07ed8732012-06-18 21:08:44 +01002072 init_completion(&fll->ok);
2073
2074 fll->id = id;
2075 fll->base = base;
2076 fll->arizona = arizona;
Charles Keepaxf3f11632013-02-20 17:28:41 +00002077 fll->sync_src = ARIZONA_FLL_SRC_NONE;
Mark Brown07ed8732012-06-18 21:08:44 +01002078
Charles Keepax19b34bd2013-02-20 17:28:34 +00002079 /* Configure default refclk to 32kHz if we have one */
2080 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
2081 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
2082 case ARIZONA_CLK_SRC_MCLK1:
2083 case ARIZONA_CLK_SRC_MCLK2:
2084 fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK;
2085 break;
2086 default:
Charles Keepaxf3f11632013-02-20 17:28:41 +00002087 fll->ref_src = ARIZONA_FLL_SRC_NONE;
Charles Keepax19b34bd2013-02-20 17:28:34 +00002088 }
2089 fll->ref_freq = 32768;
2090
Mark Brown07ed8732012-06-18 21:08:44 +01002091 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
2092 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
2093 "FLL%d clock OK", id);
2094
Mark Brown07ed8732012-06-18 21:08:44 +01002095 ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
2096 arizona_fll_clock_ok, fll);
2097 if (ret != 0) {
2098 dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
2099 id, ret);
2100 }
2101
Charles Keepaxe31c1942013-01-07 16:41:45 +00002102 regmap_update_bits(arizona->regmap, fll->base + 1,
2103 ARIZONA_FLL1_FREERUN, 0);
2104
Mark Brown07ed8732012-06-18 21:08:44 +01002105 return 0;
2106}
2107EXPORT_SYMBOL_GPL(arizona_init_fll);
2108
Mark Brownbc9ab6d2013-01-04 19:31:00 +00002109/**
2110 * arizona_set_output_mode - Set the mode of the specified output
2111 *
2112 * @codec: Device to configure
2113 * @output: Output number
2114 * @diff: True to set the output to differential mode
2115 *
2116 * Some systems use external analogue switches to connect more
2117 * analogue devices to the CODEC than are supported by the device. In
2118 * some systems this requires changing the switched output from single
2119 * ended to differential mode dynamically at runtime, an operation
2120 * supported using this function.
2121 *
2122 * Most systems have a single static configuration and should use
2123 * platform data instead.
2124 */
2125int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
2126{
2127 unsigned int reg, val;
2128
2129 if (output < 1 || output > 6)
2130 return -EINVAL;
2131
2132 reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
2133
2134 if (diff)
2135 val = ARIZONA_OUT1_MONO;
2136 else
2137 val = 0;
2138
2139 return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val);
2140}
2141EXPORT_SYMBOL_GPL(arizona_set_output_mode);
2142
Mark Brown07ed8732012-06-18 21:08:44 +01002143MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
2144MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
2145MODULE_LICENSE("GPL");