blob: 6bfd8031c0c9286c662806352402c3705bd502c4 [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
501const struct soc_enum arizona_isrc_fsl[] = {
502 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2,
503 ARIZONA_ISRC1_FSL_SHIFT, 0xf,
504 ARIZONA_RATE_ENUM_SIZE,
505 arizona_rate_text, arizona_rate_val),
506 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_2,
507 ARIZONA_ISRC2_FSL_SHIFT, 0xf,
508 ARIZONA_RATE_ENUM_SIZE,
509 arizona_rate_text, arizona_rate_val),
510 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_2,
511 ARIZONA_ISRC3_FSL_SHIFT, 0xf,
512 ARIZONA_RATE_ENUM_SIZE,
513 arizona_rate_text, arizona_rate_val),
514};
515EXPORT_SYMBOL_GPL(arizona_isrc_fsl);
516
Mark Browne853a002012-12-09 12:25:52 +0900517static const char *arizona_vol_ramp_text[] = {
518 "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
519 "15ms/6dB", "30ms/6dB",
520};
521
522const struct soc_enum arizona_in_vd_ramp =
523 SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP,
524 ARIZONA_IN_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text);
525EXPORT_SYMBOL_GPL(arizona_in_vd_ramp);
526
527const struct soc_enum arizona_in_vi_ramp =
528 SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP,
529 ARIZONA_IN_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text);
530EXPORT_SYMBOL_GPL(arizona_in_vi_ramp);
531
532const struct soc_enum arizona_out_vd_ramp =
533 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP,
534 ARIZONA_OUT_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text);
535EXPORT_SYMBOL_GPL(arizona_out_vd_ramp);
536
537const struct soc_enum arizona_out_vi_ramp =
538 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP,
539 ARIZONA_OUT_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text);
540EXPORT_SYMBOL_GPL(arizona_out_vi_ramp);
541
Mark Brown07ed8732012-06-18 21:08:44 +0100542static const char *arizona_lhpf_mode_text[] = {
543 "Low-pass", "High-pass"
544};
545
546const struct soc_enum arizona_lhpf1_mode =
547 SOC_ENUM_SINGLE(ARIZONA_HPLPF1_1, ARIZONA_LHPF1_MODE_SHIFT, 2,
548 arizona_lhpf_mode_text);
549EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
550
551const struct soc_enum arizona_lhpf2_mode =
552 SOC_ENUM_SINGLE(ARIZONA_HPLPF2_1, ARIZONA_LHPF2_MODE_SHIFT, 2,
553 arizona_lhpf_mode_text);
554EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
555
556const struct soc_enum arizona_lhpf3_mode =
557 SOC_ENUM_SINGLE(ARIZONA_HPLPF3_1, ARIZONA_LHPF3_MODE_SHIFT, 2,
558 arizona_lhpf_mode_text);
559EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
560
561const struct soc_enum arizona_lhpf4_mode =
562 SOC_ENUM_SINGLE(ARIZONA_HPLPF4_1, ARIZONA_LHPF4_MODE_SHIFT, 2,
563 arizona_lhpf_mode_text);
564EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
565
Mark Brown845571c2012-12-18 13:47:57 +0000566static const char *arizona_ng_hold_text[] = {
567 "30ms", "120ms", "250ms", "500ms",
568};
569
570const struct soc_enum arizona_ng_hold =
571 SOC_ENUM_SINGLE(ARIZONA_NOISE_GATE_CONTROL, ARIZONA_NGATE_HOLD_SHIFT,
572 4, arizona_ng_hold_text);
573EXPORT_SYMBOL_GPL(arizona_ng_hold);
574
Charles Keepax254dc322013-11-19 16:04:03 +0000575static const char * const arizona_in_hpf_cut_text[] = {
576 "2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz"
577};
578
579const struct soc_enum arizona_in_hpf_cut_enum =
580 SOC_ENUM_SINGLE(ARIZONA_HPF_CONTROL, ARIZONA_IN_HPF_CUT_SHIFT,
581 ARRAY_SIZE(arizona_in_hpf_cut_text),
582 arizona_in_hpf_cut_text);
583EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum);
584
Charles Keepaxc7f38432013-08-06 17:03:55 +0100585static const char * const arizona_in_dmic_osr_text[] = {
586 "1.536MHz", "3.072MHz", "6.144MHz",
587};
588
589const struct soc_enum arizona_in_dmic_osr[] = {
590 SOC_ENUM_SINGLE(ARIZONA_IN1L_CONTROL, ARIZONA_IN1_OSR_SHIFT,
591 ARRAY_SIZE(arizona_in_dmic_osr_text),
592 arizona_in_dmic_osr_text),
593 SOC_ENUM_SINGLE(ARIZONA_IN2L_CONTROL, ARIZONA_IN2_OSR_SHIFT,
594 ARRAY_SIZE(arizona_in_dmic_osr_text),
595 arizona_in_dmic_osr_text),
596 SOC_ENUM_SINGLE(ARIZONA_IN3L_CONTROL, ARIZONA_IN3_OSR_SHIFT,
597 ARRAY_SIZE(arizona_in_dmic_osr_text),
598 arizona_in_dmic_osr_text),
599 SOC_ENUM_SINGLE(ARIZONA_IN4L_CONTROL, ARIZONA_IN4_OSR_SHIFT,
600 ARRAY_SIZE(arizona_in_dmic_osr_text),
601 arizona_in_dmic_osr_text),
602};
603EXPORT_SYMBOL_GPL(arizona_in_dmic_osr);
604
Mark Brownddbce972013-02-15 17:27:22 +0000605static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
606{
607 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
608 unsigned int val;
609 int i;
610
611 if (ena)
612 val = ARIZONA_IN_VU;
613 else
614 val = 0;
615
616 for (i = 0; i < priv->num_inputs; i++)
617 snd_soc_update_bits(codec,
618 ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 4),
619 ARIZONA_IN_VU, val);
620}
621
Mark Brown07ed8732012-06-18 21:08:44 +0100622int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
623 int event)
624{
Mark Brownddbce972013-02-15 17:27:22 +0000625 struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000626 unsigned int reg;
627
628 if (w->shift % 2)
629 reg = ARIZONA_ADC_DIGITAL_VOLUME_1L + ((w->shift / 2) * 8);
630 else
631 reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8);
632
633 switch (event) {
Mark Brownddbce972013-02-15 17:27:22 +0000634 case SND_SOC_DAPM_PRE_PMU:
635 priv->in_pending++;
636 break;
Mark Brown43cd8bf2013-02-06 16:57:29 +0000637 case SND_SOC_DAPM_POST_PMU:
638 snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, 0);
Mark Brownddbce972013-02-15 17:27:22 +0000639
640 /* If this is the last input pending then allow VU */
641 priv->in_pending--;
642 if (priv->in_pending == 0) {
643 msleep(1);
644 arizona_in_set_vu(w->codec, 1);
645 }
Mark Brown43cd8bf2013-02-06 16:57:29 +0000646 break;
647 case SND_SOC_DAPM_PRE_PMD:
Mark Brownddbce972013-02-15 17:27:22 +0000648 snd_soc_update_bits(w->codec, reg,
649 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU,
650 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000651 break;
Mark Brownddbce972013-02-15 17:27:22 +0000652 case SND_SOC_DAPM_POST_PMD:
653 /* Disable volume updates if no inputs are enabled */
654 reg = snd_soc_read(w->codec, ARIZONA_INPUT_ENABLES);
655 if (reg == 0)
656 arizona_in_set_vu(w->codec, 0);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000657 }
658
Mark Brown07ed8732012-06-18 21:08:44 +0100659 return 0;
660}
661EXPORT_SYMBOL_GPL(arizona_in_ev);
662
663int arizona_out_ev(struct snd_soc_dapm_widget *w,
664 struct snd_kcontrol *kcontrol,
665 int event)
666{
Mark Brown1a2c7d52013-03-24 22:50:23 +0000667 switch (event) {
668 case SND_SOC_DAPM_POST_PMU:
669 switch (w->shift) {
670 case ARIZONA_OUT1L_ENA_SHIFT:
671 case ARIZONA_OUT1R_ENA_SHIFT:
672 case ARIZONA_OUT2L_ENA_SHIFT:
673 case ARIZONA_OUT2R_ENA_SHIFT:
674 case ARIZONA_OUT3L_ENA_SHIFT:
675 case ARIZONA_OUT3R_ENA_SHIFT:
676 msleep(17);
677 break;
678
679 default:
680 break;
681 }
682 break;
683 }
684
Mark Brown07ed8732012-06-18 21:08:44 +0100685 return 0;
686}
687EXPORT_SYMBOL_GPL(arizona_out_ev);
688
Mark Brownf607e312013-02-22 18:36:53 +0000689int arizona_hp_ev(struct snd_soc_dapm_widget *w,
690 struct snd_kcontrol *kcontrol,
691 int event)
692{
693 struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
Mark Brown3c43c692013-12-12 00:49:22 +0000694 struct arizona *arizona = priv->arizona;
Mark Brownf607e312013-02-22 18:36:53 +0000695 unsigned int mask = 1 << w->shift;
696 unsigned int val;
697
698 switch (event) {
699 case SND_SOC_DAPM_POST_PMU:
700 val = mask;
701 break;
702 case SND_SOC_DAPM_PRE_PMD:
703 val = 0;
704 break;
705 default:
706 return -EINVAL;
707 }
708
709 /* Store the desired state for the HP outputs */
710 priv->arizona->hp_ena &= ~mask;
711 priv->arizona->hp_ena |= val;
712
713 /* Force off if HPDET magic is active */
714 if (priv->arizona->hpdet_magic)
715 val = 0;
716
Mark Brown3c43c692013-12-12 00:49:22 +0000717 regmap_update_bits_async(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1,
718 mask, val);
Mark Brownf607e312013-02-22 18:36:53 +0000719
720 return arizona_out_ev(w, kcontrol, event);
721}
722EXPORT_SYMBOL_GPL(arizona_hp_ev);
723
Mark Browncbd840d2012-08-08 17:52:44 +0100724static unsigned int arizona_sysclk_48k_rates[] = {
725 6144000,
726 12288000,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000727 24576000,
Mark Browncbd840d2012-08-08 17:52:44 +0100728 49152000,
Mark Brownaeaeee12012-09-26 17:50:02 +0100729 73728000,
730 98304000,
731 147456000,
Mark Browncbd840d2012-08-08 17:52:44 +0100732};
733
734static unsigned int arizona_sysclk_44k1_rates[] = {
735 5644800,
736 11289600,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000737 22579200,
Mark Browncbd840d2012-08-08 17:52:44 +0100738 45158400,
Mark Brownaeaeee12012-09-26 17:50:02 +0100739 67737600,
740 90316800,
741 135475200,
Mark Browncbd840d2012-08-08 17:52:44 +0100742};
743
744static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
745 unsigned int freq)
746{
747 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
748 unsigned int reg;
749 unsigned int *rates;
750 int ref, div, refclk;
751
752 switch (clk) {
753 case ARIZONA_CLK_OPCLK:
754 reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
755 refclk = priv->sysclk;
756 break;
757 case ARIZONA_CLK_ASYNC_OPCLK:
758 reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
759 refclk = priv->asyncclk;
760 break;
761 default:
762 return -EINVAL;
763 }
764
765 if (refclk % 8000)
766 rates = arizona_sysclk_44k1_rates;
767 else
768 rates = arizona_sysclk_48k_rates;
769
770 for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) &&
771 rates[ref] <= refclk; ref++) {
772 div = 1;
773 while (rates[ref] / div >= freq && div < 32) {
774 if (rates[ref] / div == freq) {
775 dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
776 freq);
777 snd_soc_update_bits(codec, reg,
778 ARIZONA_OPCLK_DIV_MASK |
779 ARIZONA_OPCLK_SEL_MASK,
780 (div <<
781 ARIZONA_OPCLK_DIV_SHIFT) |
782 ref);
783 return 0;
784 }
785 div++;
786 }
787 }
788
789 dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
790 return -EINVAL;
791}
792
Mark Brown07ed8732012-06-18 21:08:44 +0100793int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
794 int source, unsigned int freq, int dir)
795{
796 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
797 struct arizona *arizona = priv->arizona;
798 char *name;
799 unsigned int reg;
800 unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
801 unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
802 unsigned int *clk;
803
804 switch (clk_id) {
805 case ARIZONA_CLK_SYSCLK:
806 name = "SYSCLK";
807 reg = ARIZONA_SYSTEM_CLOCK_1;
808 clk = &priv->sysclk;
809 mask |= ARIZONA_SYSCLK_FRAC;
810 break;
811 case ARIZONA_CLK_ASYNCCLK:
812 name = "ASYNCCLK";
813 reg = ARIZONA_ASYNC_CLOCK_1;
814 clk = &priv->asyncclk;
815 break;
Mark Browncbd840d2012-08-08 17:52:44 +0100816 case ARIZONA_CLK_OPCLK:
817 case ARIZONA_CLK_ASYNC_OPCLK:
818 return arizona_set_opclk(codec, clk_id, freq);
Mark Brown07ed8732012-06-18 21:08:44 +0100819 default:
820 return -EINVAL;
821 }
822
823 switch (freq) {
824 case 5644800:
825 case 6144000:
826 break;
827 case 11289600:
828 case 12288000:
Mark Brown3f341f72013-03-08 15:22:29 +0800829 val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100830 break;
831 case 22579200:
832 case 24576000:
Mark Brown3f341f72013-03-08 15:22:29 +0800833 val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100834 break;
835 case 45158400:
836 case 49152000:
Mark Brown3f341f72013-03-08 15:22:29 +0800837 val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100838 break;
Mark Brown38113362012-11-26 16:01:37 +0000839 case 67737600:
840 case 73728000:
Mark Brown3f341f72013-03-08 15:22:29 +0800841 val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000842 break;
843 case 90316800:
844 case 98304000:
Mark Brown3f341f72013-03-08 15:22:29 +0800845 val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000846 break;
847 case 135475200:
848 case 147456000:
Mark Brown3f341f72013-03-08 15:22:29 +0800849 val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000850 break;
Mark Brownf2c26d42013-01-21 16:09:36 +0900851 case 0:
852 dev_dbg(arizona->dev, "%s cleared\n", name);
853 *clk = freq;
854 return 0;
Mark Brown07ed8732012-06-18 21:08:44 +0100855 default:
856 return -EINVAL;
857 }
858
859 *clk = freq;
860
861 if (freq % 6144000)
862 val |= ARIZONA_SYSCLK_FRAC;
863
864 dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
865
866 return regmap_update_bits(arizona->regmap, reg, mask, val);
867}
868EXPORT_SYMBOL_GPL(arizona_set_sysclk);
869
870static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
871{
872 struct snd_soc_codec *codec = dai->codec;
Mark Brown3c43c692013-12-12 00:49:22 +0000873 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
874 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +0100875 int lrclk, bclk, mode, base;
876
877 base = dai->driver->base;
878
879 lrclk = 0;
880 bclk = 0;
881
882 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
883 case SND_SOC_DAIFMT_DSP_A:
884 mode = 0;
885 break;
Mark Brown07ed8732012-06-18 21:08:44 +0100886 case SND_SOC_DAIFMT_I2S:
887 mode = 2;
888 break;
Mark Brown07ed8732012-06-18 21:08:44 +0100889 default:
890 arizona_aif_err(dai, "Unsupported DAI format %d\n",
891 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
892 return -EINVAL;
893 }
894
895 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
896 case SND_SOC_DAIFMT_CBS_CFS:
897 break;
898 case SND_SOC_DAIFMT_CBS_CFM:
899 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
900 break;
901 case SND_SOC_DAIFMT_CBM_CFS:
902 bclk |= ARIZONA_AIF1_BCLK_MSTR;
903 break;
904 case SND_SOC_DAIFMT_CBM_CFM:
905 bclk |= ARIZONA_AIF1_BCLK_MSTR;
906 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
907 break;
908 default:
909 arizona_aif_err(dai, "Unsupported master mode %d\n",
910 fmt & SND_SOC_DAIFMT_MASTER_MASK);
911 return -EINVAL;
912 }
913
914 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
915 case SND_SOC_DAIFMT_NB_NF:
916 break;
917 case SND_SOC_DAIFMT_IB_IF:
918 bclk |= ARIZONA_AIF1_BCLK_INV;
919 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
920 break;
921 case SND_SOC_DAIFMT_IB_NF:
922 bclk |= ARIZONA_AIF1_BCLK_INV;
923 break;
924 case SND_SOC_DAIFMT_NB_IF:
925 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
926 break;
927 default:
928 return -EINVAL;
929 }
930
Mark Brown3c43c692013-12-12 00:49:22 +0000931 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_BCLK_CTRL,
932 ARIZONA_AIF1_BCLK_INV |
933 ARIZONA_AIF1_BCLK_MSTR,
934 bclk);
935 regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_TX_PIN_CTRL,
936 ARIZONA_AIF1TX_LRCLK_INV |
937 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
938 regmap_update_bits_async(arizona->regmap,
939 base + ARIZONA_AIF_RX_PIN_CTRL,
940 ARIZONA_AIF1RX_LRCLK_INV |
941 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
942 regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FORMAT,
943 ARIZONA_AIF1_FMT_MASK, mode);
Mark Brown07ed8732012-06-18 21:08:44 +0100944
945 return 0;
946}
947
Mark Brown949e6bc2012-07-04 18:58:04 +0100948static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100949 -1,
950 48000,
951 64000,
952 96000,
953 128000,
954 192000,
955 256000,
956 384000,
957 512000,
958 768000,
959 1024000,
960 1536000,
961 2048000,
962 3072000,
963 4096000,
964 6144000,
965 8192000,
966 12288000,
967 24576000,
968};
969
Mark Brown5b2eec32012-07-04 17:32:05 +0100970static const unsigned int arizona_48k_rates[] = {
971 12000,
972 24000,
973 48000,
974 96000,
975 192000,
976 384000,
977 768000,
978 4000,
979 8000,
980 16000,
981 32000,
982 64000,
983 128000,
984 256000,
985 512000,
986};
987
988static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = {
989 .count = ARRAY_SIZE(arizona_48k_rates),
990 .list = arizona_48k_rates,
991};
992
Mark Brown949e6bc2012-07-04 18:58:04 +0100993static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100994 -1,
995 44100,
996 58800,
997 88200,
998 117600,
999 177640,
1000 235200,
1001 352800,
1002 470400,
1003 705600,
1004 940800,
1005 1411200,
1006 1881600,
Heather Lomond4758be32012-09-05 05:02:10 -04001007 2822400,
Mark Brown07ed8732012-06-18 21:08:44 +01001008 3763200,
1009 5644800,
1010 7526400,
1011 11289600,
1012 22579200,
1013};
1014
Mark Brown5b2eec32012-07-04 17:32:05 +01001015static const unsigned int arizona_44k1_rates[] = {
1016 11025,
1017 22050,
1018 44100,
1019 88200,
1020 176400,
1021 352800,
1022 705600,
1023};
1024
1025static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = {
1026 .count = ARRAY_SIZE(arizona_44k1_rates),
1027 .list = arizona_44k1_rates,
1028};
1029
Mark Brown07ed8732012-06-18 21:08:44 +01001030static int arizona_sr_vals[] = {
1031 0,
1032 12000,
1033 24000,
1034 48000,
1035 96000,
1036 192000,
1037 384000,
1038 768000,
1039 0,
1040 11025,
1041 22050,
1042 44100,
1043 88200,
1044 176400,
1045 352800,
1046 705600,
1047 4000,
1048 8000,
1049 16000,
1050 32000,
1051 64000,
1052 128000,
1053 256000,
1054 512000,
1055};
1056
Mark Brown5b2eec32012-07-04 17:32:05 +01001057static int arizona_startup(struct snd_pcm_substream *substream,
1058 struct snd_soc_dai *dai)
1059{
1060 struct snd_soc_codec *codec = dai->codec;
1061 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1062 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
1063 const struct snd_pcm_hw_constraint_list *constraint;
1064 unsigned int base_rate;
1065
1066 switch (dai_priv->clk) {
1067 case ARIZONA_CLK_SYSCLK:
1068 base_rate = priv->sysclk;
1069 break;
1070 case ARIZONA_CLK_ASYNCCLK:
1071 base_rate = priv->asyncclk;
1072 break;
1073 default:
1074 return 0;
1075 }
1076
Mark Brownf2c26d42013-01-21 16:09:36 +09001077 if (base_rate == 0)
1078 return 0;
1079
Mark Brown5b2eec32012-07-04 17:32:05 +01001080 if (base_rate % 8000)
1081 constraint = &arizona_44k1_constraint;
1082 else
1083 constraint = &arizona_48k_constraint;
1084
1085 return snd_pcm_hw_constraint_list(substream->runtime, 0,
1086 SNDRV_PCM_HW_PARAM_RATE,
1087 constraint);
1088}
1089
Mark Brownb272efc2012-10-10 15:10:08 +09001090static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
1091 struct snd_pcm_hw_params *params,
1092 struct snd_soc_dai *dai)
Mark Brown07ed8732012-06-18 21:08:44 +01001093{
1094 struct snd_soc_codec *codec = dai->codec;
Mark Brownc013b272012-07-04 20:05:57 +01001095 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1096 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown07ed8732012-06-18 21:08:44 +01001097 int base = dai->driver->base;
Mark Brownb272efc2012-10-10 15:10:08 +09001098 int i, sr_val;
1099
1100 /*
1101 * We will need to be more flexible than this in future,
1102 * currently we use a single sample rate for SYSCLK.
1103 */
1104 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
1105 if (arizona_sr_vals[i] == params_rate(params))
1106 break;
1107 if (i == ARRAY_SIZE(arizona_sr_vals)) {
1108 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1109 params_rate(params));
1110 return -EINVAL;
1111 }
1112 sr_val = i;
1113
1114 switch (dai_priv->clk) {
1115 case ARIZONA_CLK_SYSCLK:
1116 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
1117 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
1118 if (base)
1119 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1120 ARIZONA_AIF1_RATE_MASK, 0);
1121 break;
1122 case ARIZONA_CLK_ASYNCCLK:
1123 snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
1124 ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val);
1125 if (base)
1126 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1127 ARIZONA_AIF1_RATE_MASK,
1128 8 << ARIZONA_AIF1_RATE_SHIFT);
1129 break;
1130 default:
1131 arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
1132 return -EINVAL;
1133 }
1134
1135 return 0;
1136}
1137
Mark Brown07ed8732012-06-18 21:08:44 +01001138static int arizona_hw_params(struct snd_pcm_substream *substream,
1139 struct snd_pcm_hw_params *params,
1140 struct snd_soc_dai *dai)
1141{
1142 struct snd_soc_codec *codec = dai->codec;
1143 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brownc94aa302013-01-17 16:35:14 +09001144 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +01001145 int base = dai->driver->base;
1146 const int *rates;
Mark Brown76bf9692013-03-05 14:17:47 +08001147 int i, ret, val;
Mark Brownc94aa302013-01-17 16:35:14 +09001148 int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
1149 int bclk, lrclk, wl, frame, bclk_target;
Mark Brown07ed8732012-06-18 21:08:44 +01001150
1151 if (params_rate(params) % 8000)
Mark Brown949e6bc2012-07-04 18:58:04 +01001152 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001153 else
Mark Brown949e6bc2012-07-04 18:58:04 +01001154 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001155
Mark Brownc94aa302013-01-17 16:35:14 +09001156 bclk_target = snd_soc_params_to_bclk(params);
1157 if (chan_limit && chan_limit < params_channels(params)) {
1158 arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
1159 bclk_target /= params_channels(params);
1160 bclk_target *= chan_limit;
1161 }
1162
Mark Brown76bf9692013-03-05 14:17:47 +08001163 /* Force stereo for I2S mode */
1164 val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
1165 if (params_channels(params) == 1 && (val & ARIZONA_AIF1_FMT_MASK)) {
1166 arizona_aif_dbg(dai, "Forcing stereo mode\n");
1167 bclk_target *= 2;
1168 }
1169
Mark Brown949e6bc2012-07-04 18:58:04 +01001170 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brownc94aa302013-01-17 16:35:14 +09001171 if (rates[i] >= bclk_target &&
Mark Brown50017652012-07-04 19:07:09 +01001172 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +01001173 bclk = i;
1174 break;
1175 }
1176 }
Mark Brown949e6bc2012-07-04 18:58:04 +01001177 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001178 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1179 params_rate(params));
1180 return -EINVAL;
1181 }
1182
Mark Brownb59e0f82013-01-17 14:15:59 +09001183 lrclk = rates[bclk] / params_rate(params);
Mark Brown07ed8732012-06-18 21:08:44 +01001184
1185 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
1186 rates[bclk], rates[bclk] / lrclk);
1187
1188 wl = snd_pcm_format_width(params_format(params));
1189 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl;
1190
Mark Brownb272efc2012-10-10 15:10:08 +09001191 ret = arizona_hw_params_rate(substream, params, dai);
1192 if (ret != 0)
1193 return ret;
Mark Brownc013b272012-07-04 20:05:57 +01001194
Mark Brown3c43c692013-12-12 00:49:22 +00001195 regmap_update_bits_async(arizona->regmap,
1196 base + ARIZONA_AIF_BCLK_CTRL,
1197 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
1198 regmap_update_bits_async(arizona->regmap,
1199 base + ARIZONA_AIF_TX_BCLK_RATE,
1200 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
1201 regmap_update_bits_async(arizona->regmap,
1202 base + ARIZONA_AIF_RX_BCLK_RATE,
1203 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
1204 regmap_update_bits_async(arizona->regmap,
1205 base + ARIZONA_AIF_FRAME_CTRL_1,
1206 ARIZONA_AIF1TX_WL_MASK |
1207 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
1208 regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FRAME_CTRL_2,
1209 ARIZONA_AIF1RX_WL_MASK |
1210 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
Mark Brown07ed8732012-06-18 21:08:44 +01001211
1212 return 0;
1213}
1214
Mark Brown410837a2012-07-05 17:26:59 +01001215static const char *arizona_dai_clk_str(int clk_id)
1216{
1217 switch (clk_id) {
1218 case ARIZONA_CLK_SYSCLK:
1219 return "SYSCLK";
1220 case ARIZONA_CLK_ASYNCCLK:
1221 return "ASYNCCLK";
1222 default:
1223 return "Unknown clock";
1224 }
1225}
1226
Mark Brown5b2eec32012-07-04 17:32:05 +01001227static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
1228 int clk_id, unsigned int freq, int dir)
1229{
1230 struct snd_soc_codec *codec = dai->codec;
1231 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1232 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown410837a2012-07-05 17:26:59 +01001233 struct snd_soc_dapm_route routes[2];
Mark Brown5b2eec32012-07-04 17:32:05 +01001234
1235 switch (clk_id) {
1236 case ARIZONA_CLK_SYSCLK:
1237 case ARIZONA_CLK_ASYNCCLK:
1238 break;
1239 default:
1240 return -EINVAL;
1241 }
1242
Mark Brown410837a2012-07-05 17:26:59 +01001243 if (clk_id == dai_priv->clk)
1244 return 0;
1245
1246 if (dai->active) {
Mark Brown5b2eec32012-07-04 17:32:05 +01001247 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
1248 dai->id);
1249 return -EBUSY;
1250 }
1251
Mark Brownc8d35a62012-12-07 12:49:40 +09001252 dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1,
1253 arizona_dai_clk_str(clk_id));
1254
Mark Brown410837a2012-07-05 17:26:59 +01001255 memset(&routes, 0, sizeof(routes));
1256 routes[0].sink = dai->driver->capture.stream_name;
1257 routes[1].sink = dai->driver->playback.stream_name;
Mark Brown5b2eec32012-07-04 17:32:05 +01001258
Mark Brown410837a2012-07-05 17:26:59 +01001259 routes[0].source = arizona_dai_clk_str(dai_priv->clk);
1260 routes[1].source = arizona_dai_clk_str(dai_priv->clk);
1261 snd_soc_dapm_del_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
1262
1263 routes[0].source = arizona_dai_clk_str(clk_id);
1264 routes[1].source = arizona_dai_clk_str(clk_id);
1265 snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
1266
Mark Brown0c778e82012-12-06 18:22:25 +09001267 dai_priv->clk = clk_id;
1268
Mark Brown410837a2012-07-05 17:26:59 +01001269 return snd_soc_dapm_sync(&codec->dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +01001270}
1271
Mark Brown01df2592012-12-12 16:22:08 +09001272static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
1273{
1274 struct snd_soc_codec *codec = dai->codec;
1275 int base = dai->driver->base;
1276 unsigned int reg;
1277
1278 if (tristate)
1279 reg = ARIZONA_AIF1_TRI;
1280 else
1281 reg = 0;
1282
1283 return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1284 ARIZONA_AIF1_TRI, reg);
1285}
1286
Mark Brown07ed8732012-06-18 21:08:44 +01001287const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +01001288 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +01001289 .set_fmt = arizona_set_fmt,
1290 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +01001291 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown01df2592012-12-12 16:22:08 +09001292 .set_tristate = arizona_set_tristate,
Mark Brown07ed8732012-06-18 21:08:44 +01001293};
Mark Browna8379872012-07-09 12:16:41 +01001294EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +01001295
Mark Brownbd1dd882013-05-17 13:29:03 +01001296const struct snd_soc_dai_ops arizona_simple_dai_ops = {
1297 .startup = arizona_startup,
1298 .hw_params = arizona_hw_params_rate,
1299 .set_sysclk = arizona_dai_set_sysclk,
1300};
1301EXPORT_SYMBOL_GPL(arizona_simple_dai_ops);
1302
Mark Brown5b2eec32012-07-04 17:32:05 +01001303int arizona_init_dai(struct arizona_priv *priv, int id)
1304{
1305 struct arizona_dai_priv *dai_priv = &priv->dai[id];
1306
1307 dai_priv->clk = ARIZONA_CLK_SYSCLK;
1308
1309 return 0;
1310}
1311EXPORT_SYMBOL_GPL(arizona_init_dai);
1312
Mark Brown07ed8732012-06-18 21:08:44 +01001313static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
1314{
1315 struct arizona_fll *fll = data;
1316
1317 arizona_fll_dbg(fll, "clock OK\n");
1318
1319 complete(&fll->ok);
1320
1321 return IRQ_HANDLED;
1322}
1323
1324static struct {
1325 unsigned int min;
1326 unsigned int max;
1327 u16 fratio;
1328 int ratio;
1329} fll_fratios[] = {
1330 { 0, 64000, 4, 16 },
1331 { 64000, 128000, 3, 8 },
1332 { 128000, 256000, 2, 4 },
1333 { 256000, 1000000, 1, 2 },
1334 { 1000000, 13500000, 0, 1 },
1335};
1336
Mark Brown8f113d72013-03-05 12:08:57 +08001337static struct {
1338 unsigned int min;
1339 unsigned int max;
1340 u16 gain;
1341} fll_gains[] = {
1342 { 0, 256000, 0 },
1343 { 256000, 1000000, 2 },
1344 { 1000000, 13500000, 4 },
1345};
1346
Mark Brown07ed8732012-06-18 21:08:44 +01001347struct arizona_fll_cfg {
1348 int n;
1349 int theta;
1350 int lambda;
1351 int refdiv;
1352 int outdiv;
1353 int fratio;
Mark Brown8f113d72013-03-05 12:08:57 +08001354 int gain;
Mark Brown07ed8732012-06-18 21:08:44 +01001355};
1356
1357static int arizona_calc_fll(struct arizona_fll *fll,
1358 struct arizona_fll_cfg *cfg,
1359 unsigned int Fref,
1360 unsigned int Fout)
1361{
1362 unsigned int target, div, gcd_fll;
1363 int i, ratio;
1364
1365 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout);
1366
1367 /* Fref must be <=13.5MHz */
1368 div = 1;
1369 cfg->refdiv = 0;
1370 while ((Fref / div) > 13500000) {
1371 div *= 2;
1372 cfg->refdiv++;
1373
1374 if (div > 8) {
1375 arizona_fll_err(fll,
1376 "Can't scale %dMHz in to <=13.5MHz\n",
1377 Fref);
1378 return -EINVAL;
1379 }
1380 }
1381
1382 /* Apply the division for our remaining calculations */
1383 Fref /= div;
1384
Mark Brown2b4d39f2012-07-10 17:03:46 +01001385 /* Fvco should be over the targt; don't check the upper bound */
Mark Brown07ed8732012-06-18 21:08:44 +01001386 div = 1;
Mark Brown2b4d39f2012-07-10 17:03:46 +01001387 while (Fout * div < 90000000 * fll->vco_mult) {
Mark Brown07ed8732012-06-18 21:08:44 +01001388 div++;
1389 if (div > 7) {
1390 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
1391 Fout);
1392 return -EINVAL;
1393 }
1394 }
Mark Brown2b4d39f2012-07-10 17:03:46 +01001395 target = Fout * div / fll->vco_mult;
Mark Brown07ed8732012-06-18 21:08:44 +01001396 cfg->outdiv = div;
1397
1398 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
1399
1400 /* Find an appropraite FLL_FRATIO and factor it out of the target */
1401 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
1402 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
1403 cfg->fratio = fll_fratios[i].fratio;
1404 ratio = fll_fratios[i].ratio;
1405 break;
1406 }
1407 }
1408 if (i == ARRAY_SIZE(fll_fratios)) {
1409 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
1410 Fref);
1411 return -EINVAL;
1412 }
1413
Mark Brown8f113d72013-03-05 12:08:57 +08001414 for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
1415 if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
1416 cfg->gain = fll_gains[i].gain;
1417 break;
1418 }
1419 }
1420 if (i == ARRAY_SIZE(fll_gains)) {
1421 arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
1422 Fref);
1423 return -EINVAL;
1424 }
1425
Mark Brown07ed8732012-06-18 21:08:44 +01001426 cfg->n = target / (ratio * Fref);
1427
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001428 if (target % (ratio * Fref)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001429 gcd_fll = gcd(target, ratio * Fref);
1430 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
1431
1432 cfg->theta = (target - (cfg->n * ratio * Fref))
1433 / gcd_fll;
1434 cfg->lambda = (ratio * Fref) / gcd_fll;
1435 } else {
1436 cfg->theta = 0;
1437 cfg->lambda = 0;
1438 }
1439
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001440 /* Round down to 16bit range with cost of accuracy lost.
1441 * Denominator must be bigger than numerator so we only
1442 * take care of it.
1443 */
1444 while (cfg->lambda >= (1 << 16)) {
1445 cfg->theta >>= 1;
1446 cfg->lambda >>= 1;
1447 }
1448
Mark Brown07ed8732012-06-18 21:08:44 +01001449 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
1450 cfg->n, cfg->theta, cfg->lambda);
1451 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
1452 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08001453 arizona_fll_dbg(fll, "GAIN=%d\n", cfg->gain);
Mark Brown07ed8732012-06-18 21:08:44 +01001454
1455 return 0;
1456
1457}
1458
1459static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
Mark Brown8f113d72013-03-05 12:08:57 +08001460 struct arizona_fll_cfg *cfg, int source,
1461 bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01001462{
Mark Brown3c43c692013-12-12 00:49:22 +00001463 regmap_update_bits_async(arizona->regmap, base + 3,
1464 ARIZONA_FLL1_THETA_MASK, cfg->theta);
1465 regmap_update_bits_async(arizona->regmap, base + 4,
1466 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
1467 regmap_update_bits_async(arizona->regmap, base + 5,
1468 ARIZONA_FLL1_FRATIO_MASK,
1469 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
1470 regmap_update_bits_async(arizona->regmap, base + 6,
1471 ARIZONA_FLL1_CLK_REF_DIV_MASK |
1472 ARIZONA_FLL1_CLK_REF_SRC_MASK,
1473 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
1474 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
Mark Brown07ed8732012-06-18 21:08:44 +01001475
Mark Brown8f113d72013-03-05 12:08:57 +08001476 if (sync)
Mark Brown3c43c692013-12-12 00:49:22 +00001477 regmap_update_bits_async(arizona->regmap, base + 0x7,
1478 ARIZONA_FLL1_GAIN_MASK,
1479 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
Mark Brown8f113d72013-03-05 12:08:57 +08001480 else
Mark Brown3c43c692013-12-12 00:49:22 +00001481 regmap_update_bits_async(arizona->regmap, base + 0x9,
1482 ARIZONA_FLL1_GAIN_MASK,
1483 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
Mark Brown8f113d72013-03-05 12:08:57 +08001484
Mark Brown3c43c692013-12-12 00:49:22 +00001485 regmap_update_bits_async(arizona->regmap, base + 2,
1486 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
1487 ARIZONA_FLL1_CTRL_UPD | cfg->n);
Mark Brown07ed8732012-06-18 21:08:44 +01001488}
1489
Charles Keepaxd122d6c2013-02-20 17:28:36 +00001490static bool arizona_is_enabled_fll(struct arizona_fll *fll)
1491{
1492 struct arizona *arizona = fll->arizona;
1493 unsigned int reg;
1494 int ret;
1495
1496 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
1497 if (ret != 0) {
1498 arizona_fll_err(fll, "Failed to read current state: %d\n",
1499 ret);
1500 return ret;
1501 }
1502
1503 return reg & ARIZONA_FLL1_ENA;
1504}
1505
Charles Keepax35722812013-02-20 17:28:38 +00001506static void arizona_enable_fll(struct arizona_fll *fll,
1507 struct arizona_fll_cfg *ref,
1508 struct arizona_fll_cfg *sync)
1509{
1510 struct arizona *arizona = fll->arizona;
1511 int ret;
Charles Keepax49c60542013-09-16 15:34:35 +01001512 bool use_sync = false;
Charles Keepax35722812013-02-20 17:28:38 +00001513
Mark Brownff680a12013-03-04 16:00:19 +08001514 /*
1515 * If we have both REFCLK and SYNCCLK then enable both,
1516 * otherwise apply the SYNCCLK settings to REFCLK.
1517 */
Charles Keepax49c60542013-09-16 15:34:35 +01001518 if (fll->ref_src >= 0 && fll->ref_freq &&
1519 fll->ref_src != fll->sync_src) {
Mark Brown3c43c692013-12-12 00:49:22 +00001520 regmap_update_bits_async(arizona->regmap, fll->base + 5,
1521 ARIZONA_FLL1_OUTDIV_MASK,
1522 ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
Charles Keepax35722812013-02-20 17:28:38 +00001523
Mark Brown8f113d72013-03-05 12:08:57 +08001524 arizona_apply_fll(arizona, fll->base, ref, fll->ref_src,
1525 false);
Charles Keepax49c60542013-09-16 15:34:35 +01001526 if (fll->sync_src >= 0) {
Mark Brownff680a12013-03-04 16:00:19 +08001527 arizona_apply_fll(arizona, fll->base + 0x10, sync,
Mark Brown8f113d72013-03-05 12:08:57 +08001528 fll->sync_src, true);
Charles Keepax49c60542013-09-16 15:34:35 +01001529 use_sync = true;
1530 }
Mark Brownff680a12013-03-04 16:00:19 +08001531 } else if (fll->sync_src >= 0) {
Mark Brown3c43c692013-12-12 00:49:22 +00001532 regmap_update_bits_async(arizona->regmap, fll->base + 5,
1533 ARIZONA_FLL1_OUTDIV_MASK,
1534 sync->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
Mark Brownff680a12013-03-04 16:00:19 +08001535
1536 arizona_apply_fll(arizona, fll->base, sync,
Mark Brown8f113d72013-03-05 12:08:57 +08001537 fll->sync_src, false);
Mark Browneca2e8e2013-03-06 00:09:59 +08001538
Mark Brown3c43c692013-12-12 00:49:22 +00001539 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
1540 ARIZONA_FLL1_SYNC_ENA, 0);
Mark Brownff680a12013-03-04 16:00:19 +08001541 } else {
1542 arizona_fll_err(fll, "No clocks provided\n");
1543 return;
1544 }
Charles Keepax35722812013-02-20 17:28:38 +00001545
Mark Brown576411be2013-03-05 12:07:16 +08001546 /*
1547 * Increase the bandwidth if we're not using a low frequency
1548 * sync source.
1549 */
Charles Keepax49c60542013-09-16 15:34:35 +01001550 if (use_sync && fll->sync_freq > 100000)
Mark Brown3c43c692013-12-12 00:49:22 +00001551 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
1552 ARIZONA_FLL1_SYNC_BW, 0);
Mark Brown576411be2013-03-05 12:07:16 +08001553 else
Mark Brown3c43c692013-12-12 00:49:22 +00001554 regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
1555 ARIZONA_FLL1_SYNC_BW,
1556 ARIZONA_FLL1_SYNC_BW);
Mark Brown576411be2013-03-05 12:07:16 +08001557
Charles Keepax35722812013-02-20 17:28:38 +00001558 if (!arizona_is_enabled_fll(fll))
1559 pm_runtime_get(arizona->dev);
1560
1561 /* Clear any pending completions */
1562 try_wait_for_completion(&fll->ok);
1563
Mark Brown3c43c692013-12-12 00:49:22 +00001564 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1565 ARIZONA_FLL1_FREERUN, 0);
1566 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1567 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
Charles Keepax49c60542013-09-16 15:34:35 +01001568 if (use_sync)
Mark Brown3c43c692013-12-12 00:49:22 +00001569 regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
1570 ARIZONA_FLL1_SYNC_ENA,
1571 ARIZONA_FLL1_SYNC_ENA);
Charles Keepax35722812013-02-20 17:28:38 +00001572
1573 ret = wait_for_completion_timeout(&fll->ok,
1574 msecs_to_jiffies(250));
1575 if (ret == 0)
1576 arizona_fll_warn(fll, "Timed out waiting for lock\n");
1577}
1578
Charles Keepax76040542013-02-20 17:28:37 +00001579static void arizona_disable_fll(struct arizona_fll *fll)
1580{
1581 struct arizona *arizona = fll->arizona;
1582 bool change;
1583
Mark Brown3c43c692013-12-12 00:49:22 +00001584 regmap_update_bits_async(arizona->regmap, fll->base + 1,
1585 ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
Charles Keepax76040542013-02-20 17:28:37 +00001586 regmap_update_bits_check(arizona->regmap, fll->base + 1,
1587 ARIZONA_FLL1_ENA, 0, &change);
1588 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1589 ARIZONA_FLL1_SYNC_ENA, 0);
1590
1591 if (change)
1592 pm_runtime_put_autosuspend(arizona->dev);
1593}
1594
Charles Keepaxee929a92013-02-20 17:28:40 +00001595int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
1596 unsigned int Fref, unsigned int Fout)
1597{
1598 struct arizona_fll_cfg ref, sync;
1599 int ret;
1600
Charles Keepax1c5617f2013-02-22 17:10:37 +00001601 if (fll->ref_src == source && fll->ref_freq == Fref)
Charles Keepaxee929a92013-02-20 17:28:40 +00001602 return 0;
1603
Charles Keepax49c60542013-09-16 15:34:35 +01001604 if (fll->fout) {
1605 if (Fref > 0) {
1606 ret = arizona_calc_fll(fll, &ref, Fref, fll->fout);
1607 if (ret != 0)
1608 return ret;
1609 }
Charles Keepaxee929a92013-02-20 17:28:40 +00001610
1611 if (fll->sync_src >= 0) {
Charles Keepax1c5617f2013-02-22 17:10:37 +00001612 ret = arizona_calc_fll(fll, &sync, fll->sync_freq,
1613 fll->fout);
Charles Keepaxee929a92013-02-20 17:28:40 +00001614 if (ret != 0)
1615 return ret;
1616 }
1617 }
1618
1619 fll->ref_src = source;
1620 fll->ref_freq = Fref;
Charles Keepaxee929a92013-02-20 17:28:40 +00001621
Mark Brown86cd6842013-03-07 16:14:04 +08001622 if (fll->fout && Fref > 0) {
Charles Keepaxee929a92013-02-20 17:28:40 +00001623 arizona_enable_fll(fll, &ref, &sync);
Charles Keepaxee929a92013-02-20 17:28:40 +00001624 }
1625
1626 return 0;
1627}
1628EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
1629
Mark Brown07ed8732012-06-18 21:08:44 +01001630int arizona_set_fll(struct arizona_fll *fll, int source,
1631 unsigned int Fref, unsigned int Fout)
1632{
Charles Keepax9e359c62013-02-20 17:28:35 +00001633 struct arizona_fll_cfg ref, sync;
Mark Brown07ed8732012-06-18 21:08:44 +01001634 int ret;
1635
Mark Brownff680a12013-03-04 16:00:19 +08001636 if (fll->sync_src == source &&
1637 fll->sync_freq == Fref && fll->fout == Fout)
1638 return 0;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00001639
Mark Brownff680a12013-03-04 16:00:19 +08001640 if (Fout) {
1641 if (fll->ref_src >= 0) {
1642 ret = arizona_calc_fll(fll, &ref, fll->ref_freq,
1643 Fout);
Charles Keepax9e359c62013-02-20 17:28:35 +00001644 if (ret != 0)
1645 return ret;
1646 }
1647
Mark Brownff680a12013-03-04 16:00:19 +08001648 ret = arizona_calc_fll(fll, &sync, Fref, Fout);
1649 if (ret != 0)
1650 return ret;
Charles Keepax9e359c62013-02-20 17:28:35 +00001651 }
Mark Brownff680a12013-03-04 16:00:19 +08001652
1653 fll->sync_src = source;
1654 fll->sync_freq = Fref;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00001655 fll->fout = Fout;
Charles Keepax9e359c62013-02-20 17:28:35 +00001656
Mark Brown07ed8732012-06-18 21:08:44 +01001657 if (Fout) {
Charles Keepax35722812013-02-20 17:28:38 +00001658 arizona_enable_fll(fll, &ref, &sync);
Mark Brown07ed8732012-06-18 21:08:44 +01001659 } else {
Charles Keepax76040542013-02-20 17:28:37 +00001660 arizona_disable_fll(fll);
Mark Brown07ed8732012-06-18 21:08:44 +01001661 }
1662
Mark Brown07ed8732012-06-18 21:08:44 +01001663 return 0;
1664}
1665EXPORT_SYMBOL_GPL(arizona_set_fll);
1666
1667int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
1668 int ok_irq, struct arizona_fll *fll)
1669{
1670 int ret;
Charles Keepax19b34bd2013-02-20 17:28:34 +00001671 unsigned int val;
Mark Brown07ed8732012-06-18 21:08:44 +01001672
Mark Brown07ed8732012-06-18 21:08:44 +01001673 init_completion(&fll->ok);
1674
1675 fll->id = id;
1676 fll->base = base;
1677 fll->arizona = arizona;
Charles Keepaxf3f11632013-02-20 17:28:41 +00001678 fll->sync_src = ARIZONA_FLL_SRC_NONE;
Mark Brown07ed8732012-06-18 21:08:44 +01001679
Charles Keepax19b34bd2013-02-20 17:28:34 +00001680 /* Configure default refclk to 32kHz if we have one */
1681 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
1682 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
1683 case ARIZONA_CLK_SRC_MCLK1:
1684 case ARIZONA_CLK_SRC_MCLK2:
1685 fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK;
1686 break;
1687 default:
Charles Keepaxf3f11632013-02-20 17:28:41 +00001688 fll->ref_src = ARIZONA_FLL_SRC_NONE;
Charles Keepax19b34bd2013-02-20 17:28:34 +00001689 }
1690 fll->ref_freq = 32768;
1691
Mark Brown07ed8732012-06-18 21:08:44 +01001692 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
1693 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
1694 "FLL%d clock OK", id);
1695
Mark Brown07ed8732012-06-18 21:08:44 +01001696 ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
1697 arizona_fll_clock_ok, fll);
1698 if (ret != 0) {
1699 dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
1700 id, ret);
1701 }
1702
Charles Keepaxe31c1942013-01-07 16:41:45 +00001703 regmap_update_bits(arizona->regmap, fll->base + 1,
1704 ARIZONA_FLL1_FREERUN, 0);
1705
Mark Brown07ed8732012-06-18 21:08:44 +01001706 return 0;
1707}
1708EXPORT_SYMBOL_GPL(arizona_init_fll);
1709
Mark Brownbc9ab6d2013-01-04 19:31:00 +00001710/**
1711 * arizona_set_output_mode - Set the mode of the specified output
1712 *
1713 * @codec: Device to configure
1714 * @output: Output number
1715 * @diff: True to set the output to differential mode
1716 *
1717 * Some systems use external analogue switches to connect more
1718 * analogue devices to the CODEC than are supported by the device. In
1719 * some systems this requires changing the switched output from single
1720 * ended to differential mode dynamically at runtime, an operation
1721 * supported using this function.
1722 *
1723 * Most systems have a single static configuration and should use
1724 * platform data instead.
1725 */
1726int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
1727{
1728 unsigned int reg, val;
1729
1730 if (output < 1 || output > 6)
1731 return -EINVAL;
1732
1733 reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
1734
1735 if (diff)
1736 val = ARIZONA_OUT1_MONO;
1737 else
1738 val = 0;
1739
1740 return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val);
1741}
1742EXPORT_SYMBOL_GPL(arizona_set_output_mode);
1743
Mark Brown07ed8732012-06-18 21:08:44 +01001744MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
1745MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1746MODULE_LICENSE("GPL");