blob: c9116ac0d4a7d447d38ad4030c16045d22d1dc0c [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
203 ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkr, 1);
204 if (ret != 0)
205 return ret;
206
Mark Brown899817e2013-03-13 12:32:10 +0000207 ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN_WARN,
208 "Thermal warning", arizona_thermal_warn,
209 arizona);
210 if (ret != 0)
211 dev_err(arizona->dev,
212 "Failed to get thermal warning IRQ: %d\n",
213 ret);
214
215 ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN,
216 "Thermal shutdown", arizona_thermal_shutdown,
217 arizona);
218 if (ret != 0)
219 dev_err(arizona->dev,
220 "Failed to get thermal shutdown IRQ: %d\n",
221 ret);
222
Mark Brown56447e12013-01-10 14:45:58 +0000223 return 0;
224}
225EXPORT_SYMBOL_GPL(arizona_init_spk);
226
Charles Keepaxb63144e2013-07-04 08:56:28 +0100227int arizona_init_gpio(struct snd_soc_codec *codec)
228{
229 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
230 struct arizona *arizona = priv->arizona;
231 int i;
232
233 switch (arizona->type) {
234 case WM5110:
235 snd_soc_dapm_disable_pin(&codec->dapm, "DRC2 Signal Activity");
236 }
237
238 snd_soc_dapm_disable_pin(&codec->dapm, "DRC1 Signal Activity");
239
240 for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
241 switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) {
242 case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT:
243 snd_soc_dapm_enable_pin(&codec->dapm,
244 "DRC1 Signal Activity");
245 break;
246 case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT:
247 snd_soc_dapm_enable_pin(&codec->dapm,
248 "DRC2 Signal Activity");
249 break;
250 default:
251 break;
252 }
253 }
254
255 return 0;
256}
257EXPORT_SYMBOL_GPL(arizona_init_gpio);
258
Mark Brown07ed8732012-06-18 21:08:44 +0100259const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
260 "None",
261 "Tone Generator 1",
262 "Tone Generator 2",
263 "Haptics",
264 "AEC",
265 "Mic Mute Mixer",
266 "Noise Generator",
267 "IN1L",
268 "IN1R",
269 "IN2L",
270 "IN2R",
271 "IN3L",
272 "IN3R",
Mark Brownc9c56fd2012-07-09 19:09:01 +0100273 "IN4L",
274 "IN4R",
Mark Brown07ed8732012-06-18 21:08:44 +0100275 "AIF1RX1",
276 "AIF1RX2",
277 "AIF1RX3",
278 "AIF1RX4",
279 "AIF1RX5",
280 "AIF1RX6",
281 "AIF1RX7",
282 "AIF1RX8",
283 "AIF2RX1",
284 "AIF2RX2",
285 "AIF3RX1",
286 "AIF3RX2",
287 "SLIMRX1",
288 "SLIMRX2",
289 "SLIMRX3",
290 "SLIMRX4",
291 "SLIMRX5",
292 "SLIMRX6",
293 "SLIMRX7",
294 "SLIMRX8",
295 "EQ1",
296 "EQ2",
297 "EQ3",
298 "EQ4",
299 "DRC1L",
300 "DRC1R",
301 "DRC2L",
302 "DRC2R",
303 "LHPF1",
304 "LHPF2",
305 "LHPF3",
306 "LHPF4",
307 "DSP1.1",
308 "DSP1.2",
309 "DSP1.3",
310 "DSP1.4",
311 "DSP1.5",
312 "DSP1.6",
Mark Brownc922cc42012-09-26 16:43:44 +0100313 "DSP2.1",
314 "DSP2.2",
315 "DSP2.3",
316 "DSP2.4",
317 "DSP2.5",
318 "DSP2.6",
319 "DSP3.1",
320 "DSP3.2",
321 "DSP3.3",
322 "DSP3.4",
323 "DSP3.5",
324 "DSP3.6",
325 "DSP4.1",
326 "DSP4.2",
327 "DSP4.3",
328 "DSP4.4",
329 "DSP4.5",
330 "DSP4.6",
Mark Brown07ed8732012-06-18 21:08:44 +0100331 "ASRC1L",
332 "ASRC1R",
333 "ASRC2L",
334 "ASRC2R",
Mark Brown91660bd2012-12-05 20:35:24 +0900335 "ISRC1INT1",
336 "ISRC1INT2",
337 "ISRC1INT3",
338 "ISRC1INT4",
339 "ISRC1DEC1",
340 "ISRC1DEC2",
341 "ISRC1DEC3",
342 "ISRC1DEC4",
343 "ISRC2INT1",
344 "ISRC2INT2",
345 "ISRC2INT3",
346 "ISRC2INT4",
347 "ISRC2DEC1",
348 "ISRC2DEC2",
349 "ISRC2DEC3",
350 "ISRC2DEC4",
351 "ISRC3INT1",
352 "ISRC3INT2",
353 "ISRC3INT3",
354 "ISRC3INT4",
355 "ISRC3DEC1",
356 "ISRC3DEC2",
357 "ISRC3DEC3",
358 "ISRC3DEC4",
Mark Brown07ed8732012-06-18 21:08:44 +0100359};
360EXPORT_SYMBOL_GPL(arizona_mixer_texts);
361
362int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
363 0x00, /* None */
364 0x04, /* Tone */
365 0x05,
366 0x06, /* Haptics */
367 0x08, /* AEC */
368 0x0c, /* Noise mixer */
369 0x0d, /* Comfort noise */
370 0x10, /* IN1L */
371 0x11,
372 0x12,
373 0x13,
374 0x14,
375 0x15,
Mark Brownc9c56fd2012-07-09 19:09:01 +0100376 0x16,
377 0x17,
Mark Brown07ed8732012-06-18 21:08:44 +0100378 0x20, /* AIF1RX1 */
379 0x21,
380 0x22,
381 0x23,
382 0x24,
383 0x25,
384 0x26,
385 0x27,
386 0x28, /* AIF2RX1 */
387 0x29,
388 0x30, /* AIF3RX1 */
389 0x31,
390 0x38, /* SLIMRX1 */
391 0x39,
392 0x3a,
393 0x3b,
394 0x3c,
395 0x3d,
396 0x3e,
397 0x3f,
398 0x50, /* EQ1 */
399 0x51,
400 0x52,
401 0x53,
402 0x58, /* DRC1L */
403 0x59,
404 0x5a,
405 0x5b,
406 0x60, /* LHPF1 */
407 0x61,
408 0x62,
409 0x63,
410 0x68, /* DSP1.1 */
411 0x69,
412 0x6a,
413 0x6b,
414 0x6c,
415 0x6d,
Mark Brownc922cc42012-09-26 16:43:44 +0100416 0x70, /* DSP2.1 */
417 0x71,
418 0x72,
419 0x73,
420 0x74,
421 0x75,
422 0x78, /* DSP3.1 */
423 0x79,
424 0x7a,
425 0x7b,
426 0x7c,
427 0x7d,
428 0x80, /* DSP4.1 */
429 0x81,
430 0x82,
431 0x83,
432 0x84,
433 0x85,
Mark Brown07ed8732012-06-18 21:08:44 +0100434 0x90, /* ASRC1L */
435 0x91,
436 0x92,
437 0x93,
Mark Brown91660bd2012-12-05 20:35:24 +0900438 0xa0, /* ISRC1INT1 */
439 0xa1,
440 0xa2,
441 0xa3,
442 0xa4, /* ISRC1DEC1 */
443 0xa5,
444 0xa6,
445 0xa7,
446 0xa8, /* ISRC2DEC1 */
447 0xa9,
448 0xaa,
449 0xab,
450 0xac, /* ISRC2INT1 */
451 0xad,
452 0xae,
453 0xaf,
454 0xb0, /* ISRC3DEC1 */
455 0xb1,
456 0xb2,
457 0xb3,
458 0xb4, /* ISRC3INT1 */
459 0xb5,
460 0xb6,
461 0xb7,
Mark Brown07ed8732012-06-18 21:08:44 +0100462};
463EXPORT_SYMBOL_GPL(arizona_mixer_values);
464
465const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
466EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
467
Mark Browndc914282013-02-18 19:09:23 +0000468const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = {
469 "SYNCCLK rate", "8kHz", "16kHz", "ASYNCCLK rate",
470};
471EXPORT_SYMBOL_GPL(arizona_rate_text);
472
473const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
474 0, 1, 2, 8,
475};
476EXPORT_SYMBOL_GPL(arizona_rate_val);
477
478
479const struct soc_enum arizona_isrc_fsl[] = {
480 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2,
481 ARIZONA_ISRC1_FSL_SHIFT, 0xf,
482 ARIZONA_RATE_ENUM_SIZE,
483 arizona_rate_text, arizona_rate_val),
484 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_2,
485 ARIZONA_ISRC2_FSL_SHIFT, 0xf,
486 ARIZONA_RATE_ENUM_SIZE,
487 arizona_rate_text, arizona_rate_val),
488 SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_2,
489 ARIZONA_ISRC3_FSL_SHIFT, 0xf,
490 ARIZONA_RATE_ENUM_SIZE,
491 arizona_rate_text, arizona_rate_val),
492};
493EXPORT_SYMBOL_GPL(arizona_isrc_fsl);
494
Mark Browne853a002012-12-09 12:25:52 +0900495static const char *arizona_vol_ramp_text[] = {
496 "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
497 "15ms/6dB", "30ms/6dB",
498};
499
500const struct soc_enum arizona_in_vd_ramp =
501 SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP,
502 ARIZONA_IN_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text);
503EXPORT_SYMBOL_GPL(arizona_in_vd_ramp);
504
505const struct soc_enum arizona_in_vi_ramp =
506 SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP,
507 ARIZONA_IN_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text);
508EXPORT_SYMBOL_GPL(arizona_in_vi_ramp);
509
510const struct soc_enum arizona_out_vd_ramp =
511 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP,
512 ARIZONA_OUT_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text);
513EXPORT_SYMBOL_GPL(arizona_out_vd_ramp);
514
515const struct soc_enum arizona_out_vi_ramp =
516 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP,
517 ARIZONA_OUT_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text);
518EXPORT_SYMBOL_GPL(arizona_out_vi_ramp);
519
Mark Brown07ed8732012-06-18 21:08:44 +0100520static const char *arizona_lhpf_mode_text[] = {
521 "Low-pass", "High-pass"
522};
523
524const struct soc_enum arizona_lhpf1_mode =
525 SOC_ENUM_SINGLE(ARIZONA_HPLPF1_1, ARIZONA_LHPF1_MODE_SHIFT, 2,
526 arizona_lhpf_mode_text);
527EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
528
529const struct soc_enum arizona_lhpf2_mode =
530 SOC_ENUM_SINGLE(ARIZONA_HPLPF2_1, ARIZONA_LHPF2_MODE_SHIFT, 2,
531 arizona_lhpf_mode_text);
532EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
533
534const struct soc_enum arizona_lhpf3_mode =
535 SOC_ENUM_SINGLE(ARIZONA_HPLPF3_1, ARIZONA_LHPF3_MODE_SHIFT, 2,
536 arizona_lhpf_mode_text);
537EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
538
539const struct soc_enum arizona_lhpf4_mode =
540 SOC_ENUM_SINGLE(ARIZONA_HPLPF4_1, ARIZONA_LHPF4_MODE_SHIFT, 2,
541 arizona_lhpf_mode_text);
542EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
543
Mark Brown845571c2012-12-18 13:47:57 +0000544static const char *arizona_ng_hold_text[] = {
545 "30ms", "120ms", "250ms", "500ms",
546};
547
548const struct soc_enum arizona_ng_hold =
549 SOC_ENUM_SINGLE(ARIZONA_NOISE_GATE_CONTROL, ARIZONA_NGATE_HOLD_SHIFT,
550 4, arizona_ng_hold_text);
551EXPORT_SYMBOL_GPL(arizona_ng_hold);
552
Mark Brownddbce972013-02-15 17:27:22 +0000553static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
554{
555 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
556 unsigned int val;
557 int i;
558
559 if (ena)
560 val = ARIZONA_IN_VU;
561 else
562 val = 0;
563
564 for (i = 0; i < priv->num_inputs; i++)
565 snd_soc_update_bits(codec,
566 ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 4),
567 ARIZONA_IN_VU, val);
568}
569
Mark Brown07ed8732012-06-18 21:08:44 +0100570int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
571 int event)
572{
Mark Brownddbce972013-02-15 17:27:22 +0000573 struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000574 unsigned int reg;
575
576 if (w->shift % 2)
577 reg = ARIZONA_ADC_DIGITAL_VOLUME_1L + ((w->shift / 2) * 8);
578 else
579 reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8);
580
581 switch (event) {
Mark Brownddbce972013-02-15 17:27:22 +0000582 case SND_SOC_DAPM_PRE_PMU:
583 priv->in_pending++;
584 break;
Mark Brown43cd8bf2013-02-06 16:57:29 +0000585 case SND_SOC_DAPM_POST_PMU:
586 snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, 0);
Mark Brownddbce972013-02-15 17:27:22 +0000587
588 /* If this is the last input pending then allow VU */
589 priv->in_pending--;
590 if (priv->in_pending == 0) {
591 msleep(1);
592 arizona_in_set_vu(w->codec, 1);
593 }
Mark Brown43cd8bf2013-02-06 16:57:29 +0000594 break;
595 case SND_SOC_DAPM_PRE_PMD:
Mark Brownddbce972013-02-15 17:27:22 +0000596 snd_soc_update_bits(w->codec, reg,
597 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU,
598 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000599 break;
Mark Brownddbce972013-02-15 17:27:22 +0000600 case SND_SOC_DAPM_POST_PMD:
601 /* Disable volume updates if no inputs are enabled */
602 reg = snd_soc_read(w->codec, ARIZONA_INPUT_ENABLES);
603 if (reg == 0)
604 arizona_in_set_vu(w->codec, 0);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000605 }
606
Mark Brown07ed8732012-06-18 21:08:44 +0100607 return 0;
608}
609EXPORT_SYMBOL_GPL(arizona_in_ev);
610
611int arizona_out_ev(struct snd_soc_dapm_widget *w,
612 struct snd_kcontrol *kcontrol,
613 int event)
614{
Mark Brown1a2c7d52013-03-24 22:50:23 +0000615 switch (event) {
616 case SND_SOC_DAPM_POST_PMU:
617 switch (w->shift) {
618 case ARIZONA_OUT1L_ENA_SHIFT:
619 case ARIZONA_OUT1R_ENA_SHIFT:
620 case ARIZONA_OUT2L_ENA_SHIFT:
621 case ARIZONA_OUT2R_ENA_SHIFT:
622 case ARIZONA_OUT3L_ENA_SHIFT:
623 case ARIZONA_OUT3R_ENA_SHIFT:
624 msleep(17);
625 break;
626
627 default:
628 break;
629 }
630 break;
631 }
632
Mark Brown07ed8732012-06-18 21:08:44 +0100633 return 0;
634}
635EXPORT_SYMBOL_GPL(arizona_out_ev);
636
Mark Brownf607e312013-02-22 18:36:53 +0000637int arizona_hp_ev(struct snd_soc_dapm_widget *w,
638 struct snd_kcontrol *kcontrol,
639 int event)
640{
641 struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
642 unsigned int mask = 1 << w->shift;
643 unsigned int val;
644
645 switch (event) {
646 case SND_SOC_DAPM_POST_PMU:
647 val = mask;
648 break;
649 case SND_SOC_DAPM_PRE_PMD:
650 val = 0;
651 break;
652 default:
653 return -EINVAL;
654 }
655
656 /* Store the desired state for the HP outputs */
657 priv->arizona->hp_ena &= ~mask;
658 priv->arizona->hp_ena |= val;
659
660 /* Force off if HPDET magic is active */
661 if (priv->arizona->hpdet_magic)
662 val = 0;
663
664 snd_soc_update_bits(w->codec, ARIZONA_OUTPUT_ENABLES_1, mask, val);
665
666 return arizona_out_ev(w, kcontrol, event);
667}
668EXPORT_SYMBOL_GPL(arizona_hp_ev);
669
Mark Browncbd840d2012-08-08 17:52:44 +0100670static unsigned int arizona_sysclk_48k_rates[] = {
671 6144000,
672 12288000,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000673 24576000,
Mark Browncbd840d2012-08-08 17:52:44 +0100674 49152000,
Mark Brownaeaeee12012-09-26 17:50:02 +0100675 73728000,
676 98304000,
677 147456000,
Mark Browncbd840d2012-08-08 17:52:44 +0100678};
679
680static unsigned int arizona_sysclk_44k1_rates[] = {
681 5644800,
682 11289600,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000683 22579200,
Mark Browncbd840d2012-08-08 17:52:44 +0100684 45158400,
Mark Brownaeaeee12012-09-26 17:50:02 +0100685 67737600,
686 90316800,
687 135475200,
Mark Browncbd840d2012-08-08 17:52:44 +0100688};
689
690static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
691 unsigned int freq)
692{
693 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
694 unsigned int reg;
695 unsigned int *rates;
696 int ref, div, refclk;
697
698 switch (clk) {
699 case ARIZONA_CLK_OPCLK:
700 reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
701 refclk = priv->sysclk;
702 break;
703 case ARIZONA_CLK_ASYNC_OPCLK:
704 reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
705 refclk = priv->asyncclk;
706 break;
707 default:
708 return -EINVAL;
709 }
710
711 if (refclk % 8000)
712 rates = arizona_sysclk_44k1_rates;
713 else
714 rates = arizona_sysclk_48k_rates;
715
716 for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) &&
717 rates[ref] <= refclk; ref++) {
718 div = 1;
719 while (rates[ref] / div >= freq && div < 32) {
720 if (rates[ref] / div == freq) {
721 dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
722 freq);
723 snd_soc_update_bits(codec, reg,
724 ARIZONA_OPCLK_DIV_MASK |
725 ARIZONA_OPCLK_SEL_MASK,
726 (div <<
727 ARIZONA_OPCLK_DIV_SHIFT) |
728 ref);
729 return 0;
730 }
731 div++;
732 }
733 }
734
735 dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
736 return -EINVAL;
737}
738
Mark Brown07ed8732012-06-18 21:08:44 +0100739int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
740 int source, unsigned int freq, int dir)
741{
742 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
743 struct arizona *arizona = priv->arizona;
744 char *name;
745 unsigned int reg;
746 unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
747 unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
748 unsigned int *clk;
749
750 switch (clk_id) {
751 case ARIZONA_CLK_SYSCLK:
752 name = "SYSCLK";
753 reg = ARIZONA_SYSTEM_CLOCK_1;
754 clk = &priv->sysclk;
755 mask |= ARIZONA_SYSCLK_FRAC;
756 break;
757 case ARIZONA_CLK_ASYNCCLK:
758 name = "ASYNCCLK";
759 reg = ARIZONA_ASYNC_CLOCK_1;
760 clk = &priv->asyncclk;
761 break;
Mark Browncbd840d2012-08-08 17:52:44 +0100762 case ARIZONA_CLK_OPCLK:
763 case ARIZONA_CLK_ASYNC_OPCLK:
764 return arizona_set_opclk(codec, clk_id, freq);
Mark Brown07ed8732012-06-18 21:08:44 +0100765 default:
766 return -EINVAL;
767 }
768
769 switch (freq) {
770 case 5644800:
771 case 6144000:
772 break;
773 case 11289600:
774 case 12288000:
Mark Brown3f341f72013-03-08 15:22:29 +0800775 val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100776 break;
777 case 22579200:
778 case 24576000:
Mark Brown3f341f72013-03-08 15:22:29 +0800779 val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100780 break;
781 case 45158400:
782 case 49152000:
Mark Brown3f341f72013-03-08 15:22:29 +0800783 val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100784 break;
Mark Brown38113362012-11-26 16:01:37 +0000785 case 67737600:
786 case 73728000:
Mark Brown3f341f72013-03-08 15:22:29 +0800787 val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000788 break;
789 case 90316800:
790 case 98304000:
Mark Brown3f341f72013-03-08 15:22:29 +0800791 val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000792 break;
793 case 135475200:
794 case 147456000:
Mark Brown3f341f72013-03-08 15:22:29 +0800795 val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000796 break;
Mark Brownf2c26d42013-01-21 16:09:36 +0900797 case 0:
798 dev_dbg(arizona->dev, "%s cleared\n", name);
799 *clk = freq;
800 return 0;
Mark Brown07ed8732012-06-18 21:08:44 +0100801 default:
802 return -EINVAL;
803 }
804
805 *clk = freq;
806
807 if (freq % 6144000)
808 val |= ARIZONA_SYSCLK_FRAC;
809
810 dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
811
812 return regmap_update_bits(arizona->regmap, reg, mask, val);
813}
814EXPORT_SYMBOL_GPL(arizona_set_sysclk);
815
816static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
817{
818 struct snd_soc_codec *codec = dai->codec;
819 int lrclk, bclk, mode, base;
820
821 base = dai->driver->base;
822
823 lrclk = 0;
824 bclk = 0;
825
826 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
827 case SND_SOC_DAIFMT_DSP_A:
828 mode = 0;
829 break;
Mark Brown07ed8732012-06-18 21:08:44 +0100830 case SND_SOC_DAIFMT_I2S:
831 mode = 2;
832 break;
Mark Brown07ed8732012-06-18 21:08:44 +0100833 default:
834 arizona_aif_err(dai, "Unsupported DAI format %d\n",
835 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
836 return -EINVAL;
837 }
838
839 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
840 case SND_SOC_DAIFMT_CBS_CFS:
841 break;
842 case SND_SOC_DAIFMT_CBS_CFM:
843 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
844 break;
845 case SND_SOC_DAIFMT_CBM_CFS:
846 bclk |= ARIZONA_AIF1_BCLK_MSTR;
847 break;
848 case SND_SOC_DAIFMT_CBM_CFM:
849 bclk |= ARIZONA_AIF1_BCLK_MSTR;
850 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
851 break;
852 default:
853 arizona_aif_err(dai, "Unsupported master mode %d\n",
854 fmt & SND_SOC_DAIFMT_MASTER_MASK);
855 return -EINVAL;
856 }
857
858 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
859 case SND_SOC_DAIFMT_NB_NF:
860 break;
861 case SND_SOC_DAIFMT_IB_IF:
862 bclk |= ARIZONA_AIF1_BCLK_INV;
863 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
864 break;
865 case SND_SOC_DAIFMT_IB_NF:
866 bclk |= ARIZONA_AIF1_BCLK_INV;
867 break;
868 case SND_SOC_DAIFMT_NB_IF:
869 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
870 break;
871 default:
872 return -EINVAL;
873 }
874
875 snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
876 ARIZONA_AIF1_BCLK_INV | ARIZONA_AIF1_BCLK_MSTR,
877 bclk);
878 snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_PIN_CTRL,
879 ARIZONA_AIF1TX_LRCLK_INV |
880 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
881 snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_PIN_CTRL,
882 ARIZONA_AIF1RX_LRCLK_INV |
883 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
884 snd_soc_update_bits(codec, base + ARIZONA_AIF_FORMAT,
885 ARIZONA_AIF1_FMT_MASK, mode);
886
887 return 0;
888}
889
Mark Brown949e6bc2012-07-04 18:58:04 +0100890static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100891 -1,
892 48000,
893 64000,
894 96000,
895 128000,
896 192000,
897 256000,
898 384000,
899 512000,
900 768000,
901 1024000,
902 1536000,
903 2048000,
904 3072000,
905 4096000,
906 6144000,
907 8192000,
908 12288000,
909 24576000,
910};
911
Mark Brown5b2eec32012-07-04 17:32:05 +0100912static const unsigned int arizona_48k_rates[] = {
913 12000,
914 24000,
915 48000,
916 96000,
917 192000,
918 384000,
919 768000,
920 4000,
921 8000,
922 16000,
923 32000,
924 64000,
925 128000,
926 256000,
927 512000,
928};
929
930static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = {
931 .count = ARRAY_SIZE(arizona_48k_rates),
932 .list = arizona_48k_rates,
933};
934
Mark Brown949e6bc2012-07-04 18:58:04 +0100935static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100936 -1,
937 44100,
938 58800,
939 88200,
940 117600,
941 177640,
942 235200,
943 352800,
944 470400,
945 705600,
946 940800,
947 1411200,
948 1881600,
Heather Lomond4758be32012-09-05 05:02:10 -0400949 2822400,
Mark Brown07ed8732012-06-18 21:08:44 +0100950 3763200,
951 5644800,
952 7526400,
953 11289600,
954 22579200,
955};
956
Mark Brown5b2eec32012-07-04 17:32:05 +0100957static const unsigned int arizona_44k1_rates[] = {
958 11025,
959 22050,
960 44100,
961 88200,
962 176400,
963 352800,
964 705600,
965};
966
967static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = {
968 .count = ARRAY_SIZE(arizona_44k1_rates),
969 .list = arizona_44k1_rates,
970};
971
Mark Brown07ed8732012-06-18 21:08:44 +0100972static int arizona_sr_vals[] = {
973 0,
974 12000,
975 24000,
976 48000,
977 96000,
978 192000,
979 384000,
980 768000,
981 0,
982 11025,
983 22050,
984 44100,
985 88200,
986 176400,
987 352800,
988 705600,
989 4000,
990 8000,
991 16000,
992 32000,
993 64000,
994 128000,
995 256000,
996 512000,
997};
998
Mark Brown5b2eec32012-07-04 17:32:05 +0100999static int arizona_startup(struct snd_pcm_substream *substream,
1000 struct snd_soc_dai *dai)
1001{
1002 struct snd_soc_codec *codec = dai->codec;
1003 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1004 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
1005 const struct snd_pcm_hw_constraint_list *constraint;
1006 unsigned int base_rate;
1007
1008 switch (dai_priv->clk) {
1009 case ARIZONA_CLK_SYSCLK:
1010 base_rate = priv->sysclk;
1011 break;
1012 case ARIZONA_CLK_ASYNCCLK:
1013 base_rate = priv->asyncclk;
1014 break;
1015 default:
1016 return 0;
1017 }
1018
Mark Brownf2c26d42013-01-21 16:09:36 +09001019 if (base_rate == 0)
1020 return 0;
1021
Mark Brown5b2eec32012-07-04 17:32:05 +01001022 if (base_rate % 8000)
1023 constraint = &arizona_44k1_constraint;
1024 else
1025 constraint = &arizona_48k_constraint;
1026
1027 return snd_pcm_hw_constraint_list(substream->runtime, 0,
1028 SNDRV_PCM_HW_PARAM_RATE,
1029 constraint);
1030}
1031
Mark Brownb272efc2012-10-10 15:10:08 +09001032static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
1033 struct snd_pcm_hw_params *params,
1034 struct snd_soc_dai *dai)
Mark Brown07ed8732012-06-18 21:08:44 +01001035{
1036 struct snd_soc_codec *codec = dai->codec;
Mark Brownc013b272012-07-04 20:05:57 +01001037 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1038 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown07ed8732012-06-18 21:08:44 +01001039 int base = dai->driver->base;
Mark Brownb272efc2012-10-10 15:10:08 +09001040 int i, sr_val;
1041
1042 /*
1043 * We will need to be more flexible than this in future,
1044 * currently we use a single sample rate for SYSCLK.
1045 */
1046 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
1047 if (arizona_sr_vals[i] == params_rate(params))
1048 break;
1049 if (i == ARRAY_SIZE(arizona_sr_vals)) {
1050 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1051 params_rate(params));
1052 return -EINVAL;
1053 }
1054 sr_val = i;
1055
1056 switch (dai_priv->clk) {
1057 case ARIZONA_CLK_SYSCLK:
1058 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
1059 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
1060 if (base)
1061 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1062 ARIZONA_AIF1_RATE_MASK, 0);
1063 break;
1064 case ARIZONA_CLK_ASYNCCLK:
1065 snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
1066 ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val);
1067 if (base)
1068 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1069 ARIZONA_AIF1_RATE_MASK,
1070 8 << ARIZONA_AIF1_RATE_SHIFT);
1071 break;
1072 default:
1073 arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
1074 return -EINVAL;
1075 }
1076
1077 return 0;
1078}
1079
Mark Brown07ed8732012-06-18 21:08:44 +01001080static int arizona_hw_params(struct snd_pcm_substream *substream,
1081 struct snd_pcm_hw_params *params,
1082 struct snd_soc_dai *dai)
1083{
1084 struct snd_soc_codec *codec = dai->codec;
1085 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brownc94aa302013-01-17 16:35:14 +09001086 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +01001087 int base = dai->driver->base;
1088 const int *rates;
Mark Brown76bf9692013-03-05 14:17:47 +08001089 int i, ret, val;
Mark Brownc94aa302013-01-17 16:35:14 +09001090 int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
1091 int bclk, lrclk, wl, frame, bclk_target;
Mark Brown07ed8732012-06-18 21:08:44 +01001092
1093 if (params_rate(params) % 8000)
Mark Brown949e6bc2012-07-04 18:58:04 +01001094 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001095 else
Mark Brown949e6bc2012-07-04 18:58:04 +01001096 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +01001097
Mark Brownc94aa302013-01-17 16:35:14 +09001098 bclk_target = snd_soc_params_to_bclk(params);
1099 if (chan_limit && chan_limit < params_channels(params)) {
1100 arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
1101 bclk_target /= params_channels(params);
1102 bclk_target *= chan_limit;
1103 }
1104
Mark Brown76bf9692013-03-05 14:17:47 +08001105 /* Force stereo for I2S mode */
1106 val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
1107 if (params_channels(params) == 1 && (val & ARIZONA_AIF1_FMT_MASK)) {
1108 arizona_aif_dbg(dai, "Forcing stereo mode\n");
1109 bclk_target *= 2;
1110 }
1111
Mark Brown949e6bc2012-07-04 18:58:04 +01001112 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brownc94aa302013-01-17 16:35:14 +09001113 if (rates[i] >= bclk_target &&
Mark Brown50017652012-07-04 19:07:09 +01001114 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +01001115 bclk = i;
1116 break;
1117 }
1118 }
Mark Brown949e6bc2012-07-04 18:58:04 +01001119 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001120 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1121 params_rate(params));
1122 return -EINVAL;
1123 }
1124
Mark Brownb59e0f82013-01-17 14:15:59 +09001125 lrclk = rates[bclk] / params_rate(params);
Mark Brown07ed8732012-06-18 21:08:44 +01001126
1127 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
1128 rates[bclk], rates[bclk] / lrclk);
1129
1130 wl = snd_pcm_format_width(params_format(params));
1131 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl;
1132
Mark Brownb272efc2012-10-10 15:10:08 +09001133 ret = arizona_hw_params_rate(substream, params, dai);
1134 if (ret != 0)
1135 return ret;
Mark Brownc013b272012-07-04 20:05:57 +01001136
Mark Brown07ed8732012-06-18 21:08:44 +01001137 snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
1138 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
1139 snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_BCLK_RATE,
1140 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
1141 snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_BCLK_RATE,
1142 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
1143 snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_1,
1144 ARIZONA_AIF1TX_WL_MASK |
1145 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
1146 snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_2,
1147 ARIZONA_AIF1RX_WL_MASK |
1148 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
1149
1150 return 0;
1151}
1152
Mark Brown410837a2012-07-05 17:26:59 +01001153static const char *arizona_dai_clk_str(int clk_id)
1154{
1155 switch (clk_id) {
1156 case ARIZONA_CLK_SYSCLK:
1157 return "SYSCLK";
1158 case ARIZONA_CLK_ASYNCCLK:
1159 return "ASYNCCLK";
1160 default:
1161 return "Unknown clock";
1162 }
1163}
1164
Mark Brown5b2eec32012-07-04 17:32:05 +01001165static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
1166 int clk_id, unsigned int freq, int dir)
1167{
1168 struct snd_soc_codec *codec = dai->codec;
1169 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1170 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown410837a2012-07-05 17:26:59 +01001171 struct snd_soc_dapm_route routes[2];
Mark Brown5b2eec32012-07-04 17:32:05 +01001172
1173 switch (clk_id) {
1174 case ARIZONA_CLK_SYSCLK:
1175 case ARIZONA_CLK_ASYNCCLK:
1176 break;
1177 default:
1178 return -EINVAL;
1179 }
1180
Mark Brown410837a2012-07-05 17:26:59 +01001181 if (clk_id == dai_priv->clk)
1182 return 0;
1183
1184 if (dai->active) {
Mark Brown5b2eec32012-07-04 17:32:05 +01001185 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
1186 dai->id);
1187 return -EBUSY;
1188 }
1189
Mark Brownc8d35a62012-12-07 12:49:40 +09001190 dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1,
1191 arizona_dai_clk_str(clk_id));
1192
Mark Brown410837a2012-07-05 17:26:59 +01001193 memset(&routes, 0, sizeof(routes));
1194 routes[0].sink = dai->driver->capture.stream_name;
1195 routes[1].sink = dai->driver->playback.stream_name;
Mark Brown5b2eec32012-07-04 17:32:05 +01001196
Mark Brown410837a2012-07-05 17:26:59 +01001197 routes[0].source = arizona_dai_clk_str(dai_priv->clk);
1198 routes[1].source = arizona_dai_clk_str(dai_priv->clk);
1199 snd_soc_dapm_del_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
1200
1201 routes[0].source = arizona_dai_clk_str(clk_id);
1202 routes[1].source = arizona_dai_clk_str(clk_id);
1203 snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
1204
Mark Brown0c778e82012-12-06 18:22:25 +09001205 dai_priv->clk = clk_id;
1206
Mark Brown410837a2012-07-05 17:26:59 +01001207 return snd_soc_dapm_sync(&codec->dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +01001208}
1209
Mark Brown01df2592012-12-12 16:22:08 +09001210static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
1211{
1212 struct snd_soc_codec *codec = dai->codec;
1213 int base = dai->driver->base;
1214 unsigned int reg;
1215
1216 if (tristate)
1217 reg = ARIZONA_AIF1_TRI;
1218 else
1219 reg = 0;
1220
1221 return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1222 ARIZONA_AIF1_TRI, reg);
1223}
1224
Mark Brown07ed8732012-06-18 21:08:44 +01001225const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +01001226 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +01001227 .set_fmt = arizona_set_fmt,
1228 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +01001229 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown01df2592012-12-12 16:22:08 +09001230 .set_tristate = arizona_set_tristate,
Mark Brown07ed8732012-06-18 21:08:44 +01001231};
Mark Browna8379872012-07-09 12:16:41 +01001232EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +01001233
Mark Brownbd1dd882013-05-17 13:29:03 +01001234const struct snd_soc_dai_ops arizona_simple_dai_ops = {
1235 .startup = arizona_startup,
1236 .hw_params = arizona_hw_params_rate,
1237 .set_sysclk = arizona_dai_set_sysclk,
1238};
1239EXPORT_SYMBOL_GPL(arizona_simple_dai_ops);
1240
Mark Brown5b2eec32012-07-04 17:32:05 +01001241int arizona_init_dai(struct arizona_priv *priv, int id)
1242{
1243 struct arizona_dai_priv *dai_priv = &priv->dai[id];
1244
1245 dai_priv->clk = ARIZONA_CLK_SYSCLK;
1246
1247 return 0;
1248}
1249EXPORT_SYMBOL_GPL(arizona_init_dai);
1250
Mark Brown07ed8732012-06-18 21:08:44 +01001251static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
1252{
1253 struct arizona_fll *fll = data;
1254
1255 arizona_fll_dbg(fll, "clock OK\n");
1256
1257 complete(&fll->ok);
1258
1259 return IRQ_HANDLED;
1260}
1261
1262static struct {
1263 unsigned int min;
1264 unsigned int max;
1265 u16 fratio;
1266 int ratio;
1267} fll_fratios[] = {
1268 { 0, 64000, 4, 16 },
1269 { 64000, 128000, 3, 8 },
1270 { 128000, 256000, 2, 4 },
1271 { 256000, 1000000, 1, 2 },
1272 { 1000000, 13500000, 0, 1 },
1273};
1274
Mark Brown8f113d72013-03-05 12:08:57 +08001275static struct {
1276 unsigned int min;
1277 unsigned int max;
1278 u16 gain;
1279} fll_gains[] = {
1280 { 0, 256000, 0 },
1281 { 256000, 1000000, 2 },
1282 { 1000000, 13500000, 4 },
1283};
1284
Mark Brown07ed8732012-06-18 21:08:44 +01001285struct arizona_fll_cfg {
1286 int n;
1287 int theta;
1288 int lambda;
1289 int refdiv;
1290 int outdiv;
1291 int fratio;
Mark Brown8f113d72013-03-05 12:08:57 +08001292 int gain;
Mark Brown07ed8732012-06-18 21:08:44 +01001293};
1294
1295static int arizona_calc_fll(struct arizona_fll *fll,
1296 struct arizona_fll_cfg *cfg,
1297 unsigned int Fref,
1298 unsigned int Fout)
1299{
1300 unsigned int target, div, gcd_fll;
1301 int i, ratio;
1302
1303 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout);
1304
1305 /* Fref must be <=13.5MHz */
1306 div = 1;
1307 cfg->refdiv = 0;
1308 while ((Fref / div) > 13500000) {
1309 div *= 2;
1310 cfg->refdiv++;
1311
1312 if (div > 8) {
1313 arizona_fll_err(fll,
1314 "Can't scale %dMHz in to <=13.5MHz\n",
1315 Fref);
1316 return -EINVAL;
1317 }
1318 }
1319
1320 /* Apply the division for our remaining calculations */
1321 Fref /= div;
1322
Mark Brown2b4d39f2012-07-10 17:03:46 +01001323 /* Fvco should be over the targt; don't check the upper bound */
Mark Brown07ed8732012-06-18 21:08:44 +01001324 div = 1;
Mark Brown2b4d39f2012-07-10 17:03:46 +01001325 while (Fout * div < 90000000 * fll->vco_mult) {
Mark Brown07ed8732012-06-18 21:08:44 +01001326 div++;
1327 if (div > 7) {
1328 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
1329 Fout);
1330 return -EINVAL;
1331 }
1332 }
Mark Brown2b4d39f2012-07-10 17:03:46 +01001333 target = Fout * div / fll->vco_mult;
Mark Brown07ed8732012-06-18 21:08:44 +01001334 cfg->outdiv = div;
1335
1336 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
1337
1338 /* Find an appropraite FLL_FRATIO and factor it out of the target */
1339 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
1340 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
1341 cfg->fratio = fll_fratios[i].fratio;
1342 ratio = fll_fratios[i].ratio;
1343 break;
1344 }
1345 }
1346 if (i == ARRAY_SIZE(fll_fratios)) {
1347 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
1348 Fref);
1349 return -EINVAL;
1350 }
1351
Mark Brown8f113d72013-03-05 12:08:57 +08001352 for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
1353 if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
1354 cfg->gain = fll_gains[i].gain;
1355 break;
1356 }
1357 }
1358 if (i == ARRAY_SIZE(fll_gains)) {
1359 arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
1360 Fref);
1361 return -EINVAL;
1362 }
1363
Mark Brown07ed8732012-06-18 21:08:44 +01001364 cfg->n = target / (ratio * Fref);
1365
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001366 if (target % (ratio * Fref)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001367 gcd_fll = gcd(target, ratio * Fref);
1368 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
1369
1370 cfg->theta = (target - (cfg->n * ratio * Fref))
1371 / gcd_fll;
1372 cfg->lambda = (ratio * Fref) / gcd_fll;
1373 } else {
1374 cfg->theta = 0;
1375 cfg->lambda = 0;
1376 }
1377
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001378 /* Round down to 16bit range with cost of accuracy lost.
1379 * Denominator must be bigger than numerator so we only
1380 * take care of it.
1381 */
1382 while (cfg->lambda >= (1 << 16)) {
1383 cfg->theta >>= 1;
1384 cfg->lambda >>= 1;
1385 }
1386
Mark Brown07ed8732012-06-18 21:08:44 +01001387 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
1388 cfg->n, cfg->theta, cfg->lambda);
1389 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
1390 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08001391 arizona_fll_dbg(fll, "GAIN=%d\n", cfg->gain);
Mark Brown07ed8732012-06-18 21:08:44 +01001392
1393 return 0;
1394
1395}
1396
1397static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
Mark Brown8f113d72013-03-05 12:08:57 +08001398 struct arizona_fll_cfg *cfg, int source,
1399 bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01001400{
1401 regmap_update_bits(arizona->regmap, base + 3,
1402 ARIZONA_FLL1_THETA_MASK, cfg->theta);
1403 regmap_update_bits(arizona->regmap, base + 4,
1404 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
1405 regmap_update_bits(arizona->regmap, base + 5,
1406 ARIZONA_FLL1_FRATIO_MASK,
1407 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
1408 regmap_update_bits(arizona->regmap, base + 6,
1409 ARIZONA_FLL1_CLK_REF_DIV_MASK |
1410 ARIZONA_FLL1_CLK_REF_SRC_MASK,
1411 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
1412 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
1413
Mark Brown8f113d72013-03-05 12:08:57 +08001414 if (sync)
1415 regmap_update_bits(arizona->regmap, base + 0x7,
1416 ARIZONA_FLL1_GAIN_MASK,
1417 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
1418 else
1419 regmap_update_bits(arizona->regmap, base + 0x9,
1420 ARIZONA_FLL1_GAIN_MASK,
1421 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
1422
Mark Brown07ed8732012-06-18 21:08:44 +01001423 regmap_update_bits(arizona->regmap, base + 2,
1424 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
1425 ARIZONA_FLL1_CTRL_UPD | cfg->n);
1426}
1427
Charles Keepaxd122d6c2013-02-20 17:28:36 +00001428static bool arizona_is_enabled_fll(struct arizona_fll *fll)
1429{
1430 struct arizona *arizona = fll->arizona;
1431 unsigned int reg;
1432 int ret;
1433
1434 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
1435 if (ret != 0) {
1436 arizona_fll_err(fll, "Failed to read current state: %d\n",
1437 ret);
1438 return ret;
1439 }
1440
1441 return reg & ARIZONA_FLL1_ENA;
1442}
1443
Charles Keepax35722812013-02-20 17:28:38 +00001444static void arizona_enable_fll(struct arizona_fll *fll,
1445 struct arizona_fll_cfg *ref,
1446 struct arizona_fll_cfg *sync)
1447{
1448 struct arizona *arizona = fll->arizona;
1449 int ret;
1450
Mark Brownff680a12013-03-04 16:00:19 +08001451 /*
1452 * If we have both REFCLK and SYNCCLK then enable both,
1453 * otherwise apply the SYNCCLK settings to REFCLK.
1454 */
1455 if (fll->ref_src >= 0 && fll->ref_src != fll->sync_src) {
1456 regmap_update_bits(arizona->regmap, fll->base + 5,
1457 ARIZONA_FLL1_OUTDIV_MASK,
1458 ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
Charles Keepax35722812013-02-20 17:28:38 +00001459
Mark Brown8f113d72013-03-05 12:08:57 +08001460 arizona_apply_fll(arizona, fll->base, ref, fll->ref_src,
1461 false);
Mark Brownff680a12013-03-04 16:00:19 +08001462 if (fll->sync_src >= 0)
1463 arizona_apply_fll(arizona, fll->base + 0x10, sync,
Mark Brown8f113d72013-03-05 12:08:57 +08001464 fll->sync_src, true);
Mark Brownff680a12013-03-04 16:00:19 +08001465 } else if (fll->sync_src >= 0) {
1466 regmap_update_bits(arizona->regmap, fll->base + 5,
1467 ARIZONA_FLL1_OUTDIV_MASK,
1468 sync->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
1469
1470 arizona_apply_fll(arizona, fll->base, sync,
Mark Brown8f113d72013-03-05 12:08:57 +08001471 fll->sync_src, false);
Mark Browneca2e8e2013-03-06 00:09:59 +08001472
1473 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1474 ARIZONA_FLL1_SYNC_ENA, 0);
Mark Brownff680a12013-03-04 16:00:19 +08001475 } else {
1476 arizona_fll_err(fll, "No clocks provided\n");
1477 return;
1478 }
Charles Keepax35722812013-02-20 17:28:38 +00001479
Mark Brown576411be2013-03-05 12:07:16 +08001480 /*
1481 * Increase the bandwidth if we're not using a low frequency
1482 * sync source.
1483 */
1484 if (fll->sync_src >= 0 && fll->sync_freq > 100000)
1485 regmap_update_bits(arizona->regmap, fll->base + 0x17,
1486 ARIZONA_FLL1_SYNC_BW, 0);
1487 else
1488 regmap_update_bits(arizona->regmap, fll->base + 0x17,
1489 ARIZONA_FLL1_SYNC_BW, ARIZONA_FLL1_SYNC_BW);
1490
Charles Keepax35722812013-02-20 17:28:38 +00001491 if (!arizona_is_enabled_fll(fll))
1492 pm_runtime_get(arizona->dev);
1493
1494 /* Clear any pending completions */
1495 try_wait_for_completion(&fll->ok);
1496
1497 regmap_update_bits(arizona->regmap, fll->base + 1,
1498 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
Mark Brownff680a12013-03-04 16:00:19 +08001499 if (fll->ref_src >= 0 && fll->sync_src >= 0 &&
1500 fll->ref_src != fll->sync_src)
Charles Keepax35722812013-02-20 17:28:38 +00001501 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1502 ARIZONA_FLL1_SYNC_ENA,
1503 ARIZONA_FLL1_SYNC_ENA);
1504
1505 ret = wait_for_completion_timeout(&fll->ok,
1506 msecs_to_jiffies(250));
1507 if (ret == 0)
1508 arizona_fll_warn(fll, "Timed out waiting for lock\n");
1509}
1510
Charles Keepax76040542013-02-20 17:28:37 +00001511static void arizona_disable_fll(struct arizona_fll *fll)
1512{
1513 struct arizona *arizona = fll->arizona;
1514 bool change;
1515
1516 regmap_update_bits_check(arizona->regmap, fll->base + 1,
1517 ARIZONA_FLL1_ENA, 0, &change);
1518 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1519 ARIZONA_FLL1_SYNC_ENA, 0);
1520
1521 if (change)
1522 pm_runtime_put_autosuspend(arizona->dev);
1523}
1524
Charles Keepaxee929a92013-02-20 17:28:40 +00001525int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
1526 unsigned int Fref, unsigned int Fout)
1527{
1528 struct arizona_fll_cfg ref, sync;
1529 int ret;
1530
Charles Keepax1c5617f2013-02-22 17:10:37 +00001531 if (fll->ref_src == source && fll->ref_freq == Fref)
Charles Keepaxee929a92013-02-20 17:28:40 +00001532 return 0;
1533
Mark Brown86cd6842013-03-07 16:14:04 +08001534 if (fll->fout && Fref > 0) {
Charles Keepax1c5617f2013-02-22 17:10:37 +00001535 ret = arizona_calc_fll(fll, &ref, Fref, fll->fout);
Charles Keepaxee929a92013-02-20 17:28:40 +00001536 if (ret != 0)
1537 return ret;
1538
1539 if (fll->sync_src >= 0) {
Charles Keepax1c5617f2013-02-22 17:10:37 +00001540 ret = arizona_calc_fll(fll, &sync, fll->sync_freq,
1541 fll->fout);
Charles Keepaxee929a92013-02-20 17:28:40 +00001542 if (ret != 0)
1543 return ret;
1544 }
1545 }
1546
1547 fll->ref_src = source;
1548 fll->ref_freq = Fref;
Charles Keepaxee929a92013-02-20 17:28:40 +00001549
Mark Brown86cd6842013-03-07 16:14:04 +08001550 if (fll->fout && Fref > 0) {
Charles Keepaxee929a92013-02-20 17:28:40 +00001551 arizona_enable_fll(fll, &ref, &sync);
Charles Keepaxee929a92013-02-20 17:28:40 +00001552 }
1553
1554 return 0;
1555}
1556EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
1557
Mark Brown07ed8732012-06-18 21:08:44 +01001558int arizona_set_fll(struct arizona_fll *fll, int source,
1559 unsigned int Fref, unsigned int Fout)
1560{
Charles Keepax9e359c62013-02-20 17:28:35 +00001561 struct arizona_fll_cfg ref, sync;
Mark Brown07ed8732012-06-18 21:08:44 +01001562 int ret;
1563
Mark Brownff680a12013-03-04 16:00:19 +08001564 if (fll->sync_src == source &&
1565 fll->sync_freq == Fref && fll->fout == Fout)
1566 return 0;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00001567
Mark Brownff680a12013-03-04 16:00:19 +08001568 if (Fout) {
1569 if (fll->ref_src >= 0) {
1570 ret = arizona_calc_fll(fll, &ref, fll->ref_freq,
1571 Fout);
Charles Keepax9e359c62013-02-20 17:28:35 +00001572 if (ret != 0)
1573 return ret;
1574 }
1575
Mark Brownff680a12013-03-04 16:00:19 +08001576 ret = arizona_calc_fll(fll, &sync, Fref, Fout);
1577 if (ret != 0)
1578 return ret;
Charles Keepax9e359c62013-02-20 17:28:35 +00001579 }
Mark Brownff680a12013-03-04 16:00:19 +08001580
1581 fll->sync_src = source;
1582 fll->sync_freq = Fref;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00001583 fll->fout = Fout;
Charles Keepax9e359c62013-02-20 17:28:35 +00001584
Mark Brown07ed8732012-06-18 21:08:44 +01001585 if (Fout) {
Charles Keepax35722812013-02-20 17:28:38 +00001586 arizona_enable_fll(fll, &ref, &sync);
Mark Brown07ed8732012-06-18 21:08:44 +01001587 } else {
Charles Keepax76040542013-02-20 17:28:37 +00001588 arizona_disable_fll(fll);
Mark Brown07ed8732012-06-18 21:08:44 +01001589 }
1590
Mark Brown07ed8732012-06-18 21:08:44 +01001591 return 0;
1592}
1593EXPORT_SYMBOL_GPL(arizona_set_fll);
1594
1595int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
1596 int ok_irq, struct arizona_fll *fll)
1597{
1598 int ret;
Charles Keepax19b34bd2013-02-20 17:28:34 +00001599 unsigned int val;
Mark Brown07ed8732012-06-18 21:08:44 +01001600
Mark Brown07ed8732012-06-18 21:08:44 +01001601 init_completion(&fll->ok);
1602
1603 fll->id = id;
1604 fll->base = base;
1605 fll->arizona = arizona;
Charles Keepaxf3f11632013-02-20 17:28:41 +00001606 fll->sync_src = ARIZONA_FLL_SRC_NONE;
Mark Brown07ed8732012-06-18 21:08:44 +01001607
Charles Keepax19b34bd2013-02-20 17:28:34 +00001608 /* Configure default refclk to 32kHz if we have one */
1609 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
1610 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
1611 case ARIZONA_CLK_SRC_MCLK1:
1612 case ARIZONA_CLK_SRC_MCLK2:
1613 fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK;
1614 break;
1615 default:
Charles Keepaxf3f11632013-02-20 17:28:41 +00001616 fll->ref_src = ARIZONA_FLL_SRC_NONE;
Charles Keepax19b34bd2013-02-20 17:28:34 +00001617 }
1618 fll->ref_freq = 32768;
1619
Mark Brown07ed8732012-06-18 21:08:44 +01001620 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
1621 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
1622 "FLL%d clock OK", id);
1623
Mark Brown07ed8732012-06-18 21:08:44 +01001624 ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
1625 arizona_fll_clock_ok, fll);
1626 if (ret != 0) {
1627 dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
1628 id, ret);
1629 }
1630
Charles Keepaxe31c1942013-01-07 16:41:45 +00001631 regmap_update_bits(arizona->regmap, fll->base + 1,
1632 ARIZONA_FLL1_FREERUN, 0);
1633
Mark Brown07ed8732012-06-18 21:08:44 +01001634 return 0;
1635}
1636EXPORT_SYMBOL_GPL(arizona_init_fll);
1637
Mark Brownbc9ab6d2013-01-04 19:31:00 +00001638/**
1639 * arizona_set_output_mode - Set the mode of the specified output
1640 *
1641 * @codec: Device to configure
1642 * @output: Output number
1643 * @diff: True to set the output to differential mode
1644 *
1645 * Some systems use external analogue switches to connect more
1646 * analogue devices to the CODEC than are supported by the device. In
1647 * some systems this requires changing the switched output from single
1648 * ended to differential mode dynamically at runtime, an operation
1649 * supported using this function.
1650 *
1651 * Most systems have a single static configuration and should use
1652 * platform data instead.
1653 */
1654int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
1655{
1656 unsigned int reg, val;
1657
1658 if (output < 1 || output > 6)
1659 return -EINVAL;
1660
1661 reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
1662
1663 if (diff)
1664 val = ARIZONA_OUT1_MONO;
1665 else
1666 val = 0;
1667
1668 return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val);
1669}
1670EXPORT_SYMBOL_GPL(arizona_set_output_mode);
1671
Mark Brown07ed8732012-06-18 21:08:44 +01001672MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
1673MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1674MODULE_LICENSE("GPL");