blob: d8a6823025801370230857c173811c053b945fe3 [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);
88 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
89 bool manual_ena = false;
Mark Brownf4a76e72013-03-13 12:22:39 +000090 int val;
Mark Brown56447e12013-01-10 14:45:58 +000091
92 switch (arizona->type) {
93 case WM5102:
94 switch (arizona->rev) {
95 case 0:
96 break;
97 default:
98 manual_ena = true;
99 break;
100 }
101 default:
102 break;
103 }
104
105 switch (event) {
106 case SND_SOC_DAPM_PRE_PMU:
107 if (!priv->spk_ena && manual_ena) {
Mark Brown3c43c692013-12-12 00:49:22 +0000108 regmap_write_async(arizona->regmap, 0x4f5, 0x25a);
Mark Brown56447e12013-01-10 14:45:58 +0000109 priv->spk_ena_pending = true;
110 }
111 break;
112 case SND_SOC_DAPM_POST_PMU:
Mark Brownf4a76e72013-03-13 12:22:39 +0000113 val = snd_soc_read(codec, ARIZONA_INTERRUPT_RAW_STATUS_3);
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100114 if (val & ARIZONA_SPK_OVERHEAT_STS) {
Mark Brownf4a76e72013-03-13 12:22:39 +0000115 dev_crit(arizona->dev,
116 "Speaker not enabled due to temperature\n");
117 return -EBUSY;
118 }
119
Mark Brown3c43c692013-12-12 00:49:22 +0000120 regmap_update_bits_async(arizona->regmap,
121 ARIZONA_OUTPUT_ENABLES_1,
122 1 << w->shift, 1 << w->shift);
Mark Brownf4a76e72013-03-13 12:22:39 +0000123
Mark Brown56447e12013-01-10 14:45:58 +0000124 if (priv->spk_ena_pending) {
125 msleep(75);
Mark Brown3c43c692013-12-12 00:49:22 +0000126 regmap_write_async(arizona->regmap, 0x4f5, 0xda);
Mark Brown56447e12013-01-10 14:45:58 +0000127 priv->spk_ena_pending = false;
128 priv->spk_ena++;
129 }
130 break;
131 case SND_SOC_DAPM_PRE_PMD:
132 if (manual_ena) {
133 priv->spk_ena--;
134 if (!priv->spk_ena)
Mark Brown3c43c692013-12-12 00:49:22 +0000135 regmap_write_async(arizona->regmap,
136 0x4f5, 0x25a);
Mark Brown56447e12013-01-10 14:45:58 +0000137 }
Mark Brownf4a76e72013-03-13 12:22:39 +0000138
Mark Brown3c43c692013-12-12 00:49:22 +0000139 regmap_update_bits_async(arizona->regmap,
140 ARIZONA_OUTPUT_ENABLES_1,
141 1 << w->shift, 0);
Mark Brown56447e12013-01-10 14:45:58 +0000142 break;
143 case SND_SOC_DAPM_POST_PMD:
144 if (manual_ena) {
145 if (!priv->spk_ena)
Mark Brown3c43c692013-12-12 00:49:22 +0000146 regmap_write_async(arizona->regmap,
147 0x4f5, 0x0da);
Mark Brown56447e12013-01-10 14:45:58 +0000148 }
149 break;
Charles Keepaxbee261b2015-09-16 13:59:40 +0100150 default:
151 break;
Mark Brown56447e12013-01-10 14:45:58 +0000152 }
153
154 return 0;
155}
156
Mark Brown899817e2013-03-13 12:32:10 +0000157static irqreturn_t arizona_thermal_warn(int irq, void *data)
158{
159 struct arizona *arizona = data;
160 unsigned int val;
161 int ret;
162
163 ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
164 &val);
165 if (ret != 0) {
166 dev_err(arizona->dev, "Failed to read thermal status: %d\n",
167 ret);
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100168 } else if (val & ARIZONA_SPK_OVERHEAT_WARN_STS) {
Mark Brown899817e2013-03-13 12:32:10 +0000169 dev_crit(arizona->dev, "Thermal warning\n");
170 }
171
172 return IRQ_HANDLED;
173}
174
175static irqreturn_t arizona_thermal_shutdown(int irq, void *data)
176{
177 struct arizona *arizona = data;
178 unsigned int val;
179 int ret;
180
181 ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
182 &val);
183 if (ret != 0) {
184 dev_err(arizona->dev, "Failed to read thermal status: %d\n",
185 ret);
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100186 } else if (val & ARIZONA_SPK_OVERHEAT_STS) {
Mark Brown899817e2013-03-13 12:32:10 +0000187 dev_crit(arizona->dev, "Thermal shutdown\n");
Mark Brownf4a76e72013-03-13 12:22:39 +0000188 ret = regmap_update_bits(arizona->regmap,
189 ARIZONA_OUTPUT_ENABLES_1,
190 ARIZONA_OUT4L_ENA |
191 ARIZONA_OUT4R_ENA, 0);
192 if (ret != 0)
193 dev_crit(arizona->dev,
194 "Failed to disable speaker outputs: %d\n",
195 ret);
Mark Brown899817e2013-03-13 12:32:10 +0000196 }
197
198 return IRQ_HANDLED;
199}
200
Mark Brown56447e12013-01-10 14:45:58 +0000201static const struct snd_soc_dapm_widget arizona_spkl =
Mark Brownf4a76e72013-03-13 12:22:39 +0000202 SND_SOC_DAPM_PGA_E("OUT4L", SND_SOC_NOPM,
Mark Brown56447e12013-01-10 14:45:58 +0000203 ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
204 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
205
206static const struct snd_soc_dapm_widget arizona_spkr =
Mark Brownf4a76e72013-03-13 12:22:39 +0000207 SND_SOC_DAPM_PGA_E("OUT4R", SND_SOC_NOPM,
Mark Brown56447e12013-01-10 14:45:58 +0000208 ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
209 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
210
211int arizona_init_spk(struct snd_soc_codec *codec)
212{
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200213 struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
Mark Brown899817e2013-03-13 12:32:10 +0000214 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
215 struct arizona *arizona = priv->arizona;
Mark Brown56447e12013-01-10 14:45:58 +0000216 int ret;
217
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200218 ret = snd_soc_dapm_new_controls(dapm, &arizona_spkl, 1);
Mark Brown56447e12013-01-10 14:45:58 +0000219 if (ret != 0)
220 return ret;
221
Charles Keepax40843ae2013-08-12 23:46:55 +0100222 switch (arizona->type) {
223 case WM8997:
Richard Fitzgerald43b27d72016-04-08 16:50:14 +0100224 case CS47L24:
225 case WM1831:
Charles Keepax40843ae2013-08-12 23:46:55 +0100226 break;
227 default:
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200228 ret = snd_soc_dapm_new_controls(dapm, &arizona_spkr, 1);
Charles Keepax40843ae2013-08-12 23:46:55 +0100229 if (ret != 0)
230 return ret;
231 break;
232 }
Mark Brown56447e12013-01-10 14:45:58 +0000233
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100234 ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN,
Mark Brown899817e2013-03-13 12:32:10 +0000235 "Thermal warning", arizona_thermal_warn,
236 arizona);
237 if (ret != 0)
238 dev_err(arizona->dev,
239 "Failed to get thermal warning IRQ: %d\n",
240 ret);
241
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100242 ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT,
Mark Brown899817e2013-03-13 12:32:10 +0000243 "Thermal shutdown", arizona_thermal_shutdown,
244 arizona);
245 if (ret != 0)
246 dev_err(arizona->dev,
247 "Failed to get thermal shutdown IRQ: %d\n",
248 ret);
249
Mark Brown56447e12013-01-10 14:45:58 +0000250 return 0;
251}
252EXPORT_SYMBOL_GPL(arizona_init_spk);
253
Charles Keepaxb60f3632014-06-10 18:41:02 +0100254static const struct snd_soc_dapm_route arizona_mono_routes[] = {
255 { "OUT1R", NULL, "OUT1L" },
256 { "OUT2R", NULL, "OUT2L" },
257 { "OUT3R", NULL, "OUT3L" },
258 { "OUT4R", NULL, "OUT4L" },
259 { "OUT5R", NULL, "OUT5L" },
260 { "OUT6R", NULL, "OUT6L" },
261};
262
263int arizona_init_mono(struct snd_soc_codec *codec)
264{
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200265 struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
Charles Keepaxb60f3632014-06-10 18:41:02 +0100266 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
267 struct arizona *arizona = priv->arizona;
268 int i;
269
270 for (i = 0; i < ARIZONA_MAX_OUTPUT; ++i) {
271 if (arizona->pdata.out_mono[i])
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200272 snd_soc_dapm_add_routes(dapm,
Charles Keepaxb60f3632014-06-10 18:41:02 +0100273 &arizona_mono_routes[i], 1);
274 }
275
276 return 0;
277}
278EXPORT_SYMBOL_GPL(arizona_init_mono);
279
Charles Keepaxb63144e2013-07-04 08:56:28 +0100280int arizona_init_gpio(struct snd_soc_codec *codec)
281{
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200282 struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
Charles Keepaxb63144e2013-07-04 08:56:28 +0100283 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
284 struct arizona *arizona = priv->arizona;
285 int i;
286
287 switch (arizona->type) {
288 case WM5110:
Richard Fitzgerald575ef7f2015-01-17 15:21:27 +0000289 case WM8280:
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200290 snd_soc_dapm_disable_pin(dapm, "DRC2 Signal Activity");
Charles Keepaxb79fae62013-07-04 16:53:03 +0100291 break;
292 default:
293 break;
Charles Keepaxb63144e2013-07-04 08:56:28 +0100294 }
295
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200296 snd_soc_dapm_disable_pin(dapm, "DRC1 Signal Activity");
Charles Keepaxb63144e2013-07-04 08:56:28 +0100297
298 for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
299 switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) {
300 case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT:
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200301 snd_soc_dapm_enable_pin(dapm, "DRC1 Signal Activity");
Charles Keepaxb63144e2013-07-04 08:56:28 +0100302 break;
303 case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT:
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200304 snd_soc_dapm_enable_pin(dapm, "DRC2 Signal Activity");
Charles Keepaxb63144e2013-07-04 08:56:28 +0100305 break;
306 default:
307 break;
308 }
309 }
310
311 return 0;
312}
313EXPORT_SYMBOL_GPL(arizona_init_gpio);
314
Charles Keepax141bc6a2015-12-03 18:15:06 +0000315const char * const arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100316 "None",
317 "Tone Generator 1",
318 "Tone Generator 2",
319 "Haptics",
320 "AEC",
Richard Fitzgerald6ebbce02015-09-28 14:01:09 +0100321 "AEC2",
Mark Brown07ed8732012-06-18 21:08:44 +0100322 "Mic Mute Mixer",
323 "Noise Generator",
324 "IN1L",
325 "IN1R",
326 "IN2L",
327 "IN2R",
328 "IN3L",
329 "IN3R",
Mark Brownc9c56fd2012-07-09 19:09:01 +0100330 "IN4L",
331 "IN4R",
Mark Brown07ed8732012-06-18 21:08:44 +0100332 "AIF1RX1",
333 "AIF1RX2",
334 "AIF1RX3",
335 "AIF1RX4",
336 "AIF1RX5",
337 "AIF1RX6",
338 "AIF1RX7",
339 "AIF1RX8",
340 "AIF2RX1",
341 "AIF2RX2",
Richard Fitzgeralde64001e2013-11-20 13:17:07 +0000342 "AIF2RX3",
343 "AIF2RX4",
344 "AIF2RX5",
345 "AIF2RX6",
Mark Brown07ed8732012-06-18 21:08:44 +0100346 "AIF3RX1",
347 "AIF3RX2",
348 "SLIMRX1",
349 "SLIMRX2",
350 "SLIMRX3",
351 "SLIMRX4",
352 "SLIMRX5",
353 "SLIMRX6",
354 "SLIMRX7",
355 "SLIMRX8",
356 "EQ1",
357 "EQ2",
358 "EQ3",
359 "EQ4",
360 "DRC1L",
361 "DRC1R",
362 "DRC2L",
363 "DRC2R",
364 "LHPF1",
365 "LHPF2",
366 "LHPF3",
367 "LHPF4",
368 "DSP1.1",
369 "DSP1.2",
370 "DSP1.3",
371 "DSP1.4",
372 "DSP1.5",
373 "DSP1.6",
Mark Brownc922cc42012-09-26 16:43:44 +0100374 "DSP2.1",
375 "DSP2.2",
376 "DSP2.3",
377 "DSP2.4",
378 "DSP2.5",
379 "DSP2.6",
380 "DSP3.1",
381 "DSP3.2",
382 "DSP3.3",
383 "DSP3.4",
384 "DSP3.5",
385 "DSP3.6",
386 "DSP4.1",
387 "DSP4.2",
388 "DSP4.3",
389 "DSP4.4",
390 "DSP4.5",
391 "DSP4.6",
Mark Brown07ed8732012-06-18 21:08:44 +0100392 "ASRC1L",
393 "ASRC1R",
394 "ASRC2L",
395 "ASRC2R",
Mark Brown91660bd2012-12-05 20:35:24 +0900396 "ISRC1INT1",
397 "ISRC1INT2",
398 "ISRC1INT3",
399 "ISRC1INT4",
400 "ISRC1DEC1",
401 "ISRC1DEC2",
402 "ISRC1DEC3",
403 "ISRC1DEC4",
404 "ISRC2INT1",
405 "ISRC2INT2",
406 "ISRC2INT3",
407 "ISRC2INT4",
408 "ISRC2DEC1",
409 "ISRC2DEC2",
410 "ISRC2DEC3",
411 "ISRC2DEC4",
412 "ISRC3INT1",
413 "ISRC3INT2",
414 "ISRC3INT3",
415 "ISRC3INT4",
416 "ISRC3DEC1",
417 "ISRC3DEC2",
418 "ISRC3DEC3",
419 "ISRC3DEC4",
Mark Brown07ed8732012-06-18 21:08:44 +0100420};
421EXPORT_SYMBOL_GPL(arizona_mixer_texts);
422
Charles Keepax141bc6a2015-12-03 18:15:06 +0000423unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100424 0x00, /* None */
425 0x04, /* Tone */
426 0x05,
427 0x06, /* Haptics */
428 0x08, /* AEC */
Richard Fitzgerald6ebbce02015-09-28 14:01:09 +0100429 0x09, /* AEC2 */
Mark Brown07ed8732012-06-18 21:08:44 +0100430 0x0c, /* Noise mixer */
431 0x0d, /* Comfort noise */
432 0x10, /* IN1L */
433 0x11,
434 0x12,
435 0x13,
436 0x14,
437 0x15,
Mark Brownc9c56fd2012-07-09 19:09:01 +0100438 0x16,
439 0x17,
Mark Brown07ed8732012-06-18 21:08:44 +0100440 0x20, /* AIF1RX1 */
441 0x21,
442 0x22,
443 0x23,
444 0x24,
445 0x25,
446 0x26,
447 0x27,
448 0x28, /* AIF2RX1 */
449 0x29,
Richard Fitzgeralde64001e2013-11-20 13:17:07 +0000450 0x2a,
451 0x2b,
452 0x2c,
453 0x2d,
Mark Brown07ed8732012-06-18 21:08:44 +0100454 0x30, /* AIF3RX1 */
455 0x31,
456 0x38, /* SLIMRX1 */
457 0x39,
458 0x3a,
459 0x3b,
460 0x3c,
461 0x3d,
462 0x3e,
463 0x3f,
464 0x50, /* EQ1 */
465 0x51,
466 0x52,
467 0x53,
468 0x58, /* DRC1L */
469 0x59,
470 0x5a,
471 0x5b,
472 0x60, /* LHPF1 */
473 0x61,
474 0x62,
475 0x63,
476 0x68, /* DSP1.1 */
477 0x69,
478 0x6a,
479 0x6b,
480 0x6c,
481 0x6d,
Mark Brownc922cc42012-09-26 16:43:44 +0100482 0x70, /* DSP2.1 */
483 0x71,
484 0x72,
485 0x73,
486 0x74,
487 0x75,
488 0x78, /* DSP3.1 */
489 0x79,
490 0x7a,
491 0x7b,
492 0x7c,
493 0x7d,
494 0x80, /* DSP4.1 */
495 0x81,
496 0x82,
497 0x83,
498 0x84,
499 0x85,
Mark Brown07ed8732012-06-18 21:08:44 +0100500 0x90, /* ASRC1L */
501 0x91,
502 0x92,
503 0x93,
Mark Brown91660bd2012-12-05 20:35:24 +0900504 0xa0, /* ISRC1INT1 */
505 0xa1,
506 0xa2,
507 0xa3,
508 0xa4, /* ISRC1DEC1 */
509 0xa5,
510 0xa6,
511 0xa7,
512 0xa8, /* ISRC2DEC1 */
513 0xa9,
514 0xaa,
515 0xab,
516 0xac, /* ISRC2INT1 */
517 0xad,
518 0xae,
519 0xaf,
520 0xb0, /* ISRC3DEC1 */
521 0xb1,
522 0xb2,
523 0xb3,
524 0xb4, /* ISRC3INT1 */
525 0xb5,
526 0xb6,
527 0xb7,
Mark Brown07ed8732012-06-18 21:08:44 +0100528};
529EXPORT_SYMBOL_GPL(arizona_mixer_values);
530
531const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
532EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
533
Richard Fitzgerald6ebbce02015-09-28 14:01:09 +0100534const char * const arizona_sample_rate_text[ARIZONA_SAMPLE_RATE_ENUM_SIZE] = {
535 "12kHz", "24kHz", "48kHz", "96kHz", "192kHz",
536 "11.025kHz", "22.05kHz", "44.1kHz", "88.2kHz", "176.4kHz",
537 "4kHz", "8kHz", "16kHz", "32kHz",
538};
539EXPORT_SYMBOL_GPL(arizona_sample_rate_text);
540
541const unsigned int arizona_sample_rate_val[ARIZONA_SAMPLE_RATE_ENUM_SIZE] = {
542 0x01, 0x02, 0x03, 0x04, 0x05, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
543 0x10, 0x11, 0x12, 0x13,
544};
545EXPORT_SYMBOL_GPL(arizona_sample_rate_val);
546
547const char *arizona_sample_rate_val_to_name(unsigned int rate_val)
548{
549 int i;
550
551 for (i = 0; i < ARRAY_SIZE(arizona_sample_rate_val); ++i) {
552 if (arizona_sample_rate_val[i] == rate_val)
553 return arizona_sample_rate_text[i];
554 }
555
556 return "Illegal";
557}
558EXPORT_SYMBOL_GPL(arizona_sample_rate_val_to_name);
559
Charles Keepax141bc6a2015-12-03 18:15:06 +0000560const char * const arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = {
Mark Browndc914282013-02-18 19:09:23 +0000561 "SYNCCLK rate", "8kHz", "16kHz", "ASYNCCLK rate",
562};
563EXPORT_SYMBOL_GPL(arizona_rate_text);
564
Charles Keepax141bc6a2015-12-03 18:15:06 +0000565const unsigned int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
Mark Browndc914282013-02-18 19:09:23 +0000566 0, 1, 2, 8,
567};
568EXPORT_SYMBOL_GPL(arizona_rate_val);
569
570
Charles Keepaxfbedc8c2013-12-19 09:30:12 +0000571const struct soc_enum arizona_isrc_fsh[] = {
572 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_1,
573 ARIZONA_ISRC1_FSH_SHIFT, 0xf,
574 ARIZONA_RATE_ENUM_SIZE,
575 arizona_rate_text, arizona_rate_val),
576 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_1,
577 ARIZONA_ISRC2_FSH_SHIFT, 0xf,
578 ARIZONA_RATE_ENUM_SIZE,
579 arizona_rate_text, arizona_rate_val),
580 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_1,
581 ARIZONA_ISRC3_FSH_SHIFT, 0xf,
582 ARIZONA_RATE_ENUM_SIZE,
583 arizona_rate_text, arizona_rate_val),
584};
585EXPORT_SYMBOL_GPL(arizona_isrc_fsh);
586
Mark Browndc914282013-02-18 19:09:23 +0000587const struct soc_enum arizona_isrc_fsl[] = {
588 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2,
589 ARIZONA_ISRC1_FSL_SHIFT, 0xf,
590 ARIZONA_RATE_ENUM_SIZE,
591 arizona_rate_text, arizona_rate_val),
592 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_2,
593 ARIZONA_ISRC2_FSL_SHIFT, 0xf,
594 ARIZONA_RATE_ENUM_SIZE,
595 arizona_rate_text, arizona_rate_val),
596 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_2,
597 ARIZONA_ISRC3_FSL_SHIFT, 0xf,
598 ARIZONA_RATE_ENUM_SIZE,
599 arizona_rate_text, arizona_rate_val),
600};
601EXPORT_SYMBOL_GPL(arizona_isrc_fsl);
602
Charles Keepax56d37d82013-12-19 09:30:13 +0000603const struct soc_enum arizona_asrc_rate1 =
604 SOC_VALUE_ENUM_SINGLE(ARIZONA_ASRC_RATE1,
605 ARIZONA_ASRC_RATE1_SHIFT, 0xf,
606 ARIZONA_RATE_ENUM_SIZE - 1,
607 arizona_rate_text, arizona_rate_val);
608EXPORT_SYMBOL_GPL(arizona_asrc_rate1);
609
Mark Browne853a002012-12-09 12:25:52 +0900610static const char *arizona_vol_ramp_text[] = {
611 "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
612 "15ms/6dB", "30ms/6dB",
613};
614
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100615SOC_ENUM_SINGLE_DECL(arizona_in_vd_ramp,
616 ARIZONA_INPUT_VOLUME_RAMP,
617 ARIZONA_IN_VD_RAMP_SHIFT,
618 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900619EXPORT_SYMBOL_GPL(arizona_in_vd_ramp);
620
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100621SOC_ENUM_SINGLE_DECL(arizona_in_vi_ramp,
622 ARIZONA_INPUT_VOLUME_RAMP,
623 ARIZONA_IN_VI_RAMP_SHIFT,
624 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900625EXPORT_SYMBOL_GPL(arizona_in_vi_ramp);
626
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100627SOC_ENUM_SINGLE_DECL(arizona_out_vd_ramp,
628 ARIZONA_OUTPUT_VOLUME_RAMP,
629 ARIZONA_OUT_VD_RAMP_SHIFT,
630 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900631EXPORT_SYMBOL_GPL(arizona_out_vd_ramp);
632
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100633SOC_ENUM_SINGLE_DECL(arizona_out_vi_ramp,
634 ARIZONA_OUTPUT_VOLUME_RAMP,
635 ARIZONA_OUT_VI_RAMP_SHIFT,
636 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900637EXPORT_SYMBOL_GPL(arizona_out_vi_ramp);
638
Mark Brown07ed8732012-06-18 21:08:44 +0100639static const char *arizona_lhpf_mode_text[] = {
640 "Low-pass", "High-pass"
641};
642
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100643SOC_ENUM_SINGLE_DECL(arizona_lhpf1_mode,
644 ARIZONA_HPLPF1_1,
645 ARIZONA_LHPF1_MODE_SHIFT,
646 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100647EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
648
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100649SOC_ENUM_SINGLE_DECL(arizona_lhpf2_mode,
650 ARIZONA_HPLPF2_1,
651 ARIZONA_LHPF2_MODE_SHIFT,
652 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100653EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
654
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100655SOC_ENUM_SINGLE_DECL(arizona_lhpf3_mode,
656 ARIZONA_HPLPF3_1,
657 ARIZONA_LHPF3_MODE_SHIFT,
658 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100659EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
660
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100661SOC_ENUM_SINGLE_DECL(arizona_lhpf4_mode,
662 ARIZONA_HPLPF4_1,
663 ARIZONA_LHPF4_MODE_SHIFT,
664 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100665EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
666
Mark Brown845571c2012-12-18 13:47:57 +0000667static const char *arizona_ng_hold_text[] = {
668 "30ms", "120ms", "250ms", "500ms",
669};
670
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100671SOC_ENUM_SINGLE_DECL(arizona_ng_hold,
672 ARIZONA_NOISE_GATE_CONTROL,
673 ARIZONA_NGATE_HOLD_SHIFT,
674 arizona_ng_hold_text);
Mark Brown845571c2012-12-18 13:47:57 +0000675EXPORT_SYMBOL_GPL(arizona_ng_hold);
676
Charles Keepax254dc322013-11-19 16:04:03 +0000677static const char * const arizona_in_hpf_cut_text[] = {
678 "2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz"
679};
680
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100681SOC_ENUM_SINGLE_DECL(arizona_in_hpf_cut_enum,
682 ARIZONA_HPF_CONTROL,
683 ARIZONA_IN_HPF_CUT_SHIFT,
684 arizona_in_hpf_cut_text);
Charles Keepax254dc322013-11-19 16:04:03 +0000685EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum);
686
Charles Keepaxc7f38432013-08-06 17:03:55 +0100687static const char * const arizona_in_dmic_osr_text[] = {
Charles Keepaxef326f42014-11-12 14:55:26 +0000688 "1.536MHz", "3.072MHz", "6.144MHz", "768kHz",
Charles Keepaxc7f38432013-08-06 17:03:55 +0100689};
690
691const struct soc_enum arizona_in_dmic_osr[] = {
692 SOC_ENUM_SINGLE(ARIZONA_IN1L_CONTROL, ARIZONA_IN1_OSR_SHIFT,
693 ARRAY_SIZE(arizona_in_dmic_osr_text),
694 arizona_in_dmic_osr_text),
695 SOC_ENUM_SINGLE(ARIZONA_IN2L_CONTROL, ARIZONA_IN2_OSR_SHIFT,
696 ARRAY_SIZE(arizona_in_dmic_osr_text),
697 arizona_in_dmic_osr_text),
698 SOC_ENUM_SINGLE(ARIZONA_IN3L_CONTROL, ARIZONA_IN3_OSR_SHIFT,
699 ARRAY_SIZE(arizona_in_dmic_osr_text),
700 arizona_in_dmic_osr_text),
701 SOC_ENUM_SINGLE(ARIZONA_IN4L_CONTROL, ARIZONA_IN4_OSR_SHIFT,
702 ARRAY_SIZE(arizona_in_dmic_osr_text),
703 arizona_in_dmic_osr_text),
704};
705EXPORT_SYMBOL_GPL(arizona_in_dmic_osr);
706
Charles Keepaxd1901062015-11-19 16:11:10 +0000707static const char * const arizona_anc_input_src_text[] = {
708 "None", "IN1", "IN2", "IN3", "IN4",
709};
710
711static const char * const arizona_anc_channel_src_text[] = {
712 "None", "Left", "Right", "Combine",
713};
714
715const struct soc_enum arizona_anc_input_src[] = {
716 SOC_ENUM_SINGLE(ARIZONA_ANC_SRC,
717 ARIZONA_IN_RXANCL_SEL_SHIFT,
718 ARRAY_SIZE(arizona_anc_input_src_text),
719 arizona_anc_input_src_text),
720 SOC_ENUM_SINGLE(ARIZONA_FCL_ADC_REFORMATTER_CONTROL,
721 ARIZONA_FCL_MIC_MODE_SEL,
722 ARRAY_SIZE(arizona_anc_channel_src_text),
723 arizona_anc_channel_src_text),
724 SOC_ENUM_SINGLE(ARIZONA_ANC_SRC,
725 ARIZONA_IN_RXANCR_SEL_SHIFT,
726 ARRAY_SIZE(arizona_anc_input_src_text),
727 arizona_anc_input_src_text),
728 SOC_ENUM_SINGLE(ARIZONA_FCR_ADC_REFORMATTER_CONTROL,
729 ARIZONA_FCR_MIC_MODE_SEL,
730 ARRAY_SIZE(arizona_anc_channel_src_text),
731 arizona_anc_channel_src_text),
732};
733EXPORT_SYMBOL_GPL(arizona_anc_input_src);
734
735static const char * const arizona_anc_ng_texts[] = {
736 "None",
737 "Internal",
738 "External",
739};
740
741SOC_ENUM_SINGLE_DECL(arizona_anc_ng_enum, SND_SOC_NOPM, 0,
742 arizona_anc_ng_texts);
743EXPORT_SYMBOL_GPL(arizona_anc_ng_enum);
744
745static const char * const arizona_output_anc_src_text[] = {
746 "None", "RXANCL", "RXANCR",
747};
748
749const struct soc_enum arizona_output_anc_src[] = {
750 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L,
751 ARIZONA_OUT1L_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_1R,
755 ARIZONA_OUT1R_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_2L,
759 ARIZONA_OUT2L_ANC_SRC_SHIFT,
760 ARRAY_SIZE(arizona_output_anc_src_text),
761 arizona_output_anc_src_text),
762 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2R,
763 ARIZONA_OUT2R_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_3L,
767 ARIZONA_OUT3L_ANC_SRC_SHIFT,
768 ARRAY_SIZE(arizona_output_anc_src_text),
769 arizona_output_anc_src_text),
770 SOC_ENUM_SINGLE(ARIZONA_DAC_VOLUME_LIMIT_3R,
771 ARIZONA_OUT3R_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_4L,
775 ARIZONA_OUT4L_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_4R,
779 ARIZONA_OUT4R_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_5L,
783 ARIZONA_OUT5L_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_5R,
787 ARIZONA_OUT5R_ANC_SRC_SHIFT,
788 ARRAY_SIZE(arizona_output_anc_src_text),
789 arizona_output_anc_src_text),
790 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_6L,
791 ARIZONA_OUT6L_ANC_SRC_SHIFT,
792 ARRAY_SIZE(arizona_output_anc_src_text),
793 arizona_output_anc_src_text),
794 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_6R,
795 ARIZONA_OUT6R_ANC_SRC_SHIFT,
796 ARRAY_SIZE(arizona_output_anc_src_text),
797 arizona_output_anc_src_text),
798};
799EXPORT_SYMBOL_GPL(arizona_output_anc_src);
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 Keepax054e1b42015-01-20 16:31:50 +0000878
Mark Brown1a2c7d52013-03-24 22:50:23 +0000879 switch (event) {
Charles Keepaxe1ae5fb2015-01-20 16:31:51 +0000880 case SND_SOC_DAPM_PRE_PMU:
881 switch (w->shift) {
882 case ARIZONA_OUT1L_ENA_SHIFT:
883 case ARIZONA_OUT1R_ENA_SHIFT:
884 case ARIZONA_OUT2L_ENA_SHIFT:
885 case ARIZONA_OUT2R_ENA_SHIFT:
886 case ARIZONA_OUT3L_ENA_SHIFT:
887 case ARIZONA_OUT3R_ENA_SHIFT:
888 priv->out_up_pending++;
889 priv->out_up_delay += 17;
890 break;
891 default:
892 break;
893 }
894 break;
Mark Brown1a2c7d52013-03-24 22:50:23 +0000895 case SND_SOC_DAPM_POST_PMU:
896 switch (w->shift) {
897 case ARIZONA_OUT1L_ENA_SHIFT:
898 case ARIZONA_OUT1R_ENA_SHIFT:
899 case ARIZONA_OUT2L_ENA_SHIFT:
900 case ARIZONA_OUT2R_ENA_SHIFT:
901 case ARIZONA_OUT3L_ENA_SHIFT:
902 case ARIZONA_OUT3R_ENA_SHIFT:
Charles Keepaxe1ae5fb2015-01-20 16:31:51 +0000903 priv->out_up_pending--;
904 if (!priv->out_up_pending) {
905 msleep(priv->out_up_delay);
906 priv->out_up_delay = 0;
907 }
Mark Brown1a2c7d52013-03-24 22:50:23 +0000908 break;
909
910 default:
911 break;
912 }
913 break;
Charles Keepax054e1b42015-01-20 16:31:50 +0000914 case SND_SOC_DAPM_PRE_PMD:
915 switch (w->shift) {
916 case ARIZONA_OUT1L_ENA_SHIFT:
917 case ARIZONA_OUT1R_ENA_SHIFT:
918 case ARIZONA_OUT2L_ENA_SHIFT:
919 case ARIZONA_OUT2R_ENA_SHIFT:
920 case ARIZONA_OUT3L_ENA_SHIFT:
921 case ARIZONA_OUT3R_ENA_SHIFT:
922 priv->out_down_pending++;
923 priv->out_down_delay++;
924 break;
925 default:
926 break;
927 }
928 break;
929 case SND_SOC_DAPM_POST_PMD:
930 switch (w->shift) {
931 case ARIZONA_OUT1L_ENA_SHIFT:
932 case ARIZONA_OUT1R_ENA_SHIFT:
933 case ARIZONA_OUT2L_ENA_SHIFT:
934 case ARIZONA_OUT2R_ENA_SHIFT:
935 case ARIZONA_OUT3L_ENA_SHIFT:
936 case ARIZONA_OUT3R_ENA_SHIFT:
937 priv->out_down_pending--;
938 if (!priv->out_down_pending) {
939 msleep(priv->out_down_delay);
940 priv->out_down_delay = 0;
941 }
942 break;
943 default:
944 break;
945 }
946 break;
Charles Keepaxbee261b2015-09-16 13:59:40 +0100947 default:
948 break;
Mark Brown1a2c7d52013-03-24 22:50:23 +0000949 }
950
Mark Brown07ed8732012-06-18 21:08:44 +0100951 return 0;
952}
953EXPORT_SYMBOL_GPL(arizona_out_ev);
954
Mark Brownf607e312013-02-22 18:36:53 +0000955int arizona_hp_ev(struct snd_soc_dapm_widget *w,
956 struct snd_kcontrol *kcontrol,
957 int event)
958{
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100959 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
960 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brown3c43c692013-12-12 00:49:22 +0000961 struct arizona *arizona = priv->arizona;
Mark Brownf607e312013-02-22 18:36:53 +0000962 unsigned int mask = 1 << w->shift;
963 unsigned int val;
964
965 switch (event) {
966 case SND_SOC_DAPM_POST_PMU:
967 val = mask;
968 break;
969 case SND_SOC_DAPM_PRE_PMD:
970 val = 0;
971 break;
Charles Keepaxe1ae5fb2015-01-20 16:31:51 +0000972 case SND_SOC_DAPM_PRE_PMU:
Charles Keepax054e1b42015-01-20 16:31:50 +0000973 case SND_SOC_DAPM_POST_PMD:
974 return arizona_out_ev(w, kcontrol, event);
Mark Brownf607e312013-02-22 18:36:53 +0000975 default:
976 return -EINVAL;
977 }
978
979 /* Store the desired state for the HP outputs */
980 priv->arizona->hp_ena &= ~mask;
981 priv->arizona->hp_ena |= val;
982
Charles Keepax112bdfa2015-02-16 15:41:02 +0000983 /* Force off if HPDET clamp is active */
984 if (priv->arizona->hpdet_clamp)
Mark Brownf607e312013-02-22 18:36:53 +0000985 val = 0;
986
Mark Brown3c43c692013-12-12 00:49:22 +0000987 regmap_update_bits_async(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1,
988 mask, val);
Mark Brownf607e312013-02-22 18:36:53 +0000989
990 return arizona_out_ev(w, kcontrol, event);
991}
992EXPORT_SYMBOL_GPL(arizona_hp_ev);
993
Richard Fitzgerald346d9682015-06-02 11:53:33 +0100994static int arizona_dvfs_enable(struct snd_soc_codec *codec)
995{
996 const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
997 struct arizona *arizona = priv->arizona;
998 int ret;
999
1000 ret = regulator_set_voltage(arizona->dcvdd, 1800000, 1800000);
1001 if (ret) {
1002 dev_err(codec->dev, "Failed to boost DCVDD: %d\n", ret);
1003 return ret;
1004 }
1005
1006 ret = regmap_update_bits(arizona->regmap,
1007 ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
1008 ARIZONA_SUBSYS_MAX_FREQ,
1009 ARIZONA_SUBSYS_MAX_FREQ);
1010 if (ret) {
1011 dev_err(codec->dev, "Failed to enable subsys max: %d\n", ret);
1012 regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
1013 return ret;
1014 }
1015
1016 return 0;
1017}
1018
1019static int arizona_dvfs_disable(struct snd_soc_codec *codec)
1020{
1021 const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1022 struct arizona *arizona = priv->arizona;
1023 int ret;
1024
1025 ret = regmap_update_bits(arizona->regmap,
1026 ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
1027 ARIZONA_SUBSYS_MAX_FREQ, 0);
1028 if (ret) {
1029 dev_err(codec->dev, "Failed to disable subsys max: %d\n", ret);
1030 return ret;
1031 }
1032
1033 ret = regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
1034 if (ret) {
1035 dev_err(codec->dev, "Failed to unboost DCVDD: %d\n", ret);
1036 return ret;
1037 }
1038
1039 return 0;
1040}
1041
1042int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags)
1043{
1044 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1045 int ret = 0;
1046
1047 mutex_lock(&priv->dvfs_lock);
1048
1049 if (!priv->dvfs_cached && !priv->dvfs_reqs) {
1050 ret = arizona_dvfs_enable(codec);
1051 if (ret)
1052 goto err;
1053 }
1054
1055 priv->dvfs_reqs |= flags;
1056err:
1057 mutex_unlock(&priv->dvfs_lock);
1058 return ret;
1059}
1060EXPORT_SYMBOL_GPL(arizona_dvfs_up);
1061
1062int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags)
1063{
1064 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1065 unsigned int old_reqs;
1066 int ret = 0;
1067
1068 mutex_lock(&priv->dvfs_lock);
1069
1070 old_reqs = priv->dvfs_reqs;
1071 priv->dvfs_reqs &= ~flags;
1072
1073 if (!priv->dvfs_cached && old_reqs && !priv->dvfs_reqs)
1074 ret = arizona_dvfs_disable(codec);
1075
1076 mutex_unlock(&priv->dvfs_lock);
1077 return ret;
1078}
1079EXPORT_SYMBOL_GPL(arizona_dvfs_down);
1080
1081int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
1082 struct snd_kcontrol *kcontrol, int event)
1083{
1084 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
1085 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1086 int ret = 0;
1087
1088 mutex_lock(&priv->dvfs_lock);
1089
1090 switch (event) {
1091 case SND_SOC_DAPM_POST_PMU:
1092 if (priv->dvfs_reqs)
1093 ret = arizona_dvfs_enable(codec);
1094
1095 priv->dvfs_cached = false;
1096 break;
1097 case SND_SOC_DAPM_PRE_PMD:
1098 /* We must ensure DVFS is disabled before the codec goes into
1099 * suspend so that we are never in an illegal state of DVFS
1100 * enabled without enough DCVDD
1101 */
1102 priv->dvfs_cached = true;
1103
1104 if (priv->dvfs_reqs)
1105 ret = arizona_dvfs_disable(codec);
1106 break;
1107 default:
1108 break;
1109 }
1110
1111 mutex_unlock(&priv->dvfs_lock);
1112 return ret;
1113}
1114EXPORT_SYMBOL_GPL(arizona_dvfs_sysclk_ev);
1115
1116void arizona_init_dvfs(struct arizona_priv *priv)
1117{
1118 mutex_init(&priv->dvfs_lock);
1119}
1120EXPORT_SYMBOL_GPL(arizona_init_dvfs);
1121
Charles Keepaxd1901062015-11-19 16:11:10 +00001122int arizona_anc_ev(struct snd_soc_dapm_widget *w,
1123 struct snd_kcontrol *kcontrol,
1124 int event)
1125{
1126 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
1127 unsigned int mask = 0x3 << w->shift;
1128 unsigned int val;
1129
1130 switch (event) {
1131 case SND_SOC_DAPM_POST_PMU:
1132 val = 1 << w->shift;
1133 break;
1134 case SND_SOC_DAPM_PRE_PMD:
1135 val = 1 << (w->shift + 1);
1136 break;
1137 default:
1138 return 0;
1139 }
1140
1141 snd_soc_update_bits(codec, ARIZONA_CLOCK_CONTROL, mask, val);
1142
1143 return 0;
1144}
1145EXPORT_SYMBOL_GPL(arizona_anc_ev);
1146
Richard Fitzgerald341604a2015-11-03 14:24:12 +00001147static unsigned int arizona_opclk_ref_48k_rates[] = {
Mark Browncbd840d2012-08-08 17:52:44 +01001148 6144000,
1149 12288000,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +00001150 24576000,
Mark Browncbd840d2012-08-08 17:52:44 +01001151 49152000,
1152};
1153
Richard Fitzgerald341604a2015-11-03 14:24:12 +00001154static unsigned int arizona_opclk_ref_44k1_rates[] = {
Mark Browncbd840d2012-08-08 17:52:44 +01001155 5644800,
1156 11289600,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +00001157 22579200,
Mark Browncbd840d2012-08-08 17:52:44 +01001158 45158400,
1159};
1160
1161static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
1162 unsigned int freq)
1163{
1164 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1165 unsigned int reg;
1166 unsigned int *rates;
1167 int ref, div, refclk;
1168
1169 switch (clk) {
1170 case ARIZONA_CLK_OPCLK:
1171 reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
1172 refclk = priv->sysclk;
1173 break;
1174 case ARIZONA_CLK_ASYNC_OPCLK:
1175 reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
1176 refclk = priv->asyncclk;
1177 break;
1178 default:
1179 return -EINVAL;
1180 }
1181
1182 if (refclk % 8000)
Richard Fitzgerald341604a2015-11-03 14:24:12 +00001183 rates = arizona_opclk_ref_44k1_rates;
Mark Browncbd840d2012-08-08 17:52:44 +01001184 else
Richard Fitzgerald341604a2015-11-03 14:24:12 +00001185 rates = arizona_opclk_ref_48k_rates;
Mark Browncbd840d2012-08-08 17:52:44 +01001186
Richard Fitzgerald341604a2015-11-03 14:24:12 +00001187 for (ref = 0; ref < ARRAY_SIZE(arizona_opclk_ref_48k_rates) &&
Mark Browncbd840d2012-08-08 17:52:44 +01001188 rates[ref] <= refclk; ref++) {
1189 div = 1;
1190 while (rates[ref] / div >= freq && div < 32) {
1191 if (rates[ref] / div == freq) {
1192 dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
1193 freq);
1194 snd_soc_update_bits(codec, reg,
1195 ARIZONA_OPCLK_DIV_MASK |
1196 ARIZONA_OPCLK_SEL_MASK,
1197 (div <<
1198 ARIZONA_OPCLK_DIV_SHIFT) |
1199 ref);
1200 return 0;
1201 }
1202 div++;
1203 }
1204 }
1205
1206 dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
1207 return -EINVAL;
1208}
1209
Mark Brown07ed8732012-06-18 21:08:44 +01001210int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
1211 int source, unsigned int freq, int dir)
1212{
1213 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1214 struct arizona *arizona = priv->arizona;
1215 char *name;
1216 unsigned int reg;
1217 unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
1218 unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
Charles Keepax1f0e1ea2015-12-03 18:15:07 +00001219 int *clk;
Mark Brown07ed8732012-06-18 21:08:44 +01001220
1221 switch (clk_id) {
1222 case ARIZONA_CLK_SYSCLK:
1223 name = "SYSCLK";
1224 reg = ARIZONA_SYSTEM_CLOCK_1;
1225 clk = &priv->sysclk;
1226 mask |= ARIZONA_SYSCLK_FRAC;
1227 break;
1228 case ARIZONA_CLK_ASYNCCLK:
1229 name = "ASYNCCLK";
1230 reg = ARIZONA_ASYNC_CLOCK_1;
1231 clk = &priv->asyncclk;
1232 break;
Mark Browncbd840d2012-08-08 17:52:44 +01001233 case ARIZONA_CLK_OPCLK:
1234 case ARIZONA_CLK_ASYNC_OPCLK:
1235 return arizona_set_opclk(codec, clk_id, freq);
Mark Brown07ed8732012-06-18 21:08:44 +01001236 default:
1237 return -EINVAL;
1238 }
1239
1240 switch (freq) {
1241 case 5644800:
1242 case 6144000:
1243 break;
1244 case 11289600:
1245 case 12288000:
Mark Brown3f341f72013-03-08 15:22:29 +08001246 val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +01001247 break;
1248 case 22579200:
1249 case 24576000:
Mark Brown3f341f72013-03-08 15:22:29 +08001250 val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +01001251 break;
1252 case 45158400:
1253 case 49152000:
Mark Brown3f341f72013-03-08 15:22:29 +08001254 val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +01001255 break;
Mark Brown38113362012-11-26 16:01:37 +00001256 case 67737600:
1257 case 73728000:
Mark Brown3f341f72013-03-08 15:22:29 +08001258 val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +00001259 break;
1260 case 90316800:
1261 case 98304000:
Mark Brown3f341f72013-03-08 15:22:29 +08001262 val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +00001263 break;
1264 case 135475200:
1265 case 147456000:
Mark Brown3f341f72013-03-08 15:22:29 +08001266 val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +00001267 break;
Mark Brownf2c26d42013-01-21 16:09:36 +09001268 case 0:
1269 dev_dbg(arizona->dev, "%s cleared\n", name);
1270 *clk = freq;
1271 return 0;
Mark Brown07ed8732012-06-18 21:08:44 +01001272 default:
1273 return -EINVAL;
1274 }
1275
1276 *clk = freq;
1277
1278 if (freq % 6144000)
1279 val |= ARIZONA_SYSCLK_FRAC;
1280
1281 dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
1282
1283 return regmap_update_bits(arizona->regmap, reg, mask, val);
1284}
1285EXPORT_SYMBOL_GPL(arizona_set_sysclk);
1286
1287static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
1288{
1289 struct snd_soc_codec *codec = dai->codec;
Mark Brown3c43c692013-12-12 00:49:22 +00001290 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1291 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +01001292 int lrclk, bclk, mode, base;
1293
1294 base = dai->driver->base;
1295
1296 lrclk = 0;
1297 bclk = 0;
1298
1299 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
1300 case SND_SOC_DAIFMT_DSP_A:
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001301 mode = ARIZONA_FMT_DSP_MODE_A;
1302 break;
1303 case SND_SOC_DAIFMT_DSP_B:
1304 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
1305 != SND_SOC_DAIFMT_CBM_CFM) {
1306 arizona_aif_err(dai, "DSP_B not valid in slave mode\n");
1307 return -EINVAL;
1308 }
1309 mode = ARIZONA_FMT_DSP_MODE_B;
Mark Brown07ed8732012-06-18 21:08:44 +01001310 break;
Mark Brown07ed8732012-06-18 21:08:44 +01001311 case SND_SOC_DAIFMT_I2S:
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001312 mode = ARIZONA_FMT_I2S_MODE;
1313 break;
1314 case SND_SOC_DAIFMT_LEFT_J:
1315 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
1316 != SND_SOC_DAIFMT_CBM_CFM) {
1317 arizona_aif_err(dai, "LEFT_J not valid in slave mode\n");
1318 return -EINVAL;
1319 }
1320 mode = ARIZONA_FMT_LEFT_JUSTIFIED_MODE;
Mark Brown07ed8732012-06-18 21:08:44 +01001321 break;
Mark Brown07ed8732012-06-18 21:08:44 +01001322 default:
1323 arizona_aif_err(dai, "Unsupported DAI format %d\n",
1324 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
1325 return -EINVAL;
1326 }
1327
1328 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
1329 case SND_SOC_DAIFMT_CBS_CFS:
1330 break;
1331 case SND_SOC_DAIFMT_CBS_CFM:
1332 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
1333 break;
1334 case SND_SOC_DAIFMT_CBM_CFS:
1335 bclk |= ARIZONA_AIF1_BCLK_MSTR;
1336 break;
1337 case SND_SOC_DAIFMT_CBM_CFM:
1338 bclk |= ARIZONA_AIF1_BCLK_MSTR;
1339 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
1340 break;
1341 default:
1342 arizona_aif_err(dai, "Unsupported master mode %d\n",
1343 fmt & SND_SOC_DAIFMT_MASTER_MASK);
1344 return -EINVAL;
1345 }
1346
1347 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1348 case SND_SOC_DAIFMT_NB_NF:
1349 break;
1350 case SND_SOC_DAIFMT_IB_IF:
1351 bclk |= ARIZONA_AIF1_BCLK_INV;
1352 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
1353 break;
1354 case SND_SOC_DAIFMT_IB_NF:
1355 bclk |= ARIZONA_AIF1_BCLK_INV;
1356 break;
1357 case SND_SOC_DAIFMT_NB_IF:
1358 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
1359 break;
1360 default:
1361 return -EINVAL;
1362 }
1363
Mark Brown3c43c692013-12-12 00:49:22 +00001364 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_BCLK_CTRL,
1365 ARIZONA_AIF1_BCLK_INV |
1366 ARIZONA_AIF1_BCLK_MSTR,
1367 bclk);
1368 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_TX_PIN_CTRL,
1369 ARIZONA_AIF1TX_LRCLK_INV |
1370 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
1371 regmap_update_bits_async(arizona->regmap,
1372 base + ARIZONA_AIF_RX_PIN_CTRL,
1373 ARIZONA_AIF1RX_LRCLK_INV |
1374 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
1375 regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FORMAT,
1376 ARIZONA_AIF1_FMT_MASK, mode);
Mark Brown07ed8732012-06-18 21:08:44 +01001377
1378 return 0;
1379}
1380
Mark Brown949e6bc2012-07-04 18:58:04 +01001381static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001382 -1,
1383 48000,
1384 64000,
1385 96000,
1386 128000,
1387 192000,
1388 256000,
1389 384000,
1390 512000,
1391 768000,
1392 1024000,
1393 1536000,
1394 2048000,
1395 3072000,
1396 4096000,
1397 6144000,
1398 8192000,
1399 12288000,
1400 24576000,
1401};
1402
Mark Brown949e6bc2012-07-04 18:58:04 +01001403static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001404 -1,
1405 44100,
1406 58800,
1407 88200,
1408 117600,
1409 177640,
1410 235200,
1411 352800,
1412 470400,
1413 705600,
1414 940800,
1415 1411200,
1416 1881600,
Heather Lomond4758be32012-09-05 05:02:10 -04001417 2822400,
Mark Brown07ed8732012-06-18 21:08:44 +01001418 3763200,
1419 5644800,
1420 7526400,
1421 11289600,
1422 22579200,
1423};
1424
Charles Keepaxd81221f2016-02-04 16:29:01 +00001425static const unsigned int arizona_sr_vals[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001426 0,
1427 12000,
1428 24000,
1429 48000,
1430 96000,
1431 192000,
1432 384000,
1433 768000,
1434 0,
1435 11025,
1436 22050,
1437 44100,
1438 88200,
1439 176400,
1440 352800,
1441 705600,
1442 4000,
1443 8000,
1444 16000,
1445 32000,
1446 64000,
1447 128000,
1448 256000,
1449 512000,
1450};
1451
Charles Keepaxd81221f2016-02-04 16:29:01 +00001452#define ARIZONA_48K_RATE_MASK 0x0F003E
1453#define ARIZONA_44K1_RATE_MASK 0x003E00
1454#define ARIZONA_RATE_MASK (ARIZONA_48K_RATE_MASK | ARIZONA_44K1_RATE_MASK)
1455
1456static const struct snd_pcm_hw_constraint_list arizona_constraint = {
1457 .count = ARRAY_SIZE(arizona_sr_vals),
1458 .list = arizona_sr_vals,
1459};
1460
Mark Brown5b2eec32012-07-04 17:32:05 +01001461static int arizona_startup(struct snd_pcm_substream *substream,
1462 struct snd_soc_dai *dai)
1463{
1464 struct snd_soc_codec *codec = dai->codec;
1465 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1466 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown5b2eec32012-07-04 17:32:05 +01001467 unsigned int base_rate;
1468
Charles Keepax26eb5a92015-12-29 09:49:19 +00001469 if (!substream->runtime)
1470 return 0;
1471
Mark Brown5b2eec32012-07-04 17:32:05 +01001472 switch (dai_priv->clk) {
1473 case ARIZONA_CLK_SYSCLK:
1474 base_rate = priv->sysclk;
1475 break;
1476 case ARIZONA_CLK_ASYNCCLK:
1477 base_rate = priv->asyncclk;
1478 break;
1479 default:
1480 return 0;
1481 }
1482
Mark Brownf2c26d42013-01-21 16:09:36 +09001483 if (base_rate == 0)
Charles Keepaxd81221f2016-02-04 16:29:01 +00001484 dai_priv->constraint.mask = ARIZONA_RATE_MASK;
1485 else if (base_rate % 8000)
1486 dai_priv->constraint.mask = ARIZONA_44K1_RATE_MASK;
Mark Brown5b2eec32012-07-04 17:32:05 +01001487 else
Charles Keepaxd81221f2016-02-04 16:29:01 +00001488 dai_priv->constraint.mask = ARIZONA_48K_RATE_MASK;
Mark Brown5b2eec32012-07-04 17:32:05 +01001489
1490 return snd_pcm_hw_constraint_list(substream->runtime, 0,
1491 SNDRV_PCM_HW_PARAM_RATE,
Charles Keepaxd81221f2016-02-04 16:29:01 +00001492 &dai_priv->constraint);
Mark Brown5b2eec32012-07-04 17:32:05 +01001493}
1494
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001495static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec,
1496 unsigned int rate)
1497{
1498 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1499 struct arizona *arizona = priv->arizona;
Nariman Poushin8019ff62015-07-16 16:36:21 +01001500 struct reg_sequence dac_comp[] = {
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001501 { 0x80, 0x3 },
1502 { ARIZONA_DAC_COMP_1, 0 },
1503 { ARIZONA_DAC_COMP_2, 0 },
1504 { 0x80, 0x0 },
1505 };
1506
Lars-Peter Clausend74bcaa2014-11-09 17:00:59 +01001507 mutex_lock(&arizona->dac_comp_lock);
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001508
1509 dac_comp[1].def = arizona->dac_comp_coeff;
1510 if (rate >= 176400)
1511 dac_comp[2].def = arizona->dac_comp_enabled;
1512
Lars-Peter Clausend74bcaa2014-11-09 17:00:59 +01001513 mutex_unlock(&arizona->dac_comp_lock);
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001514
1515 regmap_multi_reg_write(arizona->regmap,
1516 dac_comp,
1517 ARRAY_SIZE(dac_comp));
1518}
1519
Mark Brownb272efc2012-10-10 15:10:08 +09001520static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
1521 struct snd_pcm_hw_params *params,
1522 struct snd_soc_dai *dai)
Mark Brown07ed8732012-06-18 21:08:44 +01001523{
1524 struct snd_soc_codec *codec = dai->codec;
Mark Brownc013b272012-07-04 20:05:57 +01001525 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1526 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown07ed8732012-06-18 21:08:44 +01001527 int base = dai->driver->base;
Richard Fitzgerald2c118b42015-06-02 11:53:35 +01001528 int i, sr_val, ret;
Mark Brownb272efc2012-10-10 15:10:08 +09001529
1530 /*
1531 * We will need to be more flexible than this in future,
1532 * currently we use a single sample rate for SYSCLK.
1533 */
1534 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
1535 if (arizona_sr_vals[i] == params_rate(params))
1536 break;
1537 if (i == ARRAY_SIZE(arizona_sr_vals)) {
1538 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1539 params_rate(params));
1540 return -EINVAL;
1541 }
1542 sr_val = i;
1543
Richard Fitzgerald2c118b42015-06-02 11:53:35 +01001544 switch (priv->arizona->type) {
1545 case WM5102:
1546 case WM8997:
1547 if (arizona_sr_vals[sr_val] >= 88200)
1548 ret = arizona_dvfs_up(codec, ARIZONA_DVFS_SR1_RQ);
1549 else
1550 ret = arizona_dvfs_down(codec, ARIZONA_DVFS_SR1_RQ);
1551
1552 if (ret) {
1553 arizona_aif_err(dai, "Failed to change DVFS %d\n", ret);
1554 return ret;
1555 }
1556 break;
1557 default:
1558 break;
1559 }
1560
Mark Brownb272efc2012-10-10 15:10:08 +09001561 switch (dai_priv->clk) {
1562 case ARIZONA_CLK_SYSCLK:
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001563 switch (priv->arizona->type) {
1564 case WM5102:
1565 arizona_wm5102_set_dac_comp(codec,
1566 params_rate(params));
1567 break;
1568 default:
1569 break;
1570 }
1571
Mark Brownb272efc2012-10-10 15:10:08 +09001572 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
1573 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
1574 if (base)
1575 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1576 ARIZONA_AIF1_RATE_MASK, 0);
1577 break;
1578 case ARIZONA_CLK_ASYNCCLK:
1579 snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
Charles Keepaxc24084d2014-09-01 15:48:52 +01001580 ARIZONA_ASYNC_SAMPLE_RATE_1_MASK, sr_val);
Mark Brownb272efc2012-10-10 15:10:08 +09001581 if (base)
1582 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1583 ARIZONA_AIF1_RATE_MASK,
1584 8 << ARIZONA_AIF1_RATE_SHIFT);
1585 break;
1586 default:
1587 arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
1588 return -EINVAL;
1589 }
1590
1591 return 0;
1592}
1593
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001594static bool arizona_aif_cfg_changed(struct snd_soc_codec *codec,
1595 int base, int bclk, int lrclk, int frame)
1596{
1597 int val;
1598
1599 val = snd_soc_read(codec, base + ARIZONA_AIF_BCLK_CTRL);
1600 if (bclk != (val & ARIZONA_AIF1_BCLK_FREQ_MASK))
1601 return true;
1602
1603 val = snd_soc_read(codec, base + ARIZONA_AIF_TX_BCLK_RATE);
1604 if (lrclk != (val & ARIZONA_AIF1TX_BCPF_MASK))
1605 return true;
1606
1607 val = snd_soc_read(codec, base + ARIZONA_AIF_FRAME_CTRL_1);
1608 if (frame != (val & (ARIZONA_AIF1TX_WL_MASK |
1609 ARIZONA_AIF1TX_SLOT_LEN_MASK)))
1610 return true;
1611
1612 return false;
1613}
1614
Mark Brown07ed8732012-06-18 21:08:44 +01001615static int arizona_hw_params(struct snd_pcm_substream *substream,
1616 struct snd_pcm_hw_params *params,
1617 struct snd_soc_dai *dai)
1618{
1619 struct snd_soc_codec *codec = dai->codec;
1620 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brownc94aa302013-01-17 16:35:14 +09001621 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +01001622 int base = dai->driver->base;
1623 const int *rates;
Mark Brown76bf9692013-03-05 14:17:47 +08001624 int i, ret, val;
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001625 int channels = params_channels(params);
Mark Brownc94aa302013-01-17 16:35:14 +09001626 int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001627 int tdm_width = arizona->tdm_width[dai->id - 1];
1628 int tdm_slots = arizona->tdm_slots[dai->id - 1];
Mark Brownc94aa302013-01-17 16:35:14 +09001629 int bclk, lrclk, wl, frame, bclk_target;
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001630 bool reconfig;
1631 unsigned int aif_tx_state, aif_rx_state;
Mark Brown07ed8732012-06-18 21:08:44 +01001632
Nikesh Oswale73694d2015-12-23 14:18:05 +00001633 if (params_rate(params) % 4000)
Mark Brown949e6bc2012-07-04 18:58:04 +01001634 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001635 else
Mark Brown949e6bc2012-07-04 18:58:04 +01001636 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001637
Charles Keepax5ed68f02015-07-09 11:28:46 +01001638 wl = params_width(params);
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001639
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001640 if (tdm_slots) {
1641 arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n",
1642 tdm_slots, tdm_width);
1643 bclk_target = tdm_slots * tdm_width * params_rate(params);
1644 channels = tdm_slots;
1645 } else {
1646 bclk_target = snd_soc_params_to_bclk(params);
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001647 tdm_width = wl;
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001648 }
1649
1650 if (chan_limit && chan_limit < channels) {
Mark Brownc94aa302013-01-17 16:35:14 +09001651 arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001652 bclk_target /= channels;
Mark Brownc94aa302013-01-17 16:35:14 +09001653 bclk_target *= chan_limit;
1654 }
1655
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001656 /* Force multiple of 2 channels for I2S mode */
Mark Brown76bf9692013-03-05 14:17:47 +08001657 val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001658 val &= ARIZONA_AIF1_FMT_MASK;
1659 if ((channels & 1) && (val == ARIZONA_FMT_I2S_MODE)) {
Mark Brown76bf9692013-03-05 14:17:47 +08001660 arizona_aif_dbg(dai, "Forcing stereo mode\n");
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001661 bclk_target /= channels;
1662 bclk_target *= channels + 1;
Mark Brown76bf9692013-03-05 14:17:47 +08001663 }
1664
Mark Brown949e6bc2012-07-04 18:58:04 +01001665 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brownc94aa302013-01-17 16:35:14 +09001666 if (rates[i] >= bclk_target &&
Mark Brown50017652012-07-04 19:07:09 +01001667 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +01001668 bclk = i;
1669 break;
1670 }
1671 }
Mark Brown949e6bc2012-07-04 18:58:04 +01001672 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001673 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1674 params_rate(params));
1675 return -EINVAL;
1676 }
1677
Mark Brownb59e0f82013-01-17 14:15:59 +09001678 lrclk = rates[bclk] / params_rate(params);
Mark Brown07ed8732012-06-18 21:08:44 +01001679
1680 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
1681 rates[bclk], rates[bclk] / lrclk);
1682
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001683 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | tdm_width;
Mark Brown07ed8732012-06-18 21:08:44 +01001684
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001685 reconfig = arizona_aif_cfg_changed(codec, base, bclk, lrclk, frame);
1686
1687 if (reconfig) {
1688 /* Save AIF TX/RX state */
1689 aif_tx_state = snd_soc_read(codec,
1690 base + ARIZONA_AIF_TX_ENABLES);
1691 aif_rx_state = snd_soc_read(codec,
1692 base + ARIZONA_AIF_RX_ENABLES);
1693 /* Disable AIF TX/RX before reconfiguring it */
1694 regmap_update_bits_async(arizona->regmap,
1695 base + ARIZONA_AIF_TX_ENABLES, 0xff, 0x0);
1696 regmap_update_bits(arizona->regmap,
1697 base + ARIZONA_AIF_RX_ENABLES, 0xff, 0x0);
1698 }
1699
Mark Brownb272efc2012-10-10 15:10:08 +09001700 ret = arizona_hw_params_rate(substream, params, dai);
1701 if (ret != 0)
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001702 goto restore_aif;
Mark Brownc013b272012-07-04 20:05:57 +01001703
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001704 if (reconfig) {
1705 regmap_update_bits_async(arizona->regmap,
1706 base + ARIZONA_AIF_BCLK_CTRL,
1707 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
1708 regmap_update_bits_async(arizona->regmap,
1709 base + ARIZONA_AIF_TX_BCLK_RATE,
1710 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
1711 regmap_update_bits_async(arizona->regmap,
1712 base + ARIZONA_AIF_RX_BCLK_RATE,
1713 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
1714 regmap_update_bits_async(arizona->regmap,
1715 base + ARIZONA_AIF_FRAME_CTRL_1,
1716 ARIZONA_AIF1TX_WL_MASK |
1717 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
1718 regmap_update_bits(arizona->regmap,
1719 base + ARIZONA_AIF_FRAME_CTRL_2,
1720 ARIZONA_AIF1RX_WL_MASK |
1721 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
1722 }
Mark Brown07ed8732012-06-18 21:08:44 +01001723
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001724restore_aif:
1725 if (reconfig) {
1726 /* Restore AIF TX/RX state */
1727 regmap_update_bits_async(arizona->regmap,
1728 base + ARIZONA_AIF_TX_ENABLES,
1729 0xff, aif_tx_state);
1730 regmap_update_bits(arizona->regmap,
1731 base + ARIZONA_AIF_RX_ENABLES,
1732 0xff, aif_rx_state);
1733 }
1734 return ret;
Mark Brown07ed8732012-06-18 21:08:44 +01001735}
1736
Mark Brown410837a2012-07-05 17:26:59 +01001737static const char *arizona_dai_clk_str(int clk_id)
1738{
1739 switch (clk_id) {
1740 case ARIZONA_CLK_SYSCLK:
1741 return "SYSCLK";
1742 case ARIZONA_CLK_ASYNCCLK:
1743 return "ASYNCCLK";
1744 default:
1745 return "Unknown clock";
1746 }
1747}
1748
Mark Brown5b2eec32012-07-04 17:32:05 +01001749static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
1750 int clk_id, unsigned int freq, int dir)
1751{
1752 struct snd_soc_codec *codec = dai->codec;
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +02001753 struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
Mark Brown5b2eec32012-07-04 17:32:05 +01001754 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1755 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown410837a2012-07-05 17:26:59 +01001756 struct snd_soc_dapm_route routes[2];
Mark Brown5b2eec32012-07-04 17:32:05 +01001757
1758 switch (clk_id) {
1759 case ARIZONA_CLK_SYSCLK:
1760 case ARIZONA_CLK_ASYNCCLK:
1761 break;
1762 default:
1763 return -EINVAL;
1764 }
1765
Mark Brown410837a2012-07-05 17:26:59 +01001766 if (clk_id == dai_priv->clk)
1767 return 0;
1768
1769 if (dai->active) {
Mark Brown5b2eec32012-07-04 17:32:05 +01001770 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
1771 dai->id);
1772 return -EBUSY;
1773 }
1774
Mark Brownc8d35a62012-12-07 12:49:40 +09001775 dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1,
1776 arizona_dai_clk_str(clk_id));
1777
Mark Brown410837a2012-07-05 17:26:59 +01001778 memset(&routes, 0, sizeof(routes));
1779 routes[0].sink = dai->driver->capture.stream_name;
1780 routes[1].sink = dai->driver->playback.stream_name;
Mark Brown5b2eec32012-07-04 17:32:05 +01001781
Mark Brown410837a2012-07-05 17:26:59 +01001782 routes[0].source = arizona_dai_clk_str(dai_priv->clk);
1783 routes[1].source = arizona_dai_clk_str(dai_priv->clk);
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +02001784 snd_soc_dapm_del_routes(dapm, routes, ARRAY_SIZE(routes));
Mark Brown410837a2012-07-05 17:26:59 +01001785
1786 routes[0].source = arizona_dai_clk_str(clk_id);
1787 routes[1].source = arizona_dai_clk_str(clk_id);
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +02001788 snd_soc_dapm_add_routes(dapm, routes, ARRAY_SIZE(routes));
Mark Brown410837a2012-07-05 17:26:59 +01001789
Mark Brown0c778e82012-12-06 18:22:25 +09001790 dai_priv->clk = clk_id;
1791
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +02001792 return snd_soc_dapm_sync(dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +01001793}
1794
Mark Brown01df2592012-12-12 16:22:08 +09001795static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
1796{
1797 struct snd_soc_codec *codec = dai->codec;
1798 int base = dai->driver->base;
1799 unsigned int reg;
1800
1801 if (tristate)
1802 reg = ARIZONA_AIF1_TRI;
1803 else
1804 reg = 0;
1805
1806 return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1807 ARIZONA_AIF1_TRI, reg);
1808}
1809
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001810static void arizona_set_channels_to_mask(struct snd_soc_dai *dai,
1811 unsigned int base,
1812 int channels, unsigned int mask)
1813{
1814 struct snd_soc_codec *codec = dai->codec;
1815 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1816 struct arizona *arizona = priv->arizona;
1817 int slot, i;
1818
1819 for (i = 0; i < channels; ++i) {
1820 slot = ffs(mask) - 1;
1821 if (slot < 0)
1822 return;
1823
1824 regmap_write(arizona->regmap, base + i, slot);
1825
1826 mask &= ~(1 << slot);
1827 }
1828
1829 if (mask)
1830 arizona_aif_warn(dai, "Too many channels in TDM mask\n");
1831}
1832
1833static int arizona_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
1834 unsigned int rx_mask, int slots, int slot_width)
1835{
1836 struct snd_soc_codec *codec = dai->codec;
1837 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1838 struct arizona *arizona = priv->arizona;
1839 int base = dai->driver->base;
1840 int rx_max_chan = dai->driver->playback.channels_max;
1841 int tx_max_chan = dai->driver->capture.channels_max;
1842
1843 /* Only support TDM for the physical AIFs */
1844 if (dai->id > ARIZONA_MAX_AIF)
1845 return -ENOTSUPP;
1846
1847 if (slots == 0) {
1848 tx_mask = (1 << tx_max_chan) - 1;
1849 rx_mask = (1 << rx_max_chan) - 1;
1850 }
1851
1852 arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_3,
1853 tx_max_chan, tx_mask);
1854 arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_11,
1855 rx_max_chan, rx_mask);
1856
1857 arizona->tdm_width[dai->id - 1] = slot_width;
1858 arizona->tdm_slots[dai->id - 1] = slots;
1859
1860 return 0;
1861}
1862
Mark Brown07ed8732012-06-18 21:08:44 +01001863const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +01001864 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +01001865 .set_fmt = arizona_set_fmt,
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001866 .set_tdm_slot = arizona_set_tdm_slot,
Mark Brown07ed8732012-06-18 21:08:44 +01001867 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +01001868 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown01df2592012-12-12 16:22:08 +09001869 .set_tristate = arizona_set_tristate,
Mark Brown07ed8732012-06-18 21:08:44 +01001870};
Mark Browna8379872012-07-09 12:16:41 +01001871EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +01001872
Mark Brownbd1dd882013-05-17 13:29:03 +01001873const struct snd_soc_dai_ops arizona_simple_dai_ops = {
1874 .startup = arizona_startup,
1875 .hw_params = arizona_hw_params_rate,
1876 .set_sysclk = arizona_dai_set_sysclk,
1877};
1878EXPORT_SYMBOL_GPL(arizona_simple_dai_ops);
1879
Mark Brown5b2eec32012-07-04 17:32:05 +01001880int arizona_init_dai(struct arizona_priv *priv, int id)
1881{
1882 struct arizona_dai_priv *dai_priv = &priv->dai[id];
1883
1884 dai_priv->clk = ARIZONA_CLK_SYSCLK;
Charles Keepaxd81221f2016-02-04 16:29:01 +00001885 dai_priv->constraint = arizona_constraint;
Mark Brown5b2eec32012-07-04 17:32:05 +01001886
1887 return 0;
1888}
1889EXPORT_SYMBOL_GPL(arizona_init_dai);
1890
Mark Brown07ed8732012-06-18 21:08:44 +01001891static struct {
1892 unsigned int min;
1893 unsigned int max;
1894 u16 fratio;
1895 int ratio;
1896} fll_fratios[] = {
1897 { 0, 64000, 4, 16 },
1898 { 64000, 128000, 3, 8 },
1899 { 128000, 256000, 2, 4 },
1900 { 256000, 1000000, 1, 2 },
1901 { 1000000, 13500000, 0, 1 },
1902};
1903
Richard Fitzgerald01582a82016-02-10 11:56:13 +00001904static const unsigned int pseudo_fref_max[ARIZONA_FLL_MAX_FRATIO] = {
1905 13500000,
1906 6144000,
1907 6144000,
1908 3072000,
1909 3072000,
1910 2822400,
1911 2822400,
1912 1536000,
1913 1536000,
1914 1536000,
1915 1536000,
1916 1536000,
1917 1536000,
1918 1536000,
1919 1536000,
1920 768000,
1921};
1922
Mark Brown8f113d72013-03-05 12:08:57 +08001923static struct {
1924 unsigned int min;
1925 unsigned int max;
1926 u16 gain;
1927} fll_gains[] = {
1928 { 0, 256000, 0 },
1929 { 256000, 1000000, 2 },
1930 { 1000000, 13500000, 4 },
1931};
1932
Mark Brown07ed8732012-06-18 21:08:44 +01001933struct arizona_fll_cfg {
1934 int n;
1935 int theta;
1936 int lambda;
1937 int refdiv;
1938 int outdiv;
1939 int fratio;
Mark Brown8f113d72013-03-05 12:08:57 +08001940 int gain;
Mark Brown07ed8732012-06-18 21:08:44 +01001941};
1942
Charles Keepax23f785a82014-03-07 16:34:20 +00001943static int arizona_validate_fll(struct arizona_fll *fll,
1944 unsigned int Fref,
1945 unsigned int Fout)
1946{
1947 unsigned int Fvco_min;
1948
Charles Keepaxc8badda2014-07-09 17:41:49 +01001949 if (fll->fout && Fout != fll->fout) {
1950 arizona_fll_err(fll,
1951 "Can't change output on active FLL\n");
1952 return -EINVAL;
1953 }
1954
Charles Keepax23f785a82014-03-07 16:34:20 +00001955 if (Fref / ARIZONA_FLL_MAX_REFDIV > ARIZONA_FLL_MAX_FREF) {
1956 arizona_fll_err(fll,
1957 "Can't scale %dMHz in to <=13.5MHz\n",
1958 Fref);
1959 return -EINVAL;
1960 }
1961
1962 Fvco_min = ARIZONA_FLL_MIN_FVCO * fll->vco_mult;
1963 if (Fout * ARIZONA_FLL_MAX_OUTDIV < Fvco_min) {
1964 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
1965 Fout);
1966 return -EINVAL;
1967 }
1968
1969 return 0;
1970}
1971
Charles Keepaxd0800342014-03-07 16:34:25 +00001972static int arizona_find_fratio(unsigned int Fref, int *fratio)
1973{
1974 int i;
1975
1976 /* Find an appropriate FLL_FRATIO */
1977 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
1978 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
1979 if (fratio)
1980 *fratio = fll_fratios[i].fratio;
1981 return fll_fratios[i].ratio;
1982 }
1983 }
1984
1985 return -EINVAL;
1986}
1987
1988static int arizona_calc_fratio(struct arizona_fll *fll,
1989 struct arizona_fll_cfg *cfg,
1990 unsigned int target,
1991 unsigned int Fref, bool sync)
1992{
1993 int init_ratio, ratio;
1994 int refdiv, div;
1995
1996 /* Fref must be <=13.5MHz, find initial refdiv */
1997 div = 1;
1998 cfg->refdiv = 0;
1999 while (Fref > ARIZONA_FLL_MAX_FREF) {
2000 div *= 2;
2001 Fref /= 2;
2002 cfg->refdiv++;
2003
2004 if (div > ARIZONA_FLL_MAX_REFDIV)
2005 return -EINVAL;
2006 }
2007
2008 /* Find an appropriate FLL_FRATIO */
2009 init_ratio = arizona_find_fratio(Fref, &cfg->fratio);
2010 if (init_ratio < 0) {
2011 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
2012 Fref);
2013 return init_ratio;
2014 }
2015
2016 switch (fll->arizona->type) {
Richard Fitzgerald3451eb42015-12-16 17:06:24 +00002017 case WM5102:
2018 case WM8997:
2019 return init_ratio;
Charles Keepaxd0800342014-03-07 16:34:25 +00002020 case WM5110:
Richard Fitzgerald575ef7f2015-01-17 15:21:27 +00002021 case WM8280:
Charles Keepaxd0800342014-03-07 16:34:25 +00002022 if (fll->arizona->rev < 3 || sync)
2023 return init_ratio;
2024 break;
Richard Fitzgerald3451eb42015-12-16 17:06:24 +00002025 default:
Richard Fitzgerald6ebbce02015-09-28 14:01:09 +01002026 if (sync)
2027 return init_ratio;
2028 break;
Charles Keepaxd0800342014-03-07 16:34:25 +00002029 }
2030
2031 cfg->fratio = init_ratio - 1;
2032
2033 /* Adjust FRATIO/refdiv to avoid integer mode if possible */
2034 refdiv = cfg->refdiv;
2035
Richard Fitzgerald01582a82016-02-10 11:56:13 +00002036 arizona_fll_dbg(fll, "pseudo: initial ratio=%u fref=%u refdiv=%u\n",
2037 init_ratio, Fref, refdiv);
2038
Charles Keepaxd0800342014-03-07 16:34:25 +00002039 while (div <= ARIZONA_FLL_MAX_REFDIV) {
2040 for (ratio = init_ratio; ratio <= ARIZONA_FLL_MAX_FRATIO;
2041 ratio++) {
Charles Keepax35a730a2014-07-09 17:41:45 +01002042 if ((ARIZONA_FLL_VCO_CORNER / 2) /
Richard Fitzgerald01582a82016-02-10 11:56:13 +00002043 (fll->vco_mult * ratio) < Fref) {
2044 arizona_fll_dbg(fll, "pseudo: hit VCO corner\n");
Charles Keepax29fee822014-07-09 17:41:44 +01002045 break;
Richard Fitzgerald01582a82016-02-10 11:56:13 +00002046 }
2047
2048 if (Fref > pseudo_fref_max[ratio - 1]) {
2049 arizona_fll_dbg(fll,
2050 "pseudo: exceeded max fref(%u) for ratio=%u\n",
2051 pseudo_fref_max[ratio - 1],
2052 ratio);
2053 break;
2054 }
Charles Keepax29fee822014-07-09 17:41:44 +01002055
Charles Keepaxd0800342014-03-07 16:34:25 +00002056 if (target % (ratio * Fref)) {
2057 cfg->refdiv = refdiv;
2058 cfg->fratio = ratio - 1;
Richard Fitzgerald01582a82016-02-10 11:56:13 +00002059 arizona_fll_dbg(fll,
2060 "pseudo: found fref=%u refdiv=%d(%d) ratio=%d\n",
2061 Fref, refdiv, div, ratio);
Charles Keepaxd0800342014-03-07 16:34:25 +00002062 return ratio;
2063 }
2064 }
2065
Charles Keepax4714bc02014-07-09 17:41:43 +01002066 for (ratio = init_ratio - 1; ratio > 0; ratio--) {
Charles Keepaxd0800342014-03-07 16:34:25 +00002067 if (target % (ratio * Fref)) {
2068 cfg->refdiv = refdiv;
2069 cfg->fratio = ratio - 1;
Richard Fitzgerald01582a82016-02-10 11:56:13 +00002070 arizona_fll_dbg(fll,
2071 "pseudo: found fref=%u refdiv=%d(%d) ratio=%d\n",
2072 Fref, refdiv, div, ratio);
Charles Keepaxd0800342014-03-07 16:34:25 +00002073 return ratio;
2074 }
2075 }
2076
2077 div *= 2;
2078 Fref /= 2;
2079 refdiv++;
2080 init_ratio = arizona_find_fratio(Fref, NULL);
Richard Fitzgerald01582a82016-02-10 11:56:13 +00002081 arizona_fll_dbg(fll,
2082 "pseudo: change fref=%u refdiv=%d(%d) ratio=%u\n",
2083 Fref, refdiv, div, init_ratio);
Charles Keepaxd0800342014-03-07 16:34:25 +00002084 }
2085
2086 arizona_fll_warn(fll, "Falling back to integer mode operation\n");
2087 return cfg->fratio + 1;
2088}
2089
Mark Brown07ed8732012-06-18 21:08:44 +01002090static int arizona_calc_fll(struct arizona_fll *fll,
2091 struct arizona_fll_cfg *cfg,
Charles Keepaxd0800342014-03-07 16:34:25 +00002092 unsigned int Fref, bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01002093{
2094 unsigned int target, div, gcd_fll;
2095 int i, ratio;
2096
Charles Keepax8ccefcd2014-03-07 16:34:21 +00002097 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, fll->fout);
Mark Brown07ed8732012-06-18 21:08:44 +01002098
Mark Brown2b4d39f2012-07-10 17:03:46 +01002099 /* Fvco should be over the targt; don't check the upper bound */
Charles Keepaxf641aec2014-03-07 16:34:22 +00002100 div = ARIZONA_FLL_MIN_OUTDIV;
2101 while (fll->fout * div < ARIZONA_FLL_MIN_FVCO * fll->vco_mult) {
Mark Brown07ed8732012-06-18 21:08:44 +01002102 div++;
Charles Keepaxf641aec2014-03-07 16:34:22 +00002103 if (div > ARIZONA_FLL_MAX_OUTDIV)
Mark Brown07ed8732012-06-18 21:08:44 +01002104 return -EINVAL;
Mark Brown07ed8732012-06-18 21:08:44 +01002105 }
Charles Keepaxf641aec2014-03-07 16:34:22 +00002106 target = fll->fout * div / fll->vco_mult;
Mark Brown07ed8732012-06-18 21:08:44 +01002107 cfg->outdiv = div;
2108
2109 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
2110
Charles Keepaxd0800342014-03-07 16:34:25 +00002111 /* Find an appropriate FLL_FRATIO and refdiv */
2112 ratio = arizona_calc_fratio(fll, cfg, target, Fref, sync);
2113 if (ratio < 0)
2114 return ratio;
Mark Brown07ed8732012-06-18 21:08:44 +01002115
Mark Brown07ed8732012-06-18 21:08:44 +01002116 /* Apply the division for our remaining calculations */
Charles Keepaxd0800342014-03-07 16:34:25 +00002117 Fref = Fref / (1 << cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08002118
Mark Brown07ed8732012-06-18 21:08:44 +01002119 cfg->n = target / (ratio * Fref);
2120
Ryo Tsutsui01f58152013-02-03 17:18:00 +09002121 if (target % (ratio * Fref)) {
Mark Brown07ed8732012-06-18 21:08:44 +01002122 gcd_fll = gcd(target, ratio * Fref);
2123 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
2124
2125 cfg->theta = (target - (cfg->n * ratio * Fref))
2126 / gcd_fll;
2127 cfg->lambda = (ratio * Fref) / gcd_fll;
2128 } else {
2129 cfg->theta = 0;
2130 cfg->lambda = 0;
2131 }
2132
Ryo Tsutsui01f58152013-02-03 17:18:00 +09002133 /* Round down to 16bit range with cost of accuracy lost.
2134 * Denominator must be bigger than numerator so we only
2135 * take care of it.
2136 */
2137 while (cfg->lambda >= (1 << 16)) {
2138 cfg->theta >>= 1;
2139 cfg->lambda >>= 1;
2140 }
2141
Charles Keepax5a3935c2014-03-07 16:34:23 +00002142 for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
2143 if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
2144 cfg->gain = fll_gains[i].gain;
2145 break;
2146 }
2147 }
2148 if (i == ARRAY_SIZE(fll_gains)) {
2149 arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
2150 Fref);
2151 return -EINVAL;
2152 }
2153
Richard Fitzgerald2595b7f2016-02-23 14:16:32 +00002154 arizona_fll_dbg(fll, "N=%d THETA=%d LAMBDA=%d\n",
Mark Brown07ed8732012-06-18 21:08:44 +01002155 cfg->n, cfg->theta, cfg->lambda);
Richard Fitzgerald2595b7f2016-02-23 14:16:32 +00002156 arizona_fll_dbg(fll, "FRATIO=0x%x(%d) OUTDIV=%d REFCLK_DIV=0x%x(%d)\n",
2157 cfg->fratio, ratio, cfg->outdiv,
2158 cfg->refdiv, 1 << cfg->refdiv);
2159 arizona_fll_dbg(fll, "GAIN=0x%x(%d)\n", cfg->gain, 1 << cfg->gain);
Mark Brown07ed8732012-06-18 21:08:44 +01002160
2161 return 0;
2162
2163}
2164
2165static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
Mark Brown8f113d72013-03-05 12:08:57 +08002166 struct arizona_fll_cfg *cfg, int source,
2167 bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01002168{
Mark Brown3c43c692013-12-12 00:49:22 +00002169 regmap_update_bits_async(arizona->regmap, base + 3,
2170 ARIZONA_FLL1_THETA_MASK, cfg->theta);
2171 regmap_update_bits_async(arizona->regmap, base + 4,
2172 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
2173 regmap_update_bits_async(arizona->regmap, base + 5,
2174 ARIZONA_FLL1_FRATIO_MASK,
2175 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
2176 regmap_update_bits_async(arizona->regmap, base + 6,
2177 ARIZONA_FLL1_CLK_REF_DIV_MASK |
2178 ARIZONA_FLL1_CLK_REF_SRC_MASK,
2179 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
2180 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
Mark Brown07ed8732012-06-18 21:08:44 +01002181
Charles Keepax61719db2014-03-07 16:34:19 +00002182 if (sync) {
2183 regmap_update_bits(arizona->regmap, base + 0x7,
2184 ARIZONA_FLL1_GAIN_MASK,
2185 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
2186 } else {
2187 regmap_update_bits(arizona->regmap, base + 0x5,
2188 ARIZONA_FLL1_OUTDIV_MASK,
2189 cfg->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
2190 regmap_update_bits(arizona->regmap, base + 0x9,
2191 ARIZONA_FLL1_GAIN_MASK,
2192 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
2193 }
Mark Brown8f113d72013-03-05 12:08:57 +08002194
Mark Brown3c43c692013-12-12 00:49:22 +00002195 regmap_update_bits_async(arizona->regmap, base + 2,
2196 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
2197 ARIZONA_FLL1_CTRL_UPD | cfg->n);
Mark Brown07ed8732012-06-18 21:08:44 +01002198}
2199
Charles Keepaxc393aca2014-07-09 17:41:47 +01002200static int arizona_is_enabled_fll(struct arizona_fll *fll)
Charles Keepaxd122d6c2013-02-20 17:28:36 +00002201{
2202 struct arizona *arizona = fll->arizona;
2203 unsigned int reg;
2204 int ret;
2205
2206 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
2207 if (ret != 0) {
2208 arizona_fll_err(fll, "Failed to read current state: %d\n",
2209 ret);
2210 return ret;
2211 }
2212
2213 return reg & ARIZONA_FLL1_ENA;
2214}
2215
Charles Keepaxc393aca2014-07-09 17:41:47 +01002216static int arizona_enable_fll(struct arizona_fll *fll)
Charles Keepax35722812013-02-20 17:28:38 +00002217{
2218 struct arizona *arizona = fll->arizona;
Charles Keepax49c60542013-09-16 15:34:35 +01002219 bool use_sync = false;
Charles Keepaxc393aca2014-07-09 17:41:47 +01002220 int already_enabled = arizona_is_enabled_fll(fll);
Charles Keepax23f785a82014-03-07 16:34:20 +00002221 struct arizona_fll_cfg cfg;
Charles Keepax0e765972015-08-25 12:43:48 +01002222 int i;
2223 unsigned int val;
Charles Keepax35722812013-02-20 17:28:38 +00002224
Charles Keepaxc393aca2014-07-09 17:41:47 +01002225 if (already_enabled < 0)
2226 return already_enabled;
2227
Charles Keepaxc8badda2014-07-09 17:41:49 +01002228 if (already_enabled) {
2229 /* Facilitate smooth refclk across the transition */
Nikesh Oswal1cf5a332015-08-19 16:02:24 +01002230 regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9,
Charles Keepaxc8badda2014-07-09 17:41:49 +01002231 ARIZONA_FLL1_GAIN_MASK, 0);
Charles Keepax800f2972015-11-30 17:37:28 +00002232 regmap_update_bits(fll->arizona->regmap, fll->base + 1,
2233 ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
2234 udelay(32);
Charles Keepaxc8badda2014-07-09 17:41:49 +01002235 }
2236
Mark Brownff680a12013-03-04 16:00:19 +08002237 /*
2238 * If we have both REFCLK and SYNCCLK then enable both,
2239 * otherwise apply the SYNCCLK settings to REFCLK.
2240 */
Charles Keepax49c60542013-09-16 15:34:35 +01002241 if (fll->ref_src >= 0 && fll->ref_freq &&
2242 fll->ref_src != fll->sync_src) {
Charles Keepaxd0800342014-03-07 16:34:25 +00002243 arizona_calc_fll(fll, &cfg, fll->ref_freq, false);
Charles Keepax35722812013-02-20 17:28:38 +00002244
Charles Keepax23f785a82014-03-07 16:34:20 +00002245 arizona_apply_fll(arizona, fll->base, &cfg, fll->ref_src,
Mark Brown8f113d72013-03-05 12:08:57 +08002246 false);
Charles Keepax49c60542013-09-16 15:34:35 +01002247 if (fll->sync_src >= 0) {
Charles Keepaxd0800342014-03-07 16:34:25 +00002248 arizona_calc_fll(fll, &cfg, fll->sync_freq, true);
Charles Keepax23f785a82014-03-07 16:34:20 +00002249
2250 arizona_apply_fll(arizona, fll->base + 0x10, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08002251 fll->sync_src, true);
Charles Keepax49c60542013-09-16 15:34:35 +01002252 use_sync = true;
2253 }
Mark Brownff680a12013-03-04 16:00:19 +08002254 } else if (fll->sync_src >= 0) {
Charles Keepaxd0800342014-03-07 16:34:25 +00002255 arizona_calc_fll(fll, &cfg, fll->sync_freq, false);
Mark Brownff680a12013-03-04 16:00:19 +08002256
Charles Keepax23f785a82014-03-07 16:34:20 +00002257 arizona_apply_fll(arizona, fll->base, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08002258 fll->sync_src, false);
Mark Browneca2e8e2013-03-06 00:09:59 +08002259
Mark Brown3c43c692013-12-12 00:49:22 +00002260 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
2261 ARIZONA_FLL1_SYNC_ENA, 0);
Mark Brownff680a12013-03-04 16:00:19 +08002262 } else {
2263 arizona_fll_err(fll, "No clocks provided\n");
Charles Keepaxc393aca2014-07-09 17:41:47 +01002264 return -EINVAL;
Mark Brownff680a12013-03-04 16:00:19 +08002265 }
Charles Keepax35722812013-02-20 17:28:38 +00002266
Mark Brown576411be2013-03-05 12:07:16 +08002267 /*
2268 * Increase the bandwidth if we're not using a low frequency
2269 * sync source.
2270 */
Charles Keepax49c60542013-09-16 15:34:35 +01002271 if (use_sync && fll->sync_freq > 100000)
Mark Brown3c43c692013-12-12 00:49:22 +00002272 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
2273 ARIZONA_FLL1_SYNC_BW, 0);
Mark Brown576411be2013-03-05 12:07:16 +08002274 else
Mark Brown3c43c692013-12-12 00:49:22 +00002275 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
2276 ARIZONA_FLL1_SYNC_BW,
2277 ARIZONA_FLL1_SYNC_BW);
Mark Brown576411be2013-03-05 12:07:16 +08002278
Charles Keepaxc393aca2014-07-09 17:41:47 +01002279 if (!already_enabled)
Charles Keepax35722812013-02-20 17:28:38 +00002280 pm_runtime_get(arizona->dev);
2281
Mark Brown3c43c692013-12-12 00:49:22 +00002282 regmap_update_bits_async(arizona->regmap, fll->base + 1,
Mark Brown3c43c692013-12-12 00:49:22 +00002283 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
Charles Keepax49c60542013-09-16 15:34:35 +01002284 if (use_sync)
Mark Brown3c43c692013-12-12 00:49:22 +00002285 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
2286 ARIZONA_FLL1_SYNC_ENA,
2287 ARIZONA_FLL1_SYNC_ENA);
Charles Keepax35722812013-02-20 17:28:38 +00002288
Charles Keepaxc8badda2014-07-09 17:41:49 +01002289 if (already_enabled)
2290 regmap_update_bits_async(arizona->regmap, fll->base + 1,
2291 ARIZONA_FLL1_FREERUN, 0);
2292
Charles Keepax0e765972015-08-25 12:43:48 +01002293 arizona_fll_dbg(fll, "Waiting for FLL lock...\n");
2294 val = 0;
2295 for (i = 0; i < 15; i++) {
2296 if (i < 5)
2297 usleep_range(200, 400);
2298 else
2299 msleep(20);
2300
2301 regmap_read(arizona->regmap,
2302 ARIZONA_INTERRUPT_RAW_STATUS_5,
2303 &val);
2304 if (val & (ARIZONA_FLL1_CLOCK_OK_STS << (fll->id - 1)))
2305 break;
2306 }
2307 if (i == 15)
Charles Keepax35722812013-02-20 17:28:38 +00002308 arizona_fll_warn(fll, "Timed out waiting for lock\n");
Charles Keepax0e765972015-08-25 12:43:48 +01002309 else
2310 arizona_fll_dbg(fll, "FLL locked (%d polls)\n", i);
Charles Keepaxc393aca2014-07-09 17:41:47 +01002311
2312 return 0;
Charles Keepax35722812013-02-20 17:28:38 +00002313}
2314
Charles Keepax76040542013-02-20 17:28:37 +00002315static void arizona_disable_fll(struct arizona_fll *fll)
2316{
2317 struct arizona *arizona = fll->arizona;
2318 bool change;
2319
Mark Brown3c43c692013-12-12 00:49:22 +00002320 regmap_update_bits_async(arizona->regmap, fll->base + 1,
2321 ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
Charles Keepax76040542013-02-20 17:28:37 +00002322 regmap_update_bits_check(arizona->regmap, fll->base + 1,
2323 ARIZONA_FLL1_ENA, 0, &change);
2324 regmap_update_bits(arizona->regmap, fll->base + 0x11,
2325 ARIZONA_FLL1_SYNC_ENA, 0);
Charles Keepax5e39a502014-07-09 17:41:48 +01002326 regmap_update_bits_async(arizona->regmap, fll->base + 1,
2327 ARIZONA_FLL1_FREERUN, 0);
Charles Keepax76040542013-02-20 17:28:37 +00002328
2329 if (change)
2330 pm_runtime_put_autosuspend(arizona->dev);
2331}
2332
Charles Keepaxee929a92013-02-20 17:28:40 +00002333int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
2334 unsigned int Fref, unsigned int Fout)
2335{
Charles Keepaxc393aca2014-07-09 17:41:47 +01002336 int ret = 0;
Charles Keepaxee929a92013-02-20 17:28:40 +00002337
Charles Keepax1c5617f2013-02-22 17:10:37 +00002338 if (fll->ref_src == source && fll->ref_freq == Fref)
Charles Keepaxee929a92013-02-20 17:28:40 +00002339 return 0;
2340
Charles Keepax23f785a82014-03-07 16:34:20 +00002341 if (fll->fout && Fref > 0) {
2342 ret = arizona_validate_fll(fll, Fref, fll->fout);
2343 if (ret != 0)
2344 return ret;
Charles Keepaxee929a92013-02-20 17:28:40 +00002345 }
2346
2347 fll->ref_src = source;
2348 fll->ref_freq = Fref;
Charles Keepaxee929a92013-02-20 17:28:40 +00002349
Mark Brown86cd6842013-03-07 16:14:04 +08002350 if (fll->fout && Fref > 0) {
Charles Keepaxc393aca2014-07-09 17:41:47 +01002351 ret = arizona_enable_fll(fll);
Charles Keepaxee929a92013-02-20 17:28:40 +00002352 }
2353
Charles Keepaxc393aca2014-07-09 17:41:47 +01002354 return ret;
Charles Keepaxee929a92013-02-20 17:28:40 +00002355}
2356EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
2357
Mark Brown07ed8732012-06-18 21:08:44 +01002358int arizona_set_fll(struct arizona_fll *fll, int source,
2359 unsigned int Fref, unsigned int Fout)
2360{
Charles Keepaxc393aca2014-07-09 17:41:47 +01002361 int ret = 0;
Mark Brown07ed8732012-06-18 21:08:44 +01002362
Mark Brownff680a12013-03-04 16:00:19 +08002363 if (fll->sync_src == source &&
2364 fll->sync_freq == Fref && fll->fout == Fout)
2365 return 0;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00002366
Mark Brownff680a12013-03-04 16:00:19 +08002367 if (Fout) {
2368 if (fll->ref_src >= 0) {
Charles Keepax23f785a82014-03-07 16:34:20 +00002369 ret = arizona_validate_fll(fll, fll->ref_freq, Fout);
Charles Keepax9e359c62013-02-20 17:28:35 +00002370 if (ret != 0)
2371 return ret;
2372 }
2373
Charles Keepax23f785a82014-03-07 16:34:20 +00002374 ret = arizona_validate_fll(fll, Fref, Fout);
Mark Brownff680a12013-03-04 16:00:19 +08002375 if (ret != 0)
2376 return ret;
Charles Keepax9e359c62013-02-20 17:28:35 +00002377 }
Mark Brownff680a12013-03-04 16:00:19 +08002378
2379 fll->sync_src = source;
2380 fll->sync_freq = Fref;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00002381 fll->fout = Fout;
Charles Keepax9e359c62013-02-20 17:28:35 +00002382
Charles Keepax613124c2014-07-09 17:41:46 +01002383 if (Fout)
Charles Keepaxc393aca2014-07-09 17:41:47 +01002384 ret = arizona_enable_fll(fll);
Charles Keepax613124c2014-07-09 17:41:46 +01002385 else
Charles Keepax76040542013-02-20 17:28:37 +00002386 arizona_disable_fll(fll);
Mark Brown07ed8732012-06-18 21:08:44 +01002387
Charles Keepaxc393aca2014-07-09 17:41:47 +01002388 return ret;
Mark Brown07ed8732012-06-18 21:08:44 +01002389}
2390EXPORT_SYMBOL_GPL(arizona_set_fll);
2391
2392int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
2393 int ok_irq, struct arizona_fll *fll)
2394{
Charles Keepax19b34bd2013-02-20 17:28:34 +00002395 unsigned int val;
Mark Brown07ed8732012-06-18 21:08:44 +01002396
Mark Brown07ed8732012-06-18 21:08:44 +01002397 fll->id = id;
2398 fll->base = base;
2399 fll->arizona = arizona;
Charles Keepaxf3f11632013-02-20 17:28:41 +00002400 fll->sync_src = ARIZONA_FLL_SRC_NONE;
Mark Brown07ed8732012-06-18 21:08:44 +01002401
Charles Keepax19b34bd2013-02-20 17:28:34 +00002402 /* Configure default refclk to 32kHz if we have one */
2403 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
2404 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
2405 case ARIZONA_CLK_SRC_MCLK1:
2406 case ARIZONA_CLK_SRC_MCLK2:
2407 fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK;
2408 break;
2409 default:
Charles Keepaxf3f11632013-02-20 17:28:41 +00002410 fll->ref_src = ARIZONA_FLL_SRC_NONE;
Charles Keepax19b34bd2013-02-20 17:28:34 +00002411 }
2412 fll->ref_freq = 32768;
2413
Mark Brown07ed8732012-06-18 21:08:44 +01002414 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
2415 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
2416 "FLL%d clock OK", id);
2417
Charles Keepaxe31c1942013-01-07 16:41:45 +00002418 regmap_update_bits(arizona->regmap, fll->base + 1,
2419 ARIZONA_FLL1_FREERUN, 0);
2420
Mark Brown07ed8732012-06-18 21:08:44 +01002421 return 0;
2422}
2423EXPORT_SYMBOL_GPL(arizona_init_fll);
2424
Mark Brownbc9ab6d2013-01-04 19:31:00 +00002425/**
2426 * arizona_set_output_mode - Set the mode of the specified output
2427 *
2428 * @codec: Device to configure
2429 * @output: Output number
2430 * @diff: True to set the output to differential mode
2431 *
2432 * Some systems use external analogue switches to connect more
2433 * analogue devices to the CODEC than are supported by the device. In
2434 * some systems this requires changing the switched output from single
2435 * ended to differential mode dynamically at runtime, an operation
2436 * supported using this function.
2437 *
2438 * Most systems have a single static configuration and should use
2439 * platform data instead.
2440 */
2441int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
2442{
2443 unsigned int reg, val;
2444
2445 if (output < 1 || output > 6)
2446 return -EINVAL;
2447
2448 reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
2449
2450 if (diff)
2451 val = ARIZONA_OUT1_MONO;
2452 else
2453 val = 0;
2454
2455 return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val);
2456}
2457EXPORT_SYMBOL_GPL(arizona_set_output_mode);
2458
Richard Fitzgerald336d0442015-06-18 13:43:19 +01002459static const struct soc_enum arizona_adsp2_rate_enum[] = {
2460 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP1_CONTROL_1,
2461 ARIZONA_DSP1_RATE_SHIFT, 0xf,
2462 ARIZONA_RATE_ENUM_SIZE,
2463 arizona_rate_text, arizona_rate_val),
2464 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP2_CONTROL_1,
2465 ARIZONA_DSP1_RATE_SHIFT, 0xf,
2466 ARIZONA_RATE_ENUM_SIZE,
2467 arizona_rate_text, arizona_rate_val),
2468 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1,
2469 ARIZONA_DSP1_RATE_SHIFT, 0xf,
2470 ARIZONA_RATE_ENUM_SIZE,
2471 arizona_rate_text, arizona_rate_val),
2472 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP4_CONTROL_1,
2473 ARIZONA_DSP1_RATE_SHIFT, 0xf,
2474 ARIZONA_RATE_ENUM_SIZE,
2475 arizona_rate_text, arizona_rate_val),
2476};
2477
2478const struct snd_kcontrol_new arizona_adsp2_rate_controls[] = {
2479 SOC_ENUM("DSP1 Rate", arizona_adsp2_rate_enum[0]),
2480 SOC_ENUM("DSP2 Rate", arizona_adsp2_rate_enum[1]),
2481 SOC_ENUM("DSP3 Rate", arizona_adsp2_rate_enum[2]),
2482 SOC_ENUM("DSP4 Rate", arizona_adsp2_rate_enum[3]),
2483};
2484EXPORT_SYMBOL_GPL(arizona_adsp2_rate_controls);
2485
Charles Keepaxc05d9a82015-06-25 09:35:11 +01002486static bool arizona_eq_filter_unstable(bool mode, __be16 _a, __be16 _b)
2487{
2488 s16 a = be16_to_cpu(_a);
2489 s16 b = be16_to_cpu(_b);
2490
2491 if (!mode) {
2492 return abs(a) >= 4096;
2493 } else {
2494 if (abs(b) >= 4096)
2495 return true;
2496
2497 return (abs((a << 16) / (4096 - b)) >= 4096 << 4);
2498 }
2499}
2500
2501int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol,
2502 struct snd_ctl_elem_value *ucontrol)
2503{
2504 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
2505 struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
2506 struct soc_bytes *params = (void *)kcontrol->private_value;
2507 unsigned int val;
2508 __be16 *data;
2509 int len;
2510 int ret;
2511
2512 len = params->num_regs * regmap_get_val_bytes(arizona->regmap);
2513
2514 data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA);
2515 if (!data)
2516 return -ENOMEM;
2517
2518 data[0] &= cpu_to_be16(ARIZONA_EQ1_B1_MODE);
2519
2520 if (arizona_eq_filter_unstable(!!data[0], data[1], data[2]) ||
2521 arizona_eq_filter_unstable(true, data[4], data[5]) ||
2522 arizona_eq_filter_unstable(true, data[8], data[9]) ||
2523 arizona_eq_filter_unstable(true, data[12], data[13]) ||
2524 arizona_eq_filter_unstable(false, data[16], data[17])) {
2525 dev_err(arizona->dev, "Rejecting unstable EQ coefficients\n");
2526 ret = -EINVAL;
2527 goto out;
2528 }
2529
2530 ret = regmap_read(arizona->regmap, params->base, &val);
2531 if (ret != 0)
2532 goto out;
2533
2534 val &= ~ARIZONA_EQ1_B1_MODE;
2535 data[0] |= cpu_to_be16(val);
2536
2537 ret = regmap_raw_write(arizona->regmap, params->base, data, len);
2538
2539out:
2540 kfree(data);
2541 return ret;
2542}
2543EXPORT_SYMBOL_GPL(arizona_eq_coeff_put);
2544
Charles Keepax5f8e6712015-06-25 09:35:12 +01002545int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
2546 struct snd_ctl_elem_value *ucontrol)
2547{
2548 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
2549 struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
2550 __be16 *data = (__be16 *)ucontrol->value.bytes.data;
2551 s16 val = be16_to_cpu(*data);
2552
2553 if (abs(val) >= 4096) {
2554 dev_err(arizona->dev, "Rejecting unstable LHPF coefficients\n");
2555 return -EINVAL;
2556 }
2557
2558 return snd_soc_bytes_put(kcontrol, ucontrol);
2559}
2560EXPORT_SYMBOL_GPL(arizona_lhpf_coeff_put);
2561
Mark Brown07ed8732012-06-18 21:08:44 +01002562MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
2563MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
2564MODULE_LICENSE("GPL");