blob: 586789597ecdff8fc3fbccd38583b61b9195c332 [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;
150 }
151
152 return 0;
153}
154
Mark Brown899817e2013-03-13 12:32:10 +0000155static irqreturn_t arizona_thermal_warn(int irq, void *data)
156{
157 struct arizona *arizona = data;
158 unsigned int val;
159 int ret;
160
161 ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
162 &val);
163 if (ret != 0) {
164 dev_err(arizona->dev, "Failed to read thermal status: %d\n",
165 ret);
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100166 } else if (val & ARIZONA_SPK_OVERHEAT_WARN_STS) {
Mark Brown899817e2013-03-13 12:32:10 +0000167 dev_crit(arizona->dev, "Thermal warning\n");
168 }
169
170 return IRQ_HANDLED;
171}
172
173static irqreturn_t arizona_thermal_shutdown(int irq, void *data)
174{
175 struct arizona *arizona = data;
176 unsigned int val;
177 int ret;
178
179 ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
180 &val);
181 if (ret != 0) {
182 dev_err(arizona->dev, "Failed to read thermal status: %d\n",
183 ret);
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100184 } else if (val & ARIZONA_SPK_OVERHEAT_STS) {
Mark Brown899817e2013-03-13 12:32:10 +0000185 dev_crit(arizona->dev, "Thermal shutdown\n");
Mark Brownf4a76e72013-03-13 12:22:39 +0000186 ret = regmap_update_bits(arizona->regmap,
187 ARIZONA_OUTPUT_ENABLES_1,
188 ARIZONA_OUT4L_ENA |
189 ARIZONA_OUT4R_ENA, 0);
190 if (ret != 0)
191 dev_crit(arizona->dev,
192 "Failed to disable speaker outputs: %d\n",
193 ret);
Mark Brown899817e2013-03-13 12:32:10 +0000194 }
195
196 return IRQ_HANDLED;
197}
198
Mark Brown56447e12013-01-10 14:45:58 +0000199static const struct snd_soc_dapm_widget arizona_spkl =
Mark Brownf4a76e72013-03-13 12:22:39 +0000200 SND_SOC_DAPM_PGA_E("OUT4L", SND_SOC_NOPM,
Mark Brown56447e12013-01-10 14:45:58 +0000201 ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
202 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
203
204static const struct snd_soc_dapm_widget arizona_spkr =
Mark Brownf4a76e72013-03-13 12:22:39 +0000205 SND_SOC_DAPM_PGA_E("OUT4R", SND_SOC_NOPM,
Mark Brown56447e12013-01-10 14:45:58 +0000206 ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
207 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
208
209int arizona_init_spk(struct snd_soc_codec *codec)
210{
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200211 struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
Mark Brown899817e2013-03-13 12:32:10 +0000212 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
213 struct arizona *arizona = priv->arizona;
Mark Brown56447e12013-01-10 14:45:58 +0000214 int ret;
215
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200216 ret = snd_soc_dapm_new_controls(dapm, &arizona_spkl, 1);
Mark Brown56447e12013-01-10 14:45:58 +0000217 if (ret != 0)
218 return ret;
219
Charles Keepax40843ae2013-08-12 23:46:55 +0100220 switch (arizona->type) {
221 case WM8997:
222 break;
223 default:
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200224 ret = snd_soc_dapm_new_controls(dapm, &arizona_spkr, 1);
Charles Keepax40843ae2013-08-12 23:46:55 +0100225 if (ret != 0)
226 return ret;
227 break;
228 }
Mark Brown56447e12013-01-10 14:45:58 +0000229
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100230 ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN,
Mark Brown899817e2013-03-13 12:32:10 +0000231 "Thermal warning", arizona_thermal_warn,
232 arizona);
233 if (ret != 0)
234 dev_err(arizona->dev,
235 "Failed to get thermal warning IRQ: %d\n",
236 ret);
237
Charles Keepaxc0fe2c52014-07-15 11:21:47 +0100238 ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT,
Mark Brown899817e2013-03-13 12:32:10 +0000239 "Thermal shutdown", arizona_thermal_shutdown,
240 arizona);
241 if (ret != 0)
242 dev_err(arizona->dev,
243 "Failed to get thermal shutdown IRQ: %d\n",
244 ret);
245
Mark Brown56447e12013-01-10 14:45:58 +0000246 return 0;
247}
248EXPORT_SYMBOL_GPL(arizona_init_spk);
249
Charles Keepaxb60f3632014-06-10 18:41:02 +0100250static const struct snd_soc_dapm_route arizona_mono_routes[] = {
251 { "OUT1R", NULL, "OUT1L" },
252 { "OUT2R", NULL, "OUT2L" },
253 { "OUT3R", NULL, "OUT3L" },
254 { "OUT4R", NULL, "OUT4L" },
255 { "OUT5R", NULL, "OUT5L" },
256 { "OUT6R", NULL, "OUT6L" },
257};
258
259int arizona_init_mono(struct snd_soc_codec *codec)
260{
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200261 struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
Charles Keepaxb60f3632014-06-10 18:41:02 +0100262 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
263 struct arizona *arizona = priv->arizona;
264 int i;
265
266 for (i = 0; i < ARIZONA_MAX_OUTPUT; ++i) {
267 if (arizona->pdata.out_mono[i])
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200268 snd_soc_dapm_add_routes(dapm,
Charles Keepaxb60f3632014-06-10 18:41:02 +0100269 &arizona_mono_routes[i], 1);
270 }
271
272 return 0;
273}
274EXPORT_SYMBOL_GPL(arizona_init_mono);
275
Charles Keepaxb63144e2013-07-04 08:56:28 +0100276int arizona_init_gpio(struct snd_soc_codec *codec)
277{
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200278 struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
Charles Keepaxb63144e2013-07-04 08:56:28 +0100279 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
280 struct arizona *arizona = priv->arizona;
281 int i;
282
283 switch (arizona->type) {
284 case WM5110:
Richard Fitzgerald575ef7f2015-01-17 15:21:27 +0000285 case WM8280:
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200286 snd_soc_dapm_disable_pin(dapm, "DRC2 Signal Activity");
Charles Keepaxb79fae62013-07-04 16:53:03 +0100287 break;
288 default:
289 break;
Charles Keepaxb63144e2013-07-04 08:56:28 +0100290 }
291
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200292 snd_soc_dapm_disable_pin(dapm, "DRC1 Signal Activity");
Charles Keepaxb63144e2013-07-04 08:56:28 +0100293
294 for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
295 switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) {
296 case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT:
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200297 snd_soc_dapm_enable_pin(dapm, "DRC1 Signal Activity");
Charles Keepaxb63144e2013-07-04 08:56:28 +0100298 break;
299 case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT:
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +0200300 snd_soc_dapm_enable_pin(dapm, "DRC2 Signal Activity");
Charles Keepaxb63144e2013-07-04 08:56:28 +0100301 break;
302 default:
303 break;
304 }
305 }
306
307 return 0;
308}
309EXPORT_SYMBOL_GPL(arizona_init_gpio);
310
Mark Brown07ed8732012-06-18 21:08:44 +0100311const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
312 "None",
313 "Tone Generator 1",
314 "Tone Generator 2",
315 "Haptics",
316 "AEC",
317 "Mic Mute Mixer",
318 "Noise Generator",
319 "IN1L",
320 "IN1R",
321 "IN2L",
322 "IN2R",
323 "IN3L",
324 "IN3R",
Mark Brownc9c56fd2012-07-09 19:09:01 +0100325 "IN4L",
326 "IN4R",
Mark Brown07ed8732012-06-18 21:08:44 +0100327 "AIF1RX1",
328 "AIF1RX2",
329 "AIF1RX3",
330 "AIF1RX4",
331 "AIF1RX5",
332 "AIF1RX6",
333 "AIF1RX7",
334 "AIF1RX8",
335 "AIF2RX1",
336 "AIF2RX2",
Richard Fitzgeralde64001e2013-11-20 13:17:07 +0000337 "AIF2RX3",
338 "AIF2RX4",
339 "AIF2RX5",
340 "AIF2RX6",
Mark Brown07ed8732012-06-18 21:08:44 +0100341 "AIF3RX1",
342 "AIF3RX2",
343 "SLIMRX1",
344 "SLIMRX2",
345 "SLIMRX3",
346 "SLIMRX4",
347 "SLIMRX5",
348 "SLIMRX6",
349 "SLIMRX7",
350 "SLIMRX8",
351 "EQ1",
352 "EQ2",
353 "EQ3",
354 "EQ4",
355 "DRC1L",
356 "DRC1R",
357 "DRC2L",
358 "DRC2R",
359 "LHPF1",
360 "LHPF2",
361 "LHPF3",
362 "LHPF4",
363 "DSP1.1",
364 "DSP1.2",
365 "DSP1.3",
366 "DSP1.4",
367 "DSP1.5",
368 "DSP1.6",
Mark Brownc922cc42012-09-26 16:43:44 +0100369 "DSP2.1",
370 "DSP2.2",
371 "DSP2.3",
372 "DSP2.4",
373 "DSP2.5",
374 "DSP2.6",
375 "DSP3.1",
376 "DSP3.2",
377 "DSP3.3",
378 "DSP3.4",
379 "DSP3.5",
380 "DSP3.6",
381 "DSP4.1",
382 "DSP4.2",
383 "DSP4.3",
384 "DSP4.4",
385 "DSP4.5",
386 "DSP4.6",
Mark Brown07ed8732012-06-18 21:08:44 +0100387 "ASRC1L",
388 "ASRC1R",
389 "ASRC2L",
390 "ASRC2R",
Mark Brown91660bd2012-12-05 20:35:24 +0900391 "ISRC1INT1",
392 "ISRC1INT2",
393 "ISRC1INT3",
394 "ISRC1INT4",
395 "ISRC1DEC1",
396 "ISRC1DEC2",
397 "ISRC1DEC3",
398 "ISRC1DEC4",
399 "ISRC2INT1",
400 "ISRC2INT2",
401 "ISRC2INT3",
402 "ISRC2INT4",
403 "ISRC2DEC1",
404 "ISRC2DEC2",
405 "ISRC2DEC3",
406 "ISRC2DEC4",
407 "ISRC3INT1",
408 "ISRC3INT2",
409 "ISRC3INT3",
410 "ISRC3INT4",
411 "ISRC3DEC1",
412 "ISRC3DEC2",
413 "ISRC3DEC3",
414 "ISRC3DEC4",
Mark Brown07ed8732012-06-18 21:08:44 +0100415};
416EXPORT_SYMBOL_GPL(arizona_mixer_texts);
417
418int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
419 0x00, /* None */
420 0x04, /* Tone */
421 0x05,
422 0x06, /* Haptics */
423 0x08, /* AEC */
424 0x0c, /* Noise mixer */
425 0x0d, /* Comfort noise */
426 0x10, /* IN1L */
427 0x11,
428 0x12,
429 0x13,
430 0x14,
431 0x15,
Mark Brownc9c56fd2012-07-09 19:09:01 +0100432 0x16,
433 0x17,
Mark Brown07ed8732012-06-18 21:08:44 +0100434 0x20, /* AIF1RX1 */
435 0x21,
436 0x22,
437 0x23,
438 0x24,
439 0x25,
440 0x26,
441 0x27,
442 0x28, /* AIF2RX1 */
443 0x29,
Richard Fitzgeralde64001e2013-11-20 13:17:07 +0000444 0x2a,
445 0x2b,
446 0x2c,
447 0x2d,
Mark Brown07ed8732012-06-18 21:08:44 +0100448 0x30, /* AIF3RX1 */
449 0x31,
450 0x38, /* SLIMRX1 */
451 0x39,
452 0x3a,
453 0x3b,
454 0x3c,
455 0x3d,
456 0x3e,
457 0x3f,
458 0x50, /* EQ1 */
459 0x51,
460 0x52,
461 0x53,
462 0x58, /* DRC1L */
463 0x59,
464 0x5a,
465 0x5b,
466 0x60, /* LHPF1 */
467 0x61,
468 0x62,
469 0x63,
470 0x68, /* DSP1.1 */
471 0x69,
472 0x6a,
473 0x6b,
474 0x6c,
475 0x6d,
Mark Brownc922cc42012-09-26 16:43:44 +0100476 0x70, /* DSP2.1 */
477 0x71,
478 0x72,
479 0x73,
480 0x74,
481 0x75,
482 0x78, /* DSP3.1 */
483 0x79,
484 0x7a,
485 0x7b,
486 0x7c,
487 0x7d,
488 0x80, /* DSP4.1 */
489 0x81,
490 0x82,
491 0x83,
492 0x84,
493 0x85,
Mark Brown07ed8732012-06-18 21:08:44 +0100494 0x90, /* ASRC1L */
495 0x91,
496 0x92,
497 0x93,
Mark Brown91660bd2012-12-05 20:35:24 +0900498 0xa0, /* ISRC1INT1 */
499 0xa1,
500 0xa2,
501 0xa3,
502 0xa4, /* ISRC1DEC1 */
503 0xa5,
504 0xa6,
505 0xa7,
506 0xa8, /* ISRC2DEC1 */
507 0xa9,
508 0xaa,
509 0xab,
510 0xac, /* ISRC2INT1 */
511 0xad,
512 0xae,
513 0xaf,
514 0xb0, /* ISRC3DEC1 */
515 0xb1,
516 0xb2,
517 0xb3,
518 0xb4, /* ISRC3INT1 */
519 0xb5,
520 0xb6,
521 0xb7,
Mark Brown07ed8732012-06-18 21:08:44 +0100522};
523EXPORT_SYMBOL_GPL(arizona_mixer_values);
524
525const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
526EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
527
Mark Browndc914282013-02-18 19:09:23 +0000528const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = {
529 "SYNCCLK rate", "8kHz", "16kHz", "ASYNCCLK rate",
530};
531EXPORT_SYMBOL_GPL(arizona_rate_text);
532
533const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
534 0, 1, 2, 8,
535};
536EXPORT_SYMBOL_GPL(arizona_rate_val);
537
538
Charles Keepaxfbedc8c2013-12-19 09:30:12 +0000539const struct soc_enum arizona_isrc_fsh[] = {
540 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_1,
541 ARIZONA_ISRC1_FSH_SHIFT, 0xf,
542 ARIZONA_RATE_ENUM_SIZE,
543 arizona_rate_text, arizona_rate_val),
544 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_1,
545 ARIZONA_ISRC2_FSH_SHIFT, 0xf,
546 ARIZONA_RATE_ENUM_SIZE,
547 arizona_rate_text, arizona_rate_val),
548 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_1,
549 ARIZONA_ISRC3_FSH_SHIFT, 0xf,
550 ARIZONA_RATE_ENUM_SIZE,
551 arizona_rate_text, arizona_rate_val),
552};
553EXPORT_SYMBOL_GPL(arizona_isrc_fsh);
554
Mark Browndc914282013-02-18 19:09:23 +0000555const struct soc_enum arizona_isrc_fsl[] = {
556 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2,
557 ARIZONA_ISRC1_FSL_SHIFT, 0xf,
558 ARIZONA_RATE_ENUM_SIZE,
559 arizona_rate_text, arizona_rate_val),
560 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_2,
561 ARIZONA_ISRC2_FSL_SHIFT, 0xf,
562 ARIZONA_RATE_ENUM_SIZE,
563 arizona_rate_text, arizona_rate_val),
564 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_2,
565 ARIZONA_ISRC3_FSL_SHIFT, 0xf,
566 ARIZONA_RATE_ENUM_SIZE,
567 arizona_rate_text, arizona_rate_val),
568};
569EXPORT_SYMBOL_GPL(arizona_isrc_fsl);
570
Charles Keepax56d37d82013-12-19 09:30:13 +0000571const struct soc_enum arizona_asrc_rate1 =
572 SOC_VALUE_ENUM_SINGLE(ARIZONA_ASRC_RATE1,
573 ARIZONA_ASRC_RATE1_SHIFT, 0xf,
574 ARIZONA_RATE_ENUM_SIZE - 1,
575 arizona_rate_text, arizona_rate_val);
576EXPORT_SYMBOL_GPL(arizona_asrc_rate1);
577
Mark Browne853a002012-12-09 12:25:52 +0900578static const char *arizona_vol_ramp_text[] = {
579 "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
580 "15ms/6dB", "30ms/6dB",
581};
582
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100583SOC_ENUM_SINGLE_DECL(arizona_in_vd_ramp,
584 ARIZONA_INPUT_VOLUME_RAMP,
585 ARIZONA_IN_VD_RAMP_SHIFT,
586 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900587EXPORT_SYMBOL_GPL(arizona_in_vd_ramp);
588
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100589SOC_ENUM_SINGLE_DECL(arizona_in_vi_ramp,
590 ARIZONA_INPUT_VOLUME_RAMP,
591 ARIZONA_IN_VI_RAMP_SHIFT,
592 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900593EXPORT_SYMBOL_GPL(arizona_in_vi_ramp);
594
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100595SOC_ENUM_SINGLE_DECL(arizona_out_vd_ramp,
596 ARIZONA_OUTPUT_VOLUME_RAMP,
597 ARIZONA_OUT_VD_RAMP_SHIFT,
598 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900599EXPORT_SYMBOL_GPL(arizona_out_vd_ramp);
600
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100601SOC_ENUM_SINGLE_DECL(arizona_out_vi_ramp,
602 ARIZONA_OUTPUT_VOLUME_RAMP,
603 ARIZONA_OUT_VI_RAMP_SHIFT,
604 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900605EXPORT_SYMBOL_GPL(arizona_out_vi_ramp);
606
Mark Brown07ed8732012-06-18 21:08:44 +0100607static const char *arizona_lhpf_mode_text[] = {
608 "Low-pass", "High-pass"
609};
610
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100611SOC_ENUM_SINGLE_DECL(arizona_lhpf1_mode,
612 ARIZONA_HPLPF1_1,
613 ARIZONA_LHPF1_MODE_SHIFT,
614 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100615EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
616
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100617SOC_ENUM_SINGLE_DECL(arizona_lhpf2_mode,
618 ARIZONA_HPLPF2_1,
619 ARIZONA_LHPF2_MODE_SHIFT,
620 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100621EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
622
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100623SOC_ENUM_SINGLE_DECL(arizona_lhpf3_mode,
624 ARIZONA_HPLPF3_1,
625 ARIZONA_LHPF3_MODE_SHIFT,
626 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100627EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
628
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100629SOC_ENUM_SINGLE_DECL(arizona_lhpf4_mode,
630 ARIZONA_HPLPF4_1,
631 ARIZONA_LHPF4_MODE_SHIFT,
632 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100633EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
634
Mark Brown845571c2012-12-18 13:47:57 +0000635static const char *arizona_ng_hold_text[] = {
636 "30ms", "120ms", "250ms", "500ms",
637};
638
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100639SOC_ENUM_SINGLE_DECL(arizona_ng_hold,
640 ARIZONA_NOISE_GATE_CONTROL,
641 ARIZONA_NGATE_HOLD_SHIFT,
642 arizona_ng_hold_text);
Mark Brown845571c2012-12-18 13:47:57 +0000643EXPORT_SYMBOL_GPL(arizona_ng_hold);
644
Charles Keepax254dc322013-11-19 16:04:03 +0000645static const char * const arizona_in_hpf_cut_text[] = {
646 "2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz"
647};
648
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100649SOC_ENUM_SINGLE_DECL(arizona_in_hpf_cut_enum,
650 ARIZONA_HPF_CONTROL,
651 ARIZONA_IN_HPF_CUT_SHIFT,
652 arizona_in_hpf_cut_text);
Charles Keepax254dc322013-11-19 16:04:03 +0000653EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum);
654
Charles Keepaxc7f38432013-08-06 17:03:55 +0100655static const char * const arizona_in_dmic_osr_text[] = {
Charles Keepaxef326f42014-11-12 14:55:26 +0000656 "1.536MHz", "3.072MHz", "6.144MHz", "768kHz",
Charles Keepaxc7f38432013-08-06 17:03:55 +0100657};
658
659const struct soc_enum arizona_in_dmic_osr[] = {
660 SOC_ENUM_SINGLE(ARIZONA_IN1L_CONTROL, ARIZONA_IN1_OSR_SHIFT,
661 ARRAY_SIZE(arizona_in_dmic_osr_text),
662 arizona_in_dmic_osr_text),
663 SOC_ENUM_SINGLE(ARIZONA_IN2L_CONTROL, ARIZONA_IN2_OSR_SHIFT,
664 ARRAY_SIZE(arizona_in_dmic_osr_text),
665 arizona_in_dmic_osr_text),
666 SOC_ENUM_SINGLE(ARIZONA_IN3L_CONTROL, ARIZONA_IN3_OSR_SHIFT,
667 ARRAY_SIZE(arizona_in_dmic_osr_text),
668 arizona_in_dmic_osr_text),
669 SOC_ENUM_SINGLE(ARIZONA_IN4L_CONTROL, ARIZONA_IN4_OSR_SHIFT,
670 ARRAY_SIZE(arizona_in_dmic_osr_text),
671 arizona_in_dmic_osr_text),
672};
673EXPORT_SYMBOL_GPL(arizona_in_dmic_osr);
674
Mark Brownddbce972013-02-15 17:27:22 +0000675static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
676{
677 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
678 unsigned int val;
679 int i;
680
681 if (ena)
682 val = ARIZONA_IN_VU;
683 else
684 val = 0;
685
686 for (i = 0; i < priv->num_inputs; i++)
687 snd_soc_update_bits(codec,
688 ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 4),
689 ARIZONA_IN_VU, val);
690}
691
Mark Brown07ed8732012-06-18 21:08:44 +0100692int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
693 int event)
694{
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100695 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
696 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000697 unsigned int reg;
698
699 if (w->shift % 2)
700 reg = ARIZONA_ADC_DIGITAL_VOLUME_1L + ((w->shift / 2) * 8);
701 else
702 reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8);
703
704 switch (event) {
Mark Brownddbce972013-02-15 17:27:22 +0000705 case SND_SOC_DAPM_PRE_PMU:
706 priv->in_pending++;
707 break;
Mark Brown43cd8bf2013-02-06 16:57:29 +0000708 case SND_SOC_DAPM_POST_PMU:
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100709 snd_soc_update_bits(codec, reg, ARIZONA_IN1L_MUTE, 0);
Mark Brownddbce972013-02-15 17:27:22 +0000710
711 /* If this is the last input pending then allow VU */
712 priv->in_pending--;
713 if (priv->in_pending == 0) {
714 msleep(1);
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100715 arizona_in_set_vu(codec, 1);
Mark Brownddbce972013-02-15 17:27:22 +0000716 }
Mark Brown43cd8bf2013-02-06 16:57:29 +0000717 break;
718 case SND_SOC_DAPM_PRE_PMD:
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100719 snd_soc_update_bits(codec, reg,
Mark Brownddbce972013-02-15 17:27:22 +0000720 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU,
721 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000722 break;
Mark Brownddbce972013-02-15 17:27:22 +0000723 case SND_SOC_DAPM_POST_PMD:
724 /* Disable volume updates if no inputs are enabled */
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100725 reg = snd_soc_read(codec, ARIZONA_INPUT_ENABLES);
Mark Brownddbce972013-02-15 17:27:22 +0000726 if (reg == 0)
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100727 arizona_in_set_vu(codec, 0);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000728 }
729
Mark Brown07ed8732012-06-18 21:08:44 +0100730 return 0;
731}
732EXPORT_SYMBOL_GPL(arizona_in_ev);
733
734int arizona_out_ev(struct snd_soc_dapm_widget *w,
735 struct snd_kcontrol *kcontrol,
736 int event)
737{
Mark Brown60d66c92015-01-27 23:50:47 +0000738 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
739 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Charles Keepax054e1b42015-01-20 16:31:50 +0000740
Mark Brown1a2c7d52013-03-24 22:50:23 +0000741 switch (event) {
Charles Keepaxe1ae5fb2015-01-20 16:31:51 +0000742 case SND_SOC_DAPM_PRE_PMU:
743 switch (w->shift) {
744 case ARIZONA_OUT1L_ENA_SHIFT:
745 case ARIZONA_OUT1R_ENA_SHIFT:
746 case ARIZONA_OUT2L_ENA_SHIFT:
747 case ARIZONA_OUT2R_ENA_SHIFT:
748 case ARIZONA_OUT3L_ENA_SHIFT:
749 case ARIZONA_OUT3R_ENA_SHIFT:
750 priv->out_up_pending++;
751 priv->out_up_delay += 17;
752 break;
753 default:
754 break;
755 }
756 break;
Mark Brown1a2c7d52013-03-24 22:50:23 +0000757 case SND_SOC_DAPM_POST_PMU:
758 switch (w->shift) {
759 case ARIZONA_OUT1L_ENA_SHIFT:
760 case ARIZONA_OUT1R_ENA_SHIFT:
761 case ARIZONA_OUT2L_ENA_SHIFT:
762 case ARIZONA_OUT2R_ENA_SHIFT:
763 case ARIZONA_OUT3L_ENA_SHIFT:
764 case ARIZONA_OUT3R_ENA_SHIFT:
Charles Keepaxe1ae5fb2015-01-20 16:31:51 +0000765 priv->out_up_pending--;
766 if (!priv->out_up_pending) {
767 msleep(priv->out_up_delay);
768 priv->out_up_delay = 0;
769 }
Mark Brown1a2c7d52013-03-24 22:50:23 +0000770 break;
771
772 default:
773 break;
774 }
775 break;
Charles Keepax054e1b42015-01-20 16:31:50 +0000776 case SND_SOC_DAPM_PRE_PMD:
777 switch (w->shift) {
778 case ARIZONA_OUT1L_ENA_SHIFT:
779 case ARIZONA_OUT1R_ENA_SHIFT:
780 case ARIZONA_OUT2L_ENA_SHIFT:
781 case ARIZONA_OUT2R_ENA_SHIFT:
782 case ARIZONA_OUT3L_ENA_SHIFT:
783 case ARIZONA_OUT3R_ENA_SHIFT:
784 priv->out_down_pending++;
785 priv->out_down_delay++;
786 break;
787 default:
788 break;
789 }
790 break;
791 case SND_SOC_DAPM_POST_PMD:
792 switch (w->shift) {
793 case ARIZONA_OUT1L_ENA_SHIFT:
794 case ARIZONA_OUT1R_ENA_SHIFT:
795 case ARIZONA_OUT2L_ENA_SHIFT:
796 case ARIZONA_OUT2R_ENA_SHIFT:
797 case ARIZONA_OUT3L_ENA_SHIFT:
798 case ARIZONA_OUT3R_ENA_SHIFT:
799 priv->out_down_pending--;
800 if (!priv->out_down_pending) {
801 msleep(priv->out_down_delay);
802 priv->out_down_delay = 0;
803 }
804 break;
805 default:
806 break;
807 }
808 break;
Mark Brown1a2c7d52013-03-24 22:50:23 +0000809 }
810
Mark Brown07ed8732012-06-18 21:08:44 +0100811 return 0;
812}
813EXPORT_SYMBOL_GPL(arizona_out_ev);
814
Mark Brownf607e312013-02-22 18:36:53 +0000815int arizona_hp_ev(struct snd_soc_dapm_widget *w,
816 struct snd_kcontrol *kcontrol,
817 int event)
818{
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100819 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
820 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brown3c43c692013-12-12 00:49:22 +0000821 struct arizona *arizona = priv->arizona;
Mark Brownf607e312013-02-22 18:36:53 +0000822 unsigned int mask = 1 << w->shift;
823 unsigned int val;
824
825 switch (event) {
826 case SND_SOC_DAPM_POST_PMU:
827 val = mask;
828 break;
829 case SND_SOC_DAPM_PRE_PMD:
830 val = 0;
831 break;
Charles Keepaxe1ae5fb2015-01-20 16:31:51 +0000832 case SND_SOC_DAPM_PRE_PMU:
Charles Keepax054e1b42015-01-20 16:31:50 +0000833 case SND_SOC_DAPM_POST_PMD:
834 return arizona_out_ev(w, kcontrol, event);
Mark Brownf607e312013-02-22 18:36:53 +0000835 default:
836 return -EINVAL;
837 }
838
839 /* Store the desired state for the HP outputs */
840 priv->arizona->hp_ena &= ~mask;
841 priv->arizona->hp_ena |= val;
842
Charles Keepax112bdfa2015-02-16 15:41:02 +0000843 /* Force off if HPDET clamp is active */
844 if (priv->arizona->hpdet_clamp)
Mark Brownf607e312013-02-22 18:36:53 +0000845 val = 0;
846
Mark Brown3c43c692013-12-12 00:49:22 +0000847 regmap_update_bits_async(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1,
848 mask, val);
Mark Brownf607e312013-02-22 18:36:53 +0000849
850 return arizona_out_ev(w, kcontrol, event);
851}
852EXPORT_SYMBOL_GPL(arizona_hp_ev);
853
Richard Fitzgerald346d9682015-06-02 11:53:33 +0100854static int arizona_dvfs_enable(struct snd_soc_codec *codec)
855{
856 const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
857 struct arizona *arizona = priv->arizona;
858 int ret;
859
860 ret = regulator_set_voltage(arizona->dcvdd, 1800000, 1800000);
861 if (ret) {
862 dev_err(codec->dev, "Failed to boost DCVDD: %d\n", ret);
863 return ret;
864 }
865
866 ret = regmap_update_bits(arizona->regmap,
867 ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
868 ARIZONA_SUBSYS_MAX_FREQ,
869 ARIZONA_SUBSYS_MAX_FREQ);
870 if (ret) {
871 dev_err(codec->dev, "Failed to enable subsys max: %d\n", ret);
872 regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
873 return ret;
874 }
875
876 return 0;
877}
878
879static int arizona_dvfs_disable(struct snd_soc_codec *codec)
880{
881 const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
882 struct arizona *arizona = priv->arizona;
883 int ret;
884
885 ret = regmap_update_bits(arizona->regmap,
886 ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
887 ARIZONA_SUBSYS_MAX_FREQ, 0);
888 if (ret) {
889 dev_err(codec->dev, "Failed to disable subsys max: %d\n", ret);
890 return ret;
891 }
892
893 ret = regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
894 if (ret) {
895 dev_err(codec->dev, "Failed to unboost DCVDD: %d\n", ret);
896 return ret;
897 }
898
899 return 0;
900}
901
902int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags)
903{
904 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
905 int ret = 0;
906
907 mutex_lock(&priv->dvfs_lock);
908
909 if (!priv->dvfs_cached && !priv->dvfs_reqs) {
910 ret = arizona_dvfs_enable(codec);
911 if (ret)
912 goto err;
913 }
914
915 priv->dvfs_reqs |= flags;
916err:
917 mutex_unlock(&priv->dvfs_lock);
918 return ret;
919}
920EXPORT_SYMBOL_GPL(arizona_dvfs_up);
921
922int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags)
923{
924 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
925 unsigned int old_reqs;
926 int ret = 0;
927
928 mutex_lock(&priv->dvfs_lock);
929
930 old_reqs = priv->dvfs_reqs;
931 priv->dvfs_reqs &= ~flags;
932
933 if (!priv->dvfs_cached && old_reqs && !priv->dvfs_reqs)
934 ret = arizona_dvfs_disable(codec);
935
936 mutex_unlock(&priv->dvfs_lock);
937 return ret;
938}
939EXPORT_SYMBOL_GPL(arizona_dvfs_down);
940
941int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
942 struct snd_kcontrol *kcontrol, int event)
943{
944 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
945 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
946 int ret = 0;
947
948 mutex_lock(&priv->dvfs_lock);
949
950 switch (event) {
951 case SND_SOC_DAPM_POST_PMU:
952 if (priv->dvfs_reqs)
953 ret = arizona_dvfs_enable(codec);
954
955 priv->dvfs_cached = false;
956 break;
957 case SND_SOC_DAPM_PRE_PMD:
958 /* We must ensure DVFS is disabled before the codec goes into
959 * suspend so that we are never in an illegal state of DVFS
960 * enabled without enough DCVDD
961 */
962 priv->dvfs_cached = true;
963
964 if (priv->dvfs_reqs)
965 ret = arizona_dvfs_disable(codec);
966 break;
967 default:
968 break;
969 }
970
971 mutex_unlock(&priv->dvfs_lock);
972 return ret;
973}
974EXPORT_SYMBOL_GPL(arizona_dvfs_sysclk_ev);
975
976void arizona_init_dvfs(struct arizona_priv *priv)
977{
978 mutex_init(&priv->dvfs_lock);
979}
980EXPORT_SYMBOL_GPL(arizona_init_dvfs);
981
Richard Fitzgerald341604a2015-11-03 14:24:12 +0000982static unsigned int arizona_opclk_ref_48k_rates[] = {
Mark Browncbd840d2012-08-08 17:52:44 +0100983 6144000,
984 12288000,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000985 24576000,
Mark Browncbd840d2012-08-08 17:52:44 +0100986 49152000,
987};
988
Richard Fitzgerald341604a2015-11-03 14:24:12 +0000989static unsigned int arizona_opclk_ref_44k1_rates[] = {
Mark Browncbd840d2012-08-08 17:52:44 +0100990 5644800,
991 11289600,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000992 22579200,
Mark Browncbd840d2012-08-08 17:52:44 +0100993 45158400,
994};
995
996static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
997 unsigned int freq)
998{
999 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1000 unsigned int reg;
1001 unsigned int *rates;
1002 int ref, div, refclk;
1003
1004 switch (clk) {
1005 case ARIZONA_CLK_OPCLK:
1006 reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
1007 refclk = priv->sysclk;
1008 break;
1009 case ARIZONA_CLK_ASYNC_OPCLK:
1010 reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
1011 refclk = priv->asyncclk;
1012 break;
1013 default:
1014 return -EINVAL;
1015 }
1016
1017 if (refclk % 8000)
Richard Fitzgerald341604a2015-11-03 14:24:12 +00001018 rates = arizona_opclk_ref_44k1_rates;
Mark Browncbd840d2012-08-08 17:52:44 +01001019 else
Richard Fitzgerald341604a2015-11-03 14:24:12 +00001020 rates = arizona_opclk_ref_48k_rates;
Mark Browncbd840d2012-08-08 17:52:44 +01001021
Richard Fitzgerald341604a2015-11-03 14:24:12 +00001022 for (ref = 0; ref < ARRAY_SIZE(arizona_opclk_ref_48k_rates) &&
Mark Browncbd840d2012-08-08 17:52:44 +01001023 rates[ref] <= refclk; ref++) {
1024 div = 1;
1025 while (rates[ref] / div >= freq && div < 32) {
1026 if (rates[ref] / div == freq) {
1027 dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
1028 freq);
1029 snd_soc_update_bits(codec, reg,
1030 ARIZONA_OPCLK_DIV_MASK |
1031 ARIZONA_OPCLK_SEL_MASK,
1032 (div <<
1033 ARIZONA_OPCLK_DIV_SHIFT) |
1034 ref);
1035 return 0;
1036 }
1037 div++;
1038 }
1039 }
1040
1041 dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
1042 return -EINVAL;
1043}
1044
Mark Brown07ed8732012-06-18 21:08:44 +01001045int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
1046 int source, unsigned int freq, int dir)
1047{
1048 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1049 struct arizona *arizona = priv->arizona;
1050 char *name;
1051 unsigned int reg;
1052 unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
1053 unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
1054 unsigned int *clk;
1055
1056 switch (clk_id) {
1057 case ARIZONA_CLK_SYSCLK:
1058 name = "SYSCLK";
1059 reg = ARIZONA_SYSTEM_CLOCK_1;
1060 clk = &priv->sysclk;
1061 mask |= ARIZONA_SYSCLK_FRAC;
1062 break;
1063 case ARIZONA_CLK_ASYNCCLK:
1064 name = "ASYNCCLK";
1065 reg = ARIZONA_ASYNC_CLOCK_1;
1066 clk = &priv->asyncclk;
1067 break;
Mark Browncbd840d2012-08-08 17:52:44 +01001068 case ARIZONA_CLK_OPCLK:
1069 case ARIZONA_CLK_ASYNC_OPCLK:
1070 return arizona_set_opclk(codec, clk_id, freq);
Mark Brown07ed8732012-06-18 21:08:44 +01001071 default:
1072 return -EINVAL;
1073 }
1074
1075 switch (freq) {
1076 case 5644800:
1077 case 6144000:
1078 break;
1079 case 11289600:
1080 case 12288000:
Mark Brown3f341f72013-03-08 15:22:29 +08001081 val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +01001082 break;
1083 case 22579200:
1084 case 24576000:
Mark Brown3f341f72013-03-08 15:22:29 +08001085 val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +01001086 break;
1087 case 45158400:
1088 case 49152000:
Mark Brown3f341f72013-03-08 15:22:29 +08001089 val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +01001090 break;
Mark Brown38113362012-11-26 16:01:37 +00001091 case 67737600:
1092 case 73728000:
Mark Brown3f341f72013-03-08 15:22:29 +08001093 val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +00001094 break;
1095 case 90316800:
1096 case 98304000:
Mark Brown3f341f72013-03-08 15:22:29 +08001097 val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +00001098 break;
1099 case 135475200:
1100 case 147456000:
Mark Brown3f341f72013-03-08 15:22:29 +08001101 val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +00001102 break;
Mark Brownf2c26d42013-01-21 16:09:36 +09001103 case 0:
1104 dev_dbg(arizona->dev, "%s cleared\n", name);
1105 *clk = freq;
1106 return 0;
Mark Brown07ed8732012-06-18 21:08:44 +01001107 default:
1108 return -EINVAL;
1109 }
1110
1111 *clk = freq;
1112
1113 if (freq % 6144000)
1114 val |= ARIZONA_SYSCLK_FRAC;
1115
1116 dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
1117
1118 return regmap_update_bits(arizona->regmap, reg, mask, val);
1119}
1120EXPORT_SYMBOL_GPL(arizona_set_sysclk);
1121
1122static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
1123{
1124 struct snd_soc_codec *codec = dai->codec;
Mark Brown3c43c692013-12-12 00:49:22 +00001125 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1126 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +01001127 int lrclk, bclk, mode, base;
1128
1129 base = dai->driver->base;
1130
1131 lrclk = 0;
1132 bclk = 0;
1133
1134 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
1135 case SND_SOC_DAIFMT_DSP_A:
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001136 mode = ARIZONA_FMT_DSP_MODE_A;
1137 break;
1138 case SND_SOC_DAIFMT_DSP_B:
1139 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
1140 != SND_SOC_DAIFMT_CBM_CFM) {
1141 arizona_aif_err(dai, "DSP_B not valid in slave mode\n");
1142 return -EINVAL;
1143 }
1144 mode = ARIZONA_FMT_DSP_MODE_B;
Mark Brown07ed8732012-06-18 21:08:44 +01001145 break;
Mark Brown07ed8732012-06-18 21:08:44 +01001146 case SND_SOC_DAIFMT_I2S:
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001147 mode = ARIZONA_FMT_I2S_MODE;
1148 break;
1149 case SND_SOC_DAIFMT_LEFT_J:
1150 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
1151 != SND_SOC_DAIFMT_CBM_CFM) {
1152 arizona_aif_err(dai, "LEFT_J not valid in slave mode\n");
1153 return -EINVAL;
1154 }
1155 mode = ARIZONA_FMT_LEFT_JUSTIFIED_MODE;
Mark Brown07ed8732012-06-18 21:08:44 +01001156 break;
Mark Brown07ed8732012-06-18 21:08:44 +01001157 default:
1158 arizona_aif_err(dai, "Unsupported DAI format %d\n",
1159 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
1160 return -EINVAL;
1161 }
1162
1163 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
1164 case SND_SOC_DAIFMT_CBS_CFS:
1165 break;
1166 case SND_SOC_DAIFMT_CBS_CFM:
1167 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
1168 break;
1169 case SND_SOC_DAIFMT_CBM_CFS:
1170 bclk |= ARIZONA_AIF1_BCLK_MSTR;
1171 break;
1172 case SND_SOC_DAIFMT_CBM_CFM:
1173 bclk |= ARIZONA_AIF1_BCLK_MSTR;
1174 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
1175 break;
1176 default:
1177 arizona_aif_err(dai, "Unsupported master mode %d\n",
1178 fmt & SND_SOC_DAIFMT_MASTER_MASK);
1179 return -EINVAL;
1180 }
1181
1182 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1183 case SND_SOC_DAIFMT_NB_NF:
1184 break;
1185 case SND_SOC_DAIFMT_IB_IF:
1186 bclk |= ARIZONA_AIF1_BCLK_INV;
1187 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
1188 break;
1189 case SND_SOC_DAIFMT_IB_NF:
1190 bclk |= ARIZONA_AIF1_BCLK_INV;
1191 break;
1192 case SND_SOC_DAIFMT_NB_IF:
1193 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
1194 break;
1195 default:
1196 return -EINVAL;
1197 }
1198
Mark Brown3c43c692013-12-12 00:49:22 +00001199 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_BCLK_CTRL,
1200 ARIZONA_AIF1_BCLK_INV |
1201 ARIZONA_AIF1_BCLK_MSTR,
1202 bclk);
1203 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_TX_PIN_CTRL,
1204 ARIZONA_AIF1TX_LRCLK_INV |
1205 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
1206 regmap_update_bits_async(arizona->regmap,
1207 base + ARIZONA_AIF_RX_PIN_CTRL,
1208 ARIZONA_AIF1RX_LRCLK_INV |
1209 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
1210 regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FORMAT,
1211 ARIZONA_AIF1_FMT_MASK, mode);
Mark Brown07ed8732012-06-18 21:08:44 +01001212
1213 return 0;
1214}
1215
Mark Brown949e6bc2012-07-04 18:58:04 +01001216static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001217 -1,
1218 48000,
1219 64000,
1220 96000,
1221 128000,
1222 192000,
1223 256000,
1224 384000,
1225 512000,
1226 768000,
1227 1024000,
1228 1536000,
1229 2048000,
1230 3072000,
1231 4096000,
1232 6144000,
1233 8192000,
1234 12288000,
1235 24576000,
1236};
1237
Mark Brown5b2eec32012-07-04 17:32:05 +01001238static const unsigned int arizona_48k_rates[] = {
1239 12000,
1240 24000,
1241 48000,
1242 96000,
1243 192000,
1244 384000,
1245 768000,
1246 4000,
1247 8000,
1248 16000,
1249 32000,
1250 64000,
1251 128000,
1252 256000,
1253 512000,
1254};
1255
1256static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = {
1257 .count = ARRAY_SIZE(arizona_48k_rates),
1258 .list = arizona_48k_rates,
1259};
1260
Mark Brown949e6bc2012-07-04 18:58:04 +01001261static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001262 -1,
1263 44100,
1264 58800,
1265 88200,
1266 117600,
1267 177640,
1268 235200,
1269 352800,
1270 470400,
1271 705600,
1272 940800,
1273 1411200,
1274 1881600,
Heather Lomond4758be32012-09-05 05:02:10 -04001275 2822400,
Mark Brown07ed8732012-06-18 21:08:44 +01001276 3763200,
1277 5644800,
1278 7526400,
1279 11289600,
1280 22579200,
1281};
1282
Mark Brown5b2eec32012-07-04 17:32:05 +01001283static const unsigned int arizona_44k1_rates[] = {
1284 11025,
1285 22050,
1286 44100,
1287 88200,
1288 176400,
1289 352800,
1290 705600,
1291};
1292
1293static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = {
1294 .count = ARRAY_SIZE(arizona_44k1_rates),
1295 .list = arizona_44k1_rates,
1296};
1297
Mark Brown07ed8732012-06-18 21:08:44 +01001298static int arizona_sr_vals[] = {
1299 0,
1300 12000,
1301 24000,
1302 48000,
1303 96000,
1304 192000,
1305 384000,
1306 768000,
1307 0,
1308 11025,
1309 22050,
1310 44100,
1311 88200,
1312 176400,
1313 352800,
1314 705600,
1315 4000,
1316 8000,
1317 16000,
1318 32000,
1319 64000,
1320 128000,
1321 256000,
1322 512000,
1323};
1324
Mark Brown5b2eec32012-07-04 17:32:05 +01001325static int arizona_startup(struct snd_pcm_substream *substream,
1326 struct snd_soc_dai *dai)
1327{
1328 struct snd_soc_codec *codec = dai->codec;
1329 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1330 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
1331 const struct snd_pcm_hw_constraint_list *constraint;
1332 unsigned int base_rate;
1333
1334 switch (dai_priv->clk) {
1335 case ARIZONA_CLK_SYSCLK:
1336 base_rate = priv->sysclk;
1337 break;
1338 case ARIZONA_CLK_ASYNCCLK:
1339 base_rate = priv->asyncclk;
1340 break;
1341 default:
1342 return 0;
1343 }
1344
Mark Brownf2c26d42013-01-21 16:09:36 +09001345 if (base_rate == 0)
1346 return 0;
1347
Mark Brown5b2eec32012-07-04 17:32:05 +01001348 if (base_rate % 8000)
1349 constraint = &arizona_44k1_constraint;
1350 else
1351 constraint = &arizona_48k_constraint;
1352
1353 return snd_pcm_hw_constraint_list(substream->runtime, 0,
1354 SNDRV_PCM_HW_PARAM_RATE,
1355 constraint);
1356}
1357
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001358static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec,
1359 unsigned int rate)
1360{
1361 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1362 struct arizona *arizona = priv->arizona;
Nariman Poushin8019ff62015-07-16 16:36:21 +01001363 struct reg_sequence dac_comp[] = {
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001364 { 0x80, 0x3 },
1365 { ARIZONA_DAC_COMP_1, 0 },
1366 { ARIZONA_DAC_COMP_2, 0 },
1367 { 0x80, 0x0 },
1368 };
1369
Lars-Peter Clausend74bcaa2014-11-09 17:00:59 +01001370 mutex_lock(&arizona->dac_comp_lock);
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001371
1372 dac_comp[1].def = arizona->dac_comp_coeff;
1373 if (rate >= 176400)
1374 dac_comp[2].def = arizona->dac_comp_enabled;
1375
Lars-Peter Clausend74bcaa2014-11-09 17:00:59 +01001376 mutex_unlock(&arizona->dac_comp_lock);
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001377
1378 regmap_multi_reg_write(arizona->regmap,
1379 dac_comp,
1380 ARRAY_SIZE(dac_comp));
1381}
1382
Mark Brownb272efc2012-10-10 15:10:08 +09001383static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
1384 struct snd_pcm_hw_params *params,
1385 struct snd_soc_dai *dai)
Mark Brown07ed8732012-06-18 21:08:44 +01001386{
1387 struct snd_soc_codec *codec = dai->codec;
Mark Brownc013b272012-07-04 20:05:57 +01001388 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1389 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown07ed8732012-06-18 21:08:44 +01001390 int base = dai->driver->base;
Richard Fitzgerald2c118b42015-06-02 11:53:35 +01001391 int i, sr_val, ret;
Mark Brownb272efc2012-10-10 15:10:08 +09001392
1393 /*
1394 * We will need to be more flexible than this in future,
1395 * currently we use a single sample rate for SYSCLK.
1396 */
1397 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
1398 if (arizona_sr_vals[i] == params_rate(params))
1399 break;
1400 if (i == ARRAY_SIZE(arizona_sr_vals)) {
1401 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1402 params_rate(params));
1403 return -EINVAL;
1404 }
1405 sr_val = i;
1406
Richard Fitzgerald2c118b42015-06-02 11:53:35 +01001407 switch (priv->arizona->type) {
1408 case WM5102:
1409 case WM8997:
1410 if (arizona_sr_vals[sr_val] >= 88200)
1411 ret = arizona_dvfs_up(codec, ARIZONA_DVFS_SR1_RQ);
1412 else
1413 ret = arizona_dvfs_down(codec, ARIZONA_DVFS_SR1_RQ);
1414
1415 if (ret) {
1416 arizona_aif_err(dai, "Failed to change DVFS %d\n", ret);
1417 return ret;
1418 }
1419 break;
1420 default:
1421 break;
1422 }
1423
Mark Brownb272efc2012-10-10 15:10:08 +09001424 switch (dai_priv->clk) {
1425 case ARIZONA_CLK_SYSCLK:
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001426 switch (priv->arizona->type) {
1427 case WM5102:
1428 arizona_wm5102_set_dac_comp(codec,
1429 params_rate(params));
1430 break;
1431 default:
1432 break;
1433 }
1434
Mark Brownb272efc2012-10-10 15:10:08 +09001435 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
1436 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
1437 if (base)
1438 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1439 ARIZONA_AIF1_RATE_MASK, 0);
1440 break;
1441 case ARIZONA_CLK_ASYNCCLK:
1442 snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
Charles Keepaxc24084d2014-09-01 15:48:52 +01001443 ARIZONA_ASYNC_SAMPLE_RATE_1_MASK, sr_val);
Mark Brownb272efc2012-10-10 15:10:08 +09001444 if (base)
1445 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1446 ARIZONA_AIF1_RATE_MASK,
1447 8 << ARIZONA_AIF1_RATE_SHIFT);
1448 break;
1449 default:
1450 arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
1451 return -EINVAL;
1452 }
1453
1454 return 0;
1455}
1456
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001457static bool arizona_aif_cfg_changed(struct snd_soc_codec *codec,
1458 int base, int bclk, int lrclk, int frame)
1459{
1460 int val;
1461
1462 val = snd_soc_read(codec, base + ARIZONA_AIF_BCLK_CTRL);
1463 if (bclk != (val & ARIZONA_AIF1_BCLK_FREQ_MASK))
1464 return true;
1465
1466 val = snd_soc_read(codec, base + ARIZONA_AIF_TX_BCLK_RATE);
1467 if (lrclk != (val & ARIZONA_AIF1TX_BCPF_MASK))
1468 return true;
1469
1470 val = snd_soc_read(codec, base + ARIZONA_AIF_FRAME_CTRL_1);
1471 if (frame != (val & (ARIZONA_AIF1TX_WL_MASK |
1472 ARIZONA_AIF1TX_SLOT_LEN_MASK)))
1473 return true;
1474
1475 return false;
1476}
1477
Mark Brown07ed8732012-06-18 21:08:44 +01001478static int arizona_hw_params(struct snd_pcm_substream *substream,
1479 struct snd_pcm_hw_params *params,
1480 struct snd_soc_dai *dai)
1481{
1482 struct snd_soc_codec *codec = dai->codec;
1483 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brownc94aa302013-01-17 16:35:14 +09001484 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +01001485 int base = dai->driver->base;
1486 const int *rates;
Mark Brown76bf9692013-03-05 14:17:47 +08001487 int i, ret, val;
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001488 int channels = params_channels(params);
Mark Brownc94aa302013-01-17 16:35:14 +09001489 int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001490 int tdm_width = arizona->tdm_width[dai->id - 1];
1491 int tdm_slots = arizona->tdm_slots[dai->id - 1];
Mark Brownc94aa302013-01-17 16:35:14 +09001492 int bclk, lrclk, wl, frame, bclk_target;
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001493 bool reconfig;
1494 unsigned int aif_tx_state, aif_rx_state;
Mark Brown07ed8732012-06-18 21:08:44 +01001495
1496 if (params_rate(params) % 8000)
Mark Brown949e6bc2012-07-04 18:58:04 +01001497 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001498 else
Mark Brown949e6bc2012-07-04 18:58:04 +01001499 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001500
Charles Keepax5ed68f02015-07-09 11:28:46 +01001501 wl = params_width(params);
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001502
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001503 if (tdm_slots) {
1504 arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n",
1505 tdm_slots, tdm_width);
1506 bclk_target = tdm_slots * tdm_width * params_rate(params);
1507 channels = tdm_slots;
1508 } else {
1509 bclk_target = snd_soc_params_to_bclk(params);
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001510 tdm_width = wl;
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001511 }
1512
1513 if (chan_limit && chan_limit < channels) {
Mark Brownc94aa302013-01-17 16:35:14 +09001514 arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001515 bclk_target /= channels;
Mark Brownc94aa302013-01-17 16:35:14 +09001516 bclk_target *= chan_limit;
1517 }
1518
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001519 /* Force multiple of 2 channels for I2S mode */
Mark Brown76bf9692013-03-05 14:17:47 +08001520 val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001521 val &= ARIZONA_AIF1_FMT_MASK;
1522 if ((channels & 1) && (val == ARIZONA_FMT_I2S_MODE)) {
Mark Brown76bf9692013-03-05 14:17:47 +08001523 arizona_aif_dbg(dai, "Forcing stereo mode\n");
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001524 bclk_target /= channels;
1525 bclk_target *= channels + 1;
Mark Brown76bf9692013-03-05 14:17:47 +08001526 }
1527
Mark Brown949e6bc2012-07-04 18:58:04 +01001528 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brownc94aa302013-01-17 16:35:14 +09001529 if (rates[i] >= bclk_target &&
Mark Brown50017652012-07-04 19:07:09 +01001530 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +01001531 bclk = i;
1532 break;
1533 }
1534 }
Mark Brown949e6bc2012-07-04 18:58:04 +01001535 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001536 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1537 params_rate(params));
1538 return -EINVAL;
1539 }
1540
Mark Brownb59e0f82013-01-17 14:15:59 +09001541 lrclk = rates[bclk] / params_rate(params);
Mark Brown07ed8732012-06-18 21:08:44 +01001542
1543 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
1544 rates[bclk], rates[bclk] / lrclk);
1545
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001546 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | tdm_width;
Mark Brown07ed8732012-06-18 21:08:44 +01001547
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001548 reconfig = arizona_aif_cfg_changed(codec, base, bclk, lrclk, frame);
1549
1550 if (reconfig) {
1551 /* Save AIF TX/RX state */
1552 aif_tx_state = snd_soc_read(codec,
1553 base + ARIZONA_AIF_TX_ENABLES);
1554 aif_rx_state = snd_soc_read(codec,
1555 base + ARIZONA_AIF_RX_ENABLES);
1556 /* Disable AIF TX/RX before reconfiguring it */
1557 regmap_update_bits_async(arizona->regmap,
1558 base + ARIZONA_AIF_TX_ENABLES, 0xff, 0x0);
1559 regmap_update_bits(arizona->regmap,
1560 base + ARIZONA_AIF_RX_ENABLES, 0xff, 0x0);
1561 }
1562
Mark Brownb272efc2012-10-10 15:10:08 +09001563 ret = arizona_hw_params_rate(substream, params, dai);
1564 if (ret != 0)
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001565 goto restore_aif;
Mark Brownc013b272012-07-04 20:05:57 +01001566
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001567 if (reconfig) {
1568 regmap_update_bits_async(arizona->regmap,
1569 base + ARIZONA_AIF_BCLK_CTRL,
1570 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
1571 regmap_update_bits_async(arizona->regmap,
1572 base + ARIZONA_AIF_TX_BCLK_RATE,
1573 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
1574 regmap_update_bits_async(arizona->regmap,
1575 base + ARIZONA_AIF_RX_BCLK_RATE,
1576 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
1577 regmap_update_bits_async(arizona->regmap,
1578 base + ARIZONA_AIF_FRAME_CTRL_1,
1579 ARIZONA_AIF1TX_WL_MASK |
1580 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
1581 regmap_update_bits(arizona->regmap,
1582 base + ARIZONA_AIF_FRAME_CTRL_2,
1583 ARIZONA_AIF1RX_WL_MASK |
1584 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
1585 }
Mark Brown07ed8732012-06-18 21:08:44 +01001586
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001587restore_aif:
1588 if (reconfig) {
1589 /* Restore AIF TX/RX state */
1590 regmap_update_bits_async(arizona->regmap,
1591 base + ARIZONA_AIF_TX_ENABLES,
1592 0xff, aif_tx_state);
1593 regmap_update_bits(arizona->regmap,
1594 base + ARIZONA_AIF_RX_ENABLES,
1595 0xff, aif_rx_state);
1596 }
1597 return ret;
Mark Brown07ed8732012-06-18 21:08:44 +01001598}
1599
Mark Brown410837a2012-07-05 17:26:59 +01001600static const char *arizona_dai_clk_str(int clk_id)
1601{
1602 switch (clk_id) {
1603 case ARIZONA_CLK_SYSCLK:
1604 return "SYSCLK";
1605 case ARIZONA_CLK_ASYNCCLK:
1606 return "ASYNCCLK";
1607 default:
1608 return "Unknown clock";
1609 }
1610}
1611
Mark Brown5b2eec32012-07-04 17:32:05 +01001612static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
1613 int clk_id, unsigned int freq, int dir)
1614{
1615 struct snd_soc_codec *codec = dai->codec;
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +02001616 struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
Mark Brown5b2eec32012-07-04 17:32:05 +01001617 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1618 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown410837a2012-07-05 17:26:59 +01001619 struct snd_soc_dapm_route routes[2];
Mark Brown5b2eec32012-07-04 17:32:05 +01001620
1621 switch (clk_id) {
1622 case ARIZONA_CLK_SYSCLK:
1623 case ARIZONA_CLK_ASYNCCLK:
1624 break;
1625 default:
1626 return -EINVAL;
1627 }
1628
Mark Brown410837a2012-07-05 17:26:59 +01001629 if (clk_id == dai_priv->clk)
1630 return 0;
1631
1632 if (dai->active) {
Mark Brown5b2eec32012-07-04 17:32:05 +01001633 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
1634 dai->id);
1635 return -EBUSY;
1636 }
1637
Mark Brownc8d35a62012-12-07 12:49:40 +09001638 dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1,
1639 arizona_dai_clk_str(clk_id));
1640
Mark Brown410837a2012-07-05 17:26:59 +01001641 memset(&routes, 0, sizeof(routes));
1642 routes[0].sink = dai->driver->capture.stream_name;
1643 routes[1].sink = dai->driver->playback.stream_name;
Mark Brown5b2eec32012-07-04 17:32:05 +01001644
Mark Brown410837a2012-07-05 17:26:59 +01001645 routes[0].source = arizona_dai_clk_str(dai_priv->clk);
1646 routes[1].source = arizona_dai_clk_str(dai_priv->clk);
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +02001647 snd_soc_dapm_del_routes(dapm, routes, ARRAY_SIZE(routes));
Mark Brown410837a2012-07-05 17:26:59 +01001648
1649 routes[0].source = arizona_dai_clk_str(clk_id);
1650 routes[1].source = arizona_dai_clk_str(clk_id);
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +02001651 snd_soc_dapm_add_routes(dapm, routes, ARRAY_SIZE(routes));
Mark Brown410837a2012-07-05 17:26:59 +01001652
Mark Brown0c778e82012-12-06 18:22:25 +09001653 dai_priv->clk = clk_id;
1654
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +02001655 return snd_soc_dapm_sync(dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +01001656}
1657
Mark Brown01df2592012-12-12 16:22:08 +09001658static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
1659{
1660 struct snd_soc_codec *codec = dai->codec;
1661 int base = dai->driver->base;
1662 unsigned int reg;
1663
1664 if (tristate)
1665 reg = ARIZONA_AIF1_TRI;
1666 else
1667 reg = 0;
1668
1669 return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1670 ARIZONA_AIF1_TRI, reg);
1671}
1672
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001673static void arizona_set_channels_to_mask(struct snd_soc_dai *dai,
1674 unsigned int base,
1675 int channels, unsigned int mask)
1676{
1677 struct snd_soc_codec *codec = dai->codec;
1678 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1679 struct arizona *arizona = priv->arizona;
1680 int slot, i;
1681
1682 for (i = 0; i < channels; ++i) {
1683 slot = ffs(mask) - 1;
1684 if (slot < 0)
1685 return;
1686
1687 regmap_write(arizona->regmap, base + i, slot);
1688
1689 mask &= ~(1 << slot);
1690 }
1691
1692 if (mask)
1693 arizona_aif_warn(dai, "Too many channels in TDM mask\n");
1694}
1695
1696static int arizona_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
1697 unsigned int rx_mask, int slots, int slot_width)
1698{
1699 struct snd_soc_codec *codec = dai->codec;
1700 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1701 struct arizona *arizona = priv->arizona;
1702 int base = dai->driver->base;
1703 int rx_max_chan = dai->driver->playback.channels_max;
1704 int tx_max_chan = dai->driver->capture.channels_max;
1705
1706 /* Only support TDM for the physical AIFs */
1707 if (dai->id > ARIZONA_MAX_AIF)
1708 return -ENOTSUPP;
1709
1710 if (slots == 0) {
1711 tx_mask = (1 << tx_max_chan) - 1;
1712 rx_mask = (1 << rx_max_chan) - 1;
1713 }
1714
1715 arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_3,
1716 tx_max_chan, tx_mask);
1717 arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_11,
1718 rx_max_chan, rx_mask);
1719
1720 arizona->tdm_width[dai->id - 1] = slot_width;
1721 arizona->tdm_slots[dai->id - 1] = slots;
1722
1723 return 0;
1724}
1725
Mark Brown07ed8732012-06-18 21:08:44 +01001726const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +01001727 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +01001728 .set_fmt = arizona_set_fmt,
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001729 .set_tdm_slot = arizona_set_tdm_slot,
Mark Brown07ed8732012-06-18 21:08:44 +01001730 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +01001731 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown01df2592012-12-12 16:22:08 +09001732 .set_tristate = arizona_set_tristate,
Mark Brown07ed8732012-06-18 21:08:44 +01001733};
Mark Browna8379872012-07-09 12:16:41 +01001734EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +01001735
Mark Brownbd1dd882013-05-17 13:29:03 +01001736const struct snd_soc_dai_ops arizona_simple_dai_ops = {
1737 .startup = arizona_startup,
1738 .hw_params = arizona_hw_params_rate,
1739 .set_sysclk = arizona_dai_set_sysclk,
1740};
1741EXPORT_SYMBOL_GPL(arizona_simple_dai_ops);
1742
Mark Brown5b2eec32012-07-04 17:32:05 +01001743int arizona_init_dai(struct arizona_priv *priv, int id)
1744{
1745 struct arizona_dai_priv *dai_priv = &priv->dai[id];
1746
1747 dai_priv->clk = ARIZONA_CLK_SYSCLK;
1748
1749 return 0;
1750}
1751EXPORT_SYMBOL_GPL(arizona_init_dai);
1752
Mark Brown07ed8732012-06-18 21:08:44 +01001753static struct {
1754 unsigned int min;
1755 unsigned int max;
1756 u16 fratio;
1757 int ratio;
1758} fll_fratios[] = {
1759 { 0, 64000, 4, 16 },
1760 { 64000, 128000, 3, 8 },
1761 { 128000, 256000, 2, 4 },
1762 { 256000, 1000000, 1, 2 },
1763 { 1000000, 13500000, 0, 1 },
1764};
1765
Mark Brown8f113d72013-03-05 12:08:57 +08001766static struct {
1767 unsigned int min;
1768 unsigned int max;
1769 u16 gain;
1770} fll_gains[] = {
1771 { 0, 256000, 0 },
1772 { 256000, 1000000, 2 },
1773 { 1000000, 13500000, 4 },
1774};
1775
Mark Brown07ed8732012-06-18 21:08:44 +01001776struct arizona_fll_cfg {
1777 int n;
1778 int theta;
1779 int lambda;
1780 int refdiv;
1781 int outdiv;
1782 int fratio;
Mark Brown8f113d72013-03-05 12:08:57 +08001783 int gain;
Mark Brown07ed8732012-06-18 21:08:44 +01001784};
1785
Charles Keepax23f785a82014-03-07 16:34:20 +00001786static int arizona_validate_fll(struct arizona_fll *fll,
1787 unsigned int Fref,
1788 unsigned int Fout)
1789{
1790 unsigned int Fvco_min;
1791
Charles Keepaxc8badda2014-07-09 17:41:49 +01001792 if (fll->fout && Fout != fll->fout) {
1793 arizona_fll_err(fll,
1794 "Can't change output on active FLL\n");
1795 return -EINVAL;
1796 }
1797
Charles Keepax23f785a82014-03-07 16:34:20 +00001798 if (Fref / ARIZONA_FLL_MAX_REFDIV > ARIZONA_FLL_MAX_FREF) {
1799 arizona_fll_err(fll,
1800 "Can't scale %dMHz in to <=13.5MHz\n",
1801 Fref);
1802 return -EINVAL;
1803 }
1804
1805 Fvco_min = ARIZONA_FLL_MIN_FVCO * fll->vco_mult;
1806 if (Fout * ARIZONA_FLL_MAX_OUTDIV < Fvco_min) {
1807 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
1808 Fout);
1809 return -EINVAL;
1810 }
1811
1812 return 0;
1813}
1814
Charles Keepaxd0800342014-03-07 16:34:25 +00001815static int arizona_find_fratio(unsigned int Fref, int *fratio)
1816{
1817 int i;
1818
1819 /* Find an appropriate FLL_FRATIO */
1820 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
1821 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
1822 if (fratio)
1823 *fratio = fll_fratios[i].fratio;
1824 return fll_fratios[i].ratio;
1825 }
1826 }
1827
1828 return -EINVAL;
1829}
1830
1831static int arizona_calc_fratio(struct arizona_fll *fll,
1832 struct arizona_fll_cfg *cfg,
1833 unsigned int target,
1834 unsigned int Fref, bool sync)
1835{
1836 int init_ratio, ratio;
1837 int refdiv, div;
1838
1839 /* Fref must be <=13.5MHz, find initial refdiv */
1840 div = 1;
1841 cfg->refdiv = 0;
1842 while (Fref > ARIZONA_FLL_MAX_FREF) {
1843 div *= 2;
1844 Fref /= 2;
1845 cfg->refdiv++;
1846
1847 if (div > ARIZONA_FLL_MAX_REFDIV)
1848 return -EINVAL;
1849 }
1850
1851 /* Find an appropriate FLL_FRATIO */
1852 init_ratio = arizona_find_fratio(Fref, &cfg->fratio);
1853 if (init_ratio < 0) {
1854 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
1855 Fref);
1856 return init_ratio;
1857 }
1858
1859 switch (fll->arizona->type) {
1860 case WM5110:
Richard Fitzgerald575ef7f2015-01-17 15:21:27 +00001861 case WM8280:
Charles Keepaxd0800342014-03-07 16:34:25 +00001862 if (fll->arizona->rev < 3 || sync)
1863 return init_ratio;
1864 break;
1865 default:
1866 return init_ratio;
1867 }
1868
1869 cfg->fratio = init_ratio - 1;
1870
1871 /* Adjust FRATIO/refdiv to avoid integer mode if possible */
1872 refdiv = cfg->refdiv;
1873
1874 while (div <= ARIZONA_FLL_MAX_REFDIV) {
1875 for (ratio = init_ratio; ratio <= ARIZONA_FLL_MAX_FRATIO;
1876 ratio++) {
Charles Keepax35a730a2014-07-09 17:41:45 +01001877 if ((ARIZONA_FLL_VCO_CORNER / 2) /
1878 (fll->vco_mult * ratio) < Fref)
Charles Keepax29fee822014-07-09 17:41:44 +01001879 break;
1880
Charles Keepaxd0800342014-03-07 16:34:25 +00001881 if (target % (ratio * Fref)) {
1882 cfg->refdiv = refdiv;
1883 cfg->fratio = ratio - 1;
1884 return ratio;
1885 }
1886 }
1887
Charles Keepax4714bc02014-07-09 17:41:43 +01001888 for (ratio = init_ratio - 1; ratio > 0; ratio--) {
Charles Keepaxd0800342014-03-07 16:34:25 +00001889 if (target % (ratio * Fref)) {
1890 cfg->refdiv = refdiv;
1891 cfg->fratio = ratio - 1;
1892 return ratio;
1893 }
1894 }
1895
1896 div *= 2;
1897 Fref /= 2;
1898 refdiv++;
1899 init_ratio = arizona_find_fratio(Fref, NULL);
1900 }
1901
1902 arizona_fll_warn(fll, "Falling back to integer mode operation\n");
1903 return cfg->fratio + 1;
1904}
1905
Mark Brown07ed8732012-06-18 21:08:44 +01001906static int arizona_calc_fll(struct arizona_fll *fll,
1907 struct arizona_fll_cfg *cfg,
Charles Keepaxd0800342014-03-07 16:34:25 +00001908 unsigned int Fref, bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01001909{
1910 unsigned int target, div, gcd_fll;
1911 int i, ratio;
1912
Charles Keepax8ccefcd2014-03-07 16:34:21 +00001913 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, fll->fout);
Mark Brown07ed8732012-06-18 21:08:44 +01001914
Mark Brown2b4d39f2012-07-10 17:03:46 +01001915 /* Fvco should be over the targt; don't check the upper bound */
Charles Keepaxf641aec2014-03-07 16:34:22 +00001916 div = ARIZONA_FLL_MIN_OUTDIV;
1917 while (fll->fout * div < ARIZONA_FLL_MIN_FVCO * fll->vco_mult) {
Mark Brown07ed8732012-06-18 21:08:44 +01001918 div++;
Charles Keepaxf641aec2014-03-07 16:34:22 +00001919 if (div > ARIZONA_FLL_MAX_OUTDIV)
Mark Brown07ed8732012-06-18 21:08:44 +01001920 return -EINVAL;
Mark Brown07ed8732012-06-18 21:08:44 +01001921 }
Charles Keepaxf641aec2014-03-07 16:34:22 +00001922 target = fll->fout * div / fll->vco_mult;
Mark Brown07ed8732012-06-18 21:08:44 +01001923 cfg->outdiv = div;
1924
1925 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
1926
Charles Keepaxd0800342014-03-07 16:34:25 +00001927 /* Find an appropriate FLL_FRATIO and refdiv */
1928 ratio = arizona_calc_fratio(fll, cfg, target, Fref, sync);
1929 if (ratio < 0)
1930 return ratio;
Mark Brown07ed8732012-06-18 21:08:44 +01001931
Mark Brown07ed8732012-06-18 21:08:44 +01001932 /* Apply the division for our remaining calculations */
Charles Keepaxd0800342014-03-07 16:34:25 +00001933 Fref = Fref / (1 << cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08001934
Mark Brown07ed8732012-06-18 21:08:44 +01001935 cfg->n = target / (ratio * Fref);
1936
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001937 if (target % (ratio * Fref)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001938 gcd_fll = gcd(target, ratio * Fref);
1939 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
1940
1941 cfg->theta = (target - (cfg->n * ratio * Fref))
1942 / gcd_fll;
1943 cfg->lambda = (ratio * Fref) / gcd_fll;
1944 } else {
1945 cfg->theta = 0;
1946 cfg->lambda = 0;
1947 }
1948
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001949 /* Round down to 16bit range with cost of accuracy lost.
1950 * Denominator must be bigger than numerator so we only
1951 * take care of it.
1952 */
1953 while (cfg->lambda >= (1 << 16)) {
1954 cfg->theta >>= 1;
1955 cfg->lambda >>= 1;
1956 }
1957
Charles Keepax5a3935c2014-03-07 16:34:23 +00001958 for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
1959 if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
1960 cfg->gain = fll_gains[i].gain;
1961 break;
1962 }
1963 }
1964 if (i == ARRAY_SIZE(fll_gains)) {
1965 arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
1966 Fref);
1967 return -EINVAL;
1968 }
1969
Mark Brown07ed8732012-06-18 21:08:44 +01001970 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
1971 cfg->n, cfg->theta, cfg->lambda);
1972 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
1973 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08001974 arizona_fll_dbg(fll, "GAIN=%d\n", cfg->gain);
Mark Brown07ed8732012-06-18 21:08:44 +01001975
1976 return 0;
1977
1978}
1979
1980static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
Mark Brown8f113d72013-03-05 12:08:57 +08001981 struct arizona_fll_cfg *cfg, int source,
1982 bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01001983{
Mark Brown3c43c692013-12-12 00:49:22 +00001984 regmap_update_bits_async(arizona->regmap, base + 3,
1985 ARIZONA_FLL1_THETA_MASK, cfg->theta);
1986 regmap_update_bits_async(arizona->regmap, base + 4,
1987 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
1988 regmap_update_bits_async(arizona->regmap, base + 5,
1989 ARIZONA_FLL1_FRATIO_MASK,
1990 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
1991 regmap_update_bits_async(arizona->regmap, base + 6,
1992 ARIZONA_FLL1_CLK_REF_DIV_MASK |
1993 ARIZONA_FLL1_CLK_REF_SRC_MASK,
1994 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
1995 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
Mark Brown07ed8732012-06-18 21:08:44 +01001996
Charles Keepax61719db2014-03-07 16:34:19 +00001997 if (sync) {
1998 regmap_update_bits(arizona->regmap, base + 0x7,
1999 ARIZONA_FLL1_GAIN_MASK,
2000 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
2001 } else {
2002 regmap_update_bits(arizona->regmap, base + 0x5,
2003 ARIZONA_FLL1_OUTDIV_MASK,
2004 cfg->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
2005 regmap_update_bits(arizona->regmap, base + 0x9,
2006 ARIZONA_FLL1_GAIN_MASK,
2007 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
2008 }
Mark Brown8f113d72013-03-05 12:08:57 +08002009
Mark Brown3c43c692013-12-12 00:49:22 +00002010 regmap_update_bits_async(arizona->regmap, base + 2,
2011 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
2012 ARIZONA_FLL1_CTRL_UPD | cfg->n);
Mark Brown07ed8732012-06-18 21:08:44 +01002013}
2014
Charles Keepaxc393aca2014-07-09 17:41:47 +01002015static int arizona_is_enabled_fll(struct arizona_fll *fll)
Charles Keepaxd122d6c2013-02-20 17:28:36 +00002016{
2017 struct arizona *arizona = fll->arizona;
2018 unsigned int reg;
2019 int ret;
2020
2021 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
2022 if (ret != 0) {
2023 arizona_fll_err(fll, "Failed to read current state: %d\n",
2024 ret);
2025 return ret;
2026 }
2027
2028 return reg & ARIZONA_FLL1_ENA;
2029}
2030
Charles Keepaxc393aca2014-07-09 17:41:47 +01002031static int arizona_enable_fll(struct arizona_fll *fll)
Charles Keepax35722812013-02-20 17:28:38 +00002032{
2033 struct arizona *arizona = fll->arizona;
Charles Keepax49c60542013-09-16 15:34:35 +01002034 bool use_sync = false;
Charles Keepaxc393aca2014-07-09 17:41:47 +01002035 int already_enabled = arizona_is_enabled_fll(fll);
Charles Keepax23f785a82014-03-07 16:34:20 +00002036 struct arizona_fll_cfg cfg;
Charles Keepax0e765972015-08-25 12:43:48 +01002037 int i;
2038 unsigned int val;
Charles Keepax35722812013-02-20 17:28:38 +00002039
Charles Keepaxc393aca2014-07-09 17:41:47 +01002040 if (already_enabled < 0)
2041 return already_enabled;
2042
Charles Keepaxc8badda2014-07-09 17:41:49 +01002043 if (already_enabled) {
2044 /* Facilitate smooth refclk across the transition */
Nikesh Oswal1cf5a332015-08-19 16:02:24 +01002045 regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9,
Charles Keepaxc8badda2014-07-09 17:41:49 +01002046 ARIZONA_FLL1_GAIN_MASK, 0);
2047 regmap_update_bits_async(fll->arizona->regmap, fll->base + 1,
2048 ARIZONA_FLL1_FREERUN,
2049 ARIZONA_FLL1_FREERUN);
2050 }
2051
Mark Brownff680a12013-03-04 16:00:19 +08002052 /*
2053 * If we have both REFCLK and SYNCCLK then enable both,
2054 * otherwise apply the SYNCCLK settings to REFCLK.
2055 */
Charles Keepax49c60542013-09-16 15:34:35 +01002056 if (fll->ref_src >= 0 && fll->ref_freq &&
2057 fll->ref_src != fll->sync_src) {
Charles Keepaxd0800342014-03-07 16:34:25 +00002058 arizona_calc_fll(fll, &cfg, fll->ref_freq, false);
Charles Keepax35722812013-02-20 17:28:38 +00002059
Charles Keepax23f785a82014-03-07 16:34:20 +00002060 arizona_apply_fll(arizona, fll->base, &cfg, fll->ref_src,
Mark Brown8f113d72013-03-05 12:08:57 +08002061 false);
Charles Keepax49c60542013-09-16 15:34:35 +01002062 if (fll->sync_src >= 0) {
Charles Keepaxd0800342014-03-07 16:34:25 +00002063 arizona_calc_fll(fll, &cfg, fll->sync_freq, true);
Charles Keepax23f785a82014-03-07 16:34:20 +00002064
2065 arizona_apply_fll(arizona, fll->base + 0x10, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08002066 fll->sync_src, true);
Charles Keepax49c60542013-09-16 15:34:35 +01002067 use_sync = true;
2068 }
Mark Brownff680a12013-03-04 16:00:19 +08002069 } else if (fll->sync_src >= 0) {
Charles Keepaxd0800342014-03-07 16:34:25 +00002070 arizona_calc_fll(fll, &cfg, fll->sync_freq, false);
Mark Brownff680a12013-03-04 16:00:19 +08002071
Charles Keepax23f785a82014-03-07 16:34:20 +00002072 arizona_apply_fll(arizona, fll->base, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08002073 fll->sync_src, false);
Mark Browneca2e8e2013-03-06 00:09:59 +08002074
Mark Brown3c43c692013-12-12 00:49:22 +00002075 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
2076 ARIZONA_FLL1_SYNC_ENA, 0);
Mark Brownff680a12013-03-04 16:00:19 +08002077 } else {
2078 arizona_fll_err(fll, "No clocks provided\n");
Charles Keepaxc393aca2014-07-09 17:41:47 +01002079 return -EINVAL;
Mark Brownff680a12013-03-04 16:00:19 +08002080 }
Charles Keepax35722812013-02-20 17:28:38 +00002081
Mark Brown576411be2013-03-05 12:07:16 +08002082 /*
2083 * Increase the bandwidth if we're not using a low frequency
2084 * sync source.
2085 */
Charles Keepax49c60542013-09-16 15:34:35 +01002086 if (use_sync && fll->sync_freq > 100000)
Mark Brown3c43c692013-12-12 00:49:22 +00002087 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
2088 ARIZONA_FLL1_SYNC_BW, 0);
Mark Brown576411be2013-03-05 12:07:16 +08002089 else
Mark Brown3c43c692013-12-12 00:49:22 +00002090 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
2091 ARIZONA_FLL1_SYNC_BW,
2092 ARIZONA_FLL1_SYNC_BW);
Mark Brown576411be2013-03-05 12:07:16 +08002093
Charles Keepaxc393aca2014-07-09 17:41:47 +01002094 if (!already_enabled)
Charles Keepax35722812013-02-20 17:28:38 +00002095 pm_runtime_get(arizona->dev);
2096
Mark Brown3c43c692013-12-12 00:49:22 +00002097 regmap_update_bits_async(arizona->regmap, fll->base + 1,
Mark Brown3c43c692013-12-12 00:49:22 +00002098 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
Charles Keepax49c60542013-09-16 15:34:35 +01002099 if (use_sync)
Mark Brown3c43c692013-12-12 00:49:22 +00002100 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
2101 ARIZONA_FLL1_SYNC_ENA,
2102 ARIZONA_FLL1_SYNC_ENA);
Charles Keepax35722812013-02-20 17:28:38 +00002103
Charles Keepaxc8badda2014-07-09 17:41:49 +01002104 if (already_enabled)
2105 regmap_update_bits_async(arizona->regmap, fll->base + 1,
2106 ARIZONA_FLL1_FREERUN, 0);
2107
Charles Keepax0e765972015-08-25 12:43:48 +01002108 arizona_fll_dbg(fll, "Waiting for FLL lock...\n");
2109 val = 0;
2110 for (i = 0; i < 15; i++) {
2111 if (i < 5)
2112 usleep_range(200, 400);
2113 else
2114 msleep(20);
2115
2116 regmap_read(arizona->regmap,
2117 ARIZONA_INTERRUPT_RAW_STATUS_5,
2118 &val);
2119 if (val & (ARIZONA_FLL1_CLOCK_OK_STS << (fll->id - 1)))
2120 break;
2121 }
2122 if (i == 15)
Charles Keepax35722812013-02-20 17:28:38 +00002123 arizona_fll_warn(fll, "Timed out waiting for lock\n");
Charles Keepax0e765972015-08-25 12:43:48 +01002124 else
2125 arizona_fll_dbg(fll, "FLL locked (%d polls)\n", i);
Charles Keepaxc393aca2014-07-09 17:41:47 +01002126
2127 return 0;
Charles Keepax35722812013-02-20 17:28:38 +00002128}
2129
Charles Keepax76040542013-02-20 17:28:37 +00002130static void arizona_disable_fll(struct arizona_fll *fll)
2131{
2132 struct arizona *arizona = fll->arizona;
2133 bool change;
2134
Mark Brown3c43c692013-12-12 00:49:22 +00002135 regmap_update_bits_async(arizona->regmap, fll->base + 1,
2136 ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
Charles Keepax76040542013-02-20 17:28:37 +00002137 regmap_update_bits_check(arizona->regmap, fll->base + 1,
2138 ARIZONA_FLL1_ENA, 0, &change);
2139 regmap_update_bits(arizona->regmap, fll->base + 0x11,
2140 ARIZONA_FLL1_SYNC_ENA, 0);
Charles Keepax5e39a502014-07-09 17:41:48 +01002141 regmap_update_bits_async(arizona->regmap, fll->base + 1,
2142 ARIZONA_FLL1_FREERUN, 0);
Charles Keepax76040542013-02-20 17:28:37 +00002143
2144 if (change)
2145 pm_runtime_put_autosuspend(arizona->dev);
2146}
2147
Charles Keepaxee929a92013-02-20 17:28:40 +00002148int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
2149 unsigned int Fref, unsigned int Fout)
2150{
Charles Keepaxc393aca2014-07-09 17:41:47 +01002151 int ret = 0;
Charles Keepaxee929a92013-02-20 17:28:40 +00002152
Charles Keepax1c5617f2013-02-22 17:10:37 +00002153 if (fll->ref_src == source && fll->ref_freq == Fref)
Charles Keepaxee929a92013-02-20 17:28:40 +00002154 return 0;
2155
Charles Keepax23f785a82014-03-07 16:34:20 +00002156 if (fll->fout && Fref > 0) {
2157 ret = arizona_validate_fll(fll, Fref, fll->fout);
2158 if (ret != 0)
2159 return ret;
Charles Keepaxee929a92013-02-20 17:28:40 +00002160 }
2161
2162 fll->ref_src = source;
2163 fll->ref_freq = Fref;
Charles Keepaxee929a92013-02-20 17:28:40 +00002164
Mark Brown86cd6842013-03-07 16:14:04 +08002165 if (fll->fout && Fref > 0) {
Charles Keepaxc393aca2014-07-09 17:41:47 +01002166 ret = arizona_enable_fll(fll);
Charles Keepaxee929a92013-02-20 17:28:40 +00002167 }
2168
Charles Keepaxc393aca2014-07-09 17:41:47 +01002169 return ret;
Charles Keepaxee929a92013-02-20 17:28:40 +00002170}
2171EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
2172
Mark Brown07ed8732012-06-18 21:08:44 +01002173int arizona_set_fll(struct arizona_fll *fll, int source,
2174 unsigned int Fref, unsigned int Fout)
2175{
Charles Keepaxc393aca2014-07-09 17:41:47 +01002176 int ret = 0;
Mark Brown07ed8732012-06-18 21:08:44 +01002177
Mark Brownff680a12013-03-04 16:00:19 +08002178 if (fll->sync_src == source &&
2179 fll->sync_freq == Fref && fll->fout == Fout)
2180 return 0;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00002181
Mark Brownff680a12013-03-04 16:00:19 +08002182 if (Fout) {
2183 if (fll->ref_src >= 0) {
Charles Keepax23f785a82014-03-07 16:34:20 +00002184 ret = arizona_validate_fll(fll, fll->ref_freq, Fout);
Charles Keepax9e359c62013-02-20 17:28:35 +00002185 if (ret != 0)
2186 return ret;
2187 }
2188
Charles Keepax23f785a82014-03-07 16:34:20 +00002189 ret = arizona_validate_fll(fll, Fref, Fout);
Mark Brownff680a12013-03-04 16:00:19 +08002190 if (ret != 0)
2191 return ret;
Charles Keepax9e359c62013-02-20 17:28:35 +00002192 }
Mark Brownff680a12013-03-04 16:00:19 +08002193
2194 fll->sync_src = source;
2195 fll->sync_freq = Fref;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00002196 fll->fout = Fout;
Charles Keepax9e359c62013-02-20 17:28:35 +00002197
Charles Keepax613124c2014-07-09 17:41:46 +01002198 if (Fout)
Charles Keepaxc393aca2014-07-09 17:41:47 +01002199 ret = arizona_enable_fll(fll);
Charles Keepax613124c2014-07-09 17:41:46 +01002200 else
Charles Keepax76040542013-02-20 17:28:37 +00002201 arizona_disable_fll(fll);
Mark Brown07ed8732012-06-18 21:08:44 +01002202
Charles Keepaxc393aca2014-07-09 17:41:47 +01002203 return ret;
Mark Brown07ed8732012-06-18 21:08:44 +01002204}
2205EXPORT_SYMBOL_GPL(arizona_set_fll);
2206
2207int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
2208 int ok_irq, struct arizona_fll *fll)
2209{
Charles Keepax19b34bd2013-02-20 17:28:34 +00002210 unsigned int val;
Mark Brown07ed8732012-06-18 21:08:44 +01002211
Mark Brown07ed8732012-06-18 21:08:44 +01002212 fll->id = id;
2213 fll->base = base;
2214 fll->arizona = arizona;
Charles Keepaxf3f11632013-02-20 17:28:41 +00002215 fll->sync_src = ARIZONA_FLL_SRC_NONE;
Mark Brown07ed8732012-06-18 21:08:44 +01002216
Charles Keepax19b34bd2013-02-20 17:28:34 +00002217 /* Configure default refclk to 32kHz if we have one */
2218 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
2219 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
2220 case ARIZONA_CLK_SRC_MCLK1:
2221 case ARIZONA_CLK_SRC_MCLK2:
2222 fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK;
2223 break;
2224 default:
Charles Keepaxf3f11632013-02-20 17:28:41 +00002225 fll->ref_src = ARIZONA_FLL_SRC_NONE;
Charles Keepax19b34bd2013-02-20 17:28:34 +00002226 }
2227 fll->ref_freq = 32768;
2228
Mark Brown07ed8732012-06-18 21:08:44 +01002229 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
2230 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
2231 "FLL%d clock OK", id);
2232
Charles Keepaxe31c1942013-01-07 16:41:45 +00002233 regmap_update_bits(arizona->regmap, fll->base + 1,
2234 ARIZONA_FLL1_FREERUN, 0);
2235
Mark Brown07ed8732012-06-18 21:08:44 +01002236 return 0;
2237}
2238EXPORT_SYMBOL_GPL(arizona_init_fll);
2239
Mark Brownbc9ab6d2013-01-04 19:31:00 +00002240/**
2241 * arizona_set_output_mode - Set the mode of the specified output
2242 *
2243 * @codec: Device to configure
2244 * @output: Output number
2245 * @diff: True to set the output to differential mode
2246 *
2247 * Some systems use external analogue switches to connect more
2248 * analogue devices to the CODEC than are supported by the device. In
2249 * some systems this requires changing the switched output from single
2250 * ended to differential mode dynamically at runtime, an operation
2251 * supported using this function.
2252 *
2253 * Most systems have a single static configuration and should use
2254 * platform data instead.
2255 */
2256int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
2257{
2258 unsigned int reg, val;
2259
2260 if (output < 1 || output > 6)
2261 return -EINVAL;
2262
2263 reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
2264
2265 if (diff)
2266 val = ARIZONA_OUT1_MONO;
2267 else
2268 val = 0;
2269
2270 return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val);
2271}
2272EXPORT_SYMBOL_GPL(arizona_set_output_mode);
2273
Richard Fitzgerald336d0442015-06-18 13:43:19 +01002274static const struct soc_enum arizona_adsp2_rate_enum[] = {
2275 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP1_CONTROL_1,
2276 ARIZONA_DSP1_RATE_SHIFT, 0xf,
2277 ARIZONA_RATE_ENUM_SIZE,
2278 arizona_rate_text, arizona_rate_val),
2279 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP2_CONTROL_1,
2280 ARIZONA_DSP1_RATE_SHIFT, 0xf,
2281 ARIZONA_RATE_ENUM_SIZE,
2282 arizona_rate_text, arizona_rate_val),
2283 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1,
2284 ARIZONA_DSP1_RATE_SHIFT, 0xf,
2285 ARIZONA_RATE_ENUM_SIZE,
2286 arizona_rate_text, arizona_rate_val),
2287 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP4_CONTROL_1,
2288 ARIZONA_DSP1_RATE_SHIFT, 0xf,
2289 ARIZONA_RATE_ENUM_SIZE,
2290 arizona_rate_text, arizona_rate_val),
2291};
2292
2293const struct snd_kcontrol_new arizona_adsp2_rate_controls[] = {
2294 SOC_ENUM("DSP1 Rate", arizona_adsp2_rate_enum[0]),
2295 SOC_ENUM("DSP2 Rate", arizona_adsp2_rate_enum[1]),
2296 SOC_ENUM("DSP3 Rate", arizona_adsp2_rate_enum[2]),
2297 SOC_ENUM("DSP4 Rate", arizona_adsp2_rate_enum[3]),
2298};
2299EXPORT_SYMBOL_GPL(arizona_adsp2_rate_controls);
2300
Charles Keepaxc05d9a82015-06-25 09:35:11 +01002301static bool arizona_eq_filter_unstable(bool mode, __be16 _a, __be16 _b)
2302{
2303 s16 a = be16_to_cpu(_a);
2304 s16 b = be16_to_cpu(_b);
2305
2306 if (!mode) {
2307 return abs(a) >= 4096;
2308 } else {
2309 if (abs(b) >= 4096)
2310 return true;
2311
2312 return (abs((a << 16) / (4096 - b)) >= 4096 << 4);
2313 }
2314}
2315
2316int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol,
2317 struct snd_ctl_elem_value *ucontrol)
2318{
2319 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
2320 struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
2321 struct soc_bytes *params = (void *)kcontrol->private_value;
2322 unsigned int val;
2323 __be16 *data;
2324 int len;
2325 int ret;
2326
2327 len = params->num_regs * regmap_get_val_bytes(arizona->regmap);
2328
2329 data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA);
2330 if (!data)
2331 return -ENOMEM;
2332
2333 data[0] &= cpu_to_be16(ARIZONA_EQ1_B1_MODE);
2334
2335 if (arizona_eq_filter_unstable(!!data[0], data[1], data[2]) ||
2336 arizona_eq_filter_unstable(true, data[4], data[5]) ||
2337 arizona_eq_filter_unstable(true, data[8], data[9]) ||
2338 arizona_eq_filter_unstable(true, data[12], data[13]) ||
2339 arizona_eq_filter_unstable(false, data[16], data[17])) {
2340 dev_err(arizona->dev, "Rejecting unstable EQ coefficients\n");
2341 ret = -EINVAL;
2342 goto out;
2343 }
2344
2345 ret = regmap_read(arizona->regmap, params->base, &val);
2346 if (ret != 0)
2347 goto out;
2348
2349 val &= ~ARIZONA_EQ1_B1_MODE;
2350 data[0] |= cpu_to_be16(val);
2351
2352 ret = regmap_raw_write(arizona->regmap, params->base, data, len);
2353
2354out:
2355 kfree(data);
2356 return ret;
2357}
2358EXPORT_SYMBOL_GPL(arizona_eq_coeff_put);
2359
Charles Keepax5f8e6712015-06-25 09:35:12 +01002360int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
2361 struct snd_ctl_elem_value *ucontrol)
2362{
2363 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
2364 struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
2365 __be16 *data = (__be16 *)ucontrol->value.bytes.data;
2366 s16 val = be16_to_cpu(*data);
2367
2368 if (abs(val) >= 4096) {
2369 dev_err(arizona->dev, "Rejecting unstable LHPF coefficients\n");
2370 return -EINVAL;
2371 }
2372
2373 return snd_soc_bytes_put(kcontrol, ucontrol);
2374}
2375EXPORT_SYMBOL_GPL(arizona_lhpf_coeff_put);
2376
Mark Brown07ed8732012-06-18 21:08:44 +01002377MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
2378MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
2379MODULE_LICENSE("GPL");