blob: bcd225853eb53eb723f38f6e84a31355e653180a [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
13#include <linux/gcd.h>
14#include <linux/module.h>
15#include <linux/pm_runtime.h>
16#include <sound/pcm.h>
17#include <sound/pcm_params.h>
18#include <sound/tlv.h>
19
20#include <linux/mfd/arizona/core.h>
21#include <linux/mfd/arizona/registers.h>
22
23#include "arizona.h"
24
25#define ARIZONA_AIF_BCLK_CTRL 0x00
26#define ARIZONA_AIF_TX_PIN_CTRL 0x01
27#define ARIZONA_AIF_RX_PIN_CTRL 0x02
28#define ARIZONA_AIF_RATE_CTRL 0x03
29#define ARIZONA_AIF_FORMAT 0x04
30#define ARIZONA_AIF_TX_BCLK_RATE 0x05
31#define ARIZONA_AIF_RX_BCLK_RATE 0x06
32#define ARIZONA_AIF_FRAME_CTRL_1 0x07
33#define ARIZONA_AIF_FRAME_CTRL_2 0x08
34#define ARIZONA_AIF_FRAME_CTRL_3 0x09
35#define ARIZONA_AIF_FRAME_CTRL_4 0x0A
36#define ARIZONA_AIF_FRAME_CTRL_5 0x0B
37#define ARIZONA_AIF_FRAME_CTRL_6 0x0C
38#define ARIZONA_AIF_FRAME_CTRL_7 0x0D
39#define ARIZONA_AIF_FRAME_CTRL_8 0x0E
40#define ARIZONA_AIF_FRAME_CTRL_9 0x0F
41#define ARIZONA_AIF_FRAME_CTRL_10 0x10
42#define ARIZONA_AIF_FRAME_CTRL_11 0x11
43#define ARIZONA_AIF_FRAME_CTRL_12 0x12
44#define ARIZONA_AIF_FRAME_CTRL_13 0x13
45#define ARIZONA_AIF_FRAME_CTRL_14 0x14
46#define ARIZONA_AIF_FRAME_CTRL_15 0x15
47#define ARIZONA_AIF_FRAME_CTRL_16 0x16
48#define ARIZONA_AIF_FRAME_CTRL_17 0x17
49#define ARIZONA_AIF_FRAME_CTRL_18 0x18
50#define ARIZONA_AIF_TX_ENABLES 0x19
51#define ARIZONA_AIF_RX_ENABLES 0x1A
52#define ARIZONA_AIF_FORCE_WRITE 0x1B
53
54#define arizona_fll_err(_fll, fmt, ...) \
55 dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
56#define arizona_fll_warn(_fll, fmt, ...) \
57 dev_warn(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
58#define arizona_fll_dbg(_fll, fmt, ...) \
59 dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
60
61#define arizona_aif_err(_dai, fmt, ...) \
62 dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
63#define arizona_aif_warn(_dai, fmt, ...) \
64 dev_warn(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
65#define arizona_aif_dbg(_dai, fmt, ...) \
66 dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
67
68const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
69 "None",
70 "Tone Generator 1",
71 "Tone Generator 2",
72 "Haptics",
73 "AEC",
74 "Mic Mute Mixer",
75 "Noise Generator",
76 "IN1L",
77 "IN1R",
78 "IN2L",
79 "IN2R",
80 "IN3L",
81 "IN3R",
Mark Brownc9c56fd2012-07-09 19:09:01 +010082 "IN4L",
83 "IN4R",
Mark Brown07ed8732012-06-18 21:08:44 +010084 "AIF1RX1",
85 "AIF1RX2",
86 "AIF1RX3",
87 "AIF1RX4",
88 "AIF1RX5",
89 "AIF1RX6",
90 "AIF1RX7",
91 "AIF1RX8",
92 "AIF2RX1",
93 "AIF2RX2",
94 "AIF3RX1",
95 "AIF3RX2",
96 "SLIMRX1",
97 "SLIMRX2",
98 "SLIMRX3",
99 "SLIMRX4",
100 "SLIMRX5",
101 "SLIMRX6",
102 "SLIMRX7",
103 "SLIMRX8",
104 "EQ1",
105 "EQ2",
106 "EQ3",
107 "EQ4",
108 "DRC1L",
109 "DRC1R",
110 "DRC2L",
111 "DRC2R",
112 "LHPF1",
113 "LHPF2",
114 "LHPF3",
115 "LHPF4",
116 "DSP1.1",
117 "DSP1.2",
118 "DSP1.3",
119 "DSP1.4",
120 "DSP1.5",
121 "DSP1.6",
Mark Brownc922cc42012-09-26 16:43:44 +0100122 "DSP2.1",
123 "DSP2.2",
124 "DSP2.3",
125 "DSP2.4",
126 "DSP2.5",
127 "DSP2.6",
128 "DSP3.1",
129 "DSP3.2",
130 "DSP3.3",
131 "DSP3.4",
132 "DSP3.5",
133 "DSP3.6",
134 "DSP4.1",
135 "DSP4.2",
136 "DSP4.3",
137 "DSP4.4",
138 "DSP4.5",
139 "DSP4.6",
Mark Brown07ed8732012-06-18 21:08:44 +0100140 "ASRC1L",
141 "ASRC1R",
142 "ASRC2L",
143 "ASRC2R",
Mark Brown91660bd2012-12-05 20:35:24 +0900144 "ISRC1INT1",
145 "ISRC1INT2",
146 "ISRC1INT3",
147 "ISRC1INT4",
148 "ISRC1DEC1",
149 "ISRC1DEC2",
150 "ISRC1DEC3",
151 "ISRC1DEC4",
152 "ISRC2INT1",
153 "ISRC2INT2",
154 "ISRC2INT3",
155 "ISRC2INT4",
156 "ISRC2DEC1",
157 "ISRC2DEC2",
158 "ISRC2DEC3",
159 "ISRC2DEC4",
160 "ISRC3INT1",
161 "ISRC3INT2",
162 "ISRC3INT3",
163 "ISRC3INT4",
164 "ISRC3DEC1",
165 "ISRC3DEC2",
166 "ISRC3DEC3",
167 "ISRC3DEC4",
Mark Brown07ed8732012-06-18 21:08:44 +0100168};
169EXPORT_SYMBOL_GPL(arizona_mixer_texts);
170
171int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
172 0x00, /* None */
173 0x04, /* Tone */
174 0x05,
175 0x06, /* Haptics */
176 0x08, /* AEC */
177 0x0c, /* Noise mixer */
178 0x0d, /* Comfort noise */
179 0x10, /* IN1L */
180 0x11,
181 0x12,
182 0x13,
183 0x14,
184 0x15,
Mark Brownc9c56fd2012-07-09 19:09:01 +0100185 0x16,
186 0x17,
Mark Brown07ed8732012-06-18 21:08:44 +0100187 0x20, /* AIF1RX1 */
188 0x21,
189 0x22,
190 0x23,
191 0x24,
192 0x25,
193 0x26,
194 0x27,
195 0x28, /* AIF2RX1 */
196 0x29,
197 0x30, /* AIF3RX1 */
198 0x31,
199 0x38, /* SLIMRX1 */
200 0x39,
201 0x3a,
202 0x3b,
203 0x3c,
204 0x3d,
205 0x3e,
206 0x3f,
207 0x50, /* EQ1 */
208 0x51,
209 0x52,
210 0x53,
211 0x58, /* DRC1L */
212 0x59,
213 0x5a,
214 0x5b,
215 0x60, /* LHPF1 */
216 0x61,
217 0x62,
218 0x63,
219 0x68, /* DSP1.1 */
220 0x69,
221 0x6a,
222 0x6b,
223 0x6c,
224 0x6d,
Mark Brownc922cc42012-09-26 16:43:44 +0100225 0x70, /* DSP2.1 */
226 0x71,
227 0x72,
228 0x73,
229 0x74,
230 0x75,
231 0x78, /* DSP3.1 */
232 0x79,
233 0x7a,
234 0x7b,
235 0x7c,
236 0x7d,
237 0x80, /* DSP4.1 */
238 0x81,
239 0x82,
240 0x83,
241 0x84,
242 0x85,
Mark Brown07ed8732012-06-18 21:08:44 +0100243 0x90, /* ASRC1L */
244 0x91,
245 0x92,
246 0x93,
Mark Brown91660bd2012-12-05 20:35:24 +0900247 0xa0, /* ISRC1INT1 */
248 0xa1,
249 0xa2,
250 0xa3,
251 0xa4, /* ISRC1DEC1 */
252 0xa5,
253 0xa6,
254 0xa7,
255 0xa8, /* ISRC2DEC1 */
256 0xa9,
257 0xaa,
258 0xab,
259 0xac, /* ISRC2INT1 */
260 0xad,
261 0xae,
262 0xaf,
263 0xb0, /* ISRC3DEC1 */
264 0xb1,
265 0xb2,
266 0xb3,
267 0xb4, /* ISRC3INT1 */
268 0xb5,
269 0xb6,
270 0xb7,
Mark Brown07ed8732012-06-18 21:08:44 +0100271};
272EXPORT_SYMBOL_GPL(arizona_mixer_values);
273
274const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
275EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
276
Mark Browne853a002012-12-09 12:25:52 +0900277static const char *arizona_vol_ramp_text[] = {
278 "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
279 "15ms/6dB", "30ms/6dB",
280};
281
282const struct soc_enum arizona_in_vd_ramp =
283 SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP,
284 ARIZONA_IN_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text);
285EXPORT_SYMBOL_GPL(arizona_in_vd_ramp);
286
287const struct soc_enum arizona_in_vi_ramp =
288 SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP,
289 ARIZONA_IN_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text);
290EXPORT_SYMBOL_GPL(arizona_in_vi_ramp);
291
292const struct soc_enum arizona_out_vd_ramp =
293 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP,
294 ARIZONA_OUT_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text);
295EXPORT_SYMBOL_GPL(arizona_out_vd_ramp);
296
297const struct soc_enum arizona_out_vi_ramp =
298 SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP,
299 ARIZONA_OUT_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text);
300EXPORT_SYMBOL_GPL(arizona_out_vi_ramp);
301
Mark Brown07ed8732012-06-18 21:08:44 +0100302static const char *arizona_lhpf_mode_text[] = {
303 "Low-pass", "High-pass"
304};
305
306const struct soc_enum arizona_lhpf1_mode =
307 SOC_ENUM_SINGLE(ARIZONA_HPLPF1_1, ARIZONA_LHPF1_MODE_SHIFT, 2,
308 arizona_lhpf_mode_text);
309EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
310
311const struct soc_enum arizona_lhpf2_mode =
312 SOC_ENUM_SINGLE(ARIZONA_HPLPF2_1, ARIZONA_LHPF2_MODE_SHIFT, 2,
313 arizona_lhpf_mode_text);
314EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
315
316const struct soc_enum arizona_lhpf3_mode =
317 SOC_ENUM_SINGLE(ARIZONA_HPLPF3_1, ARIZONA_LHPF3_MODE_SHIFT, 2,
318 arizona_lhpf_mode_text);
319EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
320
321const struct soc_enum arizona_lhpf4_mode =
322 SOC_ENUM_SINGLE(ARIZONA_HPLPF4_1, ARIZONA_LHPF4_MODE_SHIFT, 2,
323 arizona_lhpf_mode_text);
324EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
325
Mark Brown845571c2012-12-18 13:47:57 +0000326static const char *arizona_ng_hold_text[] = {
327 "30ms", "120ms", "250ms", "500ms",
328};
329
330const struct soc_enum arizona_ng_hold =
331 SOC_ENUM_SINGLE(ARIZONA_NOISE_GATE_CONTROL, ARIZONA_NGATE_HOLD_SHIFT,
332 4, arizona_ng_hold_text);
333EXPORT_SYMBOL_GPL(arizona_ng_hold);
334
Mark Brown07ed8732012-06-18 21:08:44 +0100335int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
336 int event)
337{
338 return 0;
339}
340EXPORT_SYMBOL_GPL(arizona_in_ev);
341
342int arizona_out_ev(struct snd_soc_dapm_widget *w,
343 struct snd_kcontrol *kcontrol,
344 int event)
345{
346 return 0;
347}
348EXPORT_SYMBOL_GPL(arizona_out_ev);
349
Mark Browncbd840d2012-08-08 17:52:44 +0100350static unsigned int arizona_sysclk_48k_rates[] = {
351 6144000,
352 12288000,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000353 24576000,
Mark Browncbd840d2012-08-08 17:52:44 +0100354 49152000,
Mark Brownaeaeee12012-09-26 17:50:02 +0100355 73728000,
356 98304000,
357 147456000,
Mark Browncbd840d2012-08-08 17:52:44 +0100358};
359
360static unsigned int arizona_sysclk_44k1_rates[] = {
361 5644800,
362 11289600,
Dimitris Papastamos96e1f182012-11-15 11:41:30 +0000363 22579200,
Mark Browncbd840d2012-08-08 17:52:44 +0100364 45158400,
Mark Brownaeaeee12012-09-26 17:50:02 +0100365 67737600,
366 90316800,
367 135475200,
Mark Browncbd840d2012-08-08 17:52:44 +0100368};
369
370static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
371 unsigned int freq)
372{
373 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
374 unsigned int reg;
375 unsigned int *rates;
376 int ref, div, refclk;
377
378 switch (clk) {
379 case ARIZONA_CLK_OPCLK:
380 reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
381 refclk = priv->sysclk;
382 break;
383 case ARIZONA_CLK_ASYNC_OPCLK:
384 reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
385 refclk = priv->asyncclk;
386 break;
387 default:
388 return -EINVAL;
389 }
390
391 if (refclk % 8000)
392 rates = arizona_sysclk_44k1_rates;
393 else
394 rates = arizona_sysclk_48k_rates;
395
396 for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) &&
397 rates[ref] <= refclk; ref++) {
398 div = 1;
399 while (rates[ref] / div >= freq && div < 32) {
400 if (rates[ref] / div == freq) {
401 dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
402 freq);
403 snd_soc_update_bits(codec, reg,
404 ARIZONA_OPCLK_DIV_MASK |
405 ARIZONA_OPCLK_SEL_MASK,
406 (div <<
407 ARIZONA_OPCLK_DIV_SHIFT) |
408 ref);
409 return 0;
410 }
411 div++;
412 }
413 }
414
415 dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
416 return -EINVAL;
417}
418
Mark Brown07ed8732012-06-18 21:08:44 +0100419int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
420 int source, unsigned int freq, int dir)
421{
422 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
423 struct arizona *arizona = priv->arizona;
424 char *name;
425 unsigned int reg;
426 unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
427 unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
428 unsigned int *clk;
429
430 switch (clk_id) {
431 case ARIZONA_CLK_SYSCLK:
432 name = "SYSCLK";
433 reg = ARIZONA_SYSTEM_CLOCK_1;
434 clk = &priv->sysclk;
435 mask |= ARIZONA_SYSCLK_FRAC;
436 break;
437 case ARIZONA_CLK_ASYNCCLK:
438 name = "ASYNCCLK";
439 reg = ARIZONA_ASYNC_CLOCK_1;
440 clk = &priv->asyncclk;
441 break;
Mark Browncbd840d2012-08-08 17:52:44 +0100442 case ARIZONA_CLK_OPCLK:
443 case ARIZONA_CLK_ASYNC_OPCLK:
444 return arizona_set_opclk(codec, clk_id, freq);
Mark Brown07ed8732012-06-18 21:08:44 +0100445 default:
446 return -EINVAL;
447 }
448
449 switch (freq) {
450 case 5644800:
451 case 6144000:
452 break;
453 case 11289600:
454 case 12288000:
455 val |= 1 << ARIZONA_SYSCLK_FREQ_SHIFT;
456 break;
457 case 22579200:
458 case 24576000:
459 val |= 2 << ARIZONA_SYSCLK_FREQ_SHIFT;
460 break;
461 case 45158400:
462 case 49152000:
463 val |= 3 << ARIZONA_SYSCLK_FREQ_SHIFT;
464 break;
Mark Brown38113362012-11-26 16:01:37 +0000465 case 67737600:
466 case 73728000:
467 val |= 4 << ARIZONA_SYSCLK_FREQ_SHIFT;
468 break;
469 case 90316800:
470 case 98304000:
471 val |= 5 << ARIZONA_SYSCLK_FREQ_SHIFT;
472 break;
473 case 135475200:
474 case 147456000:
475 val |= 6 << ARIZONA_SYSCLK_FREQ_SHIFT;
476 break;
Mark Brown07ed8732012-06-18 21:08:44 +0100477 default:
478 return -EINVAL;
479 }
480
481 *clk = freq;
482
483 if (freq % 6144000)
484 val |= ARIZONA_SYSCLK_FRAC;
485
486 dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
487
488 return regmap_update_bits(arizona->regmap, reg, mask, val);
489}
490EXPORT_SYMBOL_GPL(arizona_set_sysclk);
491
492static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
493{
494 struct snd_soc_codec *codec = dai->codec;
495 int lrclk, bclk, mode, base;
496
497 base = dai->driver->base;
498
499 lrclk = 0;
500 bclk = 0;
501
502 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
503 case SND_SOC_DAIFMT_DSP_A:
504 mode = 0;
505 break;
506 case SND_SOC_DAIFMT_DSP_B:
507 mode = 1;
508 break;
509 case SND_SOC_DAIFMT_I2S:
510 mode = 2;
511 break;
512 case SND_SOC_DAIFMT_LEFT_J:
513 mode = 3;
514 break;
515 default:
516 arizona_aif_err(dai, "Unsupported DAI format %d\n",
517 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
518 return -EINVAL;
519 }
520
521 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
522 case SND_SOC_DAIFMT_CBS_CFS:
523 break;
524 case SND_SOC_DAIFMT_CBS_CFM:
525 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
526 break;
527 case SND_SOC_DAIFMT_CBM_CFS:
528 bclk |= ARIZONA_AIF1_BCLK_MSTR;
529 break;
530 case SND_SOC_DAIFMT_CBM_CFM:
531 bclk |= ARIZONA_AIF1_BCLK_MSTR;
532 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
533 break;
534 default:
535 arizona_aif_err(dai, "Unsupported master mode %d\n",
536 fmt & SND_SOC_DAIFMT_MASTER_MASK);
537 return -EINVAL;
538 }
539
540 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
541 case SND_SOC_DAIFMT_NB_NF:
542 break;
543 case SND_SOC_DAIFMT_IB_IF:
544 bclk |= ARIZONA_AIF1_BCLK_INV;
545 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
546 break;
547 case SND_SOC_DAIFMT_IB_NF:
548 bclk |= ARIZONA_AIF1_BCLK_INV;
549 break;
550 case SND_SOC_DAIFMT_NB_IF:
551 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
552 break;
553 default:
554 return -EINVAL;
555 }
556
557 snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
558 ARIZONA_AIF1_BCLK_INV | ARIZONA_AIF1_BCLK_MSTR,
559 bclk);
560 snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_PIN_CTRL,
561 ARIZONA_AIF1TX_LRCLK_INV |
562 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
563 snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_PIN_CTRL,
564 ARIZONA_AIF1RX_LRCLK_INV |
565 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
566 snd_soc_update_bits(codec, base + ARIZONA_AIF_FORMAT,
567 ARIZONA_AIF1_FMT_MASK, mode);
568
569 return 0;
570}
571
Mark Brown949e6bc2012-07-04 18:58:04 +0100572static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100573 -1,
574 48000,
575 64000,
576 96000,
577 128000,
578 192000,
579 256000,
580 384000,
581 512000,
582 768000,
583 1024000,
584 1536000,
585 2048000,
586 3072000,
587 4096000,
588 6144000,
589 8192000,
590 12288000,
591 24576000,
592};
593
Mark Brown5b2eec32012-07-04 17:32:05 +0100594static const unsigned int arizona_48k_rates[] = {
595 12000,
596 24000,
597 48000,
598 96000,
599 192000,
600 384000,
601 768000,
602 4000,
603 8000,
604 16000,
605 32000,
606 64000,
607 128000,
608 256000,
609 512000,
610};
611
612static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = {
613 .count = ARRAY_SIZE(arizona_48k_rates),
614 .list = arizona_48k_rates,
615};
616
Mark Brown949e6bc2012-07-04 18:58:04 +0100617static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100618 -1,
619 44100,
620 58800,
621 88200,
622 117600,
623 177640,
624 235200,
625 352800,
626 470400,
627 705600,
628 940800,
629 1411200,
630 1881600,
Heather Lomond4758be32012-09-05 05:02:10 -0400631 2822400,
Mark Brown07ed8732012-06-18 21:08:44 +0100632 3763200,
633 5644800,
634 7526400,
635 11289600,
636 22579200,
637};
638
Mark Brown5b2eec32012-07-04 17:32:05 +0100639static const unsigned int arizona_44k1_rates[] = {
640 11025,
641 22050,
642 44100,
643 88200,
644 176400,
645 352800,
646 705600,
647};
648
649static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = {
650 .count = ARRAY_SIZE(arizona_44k1_rates),
651 .list = arizona_44k1_rates,
652};
653
Mark Brown07ed8732012-06-18 21:08:44 +0100654static int arizona_sr_vals[] = {
655 0,
656 12000,
657 24000,
658 48000,
659 96000,
660 192000,
661 384000,
662 768000,
663 0,
664 11025,
665 22050,
666 44100,
667 88200,
668 176400,
669 352800,
670 705600,
671 4000,
672 8000,
673 16000,
674 32000,
675 64000,
676 128000,
677 256000,
678 512000,
679};
680
Mark Brown5b2eec32012-07-04 17:32:05 +0100681static int arizona_startup(struct snd_pcm_substream *substream,
682 struct snd_soc_dai *dai)
683{
684 struct snd_soc_codec *codec = dai->codec;
685 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
686 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
687 const struct snd_pcm_hw_constraint_list *constraint;
688 unsigned int base_rate;
689
690 switch (dai_priv->clk) {
691 case ARIZONA_CLK_SYSCLK:
692 base_rate = priv->sysclk;
693 break;
694 case ARIZONA_CLK_ASYNCCLK:
695 base_rate = priv->asyncclk;
696 break;
697 default:
698 return 0;
699 }
700
701 if (base_rate % 8000)
702 constraint = &arizona_44k1_constraint;
703 else
704 constraint = &arizona_48k_constraint;
705
706 return snd_pcm_hw_constraint_list(substream->runtime, 0,
707 SNDRV_PCM_HW_PARAM_RATE,
708 constraint);
709}
710
Mark Brown07ed8732012-06-18 21:08:44 +0100711static int arizona_hw_params(struct snd_pcm_substream *substream,
712 struct snd_pcm_hw_params *params,
713 struct snd_soc_dai *dai)
714{
715 struct snd_soc_codec *codec = dai->codec;
Mark Brownc013b272012-07-04 20:05:57 +0100716 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
717 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown07ed8732012-06-18 21:08:44 +0100718 int base = dai->driver->base;
719 const int *rates;
720 int i;
721 int bclk, lrclk, wl, frame, sr_val;
722
723 if (params_rate(params) % 8000)
Mark Brown949e6bc2012-07-04 18:58:04 +0100724 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +0100725 else
Mark Brown949e6bc2012-07-04 18:58:04 +0100726 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +0100727
Mark Brown949e6bc2012-07-04 18:58:04 +0100728 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brown50017652012-07-04 19:07:09 +0100729 if (rates[i] >= snd_soc_params_to_bclk(params) &&
730 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +0100731 bclk = i;
732 break;
733 }
734 }
Mark Brown949e6bc2012-07-04 18:58:04 +0100735 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +0100736 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
737 params_rate(params));
738 return -EINVAL;
739 }
740
Mark Brown07ed8732012-06-18 21:08:44 +0100741 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
742 if (arizona_sr_vals[i] == params_rate(params))
743 break;
744 if (i == ARRAY_SIZE(arizona_sr_vals)) {
745 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
746 params_rate(params));
747 return -EINVAL;
748 }
749 sr_val = i;
750
751 lrclk = snd_soc_params_to_bclk(params) / params_rate(params);
752
753 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
754 rates[bclk], rates[bclk] / lrclk);
755
756 wl = snd_pcm_format_width(params_format(params));
757 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl;
758
Mark Brownc013b272012-07-04 20:05:57 +0100759 /*
760 * We will need to be more flexible than this in future,
761 * currently we use a single sample rate for SYSCLK.
762 */
763 switch (dai_priv->clk) {
764 case ARIZONA_CLK_SYSCLK:
765 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
766 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
767 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
768 ARIZONA_AIF1_RATE_MASK, 0);
769 break;
770 case ARIZONA_CLK_ASYNCCLK:
771 snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
772 ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val);
773 snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
774 ARIZONA_AIF1_RATE_MASK, 8);
775 break;
776 default:
777 arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
778 return -EINVAL;
779 }
780
Mark Brown07ed8732012-06-18 21:08:44 +0100781 snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
782 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
783 snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_BCLK_RATE,
784 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
785 snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_BCLK_RATE,
786 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
787 snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_1,
788 ARIZONA_AIF1TX_WL_MASK |
789 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
790 snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_2,
791 ARIZONA_AIF1RX_WL_MASK |
792 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
793
794 return 0;
795}
796
Mark Brown410837a2012-07-05 17:26:59 +0100797static const char *arizona_dai_clk_str(int clk_id)
798{
799 switch (clk_id) {
800 case ARIZONA_CLK_SYSCLK:
801 return "SYSCLK";
802 case ARIZONA_CLK_ASYNCCLK:
803 return "ASYNCCLK";
804 default:
805 return "Unknown clock";
806 }
807}
808
Mark Brown5b2eec32012-07-04 17:32:05 +0100809static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
810 int clk_id, unsigned int freq, int dir)
811{
812 struct snd_soc_codec *codec = dai->codec;
813 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
814 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
Mark Brown410837a2012-07-05 17:26:59 +0100815 struct snd_soc_dapm_route routes[2];
Mark Brown5b2eec32012-07-04 17:32:05 +0100816
817 switch (clk_id) {
818 case ARIZONA_CLK_SYSCLK:
819 case ARIZONA_CLK_ASYNCCLK:
820 break;
821 default:
822 return -EINVAL;
823 }
824
Mark Brown410837a2012-07-05 17:26:59 +0100825 if (clk_id == dai_priv->clk)
826 return 0;
827
828 if (dai->active) {
Mark Brown5b2eec32012-07-04 17:32:05 +0100829 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
830 dai->id);
831 return -EBUSY;
832 }
833
Mark Brownc8d35a62012-12-07 12:49:40 +0900834 dev_dbg(codec->dev, "Setting AIF%d to %s\n", dai->id + 1,
835 arizona_dai_clk_str(clk_id));
836
Mark Brown410837a2012-07-05 17:26:59 +0100837 memset(&routes, 0, sizeof(routes));
838 routes[0].sink = dai->driver->capture.stream_name;
839 routes[1].sink = dai->driver->playback.stream_name;
Mark Brown5b2eec32012-07-04 17:32:05 +0100840
Mark Brown410837a2012-07-05 17:26:59 +0100841 routes[0].source = arizona_dai_clk_str(dai_priv->clk);
842 routes[1].source = arizona_dai_clk_str(dai_priv->clk);
843 snd_soc_dapm_del_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
844
845 routes[0].source = arizona_dai_clk_str(clk_id);
846 routes[1].source = arizona_dai_clk_str(clk_id);
847 snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes));
848
Mark Brown0c778e82012-12-06 18:22:25 +0900849 dai_priv->clk = clk_id;
850
Mark Brown410837a2012-07-05 17:26:59 +0100851 return snd_soc_dapm_sync(&codec->dapm);
Mark Brown5b2eec32012-07-04 17:32:05 +0100852}
853
Mark Brown01df2592012-12-12 16:22:08 +0900854static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
855{
856 struct snd_soc_codec *codec = dai->codec;
857 int base = dai->driver->base;
858 unsigned int reg;
859
860 if (tristate)
861 reg = ARIZONA_AIF1_TRI;
862 else
863 reg = 0;
864
865 return snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
866 ARIZONA_AIF1_TRI, reg);
867}
868
Mark Brown07ed8732012-06-18 21:08:44 +0100869const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +0100870 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +0100871 .set_fmt = arizona_set_fmt,
872 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +0100873 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown01df2592012-12-12 16:22:08 +0900874 .set_tristate = arizona_set_tristate,
Mark Brown07ed8732012-06-18 21:08:44 +0100875};
Mark Browna8379872012-07-09 12:16:41 +0100876EXPORT_SYMBOL_GPL(arizona_dai_ops);
Mark Brown07ed8732012-06-18 21:08:44 +0100877
Mark Brown5b2eec32012-07-04 17:32:05 +0100878int arizona_init_dai(struct arizona_priv *priv, int id)
879{
880 struct arizona_dai_priv *dai_priv = &priv->dai[id];
881
882 dai_priv->clk = ARIZONA_CLK_SYSCLK;
883
884 return 0;
885}
886EXPORT_SYMBOL_GPL(arizona_init_dai);
887
Mark Brown07ed8732012-06-18 21:08:44 +0100888static irqreturn_t arizona_fll_lock(int irq, void *data)
889{
890 struct arizona_fll *fll = data;
891
Mark Brown6b315952012-09-12 18:44:40 +0800892 arizona_fll_dbg(fll, "Lock status changed\n");
Mark Brown07ed8732012-06-18 21:08:44 +0100893
894 complete(&fll->lock);
895
896 return IRQ_HANDLED;
897}
898
899static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
900{
901 struct arizona_fll *fll = data;
902
903 arizona_fll_dbg(fll, "clock OK\n");
904
905 complete(&fll->ok);
906
907 return IRQ_HANDLED;
908}
909
910static struct {
911 unsigned int min;
912 unsigned int max;
913 u16 fratio;
914 int ratio;
915} fll_fratios[] = {
916 { 0, 64000, 4, 16 },
917 { 64000, 128000, 3, 8 },
918 { 128000, 256000, 2, 4 },
919 { 256000, 1000000, 1, 2 },
920 { 1000000, 13500000, 0, 1 },
921};
922
923struct arizona_fll_cfg {
924 int n;
925 int theta;
926 int lambda;
927 int refdiv;
928 int outdiv;
929 int fratio;
930};
931
932static int arizona_calc_fll(struct arizona_fll *fll,
933 struct arizona_fll_cfg *cfg,
934 unsigned int Fref,
935 unsigned int Fout)
936{
937 unsigned int target, div, gcd_fll;
938 int i, ratio;
939
940 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout);
941
942 /* Fref must be <=13.5MHz */
943 div = 1;
944 cfg->refdiv = 0;
945 while ((Fref / div) > 13500000) {
946 div *= 2;
947 cfg->refdiv++;
948
949 if (div > 8) {
950 arizona_fll_err(fll,
951 "Can't scale %dMHz in to <=13.5MHz\n",
952 Fref);
953 return -EINVAL;
954 }
955 }
956
957 /* Apply the division for our remaining calculations */
958 Fref /= div;
959
Mark Brown2b4d39f2012-07-10 17:03:46 +0100960 /* Fvco should be over the targt; don't check the upper bound */
Mark Brown07ed8732012-06-18 21:08:44 +0100961 div = 1;
Mark Brown2b4d39f2012-07-10 17:03:46 +0100962 while (Fout * div < 90000000 * fll->vco_mult) {
Mark Brown07ed8732012-06-18 21:08:44 +0100963 div++;
964 if (div > 7) {
965 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
966 Fout);
967 return -EINVAL;
968 }
969 }
Mark Brown2b4d39f2012-07-10 17:03:46 +0100970 target = Fout * div / fll->vco_mult;
Mark Brown07ed8732012-06-18 21:08:44 +0100971 cfg->outdiv = div;
972
973 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
974
975 /* Find an appropraite FLL_FRATIO and factor it out of the target */
976 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
977 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
978 cfg->fratio = fll_fratios[i].fratio;
979 ratio = fll_fratios[i].ratio;
980 break;
981 }
982 }
983 if (i == ARRAY_SIZE(fll_fratios)) {
984 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
985 Fref);
986 return -EINVAL;
987 }
988
989 cfg->n = target / (ratio * Fref);
990
991 if (target % Fref) {
992 gcd_fll = gcd(target, ratio * Fref);
993 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
994
995 cfg->theta = (target - (cfg->n * ratio * Fref))
996 / gcd_fll;
997 cfg->lambda = (ratio * Fref) / gcd_fll;
998 } else {
999 cfg->theta = 0;
1000 cfg->lambda = 0;
1001 }
1002
1003 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
1004 cfg->n, cfg->theta, cfg->lambda);
1005 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
1006 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
1007
1008 return 0;
1009
1010}
1011
1012static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
1013 struct arizona_fll_cfg *cfg, int source)
1014{
1015 regmap_update_bits(arizona->regmap, base + 3,
1016 ARIZONA_FLL1_THETA_MASK, cfg->theta);
1017 regmap_update_bits(arizona->regmap, base + 4,
1018 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
1019 regmap_update_bits(arizona->regmap, base + 5,
1020 ARIZONA_FLL1_FRATIO_MASK,
1021 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
1022 regmap_update_bits(arizona->regmap, base + 6,
1023 ARIZONA_FLL1_CLK_REF_DIV_MASK |
1024 ARIZONA_FLL1_CLK_REF_SRC_MASK,
1025 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
1026 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
1027
1028 regmap_update_bits(arizona->regmap, base + 2,
1029 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
1030 ARIZONA_FLL1_CTRL_UPD | cfg->n);
1031}
1032
1033int arizona_set_fll(struct arizona_fll *fll, int source,
1034 unsigned int Fref, unsigned int Fout)
1035{
1036 struct arizona *arizona = fll->arizona;
1037 struct arizona_fll_cfg cfg, sync;
1038 unsigned int reg, val;
1039 int syncsrc;
1040 bool ena;
1041 int ret;
1042
Mark Brown1cbe4bc2012-11-21 14:12:22 +09001043 if (fll->fref == Fref && fll->fout == Fout)
1044 return 0;
1045
Mark Brown07ed8732012-06-18 21:08:44 +01001046 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
1047 if (ret != 0) {
1048 arizona_fll_err(fll, "Failed to read current state: %d\n",
1049 ret);
1050 return ret;
1051 }
1052 ena = reg & ARIZONA_FLL1_ENA;
1053
1054 if (Fout) {
1055 /* Do we have a 32kHz reference? */
1056 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
1057 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
1058 case ARIZONA_CLK_SRC_MCLK1:
1059 case ARIZONA_CLK_SRC_MCLK2:
1060 syncsrc = val & ARIZONA_CLK_32K_SRC_MASK;
1061 break;
1062 default:
1063 syncsrc = -1;
1064 }
1065
1066 if (source == syncsrc)
1067 syncsrc = -1;
1068
1069 if (syncsrc >= 0) {
1070 ret = arizona_calc_fll(fll, &sync, Fref, Fout);
1071 if (ret != 0)
1072 return ret;
1073
1074 ret = arizona_calc_fll(fll, &cfg, 32768, Fout);
1075 if (ret != 0)
1076 return ret;
1077 } else {
1078 ret = arizona_calc_fll(fll, &cfg, Fref, Fout);
1079 if (ret != 0)
1080 return ret;
1081 }
1082 } else {
1083 regmap_update_bits(arizona->regmap, fll->base + 1,
1084 ARIZONA_FLL1_ENA, 0);
1085 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1086 ARIZONA_FLL1_SYNC_ENA, 0);
1087
1088 if (ena)
1089 pm_runtime_put_autosuspend(arizona->dev);
1090
Mark Brown50fcfe42012-11-28 11:50:34 +00001091 fll->fref = Fref;
1092 fll->fout = Fout;
1093
Mark Brown07ed8732012-06-18 21:08:44 +01001094 return 0;
1095 }
1096
1097 regmap_update_bits(arizona->regmap, fll->base + 5,
1098 ARIZONA_FLL1_OUTDIV_MASK,
1099 cfg.outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
1100
1101 if (syncsrc >= 0) {
1102 arizona_apply_fll(arizona, fll->base, &cfg, syncsrc);
1103 arizona_apply_fll(arizona, fll->base + 0x10, &sync, source);
1104 } else {
1105 arizona_apply_fll(arizona, fll->base, &cfg, source);
1106 }
1107
1108 if (!ena)
1109 pm_runtime_get(arizona->dev);
1110
1111 /* Clear any pending completions */
1112 try_wait_for_completion(&fll->ok);
1113
1114 regmap_update_bits(arizona->regmap, fll->base + 1,
1115 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
1116 if (syncsrc >= 0)
1117 regmap_update_bits(arizona->regmap, fll->base + 0x11,
1118 ARIZONA_FLL1_SYNC_ENA,
1119 ARIZONA_FLL1_SYNC_ENA);
1120
1121 ret = wait_for_completion_timeout(&fll->ok,
Mark Brown09871a92012-12-06 15:29:34 +09001122 msecs_to_jiffies(250));
Mark Brown07ed8732012-06-18 21:08:44 +01001123 if (ret == 0)
1124 arizona_fll_warn(fll, "Timed out waiting for lock\n");
1125
Mark Brown1cbe4bc2012-11-21 14:12:22 +09001126 fll->fref = Fref;
1127 fll->fout = Fout;
1128
Mark Brown07ed8732012-06-18 21:08:44 +01001129 return 0;
1130}
1131EXPORT_SYMBOL_GPL(arizona_set_fll);
1132
1133int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
1134 int ok_irq, struct arizona_fll *fll)
1135{
1136 int ret;
1137
1138 init_completion(&fll->lock);
1139 init_completion(&fll->ok);
1140
1141 fll->id = id;
1142 fll->base = base;
1143 fll->arizona = arizona;
1144
1145 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
1146 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
1147 "FLL%d clock OK", id);
1148
1149 ret = arizona_request_irq(arizona, lock_irq, fll->lock_name,
1150 arizona_fll_lock, fll);
1151 if (ret != 0) {
1152 dev_err(arizona->dev, "Failed to get FLL%d lock IRQ: %d\n",
1153 id, ret);
1154 }
1155
1156 ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
1157 arizona_fll_clock_ok, fll);
1158 if (ret != 0) {
1159 dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
1160 id, ret);
1161 }
1162
1163 return 0;
1164}
1165EXPORT_SYMBOL_GPL(arizona_init_fll);
1166
Mark Brownbc9ab6d2013-01-04 19:31:00 +00001167/**
1168 * arizona_set_output_mode - Set the mode of the specified output
1169 *
1170 * @codec: Device to configure
1171 * @output: Output number
1172 * @diff: True to set the output to differential mode
1173 *
1174 * Some systems use external analogue switches to connect more
1175 * analogue devices to the CODEC than are supported by the device. In
1176 * some systems this requires changing the switched output from single
1177 * ended to differential mode dynamically at runtime, an operation
1178 * supported using this function.
1179 *
1180 * Most systems have a single static configuration and should use
1181 * platform data instead.
1182 */
1183int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff)
1184{
1185 unsigned int reg, val;
1186
1187 if (output < 1 || output > 6)
1188 return -EINVAL;
1189
1190 reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
1191
1192 if (diff)
1193 val = ARIZONA_OUT1_MONO;
1194 else
1195 val = 0;
1196
1197 return snd_soc_update_bits(codec, reg, ARIZONA_OUT1_MONO, val);
1198}
1199EXPORT_SYMBOL_GPL(arizona_set_output_mode);
1200
Mark Brown07ed8732012-06-18 21:08:44 +01001201MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
1202MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1203MODULE_LICENSE("GPL");