blob: 846ca079845fa8d141411e6944f369e904e95b61 [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
Charles Keepax8c7788f2016-09-27 16:35:45 +0100112 return arizona_out_ev(w, kcontrol, event);
Mark Brown56447e12013-01-10 14:45:58 +0000113}
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,
Charles Keepax8c7788f2016-09-27 16:35:45 +0100162 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
163 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD);
Mark Brown56447e12013-01-10 14:45:58 +0000164
165static const struct snd_soc_dapm_widget arizona_spkr =
Mark Brownf4a76e72013-03-13 12:22:39 +0000166 SND_SOC_DAPM_PGA_E("OUT4R", SND_SOC_NOPM,
Mark Brown56447e12013-01-10 14:45:58 +0000167 ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
Charles Keepax8c7788f2016-09-27 16:35:45 +0100168 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
169 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD);
Mark Brown56447e12013-01-10 14:45:58 +0000170
171int arizona_init_spk(struct snd_soc_codec *codec)
172{
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200173 struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
Mark Brown899817e2013-03-13 12:32:10 +0000174 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
175 struct arizona *arizona = priv->arizona;
Mark Brown56447e12013-01-10 14:45:58 +0000176 int ret;
177
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200178 ret = snd_soc_dapm_new_controls(dapm, &arizona_spkl, 1);
Mark Brown56447e12013-01-10 14:45:58 +0000179 if (ret != 0)
180 return ret;
181
Charles Keepax40843ae2013-08-12 23:46:55 +0100182 switch (arizona->type) {
183 case WM8997:
Richard Fitzgerald43b27d72016-04-08 16:50:14 +0100184 case CS47L24:
185 case WM1831:
Charles Keepax40843ae2013-08-12 23:46:55 +0100186 break;
187 default:
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200188 ret = snd_soc_dapm_new_controls(dapm, &arizona_spkr, 1);
Charles Keepax40843ae2013-08-12 23:46:55 +0100189 if (ret != 0)
190 return ret;
191 break;
192 }
Mark Brown56447e12013-01-10 14:45:58 +0000193
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100194 ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN,
Mark Brown899817e2013-03-13 12:32:10 +0000195 "Thermal warning", arizona_thermal_warn,
196 arizona);
197 if (ret != 0)
198 dev_err(arizona->dev,
199 "Failed to get thermal warning IRQ: %d\n",
200 ret);
201
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100202 ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT,
Mark Brown899817e2013-03-13 12:32:10 +0000203 "Thermal shutdown", arizona_thermal_shutdown,
204 arizona);
205 if (ret != 0)
206 dev_err(arizona->dev,
207 "Failed to get thermal shutdown IRQ: %d\n",
208 ret);
209
Mark Brown56447e12013-01-10 14:45:58 +0000210 return 0;
211}
212EXPORT_SYMBOL_GPL(arizona_init_spk);
213
Charles Keepax54dca702016-04-15 13:11:56 +0100214int arizona_free_spk(struct snd_soc_codec *codec)
215{
216 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
217 struct arizona *arizona = priv->arizona;
218
219 arizona_free_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN, arizona);
220 arizona_free_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT, arizona);
221
222 return 0;
223}
224EXPORT_SYMBOL_GPL(arizona_free_spk);
225
Charles Keepaxb60f3632014-06-10 18:41:02 +0100226static const struct snd_soc_dapm_route arizona_mono_routes[] = {
227 { "OUT1R", NULL, "OUT1L" },
228 { "OUT2R", NULL, "OUT2L" },
229 { "OUT3R", NULL, "OUT3L" },
230 { "OUT4R", NULL, "OUT4L" },
231 { "OUT5R", NULL, "OUT5L" },
232 { "OUT6R", NULL, "OUT6L" },
233};
234
235int arizona_init_mono(struct snd_soc_codec *codec)
236{
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200237 struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
Charles Keepaxb60f3632014-06-10 18:41:02 +0100238 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
239 struct arizona *arizona = priv->arizona;
240 int i;
241
242 for (i = 0; i < ARIZONA_MAX_OUTPUT; ++i) {
243 if (arizona->pdata.out_mono[i])
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200244 snd_soc_dapm_add_routes(dapm,
Charles Keepaxb60f3632014-06-10 18:41:02 +0100245 &arizona_mono_routes[i], 1);
246 }
247
248 return 0;
249}
250EXPORT_SYMBOL_GPL(arizona_init_mono);
251
Charles Keepaxb63144e2013-07-04 08:56:28 +0100252int arizona_init_gpio(struct snd_soc_codec *codec)
253{
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200254 struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
Charles Keepaxb63144e2013-07-04 08:56:28 +0100255 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
256 struct arizona *arizona = priv->arizona;
257 int i;
258
259 switch (arizona->type) {
260 case WM5110:
Richard Fitzgerald575ef7f2015-01-17 15:21:27 +0000261 case WM8280:
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200262 snd_soc_dapm_disable_pin(dapm, "DRC2 Signal Activity");
Charles Keepaxb79fae62013-07-04 16:53:03 +0100263 break;
264 default:
265 break;
Charles Keepaxb63144e2013-07-04 08:56:28 +0100266 }
267
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200268 snd_soc_dapm_disable_pin(dapm, "DRC1 Signal Activity");
Charles Keepaxb63144e2013-07-04 08:56:28 +0100269
270 for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
271 switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) {
272 case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT:
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200273 snd_soc_dapm_enable_pin(dapm, "DRC1 Signal Activity");
Charles Keepaxb63144e2013-07-04 08:56:28 +0100274 break;
275 case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT:
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200276 snd_soc_dapm_enable_pin(dapm, "DRC2 Signal Activity");
Charles Keepaxb63144e2013-07-04 08:56:28 +0100277 break;
278 default:
279 break;
280 }
281 }
282
283 return 0;
284}
285EXPORT_SYMBOL_GPL(arizona_init_gpio);
286
Charles Keepax2230c492016-05-13 16:45:18 +0100287int arizona_init_notifiers(struct snd_soc_codec *codec)
288{
289 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
290 struct arizona *arizona = priv->arizona;
291
292 BLOCKING_INIT_NOTIFIER_HEAD(&arizona->notifier);
293
294 return 0;
295}
296EXPORT_SYMBOL_GPL(arizona_init_notifiers);
297
Charles Keepax141bc6a2015-12-03 18:15:06 +0000298const char * const arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100299 "None",
300 "Tone Generator 1",
301 "Tone Generator 2",
302 "Haptics",
303 "AEC",
Richard Fitzgerald6ebbce02015-09-28 14:01:09 +0100304 "AEC2",
Mark Brown07ed8732012-06-18 21:08:44 +0100305 "Mic Mute Mixer",
306 "Noise Generator",
307 "IN1L",
308 "IN1R",
309 "IN2L",
310 "IN2R",
311 "IN3L",
312 "IN3R",
Mark Brownc9c56fd2012-07-09 19:09:01 +0100313 "IN4L",
314 "IN4R",
Mark Brown07ed8732012-06-18 21:08:44 +0100315 "AIF1RX1",
316 "AIF1RX2",
317 "AIF1RX3",
318 "AIF1RX4",
319 "AIF1RX5",
320 "AIF1RX6",
321 "AIF1RX7",
322 "AIF1RX8",
323 "AIF2RX1",
324 "AIF2RX2",
Richard Fitzgeralde64001e2013-11-20 13:17:07 +0000325 "AIF2RX3",
326 "AIF2RX4",
327 "AIF2RX5",
328 "AIF2RX6",
Mark Brown07ed8732012-06-18 21:08:44 +0100329 "AIF3RX1",
330 "AIF3RX2",
331 "SLIMRX1",
332 "SLIMRX2",
333 "SLIMRX3",
334 "SLIMRX4",
335 "SLIMRX5",
336 "SLIMRX6",
337 "SLIMRX7",
338 "SLIMRX8",
339 "EQ1",
340 "EQ2",
341 "EQ3",
342 "EQ4",
343 "DRC1L",
344 "DRC1R",
345 "DRC2L",
346 "DRC2R",
347 "LHPF1",
348 "LHPF2",
349 "LHPF3",
350 "LHPF4",
351 "DSP1.1",
352 "DSP1.2",
353 "DSP1.3",
354 "DSP1.4",
355 "DSP1.5",
356 "DSP1.6",
Mark Brownc922cc42012-09-26 16:43:44 +0100357 "DSP2.1",
358 "DSP2.2",
359 "DSP2.3",
360 "DSP2.4",
361 "DSP2.5",
362 "DSP2.6",
363 "DSP3.1",
364 "DSP3.2",
365 "DSP3.3",
366 "DSP3.4",
367 "DSP3.5",
368 "DSP3.6",
369 "DSP4.1",
370 "DSP4.2",
371 "DSP4.3",
372 "DSP4.4",
373 "DSP4.5",
374 "DSP4.6",
Mark Brown07ed8732012-06-18 21:08:44 +0100375 "ASRC1L",
376 "ASRC1R",
377 "ASRC2L",
378 "ASRC2R",
Mark Brown91660bd2012-12-05 20:35:24 +0900379 "ISRC1INT1",
380 "ISRC1INT2",
381 "ISRC1INT3",
382 "ISRC1INT4",
383 "ISRC1DEC1",
384 "ISRC1DEC2",
385 "ISRC1DEC3",
386 "ISRC1DEC4",
387 "ISRC2INT1",
388 "ISRC2INT2",
389 "ISRC2INT3",
390 "ISRC2INT4",
391 "ISRC2DEC1",
392 "ISRC2DEC2",
393 "ISRC2DEC3",
394 "ISRC2DEC4",
395 "ISRC3INT1",
396 "ISRC3INT2",
397 "ISRC3INT3",
398 "ISRC3INT4",
399 "ISRC3DEC1",
400 "ISRC3DEC2",
401 "ISRC3DEC3",
402 "ISRC3DEC4",
Mark Brown07ed8732012-06-18 21:08:44 +0100403};
404EXPORT_SYMBOL_GPL(arizona_mixer_texts);
405
Charles Keepax141bc6a2015-12-03 18:15:06 +0000406unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100407 0x00, /* None */
408 0x04, /* Tone */
409 0x05,
410 0x06, /* Haptics */
411 0x08, /* AEC */
Richard Fitzgerald6ebbce02015-09-28 14:01:09 +0100412 0x09, /* AEC2 */
Mark Brown07ed8732012-06-18 21:08:44 +0100413 0x0c, /* Noise mixer */
414 0x0d, /* Comfort noise */
415 0x10, /* IN1L */
416 0x11,
417 0x12,
418 0x13,
419 0x14,
420 0x15,
Mark Brownc9c56fd2012-07-09 19:09:01 +0100421 0x16,
422 0x17,
Mark Brown07ed8732012-06-18 21:08:44 +0100423 0x20, /* AIF1RX1 */
424 0x21,
425 0x22,
426 0x23,
427 0x24,
428 0x25,
429 0x26,
430 0x27,
431 0x28, /* AIF2RX1 */
432 0x29,
Richard Fitzgeralde64001e2013-11-20 13:17:07 +0000433 0x2a,
434 0x2b,
435 0x2c,
436 0x2d,
Mark Brown07ed8732012-06-18 21:08:44 +0100437 0x30, /* AIF3RX1 */
438 0x31,
439 0x38, /* SLIMRX1 */
440 0x39,
441 0x3a,
442 0x3b,
443 0x3c,
444 0x3d,
445 0x3e,
446 0x3f,
447 0x50, /* EQ1 */
448 0x51,
449 0x52,
450 0x53,
451 0x58, /* DRC1L */
452 0x59,
453 0x5a,
454 0x5b,
455 0x60, /* LHPF1 */
456 0x61,
457 0x62,
458 0x63,
459 0x68, /* DSP1.1 */
460 0x69,
461 0x6a,
462 0x6b,
463 0x6c,
464 0x6d,
Mark Brownc922cc42012-09-26 16:43:44 +0100465 0x70, /* DSP2.1 */
466 0x71,
467 0x72,
468 0x73,
469 0x74,
470 0x75,
471 0x78, /* DSP3.1 */
472 0x79,
473 0x7a,
474 0x7b,
475 0x7c,
476 0x7d,
477 0x80, /* DSP4.1 */
478 0x81,
479 0x82,
480 0x83,
481 0x84,
482 0x85,
Mark Brown07ed8732012-06-18 21:08:44 +0100483 0x90, /* ASRC1L */
484 0x91,
485 0x92,
486 0x93,
Mark Brown91660bd2012-12-05 20:35:24 +0900487 0xa0, /* ISRC1INT1 */
488 0xa1,
489 0xa2,
490 0xa3,
491 0xa4, /* ISRC1DEC1 */
492 0xa5,
493 0xa6,
494 0xa7,
495 0xa8, /* ISRC2DEC1 */
496 0xa9,
497 0xaa,
498 0xab,
499 0xac, /* ISRC2INT1 */
500 0xad,
501 0xae,
502 0xaf,
503 0xb0, /* ISRC3DEC1 */
504 0xb1,
505 0xb2,
506 0xb3,
507 0xb4, /* ISRC3INT1 */
508 0xb5,
509 0xb6,
510 0xb7,
Mark Brown07ed8732012-06-18 21:08:44 +0100511};
512EXPORT_SYMBOL_GPL(arizona_mixer_values);
513
514const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
515EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
516
Richard Fitzgerald6ebbce02015-09-28 14:01:09 +0100517const char * const arizona_sample_rate_text[ARIZONA_SAMPLE_RATE_ENUM_SIZE] = {
518 "12kHz", "24kHz", "48kHz", "96kHz", "192kHz",
519 "11.025kHz", "22.05kHz", "44.1kHz", "88.2kHz", "176.4kHz",
520 "4kHz", "8kHz", "16kHz", "32kHz",
521};
522EXPORT_SYMBOL_GPL(arizona_sample_rate_text);
523
524const unsigned int arizona_sample_rate_val[ARIZONA_SAMPLE_RATE_ENUM_SIZE] = {
525 0x01, 0x02, 0x03, 0x04, 0x05, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
526 0x10, 0x11, 0x12, 0x13,
527};
528EXPORT_SYMBOL_GPL(arizona_sample_rate_val);
529
530const char *arizona_sample_rate_val_to_name(unsigned int rate_val)
531{
532 int i;
533
534 for (i = 0; i < ARRAY_SIZE(arizona_sample_rate_val); ++i) {
535 if (arizona_sample_rate_val[i] == rate_val)
536 return arizona_sample_rate_text[i];
537 }
538
539 return "Illegal";
540}
541EXPORT_SYMBOL_GPL(arizona_sample_rate_val_to_name);
542
Charles Keepax141bc6a2015-12-03 18:15:06 +0000543const char * const arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = {
Mark Browndc914282013-02-18 19:09:23 +0000544 "SYNCCLK rate", "8kHz", "16kHz", "ASYNCCLK rate",
545};
546EXPORT_SYMBOL_GPL(arizona_rate_text);
547
Charles Keepax141bc6a2015-12-03 18:15:06 +0000548const unsigned int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
Mark Browndc914282013-02-18 19:09:23 +0000549 0, 1, 2, 8,
550};
551EXPORT_SYMBOL_GPL(arizona_rate_val);
552
553
Charles Keepaxfbedc8c2013-12-19 09:30:12 +0000554const struct soc_enum arizona_isrc_fsh[] = {
555 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_1,
556 ARIZONA_ISRC1_FSH_SHIFT, 0xf,
557 ARIZONA_RATE_ENUM_SIZE,
558 arizona_rate_text, arizona_rate_val),
559 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_1,
560 ARIZONA_ISRC2_FSH_SHIFT, 0xf,
561 ARIZONA_RATE_ENUM_SIZE,
562 arizona_rate_text, arizona_rate_val),
563 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_1,
564 ARIZONA_ISRC3_FSH_SHIFT, 0xf,
565 ARIZONA_RATE_ENUM_SIZE,
566 arizona_rate_text, arizona_rate_val),
567};
568EXPORT_SYMBOL_GPL(arizona_isrc_fsh);
569
Mark Browndc914282013-02-18 19:09:23 +0000570const struct soc_enum arizona_isrc_fsl[] = {
571 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2,
572 ARIZONA_ISRC1_FSL_SHIFT, 0xf,
573 ARIZONA_RATE_ENUM_SIZE,
574 arizona_rate_text, arizona_rate_val),
575 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_2,
576 ARIZONA_ISRC2_FSL_SHIFT, 0xf,
577 ARIZONA_RATE_ENUM_SIZE,
578 arizona_rate_text, arizona_rate_val),
579 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_2,
580 ARIZONA_ISRC3_FSL_SHIFT, 0xf,
581 ARIZONA_RATE_ENUM_SIZE,
582 arizona_rate_text, arizona_rate_val),
583};
584EXPORT_SYMBOL_GPL(arizona_isrc_fsl);
585
Charles Keepax56d37d82013-12-19 09:30:13 +0000586const struct soc_enum arizona_asrc_rate1 =
587 SOC_VALUE_ENUM_SINGLE(ARIZONA_ASRC_RATE1,
588 ARIZONA_ASRC_RATE1_SHIFT, 0xf,
589 ARIZONA_RATE_ENUM_SIZE - 1,
590 arizona_rate_text, arizona_rate_val);
591EXPORT_SYMBOL_GPL(arizona_asrc_rate1);
592
Charles Keepaxa3178a32016-06-13 13:35:14 +0100593static const char * const arizona_vol_ramp_text[] = {
Mark Browne853a002012-12-09 12:25:52 +0900594 "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
595 "15ms/6dB", "30ms/6dB",
596};
597
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100598SOC_ENUM_SINGLE_DECL(arizona_in_vd_ramp,
599 ARIZONA_INPUT_VOLUME_RAMP,
600 ARIZONA_IN_VD_RAMP_SHIFT,
601 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900602EXPORT_SYMBOL_GPL(arizona_in_vd_ramp);
603
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100604SOC_ENUM_SINGLE_DECL(arizona_in_vi_ramp,
605 ARIZONA_INPUT_VOLUME_RAMP,
606 ARIZONA_IN_VI_RAMP_SHIFT,
607 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900608EXPORT_SYMBOL_GPL(arizona_in_vi_ramp);
609
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100610SOC_ENUM_SINGLE_DECL(arizona_out_vd_ramp,
611 ARIZONA_OUTPUT_VOLUME_RAMP,
612 ARIZONA_OUT_VD_RAMP_SHIFT,
613 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900614EXPORT_SYMBOL_GPL(arizona_out_vd_ramp);
615
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100616SOC_ENUM_SINGLE_DECL(arizona_out_vi_ramp,
617 ARIZONA_OUTPUT_VOLUME_RAMP,
618 ARIZONA_OUT_VI_RAMP_SHIFT,
619 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900620EXPORT_SYMBOL_GPL(arizona_out_vi_ramp);
621
Charles Keepaxa3178a32016-06-13 13:35:14 +0100622static const char * const arizona_lhpf_mode_text[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100623 "Low-pass", "High-pass"
624};
625
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100626SOC_ENUM_SINGLE_DECL(arizona_lhpf1_mode,
627 ARIZONA_HPLPF1_1,
628 ARIZONA_LHPF1_MODE_SHIFT,
629 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100630EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
631
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100632SOC_ENUM_SINGLE_DECL(arizona_lhpf2_mode,
633 ARIZONA_HPLPF2_1,
634 ARIZONA_LHPF2_MODE_SHIFT,
635 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100636EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
637
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100638SOC_ENUM_SINGLE_DECL(arizona_lhpf3_mode,
639 ARIZONA_HPLPF3_1,
640 ARIZONA_LHPF3_MODE_SHIFT,
641 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100642EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
643
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100644SOC_ENUM_SINGLE_DECL(arizona_lhpf4_mode,
645 ARIZONA_HPLPF4_1,
646 ARIZONA_LHPF4_MODE_SHIFT,
647 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100648EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
649
Charles Keepaxa3178a32016-06-13 13:35:14 +0100650static const char * const arizona_ng_hold_text[] = {
Mark Brown845571c2012-12-18 13:47:57 +0000651 "30ms", "120ms", "250ms", "500ms",
652};
653
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100654SOC_ENUM_SINGLE_DECL(arizona_ng_hold,
655 ARIZONA_NOISE_GATE_CONTROL,
656 ARIZONA_NGATE_HOLD_SHIFT,
657 arizona_ng_hold_text);
Mark Brown845571c2012-12-18 13:47:57 +0000658EXPORT_SYMBOL_GPL(arizona_ng_hold);
659
Charles Keepax254dc322013-11-19 16:04:03 +0000660static const char * const arizona_in_hpf_cut_text[] = {
661 "2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz"
662};
663
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100664SOC_ENUM_SINGLE_DECL(arizona_in_hpf_cut_enum,
665 ARIZONA_HPF_CONTROL,
666 ARIZONA_IN_HPF_CUT_SHIFT,
667 arizona_in_hpf_cut_text);
Charles Keepax254dc322013-11-19 16:04:03 +0000668EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum);
669
Charles Keepaxc7f38432013-08-06 17:03:55 +0100670static const char * const arizona_in_dmic_osr_text[] = {
Charles Keepaxef326f42014-11-12 14:55:26 +0000671 "1.536MHz", "3.072MHz", "6.144MHz", "768kHz",
Charles Keepaxc7f38432013-08-06 17:03:55 +0100672};
673
674const struct soc_enum arizona_in_dmic_osr[] = {
675 SOC_ENUM_SINGLE(ARIZONA_IN1L_CONTROL, ARIZONA_IN1_OSR_SHIFT,
676 ARRAY_SIZE(arizona_in_dmic_osr_text),
677 arizona_in_dmic_osr_text),
678 SOC_ENUM_SINGLE(ARIZONA_IN2L_CONTROL, ARIZONA_IN2_OSR_SHIFT,
679 ARRAY_SIZE(arizona_in_dmic_osr_text),
680 arizona_in_dmic_osr_text),
681 SOC_ENUM_SINGLE(ARIZONA_IN3L_CONTROL, ARIZONA_IN3_OSR_SHIFT,
682 ARRAY_SIZE(arizona_in_dmic_osr_text),
683 arizona_in_dmic_osr_text),
684 SOC_ENUM_SINGLE(ARIZONA_IN4L_CONTROL, ARIZONA_IN4_OSR_SHIFT,
685 ARRAY_SIZE(arizona_in_dmic_osr_text),
686 arizona_in_dmic_osr_text),
687};
688EXPORT_SYMBOL_GPL(arizona_in_dmic_osr);
689
Charles Keepaxd1901062015-11-19 16:11:10 +0000690static const char * const arizona_anc_input_src_text[] = {
691 "None", "IN1", "IN2", "IN3", "IN4",
692};
693
694static const char * const arizona_anc_channel_src_text[] = {
695 "None", "Left", "Right", "Combine",
696};
697
698const struct soc_enum arizona_anc_input_src[] = {
699 SOC_ENUM_SINGLE(ARIZONA_ANC_SRC,
700 ARIZONA_IN_RXANCL_SEL_SHIFT,
701 ARRAY_SIZE(arizona_anc_input_src_text),
702 arizona_anc_input_src_text),
703 SOC_ENUM_SINGLE(ARIZONA_FCL_ADC_REFORMATTER_CONTROL,
704 ARIZONA_FCL_MIC_MODE_SEL,
705 ARRAY_SIZE(arizona_anc_channel_src_text),
706 arizona_anc_channel_src_text),
707 SOC_ENUM_SINGLE(ARIZONA_ANC_SRC,
708 ARIZONA_IN_RXANCR_SEL_SHIFT,
709 ARRAY_SIZE(arizona_anc_input_src_text),
710 arizona_anc_input_src_text),
711 SOC_ENUM_SINGLE(ARIZONA_FCR_ADC_REFORMATTER_CONTROL,
712 ARIZONA_FCR_MIC_MODE_SEL,
713 ARRAY_SIZE(arizona_anc_channel_src_text),
714 arizona_anc_channel_src_text),
715};
716EXPORT_SYMBOL_GPL(arizona_anc_input_src);
717
718static const char * const arizona_anc_ng_texts[] = {
719 "None",
720 "Internal",
721 "External",
722};
723
724SOC_ENUM_SINGLE_DECL(arizona_anc_ng_enum, SND_SOC_NOPM, 0,
725 arizona_anc_ng_texts);
726EXPORT_SYMBOL_GPL(arizona_anc_ng_enum);
727
728static const char * const arizona_output_anc_src_text[] = {
729 "None", "RXANCL", "RXANCR",
730};
731
732const struct soc_enum arizona_output_anc_src[] = {
733 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L,
734 ARIZONA_OUT1L_ANC_SRC_SHIFT,
735 ARRAY_SIZE(arizona_output_anc_src_text),
736 arizona_output_anc_src_text),
737 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1R,
738 ARIZONA_OUT1R_ANC_SRC_SHIFT,
739 ARRAY_SIZE(arizona_output_anc_src_text),
740 arizona_output_anc_src_text),
741 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2L,
742 ARIZONA_OUT2L_ANC_SRC_SHIFT,
743 ARRAY_SIZE(arizona_output_anc_src_text),
744 arizona_output_anc_src_text),
745 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2R,
746 ARIZONA_OUT2R_ANC_SRC_SHIFT,
747 ARRAY_SIZE(arizona_output_anc_src_text),
748 arizona_output_anc_src_text),
749 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L,
750 ARIZONA_OUT3L_ANC_SRC_SHIFT,
751 ARRAY_SIZE(arizona_output_anc_src_text),
752 arizona_output_anc_src_text),
753 SOC_ENUM_SINGLE(ARIZONA_DAC_VOLUME_LIMIT_3R,
754 ARIZONA_OUT3R_ANC_SRC_SHIFT,
755 ARRAY_SIZE(arizona_output_anc_src_text),
756 arizona_output_anc_src_text),
757 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_4L,
758 ARIZONA_OUT4L_ANC_SRC_SHIFT,
759 ARRAY_SIZE(arizona_output_anc_src_text),
760 arizona_output_anc_src_text),
761 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_4R,
762 ARIZONA_OUT4R_ANC_SRC_SHIFT,
763 ARRAY_SIZE(arizona_output_anc_src_text),
764 arizona_output_anc_src_text),
765 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_5L,
766 ARIZONA_OUT5L_ANC_SRC_SHIFT,
767 ARRAY_SIZE(arizona_output_anc_src_text),
768 arizona_output_anc_src_text),
769 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_5R,
770 ARIZONA_OUT5R_ANC_SRC_SHIFT,
771 ARRAY_SIZE(arizona_output_anc_src_text),
772 arizona_output_anc_src_text),
773 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_6L,
774 ARIZONA_OUT6L_ANC_SRC_SHIFT,
775 ARRAY_SIZE(arizona_output_anc_src_text),
776 arizona_output_anc_src_text),
777 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_6R,
778 ARIZONA_OUT6R_ANC_SRC_SHIFT,
779 ARRAY_SIZE(arizona_output_anc_src_text),
780 arizona_output_anc_src_text),
781};
782EXPORT_SYMBOL_GPL(arizona_output_anc_src);
783
Charles Keepax97126ce2016-05-13 16:45:16 +0100784const struct snd_kcontrol_new arizona_voice_trigger_switch[] = {
785 SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0),
786 SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 1, 1, 0),
787 SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 2, 1, 0),
788 SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 3, 1, 0),
789};
790EXPORT_SYMBOL_GPL(arizona_voice_trigger_switch);
791
Mark Brownddbce972013-02-15 17:27:22 +0000792static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
793{
794 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
795 unsigned int val;
796 int i;
797
798 if (ena)
799 val = ARIZONA_IN_VU;
800 else
801 val = 0;
802
803 for (i = 0; i < priv->num_inputs; i++)
804 snd_soc_update_bits(codec,
805 ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 4),
806 ARIZONA_IN_VU, val);
807}
808
Charles Keepax002b0832015-09-16 13:59:41 +0100809bool arizona_input_analog(struct snd_soc_codec *codec, int shift)
810{
811 unsigned int reg = ARIZONA_IN1L_CONTROL + ((shift / 2) * 8);
812 unsigned int val = snd_soc_read(codec, reg);
813
814 return !(val & ARIZONA_IN1_MODE_MASK);
815}
816EXPORT_SYMBOL_GPL(arizona_input_analog);
817
Mark Brown07ed8732012-06-18 21:08:44 +0100818int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
819 int event)
820{
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100821 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
822 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000823 unsigned int reg;
824
825 if (w->shift % 2)
826 reg = ARIZONA_ADC_DIGITAL_VOLUME_1L + ((w->shift / 2) * 8);
827 else
828 reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8);
829
830 switch (event) {
Mark Brownddbce972013-02-15 17:27:22 +0000831 case SND_SOC_DAPM_PRE_PMU:
832 priv->in_pending++;
833 break;
Mark Brown43cd8bf2013-02-06 16:57:29 +0000834 case SND_SOC_DAPM_POST_PMU:
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100835 snd_soc_update_bits(codec, reg, ARIZONA_IN1L_MUTE, 0);
Mark Brownddbce972013-02-15 17:27:22 +0000836
837 /* If this is the last input pending then allow VU */
838 priv->in_pending--;
839 if (priv->in_pending == 0) {
840 msleep(1);
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100841 arizona_in_set_vu(codec, 1);
Mark Brownddbce972013-02-15 17:27:22 +0000842 }
Mark Brown43cd8bf2013-02-06 16:57:29 +0000843 break;
844 case SND_SOC_DAPM_PRE_PMD:
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100845 snd_soc_update_bits(codec, reg,
Mark Brownddbce972013-02-15 17:27:22 +0000846 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU,
847 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000848 break;
Mark Brownddbce972013-02-15 17:27:22 +0000849 case SND_SOC_DAPM_POST_PMD:
850 /* Disable volume updates if no inputs are enabled */
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100851 reg = snd_soc_read(codec, ARIZONA_INPUT_ENABLES);
Mark Brownddbce972013-02-15 17:27:22 +0000852 if (reg == 0)
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100853 arizona_in_set_vu(codec, 0);
Charles Keepaxbee261b2015-09-16 13:59:40 +0100854 break;
855 default:
856 break;
Mark Brown43cd8bf2013-02-06 16:57:29 +0000857 }
858
Mark Brown07ed8732012-06-18 21:08:44 +0100859 return 0;
860}
861EXPORT_SYMBOL_GPL(arizona_in_ev);
862
863int arizona_out_ev(struct snd_soc_dapm_widget *w,
864 struct snd_kcontrol *kcontrol,
865 int event)
866{
Mark Brown60d66c92015-01-27 23:50:47 +0000867 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
868 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Charles Keepax8c7788f2016-09-27 16:35:45 +0100869 struct arizona *arizona = priv->arizona;
Charles Keepax054e1b42015-01-20 16:31:50 +0000870
Mark Brown1a2c7d52013-03-24 22:50:23 +0000871 switch (event) {
Charles Keepaxe1ae5fb2015-01-20 16:31:51 +0000872 case SND_SOC_DAPM_PRE_PMU:
873 switch (w->shift) {
874 case ARIZONA_OUT1L_ENA_SHIFT:
875 case ARIZONA_OUT1R_ENA_SHIFT:
876 case ARIZONA_OUT2L_ENA_SHIFT:
877 case ARIZONA_OUT2R_ENA_SHIFT:
878 case ARIZONA_OUT3L_ENA_SHIFT:
879 case ARIZONA_OUT3R_ENA_SHIFT:
880 priv->out_up_pending++;
881 priv->out_up_delay += 17;
882 break;
Charles Keepax8c7788f2016-09-27 16:35:45 +0100883 case ARIZONA_OUT4L_ENA_SHIFT:
884 case ARIZONA_OUT4R_ENA_SHIFT:
885 priv->out_up_pending++;
886 switch (arizona->type) {
887 case WM5102:
888 case WM8997:
889 break;
890 default:
891 priv->out_up_delay += 10;
892 break;
893 }
894 break;
Charles Keepaxe1ae5fb2015-01-20 16:31:51 +0000895 default:
896 break;
897 }
898 break;
Mark Brown1a2c7d52013-03-24 22:50:23 +0000899 case SND_SOC_DAPM_POST_PMU:
900 switch (w->shift) {
901 case ARIZONA_OUT1L_ENA_SHIFT:
902 case ARIZONA_OUT1R_ENA_SHIFT:
903 case ARIZONA_OUT2L_ENA_SHIFT:
904 case ARIZONA_OUT2R_ENA_SHIFT:
905 case ARIZONA_OUT3L_ENA_SHIFT:
906 case ARIZONA_OUT3R_ENA_SHIFT:
Charles Keepax8c7788f2016-09-27 16:35:45 +0100907 case ARIZONA_OUT4L_ENA_SHIFT:
908 case ARIZONA_OUT4R_ENA_SHIFT:
Charles Keepaxe1ae5fb2015-01-20 16:31:51 +0000909 priv->out_up_pending--;
Charles Keepax8c7788f2016-09-27 16:35:45 +0100910 if (!priv->out_up_pending && priv->out_up_delay) {
Charles Keepaxd605bd02016-09-27 16:35:44 +0100911 dev_dbg(codec->dev, "Power up delay: %d\n",
912 priv->out_up_delay);
Charles Keepaxe1ae5fb2015-01-20 16:31:51 +0000913 msleep(priv->out_up_delay);
914 priv->out_up_delay = 0;
915 }
Mark Brown1a2c7d52013-03-24 22:50:23 +0000916 break;
917
918 default:
919 break;
920 }
921 break;
Charles Keepax054e1b42015-01-20 16:31:50 +0000922 case SND_SOC_DAPM_PRE_PMD:
923 switch (w->shift) {
924 case ARIZONA_OUT1L_ENA_SHIFT:
925 case ARIZONA_OUT1R_ENA_SHIFT:
926 case ARIZONA_OUT2L_ENA_SHIFT:
927 case ARIZONA_OUT2R_ENA_SHIFT:
928 case ARIZONA_OUT3L_ENA_SHIFT:
929 case ARIZONA_OUT3R_ENA_SHIFT:
930 priv->out_down_pending++;
931 priv->out_down_delay++;
932 break;
Charles Keepax8c7788f2016-09-27 16:35:45 +0100933 case ARIZONA_OUT4L_ENA_SHIFT:
934 case ARIZONA_OUT4R_ENA_SHIFT:
935 priv->out_down_pending++;
936 switch (arizona->type) {
937 case WM5102:
938 case WM8997:
939 break;
940 case WM8998:
941 case WM1814:
942 priv->out_down_delay += 5;
943 break;
944 default:
945 priv->out_down_delay++;
946 break;
947 }
Charles Keepax054e1b42015-01-20 16:31:50 +0000948 default:
949 break;
950 }
951 break;
952 case SND_SOC_DAPM_POST_PMD:
953 switch (w->shift) {
954 case ARIZONA_OUT1L_ENA_SHIFT:
955 case ARIZONA_OUT1R_ENA_SHIFT:
956 case ARIZONA_OUT2L_ENA_SHIFT:
957 case ARIZONA_OUT2R_ENA_SHIFT:
958 case ARIZONA_OUT3L_ENA_SHIFT:
959 case ARIZONA_OUT3R_ENA_SHIFT:
Charles Keepax8c7788f2016-09-27 16:35:45 +0100960 case ARIZONA_OUT4L_ENA_SHIFT:
961 case ARIZONA_OUT4R_ENA_SHIFT:
Charles Keepax054e1b42015-01-20 16:31:50 +0000962 priv->out_down_pending--;
Charles Keepax8c7788f2016-09-27 16:35:45 +0100963 if (!priv->out_down_pending && priv->out_down_delay) {
Charles Keepaxd605bd02016-09-27 16:35:44 +0100964 dev_dbg(codec->dev, "Power down delay: %d\n",
965 priv->out_down_delay);
Charles Keepax054e1b42015-01-20 16:31:50 +0000966 msleep(priv->out_down_delay);
967 priv->out_down_delay = 0;
968 }
969 break;
970 default:
971 break;
972 }
973 break;
Charles Keepaxbee261b2015-09-16 13:59:40 +0100974 default:
975 break;
Mark Brown1a2c7d52013-03-24 22:50:23 +0000976 }
977
Mark Brown07ed8732012-06-18 21:08:44 +0100978 return 0;
979}
980EXPORT_SYMBOL_GPL(arizona_out_ev);
981
Mark Brownf607e312013-02-22 18:36:53 +0000982int arizona_hp_ev(struct snd_soc_dapm_widget *w,
983 struct snd_kcontrol *kcontrol,
984 int event)
985{
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100986 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
987 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brown3c43c692013-12-12 00:49:22 +0000988 struct arizona *arizona = priv->arizona;
Mark Brownf607e312013-02-22 18:36:53 +0000989 unsigned int mask = 1 << w->shift;
990 unsigned int val;
991
992 switch (event) {
993 case SND_SOC_DAPM_POST_PMU:
994 val = mask;
995 break;
996 case SND_SOC_DAPM_PRE_PMD:
997 val = 0;
998 break;
Charles Keepaxe1ae5fb2015-01-20 16:31:51 +0000999 case SND_SOC_DAPM_PRE_PMU:
Charles Keepax054e1b42015-01-20 16:31:50 +00001000 case SND_SOC_DAPM_POST_PMD:
1001 return arizona_out_ev(w, kcontrol, event);
Mark Brownf607e312013-02-22 18:36:53 +00001002 default:
1003 return -EINVAL;
1004 }
1005
1006 /* Store the desired state for the HP outputs */
1007 priv->arizona->hp_ena &= ~mask;
1008 priv->arizona->hp_ena |= val;
1009
Charles Keepax112bdfa2015-02-16 15:41:02 +00001010 /* Force off if HPDET clamp is active */
1011 if (priv->arizona->hpdet_clamp)
Mark Brownf607e312013-02-22 18:36:53 +00001012 val = 0;
1013
Mark Brown3c43c692013-12-12 00:49:22 +00001014 regmap_update_bits_async(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1,
1015 mask, val);
Mark Brownf607e312013-02-22 18:36:53 +00001016
1017 return arizona_out_ev(w, kcontrol, event);
1018}
1019EXPORT_SYMBOL_GPL(arizona_hp_ev);
1020
Richard Fitzgerald346d9682015-06-02 11:53:33 +01001021static int arizona_dvfs_enable(struct snd_soc_codec *codec)
1022{
1023 const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1024 struct arizona *arizona = priv->arizona;
1025 int ret;
1026
1027 ret = regulator_set_voltage(arizona->dcvdd, 1800000, 1800000);
1028 if (ret) {
1029 dev_err(codec->dev, "Failed to boost DCVDD: %d\n", ret);
1030 return ret;
1031 }
1032
1033 ret = regmap_update_bits(arizona->regmap,
1034 ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
1035 ARIZONA_SUBSYS_MAX_FREQ,
1036 ARIZONA_SUBSYS_MAX_FREQ);
1037 if (ret) {
1038 dev_err(codec->dev, "Failed to enable subsys max: %d\n", ret);
1039 regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
1040 return ret;
1041 }
1042
1043 return 0;
1044}
1045
1046static int arizona_dvfs_disable(struct snd_soc_codec *codec)
1047{
1048 const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1049 struct arizona *arizona = priv->arizona;
1050 int ret;
1051
1052 ret = regmap_update_bits(arizona->regmap,
1053 ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
1054 ARIZONA_SUBSYS_MAX_FREQ, 0);
1055 if (ret) {
1056 dev_err(codec->dev, "Failed to disable subsys max: %d\n", ret);
1057 return ret;
1058 }
1059
1060 ret = regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
1061 if (ret) {
1062 dev_err(codec->dev, "Failed to unboost DCVDD: %d\n", ret);
1063 return ret;
1064 }
1065
1066 return 0;
1067}
1068
1069int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags)
1070{
1071 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1072 int ret = 0;
1073
1074 mutex_lock(&priv->dvfs_lock);
1075
1076 if (!priv->dvfs_cached && !priv->dvfs_reqs) {
1077 ret = arizona_dvfs_enable(codec);
1078 if (ret)
1079 goto err;
1080 }
1081
1082 priv->dvfs_reqs |= flags;
1083err:
1084 mutex_unlock(&priv->dvfs_lock);
1085 return ret;
1086}
1087EXPORT_SYMBOL_GPL(arizona_dvfs_up);
1088
1089int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags)
1090{
1091 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1092 unsigned int old_reqs;
1093 int ret = 0;
1094
1095 mutex_lock(&priv->dvfs_lock);
1096
1097 old_reqs = priv->dvfs_reqs;
1098 priv->dvfs_reqs &= ~flags;
1099
1100 if (!priv->dvfs_cached && old_reqs && !priv->dvfs_reqs)
1101 ret = arizona_dvfs_disable(codec);
1102
1103 mutex_unlock(&priv->dvfs_lock);
1104 return ret;
1105}
1106EXPORT_SYMBOL_GPL(arizona_dvfs_down);
1107
1108int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
1109 struct snd_kcontrol *kcontrol, int event)
1110{
1111 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
1112 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1113 int ret = 0;
1114
1115 mutex_lock(&priv->dvfs_lock);
1116
1117 switch (event) {
1118 case SND_SOC_DAPM_POST_PMU:
1119 if (priv->dvfs_reqs)
1120 ret = arizona_dvfs_enable(codec);
1121
1122 priv->dvfs_cached = false;
1123 break;
1124 case SND_SOC_DAPM_PRE_PMD:
1125 /* We must ensure DVFS is disabled before the codec goes into
1126 * suspend so that we are never in an illegal state of DVFS
1127 * enabled without enough DCVDD
1128 */
1129 priv->dvfs_cached = true;
1130
1131 if (priv->dvfs_reqs)
1132 ret = arizona_dvfs_disable(codec);
1133 break;
1134 default:
1135 break;
1136 }
1137
1138 mutex_unlock(&priv->dvfs_lock);
1139 return ret;
1140}
1141EXPORT_SYMBOL_GPL(arizona_dvfs_sysclk_ev);
1142
1143void arizona_init_dvfs(struct arizona_priv *priv)
1144{
1145 mutex_init(&priv->dvfs_lock);
1146}
1147EXPORT_SYMBOL_GPL(arizona_init_dvfs);
1148
Charles Keepaxd1901062015-11-19 16:11:10 +00001149int arizona_anc_ev(struct snd_soc_dapm_widget *w,
1150 struct snd_kcontrol *kcontrol,
1151 int event)
1152{
1153 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
Charles Keepaxd1901062015-11-19 16:11:10 +00001154 unsigned int val;
1155
1156 switch (event) {
1157 case SND_SOC_DAPM_POST_PMU:
1158 val = 1 << w->shift;
1159 break;
1160 case SND_SOC_DAPM_PRE_PMD:
1161 val = 1 << (w->shift + 1);
1162 break;
1163 default:
1164 return 0;
1165 }
1166
Richard Fitzgerald2ab8e742016-04-26 17:06:20 +01001167 snd_soc_write(codec, ARIZONA_CLOCK_CONTROL, val);
Charles Keepaxd1901062015-11-19 16:11:10 +00001168
1169 return 0;
1170}
1171EXPORT_SYMBOL_GPL(arizona_anc_ev);
1172
Richard Fitzgerald341604a2015-11-03 14:24:12 +00001173static unsigned int arizona_opclk_ref_48k_rates[] = {
Mark Browncbd840d2012-08-08 17:52:44 +01001174 6144000,
1175 12288000,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +00001176 24576000,
Mark Browncbd840d2012-08-08 17:52:44 +01001177 49152000,
1178};
1179
Richard Fitzgerald341604a2015-11-03 14:24:12 +00001180static unsigned int arizona_opclk_ref_44k1_rates[] = {
Mark Browncbd840d2012-08-08 17:52:44 +01001181 5644800,
1182 11289600,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +00001183 22579200,
Mark Browncbd840d2012-08-08 17:52:44 +01001184 45158400,
1185};
1186
1187static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
1188 unsigned int freq)
1189{
1190 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1191 unsigned int reg;
1192 unsigned int *rates;
1193 int ref, div, refclk;
1194
1195 switch (clk) {
1196 case ARIZONA_CLK_OPCLK:
1197 reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
1198 refclk = priv->sysclk;
1199 break;
1200 case ARIZONA_CLK_ASYNC_OPCLK:
1201 reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
1202 refclk = priv->asyncclk;
1203 break;
1204 default:
1205 return -EINVAL;
1206 }
1207
1208 if (refclk % 8000)
Richard Fitzgerald341604a2015-11-03 14:24:12 +00001209 rates = arizona_opclk_ref_44k1_rates;
Mark Browncbd840d2012-08-08 17:52:44 +01001210 else
Richard Fitzgerald341604a2015-11-03 14:24:12 +00001211 rates = arizona_opclk_ref_48k_rates;
Mark Browncbd840d2012-08-08 17:52:44 +01001212
Richard Fitzgerald341604a2015-11-03 14:24:12 +00001213 for (ref = 0; ref < ARRAY_SIZE(arizona_opclk_ref_48k_rates) &&
Mark Browncbd840d2012-08-08 17:52:44 +01001214 rates[ref] <= refclk; ref++) {
1215 div = 1;
1216 while (rates[ref] / div >= freq && div < 32) {
1217 if (rates[ref] / div == freq) {
1218 dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
1219 freq);
1220 snd_soc_update_bits(codec, reg,
1221 ARIZONA_OPCLK_DIV_MASK |
1222 ARIZONA_OPCLK_SEL_MASK,
1223 (div <<
1224 ARIZONA_OPCLK_DIV_SHIFT) |
1225 ref);
1226 return 0;
1227 }
1228 div++;
1229 }
1230 }
1231
1232 dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
1233 return -EINVAL;
1234}
1235
Mark Brown07ed8732012-06-18 21:08:44 +01001236int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
1237 int source, unsigned int freq, int dir)
1238{
1239 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1240 struct arizona *arizona = priv->arizona;
1241 char *name;
1242 unsigned int reg;
1243 unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
1244 unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
Charles Keepax1f0e1ea2015-12-03 18:15:07 +00001245 int *clk;
Mark Brown07ed8732012-06-18 21:08:44 +01001246
1247 switch (clk_id) {
1248 case ARIZONA_CLK_SYSCLK:
1249 name = "SYSCLK";
1250 reg = ARIZONA_SYSTEM_CLOCK_1;
1251 clk = &priv->sysclk;
1252 mask |= ARIZONA_SYSCLK_FRAC;
1253 break;
1254 case ARIZONA_CLK_ASYNCCLK:
1255 name = "ASYNCCLK";
1256 reg = ARIZONA_ASYNC_CLOCK_1;
1257 clk = &priv->asyncclk;
1258 break;
Mark Browncbd840d2012-08-08 17:52:44 +01001259 case ARIZONA_CLK_OPCLK:
1260 case ARIZONA_CLK_ASYNC_OPCLK:
1261 return arizona_set_opclk(codec, clk_id, freq);
Mark Brown07ed8732012-06-18 21:08:44 +01001262 default:
1263 return -EINVAL;
1264 }
1265
1266 switch (freq) {
1267 case 5644800:
1268 case 6144000:
1269 break;
1270 case 11289600:
1271 case 12288000:
Mark Brown3f341f72013-03-08 15:22:29 +08001272 val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +01001273 break;
1274 case 22579200:
1275 case 24576000:
Mark Brown3f341f72013-03-08 15:22:29 +08001276 val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +01001277 break;
1278 case 45158400:
1279 case 49152000:
Mark Brown3f341f72013-03-08 15:22:29 +08001280 val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +01001281 break;
Mark Brown38113362012-11-26 16:01:37 +00001282 case 67737600:
1283 case 73728000:
Mark Brown3f341f72013-03-08 15:22:29 +08001284 val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +00001285 break;
1286 case 90316800:
1287 case 98304000:
Mark Brown3f341f72013-03-08 15:22:29 +08001288 val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +00001289 break;
1290 case 135475200:
1291 case 147456000:
Mark Brown3f341f72013-03-08 15:22:29 +08001292 val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +00001293 break;
Mark Brownf2c26d42013-01-21 16:09:36 +09001294 case 0:
1295 dev_dbg(arizona->dev, "%s cleared\n", name);
1296 *clk = freq;
1297 return 0;
Mark Brown07ed8732012-06-18 21:08:44 +01001298 default:
1299 return -EINVAL;
1300 }
1301
1302 *clk = freq;
1303
1304 if (freq % 6144000)
1305 val |= ARIZONA_SYSCLK_FRAC;
1306
1307 dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
1308
1309 return regmap_update_bits(arizona->regmap, reg, mask, val);
1310}
1311EXPORT_SYMBOL_GPL(arizona_set_sysclk);
1312
1313static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
1314{
1315 struct snd_soc_codec *codec = dai->codec;
Mark Brown3c43c692013-12-12 00:49:22 +00001316 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1317 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +01001318 int lrclk, bclk, mode, base;
1319
1320 base = dai->driver->base;
1321
1322 lrclk = 0;
1323 bclk = 0;
1324
1325 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
1326 case SND_SOC_DAIFMT_DSP_A:
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001327 mode = ARIZONA_FMT_DSP_MODE_A;
1328 break;
1329 case SND_SOC_DAIFMT_DSP_B:
1330 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
1331 != SND_SOC_DAIFMT_CBM_CFM) {
1332 arizona_aif_err(dai, "DSP_B not valid in slave mode\n");
1333 return -EINVAL;
1334 }
1335 mode = ARIZONA_FMT_DSP_MODE_B;
Mark Brown07ed8732012-06-18 21:08:44 +01001336 break;
Mark Brown07ed8732012-06-18 21:08:44 +01001337 case SND_SOC_DAIFMT_I2S:
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001338 mode = ARIZONA_FMT_I2S_MODE;
1339 break;
1340 case SND_SOC_DAIFMT_LEFT_J:
1341 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
1342 != SND_SOC_DAIFMT_CBM_CFM) {
1343 arizona_aif_err(dai, "LEFT_J not valid in slave mode\n");
1344 return -EINVAL;
1345 }
1346 mode = ARIZONA_FMT_LEFT_JUSTIFIED_MODE;
Mark Brown07ed8732012-06-18 21:08:44 +01001347 break;
Mark Brown07ed8732012-06-18 21:08:44 +01001348 default:
1349 arizona_aif_err(dai, "Unsupported DAI format %d\n",
1350 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
1351 return -EINVAL;
1352 }
1353
1354 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
1355 case SND_SOC_DAIFMT_CBS_CFS:
1356 break;
1357 case SND_SOC_DAIFMT_CBS_CFM:
1358 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
1359 break;
1360 case SND_SOC_DAIFMT_CBM_CFS:
1361 bclk |= ARIZONA_AIF1_BCLK_MSTR;
1362 break;
1363 case SND_SOC_DAIFMT_CBM_CFM:
1364 bclk |= ARIZONA_AIF1_BCLK_MSTR;
1365 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
1366 break;
1367 default:
1368 arizona_aif_err(dai, "Unsupported master mode %d\n",
1369 fmt & SND_SOC_DAIFMT_MASTER_MASK);
1370 return -EINVAL;
1371 }
1372
1373 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1374 case SND_SOC_DAIFMT_NB_NF:
1375 break;
1376 case SND_SOC_DAIFMT_IB_IF:
1377 bclk |= ARIZONA_AIF1_BCLK_INV;
1378 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
1379 break;
1380 case SND_SOC_DAIFMT_IB_NF:
1381 bclk |= ARIZONA_AIF1_BCLK_INV;
1382 break;
1383 case SND_SOC_DAIFMT_NB_IF:
1384 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
1385 break;
1386 default:
1387 return -EINVAL;
1388 }
1389
Mark Brown3c43c692013-12-12 00:49:22 +00001390 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_BCLK_CTRL,
1391 ARIZONA_AIF1_BCLK_INV |
1392 ARIZONA_AIF1_BCLK_MSTR,
1393 bclk);
1394 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_TX_PIN_CTRL,
1395 ARIZONA_AIF1TX_LRCLK_INV |
1396 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
1397 regmap_update_bits_async(arizona->regmap,
1398 base + ARIZONA_AIF_RX_PIN_CTRL,
1399 ARIZONA_AIF1RX_LRCLK_INV |
1400 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
1401 regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FORMAT,
1402 ARIZONA_AIF1_FMT_MASK, mode);
Mark Brown07ed8732012-06-18 21:08:44 +01001403
1404 return 0;
1405}
1406
Mark Brown949e6bc2012-07-04 18:58:04 +01001407static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001408 -1,
1409 48000,
1410 64000,
1411 96000,
1412 128000,
1413 192000,
1414 256000,
1415 384000,
1416 512000,
1417 768000,
1418 1024000,
1419 1536000,
1420 2048000,
1421 3072000,
1422 4096000,
1423 6144000,
1424 8192000,
1425 12288000,
1426 24576000,
1427};
1428
Mark Brown949e6bc2012-07-04 18:58:04 +01001429static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001430 -1,
1431 44100,
1432 58800,
1433 88200,
1434 117600,
1435 177640,
1436 235200,
1437 352800,
1438 470400,
1439 705600,
1440 940800,
1441 1411200,
1442 1881600,
Heather Lomond4758be32012-09-05 05:02:10 -04001443 2822400,
Mark Brown07ed8732012-06-18 21:08:44 +01001444 3763200,
1445 5644800,
1446 7526400,
1447 11289600,
1448 22579200,
1449};
1450
Charles Keepaxd81221f2016-02-04 16:29:01 +00001451static const unsigned int arizona_sr_vals[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001452 0,
1453 12000,
1454 24000,
1455 48000,
1456 96000,
1457 192000,
1458 384000,
1459 768000,
1460 0,
1461 11025,
1462 22050,
1463 44100,
1464 88200,
1465 176400,
1466 352800,
1467 705600,
1468 4000,
1469 8000,
1470 16000,
1471 32000,
1472 64000,
1473 128000,
1474 256000,
1475 512000,
1476};
1477
Charles Keepaxd81221f2016-02-04 16:29:01 +00001478#define ARIZONA_48K_RATE_MASK 0x0F003E
1479#define ARIZONA_44K1_RATE_MASK 0x003E00
1480#define ARIZONA_RATE_MASK (ARIZONA_48K_RATE_MASK | ARIZONA_44K1_RATE_MASK)
1481
1482static const struct snd_pcm_hw_constraint_list arizona_constraint = {
1483 .count = ARRAY_SIZE(arizona_sr_vals),
1484 .list = arizona_sr_vals,
1485};
1486
Mark Brown5b2eec32012-07-04 17:32:05 +01001487static int arizona_startup(struct snd_pcm_substream *substream,
1488 struct snd_soc_dai *dai)
1489{
1490 struct snd_soc_codec *codec = dai->codec;
1491 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1492 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown5b2eec32012-07-04 17:32:05 +01001493 unsigned int base_rate;
1494
Charles Keepax26eb5a92015-12-29 09:49:19 +00001495 if (!substream->runtime)
1496 return 0;
1497
Mark Brown5b2eec32012-07-04 17:32:05 +01001498 switch (dai_priv->clk) {
1499 case ARIZONA_CLK_SYSCLK:
1500 base_rate = priv->sysclk;
1501 break;
1502 case ARIZONA_CLK_ASYNCCLK:
1503 base_rate = priv->asyncclk;
1504 break;
1505 default:
1506 return 0;
1507 }
1508
Mark Brownf2c26d42013-01-21 16:09:36 +09001509 if (base_rate == 0)
Charles Keepaxd81221f2016-02-04 16:29:01 +00001510 dai_priv->constraint.mask = ARIZONA_RATE_MASK;
1511 else if (base_rate % 8000)
1512 dai_priv->constraint.mask = ARIZONA_44K1_RATE_MASK;
Mark Brown5b2eec32012-07-04 17:32:05 +01001513 else
Charles Keepaxd81221f2016-02-04 16:29:01 +00001514 dai_priv->constraint.mask = ARIZONA_48K_RATE_MASK;
Mark Brown5b2eec32012-07-04 17:32:05 +01001515
1516 return snd_pcm_hw_constraint_list(substream->runtime, 0,
1517 SNDRV_PCM_HW_PARAM_RATE,
Charles Keepaxd81221f2016-02-04 16:29:01 +00001518 &dai_priv->constraint);
Mark Brown5b2eec32012-07-04 17:32:05 +01001519}
1520
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001521static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec,
1522 unsigned int rate)
1523{
1524 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1525 struct arizona *arizona = priv->arizona;
Nariman Poushin8019ff62015-07-16 16:36:21 +01001526 struct reg_sequence dac_comp[] = {
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001527 { 0x80, 0x3 },
1528 { ARIZONA_DAC_COMP_1, 0 },
1529 { ARIZONA_DAC_COMP_2, 0 },
1530 { 0x80, 0x0 },
1531 };
1532
Lars-Peter Clausend74bcaa2014-11-09 17:00:59 +01001533 mutex_lock(&arizona->dac_comp_lock);
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001534
1535 dac_comp[1].def = arizona->dac_comp_coeff;
1536 if (rate >= 176400)
1537 dac_comp[2].def = arizona->dac_comp_enabled;
1538
Lars-Peter Clausend74bcaa2014-11-09 17:00:59 +01001539 mutex_unlock(&arizona->dac_comp_lock);
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001540
1541 regmap_multi_reg_write(arizona->regmap,
1542 dac_comp,
1543 ARRAY_SIZE(dac_comp));
1544}
1545
Mark Brownb272efc2012-10-10 15:10:08 +09001546static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
1547 struct snd_pcm_hw_params *params,
1548 struct snd_soc_dai *dai)
Mark Brown07ed8732012-06-18 21:08:44 +01001549{
1550 struct snd_soc_codec *codec = dai->codec;
Mark Brownc013b272012-07-04 20:05:57 +01001551 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1552 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown07ed8732012-06-18 21:08:44 +01001553 int base = dai->driver->base;
Richard Fitzgerald2c118b42015-06-02 11:53:35 +01001554 int i, sr_val, ret;
Mark Brownb272efc2012-10-10 15:10:08 +09001555
1556 /*
1557 * We will need to be more flexible than this in future,
1558 * currently we use a single sample rate for SYSCLK.
1559 */
1560 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
1561 if (arizona_sr_vals[i] == params_rate(params))
1562 break;
1563 if (i == ARRAY_SIZE(arizona_sr_vals)) {
1564 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1565 params_rate(params));
1566 return -EINVAL;
1567 }
1568 sr_val = i;
1569
Richard Fitzgerald2c118b42015-06-02 11:53:35 +01001570 switch (priv->arizona->type) {
1571 case WM5102:
1572 case WM8997:
1573 if (arizona_sr_vals[sr_val] >= 88200)
1574 ret = arizona_dvfs_up(codec, ARIZONA_DVFS_SR1_RQ);
1575 else
1576 ret = arizona_dvfs_down(codec, ARIZONA_DVFS_SR1_RQ);
1577
1578 if (ret) {
1579 arizona_aif_err(dai, "Failed to change DVFS %d\n", ret);
1580 return ret;
1581 }
1582 break;
1583 default:
1584 break;
1585 }
1586
Mark Brownb272efc2012-10-10 15:10:08 +09001587 switch (dai_priv->clk) {
1588 case ARIZONA_CLK_SYSCLK:
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001589 switch (priv->arizona->type) {
1590 case WM5102:
1591 arizona_wm5102_set_dac_comp(codec,
1592 params_rate(params));
1593 break;
1594 default:
1595 break;
1596 }
1597
Mark Brownb272efc2012-10-10 15:10:08 +09001598 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
1599 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
1600 if (base)
1601 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1602 ARIZONA_AIF1_RATE_MASK, 0);
1603 break;
1604 case ARIZONA_CLK_ASYNCCLK:
1605 snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
Charles Keepaxc24084d2014-09-01 15:48:52 +01001606 ARIZONA_ASYNC_SAMPLE_RATE_1_MASK, sr_val);
Mark Brownb272efc2012-10-10 15:10:08 +09001607 if (base)
1608 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1609 ARIZONA_AIF1_RATE_MASK,
1610 8 << ARIZONA_AIF1_RATE_SHIFT);
1611 break;
1612 default:
1613 arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
1614 return -EINVAL;
1615 }
1616
1617 return 0;
1618}
1619
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001620static bool arizona_aif_cfg_changed(struct snd_soc_codec *codec,
1621 int base, int bclk, int lrclk, int frame)
1622{
1623 int val;
1624
1625 val = snd_soc_read(codec, base + ARIZONA_AIF_BCLK_CTRL);
1626 if (bclk != (val & ARIZONA_AIF1_BCLK_FREQ_MASK))
1627 return true;
1628
1629 val = snd_soc_read(codec, base + ARIZONA_AIF_TX_BCLK_RATE);
1630 if (lrclk != (val & ARIZONA_AIF1TX_BCPF_MASK))
1631 return true;
1632
1633 val = snd_soc_read(codec, base + ARIZONA_AIF_FRAME_CTRL_1);
1634 if (frame != (val & (ARIZONA_AIF1TX_WL_MASK |
1635 ARIZONA_AIF1TX_SLOT_LEN_MASK)))
1636 return true;
1637
1638 return false;
1639}
1640
Mark Brown07ed8732012-06-18 21:08:44 +01001641static int arizona_hw_params(struct snd_pcm_substream *substream,
1642 struct snd_pcm_hw_params *params,
1643 struct snd_soc_dai *dai)
1644{
1645 struct snd_soc_codec *codec = dai->codec;
1646 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brownc94aa302013-01-17 16:35:14 +09001647 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +01001648 int base = dai->driver->base;
1649 const int *rates;
Mark Brown76bf9692013-03-05 14:17:47 +08001650 int i, ret, val;
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001651 int channels = params_channels(params);
Mark Brownc94aa302013-01-17 16:35:14 +09001652 int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001653 int tdm_width = arizona->tdm_width[dai->id - 1];
1654 int tdm_slots = arizona->tdm_slots[dai->id - 1];
Mark Brownc94aa302013-01-17 16:35:14 +09001655 int bclk, lrclk, wl, frame, bclk_target;
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001656 bool reconfig;
1657 unsigned int aif_tx_state, aif_rx_state;
Mark Brown07ed8732012-06-18 21:08:44 +01001658
Nikesh Oswale73694d2015-12-23 14:18:05 +00001659 if (params_rate(params) % 4000)
Mark Brown949e6bc2012-07-04 18:58:04 +01001660 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001661 else
Mark Brown949e6bc2012-07-04 18:58:04 +01001662 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001663
Charles Keepax5ed68f02015-07-09 11:28:46 +01001664 wl = params_width(params);
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001665
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001666 if (tdm_slots) {
1667 arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n",
1668 tdm_slots, tdm_width);
1669 bclk_target = tdm_slots * tdm_width * params_rate(params);
1670 channels = tdm_slots;
1671 } else {
1672 bclk_target = snd_soc_params_to_bclk(params);
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001673 tdm_width = wl;
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001674 }
1675
1676 if (chan_limit && chan_limit < channels) {
Mark Brownc94aa302013-01-17 16:35:14 +09001677 arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001678 bclk_target /= channels;
Mark Brownc94aa302013-01-17 16:35:14 +09001679 bclk_target *= chan_limit;
1680 }
1681
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001682 /* Force multiple of 2 channels for I2S mode */
Mark Brown76bf9692013-03-05 14:17:47 +08001683 val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001684 val &= ARIZONA_AIF1_FMT_MASK;
1685 if ((channels & 1) && (val == ARIZONA_FMT_I2S_MODE)) {
Mark Brown76bf9692013-03-05 14:17:47 +08001686 arizona_aif_dbg(dai, "Forcing stereo mode\n");
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001687 bclk_target /= channels;
1688 bclk_target *= channels + 1;
Mark Brown76bf9692013-03-05 14:17:47 +08001689 }
1690
Mark Brown949e6bc2012-07-04 18:58:04 +01001691 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brownc94aa302013-01-17 16:35:14 +09001692 if (rates[i] >= bclk_target &&
Mark Brown50017652012-07-04 19:07:09 +01001693 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +01001694 bclk = i;
1695 break;
1696 }
1697 }
Mark Brown949e6bc2012-07-04 18:58:04 +01001698 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001699 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1700 params_rate(params));
1701 return -EINVAL;
1702 }
1703
Mark Brownb59e0f82013-01-17 14:15:59 +09001704 lrclk = rates[bclk] / params_rate(params);
Mark Brown07ed8732012-06-18 21:08:44 +01001705
1706 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
1707 rates[bclk], rates[bclk] / lrclk);
1708
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001709 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | tdm_width;
Mark Brown07ed8732012-06-18 21:08:44 +01001710
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001711 reconfig = arizona_aif_cfg_changed(codec, base, bclk, lrclk, frame);
1712
1713 if (reconfig) {
1714 /* Save AIF TX/RX state */
1715 aif_tx_state = snd_soc_read(codec,
1716 base + ARIZONA_AIF_TX_ENABLES);
1717 aif_rx_state = snd_soc_read(codec,
1718 base + ARIZONA_AIF_RX_ENABLES);
1719 /* Disable AIF TX/RX before reconfiguring it */
1720 regmap_update_bits_async(arizona->regmap,
1721 base + ARIZONA_AIF_TX_ENABLES, 0xff, 0x0);
1722 regmap_update_bits(arizona->regmap,
1723 base + ARIZONA_AIF_RX_ENABLES, 0xff, 0x0);
1724 }
1725
Mark Brownb272efc2012-10-10 15:10:08 +09001726 ret = arizona_hw_params_rate(substream, params, dai);
1727 if (ret != 0)
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001728 goto restore_aif;
Mark Brownc013b272012-07-04 20:05:57 +01001729
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001730 if (reconfig) {
1731 regmap_update_bits_async(arizona->regmap,
1732 base + ARIZONA_AIF_BCLK_CTRL,
1733 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
1734 regmap_update_bits_async(arizona->regmap,
1735 base + ARIZONA_AIF_TX_BCLK_RATE,
1736 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
1737 regmap_update_bits_async(arizona->regmap,
1738 base + ARIZONA_AIF_RX_BCLK_RATE,
1739 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
1740 regmap_update_bits_async(arizona->regmap,
1741 base + ARIZONA_AIF_FRAME_CTRL_1,
1742 ARIZONA_AIF1TX_WL_MASK |
1743 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
1744 regmap_update_bits(arizona->regmap,
1745 base + ARIZONA_AIF_FRAME_CTRL_2,
1746 ARIZONA_AIF1RX_WL_MASK |
1747 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
1748 }
Mark Brown07ed8732012-06-18 21:08:44 +01001749
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001750restore_aif:
1751 if (reconfig) {
1752 /* Restore AIF TX/RX state */
1753 regmap_update_bits_async(arizona->regmap,
1754 base + ARIZONA_AIF_TX_ENABLES,
1755 0xff, aif_tx_state);
1756 regmap_update_bits(arizona->regmap,
1757 base + ARIZONA_AIF_RX_ENABLES,
1758 0xff, aif_rx_state);
1759 }
1760 return ret;
Mark Brown07ed8732012-06-18 21:08:44 +01001761}
1762
Mark Brown410837a2012-07-05 17:26:59 +01001763static const char *arizona_dai_clk_str(int clk_id)
1764{
1765 switch (clk_id) {
1766 case ARIZONA_CLK_SYSCLK:
1767 return "SYSCLK";
1768 case ARIZONA_CLK_ASYNCCLK:
1769 return "ASYNCCLK";
1770 default:
1771 return "Unknown clock";
1772 }
1773}
1774
Mark Brown5b2eec32012-07-04 17:32:05 +01001775static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
1776 int clk_id, unsigned int freq, int dir)
1777{
1778 struct snd_soc_codec *codec = dai->codec;
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +02001779 struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
Mark Brown5b2eec32012-07-04 17:32:05 +01001780 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1781 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown410837a2012-07-05 17:26:59 +01001782 struct snd_soc_dapm_route routes[2];
Mark Brown5b2eec32012-07-04 17:32:05 +01001783
1784 switch (clk_id) {
1785 case ARIZONA_CLK_SYSCLK:
1786 case ARIZONA_CLK_ASYNCCLK:
1787 break;
1788 default:
1789 return -EINVAL;
1790 }
1791
Mark Brown410837a2012-07-05 17:26:59 +01001792 if (clk_id == dai_priv->clk)
1793 return 0;
1794
1795 if (dai->active) {
Mark Brown5b2eec32012-07-04 17:32:05 +01001796 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
1797 dai->id);
1798 return -EBUSY;
1799 }
1800
Mark Brownc8d35a62012-12-07 12:49:40 +09001801 dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1,
1802 arizona_dai_clk_str(clk_id));
1803
Mark Brown410837a2012-07-05 17:26:59 +01001804 memset(&routes, 0, sizeof(routes));
1805 routes[0].sink = dai->driver->capture.stream_name;
1806 routes[1].sink = dai->driver->playback.stream_name;
Mark Brown5b2eec32012-07-04 17:32:05 +01001807
Mark Brown410837a2012-07-05 17:26:59 +01001808 routes[0].source = arizona_dai_clk_str(dai_priv->clk);
1809 routes[1].source = arizona_dai_clk_str(dai_priv->clk);
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +02001810 snd_soc_dapm_del_routes(dapm, routes, ARRAY_SIZE(routes));
Mark Brown410837a2012-07-05 17:26:59 +01001811
1812 routes[0].source = arizona_dai_clk_str(clk_id);
1813 routes[1].source = arizona_dai_clk_str(clk_id);
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +02001814 snd_soc_dapm_add_routes(dapm, routes, ARRAY_SIZE(routes));
Mark Brown410837a2012-07-05 17:26:59 +01001815
Mark Brown0c778e82012-12-06 18:22:25 +09001816 dai_priv->clk = clk_id;
1817
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +02001818 return snd_soc_dapm_sync(dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +01001819}
1820
Mark Brown01df2592012-12-12 16:22:08 +09001821static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
1822{
1823 struct snd_soc_codec *codec = dai->codec;
1824 int base = dai->driver->base;
1825 unsigned int reg;
1826
1827 if (tristate)
1828 reg = ARIZONA_AIF1_TRI;
1829 else
1830 reg = 0;
1831
1832 return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1833 ARIZONA_AIF1_TRI, reg);
1834}
1835
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001836static void arizona_set_channels_to_mask(struct snd_soc_dai *dai,
1837 unsigned int base,
1838 int channels, unsigned int mask)
1839{
1840 struct snd_soc_codec *codec = dai->codec;
1841 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1842 struct arizona *arizona = priv->arizona;
1843 int slot, i;
1844
1845 for (i = 0; i < channels; ++i) {
1846 slot = ffs(mask) - 1;
1847 if (slot < 0)
1848 return;
1849
1850 regmap_write(arizona->regmap, base + i, slot);
1851
1852 mask &= ~(1 << slot);
1853 }
1854
1855 if (mask)
1856 arizona_aif_warn(dai, "Too many channels in TDM mask\n");
1857}
1858
1859static int arizona_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
1860 unsigned int rx_mask, int slots, int slot_width)
1861{
1862 struct snd_soc_codec *codec = dai->codec;
1863 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1864 struct arizona *arizona = priv->arizona;
1865 int base = dai->driver->base;
1866 int rx_max_chan = dai->driver->playback.channels_max;
1867 int tx_max_chan = dai->driver->capture.channels_max;
1868
1869 /* Only support TDM for the physical AIFs */
1870 if (dai->id > ARIZONA_MAX_AIF)
1871 return -ENOTSUPP;
1872
1873 if (slots == 0) {
1874 tx_mask = (1 << tx_max_chan) - 1;
1875 rx_mask = (1 << rx_max_chan) - 1;
1876 }
1877
1878 arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_3,
1879 tx_max_chan, tx_mask);
1880 arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_11,
1881 rx_max_chan, rx_mask);
1882
1883 arizona->tdm_width[dai->id - 1] = slot_width;
1884 arizona->tdm_slots[dai->id - 1] = slots;
1885
1886 return 0;
1887}
1888
Mark Brown07ed8732012-06-18 21:08:44 +01001889const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +01001890 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +01001891 .set_fmt = arizona_set_fmt,
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001892 .set_tdm_slot = arizona_set_tdm_slot,
Mark Brown07ed8732012-06-18 21:08:44 +01001893 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +01001894 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown01df2592012-12-12 16:22:08 +09001895 .set_tristate = arizona_set_tristate,
Mark Brown07ed8732012-06-18 21:08:44 +01001896};
Mark Browna8379872012-07-09 12:16:41 +01001897EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +01001898
Mark Brownbd1dd882013-05-17 13:29:03 +01001899const struct snd_soc_dai_ops arizona_simple_dai_ops = {
1900 .startup = arizona_startup,
1901 .hw_params = arizona_hw_params_rate,
1902 .set_sysclk = arizona_dai_set_sysclk,
1903};
1904EXPORT_SYMBOL_GPL(arizona_simple_dai_ops);
1905
Mark Brown5b2eec32012-07-04 17:32:05 +01001906int arizona_init_dai(struct arizona_priv *priv, int id)
1907{
1908 struct arizona_dai_priv *dai_priv = &priv->dai[id];
1909
1910 dai_priv->clk = ARIZONA_CLK_SYSCLK;
Charles Keepaxd81221f2016-02-04 16:29:01 +00001911 dai_priv->constraint = arizona_constraint;
Mark Brown5b2eec32012-07-04 17:32:05 +01001912
1913 return 0;
1914}
1915EXPORT_SYMBOL_GPL(arizona_init_dai);
1916
Mark Brown07ed8732012-06-18 21:08:44 +01001917static struct {
1918 unsigned int min;
1919 unsigned int max;
1920 u16 fratio;
1921 int ratio;
1922} fll_fratios[] = {
1923 { 0, 64000, 4, 16 },
1924 { 64000, 128000, 3, 8 },
1925 { 128000, 256000, 2, 4 },
1926 { 256000, 1000000, 1, 2 },
1927 { 1000000, 13500000, 0, 1 },
1928};
1929
Richard Fitzgerald01582a82016-02-10 11:56:13 +00001930static const unsigned int pseudo_fref_max[ARIZONA_FLL_MAX_FRATIO] = {
1931 13500000,
1932 6144000,
1933 6144000,
1934 3072000,
1935 3072000,
1936 2822400,
1937 2822400,
1938 1536000,
1939 1536000,
1940 1536000,
1941 1536000,
1942 1536000,
1943 1536000,
1944 1536000,
1945 1536000,
1946 768000,
1947};
1948
Mark Brown8f113d72013-03-05 12:08:57 +08001949static struct {
1950 unsigned int min;
1951 unsigned int max;
1952 u16 gain;
1953} fll_gains[] = {
1954 { 0, 256000, 0 },
1955 { 256000, 1000000, 2 },
1956 { 1000000, 13500000, 4 },
1957};
1958
Mark Brown07ed8732012-06-18 21:08:44 +01001959struct arizona_fll_cfg {
1960 int n;
Charles Keepaxe87d9ae2016-09-02 16:52:43 +01001961 unsigned int theta;
1962 unsigned int lambda;
Mark Brown07ed8732012-06-18 21:08:44 +01001963 int refdiv;
1964 int outdiv;
1965 int fratio;
Mark Brown8f113d72013-03-05 12:08:57 +08001966 int gain;
Mark Brown07ed8732012-06-18 21:08:44 +01001967};
1968
Charles Keepax23f785a82014-03-07 16:34:20 +00001969static int arizona_validate_fll(struct arizona_fll *fll,
1970 unsigned int Fref,
1971 unsigned int Fout)
1972{
1973 unsigned int Fvco_min;
1974
Charles Keepaxc8badda2014-07-09 17:41:49 +01001975 if (fll->fout && Fout != fll->fout) {
1976 arizona_fll_err(fll,
1977 "Can't change output on active FLL\n");
1978 return -EINVAL;
1979 }
1980
Charles Keepax23f785a82014-03-07 16:34:20 +00001981 if (Fref / ARIZONA_FLL_MAX_REFDIV > ARIZONA_FLL_MAX_FREF) {
1982 arizona_fll_err(fll,
1983 "Can't scale %dMHz in to <=13.5MHz\n",
1984 Fref);
1985 return -EINVAL;
1986 }
1987
1988 Fvco_min = ARIZONA_FLL_MIN_FVCO * fll->vco_mult;
1989 if (Fout * ARIZONA_FLL_MAX_OUTDIV < Fvco_min) {
1990 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
1991 Fout);
1992 return -EINVAL;
1993 }
1994
1995 return 0;
1996}
1997
Charles Keepaxd0800342014-03-07 16:34:25 +00001998static int arizona_find_fratio(unsigned int Fref, int *fratio)
1999{
2000 int i;
2001
2002 /* Find an appropriate FLL_FRATIO */
2003 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
2004 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
2005 if (fratio)
2006 *fratio = fll_fratios[i].fratio;
2007 return fll_fratios[i].ratio;
2008 }
2009 }
2010
2011 return -EINVAL;
2012}
2013
2014static int arizona_calc_fratio(struct arizona_fll *fll,
2015 struct arizona_fll_cfg *cfg,
2016 unsigned int target,
2017 unsigned int Fref, bool sync)
2018{
2019 int init_ratio, ratio;
2020 int refdiv, div;
2021
2022 /* Fref must be <=13.5MHz, find initial refdiv */
2023 div = 1;
2024 cfg->refdiv = 0;
2025 while (Fref > ARIZONA_FLL_MAX_FREF) {
2026 div *= 2;
2027 Fref /= 2;
2028 cfg->refdiv++;
2029
2030 if (div > ARIZONA_FLL_MAX_REFDIV)
2031 return -EINVAL;
2032 }
2033
2034 /* Find an appropriate FLL_FRATIO */
2035 init_ratio = arizona_find_fratio(Fref, &cfg->fratio);
2036 if (init_ratio < 0) {
2037 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
2038 Fref);
2039 return init_ratio;
2040 }
2041
2042 switch (fll->arizona->type) {
Richard Fitzgerald3451eb42015-12-16 17:06:24 +00002043 case WM5102:
2044 case WM8997:
2045 return init_ratio;
Charles Keepaxd0800342014-03-07 16:34:25 +00002046 case WM5110:
Richard Fitzgerald575ef7f2015-01-17 15:21:27 +00002047 case WM8280:
Charles Keepaxd0800342014-03-07 16:34:25 +00002048 if (fll->arizona->rev < 3 || sync)
2049 return init_ratio;
2050 break;
Richard Fitzgerald3451eb42015-12-16 17:06:24 +00002051 default:
Richard Fitzgerald6ebbce02015-09-28 14:01:09 +01002052 if (sync)
2053 return init_ratio;
2054 break;
Charles Keepaxd0800342014-03-07 16:34:25 +00002055 }
2056
2057 cfg->fratio = init_ratio - 1;
2058
2059 /* Adjust FRATIO/refdiv to avoid integer mode if possible */
2060 refdiv = cfg->refdiv;
2061
Richard Fitzgerald01582a82016-02-10 11:56:13 +00002062 arizona_fll_dbg(fll, "pseudo: initial ratio=%u fref=%u refdiv=%u\n",
2063 init_ratio, Fref, refdiv);
2064
Charles Keepaxd0800342014-03-07 16:34:25 +00002065 while (div <= ARIZONA_FLL_MAX_REFDIV) {
Richard Fitzgerald8e42db12016-04-21 14:04:14 +01002066 /* start from init_ratio because this may already give a
2067 * fractional N.K
2068 */
2069 for (ratio = init_ratio; ratio > 0; ratio--) {
2070 if (target % (ratio * Fref)) {
2071 cfg->refdiv = refdiv;
2072 cfg->fratio = ratio - 1;
2073 arizona_fll_dbg(fll,
2074 "pseudo: found fref=%u refdiv=%d(%d) ratio=%d\n",
2075 Fref, refdiv, div, ratio);
2076 return ratio;
2077 }
2078 }
2079
2080 for (ratio = init_ratio + 1; ratio <= ARIZONA_FLL_MAX_FRATIO;
Charles Keepaxd0800342014-03-07 16:34:25 +00002081 ratio++) {
Charles Keepax35a730a2014-07-09 17:41:45 +01002082 if ((ARIZONA_FLL_VCO_CORNER / 2) /
Richard Fitzgerald01582a82016-02-10 11:56:13 +00002083 (fll->vco_mult * ratio) < Fref) {
2084 arizona_fll_dbg(fll, "pseudo: hit VCO corner\n");
Charles Keepax29fee822014-07-09 17:41:44 +01002085 break;
Richard Fitzgerald01582a82016-02-10 11:56:13 +00002086 }
2087
2088 if (Fref > pseudo_fref_max[ratio - 1]) {
2089 arizona_fll_dbg(fll,
2090 "pseudo: exceeded max fref(%u) for ratio=%u\n",
2091 pseudo_fref_max[ratio - 1],
2092 ratio);
2093 break;
2094 }
Charles Keepax29fee822014-07-09 17:41:44 +01002095
Charles Keepaxd0800342014-03-07 16:34:25 +00002096 if (target % (ratio * Fref)) {
2097 cfg->refdiv = refdiv;
2098 cfg->fratio = ratio - 1;
Richard Fitzgerald01582a82016-02-10 11:56:13 +00002099 arizona_fll_dbg(fll,
2100 "pseudo: found fref=%u refdiv=%d(%d) ratio=%d\n",
2101 Fref, refdiv, div, ratio);
Charles Keepaxd0800342014-03-07 16:34:25 +00002102 return ratio;
2103 }
2104 }
2105
Charles Keepaxd0800342014-03-07 16:34:25 +00002106 div *= 2;
2107 Fref /= 2;
2108 refdiv++;
2109 init_ratio = arizona_find_fratio(Fref, NULL);
Richard Fitzgerald01582a82016-02-10 11:56:13 +00002110 arizona_fll_dbg(fll,
2111 "pseudo: change fref=%u refdiv=%d(%d) ratio=%u\n",
2112 Fref, refdiv, div, init_ratio);
Charles Keepaxd0800342014-03-07 16:34:25 +00002113 }
2114
2115 arizona_fll_warn(fll, "Falling back to integer mode operation\n");
2116 return cfg->fratio + 1;
2117}
2118
Mark Brown07ed8732012-06-18 21:08:44 +01002119static int arizona_calc_fll(struct arizona_fll *fll,
2120 struct arizona_fll_cfg *cfg,
Charles Keepaxd0800342014-03-07 16:34:25 +00002121 unsigned int Fref, bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01002122{
2123 unsigned int target, div, gcd_fll;
2124 int i, ratio;
2125
Charles Keepax8ccefcd2014-03-07 16:34:21 +00002126 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, fll->fout);
Mark Brown07ed8732012-06-18 21:08:44 +01002127
Mark Brown2b4d39f2012-07-10 17:03:46 +01002128 /* Fvco should be over the targt; don't check the upper bound */
Charles Keepaxf641aec2014-03-07 16:34:22 +00002129 div = ARIZONA_FLL_MIN_OUTDIV;
2130 while (fll->fout * div < ARIZONA_FLL_MIN_FVCO * fll->vco_mult) {
Mark Brown07ed8732012-06-18 21:08:44 +01002131 div++;
Charles Keepaxf641aec2014-03-07 16:34:22 +00002132 if (div > ARIZONA_FLL_MAX_OUTDIV)
Mark Brown07ed8732012-06-18 21:08:44 +01002133 return -EINVAL;
Mark Brown07ed8732012-06-18 21:08:44 +01002134 }
Charles Keepaxf641aec2014-03-07 16:34:22 +00002135 target = fll->fout * div / fll->vco_mult;
Mark Brown07ed8732012-06-18 21:08:44 +01002136 cfg->outdiv = div;
2137
2138 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
2139
Charles Keepaxd0800342014-03-07 16:34:25 +00002140 /* Find an appropriate FLL_FRATIO and refdiv */
2141 ratio = arizona_calc_fratio(fll, cfg, target, Fref, sync);
2142 if (ratio < 0)
2143 return ratio;
Mark Brown07ed8732012-06-18 21:08:44 +01002144
Mark Brown07ed8732012-06-18 21:08:44 +01002145 /* Apply the division for our remaining calculations */
Charles Keepaxd0800342014-03-07 16:34:25 +00002146 Fref = Fref / (1 << cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08002147
Mark Brown07ed8732012-06-18 21:08:44 +01002148 cfg->n = target / (ratio * Fref);
2149
Ryo Tsutsui01f58152013-02-03 17:18:00 +09002150 if (target % (ratio * Fref)) {
Mark Brown07ed8732012-06-18 21:08:44 +01002151 gcd_fll = gcd(target, ratio * Fref);
2152 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
2153
2154 cfg->theta = (target - (cfg->n * ratio * Fref))
2155 / gcd_fll;
2156 cfg->lambda = (ratio * Fref) / gcd_fll;
2157 } else {
2158 cfg->theta = 0;
2159 cfg->lambda = 0;
2160 }
2161
Ryo Tsutsui01f58152013-02-03 17:18:00 +09002162 /* Round down to 16bit range with cost of accuracy lost.
2163 * Denominator must be bigger than numerator so we only
2164 * take care of it.
2165 */
2166 while (cfg->lambda >= (1 << 16)) {
2167 cfg->theta >>= 1;
2168 cfg->lambda >>= 1;
2169 }
2170
Charles Keepax5a3935c2014-03-07 16:34:23 +00002171 for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
2172 if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
2173 cfg->gain = fll_gains[i].gain;
2174 break;
2175 }
2176 }
2177 if (i == ARRAY_SIZE(fll_gains)) {
2178 arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
2179 Fref);
2180 return -EINVAL;
2181 }
2182
Richard Fitzgerald2595b7f2016-02-23 14:16:32 +00002183 arizona_fll_dbg(fll, "N=%d THETA=%d LAMBDA=%d\n",
Mark Brown07ed8732012-06-18 21:08:44 +01002184 cfg->n, cfg->theta, cfg->lambda);
Richard Fitzgerald2595b7f2016-02-23 14:16:32 +00002185 arizona_fll_dbg(fll, "FRATIO=0x%x(%d) OUTDIV=%d REFCLK_DIV=0x%x(%d)\n",
2186 cfg->fratio, ratio, cfg->outdiv,
2187 cfg->refdiv, 1 << cfg->refdiv);
2188 arizona_fll_dbg(fll, "GAIN=0x%x(%d)\n", cfg->gain, 1 << cfg->gain);
Mark Brown07ed8732012-06-18 21:08:44 +01002189
2190 return 0;
2191
2192}
2193
2194static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
Mark Brown8f113d72013-03-05 12:08:57 +08002195 struct arizona_fll_cfg *cfg, int source,
2196 bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01002197{
Mark Brown3c43c692013-12-12 00:49:22 +00002198 regmap_update_bits_async(arizona->regmap, base + 3,
2199 ARIZONA_FLL1_THETA_MASK, cfg->theta);
2200 regmap_update_bits_async(arizona->regmap, base + 4,
2201 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
2202 regmap_update_bits_async(arizona->regmap, base + 5,
2203 ARIZONA_FLL1_FRATIO_MASK,
2204 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
2205 regmap_update_bits_async(arizona->regmap, base + 6,
2206 ARIZONA_FLL1_CLK_REF_DIV_MASK |
2207 ARIZONA_FLL1_CLK_REF_SRC_MASK,
2208 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
2209 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
Mark Brown07ed8732012-06-18 21:08:44 +01002210
Charles Keepax61719db2014-03-07 16:34:19 +00002211 if (sync) {
2212 regmap_update_bits(arizona->regmap, base + 0x7,
2213 ARIZONA_FLL1_GAIN_MASK,
2214 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
2215 } else {
2216 regmap_update_bits(arizona->regmap, base + 0x5,
2217 ARIZONA_FLL1_OUTDIV_MASK,
2218 cfg->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
2219 regmap_update_bits(arizona->regmap, base + 0x9,
2220 ARIZONA_FLL1_GAIN_MASK,
2221 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
2222 }
Mark Brown8f113d72013-03-05 12:08:57 +08002223
Mark Brown3c43c692013-12-12 00:49:22 +00002224 regmap_update_bits_async(arizona->regmap, base + 2,
2225 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
2226 ARIZONA_FLL1_CTRL_UPD | cfg->n);
Mark Brown07ed8732012-06-18 21:08:44 +01002227}
2228
Charles Keepax62bb7102016-09-02 16:52:44 +01002229static int arizona_is_enabled_fll(struct arizona_fll *fll, int base)
Charles Keepaxd122d6c2013-02-20 17:28:36 +00002230{
2231 struct arizona *arizona = fll->arizona;
2232 unsigned int reg;
2233 int ret;
2234
Charles Keepax62bb7102016-09-02 16:52:44 +01002235 ret = regmap_read(arizona->regmap, base + 1, &reg);
Charles Keepaxd122d6c2013-02-20 17:28:36 +00002236 if (ret != 0) {
2237 arizona_fll_err(fll, "Failed to read current state: %d\n",
2238 ret);
2239 return ret;
2240 }
2241
2242 return reg & ARIZONA_FLL1_ENA;
2243}
2244
Charles Keepaxc393aca2014-07-09 17:41:47 +01002245static int arizona_enable_fll(struct arizona_fll *fll)
Charles Keepax35722812013-02-20 17:28:38 +00002246{
2247 struct arizona *arizona = fll->arizona;
Charles Keepax49c60542013-09-16 15:34:35 +01002248 bool use_sync = false;
Charles Keepax62bb7102016-09-02 16:52:44 +01002249 int already_enabled = arizona_is_enabled_fll(fll, fll->base);
Charles Keepax0f72a8a2016-09-02 16:52:45 +01002250 int sync_enabled = arizona_is_enabled_fll(fll, fll->base + 0x10);
Charles Keepax23f785a82014-03-07 16:34:20 +00002251 struct arizona_fll_cfg cfg;
Charles Keepax0e765972015-08-25 12:43:48 +01002252 int i;
2253 unsigned int val;
Charles Keepax35722812013-02-20 17:28:38 +00002254
Charles Keepaxc393aca2014-07-09 17:41:47 +01002255 if (already_enabled < 0)
2256 return already_enabled;
Charles Keepax0f72a8a2016-09-02 16:52:45 +01002257 if (sync_enabled < 0)
2258 return sync_enabled;
Charles Keepaxc393aca2014-07-09 17:41:47 +01002259
Charles Keepaxc8badda2014-07-09 17:41:49 +01002260 if (already_enabled) {
2261 /* Facilitate smooth refclk across the transition */
Charles Keepax800f2972015-11-30 17:37:28 +00002262 regmap_update_bits(fll->arizona->regmap, fll->base + 1,
2263 ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
2264 udelay(32);
Nariman Poushinc9991052016-08-30 10:30:40 +01002265 regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9,
2266 ARIZONA_FLL1_GAIN_MASK, 0);
Charles Keepaxc8badda2014-07-09 17:41:49 +01002267 }
2268
Mark Brownff680a12013-03-04 16:00:19 +08002269 /*
2270 * If we have both REFCLK and SYNCCLK then enable both,
2271 * otherwise apply the SYNCCLK settings to REFCLK.
2272 */
Charles Keepax49c60542013-09-16 15:34:35 +01002273 if (fll->ref_src >= 0 && fll->ref_freq &&
2274 fll->ref_src != fll->sync_src) {
Charles Keepaxd0800342014-03-07 16:34:25 +00002275 arizona_calc_fll(fll, &cfg, fll->ref_freq, false);
Charles Keepax35722812013-02-20 17:28:38 +00002276
Charles Keepaxe87d9ae2016-09-02 16:52:43 +01002277 /* Ref path hardcodes lambda to 65536 when sync is on */
2278 if (fll->sync_src >= 0 && cfg.lambda)
2279 cfg.theta = (cfg.theta * (1 << 16)) / cfg.lambda;
2280
Charles Keepax23f785a82014-03-07 16:34:20 +00002281 arizona_apply_fll(arizona, fll->base, &cfg, fll->ref_src,
Mark Brown8f113d72013-03-05 12:08:57 +08002282 false);
Charles Keepax49c60542013-09-16 15:34:35 +01002283 if (fll->sync_src >= 0) {
Charles Keepaxd0800342014-03-07 16:34:25 +00002284 arizona_calc_fll(fll, &cfg, fll->sync_freq, true);
Charles Keepax23f785a82014-03-07 16:34:20 +00002285
2286 arizona_apply_fll(arizona, fll->base + 0x10, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08002287 fll->sync_src, true);
Charles Keepax49c60542013-09-16 15:34:35 +01002288 use_sync = true;
2289 }
Mark Brownff680a12013-03-04 16:00:19 +08002290 } else if (fll->sync_src >= 0) {
Charles Keepaxd0800342014-03-07 16:34:25 +00002291 arizona_calc_fll(fll, &cfg, fll->sync_freq, false);
Mark Brownff680a12013-03-04 16:00:19 +08002292
Charles Keepax23f785a82014-03-07 16:34:20 +00002293 arizona_apply_fll(arizona, fll->base, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08002294 fll->sync_src, false);
Mark Browneca2e8e2013-03-06 00:09:59 +08002295
Mark Brown3c43c692013-12-12 00:49:22 +00002296 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
2297 ARIZONA_FLL1_SYNC_ENA, 0);
Mark Brownff680a12013-03-04 16:00:19 +08002298 } else {
2299 arizona_fll_err(fll, "No clocks provided\n");
Charles Keepaxc393aca2014-07-09 17:41:47 +01002300 return -EINVAL;
Mark Brownff680a12013-03-04 16:00:19 +08002301 }
Charles Keepax35722812013-02-20 17:28:38 +00002302
Charles Keepax0f72a8a2016-09-02 16:52:45 +01002303 if (already_enabled && !!sync_enabled != use_sync)
2304 arizona_fll_warn(fll, "Synchroniser changed on active FLL\n");
2305
Mark Brown576411be2013-03-05 12:07:16 +08002306 /*
2307 * Increase the bandwidth if we're not using a low frequency
2308 * sync source.
2309 */
Charles Keepax49c60542013-09-16 15:34:35 +01002310 if (use_sync && fll->sync_freq > 100000)
Mark Brown3c43c692013-12-12 00:49:22 +00002311 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
2312 ARIZONA_FLL1_SYNC_BW, 0);
Mark Brown576411be2013-03-05 12:07:16 +08002313 else
Mark Brown3c43c692013-12-12 00:49:22 +00002314 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
2315 ARIZONA_FLL1_SYNC_BW,
2316 ARIZONA_FLL1_SYNC_BW);
Mark Brown576411be2013-03-05 12:07:16 +08002317
Charles Keepaxc393aca2014-07-09 17:41:47 +01002318 if (!already_enabled)
Richard Fitzgerald63d19e02016-08-25 11:39:32 +01002319 pm_runtime_get_sync(arizona->dev);
Charles Keepax35722812013-02-20 17:28:38 +00002320
Charles Keepax49c60542013-09-16 15:34:35 +01002321 if (use_sync)
Mark Brown3c43c692013-12-12 00:49:22 +00002322 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
2323 ARIZONA_FLL1_SYNC_ENA,
2324 ARIZONA_FLL1_SYNC_ENA);
Charles Keepax0f72a8a2016-09-02 16:52:45 +01002325 regmap_update_bits_async(arizona->regmap, fll->base + 1,
2326 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
Charles Keepax35722812013-02-20 17:28:38 +00002327
Charles Keepaxc8badda2014-07-09 17:41:49 +01002328 if (already_enabled)
2329 regmap_update_bits_async(arizona->regmap, fll->base + 1,
2330 ARIZONA_FLL1_FREERUN, 0);
2331
Charles Keepax0e765972015-08-25 12:43:48 +01002332 arizona_fll_dbg(fll, "Waiting for FLL lock...\n");
2333 val = 0;
2334 for (i = 0; i < 15; i++) {
2335 if (i < 5)
2336 usleep_range(200, 400);
2337 else
2338 msleep(20);
2339
2340 regmap_read(arizona->regmap,
2341 ARIZONA_INTERRUPT_RAW_STATUS_5,
2342 &val);
2343 if (val & (ARIZONA_FLL1_CLOCK_OK_STS << (fll->id - 1)))
2344 break;
2345 }
2346 if (i == 15)
Charles Keepax35722812013-02-20 17:28:38 +00002347 arizona_fll_warn(fll, "Timed out waiting for lock\n");
Charles Keepax0e765972015-08-25 12:43:48 +01002348 else
2349 arizona_fll_dbg(fll, "FLL locked (%d polls)\n", i);
Charles Keepaxc393aca2014-07-09 17:41:47 +01002350
2351 return 0;
Charles Keepax35722812013-02-20 17:28:38 +00002352}
2353
Charles Keepax76040542013-02-20 17:28:37 +00002354static void arizona_disable_fll(struct arizona_fll *fll)
2355{
2356 struct arizona *arizona = fll->arizona;
2357 bool change;
2358
Mark Brown3c43c692013-12-12 00:49:22 +00002359 regmap_update_bits_async(arizona->regmap, fll->base + 1,
2360 ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
Charles Keepax76040542013-02-20 17:28:37 +00002361 regmap_update_bits_check(arizona->regmap, fll->base + 1,
2362 ARIZONA_FLL1_ENA, 0, &change);
2363 regmap_update_bits(arizona->regmap, fll->base + 0x11,
2364 ARIZONA_FLL1_SYNC_ENA, 0);
Charles Keepax5e39a502014-07-09 17:41:48 +01002365 regmap_update_bits_async(arizona->regmap, fll->base + 1,
2366 ARIZONA_FLL1_FREERUN, 0);
Charles Keepax76040542013-02-20 17:28:37 +00002367
2368 if (change)
2369 pm_runtime_put_autosuspend(arizona->dev);
2370}
2371
Charles Keepaxee929a92013-02-20 17:28:40 +00002372int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
2373 unsigned int Fref, unsigned int Fout)
2374{
Charles Keepaxc393aca2014-07-09 17:41:47 +01002375 int ret = 0;
Charles Keepaxee929a92013-02-20 17:28:40 +00002376
Charles Keepax1c5617f2013-02-22 17:10:37 +00002377 if (fll->ref_src == source && fll->ref_freq == Fref)
Charles Keepaxee929a92013-02-20 17:28:40 +00002378 return 0;
2379
Charles Keepax23f785a82014-03-07 16:34:20 +00002380 if (fll->fout && Fref > 0) {
2381 ret = arizona_validate_fll(fll, Fref, fll->fout);
2382 if (ret != 0)
2383 return ret;
Charles Keepaxee929a92013-02-20 17:28:40 +00002384 }
2385
2386 fll->ref_src = source;
2387 fll->ref_freq = Fref;
Charles Keepaxee929a92013-02-20 17:28:40 +00002388
Mark Brown86cd6842013-03-07 16:14:04 +08002389 if (fll->fout && Fref > 0) {
Charles Keepaxc393aca2014-07-09 17:41:47 +01002390 ret = arizona_enable_fll(fll);
Charles Keepaxee929a92013-02-20 17:28:40 +00002391 }
2392
Charles Keepaxc393aca2014-07-09 17:41:47 +01002393 return ret;
Charles Keepaxee929a92013-02-20 17:28:40 +00002394}
2395EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
2396
Mark Brown07ed8732012-06-18 21:08:44 +01002397int arizona_set_fll(struct arizona_fll *fll, int source,
2398 unsigned int Fref, unsigned int Fout)
2399{
Charles Keepaxc393aca2014-07-09 17:41:47 +01002400 int ret = 0;
Mark Brown07ed8732012-06-18 21:08:44 +01002401
Mark Brownff680a12013-03-04 16:00:19 +08002402 if (fll->sync_src == source &&
2403 fll->sync_freq == Fref && fll->fout == Fout)
2404 return 0;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00002405
Mark Brownff680a12013-03-04 16:00:19 +08002406 if (Fout) {
2407 if (fll->ref_src >= 0) {
Charles Keepax23f785a82014-03-07 16:34:20 +00002408 ret = arizona_validate_fll(fll, fll->ref_freq, Fout);
Charles Keepax9e359c62013-02-20 17:28:35 +00002409 if (ret != 0)
2410 return ret;
2411 }
2412
Charles Keepax23f785a82014-03-07 16:34:20 +00002413 ret = arizona_validate_fll(fll, Fref, Fout);
Mark Brownff680a12013-03-04 16:00:19 +08002414 if (ret != 0)
2415 return ret;
Charles Keepax9e359c62013-02-20 17:28:35 +00002416 }
Mark Brownff680a12013-03-04 16:00:19 +08002417
2418 fll->sync_src = source;
2419 fll->sync_freq = Fref;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00002420 fll->fout = Fout;
Charles Keepax9e359c62013-02-20 17:28:35 +00002421
Charles Keepax613124c2014-07-09 17:41:46 +01002422 if (Fout)
Charles Keepaxc393aca2014-07-09 17:41:47 +01002423 ret = arizona_enable_fll(fll);
Charles Keepax613124c2014-07-09 17:41:46 +01002424 else
Charles Keepax76040542013-02-20 17:28:37 +00002425 arizona_disable_fll(fll);
Mark Brown07ed8732012-06-18 21:08:44 +01002426
Charles Keepaxc393aca2014-07-09 17:41:47 +01002427 return ret;
Mark Brown07ed8732012-06-18 21:08:44 +01002428}
2429EXPORT_SYMBOL_GPL(arizona_set_fll);
2430
2431int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
2432 int ok_irq, struct arizona_fll *fll)
2433{
Charles Keepax19b34bd2013-02-20 17:28:34 +00002434 unsigned int val;
Mark Brown07ed8732012-06-18 21:08:44 +01002435
Mark Brown07ed8732012-06-18 21:08:44 +01002436 fll->id = id;
2437 fll->base = base;
2438 fll->arizona = arizona;
Charles Keepaxf3f11632013-02-20 17:28:41 +00002439 fll->sync_src = ARIZONA_FLL_SRC_NONE;
Mark Brown07ed8732012-06-18 21:08:44 +01002440
Charles Keepax19b34bd2013-02-20 17:28:34 +00002441 /* Configure default refclk to 32kHz if we have one */
2442 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
2443 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
2444 case ARIZONA_CLK_SRC_MCLK1:
2445 case ARIZONA_CLK_SRC_MCLK2:
2446 fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK;
2447 break;
2448 default:
Charles Keepaxf3f11632013-02-20 17:28:41 +00002449 fll->ref_src = ARIZONA_FLL_SRC_NONE;
Charles Keepax19b34bd2013-02-20 17:28:34 +00002450 }
2451 fll->ref_freq = 32768;
2452
Mark Brown07ed8732012-06-18 21:08:44 +01002453 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
2454 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
2455 "FLL%d clock OK", id);
2456
Charles Keepaxe31c1942013-01-07 16:41:45 +00002457 regmap_update_bits(arizona->regmap, fll->base + 1,
2458 ARIZONA_FLL1_FREERUN, 0);
2459
Mark Brown07ed8732012-06-18 21:08:44 +01002460 return 0;
2461}
2462EXPORT_SYMBOL_GPL(arizona_init_fll);
2463
Mark Brownbc9ab6d2013-01-04 19:31:00 +00002464/**
2465 * arizona_set_output_mode - Set the mode of the specified output
2466 *
2467 * @codec: Device to configure
2468 * @output: Output number
2469 * @diff: True to set the output to differential mode
2470 *
2471 * Some systems use external analogue switches to connect more
2472 * analogue devices to the CODEC than are supported by the device. In
2473 * some systems this requires changing the switched output from single
2474 * ended to differential mode dynamically at runtime, an operation
2475 * supported using this function.
2476 *
2477 * Most systems have a single static configuration and should use
2478 * platform data instead.
2479 */
2480int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
2481{
2482 unsigned int reg, val;
2483
2484 if (output < 1 || output > 6)
2485 return -EINVAL;
2486
2487 reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
2488
2489 if (diff)
2490 val = ARIZONA_OUT1_MONO;
2491 else
2492 val = 0;
2493
2494 return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val);
2495}
2496EXPORT_SYMBOL_GPL(arizona_set_output_mode);
2497
Richard Fitzgerald336d0442015-06-18 13:43:19 +01002498static const struct soc_enum arizona_adsp2_rate_enum[] = {
2499 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP1_CONTROL_1,
2500 ARIZONA_DSP1_RATE_SHIFT, 0xf,
2501 ARIZONA_RATE_ENUM_SIZE,
2502 arizona_rate_text, arizona_rate_val),
2503 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP2_CONTROL_1,
2504 ARIZONA_DSP1_RATE_SHIFT, 0xf,
2505 ARIZONA_RATE_ENUM_SIZE,
2506 arizona_rate_text, arizona_rate_val),
2507 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1,
2508 ARIZONA_DSP1_RATE_SHIFT, 0xf,
2509 ARIZONA_RATE_ENUM_SIZE,
2510 arizona_rate_text, arizona_rate_val),
2511 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP4_CONTROL_1,
2512 ARIZONA_DSP1_RATE_SHIFT, 0xf,
2513 ARIZONA_RATE_ENUM_SIZE,
2514 arizona_rate_text, arizona_rate_val),
2515};
2516
2517const struct snd_kcontrol_new arizona_adsp2_rate_controls[] = {
2518 SOC_ENUM("DSP1 Rate", arizona_adsp2_rate_enum[0]),
2519 SOC_ENUM("DSP2 Rate", arizona_adsp2_rate_enum[1]),
2520 SOC_ENUM("DSP3 Rate", arizona_adsp2_rate_enum[2]),
2521 SOC_ENUM("DSP4 Rate", arizona_adsp2_rate_enum[3]),
2522};
2523EXPORT_SYMBOL_GPL(arizona_adsp2_rate_controls);
2524
Charles Keepaxc05d9a82015-06-25 09:35:11 +01002525static bool arizona_eq_filter_unstable(bool mode, __be16 _a, __be16 _b)
2526{
2527 s16 a = be16_to_cpu(_a);
2528 s16 b = be16_to_cpu(_b);
2529
2530 if (!mode) {
2531 return abs(a) >= 4096;
2532 } else {
2533 if (abs(b) >= 4096)
2534 return true;
2535
2536 return (abs((a << 16) / (4096 - b)) >= 4096 << 4);
2537 }
2538}
2539
2540int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol,
2541 struct snd_ctl_elem_value *ucontrol)
2542{
2543 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
2544 struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
2545 struct soc_bytes *params = (void *)kcontrol->private_value;
2546 unsigned int val;
2547 __be16 *data;
2548 int len;
2549 int ret;
2550
2551 len = params->num_regs * regmap_get_val_bytes(arizona->regmap);
2552
2553 data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA);
2554 if (!data)
2555 return -ENOMEM;
2556
2557 data[0] &= cpu_to_be16(ARIZONA_EQ1_B1_MODE);
2558
2559 if (arizona_eq_filter_unstable(!!data[0], data[1], data[2]) ||
2560 arizona_eq_filter_unstable(true, data[4], data[5]) ||
2561 arizona_eq_filter_unstable(true, data[8], data[9]) ||
2562 arizona_eq_filter_unstable(true, data[12], data[13]) ||
2563 arizona_eq_filter_unstable(false, data[16], data[17])) {
2564 dev_err(arizona->dev, "Rejecting unstable EQ coefficients\n");
2565 ret = -EINVAL;
2566 goto out;
2567 }
2568
2569 ret = regmap_read(arizona->regmap, params->base, &val);
2570 if (ret != 0)
2571 goto out;
2572
2573 val &= ~ARIZONA_EQ1_B1_MODE;
2574 data[0] |= cpu_to_be16(val);
2575
2576 ret = regmap_raw_write(arizona->regmap, params->base, data, len);
2577
2578out:
2579 kfree(data);
2580 return ret;
2581}
2582EXPORT_SYMBOL_GPL(arizona_eq_coeff_put);
2583
Charles Keepax5f8e6712015-06-25 09:35:12 +01002584int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
2585 struct snd_ctl_elem_value *ucontrol)
2586{
2587 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
2588 struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
2589 __be16 *data = (__be16 *)ucontrol->value.bytes.data;
2590 s16 val = be16_to_cpu(*data);
2591
2592 if (abs(val) >= 4096) {
2593 dev_err(arizona->dev, "Rejecting unstable LHPF coefficients\n");
2594 return -EINVAL;
2595 }
2596
2597 return snd_soc_bytes_put(kcontrol, ucontrol);
2598}
2599EXPORT_SYMBOL_GPL(arizona_lhpf_coeff_put);
2600
Charles Keepax2230c492016-05-13 16:45:18 +01002601int arizona_register_notifier(struct snd_soc_codec *codec,
2602 struct notifier_block *nb,
2603 int (*notify)(struct notifier_block *nb,
2604 unsigned long action, void *data))
2605{
2606 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
2607 struct arizona *arizona = priv->arizona;
2608
2609 nb->notifier_call = notify;
2610
2611 return blocking_notifier_chain_register(&arizona->notifier, nb);
2612}
2613EXPORT_SYMBOL_GPL(arizona_register_notifier);
2614
2615int arizona_unregister_notifier(struct snd_soc_codec *codec,
2616 struct notifier_block *nb)
2617{
2618 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
2619 struct arizona *arizona = priv->arizona;
2620
2621 return blocking_notifier_chain_unregister(&arizona->notifier, nb);
2622}
2623EXPORT_SYMBOL_GPL(arizona_unregister_notifier);
2624
Mark Brown07ed8732012-06-18 21:08:44 +01002625MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
2626MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
2627MODULE_LICENSE("GPL");