blob: 0a734d910850b1305b1fa5ee67efc571576bfbf5 [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 Keepax31833ea2016-10-26 10:59:57 +0100194 return 0;
195}
196EXPORT_SYMBOL_GPL(arizona_init_spk);
197
198int arizona_init_spk_irqs(struct arizona *arizona)
199{
200 int ret;
201
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100202 ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN,
Mark Brown899817e2013-03-13 12:32:10 +0000203 "Thermal warning", arizona_thermal_warn,
204 arizona);
205 if (ret != 0)
206 dev_err(arizona->dev,
207 "Failed to get thermal warning IRQ: %d\n",
208 ret);
209
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100210 ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT,
Mark Brown899817e2013-03-13 12:32:10 +0000211 "Thermal shutdown", arizona_thermal_shutdown,
212 arizona);
213 if (ret != 0)
214 dev_err(arizona->dev,
215 "Failed to get thermal shutdown IRQ: %d\n",
216 ret);
217
Mark Brown56447e12013-01-10 14:45:58 +0000218 return 0;
219}
Charles Keepax31833ea2016-10-26 10:59:57 +0100220EXPORT_SYMBOL_GPL(arizona_init_spk_irqs);
Mark Brown56447e12013-01-10 14:45:58 +0000221
Charles Keepax31833ea2016-10-26 10:59:57 +0100222int arizona_free_spk_irqs(struct arizona *arizona)
Charles Keepax54dca702016-04-15 13:11:56 +0100223{
Charles Keepax54dca702016-04-15 13:11:56 +0100224 arizona_free_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN, arizona);
225 arizona_free_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT, arizona);
226
227 return 0;
228}
Charles Keepax31833ea2016-10-26 10:59:57 +0100229EXPORT_SYMBOL_GPL(arizona_free_spk_irqs);
Charles Keepax54dca702016-04-15 13:11:56 +0100230
Charles Keepaxb60f3632014-06-10 18:41:02 +0100231static const struct snd_soc_dapm_route arizona_mono_routes[] = {
232 { "OUT1R", NULL, "OUT1L" },
233 { "OUT2R", NULL, "OUT2L" },
234 { "OUT3R", NULL, "OUT3L" },
235 { "OUT4R", NULL, "OUT4L" },
236 { "OUT5R", NULL, "OUT5L" },
237 { "OUT6R", NULL, "OUT6L" },
238};
239
240int arizona_init_mono(struct snd_soc_codec *codec)
241{
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200242 struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
Charles Keepaxb60f3632014-06-10 18:41:02 +0100243 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
244 struct arizona *arizona = priv->arizona;
245 int i;
246
247 for (i = 0; i < ARIZONA_MAX_OUTPUT; ++i) {
248 if (arizona->pdata.out_mono[i])
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200249 snd_soc_dapm_add_routes(dapm,
Charles Keepaxb60f3632014-06-10 18:41:02 +0100250 &arizona_mono_routes[i], 1);
251 }
252
253 return 0;
254}
255EXPORT_SYMBOL_GPL(arizona_init_mono);
256
Charles Keepaxb63144e2013-07-04 08:56:28 +0100257int arizona_init_gpio(struct snd_soc_codec *codec)
258{
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200259 struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
Richard Fitzgerald35f44032016-11-29 15:44:39 +0000260 struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
Charles Keepaxb63144e2013-07-04 08:56:28 +0100261 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
262 struct arizona *arizona = priv->arizona;
263 int i;
264
265 switch (arizona->type) {
266 case WM5110:
Richard Fitzgerald575ef7f2015-01-17 15:21:27 +0000267 case WM8280:
Richard Fitzgerald35f44032016-11-29 15:44:39 +0000268 snd_soc_component_disable_pin(component,
269 "DRC2 Signal Activity");
Charles Keepaxb79fae62013-07-04 16:53:03 +0100270 break;
271 default:
272 break;
Charles Keepaxb63144e2013-07-04 08:56:28 +0100273 }
274
Richard Fitzgerald35f44032016-11-29 15:44:39 +0000275 snd_soc_component_disable_pin(component, "DRC1 Signal Activity");
Charles Keepaxb63144e2013-07-04 08:56:28 +0100276
277 for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
278 switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) {
279 case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT:
Richard Fitzgerald35f44032016-11-29 15:44:39 +0000280 snd_soc_component_enable_pin(component,
281 "DRC1 Signal Activity");
Charles Keepaxb63144e2013-07-04 08:56:28 +0100282 break;
283 case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT:
Richard Fitzgerald35f44032016-11-29 15:44:39 +0000284 snd_soc_component_enable_pin(component,
285 "DRC2 Signal Activity");
Charles Keepaxb63144e2013-07-04 08:56:28 +0100286 break;
287 default:
288 break;
289 }
290 }
291
292 return 0;
293}
294EXPORT_SYMBOL_GPL(arizona_init_gpio);
295
Charles Keepax2230c492016-05-13 16:45:18 +0100296int arizona_init_notifiers(struct snd_soc_codec *codec)
297{
298 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
299 struct arizona *arizona = priv->arizona;
300
301 BLOCKING_INIT_NOTIFIER_HEAD(&arizona->notifier);
302
303 return 0;
304}
305EXPORT_SYMBOL_GPL(arizona_init_notifiers);
306
Charles Keepax141bc6a2015-12-03 18:15:06 +0000307const char * const arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100308 "None",
309 "Tone Generator 1",
310 "Tone Generator 2",
311 "Haptics",
312 "AEC",
Richard Fitzgerald6ebbce02015-09-28 14:01:09 +0100313 "AEC2",
Mark Brown07ed8732012-06-18 21:08:44 +0100314 "Mic Mute Mixer",
315 "Noise Generator",
316 "IN1L",
317 "IN1R",
318 "IN2L",
319 "IN2R",
320 "IN3L",
321 "IN3R",
Mark Brownc9c56fd2012-07-09 19:09:01 +0100322 "IN4L",
323 "IN4R",
Mark Brown07ed8732012-06-18 21:08:44 +0100324 "AIF1RX1",
325 "AIF1RX2",
326 "AIF1RX3",
327 "AIF1RX4",
328 "AIF1RX5",
329 "AIF1RX6",
330 "AIF1RX7",
331 "AIF1RX8",
332 "AIF2RX1",
333 "AIF2RX2",
Richard Fitzgeralde64001e2013-11-20 13:17:07 +0000334 "AIF2RX3",
335 "AIF2RX4",
336 "AIF2RX5",
337 "AIF2RX6",
Mark Brown07ed8732012-06-18 21:08:44 +0100338 "AIF3RX1",
339 "AIF3RX2",
340 "SLIMRX1",
341 "SLIMRX2",
342 "SLIMRX3",
343 "SLIMRX4",
344 "SLIMRX5",
345 "SLIMRX6",
346 "SLIMRX7",
347 "SLIMRX8",
348 "EQ1",
349 "EQ2",
350 "EQ3",
351 "EQ4",
352 "DRC1L",
353 "DRC1R",
354 "DRC2L",
355 "DRC2R",
356 "LHPF1",
357 "LHPF2",
358 "LHPF3",
359 "LHPF4",
360 "DSP1.1",
361 "DSP1.2",
362 "DSP1.3",
363 "DSP1.4",
364 "DSP1.5",
365 "DSP1.6",
Mark Brownc922cc42012-09-26 16:43:44 +0100366 "DSP2.1",
367 "DSP2.2",
368 "DSP2.3",
369 "DSP2.4",
370 "DSP2.5",
371 "DSP2.6",
372 "DSP3.1",
373 "DSP3.2",
374 "DSP3.3",
375 "DSP3.4",
376 "DSP3.5",
377 "DSP3.6",
378 "DSP4.1",
379 "DSP4.2",
380 "DSP4.3",
381 "DSP4.4",
382 "DSP4.5",
383 "DSP4.6",
Mark Brown07ed8732012-06-18 21:08:44 +0100384 "ASRC1L",
385 "ASRC1R",
386 "ASRC2L",
387 "ASRC2R",
Mark Brown91660bd2012-12-05 20:35:24 +0900388 "ISRC1INT1",
389 "ISRC1INT2",
390 "ISRC1INT3",
391 "ISRC1INT4",
392 "ISRC1DEC1",
393 "ISRC1DEC2",
394 "ISRC1DEC3",
395 "ISRC1DEC4",
396 "ISRC2INT1",
397 "ISRC2INT2",
398 "ISRC2INT3",
399 "ISRC2INT4",
400 "ISRC2DEC1",
401 "ISRC2DEC2",
402 "ISRC2DEC3",
403 "ISRC2DEC4",
404 "ISRC3INT1",
405 "ISRC3INT2",
406 "ISRC3INT3",
407 "ISRC3INT4",
408 "ISRC3DEC1",
409 "ISRC3DEC2",
410 "ISRC3DEC3",
411 "ISRC3DEC4",
Mark Brown07ed8732012-06-18 21:08:44 +0100412};
413EXPORT_SYMBOL_GPL(arizona_mixer_texts);
414
Charles Keepax141bc6a2015-12-03 18:15:06 +0000415unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100416 0x00, /* None */
417 0x04, /* Tone */
418 0x05,
419 0x06, /* Haptics */
420 0x08, /* AEC */
Richard Fitzgerald6ebbce02015-09-28 14:01:09 +0100421 0x09, /* AEC2 */
Mark Brown07ed8732012-06-18 21:08:44 +0100422 0x0c, /* Noise mixer */
423 0x0d, /* Comfort noise */
424 0x10, /* IN1L */
425 0x11,
426 0x12,
427 0x13,
428 0x14,
429 0x15,
Mark Brownc9c56fd2012-07-09 19:09:01 +0100430 0x16,
431 0x17,
Mark Brown07ed8732012-06-18 21:08:44 +0100432 0x20, /* AIF1RX1 */
433 0x21,
434 0x22,
435 0x23,
436 0x24,
437 0x25,
438 0x26,
439 0x27,
440 0x28, /* AIF2RX1 */
441 0x29,
Richard Fitzgeralde64001e2013-11-20 13:17:07 +0000442 0x2a,
443 0x2b,
444 0x2c,
445 0x2d,
Mark Brown07ed8732012-06-18 21:08:44 +0100446 0x30, /* AIF3RX1 */
447 0x31,
448 0x38, /* SLIMRX1 */
449 0x39,
450 0x3a,
451 0x3b,
452 0x3c,
453 0x3d,
454 0x3e,
455 0x3f,
456 0x50, /* EQ1 */
457 0x51,
458 0x52,
459 0x53,
460 0x58, /* DRC1L */
461 0x59,
462 0x5a,
463 0x5b,
464 0x60, /* LHPF1 */
465 0x61,
466 0x62,
467 0x63,
468 0x68, /* DSP1.1 */
469 0x69,
470 0x6a,
471 0x6b,
472 0x6c,
473 0x6d,
Mark Brownc922cc42012-09-26 16:43:44 +0100474 0x70, /* DSP2.1 */
475 0x71,
476 0x72,
477 0x73,
478 0x74,
479 0x75,
480 0x78, /* DSP3.1 */
481 0x79,
482 0x7a,
483 0x7b,
484 0x7c,
485 0x7d,
486 0x80, /* DSP4.1 */
487 0x81,
488 0x82,
489 0x83,
490 0x84,
491 0x85,
Mark Brown07ed8732012-06-18 21:08:44 +0100492 0x90, /* ASRC1L */
493 0x91,
494 0x92,
495 0x93,
Mark Brown91660bd2012-12-05 20:35:24 +0900496 0xa0, /* ISRC1INT1 */
497 0xa1,
498 0xa2,
499 0xa3,
500 0xa4, /* ISRC1DEC1 */
501 0xa5,
502 0xa6,
503 0xa7,
504 0xa8, /* ISRC2DEC1 */
505 0xa9,
506 0xaa,
507 0xab,
508 0xac, /* ISRC2INT1 */
509 0xad,
510 0xae,
511 0xaf,
512 0xb0, /* ISRC3DEC1 */
513 0xb1,
514 0xb2,
515 0xb3,
516 0xb4, /* ISRC3INT1 */
517 0xb5,
518 0xb6,
519 0xb7,
Mark Brown07ed8732012-06-18 21:08:44 +0100520};
521EXPORT_SYMBOL_GPL(arizona_mixer_values);
522
523const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
524EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
525
Richard Fitzgerald6ebbce02015-09-28 14:01:09 +0100526const char * const arizona_sample_rate_text[ARIZONA_SAMPLE_RATE_ENUM_SIZE] = {
527 "12kHz", "24kHz", "48kHz", "96kHz", "192kHz",
528 "11.025kHz", "22.05kHz", "44.1kHz", "88.2kHz", "176.4kHz",
529 "4kHz", "8kHz", "16kHz", "32kHz",
530};
531EXPORT_SYMBOL_GPL(arizona_sample_rate_text);
532
533const unsigned int arizona_sample_rate_val[ARIZONA_SAMPLE_RATE_ENUM_SIZE] = {
534 0x01, 0x02, 0x03, 0x04, 0x05, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
535 0x10, 0x11, 0x12, 0x13,
536};
537EXPORT_SYMBOL_GPL(arizona_sample_rate_val);
538
539const char *arizona_sample_rate_val_to_name(unsigned int rate_val)
540{
541 int i;
542
543 for (i = 0; i < ARRAY_SIZE(arizona_sample_rate_val); ++i) {
544 if (arizona_sample_rate_val[i] == rate_val)
545 return arizona_sample_rate_text[i];
546 }
547
548 return "Illegal";
549}
550EXPORT_SYMBOL_GPL(arizona_sample_rate_val_to_name);
551
Charles Keepax141bc6a2015-12-03 18:15:06 +0000552const char * const arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = {
Mark Browndc914282013-02-18 19:09:23 +0000553 "SYNCCLK rate", "8kHz", "16kHz", "ASYNCCLK rate",
554};
555EXPORT_SYMBOL_GPL(arizona_rate_text);
556
Charles Keepax141bc6a2015-12-03 18:15:06 +0000557const unsigned int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
Mark Browndc914282013-02-18 19:09:23 +0000558 0, 1, 2, 8,
559};
560EXPORT_SYMBOL_GPL(arizona_rate_val);
561
562
Charles Keepaxfbedc8c2013-12-19 09:30:12 +0000563const struct soc_enum arizona_isrc_fsh[] = {
564 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_1,
565 ARIZONA_ISRC1_FSH_SHIFT, 0xf,
566 ARIZONA_RATE_ENUM_SIZE,
567 arizona_rate_text, arizona_rate_val),
568 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_1,
569 ARIZONA_ISRC2_FSH_SHIFT, 0xf,
570 ARIZONA_RATE_ENUM_SIZE,
571 arizona_rate_text, arizona_rate_val),
572 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_1,
573 ARIZONA_ISRC3_FSH_SHIFT, 0xf,
574 ARIZONA_RATE_ENUM_SIZE,
575 arizona_rate_text, arizona_rate_val),
576};
577EXPORT_SYMBOL_GPL(arizona_isrc_fsh);
578
Mark Browndc914282013-02-18 19:09:23 +0000579const struct soc_enum arizona_isrc_fsl[] = {
580 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2,
581 ARIZONA_ISRC1_FSL_SHIFT, 0xf,
582 ARIZONA_RATE_ENUM_SIZE,
583 arizona_rate_text, arizona_rate_val),
584 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_2,
585 ARIZONA_ISRC2_FSL_SHIFT, 0xf,
586 ARIZONA_RATE_ENUM_SIZE,
587 arizona_rate_text, arizona_rate_val),
588 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_2,
589 ARIZONA_ISRC3_FSL_SHIFT, 0xf,
590 ARIZONA_RATE_ENUM_SIZE,
591 arizona_rate_text, arizona_rate_val),
592};
593EXPORT_SYMBOL_GPL(arizona_isrc_fsl);
594
Charles Keepax56d37d82013-12-19 09:30:13 +0000595const struct soc_enum arizona_asrc_rate1 =
596 SOC_VALUE_ENUM_SINGLE(ARIZONA_ASRC_RATE1,
597 ARIZONA_ASRC_RATE1_SHIFT, 0xf,
598 ARIZONA_RATE_ENUM_SIZE - 1,
599 arizona_rate_text, arizona_rate_val);
600EXPORT_SYMBOL_GPL(arizona_asrc_rate1);
601
Charles Keepaxa3178a32016-06-13 13:35:14 +0100602static const char * const arizona_vol_ramp_text[] = {
Mark Browne853a002012-12-09 12:25:52 +0900603 "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
604 "15ms/6dB", "30ms/6dB",
605};
606
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100607SOC_ENUM_SINGLE_DECL(arizona_in_vd_ramp,
608 ARIZONA_INPUT_VOLUME_RAMP,
609 ARIZONA_IN_VD_RAMP_SHIFT,
610 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900611EXPORT_SYMBOL_GPL(arizona_in_vd_ramp);
612
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100613SOC_ENUM_SINGLE_DECL(arizona_in_vi_ramp,
614 ARIZONA_INPUT_VOLUME_RAMP,
615 ARIZONA_IN_VI_RAMP_SHIFT,
616 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900617EXPORT_SYMBOL_GPL(arizona_in_vi_ramp);
618
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100619SOC_ENUM_SINGLE_DECL(arizona_out_vd_ramp,
620 ARIZONA_OUTPUT_VOLUME_RAMP,
621 ARIZONA_OUT_VD_RAMP_SHIFT,
622 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900623EXPORT_SYMBOL_GPL(arizona_out_vd_ramp);
624
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100625SOC_ENUM_SINGLE_DECL(arizona_out_vi_ramp,
626 ARIZONA_OUTPUT_VOLUME_RAMP,
627 ARIZONA_OUT_VI_RAMP_SHIFT,
628 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900629EXPORT_SYMBOL_GPL(arizona_out_vi_ramp);
630
Charles Keepaxa3178a32016-06-13 13:35:14 +0100631static const char * const arizona_lhpf_mode_text[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100632 "Low-pass", "High-pass"
633};
634
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100635SOC_ENUM_SINGLE_DECL(arizona_lhpf1_mode,
636 ARIZONA_HPLPF1_1,
637 ARIZONA_LHPF1_MODE_SHIFT,
638 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100639EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
640
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100641SOC_ENUM_SINGLE_DECL(arizona_lhpf2_mode,
642 ARIZONA_HPLPF2_1,
643 ARIZONA_LHPF2_MODE_SHIFT,
644 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100645EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
646
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100647SOC_ENUM_SINGLE_DECL(arizona_lhpf3_mode,
648 ARIZONA_HPLPF3_1,
649 ARIZONA_LHPF3_MODE_SHIFT,
650 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100651EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
652
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100653SOC_ENUM_SINGLE_DECL(arizona_lhpf4_mode,
654 ARIZONA_HPLPF4_1,
655 ARIZONA_LHPF4_MODE_SHIFT,
656 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100657EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
658
Charles Keepaxa3178a32016-06-13 13:35:14 +0100659static const char * const arizona_ng_hold_text[] = {
Mark Brown845571c2012-12-18 13:47:57 +0000660 "30ms", "120ms", "250ms", "500ms",
661};
662
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100663SOC_ENUM_SINGLE_DECL(arizona_ng_hold,
664 ARIZONA_NOISE_GATE_CONTROL,
665 ARIZONA_NGATE_HOLD_SHIFT,
666 arizona_ng_hold_text);
Mark Brown845571c2012-12-18 13:47:57 +0000667EXPORT_SYMBOL_GPL(arizona_ng_hold);
668
Charles Keepax254dc322013-11-19 16:04:03 +0000669static const char * const arizona_in_hpf_cut_text[] = {
670 "2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz"
671};
672
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100673SOC_ENUM_SINGLE_DECL(arizona_in_hpf_cut_enum,
674 ARIZONA_HPF_CONTROL,
675 ARIZONA_IN_HPF_CUT_SHIFT,
676 arizona_in_hpf_cut_text);
Charles Keepax254dc322013-11-19 16:04:03 +0000677EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum);
678
Charles Keepaxc7f38432013-08-06 17:03:55 +0100679static const char * const arizona_in_dmic_osr_text[] = {
Charles Keepaxef326f42014-11-12 14:55:26 +0000680 "1.536MHz", "3.072MHz", "6.144MHz", "768kHz",
Charles Keepaxc7f38432013-08-06 17:03:55 +0100681};
682
683const struct soc_enum arizona_in_dmic_osr[] = {
684 SOC_ENUM_SINGLE(ARIZONA_IN1L_CONTROL, ARIZONA_IN1_OSR_SHIFT,
685 ARRAY_SIZE(arizona_in_dmic_osr_text),
686 arizona_in_dmic_osr_text),
687 SOC_ENUM_SINGLE(ARIZONA_IN2L_CONTROL, ARIZONA_IN2_OSR_SHIFT,
688 ARRAY_SIZE(arizona_in_dmic_osr_text),
689 arizona_in_dmic_osr_text),
690 SOC_ENUM_SINGLE(ARIZONA_IN3L_CONTROL, ARIZONA_IN3_OSR_SHIFT,
691 ARRAY_SIZE(arizona_in_dmic_osr_text),
692 arizona_in_dmic_osr_text),
693 SOC_ENUM_SINGLE(ARIZONA_IN4L_CONTROL, ARIZONA_IN4_OSR_SHIFT,
694 ARRAY_SIZE(arizona_in_dmic_osr_text),
695 arizona_in_dmic_osr_text),
696};
697EXPORT_SYMBOL_GPL(arizona_in_dmic_osr);
698
Charles Keepaxd1901062015-11-19 16:11:10 +0000699static const char * const arizona_anc_input_src_text[] = {
700 "None", "IN1", "IN2", "IN3", "IN4",
701};
702
703static const char * const arizona_anc_channel_src_text[] = {
704 "None", "Left", "Right", "Combine",
705};
706
707const struct soc_enum arizona_anc_input_src[] = {
708 SOC_ENUM_SINGLE(ARIZONA_ANC_SRC,
709 ARIZONA_IN_RXANCL_SEL_SHIFT,
710 ARRAY_SIZE(arizona_anc_input_src_text),
711 arizona_anc_input_src_text),
712 SOC_ENUM_SINGLE(ARIZONA_FCL_ADC_REFORMATTER_CONTROL,
713 ARIZONA_FCL_MIC_MODE_SEL,
714 ARRAY_SIZE(arizona_anc_channel_src_text),
715 arizona_anc_channel_src_text),
716 SOC_ENUM_SINGLE(ARIZONA_ANC_SRC,
717 ARIZONA_IN_RXANCR_SEL_SHIFT,
718 ARRAY_SIZE(arizona_anc_input_src_text),
719 arizona_anc_input_src_text),
720 SOC_ENUM_SINGLE(ARIZONA_FCR_ADC_REFORMATTER_CONTROL,
721 ARIZONA_FCR_MIC_MODE_SEL,
722 ARRAY_SIZE(arizona_anc_channel_src_text),
723 arizona_anc_channel_src_text),
724};
725EXPORT_SYMBOL_GPL(arizona_anc_input_src);
726
727static const char * const arizona_anc_ng_texts[] = {
728 "None",
729 "Internal",
730 "External",
731};
732
733SOC_ENUM_SINGLE_DECL(arizona_anc_ng_enum, SND_SOC_NOPM, 0,
734 arizona_anc_ng_texts);
735EXPORT_SYMBOL_GPL(arizona_anc_ng_enum);
736
737static const char * const arizona_output_anc_src_text[] = {
738 "None", "RXANCL", "RXANCR",
739};
740
741const struct soc_enum arizona_output_anc_src[] = {
742 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L,
743 ARIZONA_OUT1L_ANC_SRC_SHIFT,
744 ARRAY_SIZE(arizona_output_anc_src_text),
745 arizona_output_anc_src_text),
746 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1R,
747 ARIZONA_OUT1R_ANC_SRC_SHIFT,
748 ARRAY_SIZE(arizona_output_anc_src_text),
749 arizona_output_anc_src_text),
750 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2L,
751 ARIZONA_OUT2L_ANC_SRC_SHIFT,
752 ARRAY_SIZE(arizona_output_anc_src_text),
753 arizona_output_anc_src_text),
754 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2R,
755 ARIZONA_OUT2R_ANC_SRC_SHIFT,
756 ARRAY_SIZE(arizona_output_anc_src_text),
757 arizona_output_anc_src_text),
758 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L,
759 ARIZONA_OUT3L_ANC_SRC_SHIFT,
760 ARRAY_SIZE(arizona_output_anc_src_text),
761 arizona_output_anc_src_text),
762 SOC_ENUM_SINGLE(ARIZONA_DAC_VOLUME_LIMIT_3R,
763 ARIZONA_OUT3R_ANC_SRC_SHIFT,
764 ARRAY_SIZE(arizona_output_anc_src_text),
765 arizona_output_anc_src_text),
766 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_4L,
767 ARIZONA_OUT4L_ANC_SRC_SHIFT,
768 ARRAY_SIZE(arizona_output_anc_src_text),
769 arizona_output_anc_src_text),
770 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_4R,
771 ARIZONA_OUT4R_ANC_SRC_SHIFT,
772 ARRAY_SIZE(arizona_output_anc_src_text),
773 arizona_output_anc_src_text),
774 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_5L,
775 ARIZONA_OUT5L_ANC_SRC_SHIFT,
776 ARRAY_SIZE(arizona_output_anc_src_text),
777 arizona_output_anc_src_text),
778 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_5R,
779 ARIZONA_OUT5R_ANC_SRC_SHIFT,
780 ARRAY_SIZE(arizona_output_anc_src_text),
781 arizona_output_anc_src_text),
782 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_6L,
783 ARIZONA_OUT6L_ANC_SRC_SHIFT,
784 ARRAY_SIZE(arizona_output_anc_src_text),
785 arizona_output_anc_src_text),
786 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_6R,
787 ARIZONA_OUT6R_ANC_SRC_SHIFT,
788 ARRAY_SIZE(arizona_output_anc_src_text),
789 arizona_output_anc_src_text),
790};
791EXPORT_SYMBOL_GPL(arizona_output_anc_src);
792
Charles Keepax97126ce2016-05-13 16:45:16 +0100793const struct snd_kcontrol_new arizona_voice_trigger_switch[] = {
794 SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0),
795 SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 1, 1, 0),
796 SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 2, 1, 0),
797 SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 3, 1, 0),
798};
799EXPORT_SYMBOL_GPL(arizona_voice_trigger_switch);
800
Mark Brownddbce972013-02-15 17:27:22 +0000801static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
802{
803 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
804 unsigned int val;
805 int i;
806
807 if (ena)
808 val = ARIZONA_IN_VU;
809 else
810 val = 0;
811
812 for (i = 0; i < priv->num_inputs; i++)
813 snd_soc_update_bits(codec,
814 ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 4),
815 ARIZONA_IN_VU, val);
816}
817
Charles Keepax002b0832015-09-16 13:59:41 +0100818bool arizona_input_analog(struct snd_soc_codec *codec, int shift)
819{
820 unsigned int reg = ARIZONA_IN1L_CONTROL + ((shift / 2) * 8);
821 unsigned int val = snd_soc_read(codec, reg);
822
823 return !(val & ARIZONA_IN1_MODE_MASK);
824}
825EXPORT_SYMBOL_GPL(arizona_input_analog);
826
Mark Brown07ed8732012-06-18 21:08:44 +0100827int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
828 int event)
829{
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100830 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
831 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000832 unsigned int reg;
833
834 if (w->shift % 2)
835 reg = ARIZONA_ADC_DIGITAL_VOLUME_1L + ((w->shift / 2) * 8);
836 else
837 reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8);
838
839 switch (event) {
Mark Brownddbce972013-02-15 17:27:22 +0000840 case SND_SOC_DAPM_PRE_PMU:
841 priv->in_pending++;
842 break;
Mark Brown43cd8bf2013-02-06 16:57:29 +0000843 case SND_SOC_DAPM_POST_PMU:
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100844 snd_soc_update_bits(codec, reg, ARIZONA_IN1L_MUTE, 0);
Mark Brownddbce972013-02-15 17:27:22 +0000845
846 /* If this is the last input pending then allow VU */
847 priv->in_pending--;
848 if (priv->in_pending == 0) {
849 msleep(1);
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100850 arizona_in_set_vu(codec, 1);
Mark Brownddbce972013-02-15 17:27:22 +0000851 }
Mark Brown43cd8bf2013-02-06 16:57:29 +0000852 break;
853 case SND_SOC_DAPM_PRE_PMD:
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100854 snd_soc_update_bits(codec, reg,
Mark Brownddbce972013-02-15 17:27:22 +0000855 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU,
856 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000857 break;
Mark Brownddbce972013-02-15 17:27:22 +0000858 case SND_SOC_DAPM_POST_PMD:
859 /* Disable volume updates if no inputs are enabled */
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100860 reg = snd_soc_read(codec, ARIZONA_INPUT_ENABLES);
Mark Brownddbce972013-02-15 17:27:22 +0000861 if (reg == 0)
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100862 arizona_in_set_vu(codec, 0);
Charles Keepaxbee261b2015-09-16 13:59:40 +0100863 break;
864 default:
865 break;
Mark Brown43cd8bf2013-02-06 16:57:29 +0000866 }
867
Mark Brown07ed8732012-06-18 21:08:44 +0100868 return 0;
869}
870EXPORT_SYMBOL_GPL(arizona_in_ev);
871
872int arizona_out_ev(struct snd_soc_dapm_widget *w,
873 struct snd_kcontrol *kcontrol,
874 int event)
875{
Mark Brown60d66c92015-01-27 23:50:47 +0000876 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
877 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Charles Keepax8c7788f2016-09-27 16:35:45 +0100878 struct arizona *arizona = priv->arizona;
Charles Keepax054e1b42015-01-20 16:31:50 +0000879
Mark Brown1a2c7d52013-03-24 22:50:23 +0000880 switch (event) {
Charles Keepaxe1ae5fb2015-01-20 16:31:51 +0000881 case SND_SOC_DAPM_PRE_PMU:
882 switch (w->shift) {
883 case ARIZONA_OUT1L_ENA_SHIFT:
884 case ARIZONA_OUT1R_ENA_SHIFT:
885 case ARIZONA_OUT2L_ENA_SHIFT:
886 case ARIZONA_OUT2R_ENA_SHIFT:
887 case ARIZONA_OUT3L_ENA_SHIFT:
888 case ARIZONA_OUT3R_ENA_SHIFT:
889 priv->out_up_pending++;
890 priv->out_up_delay += 17;
891 break;
Charles Keepax8c7788f2016-09-27 16:35:45 +0100892 case ARIZONA_OUT4L_ENA_SHIFT:
893 case ARIZONA_OUT4R_ENA_SHIFT:
894 priv->out_up_pending++;
895 switch (arizona->type) {
896 case WM5102:
897 case WM8997:
898 break;
899 default:
900 priv->out_up_delay += 10;
901 break;
902 }
903 break;
Charles Keepaxe1ae5fb2015-01-20 16:31:51 +0000904 default:
905 break;
906 }
907 break;
Mark Brown1a2c7d52013-03-24 22:50:23 +0000908 case SND_SOC_DAPM_POST_PMU:
909 switch (w->shift) {
910 case ARIZONA_OUT1L_ENA_SHIFT:
911 case ARIZONA_OUT1R_ENA_SHIFT:
912 case ARIZONA_OUT2L_ENA_SHIFT:
913 case ARIZONA_OUT2R_ENA_SHIFT:
914 case ARIZONA_OUT3L_ENA_SHIFT:
915 case ARIZONA_OUT3R_ENA_SHIFT:
Charles Keepax8c7788f2016-09-27 16:35:45 +0100916 case ARIZONA_OUT4L_ENA_SHIFT:
917 case ARIZONA_OUT4R_ENA_SHIFT:
Charles Keepaxe1ae5fb2015-01-20 16:31:51 +0000918 priv->out_up_pending--;
Charles Keepax8c7788f2016-09-27 16:35:45 +0100919 if (!priv->out_up_pending && priv->out_up_delay) {
Charles Keepaxd605bd02016-09-27 16:35:44 +0100920 dev_dbg(codec->dev, "Power up delay: %d\n",
921 priv->out_up_delay);
Charles Keepaxe1ae5fb2015-01-20 16:31:51 +0000922 msleep(priv->out_up_delay);
923 priv->out_up_delay = 0;
924 }
Mark Brown1a2c7d52013-03-24 22:50:23 +0000925 break;
926
927 default:
928 break;
929 }
930 break;
Charles Keepax054e1b42015-01-20 16:31:50 +0000931 case SND_SOC_DAPM_PRE_PMD:
932 switch (w->shift) {
933 case ARIZONA_OUT1L_ENA_SHIFT:
934 case ARIZONA_OUT1R_ENA_SHIFT:
935 case ARIZONA_OUT2L_ENA_SHIFT:
936 case ARIZONA_OUT2R_ENA_SHIFT:
937 case ARIZONA_OUT3L_ENA_SHIFT:
938 case ARIZONA_OUT3R_ENA_SHIFT:
939 priv->out_down_pending++;
940 priv->out_down_delay++;
941 break;
Charles Keepax8c7788f2016-09-27 16:35:45 +0100942 case ARIZONA_OUT4L_ENA_SHIFT:
943 case ARIZONA_OUT4R_ENA_SHIFT:
944 priv->out_down_pending++;
945 switch (arizona->type) {
946 case WM5102:
947 case WM8997:
948 break;
949 case WM8998:
950 case WM1814:
951 priv->out_down_delay += 5;
952 break;
953 default:
954 priv->out_down_delay++;
955 break;
956 }
Charles Keepax054e1b42015-01-20 16:31:50 +0000957 default:
958 break;
959 }
960 break;
961 case SND_SOC_DAPM_POST_PMD:
962 switch (w->shift) {
963 case ARIZONA_OUT1L_ENA_SHIFT:
964 case ARIZONA_OUT1R_ENA_SHIFT:
965 case ARIZONA_OUT2L_ENA_SHIFT:
966 case ARIZONA_OUT2R_ENA_SHIFT:
967 case ARIZONA_OUT3L_ENA_SHIFT:
968 case ARIZONA_OUT3R_ENA_SHIFT:
Charles Keepax8c7788f2016-09-27 16:35:45 +0100969 case ARIZONA_OUT4L_ENA_SHIFT:
970 case ARIZONA_OUT4R_ENA_SHIFT:
Charles Keepax054e1b42015-01-20 16:31:50 +0000971 priv->out_down_pending--;
Charles Keepax8c7788f2016-09-27 16:35:45 +0100972 if (!priv->out_down_pending && priv->out_down_delay) {
Charles Keepaxd605bd02016-09-27 16:35:44 +0100973 dev_dbg(codec->dev, "Power down delay: %d\n",
974 priv->out_down_delay);
Charles Keepax054e1b42015-01-20 16:31:50 +0000975 msleep(priv->out_down_delay);
976 priv->out_down_delay = 0;
977 }
978 break;
979 default:
980 break;
981 }
982 break;
Charles Keepaxbee261b2015-09-16 13:59:40 +0100983 default:
984 break;
Mark Brown1a2c7d52013-03-24 22:50:23 +0000985 }
986
Mark Brown07ed8732012-06-18 21:08:44 +0100987 return 0;
988}
989EXPORT_SYMBOL_GPL(arizona_out_ev);
990
Mark Brownf607e312013-02-22 18:36:53 +0000991int arizona_hp_ev(struct snd_soc_dapm_widget *w,
992 struct snd_kcontrol *kcontrol,
993 int event)
994{
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100995 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
996 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brown3c43c692013-12-12 00:49:22 +0000997 struct arizona *arizona = priv->arizona;
Mark Brownf607e312013-02-22 18:36:53 +0000998 unsigned int mask = 1 << w->shift;
999 unsigned int val;
1000
1001 switch (event) {
1002 case SND_SOC_DAPM_POST_PMU:
1003 val = mask;
1004 break;
1005 case SND_SOC_DAPM_PRE_PMD:
1006 val = 0;
1007 break;
Charles Keepaxe1ae5fb2015-01-20 16:31:51 +00001008 case SND_SOC_DAPM_PRE_PMU:
Charles Keepax054e1b42015-01-20 16:31:50 +00001009 case SND_SOC_DAPM_POST_PMD:
1010 return arizona_out_ev(w, kcontrol, event);
Mark Brownf607e312013-02-22 18:36:53 +00001011 default:
1012 return -EINVAL;
1013 }
1014
1015 /* Store the desired state for the HP outputs */
1016 priv->arizona->hp_ena &= ~mask;
1017 priv->arizona->hp_ena |= val;
1018
Charles Keepax112bdfa2015-02-16 15:41:02 +00001019 /* Force off if HPDET clamp is active */
1020 if (priv->arizona->hpdet_clamp)
Mark Brownf607e312013-02-22 18:36:53 +00001021 val = 0;
1022
Mark Brown3c43c692013-12-12 00:49:22 +00001023 regmap_update_bits_async(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1,
1024 mask, val);
Mark Brownf607e312013-02-22 18:36:53 +00001025
1026 return arizona_out_ev(w, kcontrol, event);
1027}
1028EXPORT_SYMBOL_GPL(arizona_hp_ev);
1029
Richard Fitzgerald346d9682015-06-02 11:53:33 +01001030static int arizona_dvfs_enable(struct snd_soc_codec *codec)
1031{
1032 const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1033 struct arizona *arizona = priv->arizona;
1034 int ret;
1035
1036 ret = regulator_set_voltage(arizona->dcvdd, 1800000, 1800000);
1037 if (ret) {
1038 dev_err(codec->dev, "Failed to boost DCVDD: %d\n", ret);
1039 return ret;
1040 }
1041
1042 ret = regmap_update_bits(arizona->regmap,
1043 ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
1044 ARIZONA_SUBSYS_MAX_FREQ,
1045 ARIZONA_SUBSYS_MAX_FREQ);
1046 if (ret) {
1047 dev_err(codec->dev, "Failed to enable subsys max: %d\n", ret);
1048 regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
1049 return ret;
1050 }
1051
1052 return 0;
1053}
1054
1055static int arizona_dvfs_disable(struct snd_soc_codec *codec)
1056{
1057 const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1058 struct arizona *arizona = priv->arizona;
1059 int ret;
1060
1061 ret = regmap_update_bits(arizona->regmap,
1062 ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
1063 ARIZONA_SUBSYS_MAX_FREQ, 0);
1064 if (ret) {
1065 dev_err(codec->dev, "Failed to disable subsys max: %d\n", ret);
1066 return ret;
1067 }
1068
1069 ret = regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
1070 if (ret) {
1071 dev_err(codec->dev, "Failed to unboost DCVDD: %d\n", ret);
1072 return ret;
1073 }
1074
1075 return 0;
1076}
1077
1078int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags)
1079{
1080 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1081 int ret = 0;
1082
1083 mutex_lock(&priv->dvfs_lock);
1084
1085 if (!priv->dvfs_cached && !priv->dvfs_reqs) {
1086 ret = arizona_dvfs_enable(codec);
1087 if (ret)
1088 goto err;
1089 }
1090
1091 priv->dvfs_reqs |= flags;
1092err:
1093 mutex_unlock(&priv->dvfs_lock);
1094 return ret;
1095}
1096EXPORT_SYMBOL_GPL(arizona_dvfs_up);
1097
1098int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags)
1099{
1100 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1101 unsigned int old_reqs;
1102 int ret = 0;
1103
1104 mutex_lock(&priv->dvfs_lock);
1105
1106 old_reqs = priv->dvfs_reqs;
1107 priv->dvfs_reqs &= ~flags;
1108
1109 if (!priv->dvfs_cached && old_reqs && !priv->dvfs_reqs)
1110 ret = arizona_dvfs_disable(codec);
1111
1112 mutex_unlock(&priv->dvfs_lock);
1113 return ret;
1114}
1115EXPORT_SYMBOL_GPL(arizona_dvfs_down);
1116
1117int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
1118 struct snd_kcontrol *kcontrol, int event)
1119{
1120 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
1121 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1122 int ret = 0;
1123
1124 mutex_lock(&priv->dvfs_lock);
1125
1126 switch (event) {
1127 case SND_SOC_DAPM_POST_PMU:
1128 if (priv->dvfs_reqs)
1129 ret = arizona_dvfs_enable(codec);
1130
1131 priv->dvfs_cached = false;
1132 break;
1133 case SND_SOC_DAPM_PRE_PMD:
1134 /* We must ensure DVFS is disabled before the codec goes into
1135 * suspend so that we are never in an illegal state of DVFS
1136 * enabled without enough DCVDD
1137 */
1138 priv->dvfs_cached = true;
1139
1140 if (priv->dvfs_reqs)
1141 ret = arizona_dvfs_disable(codec);
1142 break;
1143 default:
1144 break;
1145 }
1146
1147 mutex_unlock(&priv->dvfs_lock);
1148 return ret;
1149}
1150EXPORT_SYMBOL_GPL(arizona_dvfs_sysclk_ev);
1151
1152void arizona_init_dvfs(struct arizona_priv *priv)
1153{
1154 mutex_init(&priv->dvfs_lock);
1155}
1156EXPORT_SYMBOL_GPL(arizona_init_dvfs);
1157
Charles Keepaxd1901062015-11-19 16:11:10 +00001158int arizona_anc_ev(struct snd_soc_dapm_widget *w,
1159 struct snd_kcontrol *kcontrol,
1160 int event)
1161{
1162 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
Charles Keepaxd1901062015-11-19 16:11:10 +00001163 unsigned int val;
1164
1165 switch (event) {
1166 case SND_SOC_DAPM_POST_PMU:
1167 val = 1 << w->shift;
1168 break;
1169 case SND_SOC_DAPM_PRE_PMD:
1170 val = 1 << (w->shift + 1);
1171 break;
1172 default:
1173 return 0;
1174 }
1175
Richard Fitzgerald2ab8e742016-04-26 17:06:20 +01001176 snd_soc_write(codec, ARIZONA_CLOCK_CONTROL, val);
Charles Keepaxd1901062015-11-19 16:11:10 +00001177
1178 return 0;
1179}
1180EXPORT_SYMBOL_GPL(arizona_anc_ev);
1181
Richard Fitzgerald341604a2015-11-03 14:24:12 +00001182static unsigned int arizona_opclk_ref_48k_rates[] = {
Mark Browncbd840d2012-08-08 17:52:44 +01001183 6144000,
1184 12288000,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +00001185 24576000,
Mark Browncbd840d2012-08-08 17:52:44 +01001186 49152000,
1187};
1188
Richard Fitzgerald341604a2015-11-03 14:24:12 +00001189static unsigned int arizona_opclk_ref_44k1_rates[] = {
Mark Browncbd840d2012-08-08 17:52:44 +01001190 5644800,
1191 11289600,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +00001192 22579200,
Mark Browncbd840d2012-08-08 17:52:44 +01001193 45158400,
1194};
1195
1196static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
1197 unsigned int freq)
1198{
1199 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1200 unsigned int reg;
1201 unsigned int *rates;
1202 int ref, div, refclk;
1203
1204 switch (clk) {
1205 case ARIZONA_CLK_OPCLK:
1206 reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
1207 refclk = priv->sysclk;
1208 break;
1209 case ARIZONA_CLK_ASYNC_OPCLK:
1210 reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
1211 refclk = priv->asyncclk;
1212 break;
1213 default:
1214 return -EINVAL;
1215 }
1216
1217 if (refclk % 8000)
Richard Fitzgerald341604a2015-11-03 14:24:12 +00001218 rates = arizona_opclk_ref_44k1_rates;
Mark Browncbd840d2012-08-08 17:52:44 +01001219 else
Richard Fitzgerald341604a2015-11-03 14:24:12 +00001220 rates = arizona_opclk_ref_48k_rates;
Mark Browncbd840d2012-08-08 17:52:44 +01001221
Richard Fitzgerald341604a2015-11-03 14:24:12 +00001222 for (ref = 0; ref < ARRAY_SIZE(arizona_opclk_ref_48k_rates) &&
Mark Browncbd840d2012-08-08 17:52:44 +01001223 rates[ref] <= refclk; ref++) {
1224 div = 1;
1225 while (rates[ref] / div >= freq && div < 32) {
1226 if (rates[ref] / div == freq) {
1227 dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
1228 freq);
1229 snd_soc_update_bits(codec, reg,
1230 ARIZONA_OPCLK_DIV_MASK |
1231 ARIZONA_OPCLK_SEL_MASK,
1232 (div <<
1233 ARIZONA_OPCLK_DIV_SHIFT) |
1234 ref);
1235 return 0;
1236 }
1237 div++;
1238 }
1239 }
1240
1241 dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
1242 return -EINVAL;
1243}
1244
Charles Keepax7a4413d2016-10-21 14:15:57 +01001245int arizona_clk_ev(struct snd_soc_dapm_widget *w,
1246 struct snd_kcontrol *kcontrol, int event)
1247{
1248 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
1249 struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
1250 unsigned int val;
1251 int clk_idx;
1252 int ret;
1253
1254 ret = regmap_read(arizona->regmap, w->reg, &val);
1255 if (ret) {
1256 dev_err(codec->dev, "Failed to check clock source: %d\n", ret);
1257 return ret;
1258 }
1259
1260 val = (val & ARIZONA_SYSCLK_SRC_MASK) >> ARIZONA_SYSCLK_SRC_SHIFT;
1261
1262 switch (val) {
1263 case ARIZONA_CLK_SRC_MCLK1:
1264 clk_idx = ARIZONA_MCLK1;
1265 break;
1266 case ARIZONA_CLK_SRC_MCLK2:
1267 clk_idx = ARIZONA_MCLK2;
1268 break;
1269 default:
1270 return 0;
1271 }
1272
1273 switch (event) {
1274 case SND_SOC_DAPM_PRE_PMU:
1275 return clk_prepare_enable(arizona->mclk[clk_idx]);
1276 case SND_SOC_DAPM_POST_PMD:
1277 clk_disable_unprepare(arizona->mclk[clk_idx]);
1278 return 0;
1279 default:
1280 return 0;
1281 }
1282}
1283EXPORT_SYMBOL_GPL(arizona_clk_ev);
1284
Mark Brown07ed8732012-06-18 21:08:44 +01001285int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
1286 int source, unsigned int freq, int dir)
1287{
1288 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1289 struct arizona *arizona = priv->arizona;
1290 char *name;
1291 unsigned int reg;
1292 unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
1293 unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
Charles Keepax1f0e1ea2015-12-03 18:15:07 +00001294 int *clk;
Mark Brown07ed8732012-06-18 21:08:44 +01001295
1296 switch (clk_id) {
1297 case ARIZONA_CLK_SYSCLK:
1298 name = "SYSCLK";
1299 reg = ARIZONA_SYSTEM_CLOCK_1;
1300 clk = &priv->sysclk;
1301 mask |= ARIZONA_SYSCLK_FRAC;
1302 break;
1303 case ARIZONA_CLK_ASYNCCLK:
1304 name = "ASYNCCLK";
1305 reg = ARIZONA_ASYNC_CLOCK_1;
1306 clk = &priv->asyncclk;
1307 break;
Mark Browncbd840d2012-08-08 17:52:44 +01001308 case ARIZONA_CLK_OPCLK:
1309 case ARIZONA_CLK_ASYNC_OPCLK:
1310 return arizona_set_opclk(codec, clk_id, freq);
Mark Brown07ed8732012-06-18 21:08:44 +01001311 default:
1312 return -EINVAL;
1313 }
1314
1315 switch (freq) {
1316 case 5644800:
1317 case 6144000:
1318 break;
1319 case 11289600:
1320 case 12288000:
Mark Brown3f341f72013-03-08 15:22:29 +08001321 val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +01001322 break;
1323 case 22579200:
1324 case 24576000:
Mark Brown3f341f72013-03-08 15:22:29 +08001325 val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +01001326 break;
1327 case 45158400:
1328 case 49152000:
Mark Brown3f341f72013-03-08 15:22:29 +08001329 val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +01001330 break;
Mark Brown38113362012-11-26 16:01:37 +00001331 case 67737600:
1332 case 73728000:
Mark Brown3f341f72013-03-08 15:22:29 +08001333 val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +00001334 break;
1335 case 90316800:
1336 case 98304000:
Mark Brown3f341f72013-03-08 15:22:29 +08001337 val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +00001338 break;
1339 case 135475200:
1340 case 147456000:
Mark Brown3f341f72013-03-08 15:22:29 +08001341 val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +00001342 break;
Mark Brownf2c26d42013-01-21 16:09:36 +09001343 case 0:
1344 dev_dbg(arizona->dev, "%s cleared\n", name);
1345 *clk = freq;
1346 return 0;
Mark Brown07ed8732012-06-18 21:08:44 +01001347 default:
1348 return -EINVAL;
1349 }
1350
1351 *clk = freq;
1352
1353 if (freq % 6144000)
1354 val |= ARIZONA_SYSCLK_FRAC;
1355
1356 dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
1357
1358 return regmap_update_bits(arizona->regmap, reg, mask, val);
1359}
1360EXPORT_SYMBOL_GPL(arizona_set_sysclk);
1361
1362static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
1363{
1364 struct snd_soc_codec *codec = dai->codec;
Mark Brown3c43c692013-12-12 00:49:22 +00001365 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1366 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +01001367 int lrclk, bclk, mode, base;
1368
1369 base = dai->driver->base;
1370
1371 lrclk = 0;
1372 bclk = 0;
1373
1374 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
1375 case SND_SOC_DAIFMT_DSP_A:
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001376 mode = ARIZONA_FMT_DSP_MODE_A;
1377 break;
1378 case SND_SOC_DAIFMT_DSP_B:
1379 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
1380 != SND_SOC_DAIFMT_CBM_CFM) {
1381 arizona_aif_err(dai, "DSP_B not valid in slave mode\n");
1382 return -EINVAL;
1383 }
1384 mode = ARIZONA_FMT_DSP_MODE_B;
Mark Brown07ed8732012-06-18 21:08:44 +01001385 break;
Mark Brown07ed8732012-06-18 21:08:44 +01001386 case SND_SOC_DAIFMT_I2S:
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001387 mode = ARIZONA_FMT_I2S_MODE;
1388 break;
1389 case SND_SOC_DAIFMT_LEFT_J:
1390 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
1391 != SND_SOC_DAIFMT_CBM_CFM) {
1392 arizona_aif_err(dai, "LEFT_J not valid in slave mode\n");
1393 return -EINVAL;
1394 }
1395 mode = ARIZONA_FMT_LEFT_JUSTIFIED_MODE;
Mark Brown07ed8732012-06-18 21:08:44 +01001396 break;
Mark Brown07ed8732012-06-18 21:08:44 +01001397 default:
1398 arizona_aif_err(dai, "Unsupported DAI format %d\n",
1399 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
1400 return -EINVAL;
1401 }
1402
1403 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
1404 case SND_SOC_DAIFMT_CBS_CFS:
1405 break;
1406 case SND_SOC_DAIFMT_CBS_CFM:
1407 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
1408 break;
1409 case SND_SOC_DAIFMT_CBM_CFS:
1410 bclk |= ARIZONA_AIF1_BCLK_MSTR;
1411 break;
1412 case SND_SOC_DAIFMT_CBM_CFM:
1413 bclk |= ARIZONA_AIF1_BCLK_MSTR;
1414 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
1415 break;
1416 default:
1417 arizona_aif_err(dai, "Unsupported master mode %d\n",
1418 fmt & SND_SOC_DAIFMT_MASTER_MASK);
1419 return -EINVAL;
1420 }
1421
1422 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1423 case SND_SOC_DAIFMT_NB_NF:
1424 break;
1425 case SND_SOC_DAIFMT_IB_IF:
1426 bclk |= ARIZONA_AIF1_BCLK_INV;
1427 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
1428 break;
1429 case SND_SOC_DAIFMT_IB_NF:
1430 bclk |= ARIZONA_AIF1_BCLK_INV;
1431 break;
1432 case SND_SOC_DAIFMT_NB_IF:
1433 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
1434 break;
1435 default:
1436 return -EINVAL;
1437 }
1438
Mark Brown3c43c692013-12-12 00:49:22 +00001439 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_BCLK_CTRL,
1440 ARIZONA_AIF1_BCLK_INV |
1441 ARIZONA_AIF1_BCLK_MSTR,
1442 bclk);
1443 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_TX_PIN_CTRL,
1444 ARIZONA_AIF1TX_LRCLK_INV |
1445 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
1446 regmap_update_bits_async(arizona->regmap,
1447 base + ARIZONA_AIF_RX_PIN_CTRL,
1448 ARIZONA_AIF1RX_LRCLK_INV |
1449 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
1450 regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FORMAT,
1451 ARIZONA_AIF1_FMT_MASK, mode);
Mark Brown07ed8732012-06-18 21:08:44 +01001452
1453 return 0;
1454}
1455
Mark Brown949e6bc2012-07-04 18:58:04 +01001456static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001457 -1,
1458 48000,
1459 64000,
1460 96000,
1461 128000,
1462 192000,
1463 256000,
1464 384000,
1465 512000,
1466 768000,
1467 1024000,
1468 1536000,
1469 2048000,
1470 3072000,
1471 4096000,
1472 6144000,
1473 8192000,
1474 12288000,
1475 24576000,
1476};
1477
Mark Brown949e6bc2012-07-04 18:58:04 +01001478static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001479 -1,
1480 44100,
1481 58800,
1482 88200,
1483 117600,
1484 177640,
1485 235200,
1486 352800,
1487 470400,
1488 705600,
1489 940800,
1490 1411200,
1491 1881600,
Heather Lomond4758be32012-09-05 05:02:10 -04001492 2822400,
Mark Brown07ed8732012-06-18 21:08:44 +01001493 3763200,
1494 5644800,
1495 7526400,
1496 11289600,
1497 22579200,
1498};
1499
Charles Keepaxd81221f2016-02-04 16:29:01 +00001500static const unsigned int arizona_sr_vals[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001501 0,
1502 12000,
1503 24000,
1504 48000,
1505 96000,
1506 192000,
1507 384000,
1508 768000,
1509 0,
1510 11025,
1511 22050,
1512 44100,
1513 88200,
1514 176400,
1515 352800,
1516 705600,
1517 4000,
1518 8000,
1519 16000,
1520 32000,
1521 64000,
1522 128000,
1523 256000,
1524 512000,
1525};
1526
Charles Keepaxd81221f2016-02-04 16:29:01 +00001527#define ARIZONA_48K_RATE_MASK 0x0F003E
1528#define ARIZONA_44K1_RATE_MASK 0x003E00
1529#define ARIZONA_RATE_MASK (ARIZONA_48K_RATE_MASK | ARIZONA_44K1_RATE_MASK)
1530
1531static const struct snd_pcm_hw_constraint_list arizona_constraint = {
1532 .count = ARRAY_SIZE(arizona_sr_vals),
1533 .list = arizona_sr_vals,
1534};
1535
Mark Brown5b2eec32012-07-04 17:32:05 +01001536static int arizona_startup(struct snd_pcm_substream *substream,
1537 struct snd_soc_dai *dai)
1538{
1539 struct snd_soc_codec *codec = dai->codec;
1540 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1541 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown5b2eec32012-07-04 17:32:05 +01001542 unsigned int base_rate;
1543
Charles Keepax26eb5a92015-12-29 09:49:19 +00001544 if (!substream->runtime)
1545 return 0;
1546
Mark Brown5b2eec32012-07-04 17:32:05 +01001547 switch (dai_priv->clk) {
1548 case ARIZONA_CLK_SYSCLK:
1549 base_rate = priv->sysclk;
1550 break;
1551 case ARIZONA_CLK_ASYNCCLK:
1552 base_rate = priv->asyncclk;
1553 break;
1554 default:
1555 return 0;
1556 }
1557
Mark Brownf2c26d42013-01-21 16:09:36 +09001558 if (base_rate == 0)
Charles Keepaxd81221f2016-02-04 16:29:01 +00001559 dai_priv->constraint.mask = ARIZONA_RATE_MASK;
1560 else if (base_rate % 8000)
1561 dai_priv->constraint.mask = ARIZONA_44K1_RATE_MASK;
Mark Brown5b2eec32012-07-04 17:32:05 +01001562 else
Charles Keepaxd81221f2016-02-04 16:29:01 +00001563 dai_priv->constraint.mask = ARIZONA_48K_RATE_MASK;
Mark Brown5b2eec32012-07-04 17:32:05 +01001564
1565 return snd_pcm_hw_constraint_list(substream->runtime, 0,
1566 SNDRV_PCM_HW_PARAM_RATE,
Charles Keepaxd81221f2016-02-04 16:29:01 +00001567 &dai_priv->constraint);
Mark Brown5b2eec32012-07-04 17:32:05 +01001568}
1569
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001570static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec,
1571 unsigned int rate)
1572{
1573 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1574 struct arizona *arizona = priv->arizona;
Nariman Poushin8019ff62015-07-16 16:36:21 +01001575 struct reg_sequence dac_comp[] = {
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001576 { 0x80, 0x3 },
1577 { ARIZONA_DAC_COMP_1, 0 },
1578 { ARIZONA_DAC_COMP_2, 0 },
1579 { 0x80, 0x0 },
1580 };
1581
Lars-Peter Clausend74bcaa2014-11-09 17:00:59 +01001582 mutex_lock(&arizona->dac_comp_lock);
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001583
1584 dac_comp[1].def = arizona->dac_comp_coeff;
1585 if (rate >= 176400)
1586 dac_comp[2].def = arizona->dac_comp_enabled;
1587
Lars-Peter Clausend74bcaa2014-11-09 17:00:59 +01001588 mutex_unlock(&arizona->dac_comp_lock);
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001589
1590 regmap_multi_reg_write(arizona->regmap,
1591 dac_comp,
1592 ARRAY_SIZE(dac_comp));
1593}
1594
Mark Brownb272efc2012-10-10 15:10:08 +09001595static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
1596 struct snd_pcm_hw_params *params,
1597 struct snd_soc_dai *dai)
Mark Brown07ed8732012-06-18 21:08:44 +01001598{
1599 struct snd_soc_codec *codec = dai->codec;
Mark Brownc013b272012-07-04 20:05:57 +01001600 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1601 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown07ed8732012-06-18 21:08:44 +01001602 int base = dai->driver->base;
Richard Fitzgerald2c118b42015-06-02 11:53:35 +01001603 int i, sr_val, ret;
Mark Brownb272efc2012-10-10 15:10:08 +09001604
1605 /*
1606 * We will need to be more flexible than this in future,
1607 * currently we use a single sample rate for SYSCLK.
1608 */
1609 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
1610 if (arizona_sr_vals[i] == params_rate(params))
1611 break;
1612 if (i == ARRAY_SIZE(arizona_sr_vals)) {
1613 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1614 params_rate(params));
1615 return -EINVAL;
1616 }
1617 sr_val = i;
1618
Richard Fitzgerald2c118b42015-06-02 11:53:35 +01001619 switch (priv->arizona->type) {
1620 case WM5102:
1621 case WM8997:
1622 if (arizona_sr_vals[sr_val] >= 88200)
1623 ret = arizona_dvfs_up(codec, ARIZONA_DVFS_SR1_RQ);
1624 else
1625 ret = arizona_dvfs_down(codec, ARIZONA_DVFS_SR1_RQ);
1626
1627 if (ret) {
1628 arizona_aif_err(dai, "Failed to change DVFS %d\n", ret);
1629 return ret;
1630 }
1631 break;
1632 default:
1633 break;
1634 }
1635
Mark Brownb272efc2012-10-10 15:10:08 +09001636 switch (dai_priv->clk) {
1637 case ARIZONA_CLK_SYSCLK:
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001638 switch (priv->arizona->type) {
1639 case WM5102:
1640 arizona_wm5102_set_dac_comp(codec,
1641 params_rate(params));
1642 break;
1643 default:
1644 break;
1645 }
1646
Mark Brownb272efc2012-10-10 15:10:08 +09001647 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
1648 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
1649 if (base)
1650 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1651 ARIZONA_AIF1_RATE_MASK, 0);
1652 break;
1653 case ARIZONA_CLK_ASYNCCLK:
1654 snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
Charles Keepaxc24084d2014-09-01 15:48:52 +01001655 ARIZONA_ASYNC_SAMPLE_RATE_1_MASK, sr_val);
Mark Brownb272efc2012-10-10 15:10:08 +09001656 if (base)
1657 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1658 ARIZONA_AIF1_RATE_MASK,
1659 8 << ARIZONA_AIF1_RATE_SHIFT);
1660 break;
1661 default:
1662 arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
1663 return -EINVAL;
1664 }
1665
1666 return 0;
1667}
1668
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001669static bool arizona_aif_cfg_changed(struct snd_soc_codec *codec,
1670 int base, int bclk, int lrclk, int frame)
1671{
1672 int val;
1673
1674 val = snd_soc_read(codec, base + ARIZONA_AIF_BCLK_CTRL);
1675 if (bclk != (val & ARIZONA_AIF1_BCLK_FREQ_MASK))
1676 return true;
1677
1678 val = snd_soc_read(codec, base + ARIZONA_AIF_TX_BCLK_RATE);
1679 if (lrclk != (val & ARIZONA_AIF1TX_BCPF_MASK))
1680 return true;
1681
1682 val = snd_soc_read(codec, base + ARIZONA_AIF_FRAME_CTRL_1);
1683 if (frame != (val & (ARIZONA_AIF1TX_WL_MASK |
1684 ARIZONA_AIF1TX_SLOT_LEN_MASK)))
1685 return true;
1686
1687 return false;
1688}
1689
Mark Brown07ed8732012-06-18 21:08:44 +01001690static int arizona_hw_params(struct snd_pcm_substream *substream,
1691 struct snd_pcm_hw_params *params,
1692 struct snd_soc_dai *dai)
1693{
1694 struct snd_soc_codec *codec = dai->codec;
1695 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brownc94aa302013-01-17 16:35:14 +09001696 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +01001697 int base = dai->driver->base;
1698 const int *rates;
Mark Brown76bf9692013-03-05 14:17:47 +08001699 int i, ret, val;
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001700 int channels = params_channels(params);
Mark Brownc94aa302013-01-17 16:35:14 +09001701 int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001702 int tdm_width = arizona->tdm_width[dai->id - 1];
1703 int tdm_slots = arizona->tdm_slots[dai->id - 1];
Mark Brownc94aa302013-01-17 16:35:14 +09001704 int bclk, lrclk, wl, frame, bclk_target;
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001705 bool reconfig;
1706 unsigned int aif_tx_state, aif_rx_state;
Mark Brown07ed8732012-06-18 21:08:44 +01001707
Nikesh Oswale73694d2015-12-23 14:18:05 +00001708 if (params_rate(params) % 4000)
Mark Brown949e6bc2012-07-04 18:58:04 +01001709 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001710 else
Mark Brown949e6bc2012-07-04 18:58:04 +01001711 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001712
Charles Keepax5ed68f02015-07-09 11:28:46 +01001713 wl = params_width(params);
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001714
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001715 if (tdm_slots) {
1716 arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n",
1717 tdm_slots, tdm_width);
1718 bclk_target = tdm_slots * tdm_width * params_rate(params);
1719 channels = tdm_slots;
1720 } else {
1721 bclk_target = snd_soc_params_to_bclk(params);
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001722 tdm_width = wl;
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001723 }
1724
1725 if (chan_limit && chan_limit < channels) {
Mark Brownc94aa302013-01-17 16:35:14 +09001726 arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001727 bclk_target /= channels;
Mark Brownc94aa302013-01-17 16:35:14 +09001728 bclk_target *= chan_limit;
1729 }
1730
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001731 /* Force multiple of 2 channels for I2S mode */
Mark Brown76bf9692013-03-05 14:17:47 +08001732 val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001733 val &= ARIZONA_AIF1_FMT_MASK;
1734 if ((channels & 1) && (val == ARIZONA_FMT_I2S_MODE)) {
Mark Brown76bf9692013-03-05 14:17:47 +08001735 arizona_aif_dbg(dai, "Forcing stereo mode\n");
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001736 bclk_target /= channels;
1737 bclk_target *= channels + 1;
Mark Brown76bf9692013-03-05 14:17:47 +08001738 }
1739
Mark Brown949e6bc2012-07-04 18:58:04 +01001740 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brownc94aa302013-01-17 16:35:14 +09001741 if (rates[i] >= bclk_target &&
Mark Brown50017652012-07-04 19:07:09 +01001742 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +01001743 bclk = i;
1744 break;
1745 }
1746 }
Mark Brown949e6bc2012-07-04 18:58:04 +01001747 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001748 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1749 params_rate(params));
1750 return -EINVAL;
1751 }
1752
Mark Brownb59e0f82013-01-17 14:15:59 +09001753 lrclk = rates[bclk] / params_rate(params);
Mark Brown07ed8732012-06-18 21:08:44 +01001754
1755 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
1756 rates[bclk], rates[bclk] / lrclk);
1757
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001758 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | tdm_width;
Mark Brown07ed8732012-06-18 21:08:44 +01001759
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001760 reconfig = arizona_aif_cfg_changed(codec, base, bclk, lrclk, frame);
1761
1762 if (reconfig) {
1763 /* Save AIF TX/RX state */
1764 aif_tx_state = snd_soc_read(codec,
1765 base + ARIZONA_AIF_TX_ENABLES);
1766 aif_rx_state = snd_soc_read(codec,
1767 base + ARIZONA_AIF_RX_ENABLES);
1768 /* Disable AIF TX/RX before reconfiguring it */
1769 regmap_update_bits_async(arizona->regmap,
1770 base + ARIZONA_AIF_TX_ENABLES, 0xff, 0x0);
1771 regmap_update_bits(arizona->regmap,
1772 base + ARIZONA_AIF_RX_ENABLES, 0xff, 0x0);
1773 }
1774
Mark Brownb272efc2012-10-10 15:10:08 +09001775 ret = arizona_hw_params_rate(substream, params, dai);
1776 if (ret != 0)
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001777 goto restore_aif;
Mark Brownc013b272012-07-04 20:05:57 +01001778
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001779 if (reconfig) {
1780 regmap_update_bits_async(arizona->regmap,
1781 base + ARIZONA_AIF_BCLK_CTRL,
1782 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
1783 regmap_update_bits_async(arizona->regmap,
1784 base + ARIZONA_AIF_TX_BCLK_RATE,
1785 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
1786 regmap_update_bits_async(arizona->regmap,
1787 base + ARIZONA_AIF_RX_BCLK_RATE,
1788 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
1789 regmap_update_bits_async(arizona->regmap,
1790 base + ARIZONA_AIF_FRAME_CTRL_1,
1791 ARIZONA_AIF1TX_WL_MASK |
1792 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
1793 regmap_update_bits(arizona->regmap,
1794 base + ARIZONA_AIF_FRAME_CTRL_2,
1795 ARIZONA_AIF1RX_WL_MASK |
1796 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
1797 }
Mark Brown07ed8732012-06-18 21:08:44 +01001798
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001799restore_aif:
1800 if (reconfig) {
1801 /* Restore AIF TX/RX state */
1802 regmap_update_bits_async(arizona->regmap,
1803 base + ARIZONA_AIF_TX_ENABLES,
1804 0xff, aif_tx_state);
1805 regmap_update_bits(arizona->regmap,
1806 base + ARIZONA_AIF_RX_ENABLES,
1807 0xff, aif_rx_state);
1808 }
1809 return ret;
Mark Brown07ed8732012-06-18 21:08:44 +01001810}
1811
Mark Brown410837a2012-07-05 17:26:59 +01001812static const char *arizona_dai_clk_str(int clk_id)
1813{
1814 switch (clk_id) {
1815 case ARIZONA_CLK_SYSCLK:
1816 return "SYSCLK";
1817 case ARIZONA_CLK_ASYNCCLK:
1818 return "ASYNCCLK";
1819 default:
1820 return "Unknown clock";
1821 }
1822}
1823
Mark Brown5b2eec32012-07-04 17:32:05 +01001824static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
1825 int clk_id, unsigned int freq, int dir)
1826{
1827 struct snd_soc_codec *codec = dai->codec;
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +02001828 struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
Mark Brown5b2eec32012-07-04 17:32:05 +01001829 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1830 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown410837a2012-07-05 17:26:59 +01001831 struct snd_soc_dapm_route routes[2];
Mark Brown5b2eec32012-07-04 17:32:05 +01001832
1833 switch (clk_id) {
1834 case ARIZONA_CLK_SYSCLK:
1835 case ARIZONA_CLK_ASYNCCLK:
1836 break;
1837 default:
1838 return -EINVAL;
1839 }
1840
Mark Brown410837a2012-07-05 17:26:59 +01001841 if (clk_id == dai_priv->clk)
1842 return 0;
1843
1844 if (dai->active) {
Mark Brown5b2eec32012-07-04 17:32:05 +01001845 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
1846 dai->id);
1847 return -EBUSY;
1848 }
1849
Mark Brownc8d35a62012-12-07 12:49:40 +09001850 dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1,
1851 arizona_dai_clk_str(clk_id));
1852
Mark Brown410837a2012-07-05 17:26:59 +01001853 memset(&routes, 0, sizeof(routes));
1854 routes[0].sink = dai->driver->capture.stream_name;
1855 routes[1].sink = dai->driver->playback.stream_name;
Mark Brown5b2eec32012-07-04 17:32:05 +01001856
Mark Brown410837a2012-07-05 17:26:59 +01001857 routes[0].source = arizona_dai_clk_str(dai_priv->clk);
1858 routes[1].source = arizona_dai_clk_str(dai_priv->clk);
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +02001859 snd_soc_dapm_del_routes(dapm, routes, ARRAY_SIZE(routes));
Mark Brown410837a2012-07-05 17:26:59 +01001860
1861 routes[0].source = arizona_dai_clk_str(clk_id);
1862 routes[1].source = arizona_dai_clk_str(clk_id);
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +02001863 snd_soc_dapm_add_routes(dapm, routes, ARRAY_SIZE(routes));
Mark Brown410837a2012-07-05 17:26:59 +01001864
Mark Brown0c778e82012-12-06 18:22:25 +09001865 dai_priv->clk = clk_id;
1866
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +02001867 return snd_soc_dapm_sync(dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +01001868}
1869
Mark Brown01df2592012-12-12 16:22:08 +09001870static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
1871{
1872 struct snd_soc_codec *codec = dai->codec;
1873 int base = dai->driver->base;
1874 unsigned int reg;
1875
1876 if (tristate)
1877 reg = ARIZONA_AIF1_TRI;
1878 else
1879 reg = 0;
1880
1881 return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1882 ARIZONA_AIF1_TRI, reg);
1883}
1884
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001885static void arizona_set_channels_to_mask(struct snd_soc_dai *dai,
1886 unsigned int base,
1887 int channels, unsigned int mask)
1888{
1889 struct snd_soc_codec *codec = dai->codec;
1890 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1891 struct arizona *arizona = priv->arizona;
1892 int slot, i;
1893
1894 for (i = 0; i < channels; ++i) {
1895 slot = ffs(mask) - 1;
1896 if (slot < 0)
1897 return;
1898
1899 regmap_write(arizona->regmap, base + i, slot);
1900
1901 mask &= ~(1 << slot);
1902 }
1903
1904 if (mask)
1905 arizona_aif_warn(dai, "Too many channels in TDM mask\n");
1906}
1907
1908static int arizona_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
1909 unsigned int rx_mask, int slots, int slot_width)
1910{
1911 struct snd_soc_codec *codec = dai->codec;
1912 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1913 struct arizona *arizona = priv->arizona;
1914 int base = dai->driver->base;
1915 int rx_max_chan = dai->driver->playback.channels_max;
1916 int tx_max_chan = dai->driver->capture.channels_max;
1917
1918 /* Only support TDM for the physical AIFs */
1919 if (dai->id > ARIZONA_MAX_AIF)
1920 return -ENOTSUPP;
1921
1922 if (slots == 0) {
1923 tx_mask = (1 << tx_max_chan) - 1;
1924 rx_mask = (1 << rx_max_chan) - 1;
1925 }
1926
1927 arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_3,
1928 tx_max_chan, tx_mask);
1929 arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_11,
1930 rx_max_chan, rx_mask);
1931
1932 arizona->tdm_width[dai->id - 1] = slot_width;
1933 arizona->tdm_slots[dai->id - 1] = slots;
1934
1935 return 0;
1936}
1937
Mark Brown07ed8732012-06-18 21:08:44 +01001938const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +01001939 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +01001940 .set_fmt = arizona_set_fmt,
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001941 .set_tdm_slot = arizona_set_tdm_slot,
Mark Brown07ed8732012-06-18 21:08:44 +01001942 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +01001943 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown01df2592012-12-12 16:22:08 +09001944 .set_tristate = arizona_set_tristate,
Mark Brown07ed8732012-06-18 21:08:44 +01001945};
Mark Browna8379872012-07-09 12:16:41 +01001946EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +01001947
Mark Brownbd1dd882013-05-17 13:29:03 +01001948const struct snd_soc_dai_ops arizona_simple_dai_ops = {
1949 .startup = arizona_startup,
1950 .hw_params = arizona_hw_params_rate,
1951 .set_sysclk = arizona_dai_set_sysclk,
1952};
1953EXPORT_SYMBOL_GPL(arizona_simple_dai_ops);
1954
Mark Brown5b2eec32012-07-04 17:32:05 +01001955int arizona_init_dai(struct arizona_priv *priv, int id)
1956{
1957 struct arizona_dai_priv *dai_priv = &priv->dai[id];
1958
1959 dai_priv->clk = ARIZONA_CLK_SYSCLK;
Charles Keepaxd81221f2016-02-04 16:29:01 +00001960 dai_priv->constraint = arizona_constraint;
Mark Brown5b2eec32012-07-04 17:32:05 +01001961
1962 return 0;
1963}
1964EXPORT_SYMBOL_GPL(arizona_init_dai);
1965
Mark Brown07ed8732012-06-18 21:08:44 +01001966static struct {
1967 unsigned int min;
1968 unsigned int max;
1969 u16 fratio;
1970 int ratio;
1971} fll_fratios[] = {
1972 { 0, 64000, 4, 16 },
1973 { 64000, 128000, 3, 8 },
1974 { 128000, 256000, 2, 4 },
1975 { 256000, 1000000, 1, 2 },
1976 { 1000000, 13500000, 0, 1 },
1977};
1978
Richard Fitzgerald01582a82016-02-10 11:56:13 +00001979static const unsigned int pseudo_fref_max[ARIZONA_FLL_MAX_FRATIO] = {
1980 13500000,
1981 6144000,
1982 6144000,
1983 3072000,
1984 3072000,
1985 2822400,
1986 2822400,
1987 1536000,
1988 1536000,
1989 1536000,
1990 1536000,
1991 1536000,
1992 1536000,
1993 1536000,
1994 1536000,
1995 768000,
1996};
1997
Mark Brown8f113d72013-03-05 12:08:57 +08001998static struct {
1999 unsigned int min;
2000 unsigned int max;
2001 u16 gain;
2002} fll_gains[] = {
2003 { 0, 256000, 0 },
2004 { 256000, 1000000, 2 },
2005 { 1000000, 13500000, 4 },
2006};
2007
Mark Brown07ed8732012-06-18 21:08:44 +01002008struct arizona_fll_cfg {
2009 int n;
Charles Keepaxe87d9ae82016-09-02 16:52:43 +01002010 unsigned int theta;
2011 unsigned int lambda;
Mark Brown07ed8732012-06-18 21:08:44 +01002012 int refdiv;
2013 int outdiv;
2014 int fratio;
Mark Brown8f113d72013-03-05 12:08:57 +08002015 int gain;
Mark Brown07ed8732012-06-18 21:08:44 +01002016};
2017
Charles Keepax23f785a82014-03-07 16:34:20 +00002018static int arizona_validate_fll(struct arizona_fll *fll,
2019 unsigned int Fref,
2020 unsigned int Fout)
2021{
2022 unsigned int Fvco_min;
2023
Charles Keepaxc8badda2014-07-09 17:41:49 +01002024 if (fll->fout && Fout != fll->fout) {
2025 arizona_fll_err(fll,
2026 "Can't change output on active FLL\n");
2027 return -EINVAL;
2028 }
2029
Charles Keepax23f785a82014-03-07 16:34:20 +00002030 if (Fref / ARIZONA_FLL_MAX_REFDIV > ARIZONA_FLL_MAX_FREF) {
2031 arizona_fll_err(fll,
2032 "Can't scale %dMHz in to <=13.5MHz\n",
2033 Fref);
2034 return -EINVAL;
2035 }
2036
2037 Fvco_min = ARIZONA_FLL_MIN_FVCO * fll->vco_mult;
2038 if (Fout * ARIZONA_FLL_MAX_OUTDIV < Fvco_min) {
2039 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
2040 Fout);
2041 return -EINVAL;
2042 }
2043
2044 return 0;
2045}
2046
Charles Keepaxd0800342014-03-07 16:34:25 +00002047static int arizona_find_fratio(unsigned int Fref, int *fratio)
2048{
2049 int i;
2050
2051 /* Find an appropriate FLL_FRATIO */
2052 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
2053 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
2054 if (fratio)
2055 *fratio = fll_fratios[i].fratio;
2056 return fll_fratios[i].ratio;
2057 }
2058 }
2059
2060 return -EINVAL;
2061}
2062
2063static int arizona_calc_fratio(struct arizona_fll *fll,
2064 struct arizona_fll_cfg *cfg,
2065 unsigned int target,
2066 unsigned int Fref, bool sync)
2067{
2068 int init_ratio, ratio;
2069 int refdiv, div;
2070
2071 /* Fref must be <=13.5MHz, find initial refdiv */
2072 div = 1;
2073 cfg->refdiv = 0;
2074 while (Fref > ARIZONA_FLL_MAX_FREF) {
2075 div *= 2;
2076 Fref /= 2;
2077 cfg->refdiv++;
2078
2079 if (div > ARIZONA_FLL_MAX_REFDIV)
2080 return -EINVAL;
2081 }
2082
2083 /* Find an appropriate FLL_FRATIO */
2084 init_ratio = arizona_find_fratio(Fref, &cfg->fratio);
2085 if (init_ratio < 0) {
2086 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
2087 Fref);
2088 return init_ratio;
2089 }
2090
2091 switch (fll->arizona->type) {
Richard Fitzgerald3451eb42015-12-16 17:06:24 +00002092 case WM5102:
2093 case WM8997:
2094 return init_ratio;
Charles Keepaxd0800342014-03-07 16:34:25 +00002095 case WM5110:
Richard Fitzgerald575ef7f2015-01-17 15:21:27 +00002096 case WM8280:
Charles Keepaxd0800342014-03-07 16:34:25 +00002097 if (fll->arizona->rev < 3 || sync)
2098 return init_ratio;
2099 break;
Richard Fitzgerald3451eb42015-12-16 17:06:24 +00002100 default:
Richard Fitzgerald6ebbce02015-09-28 14:01:09 +01002101 if (sync)
2102 return init_ratio;
2103 break;
Charles Keepaxd0800342014-03-07 16:34:25 +00002104 }
2105
2106 cfg->fratio = init_ratio - 1;
2107
2108 /* Adjust FRATIO/refdiv to avoid integer mode if possible */
2109 refdiv = cfg->refdiv;
2110
Richard Fitzgerald01582a82016-02-10 11:56:13 +00002111 arizona_fll_dbg(fll, "pseudo: initial ratio=%u fref=%u refdiv=%u\n",
2112 init_ratio, Fref, refdiv);
2113
Charles Keepaxd0800342014-03-07 16:34:25 +00002114 while (div <= ARIZONA_FLL_MAX_REFDIV) {
Richard Fitzgerald8e42db12016-04-21 14:04:14 +01002115 /* start from init_ratio because this may already give a
2116 * fractional N.K
2117 */
2118 for (ratio = init_ratio; ratio > 0; ratio--) {
2119 if (target % (ratio * Fref)) {
2120 cfg->refdiv = refdiv;
2121 cfg->fratio = ratio - 1;
2122 arizona_fll_dbg(fll,
2123 "pseudo: found fref=%u refdiv=%d(%d) ratio=%d\n",
2124 Fref, refdiv, div, ratio);
2125 return ratio;
2126 }
2127 }
2128
2129 for (ratio = init_ratio + 1; ratio <= ARIZONA_FLL_MAX_FRATIO;
Charles Keepaxd0800342014-03-07 16:34:25 +00002130 ratio++) {
Charles Keepax35a730a2014-07-09 17:41:45 +01002131 if ((ARIZONA_FLL_VCO_CORNER / 2) /
Richard Fitzgerald01582a82016-02-10 11:56:13 +00002132 (fll->vco_mult * ratio) < Fref) {
2133 arizona_fll_dbg(fll, "pseudo: hit VCO corner\n");
Charles Keepax29fee822014-07-09 17:41:44 +01002134 break;
Richard Fitzgerald01582a82016-02-10 11:56:13 +00002135 }
2136
2137 if (Fref > pseudo_fref_max[ratio - 1]) {
2138 arizona_fll_dbg(fll,
2139 "pseudo: exceeded max fref(%u) for ratio=%u\n",
2140 pseudo_fref_max[ratio - 1],
2141 ratio);
2142 break;
2143 }
Charles Keepax29fee822014-07-09 17:41:44 +01002144
Charles Keepaxd0800342014-03-07 16:34:25 +00002145 if (target % (ratio * Fref)) {
2146 cfg->refdiv = refdiv;
2147 cfg->fratio = ratio - 1;
Richard Fitzgerald01582a82016-02-10 11:56:13 +00002148 arizona_fll_dbg(fll,
2149 "pseudo: found fref=%u refdiv=%d(%d) ratio=%d\n",
2150 Fref, refdiv, div, ratio);
Charles Keepaxd0800342014-03-07 16:34:25 +00002151 return ratio;
2152 }
2153 }
2154
Charles Keepaxd0800342014-03-07 16:34:25 +00002155 div *= 2;
2156 Fref /= 2;
2157 refdiv++;
2158 init_ratio = arizona_find_fratio(Fref, NULL);
Richard Fitzgerald01582a82016-02-10 11:56:13 +00002159 arizona_fll_dbg(fll,
2160 "pseudo: change fref=%u refdiv=%d(%d) ratio=%u\n",
2161 Fref, refdiv, div, init_ratio);
Charles Keepaxd0800342014-03-07 16:34:25 +00002162 }
2163
2164 arizona_fll_warn(fll, "Falling back to integer mode operation\n");
2165 return cfg->fratio + 1;
2166}
2167
Mark Brown07ed8732012-06-18 21:08:44 +01002168static int arizona_calc_fll(struct arizona_fll *fll,
2169 struct arizona_fll_cfg *cfg,
Charles Keepaxd0800342014-03-07 16:34:25 +00002170 unsigned int Fref, bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01002171{
2172 unsigned int target, div, gcd_fll;
2173 int i, ratio;
2174
Charles Keepax8ccefcd2014-03-07 16:34:21 +00002175 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, fll->fout);
Mark Brown07ed8732012-06-18 21:08:44 +01002176
Mark Brown2b4d39f2012-07-10 17:03:46 +01002177 /* Fvco should be over the targt; don't check the upper bound */
Charles Keepaxf641aec2014-03-07 16:34:22 +00002178 div = ARIZONA_FLL_MIN_OUTDIV;
2179 while (fll->fout * div < ARIZONA_FLL_MIN_FVCO * fll->vco_mult) {
Mark Brown07ed8732012-06-18 21:08:44 +01002180 div++;
Charles Keepaxf641aec2014-03-07 16:34:22 +00002181 if (div > ARIZONA_FLL_MAX_OUTDIV)
Mark Brown07ed8732012-06-18 21:08:44 +01002182 return -EINVAL;
Mark Brown07ed8732012-06-18 21:08:44 +01002183 }
Charles Keepaxf641aec2014-03-07 16:34:22 +00002184 target = fll->fout * div / fll->vco_mult;
Mark Brown07ed8732012-06-18 21:08:44 +01002185 cfg->outdiv = div;
2186
2187 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
2188
Charles Keepaxd0800342014-03-07 16:34:25 +00002189 /* Find an appropriate FLL_FRATIO and refdiv */
2190 ratio = arizona_calc_fratio(fll, cfg, target, Fref, sync);
2191 if (ratio < 0)
2192 return ratio;
Mark Brown07ed8732012-06-18 21:08:44 +01002193
Mark Brown07ed8732012-06-18 21:08:44 +01002194 /* Apply the division for our remaining calculations */
Charles Keepaxd0800342014-03-07 16:34:25 +00002195 Fref = Fref / (1 << cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08002196
Mark Brown07ed8732012-06-18 21:08:44 +01002197 cfg->n = target / (ratio * Fref);
2198
Ryo Tsutsui01f58152013-02-03 17:18:00 +09002199 if (target % (ratio * Fref)) {
Mark Brown07ed8732012-06-18 21:08:44 +01002200 gcd_fll = gcd(target, ratio * Fref);
2201 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
2202
2203 cfg->theta = (target - (cfg->n * ratio * Fref))
2204 / gcd_fll;
2205 cfg->lambda = (ratio * Fref) / gcd_fll;
2206 } else {
2207 cfg->theta = 0;
2208 cfg->lambda = 0;
2209 }
2210
Ryo Tsutsui01f58152013-02-03 17:18:00 +09002211 /* Round down to 16bit range with cost of accuracy lost.
2212 * Denominator must be bigger than numerator so we only
2213 * take care of it.
2214 */
2215 while (cfg->lambda >= (1 << 16)) {
2216 cfg->theta >>= 1;
2217 cfg->lambda >>= 1;
2218 }
2219
Charles Keepax5a3935c2014-03-07 16:34:23 +00002220 for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
2221 if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
2222 cfg->gain = fll_gains[i].gain;
2223 break;
2224 }
2225 }
2226 if (i == ARRAY_SIZE(fll_gains)) {
2227 arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
2228 Fref);
2229 return -EINVAL;
2230 }
2231
Richard Fitzgerald2595b7f2016-02-23 14:16:32 +00002232 arizona_fll_dbg(fll, "N=%d THETA=%d LAMBDA=%d\n",
Mark Brown07ed8732012-06-18 21:08:44 +01002233 cfg->n, cfg->theta, cfg->lambda);
Richard Fitzgerald2595b7f2016-02-23 14:16:32 +00002234 arizona_fll_dbg(fll, "FRATIO=0x%x(%d) OUTDIV=%d REFCLK_DIV=0x%x(%d)\n",
2235 cfg->fratio, ratio, cfg->outdiv,
2236 cfg->refdiv, 1 << cfg->refdiv);
2237 arizona_fll_dbg(fll, "GAIN=0x%x(%d)\n", cfg->gain, 1 << cfg->gain);
Mark Brown07ed8732012-06-18 21:08:44 +01002238
2239 return 0;
2240
2241}
2242
2243static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
Mark Brown8f113d72013-03-05 12:08:57 +08002244 struct arizona_fll_cfg *cfg, int source,
2245 bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01002246{
Mark Brown3c43c692013-12-12 00:49:22 +00002247 regmap_update_bits_async(arizona->regmap, base + 3,
2248 ARIZONA_FLL1_THETA_MASK, cfg->theta);
2249 regmap_update_bits_async(arizona->regmap, base + 4,
2250 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
2251 regmap_update_bits_async(arizona->regmap, base + 5,
2252 ARIZONA_FLL1_FRATIO_MASK,
2253 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
2254 regmap_update_bits_async(arizona->regmap, base + 6,
2255 ARIZONA_FLL1_CLK_REF_DIV_MASK |
2256 ARIZONA_FLL1_CLK_REF_SRC_MASK,
2257 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
2258 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
Mark Brown07ed8732012-06-18 21:08:44 +01002259
Charles Keepax61719db2014-03-07 16:34:19 +00002260 if (sync) {
2261 regmap_update_bits(arizona->regmap, base + 0x7,
2262 ARIZONA_FLL1_GAIN_MASK,
2263 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
2264 } else {
2265 regmap_update_bits(arizona->regmap, base + 0x5,
2266 ARIZONA_FLL1_OUTDIV_MASK,
2267 cfg->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
2268 regmap_update_bits(arizona->regmap, base + 0x9,
2269 ARIZONA_FLL1_GAIN_MASK,
2270 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
2271 }
Mark Brown8f113d72013-03-05 12:08:57 +08002272
Mark Brown3c43c692013-12-12 00:49:22 +00002273 regmap_update_bits_async(arizona->regmap, base + 2,
2274 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
2275 ARIZONA_FLL1_CTRL_UPD | cfg->n);
Mark Brown07ed8732012-06-18 21:08:44 +01002276}
2277
Charles Keepax62bb7102016-09-02 16:52:44 +01002278static int arizona_is_enabled_fll(struct arizona_fll *fll, int base)
Charles Keepaxd122d6c2013-02-20 17:28:36 +00002279{
2280 struct arizona *arizona = fll->arizona;
2281 unsigned int reg;
2282 int ret;
2283
Charles Keepax62bb7102016-09-02 16:52:44 +01002284 ret = regmap_read(arizona->regmap, base + 1, &reg);
Charles Keepaxd122d6c2013-02-20 17:28:36 +00002285 if (ret != 0) {
2286 arizona_fll_err(fll, "Failed to read current state: %d\n",
2287 ret);
2288 return ret;
2289 }
2290
2291 return reg & ARIZONA_FLL1_ENA;
2292}
2293
Charles Keepaxae1ea482016-10-21 14:15:58 +01002294static int arizona_set_fll_clks(struct arizona_fll *fll, int base, bool ena)
2295{
2296 struct arizona *arizona = fll->arizona;
2297 unsigned int val;
2298 struct clk *clk;
2299 int ret;
2300
2301 ret = regmap_read(arizona->regmap, base + 6, &val);
2302 if (ret != 0) {
2303 arizona_fll_err(fll, "Failed to read current source: %d\n",
2304 ret);
2305 return ret;
2306 }
2307
2308 val &= ARIZONA_FLL1_CLK_REF_SRC_MASK;
2309 val >>= ARIZONA_FLL1_CLK_REF_SRC_SHIFT;
2310
2311 switch (val) {
2312 case ARIZONA_FLL_SRC_MCLK1:
2313 clk = arizona->mclk[ARIZONA_MCLK1];
2314 break;
2315 case ARIZONA_FLL_SRC_MCLK2:
2316 clk = arizona->mclk[ARIZONA_MCLK2];
2317 break;
2318 default:
2319 return 0;
2320 }
2321
2322 if (ena) {
2323 return clk_prepare_enable(clk);
2324 } else {
2325 clk_disable_unprepare(clk);
2326 return 0;
2327 }
2328}
2329
Charles Keepaxc393aca2014-07-09 17:41:47 +01002330static int arizona_enable_fll(struct arizona_fll *fll)
Charles Keepax35722812013-02-20 17:28:38 +00002331{
2332 struct arizona *arizona = fll->arizona;
Charles Keepax49c60542013-09-16 15:34:35 +01002333 bool use_sync = false;
Charles Keepax62bb7102016-09-02 16:52:44 +01002334 int already_enabled = arizona_is_enabled_fll(fll, fll->base);
Charles Keepax0f72a8a2016-09-02 16:52:45 +01002335 int sync_enabled = arizona_is_enabled_fll(fll, fll->base + 0x10);
Charles Keepax23f785a82014-03-07 16:34:20 +00002336 struct arizona_fll_cfg cfg;
Charles Keepax0e765972015-08-25 12:43:48 +01002337 int i;
2338 unsigned int val;
Charles Keepax35722812013-02-20 17:28:38 +00002339
Charles Keepaxc393aca2014-07-09 17:41:47 +01002340 if (already_enabled < 0)
2341 return already_enabled;
Charles Keepax0f72a8a2016-09-02 16:52:45 +01002342 if (sync_enabled < 0)
2343 return sync_enabled;
Charles Keepaxc393aca2014-07-09 17:41:47 +01002344
Charles Keepaxc8badda2014-07-09 17:41:49 +01002345 if (already_enabled) {
2346 /* Facilitate smooth refclk across the transition */
Charles Keepax800f2972015-11-30 17:37:28 +00002347 regmap_update_bits(fll->arizona->regmap, fll->base + 1,
2348 ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
2349 udelay(32);
Nariman Poushinc9991052016-08-30 10:30:40 +01002350 regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9,
2351 ARIZONA_FLL1_GAIN_MASK, 0);
Charles Keepaxae1ea482016-10-21 14:15:58 +01002352
2353 if (arizona_is_enabled_fll(fll, fll->base + 0x10) > 0)
2354 arizona_set_fll_clks(fll, fll->base + 0x10, false);
2355 arizona_set_fll_clks(fll, fll->base, false);
Charles Keepaxc8badda2014-07-09 17:41:49 +01002356 }
2357
Mark Brownff680a12013-03-04 16:00:19 +08002358 /*
2359 * If we have both REFCLK and SYNCCLK then enable both,
2360 * otherwise apply the SYNCCLK settings to REFCLK.
2361 */
Charles Keepax49c60542013-09-16 15:34:35 +01002362 if (fll->ref_src >= 0 && fll->ref_freq &&
2363 fll->ref_src != fll->sync_src) {
Charles Keepaxd0800342014-03-07 16:34:25 +00002364 arizona_calc_fll(fll, &cfg, fll->ref_freq, false);
Charles Keepax35722812013-02-20 17:28:38 +00002365
Charles Keepaxe87d9ae82016-09-02 16:52:43 +01002366 /* Ref path hardcodes lambda to 65536 when sync is on */
2367 if (fll->sync_src >= 0 && cfg.lambda)
2368 cfg.theta = (cfg.theta * (1 << 16)) / cfg.lambda;
2369
Charles Keepax23f785a82014-03-07 16:34:20 +00002370 arizona_apply_fll(arizona, fll->base, &cfg, fll->ref_src,
Mark Brown8f113d72013-03-05 12:08:57 +08002371 false);
Charles Keepax49c60542013-09-16 15:34:35 +01002372 if (fll->sync_src >= 0) {
Charles Keepaxd0800342014-03-07 16:34:25 +00002373 arizona_calc_fll(fll, &cfg, fll->sync_freq, true);
Charles Keepax23f785a82014-03-07 16:34:20 +00002374
2375 arizona_apply_fll(arizona, fll->base + 0x10, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08002376 fll->sync_src, true);
Charles Keepax49c60542013-09-16 15:34:35 +01002377 use_sync = true;
2378 }
Mark Brownff680a12013-03-04 16:00:19 +08002379 } else if (fll->sync_src >= 0) {
Charles Keepaxd0800342014-03-07 16:34:25 +00002380 arizona_calc_fll(fll, &cfg, fll->sync_freq, false);
Mark Brownff680a12013-03-04 16:00:19 +08002381
Charles Keepax23f785a82014-03-07 16:34:20 +00002382 arizona_apply_fll(arizona, fll->base, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08002383 fll->sync_src, false);
Mark Browneca2e8e2013-03-06 00:09:59 +08002384
Mark Brown3c43c692013-12-12 00:49:22 +00002385 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
2386 ARIZONA_FLL1_SYNC_ENA, 0);
Mark Brownff680a12013-03-04 16:00:19 +08002387 } else {
2388 arizona_fll_err(fll, "No clocks provided\n");
Charles Keepaxc393aca2014-07-09 17:41:47 +01002389 return -EINVAL;
Mark Brownff680a12013-03-04 16:00:19 +08002390 }
Charles Keepax35722812013-02-20 17:28:38 +00002391
Charles Keepax0f72a8a2016-09-02 16:52:45 +01002392 if (already_enabled && !!sync_enabled != use_sync)
2393 arizona_fll_warn(fll, "Synchroniser changed on active FLL\n");
2394
Mark Brown576411be2013-03-05 12:07:16 +08002395 /*
2396 * Increase the bandwidth if we're not using a low frequency
2397 * sync source.
2398 */
Charles Keepax49c60542013-09-16 15:34:35 +01002399 if (use_sync && fll->sync_freq > 100000)
Mark Brown3c43c692013-12-12 00:49:22 +00002400 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
2401 ARIZONA_FLL1_SYNC_BW, 0);
Mark Brown576411be2013-03-05 12:07:16 +08002402 else
Mark Brown3c43c692013-12-12 00:49:22 +00002403 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
2404 ARIZONA_FLL1_SYNC_BW,
2405 ARIZONA_FLL1_SYNC_BW);
Mark Brown576411be2013-03-05 12:07:16 +08002406
Charles Keepaxc393aca2014-07-09 17:41:47 +01002407 if (!already_enabled)
Richard Fitzgerald63d19e02016-08-25 11:39:32 +01002408 pm_runtime_get_sync(arizona->dev);
Charles Keepax35722812013-02-20 17:28:38 +00002409
Charles Keepaxae1ea482016-10-21 14:15:58 +01002410 if (use_sync) {
2411 arizona_set_fll_clks(fll, fll->base + 0x10, true);
Mark Brown3c43c692013-12-12 00:49:22 +00002412 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
2413 ARIZONA_FLL1_SYNC_ENA,
2414 ARIZONA_FLL1_SYNC_ENA);
Charles Keepaxae1ea482016-10-21 14:15:58 +01002415 }
2416 arizona_set_fll_clks(fll, fll->base, true);
Charles Keepax0f72a8a2016-09-02 16:52:45 +01002417 regmap_update_bits_async(arizona->regmap, fll->base + 1,
2418 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
Charles Keepax35722812013-02-20 17:28:38 +00002419
Charles Keepaxc8badda2014-07-09 17:41:49 +01002420 if (already_enabled)
2421 regmap_update_bits_async(arizona->regmap, fll->base + 1,
2422 ARIZONA_FLL1_FREERUN, 0);
2423
Charles Keepax0e765972015-08-25 12:43:48 +01002424 arizona_fll_dbg(fll, "Waiting for FLL lock...\n");
2425 val = 0;
2426 for (i = 0; i < 15; i++) {
2427 if (i < 5)
2428 usleep_range(200, 400);
2429 else
2430 msleep(20);
2431
2432 regmap_read(arizona->regmap,
2433 ARIZONA_INTERRUPT_RAW_STATUS_5,
2434 &val);
2435 if (val & (ARIZONA_FLL1_CLOCK_OK_STS << (fll->id - 1)))
2436 break;
2437 }
2438 if (i == 15)
Charles Keepax35722812013-02-20 17:28:38 +00002439 arizona_fll_warn(fll, "Timed out waiting for lock\n");
Charles Keepax0e765972015-08-25 12:43:48 +01002440 else
2441 arizona_fll_dbg(fll, "FLL locked (%d polls)\n", i);
Charles Keepaxc393aca2014-07-09 17:41:47 +01002442
2443 return 0;
Charles Keepax35722812013-02-20 17:28:38 +00002444}
2445
Charles Keepax76040542013-02-20 17:28:37 +00002446static void arizona_disable_fll(struct arizona_fll *fll)
2447{
2448 struct arizona *arizona = fll->arizona;
Charles Keepaxae1ea482016-10-21 14:15:58 +01002449 bool ref_change, sync_change;
Charles Keepax76040542013-02-20 17:28:37 +00002450
Mark Brown3c43c692013-12-12 00:49:22 +00002451 regmap_update_bits_async(arizona->regmap, fll->base + 1,
2452 ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
Charles Keepax76040542013-02-20 17:28:37 +00002453 regmap_update_bits_check(arizona->regmap, fll->base + 1,
Charles Keepaxae1ea482016-10-21 14:15:58 +01002454 ARIZONA_FLL1_ENA, 0, &ref_change);
2455 regmap_update_bits_check(arizona->regmap, fll->base + 0x11,
2456 ARIZONA_FLL1_SYNC_ENA, 0, &sync_change);
Charles Keepax5e39a502014-07-09 17:41:48 +01002457 regmap_update_bits_async(arizona->regmap, fll->base + 1,
2458 ARIZONA_FLL1_FREERUN, 0);
Charles Keepax76040542013-02-20 17:28:37 +00002459
Charles Keepaxae1ea482016-10-21 14:15:58 +01002460 if (sync_change)
2461 arizona_set_fll_clks(fll, fll->base + 0x10, false);
2462
2463 if (ref_change) {
2464 arizona_set_fll_clks(fll, fll->base, false);
Charles Keepax76040542013-02-20 17:28:37 +00002465 pm_runtime_put_autosuspend(arizona->dev);
Charles Keepaxae1ea482016-10-21 14:15:58 +01002466 }
Charles Keepax76040542013-02-20 17:28:37 +00002467}
2468
Charles Keepaxee929a92013-02-20 17:28:40 +00002469int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
2470 unsigned int Fref, unsigned int Fout)
2471{
Charles Keepaxc393aca2014-07-09 17:41:47 +01002472 int ret = 0;
Charles Keepaxee929a92013-02-20 17:28:40 +00002473
Charles Keepax1c5617f2013-02-22 17:10:37 +00002474 if (fll->ref_src == source && fll->ref_freq == Fref)
Charles Keepaxee929a92013-02-20 17:28:40 +00002475 return 0;
2476
Charles Keepax23f785a82014-03-07 16:34:20 +00002477 if (fll->fout && Fref > 0) {
2478 ret = arizona_validate_fll(fll, Fref, fll->fout);
2479 if (ret != 0)
2480 return ret;
Charles Keepaxee929a92013-02-20 17:28:40 +00002481 }
2482
2483 fll->ref_src = source;
2484 fll->ref_freq = Fref;
Charles Keepaxee929a92013-02-20 17:28:40 +00002485
Mark Brown86cd6842013-03-07 16:14:04 +08002486 if (fll->fout && Fref > 0) {
Charles Keepaxc393aca2014-07-09 17:41:47 +01002487 ret = arizona_enable_fll(fll);
Charles Keepaxee929a92013-02-20 17:28:40 +00002488 }
2489
Charles Keepaxc393aca2014-07-09 17:41:47 +01002490 return ret;
Charles Keepaxee929a92013-02-20 17:28:40 +00002491}
2492EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
2493
Mark Brown07ed8732012-06-18 21:08:44 +01002494int arizona_set_fll(struct arizona_fll *fll, int source,
2495 unsigned int Fref, unsigned int Fout)
2496{
Charles Keepaxc393aca2014-07-09 17:41:47 +01002497 int ret = 0;
Mark Brown07ed8732012-06-18 21:08:44 +01002498
Mark Brownff680a12013-03-04 16:00:19 +08002499 if (fll->sync_src == source &&
2500 fll->sync_freq == Fref && fll->fout == Fout)
2501 return 0;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00002502
Mark Brownff680a12013-03-04 16:00:19 +08002503 if (Fout) {
2504 if (fll->ref_src >= 0) {
Charles Keepax23f785a82014-03-07 16:34:20 +00002505 ret = arizona_validate_fll(fll, fll->ref_freq, Fout);
Charles Keepax9e359c62013-02-20 17:28:35 +00002506 if (ret != 0)
2507 return ret;
2508 }
2509
Charles Keepax23f785a82014-03-07 16:34:20 +00002510 ret = arizona_validate_fll(fll, Fref, Fout);
Mark Brownff680a12013-03-04 16:00:19 +08002511 if (ret != 0)
2512 return ret;
Charles Keepax9e359c62013-02-20 17:28:35 +00002513 }
Mark Brownff680a12013-03-04 16:00:19 +08002514
2515 fll->sync_src = source;
2516 fll->sync_freq = Fref;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00002517 fll->fout = Fout;
Charles Keepax9e359c62013-02-20 17:28:35 +00002518
Charles Keepax613124c2014-07-09 17:41:46 +01002519 if (Fout)
Charles Keepaxc393aca2014-07-09 17:41:47 +01002520 ret = arizona_enable_fll(fll);
Charles Keepax613124c2014-07-09 17:41:46 +01002521 else
Charles Keepax76040542013-02-20 17:28:37 +00002522 arizona_disable_fll(fll);
Mark Brown07ed8732012-06-18 21:08:44 +01002523
Charles Keepaxc393aca2014-07-09 17:41:47 +01002524 return ret;
Mark Brown07ed8732012-06-18 21:08:44 +01002525}
2526EXPORT_SYMBOL_GPL(arizona_set_fll);
2527
2528int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
2529 int ok_irq, struct arizona_fll *fll)
2530{
Charles Keepax19b34bd2013-02-20 17:28:34 +00002531 unsigned int val;
Mark Brown07ed8732012-06-18 21:08:44 +01002532
Mark Brown07ed8732012-06-18 21:08:44 +01002533 fll->id = id;
2534 fll->base = base;
2535 fll->arizona = arizona;
Charles Keepaxf3f11632013-02-20 17:28:41 +00002536 fll->sync_src = ARIZONA_FLL_SRC_NONE;
Mark Brown07ed8732012-06-18 21:08:44 +01002537
Charles Keepax19b34bd2013-02-20 17:28:34 +00002538 /* Configure default refclk to 32kHz if we have one */
2539 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
2540 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
2541 case ARIZONA_CLK_SRC_MCLK1:
2542 case ARIZONA_CLK_SRC_MCLK2:
2543 fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK;
2544 break;
2545 default:
Charles Keepaxf3f11632013-02-20 17:28:41 +00002546 fll->ref_src = ARIZONA_FLL_SRC_NONE;
Charles Keepax19b34bd2013-02-20 17:28:34 +00002547 }
2548 fll->ref_freq = 32768;
2549
Mark Brown07ed8732012-06-18 21:08:44 +01002550 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
2551 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
2552 "FLL%d clock OK", id);
2553
Charles Keepaxe31c1942013-01-07 16:41:45 +00002554 regmap_update_bits(arizona->regmap, fll->base + 1,
2555 ARIZONA_FLL1_FREERUN, 0);
2556
Mark Brown07ed8732012-06-18 21:08:44 +01002557 return 0;
2558}
2559EXPORT_SYMBOL_GPL(arizona_init_fll);
2560
Mark Brownbc9ab6d2013-01-04 19:31:00 +00002561/**
2562 * arizona_set_output_mode - Set the mode of the specified output
2563 *
2564 * @codec: Device to configure
2565 * @output: Output number
2566 * @diff: True to set the output to differential mode
2567 *
2568 * Some systems use external analogue switches to connect more
2569 * analogue devices to the CODEC than are supported by the device. In
2570 * some systems this requires changing the switched output from single
2571 * ended to differential mode dynamically at runtime, an operation
2572 * supported using this function.
2573 *
2574 * Most systems have a single static configuration and should use
2575 * platform data instead.
2576 */
2577int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
2578{
2579 unsigned int reg, val;
2580
2581 if (output < 1 || output > 6)
2582 return -EINVAL;
2583
2584 reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
2585
2586 if (diff)
2587 val = ARIZONA_OUT1_MONO;
2588 else
2589 val = 0;
2590
2591 return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val);
2592}
2593EXPORT_SYMBOL_GPL(arizona_set_output_mode);
2594
Richard Fitzgerald336d0442015-06-18 13:43:19 +01002595static const struct soc_enum arizona_adsp2_rate_enum[] = {
2596 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP1_CONTROL_1,
2597 ARIZONA_DSP1_RATE_SHIFT, 0xf,
2598 ARIZONA_RATE_ENUM_SIZE,
2599 arizona_rate_text, arizona_rate_val),
2600 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP2_CONTROL_1,
2601 ARIZONA_DSP1_RATE_SHIFT, 0xf,
2602 ARIZONA_RATE_ENUM_SIZE,
2603 arizona_rate_text, arizona_rate_val),
2604 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1,
2605 ARIZONA_DSP1_RATE_SHIFT, 0xf,
2606 ARIZONA_RATE_ENUM_SIZE,
2607 arizona_rate_text, arizona_rate_val),
2608 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP4_CONTROL_1,
2609 ARIZONA_DSP1_RATE_SHIFT, 0xf,
2610 ARIZONA_RATE_ENUM_SIZE,
2611 arizona_rate_text, arizona_rate_val),
2612};
2613
2614const struct snd_kcontrol_new arizona_adsp2_rate_controls[] = {
2615 SOC_ENUM("DSP1 Rate", arizona_adsp2_rate_enum[0]),
2616 SOC_ENUM("DSP2 Rate", arizona_adsp2_rate_enum[1]),
2617 SOC_ENUM("DSP3 Rate", arizona_adsp2_rate_enum[2]),
2618 SOC_ENUM("DSP4 Rate", arizona_adsp2_rate_enum[3]),
2619};
2620EXPORT_SYMBOL_GPL(arizona_adsp2_rate_controls);
2621
Charles Keepaxc05d9a82015-06-25 09:35:11 +01002622static bool arizona_eq_filter_unstable(bool mode, __be16 _a, __be16 _b)
2623{
2624 s16 a = be16_to_cpu(_a);
2625 s16 b = be16_to_cpu(_b);
2626
2627 if (!mode) {
2628 return abs(a) >= 4096;
2629 } else {
2630 if (abs(b) >= 4096)
2631 return true;
2632
2633 return (abs((a << 16) / (4096 - b)) >= 4096 << 4);
2634 }
2635}
2636
2637int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol,
2638 struct snd_ctl_elem_value *ucontrol)
2639{
2640 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
2641 struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
2642 struct soc_bytes *params = (void *)kcontrol->private_value;
2643 unsigned int val;
2644 __be16 *data;
2645 int len;
2646 int ret;
2647
2648 len = params->num_regs * regmap_get_val_bytes(arizona->regmap);
2649
2650 data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA);
2651 if (!data)
2652 return -ENOMEM;
2653
2654 data[0] &= cpu_to_be16(ARIZONA_EQ1_B1_MODE);
2655
2656 if (arizona_eq_filter_unstable(!!data[0], data[1], data[2]) ||
2657 arizona_eq_filter_unstable(true, data[4], data[5]) ||
2658 arizona_eq_filter_unstable(true, data[8], data[9]) ||
2659 arizona_eq_filter_unstable(true, data[12], data[13]) ||
2660 arizona_eq_filter_unstable(false, data[16], data[17])) {
2661 dev_err(arizona->dev, "Rejecting unstable EQ coefficients\n");
2662 ret = -EINVAL;
2663 goto out;
2664 }
2665
2666 ret = regmap_read(arizona->regmap, params->base, &val);
2667 if (ret != 0)
2668 goto out;
2669
2670 val &= ~ARIZONA_EQ1_B1_MODE;
2671 data[0] |= cpu_to_be16(val);
2672
2673 ret = regmap_raw_write(arizona->regmap, params->base, data, len);
2674
2675out:
2676 kfree(data);
2677 return ret;
2678}
2679EXPORT_SYMBOL_GPL(arizona_eq_coeff_put);
2680
Charles Keepax5f8e6712015-06-25 09:35:12 +01002681int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
2682 struct snd_ctl_elem_value *ucontrol)
2683{
2684 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
2685 struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
2686 __be16 *data = (__be16 *)ucontrol->value.bytes.data;
2687 s16 val = be16_to_cpu(*data);
2688
2689 if (abs(val) >= 4096) {
2690 dev_err(arizona->dev, "Rejecting unstable LHPF coefficients\n");
2691 return -EINVAL;
2692 }
2693
2694 return snd_soc_bytes_put(kcontrol, ucontrol);
2695}
2696EXPORT_SYMBOL_GPL(arizona_lhpf_coeff_put);
2697
Mark Brown07ed8732012-06-18 21:08:44 +01002698MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
2699MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
2700MODULE_LICENSE("GPL");