blob: ac21b85ff75ffb7b3305d8200c8c6a38ed3896bf [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",
319 "Mic Mute Mixer",
320 "Noise Generator",
321 "IN1L",
322 "IN1R",
323 "IN2L",
324 "IN2R",
325 "IN3L",
326 "IN3R",
Mark Brownc9c56fd2012-07-09 19:09:01 +0100327 "IN4L",
328 "IN4R",
Mark Brown07ed8732012-06-18 21:08:44 +0100329 "AIF1RX1",
330 "AIF1RX2",
331 "AIF1RX3",
332 "AIF1RX4",
333 "AIF1RX5",
334 "AIF1RX6",
335 "AIF1RX7",
336 "AIF1RX8",
337 "AIF2RX1",
338 "AIF2RX2",
Richard Fitzgeralde64001e2013-11-20 13:17:07 +0000339 "AIF2RX3",
340 "AIF2RX4",
341 "AIF2RX5",
342 "AIF2RX6",
Mark Brown07ed8732012-06-18 21:08:44 +0100343 "AIF3RX1",
344 "AIF3RX2",
345 "SLIMRX1",
346 "SLIMRX2",
347 "SLIMRX3",
348 "SLIMRX4",
349 "SLIMRX5",
350 "SLIMRX6",
351 "SLIMRX7",
352 "SLIMRX8",
353 "EQ1",
354 "EQ2",
355 "EQ3",
356 "EQ4",
357 "DRC1L",
358 "DRC1R",
359 "DRC2L",
360 "DRC2R",
361 "LHPF1",
362 "LHPF2",
363 "LHPF3",
364 "LHPF4",
365 "DSP1.1",
366 "DSP1.2",
367 "DSP1.3",
368 "DSP1.4",
369 "DSP1.5",
370 "DSP1.6",
Mark Brownc922cc42012-09-26 16:43:44 +0100371 "DSP2.1",
372 "DSP2.2",
373 "DSP2.3",
374 "DSP2.4",
375 "DSP2.5",
376 "DSP2.6",
377 "DSP3.1",
378 "DSP3.2",
379 "DSP3.3",
380 "DSP3.4",
381 "DSP3.5",
382 "DSP3.6",
383 "DSP4.1",
384 "DSP4.2",
385 "DSP4.3",
386 "DSP4.4",
387 "DSP4.5",
388 "DSP4.6",
Mark Brown07ed8732012-06-18 21:08:44 +0100389 "ASRC1L",
390 "ASRC1R",
391 "ASRC2L",
392 "ASRC2R",
Mark Brown91660bd2012-12-05 20:35:24 +0900393 "ISRC1INT1",
394 "ISRC1INT2",
395 "ISRC1INT3",
396 "ISRC1INT4",
397 "ISRC1DEC1",
398 "ISRC1DEC2",
399 "ISRC1DEC3",
400 "ISRC1DEC4",
401 "ISRC2INT1",
402 "ISRC2INT2",
403 "ISRC2INT3",
404 "ISRC2INT4",
405 "ISRC2DEC1",
406 "ISRC2DEC2",
407 "ISRC2DEC3",
408 "ISRC2DEC4",
409 "ISRC3INT1",
410 "ISRC3INT2",
411 "ISRC3INT3",
412 "ISRC3INT4",
413 "ISRC3DEC1",
414 "ISRC3DEC2",
415 "ISRC3DEC3",
416 "ISRC3DEC4",
Mark Brown07ed8732012-06-18 21:08:44 +0100417};
418EXPORT_SYMBOL_GPL(arizona_mixer_texts);
419
420int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
421 0x00, /* None */
422 0x04, /* Tone */
423 0x05,
424 0x06, /* Haptics */
425 0x08, /* AEC */
426 0x0c, /* Noise mixer */
427 0x0d, /* Comfort noise */
428 0x10, /* IN1L */
429 0x11,
430 0x12,
431 0x13,
432 0x14,
433 0x15,
Mark Brownc9c56fd2012-07-09 19:09:01 +0100434 0x16,
435 0x17,
Mark Brown07ed8732012-06-18 21:08:44 +0100436 0x20, /* AIF1RX1 */
437 0x21,
438 0x22,
439 0x23,
440 0x24,
441 0x25,
442 0x26,
443 0x27,
444 0x28, /* AIF2RX1 */
445 0x29,
Richard Fitzgeralde64001e2013-11-20 13:17:07 +0000446 0x2a,
447 0x2b,
448 0x2c,
449 0x2d,
Mark Brown07ed8732012-06-18 21:08:44 +0100450 0x30, /* AIF3RX1 */
451 0x31,
452 0x38, /* SLIMRX1 */
453 0x39,
454 0x3a,
455 0x3b,
456 0x3c,
457 0x3d,
458 0x3e,
459 0x3f,
460 0x50, /* EQ1 */
461 0x51,
462 0x52,
463 0x53,
464 0x58, /* DRC1L */
465 0x59,
466 0x5a,
467 0x5b,
468 0x60, /* LHPF1 */
469 0x61,
470 0x62,
471 0x63,
472 0x68, /* DSP1.1 */
473 0x69,
474 0x6a,
475 0x6b,
476 0x6c,
477 0x6d,
Mark Brownc922cc42012-09-26 16:43:44 +0100478 0x70, /* DSP2.1 */
479 0x71,
480 0x72,
481 0x73,
482 0x74,
483 0x75,
484 0x78, /* DSP3.1 */
485 0x79,
486 0x7a,
487 0x7b,
488 0x7c,
489 0x7d,
490 0x80, /* DSP4.1 */
491 0x81,
492 0x82,
493 0x83,
494 0x84,
495 0x85,
Mark Brown07ed8732012-06-18 21:08:44 +0100496 0x90, /* ASRC1L */
497 0x91,
498 0x92,
499 0x93,
Mark Brown91660bd2012-12-05 20:35:24 +0900500 0xa0, /* ISRC1INT1 */
501 0xa1,
502 0xa2,
503 0xa3,
504 0xa4, /* ISRC1DEC1 */
505 0xa5,
506 0xa6,
507 0xa7,
508 0xa8, /* ISRC2DEC1 */
509 0xa9,
510 0xaa,
511 0xab,
512 0xac, /* ISRC2INT1 */
513 0xad,
514 0xae,
515 0xaf,
516 0xb0, /* ISRC3DEC1 */
517 0xb1,
518 0xb2,
519 0xb3,
520 0xb4, /* ISRC3INT1 */
521 0xb5,
522 0xb6,
523 0xb7,
Mark Brown07ed8732012-06-18 21:08:44 +0100524};
525EXPORT_SYMBOL_GPL(arizona_mixer_values);
526
527const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
528EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
529
Mark Browndc914282013-02-18 19:09:23 +0000530const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = {
531 "SYNCCLK rate", "8kHz", "16kHz", "ASYNCCLK rate",
532};
533EXPORT_SYMBOL_GPL(arizona_rate_text);
534
535const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
536 0, 1, 2, 8,
537};
538EXPORT_SYMBOL_GPL(arizona_rate_val);
539
540
Charles Keepaxfbedc8c2013-12-19 09:30:12 +0000541const struct soc_enum arizona_isrc_fsh[] = {
542 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_1,
543 ARIZONA_ISRC1_FSH_SHIFT, 0xf,
544 ARIZONA_RATE_ENUM_SIZE,
545 arizona_rate_text, arizona_rate_val),
546 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_1,
547 ARIZONA_ISRC2_FSH_SHIFT, 0xf,
548 ARIZONA_RATE_ENUM_SIZE,
549 arizona_rate_text, arizona_rate_val),
550 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_1,
551 ARIZONA_ISRC3_FSH_SHIFT, 0xf,
552 ARIZONA_RATE_ENUM_SIZE,
553 arizona_rate_text, arizona_rate_val),
554};
555EXPORT_SYMBOL_GPL(arizona_isrc_fsh);
556
Mark Browndc914282013-02-18 19:09:23 +0000557const struct soc_enum arizona_isrc_fsl[] = {
558 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2,
559 ARIZONA_ISRC1_FSL_SHIFT, 0xf,
560 ARIZONA_RATE_ENUM_SIZE,
561 arizona_rate_text, arizona_rate_val),
562 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_2,
563 ARIZONA_ISRC2_FSL_SHIFT, 0xf,
564 ARIZONA_RATE_ENUM_SIZE,
565 arizona_rate_text, arizona_rate_val),
566 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_2,
567 ARIZONA_ISRC3_FSL_SHIFT, 0xf,
568 ARIZONA_RATE_ENUM_SIZE,
569 arizona_rate_text, arizona_rate_val),
570};
571EXPORT_SYMBOL_GPL(arizona_isrc_fsl);
572
Charles Keepax56d37d82013-12-19 09:30:13 +0000573const struct soc_enum arizona_asrc_rate1 =
574 SOC_VALUE_ENUM_SINGLE(ARIZONA_ASRC_RATE1,
575 ARIZONA_ASRC_RATE1_SHIFT, 0xf,
576 ARIZONA_RATE_ENUM_SIZE - 1,
577 arizona_rate_text, arizona_rate_val);
578EXPORT_SYMBOL_GPL(arizona_asrc_rate1);
579
Mark Browne853a002012-12-09 12:25:52 +0900580static const char *arizona_vol_ramp_text[] = {
581 "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
582 "15ms/6dB", "30ms/6dB",
583};
584
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100585SOC_ENUM_SINGLE_DECL(arizona_in_vd_ramp,
586 ARIZONA_INPUT_VOLUME_RAMP,
587 ARIZONA_IN_VD_RAMP_SHIFT,
588 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900589EXPORT_SYMBOL_GPL(arizona_in_vd_ramp);
590
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100591SOC_ENUM_SINGLE_DECL(arizona_in_vi_ramp,
592 ARIZONA_INPUT_VOLUME_RAMP,
593 ARIZONA_IN_VI_RAMP_SHIFT,
594 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900595EXPORT_SYMBOL_GPL(arizona_in_vi_ramp);
596
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100597SOC_ENUM_SINGLE_DECL(arizona_out_vd_ramp,
598 ARIZONA_OUTPUT_VOLUME_RAMP,
599 ARIZONA_OUT_VD_RAMP_SHIFT,
600 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900601EXPORT_SYMBOL_GPL(arizona_out_vd_ramp);
602
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100603SOC_ENUM_SINGLE_DECL(arizona_out_vi_ramp,
604 ARIZONA_OUTPUT_VOLUME_RAMP,
605 ARIZONA_OUT_VI_RAMP_SHIFT,
606 arizona_vol_ramp_text);
Mark Browne853a002012-12-09 12:25:52 +0900607EXPORT_SYMBOL_GPL(arizona_out_vi_ramp);
608
Mark Brown07ed8732012-06-18 21:08:44 +0100609static const char *arizona_lhpf_mode_text[] = {
610 "Low-pass", "High-pass"
611};
612
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100613SOC_ENUM_SINGLE_DECL(arizona_lhpf1_mode,
614 ARIZONA_HPLPF1_1,
615 ARIZONA_LHPF1_MODE_SHIFT,
616 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100617EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
618
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100619SOC_ENUM_SINGLE_DECL(arizona_lhpf2_mode,
620 ARIZONA_HPLPF2_1,
621 ARIZONA_LHPF2_MODE_SHIFT,
622 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100623EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
624
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100625SOC_ENUM_SINGLE_DECL(arizona_lhpf3_mode,
626 ARIZONA_HPLPF3_1,
627 ARIZONA_LHPF3_MODE_SHIFT,
628 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100629EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
630
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100631SOC_ENUM_SINGLE_DECL(arizona_lhpf4_mode,
632 ARIZONA_HPLPF4_1,
633 ARIZONA_LHPF4_MODE_SHIFT,
634 arizona_lhpf_mode_text);
Mark Brown07ed8732012-06-18 21:08:44 +0100635EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
636
Mark Brown845571c2012-12-18 13:47:57 +0000637static const char *arizona_ng_hold_text[] = {
638 "30ms", "120ms", "250ms", "500ms",
639};
640
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100641SOC_ENUM_SINGLE_DECL(arizona_ng_hold,
642 ARIZONA_NOISE_GATE_CONTROL,
643 ARIZONA_NGATE_HOLD_SHIFT,
644 arizona_ng_hold_text);
Mark Brown845571c2012-12-18 13:47:57 +0000645EXPORT_SYMBOL_GPL(arizona_ng_hold);
646
Charles Keepax254dc322013-11-19 16:04:03 +0000647static const char * const arizona_in_hpf_cut_text[] = {
648 "2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz"
649};
650
Takashi Iwai27ca2c32014-02-18 10:01:43 +0100651SOC_ENUM_SINGLE_DECL(arizona_in_hpf_cut_enum,
652 ARIZONA_HPF_CONTROL,
653 ARIZONA_IN_HPF_CUT_SHIFT,
654 arizona_in_hpf_cut_text);
Charles Keepax254dc322013-11-19 16:04:03 +0000655EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum);
656
Charles Keepaxc7f38432013-08-06 17:03:55 +0100657static const char * const arizona_in_dmic_osr_text[] = {
Charles Keepaxef326f42014-11-12 14:55:26 +0000658 "1.536MHz", "3.072MHz", "6.144MHz", "768kHz",
Charles Keepaxc7f38432013-08-06 17:03:55 +0100659};
660
661const struct soc_enum arizona_in_dmic_osr[] = {
662 SOC_ENUM_SINGLE(ARIZONA_IN1L_CONTROL, ARIZONA_IN1_OSR_SHIFT,
663 ARRAY_SIZE(arizona_in_dmic_osr_text),
664 arizona_in_dmic_osr_text),
665 SOC_ENUM_SINGLE(ARIZONA_IN2L_CONTROL, ARIZONA_IN2_OSR_SHIFT,
666 ARRAY_SIZE(arizona_in_dmic_osr_text),
667 arizona_in_dmic_osr_text),
668 SOC_ENUM_SINGLE(ARIZONA_IN3L_CONTROL, ARIZONA_IN3_OSR_SHIFT,
669 ARRAY_SIZE(arizona_in_dmic_osr_text),
670 arizona_in_dmic_osr_text),
671 SOC_ENUM_SINGLE(ARIZONA_IN4L_CONTROL, ARIZONA_IN4_OSR_SHIFT,
672 ARRAY_SIZE(arizona_in_dmic_osr_text),
673 arizona_in_dmic_osr_text),
674};
675EXPORT_SYMBOL_GPL(arizona_in_dmic_osr);
676
Mark Brownddbce972013-02-15 17:27:22 +0000677static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
678{
679 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
680 unsigned int val;
681 int i;
682
683 if (ena)
684 val = ARIZONA_IN_VU;
685 else
686 val = 0;
687
688 for (i = 0; i < priv->num_inputs; i++)
689 snd_soc_update_bits(codec,
690 ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 4),
691 ARIZONA_IN_VU, val);
692}
693
Charles Keepax002b0832015-09-16 13:59:41 +0100694bool arizona_input_analog(struct snd_soc_codec *codec, int shift)
695{
696 unsigned int reg = ARIZONA_IN1L_CONTROL + ((shift / 2) * 8);
697 unsigned int val = snd_soc_read(codec, reg);
698
699 return !(val & ARIZONA_IN1_MODE_MASK);
700}
701EXPORT_SYMBOL_GPL(arizona_input_analog);
702
Mark Brown07ed8732012-06-18 21:08:44 +0100703int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
704 int event)
705{
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100706 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
707 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000708 unsigned int reg;
709
710 if (w->shift % 2)
711 reg = ARIZONA_ADC_DIGITAL_VOLUME_1L + ((w->shift / 2) * 8);
712 else
713 reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8);
714
715 switch (event) {
Mark Brownddbce972013-02-15 17:27:22 +0000716 case SND_SOC_DAPM_PRE_PMU:
717 priv->in_pending++;
718 break;
Mark Brown43cd8bf2013-02-06 16:57:29 +0000719 case SND_SOC_DAPM_POST_PMU:
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100720 snd_soc_update_bits(codec, reg, ARIZONA_IN1L_MUTE, 0);
Mark Brownddbce972013-02-15 17:27:22 +0000721
722 /* If this is the last input pending then allow VU */
723 priv->in_pending--;
724 if (priv->in_pending == 0) {
725 msleep(1);
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100726 arizona_in_set_vu(codec, 1);
Mark Brownddbce972013-02-15 17:27:22 +0000727 }
Mark Brown43cd8bf2013-02-06 16:57:29 +0000728 break;
729 case SND_SOC_DAPM_PRE_PMD:
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100730 snd_soc_update_bits(codec, reg,
Mark Brownddbce972013-02-15 17:27:22 +0000731 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU,
732 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000733 break;
Mark Brownddbce972013-02-15 17:27:22 +0000734 case SND_SOC_DAPM_POST_PMD:
735 /* Disable volume updates if no inputs are enabled */
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100736 reg = snd_soc_read(codec, ARIZONA_INPUT_ENABLES);
Mark Brownddbce972013-02-15 17:27:22 +0000737 if (reg == 0)
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100738 arizona_in_set_vu(codec, 0);
Charles Keepaxbee261b2015-09-16 13:59:40 +0100739 break;
740 default:
741 break;
Mark Brown43cd8bf2013-02-06 16:57:29 +0000742 }
743
Mark Brown07ed8732012-06-18 21:08:44 +0100744 return 0;
745}
746EXPORT_SYMBOL_GPL(arizona_in_ev);
747
748int arizona_out_ev(struct snd_soc_dapm_widget *w,
749 struct snd_kcontrol *kcontrol,
750 int event)
751{
Mark Brown60d66c92015-01-27 23:50:47 +0000752 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
753 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Charles Keepax054e1b42015-01-20 16:31:50 +0000754
Mark Brown1a2c7d52013-03-24 22:50:23 +0000755 switch (event) {
Charles Keepaxe1ae5fb2015-01-20 16:31:51 +0000756 case SND_SOC_DAPM_PRE_PMU:
757 switch (w->shift) {
758 case ARIZONA_OUT1L_ENA_SHIFT:
759 case ARIZONA_OUT1R_ENA_SHIFT:
760 case ARIZONA_OUT2L_ENA_SHIFT:
761 case ARIZONA_OUT2R_ENA_SHIFT:
762 case ARIZONA_OUT3L_ENA_SHIFT:
763 case ARIZONA_OUT3R_ENA_SHIFT:
764 priv->out_up_pending++;
765 priv->out_up_delay += 17;
766 break;
767 default:
768 break;
769 }
770 break;
Mark Brown1a2c7d52013-03-24 22:50:23 +0000771 case SND_SOC_DAPM_POST_PMU:
772 switch (w->shift) {
773 case ARIZONA_OUT1L_ENA_SHIFT:
774 case ARIZONA_OUT1R_ENA_SHIFT:
775 case ARIZONA_OUT2L_ENA_SHIFT:
776 case ARIZONA_OUT2R_ENA_SHIFT:
777 case ARIZONA_OUT3L_ENA_SHIFT:
778 case ARIZONA_OUT3R_ENA_SHIFT:
Charles Keepaxe1ae5fb2015-01-20 16:31:51 +0000779 priv->out_up_pending--;
780 if (!priv->out_up_pending) {
781 msleep(priv->out_up_delay);
782 priv->out_up_delay = 0;
783 }
Mark Brown1a2c7d52013-03-24 22:50:23 +0000784 break;
785
786 default:
787 break;
788 }
789 break;
Charles Keepax054e1b42015-01-20 16:31:50 +0000790 case SND_SOC_DAPM_PRE_PMD:
791 switch (w->shift) {
792 case ARIZONA_OUT1L_ENA_SHIFT:
793 case ARIZONA_OUT1R_ENA_SHIFT:
794 case ARIZONA_OUT2L_ENA_SHIFT:
795 case ARIZONA_OUT2R_ENA_SHIFT:
796 case ARIZONA_OUT3L_ENA_SHIFT:
797 case ARIZONA_OUT3R_ENA_SHIFT:
798 priv->out_down_pending++;
799 priv->out_down_delay++;
800 break;
801 default:
802 break;
803 }
804 break;
805 case SND_SOC_DAPM_POST_PMD:
806 switch (w->shift) {
807 case ARIZONA_OUT1L_ENA_SHIFT:
808 case ARIZONA_OUT1R_ENA_SHIFT:
809 case ARIZONA_OUT2L_ENA_SHIFT:
810 case ARIZONA_OUT2R_ENA_SHIFT:
811 case ARIZONA_OUT3L_ENA_SHIFT:
812 case ARIZONA_OUT3R_ENA_SHIFT:
813 priv->out_down_pending--;
814 if (!priv->out_down_pending) {
815 msleep(priv->out_down_delay);
816 priv->out_down_delay = 0;
817 }
818 break;
819 default:
820 break;
821 }
822 break;
Charles Keepaxbee261b2015-09-16 13:59:40 +0100823 default:
824 break;
Mark Brown1a2c7d52013-03-24 22:50:23 +0000825 }
826
Mark Brown07ed8732012-06-18 21:08:44 +0100827 return 0;
828}
829EXPORT_SYMBOL_GPL(arizona_out_ev);
830
Mark Brownf607e312013-02-22 18:36:53 +0000831int arizona_hp_ev(struct snd_soc_dapm_widget *w,
832 struct snd_kcontrol *kcontrol,
833 int event)
834{
Lars-Peter Clausen043123f2015-01-13 10:27:07 +0100835 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
836 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brown3c43c692013-12-12 00:49:22 +0000837 struct arizona *arizona = priv->arizona;
Mark Brownf607e312013-02-22 18:36:53 +0000838 unsigned int mask = 1 << w->shift;
839 unsigned int val;
840
841 switch (event) {
842 case SND_SOC_DAPM_POST_PMU:
843 val = mask;
844 break;
845 case SND_SOC_DAPM_PRE_PMD:
846 val = 0;
847 break;
Charles Keepaxe1ae5fb2015-01-20 16:31:51 +0000848 case SND_SOC_DAPM_PRE_PMU:
Charles Keepax054e1b42015-01-20 16:31:50 +0000849 case SND_SOC_DAPM_POST_PMD:
850 return arizona_out_ev(w, kcontrol, event);
Mark Brownf607e312013-02-22 18:36:53 +0000851 default:
852 return -EINVAL;
853 }
854
855 /* Store the desired state for the HP outputs */
856 priv->arizona->hp_ena &= ~mask;
857 priv->arizona->hp_ena |= val;
858
Charles Keepax112bdfa2015-02-16 15:41:02 +0000859 /* Force off if HPDET clamp is active */
860 if (priv->arizona->hpdet_clamp)
Mark Brownf607e312013-02-22 18:36:53 +0000861 val = 0;
862
Mark Brown3c43c692013-12-12 00:49:22 +0000863 regmap_update_bits_async(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1,
864 mask, val);
Mark Brownf607e312013-02-22 18:36:53 +0000865
866 return arizona_out_ev(w, kcontrol, event);
867}
868EXPORT_SYMBOL_GPL(arizona_hp_ev);
869
Richard Fitzgerald346d9682015-06-02 11:53:33 +0100870static int arizona_dvfs_enable(struct snd_soc_codec *codec)
871{
872 const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
873 struct arizona *arizona = priv->arizona;
874 int ret;
875
876 ret = regulator_set_voltage(arizona->dcvdd, 1800000, 1800000);
877 if (ret) {
878 dev_err(codec->dev, "Failed to boost DCVDD: %d\n", ret);
879 return ret;
880 }
881
882 ret = regmap_update_bits(arizona->regmap,
883 ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
884 ARIZONA_SUBSYS_MAX_FREQ,
885 ARIZONA_SUBSYS_MAX_FREQ);
886 if (ret) {
887 dev_err(codec->dev, "Failed to enable subsys max: %d\n", ret);
888 regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
889 return ret;
890 }
891
892 return 0;
893}
894
895static int arizona_dvfs_disable(struct snd_soc_codec *codec)
896{
897 const struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
898 struct arizona *arizona = priv->arizona;
899 int ret;
900
901 ret = regmap_update_bits(arizona->regmap,
902 ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
903 ARIZONA_SUBSYS_MAX_FREQ, 0);
904 if (ret) {
905 dev_err(codec->dev, "Failed to disable subsys max: %d\n", ret);
906 return ret;
907 }
908
909 ret = regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
910 if (ret) {
911 dev_err(codec->dev, "Failed to unboost DCVDD: %d\n", ret);
912 return ret;
913 }
914
915 return 0;
916}
917
918int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags)
919{
920 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
921 int ret = 0;
922
923 mutex_lock(&priv->dvfs_lock);
924
925 if (!priv->dvfs_cached && !priv->dvfs_reqs) {
926 ret = arizona_dvfs_enable(codec);
927 if (ret)
928 goto err;
929 }
930
931 priv->dvfs_reqs |= flags;
932err:
933 mutex_unlock(&priv->dvfs_lock);
934 return ret;
935}
936EXPORT_SYMBOL_GPL(arizona_dvfs_up);
937
938int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags)
939{
940 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
941 unsigned int old_reqs;
942 int ret = 0;
943
944 mutex_lock(&priv->dvfs_lock);
945
946 old_reqs = priv->dvfs_reqs;
947 priv->dvfs_reqs &= ~flags;
948
949 if (!priv->dvfs_cached && old_reqs && !priv->dvfs_reqs)
950 ret = arizona_dvfs_disable(codec);
951
952 mutex_unlock(&priv->dvfs_lock);
953 return ret;
954}
955EXPORT_SYMBOL_GPL(arizona_dvfs_down);
956
957int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
958 struct snd_kcontrol *kcontrol, int event)
959{
960 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
961 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
962 int ret = 0;
963
964 mutex_lock(&priv->dvfs_lock);
965
966 switch (event) {
967 case SND_SOC_DAPM_POST_PMU:
968 if (priv->dvfs_reqs)
969 ret = arizona_dvfs_enable(codec);
970
971 priv->dvfs_cached = false;
972 break;
973 case SND_SOC_DAPM_PRE_PMD:
974 /* We must ensure DVFS is disabled before the codec goes into
975 * suspend so that we are never in an illegal state of DVFS
976 * enabled without enough DCVDD
977 */
978 priv->dvfs_cached = true;
979
980 if (priv->dvfs_reqs)
981 ret = arizona_dvfs_disable(codec);
982 break;
983 default:
984 break;
985 }
986
987 mutex_unlock(&priv->dvfs_lock);
988 return ret;
989}
990EXPORT_SYMBOL_GPL(arizona_dvfs_sysclk_ev);
991
992void arizona_init_dvfs(struct arizona_priv *priv)
993{
994 mutex_init(&priv->dvfs_lock);
995}
996EXPORT_SYMBOL_GPL(arizona_init_dvfs);
997
Mark Browncbd840d2012-08-08 17:52:44 +0100998static unsigned int arizona_sysclk_48k_rates[] = {
999 6144000,
1000 12288000,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +00001001 24576000,
Mark Browncbd840d2012-08-08 17:52:44 +01001002 49152000,
Mark Brownaeaeee12012-09-26 17:50:02 +01001003 73728000,
1004 98304000,
1005 147456000,
Mark Browncbd840d2012-08-08 17:52:44 +01001006};
1007
1008static unsigned int arizona_sysclk_44k1_rates[] = {
1009 5644800,
1010 11289600,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +00001011 22579200,
Mark Browncbd840d2012-08-08 17:52:44 +01001012 45158400,
Mark Brownaeaeee12012-09-26 17:50:02 +01001013 67737600,
1014 90316800,
1015 135475200,
Mark Browncbd840d2012-08-08 17:52:44 +01001016};
1017
1018static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
1019 unsigned int freq)
1020{
1021 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1022 unsigned int reg;
1023 unsigned int *rates;
1024 int ref, div, refclk;
1025
1026 switch (clk) {
1027 case ARIZONA_CLK_OPCLK:
1028 reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
1029 refclk = priv->sysclk;
1030 break;
1031 case ARIZONA_CLK_ASYNC_OPCLK:
1032 reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
1033 refclk = priv->asyncclk;
1034 break;
1035 default:
1036 return -EINVAL;
1037 }
1038
1039 if (refclk % 8000)
1040 rates = arizona_sysclk_44k1_rates;
1041 else
1042 rates = arizona_sysclk_48k_rates;
1043
1044 for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) &&
1045 rates[ref] <= refclk; ref++) {
1046 div = 1;
1047 while (rates[ref] / div >= freq && div < 32) {
1048 if (rates[ref] / div == freq) {
1049 dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
1050 freq);
1051 snd_soc_update_bits(codec, reg,
1052 ARIZONA_OPCLK_DIV_MASK |
1053 ARIZONA_OPCLK_SEL_MASK,
1054 (div <<
1055 ARIZONA_OPCLK_DIV_SHIFT) |
1056 ref);
1057 return 0;
1058 }
1059 div++;
1060 }
1061 }
1062
1063 dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
1064 return -EINVAL;
1065}
1066
Mark Brown07ed8732012-06-18 21:08:44 +01001067int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
1068 int source, unsigned int freq, int dir)
1069{
1070 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1071 struct arizona *arizona = priv->arizona;
1072 char *name;
1073 unsigned int reg;
1074 unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
1075 unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
1076 unsigned int *clk;
1077
1078 switch (clk_id) {
1079 case ARIZONA_CLK_SYSCLK:
1080 name = "SYSCLK";
1081 reg = ARIZONA_SYSTEM_CLOCK_1;
1082 clk = &priv->sysclk;
1083 mask |= ARIZONA_SYSCLK_FRAC;
1084 break;
1085 case ARIZONA_CLK_ASYNCCLK:
1086 name = "ASYNCCLK";
1087 reg = ARIZONA_ASYNC_CLOCK_1;
1088 clk = &priv->asyncclk;
1089 break;
Mark Browncbd840d2012-08-08 17:52:44 +01001090 case ARIZONA_CLK_OPCLK:
1091 case ARIZONA_CLK_ASYNC_OPCLK:
1092 return arizona_set_opclk(codec, clk_id, freq);
Mark Brown07ed8732012-06-18 21:08:44 +01001093 default:
1094 return -EINVAL;
1095 }
1096
1097 switch (freq) {
1098 case 5644800:
1099 case 6144000:
1100 break;
1101 case 11289600:
1102 case 12288000:
Mark Brown3f341f72013-03-08 15:22:29 +08001103 val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +01001104 break;
1105 case 22579200:
1106 case 24576000:
Mark Brown3f341f72013-03-08 15:22:29 +08001107 val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +01001108 break;
1109 case 45158400:
1110 case 49152000:
Mark Brown3f341f72013-03-08 15:22:29 +08001111 val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +01001112 break;
Mark Brown38113362012-11-26 16:01:37 +00001113 case 67737600:
1114 case 73728000:
Mark Brown3f341f72013-03-08 15:22:29 +08001115 val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +00001116 break;
1117 case 90316800:
1118 case 98304000:
Mark Brown3f341f72013-03-08 15:22:29 +08001119 val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +00001120 break;
1121 case 135475200:
1122 case 147456000:
Mark Brown3f341f72013-03-08 15:22:29 +08001123 val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +00001124 break;
Mark Brownf2c26d42013-01-21 16:09:36 +09001125 case 0:
1126 dev_dbg(arizona->dev, "%s cleared\n", name);
1127 *clk = freq;
1128 return 0;
Mark Brown07ed8732012-06-18 21:08:44 +01001129 default:
1130 return -EINVAL;
1131 }
1132
1133 *clk = freq;
1134
1135 if (freq % 6144000)
1136 val |= ARIZONA_SYSCLK_FRAC;
1137
1138 dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
1139
1140 return regmap_update_bits(arizona->regmap, reg, mask, val);
1141}
1142EXPORT_SYMBOL_GPL(arizona_set_sysclk);
1143
1144static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
1145{
1146 struct snd_soc_codec *codec = dai->codec;
Mark Brown3c43c692013-12-12 00:49:22 +00001147 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1148 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +01001149 int lrclk, bclk, mode, base;
1150
1151 base = dai->driver->base;
1152
1153 lrclk = 0;
1154 bclk = 0;
1155
1156 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
1157 case SND_SOC_DAIFMT_DSP_A:
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001158 mode = ARIZONA_FMT_DSP_MODE_A;
1159 break;
1160 case SND_SOC_DAIFMT_DSP_B:
1161 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
1162 != SND_SOC_DAIFMT_CBM_CFM) {
1163 arizona_aif_err(dai, "DSP_B not valid in slave mode\n");
1164 return -EINVAL;
1165 }
1166 mode = ARIZONA_FMT_DSP_MODE_B;
Mark Brown07ed8732012-06-18 21:08:44 +01001167 break;
Mark Brown07ed8732012-06-18 21:08:44 +01001168 case SND_SOC_DAIFMT_I2S:
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001169 mode = ARIZONA_FMT_I2S_MODE;
1170 break;
1171 case SND_SOC_DAIFMT_LEFT_J:
1172 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
1173 != SND_SOC_DAIFMT_CBM_CFM) {
1174 arizona_aif_err(dai, "LEFT_J not valid in slave mode\n");
1175 return -EINVAL;
1176 }
1177 mode = ARIZONA_FMT_LEFT_JUSTIFIED_MODE;
Mark Brown07ed8732012-06-18 21:08:44 +01001178 break;
Mark Brown07ed8732012-06-18 21:08:44 +01001179 default:
1180 arizona_aif_err(dai, "Unsupported DAI format %d\n",
1181 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
1182 return -EINVAL;
1183 }
1184
1185 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
1186 case SND_SOC_DAIFMT_CBS_CFS:
1187 break;
1188 case SND_SOC_DAIFMT_CBS_CFM:
1189 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
1190 break;
1191 case SND_SOC_DAIFMT_CBM_CFS:
1192 bclk |= ARIZONA_AIF1_BCLK_MSTR;
1193 break;
1194 case SND_SOC_DAIFMT_CBM_CFM:
1195 bclk |= ARIZONA_AIF1_BCLK_MSTR;
1196 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
1197 break;
1198 default:
1199 arizona_aif_err(dai, "Unsupported master mode %d\n",
1200 fmt & SND_SOC_DAIFMT_MASTER_MASK);
1201 return -EINVAL;
1202 }
1203
1204 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1205 case SND_SOC_DAIFMT_NB_NF:
1206 break;
1207 case SND_SOC_DAIFMT_IB_IF:
1208 bclk |= ARIZONA_AIF1_BCLK_INV;
1209 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
1210 break;
1211 case SND_SOC_DAIFMT_IB_NF:
1212 bclk |= ARIZONA_AIF1_BCLK_INV;
1213 break;
1214 case SND_SOC_DAIFMT_NB_IF:
1215 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
1216 break;
1217 default:
1218 return -EINVAL;
1219 }
1220
Mark Brown3c43c692013-12-12 00:49:22 +00001221 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_BCLK_CTRL,
1222 ARIZONA_AIF1_BCLK_INV |
1223 ARIZONA_AIF1_BCLK_MSTR,
1224 bclk);
1225 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_TX_PIN_CTRL,
1226 ARIZONA_AIF1TX_LRCLK_INV |
1227 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
1228 regmap_update_bits_async(arizona->regmap,
1229 base + ARIZONA_AIF_RX_PIN_CTRL,
1230 ARIZONA_AIF1RX_LRCLK_INV |
1231 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
1232 regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FORMAT,
1233 ARIZONA_AIF1_FMT_MASK, mode);
Mark Brown07ed8732012-06-18 21:08:44 +01001234
1235 return 0;
1236}
1237
Mark Brown949e6bc2012-07-04 18:58:04 +01001238static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001239 -1,
1240 48000,
1241 64000,
1242 96000,
1243 128000,
1244 192000,
1245 256000,
1246 384000,
1247 512000,
1248 768000,
1249 1024000,
1250 1536000,
1251 2048000,
1252 3072000,
1253 4096000,
1254 6144000,
1255 8192000,
1256 12288000,
1257 24576000,
1258};
1259
Mark Brown5b2eec32012-07-04 17:32:05 +01001260static const unsigned int arizona_48k_rates[] = {
1261 12000,
1262 24000,
1263 48000,
1264 96000,
1265 192000,
1266 384000,
1267 768000,
1268 4000,
1269 8000,
1270 16000,
1271 32000,
1272 64000,
1273 128000,
1274 256000,
1275 512000,
1276};
1277
1278static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = {
1279 .count = ARRAY_SIZE(arizona_48k_rates),
1280 .list = arizona_48k_rates,
1281};
1282
Mark Brown949e6bc2012-07-04 18:58:04 +01001283static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001284 -1,
1285 44100,
1286 58800,
1287 88200,
1288 117600,
1289 177640,
1290 235200,
1291 352800,
1292 470400,
1293 705600,
1294 940800,
1295 1411200,
1296 1881600,
Heather Lomond4758be32012-09-05 05:02:10 -04001297 2822400,
Mark Brown07ed8732012-06-18 21:08:44 +01001298 3763200,
1299 5644800,
1300 7526400,
1301 11289600,
1302 22579200,
1303};
1304
Mark Brown5b2eec32012-07-04 17:32:05 +01001305static const unsigned int arizona_44k1_rates[] = {
1306 11025,
1307 22050,
1308 44100,
1309 88200,
1310 176400,
1311 352800,
1312 705600,
1313};
1314
1315static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = {
1316 .count = ARRAY_SIZE(arizona_44k1_rates),
1317 .list = arizona_44k1_rates,
1318};
1319
Mark Brown07ed8732012-06-18 21:08:44 +01001320static int arizona_sr_vals[] = {
1321 0,
1322 12000,
1323 24000,
1324 48000,
1325 96000,
1326 192000,
1327 384000,
1328 768000,
1329 0,
1330 11025,
1331 22050,
1332 44100,
1333 88200,
1334 176400,
1335 352800,
1336 705600,
1337 4000,
1338 8000,
1339 16000,
1340 32000,
1341 64000,
1342 128000,
1343 256000,
1344 512000,
1345};
1346
Mark Brown5b2eec32012-07-04 17:32:05 +01001347static int arizona_startup(struct snd_pcm_substream *substream,
1348 struct snd_soc_dai *dai)
1349{
1350 struct snd_soc_codec *codec = dai->codec;
1351 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1352 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
1353 const struct snd_pcm_hw_constraint_list *constraint;
1354 unsigned int base_rate;
1355
1356 switch (dai_priv->clk) {
1357 case ARIZONA_CLK_SYSCLK:
1358 base_rate = priv->sysclk;
1359 break;
1360 case ARIZONA_CLK_ASYNCCLK:
1361 base_rate = priv->asyncclk;
1362 break;
1363 default:
1364 return 0;
1365 }
1366
Mark Brownf2c26d42013-01-21 16:09:36 +09001367 if (base_rate == 0)
1368 return 0;
1369
Mark Brown5b2eec32012-07-04 17:32:05 +01001370 if (base_rate % 8000)
1371 constraint = &arizona_44k1_constraint;
1372 else
1373 constraint = &arizona_48k_constraint;
1374
1375 return snd_pcm_hw_constraint_list(substream->runtime, 0,
1376 SNDRV_PCM_HW_PARAM_RATE,
1377 constraint);
1378}
1379
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001380static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec,
1381 unsigned int rate)
1382{
1383 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1384 struct arizona *arizona = priv->arizona;
Nariman Poushin8019ff62015-07-16 16:36:21 +01001385 struct reg_sequence dac_comp[] = {
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001386 { 0x80, 0x3 },
1387 { ARIZONA_DAC_COMP_1, 0 },
1388 { ARIZONA_DAC_COMP_2, 0 },
1389 { 0x80, 0x0 },
1390 };
1391
Lars-Peter Clausend74bcaa2014-11-09 17:00:59 +01001392 mutex_lock(&arizona->dac_comp_lock);
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001393
1394 dac_comp[1].def = arizona->dac_comp_coeff;
1395 if (rate >= 176400)
1396 dac_comp[2].def = arizona->dac_comp_enabled;
1397
Lars-Peter Clausend74bcaa2014-11-09 17:00:59 +01001398 mutex_unlock(&arizona->dac_comp_lock);
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001399
1400 regmap_multi_reg_write(arizona->regmap,
1401 dac_comp,
1402 ARRAY_SIZE(dac_comp));
1403}
1404
Mark Brownb272efc2012-10-10 15:10:08 +09001405static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
1406 struct snd_pcm_hw_params *params,
1407 struct snd_soc_dai *dai)
Mark Brown07ed8732012-06-18 21:08:44 +01001408{
1409 struct snd_soc_codec *codec = dai->codec;
Mark Brownc013b272012-07-04 20:05:57 +01001410 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1411 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown07ed8732012-06-18 21:08:44 +01001412 int base = dai->driver->base;
Richard Fitzgerald2c118b42015-06-02 11:53:35 +01001413 int i, sr_val, ret;
Mark Brownb272efc2012-10-10 15:10:08 +09001414
1415 /*
1416 * We will need to be more flexible than this in future,
1417 * currently we use a single sample rate for SYSCLK.
1418 */
1419 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
1420 if (arizona_sr_vals[i] == params_rate(params))
1421 break;
1422 if (i == ARRAY_SIZE(arizona_sr_vals)) {
1423 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1424 params_rate(params));
1425 return -EINVAL;
1426 }
1427 sr_val = i;
1428
Richard Fitzgerald2c118b42015-06-02 11:53:35 +01001429 switch (priv->arizona->type) {
1430 case WM5102:
1431 case WM8997:
1432 if (arizona_sr_vals[sr_val] >= 88200)
1433 ret = arizona_dvfs_up(codec, ARIZONA_DVFS_SR1_RQ);
1434 else
1435 ret = arizona_dvfs_down(codec, ARIZONA_DVFS_SR1_RQ);
1436
1437 if (ret) {
1438 arizona_aif_err(dai, "Failed to change DVFS %d\n", ret);
1439 return ret;
1440 }
1441 break;
1442 default:
1443 break;
1444 }
1445
Mark Brownb272efc2012-10-10 15:10:08 +09001446 switch (dai_priv->clk) {
1447 case ARIZONA_CLK_SYSCLK:
Charles Keepaxcc9e9242014-06-06 14:14:05 +01001448 switch (priv->arizona->type) {
1449 case WM5102:
1450 arizona_wm5102_set_dac_comp(codec,
1451 params_rate(params));
1452 break;
1453 default:
1454 break;
1455 }
1456
Mark Brownb272efc2012-10-10 15:10:08 +09001457 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
1458 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
1459 if (base)
1460 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1461 ARIZONA_AIF1_RATE_MASK, 0);
1462 break;
1463 case ARIZONA_CLK_ASYNCCLK:
1464 snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
Charles Keepaxc24084d2014-09-01 15:48:52 +01001465 ARIZONA_ASYNC_SAMPLE_RATE_1_MASK, sr_val);
Mark Brownb272efc2012-10-10 15:10:08 +09001466 if (base)
1467 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1468 ARIZONA_AIF1_RATE_MASK,
1469 8 << ARIZONA_AIF1_RATE_SHIFT);
1470 break;
1471 default:
1472 arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
1473 return -EINVAL;
1474 }
1475
1476 return 0;
1477}
1478
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001479static bool arizona_aif_cfg_changed(struct snd_soc_codec *codec,
1480 int base, int bclk, int lrclk, int frame)
1481{
1482 int val;
1483
1484 val = snd_soc_read(codec, base + ARIZONA_AIF_BCLK_CTRL);
1485 if (bclk != (val & ARIZONA_AIF1_BCLK_FREQ_MASK))
1486 return true;
1487
1488 val = snd_soc_read(codec, base + ARIZONA_AIF_TX_BCLK_RATE);
1489 if (lrclk != (val & ARIZONA_AIF1TX_BCPF_MASK))
1490 return true;
1491
1492 val = snd_soc_read(codec, base + ARIZONA_AIF_FRAME_CTRL_1);
1493 if (frame != (val & (ARIZONA_AIF1TX_WL_MASK |
1494 ARIZONA_AIF1TX_SLOT_LEN_MASK)))
1495 return true;
1496
1497 return false;
1498}
1499
Mark Brown07ed8732012-06-18 21:08:44 +01001500static int arizona_hw_params(struct snd_pcm_substream *substream,
1501 struct snd_pcm_hw_params *params,
1502 struct snd_soc_dai *dai)
1503{
1504 struct snd_soc_codec *codec = dai->codec;
1505 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brownc94aa302013-01-17 16:35:14 +09001506 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +01001507 int base = dai->driver->base;
1508 const int *rates;
Mark Brown76bf9692013-03-05 14:17:47 +08001509 int i, ret, val;
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001510 int channels = params_channels(params);
Mark Brownc94aa302013-01-17 16:35:14 +09001511 int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001512 int tdm_width = arizona->tdm_width[dai->id - 1];
1513 int tdm_slots = arizona->tdm_slots[dai->id - 1];
Mark Brownc94aa302013-01-17 16:35:14 +09001514 int bclk, lrclk, wl, frame, bclk_target;
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001515 bool reconfig;
1516 unsigned int aif_tx_state, aif_rx_state;
Mark Brown07ed8732012-06-18 21:08:44 +01001517
1518 if (params_rate(params) % 8000)
Mark Brown949e6bc2012-07-04 18:58:04 +01001519 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001520 else
Mark Brown949e6bc2012-07-04 18:58:04 +01001521 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001522
Charles Keepax5ed68f02015-07-09 11:28:46 +01001523 wl = params_width(params);
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001524
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001525 if (tdm_slots) {
1526 arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n",
1527 tdm_slots, tdm_width);
1528 bclk_target = tdm_slots * tdm_width * params_rate(params);
1529 channels = tdm_slots;
1530 } else {
1531 bclk_target = snd_soc_params_to_bclk(params);
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001532 tdm_width = wl;
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001533 }
1534
1535 if (chan_limit && chan_limit < channels) {
Mark Brownc94aa302013-01-17 16:35:14 +09001536 arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001537 bclk_target /= channels;
Mark Brownc94aa302013-01-17 16:35:14 +09001538 bclk_target *= chan_limit;
1539 }
1540
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001541 /* Force multiple of 2 channels for I2S mode */
Mark Brown76bf9692013-03-05 14:17:47 +08001542 val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
Richard Fitzgeralde9c7f342014-11-12 16:12:46 +00001543 val &= ARIZONA_AIF1_FMT_MASK;
1544 if ((channels & 1) && (val == ARIZONA_FMT_I2S_MODE)) {
Mark Brown76bf9692013-03-05 14:17:47 +08001545 arizona_aif_dbg(dai, "Forcing stereo mode\n");
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001546 bclk_target /= channels;
1547 bclk_target *= channels + 1;
Mark Brown76bf9692013-03-05 14:17:47 +08001548 }
1549
Mark Brown949e6bc2012-07-04 18:58:04 +01001550 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brownc94aa302013-01-17 16:35:14 +09001551 if (rates[i] >= bclk_target &&
Mark Brown50017652012-07-04 19:07:09 +01001552 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +01001553 bclk = i;
1554 break;
1555 }
1556 }
Mark Brown949e6bc2012-07-04 18:58:04 +01001557 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001558 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1559 params_rate(params));
1560 return -EINVAL;
1561 }
1562
Mark Brownb59e0f82013-01-17 14:15:59 +09001563 lrclk = rates[bclk] / params_rate(params);
Mark Brown07ed8732012-06-18 21:08:44 +01001564
1565 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
1566 rates[bclk], rates[bclk] / lrclk);
1567
Nikesh Oswald114e5f2014-08-12 15:30:32 +01001568 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | tdm_width;
Mark Brown07ed8732012-06-18 21:08:44 +01001569
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001570 reconfig = arizona_aif_cfg_changed(codec, base, bclk, lrclk, frame);
1571
1572 if (reconfig) {
1573 /* Save AIF TX/RX state */
1574 aif_tx_state = snd_soc_read(codec,
1575 base + ARIZONA_AIF_TX_ENABLES);
1576 aif_rx_state = snd_soc_read(codec,
1577 base + ARIZONA_AIF_RX_ENABLES);
1578 /* Disable AIF TX/RX before reconfiguring it */
1579 regmap_update_bits_async(arizona->regmap,
1580 base + ARIZONA_AIF_TX_ENABLES, 0xff, 0x0);
1581 regmap_update_bits(arizona->regmap,
1582 base + ARIZONA_AIF_RX_ENABLES, 0xff, 0x0);
1583 }
1584
Mark Brownb272efc2012-10-10 15:10:08 +09001585 ret = arizona_hw_params_rate(substream, params, dai);
1586 if (ret != 0)
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001587 goto restore_aif;
Mark Brownc013b272012-07-04 20:05:57 +01001588
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001589 if (reconfig) {
1590 regmap_update_bits_async(arizona->regmap,
1591 base + ARIZONA_AIF_BCLK_CTRL,
1592 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
1593 regmap_update_bits_async(arizona->regmap,
1594 base + ARIZONA_AIF_TX_BCLK_RATE,
1595 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
1596 regmap_update_bits_async(arizona->regmap,
1597 base + ARIZONA_AIF_RX_BCLK_RATE,
1598 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
1599 regmap_update_bits_async(arizona->regmap,
1600 base + ARIZONA_AIF_FRAME_CTRL_1,
1601 ARIZONA_AIF1TX_WL_MASK |
1602 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
1603 regmap_update_bits(arizona->regmap,
1604 base + ARIZONA_AIF_FRAME_CTRL_2,
1605 ARIZONA_AIF1RX_WL_MASK |
1606 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
1607 }
Mark Brown07ed8732012-06-18 21:08:44 +01001608
Richard Fitzgeraldbedd4b12014-07-22 11:42:06 +01001609restore_aif:
1610 if (reconfig) {
1611 /* Restore AIF TX/RX state */
1612 regmap_update_bits_async(arizona->regmap,
1613 base + ARIZONA_AIF_TX_ENABLES,
1614 0xff, aif_tx_state);
1615 regmap_update_bits(arizona->regmap,
1616 base + ARIZONA_AIF_RX_ENABLES,
1617 0xff, aif_rx_state);
1618 }
1619 return ret;
Mark Brown07ed8732012-06-18 21:08:44 +01001620}
1621
Mark Brown410837a2012-07-05 17:26:59 +01001622static const char *arizona_dai_clk_str(int clk_id)
1623{
1624 switch (clk_id) {
1625 case ARIZONA_CLK_SYSCLK:
1626 return "SYSCLK";
1627 case ARIZONA_CLK_ASYNCCLK:
1628 return "ASYNCCLK";
1629 default:
1630 return "Unknown clock";
1631 }
1632}
1633
Mark Brown5b2eec32012-07-04 17:32:05 +01001634static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
1635 int clk_id, unsigned int freq, int dir)
1636{
1637 struct snd_soc_codec *codec = dai->codec;
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +02001638 struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
Mark Brown5b2eec32012-07-04 17:32:05 +01001639 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1640 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown410837a2012-07-05 17:26:59 +01001641 struct snd_soc_dapm_route routes[2];
Mark Brown5b2eec32012-07-04 17:32:05 +01001642
1643 switch (clk_id) {
1644 case ARIZONA_CLK_SYSCLK:
1645 case ARIZONA_CLK_ASYNCCLK:
1646 break;
1647 default:
1648 return -EINVAL;
1649 }
1650
Mark Brown410837a2012-07-05 17:26:59 +01001651 if (clk_id == dai_priv->clk)
1652 return 0;
1653
1654 if (dai->active) {
Mark Brown5b2eec32012-07-04 17:32:05 +01001655 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
1656 dai->id);
1657 return -EBUSY;
1658 }
1659
Mark Brownc8d35a62012-12-07 12:49:40 +09001660 dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1,
1661 arizona_dai_clk_str(clk_id));
1662
Mark Brown410837a2012-07-05 17:26:59 +01001663 memset(&routes, 0, sizeof(routes));
1664 routes[0].sink = dai->driver->capture.stream_name;
1665 routes[1].sink = dai->driver->playback.stream_name;
Mark Brown5b2eec32012-07-04 17:32:05 +01001666
Mark Brown410837a2012-07-05 17:26:59 +01001667 routes[0].source = arizona_dai_clk_str(dai_priv->clk);
1668 routes[1].source = arizona_dai_clk_str(dai_priv->clk);
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +02001669 snd_soc_dapm_del_routes(dapm, routes, ARRAY_SIZE(routes));
Mark Brown410837a2012-07-05 17:26:59 +01001670
1671 routes[0].source = arizona_dai_clk_str(clk_id);
1672 routes[1].source = arizona_dai_clk_str(clk_id);
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +02001673 snd_soc_dapm_add_routes(dapm, routes, ARRAY_SIZE(routes));
Mark Brown410837a2012-07-05 17:26:59 +01001674
Mark Brown0c778e82012-12-06 18:22:25 +09001675 dai_priv->clk = clk_id;
1676
Lars-Peter Clausen1ac52142015-06-01 10:10:24 +02001677 return snd_soc_dapm_sync(dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +01001678}
1679
Mark Brown01df2592012-12-12 16:22:08 +09001680static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
1681{
1682 struct snd_soc_codec *codec = dai->codec;
1683 int base = dai->driver->base;
1684 unsigned int reg;
1685
1686 if (tristate)
1687 reg = ARIZONA_AIF1_TRI;
1688 else
1689 reg = 0;
1690
1691 return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1692 ARIZONA_AIF1_TRI, reg);
1693}
1694
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001695static void arizona_set_channels_to_mask(struct snd_soc_dai *dai,
1696 unsigned int base,
1697 int channels, unsigned int mask)
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 slot, i;
1703
1704 for (i = 0; i < channels; ++i) {
1705 slot = ffs(mask) - 1;
1706 if (slot < 0)
1707 return;
1708
1709 regmap_write(arizona->regmap, base + i, slot);
1710
1711 mask &= ~(1 << slot);
1712 }
1713
1714 if (mask)
1715 arizona_aif_warn(dai, "Too many channels in TDM mask\n");
1716}
1717
1718static int arizona_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
1719 unsigned int rx_mask, int slots, int slot_width)
1720{
1721 struct snd_soc_codec *codec = dai->codec;
1722 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1723 struct arizona *arizona = priv->arizona;
1724 int base = dai->driver->base;
1725 int rx_max_chan = dai->driver->playback.channels_max;
1726 int tx_max_chan = dai->driver->capture.channels_max;
1727
1728 /* Only support TDM for the physical AIFs */
1729 if (dai->id > ARIZONA_MAX_AIF)
1730 return -ENOTSUPP;
1731
1732 if (slots == 0) {
1733 tx_mask = (1 << tx_max_chan) - 1;
1734 rx_mask = (1 << rx_max_chan) - 1;
1735 }
1736
1737 arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_3,
1738 tx_max_chan, tx_mask);
1739 arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_11,
1740 rx_max_chan, rx_mask);
1741
1742 arizona->tdm_width[dai->id - 1] = slot_width;
1743 arizona->tdm_slots[dai->id - 1] = slots;
1744
1745 return 0;
1746}
1747
Mark Brown07ed8732012-06-18 21:08:44 +01001748const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +01001749 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +01001750 .set_fmt = arizona_set_fmt,
Charles Keepaxed70f3a2014-06-04 10:11:06 +01001751 .set_tdm_slot = arizona_set_tdm_slot,
Mark Brown07ed8732012-06-18 21:08:44 +01001752 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +01001753 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown01df2592012-12-12 16:22:08 +09001754 .set_tristate = arizona_set_tristate,
Mark Brown07ed8732012-06-18 21:08:44 +01001755};
Mark Browna8379872012-07-09 12:16:41 +01001756EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +01001757
Mark Brownbd1dd882013-05-17 13:29:03 +01001758const struct snd_soc_dai_ops arizona_simple_dai_ops = {
1759 .startup = arizona_startup,
1760 .hw_params = arizona_hw_params_rate,
1761 .set_sysclk = arizona_dai_set_sysclk,
1762};
1763EXPORT_SYMBOL_GPL(arizona_simple_dai_ops);
1764
Mark Brown5b2eec32012-07-04 17:32:05 +01001765int arizona_init_dai(struct arizona_priv *priv, int id)
1766{
1767 struct arizona_dai_priv *dai_priv = &priv->dai[id];
1768
1769 dai_priv->clk = ARIZONA_CLK_SYSCLK;
1770
1771 return 0;
1772}
1773EXPORT_SYMBOL_GPL(arizona_init_dai);
1774
Mark Brown07ed8732012-06-18 21:08:44 +01001775static struct {
1776 unsigned int min;
1777 unsigned int max;
1778 u16 fratio;
1779 int ratio;
1780} fll_fratios[] = {
1781 { 0, 64000, 4, 16 },
1782 { 64000, 128000, 3, 8 },
1783 { 128000, 256000, 2, 4 },
1784 { 256000, 1000000, 1, 2 },
1785 { 1000000, 13500000, 0, 1 },
1786};
1787
Mark Brown8f113d72013-03-05 12:08:57 +08001788static struct {
1789 unsigned int min;
1790 unsigned int max;
1791 u16 gain;
1792} fll_gains[] = {
1793 { 0, 256000, 0 },
1794 { 256000, 1000000, 2 },
1795 { 1000000, 13500000, 4 },
1796};
1797
Mark Brown07ed8732012-06-18 21:08:44 +01001798struct arizona_fll_cfg {
1799 int n;
1800 int theta;
1801 int lambda;
1802 int refdiv;
1803 int outdiv;
1804 int fratio;
Mark Brown8f113d72013-03-05 12:08:57 +08001805 int gain;
Mark Brown07ed8732012-06-18 21:08:44 +01001806};
1807
Charles Keepax23f785a82014-03-07 16:34:20 +00001808static int arizona_validate_fll(struct arizona_fll *fll,
1809 unsigned int Fref,
1810 unsigned int Fout)
1811{
1812 unsigned int Fvco_min;
1813
Charles Keepaxc8badda2014-07-09 17:41:49 +01001814 if (fll->fout && Fout != fll->fout) {
1815 arizona_fll_err(fll,
1816 "Can't change output on active FLL\n");
1817 return -EINVAL;
1818 }
1819
Charles Keepax23f785a82014-03-07 16:34:20 +00001820 if (Fref / ARIZONA_FLL_MAX_REFDIV > ARIZONA_FLL_MAX_FREF) {
1821 arizona_fll_err(fll,
1822 "Can't scale %dMHz in to <=13.5MHz\n",
1823 Fref);
1824 return -EINVAL;
1825 }
1826
1827 Fvco_min = ARIZONA_FLL_MIN_FVCO * fll->vco_mult;
1828 if (Fout * ARIZONA_FLL_MAX_OUTDIV < Fvco_min) {
1829 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
1830 Fout);
1831 return -EINVAL;
1832 }
1833
1834 return 0;
1835}
1836
Charles Keepaxd0800342014-03-07 16:34:25 +00001837static int arizona_find_fratio(unsigned int Fref, int *fratio)
1838{
1839 int i;
1840
1841 /* Find an appropriate FLL_FRATIO */
1842 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
1843 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
1844 if (fratio)
1845 *fratio = fll_fratios[i].fratio;
1846 return fll_fratios[i].ratio;
1847 }
1848 }
1849
1850 return -EINVAL;
1851}
1852
1853static int arizona_calc_fratio(struct arizona_fll *fll,
1854 struct arizona_fll_cfg *cfg,
1855 unsigned int target,
1856 unsigned int Fref, bool sync)
1857{
1858 int init_ratio, ratio;
1859 int refdiv, div;
1860
1861 /* Fref must be <=13.5MHz, find initial refdiv */
1862 div = 1;
1863 cfg->refdiv = 0;
1864 while (Fref > ARIZONA_FLL_MAX_FREF) {
1865 div *= 2;
1866 Fref /= 2;
1867 cfg->refdiv++;
1868
1869 if (div > ARIZONA_FLL_MAX_REFDIV)
1870 return -EINVAL;
1871 }
1872
1873 /* Find an appropriate FLL_FRATIO */
1874 init_ratio = arizona_find_fratio(Fref, &cfg->fratio);
1875 if (init_ratio < 0) {
1876 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
1877 Fref);
1878 return init_ratio;
1879 }
1880
1881 switch (fll->arizona->type) {
1882 case WM5110:
Richard Fitzgerald575ef7f2015-01-17 15:21:27 +00001883 case WM8280:
Charles Keepaxd0800342014-03-07 16:34:25 +00001884 if (fll->arizona->rev < 3 || sync)
1885 return init_ratio;
1886 break;
1887 default:
1888 return init_ratio;
1889 }
1890
1891 cfg->fratio = init_ratio - 1;
1892
1893 /* Adjust FRATIO/refdiv to avoid integer mode if possible */
1894 refdiv = cfg->refdiv;
1895
1896 while (div <= ARIZONA_FLL_MAX_REFDIV) {
1897 for (ratio = init_ratio; ratio <= ARIZONA_FLL_MAX_FRATIO;
1898 ratio++) {
Charles Keepax35a730a2014-07-09 17:41:45 +01001899 if ((ARIZONA_FLL_VCO_CORNER / 2) /
1900 (fll->vco_mult * ratio) < Fref)
Charles Keepax29fee822014-07-09 17:41:44 +01001901 break;
1902
Charles Keepaxd0800342014-03-07 16:34:25 +00001903 if (target % (ratio * Fref)) {
1904 cfg->refdiv = refdiv;
1905 cfg->fratio = ratio - 1;
1906 return ratio;
1907 }
1908 }
1909
Charles Keepax4714bc02014-07-09 17:41:43 +01001910 for (ratio = init_ratio - 1; ratio > 0; ratio--) {
Charles Keepaxd0800342014-03-07 16:34:25 +00001911 if (target % (ratio * Fref)) {
1912 cfg->refdiv = refdiv;
1913 cfg->fratio = ratio - 1;
1914 return ratio;
1915 }
1916 }
1917
1918 div *= 2;
1919 Fref /= 2;
1920 refdiv++;
1921 init_ratio = arizona_find_fratio(Fref, NULL);
1922 }
1923
1924 arizona_fll_warn(fll, "Falling back to integer mode operation\n");
1925 return cfg->fratio + 1;
1926}
1927
Mark Brown07ed8732012-06-18 21:08:44 +01001928static int arizona_calc_fll(struct arizona_fll *fll,
1929 struct arizona_fll_cfg *cfg,
Charles Keepaxd0800342014-03-07 16:34:25 +00001930 unsigned int Fref, bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01001931{
1932 unsigned int target, div, gcd_fll;
1933 int i, ratio;
1934
Charles Keepax8ccefcd2014-03-07 16:34:21 +00001935 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, fll->fout);
Mark Brown07ed8732012-06-18 21:08:44 +01001936
Mark Brown2b4d39f2012-07-10 17:03:46 +01001937 /* Fvco should be over the targt; don't check the upper bound */
Charles Keepaxf641aec2014-03-07 16:34:22 +00001938 div = ARIZONA_FLL_MIN_OUTDIV;
1939 while (fll->fout * div < ARIZONA_FLL_MIN_FVCO * fll->vco_mult) {
Mark Brown07ed8732012-06-18 21:08:44 +01001940 div++;
Charles Keepaxf641aec2014-03-07 16:34:22 +00001941 if (div > ARIZONA_FLL_MAX_OUTDIV)
Mark Brown07ed8732012-06-18 21:08:44 +01001942 return -EINVAL;
Mark Brown07ed8732012-06-18 21:08:44 +01001943 }
Charles Keepaxf641aec2014-03-07 16:34:22 +00001944 target = fll->fout * div / fll->vco_mult;
Mark Brown07ed8732012-06-18 21:08:44 +01001945 cfg->outdiv = div;
1946
1947 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
1948
Charles Keepaxd0800342014-03-07 16:34:25 +00001949 /* Find an appropriate FLL_FRATIO and refdiv */
1950 ratio = arizona_calc_fratio(fll, cfg, target, Fref, sync);
1951 if (ratio < 0)
1952 return ratio;
Mark Brown07ed8732012-06-18 21:08:44 +01001953
Mark Brown07ed8732012-06-18 21:08:44 +01001954 /* Apply the division for our remaining calculations */
Charles Keepaxd0800342014-03-07 16:34:25 +00001955 Fref = Fref / (1 << cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08001956
Mark Brown07ed8732012-06-18 21:08:44 +01001957 cfg->n = target / (ratio * Fref);
1958
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001959 if (target % (ratio * Fref)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001960 gcd_fll = gcd(target, ratio * Fref);
1961 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
1962
1963 cfg->theta = (target - (cfg->n * ratio * Fref))
1964 / gcd_fll;
1965 cfg->lambda = (ratio * Fref) / gcd_fll;
1966 } else {
1967 cfg->theta = 0;
1968 cfg->lambda = 0;
1969 }
1970
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001971 /* Round down to 16bit range with cost of accuracy lost.
1972 * Denominator must be bigger than numerator so we only
1973 * take care of it.
1974 */
1975 while (cfg->lambda >= (1 << 16)) {
1976 cfg->theta >>= 1;
1977 cfg->lambda >>= 1;
1978 }
1979
Charles Keepax5a3935c2014-03-07 16:34:23 +00001980 for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
1981 if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
1982 cfg->gain = fll_gains[i].gain;
1983 break;
1984 }
1985 }
1986 if (i == ARRAY_SIZE(fll_gains)) {
1987 arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
1988 Fref);
1989 return -EINVAL;
1990 }
1991
Mark Brown07ed8732012-06-18 21:08:44 +01001992 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
1993 cfg->n, cfg->theta, cfg->lambda);
1994 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
1995 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08001996 arizona_fll_dbg(fll, "GAIN=%d\n", cfg->gain);
Mark Brown07ed8732012-06-18 21:08:44 +01001997
1998 return 0;
1999
2000}
2001
2002static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
Mark Brown8f113d72013-03-05 12:08:57 +08002003 struct arizona_fll_cfg *cfg, int source,
2004 bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01002005{
Mark Brown3c43c692013-12-12 00:49:22 +00002006 regmap_update_bits_async(arizona->regmap, base + 3,
2007 ARIZONA_FLL1_THETA_MASK, cfg->theta);
2008 regmap_update_bits_async(arizona->regmap, base + 4,
2009 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
2010 regmap_update_bits_async(arizona->regmap, base + 5,
2011 ARIZONA_FLL1_FRATIO_MASK,
2012 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
2013 regmap_update_bits_async(arizona->regmap, base + 6,
2014 ARIZONA_FLL1_CLK_REF_DIV_MASK |
2015 ARIZONA_FLL1_CLK_REF_SRC_MASK,
2016 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
2017 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
Mark Brown07ed8732012-06-18 21:08:44 +01002018
Charles Keepax61719db2014-03-07 16:34:19 +00002019 if (sync) {
2020 regmap_update_bits(arizona->regmap, base + 0x7,
2021 ARIZONA_FLL1_GAIN_MASK,
2022 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
2023 } else {
2024 regmap_update_bits(arizona->regmap, base + 0x5,
2025 ARIZONA_FLL1_OUTDIV_MASK,
2026 cfg->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
2027 regmap_update_bits(arizona->regmap, base + 0x9,
2028 ARIZONA_FLL1_GAIN_MASK,
2029 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
2030 }
Mark Brown8f113d72013-03-05 12:08:57 +08002031
Mark Brown3c43c692013-12-12 00:49:22 +00002032 regmap_update_bits_async(arizona->regmap, base + 2,
2033 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
2034 ARIZONA_FLL1_CTRL_UPD | cfg->n);
Mark Brown07ed8732012-06-18 21:08:44 +01002035}
2036
Charles Keepaxc393aca2014-07-09 17:41:47 +01002037static int arizona_is_enabled_fll(struct arizona_fll *fll)
Charles Keepaxd122d6c2013-02-20 17:28:36 +00002038{
2039 struct arizona *arizona = fll->arizona;
2040 unsigned int reg;
2041 int ret;
2042
2043 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
2044 if (ret != 0) {
2045 arizona_fll_err(fll, "Failed to read current state: %d\n",
2046 ret);
2047 return ret;
2048 }
2049
2050 return reg & ARIZONA_FLL1_ENA;
2051}
2052
Charles Keepaxc393aca2014-07-09 17:41:47 +01002053static int arizona_enable_fll(struct arizona_fll *fll)
Charles Keepax35722812013-02-20 17:28:38 +00002054{
2055 struct arizona *arizona = fll->arizona;
Charles Keepax49c60542013-09-16 15:34:35 +01002056 bool use_sync = false;
Charles Keepaxc393aca2014-07-09 17:41:47 +01002057 int already_enabled = arizona_is_enabled_fll(fll);
Charles Keepax23f785a82014-03-07 16:34:20 +00002058 struct arizona_fll_cfg cfg;
Charles Keepax0e765972015-08-25 12:43:48 +01002059 int i;
2060 unsigned int val;
Charles Keepax35722812013-02-20 17:28:38 +00002061
Charles Keepaxc393aca2014-07-09 17:41:47 +01002062 if (already_enabled < 0)
2063 return already_enabled;
2064
Charles Keepaxc8badda2014-07-09 17:41:49 +01002065 if (already_enabled) {
2066 /* Facilitate smooth refclk across the transition */
Nikesh Oswal1cf5a332015-08-19 16:02:24 +01002067 regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9,
Charles Keepaxc8badda2014-07-09 17:41:49 +01002068 ARIZONA_FLL1_GAIN_MASK, 0);
2069 regmap_update_bits_async(fll->arizona->regmap, fll->base + 1,
2070 ARIZONA_FLL1_FREERUN,
2071 ARIZONA_FLL1_FREERUN);
2072 }
2073
Mark Brownff680a12013-03-04 16:00:19 +08002074 /*
2075 * If we have both REFCLK and SYNCCLK then enable both,
2076 * otherwise apply the SYNCCLK settings to REFCLK.
2077 */
Charles Keepax49c60542013-09-16 15:34:35 +01002078 if (fll->ref_src >= 0 && fll->ref_freq &&
2079 fll->ref_src != fll->sync_src) {
Charles Keepaxd0800342014-03-07 16:34:25 +00002080 arizona_calc_fll(fll, &cfg, fll->ref_freq, false);
Charles Keepax35722812013-02-20 17:28:38 +00002081
Charles Keepax23f785a82014-03-07 16:34:20 +00002082 arizona_apply_fll(arizona, fll->base, &cfg, fll->ref_src,
Mark Brown8f113d72013-03-05 12:08:57 +08002083 false);
Charles Keepax49c60542013-09-16 15:34:35 +01002084 if (fll->sync_src >= 0) {
Charles Keepaxd0800342014-03-07 16:34:25 +00002085 arizona_calc_fll(fll, &cfg, fll->sync_freq, true);
Charles Keepax23f785a82014-03-07 16:34:20 +00002086
2087 arizona_apply_fll(arizona, fll->base + 0x10, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08002088 fll->sync_src, true);
Charles Keepax49c60542013-09-16 15:34:35 +01002089 use_sync = true;
2090 }
Mark Brownff680a12013-03-04 16:00:19 +08002091 } else if (fll->sync_src >= 0) {
Charles Keepaxd0800342014-03-07 16:34:25 +00002092 arizona_calc_fll(fll, &cfg, fll->sync_freq, false);
Mark Brownff680a12013-03-04 16:00:19 +08002093
Charles Keepax23f785a82014-03-07 16:34:20 +00002094 arizona_apply_fll(arizona, fll->base, &cfg,
Mark Brown8f113d72013-03-05 12:08:57 +08002095 fll->sync_src, false);
Mark Browneca2e8e2013-03-06 00:09:59 +08002096
Mark Brown3c43c692013-12-12 00:49:22 +00002097 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
2098 ARIZONA_FLL1_SYNC_ENA, 0);
Mark Brownff680a12013-03-04 16:00:19 +08002099 } else {
2100 arizona_fll_err(fll, "No clocks provided\n");
Charles Keepaxc393aca2014-07-09 17:41:47 +01002101 return -EINVAL;
Mark Brownff680a12013-03-04 16:00:19 +08002102 }
Charles Keepax35722812013-02-20 17:28:38 +00002103
Mark Brown576411be2013-03-05 12:07:16 +08002104 /*
2105 * Increase the bandwidth if we're not using a low frequency
2106 * sync source.
2107 */
Charles Keepax49c60542013-09-16 15:34:35 +01002108 if (use_sync && fll->sync_freq > 100000)
Mark Brown3c43c692013-12-12 00:49:22 +00002109 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
2110 ARIZONA_FLL1_SYNC_BW, 0);
Mark Brown576411be2013-03-05 12:07:16 +08002111 else
Mark Brown3c43c692013-12-12 00:49:22 +00002112 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
2113 ARIZONA_FLL1_SYNC_BW,
2114 ARIZONA_FLL1_SYNC_BW);
Mark Brown576411be2013-03-05 12:07:16 +08002115
Charles Keepaxc393aca2014-07-09 17:41:47 +01002116 if (!already_enabled)
Charles Keepax35722812013-02-20 17:28:38 +00002117 pm_runtime_get(arizona->dev);
2118
Mark Brown3c43c692013-12-12 00:49:22 +00002119 regmap_update_bits_async(arizona->regmap, fll->base + 1,
Mark Brown3c43c692013-12-12 00:49:22 +00002120 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
Charles Keepax49c60542013-09-16 15:34:35 +01002121 if (use_sync)
Mark Brown3c43c692013-12-12 00:49:22 +00002122 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
2123 ARIZONA_FLL1_SYNC_ENA,
2124 ARIZONA_FLL1_SYNC_ENA);
Charles Keepax35722812013-02-20 17:28:38 +00002125
Charles Keepaxc8badda2014-07-09 17:41:49 +01002126 if (already_enabled)
2127 regmap_update_bits_async(arizona->regmap, fll->base + 1,
2128 ARIZONA_FLL1_FREERUN, 0);
2129
Charles Keepax0e765972015-08-25 12:43:48 +01002130 arizona_fll_dbg(fll, "Waiting for FLL lock...\n");
2131 val = 0;
2132 for (i = 0; i < 15; i++) {
2133 if (i < 5)
2134 usleep_range(200, 400);
2135 else
2136 msleep(20);
2137
2138 regmap_read(arizona->regmap,
2139 ARIZONA_INTERRUPT_RAW_STATUS_5,
2140 &val);
2141 if (val & (ARIZONA_FLL1_CLOCK_OK_STS << (fll->id - 1)))
2142 break;
2143 }
2144 if (i == 15)
Charles Keepax35722812013-02-20 17:28:38 +00002145 arizona_fll_warn(fll, "Timed out waiting for lock\n");
Charles Keepax0e765972015-08-25 12:43:48 +01002146 else
2147 arizona_fll_dbg(fll, "FLL locked (%d polls)\n", i);
Charles Keepaxc393aca2014-07-09 17:41:47 +01002148
2149 return 0;
Charles Keepax35722812013-02-20 17:28:38 +00002150}
2151
Charles Keepax76040542013-02-20 17:28:37 +00002152static void arizona_disable_fll(struct arizona_fll *fll)
2153{
2154 struct arizona *arizona = fll->arizona;
2155 bool change;
2156
Mark Brown3c43c692013-12-12 00:49:22 +00002157 regmap_update_bits_async(arizona->regmap, fll->base + 1,
2158 ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
Charles Keepax76040542013-02-20 17:28:37 +00002159 regmap_update_bits_check(arizona->regmap, fll->base + 1,
2160 ARIZONA_FLL1_ENA, 0, &change);
2161 regmap_update_bits(arizona->regmap, fll->base + 0x11,
2162 ARIZONA_FLL1_SYNC_ENA, 0);
Charles Keepax5e39a502014-07-09 17:41:48 +01002163 regmap_update_bits_async(arizona->regmap, fll->base + 1,
2164 ARIZONA_FLL1_FREERUN, 0);
Charles Keepax76040542013-02-20 17:28:37 +00002165
2166 if (change)
2167 pm_runtime_put_autosuspend(arizona->dev);
2168}
2169
Charles Keepaxee929a92013-02-20 17:28:40 +00002170int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
2171 unsigned int Fref, unsigned int Fout)
2172{
Charles Keepaxc393aca2014-07-09 17:41:47 +01002173 int ret = 0;
Charles Keepaxee929a92013-02-20 17:28:40 +00002174
Charles Keepax1c5617f2013-02-22 17:10:37 +00002175 if (fll->ref_src == source && fll->ref_freq == Fref)
Charles Keepaxee929a92013-02-20 17:28:40 +00002176 return 0;
2177
Charles Keepax23f785a82014-03-07 16:34:20 +00002178 if (fll->fout && Fref > 0) {
2179 ret = arizona_validate_fll(fll, Fref, fll->fout);
2180 if (ret != 0)
2181 return ret;
Charles Keepaxee929a92013-02-20 17:28:40 +00002182 }
2183
2184 fll->ref_src = source;
2185 fll->ref_freq = Fref;
Charles Keepaxee929a92013-02-20 17:28:40 +00002186
Mark Brown86cd6842013-03-07 16:14:04 +08002187 if (fll->fout && Fref > 0) {
Charles Keepaxc393aca2014-07-09 17:41:47 +01002188 ret = arizona_enable_fll(fll);
Charles Keepaxee929a92013-02-20 17:28:40 +00002189 }
2190
Charles Keepaxc393aca2014-07-09 17:41:47 +01002191 return ret;
Charles Keepaxee929a92013-02-20 17:28:40 +00002192}
2193EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
2194
Mark Brown07ed8732012-06-18 21:08:44 +01002195int arizona_set_fll(struct arizona_fll *fll, int source,
2196 unsigned int Fref, unsigned int Fout)
2197{
Charles Keepaxc393aca2014-07-09 17:41:47 +01002198 int ret = 0;
Mark Brown07ed8732012-06-18 21:08:44 +01002199
Mark Brownff680a12013-03-04 16:00:19 +08002200 if (fll->sync_src == source &&
2201 fll->sync_freq == Fref && fll->fout == Fout)
2202 return 0;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00002203
Mark Brownff680a12013-03-04 16:00:19 +08002204 if (Fout) {
2205 if (fll->ref_src >= 0) {
Charles Keepax23f785a82014-03-07 16:34:20 +00002206 ret = arizona_validate_fll(fll, fll->ref_freq, Fout);
Charles Keepax9e359c62013-02-20 17:28:35 +00002207 if (ret != 0)
2208 return ret;
2209 }
2210
Charles Keepax23f785a82014-03-07 16:34:20 +00002211 ret = arizona_validate_fll(fll, Fref, Fout);
Mark Brownff680a12013-03-04 16:00:19 +08002212 if (ret != 0)
2213 return ret;
Charles Keepax9e359c62013-02-20 17:28:35 +00002214 }
Mark Brownff680a12013-03-04 16:00:19 +08002215
2216 fll->sync_src = source;
2217 fll->sync_freq = Fref;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00002218 fll->fout = Fout;
Charles Keepax9e359c62013-02-20 17:28:35 +00002219
Charles Keepax613124c2014-07-09 17:41:46 +01002220 if (Fout)
Charles Keepaxc393aca2014-07-09 17:41:47 +01002221 ret = arizona_enable_fll(fll);
Charles Keepax613124c2014-07-09 17:41:46 +01002222 else
Charles Keepax76040542013-02-20 17:28:37 +00002223 arizona_disable_fll(fll);
Mark Brown07ed8732012-06-18 21:08:44 +01002224
Charles Keepaxc393aca2014-07-09 17:41:47 +01002225 return ret;
Mark Brown07ed8732012-06-18 21:08:44 +01002226}
2227EXPORT_SYMBOL_GPL(arizona_set_fll);
2228
2229int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
2230 int ok_irq, struct arizona_fll *fll)
2231{
Charles Keepax19b34bd2013-02-20 17:28:34 +00002232 unsigned int val;
Mark Brown07ed8732012-06-18 21:08:44 +01002233
Mark Brown07ed8732012-06-18 21:08:44 +01002234 fll->id = id;
2235 fll->base = base;
2236 fll->arizona = arizona;
Charles Keepaxf3f11632013-02-20 17:28:41 +00002237 fll->sync_src = ARIZONA_FLL_SRC_NONE;
Mark Brown07ed8732012-06-18 21:08:44 +01002238
Charles Keepax19b34bd2013-02-20 17:28:34 +00002239 /* Configure default refclk to 32kHz if we have one */
2240 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
2241 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
2242 case ARIZONA_CLK_SRC_MCLK1:
2243 case ARIZONA_CLK_SRC_MCLK2:
2244 fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK;
2245 break;
2246 default:
Charles Keepaxf3f11632013-02-20 17:28:41 +00002247 fll->ref_src = ARIZONA_FLL_SRC_NONE;
Charles Keepax19b34bd2013-02-20 17:28:34 +00002248 }
2249 fll->ref_freq = 32768;
2250
Mark Brown07ed8732012-06-18 21:08:44 +01002251 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
2252 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
2253 "FLL%d clock OK", id);
2254
Charles Keepaxe31c1942013-01-07 16:41:45 +00002255 regmap_update_bits(arizona->regmap, fll->base + 1,
2256 ARIZONA_FLL1_FREERUN, 0);
2257
Mark Brown07ed8732012-06-18 21:08:44 +01002258 return 0;
2259}
2260EXPORT_SYMBOL_GPL(arizona_init_fll);
2261
Mark Brownbc9ab6d2013-01-04 19:31:00 +00002262/**
2263 * arizona_set_output_mode - Set the mode of the specified output
2264 *
2265 * @codec: Device to configure
2266 * @output: Output number
2267 * @diff: True to set the output to differential mode
2268 *
2269 * Some systems use external analogue switches to connect more
2270 * analogue devices to the CODEC than are supported by the device. In
2271 * some systems this requires changing the switched output from single
2272 * ended to differential mode dynamically at runtime, an operation
2273 * supported using this function.
2274 *
2275 * Most systems have a single static configuration and should use
2276 * platform data instead.
2277 */
2278int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
2279{
2280 unsigned int reg, val;
2281
2282 if (output < 1 || output > 6)
2283 return -EINVAL;
2284
2285 reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
2286
2287 if (diff)
2288 val = ARIZONA_OUT1_MONO;
2289 else
2290 val = 0;
2291
2292 return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val);
2293}
2294EXPORT_SYMBOL_GPL(arizona_set_output_mode);
2295
Richard Fitzgerald336d0442015-06-18 13:43:19 +01002296static const struct soc_enum arizona_adsp2_rate_enum[] = {
2297 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP1_CONTROL_1,
2298 ARIZONA_DSP1_RATE_SHIFT, 0xf,
2299 ARIZONA_RATE_ENUM_SIZE,
2300 arizona_rate_text, arizona_rate_val),
2301 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP2_CONTROL_1,
2302 ARIZONA_DSP1_RATE_SHIFT, 0xf,
2303 ARIZONA_RATE_ENUM_SIZE,
2304 arizona_rate_text, arizona_rate_val),
2305 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1,
2306 ARIZONA_DSP1_RATE_SHIFT, 0xf,
2307 ARIZONA_RATE_ENUM_SIZE,
2308 arizona_rate_text, arizona_rate_val),
2309 SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP4_CONTROL_1,
2310 ARIZONA_DSP1_RATE_SHIFT, 0xf,
2311 ARIZONA_RATE_ENUM_SIZE,
2312 arizona_rate_text, arizona_rate_val),
2313};
2314
2315const struct snd_kcontrol_new arizona_adsp2_rate_controls[] = {
2316 SOC_ENUM("DSP1 Rate", arizona_adsp2_rate_enum[0]),
2317 SOC_ENUM("DSP2 Rate", arizona_adsp2_rate_enum[1]),
2318 SOC_ENUM("DSP3 Rate", arizona_adsp2_rate_enum[2]),
2319 SOC_ENUM("DSP4 Rate", arizona_adsp2_rate_enum[3]),
2320};
2321EXPORT_SYMBOL_GPL(arizona_adsp2_rate_controls);
2322
Charles Keepaxc05d9a82015-06-25 09:35:11 +01002323static bool arizona_eq_filter_unstable(bool mode, __be16 _a, __be16 _b)
2324{
2325 s16 a = be16_to_cpu(_a);
2326 s16 b = be16_to_cpu(_b);
2327
2328 if (!mode) {
2329 return abs(a) >= 4096;
2330 } else {
2331 if (abs(b) >= 4096)
2332 return true;
2333
2334 return (abs((a << 16) / (4096 - b)) >= 4096 << 4);
2335 }
2336}
2337
2338int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol,
2339 struct snd_ctl_elem_value *ucontrol)
2340{
2341 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
2342 struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
2343 struct soc_bytes *params = (void *)kcontrol->private_value;
2344 unsigned int val;
2345 __be16 *data;
2346 int len;
2347 int ret;
2348
2349 len = params->num_regs * regmap_get_val_bytes(arizona->regmap);
2350
2351 data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA);
2352 if (!data)
2353 return -ENOMEM;
2354
2355 data[0] &= cpu_to_be16(ARIZONA_EQ1_B1_MODE);
2356
2357 if (arizona_eq_filter_unstable(!!data[0], data[1], data[2]) ||
2358 arizona_eq_filter_unstable(true, data[4], data[5]) ||
2359 arizona_eq_filter_unstable(true, data[8], data[9]) ||
2360 arizona_eq_filter_unstable(true, data[12], data[13]) ||
2361 arizona_eq_filter_unstable(false, data[16], data[17])) {
2362 dev_err(arizona->dev, "Rejecting unstable EQ coefficients\n");
2363 ret = -EINVAL;
2364 goto out;
2365 }
2366
2367 ret = regmap_read(arizona->regmap, params->base, &val);
2368 if (ret != 0)
2369 goto out;
2370
2371 val &= ~ARIZONA_EQ1_B1_MODE;
2372 data[0] |= cpu_to_be16(val);
2373
2374 ret = regmap_raw_write(arizona->regmap, params->base, data, len);
2375
2376out:
2377 kfree(data);
2378 return ret;
2379}
2380EXPORT_SYMBOL_GPL(arizona_eq_coeff_put);
2381
Charles Keepax5f8e6712015-06-25 09:35:12 +01002382int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
2383 struct snd_ctl_elem_value *ucontrol)
2384{
2385 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
2386 struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
2387 __be16 *data = (__be16 *)ucontrol->value.bytes.data;
2388 s16 val = be16_to_cpu(*data);
2389
2390 if (abs(val) >= 4096) {
2391 dev_err(arizona->dev, "Rejecting unstable LHPF coefficients\n");
2392 return -EINVAL;
2393 }
2394
2395 return snd_soc_bytes_put(kcontrol, ucontrol);
2396}
2397EXPORT_SYMBOL_GPL(arizona_lhpf_coeff_put);
2398
Mark Brown07ed8732012-06-18 21:08:44 +01002399MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
2400MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
2401MODULE_LICENSE("GPL");