blob: 6c773804ffe0cc3eb0bcc37d176686632e1545d6 [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>
Mark Brown56447e12013-01-10 14:45:58 +000017#include <linux/delay.h>
Mark Brown07ed8732012-06-18 21:08:44 +010018#include <sound/pcm.h>
19#include <sound/pcm_params.h>
20#include <sound/tlv.h>
21
22#include <linux/mfd/arizona/core.h>
23#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
Mark Brown07ed8732012-06-18 21:08:44 +0100227const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
228 "None",
229 "Tone Generator 1",
230 "Tone Generator 2",
231 "Haptics",
232 "AEC",
233 "Mic Mute Mixer",
234 "Noise Generator",
235 "IN1L",
236 "IN1R",
237 "IN2L",
238 "IN2R",
239 "IN3L",
240 "IN3R",
Mark Brownc9c56fd2012-07-09 19:09:01 +0100241 "IN4L",
242 "IN4R",
Mark Brown07ed8732012-06-18 21:08:44 +0100243 "AIF1RX1",
244 "AIF1RX2",
245 "AIF1RX3",
246 "AIF1RX4",
247 "AIF1RX5",
248 "AIF1RX6",
249 "AIF1RX7",
250 "AIF1RX8",
251 "AIF2RX1",
252 "AIF2RX2",
253 "AIF3RX1",
254 "AIF3RX2",
255 "SLIMRX1",
256 "SLIMRX2",
257 "SLIMRX3",
258 "SLIMRX4",
259 "SLIMRX5",
260 "SLIMRX6",
261 "SLIMRX7",
262 "SLIMRX8",
263 "EQ1",
264 "EQ2",
265 "EQ3",
266 "EQ4",
267 "DRC1L",
268 "DRC1R",
269 "DRC2L",
270 "DRC2R",
271 "LHPF1",
272 "LHPF2",
273 "LHPF3",
274 "LHPF4",
275 "DSP1.1",
276 "DSP1.2",
277 "DSP1.3",
278 "DSP1.4",
279 "DSP1.5",
280 "DSP1.6",
Mark Brownc922cc42012-09-26 16:43:44 +0100281 "DSP2.1",
282 "DSP2.2",
283 "DSP2.3",
284 "DSP2.4",
285 "DSP2.5",
286 "DSP2.6",
287 "DSP3.1",
288 "DSP3.2",
289 "DSP3.3",
290 "DSP3.4",
291 "DSP3.5",
292 "DSP3.6",
293 "DSP4.1",
294 "DSP4.2",
295 "DSP4.3",
296 "DSP4.4",
297 "DSP4.5",
298 "DSP4.6",
Mark Brown07ed8732012-06-18 21:08:44 +0100299 "ASRC1L",
300 "ASRC1R",
301 "ASRC2L",
302 "ASRC2R",
Mark Brown91660bd2012-12-05 20:35:24 +0900303 "ISRC1INT1",
304 "ISRC1INT2",
305 "ISRC1INT3",
306 "ISRC1INT4",
307 "ISRC1DEC1",
308 "ISRC1DEC2",
309 "ISRC1DEC3",
310 "ISRC1DEC4",
311 "ISRC2INT1",
312 "ISRC2INT2",
313 "ISRC2INT3",
314 "ISRC2INT4",
315 "ISRC2DEC1",
316 "ISRC2DEC2",
317 "ISRC2DEC3",
318 "ISRC2DEC4",
319 "ISRC3INT1",
320 "ISRC3INT2",
321 "ISRC3INT3",
322 "ISRC3INT4",
323 "ISRC3DEC1",
324 "ISRC3DEC2",
325 "ISRC3DEC3",
326 "ISRC3DEC4",
Mark Brown07ed8732012-06-18 21:08:44 +0100327};
328EXPORT_SYMBOL_GPL(arizona_mixer_texts);
329
330int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
331 0x00, /* None */
332 0x04, /* Tone */
333 0x05,
334 0x06, /* Haptics */
335 0x08, /* AEC */
336 0x0c, /* Noise mixer */
337 0x0d, /* Comfort noise */
338 0x10, /* IN1L */
339 0x11,
340 0x12,
341 0x13,
342 0x14,
343 0x15,
Mark Brownc9c56fd2012-07-09 19:09:01 +0100344 0x16,
345 0x17,
Mark Brown07ed8732012-06-18 21:08:44 +0100346 0x20, /* AIF1RX1 */
347 0x21,
348 0x22,
349 0x23,
350 0x24,
351 0x25,
352 0x26,
353 0x27,
354 0x28, /* AIF2RX1 */
355 0x29,
356 0x30, /* AIF3RX1 */
357 0x31,
358 0x38, /* SLIMRX1 */
359 0x39,
360 0x3a,
361 0x3b,
362 0x3c,
363 0x3d,
364 0x3e,
365 0x3f,
366 0x50, /* EQ1 */
367 0x51,
368 0x52,
369 0x53,
370 0x58, /* DRC1L */
371 0x59,
372 0x5a,
373 0x5b,
374 0x60, /* LHPF1 */
375 0x61,
376 0x62,
377 0x63,
378 0x68, /* DSP1.1 */
379 0x69,
380 0x6a,
381 0x6b,
382 0x6c,
383 0x6d,
Mark Brownc922cc42012-09-26 16:43:44 +0100384 0x70, /* DSP2.1 */
385 0x71,
386 0x72,
387 0x73,
388 0x74,
389 0x75,
390 0x78, /* DSP3.1 */
391 0x79,
392 0x7a,
393 0x7b,
394 0x7c,
395 0x7d,
396 0x80, /* DSP4.1 */
397 0x81,
398 0x82,
399 0x83,
400 0x84,
401 0x85,
Mark Brown07ed8732012-06-18 21:08:44 +0100402 0x90, /* ASRC1L */
403 0x91,
404 0x92,
405 0x93,
Mark Brown91660bd2012-12-05 20:35:24 +0900406 0xa0, /* ISRC1INT1 */
407 0xa1,
408 0xa2,
409 0xa3,
410 0xa4, /* ISRC1DEC1 */
411 0xa5,
412 0xa6,
413 0xa7,
414 0xa8, /* ISRC2DEC1 */
415 0xa9,
416 0xaa,
417 0xab,
418 0xac, /* ISRC2INT1 */
419 0xad,
420 0xae,
421 0xaf,
422 0xb0, /* ISRC3DEC1 */
423 0xb1,
424 0xb2,
425 0xb3,
426 0xb4, /* ISRC3INT1 */
427 0xb5,
428 0xb6,
429 0xb7,
Mark Brown07ed8732012-06-18 21:08:44 +0100430};
431EXPORT_SYMBOL_GPL(arizona_mixer_values);
432
433const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
434EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
435
Mark Browne853a002012-12-09 12:25:52 +0900436static const char *arizona_vol_ramp_text[] = {
437 "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
438 "15ms/6dB", "30ms/6dB",
439};
440
441const struct soc_enum arizona_in_vd_ramp =
442 SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP,
443 ARIZONA_IN_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text);
444EXPORT_SYMBOL_GPL(arizona_in_vd_ramp);
445
446const struct soc_enum arizona_in_vi_ramp =
447 SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP,
448 ARIZONA_IN_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text);
449EXPORT_SYMBOL_GPL(arizona_in_vi_ramp);
450
451const struct soc_enum arizona_out_vd_ramp =
452 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP,
453 ARIZONA_OUT_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text);
454EXPORT_SYMBOL_GPL(arizona_out_vd_ramp);
455
456const struct soc_enum arizona_out_vi_ramp =
457 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP,
458 ARIZONA_OUT_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text);
459EXPORT_SYMBOL_GPL(arizona_out_vi_ramp);
460
Mark Brown07ed8732012-06-18 21:08:44 +0100461static const char *arizona_lhpf_mode_text[] = {
462 "Low-pass", "High-pass"
463};
464
465const struct soc_enum arizona_lhpf1_mode =
466 SOC_ENUM_SINGLE(ARIZONA_HPLPF1_1, ARIZONA_LHPF1_MODE_SHIFT, 2,
467 arizona_lhpf_mode_text);
468EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
469
470const struct soc_enum arizona_lhpf2_mode =
471 SOC_ENUM_SINGLE(ARIZONA_HPLPF2_1, ARIZONA_LHPF2_MODE_SHIFT, 2,
472 arizona_lhpf_mode_text);
473EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
474
475const struct soc_enum arizona_lhpf3_mode =
476 SOC_ENUM_SINGLE(ARIZONA_HPLPF3_1, ARIZONA_LHPF3_MODE_SHIFT, 2,
477 arizona_lhpf_mode_text);
478EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
479
480const struct soc_enum arizona_lhpf4_mode =
481 SOC_ENUM_SINGLE(ARIZONA_HPLPF4_1, ARIZONA_LHPF4_MODE_SHIFT, 2,
482 arizona_lhpf_mode_text);
483EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
484
Mark Brown845571c2012-12-18 13:47:57 +0000485static const char *arizona_ng_hold_text[] = {
486 "30ms", "120ms", "250ms", "500ms",
487};
488
489const struct soc_enum arizona_ng_hold =
490 SOC_ENUM_SINGLE(ARIZONA_NOISE_GATE_CONTROL, ARIZONA_NGATE_HOLD_SHIFT,
491 4, arizona_ng_hold_text);
492EXPORT_SYMBOL_GPL(arizona_ng_hold);
493
Mark Brownddbce972013-02-15 17:27:22 +0000494static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
495{
496 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
497 unsigned int val;
498 int i;
499
500 if (ena)
501 val = ARIZONA_IN_VU;
502 else
503 val = 0;
504
505 for (i = 0; i < priv->num_inputs; i++)
506 snd_soc_update_bits(codec,
507 ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 4),
508 ARIZONA_IN_VU, val);
509}
510
Mark Brown07ed8732012-06-18 21:08:44 +0100511int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
512 int event)
513{
Mark Brownddbce972013-02-15 17:27:22 +0000514 struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000515 unsigned int reg;
516
517 if (w->shift % 2)
518 reg = ARIZONA_ADC_DIGITAL_VOLUME_1L + ((w->shift / 2) * 8);
519 else
520 reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8);
521
522 switch (event) {
Mark Brownddbce972013-02-15 17:27:22 +0000523 case SND_SOC_DAPM_PRE_PMU:
524 priv->in_pending++;
525 break;
Mark Brown43cd8bf2013-02-06 16:57:29 +0000526 case SND_SOC_DAPM_POST_PMU:
527 snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, 0);
Mark Brownddbce972013-02-15 17:27:22 +0000528
529 /* If this is the last input pending then allow VU */
530 priv->in_pending--;
531 if (priv->in_pending == 0) {
532 msleep(1);
533 arizona_in_set_vu(w->codec, 1);
534 }
Mark Brown43cd8bf2013-02-06 16:57:29 +0000535 break;
536 case SND_SOC_DAPM_PRE_PMD:
Mark Brownddbce972013-02-15 17:27:22 +0000537 snd_soc_update_bits(w->codec, reg,
538 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU,
539 ARIZONA_IN1L_MUTE | ARIZONA_IN_VU);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000540 break;
Mark Brownddbce972013-02-15 17:27:22 +0000541 case SND_SOC_DAPM_POST_PMD:
542 /* Disable volume updates if no inputs are enabled */
543 reg = snd_soc_read(w->codec, ARIZONA_INPUT_ENABLES);
544 if (reg == 0)
545 arizona_in_set_vu(w->codec, 0);
Mark Brown43cd8bf2013-02-06 16:57:29 +0000546 }
547
Mark Brown07ed8732012-06-18 21:08:44 +0100548 return 0;
549}
550EXPORT_SYMBOL_GPL(arizona_in_ev);
551
552int arizona_out_ev(struct snd_soc_dapm_widget *w,
553 struct snd_kcontrol *kcontrol,
554 int event)
555{
556 return 0;
557}
558EXPORT_SYMBOL_GPL(arizona_out_ev);
559
Mark Browncbd840d2012-08-08 17:52:44 +0100560static unsigned int arizona_sysclk_48k_rates[] = {
561 6144000,
562 12288000,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000563 24576000,
Mark Browncbd840d2012-08-08 17:52:44 +0100564 49152000,
Mark Brownaeaeee12012-09-26 17:50:02 +0100565 73728000,
566 98304000,
567 147456000,
Mark Browncbd840d2012-08-08 17:52:44 +0100568};
569
570static unsigned int arizona_sysclk_44k1_rates[] = {
571 5644800,
572 11289600,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000573 22579200,
Mark Browncbd840d2012-08-08 17:52:44 +0100574 45158400,
Mark Brownaeaeee12012-09-26 17:50:02 +0100575 67737600,
576 90316800,
577 135475200,
Mark Browncbd840d2012-08-08 17:52:44 +0100578};
579
580static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
581 unsigned int freq)
582{
583 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
584 unsigned int reg;
585 unsigned int *rates;
586 int ref, div, refclk;
587
588 switch (clk) {
589 case ARIZONA_CLK_OPCLK:
590 reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
591 refclk = priv->sysclk;
592 break;
593 case ARIZONA_CLK_ASYNC_OPCLK:
594 reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
595 refclk = priv->asyncclk;
596 break;
597 default:
598 return -EINVAL;
599 }
600
601 if (refclk % 8000)
602 rates = arizona_sysclk_44k1_rates;
603 else
604 rates = arizona_sysclk_48k_rates;
605
606 for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) &&
607 rates[ref] <= refclk; ref++) {
608 div = 1;
609 while (rates[ref] / div >= freq && div < 32) {
610 if (rates[ref] / div == freq) {
611 dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
612 freq);
613 snd_soc_update_bits(codec, reg,
614 ARIZONA_OPCLK_DIV_MASK |
615 ARIZONA_OPCLK_SEL_MASK,
616 (div <<
617 ARIZONA_OPCLK_DIV_SHIFT) |
618 ref);
619 return 0;
620 }
621 div++;
622 }
623 }
624
625 dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
626 return -EINVAL;
627}
628
Mark Brown07ed8732012-06-18 21:08:44 +0100629int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
630 int source, unsigned int freq, int dir)
631{
632 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
633 struct arizona *arizona = priv->arizona;
634 char *name;
635 unsigned int reg;
636 unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
637 unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
638 unsigned int *clk;
639
640 switch (clk_id) {
641 case ARIZONA_CLK_SYSCLK:
642 name = "SYSCLK";
643 reg = ARIZONA_SYSTEM_CLOCK_1;
644 clk = &priv->sysclk;
645 mask |= ARIZONA_SYSCLK_FRAC;
646 break;
647 case ARIZONA_CLK_ASYNCCLK:
648 name = "ASYNCCLK";
649 reg = ARIZONA_ASYNC_CLOCK_1;
650 clk = &priv->asyncclk;
651 break;
Mark Browncbd840d2012-08-08 17:52:44 +0100652 case ARIZONA_CLK_OPCLK:
653 case ARIZONA_CLK_ASYNC_OPCLK:
654 return arizona_set_opclk(codec, clk_id, freq);
Mark Brown07ed8732012-06-18 21:08:44 +0100655 default:
656 return -EINVAL;
657 }
658
659 switch (freq) {
660 case 5644800:
661 case 6144000:
662 break;
663 case 11289600:
664 case 12288000:
Mark Brown3f341f72013-03-08 15:22:29 +0800665 val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100666 break;
667 case 22579200:
668 case 24576000:
Mark Brown3f341f72013-03-08 15:22:29 +0800669 val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100670 break;
671 case 45158400:
672 case 49152000:
Mark Brown3f341f72013-03-08 15:22:29 +0800673 val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown07ed8732012-06-18 21:08:44 +0100674 break;
Mark Brown38113362012-11-26 16:01:37 +0000675 case 67737600:
676 case 73728000:
Mark Brown3f341f72013-03-08 15:22:29 +0800677 val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000678 break;
679 case 90316800:
680 case 98304000:
Mark Brown3f341f72013-03-08 15:22:29 +0800681 val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000682 break;
683 case 135475200:
684 case 147456000:
Mark Brown3f341f72013-03-08 15:22:29 +0800685 val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
Mark Brown38113362012-11-26 16:01:37 +0000686 break;
Mark Brownf2c26d42013-01-21 16:09:36 +0900687 case 0:
688 dev_dbg(arizona->dev, "%s cleared\n", name);
689 *clk = freq;
690 return 0;
Mark Brown07ed8732012-06-18 21:08:44 +0100691 default:
692 return -EINVAL;
693 }
694
695 *clk = freq;
696
697 if (freq % 6144000)
698 val |= ARIZONA_SYSCLK_FRAC;
699
700 dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
701
702 return regmap_update_bits(arizona->regmap, reg, mask, val);
703}
704EXPORT_SYMBOL_GPL(arizona_set_sysclk);
705
706static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
707{
708 struct snd_soc_codec *codec = dai->codec;
709 int lrclk, bclk, mode, base;
710
711 base = dai->driver->base;
712
713 lrclk = 0;
714 bclk = 0;
715
716 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
717 case SND_SOC_DAIFMT_DSP_A:
718 mode = 0;
719 break;
Mark Brown07ed8732012-06-18 21:08:44 +0100720 case SND_SOC_DAIFMT_I2S:
721 mode = 2;
722 break;
Mark Brown07ed8732012-06-18 21:08:44 +0100723 default:
724 arizona_aif_err(dai, "Unsupported DAI format %d\n",
725 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
726 return -EINVAL;
727 }
728
729 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
730 case SND_SOC_DAIFMT_CBS_CFS:
731 break;
732 case SND_SOC_DAIFMT_CBS_CFM:
733 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
734 break;
735 case SND_SOC_DAIFMT_CBM_CFS:
736 bclk |= ARIZONA_AIF1_BCLK_MSTR;
737 break;
738 case SND_SOC_DAIFMT_CBM_CFM:
739 bclk |= ARIZONA_AIF1_BCLK_MSTR;
740 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
741 break;
742 default:
743 arizona_aif_err(dai, "Unsupported master mode %d\n",
744 fmt & SND_SOC_DAIFMT_MASTER_MASK);
745 return -EINVAL;
746 }
747
748 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
749 case SND_SOC_DAIFMT_NB_NF:
750 break;
751 case SND_SOC_DAIFMT_IB_IF:
752 bclk |= ARIZONA_AIF1_BCLK_INV;
753 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
754 break;
755 case SND_SOC_DAIFMT_IB_NF:
756 bclk |= ARIZONA_AIF1_BCLK_INV;
757 break;
758 case SND_SOC_DAIFMT_NB_IF:
759 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
760 break;
761 default:
762 return -EINVAL;
763 }
764
765 snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
766 ARIZONA_AIF1_BCLK_INV | ARIZONA_AIF1_BCLK_MSTR,
767 bclk);
768 snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_PIN_CTRL,
769 ARIZONA_AIF1TX_LRCLK_INV |
770 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
771 snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_PIN_CTRL,
772 ARIZONA_AIF1RX_LRCLK_INV |
773 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
774 snd_soc_update_bits(codec, base + ARIZONA_AIF_FORMAT,
775 ARIZONA_AIF1_FMT_MASK, mode);
776
777 return 0;
778}
779
Mark Brown949e6bc2012-07-04 18:58:04 +0100780static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100781 -1,
782 48000,
783 64000,
784 96000,
785 128000,
786 192000,
787 256000,
788 384000,
789 512000,
790 768000,
791 1024000,
792 1536000,
793 2048000,
794 3072000,
795 4096000,
796 6144000,
797 8192000,
798 12288000,
799 24576000,
800};
801
Mark Brown5b2eec32012-07-04 17:32:05 +0100802static const unsigned int arizona_48k_rates[] = {
803 12000,
804 24000,
805 48000,
806 96000,
807 192000,
808 384000,
809 768000,
810 4000,
811 8000,
812 16000,
813 32000,
814 64000,
815 128000,
816 256000,
817 512000,
818};
819
820static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = {
821 .count = ARRAY_SIZE(arizona_48k_rates),
822 .list = arizona_48k_rates,
823};
824
Mark Brown949e6bc2012-07-04 18:58:04 +0100825static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100826 -1,
827 44100,
828 58800,
829 88200,
830 117600,
831 177640,
832 235200,
833 352800,
834 470400,
835 705600,
836 940800,
837 1411200,
838 1881600,
Heather Lomond4758be32012-09-05 05:02:10 -0400839 2822400,
Mark Brown07ed8732012-06-18 21:08:44 +0100840 3763200,
841 5644800,
842 7526400,
843 11289600,
844 22579200,
845};
846
Mark Brown5b2eec32012-07-04 17:32:05 +0100847static const unsigned int arizona_44k1_rates[] = {
848 11025,
849 22050,
850 44100,
851 88200,
852 176400,
853 352800,
854 705600,
855};
856
857static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = {
858 .count = ARRAY_SIZE(arizona_44k1_rates),
859 .list = arizona_44k1_rates,
860};
861
Mark Brown07ed8732012-06-18 21:08:44 +0100862static int arizona_sr_vals[] = {
863 0,
864 12000,
865 24000,
866 48000,
867 96000,
868 192000,
869 384000,
870 768000,
871 0,
872 11025,
873 22050,
874 44100,
875 88200,
876 176400,
877 352800,
878 705600,
879 4000,
880 8000,
881 16000,
882 32000,
883 64000,
884 128000,
885 256000,
886 512000,
887};
888
Mark Brown5b2eec32012-07-04 17:32:05 +0100889static int arizona_startup(struct snd_pcm_substream *substream,
890 struct snd_soc_dai *dai)
891{
892 struct snd_soc_codec *codec = dai->codec;
893 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
894 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
895 const struct snd_pcm_hw_constraint_list *constraint;
896 unsigned int base_rate;
897
898 switch (dai_priv->clk) {
899 case ARIZONA_CLK_SYSCLK:
900 base_rate = priv->sysclk;
901 break;
902 case ARIZONA_CLK_ASYNCCLK:
903 base_rate = priv->asyncclk;
904 break;
905 default:
906 return 0;
907 }
908
Mark Brownf2c26d42013-01-21 16:09:36 +0900909 if (base_rate == 0)
910 return 0;
911
Mark Brown5b2eec32012-07-04 17:32:05 +0100912 if (base_rate % 8000)
913 constraint = &arizona_44k1_constraint;
914 else
915 constraint = &arizona_48k_constraint;
916
917 return snd_pcm_hw_constraint_list(substream->runtime, 0,
918 SNDRV_PCM_HW_PARAM_RATE,
919 constraint);
920}
921
Mark Brownb272efc2012-10-10 15:10:08 +0900922static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
923 struct snd_pcm_hw_params *params,
924 struct snd_soc_dai *dai)
Mark Brown07ed8732012-06-18 21:08:44 +0100925{
926 struct snd_soc_codec *codec = dai->codec;
Mark Brownc013b272012-07-04 20:05:57 +0100927 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
928 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown07ed8732012-06-18 21:08:44 +0100929 int base = dai->driver->base;
Mark Brownb272efc2012-10-10 15:10:08 +0900930 int i, sr_val;
931
932 /*
933 * We will need to be more flexible than this in future,
934 * currently we use a single sample rate for SYSCLK.
935 */
936 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
937 if (arizona_sr_vals[i] == params_rate(params))
938 break;
939 if (i == ARRAY_SIZE(arizona_sr_vals)) {
940 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
941 params_rate(params));
942 return -EINVAL;
943 }
944 sr_val = i;
945
946 switch (dai_priv->clk) {
947 case ARIZONA_CLK_SYSCLK:
948 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
949 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
950 if (base)
951 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
952 ARIZONA_AIF1_RATE_MASK, 0);
953 break;
954 case ARIZONA_CLK_ASYNCCLK:
955 snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
956 ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val);
957 if (base)
958 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
959 ARIZONA_AIF1_RATE_MASK,
960 8 << ARIZONA_AIF1_RATE_SHIFT);
961 break;
962 default:
963 arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
964 return -EINVAL;
965 }
966
967 return 0;
968}
969
Mark Brown07ed8732012-06-18 21:08:44 +0100970static int arizona_hw_params(struct snd_pcm_substream *substream,
971 struct snd_pcm_hw_params *params,
972 struct snd_soc_dai *dai)
973{
974 struct snd_soc_codec *codec = dai->codec;
975 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
Mark Brownc94aa302013-01-17 16:35:14 +0900976 struct arizona *arizona = priv->arizona;
Mark Brown07ed8732012-06-18 21:08:44 +0100977 int base = dai->driver->base;
978 const int *rates;
Mark Brown76bf9692013-03-05 14:17:47 +0800979 int i, ret, val;
Mark Brownc94aa302013-01-17 16:35:14 +0900980 int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
981 int bclk, lrclk, wl, frame, bclk_target;
Mark Brown07ed8732012-06-18 21:08:44 +0100982
983 if (params_rate(params) % 8000)
Mark Brown949e6bc2012-07-04 18:58:04 +0100984 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +0100985 else
Mark Brown949e6bc2012-07-04 18:58:04 +0100986 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +0100987
Mark Brownc94aa302013-01-17 16:35:14 +0900988 bclk_target = snd_soc_params_to_bclk(params);
989 if (chan_limit && chan_limit < params_channels(params)) {
990 arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
991 bclk_target /= params_channels(params);
992 bclk_target *= chan_limit;
993 }
994
Mark Brown76bf9692013-03-05 14:17:47 +0800995 /* Force stereo for I2S mode */
996 val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
997 if (params_channels(params) == 1 && (val & ARIZONA_AIF1_FMT_MASK)) {
998 arizona_aif_dbg(dai, "Forcing stereo mode\n");
999 bclk_target *= 2;
1000 }
1001
Mark Brown949e6bc2012-07-04 18:58:04 +01001002 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brownc94aa302013-01-17 16:35:14 +09001003 if (rates[i] >= bclk_target &&
Mark Brown50017652012-07-04 19:07:09 +01001004 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +01001005 bclk = i;
1006 break;
1007 }
1008 }
Mark Brown949e6bc2012-07-04 18:58:04 +01001009 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001010 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1011 params_rate(params));
1012 return -EINVAL;
1013 }
1014
Mark Brownb59e0f82013-01-17 14:15:59 +09001015 lrclk = rates[bclk] / params_rate(params);
Mark Brown07ed8732012-06-18 21:08:44 +01001016
1017 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
1018 rates[bclk], rates[bclk] / lrclk);
1019
1020 wl = snd_pcm_format_width(params_format(params));
1021 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl;
1022
Mark Brownb272efc2012-10-10 15:10:08 +09001023 ret = arizona_hw_params_rate(substream, params, dai);
1024 if (ret != 0)
1025 return ret;
Mark Brownc013b272012-07-04 20:05:57 +01001026
Mark Brown07ed8732012-06-18 21:08:44 +01001027 snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
1028 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
1029 snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_BCLK_RATE,
1030 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
1031 snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_BCLK_RATE,
1032 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
1033 snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_1,
1034 ARIZONA_AIF1TX_WL_MASK |
1035 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
1036 snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_2,
1037 ARIZONA_AIF1RX_WL_MASK |
1038 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
1039
1040 return 0;
1041}
1042
Mark Brown410837a2012-07-05 17:26:59 +01001043static const char *arizona_dai_clk_str(int clk_id)
1044{
1045 switch (clk_id) {
1046 case ARIZONA_CLK_SYSCLK:
1047 return "SYSCLK";
1048 case ARIZONA_CLK_ASYNCCLK:
1049 return "ASYNCCLK";
1050 default:
1051 return "Unknown clock";
1052 }
1053}
1054
Mark Brown5b2eec32012-07-04 17:32:05 +01001055static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
1056 int clk_id, unsigned int freq, int dir)
1057{
1058 struct snd_soc_codec *codec = dai->codec;
1059 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
1060 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown410837a2012-07-05 17:26:59 +01001061 struct snd_soc_dapm_route routes[2];
Mark Brown5b2eec32012-07-04 17:32:05 +01001062
1063 switch (clk_id) {
1064 case ARIZONA_CLK_SYSCLK:
1065 case ARIZONA_CLK_ASYNCCLK:
1066 break;
1067 default:
1068 return -EINVAL;
1069 }
1070
Mark Brown410837a2012-07-05 17:26:59 +01001071 if (clk_id == dai_priv->clk)
1072 return 0;
1073
1074 if (dai->active) {
Mark Brown5b2eec32012-07-04 17:32:05 +01001075 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
1076 dai->id);
1077 return -EBUSY;
1078 }
1079
Mark Brownc8d35a62012-12-07 12:49:40 +09001080 dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1,
1081 arizona_dai_clk_str(clk_id));
1082
Mark Brown410837a2012-07-05 17:26:59 +01001083 memset(&routes, 0, sizeof(routes));
1084 routes[0].sink = dai->driver->capture.stream_name;
1085 routes[1].sink = dai->driver->playback.stream_name;
Mark Brown5b2eec32012-07-04 17:32:05 +01001086
Mark Brown410837a2012-07-05 17:26:59 +01001087 routes[0].source = arizona_dai_clk_str(dai_priv->clk);
1088 routes[1].source = arizona_dai_clk_str(dai_priv->clk);
1089 snd_soc_dapm_del_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
1090
1091 routes[0].source = arizona_dai_clk_str(clk_id);
1092 routes[1].source = arizona_dai_clk_str(clk_id);
1093 snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
1094
Mark Brown0c778e82012-12-06 18:22:25 +09001095 dai_priv->clk = clk_id;
1096
Mark Brown410837a2012-07-05 17:26:59 +01001097 return snd_soc_dapm_sync(&codec->dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +01001098}
1099
Mark Brown01df2592012-12-12 16:22:08 +09001100static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
1101{
1102 struct snd_soc_codec *codec = dai->codec;
1103 int base = dai->driver->base;
1104 unsigned int reg;
1105
1106 if (tristate)
1107 reg = ARIZONA_AIF1_TRI;
1108 else
1109 reg = 0;
1110
1111 return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
1112 ARIZONA_AIF1_TRI, reg);
1113}
1114
Mark Brown07ed8732012-06-18 21:08:44 +01001115const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +01001116 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +01001117 .set_fmt = arizona_set_fmt,
1118 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +01001119 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown01df2592012-12-12 16:22:08 +09001120 .set_tristate = arizona_set_tristate,
Mark Brown07ed8732012-06-18 21:08:44 +01001121};
Mark Browna8379872012-07-09 12:16:41 +01001122EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +01001123
Mark Brown5b2eec32012-07-04 17:32:05 +01001124int arizona_init_dai(struct arizona_priv *priv, int id)
1125{
1126 struct arizona_dai_priv *dai_priv = &priv->dai[id];
1127
1128 dai_priv->clk = ARIZONA_CLK_SYSCLK;
1129
1130 return 0;
1131}
1132EXPORT_SYMBOL_GPL(arizona_init_dai);
1133
Mark Brown07ed8732012-06-18 21:08:44 +01001134static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
1135{
1136 struct arizona_fll *fll = data;
1137
1138 arizona_fll_dbg(fll, "clock OK\n");
1139
1140 complete(&fll->ok);
1141
1142 return IRQ_HANDLED;
1143}
1144
1145static struct {
1146 unsigned int min;
1147 unsigned int max;
1148 u16 fratio;
1149 int ratio;
1150} fll_fratios[] = {
1151 { 0, 64000, 4, 16 },
1152 { 64000, 128000, 3, 8 },
1153 { 128000, 256000, 2, 4 },
1154 { 256000, 1000000, 1, 2 },
1155 { 1000000, 13500000, 0, 1 },
1156};
1157
Mark Brown8f113d72013-03-05 12:08:57 +08001158static struct {
1159 unsigned int min;
1160 unsigned int max;
1161 u16 gain;
1162} fll_gains[] = {
1163 { 0, 256000, 0 },
1164 { 256000, 1000000, 2 },
1165 { 1000000, 13500000, 4 },
1166};
1167
Mark Brown07ed8732012-06-18 21:08:44 +01001168struct arizona_fll_cfg {
1169 int n;
1170 int theta;
1171 int lambda;
1172 int refdiv;
1173 int outdiv;
1174 int fratio;
Mark Brown8f113d72013-03-05 12:08:57 +08001175 int gain;
Mark Brown07ed8732012-06-18 21:08:44 +01001176};
1177
1178static int arizona_calc_fll(struct arizona_fll *fll,
1179 struct arizona_fll_cfg *cfg,
1180 unsigned int Fref,
1181 unsigned int Fout)
1182{
1183 unsigned int target, div, gcd_fll;
1184 int i, ratio;
1185
1186 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout);
1187
1188 /* Fref must be <=13.5MHz */
1189 div = 1;
1190 cfg->refdiv = 0;
1191 while ((Fref / div) > 13500000) {
1192 div *= 2;
1193 cfg->refdiv++;
1194
1195 if (div > 8) {
1196 arizona_fll_err(fll,
1197 "Can't scale %dMHz in to <=13.5MHz\n",
1198 Fref);
1199 return -EINVAL;
1200 }
1201 }
1202
1203 /* Apply the division for our remaining calculations */
1204 Fref /= div;
1205
Mark Brown2b4d39f2012-07-10 17:03:46 +01001206 /* Fvco should be over the targt; don't check the upper bound */
Mark Brown07ed8732012-06-18 21:08:44 +01001207 div = 1;
Mark Brown2b4d39f2012-07-10 17:03:46 +01001208 while (Fout * div < 90000000 * fll->vco_mult) {
Mark Brown07ed8732012-06-18 21:08:44 +01001209 div++;
1210 if (div > 7) {
1211 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
1212 Fout);
1213 return -EINVAL;
1214 }
1215 }
Mark Brown2b4d39f2012-07-10 17:03:46 +01001216 target = Fout * div / fll->vco_mult;
Mark Brown07ed8732012-06-18 21:08:44 +01001217 cfg->outdiv = div;
1218
1219 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
1220
1221 /* Find an appropraite FLL_FRATIO and factor it out of the target */
1222 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
1223 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
1224 cfg->fratio = fll_fratios[i].fratio;
1225 ratio = fll_fratios[i].ratio;
1226 break;
1227 }
1228 }
1229 if (i == ARRAY_SIZE(fll_fratios)) {
1230 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
1231 Fref);
1232 return -EINVAL;
1233 }
1234
Mark Brown8f113d72013-03-05 12:08:57 +08001235 for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
1236 if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
1237 cfg->gain = fll_gains[i].gain;
1238 break;
1239 }
1240 }
1241 if (i == ARRAY_SIZE(fll_gains)) {
1242 arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
1243 Fref);
1244 return -EINVAL;
1245 }
1246
Mark Brown07ed8732012-06-18 21:08:44 +01001247 cfg->n = target / (ratio * Fref);
1248
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001249 if (target % (ratio * Fref)) {
Mark Brown07ed8732012-06-18 21:08:44 +01001250 gcd_fll = gcd(target, ratio * Fref);
1251 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
1252
1253 cfg->theta = (target - (cfg->n * ratio * Fref))
1254 / gcd_fll;
1255 cfg->lambda = (ratio * Fref) / gcd_fll;
1256 } else {
1257 cfg->theta = 0;
1258 cfg->lambda = 0;
1259 }
1260
Ryo Tsutsui01f58152013-02-03 17:18:00 +09001261 /* Round down to 16bit range with cost of accuracy lost.
1262 * Denominator must be bigger than numerator so we only
1263 * take care of it.
1264 */
1265 while (cfg->lambda >= (1 << 16)) {
1266 cfg->theta >>= 1;
1267 cfg->lambda >>= 1;
1268 }
1269
Mark Brown07ed8732012-06-18 21:08:44 +01001270 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
1271 cfg->n, cfg->theta, cfg->lambda);
1272 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
1273 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
Mark Brown8f113d72013-03-05 12:08:57 +08001274 arizona_fll_dbg(fll, "GAIN=%d\n", cfg->gain);
Mark Brown07ed8732012-06-18 21:08:44 +01001275
1276 return 0;
1277
1278}
1279
1280static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
Mark Brown8f113d72013-03-05 12:08:57 +08001281 struct arizona_fll_cfg *cfg, int source,
1282 bool sync)
Mark Brown07ed8732012-06-18 21:08:44 +01001283{
1284 regmap_update_bits(arizona->regmap, base + 3,
1285 ARIZONA_FLL1_THETA_MASK, cfg->theta);
1286 regmap_update_bits(arizona->regmap, base + 4,
1287 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
1288 regmap_update_bits(arizona->regmap, base + 5,
1289 ARIZONA_FLL1_FRATIO_MASK,
1290 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
1291 regmap_update_bits(arizona->regmap, base + 6,
1292 ARIZONA_FLL1_CLK_REF_DIV_MASK |
1293 ARIZONA_FLL1_CLK_REF_SRC_MASK,
1294 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
1295 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
1296
Mark Brown8f113d72013-03-05 12:08:57 +08001297 if (sync)
1298 regmap_update_bits(arizona->regmap, base + 0x7,
1299 ARIZONA_FLL1_GAIN_MASK,
1300 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
1301 else
1302 regmap_update_bits(arizona->regmap, base + 0x9,
1303 ARIZONA_FLL1_GAIN_MASK,
1304 cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
1305
Mark Brown07ed8732012-06-18 21:08:44 +01001306 regmap_update_bits(arizona->regmap, base + 2,
1307 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
1308 ARIZONA_FLL1_CTRL_UPD | cfg->n);
1309}
1310
Charles Keepaxd122d6c2013-02-20 17:28:36 +00001311static bool arizona_is_enabled_fll(struct arizona_fll *fll)
1312{
1313 struct arizona *arizona = fll->arizona;
1314 unsigned int reg;
1315 int ret;
1316
1317 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
1318 if (ret != 0) {
1319 arizona_fll_err(fll, "Failed to read current state: %d\n",
1320 ret);
1321 return ret;
1322 }
1323
1324 return reg & ARIZONA_FLL1_ENA;
1325}
1326
Charles Keepax35722812013-02-20 17:28:38 +00001327static void arizona_enable_fll(struct arizona_fll *fll,
1328 struct arizona_fll_cfg *ref,
1329 struct arizona_fll_cfg *sync)
1330{
1331 struct arizona *arizona = fll->arizona;
1332 int ret;
1333
Mark Brownff680a12013-03-04 16:00:19 +08001334 /*
1335 * If we have both REFCLK and SYNCCLK then enable both,
1336 * otherwise apply the SYNCCLK settings to REFCLK.
1337 */
1338 if (fll->ref_src >= 0 && fll->ref_src != fll->sync_src) {
1339 regmap_update_bits(arizona->regmap, fll->base + 5,
1340 ARIZONA_FLL1_OUTDIV_MASK,
1341 ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
Charles Keepax35722812013-02-20 17:28:38 +00001342
Mark Brown8f113d72013-03-05 12:08:57 +08001343 arizona_apply_fll(arizona, fll->base, ref, fll->ref_src,
1344 false);
Mark Brownff680a12013-03-04 16:00:19 +08001345 if (fll->sync_src >= 0)
1346 arizona_apply_fll(arizona, fll->base + 0x10, sync,
Mark Brown8f113d72013-03-05 12:08:57 +08001347 fll->sync_src, true);
Mark Brownff680a12013-03-04 16:00:19 +08001348 } else if (fll->sync_src >= 0) {
1349 regmap_update_bits(arizona->regmap, fll->base + 5,
1350 ARIZONA_FLL1_OUTDIV_MASK,
1351 sync->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
1352
1353 arizona_apply_fll(arizona, fll->base, sync,
Mark Brown8f113d72013-03-05 12:08:57 +08001354 fll->sync_src, false);
Mark Browneca2e8e2013-03-06 00:09:59 +08001355
1356 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1357 ARIZONA_FLL1_SYNC_ENA, 0);
Mark Brownff680a12013-03-04 16:00:19 +08001358 } else {
1359 arizona_fll_err(fll, "No clocks provided\n");
1360 return;
1361 }
Charles Keepax35722812013-02-20 17:28:38 +00001362
Mark Brown576411be2013-03-05 12:07:16 +08001363 /*
1364 * Increase the bandwidth if we're not using a low frequency
1365 * sync source.
1366 */
1367 if (fll->sync_src >= 0 && fll->sync_freq > 100000)
1368 regmap_update_bits(arizona->regmap, fll->base + 0x17,
1369 ARIZONA_FLL1_SYNC_BW, 0);
1370 else
1371 regmap_update_bits(arizona->regmap, fll->base + 0x17,
1372 ARIZONA_FLL1_SYNC_BW, ARIZONA_FLL1_SYNC_BW);
1373
Charles Keepax35722812013-02-20 17:28:38 +00001374 if (!arizona_is_enabled_fll(fll))
1375 pm_runtime_get(arizona->dev);
1376
1377 /* Clear any pending completions */
1378 try_wait_for_completion(&fll->ok);
1379
1380 regmap_update_bits(arizona->regmap, fll->base + 1,
1381 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
Mark Brownff680a12013-03-04 16:00:19 +08001382 if (fll->ref_src >= 0 && fll->sync_src >= 0 &&
1383 fll->ref_src != fll->sync_src)
Charles Keepax35722812013-02-20 17:28:38 +00001384 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1385 ARIZONA_FLL1_SYNC_ENA,
1386 ARIZONA_FLL1_SYNC_ENA);
1387
1388 ret = wait_for_completion_timeout(&fll->ok,
1389 msecs_to_jiffies(250));
1390 if (ret == 0)
1391 arizona_fll_warn(fll, "Timed out waiting for lock\n");
1392}
1393
Charles Keepax76040542013-02-20 17:28:37 +00001394static void arizona_disable_fll(struct arizona_fll *fll)
1395{
1396 struct arizona *arizona = fll->arizona;
1397 bool change;
1398
1399 regmap_update_bits_check(arizona->regmap, fll->base + 1,
1400 ARIZONA_FLL1_ENA, 0, &change);
1401 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1402 ARIZONA_FLL1_SYNC_ENA, 0);
1403
1404 if (change)
1405 pm_runtime_put_autosuspend(arizona->dev);
1406}
1407
Charles Keepaxee929a92013-02-20 17:28:40 +00001408int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
1409 unsigned int Fref, unsigned int Fout)
1410{
1411 struct arizona_fll_cfg ref, sync;
1412 int ret;
1413
Charles Keepax1c5617f2013-02-22 17:10:37 +00001414 if (fll->ref_src == source && fll->ref_freq == Fref)
Charles Keepaxee929a92013-02-20 17:28:40 +00001415 return 0;
1416
Mark Brown86cd6842013-03-07 16:14:04 +08001417 if (fll->fout && Fref > 0) {
Charles Keepax1c5617f2013-02-22 17:10:37 +00001418 ret = arizona_calc_fll(fll, &ref, Fref, fll->fout);
Charles Keepaxee929a92013-02-20 17:28:40 +00001419 if (ret != 0)
1420 return ret;
1421
1422 if (fll->sync_src >= 0) {
Charles Keepax1c5617f2013-02-22 17:10:37 +00001423 ret = arizona_calc_fll(fll, &sync, fll->sync_freq,
1424 fll->fout);
Charles Keepaxee929a92013-02-20 17:28:40 +00001425 if (ret != 0)
1426 return ret;
1427 }
1428 }
1429
1430 fll->ref_src = source;
1431 fll->ref_freq = Fref;
Charles Keepaxee929a92013-02-20 17:28:40 +00001432
Mark Brown86cd6842013-03-07 16:14:04 +08001433 if (fll->fout && Fref > 0) {
Charles Keepaxee929a92013-02-20 17:28:40 +00001434 arizona_enable_fll(fll, &ref, &sync);
Charles Keepaxee929a92013-02-20 17:28:40 +00001435 }
1436
1437 return 0;
1438}
1439EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
1440
Mark Brown07ed8732012-06-18 21:08:44 +01001441int arizona_set_fll(struct arizona_fll *fll, int source,
1442 unsigned int Fref, unsigned int Fout)
1443{
Charles Keepax9e359c62013-02-20 17:28:35 +00001444 struct arizona_fll_cfg ref, sync;
Mark Brown07ed8732012-06-18 21:08:44 +01001445 int ret;
1446
Mark Brownff680a12013-03-04 16:00:19 +08001447 if (fll->sync_src == source &&
1448 fll->sync_freq == Fref && fll->fout == Fout)
1449 return 0;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00001450
Mark Brownff680a12013-03-04 16:00:19 +08001451 if (Fout) {
1452 if (fll->ref_src >= 0) {
1453 ret = arizona_calc_fll(fll, &ref, fll->ref_freq,
1454 Fout);
Charles Keepax9e359c62013-02-20 17:28:35 +00001455 if (ret != 0)
1456 return ret;
1457 }
1458
Mark Brownff680a12013-03-04 16:00:19 +08001459 ret = arizona_calc_fll(fll, &sync, Fref, Fout);
1460 if (ret != 0)
1461 return ret;
Charles Keepax9e359c62013-02-20 17:28:35 +00001462 }
Mark Brownff680a12013-03-04 16:00:19 +08001463
1464 fll->sync_src = source;
1465 fll->sync_freq = Fref;
Charles Keepaxde1e6ee2013-02-20 17:28:39 +00001466 fll->fout = Fout;
Charles Keepax9e359c62013-02-20 17:28:35 +00001467
Mark Brown07ed8732012-06-18 21:08:44 +01001468 if (Fout) {
Charles Keepax35722812013-02-20 17:28:38 +00001469 arizona_enable_fll(fll, &ref, &sync);
Mark Brown07ed8732012-06-18 21:08:44 +01001470 } else {
Charles Keepax76040542013-02-20 17:28:37 +00001471 arizona_disable_fll(fll);
Mark Brown07ed8732012-06-18 21:08:44 +01001472 }
1473
Mark Brown07ed8732012-06-18 21:08:44 +01001474 return 0;
1475}
1476EXPORT_SYMBOL_GPL(arizona_set_fll);
1477
1478int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
1479 int ok_irq, struct arizona_fll *fll)
1480{
1481 int ret;
Charles Keepax19b34bd2013-02-20 17:28:34 +00001482 unsigned int val;
Mark Brown07ed8732012-06-18 21:08:44 +01001483
Mark Brown07ed8732012-06-18 21:08:44 +01001484 init_completion(&fll->ok);
1485
1486 fll->id = id;
1487 fll->base = base;
1488 fll->arizona = arizona;
Charles Keepaxf3f11632013-02-20 17:28:41 +00001489 fll->sync_src = ARIZONA_FLL_SRC_NONE;
Mark Brown07ed8732012-06-18 21:08:44 +01001490
Charles Keepax19b34bd2013-02-20 17:28:34 +00001491 /* Configure default refclk to 32kHz if we have one */
1492 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
1493 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
1494 case ARIZONA_CLK_SRC_MCLK1:
1495 case ARIZONA_CLK_SRC_MCLK2:
1496 fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK;
1497 break;
1498 default:
Charles Keepaxf3f11632013-02-20 17:28:41 +00001499 fll->ref_src = ARIZONA_FLL_SRC_NONE;
Charles Keepax19b34bd2013-02-20 17:28:34 +00001500 }
1501 fll->ref_freq = 32768;
1502
Mark Brown07ed8732012-06-18 21:08:44 +01001503 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
1504 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
1505 "FLL%d clock OK", id);
1506
Mark Brown07ed8732012-06-18 21:08:44 +01001507 ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
1508 arizona_fll_clock_ok, fll);
1509 if (ret != 0) {
1510 dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
1511 id, ret);
1512 }
1513
Charles Keepaxe31c1942013-01-07 16:41:45 +00001514 regmap_update_bits(arizona->regmap, fll->base + 1,
1515 ARIZONA_FLL1_FREERUN, 0);
1516
Mark Brown07ed8732012-06-18 21:08:44 +01001517 return 0;
1518}
1519EXPORT_SYMBOL_GPL(arizona_init_fll);
1520
Mark Brownbc9ab6d2013-01-04 19:31:00 +00001521/**
1522 * arizona_set_output_mode - Set the mode of the specified output
1523 *
1524 * @codec: Device to configure
1525 * @output: Output number
1526 * @diff: True to set the output to differential mode
1527 *
1528 * Some systems use external analogue switches to connect more
1529 * analogue devices to the CODEC than are supported by the device. In
1530 * some systems this requires changing the switched output from single
1531 * ended to differential mode dynamically at runtime, an operation
1532 * supported using this function.
1533 *
1534 * Most systems have a single static configuration and should use
1535 * platform data instead.
1536 */
1537int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
1538{
1539 unsigned int reg, val;
1540
1541 if (output < 1 || output > 6)
1542 return -EINVAL;
1543
1544 reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
1545
1546 if (diff)
1547 val = ARIZONA_OUT1_MONO;
1548 else
1549 val = 0;
1550
1551 return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val);
1552}
1553EXPORT_SYMBOL_GPL(arizona_set_output_mode);
1554
Mark Brown07ed8732012-06-18 21:08:44 +01001555MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
1556MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1557MODULE_LICENSE("GPL");