blob: a23f7d15324afe6a6025c5303d67da12de511caa [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:
224 break;
225 default:
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200226 ret = snd_soc_dapm_new_controls(dapm, &arizona_spkr, 1);
Charles Keepax40843ae2013-08-12 23:46:55 +0100227 if (ret != 0)
228 return ret;
229 break;
230 }
Mark Brown56447e12013-01-10 14:45:58 +0000231
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100232 ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN,
Mark Brown899817e2013-03-13 12:32:10 +0000233 "Thermal warning", arizona_thermal_warn,
234 arizona);
235 if (ret != 0)
236 dev_err(arizona->dev,
237 "Failed to get thermal warning IRQ: %d\n",
238 ret);
239
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100240 ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT,
Mark Brown899817e2013-03-13 12:32:10 +0000241 "Thermal shutdown", arizona_thermal_shutdown,
242 arizona);
243 if (ret != 0)
244 dev_err(arizona->dev,
245 "Failed to get thermal shutdown IRQ: %d\n",
246 ret);
247
Mark Brown56447e12013-01-10 14:45:58 +0000248 return 0;
249}
250EXPORT_SYMBOL_GPL(arizona_init_spk);
251
Charles Keepaxb60f3632014-06-10 18:41:02 +0100252static const struct snd_soc_dapm_route arizona_mono_routes[] = {
253 { "OUT1R", NULL, "OUT1L" },
254 { "OUT2R", NULL, "OUT2L" },
255 { "OUT3R", NULL, "OUT3L" },
256 { "OUT4R", NULL, "OUT4L" },
257 { "OUT5R", NULL, "OUT5L" },
258 { "OUT6R", NULL, "OUT6L" },
259};
260
261int arizona_init_mono(struct snd_soc_codec *codec)
262{
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200263 struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
Charles Keepaxb60f3632014-06-10 18:41:02 +0100264 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
265 struct arizona *arizona = priv->arizona;
266 int i;
267
268 for (i = 0; i < ARIZONA_MAX_OUTPUT; ++i) {
269 if (arizona->pdata.out_mono[i])
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200270 snd_soc_dapm_add_routes(dapm,
Charles Keepaxb60f3632014-06-10 18:41:02 +0100271 &arizona_mono_routes[i], 1);
272 }
273
274 return 0;
275}
276EXPORT_SYMBOL_GPL(arizona_init_mono);
277
Charles Keepaxb63144e2013-07-04 08:56:28 +0100278int arizona_init_gpio(struct snd_soc_codec *codec)
279{
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200280 struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
Charles Keepaxb63144e2013-07-04 08:56:28 +0100281 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
282 struct arizona *arizona = priv->arizona;
283 int i;
284
285 switch (arizona->type) {
286 case WM5110:
Richard Fitzgerald575ef7f2015-01-17 15:21:27 +0000287 case WM8280:
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200288 snd_soc_dapm_disable_pin(dapm, "DRC2 Signal Activity");
Charles Keepaxb79fae62013-07-04 16:53:03 +0100289 break;
290 default:
291 break;
Charles Keepaxb63144e2013-07-04 08:56:28 +0100292 }
293
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200294 snd_soc_dapm_disable_pin(dapm, "DRC1 Signal Activity");
Charles Keepaxb63144e2013-07-04 08:56:28 +0100295
296 for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
297 switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) {
298 case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT:
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200299 snd_soc_dapm_enable_pin(dapm, "DRC1 Signal Activity");
Charles Keepaxb63144e2013-07-04 08:56:28 +0100300 break;
301 case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT:
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200302 snd_soc_dapm_enable_pin(dapm, "DRC2 Signal Activity");
Charles Keepaxb63144e2013-07-04 08:56:28 +0100303 break;
304 default:
305 break;
306 }
307 }
308
309 return 0;
310}
311EXPORT_SYMBOL_GPL(arizona_init_gpio);
312
Mark Brown07ed8732012-06-18 21:08:44 +0100313const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
314 "None",
315 "Tone Generator 1",
316 "Tone Generator 2",
317 "Haptics",
318 "AEC",
Richard Fitzgerald6ebbce02015-09-28 14:01:09 +0100319 "AEC2",
Mark Brown07ed8732012-06-18 21:08:44 +0100320 "Mic Mute Mixer",
321 "Noise Generator",
322 "IN1L",
323 "IN1R",
324 "IN2L",
325 "IN2R",
326 "IN3L",
327 "IN3R",
Mark Brownc9c56fd2012-07-09 19:09:01 +0100328 "IN4L",
329 "IN4R",
Mark Brown07ed8732012-06-18 21:08:44 +0100330 "AIF1RX1",
331 "AIF1RX2",
332 "AIF1RX3",
333 "AIF1RX4",
334 "AIF1RX5",
335 "AIF1RX6",
336 "AIF1RX7",
337 "AIF1RX8",
338 "AIF2RX1",
339 "AIF2RX2",
Richard Fitzgeralde64001e2013-11-20 13:17:07 +0000340 "AIF2RX3",
341 "AIF2RX4",
342 "AIF2RX5",
343 "AIF2RX6",
Mark Brown07ed8732012-06-18 21:08:44 +0100344 "AIF3RX1",
345 "AIF3RX2",
346 "SLIMRX1",
347 "SLIMRX2",
348 "SLIMRX3",
349 "SLIMRX4",
350 "SLIMRX5",
351 "SLIMRX6",
352 "SLIMRX7",
353 "SLIMRX8",
354 "EQ1",
355 "EQ2",
356 "EQ3",
357 "EQ4",
358 "DRC1L",
359 "DRC1R",
360 "DRC2L",
361 "DRC2R",
362 "LHPF1",
363 "LHPF2",
364 "LHPF3",
365 "LHPF4",
366 "DSP1.1",
367 "DSP1.2",
368 "DSP1.3",
369 "DSP1.4",
370 "DSP1.5",
371 "DSP1.6",
Mark Brownc922cc42012-09-26 16:43:44 +0100372 "DSP2.1",
373 "DSP2.2",
374 "DSP2.3",
375 "DSP2.4",
376 "DSP2.5",
377 "DSP2.6",
378 "DSP3.1",
379 "DSP3.2",
380 "DSP3.3",
381 "DSP3.4",
382 "DSP3.5",
383 "DSP3.6",
384 "DSP4.1",
385 "DSP4.2",
386 "DSP4.3",
387 "DSP4.4",
388 "DSP4.5",
389 "DSP4.6",
Mark Brown07ed8732012-06-18 21:08:44 +0100390 "ASRC1L",
391 "ASRC1R",
392 "ASRC2L",
393 "ASRC2R",
Mark Brown91660bd2012-12-05 20:35:24 +0900394 "ISRC1INT1",
395 "ISRC1INT2",
396 "ISRC1INT3",
397 "ISRC1INT4",
398 "ISRC1DEC1",
399 "ISRC1DEC2",
400 "ISRC1DEC3",
401 "ISRC1DEC4",
402 "ISRC2INT1",
403 "ISRC2INT2",
404 "ISRC2INT3",
405 "ISRC2INT4",
406 "ISRC2DEC1",
407 "ISRC2DEC2",
408 "ISRC2DEC3",
409 "ISRC2DEC4",
410 "ISRC3INT1",
411 "ISRC3INT2",
412 "ISRC3INT3",
413 "ISRC3INT4",
414 "ISRC3DEC1",
415 "ISRC3DEC2",
416 "ISRC3DEC3",
417 "ISRC3DEC4",
Mark Brown07ed8732012-06-18 21:08:44 +0100418};
419EXPORT_SYMBOL_GPL(arizona_mixer_texts);
420
421int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
422 0x00, /* None */
423 0x04, /* Tone */
424 0x05,
425 0x06, /* Haptics */
426 0x08, /* AEC */
Richard Fitzgerald6ebbce02015-09-28 14:01:09 +0100427 0x09, /* AEC2 */
Mark Brown07ed8732012-06-18 21:08:44 +0100428 0x0c, /* Noise mixer */
429 0x0d, /* Comfort noise */
430 0x10, /* IN1L */
431 0x11,
432 0x12,
433 0x13,
434 0x14,
435 0x15,
Mark Brownc9c56fd2012-07-09 19:09:01 +0100436 0x16,
437 0x17,
Mark Brown07ed8732012-06-18 21:08:44 +0100438 0x20, /* AIF1RX1 */
439 0x21,
440 0x22,
441 0x23,
442 0x24,
443 0x25,
444 0x26,
445 0x27,
446 0x28, /* AIF2RX1 */
447 0x29,
Richard Fitzgeralde64001e2013-11-20 13:17:07 +0000448 0x2a,
449 0x2b,
450 0x2c,
451 0x2d,
Mark Brown07ed8732012-06-18 21:08:44 +0100452 0x30, /* AIF3RX1 */
453 0x31,
454 0x38, /* SLIMRX1 */
455 0x39,
456 0x3a,
457 0x3b,
458 0x3c,
459 0x3d,
460 0x3e,
461 0x3f,
462 0x50, /* EQ1 */
463 0x51,
464 0x52,
465 0x53,
466 0x58, /* DRC1L */
467 0x59,
468 0x5a,
469 0x5b,
470 0x60, /* LHPF1 */
471 0x61,
472 0x62,
473 0x63,
474 0x68, /* DSP1.1 */
475 0x69,
476 0x6a,
477 0x6b,
478 0x6c,
479 0x6d,
Mark Brownc922cc42012-09-26 16:43:44 +0100480 0x70, /* DSP2.1 */
481 0x71,
482 0x72,
483 0x73,
484 0x74,
485 0x75,
486 0x78, /* DSP3.1 */
487 0x79,
488 0x7a,
489 0x7b,
490 0x7c,
491 0x7d,
492 0x80, /* DSP4.1 */
493 0x81,
494 0x82,
495 0x83,
496 0x84,
497 0x85,
Mark Brown07ed8732012-06-18 21:08:44 +0100498 0x90, /* ASRC1L */
499 0x91,
500 0x92,
501 0x93,
Mark Brown91660bd2012-12-05 20:35:24 +0900502 0xa0, /* ISRC1INT1 */
503 0xa1,
504 0xa2,
505 0xa3,
506 0xa4, /* ISRC1DEC1 */
507 0xa5,
508 0xa6,
509 0xa7,
510 0xa8, /* ISRC2DEC1 */
511 0xa9,
512 0xaa,
513 0xab,
514 0xac, /* ISRC2INT1 */
515 0xad,
516 0xae,
517 0xaf,
518 0xb0, /* ISRC3DEC1 */
519 0xb1,
520 0xb2,
521 0xb3,
522 0xb4, /* ISRC3INT1 */
523 0xb5,
524 0xb6,
525 0xb7,
Mark Brown07ed8732012-06-18 21:08:44 +0100526};
527EXPORT_SYMBOL_GPL(arizona_mixer_values);
528
529const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
530EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
531
Richard Fitzgerald6ebbce02015-09-28 14:01:09 +0100532const char * const arizona_sample_rate_text[ARIZONA_SAMPLE_RATE_ENUM_SIZE] = {
533 "12kHz", "24kHz", "48kHz", "96kHz", "192kHz",
534 "11.025kHz", "22.05kHz", "44.1kHz", "88.2kHz", "176.4kHz",
535 "4kHz", "8kHz", "16kHz", "32kHz",
536};
537EXPORT_SYMBOL_GPL(arizona_sample_rate_text);
538
539const unsigned int arizona_sample_rate_val[ARIZONA_SAMPLE_RATE_ENUM_SIZE] = {
540 0x01, 0x02, 0x03, 0x04, 0x05, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
541 0x10, 0x11, 0x12, 0x13,
542};
543EXPORT_SYMBOL_GPL(arizona_sample_rate_val);
544
545const char *arizona_sample_rate_val_to_name(unsigned int rate_val)
546{
547 int i;
548
549 for (i = 0; i < ARRAY_SIZE(arizona_sample_rate_val); ++i) {
550 if (arizona_sample_rate_val[i] == rate_val)
551 return arizona_sample_rate_text[i];
552 }
553
554 return "Illegal";
555}
556EXPORT_SYMBOL_GPL(arizona_sample_rate_val_to_name);
557
Mark Browndc914282013-02-18 19:09:23 +0000558const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = {
559 "SYNCCLK rate", "8kHz", "16kHz", "ASYNCCLK rate",
560};
561EXPORT_SYMBOL_GPL(arizona_rate_text);
562
563const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
564 0, 1, 2, 8,
565};
566EXPORT_SYMBOL_GPL(arizona_rate_val);
567
568
Charles Keepaxfbedc8c2013-12-19 09:30:12 +0000569const struct soc_enum arizona_isrc_fsh[] = {
570 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_1,
571 ARIZONA_ISRC1_FSH_SHIFT, 0xf,
572 ARIZONA_RATE_ENUM_SIZE,
573 arizona_rate_text, arizona_rate_val),
574 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_1,
575 ARIZONA_ISRC2_FSH_SHIFT, 0xf,
576 ARIZONA_RATE_ENUM_SIZE,
577 arizona_rate_text, arizona_rate_val),
578 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_1,
579 ARIZONA_ISRC3_FSH_SHIFT, 0xf,
580 ARIZONA_RATE_ENUM_SIZE,
581 arizona_rate_text, arizona_rate_val),
582};
583EXPORT_SYMBOL_GPL(arizona_isrc_fsh);
584
Mark Browndc914282013-02-18 19:09:23 +0000585const struct soc_enum arizona_isrc_fsl[] = {
586 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2,
587 ARIZONA_ISRC1_FSL_SHIFT, 0xf,
588 ARIZONA_RATE_ENUM_SIZE,
589 arizona_rate_text, arizona_rate_val),
590 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_2,
591 ARIZONA_ISRC2_FSL_SHIFT, 0xf,
592 ARIZONA_RATE_ENUM_SIZE,
593 arizona_rate_text, arizona_rate_val),
594 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_2,
595 ARIZONA_ISRC3_FSL_SHIFT, 0xf,
596 ARIZONA_RATE_ENUM_SIZE,
597 arizona_rate_text, arizona_rate_val),
598};
599EXPORT_SYMBOL_GPL(arizona_isrc_fsl);
600
Charles Keepax56d37d82013-12-19 09:30:13 +0000601const struct soc_enum arizona_asrc_rate1 =
602 SOC_VALUE_ENUM_SINGLE(ARIZONA_ASRC_RATE1,
603 ARIZONA_ASRC_RATE1_SHIFT, 0xf,
604 ARIZONA_RATE_ENUM_SIZE - 1,
605 arizona_rate_text, arizona_rate_val);
606EXPORT_SYMBOL_GPL(arizona_asrc_rate1);
607
Mark Browne853a002012-12-09 12:25:52 +0900608static const char *arizona_vol_ramp_text[] = {
609 "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
610 "15ms/6dB", "30ms/6dB",
611};
612
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100613SOC_ENUM_SINGLE_DECL(arizona_in_vd_ramp,
614 ARIZONA_INPUT_VOLUME_RAMP,
615 ARIZONA_IN_VD_RAMP_SHIFT,
616 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900617EXPORT_SYMBOL_GPL(arizona_in_vd_ramp);
618
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100619SOC_ENUM_SINGLE_DECL(arizona_in_vi_ramp,
620 ARIZONA_INPUT_VOLUME_RAMP,
621 ARIZONA_IN_VI_RAMP_SHIFT,
622 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900623EXPORT_SYMBOL_GPL(arizona_in_vi_ramp);
624
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100625SOC_ENUM_SINGLE_DECL(arizona_out_vd_ramp,
626 ARIZONA_OUTPUT_VOLUME_RAMP,
627 ARIZONA_OUT_VD_RAMP_SHIFT,
628 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900629EXPORT_SYMBOL_GPL(arizona_out_vd_ramp);
630
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100631SOC_ENUM_SINGLE_DECL(arizona_out_vi_ramp,
632 ARIZONA_OUTPUT_VOLUME_RAMP,
633 ARIZONA_OUT_VI_RAMP_SHIFT,
634 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900635EXPORT_SYMBOL_GPL(arizona_out_vi_ramp);
636
Mark Brown07ed8732012-06-18 21:08:44 +0100637static const char *arizona_lhpf_mode_text[] = {
638 "Low-pass", "High-pass"
639};
640
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100641SOC_ENUM_SINGLE_DECL(arizona_lhpf1_mode,
642 ARIZONA_HPLPF1_1,
643 ARIZONA_LHPF1_MODE_SHIFT,
644 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100645EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
646
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100647SOC_ENUM_SINGLE_DECL(arizona_lhpf2_mode,
648 ARIZONA_HPLPF2_1,
649 ARIZONA_LHPF2_MODE_SHIFT,
650 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100651EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
652
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100653SOC_ENUM_SINGLE_DECL(arizona_lhpf3_mode,
654 ARIZONA_HPLPF3_1,
655 ARIZONA_LHPF3_MODE_SHIFT,
656 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100657EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
658
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100659SOC_ENUM_SINGLE_DECL(arizona_lhpf4_mode,
660 ARIZONA_HPLPF4_1,
661 ARIZONA_LHPF4_MODE_SHIFT,
662 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100663EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
664
Mark Brown845571c2012-12-18 13:47:57 +0000665static const char *arizona_ng_hold_text[] = {
666 "30ms", "120ms", "250ms", "500ms",
667};
668
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100669SOC_ENUM_SINGLE_DECL(arizona_ng_hold,
670 ARIZONA_NOISE_GATE_CONTROL,
671 ARIZONA_NGATE_HOLD_SHIFT,
672 arizona_ng_hold_text);
Mark Brown845571c2012-12-18 13:47:57 +0000673EXPORT_SYMBOL_GPL(arizona_ng_hold);
674
Charles Keepax254dc322013-11-19 16:04:03 +0000675static const char * const arizona_in_hpf_cut_text[] = {
676 "2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz"
677};
678
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100679SOC_ENUM_SINGLE_DECL(arizona_in_hpf_cut_enum,
680 ARIZONA_HPF_CONTROL,
681 ARIZONA_IN_HPF_CUT_SHIFT,
682 arizona_in_hpf_cut_text);
Charles Keepax254dc322013-11-19 16:04:03 +0000683EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum);
684
Charles Keepaxc7f38432013-08-06 17:03:55 +0100685static const char * const arizona_in_dmic_osr_text[] = {
Charles Keepaxef326f42014-11-12 14:55:26 +0000686 "1.536MHz", "3.072MHz", "6.144MHz", "768kHz",
Charles Keepaxc7f38432013-08-06 17:03:55 +0100687};
688
689const struct soc_enum arizona_in_dmic_osr[] = {
690 SOC_ENUM_SINGLE(ARIZONA_IN1L_CONTROL, ARIZONA_IN1_OSR_SHIFT,
691 ARRAY_SIZE(arizona_in_dmic_osr_text),
692 arizona_in_dmic_osr_text),
693 SOC_ENUM_SINGLE(ARIZONA_IN2L_CONTROL, ARIZONA_IN2_OSR_SHIFT,
694 ARRAY_SIZE(arizona_in_dmic_osr_text),
695 arizona_in_dmic_osr_text),
696 SOC_ENUM_SINGLE(ARIZONA_IN3L_CONTROL, ARIZONA_IN3_OSR_SHIFT,
697 ARRAY_SIZE(arizona_in_dmic_osr_text),
698 arizona_in_dmic_osr_text),
699 SOC_ENUM_SINGLE(ARIZONA_IN4L_CONTROL, ARIZONA_IN4_OSR_SHIFT,
700 ARRAY_SIZE(arizona_in_dmic_osr_text),
701 arizona_in_dmic_osr_text),
702};
703EXPORT_SYMBOL_GPL(arizona_in_dmic_osr);
704
Charles Keepaxd1901062015-11-19 16:11:10 +0000705static const char * const arizona_anc_input_src_text[] = {
706 "None", "IN1", "IN2", "IN3", "IN4",
707};
708
709static const char * const arizona_anc_channel_src_text[] = {
710 "None", "Left", "Right", "Combine",
711};
712
713const struct soc_enum arizona_anc_input_src[] = {
714 SOC_ENUM_SINGLE(ARIZONA_ANC_SRC,
715 ARIZONA_IN_RXANCL_SEL_SHIFT,
716 ARRAY_SIZE(arizona_anc_input_src_text),
717 arizona_anc_input_src_text),
718 SOC_ENUM_SINGLE(ARIZONA_FCL_ADC_REFORMATTER_CONTROL,
719 ARIZONA_FCL_MIC_MODE_SEL,
720 ARRAY_SIZE(arizona_anc_channel_src_text),
721 arizona_anc_channel_src_text),
722 SOC_ENUM_SINGLE(ARIZONA_ANC_SRC,
723 ARIZONA_IN_RXANCR_SEL_SHIFT,
724 ARRAY_SIZE(arizona_anc_input_src_text),
725 arizona_anc_input_src_text),
726 SOC_ENUM_SINGLE(ARIZONA_FCR_ADC_REFORMATTER_CONTROL,
727 ARIZONA_FCR_MIC_MODE_SEL,
728 ARRAY_SIZE(arizona_anc_channel_src_text),
729 arizona_anc_channel_src_text),
730};
731EXPORT_SYMBOL_GPL(arizona_anc_input_src);
732
733static const char * const arizona_anc_ng_texts[] = {
734 "None",
735 "Internal",
736 "External",
737};
738
739SOC_ENUM_SINGLE_DECL(arizona_anc_ng_enum, SND_SOC_NOPM, 0,
740 arizona_anc_ng_texts);
741EXPORT_SYMBOL_GPL(arizona_anc_ng_enum);
742
743static const char * const arizona_output_anc_src_text[] = {
744 "None", "RXANCL", "RXANCR",
745};
746
747const struct soc_enum arizona_output_anc_src[] = {
748 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L,
749 ARIZONA_OUT1L_ANC_SRC_SHIFT,
750 ARRAY_SIZE(arizona_output_anc_src_text),
751 arizona_output_anc_src_text),
752 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1R,
753 ARIZONA_OUT1R_ANC_SRC_SHIFT,
754 ARRAY_SIZE(arizona_output_anc_src_text),
755 arizona_output_anc_src_text),
756 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2L,
757 ARIZONA_OUT2L_ANC_SRC_SHIFT,
758 ARRAY_SIZE(arizona_output_anc_src_text),
759 arizona_output_anc_src_text),
760 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2R,
761 ARIZONA_OUT2R_ANC_SRC_SHIFT,
762 ARRAY_SIZE(arizona_output_anc_src_text),
763 arizona_output_anc_src_text),
764 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L,
765 ARIZONA_OUT3L_ANC_SRC_SHIFT,
766 ARRAY_SIZE(arizona_output_anc_src_text),
767 arizona_output_anc_src_text),
768 SOC_ENUM_SINGLE(ARIZONA_DAC_VOLUME_LIMIT_3R,
769 ARIZONA_OUT3R_ANC_SRC_SHIFT,
770 ARRAY_SIZE(arizona_output_anc_src_text),
771 arizona_output_anc_src_text),
772 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_4L,
773 ARIZONA_OUT4L_ANC_SRC_SHIFT,
774 ARRAY_SIZE(arizona_output_anc_src_text),
775 arizona_output_anc_src_text),
776 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_4R,
777 ARIZONA_OUT4R_ANC_SRC_SHIFT,
778 ARRAY_SIZE(arizona_output_anc_src_text),
779 arizona_output_anc_src_text),
780 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_5L,
781 ARIZONA_OUT5L_ANC_SRC_SHIFT,
782 ARRAY_SIZE(arizona_output_anc_src_text),
783 arizona_output_anc_src_text),
784 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_5R,
785 ARIZONA_OUT5R_ANC_SRC_SHIFT,
786 ARRAY_SIZE(arizona_output_anc_src_text),
787 arizona_output_anc_src_text),
788 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_6L,
789 ARIZONA_OUT6L_ANC_SRC_SHIFT,
790 ARRAY_SIZE(arizona_output_anc_src_text),
791 arizona_output_anc_src_text),
792 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_6R,
793 ARIZONA_OUT6R_ANC_SRC_SHIFT,
794 ARRAY_SIZE(arizona_output_anc_src_text),
795 arizona_output_anc_src_text),
796};
797EXPORT_SYMBOL_GPL(arizona_output_anc_src);
798
Mark Brownddbce972013-02-15 17:27:22 +0000799static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
800{
801 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
802 unsigned int val;
803 int i;
804
805 if (ena)
806 val = ARIZONA_IN_VU;
807 else
808 val = 0;
809
810 for (i = 0; i < priv->num_inputs; i++)
811 snd_soc_update_bits(codec,
812 ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 4),
813 ARIZONA_IN_VU, val);
814}
815
Charles Keepax002b0832015-09-16 13:59:41 +0100816bool arizona_input_analog(struct snd_soc_codec *codec, int shift)
817{
818 unsigned int reg = ARIZONA_IN1L_CONTROL + ((shift / 2) * 8);
819 unsigned int val = snd_soc_read(codec, reg);
820
821 return !(val & ARIZONA_IN1_MODE_MASK);
822}
823EXPORT_SYMBOL_GPL(arizona_input_analog);
824
Mark Brown07ed8732012-06-18 21:08:44 +0100825int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
826 int event)
827{
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100828 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
829 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000830 unsigned int reg;
831
832 if (w->shift % 2)
833 reg = ARIZONA_ADC_DIGITAL_VOLUME_1L + ((w->shift / 2) * 8);
834 else
835 reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8);
836
837 switch (event) {
Mark Brownddbce972013-02-15 17:27:22 +0000838 case SND_SOC_DAPM_PRE_PMU:
839 priv->in_pending++;
840 break;
Mark Brown43cd8bf2013-02-06 16:57:29 +0000841 case SND_SOC_DAPM_POST_PMU:
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100842 snd_soc_update_bits(codec, reg, ARIZONA_IN1L_MUTE, 0);
Mark Brownddbce972013-02-15 17:27:22 +0000843
844 /* If this is the last input pending then allow VU */
845 priv->in_pending--;
846 if (priv->in_pending == 0) {
847 msleep(1);
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100848 arizona_in_set_vu(codec, 1);
Mark Brownddbce972013-02-15 17:27:22 +0000849 }
Mark Brown43cd8bf2013-02-06 16:57:29 +0000850 break;
851 case SND_SOC_DAPM_PRE_PMD:
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100852 snd_soc_update_bits(codec, reg,
Mark Brownddbce972013-02-15 17:27:22 +0000853 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU,
854 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000855 break;
Mark Brownddbce972013-02-15 17:27:22 +0000856 case SND_SOC_DAPM_POST_PMD:
857 /* Disable volume updates if no inputs are enabled */
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100858 reg = snd_soc_read(codec, ARIZONA_INPUT_ENABLES);
Mark Brownddbce972013-02-15 17:27:22 +0000859 if (reg == 0)
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100860 arizona_in_set_vu(codec, 0);
Charles Keepaxbee261b2015-09-16 13:59:40 +0100861 break;
862 default:
863 break;
Mark Brown43cd8bf2013-02-06 16:57:29 +0000864 }
865
Mark Brown07ed8732012-06-18 21:08:44 +0100866 return 0;
867}
868EXPORT_SYMBOL_GPL(arizona_in_ev);
869
870int arizona_out_ev(struct snd_soc_dapm_widget *w,
871 struct snd_kcontrol *kcontrol,
872 int event)
873{
Mark Brown60d66c92015-01-27 23:50:47 +0000874 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
875 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Charles Keepax054e1b42015-01-20 16:31:50 +0000876
Mark Brown1a2c7d52013-03-24 22:50:23 +0000877 switch (event) {
Charles Keepaxe1ae5fb2015-01-20 16:31:51 +0000878 case SND_SOC_DAPM_PRE_PMU:
879 switch (w->shift) {
880 case ARIZONA_OUT1L_ENA_SHIFT:
881 case ARIZONA_OUT1R_ENA_SHIFT:
882 case ARIZONA_OUT2L_ENA_SHIFT:
883 case ARIZONA_OUT2R_ENA_SHIFT:
884 case ARIZONA_OUT3L_ENA_SHIFT:
885 case ARIZONA_OUT3R_ENA_SHIFT:
886 priv->out_up_pending++;
887 priv->out_up_delay += 17;
888 break;
889 default:
890 break;
891 }
892 break;
Mark Brown1a2c7d52013-03-24 22:50:23 +0000893 case SND_SOC_DAPM_POST_PMU:
894 switch (w->shift) {
895 case ARIZONA_OUT1L_ENA_SHIFT:
896 case ARIZONA_OUT1R_ENA_SHIFT:
897 case ARIZONA_OUT2L_ENA_SHIFT:
898 case ARIZONA_OUT2R_ENA_SHIFT:
899 case ARIZONA_OUT3L_ENA_SHIFT:
900 case ARIZONA_OUT3R_ENA_SHIFT:
Charles Keepaxe1ae5fb2015-01-20 16:31:51 +0000901 priv->out_up_pending--;
902 if (!priv->out_up_pending) {
903 msleep(priv->out_up_delay);
904 priv->out_up_delay = 0;
905 }
Mark Brown1a2c7d52013-03-24 22:50:23 +0000906 break;
907
908 default:
909 break;
910 }
911 break;
Charles Keepax054e1b42015-01-20 16:31:50 +0000912 case SND_SOC_DAPM_PRE_PMD:
913 switch (w->shift) {
914 case ARIZONA_OUT1L_ENA_SHIFT:
915 case ARIZONA_OUT1R_ENA_SHIFT:
916 case ARIZONA_OUT2L_ENA_SHIFT:
917 case ARIZONA_OUT2R_ENA_SHIFT:
918 case ARIZONA_OUT3L_ENA_SHIFT:
919 case ARIZONA_OUT3R_ENA_SHIFT:
920 priv->out_down_pending++;
921 priv->out_down_delay++;
922 break;
923 default:
924 break;
925 }
926 break;
927 case SND_SOC_DAPM_POST_PMD:
928 switch (w->shift) {
929 case ARIZONA_OUT1L_ENA_SHIFT:
930 case ARIZONA_OUT1R_ENA_SHIFT:
931 case ARIZONA_OUT2L_ENA_SHIFT:
932 case ARIZONA_OUT2R_ENA_SHIFT:
933 case ARIZONA_OUT3L_ENA_SHIFT:
934 case ARIZONA_OUT3R_ENA_SHIFT:
935 priv->out_down_pending--;
936 if (!priv->out_down_pending) {
937 msleep(priv->out_down_delay);
938 priv->out_down_delay = 0;
939 }
940 break;
941 default:
942 break;
943 }
944 break;
Charles Keepaxbee261b2015-09-16 13:59:40 +0100945 default:
946 break;
Mark Brown1a2c7d52013-03-24 22:50:23 +0000947 }
948
Mark Brown07ed8732012-06-18 21:08:44 +0100949 return 0;
950}
951EXPORT_SYMBOL_GPL(arizona_out_ev);
952
Mark Brownf607e312013-02-22 18:36:53 +0000953int arizona_hp_ev(struct snd_soc_dapm_widget *w,
954 struct snd_kcontrol *kcontrol,
955 int event)
956{
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100957 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
958 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brown3c43c692013-12-12 00:49:22 +0000959 struct arizona *arizona = priv->arizona;
Mark Brownf607e312013-02-22 18:36:53 +0000960 unsigned int mask = 1 << w->shift;
961 unsigned int val;
962
963 switch (event) {
964 case SND_SOC_DAPM_POST_PMU:
965 val = mask;
966 break;
967 case SND_SOC_DAPM_PRE_PMD:
968 val = 0;
969 break;
Charles Keepaxe1ae5fb2015-01-20 16:31:51 +0000970 case SND_SOC_DAPM_PRE_PMU:
Charles Keepax054e1b42015-01-20 16:31:50 +0000971 case SND_SOC_DAPM_POST_PMD:
972 return arizona_out_ev(w, kcontrol, event);
Mark Brownf607e312013-02-22 18:36:53 +0000973 default:
974 return -EINVAL;
975 }
976
977 /* Store the desired state for the HP outputs */
978 priv->arizona->hp_ena &= ~mask;
979 priv->arizona->hp_ena |= val;
980
Charles Keepax112bdfa2015-02-16 15:41:02 +0000981 /* Force off if HPDET clamp is active */
982 if (priv->arizona->hpdet_clamp)
Mark Brownf607e312013-02-22 18:36:53 +0000983 val = 0;
984
Mark Brown3c43c692013-12-12 00:49:22 +0000985 regmap_update_bits_async(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1,
986 mask, val);
Mark Brownf607e312013-02-22 18:36:53 +0000987
988 return arizona_out_ev(w, kcontrol, event);
989}
990EXPORT_SYMBOL_GPL(arizona_hp_ev);
991
Richard Fitzgerald346d9682015-06-02 11:53:33 +0100992static int arizona_dvfs_enable(struct snd_soc_codec *codec)
993{
994 const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
995 struct arizona *arizona = priv->arizona;
996 int ret;
997
998 ret = regulator_set_voltage(arizona->dcvdd, 1800000, 1800000);
999 if (ret) {
1000 dev_err(codec->dev, "Failed to boost DCVDD: %d\n", ret);
1001 return ret;
1002 }
1003
1004 ret = regmap_update_bits(arizona->regmap,
1005 ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
1006 ARIZONA_SUBSYS_MAX_FREQ,
1007 ARIZONA_SUBSYS_MAX_FREQ);
1008 if (ret) {
1009 dev_err(codec->dev, "Failed to enable subsys max: %d\n", ret);
1010 regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
1011 return ret;
1012 }
1013
1014 return 0;
1015}
1016
1017static int arizona_dvfs_disable(struct snd_soc_codec *codec)
1018{
1019 const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1020 struct arizona *arizona = priv->arizona;
1021 int ret;
1022
1023 ret = regmap_update_bits(arizona->regmap,
1024 ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
1025 ARIZONA_SUBSYS_MAX_FREQ, 0);
1026 if (ret) {
1027 dev_err(codec->dev, "Failed to disable subsys max: %d\n", ret);
1028 return ret;
1029 }
1030
1031 ret = regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
1032 if (ret) {
1033 dev_err(codec->dev, "Failed to unboost DCVDD: %d\n", ret);
1034 return ret;
1035 }
1036
1037 return 0;
1038}
1039
1040int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags)
1041{
1042 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1043 int ret = 0;
1044
1045 mutex_lock(&priv->dvfs_lock);
1046
1047 if (!priv->dvfs_cached && !priv->dvfs_reqs) {
1048 ret = arizona_dvfs_enable(codec);
1049 if (ret)
1050 goto err;
1051 }
1052
1053 priv->dvfs_reqs |= flags;
1054err:
1055 mutex_unlock(&priv->dvfs_lock);
1056 return ret;
1057}
1058EXPORT_SYMBOL_GPL(arizona_dvfs_up);
1059
1060int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags)
1061{
1062 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1063 unsigned int old_reqs;
1064 int ret = 0;
1065
1066 mutex_lock(&priv->dvfs_lock);
1067
1068 old_reqs = priv->dvfs_reqs;
1069 priv->dvfs_reqs &= ~flags;
1070
1071 if (!priv->dvfs_cached && old_reqs && !priv->dvfs_reqs)
1072 ret = arizona_dvfs_disable(codec);
1073
1074 mutex_unlock(&priv->dvfs_lock);
1075 return ret;
1076}
1077EXPORT_SYMBOL_GPL(arizona_dvfs_down);
1078
1079int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
1080 struct snd_kcontrol *kcontrol, int event)
1081{
1082 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
1083 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1084 int ret = 0;
1085
1086 mutex_lock(&priv->dvfs_lock);
1087
1088 switch (event) {
1089 case SND_SOC_DAPM_POST_PMU:
1090 if (priv->dvfs_reqs)
1091 ret = arizona_dvfs_enable(codec);
1092
1093 priv->dvfs_cached = false;
1094 break;
1095 case SND_SOC_DAPM_PRE_PMD:
1096 /* We must ensure DVFS is disabled before the codec goes into
1097 * suspend so that we are never in an illegal state of DVFS
1098 * enabled without enough DCVDD
1099 */
1100 priv->dvfs_cached = true;
1101
1102 if (priv->dvfs_reqs)
1103 ret = arizona_dvfs_disable(codec);
1104 break;
1105 default:
1106 break;
1107 }
1108
1109 mutex_unlock(&priv->dvfs_lock);
1110 return ret;
1111}
1112EXPORT_SYMBOL_GPL(arizona_dvfs_sysclk_ev);
1113
1114void arizona_init_dvfs(struct arizona_priv *priv)
1115{
1116 mutex_init(&priv->dvfs_lock);
1117}
1118EXPORT_SYMBOL_GPL(arizona_init_dvfs);
1119
Charles Keepaxd1901062015-11-19 16:11:10 +00001120int arizona_anc_ev(struct snd_soc_dapm_widget *w,
1121 struct snd_kcontrol *kcontrol,
1122 int event)
1123{
1124 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
1125 unsigned int mask = 0x3 << w->shift;
1126 unsigned int val;
1127
1128 switch (event) {
1129 case SND_SOC_DAPM_POST_PMU:
1130 val = 1 << w->shift;
1131 break;
1132 case SND_SOC_DAPM_PRE_PMD:
1133 val = 1 << (w->shift + 1);
1134 break;
1135 default:
1136 return 0;
1137 }
1138
1139 snd_soc_update_bits(codec, ARIZONA_CLOCK_CONTROL, mask, val);
1140
1141 return 0;
1142}
1143EXPORT_SYMBOL_GPL(arizona_anc_ev);
1144
Richard Fitzgerald341604a2015-11-03 14:24:12 +00001145static unsigned int arizona_opclk_ref_48k_rates[] = {
Mark Browncbd840d2012-08-08 17:52:44 +01001146 6144000,
1147 12288000,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +00001148 24576000,
Mark Browncbd840d2012-08-08 17:52:44 +01001149 49152000,
1150};
1151
Richard Fitzgerald341604a2015-11-03 14:24:12 +00001152static unsigned int arizona_opclk_ref_44k1_rates[] = {
Mark Browncbd840d2012-08-08 17:52:44 +01001153 5644800,
1154 11289600,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +00001155 22579200,
Mark Browncbd840d2012-08-08 17:52:44 +01001156 45158400,
1157};
1158
1159static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
1160 unsigned int freq)
1161{
1162 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1163 unsigned int reg;
1164 unsigned int *rates;
1165 int ref, div, refclk;
1166
1167 switch (clk) {
1168 case ARIZONA_CLK_OPCLK:
1169 reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
1170 refclk = priv->sysclk;
1171 break;
1172 case ARIZONA_CLK_ASYNC_OPCLK:
1173 reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
1174 refclk = priv->asyncclk;
1175 break;
1176 default:
1177 return -EINVAL;
1178 }
1179
1180 if (refclk % 8000)
Richard Fitzgerald341604a2015-11-03 14:24:12 +00001181 rates = arizona_opclk_ref_44k1_rates;
Mark Browncbd840d2012-08-08 17:52:44 +01001182 else
Richard Fitzgerald341604a2015-11-03 14:24:12 +00001183 rates = arizona_opclk_ref_48k_rates;
Mark Browncbd840d2012-08-08 17:52:44 +01001184
Richard Fitzgerald341604a2015-11-03 14:24:12 +00001185 for (ref = 0; ref < ARRAY_SIZE(arizona_opclk_ref_48k_rates) &&
Mark Browncbd840d2012-08-08 17:52:44 +01001186 rates[ref] <= refclk; ref++) {
1187 div = 1;
1188 while (rates[ref] / div >= freq && div < 32) {
1189 if (rates[ref] / div == freq) {
1190 dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
1191 freq);
1192 snd_soc_update_bits(codec, reg,
1193 ARIZONA_OPCLK_DIV_MASK |
1194 ARIZONA_OPCLK_SEL_MASK,
1195 (div <<
1196 ARIZONA_OPCLK_DIV_SHIFT) |
1197 ref);
1198 return 0;
1199 }
1200 div++;
1201 }
1202 }
1203
1204 dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
1205 return -EINVAL;
1206}
1207
Mark Brown07ed8732012-06-18 21:08:44 +01001208int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
1209 int source, unsigned int freq, int dir)
1210{
1211 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1212 struct arizona *arizona = priv->arizona;
1213 char *name;
1214 unsigned int reg;
1215 unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
1216 unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
1217 unsigned int *clk;
1218
1219 switch (clk_id) {
1220 case ARIZONA_CLK_SYSCLK:
1221 name = "SYSCLK";
1222 reg = ARIZONA_SYSTEM_CLOCK_1;
1223 clk = &priv->sysclk;
1224 mask |= ARIZONA_SYSCLK_FRAC;
1225 break;
1226 case ARIZONA_CLK_ASYNCCLK:
1227 name = "ASYNCCLK";
1228 reg = ARIZONA_ASYNC_CLOCK_1;
1229 clk = &priv->asyncclk;
1230 break;
Mark Browncbd840d2012-08-08 17:52:44 +01001231 case ARIZONA_CLK_OPCLK:
1232 case ARIZONA_CLK_ASYNC_OPCLK:
1233 return arizona_set_opclk(codec, clk_id, freq);
Mark Brown07ed8732012-06-18 21:08:44 +01001234 default:
1235 return -EINVAL;
1236 }
1237
1238 switch (freq) {
1239 case 5644800:
1240 case 6144000:
1241 break;
1242 case 11289600:
1243 case 12288000:
Mark Brown3f341f72013-03-08 15:22:29 +08001244 val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +01001245 break;
1246 case 22579200:
1247 case 24576000:
Mark Brown3f341f72013-03-08 15:22:29 +08001248 val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +01001249 break;
1250 case 45158400:
1251 case 49152000:
Mark Brown3f341f72013-03-08 15:22:29 +08001252 val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +01001253 break;
Mark Brown38113362012-11-26 16:01:37 +00001254 case 67737600:
1255 case 73728000:
Mark Brown3f341f72013-03-08 15:22:29 +08001256 val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +00001257 break;
1258 case 90316800:
1259 case 98304000:
Mark Brown3f341f72013-03-08 15:22:29 +08001260 val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +00001261 break;
1262 case 135475200:
1263 case 147456000:
Mark Brown3f341f72013-03-08 15:22:29 +08001264 val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +00001265 break;
Mark Brownf2c26d42013-01-21 16:09:36 +09001266 case 0:
1267 dev_dbg(arizona->dev, "%s cleared\n", name);
1268 *clk = freq;
1269 return 0;
Mark Brown07ed8732012-06-18 21:08:44 +01001270 default:
1271 return -EINVAL;
1272 }
1273
1274 *clk = freq;
1275
1276 if (freq % 6144000)
1277 val |= ARIZONA_SYSCLK_FRAC;
1278
1279 dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
1280
1281 return regmap_update_bits(arizona->regmap, reg, mask, val);
1282}
1283EXPORT_SYMBOL_GPL(arizona_set_sysclk);
1284
1285static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
1286{
1287 struct snd_soc_codec *codec = dai->codec;
Mark Brown3c43c692013-12-12 00:49:22 +00001288 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1289 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +01001290 int lrclk, bclk, mode, base;
1291
1292 base = dai->driver->base;
1293
1294 lrclk = 0;
1295 bclk = 0;
1296
1297 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
1298 case SND_SOC_DAIFMT_DSP_A:
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001299 mode = ARIZONA_FMT_DSP_MODE_A;
1300 break;
1301 case SND_SOC_DAIFMT_DSP_B:
1302 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
1303 != SND_SOC_DAIFMT_CBM_CFM) {
1304 arizona_aif_err(dai, "DSP_B not valid in slave mode\n");
1305 return -EINVAL;
1306 }
1307 mode = ARIZONA_FMT_DSP_MODE_B;
Mark Brown07ed8732012-06-18 21:08:44 +01001308 break;
Mark Brown07ed8732012-06-18 21:08:44 +01001309 case SND_SOC_DAIFMT_I2S:
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001310 mode = ARIZONA_FMT_I2S_MODE;
1311 break;
1312 case SND_SOC_DAIFMT_LEFT_J:
1313 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
1314 != SND_SOC_DAIFMT_CBM_CFM) {
1315 arizona_aif_err(dai, "LEFT_J not valid in slave mode\n");
1316 return -EINVAL;
1317 }
1318 mode = ARIZONA_FMT_LEFT_JUSTIFIED_MODE;
Mark Brown07ed8732012-06-18 21:08:44 +01001319 break;
Mark Brown07ed8732012-06-18 21:08:44 +01001320 default:
1321 arizona_aif_err(dai, "Unsupported DAI format %d\n",
1322 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
1323 return -EINVAL;
1324 }
1325
1326 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
1327 case SND_SOC_DAIFMT_CBS_CFS:
1328 break;
1329 case SND_SOC_DAIFMT_CBS_CFM:
1330 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
1331 break;
1332 case SND_SOC_DAIFMT_CBM_CFS:
1333 bclk |= ARIZONA_AIF1_BCLK_MSTR;
1334 break;
1335 case SND_SOC_DAIFMT_CBM_CFM:
1336 bclk |= ARIZONA_AIF1_BCLK_MSTR;
1337 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
1338 break;
1339 default:
1340 arizona_aif_err(dai, "Unsupported master mode %d\n",
1341 fmt & SND_SOC_DAIFMT_MASTER_MASK);
1342 return -EINVAL;
1343 }
1344
1345 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1346 case SND_SOC_DAIFMT_NB_NF:
1347 break;
1348 case SND_SOC_DAIFMT_IB_IF:
1349 bclk |= ARIZONA_AIF1_BCLK_INV;
1350 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
1351 break;
1352 case SND_SOC_DAIFMT_IB_NF:
1353 bclk |= ARIZONA_AIF1_BCLK_INV;
1354 break;
1355 case SND_SOC_DAIFMT_NB_IF:
1356 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
1357 break;
1358 default:
1359 return -EINVAL;
1360 }
1361
Mark Brown3c43c692013-12-12 00:49:22 +00001362 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_BCLK_CTRL,
1363 ARIZONA_AIF1_BCLK_INV |
1364 ARIZONA_AIF1_BCLK_MSTR,
1365 bclk);
1366 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_TX_PIN_CTRL,
1367 ARIZONA_AIF1TX_LRCLK_INV |
1368 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
1369 regmap_update_bits_async(arizona->regmap,
1370 base + ARIZONA_AIF_RX_PIN_CTRL,
1371 ARIZONA_AIF1RX_LRCLK_INV |
1372 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
1373 regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FORMAT,
1374 ARIZONA_AIF1_FMT_MASK, mode);
Mark Brown07ed8732012-06-18 21:08:44 +01001375
1376 return 0;
1377}
1378
Mark Brown949e6bc2012-07-04 18:58:04 +01001379static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001380 -1,
1381 48000,
1382 64000,
1383 96000,
1384 128000,
1385 192000,
1386 256000,
1387 384000,
1388 512000,
1389 768000,
1390 1024000,
1391 1536000,
1392 2048000,
1393 3072000,
1394 4096000,
1395 6144000,
1396 8192000,
1397 12288000,
1398 24576000,
1399};
1400
Mark Brown5b2eec32012-07-04 17:32:05 +01001401static const unsigned int arizona_48k_rates[] = {
1402 12000,
1403 24000,
1404 48000,
1405 96000,
1406 192000,
1407 384000,
1408 768000,
1409 4000,
1410 8000,
1411 16000,
1412 32000,
1413 64000,
1414 128000,
1415 256000,
1416 512000,
1417};
1418
1419static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = {
1420 .count = ARRAY_SIZE(arizona_48k_rates),
1421 .list = arizona_48k_rates,
1422};
1423
Mark Brown949e6bc2012-07-04 18:58:04 +01001424static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001425 -1,
1426 44100,
1427 58800,
1428 88200,
1429 117600,
1430 177640,
1431 235200,
1432 352800,
1433 470400,
1434 705600,
1435 940800,
1436 1411200,
1437 1881600,
Heather Lomond4758be32012-09-05 05:02:10 -04001438 2822400,
Mark Brown07ed8732012-06-18 21:08:44 +01001439 3763200,
1440 5644800,
1441 7526400,
1442 11289600,
1443 22579200,
1444};
1445
Mark Brown5b2eec32012-07-04 17:32:05 +01001446static const unsigned int arizona_44k1_rates[] = {
1447 11025,
1448 22050,
1449 44100,
1450 88200,
1451 176400,
1452 352800,
1453 705600,
1454};
1455
1456static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = {
1457 .count = ARRAY_SIZE(arizona_44k1_rates),
1458 .list = arizona_44k1_rates,
1459};
1460
Mark Brown07ed8732012-06-18 21:08:44 +01001461static int arizona_sr_vals[] = {
1462 0,
1463 12000,
1464 24000,
1465 48000,
1466 96000,
1467 192000,
1468 384000,
1469 768000,
1470 0,
1471 11025,
1472 22050,
1473 44100,
1474 88200,
1475 176400,
1476 352800,
1477 705600,
1478 4000,
1479 8000,
1480 16000,
1481 32000,
1482 64000,
1483 128000,
1484 256000,
1485 512000,
1486};
1487
Mark Brown5b2eec32012-07-04 17:32:05 +01001488static int arizona_startup(struct snd_pcm_substream *substream,
1489 struct snd_soc_dai *dai)
1490{
1491 struct snd_soc_codec *codec = dai->codec;
1492 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1493 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
1494 const struct snd_pcm_hw_constraint_list *constraint;
1495 unsigned int base_rate;
1496
1497 switch (dai_priv->clk) {
1498 case ARIZONA_CLK_SYSCLK:
1499 base_rate = priv->sysclk;
1500 break;
1501 case ARIZONA_CLK_ASYNCCLK:
1502 base_rate = priv->asyncclk;
1503 break;
1504 default:
1505 return 0;
1506 }
1507
Mark Brownf2c26d42013-01-21 16:09:36 +09001508 if (base_rate == 0)
1509 return 0;
1510
Mark Brown5b2eec32012-07-04 17:32:05 +01001511 if (base_rate % 8000)
1512 constraint = &arizona_44k1_constraint;
1513 else
1514 constraint = &arizona_48k_constraint;
1515
1516 return snd_pcm_hw_constraint_list(substream->runtime, 0,
1517 SNDRV_PCM_HW_PARAM_RATE,
1518 constraint);
1519}
1520
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001521static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec,
1522 unsigned int rate)
1523{
1524 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1525 struct arizona *arizona = priv->arizona;
Nariman Poushin8019ff62015-07-16 16:36:21 +01001526 struct reg_sequence dac_comp[] = {
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001527 { 0x80, 0x3 },
1528 { ARIZONA_DAC_COMP_1, 0 },
1529 { ARIZONA_DAC_COMP_2, 0 },
1530 { 0x80, 0x0 },
1531 };
1532
Lars-Peter Clausend74bcaa2014-11-09 17:00:59 +01001533 mutex_lock(&arizona->dac_comp_lock);
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001534
1535 dac_comp[1].def = arizona->dac_comp_coeff;
1536 if (rate >= 176400)
1537 dac_comp[2].def = arizona->dac_comp_enabled;
1538
Lars-Peter Clausend74bcaa2014-11-09 17:00:59 +01001539 mutex_unlock(&arizona->dac_comp_lock);
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001540
1541 regmap_multi_reg_write(arizona->regmap,
1542 dac_comp,
1543 ARRAY_SIZE(dac_comp));
1544}
1545
Mark Brownb272efc2012-10-10 15:10:08 +09001546static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
1547 struct snd_pcm_hw_params *params,
1548 struct snd_soc_dai *dai)
Mark Brown07ed8732012-06-18 21:08:44 +01001549{
1550 struct snd_soc_codec *codec = dai->codec;
Mark Brownc013b272012-07-04 20:05:57 +01001551 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1552 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown07ed8732012-06-18 21:08:44 +01001553 int base = dai->driver->base;
Richard Fitzgerald2c118b42015-06-02 11:53:35 +01001554 int i, sr_val, ret;
Mark Brownb272efc2012-10-10 15:10:08 +09001555
1556 /*
1557 * We will need to be more flexible than this in future,
1558 * currently we use a single sample rate for SYSCLK.
1559 */
1560 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
1561 if (arizona_sr_vals[i] == params_rate(params))
1562 break;
1563 if (i == ARRAY_SIZE(arizona_sr_vals)) {
1564 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1565 params_rate(params));
1566 return -EINVAL;
1567 }
1568 sr_val = i;
1569
Richard Fitzgerald2c118b42015-06-02 11:53:35 +01001570 switch (priv->arizona->type) {
1571 case WM5102:
1572 case WM8997:
1573 if (arizona_sr_vals[sr_val] >= 88200)
1574 ret = arizona_dvfs_up(codec, ARIZONA_DVFS_SR1_RQ);
1575 else
1576 ret = arizona_dvfs_down(codec, ARIZONA_DVFS_SR1_RQ);
1577
1578 if (ret) {
1579 arizona_aif_err(dai, "Failed to change DVFS %d\n", ret);
1580 return ret;
1581 }
1582 break;
1583 default:
1584 break;
1585 }
1586
Mark Brownb272efc2012-10-10 15:10:08 +09001587 switch (dai_priv->clk) {
1588 case ARIZONA_CLK_SYSCLK:
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001589 switch (priv->arizona->type) {
1590 case WM5102:
1591 arizona_wm5102_set_dac_comp(codec,
1592 params_rate(params));
1593 break;
1594 default:
1595 break;
1596 }
1597
Mark Brownb272efc2012-10-10 15:10:08 +09001598 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
1599 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
1600 if (base)
1601 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1602 ARIZONA_AIF1_RATE_MASK, 0);
1603 break;
1604 case ARIZONA_CLK_ASYNCCLK:
1605 snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
Charles Keepaxc24084d2014-09-01 15:48:52 +01001606 ARIZONA_ASYNC_SAMPLE_RATE_1_MASK, sr_val);
Mark Brownb272efc2012-10-10 15:10:08 +09001607 if (base)
1608 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1609 ARIZONA_AIF1_RATE_MASK,
1610 8 << ARIZONA_AIF1_RATE_SHIFT);
1611 break;
1612 default:
1613 arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
1614 return -EINVAL;
1615 }
1616
1617 return 0;
1618}
1619
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001620static bool arizona_aif_cfg_changed(struct snd_soc_codec *codec,
1621 int base, int bclk, int lrclk, int frame)
1622{
1623 int val;
1624
1625 val = snd_soc_read(codec, base + ARIZONA_AIF_BCLK_CTRL);
1626 if (bclk != (val & ARIZONA_AIF1_BCLK_FREQ_MASK))
1627 return true;
1628
1629 val = snd_soc_read(codec, base + ARIZONA_AIF_TX_BCLK_RATE);
1630 if (lrclk != (val & ARIZONA_AIF1TX_BCPF_MASK))
1631 return true;
1632
1633 val = snd_soc_read(codec, base + ARIZONA_AIF_FRAME_CTRL_1);
1634 if (frame != (val & (ARIZONA_AIF1TX_WL_MASK |
1635 ARIZONA_AIF1TX_SLOT_LEN_MASK)))
1636 return true;
1637
1638 return false;
1639}
1640
Mark Brown07ed8732012-06-18 21:08:44 +01001641static int arizona_hw_params(struct snd_pcm_substream *substream,
1642 struct snd_pcm_hw_params *params,
1643 struct snd_soc_dai *dai)
1644{
1645 struct snd_soc_codec *codec = dai->codec;
1646 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brownc94aa302013-01-17 16:35:14 +09001647 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +01001648 int base = dai->driver->base;
1649 const int *rates;
Mark Brown76bf9692013-03-05 14:17:47 +08001650 int i, ret, val;
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001651 int channels = params_channels(params);
Mark Brownc94aa302013-01-17 16:35:14 +09001652 int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001653 int tdm_width = arizona->tdm_width[dai->id - 1];
1654 int tdm_slots = arizona->tdm_slots[dai->id - 1];
Mark Brownc94aa302013-01-17 16:35:14 +09001655 int bclk, lrclk, wl, frame, bclk_target;
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001656 bool reconfig;
1657 unsigned int aif_tx_state, aif_rx_state;
Mark Brown07ed8732012-06-18 21:08:44 +01001658
1659 if (params_rate(params) % 8000)
Mark Brown949e6bc2012-07-04 18:58:04 +01001660 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001661 else
Mark Brown949e6bc2012-07-04 18:58:04 +01001662 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001663
Charles Keepax5ed68f02015-07-09 11:28:46 +01001664 wl = params_width(params);
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001665
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001666 if (tdm_slots) {
1667 arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n",
1668 tdm_slots, tdm_width);
1669 bclk_target = tdm_slots * tdm_width * params_rate(params);
1670 channels = tdm_slots;
1671 } else {
1672 bclk_target = snd_soc_params_to_bclk(params);
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001673 tdm_width = wl;
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001674 }
1675
1676 if (chan_limit && chan_limit < channels) {
Mark Brownc94aa302013-01-17 16:35:14 +09001677 arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001678 bclk_target /= channels;
Mark Brownc94aa302013-01-17 16:35:14 +09001679 bclk_target *= chan_limit;
1680 }
1681
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001682 /* Force multiple of 2 channels for I2S mode */
Mark Brown76bf9692013-03-05 14:17:47 +08001683 val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001684 val &= ARIZONA_AIF1_FMT_MASK;
1685 if ((channels & 1) && (val == ARIZONA_FMT_I2S_MODE)) {
Mark Brown76bf9692013-03-05 14:17:47 +08001686 arizona_aif_dbg(dai, "Forcing stereo mode\n");
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001687 bclk_target /= channels;
1688 bclk_target *= channels + 1;
Mark Brown76bf9692013-03-05 14:17:47 +08001689 }
1690
Mark Brown949e6bc2012-07-04 18:58:04 +01001691 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brownc94aa302013-01-17 16:35:14 +09001692 if (rates[i] >= bclk_target &&
Mark Brown50017652012-07-04 19:07:09 +01001693 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +01001694 bclk = i;
1695 break;
1696 }
1697 }
Mark Brown949e6bc2012-07-04 18:58:04 +01001698 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001699 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1700 params_rate(params));
1701 return -EINVAL;
1702 }
1703
Mark Brownb59e0f82013-01-17 14:15:59 +09001704 lrclk = rates[bclk] / params_rate(params);
Mark Brown07ed8732012-06-18 21:08:44 +01001705
1706 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
1707 rates[bclk], rates[bclk] / lrclk);
1708
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001709 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | tdm_width;
Mark Brown07ed8732012-06-18 21:08:44 +01001710
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001711 reconfig = arizona_aif_cfg_changed(codec, base, bclk, lrclk, frame);
1712
1713 if (reconfig) {
1714 /* Save AIF TX/RX state */
1715 aif_tx_state = snd_soc_read(codec,
1716 base + ARIZONA_AIF_TX_ENABLES);
1717 aif_rx_state = snd_soc_read(codec,
1718 base + ARIZONA_AIF_RX_ENABLES);
1719 /* Disable AIF TX/RX before reconfiguring it */
1720 regmap_update_bits_async(arizona->regmap,
1721 base + ARIZONA_AIF_TX_ENABLES, 0xff, 0x0);
1722 regmap_update_bits(arizona->regmap,
1723 base + ARIZONA_AIF_RX_ENABLES, 0xff, 0x0);
1724 }
1725
Mark Brownb272efc2012-10-10 15:10:08 +09001726 ret = arizona_hw_params_rate(substream, params, dai);
1727 if (ret != 0)
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001728 goto restore_aif;
Mark Brownc013b272012-07-04 20:05:57 +01001729
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001730 if (reconfig) {
1731 regmap_update_bits_async(arizona->regmap,
1732 base + ARIZONA_AIF_BCLK_CTRL,
1733 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
1734 regmap_update_bits_async(arizona->regmap,
1735 base + ARIZONA_AIF_TX_BCLK_RATE,
1736 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
1737 regmap_update_bits_async(arizona->regmap,
1738 base + ARIZONA_AIF_RX_BCLK_RATE,
1739 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
1740 regmap_update_bits_async(arizona->regmap,
1741 base + ARIZONA_AIF_FRAME_CTRL_1,
1742 ARIZONA_AIF1TX_WL_MASK |
1743 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
1744 regmap_update_bits(arizona->regmap,
1745 base + ARIZONA_AIF_FRAME_CTRL_2,
1746 ARIZONA_AIF1RX_WL_MASK |
1747 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
1748 }
Mark Brown07ed8732012-06-18 21:08:44 +01001749
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001750restore_aif:
1751 if (reconfig) {
1752 /* Restore AIF TX/RX state */
1753 regmap_update_bits_async(arizona->regmap,
1754 base + ARIZONA_AIF_TX_ENABLES,
1755 0xff, aif_tx_state);
1756 regmap_update_bits(arizona->regmap,
1757 base + ARIZONA_AIF_RX_ENABLES,
1758 0xff, aif_rx_state);
1759 }
1760 return ret;
Mark Brown07ed8732012-06-18 21:08:44 +01001761}
1762
Mark Brown410837a2012-07-05 17:26:59 +01001763static const char *arizona_dai_clk_str(int clk_id)
1764{
1765 switch (clk_id) {
1766 case ARIZONA_CLK_SYSCLK:
1767 return "SYSCLK";
1768 case ARIZONA_CLK_ASYNCCLK:
1769 return "ASYNCCLK";
1770 default:
1771 return "Unknown clock";
1772 }
1773}
1774
Mark Brown5b2eec32012-07-04 17:32:05 +01001775static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
1776 int clk_id, unsigned int freq, int dir)
1777{
1778 struct snd_soc_codec *codec = dai->codec;
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +02001779 struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
Mark Brown5b2eec32012-07-04 17:32:05 +01001780 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1781 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown410837a2012-07-05 17:26:59 +01001782 struct snd_soc_dapm_route routes[2];
Mark Brown5b2eec32012-07-04 17:32:05 +01001783
1784 switch (clk_id) {
1785 case ARIZONA_CLK_SYSCLK:
1786 case ARIZONA_CLK_ASYNCCLK:
1787 break;
1788 default:
1789 return -EINVAL;
1790 }
1791
Mark Brown410837a2012-07-05 17:26:59 +01001792 if (clk_id == dai_priv->clk)
1793 return 0;
1794
1795 if (dai->active) {
Mark Brown5b2eec32012-07-04 17:32:05 +01001796 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
1797 dai->id);
1798 return -EBUSY;
1799 }
1800
Mark Brownc8d35a62012-12-07 12:49:40 +09001801 dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1,
1802 arizona_dai_clk_str(clk_id));
1803
Mark Brown410837a2012-07-05 17:26:59 +01001804 memset(&routes, 0, sizeof(routes));
1805 routes[0].sink = dai->driver->capture.stream_name;
1806 routes[1].sink = dai->driver->playback.stream_name;
Mark Brown5b2eec32012-07-04 17:32:05 +01001807
Mark Brown410837a2012-07-05 17:26:59 +01001808 routes[0].source = arizona_dai_clk_str(dai_priv->clk);
1809 routes[1].source = arizona_dai_clk_str(dai_priv->clk);
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +02001810 snd_soc_dapm_del_routes(dapm, routes, ARRAY_SIZE(routes));
Mark Brown410837a2012-07-05 17:26:59 +01001811
1812 routes[0].source = arizona_dai_clk_str(clk_id);
1813 routes[1].source = arizona_dai_clk_str(clk_id);
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +02001814 snd_soc_dapm_add_routes(dapm, routes, ARRAY_SIZE(routes));
Mark Brown410837a2012-07-05 17:26:59 +01001815
Mark Brown0c778e82012-12-06 18:22:25 +09001816 dai_priv->clk = clk_id;
1817
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +02001818 return snd_soc_dapm_sync(dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +01001819}
1820
Mark Brown01df2592012-12-12 16:22:08 +09001821static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
1822{
1823 struct snd_soc_codec *codec = dai->codec;
1824 int base = dai->driver->base;
1825 unsigned int reg;
1826
1827 if (tristate)
1828 reg = ARIZONA_AIF1_TRI;
1829 else
1830 reg = 0;
1831
1832 return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1833 ARIZONA_AIF1_TRI, reg);
1834}
1835
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001836static void arizona_set_channels_to_mask(struct snd_soc_dai *dai,
1837 unsigned int base,
1838 int channels, unsigned int mask)
1839{
1840 struct snd_soc_codec *codec = dai->codec;
1841 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1842 struct arizona *arizona = priv->arizona;
1843 int slot, i;
1844
1845 for (i = 0; i < channels; ++i) {
1846 slot = ffs(mask) - 1;
1847 if (slot < 0)
1848 return;
1849
1850 regmap_write(arizona->regmap, base + i, slot);
1851
1852 mask &= ~(1 << slot);
1853 }
1854
1855 if (mask)
1856 arizona_aif_warn(dai, "Too many channels in TDM mask\n");
1857}
1858
1859static int arizona_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
1860 unsigned int rx_mask, int slots, int slot_width)
1861{
1862 struct snd_soc_codec *codec = dai->codec;
1863 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1864 struct arizona *arizona = priv->arizona;
1865 int base = dai->driver->base;
1866 int rx_max_chan = dai->driver->playback.channels_max;
1867 int tx_max_chan = dai->driver->capture.channels_max;
1868
1869 /* Only support TDM for the physical AIFs */
1870 if (dai->id > ARIZONA_MAX_AIF)
1871 return -ENOTSUPP;
1872
1873 if (slots == 0) {
1874 tx_mask = (1 << tx_max_chan) - 1;
1875 rx_mask = (1 << rx_max_chan) - 1;
1876 }
1877
1878 arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_3,
1879 tx_max_chan, tx_mask);
1880 arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_11,
1881 rx_max_chan, rx_mask);
1882
1883 arizona->tdm_width[dai->id - 1] = slot_width;
1884 arizona->tdm_slots[dai->id - 1] = slots;
1885
1886 return 0;
1887}
1888
Mark Brown07ed8732012-06-18 21:08:44 +01001889const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +01001890 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +01001891 .set_fmt = arizona_set_fmt,
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001892 .set_tdm_slot = arizona_set_tdm_slot,
Mark Brown07ed8732012-06-18 21:08:44 +01001893 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +01001894 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown01df2592012-12-12 16:22:08 +09001895 .set_tristate = arizona_set_tristate,
Mark Brown07ed8732012-06-18 21:08:44 +01001896};
Mark Browna8379872012-07-09 12:16:41 +01001897EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +01001898
Mark Brownbd1dd882013-05-17 13:29:03 +01001899const struct snd_soc_dai_ops arizona_simple_dai_ops = {
1900 .startup = arizona_startup,
1901 .hw_params = arizona_hw_params_rate,
1902 .set_sysclk = arizona_dai_set_sysclk,
1903};
1904EXPORT_SYMBOL_GPL(arizona_simple_dai_ops);
1905
Mark Brown5b2eec32012-07-04 17:32:05 +01001906int arizona_init_dai(struct arizona_priv *priv, int id)
1907{
1908 struct arizona_dai_priv *dai_priv = &priv->dai[id];
1909
1910 dai_priv->clk = ARIZONA_CLK_SYSCLK;
1911
1912 return 0;
1913}
1914EXPORT_SYMBOL_GPL(arizona_init_dai);
1915
Mark Brown07ed8732012-06-18 21:08:44 +01001916static struct {
1917 unsigned int min;
1918 unsigned int max;
1919 u16 fratio;
1920 int ratio;
1921} fll_fratios[] = {
1922 { 0, 64000, 4, 16 },
1923 { 64000, 128000, 3, 8 },
1924 { 128000, 256000, 2, 4 },
1925 { 256000, 1000000, 1, 2 },
1926 { 1000000, 13500000, 0, 1 },
1927};
1928
Mark Brown8f113d72013-03-05 12:08:57 +08001929static struct {
1930 unsigned int min;
1931 unsigned int max;
1932 u16 gain;
1933} fll_gains[] = {
1934 { 0, 256000, 0 },
1935 { 256000, 1000000, 2 },
1936 { 1000000, 13500000, 4 },
1937};
1938
Mark Brown07ed8732012-06-18 21:08:44 +01001939struct arizona_fll_cfg {
1940 int n;
1941 int theta;
1942 int lambda;
1943 int refdiv;
1944 int outdiv;
1945 int fratio;
Mark Brown8f113d72013-03-05 12:08:57 +08001946 int gain;
Mark Brown07ed8732012-06-18 21:08:44 +01001947};
1948
Charles Keepax23f785a82014-03-07 16:34:20 +00001949static int arizona_validate_fll(struct arizona_fll *fll,
1950 unsigned int Fref,
1951 unsigned int Fout)
1952{
1953 unsigned int Fvco_min;
1954
Charles Keepaxc8badda2014-07-09 17:41:49 +01001955 if (fll->fout && Fout != fll->fout) {
1956 arizona_fll_err(fll,
1957 "Can't change output on active FLL\n");
1958 return -EINVAL;
1959 }
1960
Charles Keepax23f785a82014-03-07 16:34:20 +00001961 if (Fref / ARIZONA_FLL_MAX_REFDIV > ARIZONA_FLL_MAX_FREF) {
1962 arizona_fll_err(fll,
1963 "Can't scale %dMHz in to <=13.5MHz\n",
1964 Fref);
1965 return -EINVAL;
1966 }
1967
1968 Fvco_min = ARIZONA_FLL_MIN_FVCO * fll->vco_mult;
1969 if (Fout * ARIZONA_FLL_MAX_OUTDIV < Fvco_min) {
1970 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
1971 Fout);
1972 return -EINVAL;
1973 }
1974
1975 return 0;
1976}
1977
Charles Keepaxd0800342014-03-07 16:34:25 +00001978static int arizona_find_fratio(unsigned int Fref, int *fratio)
1979{
1980 int i;
1981
1982 /* Find an appropriate FLL_FRATIO */
1983 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
1984 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
1985 if (fratio)
1986 *fratio = fll_fratios[i].fratio;
1987 return fll_fratios[i].ratio;
1988 }
1989 }
1990
1991 return -EINVAL;
1992}
1993
1994static int arizona_calc_fratio(struct arizona_fll *fll,
1995 struct arizona_fll_cfg *cfg,
1996 unsigned int target,
1997 unsigned int Fref, bool sync)
1998{
1999 int init_ratio, ratio;
2000 int refdiv, div;
2001
2002 /* Fref must be <=13.5MHz, find initial refdiv */
2003 div = 1;
2004 cfg->refdiv = 0;
2005 while (Fref > ARIZONA_FLL_MAX_FREF) {
2006 div *= 2;
2007 Fref /= 2;
2008 cfg->refdiv++;
2009
2010 if (div > ARIZONA_FLL_MAX_REFDIV)
2011 return -EINVAL;
2012 }
2013
2014 /* Find an appropriate FLL_FRATIO */
2015 init_ratio = arizona_find_fratio(Fref, &cfg->fratio);
2016 if (init_ratio < 0) {
2017 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
2018 Fref);
2019 return init_ratio;
2020 }
2021
2022 switch (fll->arizona->type) {
2023 case WM5110:
Richard Fitzgerald575ef7f2015-01-17 15:21:27 +00002024 case WM8280:
Charles Keepaxd0800342014-03-07 16:34:25 +00002025 if (fll->arizona->rev < 3 || sync)
2026 return init_ratio;
2027 break;
Richard Fitzgerald6ebbce02015-09-28 14:01:09 +01002028 case WM8998:
2029 case WM1814:
2030 if (sync)
2031 return init_ratio;
2032 break;
Charles Keepaxd0800342014-03-07 16:34:25 +00002033 default:
2034 return init_ratio;
2035 }
2036
2037 cfg->fratio = init_ratio - 1;
2038
2039 /* Adjust FRATIO/refdiv to avoid integer mode if possible */
2040 refdiv = cfg->refdiv;
2041
2042 while (div <= ARIZONA_FLL_MAX_REFDIV) {
2043 for (ratio = init_ratio; ratio <= ARIZONA_FLL_MAX_FRATIO;
2044 ratio++) {
Charles Keepax35a730a2014-07-09 17:41:45 +01002045 if ((ARIZONA_FLL_VCO_CORNER / 2) /
2046 (fll->vco_mult * ratio) < Fref)
Charles Keepax29fee822014-07-09 17:41:44 +01002047 break;
2048
Charles Keepaxd0800342014-03-07 16:34:25 +00002049 if (target % (ratio * Fref)) {
2050 cfg->refdiv = refdiv;
2051 cfg->fratio = ratio - 1;
2052 return ratio;
2053 }
2054 }
2055
Charles Keepax4714bc02014-07-09 17:41:43 +01002056 for (ratio = init_ratio - 1; ratio > 0; ratio--) {
Charles Keepaxd0800342014-03-07 16:34:25 +00002057 if (target % (ratio * Fref)) {
2058 cfg->refdiv = refdiv;
2059 cfg->fratio = ratio - 1;
2060 return ratio;
2061 }
2062 }
2063
2064 div *= 2;
2065 Fref /= 2;
2066 refdiv++;
2067 init_ratio = arizona_find_fratio(Fref, NULL);
2068 }
2069
2070 arizona_fll_warn(fll, "Falling back to integer mode operation\n");
2071 return cfg->fratio + 1;
2072}
2073
Mark Brown07ed8732012-06-18 21:08:44 +01002074static int arizona_calc_fll(struct arizona_fll *fll,
2075 struct arizona_fll_cfg *cfg,
Charles Keepaxd0800342014-03-07 16:34:25 +00002076 unsigned int Fref, bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01002077{
2078 unsigned int target, div, gcd_fll;
2079 int i, ratio;
2080
Charles Keepax8ccefcd2014-03-07 16:34:21 +00002081 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, fll->fout);
Mark Brown07ed8732012-06-18 21:08:44 +01002082
Mark Brown2b4d39f2012-07-10 17:03:46 +01002083 /* Fvco should be over the targt; don't check the upper bound */
Charles Keepaxf641aec2014-03-07 16:34:22 +00002084 div = ARIZONA_FLL_MIN_OUTDIV;
2085 while (fll->fout * div < ARIZONA_FLL_MIN_FVCO * fll->vco_mult) {
Mark Brown07ed8732012-06-18 21:08:44 +01002086 div++;
Charles Keepaxf641aec2014-03-07 16:34:22 +00002087 if (div > ARIZONA_FLL_MAX_OUTDIV)
Mark Brown07ed8732012-06-18 21:08:44 +01002088 return -EINVAL;
Mark Brown07ed8732012-06-18 21:08:44 +01002089 }
Charles Keepaxf641aec2014-03-07 16:34:22 +00002090 target = fll->fout * div / fll->vco_mult;
Mark Brown07ed8732012-06-18 21:08:44 +01002091 cfg->outdiv = div;
2092
2093 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
2094
Charles Keepaxd0800342014-03-07 16:34:25 +00002095 /* Find an appropriate FLL_FRATIO and refdiv */
2096 ratio = arizona_calc_fratio(fll, cfg, target, Fref, sync);
2097 if (ratio < 0)
2098 return ratio;
Mark Brown07ed8732012-06-18 21:08:44 +01002099
Mark Brown07ed8732012-06-18 21:08:44 +01002100 /* Apply the division for our remaining calculations */
Charles Keepaxd0800342014-03-07 16:34:25 +00002101 Fref = Fref / (1 << cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08002102
Mark Brown07ed8732012-06-18 21:08:44 +01002103 cfg->n = target / (ratio * Fref);
2104
Ryo Tsutsui01f58152013-02-03 17:18:00 +09002105 if (target % (ratio * Fref)) {
Mark Brown07ed8732012-06-18 21:08:44 +01002106 gcd_fll = gcd(target, ratio * Fref);
2107 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
2108
2109 cfg->theta = (target - (cfg->n * ratio * Fref))
2110 / gcd_fll;
2111 cfg->lambda = (ratio * Fref) / gcd_fll;
2112 } else {
2113 cfg->theta = 0;
2114 cfg->lambda = 0;
2115 }
2116
Ryo Tsutsui01f58152013-02-03 17:18:00 +09002117 /* Round down to 16bit range with cost of accuracy lost.
2118 * Denominator must be bigger than numerator so we only
2119 * take care of it.
2120 */
2121 while (cfg->lambda >= (1 << 16)) {
2122 cfg->theta >>= 1;
2123 cfg->lambda >>= 1;
2124 }
2125
Charles Keepax5a3935c2014-03-07 16:34:23 +00002126 for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
2127 if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
2128 cfg->gain = fll_gains[i].gain;
2129 break;
2130 }
2131 }
2132 if (i == ARRAY_SIZE(fll_gains)) {
2133 arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
2134 Fref);
2135 return -EINVAL;
2136 }
2137
Mark Brown07ed8732012-06-18 21:08:44 +01002138 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
2139 cfg->n, cfg->theta, cfg->lambda);
2140 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
2141 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08002142 arizona_fll_dbg(fll, "GAIN=%d\n", cfg->gain);
Mark Brown07ed8732012-06-18 21:08:44 +01002143
2144 return 0;
2145
2146}
2147
2148static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
Mark Brown8f113d72013-03-05 12:08:57 +08002149 struct arizona_fll_cfg *cfg, int source,
2150 bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01002151{
Mark Brown3c43c692013-12-12 00:49:22 +00002152 regmap_update_bits_async(arizona->regmap, base + 3,
2153 ARIZONA_FLL1_THETA_MASK, cfg->theta);
2154 regmap_update_bits_async(arizona->regmap, base + 4,
2155 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
2156 regmap_update_bits_async(arizona->regmap, base + 5,
2157 ARIZONA_FLL1_FRATIO_MASK,
2158 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
2159 regmap_update_bits_async(arizona->regmap, base + 6,
2160 ARIZONA_FLL1_CLK_REF_DIV_MASK |
2161 ARIZONA_FLL1_CLK_REF_SRC_MASK,
2162 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
2163 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
Mark Brown07ed8732012-06-18 21:08:44 +01002164
Charles Keepax61719db2014-03-07 16:34:19 +00002165 if (sync) {
2166 regmap_update_bits(arizona->regmap, base + 0x7,
2167 ARIZONA_FLL1_GAIN_MASK,
2168 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
2169 } else {
2170 regmap_update_bits(arizona->regmap, base + 0x5,
2171 ARIZONA_FLL1_OUTDIV_MASK,
2172 cfg->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
2173 regmap_update_bits(arizona->regmap, base + 0x9,
2174 ARIZONA_FLL1_GAIN_MASK,
2175 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
2176 }
Mark Brown8f113d72013-03-05 12:08:57 +08002177
Mark Brown3c43c692013-12-12 00:49:22 +00002178 regmap_update_bits_async(arizona->regmap, base + 2,
2179 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
2180 ARIZONA_FLL1_CTRL_UPD | cfg->n);
Mark Brown07ed8732012-06-18 21:08:44 +01002181}
2182
Charles Keepaxc393aca2014-07-09 17:41:47 +01002183static int arizona_is_enabled_fll(struct arizona_fll *fll)
Charles Keepaxd122d6c2013-02-20 17:28:36 +00002184{
2185 struct arizona *arizona = fll->arizona;
2186 unsigned int reg;
2187 int ret;
2188
2189 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
2190 if (ret != 0) {
2191 arizona_fll_err(fll, "Failed to read current state: %d\n",
2192 ret);
2193 return ret;
2194 }
2195
2196 return reg & ARIZONA_FLL1_ENA;
2197}
2198
Charles Keepaxc393aca2014-07-09 17:41:47 +01002199static int arizona_enable_fll(struct arizona_fll *fll)
Charles Keepax35722812013-02-20 17:28:38 +00002200{
2201 struct arizona *arizona = fll->arizona;
Charles Keepax49c60542013-09-16 15:34:35 +01002202 bool use_sync = false;
Charles Keepaxc393aca2014-07-09 17:41:47 +01002203 int already_enabled = arizona_is_enabled_fll(fll);
Charles Keepax23f785a82014-03-07 16:34:20 +00002204 struct arizona_fll_cfg cfg;
Charles Keepax0e765972015-08-25 12:43:48 +01002205 int i;
2206 unsigned int val;
Charles Keepax35722812013-02-20 17:28:38 +00002207
Charles Keepaxc393aca2014-07-09 17:41:47 +01002208 if (already_enabled < 0)
2209 return already_enabled;
2210
Charles Keepaxc8badda2014-07-09 17:41:49 +01002211 if (already_enabled) {
2212 /* Facilitate smooth refclk across the transition */
Nikesh Oswal1cf5a332015-08-19 16:02:24 +01002213 regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9,
Charles Keepaxc8badda2014-07-09 17:41:49 +01002214 ARIZONA_FLL1_GAIN_MASK, 0);
Charles Keepax800f2972015-11-30 17:37:28 +00002215 regmap_update_bits(fll->arizona->regmap, fll->base + 1,
2216 ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
2217 udelay(32);
Charles Keepaxc8badda2014-07-09 17:41:49 +01002218 }
2219
Mark Brownff680a12013-03-04 16:00:19 +08002220 /*
2221 * If we have both REFCLK and SYNCCLK then enable both,
2222 * otherwise apply the SYNCCLK settings to REFCLK.
2223 */
Charles Keepax49c60542013-09-16 15:34:35 +01002224 if (fll->ref_src >= 0 && fll->ref_freq &&
2225 fll->ref_src != fll->sync_src) {
Charles Keepaxd0800342014-03-07 16:34:25 +00002226 arizona_calc_fll(fll, &cfg, fll->ref_freq, false);
Charles Keepax35722812013-02-20 17:28:38 +00002227
Charles Keepax23f785a82014-03-07 16:34:20 +00002228 arizona_apply_fll(arizona, fll->base, &cfg, fll->ref_src,
Mark Brown8f113d72013-03-05 12:08:57 +08002229 false);
Charles Keepax49c60542013-09-16 15:34:35 +01002230 if (fll->sync_src >= 0) {
Charles Keepaxd0800342014-03-07 16:34:25 +00002231 arizona_calc_fll(fll, &cfg, fll->sync_freq, true);
Charles Keepax23f785a82014-03-07 16:34:20 +00002232
2233 arizona_apply_fll(arizona, fll->base + 0x10, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08002234 fll->sync_src, true);
Charles Keepax49c60542013-09-16 15:34:35 +01002235 use_sync = true;
2236 }
Mark Brownff680a12013-03-04 16:00:19 +08002237 } else if (fll->sync_src >= 0) {
Charles Keepaxd0800342014-03-07 16:34:25 +00002238 arizona_calc_fll(fll, &cfg, fll->sync_freq, false);
Mark Brownff680a12013-03-04 16:00:19 +08002239
Charles Keepax23f785a82014-03-07 16:34:20 +00002240 arizona_apply_fll(arizona, fll->base, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08002241 fll->sync_src, false);
Mark Browneca2e8e2013-03-06 00:09:59 +08002242
Mark Brown3c43c692013-12-12 00:49:22 +00002243 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
2244 ARIZONA_FLL1_SYNC_ENA, 0);
Mark Brownff680a12013-03-04 16:00:19 +08002245 } else {
2246 arizona_fll_err(fll, "No clocks provided\n");
Charles Keepaxc393aca2014-07-09 17:41:47 +01002247 return -EINVAL;
Mark Brownff680a12013-03-04 16:00:19 +08002248 }
Charles Keepax35722812013-02-20 17:28:38 +00002249
Mark Brown576411be2013-03-05 12:07:16 +08002250 /*
2251 * Increase the bandwidth if we're not using a low frequency
2252 * sync source.
2253 */
Charles Keepax49c60542013-09-16 15:34:35 +01002254 if (use_sync && fll->sync_freq > 100000)
Mark Brown3c43c692013-12-12 00:49:22 +00002255 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
2256 ARIZONA_FLL1_SYNC_BW, 0);
Mark Brown576411be2013-03-05 12:07:16 +08002257 else
Mark Brown3c43c692013-12-12 00:49:22 +00002258 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
2259 ARIZONA_FLL1_SYNC_BW,
2260 ARIZONA_FLL1_SYNC_BW);
Mark Brown576411be2013-03-05 12:07:16 +08002261
Charles Keepaxc393aca2014-07-09 17:41:47 +01002262 if (!already_enabled)
Charles Keepax35722812013-02-20 17:28:38 +00002263 pm_runtime_get(arizona->dev);
2264
Mark Brown3c43c692013-12-12 00:49:22 +00002265 regmap_update_bits_async(arizona->regmap, fll->base + 1,
Mark Brown3c43c692013-12-12 00:49:22 +00002266 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
Charles Keepax49c60542013-09-16 15:34:35 +01002267 if (use_sync)
Mark Brown3c43c692013-12-12 00:49:22 +00002268 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
2269 ARIZONA_FLL1_SYNC_ENA,
2270 ARIZONA_FLL1_SYNC_ENA);
Charles Keepax35722812013-02-20 17:28:38 +00002271
Charles Keepaxc8badda2014-07-09 17:41:49 +01002272 if (already_enabled)
2273 regmap_update_bits_async(arizona->regmap, fll->base + 1,
2274 ARIZONA_FLL1_FREERUN, 0);
2275
Charles Keepax0e765972015-08-25 12:43:48 +01002276 arizona_fll_dbg(fll, "Waiting for FLL lock...\n");
2277 val = 0;
2278 for (i = 0; i < 15; i++) {
2279 if (i < 5)
2280 usleep_range(200, 400);
2281 else
2282 msleep(20);
2283
2284 regmap_read(arizona->regmap,
2285 ARIZONA_INTERRUPT_RAW_STATUS_5,
2286 &val);
2287 if (val & (ARIZONA_FLL1_CLOCK_OK_STS << (fll->id - 1)))
2288 break;
2289 }
2290 if (i == 15)
Charles Keepax35722812013-02-20 17:28:38 +00002291 arizona_fll_warn(fll, "Timed out waiting for lock\n");
Charles Keepax0e765972015-08-25 12:43:48 +01002292 else
2293 arizona_fll_dbg(fll, "FLL locked (%d polls)\n", i);
Charles Keepaxc393aca2014-07-09 17:41:47 +01002294
2295 return 0;
Charles Keepax35722812013-02-20 17:28:38 +00002296}
2297
Charles Keepax76040542013-02-20 17:28:37 +00002298static void arizona_disable_fll(struct arizona_fll *fll)
2299{
2300 struct arizona *arizona = fll->arizona;
2301 bool change;
2302
Mark Brown3c43c692013-12-12 00:49:22 +00002303 regmap_update_bits_async(arizona->regmap, fll->base + 1,
2304 ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
Charles Keepax76040542013-02-20 17:28:37 +00002305 regmap_update_bits_check(arizona->regmap, fll->base + 1,
2306 ARIZONA_FLL1_ENA, 0, &change);
2307 regmap_update_bits(arizona->regmap, fll->base + 0x11,
2308 ARIZONA_FLL1_SYNC_ENA, 0);
Charles Keepax5e39a502014-07-09 17:41:48 +01002309 regmap_update_bits_async(arizona->regmap, fll->base + 1,
2310 ARIZONA_FLL1_FREERUN, 0);
Charles Keepax76040542013-02-20 17:28:37 +00002311
2312 if (change)
2313 pm_runtime_put_autosuspend(arizona->dev);
2314}
2315
Charles Keepaxee929a92013-02-20 17:28:40 +00002316int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
2317 unsigned int Fref, unsigned int Fout)
2318{
Charles Keepaxc393aca2014-07-09 17:41:47 +01002319 int ret = 0;
Charles Keepaxee929a92013-02-20 17:28:40 +00002320
Charles Keepax1c5617f2013-02-22 17:10:37 +00002321 if (fll->ref_src == source && fll->ref_freq == Fref)
Charles Keepaxee929a92013-02-20 17:28:40 +00002322 return 0;
2323
Charles Keepax23f785a82014-03-07 16:34:20 +00002324 if (fll->fout && Fref > 0) {
2325 ret = arizona_validate_fll(fll, Fref, fll->fout);
2326 if (ret != 0)
2327 return ret;
Charles Keepaxee929a92013-02-20 17:28:40 +00002328 }
2329
2330 fll->ref_src = source;
2331 fll->ref_freq = Fref;
Charles Keepaxee929a92013-02-20 17:28:40 +00002332
Mark Brown86cd6842013-03-07 16:14:04 +08002333 if (fll->fout && Fref > 0) {
Charles Keepaxc393aca2014-07-09 17:41:47 +01002334 ret = arizona_enable_fll(fll);
Charles Keepaxee929a92013-02-20 17:28:40 +00002335 }
2336
Charles Keepaxc393aca2014-07-09 17:41:47 +01002337 return ret;
Charles Keepaxee929a92013-02-20 17:28:40 +00002338}
2339EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
2340
Mark Brown07ed8732012-06-18 21:08:44 +01002341int arizona_set_fll(struct arizona_fll *fll, int source,
2342 unsigned int Fref, unsigned int Fout)
2343{
Charles Keepaxc393aca2014-07-09 17:41:47 +01002344 int ret = 0;
Mark Brown07ed8732012-06-18 21:08:44 +01002345
Mark Brownff680a12013-03-04 16:00:19 +08002346 if (fll->sync_src == source &&
2347 fll->sync_freq == Fref && fll->fout == Fout)
2348 return 0;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00002349
Mark Brownff680a12013-03-04 16:00:19 +08002350 if (Fout) {
2351 if (fll->ref_src >= 0) {
Charles Keepax23f785a82014-03-07 16:34:20 +00002352 ret = arizona_validate_fll(fll, fll->ref_freq, Fout);
Charles Keepax9e359c62013-02-20 17:28:35 +00002353 if (ret != 0)
2354 return ret;
2355 }
2356
Charles Keepax23f785a82014-03-07 16:34:20 +00002357 ret = arizona_validate_fll(fll, Fref, Fout);
Mark Brownff680a12013-03-04 16:00:19 +08002358 if (ret != 0)
2359 return ret;
Charles Keepax9e359c62013-02-20 17:28:35 +00002360 }
Mark Brownff680a12013-03-04 16:00:19 +08002361
2362 fll->sync_src = source;
2363 fll->sync_freq = Fref;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00002364 fll->fout = Fout;
Charles Keepax9e359c62013-02-20 17:28:35 +00002365
Charles Keepax613124c2014-07-09 17:41:46 +01002366 if (Fout)
Charles Keepaxc393aca2014-07-09 17:41:47 +01002367 ret = arizona_enable_fll(fll);
Charles Keepax613124c2014-07-09 17:41:46 +01002368 else
Charles Keepax76040542013-02-20 17:28:37 +00002369 arizona_disable_fll(fll);
Mark Brown07ed8732012-06-18 21:08:44 +01002370
Charles Keepaxc393aca2014-07-09 17:41:47 +01002371 return ret;
Mark Brown07ed8732012-06-18 21:08:44 +01002372}
2373EXPORT_SYMBOL_GPL(arizona_set_fll);
2374
2375int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
2376 int ok_irq, struct arizona_fll *fll)
2377{
Charles Keepax19b34bd2013-02-20 17:28:34 +00002378 unsigned int val;
Mark Brown07ed8732012-06-18 21:08:44 +01002379
Mark Brown07ed8732012-06-18 21:08:44 +01002380 fll->id = id;
2381 fll->base = base;
2382 fll->arizona = arizona;
Charles Keepaxf3f11632013-02-20 17:28:41 +00002383 fll->sync_src = ARIZONA_FLL_SRC_NONE;
Mark Brown07ed8732012-06-18 21:08:44 +01002384
Charles Keepax19b34bd2013-02-20 17:28:34 +00002385 /* Configure default refclk to 32kHz if we have one */
2386 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
2387 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
2388 case ARIZONA_CLK_SRC_MCLK1:
2389 case ARIZONA_CLK_SRC_MCLK2:
2390 fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK;
2391 break;
2392 default:
Charles Keepaxf3f11632013-02-20 17:28:41 +00002393 fll->ref_src = ARIZONA_FLL_SRC_NONE;
Charles Keepax19b34bd2013-02-20 17:28:34 +00002394 }
2395 fll->ref_freq = 32768;
2396
Mark Brown07ed8732012-06-18 21:08:44 +01002397 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
2398 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
2399 "FLL%d clock OK", id);
2400
Charles Keepaxe31c1942013-01-07 16:41:45 +00002401 regmap_update_bits(arizona->regmap, fll->base + 1,
2402 ARIZONA_FLL1_FREERUN, 0);
2403
Mark Brown07ed8732012-06-18 21:08:44 +01002404 return 0;
2405}
2406EXPORT_SYMBOL_GPL(arizona_init_fll);
2407
Mark Brownbc9ab6d2013-01-04 19:31:00 +00002408/**
2409 * arizona_set_output_mode - Set the mode of the specified output
2410 *
2411 * @codec: Device to configure
2412 * @output: Output number
2413 * @diff: True to set the output to differential mode
2414 *
2415 * Some systems use external analogue switches to connect more
2416 * analogue devices to the CODEC than are supported by the device. In
2417 * some systems this requires changing the switched output from single
2418 * ended to differential mode dynamically at runtime, an operation
2419 * supported using this function.
2420 *
2421 * Most systems have a single static configuration and should use
2422 * platform data instead.
2423 */
2424int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
2425{
2426 unsigned int reg, val;
2427
2428 if (output < 1 || output > 6)
2429 return -EINVAL;
2430
2431 reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
2432
2433 if (diff)
2434 val = ARIZONA_OUT1_MONO;
2435 else
2436 val = 0;
2437
2438 return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val);
2439}
2440EXPORT_SYMBOL_GPL(arizona_set_output_mode);
2441
Richard Fitzgerald336d0442015-06-18 13:43:19 +01002442static const struct soc_enum arizona_adsp2_rate_enum[] = {
2443 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP1_CONTROL_1,
2444 ARIZONA_DSP1_RATE_SHIFT, 0xf,
2445 ARIZONA_RATE_ENUM_SIZE,
2446 arizona_rate_text, arizona_rate_val),
2447 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP2_CONTROL_1,
2448 ARIZONA_DSP1_RATE_SHIFT, 0xf,
2449 ARIZONA_RATE_ENUM_SIZE,
2450 arizona_rate_text, arizona_rate_val),
2451 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1,
2452 ARIZONA_DSP1_RATE_SHIFT, 0xf,
2453 ARIZONA_RATE_ENUM_SIZE,
2454 arizona_rate_text, arizona_rate_val),
2455 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP4_CONTROL_1,
2456 ARIZONA_DSP1_RATE_SHIFT, 0xf,
2457 ARIZONA_RATE_ENUM_SIZE,
2458 arizona_rate_text, arizona_rate_val),
2459};
2460
2461const struct snd_kcontrol_new arizona_adsp2_rate_controls[] = {
2462 SOC_ENUM("DSP1 Rate", arizona_adsp2_rate_enum[0]),
2463 SOC_ENUM("DSP2 Rate", arizona_adsp2_rate_enum[1]),
2464 SOC_ENUM("DSP3 Rate", arizona_adsp2_rate_enum[2]),
2465 SOC_ENUM("DSP4 Rate", arizona_adsp2_rate_enum[3]),
2466};
2467EXPORT_SYMBOL_GPL(arizona_adsp2_rate_controls);
2468
Charles Keepaxc05d9a82015-06-25 09:35:11 +01002469static bool arizona_eq_filter_unstable(bool mode, __be16 _a, __be16 _b)
2470{
2471 s16 a = be16_to_cpu(_a);
2472 s16 b = be16_to_cpu(_b);
2473
2474 if (!mode) {
2475 return abs(a) >= 4096;
2476 } else {
2477 if (abs(b) >= 4096)
2478 return true;
2479
2480 return (abs((a << 16) / (4096 - b)) >= 4096 << 4);
2481 }
2482}
2483
2484int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol,
2485 struct snd_ctl_elem_value *ucontrol)
2486{
2487 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
2488 struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
2489 struct soc_bytes *params = (void *)kcontrol->private_value;
2490 unsigned int val;
2491 __be16 *data;
2492 int len;
2493 int ret;
2494
2495 len = params->num_regs * regmap_get_val_bytes(arizona->regmap);
2496
2497 data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA);
2498 if (!data)
2499 return -ENOMEM;
2500
2501 data[0] &= cpu_to_be16(ARIZONA_EQ1_B1_MODE);
2502
2503 if (arizona_eq_filter_unstable(!!data[0], data[1], data[2]) ||
2504 arizona_eq_filter_unstable(true, data[4], data[5]) ||
2505 arizona_eq_filter_unstable(true, data[8], data[9]) ||
2506 arizona_eq_filter_unstable(true, data[12], data[13]) ||
2507 arizona_eq_filter_unstable(false, data[16], data[17])) {
2508 dev_err(arizona->dev, "Rejecting unstable EQ coefficients\n");
2509 ret = -EINVAL;
2510 goto out;
2511 }
2512
2513 ret = regmap_read(arizona->regmap, params->base, &val);
2514 if (ret != 0)
2515 goto out;
2516
2517 val &= ~ARIZONA_EQ1_B1_MODE;
2518 data[0] |= cpu_to_be16(val);
2519
2520 ret = regmap_raw_write(arizona->regmap, params->base, data, len);
2521
2522out:
2523 kfree(data);
2524 return ret;
2525}
2526EXPORT_SYMBOL_GPL(arizona_eq_coeff_put);
2527
Charles Keepax5f8e6712015-06-25 09:35:12 +01002528int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
2529 struct snd_ctl_elem_value *ucontrol)
2530{
2531 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
2532 struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
2533 __be16 *data = (__be16 *)ucontrol->value.bytes.data;
2534 s16 val = be16_to_cpu(*data);
2535
2536 if (abs(val) >= 4096) {
2537 dev_err(arizona->dev, "Rejecting unstable LHPF coefficients\n");
2538 return -EINVAL;
2539 }
2540
2541 return snd_soc_bytes_put(kcontrol, ucontrol);
2542}
2543EXPORT_SYMBOL_GPL(arizona_lhpf_coeff_put);
2544
Mark Brown07ed8732012-06-18 21:08:44 +01002545MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
2546MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
2547MODULE_LICENSE("GPL");