blob: 657808ba1418d5588e961081c5e1578cbb671400 [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) {
96 snd_soc_write(codec, 0x4f5, 0x25a);
97 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
108 snd_soc_update_bits(codec, ARIZONA_OUTPUT_ENABLES_1,
109 1 << w->shift, 1 << w->shift);
110
Mark Brown56447e12013-01-10 14:45:58 +0000111 if (priv->spk_ena_pending) {
112 msleep(75);
113 snd_soc_write(codec, 0x4f5, 0xda);
114 priv->spk_ena_pending = false;
115 priv->spk_ena++;
116 }
117 break;
118 case SND_SOC_DAPM_PRE_PMD:
119 if (manual_ena) {
120 priv->spk_ena--;
121 if (!priv->spk_ena)
122 snd_soc_write(codec, 0x4f5, 0x25a);
123 }
Mark Brownf4a76e72013-03-13 12:22:39 +0000124
125 snd_soc_update_bits(codec, ARIZONA_OUTPUT_ENABLES_1,
126 1 << w->shift, 0);
Mark Brown56447e12013-01-10 14:45:58 +0000127 break;
128 case SND_SOC_DAPM_POST_PMD:
129 if (manual_ena) {
130 if (!priv->spk_ena)
131 snd_soc_write(codec, 0x4f5, 0x0da);
132 }
133 break;
134 }
135
136 return 0;
137}
138
Mark Brown899817e2013-03-13 12:32:10 +0000139static irqreturn_t arizona_thermal_warn(int irq, void *data)
140{
141 struct arizona *arizona = data;
142 unsigned int val;
143 int ret;
144
145 ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
146 &val);
147 if (ret != 0) {
148 dev_err(arizona->dev, "Failed to read thermal status: %d\n",
149 ret);
150 } else if (val & ARIZONA_SPK_SHUTDOWN_WARN_STS) {
151 dev_crit(arizona->dev, "Thermal warning\n");
152 }
153
154 return IRQ_HANDLED;
155}
156
157static irqreturn_t arizona_thermal_shutdown(int irq, void *data)
158{
159 struct arizona *arizona = data;
160 unsigned int val;
161 int ret;
162
163 ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
164 &val);
165 if (ret != 0) {
166 dev_err(arizona->dev, "Failed to read thermal status: %d\n",
167 ret);
168 } else if (val & ARIZONA_SPK_SHUTDOWN_STS) {
169 dev_crit(arizona->dev, "Thermal shutdown\n");
Mark Brownf4a76e72013-03-13 12:22:39 +0000170 ret = regmap_update_bits(arizona->regmap,
171 ARIZONA_OUTPUT_ENABLES_1,
172 ARIZONA_OUT4L_ENA |
173 ARIZONA_OUT4R_ENA, 0);
174 if (ret != 0)
175 dev_crit(arizona->dev,
176 "Failed to disable speaker outputs: %d\n",
177 ret);
Mark Brown899817e2013-03-13 12:32:10 +0000178 }
179
180 return IRQ_HANDLED;
181}
182
Mark Brown56447e12013-01-10 14:45:58 +0000183static const struct snd_soc_dapm_widget arizona_spkl =
Mark Brownf4a76e72013-03-13 12:22:39 +0000184 SND_SOC_DAPM_PGA_E("OUT4L", SND_SOC_NOPM,
Mark Brown56447e12013-01-10 14:45:58 +0000185 ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
186 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
187
188static const struct snd_soc_dapm_widget arizona_spkr =
Mark Brownf4a76e72013-03-13 12:22:39 +0000189 SND_SOC_DAPM_PGA_E("OUT4R", SND_SOC_NOPM,
Mark Brown56447e12013-01-10 14:45:58 +0000190 ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
191 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
192
193int arizona_init_spk(struct snd_soc_codec *codec)
194{
Mark Brown899817e2013-03-13 12:32:10 +0000195 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
196 struct arizona *arizona = priv->arizona;
Mark Brown56447e12013-01-10 14:45:58 +0000197 int ret;
198
199 ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkl, 1);
200 if (ret != 0)
201 return ret;
202
Charles Keepax40843ae2013-08-12 23:46:55 +0100203 switch (arizona->type) {
204 case WM8997:
205 break;
206 default:
207 ret = snd_soc_dapm_new_controls(&codec->dapm,
208 &arizona_spkr, 1);
209 if (ret != 0)
210 return ret;
211 break;
212 }
Mark Brown56447e12013-01-10 14:45:58 +0000213
Mark Brown899817e2013-03-13 12:32:10 +0000214 ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN_WARN,
215 "Thermal warning", arizona_thermal_warn,
216 arizona);
217 if (ret != 0)
218 dev_err(arizona->dev,
219 "Failed to get thermal warning IRQ: %d\n",
220 ret);
221
222 ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN,
223 "Thermal shutdown", arizona_thermal_shutdown,
224 arizona);
225 if (ret != 0)
226 dev_err(arizona->dev,
227 "Failed to get thermal shutdown IRQ: %d\n",
228 ret);
229
Mark Brown56447e12013-01-10 14:45:58 +0000230 return 0;
231}
232EXPORT_SYMBOL_GPL(arizona_init_spk);
233
Charles Keepaxb63144e2013-07-04 08:56:28 +0100234int arizona_init_gpio(struct snd_soc_codec *codec)
235{
236 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
237 struct arizona *arizona = priv->arizona;
238 int i;
239
240 switch (arizona->type) {
241 case WM5110:
242 snd_soc_dapm_disable_pin(&codec->dapm, "DRC2 Signal Activity");
Charles Keepaxb79fae62013-07-04 16:53:03 +0100243 break;
244 default:
245 break;
Charles Keepaxb63144e2013-07-04 08:56:28 +0100246 }
247
248 snd_soc_dapm_disable_pin(&codec->dapm, "DRC1 Signal Activity");
249
250 for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
251 switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) {
252 case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT:
253 snd_soc_dapm_enable_pin(&codec->dapm,
254 "DRC1 Signal Activity");
255 break;
256 case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT:
257 snd_soc_dapm_enable_pin(&codec->dapm,
258 "DRC2 Signal Activity");
259 break;
260 default:
261 break;
262 }
263 }
264
265 return 0;
266}
267EXPORT_SYMBOL_GPL(arizona_init_gpio);
268
Mark Brown07ed8732012-06-18 21:08:44 +0100269const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
270 "None",
271 "Tone Generator 1",
272 "Tone Generator 2",
273 "Haptics",
274 "AEC",
275 "Mic Mute Mixer",
276 "Noise Generator",
277 "IN1L",
278 "IN1R",
279 "IN2L",
280 "IN2R",
281 "IN3L",
282 "IN3R",
Mark Brownc9c56fd2012-07-09 19:09:01 +0100283 "IN4L",
284 "IN4R",
Mark Brown07ed8732012-06-18 21:08:44 +0100285 "AIF1RX1",
286 "AIF1RX2",
287 "AIF1RX3",
288 "AIF1RX4",
289 "AIF1RX5",
290 "AIF1RX6",
291 "AIF1RX7",
292 "AIF1RX8",
293 "AIF2RX1",
294 "AIF2RX2",
295 "AIF3RX1",
296 "AIF3RX2",
297 "SLIMRX1",
298 "SLIMRX2",
299 "SLIMRX3",
300 "SLIMRX4",
301 "SLIMRX5",
302 "SLIMRX6",
303 "SLIMRX7",
304 "SLIMRX8",
305 "EQ1",
306 "EQ2",
307 "EQ3",
308 "EQ4",
309 "DRC1L",
310 "DRC1R",
311 "DRC2L",
312 "DRC2R",
313 "LHPF1",
314 "LHPF2",
315 "LHPF3",
316 "LHPF4",
317 "DSP1.1",
318 "DSP1.2",
319 "DSP1.3",
320 "DSP1.4",
321 "DSP1.5",
322 "DSP1.6",
Mark Brownc922cc42012-09-26 16:43:44 +0100323 "DSP2.1",
324 "DSP2.2",
325 "DSP2.3",
326 "DSP2.4",
327 "DSP2.5",
328 "DSP2.6",
329 "DSP3.1",
330 "DSP3.2",
331 "DSP3.3",
332 "DSP3.4",
333 "DSP3.5",
334 "DSP3.6",
335 "DSP4.1",
336 "DSP4.2",
337 "DSP4.3",
338 "DSP4.4",
339 "DSP4.5",
340 "DSP4.6",
Mark Brown07ed8732012-06-18 21:08:44 +0100341 "ASRC1L",
342 "ASRC1R",
343 "ASRC2L",
344 "ASRC2R",
Mark Brown91660bd2012-12-05 20:35:24 +0900345 "ISRC1INT1",
346 "ISRC1INT2",
347 "ISRC1INT3",
348 "ISRC1INT4",
349 "ISRC1DEC1",
350 "ISRC1DEC2",
351 "ISRC1DEC3",
352 "ISRC1DEC4",
353 "ISRC2INT1",
354 "ISRC2INT2",
355 "ISRC2INT3",
356 "ISRC2INT4",
357 "ISRC2DEC1",
358 "ISRC2DEC2",
359 "ISRC2DEC3",
360 "ISRC2DEC4",
361 "ISRC3INT1",
362 "ISRC3INT2",
363 "ISRC3INT3",
364 "ISRC3INT4",
365 "ISRC3DEC1",
366 "ISRC3DEC2",
367 "ISRC3DEC3",
368 "ISRC3DEC4",
Mark Brown07ed8732012-06-18 21:08:44 +0100369};
370EXPORT_SYMBOL_GPL(arizona_mixer_texts);
371
372int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
373 0x00, /* None */
374 0x04, /* Tone */
375 0x05,
376 0x06, /* Haptics */
377 0x08, /* AEC */
378 0x0c, /* Noise mixer */
379 0x0d, /* Comfort noise */
380 0x10, /* IN1L */
381 0x11,
382 0x12,
383 0x13,
384 0x14,
385 0x15,
Mark Brownc9c56fd2012-07-09 19:09:01 +0100386 0x16,
387 0x17,
Mark Brown07ed8732012-06-18 21:08:44 +0100388 0x20, /* AIF1RX1 */
389 0x21,
390 0x22,
391 0x23,
392 0x24,
393 0x25,
394 0x26,
395 0x27,
396 0x28, /* AIF2RX1 */
397 0x29,
398 0x30, /* AIF3RX1 */
399 0x31,
400 0x38, /* SLIMRX1 */
401 0x39,
402 0x3a,
403 0x3b,
404 0x3c,
405 0x3d,
406 0x3e,
407 0x3f,
408 0x50, /* EQ1 */
409 0x51,
410 0x52,
411 0x53,
412 0x58, /* DRC1L */
413 0x59,
414 0x5a,
415 0x5b,
416 0x60, /* LHPF1 */
417 0x61,
418 0x62,
419 0x63,
420 0x68, /* DSP1.1 */
421 0x69,
422 0x6a,
423 0x6b,
424 0x6c,
425 0x6d,
Mark Brownc922cc42012-09-26 16:43:44 +0100426 0x70, /* DSP2.1 */
427 0x71,
428 0x72,
429 0x73,
430 0x74,
431 0x75,
432 0x78, /* DSP3.1 */
433 0x79,
434 0x7a,
435 0x7b,
436 0x7c,
437 0x7d,
438 0x80, /* DSP4.1 */
439 0x81,
440 0x82,
441 0x83,
442 0x84,
443 0x85,
Mark Brown07ed8732012-06-18 21:08:44 +0100444 0x90, /* ASRC1L */
445 0x91,
446 0x92,
447 0x93,
Mark Brown91660bd2012-12-05 20:35:24 +0900448 0xa0, /* ISRC1INT1 */
449 0xa1,
450 0xa2,
451 0xa3,
452 0xa4, /* ISRC1DEC1 */
453 0xa5,
454 0xa6,
455 0xa7,
456 0xa8, /* ISRC2DEC1 */
457 0xa9,
458 0xaa,
459 0xab,
460 0xac, /* ISRC2INT1 */
461 0xad,
462 0xae,
463 0xaf,
464 0xb0, /* ISRC3DEC1 */
465 0xb1,
466 0xb2,
467 0xb3,
468 0xb4, /* ISRC3INT1 */
469 0xb5,
470 0xb6,
471 0xb7,
Mark Brown07ed8732012-06-18 21:08:44 +0100472};
473EXPORT_SYMBOL_GPL(arizona_mixer_values);
474
475const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
476EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
477
Mark Browndc914282013-02-18 19:09:23 +0000478const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = {
479 "SYNCCLK rate", "8kHz", "16kHz", "ASYNCCLK rate",
480};
481EXPORT_SYMBOL_GPL(arizona_rate_text);
482
483const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
484 0, 1, 2, 8,
485};
486EXPORT_SYMBOL_GPL(arizona_rate_val);
487
488
489const struct soc_enum arizona_isrc_fsl[] = {
490 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2,
491 ARIZONA_ISRC1_FSL_SHIFT, 0xf,
492 ARIZONA_RATE_ENUM_SIZE,
493 arizona_rate_text, arizona_rate_val),
494 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_2,
495 ARIZONA_ISRC2_FSL_SHIFT, 0xf,
496 ARIZONA_RATE_ENUM_SIZE,
497 arizona_rate_text, arizona_rate_val),
498 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_2,
499 ARIZONA_ISRC3_FSL_SHIFT, 0xf,
500 ARIZONA_RATE_ENUM_SIZE,
501 arizona_rate_text, arizona_rate_val),
502};
503EXPORT_SYMBOL_GPL(arizona_isrc_fsl);
504
Mark Browne853a002012-12-09 12:25:52 +0900505static const char *arizona_vol_ramp_text[] = {
506 "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
507 "15ms/6dB", "30ms/6dB",
508};
509
510const struct soc_enum arizona_in_vd_ramp =
511 SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP,
512 ARIZONA_IN_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text);
513EXPORT_SYMBOL_GPL(arizona_in_vd_ramp);
514
515const struct soc_enum arizona_in_vi_ramp =
516 SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP,
517 ARIZONA_IN_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text);
518EXPORT_SYMBOL_GPL(arizona_in_vi_ramp);
519
520const struct soc_enum arizona_out_vd_ramp =
521 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP,
522 ARIZONA_OUT_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text);
523EXPORT_SYMBOL_GPL(arizona_out_vd_ramp);
524
525const struct soc_enum arizona_out_vi_ramp =
526 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP,
527 ARIZONA_OUT_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text);
528EXPORT_SYMBOL_GPL(arizona_out_vi_ramp);
529
Mark Brown07ed8732012-06-18 21:08:44 +0100530static const char *arizona_lhpf_mode_text[] = {
531 "Low-pass", "High-pass"
532};
533
534const struct soc_enum arizona_lhpf1_mode =
535 SOC_ENUM_SINGLE(ARIZONA_HPLPF1_1, ARIZONA_LHPF1_MODE_SHIFT, 2,
536 arizona_lhpf_mode_text);
537EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
538
539const struct soc_enum arizona_lhpf2_mode =
540 SOC_ENUM_SINGLE(ARIZONA_HPLPF2_1, ARIZONA_LHPF2_MODE_SHIFT, 2,
541 arizona_lhpf_mode_text);
542EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
543
544const struct soc_enum arizona_lhpf3_mode =
545 SOC_ENUM_SINGLE(ARIZONA_HPLPF3_1, ARIZONA_LHPF3_MODE_SHIFT, 2,
546 arizona_lhpf_mode_text);
547EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
548
549const struct soc_enum arizona_lhpf4_mode =
550 SOC_ENUM_SINGLE(ARIZONA_HPLPF4_1, ARIZONA_LHPF4_MODE_SHIFT, 2,
551 arizona_lhpf_mode_text);
552EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
553
Mark Brown845571c2012-12-18 13:47:57 +0000554static const char *arizona_ng_hold_text[] = {
555 "30ms", "120ms", "250ms", "500ms",
556};
557
558const struct soc_enum arizona_ng_hold =
559 SOC_ENUM_SINGLE(ARIZONA_NOISE_GATE_CONTROL, ARIZONA_NGATE_HOLD_SHIFT,
560 4, arizona_ng_hold_text);
561EXPORT_SYMBOL_GPL(arizona_ng_hold);
562
Charles Keepaxc7f38432013-08-06 17:03:55 +0100563static const char * const arizona_in_dmic_osr_text[] = {
564 "1.536MHz", "3.072MHz", "6.144MHz",
565};
566
567const struct soc_enum arizona_in_dmic_osr[] = {
568 SOC_ENUM_SINGLE(ARIZONA_IN1L_CONTROL, ARIZONA_IN1_OSR_SHIFT,
569 ARRAY_SIZE(arizona_in_dmic_osr_text),
570 arizona_in_dmic_osr_text),
571 SOC_ENUM_SINGLE(ARIZONA_IN2L_CONTROL, ARIZONA_IN2_OSR_SHIFT,
572 ARRAY_SIZE(arizona_in_dmic_osr_text),
573 arizona_in_dmic_osr_text),
574 SOC_ENUM_SINGLE(ARIZONA_IN3L_CONTROL, ARIZONA_IN3_OSR_SHIFT,
575 ARRAY_SIZE(arizona_in_dmic_osr_text),
576 arizona_in_dmic_osr_text),
577 SOC_ENUM_SINGLE(ARIZONA_IN4L_CONTROL, ARIZONA_IN4_OSR_SHIFT,
578 ARRAY_SIZE(arizona_in_dmic_osr_text),
579 arizona_in_dmic_osr_text),
580};
581EXPORT_SYMBOL_GPL(arizona_in_dmic_osr);
582
Mark Brownddbce972013-02-15 17:27:22 +0000583static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
584{
585 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
586 unsigned int val;
587 int i;
588
589 if (ena)
590 val = ARIZONA_IN_VU;
591 else
592 val = 0;
593
594 for (i = 0; i < priv->num_inputs; i++)
595 snd_soc_update_bits(codec,
596 ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 4),
597 ARIZONA_IN_VU, val);
598}
599
Mark Brown07ed8732012-06-18 21:08:44 +0100600int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
601 int event)
602{
Mark Brownddbce972013-02-15 17:27:22 +0000603 struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000604 unsigned int reg;
605
606 if (w->shift % 2)
607 reg = ARIZONA_ADC_DIGITAL_VOLUME_1L + ((w->shift / 2) * 8);
608 else
609 reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8);
610
611 switch (event) {
Mark Brownddbce972013-02-15 17:27:22 +0000612 case SND_SOC_DAPM_PRE_PMU:
613 priv->in_pending++;
614 break;
Mark Brown43cd8bf2013-02-06 16:57:29 +0000615 case SND_SOC_DAPM_POST_PMU:
616 snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, 0);
Mark Brownddbce972013-02-15 17:27:22 +0000617
618 /* If this is the last input pending then allow VU */
619 priv->in_pending--;
620 if (priv->in_pending == 0) {
621 msleep(1);
622 arizona_in_set_vu(w->codec, 1);
623 }
Mark Brown43cd8bf2013-02-06 16:57:29 +0000624 break;
625 case SND_SOC_DAPM_PRE_PMD:
Mark Brownddbce972013-02-15 17:27:22 +0000626 snd_soc_update_bits(w->codec, reg,
627 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU,
628 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000629 break;
Mark Brownddbce972013-02-15 17:27:22 +0000630 case SND_SOC_DAPM_POST_PMD:
631 /* Disable volume updates if no inputs are enabled */
632 reg = snd_soc_read(w->codec, ARIZONA_INPUT_ENABLES);
633 if (reg == 0)
634 arizona_in_set_vu(w->codec, 0);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000635 }
636
Mark Brown07ed8732012-06-18 21:08:44 +0100637 return 0;
638}
639EXPORT_SYMBOL_GPL(arizona_in_ev);
640
641int arizona_out_ev(struct snd_soc_dapm_widget *w,
642 struct snd_kcontrol *kcontrol,
643 int event)
644{
Mark Brown1a2c7d52013-03-24 22:50:23 +0000645 switch (event) {
646 case SND_SOC_DAPM_POST_PMU:
647 switch (w->shift) {
648 case ARIZONA_OUT1L_ENA_SHIFT:
649 case ARIZONA_OUT1R_ENA_SHIFT:
650 case ARIZONA_OUT2L_ENA_SHIFT:
651 case ARIZONA_OUT2R_ENA_SHIFT:
652 case ARIZONA_OUT3L_ENA_SHIFT:
653 case ARIZONA_OUT3R_ENA_SHIFT:
654 msleep(17);
655 break;
656
657 default:
658 break;
659 }
660 break;
661 }
662
Mark Brown07ed8732012-06-18 21:08:44 +0100663 return 0;
664}
665EXPORT_SYMBOL_GPL(arizona_out_ev);
666
Mark Brownf607e312013-02-22 18:36:53 +0000667int arizona_hp_ev(struct snd_soc_dapm_widget *w,
668 struct snd_kcontrol *kcontrol,
669 int event)
670{
671 struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
672 unsigned int mask = 1 << w->shift;
673 unsigned int val;
674
675 switch (event) {
676 case SND_SOC_DAPM_POST_PMU:
677 val = mask;
678 break;
679 case SND_SOC_DAPM_PRE_PMD:
680 val = 0;
681 break;
682 default:
683 return -EINVAL;
684 }
685
686 /* Store the desired state for the HP outputs */
687 priv->arizona->hp_ena &= ~mask;
688 priv->arizona->hp_ena |= val;
689
690 /* Force off if HPDET magic is active */
691 if (priv->arizona->hpdet_magic)
692 val = 0;
693
694 snd_soc_update_bits(w->codec, ARIZONA_OUTPUT_ENABLES_1, mask, val);
695
696 return arizona_out_ev(w, kcontrol, event);
697}
698EXPORT_SYMBOL_GPL(arizona_hp_ev);
699
Mark Browncbd840d2012-08-08 17:52:44 +0100700static unsigned int arizona_sysclk_48k_rates[] = {
701 6144000,
702 12288000,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000703 24576000,
Mark Browncbd840d2012-08-08 17:52:44 +0100704 49152000,
Mark Brownaeaeee12012-09-26 17:50:02 +0100705 73728000,
706 98304000,
707 147456000,
Mark Browncbd840d2012-08-08 17:52:44 +0100708};
709
710static unsigned int arizona_sysclk_44k1_rates[] = {
711 5644800,
712 11289600,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000713 22579200,
Mark Browncbd840d2012-08-08 17:52:44 +0100714 45158400,
Mark Brownaeaeee12012-09-26 17:50:02 +0100715 67737600,
716 90316800,
717 135475200,
Mark Browncbd840d2012-08-08 17:52:44 +0100718};
719
720static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
721 unsigned int freq)
722{
723 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
724 unsigned int reg;
725 unsigned int *rates;
726 int ref, div, refclk;
727
728 switch (clk) {
729 case ARIZONA_CLK_OPCLK:
730 reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
731 refclk = priv->sysclk;
732 break;
733 case ARIZONA_CLK_ASYNC_OPCLK:
734 reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
735 refclk = priv->asyncclk;
736 break;
737 default:
738 return -EINVAL;
739 }
740
741 if (refclk % 8000)
742 rates = arizona_sysclk_44k1_rates;
743 else
744 rates = arizona_sysclk_48k_rates;
745
746 for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) &&
747 rates[ref] <= refclk; ref++) {
748 div = 1;
749 while (rates[ref] / div >= freq && div < 32) {
750 if (rates[ref] / div == freq) {
751 dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
752 freq);
753 snd_soc_update_bits(codec, reg,
754 ARIZONA_OPCLK_DIV_MASK |
755 ARIZONA_OPCLK_SEL_MASK,
756 (div <<
757 ARIZONA_OPCLK_DIV_SHIFT) |
758 ref);
759 return 0;
760 }
761 div++;
762 }
763 }
764
765 dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
766 return -EINVAL;
767}
768
Mark Brown07ed8732012-06-18 21:08:44 +0100769int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
770 int source, unsigned int freq, int dir)
771{
772 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
773 struct arizona *arizona = priv->arizona;
774 char *name;
775 unsigned int reg;
776 unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
777 unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
778 unsigned int *clk;
779
780 switch (clk_id) {
781 case ARIZONA_CLK_SYSCLK:
782 name = "SYSCLK";
783 reg = ARIZONA_SYSTEM_CLOCK_1;
784 clk = &priv->sysclk;
785 mask |= ARIZONA_SYSCLK_FRAC;
786 break;
787 case ARIZONA_CLK_ASYNCCLK:
788 name = "ASYNCCLK";
789 reg = ARIZONA_ASYNC_CLOCK_1;
790 clk = &priv->asyncclk;
791 break;
Mark Browncbd840d2012-08-08 17:52:44 +0100792 case ARIZONA_CLK_OPCLK:
793 case ARIZONA_CLK_ASYNC_OPCLK:
794 return arizona_set_opclk(codec, clk_id, freq);
Mark Brown07ed8732012-06-18 21:08:44 +0100795 default:
796 return -EINVAL;
797 }
798
799 switch (freq) {
800 case 5644800:
801 case 6144000:
802 break;
803 case 11289600:
804 case 12288000:
Mark Brown3f341f72013-03-08 15:22:29 +0800805 val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100806 break;
807 case 22579200:
808 case 24576000:
Mark Brown3f341f72013-03-08 15:22:29 +0800809 val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100810 break;
811 case 45158400:
812 case 49152000:
Mark Brown3f341f72013-03-08 15:22:29 +0800813 val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100814 break;
Mark Brown38113362012-11-26 16:01:37 +0000815 case 67737600:
816 case 73728000:
Mark Brown3f341f72013-03-08 15:22:29 +0800817 val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000818 break;
819 case 90316800:
820 case 98304000:
Mark Brown3f341f72013-03-08 15:22:29 +0800821 val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000822 break;
823 case 135475200:
824 case 147456000:
Mark Brown3f341f72013-03-08 15:22:29 +0800825 val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000826 break;
Mark Brownf2c26d42013-01-21 16:09:36 +0900827 case 0:
828 dev_dbg(arizona->dev, "%s cleared\n", name);
829 *clk = freq;
830 return 0;
Mark Brown07ed8732012-06-18 21:08:44 +0100831 default:
832 return -EINVAL;
833 }
834
835 *clk = freq;
836
837 if (freq % 6144000)
838 val |= ARIZONA_SYSCLK_FRAC;
839
840 dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
841
842 return regmap_update_bits(arizona->regmap, reg, mask, val);
843}
844EXPORT_SYMBOL_GPL(arizona_set_sysclk);
845
846static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
847{
848 struct snd_soc_codec *codec = dai->codec;
849 int lrclk, bclk, mode, base;
850
851 base = dai->driver->base;
852
853 lrclk = 0;
854 bclk = 0;
855
856 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
857 case SND_SOC_DAIFMT_DSP_A:
858 mode = 0;
859 break;
Mark Brown07ed8732012-06-18 21:08:44 +0100860 case SND_SOC_DAIFMT_I2S:
861 mode = 2;
862 break;
Mark Brown07ed8732012-06-18 21:08:44 +0100863 default:
864 arizona_aif_err(dai, "Unsupported DAI format %d\n",
865 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
866 return -EINVAL;
867 }
868
869 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
870 case SND_SOC_DAIFMT_CBS_CFS:
871 break;
872 case SND_SOC_DAIFMT_CBS_CFM:
873 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
874 break;
875 case SND_SOC_DAIFMT_CBM_CFS:
876 bclk |= ARIZONA_AIF1_BCLK_MSTR;
877 break;
878 case SND_SOC_DAIFMT_CBM_CFM:
879 bclk |= ARIZONA_AIF1_BCLK_MSTR;
880 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
881 break;
882 default:
883 arizona_aif_err(dai, "Unsupported master mode %d\n",
884 fmt & SND_SOC_DAIFMT_MASTER_MASK);
885 return -EINVAL;
886 }
887
888 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
889 case SND_SOC_DAIFMT_NB_NF:
890 break;
891 case SND_SOC_DAIFMT_IB_IF:
892 bclk |= ARIZONA_AIF1_BCLK_INV;
893 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
894 break;
895 case SND_SOC_DAIFMT_IB_NF:
896 bclk |= ARIZONA_AIF1_BCLK_INV;
897 break;
898 case SND_SOC_DAIFMT_NB_IF:
899 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
900 break;
901 default:
902 return -EINVAL;
903 }
904
905 snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
906 ARIZONA_AIF1_BCLK_INV | ARIZONA_AIF1_BCLK_MSTR,
907 bclk);
908 snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_PIN_CTRL,
909 ARIZONA_AIF1TX_LRCLK_INV |
910 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
911 snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_PIN_CTRL,
912 ARIZONA_AIF1RX_LRCLK_INV |
913 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
914 snd_soc_update_bits(codec, base + ARIZONA_AIF_FORMAT,
915 ARIZONA_AIF1_FMT_MASK, mode);
916
917 return 0;
918}
919
Mark Brown949e6bc2012-07-04 18:58:04 +0100920static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100921 -1,
922 48000,
923 64000,
924 96000,
925 128000,
926 192000,
927 256000,
928 384000,
929 512000,
930 768000,
931 1024000,
932 1536000,
933 2048000,
934 3072000,
935 4096000,
936 6144000,
937 8192000,
938 12288000,
939 24576000,
940};
941
Mark Brown5b2eec32012-07-04 17:32:05 +0100942static const unsigned int arizona_48k_rates[] = {
943 12000,
944 24000,
945 48000,
946 96000,
947 192000,
948 384000,
949 768000,
950 4000,
951 8000,
952 16000,
953 32000,
954 64000,
955 128000,
956 256000,
957 512000,
958};
959
960static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = {
961 .count = ARRAY_SIZE(arizona_48k_rates),
962 .list = arizona_48k_rates,
963};
964
Mark Brown949e6bc2012-07-04 18:58:04 +0100965static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100966 -1,
967 44100,
968 58800,
969 88200,
970 117600,
971 177640,
972 235200,
973 352800,
974 470400,
975 705600,
976 940800,
977 1411200,
978 1881600,
Heather Lomond4758be32012-09-05 05:02:10 -0400979 2822400,
Mark Brown07ed8732012-06-18 21:08:44 +0100980 3763200,
981 5644800,
982 7526400,
983 11289600,
984 22579200,
985};
986
Mark Brown5b2eec32012-07-04 17:32:05 +0100987static const unsigned int arizona_44k1_rates[] = {
988 11025,
989 22050,
990 44100,
991 88200,
992 176400,
993 352800,
994 705600,
995};
996
997static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = {
998 .count = ARRAY_SIZE(arizona_44k1_rates),
999 .list = arizona_44k1_rates,
1000};
1001
Mark Brown07ed8732012-06-18 21:08:44 +01001002static int arizona_sr_vals[] = {
1003 0,
1004 12000,
1005 24000,
1006 48000,
1007 96000,
1008 192000,
1009 384000,
1010 768000,
1011 0,
1012 11025,
1013 22050,
1014 44100,
1015 88200,
1016 176400,
1017 352800,
1018 705600,
1019 4000,
1020 8000,
1021 16000,
1022 32000,
1023 64000,
1024 128000,
1025 256000,
1026 512000,
1027};
1028
Mark Brown5b2eec32012-07-04 17:32:05 +01001029static int arizona_startup(struct snd_pcm_substream *substream,
1030 struct snd_soc_dai *dai)
1031{
1032 struct snd_soc_codec *codec = dai->codec;
1033 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1034 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
1035 const struct snd_pcm_hw_constraint_list *constraint;
1036 unsigned int base_rate;
1037
1038 switch (dai_priv->clk) {
1039 case ARIZONA_CLK_SYSCLK:
1040 base_rate = priv->sysclk;
1041 break;
1042 case ARIZONA_CLK_ASYNCCLK:
1043 base_rate = priv->asyncclk;
1044 break;
1045 default:
1046 return 0;
1047 }
1048
Mark Brownf2c26d42013-01-21 16:09:36 +09001049 if (base_rate == 0)
1050 return 0;
1051
Mark Brown5b2eec32012-07-04 17:32:05 +01001052 if (base_rate % 8000)
1053 constraint = &arizona_44k1_constraint;
1054 else
1055 constraint = &arizona_48k_constraint;
1056
1057 return snd_pcm_hw_constraint_list(substream->runtime, 0,
1058 SNDRV_PCM_HW_PARAM_RATE,
1059 constraint);
1060}
1061
Mark Brownb272efc2012-10-10 15:10:08 +09001062static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
1063 struct snd_pcm_hw_params *params,
1064 struct snd_soc_dai *dai)
Mark Brown07ed8732012-06-18 21:08:44 +01001065{
1066 struct snd_soc_codec *codec = dai->codec;
Mark Brownc013b272012-07-04 20:05:57 +01001067 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1068 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown07ed8732012-06-18 21:08:44 +01001069 int base = dai->driver->base;
Mark Brownb272efc2012-10-10 15:10:08 +09001070 int i, sr_val;
1071
1072 /*
1073 * We will need to be more flexible than this in future,
1074 * currently we use a single sample rate for SYSCLK.
1075 */
1076 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
1077 if (arizona_sr_vals[i] == params_rate(params))
1078 break;
1079 if (i == ARRAY_SIZE(arizona_sr_vals)) {
1080 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1081 params_rate(params));
1082 return -EINVAL;
1083 }
1084 sr_val = i;
1085
1086 switch (dai_priv->clk) {
1087 case ARIZONA_CLK_SYSCLK:
1088 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
1089 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
1090 if (base)
1091 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1092 ARIZONA_AIF1_RATE_MASK, 0);
1093 break;
1094 case ARIZONA_CLK_ASYNCCLK:
1095 snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
1096 ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val);
1097 if (base)
1098 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1099 ARIZONA_AIF1_RATE_MASK,
1100 8 << ARIZONA_AIF1_RATE_SHIFT);
1101 break;
1102 default:
1103 arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
1104 return -EINVAL;
1105 }
1106
1107 return 0;
1108}
1109
Mark Brown07ed8732012-06-18 21:08:44 +01001110static int arizona_hw_params(struct snd_pcm_substream *substream,
1111 struct snd_pcm_hw_params *params,
1112 struct snd_soc_dai *dai)
1113{
1114 struct snd_soc_codec *codec = dai->codec;
1115 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brownc94aa302013-01-17 16:35:14 +09001116 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +01001117 int base = dai->driver->base;
1118 const int *rates;
Mark Brown76bf9692013-03-05 14:17:47 +08001119 int i, ret, val;
Mark Brownc94aa302013-01-17 16:35:14 +09001120 int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
1121 int bclk, lrclk, wl, frame, bclk_target;
Mark Brown07ed8732012-06-18 21:08:44 +01001122
1123 if (params_rate(params) % 8000)
Mark Brown949e6bc2012-07-04 18:58:04 +01001124 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001125 else
Mark Brown949e6bc2012-07-04 18:58:04 +01001126 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001127
Mark Brownc94aa302013-01-17 16:35:14 +09001128 bclk_target = snd_soc_params_to_bclk(params);
1129 if (chan_limit && chan_limit < params_channels(params)) {
1130 arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
1131 bclk_target /= params_channels(params);
1132 bclk_target *= chan_limit;
1133 }
1134
Mark Brown76bf9692013-03-05 14:17:47 +08001135 /* Force stereo for I2S mode */
1136 val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
1137 if (params_channels(params) == 1 && (val & ARIZONA_AIF1_FMT_MASK)) {
1138 arizona_aif_dbg(dai, "Forcing stereo mode\n");
1139 bclk_target *= 2;
1140 }
1141
Mark Brown949e6bc2012-07-04 18:58:04 +01001142 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brownc94aa302013-01-17 16:35:14 +09001143 if (rates[i] >= bclk_target &&
Mark Brown50017652012-07-04 19:07:09 +01001144 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +01001145 bclk = i;
1146 break;
1147 }
1148 }
Mark Brown949e6bc2012-07-04 18:58:04 +01001149 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001150 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1151 params_rate(params));
1152 return -EINVAL;
1153 }
1154
Mark Brownb59e0f82013-01-17 14:15:59 +09001155 lrclk = rates[bclk] / params_rate(params);
Mark Brown07ed8732012-06-18 21:08:44 +01001156
1157 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
1158 rates[bclk], rates[bclk] / lrclk);
1159
1160 wl = snd_pcm_format_width(params_format(params));
1161 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl;
1162
Mark Brownb272efc2012-10-10 15:10:08 +09001163 ret = arizona_hw_params_rate(substream, params, dai);
1164 if (ret != 0)
1165 return ret;
Mark Brownc013b272012-07-04 20:05:57 +01001166
Mark Brown07ed8732012-06-18 21:08:44 +01001167 snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
1168 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
1169 snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_BCLK_RATE,
1170 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
1171 snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_BCLK_RATE,
1172 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
1173 snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_1,
1174 ARIZONA_AIF1TX_WL_MASK |
1175 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
1176 snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_2,
1177 ARIZONA_AIF1RX_WL_MASK |
1178 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
1179
1180 return 0;
1181}
1182
Mark Brown410837a2012-07-05 17:26:59 +01001183static const char *arizona_dai_clk_str(int clk_id)
1184{
1185 switch (clk_id) {
1186 case ARIZONA_CLK_SYSCLK:
1187 return "SYSCLK";
1188 case ARIZONA_CLK_ASYNCCLK:
1189 return "ASYNCCLK";
1190 default:
1191 return "Unknown clock";
1192 }
1193}
1194
Mark Brown5b2eec32012-07-04 17:32:05 +01001195static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
1196 int clk_id, unsigned int freq, int dir)
1197{
1198 struct snd_soc_codec *codec = dai->codec;
1199 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1200 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown410837a2012-07-05 17:26:59 +01001201 struct snd_soc_dapm_route routes[2];
Mark Brown5b2eec32012-07-04 17:32:05 +01001202
1203 switch (clk_id) {
1204 case ARIZONA_CLK_SYSCLK:
1205 case ARIZONA_CLK_ASYNCCLK:
1206 break;
1207 default:
1208 return -EINVAL;
1209 }
1210
Mark Brown410837a2012-07-05 17:26:59 +01001211 if (clk_id == dai_priv->clk)
1212 return 0;
1213
1214 if (dai->active) {
Mark Brown5b2eec32012-07-04 17:32:05 +01001215 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
1216 dai->id);
1217 return -EBUSY;
1218 }
1219
Mark Brownc8d35a62012-12-07 12:49:40 +09001220 dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1,
1221 arizona_dai_clk_str(clk_id));
1222
Mark Brown410837a2012-07-05 17:26:59 +01001223 memset(&routes, 0, sizeof(routes));
1224 routes[0].sink = dai->driver->capture.stream_name;
1225 routes[1].sink = dai->driver->playback.stream_name;
Mark Brown5b2eec32012-07-04 17:32:05 +01001226
Mark Brown410837a2012-07-05 17:26:59 +01001227 routes[0].source = arizona_dai_clk_str(dai_priv->clk);
1228 routes[1].source = arizona_dai_clk_str(dai_priv->clk);
1229 snd_soc_dapm_del_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
1230
1231 routes[0].source = arizona_dai_clk_str(clk_id);
1232 routes[1].source = arizona_dai_clk_str(clk_id);
1233 snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
1234
Mark Brown0c778e82012-12-06 18:22:25 +09001235 dai_priv->clk = clk_id;
1236
Mark Brown410837a2012-07-05 17:26:59 +01001237 return snd_soc_dapm_sync(&codec->dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +01001238}
1239
Mark Brown01df2592012-12-12 16:22:08 +09001240static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
1241{
1242 struct snd_soc_codec *codec = dai->codec;
1243 int base = dai->driver->base;
1244 unsigned int reg;
1245
1246 if (tristate)
1247 reg = ARIZONA_AIF1_TRI;
1248 else
1249 reg = 0;
1250
1251 return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1252 ARIZONA_AIF1_TRI, reg);
1253}
1254
Mark Brown07ed8732012-06-18 21:08:44 +01001255const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +01001256 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +01001257 .set_fmt = arizona_set_fmt,
1258 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +01001259 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown01df2592012-12-12 16:22:08 +09001260 .set_tristate = arizona_set_tristate,
Mark Brown07ed8732012-06-18 21:08:44 +01001261};
Mark Browna8379872012-07-09 12:16:41 +01001262EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +01001263
Mark Brownbd1dd882013-05-17 13:29:03 +01001264const struct snd_soc_dai_ops arizona_simple_dai_ops = {
1265 .startup = arizona_startup,
1266 .hw_params = arizona_hw_params_rate,
1267 .set_sysclk = arizona_dai_set_sysclk,
1268};
1269EXPORT_SYMBOL_GPL(arizona_simple_dai_ops);
1270
Mark Brown5b2eec32012-07-04 17:32:05 +01001271int arizona_init_dai(struct arizona_priv *priv, int id)
1272{
1273 struct arizona_dai_priv *dai_priv = &priv->dai[id];
1274
1275 dai_priv->clk = ARIZONA_CLK_SYSCLK;
1276
1277 return 0;
1278}
1279EXPORT_SYMBOL_GPL(arizona_init_dai);
1280
Mark Brown07ed8732012-06-18 21:08:44 +01001281static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
1282{
1283 struct arizona_fll *fll = data;
1284
1285 arizona_fll_dbg(fll, "clock OK\n");
1286
1287 complete(&fll->ok);
1288
1289 return IRQ_HANDLED;
1290}
1291
1292static struct {
1293 unsigned int min;
1294 unsigned int max;
1295 u16 fratio;
1296 int ratio;
1297} fll_fratios[] = {
1298 { 0, 64000, 4, 16 },
1299 { 64000, 128000, 3, 8 },
1300 { 128000, 256000, 2, 4 },
1301 { 256000, 1000000, 1, 2 },
1302 { 1000000, 13500000, 0, 1 },
1303};
1304
Mark Brown8f113d72013-03-05 12:08:57 +08001305static struct {
1306 unsigned int min;
1307 unsigned int max;
1308 u16 gain;
1309} fll_gains[] = {
1310 { 0, 256000, 0 },
1311 { 256000, 1000000, 2 },
1312 { 1000000, 13500000, 4 },
1313};
1314
Mark Brown07ed8732012-06-18 21:08:44 +01001315struct arizona_fll_cfg {
1316 int n;
1317 int theta;
1318 int lambda;
1319 int refdiv;
1320 int outdiv;
1321 int fratio;
Mark Brown8f113d72013-03-05 12:08:57 +08001322 int gain;
Mark Brown07ed8732012-06-18 21:08:44 +01001323};
1324
1325static int arizona_calc_fll(struct arizona_fll *fll,
1326 struct arizona_fll_cfg *cfg,
1327 unsigned int Fref,
1328 unsigned int Fout)
1329{
1330 unsigned int target, div, gcd_fll;
1331 int i, ratio;
1332
1333 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout);
1334
1335 /* Fref must be <=13.5MHz */
1336 div = 1;
1337 cfg->refdiv = 0;
1338 while ((Fref / div) > 13500000) {
1339 div *= 2;
1340 cfg->refdiv++;
1341
1342 if (div > 8) {
1343 arizona_fll_err(fll,
1344 "Can't scale %dMHz in to <=13.5MHz\n",
1345 Fref);
1346 return -EINVAL;
1347 }
1348 }
1349
1350 /* Apply the division for our remaining calculations */
1351 Fref /= div;
1352
Mark Brown2b4d39f2012-07-10 17:03:46 +01001353 /* Fvco should be over the targt; don't check the upper bound */
Mark Brown07ed8732012-06-18 21:08:44 +01001354 div = 1;
Mark Brown2b4d39f2012-07-10 17:03:46 +01001355 while (Fout * div < 90000000 * fll->vco_mult) {
Mark Brown07ed8732012-06-18 21:08:44 +01001356 div++;
1357 if (div > 7) {
1358 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
1359 Fout);
1360 return -EINVAL;
1361 }
1362 }
Mark Brown2b4d39f2012-07-10 17:03:46 +01001363 target = Fout * div / fll->vco_mult;
Mark Brown07ed8732012-06-18 21:08:44 +01001364 cfg->outdiv = div;
1365
1366 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
1367
1368 /* Find an appropraite FLL_FRATIO and factor it out of the target */
1369 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
1370 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
1371 cfg->fratio = fll_fratios[i].fratio;
1372 ratio = fll_fratios[i].ratio;
1373 break;
1374 }
1375 }
1376 if (i == ARRAY_SIZE(fll_fratios)) {
1377 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
1378 Fref);
1379 return -EINVAL;
1380 }
1381
Mark Brown8f113d72013-03-05 12:08:57 +08001382 for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
1383 if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
1384 cfg->gain = fll_gains[i].gain;
1385 break;
1386 }
1387 }
1388 if (i == ARRAY_SIZE(fll_gains)) {
1389 arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
1390 Fref);
1391 return -EINVAL;
1392 }
1393
Mark Brown07ed8732012-06-18 21:08:44 +01001394 cfg->n = target / (ratio * Fref);
1395
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001396 if (target % (ratio * Fref)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001397 gcd_fll = gcd(target, ratio * Fref);
1398 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
1399
1400 cfg->theta = (target - (cfg->n * ratio * Fref))
1401 / gcd_fll;
1402 cfg->lambda = (ratio * Fref) / gcd_fll;
1403 } else {
1404 cfg->theta = 0;
1405 cfg->lambda = 0;
1406 }
1407
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001408 /* Round down to 16bit range with cost of accuracy lost.
1409 * Denominator must be bigger than numerator so we only
1410 * take care of it.
1411 */
1412 while (cfg->lambda >= (1 << 16)) {
1413 cfg->theta >>= 1;
1414 cfg->lambda >>= 1;
1415 }
1416
Mark Brown07ed8732012-06-18 21:08:44 +01001417 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
1418 cfg->n, cfg->theta, cfg->lambda);
1419 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
1420 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08001421 arizona_fll_dbg(fll, "GAIN=%d\n", cfg->gain);
Mark Brown07ed8732012-06-18 21:08:44 +01001422
1423 return 0;
1424
1425}
1426
1427static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
Mark Brown8f113d72013-03-05 12:08:57 +08001428 struct arizona_fll_cfg *cfg, int source,
1429 bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01001430{
1431 regmap_update_bits(arizona->regmap, base + 3,
1432 ARIZONA_FLL1_THETA_MASK, cfg->theta);
1433 regmap_update_bits(arizona->regmap, base + 4,
1434 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
1435 regmap_update_bits(arizona->regmap, base + 5,
1436 ARIZONA_FLL1_FRATIO_MASK,
1437 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
1438 regmap_update_bits(arizona->regmap, base + 6,
1439 ARIZONA_FLL1_CLK_REF_DIV_MASK |
1440 ARIZONA_FLL1_CLK_REF_SRC_MASK,
1441 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
1442 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
1443
Mark Brown8f113d72013-03-05 12:08:57 +08001444 if (sync)
1445 regmap_update_bits(arizona->regmap, base + 0x7,
1446 ARIZONA_FLL1_GAIN_MASK,
1447 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
1448 else
1449 regmap_update_bits(arizona->regmap, base + 0x9,
1450 ARIZONA_FLL1_GAIN_MASK,
1451 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
1452
Mark Brown07ed8732012-06-18 21:08:44 +01001453 regmap_update_bits(arizona->regmap, base + 2,
1454 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
1455 ARIZONA_FLL1_CTRL_UPD | cfg->n);
1456}
1457
Charles Keepaxd122d6c2013-02-20 17:28:36 +00001458static bool arizona_is_enabled_fll(struct arizona_fll *fll)
1459{
1460 struct arizona *arizona = fll->arizona;
1461 unsigned int reg;
1462 int ret;
1463
1464 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
1465 if (ret != 0) {
1466 arizona_fll_err(fll, "Failed to read current state: %d\n",
1467 ret);
1468 return ret;
1469 }
1470
1471 return reg & ARIZONA_FLL1_ENA;
1472}
1473
Charles Keepax35722812013-02-20 17:28:38 +00001474static void arizona_enable_fll(struct arizona_fll *fll,
1475 struct arizona_fll_cfg *ref,
1476 struct arizona_fll_cfg *sync)
1477{
1478 struct arizona *arizona = fll->arizona;
1479 int ret;
1480
Mark Brownff680a12013-03-04 16:00:19 +08001481 /*
1482 * If we have both REFCLK and SYNCCLK then enable both,
1483 * otherwise apply the SYNCCLK settings to REFCLK.
1484 */
1485 if (fll->ref_src >= 0 && fll->ref_src != fll->sync_src) {
1486 regmap_update_bits(arizona->regmap, fll->base + 5,
1487 ARIZONA_FLL1_OUTDIV_MASK,
1488 ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
Charles Keepax35722812013-02-20 17:28:38 +00001489
Mark Brown8f113d72013-03-05 12:08:57 +08001490 arizona_apply_fll(arizona, fll->base, ref, fll->ref_src,
1491 false);
Mark Brownff680a12013-03-04 16:00:19 +08001492 if (fll->sync_src >= 0)
1493 arizona_apply_fll(arizona, fll->base + 0x10, sync,
Mark Brown8f113d72013-03-05 12:08:57 +08001494 fll->sync_src, true);
Mark Brownff680a12013-03-04 16:00:19 +08001495 } else if (fll->sync_src >= 0) {
1496 regmap_update_bits(arizona->regmap, fll->base + 5,
1497 ARIZONA_FLL1_OUTDIV_MASK,
1498 sync->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
1499
1500 arizona_apply_fll(arizona, fll->base, sync,
Mark Brown8f113d72013-03-05 12:08:57 +08001501 fll->sync_src, false);
Mark Browneca2e8e2013-03-06 00:09:59 +08001502
1503 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1504 ARIZONA_FLL1_SYNC_ENA, 0);
Mark Brownff680a12013-03-04 16:00:19 +08001505 } else {
1506 arizona_fll_err(fll, "No clocks provided\n");
1507 return;
1508 }
Charles Keepax35722812013-02-20 17:28:38 +00001509
Mark Brown576411be2013-03-05 12:07:16 +08001510 /*
1511 * Increase the bandwidth if we're not using a low frequency
1512 * sync source.
1513 */
1514 if (fll->sync_src >= 0 && fll->sync_freq > 100000)
1515 regmap_update_bits(arizona->regmap, fll->base + 0x17,
1516 ARIZONA_FLL1_SYNC_BW, 0);
1517 else
1518 regmap_update_bits(arizona->regmap, fll->base + 0x17,
1519 ARIZONA_FLL1_SYNC_BW, ARIZONA_FLL1_SYNC_BW);
1520
Charles Keepax35722812013-02-20 17:28:38 +00001521 if (!arizona_is_enabled_fll(fll))
1522 pm_runtime_get(arizona->dev);
1523
1524 /* Clear any pending completions */
1525 try_wait_for_completion(&fll->ok);
1526
1527 regmap_update_bits(arizona->regmap, fll->base + 1,
1528 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
Mark Brownff680a12013-03-04 16:00:19 +08001529 if (fll->ref_src >= 0 && fll->sync_src >= 0 &&
1530 fll->ref_src != fll->sync_src)
Charles Keepax35722812013-02-20 17:28:38 +00001531 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1532 ARIZONA_FLL1_SYNC_ENA,
1533 ARIZONA_FLL1_SYNC_ENA);
1534
1535 ret = wait_for_completion_timeout(&fll->ok,
1536 msecs_to_jiffies(250));
1537 if (ret == 0)
1538 arizona_fll_warn(fll, "Timed out waiting for lock\n");
1539}
1540
Charles Keepax76040542013-02-20 17:28:37 +00001541static void arizona_disable_fll(struct arizona_fll *fll)
1542{
1543 struct arizona *arizona = fll->arizona;
1544 bool change;
1545
1546 regmap_update_bits_check(arizona->regmap, fll->base + 1,
1547 ARIZONA_FLL1_ENA, 0, &change);
1548 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1549 ARIZONA_FLL1_SYNC_ENA, 0);
1550
1551 if (change)
1552 pm_runtime_put_autosuspend(arizona->dev);
1553}
1554
Charles Keepaxee929a92013-02-20 17:28:40 +00001555int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
1556 unsigned int Fref, unsigned int Fout)
1557{
1558 struct arizona_fll_cfg ref, sync;
1559 int ret;
1560
Charles Keepax1c5617f2013-02-22 17:10:37 +00001561 if (fll->ref_src == source && fll->ref_freq == Fref)
Charles Keepaxee929a92013-02-20 17:28:40 +00001562 return 0;
1563
Mark Brown86cd6842013-03-07 16:14:04 +08001564 if (fll->fout && Fref > 0) {
Charles Keepax1c5617f2013-02-22 17:10:37 +00001565 ret = arizona_calc_fll(fll, &ref, Fref, fll->fout);
Charles Keepaxee929a92013-02-20 17:28:40 +00001566 if (ret != 0)
1567 return ret;
1568
1569 if (fll->sync_src >= 0) {
Charles Keepax1c5617f2013-02-22 17:10:37 +00001570 ret = arizona_calc_fll(fll, &sync, fll->sync_freq,
1571 fll->fout);
Charles Keepaxee929a92013-02-20 17:28:40 +00001572 if (ret != 0)
1573 return ret;
1574 }
1575 }
1576
1577 fll->ref_src = source;
1578 fll->ref_freq = Fref;
Charles Keepaxee929a92013-02-20 17:28:40 +00001579
Mark Brown86cd6842013-03-07 16:14:04 +08001580 if (fll->fout && Fref > 0) {
Charles Keepaxee929a92013-02-20 17:28:40 +00001581 arizona_enable_fll(fll, &ref, &sync);
Charles Keepaxee929a92013-02-20 17:28:40 +00001582 }
1583
1584 return 0;
1585}
1586EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
1587
Mark Brown07ed8732012-06-18 21:08:44 +01001588int arizona_set_fll(struct arizona_fll *fll, int source,
1589 unsigned int Fref, unsigned int Fout)
1590{
Charles Keepax9e359c62013-02-20 17:28:35 +00001591 struct arizona_fll_cfg ref, sync;
Mark Brown07ed8732012-06-18 21:08:44 +01001592 int ret;
1593
Mark Brownff680a12013-03-04 16:00:19 +08001594 if (fll->sync_src == source &&
1595 fll->sync_freq == Fref && fll->fout == Fout)
1596 return 0;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00001597
Mark Brownff680a12013-03-04 16:00:19 +08001598 if (Fout) {
1599 if (fll->ref_src >= 0) {
1600 ret = arizona_calc_fll(fll, &ref, fll->ref_freq,
1601 Fout);
Charles Keepax9e359c62013-02-20 17:28:35 +00001602 if (ret != 0)
1603 return ret;
1604 }
1605
Mark Brownff680a12013-03-04 16:00:19 +08001606 ret = arizona_calc_fll(fll, &sync, Fref, Fout);
1607 if (ret != 0)
1608 return ret;
Charles Keepax9e359c62013-02-20 17:28:35 +00001609 }
Mark Brownff680a12013-03-04 16:00:19 +08001610
1611 fll->sync_src = source;
1612 fll->sync_freq = Fref;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00001613 fll->fout = Fout;
Charles Keepax9e359c62013-02-20 17:28:35 +00001614
Mark Brown07ed8732012-06-18 21:08:44 +01001615 if (Fout) {
Charles Keepax35722812013-02-20 17:28:38 +00001616 arizona_enable_fll(fll, &ref, &sync);
Mark Brown07ed8732012-06-18 21:08:44 +01001617 } else {
Charles Keepax76040542013-02-20 17:28:37 +00001618 arizona_disable_fll(fll);
Mark Brown07ed8732012-06-18 21:08:44 +01001619 }
1620
Mark Brown07ed8732012-06-18 21:08:44 +01001621 return 0;
1622}
1623EXPORT_SYMBOL_GPL(arizona_set_fll);
1624
1625int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
1626 int ok_irq, struct arizona_fll *fll)
1627{
1628 int ret;
Charles Keepax19b34bd2013-02-20 17:28:34 +00001629 unsigned int val;
Mark Brown07ed8732012-06-18 21:08:44 +01001630
Mark Brown07ed8732012-06-18 21:08:44 +01001631 init_completion(&fll->ok);
1632
1633 fll->id = id;
1634 fll->base = base;
1635 fll->arizona = arizona;
Charles Keepaxf3f11632013-02-20 17:28:41 +00001636 fll->sync_src = ARIZONA_FLL_SRC_NONE;
Mark Brown07ed8732012-06-18 21:08:44 +01001637
Charles Keepax19b34bd2013-02-20 17:28:34 +00001638 /* Configure default refclk to 32kHz if we have one */
1639 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
1640 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
1641 case ARIZONA_CLK_SRC_MCLK1:
1642 case ARIZONA_CLK_SRC_MCLK2:
1643 fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK;
1644 break;
1645 default:
Charles Keepaxf3f11632013-02-20 17:28:41 +00001646 fll->ref_src = ARIZONA_FLL_SRC_NONE;
Charles Keepax19b34bd2013-02-20 17:28:34 +00001647 }
1648 fll->ref_freq = 32768;
1649
Mark Brown07ed8732012-06-18 21:08:44 +01001650 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
1651 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
1652 "FLL%d clock OK", id);
1653
Mark Brown07ed8732012-06-18 21:08:44 +01001654 ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
1655 arizona_fll_clock_ok, fll);
1656 if (ret != 0) {
1657 dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
1658 id, ret);
1659 }
1660
Charles Keepaxe31c1942013-01-07 16:41:45 +00001661 regmap_update_bits(arizona->regmap, fll->base + 1,
1662 ARIZONA_FLL1_FREERUN, 0);
1663
Mark Brown07ed8732012-06-18 21:08:44 +01001664 return 0;
1665}
1666EXPORT_SYMBOL_GPL(arizona_init_fll);
1667
Mark Brownbc9ab6d2013-01-04 19:31:00 +00001668/**
1669 * arizona_set_output_mode - Set the mode of the specified output
1670 *
1671 * @codec: Device to configure
1672 * @output: Output number
1673 * @diff: True to set the output to differential mode
1674 *
1675 * Some systems use external analogue switches to connect more
1676 * analogue devices to the CODEC than are supported by the device. In
1677 * some systems this requires changing the switched output from single
1678 * ended to differential mode dynamically at runtime, an operation
1679 * supported using this function.
1680 *
1681 * Most systems have a single static configuration and should use
1682 * platform data instead.
1683 */
1684int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
1685{
1686 unsigned int reg, val;
1687
1688 if (output < 1 || output > 6)
1689 return -EINVAL;
1690
1691 reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
1692
1693 if (diff)
1694 val = ARIZONA_OUT1_MONO;
1695 else
1696 val = 0;
1697
1698 return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val);
1699}
1700EXPORT_SYMBOL_GPL(arizona_set_output_mode);
1701
Mark Brown07ed8732012-06-18 21:08:44 +01001702MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
1703MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1704MODULE_LICENSE("GPL");