blob: 65977bc0db194b2442dc946ce83c3f5a16de15f1 [file] [log] [blame]
Mark Brown07ed8732012-06-18 21:08:44 +01001/*
2 * arizona.c - Wolfson Arizona class device shared support
3 *
4 * Copyright 2012 Wolfson Microelectronics plc
5 *
6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
Mark Brownddbce972013-02-15 17:27:22 +000013#include <linux/delay.h>
Mark Brown07ed8732012-06-18 21:08:44 +010014#include <linux/gcd.h>
15#include <linux/module.h>
16#include <linux/pm_runtime.h>
17#include <sound/pcm.h>
18#include <sound/pcm_params.h>
19#include <sound/tlv.h>
20
21#include <linux/mfd/arizona/core.h>
Charles Keepaxb63144e2013-07-04 08:56:28 +010022#include <linux/mfd/arizona/gpio.h>
Mark Brown07ed8732012-06-18 21:08:44 +010023#include <linux/mfd/arizona/registers.h>
24
25#include "arizona.h"
26
27#define ARIZONA_AIF_BCLK_CTRL 0x00
28#define ARIZONA_AIF_TX_PIN_CTRL 0x01
29#define ARIZONA_AIF_RX_PIN_CTRL 0x02
30#define ARIZONA_AIF_RATE_CTRL 0x03
31#define ARIZONA_AIF_FORMAT 0x04
32#define ARIZONA_AIF_TX_BCLK_RATE 0x05
33#define ARIZONA_AIF_RX_BCLK_RATE 0x06
34#define ARIZONA_AIF_FRAME_CTRL_1 0x07
35#define ARIZONA_AIF_FRAME_CTRL_2 0x08
36#define ARIZONA_AIF_FRAME_CTRL_3 0x09
37#define ARIZONA_AIF_FRAME_CTRL_4 0x0A
38#define ARIZONA_AIF_FRAME_CTRL_5 0x0B
39#define ARIZONA_AIF_FRAME_CTRL_6 0x0C
40#define ARIZONA_AIF_FRAME_CTRL_7 0x0D
41#define ARIZONA_AIF_FRAME_CTRL_8 0x0E
42#define ARIZONA_AIF_FRAME_CTRL_9 0x0F
43#define ARIZONA_AIF_FRAME_CTRL_10 0x10
44#define ARIZONA_AIF_FRAME_CTRL_11 0x11
45#define ARIZONA_AIF_FRAME_CTRL_12 0x12
46#define ARIZONA_AIF_FRAME_CTRL_13 0x13
47#define ARIZONA_AIF_FRAME_CTRL_14 0x14
48#define ARIZONA_AIF_FRAME_CTRL_15 0x15
49#define ARIZONA_AIF_FRAME_CTRL_16 0x16
50#define ARIZONA_AIF_FRAME_CTRL_17 0x17
51#define ARIZONA_AIF_FRAME_CTRL_18 0x18
52#define ARIZONA_AIF_TX_ENABLES 0x19
53#define ARIZONA_AIF_RX_ENABLES 0x1A
54#define ARIZONA_AIF_FORCE_WRITE 0x1B
55
Charles Keepaxd0800342014-03-07 16:34:25 +000056#define ARIZONA_FLL_VCO_CORNER 141900000
Charles Keepax87383ac2014-03-07 16:34:18 +000057#define ARIZONA_FLL_MAX_FREF 13500000
58#define ARIZONA_FLL_MIN_FVCO 90000000
Charles Keepaxd0800342014-03-07 16:34:25 +000059#define ARIZONA_FLL_MAX_FRATIO 16
Charles Keepax87383ac2014-03-07 16:34:18 +000060#define ARIZONA_FLL_MAX_REFDIV 8
61#define ARIZONA_FLL_MIN_OUTDIV 2
62#define ARIZONA_FLL_MAX_OUTDIV 7
63
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +000064#define ARIZONA_FMT_DSP_MODE_A 0
65#define ARIZONA_FMT_DSP_MODE_B 1
66#define ARIZONA_FMT_I2S_MODE 2
67#define ARIZONA_FMT_LEFT_JUSTIFIED_MODE 3
68
Mark Brown07ed8732012-06-18 21:08:44 +010069#define arizona_fll_err(_fll, fmt, ...) \
70 dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
71#define arizona_fll_warn(_fll, fmt, ...) \
72 dev_warn(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
73#define arizona_fll_dbg(_fll, fmt, ...) \
Mark Brown9092a6e2013-02-06 17:58:57 +000074 dev_dbg(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
Mark Brown07ed8732012-06-18 21:08:44 +010075
76#define arizona_aif_err(_dai, fmt, ...) \
77 dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
78#define arizona_aif_warn(_dai, fmt, ...) \
79 dev_warn(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
80#define arizona_aif_dbg(_dai, fmt, ...) \
Mark Brown9092a6e2013-02-06 17:58:57 +000081 dev_dbg(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
Mark Brown07ed8732012-06-18 21:08:44 +010082
Mark Brown56447e12013-01-10 14:45:58 +000083static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
84 struct snd_kcontrol *kcontrol,
85 int event)
86{
Lars-Peter Clausen043123f2015-01-13 10:27:07 +010087 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
Mark Brown56447e12013-01-10 14:45:58 +000088 struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
89 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
90 bool manual_ena = false;
Mark Brownf4a76e72013-03-13 12:22:39 +000091 int val;
Mark Brown56447e12013-01-10 14:45:58 +000092
93 switch (arizona->type) {
94 case WM5102:
95 switch (arizona->rev) {
96 case 0:
97 break;
98 default:
99 manual_ena = true;
100 break;
101 }
102 default:
103 break;
104 }
105
106 switch (event) {
107 case SND_SOC_DAPM_PRE_PMU:
108 if (!priv->spk_ena && manual_ena) {
Mark Brown3c43c692013-12-12 00:49:22 +0000109 regmap_write_async(arizona->regmap, 0x4f5, 0x25a);
Mark Brown56447e12013-01-10 14:45:58 +0000110 priv->spk_ena_pending = true;
111 }
112 break;
113 case SND_SOC_DAPM_POST_PMU:
Mark Brownf4a76e72013-03-13 12:22:39 +0000114 val = snd_soc_read(codec, ARIZONA_INTERRUPT_RAW_STATUS_3);
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100115 if (val & ARIZONA_SPK_OVERHEAT_STS) {
Mark Brownf4a76e72013-03-13 12:22:39 +0000116 dev_crit(arizona->dev,
117 "Speaker not enabled due to temperature\n");
118 return -EBUSY;
119 }
120
Mark Brown3c43c692013-12-12 00:49:22 +0000121 regmap_update_bits_async(arizona->regmap,
122 ARIZONA_OUTPUT_ENABLES_1,
123 1 << w->shift, 1 << w->shift);
Mark Brownf4a76e72013-03-13 12:22:39 +0000124
Mark Brown56447e12013-01-10 14:45:58 +0000125 if (priv->spk_ena_pending) {
126 msleep(75);
Mark Brown3c43c692013-12-12 00:49:22 +0000127 regmap_write_async(arizona->regmap, 0x4f5, 0xda);
Mark Brown56447e12013-01-10 14:45:58 +0000128 priv->spk_ena_pending = false;
129 priv->spk_ena++;
130 }
131 break;
132 case SND_SOC_DAPM_PRE_PMD:
133 if (manual_ena) {
134 priv->spk_ena--;
135 if (!priv->spk_ena)
Mark Brown3c43c692013-12-12 00:49:22 +0000136 regmap_write_async(arizona->regmap,
137 0x4f5, 0x25a);
Mark Brown56447e12013-01-10 14:45:58 +0000138 }
Mark Brownf4a76e72013-03-13 12:22:39 +0000139
Mark Brown3c43c692013-12-12 00:49:22 +0000140 regmap_update_bits_async(arizona->regmap,
141 ARIZONA_OUTPUT_ENABLES_1,
142 1 << w->shift, 0);
Mark Brown56447e12013-01-10 14:45:58 +0000143 break;
144 case SND_SOC_DAPM_POST_PMD:
145 if (manual_ena) {
146 if (!priv->spk_ena)
Mark Brown3c43c692013-12-12 00:49:22 +0000147 regmap_write_async(arizona->regmap,
148 0x4f5, 0x0da);
Mark Brown56447e12013-01-10 14:45:58 +0000149 }
150 break;
151 }
152
153 return 0;
154}
155
Mark Brown899817e2013-03-13 12:32:10 +0000156static irqreturn_t arizona_thermal_warn(int irq, void *data)
157{
158 struct arizona *arizona = data;
159 unsigned int val;
160 int ret;
161
162 ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
163 &val);
164 if (ret != 0) {
165 dev_err(arizona->dev, "Failed to read thermal status: %d\n",
166 ret);
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100167 } else if (val & ARIZONA_SPK_OVERHEAT_WARN_STS) {
Mark Brown899817e2013-03-13 12:32:10 +0000168 dev_crit(arizona->dev, "Thermal warning\n");
169 }
170
171 return IRQ_HANDLED;
172}
173
174static irqreturn_t arizona_thermal_shutdown(int irq, void *data)
175{
176 struct arizona *arizona = data;
177 unsigned int val;
178 int ret;
179
180 ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
181 &val);
182 if (ret != 0) {
183 dev_err(arizona->dev, "Failed to read thermal status: %d\n",
184 ret);
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100185 } else if (val & ARIZONA_SPK_OVERHEAT_STS) {
Mark Brown899817e2013-03-13 12:32:10 +0000186 dev_crit(arizona->dev, "Thermal shutdown\n");
Mark Brownf4a76e72013-03-13 12:22:39 +0000187 ret = regmap_update_bits(arizona->regmap,
188 ARIZONA_OUTPUT_ENABLES_1,
189 ARIZONA_OUT4L_ENA |
190 ARIZONA_OUT4R_ENA, 0);
191 if (ret != 0)
192 dev_crit(arizona->dev,
193 "Failed to disable speaker outputs: %d\n",
194 ret);
Mark Brown899817e2013-03-13 12:32:10 +0000195 }
196
197 return IRQ_HANDLED;
198}
199
Mark Brown56447e12013-01-10 14:45:58 +0000200static const struct snd_soc_dapm_widget arizona_spkl =
Mark Brownf4a76e72013-03-13 12:22:39 +0000201 SND_SOC_DAPM_PGA_E("OUT4L", SND_SOC_NOPM,
Mark Brown56447e12013-01-10 14:45:58 +0000202 ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
203 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
204
205static const struct snd_soc_dapm_widget arizona_spkr =
Mark Brownf4a76e72013-03-13 12:22:39 +0000206 SND_SOC_DAPM_PGA_E("OUT4R", SND_SOC_NOPM,
Mark Brown56447e12013-01-10 14:45:58 +0000207 ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
208 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
209
210int arizona_init_spk(struct snd_soc_codec *codec)
211{
Mark Brown899817e2013-03-13 12:32:10 +0000212 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
213 struct arizona *arizona = priv->arizona;
Mark Brown56447e12013-01-10 14:45:58 +0000214 int ret;
215
216 ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkl, 1);
217 if (ret != 0)
218 return ret;
219
Charles Keepax40843ae2013-08-12 23:46:55 +0100220 switch (arizona->type) {
221 case WM8997:
222 break;
223 default:
224 ret = snd_soc_dapm_new_controls(&codec->dapm,
225 &arizona_spkr, 1);
226 if (ret != 0)
227 return ret;
228 break;
229 }
Mark Brown56447e12013-01-10 14:45:58 +0000230
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100231 ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN,
Mark Brown899817e2013-03-13 12:32:10 +0000232 "Thermal warning", arizona_thermal_warn,
233 arizona);
234 if (ret != 0)
235 dev_err(arizona->dev,
236 "Failed to get thermal warning IRQ: %d\n",
237 ret);
238
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100239 ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT,
Mark Brown899817e2013-03-13 12:32:10 +0000240 "Thermal shutdown", arizona_thermal_shutdown,
241 arizona);
242 if (ret != 0)
243 dev_err(arizona->dev,
244 "Failed to get thermal shutdown IRQ: %d\n",
245 ret);
246
Mark Brown56447e12013-01-10 14:45:58 +0000247 return 0;
248}
249EXPORT_SYMBOL_GPL(arizona_init_spk);
250
Charles Keepaxb60f3632014-06-10 18:41:02 +0100251static const struct snd_soc_dapm_route arizona_mono_routes[] = {
252 { "OUT1R", NULL, "OUT1L" },
253 { "OUT2R", NULL, "OUT2L" },
254 { "OUT3R", NULL, "OUT3L" },
255 { "OUT4R", NULL, "OUT4L" },
256 { "OUT5R", NULL, "OUT5L" },
257 { "OUT6R", NULL, "OUT6L" },
258};
259
260int arizona_init_mono(struct snd_soc_codec *codec)
261{
262 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
263 struct arizona *arizona = priv->arizona;
264 int i;
265
266 for (i = 0; i < ARIZONA_MAX_OUTPUT; ++i) {
267 if (arizona->pdata.out_mono[i])
268 snd_soc_dapm_add_routes(&codec->dapm,
269 &arizona_mono_routes[i], 1);
270 }
271
272 return 0;
273}
274EXPORT_SYMBOL_GPL(arizona_init_mono);
275
Charles Keepaxb63144e2013-07-04 08:56:28 +0100276int arizona_init_gpio(struct snd_soc_codec *codec)
277{
278 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
279 struct arizona *arizona = priv->arizona;
280 int i;
281
282 switch (arizona->type) {
283 case WM5110:
284 snd_soc_dapm_disable_pin(&codec->dapm, "DRC2 Signal Activity");
Charles Keepaxb79fae62013-07-04 16:53:03 +0100285 break;
286 default:
287 break;
Charles Keepaxb63144e2013-07-04 08:56:28 +0100288 }
289
290 snd_soc_dapm_disable_pin(&codec->dapm, "DRC1 Signal Activity");
291
292 for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
293 switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) {
294 case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT:
295 snd_soc_dapm_enable_pin(&codec->dapm,
296 "DRC1 Signal Activity");
297 break;
298 case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT:
299 snd_soc_dapm_enable_pin(&codec->dapm,
300 "DRC2 Signal Activity");
301 break;
302 default:
303 break;
304 }
305 }
306
307 return 0;
308}
309EXPORT_SYMBOL_GPL(arizona_init_gpio);
310
Mark Brown07ed8732012-06-18 21:08:44 +0100311const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
312 "None",
313 "Tone Generator 1",
314 "Tone Generator 2",
315 "Haptics",
316 "AEC",
317 "Mic Mute Mixer",
318 "Noise Generator",
319 "IN1L",
320 "IN1R",
321 "IN2L",
322 "IN2R",
323 "IN3L",
324 "IN3R",
Mark Brownc9c56fd2012-07-09 19:09:01 +0100325 "IN4L",
326 "IN4R",
Mark Brown07ed8732012-06-18 21:08:44 +0100327 "AIF1RX1",
328 "AIF1RX2",
329 "AIF1RX3",
330 "AIF1RX4",
331 "AIF1RX5",
332 "AIF1RX6",
333 "AIF1RX7",
334 "AIF1RX8",
335 "AIF2RX1",
336 "AIF2RX2",
Richard Fitzgeralde64001e2013-11-20 13:17:07 +0000337 "AIF2RX3",
338 "AIF2RX4",
339 "AIF2RX5",
340 "AIF2RX6",
Mark Brown07ed8732012-06-18 21:08:44 +0100341 "AIF3RX1",
342 "AIF3RX2",
343 "SLIMRX1",
344 "SLIMRX2",
345 "SLIMRX3",
346 "SLIMRX4",
347 "SLIMRX5",
348 "SLIMRX6",
349 "SLIMRX7",
350 "SLIMRX8",
351 "EQ1",
352 "EQ2",
353 "EQ3",
354 "EQ4",
355 "DRC1L",
356 "DRC1R",
357 "DRC2L",
358 "DRC2R",
359 "LHPF1",
360 "LHPF2",
361 "LHPF3",
362 "LHPF4",
363 "DSP1.1",
364 "DSP1.2",
365 "DSP1.3",
366 "DSP1.4",
367 "DSP1.5",
368 "DSP1.6",
Mark Brownc922cc42012-09-26 16:43:44 +0100369 "DSP2.1",
370 "DSP2.2",
371 "DSP2.3",
372 "DSP2.4",
373 "DSP2.5",
374 "DSP2.6",
375 "DSP3.1",
376 "DSP3.2",
377 "DSP3.3",
378 "DSP3.4",
379 "DSP3.5",
380 "DSP3.6",
381 "DSP4.1",
382 "DSP4.2",
383 "DSP4.3",
384 "DSP4.4",
385 "DSP4.5",
386 "DSP4.6",
Mark Brown07ed8732012-06-18 21:08:44 +0100387 "ASRC1L",
388 "ASRC1R",
389 "ASRC2L",
390 "ASRC2R",
Mark Brown91660bd2012-12-05 20:35:24 +0900391 "ISRC1INT1",
392 "ISRC1INT2",
393 "ISRC1INT3",
394 "ISRC1INT4",
395 "ISRC1DEC1",
396 "ISRC1DEC2",
397 "ISRC1DEC3",
398 "ISRC1DEC4",
399 "ISRC2INT1",
400 "ISRC2INT2",
401 "ISRC2INT3",
402 "ISRC2INT4",
403 "ISRC2DEC1",
404 "ISRC2DEC2",
405 "ISRC2DEC3",
406 "ISRC2DEC4",
407 "ISRC3INT1",
408 "ISRC3INT2",
409 "ISRC3INT3",
410 "ISRC3INT4",
411 "ISRC3DEC1",
412 "ISRC3DEC2",
413 "ISRC3DEC3",
414 "ISRC3DEC4",
Mark Brown07ed8732012-06-18 21:08:44 +0100415};
416EXPORT_SYMBOL_GPL(arizona_mixer_texts);
417
418int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
419 0x00, /* None */
420 0x04, /* Tone */
421 0x05,
422 0x06, /* Haptics */
423 0x08, /* AEC */
424 0x0c, /* Noise mixer */
425 0x0d, /* Comfort noise */
426 0x10, /* IN1L */
427 0x11,
428 0x12,
429 0x13,
430 0x14,
431 0x15,
Mark Brownc9c56fd2012-07-09 19:09:01 +0100432 0x16,
433 0x17,
Mark Brown07ed8732012-06-18 21:08:44 +0100434 0x20, /* AIF1RX1 */
435 0x21,
436 0x22,
437 0x23,
438 0x24,
439 0x25,
440 0x26,
441 0x27,
442 0x28, /* AIF2RX1 */
443 0x29,
Richard Fitzgeralde64001e2013-11-20 13:17:07 +0000444 0x2a,
445 0x2b,
446 0x2c,
447 0x2d,
Mark Brown07ed8732012-06-18 21:08:44 +0100448 0x30, /* AIF3RX1 */
449 0x31,
450 0x38, /* SLIMRX1 */
451 0x39,
452 0x3a,
453 0x3b,
454 0x3c,
455 0x3d,
456 0x3e,
457 0x3f,
458 0x50, /* EQ1 */
459 0x51,
460 0x52,
461 0x53,
462 0x58, /* DRC1L */
463 0x59,
464 0x5a,
465 0x5b,
466 0x60, /* LHPF1 */
467 0x61,
468 0x62,
469 0x63,
470 0x68, /* DSP1.1 */
471 0x69,
472 0x6a,
473 0x6b,
474 0x6c,
475 0x6d,
Mark Brownc922cc42012-09-26 16:43:44 +0100476 0x70, /* DSP2.1 */
477 0x71,
478 0x72,
479 0x73,
480 0x74,
481 0x75,
482 0x78, /* DSP3.1 */
483 0x79,
484 0x7a,
485 0x7b,
486 0x7c,
487 0x7d,
488 0x80, /* DSP4.1 */
489 0x81,
490 0x82,
491 0x83,
492 0x84,
493 0x85,
Mark Brown07ed8732012-06-18 21:08:44 +0100494 0x90, /* ASRC1L */
495 0x91,
496 0x92,
497 0x93,
Mark Brown91660bd2012-12-05 20:35:24 +0900498 0xa0, /* ISRC1INT1 */
499 0xa1,
500 0xa2,
501 0xa3,
502 0xa4, /* ISRC1DEC1 */
503 0xa5,
504 0xa6,
505 0xa7,
506 0xa8, /* ISRC2DEC1 */
507 0xa9,
508 0xaa,
509 0xab,
510 0xac, /* ISRC2INT1 */
511 0xad,
512 0xae,
513 0xaf,
514 0xb0, /* ISRC3DEC1 */
515 0xb1,
516 0xb2,
517 0xb3,
518 0xb4, /* ISRC3INT1 */
519 0xb5,
520 0xb6,
521 0xb7,
Mark Brown07ed8732012-06-18 21:08:44 +0100522};
523EXPORT_SYMBOL_GPL(arizona_mixer_values);
524
525const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
526EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
527
Mark Browndc914282013-02-18 19:09:23 +0000528const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = {
529 "SYNCCLK rate", "8kHz", "16kHz", "ASYNCCLK rate",
530};
531EXPORT_SYMBOL_GPL(arizona_rate_text);
532
533const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
534 0, 1, 2, 8,
535};
536EXPORT_SYMBOL_GPL(arizona_rate_val);
537
538
Charles Keepaxfbedc8c2013-12-19 09:30:12 +0000539const struct soc_enum arizona_isrc_fsh[] = {
540 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_1,
541 ARIZONA_ISRC1_FSH_SHIFT, 0xf,
542 ARIZONA_RATE_ENUM_SIZE,
543 arizona_rate_text, arizona_rate_val),
544 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_1,
545 ARIZONA_ISRC2_FSH_SHIFT, 0xf,
546 ARIZONA_RATE_ENUM_SIZE,
547 arizona_rate_text, arizona_rate_val),
548 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_1,
549 ARIZONA_ISRC3_FSH_SHIFT, 0xf,
550 ARIZONA_RATE_ENUM_SIZE,
551 arizona_rate_text, arizona_rate_val),
552};
553EXPORT_SYMBOL_GPL(arizona_isrc_fsh);
554
Mark Browndc914282013-02-18 19:09:23 +0000555const struct soc_enum arizona_isrc_fsl[] = {
556 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2,
557 ARIZONA_ISRC1_FSL_SHIFT, 0xf,
558 ARIZONA_RATE_ENUM_SIZE,
559 arizona_rate_text, arizona_rate_val),
560 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_2,
561 ARIZONA_ISRC2_FSL_SHIFT, 0xf,
562 ARIZONA_RATE_ENUM_SIZE,
563 arizona_rate_text, arizona_rate_val),
564 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_2,
565 ARIZONA_ISRC3_FSL_SHIFT, 0xf,
566 ARIZONA_RATE_ENUM_SIZE,
567 arizona_rate_text, arizona_rate_val),
568};
569EXPORT_SYMBOL_GPL(arizona_isrc_fsl);
570
Charles Keepax56d37d82013-12-19 09:30:13 +0000571const struct soc_enum arizona_asrc_rate1 =
572 SOC_VALUE_ENUM_SINGLE(ARIZONA_ASRC_RATE1,
573 ARIZONA_ASRC_RATE1_SHIFT, 0xf,
574 ARIZONA_RATE_ENUM_SIZE - 1,
575 arizona_rate_text, arizona_rate_val);
576EXPORT_SYMBOL_GPL(arizona_asrc_rate1);
577
Mark Browne853a002012-12-09 12:25:52 +0900578static const char *arizona_vol_ramp_text[] = {
579 "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
580 "15ms/6dB", "30ms/6dB",
581};
582
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100583SOC_ENUM_SINGLE_DECL(arizona_in_vd_ramp,
584 ARIZONA_INPUT_VOLUME_RAMP,
585 ARIZONA_IN_VD_RAMP_SHIFT,
586 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900587EXPORT_SYMBOL_GPL(arizona_in_vd_ramp);
588
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100589SOC_ENUM_SINGLE_DECL(arizona_in_vi_ramp,
590 ARIZONA_INPUT_VOLUME_RAMP,
591 ARIZONA_IN_VI_RAMP_SHIFT,
592 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900593EXPORT_SYMBOL_GPL(arizona_in_vi_ramp);
594
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100595SOC_ENUM_SINGLE_DECL(arizona_out_vd_ramp,
596 ARIZONA_OUTPUT_VOLUME_RAMP,
597 ARIZONA_OUT_VD_RAMP_SHIFT,
598 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900599EXPORT_SYMBOL_GPL(arizona_out_vd_ramp);
600
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100601SOC_ENUM_SINGLE_DECL(arizona_out_vi_ramp,
602 ARIZONA_OUTPUT_VOLUME_RAMP,
603 ARIZONA_OUT_VI_RAMP_SHIFT,
604 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900605EXPORT_SYMBOL_GPL(arizona_out_vi_ramp);
606
Mark Brown07ed8732012-06-18 21:08:44 +0100607static const char *arizona_lhpf_mode_text[] = {
608 "Low-pass", "High-pass"
609};
610
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100611SOC_ENUM_SINGLE_DECL(arizona_lhpf1_mode,
612 ARIZONA_HPLPF1_1,
613 ARIZONA_LHPF1_MODE_SHIFT,
614 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100615EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
616
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100617SOC_ENUM_SINGLE_DECL(arizona_lhpf2_mode,
618 ARIZONA_HPLPF2_1,
619 ARIZONA_LHPF2_MODE_SHIFT,
620 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100621EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
622
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100623SOC_ENUM_SINGLE_DECL(arizona_lhpf3_mode,
624 ARIZONA_HPLPF3_1,
625 ARIZONA_LHPF3_MODE_SHIFT,
626 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100627EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
628
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100629SOC_ENUM_SINGLE_DECL(arizona_lhpf4_mode,
630 ARIZONA_HPLPF4_1,
631 ARIZONA_LHPF4_MODE_SHIFT,
632 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100633EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
634
Mark Brown845571c2012-12-18 13:47:57 +0000635static const char *arizona_ng_hold_text[] = {
636 "30ms", "120ms", "250ms", "500ms",
637};
638
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100639SOC_ENUM_SINGLE_DECL(arizona_ng_hold,
640 ARIZONA_NOISE_GATE_CONTROL,
641 ARIZONA_NGATE_HOLD_SHIFT,
642 arizona_ng_hold_text);
Mark Brown845571c2012-12-18 13:47:57 +0000643EXPORT_SYMBOL_GPL(arizona_ng_hold);
644
Charles Keepax254dc322013-11-19 16:04:03 +0000645static const char * const arizona_in_hpf_cut_text[] = {
646 "2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz"
647};
648
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100649SOC_ENUM_SINGLE_DECL(arizona_in_hpf_cut_enum,
650 ARIZONA_HPF_CONTROL,
651 ARIZONA_IN_HPF_CUT_SHIFT,
652 arizona_in_hpf_cut_text);
Charles Keepax254dc322013-11-19 16:04:03 +0000653EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum);
654
Charles Keepaxc7f38432013-08-06 17:03:55 +0100655static const char * const arizona_in_dmic_osr_text[] = {
Charles Keepaxef326f42014-11-12 14:55:26 +0000656 "1.536MHz", "3.072MHz", "6.144MHz", "768kHz",
Charles Keepaxc7f38432013-08-06 17:03:55 +0100657};
658
659const struct soc_enum arizona_in_dmic_osr[] = {
660 SOC_ENUM_SINGLE(ARIZONA_IN1L_CONTROL, ARIZONA_IN1_OSR_SHIFT,
661 ARRAY_SIZE(arizona_in_dmic_osr_text),
662 arizona_in_dmic_osr_text),
663 SOC_ENUM_SINGLE(ARIZONA_IN2L_CONTROL, ARIZONA_IN2_OSR_SHIFT,
664 ARRAY_SIZE(arizona_in_dmic_osr_text),
665 arizona_in_dmic_osr_text),
666 SOC_ENUM_SINGLE(ARIZONA_IN3L_CONTROL, ARIZONA_IN3_OSR_SHIFT,
667 ARRAY_SIZE(arizona_in_dmic_osr_text),
668 arizona_in_dmic_osr_text),
669 SOC_ENUM_SINGLE(ARIZONA_IN4L_CONTROL, ARIZONA_IN4_OSR_SHIFT,
670 ARRAY_SIZE(arizona_in_dmic_osr_text),
671 arizona_in_dmic_osr_text),
672};
673EXPORT_SYMBOL_GPL(arizona_in_dmic_osr);
674
Mark Brownddbce972013-02-15 17:27:22 +0000675static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
676{
677 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
678 unsigned int val;
679 int i;
680
681 if (ena)
682 val = ARIZONA_IN_VU;
683 else
684 val = 0;
685
686 for (i = 0; i < priv->num_inputs; i++)
687 snd_soc_update_bits(codec,
688 ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 4),
689 ARIZONA_IN_VU, val);
690}
691
Mark Brown07ed8732012-06-18 21:08:44 +0100692int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
693 int event)
694{
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 Brown1a2c7d52013-03-24 22:50:23 +0000738 switch (event) {
739 case SND_SOC_DAPM_POST_PMU:
740 switch (w->shift) {
741 case ARIZONA_OUT1L_ENA_SHIFT:
742 case ARIZONA_OUT1R_ENA_SHIFT:
743 case ARIZONA_OUT2L_ENA_SHIFT:
744 case ARIZONA_OUT2R_ENA_SHIFT:
745 case ARIZONA_OUT3L_ENA_SHIFT:
746 case ARIZONA_OUT3R_ENA_SHIFT:
747 msleep(17);
748 break;
749
750 default:
751 break;
752 }
753 break;
754 }
755
Mark Brown07ed8732012-06-18 21:08:44 +0100756 return 0;
757}
758EXPORT_SYMBOL_GPL(arizona_out_ev);
759
Mark Brownf607e312013-02-22 18:36:53 +0000760int arizona_hp_ev(struct snd_soc_dapm_widget *w,
761 struct snd_kcontrol *kcontrol,
762 int event)
763{
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100764 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
765 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brown3c43c692013-12-12 00:49:22 +0000766 struct arizona *arizona = priv->arizona;
Mark Brownf607e312013-02-22 18:36:53 +0000767 unsigned int mask = 1 << w->shift;
768 unsigned int val;
769
770 switch (event) {
771 case SND_SOC_DAPM_POST_PMU:
772 val = mask;
773 break;
774 case SND_SOC_DAPM_PRE_PMD:
775 val = 0;
776 break;
777 default:
778 return -EINVAL;
779 }
780
781 /* Store the desired state for the HP outputs */
782 priv->arizona->hp_ena &= ~mask;
783 priv->arizona->hp_ena |= val;
784
785 /* Force off if HPDET magic is active */
786 if (priv->arizona->hpdet_magic)
787 val = 0;
788
Mark Brown3c43c692013-12-12 00:49:22 +0000789 regmap_update_bits_async(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1,
790 mask, val);
Mark Brownf607e312013-02-22 18:36:53 +0000791
792 return arizona_out_ev(w, kcontrol, event);
793}
794EXPORT_SYMBOL_GPL(arizona_hp_ev);
795
Mark Browncbd840d2012-08-08 17:52:44 +0100796static unsigned int arizona_sysclk_48k_rates[] = {
797 6144000,
798 12288000,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000799 24576000,
Mark Browncbd840d2012-08-08 17:52:44 +0100800 49152000,
Mark Brownaeaeee12012-09-26 17:50:02 +0100801 73728000,
802 98304000,
803 147456000,
Mark Browncbd840d2012-08-08 17:52:44 +0100804};
805
806static unsigned int arizona_sysclk_44k1_rates[] = {
807 5644800,
808 11289600,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000809 22579200,
Mark Browncbd840d2012-08-08 17:52:44 +0100810 45158400,
Mark Brownaeaeee12012-09-26 17:50:02 +0100811 67737600,
812 90316800,
813 135475200,
Mark Browncbd840d2012-08-08 17:52:44 +0100814};
815
816static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
817 unsigned int freq)
818{
819 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
820 unsigned int reg;
821 unsigned int *rates;
822 int ref, div, refclk;
823
824 switch (clk) {
825 case ARIZONA_CLK_OPCLK:
826 reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
827 refclk = priv->sysclk;
828 break;
829 case ARIZONA_CLK_ASYNC_OPCLK:
830 reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
831 refclk = priv->asyncclk;
832 break;
833 default:
834 return -EINVAL;
835 }
836
837 if (refclk % 8000)
838 rates = arizona_sysclk_44k1_rates;
839 else
840 rates = arizona_sysclk_48k_rates;
841
842 for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) &&
843 rates[ref] <= refclk; ref++) {
844 div = 1;
845 while (rates[ref] / div >= freq && div < 32) {
846 if (rates[ref] / div == freq) {
847 dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
848 freq);
849 snd_soc_update_bits(codec, reg,
850 ARIZONA_OPCLK_DIV_MASK |
851 ARIZONA_OPCLK_SEL_MASK,
852 (div <<
853 ARIZONA_OPCLK_DIV_SHIFT) |
854 ref);
855 return 0;
856 }
857 div++;
858 }
859 }
860
861 dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
862 return -EINVAL;
863}
864
Mark Brown07ed8732012-06-18 21:08:44 +0100865int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
866 int source, unsigned int freq, int dir)
867{
868 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
869 struct arizona *arizona = priv->arizona;
870 char *name;
871 unsigned int reg;
872 unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
873 unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
874 unsigned int *clk;
875
876 switch (clk_id) {
877 case ARIZONA_CLK_SYSCLK:
878 name = "SYSCLK";
879 reg = ARIZONA_SYSTEM_CLOCK_1;
880 clk = &priv->sysclk;
881 mask |= ARIZONA_SYSCLK_FRAC;
882 break;
883 case ARIZONA_CLK_ASYNCCLK:
884 name = "ASYNCCLK";
885 reg = ARIZONA_ASYNC_CLOCK_1;
886 clk = &priv->asyncclk;
887 break;
Mark Browncbd840d2012-08-08 17:52:44 +0100888 case ARIZONA_CLK_OPCLK:
889 case ARIZONA_CLK_ASYNC_OPCLK:
890 return arizona_set_opclk(codec, clk_id, freq);
Mark Brown07ed8732012-06-18 21:08:44 +0100891 default:
892 return -EINVAL;
893 }
894
895 switch (freq) {
896 case 5644800:
897 case 6144000:
898 break;
899 case 11289600:
900 case 12288000:
Mark Brown3f341f72013-03-08 15:22:29 +0800901 val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100902 break;
903 case 22579200:
904 case 24576000:
Mark Brown3f341f72013-03-08 15:22:29 +0800905 val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100906 break;
907 case 45158400:
908 case 49152000:
Mark Brown3f341f72013-03-08 15:22:29 +0800909 val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100910 break;
Mark Brown38113362012-11-26 16:01:37 +0000911 case 67737600:
912 case 73728000:
Mark Brown3f341f72013-03-08 15:22:29 +0800913 val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000914 break;
915 case 90316800:
916 case 98304000:
Mark Brown3f341f72013-03-08 15:22:29 +0800917 val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000918 break;
919 case 135475200:
920 case 147456000:
Mark Brown3f341f72013-03-08 15:22:29 +0800921 val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000922 break;
Mark Brownf2c26d42013-01-21 16:09:36 +0900923 case 0:
924 dev_dbg(arizona->dev, "%s cleared\n", name);
925 *clk = freq;
926 return 0;
Mark Brown07ed8732012-06-18 21:08:44 +0100927 default:
928 return -EINVAL;
929 }
930
931 *clk = freq;
932
933 if (freq % 6144000)
934 val |= ARIZONA_SYSCLK_FRAC;
935
936 dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
937
938 return regmap_update_bits(arizona->regmap, reg, mask, val);
939}
940EXPORT_SYMBOL_GPL(arizona_set_sysclk);
941
942static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
943{
944 struct snd_soc_codec *codec = dai->codec;
Mark Brown3c43c692013-12-12 00:49:22 +0000945 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
946 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +0100947 int lrclk, bclk, mode, base;
948
949 base = dai->driver->base;
950
951 lrclk = 0;
952 bclk = 0;
953
954 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
955 case SND_SOC_DAIFMT_DSP_A:
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +0000956 mode = ARIZONA_FMT_DSP_MODE_A;
957 break;
958 case SND_SOC_DAIFMT_DSP_B:
959 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
960 != SND_SOC_DAIFMT_CBM_CFM) {
961 arizona_aif_err(dai, "DSP_B not valid in slave mode\n");
962 return -EINVAL;
963 }
964 mode = ARIZONA_FMT_DSP_MODE_B;
Mark Brown07ed8732012-06-18 21:08:44 +0100965 break;
Mark Brown07ed8732012-06-18 21:08:44 +0100966 case SND_SOC_DAIFMT_I2S:
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +0000967 mode = ARIZONA_FMT_I2S_MODE;
968 break;
969 case SND_SOC_DAIFMT_LEFT_J:
970 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
971 != SND_SOC_DAIFMT_CBM_CFM) {
972 arizona_aif_err(dai, "LEFT_J not valid in slave mode\n");
973 return -EINVAL;
974 }
975 mode = ARIZONA_FMT_LEFT_JUSTIFIED_MODE;
Mark Brown07ed8732012-06-18 21:08:44 +0100976 break;
Mark Brown07ed8732012-06-18 21:08:44 +0100977 default:
978 arizona_aif_err(dai, "Unsupported DAI format %d\n",
979 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
980 return -EINVAL;
981 }
982
983 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
984 case SND_SOC_DAIFMT_CBS_CFS:
985 break;
986 case SND_SOC_DAIFMT_CBS_CFM:
987 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
988 break;
989 case SND_SOC_DAIFMT_CBM_CFS:
990 bclk |= ARIZONA_AIF1_BCLK_MSTR;
991 break;
992 case SND_SOC_DAIFMT_CBM_CFM:
993 bclk |= ARIZONA_AIF1_BCLK_MSTR;
994 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
995 break;
996 default:
997 arizona_aif_err(dai, "Unsupported master mode %d\n",
998 fmt & SND_SOC_DAIFMT_MASTER_MASK);
999 return -EINVAL;
1000 }
1001
1002 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1003 case SND_SOC_DAIFMT_NB_NF:
1004 break;
1005 case SND_SOC_DAIFMT_IB_IF:
1006 bclk |= ARIZONA_AIF1_BCLK_INV;
1007 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
1008 break;
1009 case SND_SOC_DAIFMT_IB_NF:
1010 bclk |= ARIZONA_AIF1_BCLK_INV;
1011 break;
1012 case SND_SOC_DAIFMT_NB_IF:
1013 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
1014 break;
1015 default:
1016 return -EINVAL;
1017 }
1018
Mark Brown3c43c692013-12-12 00:49:22 +00001019 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_BCLK_CTRL,
1020 ARIZONA_AIF1_BCLK_INV |
1021 ARIZONA_AIF1_BCLK_MSTR,
1022 bclk);
1023 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_TX_PIN_CTRL,
1024 ARIZONA_AIF1TX_LRCLK_INV |
1025 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
1026 regmap_update_bits_async(arizona->regmap,
1027 base + ARIZONA_AIF_RX_PIN_CTRL,
1028 ARIZONA_AIF1RX_LRCLK_INV |
1029 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
1030 regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FORMAT,
1031 ARIZONA_AIF1_FMT_MASK, mode);
Mark Brown07ed8732012-06-18 21:08:44 +01001032
1033 return 0;
1034}
1035
Mark Brown949e6bc2012-07-04 18:58:04 +01001036static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001037 -1,
1038 48000,
1039 64000,
1040 96000,
1041 128000,
1042 192000,
1043 256000,
1044 384000,
1045 512000,
1046 768000,
1047 1024000,
1048 1536000,
1049 2048000,
1050 3072000,
1051 4096000,
1052 6144000,
1053 8192000,
1054 12288000,
1055 24576000,
1056};
1057
Mark Brown5b2eec32012-07-04 17:32:05 +01001058static const unsigned int arizona_48k_rates[] = {
1059 12000,
1060 24000,
1061 48000,
1062 96000,
1063 192000,
1064 384000,
1065 768000,
1066 4000,
1067 8000,
1068 16000,
1069 32000,
1070 64000,
1071 128000,
1072 256000,
1073 512000,
1074};
1075
1076static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = {
1077 .count = ARRAY_SIZE(arizona_48k_rates),
1078 .list = arizona_48k_rates,
1079};
1080
Mark Brown949e6bc2012-07-04 18:58:04 +01001081static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001082 -1,
1083 44100,
1084 58800,
1085 88200,
1086 117600,
1087 177640,
1088 235200,
1089 352800,
1090 470400,
1091 705600,
1092 940800,
1093 1411200,
1094 1881600,
Heather Lomond4758be32012-09-05 05:02:10 -04001095 2822400,
Mark Brown07ed8732012-06-18 21:08:44 +01001096 3763200,
1097 5644800,
1098 7526400,
1099 11289600,
1100 22579200,
1101};
1102
Mark Brown5b2eec32012-07-04 17:32:05 +01001103static const unsigned int arizona_44k1_rates[] = {
1104 11025,
1105 22050,
1106 44100,
1107 88200,
1108 176400,
1109 352800,
1110 705600,
1111};
1112
1113static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = {
1114 .count = ARRAY_SIZE(arizona_44k1_rates),
1115 .list = arizona_44k1_rates,
1116};
1117
Mark Brown07ed8732012-06-18 21:08:44 +01001118static int arizona_sr_vals[] = {
1119 0,
1120 12000,
1121 24000,
1122 48000,
1123 96000,
1124 192000,
1125 384000,
1126 768000,
1127 0,
1128 11025,
1129 22050,
1130 44100,
1131 88200,
1132 176400,
1133 352800,
1134 705600,
1135 4000,
1136 8000,
1137 16000,
1138 32000,
1139 64000,
1140 128000,
1141 256000,
1142 512000,
1143};
1144
Mark Brown5b2eec32012-07-04 17:32:05 +01001145static int arizona_startup(struct snd_pcm_substream *substream,
1146 struct snd_soc_dai *dai)
1147{
1148 struct snd_soc_codec *codec = dai->codec;
1149 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1150 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
1151 const struct snd_pcm_hw_constraint_list *constraint;
1152 unsigned int base_rate;
1153
1154 switch (dai_priv->clk) {
1155 case ARIZONA_CLK_SYSCLK:
1156 base_rate = priv->sysclk;
1157 break;
1158 case ARIZONA_CLK_ASYNCCLK:
1159 base_rate = priv->asyncclk;
1160 break;
1161 default:
1162 return 0;
1163 }
1164
Mark Brownf2c26d42013-01-21 16:09:36 +09001165 if (base_rate == 0)
1166 return 0;
1167
Mark Brown5b2eec32012-07-04 17:32:05 +01001168 if (base_rate % 8000)
1169 constraint = &arizona_44k1_constraint;
1170 else
1171 constraint = &arizona_48k_constraint;
1172
1173 return snd_pcm_hw_constraint_list(substream->runtime, 0,
1174 SNDRV_PCM_HW_PARAM_RATE,
1175 constraint);
1176}
1177
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001178static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec,
1179 unsigned int rate)
1180{
1181 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1182 struct arizona *arizona = priv->arizona;
1183 struct reg_default dac_comp[] = {
1184 { 0x80, 0x3 },
1185 { ARIZONA_DAC_COMP_1, 0 },
1186 { ARIZONA_DAC_COMP_2, 0 },
1187 { 0x80, 0x0 },
1188 };
1189
Lars-Peter Clausend74bcaa2014-11-09 17:00:59 +01001190 mutex_lock(&arizona->dac_comp_lock);
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001191
1192 dac_comp[1].def = arizona->dac_comp_coeff;
1193 if (rate >= 176400)
1194 dac_comp[2].def = arizona->dac_comp_enabled;
1195
Lars-Peter Clausend74bcaa2014-11-09 17:00:59 +01001196 mutex_unlock(&arizona->dac_comp_lock);
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001197
1198 regmap_multi_reg_write(arizona->regmap,
1199 dac_comp,
1200 ARRAY_SIZE(dac_comp));
1201}
1202
Mark Brownb272efc2012-10-10 15:10:08 +09001203static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
1204 struct snd_pcm_hw_params *params,
1205 struct snd_soc_dai *dai)
Mark Brown07ed8732012-06-18 21:08:44 +01001206{
1207 struct snd_soc_codec *codec = dai->codec;
Mark Brownc013b272012-07-04 20:05:57 +01001208 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1209 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown07ed8732012-06-18 21:08:44 +01001210 int base = dai->driver->base;
Mark Brownb272efc2012-10-10 15:10:08 +09001211 int i, sr_val;
1212
1213 /*
1214 * We will need to be more flexible than this in future,
1215 * currently we use a single sample rate for SYSCLK.
1216 */
1217 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
1218 if (arizona_sr_vals[i] == params_rate(params))
1219 break;
1220 if (i == ARRAY_SIZE(arizona_sr_vals)) {
1221 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1222 params_rate(params));
1223 return -EINVAL;
1224 }
1225 sr_val = i;
1226
1227 switch (dai_priv->clk) {
1228 case ARIZONA_CLK_SYSCLK:
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001229 switch (priv->arizona->type) {
1230 case WM5102:
1231 arizona_wm5102_set_dac_comp(codec,
1232 params_rate(params));
1233 break;
1234 default:
1235 break;
1236 }
1237
Mark Brownb272efc2012-10-10 15:10:08 +09001238 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
1239 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
1240 if (base)
1241 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1242 ARIZONA_AIF1_RATE_MASK, 0);
1243 break;
1244 case ARIZONA_CLK_ASYNCCLK:
1245 snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
Charles Keepaxc24084d2014-09-01 15:48:52 +01001246 ARIZONA_ASYNC_SAMPLE_RATE_1_MASK, sr_val);
Mark Brownb272efc2012-10-10 15:10:08 +09001247 if (base)
1248 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1249 ARIZONA_AIF1_RATE_MASK,
1250 8 << ARIZONA_AIF1_RATE_SHIFT);
1251 break;
1252 default:
1253 arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
1254 return -EINVAL;
1255 }
1256
1257 return 0;
1258}
1259
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001260static bool arizona_aif_cfg_changed(struct snd_soc_codec *codec,
1261 int base, int bclk, int lrclk, int frame)
1262{
1263 int val;
1264
1265 val = snd_soc_read(codec, base + ARIZONA_AIF_BCLK_CTRL);
1266 if (bclk != (val & ARIZONA_AIF1_BCLK_FREQ_MASK))
1267 return true;
1268
1269 val = snd_soc_read(codec, base + ARIZONA_AIF_TX_BCLK_RATE);
1270 if (lrclk != (val & ARIZONA_AIF1TX_BCPF_MASK))
1271 return true;
1272
1273 val = snd_soc_read(codec, base + ARIZONA_AIF_FRAME_CTRL_1);
1274 if (frame != (val & (ARIZONA_AIF1TX_WL_MASK |
1275 ARIZONA_AIF1TX_SLOT_LEN_MASK)))
1276 return true;
1277
1278 return false;
1279}
1280
Mark Brown07ed8732012-06-18 21:08:44 +01001281static int arizona_hw_params(struct snd_pcm_substream *substream,
1282 struct snd_pcm_hw_params *params,
1283 struct snd_soc_dai *dai)
1284{
1285 struct snd_soc_codec *codec = dai->codec;
1286 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brownc94aa302013-01-17 16:35:14 +09001287 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +01001288 int base = dai->driver->base;
1289 const int *rates;
Mark Brown76bf9692013-03-05 14:17:47 +08001290 int i, ret, val;
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001291 int channels = params_channels(params);
Mark Brownc94aa302013-01-17 16:35:14 +09001292 int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001293 int tdm_width = arizona->tdm_width[dai->id - 1];
1294 int tdm_slots = arizona->tdm_slots[dai->id - 1];
Mark Brownc94aa302013-01-17 16:35:14 +09001295 int bclk, lrclk, wl, frame, bclk_target;
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001296 bool reconfig;
1297 unsigned int aif_tx_state, aif_rx_state;
Mark Brown07ed8732012-06-18 21:08:44 +01001298
1299 if (params_rate(params) % 8000)
Mark Brown949e6bc2012-07-04 18:58:04 +01001300 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001301 else
Mark Brown949e6bc2012-07-04 18:58:04 +01001302 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001303
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001304 wl = snd_pcm_format_width(params_format(params));
1305
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001306 if (tdm_slots) {
1307 arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n",
1308 tdm_slots, tdm_width);
1309 bclk_target = tdm_slots * tdm_width * params_rate(params);
1310 channels = tdm_slots;
1311 } else {
1312 bclk_target = snd_soc_params_to_bclk(params);
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001313 tdm_width = wl;
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001314 }
1315
1316 if (chan_limit && chan_limit < channels) {
Mark Brownc94aa302013-01-17 16:35:14 +09001317 arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001318 bclk_target /= channels;
Mark Brownc94aa302013-01-17 16:35:14 +09001319 bclk_target *= chan_limit;
1320 }
1321
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001322 /* Force multiple of 2 channels for I2S mode */
Mark Brown76bf9692013-03-05 14:17:47 +08001323 val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001324 val &= ARIZONA_AIF1_FMT_MASK;
1325 if ((channels & 1) && (val == ARIZONA_FMT_I2S_MODE)) {
Mark Brown76bf9692013-03-05 14:17:47 +08001326 arizona_aif_dbg(dai, "Forcing stereo mode\n");
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001327 bclk_target /= channels;
1328 bclk_target *= channels + 1;
Mark Brown76bf9692013-03-05 14:17:47 +08001329 }
1330
Mark Brown949e6bc2012-07-04 18:58:04 +01001331 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brownc94aa302013-01-17 16:35:14 +09001332 if (rates[i] >= bclk_target &&
Mark Brown50017652012-07-04 19:07:09 +01001333 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +01001334 bclk = i;
1335 break;
1336 }
1337 }
Mark Brown949e6bc2012-07-04 18:58:04 +01001338 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001339 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1340 params_rate(params));
1341 return -EINVAL;
1342 }
1343
Mark Brownb59e0f82013-01-17 14:15:59 +09001344 lrclk = rates[bclk] / params_rate(params);
Mark Brown07ed8732012-06-18 21:08:44 +01001345
1346 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
1347 rates[bclk], rates[bclk] / lrclk);
1348
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001349 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | tdm_width;
Mark Brown07ed8732012-06-18 21:08:44 +01001350
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001351 reconfig = arizona_aif_cfg_changed(codec, base, bclk, lrclk, frame);
1352
1353 if (reconfig) {
1354 /* Save AIF TX/RX state */
1355 aif_tx_state = snd_soc_read(codec,
1356 base + ARIZONA_AIF_TX_ENABLES);
1357 aif_rx_state = snd_soc_read(codec,
1358 base + ARIZONA_AIF_RX_ENABLES);
1359 /* Disable AIF TX/RX before reconfiguring it */
1360 regmap_update_bits_async(arizona->regmap,
1361 base + ARIZONA_AIF_TX_ENABLES, 0xff, 0x0);
1362 regmap_update_bits(arizona->regmap,
1363 base + ARIZONA_AIF_RX_ENABLES, 0xff, 0x0);
1364 }
1365
Mark Brownb272efc2012-10-10 15:10:08 +09001366 ret = arizona_hw_params_rate(substream, params, dai);
1367 if (ret != 0)
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001368 goto restore_aif;
Mark Brownc013b272012-07-04 20:05:57 +01001369
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001370 if (reconfig) {
1371 regmap_update_bits_async(arizona->regmap,
1372 base + ARIZONA_AIF_BCLK_CTRL,
1373 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
1374 regmap_update_bits_async(arizona->regmap,
1375 base + ARIZONA_AIF_TX_BCLK_RATE,
1376 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
1377 regmap_update_bits_async(arizona->regmap,
1378 base + ARIZONA_AIF_RX_BCLK_RATE,
1379 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
1380 regmap_update_bits_async(arizona->regmap,
1381 base + ARIZONA_AIF_FRAME_CTRL_1,
1382 ARIZONA_AIF1TX_WL_MASK |
1383 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
1384 regmap_update_bits(arizona->regmap,
1385 base + ARIZONA_AIF_FRAME_CTRL_2,
1386 ARIZONA_AIF1RX_WL_MASK |
1387 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
1388 }
Mark Brown07ed8732012-06-18 21:08:44 +01001389
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001390restore_aif:
1391 if (reconfig) {
1392 /* Restore AIF TX/RX state */
1393 regmap_update_bits_async(arizona->regmap,
1394 base + ARIZONA_AIF_TX_ENABLES,
1395 0xff, aif_tx_state);
1396 regmap_update_bits(arizona->regmap,
1397 base + ARIZONA_AIF_RX_ENABLES,
1398 0xff, aif_rx_state);
1399 }
1400 return ret;
Mark Brown07ed8732012-06-18 21:08:44 +01001401}
1402
Mark Brown410837a2012-07-05 17:26:59 +01001403static const char *arizona_dai_clk_str(int clk_id)
1404{
1405 switch (clk_id) {
1406 case ARIZONA_CLK_SYSCLK:
1407 return "SYSCLK";
1408 case ARIZONA_CLK_ASYNCCLK:
1409 return "ASYNCCLK";
1410 default:
1411 return "Unknown clock";
1412 }
1413}
1414
Mark Brown5b2eec32012-07-04 17:32:05 +01001415static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
1416 int clk_id, unsigned int freq, int dir)
1417{
1418 struct snd_soc_codec *codec = dai->codec;
1419 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1420 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown410837a2012-07-05 17:26:59 +01001421 struct snd_soc_dapm_route routes[2];
Mark Brown5b2eec32012-07-04 17:32:05 +01001422
1423 switch (clk_id) {
1424 case ARIZONA_CLK_SYSCLK:
1425 case ARIZONA_CLK_ASYNCCLK:
1426 break;
1427 default:
1428 return -EINVAL;
1429 }
1430
Mark Brown410837a2012-07-05 17:26:59 +01001431 if (clk_id == dai_priv->clk)
1432 return 0;
1433
1434 if (dai->active) {
Mark Brown5b2eec32012-07-04 17:32:05 +01001435 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
1436 dai->id);
1437 return -EBUSY;
1438 }
1439
Mark Brownc8d35a62012-12-07 12:49:40 +09001440 dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1,
1441 arizona_dai_clk_str(clk_id));
1442
Mark Brown410837a2012-07-05 17:26:59 +01001443 memset(&routes, 0, sizeof(routes));
1444 routes[0].sink = dai->driver->capture.stream_name;
1445 routes[1].sink = dai->driver->playback.stream_name;
Mark Brown5b2eec32012-07-04 17:32:05 +01001446
Mark Brown410837a2012-07-05 17:26:59 +01001447 routes[0].source = arizona_dai_clk_str(dai_priv->clk);
1448 routes[1].source = arizona_dai_clk_str(dai_priv->clk);
1449 snd_soc_dapm_del_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
1450
1451 routes[0].source = arizona_dai_clk_str(clk_id);
1452 routes[1].source = arizona_dai_clk_str(clk_id);
1453 snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
1454
Mark Brown0c778e82012-12-06 18:22:25 +09001455 dai_priv->clk = clk_id;
1456
Mark Brown410837a2012-07-05 17:26:59 +01001457 return snd_soc_dapm_sync(&codec->dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +01001458}
1459
Mark Brown01df2592012-12-12 16:22:08 +09001460static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
1461{
1462 struct snd_soc_codec *codec = dai->codec;
1463 int base = dai->driver->base;
1464 unsigned int reg;
1465
1466 if (tristate)
1467 reg = ARIZONA_AIF1_TRI;
1468 else
1469 reg = 0;
1470
1471 return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1472 ARIZONA_AIF1_TRI, reg);
1473}
1474
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001475static void arizona_set_channels_to_mask(struct snd_soc_dai *dai,
1476 unsigned int base,
1477 int channels, unsigned int mask)
1478{
1479 struct snd_soc_codec *codec = dai->codec;
1480 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1481 struct arizona *arizona = priv->arizona;
1482 int slot, i;
1483
1484 for (i = 0; i < channels; ++i) {
1485 slot = ffs(mask) - 1;
1486 if (slot < 0)
1487 return;
1488
1489 regmap_write(arizona->regmap, base + i, slot);
1490
1491 mask &= ~(1 << slot);
1492 }
1493
1494 if (mask)
1495 arizona_aif_warn(dai, "Too many channels in TDM mask\n");
1496}
1497
1498static int arizona_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
1499 unsigned int rx_mask, int slots, int slot_width)
1500{
1501 struct snd_soc_codec *codec = dai->codec;
1502 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1503 struct arizona *arizona = priv->arizona;
1504 int base = dai->driver->base;
1505 int rx_max_chan = dai->driver->playback.channels_max;
1506 int tx_max_chan = dai->driver->capture.channels_max;
1507
1508 /* Only support TDM for the physical AIFs */
1509 if (dai->id > ARIZONA_MAX_AIF)
1510 return -ENOTSUPP;
1511
1512 if (slots == 0) {
1513 tx_mask = (1 << tx_max_chan) - 1;
1514 rx_mask = (1 << rx_max_chan) - 1;
1515 }
1516
1517 arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_3,
1518 tx_max_chan, tx_mask);
1519 arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_11,
1520 rx_max_chan, rx_mask);
1521
1522 arizona->tdm_width[dai->id - 1] = slot_width;
1523 arizona->tdm_slots[dai->id - 1] = slots;
1524
1525 return 0;
1526}
1527
Mark Brown07ed8732012-06-18 21:08:44 +01001528const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +01001529 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +01001530 .set_fmt = arizona_set_fmt,
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001531 .set_tdm_slot = arizona_set_tdm_slot,
Mark Brown07ed8732012-06-18 21:08:44 +01001532 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +01001533 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown01df2592012-12-12 16:22:08 +09001534 .set_tristate = arizona_set_tristate,
Mark Brown07ed8732012-06-18 21:08:44 +01001535};
Mark Browna8379872012-07-09 12:16:41 +01001536EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +01001537
Mark Brownbd1dd882013-05-17 13:29:03 +01001538const struct snd_soc_dai_ops arizona_simple_dai_ops = {
1539 .startup = arizona_startup,
1540 .hw_params = arizona_hw_params_rate,
1541 .set_sysclk = arizona_dai_set_sysclk,
1542};
1543EXPORT_SYMBOL_GPL(arizona_simple_dai_ops);
1544
Mark Brown5b2eec32012-07-04 17:32:05 +01001545int arizona_init_dai(struct arizona_priv *priv, int id)
1546{
1547 struct arizona_dai_priv *dai_priv = &priv->dai[id];
1548
1549 dai_priv->clk = ARIZONA_CLK_SYSCLK;
1550
1551 return 0;
1552}
1553EXPORT_SYMBOL_GPL(arizona_init_dai);
1554
Mark Brown07ed8732012-06-18 21:08:44 +01001555static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
1556{
1557 struct arizona_fll *fll = data;
1558
1559 arizona_fll_dbg(fll, "clock OK\n");
1560
1561 complete(&fll->ok);
1562
1563 return IRQ_HANDLED;
1564}
1565
1566static struct {
1567 unsigned int min;
1568 unsigned int max;
1569 u16 fratio;
1570 int ratio;
1571} fll_fratios[] = {
1572 { 0, 64000, 4, 16 },
1573 { 64000, 128000, 3, 8 },
1574 { 128000, 256000, 2, 4 },
1575 { 256000, 1000000, 1, 2 },
1576 { 1000000, 13500000, 0, 1 },
1577};
1578
Mark Brown8f113d72013-03-05 12:08:57 +08001579static struct {
1580 unsigned int min;
1581 unsigned int max;
1582 u16 gain;
1583} fll_gains[] = {
1584 { 0, 256000, 0 },
1585 { 256000, 1000000, 2 },
1586 { 1000000, 13500000, 4 },
1587};
1588
Mark Brown07ed8732012-06-18 21:08:44 +01001589struct arizona_fll_cfg {
1590 int n;
1591 int theta;
1592 int lambda;
1593 int refdiv;
1594 int outdiv;
1595 int fratio;
Mark Brown8f113d72013-03-05 12:08:57 +08001596 int gain;
Mark Brown07ed8732012-06-18 21:08:44 +01001597};
1598
Charles Keepax23f785a82014-03-07 16:34:20 +00001599static int arizona_validate_fll(struct arizona_fll *fll,
1600 unsigned int Fref,
1601 unsigned int Fout)
1602{
1603 unsigned int Fvco_min;
1604
Charles Keepaxc8badda2014-07-09 17:41:49 +01001605 if (fll->fout && Fout != fll->fout) {
1606 arizona_fll_err(fll,
1607 "Can't change output on active FLL\n");
1608 return -EINVAL;
1609 }
1610
Charles Keepax23f785a82014-03-07 16:34:20 +00001611 if (Fref / ARIZONA_FLL_MAX_REFDIV > ARIZONA_FLL_MAX_FREF) {
1612 arizona_fll_err(fll,
1613 "Can't scale %dMHz in to <=13.5MHz\n",
1614 Fref);
1615 return -EINVAL;
1616 }
1617
1618 Fvco_min = ARIZONA_FLL_MIN_FVCO * fll->vco_mult;
1619 if (Fout * ARIZONA_FLL_MAX_OUTDIV < Fvco_min) {
1620 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
1621 Fout);
1622 return -EINVAL;
1623 }
1624
1625 return 0;
1626}
1627
Charles Keepaxd0800342014-03-07 16:34:25 +00001628static int arizona_find_fratio(unsigned int Fref, int *fratio)
1629{
1630 int i;
1631
1632 /* Find an appropriate FLL_FRATIO */
1633 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
1634 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
1635 if (fratio)
1636 *fratio = fll_fratios[i].fratio;
1637 return fll_fratios[i].ratio;
1638 }
1639 }
1640
1641 return -EINVAL;
1642}
1643
1644static int arizona_calc_fratio(struct arizona_fll *fll,
1645 struct arizona_fll_cfg *cfg,
1646 unsigned int target,
1647 unsigned int Fref, bool sync)
1648{
1649 int init_ratio, ratio;
1650 int refdiv, div;
1651
1652 /* Fref must be <=13.5MHz, find initial refdiv */
1653 div = 1;
1654 cfg->refdiv = 0;
1655 while (Fref > ARIZONA_FLL_MAX_FREF) {
1656 div *= 2;
1657 Fref /= 2;
1658 cfg->refdiv++;
1659
1660 if (div > ARIZONA_FLL_MAX_REFDIV)
1661 return -EINVAL;
1662 }
1663
1664 /* Find an appropriate FLL_FRATIO */
1665 init_ratio = arizona_find_fratio(Fref, &cfg->fratio);
1666 if (init_ratio < 0) {
1667 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
1668 Fref);
1669 return init_ratio;
1670 }
1671
1672 switch (fll->arizona->type) {
1673 case WM5110:
1674 if (fll->arizona->rev < 3 || sync)
1675 return init_ratio;
1676 break;
1677 default:
1678 return init_ratio;
1679 }
1680
1681 cfg->fratio = init_ratio - 1;
1682
1683 /* Adjust FRATIO/refdiv to avoid integer mode if possible */
1684 refdiv = cfg->refdiv;
1685
1686 while (div <= ARIZONA_FLL_MAX_REFDIV) {
1687 for (ratio = init_ratio; ratio <= ARIZONA_FLL_MAX_FRATIO;
1688 ratio++) {
Charles Keepax35a730a2014-07-09 17:41:45 +01001689 if ((ARIZONA_FLL_VCO_CORNER / 2) /
1690 (fll->vco_mult * ratio) < Fref)
Charles Keepax29fee822014-07-09 17:41:44 +01001691 break;
1692
Charles Keepaxd0800342014-03-07 16:34:25 +00001693 if (target % (ratio * Fref)) {
1694 cfg->refdiv = refdiv;
1695 cfg->fratio = ratio - 1;
1696 return ratio;
1697 }
1698 }
1699
Charles Keepax4714bc02014-07-09 17:41:43 +01001700 for (ratio = init_ratio - 1; ratio > 0; ratio--) {
Charles Keepaxd0800342014-03-07 16:34:25 +00001701 if (target % (ratio * Fref)) {
1702 cfg->refdiv = refdiv;
1703 cfg->fratio = ratio - 1;
1704 return ratio;
1705 }
1706 }
1707
1708 div *= 2;
1709 Fref /= 2;
1710 refdiv++;
1711 init_ratio = arizona_find_fratio(Fref, NULL);
1712 }
1713
1714 arizona_fll_warn(fll, "Falling back to integer mode operation\n");
1715 return cfg->fratio + 1;
1716}
1717
Mark Brown07ed8732012-06-18 21:08:44 +01001718static int arizona_calc_fll(struct arizona_fll *fll,
1719 struct arizona_fll_cfg *cfg,
Charles Keepaxd0800342014-03-07 16:34:25 +00001720 unsigned int Fref, bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01001721{
1722 unsigned int target, div, gcd_fll;
1723 int i, ratio;
1724
Charles Keepax8ccefcd2014-03-07 16:34:21 +00001725 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, fll->fout);
Mark Brown07ed8732012-06-18 21:08:44 +01001726
Mark Brown2b4d39f2012-07-10 17:03:46 +01001727 /* Fvco should be over the targt; don't check the upper bound */
Charles Keepaxf641aec2014-03-07 16:34:22 +00001728 div = ARIZONA_FLL_MIN_OUTDIV;
1729 while (fll->fout * div < ARIZONA_FLL_MIN_FVCO * fll->vco_mult) {
Mark Brown07ed8732012-06-18 21:08:44 +01001730 div++;
Charles Keepaxf641aec2014-03-07 16:34:22 +00001731 if (div > ARIZONA_FLL_MAX_OUTDIV)
Mark Brown07ed8732012-06-18 21:08:44 +01001732 return -EINVAL;
Mark Brown07ed8732012-06-18 21:08:44 +01001733 }
Charles Keepaxf641aec2014-03-07 16:34:22 +00001734 target = fll->fout * div / fll->vco_mult;
Mark Brown07ed8732012-06-18 21:08:44 +01001735 cfg->outdiv = div;
1736
1737 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
1738
Charles Keepaxd0800342014-03-07 16:34:25 +00001739 /* Find an appropriate FLL_FRATIO and refdiv */
1740 ratio = arizona_calc_fratio(fll, cfg, target, Fref, sync);
1741 if (ratio < 0)
1742 return ratio;
Mark Brown07ed8732012-06-18 21:08:44 +01001743
Mark Brown07ed8732012-06-18 21:08:44 +01001744 /* Apply the division for our remaining calculations */
Charles Keepaxd0800342014-03-07 16:34:25 +00001745 Fref = Fref / (1 << cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08001746
Mark Brown07ed8732012-06-18 21:08:44 +01001747 cfg->n = target / (ratio * Fref);
1748
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001749 if (target % (ratio * Fref)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001750 gcd_fll = gcd(target, ratio * Fref);
1751 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
1752
1753 cfg->theta = (target - (cfg->n * ratio * Fref))
1754 / gcd_fll;
1755 cfg->lambda = (ratio * Fref) / gcd_fll;
1756 } else {
1757 cfg->theta = 0;
1758 cfg->lambda = 0;
1759 }
1760
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001761 /* Round down to 16bit range with cost of accuracy lost.
1762 * Denominator must be bigger than numerator so we only
1763 * take care of it.
1764 */
1765 while (cfg->lambda >= (1 << 16)) {
1766 cfg->theta >>= 1;
1767 cfg->lambda >>= 1;
1768 }
1769
Charles Keepax5a3935c2014-03-07 16:34:23 +00001770 for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
1771 if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
1772 cfg->gain = fll_gains[i].gain;
1773 break;
1774 }
1775 }
1776 if (i == ARRAY_SIZE(fll_gains)) {
1777 arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
1778 Fref);
1779 return -EINVAL;
1780 }
1781
Mark Brown07ed8732012-06-18 21:08:44 +01001782 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
1783 cfg->n, cfg->theta, cfg->lambda);
1784 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
1785 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08001786 arizona_fll_dbg(fll, "GAIN=%d\n", cfg->gain);
Mark Brown07ed8732012-06-18 21:08:44 +01001787
1788 return 0;
1789
1790}
1791
1792static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
Mark Brown8f113d72013-03-05 12:08:57 +08001793 struct arizona_fll_cfg *cfg, int source,
1794 bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01001795{
Mark Brown3c43c692013-12-12 00:49:22 +00001796 regmap_update_bits_async(arizona->regmap, base + 3,
1797 ARIZONA_FLL1_THETA_MASK, cfg->theta);
1798 regmap_update_bits_async(arizona->regmap, base + 4,
1799 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
1800 regmap_update_bits_async(arizona->regmap, base + 5,
1801 ARIZONA_FLL1_FRATIO_MASK,
1802 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
1803 regmap_update_bits_async(arizona->regmap, base + 6,
1804 ARIZONA_FLL1_CLK_REF_DIV_MASK |
1805 ARIZONA_FLL1_CLK_REF_SRC_MASK,
1806 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
1807 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
Mark Brown07ed8732012-06-18 21:08:44 +01001808
Charles Keepax61719db2014-03-07 16:34:19 +00001809 if (sync) {
1810 regmap_update_bits(arizona->regmap, base + 0x7,
1811 ARIZONA_FLL1_GAIN_MASK,
1812 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
1813 } else {
1814 regmap_update_bits(arizona->regmap, base + 0x5,
1815 ARIZONA_FLL1_OUTDIV_MASK,
1816 cfg->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
1817 regmap_update_bits(arizona->regmap, base + 0x9,
1818 ARIZONA_FLL1_GAIN_MASK,
1819 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
1820 }
Mark Brown8f113d72013-03-05 12:08:57 +08001821
Mark Brown3c43c692013-12-12 00:49:22 +00001822 regmap_update_bits_async(arizona->regmap, base + 2,
1823 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
1824 ARIZONA_FLL1_CTRL_UPD | cfg->n);
Mark Brown07ed8732012-06-18 21:08:44 +01001825}
1826
Charles Keepaxc393aca2014-07-09 17:41:47 +01001827static int arizona_is_enabled_fll(struct arizona_fll *fll)
Charles Keepaxd122d6c2013-02-20 17:28:36 +00001828{
1829 struct arizona *arizona = fll->arizona;
1830 unsigned int reg;
1831 int ret;
1832
1833 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
1834 if (ret != 0) {
1835 arizona_fll_err(fll, "Failed to read current state: %d\n",
1836 ret);
1837 return ret;
1838 }
1839
1840 return reg & ARIZONA_FLL1_ENA;
1841}
1842
Charles Keepaxc393aca2014-07-09 17:41:47 +01001843static int arizona_enable_fll(struct arizona_fll *fll)
Charles Keepax35722812013-02-20 17:28:38 +00001844{
1845 struct arizona *arizona = fll->arizona;
1846 int ret;
Charles Keepax49c60542013-09-16 15:34:35 +01001847 bool use_sync = false;
Charles Keepaxc393aca2014-07-09 17:41:47 +01001848 int already_enabled = arizona_is_enabled_fll(fll);
Charles Keepax23f785a82014-03-07 16:34:20 +00001849 struct arizona_fll_cfg cfg;
Charles Keepax35722812013-02-20 17:28:38 +00001850
Charles Keepaxc393aca2014-07-09 17:41:47 +01001851 if (already_enabled < 0)
1852 return already_enabled;
1853
Charles Keepaxc8badda2014-07-09 17:41:49 +01001854 if (already_enabled) {
1855 /* Facilitate smooth refclk across the transition */
1856 regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x7,
1857 ARIZONA_FLL1_GAIN_MASK, 0);
1858 regmap_update_bits_async(fll->arizona->regmap, fll->base + 1,
1859 ARIZONA_FLL1_FREERUN,
1860 ARIZONA_FLL1_FREERUN);
1861 }
1862
Mark Brownff680a12013-03-04 16:00:19 +08001863 /*
1864 * If we have both REFCLK and SYNCCLK then enable both,
1865 * otherwise apply the SYNCCLK settings to REFCLK.
1866 */
Charles Keepax49c60542013-09-16 15:34:35 +01001867 if (fll->ref_src >= 0 && fll->ref_freq &&
1868 fll->ref_src != fll->sync_src) {
Charles Keepaxd0800342014-03-07 16:34:25 +00001869 arizona_calc_fll(fll, &cfg, fll->ref_freq, false);
Charles Keepax35722812013-02-20 17:28:38 +00001870
Charles Keepax23f785a82014-03-07 16:34:20 +00001871 arizona_apply_fll(arizona, fll->base, &cfg, fll->ref_src,
Mark Brown8f113d72013-03-05 12:08:57 +08001872 false);
Charles Keepax49c60542013-09-16 15:34:35 +01001873 if (fll->sync_src >= 0) {
Charles Keepaxd0800342014-03-07 16:34:25 +00001874 arizona_calc_fll(fll, &cfg, fll->sync_freq, true);
Charles Keepax23f785a82014-03-07 16:34:20 +00001875
1876 arizona_apply_fll(arizona, fll->base + 0x10, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08001877 fll->sync_src, true);
Charles Keepax49c60542013-09-16 15:34:35 +01001878 use_sync = true;
1879 }
Mark Brownff680a12013-03-04 16:00:19 +08001880 } else if (fll->sync_src >= 0) {
Charles Keepaxd0800342014-03-07 16:34:25 +00001881 arizona_calc_fll(fll, &cfg, fll->sync_freq, false);
Mark Brownff680a12013-03-04 16:00:19 +08001882
Charles Keepax23f785a82014-03-07 16:34:20 +00001883 arizona_apply_fll(arizona, fll->base, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08001884 fll->sync_src, false);
Mark Browneca2e8e2013-03-06 00:09:59 +08001885
Mark Brown3c43c692013-12-12 00:49:22 +00001886 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
1887 ARIZONA_FLL1_SYNC_ENA, 0);
Mark Brownff680a12013-03-04 16:00:19 +08001888 } else {
1889 arizona_fll_err(fll, "No clocks provided\n");
Charles Keepaxc393aca2014-07-09 17:41:47 +01001890 return -EINVAL;
Mark Brownff680a12013-03-04 16:00:19 +08001891 }
Charles Keepax35722812013-02-20 17:28:38 +00001892
Mark Brown576411be2013-03-05 12:07:16 +08001893 /*
1894 * Increase the bandwidth if we're not using a low frequency
1895 * sync source.
1896 */
Charles Keepax49c60542013-09-16 15:34:35 +01001897 if (use_sync && fll->sync_freq > 100000)
Mark Brown3c43c692013-12-12 00:49:22 +00001898 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
1899 ARIZONA_FLL1_SYNC_BW, 0);
Mark Brown576411be2013-03-05 12:07:16 +08001900 else
Mark Brown3c43c692013-12-12 00:49:22 +00001901 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
1902 ARIZONA_FLL1_SYNC_BW,
1903 ARIZONA_FLL1_SYNC_BW);
Mark Brown576411be2013-03-05 12:07:16 +08001904
Charles Keepaxc393aca2014-07-09 17:41:47 +01001905 if (!already_enabled)
Charles Keepax35722812013-02-20 17:28:38 +00001906 pm_runtime_get(arizona->dev);
1907
1908 /* Clear any pending completions */
1909 try_wait_for_completion(&fll->ok);
1910
Mark Brown3c43c692013-12-12 00:49:22 +00001911 regmap_update_bits_async(arizona->regmap, fll->base + 1,
Mark Brown3c43c692013-12-12 00:49:22 +00001912 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
Charles Keepax49c60542013-09-16 15:34:35 +01001913 if (use_sync)
Mark Brown3c43c692013-12-12 00:49:22 +00001914 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
1915 ARIZONA_FLL1_SYNC_ENA,
1916 ARIZONA_FLL1_SYNC_ENA);
Charles Keepax35722812013-02-20 17:28:38 +00001917
Charles Keepaxc8badda2014-07-09 17:41:49 +01001918 if (already_enabled)
1919 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1920 ARIZONA_FLL1_FREERUN, 0);
1921
Charles Keepax35722812013-02-20 17:28:38 +00001922 ret = wait_for_completion_timeout(&fll->ok,
1923 msecs_to_jiffies(250));
1924 if (ret == 0)
1925 arizona_fll_warn(fll, "Timed out waiting for lock\n");
Charles Keepaxc393aca2014-07-09 17:41:47 +01001926
1927 return 0;
Charles Keepax35722812013-02-20 17:28:38 +00001928}
1929
Charles Keepax76040542013-02-20 17:28:37 +00001930static void arizona_disable_fll(struct arizona_fll *fll)
1931{
1932 struct arizona *arizona = fll->arizona;
1933 bool change;
1934
Mark Brown3c43c692013-12-12 00:49:22 +00001935 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1936 ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
Charles Keepax76040542013-02-20 17:28:37 +00001937 regmap_update_bits_check(arizona->regmap, fll->base + 1,
1938 ARIZONA_FLL1_ENA, 0, &change);
1939 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1940 ARIZONA_FLL1_SYNC_ENA, 0);
Charles Keepax5e39a502014-07-09 17:41:48 +01001941 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1942 ARIZONA_FLL1_FREERUN, 0);
Charles Keepax76040542013-02-20 17:28:37 +00001943
1944 if (change)
1945 pm_runtime_put_autosuspend(arizona->dev);
1946}
1947
Charles Keepaxee929a92013-02-20 17:28:40 +00001948int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
1949 unsigned int Fref, unsigned int Fout)
1950{
Charles Keepaxc393aca2014-07-09 17:41:47 +01001951 int ret = 0;
Charles Keepaxee929a92013-02-20 17:28:40 +00001952
Charles Keepax1c5617f2013-02-22 17:10:37 +00001953 if (fll->ref_src == source && fll->ref_freq == Fref)
Charles Keepaxee929a92013-02-20 17:28:40 +00001954 return 0;
1955
Charles Keepax23f785a82014-03-07 16:34:20 +00001956 if (fll->fout && Fref > 0) {
1957 ret = arizona_validate_fll(fll, Fref, fll->fout);
1958 if (ret != 0)
1959 return ret;
Charles Keepaxee929a92013-02-20 17:28:40 +00001960 }
1961
1962 fll->ref_src = source;
1963 fll->ref_freq = Fref;
Charles Keepaxee929a92013-02-20 17:28:40 +00001964
Mark Brown86cd6842013-03-07 16:14:04 +08001965 if (fll->fout && Fref > 0) {
Charles Keepaxc393aca2014-07-09 17:41:47 +01001966 ret = arizona_enable_fll(fll);
Charles Keepaxee929a92013-02-20 17:28:40 +00001967 }
1968
Charles Keepaxc393aca2014-07-09 17:41:47 +01001969 return ret;
Charles Keepaxee929a92013-02-20 17:28:40 +00001970}
1971EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
1972
Mark Brown07ed8732012-06-18 21:08:44 +01001973int arizona_set_fll(struct arizona_fll *fll, int source,
1974 unsigned int Fref, unsigned int Fout)
1975{
Charles Keepaxc393aca2014-07-09 17:41:47 +01001976 int ret = 0;
Mark Brown07ed8732012-06-18 21:08:44 +01001977
Mark Brownff680a12013-03-04 16:00:19 +08001978 if (fll->sync_src == source &&
1979 fll->sync_freq == Fref && fll->fout == Fout)
1980 return 0;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00001981
Mark Brownff680a12013-03-04 16:00:19 +08001982 if (Fout) {
1983 if (fll->ref_src >= 0) {
Charles Keepax23f785a82014-03-07 16:34:20 +00001984 ret = arizona_validate_fll(fll, fll->ref_freq, Fout);
Charles Keepax9e359c62013-02-20 17:28:35 +00001985 if (ret != 0)
1986 return ret;
1987 }
1988
Charles Keepax23f785a82014-03-07 16:34:20 +00001989 ret = arizona_validate_fll(fll, Fref, Fout);
Mark Brownff680a12013-03-04 16:00:19 +08001990 if (ret != 0)
1991 return ret;
Charles Keepax9e359c62013-02-20 17:28:35 +00001992 }
Mark Brownff680a12013-03-04 16:00:19 +08001993
1994 fll->sync_src = source;
1995 fll->sync_freq = Fref;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00001996 fll->fout = Fout;
Charles Keepax9e359c62013-02-20 17:28:35 +00001997
Charles Keepax613124c2014-07-09 17:41:46 +01001998 if (Fout)
Charles Keepaxc393aca2014-07-09 17:41:47 +01001999 ret = arizona_enable_fll(fll);
Charles Keepax613124c2014-07-09 17:41:46 +01002000 else
Charles Keepax76040542013-02-20 17:28:37 +00002001 arizona_disable_fll(fll);
Mark Brown07ed8732012-06-18 21:08:44 +01002002
Charles Keepaxc393aca2014-07-09 17:41:47 +01002003 return ret;
Mark Brown07ed8732012-06-18 21:08:44 +01002004}
2005EXPORT_SYMBOL_GPL(arizona_set_fll);
2006
2007int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
2008 int ok_irq, struct arizona_fll *fll)
2009{
2010 int ret;
Charles Keepax19b34bd2013-02-20 17:28:34 +00002011 unsigned int val;
Mark Brown07ed8732012-06-18 21:08:44 +01002012
Mark Brown07ed8732012-06-18 21:08:44 +01002013 init_completion(&fll->ok);
2014
2015 fll->id = id;
2016 fll->base = base;
2017 fll->arizona = arizona;
Charles Keepaxf3f11632013-02-20 17:28:41 +00002018 fll->sync_src = ARIZONA_FLL_SRC_NONE;
Mark Brown07ed8732012-06-18 21:08:44 +01002019
Charles Keepax19b34bd2013-02-20 17:28:34 +00002020 /* Configure default refclk to 32kHz if we have one */
2021 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
2022 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
2023 case ARIZONA_CLK_SRC_MCLK1:
2024 case ARIZONA_CLK_SRC_MCLK2:
2025 fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK;
2026 break;
2027 default:
Charles Keepaxf3f11632013-02-20 17:28:41 +00002028 fll->ref_src = ARIZONA_FLL_SRC_NONE;
Charles Keepax19b34bd2013-02-20 17:28:34 +00002029 }
2030 fll->ref_freq = 32768;
2031
Mark Brown07ed8732012-06-18 21:08:44 +01002032 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
2033 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
2034 "FLL%d clock OK", id);
2035
Mark Brown07ed8732012-06-18 21:08:44 +01002036 ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
2037 arizona_fll_clock_ok, fll);
2038 if (ret != 0) {
2039 dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
2040 id, ret);
2041 }
2042
Charles Keepaxe31c1942013-01-07 16:41:45 +00002043 regmap_update_bits(arizona->regmap, fll->base + 1,
2044 ARIZONA_FLL1_FREERUN, 0);
2045
Mark Brown07ed8732012-06-18 21:08:44 +01002046 return 0;
2047}
2048EXPORT_SYMBOL_GPL(arizona_init_fll);
2049
Mark Brownbc9ab6d2013-01-04 19:31:00 +00002050/**
2051 * arizona_set_output_mode - Set the mode of the specified output
2052 *
2053 * @codec: Device to configure
2054 * @output: Output number
2055 * @diff: True to set the output to differential mode
2056 *
2057 * Some systems use external analogue switches to connect more
2058 * analogue devices to the CODEC than are supported by the device. In
2059 * some systems this requires changing the switched output from single
2060 * ended to differential mode dynamically at runtime, an operation
2061 * supported using this function.
2062 *
2063 * Most systems have a single static configuration and should use
2064 * platform data instead.
2065 */
2066int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
2067{
2068 unsigned int reg, val;
2069
2070 if (output < 1 || output > 6)
2071 return -EINVAL;
2072
2073 reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
2074
2075 if (diff)
2076 val = ARIZONA_OUT1_MONO;
2077 else
2078 val = 0;
2079
2080 return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val);
2081}
2082EXPORT_SYMBOL_GPL(arizona_set_output_mode);
2083
Mark Brown07ed8732012-06-18 21:08:44 +01002084MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
2085MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
2086MODULE_LICENSE("GPL");