ASoC: adau17x1: Mark DSP parameter memory as readable and precious
[deliverable/linux.git] / sound / soc / codecs / adau17x1.c
CommitLineData
4101866c
LPC
1/*
2 * Common code for ADAU1X61 and ADAU1X81 codecs
3 *
4 * Copyright 2011-2014 Analog Devices Inc.
5 * Author: Lars-Peter Clausen <lars@metafoo.de>
6 *
7 * Licensed under the GPL-2 or later.
8 */
9
10#include <linux/module.h>
11#include <linux/init.h>
12#include <linux/delay.h>
13#include <linux/slab.h>
14#include <sound/core.h>
15#include <sound/pcm.h>
16#include <sound/pcm_params.h>
17#include <sound/soc.h>
18#include <sound/tlv.h>
19#include <linux/gcd.h>
20#include <linux/i2c.h>
21#include <linux/spi/spi.h>
22#include <linux/regmap.h>
23
24#include "sigmadsp.h"
25#include "adau17x1.h"
26
27static const char * const adau17x1_capture_mixer_boost_text[] = {
28 "Normal operation", "Boost Level 1", "Boost Level 2", "Boost Level 3",
29};
30
31static SOC_ENUM_SINGLE_DECL(adau17x1_capture_boost_enum,
32 ADAU17X1_REC_POWER_MGMT, 5, adau17x1_capture_mixer_boost_text);
33
34static const char * const adau17x1_mic_bias_mode_text[] = {
35 "Normal operation", "High performance",
36};
37
38static SOC_ENUM_SINGLE_DECL(adau17x1_mic_bias_mode_enum,
39 ADAU17X1_MICBIAS, 3, adau17x1_mic_bias_mode_text);
40
41static const DECLARE_TLV_DB_MINMAX(adau17x1_digital_tlv, -9563, 0);
42
43static const struct snd_kcontrol_new adau17x1_controls[] = {
44 SOC_DOUBLE_R_TLV("Digital Capture Volume",
45 ADAU17X1_LEFT_INPUT_DIGITAL_VOL,
46 ADAU17X1_RIGHT_INPUT_DIGITAL_VOL,
47 0, 0xff, 1, adau17x1_digital_tlv),
48 SOC_DOUBLE_R_TLV("Digital Playback Volume", ADAU17X1_DAC_CONTROL1,
49 ADAU17X1_DAC_CONTROL2, 0, 0xff, 1, adau17x1_digital_tlv),
50
51 SOC_SINGLE("ADC High Pass Filter Switch", ADAU17X1_ADC_CONTROL,
52 5, 1, 0),
53 SOC_SINGLE("Playback De-emphasis Switch", ADAU17X1_DAC_CONTROL0,
54 2, 1, 0),
55
56 SOC_ENUM("Capture Boost", adau17x1_capture_boost_enum),
57
58 SOC_ENUM("Mic Bias Mode", adau17x1_mic_bias_mode_enum),
59};
60
61static int adau17x1_pll_event(struct snd_soc_dapm_widget *w,
62 struct snd_kcontrol *kcontrol, int event)
63{
64 struct adau *adau = snd_soc_codec_get_drvdata(w->codec);
65 int ret;
66
67 if (SND_SOC_DAPM_EVENT_ON(event)) {
68 adau->pll_regs[5] = 1;
69 } else {
70 adau->pll_regs[5] = 0;
71 /* Bypass the PLL when disabled, otherwise registers will become
72 * inaccessible. */
73 regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
74 ADAU17X1_CLOCK_CONTROL_CORECLK_SRC_PLL, 0);
75 }
76
77 /* The PLL register is 6 bytes long and can only be written at once. */
78 ret = regmap_raw_write(adau->regmap, ADAU17X1_PLL_CONTROL,
79 adau->pll_regs, ARRAY_SIZE(adau->pll_regs));
80
81 if (SND_SOC_DAPM_EVENT_ON(event)) {
82 mdelay(5);
83 regmap_update_bits(adau->regmap, ADAU17X1_CLOCK_CONTROL,
84 ADAU17X1_CLOCK_CONTROL_CORECLK_SRC_PLL,
85 ADAU17X1_CLOCK_CONTROL_CORECLK_SRC_PLL);
86 }
87
88 return 0;
89}
90
91static const char * const adau17x1_mono_stereo_text[] = {
92 "Stereo",
93 "Mono Left Channel (L+R)",
94 "Mono Right Channel (L+R)",
95 "Mono (L+R)",
96};
97
98static SOC_ENUM_SINGLE_DECL(adau17x1_dac_mode_enum,
99 ADAU17X1_DAC_CONTROL0, 6, adau17x1_mono_stereo_text);
100
101static const struct snd_kcontrol_new adau17x1_dac_mode_mux =
102 SOC_DAPM_ENUM("DAC Mono-Stereo-Mode", adau17x1_dac_mode_enum);
103
104static const struct snd_soc_dapm_widget adau17x1_dapm_widgets[] = {
105 SND_SOC_DAPM_SUPPLY_S("PLL", 3, SND_SOC_NOPM, 0, 0, adau17x1_pll_event,
106 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
107
108 SND_SOC_DAPM_SUPPLY("AIFCLK", SND_SOC_NOPM, 0, 0, NULL, 0),
109
110 SND_SOC_DAPM_SUPPLY("MICBIAS", ADAU17X1_MICBIAS, 0, 0, NULL, 0),
111
112 SND_SOC_DAPM_SUPPLY("Left Playback Enable", ADAU17X1_PLAY_POWER_MGMT,
113 0, 0, NULL, 0),
114 SND_SOC_DAPM_SUPPLY("Right Playback Enable", ADAU17X1_PLAY_POWER_MGMT,
115 1, 0, NULL, 0),
116
117 SND_SOC_DAPM_MUX("Left DAC Mode Mux", SND_SOC_NOPM, 0, 0,
118 &adau17x1_dac_mode_mux),
119 SND_SOC_DAPM_MUX("Right DAC Mode Mux", SND_SOC_NOPM, 0, 0,
120 &adau17x1_dac_mode_mux),
121
122 SND_SOC_DAPM_ADC("Left Decimator", NULL, ADAU17X1_ADC_CONTROL, 0, 0),
123 SND_SOC_DAPM_ADC("Right Decimator", NULL, ADAU17X1_ADC_CONTROL, 1, 0),
124 SND_SOC_DAPM_DAC("Left DAC", NULL, ADAU17X1_DAC_CONTROL0, 0, 0),
125 SND_SOC_DAPM_DAC("Right DAC", NULL, ADAU17X1_DAC_CONTROL0, 1, 0),
126};
127
128static const struct snd_soc_dapm_route adau17x1_dapm_routes[] = {
129 { "Left Decimator", NULL, "SYSCLK" },
130 { "Right Decimator", NULL, "SYSCLK" },
131 { "Left DAC", NULL, "SYSCLK" },
132 { "Right DAC", NULL, "SYSCLK" },
133 { "Capture", NULL, "SYSCLK" },
134 { "Playback", NULL, "SYSCLK" },
135
136 { "Left DAC", NULL, "Left DAC Mode Mux" },
137 { "Right DAC", NULL, "Right DAC Mode Mux" },
138
139 { "Capture", NULL, "AIFCLK" },
140 { "Playback", NULL, "AIFCLK" },
141};
142
143static const struct snd_soc_dapm_route adau17x1_dapm_pll_route = {
144 "SYSCLK", NULL, "PLL",
145};
146
147/*
148 * The MUX register for the Capture and Playback MUXs selects either DSP as
149 * source/destination or one of the TDM slots. The TDM slot is selected via
150 * snd_soc_dai_set_tdm_slot(), so we only expose whether to go to the DSP or
151 * directly to the DAI interface with this control.
152 */
153static int adau17x1_dsp_mux_enum_put(struct snd_kcontrol *kcontrol,
154 struct snd_ctl_elem_value *ucontrol)
155{
156 struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
157 struct adau *adau = snd_soc_codec_get_drvdata(codec);
158 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
159 struct snd_soc_dapm_update update;
160 unsigned int stream = e->shift_l;
161 unsigned int val, change;
162 int reg;
163
164 if (ucontrol->value.enumerated.item[0] >= e->items)
165 return -EINVAL;
166
167 switch (ucontrol->value.enumerated.item[0]) {
168 case 0:
169 val = 0;
170 adau->dsp_bypass[stream] = false;
171 break;
172 default:
173 val = (adau->tdm_slot[stream] * 2) + 1;
174 adau->dsp_bypass[stream] = true;
175 break;
176 }
177
178 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
179 reg = ADAU17X1_SERIAL_INPUT_ROUTE;
180 else
181 reg = ADAU17X1_SERIAL_OUTPUT_ROUTE;
182
183 change = snd_soc_test_bits(codec, reg, 0xff, val);
184 if (change) {
185 update.kcontrol = kcontrol;
186 update.mask = 0xff;
187 update.reg = reg;
188 update.val = val;
189
190 snd_soc_dapm_mux_update_power(&codec->dapm, kcontrol,
191 ucontrol->value.enumerated.item[0], e, &update);
192 }
193
194 return change;
195}
196
197static int adau17x1_dsp_mux_enum_get(struct snd_kcontrol *kcontrol,
198 struct snd_ctl_elem_value *ucontrol)
199{
200 struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
201 struct adau *adau = snd_soc_codec_get_drvdata(codec);
202 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
203 unsigned int stream = e->shift_l;
204 unsigned int reg, val;
205 int ret;
206
207 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
208 reg = ADAU17X1_SERIAL_INPUT_ROUTE;
209 else
210 reg = ADAU17X1_SERIAL_OUTPUT_ROUTE;
211
212 ret = regmap_read(adau->regmap, reg, &val);
213 if (ret)
214 return ret;
215
216 if (val != 0)
217 val = 1;
218 ucontrol->value.enumerated.item[0] = val;
219
220 return 0;
221}
222
223#define DECLARE_ADAU17X1_DSP_MUX_CTRL(_name, _label, _stream, _text) \
224 const struct snd_kcontrol_new _name = \
225 SOC_DAPM_ENUM_EXT(_label, (const struct soc_enum)\
226 SOC_ENUM_SINGLE(SND_SOC_NOPM, _stream, \
227 ARRAY_SIZE(_text), _text), \
228 adau17x1_dsp_mux_enum_get, adau17x1_dsp_mux_enum_put)
229
230static const char * const adau17x1_dac_mux_text[] = {
231 "DSP",
232 "AIFIN",
233};
234
235static const char * const adau17x1_capture_mux_text[] = {
236 "DSP",
237 "Decimator",
238};
239
240static DECLARE_ADAU17X1_DSP_MUX_CTRL(adau17x1_dac_mux, "DAC Playback Mux",
241 SNDRV_PCM_STREAM_PLAYBACK, adau17x1_dac_mux_text);
242
243static DECLARE_ADAU17X1_DSP_MUX_CTRL(adau17x1_capture_mux, "Capture Mux",
244 SNDRV_PCM_STREAM_CAPTURE, adau17x1_capture_mux_text);
245
246static const struct snd_soc_dapm_widget adau17x1_dsp_dapm_widgets[] = {
247 SND_SOC_DAPM_PGA("DSP", ADAU17X1_DSP_RUN, 0, 0, NULL, 0),
248 SND_SOC_DAPM_SIGGEN("DSP Siggen"),
249
250 SND_SOC_DAPM_MUX("DAC Playback Mux", SND_SOC_NOPM, 0, 0,
251 &adau17x1_dac_mux),
252 SND_SOC_DAPM_MUX("Capture Mux", SND_SOC_NOPM, 0, 0,
253 &adau17x1_capture_mux),
254};
255
256static const struct snd_soc_dapm_route adau17x1_dsp_dapm_routes[] = {
257 { "DAC Playback Mux", "DSP", "DSP" },
258 { "DAC Playback Mux", "AIFIN", "Playback" },
259
260 { "Left DAC Mode Mux", "Stereo", "DAC Playback Mux" },
261 { "Left DAC Mode Mux", "Mono (L+R)", "DAC Playback Mux" },
262 { "Left DAC Mode Mux", "Mono Left Channel (L+R)", "DAC Playback Mux" },
263 { "Right DAC Mode Mux", "Stereo", "DAC Playback Mux" },
264 { "Right DAC Mode Mux", "Mono (L+R)", "DAC Playback Mux" },
265 { "Right DAC Mode Mux", "Mono Right Channel (L+R)", "DAC Playback Mux" },
266
267 { "Capture Mux", "DSP", "DSP" },
268 { "Capture Mux", "Decimator", "Left Decimator" },
269 { "Capture Mux", "Decimator", "Right Decimator" },
270
271 { "Capture", NULL, "Capture Mux" },
272
273 { "DSP", NULL, "DSP Siggen" },
274
275 { "DSP", NULL, "Left Decimator" },
276 { "DSP", NULL, "Right Decimator" },
277};
278
279static const struct snd_soc_dapm_route adau17x1_no_dsp_dapm_routes[] = {
280 { "Left DAC Mode Mux", "Stereo", "Playback" },
281 { "Left DAC Mode Mux", "Mono (L+R)", "Playback" },
282 { "Left DAC Mode Mux", "Mono Left Channel (L+R)", "Playback" },
283 { "Right DAC Mode Mux", "Stereo", "Playback" },
284 { "Right DAC Mode Mux", "Mono (L+R)", "Playback" },
285 { "Right DAC Mode Mux", "Mono Right Channel (L+R)", "Playback" },
286 { "Capture", NULL, "Left Decimator" },
287 { "Capture", NULL, "Right Decimator" },
288};
289
290bool adau17x1_has_dsp(struct adau *adau)
291{
292 switch (adau->type) {
293 case ADAU1761:
294 case ADAU1381:
295 case ADAU1781:
296 return true;
297 default:
298 return false;
299 }
300}
301EXPORT_SYMBOL_GPL(adau17x1_has_dsp);
302
303static int adau17x1_hw_params(struct snd_pcm_substream *substream,
304 struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
305{
306 struct snd_soc_codec *codec = dai->codec;
307 struct adau *adau = snd_soc_codec_get_drvdata(codec);
308 unsigned int val, div, dsp_div;
309 unsigned int freq;
d48b088e 310 int ret;
4101866c
LPC
311
312 if (adau->clk_src == ADAU17X1_CLK_SRC_PLL)
313 freq = adau->pll_freq;
314 else
315 freq = adau->sysclk;
316
317 if (freq % params_rate(params) != 0)
318 return -EINVAL;
319
320 switch (freq / params_rate(params)) {
321 case 1024: /* fs */
322 div = 0;
323 dsp_div = 1;
324 break;
325 case 6144: /* fs / 6 */
326 div = 1;
327 dsp_div = 6;
328 break;
329 case 4096: /* fs / 4 */
330 div = 2;
331 dsp_div = 5;
332 break;
333 case 3072: /* fs / 3 */
334 div = 3;
335 dsp_div = 4;
336 break;
337 case 2048: /* fs / 2 */
338 div = 4;
339 dsp_div = 3;
340 break;
341 case 1536: /* fs / 1.5 */
342 div = 5;
343 dsp_div = 2;
344 break;
345 case 512: /* fs / 0.5 */
346 div = 6;
347 dsp_div = 0;
348 break;
349 default:
350 return -EINVAL;
351 }
352
353 regmap_update_bits(adau->regmap, ADAU17X1_CONVERTER0,
354 ADAU17X1_CONVERTER0_CONVSR_MASK, div);
355 if (adau17x1_has_dsp(adau)) {
356 regmap_write(adau->regmap, ADAU17X1_SERIAL_SAMPLING_RATE, div);
357 regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, dsp_div);
358 }
359
d48b088e
LPC
360 if (adau->sigmadsp) {
361 ret = adau17x1_setup_firmware(adau, params_rate(params));
362 if (ret < 0)
363 return ret;
364 }
365
4101866c
LPC
366 if (adau->dai_fmt != SND_SOC_DAIFMT_RIGHT_J)
367 return 0;
368
d2a9b1c1
MB
369 switch (params_width(params)) {
370 case 16:
4101866c
LPC
371 val = ADAU17X1_SERIAL_PORT1_DELAY16;
372 break;
d2a9b1c1 373 case 24:
4101866c
LPC
374 val = ADAU17X1_SERIAL_PORT1_DELAY8;
375 break;
d2a9b1c1 376 case 32:
4101866c
LPC
377 val = ADAU17X1_SERIAL_PORT1_DELAY0;
378 break;
379 default:
380 return -EINVAL;
381 }
382
383 return regmap_update_bits(adau->regmap, ADAU17X1_SERIAL_PORT1,
384 ADAU17X1_SERIAL_PORT1_DELAY_MASK, val);
385}
386
387static int adau17x1_set_dai_pll(struct snd_soc_dai *dai, int pll_id,
388 int source, unsigned int freq_in, unsigned int freq_out)
389{
390 struct snd_soc_codec *codec = dai->codec;
391 struct adau *adau = snd_soc_codec_get_drvdata(codec);
392 unsigned int r, n, m, i, j;
393 unsigned int div;
394 int ret;
395
396 if (freq_in < 8000000 || freq_in > 27000000)
397 return -EINVAL;
398
399 if (!freq_out) {
400 r = 0;
401 n = 0;
402 m = 0;
403 div = 0;
404 } else {
405 if (freq_out % freq_in != 0) {
406 div = DIV_ROUND_UP(freq_in, 13500000);
407 freq_in /= div;
408 r = freq_out / freq_in;
409 i = freq_out % freq_in;
410 j = gcd(i, freq_in);
411 n = i / j;
412 m = freq_in / j;
413 div--;
414 } else {
415 r = freq_out / freq_in;
416 n = 0;
417 m = 0;
418 div = 0;
419 }
420 if (n > 0xffff || m > 0xffff || div > 3 || r > 8 || r < 2)
421 return -EINVAL;
422 }
423
424 adau->pll_regs[0] = m >> 8;
425 adau->pll_regs[1] = m & 0xff;
426 adau->pll_regs[2] = n >> 8;
427 adau->pll_regs[3] = n & 0xff;
428 adau->pll_regs[4] = (r << 3) | (div << 1);
429 if (m != 0)
430 adau->pll_regs[4] |= 1; /* Fractional mode */
431
432 /* The PLL register is 6 bytes long and can only be written at once. */
433 ret = regmap_raw_write(adau->regmap, ADAU17X1_PLL_CONTROL,
434 adau->pll_regs, ARRAY_SIZE(adau->pll_regs));
435 if (ret)
436 return ret;
437
438 adau->pll_freq = freq_out;
439
440 return 0;
441}
442
443static int adau17x1_set_dai_sysclk(struct snd_soc_dai *dai,
444 int clk_id, unsigned int freq, int dir)
445{
446 struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);
447 struct snd_soc_dapm_context *dapm = &dai->codec->dapm;
448
449 switch (clk_id) {
450 case ADAU17X1_CLK_SRC_MCLK:
451 case ADAU17X1_CLK_SRC_PLL:
452 break;
453 default:
454 return -EINVAL;
455 }
456
457 adau->sysclk = freq;
458
459 if (adau->clk_src != clk_id) {
460 if (clk_id == ADAU17X1_CLK_SRC_PLL) {
461 snd_soc_dapm_add_routes(dapm,
462 &adau17x1_dapm_pll_route, 1);
463 } else {
464 snd_soc_dapm_del_routes(dapm,
465 &adau17x1_dapm_pll_route, 1);
466 }
467 }
468
469 adau->clk_src = clk_id;
470
471 return 0;
472}
473
474static int adau17x1_set_dai_fmt(struct snd_soc_dai *dai,
475 unsigned int fmt)
476{
477 struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);
478 unsigned int ctrl0, ctrl1;
479 int lrclk_pol;
480
481 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
482 case SND_SOC_DAIFMT_CBM_CFM:
483 ctrl0 = ADAU17X1_SERIAL_PORT0_MASTER;
484 adau->master = true;
485 break;
486 case SND_SOC_DAIFMT_CBS_CFS:
487 ctrl0 = 0;
488 adau->master = false;
489 break;
490 default:
491 return -EINVAL;
492 }
493
494 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
495 case SND_SOC_DAIFMT_I2S:
496 lrclk_pol = 0;
497 ctrl1 = ADAU17X1_SERIAL_PORT1_DELAY1;
498 break;
499 case SND_SOC_DAIFMT_LEFT_J:
500 case SND_SOC_DAIFMT_RIGHT_J:
501 lrclk_pol = 1;
502 ctrl1 = ADAU17X1_SERIAL_PORT1_DELAY0;
503 break;
504 case SND_SOC_DAIFMT_DSP_A:
505 lrclk_pol = 1;
506 ctrl0 |= ADAU17X1_SERIAL_PORT0_PULSE_MODE;
507 ctrl1 = ADAU17X1_SERIAL_PORT1_DELAY1;
508 break;
509 case SND_SOC_DAIFMT_DSP_B:
510 lrclk_pol = 1;
511 ctrl0 |= ADAU17X1_SERIAL_PORT0_PULSE_MODE;
512 ctrl1 = ADAU17X1_SERIAL_PORT1_DELAY0;
513 break;
514 default:
515 return -EINVAL;
516 }
517
518 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
519 case SND_SOC_DAIFMT_NB_NF:
520 break;
521 case SND_SOC_DAIFMT_IB_NF:
522 ctrl0 |= ADAU17X1_SERIAL_PORT0_BCLK_POL;
523 break;
524 case SND_SOC_DAIFMT_NB_IF:
525 lrclk_pol = !lrclk_pol;
526 break;
527 case SND_SOC_DAIFMT_IB_IF:
528 ctrl0 |= ADAU17X1_SERIAL_PORT0_BCLK_POL;
529 lrclk_pol = !lrclk_pol;
530 break;
531 default:
532 return -EINVAL;
533 }
534
535 if (lrclk_pol)
536 ctrl0 |= ADAU17X1_SERIAL_PORT0_LRCLK_POL;
537
538 regmap_write(adau->regmap, ADAU17X1_SERIAL_PORT0, ctrl0);
539 regmap_write(adau->regmap, ADAU17X1_SERIAL_PORT1, ctrl1);
540
541 adau->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
542
543 return 0;
544}
545
546static int adau17x1_set_dai_tdm_slot(struct snd_soc_dai *dai,
547 unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
548{
549 struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);
550 unsigned int ser_ctrl0, ser_ctrl1;
551 unsigned int conv_ctrl0, conv_ctrl1;
552
553 /* I2S mode */
554 if (slots == 0) {
555 slots = 2;
556 rx_mask = 3;
557 tx_mask = 3;
558 slot_width = 32;
559 }
560
561 switch (slots) {
562 case 2:
563 ser_ctrl0 = ADAU17X1_SERIAL_PORT0_STEREO;
564 break;
565 case 4:
566 ser_ctrl0 = ADAU17X1_SERIAL_PORT0_TDM4;
567 break;
568 case 8:
569 if (adau->type == ADAU1361)
570 return -EINVAL;
571
572 ser_ctrl0 = ADAU17X1_SERIAL_PORT0_TDM8;
573 break;
574 default:
575 return -EINVAL;
576 }
577
578 switch (slot_width * slots) {
579 case 32:
580 if (adau->type == ADAU1761)
581 return -EINVAL;
582
583 ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK32;
584 break;
585 case 64:
586 ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK64;
587 break;
588 case 48:
589 ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK48;
590 break;
591 case 128:
592 ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK128;
593 break;
594 case 256:
595 if (adau->type == ADAU1361)
596 return -EINVAL;
597
598 ser_ctrl1 = ADAU17X1_SERIAL_PORT1_BCLK256;
599 break;
600 default:
601 return -EINVAL;
602 }
603
604 switch (rx_mask) {
605 case 0x03:
606 conv_ctrl1 = ADAU17X1_CONVERTER1_ADC_PAIR(1);
607 adau->tdm_slot[SNDRV_PCM_STREAM_CAPTURE] = 0;
608 break;
609 case 0x0c:
610 conv_ctrl1 = ADAU17X1_CONVERTER1_ADC_PAIR(2);
611 adau->tdm_slot[SNDRV_PCM_STREAM_CAPTURE] = 1;
612 break;
613 case 0x30:
614 conv_ctrl1 = ADAU17X1_CONVERTER1_ADC_PAIR(3);
615 adau->tdm_slot[SNDRV_PCM_STREAM_CAPTURE] = 2;
616 break;
617 case 0xc0:
618 conv_ctrl1 = ADAU17X1_CONVERTER1_ADC_PAIR(4);
619 adau->tdm_slot[SNDRV_PCM_STREAM_CAPTURE] = 3;
620 break;
621 default:
622 return -EINVAL;
623 }
624
625 switch (tx_mask) {
626 case 0x03:
627 conv_ctrl0 = ADAU17X1_CONVERTER0_DAC_PAIR(1);
628 adau->tdm_slot[SNDRV_PCM_STREAM_PLAYBACK] = 0;
629 break;
630 case 0x0c:
631 conv_ctrl0 = ADAU17X1_CONVERTER0_DAC_PAIR(2);
632 adau->tdm_slot[SNDRV_PCM_STREAM_PLAYBACK] = 1;
633 break;
634 case 0x30:
635 conv_ctrl0 = ADAU17X1_CONVERTER0_DAC_PAIR(3);
636 adau->tdm_slot[SNDRV_PCM_STREAM_PLAYBACK] = 2;
637 break;
638 case 0xc0:
639 conv_ctrl0 = ADAU17X1_CONVERTER0_DAC_PAIR(4);
640 adau->tdm_slot[SNDRV_PCM_STREAM_PLAYBACK] = 3;
641 break;
642 default:
643 return -EINVAL;
644 }
645
646 regmap_update_bits(adau->regmap, ADAU17X1_CONVERTER0,
647 ADAU17X1_CONVERTER0_DAC_PAIR_MASK, conv_ctrl0);
648 regmap_update_bits(adau->regmap, ADAU17X1_CONVERTER1,
649 ADAU17X1_CONVERTER1_ADC_PAIR_MASK, conv_ctrl1);
650 regmap_update_bits(adau->regmap, ADAU17X1_SERIAL_PORT0,
651 ADAU17X1_SERIAL_PORT0_TDM_MASK, ser_ctrl0);
652 regmap_update_bits(adau->regmap, ADAU17X1_SERIAL_PORT1,
653 ADAU17X1_SERIAL_PORT1_BCLK_MASK, ser_ctrl1);
654
655 if (!adau17x1_has_dsp(adau))
656 return 0;
657
658 if (adau->dsp_bypass[SNDRV_PCM_STREAM_PLAYBACK]) {
659 regmap_write(adau->regmap, ADAU17X1_SERIAL_INPUT_ROUTE,
660 (adau->tdm_slot[SNDRV_PCM_STREAM_PLAYBACK] * 2) + 1);
661 }
662
663 if (adau->dsp_bypass[SNDRV_PCM_STREAM_CAPTURE]) {
664 regmap_write(adau->regmap, ADAU17X1_SERIAL_OUTPUT_ROUTE,
665 (adau->tdm_slot[SNDRV_PCM_STREAM_CAPTURE] * 2) + 1);
666 }
667
668 return 0;
669}
670
d48b088e
LPC
671static int adau17x1_startup(struct snd_pcm_substream *substream,
672 struct snd_soc_dai *dai)
673{
674 struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);
675
676 if (adau->sigmadsp)
677 return sigmadsp_restrict_params(adau->sigmadsp, substream);
678
679 return 0;
680}
681
4101866c
LPC
682const struct snd_soc_dai_ops adau17x1_dai_ops = {
683 .hw_params = adau17x1_hw_params,
684 .set_sysclk = adau17x1_set_dai_sysclk,
685 .set_fmt = adau17x1_set_dai_fmt,
686 .set_pll = adau17x1_set_dai_pll,
687 .set_tdm_slot = adau17x1_set_dai_tdm_slot,
d48b088e 688 .startup = adau17x1_startup,
4101866c
LPC
689};
690EXPORT_SYMBOL_GPL(adau17x1_dai_ops);
691
692int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec,
693 enum adau17x1_micbias_voltage micbias)
694{
695 struct adau *adau = snd_soc_codec_get_drvdata(codec);
696
697 switch (micbias) {
698 case ADAU17X1_MICBIAS_0_90_AVDD:
699 case ADAU17X1_MICBIAS_0_65_AVDD:
700 break;
701 default:
702 return -EINVAL;
703 }
704
705 return regmap_write(adau->regmap, ADAU17X1_MICBIAS, micbias << 2);
706}
707EXPORT_SYMBOL_GPL(adau17x1_set_micbias_voltage);
708
dee9cec4
LPC
709bool adau17x1_precious_register(struct device *dev, unsigned int reg)
710{
711 /* SigmaDSP parameter memory */
712 if (reg < 0x400)
713 return true;
714
715 return false;
716}
717EXPORT_SYMBOL_GPL(adau17x1_precious_register);
718
4101866c
LPC
719bool adau17x1_readable_register(struct device *dev, unsigned int reg)
720{
dee9cec4
LPC
721 /* SigmaDSP parameter memory */
722 if (reg < 0x400)
723 return true;
724
4101866c
LPC
725 switch (reg) {
726 case ADAU17X1_CLOCK_CONTROL:
727 case ADAU17X1_PLL_CONTROL:
728 case ADAU17X1_REC_POWER_MGMT:
729 case ADAU17X1_MICBIAS:
730 case ADAU17X1_SERIAL_PORT0:
731 case ADAU17X1_SERIAL_PORT1:
732 case ADAU17X1_CONVERTER0:
733 case ADAU17X1_CONVERTER1:
734 case ADAU17X1_LEFT_INPUT_DIGITAL_VOL:
735 case ADAU17X1_RIGHT_INPUT_DIGITAL_VOL:
736 case ADAU17X1_ADC_CONTROL:
737 case ADAU17X1_PLAY_POWER_MGMT:
738 case ADAU17X1_DAC_CONTROL0:
739 case ADAU17X1_DAC_CONTROL1:
740 case ADAU17X1_DAC_CONTROL2:
741 case ADAU17X1_SERIAL_PORT_PAD:
742 case ADAU17X1_CONTROL_PORT_PAD0:
743 case ADAU17X1_CONTROL_PORT_PAD1:
744 case ADAU17X1_DSP_SAMPLING_RATE:
745 case ADAU17X1_SERIAL_INPUT_ROUTE:
746 case ADAU17X1_SERIAL_OUTPUT_ROUTE:
747 case ADAU17X1_DSP_ENABLE:
748 case ADAU17X1_DSP_RUN:
749 case ADAU17X1_SERIAL_SAMPLING_RATE:
750 return true;
751 default:
752 break;
753 }
754 return false;
755}
756EXPORT_SYMBOL_GPL(adau17x1_readable_register);
757
758bool adau17x1_volatile_register(struct device *dev, unsigned int reg)
759{
760 /* SigmaDSP parameter and program memory */
761 if (reg < 0x4000)
762 return true;
763
764 switch (reg) {
765 /* The PLL register is 6 bytes long */
766 case ADAU17X1_PLL_CONTROL:
767 case ADAU17X1_PLL_CONTROL + 1:
768 case ADAU17X1_PLL_CONTROL + 2:
769 case ADAU17X1_PLL_CONTROL + 3:
770 case ADAU17X1_PLL_CONTROL + 4:
771 case ADAU17X1_PLL_CONTROL + 5:
772 return true;
773 default:
774 break;
775 }
776
777 return false;
778}
779EXPORT_SYMBOL_GPL(adau17x1_volatile_register);
780
d48b088e 781int adau17x1_setup_firmware(struct adau *adau, unsigned int rate)
4101866c
LPC
782{
783 int ret;
784 int dspsr;
785
786 ret = regmap_read(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, &dspsr);
787 if (ret)
788 return ret;
789
790 regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 1);
791 regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, 0xf);
792
d48b088e 793 ret = sigmadsp_setup(adau->sigmadsp, rate);
4101866c
LPC
794 if (ret) {
795 regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 0);
796 return ret;
797 }
798 regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, dspsr);
799
800 return 0;
801}
d48b088e 802EXPORT_SYMBOL_GPL(adau17x1_setup_firmware);
4101866c
LPC
803
804int adau17x1_add_widgets(struct snd_soc_codec *codec)
805{
806 struct adau *adau = snd_soc_codec_get_drvdata(codec);
807 int ret;
808
809 ret = snd_soc_add_codec_controls(codec, adau17x1_controls,
810 ARRAY_SIZE(adau17x1_controls));
811 if (ret)
812 return ret;
813 ret = snd_soc_dapm_new_controls(&codec->dapm, adau17x1_dapm_widgets,
814 ARRAY_SIZE(adau17x1_dapm_widgets));
815 if (ret)
816 return ret;
817
818 if (adau17x1_has_dsp(adau)) {
819 ret = snd_soc_dapm_new_controls(&codec->dapm,
820 adau17x1_dsp_dapm_widgets,
821 ARRAY_SIZE(adau17x1_dsp_dapm_widgets));
d48b088e
LPC
822 if (ret)
823 return ret;
824
825 if (!adau->sigmadsp)
826 return 0;
827
828 ret = sigmadsp_attach(adau->sigmadsp, &codec->component);
829 if (ret) {
830 dev_err(codec->dev, "Failed to attach firmware: %d\n",
831 ret);
832 return ret;
833 }
4101866c 834 }
d48b088e
LPC
835
836 return 0;
4101866c
LPC
837}
838EXPORT_SYMBOL_GPL(adau17x1_add_widgets);
839
840int adau17x1_add_routes(struct snd_soc_codec *codec)
841{
842 struct adau *adau = snd_soc_codec_get_drvdata(codec);
843 int ret;
844
845 ret = snd_soc_dapm_add_routes(&codec->dapm, adau17x1_dapm_routes,
846 ARRAY_SIZE(adau17x1_dapm_routes));
847 if (ret)
848 return ret;
849
850 if (adau17x1_has_dsp(adau)) {
851 ret = snd_soc_dapm_add_routes(&codec->dapm,
852 adau17x1_dsp_dapm_routes,
853 ARRAY_SIZE(adau17x1_dsp_dapm_routes));
854 } else {
855 ret = snd_soc_dapm_add_routes(&codec->dapm,
856 adau17x1_no_dsp_dapm_routes,
857 ARRAY_SIZE(adau17x1_no_dsp_dapm_routes));
858 }
859 return ret;
860}
861EXPORT_SYMBOL_GPL(adau17x1_add_routes);
862
4101866c
LPC
863int adau17x1_resume(struct snd_soc_codec *codec)
864{
865 struct adau *adau = snd_soc_codec_get_drvdata(codec);
866
867 if (adau->switch_mode)
868 adau->switch_mode(codec->dev);
869
4101866c
LPC
870 regcache_sync(adau->regmap);
871
872 return 0;
873}
874EXPORT_SYMBOL_GPL(adau17x1_resume);
875
876int adau17x1_probe(struct device *dev, struct regmap *regmap,
d48b088e
LPC
877 enum adau17x1_type type, void (*switch_mode)(struct device *dev),
878 const char *firmware_name)
4101866c
LPC
879{
880 struct adau *adau;
881
882 if (IS_ERR(regmap))
883 return PTR_ERR(regmap);
884
885 adau = devm_kzalloc(dev, sizeof(*adau), GFP_KERNEL);
886 if (!adau)
887 return -ENOMEM;
888
889 adau->regmap = regmap;
890 adau->switch_mode = switch_mode;
891 adau->type = type;
892
893 dev_set_drvdata(dev, adau);
894
d48b088e
LPC
895 if (firmware_name) {
896 adau->sigmadsp = devm_sigmadsp_init_regmap(dev, regmap, NULL,
897 firmware_name);
898 if (IS_ERR(adau->sigmadsp)) {
899 dev_warn(dev, "Could not find firmware file: %ld\n",
900 PTR_ERR(adau->sigmadsp));
901 adau->sigmadsp = NULL;
902 }
903 }
904
4101866c
LPC
905 if (switch_mode)
906 switch_mode(dev);
907
908 return 0;
909}
910EXPORT_SYMBOL_GPL(adau17x1_probe);
911
912MODULE_DESCRIPTION("ASoC ADAU1X61/ADAU1X81 common code");
913MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
914MODULE_LICENSE("GPL");
This page took 0.166258 seconds and 5 git commands to generate.