blob: e77f61c387f7abdc4c22bc2ba8cf2bbff20185fc [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 Keepaxb63144e2013-07-04 08:56:28 +0100246int arizona_init_gpio(struct snd_soc_codec *codec)
247{
248 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
249 struct arizona *arizona = priv->arizona;
250 int i;
251
252 switch (arizona->type) {
253 case WM5110:
254 snd_soc_dapm_disable_pin(&codec->dapm, "DRC2 Signal Activity");
Charles Keepaxb79fae62013-07-04 16:53:03 +0100255 break;
256 default:
257 break;
Charles Keepaxb63144e2013-07-04 08:56:28 +0100258 }
259
260 snd_soc_dapm_disable_pin(&codec->dapm, "DRC1 Signal Activity");
261
262 for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
263 switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) {
264 case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT:
265 snd_soc_dapm_enable_pin(&codec->dapm,
266 "DRC1 Signal Activity");
267 break;
268 case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT:
269 snd_soc_dapm_enable_pin(&codec->dapm,
270 "DRC2 Signal Activity");
271 break;
272 default:
273 break;
274 }
275 }
276
277 return 0;
278}
279EXPORT_SYMBOL_GPL(arizona_init_gpio);
280
Mark Brown07ed8732012-06-18 21:08:44 +0100281const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
282 "None",
283 "Tone Generator 1",
284 "Tone Generator 2",
285 "Haptics",
286 "AEC",
287 "Mic Mute Mixer",
288 "Noise Generator",
289 "IN1L",
290 "IN1R",
291 "IN2L",
292 "IN2R",
293 "IN3L",
294 "IN3R",
Mark Brownc9c56fd2012-07-09 19:09:01 +0100295 "IN4L",
296 "IN4R",
Mark Brown07ed8732012-06-18 21:08:44 +0100297 "AIF1RX1",
298 "AIF1RX2",
299 "AIF1RX3",
300 "AIF1RX4",
301 "AIF1RX5",
302 "AIF1RX6",
303 "AIF1RX7",
304 "AIF1RX8",
305 "AIF2RX1",
306 "AIF2RX2",
Richard Fitzgeralde64001e2013-11-20 13:17:07 +0000307 "AIF2RX3",
308 "AIF2RX4",
309 "AIF2RX5",
310 "AIF2RX6",
Mark Brown07ed8732012-06-18 21:08:44 +0100311 "AIF3RX1",
312 "AIF3RX2",
313 "SLIMRX1",
314 "SLIMRX2",
315 "SLIMRX3",
316 "SLIMRX4",
317 "SLIMRX5",
318 "SLIMRX6",
319 "SLIMRX7",
320 "SLIMRX8",
321 "EQ1",
322 "EQ2",
323 "EQ3",
324 "EQ4",
325 "DRC1L",
326 "DRC1R",
327 "DRC2L",
328 "DRC2R",
329 "LHPF1",
330 "LHPF2",
331 "LHPF3",
332 "LHPF4",
333 "DSP1.1",
334 "DSP1.2",
335 "DSP1.3",
336 "DSP1.4",
337 "DSP1.5",
338 "DSP1.6",
Mark Brownc922cc42012-09-26 16:43:44 +0100339 "DSP2.1",
340 "DSP2.2",
341 "DSP2.3",
342 "DSP2.4",
343 "DSP2.5",
344 "DSP2.6",
345 "DSP3.1",
346 "DSP3.2",
347 "DSP3.3",
348 "DSP3.4",
349 "DSP3.5",
350 "DSP3.6",
351 "DSP4.1",
352 "DSP4.2",
353 "DSP4.3",
354 "DSP4.4",
355 "DSP4.5",
356 "DSP4.6",
Mark Brown07ed8732012-06-18 21:08:44 +0100357 "ASRC1L",
358 "ASRC1R",
359 "ASRC2L",
360 "ASRC2R",
Mark Brown91660bd2012-12-05 20:35:24 +0900361 "ISRC1INT1",
362 "ISRC1INT2",
363 "ISRC1INT3",
364 "ISRC1INT4",
365 "ISRC1DEC1",
366 "ISRC1DEC2",
367 "ISRC1DEC3",
368 "ISRC1DEC4",
369 "ISRC2INT1",
370 "ISRC2INT2",
371 "ISRC2INT3",
372 "ISRC2INT4",
373 "ISRC2DEC1",
374 "ISRC2DEC2",
375 "ISRC2DEC3",
376 "ISRC2DEC4",
377 "ISRC3INT1",
378 "ISRC3INT2",
379 "ISRC3INT3",
380 "ISRC3INT4",
381 "ISRC3DEC1",
382 "ISRC3DEC2",
383 "ISRC3DEC3",
384 "ISRC3DEC4",
Mark Brown07ed8732012-06-18 21:08:44 +0100385};
386EXPORT_SYMBOL_GPL(arizona_mixer_texts);
387
388int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
389 0x00, /* None */
390 0x04, /* Tone */
391 0x05,
392 0x06, /* Haptics */
393 0x08, /* AEC */
394 0x0c, /* Noise mixer */
395 0x0d, /* Comfort noise */
396 0x10, /* IN1L */
397 0x11,
398 0x12,
399 0x13,
400 0x14,
401 0x15,
Mark Brownc9c56fd2012-07-09 19:09:01 +0100402 0x16,
403 0x17,
Mark Brown07ed8732012-06-18 21:08:44 +0100404 0x20, /* AIF1RX1 */
405 0x21,
406 0x22,
407 0x23,
408 0x24,
409 0x25,
410 0x26,
411 0x27,
412 0x28, /* AIF2RX1 */
413 0x29,
Richard Fitzgeralde64001e2013-11-20 13:17:07 +0000414 0x2a,
415 0x2b,
416 0x2c,
417 0x2d,
Mark Brown07ed8732012-06-18 21:08:44 +0100418 0x30, /* AIF3RX1 */
419 0x31,
420 0x38, /* SLIMRX1 */
421 0x39,
422 0x3a,
423 0x3b,
424 0x3c,
425 0x3d,
426 0x3e,
427 0x3f,
428 0x50, /* EQ1 */
429 0x51,
430 0x52,
431 0x53,
432 0x58, /* DRC1L */
433 0x59,
434 0x5a,
435 0x5b,
436 0x60, /* LHPF1 */
437 0x61,
438 0x62,
439 0x63,
440 0x68, /* DSP1.1 */
441 0x69,
442 0x6a,
443 0x6b,
444 0x6c,
445 0x6d,
Mark Brownc922cc42012-09-26 16:43:44 +0100446 0x70, /* DSP2.1 */
447 0x71,
448 0x72,
449 0x73,
450 0x74,
451 0x75,
452 0x78, /* DSP3.1 */
453 0x79,
454 0x7a,
455 0x7b,
456 0x7c,
457 0x7d,
458 0x80, /* DSP4.1 */
459 0x81,
460 0x82,
461 0x83,
462 0x84,
463 0x85,
Mark Brown07ed8732012-06-18 21:08:44 +0100464 0x90, /* ASRC1L */
465 0x91,
466 0x92,
467 0x93,
Mark Brown91660bd2012-12-05 20:35:24 +0900468 0xa0, /* ISRC1INT1 */
469 0xa1,
470 0xa2,
471 0xa3,
472 0xa4, /* ISRC1DEC1 */
473 0xa5,
474 0xa6,
475 0xa7,
476 0xa8, /* ISRC2DEC1 */
477 0xa9,
478 0xaa,
479 0xab,
480 0xac, /* ISRC2INT1 */
481 0xad,
482 0xae,
483 0xaf,
484 0xb0, /* ISRC3DEC1 */
485 0xb1,
486 0xb2,
487 0xb3,
488 0xb4, /* ISRC3INT1 */
489 0xb5,
490 0xb6,
491 0xb7,
Mark Brown07ed8732012-06-18 21:08:44 +0100492};
493EXPORT_SYMBOL_GPL(arizona_mixer_values);
494
495const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
496EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
497
Mark Browndc914282013-02-18 19:09:23 +0000498const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = {
499 "SYNCCLK rate", "8kHz", "16kHz", "ASYNCCLK rate",
500};
501EXPORT_SYMBOL_GPL(arizona_rate_text);
502
503const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
504 0, 1, 2, 8,
505};
506EXPORT_SYMBOL_GPL(arizona_rate_val);
507
508
Charles Keepaxfbedc8c2013-12-19 09:30:12 +0000509const struct soc_enum arizona_isrc_fsh[] = {
510 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_1,
511 ARIZONA_ISRC1_FSH_SHIFT, 0xf,
512 ARIZONA_RATE_ENUM_SIZE,
513 arizona_rate_text, arizona_rate_val),
514 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_1,
515 ARIZONA_ISRC2_FSH_SHIFT, 0xf,
516 ARIZONA_RATE_ENUM_SIZE,
517 arizona_rate_text, arizona_rate_val),
518 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_1,
519 ARIZONA_ISRC3_FSH_SHIFT, 0xf,
520 ARIZONA_RATE_ENUM_SIZE,
521 arizona_rate_text, arizona_rate_val),
522};
523EXPORT_SYMBOL_GPL(arizona_isrc_fsh);
524
Mark Browndc914282013-02-18 19:09:23 +0000525const struct soc_enum arizona_isrc_fsl[] = {
526 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2,
527 ARIZONA_ISRC1_FSL_SHIFT, 0xf,
528 ARIZONA_RATE_ENUM_SIZE,
529 arizona_rate_text, arizona_rate_val),
530 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_2,
531 ARIZONA_ISRC2_FSL_SHIFT, 0xf,
532 ARIZONA_RATE_ENUM_SIZE,
533 arizona_rate_text, arizona_rate_val),
534 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_2,
535 ARIZONA_ISRC3_FSL_SHIFT, 0xf,
536 ARIZONA_RATE_ENUM_SIZE,
537 arizona_rate_text, arizona_rate_val),
538};
539EXPORT_SYMBOL_GPL(arizona_isrc_fsl);
540
Charles Keepax56d37d82013-12-19 09:30:13 +0000541const struct soc_enum arizona_asrc_rate1 =
542 SOC_VALUE_ENUM_SINGLE(ARIZONA_ASRC_RATE1,
543 ARIZONA_ASRC_RATE1_SHIFT, 0xf,
544 ARIZONA_RATE_ENUM_SIZE - 1,
545 arizona_rate_text, arizona_rate_val);
546EXPORT_SYMBOL_GPL(arizona_asrc_rate1);
547
Mark Browne853a002012-12-09 12:25:52 +0900548static const char *arizona_vol_ramp_text[] = {
549 "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
550 "15ms/6dB", "30ms/6dB",
551};
552
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100553SOC_ENUM_SINGLE_DECL(arizona_in_vd_ramp,
554 ARIZONA_INPUT_VOLUME_RAMP,
555 ARIZONA_IN_VD_RAMP_SHIFT,
556 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900557EXPORT_SYMBOL_GPL(arizona_in_vd_ramp);
558
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100559SOC_ENUM_SINGLE_DECL(arizona_in_vi_ramp,
560 ARIZONA_INPUT_VOLUME_RAMP,
561 ARIZONA_IN_VI_RAMP_SHIFT,
562 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900563EXPORT_SYMBOL_GPL(arizona_in_vi_ramp);
564
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100565SOC_ENUM_SINGLE_DECL(arizona_out_vd_ramp,
566 ARIZONA_OUTPUT_VOLUME_RAMP,
567 ARIZONA_OUT_VD_RAMP_SHIFT,
568 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900569EXPORT_SYMBOL_GPL(arizona_out_vd_ramp);
570
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100571SOC_ENUM_SINGLE_DECL(arizona_out_vi_ramp,
572 ARIZONA_OUTPUT_VOLUME_RAMP,
573 ARIZONA_OUT_VI_RAMP_SHIFT,
574 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900575EXPORT_SYMBOL_GPL(arizona_out_vi_ramp);
576
Mark Brown07ed8732012-06-18 21:08:44 +0100577static const char *arizona_lhpf_mode_text[] = {
578 "Low-pass", "High-pass"
579};
580
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100581SOC_ENUM_SINGLE_DECL(arizona_lhpf1_mode,
582 ARIZONA_HPLPF1_1,
583 ARIZONA_LHPF1_MODE_SHIFT,
584 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100585EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
586
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100587SOC_ENUM_SINGLE_DECL(arizona_lhpf2_mode,
588 ARIZONA_HPLPF2_1,
589 ARIZONA_LHPF2_MODE_SHIFT,
590 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100591EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
592
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100593SOC_ENUM_SINGLE_DECL(arizona_lhpf3_mode,
594 ARIZONA_HPLPF3_1,
595 ARIZONA_LHPF3_MODE_SHIFT,
596 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100597EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
598
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100599SOC_ENUM_SINGLE_DECL(arizona_lhpf4_mode,
600 ARIZONA_HPLPF4_1,
601 ARIZONA_LHPF4_MODE_SHIFT,
602 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100603EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
604
Mark Brown845571c2012-12-18 13:47:57 +0000605static const char *arizona_ng_hold_text[] = {
606 "30ms", "120ms", "250ms", "500ms",
607};
608
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100609SOC_ENUM_SINGLE_DECL(arizona_ng_hold,
610 ARIZONA_NOISE_GATE_CONTROL,
611 ARIZONA_NGATE_HOLD_SHIFT,
612 arizona_ng_hold_text);
Mark Brown845571c2012-12-18 13:47:57 +0000613EXPORT_SYMBOL_GPL(arizona_ng_hold);
614
Charles Keepax254dc322013-11-19 16:04:03 +0000615static const char * const arizona_in_hpf_cut_text[] = {
616 "2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz"
617};
618
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100619SOC_ENUM_SINGLE_DECL(arizona_in_hpf_cut_enum,
620 ARIZONA_HPF_CONTROL,
621 ARIZONA_IN_HPF_CUT_SHIFT,
622 arizona_in_hpf_cut_text);
Charles Keepax254dc322013-11-19 16:04:03 +0000623EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum);
624
Charles Keepaxc7f38432013-08-06 17:03:55 +0100625static const char * const arizona_in_dmic_osr_text[] = {
626 "1.536MHz", "3.072MHz", "6.144MHz",
627};
628
629const struct soc_enum arizona_in_dmic_osr[] = {
630 SOC_ENUM_SINGLE(ARIZONA_IN1L_CONTROL, ARIZONA_IN1_OSR_SHIFT,
631 ARRAY_SIZE(arizona_in_dmic_osr_text),
632 arizona_in_dmic_osr_text),
633 SOC_ENUM_SINGLE(ARIZONA_IN2L_CONTROL, ARIZONA_IN2_OSR_SHIFT,
634 ARRAY_SIZE(arizona_in_dmic_osr_text),
635 arizona_in_dmic_osr_text),
636 SOC_ENUM_SINGLE(ARIZONA_IN3L_CONTROL, ARIZONA_IN3_OSR_SHIFT,
637 ARRAY_SIZE(arizona_in_dmic_osr_text),
638 arizona_in_dmic_osr_text),
639 SOC_ENUM_SINGLE(ARIZONA_IN4L_CONTROL, ARIZONA_IN4_OSR_SHIFT,
640 ARRAY_SIZE(arizona_in_dmic_osr_text),
641 arizona_in_dmic_osr_text),
642};
643EXPORT_SYMBOL_GPL(arizona_in_dmic_osr);
644
Mark Brownddbce972013-02-15 17:27:22 +0000645static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
646{
647 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
648 unsigned int val;
649 int i;
650
651 if (ena)
652 val = ARIZONA_IN_VU;
653 else
654 val = 0;
655
656 for (i = 0; i < priv->num_inputs; i++)
657 snd_soc_update_bits(codec,
658 ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 4),
659 ARIZONA_IN_VU, val);
660}
661
Mark Brown07ed8732012-06-18 21:08:44 +0100662int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
663 int event)
664{
Mark Brownddbce972013-02-15 17:27:22 +0000665 struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000666 unsigned int reg;
667
668 if (w->shift % 2)
669 reg = ARIZONA_ADC_DIGITAL_VOLUME_1L + ((w->shift / 2) * 8);
670 else
671 reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8);
672
673 switch (event) {
Mark Brownddbce972013-02-15 17:27:22 +0000674 case SND_SOC_DAPM_PRE_PMU:
675 priv->in_pending++;
676 break;
Mark Brown43cd8bf2013-02-06 16:57:29 +0000677 case SND_SOC_DAPM_POST_PMU:
678 snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, 0);
Mark Brownddbce972013-02-15 17:27:22 +0000679
680 /* If this is the last input pending then allow VU */
681 priv->in_pending--;
682 if (priv->in_pending == 0) {
683 msleep(1);
684 arizona_in_set_vu(w->codec, 1);
685 }
Mark Brown43cd8bf2013-02-06 16:57:29 +0000686 break;
687 case SND_SOC_DAPM_PRE_PMD:
Mark Brownddbce972013-02-15 17:27:22 +0000688 snd_soc_update_bits(w->codec, reg,
689 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU,
690 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000691 break;
Mark Brownddbce972013-02-15 17:27:22 +0000692 case SND_SOC_DAPM_POST_PMD:
693 /* Disable volume updates if no inputs are enabled */
694 reg = snd_soc_read(w->codec, ARIZONA_INPUT_ENABLES);
695 if (reg == 0)
696 arizona_in_set_vu(w->codec, 0);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000697 }
698
Mark Brown07ed8732012-06-18 21:08:44 +0100699 return 0;
700}
701EXPORT_SYMBOL_GPL(arizona_in_ev);
702
703int arizona_out_ev(struct snd_soc_dapm_widget *w,
704 struct snd_kcontrol *kcontrol,
705 int event)
706{
Mark Brown1a2c7d52013-03-24 22:50:23 +0000707 switch (event) {
708 case SND_SOC_DAPM_POST_PMU:
709 switch (w->shift) {
710 case ARIZONA_OUT1L_ENA_SHIFT:
711 case ARIZONA_OUT1R_ENA_SHIFT:
712 case ARIZONA_OUT2L_ENA_SHIFT:
713 case ARIZONA_OUT2R_ENA_SHIFT:
714 case ARIZONA_OUT3L_ENA_SHIFT:
715 case ARIZONA_OUT3R_ENA_SHIFT:
716 msleep(17);
717 break;
718
719 default:
720 break;
721 }
722 break;
723 }
724
Mark Brown07ed8732012-06-18 21:08:44 +0100725 return 0;
726}
727EXPORT_SYMBOL_GPL(arizona_out_ev);
728
Mark Brownf607e312013-02-22 18:36:53 +0000729int arizona_hp_ev(struct snd_soc_dapm_widget *w,
730 struct snd_kcontrol *kcontrol,
731 int event)
732{
733 struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
Mark Brown3c43c692013-12-12 00:49:22 +0000734 struct arizona *arizona = priv->arizona;
Mark Brownf607e312013-02-22 18:36:53 +0000735 unsigned int mask = 1 << w->shift;
736 unsigned int val;
737
738 switch (event) {
739 case SND_SOC_DAPM_POST_PMU:
740 val = mask;
741 break;
742 case SND_SOC_DAPM_PRE_PMD:
743 val = 0;
744 break;
745 default:
746 return -EINVAL;
747 }
748
749 /* Store the desired state for the HP outputs */
750 priv->arizona->hp_ena &= ~mask;
751 priv->arizona->hp_ena |= val;
752
753 /* Force off if HPDET magic is active */
754 if (priv->arizona->hpdet_magic)
755 val = 0;
756
Mark Brown3c43c692013-12-12 00:49:22 +0000757 regmap_update_bits_async(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1,
758 mask, val);
Mark Brownf607e312013-02-22 18:36:53 +0000759
760 return arizona_out_ev(w, kcontrol, event);
761}
762EXPORT_SYMBOL_GPL(arizona_hp_ev);
763
Mark Browncbd840d2012-08-08 17:52:44 +0100764static unsigned int arizona_sysclk_48k_rates[] = {
765 6144000,
766 12288000,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000767 24576000,
Mark Browncbd840d2012-08-08 17:52:44 +0100768 49152000,
Mark Brownaeaeee12012-09-26 17:50:02 +0100769 73728000,
770 98304000,
771 147456000,
Mark Browncbd840d2012-08-08 17:52:44 +0100772};
773
774static unsigned int arizona_sysclk_44k1_rates[] = {
775 5644800,
776 11289600,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000777 22579200,
Mark Browncbd840d2012-08-08 17:52:44 +0100778 45158400,
Mark Brownaeaeee12012-09-26 17:50:02 +0100779 67737600,
780 90316800,
781 135475200,
Mark Browncbd840d2012-08-08 17:52:44 +0100782};
783
784static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
785 unsigned int freq)
786{
787 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
788 unsigned int reg;
789 unsigned int *rates;
790 int ref, div, refclk;
791
792 switch (clk) {
793 case ARIZONA_CLK_OPCLK:
794 reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
795 refclk = priv->sysclk;
796 break;
797 case ARIZONA_CLK_ASYNC_OPCLK:
798 reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
799 refclk = priv->asyncclk;
800 break;
801 default:
802 return -EINVAL;
803 }
804
805 if (refclk % 8000)
806 rates = arizona_sysclk_44k1_rates;
807 else
808 rates = arizona_sysclk_48k_rates;
809
810 for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) &&
811 rates[ref] <= refclk; ref++) {
812 div = 1;
813 while (rates[ref] / div >= freq && div < 32) {
814 if (rates[ref] / div == freq) {
815 dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
816 freq);
817 snd_soc_update_bits(codec, reg,
818 ARIZONA_OPCLK_DIV_MASK |
819 ARIZONA_OPCLK_SEL_MASK,
820 (div <<
821 ARIZONA_OPCLK_DIV_SHIFT) |
822 ref);
823 return 0;
824 }
825 div++;
826 }
827 }
828
829 dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
830 return -EINVAL;
831}
832
Mark Brown07ed8732012-06-18 21:08:44 +0100833int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
834 int source, unsigned int freq, int dir)
835{
836 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
837 struct arizona *arizona = priv->arizona;
838 char *name;
839 unsigned int reg;
840 unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
841 unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
842 unsigned int *clk;
843
844 switch (clk_id) {
845 case ARIZONA_CLK_SYSCLK:
846 name = "SYSCLK";
847 reg = ARIZONA_SYSTEM_CLOCK_1;
848 clk = &priv->sysclk;
849 mask |= ARIZONA_SYSCLK_FRAC;
850 break;
851 case ARIZONA_CLK_ASYNCCLK:
852 name = "ASYNCCLK";
853 reg = ARIZONA_ASYNC_CLOCK_1;
854 clk = &priv->asyncclk;
855 break;
Mark Browncbd840d2012-08-08 17:52:44 +0100856 case ARIZONA_CLK_OPCLK:
857 case ARIZONA_CLK_ASYNC_OPCLK:
858 return arizona_set_opclk(codec, clk_id, freq);
Mark Brown07ed8732012-06-18 21:08:44 +0100859 default:
860 return -EINVAL;
861 }
862
863 switch (freq) {
864 case 5644800:
865 case 6144000:
866 break;
867 case 11289600:
868 case 12288000:
Mark Brown3f341f72013-03-08 15:22:29 +0800869 val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100870 break;
871 case 22579200:
872 case 24576000:
Mark Brown3f341f72013-03-08 15:22:29 +0800873 val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100874 break;
875 case 45158400:
876 case 49152000:
Mark Brown3f341f72013-03-08 15:22:29 +0800877 val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100878 break;
Mark Brown38113362012-11-26 16:01:37 +0000879 case 67737600:
880 case 73728000:
Mark Brown3f341f72013-03-08 15:22:29 +0800881 val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000882 break;
883 case 90316800:
884 case 98304000:
Mark Brown3f341f72013-03-08 15:22:29 +0800885 val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000886 break;
887 case 135475200:
888 case 147456000:
Mark Brown3f341f72013-03-08 15:22:29 +0800889 val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000890 break;
Mark Brownf2c26d42013-01-21 16:09:36 +0900891 case 0:
892 dev_dbg(arizona->dev, "%s cleared\n", name);
893 *clk = freq;
894 return 0;
Mark Brown07ed8732012-06-18 21:08:44 +0100895 default:
896 return -EINVAL;
897 }
898
899 *clk = freq;
900
901 if (freq % 6144000)
902 val |= ARIZONA_SYSCLK_FRAC;
903
904 dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
905
906 return regmap_update_bits(arizona->regmap, reg, mask, val);
907}
908EXPORT_SYMBOL_GPL(arizona_set_sysclk);
909
910static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
911{
912 struct snd_soc_codec *codec = dai->codec;
Mark Brown3c43c692013-12-12 00:49:22 +0000913 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
914 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +0100915 int lrclk, bclk, mode, base;
916
917 base = dai->driver->base;
918
919 lrclk = 0;
920 bclk = 0;
921
922 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
923 case SND_SOC_DAIFMT_DSP_A:
924 mode = 0;
925 break;
Mark Brown07ed8732012-06-18 21:08:44 +0100926 case SND_SOC_DAIFMT_I2S:
927 mode = 2;
928 break;
Mark Brown07ed8732012-06-18 21:08:44 +0100929 default:
930 arizona_aif_err(dai, "Unsupported DAI format %d\n",
931 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
932 return -EINVAL;
933 }
934
935 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
936 case SND_SOC_DAIFMT_CBS_CFS:
937 break;
938 case SND_SOC_DAIFMT_CBS_CFM:
939 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
940 break;
941 case SND_SOC_DAIFMT_CBM_CFS:
942 bclk |= ARIZONA_AIF1_BCLK_MSTR;
943 break;
944 case SND_SOC_DAIFMT_CBM_CFM:
945 bclk |= ARIZONA_AIF1_BCLK_MSTR;
946 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
947 break;
948 default:
949 arizona_aif_err(dai, "Unsupported master mode %d\n",
950 fmt & SND_SOC_DAIFMT_MASTER_MASK);
951 return -EINVAL;
952 }
953
954 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
955 case SND_SOC_DAIFMT_NB_NF:
956 break;
957 case SND_SOC_DAIFMT_IB_IF:
958 bclk |= ARIZONA_AIF1_BCLK_INV;
959 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
960 break;
961 case SND_SOC_DAIFMT_IB_NF:
962 bclk |= ARIZONA_AIF1_BCLK_INV;
963 break;
964 case SND_SOC_DAIFMT_NB_IF:
965 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
966 break;
967 default:
968 return -EINVAL;
969 }
970
Mark Brown3c43c692013-12-12 00:49:22 +0000971 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_BCLK_CTRL,
972 ARIZONA_AIF1_BCLK_INV |
973 ARIZONA_AIF1_BCLK_MSTR,
974 bclk);
975 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_TX_PIN_CTRL,
976 ARIZONA_AIF1TX_LRCLK_INV |
977 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
978 regmap_update_bits_async(arizona->regmap,
979 base + ARIZONA_AIF_RX_PIN_CTRL,
980 ARIZONA_AIF1RX_LRCLK_INV |
981 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
982 regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FORMAT,
983 ARIZONA_AIF1_FMT_MASK, mode);
Mark Brown07ed8732012-06-18 21:08:44 +0100984
985 return 0;
986}
987
Mark Brown949e6bc2012-07-04 18:58:04 +0100988static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100989 -1,
990 48000,
991 64000,
992 96000,
993 128000,
994 192000,
995 256000,
996 384000,
997 512000,
998 768000,
999 1024000,
1000 1536000,
1001 2048000,
1002 3072000,
1003 4096000,
1004 6144000,
1005 8192000,
1006 12288000,
1007 24576000,
1008};
1009
Mark Brown5b2eec32012-07-04 17:32:05 +01001010static const unsigned int arizona_48k_rates[] = {
1011 12000,
1012 24000,
1013 48000,
1014 96000,
1015 192000,
1016 384000,
1017 768000,
1018 4000,
1019 8000,
1020 16000,
1021 32000,
1022 64000,
1023 128000,
1024 256000,
1025 512000,
1026};
1027
1028static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = {
1029 .count = ARRAY_SIZE(arizona_48k_rates),
1030 .list = arizona_48k_rates,
1031};
1032
Mark Brown949e6bc2012-07-04 18:58:04 +01001033static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001034 -1,
1035 44100,
1036 58800,
1037 88200,
1038 117600,
1039 177640,
1040 235200,
1041 352800,
1042 470400,
1043 705600,
1044 940800,
1045 1411200,
1046 1881600,
Heather Lomond4758be32012-09-05 05:02:10 -04001047 2822400,
Mark Brown07ed8732012-06-18 21:08:44 +01001048 3763200,
1049 5644800,
1050 7526400,
1051 11289600,
1052 22579200,
1053};
1054
Mark Brown5b2eec32012-07-04 17:32:05 +01001055static const unsigned int arizona_44k1_rates[] = {
1056 11025,
1057 22050,
1058 44100,
1059 88200,
1060 176400,
1061 352800,
1062 705600,
1063};
1064
1065static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = {
1066 .count = ARRAY_SIZE(arizona_44k1_rates),
1067 .list = arizona_44k1_rates,
1068};
1069
Mark Brown07ed8732012-06-18 21:08:44 +01001070static int arizona_sr_vals[] = {
1071 0,
1072 12000,
1073 24000,
1074 48000,
1075 96000,
1076 192000,
1077 384000,
1078 768000,
1079 0,
1080 11025,
1081 22050,
1082 44100,
1083 88200,
1084 176400,
1085 352800,
1086 705600,
1087 4000,
1088 8000,
1089 16000,
1090 32000,
1091 64000,
1092 128000,
1093 256000,
1094 512000,
1095};
1096
Mark Brown5b2eec32012-07-04 17:32:05 +01001097static int arizona_startup(struct snd_pcm_substream *substream,
1098 struct snd_soc_dai *dai)
1099{
1100 struct snd_soc_codec *codec = dai->codec;
1101 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1102 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
1103 const struct snd_pcm_hw_constraint_list *constraint;
1104 unsigned int base_rate;
1105
1106 switch (dai_priv->clk) {
1107 case ARIZONA_CLK_SYSCLK:
1108 base_rate = priv->sysclk;
1109 break;
1110 case ARIZONA_CLK_ASYNCCLK:
1111 base_rate = priv->asyncclk;
1112 break;
1113 default:
1114 return 0;
1115 }
1116
Mark Brownf2c26d42013-01-21 16:09:36 +09001117 if (base_rate == 0)
1118 return 0;
1119
Mark Brown5b2eec32012-07-04 17:32:05 +01001120 if (base_rate % 8000)
1121 constraint = &arizona_44k1_constraint;
1122 else
1123 constraint = &arizona_48k_constraint;
1124
1125 return snd_pcm_hw_constraint_list(substream->runtime, 0,
1126 SNDRV_PCM_HW_PARAM_RATE,
1127 constraint);
1128}
1129
Mark Brownb272efc2012-10-10 15:10:08 +09001130static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
1131 struct snd_pcm_hw_params *params,
1132 struct snd_soc_dai *dai)
Mark Brown07ed8732012-06-18 21:08:44 +01001133{
1134 struct snd_soc_codec *codec = dai->codec;
Mark Brownc013b272012-07-04 20:05:57 +01001135 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1136 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown07ed8732012-06-18 21:08:44 +01001137 int base = dai->driver->base;
Mark Brownb272efc2012-10-10 15:10:08 +09001138 int i, sr_val;
1139
1140 /*
1141 * We will need to be more flexible than this in future,
1142 * currently we use a single sample rate for SYSCLK.
1143 */
1144 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
1145 if (arizona_sr_vals[i] == params_rate(params))
1146 break;
1147 if (i == ARRAY_SIZE(arizona_sr_vals)) {
1148 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1149 params_rate(params));
1150 return -EINVAL;
1151 }
1152 sr_val = i;
1153
1154 switch (dai_priv->clk) {
1155 case ARIZONA_CLK_SYSCLK:
1156 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
1157 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
1158 if (base)
1159 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1160 ARIZONA_AIF1_RATE_MASK, 0);
1161 break;
1162 case ARIZONA_CLK_ASYNCCLK:
1163 snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
1164 ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val);
1165 if (base)
1166 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1167 ARIZONA_AIF1_RATE_MASK,
1168 8 << ARIZONA_AIF1_RATE_SHIFT);
1169 break;
1170 default:
1171 arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
1172 return -EINVAL;
1173 }
1174
1175 return 0;
1176}
1177
Mark Brown07ed8732012-06-18 21:08:44 +01001178static int arizona_hw_params(struct snd_pcm_substream *substream,
1179 struct snd_pcm_hw_params *params,
1180 struct snd_soc_dai *dai)
1181{
1182 struct snd_soc_codec *codec = dai->codec;
1183 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brownc94aa302013-01-17 16:35:14 +09001184 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +01001185 int base = dai->driver->base;
1186 const int *rates;
Mark Brown76bf9692013-03-05 14:17:47 +08001187 int i, ret, val;
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001188 int channels = params_channels(params);
Mark Brownc94aa302013-01-17 16:35:14 +09001189 int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001190 int tdm_width = arizona->tdm_width[dai->id - 1];
1191 int tdm_slots = arizona->tdm_slots[dai->id - 1];
Mark Brownc94aa302013-01-17 16:35:14 +09001192 int bclk, lrclk, wl, frame, bclk_target;
Mark Brown07ed8732012-06-18 21:08:44 +01001193
1194 if (params_rate(params) % 8000)
Mark Brown949e6bc2012-07-04 18:58:04 +01001195 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001196 else
Mark Brown949e6bc2012-07-04 18:58:04 +01001197 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001198
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001199 if (tdm_slots) {
1200 arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n",
1201 tdm_slots, tdm_width);
1202 bclk_target = tdm_slots * tdm_width * params_rate(params);
1203 channels = tdm_slots;
1204 } else {
1205 bclk_target = snd_soc_params_to_bclk(params);
1206 }
1207
1208 if (chan_limit && chan_limit < channels) {
Mark Brownc94aa302013-01-17 16:35:14 +09001209 arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001210 bclk_target /= channels;
Mark Brownc94aa302013-01-17 16:35:14 +09001211 bclk_target *= chan_limit;
1212 }
1213
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001214 /* Force multiple of 2 channels for I2S mode */
Mark Brown76bf9692013-03-05 14:17:47 +08001215 val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001216 if ((channels & 1) && (val & ARIZONA_AIF1_FMT_MASK)) {
Mark Brown76bf9692013-03-05 14:17:47 +08001217 arizona_aif_dbg(dai, "Forcing stereo mode\n");
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001218 bclk_target /= channels;
1219 bclk_target *= channels + 1;
Mark Brown76bf9692013-03-05 14:17:47 +08001220 }
1221
Mark Brown949e6bc2012-07-04 18:58:04 +01001222 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brownc94aa302013-01-17 16:35:14 +09001223 if (rates[i] >= bclk_target &&
Mark Brown50017652012-07-04 19:07:09 +01001224 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +01001225 bclk = i;
1226 break;
1227 }
1228 }
Mark Brown949e6bc2012-07-04 18:58:04 +01001229 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001230 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1231 params_rate(params));
1232 return -EINVAL;
1233 }
1234
Mark Brownb59e0f82013-01-17 14:15:59 +09001235 lrclk = rates[bclk] / params_rate(params);
Mark Brown07ed8732012-06-18 21:08:44 +01001236
1237 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
1238 rates[bclk], rates[bclk] / lrclk);
1239
1240 wl = snd_pcm_format_width(params_format(params));
1241 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl;
1242
Mark Brownb272efc2012-10-10 15:10:08 +09001243 ret = arizona_hw_params_rate(substream, params, dai);
1244 if (ret != 0)
1245 return ret;
Mark Brownc013b272012-07-04 20:05:57 +01001246
Mark Brown3c43c692013-12-12 00:49:22 +00001247 regmap_update_bits_async(arizona->regmap,
1248 base + ARIZONA_AIF_BCLK_CTRL,
1249 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
1250 regmap_update_bits_async(arizona->regmap,
1251 base + ARIZONA_AIF_TX_BCLK_RATE,
1252 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
1253 regmap_update_bits_async(arizona->regmap,
1254 base + ARIZONA_AIF_RX_BCLK_RATE,
1255 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
1256 regmap_update_bits_async(arizona->regmap,
1257 base + ARIZONA_AIF_FRAME_CTRL_1,
1258 ARIZONA_AIF1TX_WL_MASK |
1259 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
1260 regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FRAME_CTRL_2,
1261 ARIZONA_AIF1RX_WL_MASK |
1262 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
Mark Brown07ed8732012-06-18 21:08:44 +01001263
1264 return 0;
1265}
1266
Mark Brown410837a2012-07-05 17:26:59 +01001267static const char *arizona_dai_clk_str(int clk_id)
1268{
1269 switch (clk_id) {
1270 case ARIZONA_CLK_SYSCLK:
1271 return "SYSCLK";
1272 case ARIZONA_CLK_ASYNCCLK:
1273 return "ASYNCCLK";
1274 default:
1275 return "Unknown clock";
1276 }
1277}
1278
Mark Brown5b2eec32012-07-04 17:32:05 +01001279static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
1280 int clk_id, unsigned int freq, int dir)
1281{
1282 struct snd_soc_codec *codec = dai->codec;
1283 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1284 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown410837a2012-07-05 17:26:59 +01001285 struct snd_soc_dapm_route routes[2];
Mark Brown5b2eec32012-07-04 17:32:05 +01001286
1287 switch (clk_id) {
1288 case ARIZONA_CLK_SYSCLK:
1289 case ARIZONA_CLK_ASYNCCLK:
1290 break;
1291 default:
1292 return -EINVAL;
1293 }
1294
Mark Brown410837a2012-07-05 17:26:59 +01001295 if (clk_id == dai_priv->clk)
1296 return 0;
1297
1298 if (dai->active) {
Mark Brown5b2eec32012-07-04 17:32:05 +01001299 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
1300 dai->id);
1301 return -EBUSY;
1302 }
1303
Mark Brownc8d35a62012-12-07 12:49:40 +09001304 dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1,
1305 arizona_dai_clk_str(clk_id));
1306
Mark Brown410837a2012-07-05 17:26:59 +01001307 memset(&routes, 0, sizeof(routes));
1308 routes[0].sink = dai->driver->capture.stream_name;
1309 routes[1].sink = dai->driver->playback.stream_name;
Mark Brown5b2eec32012-07-04 17:32:05 +01001310
Mark Brown410837a2012-07-05 17:26:59 +01001311 routes[0].source = arizona_dai_clk_str(dai_priv->clk);
1312 routes[1].source = arizona_dai_clk_str(dai_priv->clk);
1313 snd_soc_dapm_del_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
1314
1315 routes[0].source = arizona_dai_clk_str(clk_id);
1316 routes[1].source = arizona_dai_clk_str(clk_id);
1317 snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
1318
Mark Brown0c778e82012-12-06 18:22:25 +09001319 dai_priv->clk = clk_id;
1320
Mark Brown410837a2012-07-05 17:26:59 +01001321 return snd_soc_dapm_sync(&codec->dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +01001322}
1323
Mark Brown01df2592012-12-12 16:22:08 +09001324static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
1325{
1326 struct snd_soc_codec *codec = dai->codec;
1327 int base = dai->driver->base;
1328 unsigned int reg;
1329
1330 if (tristate)
1331 reg = ARIZONA_AIF1_TRI;
1332 else
1333 reg = 0;
1334
1335 return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1336 ARIZONA_AIF1_TRI, reg);
1337}
1338
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001339static void arizona_set_channels_to_mask(struct snd_soc_dai *dai,
1340 unsigned int base,
1341 int channels, unsigned int mask)
1342{
1343 struct snd_soc_codec *codec = dai->codec;
1344 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1345 struct arizona *arizona = priv->arizona;
1346 int slot, i;
1347
1348 for (i = 0; i < channels; ++i) {
1349 slot = ffs(mask) - 1;
1350 if (slot < 0)
1351 return;
1352
1353 regmap_write(arizona->regmap, base + i, slot);
1354
1355 mask &= ~(1 << slot);
1356 }
1357
1358 if (mask)
1359 arizona_aif_warn(dai, "Too many channels in TDM mask\n");
1360}
1361
1362static int arizona_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
1363 unsigned int rx_mask, int slots, int slot_width)
1364{
1365 struct snd_soc_codec *codec = dai->codec;
1366 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1367 struct arizona *arizona = priv->arizona;
1368 int base = dai->driver->base;
1369 int rx_max_chan = dai->driver->playback.channels_max;
1370 int tx_max_chan = dai->driver->capture.channels_max;
1371
1372 /* Only support TDM for the physical AIFs */
1373 if (dai->id > ARIZONA_MAX_AIF)
1374 return -ENOTSUPP;
1375
1376 if (slots == 0) {
1377 tx_mask = (1 << tx_max_chan) - 1;
1378 rx_mask = (1 << rx_max_chan) - 1;
1379 }
1380
1381 arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_3,
1382 tx_max_chan, tx_mask);
1383 arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_11,
1384 rx_max_chan, rx_mask);
1385
1386 arizona->tdm_width[dai->id - 1] = slot_width;
1387 arizona->tdm_slots[dai->id - 1] = slots;
1388
1389 return 0;
1390}
1391
Mark Brown07ed8732012-06-18 21:08:44 +01001392const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +01001393 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +01001394 .set_fmt = arizona_set_fmt,
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001395 .set_tdm_slot = arizona_set_tdm_slot,
Mark Brown07ed8732012-06-18 21:08:44 +01001396 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +01001397 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown01df2592012-12-12 16:22:08 +09001398 .set_tristate = arizona_set_tristate,
Mark Brown07ed8732012-06-18 21:08:44 +01001399};
Mark Browna8379872012-07-09 12:16:41 +01001400EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +01001401
Mark Brownbd1dd882013-05-17 13:29:03 +01001402const struct snd_soc_dai_ops arizona_simple_dai_ops = {
1403 .startup = arizona_startup,
1404 .hw_params = arizona_hw_params_rate,
1405 .set_sysclk = arizona_dai_set_sysclk,
1406};
1407EXPORT_SYMBOL_GPL(arizona_simple_dai_ops);
1408
Mark Brown5b2eec32012-07-04 17:32:05 +01001409int arizona_init_dai(struct arizona_priv *priv, int id)
1410{
1411 struct arizona_dai_priv *dai_priv = &priv->dai[id];
1412
1413 dai_priv->clk = ARIZONA_CLK_SYSCLK;
1414
1415 return 0;
1416}
1417EXPORT_SYMBOL_GPL(arizona_init_dai);
1418
Mark Brown07ed8732012-06-18 21:08:44 +01001419static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
1420{
1421 struct arizona_fll *fll = data;
1422
1423 arizona_fll_dbg(fll, "clock OK\n");
1424
1425 complete(&fll->ok);
1426
1427 return IRQ_HANDLED;
1428}
1429
1430static struct {
1431 unsigned int min;
1432 unsigned int max;
1433 u16 fratio;
1434 int ratio;
1435} fll_fratios[] = {
1436 { 0, 64000, 4, 16 },
1437 { 64000, 128000, 3, 8 },
1438 { 128000, 256000, 2, 4 },
1439 { 256000, 1000000, 1, 2 },
1440 { 1000000, 13500000, 0, 1 },
1441};
1442
Mark Brown8f113d72013-03-05 12:08:57 +08001443static struct {
1444 unsigned int min;
1445 unsigned int max;
1446 u16 gain;
1447} fll_gains[] = {
1448 { 0, 256000, 0 },
1449 { 256000, 1000000, 2 },
1450 { 1000000, 13500000, 4 },
1451};
1452
Mark Brown07ed8732012-06-18 21:08:44 +01001453struct arizona_fll_cfg {
1454 int n;
1455 int theta;
1456 int lambda;
1457 int refdiv;
1458 int outdiv;
1459 int fratio;
Mark Brown8f113d72013-03-05 12:08:57 +08001460 int gain;
Mark Brown07ed8732012-06-18 21:08:44 +01001461};
1462
Charles Keepax23f785a82014-03-07 16:34:20 +00001463static int arizona_validate_fll(struct arizona_fll *fll,
1464 unsigned int Fref,
1465 unsigned int Fout)
1466{
1467 unsigned int Fvco_min;
1468
1469 if (Fref / ARIZONA_FLL_MAX_REFDIV > ARIZONA_FLL_MAX_FREF) {
1470 arizona_fll_err(fll,
1471 "Can't scale %dMHz in to <=13.5MHz\n",
1472 Fref);
1473 return -EINVAL;
1474 }
1475
1476 Fvco_min = ARIZONA_FLL_MIN_FVCO * fll->vco_mult;
1477 if (Fout * ARIZONA_FLL_MAX_OUTDIV < Fvco_min) {
1478 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
1479 Fout);
1480 return -EINVAL;
1481 }
1482
1483 return 0;
1484}
1485
Charles Keepaxd0800342014-03-07 16:34:25 +00001486static int arizona_find_fratio(unsigned int Fref, int *fratio)
1487{
1488 int i;
1489
1490 /* Find an appropriate FLL_FRATIO */
1491 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
1492 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
1493 if (fratio)
1494 *fratio = fll_fratios[i].fratio;
1495 return fll_fratios[i].ratio;
1496 }
1497 }
1498
1499 return -EINVAL;
1500}
1501
1502static int arizona_calc_fratio(struct arizona_fll *fll,
1503 struct arizona_fll_cfg *cfg,
1504 unsigned int target,
1505 unsigned int Fref, bool sync)
1506{
1507 int init_ratio, ratio;
1508 int refdiv, div;
1509
1510 /* Fref must be <=13.5MHz, find initial refdiv */
1511 div = 1;
1512 cfg->refdiv = 0;
1513 while (Fref > ARIZONA_FLL_MAX_FREF) {
1514 div *= 2;
1515 Fref /= 2;
1516 cfg->refdiv++;
1517
1518 if (div > ARIZONA_FLL_MAX_REFDIV)
1519 return -EINVAL;
1520 }
1521
1522 /* Find an appropriate FLL_FRATIO */
1523 init_ratio = arizona_find_fratio(Fref, &cfg->fratio);
1524 if (init_ratio < 0) {
1525 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
1526 Fref);
1527 return init_ratio;
1528 }
1529
1530 switch (fll->arizona->type) {
1531 case WM5110:
1532 if (fll->arizona->rev < 3 || sync)
1533 return init_ratio;
1534 break;
1535 default:
1536 return init_ratio;
1537 }
1538
1539 cfg->fratio = init_ratio - 1;
1540
1541 /* Adjust FRATIO/refdiv to avoid integer mode if possible */
1542 refdiv = cfg->refdiv;
1543
1544 while (div <= ARIZONA_FLL_MAX_REFDIV) {
1545 for (ratio = init_ratio; ratio <= ARIZONA_FLL_MAX_FRATIO;
1546 ratio++) {
1547 if (target % (ratio * Fref)) {
1548 cfg->refdiv = refdiv;
1549 cfg->fratio = ratio - 1;
1550 return ratio;
1551 }
1552 }
1553
1554 for (ratio = init_ratio - 1; ratio >= 0; ratio--) {
1555 if (ARIZONA_FLL_VCO_CORNER / (fll->vco_mult * ratio) <
1556 Fref)
1557 break;
1558
1559 if (target % (ratio * Fref)) {
1560 cfg->refdiv = refdiv;
1561 cfg->fratio = ratio - 1;
1562 return ratio;
1563 }
1564 }
1565
1566 div *= 2;
1567 Fref /= 2;
1568 refdiv++;
1569 init_ratio = arizona_find_fratio(Fref, NULL);
1570 }
1571
1572 arizona_fll_warn(fll, "Falling back to integer mode operation\n");
1573 return cfg->fratio + 1;
1574}
1575
Mark Brown07ed8732012-06-18 21:08:44 +01001576static int arizona_calc_fll(struct arizona_fll *fll,
1577 struct arizona_fll_cfg *cfg,
Charles Keepaxd0800342014-03-07 16:34:25 +00001578 unsigned int Fref, bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01001579{
1580 unsigned int target, div, gcd_fll;
1581 int i, ratio;
1582
Charles Keepax8ccefcd2014-03-07 16:34:21 +00001583 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, fll->fout);
Mark Brown07ed8732012-06-18 21:08:44 +01001584
Mark Brown2b4d39f2012-07-10 17:03:46 +01001585 /* Fvco should be over the targt; don't check the upper bound */
Charles Keepaxf641aec2014-03-07 16:34:22 +00001586 div = ARIZONA_FLL_MIN_OUTDIV;
1587 while (fll->fout * div < ARIZONA_FLL_MIN_FVCO * fll->vco_mult) {
Mark Brown07ed8732012-06-18 21:08:44 +01001588 div++;
Charles Keepaxf641aec2014-03-07 16:34:22 +00001589 if (div > ARIZONA_FLL_MAX_OUTDIV)
Mark Brown07ed8732012-06-18 21:08:44 +01001590 return -EINVAL;
Mark Brown07ed8732012-06-18 21:08:44 +01001591 }
Charles Keepaxf641aec2014-03-07 16:34:22 +00001592 target = fll->fout * div / fll->vco_mult;
Mark Brown07ed8732012-06-18 21:08:44 +01001593 cfg->outdiv = div;
1594
1595 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
1596
Charles Keepaxd0800342014-03-07 16:34:25 +00001597 /* Find an appropriate FLL_FRATIO and refdiv */
1598 ratio = arizona_calc_fratio(fll, cfg, target, Fref, sync);
1599 if (ratio < 0)
1600 return ratio;
Mark Brown07ed8732012-06-18 21:08:44 +01001601
Mark Brown07ed8732012-06-18 21:08:44 +01001602 /* Apply the division for our remaining calculations */
Charles Keepaxd0800342014-03-07 16:34:25 +00001603 Fref = Fref / (1 << cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08001604
Mark Brown07ed8732012-06-18 21:08:44 +01001605 cfg->n = target / (ratio * Fref);
1606
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001607 if (target % (ratio * Fref)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001608 gcd_fll = gcd(target, ratio * Fref);
1609 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
1610
1611 cfg->theta = (target - (cfg->n * ratio * Fref))
1612 / gcd_fll;
1613 cfg->lambda = (ratio * Fref) / gcd_fll;
1614 } else {
1615 cfg->theta = 0;
1616 cfg->lambda = 0;
1617 }
1618
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001619 /* Round down to 16bit range with cost of accuracy lost.
1620 * Denominator must be bigger than numerator so we only
1621 * take care of it.
1622 */
1623 while (cfg->lambda >= (1 << 16)) {
1624 cfg->theta >>= 1;
1625 cfg->lambda >>= 1;
1626 }
1627
Charles Keepax5a3935c2014-03-07 16:34:23 +00001628 for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
1629 if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
1630 cfg->gain = fll_gains[i].gain;
1631 break;
1632 }
1633 }
1634 if (i == ARRAY_SIZE(fll_gains)) {
1635 arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
1636 Fref);
1637 return -EINVAL;
1638 }
1639
Mark Brown07ed8732012-06-18 21:08:44 +01001640 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
1641 cfg->n, cfg->theta, cfg->lambda);
1642 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
1643 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08001644 arizona_fll_dbg(fll, "GAIN=%d\n", cfg->gain);
Mark Brown07ed8732012-06-18 21:08:44 +01001645
1646 return 0;
1647
1648}
1649
1650static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
Mark Brown8f113d72013-03-05 12:08:57 +08001651 struct arizona_fll_cfg *cfg, int source,
1652 bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01001653{
Mark Brown3c43c692013-12-12 00:49:22 +00001654 regmap_update_bits_async(arizona->regmap, base + 3,
1655 ARIZONA_FLL1_THETA_MASK, cfg->theta);
1656 regmap_update_bits_async(arizona->regmap, base + 4,
1657 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
1658 regmap_update_bits_async(arizona->regmap, base + 5,
1659 ARIZONA_FLL1_FRATIO_MASK,
1660 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
1661 regmap_update_bits_async(arizona->regmap, base + 6,
1662 ARIZONA_FLL1_CLK_REF_DIV_MASK |
1663 ARIZONA_FLL1_CLK_REF_SRC_MASK,
1664 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
1665 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
Mark Brown07ed8732012-06-18 21:08:44 +01001666
Charles Keepax61719db2014-03-07 16:34:19 +00001667 if (sync) {
1668 regmap_update_bits(arizona->regmap, base + 0x7,
1669 ARIZONA_FLL1_GAIN_MASK,
1670 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
1671 } else {
1672 regmap_update_bits(arizona->regmap, base + 0x5,
1673 ARIZONA_FLL1_OUTDIV_MASK,
1674 cfg->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
1675 regmap_update_bits(arizona->regmap, base + 0x9,
1676 ARIZONA_FLL1_GAIN_MASK,
1677 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
1678 }
Mark Brown8f113d72013-03-05 12:08:57 +08001679
Mark Brown3c43c692013-12-12 00:49:22 +00001680 regmap_update_bits_async(arizona->regmap, base + 2,
1681 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
1682 ARIZONA_FLL1_CTRL_UPD | cfg->n);
Mark Brown07ed8732012-06-18 21:08:44 +01001683}
1684
Charles Keepaxd122d6c2013-02-20 17:28:36 +00001685static bool arizona_is_enabled_fll(struct arizona_fll *fll)
1686{
1687 struct arizona *arizona = fll->arizona;
1688 unsigned int reg;
1689 int ret;
1690
1691 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
1692 if (ret != 0) {
1693 arizona_fll_err(fll, "Failed to read current state: %d\n",
1694 ret);
1695 return ret;
1696 }
1697
1698 return reg & ARIZONA_FLL1_ENA;
1699}
1700
Charles Keepax23f785a82014-03-07 16:34:20 +00001701static void arizona_enable_fll(struct arizona_fll *fll)
Charles Keepax35722812013-02-20 17:28:38 +00001702{
1703 struct arizona *arizona = fll->arizona;
1704 int ret;
Charles Keepax49c60542013-09-16 15:34:35 +01001705 bool use_sync = false;
Charles Keepax23f785a82014-03-07 16:34:20 +00001706 struct arizona_fll_cfg cfg;
Charles Keepax35722812013-02-20 17:28:38 +00001707
Mark Brownff680a12013-03-04 16:00:19 +08001708 /*
1709 * If we have both REFCLK and SYNCCLK then enable both,
1710 * otherwise apply the SYNCCLK settings to REFCLK.
1711 */
Charles Keepax49c60542013-09-16 15:34:35 +01001712 if (fll->ref_src >= 0 && fll->ref_freq &&
1713 fll->ref_src != fll->sync_src) {
Charles Keepaxd0800342014-03-07 16:34:25 +00001714 arizona_calc_fll(fll, &cfg, fll->ref_freq, false);
Charles Keepax35722812013-02-20 17:28:38 +00001715
Charles Keepax23f785a82014-03-07 16:34:20 +00001716 arizona_apply_fll(arizona, fll->base, &cfg, fll->ref_src,
Mark Brown8f113d72013-03-05 12:08:57 +08001717 false);
Charles Keepax49c60542013-09-16 15:34:35 +01001718 if (fll->sync_src >= 0) {
Charles Keepaxd0800342014-03-07 16:34:25 +00001719 arizona_calc_fll(fll, &cfg, fll->sync_freq, true);
Charles Keepax23f785a82014-03-07 16:34:20 +00001720
1721 arizona_apply_fll(arizona, fll->base + 0x10, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08001722 fll->sync_src, true);
Charles Keepax49c60542013-09-16 15:34:35 +01001723 use_sync = true;
1724 }
Mark Brownff680a12013-03-04 16:00:19 +08001725 } else if (fll->sync_src >= 0) {
Charles Keepaxd0800342014-03-07 16:34:25 +00001726 arizona_calc_fll(fll, &cfg, fll->sync_freq, false);
Mark Brownff680a12013-03-04 16:00:19 +08001727
Charles Keepax23f785a82014-03-07 16:34:20 +00001728 arizona_apply_fll(arizona, fll->base, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08001729 fll->sync_src, false);
Mark Browneca2e8e2013-03-06 00:09:59 +08001730
Mark Brown3c43c692013-12-12 00:49:22 +00001731 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
1732 ARIZONA_FLL1_SYNC_ENA, 0);
Mark Brownff680a12013-03-04 16:00:19 +08001733 } else {
1734 arizona_fll_err(fll, "No clocks provided\n");
1735 return;
1736 }
Charles Keepax35722812013-02-20 17:28:38 +00001737
Mark Brown576411be2013-03-05 12:07:16 +08001738 /*
1739 * Increase the bandwidth if we're not using a low frequency
1740 * sync source.
1741 */
Charles Keepax49c60542013-09-16 15:34:35 +01001742 if (use_sync && fll->sync_freq > 100000)
Mark Brown3c43c692013-12-12 00:49:22 +00001743 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
1744 ARIZONA_FLL1_SYNC_BW, 0);
Mark Brown576411be2013-03-05 12:07:16 +08001745 else
Mark Brown3c43c692013-12-12 00:49:22 +00001746 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
1747 ARIZONA_FLL1_SYNC_BW,
1748 ARIZONA_FLL1_SYNC_BW);
Mark Brown576411be2013-03-05 12:07:16 +08001749
Charles Keepax35722812013-02-20 17:28:38 +00001750 if (!arizona_is_enabled_fll(fll))
1751 pm_runtime_get(arizona->dev);
1752
1753 /* Clear any pending completions */
1754 try_wait_for_completion(&fll->ok);
1755
Mark Brown3c43c692013-12-12 00:49:22 +00001756 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1757 ARIZONA_FLL1_FREERUN, 0);
1758 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1759 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
Charles Keepax49c60542013-09-16 15:34:35 +01001760 if (use_sync)
Mark Brown3c43c692013-12-12 00:49:22 +00001761 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
1762 ARIZONA_FLL1_SYNC_ENA,
1763 ARIZONA_FLL1_SYNC_ENA);
Charles Keepax35722812013-02-20 17:28:38 +00001764
1765 ret = wait_for_completion_timeout(&fll->ok,
1766 msecs_to_jiffies(250));
1767 if (ret == 0)
1768 arizona_fll_warn(fll, "Timed out waiting for lock\n");
1769}
1770
Charles Keepax76040542013-02-20 17:28:37 +00001771static void arizona_disable_fll(struct arizona_fll *fll)
1772{
1773 struct arizona *arizona = fll->arizona;
1774 bool change;
1775
Mark Brown3c43c692013-12-12 00:49:22 +00001776 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1777 ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
Charles Keepax76040542013-02-20 17:28:37 +00001778 regmap_update_bits_check(arizona->regmap, fll->base + 1,
1779 ARIZONA_FLL1_ENA, 0, &change);
1780 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1781 ARIZONA_FLL1_SYNC_ENA, 0);
1782
1783 if (change)
1784 pm_runtime_put_autosuspend(arizona->dev);
1785}
1786
Charles Keepaxee929a92013-02-20 17:28:40 +00001787int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
1788 unsigned int Fref, unsigned int Fout)
1789{
Charles Keepaxee929a92013-02-20 17:28:40 +00001790 int ret;
1791
Charles Keepax1c5617f2013-02-22 17:10:37 +00001792 if (fll->ref_src == source && fll->ref_freq == Fref)
Charles Keepaxee929a92013-02-20 17:28:40 +00001793 return 0;
1794
Charles Keepax23f785a82014-03-07 16:34:20 +00001795 if (fll->fout && Fref > 0) {
1796 ret = arizona_validate_fll(fll, Fref, fll->fout);
1797 if (ret != 0)
1798 return ret;
Charles Keepaxee929a92013-02-20 17:28:40 +00001799 }
1800
1801 fll->ref_src = source;
1802 fll->ref_freq = Fref;
Charles Keepaxee929a92013-02-20 17:28:40 +00001803
Mark Brown86cd6842013-03-07 16:14:04 +08001804 if (fll->fout && Fref > 0) {
Charles Keepax23f785a82014-03-07 16:34:20 +00001805 arizona_enable_fll(fll);
Charles Keepaxee929a92013-02-20 17:28:40 +00001806 }
1807
1808 return 0;
1809}
1810EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
1811
Mark Brown07ed8732012-06-18 21:08:44 +01001812int arizona_set_fll(struct arizona_fll *fll, int source,
1813 unsigned int Fref, unsigned int Fout)
1814{
Mark Brown07ed8732012-06-18 21:08:44 +01001815 int ret;
1816
Mark Brownff680a12013-03-04 16:00:19 +08001817 if (fll->sync_src == source &&
1818 fll->sync_freq == Fref && fll->fout == Fout)
1819 return 0;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00001820
Mark Brownff680a12013-03-04 16:00:19 +08001821 if (Fout) {
1822 if (fll->ref_src >= 0) {
Charles Keepax23f785a82014-03-07 16:34:20 +00001823 ret = arizona_validate_fll(fll, fll->ref_freq, Fout);
Charles Keepax9e359c62013-02-20 17:28:35 +00001824 if (ret != 0)
1825 return ret;
1826 }
1827
Charles Keepax23f785a82014-03-07 16:34:20 +00001828 ret = arizona_validate_fll(fll, Fref, Fout);
Mark Brownff680a12013-03-04 16:00:19 +08001829 if (ret != 0)
1830 return ret;
Charles Keepax9e359c62013-02-20 17:28:35 +00001831 }
Mark Brownff680a12013-03-04 16:00:19 +08001832
1833 fll->sync_src = source;
1834 fll->sync_freq = Fref;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00001835 fll->fout = Fout;
Charles Keepax9e359c62013-02-20 17:28:35 +00001836
Mark Brown07ed8732012-06-18 21:08:44 +01001837 if (Fout) {
Charles Keepax23f785a82014-03-07 16:34:20 +00001838 arizona_enable_fll(fll);
Mark Brown07ed8732012-06-18 21:08:44 +01001839 } else {
Charles Keepax76040542013-02-20 17:28:37 +00001840 arizona_disable_fll(fll);
Mark Brown07ed8732012-06-18 21:08:44 +01001841 }
1842
Mark Brown07ed8732012-06-18 21:08:44 +01001843 return 0;
1844}
1845EXPORT_SYMBOL_GPL(arizona_set_fll);
1846
1847int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
1848 int ok_irq, struct arizona_fll *fll)
1849{
1850 int ret;
Charles Keepax19b34bd2013-02-20 17:28:34 +00001851 unsigned int val;
Mark Brown07ed8732012-06-18 21:08:44 +01001852
Mark Brown07ed8732012-06-18 21:08:44 +01001853 init_completion(&fll->ok);
1854
1855 fll->id = id;
1856 fll->base = base;
1857 fll->arizona = arizona;
Charles Keepaxf3f11632013-02-20 17:28:41 +00001858 fll->sync_src = ARIZONA_FLL_SRC_NONE;
Mark Brown07ed8732012-06-18 21:08:44 +01001859
Charles Keepax19b34bd2013-02-20 17:28:34 +00001860 /* Configure default refclk to 32kHz if we have one */
1861 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
1862 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
1863 case ARIZONA_CLK_SRC_MCLK1:
1864 case ARIZONA_CLK_SRC_MCLK2:
1865 fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK;
1866 break;
1867 default:
Charles Keepaxf3f11632013-02-20 17:28:41 +00001868 fll->ref_src = ARIZONA_FLL_SRC_NONE;
Charles Keepax19b34bd2013-02-20 17:28:34 +00001869 }
1870 fll->ref_freq = 32768;
1871
Mark Brown07ed8732012-06-18 21:08:44 +01001872 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
1873 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
1874 "FLL%d clock OK", id);
1875
Mark Brown07ed8732012-06-18 21:08:44 +01001876 ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
1877 arizona_fll_clock_ok, fll);
1878 if (ret != 0) {
1879 dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
1880 id, ret);
1881 }
1882
Charles Keepaxe31c1942013-01-07 16:41:45 +00001883 regmap_update_bits(arizona->regmap, fll->base + 1,
1884 ARIZONA_FLL1_FREERUN, 0);
1885
Mark Brown07ed8732012-06-18 21:08:44 +01001886 return 0;
1887}
1888EXPORT_SYMBOL_GPL(arizona_init_fll);
1889
Mark Brownbc9ab6d2013-01-04 19:31:00 +00001890/**
1891 * arizona_set_output_mode - Set the mode of the specified output
1892 *
1893 * @codec: Device to configure
1894 * @output: Output number
1895 * @diff: True to set the output to differential mode
1896 *
1897 * Some systems use external analogue switches to connect more
1898 * analogue devices to the CODEC than are supported by the device. In
1899 * some systems this requires changing the switched output from single
1900 * ended to differential mode dynamically at runtime, an operation
1901 * supported using this function.
1902 *
1903 * Most systems have a single static configuration and should use
1904 * platform data instead.
1905 */
1906int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
1907{
1908 unsigned int reg, val;
1909
1910 if (output < 1 || output > 6)
1911 return -EINVAL;
1912
1913 reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
1914
1915 if (diff)
1916 val = ARIZONA_OUT1_MONO;
1917 else
1918 val = 0;
1919
1920 return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val);
1921}
1922EXPORT_SYMBOL_GPL(arizona_set_output_mode);
1923
Mark Brown07ed8732012-06-18 21:08:44 +01001924MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
1925MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1926MODULE_LICENSE("GPL");