blob: d90804686e4efcc8dce9ff657beec81843a97ec9 [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>
Charles Keepaxb63144e2013-07-04 08:56:28 +010022#include <linux/mfd/arizona/gpio.h>
Mark Brown07ed8732012-06-18 21:08:44 +010023#include <linux/mfd/arizona/registers.h>
24
25#include "arizona.h"
26
27#define ARIZONA_AIF_BCLK_CTRL 0x00
28#define ARIZONA_AIF_TX_PIN_CTRL 0x01
29#define ARIZONA_AIF_RX_PIN_CTRL 0x02
30#define ARIZONA_AIF_RATE_CTRL 0x03
31#define ARIZONA_AIF_FORMAT 0x04
32#define ARIZONA_AIF_TX_BCLK_RATE 0x05
33#define ARIZONA_AIF_RX_BCLK_RATE 0x06
34#define ARIZONA_AIF_FRAME_CTRL_1 0x07
35#define ARIZONA_AIF_FRAME_CTRL_2 0x08
36#define ARIZONA_AIF_FRAME_CTRL_3 0x09
37#define ARIZONA_AIF_FRAME_CTRL_4 0x0A
38#define ARIZONA_AIF_FRAME_CTRL_5 0x0B
39#define ARIZONA_AIF_FRAME_CTRL_6 0x0C
40#define ARIZONA_AIF_FRAME_CTRL_7 0x0D
41#define ARIZONA_AIF_FRAME_CTRL_8 0x0E
42#define ARIZONA_AIF_FRAME_CTRL_9 0x0F
43#define ARIZONA_AIF_FRAME_CTRL_10 0x10
44#define ARIZONA_AIF_FRAME_CTRL_11 0x11
45#define ARIZONA_AIF_FRAME_CTRL_12 0x12
46#define ARIZONA_AIF_FRAME_CTRL_13 0x13
47#define ARIZONA_AIF_FRAME_CTRL_14 0x14
48#define ARIZONA_AIF_FRAME_CTRL_15 0x15
49#define ARIZONA_AIF_FRAME_CTRL_16 0x16
50#define ARIZONA_AIF_FRAME_CTRL_17 0x17
51#define ARIZONA_AIF_FRAME_CTRL_18 0x18
52#define ARIZONA_AIF_TX_ENABLES 0x19
53#define ARIZONA_AIF_RX_ENABLES 0x1A
54#define ARIZONA_AIF_FORCE_WRITE 0x1B
55
56#define arizona_fll_err(_fll, fmt, ...) \
57 dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
58#define arizona_fll_warn(_fll, fmt, ...) \
59 dev_warn(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
60#define arizona_fll_dbg(_fll, fmt, ...) \
Mark Brown9092a6e2013-02-06 17:58:57 +000061 dev_dbg(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
Mark Brown07ed8732012-06-18 21:08:44 +010062
63#define arizona_aif_err(_dai, fmt, ...) \
64 dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
65#define arizona_aif_warn(_dai, fmt, ...) \
66 dev_warn(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
67#define arizona_aif_dbg(_dai, fmt, ...) \
Mark Brown9092a6e2013-02-06 17:58:57 +000068 dev_dbg(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
Mark Brown07ed8732012-06-18 21:08:44 +010069
Mark Brown56447e12013-01-10 14:45:58 +000070static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
71 struct snd_kcontrol *kcontrol,
72 int event)
73{
74 struct snd_soc_codec *codec = w->codec;
75 struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
76 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
77 bool manual_ena = false;
Mark Brownf4a76e72013-03-13 12:22:39 +000078 int val;
Mark Brown56447e12013-01-10 14:45:58 +000079
80 switch (arizona->type) {
81 case WM5102:
82 switch (arizona->rev) {
83 case 0:
84 break;
85 default:
86 manual_ena = true;
87 break;
88 }
89 default:
90 break;
91 }
92
93 switch (event) {
94 case SND_SOC_DAPM_PRE_PMU:
95 if (!priv->spk_ena && manual_ena) {
Mark Brown3c43c692013-12-12 00:49:22 +000096 regmap_write_async(arizona->regmap, 0x4f5, 0x25a);
Mark Brown56447e12013-01-10 14:45:58 +000097 priv->spk_ena_pending = true;
98 }
99 break;
100 case SND_SOC_DAPM_POST_PMU:
Mark Brownf4a76e72013-03-13 12:22:39 +0000101 val = snd_soc_read(codec, ARIZONA_INTERRUPT_RAW_STATUS_3);
102 if (val & ARIZONA_SPK_SHUTDOWN_STS) {
103 dev_crit(arizona->dev,
104 "Speaker not enabled due to temperature\n");
105 return -EBUSY;
106 }
107
Mark Brown3c43c692013-12-12 00:49:22 +0000108 regmap_update_bits_async(arizona->regmap,
109 ARIZONA_OUTPUT_ENABLES_1,
110 1 << w->shift, 1 << w->shift);
Mark Brownf4a76e72013-03-13 12:22:39 +0000111
Mark Brown56447e12013-01-10 14:45:58 +0000112 if (priv->spk_ena_pending) {
113 msleep(75);
Mark Brown3c43c692013-12-12 00:49:22 +0000114 regmap_write_async(arizona->regmap, 0x4f5, 0xda);
Mark Brown56447e12013-01-10 14:45:58 +0000115 priv->spk_ena_pending = false;
116 priv->spk_ena++;
117 }
118 break;
119 case SND_SOC_DAPM_PRE_PMD:
120 if (manual_ena) {
121 priv->spk_ena--;
122 if (!priv->spk_ena)
Mark Brown3c43c692013-12-12 00:49:22 +0000123 regmap_write_async(arizona->regmap,
124 0x4f5, 0x25a);
Mark Brown56447e12013-01-10 14:45:58 +0000125 }
Mark Brownf4a76e72013-03-13 12:22:39 +0000126
Mark Brown3c43c692013-12-12 00:49:22 +0000127 regmap_update_bits_async(arizona->regmap,
128 ARIZONA_OUTPUT_ENABLES_1,
129 1 << w->shift, 0);
Mark Brown56447e12013-01-10 14:45:58 +0000130 break;
131 case SND_SOC_DAPM_POST_PMD:
132 if (manual_ena) {
133 if (!priv->spk_ena)
Mark Brown3c43c692013-12-12 00:49:22 +0000134 regmap_write_async(arizona->regmap,
135 0x4f5, 0x0da);
Mark Brown56447e12013-01-10 14:45:58 +0000136 }
137 break;
138 }
139
140 return 0;
141}
142
Mark Brown899817e2013-03-13 12:32:10 +0000143static irqreturn_t arizona_thermal_warn(int irq, void *data)
144{
145 struct arizona *arizona = data;
146 unsigned int val;
147 int ret;
148
149 ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
150 &val);
151 if (ret != 0) {
152 dev_err(arizona->dev, "Failed to read thermal status: %d\n",
153 ret);
154 } else if (val & ARIZONA_SPK_SHUTDOWN_WARN_STS) {
155 dev_crit(arizona->dev, "Thermal warning\n");
156 }
157
158 return IRQ_HANDLED;
159}
160
161static irqreturn_t arizona_thermal_shutdown(int irq, void *data)
162{
163 struct arizona *arizona = data;
164 unsigned int val;
165 int ret;
166
167 ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
168 &val);
169 if (ret != 0) {
170 dev_err(arizona->dev, "Failed to read thermal status: %d\n",
171 ret);
172 } else if (val & ARIZONA_SPK_SHUTDOWN_STS) {
173 dev_crit(arizona->dev, "Thermal shutdown\n");
Mark Brownf4a76e72013-03-13 12:22:39 +0000174 ret = regmap_update_bits(arizona->regmap,
175 ARIZONA_OUTPUT_ENABLES_1,
176 ARIZONA_OUT4L_ENA |
177 ARIZONA_OUT4R_ENA, 0);
178 if (ret != 0)
179 dev_crit(arizona->dev,
180 "Failed to disable speaker outputs: %d\n",
181 ret);
Mark Brown899817e2013-03-13 12:32:10 +0000182 }
183
184 return IRQ_HANDLED;
185}
186
Mark Brown56447e12013-01-10 14:45:58 +0000187static const struct snd_soc_dapm_widget arizona_spkl =
Mark Brownf4a76e72013-03-13 12:22:39 +0000188 SND_SOC_DAPM_PGA_E("OUT4L", SND_SOC_NOPM,
Mark Brown56447e12013-01-10 14:45:58 +0000189 ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
190 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
191
192static const struct snd_soc_dapm_widget arizona_spkr =
Mark Brownf4a76e72013-03-13 12:22:39 +0000193 SND_SOC_DAPM_PGA_E("OUT4R", SND_SOC_NOPM,
Mark Brown56447e12013-01-10 14:45:58 +0000194 ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
195 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
196
197int arizona_init_spk(struct snd_soc_codec *codec)
198{
Mark Brown899817e2013-03-13 12:32:10 +0000199 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
200 struct arizona *arizona = priv->arizona;
Mark Brown56447e12013-01-10 14:45:58 +0000201 int ret;
202
203 ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkl, 1);
204 if (ret != 0)
205 return ret;
206
Charles Keepax40843ae2013-08-12 23:46:55 +0100207 switch (arizona->type) {
208 case WM8997:
209 break;
210 default:
211 ret = snd_soc_dapm_new_controls(&codec->dapm,
212 &arizona_spkr, 1);
213 if (ret != 0)
214 return ret;
215 break;
216 }
Mark Brown56447e12013-01-10 14:45:58 +0000217
Mark Brown899817e2013-03-13 12:32:10 +0000218 ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN_WARN,
219 "Thermal warning", arizona_thermal_warn,
220 arizona);
221 if (ret != 0)
222 dev_err(arizona->dev,
223 "Failed to get thermal warning IRQ: %d\n",
224 ret);
225
226 ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN,
227 "Thermal shutdown", arizona_thermal_shutdown,
228 arizona);
229 if (ret != 0)
230 dev_err(arizona->dev,
231 "Failed to get thermal shutdown IRQ: %d\n",
232 ret);
233
Mark Brown56447e12013-01-10 14:45:58 +0000234 return 0;
235}
236EXPORT_SYMBOL_GPL(arizona_init_spk);
237
Charles Keepaxb63144e2013-07-04 08:56:28 +0100238int arizona_init_gpio(struct snd_soc_codec *codec)
239{
240 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
241 struct arizona *arizona = priv->arizona;
242 int i;
243
244 switch (arizona->type) {
245 case WM5110:
246 snd_soc_dapm_disable_pin(&codec->dapm, "DRC2 Signal Activity");
Charles Keepaxb79fae62013-07-04 16:53:03 +0100247 break;
248 default:
249 break;
Charles Keepaxb63144e2013-07-04 08:56:28 +0100250 }
251
252 snd_soc_dapm_disable_pin(&codec->dapm, "DRC1 Signal Activity");
253
254 for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
255 switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) {
256 case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT:
257 snd_soc_dapm_enable_pin(&codec->dapm,
258 "DRC1 Signal Activity");
259 break;
260 case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT:
261 snd_soc_dapm_enable_pin(&codec->dapm,
262 "DRC2 Signal Activity");
263 break;
264 default:
265 break;
266 }
267 }
268
269 return 0;
270}
271EXPORT_SYMBOL_GPL(arizona_init_gpio);
272
Mark Brown07ed8732012-06-18 21:08:44 +0100273const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
274 "None",
275 "Tone Generator 1",
276 "Tone Generator 2",
277 "Haptics",
278 "AEC",
279 "Mic Mute Mixer",
280 "Noise Generator",
281 "IN1L",
282 "IN1R",
283 "IN2L",
284 "IN2R",
285 "IN3L",
286 "IN3R",
Mark Brownc9c56fd2012-07-09 19:09:01 +0100287 "IN4L",
288 "IN4R",
Mark Brown07ed8732012-06-18 21:08:44 +0100289 "AIF1RX1",
290 "AIF1RX2",
291 "AIF1RX3",
292 "AIF1RX4",
293 "AIF1RX5",
294 "AIF1RX6",
295 "AIF1RX7",
296 "AIF1RX8",
297 "AIF2RX1",
298 "AIF2RX2",
Richard Fitzgeralde64001e2013-11-20 13:17:07 +0000299 "AIF2RX3",
300 "AIF2RX4",
301 "AIF2RX5",
302 "AIF2RX6",
Mark Brown07ed8732012-06-18 21:08:44 +0100303 "AIF3RX1",
304 "AIF3RX2",
305 "SLIMRX1",
306 "SLIMRX2",
307 "SLIMRX3",
308 "SLIMRX4",
309 "SLIMRX5",
310 "SLIMRX6",
311 "SLIMRX7",
312 "SLIMRX8",
313 "EQ1",
314 "EQ2",
315 "EQ3",
316 "EQ4",
317 "DRC1L",
318 "DRC1R",
319 "DRC2L",
320 "DRC2R",
321 "LHPF1",
322 "LHPF2",
323 "LHPF3",
324 "LHPF4",
325 "DSP1.1",
326 "DSP1.2",
327 "DSP1.3",
328 "DSP1.4",
329 "DSP1.5",
330 "DSP1.6",
Mark Brownc922cc42012-09-26 16:43:44 +0100331 "DSP2.1",
332 "DSP2.2",
333 "DSP2.3",
334 "DSP2.4",
335 "DSP2.5",
336 "DSP2.6",
337 "DSP3.1",
338 "DSP3.2",
339 "DSP3.3",
340 "DSP3.4",
341 "DSP3.5",
342 "DSP3.6",
343 "DSP4.1",
344 "DSP4.2",
345 "DSP4.3",
346 "DSP4.4",
347 "DSP4.5",
348 "DSP4.6",
Mark Brown07ed8732012-06-18 21:08:44 +0100349 "ASRC1L",
350 "ASRC1R",
351 "ASRC2L",
352 "ASRC2R",
Mark Brown91660bd2012-12-05 20:35:24 +0900353 "ISRC1INT1",
354 "ISRC1INT2",
355 "ISRC1INT3",
356 "ISRC1INT4",
357 "ISRC1DEC1",
358 "ISRC1DEC2",
359 "ISRC1DEC3",
360 "ISRC1DEC4",
361 "ISRC2INT1",
362 "ISRC2INT2",
363 "ISRC2INT3",
364 "ISRC2INT4",
365 "ISRC2DEC1",
366 "ISRC2DEC2",
367 "ISRC2DEC3",
368 "ISRC2DEC4",
369 "ISRC3INT1",
370 "ISRC3INT2",
371 "ISRC3INT3",
372 "ISRC3INT4",
373 "ISRC3DEC1",
374 "ISRC3DEC2",
375 "ISRC3DEC3",
376 "ISRC3DEC4",
Mark Brown07ed8732012-06-18 21:08:44 +0100377};
378EXPORT_SYMBOL_GPL(arizona_mixer_texts);
379
380int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
381 0x00, /* None */
382 0x04, /* Tone */
383 0x05,
384 0x06, /* Haptics */
385 0x08, /* AEC */
386 0x0c, /* Noise mixer */
387 0x0d, /* Comfort noise */
388 0x10, /* IN1L */
389 0x11,
390 0x12,
391 0x13,
392 0x14,
393 0x15,
Mark Brownc9c56fd2012-07-09 19:09:01 +0100394 0x16,
395 0x17,
Mark Brown07ed8732012-06-18 21:08:44 +0100396 0x20, /* AIF1RX1 */
397 0x21,
398 0x22,
399 0x23,
400 0x24,
401 0x25,
402 0x26,
403 0x27,
404 0x28, /* AIF2RX1 */
405 0x29,
Richard Fitzgeralde64001e2013-11-20 13:17:07 +0000406 0x2a,
407 0x2b,
408 0x2c,
409 0x2d,
Mark Brown07ed8732012-06-18 21:08:44 +0100410 0x30, /* AIF3RX1 */
411 0x31,
412 0x38, /* SLIMRX1 */
413 0x39,
414 0x3a,
415 0x3b,
416 0x3c,
417 0x3d,
418 0x3e,
419 0x3f,
420 0x50, /* EQ1 */
421 0x51,
422 0x52,
423 0x53,
424 0x58, /* DRC1L */
425 0x59,
426 0x5a,
427 0x5b,
428 0x60, /* LHPF1 */
429 0x61,
430 0x62,
431 0x63,
432 0x68, /* DSP1.1 */
433 0x69,
434 0x6a,
435 0x6b,
436 0x6c,
437 0x6d,
Mark Brownc922cc42012-09-26 16:43:44 +0100438 0x70, /* DSP2.1 */
439 0x71,
440 0x72,
441 0x73,
442 0x74,
443 0x75,
444 0x78, /* DSP3.1 */
445 0x79,
446 0x7a,
447 0x7b,
448 0x7c,
449 0x7d,
450 0x80, /* DSP4.1 */
451 0x81,
452 0x82,
453 0x83,
454 0x84,
455 0x85,
Mark Brown07ed8732012-06-18 21:08:44 +0100456 0x90, /* ASRC1L */
457 0x91,
458 0x92,
459 0x93,
Mark Brown91660bd2012-12-05 20:35:24 +0900460 0xa0, /* ISRC1INT1 */
461 0xa1,
462 0xa2,
463 0xa3,
464 0xa4, /* ISRC1DEC1 */
465 0xa5,
466 0xa6,
467 0xa7,
468 0xa8, /* ISRC2DEC1 */
469 0xa9,
470 0xaa,
471 0xab,
472 0xac, /* ISRC2INT1 */
473 0xad,
474 0xae,
475 0xaf,
476 0xb0, /* ISRC3DEC1 */
477 0xb1,
478 0xb2,
479 0xb3,
480 0xb4, /* ISRC3INT1 */
481 0xb5,
482 0xb6,
483 0xb7,
Mark Brown07ed8732012-06-18 21:08:44 +0100484};
485EXPORT_SYMBOL_GPL(arizona_mixer_values);
486
487const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
488EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
489
Mark Browndc914282013-02-18 19:09:23 +0000490const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = {
491 "SYNCCLK rate", "8kHz", "16kHz", "ASYNCCLK rate",
492};
493EXPORT_SYMBOL_GPL(arizona_rate_text);
494
495const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
496 0, 1, 2, 8,
497};
498EXPORT_SYMBOL_GPL(arizona_rate_val);
499
500
Charles Keepaxfbedc8c2013-12-19 09:30:12 +0000501const struct soc_enum arizona_isrc_fsh[] = {
502 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_1,
503 ARIZONA_ISRC1_FSH_SHIFT, 0xf,
504 ARIZONA_RATE_ENUM_SIZE,
505 arizona_rate_text, arizona_rate_val),
506 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_1,
507 ARIZONA_ISRC2_FSH_SHIFT, 0xf,
508 ARIZONA_RATE_ENUM_SIZE,
509 arizona_rate_text, arizona_rate_val),
510 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_1,
511 ARIZONA_ISRC3_FSH_SHIFT, 0xf,
512 ARIZONA_RATE_ENUM_SIZE,
513 arizona_rate_text, arizona_rate_val),
514};
515EXPORT_SYMBOL_GPL(arizona_isrc_fsh);
516
Mark Browndc914282013-02-18 19:09:23 +0000517const struct soc_enum arizona_isrc_fsl[] = {
518 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2,
519 ARIZONA_ISRC1_FSL_SHIFT, 0xf,
520 ARIZONA_RATE_ENUM_SIZE,
521 arizona_rate_text, arizona_rate_val),
522 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_2,
523 ARIZONA_ISRC2_FSL_SHIFT, 0xf,
524 ARIZONA_RATE_ENUM_SIZE,
525 arizona_rate_text, arizona_rate_val),
526 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_2,
527 ARIZONA_ISRC3_FSL_SHIFT, 0xf,
528 ARIZONA_RATE_ENUM_SIZE,
529 arizona_rate_text, arizona_rate_val),
530};
531EXPORT_SYMBOL_GPL(arizona_isrc_fsl);
532
Charles Keepax56d37d82013-12-19 09:30:13 +0000533const struct soc_enum arizona_asrc_rate1 =
534 SOC_VALUE_ENUM_SINGLE(ARIZONA_ASRC_RATE1,
535 ARIZONA_ASRC_RATE1_SHIFT, 0xf,
536 ARIZONA_RATE_ENUM_SIZE - 1,
537 arizona_rate_text, arizona_rate_val);
538EXPORT_SYMBOL_GPL(arizona_asrc_rate1);
539
Mark Browne853a002012-12-09 12:25:52 +0900540static const char *arizona_vol_ramp_text[] = {
541 "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
542 "15ms/6dB", "30ms/6dB",
543};
544
545const struct soc_enum arizona_in_vd_ramp =
546 SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP,
547 ARIZONA_IN_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text);
548EXPORT_SYMBOL_GPL(arizona_in_vd_ramp);
549
550const struct soc_enum arizona_in_vi_ramp =
551 SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP,
552 ARIZONA_IN_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text);
553EXPORT_SYMBOL_GPL(arizona_in_vi_ramp);
554
555const struct soc_enum arizona_out_vd_ramp =
556 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP,
557 ARIZONA_OUT_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text);
558EXPORT_SYMBOL_GPL(arizona_out_vd_ramp);
559
560const struct soc_enum arizona_out_vi_ramp =
561 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP,
562 ARIZONA_OUT_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text);
563EXPORT_SYMBOL_GPL(arizona_out_vi_ramp);
564
Mark Brown07ed8732012-06-18 21:08:44 +0100565static const char *arizona_lhpf_mode_text[] = {
566 "Low-pass", "High-pass"
567};
568
569const struct soc_enum arizona_lhpf1_mode =
570 SOC_ENUM_SINGLE(ARIZONA_HPLPF1_1, ARIZONA_LHPF1_MODE_SHIFT, 2,
571 arizona_lhpf_mode_text);
572EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
573
574const struct soc_enum arizona_lhpf2_mode =
575 SOC_ENUM_SINGLE(ARIZONA_HPLPF2_1, ARIZONA_LHPF2_MODE_SHIFT, 2,
576 arizona_lhpf_mode_text);
577EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
578
579const struct soc_enum arizona_lhpf3_mode =
580 SOC_ENUM_SINGLE(ARIZONA_HPLPF3_1, ARIZONA_LHPF3_MODE_SHIFT, 2,
581 arizona_lhpf_mode_text);
582EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
583
584const struct soc_enum arizona_lhpf4_mode =
585 SOC_ENUM_SINGLE(ARIZONA_HPLPF4_1, ARIZONA_LHPF4_MODE_SHIFT, 2,
586 arizona_lhpf_mode_text);
587EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
588
Mark Brown845571c2012-12-18 13:47:57 +0000589static const char *arizona_ng_hold_text[] = {
590 "30ms", "120ms", "250ms", "500ms",
591};
592
593const struct soc_enum arizona_ng_hold =
594 SOC_ENUM_SINGLE(ARIZONA_NOISE_GATE_CONTROL, ARIZONA_NGATE_HOLD_SHIFT,
595 4, arizona_ng_hold_text);
596EXPORT_SYMBOL_GPL(arizona_ng_hold);
597
Charles Keepax254dc322013-11-19 16:04:03 +0000598static const char * const arizona_in_hpf_cut_text[] = {
599 "2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz"
600};
601
602const struct soc_enum arizona_in_hpf_cut_enum =
603 SOC_ENUM_SINGLE(ARIZONA_HPF_CONTROL, ARIZONA_IN_HPF_CUT_SHIFT,
604 ARRAY_SIZE(arizona_in_hpf_cut_text),
605 arizona_in_hpf_cut_text);
606EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum);
607
Charles Keepaxc7f38432013-08-06 17:03:55 +0100608static const char * const arizona_in_dmic_osr_text[] = {
609 "1.536MHz", "3.072MHz", "6.144MHz",
610};
611
612const struct soc_enum arizona_in_dmic_osr[] = {
613 SOC_ENUM_SINGLE(ARIZONA_IN1L_CONTROL, ARIZONA_IN1_OSR_SHIFT,
614 ARRAY_SIZE(arizona_in_dmic_osr_text),
615 arizona_in_dmic_osr_text),
616 SOC_ENUM_SINGLE(ARIZONA_IN2L_CONTROL, ARIZONA_IN2_OSR_SHIFT,
617 ARRAY_SIZE(arizona_in_dmic_osr_text),
618 arizona_in_dmic_osr_text),
619 SOC_ENUM_SINGLE(ARIZONA_IN3L_CONTROL, ARIZONA_IN3_OSR_SHIFT,
620 ARRAY_SIZE(arizona_in_dmic_osr_text),
621 arizona_in_dmic_osr_text),
622 SOC_ENUM_SINGLE(ARIZONA_IN4L_CONTROL, ARIZONA_IN4_OSR_SHIFT,
623 ARRAY_SIZE(arizona_in_dmic_osr_text),
624 arizona_in_dmic_osr_text),
625};
626EXPORT_SYMBOL_GPL(arizona_in_dmic_osr);
627
Mark Brownddbce972013-02-15 17:27:22 +0000628static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
629{
630 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
631 unsigned int val;
632 int i;
633
634 if (ena)
635 val = ARIZONA_IN_VU;
636 else
637 val = 0;
638
639 for (i = 0; i < priv->num_inputs; i++)
640 snd_soc_update_bits(codec,
641 ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 4),
642 ARIZONA_IN_VU, val);
643}
644
Mark Brown07ed8732012-06-18 21:08:44 +0100645int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
646 int event)
647{
Mark Brownddbce972013-02-15 17:27:22 +0000648 struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000649 unsigned int reg;
650
651 if (w->shift % 2)
652 reg = ARIZONA_ADC_DIGITAL_VOLUME_1L + ((w->shift / 2) * 8);
653 else
654 reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8);
655
656 switch (event) {
Mark Brownddbce972013-02-15 17:27:22 +0000657 case SND_SOC_DAPM_PRE_PMU:
658 priv->in_pending++;
659 break;
Mark Brown43cd8bf2013-02-06 16:57:29 +0000660 case SND_SOC_DAPM_POST_PMU:
661 snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, 0);
Mark Brownddbce972013-02-15 17:27:22 +0000662
663 /* If this is the last input pending then allow VU */
664 priv->in_pending--;
665 if (priv->in_pending == 0) {
666 msleep(1);
667 arizona_in_set_vu(w->codec, 1);
668 }
Mark Brown43cd8bf2013-02-06 16:57:29 +0000669 break;
670 case SND_SOC_DAPM_PRE_PMD:
Mark Brownddbce972013-02-15 17:27:22 +0000671 snd_soc_update_bits(w->codec, reg,
672 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU,
673 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000674 break;
Mark Brownddbce972013-02-15 17:27:22 +0000675 case SND_SOC_DAPM_POST_PMD:
676 /* Disable volume updates if no inputs are enabled */
677 reg = snd_soc_read(w->codec, ARIZONA_INPUT_ENABLES);
678 if (reg == 0)
679 arizona_in_set_vu(w->codec, 0);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000680 }
681
Mark Brown07ed8732012-06-18 21:08:44 +0100682 return 0;
683}
684EXPORT_SYMBOL_GPL(arizona_in_ev);
685
686int arizona_out_ev(struct snd_soc_dapm_widget *w,
687 struct snd_kcontrol *kcontrol,
688 int event)
689{
Mark Brown1a2c7d52013-03-24 22:50:23 +0000690 switch (event) {
691 case SND_SOC_DAPM_POST_PMU:
692 switch (w->shift) {
693 case ARIZONA_OUT1L_ENA_SHIFT:
694 case ARIZONA_OUT1R_ENA_SHIFT:
695 case ARIZONA_OUT2L_ENA_SHIFT:
696 case ARIZONA_OUT2R_ENA_SHIFT:
697 case ARIZONA_OUT3L_ENA_SHIFT:
698 case ARIZONA_OUT3R_ENA_SHIFT:
699 msleep(17);
700 break;
701
702 default:
703 break;
704 }
705 break;
706 }
707
Mark Brown07ed8732012-06-18 21:08:44 +0100708 return 0;
709}
710EXPORT_SYMBOL_GPL(arizona_out_ev);
711
Mark Brownf607e312013-02-22 18:36:53 +0000712int arizona_hp_ev(struct snd_soc_dapm_widget *w,
713 struct snd_kcontrol *kcontrol,
714 int event)
715{
716 struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
Mark Brown3c43c692013-12-12 00:49:22 +0000717 struct arizona *arizona = priv->arizona;
Mark Brownf607e312013-02-22 18:36:53 +0000718 unsigned int mask = 1 << w->shift;
719 unsigned int val;
720
721 switch (event) {
722 case SND_SOC_DAPM_POST_PMU:
723 val = mask;
724 break;
725 case SND_SOC_DAPM_PRE_PMD:
726 val = 0;
727 break;
728 default:
729 return -EINVAL;
730 }
731
732 /* Store the desired state for the HP outputs */
733 priv->arizona->hp_ena &= ~mask;
734 priv->arizona->hp_ena |= val;
735
736 /* Force off if HPDET magic is active */
737 if (priv->arizona->hpdet_magic)
738 val = 0;
739
Mark Brown3c43c692013-12-12 00:49:22 +0000740 regmap_update_bits_async(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1,
741 mask, val);
Mark Brownf607e312013-02-22 18:36:53 +0000742
743 return arizona_out_ev(w, kcontrol, event);
744}
745EXPORT_SYMBOL_GPL(arizona_hp_ev);
746
Mark Browncbd840d2012-08-08 17:52:44 +0100747static unsigned int arizona_sysclk_48k_rates[] = {
748 6144000,
749 12288000,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000750 24576000,
Mark Browncbd840d2012-08-08 17:52:44 +0100751 49152000,
Mark Brownaeaeee12012-09-26 17:50:02 +0100752 73728000,
753 98304000,
754 147456000,
Mark Browncbd840d2012-08-08 17:52:44 +0100755};
756
757static unsigned int arizona_sysclk_44k1_rates[] = {
758 5644800,
759 11289600,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000760 22579200,
Mark Browncbd840d2012-08-08 17:52:44 +0100761 45158400,
Mark Brownaeaeee12012-09-26 17:50:02 +0100762 67737600,
763 90316800,
764 135475200,
Mark Browncbd840d2012-08-08 17:52:44 +0100765};
766
767static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
768 unsigned int freq)
769{
770 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
771 unsigned int reg;
772 unsigned int *rates;
773 int ref, div, refclk;
774
775 switch (clk) {
776 case ARIZONA_CLK_OPCLK:
777 reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
778 refclk = priv->sysclk;
779 break;
780 case ARIZONA_CLK_ASYNC_OPCLK:
781 reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
782 refclk = priv->asyncclk;
783 break;
784 default:
785 return -EINVAL;
786 }
787
788 if (refclk % 8000)
789 rates = arizona_sysclk_44k1_rates;
790 else
791 rates = arizona_sysclk_48k_rates;
792
793 for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) &&
794 rates[ref] <= refclk; ref++) {
795 div = 1;
796 while (rates[ref] / div >= freq && div < 32) {
797 if (rates[ref] / div == freq) {
798 dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
799 freq);
800 snd_soc_update_bits(codec, reg,
801 ARIZONA_OPCLK_DIV_MASK |
802 ARIZONA_OPCLK_SEL_MASK,
803 (div <<
804 ARIZONA_OPCLK_DIV_SHIFT) |
805 ref);
806 return 0;
807 }
808 div++;
809 }
810 }
811
812 dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
813 return -EINVAL;
814}
815
Mark Brown07ed8732012-06-18 21:08:44 +0100816int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
817 int source, unsigned int freq, int dir)
818{
819 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
820 struct arizona *arizona = priv->arizona;
821 char *name;
822 unsigned int reg;
823 unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
824 unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
825 unsigned int *clk;
826
827 switch (clk_id) {
828 case ARIZONA_CLK_SYSCLK:
829 name = "SYSCLK";
830 reg = ARIZONA_SYSTEM_CLOCK_1;
831 clk = &priv->sysclk;
832 mask |= ARIZONA_SYSCLK_FRAC;
833 break;
834 case ARIZONA_CLK_ASYNCCLK:
835 name = "ASYNCCLK";
836 reg = ARIZONA_ASYNC_CLOCK_1;
837 clk = &priv->asyncclk;
838 break;
Mark Browncbd840d2012-08-08 17:52:44 +0100839 case ARIZONA_CLK_OPCLK:
840 case ARIZONA_CLK_ASYNC_OPCLK:
841 return arizona_set_opclk(codec, clk_id, freq);
Mark Brown07ed8732012-06-18 21:08:44 +0100842 default:
843 return -EINVAL;
844 }
845
846 switch (freq) {
847 case 5644800:
848 case 6144000:
849 break;
850 case 11289600:
851 case 12288000:
Mark Brown3f341f72013-03-08 15:22:29 +0800852 val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100853 break;
854 case 22579200:
855 case 24576000:
Mark Brown3f341f72013-03-08 15:22:29 +0800856 val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100857 break;
858 case 45158400:
859 case 49152000:
Mark Brown3f341f72013-03-08 15:22:29 +0800860 val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100861 break;
Mark Brown38113362012-11-26 16:01:37 +0000862 case 67737600:
863 case 73728000:
Mark Brown3f341f72013-03-08 15:22:29 +0800864 val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000865 break;
866 case 90316800:
867 case 98304000:
Mark Brown3f341f72013-03-08 15:22:29 +0800868 val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000869 break;
870 case 135475200:
871 case 147456000:
Mark Brown3f341f72013-03-08 15:22:29 +0800872 val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000873 break;
Mark Brownf2c26d42013-01-21 16:09:36 +0900874 case 0:
875 dev_dbg(arizona->dev, "%s cleared\n", name);
876 *clk = freq;
877 return 0;
Mark Brown07ed8732012-06-18 21:08:44 +0100878 default:
879 return -EINVAL;
880 }
881
882 *clk = freq;
883
884 if (freq % 6144000)
885 val |= ARIZONA_SYSCLK_FRAC;
886
887 dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
888
889 return regmap_update_bits(arizona->regmap, reg, mask, val);
890}
891EXPORT_SYMBOL_GPL(arizona_set_sysclk);
892
893static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
894{
895 struct snd_soc_codec *codec = dai->codec;
Mark Brown3c43c692013-12-12 00:49:22 +0000896 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
897 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +0100898 int lrclk, bclk, mode, base;
899
900 base = dai->driver->base;
901
902 lrclk = 0;
903 bclk = 0;
904
905 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
906 case SND_SOC_DAIFMT_DSP_A:
907 mode = 0;
908 break;
Mark Brown07ed8732012-06-18 21:08:44 +0100909 case SND_SOC_DAIFMT_I2S:
910 mode = 2;
911 break;
Mark Brown07ed8732012-06-18 21:08:44 +0100912 default:
913 arizona_aif_err(dai, "Unsupported DAI format %d\n",
914 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
915 return -EINVAL;
916 }
917
918 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
919 case SND_SOC_DAIFMT_CBS_CFS:
920 break;
921 case SND_SOC_DAIFMT_CBS_CFM:
922 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
923 break;
924 case SND_SOC_DAIFMT_CBM_CFS:
925 bclk |= ARIZONA_AIF1_BCLK_MSTR;
926 break;
927 case SND_SOC_DAIFMT_CBM_CFM:
928 bclk |= ARIZONA_AIF1_BCLK_MSTR;
929 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
930 break;
931 default:
932 arizona_aif_err(dai, "Unsupported master mode %d\n",
933 fmt & SND_SOC_DAIFMT_MASTER_MASK);
934 return -EINVAL;
935 }
936
937 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
938 case SND_SOC_DAIFMT_NB_NF:
939 break;
940 case SND_SOC_DAIFMT_IB_IF:
941 bclk |= ARIZONA_AIF1_BCLK_INV;
942 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
943 break;
944 case SND_SOC_DAIFMT_IB_NF:
945 bclk |= ARIZONA_AIF1_BCLK_INV;
946 break;
947 case SND_SOC_DAIFMT_NB_IF:
948 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
949 break;
950 default:
951 return -EINVAL;
952 }
953
Mark Brown3c43c692013-12-12 00:49:22 +0000954 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_BCLK_CTRL,
955 ARIZONA_AIF1_BCLK_INV |
956 ARIZONA_AIF1_BCLK_MSTR,
957 bclk);
958 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_TX_PIN_CTRL,
959 ARIZONA_AIF1TX_LRCLK_INV |
960 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
961 regmap_update_bits_async(arizona->regmap,
962 base + ARIZONA_AIF_RX_PIN_CTRL,
963 ARIZONA_AIF1RX_LRCLK_INV |
964 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
965 regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FORMAT,
966 ARIZONA_AIF1_FMT_MASK, mode);
Mark Brown07ed8732012-06-18 21:08:44 +0100967
968 return 0;
969}
970
Mark Brown949e6bc2012-07-04 18:58:04 +0100971static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100972 -1,
973 48000,
974 64000,
975 96000,
976 128000,
977 192000,
978 256000,
979 384000,
980 512000,
981 768000,
982 1024000,
983 1536000,
984 2048000,
985 3072000,
986 4096000,
987 6144000,
988 8192000,
989 12288000,
990 24576000,
991};
992
Mark Brown5b2eec32012-07-04 17:32:05 +0100993static const unsigned int arizona_48k_rates[] = {
994 12000,
995 24000,
996 48000,
997 96000,
998 192000,
999 384000,
1000 768000,
1001 4000,
1002 8000,
1003 16000,
1004 32000,
1005 64000,
1006 128000,
1007 256000,
1008 512000,
1009};
1010
1011static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = {
1012 .count = ARRAY_SIZE(arizona_48k_rates),
1013 .list = arizona_48k_rates,
1014};
1015
Mark Brown949e6bc2012-07-04 18:58:04 +01001016static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +01001017 -1,
1018 44100,
1019 58800,
1020 88200,
1021 117600,
1022 177640,
1023 235200,
1024 352800,
1025 470400,
1026 705600,
1027 940800,
1028 1411200,
1029 1881600,
Heather Lomond4758be32012-09-05 05:02:10 -04001030 2822400,
Mark Brown07ed8732012-06-18 21:08:44 +01001031 3763200,
1032 5644800,
1033 7526400,
1034 11289600,
1035 22579200,
1036};
1037
Mark Brown5b2eec32012-07-04 17:32:05 +01001038static const unsigned int arizona_44k1_rates[] = {
1039 11025,
1040 22050,
1041 44100,
1042 88200,
1043 176400,
1044 352800,
1045 705600,
1046};
1047
1048static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = {
1049 .count = ARRAY_SIZE(arizona_44k1_rates),
1050 .list = arizona_44k1_rates,
1051};
1052
Mark Brown07ed8732012-06-18 21:08:44 +01001053static int arizona_sr_vals[] = {
1054 0,
1055 12000,
1056 24000,
1057 48000,
1058 96000,
1059 192000,
1060 384000,
1061 768000,
1062 0,
1063 11025,
1064 22050,
1065 44100,
1066 88200,
1067 176400,
1068 352800,
1069 705600,
1070 4000,
1071 8000,
1072 16000,
1073 32000,
1074 64000,
1075 128000,
1076 256000,
1077 512000,
1078};
1079
Mark Brown5b2eec32012-07-04 17:32:05 +01001080static int arizona_startup(struct snd_pcm_substream *substream,
1081 struct snd_soc_dai *dai)
1082{
1083 struct snd_soc_codec *codec = dai->codec;
1084 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1085 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
1086 const struct snd_pcm_hw_constraint_list *constraint;
1087 unsigned int base_rate;
1088
1089 switch (dai_priv->clk) {
1090 case ARIZONA_CLK_SYSCLK:
1091 base_rate = priv->sysclk;
1092 break;
1093 case ARIZONA_CLK_ASYNCCLK:
1094 base_rate = priv->asyncclk;
1095 break;
1096 default:
1097 return 0;
1098 }
1099
Mark Brownf2c26d42013-01-21 16:09:36 +09001100 if (base_rate == 0)
1101 return 0;
1102
Mark Brown5b2eec32012-07-04 17:32:05 +01001103 if (base_rate % 8000)
1104 constraint = &arizona_44k1_constraint;
1105 else
1106 constraint = &arizona_48k_constraint;
1107
1108 return snd_pcm_hw_constraint_list(substream->runtime, 0,
1109 SNDRV_PCM_HW_PARAM_RATE,
1110 constraint);
1111}
1112
Mark Brownb272efc2012-10-10 15:10:08 +09001113static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
1114 struct snd_pcm_hw_params *params,
1115 struct snd_soc_dai *dai)
Mark Brown07ed8732012-06-18 21:08:44 +01001116{
1117 struct snd_soc_codec *codec = dai->codec;
Mark Brownc013b272012-07-04 20:05:57 +01001118 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1119 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown07ed8732012-06-18 21:08:44 +01001120 int base = dai->driver->base;
Mark Brownb272efc2012-10-10 15:10:08 +09001121 int i, sr_val;
1122
1123 /*
1124 * We will need to be more flexible than this in future,
1125 * currently we use a single sample rate for SYSCLK.
1126 */
1127 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
1128 if (arizona_sr_vals[i] == params_rate(params))
1129 break;
1130 if (i == ARRAY_SIZE(arizona_sr_vals)) {
1131 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1132 params_rate(params));
1133 return -EINVAL;
1134 }
1135 sr_val = i;
1136
1137 switch (dai_priv->clk) {
1138 case ARIZONA_CLK_SYSCLK:
1139 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
1140 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
1141 if (base)
1142 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1143 ARIZONA_AIF1_RATE_MASK, 0);
1144 break;
1145 case ARIZONA_CLK_ASYNCCLK:
1146 snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
1147 ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val);
1148 if (base)
1149 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1150 ARIZONA_AIF1_RATE_MASK,
1151 8 << ARIZONA_AIF1_RATE_SHIFT);
1152 break;
1153 default:
1154 arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
1155 return -EINVAL;
1156 }
1157
1158 return 0;
1159}
1160
Mark Brown07ed8732012-06-18 21:08:44 +01001161static int arizona_hw_params(struct snd_pcm_substream *substream,
1162 struct snd_pcm_hw_params *params,
1163 struct snd_soc_dai *dai)
1164{
1165 struct snd_soc_codec *codec = dai->codec;
1166 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brownc94aa302013-01-17 16:35:14 +09001167 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +01001168 int base = dai->driver->base;
1169 const int *rates;
Mark Brown76bf9692013-03-05 14:17:47 +08001170 int i, ret, val;
Mark Brownc94aa302013-01-17 16:35:14 +09001171 int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
1172 int bclk, lrclk, wl, frame, bclk_target;
Mark Brown07ed8732012-06-18 21:08:44 +01001173
1174 if (params_rate(params) % 8000)
Mark Brown949e6bc2012-07-04 18:58:04 +01001175 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001176 else
Mark Brown949e6bc2012-07-04 18:58:04 +01001177 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001178
Mark Brownc94aa302013-01-17 16:35:14 +09001179 bclk_target = snd_soc_params_to_bclk(params);
1180 if (chan_limit && chan_limit < params_channels(params)) {
1181 arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
1182 bclk_target /= params_channels(params);
1183 bclk_target *= chan_limit;
1184 }
1185
Mark Brown76bf9692013-03-05 14:17:47 +08001186 /* Force stereo for I2S mode */
1187 val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
1188 if (params_channels(params) == 1 && (val & ARIZONA_AIF1_FMT_MASK)) {
1189 arizona_aif_dbg(dai, "Forcing stereo mode\n");
1190 bclk_target *= 2;
1191 }
1192
Mark Brown949e6bc2012-07-04 18:58:04 +01001193 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brownc94aa302013-01-17 16:35:14 +09001194 if (rates[i] >= bclk_target &&
Mark Brown50017652012-07-04 19:07:09 +01001195 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +01001196 bclk = i;
1197 break;
1198 }
1199 }
Mark Brown949e6bc2012-07-04 18:58:04 +01001200 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001201 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1202 params_rate(params));
1203 return -EINVAL;
1204 }
1205
Mark Brownb59e0f82013-01-17 14:15:59 +09001206 lrclk = rates[bclk] / params_rate(params);
Mark Brown07ed8732012-06-18 21:08:44 +01001207
1208 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
1209 rates[bclk], rates[bclk] / lrclk);
1210
1211 wl = snd_pcm_format_width(params_format(params));
1212 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl;
1213
Mark Brownb272efc2012-10-10 15:10:08 +09001214 ret = arizona_hw_params_rate(substream, params, dai);
1215 if (ret != 0)
1216 return ret;
Mark Brownc013b272012-07-04 20:05:57 +01001217
Mark Brown3c43c692013-12-12 00:49:22 +00001218 regmap_update_bits_async(arizona->regmap,
1219 base + ARIZONA_AIF_BCLK_CTRL,
1220 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
1221 regmap_update_bits_async(arizona->regmap,
1222 base + ARIZONA_AIF_TX_BCLK_RATE,
1223 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
1224 regmap_update_bits_async(arizona->regmap,
1225 base + ARIZONA_AIF_RX_BCLK_RATE,
1226 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
1227 regmap_update_bits_async(arizona->regmap,
1228 base + ARIZONA_AIF_FRAME_CTRL_1,
1229 ARIZONA_AIF1TX_WL_MASK |
1230 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
1231 regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FRAME_CTRL_2,
1232 ARIZONA_AIF1RX_WL_MASK |
1233 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
Mark Brown07ed8732012-06-18 21:08:44 +01001234
1235 return 0;
1236}
1237
Mark Brown410837a2012-07-05 17:26:59 +01001238static const char *arizona_dai_clk_str(int clk_id)
1239{
1240 switch (clk_id) {
1241 case ARIZONA_CLK_SYSCLK:
1242 return "SYSCLK";
1243 case ARIZONA_CLK_ASYNCCLK:
1244 return "ASYNCCLK";
1245 default:
1246 return "Unknown clock";
1247 }
1248}
1249
Mark Brown5b2eec32012-07-04 17:32:05 +01001250static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
1251 int clk_id, unsigned int freq, int dir)
1252{
1253 struct snd_soc_codec *codec = dai->codec;
1254 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1255 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown410837a2012-07-05 17:26:59 +01001256 struct snd_soc_dapm_route routes[2];
Mark Brown5b2eec32012-07-04 17:32:05 +01001257
1258 switch (clk_id) {
1259 case ARIZONA_CLK_SYSCLK:
1260 case ARIZONA_CLK_ASYNCCLK:
1261 break;
1262 default:
1263 return -EINVAL;
1264 }
1265
Mark Brown410837a2012-07-05 17:26:59 +01001266 if (clk_id == dai_priv->clk)
1267 return 0;
1268
1269 if (dai->active) {
Mark Brown5b2eec32012-07-04 17:32:05 +01001270 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
1271 dai->id);
1272 return -EBUSY;
1273 }
1274
Mark Brownc8d35a62012-12-07 12:49:40 +09001275 dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1,
1276 arizona_dai_clk_str(clk_id));
1277
Mark Brown410837a2012-07-05 17:26:59 +01001278 memset(&routes, 0, sizeof(routes));
1279 routes[0].sink = dai->driver->capture.stream_name;
1280 routes[1].sink = dai->driver->playback.stream_name;
Mark Brown5b2eec32012-07-04 17:32:05 +01001281
Mark Brown410837a2012-07-05 17:26:59 +01001282 routes[0].source = arizona_dai_clk_str(dai_priv->clk);
1283 routes[1].source = arizona_dai_clk_str(dai_priv->clk);
1284 snd_soc_dapm_del_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
1285
1286 routes[0].source = arizona_dai_clk_str(clk_id);
1287 routes[1].source = arizona_dai_clk_str(clk_id);
1288 snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
1289
Mark Brown0c778e82012-12-06 18:22:25 +09001290 dai_priv->clk = clk_id;
1291
Mark Brown410837a2012-07-05 17:26:59 +01001292 return snd_soc_dapm_sync(&codec->dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +01001293}
1294
Mark Brown01df2592012-12-12 16:22:08 +09001295static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
1296{
1297 struct snd_soc_codec *codec = dai->codec;
1298 int base = dai->driver->base;
1299 unsigned int reg;
1300
1301 if (tristate)
1302 reg = ARIZONA_AIF1_TRI;
1303 else
1304 reg = 0;
1305
1306 return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1307 ARIZONA_AIF1_TRI, reg);
1308}
1309
Mark Brown07ed8732012-06-18 21:08:44 +01001310const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +01001311 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +01001312 .set_fmt = arizona_set_fmt,
1313 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +01001314 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown01df2592012-12-12 16:22:08 +09001315 .set_tristate = arizona_set_tristate,
Mark Brown07ed8732012-06-18 21:08:44 +01001316};
Mark Browna8379872012-07-09 12:16:41 +01001317EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +01001318
Mark Brownbd1dd882013-05-17 13:29:03 +01001319const struct snd_soc_dai_ops arizona_simple_dai_ops = {
1320 .startup = arizona_startup,
1321 .hw_params = arizona_hw_params_rate,
1322 .set_sysclk = arizona_dai_set_sysclk,
1323};
1324EXPORT_SYMBOL_GPL(arizona_simple_dai_ops);
1325
Mark Brown5b2eec32012-07-04 17:32:05 +01001326int arizona_init_dai(struct arizona_priv *priv, int id)
1327{
1328 struct arizona_dai_priv *dai_priv = &priv->dai[id];
1329
1330 dai_priv->clk = ARIZONA_CLK_SYSCLK;
1331
1332 return 0;
1333}
1334EXPORT_SYMBOL_GPL(arizona_init_dai);
1335
Mark Brown07ed8732012-06-18 21:08:44 +01001336static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
1337{
1338 struct arizona_fll *fll = data;
1339
1340 arizona_fll_dbg(fll, "clock OK\n");
1341
1342 complete(&fll->ok);
1343
1344 return IRQ_HANDLED;
1345}
1346
1347static struct {
1348 unsigned int min;
1349 unsigned int max;
1350 u16 fratio;
1351 int ratio;
1352} fll_fratios[] = {
1353 { 0, 64000, 4, 16 },
1354 { 64000, 128000, 3, 8 },
1355 { 128000, 256000, 2, 4 },
1356 { 256000, 1000000, 1, 2 },
1357 { 1000000, 13500000, 0, 1 },
1358};
1359
Mark Brown8f113d72013-03-05 12:08:57 +08001360static struct {
1361 unsigned int min;
1362 unsigned int max;
1363 u16 gain;
1364} fll_gains[] = {
1365 { 0, 256000, 0 },
1366 { 256000, 1000000, 2 },
1367 { 1000000, 13500000, 4 },
1368};
1369
Mark Brown07ed8732012-06-18 21:08:44 +01001370struct arizona_fll_cfg {
1371 int n;
1372 int theta;
1373 int lambda;
1374 int refdiv;
1375 int outdiv;
1376 int fratio;
Mark Brown8f113d72013-03-05 12:08:57 +08001377 int gain;
Mark Brown07ed8732012-06-18 21:08:44 +01001378};
1379
1380static int arizona_calc_fll(struct arizona_fll *fll,
1381 struct arizona_fll_cfg *cfg,
1382 unsigned int Fref,
1383 unsigned int Fout)
1384{
1385 unsigned int target, div, gcd_fll;
1386 int i, ratio;
1387
1388 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout);
1389
1390 /* Fref must be <=13.5MHz */
1391 div = 1;
1392 cfg->refdiv = 0;
1393 while ((Fref / div) > 13500000) {
1394 div *= 2;
1395 cfg->refdiv++;
1396
1397 if (div > 8) {
1398 arizona_fll_err(fll,
1399 "Can't scale %dMHz in to <=13.5MHz\n",
1400 Fref);
1401 return -EINVAL;
1402 }
1403 }
1404
1405 /* Apply the division for our remaining calculations */
1406 Fref /= div;
1407
Mark Brown2b4d39f2012-07-10 17:03:46 +01001408 /* Fvco should be over the targt; don't check the upper bound */
Charles Keepaxda28ed52014-03-07 16:34:17 +00001409 div = 2;
Mark Brown2b4d39f2012-07-10 17:03:46 +01001410 while (Fout * div < 90000000 * fll->vco_mult) {
Mark Brown07ed8732012-06-18 21:08:44 +01001411 div++;
1412 if (div > 7) {
1413 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
1414 Fout);
1415 return -EINVAL;
1416 }
1417 }
Mark Brown2b4d39f2012-07-10 17:03:46 +01001418 target = Fout * div / fll->vco_mult;
Mark Brown07ed8732012-06-18 21:08:44 +01001419 cfg->outdiv = div;
1420
1421 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
1422
1423 /* Find an appropraite FLL_FRATIO and factor it out of the target */
1424 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
1425 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
1426 cfg->fratio = fll_fratios[i].fratio;
1427 ratio = fll_fratios[i].ratio;
1428 break;
1429 }
1430 }
1431 if (i == ARRAY_SIZE(fll_fratios)) {
1432 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
1433 Fref);
1434 return -EINVAL;
1435 }
1436
Mark Brown8f113d72013-03-05 12:08:57 +08001437 for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
1438 if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
1439 cfg->gain = fll_gains[i].gain;
1440 break;
1441 }
1442 }
1443 if (i == ARRAY_SIZE(fll_gains)) {
1444 arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
1445 Fref);
1446 return -EINVAL;
1447 }
1448
Mark Brown07ed8732012-06-18 21:08:44 +01001449 cfg->n = target / (ratio * Fref);
1450
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001451 if (target % (ratio * Fref)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001452 gcd_fll = gcd(target, ratio * Fref);
1453 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
1454
1455 cfg->theta = (target - (cfg->n * ratio * Fref))
1456 / gcd_fll;
1457 cfg->lambda = (ratio * Fref) / gcd_fll;
1458 } else {
1459 cfg->theta = 0;
1460 cfg->lambda = 0;
1461 }
1462
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001463 /* Round down to 16bit range with cost of accuracy lost.
1464 * Denominator must be bigger than numerator so we only
1465 * take care of it.
1466 */
1467 while (cfg->lambda >= (1 << 16)) {
1468 cfg->theta >>= 1;
1469 cfg->lambda >>= 1;
1470 }
1471
Mark Brown07ed8732012-06-18 21:08:44 +01001472 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
1473 cfg->n, cfg->theta, cfg->lambda);
1474 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
1475 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08001476 arizona_fll_dbg(fll, "GAIN=%d\n", cfg->gain);
Mark Brown07ed8732012-06-18 21:08:44 +01001477
1478 return 0;
1479
1480}
1481
1482static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
Mark Brown8f113d72013-03-05 12:08:57 +08001483 struct arizona_fll_cfg *cfg, int source,
1484 bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01001485{
Mark Brown3c43c692013-12-12 00:49:22 +00001486 regmap_update_bits_async(arizona->regmap, base + 3,
1487 ARIZONA_FLL1_THETA_MASK, cfg->theta);
1488 regmap_update_bits_async(arizona->regmap, base + 4,
1489 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
1490 regmap_update_bits_async(arizona->regmap, base + 5,
1491 ARIZONA_FLL1_FRATIO_MASK,
1492 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
1493 regmap_update_bits_async(arizona->regmap, base + 6,
1494 ARIZONA_FLL1_CLK_REF_DIV_MASK |
1495 ARIZONA_FLL1_CLK_REF_SRC_MASK,
1496 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
1497 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
Mark Brown07ed8732012-06-18 21:08:44 +01001498
Mark Brown8f113d72013-03-05 12:08:57 +08001499 if (sync)
Mark Brown3c43c692013-12-12 00:49:22 +00001500 regmap_update_bits_async(arizona->regmap, base + 0x7,
1501 ARIZONA_FLL1_GAIN_MASK,
1502 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
Mark Brown8f113d72013-03-05 12:08:57 +08001503 else
Mark Brown3c43c692013-12-12 00:49:22 +00001504 regmap_update_bits_async(arizona->regmap, base + 0x9,
1505 ARIZONA_FLL1_GAIN_MASK,
1506 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
Mark Brown8f113d72013-03-05 12:08:57 +08001507
Mark Brown3c43c692013-12-12 00:49:22 +00001508 regmap_update_bits_async(arizona->regmap, base + 2,
1509 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
1510 ARIZONA_FLL1_CTRL_UPD | cfg->n);
Mark Brown07ed8732012-06-18 21:08:44 +01001511}
1512
Charles Keepaxd122d6c2013-02-20 17:28:36 +00001513static bool arizona_is_enabled_fll(struct arizona_fll *fll)
1514{
1515 struct arizona *arizona = fll->arizona;
1516 unsigned int reg;
1517 int ret;
1518
1519 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
1520 if (ret != 0) {
1521 arizona_fll_err(fll, "Failed to read current state: %d\n",
1522 ret);
1523 return ret;
1524 }
1525
1526 return reg & ARIZONA_FLL1_ENA;
1527}
1528
Charles Keepax35722812013-02-20 17:28:38 +00001529static void arizona_enable_fll(struct arizona_fll *fll,
1530 struct arizona_fll_cfg *ref,
1531 struct arizona_fll_cfg *sync)
1532{
1533 struct arizona *arizona = fll->arizona;
1534 int ret;
Charles Keepax49c60542013-09-16 15:34:35 +01001535 bool use_sync = false;
Charles Keepax35722812013-02-20 17:28:38 +00001536
Mark Brownff680a12013-03-04 16:00:19 +08001537 /*
1538 * If we have both REFCLK and SYNCCLK then enable both,
1539 * otherwise apply the SYNCCLK settings to REFCLK.
1540 */
Charles Keepax49c60542013-09-16 15:34:35 +01001541 if (fll->ref_src >= 0 && fll->ref_freq &&
1542 fll->ref_src != fll->sync_src) {
Mark Brown3c43c692013-12-12 00:49:22 +00001543 regmap_update_bits_async(arizona->regmap, fll->base + 5,
1544 ARIZONA_FLL1_OUTDIV_MASK,
1545 ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
Charles Keepax35722812013-02-20 17:28:38 +00001546
Mark Brown8f113d72013-03-05 12:08:57 +08001547 arizona_apply_fll(arizona, fll->base, ref, fll->ref_src,
1548 false);
Charles Keepax49c60542013-09-16 15:34:35 +01001549 if (fll->sync_src >= 0) {
Mark Brownff680a12013-03-04 16:00:19 +08001550 arizona_apply_fll(arizona, fll->base + 0x10, sync,
Mark Brown8f113d72013-03-05 12:08:57 +08001551 fll->sync_src, true);
Charles Keepax49c60542013-09-16 15:34:35 +01001552 use_sync = true;
1553 }
Mark Brownff680a12013-03-04 16:00:19 +08001554 } else if (fll->sync_src >= 0) {
Mark Brown3c43c692013-12-12 00:49:22 +00001555 regmap_update_bits_async(arizona->regmap, fll->base + 5,
1556 ARIZONA_FLL1_OUTDIV_MASK,
1557 sync->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
Mark Brownff680a12013-03-04 16:00:19 +08001558
1559 arizona_apply_fll(arizona, fll->base, sync,
Mark Brown8f113d72013-03-05 12:08:57 +08001560 fll->sync_src, false);
Mark Browneca2e8e2013-03-06 00:09:59 +08001561
Mark Brown3c43c692013-12-12 00:49:22 +00001562 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
1563 ARIZONA_FLL1_SYNC_ENA, 0);
Mark Brownff680a12013-03-04 16:00:19 +08001564 } else {
1565 arizona_fll_err(fll, "No clocks provided\n");
1566 return;
1567 }
Charles Keepax35722812013-02-20 17:28:38 +00001568
Mark Brown576411be2013-03-05 12:07:16 +08001569 /*
1570 * Increase the bandwidth if we're not using a low frequency
1571 * sync source.
1572 */
Charles Keepax49c60542013-09-16 15:34:35 +01001573 if (use_sync && fll->sync_freq > 100000)
Mark Brown3c43c692013-12-12 00:49:22 +00001574 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
1575 ARIZONA_FLL1_SYNC_BW, 0);
Mark Brown576411be2013-03-05 12:07:16 +08001576 else
Mark Brown3c43c692013-12-12 00:49:22 +00001577 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
1578 ARIZONA_FLL1_SYNC_BW,
1579 ARIZONA_FLL1_SYNC_BW);
Mark Brown576411be2013-03-05 12:07:16 +08001580
Charles Keepax35722812013-02-20 17:28:38 +00001581 if (!arizona_is_enabled_fll(fll))
1582 pm_runtime_get(arizona->dev);
1583
1584 /* Clear any pending completions */
1585 try_wait_for_completion(&fll->ok);
1586
Mark Brown3c43c692013-12-12 00:49:22 +00001587 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1588 ARIZONA_FLL1_FREERUN, 0);
1589 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1590 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
Charles Keepax49c60542013-09-16 15:34:35 +01001591 if (use_sync)
Mark Brown3c43c692013-12-12 00:49:22 +00001592 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
1593 ARIZONA_FLL1_SYNC_ENA,
1594 ARIZONA_FLL1_SYNC_ENA);
Charles Keepax35722812013-02-20 17:28:38 +00001595
1596 ret = wait_for_completion_timeout(&fll->ok,
1597 msecs_to_jiffies(250));
1598 if (ret == 0)
1599 arizona_fll_warn(fll, "Timed out waiting for lock\n");
1600}
1601
Charles Keepax76040542013-02-20 17:28:37 +00001602static void arizona_disable_fll(struct arizona_fll *fll)
1603{
1604 struct arizona *arizona = fll->arizona;
1605 bool change;
1606
Mark Brown3c43c692013-12-12 00:49:22 +00001607 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1608 ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
Charles Keepax76040542013-02-20 17:28:37 +00001609 regmap_update_bits_check(arizona->regmap, fll->base + 1,
1610 ARIZONA_FLL1_ENA, 0, &change);
1611 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1612 ARIZONA_FLL1_SYNC_ENA, 0);
1613
1614 if (change)
1615 pm_runtime_put_autosuspend(arizona->dev);
1616}
1617
Charles Keepaxee929a92013-02-20 17:28:40 +00001618int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
1619 unsigned int Fref, unsigned int Fout)
1620{
1621 struct arizona_fll_cfg ref, sync;
1622 int ret;
1623
Charles Keepax1c5617f2013-02-22 17:10:37 +00001624 if (fll->ref_src == source && fll->ref_freq == Fref)
Charles Keepaxee929a92013-02-20 17:28:40 +00001625 return 0;
1626
Charles Keepax49c60542013-09-16 15:34:35 +01001627 if (fll->fout) {
1628 if (Fref > 0) {
1629 ret = arizona_calc_fll(fll, &ref, Fref, fll->fout);
1630 if (ret != 0)
1631 return ret;
1632 }
Charles Keepaxee929a92013-02-20 17:28:40 +00001633
1634 if (fll->sync_src >= 0) {
Charles Keepax1c5617f2013-02-22 17:10:37 +00001635 ret = arizona_calc_fll(fll, &sync, fll->sync_freq,
1636 fll->fout);
Charles Keepaxee929a92013-02-20 17:28:40 +00001637 if (ret != 0)
1638 return ret;
1639 }
1640 }
1641
1642 fll->ref_src = source;
1643 fll->ref_freq = Fref;
Charles Keepaxee929a92013-02-20 17:28:40 +00001644
Mark Brown86cd6842013-03-07 16:14:04 +08001645 if (fll->fout && Fref > 0) {
Charles Keepaxee929a92013-02-20 17:28:40 +00001646 arizona_enable_fll(fll, &ref, &sync);
Charles Keepaxee929a92013-02-20 17:28:40 +00001647 }
1648
1649 return 0;
1650}
1651EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
1652
Mark Brown07ed8732012-06-18 21:08:44 +01001653int arizona_set_fll(struct arizona_fll *fll, int source,
1654 unsigned int Fref, unsigned int Fout)
1655{
Charles Keepax9e359c62013-02-20 17:28:35 +00001656 struct arizona_fll_cfg ref, sync;
Mark Brown07ed8732012-06-18 21:08:44 +01001657 int ret;
1658
Mark Brownff680a12013-03-04 16:00:19 +08001659 if (fll->sync_src == source &&
1660 fll->sync_freq == Fref && fll->fout == Fout)
1661 return 0;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00001662
Mark Brownff680a12013-03-04 16:00:19 +08001663 if (Fout) {
1664 if (fll->ref_src >= 0) {
1665 ret = arizona_calc_fll(fll, &ref, fll->ref_freq,
1666 Fout);
Charles Keepax9e359c62013-02-20 17:28:35 +00001667 if (ret != 0)
1668 return ret;
1669 }
1670
Mark Brownff680a12013-03-04 16:00:19 +08001671 ret = arizona_calc_fll(fll, &sync, Fref, Fout);
1672 if (ret != 0)
1673 return ret;
Charles Keepax9e359c62013-02-20 17:28:35 +00001674 }
Mark Brownff680a12013-03-04 16:00:19 +08001675
1676 fll->sync_src = source;
1677 fll->sync_freq = Fref;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00001678 fll->fout = Fout;
Charles Keepax9e359c62013-02-20 17:28:35 +00001679
Mark Brown07ed8732012-06-18 21:08:44 +01001680 if (Fout) {
Charles Keepax35722812013-02-20 17:28:38 +00001681 arizona_enable_fll(fll, &ref, &sync);
Mark Brown07ed8732012-06-18 21:08:44 +01001682 } else {
Charles Keepax76040542013-02-20 17:28:37 +00001683 arizona_disable_fll(fll);
Mark Brown07ed8732012-06-18 21:08:44 +01001684 }
1685
Mark Brown07ed8732012-06-18 21:08:44 +01001686 return 0;
1687}
1688EXPORT_SYMBOL_GPL(arizona_set_fll);
1689
1690int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
1691 int ok_irq, struct arizona_fll *fll)
1692{
1693 int ret;
Charles Keepax19b34bd2013-02-20 17:28:34 +00001694 unsigned int val;
Mark Brown07ed8732012-06-18 21:08:44 +01001695
Mark Brown07ed8732012-06-18 21:08:44 +01001696 init_completion(&fll->ok);
1697
1698 fll->id = id;
1699 fll->base = base;
1700 fll->arizona = arizona;
Charles Keepaxf3f11632013-02-20 17:28:41 +00001701 fll->sync_src = ARIZONA_FLL_SRC_NONE;
Mark Brown07ed8732012-06-18 21:08:44 +01001702
Charles Keepax19b34bd2013-02-20 17:28:34 +00001703 /* Configure default refclk to 32kHz if we have one */
1704 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
1705 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
1706 case ARIZONA_CLK_SRC_MCLK1:
1707 case ARIZONA_CLK_SRC_MCLK2:
1708 fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK;
1709 break;
1710 default:
Charles Keepaxf3f11632013-02-20 17:28:41 +00001711 fll->ref_src = ARIZONA_FLL_SRC_NONE;
Charles Keepax19b34bd2013-02-20 17:28:34 +00001712 }
1713 fll->ref_freq = 32768;
1714
Mark Brown07ed8732012-06-18 21:08:44 +01001715 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
1716 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
1717 "FLL%d clock OK", id);
1718
Mark Brown07ed8732012-06-18 21:08:44 +01001719 ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
1720 arizona_fll_clock_ok, fll);
1721 if (ret != 0) {
1722 dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
1723 id, ret);
1724 }
1725
Charles Keepaxe31c1942013-01-07 16:41:45 +00001726 regmap_update_bits(arizona->regmap, fll->base + 1,
1727 ARIZONA_FLL1_FREERUN, 0);
1728
Mark Brown07ed8732012-06-18 21:08:44 +01001729 return 0;
1730}
1731EXPORT_SYMBOL_GPL(arizona_init_fll);
1732
Mark Brownbc9ab6d2013-01-04 19:31:00 +00001733/**
1734 * arizona_set_output_mode - Set the mode of the specified output
1735 *
1736 * @codec: Device to configure
1737 * @output: Output number
1738 * @diff: True to set the output to differential mode
1739 *
1740 * Some systems use external analogue switches to connect more
1741 * analogue devices to the CODEC than are supported by the device. In
1742 * some systems this requires changing the switched output from single
1743 * ended to differential mode dynamically at runtime, an operation
1744 * supported using this function.
1745 *
1746 * Most systems have a single static configuration and should use
1747 * platform data instead.
1748 */
1749int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
1750{
1751 unsigned int reg, val;
1752
1753 if (output < 1 || output > 6)
1754 return -EINVAL;
1755
1756 reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
1757
1758 if (diff)
1759 val = ARIZONA_OUT1_MONO;
1760 else
1761 val = 0;
1762
1763 return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val);
1764}
1765EXPORT_SYMBOL_GPL(arizona_set_output_mode);
1766
Mark Brown07ed8732012-06-18 21:08:44 +01001767MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
1768MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1769MODULE_LICENSE("GPL");