diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
commit | fcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch) | |
tree | a57612d1888735a2ec7972891b68c1ac5ec8faea /sound/soc/tegra | |
parent | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff) |
Diffstat (limited to 'sound/soc/tegra')
-rw-r--r-- | sound/soc/tegra/tegra30_dam.c | 650 | ||||
-rw-r--r-- | sound/soc/tegra/tegra30_dam.h | 163 | ||||
-rw-r--r-- | sound/soc/tegra/tegra30_spdif.c | 505 | ||||
-rw-r--r-- | sound/soc/tegra/tegra30_spdif.h | 777 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_aic326x.c | 1281 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_max98088.c | 1233 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_max98095.c | 723 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_p1852.c | 272 | ||||
-rw-r--r-- | sound/soc/tegra/tegra_rt5640.c | 738 |
9 files changed, 6342 insertions, 0 deletions
diff --git a/sound/soc/tegra/tegra30_dam.c b/sound/soc/tegra/tegra30_dam.c new file mode 100644 index 00000000000..d308179110c --- /dev/null +++ b/sound/soc/tegra/tegra30_dam.c | |||
@@ -0,0 +1,650 @@ | |||
1 | /* | ||
2 | * tegra30_dam.c - Tegra 30 DAM driver | ||
3 | * | ||
4 | * Author: Nikesh Oswal <noswal@nvidia.com> | ||
5 | * Copyright (C) 2011 - NVIDIA, Inc. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
19 | * 02110-1301 USA | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include <linux/clk.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/debugfs.h> | ||
26 | #include <linux/device.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/seq_file.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <linux/io.h> | ||
31 | #include <sound/soc.h> | ||
32 | #include "tegra30_dam.h" | ||
33 | #include "tegra30_ahub.h" | ||
34 | |||
35 | #define DRV_NAME "tegra30-dam" | ||
36 | |||
37 | static struct tegra30_dam_context *dams_cont_info[TEGRA30_NR_DAM_IFC]; | ||
38 | |||
39 | enum { | ||
40 | dam_ch_in0 = 0x0, | ||
41 | dam_ch_in1, | ||
42 | dam_ch_out, | ||
43 | dam_ch_maxnum | ||
44 | } tegra30_dam_chtype; | ||
45 | |||
46 | struct tegra30_dam_src_step_table step_table[] = { | ||
47 | { 8000, 44100, 80 }, | ||
48 | { 8000, 48000, 1 }, | ||
49 | { 16000, 44100, 160 }, | ||
50 | { 16000, 48000, 1 }, | ||
51 | { 44100, 8000, 441 }, | ||
52 | { 48000, 8000, 0 }, | ||
53 | { 44100, 16000, 441 }, | ||
54 | { 48000, 16000, 0 }, | ||
55 | }; | ||
56 | |||
57 | static void tegra30_dam_set_output_samplerate(struct tegra30_dam_context *dam, | ||
58 | int fsout); | ||
59 | static void tegra30_dam_set_input_samplerate(struct tegra30_dam_context *dam, | ||
60 | int fsin); | ||
61 | static int tegra30_dam_set_step_reset(struct tegra30_dam_context *dam, | ||
62 | int insample, int outsample); | ||
63 | static void tegra30_dam_ch0_set_step(struct tegra30_dam_context *dam, int step); | ||
64 | |||
65 | static inline void tegra30_dam_writel(struct tegra30_dam_context *dam, | ||
66 | u32 val, u32 reg) | ||
67 | { | ||
68 | #ifdef CONFIG_PM | ||
69 | dam->reg_cache[reg >> 2] = val; | ||
70 | #endif | ||
71 | __raw_writel(val, dam->damregs + reg); | ||
72 | } | ||
73 | |||
74 | static inline u32 tegra30_dam_readl(struct tegra30_dam_context *dam, u32 reg) | ||
75 | { | ||
76 | u32 val = __raw_readl(dam->damregs + reg); | ||
77 | |||
78 | return val; | ||
79 | } | ||
80 | |||
81 | #ifdef CONFIG_PM | ||
82 | int tegra30_dam_resume(int ifc) | ||
83 | { | ||
84 | int i = 0; | ||
85 | struct tegra30_dam_context *dam; | ||
86 | |||
87 | if (ifc >= TEGRA30_NR_DAM_IFC) | ||
88 | return -EINVAL; | ||
89 | |||
90 | dam = dams_cont_info[ifc]; | ||
91 | |||
92 | if (dam->in_use) { | ||
93 | tegra30_dam_enable_clock(ifc); | ||
94 | |||
95 | for (i = 0; i <= TEGRA30_DAM_CTRL_REGINDEX; i++) { | ||
96 | if ((i == TEGRA30_DAM_CTRL_RSVD_6) || | ||
97 | (i == TEGRA30_DAM_CTRL_RSVD_10)) | ||
98 | continue; | ||
99 | |||
100 | tegra30_dam_writel(dam, dam->reg_cache[i], | ||
101 | (i << 2)); | ||
102 | } | ||
103 | |||
104 | tegra30_dam_disable_clock(ifc); | ||
105 | } | ||
106 | |||
107 | return 0; | ||
108 | } | ||
109 | #endif | ||
110 | |||
111 | void tegra30_dam_disable_clock(int ifc) | ||
112 | { | ||
113 | struct tegra30_dam_context *dam; | ||
114 | |||
115 | if (ifc >= TEGRA30_NR_DAM_IFC) | ||
116 | return; | ||
117 | |||
118 | dam = dams_cont_info[ifc]; | ||
119 | clk_disable(dam->dam_clk); | ||
120 | tegra30_ahub_disable_clocks(); | ||
121 | } | ||
122 | |||
123 | int tegra30_dam_enable_clock(int ifc) | ||
124 | { | ||
125 | struct tegra30_dam_context *dam; | ||
126 | |||
127 | if (ifc >= TEGRA30_NR_DAM_IFC) | ||
128 | return -EINVAL; | ||
129 | |||
130 | dam = dams_cont_info[ifc]; | ||
131 | tegra30_ahub_enable_clocks(); | ||
132 | clk_enable(dam->dam_clk); | ||
133 | |||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | #ifdef CONFIG_DEBUG_FS | ||
138 | static int tegra30_dam_show(struct seq_file *s, void *unused) | ||
139 | { | ||
140 | #define REG(r) { r, #r } | ||
141 | static const struct { | ||
142 | int offset; | ||
143 | const char *name; | ||
144 | } regs[] = { | ||
145 | REG(TEGRA30_DAM_CTRL), | ||
146 | REG(TEGRA30_DAM_CLIP), | ||
147 | REG(TEGRA30_DAM_CLIP_THRESHOLD), | ||
148 | REG(TEGRA30_DAM_AUDIOCIF_OUT_CTRL), | ||
149 | REG(TEGRA30_DAM_CH0_CTRL), | ||
150 | REG(TEGRA30_DAM_CH0_CONV), | ||
151 | REG(TEGRA30_DAM_AUDIOCIF_CH0_CTRL), | ||
152 | REG(TEGRA30_DAM_CH1_CTRL), | ||
153 | REG(TEGRA30_DAM_CH1_CONV), | ||
154 | REG(TEGRA30_DAM_AUDIOCIF_CH1_CTRL), | ||
155 | }; | ||
156 | #undef REG | ||
157 | |||
158 | struct tegra30_dam_context *dam = s->private; | ||
159 | int i; | ||
160 | |||
161 | clk_enable(dam->dam_clk); | ||
162 | |||
163 | for (i = 0; i < ARRAY_SIZE(regs); i++) { | ||
164 | u32 val = tegra30_dam_readl(dam, regs[i].offset); | ||
165 | seq_printf(s, "%s = %08x\n", regs[i].name, val); | ||
166 | } | ||
167 | |||
168 | clk_disable(dam->dam_clk); | ||
169 | |||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | static int tegra30_dam_debug_open(struct inode *inode, struct file *file) | ||
174 | { | ||
175 | return single_open(file, tegra30_dam_show, inode->i_private); | ||
176 | } | ||
177 | |||
178 | static const struct file_operations tegra30_dam_debug_fops = { | ||
179 | .open = tegra30_dam_debug_open, | ||
180 | .read = seq_read, | ||
181 | .llseek = seq_lseek, | ||
182 | .release = single_release, | ||
183 | }; | ||
184 | |||
185 | static void tegra30_dam_debug_add(struct tegra30_dam_context *dam, int id) | ||
186 | { | ||
187 | char name[] = DRV_NAME ".0"; | ||
188 | |||
189 | snprintf(name, sizeof(name), DRV_NAME".%1d", id); | ||
190 | dam->debug = debugfs_create_file(name, S_IRUGO, snd_soc_debugfs_root, | ||
191 | dam, &tegra30_dam_debug_fops); | ||
192 | } | ||
193 | |||
194 | static void tegra30_dam_debug_remove(struct tegra30_dam_context *dam) | ||
195 | { | ||
196 | if (dam->debug) | ||
197 | debugfs_remove(dam->debug); | ||
198 | } | ||
199 | #else | ||
200 | static inline void tegra30_dam_debug_add(struct tegra30_dam_context *dam, | ||
201 | int id) | ||
202 | { | ||
203 | } | ||
204 | |||
205 | static inline void tegra30_dam_debug_remove(struct tegra30_dam_context *dam) | ||
206 | { | ||
207 | } | ||
208 | #endif | ||
209 | |||
210 | int tegra30_dam_allocate_controller() | ||
211 | { | ||
212 | int i = 0; | ||
213 | struct tegra30_dam_context *dam = NULL; | ||
214 | |||
215 | for (i = 0; i < TEGRA30_NR_DAM_IFC; i++) { | ||
216 | |||
217 | dam = dams_cont_info[i]; | ||
218 | |||
219 | if (!dam->in_use) { | ||
220 | dam->in_use = true; | ||
221 | return i; | ||
222 | } | ||
223 | } | ||
224 | |||
225 | return -ENOENT; | ||
226 | } | ||
227 | |||
228 | int tegra30_dam_allocate_channel(int ifc, int chid) | ||
229 | { | ||
230 | struct tegra30_dam_context *dam = NULL; | ||
231 | |||
232 | if (ifc >= TEGRA30_NR_DAM_IFC) | ||
233 | return -EINVAL; | ||
234 | |||
235 | dam = dams_cont_info[ifc]; | ||
236 | |||
237 | if (!dam->ch_alloc[chid]) { | ||
238 | dam->ch_alloc[chid] = true; | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | return -ENOENT; | ||
243 | } | ||
244 | |||
245 | int tegra30_dam_free_channel(int ifc, int chid) | ||
246 | { | ||
247 | struct tegra30_dam_context *dam = NULL; | ||
248 | |||
249 | if (ifc >= TEGRA30_NR_DAM_IFC) | ||
250 | return -EINVAL; | ||
251 | |||
252 | dam = dams_cont_info[ifc]; | ||
253 | |||
254 | if (dam->ch_alloc[chid]) { | ||
255 | dam->ch_alloc[chid] = false; | ||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | return -EINVAL; | ||
260 | } | ||
261 | |||
262 | int tegra30_dam_free_controller(int ifc) | ||
263 | { | ||
264 | struct tegra30_dam_context *dam = NULL; | ||
265 | |||
266 | if (ifc >= TEGRA30_NR_DAM_IFC) | ||
267 | return -EINVAL; | ||
268 | |||
269 | dam = dams_cont_info[ifc]; | ||
270 | |||
271 | if (!dam->ch_alloc[dam_ch_in0] && | ||
272 | !dam->ch_alloc[dam_ch_in1]) { | ||
273 | dam->in_use = false; | ||
274 | return 0; | ||
275 | } | ||
276 | |||
277 | return -EINVAL; | ||
278 | } | ||
279 | |||
280 | void tegra30_dam_set_samplerate(int ifc, int chid, int samplerate) | ||
281 | { | ||
282 | struct tegra30_dam_context *dam = dams_cont_info[ifc]; | ||
283 | |||
284 | if (ifc >= TEGRA30_NR_DAM_IFC) | ||
285 | return; | ||
286 | |||
287 | switch (chid) { | ||
288 | case dam_ch_in0: | ||
289 | tegra30_dam_set_input_samplerate(dam, samplerate); | ||
290 | dam->ch_insamplerate[dam_ch_in0] = samplerate; | ||
291 | tegra30_dam_set_step_reset(dam, samplerate, dam->outsamplerate); | ||
292 | break; | ||
293 | case dam_ch_in1: | ||
294 | if (samplerate != dam->outsamplerate) | ||
295 | return; | ||
296 | dam->ch_insamplerate[dam_ch_in1] = samplerate; | ||
297 | break; | ||
298 | case dam_ch_out: | ||
299 | tegra30_dam_set_output_samplerate(dam, samplerate); | ||
300 | dam->outsamplerate = samplerate; | ||
301 | break; | ||
302 | default: | ||
303 | break; | ||
304 | } | ||
305 | } | ||
306 | |||
307 | void tegra30_dam_set_output_samplerate(struct tegra30_dam_context *dam, | ||
308 | int fsout) | ||
309 | { | ||
310 | u32 val; | ||
311 | |||
312 | val = tegra30_dam_readl(dam, TEGRA30_DAM_CTRL); | ||
313 | val &= ~TEGRA30_DAM_CTRL_FSOUT_MASK; | ||
314 | |||
315 | switch (fsout) { | ||
316 | case TEGRA30_AUDIO_SAMPLERATE_8000: | ||
317 | val |= TEGRA30_DAM_CTRL_FSOUT_FS8; | ||
318 | break; | ||
319 | case TEGRA30_AUDIO_SAMPLERATE_16000: | ||
320 | val |= TEGRA30_DAM_CTRL_FSOUT_FS16; | ||
321 | break; | ||
322 | case TEGRA30_AUDIO_SAMPLERATE_44100: | ||
323 | val |= TEGRA30_DAM_CTRL_FSOUT_FS44; | ||
324 | break; | ||
325 | case TEGRA30_AUDIO_SAMPLERATE_48000: | ||
326 | val |= TEGRA30_DAM_CTRL_FSOUT_FS48; | ||
327 | break; | ||
328 | default: | ||
329 | break; | ||
330 | } | ||
331 | |||
332 | tegra30_dam_writel(dam, val, TEGRA30_DAM_CTRL); | ||
333 | } | ||
334 | |||
335 | void tegra30_dam_set_input_samplerate(struct tegra30_dam_context *dam, int fsin) | ||
336 | { | ||
337 | u32 val; | ||
338 | |||
339 | val = tegra30_dam_readl(dam, TEGRA30_DAM_CH0_CTRL); | ||
340 | val &= ~TEGRA30_DAM_CH0_CTRL_FSIN_MASK; | ||
341 | |||
342 | switch (fsin) { | ||
343 | case TEGRA30_AUDIO_SAMPLERATE_8000: | ||
344 | val |= TEGRA30_DAM_CH0_CTRL_FSIN_FS8; | ||
345 | break; | ||
346 | case TEGRA30_AUDIO_SAMPLERATE_16000: | ||
347 | val |= TEGRA30_DAM_CH0_CTRL_FSIN_FS16; | ||
348 | break; | ||
349 | case TEGRA30_AUDIO_SAMPLERATE_44100: | ||
350 | val |= TEGRA30_DAM_CH0_CTRL_FSIN_FS44; | ||
351 | break; | ||
352 | case TEGRA30_AUDIO_SAMPLERATE_48000: | ||
353 | val |= TEGRA30_DAM_CH0_CTRL_FSIN_FS48; | ||
354 | break; | ||
355 | default: | ||
356 | break; | ||
357 | } | ||
358 | |||
359 | tegra30_dam_writel(dam, val, TEGRA30_DAM_CH0_CTRL); | ||
360 | } | ||
361 | |||
362 | int tegra30_dam_set_step_reset(struct tegra30_dam_context *dam, | ||
363 | int insample, int outsample) | ||
364 | { | ||
365 | int step_reset = 0; | ||
366 | int i = 0; | ||
367 | |||
368 | for (i = 0; i < ARRAY_SIZE(step_table); i++) { | ||
369 | if ((insample == step_table[i].insample) && | ||
370 | (outsample == step_table[i].outsample)) | ||
371 | step_reset = step_table[i].stepreset; | ||
372 | } | ||
373 | |||
374 | tegra30_dam_ch0_set_step(dam, step_reset); | ||
375 | |||
376 | return 0; | ||
377 | } | ||
378 | |||
379 | void tegra30_dam_ch0_set_step(struct tegra30_dam_context *dam, int step) | ||
380 | { | ||
381 | u32 val; | ||
382 | |||
383 | val = tegra30_dam_readl(dam, TEGRA30_DAM_CH0_CTRL); | ||
384 | val &= ~TEGRA30_DAM_CH0_CTRL_STEP_MASK; | ||
385 | val |= step << TEGRA30_DAM_CH0_CTRL_STEP_SHIFT; | ||
386 | tegra30_dam_writel(dam, val, TEGRA30_DAM_CH0_CTRL); | ||
387 | } | ||
388 | |||
389 | int tegra30_dam_set_gain(int ifc, int chid, int gain) | ||
390 | { | ||
391 | |||
392 | if (ifc >= TEGRA30_NR_DAM_IFC) | ||
393 | return -EINVAL; | ||
394 | |||
395 | switch (chid) { | ||
396 | case dam_ch_in0: | ||
397 | tegra30_dam_writel(dams_cont_info[ifc], gain, | ||
398 | TEGRA30_DAM_CH0_CONV); | ||
399 | break; | ||
400 | case dam_ch_in1: | ||
401 | tegra30_dam_writel(dams_cont_info[ifc], gain, | ||
402 | TEGRA30_DAM_CH1_CONV); | ||
403 | break; | ||
404 | default: | ||
405 | break; | ||
406 | } | ||
407 | |||
408 | return 0; | ||
409 | } | ||
410 | |||
411 | int tegra30_dam_set_acif(int ifc, int chid, unsigned int audio_channels, | ||
412 | unsigned int audio_bits, unsigned int client_channels, | ||
413 | unsigned int client_bits) | ||
414 | { | ||
415 | unsigned int reg; | ||
416 | unsigned int value = 0; | ||
417 | |||
418 | if (ifc >= TEGRA30_NR_DAM_IFC) | ||
419 | return -EINVAL; | ||
420 | |||
421 | /*ch0 takes input as mono/16bit always*/ | ||
422 | if ((chid == dam_ch_in0) && | ||
423 | ((client_channels != 1) || (client_bits != 16))) | ||
424 | return -EINVAL; | ||
425 | |||
426 | value |= TEGRA30_CIF_MONOCONV_COPY; | ||
427 | value |= TEGRA30_CIF_STEREOCONV_CH0; | ||
428 | value |= (audio_channels-1) << TEGRA30_AUDIO_CHANNELS_SHIFT; | ||
429 | value |= (((audio_bits>>2)-1)<<TEGRA30_AUDIO_BITS_SHIFT); | ||
430 | value |= (client_channels-1) << TEGRA30_CLIENT_CHANNELS_SHIFT; | ||
431 | value |= (((client_bits>>2)-1)<<TEGRA30_CLIENT_BITS_SHIFT); | ||
432 | |||
433 | switch (chid) { | ||
434 | case dam_ch_out: | ||
435 | value |= TEGRA30_CIF_DIRECTION_TX; | ||
436 | reg = TEGRA30_DAM_AUDIOCIF_OUT_CTRL; | ||
437 | break; | ||
438 | case dam_ch_in0: | ||
439 | value |= TEGRA30_CIF_DIRECTION_RX; | ||
440 | reg = TEGRA30_DAM_AUDIOCIF_CH0_CTRL; | ||
441 | break; | ||
442 | case dam_ch_in1: | ||
443 | value |= TEGRA30_CIF_DIRECTION_RX; | ||
444 | reg = TEGRA30_DAM_AUDIOCIF_CH1_CTRL; | ||
445 | break; | ||
446 | default: | ||
447 | return -EINVAL; | ||
448 | } | ||
449 | |||
450 | tegra30_dam_writel(dams_cont_info[ifc], value, reg); | ||
451 | |||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | void tegra30_dam_enable(int ifc, int on, int chid) | ||
456 | { | ||
457 | u32 old_val, val, enreg; | ||
458 | struct tegra30_dam_context *dam = dams_cont_info[ifc]; | ||
459 | |||
460 | if (ifc >= TEGRA30_NR_DAM_IFC) | ||
461 | return; | ||
462 | |||
463 | if (chid == dam_ch_in0) | ||
464 | enreg = TEGRA30_DAM_CH0_CTRL; | ||
465 | else | ||
466 | enreg = TEGRA30_DAM_CH1_CTRL; | ||
467 | |||
468 | old_val = val = tegra30_dam_readl(dam, enreg); | ||
469 | |||
470 | if (on) { | ||
471 | if (!dam->ch_enable_refcnt[chid]++) | ||
472 | val |= TEGRA30_DAM_CH0_CTRL_EN; | ||
473 | } else if (dam->ch_enable_refcnt[chid]) { | ||
474 | dam->ch_enable_refcnt[chid]--; | ||
475 | if (!dam->ch_enable_refcnt[chid]) | ||
476 | val &= ~TEGRA30_DAM_CH0_CTRL_EN; | ||
477 | } | ||
478 | |||
479 | if (val != old_val) | ||
480 | tegra30_dam_writel(dam, val, enreg); | ||
481 | |||
482 | old_val = val = tegra30_dam_readl(dam, TEGRA30_DAM_CTRL); | ||
483 | |||
484 | if (dam->ch_enable_refcnt[dam_ch_in0] || | ||
485 | dam->ch_enable_refcnt[dam_ch_in1]) | ||
486 | val |= TEGRA30_DAM_CTRL_DAM_EN; | ||
487 | else | ||
488 | val &= ~TEGRA30_DAM_CTRL_DAM_EN; | ||
489 | |||
490 | if (old_val != val) | ||
491 | tegra30_dam_writel(dam, val, TEGRA30_DAM_CTRL); | ||
492 | } | ||
493 | |||
494 | void tegra30_dam_ch0_set_datasync(struct tegra30_dam_context *dam, int datasync) | ||
495 | { | ||
496 | u32 val; | ||
497 | |||
498 | val = tegra30_dam_readl(dam, TEGRA30_DAM_CH0_CTRL); | ||
499 | val &= ~TEGRA30_DAM_CH0_CTRL_DATA_SYNC_MASK; | ||
500 | val |= datasync << TEGRA30_DAM_DATA_SYNC_SHIFT; | ||
501 | tegra30_dam_writel(dam, val, TEGRA30_DAM_CH0_CTRL); | ||
502 | } | ||
503 | |||
504 | void tegra30_dam_ch1_set_datasync(struct tegra30_dam_context *dam, int datasync) | ||
505 | { | ||
506 | u32 val; | ||
507 | |||
508 | val = tegra30_dam_readl(dam, TEGRA30_DAM_CH1_CTRL); | ||
509 | val &= ~TEGRA30_DAM_CH1_CTRL_DATA_SYNC_MASK; | ||
510 | val |= datasync << TEGRA30_DAM_DATA_SYNC_SHIFT; | ||
511 | tegra30_dam_writel(dam, val, TEGRA30_DAM_CH1_CTRL); | ||
512 | } | ||
513 | |||
514 | void tegra30_dam_enable_clip_counter(struct tegra30_dam_context *dam, int on) | ||
515 | { | ||
516 | u32 val; | ||
517 | |||
518 | val = tegra30_dam_readl(dam, TEGRA30_DAM_CLIP); | ||
519 | val &= ~TEGRA30_DAM_CLIP_COUNTER_ENABLE; | ||
520 | val |= on ? TEGRA30_DAM_CLIP_COUNTER_ENABLE : 0; | ||
521 | tegra30_dam_writel(dam, val, TEGRA30_DAM_CLIP); | ||
522 | } | ||
523 | |||
524 | static int __devinit tegra30_dam_probe(struct platform_device *pdev) | ||
525 | { | ||
526 | struct resource *res, *region; | ||
527 | struct tegra30_dam_context *dam; | ||
528 | int ret = 0; | ||
529 | #ifdef CONFIG_PM | ||
530 | int i; | ||
531 | #endif | ||
532 | int clkm_rate; | ||
533 | |||
534 | if ((pdev->id < 0) || | ||
535 | (pdev->id >= TEGRA30_NR_DAM_IFC)) { | ||
536 | dev_err(&pdev->dev, "ID %d out of range\n", pdev->id); | ||
537 | return -EINVAL; | ||
538 | } | ||
539 | |||
540 | dams_cont_info[pdev->id] = devm_kzalloc(&pdev->dev, | ||
541 | sizeof(struct tegra30_dam_context), | ||
542 | GFP_KERNEL); | ||
543 | if (!dams_cont_info[pdev->id]) { | ||
544 | dev_err(&pdev->dev, "Can't allocate dam context\n"); | ||
545 | ret = -ENOMEM; | ||
546 | goto exit; | ||
547 | } | ||
548 | dam = dams_cont_info[pdev->id]; | ||
549 | |||
550 | dam->dam_clk = clk_get(&pdev->dev, NULL); | ||
551 | if (IS_ERR(dam->dam_clk)) { | ||
552 | dev_err(&pdev->dev, "Can't retrieve dam clock\n"); | ||
553 | ret = PTR_ERR(dam->dam_clk); | ||
554 | goto err_free; | ||
555 | } | ||
556 | clkm_rate = clk_get_rate(clk_get_parent(dam->dam_clk)); | ||
557 | while (clkm_rate > 12000000) | ||
558 | clkm_rate >>= 1; | ||
559 | |||
560 | clk_set_rate(dam->dam_clk,clkm_rate); | ||
561 | |||
562 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
563 | if (!res) { | ||
564 | dev_err(&pdev->dev, "No memory 0 resource\n"); | ||
565 | ret = -ENODEV; | ||
566 | goto err_clk_put_dam; | ||
567 | } | ||
568 | |||
569 | region = devm_request_mem_region(&pdev->dev, res->start, | ||
570 | resource_size(res), pdev->name); | ||
571 | if (!region) { | ||
572 | dev_err(&pdev->dev, "Memory region 0 already claimed\n"); | ||
573 | ret = -EBUSY; | ||
574 | goto err_clk_put_dam; | ||
575 | } | ||
576 | |||
577 | dam->damregs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); | ||
578 | if (!dam->damregs) { | ||
579 | dev_err(&pdev->dev, "ioremap 0 failed\n"); | ||
580 | ret = -ENOMEM; | ||
581 | goto err_clk_put_dam; | ||
582 | } | ||
583 | |||
584 | #ifdef CONFIG_PM | ||
585 | /* cache the POR values of DAM regs*/ | ||
586 | tegra30_dam_enable_clock(pdev->id); | ||
587 | |||
588 | for (i = 0; i <= TEGRA30_DAM_CTRL_REGINDEX; i++) { | ||
589 | if ((i == TEGRA30_DAM_CTRL_RSVD_6) || | ||
590 | (i == TEGRA30_DAM_CTRL_RSVD_10)) | ||
591 | continue; | ||
592 | |||
593 | dam->reg_cache[i] = | ||
594 | tegra30_dam_readl(dam, i << 2); | ||
595 | } | ||
596 | |||
597 | tegra30_dam_disable_clock(pdev->id); | ||
598 | #endif | ||
599 | |||
600 | platform_set_drvdata(pdev, dam); | ||
601 | |||
602 | tegra30_dam_debug_add(dam, pdev->id); | ||
603 | |||
604 | return 0; | ||
605 | |||
606 | err_clk_put_dam: | ||
607 | clk_put(dam->dam_clk); | ||
608 | err_free: | ||
609 | dams_cont_info[pdev->id] = NULL; | ||
610 | exit: | ||
611 | return ret; | ||
612 | } | ||
613 | |||
614 | static int __devexit tegra30_dam_remove(struct platform_device *pdev) | ||
615 | { | ||
616 | struct tegra30_dam_context *dam; | ||
617 | |||
618 | dam = platform_get_drvdata(pdev); | ||
619 | clk_put(dam->dam_clk); | ||
620 | tegra30_dam_debug_remove(dam); | ||
621 | dams_cont_info[pdev->id] = NULL; | ||
622 | |||
623 | return 0; | ||
624 | } | ||
625 | |||
626 | static struct platform_driver tegra30_dam_driver = { | ||
627 | .probe = tegra30_dam_probe, | ||
628 | .remove = __devexit_p(tegra30_dam_remove), | ||
629 | .driver = { | ||
630 | .name = DRV_NAME, | ||
631 | .owner = THIS_MODULE, | ||
632 | }, | ||
633 | }; | ||
634 | |||
635 | static int __init tegra30_dam_modinit(void) | ||
636 | { | ||
637 | return platform_driver_register(&tegra30_dam_driver); | ||
638 | } | ||
639 | module_init(tegra30_dam_modinit); | ||
640 | |||
641 | static void __exit tegra30_dam_modexit(void) | ||
642 | { | ||
643 | platform_driver_unregister(&tegra30_dam_driver); | ||
644 | } | ||
645 | module_exit(tegra30_dam_modexit); | ||
646 | |||
647 | MODULE_AUTHOR("Nikesh Oswal <noswal@nvidia.com>"); | ||
648 | MODULE_DESCRIPTION("Tegra 30 DAM driver"); | ||
649 | MODULE_LICENSE("GPL"); | ||
650 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/sound/soc/tegra/tegra30_dam.h b/sound/soc/tegra/tegra30_dam.h new file mode 100644 index 00000000000..371e8139eec --- /dev/null +++ b/sound/soc/tegra/tegra30_dam.h | |||
@@ -0,0 +1,163 @@ | |||
1 | /* | ||
2 | * tegra30_dam.h - Tegra 30 DAM driver. | ||
3 | * | ||
4 | * Author: Nikesh Oswal <noswal@nvidia.com> | ||
5 | * Copyright (C) 2011 - NVIDIA, Inc. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
19 | * 02110-1301 USA | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #ifndef __TEGRA30_DAM_H | ||
24 | #define __TEGRA30_DAM_H | ||
25 | |||
26 | /* Register offsets from TEGRA30_DAM*_BASE */ | ||
27 | #define TEGRA30_DAM_CTRL 0 | ||
28 | #define TEGRA30_DAM_CLIP 4 | ||
29 | #define TEGRA30_DAM_CLIP_THRESHOLD 8 | ||
30 | #define TEGRA30_DAM_AUDIOCIF_OUT_CTRL 0x0C | ||
31 | #define TEGRA30_DAM_CH0_CTRL 0x10 | ||
32 | #define TEGRA30_DAM_CH0_CONV 0x14 | ||
33 | #define TEGRA30_DAM_AUDIOCIF_CH0_CTRL 0x1C | ||
34 | #define TEGRA30_DAM_CH1_CTRL 0x20 | ||
35 | #define TEGRA30_DAM_CH1_CONV 0x24 | ||
36 | #define TEGRA30_DAM_AUDIOCIF_CH1_CTRL 0x2C | ||
37 | #define TEGRA30_DAM_CTRL_REGINDEX (TEGRA30_DAM_AUDIOCIF_CH1_CTRL >> 2) | ||
38 | #define TEGRA30_DAM_CTRL_RSVD_6 6 | ||
39 | #define TEGRA30_DAM_CTRL_RSVD_10 10 | ||
40 | |||
41 | #define TEGRA30_NR_DAM_IFC 3 | ||
42 | |||
43 | #define TEGRA30_DAM_NUM_INPUT_CHANNELS 2 | ||
44 | |||
45 | /* Fields in TEGRA30_DAM_CTRL */ | ||
46 | #define TEGRA30_DAM_CTRL_SOFT_RESET_ENABLE (1 << 31) | ||
47 | #define TEGRA30_DAM_CTRL_FSOUT_SHIFT 4 | ||
48 | #define TEGRA30_DAM_CTRL_FSOUT_MASK (0xf << TEGRA30_DAM_CTRL_FSOUT_SHIFT) | ||
49 | #define TEGRA30_DAM_FS_8KHZ 0 | ||
50 | #define TEGRA30_DAM_FS_16KHZ 1 | ||
51 | #define TEGRA30_DAM_FS_44KHZ 2 | ||
52 | #define TEGRA30_DAM_FS_48KHZ 3 | ||
53 | #define TEGRA30_DAM_CTRL_FSOUT_FS8 (TEGRA30_DAM_FS_8KHZ << TEGRA30_DAM_CTRL_FSOUT_SHIFT) | ||
54 | #define TEGRA30_DAM_CTRL_FSOUT_FS16 (TEGRA30_DAM_FS_16KHZ << TEGRA30_DAM_CTRL_FSOUT_SHIFT) | ||
55 | #define TEGRA30_DAM_CTRL_FSOUT_FS44 (TEGRA30_DAM_FS_44KHZ << TEGRA30_DAM_CTRL_FSOUT_SHIFT) | ||
56 | #define TEGRA30_DAM_CTRL_FSOUT_FS48 (TEGRA30_DAM_FS_48KHZ << TEGRA30_DAM_CTRL_FSOUT_SHIFT) | ||
57 | #define TEGRA30_DAM_CTRL_CG_EN (1 << 1) | ||
58 | #define TEGRA30_DAM_CTRL_DAM_EN (1 << 0) | ||
59 | |||
60 | |||
61 | /* Fields in TEGRA30_DAM_CLIP */ | ||
62 | #define TEGRA30_DAM_CLIP_COUNTER_ENABLE (1 << 31) | ||
63 | #define TEGRA30_DAM_CLIP_COUNT_MASK 0x7fffffff | ||
64 | |||
65 | |||
66 | /* Fields in TEGRA30_DAM_CH0_CTRL */ | ||
67 | #define TEGRA30_STEP_RESET 1 | ||
68 | #define TEGRA30_DAM_DATA_SYNC 1 | ||
69 | #define TEGRA30_DAM_DATA_SYNC_SHIFT 4 | ||
70 | #define TEGRA30_DAM_CH0_CTRL_FSIN_SHIFT 8 | ||
71 | #define TEGRA30_DAM_CH0_CTRL_STEP_SHIFT 16 | ||
72 | #define TEGRA30_DAM_CH0_CTRL_STEP_MASK (0xffff << 16) | ||
73 | #define TEGRA30_DAM_CH0_CTRL_STEP_RESET (TEGRA30_STEP_RESET << 16) | ||
74 | #define TEGRA30_DAM_CH0_CTRL_FSIN_MASK (0xf << 8) | ||
75 | #define TEGRA30_DAM_CH0_CTRL_FSIN_FS8 (TEGRA30_DAM_FS_8KHZ << 8) | ||
76 | #define TEGRA30_DAM_CH0_CTRL_FSIN_FS16 (TEGRA30_DAM_FS_16KHZ << 8) | ||
77 | #define TEGRA30_DAM_CH0_CTRL_FSIN_FS44 (TEGRA30_DAM_FS_44KHZ << 8) | ||
78 | #define TEGRA30_DAM_CH0_CTRL_FSIN_FS48 (TEGRA30_DAM_FS_48KHZ << 8) | ||
79 | #define TEGRA30_DAM_CH0_CTRL_DATA_SYNC_MASK (0xf << TEGRA30_DAM_DATA_SYNC_SHIFT) | ||
80 | #define TEGRA30_DAM_CH0_CTRL_DATA_SYNC (TEGRA30_DAM_DATA_SYNC << TEGRA30_DAM_DATA_SYNC_SHIFT) | ||
81 | #define TEGRA30_DAM_CH0_CTRL_EN (1 << 0) | ||
82 | |||
83 | |||
84 | /* Fields in TEGRA30_DAM_CH0_CONV */ | ||
85 | #define TEGRA30_DAM_GAIN 1 | ||
86 | #define TEGRA30_DAM_GAIN_SHIFT 0 | ||
87 | #define TEGRA30_DAM_CH0_CONV_GAIN (TEGRA30_DAM_GAIN << TEGRA30_DAM_GAIN_SHIFT) | ||
88 | |||
89 | /* Fields in TEGRA30_DAM_CH1_CTRL */ | ||
90 | #define TEGRA30_DAM_CH1_CTRL_DATA_SYNC_MASK (0xf << TEGRA30_DAM_DATA_SYNC_SHIFT) | ||
91 | #define TEGRA30_DAM_CH1_CTRL_DATA_SYNC (TEGRA30_DAM_DATA_SYNC << TEGRA30_DAM_DATA_SYNC_SHIFT) | ||
92 | #define TEGRA30_DAM_CH1_CTRL_EN (1 << 0) | ||
93 | |||
94 | /* Fields in TEGRA30_DAM_CH1_CONV */ | ||
95 | #define TEGRA30_DAM_CH1_CONV_GAIN (TEGRA30_DAM_GAIN << TEGRA30_DAM_GAIN_SHIFT) | ||
96 | |||
97 | #define TEGRA30_AUDIO_CHANNELS_SHIFT 24 | ||
98 | #define TEGRA30_AUDIO_CHANNELS_MASK (7 << TEGRA30_AUDIO_CHANNELS_SHIFT) | ||
99 | #define TEGRA30_CLIENT_CHANNELS_SHIFT 16 | ||
100 | #define TEGRA30_CLIENT_CHANNELS_MASK (7 << TEGRA30_CLIENT_CHANNELS_SHIFT) | ||
101 | #define TEGRA30_AUDIO_BITS_SHIFT 12 | ||
102 | #define TEGRA30_AUDIO_BITS_MASK (7 << TEGRA30_AUDIO_BITS_SHIFT) | ||
103 | #define TEGRA30_CLIENT_BITS_SHIFT 8 | ||
104 | #define TEGRA30_CLIENT_BITS_MASK (7 << TEGRA30_CLIENT_BITS_SHIFT) | ||
105 | #define TEGRA30_CIF_DIRECTION_TX (0 << 2) | ||
106 | #define TEGRA30_CIF_DIRECTION_RX (1 << 2) | ||
107 | #define TEGRA30_CIF_BIT24 5 | ||
108 | #define TEGRA30_CIF_BIT16 3 | ||
109 | #define TEGRA30_CIF_CH1 0 | ||
110 | #define TEGRA30_CIF_MONOCONV_COPY (1<<0) | ||
111 | #define TEGRA30_CIF_STEREOCONV_CH0 (0<<4) | ||
112 | |||
113 | /* | ||
114 | * Audio Samplerates | ||
115 | */ | ||
116 | #define TEGRA30_AUDIO_SAMPLERATE_8000 8000 | ||
117 | #define TEGRA30_AUDIO_SAMPLERATE_16000 16000 | ||
118 | #define TEGRA30_AUDIO_SAMPLERATE_44100 44100 | ||
119 | #define TEGRA30_AUDIO_SAMPLERATE_48000 48000 | ||
120 | |||
121 | #define TEGRA30_DAM_CHIN0_SRC 0 | ||
122 | #define TEGRA30_DAM_CHIN1 1 | ||
123 | #define TEGRA30_DAM_CHOUT 2 | ||
124 | #define TEGRA30_DAM_ENABLE 1 | ||
125 | #define TEGRA30_DAM_DISABLE 0 | ||
126 | |||
127 | struct tegra30_dam_context { | ||
128 | int outsamplerate; | ||
129 | bool ch_alloc[TEGRA30_DAM_NUM_INPUT_CHANNELS]; | ||
130 | int ch_enable_refcnt[TEGRA30_DAM_NUM_INPUT_CHANNELS]; | ||
131 | int ch_insamplerate[TEGRA30_DAM_NUM_INPUT_CHANNELS]; | ||
132 | #ifdef CONFIG_PM | ||
133 | int reg_cache[TEGRA30_DAM_CTRL_REGINDEX + 1]; | ||
134 | #endif | ||
135 | struct clk *dam_clk; | ||
136 | bool in_use; | ||
137 | void __iomem *damregs; | ||
138 | struct dentry *debug; | ||
139 | }; | ||
140 | |||
141 | struct tegra30_dam_src_step_table { | ||
142 | int insample; | ||
143 | int outsample; | ||
144 | int stepreset; | ||
145 | }; | ||
146 | |||
147 | #ifdef CONFIG_PM | ||
148 | int tegra30_dam_resume(int ifc); | ||
149 | #endif | ||
150 | void tegra30_dam_disable_clock(int ifc); | ||
151 | int tegra30_dam_enable_clock(int ifc); | ||
152 | int tegra30_dam_allocate_controller(void); | ||
153 | int tegra30_dam_allocate_channel(int ifc, int chid); | ||
154 | int tegra30_dam_free_channel(int ifc, int chid); | ||
155 | int tegra30_dam_free_controller(int ifc); | ||
156 | void tegra30_dam_set_samplerate(int ifc, int chtype, int samplerate); | ||
157 | int tegra30_dam_set_gain(int ifc, int chtype, int gain); | ||
158 | int tegra30_dam_set_acif(int ifc, int chtype, unsigned int audio_channels, | ||
159 | unsigned int audio_bits, unsigned int client_channels, | ||
160 | unsigned int client_bits); | ||
161 | void tegra30_dam_enable(int ifc, int on, int chtype); | ||
162 | |||
163 | #endif | ||
diff --git a/sound/soc/tegra/tegra30_spdif.c b/sound/soc/tegra/tegra30_spdif.c new file mode 100644 index 00000000000..038127c0afb --- /dev/null +++ b/sound/soc/tegra/tegra30_spdif.c | |||
@@ -0,0 +1,505 @@ | |||
1 | /* | ||
2 | * tegra30_spdif.c - Tegra30 SPDIF driver | ||
3 | * | ||
4 | * Author: Sumit Bhattacharya <sumitb@nvidia.com> | ||
5 | * Copyright (C) 2011 - NVIDIA, Inc. | ||
6 | * | ||
7 | * Based on code copyright/by: | ||
8 | * | ||
9 | * Copyright (c) 2009-2011, NVIDIA Corporation. | ||
10 | * Scott Peterson <speterson@nvidia.com> | ||
11 | * | ||
12 | * Copyright (C) 2010 Google, Inc. | ||
13 | * Iliyan Malchev <malchev@google.com> | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or | ||
16 | * modify it under the terms of the GNU General Public License | ||
17 | * version 2 as published by the Free Software Foundation. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, but | ||
20 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
22 | * General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, write to the Free Software | ||
26 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
27 | * 02110-1301 USA | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #include <linux/clk.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/debugfs.h> | ||
34 | #include <linux/device.h> | ||
35 | #include <linux/platform_device.h> | ||
36 | #include <linux/seq_file.h> | ||
37 | #include <linux/slab.h> | ||
38 | #include <linux/io.h> | ||
39 | #include <mach/iomap.h> | ||
40 | #include <mach/hdmi-audio.h> | ||
41 | #include <sound/core.h> | ||
42 | #include <sound/pcm.h> | ||
43 | #include <sound/pcm_params.h> | ||
44 | #include <sound/soc.h> | ||
45 | |||
46 | #include "tegra30_spdif.h" | ||
47 | |||
48 | #define DRV_NAME "tegra30-spdif" | ||
49 | |||
50 | static inline void tegra30_spdif_write(struct tegra30_spdif *spdif, | ||
51 | u32 reg, u32 val) | ||
52 | { | ||
53 | __raw_writel(val, spdif->regs + reg); | ||
54 | } | ||
55 | |||
56 | static inline u32 tegra30_spdif_read(struct tegra30_spdif *spdif, u32 reg) | ||
57 | { | ||
58 | return __raw_readl(spdif->regs + reg); | ||
59 | } | ||
60 | |||
61 | static void tegra30_spdif_enable_clocks(struct tegra30_spdif *spdif) | ||
62 | { | ||
63 | clk_enable(spdif->clk_spdif_out); | ||
64 | tegra30_ahub_enable_clocks(); | ||
65 | } | ||
66 | |||
67 | static void tegra30_spdif_disable_clocks(struct tegra30_spdif *spdif) | ||
68 | { | ||
69 | tegra30_ahub_disable_clocks(); | ||
70 | clk_disable(spdif->clk_spdif_out); | ||
71 | } | ||
72 | |||
73 | #ifdef CONFIG_DEBUG_FS | ||
74 | static int tegra30_spdif_show(struct seq_file *s, void *unused) | ||
75 | { | ||
76 | #define REG(r) { r, #r } | ||
77 | static const struct { | ||
78 | int offset; | ||
79 | const char *name; | ||
80 | } regs[] = { | ||
81 | REG(TEGRA30_SPDIF_CTRL), | ||
82 | REG(TEGRA30_SPDIF_STROBE_CTRL), | ||
83 | REG(TEGRA30_SPDIF_CIF_TXD_CTRL), | ||
84 | REG(TEGRA30_SPDIF_CIF_RXD_CTRL), | ||
85 | REG(TEGRA30_SPDIF_CIF_TXU_CTRL), | ||
86 | REG(TEGRA30_SPDIF_CIF_RXU_CTRL), | ||
87 | REG(TEGRA30_SPDIF_CH_STA_RX_A), | ||
88 | REG(TEGRA30_SPDIF_CH_STA_RX_B), | ||
89 | REG(TEGRA30_SPDIF_CH_STA_RX_C), | ||
90 | REG(TEGRA30_SPDIF_CH_STA_RX_D), | ||
91 | REG(TEGRA30_SPDIF_CH_STA_RX_E), | ||
92 | REG(TEGRA30_SPDIF_CH_STA_RX_F), | ||
93 | REG(TEGRA30_SPDIF_CH_STA_TX_A), | ||
94 | REG(TEGRA30_SPDIF_CH_STA_TX_B), | ||
95 | REG(TEGRA30_SPDIF_CH_STA_TX_C), | ||
96 | REG(TEGRA30_SPDIF_CH_STA_TX_D), | ||
97 | REG(TEGRA30_SPDIF_CH_STA_TX_E), | ||
98 | REG(TEGRA30_SPDIF_CH_STA_TX_F), | ||
99 | REG(TEGRA30_SPDIF_FLOWCTL_CTRL), | ||
100 | REG(TEGRA30_SPDIF_TX_STEP), | ||
101 | REG(TEGRA30_SPDIF_FLOW_STATUS), | ||
102 | REG(TEGRA30_SPDIF_FLOW_TOTAL), | ||
103 | REG(TEGRA30_SPDIF_FLOW_OVER), | ||
104 | REG(TEGRA30_SPDIF_FLOW_UNDER), | ||
105 | REG(TEGRA30_SPDIF_LCOEF_1_4_0), | ||
106 | REG(TEGRA30_SPDIF_LCOEF_1_4_1), | ||
107 | REG(TEGRA30_SPDIF_LCOEF_1_4_2), | ||
108 | REG(TEGRA30_SPDIF_LCOEF_1_4_3), | ||
109 | REG(TEGRA30_SPDIF_LCOEF_1_4_4), | ||
110 | REG(TEGRA30_SPDIF_LCOEF_1_4_5), | ||
111 | REG(TEGRA30_SPDIF_LCOEF_2_4_0), | ||
112 | REG(TEGRA30_SPDIF_LCOEF_2_4_1), | ||
113 | REG(TEGRA30_SPDIF_LCOEF_2_4_2), | ||
114 | }; | ||
115 | #undef REG | ||
116 | |||
117 | struct tegra30_spdif *spdif = s->private; | ||
118 | int i; | ||
119 | |||
120 | tegra30_spdif_enable_clocks(spdif); | ||
121 | |||
122 | for (i = 0; i < ARRAY_SIZE(regs); i++) { | ||
123 | u32 val = tegra30_spdif_read(spdif, regs[i].offset); | ||
124 | seq_printf(s, "%s = %08x\n", regs[i].name, val); | ||
125 | } | ||
126 | |||
127 | tegra30_spdif_disable_clocks(spdif); | ||
128 | |||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | static int tegra30_spdif_debug_open(struct inode *inode, struct file *file) | ||
133 | { | ||
134 | return single_open(file, tegra30_spdif_show, inode->i_private); | ||
135 | } | ||
136 | |||
137 | static const struct file_operations tegra30_spdif_debug_fops = { | ||
138 | .open = tegra30_spdif_debug_open, | ||
139 | .read = seq_read, | ||
140 | .llseek = seq_lseek, | ||
141 | .release = single_release, | ||
142 | }; | ||
143 | |||
144 | static void tegra30_spdif_debug_add(struct tegra30_spdif *spdif) | ||
145 | { | ||
146 | char name[] = DRV_NAME; | ||
147 | |||
148 | spdif->debug = debugfs_create_file(name, S_IRUGO, snd_soc_debugfs_root, | ||
149 | spdif, &tegra30_spdif_debug_fops); | ||
150 | } | ||
151 | |||
152 | static void tegra30_spdif_debug_remove(struct tegra30_spdif *spdif) | ||
153 | { | ||
154 | if (spdif->debug) | ||
155 | debugfs_remove(spdif->debug); | ||
156 | } | ||
157 | #else | ||
158 | static inline void tegra30_spdif_debug_add(struct tegra30_spdif *spdif) | ||
159 | { | ||
160 | } | ||
161 | |||
162 | static inline void tegra30_spdif_debug_remove(struct tegra30_spdif *spdif) | ||
163 | { | ||
164 | } | ||
165 | #endif | ||
166 | |||
167 | int tegra30_spdif_startup(struct snd_pcm_substream *substream, | ||
168 | struct snd_soc_dai *dai) | ||
169 | { | ||
170 | struct tegra30_spdif *spdif = snd_soc_dai_get_drvdata(dai); | ||
171 | int ret = 0; | ||
172 | |||
173 | tegra30_spdif_enable_clocks(spdif); | ||
174 | |||
175 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
176 | ret = tegra30_ahub_allocate_tx_fifo(&spdif->txcif, | ||
177 | &spdif->playback_dma_data.addr, | ||
178 | &spdif->playback_dma_data.req_sel); | ||
179 | spdif->playback_dma_data.wrap = 4; | ||
180 | spdif->playback_dma_data.width = 32; | ||
181 | tegra30_ahub_set_rx_cif_source(TEGRA30_AHUB_RXCIF_SPDIF_RX0, | ||
182 | spdif->txcif); | ||
183 | } | ||
184 | |||
185 | tegra30_spdif_disable_clocks(spdif); | ||
186 | |||
187 | return ret; | ||
188 | } | ||
189 | |||
190 | void tegra30_spdif_shutdown(struct snd_pcm_substream *substream, | ||
191 | struct snd_soc_dai *dai) | ||
192 | { | ||
193 | struct tegra30_spdif *spdif = snd_soc_dai_get_drvdata(dai); | ||
194 | |||
195 | tegra30_spdif_enable_clocks(spdif); | ||
196 | |||
197 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
198 | tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_SPDIF_RX0); | ||
199 | tegra30_ahub_free_tx_fifo(spdif->txcif); | ||
200 | } | ||
201 | |||
202 | tegra30_spdif_disable_clocks(spdif); | ||
203 | } | ||
204 | |||
205 | static int tegra30_spdif_hw_params(struct snd_pcm_substream *substream, | ||
206 | struct snd_pcm_hw_params *params, | ||
207 | struct snd_soc_dai *dai) | ||
208 | { | ||
209 | struct device *dev = substream->pcm->card->dev; | ||
210 | struct tegra30_spdif *spdif = snd_soc_dai_get_drvdata(dai); | ||
211 | int ret, srate, spdifclock; | ||
212 | |||
213 | if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) { | ||
214 | dev_err(dev, "spdif capture is not supported\n"); | ||
215 | return -EINVAL; | ||
216 | } | ||
217 | |||
218 | spdif->reg_ctrl &= ~TEGRA30_SPDIF_CTRL_BIT_MODE_MASK; | ||
219 | switch (params_format(params)) { | ||
220 | case SNDRV_PCM_FORMAT_S16_LE: | ||
221 | spdif->reg_ctrl |= TEGRA30_SPDIF_CTRL_PACK_ENABLE; | ||
222 | spdif->reg_ctrl |= TEGRA30_SPDIF_CTRL_BIT_MODE_16BIT; | ||
223 | break; | ||
224 | default: | ||
225 | return -EINVAL; | ||
226 | } | ||
227 | |||
228 | srate = params_rate(params); | ||
229 | spdif->reg_ch_sta_a &= ~TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_MASK; | ||
230 | spdif->reg_ch_sta_b &= ~TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_MASK; | ||
231 | switch (srate) { | ||
232 | case 32000: | ||
233 | spdifclock = 4096000; | ||
234 | spdif->reg_ch_sta_a |= | ||
235 | TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_32000; | ||
236 | spdif->reg_ch_sta_b |= | ||
237 | TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_32000; | ||
238 | break; | ||
239 | case 44100: | ||
240 | spdifclock = 5644800; | ||
241 | spdif->reg_ch_sta_a |= | ||
242 | TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_44100; | ||
243 | spdif->reg_ch_sta_b |= | ||
244 | TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_44100; | ||
245 | break; | ||
246 | case 48000: | ||
247 | spdifclock = 6144000; | ||
248 | spdif->reg_ch_sta_a |= | ||
249 | TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_48000; | ||
250 | spdif->reg_ch_sta_b |= | ||
251 | TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_48000; | ||
252 | break; | ||
253 | case 88200: | ||
254 | spdifclock = 11289600; | ||
255 | spdif->reg_ch_sta_a |= | ||
256 | TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_88200; | ||
257 | spdif->reg_ch_sta_b |= | ||
258 | TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_88200; | ||
259 | break; | ||
260 | case 96000: | ||
261 | spdifclock = 12288000; | ||
262 | spdif->reg_ch_sta_a |= | ||
263 | TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_96000; | ||
264 | spdif->reg_ch_sta_b |= | ||
265 | TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_96000; | ||
266 | break; | ||
267 | case 176400: | ||
268 | spdifclock = 22579200; | ||
269 | spdif->reg_ch_sta_a |= | ||
270 | TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_176400; | ||
271 | spdif->reg_ch_sta_b |= | ||
272 | TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_176400; | ||
273 | break; | ||
274 | case 192000: | ||
275 | spdifclock = 24576000; | ||
276 | spdif->reg_ch_sta_a |= | ||
277 | TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_192000; | ||
278 | spdif->reg_ch_sta_b |= | ||
279 | TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_192000; | ||
280 | break; | ||
281 | default: | ||
282 | return -EINVAL; | ||
283 | } | ||
284 | |||
285 | ret = clk_set_rate(spdif->clk_spdif_out, spdifclock); | ||
286 | if (ret) { | ||
287 | dev_err(dev, "Can't set SPDIF clock rate: %d\n", ret); | ||
288 | return ret; | ||
289 | } | ||
290 | |||
291 | tegra30_spdif_enable_clocks(spdif); | ||
292 | |||
293 | tegra30_spdif_write(spdif, TEGRA30_SPDIF_CH_STA_TX_A, | ||
294 | spdif->reg_ch_sta_a); | ||
295 | tegra30_spdif_write(spdif, TEGRA30_SPDIF_CH_STA_TX_B, | ||
296 | spdif->reg_ch_sta_b); | ||
297 | |||
298 | tegra30_spdif_disable_clocks(spdif); | ||
299 | |||
300 | ret = tegra_hdmi_setup_audio_freq_source(srate, SPDIF); | ||
301 | if (ret) { | ||
302 | dev_err(dev, "Can't set HDMI audio freq source: %d\n", ret); | ||
303 | return ret; | ||
304 | } | ||
305 | |||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | static void tegra30_spdif_start_playback(struct tegra30_spdif *spdif) | ||
310 | { | ||
311 | tegra30_ahub_enable_tx_fifo(spdif->txcif); | ||
312 | spdif->reg_ctrl |= TEGRA30_SPDIF_CTRL_TX_EN_ENABLE | | ||
313 | TEGRA30_SPDIF_CTRL_TC_EN_ENABLE; | ||
314 | tegra30_spdif_write(spdif, TEGRA30_SPDIF_CTRL, spdif->reg_ctrl); | ||
315 | } | ||
316 | |||
317 | static void tegra30_spdif_stop_playback(struct tegra30_spdif *spdif) | ||
318 | { | ||
319 | tegra30_ahub_disable_tx_fifo(spdif->txcif); | ||
320 | spdif->reg_ctrl &= ~(TEGRA30_SPDIF_CTRL_TX_EN_ENABLE | | ||
321 | TEGRA30_SPDIF_CTRL_TC_EN_ENABLE); | ||
322 | tegra30_spdif_write(spdif, TEGRA30_SPDIF_CTRL, spdif->reg_ctrl); | ||
323 | } | ||
324 | |||
325 | static int tegra30_spdif_trigger(struct snd_pcm_substream *substream, int cmd, | ||
326 | struct snd_soc_dai *dai) | ||
327 | { | ||
328 | struct tegra30_spdif *spdif = snd_soc_dai_get_drvdata(dai); | ||
329 | |||
330 | switch (cmd) { | ||
331 | case SNDRV_PCM_TRIGGER_START: | ||
332 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
333 | case SNDRV_PCM_TRIGGER_RESUME: | ||
334 | tegra30_spdif_enable_clocks(spdif); | ||
335 | tegra30_spdif_start_playback(spdif); | ||
336 | break; | ||
337 | case SNDRV_PCM_TRIGGER_STOP: | ||
338 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
339 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
340 | tegra30_spdif_stop_playback(spdif); | ||
341 | tegra30_spdif_disable_clocks(spdif); | ||
342 | break; | ||
343 | default: | ||
344 | return -EINVAL; | ||
345 | } | ||
346 | |||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | static int tegra30_spdif_probe(struct snd_soc_dai *dai) | ||
351 | { | ||
352 | struct tegra30_spdif *spdif = snd_soc_dai_get_drvdata(dai); | ||
353 | |||
354 | dai->playback_dma_data = &spdif->playback_dma_data; | ||
355 | dai->capture_dma_data = NULL; | ||
356 | |||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | static struct snd_soc_dai_ops tegra30_spdif_dai_ops = { | ||
361 | .startup = tegra30_spdif_startup, | ||
362 | .shutdown = tegra30_spdif_shutdown, | ||
363 | .hw_params = tegra30_spdif_hw_params, | ||
364 | .trigger = tegra30_spdif_trigger, | ||
365 | }; | ||
366 | |||
367 | struct snd_soc_dai_driver tegra30_spdif_dai = { | ||
368 | .name = DRV_NAME, | ||
369 | .probe = tegra30_spdif_probe, | ||
370 | .playback = { | ||
371 | .channels_min = 2, | ||
372 | .channels_max = 2, | ||
373 | .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | | ||
374 | SNDRV_PCM_RATE_48000, | ||
375 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
376 | }, | ||
377 | .ops = &tegra30_spdif_dai_ops, | ||
378 | }; | ||
379 | |||
380 | static __devinit int tegra30_spdif_platform_probe(struct platform_device *pdev) | ||
381 | { | ||
382 | struct tegra30_spdif *spdif; | ||
383 | struct resource *mem, *memregion; | ||
384 | int ret; | ||
385 | u32 reg_val; | ||
386 | |||
387 | spdif = kzalloc(sizeof(struct tegra30_spdif), GFP_KERNEL); | ||
388 | if (!spdif) { | ||
389 | dev_err(&pdev->dev, "Can't allocate tegra30_spdif\n"); | ||
390 | ret = -ENOMEM; | ||
391 | goto exit; | ||
392 | } | ||
393 | dev_set_drvdata(&pdev->dev, spdif); | ||
394 | |||
395 | spdif->clk_spdif_out = clk_get(&pdev->dev, "spdif_out"); | ||
396 | if (IS_ERR(spdif->clk_spdif_out)) { | ||
397 | dev_err(&pdev->dev, "Can't retrieve spdif clock\n"); | ||
398 | ret = PTR_ERR(spdif->clk_spdif_out); | ||
399 | goto err_free; | ||
400 | } | ||
401 | |||
402 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
403 | if (!mem) { | ||
404 | dev_err(&pdev->dev, "No memory resource\n"); | ||
405 | ret = -ENODEV; | ||
406 | goto err_clk_put_spdif; | ||
407 | } | ||
408 | |||
409 | memregion = request_mem_region(mem->start, resource_size(mem), | ||
410 | DRV_NAME); | ||
411 | if (!memregion) { | ||
412 | dev_err(&pdev->dev, "Memory region already claimed\n"); | ||
413 | ret = -EBUSY; | ||
414 | goto err_clk_put_spdif; | ||
415 | } | ||
416 | |||
417 | spdif->regs = ioremap(mem->start, resource_size(mem)); | ||
418 | if (!spdif->regs) { | ||
419 | dev_err(&pdev->dev, "ioremap failed\n"); | ||
420 | ret = -ENOMEM; | ||
421 | goto err_release; | ||
422 | } | ||
423 | |||
424 | tegra30_spdif_enable_clocks(spdif); | ||
425 | |||
426 | reg_val = TEGRA30_SPDIF_CIF_TXD_CTRL_DIRECTION_RXCIF | | ||
427 | TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_BIT16 | | ||
428 | TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_BIT16 | | ||
429 | TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_CH2 | | ||
430 | TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_CH2 | | ||
431 | (3 << TEGRA30_SPDIF_CIF_TXD_CTRL_FIFO_TH_SHIFT); | ||
432 | |||
433 | tegra30_spdif_write(spdif, TEGRA30_SPDIF_CIF_TXD_CTRL, reg_val); | ||
434 | |||
435 | tegra30_spdif_disable_clocks(spdif); | ||
436 | |||
437 | ret = snd_soc_register_dai(&pdev->dev, &tegra30_spdif_dai); | ||
438 | if (ret) { | ||
439 | dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); | ||
440 | ret = -ENOMEM; | ||
441 | goto err_unmap; | ||
442 | } | ||
443 | |||
444 | tegra30_spdif_debug_add(spdif); | ||
445 | |||
446 | return 0; | ||
447 | |||
448 | err_unmap: | ||
449 | iounmap(spdif->regs); | ||
450 | err_release: | ||
451 | release_mem_region(mem->start, resource_size(mem)); | ||
452 | err_clk_put_spdif: | ||
453 | clk_put(spdif->clk_spdif_out); | ||
454 | err_free: | ||
455 | kfree(spdif); | ||
456 | exit: | ||
457 | return ret; | ||
458 | } | ||
459 | |||
460 | static int __devexit tegra30_spdif_platform_remove(struct platform_device *pdev) | ||
461 | { | ||
462 | struct tegra30_spdif *spdif = dev_get_drvdata(&pdev->dev); | ||
463 | struct resource *res; | ||
464 | |||
465 | snd_soc_unregister_dai(&pdev->dev); | ||
466 | |||
467 | tegra30_spdif_debug_remove(spdif); | ||
468 | |||
469 | iounmap(spdif->regs); | ||
470 | |||
471 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
472 | release_mem_region(res->start, resource_size(res)); | ||
473 | |||
474 | clk_put(spdif->clk_spdif_out); | ||
475 | |||
476 | kfree(spdif); | ||
477 | |||
478 | return 0; | ||
479 | } | ||
480 | |||
481 | static struct platform_driver tegra30_spdif_driver = { | ||
482 | .driver = { | ||
483 | .name = DRV_NAME, | ||
484 | .owner = THIS_MODULE, | ||
485 | }, | ||
486 | .probe = tegra30_spdif_platform_probe, | ||
487 | .remove = __devexit_p(tegra30_spdif_platform_remove), | ||
488 | }; | ||
489 | |||
490 | static int __init snd_tegra30_spdif_init(void) | ||
491 | { | ||
492 | return platform_driver_register(&tegra30_spdif_driver); | ||
493 | } | ||
494 | module_init(snd_tegra30_spdif_init); | ||
495 | |||
496 | static void __exit snd_tegra30_spdif_exit(void) | ||
497 | { | ||
498 | platform_driver_unregister(&tegra30_spdif_driver); | ||
499 | } | ||
500 | module_exit(snd_tegra30_spdif_exit); | ||
501 | |||
502 | MODULE_AUTHOR("Sumit Bhattacharya <sumitb@nvidia.com>"); | ||
503 | MODULE_DESCRIPTION("Tegra30 SPDIF ASoC driver"); | ||
504 | MODULE_LICENSE("GPL"); | ||
505 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/sound/soc/tegra/tegra30_spdif.h b/sound/soc/tegra/tegra30_spdif.h new file mode 100644 index 00000000000..c4763c31b25 --- /dev/null +++ b/sound/soc/tegra/tegra30_spdif.h | |||
@@ -0,0 +1,777 @@ | |||
1 | /* | ||
2 | * tegra30_spdif.h - Definitions for Tegra30 SPDIF driver | ||
3 | * | ||
4 | * Author: Sumit Bhattacharya <sumitb@nvidia.com> | ||
5 | * Copyright (C) 2011 - NVIDIA, Inc. | ||
6 | * | ||
7 | * Based on code copyright/by: | ||
8 | * | ||
9 | * Copyright (c) 2009-2011, NVIDIA Corporation. | ||
10 | * Scott Peterson <speterson@nvidia.com> | ||
11 | * | ||
12 | * Copyright (C) 2010 Google, Inc. | ||
13 | * Iliyan Malchev <malchev@google.com> | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or | ||
16 | * modify it under the terms of the GNU General Public License | ||
17 | * version 2 as published by the Free Software Foundation. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, but | ||
20 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
22 | * General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, write to the Free Software | ||
26 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
27 | * 02110-1301 USA | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #ifndef __TEGRA30_SPDIF_H__ | ||
32 | #define __TEGRA30_SPDIF_H__ | ||
33 | |||
34 | #include "tegra_pcm.h" | ||
35 | #include "tegra30_ahub.h" | ||
36 | |||
37 | /* Register offsets from TEGRA_SPDIF_BASE */ | ||
38 | |||
39 | #define TEGRA30_SPDIF_CTRL 0x0 | ||
40 | #define TEGRA30_SPDIF_STROBE_CTRL 0x4 | ||
41 | #define TEGRA30_SPDIF_CIF_TXD_CTRL 0x08 | ||
42 | #define TEGRA30_SPDIF_CIF_RXD_CTRL 0x0C | ||
43 | #define TEGRA30_SPDIF_CIF_TXU_CTRL 0x10 | ||
44 | #define TEGRA30_SPDIF_CIF_RXU_CTRL 0x14 | ||
45 | #define TEGRA30_SPDIF_CH_STA_RX_A 0x18 | ||
46 | #define TEGRA30_SPDIF_CH_STA_RX_B 0x1C | ||
47 | #define TEGRA30_SPDIF_CH_STA_RX_C 0x20 | ||
48 | #define TEGRA30_SPDIF_CH_STA_RX_D 0x24 | ||
49 | #define TEGRA30_SPDIF_CH_STA_RX_E 0x28 | ||
50 | #define TEGRA30_SPDIF_CH_STA_RX_F 0x2C | ||
51 | #define TEGRA30_SPDIF_CH_STA_TX_A 0x30 | ||
52 | #define TEGRA30_SPDIF_CH_STA_TX_B 0x34 | ||
53 | #define TEGRA30_SPDIF_CH_STA_TX_C 0x38 | ||
54 | #define TEGRA30_SPDIF_CH_STA_TX_D 0x3C | ||
55 | #define TEGRA30_SPDIF_CH_STA_TX_E 0x40 | ||
56 | #define TEGRA30_SPDIF_CH_STA_TX_F 0x44 | ||
57 | #define TEGRA30_SPDIF_FLOWCTL_CTRL 0x70 | ||
58 | #define TEGRA30_SPDIF_TX_STEP 0x74 | ||
59 | #define TEGRA30_SPDIF_FLOW_STATUS 0x78 | ||
60 | #define TEGRA30_SPDIF_FLOW_TOTAL 0x7c | ||
61 | #define TEGRA30_SPDIF_FLOW_OVER 0x80 | ||
62 | #define TEGRA30_SPDIF_FLOW_UNDER 0x84 | ||
63 | #define TEGRA30_SPDIF_LCOEF_1_4_0 0x88 | ||
64 | #define TEGRA30_SPDIF_LCOEF_1_4_1 0x8c | ||
65 | #define TEGRA30_SPDIF_LCOEF_1_4_2 0x90 | ||
66 | #define TEGRA30_SPDIF_LCOEF_1_4_3 0x94 | ||
67 | #define TEGRA30_SPDIF_LCOEF_1_4_4 0x98 | ||
68 | #define TEGRA30_SPDIF_LCOEF_1_4_5 0x9c | ||
69 | #define TEGRA30_SPDIF_LCOEF_2_4_0 0xa0 | ||
70 | #define TEGRA30_SPDIF_LCOEF_2_4_1 0xa4 | ||
71 | #define TEGRA30_SPDIF_LCOEF_2_4_2 0xa8 | ||
72 | |||
73 | /* Fields in TEGRA30_SPDIF_CTRL */ | ||
74 | #define TEGRA30_SPDIF_CTRL_FLOWCTL_EN_ENABLE (1<<31) | ||
75 | #define TEGRA30_SPDIF_CTRL_CAP_LC_LEFT_CH (1<<30) | ||
76 | #define TEGRA30_SPDIF_CTRL_RX_EN_ENABLE (1<<29) | ||
77 | #define TEGRA30_SPDIF_CTRL_TX_EN_ENABLE (1<<28) | ||
78 | #define TEGRA30_SPDIF_CTRL_TC_EN_ENABLE (1<<27) | ||
79 | #define TEGRA30_SPDIF_CTRL_TU_EN_ENABLE (1<<26) | ||
80 | #define TEGRA30_SPDIF_CTRL_IE_P_RSVD_ENABLE (1<<23) | ||
81 | #define TEGRA30_SPDIF_CTRL_IE_B_RSVD_ENABLE (1<<22) | ||
82 | #define TEGRA30_SPDIF_CTRL_IE_C_RSVD_ENABLE (1<<21) | ||
83 | #define TEGRA30_SPDIF_CTRL_IE_U_RSVD_ENABLE (1<<20) | ||
84 | #define TEGRA30_SPDIF_CTRL_LBK_EN_ENABLE (1<<15) | ||
85 | #define TEGRA30_SPDIF_CTRL_PACK_ENABLE (1<<14) | ||
86 | |||
87 | #define TEGRA30_SPDIF_BIT_MODE16 0 | ||
88 | #define TEGRA30_SPDIF_BIT_MODE20 1 | ||
89 | #define TEGRA30_SPDIF_BIT_MODE24 2 | ||
90 | #define TEGRA30_SPDIF_BIT_MODERAW 3 | ||
91 | |||
92 | #define TEGRA30_SPDIF_CTRL_BIT_MODE_SHIFT 12 | ||
93 | #define TEGRA30_SPDIF_CTRL_BIT_MODE_MASK (3 << TEGRA30_SPDIF_CTRL_BIT_MODE_SHIFT) | ||
94 | #define TEGRA30_SPDIF_CTRL_BIT_MODE_16BIT (TEGRA30_SPDIF_BIT_MODE16 << TEGRA30_SPDIF_CTRL_BIT_MODE_SHIFT) | ||
95 | #define TEGRA30_SPDIF_CTRL_BIT_MODE_20BIT (TEGRA30_SPDIF_BIT_MODE20 << TEGRA30_SPDIF_CTRL_BIT_MODE_SHIFT) | ||
96 | #define TEGRA30_SPDIF_CTRL_BIT_MODE_24BIT (TEGRA30_SPDIF_BIT_MODE24 << TEGRA30_SPDIF_CTRL_BIT_MODE_SHIFT) | ||
97 | #define TEGRA30_SPDIF_CTRL_BIT_MODE_RAW (TEGRA30_SPDIF_BIT_MODERAW << TEGRA30_SPDIF_CTRL_BIT_MODE_SHIFT) | ||
98 | |||
99 | #define TEGRA30_SPDIF_CTRL_CG_EN_ENABLE (1<<11) | ||
100 | |||
101 | #define TEGRA30_SPDIF_CTRL_OBS_SEL_SHIFT 8 | ||
102 | #define TEGRA30_SPDIF_CTRL_OBS_SEL_NASK (0x7 << TEGRA30_SPDIF_CTRL_OBS_SEL_SHIFT) | ||
103 | |||
104 | #define TEGRA30_SPDIF_CTRL_SOFT_RESET_ENABLE (1<<7) | ||
105 | |||
106 | /* Fields in TEGRA30_SPDIF_STROBE_CTRL */ | ||
107 | #define TEGRA30_SPDIF_STROBE_CTRL_PERIOD_SHIFT 16 | ||
108 | #define TEGRA30_SPDIF_STROBE_CTRL_PERIOD_MASK (0xff << TEGRA30_SPDIF_STROBE_CTRL_PERIOD_SHIFT) | ||
109 | |||
110 | #define TEGRA30_SPDIF_STROBE_CTRL_STROBE (1<<15) | ||
111 | |||
112 | #define TEGRA30_SPDIF_STROBE_CTRL_DATA_STROBES_SHIFT 8 | ||
113 | #define TEGRA30_SPDIF_STROBE_CTRL_DATA_STROBES_MASK (0x1f << TEGRA30_SPDIF_STROBE_CTRL_DATA_STROBES_SHIFT) | ||
114 | |||
115 | #define TEGRA30_SPDIF_STROBE_CTRL_CLOCK_PERIOD_SHIFT 0 | ||
116 | #define TEGRA30_SPDIF_STROBE_CTRL_CLOCK_PERIOD_MASK (0x3f << TEGRA30_SPDIF_STROBE_CTRL_CLOCK_PERIOD_SHIFT) | ||
117 | |||
118 | /* Fields in TEGRA30_SPDIF_CIF_TXD_CTRL */ | ||
119 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_MONO_CONV_COPY (1<<0) | ||
120 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_TRUNCATE_CHOP (1<<1) | ||
121 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_DIRECTION_RXCIF (1<<2) | ||
122 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_REPLICATE_ENABLE (1<<3) | ||
123 | |||
124 | #define TEGRA30_SPDIF_CIF_STEREO_CH0 0 | ||
125 | #define TEGRA30_SPDIF_CIF_STEREO_CH1 1 | ||
126 | #define TEGRA30_SPDIF_CIF_STEREO_AVG 2 | ||
127 | #define TEGRA30_SPDIF_CIF_STEREO_RSVD 3 | ||
128 | |||
129 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_STEREO_CONV_SHIFT 4 | ||
130 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_STEREO_CONV_MASK \ | ||
131 | (0x3 << TEGRA30_SPDIF_CIF_TXD_CTRL_STEREO_CONV_SHIFT) | ||
132 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_STEREO_CONV_CH0 \ | ||
133 | (TEGRA30_SPDIF_CIF_STEREO_CH0 << TEGRA30_SPDIF_CIF_TXD_CTRL_STEREO_CONV_SHIFT) | ||
134 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_STEREO_CONV_CH1 \ | ||
135 | (TEGRA30_SPDIF_CIF_STEREO_CH1 << TEGRA30_SPDIF_CIF_TXD_CTRL_STEREO_CONV_SHIFT) | ||
136 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_STEREO_CONV_AVG \ | ||
137 | (TEGRA30_SPDIF_CIF_STEREO_AVG << TEGRA30_SPDIF_CIF_TXD_CTRL_STEREO_CONV_SHIFT) | ||
138 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_STEREO_CONV_RSVD \ | ||
139 | (TEGRA30_SPDIF_CIF_STEREO_RSVD << TEGRA30_SPDIF_CIF_TXD_CTRL_STEREO_CONV_SHIFT) | ||
140 | |||
141 | #define TEGRA30_SPDIF_CIF_EXPAND_ZERO 0 | ||
142 | #define TEGRA30_SPDIF_CIF_EXPAND_ONE 1 | ||
143 | #define TEGRA30_SPDIF_CIF_EXPAND_LFSR 2 | ||
144 | #define TEGRA30_SPDIF_CIF_EXPAND_RSVD 3 | ||
145 | |||
146 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_EXPAND_SHIFT 6 | ||
147 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_EXPAND_MASK \ | ||
148 | (0x3 << TEGRA30_SPDIF_CIF_TXD_CTRL_EXPAND_SHIFT) | ||
149 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_EXPAND_ZERO \ | ||
150 | (TEGRA30_SPDIF_CIF_EXPAND_ZERO << TEGRA30_SPDIF_CIF_TXD_CTRL_EXPAND_SHIFT) | ||
151 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_EXPAND_ONE \ | ||
152 | (TEGRA30_SPDIF_CIF_EXPAND_ONE << TEGRA30_SPDIF_CIF_TXD_CTRL_EXPAND_SHIFT) | ||
153 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_EXPAND_LFSR \ | ||
154 | (TEGRA30_SPDIF_CIF_EXPAND_LFSR << TEGRA30_SPDIF_CIF_TXD_CTRL_EXPAND_SHIFT) | ||
155 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_EXPAND_RSVD \ | ||
156 | (TEGRA30_SPDIF_CIF_EXPAND_RSVD << TEGRA30_SPDIF_CIF_TXD_CTRL_EXPAND_SHIFT) | ||
157 | |||
158 | #define TEGRA30_SPDIF_CIF_BIT4 0 | ||
159 | #define TEGRA30_SPDIF_CIF_BIT8 1 | ||
160 | #define TEGRA30_SPDIF_CIF_BIT12 2 | ||
161 | #define TEGRA30_SPDIF_CIF_BIT16 3 | ||
162 | #define TEGRA30_SPDIF_CIF_BIT20 4 | ||
163 | #define TEGRA30_SPDIF_CIF_BIT24 5 | ||
164 | #define TEGRA30_SPDIF_CIF_BIT28 6 | ||
165 | #define TEGRA30_SPDIF_CIF_BIT32 7 | ||
166 | |||
167 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_BITS_SHIFT 8 | ||
168 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_BITS_MASK \ | ||
169 | (0x7 << TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_BITS_SHIFT) | ||
170 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_BIT4 \ | ||
171 | (TEGRA30_SPDIF_CIF_BIT4 << TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_BITS_SHIFT) | ||
172 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_BIT8 \ | ||
173 | (TEGRA30_SPDIF_CIF_BIT8 << TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_BITS_SHIFT) | ||
174 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_BIT12 \ | ||
175 | (TEGRA30_SPDIF_CIF_BIT12 << TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_BITS_SHIFT) | ||
176 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_BIT16 \ | ||
177 | (TEGRA30_SPDIF_CIF_BIT16 << TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_BITS_SHIFT) | ||
178 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_BIT20 \ | ||
179 | (TEGRA30_SPDIF_CIF_BIT20 << TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_BITS_SHIFT) | ||
180 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_BIT24 \ | ||
181 | (TEGRA30_SPDIF_CIF_BIT24 << TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_BITS_SHIFT) | ||
182 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_BIT28 \ | ||
183 | (TEGRA30_SPDIF_CIF_BIT28 << TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_BITS_SHIFT) | ||
184 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_BIT32 \ | ||
185 | (TEGRA30_SPDIF_CIF_BIT32 << TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_BITS_SHIFT) | ||
186 | |||
187 | |||
188 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_BITS_SHIFT 12 | ||
189 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_BITS_MASK \ | ||
190 | (0x7 << TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_BITS_SHIFT) | ||
191 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_BIT4 \ | ||
192 | (TEGRA30_SPDIF_CIF_BIT4 << TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_BITS_SHIFT) | ||
193 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_BIT8 \ | ||
194 | (TEGRA30_SPDIF_CIF_BIT8 << TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_BITS_SHIFT) | ||
195 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_BIT12 \ | ||
196 | (TEGRA30_SPDIF_CIF_BIT12 << TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_BITS_SHIFT) | ||
197 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_BIT16 \ | ||
198 | (TEGRA30_SPDIF_CIF_BIT16 << TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_BITS_SHIFT) | ||
199 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_BIT20 \ | ||
200 | (TEGRA30_SPDIF_CIF_BIT20 << TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_BITS_SHIFT) | ||
201 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_BIT24 \ | ||
202 | (TEGRA30_SPDIF_CIF_BIT24 << TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_BITS_SHIFT) | ||
203 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_BIT28 \ | ||
204 | (TEGRA30_SPDIF_CIF_BIT28 << TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_BITS_SHIFT) | ||
205 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_BIT32 \ | ||
206 | (TEGRA30_SPDIF_CIF_BIT32 << TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_BITS_SHIFT) | ||
207 | |||
208 | #define TEGRA30_SPDIF_CIF_CH1 0 | ||
209 | #define TEGRA30_SPDIF_CIF_CH2 1 | ||
210 | #define TEGRA30_SPDIF_CIF_CH3 2 | ||
211 | #define TEGRA30_SPDIF_CIF_CH4 3 | ||
212 | #define TEGRA30_SPDIF_CIF_CH5 4 | ||
213 | #define TEGRA30_SPDIF_CIF_CH6 5 | ||
214 | #define TEGRA30_SPDIF_CIF_CH7 6 | ||
215 | #define TEGRA30_SPDIF_CIF_CH8 7 | ||
216 | |||
217 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_CH_SHIFT 16 | ||
218 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_CH_MASK \ | ||
219 | (0x7 << TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_CH_SHIFT) | ||
220 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_CH1 \ | ||
221 | (TEGRA30_SPDIF_CIF_CH1 << TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_CH_SHIFT) | ||
222 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_CH2 \ | ||
223 | (TEGRA30_SPDIF_CIF_CH2 << TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_CH_SHIFT) | ||
224 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_CH3 \ | ||
225 | (TEGRA30_SPDIF_CIF_CH3 << TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_CH_SHIFT) | ||
226 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_CH4 \ | ||
227 | (TEGRA30_SPDIF_CIF_CH4 << TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_CH_SHIFT) | ||
228 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_CH5 \ | ||
229 | (TEGRA30_SPDIF_CIF_CH5 << TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_CH_SHIFT) | ||
230 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_CH6 \ | ||
231 | (TEGRA30_SPDIF_CIF_CH6 << TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_CH_SHIFT) | ||
232 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_CH7 \ | ||
233 | (TEGRA30_SPDIF_CIF_CH7 << TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_CH_SHIFT) | ||
234 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_CH8 \ | ||
235 | (TEGRA30_SPDIF_CIF_CH8 << TEGRA30_SPDIF_CIF_TXD_CTRL_CLIENT_CH_SHIFT) | ||
236 | |||
237 | |||
238 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_CH_SHIFT 24 | ||
239 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_CH_MASK \ | ||
240 | (0x7 << TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_CH_SHIFT) | ||
241 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_CH1 \ | ||
242 | (TEGRA30_SPDIF_CIF_CH1 << TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_CH_SHIFT) | ||
243 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_CH2 \ | ||
244 | (TEGRA30_SPDIF_CIF_CH2 << TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_CH_SHIFT) | ||
245 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_CH3 \ | ||
246 | (TEGRA30_SPDIF_CIF_CH3 << TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_CH_SHIFT) | ||
247 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_CH4 \ | ||
248 | (TEGRA30_SPDIF_CIF_CH4 << TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_CH_SHIFT) | ||
249 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_CH5 \ | ||
250 | (TEGRA30_SPDIF_CIF_CH5 << TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_CH_SHIFT) | ||
251 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_CH6 \ | ||
252 | (TEGRA30_SPDIF_CIF_CH6 << TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_CH_SHIFT) | ||
253 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_CH7 \ | ||
254 | (TEGRA30_SPDIF_CIF_CH7 << TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_CH_SHIFT) | ||
255 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_CH8 \ | ||
256 | (TEGRA30_SPDIF_CIF_CH8 << TEGRA30_SPDIF_CIF_TXD_CTRL_AUDIO_CH_SHIFT) | ||
257 | |||
258 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_FIFO_TH_SHIFT 28 | ||
259 | #define TEGRA30_SPDIF_CIF_TXD_CTRL_FIFO_TH_MASK (0x7 << TEGRA30_SPDIF_CIF_TXD_CTRL_FIFO_TH_SHIFT) | ||
260 | |||
261 | /* Fields in TEGRA30_TEGRA30_SPDIF_CIF_RXD_CTRL */ | ||
262 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_MONO_CONV_COPY (1<<0) | ||
263 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_TRUNCATE_CHOP (1<<1) | ||
264 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_DIRECTION_RXCIF (1<<2) | ||
265 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_REPLICATE_ENABLE (1<<3) | ||
266 | |||
267 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_STEREO_CONV_SHIFT 4 | ||
268 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_STEREO_CONV_MASK \ | ||
269 | (0x3 << TEGRA30_SPDIF_CIF_RXD_CTRL_STEREO_CONV_SHIFT) | ||
270 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_STEREO_CONV_CH0 \ | ||
271 | (TEGRA30_SPDIF_CIF_STEREO_CH0 << TEGRA30_SPDIF_CIF_RXD_CTRL_STEREO_CONV_SHIFT) | ||
272 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_STEREO_CONV_CH1 \ | ||
273 | (TEGRA30_SPDIF_CIF_STEREO_CH1 << TEGRA30_SPDIF_CIF_RXD_CTRL_STEREO_CONV_SHIFT) | ||
274 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_STEREO_CONV_AVG \ | ||
275 | (TEGRA30_SPDIF_CIF_STEREO_AVG << TEGRA30_SPDIF_CIF_RXD_CTRL_STEREO_CONV_SHIFT) | ||
276 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_STEREO_CONV_RSVD \ | ||
277 | (TEGRA30_SPDIF_CIF_STEREO_RSVD << TEGRA30_SPDIF_CIF_RXD_CTRL_STEREO_CONV_SHIFT) | ||
278 | |||
279 | |||
280 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_EXPAND_SHIFT 6 | ||
281 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_EXPAND_MASK \ | ||
282 | (0x3 << TEGRA30_SPDIF_CIF_RXD_CTRL_EXPAND_SHIFT) | ||
283 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_EXPAND_ZERO \ | ||
284 | (TEGRA30_SPDIF_CIF_EXPAND_ZERO << TEGRA30_SPDIF_CIF_RXD_CTRL_EXPAND_SHIFT) | ||
285 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_EXPAND_ONE \ | ||
286 | (TEGRA30_SPDIF_CIF_EXPAND_ONE << TEGRA30_SPDIF_CIF_RXD_CTRL_EXPAND_SHIFT) | ||
287 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_EXPAND_LFSR \ | ||
288 | (TEGRA30_SPDIF_CIF_EXPAND_LFSR << TEGRA30_SPDIF_CIF_RXD_CTRL_EXPAND_SHIFT) | ||
289 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_EXPAND_RSVD \ | ||
290 | |||
291 | |||
292 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_BITS_SHIFT 8 | ||
293 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_BITS_MASK \ | ||
294 | (0x7 << TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_BITS_SHIFT) | ||
295 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_BIT4 \ | ||
296 | (TEGRA30_SPDIF_CIF_BIT4 << TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_BITS_SHIFT) | ||
297 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_BIT8 \ | ||
298 | (TEGRA30_SPDIF_CIF_BIT8 << TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_BITS_SHIFT) | ||
299 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_BIT12 \ | ||
300 | (TEGRA30_SPDIF_CIF_BIT12 << TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_BITS_SHIFT) | ||
301 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_BIT16 \ | ||
302 | (TEGRA30_SPDIF_CIF_BIT16 << TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_BITS_SHIFT) | ||
303 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_BIT20 \ | ||
304 | (TEGRA30_SPDIF_CIF_BIT20 << TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_BITS_SHIFT) | ||
305 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_BIT24 \ | ||
306 | (TEGRA30_SPDIF_CIF_BIT24 << TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_BITS_SHIFT) | ||
307 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_BIT28 \ | ||
308 | (TEGRA30_SPDIF_CIF_BIT28 << TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_BITS_SHIFT) | ||
309 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_BIT32 \ | ||
310 | (TEGRA30_SPDIF_CIF_BIT32 << TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_BITS_SHIFT) | ||
311 | |||
312 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_BITS_SHIFT 12 | ||
313 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_BITS_MASK \ | ||
314 | (0x7 << TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_BITS_SHIFT) | ||
315 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_BIT4 \ | ||
316 | (TEGRA30_SPDIF_CIF_BIT4 << TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_BITS_SHIFT) | ||
317 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_BIT8 \ | ||
318 | (TEGRA30_SPDIF_CIF_BIT8 << TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_BITS_SHIFT) | ||
319 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_BIT12 \ | ||
320 | (TEGRA30_SPDIF_CIF_BIT12 << TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_BITS_SHIFT) | ||
321 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_BIT16 \ | ||
322 | (TEGRA30_SPDIF_CIF_BIT16 << TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_BITS_SHIFT) | ||
323 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_BIT20 \ | ||
324 | (TEGRA30_SPDIF_CIF_BIT20 << TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_BITS_SHIFT) | ||
325 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_BIT24 \ | ||
326 | (TEGRA30_SPDIF_CIF_BIT24 << TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_BITS_SHIFT) | ||
327 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_BIT28 \ | ||
328 | (TEGRA30_SPDIF_CIF_BIT28 << TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_BITS_SHIFT) | ||
329 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_BIT32 \ | ||
330 | (TEGRA30_SPDIF_CIF_BIT32 << TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_BITS_SHIFT) | ||
331 | |||
332 | |||
333 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_CH_SHIFT 16 | ||
334 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_CH_MASK \ | ||
335 | (0x7 << TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_CH_SHIFT) | ||
336 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_CH1 \ | ||
337 | (TEGRA30_SPDIF_CIF_CH1 << TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_CH_SHIFT) | ||
338 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_CH2 \ | ||
339 | (TEGRA30_SPDIF_CIF_CH2 << TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_CH_SHIFT) | ||
340 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_CH3 \ | ||
341 | (TEGRA30_SPDIF_CIF_CH3 << TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_CH_SHIFT) | ||
342 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_CH4 \ | ||
343 | (TEGRA30_SPDIF_CIF_CH4 << TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_CH_SHIFT) | ||
344 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_CH5 \ | ||
345 | (TEGRA30_SPDIF_CIF_CH5 << TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_CH_SHIFT) | ||
346 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_CH6 \ | ||
347 | (TEGRA30_SPDIF_CIF_CH6 << TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_CH_SHIFT) | ||
348 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_CH7 \ | ||
349 | (TEGRA30_SPDIF_CIF_CH7 << TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_CH_SHIFT) | ||
350 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_CH8 \ | ||
351 | (TEGRA30_SPDIF_CIF_CH8 << TEGRA30_SPDIF_CIF_RXD_CTRL_CLIENT_CH_SHIFT) | ||
352 | |||
353 | |||
354 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_CHANNELS_SHIFT 24 | ||
355 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_CHANNELS_MASK \ | ||
356 | (0x7 << TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_CHANNELS_SHIFT) | ||
357 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_CH1 \ | ||
358 | (TEGRA30_SPDIF_CIF_CH1 << TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_CHANNELS_SHIFT) | ||
359 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_CH2 \ | ||
360 | (TEGRA30_SPDIF_CIF_CH2 << TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_CHANNELS_SHIFT) | ||
361 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_CH3 \ | ||
362 | (TEGRA30_SPDIF_CIF_CH3 << TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_CHANNELS_SHIFT) | ||
363 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_CH4 \ | ||
364 | (TEGRA30_SPDIF_CIF_CH4 << TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_CHANNELS_SHIFT) | ||
365 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_CH5 \ | ||
366 | (TEGRA30_SPDIF_CIF_CH5 << TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_CHANNELS_SHIFT) | ||
367 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_CH6 \ | ||
368 | (TEGRA30_SPDIF_CIF_CH6 << TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_CHANNELS_SHIFT) | ||
369 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_CH7 \ | ||
370 | (TEGRA30_SPDIF_CIF_CH7 << TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_CHANNELS_SHIFT) | ||
371 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_CH8 \ | ||
372 | (TEGRA30_SPDIF_CIF_CH8 << TEGRA30_SPDIF_CIF_RXD_CTRL_AUDIO_CHANNELS_SHIFT) | ||
373 | |||
374 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_FIFO_TH_SHIFT 28 | ||
375 | #define TEGRA30_SPDIF_CIF_RXD_CTRL_FIFO_TH_MASK (0x7 << TEGRA30_SPDIF_CIF_RXD_CTRL_FIFO_TH_SHIFT) | ||
376 | |||
377 | /* Fields in TEGRA30_TEGRA30_SPDIF_CIF_TXU_CTRL */ | ||
378 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_MONO_CONV_COPY (1<<0) | ||
379 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_TRUNCATE_CHOP (1<<1) | ||
380 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_DIRECTION_RXCIF (1<<2) | ||
381 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_REPLICATE_ENABLE (1<<3) | ||
382 | |||
383 | |||
384 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_STEREO_CONV_SHIFT 4 | ||
385 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_STEREO_CONV_MASK \ | ||
386 | (0x3 << TEGRA30_SPDIF_CIF_TXU_CTRL_0_STEREO_CONV_SHIFT) | ||
387 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_STEREO_CONV_CH0 \ | ||
388 | (TEGRA30_SPDIF_CIF_STEREO_CH0 << TEGRA30_SPDIF_CIF_TXU_CTRL_0_STEREO_CONV_SHIFT) | ||
389 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_STEREO_CONV_CH1 \ | ||
390 | (TEGRA30_SPDIF_CIF_STEREO_CH1 << TEGRA30_SPDIF_CIF_TXU_CTRL_0_STEREO_CONV_SHIFT) | ||
391 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_STEREO_CONV_AVG \ | ||
392 | (TEGRA30_SPDIF_CIF_STEREO_AVG << TEGRA30_SPDIF_CIF_TXU_CTRL_0_STEREO_CONV_SHIFT) | ||
393 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_STEREO_CONV_RSVD \ | ||
394 | (TEGRA30_SPDIF_CIF_STEREO_RSVD << TEGRA30_SPDIF_CIF_TXU_CTRL_0_STEREO_CONV_SHIFT) | ||
395 | |||
396 | |||
397 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_EXPAND_SHIFT 6 | ||
398 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_EXPAND_MASK \ | ||
399 | (0x3 << TEGRA30_SPDIF_CIF_TXU_CTRL_EXPAND_SHIFT) | ||
400 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_EXPAND_ZERO \ | ||
401 | (TEGRA30_SPDIF_CIF_EXPAND_ZERO << TEGRA30_SPDIF_CIF_TXU_CTRL_EXPAND_SHIFT) | ||
402 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_EXPAND_ONE \ | ||
403 | (TEGRA30_SPDIF_CIF_EXPAND_ONE << TEGRA30_SPDIF_CIF_TXU_CTRL_EXPAND_SHIFT) | ||
404 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_EXPAND_LFSR \ | ||
405 | (TEGRA30_SPDIF_CIF_EXPAND_LFSR << TEGRA30_SPDIF_CIF_TXU_CTRL_EXPAND_SHIFT) | ||
406 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_EXPAND_RSVD \ | ||
407 | (TEGRA30_SPDIF_CIF_EXPAND_RSVD << TEGRA30_SPDIF_CIF_TXU_CTRL_EXPAND_SHIFT) | ||
408 | |||
409 | |||
410 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_BITS_SHIFT 8 | ||
411 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_BITS_MASK \ | ||
412 | (0x7 << TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_BITS_SHIFT) | ||
413 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_BIT4 \ | ||
414 | (TEGRA30_SPDIF_CIF_BIT4 << TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_BITS_SHIFT) | ||
415 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_BIT8 \ | ||
416 | (TEGRA30_SPDIF_CIF_BIT8 << TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_BITS_SHIFT) | ||
417 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_BIT12 \ | ||
418 | (TEGRA30_SPDIF_CIF_BIT12 << TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_BITS_SHIFT) | ||
419 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_BIT16 \ | ||
420 | (TEGRA30_SPDIF_CIF_BIT16 << TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_BITS_SHIFT) | ||
421 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_BIT20 \ | ||
422 | (TEGRA30_SPDIF_CIF_BIT20 << TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_BITS_SHIFT) | ||
423 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_BIT24 \ | ||
424 | (TEGRA30_SPDIF_CIF_BIT24 << TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_BITS_SHIFT) | ||
425 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_BIT28 \ | ||
426 | (TEGRA30_SPDIF_CIF_BIT28 << TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_BITS_SHIFT) | ||
427 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_BIT32 \ | ||
428 | (TEGRA30_SPDIF_CIF_BIT32 << TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_BITS_SHIFT) | ||
429 | |||
430 | |||
431 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_BITS_SHIFT 12 | ||
432 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_BITS_MASK \ | ||
433 | (0x7 << TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_BITS_SHIFT) | ||
434 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_BIT4 \ | ||
435 | (TEGRA30_SPDIF_CIF_BIT4 << TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_BITS_SHIFT) | ||
436 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_BIT8 \ | ||
437 | (TEGRA30_SPDIF_CIF_BIT8 << TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_BITS_SHIFT) | ||
438 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_BIT12 \ | ||
439 | (TEGRA30_SPDIF_CIF_BIT12 << TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_BITS_SHIFT) | ||
440 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_BIT16 \ | ||
441 | (TEGRA30_SPDIF_CIF_BIT16 << TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_BITS_SHIFT) | ||
442 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_BIT20 \ | ||
443 | (TEGRA30_SPDIF_CIF_BIT20 << TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_BITS_SHIFT) | ||
444 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_BIT24 \ | ||
445 | (TEGRA30_SPDIF_CIF_BIT24 << TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_BITS_SHIFT) | ||
446 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_BIT28 \ | ||
447 | (TEGRA30_SPDIF_CIF_BIT28 << TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_BITS_SHIFT) | ||
448 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_BIT32 \ | ||
449 | (TEGRA30_SPDIF_CIF_BIT32 << TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_BITS_SHIFT) | ||
450 | |||
451 | |||
452 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_CH_SHIFT 16 | ||
453 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_CH_MASK \ | ||
454 | (0x7 << TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_CH_SHIFT) | ||
455 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_CH1 \ | ||
456 | (TEGRA30_SPDIF_CIF_CH1 << TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_CH_SHIFT) | ||
457 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_CH2 \ | ||
458 | (TEGRA30_SPDIF_CIF_CH2 << TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_CH_SHIFT) | ||
459 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_CH3 \ | ||
460 | (TEGRA30_SPDIF_CIF_CH3 << TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_CH_SHIFT) | ||
461 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_CH4 \ | ||
462 | (TEGRA30_SPDIF_CIF_CH4 << TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_CH_SHIFT) | ||
463 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_CH5 \ | ||
464 | (TEGRA30_SPDIF_CIF_CH5 << TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_CH_SHIFT) | ||
465 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_CH6 \ | ||
466 | (TEGRA30_SPDIF_CIF_CH6 << TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_CH_SHIFT) | ||
467 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_CH7 \ | ||
468 | (TEGRA30_SPDIF_CIF_CH7 << TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_CH_SHIFT) | ||
469 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_CH8 \ | ||
470 | (TEGRA30_SPDIF_CIF_CH8 << TEGRA30_SPDIF_CIF_TXU_CTRL_CLIENT_CH_SHIFT) | ||
471 | |||
472 | |||
473 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_CH_SHIFT 24 | ||
474 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_CH_MASK \ | ||
475 | (0x7 << TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_CH_SHIFT) | ||
476 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_CH1 \ | ||
477 | (TEGRA30_SPDIF_CIF_CH1 << TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_CH_SHIFT) | ||
478 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_CH2 \ | ||
479 | (TEGRA30_SPDIF_CIF_CH2 << TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_CH_SHIFT) | ||
480 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_CH3 \ | ||
481 | (TEGRA30_SPDIF_CIF_CH3 << TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_CH_SHIFT) | ||
482 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_CH4 \ | ||
483 | (TEGRA30_SPDIF_CIF_CH4 << TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_CH_SHIFT) | ||
484 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_CH5 \ | ||
485 | (TEGRA30_SPDIF_CIF_CH5 << TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_CH_SHIFT) | ||
486 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_CH6 \ | ||
487 | (TEGRA30_SPDIF_CIF_CH6 << TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_CH_SHIFT) | ||
488 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_CH7 \ | ||
489 | (TEGRA30_SPDIF_CIF_CH7 << TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_CH_SHIFT) | ||
490 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_CH8 \ | ||
491 | (TEGRA30_SPDIF_CIF_CH8 << TEGRA30_SPDIF_CIF_TXU_CTRL_AUDIO_CH_SHIFT) | ||
492 | |||
493 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_FIFO_TH_SHIFT 28 | ||
494 | #define TEGRA30_SPDIF_CIF_TXU_CTRL_FIFO_TH_MASK (0x7 << TEGRA30_SPDIF_CIF_TXU_CTRL_FIFO_TH_SHIFT) | ||
495 | |||
496 | /* Fields in TEGRA30_TEGRA30_SPDIF_CIF_RXU_CTRL */ | ||
497 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_MONO_CONV_COPY (1<<0) | ||
498 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_TRUNCATE_CHOP (1<<1) | ||
499 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_DIRECTION_RXCIF (1<<2) | ||
500 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_REPLICATE_ENABLE (1<<3) | ||
501 | |||
502 | |||
503 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_STEREO_CONV_SHIFT 4 | ||
504 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_STEREO_CONV_MASK \ | ||
505 | (0x3 << TEGRA30_SPDIF_CIF_RXU_CTRL_0_STEREO_CONV_SHIFT) | ||
506 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_STEREO_CONV_CH0 \ | ||
507 | (TEGRA30_SPDIF_CIF_STEREO_CH0 << TEGRA30_SPDIF_CIF_RXU_CTRL_0_STEREO_CONV_SHIFT) | ||
508 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_STEREO_CONV_CH1 \ | ||
509 | (TEGRA30_SPDIF_CIF_STEREO_CH1 << TEGRA30_SPDIF_CIF_RXU_CTRL_0_STEREO_CONV_SHIFT) | ||
510 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_STEREO_CONV_AVG \ | ||
511 | (TEGRA30_SPDIF_CIF_STEREO_AVG << TEGRA30_SPDIF_CIF_RXU_CTRL_0_STEREO_CONV_SHIFT) | ||
512 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_STEREO_CONV_RSVD \ | ||
513 | (TEGRA30_SPDIF_CIF_STEREO_RSVD << TEGRA30_SPDIF_CIF_RXU_CTRL_0_STEREO_CONV_SHIFT) | ||
514 | |||
515 | |||
516 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_EXPAND_SHIFT 6 | ||
517 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_EXPAND_MASK \ | ||
518 | (0x3 << TEGRA30_SPDIF_CIF_RXU_CTRL_EXPAND_SHIFT) | ||
519 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_EXPAND_ZERO \ | ||
520 | (TEGRA30_SPDIF_CIF_EXPAND_ZERO << TEGRA30_SPDIF_CIF_RXU_CTRL_EXPAND_SHIFT) | ||
521 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_EXPAND_ONE \ | ||
522 | (TEGRA30_SPDIF_CIF_EXPAND_ONE << TEGRA30_SPDIF_CIF_RXU_CTRL_EXPAND_SHIFT) | ||
523 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_EXPAND_LFSR \ | ||
524 | (TEGRA30_SPDIF_CIF_EXPAND_LFSR << TEGRA30_SPDIF_CIF_RXU_CTRL_EXPAND_SHIFT) | ||
525 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_EXPAND_RSVD \ | ||
526 | (TEGRA30_SPDIF_CIF_EXPAND_RSVD << TEGRA30_SPDIF_CIF_RXU_CTRL_EXPAND_SHIFT) | ||
527 | |||
528 | |||
529 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_BITS_SHIFT 8 | ||
530 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_BITS_MASK \ | ||
531 | (0x7 << TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_BITS_SHIFT) | ||
532 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_BIT4 \ | ||
533 | (TEGRA30_SPDIF_CIF_BIT4 << TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_BITS_SHIFT) | ||
534 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_BIT8 \ | ||
535 | (TEGRA30_SPDIF_CIF_BIT8 << TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_BITS_SHIFT) | ||
536 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_BIT12 \ | ||
537 | (TEGRA30_SPDIF_CIF_BIT12 << TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_BITS_SHIFT) | ||
538 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_BIT16 \ | ||
539 | (TEGRA30_SPDIF_CIF_BIT16 << TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_BITS_SHIFT) | ||
540 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_BIT20 \ | ||
541 | (TEGRA30_SPDIF_CIF_BIT20 << TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_BITS_SHIFT) | ||
542 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_BIT24 \ | ||
543 | (TEGRA30_SPDIF_CIF_BIT24 << TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_BITS_SHIFT) | ||
544 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_BIT28 \ | ||
545 | (TEGRA30_SPDIF_CIF_BIT28 << TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_BITS_SHIFT) | ||
546 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_BIT32 \ | ||
547 | (TEGRA30_SPDIF_CIF_BIT32 << TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_BITS_SHIFT) | ||
548 | |||
549 | |||
550 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_BITS_SHIFT 12 | ||
551 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_BITS_MASK \ | ||
552 | (0x7 << TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_BITS_SHIFT) | ||
553 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_BIT4 \ | ||
554 | (TEGRA30_SPDIF_CIF_BIT4 << TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_BITS_SHIFT) | ||
555 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_BIT8 \ | ||
556 | (TEGRA30_SPDIF_CIF_BIT8 << TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_BITS_SHIFT) | ||
557 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_BIT12 \ | ||
558 | (TEGRA30_SPDIF_CIF_BIT12 << TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_BITS_SHIFT) | ||
559 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_BIT16 \ | ||
560 | (TEGRA30_SPDIF_CIF_BIT16 << TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_BITS_SHIFT) | ||
561 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_BIT20 \ | ||
562 | (TEGRA30_SPDIF_CIF_BIT20 << TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_BITS_SHIFT) | ||
563 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_BIT24 \ | ||
564 | (TEGRA30_SPDIF_CIF_BIT24 << TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_BITS_SHIFT) | ||
565 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_BIT28 \ | ||
566 | (TEGRA30_SPDIF_CIF_BIT28 << TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_BITS_SHIFT) | ||
567 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_BIT32 \ | ||
568 | (TEGRA30_SPDIF_CIF_BIT32 << TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_BITS_SHIFT) | ||
569 | |||
570 | |||
571 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_CH_SHIFT 16 | ||
572 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_CH_MASK \ | ||
573 | (0x7 << TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_CH_SHIFT) | ||
574 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_CH1 \ | ||
575 | (TEGRA30_SPDIF_CIF_CH1 << TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_CH_SHIFT) | ||
576 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_CH2 \ | ||
577 | (TEGRA30_SPDIF_CIF_CH2 << TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_CH_SHIFT) | ||
578 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_CH3 \ | ||
579 | (TEGRA30_SPDIF_CIF_CH3 << TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_CH_SHIFT) | ||
580 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_CH4 \ | ||
581 | (TEGRA30_SPDIF_CIF_CH4 << TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_CH_SHIFT) | ||
582 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_CH5 \ | ||
583 | (TEGRA30_SPDIF_CIF_CH5 << TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_CH_SHIFT) | ||
584 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_CH6 \ | ||
585 | (TEGRA30_SPDIF_CIF_CH6 << TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_CH_SHIFT) | ||
586 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_CH7 \ | ||
587 | (TEGRA30_SPDIF_CIF_CH7 << TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_CH_SHIFT) | ||
588 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_CH8 \ | ||
589 | (TEGRA30_SPDIF_CIF_CH8 << TEGRA30_SPDIF_CIF_RXU_CTRL_CLIENT_CH_SHIFT) | ||
590 | |||
591 | |||
592 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_CH_SHIFT 24 | ||
593 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_CH_MASK \ | ||
594 | (0x7 << TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_CH_SHIFT) | ||
595 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_CH1 \ | ||
596 | (TEGRA30_SPDIF_CIF_CH1 << TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_CH_SHIFT) | ||
597 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_CH2 \ | ||
598 | (TEGRA30_SPDIF_CIF_CH2 << TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_CH_SHIFT) | ||
599 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_CH3 \ | ||
600 | (TEGRA30_SPDIF_CIF_CH3 << TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_CH_SHIFT) | ||
601 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_CH4 \ | ||
602 | (TEGRA30_SPDIF_CIF_CH4 << TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_CH_SHIFT) | ||
603 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_CH5 \ | ||
604 | (TEGRA30_SPDIF_CIF_CH5 << TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_CH_SHIFT) | ||
605 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_CH6 \ | ||
606 | (TEGRA30_SPDIF_CIF_CH6 << TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_CH_SHIFT) | ||
607 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_CH7 \ | ||
608 | (TEGRA30_SPDIF_CIF_CH7 << TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_CH_SHIFT) | ||
609 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_CH8 \ | ||
610 | (TEGRA30_SPDIF_CIF_CH8 << TEGRA30_SPDIF_CIF_RXU_CTRL_AUDIO_CH_SHIFT) | ||
611 | |||
612 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_FIFO_TH_SHIFT 28 | ||
613 | #define TEGRA30_SPDIF_CIF_RXU_CTRL_FIFO_TH_MASK (0x7 << TEGRA30_SPDIF_CIF_RXU_CTRL_FIFO_TH_SHIFT) | ||
614 | |||
615 | /* Fields in TEGRA30_SPDIF_CH_STA_RX_A */ | ||
616 | /* Fields in TEGRA30_SPDIF_CH_STA_RX_B */ | ||
617 | /* Fields in TEGRA30_SPDIF_CH_STA_RX_C */ | ||
618 | /* Fields in TEGRA30_SPDIF_CH_STA_RX_D */ | ||
619 | /* Fields in TEGRA30_SPDIF_CH_STA_RX_E */ | ||
620 | /* Fields in TEGRA30_SPDIF_CH_STA_RX_F */ | ||
621 | |||
622 | /* | ||
623 | * The 6-word receive channel data page buffer holds a block (192 frames) of | ||
624 | * channel status information. The order of receive is from LSB to MSB | ||
625 | * bit, and from CH_STA_RX_A to CH_STA_RX_F then back to CH_STA_RX_A. | ||
626 | */ | ||
627 | |||
628 | /* Fields in TEGRA30_SPDIF_CH_STA_TX_A */ | ||
629 | #define TEGRA30_SPDIF_CH_STA_TX_A_SF_22050 0x4 | ||
630 | #define TEGRA30_SPDIF_CH_STA_TX_A_SF_24000 0x6 | ||
631 | #define TEGRA30_SPDIF_CH_STA_TX_A_SF_32000 0x3 | ||
632 | #define TEGRA30_SPDIF_CH_STA_TX_A_SF_44100 0x0 | ||
633 | #define TEGRA30_SPDIF_CH_STA_TX_A_SF_48000 0x2 | ||
634 | #define TEGRA30_SPDIF_CH_STA_TX_A_SF_88200 0x8 | ||
635 | #define TEGRA30_SPDIF_CH_STA_TX_A_SF_96000 0xA | ||
636 | #define TEGRA30_SPDIF_CH_STA_TX_A_SF_176400 0xC | ||
637 | #define TEGRA30_SPDIF_CH_STA_TX_A_SF_192000 0xE | ||
638 | |||
639 | #define TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT 24 | ||
640 | #define TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_MASK \ | ||
641 | (0xF << TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT) | ||
642 | #define TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_22050 \ | ||
643 | (TEGRA30_SPDIF_CH_STA_TX_A_SF_22050 << TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT) | ||
644 | #define TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_24000 \ | ||
645 | (TEGRA30_SPDIF_CH_STA_TX_A_SF_24000 << TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT) | ||
646 | #define TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_32000 \ | ||
647 | (TEGRA30_SPDIF_CH_STA_TX_A_SF_32000 << TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT) | ||
648 | #define TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_44100 \ | ||
649 | (TEGRA30_SPDIF_CH_STA_TX_A_SF_44100 << TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT) | ||
650 | #define TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_48000 \ | ||
651 | (TEGRA30_SPDIF_CH_STA_TX_A_SF_48000 << TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT) | ||
652 | #define TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_88200 \ | ||
653 | (TEGRA30_SPDIF_CH_STA_TX_A_SF_88200 << TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT) | ||
654 | #define TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_96000 \ | ||
655 | (TEGRA30_SPDIF_CH_STA_TX_A_SF_96000 << TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT) | ||
656 | #define TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_176400 \ | ||
657 | (TEGRA30_SPDIF_CH_STA_TX_A_SF_176400 << TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT) | ||
658 | #define TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_192000 \ | ||
659 | (TEGRA30_SPDIF_CH_STA_TX_A_SF_192000 << TEGRA30_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT) | ||
660 | |||
661 | /* Fields in TEGRA30_SPDIF_CH_STA_TX_B */ | ||
662 | #define TEGRA30_SPDIF_CH_STA_TX_B_SF_8000 0x6 | ||
663 | #define TEGRA30_SPDIF_CH_STA_TX_B_SF_11025 0xA | ||
664 | #define TEGRA30_SPDIF_CH_STA_TX_B_SF_12000 0x2 | ||
665 | #define TEGRA30_SPDIF_CH_STA_TX_B_SF_16000 0x8 | ||
666 | #define TEGRA30_SPDIF_CH_STA_TX_B_SF_22050 0xB | ||
667 | #define TEGRA30_SPDIF_CH_STA_TX_B_SF_24000 0x9 | ||
668 | #define TEGRA30_SPDIF_CH_STA_TX_B_SF_32000 0xC | ||
669 | #define TEGRA30_SPDIF_CH_STA_TX_B_SF_44100 0xF | ||
670 | #define TEGRA30_SPDIF_CH_STA_TX_B_SF_48000 0xD | ||
671 | #define TEGRA30_SPDIF_CH_STA_TX_B_SF_88200 0x7 | ||
672 | #define TEGRA30_SPDIF_CH_STA_TX_B_SF_96000 0x5 | ||
673 | #define TEGRA30_SPDIF_CH_STA_TX_B_SF_176400 0x3 | ||
674 | #define TEGRA30_SPDIF_CH_STA_TX_B_SF_192000 0x1 | ||
675 | |||
676 | #define TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT 4 | ||
677 | #define TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_MASK \ | ||
678 | (0xF << TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT) | ||
679 | #define TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_8000 \ | ||
680 | (TEGRA30_SPDIF_CH_STA_TX_B_SF_8000 << TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT) | ||
681 | #define TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_11025 \ | ||
682 | (TEGRA30_SPDIF_CH_STA_TX_B_SF_11025 << TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT) | ||
683 | #define TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_12000 \ | ||
684 | (TEGRA30_SPDIF_CH_STA_TX_B_SF_12000 << TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT) | ||
685 | #define TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_16000 \ | ||
686 | (TEGRA30_SPDIF_CH_STA_TX_B_SF_16000 << TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT) | ||
687 | #define TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_22050 \ | ||
688 | (TEGRA30_SPDIF_CH_STA_TX_B_SF_22025 << TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT) | ||
689 | #define TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_24000 \ | ||
690 | (TEGRA30_SPDIF_CH_STA_TX_B_SF_24000 << TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT) | ||
691 | #define TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_32000 \ | ||
692 | (TEGRA30_SPDIF_CH_STA_TX_B_SF_32000 << TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT) | ||
693 | #define TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_44100 \ | ||
694 | (TEGRA30_SPDIF_CH_STA_TX_B_SF_44100 << TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT) | ||
695 | #define TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_48000 \ | ||
696 | (TEGRA30_SPDIF_CH_STA_TX_B_SF_48000 << TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT) | ||
697 | #define TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_88200 \ | ||
698 | (TEGRA30_SPDIF_CH_STA_TX_B_SF_88200 << TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT) | ||
699 | #define TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_96000 \ | ||
700 | (TEGRA30_SPDIF_CH_STA_TX_B_SF_96000 << TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT) | ||
701 | #define TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_176400 \ | ||
702 | (TEGRA30_SPDIF_CH_STA_TX_B_SF_176400 << TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT) | ||
703 | #define TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_192000 \ | ||
704 | (TEGRA30_SPDIF_CH_STA_TX_B_SF_192000 << TEGRA30_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT) | ||
705 | |||
706 | /* Fields in TEGRA30_SPDIF_CH_STA_TX_C */ | ||
707 | /* Fields in TEGRA30_SPDIF_CH_STA_TX_D */ | ||
708 | /* Fields in TEGRA30_SPDIF_CH_STA_TX_E */ | ||
709 | /* Fields in TEGRA30_SPDIF_CH_STA_TX_F */ | ||
710 | |||
711 | /* Fields in TEGRA30_SPDIF_FLOWCTL_CTRL */ | ||
712 | #define TEGRA30_SPDIF_FLOWCTL_CTRL_FILTER_QUAD (1<<31) | ||
713 | |||
714 | /* Fields in TEGRA30_SPDIF_TX_STEP */ | ||
715 | #define TEGRA30_SPDIF_TX_STEP_STEP_SIZE_SHIFT 0 | ||
716 | #define TEGRA30_SPDIF_TX_STEP_STEP_SIZE_MASK (0xffff << TEGRA30_SPDIF_TX_STEP_STEP_SIZE_SHIFT) | ||
717 | |||
718 | /* Fields in TEGRA30_SPDIF_FLOW_STATUS */ | ||
719 | #define TEGRA30_SPDIF_FLOW_STATUS_COUNTER_EN_ENABLE (1<<1) | ||
720 | #define TEGRA30_SPDIF_FLOW_STATUS_MONITOR_CLR_CLEAR (1<<2) | ||
721 | #define TEGRA30_SPDIF_FLOW_STATUS_COUNTER_CLR_CLEAR (1<<3) | ||
722 | #define TEGRA30_SPDIF_FLOW_STATUS_MONITOR_INT_EN_ENABLE (1<<4) | ||
723 | #define TEGRA30_SPDIF_FLOW_STATUS_FLOW_OVERFLOW_OVER (1<<30) | ||
724 | #define TEGRA30_SPDIF_FLOW_STATUS_FLOW_UNDERFLOW_UNDER (1<<31) | ||
725 | |||
726 | /* Fields in TEGRA30_SPDIF_FLOW_TOTAL */ | ||
727 | /* Fields in TEGRA30_SPDIF_FLOW_OVER */ | ||
728 | /* Fields in TEGRA30_SPDIF_FLOW_UNDER */ | ||
729 | |||
730 | /* Fields in TEGRA30_SPDIF_LCOEF_1_4_0 */ | ||
731 | #define TEGRA30_SPDIF_LCOEF_1_4_0_COEF_SHIFT 0 | ||
732 | #define TEGRA30_SPDIF_LCOEF_1_4_0_COEF_MASK (0xffff << TEGRA30_TEGRA30_SPDIF_LCOEF_1_4_0_COEF_SHIFT) | ||
733 | |||
734 | /* Fields in TEGRA30_SPDIF_LCOEF_1_4_1 */ | ||
735 | #define TEGRA30_SPDIF_LCOEF_1_4_1_COEF_SHIFT 0 | ||
736 | #define TEGRA30_SPDIF_LCOEF_1_4_1_COEF_MASK (0xffff << TEGRA30_SPDIF_LCOEF_1_4_1_COEF_SHIFT) | ||
737 | |||
738 | /* Fields in TEGRA30_SPDIF_LCOEF_1_4_2 */ | ||
739 | #define TEGRA30_SPDIF_LCOEF_1_4_2_COEF_SHIFT 0 | ||
740 | #define TEGRA30_SPDIF_LCOEF_1_4_2_COEF_MASK (0xffff << TEGRA30_SPDIF_LCOEF_1_4_2_COEF_SHIFT) | ||
741 | |||
742 | /* Fields in TEGRA30_SPDIF_LCOEF_1_4_3 */ | ||
743 | #define TEGRA30_SPDIF_LCOEF_1_4_3_COEF_SHIFT 0 | ||
744 | #define TEGRA30_SPDIF_LCOEF_1_4_3_COEF_MASK (0xffff << TEGRA30_SPDIF_LCOEF_1_4_3_COEF_SHIFT) | ||
745 | |||
746 | /* Fields in TEGRA30_SPDIF_LCOEF_1_4_4 */ | ||
747 | #define TEGRA30_SPDIF_LCOEF_1_4_4_COEF_SHIFT 0 | ||
748 | #define TEGRA30_SPDIF_LCOEF_1_4_4_COEF_MASK (0xffff << TEGRA30_SPDIF_LCOEF_1_4_4_COEF_SHIFT) | ||
749 | |||
750 | /* Fields in TEGRA30_SPDIF_LCOEF_1_4_5 */ | ||
751 | #define TEGRA30_SPDIF_LCOEF_1_4_5_COEF_SHIFT 0 | ||
752 | #define TEGRA30_SPDIF_LCOEF_1_4_5_COEF_MASK (0xffff << TEGRA30_SPDIF_LCOEF_1_4_5_COEF_SHIFT) | ||
753 | |||
754 | /* Fields in TEGRA30_SPDIF_LCOEF_2_4_0 */ | ||
755 | #define TEGRA30_SPDIF_LCOEF_2_4_0_COEF_SHIFT 0 | ||
756 | #define TEGRA30_SPDIF_LCOEF_2_4_0_COEF_MASK (0xffff << TEGRA30_SPDIF_LCOEF_2_4_0_COEF_SHIFT) | ||
757 | |||
758 | /* Fields in TEGRA30_SPDIF_LCOEF_2_4_1 */ | ||
759 | #define TEGRA30_SPDIF_LCOEF_2_4_1_COEF_SHIFT 0 | ||
760 | #define TEGRA30_SPDIF_LCOEF_2_4_1_COEF_MASK (0xffff << TEGRA30_SPDIF_LCOEF_2_4_1_COEF_SHIFT) | ||
761 | |||
762 | /* Fields in TEGRA30_SPDIF_LCOEF_2_4_2 */ | ||
763 | #define TEGRA30_SPDIF_LCOEF_2_4_2_COEF_SHIFT 0 | ||
764 | #define TEGRA30_SPDIF_LCOEF_2_4_2_COEF_MASK (0xffff << SPDIF_LCOEF_2_4_2_COEF_SHIFT) | ||
765 | |||
766 | struct tegra30_spdif { | ||
767 | struct clk *clk_spdif_out; | ||
768 | enum tegra30_ahub_txcif txcif; | ||
769 | struct tegra_pcm_dma_params playback_dma_data; | ||
770 | void __iomem *regs; | ||
771 | struct dentry *debug; | ||
772 | u32 reg_ctrl; | ||
773 | u32 reg_ch_sta_a; | ||
774 | u32 reg_ch_sta_b; | ||
775 | }; | ||
776 | |||
777 | #endif | ||
diff --git a/sound/soc/tegra/tegra_aic326x.c b/sound/soc/tegra/tegra_aic326x.c new file mode 100644 index 00000000000..6d38934138b --- /dev/null +++ b/sound/soc/tegra/tegra_aic326x.c | |||
@@ -0,0 +1,1281 @@ | |||
1 | /* | ||
2 | * tegra_aic326x.c - Tegra machine ASoC driver for boards using TI 3262 codec. | ||
3 | * | ||
4 | * Author: Vinod G. <vinodg@nvidia.com> | ||
5 | * Copyright (C) 2011 - NVIDIA, Inc. | ||
6 | * | ||
7 | * Based on code copyright/by: | ||
8 | * | ||
9 | * (c) 2010, 2011 Nvidia Graphics Pvt. Ltd. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * version 2 as published by the Free Software Foundation. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, but | ||
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | * General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
23 | * 02110-1301 USA | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include <asm/mach-types.h> | ||
28 | |||
29 | #include <linux/module.h> | ||
30 | #include <linux/platform_device.h> | ||
31 | #include <linux/slab.h> | ||
32 | #include <linux/gpio.h> | ||
33 | #include <linux/regulator/consumer.h> | ||
34 | #ifdef CONFIG_SWITCH | ||
35 | #include <linux/switch.h> | ||
36 | #endif | ||
37 | |||
38 | #include <mach/tegra_aic326x_pdata.h> | ||
39 | |||
40 | #include <sound/core.h> | ||
41 | #include <sound/jack.h> | ||
42 | #include <sound/pcm.h> | ||
43 | #include <sound/pcm_params.h> | ||
44 | #include <sound/soc.h> | ||
45 | |||
46 | #include "../codecs/tlv320aic326x.h" | ||
47 | |||
48 | #include "tegra_pcm.h" | ||
49 | #include "tegra_asoc_utils.h" | ||
50 | |||
51 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
52 | #include "tegra20_das.h" | ||
53 | #else | ||
54 | #include "tegra30_ahub.h" | ||
55 | #include "tegra30_i2s.h" | ||
56 | #include "tegra30_dam.h" | ||
57 | #endif | ||
58 | |||
59 | |||
60 | #define DRV_NAME "tegra-snd-aic326x" | ||
61 | |||
62 | #define GPIO_SPKR_EN BIT(0) | ||
63 | #define GPIO_HP_MUTE BIT(1) | ||
64 | #define GPIO_INT_MIC_EN BIT(2) | ||
65 | #define GPIO_EXT_MIC_EN BIT(3) | ||
66 | |||
67 | #define DAI_LINK_HIFI 0 | ||
68 | #define DAI_LINK_SPDIF 1 | ||
69 | #define DAI_LINK_BTSCO 2 | ||
70 | #define DAI_LINK_VOICE_CALL 3 | ||
71 | #define DAI_LINK_BT_VOICE_CALL 4 | ||
72 | #define NUM_DAI_LINKS 5 | ||
73 | |||
74 | extern int g_is_call_mode; | ||
75 | |||
76 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
77 | const char *tegra_i2s_dai_name[TEGRA30_NR_I2S_IFC] = { | ||
78 | "tegra30-i2s.0", | ||
79 | "tegra30-i2s.1", | ||
80 | "tegra30-i2s.2", | ||
81 | "tegra30-i2s.3", | ||
82 | "tegra30-i2s.4", | ||
83 | }; | ||
84 | #endif | ||
85 | |||
86 | struct tegra_aic326x { | ||
87 | struct tegra_asoc_utils_data util_data; | ||
88 | struct tegra_aic326x_platform_data *pdata; | ||
89 | struct regulator *audio_reg; | ||
90 | int gpio_requested; | ||
91 | bool init_done; | ||
92 | int is_call_mode; | ||
93 | int is_device_bt; | ||
94 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
95 | struct codec_config codec_info[NUM_I2S_DEVICES]; | ||
96 | struct snd_soc_card *pcard; | ||
97 | #endif | ||
98 | }; | ||
99 | |||
100 | static int tegra_aic326x_call_mode_info(struct snd_kcontrol *kcontrol, | ||
101 | struct snd_ctl_elem_info *uinfo) | ||
102 | { | ||
103 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
104 | uinfo->count = 1; | ||
105 | uinfo->value.integer.min = 0; | ||
106 | uinfo->value.integer.max = 1; | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | static int tegra_aic326x_call_mode_get(struct snd_kcontrol *kcontrol, | ||
111 | struct snd_ctl_elem_value *ucontrol) | ||
112 | { | ||
113 | struct tegra_aic326x *machine = snd_kcontrol_chip(kcontrol); | ||
114 | |||
115 | ucontrol->value.integer.value[0] = machine->is_call_mode; | ||
116 | |||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | static int tegra_aic326x_call_mode_put(struct snd_kcontrol *kcontrol, | ||
121 | struct snd_ctl_elem_value *ucontrol) | ||
122 | { | ||
123 | struct tegra_aic326x *machine = snd_kcontrol_chip(kcontrol); | ||
124 | int is_call_mode_new = ucontrol->value.integer.value[0]; | ||
125 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
126 | int codec_dap_id, codec_dap_sel, bb_dap_id, bb_dap_sel; | ||
127 | #else /*assumes tegra3*/ | ||
128 | int codec_index; | ||
129 | unsigned int i; | ||
130 | #endif | ||
131 | |||
132 | if (machine->is_call_mode == is_call_mode_new) | ||
133 | return 0; | ||
134 | |||
135 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
136 | bb_dap_id = TEGRA20_DAS_DAP_ID_3; | ||
137 | bb_dap_sel = TEGRA20_DAS_DAP_SEL_DAP3; | ||
138 | |||
139 | if (machine->is_device_bt) { | ||
140 | codec_dap_id = TEGRA20_DAS_DAP_ID_4; | ||
141 | codec_dap_sel = TEGRA20_DAS_DAP_SEL_DAP4; | ||
142 | } | ||
143 | else { | ||
144 | codec_dap_id = TEGRA20_DAS_DAP_ID_2; | ||
145 | codec_dap_sel = TEGRA20_DAS_DAP_SEL_DAP2; | ||
146 | } | ||
147 | #else /*assumes tegra3*/ | ||
148 | if (machine->is_device_bt) | ||
149 | codec_index = BT_SCO; | ||
150 | else | ||
151 | codec_index = HIFI_CODEC; | ||
152 | #endif | ||
153 | |||
154 | if (is_call_mode_new) { | ||
155 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
156 | tegra20_das_set_tristate(codec_dap_id, 1); | ||
157 | tegra20_das_set_tristate(bb_dap_id, 1); | ||
158 | tegra20_das_connect_dap_to_dap(codec_dap_id, | ||
159 | bb_dap_sel, 0, 0, 0); | ||
160 | tegra20_das_connect_dap_to_dap(bb_dap_id, | ||
161 | codec_dap_sel, 1, 0, 0); | ||
162 | tegra20_das_set_tristate(codec_dap_id, 0); | ||
163 | tegra20_das_set_tristate(bb_dap_id, 0); | ||
164 | #else /*assumes tegra3*/ | ||
165 | if (machine->codec_info[codec_index].rate == 0 || | ||
166 | machine->codec_info[codec_index].channels == 0) | ||
167 | return -EINVAL; | ||
168 | |||
169 | for (i = 0; i < machine->pcard->num_links; i++) | ||
170 | machine->pcard->dai_link[i].ignore_suspend = 1; | ||
171 | |||
172 | tegra30_make_voice_call_connections( | ||
173 | &machine->codec_info[codec_index], | ||
174 | &machine->codec_info[BASEBAND]); | ||
175 | #endif | ||
176 | } else { | ||
177 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
178 | tegra20_das_set_tristate(codec_dap_id, 1); | ||
179 | tegra20_das_set_tristate(bb_dap_id, 1); | ||
180 | tegra20_das_connect_dap_to_dap(bb_dap_id, | ||
181 | bb_dap_sel, 0, 0, 0); | ||
182 | tegra20_das_connect_dap_to_dap(codec_dap_id, | ||
183 | codec_dap_sel, 0, 0, 0); | ||
184 | tegra20_das_set_tristate(codec_dap_id, 0); | ||
185 | tegra20_das_set_tristate(bb_dap_id, 0); | ||
186 | #else /*assumes tegra3*/ | ||
187 | tegra30_break_voice_call_connections( | ||
188 | &machine->codec_info[codec_index], | ||
189 | &machine->codec_info[BASEBAND]); | ||
190 | |||
191 | for (i = 0; i < machine->pcard->num_links; i++) | ||
192 | machine->pcard->dai_link[i].ignore_suspend = 0; | ||
193 | #endif | ||
194 | } | ||
195 | |||
196 | machine->is_call_mode = is_call_mode_new; | ||
197 | g_is_call_mode = machine->is_call_mode; | ||
198 | |||
199 | return 1; | ||
200 | } | ||
201 | |||
202 | struct snd_kcontrol_new tegra_aic326x_call_mode_control = { | ||
203 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
204 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
205 | .name = "Call Mode Switch", | ||
206 | .private_value = 0xffff, | ||
207 | .info = tegra_aic326x_call_mode_info, | ||
208 | .get = tegra_aic326x_call_mode_get, | ||
209 | .put = tegra_aic326x_call_mode_put | ||
210 | }; | ||
211 | |||
212 | static int tegra_aic326x_get_mclk(int srate) | ||
213 | { | ||
214 | int mclk = 0; | ||
215 | switch (srate) { | ||
216 | case 8000: | ||
217 | case 16000: | ||
218 | case 24000: | ||
219 | case 32000: | ||
220 | case 48000: | ||
221 | case 64000: | ||
222 | case 96000: | ||
223 | mclk = 12288000; | ||
224 | break; | ||
225 | case 11025: | ||
226 | case 22050: | ||
227 | case 44100: | ||
228 | case 88200: | ||
229 | mclk = 11289600; | ||
230 | break; | ||
231 | default: | ||
232 | mclk = -EINVAL; | ||
233 | break; | ||
234 | } | ||
235 | |||
236 | return mclk; | ||
237 | } | ||
238 | |||
239 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
240 | static int tegra_aic326x_set_dam_cif(int dam_ifc, int srate, | ||
241 | int channels, int bit_size, int src_on, int src_srate, | ||
242 | int src_channels, int src_bit_size) | ||
243 | { | ||
244 | tegra30_dam_set_gain(dam_ifc, TEGRA30_DAM_CHIN1, 0x1000); | ||
245 | tegra30_dam_set_samplerate(dam_ifc, TEGRA30_DAM_CHOUT, | ||
246 | srate); | ||
247 | tegra30_dam_set_samplerate(dam_ifc, TEGRA30_DAM_CHIN1, | ||
248 | srate); | ||
249 | tegra30_dam_set_acif(dam_ifc, TEGRA30_DAM_CHIN1, | ||
250 | channels, bit_size, channels, | ||
251 | bit_size); | ||
252 | tegra30_dam_set_acif(dam_ifc, TEGRA30_DAM_CHOUT, | ||
253 | channels, bit_size, channels, | ||
254 | bit_size); | ||
255 | |||
256 | if (src_on) { | ||
257 | tegra30_dam_set_gain(dam_ifc, TEGRA30_DAM_CHIN0_SRC, 0x1000); | ||
258 | tegra30_dam_set_samplerate(dam_ifc, TEGRA30_DAM_CHIN0_SRC, | ||
259 | src_srate); | ||
260 | tegra30_dam_set_acif(dam_ifc, TEGRA30_DAM_CHIN0_SRC, | ||
261 | src_channels, src_bit_size, 1, 16); | ||
262 | } | ||
263 | |||
264 | return 0; | ||
265 | } | ||
266 | #endif | ||
267 | |||
268 | static int tegra_aic326x_hw_params(struct snd_pcm_substream *substream, | ||
269 | struct snd_pcm_hw_params *params) | ||
270 | { | ||
271 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
272 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
273 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
274 | struct snd_soc_codec *codec = rtd->codec; | ||
275 | struct snd_soc_card *card = codec->card; | ||
276 | struct tegra_aic326x *machine = snd_soc_card_get_drvdata(card); | ||
277 | int srate, mclk, sample_size, daifmt; | ||
278 | int err; | ||
279 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
280 | struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai); | ||
281 | #endif | ||
282 | |||
283 | switch (params_format(params)) { | ||
284 | case SNDRV_PCM_FORMAT_S16_LE: | ||
285 | sample_size = 16; | ||
286 | break; | ||
287 | default: | ||
288 | return -EINVAL; | ||
289 | } | ||
290 | |||
291 | srate = params_rate(params); | ||
292 | |||
293 | mclk = tegra_aic326x_get_mclk(srate); | ||
294 | if (mclk < 0) | ||
295 | return mclk; | ||
296 | |||
297 | daifmt = SND_SOC_DAIFMT_I2S | | ||
298 | SND_SOC_DAIFMT_NB_NF | | ||
299 | SND_SOC_DAIFMT_CBS_CFS; | ||
300 | |||
301 | err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); | ||
302 | if (err < 0) { | ||
303 | if (!(machine->util_data.set_mclk % mclk)) | ||
304 | mclk = machine->util_data.set_mclk; | ||
305 | else { | ||
306 | dev_err(card->dev, "Can't configure clocks\n"); | ||
307 | return err; | ||
308 | } | ||
309 | } | ||
310 | |||
311 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); | ||
312 | |||
313 | err = snd_soc_dai_set_fmt(codec_dai, daifmt); | ||
314 | if (err < 0) { | ||
315 | dev_err(card->dev, "codec_dai fmt not set\n"); | ||
316 | return err; | ||
317 | } | ||
318 | |||
319 | err = snd_soc_dai_set_fmt(cpu_dai, daifmt); | ||
320 | if (err < 0) { | ||
321 | dev_err(card->dev, "cpu_dai fmt not set\n"); | ||
322 | return err; | ||
323 | } | ||
324 | |||
325 | err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, | ||
326 | SND_SOC_CLOCK_IN); | ||
327 | if (err < 0) { | ||
328 | dev_err(card->dev, "codec_dai clock not set\n"); | ||
329 | return err; | ||
330 | } | ||
331 | |||
332 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
333 | err = tegra20_das_connect_dac_to_dap(TEGRA20_DAS_DAP_SEL_DAC1, | ||
334 | TEGRA20_DAS_DAP_ID_1); | ||
335 | if (err < 0) { | ||
336 | dev_err(card->dev, "failed to set dap-dac path\n"); | ||
337 | return err; | ||
338 | } | ||
339 | |||
340 | err = tegra20_das_connect_dap_to_dac(TEGRA20_DAS_DAP_ID_1, | ||
341 | TEGRA20_DAS_DAP_SEL_DAC1); | ||
342 | if (err < 0) { | ||
343 | dev_err(card->dev, "failed to set dac-dap path\n"); | ||
344 | return err; | ||
345 | } | ||
346 | #else /*assumes tegra3*/ | ||
347 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && i2s->is_dam_used) | ||
348 | tegra_aic326x_set_dam_cif(i2s->dam_ifc, srate, | ||
349 | params_channels(params), sample_size, 0, 0, 0, 0); | ||
350 | #endif | ||
351 | |||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | static int tegra_aic326x_spdif_hw_params(struct snd_pcm_substream *substream, | ||
356 | struct snd_pcm_hw_params *params) | ||
357 | { | ||
358 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
359 | struct snd_soc_card *card = rtd->card; | ||
360 | struct tegra_aic326x *machine = snd_soc_card_get_drvdata(card); | ||
361 | int srate, mclk, min_mclk; | ||
362 | int err; | ||
363 | |||
364 | srate = params_rate(params); | ||
365 | |||
366 | mclk = tegra_aic326x_get_mclk(srate); | ||
367 | if (mclk < 0) | ||
368 | return mclk; | ||
369 | |||
370 | min_mclk = 128 * srate; | ||
371 | |||
372 | err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); | ||
373 | if (err < 0) { | ||
374 | if (!(machine->util_data.set_mclk % min_mclk)) | ||
375 | mclk = machine->util_data.set_mclk; | ||
376 | else { | ||
377 | dev_err(card->dev, "Can't configure clocks\n"); | ||
378 | return err; | ||
379 | } | ||
380 | } | ||
381 | |||
382 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); | ||
383 | |||
384 | return 0; | ||
385 | } | ||
386 | |||
387 | static int tegra_aic326x_bt_hw_params(struct snd_pcm_substream *substream, | ||
388 | struct snd_pcm_hw_params *params) | ||
389 | { | ||
390 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
391 | struct snd_soc_card *card = rtd->card; | ||
392 | struct tegra_aic326x *machine = snd_soc_card_get_drvdata(card); | ||
393 | int err, srate, mclk, min_mclk, sample_size; | ||
394 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
395 | struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(rtd->cpu_dai); | ||
396 | #endif | ||
397 | |||
398 | switch (params_format(params)) { | ||
399 | case SNDRV_PCM_FORMAT_S16_LE: | ||
400 | sample_size = 16; | ||
401 | break; | ||
402 | default: | ||
403 | return -EINVAL; | ||
404 | } | ||
405 | |||
406 | srate = params_rate(params); | ||
407 | |||
408 | mclk = tegra_aic326x_get_mclk(srate); | ||
409 | if (mclk < 0) | ||
410 | return mclk; | ||
411 | |||
412 | min_mclk = 64 * srate; | ||
413 | |||
414 | err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); | ||
415 | if (err < 0) { | ||
416 | if (!(machine->util_data.set_mclk % min_mclk)) | ||
417 | mclk = machine->util_data.set_mclk; | ||
418 | else { | ||
419 | dev_err(card->dev, "Can't configure clocks\n"); | ||
420 | return err; | ||
421 | } | ||
422 | } | ||
423 | |||
424 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); | ||
425 | |||
426 | err = snd_soc_dai_set_fmt(rtd->cpu_dai, | ||
427 | SND_SOC_DAIFMT_DSP_A | | ||
428 | SND_SOC_DAIFMT_NB_NF | | ||
429 | SND_SOC_DAIFMT_CBS_CFS); | ||
430 | |||
431 | if (err < 0) { | ||
432 | dev_err(rtd->codec->card->dev, "cpu_dai fmt not set\n"); | ||
433 | return err; | ||
434 | } | ||
435 | |||
436 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
437 | err = tegra20_das_connect_dac_to_dap(TEGRA20_DAS_DAP_SEL_DAC2, | ||
438 | TEGRA20_DAS_DAP_ID_4); | ||
439 | if (err < 0) { | ||
440 | dev_err(card->dev, "failed to set dac-dap path\n"); | ||
441 | return err; | ||
442 | } | ||
443 | |||
444 | err = tegra20_das_connect_dap_to_dac(TEGRA20_DAS_DAP_ID_4, | ||
445 | TEGRA20_DAS_DAP_SEL_DAC2); | ||
446 | if (err < 0) { | ||
447 | dev_err(card->dev, "failed to set dac-dap path\n"); | ||
448 | return err; | ||
449 | } | ||
450 | #else | ||
451 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && i2s->is_dam_used) | ||
452 | tegra_aic326x_set_dam_cif(i2s->dam_ifc, params_rate(params), | ||
453 | params_channels(params), sample_size, 0, 0, 0, 0); | ||
454 | #endif | ||
455 | |||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
460 | static int tegra_aic326x_startup(struct snd_pcm_substream *substream) | ||
461 | { | ||
462 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
463 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
464 | struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai); | ||
465 | struct tegra_aic326x *machine = snd_soc_card_get_drvdata(rtd->card); | ||
466 | struct codec_config *codec_info; | ||
467 | struct codec_config *bb_info; | ||
468 | int codec_index; | ||
469 | |||
470 | if (!i2s->is_dam_used) | ||
471 | return 0; | ||
472 | |||
473 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
474 | /*dam configuration*/ | ||
475 | if (!i2s->dam_ch_refcount) | ||
476 | i2s->dam_ifc = tegra30_dam_allocate_controller(); | ||
477 | |||
478 | tegra30_dam_allocate_channel(i2s->dam_ifc, TEGRA30_DAM_CHIN1); | ||
479 | i2s->dam_ch_refcount++; | ||
480 | tegra30_dam_enable_clock(i2s->dam_ifc); | ||
481 | |||
482 | tegra30_ahub_set_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX1 + | ||
483 | (i2s->dam_ifc*2), i2s->txcif); | ||
484 | |||
485 | /* | ||
486 | *make the dam tx to i2s rx connection if this is the only client | ||
487 | *using i2s for playback | ||
488 | */ | ||
489 | if (i2s->playback_ref_count == 1) | ||
490 | tegra30_ahub_set_rx_cif_source( | ||
491 | TEGRA30_AHUB_RXCIF_I2S0_RX0 + i2s->id, | ||
492 | TEGRA30_AHUB_TXCIF_DAM0_TX0 + i2s->dam_ifc); | ||
493 | |||
494 | /* enable the dam*/ | ||
495 | tegra30_dam_enable(i2s->dam_ifc, TEGRA30_DAM_ENABLE, | ||
496 | TEGRA30_DAM_CHIN1); | ||
497 | } else { | ||
498 | |||
499 | i2s->is_call_mode_rec = machine->is_call_mode; | ||
500 | |||
501 | if (!i2s->is_call_mode_rec) | ||
502 | return 0; | ||
503 | |||
504 | if (machine->is_device_bt) | ||
505 | codec_index = BT_SCO; | ||
506 | else | ||
507 | codec_index = HIFI_CODEC; | ||
508 | |||
509 | codec_info = &machine->codec_info[codec_index]; | ||
510 | bb_info = &machine->codec_info[BASEBAND]; | ||
511 | |||
512 | /* allocate a dam for voice call recording */ | ||
513 | |||
514 | i2s->call_record_dam_ifc = tegra30_dam_allocate_controller(); | ||
515 | tegra30_dam_allocate_channel(i2s->call_record_dam_ifc, | ||
516 | TEGRA30_DAM_CHIN0_SRC); | ||
517 | tegra30_dam_allocate_channel(i2s->call_record_dam_ifc, | ||
518 | TEGRA30_DAM_CHIN1); | ||
519 | tegra30_dam_enable_clock(i2s->call_record_dam_ifc); | ||
520 | |||
521 | /* configure the dam */ | ||
522 | tegra_aic326x_set_dam_cif(i2s->call_record_dam_ifc, | ||
523 | codec_info->rate, codec_info->channels, | ||
524 | codec_info->bitsize, 1, bb_info->rate, | ||
525 | bb_info->channels, bb_info->bitsize); | ||
526 | |||
527 | /* setup the connections for voice call record */ | ||
528 | |||
529 | tegra30_ahub_unset_rx_cif_source(i2s->rxcif); | ||
530 | tegra30_ahub_set_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX0 + | ||
531 | (i2s->call_record_dam_ifc*2), | ||
532 | TEGRA30_AHUB_TXCIF_I2S0_TX0 + bb_info->i2s_id); | ||
533 | tegra30_ahub_set_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX1 + | ||
534 | (i2s->call_record_dam_ifc*2), | ||
535 | TEGRA30_AHUB_TXCIF_I2S0_TX0 + codec_info->i2s_id); | ||
536 | tegra30_ahub_set_rx_cif_source(i2s->rxcif, | ||
537 | TEGRA30_AHUB_TXCIF_DAM0_TX0 + i2s->call_record_dam_ifc); | ||
538 | |||
539 | /* enable the dam*/ | ||
540 | |||
541 | tegra30_dam_enable(i2s->call_record_dam_ifc, TEGRA30_DAM_ENABLE, | ||
542 | TEGRA30_DAM_CHIN1); | ||
543 | tegra30_dam_enable(i2s->call_record_dam_ifc, TEGRA30_DAM_ENABLE, | ||
544 | TEGRA30_DAM_CHIN0_SRC); | ||
545 | } | ||
546 | |||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | static void tegra_aic326x_shutdown(struct snd_pcm_substream *substream) | ||
551 | { | ||
552 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
553 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
554 | struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai); | ||
555 | |||
556 | if (!i2s->is_dam_used) | ||
557 | return; | ||
558 | |||
559 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
560 | /* disable the dam*/ | ||
561 | tegra30_dam_enable(i2s->dam_ifc, TEGRA30_DAM_DISABLE, | ||
562 | TEGRA30_DAM_CHIN1); | ||
563 | |||
564 | /* disconnect the ahub connections*/ | ||
565 | tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX1 + | ||
566 | (i2s->dam_ifc*2)); | ||
567 | |||
568 | /* disable the dam and free the controller */ | ||
569 | tegra30_dam_disable_clock(i2s->dam_ifc); | ||
570 | tegra30_dam_free_channel(i2s->dam_ifc, TEGRA30_DAM_CHIN1); | ||
571 | i2s->dam_ch_refcount--; | ||
572 | if (!i2s->dam_ch_refcount) | ||
573 | tegra30_dam_free_controller(i2s->dam_ifc); | ||
574 | } else { | ||
575 | |||
576 | if (!i2s->is_call_mode_rec) | ||
577 | return 0; | ||
578 | |||
579 | i2s->is_call_mode_rec = 0; | ||
580 | |||
581 | /* disable the dam*/ | ||
582 | tegra30_dam_enable(i2s->call_record_dam_ifc, | ||
583 | TEGRA30_DAM_DISABLE, TEGRA30_DAM_CHIN1); | ||
584 | tegra30_dam_enable(i2s->call_record_dam_ifc, | ||
585 | TEGRA30_DAM_DISABLE, TEGRA30_DAM_CHIN0_SRC); | ||
586 | |||
587 | /* disconnect the ahub connections*/ | ||
588 | tegra30_ahub_unset_rx_cif_source(i2s->rxcif); | ||
589 | tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX0 + | ||
590 | (i2s->call_record_dam_ifc*2)); | ||
591 | tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX1 + | ||
592 | (i2s->call_record_dam_ifc*2)); | ||
593 | |||
594 | /* free the dam channels and dam controller */ | ||
595 | tegra30_dam_disable_clock(i2s->call_record_dam_ifc); | ||
596 | tegra30_dam_free_channel(i2s->call_record_dam_ifc, | ||
597 | TEGRA30_DAM_CHIN1); | ||
598 | tegra30_dam_free_channel(i2s->call_record_dam_ifc, | ||
599 | TEGRA30_DAM_CHIN0_SRC); | ||
600 | tegra30_dam_free_controller(i2s->call_record_dam_ifc); | ||
601 | } | ||
602 | |||
603 | return; | ||
604 | } | ||
605 | #endif | ||
606 | |||
607 | |||
608 | static int tegra_aic326x_hw_free(struct snd_pcm_substream *substream) | ||
609 | { | ||
610 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
611 | struct tegra_aic326x *machine = snd_soc_card_get_drvdata(rtd->card); | ||
612 | |||
613 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 0); | ||
614 | |||
615 | return 0; | ||
616 | } | ||
617 | |||
618 | static int tegra_aic326x_voice_call_hw_params( | ||
619 | struct snd_pcm_substream *substream, | ||
620 | struct snd_pcm_hw_params *params) | ||
621 | { | ||
622 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
623 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
624 | struct snd_soc_codec *codec = rtd->codec; | ||
625 | struct snd_soc_card *card = codec->card; | ||
626 | struct tegra_aic326x *machine = snd_soc_card_get_drvdata(card); | ||
627 | int srate, mclk; | ||
628 | int err, pcmdiv, vxclkdiv;; | ||
629 | |||
630 | srate = params_rate(params); | ||
631 | mclk = tegra_aic326x_get_mclk(srate); | ||
632 | if (mclk < 0) | ||
633 | return mclk; | ||
634 | |||
635 | err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); | ||
636 | if (err < 0) { | ||
637 | if (!(machine->util_data.set_mclk % mclk)) | ||
638 | mclk = machine->util_data.set_mclk; | ||
639 | else { | ||
640 | dev_err(card->dev, "Can't configure clocks\n"); | ||
641 | return err; | ||
642 | } | ||
643 | } | ||
644 | |||
645 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); | ||
646 | |||
647 | if(machine_is_tegra_enterprise()) { | ||
648 | err = snd_soc_dai_set_fmt(codec_dai, | ||
649 | SND_SOC_DAIFMT_I2S | | ||
650 | SND_SOC_DAIFMT_NB_NF | | ||
651 | SND_SOC_DAIFMT_CBS_CFS); | ||
652 | } else { | ||
653 | err = snd_soc_dai_set_fmt(codec_dai, | ||
654 | SND_SOC_DAIFMT_DSP_B | | ||
655 | SND_SOC_DAIFMT_NB_NF | | ||
656 | SND_SOC_DAIFMT_CBS_CFS); | ||
657 | } | ||
658 | |||
659 | if (err < 0) { | ||
660 | dev_err(card->dev, "codec_dai fmt not set\n"); | ||
661 | return err; | ||
662 | } | ||
663 | |||
664 | err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, | ||
665 | SND_SOC_CLOCK_IN); | ||
666 | if (err < 0) { | ||
667 | dev_err(card->dev, "codec_dai clock not set\n"); | ||
668 | return err; | ||
669 | } | ||
670 | |||
671 | if(!machine_is_tegra_enterprise()) { | ||
672 | if (params_rate(params) == 8000) { | ||
673 | /* Change these Settings for 8KHz*/ | ||
674 | pcmdiv = 1; | ||
675 | /* BB expecting 2048Khz bclk */ | ||
676 | vxclkdiv = 27; | ||
677 | } else if (params_rate(params) == 16000) { | ||
678 | pcmdiv = 1; | ||
679 | /* BB expecting 2048Khz bclk */ | ||
680 | vxclkdiv = 27; | ||
681 | } else { | ||
682 | dev_err(card->dev, "codec_dai unsupported voice rate\n"); | ||
683 | return -EINVAL; | ||
684 | } | ||
685 | } | ||
686 | |||
687 | //snd_soc_dai_set_clkdiv(codec_dai, ASI2_BCLK_N, vxclkdiv); | ||
688 | //snd_soc_dai_set_clkdiv(codec_dai, ASI2_WCLK_N, pcmdiv); | ||
689 | |||
690 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
691 | /* codec configuration */ | ||
692 | machine->codec_info[HIFI_CODEC].rate = params_rate(params); | ||
693 | machine->codec_info[HIFI_CODEC].channels = params_channels(params); | ||
694 | machine->codec_info[HIFI_CODEC].bitsize = 16; | ||
695 | machine->codec_info[HIFI_CODEC].is_i2smaster = 1; | ||
696 | machine->codec_info[HIFI_CODEC].is_format_dsp = 0; | ||
697 | |||
698 | /* baseband configuration */ | ||
699 | machine->codec_info[BASEBAND].bitsize = 16; | ||
700 | machine->codec_info[BASEBAND].is_i2smaster = 1; | ||
701 | machine->codec_info[BASEBAND].is_format_dsp = 1; | ||
702 | #endif | ||
703 | |||
704 | machine->is_device_bt = 0; | ||
705 | |||
706 | return 0; | ||
707 | } | ||
708 | |||
709 | static void tegra_aic326x_voice_call_shutdown( | ||
710 | struct snd_pcm_substream *substream) | ||
711 | { | ||
712 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
713 | struct tegra_aic326x *machine = | ||
714 | snd_soc_card_get_drvdata(rtd->codec->card); | ||
715 | |||
716 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
717 | machine->codec_info[HIFI_CODEC].rate = 0; | ||
718 | machine->codec_info[HIFI_CODEC].channels = 0; | ||
719 | #endif | ||
720 | |||
721 | machine->is_device_bt = 0; | ||
722 | } | ||
723 | |||
724 | static int tegra_aic326x_bt_voice_call_hw_params( | ||
725 | struct snd_pcm_substream *substream, | ||
726 | struct snd_pcm_hw_params *params) | ||
727 | { | ||
728 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
729 | struct snd_soc_card *card = rtd->card; | ||
730 | struct tegra_aic326x *machine = snd_soc_card_get_drvdata(card); | ||
731 | int err, srate, mclk, min_mclk; | ||
732 | |||
733 | srate = params_rate(params); | ||
734 | |||
735 | mclk = tegra_aic326x_get_mclk(srate); | ||
736 | if (mclk < 0) | ||
737 | return mclk; | ||
738 | |||
739 | min_mclk = 64 * srate; | ||
740 | |||
741 | err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); | ||
742 | if (err < 0) { | ||
743 | if (!(machine->util_data.set_mclk % min_mclk)) | ||
744 | mclk = machine->util_data.set_mclk; | ||
745 | else { | ||
746 | dev_err(card->dev, "Can't configure clocks\n"); | ||
747 | return err; | ||
748 | } | ||
749 | } | ||
750 | |||
751 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); | ||
752 | |||
753 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
754 | /* codec configuration */ | ||
755 | machine->codec_info[BT_SCO].rate = params_rate(params); | ||
756 | machine->codec_info[BT_SCO].channels = params_channels(params); | ||
757 | machine->codec_info[BT_SCO].bitsize = 16; | ||
758 | machine->codec_info[BT_SCO].is_i2smaster = 1; | ||
759 | machine->codec_info[BT_SCO].is_format_dsp = 1; | ||
760 | |||
761 | /* baseband configuration */ | ||
762 | machine->codec_info[BASEBAND].bitsize = 16; | ||
763 | machine->codec_info[BASEBAND].is_i2smaster = 1; | ||
764 | machine->codec_info[BASEBAND].is_format_dsp = 1; | ||
765 | #endif | ||
766 | |||
767 | machine->is_device_bt = 1; | ||
768 | |||
769 | return 0; | ||
770 | } | ||
771 | |||
772 | static void tegra_aic326x_bt_voice_call_shutdown( | ||
773 | struct snd_pcm_substream *substream) | ||
774 | { | ||
775 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
776 | struct tegra_aic326x *machine = | ||
777 | snd_soc_card_get_drvdata(rtd->codec->card); | ||
778 | |||
779 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
780 | machine->codec_info[BT_SCO].rate = 0; | ||
781 | machine->codec_info[BT_SCO].channels = 0; | ||
782 | #endif | ||
783 | |||
784 | machine->is_device_bt = 0; | ||
785 | } | ||
786 | |||
787 | static struct snd_soc_ops tegra_aic326x_hifi_ops = { | ||
788 | .hw_params = tegra_aic326x_hw_params, | ||
789 | .hw_free = tegra_aic326x_hw_free, | ||
790 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
791 | .startup = tegra_aic326x_startup, | ||
792 | .shutdown = tegra_aic326x_shutdown, | ||
793 | #endif | ||
794 | }; | ||
795 | |||
796 | static struct snd_soc_ops tegra_aic326x_spdif_ops = { | ||
797 | .hw_params = tegra_aic326x_spdif_hw_params, | ||
798 | .hw_free = tegra_aic326x_hw_free, | ||
799 | }; | ||
800 | |||
801 | static struct snd_soc_ops tegra_aic326x_voice_call_ops = { | ||
802 | .hw_params = tegra_aic326x_voice_call_hw_params, | ||
803 | .shutdown = tegra_aic326x_voice_call_shutdown, | ||
804 | .hw_free = tegra_aic326x_hw_free, | ||
805 | }; | ||
806 | |||
807 | static struct snd_soc_ops tegra_aic326x_bt_voice_call_ops = { | ||
808 | .hw_params = tegra_aic326x_bt_voice_call_hw_params, | ||
809 | .shutdown = tegra_aic326x_bt_voice_call_shutdown, | ||
810 | .hw_free = tegra_aic326x_hw_free, | ||
811 | }; | ||
812 | |||
813 | static struct snd_soc_ops tegra_aic326x_bt_ops = { | ||
814 | .hw_params = tegra_aic326x_bt_hw_params, | ||
815 | .hw_free = tegra_aic326x_hw_free, | ||
816 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
817 | .startup = tegra_aic326x_startup, | ||
818 | .shutdown = tegra_aic326x_shutdown, | ||
819 | #endif | ||
820 | }; | ||
821 | |||
822 | static struct snd_soc_jack tegra_aic326x_hp_jack; | ||
823 | |||
824 | #ifdef CONFIG_SWITCH | ||
825 | static struct switch_dev aic326x_wired_switch_dev = { | ||
826 | .name = "h2w", | ||
827 | }; | ||
828 | |||
829 | /* These values are copied from WiredAccessoryObserver */ | ||
830 | enum headset_state { | ||
831 | BIT_NO_HEADSET = 0, | ||
832 | BIT_HEADSET = (1 << 0), | ||
833 | BIT_HEADSET_NO_MIC = (1 << 1), | ||
834 | }; | ||
835 | |||
836 | static int aic326x_headset_switch_notify(struct notifier_block *self, | ||
837 | unsigned long action, void *dev) | ||
838 | { | ||
839 | int state = 0; | ||
840 | |||
841 | switch (action) { | ||
842 | case SND_JACK_HEADPHONE: | ||
843 | state |= BIT_HEADSET_NO_MIC; | ||
844 | break; | ||
845 | case SND_JACK_HEADSET: | ||
846 | state |= BIT_HEADSET; | ||
847 | break; | ||
848 | default: | ||
849 | state |= BIT_NO_HEADSET; | ||
850 | } | ||
851 | |||
852 | switch_set_state(&aic326x_wired_switch_dev, state); | ||
853 | |||
854 | return NOTIFY_OK; | ||
855 | } | ||
856 | |||
857 | static struct notifier_block aic326x_headset_switch_nb = { | ||
858 | .notifier_call = aic326x_headset_switch_notify, | ||
859 | }; | ||
860 | #else | ||
861 | static struct snd_soc_jack_pin tegra_aic326x_hp_jack_pins[] = { | ||
862 | { | ||
863 | .pin = "Headphone Jack", | ||
864 | .mask = SND_JACK_HEADPHONE, | ||
865 | }, | ||
866 | }; | ||
867 | #endif | ||
868 | |||
869 | static int tegra_aic326x_event_int_spk(struct snd_soc_dapm_widget *w, | ||
870 | struct snd_kcontrol *k, int event) | ||
871 | { | ||
872 | struct snd_soc_dapm_context *dapm = w->dapm; | ||
873 | struct snd_soc_card *card = dapm->card; | ||
874 | struct tegra_aic326x *machine = snd_soc_card_get_drvdata(card); | ||
875 | struct tegra_aic326x_platform_data *pdata = machine->pdata; | ||
876 | |||
877 | if (!(machine->gpio_requested & GPIO_SPKR_EN)) | ||
878 | return 0; | ||
879 | |||
880 | gpio_set_value_cansleep(pdata->gpio_spkr_en, | ||
881 | SND_SOC_DAPM_EVENT_ON(event)); | ||
882 | |||
883 | return 0; | ||
884 | } | ||
885 | |||
886 | static int tegra_aic326x_event_hp(struct snd_soc_dapm_widget *w, | ||
887 | struct snd_kcontrol *k, int event) | ||
888 | { | ||
889 | struct snd_soc_dapm_context *dapm = w->dapm; | ||
890 | struct snd_soc_card *card = dapm->card; | ||
891 | struct tegra_aic326x *machine = snd_soc_card_get_drvdata(card); | ||
892 | struct tegra_aic326x_platform_data *pdata = machine->pdata; | ||
893 | |||
894 | if (!(machine->gpio_requested & GPIO_HP_MUTE)) | ||
895 | return 0; | ||
896 | |||
897 | gpio_set_value_cansleep(pdata->gpio_hp_mute, | ||
898 | !SND_SOC_DAPM_EVENT_ON(event)); | ||
899 | |||
900 | return 0; | ||
901 | } | ||
902 | |||
903 | static const struct snd_soc_dapm_widget tegra_aic326x_dapm_widgets[] = { | ||
904 | SND_SOC_DAPM_SPK("Int Spk", tegra_aic326x_event_int_spk), | ||
905 | SND_SOC_DAPM_HP("Earpiece", NULL), | ||
906 | SND_SOC_DAPM_HP("Headphone Jack", tegra_aic326x_event_hp), | ||
907 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | ||
908 | SND_SOC_DAPM_INPUT("Ext Mic"), | ||
909 | SND_SOC_DAPM_LINE("Linein", NULL), | ||
910 | SND_SOC_DAPM_MIC("Int Mic", NULL), | ||
911 | }; | ||
912 | |||
913 | static const struct snd_soc_dapm_route aic326x_audio_map[] = { | ||
914 | {"Int Spk", NULL, "SPKL"}, | ||
915 | {"Int Spk", NULL, "SPKR"}, | ||
916 | {"Earpiece", NULL, "RECP"}, | ||
917 | {"Earpiece", NULL, "RECM"}, | ||
918 | {"Headphone Jack", NULL, "HPL"}, | ||
919 | {"Headphone Jack", NULL, "HPR"}, | ||
920 | /* internal (IN2L/IN2R) mic is stero */ | ||
921 | {"Mic Bias Int" ,NULL, "Int Mic"}, | ||
922 | {"IN2L", NULL, "Mic Bias Int"}, | ||
923 | {"Mic Bias Int" ,NULL, "Int Mic"}, | ||
924 | {"IN2R", NULL, "Mic Bias Int"}, | ||
925 | {"Mic Bias Ext" ,NULL, "Mic Jack"}, | ||
926 | {"CM1L" ,NULL, "Mic Jack"}, | ||
927 | {"IN1L", NULL, "Mic Bias Ext"}, | ||
928 | {"IN1L", NULL, "CM1L"}, | ||
929 | }; | ||
930 | |||
931 | static const struct snd_kcontrol_new tegra_aic326x_controls[] = { | ||
932 | SOC_DAPM_PIN_SWITCH("Int Spk"), | ||
933 | SOC_DAPM_PIN_SWITCH("Earpiece"), | ||
934 | SOC_DAPM_PIN_SWITCH("Headphone Jack"), | ||
935 | SOC_DAPM_PIN_SWITCH("Mic Jack"), | ||
936 | SOC_DAPM_PIN_SWITCH("Ext Mic"), | ||
937 | SOC_DAPM_PIN_SWITCH("Linein"), | ||
938 | SOC_DAPM_PIN_SWITCH("Int Mic"), | ||
939 | }; | ||
940 | |||
941 | static int tegra_aic326x_init(struct snd_soc_pcm_runtime *rtd) | ||
942 | { | ||
943 | struct snd_soc_codec *codec = rtd->codec; | ||
944 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
945 | struct snd_soc_card *card = codec->card; | ||
946 | struct tegra_aic326x *machine = snd_soc_card_get_drvdata(card); | ||
947 | struct tegra_aic326x_platform_data *pdata = machine->pdata; | ||
948 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
949 | struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(rtd->cpu_dai); | ||
950 | #endif | ||
951 | int ret; | ||
952 | |||
953 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
954 | if (machine->codec_info[BASEBAND].i2s_id != -1) | ||
955 | i2s->is_dam_used = true; | ||
956 | #endif | ||
957 | |||
958 | if (machine->init_done) | ||
959 | return 0; | ||
960 | |||
961 | machine->init_done = true; | ||
962 | |||
963 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
964 | machine->pcard = card; | ||
965 | #endif | ||
966 | |||
967 | if (machine_is_whistler()) { | ||
968 | machine->audio_reg = regulator_get(NULL, "avddio_audio"); | ||
969 | if (IS_ERR(machine->audio_reg)) { | ||
970 | dev_err(card->dev, "cannot get avddio_audio reg\n"); | ||
971 | ret = PTR_ERR(machine->audio_reg); | ||
972 | return ret; | ||
973 | } | ||
974 | |||
975 | ret = regulator_enable(machine->audio_reg); | ||
976 | if (ret) { | ||
977 | dev_err(card->dev, "cannot enable avddio_audio reg\n"); | ||
978 | regulator_put(machine->audio_reg); | ||
979 | machine->audio_reg = NULL; | ||
980 | return ret; | ||
981 | } | ||
982 | } | ||
983 | |||
984 | if (gpio_is_valid(pdata->gpio_spkr_en)) { | ||
985 | ret = gpio_request(pdata->gpio_spkr_en, "spkr_en"); | ||
986 | if (ret) { | ||
987 | dev_err(card->dev, "cannot get spkr_en gpio\n"); | ||
988 | return ret; | ||
989 | } | ||
990 | machine->gpio_requested |= GPIO_SPKR_EN; | ||
991 | |||
992 | gpio_direction_output(pdata->gpio_spkr_en, 0); | ||
993 | } | ||
994 | |||
995 | if (gpio_is_valid(pdata->gpio_hp_mute)) { | ||
996 | ret = gpio_request(pdata->gpio_hp_mute, "hp_mute"); | ||
997 | if (ret) { | ||
998 | dev_err(card->dev, "cannot get hp_mute gpio\n"); | ||
999 | return ret; | ||
1000 | } | ||
1001 | machine->gpio_requested |= GPIO_HP_MUTE; | ||
1002 | |||
1003 | gpio_direction_output(pdata->gpio_hp_mute, 0); | ||
1004 | } | ||
1005 | |||
1006 | if (gpio_is_valid(pdata->gpio_int_mic_en)) { | ||
1007 | ret = gpio_request(pdata->gpio_int_mic_en, "int_mic_en"); | ||
1008 | if (ret) { | ||
1009 | dev_err(card->dev, "cannot get int_mic_en gpio\n"); | ||
1010 | return ret; | ||
1011 | } | ||
1012 | machine->gpio_requested |= GPIO_INT_MIC_EN; | ||
1013 | |||
1014 | /* Disable int mic; enable signal is active-high */ | ||
1015 | gpio_direction_output(pdata->gpio_int_mic_en, 0); | ||
1016 | } | ||
1017 | |||
1018 | if (gpio_is_valid(pdata->gpio_ext_mic_en)) { | ||
1019 | ret = gpio_request(pdata->gpio_ext_mic_en, "ext_mic_en"); | ||
1020 | if (ret) { | ||
1021 | dev_err(card->dev, "cannot get ext_mic_en gpio\n"); | ||
1022 | return ret; | ||
1023 | } | ||
1024 | machine->gpio_requested |= GPIO_EXT_MIC_EN; | ||
1025 | |||
1026 | /* Enable ext mic; enable signal is active-low */ | ||
1027 | gpio_direction_output(pdata->gpio_ext_mic_en, 0); | ||
1028 | } | ||
1029 | |||
1030 | ret = snd_soc_add_controls(codec, tegra_aic326x_controls, | ||
1031 | ARRAY_SIZE(tegra_aic326x_controls)); | ||
1032 | if (ret < 0) | ||
1033 | return ret; | ||
1034 | |||
1035 | snd_soc_dapm_new_controls(dapm, tegra_aic326x_dapm_widgets, | ||
1036 | ARRAY_SIZE(tegra_aic326x_dapm_widgets)); | ||
1037 | |||
1038 | snd_soc_dapm_add_routes(dapm, aic326x_audio_map, | ||
1039 | ARRAY_SIZE(aic326x_audio_map)); | ||
1040 | |||
1041 | ret = snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET, | ||
1042 | &tegra_aic326x_hp_jack); | ||
1043 | if (ret < 0) | ||
1044 | return ret; | ||
1045 | |||
1046 | #ifdef CONFIG_SWITCH | ||
1047 | snd_soc_jack_notifier_register(&tegra_aic326x_hp_jack, | ||
1048 | &aic326x_headset_switch_nb); | ||
1049 | #else /*gpio based headset detection*/ | ||
1050 | snd_soc_jack_add_pins(&tegra_aic326x_hp_jack, | ||
1051 | ARRAY_SIZE(tegra_aic326x_hp_jack_pins), | ||
1052 | tegra_aic326x_hp_jack_pins); | ||
1053 | #endif | ||
1054 | |||
1055 | aic326x_headset_detect(codec, &tegra_aic326x_hp_jack, | ||
1056 | SND_JACK_HEADSET); | ||
1057 | |||
1058 | /* Add call mode switch control */ | ||
1059 | ret = snd_ctl_add(codec->card->snd_card, | ||
1060 | snd_ctl_new1(&tegra_aic326x_call_mode_control, | ||
1061 | machine)); | ||
1062 | if (ret < 0) | ||
1063 | return ret; | ||
1064 | |||
1065 | snd_soc_dapm_force_enable_pin(dapm, "MICBIAS_EXT ON"); | ||
1066 | snd_soc_dapm_force_enable_pin(dapm,"MICBIAS_INT ON"); | ||
1067 | snd_soc_dapm_sync(dapm); | ||
1068 | |||
1069 | return 0; | ||
1070 | } | ||
1071 | |||
1072 | static struct snd_soc_dai_link tegra_aic326x_dai[] = { | ||
1073 | [DAI_LINK_HIFI] = { | ||
1074 | .name = "AIC3262", | ||
1075 | .stream_name = "AIC3262 PCM HIFI", | ||
1076 | .codec_name = "aic3262-codec.4-0018", | ||
1077 | .platform_name = "tegra-pcm-audio", | ||
1078 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
1079 | .cpu_dai_name = "tegra20-i2s.0", | ||
1080 | #else | ||
1081 | .cpu_dai_name = "tegra30-i2s.0", | ||
1082 | #endif | ||
1083 | .codec_dai_name = "aic3262-asi1", | ||
1084 | .init = tegra_aic326x_init, | ||
1085 | .ops = &tegra_aic326x_hifi_ops, | ||
1086 | }, | ||
1087 | [DAI_LINK_SPDIF] = { | ||
1088 | .name = "SPDIF", | ||
1089 | .stream_name = "SPDIF PCM", | ||
1090 | .codec_name = "spdif-dit.0", | ||
1091 | .platform_name = "tegra-pcm-audio", | ||
1092 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
1093 | .cpu_dai_name = "tegra20-spdif", | ||
1094 | #else | ||
1095 | .cpu_dai_name = "tegra30-spdif", | ||
1096 | #endif | ||
1097 | .codec_dai_name = "dit-hifi", | ||
1098 | .ops = &tegra_aic326x_spdif_ops, | ||
1099 | }, | ||
1100 | [DAI_LINK_BTSCO] = { | ||
1101 | .name = "BT-SCO", | ||
1102 | .stream_name = "BT SCO PCM", | ||
1103 | .codec_name = "spdif-dit.1", | ||
1104 | .platform_name = "tegra-pcm-audio", | ||
1105 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
1106 | .cpu_dai_name = "tegra20-i2s.1", | ||
1107 | #else | ||
1108 | .cpu_dai_name = "tegra30-i2s.3", | ||
1109 | #endif | ||
1110 | .codec_dai_name = "dit-hifi", | ||
1111 | .init = tegra_aic326x_init, | ||
1112 | .ops = &tegra_aic326x_bt_ops, | ||
1113 | }, | ||
1114 | [DAI_LINK_VOICE_CALL] = { | ||
1115 | .name = "VOICE CALL", | ||
1116 | .stream_name = "VOICE CALL PCM", | ||
1117 | .codec_name = "aic3262-codec.4-0018", | ||
1118 | .platform_name = "tegra-pcm-audio", | ||
1119 | .cpu_dai_name = "dit-hifi", | ||
1120 | .codec_dai_name = "aic3262-asi2", | ||
1121 | .ops = &tegra_aic326x_voice_call_ops, | ||
1122 | }, | ||
1123 | [DAI_LINK_BT_VOICE_CALL] = { | ||
1124 | .name = "BT VOICE CALL", | ||
1125 | .stream_name = "BT VOICE CALL PCM", | ||
1126 | .codec_name = "spdif-dit.2", | ||
1127 | .platform_name = "tegra-pcm-audio", | ||
1128 | .cpu_dai_name = "dit-hifi", | ||
1129 | .codec_dai_name = "dit-hifi", | ||
1130 | .ops = &tegra_aic326x_bt_voice_call_ops, | ||
1131 | }, | ||
1132 | }; | ||
1133 | |||
1134 | static struct snd_soc_card snd_soc_tegra_aic326x = { | ||
1135 | .name = "tegra-aic326x", | ||
1136 | .dai_link = tegra_aic326x_dai, | ||
1137 | .num_links = ARRAY_SIZE(tegra_aic326x_dai), | ||
1138 | }; | ||
1139 | |||
1140 | static __devinit int tegra_aic326x_driver_probe(struct platform_device *pdev) | ||
1141 | { | ||
1142 | struct snd_soc_card *card = &snd_soc_tegra_aic326x; | ||
1143 | struct tegra_aic326x *machine; | ||
1144 | struct tegra_aic326x_platform_data *pdata; | ||
1145 | int ret, i; | ||
1146 | |||
1147 | pdata = pdev->dev.platform_data; | ||
1148 | if (!pdata) { | ||
1149 | dev_err(&pdev->dev, "No platform data supplied\n"); | ||
1150 | return -EINVAL; | ||
1151 | } | ||
1152 | |||
1153 | machine = kzalloc(sizeof(struct tegra_aic326x), GFP_KERNEL); | ||
1154 | if (!machine) { | ||
1155 | dev_err(&pdev->dev, "Can't allocate tegra_aic326x struct\n"); | ||
1156 | return -ENOMEM; | ||
1157 | } | ||
1158 | |||
1159 | machine->pdata = pdata; | ||
1160 | |||
1161 | ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); | ||
1162 | if (ret) | ||
1163 | goto err_free_machine; | ||
1164 | |||
1165 | card->dev = &pdev->dev; | ||
1166 | platform_set_drvdata(pdev, card); | ||
1167 | snd_soc_card_set_drvdata(card, machine); | ||
1168 | |||
1169 | #ifdef CONFIG_SWITCH | ||
1170 | /* Add h2w switch class support */ | ||
1171 | ret = switch_dev_register(&aic326x_wired_switch_dev); | ||
1172 | if (ret < 0) { | ||
1173 | dev_err(&pdev->dev, "not able to register switch device %d\n", | ||
1174 | ret); | ||
1175 | goto err_fini_utils; | ||
1176 | } | ||
1177 | #endif | ||
1178 | |||
1179 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
1180 | for (i = 0; i < NUM_I2S_DEVICES ; i++) | ||
1181 | machine->codec_info[i].i2s_id = pdata->audio_port_id[i]; | ||
1182 | |||
1183 | machine->codec_info[BASEBAND].rate = pdata->baseband_param.rate; | ||
1184 | machine->codec_info[BASEBAND].channels = pdata->baseband_param.channels; | ||
1185 | |||
1186 | tegra_aic326x_dai[DAI_LINK_HIFI].cpu_dai_name = | ||
1187 | tegra_i2s_dai_name[machine->codec_info[HIFI_CODEC].i2s_id]; | ||
1188 | |||
1189 | tegra_aic326x_dai[DAI_LINK_BTSCO].cpu_dai_name = | ||
1190 | tegra_i2s_dai_name[machine->codec_info[BT_SCO].i2s_id]; | ||
1191 | #endif | ||
1192 | |||
1193 | if(machine_is_tegra_enterprise()) { | ||
1194 | tegra_aic326x_dai[DAI_LINK_HIFI].codec_name = "aic3262-codec.0-0018"; | ||
1195 | tegra_aic326x_dai[DAI_LINK_VOICE_CALL].codec_name = "aic3262-codec.0-0018"; | ||
1196 | tegra_aic326x_dai[DAI_LINK_VOICE_CALL].codec_dai_name = "aic3262-asi1"; | ||
1197 | } | ||
1198 | |||
1199 | ret = snd_soc_register_card(card); | ||
1200 | if (ret) { | ||
1201 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", | ||
1202 | ret); | ||
1203 | goto err_switch_unregister; | ||
1204 | } | ||
1205 | |||
1206 | if (!card->instantiated) { | ||
1207 | dev_err(&pdev->dev, "No TI AIC3262 codec\n"); | ||
1208 | goto err_unregister_card; | ||
1209 | } | ||
1210 | |||
1211 | return 0; | ||
1212 | |||
1213 | err_unregister_card: | ||
1214 | snd_soc_unregister_card(card); | ||
1215 | err_switch_unregister: | ||
1216 | #ifdef CONFIG_SWITCH | ||
1217 | switch_dev_unregister(&aic326x_wired_switch_dev); | ||
1218 | #endif | ||
1219 | err_fini_utils: | ||
1220 | tegra_asoc_utils_fini(&machine->util_data); | ||
1221 | err_free_machine: | ||
1222 | kfree(machine); | ||
1223 | return ret; | ||
1224 | } | ||
1225 | |||
1226 | static int __devexit tegra_aic326x_driver_remove(struct platform_device *pdev) | ||
1227 | { | ||
1228 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
1229 | struct tegra_aic326x *machine = snd_soc_card_get_drvdata(card); | ||
1230 | struct tegra_aic326x_platform_data *pdata = machine->pdata; | ||
1231 | |||
1232 | snd_soc_unregister_card(card); | ||
1233 | |||
1234 | #ifdef CONFIG_SWITCH | ||
1235 | switch_dev_unregister(&aic326x_wired_switch_dev); | ||
1236 | #endif | ||
1237 | |||
1238 | tegra_asoc_utils_fini(&machine->util_data); | ||
1239 | |||
1240 | if (machine->gpio_requested & GPIO_EXT_MIC_EN) | ||
1241 | gpio_free(pdata->gpio_ext_mic_en); | ||
1242 | if (machine->gpio_requested & GPIO_INT_MIC_EN) | ||
1243 | gpio_free(pdata->gpio_int_mic_en); | ||
1244 | if (machine->gpio_requested & GPIO_HP_MUTE) | ||
1245 | gpio_free(pdata->gpio_hp_mute); | ||
1246 | if (machine->gpio_requested & GPIO_SPKR_EN) | ||
1247 | gpio_free(pdata->gpio_spkr_en); | ||
1248 | |||
1249 | kfree(machine); | ||
1250 | |||
1251 | return 0; | ||
1252 | } | ||
1253 | |||
1254 | static struct platform_driver tegra_aic326x_driver = { | ||
1255 | .driver = { | ||
1256 | .name = DRV_NAME, | ||
1257 | .owner = THIS_MODULE, | ||
1258 | .pm = &snd_soc_pm_ops, | ||
1259 | }, | ||
1260 | .probe = tegra_aic326x_driver_probe, | ||
1261 | .remove = __devexit_p(tegra_aic326x_driver_remove), | ||
1262 | }; | ||
1263 | |||
1264 | static int __init tegra_aic326x_modinit(void) | ||
1265 | { | ||
1266 | return platform_driver_register(&tegra_aic326x_driver); | ||
1267 | } | ||
1268 | module_init(tegra_aic326x_modinit); | ||
1269 | |||
1270 | static void __exit tegra_aic326x_modexit(void) | ||
1271 | { | ||
1272 | platform_driver_unregister(&tegra_aic326x_driver); | ||
1273 | } | ||
1274 | module_exit(tegra_aic326x_modexit); | ||
1275 | |||
1276 | /* Module information */ | ||
1277 | MODULE_AUTHOR("Vinod G. <vinodg@nvidia.com>"); | ||
1278 | MODULE_DESCRIPTION("Tegra+AIC3262 machine ASoC driver"); | ||
1279 | MODULE_DESCRIPTION("Tegra ALSA SoC"); | ||
1280 | MODULE_LICENSE("GPL"); | ||
1281 | |||
diff --git a/sound/soc/tegra/tegra_max98088.c b/sound/soc/tegra/tegra_max98088.c new file mode 100644 index 00000000000..bae2b783895 --- /dev/null +++ b/sound/soc/tegra/tegra_max98088.c | |||
@@ -0,0 +1,1233 @@ | |||
1 | /* | ||
2 | * tegra_max98088.c - Tegra machine ASoC driver for boards using MAX98088 codec. | ||
3 | * | ||
4 | * Author: Sumit Bhattacharya <sumitb@nvidia.com> | ||
5 | * Copyright (C) 2011 - NVIDIA, Inc. | ||
6 | * | ||
7 | * Based on code copyright/by: | ||
8 | * | ||
9 | * (c) 2010, 2011 Nvidia Graphics Pvt. Ltd. | ||
10 | * | ||
11 | * Copyright 2007 Wolfson Microelectronics PLC. | ||
12 | * Author: Graeme Gregory | ||
13 | * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or | ||
16 | * modify it under the terms of the GNU General Public License | ||
17 | * version 2 as published by the Free Software Foundation. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, but | ||
20 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
22 | * General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, write to the Free Software | ||
26 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
27 | * 02110-1301 USA | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #include <asm/mach-types.h> | ||
32 | |||
33 | #include <linux/clk.h> | ||
34 | #include <linux/module.h> | ||
35 | #include <linux/platform_device.h> | ||
36 | #include <linux/slab.h> | ||
37 | #include <linux/gpio.h> | ||
38 | #include <linux/regulator/consumer.h> | ||
39 | #ifdef CONFIG_SWITCH | ||
40 | #include <linux/switch.h> | ||
41 | #endif | ||
42 | |||
43 | #include <mach/tegra_asoc_pdata.h> | ||
44 | |||
45 | #include <sound/core.h> | ||
46 | #include <sound/jack.h> | ||
47 | #include <sound/pcm.h> | ||
48 | #include <sound/pcm_params.h> | ||
49 | #include <sound/soc.h> | ||
50 | |||
51 | #include "../codecs/max98088.h" | ||
52 | |||
53 | #include "tegra_pcm.h" | ||
54 | #include "tegra_asoc_utils.h" | ||
55 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
56 | #include "tegra30_ahub.h" | ||
57 | #include "tegra30_i2s.h" | ||
58 | #include "tegra30_dam.h" | ||
59 | #endif | ||
60 | |||
61 | #define DRV_NAME "tegra-snd-max98088" | ||
62 | |||
63 | #define GPIO_SPKR_EN BIT(0) | ||
64 | #define GPIO_HP_MUTE BIT(1) | ||
65 | #define GPIO_INT_MIC_EN BIT(2) | ||
66 | #define GPIO_EXT_MIC_EN BIT(3) | ||
67 | |||
68 | #define DAI_LINK_HIFI 0 | ||
69 | #define DAI_LINK_SPDIF 1 | ||
70 | #define DAI_LINK_BTSCO 2 | ||
71 | #define DAI_LINK_VOICE_CALL 3 | ||
72 | #define DAI_LINK_BT_VOICE_CALL 4 | ||
73 | #define NUM_DAI_LINKS 5 | ||
74 | |||
75 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
76 | const char *tegra_max98088_i2s_dai_name[TEGRA30_NR_I2S_IFC] = { | ||
77 | "tegra30-i2s.0", | ||
78 | "tegra30-i2s.1", | ||
79 | "tegra30-i2s.2", | ||
80 | "tegra30-i2s.3", | ||
81 | "tegra30-i2s.4", | ||
82 | }; | ||
83 | #endif | ||
84 | |||
85 | extern int g_is_call_mode; | ||
86 | |||
87 | struct tegra_max98088 { | ||
88 | struct tegra_asoc_utils_data util_data; | ||
89 | struct tegra_asoc_platform_data *pdata; | ||
90 | int gpio_requested; | ||
91 | bool init_done; | ||
92 | int is_call_mode; | ||
93 | int is_device_bt; | ||
94 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
95 | struct codec_config codec_info[NUM_I2S_DEVICES]; | ||
96 | #endif | ||
97 | enum snd_soc_bias_level bias_level; | ||
98 | struct snd_soc_card *pcard; | ||
99 | }; | ||
100 | |||
101 | static int tegra_call_mode_info(struct snd_kcontrol *kcontrol, | ||
102 | struct snd_ctl_elem_info *uinfo) | ||
103 | { | ||
104 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
105 | uinfo->count = 1; | ||
106 | uinfo->value.integer.min = 0; | ||
107 | uinfo->value.integer.max = 1; | ||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | static int tegra_call_mode_get(struct snd_kcontrol *kcontrol, | ||
112 | struct snd_ctl_elem_value *ucontrol) | ||
113 | { | ||
114 | struct tegra_max98088 *machine = snd_kcontrol_chip(kcontrol); | ||
115 | |||
116 | ucontrol->value.integer.value[0] = machine->is_call_mode; | ||
117 | |||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | static int tegra_call_mode_put(struct snd_kcontrol *kcontrol, | ||
122 | struct snd_ctl_elem_value *ucontrol) | ||
123 | { | ||
124 | struct tegra_max98088 *machine = snd_kcontrol_chip(kcontrol); | ||
125 | int is_call_mode_new = ucontrol->value.integer.value[0]; | ||
126 | int codec_index; | ||
127 | unsigned int i; | ||
128 | |||
129 | if (machine->is_call_mode == is_call_mode_new) | ||
130 | return 0; | ||
131 | |||
132 | if (machine->is_device_bt) | ||
133 | codec_index = BT_SCO; | ||
134 | else | ||
135 | codec_index = HIFI_CODEC; | ||
136 | |||
137 | if (is_call_mode_new) { | ||
138 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
139 | if (machine->codec_info[codec_index].rate == 0 || | ||
140 | machine->codec_info[codec_index].channels == 0) | ||
141 | return -EINVAL; | ||
142 | |||
143 | for (i = 0; i < machine->pcard->num_links; i++) | ||
144 | machine->pcard->dai_link[i].ignore_suspend = 1; | ||
145 | |||
146 | tegra30_make_voice_call_connections( | ||
147 | &machine->codec_info[codec_index], | ||
148 | &machine->codec_info[BASEBAND]); | ||
149 | #endif | ||
150 | } else { | ||
151 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
152 | tegra30_break_voice_call_connections( | ||
153 | &machine->codec_info[codec_index], | ||
154 | &machine->codec_info[BASEBAND]); | ||
155 | |||
156 | for (i = 0; i < machine->pcard->num_links; i++) | ||
157 | machine->pcard->dai_link[i].ignore_suspend = 0; | ||
158 | #endif | ||
159 | } | ||
160 | |||
161 | machine->is_call_mode = is_call_mode_new; | ||
162 | g_is_call_mode = machine->is_call_mode; | ||
163 | |||
164 | return 1; | ||
165 | } | ||
166 | |||
167 | struct snd_kcontrol_new tegra_call_mode_control = { | ||
168 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
169 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
170 | .name = "Call Mode Switch", | ||
171 | .private_value = 0xffff, | ||
172 | .info = tegra_call_mode_info, | ||
173 | .get = tegra_call_mode_get, | ||
174 | .put = tegra_call_mode_put | ||
175 | }; | ||
176 | |||
177 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
178 | static int tegra_max98088_set_dam_cif(int dam_ifc, int srate, | ||
179 | int channels, int bit_size, int src_on, int src_srate, | ||
180 | int src_channels, int src_bit_size) | ||
181 | { | ||
182 | tegra30_dam_set_gain(dam_ifc, TEGRA30_DAM_CHIN1, 0x1000); | ||
183 | tegra30_dam_set_samplerate(dam_ifc, TEGRA30_DAM_CHOUT, | ||
184 | srate); | ||
185 | tegra30_dam_set_samplerate(dam_ifc, TEGRA30_DAM_CHIN1, | ||
186 | srate); | ||
187 | tegra30_dam_set_acif(dam_ifc, TEGRA30_DAM_CHIN1, | ||
188 | channels, bit_size, channels, | ||
189 | bit_size); | ||
190 | tegra30_dam_set_acif(dam_ifc, TEGRA30_DAM_CHOUT, | ||
191 | channels, bit_size, channels, | ||
192 | bit_size); | ||
193 | |||
194 | if (src_on) { | ||
195 | tegra30_dam_set_gain(dam_ifc, TEGRA30_DAM_CHIN0_SRC, 0x1000); | ||
196 | tegra30_dam_set_samplerate(dam_ifc, TEGRA30_DAM_CHIN0_SRC, | ||
197 | src_srate); | ||
198 | tegra30_dam_set_acif(dam_ifc, TEGRA30_DAM_CHIN0_SRC, | ||
199 | src_channels, src_bit_size, 1, 16); | ||
200 | } | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | #endif | ||
205 | |||
206 | static int tegra_max98088_hw_params(struct snd_pcm_substream *substream, | ||
207 | struct snd_pcm_hw_params *params) | ||
208 | { | ||
209 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
210 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
211 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
212 | struct snd_soc_codec *codec = rtd->codec; | ||
213 | struct snd_soc_card *card = codec->card; | ||
214 | struct tegra_max98088 *machine = snd_soc_card_get_drvdata(card); | ||
215 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
216 | struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai); | ||
217 | #endif | ||
218 | int srate, mclk, sample_size, i2s_daifmt; | ||
219 | int err; | ||
220 | struct clk *clk; | ||
221 | int rate; | ||
222 | |||
223 | switch (params_format(params)) { | ||
224 | case SNDRV_PCM_FORMAT_S16_LE: | ||
225 | sample_size = 16; | ||
226 | break; | ||
227 | default: | ||
228 | return -EINVAL; | ||
229 | } | ||
230 | |||
231 | srate = params_rate(params); | ||
232 | switch (srate) { | ||
233 | case 8000: | ||
234 | case 16000: | ||
235 | case 24000: | ||
236 | case 32000: | ||
237 | case 48000: | ||
238 | case 64000: | ||
239 | case 96000: | ||
240 | mclk = 12288000; | ||
241 | break; | ||
242 | case 11025: | ||
243 | case 22050: | ||
244 | case 44100: | ||
245 | case 88200: | ||
246 | mclk = 11289600; | ||
247 | break; | ||
248 | default: | ||
249 | mclk = 12000000; | ||
250 | break; | ||
251 | } | ||
252 | |||
253 | |||
254 | #if defined(CONFIG_ARCH_TEGRA_2x_SOC) | ||
255 | clk = clk_get_sys(NULL, "cdev1"); | ||
256 | #else | ||
257 | clk = clk_get_sys("extern1", NULL); | ||
258 | #endif | ||
259 | if (IS_ERR(clk)) { | ||
260 | dev_err(card->dev, "Can't retrieve clk cdev1\n"); | ||
261 | err = PTR_ERR(clk); | ||
262 | return err; | ||
263 | } | ||
264 | |||
265 | rate = clk_get_rate(clk); | ||
266 | printk("extern1 rate=%d\n",rate); | ||
267 | |||
268 | #if TEGRA30_I2S_MASTER_PLAYBACK | ||
269 | i2s_daifmt = SND_SOC_DAIFMT_I2S | | ||
270 | SND_SOC_DAIFMT_NB_NF | | ||
271 | SND_SOC_DAIFMT_CBS_CFS; | ||
272 | #else | ||
273 | i2s_daifmt = SND_SOC_DAIFMT_I2S | | ||
274 | SND_SOC_DAIFMT_NB_NF | | ||
275 | SND_SOC_DAIFMT_CBM_CFM; | ||
276 | mclk = rate; | ||
277 | #endif | ||
278 | |||
279 | err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); | ||
280 | if (err < 0) { | ||
281 | if (!(machine->util_data.set_mclk % mclk)) | ||
282 | mclk = machine->util_data.set_mclk; | ||
283 | else { | ||
284 | dev_err(card->dev, "Can't configure clocks\n"); | ||
285 | return err; | ||
286 | } | ||
287 | } | ||
288 | |||
289 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); | ||
290 | |||
291 | err = snd_soc_dai_set_fmt(codec_dai,i2s_daifmt); | ||
292 | if (err < 0) { | ||
293 | dev_err(card->dev, "codec_dai fmt not set\n"); | ||
294 | return err; | ||
295 | } | ||
296 | |||
297 | err = snd_soc_dai_set_fmt(cpu_dai, i2s_daifmt); | ||
298 | if (err < 0) { | ||
299 | dev_err(card->dev, "cpu_dai fmt not set\n"); | ||
300 | return err; | ||
301 | } | ||
302 | |||
303 | err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, | ||
304 | SND_SOC_CLOCK_IN); | ||
305 | if (err < 0) { | ||
306 | dev_err(card->dev, "codec_dai clock not set\n"); | ||
307 | return err; | ||
308 | } | ||
309 | |||
310 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
311 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
312 | tegra_max98088_set_dam_cif(i2s->dam_ifc, srate, | ||
313 | params_channels(params), sample_size, 0, 0, 0, 0); | ||
314 | #endif | ||
315 | |||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | static int tegra_spdif_hw_params(struct snd_pcm_substream *substream, | ||
320 | struct snd_pcm_hw_params *params) | ||
321 | { | ||
322 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
323 | struct snd_soc_card *card = rtd->card; | ||
324 | struct tegra_max98088 *machine = snd_soc_card_get_drvdata(card); | ||
325 | int srate, mclk, min_mclk; | ||
326 | int err; | ||
327 | |||
328 | srate = params_rate(params); | ||
329 | switch (srate) { | ||
330 | case 11025: | ||
331 | case 22050: | ||
332 | case 44100: | ||
333 | case 88200: | ||
334 | mclk = 11289600; | ||
335 | break; | ||
336 | case 8000: | ||
337 | case 16000: | ||
338 | case 32000: | ||
339 | case 48000: | ||
340 | case 64000: | ||
341 | case 96000: | ||
342 | mclk = 12288000; | ||
343 | break; | ||
344 | default: | ||
345 | return -EINVAL; | ||
346 | } | ||
347 | min_mclk = 128 * srate; | ||
348 | |||
349 | err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); | ||
350 | if (err < 0) { | ||
351 | if (!(machine->util_data.set_mclk % min_mclk)) | ||
352 | mclk = machine->util_data.set_mclk; | ||
353 | else { | ||
354 | dev_err(card->dev, "Can't configure clocks\n"); | ||
355 | return err; | ||
356 | } | ||
357 | } | ||
358 | |||
359 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); | ||
360 | |||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | static int tegra_bt_hw_params(struct snd_pcm_substream *substream, | ||
365 | struct snd_pcm_hw_params *params) | ||
366 | { | ||
367 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
368 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
369 | struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(rtd->cpu_dai); | ||
370 | #endif | ||
371 | struct snd_soc_card *card = rtd->card; | ||
372 | struct tegra_max98088 *machine = snd_soc_card_get_drvdata(card); | ||
373 | int err, srate, mclk, min_mclk, sample_size; | ||
374 | |||
375 | switch (params_format(params)) { | ||
376 | case SNDRV_PCM_FORMAT_S16_LE: | ||
377 | sample_size = 16; | ||
378 | break; | ||
379 | default: | ||
380 | return -EINVAL; | ||
381 | } | ||
382 | |||
383 | srate = params_rate(params); | ||
384 | switch (srate) { | ||
385 | case 11025: | ||
386 | case 22050: | ||
387 | case 44100: | ||
388 | case 88200: | ||
389 | mclk = 11289600; | ||
390 | break; | ||
391 | case 8000: | ||
392 | case 16000: | ||
393 | case 32000: | ||
394 | case 48000: | ||
395 | case 64000: | ||
396 | case 96000: | ||
397 | mclk = 12288000; | ||
398 | break; | ||
399 | default: | ||
400 | return -EINVAL; | ||
401 | } | ||
402 | min_mclk = 64 * srate; | ||
403 | |||
404 | err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); | ||
405 | if (err < 0) { | ||
406 | if (!(machine->util_data.set_mclk % min_mclk)) | ||
407 | mclk = machine->util_data.set_mclk; | ||
408 | else { | ||
409 | dev_err(card->dev, "Can't configure clocks\n"); | ||
410 | return err; | ||
411 | } | ||
412 | } | ||
413 | |||
414 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); | ||
415 | |||
416 | err = snd_soc_dai_set_fmt(rtd->cpu_dai, | ||
417 | SND_SOC_DAIFMT_DSP_A | | ||
418 | SND_SOC_DAIFMT_NB_NF | | ||
419 | SND_SOC_DAIFMT_CBS_CFS); | ||
420 | if (err < 0) { | ||
421 | dev_err(rtd->codec->card->dev, "cpu_dai fmt not set\n"); | ||
422 | return err; | ||
423 | } | ||
424 | |||
425 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
426 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
427 | tegra_max98088_set_dam_cif(i2s->dam_ifc, params_rate(params), | ||
428 | params_channels(params), sample_size, 0, 0, 0, 0); | ||
429 | #endif | ||
430 | |||
431 | return 0; | ||
432 | } | ||
433 | |||
434 | static int tegra_hw_free(struct snd_pcm_substream *substream) | ||
435 | { | ||
436 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
437 | struct tegra_max98088 *machine = snd_soc_card_get_drvdata(rtd->card); | ||
438 | |||
439 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 0); | ||
440 | |||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
445 | static int tegra_max98088_startup(struct snd_pcm_substream *substream) | ||
446 | { | ||
447 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
448 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
449 | struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai); | ||
450 | struct tegra_max98088 *machine = snd_soc_card_get_drvdata(rtd->card); | ||
451 | struct codec_config *codec_info; | ||
452 | struct codec_config *bb_info; | ||
453 | int codec_index; | ||
454 | |||
455 | if (!i2s->is_dam_used) | ||
456 | return 0; | ||
457 | |||
458 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
459 | /*dam configuration*/ | ||
460 | if (!i2s->dam_ch_refcount) | ||
461 | i2s->dam_ifc = tegra30_dam_allocate_controller(); | ||
462 | |||
463 | tegra30_dam_allocate_channel(i2s->dam_ifc, TEGRA30_DAM_CHIN1); | ||
464 | i2s->dam_ch_refcount++; | ||
465 | tegra30_dam_enable_clock(i2s->dam_ifc); | ||
466 | |||
467 | tegra30_ahub_set_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX1 + | ||
468 | (i2s->dam_ifc*2), i2s->txcif); | ||
469 | |||
470 | /* | ||
471 | *make the dam tx to i2s rx connection if this is the only client | ||
472 | *using i2s for playback | ||
473 | */ | ||
474 | if (i2s->playback_ref_count == 1) | ||
475 | tegra30_ahub_set_rx_cif_source( | ||
476 | TEGRA30_AHUB_RXCIF_I2S0_RX0 + i2s->id, | ||
477 | TEGRA30_AHUB_TXCIF_DAM0_TX0 + i2s->dam_ifc); | ||
478 | |||
479 | /* enable the dam*/ | ||
480 | tegra30_dam_enable(i2s->dam_ifc, TEGRA30_DAM_ENABLE, | ||
481 | TEGRA30_DAM_CHIN1); | ||
482 | } else { | ||
483 | |||
484 | i2s->is_call_mode_rec = machine->is_call_mode; | ||
485 | |||
486 | if (!i2s->is_call_mode_rec) | ||
487 | return 0; | ||
488 | |||
489 | if (machine->is_device_bt) | ||
490 | codec_index = BT_SCO; | ||
491 | else | ||
492 | codec_index = HIFI_CODEC; | ||
493 | |||
494 | codec_info = &machine->codec_info[codec_index]; | ||
495 | bb_info = &machine->codec_info[BASEBAND]; | ||
496 | |||
497 | /* allocate a dam for voice call recording */ | ||
498 | |||
499 | i2s->call_record_dam_ifc = tegra30_dam_allocate_controller(); | ||
500 | tegra30_dam_allocate_channel(i2s->call_record_dam_ifc, | ||
501 | TEGRA30_DAM_CHIN0_SRC); | ||
502 | tegra30_dam_allocate_channel(i2s->call_record_dam_ifc, | ||
503 | TEGRA30_DAM_CHIN1); | ||
504 | tegra30_dam_enable_clock(i2s->call_record_dam_ifc); | ||
505 | |||
506 | /* configure the dam */ | ||
507 | tegra_max98088_set_dam_cif(i2s->call_record_dam_ifc, | ||
508 | codec_info->rate, codec_info->channels, | ||
509 | codec_info->bitsize, 1, bb_info->rate, | ||
510 | bb_info->channels, bb_info->bitsize); | ||
511 | |||
512 | /* setup the connections for voice call record */ | ||
513 | |||
514 | tegra30_ahub_unset_rx_cif_source(i2s->rxcif); | ||
515 | tegra30_ahub_set_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX0 + | ||
516 | (i2s->call_record_dam_ifc*2), | ||
517 | TEGRA30_AHUB_TXCIF_I2S0_TX0 + bb_info->i2s_id); | ||
518 | tegra30_ahub_set_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX1 + | ||
519 | (i2s->call_record_dam_ifc*2), | ||
520 | TEGRA30_AHUB_TXCIF_I2S0_TX0 + codec_info->i2s_id); | ||
521 | tegra30_ahub_set_rx_cif_source(i2s->rxcif, | ||
522 | TEGRA30_AHUB_TXCIF_DAM0_TX0 + i2s->call_record_dam_ifc); | ||
523 | |||
524 | /* enable the dam*/ | ||
525 | |||
526 | tegra30_dam_enable(i2s->call_record_dam_ifc, TEGRA30_DAM_ENABLE, | ||
527 | TEGRA30_DAM_CHIN1); | ||
528 | tegra30_dam_enable(i2s->call_record_dam_ifc, TEGRA30_DAM_ENABLE, | ||
529 | TEGRA30_DAM_CHIN0_SRC); | ||
530 | } | ||
531 | |||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | static void tegra_max98088_shutdown(struct snd_pcm_substream *substream) | ||
536 | { | ||
537 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
538 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
539 | struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai); | ||
540 | |||
541 | if (!i2s->is_dam_used) | ||
542 | return; | ||
543 | |||
544 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
545 | /* disable the dam*/ | ||
546 | tegra30_dam_enable(i2s->dam_ifc, TEGRA30_DAM_DISABLE, | ||
547 | TEGRA30_DAM_CHIN1); | ||
548 | |||
549 | /* disconnect the ahub connections*/ | ||
550 | tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX1 + | ||
551 | (i2s->dam_ifc*2)); | ||
552 | |||
553 | /* disable the dam and free the controller */ | ||
554 | tegra30_dam_disable_clock(i2s->dam_ifc); | ||
555 | tegra30_dam_free_channel(i2s->dam_ifc, TEGRA30_DAM_CHIN1); | ||
556 | i2s->dam_ch_refcount--; | ||
557 | if (!i2s->dam_ch_refcount) | ||
558 | tegra30_dam_free_controller(i2s->dam_ifc); | ||
559 | } else { | ||
560 | |||
561 | if (!i2s->is_call_mode_rec) | ||
562 | return 0; | ||
563 | |||
564 | i2s->is_call_mode_rec = 0; | ||
565 | |||
566 | /* disable the dam*/ | ||
567 | tegra30_dam_enable(i2s->call_record_dam_ifc, | ||
568 | TEGRA30_DAM_DISABLE, TEGRA30_DAM_CHIN1); | ||
569 | tegra30_dam_enable(i2s->call_record_dam_ifc, | ||
570 | TEGRA30_DAM_DISABLE, TEGRA30_DAM_CHIN0_SRC); | ||
571 | |||
572 | /* disconnect the ahub connections*/ | ||
573 | tegra30_ahub_unset_rx_cif_source(i2s->rxcif); | ||
574 | tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX0 + | ||
575 | (i2s->call_record_dam_ifc*2)); | ||
576 | tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX1 + | ||
577 | (i2s->call_record_dam_ifc*2)); | ||
578 | |||
579 | /* free the dam channels and dam controller */ | ||
580 | tegra30_dam_disable_clock(i2s->call_record_dam_ifc); | ||
581 | tegra30_dam_free_channel(i2s->call_record_dam_ifc, | ||
582 | TEGRA30_DAM_CHIN1); | ||
583 | tegra30_dam_free_channel(i2s->call_record_dam_ifc, | ||
584 | TEGRA30_DAM_CHIN0_SRC); | ||
585 | tegra30_dam_free_controller(i2s->call_record_dam_ifc); | ||
586 | } | ||
587 | |||
588 | return; | ||
589 | } | ||
590 | #endif | ||
591 | |||
592 | static int tegra_voice_call_hw_params(struct snd_pcm_substream *substream, | ||
593 | struct snd_pcm_hw_params *params) | ||
594 | { | ||
595 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
596 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
597 | struct snd_soc_codec *codec = rtd->codec; | ||
598 | struct snd_soc_card *card = codec->card; | ||
599 | struct tegra_max98088 *machine = snd_soc_card_get_drvdata(card); | ||
600 | int srate, mclk; | ||
601 | int err; | ||
602 | |||
603 | srate = params_rate(params); | ||
604 | switch (srate) { | ||
605 | case 8000: | ||
606 | case 16000: | ||
607 | case 24000: | ||
608 | case 32000: | ||
609 | case 48000: | ||
610 | case 64000: | ||
611 | case 96000: | ||
612 | mclk = 12288000; | ||
613 | break; | ||
614 | case 11025: | ||
615 | case 22050: | ||
616 | case 44100: | ||
617 | case 88200: | ||
618 | mclk = 11289600; | ||
619 | break; | ||
620 | default: | ||
621 | return -EINVAL; | ||
622 | break; | ||
623 | } | ||
624 | |||
625 | err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); | ||
626 | if (err < 0) { | ||
627 | if (!(machine->util_data.set_mclk % mclk)) | ||
628 | mclk = machine->util_data.set_mclk; | ||
629 | else { | ||
630 | dev_err(card->dev, "Can't configure clocks\n"); | ||
631 | return err; | ||
632 | } | ||
633 | } | ||
634 | |||
635 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); | ||
636 | |||
637 | err = snd_soc_dai_set_fmt(codec_dai, | ||
638 | SND_SOC_DAIFMT_I2S | | ||
639 | SND_SOC_DAIFMT_NB_NF | | ||
640 | SND_SOC_DAIFMT_CBS_CFS); | ||
641 | if (err < 0) { | ||
642 | dev_err(card->dev, "codec_dai fmt not set\n"); | ||
643 | return err; | ||
644 | } | ||
645 | |||
646 | err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, | ||
647 | SND_SOC_CLOCK_IN); | ||
648 | if (err < 0) { | ||
649 | dev_err(card->dev, "codec_dai clock not set\n"); | ||
650 | return err; | ||
651 | } | ||
652 | |||
653 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
654 | /* codec configuration */ | ||
655 | machine->codec_info[HIFI_CODEC].rate = params_rate(params); | ||
656 | machine->codec_info[HIFI_CODEC].channels = params_channels(params); | ||
657 | machine->codec_info[HIFI_CODEC].bitsize = 16; | ||
658 | machine->codec_info[HIFI_CODEC].is_i2smaster = 1; | ||
659 | machine->codec_info[HIFI_CODEC].is_format_dsp = 0; | ||
660 | |||
661 | /* baseband configuration */ | ||
662 | machine->codec_info[BASEBAND].bitsize = 16; | ||
663 | machine->codec_info[BASEBAND].is_i2smaster = 1; | ||
664 | machine->codec_info[BASEBAND].is_format_dsp = 1; | ||
665 | #endif | ||
666 | |||
667 | machine->is_device_bt = 0; | ||
668 | |||
669 | return 0; | ||
670 | } | ||
671 | |||
672 | static void tegra_voice_call_shutdown(struct snd_pcm_substream *substream) | ||
673 | { | ||
674 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
675 | struct tegra_max98088 *machine = | ||
676 | snd_soc_card_get_drvdata(rtd->codec->card); | ||
677 | |||
678 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
679 | machine->codec_info[HIFI_CODEC].rate = 0; | ||
680 | machine->codec_info[HIFI_CODEC].channels = 0; | ||
681 | #endif | ||
682 | |||
683 | return; | ||
684 | } | ||
685 | |||
686 | static int tegra_bt_voice_call_hw_params(struct snd_pcm_substream *substream, | ||
687 | struct snd_pcm_hw_params *params) | ||
688 | { | ||
689 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
690 | struct snd_soc_card *card = rtd->card; | ||
691 | struct tegra_max98088 *machine = snd_soc_card_get_drvdata(card); | ||
692 | int err, srate, mclk, min_mclk; | ||
693 | |||
694 | srate = params_rate(params); | ||
695 | switch (srate) { | ||
696 | case 11025: | ||
697 | case 22050: | ||
698 | case 44100: | ||
699 | case 88200: | ||
700 | mclk = 11289600; | ||
701 | break; | ||
702 | case 8000: | ||
703 | case 16000: | ||
704 | case 32000: | ||
705 | case 48000: | ||
706 | case 64000: | ||
707 | case 96000: | ||
708 | mclk = 12288000; | ||
709 | break; | ||
710 | default: | ||
711 | return -EINVAL; | ||
712 | } | ||
713 | min_mclk = 64 * srate; | ||
714 | |||
715 | err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); | ||
716 | if (err < 0) { | ||
717 | if (!(machine->util_data.set_mclk % min_mclk)) | ||
718 | mclk = machine->util_data.set_mclk; | ||
719 | else { | ||
720 | dev_err(card->dev, "Can't configure clocks\n"); | ||
721 | return err; | ||
722 | } | ||
723 | } | ||
724 | |||
725 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); | ||
726 | |||
727 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
728 | /* codec configuration */ | ||
729 | machine->codec_info[BT_SCO].rate = params_rate(params); | ||
730 | machine->codec_info[BT_SCO].channels = params_channels(params); | ||
731 | machine->codec_info[BT_SCO].bitsize = 16; | ||
732 | machine->codec_info[BT_SCO].is_i2smaster = 1; | ||
733 | machine->codec_info[BT_SCO].is_format_dsp = 1; | ||
734 | |||
735 | /* baseband configuration */ | ||
736 | machine->codec_info[BASEBAND].bitsize = 16; | ||
737 | machine->codec_info[BASEBAND].is_i2smaster = 1; | ||
738 | machine->codec_info[BASEBAND].is_format_dsp = 1; | ||
739 | #endif | ||
740 | |||
741 | machine->is_device_bt = 1; | ||
742 | |||
743 | return 0; | ||
744 | } | ||
745 | |||
746 | static void tegra_bt_voice_call_shutdown(struct snd_pcm_substream *substream) | ||
747 | { | ||
748 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
749 | struct tegra_max98088 *machine = | ||
750 | snd_soc_card_get_drvdata(rtd->codec->card); | ||
751 | |||
752 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
753 | machine->codec_info[BT_SCO].rate = 0; | ||
754 | machine->codec_info[BT_SCO].channels = 0; | ||
755 | #endif | ||
756 | |||
757 | return; | ||
758 | } | ||
759 | |||
760 | static struct snd_soc_ops tegra_max98088_ops = { | ||
761 | .hw_params = tegra_max98088_hw_params, | ||
762 | .hw_free = tegra_hw_free, | ||
763 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
764 | .startup = tegra_max98088_startup, | ||
765 | .shutdown = tegra_max98088_shutdown, | ||
766 | #endif | ||
767 | }; | ||
768 | |||
769 | static struct snd_soc_ops tegra_spdif_ops = { | ||
770 | .hw_params = tegra_spdif_hw_params, | ||
771 | .hw_free = tegra_hw_free, | ||
772 | }; | ||
773 | |||
774 | static struct snd_soc_ops tegra_voice_call_ops = { | ||
775 | .hw_params = tegra_voice_call_hw_params, | ||
776 | .shutdown = tegra_voice_call_shutdown, | ||
777 | .hw_free = tegra_hw_free, | ||
778 | }; | ||
779 | |||
780 | static struct snd_soc_ops tegra_bt_voice_call_ops = { | ||
781 | .hw_params = tegra_bt_voice_call_hw_params, | ||
782 | .shutdown = tegra_bt_voice_call_shutdown, | ||
783 | .hw_free = tegra_hw_free, | ||
784 | }; | ||
785 | |||
786 | static struct snd_soc_ops tegra_bt_ops = { | ||
787 | .hw_params = tegra_bt_hw_params, | ||
788 | .hw_free = tegra_hw_free, | ||
789 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
790 | .startup = tegra_max98088_startup, | ||
791 | .shutdown = tegra_max98088_shutdown, | ||
792 | #endif | ||
793 | }; | ||
794 | |||
795 | static struct snd_soc_jack tegra_max98088_hp_jack; | ||
796 | |||
797 | #ifdef CONFIG_SWITCH | ||
798 | static struct switch_dev wired_switch_dev = { | ||
799 | .name = "h2w", | ||
800 | }; | ||
801 | |||
802 | /* These values are copied from WiredAccessoryObserver */ | ||
803 | enum headset_state { | ||
804 | BIT_NO_HEADSET = 0, | ||
805 | BIT_HEADSET = (1 << 0), | ||
806 | BIT_HEADSET_NO_MIC = (1 << 1), | ||
807 | }; | ||
808 | |||
809 | static int headset_switch_notify(struct notifier_block *self, | ||
810 | unsigned long action, void *dev) | ||
811 | { | ||
812 | int state = 0; | ||
813 | |||
814 | switch (action) { | ||
815 | case SND_JACK_HEADPHONE: | ||
816 | state |= BIT_HEADSET_NO_MIC; | ||
817 | break; | ||
818 | case SND_JACK_HEADSET: | ||
819 | state |= BIT_HEADSET; | ||
820 | break; | ||
821 | default: | ||
822 | state |= BIT_NO_HEADSET; | ||
823 | } | ||
824 | |||
825 | switch_set_state(&wired_switch_dev, state); | ||
826 | |||
827 | return NOTIFY_OK; | ||
828 | } | ||
829 | |||
830 | static struct notifier_block headset_switch_nb = { | ||
831 | .notifier_call = headset_switch_notify, | ||
832 | }; | ||
833 | #else | ||
834 | static struct snd_soc_jack_pin tegra_max98088_hp_jack_pins[] = { | ||
835 | { | ||
836 | .pin = "Headphone Jack", | ||
837 | .mask = SND_JACK_HEADPHONE, | ||
838 | }, | ||
839 | }; | ||
840 | #endif | ||
841 | |||
842 | static int tegra_max98088_event_int_spk(struct snd_soc_dapm_widget *w, | ||
843 | struct snd_kcontrol *k, int event) | ||
844 | { | ||
845 | struct snd_soc_dapm_context *dapm = w->dapm; | ||
846 | struct snd_soc_card *card = dapm->card; | ||
847 | struct tegra_max98088 *machine = snd_soc_card_get_drvdata(card); | ||
848 | struct tegra_asoc_platform_data *pdata = machine->pdata; | ||
849 | |||
850 | if (!(machine->gpio_requested & GPIO_SPKR_EN)) | ||
851 | return 0; | ||
852 | |||
853 | gpio_set_value_cansleep(pdata->gpio_spkr_en, | ||
854 | SND_SOC_DAPM_EVENT_ON(event)); | ||
855 | |||
856 | return 0; | ||
857 | } | ||
858 | |||
859 | static int tegra_max98088_event_hp(struct snd_soc_dapm_widget *w, | ||
860 | struct snd_kcontrol *k, int event) | ||
861 | { | ||
862 | struct snd_soc_dapm_context *dapm = w->dapm; | ||
863 | struct snd_soc_card *card = dapm->card; | ||
864 | struct tegra_max98088 *machine = snd_soc_card_get_drvdata(card); | ||
865 | struct tegra_asoc_platform_data *pdata = machine->pdata; | ||
866 | |||
867 | if (!(machine->gpio_requested & GPIO_HP_MUTE)) | ||
868 | return 0; | ||
869 | |||
870 | gpio_set_value_cansleep(pdata->gpio_hp_mute, | ||
871 | !SND_SOC_DAPM_EVENT_ON(event)); | ||
872 | |||
873 | return 0; | ||
874 | } | ||
875 | |||
876 | static const struct snd_soc_dapm_widget tegra_max98088_dapm_widgets[] = { | ||
877 | SND_SOC_DAPM_SPK("Int Spk", tegra_max98088_event_int_spk), | ||
878 | SND_SOC_DAPM_OUTPUT("Earpiece"), | ||
879 | SND_SOC_DAPM_HP("Headphone Jack", tegra_max98088_event_hp), | ||
880 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | ||
881 | SND_SOC_DAPM_INPUT("Int Mic"), | ||
882 | }; | ||
883 | |||
884 | static const struct snd_soc_dapm_route enterprise_audio_map[] = { | ||
885 | {"Int Spk", NULL, "SPKL"}, | ||
886 | {"Int Spk", NULL, "SPKR"}, | ||
887 | {"Earpiece", NULL, "RECL"}, | ||
888 | {"Earpiece", NULL, "RECR"}, | ||
889 | {"Headphone Jack", NULL, "HPL"}, | ||
890 | {"Headphone Jack", NULL, "HPR"}, | ||
891 | {"MICBIAS", NULL, "Mic Jack"}, | ||
892 | {"MIC2", NULL, "MICBIAS"}, | ||
893 | {"MICBIAS", NULL, "Int Mic"}, | ||
894 | {"MIC1", NULL, "MICBIAS"}, | ||
895 | }; | ||
896 | |||
897 | static const struct snd_kcontrol_new tegra_max98088_controls[] = { | ||
898 | SOC_DAPM_PIN_SWITCH("Int Spk"), | ||
899 | SOC_DAPM_PIN_SWITCH("Earpiece"), | ||
900 | SOC_DAPM_PIN_SWITCH("Headphone Jack"), | ||
901 | SOC_DAPM_PIN_SWITCH("Mic Jack"), | ||
902 | SOC_DAPM_PIN_SWITCH("Int Mic"), | ||
903 | }; | ||
904 | |||
905 | static int tegra_max98088_init(struct snd_soc_pcm_runtime *rtd) | ||
906 | { | ||
907 | struct snd_soc_codec *codec = rtd->codec; | ||
908 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
909 | struct snd_soc_card *card = codec->card; | ||
910 | struct tegra_max98088 *machine = snd_soc_card_get_drvdata(card); | ||
911 | struct tegra_asoc_platform_data *pdata = machine->pdata; | ||
912 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
913 | struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(rtd->cpu_dai); | ||
914 | #endif | ||
915 | int ret; | ||
916 | |||
917 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
918 | if (machine->codec_info[BASEBAND].i2s_id != -1) | ||
919 | i2s->is_dam_used = true; | ||
920 | #endif | ||
921 | |||
922 | if (machine->init_done) | ||
923 | return 0; | ||
924 | |||
925 | machine->init_done = true; | ||
926 | |||
927 | machine->pcard = card; | ||
928 | machine->bias_level = SND_SOC_BIAS_STANDBY; | ||
929 | |||
930 | if (gpio_is_valid(pdata->gpio_spkr_en)) { | ||
931 | ret = gpio_request(pdata->gpio_spkr_en, "spkr_en"); | ||
932 | if (ret) { | ||
933 | dev_err(card->dev, "cannot get spkr_en gpio\n"); | ||
934 | return ret; | ||
935 | } | ||
936 | machine->gpio_requested |= GPIO_SPKR_EN; | ||
937 | |||
938 | gpio_direction_output(pdata->gpio_spkr_en, 0); | ||
939 | } | ||
940 | |||
941 | if (gpio_is_valid(pdata->gpio_hp_mute)) { | ||
942 | ret = gpio_request(pdata->gpio_hp_mute, "hp_mute"); | ||
943 | if (ret) { | ||
944 | dev_err(card->dev, "cannot get hp_mute gpio\n"); | ||
945 | return ret; | ||
946 | } | ||
947 | machine->gpio_requested |= GPIO_HP_MUTE; | ||
948 | |||
949 | gpio_direction_output(pdata->gpio_hp_mute, 0); | ||
950 | } | ||
951 | |||
952 | if (gpio_is_valid(pdata->gpio_int_mic_en)) { | ||
953 | ret = gpio_request(pdata->gpio_int_mic_en, "int_mic_en"); | ||
954 | if (ret) { | ||
955 | dev_err(card->dev, "cannot get int_mic_en gpio\n"); | ||
956 | return ret; | ||
957 | } | ||
958 | machine->gpio_requested |= GPIO_INT_MIC_EN; | ||
959 | |||
960 | /* Disable int mic; enable signal is active-high */ | ||
961 | gpio_direction_output(pdata->gpio_int_mic_en, 0); | ||
962 | } | ||
963 | |||
964 | if (gpio_is_valid(pdata->gpio_ext_mic_en)) { | ||
965 | ret = gpio_request(pdata->gpio_ext_mic_en, "ext_mic_en"); | ||
966 | if (ret) { | ||
967 | dev_err(card->dev, "cannot get ext_mic_en gpio\n"); | ||
968 | return ret; | ||
969 | } | ||
970 | machine->gpio_requested |= GPIO_EXT_MIC_EN; | ||
971 | |||
972 | /* Enable ext mic; enable signal is active-low */ | ||
973 | gpio_direction_output(pdata->gpio_ext_mic_en, 0); | ||
974 | } | ||
975 | |||
976 | ret = snd_soc_add_controls(codec, tegra_max98088_controls, | ||
977 | ARRAY_SIZE(tegra_max98088_controls)); | ||
978 | if (ret < 0) | ||
979 | return ret; | ||
980 | |||
981 | snd_soc_dapm_new_controls(dapm, tegra_max98088_dapm_widgets, | ||
982 | ARRAY_SIZE(tegra_max98088_dapm_widgets)); | ||
983 | |||
984 | snd_soc_dapm_add_routes(dapm, enterprise_audio_map, | ||
985 | ARRAY_SIZE(enterprise_audio_map)); | ||
986 | |||
987 | ret = snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET, | ||
988 | &tegra_max98088_hp_jack); | ||
989 | if (ret < 0) | ||
990 | return ret; | ||
991 | |||
992 | #ifdef CONFIG_SWITCH | ||
993 | snd_soc_jack_notifier_register(&tegra_max98088_hp_jack, | ||
994 | &headset_switch_nb); | ||
995 | #else /*gpio based headset detection*/ | ||
996 | snd_soc_jack_add_pins(&tegra_max98088_hp_jack, | ||
997 | ARRAY_SIZE(tegra_max98088_hp_jack_pins), | ||
998 | tegra_max98088_hp_jack_pins); | ||
999 | #endif | ||
1000 | |||
1001 | max98088_headset_detect(codec, &tegra_max98088_hp_jack, | ||
1002 | SND_JACK_HEADSET); | ||
1003 | |||
1004 | /* Add call mode switch control */ | ||
1005 | ret = snd_ctl_add(codec->card->snd_card, | ||
1006 | snd_ctl_new1(&tegra_call_mode_control, machine)); | ||
1007 | if (ret < 0) | ||
1008 | return ret; | ||
1009 | |||
1010 | snd_soc_dapm_nc_pin(dapm, "INA1"); | ||
1011 | snd_soc_dapm_nc_pin(dapm, "INA2"); | ||
1012 | snd_soc_dapm_nc_pin(dapm, "INB1"); | ||
1013 | snd_soc_dapm_nc_pin(dapm, "INB2"); | ||
1014 | snd_soc_dapm_sync(dapm); | ||
1015 | |||
1016 | return 0; | ||
1017 | } | ||
1018 | |||
1019 | static struct snd_soc_dai_link tegra_max98088_dai[NUM_DAI_LINKS] = { | ||
1020 | [DAI_LINK_HIFI] = { | ||
1021 | .name = "MAX98088", | ||
1022 | .stream_name = "MAX98088 HIFI", | ||
1023 | .codec_name = "max98088.0-0010", | ||
1024 | .platform_name = "tegra-pcm-audio", | ||
1025 | .codec_dai_name = "HiFi", | ||
1026 | .init = tegra_max98088_init, | ||
1027 | .ops = &tegra_max98088_ops, | ||
1028 | }, | ||
1029 | [DAI_LINK_SPDIF] = { | ||
1030 | .name = "SPDIF", | ||
1031 | .stream_name = "SPDIF PCM", | ||
1032 | .codec_name = "spdif-dit.0", | ||
1033 | .platform_name = "tegra-pcm-audio", | ||
1034 | .cpu_dai_name = "tegra30-spdif", | ||
1035 | .codec_dai_name = "dit-hifi", | ||
1036 | .ops = &tegra_spdif_ops, | ||
1037 | }, | ||
1038 | [DAI_LINK_BTSCO] = { | ||
1039 | .name = "BT SCO", | ||
1040 | .stream_name = "BT SCO PCM", | ||
1041 | .codec_name = "spdif-dit.1", | ||
1042 | .platform_name = "tegra-pcm-audio", | ||
1043 | .codec_dai_name = "dit-hifi", | ||
1044 | .init = tegra_max98088_init, | ||
1045 | .ops = &tegra_bt_ops, | ||
1046 | }, | ||
1047 | [DAI_LINK_VOICE_CALL] = { | ||
1048 | .name = "VOICE CALL", | ||
1049 | .stream_name = "VOICE CALL PCM", | ||
1050 | .codec_name = "max98088.0-0010", | ||
1051 | .platform_name = "tegra-pcm-audio", | ||
1052 | .cpu_dai_name = "dit-hifi", | ||
1053 | .codec_dai_name = "HiFi", | ||
1054 | .ops = &tegra_voice_call_ops, | ||
1055 | }, | ||
1056 | [DAI_LINK_BT_VOICE_CALL] = { | ||
1057 | .name = "BT VOICE CALL", | ||
1058 | .stream_name = "BT VOICE CALL PCM", | ||
1059 | .codec_name = "spdif-dit.2", | ||
1060 | .platform_name = "tegra-pcm-audio", | ||
1061 | .cpu_dai_name = "dit-hifi", | ||
1062 | .codec_dai_name = "dit-hifi", | ||
1063 | .ops = &tegra_bt_voice_call_ops, | ||
1064 | }, | ||
1065 | }; | ||
1066 | |||
1067 | static int tegra30_soc_set_bias_level(struct snd_soc_card *card, | ||
1068 | enum snd_soc_bias_level level) | ||
1069 | { | ||
1070 | struct tegra_max98088 *machine = snd_soc_card_get_drvdata(card); | ||
1071 | |||
1072 | if (machine->bias_level == SND_SOC_BIAS_OFF && | ||
1073 | level != SND_SOC_BIAS_OFF) | ||
1074 | tegra_asoc_utils_clk_enable(&machine->util_data); | ||
1075 | |||
1076 | return 0; | ||
1077 | } | ||
1078 | |||
1079 | static int tegra30_soc_set_bias_level_post(struct snd_soc_card *card, | ||
1080 | enum snd_soc_bias_level level) | ||
1081 | { | ||
1082 | struct tegra_max98088 *machine = snd_soc_card_get_drvdata(card); | ||
1083 | |||
1084 | if (machine->bias_level != SND_SOC_BIAS_OFF && | ||
1085 | level == SND_SOC_BIAS_OFF) | ||
1086 | tegra_asoc_utils_clk_disable(&machine->util_data); | ||
1087 | |||
1088 | machine->bias_level = level; | ||
1089 | |||
1090 | return 0 ; | ||
1091 | } | ||
1092 | |||
1093 | static struct snd_soc_card snd_soc_tegra_max98088 = { | ||
1094 | .name = "tegra-max98088", | ||
1095 | .dai_link = tegra_max98088_dai, | ||
1096 | .num_links = ARRAY_SIZE(tegra_max98088_dai), | ||
1097 | .set_bias_level = tegra30_soc_set_bias_level, | ||
1098 | .set_bias_level_post = tegra30_soc_set_bias_level_post, | ||
1099 | }; | ||
1100 | |||
1101 | static __devinit int tegra_max98088_driver_probe(struct platform_device *pdev) | ||
1102 | { | ||
1103 | struct snd_soc_card *card = &snd_soc_tegra_max98088; | ||
1104 | struct tegra_max98088 *machine; | ||
1105 | struct tegra_asoc_platform_data *pdata; | ||
1106 | int ret, i; | ||
1107 | |||
1108 | pdata = pdev->dev.platform_data; | ||
1109 | if (!pdata) { | ||
1110 | dev_err(&pdev->dev, "No platform data supplied\n"); | ||
1111 | return -EINVAL; | ||
1112 | } | ||
1113 | |||
1114 | machine = kzalloc(sizeof(struct tegra_max98088), GFP_KERNEL); | ||
1115 | if (!machine) { | ||
1116 | dev_err(&pdev->dev, "Can't allocate tegra_max98088 struct\n"); | ||
1117 | return -ENOMEM; | ||
1118 | } | ||
1119 | |||
1120 | machine->pdata = pdata; | ||
1121 | |||
1122 | ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); | ||
1123 | if (ret) | ||
1124 | goto err_free_machine; | ||
1125 | |||
1126 | card->dev = &pdev->dev; | ||
1127 | platform_set_drvdata(pdev, card); | ||
1128 | snd_soc_card_set_drvdata(card, machine); | ||
1129 | |||
1130 | #ifdef CONFIG_SWITCH | ||
1131 | /* Add h2w switch class support */ | ||
1132 | ret = switch_dev_register(&wired_switch_dev); | ||
1133 | if (ret < 0) { | ||
1134 | dev_err(&pdev->dev, "not able to register switch device\n"); | ||
1135 | goto err_fini_utils; | ||
1136 | } | ||
1137 | #endif | ||
1138 | |||
1139 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
1140 | for (i = 0; i < NUM_I2S_DEVICES ; i++) | ||
1141 | machine->codec_info[i].i2s_id = pdata->audio_port_id[i]; | ||
1142 | |||
1143 | machine->codec_info[BASEBAND].rate = pdata->baseband_param.rate; | ||
1144 | machine->codec_info[BASEBAND].channels = pdata->baseband_param.channels; | ||
1145 | |||
1146 | tegra_max98088_dai[DAI_LINK_HIFI].cpu_dai_name = | ||
1147 | tegra_max98088_i2s_dai_name[machine->codec_info[HIFI_CODEC].i2s_id]; | ||
1148 | |||
1149 | tegra_max98088_dai[DAI_LINK_BTSCO].cpu_dai_name = | ||
1150 | tegra_max98088_i2s_dai_name[machine->codec_info[BT_SCO].i2s_id]; | ||
1151 | #endif | ||
1152 | |||
1153 | ret = snd_soc_register_card(card); | ||
1154 | if (ret) { | ||
1155 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", | ||
1156 | ret); | ||
1157 | goto err_switch_unregister; | ||
1158 | } | ||
1159 | |||
1160 | if (!card->instantiated) { | ||
1161 | dev_err(&pdev->dev, "No MAX98088 codec\n"); | ||
1162 | goto err_unregister_card; | ||
1163 | } | ||
1164 | |||
1165 | return 0; | ||
1166 | |||
1167 | err_unregister_card: | ||
1168 | snd_soc_unregister_card(card); | ||
1169 | err_switch_unregister: | ||
1170 | #ifdef CONFIG_SWITCH | ||
1171 | switch_dev_unregister(&wired_switch_dev); | ||
1172 | #endif | ||
1173 | err_fini_utils: | ||
1174 | tegra_asoc_utils_fini(&machine->util_data); | ||
1175 | err_free_machine: | ||
1176 | kfree(machine); | ||
1177 | return ret; | ||
1178 | } | ||
1179 | |||
1180 | static int __devexit tegra_max98088_driver_remove(struct platform_device *pdev) | ||
1181 | { | ||
1182 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
1183 | struct tegra_max98088 *machine = snd_soc_card_get_drvdata(card); | ||
1184 | struct tegra_asoc_platform_data *pdata = machine->pdata; | ||
1185 | |||
1186 | snd_soc_unregister_card(card); | ||
1187 | |||
1188 | #ifdef CONFIG_SWITCH | ||
1189 | switch_dev_unregister(&wired_switch_dev); | ||
1190 | #endif | ||
1191 | |||
1192 | tegra_asoc_utils_fini(&machine->util_data); | ||
1193 | |||
1194 | if (machine->gpio_requested & GPIO_EXT_MIC_EN) | ||
1195 | gpio_free(pdata->gpio_ext_mic_en); | ||
1196 | if (machine->gpio_requested & GPIO_INT_MIC_EN) | ||
1197 | gpio_free(pdata->gpio_int_mic_en); | ||
1198 | if (machine->gpio_requested & GPIO_HP_MUTE) | ||
1199 | gpio_free(pdata->gpio_hp_mute); | ||
1200 | if (machine->gpio_requested & GPIO_SPKR_EN) | ||
1201 | gpio_free(pdata->gpio_spkr_en); | ||
1202 | |||
1203 | kfree(machine); | ||
1204 | |||
1205 | return 0; | ||
1206 | } | ||
1207 | |||
1208 | static struct platform_driver tegra_max98088_driver = { | ||
1209 | .driver = { | ||
1210 | .name = DRV_NAME, | ||
1211 | .owner = THIS_MODULE, | ||
1212 | .pm = &snd_soc_pm_ops, | ||
1213 | }, | ||
1214 | .probe = tegra_max98088_driver_probe, | ||
1215 | .remove = __devexit_p(tegra_max98088_driver_remove), | ||
1216 | }; | ||
1217 | |||
1218 | static int __init tegra_max98088_modinit(void) | ||
1219 | { | ||
1220 | return platform_driver_register(&tegra_max98088_driver); | ||
1221 | } | ||
1222 | module_init(tegra_max98088_modinit); | ||
1223 | |||
1224 | static void __exit tegra_max98088_modexit(void) | ||
1225 | { | ||
1226 | platform_driver_unregister(&tegra_max98088_driver); | ||
1227 | } | ||
1228 | module_exit(tegra_max98088_modexit); | ||
1229 | |||
1230 | MODULE_AUTHOR("Sumit Bhattacharya <sumitb@nvidia.com>"); | ||
1231 | MODULE_DESCRIPTION("Tegra+MAX98088 machine ASoC driver"); | ||
1232 | MODULE_LICENSE("GPL"); | ||
1233 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/sound/soc/tegra/tegra_max98095.c b/sound/soc/tegra/tegra_max98095.c new file mode 100644 index 00000000000..2104ba849cd --- /dev/null +++ b/sound/soc/tegra/tegra_max98095.c | |||
@@ -0,0 +1,723 @@ | |||
1 | /* | ||
2 | * tegra_max98095.c - Tegra machine ASoC driver for boards using MAX98095 codec. | ||
3 | * | ||
4 | * Author: Ravindra Lokhande <rlokhande@nvidia.com> | ||
5 | * Copyright (C) 2012 - NVIDIA, Inc. | ||
6 | * | ||
7 | * Based on version from Sumit Bhattacharya <sumitb@nvidia.com> | ||
8 | * | ||
9 | * Based on code copyright/by: | ||
10 | * | ||
11 | * (c) 2010, 2011, 2012 Nvidia Graphics Pvt. Ltd. | ||
12 | * | ||
13 | * Copyright 2007 Wolfson Microelectronics PLC. | ||
14 | * Author: Graeme Gregory | ||
15 | * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com | ||
16 | * | ||
17 | * This program is free software; you can redistribute it and/or | ||
18 | * modify it under the terms of the GNU General Public License | ||
19 | * version 2 as published by the Free Software Foundation. | ||
20 | * | ||
21 | * This program is distributed in the hope that it will be useful, but | ||
22 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
24 | * General Public License for more details. | ||
25 | * | ||
26 | * You should have received a copy of the GNU General Public License | ||
27 | * along with this program; if not, write to the Free Software | ||
28 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
29 | * 02110-1301 USA | ||
30 | * | ||
31 | */ | ||
32 | |||
33 | #include <asm/mach-types.h> | ||
34 | |||
35 | #include <linux/module.h> | ||
36 | #include <linux/platform_device.h> | ||
37 | #include <linux/slab.h> | ||
38 | #include <linux/gpio.h> | ||
39 | #include <linux/regulator/consumer.h> | ||
40 | #ifdef CONFIG_SWITCH | ||
41 | #include <linux/switch.h> | ||
42 | #endif | ||
43 | |||
44 | #include <mach/tegra_asoc_pdata.h> | ||
45 | |||
46 | #include <sound/core.h> | ||
47 | #include <sound/jack.h> | ||
48 | #include <sound/pcm.h> | ||
49 | #include <sound/pcm_params.h> | ||
50 | #include <sound/soc.h> | ||
51 | |||
52 | #include "../codecs/max98095.h" | ||
53 | |||
54 | #include "tegra_pcm.h" | ||
55 | #include "tegra_asoc_utils.h" | ||
56 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
57 | #include "tegra30_ahub.h" | ||
58 | #include "tegra30_i2s.h" | ||
59 | #include "tegra30_dam.h" | ||
60 | #endif | ||
61 | |||
62 | #define DRV_NAME "tegra-snd-max98095" | ||
63 | |||
64 | #define GPIO_SPKR_EN BIT(0) | ||
65 | #define GPIO_HP_MUTE BIT(1) | ||
66 | #define GPIO_INT_MIC_EN BIT(2) | ||
67 | #define GPIO_EXT_MIC_EN BIT(3) | ||
68 | |||
69 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
70 | const char *tegra_max98095_i2s_dai_name[TEGRA30_NR_I2S_IFC] = { | ||
71 | "tegra30-i2s.0", | ||
72 | "tegra30-i2s.1", | ||
73 | "tegra30-i2s.2", | ||
74 | "tegra30-i2s.3", | ||
75 | "tegra30-i2s.4", | ||
76 | }; | ||
77 | #endif | ||
78 | |||
79 | struct tegra_max98095 { | ||
80 | struct tegra_asoc_utils_data util_data; | ||
81 | struct tegra_asoc_platform_data *pdata; | ||
82 | int gpio_requested; | ||
83 | bool init_done; | ||
84 | int is_call_mode; | ||
85 | int is_device_bt; | ||
86 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
87 | struct codec_config codec_info[NUM_I2S_DEVICES]; | ||
88 | #endif | ||
89 | enum snd_soc_bias_level bias_level; | ||
90 | }; | ||
91 | |||
92 | |||
93 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
94 | static int tegra_max98095_set_dam_cif(int dam_ifc, int srate, | ||
95 | int channels, int bit_size) | ||
96 | { | ||
97 | tegra30_dam_set_samplerate(dam_ifc, TEGRA30_DAM_CHOUT, | ||
98 | srate); | ||
99 | tegra30_dam_set_samplerate(dam_ifc, TEGRA30_DAM_CHIN1, | ||
100 | srate); | ||
101 | tegra30_dam_set_acif(dam_ifc, TEGRA30_DAM_CHIN1, | ||
102 | channels, bit_size, channels, | ||
103 | bit_size); | ||
104 | tegra30_dam_set_acif(dam_ifc, TEGRA30_DAM_CHOUT, | ||
105 | channels, bit_size, channels, | ||
106 | bit_size); | ||
107 | |||
108 | return 0; | ||
109 | } | ||
110 | #endif | ||
111 | |||
112 | static int tegra_max98095_hw_params(struct snd_pcm_substream *substream, | ||
113 | struct snd_pcm_hw_params *params) | ||
114 | { | ||
115 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
116 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
117 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
118 | struct snd_soc_codec *codec = rtd->codec; | ||
119 | struct snd_soc_card *card = codec->card; | ||
120 | struct tegra_max98095 *machine = snd_soc_card_get_drvdata(card); | ||
121 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
122 | struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai); | ||
123 | #endif | ||
124 | unsigned int srate, mclk, sample_size; | ||
125 | int err; | ||
126 | |||
127 | switch (params_format(params)) { | ||
128 | case SNDRV_PCM_FORMAT_S16_LE: | ||
129 | sample_size = 16; | ||
130 | break; | ||
131 | default: | ||
132 | return -EINVAL; | ||
133 | } | ||
134 | |||
135 | srate = params_rate(params); | ||
136 | switch (srate) { | ||
137 | case 8000: | ||
138 | case 16000: | ||
139 | case 24000: | ||
140 | case 32000: | ||
141 | case 48000: | ||
142 | case 64000: | ||
143 | case 96000: | ||
144 | mclk = 12288000; | ||
145 | break; | ||
146 | case 11025: | ||
147 | case 22050: | ||
148 | case 44100: | ||
149 | case 88200: | ||
150 | mclk = 11289600; | ||
151 | break; | ||
152 | default: | ||
153 | mclk = 12000000; | ||
154 | break; | ||
155 | } | ||
156 | |||
157 | err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); | ||
158 | if (err < 0) { | ||
159 | if (!(machine->util_data.set_mclk % mclk)) | ||
160 | mclk = machine->util_data.set_mclk; | ||
161 | else { | ||
162 | dev_err(card->dev, "Can't configure clocks\n"); | ||
163 | return err; | ||
164 | } | ||
165 | } | ||
166 | |||
167 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); | ||
168 | |||
169 | err = snd_soc_dai_set_fmt(codec_dai, | ||
170 | SND_SOC_DAIFMT_I2S | | ||
171 | SND_SOC_DAIFMT_NB_NF | | ||
172 | SND_SOC_DAIFMT_CBS_CFS); | ||
173 | if (err < 0) { | ||
174 | dev_err(card->dev, "codec_dai fmt not set\n"); | ||
175 | return err; | ||
176 | } | ||
177 | |||
178 | err = snd_soc_dai_set_fmt(cpu_dai, | ||
179 | SND_SOC_DAIFMT_I2S | | ||
180 | SND_SOC_DAIFMT_NB_NF | | ||
181 | SND_SOC_DAIFMT_CBS_CFS); | ||
182 | if (err < 0) { | ||
183 | dev_err(card->dev, "cpu_dai fmt not set\n"); | ||
184 | return err; | ||
185 | } | ||
186 | |||
187 | err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, | ||
188 | SND_SOC_CLOCK_IN); | ||
189 | if (err < 0) { | ||
190 | dev_err(card->dev, "codec_dai clock not set\n"); | ||
191 | return err; | ||
192 | } | ||
193 | |||
194 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
195 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
196 | tegra_max98095_set_dam_cif(i2s->dam_ifc, srate, | ||
197 | params_channels(params), sample_size); | ||
198 | #endif | ||
199 | |||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | static int tegra_spdif_hw_params(struct snd_pcm_substream *substream, | ||
204 | struct snd_pcm_hw_params *params) | ||
205 | { | ||
206 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
207 | struct snd_soc_card *card = rtd->card; | ||
208 | struct tegra_max98095 *machine = snd_soc_card_get_drvdata(card); | ||
209 | unsigned int srate, mclk, min_mclk; | ||
210 | int err; | ||
211 | |||
212 | srate = params_rate(params); | ||
213 | switch (srate) { | ||
214 | case 11025: | ||
215 | case 22050: | ||
216 | case 44100: | ||
217 | case 88200: | ||
218 | mclk = 11289600; | ||
219 | break; | ||
220 | case 8000: | ||
221 | case 16000: | ||
222 | case 32000: | ||
223 | case 48000: | ||
224 | case 64000: | ||
225 | case 96000: | ||
226 | mclk = 12288000; | ||
227 | break; | ||
228 | default: | ||
229 | return -EINVAL; | ||
230 | } | ||
231 | min_mclk = 128 * srate; | ||
232 | |||
233 | err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); | ||
234 | if (err < 0) { | ||
235 | if (!(machine->util_data.set_mclk % min_mclk)) | ||
236 | mclk = machine->util_data.set_mclk; | ||
237 | else { | ||
238 | dev_err(card->dev, "Can't configure clocks\n"); | ||
239 | return err; | ||
240 | } | ||
241 | } | ||
242 | |||
243 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); | ||
244 | |||
245 | |||
246 | |||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | static int tegra_hw_free(struct snd_pcm_substream *substream) | ||
251 | { | ||
252 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
253 | struct tegra_max98095 *machine = snd_soc_card_get_drvdata(rtd->card); | ||
254 | |||
255 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 0); | ||
256 | |||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
261 | static int tegra_max98095_startup(struct snd_pcm_substream *substream) | ||
262 | { | ||
263 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
264 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
265 | struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai); | ||
266 | |||
267 | if ((substream->stream != SNDRV_PCM_STREAM_PLAYBACK) || | ||
268 | !(i2s->is_dam_used)) | ||
269 | return 0; | ||
270 | |||
271 | /*dam configuration*/ | ||
272 | if (!i2s->dam_ch_refcount) | ||
273 | i2s->dam_ifc = tegra30_dam_allocate_controller(); | ||
274 | |||
275 | tegra30_dam_allocate_channel(i2s->dam_ifc, TEGRA30_DAM_CHIN1); | ||
276 | i2s->dam_ch_refcount++; | ||
277 | tegra30_dam_enable_clock(i2s->dam_ifc); | ||
278 | tegra30_dam_set_gain(i2s->dam_ifc, TEGRA30_DAM_CHIN1, 0x1000); | ||
279 | |||
280 | tegra30_ahub_set_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX1 + | ||
281 | (i2s->dam_ifc*2), i2s->txcif); | ||
282 | |||
283 | /* | ||
284 | *make the dam tx to i2s rx connection if this is the only client | ||
285 | *using i2s for playback | ||
286 | */ | ||
287 | if (i2s->playback_ref_count == 1) | ||
288 | tegra30_ahub_set_rx_cif_source( | ||
289 | TEGRA30_AHUB_RXCIF_I2S0_RX0 + i2s->id, | ||
290 | TEGRA30_AHUB_TXCIF_DAM0_TX0 + i2s->dam_ifc); | ||
291 | |||
292 | /* enable the dam*/ | ||
293 | tegra30_dam_enable(i2s->dam_ifc, TEGRA30_DAM_ENABLE, | ||
294 | TEGRA30_DAM_CHIN1); | ||
295 | |||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static void tegra_max98095_shutdown(struct snd_pcm_substream *substream) | ||
300 | { | ||
301 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
302 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
303 | struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai); | ||
304 | |||
305 | if ((substream->stream != SNDRV_PCM_STREAM_PLAYBACK) || | ||
306 | !(i2s->is_dam_used)) | ||
307 | return; | ||
308 | |||
309 | /* disable the dam*/ | ||
310 | tegra30_dam_enable(i2s->dam_ifc, TEGRA30_DAM_DISABLE, | ||
311 | TEGRA30_DAM_CHIN1); | ||
312 | |||
313 | /* disconnect the ahub connections*/ | ||
314 | tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX1 + | ||
315 | (i2s->dam_ifc*2)); | ||
316 | |||
317 | /* disable the dam and free the controller */ | ||
318 | tegra30_dam_disable_clock(i2s->dam_ifc); | ||
319 | tegra30_dam_free_channel(i2s->dam_ifc, TEGRA30_DAM_CHIN1); | ||
320 | i2s->dam_ch_refcount--; | ||
321 | if (!i2s->dam_ch_refcount) | ||
322 | tegra30_dam_free_controller(i2s->dam_ifc); | ||
323 | |||
324 | return; | ||
325 | } | ||
326 | #endif | ||
327 | |||
328 | static struct snd_soc_ops tegra_max98095_ops = { | ||
329 | .hw_params = tegra_max98095_hw_params, | ||
330 | .hw_free = tegra_hw_free, | ||
331 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
332 | .startup = tegra_max98095_startup, | ||
333 | .shutdown = tegra_max98095_shutdown, | ||
334 | #endif | ||
335 | }; | ||
336 | |||
337 | static struct snd_soc_ops tegra_spdif_ops = { | ||
338 | .hw_params = tegra_spdif_hw_params, | ||
339 | .hw_free = tegra_hw_free, | ||
340 | }; | ||
341 | |||
342 | static struct snd_soc_jack tegra_max98095_hp_jack; | ||
343 | |||
344 | #ifdef CONFIG_SWITCH | ||
345 | static struct switch_dev wired_switch_dev = { | ||
346 | .name = "h2w", | ||
347 | }; | ||
348 | |||
349 | /* These values are copied from WiredAccessoryObserver */ | ||
350 | enum headset_state { | ||
351 | BIT_NO_HEADSET = 0, | ||
352 | BIT_HEADSET = (1 << 0), | ||
353 | BIT_HEADSET_NO_MIC = (1 << 1), | ||
354 | }; | ||
355 | |||
356 | static int headset_switch_notify(struct notifier_block *self, | ||
357 | unsigned long action, void *dev) | ||
358 | { | ||
359 | int state = 0; | ||
360 | |||
361 | switch (action) { | ||
362 | case SND_JACK_HEADPHONE: | ||
363 | state |= BIT_HEADSET_NO_MIC; | ||
364 | break; | ||
365 | case SND_JACK_HEADSET: | ||
366 | state |= BIT_HEADSET; | ||
367 | break; | ||
368 | default: | ||
369 | state |= BIT_NO_HEADSET; | ||
370 | } | ||
371 | |||
372 | switch_set_state(&wired_switch_dev, state); | ||
373 | |||
374 | return NOTIFY_OK; | ||
375 | } | ||
376 | |||
377 | static struct notifier_block headset_switch_nb = { | ||
378 | .notifier_call = headset_switch_notify, | ||
379 | }; | ||
380 | #else | ||
381 | static struct snd_soc_jack_pin tegra_max98095_hp_jack_pins[] = { | ||
382 | { | ||
383 | .pin = "Headphone Jack", | ||
384 | .mask = SND_JACK_HEADPHONE, | ||
385 | }, | ||
386 | }; | ||
387 | #endif | ||
388 | |||
389 | static int tegra_max98095_event_int_spk(struct snd_soc_dapm_widget *w, | ||
390 | struct snd_kcontrol *k, int event) | ||
391 | { | ||
392 | struct snd_soc_dapm_context *dapm = w->dapm; | ||
393 | struct snd_soc_card *card = dapm->card; | ||
394 | struct tegra_max98095 *machine = snd_soc_card_get_drvdata(card); | ||
395 | struct tegra_asoc_platform_data *pdata = machine->pdata; | ||
396 | |||
397 | if (!(machine->gpio_requested & GPIO_SPKR_EN)) | ||
398 | return 0; | ||
399 | |||
400 | gpio_set_value_cansleep(pdata->gpio_spkr_en, | ||
401 | SND_SOC_DAPM_EVENT_ON(event)); | ||
402 | |||
403 | return 0; | ||
404 | } | ||
405 | |||
406 | static int tegra_max98095_event_hp(struct snd_soc_dapm_widget *w, | ||
407 | struct snd_kcontrol *k, int event) | ||
408 | { | ||
409 | struct snd_soc_dapm_context *dapm = w->dapm; | ||
410 | struct snd_soc_card *card = dapm->card; | ||
411 | struct tegra_max98095 *machine = snd_soc_card_get_drvdata(card); | ||
412 | struct tegra_asoc_platform_data *pdata = machine->pdata; | ||
413 | |||
414 | if (!(machine->gpio_requested & GPIO_HP_MUTE)) | ||
415 | return 0; | ||
416 | |||
417 | gpio_set_value_cansleep(pdata->gpio_hp_mute, | ||
418 | !SND_SOC_DAPM_EVENT_ON(event)); | ||
419 | |||
420 | return 0; | ||
421 | } | ||
422 | |||
423 | static const struct snd_soc_dapm_widget tegra_max98095_dapm_widgets[] = { | ||
424 | SND_SOC_DAPM_SPK("Int Spk", tegra_max98095_event_int_spk), | ||
425 | SND_SOC_DAPM_HP("Headphone Jack", tegra_max98095_event_hp), | ||
426 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | ||
427 | SND_SOC_DAPM_INPUT("Int Mic"), | ||
428 | SND_SOC_DAPM_LINE("Line In", NULL), | ||
429 | }; | ||
430 | |||
431 | static const struct snd_soc_dapm_route enterprise_audio_map[] = { | ||
432 | {"Int Spk", NULL, "SPKL"}, | ||
433 | {"Int Spk", NULL, "SPKR"}, | ||
434 | {"Headphone Jack", NULL, "HPL"}, | ||
435 | {"Headphone Jack", NULL, "HPR"}, | ||
436 | {"MICBIAS2", NULL, "Mic Jack"}, | ||
437 | {"MIC2", NULL, "MICBIAS2"}, | ||
438 | {"MIC1", NULL, "Int Mic"}, | ||
439 | {"MIC1", NULL, "MICBIAS1"}, | ||
440 | {"INB1", NULL, "Line In"}, | ||
441 | {"INB2", NULL, "Line In"}, | ||
442 | }; | ||
443 | |||
444 | static const struct snd_kcontrol_new tegra_max98095_controls[] = { | ||
445 | SOC_DAPM_PIN_SWITCH("Int Spk"), | ||
446 | SOC_DAPM_PIN_SWITCH("Headphone Jack"), | ||
447 | SOC_DAPM_PIN_SWITCH("Mic Jack"), | ||
448 | SOC_DAPM_PIN_SWITCH("Int Mic"), | ||
449 | SOC_DAPM_PIN_SWITCH("LineIn"), | ||
450 | }; | ||
451 | |||
452 | static int tegra_max98095_init(struct snd_soc_pcm_runtime *rtd) | ||
453 | { | ||
454 | struct snd_soc_codec *codec = rtd->codec; | ||
455 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
456 | struct snd_soc_card *card = codec->card; | ||
457 | struct tegra_max98095 *machine = snd_soc_card_get_drvdata(card); | ||
458 | struct tegra_asoc_platform_data *pdata = machine->pdata; | ||
459 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
460 | struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(rtd->cpu_dai); | ||
461 | #endif | ||
462 | int ret; | ||
463 | |||
464 | #ifndef CONFIG_ARCH_TEGRA_2x_SOC | ||
465 | if (machine->codec_info[BASEBAND].i2s_id != -1) | ||
466 | i2s->is_dam_used = true; | ||
467 | #endif | ||
468 | |||
469 | if (machine->init_done) | ||
470 | return 0; | ||
471 | |||
472 | machine->init_done = true; | ||
473 | |||
474 | if (gpio_is_valid(pdata->gpio_spkr_en)) { | ||
475 | ret = gpio_request(pdata->gpio_spkr_en, "spkr_en"); | ||
476 | if (ret) { | ||
477 | dev_err(card->dev, "cannot get spkr_en gpio\n"); | ||
478 | return ret; | ||
479 | } | ||
480 | machine->gpio_requested |= GPIO_SPKR_EN; | ||
481 | |||
482 | gpio_direction_output(pdata->gpio_spkr_en, 0); | ||
483 | } | ||
484 | |||
485 | if (gpio_is_valid(pdata->gpio_hp_mute)) { | ||
486 | ret = gpio_request(pdata->gpio_hp_mute, "hp_mute"); | ||
487 | if (ret) { | ||
488 | dev_err(card->dev, "cannot get hp_mute gpio\n"); | ||
489 | return ret; | ||
490 | } | ||
491 | machine->gpio_requested |= GPIO_HP_MUTE; | ||
492 | |||
493 | gpio_direction_output(pdata->gpio_hp_mute, 0); | ||
494 | } | ||
495 | |||
496 | if (gpio_is_valid(pdata->gpio_int_mic_en)) { | ||
497 | ret = gpio_request(pdata->gpio_int_mic_en, "int_mic_en"); | ||
498 | if (ret) { | ||
499 | dev_err(card->dev, "cannot get int_mic_en gpio\n"); | ||
500 | return ret; | ||
501 | } | ||
502 | machine->gpio_requested |= GPIO_INT_MIC_EN; | ||
503 | |||
504 | /* Disable int mic; enable signal is active-high */ | ||
505 | gpio_direction_output(pdata->gpio_int_mic_en, 0); | ||
506 | } | ||
507 | |||
508 | if (gpio_is_valid(pdata->gpio_ext_mic_en)) { | ||
509 | ret = gpio_request(pdata->gpio_ext_mic_en, "ext_mic_en"); | ||
510 | if (ret) { | ||
511 | dev_err(card->dev, "cannot get ext_mic_en gpio\n"); | ||
512 | return ret; | ||
513 | } | ||
514 | machine->gpio_requested |= GPIO_EXT_MIC_EN; | ||
515 | |||
516 | /* Enable ext mic; enable signal is active-low */ | ||
517 | gpio_direction_output(pdata->gpio_ext_mic_en, 0); | ||
518 | } | ||
519 | |||
520 | ret = snd_soc_add_controls(codec, tegra_max98095_controls, | ||
521 | ARRAY_SIZE(tegra_max98095_controls)); | ||
522 | if (ret < 0) | ||
523 | return ret; | ||
524 | |||
525 | snd_soc_dapm_new_controls(dapm, tegra_max98095_dapm_widgets, | ||
526 | ARRAY_SIZE(tegra_max98095_dapm_widgets)); | ||
527 | |||
528 | snd_soc_dapm_add_routes(dapm, enterprise_audio_map, | ||
529 | ARRAY_SIZE(enterprise_audio_map)); | ||
530 | |||
531 | ret = snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET, | ||
532 | &tegra_max98095_hp_jack); | ||
533 | if (ret < 0) | ||
534 | return ret; | ||
535 | |||
536 | #ifdef CONFIG_SWITCH | ||
537 | snd_soc_jack_notifier_register(&tegra_max98095_hp_jack, | ||
538 | &headset_switch_nb); | ||
539 | #else /*gpio based headset detection*/ | ||
540 | snd_soc_jack_add_pins(&tegra_max98095_hp_jack, | ||
541 | ARRAY_SIZE(tegra_max98095_hp_jack_pins), | ||
542 | tegra_max98095_hp_jack_pins); | ||
543 | #endif | ||
544 | |||
545 | /* max98095_headset_detect(codec, &tegra_max98095_hp_jack, | ||
546 | SND_JACK_HEADSET); */ | ||
547 | |||
548 | snd_soc_dapm_nc_pin(dapm, "INA1"); | ||
549 | snd_soc_dapm_nc_pin(dapm, "INA2"); | ||
550 | snd_soc_dapm_nc_pin(dapm, "INB1"); | ||
551 | snd_soc_dapm_nc_pin(dapm, "INB2"); | ||
552 | snd_soc_dapm_sync(dapm); | ||
553 | |||
554 | return 0; | ||
555 | } | ||
556 | |||
557 | static struct snd_soc_dai_link tegra_max98095_dai[] = { | ||
558 | { | ||
559 | .name = "MAX98095", | ||
560 | .stream_name = "MAX98095 HIFI", | ||
561 | .codec_name = "max98095.4-0010", | ||
562 | .platform_name = "tegra-pcm-audio", | ||
563 | .cpu_dai_name = "tegra30-i2s.1", | ||
564 | .codec_dai_name = "HiFi", | ||
565 | .init = tegra_max98095_init, | ||
566 | .ops = &tegra_max98095_ops, | ||
567 | }, | ||
568 | { | ||
569 | .name = "SPDIF", | ||
570 | .stream_name = "SPDIF PCM", | ||
571 | .codec_name = "spdif-dit.0", | ||
572 | .platform_name = "tegra-pcm-audio", | ||
573 | .cpu_dai_name = "tegra30-spdif", | ||
574 | .codec_dai_name = "dit-hifi", | ||
575 | .ops = &tegra_spdif_ops, | ||
576 | }, | ||
577 | }; | ||
578 | |||
579 | static int tegra30_soc_set_bias_level(struct snd_soc_card *card, | ||
580 | enum snd_soc_bias_level level) | ||
581 | { | ||
582 | struct tegra_max98095 *machine = snd_soc_card_get_drvdata(card); | ||
583 | |||
584 | if (machine->bias_level == SND_SOC_BIAS_OFF && | ||
585 | level != SND_SOC_BIAS_OFF) | ||
586 | tegra_asoc_utils_clk_enable(&machine->util_data); | ||
587 | |||
588 | machine->bias_level = level; | ||
589 | |||
590 | return 0; | ||
591 | } | ||
592 | |||
593 | static int tegra30_soc_set_bias_level_post(struct snd_soc_card *card, | ||
594 | enum snd_soc_bias_level level) | ||
595 | { | ||
596 | struct tegra_max98095 *machine = snd_soc_card_get_drvdata(card); | ||
597 | |||
598 | if (level == SND_SOC_BIAS_OFF) | ||
599 | tegra_asoc_utils_clk_disable(&machine->util_data); | ||
600 | |||
601 | return 0 ; | ||
602 | } | ||
603 | |||
604 | static struct snd_soc_card snd_soc_tegra_max98095 = { | ||
605 | .name = "tegra-max98095", | ||
606 | .dai_link = tegra_max98095_dai, | ||
607 | .num_links = ARRAY_SIZE(tegra_max98095_dai), | ||
608 | .set_bias_level = tegra30_soc_set_bias_level, | ||
609 | .set_bias_level_post = tegra30_soc_set_bias_level_post, | ||
610 | }; | ||
611 | |||
612 | static __devinit int tegra_max98095_driver_probe(struct platform_device *pdev) | ||
613 | { | ||
614 | struct snd_soc_card *card = &snd_soc_tegra_max98095; | ||
615 | struct tegra_max98095 *machine; | ||
616 | struct tegra_asoc_platform_data *pdata; | ||
617 | int ret; | ||
618 | |||
619 | pdata = pdev->dev.platform_data; | ||
620 | if (!pdata) { | ||
621 | dev_err(&pdev->dev, "No platform data supplied\n"); | ||
622 | return -EINVAL; | ||
623 | } | ||
624 | |||
625 | machine = kzalloc(sizeof(struct tegra_max98095), GFP_KERNEL); | ||
626 | if (!machine) { | ||
627 | dev_err(&pdev->dev, "Can't allocate tegra_max98095 struct\n"); | ||
628 | return -ENOMEM; | ||
629 | } | ||
630 | |||
631 | machine->pdata = pdata; | ||
632 | |||
633 | ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); | ||
634 | if (ret) | ||
635 | goto err_free_machine; | ||
636 | |||
637 | card->dev = &pdev->dev; | ||
638 | platform_set_drvdata(pdev, card); | ||
639 | snd_soc_card_set_drvdata(card, machine); | ||
640 | |||
641 | #ifdef CONFIG_SWITCH | ||
642 | /* Add h2w switch class support */ | ||
643 | ret = switch_dev_register(&wired_switch_dev); | ||
644 | if (ret < 0) { | ||
645 | dev_err(&pdev->dev, "not able to register switch device\n"); | ||
646 | goto err_fini_utils; | ||
647 | } | ||
648 | #endif | ||
649 | |||
650 | ret = snd_soc_register_card(card); | ||
651 | if (ret) { | ||
652 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", | ||
653 | ret); | ||
654 | goto err_switch_unregister; | ||
655 | } | ||
656 | |||
657 | return 0; | ||
658 | |||
659 | err_switch_unregister: | ||
660 | #ifdef CONFIG_SWITCH | ||
661 | switch_dev_unregister(&wired_switch_dev); | ||
662 | #endif | ||
663 | err_fini_utils: | ||
664 | tegra_asoc_utils_fini(&machine->util_data); | ||
665 | err_free_machine: | ||
666 | kfree(machine); | ||
667 | return ret; | ||
668 | } | ||
669 | |||
670 | static int __devexit tegra_max98095_driver_remove(struct platform_device *pdev) | ||
671 | { | ||
672 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
673 | struct tegra_max98095 *machine = snd_soc_card_get_drvdata(card); | ||
674 | struct tegra_asoc_platform_data *pdata = machine->pdata; | ||
675 | |||
676 | snd_soc_unregister_card(card); | ||
677 | |||
678 | #ifdef CONFIG_SWITCH | ||
679 | switch_dev_unregister(&wired_switch_dev); | ||
680 | #endif | ||
681 | |||
682 | tegra_asoc_utils_fini(&machine->util_data); | ||
683 | |||
684 | if (machine->gpio_requested & GPIO_EXT_MIC_EN) | ||
685 | gpio_free(pdata->gpio_ext_mic_en); | ||
686 | if (machine->gpio_requested & GPIO_INT_MIC_EN) | ||
687 | gpio_free(pdata->gpio_int_mic_en); | ||
688 | if (machine->gpio_requested & GPIO_HP_MUTE) | ||
689 | gpio_free(pdata->gpio_hp_mute); | ||
690 | if (machine->gpio_requested & GPIO_SPKR_EN) | ||
691 | gpio_free(pdata->gpio_spkr_en); | ||
692 | |||
693 | kfree(machine); | ||
694 | |||
695 | return 0; | ||
696 | } | ||
697 | |||
698 | static struct platform_driver tegra_max98095_driver = { | ||
699 | .driver = { | ||
700 | .name = DRV_NAME, | ||
701 | .owner = THIS_MODULE, | ||
702 | .pm = &snd_soc_pm_ops, | ||
703 | }, | ||
704 | .probe = tegra_max98095_driver_probe, | ||
705 | .remove = __devexit_p(tegra_max98095_driver_remove), | ||
706 | }; | ||
707 | |||
708 | static int __init tegra_max98095_modinit(void) | ||
709 | { | ||
710 | return platform_driver_register(&tegra_max98095_driver); | ||
711 | } | ||
712 | module_init(tegra_max98095_modinit); | ||
713 | |||
714 | static void __exit tegra_max98095_modexit(void) | ||
715 | { | ||
716 | platform_driver_unregister(&tegra_max98095_driver); | ||
717 | } | ||
718 | module_exit(tegra_max98095_modexit); | ||
719 | |||
720 | MODULE_AUTHOR("Ravindra Lokhande <rlokhande@nvidia.com>"); | ||
721 | MODULE_DESCRIPTION("Tegra+MAX98095 machine ASoC driver"); | ||
722 | MODULE_LICENSE("GPL"); | ||
723 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/sound/soc/tegra/tegra_p1852.c b/sound/soc/tegra/tegra_p1852.c new file mode 100644 index 00000000000..27a1ea59034 --- /dev/null +++ b/sound/soc/tegra/tegra_p1852.c | |||
@@ -0,0 +1,272 @@ | |||
1 | /* | ||
2 | * tegra_p1852.c - Tegra machine ASoC driver for P1852 Boards. | ||
3 | * | ||
4 | * Author: Nitin Pai <npai@nvidia.com> | ||
5 | * Copyright (C) 2010-2012 - NVIDIA, Inc. | ||
6 | * | ||
7 | * Based on code copyright/by: | ||
8 | * Copyright (c) 2009-2010, NVIDIA Corporation. | ||
9 | * Stephen Warren <swarren@nvidia.com> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * version 2 as published by the Free Software Foundation. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, but | ||
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | * General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
23 | * 02110-1301 USA | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include <asm/mach-types.h> | ||
28 | |||
29 | #include <linux/clk.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/platform_device.h> | ||
32 | #include <linux/slab.h> | ||
33 | |||
34 | #include <mach/tegra_p1852_pdata.h> | ||
35 | |||
36 | #include <sound/core.h> | ||
37 | #include <sound/pcm.h> | ||
38 | #include <sound/pcm_params.h> | ||
39 | #include <sound/soc.h> | ||
40 | |||
41 | #include "tegra_pcm.h" | ||
42 | #include "tegra_asoc_utils.h" | ||
43 | |||
44 | #define DRV_NAME "tegra-snd-p1852" | ||
45 | |||
46 | struct tegra_p1852 { | ||
47 | struct tegra_asoc_utils_data util_data; | ||
48 | struct tegra_p1852_platform_data *pdata; | ||
49 | }; | ||
50 | |||
51 | static int tegra_p1852_hw_params(struct snd_pcm_substream *substream, | ||
52 | struct snd_pcm_hw_params *params) | ||
53 | { | ||
54 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
55 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
56 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
57 | struct snd_soc_codec *codec = rtd->codec; | ||
58 | struct snd_soc_card *card = codec->card; | ||
59 | struct tegra_p1852 *machine = snd_soc_card_get_drvdata(card); | ||
60 | int srate, mclk; | ||
61 | int i2s_daifmt = 0; | ||
62 | int err; | ||
63 | struct tegra_p1852_platform_data *pdata; | ||
64 | int codec_id = codec_dai->id; | ||
65 | |||
66 | pdata = machine->pdata; | ||
67 | |||
68 | srate = params_rate(params); | ||
69 | switch (srate) { | ||
70 | case 64000: | ||
71 | case 88200: | ||
72 | case 96000: | ||
73 | mclk = 128 * srate; | ||
74 | break; | ||
75 | default: | ||
76 | mclk = 256 * srate; | ||
77 | break; | ||
78 | } | ||
79 | |||
80 | err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); | ||
81 | if (err < 0) { | ||
82 | if (!(machine->util_data.set_mclk % mclk)) | ||
83 | mclk = machine->util_data.set_mclk; | ||
84 | else { | ||
85 | dev_err(card->dev, "Can't configure clocks\n"); | ||
86 | return err; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); | ||
91 | |||
92 | if (pdata->codec_info[codec_id].master) | ||
93 | i2s_daifmt |= SND_SOC_DAIFMT_CBM_CFM; | ||
94 | else | ||
95 | i2s_daifmt |= SND_SOC_DAIFMT_CBS_CFS; | ||
96 | |||
97 | switch (pdata->codec_info[codec_id].i2s_format) { | ||
98 | case format_tdm: | ||
99 | i2s_daifmt |= SND_SOC_DAIFMT_DSP_A; | ||
100 | break; | ||
101 | case format_i2s: | ||
102 | i2s_daifmt |= SND_SOC_DAIFMT_I2S; | ||
103 | break; | ||
104 | case format_rjm: | ||
105 | i2s_daifmt |= SND_SOC_DAIFMT_RIGHT_J; | ||
106 | break; | ||
107 | case format_ljm: | ||
108 | i2s_daifmt |= SND_SOC_DAIFMT_LEFT_J; | ||
109 | break; | ||
110 | default: | ||
111 | break; | ||
112 | } | ||
113 | |||
114 | err = snd_soc_dai_set_fmt(codec_dai, i2s_daifmt); | ||
115 | if (err < 0) | ||
116 | dev_info(card->dev, "codec_dai fmt not set\n"); | ||
117 | |||
118 | err = snd_soc_dai_set_fmt(cpu_dai, i2s_daifmt); | ||
119 | if (err < 0) { | ||
120 | dev_err(card->dev, "cpu_dai fmt not set\n"); | ||
121 | return err; | ||
122 | } | ||
123 | |||
124 | err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, | ||
125 | SND_SOC_CLOCK_IN); | ||
126 | if (err < 0) | ||
127 | dev_info(card->dev, "codec_dai clock not set\n"); | ||
128 | |||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | static int tegra_hw_free(struct snd_pcm_substream *substream) | ||
133 | { | ||
134 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
135 | struct tegra_p1852 *machine = snd_soc_card_get_drvdata(rtd->card); | ||
136 | |||
137 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 0); | ||
138 | |||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | static struct snd_soc_ops tegra_p1852_ops = { | ||
143 | .hw_params = tegra_p1852_hw_params, | ||
144 | .hw_free = tegra_hw_free, | ||
145 | }; | ||
146 | |||
147 | static struct snd_soc_dai_link tegra_p1852_dai_link[] = { | ||
148 | { | ||
149 | .name = "I2S-TDM-1", | ||
150 | .stream_name = "TEGRA PCM", | ||
151 | .platform_name = "tegra-pcm-audio", | ||
152 | .ops = &tegra_p1852_ops, | ||
153 | }, | ||
154 | { | ||
155 | .name = "I2S-TDM-2", | ||
156 | .stream_name = "TEGRA PCM", | ||
157 | .platform_name = "tegra-pcm-audio", | ||
158 | .ops = &tegra_p1852_ops, | ||
159 | } | ||
160 | }; | ||
161 | |||
162 | static struct snd_soc_card snd_soc_tegra_p1852 = { | ||
163 | .name = "tegra-p1852", | ||
164 | .dai_link = tegra_p1852_dai_link, | ||
165 | .num_links = ARRAY_SIZE(tegra_p1852_dai_link), | ||
166 | }; | ||
167 | |||
168 | static __devinit int tegra_p1852_driver_probe(struct platform_device *pdev) | ||
169 | { | ||
170 | struct snd_soc_card *card = &snd_soc_tegra_p1852; | ||
171 | struct tegra_p1852 *machine; | ||
172 | struct tegra_p1852_platform_data *pdata; | ||
173 | int ret; | ||
174 | int i; | ||
175 | |||
176 | pdata = pdev->dev.platform_data; | ||
177 | if (!pdata) { | ||
178 | dev_err(&pdev->dev, "No platform data supplied\n"); | ||
179 | return -EINVAL; | ||
180 | } | ||
181 | |||
182 | machine = kzalloc(sizeof(struct tegra_p1852), GFP_KERNEL); | ||
183 | if (!machine) { | ||
184 | dev_err(&pdev->dev, "Can't allocate tegra_p1852 struct\n"); | ||
185 | return -ENOMEM; | ||
186 | } | ||
187 | |||
188 | machine->pdata = pdata; | ||
189 | |||
190 | /* The codec driver and codec dai have to come from the system | ||
191 | * level board configuration file | ||
192 | * */ | ||
193 | for (i = 0; i < ARRAY_SIZE(tegra_p1852_dai_link); i++) { | ||
194 | tegra_p1852_dai_link[i].codec_name = | ||
195 | pdata->codec_info[i].codec_name; | ||
196 | tegra_p1852_dai_link[i].cpu_dai_name = | ||
197 | pdata->codec_info[i].cpu_dai_name; | ||
198 | tegra_p1852_dai_link[i].codec_dai_name = | ||
199 | pdata->codec_info[i].codec_dai_name; | ||
200 | tegra_p1852_dai_link[i].name = | ||
201 | pdata->codec_info[i].name; | ||
202 | } | ||
203 | |||
204 | ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); | ||
205 | if (ret) | ||
206 | goto err_free_machine; | ||
207 | |||
208 | card->dev = &pdev->dev; | ||
209 | platform_set_drvdata(pdev, card); | ||
210 | snd_soc_card_set_drvdata(card, machine); | ||
211 | |||
212 | ret = snd_soc_register_card(card); | ||
213 | if (ret) { | ||
214 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", | ||
215 | ret); | ||
216 | } | ||
217 | |||
218 | if (!card->instantiated) { | ||
219 | ret = -ENODEV; | ||
220 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", | ||
221 | ret); | ||
222 | goto err_unregister_card; | ||
223 | } | ||
224 | |||
225 | return 0; | ||
226 | |||
227 | err_unregister_card: | ||
228 | snd_soc_unregister_card(card); | ||
229 | tegra_asoc_utils_fini(&machine->util_data); | ||
230 | err_free_machine: | ||
231 | kfree(machine); | ||
232 | return ret; | ||
233 | } | ||
234 | |||
235 | static int __devexit tegra_p1852_driver_remove(struct platform_device *pdev) | ||
236 | { | ||
237 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
238 | struct tegra_p1852 *machine = snd_soc_card_get_drvdata(card); | ||
239 | |||
240 | snd_soc_unregister_card(card); | ||
241 | tegra_asoc_utils_fini(&machine->util_data); | ||
242 | kfree(machine); | ||
243 | |||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | static struct platform_driver tegra_p1852_driver = { | ||
248 | .driver = { | ||
249 | .name = DRV_NAME, | ||
250 | .owner = THIS_MODULE, | ||
251 | .pm = &snd_soc_pm_ops, | ||
252 | }, | ||
253 | .probe = tegra_p1852_driver_probe, | ||
254 | .remove = __devexit_p(tegra_p1852_driver_remove), | ||
255 | }; | ||
256 | |||
257 | static int __init tegra_p1852_modinit(void) | ||
258 | { | ||
259 | return platform_driver_register(&tegra_p1852_driver); | ||
260 | } | ||
261 | module_init(tegra_p1852_modinit); | ||
262 | |||
263 | static void __exit tegra_p1852_modexit(void) | ||
264 | { | ||
265 | platform_driver_unregister(&tegra_p1852_driver); | ||
266 | } | ||
267 | module_exit(tegra_p1852_modexit); | ||
268 | |||
269 | MODULE_AUTHOR("Nitin Pai <npai@nvidia.com>"); | ||
270 | MODULE_DESCRIPTION("Tegra+P1852 machine ASoC driver"); | ||
271 | MODULE_LICENSE("GPL"); | ||
272 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c new file mode 100644 index 00000000000..f6f4ed3d421 --- /dev/null +++ b/sound/soc/tegra/tegra_rt5640.c | |||
@@ -0,0 +1,738 @@ | |||
1 | /* | ||
2 | * tegra_rt5640.c - Tegra machine ASoC driver for boards using ALC5640 codec. | ||
3 | * | ||
4 | * Author: Johnny Qiu <joqiu@nvidia.com> | ||
5 | * Copyright (C) 2011-2012, NVIDIA, Inc. | ||
6 | * | ||
7 | * Based on code copyright/by: | ||
8 | * | ||
9 | * Copyright 2007 Wolfson Microelectronics PLC. | ||
10 | * Author: Graeme Gregory | ||
11 | * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * version 2 as published by the Free Software Foundation. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, but | ||
18 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
20 | * General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
25 | * 02110-1301 USA | ||
26 | * | ||
27 | */ | ||
28 | |||
29 | #include <asm/mach-types.h> | ||
30 | |||
31 | #include <linux/module.h> | ||
32 | #include <linux/platform_device.h> | ||
33 | #include <linux/slab.h> | ||
34 | #include <linux/gpio.h> | ||
35 | #include <linux/regulator/consumer.h> | ||
36 | #ifdef CONFIG_SWITCH | ||
37 | #include <linux/switch.h> | ||
38 | #endif | ||
39 | |||
40 | #include <mach/tegra_rt5640_pdata.h> | ||
41 | |||
42 | #include <sound/core.h> | ||
43 | #include <sound/jack.h> | ||
44 | #include <sound/pcm.h> | ||
45 | #include <sound/pcm_params.h> | ||
46 | #include <sound/soc.h> | ||
47 | |||
48 | #include "../codecs/rt5639.h" | ||
49 | #include "../codecs/rt5640.h" | ||
50 | |||
51 | #include "tegra_pcm.h" | ||
52 | #include "tegra_asoc_utils.h" | ||
53 | |||
54 | #define DRV_NAME "tegra-snd-rt5640" | ||
55 | |||
56 | #define GPIO_SPKR_EN BIT(0) | ||
57 | #define GPIO_HP_MUTE BIT(1) | ||
58 | #define GPIO_INT_MIC_EN BIT(2) | ||
59 | #define GPIO_EXT_MIC_EN BIT(3) | ||
60 | #define GPIO_HP_DET BIT(4) | ||
61 | |||
62 | struct tegra_rt5640 { | ||
63 | struct tegra_asoc_utils_data util_data; | ||
64 | struct tegra_rt5640_platform_data *pdata; | ||
65 | struct regulator *spk_reg; | ||
66 | struct regulator *dmic_reg; | ||
67 | struct regulator *cdc_en; | ||
68 | int gpio_requested; | ||
69 | #ifdef CONFIG_SWITCH | ||
70 | int jack_status; | ||
71 | #endif | ||
72 | }; | ||
73 | |||
74 | static int tegra_rt5640_hw_params(struct snd_pcm_substream *substream, | ||
75 | struct snd_pcm_hw_params *params) | ||
76 | { | ||
77 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
78 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
79 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
80 | struct snd_soc_codec *codec = rtd->codec; | ||
81 | struct snd_soc_card *card = codec->card; | ||
82 | struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); | ||
83 | int srate, mclk, i2s_daifmt; | ||
84 | int err; | ||
85 | |||
86 | srate = params_rate(params); | ||
87 | mclk = 256 * srate; | ||
88 | err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); | ||
89 | if (err < 0) { | ||
90 | if (!(machine->util_data.set_mclk % mclk)) { | ||
91 | mclk = machine->util_data.set_mclk; | ||
92 | } else { | ||
93 | dev_err(card->dev, "Can't configure clocks\n"); | ||
94 | return err; | ||
95 | } | ||
96 | } | ||
97 | |||
98 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); | ||
99 | |||
100 | i2s_daifmt = SND_SOC_DAIFMT_NB_NF | | ||
101 | SND_SOC_DAIFMT_CBS_CFS; | ||
102 | |||
103 | i2s_daifmt |= SND_SOC_DAIFMT_I2S; | ||
104 | |||
105 | err = snd_soc_dai_set_fmt(codec_dai, i2s_daifmt); | ||
106 | if (err < 0) { | ||
107 | dev_err(card->dev, "codec_dai fmt not set\n"); | ||
108 | return err; | ||
109 | } | ||
110 | |||
111 | err = snd_soc_dai_set_fmt(cpu_dai, i2s_daifmt); | ||
112 | if (err < 0) { | ||
113 | dev_err(card->dev, "cpu_dai fmt not set\n"); | ||
114 | return err; | ||
115 | } | ||
116 | |||
117 | err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, | ||
118 | SND_SOC_CLOCK_IN); | ||
119 | if (err < 0) { | ||
120 | dev_err(card->dev, "codec_dai clock not set\n"); | ||
121 | return err; | ||
122 | } | ||
123 | |||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | static int tegra_bt_sco_hw_params(struct snd_pcm_substream *substream, | ||
128 | struct snd_pcm_hw_params *params) | ||
129 | { | ||
130 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
131 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
132 | struct snd_soc_card *card = rtd->card; | ||
133 | struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); | ||
134 | int srate, mclk, min_mclk; | ||
135 | int err; | ||
136 | |||
137 | srate = params_rate(params); | ||
138 | switch (srate) { | ||
139 | case 11025: | ||
140 | case 22050: | ||
141 | case 44100: | ||
142 | case 88200: | ||
143 | mclk = 11289600; | ||
144 | break; | ||
145 | case 8000: | ||
146 | case 16000: | ||
147 | case 32000: | ||
148 | case 48000: | ||
149 | case 64000: | ||
150 | case 96000: | ||
151 | mclk = 12288000; | ||
152 | break; | ||
153 | default: | ||
154 | return -EINVAL; | ||
155 | } | ||
156 | min_mclk = 64 * srate; | ||
157 | |||
158 | err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); | ||
159 | if (err < 0) { | ||
160 | if (!(machine->util_data.set_mclk % min_mclk)) | ||
161 | mclk = machine->util_data.set_mclk; | ||
162 | else { | ||
163 | dev_err(card->dev, "Can't configure clocks\n"); | ||
164 | return err; | ||
165 | } | ||
166 | } | ||
167 | |||
168 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); | ||
169 | |||
170 | err = snd_soc_dai_set_fmt(cpu_dai, | ||
171 | SND_SOC_DAIFMT_DSP_A | | ||
172 | SND_SOC_DAIFMT_NB_NF | | ||
173 | SND_SOC_DAIFMT_CBS_CFS); | ||
174 | if (err < 0) { | ||
175 | dev_err(card->dev, "cpu_dai fmt not set\n"); | ||
176 | return err; | ||
177 | } | ||
178 | |||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | static int tegra_spdif_hw_params(struct snd_pcm_substream *substream, | ||
183 | struct snd_pcm_hw_params *params) | ||
184 | { | ||
185 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
186 | struct snd_soc_card *card = rtd->card; | ||
187 | struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); | ||
188 | int srate, mclk, min_mclk; | ||
189 | int err; | ||
190 | |||
191 | srate = params_rate(params); | ||
192 | switch (srate) { | ||
193 | case 11025: | ||
194 | case 22050: | ||
195 | case 44100: | ||
196 | case 88200: | ||
197 | mclk = 11289600; | ||
198 | break; | ||
199 | case 8000: | ||
200 | case 16000: | ||
201 | case 32000: | ||
202 | case 48000: | ||
203 | case 64000: | ||
204 | case 96000: | ||
205 | mclk = 12288000; | ||
206 | break; | ||
207 | default: | ||
208 | return -EINVAL; | ||
209 | } | ||
210 | min_mclk = 128 * srate; | ||
211 | |||
212 | err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); | ||
213 | if (err < 0) { | ||
214 | if (!(machine->util_data.set_mclk % min_mclk)) | ||
215 | mclk = machine->util_data.set_mclk; | ||
216 | else { | ||
217 | dev_err(card->dev, "Can't configure clocks\n"); | ||
218 | return err; | ||
219 | } | ||
220 | } | ||
221 | |||
222 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); | ||
223 | |||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | static int tegra_hw_free(struct snd_pcm_substream *substream) | ||
228 | { | ||
229 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
230 | struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(rtd->card); | ||
231 | |||
232 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 0); | ||
233 | |||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static struct snd_soc_ops tegra_rt5640_ops = { | ||
238 | .hw_params = tegra_rt5640_hw_params, | ||
239 | .hw_free = tegra_hw_free, | ||
240 | }; | ||
241 | |||
242 | static struct snd_soc_ops tegra_rt5640_bt_sco_ops = { | ||
243 | .hw_params = tegra_bt_sco_hw_params, | ||
244 | .hw_free = tegra_hw_free, | ||
245 | }; | ||
246 | |||
247 | static struct snd_soc_ops tegra_spdif_ops = { | ||
248 | .hw_params = tegra_spdif_hw_params, | ||
249 | .hw_free = tegra_hw_free, | ||
250 | }; | ||
251 | |||
252 | static struct snd_soc_jack tegra_rt5640_hp_jack; | ||
253 | |||
254 | static struct snd_soc_jack_gpio tegra_rt5640_hp_jack_gpio = { | ||
255 | .name = "headphone detect", | ||
256 | .report = SND_JACK_HEADPHONE, | ||
257 | .debounce_time = 150, | ||
258 | .invert = 1, | ||
259 | }; | ||
260 | |||
261 | #ifdef CONFIG_SWITCH | ||
262 | /* These values are copied from Android WiredAccessoryObserver */ | ||
263 | enum headset_state { | ||
264 | BIT_NO_HEADSET = 0, | ||
265 | BIT_HEADSET = (1 << 0), | ||
266 | BIT_HEADSET_NO_MIC = (1 << 1), | ||
267 | }; | ||
268 | |||
269 | static struct switch_dev tegra_rt5640_headset_switch = { | ||
270 | .name = "h2w", | ||
271 | }; | ||
272 | |||
273 | static int tegra_rt5640_jack_notifier(struct notifier_block *self, | ||
274 | unsigned long action, void *dev) | ||
275 | { | ||
276 | struct snd_soc_jack *jack = dev; | ||
277 | struct snd_soc_codec *codec = jack->codec; | ||
278 | struct snd_soc_card *card = codec->card; | ||
279 | struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); | ||
280 | enum headset_state state = BIT_NO_HEADSET; | ||
281 | unsigned char status_jack; | ||
282 | |||
283 | if (jack == &tegra_rt5640_hp_jack) { | ||
284 | if (action) { | ||
285 | if (!strncmp(machine->pdata->codec_name, "rt5639", 6)) | ||
286 | status_jack = rt5639_headset_detect(codec, 1); | ||
287 | else if (!strncmp(machine->pdata->codec_name, "rt5640", | ||
288 | 6)) | ||
289 | status_jack = rt5640_headset_detect(codec, 1); | ||
290 | |||
291 | machine->jack_status &= ~SND_JACK_HEADPHONE; | ||
292 | machine->jack_status &= ~SND_JACK_MICROPHONE; | ||
293 | if (status_jack == RT5639_HEADPHO_DET || | ||
294 | status_jack == RT5640_HEADPHO_DET) | ||
295 | machine->jack_status |= | ||
296 | SND_JACK_HEADPHONE; | ||
297 | else if (status_jack == RT5639_HEADSET_DET || | ||
298 | status_jack == RT5640_HEADSET_DET) { | ||
299 | machine->jack_status |= | ||
300 | SND_JACK_HEADPHONE; | ||
301 | machine->jack_status |= | ||
302 | SND_JACK_MICROPHONE; | ||
303 | } | ||
304 | } else { | ||
305 | if (!strncmp(machine->pdata->codec_name, "rt5639", 6)) | ||
306 | rt5639_headset_detect(codec, 0); | ||
307 | else if (!strncmp(machine->pdata->codec_name, "rt5640", | ||
308 | 6)) | ||
309 | rt5640_headset_detect(codec, 0); | ||
310 | |||
311 | machine->jack_status &= ~SND_JACK_HEADPHONE; | ||
312 | machine->jack_status &= ~SND_JACK_MICROPHONE; | ||
313 | } | ||
314 | } | ||
315 | |||
316 | switch (machine->jack_status) { | ||
317 | case SND_JACK_HEADPHONE: | ||
318 | state = BIT_HEADSET_NO_MIC; | ||
319 | break; | ||
320 | case SND_JACK_HEADSET: | ||
321 | state = BIT_HEADSET; | ||
322 | break; | ||
323 | case SND_JACK_MICROPHONE: | ||
324 | /* mic: would not report */ | ||
325 | default: | ||
326 | state = BIT_NO_HEADSET; | ||
327 | } | ||
328 | |||
329 | switch_set_state(&tegra_rt5640_headset_switch, state); | ||
330 | |||
331 | return NOTIFY_OK; | ||
332 | } | ||
333 | |||
334 | static struct notifier_block tegra_rt5640_jack_detect_nb = { | ||
335 | .notifier_call = tegra_rt5640_jack_notifier, | ||
336 | }; | ||
337 | #else | ||
338 | static struct snd_soc_jack_pin tegra_rt5640_hp_jack_pins[] = { | ||
339 | { | ||
340 | .pin = "Headphone Jack", | ||
341 | .mask = SND_JACK_HEADPHONE, | ||
342 | }, | ||
343 | }; | ||
344 | |||
345 | #endif | ||
346 | |||
347 | static int tegra_rt5640_event_int_spk(struct snd_soc_dapm_widget *w, | ||
348 | struct snd_kcontrol *k, int event) | ||
349 | { | ||
350 | struct snd_soc_dapm_context *dapm = w->dapm; | ||
351 | struct snd_soc_card *card = dapm->card; | ||
352 | struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); | ||
353 | struct tegra_rt5640_platform_data *pdata = machine->pdata; | ||
354 | |||
355 | if (machine->spk_reg) { | ||
356 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
357 | regulator_enable(machine->spk_reg); | ||
358 | else | ||
359 | regulator_disable(machine->spk_reg); | ||
360 | } | ||
361 | |||
362 | if (!(machine->gpio_requested & GPIO_SPKR_EN)) | ||
363 | return 0; | ||
364 | |||
365 | gpio_set_value_cansleep(pdata->gpio_spkr_en, | ||
366 | SND_SOC_DAPM_EVENT_ON(event)); | ||
367 | |||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | static int tegra_rt5640_event_hp(struct snd_soc_dapm_widget *w, | ||
372 | struct snd_kcontrol *k, int event) | ||
373 | { | ||
374 | struct snd_soc_dapm_context *dapm = w->dapm; | ||
375 | struct snd_soc_card *card = dapm->card; | ||
376 | struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); | ||
377 | struct tegra_rt5640_platform_data *pdata = machine->pdata; | ||
378 | |||
379 | if (!(machine->gpio_requested & GPIO_HP_MUTE)) | ||
380 | return 0; | ||
381 | |||
382 | gpio_set_value_cansleep(pdata->gpio_hp_mute, | ||
383 | !SND_SOC_DAPM_EVENT_ON(event)); | ||
384 | |||
385 | return 0; | ||
386 | } | ||
387 | |||
388 | static int tegra_rt5640_event_int_mic(struct snd_soc_dapm_widget *w, | ||
389 | struct snd_kcontrol *k, int event) | ||
390 | { | ||
391 | struct snd_soc_dapm_context *dapm = w->dapm; | ||
392 | struct snd_soc_card *card = dapm->card; | ||
393 | struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); | ||
394 | struct tegra_rt5640_platform_data *pdata = machine->pdata; | ||
395 | |||
396 | if (machine->dmic_reg) { | ||
397 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
398 | regulator_enable(machine->dmic_reg); | ||
399 | else | ||
400 | regulator_disable(machine->dmic_reg); | ||
401 | } | ||
402 | |||
403 | if (!(machine->gpio_requested & GPIO_INT_MIC_EN)) | ||
404 | return 0; | ||
405 | |||
406 | gpio_set_value_cansleep(pdata->gpio_int_mic_en, | ||
407 | SND_SOC_DAPM_EVENT_ON(event)); | ||
408 | |||
409 | return 0; | ||
410 | } | ||
411 | |||
412 | static int tegra_rt5640_event_ext_mic(struct snd_soc_dapm_widget *w, | ||
413 | struct snd_kcontrol *k, int event) | ||
414 | { | ||
415 | struct snd_soc_dapm_context *dapm = w->dapm; | ||
416 | struct snd_soc_card *card = dapm->card; | ||
417 | struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); | ||
418 | struct tegra_rt5640_platform_data *pdata = machine->pdata; | ||
419 | |||
420 | if (!(machine->gpio_requested & GPIO_EXT_MIC_EN)) | ||
421 | return 0; | ||
422 | |||
423 | gpio_set_value_cansleep(pdata->gpio_ext_mic_en, | ||
424 | !SND_SOC_DAPM_EVENT_ON(event)); | ||
425 | |||
426 | return 0; | ||
427 | } | ||
428 | |||
429 | static const struct snd_soc_dapm_widget cardhu_dapm_widgets[] = { | ||
430 | SND_SOC_DAPM_SPK("Int Spk", tegra_rt5640_event_int_spk), | ||
431 | SND_SOC_DAPM_HP("Headphone Jack", tegra_rt5640_event_hp), | ||
432 | SND_SOC_DAPM_MIC("Mic Jack", tegra_rt5640_event_ext_mic), | ||
433 | SND_SOC_DAPM_MIC("Int Mic", tegra_rt5640_event_int_mic), | ||
434 | }; | ||
435 | |||
436 | static const struct snd_soc_dapm_route cardhu_audio_map[] = { | ||
437 | {"Headphone Jack", NULL, "HPOR"}, | ||
438 | {"Headphone Jack", NULL, "HPOL"}, | ||
439 | {"Int Spk", NULL, "SPORP"}, | ||
440 | {"Int Spk", NULL, "SPORN"}, | ||
441 | {"Int Spk", NULL, "SPOLP"}, | ||
442 | {"Int Spk", NULL, "SPOLN"}, | ||
443 | {"micbias1", NULL, "Mic Jack"}, | ||
444 | {"IN1P", NULL, "micbias1"}, | ||
445 | {"IN1N", NULL, "micbias1"}, | ||
446 | {"micbias1", NULL, "Int Mic"}, | ||
447 | {"IN2P", NULL, "micbias1"}, | ||
448 | }; | ||
449 | |||
450 | static const struct snd_kcontrol_new cardhu_controls[] = { | ||
451 | SOC_DAPM_PIN_SWITCH("Int Spk"), | ||
452 | SOC_DAPM_PIN_SWITCH("Headphone Jack"), | ||
453 | SOC_DAPM_PIN_SWITCH("Mic Jack"), | ||
454 | SOC_DAPM_PIN_SWITCH("Int Mic"), | ||
455 | }; | ||
456 | |||
457 | static int tegra_rt5640_init(struct snd_soc_pcm_runtime *rtd) | ||
458 | { | ||
459 | struct snd_soc_codec *codec = rtd->codec; | ||
460 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
461 | struct snd_soc_card *card = codec->card; | ||
462 | struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); | ||
463 | struct tegra_rt5640_platform_data *pdata = machine->pdata; | ||
464 | int ret; | ||
465 | |||
466 | if (gpio_is_valid(pdata->gpio_spkr_en)) { | ||
467 | ret = gpio_request(pdata->gpio_spkr_en, "spkr_en"); | ||
468 | if (ret) { | ||
469 | dev_err(card->dev, "cannot get spkr_en gpio\n"); | ||
470 | return ret; | ||
471 | } | ||
472 | machine->gpio_requested |= GPIO_SPKR_EN; | ||
473 | |||
474 | gpio_direction_output(pdata->gpio_spkr_en, 0); | ||
475 | } | ||
476 | |||
477 | if (gpio_is_valid(pdata->gpio_hp_mute)) { | ||
478 | ret = gpio_request(pdata->gpio_hp_mute, "hp_mute"); | ||
479 | if (ret) { | ||
480 | dev_err(card->dev, "cannot get hp_mute gpio\n"); | ||
481 | return ret; | ||
482 | } | ||
483 | machine->gpio_requested |= GPIO_HP_MUTE; | ||
484 | |||
485 | gpio_direction_output(pdata->gpio_hp_mute, 0); | ||
486 | } | ||
487 | |||
488 | if (gpio_is_valid(pdata->gpio_int_mic_en)) { | ||
489 | ret = gpio_request(pdata->gpio_int_mic_en, "int_mic_en"); | ||
490 | if (ret) { | ||
491 | dev_err(card->dev, "cannot get int_mic_en gpio\n"); | ||
492 | return ret; | ||
493 | } | ||
494 | machine->gpio_requested |= GPIO_INT_MIC_EN; | ||
495 | |||
496 | /* Disable int mic; enable signal is active-high */ | ||
497 | gpio_direction_output(pdata->gpio_int_mic_en, 0); | ||
498 | } | ||
499 | |||
500 | if (gpio_is_valid(pdata->gpio_ext_mic_en)) { | ||
501 | ret = gpio_request(pdata->gpio_ext_mic_en, "ext_mic_en"); | ||
502 | if (ret) { | ||
503 | dev_err(card->dev, "cannot get ext_mic_en gpio\n"); | ||
504 | return ret; | ||
505 | } | ||
506 | machine->gpio_requested |= GPIO_EXT_MIC_EN; | ||
507 | |||
508 | /* Enable ext mic; enable signal is active-low */ | ||
509 | gpio_direction_output(pdata->gpio_ext_mic_en, 0); | ||
510 | } | ||
511 | |||
512 | if (gpio_is_valid(pdata->gpio_hp_det)) { | ||
513 | tegra_rt5640_hp_jack_gpio.gpio = pdata->gpio_hp_det; | ||
514 | snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, | ||
515 | &tegra_rt5640_hp_jack); | ||
516 | #ifndef CONFIG_SWITCH | ||
517 | snd_soc_jack_add_pins(&tegra_rt5640_hp_jack, | ||
518 | ARRAY_SIZE(tegra_rt5640_hp_jack_pins), | ||
519 | tegra_rt5640_hp_jack_pins); | ||
520 | #else | ||
521 | snd_soc_jack_notifier_register(&tegra_rt5640_hp_jack, | ||
522 | &tegra_rt5640_jack_detect_nb); | ||
523 | #endif | ||
524 | snd_soc_jack_add_gpios(&tegra_rt5640_hp_jack, | ||
525 | 1, | ||
526 | &tegra_rt5640_hp_jack_gpio); | ||
527 | machine->gpio_requested |= GPIO_HP_DET; | ||
528 | } | ||
529 | |||
530 | ret = snd_soc_add_controls(codec, cardhu_controls, | ||
531 | ARRAY_SIZE(cardhu_controls)); | ||
532 | if (ret < 0) | ||
533 | return ret; | ||
534 | |||
535 | snd_soc_dapm_new_controls(dapm, cardhu_dapm_widgets, | ||
536 | ARRAY_SIZE(cardhu_dapm_widgets)); | ||
537 | |||
538 | snd_soc_dapm_add_routes(dapm, cardhu_audio_map, | ||
539 | ARRAY_SIZE(cardhu_audio_map)); | ||
540 | /* FIXME: Calculate automatically based on DAPM routes? */ | ||
541 | snd_soc_dapm_nc_pin(dapm, "LOUTL"); | ||
542 | snd_soc_dapm_nc_pin(dapm, "LOUTR"); | ||
543 | |||
544 | snd_soc_dapm_sync(dapm); | ||
545 | |||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | static struct snd_soc_dai_link tegra_rt5640_dai[] = { | ||
550 | { | ||
551 | .name = "RT5640", | ||
552 | .stream_name = "RT5640 PCM", | ||
553 | .codec_name = "rt5640.4-001c", | ||
554 | .platform_name = "tegra-pcm-audio", | ||
555 | .cpu_dai_name = "tegra30-i2s.1", | ||
556 | .codec_dai_name = "rt5640-aif1", | ||
557 | .init = tegra_rt5640_init, | ||
558 | .ops = &tegra_rt5640_ops, | ||
559 | }, | ||
560 | { | ||
561 | .name = "SPDIF", | ||
562 | .stream_name = "SPDIF PCM", | ||
563 | .codec_name = "spdif-dit.0", | ||
564 | .platform_name = "tegra-pcm-audio", | ||
565 | .cpu_dai_name = "tegra30-spdif", | ||
566 | .codec_dai_name = "dit-hifi", | ||
567 | .ops = &tegra_spdif_ops, | ||
568 | }, | ||
569 | { | ||
570 | .name = "BT-SCO", | ||
571 | .stream_name = "BT SCO PCM", | ||
572 | .codec_name = "spdif-dit.1", | ||
573 | .platform_name = "tegra-pcm-audio", | ||
574 | .cpu_dai_name = "tegra30-i2s.3", | ||
575 | .codec_dai_name = "dit-hifi", | ||
576 | .ops = &tegra_rt5640_bt_sco_ops, | ||
577 | }, | ||
578 | }; | ||
579 | |||
580 | static struct snd_soc_card snd_soc_tegra_rt5640 = { | ||
581 | .name = "tegra-rt5640", | ||
582 | .dai_link = tegra_rt5640_dai, | ||
583 | .num_links = ARRAY_SIZE(tegra_rt5640_dai), | ||
584 | }; | ||
585 | |||
586 | static __devinit int tegra_rt5640_driver_probe(struct platform_device *pdev) | ||
587 | { | ||
588 | struct snd_soc_card *card = &snd_soc_tegra_rt5640; | ||
589 | struct tegra_rt5640 *machine; | ||
590 | struct tegra_rt5640_platform_data *pdata; | ||
591 | int ret; | ||
592 | |||
593 | pdata = pdev->dev.platform_data; | ||
594 | if (!pdata) { | ||
595 | dev_err(&pdev->dev, "No platform data supplied\n"); | ||
596 | return -EINVAL; | ||
597 | } | ||
598 | |||
599 | if (pdata->codec_name) | ||
600 | card->dai_link->codec_name = pdata->codec_name; | ||
601 | if (pdata->codec_dai_name) | ||
602 | card->dai_link->codec_dai_name = pdata->codec_dai_name; | ||
603 | |||
604 | machine = kzalloc(sizeof(struct tegra_rt5640), GFP_KERNEL); | ||
605 | if (!machine) { | ||
606 | dev_err(&pdev->dev, "Can't allocate tegra_rt5640 struct\n"); | ||
607 | return -ENOMEM; | ||
608 | } | ||
609 | |||
610 | machine->pdata = pdata; | ||
611 | |||
612 | ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); | ||
613 | if (ret) | ||
614 | goto err_free_machine; | ||
615 | |||
616 | machine->cdc_en = regulator_get(NULL, "cdc_en"); | ||
617 | if (WARN_ON(IS_ERR(machine->cdc_en))) { | ||
618 | dev_err(&pdev->dev, "Couldn't get regulator cdc_en: %ld\n", | ||
619 | PTR_ERR(machine->cdc_en)); | ||
620 | machine->cdc_en = 0; | ||
621 | } else { | ||
622 | regulator_enable(machine->cdc_en); | ||
623 | } | ||
624 | |||
625 | machine->spk_reg = regulator_get(&pdev->dev, "vdd_spk_amp"); | ||
626 | if (IS_ERR(machine->spk_reg)) { | ||
627 | dev_info(&pdev->dev, "No speaker regulator found\n"); | ||
628 | machine->spk_reg = 0; | ||
629 | } | ||
630 | |||
631 | #ifdef CONFIG_SWITCH | ||
632 | /* Addd h2w swith class support */ | ||
633 | ret = switch_dev_register(&tegra_rt5640_headset_switch); | ||
634 | if (ret < 0) | ||
635 | goto err_fini_utils; | ||
636 | #endif | ||
637 | |||
638 | card->dev = &pdev->dev; | ||
639 | platform_set_drvdata(pdev, card); | ||
640 | snd_soc_card_set_drvdata(card, machine); | ||
641 | |||
642 | ret = snd_soc_register_card(card); | ||
643 | if (ret) { | ||
644 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", | ||
645 | ret); | ||
646 | goto err_unregister_switch; | ||
647 | } | ||
648 | |||
649 | if (!card->instantiated) { | ||
650 | ret = -ENODEV; | ||
651 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", | ||
652 | ret); | ||
653 | goto err_unregister_card; | ||
654 | } | ||
655 | |||
656 | return 0; | ||
657 | |||
658 | err_unregister_card: | ||
659 | snd_soc_unregister_card(card); | ||
660 | err_unregister_switch: | ||
661 | #ifdef CONFIG_SWITCH | ||
662 | switch_dev_unregister(&tegra_rt5640_headset_switch); | ||
663 | err_fini_utils: | ||
664 | #endif | ||
665 | tegra_asoc_utils_fini(&machine->util_data); | ||
666 | err_free_machine: | ||
667 | kfree(machine); | ||
668 | return ret; | ||
669 | } | ||
670 | |||
671 | static int __devexit tegra_rt5640_driver_remove(struct platform_device *pdev) | ||
672 | { | ||
673 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
674 | struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card); | ||
675 | struct tegra_rt5640_platform_data *pdata = machine->pdata; | ||
676 | |||
677 | if (machine->gpio_requested & GPIO_HP_DET) | ||
678 | snd_soc_jack_free_gpios(&tegra_rt5640_hp_jack, | ||
679 | 1, | ||
680 | &tegra_rt5640_hp_jack_gpio); | ||
681 | if (machine->gpio_requested & GPIO_EXT_MIC_EN) | ||
682 | gpio_free(pdata->gpio_ext_mic_en); | ||
683 | if (machine->gpio_requested & GPIO_INT_MIC_EN) | ||
684 | gpio_free(pdata->gpio_int_mic_en); | ||
685 | if (machine->gpio_requested & GPIO_HP_MUTE) | ||
686 | gpio_free(pdata->gpio_hp_mute); | ||
687 | if (machine->gpio_requested & GPIO_SPKR_EN) | ||
688 | gpio_free(pdata->gpio_spkr_en); | ||
689 | machine->gpio_requested = 0; | ||
690 | |||
691 | if (machine->spk_reg) | ||
692 | regulator_put(machine->spk_reg); | ||
693 | if (machine->dmic_reg) | ||
694 | regulator_put(machine->dmic_reg); | ||
695 | |||
696 | if (machine->cdc_en) { | ||
697 | regulator_disable(machine->cdc_en); | ||
698 | regulator_put(machine->cdc_en); | ||
699 | } | ||
700 | |||
701 | snd_soc_unregister_card(card); | ||
702 | |||
703 | tegra_asoc_utils_fini(&machine->util_data); | ||
704 | |||
705 | #ifdef CONFIG_SWITCH | ||
706 | switch_dev_unregister(&tegra_rt5640_headset_switch); | ||
707 | #endif | ||
708 | kfree(machine); | ||
709 | |||
710 | return 0; | ||
711 | } | ||
712 | |||
713 | static struct platform_driver tegra_rt5640_driver = { | ||
714 | .driver = { | ||
715 | .name = DRV_NAME, | ||
716 | .owner = THIS_MODULE, | ||
717 | .pm = &snd_soc_pm_ops, | ||
718 | }, | ||
719 | .probe = tegra_rt5640_driver_probe, | ||
720 | .remove = __devexit_p(tegra_rt5640_driver_remove), | ||
721 | }; | ||
722 | |||
723 | static int __init tegra_rt5640_modinit(void) | ||
724 | { | ||
725 | return platform_driver_register(&tegra_rt5640_driver); | ||
726 | } | ||
727 | module_init(tegra_rt5640_modinit); | ||
728 | |||
729 | static void __exit tegra_rt5640_modexit(void) | ||
730 | { | ||
731 | platform_driver_unregister(&tegra_rt5640_driver); | ||
732 | } | ||
733 | module_exit(tegra_rt5640_modexit); | ||
734 | |||
735 | MODULE_AUTHOR("Johnny Qiu <joqiu@nvidia.com>"); | ||
736 | MODULE_DESCRIPTION("Tegra+RT5640 machine ASoC driver"); | ||
737 | MODULE_LICENSE("GPL"); | ||
738 | MODULE_ALIAS("platform:" DRV_NAME); | ||