blob: 747c71e59c04ff5811fac358a7b1ee57a0235200 [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
Mark Brown07ed8732012-06-18 21:08:44 +010064#define arizona_fll_err(_fll, fmt, ...) \
65 dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
66#define arizona_fll_warn(_fll, fmt, ...) \
67 dev_warn(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
68#define arizona_fll_dbg(_fll, fmt, ...) \
Mark Brown9092a6e2013-02-06 17:58:57 +000069 dev_dbg(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
Mark Brown07ed8732012-06-18 21:08:44 +010070
71#define arizona_aif_err(_dai, fmt, ...) \
72 dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
73#define arizona_aif_warn(_dai, fmt, ...) \
74 dev_warn(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
75#define arizona_aif_dbg(_dai, fmt, ...) \
Mark Brown9092a6e2013-02-06 17:58:57 +000076 dev_dbg(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
Mark Brown07ed8732012-06-18 21:08:44 +010077
Mark Brown56447e12013-01-10 14:45:58 +000078static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
79 struct snd_kcontrol *kcontrol,
80 int event)
81{
82 struct snd_soc_codec *codec = w->codec;
83 struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
84 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
85 bool manual_ena = false;
Mark Brownf4a76e72013-03-13 12:22:39 +000086 int val;
Mark Brown56447e12013-01-10 14:45:58 +000087
88 switch (arizona->type) {
89 case WM5102:
90 switch (arizona->rev) {
91 case 0:
92 break;
93 default:
94 manual_ena = true;
95 break;
96 }
97 default:
98 break;
99 }
100
101 switch (event) {
102 case SND_SOC_DAPM_PRE_PMU:
103 if (!priv->spk_ena && manual_ena) {
Mark Brown3c43c692013-12-12 00:49:22 +0000104 regmap_write_async(arizona->regmap, 0x4f5, 0x25a);
Mark Brown56447e12013-01-10 14:45:58 +0000105 priv->spk_ena_pending = true;
106 }
107 break;
108 case SND_SOC_DAPM_POST_PMU:
Mark Brownf4a76e72013-03-13 12:22:39 +0000109 val = snd_soc_read(codec, ARIZONA_INTERRUPT_RAW_STATUS_3);
110 if (val & ARIZONA_SPK_SHUTDOWN_STS) {
111 dev_crit(arizona->dev,
112 "Speaker not enabled due to temperature\n");
113 return -EBUSY;
114 }
115
Mark Brown3c43c692013-12-12 00:49:22 +0000116 regmap_update_bits_async(arizona->regmap,
117 ARIZONA_OUTPUT_ENABLES_1,
118 1 << w->shift, 1 << w->shift);
Mark Brownf4a76e72013-03-13 12:22:39 +0000119
Mark Brown56447e12013-01-10 14:45:58 +0000120 if (priv->spk_ena_pending) {
121 msleep(75);
Mark Brown3c43c692013-12-12 00:49:22 +0000122 regmap_write_async(arizona->regmap, 0x4f5, 0xda);
Mark Brown56447e12013-01-10 14:45:58 +0000123 priv->spk_ena_pending = false;
124 priv->spk_ena++;
125 }
126 break;
127 case SND_SOC_DAPM_PRE_PMD:
128 if (manual_ena) {
129 priv->spk_ena--;
130 if (!priv->spk_ena)
Mark Brown3c43c692013-12-12 00:49:22 +0000131 regmap_write_async(arizona->regmap,
132 0x4f5, 0x25a);
Mark Brown56447e12013-01-10 14:45:58 +0000133 }
Mark Brownf4a76e72013-03-13 12:22:39 +0000134
Mark Brown3c43c692013-12-12 00:49:22 +0000135 regmap_update_bits_async(arizona->regmap,
136 ARIZONA_OUTPUT_ENABLES_1,
137 1 << w->shift, 0);
Mark Brown56447e12013-01-10 14:45:58 +0000138 break;
139 case SND_SOC_DAPM_POST_PMD:
140 if (manual_ena) {
141 if (!priv->spk_ena)
Mark Brown3c43c692013-12-12 00:49:22 +0000142 regmap_write_async(arizona->regmap,
143 0x4f5, 0x0da);
Mark Brown56447e12013-01-10 14:45:58 +0000144 }
145 break;
146 }
147
148 return 0;
149}
150
Mark Brown899817e2013-03-13 12:32:10 +0000151static irqreturn_t arizona_thermal_warn(int irq, void *data)
152{
153 struct arizona *arizona = data;
154 unsigned int val;
155 int ret;
156
157 ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
158 &val);
159 if (ret != 0) {
160 dev_err(arizona->dev, "Failed to read thermal status: %d\n",
161 ret);
162 } else if (val & ARIZONA_SPK_SHUTDOWN_WARN_STS) {
163 dev_crit(arizona->dev, "Thermal warning\n");
164 }
165
166 return IRQ_HANDLED;
167}
168
169static irqreturn_t arizona_thermal_shutdown(int irq, void *data)
170{
171 struct arizona *arizona = data;
172 unsigned int val;
173 int ret;
174
175 ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
176 &val);
177 if (ret != 0) {
178 dev_err(arizona->dev, "Failed to read thermal status: %d\n",
179 ret);
180 } else if (val & ARIZONA_SPK_SHUTDOWN_STS) {
181 dev_crit(arizona->dev, "Thermal shutdown\n");
Mark Brownf4a76e72013-03-13 12:22:39 +0000182 ret = regmap_update_bits(arizona->regmap,
183 ARIZONA_OUTPUT_ENABLES_1,
184 ARIZONA_OUT4L_ENA |
185 ARIZONA_OUT4R_ENA, 0);
186 if (ret != 0)
187 dev_crit(arizona->dev,
188 "Failed to disable speaker outputs: %d\n",
189 ret);
Mark Brown899817e2013-03-13 12:32:10 +0000190 }
191
192 return IRQ_HANDLED;
193}
194
Mark Brown56447e12013-01-10 14:45:58 +0000195static const struct snd_soc_dapm_widget arizona_spkl =
Mark Brownf4a76e72013-03-13 12:22:39 +0000196 SND_SOC_DAPM_PGA_E("OUT4L", SND_SOC_NOPM,
Mark Brown56447e12013-01-10 14:45:58 +0000197 ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
198 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
199
200static const struct snd_soc_dapm_widget arizona_spkr =
Mark Brownf4a76e72013-03-13 12:22:39 +0000201 SND_SOC_DAPM_PGA_E("OUT4R", SND_SOC_NOPM,
Mark Brown56447e12013-01-10 14:45:58 +0000202 ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
203 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
204
205int arizona_init_spk(struct snd_soc_codec *codec)
206{
Mark Brown899817e2013-03-13 12:32:10 +0000207 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
208 struct arizona *arizona = priv->arizona;
Mark Brown56447e12013-01-10 14:45:58 +0000209 int ret;
210
211 ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkl, 1);
212 if (ret != 0)
213 return ret;
214
Charles Keepax40843ae2013-08-12 23:46:55 +0100215 switch (arizona->type) {
216 case WM8997:
217 break;
218 default:
219 ret = snd_soc_dapm_new_controls(&codec->dapm,
220 &arizona_spkr, 1);
221 if (ret != 0)
222 return ret;
223 break;
224 }
Mark Brown56447e12013-01-10 14:45:58 +0000225
Mark Brown899817e2013-03-13 12:32:10 +0000226 ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN_WARN,
227 "Thermal warning", arizona_thermal_warn,
228 arizona);
229 if (ret != 0)
230 dev_err(arizona->dev,
231 "Failed to get thermal warning IRQ: %d\n",
232 ret);
233
234 ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN,
235 "Thermal shutdown", arizona_thermal_shutdown,
236 arizona);
237 if (ret != 0)
238 dev_err(arizona->dev,
239 "Failed to get thermal shutdown IRQ: %d\n",
240 ret);
241
Mark Brown56447e12013-01-10 14:45:58 +0000242 return 0;
243}
244EXPORT_SYMBOL_GPL(arizona_init_spk);
245
Charles Keepaxb60f3632014-06-10 18:41:02 +0100246static const struct snd_soc_dapm_route arizona_mono_routes[] = {
247 { "OUT1R", NULL, "OUT1L" },
248 { "OUT2R", NULL, "OUT2L" },
249 { "OUT3R", NULL, "OUT3L" },
250 { "OUT4R", NULL, "OUT4L" },
251 { "OUT5R", NULL, "OUT5L" },
252 { "OUT6R", NULL, "OUT6L" },
253};
254
255int arizona_init_mono(struct snd_soc_codec *codec)
256{
257 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
258 struct arizona *arizona = priv->arizona;
259 int i;
260
261 for (i = 0; i < ARIZONA_MAX_OUTPUT; ++i) {
262 if (arizona->pdata.out_mono[i])
263 snd_soc_dapm_add_routes(&codec->dapm,
264 &arizona_mono_routes[i], 1);
265 }
266
267 return 0;
268}
269EXPORT_SYMBOL_GPL(arizona_init_mono);
270
Charles Keepaxb63144e2013-07-04 08:56:28 +0100271int arizona_init_gpio(struct snd_soc_codec *codec)
272{
273 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
274 struct arizona *arizona = priv->arizona;
275 int i;
276
277 switch (arizona->type) {
278 case WM5110:
279 snd_soc_dapm_disable_pin(&codec->dapm, "DRC2 Signal Activity");
Charles Keepaxb79fae62013-07-04 16:53:03 +0100280 break;
281 default:
282 break;
Charles Keepaxb63144e2013-07-04 08:56:28 +0100283 }
284
285 snd_soc_dapm_disable_pin(&codec->dapm, "DRC1 Signal Activity");
286
287 for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
288 switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) {
289 case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT:
290 snd_soc_dapm_enable_pin(&codec->dapm,
291 "DRC1 Signal Activity");
292 break;
293 case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT:
294 snd_soc_dapm_enable_pin(&codec->dapm,
295 "DRC2 Signal Activity");
296 break;
297 default:
298 break;
299 }
300 }
301
302 return 0;
303}
304EXPORT_SYMBOL_GPL(arizona_init_gpio);
305
Mark Brown07ed8732012-06-18 21:08:44 +0100306const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
307 "None",
308 "Tone Generator 1",
309 "Tone Generator 2",
310 "Haptics",
311 "AEC",
312 "Mic Mute Mixer",
313 "Noise Generator",
314 "IN1L",
315 "IN1R",
316 "IN2L",
317 "IN2R",
318 "IN3L",
319 "IN3R",
Mark Brownc9c56fd2012-07-09 19:09:01 +0100320 "IN4L",
321 "IN4R",
Mark Brown07ed8732012-06-18 21:08:44 +0100322 "AIF1RX1",
323 "AIF1RX2",
324 "AIF1RX3",
325 "AIF1RX4",
326 "AIF1RX5",
327 "AIF1RX6",
328 "AIF1RX7",
329 "AIF1RX8",
330 "AIF2RX1",
331 "AIF2RX2",
Richard Fitzgeralde64001e2013-11-20 13:17:07 +0000332 "AIF2RX3",
333 "AIF2RX4",
334 "AIF2RX5",
335 "AIF2RX6",
Mark Brown07ed8732012-06-18 21:08:44 +0100336 "AIF3RX1",
337 "AIF3RX2",
338 "SLIMRX1",
339 "SLIMRX2",
340 "SLIMRX3",
341 "SLIMRX4",
342 "SLIMRX5",
343 "SLIMRX6",
344 "SLIMRX7",
345 "SLIMRX8",
346 "EQ1",
347 "EQ2",
348 "EQ3",
349 "EQ4",
350 "DRC1L",
351 "DRC1R",
352 "DRC2L",
353 "DRC2R",
354 "LHPF1",
355 "LHPF2",
356 "LHPF3",
357 "LHPF4",
358 "DSP1.1",
359 "DSP1.2",
360 "DSP1.3",
361 "DSP1.4",
362 "DSP1.5",
363 "DSP1.6",
Mark Brownc922cc42012-09-26 16:43:44 +0100364 "DSP2.1",
365 "DSP2.2",
366 "DSP2.3",
367 "DSP2.4",
368 "DSP2.5",
369 "DSP2.6",
370 "DSP3.1",
371 "DSP3.2",
372 "DSP3.3",
373 "DSP3.4",
374 "DSP3.5",
375 "DSP3.6",
376 "DSP4.1",
377 "DSP4.2",
378 "DSP4.3",
379 "DSP4.4",
380 "DSP4.5",
381 "DSP4.6",
Mark Brown07ed8732012-06-18 21:08:44 +0100382 "ASRC1L",
383 "ASRC1R",
384 "ASRC2L",
385 "ASRC2R",
Mark Brown91660bd2012-12-05 20:35:24 +0900386 "ISRC1INT1",
387 "ISRC1INT2",
388 "ISRC1INT3",
389 "ISRC1INT4",
390 "ISRC1DEC1",
391 "ISRC1DEC2",
392 "ISRC1DEC3",
393 "ISRC1DEC4",
394 "ISRC2INT1",
395 "ISRC2INT2",
396 "ISRC2INT3",
397 "ISRC2INT4",
398 "ISRC2DEC1",
399 "ISRC2DEC2",
400 "ISRC2DEC3",
401 "ISRC2DEC4",
402 "ISRC3INT1",
403 "ISRC3INT2",
404 "ISRC3INT3",
405 "ISRC3INT4",
406 "ISRC3DEC1",
407 "ISRC3DEC2",
408 "ISRC3DEC3",
409 "ISRC3DEC4",
Mark Brown07ed8732012-06-18 21:08:44 +0100410};
411EXPORT_SYMBOL_GPL(arizona_mixer_texts);
412
413int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
414 0x00, /* None */
415 0x04, /* Tone */
416 0x05,
417 0x06, /* Haptics */
418 0x08, /* AEC */
419 0x0c, /* Noise mixer */
420 0x0d, /* Comfort noise */
421 0x10, /* IN1L */
422 0x11,
423 0x12,
424 0x13,
425 0x14,
426 0x15,
Mark Brownc9c56fd2012-07-09 19:09:01 +0100427 0x16,
428 0x17,
Mark Brown07ed8732012-06-18 21:08:44 +0100429 0x20, /* AIF1RX1 */
430 0x21,
431 0x22,
432 0x23,
433 0x24,
434 0x25,
435 0x26,
436 0x27,
437 0x28, /* AIF2RX1 */
438 0x29,
Richard Fitzgeralde64001e2013-11-20 13:17:07 +0000439 0x2a,
440 0x2b,
441 0x2c,
442 0x2d,
Mark Brown07ed8732012-06-18 21:08:44 +0100443 0x30, /* AIF3RX1 */
444 0x31,
445 0x38, /* SLIMRX1 */
446 0x39,
447 0x3a,
448 0x3b,
449 0x3c,
450 0x3d,
451 0x3e,
452 0x3f,
453 0x50, /* EQ1 */
454 0x51,
455 0x52,
456 0x53,
457 0x58, /* DRC1L */
458 0x59,
459 0x5a,
460 0x5b,
461 0x60, /* LHPF1 */
462 0x61,
463 0x62,
464 0x63,
465 0x68, /* DSP1.1 */
466 0x69,
467 0x6a,
468 0x6b,
469 0x6c,
470 0x6d,
Mark Brownc922cc42012-09-26 16:43:44 +0100471 0x70, /* DSP2.1 */
472 0x71,
473 0x72,
474 0x73,
475 0x74,
476 0x75,
477 0x78, /* DSP3.1 */
478 0x79,
479 0x7a,
480 0x7b,
481 0x7c,
482 0x7d,
483 0x80, /* DSP4.1 */
484 0x81,
485 0x82,
486 0x83,
487 0x84,
488 0x85,
Mark Brown07ed8732012-06-18 21:08:44 +0100489 0x90, /* ASRC1L */
490 0x91,
491 0x92,
492 0x93,
Mark Brown91660bd2012-12-05 20:35:24 +0900493 0xa0, /* ISRC1INT1 */
494 0xa1,
495 0xa2,
496 0xa3,
497 0xa4, /* ISRC1DEC1 */
498 0xa5,
499 0xa6,
500 0xa7,
501 0xa8, /* ISRC2DEC1 */
502 0xa9,
503 0xaa,
504 0xab,
505 0xac, /* ISRC2INT1 */
506 0xad,
507 0xae,
508 0xaf,
509 0xb0, /* ISRC3DEC1 */
510 0xb1,
511 0xb2,
512 0xb3,
513 0xb4, /* ISRC3INT1 */
514 0xb5,
515 0xb6,
516 0xb7,
Mark Brown07ed8732012-06-18 21:08:44 +0100517};
518EXPORT_SYMBOL_GPL(arizona_mixer_values);
519
520const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
521EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
522
Mark Browndc914282013-02-18 19:09:23 +0000523const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = {
524 "SYNCCLK rate", "8kHz", "16kHz", "ASYNCCLK rate",
525};
526EXPORT_SYMBOL_GPL(arizona_rate_text);
527
528const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
529 0, 1, 2, 8,
530};
531EXPORT_SYMBOL_GPL(arizona_rate_val);
532
533
Charles Keepaxfbedc8c2013-12-19 09:30:12 +0000534const struct soc_enum arizona_isrc_fsh[] = {
535 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_1,
536 ARIZONA_ISRC1_FSH_SHIFT, 0xf,
537 ARIZONA_RATE_ENUM_SIZE,
538 arizona_rate_text, arizona_rate_val),
539 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_1,
540 ARIZONA_ISRC2_FSH_SHIFT, 0xf,
541 ARIZONA_RATE_ENUM_SIZE,
542 arizona_rate_text, arizona_rate_val),
543 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_1,
544 ARIZONA_ISRC3_FSH_SHIFT, 0xf,
545 ARIZONA_RATE_ENUM_SIZE,
546 arizona_rate_text, arizona_rate_val),
547};
548EXPORT_SYMBOL_GPL(arizona_isrc_fsh);
549
Mark Browndc914282013-02-18 19:09:23 +0000550const struct soc_enum arizona_isrc_fsl[] = {
551 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2,
552 ARIZONA_ISRC1_FSL_SHIFT, 0xf,
553 ARIZONA_RATE_ENUM_SIZE,
554 arizona_rate_text, arizona_rate_val),
555 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_2,
556 ARIZONA_ISRC2_FSL_SHIFT, 0xf,
557 ARIZONA_RATE_ENUM_SIZE,
558 arizona_rate_text, arizona_rate_val),
559 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_2,
560 ARIZONA_ISRC3_FSL_SHIFT, 0xf,
561 ARIZONA_RATE_ENUM_SIZE,
562 arizona_rate_text, arizona_rate_val),
563};
564EXPORT_SYMBOL_GPL(arizona_isrc_fsl);
565
Charles Keepax56d37d82013-12-19 09:30:13 +0000566const struct soc_enum arizona_asrc_rate1 =
567 SOC_VALUE_ENUM_SINGLE(ARIZONA_ASRC_RATE1,
568 ARIZONA_ASRC_RATE1_SHIFT, 0xf,
569 ARIZONA_RATE_ENUM_SIZE - 1,
570 arizona_rate_text, arizona_rate_val);
571EXPORT_SYMBOL_GPL(arizona_asrc_rate1);
572
Mark Browne853a002012-12-09 12:25:52 +0900573static const char *arizona_vol_ramp_text[] = {
574 "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
575 "15ms/6dB", "30ms/6dB",
576};
577
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100578SOC_ENUM_SINGLE_DECL(arizona_in_vd_ramp,
579 ARIZONA_INPUT_VOLUME_RAMP,
580 ARIZONA_IN_VD_RAMP_SHIFT,
581 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900582EXPORT_SYMBOL_GPL(arizona_in_vd_ramp);
583
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100584SOC_ENUM_SINGLE_DECL(arizona_in_vi_ramp,
585 ARIZONA_INPUT_VOLUME_RAMP,
586 ARIZONA_IN_VI_RAMP_SHIFT,
587 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900588EXPORT_SYMBOL_GPL(arizona_in_vi_ramp);
589
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100590SOC_ENUM_SINGLE_DECL(arizona_out_vd_ramp,
591 ARIZONA_OUTPUT_VOLUME_RAMP,
592 ARIZONA_OUT_VD_RAMP_SHIFT,
593 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900594EXPORT_SYMBOL_GPL(arizona_out_vd_ramp);
595
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100596SOC_ENUM_SINGLE_DECL(arizona_out_vi_ramp,
597 ARIZONA_OUTPUT_VOLUME_RAMP,
598 ARIZONA_OUT_VI_RAMP_SHIFT,
599 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900600EXPORT_SYMBOL_GPL(arizona_out_vi_ramp);
601
Mark Brown07ed8732012-06-18 21:08:44 +0100602static const char *arizona_lhpf_mode_text[] = {
603 "Low-pass", "High-pass"
604};
605
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100606SOC_ENUM_SINGLE_DECL(arizona_lhpf1_mode,
607 ARIZONA_HPLPF1_1,
608 ARIZONA_LHPF1_MODE_SHIFT,
609 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100610EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
611
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100612SOC_ENUM_SINGLE_DECL(arizona_lhpf2_mode,
613 ARIZONA_HPLPF2_1,
614 ARIZONA_LHPF2_MODE_SHIFT,
615 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100616EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
617
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100618SOC_ENUM_SINGLE_DECL(arizona_lhpf3_mode,
619 ARIZONA_HPLPF3_1,
620 ARIZONA_LHPF3_MODE_SHIFT,
621 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100622EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
623
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100624SOC_ENUM_SINGLE_DECL(arizona_lhpf4_mode,
625 ARIZONA_HPLPF4_1,
626 ARIZONA_LHPF4_MODE_SHIFT,
627 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100628EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
629
Mark Brown845571c2012-12-18 13:47:57 +0000630static const char *arizona_ng_hold_text[] = {
631 "30ms", "120ms", "250ms", "500ms",
632};
633
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100634SOC_ENUM_SINGLE_DECL(arizona_ng_hold,
635 ARIZONA_NOISE_GATE_CONTROL,
636 ARIZONA_NGATE_HOLD_SHIFT,
637 arizona_ng_hold_text);
Mark Brown845571c2012-12-18 13:47:57 +0000638EXPORT_SYMBOL_GPL(arizona_ng_hold);
639
Charles Keepax254dc322013-11-19 16:04:03 +0000640static const char * const arizona_in_hpf_cut_text[] = {
641 "2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz"
642};
643
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100644SOC_ENUM_SINGLE_DECL(arizona_in_hpf_cut_enum,
645 ARIZONA_HPF_CONTROL,
646 ARIZONA_IN_HPF_CUT_SHIFT,
647 arizona_in_hpf_cut_text);
Charles Keepax254dc322013-11-19 16:04:03 +0000648EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum);
649
Charles Keepaxc7f38432013-08-06 17:03:55 +0100650static const char * const arizona_in_dmic_osr_text[] = {
651 "1.536MHz", "3.072MHz", "6.144MHz",
652};
653
654const struct soc_enum arizona_in_dmic_osr[] = {
655 SOC_ENUM_SINGLE(ARIZONA_IN1L_CONTROL, ARIZONA_IN1_OSR_SHIFT,
656 ARRAY_SIZE(arizona_in_dmic_osr_text),
657 arizona_in_dmic_osr_text),
658 SOC_ENUM_SINGLE(ARIZONA_IN2L_CONTROL, ARIZONA_IN2_OSR_SHIFT,
659 ARRAY_SIZE(arizona_in_dmic_osr_text),
660 arizona_in_dmic_osr_text),
661 SOC_ENUM_SINGLE(ARIZONA_IN3L_CONTROL, ARIZONA_IN3_OSR_SHIFT,
662 ARRAY_SIZE(arizona_in_dmic_osr_text),
663 arizona_in_dmic_osr_text),
664 SOC_ENUM_SINGLE(ARIZONA_IN4L_CONTROL, ARIZONA_IN4_OSR_SHIFT,
665 ARRAY_SIZE(arizona_in_dmic_osr_text),
666 arizona_in_dmic_osr_text),
667};
668EXPORT_SYMBOL_GPL(arizona_in_dmic_osr);
669
Mark Brownddbce972013-02-15 17:27:22 +0000670static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
671{
672 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
673 unsigned int val;
674 int i;
675
676 if (ena)
677 val = ARIZONA_IN_VU;
678 else
679 val = 0;
680
681 for (i = 0; i < priv->num_inputs; i++)
682 snd_soc_update_bits(codec,
683 ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 4),
684 ARIZONA_IN_VU, val);
685}
686
Mark Brown07ed8732012-06-18 21:08:44 +0100687int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
688 int event)
689{
Mark Brownddbce972013-02-15 17:27:22 +0000690 struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000691 unsigned int reg;
692
693 if (w->shift % 2)
694 reg = ARIZONA_ADC_DIGITAL_VOLUME_1L + ((w->shift / 2) * 8);
695 else
696 reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8);
697
698 switch (event) {
Mark Brownddbce972013-02-15 17:27:22 +0000699 case SND_SOC_DAPM_PRE_PMU:
700 priv->in_pending++;
701 break;
Mark Brown43cd8bf2013-02-06 16:57:29 +0000702 case SND_SOC_DAPM_POST_PMU:
703 snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, 0);
Mark Brownddbce972013-02-15 17:27:22 +0000704
705 /* If this is the last input pending then allow VU */
706 priv->in_pending--;
707 if (priv->in_pending == 0) {
708 msleep(1);
709 arizona_in_set_vu(w->codec, 1);
710 }
Mark Brown43cd8bf2013-02-06 16:57:29 +0000711 break;
712 case SND_SOC_DAPM_PRE_PMD:
Mark Brownddbce972013-02-15 17:27:22 +0000713 snd_soc_update_bits(w->codec, reg,
714 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU,
715 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000716 break;
Mark Brownddbce972013-02-15 17:27:22 +0000717 case SND_SOC_DAPM_POST_PMD:
718 /* Disable volume updates if no inputs are enabled */
719 reg = snd_soc_read(w->codec, ARIZONA_INPUT_ENABLES);
720 if (reg == 0)
721 arizona_in_set_vu(w->codec, 0);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000722 }
723
Mark Brown07ed8732012-06-18 21:08:44 +0100724 return 0;
725}
726EXPORT_SYMBOL_GPL(arizona_in_ev);
727
728int arizona_out_ev(struct snd_soc_dapm_widget *w,
729 struct snd_kcontrol *kcontrol,
730 int event)
731{
Mark Brown1a2c7d52013-03-24 22:50:23 +0000732 switch (event) {
733 case SND_SOC_DAPM_POST_PMU:
734 switch (w->shift) {
735 case ARIZONA_OUT1L_ENA_SHIFT:
736 case ARIZONA_OUT1R_ENA_SHIFT:
737 case ARIZONA_OUT2L_ENA_SHIFT:
738 case ARIZONA_OUT2R_ENA_SHIFT:
739 case ARIZONA_OUT3L_ENA_SHIFT:
740 case ARIZONA_OUT3R_ENA_SHIFT:
741 msleep(17);
742 break;
743
744 default:
745 break;
746 }
747 break;
748 }
749
Mark Brown07ed8732012-06-18 21:08:44 +0100750 return 0;
751}
752EXPORT_SYMBOL_GPL(arizona_out_ev);
753
Mark Brownf607e312013-02-22 18:36:53 +0000754int arizona_hp_ev(struct snd_soc_dapm_widget *w,
755 struct snd_kcontrol *kcontrol,
756 int event)
757{
758 struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
Mark Brown3c43c692013-12-12 00:49:22 +0000759 struct arizona *arizona = priv->arizona;
Mark Brownf607e312013-02-22 18:36:53 +0000760 unsigned int mask = 1 << w->shift;
761 unsigned int val;
762
763 switch (event) {
764 case SND_SOC_DAPM_POST_PMU:
765 val = mask;
766 break;
767 case SND_SOC_DAPM_PRE_PMD:
768 val = 0;
769 break;
770 default:
771 return -EINVAL;
772 }
773
774 /* Store the desired state for the HP outputs */
775 priv->arizona->hp_ena &= ~mask;
776 priv->arizona->hp_ena |= val;
777
778 /* Force off if HPDET magic is active */
779 if (priv->arizona->hpdet_magic)
780 val = 0;
781
Mark Brown3c43c692013-12-12 00:49:22 +0000782 regmap_update_bits_async(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1,
783 mask, val);
Mark Brownf607e312013-02-22 18:36:53 +0000784
785 return arizona_out_ev(w, kcontrol, event);
786}
787EXPORT_SYMBOL_GPL(arizona_hp_ev);
788
Mark Browncbd840d2012-08-08 17:52:44 +0100789static unsigned int arizona_sysclk_48k_rates[] = {
790 6144000,
791 12288000,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000792 24576000,
Mark Browncbd840d2012-08-08 17:52:44 +0100793 49152000,
Mark Brownaeaeee12012-09-26 17:50:02 +0100794 73728000,
795 98304000,
796 147456000,
Mark Browncbd840d2012-08-08 17:52:44 +0100797};
798
799static unsigned int arizona_sysclk_44k1_rates[] = {
800 5644800,
801 11289600,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000802 22579200,
Mark Browncbd840d2012-08-08 17:52:44 +0100803 45158400,
Mark Brownaeaeee12012-09-26 17:50:02 +0100804 67737600,
805 90316800,
806 135475200,
Mark Browncbd840d2012-08-08 17:52:44 +0100807};
808
809static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
810 unsigned int freq)
811{
812 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
813 unsigned int reg;
814 unsigned int *rates;
815 int ref, div, refclk;
816
817 switch (clk) {
818 case ARIZONA_CLK_OPCLK:
819 reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
820 refclk = priv->sysclk;
821 break;
822 case ARIZONA_CLK_ASYNC_OPCLK:
823 reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
824 refclk = priv->asyncclk;
825 break;
826 default:
827 return -EINVAL;
828 }
829
830 if (refclk % 8000)
831 rates = arizona_sysclk_44k1_rates;
832 else
833 rates = arizona_sysclk_48k_rates;
834
835 for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) &&
836 rates[ref] <= refclk; ref++) {
837 div = 1;
838 while (rates[ref] / div >= freq && div < 32) {
839 if (rates[ref] / div == freq) {
840 dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
841 freq);
842 snd_soc_update_bits(codec, reg,
843 ARIZONA_OPCLK_DIV_MASK |
844 ARIZONA_OPCLK_SEL_MASK,
845 (div <<
846 ARIZONA_OPCLK_DIV_SHIFT) |
847 ref);
848 return 0;
849 }
850 div++;
851 }
852 }
853
854 dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
855 return -EINVAL;
856}
857
Mark Brown07ed8732012-06-18 21:08:44 +0100858int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
859 int source, unsigned int freq, int dir)
860{
861 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
862 struct arizona *arizona = priv->arizona;
863 char *name;
864 unsigned int reg;
865 unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
866 unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
867 unsigned int *clk;
868
869 switch (clk_id) {
870 case ARIZONA_CLK_SYSCLK:
871 name = "SYSCLK";
872 reg = ARIZONA_SYSTEM_CLOCK_1;
873 clk = &priv->sysclk;
874 mask |= ARIZONA_SYSCLK_FRAC;
875 break;
876 case ARIZONA_CLK_ASYNCCLK:
877 name = "ASYNCCLK";
878 reg = ARIZONA_ASYNC_CLOCK_1;
879 clk = &priv->asyncclk;
880 break;
Mark Browncbd840d2012-08-08 17:52:44 +0100881 case ARIZONA_CLK_OPCLK:
882 case ARIZONA_CLK_ASYNC_OPCLK:
883 return arizona_set_opclk(codec, clk_id, freq);
Mark Brown07ed8732012-06-18 21:08:44 +0100884 default:
885 return -EINVAL;
886 }
887
888 switch (freq) {
889 case 5644800:
890 case 6144000:
891 break;
892 case 11289600:
893 case 12288000:
Mark Brown3f341f72013-03-08 15:22:29 +0800894 val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100895 break;
896 case 22579200:
897 case 24576000:
Mark Brown3f341f72013-03-08 15:22:29 +0800898 val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100899 break;
900 case 45158400:
901 case 49152000:
Mark Brown3f341f72013-03-08 15:22:29 +0800902 val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100903 break;
Mark Brown38113362012-11-26 16:01:37 +0000904 case 67737600:
905 case 73728000:
Mark Brown3f341f72013-03-08 15:22:29 +0800906 val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000907 break;
908 case 90316800:
909 case 98304000:
Mark Brown3f341f72013-03-08 15:22:29 +0800910 val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000911 break;
912 case 135475200:
913 case 147456000:
Mark Brown3f341f72013-03-08 15:22:29 +0800914 val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000915 break;
Mark Brownf2c26d42013-01-21 16:09:36 +0900916 case 0:
917 dev_dbg(arizona->dev, "%s cleared\n", name);
918 *clk = freq;
919 return 0;
Mark Brown07ed8732012-06-18 21:08:44 +0100920 default:
921 return -EINVAL;
922 }
923
924 *clk = freq;
925
926 if (freq % 6144000)
927 val |= ARIZONA_SYSCLK_FRAC;
928
929 dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
930
931 return regmap_update_bits(arizona->regmap, reg, mask, val);
932}
933EXPORT_SYMBOL_GPL(arizona_set_sysclk);
934
935static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
936{
937 struct snd_soc_codec *codec = dai->codec;
Mark Brown3c43c692013-12-12 00:49:22 +0000938 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
939 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +0100940 int lrclk, bclk, mode, base;
941
942 base = dai->driver->base;
943
944 lrclk = 0;
945 bclk = 0;
946
947 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
948 case SND_SOC_DAIFMT_DSP_A:
949 mode = 0;
950 break;
Mark Brown07ed8732012-06-18 21:08:44 +0100951 case SND_SOC_DAIFMT_I2S:
952 mode = 2;
953 break;
Mark Brown07ed8732012-06-18 21:08:44 +0100954 default:
955 arizona_aif_err(dai, "Unsupported DAI format %d\n",
956 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
957 return -EINVAL;
958 }
959
960 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
961 case SND_SOC_DAIFMT_CBS_CFS:
962 break;
963 case SND_SOC_DAIFMT_CBS_CFM:
964 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
965 break;
966 case SND_SOC_DAIFMT_CBM_CFS:
967 bclk |= ARIZONA_AIF1_BCLK_MSTR;
968 break;
969 case SND_SOC_DAIFMT_CBM_CFM:
970 bclk |= ARIZONA_AIF1_BCLK_MSTR;
971 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
972 break;
973 default:
974 arizona_aif_err(dai, "Unsupported master mode %d\n",
975 fmt & SND_SOC_DAIFMT_MASTER_MASK);
976 return -EINVAL;
977 }
978
979 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
980 case SND_SOC_DAIFMT_NB_NF:
981 break;
982 case SND_SOC_DAIFMT_IB_IF:
983 bclk |= ARIZONA_AIF1_BCLK_INV;
984 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
985 break;
986 case SND_SOC_DAIFMT_IB_NF:
987 bclk |= ARIZONA_AIF1_BCLK_INV;
988 break;
989 case SND_SOC_DAIFMT_NB_IF:
990 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
991 break;
992 default:
993 return -EINVAL;
994 }
995
Mark Brown3c43c692013-12-12 00:49:22 +0000996 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_BCLK_CTRL,
997 ARIZONA_AIF1_BCLK_INV |
998 ARIZONA_AIF1_BCLK_MSTR,
999 bclk);
1000 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_TX_PIN_CTRL,
1001 ARIZONA_AIF1TX_LRCLK_INV |
1002 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
1003 regmap_update_bits_async(arizona->regmap,
1004 base + ARIZONA_AIF_RX_PIN_CTRL,
1005 ARIZONA_AIF1RX_LRCLK_INV |
1006 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
1007 regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FORMAT,
1008 ARIZONA_AIF1_FMT_MASK, mode);
Mark Brown07ed8732012-06-18 21:08:44 +01001009
1010 return 0;
1011}
1012
Mark Brown949e6bc2012-07-04 18:58:04 +01001013static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001014 -1,
1015 48000,
1016 64000,
1017 96000,
1018 128000,
1019 192000,
1020 256000,
1021 384000,
1022 512000,
1023 768000,
1024 1024000,
1025 1536000,
1026 2048000,
1027 3072000,
1028 4096000,
1029 6144000,
1030 8192000,
1031 12288000,
1032 24576000,
1033};
1034
Mark Brown5b2eec32012-07-04 17:32:05 +01001035static const unsigned int arizona_48k_rates[] = {
1036 12000,
1037 24000,
1038 48000,
1039 96000,
1040 192000,
1041 384000,
1042 768000,
1043 4000,
1044 8000,
1045 16000,
1046 32000,
1047 64000,
1048 128000,
1049 256000,
1050 512000,
1051};
1052
1053static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = {
1054 .count = ARRAY_SIZE(arizona_48k_rates),
1055 .list = arizona_48k_rates,
1056};
1057
Mark Brown949e6bc2012-07-04 18:58:04 +01001058static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001059 -1,
1060 44100,
1061 58800,
1062 88200,
1063 117600,
1064 177640,
1065 235200,
1066 352800,
1067 470400,
1068 705600,
1069 940800,
1070 1411200,
1071 1881600,
Heather Lomond4758be32012-09-05 05:02:10 -04001072 2822400,
Mark Brown07ed8732012-06-18 21:08:44 +01001073 3763200,
1074 5644800,
1075 7526400,
1076 11289600,
1077 22579200,
1078};
1079
Mark Brown5b2eec32012-07-04 17:32:05 +01001080static const unsigned int arizona_44k1_rates[] = {
1081 11025,
1082 22050,
1083 44100,
1084 88200,
1085 176400,
1086 352800,
1087 705600,
1088};
1089
1090static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = {
1091 .count = ARRAY_SIZE(arizona_44k1_rates),
1092 .list = arizona_44k1_rates,
1093};
1094
Mark Brown07ed8732012-06-18 21:08:44 +01001095static int arizona_sr_vals[] = {
1096 0,
1097 12000,
1098 24000,
1099 48000,
1100 96000,
1101 192000,
1102 384000,
1103 768000,
1104 0,
1105 11025,
1106 22050,
1107 44100,
1108 88200,
1109 176400,
1110 352800,
1111 705600,
1112 4000,
1113 8000,
1114 16000,
1115 32000,
1116 64000,
1117 128000,
1118 256000,
1119 512000,
1120};
1121
Mark Brown5b2eec32012-07-04 17:32:05 +01001122static int arizona_startup(struct snd_pcm_substream *substream,
1123 struct snd_soc_dai *dai)
1124{
1125 struct snd_soc_codec *codec = dai->codec;
1126 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1127 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
1128 const struct snd_pcm_hw_constraint_list *constraint;
1129 unsigned int base_rate;
1130
1131 switch (dai_priv->clk) {
1132 case ARIZONA_CLK_SYSCLK:
1133 base_rate = priv->sysclk;
1134 break;
1135 case ARIZONA_CLK_ASYNCCLK:
1136 base_rate = priv->asyncclk;
1137 break;
1138 default:
1139 return 0;
1140 }
1141
Mark Brownf2c26d42013-01-21 16:09:36 +09001142 if (base_rate == 0)
1143 return 0;
1144
Mark Brown5b2eec32012-07-04 17:32:05 +01001145 if (base_rate % 8000)
1146 constraint = &arizona_44k1_constraint;
1147 else
1148 constraint = &arizona_48k_constraint;
1149
1150 return snd_pcm_hw_constraint_list(substream->runtime, 0,
1151 SNDRV_PCM_HW_PARAM_RATE,
1152 constraint);
1153}
1154
Mark Brownb272efc2012-10-10 15:10:08 +09001155static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
1156 struct snd_pcm_hw_params *params,
1157 struct snd_soc_dai *dai)
Mark Brown07ed8732012-06-18 21:08:44 +01001158{
1159 struct snd_soc_codec *codec = dai->codec;
Mark Brownc013b272012-07-04 20:05:57 +01001160 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1161 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown07ed8732012-06-18 21:08:44 +01001162 int base = dai->driver->base;
Mark Brownb272efc2012-10-10 15:10:08 +09001163 int i, sr_val;
1164
1165 /*
1166 * We will need to be more flexible than this in future,
1167 * currently we use a single sample rate for SYSCLK.
1168 */
1169 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
1170 if (arizona_sr_vals[i] == params_rate(params))
1171 break;
1172 if (i == ARRAY_SIZE(arizona_sr_vals)) {
1173 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1174 params_rate(params));
1175 return -EINVAL;
1176 }
1177 sr_val = i;
1178
1179 switch (dai_priv->clk) {
1180 case ARIZONA_CLK_SYSCLK:
1181 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
1182 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
1183 if (base)
1184 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1185 ARIZONA_AIF1_RATE_MASK, 0);
1186 break;
1187 case ARIZONA_CLK_ASYNCCLK:
1188 snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
1189 ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val);
1190 if (base)
1191 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1192 ARIZONA_AIF1_RATE_MASK,
1193 8 << ARIZONA_AIF1_RATE_SHIFT);
1194 break;
1195 default:
1196 arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
1197 return -EINVAL;
1198 }
1199
1200 return 0;
1201}
1202
Mark Brown07ed8732012-06-18 21:08:44 +01001203static int arizona_hw_params(struct snd_pcm_substream *substream,
1204 struct snd_pcm_hw_params *params,
1205 struct snd_soc_dai *dai)
1206{
1207 struct snd_soc_codec *codec = dai->codec;
1208 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brownc94aa302013-01-17 16:35:14 +09001209 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +01001210 int base = dai->driver->base;
1211 const int *rates;
Mark Brown76bf9692013-03-05 14:17:47 +08001212 int i, ret, val;
Mark Brownc94aa302013-01-17 16:35:14 +09001213 int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
1214 int bclk, lrclk, wl, frame, bclk_target;
Mark Brown07ed8732012-06-18 21:08:44 +01001215
1216 if (params_rate(params) % 8000)
Mark Brown949e6bc2012-07-04 18:58:04 +01001217 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001218 else
Mark Brown949e6bc2012-07-04 18:58:04 +01001219 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001220
Mark Brownc94aa302013-01-17 16:35:14 +09001221 bclk_target = snd_soc_params_to_bclk(params);
1222 if (chan_limit && chan_limit < params_channels(params)) {
1223 arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
1224 bclk_target /= params_channels(params);
1225 bclk_target *= chan_limit;
1226 }
1227
Mark Brown76bf9692013-03-05 14:17:47 +08001228 /* Force stereo for I2S mode */
1229 val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
1230 if (params_channels(params) == 1 && (val & ARIZONA_AIF1_FMT_MASK)) {
1231 arizona_aif_dbg(dai, "Forcing stereo mode\n");
1232 bclk_target *= 2;
1233 }
1234
Mark Brown949e6bc2012-07-04 18:58:04 +01001235 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brownc94aa302013-01-17 16:35:14 +09001236 if (rates[i] >= bclk_target &&
Mark Brown50017652012-07-04 19:07:09 +01001237 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +01001238 bclk = i;
1239 break;
1240 }
1241 }
Mark Brown949e6bc2012-07-04 18:58:04 +01001242 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001243 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1244 params_rate(params));
1245 return -EINVAL;
1246 }
1247
Mark Brownb59e0f82013-01-17 14:15:59 +09001248 lrclk = rates[bclk] / params_rate(params);
Mark Brown07ed8732012-06-18 21:08:44 +01001249
1250 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
1251 rates[bclk], rates[bclk] / lrclk);
1252
1253 wl = snd_pcm_format_width(params_format(params));
1254 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl;
1255
Mark Brownb272efc2012-10-10 15:10:08 +09001256 ret = arizona_hw_params_rate(substream, params, dai);
1257 if (ret != 0)
1258 return ret;
Mark Brownc013b272012-07-04 20:05:57 +01001259
Mark Brown3c43c692013-12-12 00:49:22 +00001260 regmap_update_bits_async(arizona->regmap,
1261 base + ARIZONA_AIF_BCLK_CTRL,
1262 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
1263 regmap_update_bits_async(arizona->regmap,
1264 base + ARIZONA_AIF_TX_BCLK_RATE,
1265 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
1266 regmap_update_bits_async(arizona->regmap,
1267 base + ARIZONA_AIF_RX_BCLK_RATE,
1268 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
1269 regmap_update_bits_async(arizona->regmap,
1270 base + ARIZONA_AIF_FRAME_CTRL_1,
1271 ARIZONA_AIF1TX_WL_MASK |
1272 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
1273 regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FRAME_CTRL_2,
1274 ARIZONA_AIF1RX_WL_MASK |
1275 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
Mark Brown07ed8732012-06-18 21:08:44 +01001276
1277 return 0;
1278}
1279
Mark Brown410837a2012-07-05 17:26:59 +01001280static const char *arizona_dai_clk_str(int clk_id)
1281{
1282 switch (clk_id) {
1283 case ARIZONA_CLK_SYSCLK:
1284 return "SYSCLK";
1285 case ARIZONA_CLK_ASYNCCLK:
1286 return "ASYNCCLK";
1287 default:
1288 return "Unknown clock";
1289 }
1290}
1291
Mark Brown5b2eec32012-07-04 17:32:05 +01001292static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
1293 int clk_id, unsigned int freq, int dir)
1294{
1295 struct snd_soc_codec *codec = dai->codec;
1296 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1297 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown410837a2012-07-05 17:26:59 +01001298 struct snd_soc_dapm_route routes[2];
Mark Brown5b2eec32012-07-04 17:32:05 +01001299
1300 switch (clk_id) {
1301 case ARIZONA_CLK_SYSCLK:
1302 case ARIZONA_CLK_ASYNCCLK:
1303 break;
1304 default:
1305 return -EINVAL;
1306 }
1307
Mark Brown410837a2012-07-05 17:26:59 +01001308 if (clk_id == dai_priv->clk)
1309 return 0;
1310
1311 if (dai->active) {
Mark Brown5b2eec32012-07-04 17:32:05 +01001312 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
1313 dai->id);
1314 return -EBUSY;
1315 }
1316
Mark Brownc8d35a62012-12-07 12:49:40 +09001317 dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1,
1318 arizona_dai_clk_str(clk_id));
1319
Mark Brown410837a2012-07-05 17:26:59 +01001320 memset(&routes, 0, sizeof(routes));
1321 routes[0].sink = dai->driver->capture.stream_name;
1322 routes[1].sink = dai->driver->playback.stream_name;
Mark Brown5b2eec32012-07-04 17:32:05 +01001323
Mark Brown410837a2012-07-05 17:26:59 +01001324 routes[0].source = arizona_dai_clk_str(dai_priv->clk);
1325 routes[1].source = arizona_dai_clk_str(dai_priv->clk);
1326 snd_soc_dapm_del_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
1327
1328 routes[0].source = arizona_dai_clk_str(clk_id);
1329 routes[1].source = arizona_dai_clk_str(clk_id);
1330 snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
1331
Mark Brown0c778e82012-12-06 18:22:25 +09001332 dai_priv->clk = clk_id;
1333
Mark Brown410837a2012-07-05 17:26:59 +01001334 return snd_soc_dapm_sync(&codec->dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +01001335}
1336
Mark Brown01df2592012-12-12 16:22:08 +09001337static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
1338{
1339 struct snd_soc_codec *codec = dai->codec;
1340 int base = dai->driver->base;
1341 unsigned int reg;
1342
1343 if (tristate)
1344 reg = ARIZONA_AIF1_TRI;
1345 else
1346 reg = 0;
1347
1348 return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1349 ARIZONA_AIF1_TRI, reg);
1350}
1351
Mark Brown07ed8732012-06-18 21:08:44 +01001352const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +01001353 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +01001354 .set_fmt = arizona_set_fmt,
1355 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +01001356 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown01df2592012-12-12 16:22:08 +09001357 .set_tristate = arizona_set_tristate,
Mark Brown07ed8732012-06-18 21:08:44 +01001358};
Mark Browna8379872012-07-09 12:16:41 +01001359EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +01001360
Mark Brownbd1dd882013-05-17 13:29:03 +01001361const struct snd_soc_dai_ops arizona_simple_dai_ops = {
1362 .startup = arizona_startup,
1363 .hw_params = arizona_hw_params_rate,
1364 .set_sysclk = arizona_dai_set_sysclk,
1365};
1366EXPORT_SYMBOL_GPL(arizona_simple_dai_ops);
1367
Mark Brown5b2eec32012-07-04 17:32:05 +01001368int arizona_init_dai(struct arizona_priv *priv, int id)
1369{
1370 struct arizona_dai_priv *dai_priv = &priv->dai[id];
1371
1372 dai_priv->clk = ARIZONA_CLK_SYSCLK;
1373
1374 return 0;
1375}
1376EXPORT_SYMBOL_GPL(arizona_init_dai);
1377
Mark Brown07ed8732012-06-18 21:08:44 +01001378static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
1379{
1380 struct arizona_fll *fll = data;
1381
1382 arizona_fll_dbg(fll, "clock OK\n");
1383
1384 complete(&fll->ok);
1385
1386 return IRQ_HANDLED;
1387}
1388
1389static struct {
1390 unsigned int min;
1391 unsigned int max;
1392 u16 fratio;
1393 int ratio;
1394} fll_fratios[] = {
1395 { 0, 64000, 4, 16 },
1396 { 64000, 128000, 3, 8 },
1397 { 128000, 256000, 2, 4 },
1398 { 256000, 1000000, 1, 2 },
1399 { 1000000, 13500000, 0, 1 },
1400};
1401
Mark Brown8f113d72013-03-05 12:08:57 +08001402static struct {
1403 unsigned int min;
1404 unsigned int max;
1405 u16 gain;
1406} fll_gains[] = {
1407 { 0, 256000, 0 },
1408 { 256000, 1000000, 2 },
1409 { 1000000, 13500000, 4 },
1410};
1411
Mark Brown07ed8732012-06-18 21:08:44 +01001412struct arizona_fll_cfg {
1413 int n;
1414 int theta;
1415 int lambda;
1416 int refdiv;
1417 int outdiv;
1418 int fratio;
Mark Brown8f113d72013-03-05 12:08:57 +08001419 int gain;
Mark Brown07ed8732012-06-18 21:08:44 +01001420};
1421
Charles Keepax23f785a82014-03-07 16:34:20 +00001422static int arizona_validate_fll(struct arizona_fll *fll,
1423 unsigned int Fref,
1424 unsigned int Fout)
1425{
1426 unsigned int Fvco_min;
1427
1428 if (Fref / ARIZONA_FLL_MAX_REFDIV > ARIZONA_FLL_MAX_FREF) {
1429 arizona_fll_err(fll,
1430 "Can't scale %dMHz in to <=13.5MHz\n",
1431 Fref);
1432 return -EINVAL;
1433 }
1434
1435 Fvco_min = ARIZONA_FLL_MIN_FVCO * fll->vco_mult;
1436 if (Fout * ARIZONA_FLL_MAX_OUTDIV < Fvco_min) {
1437 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
1438 Fout);
1439 return -EINVAL;
1440 }
1441
1442 return 0;
1443}
1444
Charles Keepaxd0800342014-03-07 16:34:25 +00001445static int arizona_find_fratio(unsigned int Fref, int *fratio)
1446{
1447 int i;
1448
1449 /* Find an appropriate FLL_FRATIO */
1450 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
1451 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
1452 if (fratio)
1453 *fratio = fll_fratios[i].fratio;
1454 return fll_fratios[i].ratio;
1455 }
1456 }
1457
1458 return -EINVAL;
1459}
1460
1461static int arizona_calc_fratio(struct arizona_fll *fll,
1462 struct arizona_fll_cfg *cfg,
1463 unsigned int target,
1464 unsigned int Fref, bool sync)
1465{
1466 int init_ratio, ratio;
1467 int refdiv, div;
1468
1469 /* Fref must be <=13.5MHz, find initial refdiv */
1470 div = 1;
1471 cfg->refdiv = 0;
1472 while (Fref > ARIZONA_FLL_MAX_FREF) {
1473 div *= 2;
1474 Fref /= 2;
1475 cfg->refdiv++;
1476
1477 if (div > ARIZONA_FLL_MAX_REFDIV)
1478 return -EINVAL;
1479 }
1480
1481 /* Find an appropriate FLL_FRATIO */
1482 init_ratio = arizona_find_fratio(Fref, &cfg->fratio);
1483 if (init_ratio < 0) {
1484 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
1485 Fref);
1486 return init_ratio;
1487 }
1488
1489 switch (fll->arizona->type) {
1490 case WM5110:
1491 if (fll->arizona->rev < 3 || sync)
1492 return init_ratio;
1493 break;
1494 default:
1495 return init_ratio;
1496 }
1497
1498 cfg->fratio = init_ratio - 1;
1499
1500 /* Adjust FRATIO/refdiv to avoid integer mode if possible */
1501 refdiv = cfg->refdiv;
1502
1503 while (div <= ARIZONA_FLL_MAX_REFDIV) {
1504 for (ratio = init_ratio; ratio <= ARIZONA_FLL_MAX_FRATIO;
1505 ratio++) {
1506 if (target % (ratio * Fref)) {
1507 cfg->refdiv = refdiv;
1508 cfg->fratio = ratio - 1;
1509 return ratio;
1510 }
1511 }
1512
1513 for (ratio = init_ratio - 1; ratio >= 0; ratio--) {
1514 if (ARIZONA_FLL_VCO_CORNER / (fll->vco_mult * ratio) <
1515 Fref)
1516 break;
1517
1518 if (target % (ratio * Fref)) {
1519 cfg->refdiv = refdiv;
1520 cfg->fratio = ratio - 1;
1521 return ratio;
1522 }
1523 }
1524
1525 div *= 2;
1526 Fref /= 2;
1527 refdiv++;
1528 init_ratio = arizona_find_fratio(Fref, NULL);
1529 }
1530
1531 arizona_fll_warn(fll, "Falling back to integer mode operation\n");
1532 return cfg->fratio + 1;
1533}
1534
Mark Brown07ed8732012-06-18 21:08:44 +01001535static int arizona_calc_fll(struct arizona_fll *fll,
1536 struct arizona_fll_cfg *cfg,
Charles Keepaxd0800342014-03-07 16:34:25 +00001537 unsigned int Fref, bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01001538{
1539 unsigned int target, div, gcd_fll;
1540 int i, ratio;
1541
Charles Keepax8ccefcd2014-03-07 16:34:21 +00001542 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, fll->fout);
Mark Brown07ed8732012-06-18 21:08:44 +01001543
Mark Brown2b4d39f2012-07-10 17:03:46 +01001544 /* Fvco should be over the targt; don't check the upper bound */
Charles Keepaxf641aec2014-03-07 16:34:22 +00001545 div = ARIZONA_FLL_MIN_OUTDIV;
1546 while (fll->fout * div < ARIZONA_FLL_MIN_FVCO * fll->vco_mult) {
Mark Brown07ed8732012-06-18 21:08:44 +01001547 div++;
Charles Keepaxf641aec2014-03-07 16:34:22 +00001548 if (div > ARIZONA_FLL_MAX_OUTDIV)
Mark Brown07ed8732012-06-18 21:08:44 +01001549 return -EINVAL;
Mark Brown07ed8732012-06-18 21:08:44 +01001550 }
Charles Keepaxf641aec2014-03-07 16:34:22 +00001551 target = fll->fout * div / fll->vco_mult;
Mark Brown07ed8732012-06-18 21:08:44 +01001552 cfg->outdiv = div;
1553
1554 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
1555
Charles Keepaxd0800342014-03-07 16:34:25 +00001556 /* Find an appropriate FLL_FRATIO and refdiv */
1557 ratio = arizona_calc_fratio(fll, cfg, target, Fref, sync);
1558 if (ratio < 0)
1559 return ratio;
Mark Brown07ed8732012-06-18 21:08:44 +01001560
Mark Brown07ed8732012-06-18 21:08:44 +01001561 /* Apply the division for our remaining calculations */
Charles Keepaxd0800342014-03-07 16:34:25 +00001562 Fref = Fref / (1 << cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08001563
Mark Brown07ed8732012-06-18 21:08:44 +01001564 cfg->n = target / (ratio * Fref);
1565
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001566 if (target % (ratio * Fref)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001567 gcd_fll = gcd(target, ratio * Fref);
1568 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
1569
1570 cfg->theta = (target - (cfg->n * ratio * Fref))
1571 / gcd_fll;
1572 cfg->lambda = (ratio * Fref) / gcd_fll;
1573 } else {
1574 cfg->theta = 0;
1575 cfg->lambda = 0;
1576 }
1577
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001578 /* Round down to 16bit range with cost of accuracy lost.
1579 * Denominator must be bigger than numerator so we only
1580 * take care of it.
1581 */
1582 while (cfg->lambda >= (1 << 16)) {
1583 cfg->theta >>= 1;
1584 cfg->lambda >>= 1;
1585 }
1586
Charles Keepax5a3935c2014-03-07 16:34:23 +00001587 for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
1588 if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
1589 cfg->gain = fll_gains[i].gain;
1590 break;
1591 }
1592 }
1593 if (i == ARRAY_SIZE(fll_gains)) {
1594 arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
1595 Fref);
1596 return -EINVAL;
1597 }
1598
Mark Brown07ed8732012-06-18 21:08:44 +01001599 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
1600 cfg->n, cfg->theta, cfg->lambda);
1601 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
1602 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08001603 arizona_fll_dbg(fll, "GAIN=%d\n", cfg->gain);
Mark Brown07ed8732012-06-18 21:08:44 +01001604
1605 return 0;
1606
1607}
1608
1609static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
Mark Brown8f113d72013-03-05 12:08:57 +08001610 struct arizona_fll_cfg *cfg, int source,
1611 bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01001612{
Mark Brown3c43c692013-12-12 00:49:22 +00001613 regmap_update_bits_async(arizona->regmap, base + 3,
1614 ARIZONA_FLL1_THETA_MASK, cfg->theta);
1615 regmap_update_bits_async(arizona->regmap, base + 4,
1616 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
1617 regmap_update_bits_async(arizona->regmap, base + 5,
1618 ARIZONA_FLL1_FRATIO_MASK,
1619 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
1620 regmap_update_bits_async(arizona->regmap, base + 6,
1621 ARIZONA_FLL1_CLK_REF_DIV_MASK |
1622 ARIZONA_FLL1_CLK_REF_SRC_MASK,
1623 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
1624 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
Mark Brown07ed8732012-06-18 21:08:44 +01001625
Charles Keepax61719db2014-03-07 16:34:19 +00001626 if (sync) {
1627 regmap_update_bits(arizona->regmap, base + 0x7,
1628 ARIZONA_FLL1_GAIN_MASK,
1629 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
1630 } else {
1631 regmap_update_bits(arizona->regmap, base + 0x5,
1632 ARIZONA_FLL1_OUTDIV_MASK,
1633 cfg->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
1634 regmap_update_bits(arizona->regmap, base + 0x9,
1635 ARIZONA_FLL1_GAIN_MASK,
1636 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
1637 }
Mark Brown8f113d72013-03-05 12:08:57 +08001638
Mark Brown3c43c692013-12-12 00:49:22 +00001639 regmap_update_bits_async(arizona->regmap, base + 2,
1640 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
1641 ARIZONA_FLL1_CTRL_UPD | cfg->n);
Mark Brown07ed8732012-06-18 21:08:44 +01001642}
1643
Charles Keepaxd122d6c2013-02-20 17:28:36 +00001644static bool arizona_is_enabled_fll(struct arizona_fll *fll)
1645{
1646 struct arizona *arizona = fll->arizona;
1647 unsigned int reg;
1648 int ret;
1649
1650 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
1651 if (ret != 0) {
1652 arizona_fll_err(fll, "Failed to read current state: %d\n",
1653 ret);
1654 return ret;
1655 }
1656
1657 return reg & ARIZONA_FLL1_ENA;
1658}
1659
Charles Keepax23f785a82014-03-07 16:34:20 +00001660static void arizona_enable_fll(struct arizona_fll *fll)
Charles Keepax35722812013-02-20 17:28:38 +00001661{
1662 struct arizona *arizona = fll->arizona;
1663 int ret;
Charles Keepax49c60542013-09-16 15:34:35 +01001664 bool use_sync = false;
Charles Keepax23f785a82014-03-07 16:34:20 +00001665 struct arizona_fll_cfg cfg;
Charles Keepax35722812013-02-20 17:28:38 +00001666
Mark Brownff680a12013-03-04 16:00:19 +08001667 /*
1668 * If we have both REFCLK and SYNCCLK then enable both,
1669 * otherwise apply the SYNCCLK settings to REFCLK.
1670 */
Charles Keepax49c60542013-09-16 15:34:35 +01001671 if (fll->ref_src >= 0 && fll->ref_freq &&
1672 fll->ref_src != fll->sync_src) {
Charles Keepaxd0800342014-03-07 16:34:25 +00001673 arizona_calc_fll(fll, &cfg, fll->ref_freq, false);
Charles Keepax35722812013-02-20 17:28:38 +00001674
Charles Keepax23f785a82014-03-07 16:34:20 +00001675 arizona_apply_fll(arizona, fll->base, &cfg, fll->ref_src,
Mark Brown8f113d72013-03-05 12:08:57 +08001676 false);
Charles Keepax49c60542013-09-16 15:34:35 +01001677 if (fll->sync_src >= 0) {
Charles Keepaxd0800342014-03-07 16:34:25 +00001678 arizona_calc_fll(fll, &cfg, fll->sync_freq, true);
Charles Keepax23f785a82014-03-07 16:34:20 +00001679
1680 arizona_apply_fll(arizona, fll->base + 0x10, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08001681 fll->sync_src, true);
Charles Keepax49c60542013-09-16 15:34:35 +01001682 use_sync = true;
1683 }
Mark Brownff680a12013-03-04 16:00:19 +08001684 } else if (fll->sync_src >= 0) {
Charles Keepaxd0800342014-03-07 16:34:25 +00001685 arizona_calc_fll(fll, &cfg, fll->sync_freq, false);
Mark Brownff680a12013-03-04 16:00:19 +08001686
Charles Keepax23f785a82014-03-07 16:34:20 +00001687 arizona_apply_fll(arizona, fll->base, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08001688 fll->sync_src, false);
Mark Browneca2e8e2013-03-06 00:09:59 +08001689
Mark Brown3c43c692013-12-12 00:49:22 +00001690 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
1691 ARIZONA_FLL1_SYNC_ENA, 0);
Mark Brownff680a12013-03-04 16:00:19 +08001692 } else {
1693 arizona_fll_err(fll, "No clocks provided\n");
1694 return;
1695 }
Charles Keepax35722812013-02-20 17:28:38 +00001696
Mark Brown576411be2013-03-05 12:07:16 +08001697 /*
1698 * Increase the bandwidth if we're not using a low frequency
1699 * sync source.
1700 */
Charles Keepax49c60542013-09-16 15:34:35 +01001701 if (use_sync && fll->sync_freq > 100000)
Mark Brown3c43c692013-12-12 00:49:22 +00001702 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
1703 ARIZONA_FLL1_SYNC_BW, 0);
Mark Brown576411be2013-03-05 12:07:16 +08001704 else
Mark Brown3c43c692013-12-12 00:49:22 +00001705 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
1706 ARIZONA_FLL1_SYNC_BW,
1707 ARIZONA_FLL1_SYNC_BW);
Mark Brown576411be2013-03-05 12:07:16 +08001708
Charles Keepax35722812013-02-20 17:28:38 +00001709 if (!arizona_is_enabled_fll(fll))
1710 pm_runtime_get(arizona->dev);
1711
1712 /* Clear any pending completions */
1713 try_wait_for_completion(&fll->ok);
1714
Mark Brown3c43c692013-12-12 00:49:22 +00001715 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1716 ARIZONA_FLL1_FREERUN, 0);
1717 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1718 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
Charles Keepax49c60542013-09-16 15:34:35 +01001719 if (use_sync)
Mark Brown3c43c692013-12-12 00:49:22 +00001720 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
1721 ARIZONA_FLL1_SYNC_ENA,
1722 ARIZONA_FLL1_SYNC_ENA);
Charles Keepax35722812013-02-20 17:28:38 +00001723
1724 ret = wait_for_completion_timeout(&fll->ok,
1725 msecs_to_jiffies(250));
1726 if (ret == 0)
1727 arizona_fll_warn(fll, "Timed out waiting for lock\n");
1728}
1729
Charles Keepax76040542013-02-20 17:28:37 +00001730static void arizona_disable_fll(struct arizona_fll *fll)
1731{
1732 struct arizona *arizona = fll->arizona;
1733 bool change;
1734
Mark Brown3c43c692013-12-12 00:49:22 +00001735 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1736 ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
Charles Keepax76040542013-02-20 17:28:37 +00001737 regmap_update_bits_check(arizona->regmap, fll->base + 1,
1738 ARIZONA_FLL1_ENA, 0, &change);
1739 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1740 ARIZONA_FLL1_SYNC_ENA, 0);
1741
1742 if (change)
1743 pm_runtime_put_autosuspend(arizona->dev);
1744}
1745
Charles Keepaxee929a92013-02-20 17:28:40 +00001746int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
1747 unsigned int Fref, unsigned int Fout)
1748{
Charles Keepaxee929a92013-02-20 17:28:40 +00001749 int ret;
1750
Charles Keepax1c5617f2013-02-22 17:10:37 +00001751 if (fll->ref_src == source && fll->ref_freq == Fref)
Charles Keepaxee929a92013-02-20 17:28:40 +00001752 return 0;
1753
Charles Keepax23f785a82014-03-07 16:34:20 +00001754 if (fll->fout && Fref > 0) {
1755 ret = arizona_validate_fll(fll, Fref, fll->fout);
1756 if (ret != 0)
1757 return ret;
Charles Keepaxee929a92013-02-20 17:28:40 +00001758 }
1759
1760 fll->ref_src = source;
1761 fll->ref_freq = Fref;
Charles Keepaxee929a92013-02-20 17:28:40 +00001762
Mark Brown86cd6842013-03-07 16:14:04 +08001763 if (fll->fout && Fref > 0) {
Charles Keepax23f785a82014-03-07 16:34:20 +00001764 arizona_enable_fll(fll);
Charles Keepaxee929a92013-02-20 17:28:40 +00001765 }
1766
1767 return 0;
1768}
1769EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
1770
Mark Brown07ed8732012-06-18 21:08:44 +01001771int arizona_set_fll(struct arizona_fll *fll, int source,
1772 unsigned int Fref, unsigned int Fout)
1773{
Mark Brown07ed8732012-06-18 21:08:44 +01001774 int ret;
1775
Mark Brownff680a12013-03-04 16:00:19 +08001776 if (fll->sync_src == source &&
1777 fll->sync_freq == Fref && fll->fout == Fout)
1778 return 0;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00001779
Mark Brownff680a12013-03-04 16:00:19 +08001780 if (Fout) {
1781 if (fll->ref_src >= 0) {
Charles Keepax23f785a82014-03-07 16:34:20 +00001782 ret = arizona_validate_fll(fll, fll->ref_freq, Fout);
Charles Keepax9e359c62013-02-20 17:28:35 +00001783 if (ret != 0)
1784 return ret;
1785 }
1786
Charles Keepax23f785a82014-03-07 16:34:20 +00001787 ret = arizona_validate_fll(fll, Fref, Fout);
Mark Brownff680a12013-03-04 16:00:19 +08001788 if (ret != 0)
1789 return ret;
Charles Keepax9e359c62013-02-20 17:28:35 +00001790 }
Mark Brownff680a12013-03-04 16:00:19 +08001791
1792 fll->sync_src = source;
1793 fll->sync_freq = Fref;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00001794 fll->fout = Fout;
Charles Keepax9e359c62013-02-20 17:28:35 +00001795
Mark Brown07ed8732012-06-18 21:08:44 +01001796 if (Fout) {
Charles Keepax23f785a82014-03-07 16:34:20 +00001797 arizona_enable_fll(fll);
Mark Brown07ed8732012-06-18 21:08:44 +01001798 } else {
Charles Keepax76040542013-02-20 17:28:37 +00001799 arizona_disable_fll(fll);
Mark Brown07ed8732012-06-18 21:08:44 +01001800 }
1801
Mark Brown07ed8732012-06-18 21:08:44 +01001802 return 0;
1803}
1804EXPORT_SYMBOL_GPL(arizona_set_fll);
1805
1806int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
1807 int ok_irq, struct arizona_fll *fll)
1808{
1809 int ret;
Charles Keepax19b34bd2013-02-20 17:28:34 +00001810 unsigned int val;
Mark Brown07ed8732012-06-18 21:08:44 +01001811
Mark Brown07ed8732012-06-18 21:08:44 +01001812 init_completion(&fll->ok);
1813
1814 fll->id = id;
1815 fll->base = base;
1816 fll->arizona = arizona;
Charles Keepaxf3f11632013-02-20 17:28:41 +00001817 fll->sync_src = ARIZONA_FLL_SRC_NONE;
Mark Brown07ed8732012-06-18 21:08:44 +01001818
Charles Keepax19b34bd2013-02-20 17:28:34 +00001819 /* Configure default refclk to 32kHz if we have one */
1820 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
1821 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
1822 case ARIZONA_CLK_SRC_MCLK1:
1823 case ARIZONA_CLK_SRC_MCLK2:
1824 fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK;
1825 break;
1826 default:
Charles Keepaxf3f11632013-02-20 17:28:41 +00001827 fll->ref_src = ARIZONA_FLL_SRC_NONE;
Charles Keepax19b34bd2013-02-20 17:28:34 +00001828 }
1829 fll->ref_freq = 32768;
1830
Mark Brown07ed8732012-06-18 21:08:44 +01001831 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
1832 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
1833 "FLL%d clock OK", id);
1834
Mark Brown07ed8732012-06-18 21:08:44 +01001835 ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
1836 arizona_fll_clock_ok, fll);
1837 if (ret != 0) {
1838 dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
1839 id, ret);
1840 }
1841
Charles Keepaxe31c1942013-01-07 16:41:45 +00001842 regmap_update_bits(arizona->regmap, fll->base + 1,
1843 ARIZONA_FLL1_FREERUN, 0);
1844
Mark Brown07ed8732012-06-18 21:08:44 +01001845 return 0;
1846}
1847EXPORT_SYMBOL_GPL(arizona_init_fll);
1848
Mark Brownbc9ab6d2013-01-04 19:31:00 +00001849/**
1850 * arizona_set_output_mode - Set the mode of the specified output
1851 *
1852 * @codec: Device to configure
1853 * @output: Output number
1854 * @diff: True to set the output to differential mode
1855 *
1856 * Some systems use external analogue switches to connect more
1857 * analogue devices to the CODEC than are supported by the device. In
1858 * some systems this requires changing the switched output from single
1859 * ended to differential mode dynamically at runtime, an operation
1860 * supported using this function.
1861 *
1862 * Most systems have a single static configuration and should use
1863 * platform data instead.
1864 */
1865int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
1866{
1867 unsigned int reg, val;
1868
1869 if (output < 1 || output > 6)
1870 return -EINVAL;
1871
1872 reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
1873
1874 if (diff)
1875 val = ARIZONA_OUT1_MONO;
1876 else
1877 val = 0;
1878
1879 return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val);
1880}
1881EXPORT_SYMBOL_GPL(arizona_set_output_mode);
1882
Mark Brown07ed8732012-06-18 21:08:44 +01001883MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
1884MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1885MODULE_LICENSE("GPL");