diff options
Diffstat (limited to 'sound/soc/tegra')
30 files changed, 12986 insertions, 1178 deletions
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig index 035d39a4beb..2a8b4f1cef6 100644 --- a/sound/soc/tegra/Kconfig +++ b/sound/soc/tegra/Kconfig | |||
@@ -4,14 +4,55 @@ config SND_SOC_TEGRA | |||
4 | help | 4 | help |
5 | Say Y or M here if you want support for SoC audio on Tegra. | 5 | Say Y or M here if you want support for SoC audio on Tegra. |
6 | 6 | ||
7 | config SND_SOC_TEGRA_I2S | 7 | config SND_SOC_TEGRA20_DAS |
8 | tristate | 8 | tristate "Tegra 20 Digital Audio Switch driver" |
9 | depends on SND_SOC_TEGRA | 9 | depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC |
10 | |||
11 | config SND_SOC_TEGRA20_I2S | ||
12 | tristate "Tegra 20 I2S driver" | ||
13 | depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC | ||
14 | select SND_SOC_TEGRA20_DAS | ||
15 | help | ||
16 | Say Y or M if you want to add support for codecs attached to the | ||
17 | Tegra I2S interface. You will also need to select the individual | ||
18 | machine drivers to support below. | ||
19 | |||
20 | config SND_SOC_TEGRA30_AHUB | ||
21 | tristate "Tegra 30 Audio Hub driver" | ||
22 | depends on SND_SOC_TEGRA && ARCH_TEGRA_3x_SOC | ||
23 | |||
24 | config SND_SOC_TEGRA30_DAM | ||
25 | tristate "Tegra 30 Audio Dam driver" | ||
26 | depends on SND_SOC_TEGRA && ARCH_TEGRA_3x_SOC | ||
27 | select SND_SOC_TEGRA30_AHUB | ||
28 | |||
29 | config SND_SOC_TEGRA30_I2S | ||
30 | tristate "Tegra 30 I2S driver" | ||
31 | depends on SND_SOC_TEGRA && ARCH_TEGRA_3x_SOC | ||
32 | select SND_SOC_TEGRA30_AHUB | ||
10 | help | 33 | help |
11 | Say Y or M if you want to add support for codecs attached to the | 34 | Say Y or M if you want to add support for codecs attached to the |
12 | Tegra I2S interface. You will also need to select the individual | 35 | Tegra I2S interface. You will also need to select the individual |
13 | machine drivers to support below. | 36 | machine drivers to support below. |
14 | 37 | ||
38 | config SND_SOC_TEGRA20_SPDIF | ||
39 | tristate | ||
40 | depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC && TEGRA_DC | ||
41 | default m | ||
42 | help | ||
43 | Say Y or M if you want to add support for the TEGRA20 SPDIF interface. | ||
44 | You will also need to select the individual machine drivers to support | ||
45 | below. | ||
46 | |||
47 | config SND_SOC_TEGRA30_SPDIF | ||
48 | tristate | ||
49 | depends on SND_SOC_TEGRA && ARCH_TEGRA_3x_SOC && TEGRA_DC | ||
50 | select SND_SOC_TEGRA30_AHUB | ||
51 | help | ||
52 | Say Y or M if you want to add support for the TEGRA30 SPDIF interface. | ||
53 | You will also need to select the individual machine drivers to support | ||
54 | below. | ||
55 | |||
15 | config MACH_HAS_SND_SOC_TEGRA_WM8903 | 56 | config MACH_HAS_SND_SOC_TEGRA_WM8903 |
16 | bool | 57 | bool |
17 | help | 58 | help |
@@ -21,10 +62,15 @@ config MACH_HAS_SND_SOC_TEGRA_WM8903 | |||
21 | 62 | ||
22 | config SND_SOC_TEGRA_WM8903 | 63 | config SND_SOC_TEGRA_WM8903 |
23 | tristate "SoC Audio support for Tegra boards using a WM8903 codec" | 64 | tristate "SoC Audio support for Tegra boards using a WM8903 codec" |
24 | depends on SND_SOC_TEGRA && I2C | 65 | depends on SND_SOC_TEGRA && I2C && TEGRA_DC |
25 | depends on MACH_HAS_SND_SOC_TEGRA_WM8903 | 66 | depends on MACH_HAS_SND_SOC_TEGRA_WM8903 |
26 | select SND_SOC_TEGRA_I2S | 67 | select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC |
68 | select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC | ||
69 | select SND_SOC_TEGRA20_SPDIF if ARCH_TEGRA_2x_SOC | ||
70 | select SND_SOC_TEGRA30_SPDIF if ARCH_TEGRA_3x_SOC | ||
27 | select SND_SOC_WM8903 | 71 | select SND_SOC_WM8903 |
72 | select SND_SOC_SPDIF | ||
73 | select SND_SOC_TEGRA30_DAM if ARCH_TEGRA_3x_SOC | ||
28 | help | 74 | help |
29 | Say Y or M here if you want to add support for SoC audio on Tegra | 75 | Say Y or M here if you want to add support for SoC audio on Tegra |
30 | boards using the WM8093 codec. Currently, the supported boards are | 76 | boards using the WM8093 codec. Currently, the supported boards are |
@@ -38,3 +84,147 @@ config SND_SOC_TEGRA_TRIMSLICE | |||
38 | help | 84 | help |
39 | Say Y or M here if you want to add support for SoC audio on the | 85 | Say Y or M here if you want to add support for SoC audio on the |
40 | TrimSlice platform. | 86 | TrimSlice platform. |
87 | |||
88 | config SND_SOC_TEGRA_P1852 | ||
89 | tristate "SoC Audio support for P1852 SKUs" | ||
90 | depends on SND_SOC_TEGRA | ||
91 | depends on MACH_P1852 | ||
92 | select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC | ||
93 | select SND_SOC_TEGRA30_SPDIF if ARCH_TEGRA_3x_SOC | ||
94 | select SND_SOC_SPDIF | ||
95 | select SND_SOC_TEGRA30_DAM if ARCH_TEGRA_3x_SOC | ||
96 | help | ||
97 | Say Y or M here if you want to add support for SoC audio on the | ||
98 | TEGRA P1852 SKUs. These are plug-n-play boards and and the codecs | ||
99 | used by the system integrator needs to be provided while instantiating | ||
100 | the driver. | ||
101 | |||
102 | config MACH_HAS_SND_SOC_TEGRA_WM8753 | ||
103 | bool | ||
104 | help | ||
105 | Machines that use the SND_SOC_TEGRA_WM8753 driver should select | ||
106 | this config option, in order to allow the user to enable | ||
107 | SND_SOC_TEGRA_WM8753. | ||
108 | |||
109 | config SND_SOC_TEGRA_WM8753 | ||
110 | tristate "SoC Audio support for Tegra boards using a WM8753 codec" | ||
111 | depends on SND_SOC_TEGRA && I2C && TEGRA_DC | ||
112 | depends on MACH_HAS_SND_SOC_TEGRA_WM8753 | ||
113 | select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC | ||
114 | select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC | ||
115 | select SND_SOC_TEGRA20_SPDIF if ARCH_TEGRA_2x_SOC | ||
116 | select SND_SOC_TEGRA30_SPDIF if ARCH_TEGRA_3x_SOC | ||
117 | select SND_SOC_WM8753 | ||
118 | select SND_SOC_SPDIF | ||
119 | help | ||
120 | Say Y or M here if you want to add support for SoC audio on Tegra | ||
121 | boards using the WM8753 codec. Currently, only supported board is | ||
122 | Whistler. | ||
123 | |||
124 | config MACH_HAS_SND_SOC_TEGRA_MAX98088 | ||
125 | bool | ||
126 | help | ||
127 | Machines that use the SND_SOC_TEGRA_MAX98088 driver should select | ||
128 | this config option, in order to allow the user to enable | ||
129 | SND_SOC_TEGRA_MAX98088. | ||
130 | |||
131 | config SND_SOC_TEGRA_MAX98088 | ||
132 | tristate "SoC Audio support for Tegra boards using a MAX98088 codec" | ||
133 | depends on SND_SOC_TEGRA && I2C && TEGRA_DC | ||
134 | depends on MACH_HAS_SND_SOC_TEGRA_MAX98088 | ||
135 | select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC | ||
136 | select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC | ||
137 | select SND_SOC_TEGRA30_SPDIF if ARCH_TEGRA_3x_SOC | ||
138 | select SND_SOC_MAX98088 | ||
139 | select SND_SOC_SPDIF | ||
140 | select SND_SOC_TEGRA30_DAM if ARCH_TEGRA_3x_SOC | ||
141 | help | ||
142 | Say Y or M here if you want to add support for SoC audio on Tegra | ||
143 | boards using the MAX98088 codec. Currently, only supported board is | ||
144 | Enterprise. | ||
145 | |||
146 | config MACH_HAS_SND_SOC_TEGRA_TLV320AIC326X | ||
147 | bool | ||
148 | help | ||
149 | Machines that use the SND_SOC_TEGRA_TLV320AIC326X driver should select | ||
150 | this config option, in order to allow the user to enable | ||
151 | SND_SOC_TEGRA_TLV320AIC326X. | ||
152 | |||
153 | config SND_SOC_TEGRA_TLV320AIC326X | ||
154 | tristate "SoC Audio support for Tegra boards using a TI AIC326x codec" | ||
155 | depends on SND_SOC_TEGRA && I2C && TEGRA_DC | ||
156 | depends on MACH_HAS_SND_SOC_TEGRA_TLV320AIC326X | ||
157 | select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC | ||
158 | select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC | ||
159 | select SND_SOC_TEGRA30_SPDIF if ARCH_TEGRA_3x_SOC | ||
160 | select SND_SOC_TLV320AIC326X | ||
161 | select SND_SOC_SPDIF | ||
162 | select SND_SOC_TEGRA30_DAM if ARCH_TEGRA_3x_SOC | ||
163 | help | ||
164 | Say Y or M here if you want to add support for SoC audio on Tegra | ||
165 | boards using the TI AIC326X codec. | ||
166 | |||
167 | config MACH_HAS_SND_SOC_TEGRA_RT5639 | ||
168 | bool | ||
169 | help | ||
170 | Machines that use the SND_SOC_TEGRA_RT5639 driver should select | ||
171 | this config option, in order to allow the user to enable | ||
172 | SND_SOC_TEGRA_RT5639. | ||
173 | |||
174 | config SND_SOC_TEGRA_RT5639 | ||
175 | tristate "SoC Audio support for Tegra boards using a ALC5639 codec" | ||
176 | depends on SND_SOC_TEGRA && I2C && TEGRA_DC | ||
177 | depends on MACH_HAS_SND_SOC_TEGRA_RT5639 | ||
178 | depends on SND_SOC_TEGRA_RT5640 | ||
179 | select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC | ||
180 | select SND_SOC_TEGRA30_SPDIF if ARCH_TEGRA_3x_SOC | ||
181 | select SND_SOC_RT5639 | ||
182 | select SND_SOC_SPDIF | ||
183 | select SND_SOC_TEGRA30_DAM if ARCH_TEGRA_3x_SOC | ||
184 | help | ||
185 | Say Y or M here if you want to add support for SoC audio on Tegra | ||
186 | boards using the ALC5639 codec. Currently, the supported board | ||
187 | is Kai. | ||
188 | |||
189 | config MACH_HAS_SND_SOC_TEGRA_RT5640 | ||
190 | bool | ||
191 | help | ||
192 | Machines that use the SND_SOC_TEGRA_RT5640 driver should select | ||
193 | this config option, in order to allow the user to enable | ||
194 | SND_SOC_TEGRA_RT5640. | ||
195 | |||
196 | config SND_SOC_TEGRA_RT5640 | ||
197 | tristate "SoC Audio support for Tegra boards using a ALC5640 codec" | ||
198 | depends on SND_SOC_TEGRA && I2C && TEGRA_DC | ||
199 | depends on MACH_HAS_SND_SOC_TEGRA_RT5640 | ||
200 | select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC | ||
201 | select SND_SOC_TEGRA30_SPDIF if ARCH_TEGRA_3x_SOC | ||
202 | select SND_SOC_RT5640 | ||
203 | select SND_SOC_SPDIF | ||
204 | select SND_SOC_TEGRA30_DAM if ARCH_TEGRA_3x_SOC | ||
205 | help | ||
206 | Say Y or M here if you want to add support for SoC audio on Tegra | ||
207 | boards using the ALC5640 codec. Currently, the supported boards | ||
208 | are Kai and Cardhu. | ||
209 | |||
210 | config MACH_HAS_SND_SOC_TEGRA_MAX98095 | ||
211 | bool | ||
212 | help | ||
213 | Machines that use the SND_SOC_TEGRA_MAX98095 driver should select | ||
214 | this config option, in order to allow the user to enable | ||
215 | SND_SOC_TEGRA_MAX98095. | ||
216 | |||
217 | config SND_SOC_TEGRA_MAX98095 | ||
218 | tristate "SoC Audio support for Tegra boards using a MAX98095 codec" | ||
219 | depends on SND_SOC_TEGRA && I2C && TEGRA_DC | ||
220 | depends on MACH_HAS_SND_SOC_TEGRA_MAX98095 | ||
221 | select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC | ||
222 | select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC | ||
223 | select SND_SOC_TEGRA30_SPDIF if ARCH_TEGRA_3x_SOC | ||
224 | select SND_SOC_MAX98095 | ||
225 | select SND_SOC_SPDIF | ||
226 | select SND_SOC_TEGRA30_DAM if ARCH_TEGRA_3x_SOC | ||
227 | help | ||
228 | Say Y or M here if you want to add support for SoC audio on Tegra | ||
229 | boards using the MAX98095 codec. Currently, only supported board is | ||
230 | Cardhu. | ||
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile index fa6574d92a3..d546046d1e1 100644 --- a/sound/soc/tegra/Makefile +++ b/sound/soc/tegra/Makefile | |||
@@ -1,17 +1,41 @@ | |||
1 | GCOV_PROFILE := y | ||
2 | |||
1 | # Tegra platform Support | 3 | # Tegra platform Support |
2 | snd-soc-tegra-das-objs := tegra_das.o | ||
3 | snd-soc-tegra-pcm-objs := tegra_pcm.o | 4 | snd-soc-tegra-pcm-objs := tegra_pcm.o |
4 | snd-soc-tegra-i2s-objs := tegra_i2s.o | 5 | snd-soc-tegra20-spdif-objs := tegra20_spdif.o |
5 | snd-soc-tegra-utils-objs += tegra_asoc_utils.o | 6 | snd-soc-tegra-utils-objs += tegra_asoc_utils.o |
7 | snd-soc-tegra20-das-objs := tegra20_das.o | ||
8 | snd-soc-tegra20-i2s-objs := tegra20_i2s.o | ||
9 | snd-soc-tegra30-ahub-objs := tegra30_ahub.o | ||
10 | snd-soc-tegra30-i2s-objs := tegra30_i2s.o | ||
11 | snd-soc-tegra30-spdif-objs := tegra30_spdif.o | ||
12 | snd-soc-tegra30-dam-objs := tegra30_dam.o | ||
6 | 13 | ||
7 | obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o | ||
8 | obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-das.o | ||
9 | obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o | 14 | obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o |
10 | obj-$(CONFIG_SND_SOC_TEGRA_I2S) += snd-soc-tegra-i2s.o | 15 | obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o |
16 | obj-$(CONFIG_SND_SOC_TEGRA20_DAS) += snd-soc-tegra20-das.o | ||
17 | obj-$(CONFIG_SND_SOC_TEGRA20_I2S) += snd-soc-tegra20-i2s.o | ||
18 | obj-$(CONFIG_SND_SOC_TEGRA30_AHUB) += snd-soc-tegra30-ahub.o | ||
19 | obj-$(CONFIG_SND_SOC_TEGRA30_DAM) += snd-soc-tegra30-dam.o | ||
20 | obj-$(CONFIG_SND_SOC_TEGRA30_I2S) += snd-soc-tegra30-i2s.o | ||
21 | obj-$(CONFIG_SND_SOC_TEGRA20_SPDIF) += snd-soc-tegra20-spdif.o | ||
22 | obj-$(CONFIG_SND_SOC_TEGRA30_SPDIF) += snd-soc-tegra30-spdif.o | ||
11 | 23 | ||
12 | # Tegra machine Support | 24 | # Tegra machine Support |
13 | snd-soc-tegra-wm8903-objs := tegra_wm8903.o | 25 | snd-soc-tegra-wm8903-objs := tegra_wm8903.o |
14 | snd-soc-tegra-trimslice-objs := trimslice.o | 26 | snd-soc-tegra-trimslice-objs := trimslice.o |
27 | snd-soc-tegra-wm8753-objs := tegra_wm8753.o | ||
28 | snd-soc-tegra-max98088-objs := tegra_max98088.o | ||
29 | snd-soc-tegra-aic326x-objs := tegra_aic326x.o | ||
30 | snd-soc-tegra-rt5640-objs := tegra_rt5640.o | ||
31 | snd-soc-tegra-max98095-objs := tegra_max98095.o | ||
32 | snd-soc-tegra-p1852-objs := tegra_p1852.o | ||
15 | 33 | ||
16 | obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o | 34 | obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o |
17 | obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o | 35 | obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o |
36 | obj-$(CONFIG_SND_SOC_TEGRA_WM8753) += snd-soc-tegra-wm8753.o | ||
37 | obj-$(CONFIG_SND_SOC_TEGRA_MAX98088) += snd-soc-tegra-max98088.o | ||
38 | obj-$(CONFIG_SND_SOC_TEGRA_TLV320AIC326X) += snd-soc-tegra-aic326x.o | ||
39 | obj-$(CONFIG_SND_SOC_TEGRA_RT5640) += snd-soc-tegra-rt5640.o | ||
40 | obj-$(CONFIG_SND_SOC_TEGRA_MAX98095) += snd-soc-tegra-max98095.o | ||
41 | obj-$(CONFIG_SND_SOC_TEGRA_P1852) += snd-soc-tegra-p1852.o | ||
diff --git a/sound/soc/tegra/tegra20_das.c b/sound/soc/tegra/tegra20_das.c new file mode 100644 index 00000000000..0774d360399 --- /dev/null +++ b/sound/soc/tegra/tegra20_das.c | |||
@@ -0,0 +1,333 @@ | |||
1 | /* | ||
2 | * tegra20_das.c - Tegra20 DAS driver | ||
3 | * | ||
4 | * Author: Stephen Warren <swarren@nvidia.com> | ||
5 | * Copyright (C) 2010 - 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/module.h> | ||
24 | #include <linux/debugfs.h> | ||
25 | #include <linux/device.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/seq_file.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/io.h> | ||
30 | #include <mach/iomap.h> | ||
31 | #include <mach/pinmux.h> | ||
32 | #include <sound/soc.h> | ||
33 | #include "tegra20_das.h" | ||
34 | |||
35 | #define DRV_NAME "tegra20-das" | ||
36 | |||
37 | static struct tegra20_das *das; | ||
38 | |||
39 | static inline void tegra20_das_write(u32 reg, u32 val) | ||
40 | { | ||
41 | #ifdef CONFIG_PM | ||
42 | das->reg_cache[reg >> 2] = val; | ||
43 | #endif | ||
44 | __raw_writel(val, das->regs + reg); | ||
45 | } | ||
46 | |||
47 | static inline u32 tegra20_das_read(u32 reg) | ||
48 | { | ||
49 | return __raw_readl(das->regs + reg); | ||
50 | } | ||
51 | |||
52 | #ifdef CONFIG_PM | ||
53 | int tegra20_das_resume() | ||
54 | { | ||
55 | int i, reg; | ||
56 | |||
57 | for (i = 0; i <= TEGRA20_DAS_DAP_ID_5; i++) | ||
58 | tegra20_das_write(i << 2, das->reg_cache[i]); | ||
59 | |||
60 | for (i = 0; i <= TEGRA20_DAS_DAC_ID_3; i++) { | ||
61 | reg = TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL + | ||
62 | (i * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE); | ||
63 | tegra20_das_write(reg, das->reg_cache[reg >> 2]); | ||
64 | } | ||
65 | |||
66 | return 0; | ||
67 | } | ||
68 | #endif | ||
69 | |||
70 | int tegra20_das_set_tristate(int dap_id, int is_tristate) | ||
71 | { | ||
72 | enum tegra_pingroup pin; | ||
73 | enum tegra_tristate tristate; | ||
74 | |||
75 | switch (dap_id) { | ||
76 | case TEGRA20_DAS_DAP_ID_1: | ||
77 | pin = TEGRA_PINGROUP_DAP1; | ||
78 | break; | ||
79 | case TEGRA20_DAS_DAP_ID_2: | ||
80 | pin = TEGRA_PINGROUP_DAP2; | ||
81 | break; | ||
82 | case TEGRA20_DAS_DAP_ID_3: | ||
83 | pin = TEGRA_PINGROUP_DAP3; | ||
84 | break; | ||
85 | case TEGRA20_DAS_DAP_ID_4: | ||
86 | pin = TEGRA_PINGROUP_DAP4; | ||
87 | break; | ||
88 | default: | ||
89 | return -EINVAL; | ||
90 | } | ||
91 | |||
92 | if (is_tristate) | ||
93 | tristate = TEGRA_TRI_TRISTATE; | ||
94 | else | ||
95 | tristate = TEGRA_TRI_NORMAL; | ||
96 | |||
97 | tegra_pinmux_set_tristate(pin, tristate); | ||
98 | } | ||
99 | EXPORT_SYMBOL_GPL(tegra20_das_set_tristate); | ||
100 | |||
101 | int tegra20_das_connect_dap_to_dac(int dap, int dac) | ||
102 | { | ||
103 | u32 addr; | ||
104 | u32 reg; | ||
105 | |||
106 | if (!das) | ||
107 | return -ENODEV; | ||
108 | |||
109 | addr = TEGRA20_DAS_DAP_CTRL_SEL + | ||
110 | (dap * TEGRA20_DAS_DAP_CTRL_SEL_STRIDE); | ||
111 | reg = dac << TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P; | ||
112 | |||
113 | tegra20_das_write(addr, reg); | ||
114 | |||
115 | return 0; | ||
116 | } | ||
117 | EXPORT_SYMBOL_GPL(tegra20_das_connect_dap_to_dac); | ||
118 | |||
119 | int tegra20_das_connect_dap_to_dap(int dap, int otherdap, int master, | ||
120 | int sdata1rx, int sdata2rx) | ||
121 | { | ||
122 | u32 addr; | ||
123 | u32 reg; | ||
124 | |||
125 | if (!das) | ||
126 | return -ENODEV; | ||
127 | |||
128 | addr = TEGRA20_DAS_DAP_CTRL_SEL + | ||
129 | (dap * TEGRA20_DAS_DAP_CTRL_SEL_STRIDE); | ||
130 | reg = otherdap << TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P | | ||
131 | !!sdata2rx << TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P | | ||
132 | !!sdata1rx << TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P | | ||
133 | !!master << TEGRA20_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P; | ||
134 | |||
135 | tegra20_das_write(addr, reg); | ||
136 | |||
137 | return 0; | ||
138 | } | ||
139 | EXPORT_SYMBOL_GPL(tegra20_das_connect_dap_to_dap); | ||
140 | |||
141 | int tegra20_das_connect_dac_to_dap(int dac, int dap) | ||
142 | { | ||
143 | u32 addr; | ||
144 | u32 reg; | ||
145 | |||
146 | if (!das) | ||
147 | return -ENODEV; | ||
148 | |||
149 | addr = TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL + | ||
150 | (dac * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE); | ||
151 | reg = dap << TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P | | ||
152 | dap << TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P | | ||
153 | dap << TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P; | ||
154 | |||
155 | tegra20_das_write(addr, reg); | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | EXPORT_SYMBOL_GPL(tegra20_das_connect_dac_to_dap); | ||
160 | |||
161 | #ifdef CONFIG_DEBUG_FS | ||
162 | static int tegra20_das_show(struct seq_file *s, void *unused) | ||
163 | { | ||
164 | int i; | ||
165 | u32 addr; | ||
166 | u32 reg; | ||
167 | |||
168 | for (i = 0; i < TEGRA20_DAS_DAP_CTRL_SEL_COUNT; i++) { | ||
169 | addr = TEGRA20_DAS_DAP_CTRL_SEL + | ||
170 | (i * TEGRA20_DAS_DAP_CTRL_SEL_STRIDE); | ||
171 | reg = tegra20_das_read(addr); | ||
172 | seq_printf(s, "TEGRA20_DAS_DAP_CTRL_SEL[%d] = %08x\n", i, reg); | ||
173 | } | ||
174 | |||
175 | for (i = 0; i < TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_COUNT; i++) { | ||
176 | addr = TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL + | ||
177 | (i * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE); | ||
178 | reg = tegra20_das_read(addr); | ||
179 | seq_printf(s, "TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL[%d] = %08x\n", | ||
180 | i, reg); | ||
181 | } | ||
182 | |||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | static int tegra20_das_debug_open(struct inode *inode, struct file *file) | ||
187 | { | ||
188 | return single_open(file, tegra20_das_show, inode->i_private); | ||
189 | } | ||
190 | |||
191 | static const struct file_operations tegra20_das_debug_fops = { | ||
192 | .open = tegra20_das_debug_open, | ||
193 | .read = seq_read, | ||
194 | .llseek = seq_lseek, | ||
195 | .release = single_release, | ||
196 | }; | ||
197 | |||
198 | static void tegra20_das_debug_add(struct tegra20_das *das) | ||
199 | { | ||
200 | das->debug = debugfs_create_file(DRV_NAME, S_IRUGO, | ||
201 | snd_soc_debugfs_root, das, | ||
202 | &tegra20_das_debug_fops); | ||
203 | } | ||
204 | |||
205 | static void tegra20_das_debug_remove(struct tegra20_das *das) | ||
206 | { | ||
207 | if (das->debug) | ||
208 | debugfs_remove(das->debug); | ||
209 | } | ||
210 | #else | ||
211 | static inline void tegra20_das_debug_add(struct tegra20_das *das) | ||
212 | { | ||
213 | } | ||
214 | |||
215 | static inline void tegra20_das_debug_remove(struct tegra20_das *das) | ||
216 | { | ||
217 | } | ||
218 | #endif | ||
219 | |||
220 | static int __devinit tegra20_das_probe(struct platform_device *pdev) | ||
221 | { | ||
222 | struct resource *res, *region; | ||
223 | int ret = 0; | ||
224 | #ifdef CONFIG_PM | ||
225 | int i, reg; | ||
226 | #endif | ||
227 | |||
228 | if (das) | ||
229 | return -ENODEV; | ||
230 | |||
231 | das = kzalloc(sizeof(struct tegra20_das), GFP_KERNEL); | ||
232 | if (!das) { | ||
233 | dev_err(&pdev->dev, "Can't allocate tegra20_das\n"); | ||
234 | ret = -ENOMEM; | ||
235 | goto exit; | ||
236 | } | ||
237 | das->dev = &pdev->dev; | ||
238 | |||
239 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
240 | if (!res) { | ||
241 | dev_err(&pdev->dev, "No memory resource\n"); | ||
242 | ret = -ENODEV; | ||
243 | goto err_free; | ||
244 | } | ||
245 | |||
246 | region = request_mem_region(res->start, resource_size(res), | ||
247 | pdev->name); | ||
248 | if (!region) { | ||
249 | dev_err(&pdev->dev, "Memory region already claimed\n"); | ||
250 | ret = -EBUSY; | ||
251 | goto err_free; | ||
252 | } | ||
253 | |||
254 | das->regs = ioremap(res->start, resource_size(res)); | ||
255 | if (!das->regs) { | ||
256 | dev_err(&pdev->dev, "ioremap failed\n"); | ||
257 | ret = -ENOMEM; | ||
258 | goto err_release; | ||
259 | } | ||
260 | |||
261 | #ifdef CONFIG_PM | ||
262 | /* populate the das reg cache with POR values*/ | ||
263 | for (i = 0; i <= TEGRA20_DAS_DAP_ID_5; i++) | ||
264 | das->reg_cache[i] = tegra20_das_read(i << 2); | ||
265 | |||
266 | for (i = 0; i <= TEGRA20_DAS_DAC_ID_3; i++) { | ||
267 | reg = TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL + | ||
268 | (i * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE); | ||
269 | das->reg_cache[reg >> 2] = tegra20_das_read(reg); | ||
270 | } | ||
271 | #endif | ||
272 | |||
273 | tegra20_das_debug_add(das); | ||
274 | |||
275 | platform_set_drvdata(pdev, das); | ||
276 | |||
277 | return 0; | ||
278 | |||
279 | err_release: | ||
280 | release_mem_region(res->start, resource_size(res)); | ||
281 | err_free: | ||
282 | kfree(das); | ||
283 | das = 0; | ||
284 | exit: | ||
285 | return ret; | ||
286 | } | ||
287 | |||
288 | static int __devexit tegra20_das_remove(struct platform_device *pdev) | ||
289 | { | ||
290 | struct resource *res; | ||
291 | |||
292 | if (!das) | ||
293 | return -ENODEV; | ||
294 | |||
295 | platform_set_drvdata(pdev, NULL); | ||
296 | |||
297 | tegra20_das_debug_remove(das); | ||
298 | |||
299 | iounmap(das->regs); | ||
300 | |||
301 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
302 | release_mem_region(res->start, resource_size(res)); | ||
303 | |||
304 | kfree(das); | ||
305 | das = 0; | ||
306 | |||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | static struct platform_driver tegra20_das_driver = { | ||
311 | .probe = tegra20_das_probe, | ||
312 | .remove = __devexit_p(tegra20_das_remove), | ||
313 | .driver = { | ||
314 | .name = DRV_NAME, | ||
315 | }, | ||
316 | }; | ||
317 | |||
318 | static int __init tegra20_das_modinit(void) | ||
319 | { | ||
320 | return platform_driver_register(&tegra20_das_driver); | ||
321 | } | ||
322 | module_init(tegra20_das_modinit); | ||
323 | |||
324 | static void __exit tegra20_das_modexit(void) | ||
325 | { | ||
326 | platform_driver_unregister(&tegra20_das_driver); | ||
327 | } | ||
328 | module_exit(tegra20_das_modexit); | ||
329 | |||
330 | MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); | ||
331 | MODULE_DESCRIPTION("Tegra DAS driver"); | ||
332 | MODULE_LICENSE("GPL"); | ||
333 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/sound/soc/tegra/tegra20_das.h b/sound/soc/tegra/tegra20_das.h new file mode 100644 index 00000000000..0d58c7d1bc3 --- /dev/null +++ b/sound/soc/tegra/tegra20_das.h | |||
@@ -0,0 +1,148 @@ | |||
1 | /* | ||
2 | * tegra20_das.h - Definitions for Tegra20 DAS driver | ||
3 | * | ||
4 | * Author: Stephen Warren <swarren@nvidia.com> | ||
5 | * Copyright (C) 2010 - 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 __TEGRA20_DAS_H__ | ||
24 | #define __TEGRA20_DAS_H__ | ||
25 | |||
26 | /* Register TEGRA20_DAS_DAP_CTRL_SEL */ | ||
27 | #define TEGRA20_DAS_DAP_CTRL_SEL 0x00 | ||
28 | #define TEGRA20_DAS_DAP_CTRL_SEL_COUNT 5 | ||
29 | #define TEGRA20_DAS_DAP_CTRL_SEL_STRIDE 4 | ||
30 | #define TEGRA20_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P 31 | ||
31 | #define TEGRA20_DAS_DAP_CTRL_SEL_DAP_MS_SEL_S 1 | ||
32 | #define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P 30 | ||
33 | #define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_S 1 | ||
34 | #define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P 29 | ||
35 | #define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_S 1 | ||
36 | #define TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P 0 | ||
37 | #define TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_S 5 | ||
38 | |||
39 | /* Values for field TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL */ | ||
40 | #define TEGRA20_DAS_DAP_SEL_DAC1 0 | ||
41 | #define TEGRA20_DAS_DAP_SEL_DAC2 1 | ||
42 | #define TEGRA20_DAS_DAP_SEL_DAC3 2 | ||
43 | #define TEGRA20_DAS_DAP_SEL_DAP1 16 | ||
44 | #define TEGRA20_DAS_DAP_SEL_DAP2 17 | ||
45 | #define TEGRA20_DAS_DAP_SEL_DAP3 18 | ||
46 | #define TEGRA20_DAS_DAP_SEL_DAP4 19 | ||
47 | #define TEGRA20_DAS_DAP_SEL_DAP5 20 | ||
48 | |||
49 | /* Register TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL */ | ||
50 | #define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL 0x40 | ||
51 | #define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_COUNT 3 | ||
52 | #define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE 4 | ||
53 | #define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P 28 | ||
54 | #define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_S 4 | ||
55 | #define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P 24 | ||
56 | #define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_S 4 | ||
57 | #define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P 0 | ||
58 | #define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_S 4 | ||
59 | |||
60 | /* | ||
61 | * Values for: | ||
62 | * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL | ||
63 | * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL | ||
64 | * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL | ||
65 | */ | ||
66 | #define TEGRA20_DAS_DAC_SEL_DAP1 0 | ||
67 | #define TEGRA20_DAS_DAC_SEL_DAP2 1 | ||
68 | #define TEGRA20_DAS_DAC_SEL_DAP3 2 | ||
69 | #define TEGRA20_DAS_DAC_SEL_DAP4 3 | ||
70 | #define TEGRA20_DAS_DAC_SEL_DAP5 4 | ||
71 | |||
72 | /* | ||
73 | * Names/IDs of the DACs/DAPs. | ||
74 | */ | ||
75 | |||
76 | #define TEGRA20_DAS_DAP_ID_1 0 | ||
77 | #define TEGRA20_DAS_DAP_ID_2 1 | ||
78 | #define TEGRA20_DAS_DAP_ID_3 2 | ||
79 | #define TEGRA20_DAS_DAP_ID_4 3 | ||
80 | #define TEGRA20_DAS_DAP_ID_5 4 | ||
81 | |||
82 | #define TEGRA20_DAS_DAC_ID_1 0 | ||
83 | #define TEGRA20_DAS_DAC_ID_2 1 | ||
84 | #define TEGRA20_DAS_DAC_ID_3 2 | ||
85 | |||
86 | #ifdef CONFIG_PM | ||
87 | #define TEGRA20_DAS_CACHE_SIZE ((((TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL) + (TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE*TEGRA20_DAS_DAC_ID_3))>>2) + 1) | ||
88 | #endif | ||
89 | |||
90 | struct tegra20_das { | ||
91 | struct device *dev; | ||
92 | void __iomem *regs; | ||
93 | struct dentry *debug; | ||
94 | #ifdef CONFIG_PM | ||
95 | u32 reg_cache[TEGRA20_DAS_CACHE_SIZE]; | ||
96 | #endif | ||
97 | }; | ||
98 | |||
99 | #ifdef CONFIG_PM | ||
100 | /* Restores the das registers from cache */ | ||
101 | extern int tegra20_das_resume(); | ||
102 | #endif | ||
103 | /* | ||
104 | * Terminology: | ||
105 | * DAS: Digital audio switch (HW module controlled by this driver) | ||
106 | * DAP: Digital audio port (port/pins on Tegra device) | ||
107 | * DAC: Digital audio controller (e.g. I2S or AC97 controller elsewhere) | ||
108 | * | ||
109 | * The Tegra DAS is a mux/cross-bar which can connect each DAP to a specific | ||
110 | * DAC, or another DAP. When DAPs are connected, one must be the master and | ||
111 | * one the slave. Each DAC allows selection of a specific DAP for input, to | ||
112 | * cater for the case where N DAPs are connected to 1 DAC for broadcast | ||
113 | * output. | ||
114 | * | ||
115 | * This driver is dumb; no attempt is made to ensure that a valid routing | ||
116 | * configuration is programmed. | ||
117 | */ | ||
118 | |||
119 | /* | ||
120 | * Connect a DAP to to a DAC | ||
121 | * dap_id: DAP to connect: TEGRA20_DAS_DAP_ID_* | ||
122 | * dac_sel: DAC to connect to: TEGRA20_DAS_DAP_SEL_DAC* | ||
123 | */ | ||
124 | extern int tegra20_das_connect_dap_to_dac(int dap_id, int dac_sel); | ||
125 | |||
126 | /* | ||
127 | * Connect a DAP to to another DAP | ||
128 | * dap_id: DAP to connect: TEGRA20_DAS_DAP_ID_* | ||
129 | * other_dap_sel: DAP to connect to: TEGRA20_DAS_DAP_SEL_DAP* | ||
130 | * master: Is this DAP the master (1) or slave (0) | ||
131 | * sdata1rx: Is this DAP's SDATA1 pin RX (1) or TX (0) | ||
132 | * sdata2rx: Is this DAP's SDATA2 pin RX (1) or TX (0) | ||
133 | */ | ||
134 | extern int tegra20_das_connect_dap_to_dap(int dap_id, int other_dap_sel, | ||
135 | int master, int sdata1rx, | ||
136 | int sdata2rx); | ||
137 | |||
138 | /* | ||
139 | * Connect a DAC's input to a DAP | ||
140 | * (DAC outputs are selected by the DAP) | ||
141 | * dac_id: DAC ID to connect: TEGRA20_DAS_DAC_ID_* | ||
142 | * dap_sel: DAP to receive input from: TEGRA20_DAS_DAC_SEL_DAP* | ||
143 | */ | ||
144 | extern int tegra20_das_connect_dac_to_dap(int dac_id, int dap_sel); | ||
145 | |||
146 | extern int tegra20_das_set_tristate(int dap_id, int is_tristate); | ||
147 | |||
148 | #endif | ||
diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c new file mode 100644 index 00000000000..e6de1c07a39 --- /dev/null +++ b/sound/soc/tegra/tegra20_i2s.c | |||
@@ -0,0 +1,586 @@ | |||
1 | /* | ||
2 | * tegra20_i2s.c - Tegra20 I2S driver | ||
3 | * | ||
4 | * Author: Stephen Warren <swarren@nvidia.com> | ||
5 | * Copyright (C) 2010 - NVIDIA, Inc. | ||
6 | * | ||
7 | * Based on code copyright/by: | ||
8 | * | ||
9 | * Copyright (c) 2009-2010, 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 | #include <asm/mach-types.h> | ||
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 <sound/core.h> | ||
41 | #include <sound/pcm.h> | ||
42 | #include <sound/pcm_params.h> | ||
43 | #include <sound/soc.h> | ||
44 | |||
45 | #include "tegra20_das.h" | ||
46 | #include "tegra20_i2s.h" | ||
47 | |||
48 | #define DRV_NAME "tegra20-i2s" | ||
49 | |||
50 | static inline void tegra20_i2s_write(struct tegra20_i2s *i2s, u32 reg, u32 val) | ||
51 | { | ||
52 | #ifdef CONFIG_PM | ||
53 | i2s->reg_cache[reg >> 2] = val; | ||
54 | #endif | ||
55 | __raw_writel(val, i2s->regs + reg); | ||
56 | } | ||
57 | |||
58 | static inline u32 tegra20_i2s_read(struct tegra20_i2s *i2s, u32 reg) | ||
59 | { | ||
60 | return __raw_readl(i2s->regs + reg); | ||
61 | } | ||
62 | |||
63 | #ifdef CONFIG_DEBUG_FS | ||
64 | static int tegra20_i2s_show(struct seq_file *s, void *unused) | ||
65 | { | ||
66 | #define REG(r) { r, #r } | ||
67 | static const struct { | ||
68 | int offset; | ||
69 | const char *name; | ||
70 | } regs[] = { | ||
71 | REG(TEGRA20_I2S_CTRL), | ||
72 | REG(TEGRA20_I2S_STATUS), | ||
73 | REG(TEGRA20_I2S_TIMING), | ||
74 | REG(TEGRA20_I2S_FIFO_SCR), | ||
75 | REG(TEGRA20_I2S_PCM_CTRL), | ||
76 | REG(TEGRA20_I2S_NW_CTRL), | ||
77 | REG(TEGRA20_I2S_TDM_CTRL), | ||
78 | REG(TEGRA20_I2S_TDM_TX_RX_CTRL), | ||
79 | }; | ||
80 | #undef REG | ||
81 | |||
82 | struct tegra20_i2s *i2s = s->private; | ||
83 | int i; | ||
84 | |||
85 | clk_enable(i2s->clk_i2s); | ||
86 | |||
87 | for (i = 0; i < ARRAY_SIZE(regs); i++) { | ||
88 | u32 val = tegra20_i2s_read(i2s, regs[i].offset); | ||
89 | seq_printf(s, "%s = %08x\n", regs[i].name, val); | ||
90 | } | ||
91 | |||
92 | clk_disable(i2s->clk_i2s); | ||
93 | |||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | static int tegra20_i2s_debug_open(struct inode *inode, struct file *file) | ||
98 | { | ||
99 | return single_open(file, tegra20_i2s_show, inode->i_private); | ||
100 | } | ||
101 | |||
102 | static const struct file_operations tegra20_i2s_debug_fops = { | ||
103 | .open = tegra20_i2s_debug_open, | ||
104 | .read = seq_read, | ||
105 | .llseek = seq_lseek, | ||
106 | .release = single_release, | ||
107 | }; | ||
108 | |||
109 | static void tegra20_i2s_debug_add(struct tegra20_i2s *i2s, int id) | ||
110 | { | ||
111 | char name[] = DRV_NAME ".0"; | ||
112 | |||
113 | snprintf(name, sizeof(name), DRV_NAME".%1d", id); | ||
114 | i2s->debug = debugfs_create_file(name, S_IRUGO, snd_soc_debugfs_root, | ||
115 | i2s, &tegra20_i2s_debug_fops); | ||
116 | } | ||
117 | |||
118 | static void tegra20_i2s_debug_remove(struct tegra20_i2s *i2s) | ||
119 | { | ||
120 | if (i2s->debug) | ||
121 | debugfs_remove(i2s->debug); | ||
122 | } | ||
123 | #else | ||
124 | static inline void tegra20_i2s_debug_add(struct tegra20_i2s *i2s, int id) | ||
125 | { | ||
126 | } | ||
127 | |||
128 | static inline void tegra20_i2s_debug_remove(struct tegra20_i2s *i2s) | ||
129 | { | ||
130 | } | ||
131 | #endif | ||
132 | |||
133 | static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai, | ||
134 | unsigned int fmt) | ||
135 | { | ||
136 | struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai); | ||
137 | |||
138 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
139 | case SND_SOC_DAIFMT_NB_NF: | ||
140 | break; | ||
141 | default: | ||
142 | return -EINVAL; | ||
143 | } | ||
144 | |||
145 | i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_MASTER_ENABLE; | ||
146 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
147 | case SND_SOC_DAIFMT_CBS_CFS: | ||
148 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_MASTER_ENABLE; | ||
149 | break; | ||
150 | case SND_SOC_DAIFMT_CBM_CFM: | ||
151 | break; | ||
152 | default: | ||
153 | return -EINVAL; | ||
154 | } | ||
155 | |||
156 | i2s->reg_ctrl &= ~(TEGRA20_I2S_CTRL_BIT_FORMAT_MASK | | ||
157 | TEGRA20_I2S_CTRL_LRCK_MASK); | ||
158 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
159 | case SND_SOC_DAIFMT_DSP_A: | ||
160 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP; | ||
161 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW; | ||
162 | break; | ||
163 | case SND_SOC_DAIFMT_DSP_B: | ||
164 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP; | ||
165 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_R_LOW; | ||
166 | break; | ||
167 | case SND_SOC_DAIFMT_I2S: | ||
168 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_I2S; | ||
169 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW; | ||
170 | break; | ||
171 | case SND_SOC_DAIFMT_RIGHT_J: | ||
172 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_RJM; | ||
173 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW; | ||
174 | break; | ||
175 | case SND_SOC_DAIFMT_LEFT_J: | ||
176 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_LJM; | ||
177 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW; | ||
178 | break; | ||
179 | default: | ||
180 | return -EINVAL; | ||
181 | } | ||
182 | |||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | static int tegra20_i2s_hw_params(struct snd_pcm_substream *substream, | ||
187 | struct snd_pcm_hw_params *params, | ||
188 | struct snd_soc_dai *dai) | ||
189 | { | ||
190 | struct device *dev = substream->pcm->card->dev; | ||
191 | struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai); | ||
192 | u32 reg; | ||
193 | int ret, sample_size, srate, i2sclock, bitcnt, i2sclk_div; | ||
194 | |||
195 | if ((i2s->reg_ctrl & TEGRA20_I2S_CTRL_BIT_FORMAT_I2S) && | ||
196 | (params_channels(params) != 2)) { | ||
197 | dev_err(dev, "Only Stereo is supported in I2s mode\n"); | ||
198 | return -EINVAL; | ||
199 | } | ||
200 | |||
201 | i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_BIT_SIZE_MASK; | ||
202 | switch (params_format(params)) { | ||
203 | case SNDRV_PCM_FORMAT_S16_LE: | ||
204 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_SIZE_16; | ||
205 | sample_size = 16; | ||
206 | break; | ||
207 | case SNDRV_PCM_FORMAT_S24_LE: | ||
208 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_SIZE_24; | ||
209 | sample_size = 24; | ||
210 | break; | ||
211 | case SNDRV_PCM_FORMAT_S32_LE: | ||
212 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_SIZE_32; | ||
213 | sample_size = 32; | ||
214 | break; | ||
215 | default: | ||
216 | return -EINVAL; | ||
217 | } | ||
218 | |||
219 | srate = params_rate(params); | ||
220 | |||
221 | /* Final "* 2" required by Tegra hardware */ | ||
222 | i2sclock = srate * params_channels(params) * sample_size * 2; | ||
223 | |||
224 | /* Additional "* 2" is needed for DSP mode */ | ||
225 | if (i2s->reg_ctrl & TEGRA20_I2S_CTRL_BIT_FORMAT_DSP && !machine_is_whistler()) | ||
226 | i2sclock *= 2; | ||
227 | |||
228 | ret = clk_set_rate(i2s->clk_i2s, i2sclock); | ||
229 | if (ret) { | ||
230 | dev_err(dev, "Can't set I2S clock rate: %d\n", ret); | ||
231 | return ret; | ||
232 | } | ||
233 | |||
234 | if (i2s->reg_ctrl & TEGRA20_I2S_CTRL_BIT_FORMAT_DSP) | ||
235 | i2sclk_div = srate; | ||
236 | else | ||
237 | i2sclk_div = params_channels(params) * srate; | ||
238 | |||
239 | bitcnt = (i2sclock / i2sclk_div) - 1; | ||
240 | |||
241 | if (bitcnt < 0 || bitcnt > TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US) | ||
242 | return -EINVAL; | ||
243 | reg = bitcnt << TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT; | ||
244 | |||
245 | if (i2sclock % i2sclk_div) | ||
246 | reg |= TEGRA20_I2S_TIMING_NON_SYM_ENABLE; | ||
247 | |||
248 | clk_enable(i2s->clk_i2s); | ||
249 | |||
250 | tegra20_i2s_write(i2s, TEGRA20_I2S_TIMING, reg); | ||
251 | |||
252 | if (sample_size * params_channels(params) >= 32) | ||
253 | tegra20_i2s_write(i2s, TEGRA20_I2S_FIFO_SCR, | ||
254 | TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS | | ||
255 | TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS); | ||
256 | else | ||
257 | tegra20_i2s_write(i2s, TEGRA20_I2S_FIFO_SCR, | ||
258 | TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_EIGHT_SLOTS | | ||
259 | TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_EIGHT_SLOTS); | ||
260 | |||
261 | i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_FIFO_FORMAT_MASK; | ||
262 | reg = tegra20_i2s_read(i2s, TEGRA20_I2S_PCM_CTRL); | ||
263 | if (i2s->reg_ctrl & TEGRA20_I2S_CTRL_BIT_FORMAT_DSP) { | ||
264 | if (sample_size == 16) | ||
265 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_FIFO_FORMAT_16_LSB; | ||
266 | else if (sample_size == 24) | ||
267 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_FIFO_FORMAT_24_LSB; | ||
268 | else | ||
269 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_FIFO_FORMAT_32; | ||
270 | |||
271 | i2s->capture_dma_data.width = sample_size; | ||
272 | i2s->playback_dma_data.width = sample_size; | ||
273 | |||
274 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
275 | reg |= TEGRA20_I2S_PCM_CTRL_TRM_MODE_EN; | ||
276 | else | ||
277 | reg |= TEGRA20_I2S_PCM_CTRL_RCV_MODE_EN; | ||
278 | } else { | ||
279 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_FIFO_FORMAT_PACKED; | ||
280 | i2s->capture_dma_data.width = 32; | ||
281 | i2s->playback_dma_data.width = 32; | ||
282 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
283 | reg &= ~TEGRA20_I2S_PCM_CTRL_TRM_MODE_EN; | ||
284 | else | ||
285 | reg &= ~TEGRA20_I2S_PCM_CTRL_RCV_MODE_EN; | ||
286 | } | ||
287 | tegra20_i2s_write(i2s, TEGRA20_I2S_PCM_CTRL, reg); | ||
288 | |||
289 | clk_disable(i2s->clk_i2s); | ||
290 | |||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | static void tegra20_i2s_start_playback(struct tegra20_i2s *i2s) | ||
295 | { | ||
296 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_FIFO1_ENABLE; | ||
297 | tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl); | ||
298 | } | ||
299 | |||
300 | static void tegra20_i2s_stop_playback(struct tegra20_i2s *i2s) | ||
301 | { | ||
302 | i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_FIFO1_ENABLE; | ||
303 | tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl); | ||
304 | } | ||
305 | |||
306 | static void tegra20_i2s_start_capture(struct tegra20_i2s *i2s) | ||
307 | { | ||
308 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_FIFO2_ENABLE; | ||
309 | tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl); | ||
310 | } | ||
311 | |||
312 | static void tegra20_i2s_stop_capture(struct tegra20_i2s *i2s) | ||
313 | { | ||
314 | i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_FIFO2_ENABLE; | ||
315 | tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl); | ||
316 | } | ||
317 | |||
318 | static int tegra20_i2s_trigger(struct snd_pcm_substream *substream, int cmd, | ||
319 | struct snd_soc_dai *dai) | ||
320 | { | ||
321 | struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai); | ||
322 | |||
323 | switch (cmd) { | ||
324 | case SNDRV_PCM_TRIGGER_START: | ||
325 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
326 | case SNDRV_PCM_TRIGGER_RESUME: | ||
327 | clk_enable(i2s->clk_i2s); | ||
328 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
329 | tegra20_i2s_start_playback(i2s); | ||
330 | else | ||
331 | tegra20_i2s_start_capture(i2s); | ||
332 | break; | ||
333 | case SNDRV_PCM_TRIGGER_STOP: | ||
334 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
335 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
336 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
337 | tegra20_i2s_stop_playback(i2s); | ||
338 | else | ||
339 | tegra20_i2s_stop_capture(i2s); | ||
340 | clk_disable(i2s->clk_i2s); | ||
341 | break; | ||
342 | default: | ||
343 | return -EINVAL; | ||
344 | } | ||
345 | |||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | static int tegra20_i2s_probe(struct snd_soc_dai *dai) | ||
350 | { | ||
351 | struct tegra20_i2s * i2s = snd_soc_dai_get_drvdata(dai); | ||
352 | #ifdef CONFIG_PM | ||
353 | int i; | ||
354 | #endif | ||
355 | |||
356 | dai->capture_dma_data = &i2s->capture_dma_data; | ||
357 | dai->playback_dma_data = &i2s->playback_dma_data; | ||
358 | |||
359 | #ifdef CONFIG_PM | ||
360 | /* populate the i2s reg cache with POR values*/ | ||
361 | clk_enable(i2s->clk_i2s); | ||
362 | |||
363 | for (i = 0; i < ((TEGRA20_I2S_TDM_TX_RX_CTRL >> 2) + 1); i++) { | ||
364 | if ((i == TEGRA20_I2S_CACHE_RSVD_6) || | ||
365 | (i == TEGRA20_I2S_CACHE_RSVD_7)) | ||
366 | continue; | ||
367 | |||
368 | i2s->reg_cache[i] = tegra20_i2s_read(i2s, i << 2); | ||
369 | } | ||
370 | |||
371 | clk_disable(i2s->clk_i2s); | ||
372 | #endif | ||
373 | |||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | #ifdef CONFIG_PM | ||
378 | int tegra20_i2s_resume(struct snd_soc_dai *cpu_dai) | ||
379 | { | ||
380 | struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai); | ||
381 | int i; | ||
382 | |||
383 | clk_enable(i2s->clk_i2s); | ||
384 | |||
385 | /*restore the i2s regs*/ | ||
386 | for (i = 0; i < ((TEGRA20_I2S_TDM_TX_RX_CTRL >> 2) + 1); i++) { | ||
387 | if ((i == TEGRA20_I2S_CACHE_RSVD_6) || | ||
388 | (i == TEGRA20_I2S_CACHE_RSVD_7)) | ||
389 | continue; | ||
390 | |||
391 | tegra20_i2s_write(i2s, i << 2, i2s->reg_cache[i]); | ||
392 | } | ||
393 | |||
394 | /*restore the das regs*/ | ||
395 | tegra20_das_resume(); | ||
396 | |||
397 | clk_disable(i2s->clk_i2s); | ||
398 | |||
399 | return 0; | ||
400 | } | ||
401 | #else | ||
402 | #define tegra20_i2s_resume NULL | ||
403 | #endif | ||
404 | |||
405 | static struct snd_soc_dai_ops tegra20_i2s_dai_ops = { | ||
406 | .set_fmt = tegra20_i2s_set_fmt, | ||
407 | .hw_params = tegra20_i2s_hw_params, | ||
408 | .trigger = tegra20_i2s_trigger, | ||
409 | }; | ||
410 | |||
411 | struct snd_soc_dai_driver tegra20_i2s_dai[] = { | ||
412 | { | ||
413 | .name = DRV_NAME ".0", | ||
414 | .probe = tegra20_i2s_probe, | ||
415 | .resume = tegra20_i2s_resume, | ||
416 | .playback = { | ||
417 | .channels_min = 1, | ||
418 | .channels_max = 2, | ||
419 | .rates = SNDRV_PCM_RATE_8000_96000, | ||
420 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
421 | }, | ||
422 | .capture = { | ||
423 | .channels_min = 1, | ||
424 | .channels_max = 2, | ||
425 | .rates = SNDRV_PCM_RATE_8000_96000, | ||
426 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
427 | }, | ||
428 | .ops = &tegra20_i2s_dai_ops, | ||
429 | .symmetric_rates = 1, | ||
430 | }, | ||
431 | { | ||
432 | .name = DRV_NAME ".1", | ||
433 | .probe = tegra20_i2s_probe, | ||
434 | .resume = tegra20_i2s_resume, | ||
435 | .playback = { | ||
436 | .channels_min = 1, | ||
437 | .channels_max = 2, | ||
438 | .rates = SNDRV_PCM_RATE_8000_96000, | ||
439 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
440 | }, | ||
441 | .capture = { | ||
442 | .channels_min = 1, | ||
443 | .channels_max = 2, | ||
444 | .rates = SNDRV_PCM_RATE_8000_96000, | ||
445 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
446 | }, | ||
447 | .ops = &tegra20_i2s_dai_ops, | ||
448 | .symmetric_rates = 1, | ||
449 | }, | ||
450 | }; | ||
451 | |||
452 | static __devinit int tegra20_i2s_platform_probe(struct platform_device *pdev) | ||
453 | { | ||
454 | struct tegra20_i2s * i2s; | ||
455 | struct resource *mem, *memregion, *dmareq; | ||
456 | int ret; | ||
457 | |||
458 | if ((pdev->id < 0) || | ||
459 | (pdev->id >= ARRAY_SIZE(tegra20_i2s_dai))) { | ||
460 | dev_err(&pdev->dev, "ID %d out of range\n", pdev->id); | ||
461 | return -EINVAL; | ||
462 | } | ||
463 | |||
464 | i2s = kzalloc(sizeof(struct tegra20_i2s), GFP_KERNEL); | ||
465 | if (!i2s) { | ||
466 | dev_err(&pdev->dev, "Can't allocate tegra20_i2s\n"); | ||
467 | ret = -ENOMEM; | ||
468 | goto exit; | ||
469 | } | ||
470 | dev_set_drvdata(&pdev->dev, i2s); | ||
471 | |||
472 | i2s->clk_i2s = clk_get(&pdev->dev, NULL); | ||
473 | if (IS_ERR(i2s->clk_i2s)) { | ||
474 | dev_err(&pdev->dev, "Can't retrieve i2s clock\n"); | ||
475 | ret = PTR_ERR(i2s->clk_i2s); | ||
476 | goto err_free; | ||
477 | } | ||
478 | |||
479 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
480 | if (!mem) { | ||
481 | dev_err(&pdev->dev, "No memory resource\n"); | ||
482 | ret = -ENODEV; | ||
483 | goto err_clk_put; | ||
484 | } | ||
485 | |||
486 | dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0); | ||
487 | if (!dmareq) { | ||
488 | dev_err(&pdev->dev, "No DMA resource\n"); | ||
489 | ret = -ENODEV; | ||
490 | goto err_clk_put; | ||
491 | } | ||
492 | |||
493 | memregion = request_mem_region(mem->start, resource_size(mem), | ||
494 | DRV_NAME); | ||
495 | if (!memregion) { | ||
496 | dev_err(&pdev->dev, "Memory region already claimed\n"); | ||
497 | ret = -EBUSY; | ||
498 | goto err_clk_put; | ||
499 | } | ||
500 | |||
501 | i2s->regs = ioremap(mem->start, resource_size(mem)); | ||
502 | if (!i2s->regs) { | ||
503 | dev_err(&pdev->dev, "ioremap failed\n"); | ||
504 | ret = -ENOMEM; | ||
505 | goto err_release; | ||
506 | } | ||
507 | |||
508 | i2s->capture_dma_data.addr = mem->start + TEGRA20_I2S_FIFO2; | ||
509 | i2s->capture_dma_data.wrap = 4; | ||
510 | i2s->capture_dma_data.width = 32; | ||
511 | i2s->capture_dma_data.req_sel = dmareq->start; | ||
512 | |||
513 | i2s->playback_dma_data.addr = mem->start + TEGRA20_I2S_FIFO1; | ||
514 | i2s->playback_dma_data.wrap = 4; | ||
515 | i2s->playback_dma_data.width = 32; | ||
516 | i2s->playback_dma_data.req_sel = dmareq->start; | ||
517 | |||
518 | ret = snd_soc_register_dai(&pdev->dev, &tegra20_i2s_dai[pdev->id]); | ||
519 | if (ret) { | ||
520 | dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); | ||
521 | ret = -ENOMEM; | ||
522 | goto err_unmap; | ||
523 | } | ||
524 | |||
525 | tegra20_i2s_debug_add(i2s, pdev->id); | ||
526 | |||
527 | return 0; | ||
528 | |||
529 | err_unmap: | ||
530 | iounmap(i2s->regs); | ||
531 | err_release: | ||
532 | release_mem_region(mem->start, resource_size(mem)); | ||
533 | err_clk_put: | ||
534 | clk_put(i2s->clk_i2s); | ||
535 | err_free: | ||
536 | kfree(i2s); | ||
537 | exit: | ||
538 | return ret; | ||
539 | } | ||
540 | |||
541 | static int __devexit tegra20_i2s_platform_remove(struct platform_device *pdev) | ||
542 | { | ||
543 | struct tegra20_i2s *i2s = dev_get_drvdata(&pdev->dev); | ||
544 | struct resource *res; | ||
545 | |||
546 | snd_soc_unregister_dai(&pdev->dev); | ||
547 | |||
548 | tegra20_i2s_debug_remove(i2s); | ||
549 | |||
550 | iounmap(i2s->regs); | ||
551 | |||
552 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
553 | release_mem_region(res->start, resource_size(res)); | ||
554 | |||
555 | clk_put(i2s->clk_i2s); | ||
556 | |||
557 | kfree(i2s); | ||
558 | |||
559 | return 0; | ||
560 | } | ||
561 | |||
562 | static struct platform_driver tegra20_i2s_driver = { | ||
563 | .driver = { | ||
564 | .name = DRV_NAME, | ||
565 | .owner = THIS_MODULE, | ||
566 | }, | ||
567 | .probe = tegra20_i2s_platform_probe, | ||
568 | .remove = __devexit_p(tegra20_i2s_platform_remove), | ||
569 | }; | ||
570 | |||
571 | static int __init snd_tegra20_i2s_init(void) | ||
572 | { | ||
573 | return platform_driver_register(&tegra20_i2s_driver); | ||
574 | } | ||
575 | module_init(snd_tegra20_i2s_init); | ||
576 | |||
577 | static void __exit snd_tegra20_i2s_exit(void) | ||
578 | { | ||
579 | platform_driver_unregister(&tegra20_i2s_driver); | ||
580 | } | ||
581 | module_exit(snd_tegra20_i2s_exit); | ||
582 | |||
583 | MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); | ||
584 | MODULE_DESCRIPTION("Tegra I2S ASoC driver"); | ||
585 | MODULE_LICENSE("GPL"); | ||
586 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/sound/soc/tegra/tegra20_i2s.h b/sound/soc/tegra/tegra20_i2s.h new file mode 100644 index 00000000000..ded0c8dee02 --- /dev/null +++ b/sound/soc/tegra/tegra20_i2s.h | |||
@@ -0,0 +1,198 @@ | |||
1 | /* | ||
2 | * tegra20_i2s.h - Definitions for Tegra20 I2S driver | ||
3 | * | ||
4 | * Author: Stephen Warren <swarren@nvidia.com> | ||
5 | * Copyright (C) 2010 - NVIDIA, Inc. | ||
6 | * | ||
7 | * Based on code copyright/by: | ||
8 | * | ||
9 | * Copyright (c) 2009-2010, 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 __TEGRA20_I2S_H__ | ||
32 | #define __TEGRA20_I2S_H__ | ||
33 | |||
34 | #include "tegra_pcm.h" | ||
35 | |||
36 | /* Register offsets from TEGRA20_I2S1_BASE and TEGRA20_I2S2_BASE */ | ||
37 | |||
38 | #define TEGRA20_I2S_CTRL 0x00 | ||
39 | #define TEGRA20_I2S_STATUS 0x04 | ||
40 | #define TEGRA20_I2S_TIMING 0x08 | ||
41 | #define TEGRA20_I2S_FIFO_SCR 0x0c | ||
42 | #define TEGRA20_I2S_PCM_CTRL 0x10 | ||
43 | #define TEGRA20_I2S_NW_CTRL 0x14 | ||
44 | #define TEGRA20_I2S_TDM_CTRL 0x20 | ||
45 | #define TEGRA20_I2S_TDM_TX_RX_CTRL 0x24 | ||
46 | #define TEGRA20_I2S_FIFO1 0x40 | ||
47 | #define TEGRA20_I2S_FIFO2 0x80 | ||
48 | |||
49 | /* Fields in TEGRA20_I2S_CTRL */ | ||
50 | |||
51 | #define TEGRA20_I2S_CTRL_FIFO2_TX_ENABLE (1 << 30) | ||
52 | #define TEGRA20_I2S_CTRL_FIFO1_ENABLE (1 << 29) | ||
53 | #define TEGRA20_I2S_CTRL_FIFO2_ENABLE (1 << 28) | ||
54 | #define TEGRA20_I2S_CTRL_FIFO1_RX_ENABLE (1 << 27) | ||
55 | #define TEGRA20_I2S_CTRL_FIFO_LPBK_ENABLE (1 << 26) | ||
56 | #define TEGRA20_I2S_CTRL_MASTER_ENABLE (1 << 25) | ||
57 | |||
58 | #define TEGRA20_I2S_LRCK_LEFT_LOW 0 | ||
59 | #define TEGRA20_I2S_LRCK_RIGHT_LOW 1 | ||
60 | |||
61 | #define TEGRA20_I2S_CTRL_LRCK_SHIFT 24 | ||
62 | #define TEGRA20_I2S_CTRL_LRCK_MASK (1 << TEGRA20_I2S_CTRL_LRCK_SHIFT) | ||
63 | #define TEGRA20_I2S_CTRL_LRCK_L_LOW (TEGRA20_I2S_LRCK_LEFT_LOW << TEGRA20_I2S_CTRL_LRCK_SHIFT) | ||
64 | #define TEGRA20_I2S_CTRL_LRCK_R_LOW (TEGRA20_I2S_LRCK_RIGHT_LOW << TEGRA20_I2S_CTRL_LRCK_SHIFT) | ||
65 | |||
66 | #define TEGRA20_I2S_BIT_FORMAT_I2S 0 | ||
67 | #define TEGRA20_I2S_BIT_FORMAT_RJM 1 | ||
68 | #define TEGRA20_I2S_BIT_FORMAT_LJM 2 | ||
69 | #define TEGRA20_I2S_BIT_FORMAT_DSP 3 | ||
70 | |||
71 | #define TEGRA20_I2S_CTRL_BIT_FORMAT_SHIFT 10 | ||
72 | #define TEGRA20_I2S_CTRL_BIT_FORMAT_MASK (3 << TEGRA20_I2S_CTRL_BIT_FORMAT_SHIFT) | ||
73 | #define TEGRA20_I2S_CTRL_BIT_FORMAT_I2S (TEGRA20_I2S_BIT_FORMAT_I2S << TEGRA20_I2S_CTRL_BIT_FORMAT_SHIFT) | ||
74 | #define TEGRA20_I2S_CTRL_BIT_FORMAT_RJM (TEGRA20_I2S_BIT_FORMAT_RJM << TEGRA20_I2S_CTRL_BIT_FORMAT_SHIFT) | ||
75 | #define TEGRA20_I2S_CTRL_BIT_FORMAT_LJM (TEGRA20_I2S_BIT_FORMAT_LJM << TEGRA20_I2S_CTRL_BIT_FORMAT_SHIFT) | ||
76 | #define TEGRA20_I2S_CTRL_BIT_FORMAT_DSP (TEGRA20_I2S_BIT_FORMAT_DSP << TEGRA20_I2S_CTRL_BIT_FORMAT_SHIFT) | ||
77 | |||
78 | #define TEGRA20_I2S_BIT_SIZE_16 0 | ||
79 | #define TEGRA20_I2S_BIT_SIZE_20 1 | ||
80 | #define TEGRA20_I2S_BIT_SIZE_24 2 | ||
81 | #define TEGRA20_I2S_BIT_SIZE_32 3 | ||
82 | |||
83 | #define TEGRA20_I2S_CTRL_BIT_SIZE_SHIFT 8 | ||
84 | #define TEGRA20_I2S_CTRL_BIT_SIZE_MASK (3 << TEGRA20_I2S_CTRL_BIT_SIZE_SHIFT) | ||
85 | #define TEGRA20_I2S_CTRL_BIT_SIZE_16 (TEGRA20_I2S_BIT_SIZE_16 << TEGRA20_I2S_CTRL_BIT_SIZE_SHIFT) | ||
86 | #define TEGRA20_I2S_CTRL_BIT_SIZE_20 (TEGRA20_I2S_BIT_SIZE_20 << TEGRA20_I2S_CTRL_BIT_SIZE_SHIFT) | ||
87 | #define TEGRA20_I2S_CTRL_BIT_SIZE_24 (TEGRA20_I2S_BIT_SIZE_24 << TEGRA20_I2S_CTRL_BIT_SIZE_SHIFT) | ||
88 | #define TEGRA20_I2S_CTRL_BIT_SIZE_32 (TEGRA20_I2S_BIT_SIZE_32 << TEGRA20_I2S_CTRL_BIT_SIZE_SHIFT) | ||
89 | |||
90 | #define TEGRA20_I2S_FIFO_16_LSB 0 | ||
91 | #define TEGRA20_I2S_FIFO_20_LSB 1 | ||
92 | #define TEGRA20_I2S_FIFO_24_LSB 2 | ||
93 | #define TEGRA20_I2S_FIFO_32 3 | ||
94 | #define TEGRA20_I2S_FIFO_PACKED 7 | ||
95 | |||
96 | #define TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT 4 | ||
97 | #define TEGRA20_I2S_CTRL_FIFO_FORMAT_MASK (7 << TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT) | ||
98 | #define TEGRA20_I2S_CTRL_FIFO_FORMAT_16_LSB (TEGRA20_I2S_FIFO_16_LSB << TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT) | ||
99 | #define TEGRA20_I2S_CTRL_FIFO_FORMAT_20_LSB (TEGRA20_I2S_FIFO_20_LSB << TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT) | ||
100 | #define TEGRA20_I2S_CTRL_FIFO_FORMAT_24_LSB (TEGRA20_I2S_FIFO_24_LSB << TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT) | ||
101 | #define TEGRA20_I2S_CTRL_FIFO_FORMAT_32 (TEGRA20_I2S_FIFO_32 << TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT) | ||
102 | #define TEGRA20_I2S_CTRL_FIFO_FORMAT_PACKED (TEGRA20_I2S_FIFO_PACKED << TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT) | ||
103 | |||
104 | #define TEGRA20_I2S_CTRL_IE_FIFO1_ERR (1 << 3) | ||
105 | #define TEGRA20_I2S_CTRL_IE_FIFO2_ERR (1 << 2) | ||
106 | #define TEGRA20_I2S_CTRL_QE_FIFO1 (1 << 1) | ||
107 | #define TEGRA20_I2S_CTRL_QE_FIFO2 (1 << 0) | ||
108 | |||
109 | /* Fields in TEGRA20_I2S_STATUS */ | ||
110 | |||
111 | #define TEGRA20_I2S_STATUS_FIFO1_RDY (1 << 31) | ||
112 | #define TEGRA20_I2S_STATUS_FIFO2_RDY (1 << 30) | ||
113 | #define TEGRA20_I2S_STATUS_FIFO1_BSY (1 << 29) | ||
114 | #define TEGRA20_I2S_STATUS_FIFO2_BSY (1 << 28) | ||
115 | #define TEGRA20_I2S_STATUS_FIFO1_ERR (1 << 3) | ||
116 | #define TEGRA20_I2S_STATUS_FIFO2_ERR (1 << 2) | ||
117 | #define TEGRA20_I2S_STATUS_QS_FIFO1 (1 << 1) | ||
118 | #define TEGRA20_I2S_STATUS_QS_FIFO2 (1 << 0) | ||
119 | |||
120 | /* Fields in TEGRA20_I2S_TIMING */ | ||
121 | |||
122 | #define TEGRA20_I2S_TIMING_NON_SYM_ENABLE (1 << 12) | ||
123 | #define TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT 0 | ||
124 | #define TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US 0x7fff | ||
125 | #define TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_MASK (TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US << TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT) | ||
126 | |||
127 | /* Fields in TEGRA20_I2S_FIFO_SCR */ | ||
128 | |||
129 | #define TEGRA20_I2S_FIFO_SCR_FIFO2_FULL_EMPTY_COUNT_SHIFT 24 | ||
130 | #define TEGRA20_I2S_FIFO_SCR_FIFO1_FULL_EMPTY_COUNT_SHIFT 16 | ||
131 | #define TEGRA20_I2S_FIFO_SCR_FIFO_FULL_EMPTY_COUNT_MASK 0x3f | ||
132 | |||
133 | #define TEGRA20_I2S_FIFO_SCR_FIFO2_CLR (1 << 12) | ||
134 | #define TEGRA20_I2S_FIFO_SCR_FIFO1_CLR (1 << 8) | ||
135 | |||
136 | #define TEGRA20_I2S_FIFO_ATN_LVL_ONE_SLOT 0 | ||
137 | #define TEGRA20_I2S_FIFO_ATN_LVL_FOUR_SLOTS 1 | ||
138 | #define TEGRA20_I2S_FIFO_ATN_LVL_EIGHT_SLOTS 2 | ||
139 | #define TEGRA20_I2S_FIFO_ATN_LVL_TWELVE_SLOTS 3 | ||
140 | |||
141 | #define TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT 4 | ||
142 | #define TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_MASK (3 << TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT) | ||
143 | #define TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_ONE_SLOT (TEGRA20_I2S_FIFO_ATN_LVL_ONE_SLOT << TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT) | ||
144 | #define TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS (TEGRA20_I2S_FIFO_ATN_LVL_FOUR_SLOTS << TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT) | ||
145 | #define TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_EIGHT_SLOTS (TEGRA20_I2S_FIFO_ATN_LVL_EIGHT_SLOTS << TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT) | ||
146 | #define TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_TWELVE_SLOTS (TEGRA20_I2S_FIFO_ATN_LVL_TWELVE_SLOTS << TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT) | ||
147 | |||
148 | #define TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT 0 | ||
149 | #define TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_MASK (3 << TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT) | ||
150 | #define TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_ONE_SLOT (TEGRA20_I2S_FIFO_ATN_LVL_ONE_SLOT << TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT) | ||
151 | #define TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS (TEGRA20_I2S_FIFO_ATN_LVL_FOUR_SLOTS << TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT) | ||
152 | #define TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_EIGHT_SLOTS (TEGRA20_I2S_FIFO_ATN_LVL_EIGHT_SLOTS << TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT) | ||
153 | #define TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_TWELVE_SLOTS (TEGRA20_I2S_FIFO_ATN_LVL_TWELVE_SLOTS << TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT) | ||
154 | |||
155 | /* Fields in TEGRA20_I2S_PCM_CTRL */ | ||
156 | |||
157 | #define TEGRA20_I2S_PCM_TX_POS_EDGE_NO_HIGHZ 0 | ||
158 | #define TEGRA20_I2S_PCM_TX_POS_EDGE_HIGHZ 1 | ||
159 | #define TEGRA20_I2S_PCM_TX_NEG_EDGE_NO_HIGHZ 2 | ||
160 | #define TEGRA20_I2S_PCM_TX_NEG_EDGE_HIGHZ 3 | ||
161 | |||
162 | #define TEGRA20_I2S_PCM_CTRL_TX_EDGE_CTRL_SHIFT 9 | ||
163 | #define TEGRA20_I2S_PCM_CTRL_TX_EDGE_CTRL_MASK (0x3 << TEGRA20_I2S_PCM_CTRL_TX_EDGE_CTRL_SHIFT) | ||
164 | #define TEGRA20_I2S_PCM_CTRL_TX_POS_EDGE_NO_HIGHZ (TEGRA20_I2S_PCM_TX_POS_EDGE_NO_HIGHZ << TEGRA20_I2S_PCM_CTRL_TX_EDGE_CTRL_SHIFT) | ||
165 | #define TEGRA20_I2S_PCM_CTRL_TX_POS_EDGE_HIGHZ (TEGRA20_I2S_PCM_TX_POS_EDGE_HIGHZ << TEGRA20_I2S_PCM_CTRL_TX_EDGE_CTRL_SHIFT) | ||
166 | #define TEGRA20_I2S_PCM_CTRL_TX_NEG_EDGE_NO_HIGHZ (TEGRA20_I2S_PCM_TX_NEG_EDGE_NO_HIGHZ << TEGRA20_I2S_PCM_CTRL_TX_EDGE_CTRL_SHIFT) | ||
167 | #define TEGRA20_I2S_PCM_CTRL_TX_NEG_EDGE_HIGHZ (TEGRA20_I2S_PCM_TX_NEG_EDGE_HIGHZ << TEGRA20_I2S_PCM_CTRL_TX_EDGE_CTRL_SHIFT) | ||
168 | |||
169 | #define TEGRA20_I2S_PCM_CTRL_TX_MASK_BITS_SHIFT 6 | ||
170 | #define TEGRA20_I2S_PCM_CTRL_TX_MASK_BITS_MASK (0x7 << TEGRA20_I2S_PCM_CTRL_TX_MASK_BITS_SHIFT) | ||
171 | |||
172 | #define TEGRA20_I2S_PCM_CTRL_FSYNC_LONG (1 << 5) | ||
173 | #define TEGRA20_I2S_PCM_CTRL_TRM_MODE_EN (1 << 4) | ||
174 | |||
175 | #define TEGRA20_I2S_PCM_CTRL_RX_MASK_BITS_SHIFT 1 | ||
176 | #define TEGRA20_I2S_PCM_CTRL_RX_MASK_BITS_MASK (0x7 << TEGRA20_I2S_PCM_CTRL_RX_MASK_BITS_SHIFT) | ||
177 | |||
178 | #define TEGRA20_I2S_PCM_CTRL_RCV_MODE_EN (1 << 0) | ||
179 | |||
180 | #ifdef CONFIG_PM | ||
181 | /* unused cache locations for i2s reg cache */ | ||
182 | #define TEGRA20_I2S_CACHE_RSVD_6 ((TEGRA20_I2S_NW_CTRL>>2) + 1) | ||
183 | #define TEGRA20_I2S_CACHE_RSVD_7 (TEGRA20_I2S_CACHE_RSVD_6 + 1) | ||
184 | #endif | ||
185 | |||
186 | struct tegra20_i2s { | ||
187 | struct clk *clk_i2s; | ||
188 | struct tegra_pcm_dma_params capture_dma_data; | ||
189 | struct tegra_pcm_dma_params playback_dma_data; | ||
190 | void __iomem *regs; | ||
191 | struct dentry *debug; | ||
192 | u32 reg_ctrl; | ||
193 | #ifdef CONFIG_PM | ||
194 | u32 reg_cache[(TEGRA20_I2S_TDM_TX_RX_CTRL >> 2) + 1]; | ||
195 | #endif | ||
196 | }; | ||
197 | |||
198 | #endif | ||
diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c new file mode 100644 index 00000000000..3e747b5e193 --- /dev/null +++ b/sound/soc/tegra/tegra20_spdif.c | |||
@@ -0,0 +1,463 @@ | |||
1 | /* | ||
2 | * tegra20_spdif.c - Tegra20 SPDIF driver | ||
3 | * | ||
4 | * Author: Stephen Warren <swarren@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 <mach/iomap.h> | ||
32 | #include <mach/hdmi-audio.h> | ||
33 | #include <sound/core.h> | ||
34 | #include <sound/pcm.h> | ||
35 | #include <sound/pcm_params.h> | ||
36 | #include <sound/soc.h> | ||
37 | |||
38 | #include "tegra20_spdif.h" | ||
39 | |||
40 | #define DRV_NAME "tegra20-spdif" | ||
41 | |||
42 | static inline void tegra20_spdif_write(struct tegra20_spdif *spdif, u32 reg, | ||
43 | u32 val) | ||
44 | { | ||
45 | #ifdef CONFIG_PM | ||
46 | if (reg < TEGRA20_SPDIF_CH_STA_TX_A) | ||
47 | spdif->reg_ctrl_cache[reg >> 2] = val; | ||
48 | else | ||
49 | spdif->reg_tx_cache[((reg - TEGRA20_SPDIF_CH_STA_TX_A) >> 2)] | ||
50 | = val; | ||
51 | #endif | ||
52 | __raw_writel(val, spdif->regs + reg); | ||
53 | } | ||
54 | |||
55 | static inline u32 tegra20_spdif_read(struct tegra20_spdif *spdif, u32 reg) | ||
56 | { | ||
57 | return __raw_readl(spdif->regs + reg); | ||
58 | } | ||
59 | |||
60 | #ifdef CONFIG_DEBUG_FS | ||
61 | static int tegra20_spdif_show(struct seq_file *s, void *unused) | ||
62 | { | ||
63 | #define REG(r) { r, #r } | ||
64 | static const struct { | ||
65 | int offset; | ||
66 | const char *name; | ||
67 | } regs[] = { | ||
68 | REG(TEGRA20_SPDIF_CTRL), | ||
69 | REG(TEGRA20_SPDIF_STATUS), | ||
70 | REG(TEGRA20_SPDIF_STROBE_CTRL), | ||
71 | REG(TEGRA20_SPDIF_DATA_FIFO_CSR), | ||
72 | REG(TEGRA20_SPDIF_CH_STA_RX_A), | ||
73 | REG(TEGRA20_SPDIF_CH_STA_RX_B), | ||
74 | REG(TEGRA20_SPDIF_CH_STA_RX_C), | ||
75 | REG(TEGRA20_SPDIF_CH_STA_RX_D), | ||
76 | REG(TEGRA20_SPDIF_CH_STA_RX_E), | ||
77 | REG(TEGRA20_SPDIF_CH_STA_RX_F), | ||
78 | REG(TEGRA20_SPDIF_CH_STA_TX_A), | ||
79 | REG(TEGRA20_SPDIF_CH_STA_TX_B), | ||
80 | REG(TEGRA20_SPDIF_CH_STA_TX_C), | ||
81 | REG(TEGRA20_SPDIF_CH_STA_TX_D), | ||
82 | REG(TEGRA20_SPDIF_CH_STA_TX_E), | ||
83 | REG(TEGRA20_SPDIF_CH_STA_TX_F), | ||
84 | }; | ||
85 | #undef REG | ||
86 | |||
87 | struct tegra20_spdif *spdif = s->private; | ||
88 | int i; | ||
89 | |||
90 | for (i = 0; i < ARRAY_SIZE(regs); i++) { | ||
91 | u32 val = tegra20_spdif_read(spdif, regs[i].offset); | ||
92 | seq_printf(s, "%s = %08x\n", regs[i].name, val); | ||
93 | } | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | static int tegra20_spdif_debug_open(struct inode *inode, struct file *file) | ||
99 | { | ||
100 | return single_open(file, tegra20_spdif_show, inode->i_private); | ||
101 | } | ||
102 | |||
103 | static const struct file_operations tegra20_spdif_debug_fops = { | ||
104 | .open = tegra20_spdif_debug_open, | ||
105 | .read = seq_read, | ||
106 | .llseek = seq_lseek, | ||
107 | .release = single_release, | ||
108 | }; | ||
109 | |||
110 | static void tegra20_spdif_debug_add(struct tegra20_spdif *spdif) | ||
111 | { | ||
112 | spdif->debug = debugfs_create_file(DRV_NAME, S_IRUGO, | ||
113 | snd_soc_debugfs_root, spdif, | ||
114 | &tegra20_spdif_debug_fops); | ||
115 | } | ||
116 | |||
117 | static void tegra20_spdif_debug_remove(struct tegra20_spdif *spdif) | ||
118 | { | ||
119 | if (spdif->debug) | ||
120 | debugfs_remove(spdif->debug); | ||
121 | } | ||
122 | #else | ||
123 | static inline void tegra20_spdif_debug_add(struct tegra20_spdif *spdif) | ||
124 | { | ||
125 | } | ||
126 | |||
127 | static inline void tegra20_spdif_debug_remove(struct tegra20_spdif *spdif) | ||
128 | { | ||
129 | } | ||
130 | #endif | ||
131 | |||
132 | static int tegra20_spdif_hw_params(struct snd_pcm_substream *substream, | ||
133 | struct snd_pcm_hw_params *params, | ||
134 | struct snd_soc_dai *dai) | ||
135 | { | ||
136 | struct device *dev = substream->pcm->card->dev; | ||
137 | struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai); | ||
138 | int ret, srate, spdifclock; | ||
139 | u32 ch_sta[2] = {0, 0}; | ||
140 | |||
141 | spdif->reg_ctrl &= ~TEGRA20_SPDIF_CTRL_PACK; | ||
142 | spdif->reg_ctrl &= ~TEGRA20_SPDIF_CTRL_BIT_MODE_MASK; | ||
143 | switch (params_format(params)) { | ||
144 | case SNDRV_PCM_FORMAT_S16_LE: | ||
145 | spdif->reg_ctrl |= TEGRA20_SPDIF_CTRL_PACK; | ||
146 | spdif->reg_ctrl |= TEGRA20_SPDIF_CTRL_BIT_MODE_16BIT; | ||
147 | break; | ||
148 | default: | ||
149 | return -EINVAL; | ||
150 | } | ||
151 | |||
152 | srate = params_rate(params); | ||
153 | ch_sta[0] = tegra20_spdif_read(spdif, TEGRA20_SPDIF_CH_STA_TX_A); | ||
154 | ch_sta[0] &= ~TEGRA20_SPDIF_CH_STA_TX_A_SAMP_FREQ_MASK; | ||
155 | ch_sta[1] = tegra20_spdif_read(spdif, TEGRA20_SPDIF_CH_STA_TX_B); | ||
156 | ch_sta[1] &= ~TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_MASK; | ||
157 | switch (params_rate(params)) { | ||
158 | case 32000: | ||
159 | spdifclock = 4096000; | ||
160 | ch_sta[0] |= TEGRA20_SPDIF_CH_STA_TX_A_SAMP_FREQ_32000; | ||
161 | ch_sta[1] |= TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_32000; | ||
162 | break; | ||
163 | case 44100: | ||
164 | spdifclock = 5644800; | ||
165 | ch_sta[0] |= TEGRA20_SPDIF_CH_STA_TX_A_SAMP_FREQ_44100; | ||
166 | ch_sta[1] |= TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_44100; | ||
167 | break; | ||
168 | case 48000: | ||
169 | spdifclock = 6144000; | ||
170 | ch_sta[0] |= TEGRA20_SPDIF_CH_STA_TX_A_SAMP_FREQ_48000; | ||
171 | ch_sta[1] |= TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_48000; | ||
172 | break; | ||
173 | case 88200: | ||
174 | spdifclock = 11289600; | ||
175 | ch_sta[0] |= TEGRA20_SPDIF_CH_STA_TX_A_SAMP_FREQ_88200; | ||
176 | ch_sta[1] |= TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_88200; | ||
177 | break; | ||
178 | case 96000: | ||
179 | spdifclock = 12288000; | ||
180 | ch_sta[0] |= TEGRA20_SPDIF_CH_STA_TX_A_SAMP_FREQ_96000; | ||
181 | ch_sta[1] |= TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_96000; | ||
182 | break; | ||
183 | case 176400: | ||
184 | spdifclock = 22579200; | ||
185 | ch_sta[0] |= TEGRA20_SPDIF_CH_STA_TX_A_SAMP_FREQ_176400; | ||
186 | ch_sta[1] |= TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_176400; | ||
187 | break; | ||
188 | case 192000: | ||
189 | spdifclock = 24576000; | ||
190 | ch_sta[0] |= TEGRA20_SPDIF_CH_STA_TX_A_SAMP_FREQ_192000; | ||
191 | ch_sta[1] |= TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_192000; | ||
192 | break; | ||
193 | default: | ||
194 | return -EINVAL; | ||
195 | } | ||
196 | |||
197 | ret = clk_set_rate(spdif->clk_spdif_out, spdifclock); | ||
198 | if (ret) { | ||
199 | dev_err(dev, "Can't set SPDIF clock rate: %d\n", ret); | ||
200 | return ret; | ||
201 | } | ||
202 | |||
203 | clk_enable(spdif->clk_spdif_out); | ||
204 | |||
205 | tegra20_spdif_write(spdif, TEGRA20_SPDIF_CH_STA_TX_A, ch_sta[0]); | ||
206 | tegra20_spdif_write(spdif, TEGRA20_SPDIF_CH_STA_TX_B, ch_sta[1]); | ||
207 | |||
208 | clk_disable(spdif->clk_spdif_out); | ||
209 | |||
210 | ret = tegra_hdmi_setup_audio_freq_source(srate, SPDIF); | ||
211 | if (ret) { | ||
212 | dev_err(dev, "Can't set HDMI audio freq source: %d\n", ret); | ||
213 | return ret; | ||
214 | } | ||
215 | |||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | static void tegra20_spdif_start_playback(struct tegra20_spdif *spdif) | ||
220 | { | ||
221 | spdif->reg_ctrl |= TEGRA20_SPDIF_CTRL_TC_EN | TEGRA20_SPDIF_CTRL_TX_EN; | ||
222 | tegra20_spdif_write(spdif, TEGRA20_SPDIF_CTRL, spdif->reg_ctrl); | ||
223 | } | ||
224 | |||
225 | static void tegra20_spdif_stop_playback(struct tegra20_spdif *spdif) | ||
226 | { | ||
227 | spdif->reg_ctrl &= ~(TEGRA20_SPDIF_CTRL_TX_EN | | ||
228 | TEGRA20_SPDIF_CTRL_TC_EN); | ||
229 | tegra20_spdif_write(spdif, TEGRA20_SPDIF_CTRL, spdif->reg_ctrl); | ||
230 | } | ||
231 | |||
232 | static int tegra20_spdif_trigger(struct snd_pcm_substream *substream, int cmd, | ||
233 | struct snd_soc_dai *dai) | ||
234 | { | ||
235 | struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai); | ||
236 | |||
237 | switch (cmd) { | ||
238 | case SNDRV_PCM_TRIGGER_START: | ||
239 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
240 | case SNDRV_PCM_TRIGGER_RESUME: | ||
241 | clk_enable(spdif->clk_spdif_out); | ||
242 | tegra20_spdif_start_playback(spdif); | ||
243 | break; | ||
244 | case SNDRV_PCM_TRIGGER_STOP: | ||
245 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
246 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
247 | tegra20_spdif_stop_playback(spdif); | ||
248 | clk_disable(spdif->clk_spdif_out); | ||
249 | break; | ||
250 | default: | ||
251 | return -EINVAL; | ||
252 | } | ||
253 | |||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | static int tegra20_spdif_probe(struct snd_soc_dai *dai) | ||
258 | { | ||
259 | struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai); | ||
260 | #ifdef CONFIG_PM | ||
261 | int i, reg; | ||
262 | #endif | ||
263 | |||
264 | dai->capture_dma_data = NULL; | ||
265 | dai->playback_dma_data = &spdif->playback_dma_data; | ||
266 | |||
267 | #ifdef CONFIG_PM | ||
268 | clk_enable(spdif->clk_spdif_out); | ||
269 | |||
270 | /* populate the spdif reg cache with POR values*/ | ||
271 | for (i = 0; i < TEGRA20_SPDIF_CTRL_CACHE_SIZE; i++) | ||
272 | spdif->reg_ctrl_cache[i] = tegra20_spdif_read(spdif, i << 2); | ||
273 | |||
274 | for (i = 0; i < TEGRA20_SPDIF_TX_CACHE_SIZE; i++) { | ||
275 | reg = (TEGRA20_SPDIF_CH_STA_TX_A) + (i << 2); | ||
276 | spdif->reg_tx_cache[i] = tegra20_spdif_read(spdif, reg); | ||
277 | } | ||
278 | |||
279 | clk_disable(spdif->clk_spdif_out); | ||
280 | |||
281 | #endif | ||
282 | |||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | #ifdef CONFIG_PM | ||
287 | int tegra20_spdif_resume(struct snd_soc_dai *cpu_dai) | ||
288 | { | ||
289 | struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(cpu_dai); | ||
290 | int i, reg; | ||
291 | |||
292 | clk_enable(spdif->clk_spdif_out); | ||
293 | |||
294 | /*restore the spdif regs*/ | ||
295 | for (i = 0; i < TEGRA20_SPDIF_CTRL_CACHE_SIZE; i++) | ||
296 | tegra20_spdif_write(spdif, i << 2, spdif->reg_ctrl_cache[i]); | ||
297 | |||
298 | for (i = 0; i < TEGRA20_SPDIF_TX_CACHE_SIZE; i++) { | ||
299 | reg = (TEGRA20_SPDIF_CH_STA_TX_A) + (i << 2); | ||
300 | tegra20_spdif_write(spdif, reg, spdif->reg_tx_cache[i]); | ||
301 | } | ||
302 | |||
303 | clk_disable(spdif->clk_spdif_out); | ||
304 | |||
305 | return 0; | ||
306 | } | ||
307 | #else | ||
308 | #define tegra20_spdif_resume NULL | ||
309 | #endif | ||
310 | |||
311 | static struct snd_soc_dai_ops tegra20_spdif_dai_ops = { | ||
312 | .hw_params = tegra20_spdif_hw_params, | ||
313 | .trigger = tegra20_spdif_trigger, | ||
314 | }; | ||
315 | |||
316 | struct snd_soc_dai_driver tegra20_spdif_dai = { | ||
317 | .name = DRV_NAME, | ||
318 | .probe = tegra20_spdif_probe, | ||
319 | .resume = tegra20_spdif_resume, | ||
320 | .playback = { | ||
321 | .channels_min = 2, | ||
322 | .channels_max = 2, | ||
323 | .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | | ||
324 | SNDRV_PCM_RATE_48000, | ||
325 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
326 | }, | ||
327 | .ops = &tegra20_spdif_dai_ops, | ||
328 | }; | ||
329 | |||
330 | static __devinit int tegra20_spdif_platform_probe(struct platform_device *pdev) | ||
331 | { | ||
332 | struct tegra20_spdif *spdif; | ||
333 | struct resource *mem, *memregion, *dmareq; | ||
334 | int ret; | ||
335 | u32 reg_val; | ||
336 | |||
337 | spdif = kzalloc(sizeof(struct tegra20_spdif), GFP_KERNEL); | ||
338 | if (!spdif) { | ||
339 | dev_err(&pdev->dev, "Can't allocate tegra20_spdif\n"); | ||
340 | ret = -ENOMEM; | ||
341 | goto exit; | ||
342 | } | ||
343 | dev_set_drvdata(&pdev->dev, spdif); | ||
344 | |||
345 | spdif->clk_spdif_out = clk_get(&pdev->dev, "spdif_out"); | ||
346 | if (IS_ERR(spdif->clk_spdif_out)) { | ||
347 | pr_err("Can't retrieve spdif clock\n"); | ||
348 | ret = PTR_ERR(spdif->clk_spdif_out); | ||
349 | goto err_free; | ||
350 | } | ||
351 | |||
352 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
353 | if (!mem) { | ||
354 | dev_err(&pdev->dev, "No memory resource\n"); | ||
355 | ret = -ENODEV; | ||
356 | goto err_clk_put; | ||
357 | } | ||
358 | |||
359 | dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0); | ||
360 | if (!dmareq) { | ||
361 | dev_err(&pdev->dev, "No DMA resource\n"); | ||
362 | ret = -ENODEV; | ||
363 | goto err_clk_put; | ||
364 | } | ||
365 | |||
366 | memregion = request_mem_region(mem->start, resource_size(mem), | ||
367 | DRV_NAME); | ||
368 | if (!memregion) { | ||
369 | dev_err(&pdev->dev, "Memory region already claimed\n"); | ||
370 | ret = -EBUSY; | ||
371 | goto err_clk_put; | ||
372 | } | ||
373 | |||
374 | spdif->regs = ioremap(mem->start, resource_size(mem)); | ||
375 | if (!spdif->regs) { | ||
376 | dev_err(&pdev->dev, "ioremap failed\n"); | ||
377 | ret = -ENOMEM; | ||
378 | goto err_release; | ||
379 | } | ||
380 | |||
381 | spdif->playback_dma_data.addr = mem->start + TEGRA20_SPDIF_DATA_OUT; | ||
382 | spdif->playback_dma_data.wrap = 4; | ||
383 | spdif->playback_dma_data.width = 32; | ||
384 | spdif->playback_dma_data.req_sel = dmareq->start; | ||
385 | |||
386 | clk_enable(spdif->clk_spdif_out); | ||
387 | |||
388 | reg_val = tegra20_spdif_read(spdif, TEGRA20_SPDIF_DATA_FIFO_CSR); | ||
389 | reg_val &= ~TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_MASK; | ||
390 | reg_val |= TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU4_WORD_FULL; | ||
391 | tegra20_spdif_write(spdif, TEGRA20_SPDIF_DATA_FIFO_CSR, reg_val); | ||
392 | |||
393 | clk_disable(spdif->clk_spdif_out); | ||
394 | |||
395 | ret = snd_soc_register_dai(&pdev->dev, &tegra20_spdif_dai); | ||
396 | if (ret) { | ||
397 | dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); | ||
398 | ret = -ENOMEM; | ||
399 | goto err_unmap; | ||
400 | } | ||
401 | |||
402 | tegra20_spdif_debug_add(spdif); | ||
403 | |||
404 | return 0; | ||
405 | |||
406 | err_unmap: | ||
407 | iounmap(spdif->regs); | ||
408 | err_release: | ||
409 | release_mem_region(mem->start, resource_size(mem)); | ||
410 | err_clk_put: | ||
411 | clk_put(spdif->clk_spdif_out); | ||
412 | err_free: | ||
413 | kfree(spdif); | ||
414 | exit: | ||
415 | return ret; | ||
416 | } | ||
417 | |||
418 | static int __devexit tegra20_spdif_platform_remove(struct platform_device *pdev) | ||
419 | { | ||
420 | struct tegra20_spdif *spdif = dev_get_drvdata(&pdev->dev); | ||
421 | struct resource *res; | ||
422 | |||
423 | snd_soc_unregister_dai(&pdev->dev); | ||
424 | |||
425 | tegra20_spdif_debug_remove(spdif); | ||
426 | |||
427 | iounmap(spdif->regs); | ||
428 | |||
429 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
430 | release_mem_region(res->start, resource_size(res)); | ||
431 | |||
432 | clk_put(spdif->clk_spdif_out); | ||
433 | |||
434 | kfree(spdif); | ||
435 | |||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | static struct platform_driver tegra20_spdif_driver = { | ||
440 | .driver = { | ||
441 | .name = DRV_NAME, | ||
442 | .owner = THIS_MODULE, | ||
443 | }, | ||
444 | .probe = tegra20_spdif_platform_probe, | ||
445 | .remove = __devexit_p(tegra20_spdif_platform_remove), | ||
446 | }; | ||
447 | |||
448 | static int __init snd_tegra20_spdif_init(void) | ||
449 | { | ||
450 | return platform_driver_register(&tegra20_spdif_driver); | ||
451 | } | ||
452 | module_init(snd_tegra20_spdif_init); | ||
453 | |||
454 | static void __exit snd_tegra20_spdif_exit(void) | ||
455 | { | ||
456 | platform_driver_unregister(&tegra20_spdif_driver); | ||
457 | } | ||
458 | module_exit(snd_tegra20_spdif_exit); | ||
459 | |||
460 | MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); | ||
461 | MODULE_DESCRIPTION("Tegra SPDIF ASoC driver"); | ||
462 | MODULE_LICENSE("GPL"); | ||
463 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/sound/soc/tegra/tegra20_spdif.h b/sound/soc/tegra/tegra20_spdif.h new file mode 100644 index 00000000000..c1fb6ed2a79 --- /dev/null +++ b/sound/soc/tegra/tegra20_spdif.h | |||
@@ -0,0 +1,556 @@ | |||
1 | /* | ||
2 | * tegra20_spdif.h - Definitions for Tegra20 SPDIF driver | ||
3 | * | ||
4 | * Author: Stephen Warren <swarren@nvidia.com> | ||
5 | * Copyright (C) 2011 - NVIDIA, Inc. | ||
6 | * | ||
7 | * Based on code copyright/by: | ||
8 | * Copyright (c) 2008-2009, NVIDIA Corporation | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License | ||
12 | * version 2 as published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
22 | * 02110-1301 USA | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #ifndef __TEGRA20_SPDIF_H__ | ||
27 | #define __TEGRA20_SPDIF_H__ | ||
28 | |||
29 | #include "tegra_pcm.h" | ||
30 | |||
31 | /* Offsets from TEGRA_SPDIF_BASE */ | ||
32 | |||
33 | #define TEGRA20_SPDIF_CTRL 0x0 | ||
34 | #define TEGRA20_SPDIF_STATUS 0x4 | ||
35 | #define TEGRA20_SPDIF_STROBE_CTRL 0x8 | ||
36 | #define TEGRA20_SPDIF_DATA_FIFO_CSR 0x0C | ||
37 | #define TEGRA20_SPDIF_DATA_OUT 0x40 | ||
38 | #define TEGRA20_SPDIF_DATA_IN 0x80 | ||
39 | #define TEGRA20_SPDIF_CH_STA_RX_A 0x100 | ||
40 | #define TEGRA20_SPDIF_CH_STA_RX_B 0x104 | ||
41 | #define TEGRA20_SPDIF_CH_STA_RX_C 0x108 | ||
42 | #define TEGRA20_SPDIF_CH_STA_RX_D 0x10C | ||
43 | #define TEGRA20_SPDIF_CH_STA_RX_E 0x110 | ||
44 | #define TEGRA20_SPDIF_CH_STA_RX_F 0x114 | ||
45 | #define TEGRA20_SPDIF_CH_STA_TX_A 0x140 | ||
46 | #define TEGRA20_SPDIF_CH_STA_TX_B 0x144 | ||
47 | #define TEGRA20_SPDIF_CH_STA_TX_C 0x148 | ||
48 | #define TEGRA20_SPDIF_CH_STA_TX_D 0x14C | ||
49 | #define TEGRA20_SPDIF_CH_STA_TX_E 0x150 | ||
50 | #define TEGRA20_SPDIF_CH_STA_TX_F 0x154 | ||
51 | #define TEGRA20_SPDIF_USR_STA_RX_A 0x180 | ||
52 | #define TEGRA20_SPDIF_USR_DAT_TX_A 0x1C0 | ||
53 | |||
54 | /* Fields in TEGRA20_SPDIF_CTRL */ | ||
55 | |||
56 | /* Start capturing from 0=right, 1=left channel */ | ||
57 | #define TEGRA20_SPDIF_CTRL_CAP_LC (1 << 30) | ||
58 | |||
59 | /* SPDIF receiver(RX) enable */ | ||
60 | #define TEGRA20_SPDIF_CTRL_RX_EN (1 << 29) | ||
61 | |||
62 | /* SPDIF Transmitter(TX) enable */ | ||
63 | #define TEGRA20_SPDIF_CTRL_TX_EN (1 << 28) | ||
64 | |||
65 | /* Transmit Channel status */ | ||
66 | #define TEGRA20_SPDIF_CTRL_TC_EN (1 << 27) | ||
67 | |||
68 | /* Transmit user Data */ | ||
69 | #define TEGRA20_SPDIF_CTRL_TU_EN (1 << 26) | ||
70 | |||
71 | /* Interrupt on transmit error */ | ||
72 | #define TEGRA20_SPDIF_CTRL_IE_TXE (1 << 25) | ||
73 | |||
74 | /* Interrupt on receive error */ | ||
75 | #define TEGRA20_SPDIF_CTRL_IE_RXE (1 << 24) | ||
76 | |||
77 | /* Interrupt on invalid preamble */ | ||
78 | #define TEGRA20_SPDIF_CTRL_IE_P (1 << 23) | ||
79 | |||
80 | /* Interrupt on "B" preamble */ | ||
81 | #define TEGRA20_SPDIF_CTRL_IE_B (1 << 22) | ||
82 | |||
83 | /* Interrupt when block of channel status received */ | ||
84 | #define TEGRA20_SPDIF_CTRL_IE_C (1 << 21) | ||
85 | |||
86 | /* Interrupt when a valid information unit (IU) is received */ | ||
87 | #define TEGRA20_SPDIF_CTRL_IE_U (1 << 20) | ||
88 | |||
89 | /* Interrupt when RX user FIFO attention level is reached */ | ||
90 | #define TEGRA20_SPDIF_CTRL_QE_RU (1 << 19) | ||
91 | |||
92 | /* Interrupt when TX user FIFO attention level is reached */ | ||
93 | #define TEGRA20_SPDIF_CTRL_QE_TU (1 << 18) | ||
94 | |||
95 | /* Interrupt when RX data FIFO attention level is reached */ | ||
96 | #define TEGRA20_SPDIF_CTRL_QE_RX (1 << 17) | ||
97 | |||
98 | /* Interrupt when TX data FIFO attention level is reached */ | ||
99 | #define TEGRA20_SPDIF_CTRL_QE_TX (1 << 16) | ||
100 | |||
101 | /* Loopback test mode enable */ | ||
102 | #define TEGRA20_SPDIF_CTRL_LBK_EN (1 << 15) | ||
103 | |||
104 | /* | ||
105 | * Pack data mode: | ||
106 | * 0 = Single data (16 bit needs to be padded to match the | ||
107 | * interface data bit size). | ||
108 | * 1 = Packeted left/right channel data into a single word. | ||
109 | */ | ||
110 | #define TEGRA20_SPDIF_CTRL_PACK (1 << 14) | ||
111 | |||
112 | /* | ||
113 | * 00 = 16bit data | ||
114 | * 01 = 20bit data | ||
115 | * 10 = 24bit data | ||
116 | * 11 = raw data | ||
117 | */ | ||
118 | #define TEGRA20_SPDIF_BIT_MODE_16BIT 0 | ||
119 | #define TEGRA20_SPDIF_BIT_MODE_20BIT 1 | ||
120 | #define TEGRA20_SPDIF_BIT_MODE_24BIT 2 | ||
121 | #define TEGRA20_SPDIF_BIT_MODE_RAW 3 | ||
122 | |||
123 | #define TEGRA20_SPDIF_CTRL_BIT_MODE_SHIFT 12 | ||
124 | #define TEGRA20_SPDIF_CTRL_BIT_MODE_MASK (3 << TEGRA20_SPDIF_CTRL_BIT_MODE_SHIFT) | ||
125 | #define TEGRA20_SPDIF_CTRL_BIT_MODE_16BIT (TEGRA20_SPDIF_BIT_MODE_16BIT << TEGRA20_SPDIF_CTRL_BIT_MODE_SHIFT) | ||
126 | #define TEGRA20_SPDIF_CTRL_BIT_MODE_20BIT (TEGRA20_SPDIF_BIT_MODE_20BIT << TEGRA20_SPDIF_CTRL_BIT_MODE_SHIFT) | ||
127 | #define TEGRA20_SPDIF_CTRL_BIT_MODE_24BIT (TEGRA20_SPDIF_BIT_MODE_24BIT << TEGRA20_SPDIF_CTRL_BIT_MODE_SHIFT) | ||
128 | #define TEGRA20_SPDIF_CTRL_BIT_MODE_RAW (TEGRA20_SPDIF_BIT_MODE_RAW << TEGRA20_SPDIF_CTRL_BIT_MODE_SHIFT) | ||
129 | |||
130 | /* Fields in TEGRA20_SPDIF_STATUS */ | ||
131 | |||
132 | /* | ||
133 | * Note: IS_P, IS_B, IS_C, and IS_U are sticky bits. Software must | ||
134 | * write a 1 to the corresponding bit location to clear the status. | ||
135 | */ | ||
136 | |||
137 | /* | ||
138 | * Receiver(RX) shifter is busy receiving data. | ||
139 | * This bit is asserted when the receiver first locked onto the | ||
140 | * preamble of the data stream after RX_EN is asserted. This bit is | ||
141 | * deasserted when either, | ||
142 | * (a) the end of a frame is reached after RX_EN is deeasserted, or | ||
143 | * (b) the SPDIF data stream becomes inactive. | ||
144 | */ | ||
145 | #define TEGRA20_SPDIF_STATUS_RX_BSY (1 << 29) | ||
146 | |||
147 | /* | ||
148 | * Transmitter(TX) shifter is busy transmitting data. | ||
149 | * This bit is asserted when TX_EN is asserted. | ||
150 | * This bit is deasserted when the end of a frame is reached after | ||
151 | * TX_EN is deasserted. | ||
152 | */ | ||
153 | #define TEGRA20_SPDIF_STATUS_TX_BSY (1 << 28) | ||
154 | |||
155 | /* | ||
156 | * TX is busy shifting out channel status. | ||
157 | * This bit is asserted when both TX_EN and TC_EN are asserted and | ||
158 | * data from CH_STA_TX_A register is loaded into the internal shifter. | ||
159 | * This bit is deasserted when either, | ||
160 | * (a) the end of a frame is reached after TX_EN is deasserted, or | ||
161 | * (b) CH_STA_TX_F register is loaded into the internal shifter. | ||
162 | */ | ||
163 | #define TEGRA20_SPDIF_STATUS_TC_BSY (1 << 27) | ||
164 | |||
165 | /* | ||
166 | * TX User data FIFO busy. | ||
167 | * This bit is asserted when TX_EN and TXU_EN are asserted and | ||
168 | * there's data in the TX user FIFO. This bit is deassert when either, | ||
169 | * (a) the end of a frame is reached after TX_EN is deasserted, or | ||
170 | * (b) there's no data left in the TX user FIFO. | ||
171 | */ | ||
172 | #define TEGRA20_SPDIF_STATUS_TU_BSY (1 << 26) | ||
173 | |||
174 | /* TX FIFO Underrun error status */ | ||
175 | #define TEGRA20_SPDIF_STATUS_TX_ERR (1 << 25) | ||
176 | |||
177 | /* RX FIFO Overrun error status */ | ||
178 | #define TEGRA20_SPDIF_STATUS_RX_ERR (1 << 24) | ||
179 | |||
180 | /* Preamble status: 0=Preamble OK, 1=bad/missing preamble */ | ||
181 | #define TEGRA20_SPDIF_STATUS_IS_P (1 << 23) | ||
182 | |||
183 | /* B-preamble detection status: 0=not detected, 1=B-preamble detected */ | ||
184 | #define TEGRA20_SPDIF_STATUS_IS_B (1 << 22) | ||
185 | |||
186 | /* | ||
187 | * RX channel block data receive status: | ||
188 | * 0=entire block not recieved yet. | ||
189 | * 1=received entire block of channel status, | ||
190 | */ | ||
191 | #define TEGRA20_SPDIF_STATUS_IS_C (1 << 21) | ||
192 | |||
193 | /* RX User Data Valid flag: 1=valid IU detected, 0 = no IU detected. */ | ||
194 | #define TEGRA20_SPDIF_STATUS_IS_U (1 << 20) | ||
195 | |||
196 | /* | ||
197 | * RX User FIFO Status: | ||
198 | * 1=attention level reached, 0=attention level not reached. | ||
199 | */ | ||
200 | #define TEGRA20_SPDIF_STATUS_QS_RU (1 << 19) | ||
201 | |||
202 | /* | ||
203 | * TX User FIFO Status: | ||
204 | * 1=attention level reached, 0=attention level not reached. | ||
205 | */ | ||
206 | #define TEGRA20_SPDIF_STATUS_QS_TU (1 << 18) | ||
207 | |||
208 | /* | ||
209 | * RX Data FIFO Status: | ||
210 | * 1=attention level reached, 0=attention level not reached. | ||
211 | */ | ||
212 | #define TEGRA20_SPDIF_STATUS_QS_RX (1 << 17) | ||
213 | |||
214 | /* | ||
215 | * TX Data FIFO Status: | ||
216 | * 1=attention level reached, 0=attention level not reached. | ||
217 | */ | ||
218 | #define TEGRA20_SPDIF_STATUS_QS_TX (1 << 16) | ||
219 | |||
220 | /* Fields in TEGRA20_SPDIF_STROBE_CTRL */ | ||
221 | |||
222 | /* | ||
223 | * Indicates the approximate number of detected SPDIFIN clocks within a | ||
224 | * bi-phase period. | ||
225 | */ | ||
226 | #define TEGRA20_SPDIF_STROBE_CTRL_PERIOD_SHIFT 16 | ||
227 | #define TEGRA20_SPDIF_STROBE_CTRL_PERIOD_MASK (0xff << TEGRA20_SPDIF_STROBE_CTRL_PERIOD_SHIFT) | ||
228 | |||
229 | /* Data strobe mode: 0=Auto-locked 1=Manual locked */ | ||
230 | #define TEGRA20_SPDIF_STROBE_CTRL_STROBE (1 << 15) | ||
231 | |||
232 | /* | ||
233 | * Manual data strobe time within the bi-phase clock period (in terms of | ||
234 | * the number of over-sampling clocks). | ||
235 | */ | ||
236 | #define TEGRA20_SPDIF_STROBE_CTRL_DATA_STROBES_SHIFT 8 | ||
237 | #define TEGRA20_SPDIF_STROBE_CTRL_DATA_STROBES_MASK (0x1f << TEGRA20_SPDIF_STROBE_CTRL_DATA_STROBES_SHIFT) | ||
238 | |||
239 | /* | ||
240 | * Manual SPDIFIN bi-phase clock period (in terms of the number of | ||
241 | * over-sampling clocks). | ||
242 | */ | ||
243 | #define TEGRA20_SPDIF_STROBE_CTRL_CLOCK_PERIOD_SHIFT 0 | ||
244 | #define TEGRA20_SPDIF_STROBE_CTRL_CLOCK_PERIOD_MASK (0x3f << TEGRA20_SPDIF_STROBE_CTRL_CLOCK_PERIOD_SHIFT) | ||
245 | |||
246 | /* Fields in SPDIF_DATA_FIFO_CSR */ | ||
247 | |||
248 | /* Clear Receiver User FIFO (RX USR.FIFO) */ | ||
249 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_CLR (1 << 31) | ||
250 | |||
251 | #define TEGRA20_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT 0 | ||
252 | #define TEGRA20_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS 1 | ||
253 | #define TEGRA20_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS 2 | ||
254 | #define TEGRA20_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS 3 | ||
255 | |||
256 | /* RU FIFO attention level */ | ||
257 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT 29 | ||
258 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_MASK \ | ||
259 | (0x3 << TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT) | ||
260 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU1_WORD_FULL \ | ||
261 | (TEGRA20_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT << TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT) | ||
262 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU2_WORD_FULL \ | ||
263 | (TEGRA20_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT) | ||
264 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU3_WORD_FULL \ | ||
265 | (TEGRA20_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT) | ||
266 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU4_WORD_FULL \ | ||
267 | (TEGRA20_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT) | ||
268 | |||
269 | /* Number of RX USR.FIFO levels with valid data. */ | ||
270 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_SHIFT 24 | ||
271 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_MASK (0x1f << TEGRA20_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_SHIFT) | ||
272 | |||
273 | /* Clear Transmitter User FIFO (TX USR.FIFO) */ | ||
274 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_CLR (1 << 23) | ||
275 | |||
276 | /* TU FIFO attention level */ | ||
277 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT 21 | ||
278 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_MASK \ | ||
279 | (0x3 << TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT) | ||
280 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU1_WORD_FULL \ | ||
281 | (TEGRA20_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT << TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT) | ||
282 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU2_WORD_FULL \ | ||
283 | (TEGRA20_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT) | ||
284 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU3_WORD_FULL \ | ||
285 | (TEGRA20_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT) | ||
286 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU4_WORD_FULL \ | ||
287 | (TEGRA20_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT) | ||
288 | |||
289 | /* Number of TX USR.FIFO levels that could be filled. */ | ||
290 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_SHIFT 16 | ||
291 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_MASK (0x1f << SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_SHIFT) | ||
292 | |||
293 | /* Clear Receiver Data FIFO (RX DATA.FIFO) */ | ||
294 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_CLR (1 << 15) | ||
295 | |||
296 | #define TEGRA20_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT 0 | ||
297 | #define TEGRA20_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS 1 | ||
298 | #define TEGRA20_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS 2 | ||
299 | #define TEGRA20_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOT 3 | ||
300 | |||
301 | /* RU FIFO attention level */ | ||
302 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT 13 | ||
303 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_MASK \ | ||
304 | (0x3 << TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT) | ||
305 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU1_WORD_FULL \ | ||
306 | (TEGRA20_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT << TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT) | ||
307 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU4_WORD_FULL \ | ||
308 | (TEGRA20_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT) | ||
309 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU8_WORD_FULL \ | ||
310 | (TEGRA20_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT) | ||
311 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU12_WORD_FULL \ | ||
312 | (TEGRA20_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT) | ||
313 | |||
314 | /* Number of RX DATA.FIFO levels with valid data. */ | ||
315 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_SHIFT 8 | ||
316 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_MASK (0x1f << TEGRA20_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_SHIFT) | ||
317 | |||
318 | /* Clear Transmitter Data FIFO (TX DATA.FIFO) */ | ||
319 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_CLR (1 << 7) | ||
320 | |||
321 | /* TU FIFO attention level */ | ||
322 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT 5 | ||
323 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_MASK \ | ||
324 | (0x3 << TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT) | ||
325 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU1_WORD_FULL \ | ||
326 | (TEGRA20_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT << TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT) | ||
327 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU4_WORD_FULL \ | ||
328 | (TEGRA20_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT) | ||
329 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU8_WORD_FULL \ | ||
330 | (TEGRA20_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT) | ||
331 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU12_WORD_FULL \ | ||
332 | (TEGRA20_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT) | ||
333 | |||
334 | /* Number of TX DATA.FIFO levels that could be filled. */ | ||
335 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_SHIFT 0 | ||
336 | #define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_MASK (0x1f << SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_SHIFT) | ||
337 | |||
338 | /* Fields in TEGRA20_SPDIF_DATA_OUT */ | ||
339 | |||
340 | /* | ||
341 | * This register has 5 different formats: | ||
342 | * 16-bit (BIT_MODE=00, PACK=0) | ||
343 | * 20-bit (BIT_MODE=01, PACK=0) | ||
344 | * 24-bit (BIT_MODE=10, PACK=0) | ||
345 | * raw (BIT_MODE=11, PACK=0) | ||
346 | * 16-bit packed (BIT_MODE=00, PACK=1) | ||
347 | */ | ||
348 | |||
349 | #define TEGRA20_SPDIF_DATA_OUT_DATA_16_SHIFT 0 | ||
350 | #define TEGRA20_SPDIF_DATA_OUT_DATA_16_MASK (0xffff << TEGRA20_SPDIF_DATA_OUT_DATA_16_SHIFT) | ||
351 | |||
352 | #define TEGRA20_SPDIF_DATA_OUT_DATA_20_SHIFT 0 | ||
353 | #define TEGRA20_SPDIF_DATA_OUT_DATA_20_MASK (0xfffff << TEGRA20_SPDIF_DATA_OUT_DATA_20_SHIFT) | ||
354 | |||
355 | #define TEGRA20_SPDIF_DATA_OUT_DATA_24_SHIFT 0 | ||
356 | #define TEGRA20_SPDIF_DATA_OUT_DATA_24_MASK (0xffffff << TEGRA20_SPDIF_DATA_OUT_DATA_24_SHIFT) | ||
357 | |||
358 | #define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_P (1 << 31) | ||
359 | #define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_C (1 << 30) | ||
360 | #define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_U (1 << 29) | ||
361 | #define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_V (1 << 28) | ||
362 | |||
363 | #define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_DATA_SHIFT 8 | ||
364 | #define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_DATA_MASK (0xfffff << TEGRA20_SPDIF_DATA_OUT_DATA_RAW_DATA_SHIFT) | ||
365 | |||
366 | #define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_AUX_SHIFT 4 | ||
367 | #define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_AUX_MASK (0xf << TEGRA20_SPDIF_DATA_OUT_DATA_RAW_AUX_SHIFT) | ||
368 | |||
369 | #define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_SHIFT 0 | ||
370 | #define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_MASK (0xf << TEGRA20_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_SHIFT) | ||
371 | |||
372 | #define TEGRA20_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_SHIFT 16 | ||
373 | #define TEGRA20_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_MASK (0xffff << TEGRA20_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_SHIFT) | ||
374 | |||
375 | #define TEGRA20_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_SHIFT 0 | ||
376 | #define TEGRA20_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_MASK (0xffff << TEGRA20_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_SHIFT) | ||
377 | |||
378 | /* Fields in TEGRA20_SPDIF_DATA_IN */ | ||
379 | |||
380 | /* | ||
381 | * This register has 5 different formats: | ||
382 | * 16-bit (BIT_MODE=00, PACK=0) | ||
383 | * 20-bit (BIT_MODE=01, PACK=0) | ||
384 | * 24-bit (BIT_MODE=10, PACK=0) | ||
385 | * raw (BIT_MODE=11, PACK=0) | ||
386 | * 16-bit packed (BIT_MODE=00, PACK=1) | ||
387 | * | ||
388 | * Bits 31:24 are common to all modes except 16-bit packed | ||
389 | */ | ||
390 | |||
391 | #define TEGRA20_SPDIF_DATA_IN_DATA_P (1 << 31) | ||
392 | #define TEGRA20_SPDIF_DATA_IN_DATA_C (1 << 30) | ||
393 | #define TEGRA20_SPDIF_DATA_IN_DATA_U (1 << 29) | ||
394 | #define TEGRA20_SPDIF_DATA_IN_DATA_V (1 << 28) | ||
395 | |||
396 | #define TEGRA20_SPDIF_DATA_IN_DATA_PREAMBLE_SHIFT 24 | ||
397 | #define TEGRA20_SPDIF_DATA_IN_DATA_PREAMBLE_MASK (0xf << TEGRA20_SPDIF_DATA_IN_DATA_PREAMBLE_SHIFT) | ||
398 | |||
399 | #define TEGRA20_SPDIF_DATA_IN_DATA_16_SHIFT 0 | ||
400 | #define TEGRA20_SPDIF_DATA_IN_DATA_16_MASK (0xffff << TEGRA20_SPDIF_DATA_IN_DATA_16_SHIFT) | ||
401 | |||
402 | #define TEGRA20_SPDIF_DATA_IN_DATA_20_SHIFT 0 | ||
403 | #define TEGRA20_SPDIF_DATA_IN_DATA_20_MASK (0xfffff << TEGRA20_SPDIF_DATA_IN_DATA_20_SHIFT) | ||
404 | |||
405 | #define TEGRA20_SPDIF_DATA_IN_DATA_24_SHIFT 0 | ||
406 | #define TEGRA20_SPDIF_DATA_IN_DATA_24_MASK (0xffffff << TEGRA20_SPDIF_DATA_IN_DATA_24_SHIFT) | ||
407 | |||
408 | #define TEGRA20_SPDIF_DATA_IN_DATA_RAW_DATA_SHIFT 8 | ||
409 | #define TEGRA20_SPDIF_DATA_IN_DATA_RAW_DATA_MASK (0xfffff << TEGRA20_SPDIF_DATA_IN_DATA_RAW_DATA_SHIFT) | ||
410 | |||
411 | #define TEGRA20_SPDIF_DATA_IN_DATA_RAW_AUX_SHIFT 4 | ||
412 | #define TEGRA20_SPDIF_DATA_IN_DATA_RAW_AUX_MASK (0xf << TEGRA20_SPDIF_DATA_IN_DATA_RAW_AUX_SHIFT) | ||
413 | |||
414 | #define TEGRA20_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_SHIFT 0 | ||
415 | #define TEGRA20_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_MASK (0xf << TEGRA20_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_SHIFT) | ||
416 | |||
417 | #define TEGRA20_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_SHIFT 16 | ||
418 | #define TEGRA20_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_MASK (0xffff << TEGRA20_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_SHIFT) | ||
419 | |||
420 | #define TEGRA20_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_SHIFT 0 | ||
421 | #define TEGRA20_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_MASK (0xffff << TEGRA20_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_SHIFT) | ||
422 | |||
423 | /* Fields in TEGRA20_SPDIF_CH_STA_RX_A */ | ||
424 | /* Fields in TEGRA20_SPDIF_CH_STA_RX_B */ | ||
425 | /* Fields in TEGRA20_SPDIF_CH_STA_RX_C */ | ||
426 | /* Fields in TEGRA20_SPDIF_CH_STA_RX_D */ | ||
427 | /* Fields in TEGRA20_SPDIF_CH_STA_RX_E */ | ||
428 | /* Fields in TEGRA20_SPDIF_CH_STA_RX_F */ | ||
429 | |||
430 | /* | ||
431 | * The 6-word receive channel data page buffer holds a block (192 frames) of | ||
432 | * channel status information. The order of receive is from LSB to MSB | ||
433 | * bit, and from CH_STA_RX_A to CH_STA_RX_F then back to CH_STA_RX_A. | ||
434 | */ | ||
435 | |||
436 | /* Fields in TEGRA20_SPDIF_CH_STA_TX_A */ | ||
437 | #define TEGRA20_SPDIF_CH_STA_TX_A_SF_22050 0x4 | ||
438 | #define TEGRA20_SPDIF_CH_STA_TX_A_SF_24000 0x6 | ||
439 | #define TEGRA20_SPDIF_CH_STA_TX_A_SF_32000 0x3 | ||
440 | #define TEGRA20_SPDIF_CH_STA_TX_A_SF_44100 0x0 | ||
441 | #define TEGRA20_SPDIF_CH_STA_TX_A_SF_48000 0x2 | ||
442 | #define TEGRA20_SPDIF_CH_STA_TX_A_SF_88200 0x8 | ||
443 | #define TEGRA20_SPDIF_CH_STA_TX_A_SF_96000 0xA | ||
444 | #define TEGRA20_SPDIF_CH_STA_TX_A_SF_176400 0xC | ||
445 | #define TEGRA20_SPDIF_CH_STA_TX_A_SF_192000 0xE | ||
446 | |||
447 | #define TEGRA20_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT 24 | ||
448 | #define TEGRA20_SPDIF_CH_STA_TX_A_SAMP_FREQ_MASK \ | ||
449 | (0xF << TEGRA20_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT) | ||
450 | #define TEGRA20_SPDIF_CH_STA_TX_A_SAMP_FREQ_22050 \ | ||
451 | (TEGRA20_SPDIF_CH_STA_TX_A_SF_22050 << TEGRA20_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT) | ||
452 | #define TEGRA20_SPDIF_CH_STA_TX_A_SAMP_FREQ_24000 \ | ||
453 | (TEGRA20_SPDIF_CH_STA_TX_A_SF_24000 << TEGRA20_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT) | ||
454 | #define TEGRA20_SPDIF_CH_STA_TX_A_SAMP_FREQ_32000 \ | ||
455 | (TEGRA20_SPDIF_CH_STA_TX_A_SF_32000 << TEGRA20_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT) | ||
456 | #define TEGRA20_SPDIF_CH_STA_TX_A_SAMP_FREQ_44100 \ | ||
457 | (TEGRA20_SPDIF_CH_STA_TX_A_SF_44100 << TEGRA20_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT) | ||
458 | #define TEGRA20_SPDIF_CH_STA_TX_A_SAMP_FREQ_48000 \ | ||
459 | (TEGRA20_SPDIF_CH_STA_TX_A_SF_48000 << TEGRA20_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT) | ||
460 | #define TEGRA20_SPDIF_CH_STA_TX_A_SAMP_FREQ_88200 \ | ||
461 | (TEGRA20_SPDIF_CH_STA_TX_A_SF_88200 << TEGRA20_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT) | ||
462 | #define TEGRA20_SPDIF_CH_STA_TX_A_SAMP_FREQ_96000 \ | ||
463 | (TEGRA20_SPDIF_CH_STA_TX_A_SF_96000 << TEGRA20_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT) | ||
464 | #define TEGRA20_SPDIF_CH_STA_TX_A_SAMP_FREQ_176400 \ | ||
465 | (TEGRA20_SPDIF_CH_STA_TX_A_SF_176400 << TEGRA20_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT) | ||
466 | #define TEGRA20_SPDIF_CH_STA_TX_A_SAMP_FREQ_192000 \ | ||
467 | (TEGRA20_SPDIF_CH_STA_TX_A_SF_192000 << TEGRA20_SPDIF_CH_STA_TX_A_SAMP_FREQ_SHIFT) | ||
468 | |||
469 | /* Fields in TEGRA20_SPDIF_CH_STA_TX_B */ | ||
470 | #define TEGRA20_SPDIF_CH_STA_TX_B_SF_8000 0x6 | ||
471 | #define TEGRA20_SPDIF_CH_STA_TX_B_SF_11025 0xA | ||
472 | #define TEGRA20_SPDIF_CH_STA_TX_B_SF_12000 0x2 | ||
473 | #define TEGRA20_SPDIF_CH_STA_TX_B_SF_16000 0x8 | ||
474 | #define TEGRA20_SPDIF_CH_STA_TX_B_SF_22050 0xB | ||
475 | #define TEGRA20_SPDIF_CH_STA_TX_B_SF_24000 0x9 | ||
476 | #define TEGRA20_SPDIF_CH_STA_TX_B_SF_32000 0xC | ||
477 | #define TEGRA20_SPDIF_CH_STA_TX_B_SF_44100 0xF | ||
478 | #define TEGRA20_SPDIF_CH_STA_TX_B_SF_48000 0xD | ||
479 | #define TEGRA20_SPDIF_CH_STA_TX_B_SF_88200 0x7 | ||
480 | #define TEGRA20_SPDIF_CH_STA_TX_B_SF_96000 0x5 | ||
481 | #define TEGRA20_SPDIF_CH_STA_TX_B_SF_176400 0x3 | ||
482 | #define TEGRA20_SPDIF_CH_STA_TX_B_SF_192000 0x1 | ||
483 | |||
484 | #define TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT 4 | ||
485 | #define TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_MASK \ | ||
486 | (0xF << TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT) | ||
487 | #define TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_8000 \ | ||
488 | (TEGRA20_SPDIF_CH_STA_TX_B_SF_8000 << TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT) | ||
489 | #define TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_11025 \ | ||
490 | (TEGRA20_SPDIF_CH_STA_TX_B_SF_11025 << TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT) | ||
491 | #define TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_12000 \ | ||
492 | (TEGRA20_SPDIF_CH_STA_TX_B_SF_12000 << TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT) | ||
493 | #define TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_16000 \ | ||
494 | (TEGRA20_SPDIF_CH_STA_TX_B_SF_16000 << TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT) | ||
495 | #define TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_22050 \ | ||
496 | (TEGRA20_SPDIF_CH_STA_TX_B_SF_22025 << TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT) | ||
497 | #define TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_24000 \ | ||
498 | (TEGRA20_SPDIF_CH_STA_TX_B_SF_24000 << TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT) | ||
499 | #define TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_32000 \ | ||
500 | (TEGRA20_SPDIF_CH_STA_TX_B_SF_32000 << TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT) | ||
501 | #define TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_44100 \ | ||
502 | (TEGRA20_SPDIF_CH_STA_TX_B_SF_44100 << TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT) | ||
503 | #define TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_48000 \ | ||
504 | (TEGRA20_SPDIF_CH_STA_TX_B_SF_48000 << TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT) | ||
505 | #define TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_88200 \ | ||
506 | (TEGRA20_SPDIF_CH_STA_TX_B_SF_88200 << TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT) | ||
507 | #define TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_96000 \ | ||
508 | (TEGRA20_SPDIF_CH_STA_TX_B_SF_96000 << TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT) | ||
509 | #define TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_176400 \ | ||
510 | (TEGRA20_SPDIF_CH_STA_TX_B_SF_176400 << TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT) | ||
511 | #define TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_192000 \ | ||
512 | (TEGRA20_SPDIF_CH_STA_TX_B_SF_192000 << TEGRA20_SPDIF_CH_STA_TX_B_ORIG_SAMP_FREQ_SHIFT) | ||
513 | |||
514 | /* Fields in TEGRA20_SPDIF_CH_STA_TX_C */ | ||
515 | /* Fields in TEGRA20_SPDIF_CH_STA_TX_D */ | ||
516 | /* Fields in TEGRA20_SPDIF_CH_STA_TX_E */ | ||
517 | /* Fields in TEGRA20_SPDIF_CH_STA_TX_F */ | ||
518 | |||
519 | /* | ||
520 | * The 6-word transmit channel data page buffer holds a block (192 frames) of | ||
521 | * channel status information. The order of transmission is from LSB to MSB | ||
522 | * bit, and from CH_STA_TX_A to CH_STA_TX_F then back to CH_STA_TX_A. | ||
523 | */ | ||
524 | |||
525 | /* Fields in TEGRA20_SPDIF_USR_STA_RX_A */ | ||
526 | |||
527 | /* | ||
528 | * This 4-word deep FIFO receives user FIFO field information. The order of | ||
529 | * receive is from LSB to MSB bit. | ||
530 | */ | ||
531 | |||
532 | /* Fields in TEGRA20_SPDIF_USR_DAT_TX_A */ | ||
533 | |||
534 | /* | ||
535 | * This 4-word deep FIFO transmits user FIFO field information. The order of | ||
536 | * transmission is from LSB to MSB bit. | ||
537 | */ | ||
538 | #ifdef CONFIG_PM | ||
539 | #define TEGRA20_SPDIF_CTRL_CACHE_SIZE ((TEGRA20_SPDIF_DATA_FIFO_CSR >> 2) + 1) | ||
540 | #define TEGRA20_SPDIF_TX_CACHE_SIZE (((TEGRA20_SPDIF_CH_STA_TX_F - TEGRA20_SPDIF_CH_STA_TX_A) >> 2) + 1) | ||
541 | #endif | ||
542 | |||
543 | struct tegra20_spdif { | ||
544 | struct clk *clk_spdif_out; | ||
545 | struct tegra_pcm_dma_params capture_dma_data; | ||
546 | struct tegra_pcm_dma_params playback_dma_data; | ||
547 | void __iomem *regs; | ||
548 | struct dentry *debug; | ||
549 | u32 reg_ctrl; | ||
550 | #ifdef CONFIG_PM | ||
551 | u32 reg_ctrl_cache[TEGRA20_SPDIF_CTRL_CACHE_SIZE]; | ||
552 | u32 reg_tx_cache[TEGRA20_SPDIF_TX_CACHE_SIZE]; | ||
553 | #endif | ||
554 | }; | ||
555 | |||
556 | #endif | ||
diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c new file mode 100644 index 00000000000..710d9465b4b --- /dev/null +++ b/sound/soc/tegra/tegra30_ahub.c | |||
@@ -0,0 +1,665 @@ | |||
1 | /* | ||
2 | * tegra30_ahub.c - Tegra 30 AHUB driver | ||
3 | * | ||
4 | * Author: Stephen Warren <swarren@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 <mach/dma.h> | ||
32 | #include <mach/iomap.h> | ||
33 | #include <sound/soc.h> | ||
34 | #include "tegra30_ahub.h" | ||
35 | |||
36 | #define DRV_NAME "tegra30-ahub" | ||
37 | |||
38 | static struct tegra30_ahub *ahub; | ||
39 | |||
40 | static inline void tegra30_apbif_write(u32 reg, u32 val) | ||
41 | { | ||
42 | #ifdef CONFIG_PM | ||
43 | ahub->apbif_reg_cache[reg >> 2] = val; | ||
44 | #endif | ||
45 | __raw_writel(val, ahub->apbif_regs + reg); | ||
46 | } | ||
47 | |||
48 | static inline u32 tegra30_apbif_read(u32 reg) | ||
49 | { | ||
50 | return __raw_readl(ahub->apbif_regs + reg); | ||
51 | } | ||
52 | |||
53 | static inline void tegra30_audio_write(u32 reg, u32 val) | ||
54 | { | ||
55 | #ifdef CONFIG_PM | ||
56 | ahub->ahub_reg_cache[reg >> 2] = val; | ||
57 | #endif | ||
58 | __raw_writel(val, ahub->audio_regs + reg); | ||
59 | } | ||
60 | |||
61 | static inline u32 tegra30_audio_read(u32 reg) | ||
62 | { | ||
63 | return __raw_readl(ahub->audio_regs + reg); | ||
64 | } | ||
65 | |||
66 | #ifdef CONFIG_PM | ||
67 | int tegra30_ahub_apbif_resume() | ||
68 | { | ||
69 | int i = 0; | ||
70 | int cache_idx_rsvd; | ||
71 | |||
72 | tegra30_ahub_enable_clocks(); | ||
73 | |||
74 | /*restore ahub regs*/ | ||
75 | for (i = 0; i < TEGRA30_AHUB_AUDIO_RX_COUNT; i++) | ||
76 | tegra30_audio_write(i<<2, ahub->ahub_reg_cache[i]); | ||
77 | |||
78 | /*restore apbif regs*/ | ||
79 | cache_idx_rsvd = TEGRA30_APBIF_CACHE_REG_INDEX_RSVD; | ||
80 | for (i = 0; i < TEGRA30_APBIF_CACHE_REG_COUNT; i++) { | ||
81 | if (i == cache_idx_rsvd) { | ||
82 | cache_idx_rsvd += | ||
83 | TEGRA30_APBIF_CACHE_REG_INDEX_RSVD_STRIDE; | ||
84 | continue; | ||
85 | } | ||
86 | |||
87 | tegra30_apbif_write(i<<2, ahub->apbif_reg_cache[i]); | ||
88 | } | ||
89 | |||
90 | tegra30_ahub_disable_clocks(); | ||
91 | |||
92 | return 0; | ||
93 | } | ||
94 | #endif | ||
95 | |||
96 | /* | ||
97 | * clk_apbif isn't required for a theoretical I2S<->I2S configuration where | ||
98 | * no PCM data is read from or sent to memory. However, that's an unlikely | ||
99 | * use-case, and not something the rest of the driver supports right now, so | ||
100 | * we'll just treat the two clocks as one for now. | ||
101 | * | ||
102 | * This function should not be a plain ref-count. Instead, each active stream | ||
103 | * contributes some requirement to the minimum clock rate, so starting or | ||
104 | * stopping streams should dynamically adjust the clock as required. However, | ||
105 | * this is not yet implemented. | ||
106 | */ | ||
107 | void tegra30_ahub_enable_clocks(void) | ||
108 | { | ||
109 | clk_enable(ahub->clk_d_audio); | ||
110 | clk_enable(ahub->clk_apbif); | ||
111 | } | ||
112 | |||
113 | void tegra30_ahub_disable_clocks(void) | ||
114 | { | ||
115 | clk_disable(ahub->clk_apbif); | ||
116 | clk_disable(ahub->clk_d_audio); | ||
117 | } | ||
118 | |||
119 | #ifdef CONFIG_DEBUG_FS | ||
120 | static inline u32 tegra30_ahub_read(u32 space, u32 reg) | ||
121 | { | ||
122 | if (space == 0) | ||
123 | return tegra30_apbif_read(reg); | ||
124 | else | ||
125 | return tegra30_audio_read(reg); | ||
126 | } | ||
127 | |||
128 | static int tegra30_ahub_show(struct seq_file *s, void *unused) | ||
129 | { | ||
130 | #define REG(space, r) { space, r, 0, 1, #r } | ||
131 | #define ARR(space, r) { space, r, r##_STRIDE, r##_COUNT, #r } | ||
132 | static const struct { | ||
133 | int space; | ||
134 | u32 offset; | ||
135 | u32 stride; | ||
136 | u32 count; | ||
137 | const char *name; | ||
138 | } regs[] = { | ||
139 | ARR(0, TEGRA30_AHUB_CHANNEL_CTRL), | ||
140 | ARR(0, TEGRA30_AHUB_CHANNEL_CLEAR), | ||
141 | ARR(0, TEGRA30_AHUB_CHANNEL_STATUS), | ||
142 | ARR(0, TEGRA30_AHUB_CIF_TX_CTRL), | ||
143 | ARR(0, TEGRA30_AHUB_CIF_RX_CTRL), | ||
144 | REG(0, TEGRA30_AHUB_CONFIG_LINK_CTRL), | ||
145 | REG(0, TEGRA30_AHUB_MISC_CTRL), | ||
146 | REG(0, TEGRA30_AHUB_APBDMA_LIVE_STATUS), | ||
147 | REG(0, TEGRA30_AHUB_I2S_LIVE_STATUS), | ||
148 | ARR(0, TEGRA30_AHUB_DAM_LIVE_STATUS), | ||
149 | REG(0, TEGRA30_AHUB_SPDIF_LIVE_STATUS), | ||
150 | REG(0, TEGRA30_AHUB_I2S_INT_MASK), | ||
151 | REG(0, TEGRA30_AHUB_DAM_INT_MASK), | ||
152 | REG(0, TEGRA30_AHUB_SPDIF_INT_MASK), | ||
153 | REG(0, TEGRA30_AHUB_APBIF_INT_MASK), | ||
154 | REG(0, TEGRA30_AHUB_I2S_INT_STATUS), | ||
155 | REG(0, TEGRA30_AHUB_DAM_INT_STATUS), | ||
156 | REG(0, TEGRA30_AHUB_SPDIF_INT_STATUS), | ||
157 | REG(0, TEGRA30_AHUB_APBIF_INT_STATUS), | ||
158 | REG(0, TEGRA30_AHUB_I2S_INT_SOURCE), | ||
159 | REG(0, TEGRA30_AHUB_DAM_INT_SOURCE), | ||
160 | REG(0, TEGRA30_AHUB_SPDIF_INT_SOURCE), | ||
161 | REG(0, TEGRA30_AHUB_APBIF_INT_SOURCE), | ||
162 | REG(0, TEGRA30_AHUB_I2S_INT_SET), | ||
163 | REG(0, TEGRA30_AHUB_DAM_INT_SET), | ||
164 | REG(0, TEGRA30_AHUB_SPDIF_INT_SET), | ||
165 | REG(0, TEGRA30_AHUB_APBIF_INT_SET), | ||
166 | ARR(1, TEGRA30_AHUB_AUDIO_RX), | ||
167 | }; | ||
168 | #undef ARRG | ||
169 | #undef REG | ||
170 | |||
171 | int i, j; | ||
172 | |||
173 | tegra30_ahub_enable_clocks(); | ||
174 | |||
175 | for (i = 0; i < ARRAY_SIZE(regs); i++) { | ||
176 | if (regs[i].count > 1) { | ||
177 | for (j = 0; j < regs[i].count; j++) { | ||
178 | u32 reg = regs[i].offset + (j * regs[i].stride); | ||
179 | u32 val = tegra30_ahub_read(regs[i].space, reg); | ||
180 | seq_printf(s, "%s[%d] = %08x\n", regs[i].name, | ||
181 | j, val); | ||
182 | } | ||
183 | } else { | ||
184 | u32 val = tegra30_ahub_read(regs[i].space, | ||
185 | regs[i].offset); | ||
186 | seq_printf(s, "%s = %08x\n", regs[i].name, val); | ||
187 | } | ||
188 | } | ||
189 | |||
190 | tegra30_ahub_disable_clocks(); | ||
191 | |||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | static int tegra30_ahub_debug_open(struct inode *inode, struct file *file) | ||
196 | { | ||
197 | return single_open(file, tegra30_ahub_show, inode->i_private); | ||
198 | } | ||
199 | |||
200 | static const struct file_operations tegra30_ahub_debug_fops = { | ||
201 | .open = tegra30_ahub_debug_open, | ||
202 | .read = seq_read, | ||
203 | .llseek = seq_lseek, | ||
204 | .release = single_release, | ||
205 | }; | ||
206 | |||
207 | static void tegra30_ahub_debug_add(struct tegra30_ahub *ahub) | ||
208 | { | ||
209 | ahub->debug = debugfs_create_file(DRV_NAME, S_IRUGO, | ||
210 | snd_soc_debugfs_root, ahub, | ||
211 | &tegra30_ahub_debug_fops); | ||
212 | } | ||
213 | |||
214 | static void tegra30_ahub_debug_remove(struct tegra30_ahub *ahub) | ||
215 | { | ||
216 | if (ahub->debug) | ||
217 | debugfs_remove(ahub->debug); | ||
218 | } | ||
219 | #else | ||
220 | static inline void tegra30_ahub_debug_add(struct tegra30_ahub *ahub) | ||
221 | { | ||
222 | } | ||
223 | |||
224 | static inline void tegra30_ahub_debug_remove(struct tegra30_ahub *ahub) | ||
225 | { | ||
226 | } | ||
227 | #endif | ||
228 | |||
229 | int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif, | ||
230 | unsigned long *fiforeg, | ||
231 | unsigned long *reqsel) | ||
232 | { | ||
233 | int channel; | ||
234 | u32 reg, val; | ||
235 | |||
236 | channel = find_first_zero_bit(ahub->rx_usage, | ||
237 | TEGRA30_AHUB_CHANNEL_CTRL_COUNT); | ||
238 | if (channel >= TEGRA30_AHUB_CHANNEL_CTRL_COUNT) | ||
239 | return -EBUSY; | ||
240 | |||
241 | __set_bit(channel, ahub->rx_usage); | ||
242 | |||
243 | *rxcif = TEGRA30_AHUB_RXCIF_APBIF_RX0 + channel; | ||
244 | *fiforeg = ahub->apbif_addr + TEGRA30_AHUB_CHANNEL_RXFIFO + | ||
245 | (channel * TEGRA30_AHUB_CHANNEL_RXFIFO_STRIDE); | ||
246 | *reqsel = TEGRA_DMA_REQ_SEL_APBIF_CH0 + channel; | ||
247 | |||
248 | tegra30_ahub_enable_clocks(); | ||
249 | |||
250 | reg = TEGRA30_AHUB_CHANNEL_CTRL + | ||
251 | (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); | ||
252 | val = tegra30_apbif_read(reg); | ||
253 | val &= ~(TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_MASK | | ||
254 | TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK); | ||
255 | val |= (7 << TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_SHIFT) | | ||
256 | TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_EN | | ||
257 | TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_16; | ||
258 | tegra30_apbif_write(reg, val); | ||
259 | |||
260 | reg = TEGRA30_AHUB_CIF_RX_CTRL + | ||
261 | (channel * TEGRA30_AHUB_CIF_RX_CTRL_STRIDE); | ||
262 | val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) | | ||
263 | (1 << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | | ||
264 | (1 << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) | | ||
265 | TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16 | | ||
266 | TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16 | | ||
267 | TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX; | ||
268 | tegra30_apbif_write(reg, val); | ||
269 | |||
270 | tegra30_ahub_disable_clocks(); | ||
271 | |||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif) | ||
276 | { | ||
277 | int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; | ||
278 | int reg, val; | ||
279 | |||
280 | tegra30_ahub_enable_clocks(); | ||
281 | |||
282 | reg = TEGRA30_AHUB_CHANNEL_CTRL + | ||
283 | (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); | ||
284 | val = tegra30_apbif_read(reg); | ||
285 | val |= TEGRA30_AHUB_CHANNEL_CTRL_RX_EN; | ||
286 | tegra30_apbif_write(reg, val); | ||
287 | |||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif) | ||
292 | { | ||
293 | int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; | ||
294 | int reg, val; | ||
295 | |||
296 | reg = TEGRA30_AHUB_CHANNEL_CTRL + | ||
297 | (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); | ||
298 | val = tegra30_apbif_read(reg); | ||
299 | val &= ~TEGRA30_AHUB_CHANNEL_CTRL_RX_EN; | ||
300 | tegra30_apbif_write(reg, val); | ||
301 | |||
302 | tegra30_ahub_disable_clocks(); | ||
303 | |||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif) | ||
308 | { | ||
309 | int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; | ||
310 | |||
311 | __clear_bit(channel, ahub->rx_usage); | ||
312 | |||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif, | ||
317 | unsigned long *fiforeg, | ||
318 | unsigned long *reqsel) | ||
319 | { | ||
320 | int channel; | ||
321 | u32 reg, val; | ||
322 | |||
323 | channel = find_first_zero_bit(ahub->tx_usage, | ||
324 | TEGRA30_AHUB_CHANNEL_CTRL_COUNT); | ||
325 | if (channel >= TEGRA30_AHUB_CHANNEL_CTRL_COUNT) | ||
326 | return -EBUSY; | ||
327 | |||
328 | __set_bit(channel, ahub->tx_usage); | ||
329 | |||
330 | *txcif = TEGRA30_AHUB_TXCIF_APBIF_TX0 + channel; | ||
331 | *fiforeg = ahub->apbif_addr + TEGRA30_AHUB_CHANNEL_TXFIFO + | ||
332 | (channel * TEGRA30_AHUB_CHANNEL_TXFIFO_STRIDE); | ||
333 | *reqsel = TEGRA_DMA_REQ_SEL_APBIF_CH0 + channel; | ||
334 | |||
335 | tegra30_ahub_enable_clocks(); | ||
336 | |||
337 | reg = TEGRA30_AHUB_CHANNEL_CTRL + | ||
338 | (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); | ||
339 | val = tegra30_apbif_read(reg); | ||
340 | val &= ~(TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_MASK | | ||
341 | TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK); | ||
342 | val |= (7 << TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_SHIFT) | | ||
343 | TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_EN | | ||
344 | TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_16; | ||
345 | tegra30_apbif_write(reg, val); | ||
346 | |||
347 | reg = TEGRA30_AHUB_CIF_TX_CTRL + | ||
348 | (channel * TEGRA30_AHUB_CIF_TX_CTRL_STRIDE); | ||
349 | val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) | | ||
350 | (1 << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | | ||
351 | (1 << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) | | ||
352 | TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16 | | ||
353 | TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16 | | ||
354 | TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX; | ||
355 | tegra30_apbif_write(reg, val); | ||
356 | |||
357 | tegra30_ahub_disable_clocks(); | ||
358 | |||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif) | ||
363 | { | ||
364 | int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0; | ||
365 | int reg, val; | ||
366 | |||
367 | tegra30_ahub_enable_clocks(); | ||
368 | |||
369 | reg = TEGRA30_AHUB_CHANNEL_CTRL + | ||
370 | (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); | ||
371 | val = tegra30_apbif_read(reg); | ||
372 | val |= TEGRA30_AHUB_CHANNEL_CTRL_TX_EN; | ||
373 | tegra30_apbif_write(reg, val); | ||
374 | |||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif) | ||
379 | { | ||
380 | int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0; | ||
381 | int reg, val; | ||
382 | |||
383 | reg = TEGRA30_AHUB_CHANNEL_CTRL + | ||
384 | (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); | ||
385 | val = tegra30_apbif_read(reg); | ||
386 | val &= ~TEGRA30_AHUB_CHANNEL_CTRL_TX_EN; | ||
387 | tegra30_apbif_write(reg, val); | ||
388 | |||
389 | tegra30_ahub_disable_clocks(); | ||
390 | |||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | int tegra30_ahub_free_tx_fifo(enum tegra30_ahub_txcif txcif) | ||
395 | { | ||
396 | int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0; | ||
397 | |||
398 | __clear_bit(channel, ahub->tx_usage); | ||
399 | |||
400 | return 0; | ||
401 | } | ||
402 | |||
403 | int tegra30_ahub_set_rx_cif_source(enum tegra30_ahub_rxcif rxcif, | ||
404 | enum tegra30_ahub_txcif txcif) | ||
405 | { | ||
406 | int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; | ||
407 | int reg; | ||
408 | |||
409 | tegra30_ahub_enable_clocks(); | ||
410 | |||
411 | reg = TEGRA30_AHUB_AUDIO_RX + | ||
412 | (channel * TEGRA30_AHUB_AUDIO_RX_STRIDE); | ||
413 | tegra30_audio_write(reg, 1 << txcif); | ||
414 | |||
415 | tegra30_ahub_disable_clocks(); | ||
416 | |||
417 | return 0; | ||
418 | } | ||
419 | |||
420 | int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif) | ||
421 | { | ||
422 | int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; | ||
423 | int reg; | ||
424 | |||
425 | tegra30_ahub_enable_clocks(); | ||
426 | |||
427 | reg = TEGRA30_AHUB_AUDIO_RX + | ||
428 | (channel * TEGRA30_AHUB_AUDIO_RX_STRIDE); | ||
429 | tegra30_audio_write(reg, 0); | ||
430 | |||
431 | tegra30_ahub_disable_clocks(); | ||
432 | |||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | int tegra30_ahub_set_rx_cif_channels(enum tegra30_ahub_rxcif rxcif, | ||
437 | unsigned int audio_ch, | ||
438 | unsigned int client_ch) | ||
439 | { | ||
440 | int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; | ||
441 | unsigned int reg, val; | ||
442 | |||
443 | tegra30_ahub_enable_clocks(); | ||
444 | |||
445 | reg = TEGRA30_AHUB_CIF_RX_CTRL + | ||
446 | (channel * TEGRA30_AHUB_CIF_RX_CTRL_STRIDE); | ||
447 | val = tegra30_apbif_read(reg); | ||
448 | val &= ~(TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK | | ||
449 | TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK); | ||
450 | val |= ((audio_ch - 1) << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | | ||
451 | ((client_ch - 1) << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT); | ||
452 | tegra30_apbif_write(reg, val); | ||
453 | |||
454 | tegra30_ahub_disable_clocks(); | ||
455 | |||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | int tegra30_ahub_set_tx_cif_channels(enum tegra30_ahub_txcif txcif, | ||
460 | unsigned int audio_ch, | ||
461 | unsigned int client_ch) | ||
462 | { | ||
463 | int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0; | ||
464 | unsigned int reg, val; | ||
465 | |||
466 | tegra30_ahub_enable_clocks(); | ||
467 | |||
468 | reg = TEGRA30_AHUB_CIF_TX_CTRL + | ||
469 | (channel * TEGRA30_AHUB_CIF_TX_CTRL_STRIDE); | ||
470 | val = tegra30_apbif_read(reg); | ||
471 | val &= ~(TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK | | ||
472 | TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK); | ||
473 | val |= ((audio_ch - 1) << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | | ||
474 | ((client_ch - 1) << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT); | ||
475 | |||
476 | tegra30_apbif_write(reg, val); | ||
477 | |||
478 | tegra30_ahub_disable_clocks(); | ||
479 | |||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | static int __devinit tegra30_ahub_probe(struct platform_device *pdev) | ||
484 | { | ||
485 | struct resource *res0, *res1, *region; | ||
486 | int ret = 0; | ||
487 | #ifdef CONFIG_PM | ||
488 | int i = 0, cache_idx_rsvd; | ||
489 | #endif | ||
490 | int clkm_rate; | ||
491 | |||
492 | if (ahub) | ||
493 | return -ENODEV; | ||
494 | |||
495 | ahub = kzalloc(sizeof(struct tegra30_ahub), GFP_KERNEL); | ||
496 | if (!ahub) { | ||
497 | dev_err(&pdev->dev, "Can't allocate tegra30_ahub\n"); | ||
498 | ret = -ENOMEM; | ||
499 | goto exit; | ||
500 | } | ||
501 | ahub->dev = &pdev->dev; | ||
502 | |||
503 | ahub->clk_d_audio = clk_get(&pdev->dev, "d_audio"); | ||
504 | if (IS_ERR(ahub->clk_d_audio)) { | ||
505 | dev_err(&pdev->dev, "Can't retrieve ahub d_audio clock\n"); | ||
506 | ret = PTR_ERR(ahub->clk_d_audio); | ||
507 | goto err_free; | ||
508 | } | ||
509 | clkm_rate = clk_get_rate(clk_get_parent(ahub->clk_d_audio)); | ||
510 | while (clkm_rate > 12000000) | ||
511 | clkm_rate >>= 1; | ||
512 | |||
513 | clk_set_rate(ahub->clk_d_audio,clkm_rate); | ||
514 | |||
515 | ahub->clk_apbif = clk_get(&pdev->dev, "apbif"); | ||
516 | if (IS_ERR(ahub->clk_apbif)) { | ||
517 | dev_err(&pdev->dev, "Can't retrieve ahub apbif clock\n"); | ||
518 | ret = PTR_ERR(ahub->clk_apbif); | ||
519 | goto err_clk_put_d_audio; | ||
520 | } | ||
521 | |||
522 | res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
523 | if (!res0) { | ||
524 | dev_err(&pdev->dev, "No memory 0 resource\n"); | ||
525 | ret = -ENODEV; | ||
526 | goto err_clk_put_apbif; | ||
527 | } | ||
528 | |||
529 | region = request_mem_region(res0->start, resource_size(res0), | ||
530 | pdev->name); | ||
531 | if (!region) { | ||
532 | dev_err(&pdev->dev, "Memory region 0 already claimed\n"); | ||
533 | ret = -EBUSY; | ||
534 | goto err_clk_put_apbif; | ||
535 | } | ||
536 | |||
537 | ahub->apbif_regs = ioremap(res0->start, resource_size(res0)); | ||
538 | if (!ahub->apbif_regs) { | ||
539 | dev_err(&pdev->dev, "ioremap 0 failed\n"); | ||
540 | ret = -ENOMEM; | ||
541 | goto err_release0; | ||
542 | } | ||
543 | |||
544 | ahub->apbif_addr = res0->start; | ||
545 | |||
546 | res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
547 | if (!res1) { | ||
548 | dev_err(&pdev->dev, "No memory 1 resource\n"); | ||
549 | ret = -ENODEV; | ||
550 | goto err_unmap0; | ||
551 | } | ||
552 | |||
553 | region = request_mem_region(res1->start, resource_size(res1), | ||
554 | pdev->name); | ||
555 | if (!region) { | ||
556 | dev_err(&pdev->dev, "Memory region 1 already claimed\n"); | ||
557 | ret = -EBUSY; | ||
558 | goto err_unmap0; | ||
559 | } | ||
560 | |||
561 | ahub->audio_regs = ioremap(res1->start, resource_size(res1)); | ||
562 | if (!ahub->audio_regs) { | ||
563 | dev_err(&pdev->dev, "ioremap 1 failed\n"); | ||
564 | ret = -ENOMEM; | ||
565 | goto err_release1; | ||
566 | } | ||
567 | |||
568 | #ifdef CONFIG_PM | ||
569 | /* cache the POR values of ahub/apbif regs*/ | ||
570 | tegra30_ahub_enable_clocks(); | ||
571 | |||
572 | for (i = 0; i < TEGRA30_AHUB_AUDIO_RX_COUNT; i++) | ||
573 | ahub->ahub_reg_cache[i] = tegra30_audio_read(i<<2); | ||
574 | |||
575 | cache_idx_rsvd = TEGRA30_APBIF_CACHE_REG_INDEX_RSVD; | ||
576 | for (i = 0; i < TEGRA30_APBIF_CACHE_REG_COUNT; i++) { | ||
577 | if (i == cache_idx_rsvd) { | ||
578 | cache_idx_rsvd += | ||
579 | TEGRA30_APBIF_CACHE_REG_INDEX_RSVD_STRIDE; | ||
580 | continue; | ||
581 | } | ||
582 | |||
583 | ahub->apbif_reg_cache[i] = tegra30_apbif_read(i<<2); | ||
584 | } | ||
585 | |||
586 | tegra30_ahub_disable_clocks(); | ||
587 | #endif | ||
588 | |||
589 | tegra30_ahub_debug_add(ahub); | ||
590 | |||
591 | platform_set_drvdata(pdev, ahub); | ||
592 | |||
593 | return 0; | ||
594 | |||
595 | err_release1: | ||
596 | release_mem_region(res1->start, resource_size(res1)); | ||
597 | err_unmap0: | ||
598 | iounmap(ahub->apbif_regs); | ||
599 | err_release0: | ||
600 | release_mem_region(res0->start, resource_size(res0)); | ||
601 | err_clk_put_apbif: | ||
602 | clk_put(ahub->clk_apbif); | ||
603 | err_clk_put_d_audio: | ||
604 | clk_put(ahub->clk_d_audio); | ||
605 | err_free: | ||
606 | kfree(ahub); | ||
607 | ahub = 0; | ||
608 | exit: | ||
609 | return ret; | ||
610 | } | ||
611 | |||
612 | static int __devexit tegra30_ahub_remove(struct platform_device *pdev) | ||
613 | { | ||
614 | struct resource *res; | ||
615 | |||
616 | if (!ahub) | ||
617 | return -ENODEV; | ||
618 | |||
619 | platform_set_drvdata(pdev, NULL); | ||
620 | |||
621 | tegra30_ahub_debug_remove(ahub); | ||
622 | |||
623 | iounmap(ahub->audio_regs); | ||
624 | |||
625 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
626 | release_mem_region(res->start, resource_size(res)); | ||
627 | |||
628 | iounmap(ahub->apbif_regs); | ||
629 | |||
630 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
631 | release_mem_region(res->start, resource_size(res)); | ||
632 | |||
633 | clk_put(ahub->clk_apbif); | ||
634 | clk_put(ahub->clk_d_audio); | ||
635 | |||
636 | kfree(ahub); | ||
637 | ahub = 0; | ||
638 | |||
639 | return 0; | ||
640 | } | ||
641 | |||
642 | static struct platform_driver tegra30_ahub_driver = { | ||
643 | .probe = tegra30_ahub_probe, | ||
644 | .remove = __devexit_p(tegra30_ahub_remove), | ||
645 | .driver = { | ||
646 | .name = DRV_NAME, | ||
647 | }, | ||
648 | }; | ||
649 | |||
650 | static int __init tegra30_ahub_modinit(void) | ||
651 | { | ||
652 | return platform_driver_register(&tegra30_ahub_driver); | ||
653 | } | ||
654 | module_init(tegra30_ahub_modinit); | ||
655 | |||
656 | static void __exit tegra30_ahub_modexit(void) | ||
657 | { | ||
658 | platform_driver_unregister(&tegra30_ahub_driver); | ||
659 | } | ||
660 | module_exit(tegra30_ahub_modexit); | ||
661 | |||
662 | MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); | ||
663 | MODULE_DESCRIPTION("Tegra 30 AHUB driver"); | ||
664 | MODULE_LICENSE("GPL"); | ||
665 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/sound/soc/tegra/tegra30_ahub.h b/sound/soc/tegra/tegra30_ahub.h new file mode 100644 index 00000000000..7de1b7c86c7 --- /dev/null +++ b/sound/soc/tegra/tegra30_ahub.h | |||
@@ -0,0 +1,512 @@ | |||
1 | /* | ||
2 | * tegra30_ahub.h - Definitions for Tegra 30 AHUB driver | ||
3 | * | ||
4 | * Author: Stephen Warren <swarren@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_AHUB_H__ | ||
24 | #define __TEGRA30_AHUB_H__ | ||
25 | |||
26 | /* Fields in *_CIF_RX/TX_CTRL; used by AHUB FIFOs, and all other audio modules */ | ||
27 | |||
28 | #define TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT 28 | ||
29 | #define TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_MASK_US 0xf | ||
30 | #define TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_MASK (TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_MASK_US << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) | ||
31 | |||
32 | /* Channel count minus 1 */ | ||
33 | #define TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT 24 | ||
34 | #define TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK_US 7 | ||
35 | #define TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK (TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK_US << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | ||
36 | |||
37 | /* Channel count minus 1 */ | ||
38 | #define TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT 16 | ||
39 | #define TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK_US 7 | ||
40 | #define TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK (TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK_US << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) | ||
41 | |||
42 | #define TEGRA30_AUDIOCIF_BITS_4 0 | ||
43 | #define TEGRA30_AUDIOCIF_BITS_8 1 | ||
44 | #define TEGRA30_AUDIOCIF_BITS_12 2 | ||
45 | #define TEGRA30_AUDIOCIF_BITS_16 3 | ||
46 | #define TEGRA30_AUDIOCIF_BITS_20 4 | ||
47 | #define TEGRA30_AUDIOCIF_BITS_24 5 | ||
48 | #define TEGRA30_AUDIOCIF_BITS_28 6 | ||
49 | #define TEGRA30_AUDIOCIF_BITS_32 7 | ||
50 | |||
51 | #define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT 12 | ||
52 | #define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_MASK (7 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | ||
53 | #define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_4 (TEGRA30_AUDIOCIF_BITS_4 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | ||
54 | #define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_8 (TEGRA30_AUDIOCIF_BITS_8 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | ||
55 | #define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_12 (TEGRA30_AUDIOCIF_BITS_12 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | ||
56 | #define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16 (TEGRA30_AUDIOCIF_BITS_16 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | ||
57 | #define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_20 (TEGRA30_AUDIOCIF_BITS_20 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | ||
58 | #define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_24 (TEGRA30_AUDIOCIF_BITS_24 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | ||
59 | #define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_28 (TEGRA30_AUDIOCIF_BITS_28 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | ||
60 | #define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_32 (TEGRA30_AUDIOCIF_BITS_32 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) | ||
61 | |||
62 | #define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT 8 | ||
63 | #define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_MASK (7 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) | ||
64 | #define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_4 (TEGRA30_AUDIOCIF_BITS_4 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) | ||
65 | #define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_8 (TEGRA30_AUDIOCIF_BITS_8 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) | ||
66 | #define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_12 (TEGRA30_AUDIOCIF_BITS_12 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) | ||
67 | #define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16 (TEGRA30_AUDIOCIF_BITS_16 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) | ||
68 | #define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_20 (TEGRA30_AUDIOCIF_BITS_20 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) | ||
69 | #define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_24 (TEGRA30_AUDIOCIF_BITS_24 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) | ||
70 | #define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_28 (TEGRA30_AUDIOCIF_BITS_28 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) | ||
71 | #define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_32 (TEGRA30_AUDIOCIF_BITS_32 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) | ||
72 | |||
73 | #define TEGRA30_AUDIOCIF_EXPAND_ZERO 0 | ||
74 | #define TEGRA30_AUDIOCIF_EXPAND_ONE 1 | ||
75 | #define TEGRA30_AUDIOCIF_EXPAND_LFSR 2 | ||
76 | |||
77 | #define TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT 6 | ||
78 | #define TEGRA30_AUDIOCIF_CTRL_EXPAND_MASK (3 << TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT) | ||
79 | #define TEGRA30_AUDIOCIF_CTRL_EXPAND_ZERO (TEGRA30_AUDIOCIF_EXPAND_ZERO << TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT) | ||
80 | #define TEGRA30_AUDIOCIF_CTRL_EXPAND_ONE (TEGRA30_AUDIOCIF_EXPAND_ONE << TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT) | ||
81 | #define TEGRA30_AUDIOCIF_CTRL_EXPAND_LFSR (TEGRA30_AUDIOCIF_EXPAND_LFSR << TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT) | ||
82 | |||
83 | #define TEGRA30_AUDIOCIF_STEREO_CONV_CH0 0 | ||
84 | #define TEGRA30_AUDIOCIF_STEREO_CONV_CH1 1 | ||
85 | #define TEGRA30_AUDIOCIF_STEREO_CONV_AVG 2 | ||
86 | |||
87 | #define TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT 4 | ||
88 | #define TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_MASK (3 << TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) | ||
89 | #define TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_CH0 (TEGRA30_AUDIOCIF_STEREO_CONV_CH0 << TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) | ||
90 | #define TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_CH1 (TEGRA30_AUDIOCIF_STEREO_CONV_CH1 << TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) | ||
91 | #define TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_AVG (TEGRA30_AUDIOCIF_STEREO_CONV_AVG << TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) | ||
92 | |||
93 | #define TEGRA30_AUDIOCIF_CTRL_REPLICATE 3 | ||
94 | |||
95 | #define TEGRA30_AUDIOCIF_DIRECTION_TX 0 | ||
96 | #define TEGRA30_AUDIOCIF_DIRECTION_RX 1 | ||
97 | |||
98 | #define TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT 2 | ||
99 | #define TEGRA30_AUDIOCIF_CTRL_DIRECTION_MASK (1 << TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT) | ||
100 | #define TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX (TEGRA30_AUDIOCIF_DIRECTION_TX << TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT) | ||
101 | #define TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX (TEGRA30_AUDIOCIF_DIRECTION_RX << TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT) | ||
102 | |||
103 | #define TEGRA30_AUDIOCIF_TRUNCATE_ROUND 0 | ||
104 | #define TEGRA30_AUDIOCIF_TRUNCATE_CHOP 1 | ||
105 | |||
106 | #define TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT 1 | ||
107 | #define TEGRA30_AUDIOCIF_CTRL_TRUNCATE_MASK (1 << TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT) | ||
108 | #define TEGRA30_AUDIOCIF_CTRL_TRUNCATE_ROUND (TEGRA30_AUDIOCIF_TRUNCATE_ROUND << TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT) | ||
109 | #define TEGRA30_AUDIOCIF_CTRL_TRUNCATE_CHOP (TEGRA30_AUDIOCIF_TRUNCATE_CHOP << TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT) | ||
110 | |||
111 | #define TEGRA30_AUDIOCIF_MONO_CONV_ZERO 0 | ||
112 | #define TEGRA30_AUDIOCIF_MONO_CONV_COPY 1 | ||
113 | |||
114 | #define TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT 0 | ||
115 | #define TEGRA30_AUDIOCIF_CTRL_MONO_CONV_MASK (1 << TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT) | ||
116 | #define TEGRA30_AUDIOCIF_CTRL_MONO_CONV_ZERO (TEGRA30_AUDIOCIF_MONO_CONV_ZERO << TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT) | ||
117 | #define TEGRA30_AUDIOCIF_CTRL_MONO_CONV_COPY (TEGRA30_AUDIOCIF_MONO_CONV_COPY << TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT) | ||
118 | |||
119 | /* Registers within TEGRA30_AUDIO_CLUSTER_BASE */ | ||
120 | |||
121 | /* TEGRA30_AHUB_CHANNEL_CTRL */ | ||
122 | |||
123 | #define TEGRA30_AHUB_CHANNEL_CTRL 0x0 | ||
124 | #define TEGRA30_AHUB_CHANNEL_CTRL_STRIDE 0x20 | ||
125 | #define TEGRA30_AHUB_CHANNEL_CTRL_COUNT 4 | ||
126 | #define TEGRA30_AHUB_CHANNEL_CTRL_TX_EN (1 << 31) | ||
127 | #define TEGRA30_AHUB_CHANNEL_CTRL_RX_EN (1 << 30) | ||
128 | #define TEGRA30_AHUB_CHANNEL_CTRL_LOOPBACK (1 << 29) | ||
129 | |||
130 | #define TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_SHIFT 16 | ||
131 | #define TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_MASK_US 0xff | ||
132 | #define TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_MASK (TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_MASK_US << TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_SHIFT) | ||
133 | |||
134 | #define TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_SHIFT 8 | ||
135 | #define TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_MASK_US 0xff | ||
136 | #define TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_MASK (TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_MASK_US << TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_SHIFT) | ||
137 | |||
138 | #define TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_EN (1 << 6) | ||
139 | |||
140 | #define TEGRA30_PACK_8_4 2 | ||
141 | #define TEGRA30_PACK_16 3 | ||
142 | |||
143 | #define TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_SHIFT 4 | ||
144 | #define TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK_US 3 | ||
145 | #define TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK (TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK_US << TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_SHIFT) | ||
146 | #define TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_8_4 (TEGRA30_PACK_8_4 << TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_SHIFT) | ||
147 | #define TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_16 (TEGRA30_PACK_16 << TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_SHIFT) | ||
148 | |||
149 | #define TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_EN (1 << 2) | ||
150 | |||
151 | #define TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_SHIFT 0 | ||
152 | #define TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK_US 3 | ||
153 | #define TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK (TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK_US << TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_SHIFT) | ||
154 | #define TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_8_4 (TEGRA30_PACK_8_4 << TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_SHIFT) | ||
155 | #define TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_16 (TEGRA30_PACK_16 << TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_SHIFT) | ||
156 | |||
157 | /* TEGRA30_AHUB_CHANNEL_CLEAR */ | ||
158 | |||
159 | #define TEGRA30_AHUB_CHANNEL_CLEAR 0x4 | ||
160 | #define TEGRA30_AHUB_CHANNEL_CLEAR_STRIDE 0x20 | ||
161 | #define TEGRA30_AHUB_CHANNEL_CLEAR_COUNT 4 | ||
162 | #define TEGRA30_AHUB_CHANNEL_CLEAR_TX_SOFT_RESET (1 << 31) | ||
163 | #define TEGRA30_AHUB_CHANNEL_CLEAR_RX_SOFT_RESET (1 << 30) | ||
164 | |||
165 | /* TEGRA30_AHUB_CHANNEL_STATUS */ | ||
166 | |||
167 | #define TEGRA30_AHUB_CHANNEL_STATUS 0x8 | ||
168 | #define TEGRA30_AHUB_CHANNEL_STATUS_STRIDE 0x20 | ||
169 | #define TEGRA30_AHUB_CHANNEL_STATUS_COUNT 4 | ||
170 | #define TEGRA30_AHUB_CHANNEL_STATUS_TX_FREE_SHIFT 24 | ||
171 | #define TEGRA30_AHUB_CHANNEL_STATUS_TX_FREE_MASK_US 0xff | ||
172 | #define TEGRA30_AHUB_CHANNEL_STATUS_TX_FREE_MASK (TEGRA30_AHUB_CHANNEL_STATUS_TX_FREE_MASK_US << TEGRA30_AHUB_CHANNEL_STATUS_TX_FREE_SHIFT) | ||
173 | #define TEGRA30_AHUB_CHANNEL_STATUS_RX_FREE_SHIFT 16 | ||
174 | #define TEGRA30_AHUB_CHANNEL_STATUS_RX_FREE_MASK_US 0xff | ||
175 | #define TEGRA30_AHUB_CHANNEL_STATUS_RX_FREE_MASK (TEGRA30_AHUB_CHANNEL_STATUS_RX_FREE_MASK_US << TEGRA30_AHUB_CHANNEL_STATUS_RX_FREE_SHIFT) | ||
176 | #define TEGRA30_AHUB_CHANNEL_STATUS_TX_TRIG (1 << 1) | ||
177 | #define TEGRA30_AHUB_CHANNEL_STATUS_RX_TRIG (1 << 0) | ||
178 | |||
179 | /* TEGRA30_AHUB_CHANNEL_TXFIFO */ | ||
180 | |||
181 | #define TEGRA30_AHUB_CHANNEL_TXFIFO 0xc | ||
182 | #define TEGRA30_AHUB_CHANNEL_TXFIFO_STRIDE 0x20 | ||
183 | #define TEGRA30_AHUB_CHANNEL_TXFIFO_COUNT 4 | ||
184 | |||
185 | /* TEGRA30_AHUB_CHANNEL_RXFIFO */ | ||
186 | |||
187 | #define TEGRA30_AHUB_CHANNEL_RXFIFO 0x10 | ||
188 | #define TEGRA30_AHUB_CHANNEL_RXFIFO_STRIDE 0x20 | ||
189 | #define TEGRA30_AHUB_CHANNEL_RXFIFO_COUNT 4 | ||
190 | |||
191 | /* TEGRA30_AHUB_CIF_TX_CTRL */ | ||
192 | |||
193 | #define TEGRA30_AHUB_CIF_TX_CTRL 0x14 | ||
194 | #define TEGRA30_AHUB_CIF_TX_CTRL_STRIDE 0x20 | ||
195 | #define TEGRA30_AHUB_CIF_TX_CTRL_COUNT 4 | ||
196 | /* Uses field from TEGRA30_AUDIOCIF_CTRL_* */ | ||
197 | |||
198 | /* TEGRA30_AHUB_CIF_RX_CTRL */ | ||
199 | |||
200 | #define TEGRA30_AHUB_CIF_RX_CTRL 0x18 | ||
201 | #define TEGRA30_AHUB_CIF_RX_CTRL_STRIDE 0x20 | ||
202 | #define TEGRA30_AHUB_CIF_RX_CTRL_COUNT 4 | ||
203 | /* Uses field from TEGRA30_AUDIOCIF_CTRL_* */ | ||
204 | |||
205 | /* TEGRA30_AHUB_CONFIG_LINK_CTRL */ | ||
206 | |||
207 | #define TEGRA30_AHUB_CONFIG_LINK_CTRL 0x80 | ||
208 | #define TEGRA30_AHUB_CONFIG_LINK_CTRL_MASTER_FIFO_FULL_CNT_SHIFT 28 | ||
209 | #define TEGRA30_AHUB_CONFIG_LINK_CTRL_MASTER_FIFO_FULL_CNT_MASK_US 0xf | ||
210 | #define TEGRA30_AHUB_CONFIG_LINK_CTRL_MASTER_FIFO_FULL_CNT_MASK (TEGRA30_AHUB_CONFIG_LINK_CTRL_MASTER_FIFO_FULL_CNT_MASK_US << TEGRA30_AHUB_CONFIG_LINK_CTRL_MASTER_FIFO_FULL_CNT_SHIFT) | ||
211 | #define TEGRA30_AHUB_CONFIG_LINK_CTRL_TIMEOUT_CNT_SHIFT 16 | ||
212 | #define TEGRA30_AHUB_CONFIG_LINK_CTRL_TIMEOUT_CNT_MASK_US 0xfff | ||
213 | #define TEGRA30_AHUB_CONFIG_LINK_CTRL_TIMEOUT_CNT_MASK (TEGRA30_AHUB_CONFIG_LINK_CTRL_TIMEOUT_CNT_MASK_US << TEGRA30_AHUB_CONFIG_LINK_CTRL_TIMEOUT_CNT_SHIFT) | ||
214 | #define TEGRA30_AHUB_CONFIG_LINK_CTRL_IDLE_CNT_SHIFT 5 | ||
215 | #define TEGRA30_AHUB_CONFIG_LINK_CTRL_IDLE_CNT_MASK_US 0xfff | ||
216 | #define TEGRA30_AHUB_CONFIG_LINK_CTRL_IDLE_CNT_MASK (TEGRA30_AHUB_CONFIG_LINK_CTRL_IDLE_CNT_MASK_US << TEGRA30_AHUB_CONFIG_LINK_CTRL_IDLE_CNT_SHIFT) | ||
217 | #define TEGRA30_AHUB_CONFIG_LINK_CTRL_CG_EN (1 << 2) | ||
218 | #define TEGRA30_AHUB_CONFIG_LINK_CTRL_CLEAR_TIMEOUT_CNTR (1 << 1) | ||
219 | #define TEGRA30_AHUB_CONFIG_LINK_CTRL_SOFT_RESET (1 << 0) | ||
220 | |||
221 | /* TEGRA30_AHUB_MISC_CTRL */ | ||
222 | |||
223 | #define TEGRA30_AHUB_MISC_CTRL 0x84 | ||
224 | #define TEGRA30_AHUB_MISC_CTRL_AUDIO_ACTIVE (1 << 31) | ||
225 | #define TEGRA30_AHUB_MISC_CTRL_AUDIO_CG_EN (1 << 9) | ||
226 | #define TEGRA30_AHUB_MISC_CTRL_AUDIO_OBS_SEL_SHIFT 0 | ||
227 | #define TEGRA30_AHUB_MISC_CTRL_AUDIO_OBS_SEL_MASK (0x1f << TEGRA30_AHUB_MISC_CTRL_AUDIO_OBS_SEL_SHIFT) | ||
228 | |||
229 | /* TEGRA30_AHUB_APBDMA_LIVE_STATUS */ | ||
230 | |||
231 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS 0x88 | ||
232 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_RX_CIF_FIFO_FULL (1 << 31) | ||
233 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_TX_CIF_FIFO_FULL (1 << 30) | ||
234 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_RX_CIF_FIFO_FULL (1 << 29) | ||
235 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_TX_CIF_FIFO_FULL (1 << 28) | ||
236 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_RX_CIF_FIFO_FULL (1 << 27) | ||
237 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_TX_CIF_FIFO_FULL (1 << 26) | ||
238 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_RX_CIF_FIFO_FULL (1 << 25) | ||
239 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_TX_CIF_FIFO_FULL (1 << 24) | ||
240 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_RX_CIF_FIFO_EMPTY (1 << 23) | ||
241 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_TX_CIF_FIFO_EMPTY (1 << 22) | ||
242 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_RX_CIF_FIFO_EMPTY (1 << 21) | ||
243 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_TX_CIF_FIFO_EMPTY (1 << 20) | ||
244 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_RX_CIF_FIFO_EMPTY (1 << 19) | ||
245 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_TX_CIF_FIFO_EMPTY (1 << 18) | ||
246 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_RX_CIF_FIFO_EMPTY (1 << 17) | ||
247 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_TX_CIF_FIFO_EMPTY (1 << 16) | ||
248 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_RX_DMA_FIFO_FULL (1 << 15) | ||
249 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_TX_DMA_FIFO_FULL (1 << 14) | ||
250 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_RX_DMA_FIFO_FULL (1 << 13) | ||
251 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_TX_DMA_FIFO_FULL (1 << 12) | ||
252 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_RX_DMA_FIFO_FULL (1 << 11) | ||
253 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_TX_DMA_FIFO_FULL (1 << 10) | ||
254 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_RX_DMA_FIFO_FULL (1 << 9) | ||
255 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_TX_DMA_FIFO_FULL (1 << 8) | ||
256 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_RX_DMA_FIFO_EMPTY (1 << 7) | ||
257 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_TX_DMA_FIFO_EMPTY (1 << 6) | ||
258 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_RX_DMA_FIFO_EMPTY (1 << 5) | ||
259 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_TX_DMA_FIFO_EMPTY (1 << 4) | ||
260 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_RX_DMA_FIFO_EMPTY (1 << 3) | ||
261 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_TX_DMA_FIFO_EMPTY (1 << 2) | ||
262 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_RX_DMA_FIFO_EMPTY (1 << 1) | ||
263 | #define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_TX_DMA_FIFO_EMPTY (1 << 0) | ||
264 | |||
265 | /* TEGRA30_AHUB_I2S_LIVE_STATUS */ | ||
266 | |||
267 | #define TEGRA30_AHUB_I2S_LIVE_STATUS 0x8c | ||
268 | #define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S4_RX_FIFO_FULL (1 << 29) | ||
269 | #define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S4_TX_FIFO_FULL (1 << 28) | ||
270 | #define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S3_RX_FIFO_FULL (1 << 27) | ||
271 | #define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S3_TX_FIFO_FULL (1 << 26) | ||
272 | #define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S2_RX_FIFO_FULL (1 << 25) | ||
273 | #define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S2_TX_FIFO_FULL (1 << 24) | ||
274 | #define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S1_RX_FIFO_FULL (1 << 23) | ||
275 | #define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S1_TX_FIFO_FULL (1 << 22) | ||
276 | #define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_RX_FIFO_FULL (1 << 21) | ||
277 | #define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_TX_FIFO_FULL (1 << 20) | ||
278 | #define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S4_RX_FIFO_ENABLED (1 << 19) | ||
279 | #define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S4_TX_FIFO_ENABLED (1 << 18) | ||
280 | #define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S3_RX_FIFO_ENABLED (1 << 17) | ||
281 | #define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S3_TX_FIFO_ENABLED (1 << 16) | ||
282 | #define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S2_RX_FIFO_ENABLED (1 << 15) | ||
283 | #define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S2_TX_FIFO_ENABLED (1 << 14) | ||
284 | #define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S1_RX_FIFO_ENABLED (1 << 13) | ||
285 | #define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S1_TX_FIFO_ENABLED (1 << 12) | ||
286 | #define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_RX_FIFO_ENABLED (1 << 11) | ||
287 | #define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_TX_FIFO_ENABLED (1 << 10) | ||
288 | #define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S4_RX_FIFO_EMPTY (1 << 9) | ||
289 | #define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S4_TX_FIFO_EMPTY (1 << 8) | ||
290 | #define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S3_RX_FIFO_EMPTY (1 << 7) | ||
291 | #define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S3_TX_FIFO_EMPTY (1 << 6) | ||
292 | #define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S2_RX_FIFO_EMPTY (1 << 5) | ||
293 | #define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S2_TX_FIFO_EMPTY (1 << 4) | ||
294 | #define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S1_RX_FIFO_EMPTY (1 << 3) | ||
295 | #define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S1_TX_FIFO_EMPTY (1 << 2) | ||
296 | #define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_RX_FIFO_EMPTY (1 << 1) | ||
297 | #define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_TX_FIFO_EMPTY (1 << 0) | ||
298 | |||
299 | /* TEGRA30_AHUB_DAM0_LIVE_STATUS */ | ||
300 | |||
301 | #define TEGRA30_AHUB_DAM_LIVE_STATUS 0x90 | ||
302 | #define TEGRA30_AHUB_DAM_LIVE_STATUS_STRIDE 0x8 | ||
303 | #define TEGRA30_AHUB_DAM_LIVE_STATUS_COUNT 3 | ||
304 | #define TEGRA30_AHUB_DAM_LIVE_STATUS_TX_ENABLED (1 << 26) | ||
305 | #define TEGRA30_AHUB_DAM_LIVE_STATUS_RX1_ENABLED (1 << 25) | ||
306 | #define TEGRA30_AHUB_DAM_LIVE_STATUS_RX0_ENABLED (1 << 24) | ||
307 | #define TEGRA30_AHUB_DAM_LIVE_STATUS_TXFIFO_FULL (1 << 15) | ||
308 | #define TEGRA30_AHUB_DAM_LIVE_STATUS_RX1FIFO_FULL (1 << 9) | ||
309 | #define TEGRA30_AHUB_DAM_LIVE_STATUS_RX0FIFO_FULL (1 << 8) | ||
310 | #define TEGRA30_AHUB_DAM_LIVE_STATUS_TXFIFO_EMPTY (1 << 7) | ||
311 | #define TEGRA30_AHUB_DAM_LIVE_STATUS_RX1FIFO_EMPTY (1 << 1) | ||
312 | #define TEGRA30_AHUB_DAM_LIVE_STATUS_RX0FIFO_EMPTY (1 << 0) | ||
313 | |||
314 | /* TEGRA30_AHUB_SPDIF_LIVE_STATUS */ | ||
315 | |||
316 | #define TEGRA30_AHUB_SPDIF_LIVE_STATUS 0xa8 | ||
317 | #define TEGRA30_AHUB_SPDIF_LIVE_STATUS_USER_TX_ENABLED (1 << 11) | ||
318 | #define TEGRA30_AHUB_SPDIF_LIVE_STATUS_USER_RX_ENABLED (1 << 10) | ||
319 | #define TEGRA30_AHUB_SPDIF_LIVE_STATUS_DATA_TX_ENABLED (1 << 9) | ||
320 | #define TEGRA30_AHUB_SPDIF_LIVE_STATUS_DATA_RX_ENABLED (1 << 8) | ||
321 | #define TEGRA30_AHUB_SPDIF_LIVE_STATUS_USER_TXFIFO_FULL (1 << 7) | ||
322 | #define TEGRA30_AHUB_SPDIF_LIVE_STATUS_USER_RXFIFO_FULL (1 << 6) | ||
323 | #define TEGRA30_AHUB_SPDIF_LIVE_STATUS_DATA_TXFIFO_FULL (1 << 5) | ||
324 | #define TEGRA30_AHUB_SPDIF_LIVE_STATUS_DATA_RXFIFO_FULL (1 << 4) | ||
325 | #define TEGRA30_AHUB_SPDIF_LIVE_STATUS_USER_TXFIFO_EMPTY (1 << 3) | ||
326 | #define TEGRA30_AHUB_SPDIF_LIVE_STATUS_USER_RXFIFO_EMPTY (1 << 2) | ||
327 | #define TEGRA30_AHUB_SPDIF_LIVE_STATUS_DATA_TXFIFO_EMPTY (1 << 1) | ||
328 | #define TEGRA30_AHUB_SPDIF_LIVE_STATUS_DATA_RXFIFO_EMPTY (1 << 0) | ||
329 | |||
330 | /* TEGRA30_AHUB_I2S_INT_MASK */ | ||
331 | |||
332 | #define TEGRA30_AHUB_I2S_INT_MASK 0xb0 | ||
333 | |||
334 | /* TEGRA30_AHUB_DAM_INT_MASK */ | ||
335 | |||
336 | #define TEGRA30_AHUB_DAM_INT_MASK 0xb4 | ||
337 | |||
338 | /* TEGRA30_AHUB_SPDIF_INT_MASK */ | ||
339 | |||
340 | #define TEGRA30_AHUB_SPDIF_INT_MASK 0xbc | ||
341 | |||
342 | /* TEGRA30_AHUB_APBIF_INT_MASK */ | ||
343 | |||
344 | #define TEGRA30_AHUB_APBIF_INT_MASK 0xc0 | ||
345 | |||
346 | /* TEGRA30_AHUB_I2S_INT_STATUS */ | ||
347 | |||
348 | #define TEGRA30_AHUB_I2S_INT_STATUS 0xc8 | ||
349 | |||
350 | /* TEGRA30_AHUB_DAM_INT_STATUS */ | ||
351 | |||
352 | #define TEGRA30_AHUB_DAM_INT_STATUS 0xcc | ||
353 | |||
354 | /* TEGRA30_AHUB_SPDIF_INT_STATUS */ | ||
355 | |||
356 | #define TEGRA30_AHUB_SPDIF_INT_STATUS 0xd4 | ||
357 | |||
358 | /* TEGRA30_AHUB_APBIF_INT_STATUS */ | ||
359 | |||
360 | #define TEGRA30_AHUB_APBIF_INT_STATUS 0xd8 | ||
361 | |||
362 | /* TEGRA30_AHUB_I2S_INT_SOURCE */ | ||
363 | |||
364 | #define TEGRA30_AHUB_I2S_INT_SOURCE 0xe0 | ||
365 | |||
366 | /* TEGRA30_AHUB_DAM_INT_SOURCE */ | ||
367 | |||
368 | #define TEGRA30_AHUB_DAM_INT_SOURCE 0xe4 | ||
369 | |||
370 | /* TEGRA30_AHUB_SPDIF_INT_SOURCE */ | ||
371 | |||
372 | #define TEGRA30_AHUB_SPDIF_INT_SOURCE 0xec | ||
373 | |||
374 | /* TEGRA30_AHUB_APBIF_INT_SOURCE */ | ||
375 | |||
376 | #define TEGRA30_AHUB_APBIF_INT_SOURCE 0xf0 | ||
377 | |||
378 | /* TEGRA30_AHUB_I2S_INT_SET */ | ||
379 | |||
380 | #define TEGRA30_AHUB_I2S_INT_SET 0xf8 | ||
381 | |||
382 | /* TEGRA30_AHUB_DAM_INT_SET */ | ||
383 | |||
384 | #define TEGRA30_AHUB_DAM_INT_SET 0xfc | ||
385 | |||
386 | /* TEGRA30_AHUB_SPDIF_INT_SET */ | ||
387 | |||
388 | #define TEGRA30_AHUB_SPDIF_INT_SET 0x100 | ||
389 | |||
390 | /* TEGRA30_AHUB_APBIF_INT_SET */ | ||
391 | |||
392 | #define TEGRA30_AHUB_APBIF_INT_SET 0x104 | ||
393 | |||
394 | /* Registers within TEGRA30_AHUB_BASE */ | ||
395 | |||
396 | #define TEGRA30_AHUB_AUDIO_RX 0x0 | ||
397 | #define TEGRA30_AHUB_AUDIO_RX_STRIDE 0x4 | ||
398 | #define TEGRA30_AHUB_AUDIO_RX_COUNT 17 | ||
399 | /* This register repeats once for each entry in enum tegra30_ahub_rxcif */ | ||
400 | /* The fields in this register are 1 bit per entry in tegra30_ahub_txcif */ | ||
401 | |||
402 | /* apbif register count */ | ||
403 | #define TEGRA30_APBIF_CACHE_REG_COUNT_PER_CHANNEL ((TEGRA30_AHUB_CIF_RX_CTRL>>2) + 1) | ||
404 | #define TEGRA30_APBIF_CACHE_REG_COUNT ((TEGRA30_APBIF_CACHE_REG_COUNT_PER_CHANNEL + 1) * TEGRA30_AHUB_CHANNEL_CTRL_COUNT) | ||
405 | |||
406 | /* cache index to be skipped */ | ||
407 | #define TEGRA30_APBIF_CACHE_REG_INDEX_RSVD TEGRA30_APBIF_CACHE_REG_COUNT_PER_CHANNEL | ||
408 | #define TEGRA30_APBIF_CACHE_REG_INDEX_RSVD_STRIDE (TEGRA30_APBIF_CACHE_REG_COUNT_PER_CHANNEL + 1) | ||
409 | |||
410 | /* | ||
411 | * Terminology: | ||
412 | * AHUB: Audio Hub; a cross-bar switch between the audio devices: DMA FIFOs, | ||
413 | * I2S controllers, SPDIF controllers, and DAMs. | ||
414 | * XBAR: The core cross-bar component of the AHUB. | ||
415 | * CIF: Client Interface; the HW module connecting an audio device to the | ||
416 | * XBAR. | ||
417 | * DAM: Digital Audio Mixer: A HW module that mixes multiple audio streams, | ||
418 | * possibly including sample-rate conversion. | ||
419 | * | ||
420 | * Each TX CIF transmits data into the XBAR. Each RX CIF can receive audio | ||
421 | * transmitted by a particular TX CIF. | ||
422 | * | ||
423 | * This driver is currently very simplistic; many HW features are not | ||
424 | * exposed; DAMs are not supported, only 16-bit stereo audio is supported, | ||
425 | * etc. | ||
426 | */ | ||
427 | |||
428 | enum tegra30_ahub_txcif { | ||
429 | TEGRA30_AHUB_TXCIF_APBIF_TX0, | ||
430 | TEGRA30_AHUB_TXCIF_APBIF_TX1, | ||
431 | TEGRA30_AHUB_TXCIF_APBIF_TX2, | ||
432 | TEGRA30_AHUB_TXCIF_APBIF_TX3, | ||
433 | TEGRA30_AHUB_TXCIF_I2S0_TX0, | ||
434 | TEGRA30_AHUB_TXCIF_I2S1_TX0, | ||
435 | TEGRA30_AHUB_TXCIF_I2S2_TX0, | ||
436 | TEGRA30_AHUB_TXCIF_I2S3_TX0, | ||
437 | TEGRA30_AHUB_TXCIF_I2S4_TX0, | ||
438 | TEGRA30_AHUB_TXCIF_DAM0_TX0, | ||
439 | TEGRA30_AHUB_TXCIF_DAM1_TX0, | ||
440 | TEGRA30_AHUB_TXCIF_DAM2_TX0, | ||
441 | TEGRA30_AHUB_TXCIF_SPDIF_TX0, | ||
442 | TEGRA30_AHUB_TXCIF_SPDIF_TX1, | ||
443 | }; | ||
444 | |||
445 | enum tegra30_ahub_rxcif { | ||
446 | TEGRA30_AHUB_RXCIF_APBIF_RX0, | ||
447 | TEGRA30_AHUB_RXCIF_APBIF_RX1, | ||
448 | TEGRA30_AHUB_RXcIF_APBIF_RX2, | ||
449 | TEGRA30_AHUB_RXCIF_APBIF_RX3, | ||
450 | TEGRA30_AHUB_RXCIF_I2S0_RX0, | ||
451 | TEGRA30_AHUB_RXCIF_I2S1_RX0, | ||
452 | TEGRA30_AHUB_RXCIF_I2S2_RX0, | ||
453 | TEGRA30_AHUB_RXCIF_I2S3_RX0, | ||
454 | TEGRA30_AHUB_RXCIF_I2S4_RX0, | ||
455 | TEGRA30_AHUB_RXCIF_DAM0_RX0, | ||
456 | TEGRA30_AHUB_RXCIF_DAM0_RX1, | ||
457 | TEGRA30_AHUB_RXCIF_DAM1_RX0, | ||
458 | TEGRA30_AHUB_RXCIF_DAM2_RX1, | ||
459 | TEGRA30_AHUB_RXCIF_DAM3_RX0, | ||
460 | TEGRA30_AHUB_RXCIF_DAM3_RX1, | ||
461 | TEGRA30_AHUB_RXCIF_SPDIF_RX0, | ||
462 | TEGRA30_AHUB_RXCIF_SPDIF_RX1, | ||
463 | }; | ||
464 | |||
465 | extern void tegra30_ahub_enable_clocks(void); | ||
466 | extern void tegra30_ahub_disable_clocks(void); | ||
467 | |||
468 | extern int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif, | ||
469 | unsigned long *fiforeg, | ||
470 | unsigned long *reqsel); | ||
471 | extern int tegra30_ahub_set_rx_cif_channels(enum tegra30_ahub_rxcif rxcif, | ||
472 | unsigned int audio_ch, | ||
473 | unsigned int client_ch); | ||
474 | extern int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif); | ||
475 | extern int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif); | ||
476 | extern int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif); | ||
477 | |||
478 | extern int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif, | ||
479 | unsigned long *fiforeg, | ||
480 | unsigned long *reqsel); | ||
481 | extern int tegra30_ahub_set_tx_cif_channels(enum tegra30_ahub_txcif txcif, | ||
482 | unsigned int audio_ch, | ||
483 | unsigned int client_ch); | ||
484 | extern int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif); | ||
485 | extern int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif); | ||
486 | extern int tegra30_ahub_free_tx_fifo(enum tegra30_ahub_txcif txcif); | ||
487 | |||
488 | extern int tegra30_ahub_set_rx_cif_source(enum tegra30_ahub_rxcif rxcif, | ||
489 | enum tegra30_ahub_txcif txcif); | ||
490 | extern int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif); | ||
491 | |||
492 | #ifdef CONFIG_PM | ||
493 | extern int tegra30_ahub_apbif_resume(void); | ||
494 | #endif | ||
495 | |||
496 | struct tegra30_ahub { | ||
497 | struct device *dev; | ||
498 | struct clk *clk_d_audio; | ||
499 | struct clk *clk_apbif; | ||
500 | resource_size_t apbif_addr; | ||
501 | void __iomem *apbif_regs; | ||
502 | void __iomem *audio_regs; | ||
503 | DECLARE_BITMAP(rx_usage, TEGRA30_AHUB_CHANNEL_CTRL_COUNT); | ||
504 | DECLARE_BITMAP(tx_usage, TEGRA30_AHUB_CHANNEL_CTRL_COUNT); | ||
505 | struct dentry *debug; | ||
506 | #ifdef CONFIG_PM | ||
507 | u32 ahub_reg_cache[TEGRA30_AHUB_AUDIO_RX_COUNT]; | ||
508 | u32 apbif_reg_cache[TEGRA30_APBIF_CACHE_REG_COUNT]; | ||
509 | #endif | ||
510 | }; | ||
511 | |||
512 | #endif | ||
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_i2s.c b/sound/soc/tegra/tegra30_i2s.c new file mode 100644 index 00000000000..02d1038ea36 --- /dev/null +++ b/sound/soc/tegra/tegra30_i2s.c | |||
@@ -0,0 +1,949 @@ | |||
1 | /* | ||
2 | * tegra30_i2s.c - Tegra 30 I2S driver | ||
3 | * | ||
4 | * Author: Stephen Warren <swarren@nvidia.com> | ||
5 | * Copyright (c) 2010-2011, NVIDIA Corporation. | ||
6 | * | ||
7 | * Based on code copyright/by: | ||
8 | * | ||
9 | * Copyright (c) 2009-2010, 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 <sound/core.h> | ||
41 | #include <sound/pcm.h> | ||
42 | #include <sound/pcm_params.h> | ||
43 | #include <sound/soc.h> | ||
44 | |||
45 | #include "tegra30_ahub.h" | ||
46 | #include "tegra30_dam.h" | ||
47 | #include "tegra30_i2s.h" | ||
48 | |||
49 | #define DRV_NAME "tegra30-i2s" | ||
50 | |||
51 | static struct tegra30_i2s i2scont[TEGRA30_NR_I2S_IFC]; | ||
52 | |||
53 | static inline void tegra30_i2s_write(struct tegra30_i2s *i2s, u32 reg, u32 val) | ||
54 | { | ||
55 | #ifdef CONFIG_PM | ||
56 | i2s->reg_cache[reg >> 2] = val; | ||
57 | #endif | ||
58 | __raw_writel(val, i2s->regs + reg); | ||
59 | } | ||
60 | |||
61 | static inline u32 tegra30_i2s_read(struct tegra30_i2s *i2s, u32 reg) | ||
62 | { | ||
63 | return __raw_readl(i2s->regs + reg); | ||
64 | } | ||
65 | |||
66 | static void tegra30_i2s_enable_clocks(struct tegra30_i2s *i2s) | ||
67 | { | ||
68 | tegra30_ahub_enable_clocks(); | ||
69 | clk_enable(i2s->clk_i2s); | ||
70 | } | ||
71 | |||
72 | static void tegra30_i2s_disable_clocks(struct tegra30_i2s *i2s) | ||
73 | { | ||
74 | clk_disable(i2s->clk_i2s); | ||
75 | tegra30_ahub_disable_clocks(); | ||
76 | } | ||
77 | |||
78 | #ifdef CONFIG_DEBUG_FS | ||
79 | static int tegra30_i2s_show(struct seq_file *s, void *unused) | ||
80 | { | ||
81 | #define REG(r) { r, #r } | ||
82 | static const struct { | ||
83 | int offset; | ||
84 | const char *name; | ||
85 | } regs[] = { | ||
86 | REG(TEGRA30_I2S_CTRL), | ||
87 | REG(TEGRA30_I2S_TIMING), | ||
88 | REG(TEGRA30_I2S_OFFSET), | ||
89 | REG(TEGRA30_I2S_CH_CTRL), | ||
90 | REG(TEGRA30_I2S_SLOT_CTRL), | ||
91 | REG(TEGRA30_I2S_CIF_TX_CTRL), | ||
92 | REG(TEGRA30_I2S_CIF_RX_CTRL), | ||
93 | REG(TEGRA30_I2S_FLOWCTL), | ||
94 | REG(TEGRA30_I2S_TX_STEP), | ||
95 | REG(TEGRA30_I2S_FLOW_STATUS), | ||
96 | REG(TEGRA30_I2S_FLOW_TOTAL), | ||
97 | REG(TEGRA30_I2S_FLOW_OVER), | ||
98 | REG(TEGRA30_I2S_FLOW_UNDER), | ||
99 | REG(TEGRA30_I2S_LCOEF_1_4_0), | ||
100 | REG(TEGRA30_I2S_LCOEF_1_4_1), | ||
101 | REG(TEGRA30_I2S_LCOEF_1_4_2), | ||
102 | REG(TEGRA30_I2S_LCOEF_1_4_3), | ||
103 | REG(TEGRA30_I2S_LCOEF_1_4_4), | ||
104 | REG(TEGRA30_I2S_LCOEF_1_4_5), | ||
105 | REG(TEGRA30_I2S_LCOEF_2_4_0), | ||
106 | REG(TEGRA30_I2S_LCOEF_2_4_1), | ||
107 | REG(TEGRA30_I2S_LCOEF_2_4_2), | ||
108 | }; | ||
109 | #undef REG | ||
110 | |||
111 | struct tegra30_i2s *i2s = s->private; | ||
112 | int i; | ||
113 | |||
114 | tegra30_i2s_enable_clocks(i2s); | ||
115 | |||
116 | for (i = 0; i < ARRAY_SIZE(regs); i++) { | ||
117 | u32 val = tegra30_i2s_read(i2s, regs[i].offset); | ||
118 | seq_printf(s, "%s = %08x\n", regs[i].name, val); | ||
119 | } | ||
120 | |||
121 | tegra30_i2s_disable_clocks(i2s); | ||
122 | |||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | static int tegra30_i2s_debug_open(struct inode *inode, struct file *file) | ||
127 | { | ||
128 | return single_open(file, tegra30_i2s_show, inode->i_private); | ||
129 | } | ||
130 | |||
131 | static const struct file_operations tegra30_i2s_debug_fops = { | ||
132 | .open = tegra30_i2s_debug_open, | ||
133 | .read = seq_read, | ||
134 | .llseek = seq_lseek, | ||
135 | .release = single_release, | ||
136 | }; | ||
137 | |||
138 | static void tegra30_i2s_debug_add(struct tegra30_i2s *i2s, int id) | ||
139 | { | ||
140 | char name[] = DRV_NAME ".0"; | ||
141 | |||
142 | snprintf(name, sizeof(name), DRV_NAME".%1d", id); | ||
143 | i2s->debug = debugfs_create_file(name, S_IRUGO, snd_soc_debugfs_root, | ||
144 | i2s, &tegra30_i2s_debug_fops); | ||
145 | } | ||
146 | |||
147 | static void tegra30_i2s_debug_remove(struct tegra30_i2s *i2s) | ||
148 | { | ||
149 | if (i2s->debug) | ||
150 | debugfs_remove(i2s->debug); | ||
151 | } | ||
152 | #else | ||
153 | static inline void tegra30_i2s_debug_add(struct tegra30_i2s *i2s, int id) | ||
154 | { | ||
155 | } | ||
156 | |||
157 | static inline void tegra30_i2s_debug_remove(struct tegra30_i2s *i2s) | ||
158 | { | ||
159 | } | ||
160 | #endif | ||
161 | |||
162 | int tegra30_i2s_startup(struct snd_pcm_substream *substream, | ||
163 | struct snd_soc_dai *dai) | ||
164 | { | ||
165 | struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai); | ||
166 | int ret; | ||
167 | |||
168 | tegra30_i2s_enable_clocks(i2s); | ||
169 | |||
170 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
171 | /* increment the playback ref count */ | ||
172 | i2s->playback_ref_count++; | ||
173 | |||
174 | ret = tegra30_ahub_allocate_tx_fifo(&i2s->txcif, | ||
175 | &i2s->playback_dma_data.addr, | ||
176 | &i2s->playback_dma_data.req_sel); | ||
177 | i2s->playback_dma_data.wrap = 4; | ||
178 | i2s->playback_dma_data.width = 32; | ||
179 | |||
180 | if (!i2s->is_dam_used) | ||
181 | tegra30_ahub_set_rx_cif_source( | ||
182 | TEGRA30_AHUB_RXCIF_I2S0_RX0 + i2s->id, | ||
183 | i2s->txcif); | ||
184 | } else { | ||
185 | ret = tegra30_ahub_allocate_rx_fifo(&i2s->rxcif, | ||
186 | &i2s->capture_dma_data.addr, | ||
187 | &i2s->capture_dma_data.req_sel); | ||
188 | i2s->capture_dma_data.wrap = 4; | ||
189 | i2s->capture_dma_data.width = 32; | ||
190 | tegra30_ahub_set_rx_cif_source(i2s->rxcif, | ||
191 | TEGRA30_AHUB_TXCIF_I2S0_TX0 + i2s->id); | ||
192 | } | ||
193 | |||
194 | tegra30_i2s_disable_clocks(i2s); | ||
195 | |||
196 | return ret; | ||
197 | } | ||
198 | |||
199 | void tegra30_i2s_shutdown(struct snd_pcm_substream *substream, | ||
200 | struct snd_soc_dai *dai) | ||
201 | { | ||
202 | struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai); | ||
203 | |||
204 | tegra30_i2s_enable_clocks(i2s); | ||
205 | |||
206 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
207 | if (i2s->playback_ref_count == 1) | ||
208 | tegra30_ahub_unset_rx_cif_source( | ||
209 | TEGRA30_AHUB_RXCIF_I2S0_RX0 + i2s->id); | ||
210 | |||
211 | /* free the apbif dma channel*/ | ||
212 | tegra30_ahub_free_tx_fifo(i2s->txcif); | ||
213 | |||
214 | /* decrement the playback ref count */ | ||
215 | i2s->playback_ref_count--; | ||
216 | } else { | ||
217 | tegra30_ahub_unset_rx_cif_source(i2s->rxcif); | ||
218 | tegra30_ahub_free_rx_fifo(i2s->rxcif); | ||
219 | } | ||
220 | |||
221 | tegra30_i2s_disable_clocks(i2s); | ||
222 | } | ||
223 | |||
224 | static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai, | ||
225 | unsigned int fmt) | ||
226 | { | ||
227 | struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai); | ||
228 | |||
229 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
230 | case SND_SOC_DAIFMT_NB_NF: | ||
231 | break; | ||
232 | default: | ||
233 | return -EINVAL; | ||
234 | } | ||
235 | |||
236 | i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_MASTER_ENABLE; | ||
237 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
238 | case SND_SOC_DAIFMT_CBS_CFS: | ||
239 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_MASTER_ENABLE; | ||
240 | break; | ||
241 | case SND_SOC_DAIFMT_CBM_CFM: | ||
242 | break; | ||
243 | default: | ||
244 | return -EINVAL; | ||
245 | } | ||
246 | |||
247 | i2s->reg_ctrl &= ~(TEGRA30_I2S_CTRL_FRAME_FORMAT_MASK | | ||
248 | TEGRA30_I2S_CTRL_LRCK_MASK); | ||
249 | i2s->reg_ch_ctrl &= ~TEGRA30_I2S_CH_CTRL_EGDE_CTRL_MASK; | ||
250 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
251 | case SND_SOC_DAIFMT_DSP_A: | ||
252 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC; | ||
253 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_R_LOW; | ||
254 | i2s->reg_ch_ctrl |= TEGRA30_I2S_CH_CTRL_EGDE_CTRL_NEG_EDGE; | ||
255 | break; | ||
256 | case SND_SOC_DAIFMT_DSP_B: | ||
257 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC; | ||
258 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_R_LOW; | ||
259 | i2s->reg_ch_ctrl |= TEGRA30_I2S_CH_CTRL_EGDE_CTRL_POS_EDGE; | ||
260 | break; | ||
261 | case SND_SOC_DAIFMT_I2S: | ||
262 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK; | ||
263 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW; | ||
264 | i2s->reg_ch_ctrl |= TEGRA30_I2S_CH_CTRL_EGDE_CTRL_POS_EDGE; | ||
265 | break; | ||
266 | case SND_SOC_DAIFMT_RIGHT_J: | ||
267 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK; | ||
268 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_R_LOW; | ||
269 | i2s->reg_ch_ctrl |= TEGRA30_I2S_CH_CTRL_EGDE_CTRL_POS_EDGE; | ||
270 | break; | ||
271 | case SND_SOC_DAIFMT_LEFT_J: | ||
272 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK; | ||
273 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_R_LOW; | ||
274 | i2s->reg_ch_ctrl |= TEGRA30_I2S_CH_CTRL_EGDE_CTRL_POS_EDGE; | ||
275 | break; | ||
276 | default: | ||
277 | return -EINVAL; | ||
278 | } | ||
279 | |||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream, | ||
284 | struct snd_pcm_hw_params *params, | ||
285 | struct snd_soc_dai *dai) | ||
286 | { | ||
287 | struct device *dev = substream->pcm->card->dev; | ||
288 | struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai); | ||
289 | u32 val; | ||
290 | int ret, sample_size, srate, i2sclock, bitcnt, sym_bitclk; | ||
291 | int i2s_client_ch; | ||
292 | |||
293 | i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_BIT_SIZE_MASK; | ||
294 | switch (params_format(params)) { | ||
295 | case SNDRV_PCM_FORMAT_S16_LE: | ||
296 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_BIT_SIZE_16; | ||
297 | sample_size = 16; | ||
298 | break; | ||
299 | default: | ||
300 | return -EINVAL; | ||
301 | } | ||
302 | |||
303 | srate = params_rate(params); | ||
304 | |||
305 | if (i2s->reg_ctrl & TEGRA30_I2S_CTRL_MASTER_ENABLE) { | ||
306 | i2sclock = srate * params_channels(params) * sample_size; | ||
307 | |||
308 | /* Additional "* 4" is needed for FSYNC mode */ | ||
309 | if (i2s->reg_ctrl & TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC) | ||
310 | i2sclock *= 4; | ||
311 | ret = clk_set_parent(i2s->clk_i2s, i2s->clk_pll_a_out0); | ||
312 | if (ret) { | ||
313 | dev_err(dev, "Can't set parent of I2S clock\n"); | ||
314 | return ret; | ||
315 | } | ||
316 | |||
317 | ret = clk_set_rate(i2s->clk_i2s, i2sclock); | ||
318 | if (ret) { | ||
319 | dev_err(dev, "Can't set I2S clock rate: %d\n", ret); | ||
320 | return ret; | ||
321 | } | ||
322 | |||
323 | if (i2s->reg_ctrl & TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC) { | ||
324 | bitcnt = (i2sclock / srate) - 1; | ||
325 | sym_bitclk = !(i2sclock % srate); | ||
326 | } else { | ||
327 | bitcnt = (i2sclock / (2 * srate)) - 1; | ||
328 | sym_bitclk = !(i2sclock % (2 * srate)); | ||
329 | } | ||
330 | val = bitcnt << TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT; | ||
331 | |||
332 | if (!sym_bitclk) | ||
333 | val |= TEGRA30_I2S_TIMING_NON_SYM_ENABLE; | ||
334 | |||
335 | tegra30_i2s_enable_clocks(i2s); | ||
336 | |||
337 | tegra30_i2s_write(i2s, TEGRA30_I2S_TIMING, val); | ||
338 | } else { | ||
339 | i2sclock = srate * params_channels(params) * sample_size; | ||
340 | |||
341 | /* Additional "* 2" is needed for FSYNC mode */ | ||
342 | if (i2s->reg_ctrl & TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC) | ||
343 | i2sclock *= 2; | ||
344 | |||
345 | ret = clk_set_rate(i2s->clk_i2s_sync, i2sclock); | ||
346 | if (ret) { | ||
347 | dev_err(dev, "Can't set I2S sync clock rate\n"); | ||
348 | return ret; | ||
349 | } | ||
350 | |||
351 | ret = clk_set_rate(i2s->clk_audio_2x, i2sclock); | ||
352 | if (ret) { | ||
353 | dev_err(dev, "Can't set I2S sync clock rate\n"); | ||
354 | return ret; | ||
355 | } | ||
356 | |||
357 | ret = clk_set_parent(i2s->clk_i2s, i2s->clk_audio_2x); | ||
358 | if (ret) { | ||
359 | dev_err(dev, "Can't set parent of audio2x clock\n"); | ||
360 | return ret; | ||
361 | } | ||
362 | |||
363 | tegra30_i2s_enable_clocks(i2s); | ||
364 | } | ||
365 | |||
366 | i2s_client_ch = (i2s->reg_ctrl & TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC) ? | ||
367 | params_channels(params) : 2; | ||
368 | |||
369 | val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) | | ||
370 | ((params_channels(params) - 1) << | ||
371 | TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | | ||
372 | ((i2s_client_ch - 1) << | ||
373 | TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) | | ||
374 | TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16 | | ||
375 | TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16; | ||
376 | |||
377 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
378 | val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX; | ||
379 | tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_RX_CTRL, val); | ||
380 | |||
381 | tegra30_ahub_set_tx_cif_channels(i2s->txcif, | ||
382 | params_channels(params), | ||
383 | params_channels(params)); | ||
384 | } else { | ||
385 | val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX; | ||
386 | tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_TX_CTRL, val); | ||
387 | |||
388 | tegra30_ahub_set_rx_cif_channels(i2s->rxcif, | ||
389 | params_channels(params), | ||
390 | params_channels(params)); | ||
391 | } | ||
392 | |||
393 | val = (1 << TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_SHIFT) | | ||
394 | (1 << TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT); | ||
395 | tegra30_i2s_write(i2s, TEGRA30_I2S_OFFSET, val); | ||
396 | |||
397 | tegra30_i2s_write(i2s, TEGRA30_I2S_CH_CTRL, i2s->reg_ch_ctrl); | ||
398 | |||
399 | val = tegra30_i2s_read(i2s, TEGRA30_I2S_SLOT_CTRL); | ||
400 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
401 | val &= ~TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_MASK; | ||
402 | val |= (1 << TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_SHIFT); | ||
403 | } else { | ||
404 | val &= ~TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_MASK; | ||
405 | val |= (1 << TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_SHIFT); | ||
406 | } | ||
407 | tegra30_i2s_write(i2s, TEGRA30_I2S_SLOT_CTRL, val); | ||
408 | |||
409 | tegra30_i2s_disable_clocks(i2s); | ||
410 | |||
411 | return 0; | ||
412 | } | ||
413 | |||
414 | static void tegra30_i2s_start_playback(struct tegra30_i2s *i2s) | ||
415 | { | ||
416 | tegra30_ahub_enable_tx_fifo(i2s->txcif); | ||
417 | /* if this is the only user of i2s tx then enable it*/ | ||
418 | if (i2s->playback_ref_count == 1) { | ||
419 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_TX; | ||
420 | tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl); | ||
421 | } | ||
422 | } | ||
423 | |||
424 | static void tegra30_i2s_stop_playback(struct tegra30_i2s *i2s) | ||
425 | { | ||
426 | tegra30_ahub_disable_tx_fifo(i2s->txcif); | ||
427 | /* if this is the only user of i2s tx then disable it*/ | ||
428 | if (i2s->playback_ref_count == 1) { | ||
429 | i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_TX; | ||
430 | tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl); | ||
431 | } | ||
432 | } | ||
433 | |||
434 | static void tegra30_i2s_start_capture(struct tegra30_i2s *i2s) | ||
435 | { | ||
436 | tegra30_ahub_enable_rx_fifo(i2s->rxcif); | ||
437 | if (!i2s->is_call_mode_rec) { | ||
438 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_RX; | ||
439 | tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl); | ||
440 | } | ||
441 | } | ||
442 | |||
443 | static void tegra30_i2s_stop_capture(struct tegra30_i2s *i2s) | ||
444 | { | ||
445 | tegra30_ahub_disable_rx_fifo(i2s->rxcif); | ||
446 | if (!i2s->is_call_mode_rec) { | ||
447 | i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_RX; | ||
448 | tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl); | ||
449 | } | ||
450 | } | ||
451 | |||
452 | static int tegra30_i2s_trigger(struct snd_pcm_substream *substream, int cmd, | ||
453 | struct snd_soc_dai *dai) | ||
454 | { | ||
455 | struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai); | ||
456 | |||
457 | switch (cmd) { | ||
458 | case SNDRV_PCM_TRIGGER_START: | ||
459 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
460 | case SNDRV_PCM_TRIGGER_RESUME: | ||
461 | tegra30_i2s_enable_clocks(i2s); | ||
462 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
463 | tegra30_i2s_start_playback(i2s); | ||
464 | else | ||
465 | tegra30_i2s_start_capture(i2s); | ||
466 | break; | ||
467 | case SNDRV_PCM_TRIGGER_STOP: | ||
468 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
469 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
470 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
471 | tegra30_i2s_stop_playback(i2s); | ||
472 | else | ||
473 | tegra30_i2s_stop_capture(i2s); | ||
474 | tegra30_i2s_disable_clocks(i2s); | ||
475 | break; | ||
476 | default: | ||
477 | return -EINVAL; | ||
478 | } | ||
479 | |||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | static int tegra30_i2s_probe(struct snd_soc_dai *dai) | ||
484 | { | ||
485 | struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai); | ||
486 | #ifdef CONFIG_PM | ||
487 | int i; | ||
488 | #endif | ||
489 | |||
490 | dai->capture_dma_data = &i2s->capture_dma_data; | ||
491 | dai->playback_dma_data = &i2s->playback_dma_data; | ||
492 | |||
493 | #ifdef CONFIG_PM | ||
494 | tegra30_i2s_enable_clocks(i2s); | ||
495 | |||
496 | /*cache the POR values of i2s regs*/ | ||
497 | for (i = 0; i < ((TEGRA30_I2S_CIF_TX_CTRL>>2) + 1); i++) | ||
498 | i2s->reg_cache[i] = tegra30_i2s_read(i2s, i<<2); | ||
499 | |||
500 | tegra30_i2s_disable_clocks(i2s); | ||
501 | #endif | ||
502 | |||
503 | return 0; | ||
504 | } | ||
505 | |||
506 | #ifdef CONFIG_PM | ||
507 | int tegra30_i2s_resume(struct snd_soc_dai *cpu_dai) | ||
508 | { | ||
509 | struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai); | ||
510 | int i, ret = 0; | ||
511 | |||
512 | tegra30_i2s_enable_clocks(i2s); | ||
513 | |||
514 | /*restore the i2s regs*/ | ||
515 | for (i = 0; i < ((TEGRA30_I2S_CIF_TX_CTRL>>2) + 1); i++) | ||
516 | tegra30_i2s_write(i2s, i<<2, i2s->reg_cache[i]); | ||
517 | |||
518 | tegra30_ahub_apbif_resume(); | ||
519 | |||
520 | tegra30_i2s_disable_clocks(i2s); | ||
521 | |||
522 | if (i2s->dam_ch_refcount) | ||
523 | ret = tegra30_dam_resume(i2s->dam_ifc); | ||
524 | |||
525 | return ret; | ||
526 | } | ||
527 | #else | ||
528 | #define tegra30_i2s_resume NULL | ||
529 | #endif | ||
530 | |||
531 | static struct snd_soc_dai_ops tegra30_i2s_dai_ops = { | ||
532 | .startup = tegra30_i2s_startup, | ||
533 | .shutdown = tegra30_i2s_shutdown, | ||
534 | .set_fmt = tegra30_i2s_set_fmt, | ||
535 | .hw_params = tegra30_i2s_hw_params, | ||
536 | .trigger = tegra30_i2s_trigger, | ||
537 | }; | ||
538 | |||
539 | #define TEGRA30_I2S_DAI(id) \ | ||
540 | { \ | ||
541 | .name = DRV_NAME "." #id, \ | ||
542 | .probe = tegra30_i2s_probe, \ | ||
543 | .resume = tegra30_i2s_resume, \ | ||
544 | .playback = { \ | ||
545 | .channels_min = 1, \ | ||
546 | .channels_max = 2, \ | ||
547 | .rates = SNDRV_PCM_RATE_8000_96000, \ | ||
548 | .formats = SNDRV_PCM_FMTBIT_S16_LE, \ | ||
549 | }, \ | ||
550 | .capture = { \ | ||
551 | .channels_min = 1, \ | ||
552 | .channels_max = 2, \ | ||
553 | .rates = SNDRV_PCM_RATE_8000_96000, \ | ||
554 | .formats = SNDRV_PCM_FMTBIT_S16_LE, \ | ||
555 | }, \ | ||
556 | .ops = &tegra30_i2s_dai_ops, \ | ||
557 | .symmetric_rates = 1, \ | ||
558 | } | ||
559 | |||
560 | struct snd_soc_dai_driver tegra30_i2s_dai[] = { | ||
561 | TEGRA30_I2S_DAI(0), | ||
562 | TEGRA30_I2S_DAI(1), | ||
563 | TEGRA30_I2S_DAI(2), | ||
564 | TEGRA30_I2S_DAI(3), | ||
565 | TEGRA30_I2S_DAI(4), | ||
566 | }; | ||
567 | |||
568 | static int configure_baseband_i2s(struct tegra30_i2s *i2s, int is_i2smaster, | ||
569 | int is_formatdsp, int channels, int rate, int bitsize) | ||
570 | { | ||
571 | u32 val; | ||
572 | int i2sclock, bitcnt; | ||
573 | |||
574 | i2s->reg_ctrl &= ~(TEGRA30_I2S_CTRL_FRAME_FORMAT_MASK | | ||
575 | TEGRA30_I2S_CTRL_LRCK_MASK | | ||
576 | TEGRA30_I2S_CTRL_MASTER_ENABLE); | ||
577 | i2s->reg_ch_ctrl &= ~TEGRA30_I2S_CH_CTRL_EGDE_CTRL_MASK; | ||
578 | |||
579 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_BIT_SIZE_16; | ||
580 | |||
581 | if (is_i2smaster) | ||
582 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_MASTER_ENABLE; | ||
583 | |||
584 | if (is_formatdsp) { | ||
585 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC; | ||
586 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_R_LOW; | ||
587 | i2s->reg_ch_ctrl |= TEGRA30_I2S_CH_CTRL_EGDE_CTRL_NEG_EDGE; | ||
588 | } else { | ||
589 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK; | ||
590 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW; | ||
591 | i2s->reg_ch_ctrl |= TEGRA30_I2S_CH_CTRL_EGDE_CTRL_POS_EDGE; | ||
592 | } | ||
593 | |||
594 | tegra30_i2s_write(i2s, TEGRA30_I2S_CH_CTRL, i2s->reg_ch_ctrl); | ||
595 | |||
596 | val = tegra30_i2s_read(i2s, TEGRA30_I2S_SLOT_CTRL); | ||
597 | val &= ~(TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_MASK | | ||
598 | TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_MASK); | ||
599 | val |= (1 << TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_SHIFT | | ||
600 | 1 << TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_SHIFT); | ||
601 | tegra30_i2s_write(i2s, TEGRA30_I2S_SLOT_CTRL, val); | ||
602 | |||
603 | val = (1 << TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_SHIFT) | | ||
604 | (1 << TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT); | ||
605 | tegra30_i2s_write(i2s, TEGRA30_I2S_OFFSET, val); | ||
606 | |||
607 | i2sclock = rate * channels * bitsize * 2; | ||
608 | |||
609 | /* additional 8 for baseband */ | ||
610 | if (is_formatdsp) | ||
611 | i2sclock *= 8; | ||
612 | |||
613 | clk_set_rate(i2s->clk_i2s, i2sclock); | ||
614 | |||
615 | if (is_formatdsp) { | ||
616 | bitcnt = (i2sclock/rate) - 1; | ||
617 | val = bitcnt << TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT; | ||
618 | if (i2sclock % (rate)) | ||
619 | val |= TEGRA30_I2S_TIMING_NON_SYM_ENABLE; | ||
620 | } else { | ||
621 | bitcnt = (i2sclock/(2*rate)) - 1; | ||
622 | val = bitcnt << TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT; | ||
623 | if (i2sclock % (2*rate)) | ||
624 | val |= TEGRA30_I2S_TIMING_NON_SYM_ENABLE; | ||
625 | } | ||
626 | |||
627 | tegra30_i2s_write(i2s, TEGRA30_I2S_TIMING, val); | ||
628 | |||
629 | /* configure the i2s cif*/ | ||
630 | val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) | | ||
631 | ((channels - 1) << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | | ||
632 | ((channels - 1) << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) | | ||
633 | TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16 | | ||
634 | TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16; | ||
635 | val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX; | ||
636 | tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_RX_CTRL, val); | ||
637 | |||
638 | val &= ~TEGRA30_AUDIOCIF_CTRL_DIRECTION_MASK; | ||
639 | val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX; | ||
640 | tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_TX_CTRL, val); | ||
641 | |||
642 | return 0; | ||
643 | } | ||
644 | |||
645 | static int configure_dam(struct tegra30_i2s *i2s, int out_channel, | ||
646 | int out_rate, int out_bitsize, int in_channels, | ||
647 | int in_rate, int in_bitsize) | ||
648 | { | ||
649 | |||
650 | if (!i2s->dam_ch_refcount) | ||
651 | i2s->dam_ifc = tegra30_dam_allocate_controller(); | ||
652 | |||
653 | tegra30_dam_allocate_channel(i2s->dam_ifc, TEGRA30_DAM_CHIN0_SRC); | ||
654 | i2s->dam_ch_refcount++; | ||
655 | tegra30_dam_enable_clock(i2s->dam_ifc); | ||
656 | tegra30_dam_set_samplerate(i2s->dam_ifc, TEGRA30_DAM_CHOUT, out_rate); | ||
657 | tegra30_dam_set_samplerate(i2s->dam_ifc, TEGRA30_DAM_CHIN0_SRC, | ||
658 | in_rate); | ||
659 | tegra30_dam_set_gain(i2s->dam_ifc, TEGRA30_DAM_CHIN0_SRC, 0x1000); | ||
660 | tegra30_dam_set_acif(i2s->dam_ifc, TEGRA30_DAM_CHIN0_SRC, | ||
661 | in_channels, in_bitsize, 1, 16); | ||
662 | tegra30_dam_set_acif(i2s->dam_ifc, TEGRA30_DAM_CHOUT, | ||
663 | out_channel, out_bitsize, out_channel, out_bitsize); | ||
664 | |||
665 | return 0; | ||
666 | } | ||
667 | |||
668 | |||
669 | int tegra30_make_voice_call_connections(struct codec_config *codec_info, | ||
670 | struct codec_config *bb_info) | ||
671 | { | ||
672 | struct tegra30_i2s *codec_i2s; | ||
673 | struct tegra30_i2s *bb_i2s; | ||
674 | |||
675 | codec_i2s = &i2scont[codec_info->i2s_id]; | ||
676 | bb_i2s = &i2scont[bb_info->i2s_id]; | ||
677 | tegra30_i2s_enable_clocks(codec_i2s); | ||
678 | tegra30_i2s_enable_clocks(bb_i2s); | ||
679 | |||
680 | /* increment the codec i2s playback ref count */ | ||
681 | codec_i2s->playback_ref_count++; | ||
682 | bb_i2s->playback_ref_count++; | ||
683 | |||
684 | /*Configure codec i2s*/ | ||
685 | configure_baseband_i2s(codec_i2s, codec_info->is_i2smaster, | ||
686 | codec_info->is_format_dsp, codec_info->channels, | ||
687 | codec_info->rate, codec_info->bitsize); | ||
688 | |||
689 | /*Configure bb i2s*/ | ||
690 | configure_baseband_i2s(bb_i2s, bb_info->is_i2smaster, | ||
691 | bb_info->is_format_dsp, bb_info->channels, | ||
692 | bb_info->rate, bb_info->bitsize); | ||
693 | |||
694 | /*configure codec dam*/ | ||
695 | configure_dam(codec_i2s, codec_info->channels, | ||
696 | codec_info->rate, codec_info->bitsize, bb_info->channels, | ||
697 | bb_info->rate, bb_info->bitsize); | ||
698 | |||
699 | /*configure bb dam*/ | ||
700 | configure_dam(bb_i2s, bb_info->channels, | ||
701 | bb_info->rate, bb_info->bitsize, codec_info->channels, | ||
702 | codec_info->rate, codec_info->bitsize); | ||
703 | |||
704 | /*make ahub connections*/ | ||
705 | |||
706 | /* if this is the only user of i2s tx then make ahub i2s rx connection*/ | ||
707 | if (codec_i2s->playback_ref_count == 1) { | ||
708 | tegra30_ahub_set_rx_cif_source(TEGRA30_AHUB_RXCIF_I2S0_RX0 + | ||
709 | codec_info->i2s_id, TEGRA30_AHUB_TXCIF_DAM0_TX0 + | ||
710 | codec_i2s->dam_ifc); | ||
711 | } | ||
712 | |||
713 | tegra30_ahub_set_rx_cif_source(TEGRA30_AHUB_RXCIF_I2S0_RX0 + | ||
714 | bb_info->i2s_id, TEGRA30_AHUB_TXCIF_DAM0_TX0 + | ||
715 | bb_i2s->dam_ifc); | ||
716 | tegra30_ahub_set_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX0 + | ||
717 | (codec_i2s->dam_ifc*2), TEGRA30_AHUB_TXCIF_I2S0_TX0 + | ||
718 | bb_info->i2s_id); | ||
719 | tegra30_ahub_set_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX0 + | ||
720 | (bb_i2s->dam_ifc*2), TEGRA30_AHUB_TXCIF_I2S0_TX0 + | ||
721 | codec_info->i2s_id); | ||
722 | |||
723 | /*enable dam and i2s*/ | ||
724 | tegra30_dam_enable(codec_i2s->dam_ifc, TEGRA30_DAM_ENABLE, | ||
725 | TEGRA30_DAM_CHIN0_SRC); | ||
726 | tegra30_dam_enable(bb_i2s->dam_ifc, TEGRA30_DAM_ENABLE, | ||
727 | TEGRA30_DAM_CHIN0_SRC); | ||
728 | |||
729 | /* if this is the only user of i2s tx then enable it*/ | ||
730 | if (codec_i2s->playback_ref_count == 1) | ||
731 | codec_i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_TX; | ||
732 | |||
733 | codec_i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_RX; | ||
734 | tegra30_i2s_write(codec_i2s, TEGRA30_I2S_CTRL, | ||
735 | codec_i2s->reg_ctrl); | ||
736 | bb_i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_TX; | ||
737 | bb_i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_RX; | ||
738 | tegra30_i2s_write(bb_i2s, TEGRA30_I2S_CTRL, | ||
739 | bb_i2s->reg_ctrl); | ||
740 | |||
741 | return 0; | ||
742 | } | ||
743 | |||
744 | int tegra30_break_voice_call_connections(struct codec_config *codec_info, | ||
745 | struct codec_config *bb_info) | ||
746 | { | ||
747 | struct tegra30_i2s *codec_i2s; | ||
748 | struct tegra30_i2s *bb_i2s; | ||
749 | |||
750 | codec_i2s = &i2scont[codec_info->i2s_id]; | ||
751 | bb_i2s = &i2scont[bb_info->i2s_id]; | ||
752 | |||
753 | /* disconnect the ahub connections */ | ||
754 | |||
755 | /* if this is the only user of i2s tx then break ahub | ||
756 | i2s rx connection */ | ||
757 | if (codec_i2s->playback_ref_count == 1) | ||
758 | tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_I2S0_RX0 | ||
759 | + codec_info->i2s_id); | ||
760 | |||
761 | tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_I2S0_RX0 | ||
762 | + bb_info->i2s_id); | ||
763 | tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX0 | ||
764 | + (codec_i2s->dam_ifc*2)); | ||
765 | tegra30_ahub_unset_rx_cif_source(TEGRA30_AHUB_RXCIF_DAM0_RX0 | ||
766 | + (bb_i2s->dam_ifc*2)); | ||
767 | |||
768 | /* disable the i2s */ | ||
769 | |||
770 | /* if this is the only user of i2s tx then disable it*/ | ||
771 | if (codec_i2s->playback_ref_count == 1) | ||
772 | codec_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_TX; | ||
773 | |||
774 | codec_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_RX; | ||
775 | tegra30_i2s_write(codec_i2s, TEGRA30_I2S_CTRL, codec_i2s->reg_ctrl); | ||
776 | bb_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_TX; | ||
777 | bb_i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_RX; | ||
778 | tegra30_i2s_write(bb_i2s, TEGRA30_I2S_CTRL, bb_i2s->reg_ctrl); | ||
779 | tegra30_i2s_disable_clocks(codec_i2s); | ||
780 | tegra30_i2s_disable_clocks(bb_i2s); | ||
781 | |||
782 | /* decrement the codec i2s playback ref count */ | ||
783 | codec_i2s->playback_ref_count--; | ||
784 | bb_i2s->playback_ref_count--; | ||
785 | |||
786 | /* disable the codec dam */ | ||
787 | tegra30_dam_enable(codec_i2s->dam_ifc, | ||
788 | TEGRA30_DAM_DISABLE, TEGRA30_DAM_CHIN0_SRC); | ||
789 | tegra30_dam_disable_clock(codec_i2s->dam_ifc); | ||
790 | tegra30_dam_free_channel(codec_i2s->dam_ifc, | ||
791 | TEGRA30_DAM_CHIN0_SRC); | ||
792 | codec_i2s->dam_ch_refcount--; | ||
793 | if (!codec_i2s->dam_ch_refcount) | ||
794 | tegra30_dam_free_controller(codec_i2s->dam_ifc); | ||
795 | |||
796 | /* disable the bb dam */ | ||
797 | tegra30_dam_enable(bb_i2s->dam_ifc, TEGRA30_DAM_DISABLE, | ||
798 | TEGRA30_DAM_CHIN0_SRC); | ||
799 | tegra30_dam_disable_clock(bb_i2s->dam_ifc); | ||
800 | tegra30_dam_free_channel(bb_i2s->dam_ifc, TEGRA30_DAM_CHIN0_SRC); | ||
801 | bb_i2s->dam_ch_refcount--; | ||
802 | if (!bb_i2s->dam_ch_refcount) | ||
803 | tegra30_dam_free_controller(bb_i2s->dam_ifc); | ||
804 | |||
805 | return 0; | ||
806 | } | ||
807 | |||
808 | static __devinit int tegra30_i2s_platform_probe(struct platform_device *pdev) | ||
809 | { | ||
810 | struct tegra30_i2s *i2s; | ||
811 | struct resource *mem, *memregion; | ||
812 | int ret; | ||
813 | |||
814 | if ((pdev->id < 0) || | ||
815 | (pdev->id >= ARRAY_SIZE(tegra30_i2s_dai))) { | ||
816 | dev_err(&pdev->dev, "ID %d out of range\n", pdev->id); | ||
817 | return -EINVAL; | ||
818 | } | ||
819 | |||
820 | i2s = &i2scont[pdev->id]; | ||
821 | dev_set_drvdata(&pdev->dev, i2s); | ||
822 | i2s->id = pdev->id; | ||
823 | |||
824 | i2s->clk_i2s = clk_get(&pdev->dev, "i2s"); | ||
825 | if (IS_ERR(i2s->clk_i2s)) { | ||
826 | dev_err(&pdev->dev, "Can't retrieve i2s clock\n"); | ||
827 | ret = PTR_ERR(i2s->clk_i2s); | ||
828 | goto exit; | ||
829 | } | ||
830 | |||
831 | i2s->clk_i2s_sync = clk_get(&pdev->dev, "ext_audio_sync"); | ||
832 | if (IS_ERR(i2s->clk_i2s_sync)) { | ||
833 | dev_err(&pdev->dev, "Can't retrieve i2s_sync clock\n"); | ||
834 | ret = PTR_ERR(i2s->clk_i2s_sync); | ||
835 | goto err_i2s_clk_put; | ||
836 | } | ||
837 | |||
838 | i2s->clk_audio_2x = clk_get(&pdev->dev, "audio_sync_2x"); | ||
839 | if (IS_ERR(i2s->clk_audio_2x)) { | ||
840 | dev_err(&pdev->dev, "Can't retrieve audio 2x clock\n"); | ||
841 | ret = PTR_ERR(i2s->clk_audio_2x); | ||
842 | goto err_i2s_sync_clk_put; | ||
843 | } | ||
844 | |||
845 | i2s->clk_pll_a_out0 = clk_get_sys(NULL, "pll_a_out0"); | ||
846 | if (IS_ERR(i2s->clk_pll_a_out0)) { | ||
847 | dev_err(&pdev->dev, "Can't retrieve pll_a_out0 clock\n"); | ||
848 | ret = PTR_ERR(i2s->clk_pll_a_out0); | ||
849 | goto err_audio_2x_clk_put; | ||
850 | } | ||
851 | |||
852 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
853 | if (!mem) { | ||
854 | dev_err(&pdev->dev, "No memory resource\n"); | ||
855 | ret = -ENODEV; | ||
856 | goto err_pll_a_out0_clk_put; | ||
857 | } | ||
858 | |||
859 | memregion = request_mem_region(mem->start, resource_size(mem), | ||
860 | DRV_NAME); | ||
861 | if (!memregion) { | ||
862 | dev_err(&pdev->dev, "Memory region already claimed\n"); | ||
863 | ret = -EBUSY; | ||
864 | goto err_pll_a_out0_clk_put; | ||
865 | } | ||
866 | |||
867 | i2s->regs = ioremap(mem->start, resource_size(mem)); | ||
868 | if (!i2s->regs) { | ||
869 | dev_err(&pdev->dev, "ioremap failed\n"); | ||
870 | ret = -ENOMEM; | ||
871 | goto err_release; | ||
872 | } | ||
873 | |||
874 | ret = snd_soc_register_dai(&pdev->dev, &tegra30_i2s_dai[pdev->id]); | ||
875 | if (ret) { | ||
876 | dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); | ||
877 | ret = -ENOMEM; | ||
878 | goto err_unmap; | ||
879 | } | ||
880 | |||
881 | tegra30_i2s_debug_add(i2s, pdev->id); | ||
882 | |||
883 | return 0; | ||
884 | |||
885 | err_unmap: | ||
886 | iounmap(i2s->regs); | ||
887 | err_release: | ||
888 | release_mem_region(mem->start, resource_size(mem)); | ||
889 | err_pll_a_out0_clk_put: | ||
890 | clk_put(i2s->clk_pll_a_out0); | ||
891 | err_audio_2x_clk_put: | ||
892 | clk_put(i2s->clk_audio_2x); | ||
893 | err_i2s_sync_clk_put: | ||
894 | clk_put(i2s->clk_i2s_sync); | ||
895 | err_i2s_clk_put: | ||
896 | clk_put(i2s->clk_i2s); | ||
897 | exit: | ||
898 | return ret; | ||
899 | } | ||
900 | |||
901 | static int __devexit tegra30_i2s_platform_remove(struct platform_device *pdev) | ||
902 | { | ||
903 | struct tegra30_i2s *i2s = dev_get_drvdata(&pdev->dev); | ||
904 | struct resource *res; | ||
905 | |||
906 | snd_soc_unregister_dai(&pdev->dev); | ||
907 | |||
908 | tegra30_i2s_debug_remove(i2s); | ||
909 | |||
910 | iounmap(i2s->regs); | ||
911 | |||
912 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
913 | release_mem_region(res->start, resource_size(res)); | ||
914 | |||
915 | clk_put(i2s->clk_pll_a_out0); | ||
916 | clk_put(i2s->clk_audio_2x); | ||
917 | clk_put(i2s->clk_i2s_sync); | ||
918 | clk_put(i2s->clk_i2s); | ||
919 | |||
920 | kfree(i2s); | ||
921 | |||
922 | return 0; | ||
923 | } | ||
924 | |||
925 | static struct platform_driver tegra30_i2s_driver = { | ||
926 | .driver = { | ||
927 | .name = DRV_NAME, | ||
928 | .owner = THIS_MODULE, | ||
929 | }, | ||
930 | .probe = tegra30_i2s_platform_probe, | ||
931 | .remove = __devexit_p(tegra30_i2s_platform_remove), | ||
932 | }; | ||
933 | |||
934 | static int __init snd_tegra30_i2s_init(void) | ||
935 | { | ||
936 | return platform_driver_register(&tegra30_i2s_driver); | ||
937 | } | ||
938 | module_init(snd_tegra30_i2s_init); | ||
939 | |||
940 | static void __exit snd_tegra30_i2s_exit(void) | ||
941 | { | ||
942 | platform_driver_unregister(&tegra30_i2s_driver); | ||
943 | } | ||
944 | module_exit(snd_tegra30_i2s_exit); | ||
945 | |||
946 | MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); | ||
947 | MODULE_DESCRIPTION("Tegra 30 I2S ASoC driver"); | ||
948 | MODULE_LICENSE("GPL"); | ||
949 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/sound/soc/tegra/tegra30_i2s.h b/sound/soc/tegra/tegra30_i2s.h new file mode 100644 index 00000000000..b9baddd5db8 --- /dev/null +++ b/sound/soc/tegra/tegra30_i2s.h | |||
@@ -0,0 +1,274 @@ | |||
1 | /* | ||
2 | * tegra30_i2s.h - Definitions for Tegra 30 I2S driver | ||
3 | * | ||
4 | * Copyright (c) 2010-2011, NVIDIA Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef __TEGRA30_I2S_H__ | ||
23 | #define __TEGRA30_I2S_H__ | ||
24 | |||
25 | #include "tegra_pcm.h" | ||
26 | |||
27 | /* Register offsets from TEGRA30_I2S*_BASE */ | ||
28 | |||
29 | #define TEGRA30_I2S_CTRL 0x0 | ||
30 | #define TEGRA30_I2S_TIMING 0x4 | ||
31 | #define TEGRA30_I2S_OFFSET 0x08 | ||
32 | #define TEGRA30_I2S_CH_CTRL 0x0c | ||
33 | #define TEGRA30_I2S_SLOT_CTRL 0x10 | ||
34 | #define TEGRA30_I2S_CIF_RX_CTRL 0x14 | ||
35 | #define TEGRA30_I2S_CIF_TX_CTRL 0x18 | ||
36 | #define TEGRA30_I2S_FLOWCTL 0x1c | ||
37 | #define TEGRA30_I2S_TX_STEP 0x20 | ||
38 | #define TEGRA30_I2S_FLOW_STATUS 0x24 | ||
39 | #define TEGRA30_I2S_FLOW_TOTAL 0x28 | ||
40 | #define TEGRA30_I2S_FLOW_OVER 0x2c | ||
41 | #define TEGRA30_I2S_FLOW_UNDER 0x30 | ||
42 | #define TEGRA30_I2S_LCOEF_1_4_0 0x34 | ||
43 | #define TEGRA30_I2S_LCOEF_1_4_1 0x38 | ||
44 | #define TEGRA30_I2S_LCOEF_1_4_2 0x3c | ||
45 | #define TEGRA30_I2S_LCOEF_1_4_3 0x40 | ||
46 | #define TEGRA30_I2S_LCOEF_1_4_4 0x44 | ||
47 | #define TEGRA30_I2S_LCOEF_1_4_5 0x48 | ||
48 | #define TEGRA30_I2S_LCOEF_2_4_0 0x4c | ||
49 | #define TEGRA30_I2S_LCOEF_2_4_1 0x50 | ||
50 | #define TEGRA30_I2S_LCOEF_2_4_2 0x54 | ||
51 | |||
52 | /* Fields in TEGRA30_I2S_CTRL */ | ||
53 | |||
54 | #define TEGRA30_I2S_CTRL_XFER_EN_TX (1 << 31) | ||
55 | #define TEGRA30_I2S_CTRL_XFER_EN_RX (1 << 30) | ||
56 | #define TEGRA30_I2S_CTRL_CG_EN (1 << 29) | ||
57 | #define TEGRA30_I2S_CTRL_SOFT_RESET (1 << 28) | ||
58 | #define TEGRA30_I2S_CTRL_TX_FLOWCTL_EN (1 << 27) | ||
59 | |||
60 | #define TEGRA30_I2S_CTRL_OBS_SEL_SHIFT 24 | ||
61 | #define TEGRA30_I2S_CTRL_OBS_SEL_MASK (7 << TEGRA30_I2S_CTRL_OBS_SEL_SHIFT) | ||
62 | |||
63 | #define TEGRA30_I2S_FRAME_FORMAT_LRCK 0 | ||
64 | #define TEGRA30_I2S_FRAME_FORMAT_FSYNC 1 | ||
65 | |||
66 | #define TEGRA30_I2S_CTRL_FRAME_FORMAT_SHIFT 12 | ||
67 | #define TEGRA30_I2S_CTRL_FRAME_FORMAT_MASK (7 << TEGRA30_I2S_CTRL_FRAME_FORMAT_SHIFT) | ||
68 | #define TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK (TEGRA30_I2S_FRAME_FORMAT_LRCK << TEGRA30_I2S_CTRL_FRAME_FORMAT_SHIFT) | ||
69 | #define TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC (TEGRA30_I2S_FRAME_FORMAT_FSYNC << TEGRA30_I2S_CTRL_FRAME_FORMAT_SHIFT) | ||
70 | |||
71 | #define TEGRA30_I2S_CTRL_MASTER_ENABLE (1 << 10) | ||
72 | |||
73 | #define TEGRA30_I2S_LRCK_LEFT_LOW 0 | ||
74 | #define TEGRA30_I2S_LRCK_RIGHT_LOW 1 | ||
75 | |||
76 | #define TEGRA30_I2S_CTRL_LRCK_SHIFT 9 | ||
77 | #define TEGRA30_I2S_CTRL_LRCK_MASK (1 << TEGRA30_I2S_CTRL_LRCK_SHIFT) | ||
78 | #define TEGRA30_I2S_CTRL_LRCK_L_LOW (TEGRA30_I2S_LRCK_LEFT_LOW << TEGRA30_I2S_CTRL_LRCK_SHIFT) | ||
79 | #define TEGRA30_I2S_CTRL_LRCK_R_LOW (TEGRA30_I2S_LRCK_RIGHT_LOW << TEGRA30_I2S_CTRL_LRCK_SHIFT) | ||
80 | |||
81 | #define TEGRA30_I2S_CTRL_LPBK_ENABLE (1 << 8) | ||
82 | |||
83 | #define TEGRA30_I2S_BIT_CODE_LINEAR 0 | ||
84 | #define TEGRA30_I2S_BIT_CODE_ULAW 1 | ||
85 | #define TEGRA30_I2S_BIT_CODE_ALAW 2 | ||
86 | |||
87 | #define TEGRA30_I2S_CTRL_BIT_CODE_SHIFT 4 | ||
88 | #define TEGRA30_I2S_CTRL_BIT_CODE_MASK (3 << TEGRA30_I2S_CTRL_BIT_CODE_SHIFT) | ||
89 | #define TEGRA30_I2S_CTRL_BIT_CODE_LINEAR (TEGRA30_I2S_BIT_CODE_LINEAR << TEGRA30_I2S_CTRL_BIT_CODE_SHIFT) | ||
90 | #define TEGRA30_I2S_CTRL_BIT_CODE_ULAW (TEGRA30_I2S_BIT_CODE_ULAW << TEGRA30_I2S_CTRL_BIT_CODE_SHIFT) | ||
91 | #define TEGRA30_I2S_CTRL_BIT_CODE_ALAW (TEGRA30_I2S_BIT_CODE_ALAW << TEGRA30_I2S_CTRL_BIT_CODE_SHIFT) | ||
92 | |||
93 | #define TEGRA30_I2S_BITS_8 1 | ||
94 | #define TEGRA30_I2S_BITS_12 2 | ||
95 | #define TEGRA30_I2S_BITS_16 3 | ||
96 | #define TEGRA30_I2S_BITS_20 4 | ||
97 | #define TEGRA30_I2S_BITS_24 5 | ||
98 | #define TEGRA30_I2S_BITS_28 6 | ||
99 | #define TEGRA30_I2S_BITS_32 7 | ||
100 | |||
101 | /* Sample container size; see {RX,TX}_MASK field in CH_CTRL below */ | ||
102 | #define TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT 0 | ||
103 | #define TEGRA30_I2S_CTRL_BIT_SIZE_MASK (7 << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT) | ||
104 | #define TEGRA30_I2S_CTRL_BIT_SIZE_8 (TEGRA30_I2S_BITS_8 << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT) | ||
105 | #define TEGRA30_I2S_CTRL_BIT_SIZE_12 (TEGRA30_I2S_BITS_12 << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT) | ||
106 | #define TEGRA30_I2S_CTRL_BIT_SIZE_16 (TEGRA30_I2S_BITS_16 << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT) | ||
107 | #define TEGRA30_I2S_CTRL_BIT_SIZE_20 (TEGRA30_I2S_BITS_20 << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT) | ||
108 | #define TEGRA30_I2S_CTRL_BIT_SIZE_24 (TEGRA30_I2S_BITS_24 << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT) | ||
109 | #define TEGRA30_I2S_CTRL_BIT_SIZE_28 (TEGRA30_I2S_BITS_28 << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT) | ||
110 | #define TEGRA30_I2S_CTRL_BIT_SIZE_32 (TEGRA30_I2S_BITS_32 << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT) | ||
111 | |||
112 | /* Fields in TEGRA30_I2S_TIMING */ | ||
113 | |||
114 | #define TEGRA30_I2S_TIMING_NON_SYM_ENABLE (1 << 12) | ||
115 | #define TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT 0 | ||
116 | #define TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US 0x7fff | ||
117 | #define TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_MASK (TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US << TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT) | ||
118 | |||
119 | /* Fields in TEGRA30_I2S_OFFSET */ | ||
120 | |||
121 | #define TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_SHIFT 16 | ||
122 | #define TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_MASK_US 0x7ff | ||
123 | #define TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_MASK (TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_MASK_US << TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_SHIFT) | ||
124 | #define TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT 0 | ||
125 | #define TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_MASK_US 0x7ff | ||
126 | #define TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_MASK (TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_MASK_US << TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT) | ||
127 | |||
128 | /* Fields in TEGRA30_I2S_CH_CTRL */ | ||
129 | |||
130 | /* (FSYNC width - 1) in bit clocks */ | ||
131 | #define TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_SHIFT 24 | ||
132 | #define TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_MASK_US 0xff | ||
133 | #define TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_MASK (TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_MASK_US << TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_SHIFT) | ||
134 | |||
135 | #define TEGRA30_I2S_HIGHZ_NO 0 | ||
136 | #define TEGRA30_I2S_HIGHZ_YES 1 | ||
137 | #define TEGRA30_I2S_HIGHZ_ON_HALF_BIT_CLK 2 | ||
138 | |||
139 | #define TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_SHIFT 12 | ||
140 | #define TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_MASK (3 << TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_SHIFT) | ||
141 | #define TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_NO (TEGRA30_I2S_HIGHZ_NO << TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_SHIFT) | ||
142 | #define TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_YES (TEGRA30_I2S_HIGHZ_YES << TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_SHIFT) | ||
143 | #define TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_ON_HALF_BIT_CLK (TEGRA30_I2S_HIGHZ_ON_HALF_BIT_CLK << TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_SHIFT) | ||
144 | |||
145 | #define TEGRA30_I2S_MSB_FIRST 0 | ||
146 | #define TEGRA30_I2S_LSB_FIRST 1 | ||
147 | |||
148 | #define TEGRA30_I2S_CH_CTRL_RX_BIT_ORDER_SHIFT 10 | ||
149 | #define TEGRA30_I2S_CH_CTRL_RX_BIT_ORDER_MASK (1 << TEGRA30_I2S_CH_CTRL_RX_BIT_ORDER_SHIFT) | ||
150 | #define TEGRA30_I2S_CH_CTRL_RX_BIT_ORDER_MSB_FIRST (TEGRA30_I2S_MSB_FIRST << TEGRA30_I2S_CH_CTRL_RX_BIT_ORDER_SHIFT) | ||
151 | #define TEGRA30_I2S_CH_CTRL_RX_BIT_ORDER_LSB_FIRST (TEGRA30_I2S_LSB_FIRST << TEGRA30_I2S_CH_CTRL_RX_BIT_ORDER_SHIFT) | ||
152 | #define TEGRA30_I2S_CH_CTRL_TX_BIT_ORDER_SHIFT 9 | ||
153 | #define TEGRA30_I2S_CH_CTRL_TX_BIT_ORDER_MASK (1 << TEGRA30_I2S_CH_CTRL_TX_BIT_ORDER_SHIFT) | ||
154 | #define TEGRA30_I2S_CH_CTRL_TX_BIT_ORDER_MSB_FIRST (TEGRA30_I2S_MSB_FIRST << TEGRA30_I2S_CH_CTRL_TX_BIT_ORDER_SHIFT) | ||
155 | #define TEGRA30_I2S_CH_CTRL_TX_BIT_ORDER_LSB_FIRST (TEGRA30_I2S_LSB_FIRST << TEGRA30_I2S_CH_CTRL_TX_BIT_ORDER_SHIFT) | ||
156 | |||
157 | #define TEGRA30_I2S_POS_EDGE 0 | ||
158 | #define TEGRA30_I2S_NEG_EDGE 1 | ||
159 | |||
160 | #define TEGRA30_I2S_CH_CTRL_EGDE_CTRL_SHIFT 8 | ||
161 | #define TEGRA30_I2S_CH_CTRL_EGDE_CTRL_MASK (1 << TEGRA30_I2S_CH_CTRL_EGDE_CTRL_SHIFT) | ||
162 | #define TEGRA30_I2S_CH_CTRL_EGDE_CTRL_POS_EDGE (TEGRA30_I2S_POS_EDGE << TEGRA30_I2S_CH_CTRL_EGDE_CTRL_SHIFT) | ||
163 | #define TEGRA30_I2S_CH_CTRL_EGDE_CTRL_NEG_EDGE (TEGRA30_I2S_NEG_EDGE << TEGRA30_I2S_CH_CTRL_EGDE_CTRL_SHIFT) | ||
164 | |||
165 | /* Sample size is # bits from BIT_SIZE minus this field */ | ||
166 | #define TEGRA30_I2S_CH_CTRL_RX_MASK_BITS_SHIFT 4 | ||
167 | #define TEGRA30_I2S_CH_CTRL_RX_MASK_BITS_MASK_US 7 | ||
168 | #define TEGRA30_I2S_CH_CTRL_RX_MASK_BITS_MASK (TEGRA30_I2S_CH_CTRL_RX_MASK_BITS_MASK_US << TEGRA30_I2S_CH_CTRL_RX_MASK_BITS_SHIFT) | ||
169 | |||
170 | #define TEGRA30_I2S_CH_CTRL_TX_MASK_BITS_SHIFT 0 | ||
171 | #define TEGRA30_I2S_CH_CTRL_TX_MASK_BITS_MASK_US 7 | ||
172 | #define TEGRA30_I2S_CH_CTRL_TX_MASK_BITS_MASK (TEGRA30_I2S_CH_CTRL_TX_MASK_BITS_MASK_US << TEGRA30_I2S_CH_CTRL_TX_MASK_BITS_SHIFT) | ||
173 | |||
174 | /* Fields in TEGRA30_I2S_SLOT_CTRL */ | ||
175 | |||
176 | /* Number of slots in frame, minus 1 */ | ||
177 | #define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT 16 | ||
178 | #define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK_US 7 | ||
179 | #define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK (TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOT_MASK_US << TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOT_SHIFT) | ||
180 | |||
181 | /* TDM mode slot enable bitmask */ | ||
182 | #define TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_SHIFT 8 | ||
183 | #define TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_MASK (0xff << TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_SHIFT) | ||
184 | |||
185 | #define TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_SHIFT 0 | ||
186 | #define TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_MASK (0xff << TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_SHIFT) | ||
187 | |||
188 | /* Fields in TEGRA30_I2S_CIF_RX_CTRL */ | ||
189 | /* Uses field from TEGRA30_AUDIOCIF_CTRL_* in tegra30_ahub.h */ | ||
190 | |||
191 | /* Fields in TEGRA30_I2S_CIF_TX_CTRL */ | ||
192 | /* Uses field from TEGRA30_AUDIOCIF_CTRL_* in tegra30_ahub.h */ | ||
193 | |||
194 | /* Fields in TEGRA30_I2S_FLOWCTL */ | ||
195 | |||
196 | #define TEGRA30_I2S_FILTER_LINEAR 0 | ||
197 | #define TEGRA30_I2S_FILTER_QUAD 1 | ||
198 | |||
199 | #define TEGRA30_I2S_FLOWCTL_FILTER_SHIFT 31 | ||
200 | #define TEGRA30_I2S_FLOWCTL_FILTER_MASK (1 << TEGRA30_I2S_FLOWCTL_FILTER_SHIFT) | ||
201 | #define TEGRA30_I2S_FLOWCTL_FILTER_LINEAR (TEGRA30_I2S_FILTER_LINEAR << TEGRA30_I2S_FLOWCTL_FILTER_SHIFT) | ||
202 | #define TEGRA30_I2S_FLOWCTL_FILTER_QUAD (TEGRA30_I2S_FILTER_QUAD << TEGRA30_I2S_FLOWCTL_FILTER_SHIFT) | ||
203 | |||
204 | /* Fields in TEGRA30_I2S_TX_STEP */ | ||
205 | |||
206 | #define TEGRA30_I2S_TX_STEP_SHIFT 0 | ||
207 | #define TEGRA30_I2S_TX_STEP_MASK_US 0xffff | ||
208 | #define TEGRA30_I2S_TX_STEP_MASK (TEGRA30_I2S_TX_STEP_MASK_US << TEGRA30_I2S_TX_STEP_SHIFT) | ||
209 | |||
210 | /* Fields in TEGRA30_I2S_FLOW_STATUS */ | ||
211 | |||
212 | #define TEGRA30_I2S_FLOW_STATUS_UNDERFLOW (1 << 31) | ||
213 | #define TEGRA30_I2S_FLOW_STATUS_OVERFLOW (1 << 30) | ||
214 | #define TEGRA30_I2S_FLOW_STATUS_MONITOR_INT_EN (1 << 4) | ||
215 | #define TEGRA30_I2S_FLOW_STATUS_COUNTER_CLR (1 << 3) | ||
216 | #define TEGRA30_I2S_FLOW_STATUS_MONITOR_CLR (1 << 2) | ||
217 | #define TEGRA30_I2S_FLOW_STATUS_COUNTER_EN (1 << 1) | ||
218 | #define TEGRA30_I2S_FLOW_STATUS_MONITOR_EN (1 << 0) | ||
219 | |||
220 | /* | ||
221 | * There are no fields in TEGRA30_I2S_FLOW_TOTAL, TEGRA30_I2S_FLOW_OVER, | ||
222 | * TEGRA30_I2S_FLOW_UNDER; they are counters taking the whole register. | ||
223 | */ | ||
224 | |||
225 | /* Fields in TEGRA30_I2S_LCOEF_* */ | ||
226 | |||
227 | #define TEGRA30_I2S_LCOEF_COEF_SHIFT 0 | ||
228 | #define TEGRA30_I2S_LCOEF_COEF_MASK_US 0xffff | ||
229 | #define TEGRA30_I2S_LCOEF_COEF_MASK (TEGRA30_I2S_LCOEF_COEF_MASK_US << TEGRA30_I2S_LCOEF_COEF_SHIFT) | ||
230 | |||
231 | /* Number of i2s controllers*/ | ||
232 | #define TEGRA30_NR_I2S_IFC 5 | ||
233 | |||
234 | struct tegra30_i2s { | ||
235 | int id; | ||
236 | struct clk *clk_i2s; | ||
237 | struct clk *clk_i2s_sync; | ||
238 | struct clk *clk_audio_2x; | ||
239 | struct clk *clk_pll_a_out0; | ||
240 | enum tegra30_ahub_rxcif rxcif; | ||
241 | struct tegra_pcm_dma_params capture_dma_data; | ||
242 | enum tegra30_ahub_txcif txcif; | ||
243 | struct tegra_pcm_dma_params playback_dma_data; | ||
244 | void __iomem *regs; | ||
245 | struct dentry *debug; | ||
246 | u32 reg_ctrl; | ||
247 | u32 reg_ch_ctrl; | ||
248 | int dam_ifc; | ||
249 | int dam_ch_refcount; | ||
250 | int playback_ref_count; | ||
251 | bool is_dam_used; | ||
252 | #ifdef CONFIG_PM | ||
253 | u32 reg_cache[(TEGRA30_I2S_CIF_TX_CTRL >> 2) + 1]; | ||
254 | #endif | ||
255 | int call_record_dam_ifc; | ||
256 | int is_call_mode_rec; | ||
257 | }; | ||
258 | |||
259 | struct codec_config { | ||
260 | int i2s_id; | ||
261 | int rate; | ||
262 | int channels; | ||
263 | int bitsize; | ||
264 | int is_i2smaster; | ||
265 | int is_format_dsp; | ||
266 | }; | ||
267 | |||
268 | int tegra30_make_voice_call_connections(struct codec_config *codec_info, | ||
269 | struct codec_config *bb_info); | ||
270 | |||
271 | int tegra30_break_voice_call_connections(struct codec_config *codec_info, | ||
272 | struct codec_config *bb_info); | ||
273 | |||
274 | #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_asoc_utils.c b/sound/soc/tegra/tegra_asoc_utils.c index dfa85cbb05c..04e7e3c15cd 100644 --- a/sound/soc/tegra/tegra_asoc_utils.c +++ b/sound/soc/tegra/tegra_asoc_utils.c | |||
@@ -25,21 +25,39 @@ | |||
25 | #include <linux/err.h> | 25 | #include <linux/err.h> |
26 | #include <linux/kernel.h> | 26 | #include <linux/kernel.h> |
27 | 27 | ||
28 | #include <mach/clk.h> | ||
29 | |||
28 | #include "tegra_asoc_utils.h" | 30 | #include "tegra_asoc_utils.h" |
29 | 31 | ||
32 | int g_is_call_mode; | ||
33 | |||
34 | bool tegra_is_voice_call_active() | ||
35 | { | ||
36 | if (g_is_call_mode) | ||
37 | return true; | ||
38 | else | ||
39 | return false; | ||
40 | } | ||
41 | EXPORT_SYMBOL_GPL(tegra_is_voice_call_active); | ||
42 | |||
30 | int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate, | 43 | int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate, |
31 | int mclk) | 44 | int mclk) |
32 | { | 45 | { |
33 | int new_baseclock; | 46 | int new_baseclock; |
34 | bool clk_change; | 47 | bool clk_change; |
35 | int err; | 48 | int err; |
49 | bool reenable_clock; | ||
36 | 50 | ||
37 | switch (srate) { | 51 | switch (srate) { |
38 | case 11025: | 52 | case 11025: |
39 | case 22050: | 53 | case 22050: |
40 | case 44100: | 54 | case 44100: |
41 | case 88200: | 55 | case 88200: |
56 | #if defined(CONFIG_ARCH_TEGRA_2x_SOC) | ||
42 | new_baseclock = 56448000; | 57 | new_baseclock = 56448000; |
58 | #else | ||
59 | new_baseclock = 564480000; | ||
60 | #endif | ||
43 | break; | 61 | break; |
44 | case 8000: | 62 | case 8000: |
45 | case 16000: | 63 | case 16000: |
@@ -47,7 +65,11 @@ int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate, | |||
47 | case 48000: | 65 | case 48000: |
48 | case 64000: | 66 | case 64000: |
49 | case 96000: | 67 | case 96000: |
68 | #if defined(CONFIG_ARCH_TEGRA_2x_SOC) | ||
50 | new_baseclock = 73728000; | 69 | new_baseclock = 73728000; |
70 | #else | ||
71 | new_baseclock = 552960000; | ||
72 | #endif | ||
51 | break; | 73 | break; |
52 | default: | 74 | default: |
53 | return -EINVAL; | 75 | return -EINVAL; |
@@ -58,38 +80,60 @@ int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate, | |||
58 | if (!clk_change) | 80 | if (!clk_change) |
59 | return 0; | 81 | return 0; |
60 | 82 | ||
83 | /* Don't change rate if already one dai-link is using it */ | ||
84 | if (data->lock_count) | ||
85 | return -EINVAL; | ||
86 | |||
61 | data->set_baseclock = 0; | 87 | data->set_baseclock = 0; |
62 | data->set_mclk = 0; | 88 | data->set_mclk = 0; |
63 | 89 | ||
64 | clk_disable(data->clk_cdev1); | 90 | reenable_clock = false; |
65 | clk_disable(data->clk_pll_a_out0); | 91 | if(tegra_is_clk_enabled(data->clk_pll_a)) { |
66 | clk_disable(data->clk_pll_a); | 92 | clk_disable(data->clk_pll_a); |
67 | 93 | reenable_clock = true; | |
94 | } | ||
68 | err = clk_set_rate(data->clk_pll_a, new_baseclock); | 95 | err = clk_set_rate(data->clk_pll_a, new_baseclock); |
69 | if (err) { | 96 | if (err) { |
70 | dev_err(data->dev, "Can't set pll_a rate: %d\n", err); | 97 | dev_err(data->dev, "Can't set pll_a rate: %d\n", err); |
71 | return err; | 98 | return err; |
72 | } | 99 | } |
100 | if(reenable_clock) | ||
101 | clk_enable(data->clk_pll_a); | ||
73 | 102 | ||
103 | reenable_clock = false; | ||
104 | if(tegra_is_clk_enabled(data->clk_pll_a_out0)) { | ||
105 | clk_disable(data->clk_pll_a_out0); | ||
106 | reenable_clock = true; | ||
107 | } | ||
74 | err = clk_set_rate(data->clk_pll_a_out0, mclk); | 108 | err = clk_set_rate(data->clk_pll_a_out0, mclk); |
75 | if (err) { | 109 | if (err) { |
76 | dev_err(data->dev, "Can't set pll_a_out0 rate: %d\n", err); | 110 | dev_err(data->dev, "Can't set clk_pll_a_out0 rate: %d\n", err); |
77 | return err; | 111 | return err; |
78 | } | 112 | } |
113 | if(reenable_clock) | ||
114 | clk_enable(data->clk_pll_a_out0); | ||
79 | 115 | ||
80 | /* Don't set cdev1 rate; its locked to pll_a_out0 */ | ||
81 | 116 | ||
82 | err = clk_enable(data->clk_pll_a); | 117 | data->set_baseclock = new_baseclock; |
83 | if (err) { | 118 | data->set_mclk = mclk; |
84 | dev_err(data->dev, "Can't enable pll_a: %d\n", err); | ||
85 | return err; | ||
86 | } | ||
87 | 119 | ||
88 | err = clk_enable(data->clk_pll_a_out0); | 120 | return 0; |
89 | if (err) { | 121 | } |
90 | dev_err(data->dev, "Can't enable pll_a_out0: %d\n", err); | 122 | EXPORT_SYMBOL_GPL(tegra_asoc_utils_set_rate); |
91 | return err; | 123 | |
92 | } | 124 | void tegra_asoc_utils_lock_clk_rate(struct tegra_asoc_utils_data *data, |
125 | int lock) | ||
126 | { | ||
127 | if (lock) | ||
128 | data->lock_count++; | ||
129 | else if (data->lock_count) | ||
130 | data->lock_count--; | ||
131 | } | ||
132 | EXPORT_SYMBOL_GPL(tegra_asoc_utils_lock_clk_rate); | ||
133 | |||
134 | int tegra_asoc_utils_clk_enable(struct tegra_asoc_utils_data *data) | ||
135 | { | ||
136 | int err; | ||
93 | 137 | ||
94 | err = clk_enable(data->clk_cdev1); | 138 | err = clk_enable(data->clk_cdev1); |
95 | if (err) { | 139 | if (err) { |
@@ -97,25 +141,37 @@ int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate, | |||
97 | return err; | 141 | return err; |
98 | } | 142 | } |
99 | 143 | ||
100 | data->set_baseclock = new_baseclock; | 144 | return 0; |
101 | data->set_mclk = mclk; | 145 | } |
146 | EXPORT_SYMBOL_GPL(tegra_asoc_utils_clk_enable); | ||
102 | 147 | ||
148 | int tegra_asoc_utils_clk_disable(struct tegra_asoc_utils_data *data) | ||
149 | { | ||
150 | clk_disable(data->clk_cdev1); | ||
103 | return 0; | 151 | return 0; |
104 | } | 152 | } |
105 | EXPORT_SYMBOL_GPL(tegra_asoc_utils_set_rate); | 153 | EXPORT_SYMBOL_GPL(tegra_asoc_utils_clk_disable); |
106 | 154 | ||
107 | int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data, | 155 | int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data, |
108 | struct device *dev) | 156 | struct device *dev) |
109 | { | 157 | { |
110 | int ret; | 158 | int ret; |
159 | int rate; | ||
111 | 160 | ||
112 | data->dev = dev; | 161 | data->dev = dev; |
113 | 162 | ||
163 | data->clk_pll_p_out1 = clk_get_sys(NULL, "pll_p_out1"); | ||
164 | if (IS_ERR(data->clk_pll_p_out1)) { | ||
165 | dev_err(data->dev, "Can't retrieve clk pll_p_out1\n"); | ||
166 | ret = PTR_ERR(data->clk_pll_p_out1); | ||
167 | goto err; | ||
168 | } | ||
169 | |||
114 | data->clk_pll_a = clk_get_sys(NULL, "pll_a"); | 170 | data->clk_pll_a = clk_get_sys(NULL, "pll_a"); |
115 | if (IS_ERR(data->clk_pll_a)) { | 171 | if (IS_ERR(data->clk_pll_a)) { |
116 | dev_err(data->dev, "Can't retrieve clk pll_a\n"); | 172 | dev_err(data->dev, "Can't retrieve clk pll_a\n"); |
117 | ret = PTR_ERR(data->clk_pll_a); | 173 | ret = PTR_ERR(data->clk_pll_a); |
118 | goto err; | 174 | goto err_put_pll_p_out1; |
119 | } | 175 | } |
120 | 176 | ||
121 | data->clk_pll_a_out0 = clk_get_sys(NULL, "pll_a_out0"); | 177 | data->clk_pll_a_out0 = clk_get_sys(NULL, "pll_a_out0"); |
@@ -125,19 +181,90 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data, | |||
125 | goto err_put_pll_a; | 181 | goto err_put_pll_a; |
126 | } | 182 | } |
127 | 183 | ||
184 | data->clk_m = clk_get_sys(NULL, "clk_m"); | ||
185 | if (IS_ERR(data->clk_m)) { | ||
186 | dev_err(data->dev, "Can't retrieve clk clk_m\n"); | ||
187 | ret = PTR_ERR(data->clk_m); | ||
188 | goto err; | ||
189 | } | ||
190 | |||
191 | #if defined(CONFIG_ARCH_TEGRA_2x_SOC) | ||
128 | data->clk_cdev1 = clk_get_sys(NULL, "cdev1"); | 192 | data->clk_cdev1 = clk_get_sys(NULL, "cdev1"); |
193 | #else | ||
194 | data->clk_cdev1 = clk_get_sys("extern1", NULL); | ||
195 | #endif | ||
129 | if (IS_ERR(data->clk_cdev1)) { | 196 | if (IS_ERR(data->clk_cdev1)) { |
130 | dev_err(data->dev, "Can't retrieve clk cdev1\n"); | 197 | dev_err(data->dev, "Can't retrieve clk cdev1\n"); |
131 | ret = PTR_ERR(data->clk_cdev1); | 198 | ret = PTR_ERR(data->clk_cdev1); |
132 | goto err_put_pll_a_out0; | 199 | goto err_put_pll_a_out0; |
133 | } | 200 | } |
134 | 201 | ||
202 | #if defined(CONFIG_ARCH_TEGRA_2x_SOC) | ||
203 | data->clk_out1 = ERR_PTR(-ENOENT); | ||
204 | #else | ||
205 | data->clk_out1 = clk_get_sys("clk_out_1", "extern1"); | ||
206 | if (IS_ERR(data->clk_out1)) { | ||
207 | dev_err(data->dev, "Can't retrieve clk out1\n"); | ||
208 | ret = PTR_ERR(data->clk_out1); | ||
209 | goto err_put_cdev1; | ||
210 | } | ||
211 | #endif | ||
212 | |||
213 | #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) | ||
214 | #if TEGRA30_I2S_MASTER_PLAYBACK | ||
215 | ret = clk_set_parent(data->clk_cdev1, data->clk_pll_a_out0); | ||
216 | if (ret) { | ||
217 | dev_err(data->dev, "Can't set clk cdev1/extern1 parent"); | ||
218 | goto err_put_out1; | ||
219 | } | ||
220 | #else | ||
221 | rate = clk_get_rate(data->clk_m); | ||
222 | |||
223 | if(rate == 26000000) | ||
224 | clk_set_rate(data->clk_cdev1, 13000000); | ||
225 | |||
226 | ret = clk_set_parent(data->clk_cdev1, data->clk_m); | ||
227 | if (ret) { | ||
228 | dev_err(data->dev, "Can't set clk cdev1/extern1 parent"); | ||
229 | goto err_put_out1; | ||
230 | } | ||
231 | #endif | ||
232 | |||
233 | #endif | ||
234 | |||
235 | ret = clk_enable(data->clk_cdev1); | ||
236 | if (ret) { | ||
237 | dev_err(data->dev, "Can't enable clk cdev1/extern1"); | ||
238 | goto err_put_out1; | ||
239 | } | ||
240 | |||
241 | if (!IS_ERR(data->clk_out1)) { | ||
242 | ret = clk_enable(data->clk_out1); | ||
243 | if (ret) { | ||
244 | dev_err(data->dev, "Can't enable clk out1"); | ||
245 | goto err_put_out1; | ||
246 | } | ||
247 | } | ||
248 | |||
249 | ret = tegra_asoc_utils_set_rate(data, 48000, 256 * 48000); | ||
250 | if (ret) | ||
251 | goto err_put_out1; | ||
252 | |||
135 | return 0; | 253 | return 0; |
136 | 254 | ||
255 | err_put_out1: | ||
256 | if (!IS_ERR(data->clk_out1)) | ||
257 | clk_put(data->clk_out1); | ||
258 | #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) | ||
259 | err_put_cdev1: | ||
260 | #endif | ||
261 | clk_put(data->clk_cdev1); | ||
137 | err_put_pll_a_out0: | 262 | err_put_pll_a_out0: |
138 | clk_put(data->clk_pll_a_out0); | 263 | clk_put(data->clk_pll_a_out0); |
139 | err_put_pll_a: | 264 | err_put_pll_a: |
140 | clk_put(data->clk_pll_a); | 265 | clk_put(data->clk_pll_a); |
266 | err_put_pll_p_out1: | ||
267 | clk_put(data->clk_pll_p_out1); | ||
141 | err: | 268 | err: |
142 | return ret; | 269 | return ret; |
143 | } | 270 | } |
@@ -145,9 +272,19 @@ EXPORT_SYMBOL_GPL(tegra_asoc_utils_init); | |||
145 | 272 | ||
146 | void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data) | 273 | void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data) |
147 | { | 274 | { |
275 | if (!IS_ERR(data->clk_out1)) | ||
276 | clk_put(data->clk_out1); | ||
277 | |||
148 | clk_put(data->clk_cdev1); | 278 | clk_put(data->clk_cdev1); |
149 | clk_put(data->clk_pll_a_out0); | 279 | |
150 | clk_put(data->clk_pll_a); | 280 | if (!IS_ERR(data->clk_pll_a_out0)) |
281 | clk_put(data->clk_pll_a_out0); | ||
282 | |||
283 | if (!IS_ERR(data->clk_pll_a)) | ||
284 | clk_put(data->clk_pll_a); | ||
285 | |||
286 | if (!IS_ERR(data->clk_pll_p_out1)) | ||
287 | clk_put(data->clk_pll_p_out1); | ||
151 | } | 288 | } |
152 | EXPORT_SYMBOL_GPL(tegra_asoc_utils_fini); | 289 | EXPORT_SYMBOL_GPL(tegra_asoc_utils_fini); |
153 | 290 | ||
diff --git a/sound/soc/tegra/tegra_asoc_utils.h b/sound/soc/tegra/tegra_asoc_utils.h index 4818195da25..1c4e521cb4b 100644 --- a/sound/soc/tegra/tegra_asoc_utils.h +++ b/sound/soc/tegra/tegra_asoc_utils.h | |||
@@ -23,6 +23,9 @@ | |||
23 | #ifndef __TEGRA_ASOC_UTILS_H__ | 23 | #ifndef __TEGRA_ASOC_UTILS_H__ |
24 | #define __TEGRA_ASOC_UTILS_H_ | 24 | #define __TEGRA_ASOC_UTILS_H_ |
25 | 25 | ||
26 | |||
27 | #define TEGRA30_I2S_MASTER_PLAYBACK 1 | ||
28 | |||
26 | struct clk; | 29 | struct clk; |
27 | struct device; | 30 | struct device; |
28 | 31 | ||
@@ -31,15 +34,23 @@ struct tegra_asoc_utils_data { | |||
31 | struct clk *clk_pll_a; | 34 | struct clk *clk_pll_a; |
32 | struct clk *clk_pll_a_out0; | 35 | struct clk *clk_pll_a_out0; |
33 | struct clk *clk_cdev1; | 36 | struct clk *clk_cdev1; |
37 | struct clk *clk_out1; | ||
38 | struct clk *clk_m; | ||
39 | struct clk *clk_pll_p_out1; | ||
34 | int set_baseclock; | 40 | int set_baseclock; |
35 | int set_mclk; | 41 | int set_mclk; |
42 | int lock_count; | ||
36 | }; | 43 | }; |
37 | 44 | ||
38 | int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate, | 45 | int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate, |
39 | int mclk); | 46 | int mclk); |
47 | void tegra_asoc_utils_lock_clk_rate(struct tegra_asoc_utils_data *data, | ||
48 | int lock); | ||
40 | int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data, | 49 | int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data, |
41 | struct device *dev); | 50 | struct device *dev); |
42 | void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data); | 51 | void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data); |
52 | int tegra_asoc_utils_clk_enable(struct tegra_asoc_utils_data *data); | ||
53 | int tegra_asoc_utils_clk_disable(struct tegra_asoc_utils_data *data); | ||
43 | 54 | ||
44 | #endif | 55 | #endif |
45 | 56 | ||
diff --git a/sound/soc/tegra/tegra_das.c b/sound/soc/tegra/tegra_das.c deleted file mode 100644 index 9f24ef73f2c..00000000000 --- a/sound/soc/tegra/tegra_das.c +++ /dev/null | |||
@@ -1,265 +0,0 @@ | |||
1 | /* | ||
2 | * tegra_das.c - Tegra DAS driver | ||
3 | * | ||
4 | * Author: Stephen Warren <swarren@nvidia.com> | ||
5 | * Copyright (C) 2010 - 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/module.h> | ||
24 | #include <linux/debugfs.h> | ||
25 | #include <linux/device.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/seq_file.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/io.h> | ||
30 | #include <mach/iomap.h> | ||
31 | #include <sound/soc.h> | ||
32 | #include "tegra_das.h" | ||
33 | |||
34 | #define DRV_NAME "tegra-das" | ||
35 | |||
36 | static struct tegra_das *das; | ||
37 | |||
38 | static inline void tegra_das_write(u32 reg, u32 val) | ||
39 | { | ||
40 | __raw_writel(val, das->regs + reg); | ||
41 | } | ||
42 | |||
43 | static inline u32 tegra_das_read(u32 reg) | ||
44 | { | ||
45 | return __raw_readl(das->regs + reg); | ||
46 | } | ||
47 | |||
48 | int tegra_das_connect_dap_to_dac(int dap, int dac) | ||
49 | { | ||
50 | u32 addr; | ||
51 | u32 reg; | ||
52 | |||
53 | if (!das) | ||
54 | return -ENODEV; | ||
55 | |||
56 | addr = TEGRA_DAS_DAP_CTRL_SEL + | ||
57 | (dap * TEGRA_DAS_DAP_CTRL_SEL_STRIDE); | ||
58 | reg = dac << TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P; | ||
59 | |||
60 | tegra_das_write(addr, reg); | ||
61 | |||
62 | return 0; | ||
63 | } | ||
64 | EXPORT_SYMBOL_GPL(tegra_das_connect_dap_to_dac); | ||
65 | |||
66 | int tegra_das_connect_dap_to_dap(int dap, int otherdap, int master, | ||
67 | int sdata1rx, int sdata2rx) | ||
68 | { | ||
69 | u32 addr; | ||
70 | u32 reg; | ||
71 | |||
72 | if (!das) | ||
73 | return -ENODEV; | ||
74 | |||
75 | addr = TEGRA_DAS_DAP_CTRL_SEL + | ||
76 | (dap * TEGRA_DAS_DAP_CTRL_SEL_STRIDE); | ||
77 | reg = otherdap << TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P | | ||
78 | !!sdata2rx << TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P | | ||
79 | !!sdata1rx << TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P | | ||
80 | !!master << TEGRA_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P; | ||
81 | |||
82 | tegra_das_write(addr, reg); | ||
83 | |||
84 | return 0; | ||
85 | } | ||
86 | EXPORT_SYMBOL_GPL(tegra_das_connect_dap_to_dap); | ||
87 | |||
88 | int tegra_das_connect_dac_to_dap(int dac, int dap) | ||
89 | { | ||
90 | u32 addr; | ||
91 | u32 reg; | ||
92 | |||
93 | if (!das) | ||
94 | return -ENODEV; | ||
95 | |||
96 | addr = TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL + | ||
97 | (dac * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE); | ||
98 | reg = dap << TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P | | ||
99 | dap << TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P | | ||
100 | dap << TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P; | ||
101 | |||
102 | tegra_das_write(addr, reg); | ||
103 | |||
104 | return 0; | ||
105 | } | ||
106 | EXPORT_SYMBOL_GPL(tegra_das_connect_dac_to_dap); | ||
107 | |||
108 | #ifdef CONFIG_DEBUG_FS | ||
109 | static int tegra_das_show(struct seq_file *s, void *unused) | ||
110 | { | ||
111 | int i; | ||
112 | u32 addr; | ||
113 | u32 reg; | ||
114 | |||
115 | for (i = 0; i < TEGRA_DAS_DAP_CTRL_SEL_COUNT; i++) { | ||
116 | addr = TEGRA_DAS_DAP_CTRL_SEL + | ||
117 | (i * TEGRA_DAS_DAP_CTRL_SEL_STRIDE); | ||
118 | reg = tegra_das_read(addr); | ||
119 | seq_printf(s, "TEGRA_DAS_DAP_CTRL_SEL[%d] = %08x\n", i, reg); | ||
120 | } | ||
121 | |||
122 | for (i = 0; i < TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_COUNT; i++) { | ||
123 | addr = TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL + | ||
124 | (i * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE); | ||
125 | reg = tegra_das_read(addr); | ||
126 | seq_printf(s, "TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL[%d] = %08x\n", | ||
127 | i, reg); | ||
128 | } | ||
129 | |||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | static int tegra_das_debug_open(struct inode *inode, struct file *file) | ||
134 | { | ||
135 | return single_open(file, tegra_das_show, inode->i_private); | ||
136 | } | ||
137 | |||
138 | static const struct file_operations tegra_das_debug_fops = { | ||
139 | .open = tegra_das_debug_open, | ||
140 | .read = seq_read, | ||
141 | .llseek = seq_lseek, | ||
142 | .release = single_release, | ||
143 | }; | ||
144 | |||
145 | static void tegra_das_debug_add(struct tegra_das *das) | ||
146 | { | ||
147 | das->debug = debugfs_create_file(DRV_NAME, S_IRUGO, | ||
148 | snd_soc_debugfs_root, das, | ||
149 | &tegra_das_debug_fops); | ||
150 | } | ||
151 | |||
152 | static void tegra_das_debug_remove(struct tegra_das *das) | ||
153 | { | ||
154 | if (das->debug) | ||
155 | debugfs_remove(das->debug); | ||
156 | } | ||
157 | #else | ||
158 | static inline void tegra_das_debug_add(struct tegra_das *das) | ||
159 | { | ||
160 | } | ||
161 | |||
162 | static inline void tegra_das_debug_remove(struct tegra_das *das) | ||
163 | { | ||
164 | } | ||
165 | #endif | ||
166 | |||
167 | static int __devinit tegra_das_probe(struct platform_device *pdev) | ||
168 | { | ||
169 | struct resource *res, *region; | ||
170 | int ret = 0; | ||
171 | |||
172 | if (das) | ||
173 | return -ENODEV; | ||
174 | |||
175 | das = kzalloc(sizeof(struct tegra_das), GFP_KERNEL); | ||
176 | if (!das) { | ||
177 | dev_err(&pdev->dev, "Can't allocate tegra_das\n"); | ||
178 | ret = -ENOMEM; | ||
179 | goto exit; | ||
180 | } | ||
181 | das->dev = &pdev->dev; | ||
182 | |||
183 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
184 | if (!res) { | ||
185 | dev_err(&pdev->dev, "No memory resource\n"); | ||
186 | ret = -ENODEV; | ||
187 | goto err_free; | ||
188 | } | ||
189 | |||
190 | region = request_mem_region(res->start, resource_size(res), | ||
191 | pdev->name); | ||
192 | if (!region) { | ||
193 | dev_err(&pdev->dev, "Memory region already claimed\n"); | ||
194 | ret = -EBUSY; | ||
195 | goto err_free; | ||
196 | } | ||
197 | |||
198 | das->regs = ioremap(res->start, resource_size(res)); | ||
199 | if (!das->regs) { | ||
200 | dev_err(&pdev->dev, "ioremap failed\n"); | ||
201 | ret = -ENOMEM; | ||
202 | goto err_release; | ||
203 | } | ||
204 | |||
205 | tegra_das_debug_add(das); | ||
206 | |||
207 | platform_set_drvdata(pdev, das); | ||
208 | |||
209 | return 0; | ||
210 | |||
211 | err_release: | ||
212 | release_mem_region(res->start, resource_size(res)); | ||
213 | err_free: | ||
214 | kfree(das); | ||
215 | das = 0; | ||
216 | exit: | ||
217 | return ret; | ||
218 | } | ||
219 | |||
220 | static int __devexit tegra_das_remove(struct platform_device *pdev) | ||
221 | { | ||
222 | struct resource *res; | ||
223 | |||
224 | if (!das) | ||
225 | return -ENODEV; | ||
226 | |||
227 | platform_set_drvdata(pdev, NULL); | ||
228 | |||
229 | tegra_das_debug_remove(das); | ||
230 | |||
231 | iounmap(das->regs); | ||
232 | |||
233 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
234 | release_mem_region(res->start, resource_size(res)); | ||
235 | |||
236 | kfree(das); | ||
237 | das = 0; | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static struct platform_driver tegra_das_driver = { | ||
243 | .probe = tegra_das_probe, | ||
244 | .remove = __devexit_p(tegra_das_remove), | ||
245 | .driver = { | ||
246 | .name = DRV_NAME, | ||
247 | }, | ||
248 | }; | ||
249 | |||
250 | static int __init tegra_das_modinit(void) | ||
251 | { | ||
252 | return platform_driver_register(&tegra_das_driver); | ||
253 | } | ||
254 | module_init(tegra_das_modinit); | ||
255 | |||
256 | static void __exit tegra_das_modexit(void) | ||
257 | { | ||
258 | platform_driver_unregister(&tegra_das_driver); | ||
259 | } | ||
260 | module_exit(tegra_das_modexit); | ||
261 | |||
262 | MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); | ||
263 | MODULE_DESCRIPTION("Tegra DAS driver"); | ||
264 | MODULE_LICENSE("GPL"); | ||
265 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/sound/soc/tegra/tegra_das.h b/sound/soc/tegra/tegra_das.h deleted file mode 100644 index 2c96c7b3c45..00000000000 --- a/sound/soc/tegra/tegra_das.h +++ /dev/null | |||
@@ -1,135 +0,0 @@ | |||
1 | /* | ||
2 | * tegra_das.h - Definitions for Tegra DAS driver | ||
3 | * | ||
4 | * Author: Stephen Warren <swarren@nvidia.com> | ||
5 | * Copyright (C) 2010 - 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 __TEGRA_DAS_H__ | ||
24 | #define __TEGRA_DAS_H__ | ||
25 | |||
26 | /* Register TEGRA_DAS_DAP_CTRL_SEL */ | ||
27 | #define TEGRA_DAS_DAP_CTRL_SEL 0x00 | ||
28 | #define TEGRA_DAS_DAP_CTRL_SEL_COUNT 5 | ||
29 | #define TEGRA_DAS_DAP_CTRL_SEL_STRIDE 4 | ||
30 | #define TEGRA_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P 31 | ||
31 | #define TEGRA_DAS_DAP_CTRL_SEL_DAP_MS_SEL_S 1 | ||
32 | #define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P 30 | ||
33 | #define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_S 1 | ||
34 | #define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P 29 | ||
35 | #define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_S 1 | ||
36 | #define TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P 0 | ||
37 | #define TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_S 5 | ||
38 | |||
39 | /* Values for field TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL */ | ||
40 | #define TEGRA_DAS_DAP_SEL_DAC1 0 | ||
41 | #define TEGRA_DAS_DAP_SEL_DAC2 1 | ||
42 | #define TEGRA_DAS_DAP_SEL_DAC3 2 | ||
43 | #define TEGRA_DAS_DAP_SEL_DAP1 16 | ||
44 | #define TEGRA_DAS_DAP_SEL_DAP2 17 | ||
45 | #define TEGRA_DAS_DAP_SEL_DAP3 18 | ||
46 | #define TEGRA_DAS_DAP_SEL_DAP4 19 | ||
47 | #define TEGRA_DAS_DAP_SEL_DAP5 20 | ||
48 | |||
49 | /* Register TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL */ | ||
50 | #define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL 0x40 | ||
51 | #define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_COUNT 3 | ||
52 | #define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE 4 | ||
53 | #define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P 28 | ||
54 | #define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_S 4 | ||
55 | #define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P 24 | ||
56 | #define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_S 4 | ||
57 | #define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P 0 | ||
58 | #define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_S 4 | ||
59 | |||
60 | /* | ||
61 | * Values for: | ||
62 | * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL | ||
63 | * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL | ||
64 | * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL | ||
65 | */ | ||
66 | #define TEGRA_DAS_DAC_SEL_DAP1 0 | ||
67 | #define TEGRA_DAS_DAC_SEL_DAP2 1 | ||
68 | #define TEGRA_DAS_DAC_SEL_DAP3 2 | ||
69 | #define TEGRA_DAS_DAC_SEL_DAP4 3 | ||
70 | #define TEGRA_DAS_DAC_SEL_DAP5 4 | ||
71 | |||
72 | /* | ||
73 | * Names/IDs of the DACs/DAPs. | ||
74 | */ | ||
75 | |||
76 | #define TEGRA_DAS_DAP_ID_1 0 | ||
77 | #define TEGRA_DAS_DAP_ID_2 1 | ||
78 | #define TEGRA_DAS_DAP_ID_3 2 | ||
79 | #define TEGRA_DAS_DAP_ID_4 3 | ||
80 | #define TEGRA_DAS_DAP_ID_5 4 | ||
81 | |||
82 | #define TEGRA_DAS_DAC_ID_1 0 | ||
83 | #define TEGRA_DAS_DAC_ID_2 1 | ||
84 | #define TEGRA_DAS_DAC_ID_3 2 | ||
85 | |||
86 | struct tegra_das { | ||
87 | struct device *dev; | ||
88 | void __iomem *regs; | ||
89 | struct dentry *debug; | ||
90 | }; | ||
91 | |||
92 | /* | ||
93 | * Terminology: | ||
94 | * DAS: Digital audio switch (HW module controlled by this driver) | ||
95 | * DAP: Digital audio port (port/pins on Tegra device) | ||
96 | * DAC: Digital audio controller (e.g. I2S or AC97 controller elsewhere) | ||
97 | * | ||
98 | * The Tegra DAS is a mux/cross-bar which can connect each DAP to a specific | ||
99 | * DAC, or another DAP. When DAPs are connected, one must be the master and | ||
100 | * one the slave. Each DAC allows selection of a specific DAP for input, to | ||
101 | * cater for the case where N DAPs are connected to 1 DAC for broadcast | ||
102 | * output. | ||
103 | * | ||
104 | * This driver is dumb; no attempt is made to ensure that a valid routing | ||
105 | * configuration is programmed. | ||
106 | */ | ||
107 | |||
108 | /* | ||
109 | * Connect a DAP to to a DAC | ||
110 | * dap_id: DAP to connect: TEGRA_DAS_DAP_ID_* | ||
111 | * dac_sel: DAC to connect to: TEGRA_DAS_DAP_SEL_DAC* | ||
112 | */ | ||
113 | extern int tegra_das_connect_dap_to_dac(int dap_id, int dac_sel); | ||
114 | |||
115 | /* | ||
116 | * Connect a DAP to to another DAP | ||
117 | * dap_id: DAP to connect: TEGRA_DAS_DAP_ID_* | ||
118 | * other_dap_sel: DAP to connect to: TEGRA_DAS_DAP_SEL_DAP* | ||
119 | * master: Is this DAP the master (1) or slave (0) | ||
120 | * sdata1rx: Is this DAP's SDATA1 pin RX (1) or TX (0) | ||
121 | * sdata2rx: Is this DAP's SDATA2 pin RX (1) or TX (0) | ||
122 | */ | ||
123 | extern int tegra_das_connect_dap_to_dap(int dap_id, int other_dap_sel, | ||
124 | int master, int sdata1rx, | ||
125 | int sdata2rx); | ||
126 | |||
127 | /* | ||
128 | * Connect a DAC's input to a DAP | ||
129 | * (DAC outputs are selected by the DAP) | ||
130 | * dac_id: DAC ID to connect: TEGRA_DAS_DAC_ID_* | ||
131 | * dap_sel: DAP to receive input from: TEGRA_DAS_DAC_SEL_DAP* | ||
132 | */ | ||
133 | extern int tegra_das_connect_dac_to_dap(int dac_id, int dap_sel); | ||
134 | |||
135 | #endif | ||
diff --git a/sound/soc/tegra/tegra_i2s.c b/sound/soc/tegra/tegra_i2s.c deleted file mode 100644 index 95f03c10b4f..00000000000 --- a/sound/soc/tegra/tegra_i2s.c +++ /dev/null | |||
@@ -1,509 +0,0 @@ | |||
1 | /* | ||
2 | * tegra_i2s.c - Tegra I2S driver | ||
3 | * | ||
4 | * Author: Stephen Warren <swarren@nvidia.com> | ||
5 | * Copyright (C) 2010 - NVIDIA, Inc. | ||
6 | * | ||
7 | * Based on code copyright/by: | ||
8 | * | ||
9 | * Copyright (c) 2009-2010, 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 <sound/core.h> | ||
41 | #include <sound/pcm.h> | ||
42 | #include <sound/pcm_params.h> | ||
43 | #include <sound/soc.h> | ||
44 | |||
45 | #include "tegra_das.h" | ||
46 | #include "tegra_i2s.h" | ||
47 | |||
48 | #define DRV_NAME "tegra-i2s" | ||
49 | |||
50 | static inline void tegra_i2s_write(struct tegra_i2s *i2s, u32 reg, u32 val) | ||
51 | { | ||
52 | __raw_writel(val, i2s->regs + reg); | ||
53 | } | ||
54 | |||
55 | static inline u32 tegra_i2s_read(struct tegra_i2s *i2s, u32 reg) | ||
56 | { | ||
57 | return __raw_readl(i2s->regs + reg); | ||
58 | } | ||
59 | |||
60 | #ifdef CONFIG_DEBUG_FS | ||
61 | static int tegra_i2s_show(struct seq_file *s, void *unused) | ||
62 | { | ||
63 | #define REG(r) { r, #r } | ||
64 | static const struct { | ||
65 | int offset; | ||
66 | const char *name; | ||
67 | } regs[] = { | ||
68 | REG(TEGRA_I2S_CTRL), | ||
69 | REG(TEGRA_I2S_STATUS), | ||
70 | REG(TEGRA_I2S_TIMING), | ||
71 | REG(TEGRA_I2S_FIFO_SCR), | ||
72 | REG(TEGRA_I2S_PCM_CTRL), | ||
73 | REG(TEGRA_I2S_NW_CTRL), | ||
74 | REG(TEGRA_I2S_TDM_CTRL), | ||
75 | REG(TEGRA_I2S_TDM_TX_RX_CTRL), | ||
76 | }; | ||
77 | #undef REG | ||
78 | |||
79 | struct tegra_i2s *i2s = s->private; | ||
80 | int i; | ||
81 | |||
82 | for (i = 0; i < ARRAY_SIZE(regs); i++) { | ||
83 | u32 val = tegra_i2s_read(i2s, regs[i].offset); | ||
84 | seq_printf(s, "%s = %08x\n", regs[i].name, val); | ||
85 | } | ||
86 | |||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | static int tegra_i2s_debug_open(struct inode *inode, struct file *file) | ||
91 | { | ||
92 | return single_open(file, tegra_i2s_show, inode->i_private); | ||
93 | } | ||
94 | |||
95 | static const struct file_operations tegra_i2s_debug_fops = { | ||
96 | .open = tegra_i2s_debug_open, | ||
97 | .read = seq_read, | ||
98 | .llseek = seq_lseek, | ||
99 | .release = single_release, | ||
100 | }; | ||
101 | |||
102 | static void tegra_i2s_debug_add(struct tegra_i2s *i2s, int id) | ||
103 | { | ||
104 | char name[] = DRV_NAME ".0"; | ||
105 | |||
106 | snprintf(name, sizeof(name), DRV_NAME".%1d", id); | ||
107 | i2s->debug = debugfs_create_file(name, S_IRUGO, snd_soc_debugfs_root, | ||
108 | i2s, &tegra_i2s_debug_fops); | ||
109 | } | ||
110 | |||
111 | static void tegra_i2s_debug_remove(struct tegra_i2s *i2s) | ||
112 | { | ||
113 | if (i2s->debug) | ||
114 | debugfs_remove(i2s->debug); | ||
115 | } | ||
116 | #else | ||
117 | static inline void tegra_i2s_debug_add(struct tegra_i2s *i2s, int id) | ||
118 | { | ||
119 | } | ||
120 | |||
121 | static inline void tegra_i2s_debug_remove(struct tegra_i2s *i2s) | ||
122 | { | ||
123 | } | ||
124 | #endif | ||
125 | |||
126 | static int tegra_i2s_set_fmt(struct snd_soc_dai *dai, | ||
127 | unsigned int fmt) | ||
128 | { | ||
129 | struct tegra_i2s *i2s = snd_soc_dai_get_drvdata(dai); | ||
130 | |||
131 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
132 | case SND_SOC_DAIFMT_NB_NF: | ||
133 | break; | ||
134 | default: | ||
135 | return -EINVAL; | ||
136 | } | ||
137 | |||
138 | i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_MASTER_ENABLE; | ||
139 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
140 | case SND_SOC_DAIFMT_CBS_CFS: | ||
141 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_MASTER_ENABLE; | ||
142 | break; | ||
143 | case SND_SOC_DAIFMT_CBM_CFM: | ||
144 | break; | ||
145 | default: | ||
146 | return -EINVAL; | ||
147 | } | ||
148 | |||
149 | i2s->reg_ctrl &= ~(TEGRA_I2S_CTRL_BIT_FORMAT_MASK | | ||
150 | TEGRA_I2S_CTRL_LRCK_MASK); | ||
151 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
152 | case SND_SOC_DAIFMT_DSP_A: | ||
153 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_DSP; | ||
154 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW; | ||
155 | break; | ||
156 | case SND_SOC_DAIFMT_DSP_B: | ||
157 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_DSP; | ||
158 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_R_LOW; | ||
159 | break; | ||
160 | case SND_SOC_DAIFMT_I2S: | ||
161 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_I2S; | ||
162 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW; | ||
163 | break; | ||
164 | case SND_SOC_DAIFMT_RIGHT_J: | ||
165 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_RJM; | ||
166 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW; | ||
167 | break; | ||
168 | case SND_SOC_DAIFMT_LEFT_J: | ||
169 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_LJM; | ||
170 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW; | ||
171 | break; | ||
172 | default: | ||
173 | return -EINVAL; | ||
174 | } | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static int tegra_i2s_hw_params(struct snd_pcm_substream *substream, | ||
180 | struct snd_pcm_hw_params *params, | ||
181 | struct snd_soc_dai *dai) | ||
182 | { | ||
183 | struct device *dev = substream->pcm->card->dev; | ||
184 | struct tegra_i2s *i2s = snd_soc_dai_get_drvdata(dai); | ||
185 | u32 reg; | ||
186 | int ret, sample_size, srate, i2sclock, bitcnt; | ||
187 | |||
188 | i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_BIT_SIZE_MASK; | ||
189 | switch (params_format(params)) { | ||
190 | case SNDRV_PCM_FORMAT_S16_LE: | ||
191 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_SIZE_16; | ||
192 | sample_size = 16; | ||
193 | break; | ||
194 | case SNDRV_PCM_FORMAT_S24_LE: | ||
195 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_SIZE_24; | ||
196 | sample_size = 24; | ||
197 | break; | ||
198 | case SNDRV_PCM_FORMAT_S32_LE: | ||
199 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_SIZE_32; | ||
200 | sample_size = 32; | ||
201 | break; | ||
202 | default: | ||
203 | return -EINVAL; | ||
204 | } | ||
205 | |||
206 | srate = params_rate(params); | ||
207 | |||
208 | /* Final "* 2" required by Tegra hardware */ | ||
209 | i2sclock = srate * params_channels(params) * sample_size * 2; | ||
210 | |||
211 | ret = clk_set_rate(i2s->clk_i2s, i2sclock); | ||
212 | if (ret) { | ||
213 | dev_err(dev, "Can't set I2S clock rate: %d\n", ret); | ||
214 | return ret; | ||
215 | } | ||
216 | |||
217 | bitcnt = (i2sclock / (2 * srate)) - 1; | ||
218 | if (bitcnt < 0 || bitcnt > TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US) | ||
219 | return -EINVAL; | ||
220 | reg = bitcnt << TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT; | ||
221 | |||
222 | if (i2sclock % (2 * srate)) | ||
223 | reg |= TEGRA_I2S_TIMING_NON_SYM_ENABLE; | ||
224 | |||
225 | if (!i2s->clk_refs) | ||
226 | clk_enable(i2s->clk_i2s); | ||
227 | |||
228 | tegra_i2s_write(i2s, TEGRA_I2S_TIMING, reg); | ||
229 | |||
230 | tegra_i2s_write(i2s, TEGRA_I2S_FIFO_SCR, | ||
231 | TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS | | ||
232 | TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS); | ||
233 | |||
234 | if (!i2s->clk_refs) | ||
235 | clk_disable(i2s->clk_i2s); | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static void tegra_i2s_start_playback(struct tegra_i2s *i2s) | ||
241 | { | ||
242 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_FIFO1_ENABLE; | ||
243 | tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl); | ||
244 | } | ||
245 | |||
246 | static void tegra_i2s_stop_playback(struct tegra_i2s *i2s) | ||
247 | { | ||
248 | i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_FIFO1_ENABLE; | ||
249 | tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl); | ||
250 | } | ||
251 | |||
252 | static void tegra_i2s_start_capture(struct tegra_i2s *i2s) | ||
253 | { | ||
254 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_FIFO2_ENABLE; | ||
255 | tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl); | ||
256 | } | ||
257 | |||
258 | static void tegra_i2s_stop_capture(struct tegra_i2s *i2s) | ||
259 | { | ||
260 | i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_FIFO2_ENABLE; | ||
261 | tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl); | ||
262 | } | ||
263 | |||
264 | static int tegra_i2s_trigger(struct snd_pcm_substream *substream, int cmd, | ||
265 | struct snd_soc_dai *dai) | ||
266 | { | ||
267 | struct tegra_i2s *i2s = snd_soc_dai_get_drvdata(dai); | ||
268 | |||
269 | switch (cmd) { | ||
270 | case SNDRV_PCM_TRIGGER_START: | ||
271 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
272 | case SNDRV_PCM_TRIGGER_RESUME: | ||
273 | if (!i2s->clk_refs) | ||
274 | clk_enable(i2s->clk_i2s); | ||
275 | i2s->clk_refs++; | ||
276 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
277 | tegra_i2s_start_playback(i2s); | ||
278 | else | ||
279 | tegra_i2s_start_capture(i2s); | ||
280 | break; | ||
281 | case SNDRV_PCM_TRIGGER_STOP: | ||
282 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
283 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
284 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
285 | tegra_i2s_stop_playback(i2s); | ||
286 | else | ||
287 | tegra_i2s_stop_capture(i2s); | ||
288 | i2s->clk_refs--; | ||
289 | if (!i2s->clk_refs) | ||
290 | clk_disable(i2s->clk_i2s); | ||
291 | break; | ||
292 | default: | ||
293 | return -EINVAL; | ||
294 | } | ||
295 | |||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static int tegra_i2s_probe(struct snd_soc_dai *dai) | ||
300 | { | ||
301 | struct tegra_i2s * i2s = snd_soc_dai_get_drvdata(dai); | ||
302 | |||
303 | dai->capture_dma_data = &i2s->capture_dma_data; | ||
304 | dai->playback_dma_data = &i2s->playback_dma_data; | ||
305 | |||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | static struct snd_soc_dai_ops tegra_i2s_dai_ops = { | ||
310 | .set_fmt = tegra_i2s_set_fmt, | ||
311 | .hw_params = tegra_i2s_hw_params, | ||
312 | .trigger = tegra_i2s_trigger, | ||
313 | }; | ||
314 | |||
315 | struct snd_soc_dai_driver tegra_i2s_dai[] = { | ||
316 | { | ||
317 | .name = DRV_NAME ".0", | ||
318 | .probe = tegra_i2s_probe, | ||
319 | .playback = { | ||
320 | .channels_min = 2, | ||
321 | .channels_max = 2, | ||
322 | .rates = SNDRV_PCM_RATE_8000_96000, | ||
323 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
324 | }, | ||
325 | .capture = { | ||
326 | .channels_min = 2, | ||
327 | .channels_max = 2, | ||
328 | .rates = SNDRV_PCM_RATE_8000_96000, | ||
329 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
330 | }, | ||
331 | .ops = &tegra_i2s_dai_ops, | ||
332 | .symmetric_rates = 1, | ||
333 | }, | ||
334 | { | ||
335 | .name = DRV_NAME ".1", | ||
336 | .probe = tegra_i2s_probe, | ||
337 | .playback = { | ||
338 | .channels_min = 2, | ||
339 | .channels_max = 2, | ||
340 | .rates = SNDRV_PCM_RATE_8000_96000, | ||
341 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
342 | }, | ||
343 | .capture = { | ||
344 | .channels_min = 2, | ||
345 | .channels_max = 2, | ||
346 | .rates = SNDRV_PCM_RATE_8000_96000, | ||
347 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
348 | }, | ||
349 | .ops = &tegra_i2s_dai_ops, | ||
350 | .symmetric_rates = 1, | ||
351 | }, | ||
352 | }; | ||
353 | |||
354 | static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev) | ||
355 | { | ||
356 | struct tegra_i2s * i2s; | ||
357 | char clk_name[12]; /* tegra-i2s.0 */ | ||
358 | struct resource *mem, *memregion, *dmareq; | ||
359 | int ret; | ||
360 | |||
361 | if ((pdev->id < 0) || | ||
362 | (pdev->id >= ARRAY_SIZE(tegra_i2s_dai))) { | ||
363 | dev_err(&pdev->dev, "ID %d out of range\n", pdev->id); | ||
364 | return -EINVAL; | ||
365 | } | ||
366 | |||
367 | /* | ||
368 | * FIXME: Until a codec driver exists for the tegra DAS, hard-code a | ||
369 | * 1:1 mapping between audio controllers and audio ports. | ||
370 | */ | ||
371 | ret = tegra_das_connect_dap_to_dac(TEGRA_DAS_DAP_ID_1 + pdev->id, | ||
372 | TEGRA_DAS_DAP_SEL_DAC1 + pdev->id); | ||
373 | if (ret) { | ||
374 | dev_err(&pdev->dev, "Can't set up DAP connection\n"); | ||
375 | return ret; | ||
376 | } | ||
377 | ret = tegra_das_connect_dac_to_dap(TEGRA_DAS_DAC_ID_1 + pdev->id, | ||
378 | TEGRA_DAS_DAC_SEL_DAP1 + pdev->id); | ||
379 | if (ret) { | ||
380 | dev_err(&pdev->dev, "Can't set up DAC connection\n"); | ||
381 | return ret; | ||
382 | } | ||
383 | |||
384 | i2s = kzalloc(sizeof(struct tegra_i2s), GFP_KERNEL); | ||
385 | if (!i2s) { | ||
386 | dev_err(&pdev->dev, "Can't allocate tegra_i2s\n"); | ||
387 | ret = -ENOMEM; | ||
388 | goto exit; | ||
389 | } | ||
390 | dev_set_drvdata(&pdev->dev, i2s); | ||
391 | |||
392 | snprintf(clk_name, sizeof(clk_name), DRV_NAME ".%d", pdev->id); | ||
393 | i2s->clk_i2s = clk_get_sys(clk_name, NULL); | ||
394 | if (IS_ERR(i2s->clk_i2s)) { | ||
395 | dev_err(&pdev->dev, "Can't retrieve i2s clock\n"); | ||
396 | ret = PTR_ERR(i2s->clk_i2s); | ||
397 | goto err_free; | ||
398 | } | ||
399 | |||
400 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
401 | if (!mem) { | ||
402 | dev_err(&pdev->dev, "No memory resource\n"); | ||
403 | ret = -ENODEV; | ||
404 | goto err_clk_put; | ||
405 | } | ||
406 | |||
407 | dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0); | ||
408 | if (!dmareq) { | ||
409 | dev_err(&pdev->dev, "No DMA resource\n"); | ||
410 | ret = -ENODEV; | ||
411 | goto err_clk_put; | ||
412 | } | ||
413 | |||
414 | memregion = request_mem_region(mem->start, resource_size(mem), | ||
415 | DRV_NAME); | ||
416 | if (!memregion) { | ||
417 | dev_err(&pdev->dev, "Memory region already claimed\n"); | ||
418 | ret = -EBUSY; | ||
419 | goto err_clk_put; | ||
420 | } | ||
421 | |||
422 | i2s->regs = ioremap(mem->start, resource_size(mem)); | ||
423 | if (!i2s->regs) { | ||
424 | dev_err(&pdev->dev, "ioremap failed\n"); | ||
425 | ret = -ENOMEM; | ||
426 | goto err_release; | ||
427 | } | ||
428 | |||
429 | i2s->capture_dma_data.addr = mem->start + TEGRA_I2S_FIFO2; | ||
430 | i2s->capture_dma_data.wrap = 4; | ||
431 | i2s->capture_dma_data.width = 32; | ||
432 | i2s->capture_dma_data.req_sel = dmareq->start; | ||
433 | |||
434 | i2s->playback_dma_data.addr = mem->start + TEGRA_I2S_FIFO1; | ||
435 | i2s->playback_dma_data.wrap = 4; | ||
436 | i2s->playback_dma_data.width = 32; | ||
437 | i2s->playback_dma_data.req_sel = dmareq->start; | ||
438 | |||
439 | i2s->reg_ctrl = TEGRA_I2S_CTRL_FIFO_FORMAT_PACKED; | ||
440 | |||
441 | ret = snd_soc_register_dai(&pdev->dev, &tegra_i2s_dai[pdev->id]); | ||
442 | if (ret) { | ||
443 | dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); | ||
444 | ret = -ENOMEM; | ||
445 | goto err_unmap; | ||
446 | } | ||
447 | |||
448 | tegra_i2s_debug_add(i2s, pdev->id); | ||
449 | |||
450 | return 0; | ||
451 | |||
452 | err_unmap: | ||
453 | iounmap(i2s->regs); | ||
454 | err_release: | ||
455 | release_mem_region(mem->start, resource_size(mem)); | ||
456 | err_clk_put: | ||
457 | clk_put(i2s->clk_i2s); | ||
458 | err_free: | ||
459 | kfree(i2s); | ||
460 | exit: | ||
461 | return ret; | ||
462 | } | ||
463 | |||
464 | static int __devexit tegra_i2s_platform_remove(struct platform_device *pdev) | ||
465 | { | ||
466 | struct tegra_i2s *i2s = dev_get_drvdata(&pdev->dev); | ||
467 | struct resource *res; | ||
468 | |||
469 | snd_soc_unregister_dai(&pdev->dev); | ||
470 | |||
471 | tegra_i2s_debug_remove(i2s); | ||
472 | |||
473 | iounmap(i2s->regs); | ||
474 | |||
475 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
476 | release_mem_region(res->start, resource_size(res)); | ||
477 | |||
478 | clk_put(i2s->clk_i2s); | ||
479 | |||
480 | kfree(i2s); | ||
481 | |||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | static struct platform_driver tegra_i2s_driver = { | ||
486 | .driver = { | ||
487 | .name = DRV_NAME, | ||
488 | .owner = THIS_MODULE, | ||
489 | }, | ||
490 | .probe = tegra_i2s_platform_probe, | ||
491 | .remove = __devexit_p(tegra_i2s_platform_remove), | ||
492 | }; | ||
493 | |||
494 | static int __init snd_tegra_i2s_init(void) | ||
495 | { | ||
496 | return platform_driver_register(&tegra_i2s_driver); | ||
497 | } | ||
498 | module_init(snd_tegra_i2s_init); | ||
499 | |||
500 | static void __exit snd_tegra_i2s_exit(void) | ||
501 | { | ||
502 | platform_driver_unregister(&tegra_i2s_driver); | ||
503 | } | ||
504 | module_exit(snd_tegra_i2s_exit); | ||
505 | |||
506 | MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); | ||
507 | MODULE_DESCRIPTION("Tegra I2S ASoC driver"); | ||
508 | MODULE_LICENSE("GPL"); | ||
509 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/sound/soc/tegra/tegra_i2s.h b/sound/soc/tegra/tegra_i2s.h deleted file mode 100644 index 2b38a096f46..00000000000 --- a/sound/soc/tegra/tegra_i2s.h +++ /dev/null | |||
@@ -1,165 +0,0 @@ | |||
1 | /* | ||
2 | * tegra_i2s.h - Definitions for Tegra I2S driver | ||
3 | * | ||
4 | * Author: Stephen Warren <swarren@nvidia.com> | ||
5 | * Copyright (C) 2010 - NVIDIA, Inc. | ||
6 | * | ||
7 | * Based on code copyright/by: | ||
8 | * | ||
9 | * Copyright (c) 2009-2010, 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 __TEGRA_I2S_H__ | ||
32 | #define __TEGRA_I2S_H__ | ||
33 | |||
34 | #include "tegra_pcm.h" | ||
35 | |||
36 | /* Register offsets from TEGRA_I2S1_BASE and TEGRA_I2S2_BASE */ | ||
37 | |||
38 | #define TEGRA_I2S_CTRL 0x00 | ||
39 | #define TEGRA_I2S_STATUS 0x04 | ||
40 | #define TEGRA_I2S_TIMING 0x08 | ||
41 | #define TEGRA_I2S_FIFO_SCR 0x0c | ||
42 | #define TEGRA_I2S_PCM_CTRL 0x10 | ||
43 | #define TEGRA_I2S_NW_CTRL 0x14 | ||
44 | #define TEGRA_I2S_TDM_CTRL 0x20 | ||
45 | #define TEGRA_I2S_TDM_TX_RX_CTRL 0x24 | ||
46 | #define TEGRA_I2S_FIFO1 0x40 | ||
47 | #define TEGRA_I2S_FIFO2 0x80 | ||
48 | |||
49 | /* Fields in TEGRA_I2S_CTRL */ | ||
50 | |||
51 | #define TEGRA_I2S_CTRL_FIFO2_TX_ENABLE (1 << 30) | ||
52 | #define TEGRA_I2S_CTRL_FIFO1_ENABLE (1 << 29) | ||
53 | #define TEGRA_I2S_CTRL_FIFO2_ENABLE (1 << 28) | ||
54 | #define TEGRA_I2S_CTRL_FIFO1_RX_ENABLE (1 << 27) | ||
55 | #define TEGRA_I2S_CTRL_FIFO_LPBK_ENABLE (1 << 26) | ||
56 | #define TEGRA_I2S_CTRL_MASTER_ENABLE (1 << 25) | ||
57 | |||
58 | #define TEGRA_I2S_LRCK_LEFT_LOW 0 | ||
59 | #define TEGRA_I2S_LRCK_RIGHT_LOW 1 | ||
60 | |||
61 | #define TEGRA_I2S_CTRL_LRCK_SHIFT 24 | ||
62 | #define TEGRA_I2S_CTRL_LRCK_MASK (1 << TEGRA_I2S_CTRL_LRCK_SHIFT) | ||
63 | #define TEGRA_I2S_CTRL_LRCK_L_LOW (TEGRA_I2S_LRCK_LEFT_LOW << TEGRA_I2S_CTRL_LRCK_SHIFT) | ||
64 | #define TEGRA_I2S_CTRL_LRCK_R_LOW (TEGRA_I2S_LRCK_RIGHT_LOW << TEGRA_I2S_CTRL_LRCK_SHIFT) | ||
65 | |||
66 | #define TEGRA_I2S_BIT_FORMAT_I2S 0 | ||
67 | #define TEGRA_I2S_BIT_FORMAT_RJM 1 | ||
68 | #define TEGRA_I2S_BIT_FORMAT_LJM 2 | ||
69 | #define TEGRA_I2S_BIT_FORMAT_DSP 3 | ||
70 | |||
71 | #define TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT 10 | ||
72 | #define TEGRA_I2S_CTRL_BIT_FORMAT_MASK (3 << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT) | ||
73 | #define TEGRA_I2S_CTRL_BIT_FORMAT_I2S (TEGRA_I2S_BIT_FORMAT_I2S << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT) | ||
74 | #define TEGRA_I2S_CTRL_BIT_FORMAT_RJM (TEGRA_I2S_BIT_FORMAT_RJM << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT) | ||
75 | #define TEGRA_I2S_CTRL_BIT_FORMAT_LJM (TEGRA_I2S_BIT_FORMAT_LJM << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT) | ||
76 | #define TEGRA_I2S_CTRL_BIT_FORMAT_DSP (TEGRA_I2S_BIT_FORMAT_DSP << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT) | ||
77 | |||
78 | #define TEGRA_I2S_BIT_SIZE_16 0 | ||
79 | #define TEGRA_I2S_BIT_SIZE_20 1 | ||
80 | #define TEGRA_I2S_BIT_SIZE_24 2 | ||
81 | #define TEGRA_I2S_BIT_SIZE_32 3 | ||
82 | |||
83 | #define TEGRA_I2S_CTRL_BIT_SIZE_SHIFT 8 | ||
84 | #define TEGRA_I2S_CTRL_BIT_SIZE_MASK (3 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT) | ||
85 | #define TEGRA_I2S_CTRL_BIT_SIZE_16 (TEGRA_I2S_BIT_SIZE_16 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT) | ||
86 | #define TEGRA_I2S_CTRL_BIT_SIZE_20 (TEGRA_I2S_BIT_SIZE_20 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT) | ||
87 | #define TEGRA_I2S_CTRL_BIT_SIZE_24 (TEGRA_I2S_BIT_SIZE_24 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT) | ||
88 | #define TEGRA_I2S_CTRL_BIT_SIZE_32 (TEGRA_I2S_BIT_SIZE_32 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT) | ||
89 | |||
90 | #define TEGRA_I2S_FIFO_16_LSB 0 | ||
91 | #define TEGRA_I2S_FIFO_20_LSB 1 | ||
92 | #define TEGRA_I2S_FIFO_24_LSB 2 | ||
93 | #define TEGRA_I2S_FIFO_32 3 | ||
94 | #define TEGRA_I2S_FIFO_PACKED 7 | ||
95 | |||
96 | #define TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT 4 | ||
97 | #define TEGRA_I2S_CTRL_FIFO_FORMAT_MASK (7 << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT) | ||
98 | #define TEGRA_I2S_CTRL_FIFO_FORMAT_16_LSB (TEGRA_I2S_FIFO_16_LSB << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT) | ||
99 | #define TEGRA_I2S_CTRL_FIFO_FORMAT_20_LSB (TEGRA_I2S_FIFO_20_LSB << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT) | ||
100 | #define TEGRA_I2S_CTRL_FIFO_FORMAT_24_LSB (TEGRA_I2S_FIFO_24_LSB << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT) | ||
101 | #define TEGRA_I2S_CTRL_FIFO_FORMAT_32 (TEGRA_I2S_FIFO_32 << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT) | ||
102 | #define TEGRA_I2S_CTRL_FIFO_FORMAT_PACKED (TEGRA_I2S_FIFO_PACKED << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT) | ||
103 | |||
104 | #define TEGRA_I2S_CTRL_IE_FIFO1_ERR (1 << 3) | ||
105 | #define TEGRA_I2S_CTRL_IE_FIFO2_ERR (1 << 2) | ||
106 | #define TEGRA_I2S_CTRL_QE_FIFO1 (1 << 1) | ||
107 | #define TEGRA_I2S_CTRL_QE_FIFO2 (1 << 0) | ||
108 | |||
109 | /* Fields in TEGRA_I2S_STATUS */ | ||
110 | |||
111 | #define TEGRA_I2S_STATUS_FIFO1_RDY (1 << 31) | ||
112 | #define TEGRA_I2S_STATUS_FIFO2_RDY (1 << 30) | ||
113 | #define TEGRA_I2S_STATUS_FIFO1_BSY (1 << 29) | ||
114 | #define TEGRA_I2S_STATUS_FIFO2_BSY (1 << 28) | ||
115 | #define TEGRA_I2S_STATUS_FIFO1_ERR (1 << 3) | ||
116 | #define TEGRA_I2S_STATUS_FIFO2_ERR (1 << 2) | ||
117 | #define TEGRA_I2S_STATUS_QS_FIFO1 (1 << 1) | ||
118 | #define TEGRA_I2S_STATUS_QS_FIFO2 (1 << 0) | ||
119 | |||
120 | /* Fields in TEGRA_I2S_TIMING */ | ||
121 | |||
122 | #define TEGRA_I2S_TIMING_NON_SYM_ENABLE (1 << 12) | ||
123 | #define TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT 0 | ||
124 | #define TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US 0x7fff | ||
125 | #define TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK (TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US << TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT) | ||
126 | |||
127 | /* Fields in TEGRA_I2S_FIFO_SCR */ | ||
128 | |||
129 | #define TEGRA_I2S_FIFO_SCR_FIFO2_FULL_EMPTY_COUNT_SHIFT 24 | ||
130 | #define TEGRA_I2S_FIFO_SCR_FIFO1_FULL_EMPTY_COUNT_SHIFT 16 | ||
131 | #define TEGRA_I2S_FIFO_SCR_FIFO_FULL_EMPTY_COUNT_MASK 0x3f | ||
132 | |||
133 | #define TEGRA_I2S_FIFO_SCR_FIFO2_CLR (1 << 12) | ||
134 | #define TEGRA_I2S_FIFO_SCR_FIFO1_CLR (1 << 8) | ||
135 | |||
136 | #define TEGRA_I2S_FIFO_ATN_LVL_ONE_SLOT 0 | ||
137 | #define TEGRA_I2S_FIFO_ATN_LVL_FOUR_SLOTS 1 | ||
138 | #define TEGRA_I2S_FIFO_ATN_LVL_EIGHT_SLOTS 2 | ||
139 | #define TEGRA_I2S_FIFO_ATN_LVL_TWELVE_SLOTS 3 | ||
140 | |||
141 | #define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT 4 | ||
142 | #define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_MASK (3 << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT) | ||
143 | #define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_ONE_SLOT (TEGRA_I2S_FIFO_ATN_LVL_ONE_SLOT << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT) | ||
144 | #define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS (TEGRA_I2S_FIFO_ATN_LVL_FOUR_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT) | ||
145 | #define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_EIGHT_SLOTS (TEGRA_I2S_FIFO_ATN_LVL_EIGHT_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT) | ||
146 | #define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_TWELVE_SLOTS (TEGRA_I2S_FIFO_ATN_LVL_TWELVE_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT) | ||
147 | |||
148 | #define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT 0 | ||
149 | #define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_MASK (3 << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT) | ||
150 | #define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_ONE_SLOT (TEGRA_I2S_FIFO_ATN_LVL_ONE_SLOT << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT) | ||
151 | #define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS (TEGRA_I2S_FIFO_ATN_LVL_FOUR_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT) | ||
152 | #define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_EIGHT_SLOTS (TEGRA_I2S_FIFO_ATN_LVL_EIGHT_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT) | ||
153 | #define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_TWELVE_SLOTS (TEGRA_I2S_FIFO_ATN_LVL_TWELVE_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT) | ||
154 | |||
155 | struct tegra_i2s { | ||
156 | struct clk *clk_i2s; | ||
157 | int clk_refs; | ||
158 | struct tegra_pcm_dma_params capture_dma_data; | ||
159 | struct tegra_pcm_dma_params playback_dma_data; | ||
160 | void __iomem *regs; | ||
161 | struct dentry *debug; | ||
162 | u32 reg_ctrl; | ||
163 | }; | ||
164 | |||
165 | #endif | ||
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_pcm.c b/sound/soc/tegra/tegra_pcm.c index 3c271f95358..f277d282fbd 100644 --- a/sound/soc/tegra/tegra_pcm.c +++ b/sound/soc/tegra/tegra_pcm.c | |||
@@ -48,9 +48,9 @@ static const struct snd_pcm_hardware tegra_pcm_hardware = { | |||
48 | SNDRV_PCM_INFO_RESUME | | 48 | SNDRV_PCM_INFO_RESUME | |
49 | SNDRV_PCM_INFO_INTERLEAVED, | 49 | SNDRV_PCM_INFO_INTERLEAVED, |
50 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 50 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
51 | .channels_min = 2, | 51 | .channels_min = 1, |
52 | .channels_max = 2, | 52 | .channels_max = 2, |
53 | .period_bytes_min = 1024, | 53 | .period_bytes_min = 128, |
54 | .period_bytes_max = PAGE_SIZE, | 54 | .period_bytes_max = PAGE_SIZE, |
55 | .periods_min = 2, | 55 | .periods_min = 2, |
56 | .periods_max = 8, | 56 | .periods_max = 8, |
@@ -147,28 +147,30 @@ static int tegra_pcm_open(struct snd_pcm_substream *substream) | |||
147 | 147 | ||
148 | spin_lock_init(&prtd->lock); | 148 | spin_lock_init(&prtd->lock); |
149 | 149 | ||
150 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 150 | dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); |
151 | dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); | ||
152 | setup_dma_tx_request(&prtd->dma_req[0], dmap); | ||
153 | setup_dma_tx_request(&prtd->dma_req[1], dmap); | ||
154 | } else { | ||
155 | dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); | ||
156 | setup_dma_rx_request(&prtd->dma_req[0], dmap); | ||
157 | setup_dma_rx_request(&prtd->dma_req[1], dmap); | ||
158 | } | ||
159 | 151 | ||
160 | prtd->dma_req[0].dev = prtd; | 152 | if (dmap) { |
161 | prtd->dma_req[1].dev = prtd; | 153 | prtd->dma_req[0].dev = prtd; |
154 | prtd->dma_req[1].dev = prtd; | ||
162 | 155 | ||
163 | prtd->dma_chan = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT); | 156 | prtd->dma_chan = tegra_dma_allocate_channel( |
164 | if (prtd->dma_chan == NULL) { | 157 | TEGRA_DMA_MODE_CONTINUOUS_SINGLE, |
165 | ret = -ENOMEM; | 158 | "pcm"); |
166 | goto err; | 159 | if (prtd->dma_chan == NULL) { |
160 | ret = -ENOMEM; | ||
161 | goto err; | ||
162 | } | ||
167 | } | 163 | } |
168 | 164 | ||
169 | /* Set HW params now that initialization is complete */ | 165 | /* Set HW params now that initialization is complete */ |
170 | snd_soc_set_runtime_hwparams(substream, &tegra_pcm_hardware); | 166 | snd_soc_set_runtime_hwparams(substream, &tegra_pcm_hardware); |
171 | 167 | ||
168 | /* Ensure period size is multiple of 8 */ | ||
169 | ret = snd_pcm_hw_constraint_step(runtime, 0, | ||
170 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 0x8); | ||
171 | if (ret < 0) | ||
172 | goto err; | ||
173 | |||
172 | /* Ensure that buffer size is a multiple of period size */ | 174 | /* Ensure that buffer size is a multiple of period size */ |
173 | ret = snd_pcm_hw_constraint_integer(runtime, | 175 | ret = snd_pcm_hw_constraint_integer(runtime, |
174 | SNDRV_PCM_HW_PARAM_PERIODS); | 176 | SNDRV_PCM_HW_PARAM_PERIODS); |
@@ -192,7 +194,8 @@ static int tegra_pcm_close(struct snd_pcm_substream *substream) | |||
192 | struct snd_pcm_runtime *runtime = substream->runtime; | 194 | struct snd_pcm_runtime *runtime = substream->runtime; |
193 | struct tegra_runtime_data *prtd = runtime->private_data; | 195 | struct tegra_runtime_data *prtd = runtime->private_data; |
194 | 196 | ||
195 | tegra_dma_free_channel(prtd->dma_chan); | 197 | if (prtd->dma_chan) |
198 | tegra_dma_free_channel(prtd->dma_chan); | ||
196 | 199 | ||
197 | kfree(prtd); | 200 | kfree(prtd); |
198 | 201 | ||
@@ -204,9 +207,21 @@ static int tegra_pcm_hw_params(struct snd_pcm_substream *substream, | |||
204 | { | 207 | { |
205 | struct snd_pcm_runtime *runtime = substream->runtime; | 208 | struct snd_pcm_runtime *runtime = substream->runtime; |
206 | struct tegra_runtime_data *prtd = runtime->private_data; | 209 | struct tegra_runtime_data *prtd = runtime->private_data; |
210 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
211 | struct tegra_pcm_dma_params * dmap; | ||
207 | 212 | ||
208 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | 213 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); |
209 | 214 | ||
215 | dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); | ||
216 | if (dmap) { | ||
217 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
218 | setup_dma_tx_request(&prtd->dma_req[0], dmap); | ||
219 | setup_dma_tx_request(&prtd->dma_req[1], dmap); | ||
220 | } else { | ||
221 | setup_dma_rx_request(&prtd->dma_req[0], dmap); | ||
222 | setup_dma_rx_request(&prtd->dma_req[1], dmap); | ||
223 | } | ||
224 | } | ||
210 | prtd->dma_req[0].size = params_period_bytes(params); | 225 | prtd->dma_req[0].size = params_period_bytes(params); |
211 | prtd->dma_req[1].size = prtd->dma_req[0].size; | 226 | prtd->dma_req[1].size = prtd->dma_req[0].size; |
212 | 227 | ||
@@ -261,10 +276,14 @@ static snd_pcm_uframes_t tegra_pcm_pointer(struct snd_pcm_substream *substream) | |||
261 | { | 276 | { |
262 | struct snd_pcm_runtime *runtime = substream->runtime; | 277 | struct snd_pcm_runtime *runtime = substream->runtime; |
263 | struct tegra_runtime_data *prtd = runtime->private_data; | 278 | struct tegra_runtime_data *prtd = runtime->private_data; |
279 | int dma_transfer_count; | ||
264 | 280 | ||
265 | return prtd->period_index * runtime->period_size; | 281 | dma_transfer_count = tegra_dma_get_transfer_count(prtd->dma_chan, |
266 | } | 282 | &prtd->dma_req[prtd->dma_req_idx]); |
267 | 283 | ||
284 | return prtd->period_index * runtime->period_size + | ||
285 | bytes_to_frames(runtime, dma_transfer_count); | ||
286 | } | ||
268 | 287 | ||
269 | static int tegra_pcm_mmap(struct snd_pcm_substream *substream, | 288 | static int tegra_pcm_mmap(struct snd_pcm_substream *substream, |
270 | struct vm_area_struct *vma) | 289 | struct vm_area_struct *vma) |
@@ -309,9 +328,14 @@ static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) | |||
309 | 328 | ||
310 | static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream) | 329 | static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream) |
311 | { | 330 | { |
312 | struct snd_pcm_substream *substream = pcm->streams[stream].substream; | 331 | struct snd_pcm_substream *substream; |
313 | struct snd_dma_buffer *buf = &substream->dma_buffer; | 332 | struct snd_dma_buffer *buf; |
333 | |||
334 | substream = pcm->streams[stream].substream; | ||
335 | if (!substream) | ||
336 | return; | ||
314 | 337 | ||
338 | buf = &substream->dma_buffer; | ||
315 | if (!buf->area) | 339 | if (!buf->area) |
316 | return; | 340 | return; |
317 | 341 | ||
@@ -322,9 +346,11 @@ static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream) | |||
322 | 346 | ||
323 | static u64 tegra_dma_mask = DMA_BIT_MASK(32); | 347 | static u64 tegra_dma_mask = DMA_BIT_MASK(32); |
324 | 348 | ||
325 | static int tegra_pcm_new(struct snd_card *card, | 349 | static int tegra_pcm_new(struct snd_soc_pcm_runtime *rtd) |
326 | struct snd_soc_dai *dai, struct snd_pcm *pcm) | ||
327 | { | 350 | { |
351 | struct snd_card *card = rtd->card->snd_card; | ||
352 | struct snd_soc_dai *dai = rtd->cpu_dai; | ||
353 | struct snd_pcm *pcm = rtd->pcm; | ||
328 | int ret = 0; | 354 | int ret = 0; |
329 | 355 | ||
330 | if (!card->dev->dma_mask) | 356 | if (!card->dev->dma_mask) |
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); | ||
diff --git a/sound/soc/tegra/tegra_wm8753.c b/sound/soc/tegra/tegra_wm8753.c new file mode 100644 index 00000000000..62c1c056a61 --- /dev/null +++ b/sound/soc/tegra/tegra_wm8753.c | |||
@@ -0,0 +1,972 @@ | |||
1 | /* | ||
2 | * tegra_wm8753.c - Tegra machine ASoC driver for boards using WM8753 codec. | ||
3 | * | ||
4 | * Author: Sumit Bhattacharya <sumitb@nvidia.com> | ||
5 | * Copyright (C) 2010-2011 - NVIDIA, Inc. | ||
6 | * | ||
7 | * Based on code copyright/by: | ||
8 | * | ||
9 | * (c) 2009, 2010 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/module.h> | ||
34 | #include <linux/platform_device.h> | ||
35 | #include <linux/slab.h> | ||
36 | #include <linux/gpio.h> | ||
37 | #include <linux/regulator/consumer.h> | ||
38 | #ifdef CONFIG_SWITCH | ||
39 | #include <linux/switch.h> | ||
40 | #endif | ||
41 | |||
42 | #include <mach/tegra_wm8753_pdata.h> | ||
43 | |||
44 | #include <sound/core.h> | ||
45 | #include <sound/jack.h> | ||
46 | #include <sound/pcm.h> | ||
47 | #include <sound/pcm_params.h> | ||
48 | #include <sound/soc.h> | ||
49 | |||
50 | #include "../codecs/wm8753.h" | ||
51 | |||
52 | #include "tegra_pcm.h" | ||
53 | #include "tegra_asoc_utils.h" | ||
54 | |||
55 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
56 | #include "tegra20_das.h" | ||
57 | #endif | ||
58 | |||
59 | #define DRV_NAME "tegra-snd-wm8753" | ||
60 | |||
61 | #define GPIO_SPKR_EN BIT(0) | ||
62 | #define GPIO_HP_MUTE BIT(1) | ||
63 | #define GPIO_INT_MIC_EN BIT(2) | ||
64 | #define GPIO_EXT_MIC_EN BIT(3) | ||
65 | |||
66 | extern int g_is_call_mode; | ||
67 | |||
68 | struct tegra_wm8753 { | ||
69 | struct tegra_asoc_utils_data util_data; | ||
70 | struct tegra_wm8753_platform_data *pdata; | ||
71 | struct regulator *audio_reg; | ||
72 | int gpio_requested; | ||
73 | int is_call_mode; | ||
74 | int is_call_mode_bt; | ||
75 | }; | ||
76 | |||
77 | static int tegra_wm8753_hw_params(struct snd_pcm_substream *substream, | ||
78 | struct snd_pcm_hw_params *params) | ||
79 | { | ||
80 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
81 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
82 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
83 | struct snd_soc_codec *codec = rtd->codec; | ||
84 | struct snd_soc_card *card = codec->card; | ||
85 | struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card); | ||
86 | int srate, mclk, i2s_daifmt; | ||
87 | int err; | ||
88 | srate = params_rate(params); | ||
89 | switch (srate) { | ||
90 | case 8000: | ||
91 | case 16000: | ||
92 | case 24000: | ||
93 | case 32000: | ||
94 | case 48000: | ||
95 | case 64000: | ||
96 | case 96000: | ||
97 | mclk = 12288000; | ||
98 | break; | ||
99 | case 11025: | ||
100 | case 22050: | ||
101 | case 44100: | ||
102 | case 88200: | ||
103 | mclk = 11289600; | ||
104 | break; | ||
105 | default: | ||
106 | mclk = 12000000; | ||
107 | break; | ||
108 | } | ||
109 | |||
110 | err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); | ||
111 | if (err < 0) { | ||
112 | if (!(machine->util_data.set_mclk % mclk)) | ||
113 | mclk = machine->util_data.set_mclk; | ||
114 | else { | ||
115 | dev_err(card->dev, "Can't configure clocks\n"); | ||
116 | return err; | ||
117 | } | ||
118 | } | ||
119 | |||
120 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); | ||
121 | |||
122 | i2s_daifmt = SND_SOC_DAIFMT_NB_NF | | ||
123 | SND_SOC_DAIFMT_CBS_CFS; | ||
124 | |||
125 | /* Use DSP mode for mono on Tegra20 */ | ||
126 | if ((params_channels(params) != 2) && machine_is_whistler()) | ||
127 | i2s_daifmt |= SND_SOC_DAIFMT_DSP_A; | ||
128 | else | ||
129 | i2s_daifmt |= SND_SOC_DAIFMT_I2S; | ||
130 | |||
131 | err = snd_soc_dai_set_fmt(codec_dai, i2s_daifmt); | ||
132 | if (err < 0) { | ||
133 | dev_err(card->dev, "codec_dai fmt not set\n"); | ||
134 | return err; | ||
135 | } | ||
136 | |||
137 | err = snd_soc_dai_set_fmt(cpu_dai, i2s_daifmt); | ||
138 | if (err < 0) { | ||
139 | dev_err(card->dev, "cpu_dai fmt not set\n"); | ||
140 | return err; | ||
141 | } | ||
142 | |||
143 | err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, | ||
144 | SND_SOC_CLOCK_IN); | ||
145 | if (err < 0) { | ||
146 | dev_err(card->dev, "codec_dai clock not set\n"); | ||
147 | return err; | ||
148 | } | ||
149 | |||
150 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
151 | err = tegra20_das_connect_dac_to_dap(TEGRA20_DAS_DAP_SEL_DAC1, | ||
152 | TEGRA20_DAS_DAP_ID_1); | ||
153 | if (err < 0) { | ||
154 | dev_err(card->dev, "failed to set dap-dac path\n"); | ||
155 | return err; | ||
156 | } | ||
157 | |||
158 | err = tegra20_das_connect_dap_to_dac(TEGRA20_DAS_DAP_ID_1, | ||
159 | TEGRA20_DAS_DAP_SEL_DAC1); | ||
160 | if (err < 0) { | ||
161 | dev_err(card->dev, "failed to set dac-dap path\n"); | ||
162 | return err; | ||
163 | } | ||
164 | #endif | ||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | static int tegra_bt_sco_hw_params(struct snd_pcm_substream *substream, | ||
169 | struct snd_pcm_hw_params *params) | ||
170 | { | ||
171 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
172 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
173 | struct snd_soc_codec *codec = rtd->codec; | ||
174 | struct snd_soc_card *card = codec->card; | ||
175 | struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card); | ||
176 | int srate, mclk, min_mclk; | ||
177 | int err; | ||
178 | |||
179 | srate = params_rate(params); | ||
180 | switch (srate) { | ||
181 | case 11025: | ||
182 | case 22050: | ||
183 | case 44100: | ||
184 | case 88200: | ||
185 | mclk = 11289600; | ||
186 | break; | ||
187 | case 8000: | ||
188 | case 16000: | ||
189 | case 32000: | ||
190 | case 48000: | ||
191 | case 64000: | ||
192 | case 96000: | ||
193 | mclk = 12288000; | ||
194 | break; | ||
195 | default: | ||
196 | return -EINVAL; | ||
197 | } | ||
198 | min_mclk = 64 * srate; | ||
199 | |||
200 | err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); | ||
201 | if (err < 0) { | ||
202 | if (!(machine->util_data.set_mclk % min_mclk)) | ||
203 | mclk = machine->util_data.set_mclk; | ||
204 | else { | ||
205 | dev_err(card->dev, "Can't configure clocks\n"); | ||
206 | return err; | ||
207 | } | ||
208 | } | ||
209 | |||
210 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); | ||
211 | |||
212 | err = snd_soc_dai_set_fmt(cpu_dai, | ||
213 | SND_SOC_DAIFMT_DSP_A | | ||
214 | SND_SOC_DAIFMT_NB_NF | | ||
215 | SND_SOC_DAIFMT_CBS_CFS); | ||
216 | if (err < 0) { | ||
217 | dev_err(card->dev, "cpu_dai fmt not set\n"); | ||
218 | return err; | ||
219 | } | ||
220 | |||
221 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
222 | err = tegra20_das_connect_dac_to_dap(TEGRA20_DAS_DAP_SEL_DAC2, | ||
223 | TEGRA20_DAS_DAP_ID_4); | ||
224 | if (err < 0) { | ||
225 | dev_err(card->dev, "failed to set dac-dap path\n"); | ||
226 | return err; | ||
227 | } | ||
228 | |||
229 | err = tegra20_das_connect_dap_to_dac(TEGRA20_DAS_DAP_ID_4, | ||
230 | TEGRA20_DAS_DAP_SEL_DAC2); | ||
231 | if (err < 0) { | ||
232 | dev_err(card->dev, "failed to set dac-dap path\n"); | ||
233 | return err; | ||
234 | } | ||
235 | #endif | ||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | static int tegra_spdif_hw_params(struct snd_pcm_substream *substream, | ||
240 | struct snd_pcm_hw_params *params) | ||
241 | { | ||
242 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
243 | struct snd_soc_card *card = rtd->card; | ||
244 | struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card); | ||
245 | int srate, mclk, min_mclk; | ||
246 | int err; | ||
247 | |||
248 | srate = params_rate(params); | ||
249 | switch (srate) { | ||
250 | case 11025: | ||
251 | case 22050: | ||
252 | case 44100: | ||
253 | case 88200: | ||
254 | mclk = 11289600; | ||
255 | break; | ||
256 | case 8000: | ||
257 | case 16000: | ||
258 | case 32000: | ||
259 | case 48000: | ||
260 | case 64000: | ||
261 | case 96000: | ||
262 | mclk = 12288000; | ||
263 | break; | ||
264 | default: | ||
265 | return -EINVAL; | ||
266 | } | ||
267 | min_mclk = 128 * srate; | ||
268 | |||
269 | err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); | ||
270 | if (err < 0) { | ||
271 | if (!(machine->util_data.set_mclk % min_mclk)) | ||
272 | mclk = machine->util_data.set_mclk; | ||
273 | else { | ||
274 | dev_err(card->dev, "Can't configure clocks\n"); | ||
275 | return err; | ||
276 | } | ||
277 | } | ||
278 | |||
279 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); | ||
280 | |||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | static int tegra_wm8753_voice_hw_params(struct snd_pcm_substream *substream, | ||
285 | struct snd_pcm_hw_params *params) | ||
286 | { | ||
287 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
288 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
289 | struct snd_soc_codec *codec = rtd->codec; | ||
290 | struct snd_soc_card *card = codec->card; | ||
291 | struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card); | ||
292 | int srate, mclk, i2s_daifmt, sys_clk; | ||
293 | int err, pcmdiv, vxclkdiv; | ||
294 | |||
295 | srate = params_rate(params); | ||
296 | switch (srate) { | ||
297 | case 8000: | ||
298 | case 16000: | ||
299 | case 24000: | ||
300 | case 32000: | ||
301 | case 48000: | ||
302 | case 64000: | ||
303 | case 96000: | ||
304 | mclk = 12288000; | ||
305 | break; | ||
306 | case 11025: | ||
307 | case 22050: | ||
308 | case 44100: | ||
309 | case 88200: | ||
310 | mclk = 11289600; | ||
311 | break; | ||
312 | default: | ||
313 | mclk = 12000000; | ||
314 | break; | ||
315 | } | ||
316 | |||
317 | err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); | ||
318 | if (err < 0) { | ||
319 | if (!(machine->util_data.set_mclk % mclk)) | ||
320 | mclk = machine->util_data.set_mclk; | ||
321 | else { | ||
322 | dev_err(card->dev, "Can't configure clocks\n"); | ||
323 | return err; | ||
324 | } | ||
325 | } | ||
326 | |||
327 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); | ||
328 | |||
329 | i2s_daifmt = SND_SOC_DAIFMT_NB_NF | | ||
330 | SND_SOC_DAIFMT_CBM_CFM; | ||
331 | |||
332 | i2s_daifmt |= SND_SOC_DAIFMT_DSP_A; | ||
333 | |||
334 | err = snd_soc_dai_set_fmt(codec_dai, i2s_daifmt); | ||
335 | if (err < 0) { | ||
336 | dev_err(card->dev, "codec_dai fmt not set\n"); | ||
337 | return err; | ||
338 | } | ||
339 | |||
340 | sys_clk = machine->util_data.set_mclk; | ||
341 | |||
342 | err = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK, sys_clk, | ||
343 | SND_SOC_CLOCK_IN); | ||
344 | if (err < 0) { | ||
345 | dev_err(card->dev, "codec_dai clock not set\n"); | ||
346 | return err; | ||
347 | } | ||
348 | |||
349 | err = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, | ||
350 | sys_clk, 12288000); | ||
351 | |||
352 | if (err < 0) { | ||
353 | dev_err(card->dev, "codec_dai pll not set\n"); | ||
354 | return err; | ||
355 | } | ||
356 | |||
357 | if (params_rate(params) == 8000) { | ||
358 | pcmdiv = WM8753_PCM_DIV_6; | ||
359 | /* BB expecting 2048Khz bclk */ | ||
360 | vxclkdiv = WM8753_VXCLK_DIV_1; | ||
361 | } else if (params_rate(params) == 16000) { | ||
362 | pcmdiv = WM8753_PCM_DIV_3; | ||
363 | /* BB expecting 2048Khz bclk */ | ||
364 | vxclkdiv = WM8753_VXCLK_DIV_2; | ||
365 | } else { | ||
366 | dev_err(card->dev, "codec_dai unsupported voice rate\n"); | ||
367 | return -EINVAL; | ||
368 | } | ||
369 | |||
370 | snd_soc_dai_set_clkdiv(codec_dai, WM8753_VXCLKDIV, vxclkdiv); | ||
371 | snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv); | ||
372 | |||
373 | machine->is_call_mode_bt = 0; | ||
374 | |||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | static int tegra_bt_call_hw_params(struct snd_pcm_substream *substream, | ||
379 | struct snd_pcm_hw_params *params) | ||
380 | { | ||
381 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
382 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
383 | struct snd_soc_codec *codec = rtd->codec; | ||
384 | struct snd_soc_card *card = codec->card; | ||
385 | struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card); | ||
386 | int srate, mclk; | ||
387 | int err; | ||
388 | |||
389 | srate = params_rate(params); | ||
390 | switch (srate) { | ||
391 | case 8000: | ||
392 | case 16000: | ||
393 | case 24000: | ||
394 | case 32000: | ||
395 | case 48000: | ||
396 | case 64000: | ||
397 | case 96000: | ||
398 | mclk = 12288000; | ||
399 | break; | ||
400 | case 11025: | ||
401 | case 22050: | ||
402 | case 44100: | ||
403 | case 88200: | ||
404 | mclk = 11289600; | ||
405 | break; | ||
406 | default: | ||
407 | mclk = 12000000; | ||
408 | break; | ||
409 | } | ||
410 | |||
411 | err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); | ||
412 | if (err < 0) { | ||
413 | if (!(machine->util_data.set_mclk % mclk)) | ||
414 | mclk = machine->util_data.set_mclk; | ||
415 | else { | ||
416 | dev_err(card->dev, "Can't configure clocks\n"); | ||
417 | return err; | ||
418 | } | ||
419 | } | ||
420 | |||
421 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); | ||
422 | |||
423 | machine->is_call_mode_bt = 1; | ||
424 | |||
425 | return 0; | ||
426 | } | ||
427 | |||
428 | |||
429 | static int tegra_hw_free(struct snd_pcm_substream *substream) | ||
430 | { | ||
431 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
432 | struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(rtd->card); | ||
433 | |||
434 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 0); | ||
435 | |||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | static int tegra_bt_call_hw_free(struct snd_pcm_substream *substream) | ||
440 | { | ||
441 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
442 | struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(rtd->card); | ||
443 | |||
444 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 0); | ||
445 | machine->is_call_mode_bt = 0; | ||
446 | |||
447 | return 0; | ||
448 | } | ||
449 | |||
450 | static int tegra_wm8753_voice_hw_free(struct snd_pcm_substream *substream) | ||
451 | { | ||
452 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
453 | struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(rtd->card); | ||
454 | |||
455 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 0); | ||
456 | machine->is_call_mode_bt = 0; | ||
457 | |||
458 | return 0; | ||
459 | } | ||
460 | |||
461 | static int tegra_call_mode_info(struct snd_kcontrol *kcontrol, | ||
462 | struct snd_ctl_elem_info *uinfo) | ||
463 | { | ||
464 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
465 | uinfo->count = 1; | ||
466 | uinfo->value.integer.min = 0; | ||
467 | uinfo->value.integer.max = 1; | ||
468 | return 0; | ||
469 | } | ||
470 | |||
471 | static int tegra_call_mode_get(struct snd_kcontrol *kcontrol, | ||
472 | struct snd_ctl_elem_value *ucontrol) | ||
473 | { | ||
474 | struct tegra_wm8753 *machine = snd_kcontrol_chip(kcontrol); | ||
475 | |||
476 | ucontrol->value.integer.value[0] = machine->is_call_mode; | ||
477 | |||
478 | return 0; | ||
479 | } | ||
480 | |||
481 | static int tegra_call_mode_put(struct snd_kcontrol *kcontrol, | ||
482 | struct snd_ctl_elem_value *ucontrol) | ||
483 | { | ||
484 | struct tegra_wm8753 *machine = snd_kcontrol_chip(kcontrol); | ||
485 | int is_call_mode_new = ucontrol->value.integer.value[0]; | ||
486 | int codec_dap_id, codec_dap_sel, bb_dap_id, bb_dap_sel; | ||
487 | |||
488 | if (machine->is_call_mode == is_call_mode_new) | ||
489 | return 0; | ||
490 | |||
491 | bb_dap_id = TEGRA20_DAS_DAP_ID_3; | ||
492 | bb_dap_sel = TEGRA20_DAS_DAP_SEL_DAP3; | ||
493 | |||
494 | if (machine->is_call_mode_bt) { | ||
495 | codec_dap_id = TEGRA20_DAS_DAP_ID_4; | ||
496 | codec_dap_sel = TEGRA20_DAS_DAP_SEL_DAP4; | ||
497 | } | ||
498 | else { | ||
499 | codec_dap_id = TEGRA20_DAS_DAP_ID_2; | ||
500 | codec_dap_sel = TEGRA20_DAS_DAP_SEL_DAP2; | ||
501 | } | ||
502 | |||
503 | if (is_call_mode_new) { | ||
504 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
505 | tegra20_das_set_tristate(codec_dap_id, 1); | ||
506 | tegra20_das_set_tristate(bb_dap_id, 1); | ||
507 | tegra20_das_connect_dap_to_dap(codec_dap_id, | ||
508 | bb_dap_sel, 0, 0, 0); | ||
509 | tegra20_das_connect_dap_to_dap(bb_dap_id, | ||
510 | codec_dap_sel, 1, 0, 0); | ||
511 | tegra20_das_set_tristate(codec_dap_id, 0); | ||
512 | tegra20_das_set_tristate(bb_dap_id, 0); | ||
513 | #endif | ||
514 | } else { | ||
515 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
516 | tegra20_das_set_tristate(codec_dap_id, 1); | ||
517 | tegra20_das_set_tristate(bb_dap_id, 1); | ||
518 | tegra20_das_connect_dap_to_dap(bb_dap_id, | ||
519 | bb_dap_sel, 0, 0, 0); | ||
520 | tegra20_das_connect_dap_to_dap(codec_dap_id, | ||
521 | codec_dap_sel, 0, 0, 0); | ||
522 | tegra20_das_set_tristate(codec_dap_id, 0); | ||
523 | tegra20_das_set_tristate(bb_dap_id, 0); | ||
524 | #endif | ||
525 | } | ||
526 | |||
527 | machine->is_call_mode = is_call_mode_new; | ||
528 | g_is_call_mode = machine->is_call_mode; | ||
529 | |||
530 | return 1; | ||
531 | } | ||
532 | |||
533 | struct snd_kcontrol_new tegra_call_mode_control = { | ||
534 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
535 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
536 | .name = "Call Mode Switch", | ||
537 | .private_value = 0xffff, | ||
538 | .info = tegra_call_mode_info, | ||
539 | .get = tegra_call_mode_get, | ||
540 | .put = tegra_call_mode_put | ||
541 | }; | ||
542 | |||
543 | static struct snd_soc_ops tegra_wm8753_ops = { | ||
544 | .hw_params = tegra_wm8753_hw_params, | ||
545 | .hw_free = tegra_hw_free, | ||
546 | }; | ||
547 | |||
548 | static struct snd_soc_ops tegra_wm8753_voice_ops = { | ||
549 | .hw_params = tegra_wm8753_voice_hw_params, | ||
550 | .hw_free = tegra_wm8753_voice_hw_free, | ||
551 | }; | ||
552 | |||
553 | static struct snd_soc_ops tegra_bt_call_ops = { | ||
554 | .hw_params = tegra_bt_call_hw_params, | ||
555 | .hw_free = tegra_bt_call_hw_free, | ||
556 | }; | ||
557 | |||
558 | static struct snd_soc_ops tegra_bt_sco_ops = { | ||
559 | .hw_params = tegra_bt_sco_hw_params, | ||
560 | .hw_free = tegra_hw_free, | ||
561 | }; | ||
562 | |||
563 | static struct snd_soc_ops tegra_spdif_ops = { | ||
564 | .hw_params = tegra_spdif_hw_params, | ||
565 | .hw_free = tegra_hw_free, | ||
566 | }; | ||
567 | |||
568 | static struct snd_soc_jack tegra_wm8753_hp_jack; | ||
569 | |||
570 | #ifdef CONFIG_SWITCH | ||
571 | static struct switch_dev wired_switch_dev = { | ||
572 | .name = "h2w", | ||
573 | }; | ||
574 | |||
575 | /* These values are copied from WiredAccessoryObserver */ | ||
576 | enum headset_state { | ||
577 | BIT_NO_HEADSET = 0, | ||
578 | BIT_HEADSET = (1 << 0), | ||
579 | BIT_HEADSET_NO_MIC = (1 << 1), | ||
580 | }; | ||
581 | |||
582 | static int headset_switch_notify(struct notifier_block *self, | ||
583 | unsigned long action, void *dev) | ||
584 | { | ||
585 | switch (action) { | ||
586 | case SND_JACK_HEADPHONE: | ||
587 | switch_set_state(&wired_switch_dev, BIT_HEADSET_NO_MIC); | ||
588 | break; | ||
589 | case SND_JACK_HEADSET: | ||
590 | switch_set_state(&wired_switch_dev, BIT_HEADSET); | ||
591 | break; | ||
592 | default: | ||
593 | switch_set_state(&wired_switch_dev, BIT_NO_HEADSET); | ||
594 | } | ||
595 | |||
596 | return NOTIFY_OK; | ||
597 | } | ||
598 | |||
599 | static struct notifier_block headset_switch_nb = { | ||
600 | .notifier_call = headset_switch_notify, | ||
601 | }; | ||
602 | #else | ||
603 | static struct snd_soc_jack_pin tegra_wm8753_hp_jack_pins[] = { | ||
604 | { | ||
605 | .pin = "Headphone Jack", | ||
606 | .mask = SND_JACK_HEADPHONE, | ||
607 | }, | ||
608 | }; | ||
609 | #endif | ||
610 | |||
611 | static int tegra_wm8753_event_int_spk(struct snd_soc_dapm_widget *w, | ||
612 | struct snd_kcontrol *k, int event) | ||
613 | { | ||
614 | struct snd_soc_dapm_context *dapm = w->dapm; | ||
615 | struct snd_soc_card *card = dapm->card; | ||
616 | struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card); | ||
617 | struct tegra_wm8753_platform_data *pdata = machine->pdata; | ||
618 | |||
619 | if (!(machine->gpio_requested & GPIO_SPKR_EN)) | ||
620 | return 0; | ||
621 | |||
622 | gpio_set_value_cansleep(pdata->gpio_spkr_en, | ||
623 | SND_SOC_DAPM_EVENT_ON(event)); | ||
624 | |||
625 | return 0; | ||
626 | } | ||
627 | |||
628 | static int tegra_wm8753_event_hp(struct snd_soc_dapm_widget *w, | ||
629 | struct snd_kcontrol *k, int event) | ||
630 | { | ||
631 | struct snd_soc_dapm_context *dapm = w->dapm; | ||
632 | struct snd_soc_card *card = dapm->card; | ||
633 | struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card); | ||
634 | struct tegra_wm8753_platform_data *pdata = machine->pdata; | ||
635 | |||
636 | if (!(machine->gpio_requested & GPIO_HP_MUTE)) | ||
637 | return 0; | ||
638 | |||
639 | gpio_set_value_cansleep(pdata->gpio_hp_mute, | ||
640 | !SND_SOC_DAPM_EVENT_ON(event)); | ||
641 | |||
642 | return 0; | ||
643 | } | ||
644 | |||
645 | static const struct snd_soc_dapm_widget tegra_wm8753_dapm_widgets[] = { | ||
646 | SND_SOC_DAPM_SPK("Int Spk", tegra_wm8753_event_int_spk), | ||
647 | SND_SOC_DAPM_HP("Earpiece", NULL), | ||
648 | SND_SOC_DAPM_OUTPUT("Mono Out"), | ||
649 | SND_SOC_DAPM_HP("Headphone Jack", tegra_wm8753_event_hp), | ||
650 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | ||
651 | SND_SOC_DAPM_INPUT("Int Mic"), | ||
652 | SND_SOC_DAPM_LINE("LineIn Jack", NULL), | ||
653 | }; | ||
654 | |||
655 | static const struct snd_soc_dapm_route whistler_audio_map[] = { | ||
656 | {"Int Spk", NULL, "ROUT2"}, | ||
657 | {"Int Spk", NULL, "LOUT2"}, | ||
658 | {"Earpiece", NULL, "OUT3"}, | ||
659 | {"Earpiece", NULL, "LOUT1"}, | ||
660 | {"Mono Out", NULL, "MONO1"}, | ||
661 | {"Mono Out", NULL, "MONO2"}, | ||
662 | {"Headphone Jack", NULL, "ROUT1"}, | ||
663 | {"Headphone Jack", NULL, "LOUT1"}, | ||
664 | {"Headphone Jack", NULL, "OUT4"}, | ||
665 | {"Mic Bias", NULL, "Mic Jack"}, | ||
666 | {"MIC1", NULL, "Mic Bias"}, | ||
667 | {"Mic Bias", NULL, "Int Mic"}, | ||
668 | {"MIC2", NULL, "Mic Bias"}, | ||
669 | {"MIC2N", NULL, "Mic Bias"}, | ||
670 | {"LINE1", NULL, "LineIn Jack"}, | ||
671 | {"LINE2", NULL, "LineIn Jack"}, | ||
672 | }; | ||
673 | |||
674 | static const struct snd_kcontrol_new tegra_wm8753_controls[] = { | ||
675 | SOC_DAPM_PIN_SWITCH("Int Spk"), | ||
676 | SOC_DAPM_PIN_SWITCH("Earpiece"), | ||
677 | SOC_DAPM_PIN_SWITCH("Mono Out"), | ||
678 | SOC_DAPM_PIN_SWITCH("Headphone Jack"), | ||
679 | SOC_DAPM_PIN_SWITCH("Mic Jack"), | ||
680 | SOC_DAPM_PIN_SWITCH("Int Mic"), | ||
681 | SOC_DAPM_PIN_SWITCH("LineIn Jack"), | ||
682 | }; | ||
683 | |||
684 | static int tegra_wm8753_init(struct snd_soc_pcm_runtime *rtd) | ||
685 | { | ||
686 | struct snd_soc_codec *codec = rtd->codec; | ||
687 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
688 | struct snd_soc_card *card = codec->card; | ||
689 | struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card); | ||
690 | struct tegra_wm8753_platform_data *pdata = machine->pdata; | ||
691 | int ret; | ||
692 | |||
693 | if (machine_is_whistler()) { | ||
694 | machine->audio_reg = regulator_get(NULL, "avddio_audio"); | ||
695 | if (IS_ERR(machine->audio_reg)) { | ||
696 | dev_err(card->dev, "cannot get avddio_audio reg\n"); | ||
697 | ret = PTR_ERR(machine->audio_reg); | ||
698 | return ret; | ||
699 | } | ||
700 | |||
701 | ret = regulator_enable(machine->audio_reg); | ||
702 | if (ret) { | ||
703 | dev_err(card->dev, "cannot enable avddio_audio reg\n"); | ||
704 | regulator_put(machine->audio_reg); | ||
705 | machine->audio_reg = NULL; | ||
706 | return ret; | ||
707 | } | ||
708 | } | ||
709 | |||
710 | if (gpio_is_valid(pdata->gpio_spkr_en)) { | ||
711 | ret = gpio_request(pdata->gpio_spkr_en, "spkr_en"); | ||
712 | if (ret) { | ||
713 | dev_err(card->dev, "cannot get spkr_en gpio\n"); | ||
714 | return ret; | ||
715 | } | ||
716 | machine->gpio_requested |= GPIO_SPKR_EN; | ||
717 | |||
718 | gpio_direction_output(pdata->gpio_spkr_en, 0); | ||
719 | } | ||
720 | |||
721 | if (gpio_is_valid(pdata->gpio_hp_mute)) { | ||
722 | ret = gpio_request(pdata->gpio_hp_mute, "hp_mute"); | ||
723 | if (ret) { | ||
724 | dev_err(card->dev, "cannot get hp_mute gpio\n"); | ||
725 | return ret; | ||
726 | } | ||
727 | machine->gpio_requested |= GPIO_HP_MUTE; | ||
728 | |||
729 | gpio_direction_output(pdata->gpio_hp_mute, 0); | ||
730 | } | ||
731 | |||
732 | if (gpio_is_valid(pdata->gpio_int_mic_en)) { | ||
733 | ret = gpio_request(pdata->gpio_int_mic_en, "int_mic_en"); | ||
734 | if (ret) { | ||
735 | dev_err(card->dev, "cannot get int_mic_en gpio\n"); | ||
736 | return ret; | ||
737 | } | ||
738 | machine->gpio_requested |= GPIO_INT_MIC_EN; | ||
739 | |||
740 | /* Disable int mic; enable signal is active-high */ | ||
741 | gpio_direction_output(pdata->gpio_int_mic_en, 0); | ||
742 | } | ||
743 | |||
744 | if (gpio_is_valid(pdata->gpio_ext_mic_en)) { | ||
745 | ret = gpio_request(pdata->gpio_ext_mic_en, "ext_mic_en"); | ||
746 | if (ret) { | ||
747 | dev_err(card->dev, "cannot get ext_mic_en gpio\n"); | ||
748 | return ret; | ||
749 | } | ||
750 | machine->gpio_requested |= GPIO_EXT_MIC_EN; | ||
751 | |||
752 | /* Enable ext mic; enable signal is active-low */ | ||
753 | gpio_direction_output(pdata->gpio_ext_mic_en, 0); | ||
754 | } | ||
755 | |||
756 | ret = snd_soc_add_controls(codec, tegra_wm8753_controls, | ||
757 | ARRAY_SIZE(tegra_wm8753_controls)); | ||
758 | if (ret < 0) | ||
759 | return ret; | ||
760 | |||
761 | snd_soc_dapm_new_controls(dapm, tegra_wm8753_dapm_widgets, | ||
762 | ARRAY_SIZE(tegra_wm8753_dapm_widgets)); | ||
763 | |||
764 | snd_soc_dapm_add_routes(dapm, whistler_audio_map, | ||
765 | ARRAY_SIZE(whistler_audio_map)); | ||
766 | |||
767 | snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, | ||
768 | &tegra_wm8753_hp_jack); | ||
769 | wm8753_headphone_detect(codec, &tegra_wm8753_hp_jack, | ||
770 | SND_JACK_HEADPHONE, pdata->debounce_time_hp); | ||
771 | #ifdef CONFIG_SWITCH | ||
772 | snd_soc_jack_notifier_register(&tegra_wm8753_hp_jack, | ||
773 | &headset_switch_nb); | ||
774 | #else | ||
775 | snd_soc_jack_add_pins(&tegra_wm8753_hp_jack, | ||
776 | ARRAY_SIZE(tegra_wm8753_hp_jack_pins), | ||
777 | tegra_wm8753_hp_jack_pins); | ||
778 | #endif | ||
779 | |||
780 | /* Add call mode switch control */ | ||
781 | ret = snd_ctl_add(codec->card->snd_card, | ||
782 | snd_ctl_new1(&tegra_call_mode_control, machine)); | ||
783 | if (ret < 0) | ||
784 | return ret; | ||
785 | |||
786 | snd_soc_dapm_nc_pin(dapm, "ACIN"); | ||
787 | snd_soc_dapm_nc_pin(dapm, "ACOP"); | ||
788 | snd_soc_dapm_nc_pin(dapm, "OUT3"); | ||
789 | snd_soc_dapm_nc_pin(dapm, "OUT4"); | ||
790 | |||
791 | snd_soc_dapm_sync(dapm); | ||
792 | |||
793 | return 0; | ||
794 | } | ||
795 | |||
796 | static struct snd_soc_dai_link tegra_wm8753_dai[] = { | ||
797 | { | ||
798 | .name = "WM8753", | ||
799 | .stream_name = "WM8753 PCM HIFI", | ||
800 | .codec_name = "wm8753-codec.4-001a", | ||
801 | .platform_name = "tegra-pcm-audio", | ||
802 | .cpu_dai_name = "tegra20-i2s.0", | ||
803 | .codec_dai_name = "wm8753-hifi", | ||
804 | .init = tegra_wm8753_init, | ||
805 | .ops = &tegra_wm8753_ops, | ||
806 | }, | ||
807 | { | ||
808 | .name = "SPDIF", | ||
809 | .stream_name = "SPDIF PCM", | ||
810 | .codec_name = "spdif-dit.0", | ||
811 | .platform_name = "tegra-pcm-audio", | ||
812 | .cpu_dai_name = "tegra20-spdif", | ||
813 | .codec_dai_name = "dit-hifi", | ||
814 | .ops = &tegra_spdif_ops, | ||
815 | }, | ||
816 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
817 | { | ||
818 | .name = "BT-SCO", | ||
819 | .stream_name = "BT SCO PCM", | ||
820 | .codec_name = "spdif-dit.1", | ||
821 | .platform_name = "tegra-pcm-audio", | ||
822 | .cpu_dai_name = "tegra20-i2s.1", | ||
823 | .codec_dai_name = "dit-hifi", | ||
824 | .ops = &tegra_bt_sco_ops, | ||
825 | }, | ||
826 | #endif | ||
827 | { | ||
828 | .name = "VOICE CALL", | ||
829 | .stream_name = "VOICE CALL PCM", | ||
830 | .codec_name = "wm8753-codec.4-001a", | ||
831 | .platform_name = "tegra-pcm-audio", | ||
832 | .cpu_dai_name = "dit-hifi", | ||
833 | .codec_dai_name = "wm8753-voice", | ||
834 | .ops = &tegra_wm8753_voice_ops, | ||
835 | }, | ||
836 | { | ||
837 | .name = "BT VOICE CALL", | ||
838 | .stream_name = "BT VOICE CALL PCM", | ||
839 | .codec_name = "spdif-dit.2", | ||
840 | .platform_name = "tegra-pcm-audio", | ||
841 | .cpu_dai_name = "dit-hifi", | ||
842 | .codec_dai_name = "dit-hifi", | ||
843 | .ops = &tegra_bt_call_ops, | ||
844 | }, | ||
845 | }; | ||
846 | |||
847 | static struct snd_soc_card snd_soc_tegra_wm8753 = { | ||
848 | .name = "tegra-wm8753", | ||
849 | .dai_link = tegra_wm8753_dai, | ||
850 | .num_links = ARRAY_SIZE(tegra_wm8753_dai), | ||
851 | }; | ||
852 | |||
853 | static __devinit int tegra_wm8753_driver_probe(struct platform_device *pdev) | ||
854 | { | ||
855 | struct snd_soc_card *card = &snd_soc_tegra_wm8753; | ||
856 | struct tegra_wm8753 *machine; | ||
857 | struct tegra_wm8753_platform_data *pdata; | ||
858 | int ret; | ||
859 | |||
860 | |||
861 | pdata = pdev->dev.platform_data; | ||
862 | if (!pdata) { | ||
863 | dev_err(&pdev->dev, "No platform data supplied\n"); | ||
864 | return -EINVAL; | ||
865 | } | ||
866 | |||
867 | machine = kzalloc(sizeof(struct tegra_wm8753), GFP_KERNEL); | ||
868 | if (!machine) { | ||
869 | dev_err(&pdev->dev, "Can't allocate tegra_wm8753 struct\n"); | ||
870 | return -ENOMEM; | ||
871 | } | ||
872 | |||
873 | machine->pdata = pdata; | ||
874 | |||
875 | ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); | ||
876 | if (ret) | ||
877 | goto err_free_machine; | ||
878 | |||
879 | card->dev = &pdev->dev; | ||
880 | platform_set_drvdata(pdev, card); | ||
881 | snd_soc_card_set_drvdata(card, machine); | ||
882 | |||
883 | ret = snd_soc_register_card(card); | ||
884 | if (ret) { | ||
885 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", | ||
886 | ret); | ||
887 | goto err_fini_utils; | ||
888 | } | ||
889 | |||
890 | if (!card->instantiated) { | ||
891 | dev_err(&pdev->dev, "No WM8753 codec\n"); | ||
892 | goto err_unregister_card; | ||
893 | } | ||
894 | |||
895 | #ifdef CONFIG_SWITCH | ||
896 | /* Add h2w swith class support */ | ||
897 | ret = switch_dev_register(&wired_switch_dev); | ||
898 | if (ret < 0) { | ||
899 | dev_err(&pdev->dev, "not able to register switch device\n"); | ||
900 | goto err_unregister_card; | ||
901 | } | ||
902 | #endif | ||
903 | |||
904 | return 0; | ||
905 | |||
906 | err_unregister_card: | ||
907 | snd_soc_unregister_card(card); | ||
908 | err_fini_utils: | ||
909 | tegra_asoc_utils_fini(&machine->util_data); | ||
910 | err_free_machine: | ||
911 | kfree(machine); | ||
912 | return ret; | ||
913 | } | ||
914 | |||
915 | static int __devexit tegra_wm8753_driver_remove(struct platform_device *pdev) | ||
916 | { | ||
917 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
918 | struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card); | ||
919 | struct tegra_wm8753_platform_data *pdata = machine->pdata; | ||
920 | |||
921 | snd_soc_unregister_card(card); | ||
922 | |||
923 | #ifdef CONFIG_SWITCH | ||
924 | switch_dev_unregister(&wired_switch_dev); | ||
925 | #endif | ||
926 | |||
927 | tegra_asoc_utils_fini(&machine->util_data); | ||
928 | |||
929 | if (machine->gpio_requested & GPIO_EXT_MIC_EN) | ||
930 | gpio_free(pdata->gpio_ext_mic_en); | ||
931 | if (machine->gpio_requested & GPIO_INT_MIC_EN) | ||
932 | gpio_free(pdata->gpio_int_mic_en); | ||
933 | if (machine->gpio_requested & GPIO_HP_MUTE) | ||
934 | gpio_free(pdata->gpio_hp_mute); | ||
935 | if (machine->gpio_requested & GPIO_SPKR_EN) | ||
936 | gpio_free(pdata->gpio_spkr_en); | ||
937 | if (machine->audio_reg) { | ||
938 | regulator_disable(machine->audio_reg); | ||
939 | regulator_put(machine->audio_reg); | ||
940 | } | ||
941 | |||
942 | kfree(machine); | ||
943 | |||
944 | return 0; | ||
945 | } | ||
946 | |||
947 | static struct platform_driver tegra_wm8753_driver = { | ||
948 | .driver = { | ||
949 | .name = DRV_NAME, | ||
950 | .owner = THIS_MODULE, | ||
951 | .pm = &snd_soc_pm_ops, | ||
952 | }, | ||
953 | .probe = tegra_wm8753_driver_probe, | ||
954 | .remove = __devexit_p(tegra_wm8753_driver_remove), | ||
955 | }; | ||
956 | |||
957 | static int __init tegra_wm8753_modinit(void) | ||
958 | { | ||
959 | return platform_driver_register(&tegra_wm8753_driver); | ||
960 | } | ||
961 | module_init(tegra_wm8753_modinit); | ||
962 | |||
963 | static void __exit tegra_wm8753_modexit(void) | ||
964 | { | ||
965 | platform_driver_unregister(&tegra_wm8753_driver); | ||
966 | } | ||
967 | module_exit(tegra_wm8753_modexit); | ||
968 | |||
969 | MODULE_AUTHOR("Sumit Bhattacharya <sumitb@nvidia.com>"); | ||
970 | MODULE_DESCRIPTION("Tegra+WM8753 machine ASoC driver"); | ||
971 | MODULE_LICENSE("GPL"); | ||
972 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index 0d6738a8b29..55e4f61edfd 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c | |||
@@ -30,10 +30,15 @@ | |||
30 | 30 | ||
31 | #include <asm/mach-types.h> | 31 | #include <asm/mach-types.h> |
32 | 32 | ||
33 | #include <linux/clk.h> | ||
33 | #include <linux/module.h> | 34 | #include <linux/module.h> |
34 | #include <linux/platform_device.h> | 35 | #include <linux/platform_device.h> |
35 | #include <linux/slab.h> | 36 | #include <linux/slab.h> |
36 | #include <linux/gpio.h> | 37 | #include <linux/gpio.h> |
38 | #include <linux/regulator/consumer.h> | ||
39 | #ifdef CONFIG_SWITCH | ||
40 | #include <linux/switch.h> | ||
41 | #endif | ||
37 | 42 | ||
38 | #include <mach/tegra_wm8903_pdata.h> | 43 | #include <mach/tegra_wm8903_pdata.h> |
39 | 44 | ||
@@ -45,22 +50,31 @@ | |||
45 | 50 | ||
46 | #include "../codecs/wm8903.h" | 51 | #include "../codecs/wm8903.h" |
47 | 52 | ||
48 | #include "tegra_das.h" | ||
49 | #include "tegra_i2s.h" | ||
50 | #include "tegra_pcm.h" | 53 | #include "tegra_pcm.h" |
51 | #include "tegra_asoc_utils.h" | 54 | #include "tegra_asoc_utils.h" |
52 | 55 | ||
56 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
57 | #include "tegra20_das.h" | ||
58 | #endif | ||
59 | |||
53 | #define DRV_NAME "tegra-snd-wm8903" | 60 | #define DRV_NAME "tegra-snd-wm8903" |
54 | 61 | ||
55 | #define GPIO_SPKR_EN BIT(0) | 62 | #define GPIO_SPKR_EN BIT(0) |
56 | #define GPIO_HP_MUTE BIT(1) | 63 | #define GPIO_HP_MUTE BIT(1) |
57 | #define GPIO_INT_MIC_EN BIT(2) | 64 | #define GPIO_INT_MIC_EN BIT(2) |
58 | #define GPIO_EXT_MIC_EN BIT(3) | 65 | #define GPIO_EXT_MIC_EN BIT(3) |
66 | #define GPIO_HP_DET BIT(4) | ||
59 | 67 | ||
60 | struct tegra_wm8903 { | 68 | struct tegra_wm8903 { |
61 | struct tegra_asoc_utils_data util_data; | 69 | struct tegra_asoc_utils_data util_data; |
62 | struct tegra_wm8903_platform_data *pdata; | 70 | struct tegra_wm8903_platform_data *pdata; |
71 | struct regulator *spk_reg; | ||
72 | struct regulator *dmic_reg; | ||
63 | int gpio_requested; | 73 | int gpio_requested; |
74 | #ifdef CONFIG_SWITCH | ||
75 | int jack_status; | ||
76 | #endif | ||
77 | enum snd_soc_bias_level bias_level; | ||
64 | }; | 78 | }; |
65 | 79 | ||
66 | static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream, | 80 | static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream, |
@@ -72,8 +86,10 @@ static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream, | |||
72 | struct snd_soc_codec *codec = rtd->codec; | 86 | struct snd_soc_codec *codec = rtd->codec; |
73 | struct snd_soc_card *card = codec->card; | 87 | struct snd_soc_card *card = codec->card; |
74 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); | 88 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); |
75 | int srate, mclk; | 89 | int srate, mclk, i2s_daifmt; |
76 | int err; | 90 | int err; |
91 | struct clk *clk_m; | ||
92 | int rate; | ||
77 | 93 | ||
78 | srate = params_rate(params); | 94 | srate = params_rate(params); |
79 | switch (srate) { | 95 | switch (srate) { |
@@ -86,29 +102,60 @@ static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream, | |||
86 | mclk = 256 * srate; | 102 | mclk = 256 * srate; |
87 | break; | 103 | break; |
88 | } | 104 | } |
105 | |||
106 | |||
107 | |||
108 | clk_m = clk_get_sys(NULL, "clk_m"); | ||
109 | if (IS_ERR(clk_m)) { | ||
110 | dev_err(card->dev, "Can't retrieve clk clk_m\n"); | ||
111 | err = PTR_ERR(clk_m); | ||
112 | return err; | ||
113 | } | ||
114 | rate = clk_get_rate(clk_m); | ||
115 | printk("extern1 rate=%d\n",rate); | ||
116 | |||
117 | #if TEGRA30_I2S_MASTER_PLAYBACK | ||
89 | /* FIXME: Codec only requires >= 3MHz if OSR==0 */ | 118 | /* FIXME: Codec only requires >= 3MHz if OSR==0 */ |
90 | while (mclk < 6000000) | 119 | while (mclk < 6000000) |
91 | mclk *= 2; | 120 | mclk *= 2; |
92 | 121 | ||
122 | i2s_daifmt = SND_SOC_DAIFMT_NB_NF | | ||
123 | SND_SOC_DAIFMT_CBS_CFS; | ||
124 | #else | ||
125 | mclk = rate; | ||
126 | |||
127 | i2s_daifmt = SND_SOC_DAIFMT_NB_NF | | ||
128 | SND_SOC_DAIFMT_CBM_CFM; | ||
129 | #endif | ||
130 | |||
131 | |||
93 | err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); | 132 | err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); |
94 | if (err < 0) { | 133 | if (err < 0) { |
95 | dev_err(card->dev, "Can't configure clocks\n"); | 134 | if (!(machine->util_data.set_mclk % mclk)) |
96 | return err; | 135 | mclk = machine->util_data.set_mclk; |
136 | else { | ||
137 | dev_err(card->dev, "Can't configure clocks\n"); | ||
138 | return err; | ||
139 | } | ||
97 | } | 140 | } |
98 | 141 | ||
99 | err = snd_soc_dai_set_fmt(codec_dai, | 142 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); |
100 | SND_SOC_DAIFMT_I2S | | 143 | |
101 | SND_SOC_DAIFMT_NB_NF | | 144 | /* Use DSP mode for mono on Tegra20 */ |
102 | SND_SOC_DAIFMT_CBS_CFS); | 145 | if ((params_channels(params) != 2) && |
146 | (machine_is_ventana() || machine_is_harmony() || | ||
147 | machine_is_kaen() || machine_is_aebl())) | ||
148 | i2s_daifmt |= SND_SOC_DAIFMT_DSP_A; | ||
149 | else | ||
150 | i2s_daifmt |= SND_SOC_DAIFMT_I2S; | ||
151 | |||
152 | err = snd_soc_dai_set_fmt(codec_dai, i2s_daifmt); | ||
103 | if (err < 0) { | 153 | if (err < 0) { |
104 | dev_err(card->dev, "codec_dai fmt not set\n"); | 154 | dev_err(card->dev, "codec_dai fmt not set\n"); |
105 | return err; | 155 | return err; |
106 | } | 156 | } |
107 | 157 | ||
108 | err = snd_soc_dai_set_fmt(cpu_dai, | 158 | err = snd_soc_dai_set_fmt(cpu_dai, i2s_daifmt); |
109 | SND_SOC_DAIFMT_I2S | | ||
110 | SND_SOC_DAIFMT_NB_NF | | ||
111 | SND_SOC_DAIFMT_CBS_CFS); | ||
112 | if (err < 0) { | 159 | if (err < 0) { |
113 | dev_err(card->dev, "cpu_dai fmt not set\n"); | 160 | dev_err(card->dev, "cpu_dai fmt not set\n"); |
114 | return err; | 161 | return err; |
@@ -121,22 +168,167 @@ static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream, | |||
121 | return err; | 168 | return err; |
122 | } | 169 | } |
123 | 170 | ||
171 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
172 | err = tegra20_das_connect_dac_to_dap(TEGRA20_DAS_DAP_SEL_DAC1, | ||
173 | TEGRA20_DAS_DAP_ID_1); | ||
174 | if (err < 0) { | ||
175 | dev_err(card->dev, "failed to set dap-dac path\n"); | ||
176 | return err; | ||
177 | } | ||
178 | |||
179 | err = tegra20_das_connect_dap_to_dac(TEGRA20_DAS_DAP_ID_1, | ||
180 | TEGRA20_DAS_DAP_SEL_DAC1); | ||
181 | if (err < 0) { | ||
182 | dev_err(card->dev, "failed to set dac-dap path\n"); | ||
183 | return err; | ||
184 | } | ||
185 | #endif | ||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | static int tegra_bt_sco_hw_params(struct snd_pcm_substream *substream, | ||
190 | struct snd_pcm_hw_params *params) | ||
191 | { | ||
192 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
193 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
194 | struct snd_soc_card *card = rtd->card; | ||
195 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); | ||
196 | int srate, mclk, min_mclk; | ||
197 | int err; | ||
198 | |||
199 | srate = params_rate(params); | ||
200 | switch (srate) { | ||
201 | case 11025: | ||
202 | case 22050: | ||
203 | case 44100: | ||
204 | case 88200: | ||
205 | mclk = 11289600; | ||
206 | break; | ||
207 | case 8000: | ||
208 | case 16000: | ||
209 | case 32000: | ||
210 | case 48000: | ||
211 | case 64000: | ||
212 | case 96000: | ||
213 | mclk = 12288000; | ||
214 | break; | ||
215 | default: | ||
216 | return -EINVAL; | ||
217 | } | ||
218 | min_mclk = 64 * srate; | ||
219 | |||
220 | err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); | ||
221 | if (err < 0) { | ||
222 | if (!(machine->util_data.set_mclk % min_mclk)) | ||
223 | mclk = machine->util_data.set_mclk; | ||
224 | else { | ||
225 | dev_err(card->dev, "Can't configure clocks\n"); | ||
226 | return err; | ||
227 | } | ||
228 | } | ||
229 | |||
230 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); | ||
231 | |||
232 | err = snd_soc_dai_set_fmt(cpu_dai, | ||
233 | SND_SOC_DAIFMT_DSP_A | | ||
234 | SND_SOC_DAIFMT_NB_NF | | ||
235 | SND_SOC_DAIFMT_CBS_CFS); | ||
236 | if (err < 0) { | ||
237 | dev_err(card->dev, "cpu_dai fmt not set\n"); | ||
238 | return err; | ||
239 | } | ||
240 | |||
241 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
242 | err = tegra20_das_connect_dac_to_dap(TEGRA20_DAS_DAP_SEL_DAC2, | ||
243 | TEGRA20_DAS_DAP_ID_4); | ||
244 | if (err < 0) { | ||
245 | dev_err(card->dev, "failed to set dac-dap path\n"); | ||
246 | return err; | ||
247 | } | ||
248 | |||
249 | err = tegra20_das_connect_dap_to_dac(TEGRA20_DAS_DAP_ID_4, | ||
250 | TEGRA20_DAS_DAP_SEL_DAC2); | ||
251 | if (err < 0) { | ||
252 | dev_err(card->dev, "failed to set dac-dap path\n"); | ||
253 | return err; | ||
254 | } | ||
255 | #endif | ||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | static int tegra_spdif_hw_params(struct snd_pcm_substream *substream, | ||
260 | struct snd_pcm_hw_params *params) | ||
261 | { | ||
262 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
263 | struct snd_soc_card *card = rtd->card; | ||
264 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); | ||
265 | int srate, mclk, min_mclk; | ||
266 | int err; | ||
267 | |||
268 | srate = params_rate(params); | ||
269 | switch (srate) { | ||
270 | case 11025: | ||
271 | case 22050: | ||
272 | case 44100: | ||
273 | case 88200: | ||
274 | mclk = 11289600; | ||
275 | break; | ||
276 | case 8000: | ||
277 | case 16000: | ||
278 | case 32000: | ||
279 | case 48000: | ||
280 | case 64000: | ||
281 | case 96000: | ||
282 | mclk = 12288000; | ||
283 | break; | ||
284 | default: | ||
285 | return -EINVAL; | ||
286 | } | ||
287 | min_mclk = 128 * srate; | ||
288 | |||
289 | err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); | ||
290 | if (err < 0) { | ||
291 | if (!(machine->util_data.set_mclk % min_mclk)) | ||
292 | mclk = machine->util_data.set_mclk; | ||
293 | else { | ||
294 | dev_err(card->dev, "Can't configure clocks\n"); | ||
295 | return err; | ||
296 | } | ||
297 | } | ||
298 | |||
299 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1); | ||
300 | |||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | static int tegra_hw_free(struct snd_pcm_substream *substream) | ||
305 | { | ||
306 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
307 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(rtd->card); | ||
308 | |||
309 | tegra_asoc_utils_lock_clk_rate(&machine->util_data, 0); | ||
310 | |||
124 | return 0; | 311 | return 0; |
125 | } | 312 | } |
126 | 313 | ||
127 | static struct snd_soc_ops tegra_wm8903_ops = { | 314 | static struct snd_soc_ops tegra_wm8903_ops = { |
128 | .hw_params = tegra_wm8903_hw_params, | 315 | .hw_params = tegra_wm8903_hw_params, |
316 | .hw_free = tegra_hw_free, | ||
129 | }; | 317 | }; |
130 | 318 | ||
131 | static struct snd_soc_jack tegra_wm8903_hp_jack; | 319 | static struct snd_soc_ops tegra_wm8903_bt_sco_ops = { |
320 | .hw_params = tegra_bt_sco_hw_params, | ||
321 | .hw_free = tegra_hw_free, | ||
322 | }; | ||
132 | 323 | ||
133 | static struct snd_soc_jack_pin tegra_wm8903_hp_jack_pins[] = { | 324 | static struct snd_soc_ops tegra_spdif_ops = { |
134 | { | 325 | .hw_params = tegra_spdif_hw_params, |
135 | .pin = "Headphone Jack", | 326 | .hw_free = tegra_hw_free, |
136 | .mask = SND_JACK_HEADPHONE, | ||
137 | }, | ||
138 | }; | 327 | }; |
139 | 328 | ||
329 | static struct snd_soc_jack tegra_wm8903_hp_jack; | ||
330 | static struct snd_soc_jack tegra_wm8903_mic_jack; | ||
331 | |||
140 | static struct snd_soc_jack_gpio tegra_wm8903_hp_jack_gpio = { | 332 | static struct snd_soc_jack_gpio tegra_wm8903_hp_jack_gpio = { |
141 | .name = "headphone detect", | 333 | .name = "headphone detect", |
142 | .report = SND_JACK_HEADPHONE, | 334 | .report = SND_JACK_HEADPHONE, |
@@ -144,7 +336,63 @@ static struct snd_soc_jack_gpio tegra_wm8903_hp_jack_gpio = { | |||
144 | .invert = 1, | 336 | .invert = 1, |
145 | }; | 337 | }; |
146 | 338 | ||
147 | static struct snd_soc_jack tegra_wm8903_mic_jack; | 339 | #ifdef CONFIG_SWITCH |
340 | /* These values are copied from Android WiredAccessoryObserver */ | ||
341 | enum headset_state { | ||
342 | BIT_NO_HEADSET = 0, | ||
343 | BIT_HEADSET = (1 << 0), | ||
344 | BIT_HEADSET_NO_MIC = (1 << 1), | ||
345 | }; | ||
346 | |||
347 | static struct switch_dev tegra_wm8903_headset_switch = { | ||
348 | .name = "h2w", | ||
349 | }; | ||
350 | |||
351 | static int tegra_wm8903_jack_notifier(struct notifier_block *self, | ||
352 | unsigned long action, void *dev) | ||
353 | { | ||
354 | struct snd_soc_jack *jack = dev; | ||
355 | struct snd_soc_codec *codec = jack->codec; | ||
356 | struct snd_soc_card *card = codec->card; | ||
357 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); | ||
358 | enum headset_state state = BIT_NO_HEADSET; | ||
359 | |||
360 | if (jack == &tegra_wm8903_hp_jack) { | ||
361 | machine->jack_status &= ~SND_JACK_HEADPHONE; | ||
362 | machine->jack_status |= (action & SND_JACK_HEADPHONE); | ||
363 | } else { | ||
364 | machine->jack_status &= ~SND_JACK_MICROPHONE; | ||
365 | machine->jack_status |= (action & SND_JACK_MICROPHONE); | ||
366 | } | ||
367 | |||
368 | switch (machine->jack_status) { | ||
369 | case SND_JACK_HEADPHONE: | ||
370 | state = BIT_HEADSET_NO_MIC; | ||
371 | break; | ||
372 | case SND_JACK_HEADSET: | ||
373 | state = BIT_HEADSET; | ||
374 | break; | ||
375 | case SND_JACK_MICROPHONE: | ||
376 | /* mic: would not report */ | ||
377 | default: | ||
378 | state = BIT_NO_HEADSET; | ||
379 | } | ||
380 | |||
381 | switch_set_state(&tegra_wm8903_headset_switch, state); | ||
382 | |||
383 | return NOTIFY_OK; | ||
384 | } | ||
385 | |||
386 | static struct notifier_block tegra_wm8903_jack_detect_nb = { | ||
387 | .notifier_call = tegra_wm8903_jack_notifier, | ||
388 | }; | ||
389 | #else | ||
390 | static struct snd_soc_jack_pin tegra_wm8903_hp_jack_pins[] = { | ||
391 | { | ||
392 | .pin = "Headphone Jack", | ||
393 | .mask = SND_JACK_HEADPHONE, | ||
394 | }, | ||
395 | }; | ||
148 | 396 | ||
149 | static struct snd_soc_jack_pin tegra_wm8903_mic_jack_pins[] = { | 397 | static struct snd_soc_jack_pin tegra_wm8903_mic_jack_pins[] = { |
150 | { | 398 | { |
@@ -152,6 +400,7 @@ static struct snd_soc_jack_pin tegra_wm8903_mic_jack_pins[] = { | |||
152 | .mask = SND_JACK_MICROPHONE, | 400 | .mask = SND_JACK_MICROPHONE, |
153 | }, | 401 | }, |
154 | }; | 402 | }; |
403 | #endif | ||
155 | 404 | ||
156 | static int tegra_wm8903_event_int_spk(struct snd_soc_dapm_widget *w, | 405 | static int tegra_wm8903_event_int_spk(struct snd_soc_dapm_widget *w, |
157 | struct snd_kcontrol *k, int event) | 406 | struct snd_kcontrol *k, int event) |
@@ -161,6 +410,13 @@ static int tegra_wm8903_event_int_spk(struct snd_soc_dapm_widget *w, | |||
161 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); | 410 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); |
162 | struct tegra_wm8903_platform_data *pdata = machine->pdata; | 411 | struct tegra_wm8903_platform_data *pdata = machine->pdata; |
163 | 412 | ||
413 | if (machine->spk_reg) { | ||
414 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
415 | regulator_enable(machine->spk_reg); | ||
416 | else | ||
417 | regulator_disable(machine->spk_reg); | ||
418 | } | ||
419 | |||
164 | if (!(machine->gpio_requested & GPIO_SPKR_EN)) | 420 | if (!(machine->gpio_requested & GPIO_SPKR_EN)) |
165 | return 0; | 421 | return 0; |
166 | 422 | ||
@@ -187,7 +443,57 @@ static int tegra_wm8903_event_hp(struct snd_soc_dapm_widget *w, | |||
187 | return 0; | 443 | return 0; |
188 | } | 444 | } |
189 | 445 | ||
190 | static const struct snd_soc_dapm_widget tegra_wm8903_dapm_widgets[] = { | 446 | static int tegra_wm8903_event_int_mic(struct snd_soc_dapm_widget *w, |
447 | struct snd_kcontrol *k, int event) | ||
448 | { | ||
449 | struct snd_soc_dapm_context *dapm = w->dapm; | ||
450 | struct snd_soc_card *card = dapm->card; | ||
451 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); | ||
452 | struct tegra_wm8903_platform_data *pdata = machine->pdata; | ||
453 | |||
454 | if (machine->dmic_reg) { | ||
455 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
456 | regulator_enable(machine->dmic_reg); | ||
457 | else | ||
458 | regulator_disable(machine->dmic_reg); | ||
459 | } | ||
460 | |||
461 | if (!(machine->gpio_requested & GPIO_INT_MIC_EN)) | ||
462 | return 0; | ||
463 | |||
464 | gpio_set_value_cansleep(pdata->gpio_int_mic_en, | ||
465 | SND_SOC_DAPM_EVENT_ON(event)); | ||
466 | |||
467 | return 0; | ||
468 | } | ||
469 | |||
470 | static int tegra_wm8903_event_ext_mic(struct snd_soc_dapm_widget *w, | ||
471 | struct snd_kcontrol *k, int event) | ||
472 | { | ||
473 | struct snd_soc_dapm_context *dapm = w->dapm; | ||
474 | struct snd_soc_card *card = dapm->card; | ||
475 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); | ||
476 | struct tegra_wm8903_platform_data *pdata = machine->pdata; | ||
477 | |||
478 | if (!(machine->gpio_requested & GPIO_EXT_MIC_EN)) | ||
479 | return 0; | ||
480 | |||
481 | gpio_set_value_cansleep(pdata->gpio_ext_mic_en, | ||
482 | SND_SOC_DAPM_EVENT_ON(event)); | ||
483 | |||
484 | return 0; | ||
485 | } | ||
486 | |||
487 | static const struct snd_soc_dapm_widget cardhu_dapm_widgets[] = { | ||
488 | SND_SOC_DAPM_SPK("Int Spk", tegra_wm8903_event_int_spk), | ||
489 | SND_SOC_DAPM_HP("Headphone Jack", tegra_wm8903_event_hp), | ||
490 | SND_SOC_DAPM_LINE("LineOut", NULL), | ||
491 | SND_SOC_DAPM_MIC("Mic Jack", tegra_wm8903_event_ext_mic), | ||
492 | SND_SOC_DAPM_MIC("Int Mic", tegra_wm8903_event_int_mic), | ||
493 | SND_SOC_DAPM_LINE("Line In", NULL), | ||
494 | }; | ||
495 | |||
496 | static const struct snd_soc_dapm_widget tegra_wm8903_default_dapm_widgets[] = { | ||
191 | SND_SOC_DAPM_SPK("Int Spk", tegra_wm8903_event_int_spk), | 497 | SND_SOC_DAPM_SPK("Int Spk", tegra_wm8903_event_int_spk), |
192 | SND_SOC_DAPM_HP("Headphone Jack", tegra_wm8903_event_hp), | 498 | SND_SOC_DAPM_HP("Headphone Jack", tegra_wm8903_event_hp), |
193 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | 499 | SND_SOC_DAPM_MIC("Mic Jack", NULL), |
@@ -204,6 +510,24 @@ static const struct snd_soc_dapm_route harmony_audio_map[] = { | |||
204 | {"IN1L", NULL, "Mic Bias"}, | 510 | {"IN1L", NULL, "Mic Bias"}, |
205 | }; | 511 | }; |
206 | 512 | ||
513 | static const struct snd_soc_dapm_route cardhu_audio_map[] = { | ||
514 | {"Headphone Jack", NULL, "HPOUTR"}, | ||
515 | {"Headphone Jack", NULL, "HPOUTL"}, | ||
516 | {"Int Spk", NULL, "ROP"}, | ||
517 | {"Int Spk", NULL, "RON"}, | ||
518 | {"Int Spk", NULL, "LOP"}, | ||
519 | {"Int Spk", NULL, "LON"}, | ||
520 | {"LineOut", NULL, "LINEOUTL"}, | ||
521 | {"LineOut", NULL, "LINEOUTR"}, | ||
522 | {"Mic Bias", NULL, "Mic Jack"}, | ||
523 | {"IN1L", NULL, "Mic Bias"}, | ||
524 | {"Mic Bias", NULL, "Int Mic"}, | ||
525 | {"IN1L", NULL, "Mic Bias"}, | ||
526 | {"IN1R", NULL, "Mic Bias"}, | ||
527 | {"IN3L", NULL, "Line In"}, | ||
528 | {"IN3R", NULL, "Line In"}, | ||
529 | }; | ||
530 | |||
207 | static const struct snd_soc_dapm_route seaboard_audio_map[] = { | 531 | static const struct snd_soc_dapm_route seaboard_audio_map[] = { |
208 | {"Headphone Jack", NULL, "HPOUTR"}, | 532 | {"Headphone Jack", NULL, "HPOUTR"}, |
209 | {"Headphone Jack", NULL, "HPOUTL"}, | 533 | {"Headphone Jack", NULL, "HPOUTL"}, |
@@ -235,7 +559,16 @@ static const struct snd_soc_dapm_route aebl_audio_map[] = { | |||
235 | {"IN1R", NULL, "Mic Bias"}, | 559 | {"IN1R", NULL, "Mic Bias"}, |
236 | }; | 560 | }; |
237 | 561 | ||
238 | static const struct snd_kcontrol_new tegra_wm8903_controls[] = { | 562 | static const struct snd_kcontrol_new cardhu_controls[] = { |
563 | SOC_DAPM_PIN_SWITCH("Int Spk"), | ||
564 | SOC_DAPM_PIN_SWITCH("Headphone Jack"), | ||
565 | SOC_DAPM_PIN_SWITCH("LineOut"), | ||
566 | SOC_DAPM_PIN_SWITCH("Mic Jack"), | ||
567 | SOC_DAPM_PIN_SWITCH("Int Mic"), | ||
568 | SOC_DAPM_PIN_SWITCH("Line In"), | ||
569 | }; | ||
570 | |||
571 | static const struct snd_kcontrol_new tegra_wm8903_default_controls[] = { | ||
239 | SOC_DAPM_PIN_SWITCH("Int Spk"), | 572 | SOC_DAPM_PIN_SWITCH("Int Spk"), |
240 | }; | 573 | }; |
241 | 574 | ||
@@ -248,6 +581,8 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) | |||
248 | struct tegra_wm8903_platform_data *pdata = machine->pdata; | 581 | struct tegra_wm8903_platform_data *pdata = machine->pdata; |
249 | int ret; | 582 | int ret; |
250 | 583 | ||
584 | machine->bias_level = SND_SOC_BIAS_STANDBY; | ||
585 | |||
251 | if (gpio_is_valid(pdata->gpio_spkr_en)) { | 586 | if (gpio_is_valid(pdata->gpio_spkr_en)) { |
252 | ret = gpio_request(pdata->gpio_spkr_en, "spkr_en"); | 587 | ret = gpio_request(pdata->gpio_spkr_en, "spkr_en"); |
253 | if (ret) { | 588 | if (ret) { |
@@ -267,7 +602,7 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) | |||
267 | } | 602 | } |
268 | machine->gpio_requested |= GPIO_HP_MUTE; | 603 | machine->gpio_requested |= GPIO_HP_MUTE; |
269 | 604 | ||
270 | gpio_direction_output(pdata->gpio_hp_mute, 0); | 605 | gpio_direction_output(pdata->gpio_hp_mute, 1); |
271 | } | 606 | } |
272 | 607 | ||
273 | if (gpio_is_valid(pdata->gpio_int_mic_en)) { | 608 | if (gpio_is_valid(pdata->gpio_int_mic_en)) { |
@@ -298,28 +633,41 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) | |||
298 | tegra_wm8903_hp_jack_gpio.gpio = pdata->gpio_hp_det; | 633 | tegra_wm8903_hp_jack_gpio.gpio = pdata->gpio_hp_det; |
299 | snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, | 634 | snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, |
300 | &tegra_wm8903_hp_jack); | 635 | &tegra_wm8903_hp_jack); |
636 | #ifndef CONFIG_SWITCH | ||
301 | snd_soc_jack_add_pins(&tegra_wm8903_hp_jack, | 637 | snd_soc_jack_add_pins(&tegra_wm8903_hp_jack, |
302 | ARRAY_SIZE(tegra_wm8903_hp_jack_pins), | 638 | ARRAY_SIZE(tegra_wm8903_hp_jack_pins), |
303 | tegra_wm8903_hp_jack_pins); | 639 | tegra_wm8903_hp_jack_pins); |
640 | #else | ||
641 | snd_soc_jack_notifier_register(&tegra_wm8903_hp_jack, | ||
642 | &tegra_wm8903_jack_detect_nb); | ||
643 | #endif | ||
304 | snd_soc_jack_add_gpios(&tegra_wm8903_hp_jack, | 644 | snd_soc_jack_add_gpios(&tegra_wm8903_hp_jack, |
305 | 1, | 645 | 1, |
306 | &tegra_wm8903_hp_jack_gpio); | 646 | &tegra_wm8903_hp_jack_gpio); |
647 | machine->gpio_requested |= GPIO_HP_DET; | ||
307 | } | 648 | } |
308 | 649 | ||
309 | snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE, | 650 | snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE, |
310 | &tegra_wm8903_mic_jack); | 651 | &tegra_wm8903_mic_jack); |
652 | #ifndef CONFIG_SWITCH | ||
311 | snd_soc_jack_add_pins(&tegra_wm8903_mic_jack, | 653 | snd_soc_jack_add_pins(&tegra_wm8903_mic_jack, |
312 | ARRAY_SIZE(tegra_wm8903_mic_jack_pins), | 654 | ARRAY_SIZE(tegra_wm8903_mic_jack_pins), |
313 | tegra_wm8903_mic_jack_pins); | 655 | tegra_wm8903_mic_jack_pins); |
656 | #else | ||
657 | snd_soc_jack_notifier_register(&tegra_wm8903_mic_jack, | ||
658 | &tegra_wm8903_jack_detect_nb); | ||
659 | #endif | ||
314 | wm8903_mic_detect(codec, &tegra_wm8903_mic_jack, SND_JACK_MICROPHONE, | 660 | wm8903_mic_detect(codec, &tegra_wm8903_mic_jack, SND_JACK_MICROPHONE, |
315 | 0); | 661 | machine_is_cardhu() ? SND_JACK_MICROPHONE : 0); |
316 | 662 | ||
317 | snd_soc_dapm_force_enable_pin(dapm, "Mic Bias"); | 663 | snd_soc_dapm_force_enable_pin(dapm, "Mic Bias"); |
318 | 664 | ||
319 | /* FIXME: Calculate automatically based on DAPM routes? */ | 665 | /* FIXME: Calculate automatically based on DAPM routes? */ |
320 | if (!machine_is_harmony() && !machine_is_ventana()) | 666 | if (!machine_is_harmony() && !machine_is_ventana() && |
667 | !machine_is_cardhu()) | ||
321 | snd_soc_dapm_nc_pin(dapm, "IN1L"); | 668 | snd_soc_dapm_nc_pin(dapm, "IN1L"); |
322 | if (!machine_is_seaboard() && !machine_is_aebl()) | 669 | if (!machine_is_seaboard() && !machine_is_aebl() && |
670 | !machine_is_cardhu()) | ||
323 | snd_soc_dapm_nc_pin(dapm, "IN1R"); | 671 | snd_soc_dapm_nc_pin(dapm, "IN1R"); |
324 | snd_soc_dapm_nc_pin(dapm, "IN2L"); | 672 | snd_soc_dapm_nc_pin(dapm, "IN2L"); |
325 | if (!machine_is_kaen()) | 673 | if (!machine_is_kaen()) |
@@ -342,26 +690,98 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) | |||
342 | return 0; | 690 | return 0; |
343 | } | 691 | } |
344 | 692 | ||
345 | static struct snd_soc_dai_link tegra_wm8903_dai = { | 693 | #ifdef WM8903_SET_BIAS_LEVEL |
346 | .name = "WM8903", | 694 | static int tegra30_soc_set_bias_level(struct snd_soc_card *card, |
347 | .stream_name = "WM8903 PCM", | 695 | enum snd_soc_bias_level level) |
348 | .codec_name = "wm8903.0-001a", | 696 | { |
349 | .platform_name = "tegra-pcm-audio", | 697 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); |
350 | .cpu_dai_name = "tegra-i2s.0", | 698 | |
351 | .codec_dai_name = "wm8903-hifi", | 699 | if (machine->bias_level == SND_SOC_BIAS_OFF && |
352 | .init = tegra_wm8903_init, | 700 | level != SND_SOC_BIAS_OFF) |
353 | .ops = &tegra_wm8903_ops, | 701 | tegra_asoc_utils_clk_enable(&machine->util_data); |
702 | |||
703 | return 0; | ||
704 | } | ||
705 | |||
706 | static int tegra30_soc_set_bias_level_post(struct snd_soc_card *card, | ||
707 | enum snd_soc_bias_level level) | ||
708 | { | ||
709 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); | ||
710 | |||
711 | if (machine->bias_level != SND_SOC_BIAS_OFF && | ||
712 | level == SND_SOC_BIAS_OFF) | ||
713 | tegra_asoc_utils_clk_disable(&machine->util_data); | ||
714 | |||
715 | machine->bias_level = level; | ||
716 | |||
717 | return 0 ; | ||
718 | } | ||
719 | #endif | ||
720 | |||
721 | static struct snd_soc_dai_link tegra_wm8903_dai[] = { | ||
722 | { | ||
723 | .name = "WM8903", | ||
724 | .stream_name = "WM8903 PCM", | ||
725 | .codec_name = "wm8903.0-001a", | ||
726 | .platform_name = "tegra-pcm-audio", | ||
727 | .cpu_dai_name = "tegra20-i2s.0", | ||
728 | .codec_dai_name = "wm8903-hifi", | ||
729 | .init = tegra_wm8903_init, | ||
730 | .ops = &tegra_wm8903_ops, | ||
731 | }, | ||
732 | { | ||
733 | .name = "SPDIF", | ||
734 | .stream_name = "SPDIF PCM", | ||
735 | .codec_name = "spdif-dit.0", | ||
736 | .platform_name = "tegra-pcm-audio", | ||
737 | .cpu_dai_name = "tegra20-spdif", | ||
738 | .codec_dai_name = "dit-hifi", | ||
739 | .ops = &tegra_spdif_ops, | ||
740 | }, | ||
741 | { | ||
742 | .name = "BT-SCO", | ||
743 | .stream_name = "BT SCO PCM", | ||
744 | .codec_name = "spdif-dit.1", | ||
745 | .platform_name = "tegra-pcm-audio", | ||
746 | .cpu_dai_name = "tegra20-i2s.1", | ||
747 | .codec_dai_name = "dit-hifi", | ||
748 | .ops = &tegra_wm8903_bt_sco_ops, | ||
749 | }, | ||
354 | }; | 750 | }; |
355 | 751 | ||
752 | static int tegra_wm8903_suspend_post(struct snd_soc_card *card) | ||
753 | { | ||
754 | struct snd_soc_jack_gpio *gpio = &tegra_wm8903_hp_jack_gpio; | ||
755 | |||
756 | if (gpio_is_valid(gpio->gpio)) | ||
757 | disable_irq(gpio_to_irq(gpio->gpio)); | ||
758 | |||
759 | return 0; | ||
760 | } | ||
761 | |||
762 | static int tegra_wm8903_resume_pre(struct snd_soc_card *card) | ||
763 | { | ||
764 | int val; | ||
765 | struct snd_soc_jack_gpio *gpio = &tegra_wm8903_hp_jack_gpio; | ||
766 | |||
767 | if (gpio_is_valid(gpio->gpio)) { | ||
768 | val = gpio_get_value(gpio->gpio); | ||
769 | val = gpio->invert ? !val : val; | ||
770 | snd_soc_jack_report(gpio->jack, val, gpio->report); | ||
771 | enable_irq(gpio_to_irq(gpio->gpio)); | ||
772 | } | ||
773 | |||
774 | return 0; | ||
775 | } | ||
776 | |||
356 | static struct snd_soc_card snd_soc_tegra_wm8903 = { | 777 | static struct snd_soc_card snd_soc_tegra_wm8903 = { |
357 | .name = "tegra-wm8903", | 778 | .name = "tegra-wm8903", |
358 | .dai_link = &tegra_wm8903_dai, | 779 | .dai_link = tegra_wm8903_dai, |
359 | .num_links = 1, | 780 | .num_links = ARRAY_SIZE(tegra_wm8903_dai), |
360 | 781 | .suspend_post = tegra_wm8903_suspend_post, | |
361 | .controls = tegra_wm8903_controls, | 782 | .resume_pre = tegra_wm8903_resume_pre, |
362 | .num_controls = ARRAY_SIZE(tegra_wm8903_controls), | 783 | //.set_bias_level = tegra30_soc_set_bias_level, |
363 | .dapm_widgets = tegra_wm8903_dapm_widgets, | 784 | //.set_bias_level_post = tegra30_soc_set_bias_level_post, |
364 | .num_dapm_widgets = ARRAY_SIZE(tegra_wm8903_dapm_widgets), | ||
365 | }; | 785 | }; |
366 | 786 | ||
367 | static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) | 787 | static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) |
@@ -389,13 +809,63 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) | |||
389 | if (ret) | 809 | if (ret) |
390 | goto err_free_machine; | 810 | goto err_free_machine; |
391 | 811 | ||
812 | if (machine_is_cardhu() || machine_is_ventana()) { | ||
813 | machine->spk_reg = regulator_get(&pdev->dev, "vdd_spk_amp"); | ||
814 | if (IS_ERR(machine->spk_reg)) { | ||
815 | dev_info(&pdev->dev, "No speaker regulator found\n"); | ||
816 | machine->spk_reg = 0; | ||
817 | } | ||
818 | } | ||
819 | |||
820 | if (machine_is_ventana()) { | ||
821 | machine->dmic_reg = regulator_get(&pdev->dev, "vdd_dmic"); | ||
822 | if (IS_ERR(machine->dmic_reg)) { | ||
823 | dev_info(&pdev->dev, "No digital mic" | ||
824 | " regulator found\n"); | ||
825 | machine->dmic_reg = 0; | ||
826 | } | ||
827 | } | ||
828 | |||
829 | if (machine_is_cardhu()) { | ||
830 | tegra_wm8903_dai[0].codec_name = "wm8903.4-001a", | ||
831 | tegra_wm8903_dai[0].cpu_dai_name = "tegra30-i2s.1"; | ||
832 | |||
833 | tegra_wm8903_dai[1].cpu_dai_name = "tegra30-spdif"; | ||
834 | |||
835 | tegra_wm8903_dai[2].cpu_dai_name = "tegra30-i2s.3"; | ||
836 | } | ||
837 | |||
838 | #ifdef CONFIG_SWITCH | ||
839 | /* Addd h2w swith class support */ | ||
840 | ret = switch_dev_register(&tegra_wm8903_headset_switch); | ||
841 | if (ret < 0) | ||
842 | goto err_fini_utils; | ||
843 | #endif | ||
844 | |||
392 | card->dev = &pdev->dev; | 845 | card->dev = &pdev->dev; |
393 | platform_set_drvdata(pdev, card); | 846 | platform_set_drvdata(pdev, card); |
394 | snd_soc_card_set_drvdata(card, machine); | 847 | snd_soc_card_set_drvdata(card, machine); |
395 | 848 | ||
396 | if (machine_is_harmony() || machine_is_ventana()) { | 849 | if (machine_is_cardhu() || machine_is_ventana()) { |
850 | card->controls = cardhu_controls; | ||
851 | card->num_controls = ARRAY_SIZE(cardhu_controls); | ||
852 | |||
853 | card->dapm_widgets = cardhu_dapm_widgets; | ||
854 | card->num_dapm_widgets = ARRAY_SIZE(cardhu_dapm_widgets); | ||
855 | } else { | ||
856 | card->controls = tegra_wm8903_default_controls; | ||
857 | card->num_controls = ARRAY_SIZE(tegra_wm8903_default_controls); | ||
858 | |||
859 | card->dapm_widgets = tegra_wm8903_default_dapm_widgets; | ||
860 | card->num_dapm_widgets = ARRAY_SIZE(tegra_wm8903_default_dapm_widgets); | ||
861 | } | ||
862 | |||
863 | if (machine_is_harmony()) { | ||
397 | card->dapm_routes = harmony_audio_map; | 864 | card->dapm_routes = harmony_audio_map; |
398 | card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map); | 865 | card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map); |
866 | } else if (machine_is_ventana() || machine_is_cardhu()) { | ||
867 | card->dapm_routes = cardhu_audio_map; | ||
868 | card->num_dapm_routes = ARRAY_SIZE(cardhu_audio_map); | ||
399 | } else if (machine_is_seaboard()) { | 869 | } else if (machine_is_seaboard()) { |
400 | card->dapm_routes = seaboard_audio_map; | 870 | card->dapm_routes = seaboard_audio_map; |
401 | card->num_dapm_routes = ARRAY_SIZE(seaboard_audio_map); | 871 | card->num_dapm_routes = ARRAY_SIZE(seaboard_audio_map); |
@@ -411,11 +881,24 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) | |||
411 | if (ret) { | 881 | if (ret) { |
412 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", | 882 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", |
413 | ret); | 883 | ret); |
414 | goto err_fini_utils; | 884 | goto err_unregister_switch; |
885 | } | ||
886 | |||
887 | if (!card->instantiated) { | ||
888 | ret = -ENODEV; | ||
889 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", | ||
890 | ret); | ||
891 | goto err_unregister_card; | ||
415 | } | 892 | } |
416 | 893 | ||
417 | return 0; | 894 | return 0; |
418 | 895 | ||
896 | err_unregister_card: | ||
897 | snd_soc_unregister_card(card); | ||
898 | err_unregister_switch: | ||
899 | #ifdef CONFIG_SWITCH | ||
900 | switch_dev_unregister(&tegra_wm8903_headset_switch); | ||
901 | #endif | ||
419 | err_fini_utils: | 902 | err_fini_utils: |
420 | tegra_asoc_utils_fini(&machine->util_data); | 903 | tegra_asoc_utils_fini(&machine->util_data); |
421 | err_free_machine: | 904 | err_free_machine: |
@@ -429,10 +912,10 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev) | |||
429 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); | 912 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); |
430 | struct tegra_wm8903_platform_data *pdata = machine->pdata; | 913 | struct tegra_wm8903_platform_data *pdata = machine->pdata; |
431 | 914 | ||
432 | snd_soc_unregister_card(card); | 915 | if (machine->gpio_requested & GPIO_HP_DET) |
433 | 916 | snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack, | |
434 | tegra_asoc_utils_fini(&machine->util_data); | 917 | 1, |
435 | 918 | &tegra_wm8903_hp_jack_gpio); | |
436 | if (machine->gpio_requested & GPIO_EXT_MIC_EN) | 919 | if (machine->gpio_requested & GPIO_EXT_MIC_EN) |
437 | gpio_free(pdata->gpio_ext_mic_en); | 920 | gpio_free(pdata->gpio_ext_mic_en); |
438 | if (machine->gpio_requested & GPIO_INT_MIC_EN) | 921 | if (machine->gpio_requested & GPIO_INT_MIC_EN) |
@@ -441,7 +924,20 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev) | |||
441 | gpio_free(pdata->gpio_hp_mute); | 924 | gpio_free(pdata->gpio_hp_mute); |
442 | if (machine->gpio_requested & GPIO_SPKR_EN) | 925 | if (machine->gpio_requested & GPIO_SPKR_EN) |
443 | gpio_free(pdata->gpio_spkr_en); | 926 | gpio_free(pdata->gpio_spkr_en); |
927 | machine->gpio_requested = 0; | ||
928 | |||
929 | if (machine->spk_reg) | ||
930 | regulator_put(machine->spk_reg); | ||
931 | if (machine->dmic_reg) | ||
932 | regulator_put(machine->dmic_reg); | ||
933 | |||
934 | snd_soc_unregister_card(card); | ||
935 | |||
936 | tegra_asoc_utils_fini(&machine->util_data); | ||
444 | 937 | ||
938 | #ifdef CONFIG_SWITCH | ||
939 | switch_dev_unregister(&tegra_wm8903_headset_switch); | ||
940 | #endif | ||
445 | kfree(machine); | 941 | kfree(machine); |
446 | 942 | ||
447 | return 0; | 943 | return 0; |