blob: 0fc3b4b615522fa820edefe900b7f32e509806ee [file] [log] [blame]
Mark Brown07ed8732012-06-18 21:08:44 +01001/*
2 * arizona.c - Wolfson Arizona class device shared support
3 *
4 * Copyright 2012 Wolfson Microelectronics plc
5 *
6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
Mark Brownddbce972013-02-15 17:27:22 +000013#include <linux/delay.h>
Mark Brown07ed8732012-06-18 21:08:44 +010014#include <linux/gcd.h>
15#include <linux/module.h>
16#include <linux/pm_runtime.h>
17#include <sound/pcm.h>
18#include <sound/pcm_params.h>
19#include <sound/tlv.h>
20
21#include <linux/mfd/arizona/core.h>
22#include <linux/mfd/arizona/registers.h>
23
24#include "arizona.h"
25
26#define ARIZONA_AIF_BCLK_CTRL 0x00
27#define ARIZONA_AIF_TX_PIN_CTRL 0x01
28#define ARIZONA_AIF_RX_PIN_CTRL 0x02
29#define ARIZONA_AIF_RATE_CTRL 0x03
30#define ARIZONA_AIF_FORMAT 0x04
31#define ARIZONA_AIF_TX_BCLK_RATE 0x05
32#define ARIZONA_AIF_RX_BCLK_RATE 0x06
33#define ARIZONA_AIF_FRAME_CTRL_1 0x07
34#define ARIZONA_AIF_FRAME_CTRL_2 0x08
35#define ARIZONA_AIF_FRAME_CTRL_3 0x09
36#define ARIZONA_AIF_FRAME_CTRL_4 0x0A
37#define ARIZONA_AIF_FRAME_CTRL_5 0x0B
38#define ARIZONA_AIF_FRAME_CTRL_6 0x0C
39#define ARIZONA_AIF_FRAME_CTRL_7 0x0D
40#define ARIZONA_AIF_FRAME_CTRL_8 0x0E
41#define ARIZONA_AIF_FRAME_CTRL_9 0x0F
42#define ARIZONA_AIF_FRAME_CTRL_10 0x10
43#define ARIZONA_AIF_FRAME_CTRL_11 0x11
44#define ARIZONA_AIF_FRAME_CTRL_12 0x12
45#define ARIZONA_AIF_FRAME_CTRL_13 0x13
46#define ARIZONA_AIF_FRAME_CTRL_14 0x14
47#define ARIZONA_AIF_FRAME_CTRL_15 0x15
48#define ARIZONA_AIF_FRAME_CTRL_16 0x16
49#define ARIZONA_AIF_FRAME_CTRL_17 0x17
50#define ARIZONA_AIF_FRAME_CTRL_18 0x18
51#define ARIZONA_AIF_TX_ENABLES 0x19
52#define ARIZONA_AIF_RX_ENABLES 0x1A
53#define ARIZONA_AIF_FORCE_WRITE 0x1B
54
Charles Keepaxd0800342014-03-07 16:34:25 +000055#define ARIZONA_FLL_VCO_CORNER 141900000
Charles Keepax87383ac2014-03-07 16:34:18 +000056#define ARIZONA_FLL_MAX_FREF 13500000
57#define ARIZONA_FLL_MIN_FVCO 90000000
Charles Keepaxd0800342014-03-07 16:34:25 +000058#define ARIZONA_FLL_MAX_FRATIO 16
Charles Keepax87383ac2014-03-07 16:34:18 +000059#define ARIZONA_FLL_MAX_REFDIV 8
60#define ARIZONA_FLL_MIN_OUTDIV 2
61#define ARIZONA_FLL_MAX_OUTDIV 7
62
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +000063#define ARIZONA_FMT_DSP_MODE_A 0
64#define ARIZONA_FMT_DSP_MODE_B 1
65#define ARIZONA_FMT_I2S_MODE 2
66#define ARIZONA_FMT_LEFT_JUSTIFIED_MODE 3
67
Mark Brown07ed8732012-06-18 21:08:44 +010068#define arizona_fll_err(_fll, fmt, ...) \
69 dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
70#define arizona_fll_warn(_fll, fmt, ...) \
71 dev_warn(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
72#define arizona_fll_dbg(_fll, fmt, ...) \
Mark Brown9092a6e2013-02-06 17:58:57 +000073 dev_dbg(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
Mark Brown07ed8732012-06-18 21:08:44 +010074
75#define arizona_aif_err(_dai, fmt, ...) \
76 dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
77#define arizona_aif_warn(_dai, fmt, ...) \
78 dev_warn(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
79#define arizona_aif_dbg(_dai, fmt, ...) \
Mark Brown9092a6e2013-02-06 17:58:57 +000080 dev_dbg(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
Mark Brown07ed8732012-06-18 21:08:44 +010081
Mark Brown56447e12013-01-10 14:45:58 +000082static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
83 struct snd_kcontrol *kcontrol,
84 int event)
85{
Lars-Peter Clausen043123f2015-01-13 10:27:07 +010086 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
Mark Brown56447e12013-01-10 14:45:58 +000087 struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
Mark Brownf4a76e72013-03-13 12:22:39 +000088 int val;
Mark Brown56447e12013-01-10 14:45:58 +000089
Mark Brown56447e12013-01-10 14:45:58 +000090 switch (event) {
Mark Brown56447e12013-01-10 14:45:58 +000091 case SND_SOC_DAPM_POST_PMU:
Mark Brownf4a76e72013-03-13 12:22:39 +000092 val = snd_soc_read(codec, ARIZONA_INTERRUPT_RAW_STATUS_3);
Charles Keepaxc0fe2c52014-07-15 11:21:47 +010093 if (val & ARIZONA_SPK_OVERHEAT_STS) {
Mark Brownf4a76e72013-03-13 12:22:39 +000094 dev_crit(arizona->dev,
95 "Speaker not enabled due to temperature\n");
96 return -EBUSY;
97 }
98
Mark Brown3c43c692013-12-12 00:49:22 +000099 regmap_update_bits_async(arizona->regmap,
100 ARIZONA_OUTPUT_ENABLES_1,
101 1 << w->shift, 1 << w->shift);
Mark Brown56447e12013-01-10 14:45:58 +0000102 break;
103 case SND_SOC_DAPM_PRE_PMD:
Mark Brown3c43c692013-12-12 00:49:22 +0000104 regmap_update_bits_async(arizona->regmap,
105 ARIZONA_OUTPUT_ENABLES_1,
106 1 << w->shift, 0);
Mark Brown56447e12013-01-10 14:45:58 +0000107 break;
Charles Keepaxbee261b2015-09-16 13:59:40 +0100108 default:
109 break;
Mark Brown56447e12013-01-10 14:45:58 +0000110 }
111
112 return 0;
113}
114
Mark Brown899817e2013-03-13 12:32:10 +0000115static irqreturn_t arizona_thermal_warn(int irq, void *data)
116{
117 struct arizona *arizona = data;
118 unsigned int val;
119 int ret;
120
121 ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
122 &val);
123 if (ret != 0) {
124 dev_err(arizona->dev, "Failed to read thermal status: %d\n",
125 ret);
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100126 } else if (val & ARIZONA_SPK_OVERHEAT_WARN_STS) {
Mark Brown899817e2013-03-13 12:32:10 +0000127 dev_crit(arizona->dev, "Thermal warning\n");
128 }
129
130 return IRQ_HANDLED;
131}
132
133static irqreturn_t arizona_thermal_shutdown(int irq, void *data)
134{
135 struct arizona *arizona = data;
136 unsigned int val;
137 int ret;
138
139 ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
140 &val);
141 if (ret != 0) {
142 dev_err(arizona->dev, "Failed to read thermal status: %d\n",
143 ret);
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100144 } else if (val & ARIZONA_SPK_OVERHEAT_STS) {
Mark Brown899817e2013-03-13 12:32:10 +0000145 dev_crit(arizona->dev, "Thermal shutdown\n");
Mark Brownf4a76e72013-03-13 12:22:39 +0000146 ret = regmap_update_bits(arizona->regmap,
147 ARIZONA_OUTPUT_ENABLES_1,
148 ARIZONA_OUT4L_ENA |
149 ARIZONA_OUT4R_ENA, 0);
150 if (ret != 0)
151 dev_crit(arizona->dev,
152 "Failed to disable speaker outputs: %d\n",
153 ret);
Mark Brown899817e2013-03-13 12:32:10 +0000154 }
155
156 return IRQ_HANDLED;
157}
158
Mark Brown56447e12013-01-10 14:45:58 +0000159static const struct snd_soc_dapm_widget arizona_spkl =
Mark Brownf4a76e72013-03-13 12:22:39 +0000160 SND_SOC_DAPM_PGA_E("OUT4L", SND_SOC_NOPM,
Mark Brown56447e12013-01-10 14:45:58 +0000161 ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
162 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
163
164static const struct snd_soc_dapm_widget arizona_spkr =
Mark Brownf4a76e72013-03-13 12:22:39 +0000165 SND_SOC_DAPM_PGA_E("OUT4R", SND_SOC_NOPM,
Mark Brown56447e12013-01-10 14:45:58 +0000166 ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
167 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
168
169int arizona_init_spk(struct snd_soc_codec *codec)
170{
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200171 struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
Mark Brown899817e2013-03-13 12:32:10 +0000172 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
173 struct arizona *arizona = priv->arizona;
Mark Brown56447e12013-01-10 14:45:58 +0000174 int ret;
175
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200176 ret = snd_soc_dapm_new_controls(dapm, &arizona_spkl, 1);
Mark Brown56447e12013-01-10 14:45:58 +0000177 if (ret != 0)
178 return ret;
179
Charles Keepax40843ae2013-08-12 23:46:55 +0100180 switch (arizona->type) {
181 case WM8997:
Richard Fitzgerald43b27d72016-04-08 16:50:14 +0100182 case CS47L24:
183 case WM1831:
Charles Keepax40843ae2013-08-12 23:46:55 +0100184 break;
185 default:
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200186 ret = snd_soc_dapm_new_controls(dapm, &arizona_spkr, 1);
Charles Keepax40843ae2013-08-12 23:46:55 +0100187 if (ret != 0)
188 return ret;
189 break;
190 }
Mark Brown56447e12013-01-10 14:45:58 +0000191
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100192 ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN,
Mark Brown899817e2013-03-13 12:32:10 +0000193 "Thermal warning", arizona_thermal_warn,
194 arizona);
195 if (ret != 0)
196 dev_err(arizona->dev,
197 "Failed to get thermal warning IRQ: %d\n",
198 ret);
199
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100200 ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT,
Mark Brown899817e2013-03-13 12:32:10 +0000201 "Thermal shutdown", arizona_thermal_shutdown,
202 arizona);
203 if (ret != 0)
204 dev_err(arizona->dev,
205 "Failed to get thermal shutdown IRQ: %d\n",
206 ret);
207
Mark Brown56447e12013-01-10 14:45:58 +0000208 return 0;
209}
210EXPORT_SYMBOL_GPL(arizona_init_spk);
211
Charles Keepax54dca702016-04-15 13:11:56 +0100212int arizona_free_spk(struct snd_soc_codec *codec)
213{
214 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
215 struct arizona *arizona = priv->arizona;
216
217 arizona_free_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN, arizona);
218 arizona_free_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT, arizona);
219
220 return 0;
221}
222EXPORT_SYMBOL_GPL(arizona_free_spk);
223
Charles Keepaxb60f3632014-06-10 18:41:02 +0100224static const struct snd_soc_dapm_route arizona_mono_routes[] = {
225 { "OUT1R", NULL, "OUT1L" },
226 { "OUT2R", NULL, "OUT2L" },
227 { "OUT3R", NULL, "OUT3L" },
228 { "OUT4R", NULL, "OUT4L" },
229 { "OUT5R", NULL, "OUT5L" },
230 { "OUT6R", NULL, "OUT6L" },
231};
232
233int arizona_init_mono(struct snd_soc_codec *codec)
234{
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200235 struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
Charles Keepaxb60f3632014-06-10 18:41:02 +0100236 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
237 struct arizona *arizona = priv->arizona;
238 int i;
239
240 for (i = 0; i < ARIZONA_MAX_OUTPUT; ++i) {
241 if (arizona->pdata.out_mono[i])
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200242 snd_soc_dapm_add_routes(dapm,
Charles Keepaxb60f3632014-06-10 18:41:02 +0100243 &arizona_mono_routes[i], 1);
244 }
245
246 return 0;
247}
248EXPORT_SYMBOL_GPL(arizona_init_mono);
249
Charles Keepaxb63144e2013-07-04 08:56:28 +0100250int arizona_init_gpio(struct snd_soc_codec *codec)
251{
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200252 struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
Charles Keepaxb63144e2013-07-04 08:56:28 +0100253 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
254 struct arizona *arizona = priv->arizona;
255 int i;
256
257 switch (arizona->type) {
258 case WM5110:
Richard Fitzgerald575ef7f2015-01-17 15:21:27 +0000259 case WM8280:
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200260 snd_soc_dapm_disable_pin(dapm, "DRC2 Signal Activity");
Charles Keepaxb79fae62013-07-04 16:53:03 +0100261 break;
262 default:
263 break;
Charles Keepaxb63144e2013-07-04 08:56:28 +0100264 }
265
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200266 snd_soc_dapm_disable_pin(dapm, "DRC1 Signal Activity");
Charles Keepaxb63144e2013-07-04 08:56:28 +0100267
268 for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
269 switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) {
270 case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT:
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200271 snd_soc_dapm_enable_pin(dapm, "DRC1 Signal Activity");
Charles Keepaxb63144e2013-07-04 08:56:28 +0100272 break;
273 case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT:
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200274 snd_soc_dapm_enable_pin(dapm, "DRC2 Signal Activity");
Charles Keepaxb63144e2013-07-04 08:56:28 +0100275 break;
276 default:
277 break;
278 }
279 }
280
281 return 0;
282}
283EXPORT_SYMBOL_GPL(arizona_init_gpio);
284
Charles Keepax2230c492016-05-13 16:45:18 +0100285int arizona_init_notifiers(struct snd_soc_codec *codec)
286{
287 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
288 struct arizona *arizona = priv->arizona;
289
290 BLOCKING_INIT_NOTIFIER_HEAD(&arizona->notifier);
291
292 return 0;
293}
294EXPORT_SYMBOL_GPL(arizona_init_notifiers);
295
Charles Keepax141bc6a2015-12-03 18:15:06 +0000296const char * const arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100297 "None",
298 "Tone Generator 1",
299 "Tone Generator 2",
300 "Haptics",
301 "AEC",
Richard Fitzgerald6ebbce02015-09-28 14:01:09 +0100302 "AEC2",
Mark Brown07ed8732012-06-18 21:08:44 +0100303 "Mic Mute Mixer",
304 "Noise Generator",
305 "IN1L",
306 "IN1R",
307 "IN2L",
308 "IN2R",
309 "IN3L",
310 "IN3R",
Mark Brownc9c56fd2012-07-09 19:09:01 +0100311 "IN4L",
312 "IN4R",
Mark Brown07ed8732012-06-18 21:08:44 +0100313 "AIF1RX1",
314 "AIF1RX2",
315 "AIF1RX3",
316 "AIF1RX4",
317 "AIF1RX5",
318 "AIF1RX6",
319 "AIF1RX7",
320 "AIF1RX8",
321 "AIF2RX1",
322 "AIF2RX2",
Richard Fitzgeralde64001e2013-11-20 13:17:07 +0000323 "AIF2RX3",
324 "AIF2RX4",
325 "AIF2RX5",
326 "AIF2RX6",
Mark Brown07ed8732012-06-18 21:08:44 +0100327 "AIF3RX1",
328 "AIF3RX2",
329 "SLIMRX1",
330 "SLIMRX2",
331 "SLIMRX3",
332 "SLIMRX4",
333 "SLIMRX5",
334 "SLIMRX6",
335 "SLIMRX7",
336 "SLIMRX8",
337 "EQ1",
338 "EQ2",
339 "EQ3",
340 "EQ4",
341 "DRC1L",
342 "DRC1R",
343 "DRC2L",
344 "DRC2R",
345 "LHPF1",
346 "LHPF2",
347 "LHPF3",
348 "LHPF4",
349 "DSP1.1",
350 "DSP1.2",
351 "DSP1.3",
352 "DSP1.4",
353 "DSP1.5",
354 "DSP1.6",
Mark Brownc922cc42012-09-26 16:43:44 +0100355 "DSP2.1",
356 "DSP2.2",
357 "DSP2.3",
358 "DSP2.4",
359 "DSP2.5",
360 "DSP2.6",
361 "DSP3.1",
362 "DSP3.2",
363 "DSP3.3",
364 "DSP3.4",
365 "DSP3.5",
366 "DSP3.6",
367 "DSP4.1",
368 "DSP4.2",
369 "DSP4.3",
370 "DSP4.4",
371 "DSP4.5",
372 "DSP4.6",
Mark Brown07ed8732012-06-18 21:08:44 +0100373 "ASRC1L",
374 "ASRC1R",
375 "ASRC2L",
376 "ASRC2R",
Mark Brown91660bd2012-12-05 20:35:24 +0900377 "ISRC1INT1",
378 "ISRC1INT2",
379 "ISRC1INT3",
380 "ISRC1INT4",
381 "ISRC1DEC1",
382 "ISRC1DEC2",
383 "ISRC1DEC3",
384 "ISRC1DEC4",
385 "ISRC2INT1",
386 "ISRC2INT2",
387 "ISRC2INT3",
388 "ISRC2INT4",
389 "ISRC2DEC1",
390 "ISRC2DEC2",
391 "ISRC2DEC3",
392 "ISRC2DEC4",
393 "ISRC3INT1",
394 "ISRC3INT2",
395 "ISRC3INT3",
396 "ISRC3INT4",
397 "ISRC3DEC1",
398 "ISRC3DEC2",
399 "ISRC3DEC3",
400 "ISRC3DEC4",
Mark Brown07ed8732012-06-18 21:08:44 +0100401};
402EXPORT_SYMBOL_GPL(arizona_mixer_texts);
403
Charles Keepax141bc6a2015-12-03 18:15:06 +0000404unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100405 0x00, /* None */
406 0x04, /* Tone */
407 0x05,
408 0x06, /* Haptics */
409 0x08, /* AEC */
Richard Fitzgerald6ebbce02015-09-28 14:01:09 +0100410 0x09, /* AEC2 */
Mark Brown07ed8732012-06-18 21:08:44 +0100411 0x0c, /* Noise mixer */
412 0x0d, /* Comfort noise */
413 0x10, /* IN1L */
414 0x11,
415 0x12,
416 0x13,
417 0x14,
418 0x15,
Mark Brownc9c56fd2012-07-09 19:09:01 +0100419 0x16,
420 0x17,
Mark Brown07ed8732012-06-18 21:08:44 +0100421 0x20, /* AIF1RX1 */
422 0x21,
423 0x22,
424 0x23,
425 0x24,
426 0x25,
427 0x26,
428 0x27,
429 0x28, /* AIF2RX1 */
430 0x29,
Richard Fitzgeralde64001e2013-11-20 13:17:07 +0000431 0x2a,
432 0x2b,
433 0x2c,
434 0x2d,
Mark Brown07ed8732012-06-18 21:08:44 +0100435 0x30, /* AIF3RX1 */
436 0x31,
437 0x38, /* SLIMRX1 */
438 0x39,
439 0x3a,
440 0x3b,
441 0x3c,
442 0x3d,
443 0x3e,
444 0x3f,
445 0x50, /* EQ1 */
446 0x51,
447 0x52,
448 0x53,
449 0x58, /* DRC1L */
450 0x59,
451 0x5a,
452 0x5b,
453 0x60, /* LHPF1 */
454 0x61,
455 0x62,
456 0x63,
457 0x68, /* DSP1.1 */
458 0x69,
459 0x6a,
460 0x6b,
461 0x6c,
462 0x6d,
Mark Brownc922cc42012-09-26 16:43:44 +0100463 0x70, /* DSP2.1 */
464 0x71,
465 0x72,
466 0x73,
467 0x74,
468 0x75,
469 0x78, /* DSP3.1 */
470 0x79,
471 0x7a,
472 0x7b,
473 0x7c,
474 0x7d,
475 0x80, /* DSP4.1 */
476 0x81,
477 0x82,
478 0x83,
479 0x84,
480 0x85,
Mark Brown07ed8732012-06-18 21:08:44 +0100481 0x90, /* ASRC1L */
482 0x91,
483 0x92,
484 0x93,
Mark Brown91660bd2012-12-05 20:35:24 +0900485 0xa0, /* ISRC1INT1 */
486 0xa1,
487 0xa2,
488 0xa3,
489 0xa4, /* ISRC1DEC1 */
490 0xa5,
491 0xa6,
492 0xa7,
493 0xa8, /* ISRC2DEC1 */
494 0xa9,
495 0xaa,
496 0xab,
497 0xac, /* ISRC2INT1 */
498 0xad,
499 0xae,
500 0xaf,
501 0xb0, /* ISRC3DEC1 */
502 0xb1,
503 0xb2,
504 0xb3,
505 0xb4, /* ISRC3INT1 */
506 0xb5,
507 0xb6,
508 0xb7,
Mark Brown07ed8732012-06-18 21:08:44 +0100509};
510EXPORT_SYMBOL_GPL(arizona_mixer_values);
511
512const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
513EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
514
Richard Fitzgerald6ebbce02015-09-28 14:01:09 +0100515const char * const arizona_sample_rate_text[ARIZONA_SAMPLE_RATE_ENUM_SIZE] = {
516 "12kHz", "24kHz", "48kHz", "96kHz", "192kHz",
517 "11.025kHz", "22.05kHz", "44.1kHz", "88.2kHz", "176.4kHz",
518 "4kHz", "8kHz", "16kHz", "32kHz",
519};
520EXPORT_SYMBOL_GPL(arizona_sample_rate_text);
521
522const unsigned int arizona_sample_rate_val[ARIZONA_SAMPLE_RATE_ENUM_SIZE] = {
523 0x01, 0x02, 0x03, 0x04, 0x05, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
524 0x10, 0x11, 0x12, 0x13,
525};
526EXPORT_SYMBOL_GPL(arizona_sample_rate_val);
527
528const char *arizona_sample_rate_val_to_name(unsigned int rate_val)
529{
530 int i;
531
532 for (i = 0; i < ARRAY_SIZE(arizona_sample_rate_val); ++i) {
533 if (arizona_sample_rate_val[i] == rate_val)
534 return arizona_sample_rate_text[i];
535 }
536
537 return "Illegal";
538}
539EXPORT_SYMBOL_GPL(arizona_sample_rate_val_to_name);
540
Charles Keepax141bc6a2015-12-03 18:15:06 +0000541const char * const arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = {
Mark Browndc914282013-02-18 19:09:23 +0000542 "SYNCCLK rate", "8kHz", "16kHz", "ASYNCCLK rate",
543};
544EXPORT_SYMBOL_GPL(arizona_rate_text);
545
Charles Keepax141bc6a2015-12-03 18:15:06 +0000546const unsigned int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
Mark Browndc914282013-02-18 19:09:23 +0000547 0, 1, 2, 8,
548};
549EXPORT_SYMBOL_GPL(arizona_rate_val);
550
551
Charles Keepaxfbedc8c2013-12-19 09:30:12 +0000552const struct soc_enum arizona_isrc_fsh[] = {
553 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_1,
554 ARIZONA_ISRC1_FSH_SHIFT, 0xf,
555 ARIZONA_RATE_ENUM_SIZE,
556 arizona_rate_text, arizona_rate_val),
557 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_1,
558 ARIZONA_ISRC2_FSH_SHIFT, 0xf,
559 ARIZONA_RATE_ENUM_SIZE,
560 arizona_rate_text, arizona_rate_val),
561 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_1,
562 ARIZONA_ISRC3_FSH_SHIFT, 0xf,
563 ARIZONA_RATE_ENUM_SIZE,
564 arizona_rate_text, arizona_rate_val),
565};
566EXPORT_SYMBOL_GPL(arizona_isrc_fsh);
567
Mark Browndc914282013-02-18 19:09:23 +0000568const struct soc_enum arizona_isrc_fsl[] = {
569 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2,
570 ARIZONA_ISRC1_FSL_SHIFT, 0xf,
571 ARIZONA_RATE_ENUM_SIZE,
572 arizona_rate_text, arizona_rate_val),
573 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_2,
574 ARIZONA_ISRC2_FSL_SHIFT, 0xf,
575 ARIZONA_RATE_ENUM_SIZE,
576 arizona_rate_text, arizona_rate_val),
577 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_2,
578 ARIZONA_ISRC3_FSL_SHIFT, 0xf,
579 ARIZONA_RATE_ENUM_SIZE,
580 arizona_rate_text, arizona_rate_val),
581};
582EXPORT_SYMBOL_GPL(arizona_isrc_fsl);
583
Charles Keepax56d37d82013-12-19 09:30:13 +0000584const struct soc_enum arizona_asrc_rate1 =
585 SOC_VALUE_ENUM_SINGLE(ARIZONA_ASRC_RATE1,
586 ARIZONA_ASRC_RATE1_SHIFT, 0xf,
587 ARIZONA_RATE_ENUM_SIZE - 1,
588 arizona_rate_text, arizona_rate_val);
589EXPORT_SYMBOL_GPL(arizona_asrc_rate1);
590
Charles Keepaxa3178a32016-06-13 13:35:14 +0100591static const char * const arizona_vol_ramp_text[] = {
Mark Browne853a002012-12-09 12:25:52 +0900592 "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
593 "15ms/6dB", "30ms/6dB",
594};
595
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100596SOC_ENUM_SINGLE_DECL(arizona_in_vd_ramp,
597 ARIZONA_INPUT_VOLUME_RAMP,
598 ARIZONA_IN_VD_RAMP_SHIFT,
599 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900600EXPORT_SYMBOL_GPL(arizona_in_vd_ramp);
601
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100602SOC_ENUM_SINGLE_DECL(arizona_in_vi_ramp,
603 ARIZONA_INPUT_VOLUME_RAMP,
604 ARIZONA_IN_VI_RAMP_SHIFT,
605 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900606EXPORT_SYMBOL_GPL(arizona_in_vi_ramp);
607
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100608SOC_ENUM_SINGLE_DECL(arizona_out_vd_ramp,
609 ARIZONA_OUTPUT_VOLUME_RAMP,
610 ARIZONA_OUT_VD_RAMP_SHIFT,
611 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900612EXPORT_SYMBOL_GPL(arizona_out_vd_ramp);
613
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100614SOC_ENUM_SINGLE_DECL(arizona_out_vi_ramp,
615 ARIZONA_OUTPUT_VOLUME_RAMP,
616 ARIZONA_OUT_VI_RAMP_SHIFT,
617 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900618EXPORT_SYMBOL_GPL(arizona_out_vi_ramp);
619
Charles Keepaxa3178a32016-06-13 13:35:14 +0100620static const char * const arizona_lhpf_mode_text[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100621 "Low-pass", "High-pass"
622};
623
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100624SOC_ENUM_SINGLE_DECL(arizona_lhpf1_mode,
625 ARIZONA_HPLPF1_1,
626 ARIZONA_LHPF1_MODE_SHIFT,
627 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100628EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
629
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100630SOC_ENUM_SINGLE_DECL(arizona_lhpf2_mode,
631 ARIZONA_HPLPF2_1,
632 ARIZONA_LHPF2_MODE_SHIFT,
633 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100634EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
635
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100636SOC_ENUM_SINGLE_DECL(arizona_lhpf3_mode,
637 ARIZONA_HPLPF3_1,
638 ARIZONA_LHPF3_MODE_SHIFT,
639 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100640EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
641
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100642SOC_ENUM_SINGLE_DECL(arizona_lhpf4_mode,
643 ARIZONA_HPLPF4_1,
644 ARIZONA_LHPF4_MODE_SHIFT,
645 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100646EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
647
Charles Keepaxa3178a32016-06-13 13:35:14 +0100648static const char * const arizona_ng_hold_text[] = {
Mark Brown845571c2012-12-18 13:47:57 +0000649 "30ms", "120ms", "250ms", "500ms",
650};
651
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100652SOC_ENUM_SINGLE_DECL(arizona_ng_hold,
653 ARIZONA_NOISE_GATE_CONTROL,
654 ARIZONA_NGATE_HOLD_SHIFT,
655 arizona_ng_hold_text);
Mark Brown845571c2012-12-18 13:47:57 +0000656EXPORT_SYMBOL_GPL(arizona_ng_hold);
657
Charles Keepax254dc322013-11-19 16:04:03 +0000658static const char * const arizona_in_hpf_cut_text[] = {
659 "2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz"
660};
661
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100662SOC_ENUM_SINGLE_DECL(arizona_in_hpf_cut_enum,
663 ARIZONA_HPF_CONTROL,
664 ARIZONA_IN_HPF_CUT_SHIFT,
665 arizona_in_hpf_cut_text);
Charles Keepax254dc322013-11-19 16:04:03 +0000666EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum);
667
Charles Keepaxc7f38432013-08-06 17:03:55 +0100668static const char * const arizona_in_dmic_osr_text[] = {
Charles Keepaxef326f42014-11-12 14:55:26 +0000669 "1.536MHz", "3.072MHz", "6.144MHz", "768kHz",
Charles Keepaxc7f38432013-08-06 17:03:55 +0100670};
671
672const struct soc_enum arizona_in_dmic_osr[] = {
673 SOC_ENUM_SINGLE(ARIZONA_IN1L_CONTROL, ARIZONA_IN1_OSR_SHIFT,
674 ARRAY_SIZE(arizona_in_dmic_osr_text),
675 arizona_in_dmic_osr_text),
676 SOC_ENUM_SINGLE(ARIZONA_IN2L_CONTROL, ARIZONA_IN2_OSR_SHIFT,
677 ARRAY_SIZE(arizona_in_dmic_osr_text),
678 arizona_in_dmic_osr_text),
679 SOC_ENUM_SINGLE(ARIZONA_IN3L_CONTROL, ARIZONA_IN3_OSR_SHIFT,
680 ARRAY_SIZE(arizona_in_dmic_osr_text),
681 arizona_in_dmic_osr_text),
682 SOC_ENUM_SINGLE(ARIZONA_IN4L_CONTROL, ARIZONA_IN4_OSR_SHIFT,
683 ARRAY_SIZE(arizona_in_dmic_osr_text),
684 arizona_in_dmic_osr_text),
685};
686EXPORT_SYMBOL_GPL(arizona_in_dmic_osr);
687
Charles Keepaxd1901062015-11-19 16:11:10 +0000688static const char * const arizona_anc_input_src_text[] = {
689 "None", "IN1", "IN2", "IN3", "IN4",
690};
691
692static const char * const arizona_anc_channel_src_text[] = {
693 "None", "Left", "Right", "Combine",
694};
695
696const struct soc_enum arizona_anc_input_src[] = {
697 SOC_ENUM_SINGLE(ARIZONA_ANC_SRC,
698 ARIZONA_IN_RXANCL_SEL_SHIFT,
699 ARRAY_SIZE(arizona_anc_input_src_text),
700 arizona_anc_input_src_text),
701 SOC_ENUM_SINGLE(ARIZONA_FCL_ADC_REFORMATTER_CONTROL,
702 ARIZONA_FCL_MIC_MODE_SEL,
703 ARRAY_SIZE(arizona_anc_channel_src_text),
704 arizona_anc_channel_src_text),
705 SOC_ENUM_SINGLE(ARIZONA_ANC_SRC,
706 ARIZONA_IN_RXANCR_SEL_SHIFT,
707 ARRAY_SIZE(arizona_anc_input_src_text),
708 arizona_anc_input_src_text),
709 SOC_ENUM_SINGLE(ARIZONA_FCR_ADC_REFORMATTER_CONTROL,
710 ARIZONA_FCR_MIC_MODE_SEL,
711 ARRAY_SIZE(arizona_anc_channel_src_text),
712 arizona_anc_channel_src_text),
713};
714EXPORT_SYMBOL_GPL(arizona_anc_input_src);
715
716static const char * const arizona_anc_ng_texts[] = {
717 "None",
718 "Internal",
719 "External",
720};
721
722SOC_ENUM_SINGLE_DECL(arizona_anc_ng_enum, SND_SOC_NOPM, 0,
723 arizona_anc_ng_texts);
724EXPORT_SYMBOL_GPL(arizona_anc_ng_enum);
725
726static const char * const arizona_output_anc_src_text[] = {
727 "None", "RXANCL", "RXANCR",
728};
729
730const struct soc_enum arizona_output_anc_src[] = {
731 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L,
732 ARIZONA_OUT1L_ANC_SRC_SHIFT,
733 ARRAY_SIZE(arizona_output_anc_src_text),
734 arizona_output_anc_src_text),
735 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1R,
736 ARIZONA_OUT1R_ANC_SRC_SHIFT,
737 ARRAY_SIZE(arizona_output_anc_src_text),
738 arizona_output_anc_src_text),
739 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2L,
740 ARIZONA_OUT2L_ANC_SRC_SHIFT,
741 ARRAY_SIZE(arizona_output_anc_src_text),
742 arizona_output_anc_src_text),
743 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2R,
744 ARIZONA_OUT2R_ANC_SRC_SHIFT,
745 ARRAY_SIZE(arizona_output_anc_src_text),
746 arizona_output_anc_src_text),
747 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L,
748 ARIZONA_OUT3L_ANC_SRC_SHIFT,
749 ARRAY_SIZE(arizona_output_anc_src_text),
750 arizona_output_anc_src_text),
751 SOC_ENUM_SINGLE(ARIZONA_DAC_VOLUME_LIMIT_3R,
752 ARIZONA_OUT3R_ANC_SRC_SHIFT,
753 ARRAY_SIZE(arizona_output_anc_src_text),
754 arizona_output_anc_src_text),
755 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_4L,
756 ARIZONA_OUT4L_ANC_SRC_SHIFT,
757 ARRAY_SIZE(arizona_output_anc_src_text),
758 arizona_output_anc_src_text),
759 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_4R,
760 ARIZONA_OUT4R_ANC_SRC_SHIFT,
761 ARRAY_SIZE(arizona_output_anc_src_text),
762 arizona_output_anc_src_text),
763 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_5L,
764 ARIZONA_OUT5L_ANC_SRC_SHIFT,
765 ARRAY_SIZE(arizona_output_anc_src_text),
766 arizona_output_anc_src_text),
767 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_5R,
768 ARIZONA_OUT5R_ANC_SRC_SHIFT,
769 ARRAY_SIZE(arizona_output_anc_src_text),
770 arizona_output_anc_src_text),
771 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_6L,
772 ARIZONA_OUT6L_ANC_SRC_SHIFT,
773 ARRAY_SIZE(arizona_output_anc_src_text),
774 arizona_output_anc_src_text),
775 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_6R,
776 ARIZONA_OUT6R_ANC_SRC_SHIFT,
777 ARRAY_SIZE(arizona_output_anc_src_text),
778 arizona_output_anc_src_text),
779};
780EXPORT_SYMBOL_GPL(arizona_output_anc_src);
781
Charles Keepax97126ce2016-05-13 16:45:16 +0100782const struct snd_kcontrol_new arizona_voice_trigger_switch[] = {
783 SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0),
784 SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 1, 1, 0),
785 SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 2, 1, 0),
786 SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 3, 1, 0),
787};
788EXPORT_SYMBOL_GPL(arizona_voice_trigger_switch);
789
Mark Brownddbce972013-02-15 17:27:22 +0000790static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
791{
792 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
793 unsigned int val;
794 int i;
795
796 if (ena)
797 val = ARIZONA_IN_VU;
798 else
799 val = 0;
800
801 for (i = 0; i < priv->num_inputs; i++)
802 snd_soc_update_bits(codec,
803 ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 4),
804 ARIZONA_IN_VU, val);
805}
806
Charles Keepax002b0832015-09-16 13:59:41 +0100807bool arizona_input_analog(struct snd_soc_codec *codec, int shift)
808{
809 unsigned int reg = ARIZONA_IN1L_CONTROL + ((shift / 2) * 8);
810 unsigned int val = snd_soc_read(codec, reg);
811
812 return !(val & ARIZONA_IN1_MODE_MASK);
813}
814EXPORT_SYMBOL_GPL(arizona_input_analog);
815
Mark Brown07ed8732012-06-18 21:08:44 +0100816int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
817 int event)
818{
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100819 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
820 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000821 unsigned int reg;
822
823 if (w->shift % 2)
824 reg = ARIZONA_ADC_DIGITAL_VOLUME_1L + ((w->shift / 2) * 8);
825 else
826 reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8);
827
828 switch (event) {
Mark Brownddbce972013-02-15 17:27:22 +0000829 case SND_SOC_DAPM_PRE_PMU:
830 priv->in_pending++;
831 break;
Mark Brown43cd8bf2013-02-06 16:57:29 +0000832 case SND_SOC_DAPM_POST_PMU:
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100833 snd_soc_update_bits(codec, reg, ARIZONA_IN1L_MUTE, 0);
Mark Brownddbce972013-02-15 17:27:22 +0000834
835 /* If this is the last input pending then allow VU */
836 priv->in_pending--;
837 if (priv->in_pending == 0) {
838 msleep(1);
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100839 arizona_in_set_vu(codec, 1);
Mark Brownddbce972013-02-15 17:27:22 +0000840 }
Mark Brown43cd8bf2013-02-06 16:57:29 +0000841 break;
842 case SND_SOC_DAPM_PRE_PMD:
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100843 snd_soc_update_bits(codec, reg,
Mark Brownddbce972013-02-15 17:27:22 +0000844 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU,
845 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000846 break;
Mark Brownddbce972013-02-15 17:27:22 +0000847 case SND_SOC_DAPM_POST_PMD:
848 /* Disable volume updates if no inputs are enabled */
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100849 reg = snd_soc_read(codec, ARIZONA_INPUT_ENABLES);
Mark Brownddbce972013-02-15 17:27:22 +0000850 if (reg == 0)
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100851 arizona_in_set_vu(codec, 0);
Charles Keepaxbee261b2015-09-16 13:59:40 +0100852 break;
853 default:
854 break;
Mark Brown43cd8bf2013-02-06 16:57:29 +0000855 }
856
Mark Brown07ed8732012-06-18 21:08:44 +0100857 return 0;
858}
859EXPORT_SYMBOL_GPL(arizona_in_ev);
860
861int arizona_out_ev(struct snd_soc_dapm_widget *w,
862 struct snd_kcontrol *kcontrol,
863 int event)
864{
Mark Brown60d66c92015-01-27 23:50:47 +0000865 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
866 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Charles Keepax054e1b42015-01-20 16:31:50 +0000867
Mark Brown1a2c7d52013-03-24 22:50:23 +0000868 switch (event) {
Charles Keepaxe1ae5fb2015-01-20 16:31:51 +0000869 case SND_SOC_DAPM_PRE_PMU:
870 switch (w->shift) {
871 case ARIZONA_OUT1L_ENA_SHIFT:
872 case ARIZONA_OUT1R_ENA_SHIFT:
873 case ARIZONA_OUT2L_ENA_SHIFT:
874 case ARIZONA_OUT2R_ENA_SHIFT:
875 case ARIZONA_OUT3L_ENA_SHIFT:
876 case ARIZONA_OUT3R_ENA_SHIFT:
877 priv->out_up_pending++;
878 priv->out_up_delay += 17;
879 break;
880 default:
881 break;
882 }
883 break;
Mark Brown1a2c7d52013-03-24 22:50:23 +0000884 case SND_SOC_DAPM_POST_PMU:
885 switch (w->shift) {
886 case ARIZONA_OUT1L_ENA_SHIFT:
887 case ARIZONA_OUT1R_ENA_SHIFT:
888 case ARIZONA_OUT2L_ENA_SHIFT:
889 case ARIZONA_OUT2R_ENA_SHIFT:
890 case ARIZONA_OUT3L_ENA_SHIFT:
891 case ARIZONA_OUT3R_ENA_SHIFT:
Charles Keepaxe1ae5fb2015-01-20 16:31:51 +0000892 priv->out_up_pending--;
893 if (!priv->out_up_pending) {
894 msleep(priv->out_up_delay);
895 priv->out_up_delay = 0;
896 }
Mark Brown1a2c7d52013-03-24 22:50:23 +0000897 break;
898
899 default:
900 break;
901 }
902 break;
Charles Keepax054e1b42015-01-20 16:31:50 +0000903 case SND_SOC_DAPM_PRE_PMD:
904 switch (w->shift) {
905 case ARIZONA_OUT1L_ENA_SHIFT:
906 case ARIZONA_OUT1R_ENA_SHIFT:
907 case ARIZONA_OUT2L_ENA_SHIFT:
908 case ARIZONA_OUT2R_ENA_SHIFT:
909 case ARIZONA_OUT3L_ENA_SHIFT:
910 case ARIZONA_OUT3R_ENA_SHIFT:
911 priv->out_down_pending++;
912 priv->out_down_delay++;
913 break;
914 default:
915 break;
916 }
917 break;
918 case SND_SOC_DAPM_POST_PMD:
919 switch (w->shift) {
920 case ARIZONA_OUT1L_ENA_SHIFT:
921 case ARIZONA_OUT1R_ENA_SHIFT:
922 case ARIZONA_OUT2L_ENA_SHIFT:
923 case ARIZONA_OUT2R_ENA_SHIFT:
924 case ARIZONA_OUT3L_ENA_SHIFT:
925 case ARIZONA_OUT3R_ENA_SHIFT:
926 priv->out_down_pending--;
927 if (!priv->out_down_pending) {
928 msleep(priv->out_down_delay);
929 priv->out_down_delay = 0;
930 }
931 break;
932 default:
933 break;
934 }
935 break;
Charles Keepaxbee261b2015-09-16 13:59:40 +0100936 default:
937 break;
Mark Brown1a2c7d52013-03-24 22:50:23 +0000938 }
939
Mark Brown07ed8732012-06-18 21:08:44 +0100940 return 0;
941}
942EXPORT_SYMBOL_GPL(arizona_out_ev);
943
Mark Brownf607e312013-02-22 18:36:53 +0000944int arizona_hp_ev(struct snd_soc_dapm_widget *w,
945 struct snd_kcontrol *kcontrol,
946 int event)
947{
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100948 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
949 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brown3c43c692013-12-12 00:49:22 +0000950 struct arizona *arizona = priv->arizona;
Mark Brownf607e312013-02-22 18:36:53 +0000951 unsigned int mask = 1 << w->shift;
952 unsigned int val;
953
954 switch (event) {
955 case SND_SOC_DAPM_POST_PMU:
956 val = mask;
957 break;
958 case SND_SOC_DAPM_PRE_PMD:
959 val = 0;
960 break;
Charles Keepaxe1ae5fb2015-01-20 16:31:51 +0000961 case SND_SOC_DAPM_PRE_PMU:
Charles Keepax054e1b42015-01-20 16:31:50 +0000962 case SND_SOC_DAPM_POST_PMD:
963 return arizona_out_ev(w, kcontrol, event);
Mark Brownf607e312013-02-22 18:36:53 +0000964 default:
965 return -EINVAL;
966 }
967
968 /* Store the desired state for the HP outputs */
969 priv->arizona->hp_ena &= ~mask;
970 priv->arizona->hp_ena |= val;
971
Charles Keepax112bdfa2015-02-16 15:41:02 +0000972 /* Force off if HPDET clamp is active */
973 if (priv->arizona->hpdet_clamp)
Mark Brownf607e312013-02-22 18:36:53 +0000974 val = 0;
975
Mark Brown3c43c692013-12-12 00:49:22 +0000976 regmap_update_bits_async(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1,
977 mask, val);
Mark Brownf607e312013-02-22 18:36:53 +0000978
979 return arizona_out_ev(w, kcontrol, event);
980}
981EXPORT_SYMBOL_GPL(arizona_hp_ev);
982
Richard Fitzgerald346d9682015-06-02 11:53:33 +0100983static int arizona_dvfs_enable(struct snd_soc_codec *codec)
984{
985 const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
986 struct arizona *arizona = priv->arizona;
987 int ret;
988
989 ret = regulator_set_voltage(arizona->dcvdd, 1800000, 1800000);
990 if (ret) {
991 dev_err(codec->dev, "Failed to boost DCVDD: %d\n", ret);
992 return ret;
993 }
994
995 ret = regmap_update_bits(arizona->regmap,
996 ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
997 ARIZONA_SUBSYS_MAX_FREQ,
998 ARIZONA_SUBSYS_MAX_FREQ);
999 if (ret) {
1000 dev_err(codec->dev, "Failed to enable subsys max: %d\n", ret);
1001 regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
1002 return ret;
1003 }
1004
1005 return 0;
1006}
1007
1008static int arizona_dvfs_disable(struct snd_soc_codec *codec)
1009{
1010 const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1011 struct arizona *arizona = priv->arizona;
1012 int ret;
1013
1014 ret = regmap_update_bits(arizona->regmap,
1015 ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
1016 ARIZONA_SUBSYS_MAX_FREQ, 0);
1017 if (ret) {
1018 dev_err(codec->dev, "Failed to disable subsys max: %d\n", ret);
1019 return ret;
1020 }
1021
1022 ret = regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
1023 if (ret) {
1024 dev_err(codec->dev, "Failed to unboost DCVDD: %d\n", ret);
1025 return ret;
1026 }
1027
1028 return 0;
1029}
1030
1031int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags)
1032{
1033 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1034 int ret = 0;
1035
1036 mutex_lock(&priv->dvfs_lock);
1037
1038 if (!priv->dvfs_cached && !priv->dvfs_reqs) {
1039 ret = arizona_dvfs_enable(codec);
1040 if (ret)
1041 goto err;
1042 }
1043
1044 priv->dvfs_reqs |= flags;
1045err:
1046 mutex_unlock(&priv->dvfs_lock);
1047 return ret;
1048}
1049EXPORT_SYMBOL_GPL(arizona_dvfs_up);
1050
1051int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags)
1052{
1053 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1054 unsigned int old_reqs;
1055 int ret = 0;
1056
1057 mutex_lock(&priv->dvfs_lock);
1058
1059 old_reqs = priv->dvfs_reqs;
1060 priv->dvfs_reqs &= ~flags;
1061
1062 if (!priv->dvfs_cached && old_reqs && !priv->dvfs_reqs)
1063 ret = arizona_dvfs_disable(codec);
1064
1065 mutex_unlock(&priv->dvfs_lock);
1066 return ret;
1067}
1068EXPORT_SYMBOL_GPL(arizona_dvfs_down);
1069
1070int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
1071 struct snd_kcontrol *kcontrol, int event)
1072{
1073 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
1074 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1075 int ret = 0;
1076
1077 mutex_lock(&priv->dvfs_lock);
1078
1079 switch (event) {
1080 case SND_SOC_DAPM_POST_PMU:
1081 if (priv->dvfs_reqs)
1082 ret = arizona_dvfs_enable(codec);
1083
1084 priv->dvfs_cached = false;
1085 break;
1086 case SND_SOC_DAPM_PRE_PMD:
1087 /* We must ensure DVFS is disabled before the codec goes into
1088 * suspend so that we are never in an illegal state of DVFS
1089 * enabled without enough DCVDD
1090 */
1091 priv->dvfs_cached = true;
1092
1093 if (priv->dvfs_reqs)
1094 ret = arizona_dvfs_disable(codec);
1095 break;
1096 default:
1097 break;
1098 }
1099
1100 mutex_unlock(&priv->dvfs_lock);
1101 return ret;
1102}
1103EXPORT_SYMBOL_GPL(arizona_dvfs_sysclk_ev);
1104
1105void arizona_init_dvfs(struct arizona_priv *priv)
1106{
1107 mutex_init(&priv->dvfs_lock);
1108}
1109EXPORT_SYMBOL_GPL(arizona_init_dvfs);
1110
Charles Keepaxd1901062015-11-19 16:11:10 +00001111int arizona_anc_ev(struct snd_soc_dapm_widget *w,
1112 struct snd_kcontrol *kcontrol,
1113 int event)
1114{
1115 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
Charles Keepaxd1901062015-11-19 16:11:10 +00001116 unsigned int val;
1117
1118 switch (event) {
1119 case SND_SOC_DAPM_POST_PMU:
1120 val = 1 << w->shift;
1121 break;
1122 case SND_SOC_DAPM_PRE_PMD:
1123 val = 1 << (w->shift + 1);
1124 break;
1125 default:
1126 return 0;
1127 }
1128
Richard Fitzgerald2ab8e742016-04-26 17:06:20 +01001129 snd_soc_write(codec, ARIZONA_CLOCK_CONTROL, val);
Charles Keepaxd1901062015-11-19 16:11:10 +00001130
1131 return 0;
1132}
1133EXPORT_SYMBOL_GPL(arizona_anc_ev);
1134
Richard Fitzgerald341604a2015-11-03 14:24:12 +00001135static unsigned int arizona_opclk_ref_48k_rates[] = {
Mark Browncbd840d2012-08-08 17:52:44 +01001136 6144000,
1137 12288000,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +00001138 24576000,
Mark Browncbd840d2012-08-08 17:52:44 +01001139 49152000,
1140};
1141
Richard Fitzgerald341604a2015-11-03 14:24:12 +00001142static unsigned int arizona_opclk_ref_44k1_rates[] = {
Mark Browncbd840d2012-08-08 17:52:44 +01001143 5644800,
1144 11289600,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +00001145 22579200,
Mark Browncbd840d2012-08-08 17:52:44 +01001146 45158400,
1147};
1148
1149static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
1150 unsigned int freq)
1151{
1152 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1153 unsigned int reg;
1154 unsigned int *rates;
1155 int ref, div, refclk;
1156
1157 switch (clk) {
1158 case ARIZONA_CLK_OPCLK:
1159 reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
1160 refclk = priv->sysclk;
1161 break;
1162 case ARIZONA_CLK_ASYNC_OPCLK:
1163 reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
1164 refclk = priv->asyncclk;
1165 break;
1166 default:
1167 return -EINVAL;
1168 }
1169
1170 if (refclk % 8000)
Richard Fitzgerald341604a2015-11-03 14:24:12 +00001171 rates = arizona_opclk_ref_44k1_rates;
Mark Browncbd840d2012-08-08 17:52:44 +01001172 else
Richard Fitzgerald341604a2015-11-03 14:24:12 +00001173 rates = arizona_opclk_ref_48k_rates;
Mark Browncbd840d2012-08-08 17:52:44 +01001174
Richard Fitzgerald341604a2015-11-03 14:24:12 +00001175 for (ref = 0; ref < ARRAY_SIZE(arizona_opclk_ref_48k_rates) &&
Mark Browncbd840d2012-08-08 17:52:44 +01001176 rates[ref] <= refclk; ref++) {
1177 div = 1;
1178 while (rates[ref] / div >= freq && div < 32) {
1179 if (rates[ref] / div == freq) {
1180 dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
1181 freq);
1182 snd_soc_update_bits(codec, reg,
1183 ARIZONA_OPCLK_DIV_MASK |
1184 ARIZONA_OPCLK_SEL_MASK,
1185 (div <<
1186 ARIZONA_OPCLK_DIV_SHIFT) |
1187 ref);
1188 return 0;
1189 }
1190 div++;
1191 }
1192 }
1193
1194 dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
1195 return -EINVAL;
1196}
1197
Mark Brown07ed8732012-06-18 21:08:44 +01001198int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
1199 int source, unsigned int freq, int dir)
1200{
1201 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1202 struct arizona *arizona = priv->arizona;
1203 char *name;
1204 unsigned int reg;
1205 unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
1206 unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
Charles Keepax1f0e1ea2015-12-03 18:15:07 +00001207 int *clk;
Mark Brown07ed8732012-06-18 21:08:44 +01001208
1209 switch (clk_id) {
1210 case ARIZONA_CLK_SYSCLK:
1211 name = "SYSCLK";
1212 reg = ARIZONA_SYSTEM_CLOCK_1;
1213 clk = &priv->sysclk;
1214 mask |= ARIZONA_SYSCLK_FRAC;
1215 break;
1216 case ARIZONA_CLK_ASYNCCLK:
1217 name = "ASYNCCLK";
1218 reg = ARIZONA_ASYNC_CLOCK_1;
1219 clk = &priv->asyncclk;
1220 break;
Mark Browncbd840d2012-08-08 17:52:44 +01001221 case ARIZONA_CLK_OPCLK:
1222 case ARIZONA_CLK_ASYNC_OPCLK:
1223 return arizona_set_opclk(codec, clk_id, freq);
Mark Brown07ed8732012-06-18 21:08:44 +01001224 default:
1225 return -EINVAL;
1226 }
1227
1228 switch (freq) {
1229 case 5644800:
1230 case 6144000:
1231 break;
1232 case 11289600:
1233 case 12288000:
Mark Brown3f341f72013-03-08 15:22:29 +08001234 val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +01001235 break;
1236 case 22579200:
1237 case 24576000:
Mark Brown3f341f72013-03-08 15:22:29 +08001238 val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +01001239 break;
1240 case 45158400:
1241 case 49152000:
Mark Brown3f341f72013-03-08 15:22:29 +08001242 val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +01001243 break;
Mark Brown38113362012-11-26 16:01:37 +00001244 case 67737600:
1245 case 73728000:
Mark Brown3f341f72013-03-08 15:22:29 +08001246 val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +00001247 break;
1248 case 90316800:
1249 case 98304000:
Mark Brown3f341f72013-03-08 15:22:29 +08001250 val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +00001251 break;
1252 case 135475200:
1253 case 147456000:
Mark Brown3f341f72013-03-08 15:22:29 +08001254 val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +00001255 break;
Mark Brownf2c26d42013-01-21 16:09:36 +09001256 case 0:
1257 dev_dbg(arizona->dev, "%s cleared\n", name);
1258 *clk = freq;
1259 return 0;
Mark Brown07ed8732012-06-18 21:08:44 +01001260 default:
1261 return -EINVAL;
1262 }
1263
1264 *clk = freq;
1265
1266 if (freq % 6144000)
1267 val |= ARIZONA_SYSCLK_FRAC;
1268
1269 dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
1270
1271 return regmap_update_bits(arizona->regmap, reg, mask, val);
1272}
1273EXPORT_SYMBOL_GPL(arizona_set_sysclk);
1274
1275static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
1276{
1277 struct snd_soc_codec *codec = dai->codec;
Mark Brown3c43c692013-12-12 00:49:22 +00001278 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1279 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +01001280 int lrclk, bclk, mode, base;
1281
1282 base = dai->driver->base;
1283
1284 lrclk = 0;
1285 bclk = 0;
1286
1287 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
1288 case SND_SOC_DAIFMT_DSP_A:
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001289 mode = ARIZONA_FMT_DSP_MODE_A;
1290 break;
1291 case SND_SOC_DAIFMT_DSP_B:
1292 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
1293 != SND_SOC_DAIFMT_CBM_CFM) {
1294 arizona_aif_err(dai, "DSP_B not valid in slave mode\n");
1295 return -EINVAL;
1296 }
1297 mode = ARIZONA_FMT_DSP_MODE_B;
Mark Brown07ed8732012-06-18 21:08:44 +01001298 break;
Mark Brown07ed8732012-06-18 21:08:44 +01001299 case SND_SOC_DAIFMT_I2S:
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001300 mode = ARIZONA_FMT_I2S_MODE;
1301 break;
1302 case SND_SOC_DAIFMT_LEFT_J:
1303 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
1304 != SND_SOC_DAIFMT_CBM_CFM) {
1305 arizona_aif_err(dai, "LEFT_J not valid in slave mode\n");
1306 return -EINVAL;
1307 }
1308 mode = ARIZONA_FMT_LEFT_JUSTIFIED_MODE;
Mark Brown07ed8732012-06-18 21:08:44 +01001309 break;
Mark Brown07ed8732012-06-18 21:08:44 +01001310 default:
1311 arizona_aif_err(dai, "Unsupported DAI format %d\n",
1312 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
1313 return -EINVAL;
1314 }
1315
1316 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
1317 case SND_SOC_DAIFMT_CBS_CFS:
1318 break;
1319 case SND_SOC_DAIFMT_CBS_CFM:
1320 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
1321 break;
1322 case SND_SOC_DAIFMT_CBM_CFS:
1323 bclk |= ARIZONA_AIF1_BCLK_MSTR;
1324 break;
1325 case SND_SOC_DAIFMT_CBM_CFM:
1326 bclk |= ARIZONA_AIF1_BCLK_MSTR;
1327 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
1328 break;
1329 default:
1330 arizona_aif_err(dai, "Unsupported master mode %d\n",
1331 fmt & SND_SOC_DAIFMT_MASTER_MASK);
1332 return -EINVAL;
1333 }
1334
1335 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1336 case SND_SOC_DAIFMT_NB_NF:
1337 break;
1338 case SND_SOC_DAIFMT_IB_IF:
1339 bclk |= ARIZONA_AIF1_BCLK_INV;
1340 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
1341 break;
1342 case SND_SOC_DAIFMT_IB_NF:
1343 bclk |= ARIZONA_AIF1_BCLK_INV;
1344 break;
1345 case SND_SOC_DAIFMT_NB_IF:
1346 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
1347 break;
1348 default:
1349 return -EINVAL;
1350 }
1351
Mark Brown3c43c692013-12-12 00:49:22 +00001352 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_BCLK_CTRL,
1353 ARIZONA_AIF1_BCLK_INV |
1354 ARIZONA_AIF1_BCLK_MSTR,
1355 bclk);
1356 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_TX_PIN_CTRL,
1357 ARIZONA_AIF1TX_LRCLK_INV |
1358 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
1359 regmap_update_bits_async(arizona->regmap,
1360 base + ARIZONA_AIF_RX_PIN_CTRL,
1361 ARIZONA_AIF1RX_LRCLK_INV |
1362 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
1363 regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FORMAT,
1364 ARIZONA_AIF1_FMT_MASK, mode);
Mark Brown07ed8732012-06-18 21:08:44 +01001365
1366 return 0;
1367}
1368
Mark Brown949e6bc2012-07-04 18:58:04 +01001369static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001370 -1,
1371 48000,
1372 64000,
1373 96000,
1374 128000,
1375 192000,
1376 256000,
1377 384000,
1378 512000,
1379 768000,
1380 1024000,
1381 1536000,
1382 2048000,
1383 3072000,
1384 4096000,
1385 6144000,
1386 8192000,
1387 12288000,
1388 24576000,
1389};
1390
Mark Brown949e6bc2012-07-04 18:58:04 +01001391static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001392 -1,
1393 44100,
1394 58800,
1395 88200,
1396 117600,
1397 177640,
1398 235200,
1399 352800,
1400 470400,
1401 705600,
1402 940800,
1403 1411200,
1404 1881600,
Heather Lomond4758be32012-09-05 05:02:10 -04001405 2822400,
Mark Brown07ed8732012-06-18 21:08:44 +01001406 3763200,
1407 5644800,
1408 7526400,
1409 11289600,
1410 22579200,
1411};
1412
Charles Keepaxd81221f2016-02-04 16:29:01 +00001413static const unsigned int arizona_sr_vals[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001414 0,
1415 12000,
1416 24000,
1417 48000,
1418 96000,
1419 192000,
1420 384000,
1421 768000,
1422 0,
1423 11025,
1424 22050,
1425 44100,
1426 88200,
1427 176400,
1428 352800,
1429 705600,
1430 4000,
1431 8000,
1432 16000,
1433 32000,
1434 64000,
1435 128000,
1436 256000,
1437 512000,
1438};
1439
Charles Keepaxd81221f2016-02-04 16:29:01 +00001440#define ARIZONA_48K_RATE_MASK 0x0F003E
1441#define ARIZONA_44K1_RATE_MASK 0x003E00
1442#define ARIZONA_RATE_MASK (ARIZONA_48K_RATE_MASK | ARIZONA_44K1_RATE_MASK)
1443
1444static const struct snd_pcm_hw_constraint_list arizona_constraint = {
1445 .count = ARRAY_SIZE(arizona_sr_vals),
1446 .list = arizona_sr_vals,
1447};
1448
Mark Brown5b2eec32012-07-04 17:32:05 +01001449static int arizona_startup(struct snd_pcm_substream *substream,
1450 struct snd_soc_dai *dai)
1451{
1452 struct snd_soc_codec *codec = dai->codec;
1453 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1454 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown5b2eec32012-07-04 17:32:05 +01001455 unsigned int base_rate;
1456
Charles Keepax26eb5a92015-12-29 09:49:19 +00001457 if (!substream->runtime)
1458 return 0;
1459
Mark Brown5b2eec32012-07-04 17:32:05 +01001460 switch (dai_priv->clk) {
1461 case ARIZONA_CLK_SYSCLK:
1462 base_rate = priv->sysclk;
1463 break;
1464 case ARIZONA_CLK_ASYNCCLK:
1465 base_rate = priv->asyncclk;
1466 break;
1467 default:
1468 return 0;
1469 }
1470
Mark Brownf2c26d42013-01-21 16:09:36 +09001471 if (base_rate == 0)
Charles Keepaxd81221f2016-02-04 16:29:01 +00001472 dai_priv->constraint.mask = ARIZONA_RATE_MASK;
1473 else if (base_rate % 8000)
1474 dai_priv->constraint.mask = ARIZONA_44K1_RATE_MASK;
Mark Brown5b2eec32012-07-04 17:32:05 +01001475 else
Charles Keepaxd81221f2016-02-04 16:29:01 +00001476 dai_priv->constraint.mask = ARIZONA_48K_RATE_MASK;
Mark Brown5b2eec32012-07-04 17:32:05 +01001477
1478 return snd_pcm_hw_constraint_list(substream->runtime, 0,
1479 SNDRV_PCM_HW_PARAM_RATE,
Charles Keepaxd81221f2016-02-04 16:29:01 +00001480 &dai_priv->constraint);
Mark Brown5b2eec32012-07-04 17:32:05 +01001481}
1482
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001483static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec,
1484 unsigned int rate)
1485{
1486 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1487 struct arizona *arizona = priv->arizona;
Nariman Poushin8019ff62015-07-16 16:36:21 +01001488 struct reg_sequence dac_comp[] = {
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001489 { 0x80, 0x3 },
1490 { ARIZONA_DAC_COMP_1, 0 },
1491 { ARIZONA_DAC_COMP_2, 0 },
1492 { 0x80, 0x0 },
1493 };
1494
Lars-Peter Clausend74bcaa2014-11-09 17:00:59 +01001495 mutex_lock(&arizona->dac_comp_lock);
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001496
1497 dac_comp[1].def = arizona->dac_comp_coeff;
1498 if (rate >= 176400)
1499 dac_comp[2].def = arizona->dac_comp_enabled;
1500
Lars-Peter Clausend74bcaa2014-11-09 17:00:59 +01001501 mutex_unlock(&arizona->dac_comp_lock);
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001502
1503 regmap_multi_reg_write(arizona->regmap,
1504 dac_comp,
1505 ARRAY_SIZE(dac_comp));
1506}
1507
Mark Brownb272efc2012-10-10 15:10:08 +09001508static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
1509 struct snd_pcm_hw_params *params,
1510 struct snd_soc_dai *dai)
Mark Brown07ed8732012-06-18 21:08:44 +01001511{
1512 struct snd_soc_codec *codec = dai->codec;
Mark Brownc013b272012-07-04 20:05:57 +01001513 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1514 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown07ed8732012-06-18 21:08:44 +01001515 int base = dai->driver->base;
Richard Fitzgerald2c118b42015-06-02 11:53:35 +01001516 int i, sr_val, ret;
Mark Brownb272efc2012-10-10 15:10:08 +09001517
1518 /*
1519 * We will need to be more flexible than this in future,
1520 * currently we use a single sample rate for SYSCLK.
1521 */
1522 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
1523 if (arizona_sr_vals[i] == params_rate(params))
1524 break;
1525 if (i == ARRAY_SIZE(arizona_sr_vals)) {
1526 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1527 params_rate(params));
1528 return -EINVAL;
1529 }
1530 sr_val = i;
1531
Richard Fitzgerald2c118b42015-06-02 11:53:35 +01001532 switch (priv->arizona->type) {
1533 case WM5102:
1534 case WM8997:
1535 if (arizona_sr_vals[sr_val] >= 88200)
1536 ret = arizona_dvfs_up(codec, ARIZONA_DVFS_SR1_RQ);
1537 else
1538 ret = arizona_dvfs_down(codec, ARIZONA_DVFS_SR1_RQ);
1539
1540 if (ret) {
1541 arizona_aif_err(dai, "Failed to change DVFS %d\n", ret);
1542 return ret;
1543 }
1544 break;
1545 default:
1546 break;
1547 }
1548
Mark Brownb272efc2012-10-10 15:10:08 +09001549 switch (dai_priv->clk) {
1550 case ARIZONA_CLK_SYSCLK:
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001551 switch (priv->arizona->type) {
1552 case WM5102:
1553 arizona_wm5102_set_dac_comp(codec,
1554 params_rate(params));
1555 break;
1556 default:
1557 break;
1558 }
1559
Mark Brownb272efc2012-10-10 15:10:08 +09001560 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
1561 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
1562 if (base)
1563 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1564 ARIZONA_AIF1_RATE_MASK, 0);
1565 break;
1566 case ARIZONA_CLK_ASYNCCLK:
1567 snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
Charles Keepaxc24084d2014-09-01 15:48:52 +01001568 ARIZONA_ASYNC_SAMPLE_RATE_1_MASK, sr_val);
Mark Brownb272efc2012-10-10 15:10:08 +09001569 if (base)
1570 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1571 ARIZONA_AIF1_RATE_MASK,
1572 8 << ARIZONA_AIF1_RATE_SHIFT);
1573 break;
1574 default:
1575 arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
1576 return -EINVAL;
1577 }
1578
1579 return 0;
1580}
1581
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001582static bool arizona_aif_cfg_changed(struct snd_soc_codec *codec,
1583 int base, int bclk, int lrclk, int frame)
1584{
1585 int val;
1586
1587 val = snd_soc_read(codec, base + ARIZONA_AIF_BCLK_CTRL);
1588 if (bclk != (val & ARIZONA_AIF1_BCLK_FREQ_MASK))
1589 return true;
1590
1591 val = snd_soc_read(codec, base + ARIZONA_AIF_TX_BCLK_RATE);
1592 if (lrclk != (val & ARIZONA_AIF1TX_BCPF_MASK))
1593 return true;
1594
1595 val = snd_soc_read(codec, base + ARIZONA_AIF_FRAME_CTRL_1);
1596 if (frame != (val & (ARIZONA_AIF1TX_WL_MASK |
1597 ARIZONA_AIF1TX_SLOT_LEN_MASK)))
1598 return true;
1599
1600 return false;
1601}
1602
Mark Brown07ed8732012-06-18 21:08:44 +01001603static int arizona_hw_params(struct snd_pcm_substream *substream,
1604 struct snd_pcm_hw_params *params,
1605 struct snd_soc_dai *dai)
1606{
1607 struct snd_soc_codec *codec = dai->codec;
1608 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brownc94aa302013-01-17 16:35:14 +09001609 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +01001610 int base = dai->driver->base;
1611 const int *rates;
Mark Brown76bf9692013-03-05 14:17:47 +08001612 int i, ret, val;
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001613 int channels = params_channels(params);
Mark Brownc94aa302013-01-17 16:35:14 +09001614 int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001615 int tdm_width = arizona->tdm_width[dai->id - 1];
1616 int tdm_slots = arizona->tdm_slots[dai->id - 1];
Mark Brownc94aa302013-01-17 16:35:14 +09001617 int bclk, lrclk, wl, frame, bclk_target;
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001618 bool reconfig;
1619 unsigned int aif_tx_state, aif_rx_state;
Mark Brown07ed8732012-06-18 21:08:44 +01001620
Nikesh Oswale73694d2015-12-23 14:18:05 +00001621 if (params_rate(params) % 4000)
Mark Brown949e6bc2012-07-04 18:58:04 +01001622 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001623 else
Mark Brown949e6bc2012-07-04 18:58:04 +01001624 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001625
Charles Keepax5ed68f02015-07-09 11:28:46 +01001626 wl = params_width(params);
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001627
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001628 if (tdm_slots) {
1629 arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n",
1630 tdm_slots, tdm_width);
1631 bclk_target = tdm_slots * tdm_width * params_rate(params);
1632 channels = tdm_slots;
1633 } else {
1634 bclk_target = snd_soc_params_to_bclk(params);
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001635 tdm_width = wl;
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001636 }
1637
1638 if (chan_limit && chan_limit < channels) {
Mark Brownc94aa302013-01-17 16:35:14 +09001639 arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001640 bclk_target /= channels;
Mark Brownc94aa302013-01-17 16:35:14 +09001641 bclk_target *= chan_limit;
1642 }
1643
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001644 /* Force multiple of 2 channels for I2S mode */
Mark Brown76bf9692013-03-05 14:17:47 +08001645 val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001646 val &= ARIZONA_AIF1_FMT_MASK;
1647 if ((channels & 1) && (val == ARIZONA_FMT_I2S_MODE)) {
Mark Brown76bf9692013-03-05 14:17:47 +08001648 arizona_aif_dbg(dai, "Forcing stereo mode\n");
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001649 bclk_target /= channels;
1650 bclk_target *= channels + 1;
Mark Brown76bf9692013-03-05 14:17:47 +08001651 }
1652
Mark Brown949e6bc2012-07-04 18:58:04 +01001653 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brownc94aa302013-01-17 16:35:14 +09001654 if (rates[i] >= bclk_target &&
Mark Brown50017652012-07-04 19:07:09 +01001655 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +01001656 bclk = i;
1657 break;
1658 }
1659 }
Mark Brown949e6bc2012-07-04 18:58:04 +01001660 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001661 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1662 params_rate(params));
1663 return -EINVAL;
1664 }
1665
Mark Brownb59e0f82013-01-17 14:15:59 +09001666 lrclk = rates[bclk] / params_rate(params);
Mark Brown07ed8732012-06-18 21:08:44 +01001667
1668 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
1669 rates[bclk], rates[bclk] / lrclk);
1670
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001671 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | tdm_width;
Mark Brown07ed8732012-06-18 21:08:44 +01001672
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001673 reconfig = arizona_aif_cfg_changed(codec, base, bclk, lrclk, frame);
1674
1675 if (reconfig) {
1676 /* Save AIF TX/RX state */
1677 aif_tx_state = snd_soc_read(codec,
1678 base + ARIZONA_AIF_TX_ENABLES);
1679 aif_rx_state = snd_soc_read(codec,
1680 base + ARIZONA_AIF_RX_ENABLES);
1681 /* Disable AIF TX/RX before reconfiguring it */
1682 regmap_update_bits_async(arizona->regmap,
1683 base + ARIZONA_AIF_TX_ENABLES, 0xff, 0x0);
1684 regmap_update_bits(arizona->regmap,
1685 base + ARIZONA_AIF_RX_ENABLES, 0xff, 0x0);
1686 }
1687
Mark Brownb272efc2012-10-10 15:10:08 +09001688 ret = arizona_hw_params_rate(substream, params, dai);
1689 if (ret != 0)
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001690 goto restore_aif;
Mark Brownc013b272012-07-04 20:05:57 +01001691
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001692 if (reconfig) {
1693 regmap_update_bits_async(arizona->regmap,
1694 base + ARIZONA_AIF_BCLK_CTRL,
1695 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
1696 regmap_update_bits_async(arizona->regmap,
1697 base + ARIZONA_AIF_TX_BCLK_RATE,
1698 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
1699 regmap_update_bits_async(arizona->regmap,
1700 base + ARIZONA_AIF_RX_BCLK_RATE,
1701 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
1702 regmap_update_bits_async(arizona->regmap,
1703 base + ARIZONA_AIF_FRAME_CTRL_1,
1704 ARIZONA_AIF1TX_WL_MASK |
1705 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
1706 regmap_update_bits(arizona->regmap,
1707 base + ARIZONA_AIF_FRAME_CTRL_2,
1708 ARIZONA_AIF1RX_WL_MASK |
1709 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
1710 }
Mark Brown07ed8732012-06-18 21:08:44 +01001711
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001712restore_aif:
1713 if (reconfig) {
1714 /* Restore AIF TX/RX state */
1715 regmap_update_bits_async(arizona->regmap,
1716 base + ARIZONA_AIF_TX_ENABLES,
1717 0xff, aif_tx_state);
1718 regmap_update_bits(arizona->regmap,
1719 base + ARIZONA_AIF_RX_ENABLES,
1720 0xff, aif_rx_state);
1721 }
1722 return ret;
Mark Brown07ed8732012-06-18 21:08:44 +01001723}
1724
Mark Brown410837a2012-07-05 17:26:59 +01001725static const char *arizona_dai_clk_str(int clk_id)
1726{
1727 switch (clk_id) {
1728 case ARIZONA_CLK_SYSCLK:
1729 return "SYSCLK";
1730 case ARIZONA_CLK_ASYNCCLK:
1731 return "ASYNCCLK";
1732 default:
1733 return "Unknown clock";
1734 }
1735}
1736
Mark Brown5b2eec32012-07-04 17:32:05 +01001737static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
1738 int clk_id, unsigned int freq, int dir)
1739{
1740 struct snd_soc_codec *codec = dai->codec;
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +02001741 struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
Mark Brown5b2eec32012-07-04 17:32:05 +01001742 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1743 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown410837a2012-07-05 17:26:59 +01001744 struct snd_soc_dapm_route routes[2];
Mark Brown5b2eec32012-07-04 17:32:05 +01001745
1746 switch (clk_id) {
1747 case ARIZONA_CLK_SYSCLK:
1748 case ARIZONA_CLK_ASYNCCLK:
1749 break;
1750 default:
1751 return -EINVAL;
1752 }
1753
Mark Brown410837a2012-07-05 17:26:59 +01001754 if (clk_id == dai_priv->clk)
1755 return 0;
1756
1757 if (dai->active) {
Mark Brown5b2eec32012-07-04 17:32:05 +01001758 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
1759 dai->id);
1760 return -EBUSY;
1761 }
1762
Mark Brownc8d35a62012-12-07 12:49:40 +09001763 dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1,
1764 arizona_dai_clk_str(clk_id));
1765
Mark Brown410837a2012-07-05 17:26:59 +01001766 memset(&routes, 0, sizeof(routes));
1767 routes[0].sink = dai->driver->capture.stream_name;
1768 routes[1].sink = dai->driver->playback.stream_name;
Mark Brown5b2eec32012-07-04 17:32:05 +01001769
Mark Brown410837a2012-07-05 17:26:59 +01001770 routes[0].source = arizona_dai_clk_str(dai_priv->clk);
1771 routes[1].source = arizona_dai_clk_str(dai_priv->clk);
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +02001772 snd_soc_dapm_del_routes(dapm, routes, ARRAY_SIZE(routes));
Mark Brown410837a2012-07-05 17:26:59 +01001773
1774 routes[0].source = arizona_dai_clk_str(clk_id);
1775 routes[1].source = arizona_dai_clk_str(clk_id);
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +02001776 snd_soc_dapm_add_routes(dapm, routes, ARRAY_SIZE(routes));
Mark Brown410837a2012-07-05 17:26:59 +01001777
Mark Brown0c778e82012-12-06 18:22:25 +09001778 dai_priv->clk = clk_id;
1779
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +02001780 return snd_soc_dapm_sync(dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +01001781}
1782
Mark Brown01df2592012-12-12 16:22:08 +09001783static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
1784{
1785 struct snd_soc_codec *codec = dai->codec;
1786 int base = dai->driver->base;
1787 unsigned int reg;
1788
1789 if (tristate)
1790 reg = ARIZONA_AIF1_TRI;
1791 else
1792 reg = 0;
1793
1794 return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1795 ARIZONA_AIF1_TRI, reg);
1796}
1797
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001798static void arizona_set_channels_to_mask(struct snd_soc_dai *dai,
1799 unsigned int base,
1800 int channels, unsigned int mask)
1801{
1802 struct snd_soc_codec *codec = dai->codec;
1803 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1804 struct arizona *arizona = priv->arizona;
1805 int slot, i;
1806
1807 for (i = 0; i < channels; ++i) {
1808 slot = ffs(mask) - 1;
1809 if (slot < 0)
1810 return;
1811
1812 regmap_write(arizona->regmap, base + i, slot);
1813
1814 mask &= ~(1 << slot);
1815 }
1816
1817 if (mask)
1818 arizona_aif_warn(dai, "Too many channels in TDM mask\n");
1819}
1820
1821static int arizona_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
1822 unsigned int rx_mask, int slots, int slot_width)
1823{
1824 struct snd_soc_codec *codec = dai->codec;
1825 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1826 struct arizona *arizona = priv->arizona;
1827 int base = dai->driver->base;
1828 int rx_max_chan = dai->driver->playback.channels_max;
1829 int tx_max_chan = dai->driver->capture.channels_max;
1830
1831 /* Only support TDM for the physical AIFs */
1832 if (dai->id > ARIZONA_MAX_AIF)
1833 return -ENOTSUPP;
1834
1835 if (slots == 0) {
1836 tx_mask = (1 << tx_max_chan) - 1;
1837 rx_mask = (1 << rx_max_chan) - 1;
1838 }
1839
1840 arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_3,
1841 tx_max_chan, tx_mask);
1842 arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_11,
1843 rx_max_chan, rx_mask);
1844
1845 arizona->tdm_width[dai->id - 1] = slot_width;
1846 arizona->tdm_slots[dai->id - 1] = slots;
1847
1848 return 0;
1849}
1850
Mark Brown07ed8732012-06-18 21:08:44 +01001851const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +01001852 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +01001853 .set_fmt = arizona_set_fmt,
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001854 .set_tdm_slot = arizona_set_tdm_slot,
Mark Brown07ed8732012-06-18 21:08:44 +01001855 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +01001856 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown01df2592012-12-12 16:22:08 +09001857 .set_tristate = arizona_set_tristate,
Mark Brown07ed8732012-06-18 21:08:44 +01001858};
Mark Browna8379872012-07-09 12:16:41 +01001859EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +01001860
Mark Brownbd1dd882013-05-17 13:29:03 +01001861const struct snd_soc_dai_ops arizona_simple_dai_ops = {
1862 .startup = arizona_startup,
1863 .hw_params = arizona_hw_params_rate,
1864 .set_sysclk = arizona_dai_set_sysclk,
1865};
1866EXPORT_SYMBOL_GPL(arizona_simple_dai_ops);
1867
Mark Brown5b2eec32012-07-04 17:32:05 +01001868int arizona_init_dai(struct arizona_priv *priv, int id)
1869{
1870 struct arizona_dai_priv *dai_priv = &priv->dai[id];
1871
1872 dai_priv->clk = ARIZONA_CLK_SYSCLK;
Charles Keepaxd81221f2016-02-04 16:29:01 +00001873 dai_priv->constraint = arizona_constraint;
Mark Brown5b2eec32012-07-04 17:32:05 +01001874
1875 return 0;
1876}
1877EXPORT_SYMBOL_GPL(arizona_init_dai);
1878
Mark Brown07ed8732012-06-18 21:08:44 +01001879static struct {
1880 unsigned int min;
1881 unsigned int max;
1882 u16 fratio;
1883 int ratio;
1884} fll_fratios[] = {
1885 { 0, 64000, 4, 16 },
1886 { 64000, 128000, 3, 8 },
1887 { 128000, 256000, 2, 4 },
1888 { 256000, 1000000, 1, 2 },
1889 { 1000000, 13500000, 0, 1 },
1890};
1891
Richard Fitzgerald01582a82016-02-10 11:56:13 +00001892static const unsigned int pseudo_fref_max[ARIZONA_FLL_MAX_FRATIO] = {
1893 13500000,
1894 6144000,
1895 6144000,
1896 3072000,
1897 3072000,
1898 2822400,
1899 2822400,
1900 1536000,
1901 1536000,
1902 1536000,
1903 1536000,
1904 1536000,
1905 1536000,
1906 1536000,
1907 1536000,
1908 768000,
1909};
1910
Mark Brown8f113d72013-03-05 12:08:57 +08001911static struct {
1912 unsigned int min;
1913 unsigned int max;
1914 u16 gain;
1915} fll_gains[] = {
1916 { 0, 256000, 0 },
1917 { 256000, 1000000, 2 },
1918 { 1000000, 13500000, 4 },
1919};
1920
Mark Brown07ed8732012-06-18 21:08:44 +01001921struct arizona_fll_cfg {
1922 int n;
1923 int theta;
1924 int lambda;
1925 int refdiv;
1926 int outdiv;
1927 int fratio;
Mark Brown8f113d72013-03-05 12:08:57 +08001928 int gain;
Mark Brown07ed8732012-06-18 21:08:44 +01001929};
1930
Charles Keepax23f785a82014-03-07 16:34:20 +00001931static int arizona_validate_fll(struct arizona_fll *fll,
1932 unsigned int Fref,
1933 unsigned int Fout)
1934{
1935 unsigned int Fvco_min;
1936
Charles Keepaxc8badda2014-07-09 17:41:49 +01001937 if (fll->fout && Fout != fll->fout) {
1938 arizona_fll_err(fll,
1939 "Can't change output on active FLL\n");
1940 return -EINVAL;
1941 }
1942
Charles Keepax23f785a82014-03-07 16:34:20 +00001943 if (Fref / ARIZONA_FLL_MAX_REFDIV > ARIZONA_FLL_MAX_FREF) {
1944 arizona_fll_err(fll,
1945 "Can't scale %dMHz in to <=13.5MHz\n",
1946 Fref);
1947 return -EINVAL;
1948 }
1949
1950 Fvco_min = ARIZONA_FLL_MIN_FVCO * fll->vco_mult;
1951 if (Fout * ARIZONA_FLL_MAX_OUTDIV < Fvco_min) {
1952 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
1953 Fout);
1954 return -EINVAL;
1955 }
1956
1957 return 0;
1958}
1959
Charles Keepaxd0800342014-03-07 16:34:25 +00001960static int arizona_find_fratio(unsigned int Fref, int *fratio)
1961{
1962 int i;
1963
1964 /* Find an appropriate FLL_FRATIO */
1965 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
1966 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
1967 if (fratio)
1968 *fratio = fll_fratios[i].fratio;
1969 return fll_fratios[i].ratio;
1970 }
1971 }
1972
1973 return -EINVAL;
1974}
1975
1976static int arizona_calc_fratio(struct arizona_fll *fll,
1977 struct arizona_fll_cfg *cfg,
1978 unsigned int target,
1979 unsigned int Fref, bool sync)
1980{
1981 int init_ratio, ratio;
1982 int refdiv, div;
1983
1984 /* Fref must be <=13.5MHz, find initial refdiv */
1985 div = 1;
1986 cfg->refdiv = 0;
1987 while (Fref > ARIZONA_FLL_MAX_FREF) {
1988 div *= 2;
1989 Fref /= 2;
1990 cfg->refdiv++;
1991
1992 if (div > ARIZONA_FLL_MAX_REFDIV)
1993 return -EINVAL;
1994 }
1995
1996 /* Find an appropriate FLL_FRATIO */
1997 init_ratio = arizona_find_fratio(Fref, &cfg->fratio);
1998 if (init_ratio < 0) {
1999 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
2000 Fref);
2001 return init_ratio;
2002 }
2003
2004 switch (fll->arizona->type) {
Richard Fitzgerald3451eb42015-12-16 17:06:24 +00002005 case WM5102:
2006 case WM8997:
2007 return init_ratio;
Charles Keepaxd0800342014-03-07 16:34:25 +00002008 case WM5110:
Richard Fitzgerald575ef7f2015-01-17 15:21:27 +00002009 case WM8280:
Charles Keepaxd0800342014-03-07 16:34:25 +00002010 if (fll->arizona->rev < 3 || sync)
2011 return init_ratio;
2012 break;
Richard Fitzgerald3451eb42015-12-16 17:06:24 +00002013 default:
Richard Fitzgerald6ebbce02015-09-28 14:01:09 +01002014 if (sync)
2015 return init_ratio;
2016 break;
Charles Keepaxd0800342014-03-07 16:34:25 +00002017 }
2018
2019 cfg->fratio = init_ratio - 1;
2020
2021 /* Adjust FRATIO/refdiv to avoid integer mode if possible */
2022 refdiv = cfg->refdiv;
2023
Richard Fitzgerald01582a82016-02-10 11:56:13 +00002024 arizona_fll_dbg(fll, "pseudo: initial ratio=%u fref=%u refdiv=%u\n",
2025 init_ratio, Fref, refdiv);
2026
Charles Keepaxd0800342014-03-07 16:34:25 +00002027 while (div <= ARIZONA_FLL_MAX_REFDIV) {
Richard Fitzgerald8e42db12016-04-21 14:04:14 +01002028 /* start from init_ratio because this may already give a
2029 * fractional N.K
2030 */
2031 for (ratio = init_ratio; ratio > 0; ratio--) {
2032 if (target % (ratio * Fref)) {
2033 cfg->refdiv = refdiv;
2034 cfg->fratio = ratio - 1;
2035 arizona_fll_dbg(fll,
2036 "pseudo: found fref=%u refdiv=%d(%d) ratio=%d\n",
2037 Fref, refdiv, div, ratio);
2038 return ratio;
2039 }
2040 }
2041
2042 for (ratio = init_ratio + 1; ratio <= ARIZONA_FLL_MAX_FRATIO;
Charles Keepaxd0800342014-03-07 16:34:25 +00002043 ratio++) {
Charles Keepax35a730a2014-07-09 17:41:45 +01002044 if ((ARIZONA_FLL_VCO_CORNER / 2) /
Richard Fitzgerald01582a82016-02-10 11:56:13 +00002045 (fll->vco_mult * ratio) < Fref) {
2046 arizona_fll_dbg(fll, "pseudo: hit VCO corner\n");
Charles Keepax29fee822014-07-09 17:41:44 +01002047 break;
Richard Fitzgerald01582a82016-02-10 11:56:13 +00002048 }
2049
2050 if (Fref > pseudo_fref_max[ratio - 1]) {
2051 arizona_fll_dbg(fll,
2052 "pseudo: exceeded max fref(%u) for ratio=%u\n",
2053 pseudo_fref_max[ratio - 1],
2054 ratio);
2055 break;
2056 }
Charles Keepax29fee822014-07-09 17:41:44 +01002057
Charles Keepaxd0800342014-03-07 16:34:25 +00002058 if (target % (ratio * Fref)) {
2059 cfg->refdiv = refdiv;
2060 cfg->fratio = ratio - 1;
Richard Fitzgerald01582a82016-02-10 11:56:13 +00002061 arizona_fll_dbg(fll,
2062 "pseudo: found fref=%u refdiv=%d(%d) ratio=%d\n",
2063 Fref, refdiv, div, ratio);
Charles Keepaxd0800342014-03-07 16:34:25 +00002064 return ratio;
2065 }
2066 }
2067
Charles Keepaxd0800342014-03-07 16:34:25 +00002068 div *= 2;
2069 Fref /= 2;
2070 refdiv++;
2071 init_ratio = arizona_find_fratio(Fref, NULL);
Richard Fitzgerald01582a82016-02-10 11:56:13 +00002072 arizona_fll_dbg(fll,
2073 "pseudo: change fref=%u refdiv=%d(%d) ratio=%u\n",
2074 Fref, refdiv, div, init_ratio);
Charles Keepaxd0800342014-03-07 16:34:25 +00002075 }
2076
2077 arizona_fll_warn(fll, "Falling back to integer mode operation\n");
2078 return cfg->fratio + 1;
2079}
2080
Mark Brown07ed8732012-06-18 21:08:44 +01002081static int arizona_calc_fll(struct arizona_fll *fll,
2082 struct arizona_fll_cfg *cfg,
Charles Keepaxd0800342014-03-07 16:34:25 +00002083 unsigned int Fref, bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01002084{
2085 unsigned int target, div, gcd_fll;
2086 int i, ratio;
2087
Charles Keepax8ccefcd2014-03-07 16:34:21 +00002088 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, fll->fout);
Mark Brown07ed8732012-06-18 21:08:44 +01002089
Mark Brown2b4d39f2012-07-10 17:03:46 +01002090 /* Fvco should be over the targt; don't check the upper bound */
Charles Keepaxf641aec2014-03-07 16:34:22 +00002091 div = ARIZONA_FLL_MIN_OUTDIV;
2092 while (fll->fout * div < ARIZONA_FLL_MIN_FVCO * fll->vco_mult) {
Mark Brown07ed8732012-06-18 21:08:44 +01002093 div++;
Charles Keepaxf641aec2014-03-07 16:34:22 +00002094 if (div > ARIZONA_FLL_MAX_OUTDIV)
Mark Brown07ed8732012-06-18 21:08:44 +01002095 return -EINVAL;
Mark Brown07ed8732012-06-18 21:08:44 +01002096 }
Charles Keepaxf641aec2014-03-07 16:34:22 +00002097 target = fll->fout * div / fll->vco_mult;
Mark Brown07ed8732012-06-18 21:08:44 +01002098 cfg->outdiv = div;
2099
2100 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
2101
Charles Keepaxd0800342014-03-07 16:34:25 +00002102 /* Find an appropriate FLL_FRATIO and refdiv */
2103 ratio = arizona_calc_fratio(fll, cfg, target, Fref, sync);
2104 if (ratio < 0)
2105 return ratio;
Mark Brown07ed8732012-06-18 21:08:44 +01002106
Mark Brown07ed8732012-06-18 21:08:44 +01002107 /* Apply the division for our remaining calculations */
Charles Keepaxd0800342014-03-07 16:34:25 +00002108 Fref = Fref / (1 << cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08002109
Mark Brown07ed8732012-06-18 21:08:44 +01002110 cfg->n = target / (ratio * Fref);
2111
Ryo Tsutsui01f58152013-02-03 17:18:00 +09002112 if (target % (ratio * Fref)) {
Mark Brown07ed8732012-06-18 21:08:44 +01002113 gcd_fll = gcd(target, ratio * Fref);
2114 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
2115
2116 cfg->theta = (target - (cfg->n * ratio * Fref))
2117 / gcd_fll;
2118 cfg->lambda = (ratio * Fref) / gcd_fll;
2119 } else {
2120 cfg->theta = 0;
2121 cfg->lambda = 0;
2122 }
2123
Ryo Tsutsui01f58152013-02-03 17:18:00 +09002124 /* Round down to 16bit range with cost of accuracy lost.
2125 * Denominator must be bigger than numerator so we only
2126 * take care of it.
2127 */
2128 while (cfg->lambda >= (1 << 16)) {
2129 cfg->theta >>= 1;
2130 cfg->lambda >>= 1;
2131 }
2132
Charles Keepax5a3935c2014-03-07 16:34:23 +00002133 for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
2134 if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
2135 cfg->gain = fll_gains[i].gain;
2136 break;
2137 }
2138 }
2139 if (i == ARRAY_SIZE(fll_gains)) {
2140 arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
2141 Fref);
2142 return -EINVAL;
2143 }
2144
Richard Fitzgerald2595b7f2016-02-23 14:16:32 +00002145 arizona_fll_dbg(fll, "N=%d THETA=%d LAMBDA=%d\n",
Mark Brown07ed8732012-06-18 21:08:44 +01002146 cfg->n, cfg->theta, cfg->lambda);
Richard Fitzgerald2595b7f2016-02-23 14:16:32 +00002147 arizona_fll_dbg(fll, "FRATIO=0x%x(%d) OUTDIV=%d REFCLK_DIV=0x%x(%d)\n",
2148 cfg->fratio, ratio, cfg->outdiv,
2149 cfg->refdiv, 1 << cfg->refdiv);
2150 arizona_fll_dbg(fll, "GAIN=0x%x(%d)\n", cfg->gain, 1 << cfg->gain);
Mark Brown07ed8732012-06-18 21:08:44 +01002151
2152 return 0;
2153
2154}
2155
2156static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
Mark Brown8f113d72013-03-05 12:08:57 +08002157 struct arizona_fll_cfg *cfg, int source,
2158 bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01002159{
Mark Brown3c43c692013-12-12 00:49:22 +00002160 regmap_update_bits_async(arizona->regmap, base + 3,
2161 ARIZONA_FLL1_THETA_MASK, cfg->theta);
2162 regmap_update_bits_async(arizona->regmap, base + 4,
2163 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
2164 regmap_update_bits_async(arizona->regmap, base + 5,
2165 ARIZONA_FLL1_FRATIO_MASK,
2166 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
2167 regmap_update_bits_async(arizona->regmap, base + 6,
2168 ARIZONA_FLL1_CLK_REF_DIV_MASK |
2169 ARIZONA_FLL1_CLK_REF_SRC_MASK,
2170 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
2171 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
Mark Brown07ed8732012-06-18 21:08:44 +01002172
Charles Keepax61719db2014-03-07 16:34:19 +00002173 if (sync) {
2174 regmap_update_bits(arizona->regmap, base + 0x7,
2175 ARIZONA_FLL1_GAIN_MASK,
2176 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
2177 } else {
2178 regmap_update_bits(arizona->regmap, base + 0x5,
2179 ARIZONA_FLL1_OUTDIV_MASK,
2180 cfg->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
2181 regmap_update_bits(arizona->regmap, base + 0x9,
2182 ARIZONA_FLL1_GAIN_MASK,
2183 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
2184 }
Mark Brown8f113d72013-03-05 12:08:57 +08002185
Mark Brown3c43c692013-12-12 00:49:22 +00002186 regmap_update_bits_async(arizona->regmap, base + 2,
2187 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
2188 ARIZONA_FLL1_CTRL_UPD | cfg->n);
Mark Brown07ed8732012-06-18 21:08:44 +01002189}
2190
Charles Keepaxc393aca2014-07-09 17:41:47 +01002191static int arizona_is_enabled_fll(struct arizona_fll *fll)
Charles Keepaxd122d6c2013-02-20 17:28:36 +00002192{
2193 struct arizona *arizona = fll->arizona;
2194 unsigned int reg;
2195 int ret;
2196
2197 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
2198 if (ret != 0) {
2199 arizona_fll_err(fll, "Failed to read current state: %d\n",
2200 ret);
2201 return ret;
2202 }
2203
2204 return reg & ARIZONA_FLL1_ENA;
2205}
2206
Charles Keepaxc393aca2014-07-09 17:41:47 +01002207static int arizona_enable_fll(struct arizona_fll *fll)
Charles Keepax35722812013-02-20 17:28:38 +00002208{
2209 struct arizona *arizona = fll->arizona;
Charles Keepax49c60542013-09-16 15:34:35 +01002210 bool use_sync = false;
Charles Keepaxc393aca2014-07-09 17:41:47 +01002211 int already_enabled = arizona_is_enabled_fll(fll);
Charles Keepax23f785a82014-03-07 16:34:20 +00002212 struct arizona_fll_cfg cfg;
Charles Keepax0e765972015-08-25 12:43:48 +01002213 int i;
2214 unsigned int val;
Charles Keepax35722812013-02-20 17:28:38 +00002215
Charles Keepaxc393aca2014-07-09 17:41:47 +01002216 if (already_enabled < 0)
2217 return already_enabled;
2218
Charles Keepaxc8badda2014-07-09 17:41:49 +01002219 if (already_enabled) {
2220 /* Facilitate smooth refclk across the transition */
Charles Keepax800f2972015-11-30 17:37:28 +00002221 regmap_update_bits(fll->arizona->regmap, fll->base + 1,
2222 ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
2223 udelay(32);
Nariman Poushinc9991052016-08-30 10:30:40 +01002224 regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9,
2225 ARIZONA_FLL1_GAIN_MASK, 0);
Charles Keepaxc8badda2014-07-09 17:41:49 +01002226 }
2227
Mark Brownff680a12013-03-04 16:00:19 +08002228 /*
2229 * If we have both REFCLK and SYNCCLK then enable both,
2230 * otherwise apply the SYNCCLK settings to REFCLK.
2231 */
Charles Keepax49c60542013-09-16 15:34:35 +01002232 if (fll->ref_src >= 0 && fll->ref_freq &&
2233 fll->ref_src != fll->sync_src) {
Charles Keepaxd0800342014-03-07 16:34:25 +00002234 arizona_calc_fll(fll, &cfg, fll->ref_freq, false);
Charles Keepax35722812013-02-20 17:28:38 +00002235
Charles Keepax23f785a82014-03-07 16:34:20 +00002236 arizona_apply_fll(arizona, fll->base, &cfg, fll->ref_src,
Mark Brown8f113d72013-03-05 12:08:57 +08002237 false);
Charles Keepax49c60542013-09-16 15:34:35 +01002238 if (fll->sync_src >= 0) {
Charles Keepaxd0800342014-03-07 16:34:25 +00002239 arizona_calc_fll(fll, &cfg, fll->sync_freq, true);
Charles Keepax23f785a82014-03-07 16:34:20 +00002240
2241 arizona_apply_fll(arizona, fll->base + 0x10, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08002242 fll->sync_src, true);
Charles Keepax49c60542013-09-16 15:34:35 +01002243 use_sync = true;
2244 }
Mark Brownff680a12013-03-04 16:00:19 +08002245 } else if (fll->sync_src >= 0) {
Charles Keepaxd0800342014-03-07 16:34:25 +00002246 arizona_calc_fll(fll, &cfg, fll->sync_freq, false);
Mark Brownff680a12013-03-04 16:00:19 +08002247
Charles Keepax23f785a82014-03-07 16:34:20 +00002248 arizona_apply_fll(arizona, fll->base, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08002249 fll->sync_src, false);
Mark Browneca2e8e2013-03-06 00:09:59 +08002250
Mark Brown3c43c692013-12-12 00:49:22 +00002251 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
2252 ARIZONA_FLL1_SYNC_ENA, 0);
Mark Brownff680a12013-03-04 16:00:19 +08002253 } else {
2254 arizona_fll_err(fll, "No clocks provided\n");
Charles Keepaxc393aca2014-07-09 17:41:47 +01002255 return -EINVAL;
Mark Brownff680a12013-03-04 16:00:19 +08002256 }
Charles Keepax35722812013-02-20 17:28:38 +00002257
Mark Brown576411be2013-03-05 12:07:16 +08002258 /*
2259 * Increase the bandwidth if we're not using a low frequency
2260 * sync source.
2261 */
Charles Keepax49c60542013-09-16 15:34:35 +01002262 if (use_sync && fll->sync_freq > 100000)
Mark Brown3c43c692013-12-12 00:49:22 +00002263 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
2264 ARIZONA_FLL1_SYNC_BW, 0);
Mark Brown576411be2013-03-05 12:07:16 +08002265 else
Mark Brown3c43c692013-12-12 00:49:22 +00002266 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
2267 ARIZONA_FLL1_SYNC_BW,
2268 ARIZONA_FLL1_SYNC_BW);
Mark Brown576411be2013-03-05 12:07:16 +08002269
Charles Keepaxc393aca2014-07-09 17:41:47 +01002270 if (!already_enabled)
Charles Keepax35722812013-02-20 17:28:38 +00002271 pm_runtime_get(arizona->dev);
2272
Mark Brown3c43c692013-12-12 00:49:22 +00002273 regmap_update_bits_async(arizona->regmap, fll->base + 1,
Mark Brown3c43c692013-12-12 00:49:22 +00002274 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
Charles Keepax49c60542013-09-16 15:34:35 +01002275 if (use_sync)
Mark Brown3c43c692013-12-12 00:49:22 +00002276 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
2277 ARIZONA_FLL1_SYNC_ENA,
2278 ARIZONA_FLL1_SYNC_ENA);
Charles Keepax35722812013-02-20 17:28:38 +00002279
Charles Keepaxc8badda2014-07-09 17:41:49 +01002280 if (already_enabled)
2281 regmap_update_bits_async(arizona->regmap, fll->base + 1,
2282 ARIZONA_FLL1_FREERUN, 0);
2283
Charles Keepax0e765972015-08-25 12:43:48 +01002284 arizona_fll_dbg(fll, "Waiting for FLL lock...\n");
2285 val = 0;
2286 for (i = 0; i < 15; i++) {
2287 if (i < 5)
2288 usleep_range(200, 400);
2289 else
2290 msleep(20);
2291
2292 regmap_read(arizona->regmap,
2293 ARIZONA_INTERRUPT_RAW_STATUS_5,
2294 &val);
2295 if (val & (ARIZONA_FLL1_CLOCK_OK_STS << (fll->id - 1)))
2296 break;
2297 }
2298 if (i == 15)
Charles Keepax35722812013-02-20 17:28:38 +00002299 arizona_fll_warn(fll, "Timed out waiting for lock\n");
Charles Keepax0e765972015-08-25 12:43:48 +01002300 else
2301 arizona_fll_dbg(fll, "FLL locked (%d polls)\n", i);
Charles Keepaxc393aca2014-07-09 17:41:47 +01002302
2303 return 0;
Charles Keepax35722812013-02-20 17:28:38 +00002304}
2305
Charles Keepax76040542013-02-20 17:28:37 +00002306static void arizona_disable_fll(struct arizona_fll *fll)
2307{
2308 struct arizona *arizona = fll->arizona;
2309 bool change;
2310
Mark Brown3c43c692013-12-12 00:49:22 +00002311 regmap_update_bits_async(arizona->regmap, fll->base + 1,
2312 ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
Charles Keepax76040542013-02-20 17:28:37 +00002313 regmap_update_bits_check(arizona->regmap, fll->base + 1,
2314 ARIZONA_FLL1_ENA, 0, &change);
2315 regmap_update_bits(arizona->regmap, fll->base + 0x11,
2316 ARIZONA_FLL1_SYNC_ENA, 0);
Charles Keepax5e39a502014-07-09 17:41:48 +01002317 regmap_update_bits_async(arizona->regmap, fll->base + 1,
2318 ARIZONA_FLL1_FREERUN, 0);
Charles Keepax76040542013-02-20 17:28:37 +00002319
2320 if (change)
2321 pm_runtime_put_autosuspend(arizona->dev);
2322}
2323
Charles Keepaxee929a92013-02-20 17:28:40 +00002324int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
2325 unsigned int Fref, unsigned int Fout)
2326{
Charles Keepaxc393aca2014-07-09 17:41:47 +01002327 int ret = 0;
Charles Keepaxee929a92013-02-20 17:28:40 +00002328
Charles Keepax1c5617f2013-02-22 17:10:37 +00002329 if (fll->ref_src == source && fll->ref_freq == Fref)
Charles Keepaxee929a92013-02-20 17:28:40 +00002330 return 0;
2331
Charles Keepax23f785a82014-03-07 16:34:20 +00002332 if (fll->fout && Fref > 0) {
2333 ret = arizona_validate_fll(fll, Fref, fll->fout);
2334 if (ret != 0)
2335 return ret;
Charles Keepaxee929a92013-02-20 17:28:40 +00002336 }
2337
2338 fll->ref_src = source;
2339 fll->ref_freq = Fref;
Charles Keepaxee929a92013-02-20 17:28:40 +00002340
Mark Brown86cd6842013-03-07 16:14:04 +08002341 if (fll->fout && Fref > 0) {
Charles Keepaxc393aca2014-07-09 17:41:47 +01002342 ret = arizona_enable_fll(fll);
Charles Keepaxee929a92013-02-20 17:28:40 +00002343 }
2344
Charles Keepaxc393aca2014-07-09 17:41:47 +01002345 return ret;
Charles Keepaxee929a92013-02-20 17:28:40 +00002346}
2347EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
2348
Mark Brown07ed8732012-06-18 21:08:44 +01002349int arizona_set_fll(struct arizona_fll *fll, int source,
2350 unsigned int Fref, unsigned int Fout)
2351{
Charles Keepaxc393aca2014-07-09 17:41:47 +01002352 int ret = 0;
Mark Brown07ed8732012-06-18 21:08:44 +01002353
Mark Brownff680a12013-03-04 16:00:19 +08002354 if (fll->sync_src == source &&
2355 fll->sync_freq == Fref && fll->fout == Fout)
2356 return 0;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00002357
Mark Brownff680a12013-03-04 16:00:19 +08002358 if (Fout) {
2359 if (fll->ref_src >= 0) {
Charles Keepax23f785a82014-03-07 16:34:20 +00002360 ret = arizona_validate_fll(fll, fll->ref_freq, Fout);
Charles Keepax9e359c62013-02-20 17:28:35 +00002361 if (ret != 0)
2362 return ret;
2363 }
2364
Charles Keepax23f785a82014-03-07 16:34:20 +00002365 ret = arizona_validate_fll(fll, Fref, Fout);
Mark Brownff680a12013-03-04 16:00:19 +08002366 if (ret != 0)
2367 return ret;
Charles Keepax9e359c62013-02-20 17:28:35 +00002368 }
Mark Brownff680a12013-03-04 16:00:19 +08002369
2370 fll->sync_src = source;
2371 fll->sync_freq = Fref;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00002372 fll->fout = Fout;
Charles Keepax9e359c62013-02-20 17:28:35 +00002373
Charles Keepax613124c2014-07-09 17:41:46 +01002374 if (Fout)
Charles Keepaxc393aca2014-07-09 17:41:47 +01002375 ret = arizona_enable_fll(fll);
Charles Keepax613124c2014-07-09 17:41:46 +01002376 else
Charles Keepax76040542013-02-20 17:28:37 +00002377 arizona_disable_fll(fll);
Mark Brown07ed8732012-06-18 21:08:44 +01002378
Charles Keepaxc393aca2014-07-09 17:41:47 +01002379 return ret;
Mark Brown07ed8732012-06-18 21:08:44 +01002380}
2381EXPORT_SYMBOL_GPL(arizona_set_fll);
2382
2383int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
2384 int ok_irq, struct arizona_fll *fll)
2385{
Charles Keepax19b34bd2013-02-20 17:28:34 +00002386 unsigned int val;
Mark Brown07ed8732012-06-18 21:08:44 +01002387
Mark Brown07ed8732012-06-18 21:08:44 +01002388 fll->id = id;
2389 fll->base = base;
2390 fll->arizona = arizona;
Charles Keepaxf3f11632013-02-20 17:28:41 +00002391 fll->sync_src = ARIZONA_FLL_SRC_NONE;
Mark Brown07ed8732012-06-18 21:08:44 +01002392
Charles Keepax19b34bd2013-02-20 17:28:34 +00002393 /* Configure default refclk to 32kHz if we have one */
2394 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
2395 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
2396 case ARIZONA_CLK_SRC_MCLK1:
2397 case ARIZONA_CLK_SRC_MCLK2:
2398 fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK;
2399 break;
2400 default:
Charles Keepaxf3f11632013-02-20 17:28:41 +00002401 fll->ref_src = ARIZONA_FLL_SRC_NONE;
Charles Keepax19b34bd2013-02-20 17:28:34 +00002402 }
2403 fll->ref_freq = 32768;
2404
Mark Brown07ed8732012-06-18 21:08:44 +01002405 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
2406 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
2407 "FLL%d clock OK", id);
2408
Charles Keepaxe31c1942013-01-07 16:41:45 +00002409 regmap_update_bits(arizona->regmap, fll->base + 1,
2410 ARIZONA_FLL1_FREERUN, 0);
2411
Mark Brown07ed8732012-06-18 21:08:44 +01002412 return 0;
2413}
2414EXPORT_SYMBOL_GPL(arizona_init_fll);
2415
Mark Brownbc9ab6d2013-01-04 19:31:00 +00002416/**
2417 * arizona_set_output_mode - Set the mode of the specified output
2418 *
2419 * @codec: Device to configure
2420 * @output: Output number
2421 * @diff: True to set the output to differential mode
2422 *
2423 * Some systems use external analogue switches to connect more
2424 * analogue devices to the CODEC than are supported by the device. In
2425 * some systems this requires changing the switched output from single
2426 * ended to differential mode dynamically at runtime, an operation
2427 * supported using this function.
2428 *
2429 * Most systems have a single static configuration and should use
2430 * platform data instead.
2431 */
2432int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
2433{
2434 unsigned int reg, val;
2435
2436 if (output < 1 || output > 6)
2437 return -EINVAL;
2438
2439 reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
2440
2441 if (diff)
2442 val = ARIZONA_OUT1_MONO;
2443 else
2444 val = 0;
2445
2446 return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val);
2447}
2448EXPORT_SYMBOL_GPL(arizona_set_output_mode);
2449
Richard Fitzgerald336d0442015-06-18 13:43:19 +01002450static const struct soc_enum arizona_adsp2_rate_enum[] = {
2451 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP1_CONTROL_1,
2452 ARIZONA_DSP1_RATE_SHIFT, 0xf,
2453 ARIZONA_RATE_ENUM_SIZE,
2454 arizona_rate_text, arizona_rate_val),
2455 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP2_CONTROL_1,
2456 ARIZONA_DSP1_RATE_SHIFT, 0xf,
2457 ARIZONA_RATE_ENUM_SIZE,
2458 arizona_rate_text, arizona_rate_val),
2459 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1,
2460 ARIZONA_DSP1_RATE_SHIFT, 0xf,
2461 ARIZONA_RATE_ENUM_SIZE,
2462 arizona_rate_text, arizona_rate_val),
2463 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP4_CONTROL_1,
2464 ARIZONA_DSP1_RATE_SHIFT, 0xf,
2465 ARIZONA_RATE_ENUM_SIZE,
2466 arizona_rate_text, arizona_rate_val),
2467};
2468
2469const struct snd_kcontrol_new arizona_adsp2_rate_controls[] = {
2470 SOC_ENUM("DSP1 Rate", arizona_adsp2_rate_enum[0]),
2471 SOC_ENUM("DSP2 Rate", arizona_adsp2_rate_enum[1]),
2472 SOC_ENUM("DSP3 Rate", arizona_adsp2_rate_enum[2]),
2473 SOC_ENUM("DSP4 Rate", arizona_adsp2_rate_enum[3]),
2474};
2475EXPORT_SYMBOL_GPL(arizona_adsp2_rate_controls);
2476
Charles Keepaxc05d9a82015-06-25 09:35:11 +01002477static bool arizona_eq_filter_unstable(bool mode, __be16 _a, __be16 _b)
2478{
2479 s16 a = be16_to_cpu(_a);
2480 s16 b = be16_to_cpu(_b);
2481
2482 if (!mode) {
2483 return abs(a) >= 4096;
2484 } else {
2485 if (abs(b) >= 4096)
2486 return true;
2487
2488 return (abs((a << 16) / (4096 - b)) >= 4096 << 4);
2489 }
2490}
2491
2492int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol,
2493 struct snd_ctl_elem_value *ucontrol)
2494{
2495 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
2496 struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
2497 struct soc_bytes *params = (void *)kcontrol->private_value;
2498 unsigned int val;
2499 __be16 *data;
2500 int len;
2501 int ret;
2502
2503 len = params->num_regs * regmap_get_val_bytes(arizona->regmap);
2504
2505 data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA);
2506 if (!data)
2507 return -ENOMEM;
2508
2509 data[0] &= cpu_to_be16(ARIZONA_EQ1_B1_MODE);
2510
2511 if (arizona_eq_filter_unstable(!!data[0], data[1], data[2]) ||
2512 arizona_eq_filter_unstable(true, data[4], data[5]) ||
2513 arizona_eq_filter_unstable(true, data[8], data[9]) ||
2514 arizona_eq_filter_unstable(true, data[12], data[13]) ||
2515 arizona_eq_filter_unstable(false, data[16], data[17])) {
2516 dev_err(arizona->dev, "Rejecting unstable EQ coefficients\n");
2517 ret = -EINVAL;
2518 goto out;
2519 }
2520
2521 ret = regmap_read(arizona->regmap, params->base, &val);
2522 if (ret != 0)
2523 goto out;
2524
2525 val &= ~ARIZONA_EQ1_B1_MODE;
2526 data[0] |= cpu_to_be16(val);
2527
2528 ret = regmap_raw_write(arizona->regmap, params->base, data, len);
2529
2530out:
2531 kfree(data);
2532 return ret;
2533}
2534EXPORT_SYMBOL_GPL(arizona_eq_coeff_put);
2535
Charles Keepax5f8e6712015-06-25 09:35:12 +01002536int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
2537 struct snd_ctl_elem_value *ucontrol)
2538{
2539 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
2540 struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
2541 __be16 *data = (__be16 *)ucontrol->value.bytes.data;
2542 s16 val = be16_to_cpu(*data);
2543
2544 if (abs(val) >= 4096) {
2545 dev_err(arizona->dev, "Rejecting unstable LHPF coefficients\n");
2546 return -EINVAL;
2547 }
2548
2549 return snd_soc_bytes_put(kcontrol, ucontrol);
2550}
2551EXPORT_SYMBOL_GPL(arizona_lhpf_coeff_put);
2552
Charles Keepax2230c492016-05-13 16:45:18 +01002553int arizona_register_notifier(struct snd_soc_codec *codec,
2554 struct notifier_block *nb,
2555 int (*notify)(struct notifier_block *nb,
2556 unsigned long action, void *data))
2557{
2558 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
2559 struct arizona *arizona = priv->arizona;
2560
2561 nb->notifier_call = notify;
2562
2563 return blocking_notifier_chain_register(&arizona->notifier, nb);
2564}
2565EXPORT_SYMBOL_GPL(arizona_register_notifier);
2566
2567int arizona_unregister_notifier(struct snd_soc_codec *codec,
2568 struct notifier_block *nb)
2569{
2570 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
2571 struct arizona *arizona = priv->arizona;
2572
2573 return blocking_notifier_chain_unregister(&arizona->notifier, nb);
2574}
2575EXPORT_SYMBOL_GPL(arizona_unregister_notifier);
2576
Mark Brown07ed8732012-06-18 21:08:44 +01002577MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
2578MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
2579MODULE_LICENSE("GPL");