Commit b9b50363e6c60d471fe2e71e48d434aad58b3749
Exists in
master
and in
7 other branches
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6: ALSA: ASoC: Fix double free and memory leak in many codec drivers ALSA: CA0106 on MSI K8N Diamond PLUS Motherboard
Showing 9 changed files Inline Diff
sound/pci/ca0106/ca0106_main.c
1 | /* | 1 | /* |
2 | * Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk> | 2 | * Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk> |
3 | * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit | 3 | * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit |
4 | * Version: 0.0.25 | 4 | * Version: 0.0.25 |
5 | * | 5 | * |
6 | * FEATURES currently supported: | 6 | * FEATURES currently supported: |
7 | * Front, Rear and Center/LFE. | 7 | * Front, Rear and Center/LFE. |
8 | * Surround40 and Surround51. | 8 | * Surround40 and Surround51. |
9 | * Capture from MIC an LINE IN input. | 9 | * Capture from MIC an LINE IN input. |
10 | * SPDIF digital playback of PCM stereo and AC3/DTS works. | 10 | * SPDIF digital playback of PCM stereo and AC3/DTS works. |
11 | * (One can use a standard mono mini-jack to one RCA plugs cable. | 11 | * (One can use a standard mono mini-jack to one RCA plugs cable. |
12 | * or one can use a standard stereo mini-jack to two RCA plugs cable. | 12 | * or one can use a standard stereo mini-jack to two RCA plugs cable. |
13 | * Plug one of the RCA plugs into the Coax input of the external decoder/receiver.) | 13 | * Plug one of the RCA plugs into the Coax input of the external decoder/receiver.) |
14 | * ( In theory one could output 3 different AC3 streams at once, to 3 different SPDIF outputs. ) | 14 | * ( In theory one could output 3 different AC3 streams at once, to 3 different SPDIF outputs. ) |
15 | * Notes on how to capture sound: | 15 | * Notes on how to capture sound: |
16 | * The AC97 is used in the PLAYBACK direction. | 16 | * The AC97 is used in the PLAYBACK direction. |
17 | * The output from the AC97 chip, instead of reaching the speakers, is fed into the Philips 1361T ADC. | 17 | * The output from the AC97 chip, instead of reaching the speakers, is fed into the Philips 1361T ADC. |
18 | * So, to record from the MIC, set the MIC Playback volume to max, | 18 | * So, to record from the MIC, set the MIC Playback volume to max, |
19 | * unmute the MIC and turn up the MASTER Playback volume. | 19 | * unmute the MIC and turn up the MASTER Playback volume. |
20 | * So, to prevent feedback when capturing, minimise the "Capture feedback into Playback" volume. | 20 | * So, to prevent feedback when capturing, minimise the "Capture feedback into Playback" volume. |
21 | * | 21 | * |
22 | * The only playback controls that currently do anything are: - | 22 | * The only playback controls that currently do anything are: - |
23 | * Analog Front | 23 | * Analog Front |
24 | * Analog Rear | 24 | * Analog Rear |
25 | * Analog Center/LFE | 25 | * Analog Center/LFE |
26 | * SPDIF Front | 26 | * SPDIF Front |
27 | * SPDIF Rear | 27 | * SPDIF Rear |
28 | * SPDIF Center/LFE | 28 | * SPDIF Center/LFE |
29 | * | 29 | * |
30 | * For capture from Mic in or Line in. | 30 | * For capture from Mic in or Line in. |
31 | * Digital/Analog ( switch must be in Analog mode for CAPTURE. ) | 31 | * Digital/Analog ( switch must be in Analog mode for CAPTURE. ) |
32 | * | 32 | * |
33 | * CAPTURE feedback into PLAYBACK | 33 | * CAPTURE feedback into PLAYBACK |
34 | * | 34 | * |
35 | * Changelog: | 35 | * Changelog: |
36 | * Support interrupts per period. | 36 | * Support interrupts per period. |
37 | * Removed noise from Center/LFE channel when in Analog mode. | 37 | * Removed noise from Center/LFE channel when in Analog mode. |
38 | * Rename and remove mixer controls. | 38 | * Rename and remove mixer controls. |
39 | * 0.0.6 | 39 | * 0.0.6 |
40 | * Use separate card based DMA buffer for periods table list. | 40 | * Use separate card based DMA buffer for periods table list. |
41 | * 0.0.7 | 41 | * 0.0.7 |
42 | * Change remove and rename ctrls into lists. | 42 | * Change remove and rename ctrls into lists. |
43 | * 0.0.8 | 43 | * 0.0.8 |
44 | * Try to fix capture sources. | 44 | * Try to fix capture sources. |
45 | * 0.0.9 | 45 | * 0.0.9 |
46 | * Fix AC3 output. | 46 | * Fix AC3 output. |
47 | * Enable S32_LE format support. | 47 | * Enable S32_LE format support. |
48 | * 0.0.10 | 48 | * 0.0.10 |
49 | * Enable playback 48000 and 96000 rates. (Rates other that these do not work, even with "plug:front".) | 49 | * Enable playback 48000 and 96000 rates. (Rates other that these do not work, even with "plug:front".) |
50 | * 0.0.11 | 50 | * 0.0.11 |
51 | * Add Model name recognition. | 51 | * Add Model name recognition. |
52 | * 0.0.12 | 52 | * 0.0.12 |
53 | * Correct interrupt timing. interrupt at end of period, instead of in the middle of a playback period. | 53 | * Correct interrupt timing. interrupt at end of period, instead of in the middle of a playback period. |
54 | * Remove redundent "voice" handling. | 54 | * Remove redundent "voice" handling. |
55 | * 0.0.13 | 55 | * 0.0.13 |
56 | * Single trigger call for multi channels. | 56 | * Single trigger call for multi channels. |
57 | * 0.0.14 | 57 | * 0.0.14 |
58 | * Set limits based on what the sound card hardware can do. | 58 | * Set limits based on what the sound card hardware can do. |
59 | * playback periods_min=2, periods_max=8 | 59 | * playback periods_min=2, periods_max=8 |
60 | * capture hw constraints require period_size = n * 64 bytes. | 60 | * capture hw constraints require period_size = n * 64 bytes. |
61 | * playback hw constraints require period_size = n * 64 bytes. | 61 | * playback hw constraints require period_size = n * 64 bytes. |
62 | * 0.0.15 | 62 | * 0.0.15 |
63 | * Minor updates. | 63 | * Minor updates. |
64 | * 0.0.16 | 64 | * 0.0.16 |
65 | * Implement 192000 sample rate. | 65 | * Implement 192000 sample rate. |
66 | * 0.0.17 | 66 | * 0.0.17 |
67 | * Add support for SB0410 and SB0413. | 67 | * Add support for SB0410 and SB0413. |
68 | * 0.0.18 | 68 | * 0.0.18 |
69 | * Modified Copyright message. | 69 | * Modified Copyright message. |
70 | * 0.0.19 | 70 | * 0.0.19 |
71 | * Finally fix support for SB Live 24 bit. SB0410 and SB0413. | 71 | * Finally fix support for SB Live 24 bit. SB0410 and SB0413. |
72 | * The output codec needs resetting, otherwise all output is muted. | 72 | * The output codec needs resetting, otherwise all output is muted. |
73 | * 0.0.20 | 73 | * 0.0.20 |
74 | * Merge "pci_disable_device(pci);" fixes. | 74 | * Merge "pci_disable_device(pci);" fixes. |
75 | * 0.0.21 | 75 | * 0.0.21 |
76 | * Add 4 capture channels. (SPDIF only comes in on channel 0. ) | 76 | * Add 4 capture channels. (SPDIF only comes in on channel 0. ) |
77 | * Add SPDIF capture using optional digital I/O module for SB Live 24bit. (Analog capture does not yet work.) | 77 | * Add SPDIF capture using optional digital I/O module for SB Live 24bit. (Analog capture does not yet work.) |
78 | * 0.0.22 | 78 | * 0.0.22 |
79 | * Add support for MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97. From kiksen, bug #901 | 79 | * Add support for MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97. From kiksen, bug #901 |
80 | * 0.0.23 | 80 | * 0.0.23 |
81 | * Implement support for Line-in capture on SB Live 24bit. | 81 | * Implement support for Line-in capture on SB Live 24bit. |
82 | * 0.0.24 | 82 | * 0.0.24 |
83 | * Add support for mute control on SB Live 24bit (cards w/ SPI DAC) | 83 | * Add support for mute control on SB Live 24bit (cards w/ SPI DAC) |
84 | * 0.0.25 | 84 | * 0.0.25 |
85 | * Powerdown SPI DAC channels when not in use | 85 | * Powerdown SPI DAC channels when not in use |
86 | * | 86 | * |
87 | * BUGS: | 87 | * BUGS: |
88 | * Some stability problems when unloading the snd-ca0106 kernel module. | 88 | * Some stability problems when unloading the snd-ca0106 kernel module. |
89 | * -- | 89 | * -- |
90 | * | 90 | * |
91 | * TODO: | 91 | * TODO: |
92 | * 4 Capture channels, only one implemented so far. | 92 | * 4 Capture channels, only one implemented so far. |
93 | * Other capture rates apart from 48khz not implemented. | 93 | * Other capture rates apart from 48khz not implemented. |
94 | * MIDI | 94 | * MIDI |
95 | * -- | 95 | * -- |
96 | * GENERAL INFO: | 96 | * GENERAL INFO: |
97 | * Model: SB0310 | 97 | * Model: SB0310 |
98 | * P17 Chip: CA0106-DAT | 98 | * P17 Chip: CA0106-DAT |
99 | * AC97 Codec: STAC 9721 | 99 | * AC97 Codec: STAC 9721 |
100 | * ADC: Philips 1361T (Stereo 24bit) | 100 | * ADC: Philips 1361T (Stereo 24bit) |
101 | * DAC: WM8746EDS (6-channel, 24bit, 192Khz) | 101 | * DAC: WM8746EDS (6-channel, 24bit, 192Khz) |
102 | * | 102 | * |
103 | * GENERAL INFO: | 103 | * GENERAL INFO: |
104 | * Model: SB0410 | 104 | * Model: SB0410 |
105 | * P17 Chip: CA0106-DAT | 105 | * P17 Chip: CA0106-DAT |
106 | * AC97 Codec: None | 106 | * AC97 Codec: None |
107 | * ADC: WM8775EDS (4 Channel) | 107 | * ADC: WM8775EDS (4 Channel) |
108 | * DAC: CS4382 (114 dB, 24-Bit, 192 kHz, 8-Channel D/A Converter with DSD Support) | 108 | * DAC: CS4382 (114 dB, 24-Bit, 192 kHz, 8-Channel D/A Converter with DSD Support) |
109 | * SPDIF Out control switches between Mic in and SPDIF out. | 109 | * SPDIF Out control switches between Mic in and SPDIF out. |
110 | * No sound out or mic input working yet. | 110 | * No sound out or mic input working yet. |
111 | * | 111 | * |
112 | * GENERAL INFO: | 112 | * GENERAL INFO: |
113 | * Model: SB0413 | 113 | * Model: SB0413 |
114 | * P17 Chip: CA0106-DAT | 114 | * P17 Chip: CA0106-DAT |
115 | * AC97 Codec: None. | 115 | * AC97 Codec: None. |
116 | * ADC: Unknown | 116 | * ADC: Unknown |
117 | * DAC: Unknown | 117 | * DAC: Unknown |
118 | * Trying to handle it like the SB0410. | 118 | * Trying to handle it like the SB0410. |
119 | * | 119 | * |
120 | * This code was initally based on code from ALSA's emu10k1x.c which is: | 120 | * This code was initally based on code from ALSA's emu10k1x.c which is: |
121 | * Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com> | 121 | * Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com> |
122 | * | 122 | * |
123 | * This program is free software; you can redistribute it and/or modify | 123 | * This program is free software; you can redistribute it and/or modify |
124 | * it under the terms of the GNU General Public License as published by | 124 | * it under the terms of the GNU General Public License as published by |
125 | * the Free Software Foundation; either version 2 of the License, or | 125 | * the Free Software Foundation; either version 2 of the License, or |
126 | * (at your option) any later version. | 126 | * (at your option) any later version. |
127 | * | 127 | * |
128 | * This program is distributed in the hope that it will be useful, | 128 | * This program is distributed in the hope that it will be useful, |
129 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 129 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
130 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 130 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
131 | * GNU General Public License for more details. | 131 | * GNU General Public License for more details. |
132 | * | 132 | * |
133 | * You should have received a copy of the GNU General Public License | 133 | * You should have received a copy of the GNU General Public License |
134 | * along with this program; if not, write to the Free Software | 134 | * along with this program; if not, write to the Free Software |
135 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 135 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
136 | * | 136 | * |
137 | */ | 137 | */ |
138 | #include <linux/delay.h> | 138 | #include <linux/delay.h> |
139 | #include <linux/init.h> | 139 | #include <linux/init.h> |
140 | #include <linux/interrupt.h> | 140 | #include <linux/interrupt.h> |
141 | #include <linux/pci.h> | 141 | #include <linux/pci.h> |
142 | #include <linux/slab.h> | 142 | #include <linux/slab.h> |
143 | #include <linux/moduleparam.h> | 143 | #include <linux/moduleparam.h> |
144 | #include <linux/dma-mapping.h> | 144 | #include <linux/dma-mapping.h> |
145 | #include <sound/core.h> | 145 | #include <sound/core.h> |
146 | #include <sound/initval.h> | 146 | #include <sound/initval.h> |
147 | #include <sound/pcm.h> | 147 | #include <sound/pcm.h> |
148 | #include <sound/ac97_codec.h> | 148 | #include <sound/ac97_codec.h> |
149 | #include <sound/info.h> | 149 | #include <sound/info.h> |
150 | 150 | ||
151 | MODULE_AUTHOR("James Courtier-Dutton <James@superbug.demon.co.uk>"); | 151 | MODULE_AUTHOR("James Courtier-Dutton <James@superbug.demon.co.uk>"); |
152 | MODULE_DESCRIPTION("CA0106"); | 152 | MODULE_DESCRIPTION("CA0106"); |
153 | MODULE_LICENSE("GPL"); | 153 | MODULE_LICENSE("GPL"); |
154 | MODULE_SUPPORTED_DEVICE("{{Creative,SB CA0106 chip}}"); | 154 | MODULE_SUPPORTED_DEVICE("{{Creative,SB CA0106 chip}}"); |
155 | 155 | ||
156 | // module parameters (see "Module Parameters") | 156 | // module parameters (see "Module Parameters") |
157 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | 157 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; |
158 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | 158 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; |
159 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | 159 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; |
160 | static uint subsystem[SNDRV_CARDS]; /* Force card subsystem model */ | 160 | static uint subsystem[SNDRV_CARDS]; /* Force card subsystem model */ |
161 | 161 | ||
162 | module_param_array(index, int, NULL, 0444); | 162 | module_param_array(index, int, NULL, 0444); |
163 | MODULE_PARM_DESC(index, "Index value for the CA0106 soundcard."); | 163 | MODULE_PARM_DESC(index, "Index value for the CA0106 soundcard."); |
164 | module_param_array(id, charp, NULL, 0444); | 164 | module_param_array(id, charp, NULL, 0444); |
165 | MODULE_PARM_DESC(id, "ID string for the CA0106 soundcard."); | 165 | MODULE_PARM_DESC(id, "ID string for the CA0106 soundcard."); |
166 | module_param_array(enable, bool, NULL, 0444); | 166 | module_param_array(enable, bool, NULL, 0444); |
167 | MODULE_PARM_DESC(enable, "Enable the CA0106 soundcard."); | 167 | MODULE_PARM_DESC(enable, "Enable the CA0106 soundcard."); |
168 | module_param_array(subsystem, uint, NULL, 0444); | 168 | module_param_array(subsystem, uint, NULL, 0444); |
169 | MODULE_PARM_DESC(subsystem, "Force card subsystem model."); | 169 | MODULE_PARM_DESC(subsystem, "Force card subsystem model."); |
170 | 170 | ||
171 | #include "ca0106.h" | 171 | #include "ca0106.h" |
172 | 172 | ||
173 | static struct snd_ca0106_details ca0106_chip_details[] = { | 173 | static struct snd_ca0106_details ca0106_chip_details[] = { |
174 | /* Sound Blaster X-Fi Extreme Audio. This does not have an AC97. 53SB079000000 */ | 174 | /* Sound Blaster X-Fi Extreme Audio. This does not have an AC97. 53SB079000000 */ |
175 | /* It is really just a normal SB Live 24bit. */ | 175 | /* It is really just a normal SB Live 24bit. */ |
176 | /* Tested: | 176 | /* Tested: |
177 | * See ALSA bug#3251 | 177 | * See ALSA bug#3251 |
178 | */ | 178 | */ |
179 | { .serial = 0x10131102, | 179 | { .serial = 0x10131102, |
180 | .name = "X-Fi Extreme Audio [SBxxxx]", | 180 | .name = "X-Fi Extreme Audio [SBxxxx]", |
181 | .gpio_type = 1, | 181 | .gpio_type = 1, |
182 | .i2c_adc = 1 } , | 182 | .i2c_adc = 1 } , |
183 | /* Sound Blaster X-Fi Extreme Audio. This does not have an AC97. 53SB079000000 */ | 183 | /* Sound Blaster X-Fi Extreme Audio. This does not have an AC97. 53SB079000000 */ |
184 | /* It is really just a normal SB Live 24bit. */ | 184 | /* It is really just a normal SB Live 24bit. */ |
185 | /* | 185 | /* |
186 | * CTRL:CA0111-WTLF | 186 | * CTRL:CA0111-WTLF |
187 | * ADC: WM8775SEDS | 187 | * ADC: WM8775SEDS |
188 | * DAC: CS4382-KQZ | 188 | * DAC: CS4382-KQZ |
189 | */ | 189 | */ |
190 | /* Tested: | 190 | /* Tested: |
191 | * Playback on front, rear, center/lfe speakers | 191 | * Playback on front, rear, center/lfe speakers |
192 | * Capture from Mic in. | 192 | * Capture from Mic in. |
193 | * Not-Tested: | 193 | * Not-Tested: |
194 | * Capture from Line in. | 194 | * Capture from Line in. |
195 | * Playback to digital out. | 195 | * Playback to digital out. |
196 | */ | 196 | */ |
197 | { .serial = 0x10121102, | 197 | { .serial = 0x10121102, |
198 | .name = "X-Fi Extreme Audio [SB0790]", | 198 | .name = "X-Fi Extreme Audio [SB0790]", |
199 | .gpio_type = 1, | 199 | .gpio_type = 1, |
200 | .i2c_adc = 1 } , | 200 | .i2c_adc = 1 } , |
201 | /* New Dell Sound Blaster Live! 7.1 24bit. This does not have an AC97. */ | 201 | /* New Dell Sound Blaster Live! 7.1 24bit. This does not have an AC97. */ |
202 | /* AudigyLS[SB0310] */ | 202 | /* AudigyLS[SB0310] */ |
203 | { .serial = 0x10021102, | 203 | { .serial = 0x10021102, |
204 | .name = "AudigyLS [SB0310]", | 204 | .name = "AudigyLS [SB0310]", |
205 | .ac97 = 1 } , | 205 | .ac97 = 1 } , |
206 | /* Unknown AudigyLS that also says SB0310 on it */ | 206 | /* Unknown AudigyLS that also says SB0310 on it */ |
207 | { .serial = 0x10051102, | 207 | { .serial = 0x10051102, |
208 | .name = "AudigyLS [SB0310b]", | 208 | .name = "AudigyLS [SB0310b]", |
209 | .ac97 = 1 } , | 209 | .ac97 = 1 } , |
210 | /* New Sound Blaster Live! 7.1 24bit. This does not have an AC97. 53SB041000001 */ | 210 | /* New Sound Blaster Live! 7.1 24bit. This does not have an AC97. 53SB041000001 */ |
211 | { .serial = 0x10061102, | 211 | { .serial = 0x10061102, |
212 | .name = "Live! 7.1 24bit [SB0410]", | 212 | .name = "Live! 7.1 24bit [SB0410]", |
213 | .gpio_type = 1, | 213 | .gpio_type = 1, |
214 | .i2c_adc = 1 } , | 214 | .i2c_adc = 1 } , |
215 | /* New Dell Sound Blaster Live! 7.1 24bit. This does not have an AC97. */ | 215 | /* New Dell Sound Blaster Live! 7.1 24bit. This does not have an AC97. */ |
216 | { .serial = 0x10071102, | 216 | { .serial = 0x10071102, |
217 | .name = "Live! 7.1 24bit [SB0413]", | 217 | .name = "Live! 7.1 24bit [SB0413]", |
218 | .gpio_type = 1, | 218 | .gpio_type = 1, |
219 | .i2c_adc = 1 } , | 219 | .i2c_adc = 1 } , |
220 | /* New Audigy SE. Has a different DAC. */ | 220 | /* New Audigy SE. Has a different DAC. */ |
221 | /* SB0570: | 221 | /* SB0570: |
222 | * CTRL:CA0106-DAT | 222 | * CTRL:CA0106-DAT |
223 | * ADC: WM8775EDS | 223 | * ADC: WM8775EDS |
224 | * DAC: WM8768GEDS | 224 | * DAC: WM8768GEDS |
225 | */ | 225 | */ |
226 | { .serial = 0x100a1102, | 226 | { .serial = 0x100a1102, |
227 | .name = "Audigy SE [SB0570]", | 227 | .name = "Audigy SE [SB0570]", |
228 | .gpio_type = 1, | 228 | .gpio_type = 1, |
229 | .i2c_adc = 1, | 229 | .i2c_adc = 1, |
230 | .spi_dac = 1 } , | 230 | .spi_dac = 1 } , |
231 | /* New Audigy LS. Has a different DAC. */ | 231 | /* New Audigy LS. Has a different DAC. */ |
232 | /* SB0570: | 232 | /* SB0570: |
233 | * CTRL:CA0106-DAT | 233 | * CTRL:CA0106-DAT |
234 | * ADC: WM8775EDS | 234 | * ADC: WM8775EDS |
235 | * DAC: WM8768GEDS | 235 | * DAC: WM8768GEDS |
236 | */ | 236 | */ |
237 | { .serial = 0x10111102, | 237 | { .serial = 0x10111102, |
238 | .name = "Audigy SE OEM [SB0570a]", | 238 | .name = "Audigy SE OEM [SB0570a]", |
239 | .gpio_type = 1, | 239 | .gpio_type = 1, |
240 | .i2c_adc = 1, | 240 | .i2c_adc = 1, |
241 | .spi_dac = 1 } , | 241 | .spi_dac = 1 } , |
242 | /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */ | 242 | /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */ |
243 | /* SB0438 | 243 | /* SB0438 |
244 | * CTRL:CA0106-DAT | 244 | * CTRL:CA0106-DAT |
245 | * ADC: WM8775SEDS | 245 | * ADC: WM8775SEDS |
246 | * DAC: CS4382-KQZ | 246 | * DAC: CS4382-KQZ |
247 | */ | 247 | */ |
248 | { .serial = 0x10091462, | 248 | { .serial = 0x10091462, |
249 | .name = "MSI K8N Diamond MB [SB0438]", | 249 | .name = "MSI K8N Diamond MB [SB0438]", |
250 | .gpio_type = 2, | 250 | .gpio_type = 2, |
251 | .i2c_adc = 1 } , | 251 | .i2c_adc = 1 } , |
252 | /* Another MSI K8N Diamond MB, which has apprently a different SSID */ | 252 | /* MSI K8N Diamond PLUS MB */ |
253 | { .serial = 0x10091102, | 253 | { .serial = 0x10091102, |
254 | .name = "MSI K8N Diamond MB", | 254 | .name = "MSI K8N Diamond MB", |
255 | .gpio_type = 2, | 255 | .gpio_type = 2, |
256 | .i2c_adc = 1 } , | 256 | .i2c_adc = 1, |
257 | .spi_dac = 2 } | ||
257 | /* Shuttle XPC SD31P which has an onboard Creative Labs | 258 | /* Shuttle XPC SD31P which has an onboard Creative Labs |
258 | * Sound Blaster Live! 24-bit EAX | 259 | * Sound Blaster Live! 24-bit EAX |
259 | * high-definition 7.1 audio processor". | 260 | * high-definition 7.1 audio processor". |
260 | * Added using info from andrewvegan in alsa bug #1298 | 261 | * Added using info from andrewvegan in alsa bug #1298 |
261 | */ | 262 | */ |
262 | { .serial = 0x30381297, | 263 | { .serial = 0x30381297, |
263 | .name = "Shuttle XPC SD31P [SD31P]", | 264 | .name = "Shuttle XPC SD31P [SD31P]", |
264 | .gpio_type = 1, | 265 | .gpio_type = 1, |
265 | .i2c_adc = 1 } , | 266 | .i2c_adc = 1 } , |
266 | /* Shuttle XPC SD11G5 which has an onboard Creative Labs | 267 | /* Shuttle XPC SD11G5 which has an onboard Creative Labs |
267 | * Sound Blaster Live! 24-bit EAX | 268 | * Sound Blaster Live! 24-bit EAX |
268 | * high-definition 7.1 audio processor". | 269 | * high-definition 7.1 audio processor". |
269 | * Fixes ALSA bug#1600 | 270 | * Fixes ALSA bug#1600 |
270 | */ | 271 | */ |
271 | { .serial = 0x30411297, | 272 | { .serial = 0x30411297, |
272 | .name = "Shuttle XPC SD11G5 [SD11G5]", | 273 | .name = "Shuttle XPC SD11G5 [SD11G5]", |
273 | .gpio_type = 1, | 274 | .gpio_type = 1, |
274 | .i2c_adc = 1 } , | 275 | .i2c_adc = 1 } , |
275 | { .serial = 0, | 276 | { .serial = 0, |
276 | .name = "AudigyLS [Unknown]" } | 277 | .name = "AudigyLS [Unknown]" } |
277 | }; | 278 | }; |
278 | 279 | ||
279 | /* hardware definition */ | 280 | /* hardware definition */ |
280 | static struct snd_pcm_hardware snd_ca0106_playback_hw = { | 281 | static struct snd_pcm_hardware snd_ca0106_playback_hw = { |
281 | .info = SNDRV_PCM_INFO_MMAP | | 282 | .info = SNDRV_PCM_INFO_MMAP | |
282 | SNDRV_PCM_INFO_INTERLEAVED | | 283 | SNDRV_PCM_INFO_INTERLEAVED | |
283 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 284 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
284 | SNDRV_PCM_INFO_MMAP_VALID | | 285 | SNDRV_PCM_INFO_MMAP_VALID | |
285 | SNDRV_PCM_INFO_SYNC_START, | 286 | SNDRV_PCM_INFO_SYNC_START, |
286 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, | 287 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, |
287 | .rates = (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | | 288 | .rates = (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | |
288 | SNDRV_PCM_RATE_192000), | 289 | SNDRV_PCM_RATE_192000), |
289 | .rate_min = 48000, | 290 | .rate_min = 48000, |
290 | .rate_max = 192000, | 291 | .rate_max = 192000, |
291 | .channels_min = 2, //1, | 292 | .channels_min = 2, //1, |
292 | .channels_max = 2, //6, | 293 | .channels_max = 2, //6, |
293 | .buffer_bytes_max = ((65536 - 64) * 8), | 294 | .buffer_bytes_max = ((65536 - 64) * 8), |
294 | .period_bytes_min = 64, | 295 | .period_bytes_min = 64, |
295 | .period_bytes_max = (65536 - 64), | 296 | .period_bytes_max = (65536 - 64), |
296 | .periods_min = 2, | 297 | .periods_min = 2, |
297 | .periods_max = 8, | 298 | .periods_max = 8, |
298 | .fifo_size = 0, | 299 | .fifo_size = 0, |
299 | }; | 300 | }; |
300 | 301 | ||
301 | static struct snd_pcm_hardware snd_ca0106_capture_hw = { | 302 | static struct snd_pcm_hardware snd_ca0106_capture_hw = { |
302 | .info = (SNDRV_PCM_INFO_MMAP | | 303 | .info = (SNDRV_PCM_INFO_MMAP | |
303 | SNDRV_PCM_INFO_INTERLEAVED | | 304 | SNDRV_PCM_INFO_INTERLEAVED | |
304 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 305 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
305 | SNDRV_PCM_INFO_MMAP_VALID), | 306 | SNDRV_PCM_INFO_MMAP_VALID), |
306 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, | 307 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, |
307 | .rates = (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | | 308 | .rates = (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | |
308 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000), | 309 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000), |
309 | .rate_min = 44100, | 310 | .rate_min = 44100, |
310 | .rate_max = 192000, | 311 | .rate_max = 192000, |
311 | .channels_min = 2, | 312 | .channels_min = 2, |
312 | .channels_max = 2, | 313 | .channels_max = 2, |
313 | .buffer_bytes_max = ((65536 - 64) * 8), | 314 | .buffer_bytes_max = ((65536 - 64) * 8), |
314 | .period_bytes_min = 64, | 315 | .period_bytes_min = 64, |
315 | .period_bytes_max = (65536 - 64), | 316 | .period_bytes_max = (65536 - 64), |
316 | .periods_min = 2, | 317 | .periods_min = 2, |
317 | .periods_max = 2, | 318 | .periods_max = 2, |
318 | .fifo_size = 0, | 319 | .fifo_size = 0, |
319 | }; | 320 | }; |
320 | 321 | ||
321 | unsigned int snd_ca0106_ptr_read(struct snd_ca0106 * emu, | 322 | unsigned int snd_ca0106_ptr_read(struct snd_ca0106 * emu, |
322 | unsigned int reg, | 323 | unsigned int reg, |
323 | unsigned int chn) | 324 | unsigned int chn) |
324 | { | 325 | { |
325 | unsigned long flags; | 326 | unsigned long flags; |
326 | unsigned int regptr, val; | 327 | unsigned int regptr, val; |
327 | 328 | ||
328 | regptr = (reg << 16) | chn; | 329 | regptr = (reg << 16) | chn; |
329 | 330 | ||
330 | spin_lock_irqsave(&emu->emu_lock, flags); | 331 | spin_lock_irqsave(&emu->emu_lock, flags); |
331 | outl(regptr, emu->port + PTR); | 332 | outl(regptr, emu->port + PTR); |
332 | val = inl(emu->port + DATA); | 333 | val = inl(emu->port + DATA); |
333 | spin_unlock_irqrestore(&emu->emu_lock, flags); | 334 | spin_unlock_irqrestore(&emu->emu_lock, flags); |
334 | return val; | 335 | return val; |
335 | } | 336 | } |
336 | 337 | ||
337 | void snd_ca0106_ptr_write(struct snd_ca0106 *emu, | 338 | void snd_ca0106_ptr_write(struct snd_ca0106 *emu, |
338 | unsigned int reg, | 339 | unsigned int reg, |
339 | unsigned int chn, | 340 | unsigned int chn, |
340 | unsigned int data) | 341 | unsigned int data) |
341 | { | 342 | { |
342 | unsigned int regptr; | 343 | unsigned int regptr; |
343 | unsigned long flags; | 344 | unsigned long flags; |
344 | 345 | ||
345 | regptr = (reg << 16) | chn; | 346 | regptr = (reg << 16) | chn; |
346 | 347 | ||
347 | spin_lock_irqsave(&emu->emu_lock, flags); | 348 | spin_lock_irqsave(&emu->emu_lock, flags); |
348 | outl(regptr, emu->port + PTR); | 349 | outl(regptr, emu->port + PTR); |
349 | outl(data, emu->port + DATA); | 350 | outl(data, emu->port + DATA); |
350 | spin_unlock_irqrestore(&emu->emu_lock, flags); | 351 | spin_unlock_irqrestore(&emu->emu_lock, flags); |
351 | } | 352 | } |
352 | 353 | ||
353 | int snd_ca0106_spi_write(struct snd_ca0106 * emu, | 354 | int snd_ca0106_spi_write(struct snd_ca0106 * emu, |
354 | unsigned int data) | 355 | unsigned int data) |
355 | { | 356 | { |
356 | unsigned int reset, set; | 357 | unsigned int reset, set; |
357 | unsigned int reg, tmp; | 358 | unsigned int reg, tmp; |
358 | int n, result; | 359 | int n, result; |
359 | reg = SPI; | 360 | reg = SPI; |
360 | if (data > 0xffff) /* Only 16bit values allowed */ | 361 | if (data > 0xffff) /* Only 16bit values allowed */ |
361 | return 1; | 362 | return 1; |
362 | tmp = snd_ca0106_ptr_read(emu, reg, 0); | 363 | tmp = snd_ca0106_ptr_read(emu, reg, 0); |
363 | reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */ | 364 | reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */ |
364 | set = reset | 0x10000; /* Set xxx1xxxx */ | 365 | set = reset | 0x10000; /* Set xxx1xxxx */ |
365 | snd_ca0106_ptr_write(emu, reg, 0, reset | data); | 366 | snd_ca0106_ptr_write(emu, reg, 0, reset | data); |
366 | tmp = snd_ca0106_ptr_read(emu, reg, 0); /* write post */ | 367 | tmp = snd_ca0106_ptr_read(emu, reg, 0); /* write post */ |
367 | snd_ca0106_ptr_write(emu, reg, 0, set | data); | 368 | snd_ca0106_ptr_write(emu, reg, 0, set | data); |
368 | result = 1; | 369 | result = 1; |
369 | /* Wait for status bit to return to 0 */ | 370 | /* Wait for status bit to return to 0 */ |
370 | for (n = 0; n < 100; n++) { | 371 | for (n = 0; n < 100; n++) { |
371 | udelay(10); | 372 | udelay(10); |
372 | tmp = snd_ca0106_ptr_read(emu, reg, 0); | 373 | tmp = snd_ca0106_ptr_read(emu, reg, 0); |
373 | if (!(tmp & 0x10000)) { | 374 | if (!(tmp & 0x10000)) { |
374 | result = 0; | 375 | result = 0; |
375 | break; | 376 | break; |
376 | } | 377 | } |
377 | } | 378 | } |
378 | if (result) /* Timed out */ | 379 | if (result) /* Timed out */ |
379 | return 1; | 380 | return 1; |
380 | snd_ca0106_ptr_write(emu, reg, 0, reset | data); | 381 | snd_ca0106_ptr_write(emu, reg, 0, reset | data); |
381 | tmp = snd_ca0106_ptr_read(emu, reg, 0); /* Write post */ | 382 | tmp = snd_ca0106_ptr_read(emu, reg, 0); /* Write post */ |
382 | return 0; | 383 | return 0; |
383 | } | 384 | } |
384 | 385 | ||
385 | /* The ADC does not support i2c read, so only write is implemented */ | 386 | /* The ADC does not support i2c read, so only write is implemented */ |
386 | int snd_ca0106_i2c_write(struct snd_ca0106 *emu, | 387 | int snd_ca0106_i2c_write(struct snd_ca0106 *emu, |
387 | u32 reg, | 388 | u32 reg, |
388 | u32 value) | 389 | u32 value) |
389 | { | 390 | { |
390 | u32 tmp; | 391 | u32 tmp; |
391 | int timeout = 0; | 392 | int timeout = 0; |
392 | int status; | 393 | int status; |
393 | int retry; | 394 | int retry; |
394 | if ((reg > 0x7f) || (value > 0x1ff)) { | 395 | if ((reg > 0x7f) || (value > 0x1ff)) { |
395 | snd_printk(KERN_ERR "i2c_write: invalid values.\n"); | 396 | snd_printk(KERN_ERR "i2c_write: invalid values.\n"); |
396 | return -EINVAL; | 397 | return -EINVAL; |
397 | } | 398 | } |
398 | 399 | ||
399 | tmp = reg << 25 | value << 16; | 400 | tmp = reg << 25 | value << 16; |
400 | // snd_printk("I2C-write:reg=0x%x, value=0x%x\n", reg, value); | 401 | // snd_printk("I2C-write:reg=0x%x, value=0x%x\n", reg, value); |
401 | /* Not sure what this I2C channel controls. */ | 402 | /* Not sure what this I2C channel controls. */ |
402 | /* snd_ca0106_ptr_write(emu, I2C_D0, 0, tmp); */ | 403 | /* snd_ca0106_ptr_write(emu, I2C_D0, 0, tmp); */ |
403 | 404 | ||
404 | /* This controls the I2C connected to the WM8775 ADC Codec */ | 405 | /* This controls the I2C connected to the WM8775 ADC Codec */ |
405 | snd_ca0106_ptr_write(emu, I2C_D1, 0, tmp); | 406 | snd_ca0106_ptr_write(emu, I2C_D1, 0, tmp); |
406 | 407 | ||
407 | for (retry = 0; retry < 10; retry++) { | 408 | for (retry = 0; retry < 10; retry++) { |
408 | /* Send the data to i2c */ | 409 | /* Send the data to i2c */ |
409 | //tmp = snd_ca0106_ptr_read(emu, I2C_A, 0); | 410 | //tmp = snd_ca0106_ptr_read(emu, I2C_A, 0); |
410 | //tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK); | 411 | //tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK); |
411 | tmp = 0; | 412 | tmp = 0; |
412 | tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD); | 413 | tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD); |
413 | snd_ca0106_ptr_write(emu, I2C_A, 0, tmp); | 414 | snd_ca0106_ptr_write(emu, I2C_A, 0, tmp); |
414 | 415 | ||
415 | /* Wait till the transaction ends */ | 416 | /* Wait till the transaction ends */ |
416 | while (1) { | 417 | while (1) { |
417 | status = snd_ca0106_ptr_read(emu, I2C_A, 0); | 418 | status = snd_ca0106_ptr_read(emu, I2C_A, 0); |
418 | //snd_printk("I2C:status=0x%x\n", status); | 419 | //snd_printk("I2C:status=0x%x\n", status); |
419 | timeout++; | 420 | timeout++; |
420 | if ((status & I2C_A_ADC_START) == 0) | 421 | if ((status & I2C_A_ADC_START) == 0) |
421 | break; | 422 | break; |
422 | 423 | ||
423 | if (timeout > 1000) | 424 | if (timeout > 1000) |
424 | break; | 425 | break; |
425 | } | 426 | } |
426 | //Read back and see if the transaction is successful | 427 | //Read back and see if the transaction is successful |
427 | if ((status & I2C_A_ADC_ABORT) == 0) | 428 | if ((status & I2C_A_ADC_ABORT) == 0) |
428 | break; | 429 | break; |
429 | } | 430 | } |
430 | 431 | ||
431 | if (retry == 10) { | 432 | if (retry == 10) { |
432 | snd_printk(KERN_ERR "Writing to ADC failed!\n"); | 433 | snd_printk(KERN_ERR "Writing to ADC failed!\n"); |
433 | return -EINVAL; | 434 | return -EINVAL; |
434 | } | 435 | } |
435 | 436 | ||
436 | return 0; | 437 | return 0; |
437 | } | 438 | } |
438 | 439 | ||
439 | 440 | ||
440 | static void snd_ca0106_intr_enable(struct snd_ca0106 *emu, unsigned int intrenb) | 441 | static void snd_ca0106_intr_enable(struct snd_ca0106 *emu, unsigned int intrenb) |
441 | { | 442 | { |
442 | unsigned long flags; | 443 | unsigned long flags; |
443 | unsigned int intr_enable; | 444 | unsigned int intr_enable; |
444 | 445 | ||
445 | spin_lock_irqsave(&emu->emu_lock, flags); | 446 | spin_lock_irqsave(&emu->emu_lock, flags); |
446 | intr_enable = inl(emu->port + INTE) | intrenb; | 447 | intr_enable = inl(emu->port + INTE) | intrenb; |
447 | outl(intr_enable, emu->port + INTE); | 448 | outl(intr_enable, emu->port + INTE); |
448 | spin_unlock_irqrestore(&emu->emu_lock, flags); | 449 | spin_unlock_irqrestore(&emu->emu_lock, flags); |
449 | } | 450 | } |
450 | 451 | ||
451 | static void snd_ca0106_intr_disable(struct snd_ca0106 *emu, unsigned int intrenb) | 452 | static void snd_ca0106_intr_disable(struct snd_ca0106 *emu, unsigned int intrenb) |
452 | { | 453 | { |
453 | unsigned long flags; | 454 | unsigned long flags; |
454 | unsigned int intr_enable; | 455 | unsigned int intr_enable; |
455 | 456 | ||
456 | spin_lock_irqsave(&emu->emu_lock, flags); | 457 | spin_lock_irqsave(&emu->emu_lock, flags); |
457 | intr_enable = inl(emu->port + INTE) & ~intrenb; | 458 | intr_enable = inl(emu->port + INTE) & ~intrenb; |
458 | outl(intr_enable, emu->port + INTE); | 459 | outl(intr_enable, emu->port + INTE); |
459 | spin_unlock_irqrestore(&emu->emu_lock, flags); | 460 | spin_unlock_irqrestore(&emu->emu_lock, flags); |
460 | } | 461 | } |
461 | 462 | ||
462 | 463 | ||
463 | static void snd_ca0106_pcm_free_substream(struct snd_pcm_runtime *runtime) | 464 | static void snd_ca0106_pcm_free_substream(struct snd_pcm_runtime *runtime) |
464 | { | 465 | { |
465 | kfree(runtime->private_data); | 466 | kfree(runtime->private_data); |
466 | } | 467 | } |
467 | 468 | ||
468 | static const int spi_dacd_reg[] = { | 469 | static const int spi_dacd_reg[] = { |
469 | [PCM_FRONT_CHANNEL] = SPI_DACD4_REG, | 470 | [PCM_FRONT_CHANNEL] = SPI_DACD4_REG, |
470 | [PCM_REAR_CHANNEL] = SPI_DACD0_REG, | 471 | [PCM_REAR_CHANNEL] = SPI_DACD0_REG, |
471 | [PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_REG, | 472 | [PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_REG, |
472 | [PCM_UNKNOWN_CHANNEL] = SPI_DACD1_REG, | 473 | [PCM_UNKNOWN_CHANNEL] = SPI_DACD1_REG, |
473 | }; | 474 | }; |
474 | static const int spi_dacd_bit[] = { | 475 | static const int spi_dacd_bit[] = { |
475 | [PCM_FRONT_CHANNEL] = SPI_DACD4_BIT, | 476 | [PCM_FRONT_CHANNEL] = SPI_DACD4_BIT, |
476 | [PCM_REAR_CHANNEL] = SPI_DACD0_BIT, | 477 | [PCM_REAR_CHANNEL] = SPI_DACD0_BIT, |
477 | [PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_BIT, | 478 | [PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_BIT, |
478 | [PCM_UNKNOWN_CHANNEL] = SPI_DACD1_BIT, | 479 | [PCM_UNKNOWN_CHANNEL] = SPI_DACD1_BIT, |
479 | }; | 480 | }; |
480 | 481 | ||
481 | /* open_playback callback */ | 482 | /* open_playback callback */ |
482 | static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substream, | 483 | static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substream, |
483 | int channel_id) | 484 | int channel_id) |
484 | { | 485 | { |
485 | struct snd_ca0106 *chip = snd_pcm_substream_chip(substream); | 486 | struct snd_ca0106 *chip = snd_pcm_substream_chip(substream); |
486 | struct snd_ca0106_channel *channel = &(chip->playback_channels[channel_id]); | 487 | struct snd_ca0106_channel *channel = &(chip->playback_channels[channel_id]); |
487 | struct snd_ca0106_pcm *epcm; | 488 | struct snd_ca0106_pcm *epcm; |
488 | struct snd_pcm_runtime *runtime = substream->runtime; | 489 | struct snd_pcm_runtime *runtime = substream->runtime; |
489 | int err; | 490 | int err; |
490 | 491 | ||
491 | epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); | 492 | epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); |
492 | 493 | ||
493 | if (epcm == NULL) | 494 | if (epcm == NULL) |
494 | return -ENOMEM; | 495 | return -ENOMEM; |
495 | epcm->emu = chip; | 496 | epcm->emu = chip; |
496 | epcm->substream = substream; | 497 | epcm->substream = substream; |
497 | epcm->channel_id=channel_id; | 498 | epcm->channel_id=channel_id; |
498 | 499 | ||
499 | runtime->private_data = epcm; | 500 | runtime->private_data = epcm; |
500 | runtime->private_free = snd_ca0106_pcm_free_substream; | 501 | runtime->private_free = snd_ca0106_pcm_free_substream; |
501 | 502 | ||
502 | runtime->hw = snd_ca0106_playback_hw; | 503 | runtime->hw = snd_ca0106_playback_hw; |
503 | 504 | ||
504 | channel->emu = chip; | 505 | channel->emu = chip; |
505 | channel->number = channel_id; | 506 | channel->number = channel_id; |
506 | 507 | ||
507 | channel->use = 1; | 508 | channel->use = 1; |
508 | //printk("open:channel_id=%d, chip=%p, channel=%p\n",channel_id, chip, channel); | 509 | //printk("open:channel_id=%d, chip=%p, channel=%p\n",channel_id, chip, channel); |
509 | //channel->interrupt = snd_ca0106_pcm_channel_interrupt; | 510 | //channel->interrupt = snd_ca0106_pcm_channel_interrupt; |
510 | channel->epcm = epcm; | 511 | channel->epcm = epcm; |
511 | if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) | 512 | if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) |
512 | return err; | 513 | return err; |
513 | if ((err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64)) < 0) | 514 | if ((err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64)) < 0) |
514 | return err; | 515 | return err; |
515 | snd_pcm_set_sync(substream); | 516 | snd_pcm_set_sync(substream); |
516 | 517 | ||
517 | if (chip->details->spi_dac && channel_id != PCM_FRONT_CHANNEL) { | 518 | if (chip->details->spi_dac && channel_id != PCM_FRONT_CHANNEL) { |
518 | const int reg = spi_dacd_reg[channel_id]; | 519 | const int reg = spi_dacd_reg[channel_id]; |
519 | 520 | ||
520 | /* Power up dac */ | 521 | /* Power up dac */ |
521 | chip->spi_dac_reg[reg] &= ~spi_dacd_bit[channel_id]; | 522 | chip->spi_dac_reg[reg] &= ~spi_dacd_bit[channel_id]; |
522 | err = snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]); | 523 | err = snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]); |
523 | if (err < 0) | 524 | if (err < 0) |
524 | return err; | 525 | return err; |
525 | } | 526 | } |
526 | return 0; | 527 | return 0; |
527 | } | 528 | } |
528 | 529 | ||
529 | /* close callback */ | 530 | /* close callback */ |
530 | static int snd_ca0106_pcm_close_playback(struct snd_pcm_substream *substream) | 531 | static int snd_ca0106_pcm_close_playback(struct snd_pcm_substream *substream) |
531 | { | 532 | { |
532 | struct snd_ca0106 *chip = snd_pcm_substream_chip(substream); | 533 | struct snd_ca0106 *chip = snd_pcm_substream_chip(substream); |
533 | struct snd_pcm_runtime *runtime = substream->runtime; | 534 | struct snd_pcm_runtime *runtime = substream->runtime; |
534 | struct snd_ca0106_pcm *epcm = runtime->private_data; | 535 | struct snd_ca0106_pcm *epcm = runtime->private_data; |
535 | chip->playback_channels[epcm->channel_id].use = 0; | 536 | chip->playback_channels[epcm->channel_id].use = 0; |
536 | 537 | ||
537 | if (chip->details->spi_dac && epcm->channel_id != PCM_FRONT_CHANNEL) { | 538 | if (chip->details->spi_dac && epcm->channel_id != PCM_FRONT_CHANNEL) { |
538 | const int reg = spi_dacd_reg[epcm->channel_id]; | 539 | const int reg = spi_dacd_reg[epcm->channel_id]; |
539 | 540 | ||
540 | /* Power down DAC */ | 541 | /* Power down DAC */ |
541 | chip->spi_dac_reg[reg] |= spi_dacd_bit[epcm->channel_id]; | 542 | chip->spi_dac_reg[reg] |= spi_dacd_bit[epcm->channel_id]; |
542 | snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]); | 543 | snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]); |
543 | } | 544 | } |
544 | /* FIXME: maybe zero others */ | 545 | /* FIXME: maybe zero others */ |
545 | return 0; | 546 | return 0; |
546 | } | 547 | } |
547 | 548 | ||
548 | static int snd_ca0106_pcm_open_playback_front(struct snd_pcm_substream *substream) | 549 | static int snd_ca0106_pcm_open_playback_front(struct snd_pcm_substream *substream) |
549 | { | 550 | { |
550 | return snd_ca0106_pcm_open_playback_channel(substream, PCM_FRONT_CHANNEL); | 551 | return snd_ca0106_pcm_open_playback_channel(substream, PCM_FRONT_CHANNEL); |
551 | } | 552 | } |
552 | 553 | ||
553 | static int snd_ca0106_pcm_open_playback_center_lfe(struct snd_pcm_substream *substream) | 554 | static int snd_ca0106_pcm_open_playback_center_lfe(struct snd_pcm_substream *substream) |
554 | { | 555 | { |
555 | return snd_ca0106_pcm_open_playback_channel(substream, PCM_CENTER_LFE_CHANNEL); | 556 | return snd_ca0106_pcm_open_playback_channel(substream, PCM_CENTER_LFE_CHANNEL); |
556 | } | 557 | } |
557 | 558 | ||
558 | static int snd_ca0106_pcm_open_playback_unknown(struct snd_pcm_substream *substream) | 559 | static int snd_ca0106_pcm_open_playback_unknown(struct snd_pcm_substream *substream) |
559 | { | 560 | { |
560 | return snd_ca0106_pcm_open_playback_channel(substream, PCM_UNKNOWN_CHANNEL); | 561 | return snd_ca0106_pcm_open_playback_channel(substream, PCM_UNKNOWN_CHANNEL); |
561 | } | 562 | } |
562 | 563 | ||
563 | static int snd_ca0106_pcm_open_playback_rear(struct snd_pcm_substream *substream) | 564 | static int snd_ca0106_pcm_open_playback_rear(struct snd_pcm_substream *substream) |
564 | { | 565 | { |
565 | return snd_ca0106_pcm_open_playback_channel(substream, PCM_REAR_CHANNEL); | 566 | return snd_ca0106_pcm_open_playback_channel(substream, PCM_REAR_CHANNEL); |
566 | } | 567 | } |
567 | 568 | ||
568 | /* open_capture callback */ | 569 | /* open_capture callback */ |
569 | static int snd_ca0106_pcm_open_capture_channel(struct snd_pcm_substream *substream, | 570 | static int snd_ca0106_pcm_open_capture_channel(struct snd_pcm_substream *substream, |
570 | int channel_id) | 571 | int channel_id) |
571 | { | 572 | { |
572 | struct snd_ca0106 *chip = snd_pcm_substream_chip(substream); | 573 | struct snd_ca0106 *chip = snd_pcm_substream_chip(substream); |
573 | struct snd_ca0106_channel *channel = &(chip->capture_channels[channel_id]); | 574 | struct snd_ca0106_channel *channel = &(chip->capture_channels[channel_id]); |
574 | struct snd_ca0106_pcm *epcm; | 575 | struct snd_ca0106_pcm *epcm; |
575 | struct snd_pcm_runtime *runtime = substream->runtime; | 576 | struct snd_pcm_runtime *runtime = substream->runtime; |
576 | int err; | 577 | int err; |
577 | 578 | ||
578 | epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); | 579 | epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); |
579 | if (epcm == NULL) { | 580 | if (epcm == NULL) { |
580 | snd_printk(KERN_ERR "open_capture_channel: failed epcm alloc\n"); | 581 | snd_printk(KERN_ERR "open_capture_channel: failed epcm alloc\n"); |
581 | return -ENOMEM; | 582 | return -ENOMEM; |
582 | } | 583 | } |
583 | epcm->emu = chip; | 584 | epcm->emu = chip; |
584 | epcm->substream = substream; | 585 | epcm->substream = substream; |
585 | epcm->channel_id=channel_id; | 586 | epcm->channel_id=channel_id; |
586 | 587 | ||
587 | runtime->private_data = epcm; | 588 | runtime->private_data = epcm; |
588 | runtime->private_free = snd_ca0106_pcm_free_substream; | 589 | runtime->private_free = snd_ca0106_pcm_free_substream; |
589 | 590 | ||
590 | runtime->hw = snd_ca0106_capture_hw; | 591 | runtime->hw = snd_ca0106_capture_hw; |
591 | 592 | ||
592 | channel->emu = chip; | 593 | channel->emu = chip; |
593 | channel->number = channel_id; | 594 | channel->number = channel_id; |
594 | 595 | ||
595 | channel->use = 1; | 596 | channel->use = 1; |
596 | //printk("open:channel_id=%d, chip=%p, channel=%p\n",channel_id, chip, channel); | 597 | //printk("open:channel_id=%d, chip=%p, channel=%p\n",channel_id, chip, channel); |
597 | //channel->interrupt = snd_ca0106_pcm_channel_interrupt; | 598 | //channel->interrupt = snd_ca0106_pcm_channel_interrupt; |
598 | channel->epcm = epcm; | 599 | channel->epcm = epcm; |
599 | if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) | 600 | if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) |
600 | return err; | 601 | return err; |
601 | //snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hw_constraints_capture_period_sizes); | 602 | //snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hw_constraints_capture_period_sizes); |
602 | if ((err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64)) < 0) | 603 | if ((err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64)) < 0) |
603 | return err; | 604 | return err; |
604 | return 0; | 605 | return 0; |
605 | } | 606 | } |
606 | 607 | ||
607 | /* close callback */ | 608 | /* close callback */ |
608 | static int snd_ca0106_pcm_close_capture(struct snd_pcm_substream *substream) | 609 | static int snd_ca0106_pcm_close_capture(struct snd_pcm_substream *substream) |
609 | { | 610 | { |
610 | struct snd_ca0106 *chip = snd_pcm_substream_chip(substream); | 611 | struct snd_ca0106 *chip = snd_pcm_substream_chip(substream); |
611 | struct snd_pcm_runtime *runtime = substream->runtime; | 612 | struct snd_pcm_runtime *runtime = substream->runtime; |
612 | struct snd_ca0106_pcm *epcm = runtime->private_data; | 613 | struct snd_ca0106_pcm *epcm = runtime->private_data; |
613 | chip->capture_channels[epcm->channel_id].use = 0; | 614 | chip->capture_channels[epcm->channel_id].use = 0; |
614 | /* FIXME: maybe zero others */ | 615 | /* FIXME: maybe zero others */ |
615 | return 0; | 616 | return 0; |
616 | } | 617 | } |
617 | 618 | ||
618 | static int snd_ca0106_pcm_open_0_capture(struct snd_pcm_substream *substream) | 619 | static int snd_ca0106_pcm_open_0_capture(struct snd_pcm_substream *substream) |
619 | { | 620 | { |
620 | return snd_ca0106_pcm_open_capture_channel(substream, 0); | 621 | return snd_ca0106_pcm_open_capture_channel(substream, 0); |
621 | } | 622 | } |
622 | 623 | ||
623 | static int snd_ca0106_pcm_open_1_capture(struct snd_pcm_substream *substream) | 624 | static int snd_ca0106_pcm_open_1_capture(struct snd_pcm_substream *substream) |
624 | { | 625 | { |
625 | return snd_ca0106_pcm_open_capture_channel(substream, 1); | 626 | return snd_ca0106_pcm_open_capture_channel(substream, 1); |
626 | } | 627 | } |
627 | 628 | ||
628 | static int snd_ca0106_pcm_open_2_capture(struct snd_pcm_substream *substream) | 629 | static int snd_ca0106_pcm_open_2_capture(struct snd_pcm_substream *substream) |
629 | { | 630 | { |
630 | return snd_ca0106_pcm_open_capture_channel(substream, 2); | 631 | return snd_ca0106_pcm_open_capture_channel(substream, 2); |
631 | } | 632 | } |
632 | 633 | ||
633 | static int snd_ca0106_pcm_open_3_capture(struct snd_pcm_substream *substream) | 634 | static int snd_ca0106_pcm_open_3_capture(struct snd_pcm_substream *substream) |
634 | { | 635 | { |
635 | return snd_ca0106_pcm_open_capture_channel(substream, 3); | 636 | return snd_ca0106_pcm_open_capture_channel(substream, 3); |
636 | } | 637 | } |
637 | 638 | ||
638 | /* hw_params callback */ | 639 | /* hw_params callback */ |
639 | static int snd_ca0106_pcm_hw_params_playback(struct snd_pcm_substream *substream, | 640 | static int snd_ca0106_pcm_hw_params_playback(struct snd_pcm_substream *substream, |
640 | struct snd_pcm_hw_params *hw_params) | 641 | struct snd_pcm_hw_params *hw_params) |
641 | { | 642 | { |
642 | return snd_pcm_lib_malloc_pages(substream, | 643 | return snd_pcm_lib_malloc_pages(substream, |
643 | params_buffer_bytes(hw_params)); | 644 | params_buffer_bytes(hw_params)); |
644 | } | 645 | } |
645 | 646 | ||
646 | /* hw_free callback */ | 647 | /* hw_free callback */ |
647 | static int snd_ca0106_pcm_hw_free_playback(struct snd_pcm_substream *substream) | 648 | static int snd_ca0106_pcm_hw_free_playback(struct snd_pcm_substream *substream) |
648 | { | 649 | { |
649 | return snd_pcm_lib_free_pages(substream); | 650 | return snd_pcm_lib_free_pages(substream); |
650 | } | 651 | } |
651 | 652 | ||
652 | /* hw_params callback */ | 653 | /* hw_params callback */ |
653 | static int snd_ca0106_pcm_hw_params_capture(struct snd_pcm_substream *substream, | 654 | static int snd_ca0106_pcm_hw_params_capture(struct snd_pcm_substream *substream, |
654 | struct snd_pcm_hw_params *hw_params) | 655 | struct snd_pcm_hw_params *hw_params) |
655 | { | 656 | { |
656 | return snd_pcm_lib_malloc_pages(substream, | 657 | return snd_pcm_lib_malloc_pages(substream, |
657 | params_buffer_bytes(hw_params)); | 658 | params_buffer_bytes(hw_params)); |
658 | } | 659 | } |
659 | 660 | ||
660 | /* hw_free callback */ | 661 | /* hw_free callback */ |
661 | static int snd_ca0106_pcm_hw_free_capture(struct snd_pcm_substream *substream) | 662 | static int snd_ca0106_pcm_hw_free_capture(struct snd_pcm_substream *substream) |
662 | { | 663 | { |
663 | return snd_pcm_lib_free_pages(substream); | 664 | return snd_pcm_lib_free_pages(substream); |
664 | } | 665 | } |
665 | 666 | ||
666 | /* prepare playback callback */ | 667 | /* prepare playback callback */ |
667 | static int snd_ca0106_pcm_prepare_playback(struct snd_pcm_substream *substream) | 668 | static int snd_ca0106_pcm_prepare_playback(struct snd_pcm_substream *substream) |
668 | { | 669 | { |
669 | struct snd_ca0106 *emu = snd_pcm_substream_chip(substream); | 670 | struct snd_ca0106 *emu = snd_pcm_substream_chip(substream); |
670 | struct snd_pcm_runtime *runtime = substream->runtime; | 671 | struct snd_pcm_runtime *runtime = substream->runtime; |
671 | struct snd_ca0106_pcm *epcm = runtime->private_data; | 672 | struct snd_ca0106_pcm *epcm = runtime->private_data; |
672 | int channel = epcm->channel_id; | 673 | int channel = epcm->channel_id; |
673 | u32 *table_base = (u32 *)(emu->buffer.area+(8*16*channel)); | 674 | u32 *table_base = (u32 *)(emu->buffer.area+(8*16*channel)); |
674 | u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size); | 675 | u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size); |
675 | u32 hcfg_mask = HCFG_PLAYBACK_S32_LE; | 676 | u32 hcfg_mask = HCFG_PLAYBACK_S32_LE; |
676 | u32 hcfg_set = 0x00000000; | 677 | u32 hcfg_set = 0x00000000; |
677 | u32 hcfg; | 678 | u32 hcfg; |
678 | u32 reg40_mask = 0x30000 << (channel<<1); | 679 | u32 reg40_mask = 0x30000 << (channel<<1); |
679 | u32 reg40_set = 0; | 680 | u32 reg40_set = 0; |
680 | u32 reg40; | 681 | u32 reg40; |
681 | /* FIXME: Depending on mixer selection of SPDIF out or not, select the spdif rate or the DAC rate. */ | 682 | /* FIXME: Depending on mixer selection of SPDIF out or not, select the spdif rate or the DAC rate. */ |
682 | u32 reg71_mask = 0x03030000 ; /* Global. Set SPDIF rate. We only support 44100 to spdif, not to DAC. */ | 683 | u32 reg71_mask = 0x03030000 ; /* Global. Set SPDIF rate. We only support 44100 to spdif, not to DAC. */ |
683 | u32 reg71_set = 0; | 684 | u32 reg71_set = 0; |
684 | u32 reg71; | 685 | u32 reg71; |
685 | int i; | 686 | int i; |
686 | 687 | ||
687 | //snd_printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, periods=%u, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, runtime->periods, frames_to_bytes(runtime, 1)); | 688 | //snd_printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, periods=%u, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, runtime->periods, frames_to_bytes(runtime, 1)); |
688 | //snd_printk("dma_addr=%x, dma_area=%p, table_base=%p\n",runtime->dma_addr, runtime->dma_area, table_base); | 689 | //snd_printk("dma_addr=%x, dma_area=%p, table_base=%p\n",runtime->dma_addr, runtime->dma_area, table_base); |
689 | //snd_printk("dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",emu->buffer.addr, emu->buffer.area, emu->buffer.bytes); | 690 | //snd_printk("dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",emu->buffer.addr, emu->buffer.area, emu->buffer.bytes); |
690 | /* Rate can be set per channel. */ | 691 | /* Rate can be set per channel. */ |
691 | /* reg40 control host to fifo */ | 692 | /* reg40 control host to fifo */ |
692 | /* reg71 controls DAC rate. */ | 693 | /* reg71 controls DAC rate. */ |
693 | switch (runtime->rate) { | 694 | switch (runtime->rate) { |
694 | case 44100: | 695 | case 44100: |
695 | reg40_set = 0x10000 << (channel<<1); | 696 | reg40_set = 0x10000 << (channel<<1); |
696 | reg71_set = 0x01010000; | 697 | reg71_set = 0x01010000; |
697 | break; | 698 | break; |
698 | case 48000: | 699 | case 48000: |
699 | reg40_set = 0; | 700 | reg40_set = 0; |
700 | reg71_set = 0; | 701 | reg71_set = 0; |
701 | break; | 702 | break; |
702 | case 96000: | 703 | case 96000: |
703 | reg40_set = 0x20000 << (channel<<1); | 704 | reg40_set = 0x20000 << (channel<<1); |
704 | reg71_set = 0x02020000; | 705 | reg71_set = 0x02020000; |
705 | break; | 706 | break; |
706 | case 192000: | 707 | case 192000: |
707 | reg40_set = 0x30000 << (channel<<1); | 708 | reg40_set = 0x30000 << (channel<<1); |
708 | reg71_set = 0x03030000; | 709 | reg71_set = 0x03030000; |
709 | break; | 710 | break; |
710 | default: | 711 | default: |
711 | reg40_set = 0; | 712 | reg40_set = 0; |
712 | reg71_set = 0; | 713 | reg71_set = 0; |
713 | break; | 714 | break; |
714 | } | 715 | } |
715 | /* Format is a global setting */ | 716 | /* Format is a global setting */ |
716 | /* FIXME: Only let the first channel accessed set this. */ | 717 | /* FIXME: Only let the first channel accessed set this. */ |
717 | switch (runtime->format) { | 718 | switch (runtime->format) { |
718 | case SNDRV_PCM_FORMAT_S16_LE: | 719 | case SNDRV_PCM_FORMAT_S16_LE: |
719 | hcfg_set = 0; | 720 | hcfg_set = 0; |
720 | break; | 721 | break; |
721 | case SNDRV_PCM_FORMAT_S32_LE: | 722 | case SNDRV_PCM_FORMAT_S32_LE: |
722 | hcfg_set = HCFG_PLAYBACK_S32_LE; | 723 | hcfg_set = HCFG_PLAYBACK_S32_LE; |
723 | break; | 724 | break; |
724 | default: | 725 | default: |
725 | hcfg_set = 0; | 726 | hcfg_set = 0; |
726 | break; | 727 | break; |
727 | } | 728 | } |
728 | hcfg = inl(emu->port + HCFG) ; | 729 | hcfg = inl(emu->port + HCFG) ; |
729 | hcfg = (hcfg & ~hcfg_mask) | hcfg_set; | 730 | hcfg = (hcfg & ~hcfg_mask) | hcfg_set; |
730 | outl(hcfg, emu->port + HCFG); | 731 | outl(hcfg, emu->port + HCFG); |
731 | reg40 = snd_ca0106_ptr_read(emu, 0x40, 0); | 732 | reg40 = snd_ca0106_ptr_read(emu, 0x40, 0); |
732 | reg40 = (reg40 & ~reg40_mask) | reg40_set; | 733 | reg40 = (reg40 & ~reg40_mask) | reg40_set; |
733 | snd_ca0106_ptr_write(emu, 0x40, 0, reg40); | 734 | snd_ca0106_ptr_write(emu, 0x40, 0, reg40); |
734 | reg71 = snd_ca0106_ptr_read(emu, 0x71, 0); | 735 | reg71 = snd_ca0106_ptr_read(emu, 0x71, 0); |
735 | reg71 = (reg71 & ~reg71_mask) | reg71_set; | 736 | reg71 = (reg71 & ~reg71_mask) | reg71_set; |
736 | snd_ca0106_ptr_write(emu, 0x71, 0, reg71); | 737 | snd_ca0106_ptr_write(emu, 0x71, 0, reg71); |
737 | 738 | ||
738 | /* FIXME: Check emu->buffer.size before actually writing to it. */ | 739 | /* FIXME: Check emu->buffer.size before actually writing to it. */ |
739 | for(i=0; i < runtime->periods; i++) { | 740 | for(i=0; i < runtime->periods; i++) { |
740 | table_base[i*2] = runtime->dma_addr + (i * period_size_bytes); | 741 | table_base[i*2] = runtime->dma_addr + (i * period_size_bytes); |
741 | table_base[i*2+1] = period_size_bytes << 16; | 742 | table_base[i*2+1] = period_size_bytes << 16; |
742 | } | 743 | } |
743 | 744 | ||
744 | snd_ca0106_ptr_write(emu, PLAYBACK_LIST_ADDR, channel, emu->buffer.addr+(8*16*channel)); | 745 | snd_ca0106_ptr_write(emu, PLAYBACK_LIST_ADDR, channel, emu->buffer.addr+(8*16*channel)); |
745 | snd_ca0106_ptr_write(emu, PLAYBACK_LIST_SIZE, channel, (runtime->periods - 1) << 19); | 746 | snd_ca0106_ptr_write(emu, PLAYBACK_LIST_SIZE, channel, (runtime->periods - 1) << 19); |
746 | snd_ca0106_ptr_write(emu, PLAYBACK_LIST_PTR, channel, 0); | 747 | snd_ca0106_ptr_write(emu, PLAYBACK_LIST_PTR, channel, 0); |
747 | snd_ca0106_ptr_write(emu, PLAYBACK_DMA_ADDR, channel, runtime->dma_addr); | 748 | snd_ca0106_ptr_write(emu, PLAYBACK_DMA_ADDR, channel, runtime->dma_addr); |
748 | snd_ca0106_ptr_write(emu, PLAYBACK_PERIOD_SIZE, channel, frames_to_bytes(runtime, runtime->period_size)<<16); // buffer size in bytes | 749 | snd_ca0106_ptr_write(emu, PLAYBACK_PERIOD_SIZE, channel, frames_to_bytes(runtime, runtime->period_size)<<16); // buffer size in bytes |
749 | /* FIXME test what 0 bytes does. */ | 750 | /* FIXME test what 0 bytes does. */ |
750 | snd_ca0106_ptr_write(emu, PLAYBACK_PERIOD_SIZE, channel, 0); // buffer size in bytes | 751 | snd_ca0106_ptr_write(emu, PLAYBACK_PERIOD_SIZE, channel, 0); // buffer size in bytes |
751 | snd_ca0106_ptr_write(emu, PLAYBACK_POINTER, channel, 0); | 752 | snd_ca0106_ptr_write(emu, PLAYBACK_POINTER, channel, 0); |
752 | snd_ca0106_ptr_write(emu, 0x07, channel, 0x0); | 753 | snd_ca0106_ptr_write(emu, 0x07, channel, 0x0); |
753 | snd_ca0106_ptr_write(emu, 0x08, channel, 0); | 754 | snd_ca0106_ptr_write(emu, 0x08, channel, 0); |
754 | snd_ca0106_ptr_write(emu, PLAYBACK_MUTE, 0x0, 0x0); /* Unmute output */ | 755 | snd_ca0106_ptr_write(emu, PLAYBACK_MUTE, 0x0, 0x0); /* Unmute output */ |
755 | #if 0 | 756 | #if 0 |
756 | snd_ca0106_ptr_write(emu, SPCS0, 0, | 757 | snd_ca0106_ptr_write(emu, SPCS0, 0, |
757 | SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | | 758 | SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | |
758 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | | 759 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | |
759 | SPCS_GENERATIONSTATUS | 0x00001200 | | 760 | SPCS_GENERATIONSTATUS | 0x00001200 | |
760 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT ); | 761 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT ); |
761 | } | 762 | } |
762 | #endif | 763 | #endif |
763 | 764 | ||
764 | return 0; | 765 | return 0; |
765 | } | 766 | } |
766 | 767 | ||
767 | /* prepare capture callback */ | 768 | /* prepare capture callback */ |
768 | static int snd_ca0106_pcm_prepare_capture(struct snd_pcm_substream *substream) | 769 | static int snd_ca0106_pcm_prepare_capture(struct snd_pcm_substream *substream) |
769 | { | 770 | { |
770 | struct snd_ca0106 *emu = snd_pcm_substream_chip(substream); | 771 | struct snd_ca0106 *emu = snd_pcm_substream_chip(substream); |
771 | struct snd_pcm_runtime *runtime = substream->runtime; | 772 | struct snd_pcm_runtime *runtime = substream->runtime; |
772 | struct snd_ca0106_pcm *epcm = runtime->private_data; | 773 | struct snd_ca0106_pcm *epcm = runtime->private_data; |
773 | int channel = epcm->channel_id; | 774 | int channel = epcm->channel_id; |
774 | u32 hcfg_mask = HCFG_CAPTURE_S32_LE; | 775 | u32 hcfg_mask = HCFG_CAPTURE_S32_LE; |
775 | u32 hcfg_set = 0x00000000; | 776 | u32 hcfg_set = 0x00000000; |
776 | u32 hcfg; | 777 | u32 hcfg; |
777 | u32 over_sampling=0x2; | 778 | u32 over_sampling=0x2; |
778 | u32 reg71_mask = 0x0000c000 ; /* Global. Set ADC rate. */ | 779 | u32 reg71_mask = 0x0000c000 ; /* Global. Set ADC rate. */ |
779 | u32 reg71_set = 0; | 780 | u32 reg71_set = 0; |
780 | u32 reg71; | 781 | u32 reg71; |
781 | 782 | ||
782 | //snd_printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, periods=%u, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, runtime->periods, frames_to_bytes(runtime, 1)); | 783 | //snd_printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, periods=%u, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, runtime->periods, frames_to_bytes(runtime, 1)); |
783 | //snd_printk("dma_addr=%x, dma_area=%p, table_base=%p\n",runtime->dma_addr, runtime->dma_area, table_base); | 784 | //snd_printk("dma_addr=%x, dma_area=%p, table_base=%p\n",runtime->dma_addr, runtime->dma_area, table_base); |
784 | //snd_printk("dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",emu->buffer.addr, emu->buffer.area, emu->buffer.bytes); | 785 | //snd_printk("dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",emu->buffer.addr, emu->buffer.area, emu->buffer.bytes); |
785 | /* reg71 controls ADC rate. */ | 786 | /* reg71 controls ADC rate. */ |
786 | switch (runtime->rate) { | 787 | switch (runtime->rate) { |
787 | case 44100: | 788 | case 44100: |
788 | reg71_set = 0x00004000; | 789 | reg71_set = 0x00004000; |
789 | break; | 790 | break; |
790 | case 48000: | 791 | case 48000: |
791 | reg71_set = 0; | 792 | reg71_set = 0; |
792 | break; | 793 | break; |
793 | case 96000: | 794 | case 96000: |
794 | reg71_set = 0x00008000; | 795 | reg71_set = 0x00008000; |
795 | over_sampling=0xa; | 796 | over_sampling=0xa; |
796 | break; | 797 | break; |
797 | case 192000: | 798 | case 192000: |
798 | reg71_set = 0x0000c000; | 799 | reg71_set = 0x0000c000; |
799 | over_sampling=0xa; | 800 | over_sampling=0xa; |
800 | break; | 801 | break; |
801 | default: | 802 | default: |
802 | reg71_set = 0; | 803 | reg71_set = 0; |
803 | break; | 804 | break; |
804 | } | 805 | } |
805 | /* Format is a global setting */ | 806 | /* Format is a global setting */ |
806 | /* FIXME: Only let the first channel accessed set this. */ | 807 | /* FIXME: Only let the first channel accessed set this. */ |
807 | switch (runtime->format) { | 808 | switch (runtime->format) { |
808 | case SNDRV_PCM_FORMAT_S16_LE: | 809 | case SNDRV_PCM_FORMAT_S16_LE: |
809 | hcfg_set = 0; | 810 | hcfg_set = 0; |
810 | break; | 811 | break; |
811 | case SNDRV_PCM_FORMAT_S32_LE: | 812 | case SNDRV_PCM_FORMAT_S32_LE: |
812 | hcfg_set = HCFG_CAPTURE_S32_LE; | 813 | hcfg_set = HCFG_CAPTURE_S32_LE; |
813 | break; | 814 | break; |
814 | default: | 815 | default: |
815 | hcfg_set = 0; | 816 | hcfg_set = 0; |
816 | break; | 817 | break; |
817 | } | 818 | } |
818 | hcfg = inl(emu->port + HCFG) ; | 819 | hcfg = inl(emu->port + HCFG) ; |
819 | hcfg = (hcfg & ~hcfg_mask) | hcfg_set; | 820 | hcfg = (hcfg & ~hcfg_mask) | hcfg_set; |
820 | outl(hcfg, emu->port + HCFG); | 821 | outl(hcfg, emu->port + HCFG); |
821 | reg71 = snd_ca0106_ptr_read(emu, 0x71, 0); | 822 | reg71 = snd_ca0106_ptr_read(emu, 0x71, 0); |
822 | reg71 = (reg71 & ~reg71_mask) | reg71_set; | 823 | reg71 = (reg71 & ~reg71_mask) | reg71_set; |
823 | snd_ca0106_ptr_write(emu, 0x71, 0, reg71); | 824 | snd_ca0106_ptr_write(emu, 0x71, 0, reg71); |
824 | if (emu->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */ | 825 | if (emu->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */ |
825 | snd_ca0106_i2c_write(emu, ADC_MASTER, over_sampling); /* Adjust the over sampler to better suit the capture rate. */ | 826 | snd_ca0106_i2c_write(emu, ADC_MASTER, over_sampling); /* Adjust the over sampler to better suit the capture rate. */ |
826 | } | 827 | } |
827 | 828 | ||
828 | 829 | ||
829 | //printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, frames_to_bytes(runtime, 1)); | 830 | //printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, frames_to_bytes(runtime, 1)); |
830 | snd_ca0106_ptr_write(emu, 0x13, channel, 0); | 831 | snd_ca0106_ptr_write(emu, 0x13, channel, 0); |
831 | snd_ca0106_ptr_write(emu, CAPTURE_DMA_ADDR, channel, runtime->dma_addr); | 832 | snd_ca0106_ptr_write(emu, CAPTURE_DMA_ADDR, channel, runtime->dma_addr); |
832 | snd_ca0106_ptr_write(emu, CAPTURE_BUFFER_SIZE, channel, frames_to_bytes(runtime, runtime->buffer_size)<<16); // buffer size in bytes | 833 | snd_ca0106_ptr_write(emu, CAPTURE_BUFFER_SIZE, channel, frames_to_bytes(runtime, runtime->buffer_size)<<16); // buffer size in bytes |
833 | snd_ca0106_ptr_write(emu, CAPTURE_POINTER, channel, 0); | 834 | snd_ca0106_ptr_write(emu, CAPTURE_POINTER, channel, 0); |
834 | 835 | ||
835 | return 0; | 836 | return 0; |
836 | } | 837 | } |
837 | 838 | ||
838 | /* trigger_playback callback */ | 839 | /* trigger_playback callback */ |
839 | static int snd_ca0106_pcm_trigger_playback(struct snd_pcm_substream *substream, | 840 | static int snd_ca0106_pcm_trigger_playback(struct snd_pcm_substream *substream, |
840 | int cmd) | 841 | int cmd) |
841 | { | 842 | { |
842 | struct snd_ca0106 *emu = snd_pcm_substream_chip(substream); | 843 | struct snd_ca0106 *emu = snd_pcm_substream_chip(substream); |
843 | struct snd_pcm_runtime *runtime; | 844 | struct snd_pcm_runtime *runtime; |
844 | struct snd_ca0106_pcm *epcm; | 845 | struct snd_ca0106_pcm *epcm; |
845 | int channel; | 846 | int channel; |
846 | int result = 0; | 847 | int result = 0; |
847 | struct snd_pcm_substream *s; | 848 | struct snd_pcm_substream *s; |
848 | u32 basic = 0; | 849 | u32 basic = 0; |
849 | u32 extended = 0; | 850 | u32 extended = 0; |
850 | int running=0; | 851 | int running=0; |
851 | 852 | ||
852 | switch (cmd) { | 853 | switch (cmd) { |
853 | case SNDRV_PCM_TRIGGER_START: | 854 | case SNDRV_PCM_TRIGGER_START: |
854 | running=1; | 855 | running=1; |
855 | break; | 856 | break; |
856 | case SNDRV_PCM_TRIGGER_STOP: | 857 | case SNDRV_PCM_TRIGGER_STOP: |
857 | default: | 858 | default: |
858 | running=0; | 859 | running=0; |
859 | break; | 860 | break; |
860 | } | 861 | } |
861 | snd_pcm_group_for_each_entry(s, substream) { | 862 | snd_pcm_group_for_each_entry(s, substream) { |
862 | if (snd_pcm_substream_chip(s) != emu || | 863 | if (snd_pcm_substream_chip(s) != emu || |
863 | s->stream != SNDRV_PCM_STREAM_PLAYBACK) | 864 | s->stream != SNDRV_PCM_STREAM_PLAYBACK) |
864 | continue; | 865 | continue; |
865 | runtime = s->runtime; | 866 | runtime = s->runtime; |
866 | epcm = runtime->private_data; | 867 | epcm = runtime->private_data; |
867 | channel = epcm->channel_id; | 868 | channel = epcm->channel_id; |
868 | //snd_printk("channel=%d\n",channel); | 869 | //snd_printk("channel=%d\n",channel); |
869 | epcm->running = running; | 870 | epcm->running = running; |
870 | basic |= (0x1<<channel); | 871 | basic |= (0x1<<channel); |
871 | extended |= (0x10<<channel); | 872 | extended |= (0x10<<channel); |
872 | snd_pcm_trigger_done(s, substream); | 873 | snd_pcm_trigger_done(s, substream); |
873 | } | 874 | } |
874 | //snd_printk("basic=0x%x, extended=0x%x\n",basic, extended); | 875 | //snd_printk("basic=0x%x, extended=0x%x\n",basic, extended); |
875 | 876 | ||
876 | switch (cmd) { | 877 | switch (cmd) { |
877 | case SNDRV_PCM_TRIGGER_START: | 878 | case SNDRV_PCM_TRIGGER_START: |
878 | snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0) | (extended)); | 879 | snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0) | (extended)); |
879 | snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0)|(basic)); | 880 | snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0)|(basic)); |
880 | break; | 881 | break; |
881 | case SNDRV_PCM_TRIGGER_STOP: | 882 | case SNDRV_PCM_TRIGGER_STOP: |
882 | snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0) & ~(basic)); | 883 | snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0) & ~(basic)); |
883 | snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0) & ~(extended)); | 884 | snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0) & ~(extended)); |
884 | break; | 885 | break; |
885 | default: | 886 | default: |
886 | result = -EINVAL; | 887 | result = -EINVAL; |
887 | break; | 888 | break; |
888 | } | 889 | } |
889 | return result; | 890 | return result; |
890 | } | 891 | } |
891 | 892 | ||
892 | /* trigger_capture callback */ | 893 | /* trigger_capture callback */ |
893 | static int snd_ca0106_pcm_trigger_capture(struct snd_pcm_substream *substream, | 894 | static int snd_ca0106_pcm_trigger_capture(struct snd_pcm_substream *substream, |
894 | int cmd) | 895 | int cmd) |
895 | { | 896 | { |
896 | struct snd_ca0106 *emu = snd_pcm_substream_chip(substream); | 897 | struct snd_ca0106 *emu = snd_pcm_substream_chip(substream); |
897 | struct snd_pcm_runtime *runtime = substream->runtime; | 898 | struct snd_pcm_runtime *runtime = substream->runtime; |
898 | struct snd_ca0106_pcm *epcm = runtime->private_data; | 899 | struct snd_ca0106_pcm *epcm = runtime->private_data; |
899 | int channel = epcm->channel_id; | 900 | int channel = epcm->channel_id; |
900 | int result = 0; | 901 | int result = 0; |
901 | 902 | ||
902 | switch (cmd) { | 903 | switch (cmd) { |
903 | case SNDRV_PCM_TRIGGER_START: | 904 | case SNDRV_PCM_TRIGGER_START: |
904 | snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0) | (0x110000<<channel)); | 905 | snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0) | (0x110000<<channel)); |
905 | snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0)|(0x100<<channel)); | 906 | snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0)|(0x100<<channel)); |
906 | epcm->running = 1; | 907 | epcm->running = 1; |
907 | break; | 908 | break; |
908 | case SNDRV_PCM_TRIGGER_STOP: | 909 | case SNDRV_PCM_TRIGGER_STOP: |
909 | snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0) & ~(0x100<<channel)); | 910 | snd_ca0106_ptr_write(emu, BASIC_INTERRUPT, 0, snd_ca0106_ptr_read(emu, BASIC_INTERRUPT, 0) & ~(0x100<<channel)); |
910 | snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0) & ~(0x110000<<channel)); | 911 | snd_ca0106_ptr_write(emu, EXTENDED_INT_MASK, 0, snd_ca0106_ptr_read(emu, EXTENDED_INT_MASK, 0) & ~(0x110000<<channel)); |
911 | epcm->running = 0; | 912 | epcm->running = 0; |
912 | break; | 913 | break; |
913 | default: | 914 | default: |
914 | result = -EINVAL; | 915 | result = -EINVAL; |
915 | break; | 916 | break; |
916 | } | 917 | } |
917 | return result; | 918 | return result; |
918 | } | 919 | } |
919 | 920 | ||
920 | /* pointer_playback callback */ | 921 | /* pointer_playback callback */ |
921 | static snd_pcm_uframes_t | 922 | static snd_pcm_uframes_t |
922 | snd_ca0106_pcm_pointer_playback(struct snd_pcm_substream *substream) | 923 | snd_ca0106_pcm_pointer_playback(struct snd_pcm_substream *substream) |
923 | { | 924 | { |
924 | struct snd_ca0106 *emu = snd_pcm_substream_chip(substream); | 925 | struct snd_ca0106 *emu = snd_pcm_substream_chip(substream); |
925 | struct snd_pcm_runtime *runtime = substream->runtime; | 926 | struct snd_pcm_runtime *runtime = substream->runtime; |
926 | struct snd_ca0106_pcm *epcm = runtime->private_data; | 927 | struct snd_ca0106_pcm *epcm = runtime->private_data; |
927 | snd_pcm_uframes_t ptr, ptr1, ptr2,ptr3,ptr4 = 0; | 928 | snd_pcm_uframes_t ptr, ptr1, ptr2,ptr3,ptr4 = 0; |
928 | int channel = epcm->channel_id; | 929 | int channel = epcm->channel_id; |
929 | 930 | ||
930 | if (!epcm->running) | 931 | if (!epcm->running) |
931 | return 0; | 932 | return 0; |
932 | 933 | ||
933 | ptr3 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel); | 934 | ptr3 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel); |
934 | ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel); | 935 | ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel); |
935 | ptr4 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel); | 936 | ptr4 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel); |
936 | if (ptr3 != ptr4) ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel); | 937 | if (ptr3 != ptr4) ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel); |
937 | ptr2 = bytes_to_frames(runtime, ptr1); | 938 | ptr2 = bytes_to_frames(runtime, ptr1); |
938 | ptr2+= (ptr4 >> 3) * runtime->period_size; | 939 | ptr2+= (ptr4 >> 3) * runtime->period_size; |
939 | ptr=ptr2; | 940 | ptr=ptr2; |
940 | if (ptr >= runtime->buffer_size) | 941 | if (ptr >= runtime->buffer_size) |
941 | ptr -= runtime->buffer_size; | 942 | ptr -= runtime->buffer_size; |
942 | //printk("ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n", ptr1, ptr2, ptr, (int)runtime->buffer_size, (int)runtime->period_size, (int)runtime->frame_bits, (int)runtime->rate); | 943 | //printk("ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n", ptr1, ptr2, ptr, (int)runtime->buffer_size, (int)runtime->period_size, (int)runtime->frame_bits, (int)runtime->rate); |
943 | 944 | ||
944 | return ptr; | 945 | return ptr; |
945 | } | 946 | } |
946 | 947 | ||
947 | /* pointer_capture callback */ | 948 | /* pointer_capture callback */ |
948 | static snd_pcm_uframes_t | 949 | static snd_pcm_uframes_t |
949 | snd_ca0106_pcm_pointer_capture(struct snd_pcm_substream *substream) | 950 | snd_ca0106_pcm_pointer_capture(struct snd_pcm_substream *substream) |
950 | { | 951 | { |
951 | struct snd_ca0106 *emu = snd_pcm_substream_chip(substream); | 952 | struct snd_ca0106 *emu = snd_pcm_substream_chip(substream); |
952 | struct snd_pcm_runtime *runtime = substream->runtime; | 953 | struct snd_pcm_runtime *runtime = substream->runtime; |
953 | struct snd_ca0106_pcm *epcm = runtime->private_data; | 954 | struct snd_ca0106_pcm *epcm = runtime->private_data; |
954 | snd_pcm_uframes_t ptr, ptr1, ptr2 = 0; | 955 | snd_pcm_uframes_t ptr, ptr1, ptr2 = 0; |
955 | int channel = channel=epcm->channel_id; | 956 | int channel = channel=epcm->channel_id; |
956 | 957 | ||
957 | if (!epcm->running) | 958 | if (!epcm->running) |
958 | return 0; | 959 | return 0; |
959 | 960 | ||
960 | ptr1 = snd_ca0106_ptr_read(emu, CAPTURE_POINTER, channel); | 961 | ptr1 = snd_ca0106_ptr_read(emu, CAPTURE_POINTER, channel); |
961 | ptr2 = bytes_to_frames(runtime, ptr1); | 962 | ptr2 = bytes_to_frames(runtime, ptr1); |
962 | ptr=ptr2; | 963 | ptr=ptr2; |
963 | if (ptr >= runtime->buffer_size) | 964 | if (ptr >= runtime->buffer_size) |
964 | ptr -= runtime->buffer_size; | 965 | ptr -= runtime->buffer_size; |
965 | //printk("ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n", ptr1, ptr2, ptr, (int)runtime->buffer_size, (int)runtime->period_size, (int)runtime->frame_bits, (int)runtime->rate); | 966 | //printk("ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n", ptr1, ptr2, ptr, (int)runtime->buffer_size, (int)runtime->period_size, (int)runtime->frame_bits, (int)runtime->rate); |
966 | 967 | ||
967 | return ptr; | 968 | return ptr; |
968 | } | 969 | } |
969 | 970 | ||
970 | /* operators */ | 971 | /* operators */ |
971 | static struct snd_pcm_ops snd_ca0106_playback_front_ops = { | 972 | static struct snd_pcm_ops snd_ca0106_playback_front_ops = { |
972 | .open = snd_ca0106_pcm_open_playback_front, | 973 | .open = snd_ca0106_pcm_open_playback_front, |
973 | .close = snd_ca0106_pcm_close_playback, | 974 | .close = snd_ca0106_pcm_close_playback, |
974 | .ioctl = snd_pcm_lib_ioctl, | 975 | .ioctl = snd_pcm_lib_ioctl, |
975 | .hw_params = snd_ca0106_pcm_hw_params_playback, | 976 | .hw_params = snd_ca0106_pcm_hw_params_playback, |
976 | .hw_free = snd_ca0106_pcm_hw_free_playback, | 977 | .hw_free = snd_ca0106_pcm_hw_free_playback, |
977 | .prepare = snd_ca0106_pcm_prepare_playback, | 978 | .prepare = snd_ca0106_pcm_prepare_playback, |
978 | .trigger = snd_ca0106_pcm_trigger_playback, | 979 | .trigger = snd_ca0106_pcm_trigger_playback, |
979 | .pointer = snd_ca0106_pcm_pointer_playback, | 980 | .pointer = snd_ca0106_pcm_pointer_playback, |
980 | }; | 981 | }; |
981 | 982 | ||
982 | static struct snd_pcm_ops snd_ca0106_capture_0_ops = { | 983 | static struct snd_pcm_ops snd_ca0106_capture_0_ops = { |
983 | .open = snd_ca0106_pcm_open_0_capture, | 984 | .open = snd_ca0106_pcm_open_0_capture, |
984 | .close = snd_ca0106_pcm_close_capture, | 985 | .close = snd_ca0106_pcm_close_capture, |
985 | .ioctl = snd_pcm_lib_ioctl, | 986 | .ioctl = snd_pcm_lib_ioctl, |
986 | .hw_params = snd_ca0106_pcm_hw_params_capture, | 987 | .hw_params = snd_ca0106_pcm_hw_params_capture, |
987 | .hw_free = snd_ca0106_pcm_hw_free_capture, | 988 | .hw_free = snd_ca0106_pcm_hw_free_capture, |
988 | .prepare = snd_ca0106_pcm_prepare_capture, | 989 | .prepare = snd_ca0106_pcm_prepare_capture, |
989 | .trigger = snd_ca0106_pcm_trigger_capture, | 990 | .trigger = snd_ca0106_pcm_trigger_capture, |
990 | .pointer = snd_ca0106_pcm_pointer_capture, | 991 | .pointer = snd_ca0106_pcm_pointer_capture, |
991 | }; | 992 | }; |
992 | 993 | ||
993 | static struct snd_pcm_ops snd_ca0106_capture_1_ops = { | 994 | static struct snd_pcm_ops snd_ca0106_capture_1_ops = { |
994 | .open = snd_ca0106_pcm_open_1_capture, | 995 | .open = snd_ca0106_pcm_open_1_capture, |
995 | .close = snd_ca0106_pcm_close_capture, | 996 | .close = snd_ca0106_pcm_close_capture, |
996 | .ioctl = snd_pcm_lib_ioctl, | 997 | .ioctl = snd_pcm_lib_ioctl, |
997 | .hw_params = snd_ca0106_pcm_hw_params_capture, | 998 | .hw_params = snd_ca0106_pcm_hw_params_capture, |
998 | .hw_free = snd_ca0106_pcm_hw_free_capture, | 999 | .hw_free = snd_ca0106_pcm_hw_free_capture, |
999 | .prepare = snd_ca0106_pcm_prepare_capture, | 1000 | .prepare = snd_ca0106_pcm_prepare_capture, |
1000 | .trigger = snd_ca0106_pcm_trigger_capture, | 1001 | .trigger = snd_ca0106_pcm_trigger_capture, |
1001 | .pointer = snd_ca0106_pcm_pointer_capture, | 1002 | .pointer = snd_ca0106_pcm_pointer_capture, |
1002 | }; | 1003 | }; |
1003 | 1004 | ||
1004 | static struct snd_pcm_ops snd_ca0106_capture_2_ops = { | 1005 | static struct snd_pcm_ops snd_ca0106_capture_2_ops = { |
1005 | .open = snd_ca0106_pcm_open_2_capture, | 1006 | .open = snd_ca0106_pcm_open_2_capture, |
1006 | .close = snd_ca0106_pcm_close_capture, | 1007 | .close = snd_ca0106_pcm_close_capture, |
1007 | .ioctl = snd_pcm_lib_ioctl, | 1008 | .ioctl = snd_pcm_lib_ioctl, |
1008 | .hw_params = snd_ca0106_pcm_hw_params_capture, | 1009 | .hw_params = snd_ca0106_pcm_hw_params_capture, |
1009 | .hw_free = snd_ca0106_pcm_hw_free_capture, | 1010 | .hw_free = snd_ca0106_pcm_hw_free_capture, |
1010 | .prepare = snd_ca0106_pcm_prepare_capture, | 1011 | .prepare = snd_ca0106_pcm_prepare_capture, |
1011 | .trigger = snd_ca0106_pcm_trigger_capture, | 1012 | .trigger = snd_ca0106_pcm_trigger_capture, |
1012 | .pointer = snd_ca0106_pcm_pointer_capture, | 1013 | .pointer = snd_ca0106_pcm_pointer_capture, |
1013 | }; | 1014 | }; |
1014 | 1015 | ||
1015 | static struct snd_pcm_ops snd_ca0106_capture_3_ops = { | 1016 | static struct snd_pcm_ops snd_ca0106_capture_3_ops = { |
1016 | .open = snd_ca0106_pcm_open_3_capture, | 1017 | .open = snd_ca0106_pcm_open_3_capture, |
1017 | .close = snd_ca0106_pcm_close_capture, | 1018 | .close = snd_ca0106_pcm_close_capture, |
1018 | .ioctl = snd_pcm_lib_ioctl, | 1019 | .ioctl = snd_pcm_lib_ioctl, |
1019 | .hw_params = snd_ca0106_pcm_hw_params_capture, | 1020 | .hw_params = snd_ca0106_pcm_hw_params_capture, |
1020 | .hw_free = snd_ca0106_pcm_hw_free_capture, | 1021 | .hw_free = snd_ca0106_pcm_hw_free_capture, |
1021 | .prepare = snd_ca0106_pcm_prepare_capture, | 1022 | .prepare = snd_ca0106_pcm_prepare_capture, |
1022 | .trigger = snd_ca0106_pcm_trigger_capture, | 1023 | .trigger = snd_ca0106_pcm_trigger_capture, |
1023 | .pointer = snd_ca0106_pcm_pointer_capture, | 1024 | .pointer = snd_ca0106_pcm_pointer_capture, |
1024 | }; | 1025 | }; |
1025 | 1026 | ||
1026 | static struct snd_pcm_ops snd_ca0106_playback_center_lfe_ops = { | 1027 | static struct snd_pcm_ops snd_ca0106_playback_center_lfe_ops = { |
1027 | .open = snd_ca0106_pcm_open_playback_center_lfe, | 1028 | .open = snd_ca0106_pcm_open_playback_center_lfe, |
1028 | .close = snd_ca0106_pcm_close_playback, | 1029 | .close = snd_ca0106_pcm_close_playback, |
1029 | .ioctl = snd_pcm_lib_ioctl, | 1030 | .ioctl = snd_pcm_lib_ioctl, |
1030 | .hw_params = snd_ca0106_pcm_hw_params_playback, | 1031 | .hw_params = snd_ca0106_pcm_hw_params_playback, |
1031 | .hw_free = snd_ca0106_pcm_hw_free_playback, | 1032 | .hw_free = snd_ca0106_pcm_hw_free_playback, |
1032 | .prepare = snd_ca0106_pcm_prepare_playback, | 1033 | .prepare = snd_ca0106_pcm_prepare_playback, |
1033 | .trigger = snd_ca0106_pcm_trigger_playback, | 1034 | .trigger = snd_ca0106_pcm_trigger_playback, |
1034 | .pointer = snd_ca0106_pcm_pointer_playback, | 1035 | .pointer = snd_ca0106_pcm_pointer_playback, |
1035 | }; | 1036 | }; |
1036 | 1037 | ||
1037 | static struct snd_pcm_ops snd_ca0106_playback_unknown_ops = { | 1038 | static struct snd_pcm_ops snd_ca0106_playback_unknown_ops = { |
1038 | .open = snd_ca0106_pcm_open_playback_unknown, | 1039 | .open = snd_ca0106_pcm_open_playback_unknown, |
1039 | .close = snd_ca0106_pcm_close_playback, | 1040 | .close = snd_ca0106_pcm_close_playback, |
1040 | .ioctl = snd_pcm_lib_ioctl, | 1041 | .ioctl = snd_pcm_lib_ioctl, |
1041 | .hw_params = snd_ca0106_pcm_hw_params_playback, | 1042 | .hw_params = snd_ca0106_pcm_hw_params_playback, |
1042 | .hw_free = snd_ca0106_pcm_hw_free_playback, | 1043 | .hw_free = snd_ca0106_pcm_hw_free_playback, |
1043 | .prepare = snd_ca0106_pcm_prepare_playback, | 1044 | .prepare = snd_ca0106_pcm_prepare_playback, |
1044 | .trigger = snd_ca0106_pcm_trigger_playback, | 1045 | .trigger = snd_ca0106_pcm_trigger_playback, |
1045 | .pointer = snd_ca0106_pcm_pointer_playback, | 1046 | .pointer = snd_ca0106_pcm_pointer_playback, |
1046 | }; | 1047 | }; |
1047 | 1048 | ||
1048 | static struct snd_pcm_ops snd_ca0106_playback_rear_ops = { | 1049 | static struct snd_pcm_ops snd_ca0106_playback_rear_ops = { |
1049 | .open = snd_ca0106_pcm_open_playback_rear, | 1050 | .open = snd_ca0106_pcm_open_playback_rear, |
1050 | .close = snd_ca0106_pcm_close_playback, | 1051 | .close = snd_ca0106_pcm_close_playback, |
1051 | .ioctl = snd_pcm_lib_ioctl, | 1052 | .ioctl = snd_pcm_lib_ioctl, |
1052 | .hw_params = snd_ca0106_pcm_hw_params_playback, | 1053 | .hw_params = snd_ca0106_pcm_hw_params_playback, |
1053 | .hw_free = snd_ca0106_pcm_hw_free_playback, | 1054 | .hw_free = snd_ca0106_pcm_hw_free_playback, |
1054 | .prepare = snd_ca0106_pcm_prepare_playback, | 1055 | .prepare = snd_ca0106_pcm_prepare_playback, |
1055 | .trigger = snd_ca0106_pcm_trigger_playback, | 1056 | .trigger = snd_ca0106_pcm_trigger_playback, |
1056 | .pointer = snd_ca0106_pcm_pointer_playback, | 1057 | .pointer = snd_ca0106_pcm_pointer_playback, |
1057 | }; | 1058 | }; |
1058 | 1059 | ||
1059 | 1060 | ||
1060 | static unsigned short snd_ca0106_ac97_read(struct snd_ac97 *ac97, | 1061 | static unsigned short snd_ca0106_ac97_read(struct snd_ac97 *ac97, |
1061 | unsigned short reg) | 1062 | unsigned short reg) |
1062 | { | 1063 | { |
1063 | struct snd_ca0106 *emu = ac97->private_data; | 1064 | struct snd_ca0106 *emu = ac97->private_data; |
1064 | unsigned long flags; | 1065 | unsigned long flags; |
1065 | unsigned short val; | 1066 | unsigned short val; |
1066 | 1067 | ||
1067 | spin_lock_irqsave(&emu->emu_lock, flags); | 1068 | spin_lock_irqsave(&emu->emu_lock, flags); |
1068 | outb(reg, emu->port + AC97ADDRESS); | 1069 | outb(reg, emu->port + AC97ADDRESS); |
1069 | val = inw(emu->port + AC97DATA); | 1070 | val = inw(emu->port + AC97DATA); |
1070 | spin_unlock_irqrestore(&emu->emu_lock, flags); | 1071 | spin_unlock_irqrestore(&emu->emu_lock, flags); |
1071 | return val; | 1072 | return val; |
1072 | } | 1073 | } |
1073 | 1074 | ||
1074 | static void snd_ca0106_ac97_write(struct snd_ac97 *ac97, | 1075 | static void snd_ca0106_ac97_write(struct snd_ac97 *ac97, |
1075 | unsigned short reg, unsigned short val) | 1076 | unsigned short reg, unsigned short val) |
1076 | { | 1077 | { |
1077 | struct snd_ca0106 *emu = ac97->private_data; | 1078 | struct snd_ca0106 *emu = ac97->private_data; |
1078 | unsigned long flags; | 1079 | unsigned long flags; |
1079 | 1080 | ||
1080 | spin_lock_irqsave(&emu->emu_lock, flags); | 1081 | spin_lock_irqsave(&emu->emu_lock, flags); |
1081 | outb(reg, emu->port + AC97ADDRESS); | 1082 | outb(reg, emu->port + AC97ADDRESS); |
1082 | outw(val, emu->port + AC97DATA); | 1083 | outw(val, emu->port + AC97DATA); |
1083 | spin_unlock_irqrestore(&emu->emu_lock, flags); | 1084 | spin_unlock_irqrestore(&emu->emu_lock, flags); |
1084 | } | 1085 | } |
1085 | 1086 | ||
1086 | static int snd_ca0106_ac97(struct snd_ca0106 *chip) | 1087 | static int snd_ca0106_ac97(struct snd_ca0106 *chip) |
1087 | { | 1088 | { |
1088 | struct snd_ac97_bus *pbus; | 1089 | struct snd_ac97_bus *pbus; |
1089 | struct snd_ac97_template ac97; | 1090 | struct snd_ac97_template ac97; |
1090 | int err; | 1091 | int err; |
1091 | static struct snd_ac97_bus_ops ops = { | 1092 | static struct snd_ac97_bus_ops ops = { |
1092 | .write = snd_ca0106_ac97_write, | 1093 | .write = snd_ca0106_ac97_write, |
1093 | .read = snd_ca0106_ac97_read, | 1094 | .read = snd_ca0106_ac97_read, |
1094 | }; | 1095 | }; |
1095 | 1096 | ||
1096 | if ((err = snd_ac97_bus(chip->card, 0, &ops, NULL, &pbus)) < 0) | 1097 | if ((err = snd_ac97_bus(chip->card, 0, &ops, NULL, &pbus)) < 0) |
1097 | return err; | 1098 | return err; |
1098 | pbus->no_vra = 1; /* we don't need VRA */ | 1099 | pbus->no_vra = 1; /* we don't need VRA */ |
1099 | 1100 | ||
1100 | memset(&ac97, 0, sizeof(ac97)); | 1101 | memset(&ac97, 0, sizeof(ac97)); |
1101 | ac97.private_data = chip; | 1102 | ac97.private_data = chip; |
1102 | ac97.scaps = AC97_SCAP_NO_SPDIF; | 1103 | ac97.scaps = AC97_SCAP_NO_SPDIF; |
1103 | return snd_ac97_mixer(pbus, &ac97, &chip->ac97); | 1104 | return snd_ac97_mixer(pbus, &ac97, &chip->ac97); |
1104 | } | 1105 | } |
1105 | 1106 | ||
1106 | static int snd_ca0106_free(struct snd_ca0106 *chip) | 1107 | static int snd_ca0106_free(struct snd_ca0106 *chip) |
1107 | { | 1108 | { |
1108 | if (chip->res_port != NULL) { /* avoid access to already used hardware */ | 1109 | if (chip->res_port != NULL) { /* avoid access to already used hardware */ |
1109 | // disable interrupts | 1110 | // disable interrupts |
1110 | snd_ca0106_ptr_write(chip, BASIC_INTERRUPT, 0, 0); | 1111 | snd_ca0106_ptr_write(chip, BASIC_INTERRUPT, 0, 0); |
1111 | outl(0, chip->port + INTE); | 1112 | outl(0, chip->port + INTE); |
1112 | snd_ca0106_ptr_write(chip, EXTENDED_INT_MASK, 0, 0); | 1113 | snd_ca0106_ptr_write(chip, EXTENDED_INT_MASK, 0, 0); |
1113 | udelay(1000); | 1114 | udelay(1000); |
1114 | // disable audio | 1115 | // disable audio |
1115 | //outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG); | 1116 | //outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG); |
1116 | outl(0, chip->port + HCFG); | 1117 | outl(0, chip->port + HCFG); |
1117 | /* FIXME: We need to stop and DMA transfers here. | 1118 | /* FIXME: We need to stop and DMA transfers here. |
1118 | * But as I am not sure how yet, we cannot from the dma pages. | 1119 | * But as I am not sure how yet, we cannot from the dma pages. |
1119 | * So we can fix: snd-malloc: Memory leak? pages not freed = 8 | 1120 | * So we can fix: snd-malloc: Memory leak? pages not freed = 8 |
1120 | */ | 1121 | */ |
1121 | } | 1122 | } |
1122 | if (chip->irq >= 0) | 1123 | if (chip->irq >= 0) |
1123 | free_irq(chip->irq, chip); | 1124 | free_irq(chip->irq, chip); |
1124 | // release the data | 1125 | // release the data |
1125 | #if 1 | 1126 | #if 1 |
1126 | if (chip->buffer.area) | 1127 | if (chip->buffer.area) |
1127 | snd_dma_free_pages(&chip->buffer); | 1128 | snd_dma_free_pages(&chip->buffer); |
1128 | #endif | 1129 | #endif |
1129 | 1130 | ||
1130 | // release the i/o port | 1131 | // release the i/o port |
1131 | release_and_free_resource(chip->res_port); | 1132 | release_and_free_resource(chip->res_port); |
1132 | 1133 | ||
1133 | pci_disable_device(chip->pci); | 1134 | pci_disable_device(chip->pci); |
1134 | kfree(chip); | 1135 | kfree(chip); |
1135 | return 0; | 1136 | return 0; |
1136 | } | 1137 | } |
1137 | 1138 | ||
1138 | static int snd_ca0106_dev_free(struct snd_device *device) | 1139 | static int snd_ca0106_dev_free(struct snd_device *device) |
1139 | { | 1140 | { |
1140 | struct snd_ca0106 *chip = device->device_data; | 1141 | struct snd_ca0106 *chip = device->device_data; |
1141 | return snd_ca0106_free(chip); | 1142 | return snd_ca0106_free(chip); |
1142 | } | 1143 | } |
1143 | 1144 | ||
1144 | static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id) | 1145 | static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id) |
1145 | { | 1146 | { |
1146 | unsigned int status; | 1147 | unsigned int status; |
1147 | 1148 | ||
1148 | struct snd_ca0106 *chip = dev_id; | 1149 | struct snd_ca0106 *chip = dev_id; |
1149 | int i; | 1150 | int i; |
1150 | int mask; | 1151 | int mask; |
1151 | unsigned int stat76; | 1152 | unsigned int stat76; |
1152 | struct snd_ca0106_channel *pchannel; | 1153 | struct snd_ca0106_channel *pchannel; |
1153 | 1154 | ||
1154 | status = inl(chip->port + IPR); | 1155 | status = inl(chip->port + IPR); |
1155 | if (! status) | 1156 | if (! status) |
1156 | return IRQ_NONE; | 1157 | return IRQ_NONE; |
1157 | 1158 | ||
1158 | stat76 = snd_ca0106_ptr_read(chip, EXTENDED_INT, 0); | 1159 | stat76 = snd_ca0106_ptr_read(chip, EXTENDED_INT, 0); |
1159 | //snd_printk("interrupt status = 0x%08x, stat76=0x%08x\n", status, stat76); | 1160 | //snd_printk("interrupt status = 0x%08x, stat76=0x%08x\n", status, stat76); |
1160 | //snd_printk("ptr=0x%08x\n",snd_ca0106_ptr_read(chip, PLAYBACK_POINTER, 0)); | 1161 | //snd_printk("ptr=0x%08x\n",snd_ca0106_ptr_read(chip, PLAYBACK_POINTER, 0)); |
1161 | mask = 0x11; /* 0x1 for one half, 0x10 for the other half period. */ | 1162 | mask = 0x11; /* 0x1 for one half, 0x10 for the other half period. */ |
1162 | for(i = 0; i < 4; i++) { | 1163 | for(i = 0; i < 4; i++) { |
1163 | pchannel = &(chip->playback_channels[i]); | 1164 | pchannel = &(chip->playback_channels[i]); |
1164 | if (stat76 & mask) { | 1165 | if (stat76 & mask) { |
1165 | /* FIXME: Select the correct substream for period elapsed */ | 1166 | /* FIXME: Select the correct substream for period elapsed */ |
1166 | if(pchannel->use) { | 1167 | if(pchannel->use) { |
1167 | snd_pcm_period_elapsed(pchannel->epcm->substream); | 1168 | snd_pcm_period_elapsed(pchannel->epcm->substream); |
1168 | //printk(KERN_INFO "interrupt [%d] used\n", i); | 1169 | //printk(KERN_INFO "interrupt [%d] used\n", i); |
1169 | } | 1170 | } |
1170 | } | 1171 | } |
1171 | //printk(KERN_INFO "channel=%p\n",pchannel); | 1172 | //printk(KERN_INFO "channel=%p\n",pchannel); |
1172 | //printk(KERN_INFO "interrupt stat76[%d] = %08x, use=%d, channel=%d\n", i, stat76, pchannel->use, pchannel->number); | 1173 | //printk(KERN_INFO "interrupt stat76[%d] = %08x, use=%d, channel=%d\n", i, stat76, pchannel->use, pchannel->number); |
1173 | mask <<= 1; | 1174 | mask <<= 1; |
1174 | } | 1175 | } |
1175 | mask = 0x110000; /* 0x1 for one half, 0x10 for the other half period. */ | 1176 | mask = 0x110000; /* 0x1 for one half, 0x10 for the other half period. */ |
1176 | for(i = 0; i < 4; i++) { | 1177 | for(i = 0; i < 4; i++) { |
1177 | pchannel = &(chip->capture_channels[i]); | 1178 | pchannel = &(chip->capture_channels[i]); |
1178 | if (stat76 & mask) { | 1179 | if (stat76 & mask) { |
1179 | /* FIXME: Select the correct substream for period elapsed */ | 1180 | /* FIXME: Select the correct substream for period elapsed */ |
1180 | if(pchannel->use) { | 1181 | if(pchannel->use) { |
1181 | snd_pcm_period_elapsed(pchannel->epcm->substream); | 1182 | snd_pcm_period_elapsed(pchannel->epcm->substream); |
1182 | //printk(KERN_INFO "interrupt [%d] used\n", i); | 1183 | //printk(KERN_INFO "interrupt [%d] used\n", i); |
1183 | } | 1184 | } |
1184 | } | 1185 | } |
1185 | //printk(KERN_INFO "channel=%p\n",pchannel); | 1186 | //printk(KERN_INFO "channel=%p\n",pchannel); |
1186 | //printk(KERN_INFO "interrupt stat76[%d] = %08x, use=%d, channel=%d\n", i, stat76, pchannel->use, pchannel->number); | 1187 | //printk(KERN_INFO "interrupt stat76[%d] = %08x, use=%d, channel=%d\n", i, stat76, pchannel->use, pchannel->number); |
1187 | mask <<= 1; | 1188 | mask <<= 1; |
1188 | } | 1189 | } |
1189 | 1190 | ||
1190 | snd_ca0106_ptr_write(chip, EXTENDED_INT, 0, stat76); | 1191 | snd_ca0106_ptr_write(chip, EXTENDED_INT, 0, stat76); |
1191 | 1192 | ||
1192 | if (chip->midi.dev_id && | 1193 | if (chip->midi.dev_id && |
1193 | (status & (chip->midi.ipr_tx|chip->midi.ipr_rx))) { | 1194 | (status & (chip->midi.ipr_tx|chip->midi.ipr_rx))) { |
1194 | if (chip->midi.interrupt) | 1195 | if (chip->midi.interrupt) |
1195 | chip->midi.interrupt(&chip->midi, status); | 1196 | chip->midi.interrupt(&chip->midi, status); |
1196 | else | 1197 | else |
1197 | chip->midi.interrupt_disable(&chip->midi, chip->midi.tx_enable | chip->midi.rx_enable); | 1198 | chip->midi.interrupt_disable(&chip->midi, chip->midi.tx_enable | chip->midi.rx_enable); |
1198 | } | 1199 | } |
1199 | 1200 | ||
1200 | // acknowledge the interrupt if necessary | 1201 | // acknowledge the interrupt if necessary |
1201 | outl(status, chip->port+IPR); | 1202 | outl(status, chip->port+IPR); |
1202 | 1203 | ||
1203 | return IRQ_HANDLED; | 1204 | return IRQ_HANDLED; |
1204 | } | 1205 | } |
1205 | 1206 | ||
1206 | static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device, struct snd_pcm **rpcm) | 1207 | static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device, struct snd_pcm **rpcm) |
1207 | { | 1208 | { |
1208 | struct snd_pcm *pcm; | 1209 | struct snd_pcm *pcm; |
1209 | struct snd_pcm_substream *substream; | 1210 | struct snd_pcm_substream *substream; |
1210 | int err; | 1211 | int err; |
1211 | 1212 | ||
1212 | if (rpcm) | 1213 | if (rpcm) |
1213 | *rpcm = NULL; | 1214 | *rpcm = NULL; |
1214 | if ((err = snd_pcm_new(emu->card, "ca0106", device, 1, 1, &pcm)) < 0) | 1215 | if ((err = snd_pcm_new(emu->card, "ca0106", device, 1, 1, &pcm)) < 0) |
1215 | return err; | 1216 | return err; |
1216 | 1217 | ||
1217 | pcm->private_data = emu; | 1218 | pcm->private_data = emu; |
1218 | 1219 | ||
1219 | switch (device) { | 1220 | switch (device) { |
1220 | case 0: | 1221 | case 0: |
1221 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_front_ops); | 1222 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_front_ops); |
1222 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_0_ops); | 1223 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_0_ops); |
1223 | break; | 1224 | break; |
1224 | case 1: | 1225 | case 1: |
1225 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_rear_ops); | 1226 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_rear_ops); |
1226 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_1_ops); | 1227 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_1_ops); |
1227 | break; | 1228 | break; |
1228 | case 2: | 1229 | case 2: |
1229 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_center_lfe_ops); | 1230 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_center_lfe_ops); |
1230 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_2_ops); | 1231 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_2_ops); |
1231 | break; | 1232 | break; |
1232 | case 3: | 1233 | case 3: |
1233 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_unknown_ops); | 1234 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_unknown_ops); |
1234 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_3_ops); | 1235 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_3_ops); |
1235 | break; | 1236 | break; |
1236 | } | 1237 | } |
1237 | 1238 | ||
1238 | pcm->info_flags = 0; | 1239 | pcm->info_flags = 0; |
1239 | pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; | 1240 | pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; |
1240 | strcpy(pcm->name, "CA0106"); | 1241 | strcpy(pcm->name, "CA0106"); |
1241 | emu->pcm = pcm; | 1242 | emu->pcm = pcm; |
1242 | 1243 | ||
1243 | for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; | 1244 | for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; |
1244 | substream; | 1245 | substream; |
1245 | substream = substream->next) { | 1246 | substream = substream->next) { |
1246 | if ((err = snd_pcm_lib_preallocate_pages(substream, | 1247 | if ((err = snd_pcm_lib_preallocate_pages(substream, |
1247 | SNDRV_DMA_TYPE_DEV, | 1248 | SNDRV_DMA_TYPE_DEV, |
1248 | snd_dma_pci_data(emu->pci), | 1249 | snd_dma_pci_data(emu->pci), |
1249 | 64*1024, 64*1024)) < 0) /* FIXME: 32*1024 for sound buffer, between 32and64 for Periods table. */ | 1250 | 64*1024, 64*1024)) < 0) /* FIXME: 32*1024 for sound buffer, between 32and64 for Periods table. */ |
1250 | return err; | 1251 | return err; |
1251 | } | 1252 | } |
1252 | 1253 | ||
1253 | for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; | 1254 | for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; |
1254 | substream; | 1255 | substream; |
1255 | substream = substream->next) { | 1256 | substream = substream->next) { |
1256 | if ((err = snd_pcm_lib_preallocate_pages(substream, | 1257 | if ((err = snd_pcm_lib_preallocate_pages(substream, |
1257 | SNDRV_DMA_TYPE_DEV, | 1258 | SNDRV_DMA_TYPE_DEV, |
1258 | snd_dma_pci_data(emu->pci), | 1259 | snd_dma_pci_data(emu->pci), |
1259 | 64*1024, 64*1024)) < 0) | 1260 | 64*1024, 64*1024)) < 0) |
1260 | return err; | 1261 | return err; |
1261 | } | 1262 | } |
1262 | 1263 | ||
1263 | if (rpcm) | 1264 | if (rpcm) |
1264 | *rpcm = pcm; | 1265 | *rpcm = pcm; |
1265 | 1266 | ||
1266 | return 0; | 1267 | return 0; |
1267 | } | 1268 | } |
1268 | 1269 | ||
1269 | #define SPI_REG(reg, value) (((reg) << SPI_REG_SHIFT) | (value)) | 1270 | #define SPI_REG(reg, value) (((reg) << SPI_REG_SHIFT) | (value)) |
1270 | static unsigned int spi_dac_init[] = { | 1271 | static unsigned int spi_dac_init[] = { |
1271 | SPI_REG(SPI_LDA1_REG, SPI_DA_BIT_0dB), /* 0dB dig. attenuation */ | 1272 | SPI_REG(SPI_LDA1_REG, SPI_DA_BIT_0dB), /* 0dB dig. attenuation */ |
1272 | SPI_REG(SPI_RDA1_REG, SPI_DA_BIT_0dB), | 1273 | SPI_REG(SPI_RDA1_REG, SPI_DA_BIT_0dB), |
1273 | SPI_REG(SPI_PL_REG, SPI_PL_BIT_L_L | SPI_PL_BIT_R_R | SPI_IZD_BIT), | 1274 | SPI_REG(SPI_PL_REG, SPI_PL_BIT_L_L | SPI_PL_BIT_R_R | SPI_IZD_BIT), |
1274 | SPI_REG(SPI_FMT_REG, SPI_FMT_BIT_I2S | SPI_IWL_BIT_24), | 1275 | SPI_REG(SPI_FMT_REG, SPI_FMT_BIT_I2S | SPI_IWL_BIT_24), |
1275 | SPI_REG(SPI_LDA2_REG, SPI_DA_BIT_0dB), | 1276 | SPI_REG(SPI_LDA2_REG, SPI_DA_BIT_0dB), |
1276 | SPI_REG(SPI_RDA2_REG, SPI_DA_BIT_0dB), | 1277 | SPI_REG(SPI_RDA2_REG, SPI_DA_BIT_0dB), |
1277 | SPI_REG(SPI_LDA3_REG, SPI_DA_BIT_0dB), | 1278 | SPI_REG(SPI_LDA3_REG, SPI_DA_BIT_0dB), |
1278 | SPI_REG(SPI_RDA3_REG, SPI_DA_BIT_0dB), | 1279 | SPI_REG(SPI_RDA3_REG, SPI_DA_BIT_0dB), |
1279 | SPI_REG(SPI_MASTDA_REG, SPI_DA_BIT_0dB), | 1280 | SPI_REG(SPI_MASTDA_REG, SPI_DA_BIT_0dB), |
1280 | SPI_REG(9, 0x00), | 1281 | SPI_REG(9, 0x00), |
1281 | SPI_REG(SPI_MS_REG, SPI_DACD0_BIT | SPI_DACD1_BIT | SPI_DACD2_BIT), | 1282 | SPI_REG(SPI_MS_REG, SPI_DACD0_BIT | SPI_DACD1_BIT | SPI_DACD2_BIT), |
1282 | SPI_REG(12, 0x00), | 1283 | SPI_REG(12, 0x00), |
1283 | SPI_REG(SPI_LDA4_REG, SPI_DA_BIT_0dB), | 1284 | SPI_REG(SPI_LDA4_REG, SPI_DA_BIT_0dB), |
1284 | SPI_REG(SPI_RDA4_REG, SPI_DA_BIT_0dB | SPI_DA_BIT_UPDATE), | 1285 | SPI_REG(SPI_RDA4_REG, SPI_DA_BIT_0dB | SPI_DA_BIT_UPDATE), |
1285 | SPI_REG(SPI_DACD4_REG, 0x00), | 1286 | SPI_REG(SPI_DACD4_REG, 0x00), |
1286 | }; | 1287 | }; |
1287 | 1288 | ||
1288 | static unsigned int i2c_adc_init[][2] = { | 1289 | static unsigned int i2c_adc_init[][2] = { |
1289 | { 0x17, 0x00 }, /* Reset */ | 1290 | { 0x17, 0x00 }, /* Reset */ |
1290 | { 0x07, 0x00 }, /* Timeout */ | 1291 | { 0x07, 0x00 }, /* Timeout */ |
1291 | { 0x0b, 0x22 }, /* Interface control */ | 1292 | { 0x0b, 0x22 }, /* Interface control */ |
1292 | { 0x0c, 0x22 }, /* Master mode control */ | 1293 | { 0x0c, 0x22 }, /* Master mode control */ |
1293 | { 0x0d, 0x08 }, /* Powerdown control */ | 1294 | { 0x0d, 0x08 }, /* Powerdown control */ |
1294 | { 0x0e, 0xcf }, /* Attenuation Left 0x01 = -103dB, 0xff = 24dB */ | 1295 | { 0x0e, 0xcf }, /* Attenuation Left 0x01 = -103dB, 0xff = 24dB */ |
1295 | { 0x0f, 0xcf }, /* Attenuation Right 0.5dB steps */ | 1296 | { 0x0f, 0xcf }, /* Attenuation Right 0.5dB steps */ |
1296 | { 0x10, 0x7b }, /* ALC Control 1 */ | 1297 | { 0x10, 0x7b }, /* ALC Control 1 */ |
1297 | { 0x11, 0x00 }, /* ALC Control 2 */ | 1298 | { 0x11, 0x00 }, /* ALC Control 2 */ |
1298 | { 0x12, 0x32 }, /* ALC Control 3 */ | 1299 | { 0x12, 0x32 }, /* ALC Control 3 */ |
1299 | { 0x13, 0x00 }, /* Noise gate control */ | 1300 | { 0x13, 0x00 }, /* Noise gate control */ |
1300 | { 0x14, 0xa6 }, /* Limiter control */ | 1301 | { 0x14, 0xa6 }, /* Limiter control */ |
1301 | { 0x15, ADC_MUX_LINEIN }, /* ADC Mixer control */ | 1302 | { 0x15, ADC_MUX_LINEIN }, /* ADC Mixer control */ |
1302 | }; | 1303 | }; |
1303 | 1304 | ||
1304 | static int __devinit snd_ca0106_create(int dev, struct snd_card *card, | 1305 | static int __devinit snd_ca0106_create(int dev, struct snd_card *card, |
1305 | struct pci_dev *pci, | 1306 | struct pci_dev *pci, |
1306 | struct snd_ca0106 **rchip) | 1307 | struct snd_ca0106 **rchip) |
1307 | { | 1308 | { |
1308 | struct snd_ca0106 *chip; | 1309 | struct snd_ca0106 *chip; |
1309 | struct snd_ca0106_details *c; | 1310 | struct snd_ca0106_details *c; |
1310 | int err; | 1311 | int err; |
1311 | int ch; | 1312 | int ch; |
1312 | static struct snd_device_ops ops = { | 1313 | static struct snd_device_ops ops = { |
1313 | .dev_free = snd_ca0106_dev_free, | 1314 | .dev_free = snd_ca0106_dev_free, |
1314 | }; | 1315 | }; |
1315 | 1316 | ||
1316 | *rchip = NULL; | 1317 | *rchip = NULL; |
1317 | 1318 | ||
1318 | if ((err = pci_enable_device(pci)) < 0) | 1319 | if ((err = pci_enable_device(pci)) < 0) |
1319 | return err; | 1320 | return err; |
1320 | if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0 || | 1321 | if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0 || |
1321 | pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0) { | 1322 | pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0) { |
1322 | printk(KERN_ERR "error to set 32bit mask DMA\n"); | 1323 | printk(KERN_ERR "error to set 32bit mask DMA\n"); |
1323 | pci_disable_device(pci); | 1324 | pci_disable_device(pci); |
1324 | return -ENXIO; | 1325 | return -ENXIO; |
1325 | } | 1326 | } |
1326 | 1327 | ||
1327 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | 1328 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); |
1328 | if (chip == NULL) { | 1329 | if (chip == NULL) { |
1329 | pci_disable_device(pci); | 1330 | pci_disable_device(pci); |
1330 | return -ENOMEM; | 1331 | return -ENOMEM; |
1331 | } | 1332 | } |
1332 | 1333 | ||
1333 | chip->card = card; | 1334 | chip->card = card; |
1334 | chip->pci = pci; | 1335 | chip->pci = pci; |
1335 | chip->irq = -1; | 1336 | chip->irq = -1; |
1336 | 1337 | ||
1337 | spin_lock_init(&chip->emu_lock); | 1338 | spin_lock_init(&chip->emu_lock); |
1338 | 1339 | ||
1339 | chip->port = pci_resource_start(pci, 0); | 1340 | chip->port = pci_resource_start(pci, 0); |
1340 | if ((chip->res_port = request_region(chip->port, 0x20, | 1341 | if ((chip->res_port = request_region(chip->port, 0x20, |
1341 | "snd_ca0106")) == NULL) { | 1342 | "snd_ca0106")) == NULL) { |
1342 | snd_ca0106_free(chip); | 1343 | snd_ca0106_free(chip); |
1343 | printk(KERN_ERR "cannot allocate the port\n"); | 1344 | printk(KERN_ERR "cannot allocate the port\n"); |
1344 | return -EBUSY; | 1345 | return -EBUSY; |
1345 | } | 1346 | } |
1346 | 1347 | ||
1347 | if (request_irq(pci->irq, snd_ca0106_interrupt, | 1348 | if (request_irq(pci->irq, snd_ca0106_interrupt, |
1348 | IRQF_SHARED, "snd_ca0106", chip)) { | 1349 | IRQF_SHARED, "snd_ca0106", chip)) { |
1349 | snd_ca0106_free(chip); | 1350 | snd_ca0106_free(chip); |
1350 | printk(KERN_ERR "cannot grab irq\n"); | 1351 | printk(KERN_ERR "cannot grab irq\n"); |
1351 | return -EBUSY; | 1352 | return -EBUSY; |
1352 | } | 1353 | } |
1353 | chip->irq = pci->irq; | 1354 | chip->irq = pci->irq; |
1354 | 1355 | ||
1355 | /* This stores the periods table. */ | 1356 | /* This stores the periods table. */ |
1356 | if(snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), 1024, &chip->buffer) < 0) { | 1357 | if(snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), 1024, &chip->buffer) < 0) { |
1357 | snd_ca0106_free(chip); | 1358 | snd_ca0106_free(chip); |
1358 | return -ENOMEM; | 1359 | return -ENOMEM; |
1359 | } | 1360 | } |
1360 | 1361 | ||
1361 | pci_set_master(pci); | 1362 | pci_set_master(pci); |
1362 | /* read serial */ | 1363 | /* read serial */ |
1363 | pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial); | 1364 | pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial); |
1364 | pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model); | 1365 | pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model); |
1365 | #if 1 | 1366 | #if 1 |
1366 | printk(KERN_INFO "snd-ca0106: Model %04x Rev %08x Serial %08x\n", chip->model, | 1367 | printk(KERN_INFO "snd-ca0106: Model %04x Rev %08x Serial %08x\n", chip->model, |
1367 | pci->revision, chip->serial); | 1368 | pci->revision, chip->serial); |
1368 | #endif | 1369 | #endif |
1369 | strcpy(card->driver, "CA0106"); | 1370 | strcpy(card->driver, "CA0106"); |
1370 | strcpy(card->shortname, "CA0106"); | 1371 | strcpy(card->shortname, "CA0106"); |
1371 | 1372 | ||
1372 | for (c = ca0106_chip_details; c->serial; c++) { | 1373 | for (c = ca0106_chip_details; c->serial; c++) { |
1373 | if (subsystem[dev]) { | 1374 | if (subsystem[dev]) { |
1374 | if (c->serial == subsystem[dev]) | 1375 | if (c->serial == subsystem[dev]) |
1375 | break; | 1376 | break; |
1376 | } else if (c->serial == chip->serial) | 1377 | } else if (c->serial == chip->serial) |
1377 | break; | 1378 | break; |
1378 | } | 1379 | } |
1379 | chip->details = c; | 1380 | chip->details = c; |
1380 | if (subsystem[dev]) { | 1381 | if (subsystem[dev]) { |
1381 | printk(KERN_INFO "snd-ca0106: Sound card name=%s, subsystem=0x%x. Forced to subsystem=0x%x\n", | 1382 | printk(KERN_INFO "snd-ca0106: Sound card name=%s, subsystem=0x%x. Forced to subsystem=0x%x\n", |
1382 | c->name, chip->serial, subsystem[dev]); | 1383 | c->name, chip->serial, subsystem[dev]); |
1383 | } | 1384 | } |
1384 | 1385 | ||
1385 | sprintf(card->longname, "%s at 0x%lx irq %i", | 1386 | sprintf(card->longname, "%s at 0x%lx irq %i", |
1386 | c->name, chip->port, chip->irq); | 1387 | c->name, chip->port, chip->irq); |
1387 | 1388 | ||
1388 | outl(0, chip->port + INTE); | 1389 | outl(0, chip->port + INTE); |
1389 | 1390 | ||
1390 | /* | 1391 | /* |
1391 | * Init to 0x02109204 : | 1392 | * Init to 0x02109204 : |
1392 | * Clock accuracy = 0 (1000ppm) | 1393 | * Clock accuracy = 0 (1000ppm) |
1393 | * Sample Rate = 2 (48kHz) | 1394 | * Sample Rate = 2 (48kHz) |
1394 | * Audio Channel = 1 (Left of 2) | 1395 | * Audio Channel = 1 (Left of 2) |
1395 | * Source Number = 0 (Unspecified) | 1396 | * Source Number = 0 (Unspecified) |
1396 | * Generation Status = 1 (Original for Cat Code 12) | 1397 | * Generation Status = 1 (Original for Cat Code 12) |
1397 | * Cat Code = 12 (Digital Signal Mixer) | 1398 | * Cat Code = 12 (Digital Signal Mixer) |
1398 | * Mode = 0 (Mode 0) | 1399 | * Mode = 0 (Mode 0) |
1399 | * Emphasis = 0 (None) | 1400 | * Emphasis = 0 (None) |
1400 | * CP = 1 (Copyright unasserted) | 1401 | * CP = 1 (Copyright unasserted) |
1401 | * AN = 0 (Audio data) | 1402 | * AN = 0 (Audio data) |
1402 | * P = 0 (Consumer) | 1403 | * P = 0 (Consumer) |
1403 | */ | 1404 | */ |
1404 | snd_ca0106_ptr_write(chip, SPCS0, 0, | 1405 | snd_ca0106_ptr_write(chip, SPCS0, 0, |
1405 | chip->spdif_bits[0] = | 1406 | chip->spdif_bits[0] = |
1406 | SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | | 1407 | SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | |
1407 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | | 1408 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | |
1408 | SPCS_GENERATIONSTATUS | 0x00001200 | | 1409 | SPCS_GENERATIONSTATUS | 0x00001200 | |
1409 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); | 1410 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); |
1410 | /* Only SPCS1 has been tested */ | 1411 | /* Only SPCS1 has been tested */ |
1411 | snd_ca0106_ptr_write(chip, SPCS1, 0, | 1412 | snd_ca0106_ptr_write(chip, SPCS1, 0, |
1412 | chip->spdif_bits[1] = | 1413 | chip->spdif_bits[1] = |
1413 | SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | | 1414 | SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | |
1414 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | | 1415 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | |
1415 | SPCS_GENERATIONSTATUS | 0x00001200 | | 1416 | SPCS_GENERATIONSTATUS | 0x00001200 | |
1416 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); | 1417 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); |
1417 | snd_ca0106_ptr_write(chip, SPCS2, 0, | 1418 | snd_ca0106_ptr_write(chip, SPCS2, 0, |
1418 | chip->spdif_bits[2] = | 1419 | chip->spdif_bits[2] = |
1419 | SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | | 1420 | SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | |
1420 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | | 1421 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | |
1421 | SPCS_GENERATIONSTATUS | 0x00001200 | | 1422 | SPCS_GENERATIONSTATUS | 0x00001200 | |
1422 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); | 1423 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); |
1423 | snd_ca0106_ptr_write(chip, SPCS3, 0, | 1424 | snd_ca0106_ptr_write(chip, SPCS3, 0, |
1424 | chip->spdif_bits[3] = | 1425 | chip->spdif_bits[3] = |
1425 | SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | | 1426 | SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | |
1426 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | | 1427 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | |
1427 | SPCS_GENERATIONSTATUS | 0x00001200 | | 1428 | SPCS_GENERATIONSTATUS | 0x00001200 | |
1428 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); | 1429 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); |
1429 | 1430 | ||
1430 | snd_ca0106_ptr_write(chip, PLAYBACK_MUTE, 0, 0x00fc0000); | 1431 | snd_ca0106_ptr_write(chip, PLAYBACK_MUTE, 0, 0x00fc0000); |
1431 | snd_ca0106_ptr_write(chip, CAPTURE_MUTE, 0, 0x00fc0000); | 1432 | snd_ca0106_ptr_write(chip, CAPTURE_MUTE, 0, 0x00fc0000); |
1432 | 1433 | ||
1433 | /* Write 0x8000 to AC97_REC_GAIN to mute it. */ | 1434 | /* Write 0x8000 to AC97_REC_GAIN to mute it. */ |
1434 | outb(AC97_REC_GAIN, chip->port + AC97ADDRESS); | 1435 | outb(AC97_REC_GAIN, chip->port + AC97ADDRESS); |
1435 | outw(0x8000, chip->port + AC97DATA); | 1436 | outw(0x8000, chip->port + AC97DATA); |
1436 | #if 0 | 1437 | #if 0 |
1437 | snd_ca0106_ptr_write(chip, SPCS0, 0, 0x2108006); | 1438 | snd_ca0106_ptr_write(chip, SPCS0, 0, 0x2108006); |
1438 | snd_ca0106_ptr_write(chip, 0x42, 0, 0x2108006); | 1439 | snd_ca0106_ptr_write(chip, 0x42, 0, 0x2108006); |
1439 | snd_ca0106_ptr_write(chip, 0x43, 0, 0x2108006); | 1440 | snd_ca0106_ptr_write(chip, 0x43, 0, 0x2108006); |
1440 | snd_ca0106_ptr_write(chip, 0x44, 0, 0x2108006); | 1441 | snd_ca0106_ptr_write(chip, 0x44, 0, 0x2108006); |
1441 | #endif | 1442 | #endif |
1442 | 1443 | ||
1443 | //snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0xf0f003f); /* OSS drivers set this. */ | 1444 | //snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0xf0f003f); /* OSS drivers set this. */ |
1444 | /* Analog or Digital output */ | 1445 | /* Analog or Digital output */ |
1445 | snd_ca0106_ptr_write(chip, SPDIF_SELECT1, 0, 0xf); | 1446 | snd_ca0106_ptr_write(chip, SPDIF_SELECT1, 0, 0xf); |
1446 | snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000); /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers. Use 0x000f0000 for surround71 */ | 1447 | snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000); /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers. Use 0x000f0000 for surround71 */ |
1447 | chip->spdif_enable = 0; /* Set digital SPDIF output off */ | 1448 | chip->spdif_enable = 0; /* Set digital SPDIF output off */ |
1448 | //snd_ca0106_ptr_write(chip, 0x45, 0, 0); /* Analogue out */ | 1449 | //snd_ca0106_ptr_write(chip, 0x45, 0, 0); /* Analogue out */ |
1449 | //snd_ca0106_ptr_write(chip, 0x45, 0, 0xf00); /* Digital out */ | 1450 | //snd_ca0106_ptr_write(chip, 0x45, 0, 0xf00); /* Digital out */ |
1450 | 1451 | ||
1451 | snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 0, 0x40c81000); /* goes to 0x40c80000 when doing SPDIF IN/OUT */ | 1452 | snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 0, 0x40c81000); /* goes to 0x40c80000 when doing SPDIF IN/OUT */ |
1452 | snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 1, 0xffffffff); /* (Mute) CAPTURE feedback into PLAYBACK volume. Only lower 16 bits matter. */ | 1453 | snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 1, 0xffffffff); /* (Mute) CAPTURE feedback into PLAYBACK volume. Only lower 16 bits matter. */ |
1453 | snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 2, 0x30300000); /* SPDIF IN Volume */ | 1454 | snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 2, 0x30300000); /* SPDIF IN Volume */ |
1454 | snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 3, 0x00700000); /* SPDIF IN Volume, 0x70 = (vol & 0x3f) | 0x40 */ | 1455 | snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 3, 0x00700000); /* SPDIF IN Volume, 0x70 = (vol & 0x3f) | 0x40 */ |
1455 | snd_ca0106_ptr_write(chip, PLAYBACK_ROUTING1, 0, 0x32765410); | 1456 | snd_ca0106_ptr_write(chip, PLAYBACK_ROUTING1, 0, 0x32765410); |
1456 | snd_ca0106_ptr_write(chip, PLAYBACK_ROUTING2, 0, 0x76767676); | 1457 | snd_ca0106_ptr_write(chip, PLAYBACK_ROUTING2, 0, 0x76767676); |
1457 | snd_ca0106_ptr_write(chip, CAPTURE_ROUTING1, 0, 0x32765410); | 1458 | snd_ca0106_ptr_write(chip, CAPTURE_ROUTING1, 0, 0x32765410); |
1458 | snd_ca0106_ptr_write(chip, CAPTURE_ROUTING2, 0, 0x76767676); | 1459 | snd_ca0106_ptr_write(chip, CAPTURE_ROUTING2, 0, 0x76767676); |
1459 | for(ch = 0; ch < 4; ch++) { | 1460 | for(ch = 0; ch < 4; ch++) { |
1460 | snd_ca0106_ptr_write(chip, CAPTURE_VOLUME1, ch, 0x30303030); /* Only high 16 bits matter */ | 1461 | snd_ca0106_ptr_write(chip, CAPTURE_VOLUME1, ch, 0x30303030); /* Only high 16 bits matter */ |
1461 | snd_ca0106_ptr_write(chip, CAPTURE_VOLUME2, ch, 0x30303030); | 1462 | snd_ca0106_ptr_write(chip, CAPTURE_VOLUME2, ch, 0x30303030); |
1462 | //snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0x40404040); /* Mute */ | 1463 | //snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0x40404040); /* Mute */ |
1463 | //snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0x40404040); /* Mute */ | 1464 | //snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0x40404040); /* Mute */ |
1464 | snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0xffffffff); /* Mute */ | 1465 | snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0xffffffff); /* Mute */ |
1465 | snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0xffffffff); /* Mute */ | 1466 | snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0xffffffff); /* Mute */ |
1466 | } | 1467 | } |
1467 | if (chip->details->i2c_adc == 1) { | 1468 | if (chip->details->i2c_adc == 1) { |
1468 | /* Select MIC, Line in, TAD in, AUX in */ | 1469 | /* Select MIC, Line in, TAD in, AUX in */ |
1469 | snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); | 1470 | snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); |
1470 | /* Default to CAPTURE_SOURCE to i2s in */ | 1471 | /* Default to CAPTURE_SOURCE to i2s in */ |
1471 | chip->capture_source = 3; | 1472 | chip->capture_source = 3; |
1472 | } else if (chip->details->ac97 == 1) { | 1473 | } else if (chip->details->ac97 == 1) { |
1473 | /* Default to AC97 in */ | 1474 | /* Default to AC97 in */ |
1474 | snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x444400e4); | 1475 | snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x444400e4); |
1475 | /* Default to CAPTURE_SOURCE to AC97 in */ | 1476 | /* Default to CAPTURE_SOURCE to AC97 in */ |
1476 | chip->capture_source = 4; | 1477 | chip->capture_source = 4; |
1477 | } else { | 1478 | } else { |
1478 | /* Select MIC, Line in, TAD in, AUX in */ | 1479 | /* Select MIC, Line in, TAD in, AUX in */ |
1479 | snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); | 1480 | snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); |
1480 | /* Default to Set CAPTURE_SOURCE to i2s in */ | 1481 | /* Default to Set CAPTURE_SOURCE to i2s in */ |
1481 | chip->capture_source = 3; | 1482 | chip->capture_source = 3; |
1482 | } | 1483 | } |
1483 | 1484 | ||
1484 | if (chip->details->gpio_type == 2) { /* The SB0438 use GPIO differently. */ | 1485 | if (chip->details->gpio_type == 2) { /* The SB0438 use GPIO differently. */ |
1485 | /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ | 1486 | /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ |
1486 | outl(0x0, chip->port+GPIO); | 1487 | outl(0x0, chip->port+GPIO); |
1487 | //outl(0x00f0e000, chip->port+GPIO); /* Analog */ | 1488 | //outl(0x00f0e000, chip->port+GPIO); /* Analog */ |
1488 | outl(0x005f5301, chip->port+GPIO); /* Analog */ | 1489 | outl(0x005f5301, chip->port+GPIO); /* Analog */ |
1489 | } else if (chip->details->gpio_type == 1) { /* The SB0410 and SB0413 use GPIO differently. */ | 1490 | } else if (chip->details->gpio_type == 1) { /* The SB0410 and SB0413 use GPIO differently. */ |
1490 | /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ | 1491 | /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ |
1491 | outl(0x0, chip->port+GPIO); | 1492 | outl(0x0, chip->port+GPIO); |
1492 | //outl(0x00f0e000, chip->port+GPIO); /* Analog */ | 1493 | //outl(0x00f0e000, chip->port+GPIO); /* Analog */ |
1493 | outl(0x005f5301, chip->port+GPIO); /* Analog */ | 1494 | outl(0x005f5301, chip->port+GPIO); /* Analog */ |
1494 | } else { | 1495 | } else { |
1495 | outl(0x0, chip->port+GPIO); | 1496 | outl(0x0, chip->port+GPIO); |
1496 | outl(0x005f03a3, chip->port+GPIO); /* Analog */ | 1497 | outl(0x005f03a3, chip->port+GPIO); /* Analog */ |
1497 | //outl(0x005f02a2, chip->port+GPIO); /* SPDIF */ | 1498 | //outl(0x005f02a2, chip->port+GPIO); /* SPDIF */ |
1498 | } | 1499 | } |
1499 | snd_ca0106_intr_enable(chip, 0x105); /* Win2000 uses 0x1e0 */ | 1500 | snd_ca0106_intr_enable(chip, 0x105); /* Win2000 uses 0x1e0 */ |
1500 | 1501 | ||
1501 | //outl(HCFG_LOCKSOUNDCACHE|HCFG_AUDIOENABLE, chip->port+HCFG); | 1502 | //outl(HCFG_LOCKSOUNDCACHE|HCFG_AUDIOENABLE, chip->port+HCFG); |
1502 | //outl(0x00001409, chip->port+HCFG); /* 0x1000 causes AC3 to fails. Maybe it effects 24 bit output. */ | 1503 | //outl(0x00001409, chip->port+HCFG); /* 0x1000 causes AC3 to fails. Maybe it effects 24 bit output. */ |
1503 | //outl(0x00000009, chip->port+HCFG); | 1504 | //outl(0x00000009, chip->port+HCFG); |
1504 | outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); /* AC97 2.0, Enable outputs. */ | 1505 | outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); /* AC97 2.0, Enable outputs. */ |
1505 | 1506 | ||
1506 | if (chip->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */ | 1507 | if (chip->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */ |
1507 | int size, n; | 1508 | int size, n; |
1508 | 1509 | ||
1509 | size = ARRAY_SIZE(i2c_adc_init); | 1510 | size = ARRAY_SIZE(i2c_adc_init); |
1510 | //snd_printk("I2C:array size=0x%x\n", size); | 1511 | //snd_printk("I2C:array size=0x%x\n", size); |
1511 | for (n=0; n < size; n++) { | 1512 | for (n=0; n < size; n++) { |
1512 | snd_ca0106_i2c_write(chip, i2c_adc_init[n][0], i2c_adc_init[n][1]); | 1513 | snd_ca0106_i2c_write(chip, i2c_adc_init[n][0], i2c_adc_init[n][1]); |
1513 | } | 1514 | } |
1514 | for (n=0; n < 4; n++) { | 1515 | for (n=0; n < 4; n++) { |
1515 | chip->i2c_capture_volume[n][0]= 0xcf; | 1516 | chip->i2c_capture_volume[n][0]= 0xcf; |
1516 | chip->i2c_capture_volume[n][1]= 0xcf; | 1517 | chip->i2c_capture_volume[n][1]= 0xcf; |
1517 | } | 1518 | } |
1518 | chip->i2c_capture_source=2; /* Line in */ | 1519 | chip->i2c_capture_source=2; /* Line in */ |
1519 | //snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); /* Enable Line-in capture. MIC in currently untested. */ | 1520 | //snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); /* Enable Line-in capture. MIC in currently untested. */ |
1520 | } | 1521 | } |
1521 | if (chip->details->spi_dac == 1) { /* The SB0570 use SPI to control DAC. */ | 1522 | if (chip->details->spi_dac == 1) { /* The SB0570 use SPI to control DAC. */ |
1522 | int size, n; | 1523 | int size, n; |
1523 | 1524 | ||
1524 | size = ARRAY_SIZE(spi_dac_init); | 1525 | size = ARRAY_SIZE(spi_dac_init); |
1525 | for (n = 0; n < size; n++) { | 1526 | for (n = 0; n < size; n++) { |
1526 | int reg = spi_dac_init[n] >> SPI_REG_SHIFT; | 1527 | int reg = spi_dac_init[n] >> SPI_REG_SHIFT; |
1527 | 1528 | ||
1528 | snd_ca0106_spi_write(chip, spi_dac_init[n]); | 1529 | snd_ca0106_spi_write(chip, spi_dac_init[n]); |
1529 | if (reg < ARRAY_SIZE(chip->spi_dac_reg)) | 1530 | if (reg < ARRAY_SIZE(chip->spi_dac_reg)) |
1530 | chip->spi_dac_reg[reg] = spi_dac_init[n]; | 1531 | chip->spi_dac_reg[reg] = spi_dac_init[n]; |
1531 | } | 1532 | } |
1532 | } | 1533 | } |
1533 | 1534 | ||
1534 | if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, | 1535 | if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, |
1535 | chip, &ops)) < 0) { | 1536 | chip, &ops)) < 0) { |
1536 | snd_ca0106_free(chip); | 1537 | snd_ca0106_free(chip); |
1537 | return err; | 1538 | return err; |
1538 | } | 1539 | } |
1539 | *rchip = chip; | 1540 | *rchip = chip; |
1540 | return 0; | 1541 | return 0; |
1541 | } | 1542 | } |
1542 | 1543 | ||
1543 | 1544 | ||
1544 | static void ca0106_midi_interrupt_enable(struct snd_ca_midi *midi, int intr) | 1545 | static void ca0106_midi_interrupt_enable(struct snd_ca_midi *midi, int intr) |
1545 | { | 1546 | { |
1546 | snd_ca0106_intr_enable((struct snd_ca0106 *)(midi->dev_id), intr); | 1547 | snd_ca0106_intr_enable((struct snd_ca0106 *)(midi->dev_id), intr); |
1547 | } | 1548 | } |
1548 | 1549 | ||
1549 | static void ca0106_midi_interrupt_disable(struct snd_ca_midi *midi, int intr) | 1550 | static void ca0106_midi_interrupt_disable(struct snd_ca_midi *midi, int intr) |
1550 | { | 1551 | { |
1551 | snd_ca0106_intr_disable((struct snd_ca0106 *)(midi->dev_id), intr); | 1552 | snd_ca0106_intr_disable((struct snd_ca0106 *)(midi->dev_id), intr); |
1552 | } | 1553 | } |
1553 | 1554 | ||
1554 | static unsigned char ca0106_midi_read(struct snd_ca_midi *midi, int idx) | 1555 | static unsigned char ca0106_midi_read(struct snd_ca_midi *midi, int idx) |
1555 | { | 1556 | { |
1556 | return (unsigned char)snd_ca0106_ptr_read((struct snd_ca0106 *)(midi->dev_id), | 1557 | return (unsigned char)snd_ca0106_ptr_read((struct snd_ca0106 *)(midi->dev_id), |
1557 | midi->port + idx, 0); | 1558 | midi->port + idx, 0); |
1558 | } | 1559 | } |
1559 | 1560 | ||
1560 | static void ca0106_midi_write(struct snd_ca_midi *midi, int data, int idx) | 1561 | static void ca0106_midi_write(struct snd_ca_midi *midi, int data, int idx) |
1561 | { | 1562 | { |
1562 | snd_ca0106_ptr_write((struct snd_ca0106 *)(midi->dev_id), midi->port + idx, 0, data); | 1563 | snd_ca0106_ptr_write((struct snd_ca0106 *)(midi->dev_id), midi->port + idx, 0, data); |
1563 | } | 1564 | } |
1564 | 1565 | ||
1565 | static struct snd_card *ca0106_dev_id_card(void *dev_id) | 1566 | static struct snd_card *ca0106_dev_id_card(void *dev_id) |
1566 | { | 1567 | { |
1567 | return ((struct snd_ca0106 *)dev_id)->card; | 1568 | return ((struct snd_ca0106 *)dev_id)->card; |
1568 | } | 1569 | } |
1569 | 1570 | ||
1570 | static int ca0106_dev_id_port(void *dev_id) | 1571 | static int ca0106_dev_id_port(void *dev_id) |
1571 | { | 1572 | { |
1572 | return ((struct snd_ca0106 *)dev_id)->port; | 1573 | return ((struct snd_ca0106 *)dev_id)->port; |
1573 | } | 1574 | } |
1574 | 1575 | ||
1575 | static int __devinit snd_ca0106_midi(struct snd_ca0106 *chip, unsigned int channel) | 1576 | static int __devinit snd_ca0106_midi(struct snd_ca0106 *chip, unsigned int channel) |
1576 | { | 1577 | { |
1577 | struct snd_ca_midi *midi; | 1578 | struct snd_ca_midi *midi; |
1578 | char *name; | 1579 | char *name; |
1579 | int err; | 1580 | int err; |
1580 | 1581 | ||
1581 | if (channel == CA0106_MIDI_CHAN_B) { | 1582 | if (channel == CA0106_MIDI_CHAN_B) { |
1582 | name = "CA0106 MPU-401 (UART) B"; | 1583 | name = "CA0106 MPU-401 (UART) B"; |
1583 | midi = &chip->midi2; | 1584 | midi = &chip->midi2; |
1584 | midi->tx_enable = INTE_MIDI_TX_B; | 1585 | midi->tx_enable = INTE_MIDI_TX_B; |
1585 | midi->rx_enable = INTE_MIDI_RX_B; | 1586 | midi->rx_enable = INTE_MIDI_RX_B; |
1586 | midi->ipr_tx = IPR_MIDI_TX_B; | 1587 | midi->ipr_tx = IPR_MIDI_TX_B; |
1587 | midi->ipr_rx = IPR_MIDI_RX_B; | 1588 | midi->ipr_rx = IPR_MIDI_RX_B; |
1588 | midi->port = MIDI_UART_B_DATA; | 1589 | midi->port = MIDI_UART_B_DATA; |
1589 | } else { | 1590 | } else { |
1590 | name = "CA0106 MPU-401 (UART)"; | 1591 | name = "CA0106 MPU-401 (UART)"; |
1591 | midi = &chip->midi; | 1592 | midi = &chip->midi; |
1592 | midi->tx_enable = INTE_MIDI_TX_A; | 1593 | midi->tx_enable = INTE_MIDI_TX_A; |
1593 | midi->rx_enable = INTE_MIDI_TX_B; | 1594 | midi->rx_enable = INTE_MIDI_TX_B; |
1594 | midi->ipr_tx = IPR_MIDI_TX_A; | 1595 | midi->ipr_tx = IPR_MIDI_TX_A; |
1595 | midi->ipr_rx = IPR_MIDI_RX_A; | 1596 | midi->ipr_rx = IPR_MIDI_RX_A; |
1596 | midi->port = MIDI_UART_A_DATA; | 1597 | midi->port = MIDI_UART_A_DATA; |
1597 | } | 1598 | } |
1598 | 1599 | ||
1599 | midi->reset = CA0106_MPU401_RESET; | 1600 | midi->reset = CA0106_MPU401_RESET; |
1600 | midi->enter_uart = CA0106_MPU401_ENTER_UART; | 1601 | midi->enter_uart = CA0106_MPU401_ENTER_UART; |
1601 | midi->ack = CA0106_MPU401_ACK; | 1602 | midi->ack = CA0106_MPU401_ACK; |
1602 | 1603 | ||
1603 | midi->input_avail = CA0106_MIDI_INPUT_AVAIL; | 1604 | midi->input_avail = CA0106_MIDI_INPUT_AVAIL; |
1604 | midi->output_ready = CA0106_MIDI_OUTPUT_READY; | 1605 | midi->output_ready = CA0106_MIDI_OUTPUT_READY; |
1605 | 1606 | ||
1606 | midi->channel = channel; | 1607 | midi->channel = channel; |
1607 | 1608 | ||
1608 | midi->interrupt_enable = ca0106_midi_interrupt_enable; | 1609 | midi->interrupt_enable = ca0106_midi_interrupt_enable; |
1609 | midi->interrupt_disable = ca0106_midi_interrupt_disable; | 1610 | midi->interrupt_disable = ca0106_midi_interrupt_disable; |
1610 | 1611 | ||
1611 | midi->read = ca0106_midi_read; | 1612 | midi->read = ca0106_midi_read; |
1612 | midi->write = ca0106_midi_write; | 1613 | midi->write = ca0106_midi_write; |
1613 | 1614 | ||
1614 | midi->get_dev_id_card = ca0106_dev_id_card; | 1615 | midi->get_dev_id_card = ca0106_dev_id_card; |
1615 | midi->get_dev_id_port = ca0106_dev_id_port; | 1616 | midi->get_dev_id_port = ca0106_dev_id_port; |
1616 | 1617 | ||
1617 | midi->dev_id = chip; | 1618 | midi->dev_id = chip; |
1618 | 1619 | ||
1619 | if ((err = ca_midi_init(chip, midi, 0, name)) < 0) | 1620 | if ((err = ca_midi_init(chip, midi, 0, name)) < 0) |
1620 | return err; | 1621 | return err; |
1621 | 1622 | ||
1622 | return 0; | 1623 | return 0; |
1623 | } | 1624 | } |
1624 | 1625 | ||
1625 | 1626 | ||
1626 | static int __devinit snd_ca0106_probe(struct pci_dev *pci, | 1627 | static int __devinit snd_ca0106_probe(struct pci_dev *pci, |
1627 | const struct pci_device_id *pci_id) | 1628 | const struct pci_device_id *pci_id) |
1628 | { | 1629 | { |
1629 | static int dev; | 1630 | static int dev; |
1630 | struct snd_card *card; | 1631 | struct snd_card *card; |
1631 | struct snd_ca0106 *chip; | 1632 | struct snd_ca0106 *chip; |
1632 | int err; | 1633 | int err; |
1633 | 1634 | ||
1634 | if (dev >= SNDRV_CARDS) | 1635 | if (dev >= SNDRV_CARDS) |
1635 | return -ENODEV; | 1636 | return -ENODEV; |
1636 | if (!enable[dev]) { | 1637 | if (!enable[dev]) { |
1637 | dev++; | 1638 | dev++; |
1638 | return -ENOENT; | 1639 | return -ENOENT; |
1639 | } | 1640 | } |
1640 | 1641 | ||
1641 | card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); | 1642 | card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); |
1642 | if (card == NULL) | 1643 | if (card == NULL) |
1643 | return -ENOMEM; | 1644 | return -ENOMEM; |
1644 | 1645 | ||
1645 | if ((err = snd_ca0106_create(dev, card, pci, &chip)) < 0) { | 1646 | if ((err = snd_ca0106_create(dev, card, pci, &chip)) < 0) { |
1646 | snd_card_free(card); | 1647 | snd_card_free(card); |
1647 | return err; | 1648 | return err; |
1648 | } | 1649 | } |
1649 | 1650 | ||
1650 | if ((err = snd_ca0106_pcm(chip, 0, NULL)) < 0) { | 1651 | if ((err = snd_ca0106_pcm(chip, 0, NULL)) < 0) { |
1651 | snd_card_free(card); | 1652 | snd_card_free(card); |
1652 | return err; | 1653 | return err; |
1653 | } | 1654 | } |
1654 | if ((err = snd_ca0106_pcm(chip, 1, NULL)) < 0) { | 1655 | if ((err = snd_ca0106_pcm(chip, 1, NULL)) < 0) { |
1655 | snd_card_free(card); | 1656 | snd_card_free(card); |
1656 | return err; | 1657 | return err; |
1657 | } | 1658 | } |
1658 | if ((err = snd_ca0106_pcm(chip, 2, NULL)) < 0) { | 1659 | if ((err = snd_ca0106_pcm(chip, 2, NULL)) < 0) { |
1659 | snd_card_free(card); | 1660 | snd_card_free(card); |
1660 | return err; | 1661 | return err; |
1661 | } | 1662 | } |
1662 | if ((err = snd_ca0106_pcm(chip, 3, NULL)) < 0) { | 1663 | if ((err = snd_ca0106_pcm(chip, 3, NULL)) < 0) { |
1663 | snd_card_free(card); | 1664 | snd_card_free(card); |
1664 | return err; | 1665 | return err; |
1665 | } | 1666 | } |
1666 | if (chip->details->ac97 == 1) { /* The SB0410 and SB0413 do not have an AC97 chip. */ | 1667 | if (chip->details->ac97 == 1) { /* The SB0410 and SB0413 do not have an AC97 chip. */ |
1667 | if ((err = snd_ca0106_ac97(chip)) < 0) { | 1668 | if ((err = snd_ca0106_ac97(chip)) < 0) { |
1668 | snd_card_free(card); | 1669 | snd_card_free(card); |
1669 | return err; | 1670 | return err; |
1670 | } | 1671 | } |
1671 | } | 1672 | } |
1672 | if ((err = snd_ca0106_mixer(chip)) < 0) { | 1673 | if ((err = snd_ca0106_mixer(chip)) < 0) { |
1673 | snd_card_free(card); | 1674 | snd_card_free(card); |
1674 | return err; | 1675 | return err; |
1675 | } | 1676 | } |
1676 | 1677 | ||
1677 | snd_printdd("ca0106: probe for MIDI channel A ..."); | 1678 | snd_printdd("ca0106: probe for MIDI channel A ..."); |
1678 | if ((err = snd_ca0106_midi(chip,CA0106_MIDI_CHAN_A)) < 0) { | 1679 | if ((err = snd_ca0106_midi(chip,CA0106_MIDI_CHAN_A)) < 0) { |
1679 | snd_card_free(card); | 1680 | snd_card_free(card); |
1680 | snd_printdd(" failed, err=0x%x\n",err); | 1681 | snd_printdd(" failed, err=0x%x\n",err); |
1681 | return err; | 1682 | return err; |
1682 | } | 1683 | } |
1683 | snd_printdd(" done.\n"); | 1684 | snd_printdd(" done.\n"); |
1684 | 1685 | ||
1685 | #ifdef CONFIG_PROC_FS | 1686 | #ifdef CONFIG_PROC_FS |
1686 | snd_ca0106_proc_init(chip); | 1687 | snd_ca0106_proc_init(chip); |
1687 | #endif | 1688 | #endif |
1688 | 1689 | ||
1689 | snd_card_set_dev(card, &pci->dev); | 1690 | snd_card_set_dev(card, &pci->dev); |
1690 | 1691 | ||
1691 | if ((err = snd_card_register(card)) < 0) { | 1692 | if ((err = snd_card_register(card)) < 0) { |
1692 | snd_card_free(card); | 1693 | snd_card_free(card); |
1693 | return err; | 1694 | return err; |
1694 | } | 1695 | } |
1695 | 1696 | ||
1696 | pci_set_drvdata(pci, card); | 1697 | pci_set_drvdata(pci, card); |
1697 | dev++; | 1698 | dev++; |
1698 | return 0; | 1699 | return 0; |
1699 | } | 1700 | } |
1700 | 1701 | ||
1701 | static void __devexit snd_ca0106_remove(struct pci_dev *pci) | 1702 | static void __devexit snd_ca0106_remove(struct pci_dev *pci) |
1702 | { | 1703 | { |
1703 | snd_card_free(pci_get_drvdata(pci)); | 1704 | snd_card_free(pci_get_drvdata(pci)); |
1704 | pci_set_drvdata(pci, NULL); | 1705 | pci_set_drvdata(pci, NULL); |
1705 | } | 1706 | } |
1706 | 1707 | ||
1707 | // PCI IDs | 1708 | // PCI IDs |
1708 | static struct pci_device_id snd_ca0106_ids[] = { | 1709 | static struct pci_device_id snd_ca0106_ids[] = { |
1709 | { 0x1102, 0x0007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Audigy LS or Live 24bit */ | 1710 | { 0x1102, 0x0007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Audigy LS or Live 24bit */ |
1710 | { 0, } | 1711 | { 0, } |
1711 | }; | 1712 | }; |
1712 | MODULE_DEVICE_TABLE(pci, snd_ca0106_ids); | 1713 | MODULE_DEVICE_TABLE(pci, snd_ca0106_ids); |
1713 | 1714 | ||
1714 | // pci_driver definition | 1715 | // pci_driver definition |
1715 | static struct pci_driver driver = { | 1716 | static struct pci_driver driver = { |
1716 | .name = "CA0106", | 1717 | .name = "CA0106", |
1717 | .id_table = snd_ca0106_ids, | 1718 | .id_table = snd_ca0106_ids, |
1718 | .probe = snd_ca0106_probe, | 1719 | .probe = snd_ca0106_probe, |
1719 | .remove = __devexit_p(snd_ca0106_remove), | 1720 | .remove = __devexit_p(snd_ca0106_remove), |
1720 | }; | 1721 | }; |
1721 | 1722 | ||
1722 | // initialization of the module | 1723 | // initialization of the module |
1723 | static int __init alsa_card_ca0106_init(void) | 1724 | static int __init alsa_card_ca0106_init(void) |
1724 | { | 1725 | { |
1725 | return pci_register_driver(&driver); | 1726 | return pci_register_driver(&driver); |
1726 | } | 1727 | } |
1727 | 1728 | ||
1728 | // clean up the module | 1729 | // clean up the module |
1729 | static void __exit alsa_card_ca0106_exit(void) | 1730 | static void __exit alsa_card_ca0106_exit(void) |
1730 | { | 1731 | { |
1731 | pci_unregister_driver(&driver); | 1732 | pci_unregister_driver(&driver); |
1732 | } | 1733 | } |
1733 | 1734 | ||
1734 | module_init(alsa_card_ca0106_init) | 1735 | module_init(alsa_card_ca0106_init) |
1735 | module_exit(alsa_card_ca0106_exit) | 1736 | module_exit(alsa_card_ca0106_exit) |
1736 | 1737 |
sound/soc/codecs/ak4535.c
1 | /* | 1 | /* |
2 | * ak4535.c -- AK4535 ALSA Soc Audio driver | 2 | * ak4535.c -- AK4535 ALSA Soc Audio driver |
3 | * | 3 | * |
4 | * Copyright 2005 Openedhand Ltd. | 4 | * Copyright 2005 Openedhand Ltd. |
5 | * | 5 | * |
6 | * Author: Richard Purdie <richard@openedhand.com> | 6 | * Author: Richard Purdie <richard@openedhand.com> |
7 | * | 7 | * |
8 | * Based on wm8753.c by Liam Girdwood | 8 | * Based on wm8753.c by Liam Girdwood |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License version 2 as | 11 | * it under the terms of the GNU General Public License version 2 as |
12 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/moduleparam.h> | 16 | #include <linux/moduleparam.h> |
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
19 | #include <linux/pm.h> | 19 | #include <linux/pm.h> |
20 | #include <linux/i2c.h> | 20 | #include <linux/i2c.h> |
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <sound/core.h> | 22 | #include <sound/core.h> |
23 | #include <sound/pcm.h> | 23 | #include <sound/pcm.h> |
24 | #include <sound/pcm_params.h> | 24 | #include <sound/pcm_params.h> |
25 | #include <sound/soc.h> | 25 | #include <sound/soc.h> |
26 | #include <sound/soc-dapm.h> | 26 | #include <sound/soc-dapm.h> |
27 | #include <sound/initval.h> | 27 | #include <sound/initval.h> |
28 | 28 | ||
29 | #include "ak4535.h" | 29 | #include "ak4535.h" |
30 | 30 | ||
31 | #define AUDIO_NAME "ak4535" | 31 | #define AUDIO_NAME "ak4535" |
32 | #define AK4535_VERSION "0.3" | 32 | #define AK4535_VERSION "0.3" |
33 | 33 | ||
34 | struct snd_soc_codec_device soc_codec_dev_ak4535; | 34 | struct snd_soc_codec_device soc_codec_dev_ak4535; |
35 | 35 | ||
36 | /* codec private data */ | 36 | /* codec private data */ |
37 | struct ak4535_priv { | 37 | struct ak4535_priv { |
38 | unsigned int sysclk; | 38 | unsigned int sysclk; |
39 | }; | 39 | }; |
40 | 40 | ||
41 | /* | 41 | /* |
42 | * ak4535 register cache | 42 | * ak4535 register cache |
43 | */ | 43 | */ |
44 | static const u16 ak4535_reg[AK4535_CACHEREGNUM] = { | 44 | static const u16 ak4535_reg[AK4535_CACHEREGNUM] = { |
45 | 0x0000, 0x0080, 0x0000, 0x0003, | 45 | 0x0000, 0x0080, 0x0000, 0x0003, |
46 | 0x0002, 0x0000, 0x0011, 0x0001, | 46 | 0x0002, 0x0000, 0x0011, 0x0001, |
47 | 0x0000, 0x0040, 0x0036, 0x0010, | 47 | 0x0000, 0x0040, 0x0036, 0x0010, |
48 | 0x0000, 0x0000, 0x0057, 0x0000, | 48 | 0x0000, 0x0000, 0x0057, 0x0000, |
49 | }; | 49 | }; |
50 | 50 | ||
51 | /* | 51 | /* |
52 | * read ak4535 register cache | 52 | * read ak4535 register cache |
53 | */ | 53 | */ |
54 | static inline unsigned int ak4535_read_reg_cache(struct snd_soc_codec *codec, | 54 | static inline unsigned int ak4535_read_reg_cache(struct snd_soc_codec *codec, |
55 | unsigned int reg) | 55 | unsigned int reg) |
56 | { | 56 | { |
57 | u16 *cache = codec->reg_cache; | 57 | u16 *cache = codec->reg_cache; |
58 | if (reg >= AK4535_CACHEREGNUM) | 58 | if (reg >= AK4535_CACHEREGNUM) |
59 | return -1; | 59 | return -1; |
60 | return cache[reg]; | 60 | return cache[reg]; |
61 | } | 61 | } |
62 | 62 | ||
63 | static inline unsigned int ak4535_read(struct snd_soc_codec *codec, | 63 | static inline unsigned int ak4535_read(struct snd_soc_codec *codec, |
64 | unsigned int reg) | 64 | unsigned int reg) |
65 | { | 65 | { |
66 | u8 data; | 66 | u8 data; |
67 | data = reg; | 67 | data = reg; |
68 | 68 | ||
69 | if (codec->hw_write(codec->control_data, &data, 1) != 1) | 69 | if (codec->hw_write(codec->control_data, &data, 1) != 1) |
70 | return -EIO; | 70 | return -EIO; |
71 | 71 | ||
72 | if (codec->hw_read(codec->control_data, &data, 1) != 1) | 72 | if (codec->hw_read(codec->control_data, &data, 1) != 1) |
73 | return -EIO; | 73 | return -EIO; |
74 | 74 | ||
75 | return data; | 75 | return data; |
76 | }; | 76 | }; |
77 | 77 | ||
78 | /* | 78 | /* |
79 | * write ak4535 register cache | 79 | * write ak4535 register cache |
80 | */ | 80 | */ |
81 | static inline void ak4535_write_reg_cache(struct snd_soc_codec *codec, | 81 | static inline void ak4535_write_reg_cache(struct snd_soc_codec *codec, |
82 | u16 reg, unsigned int value) | 82 | u16 reg, unsigned int value) |
83 | { | 83 | { |
84 | u16 *cache = codec->reg_cache; | 84 | u16 *cache = codec->reg_cache; |
85 | if (reg >= AK4535_CACHEREGNUM) | 85 | if (reg >= AK4535_CACHEREGNUM) |
86 | return; | 86 | return; |
87 | cache[reg] = value; | 87 | cache[reg] = value; |
88 | } | 88 | } |
89 | 89 | ||
90 | /* | 90 | /* |
91 | * write to the AK4535 register space | 91 | * write to the AK4535 register space |
92 | */ | 92 | */ |
93 | static int ak4535_write(struct snd_soc_codec *codec, unsigned int reg, | 93 | static int ak4535_write(struct snd_soc_codec *codec, unsigned int reg, |
94 | unsigned int value) | 94 | unsigned int value) |
95 | { | 95 | { |
96 | u8 data[2]; | 96 | u8 data[2]; |
97 | 97 | ||
98 | /* data is | 98 | /* data is |
99 | * D15..D8 AK4535 register offset | 99 | * D15..D8 AK4535 register offset |
100 | * D7...D0 register data | 100 | * D7...D0 register data |
101 | */ | 101 | */ |
102 | data[0] = reg & 0xff; | 102 | data[0] = reg & 0xff; |
103 | data[1] = value & 0xff; | 103 | data[1] = value & 0xff; |
104 | 104 | ||
105 | ak4535_write_reg_cache(codec, reg, value); | 105 | ak4535_write_reg_cache(codec, reg, value); |
106 | if (codec->hw_write(codec->control_data, data, 2) == 2) | 106 | if (codec->hw_write(codec->control_data, data, 2) == 2) |
107 | return 0; | 107 | return 0; |
108 | else | 108 | else |
109 | return -EIO; | 109 | return -EIO; |
110 | } | 110 | } |
111 | 111 | ||
112 | static int ak4535_sync(struct snd_soc_codec *codec) | 112 | static int ak4535_sync(struct snd_soc_codec *codec) |
113 | { | 113 | { |
114 | u16 *cache = codec->reg_cache; | 114 | u16 *cache = codec->reg_cache; |
115 | int i, r = 0; | 115 | int i, r = 0; |
116 | 116 | ||
117 | for (i = 0; i < AK4535_CACHEREGNUM; i++) | 117 | for (i = 0; i < AK4535_CACHEREGNUM; i++) |
118 | r |= ak4535_write(codec, i, cache[i]); | 118 | r |= ak4535_write(codec, i, cache[i]); |
119 | 119 | ||
120 | return r; | 120 | return r; |
121 | }; | 121 | }; |
122 | 122 | ||
123 | static const char *ak4535_mono_gain[] = {"+6dB", "-17dB"}; | 123 | static const char *ak4535_mono_gain[] = {"+6dB", "-17dB"}; |
124 | static const char *ak4535_mono_out[] = {"(L + R)/2", "Hi-Z"}; | 124 | static const char *ak4535_mono_out[] = {"(L + R)/2", "Hi-Z"}; |
125 | static const char *ak4535_hp_out[] = {"Stereo", "Mono"}; | 125 | static const char *ak4535_hp_out[] = {"Stereo", "Mono"}; |
126 | static const char *ak4535_deemp[] = {"44.1kHz", "Off", "48kHz", "32kHz"}; | 126 | static const char *ak4535_deemp[] = {"44.1kHz", "Off", "48kHz", "32kHz"}; |
127 | static const char *ak4535_mic_select[] = {"Internal", "External"}; | 127 | static const char *ak4535_mic_select[] = {"Internal", "External"}; |
128 | 128 | ||
129 | static const struct soc_enum ak4535_enum[] = { | 129 | static const struct soc_enum ak4535_enum[] = { |
130 | SOC_ENUM_SINGLE(AK4535_SIG1, 7, 2, ak4535_mono_gain), | 130 | SOC_ENUM_SINGLE(AK4535_SIG1, 7, 2, ak4535_mono_gain), |
131 | SOC_ENUM_SINGLE(AK4535_SIG1, 6, 2, ak4535_mono_out), | 131 | SOC_ENUM_SINGLE(AK4535_SIG1, 6, 2, ak4535_mono_out), |
132 | SOC_ENUM_SINGLE(AK4535_MODE2, 2, 2, ak4535_hp_out), | 132 | SOC_ENUM_SINGLE(AK4535_MODE2, 2, 2, ak4535_hp_out), |
133 | SOC_ENUM_SINGLE(AK4535_DAC, 0, 4, ak4535_deemp), | 133 | SOC_ENUM_SINGLE(AK4535_DAC, 0, 4, ak4535_deemp), |
134 | SOC_ENUM_SINGLE(AK4535_MIC, 1, 2, ak4535_mic_select), | 134 | SOC_ENUM_SINGLE(AK4535_MIC, 1, 2, ak4535_mic_select), |
135 | }; | 135 | }; |
136 | 136 | ||
137 | static const struct snd_kcontrol_new ak4535_snd_controls[] = { | 137 | static const struct snd_kcontrol_new ak4535_snd_controls[] = { |
138 | SOC_SINGLE("ALC2 Switch", AK4535_SIG1, 1, 1, 0), | 138 | SOC_SINGLE("ALC2 Switch", AK4535_SIG1, 1, 1, 0), |
139 | SOC_ENUM("Mono 1 Output", ak4535_enum[1]), | 139 | SOC_ENUM("Mono 1 Output", ak4535_enum[1]), |
140 | SOC_ENUM("Mono 1 Gain", ak4535_enum[0]), | 140 | SOC_ENUM("Mono 1 Gain", ak4535_enum[0]), |
141 | SOC_ENUM("Headphone Output", ak4535_enum[2]), | 141 | SOC_ENUM("Headphone Output", ak4535_enum[2]), |
142 | SOC_ENUM("Playback Deemphasis", ak4535_enum[3]), | 142 | SOC_ENUM("Playback Deemphasis", ak4535_enum[3]), |
143 | SOC_SINGLE("Bass Volume", AK4535_DAC, 2, 3, 0), | 143 | SOC_SINGLE("Bass Volume", AK4535_DAC, 2, 3, 0), |
144 | SOC_SINGLE("Mic Boost (+20dB) Switch", AK4535_MIC, 0, 1, 0), | 144 | SOC_SINGLE("Mic Boost (+20dB) Switch", AK4535_MIC, 0, 1, 0), |
145 | SOC_ENUM("Mic Select", ak4535_enum[4]), | 145 | SOC_ENUM("Mic Select", ak4535_enum[4]), |
146 | SOC_SINGLE("ALC Operation Time", AK4535_TIMER, 0, 3, 0), | 146 | SOC_SINGLE("ALC Operation Time", AK4535_TIMER, 0, 3, 0), |
147 | SOC_SINGLE("ALC Recovery Time", AK4535_TIMER, 2, 3, 0), | 147 | SOC_SINGLE("ALC Recovery Time", AK4535_TIMER, 2, 3, 0), |
148 | SOC_SINGLE("ALC ZC Time", AK4535_TIMER, 4, 3, 0), | 148 | SOC_SINGLE("ALC ZC Time", AK4535_TIMER, 4, 3, 0), |
149 | SOC_SINGLE("ALC 1 Switch", AK4535_ALC1, 5, 1, 0), | 149 | SOC_SINGLE("ALC 1 Switch", AK4535_ALC1, 5, 1, 0), |
150 | SOC_SINGLE("ALC 2 Switch", AK4535_ALC1, 6, 1, 0), | 150 | SOC_SINGLE("ALC 2 Switch", AK4535_ALC1, 6, 1, 0), |
151 | SOC_SINGLE("ALC Volume", AK4535_ALC2, 0, 127, 0), | 151 | SOC_SINGLE("ALC Volume", AK4535_ALC2, 0, 127, 0), |
152 | SOC_SINGLE("Capture Volume", AK4535_PGA, 0, 127, 0), | 152 | SOC_SINGLE("Capture Volume", AK4535_PGA, 0, 127, 0), |
153 | SOC_SINGLE("Left Playback Volume", AK4535_LATT, 0, 127, 1), | 153 | SOC_SINGLE("Left Playback Volume", AK4535_LATT, 0, 127, 1), |
154 | SOC_SINGLE("Right Playback Volume", AK4535_RATT, 0, 127, 1), | 154 | SOC_SINGLE("Right Playback Volume", AK4535_RATT, 0, 127, 1), |
155 | SOC_SINGLE("AUX Bypass Volume", AK4535_VOL, 0, 15, 0), | 155 | SOC_SINGLE("AUX Bypass Volume", AK4535_VOL, 0, 15, 0), |
156 | SOC_SINGLE("Mic Sidetone Volume", AK4535_VOL, 4, 7, 0), | 156 | SOC_SINGLE("Mic Sidetone Volume", AK4535_VOL, 4, 7, 0), |
157 | }; | 157 | }; |
158 | 158 | ||
159 | /* add non dapm controls */ | 159 | /* add non dapm controls */ |
160 | static int ak4535_add_controls(struct snd_soc_codec *codec) | 160 | static int ak4535_add_controls(struct snd_soc_codec *codec) |
161 | { | 161 | { |
162 | int err, i; | 162 | int err, i; |
163 | 163 | ||
164 | for (i = 0; i < ARRAY_SIZE(ak4535_snd_controls); i++) { | 164 | for (i = 0; i < ARRAY_SIZE(ak4535_snd_controls); i++) { |
165 | err = snd_ctl_add(codec->card, | 165 | err = snd_ctl_add(codec->card, |
166 | snd_soc_cnew(&ak4535_snd_controls[i], codec, NULL)); | 166 | snd_soc_cnew(&ak4535_snd_controls[i], codec, NULL)); |
167 | if (err < 0) | 167 | if (err < 0) |
168 | return err; | 168 | return err; |
169 | } | 169 | } |
170 | 170 | ||
171 | return 0; | 171 | return 0; |
172 | } | 172 | } |
173 | 173 | ||
174 | /* Mono 1 Mixer */ | 174 | /* Mono 1 Mixer */ |
175 | static const struct snd_kcontrol_new ak4535_mono1_mixer_controls[] = { | 175 | static const struct snd_kcontrol_new ak4535_mono1_mixer_controls[] = { |
176 | SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4535_SIG1, 4, 1, 0), | 176 | SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4535_SIG1, 4, 1, 0), |
177 | SOC_DAPM_SINGLE("Mono Playback Switch", AK4535_SIG1, 5, 1, 0), | 177 | SOC_DAPM_SINGLE("Mono Playback Switch", AK4535_SIG1, 5, 1, 0), |
178 | }; | 178 | }; |
179 | 179 | ||
180 | /* Stereo Mixer */ | 180 | /* Stereo Mixer */ |
181 | static const struct snd_kcontrol_new ak4535_stereo_mixer_controls[] = { | 181 | static const struct snd_kcontrol_new ak4535_stereo_mixer_controls[] = { |
182 | SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4535_SIG2, 4, 1, 0), | 182 | SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4535_SIG2, 4, 1, 0), |
183 | SOC_DAPM_SINGLE("Playback Switch", AK4535_SIG2, 7, 1, 0), | 183 | SOC_DAPM_SINGLE("Playback Switch", AK4535_SIG2, 7, 1, 0), |
184 | SOC_DAPM_SINGLE("Aux Bypass Switch", AK4535_SIG2, 5, 1, 0), | 184 | SOC_DAPM_SINGLE("Aux Bypass Switch", AK4535_SIG2, 5, 1, 0), |
185 | }; | 185 | }; |
186 | 186 | ||
187 | /* Input Mixer */ | 187 | /* Input Mixer */ |
188 | static const struct snd_kcontrol_new ak4535_input_mixer_controls[] = { | 188 | static const struct snd_kcontrol_new ak4535_input_mixer_controls[] = { |
189 | SOC_DAPM_SINGLE("Mic Capture Switch", AK4535_MIC, 2, 1, 0), | 189 | SOC_DAPM_SINGLE("Mic Capture Switch", AK4535_MIC, 2, 1, 0), |
190 | SOC_DAPM_SINGLE("Aux Capture Switch", AK4535_MIC, 5, 1, 0), | 190 | SOC_DAPM_SINGLE("Aux Capture Switch", AK4535_MIC, 5, 1, 0), |
191 | }; | 191 | }; |
192 | 192 | ||
193 | /* Input mux */ | 193 | /* Input mux */ |
194 | static const struct snd_kcontrol_new ak4535_input_mux_control = | 194 | static const struct snd_kcontrol_new ak4535_input_mux_control = |
195 | SOC_DAPM_ENUM("Input Select", ak4535_enum[4]); | 195 | SOC_DAPM_ENUM("Input Select", ak4535_enum[4]); |
196 | 196 | ||
197 | /* HP L switch */ | 197 | /* HP L switch */ |
198 | static const struct snd_kcontrol_new ak4535_hpl_control = | 198 | static const struct snd_kcontrol_new ak4535_hpl_control = |
199 | SOC_DAPM_SINGLE("Switch", AK4535_SIG2, 1, 1, 1); | 199 | SOC_DAPM_SINGLE("Switch", AK4535_SIG2, 1, 1, 1); |
200 | 200 | ||
201 | /* HP R switch */ | 201 | /* HP R switch */ |
202 | static const struct snd_kcontrol_new ak4535_hpr_control = | 202 | static const struct snd_kcontrol_new ak4535_hpr_control = |
203 | SOC_DAPM_SINGLE("Switch", AK4535_SIG2, 0, 1, 1); | 203 | SOC_DAPM_SINGLE("Switch", AK4535_SIG2, 0, 1, 1); |
204 | 204 | ||
205 | /* mono 2 switch */ | 205 | /* mono 2 switch */ |
206 | static const struct snd_kcontrol_new ak4535_mono2_control = | 206 | static const struct snd_kcontrol_new ak4535_mono2_control = |
207 | SOC_DAPM_SINGLE("Switch", AK4535_SIG1, 0, 1, 0); | 207 | SOC_DAPM_SINGLE("Switch", AK4535_SIG1, 0, 1, 0); |
208 | 208 | ||
209 | /* Line out switch */ | 209 | /* Line out switch */ |
210 | static const struct snd_kcontrol_new ak4535_line_control = | 210 | static const struct snd_kcontrol_new ak4535_line_control = |
211 | SOC_DAPM_SINGLE("Switch", AK4535_SIG2, 6, 1, 0); | 211 | SOC_DAPM_SINGLE("Switch", AK4535_SIG2, 6, 1, 0); |
212 | 212 | ||
213 | /* ak4535 dapm widgets */ | 213 | /* ak4535 dapm widgets */ |
214 | static const struct snd_soc_dapm_widget ak4535_dapm_widgets[] = { | 214 | static const struct snd_soc_dapm_widget ak4535_dapm_widgets[] = { |
215 | SND_SOC_DAPM_MIXER("Stereo Mixer", SND_SOC_NOPM, 0, 0, | 215 | SND_SOC_DAPM_MIXER("Stereo Mixer", SND_SOC_NOPM, 0, 0, |
216 | &ak4535_stereo_mixer_controls[0], | 216 | &ak4535_stereo_mixer_controls[0], |
217 | ARRAY_SIZE(ak4535_stereo_mixer_controls)), | 217 | ARRAY_SIZE(ak4535_stereo_mixer_controls)), |
218 | SND_SOC_DAPM_MIXER("Mono1 Mixer", SND_SOC_NOPM, 0, 0, | 218 | SND_SOC_DAPM_MIXER("Mono1 Mixer", SND_SOC_NOPM, 0, 0, |
219 | &ak4535_mono1_mixer_controls[0], | 219 | &ak4535_mono1_mixer_controls[0], |
220 | ARRAY_SIZE(ak4535_mono1_mixer_controls)), | 220 | ARRAY_SIZE(ak4535_mono1_mixer_controls)), |
221 | SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0, | 221 | SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0, |
222 | &ak4535_input_mixer_controls[0], | 222 | &ak4535_input_mixer_controls[0], |
223 | ARRAY_SIZE(ak4535_input_mixer_controls)), | 223 | ARRAY_SIZE(ak4535_input_mixer_controls)), |
224 | SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, | 224 | SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, |
225 | &ak4535_input_mux_control), | 225 | &ak4535_input_mux_control), |
226 | SND_SOC_DAPM_DAC("DAC", "Playback", AK4535_PM2, 0, 0), | 226 | SND_SOC_DAPM_DAC("DAC", "Playback", AK4535_PM2, 0, 0), |
227 | SND_SOC_DAPM_SWITCH("Mono 2 Enable", SND_SOC_NOPM, 0, 0, | 227 | SND_SOC_DAPM_SWITCH("Mono 2 Enable", SND_SOC_NOPM, 0, 0, |
228 | &ak4535_mono2_control), | 228 | &ak4535_mono2_control), |
229 | /* speaker powersave bit */ | 229 | /* speaker powersave bit */ |
230 | SND_SOC_DAPM_PGA("Speaker Enable", AK4535_MODE2, 0, 0, NULL, 0), | 230 | SND_SOC_DAPM_PGA("Speaker Enable", AK4535_MODE2, 0, 0, NULL, 0), |
231 | SND_SOC_DAPM_SWITCH("Line Out Enable", SND_SOC_NOPM, 0, 0, | 231 | SND_SOC_DAPM_SWITCH("Line Out Enable", SND_SOC_NOPM, 0, 0, |
232 | &ak4535_line_control), | 232 | &ak4535_line_control), |
233 | SND_SOC_DAPM_SWITCH("Left HP Enable", SND_SOC_NOPM, 0, 0, | 233 | SND_SOC_DAPM_SWITCH("Left HP Enable", SND_SOC_NOPM, 0, 0, |
234 | &ak4535_hpl_control), | 234 | &ak4535_hpl_control), |
235 | SND_SOC_DAPM_SWITCH("Right HP Enable", SND_SOC_NOPM, 0, 0, | 235 | SND_SOC_DAPM_SWITCH("Right HP Enable", SND_SOC_NOPM, 0, 0, |
236 | &ak4535_hpr_control), | 236 | &ak4535_hpr_control), |
237 | SND_SOC_DAPM_OUTPUT("LOUT"), | 237 | SND_SOC_DAPM_OUTPUT("LOUT"), |
238 | SND_SOC_DAPM_OUTPUT("HPL"), | 238 | SND_SOC_DAPM_OUTPUT("HPL"), |
239 | SND_SOC_DAPM_OUTPUT("ROUT"), | 239 | SND_SOC_DAPM_OUTPUT("ROUT"), |
240 | SND_SOC_DAPM_OUTPUT("HPR"), | 240 | SND_SOC_DAPM_OUTPUT("HPR"), |
241 | SND_SOC_DAPM_OUTPUT("SPP"), | 241 | SND_SOC_DAPM_OUTPUT("SPP"), |
242 | SND_SOC_DAPM_OUTPUT("SPN"), | 242 | SND_SOC_DAPM_OUTPUT("SPN"), |
243 | SND_SOC_DAPM_OUTPUT("MOUT1"), | 243 | SND_SOC_DAPM_OUTPUT("MOUT1"), |
244 | SND_SOC_DAPM_OUTPUT("MOUT2"), | 244 | SND_SOC_DAPM_OUTPUT("MOUT2"), |
245 | SND_SOC_DAPM_OUTPUT("MICOUT"), | 245 | SND_SOC_DAPM_OUTPUT("MICOUT"), |
246 | SND_SOC_DAPM_ADC("ADC", "Capture", AK4535_PM1, 0, 0), | 246 | SND_SOC_DAPM_ADC("ADC", "Capture", AK4535_PM1, 0, 0), |
247 | SND_SOC_DAPM_PGA("Spk Amp", AK4535_PM2, 3, 0, NULL, 0), | 247 | SND_SOC_DAPM_PGA("Spk Amp", AK4535_PM2, 3, 0, NULL, 0), |
248 | SND_SOC_DAPM_PGA("HP R Amp", AK4535_PM2, 1, 0, NULL, 0), | 248 | SND_SOC_DAPM_PGA("HP R Amp", AK4535_PM2, 1, 0, NULL, 0), |
249 | SND_SOC_DAPM_PGA("HP L Amp", AK4535_PM2, 2, 0, NULL, 0), | 249 | SND_SOC_DAPM_PGA("HP L Amp", AK4535_PM2, 2, 0, NULL, 0), |
250 | SND_SOC_DAPM_PGA("Mic", AK4535_PM1, 1, 0, NULL, 0), | 250 | SND_SOC_DAPM_PGA("Mic", AK4535_PM1, 1, 0, NULL, 0), |
251 | SND_SOC_DAPM_PGA("Line Out", AK4535_PM1, 4, 0, NULL, 0), | 251 | SND_SOC_DAPM_PGA("Line Out", AK4535_PM1, 4, 0, NULL, 0), |
252 | SND_SOC_DAPM_PGA("Mono Out", AK4535_PM1, 3, 0, NULL, 0), | 252 | SND_SOC_DAPM_PGA("Mono Out", AK4535_PM1, 3, 0, NULL, 0), |
253 | SND_SOC_DAPM_PGA("AUX In", AK4535_PM1, 2, 0, NULL, 0), | 253 | SND_SOC_DAPM_PGA("AUX In", AK4535_PM1, 2, 0, NULL, 0), |
254 | 254 | ||
255 | SND_SOC_DAPM_MICBIAS("Mic Int Bias", AK4535_MIC, 3, 0), | 255 | SND_SOC_DAPM_MICBIAS("Mic Int Bias", AK4535_MIC, 3, 0), |
256 | SND_SOC_DAPM_MICBIAS("Mic Ext Bias", AK4535_MIC, 4, 0), | 256 | SND_SOC_DAPM_MICBIAS("Mic Ext Bias", AK4535_MIC, 4, 0), |
257 | SND_SOC_DAPM_INPUT("MICIN"), | 257 | SND_SOC_DAPM_INPUT("MICIN"), |
258 | SND_SOC_DAPM_INPUT("MICEXT"), | 258 | SND_SOC_DAPM_INPUT("MICEXT"), |
259 | SND_SOC_DAPM_INPUT("AUX"), | 259 | SND_SOC_DAPM_INPUT("AUX"), |
260 | SND_SOC_DAPM_INPUT("MIN"), | 260 | SND_SOC_DAPM_INPUT("MIN"), |
261 | SND_SOC_DAPM_INPUT("AIN"), | 261 | SND_SOC_DAPM_INPUT("AIN"), |
262 | }; | 262 | }; |
263 | 263 | ||
264 | static const struct snd_soc_dapm_route audio_map[] = { | 264 | static const struct snd_soc_dapm_route audio_map[] = { |
265 | /*stereo mixer */ | 265 | /*stereo mixer */ |
266 | {"Stereo Mixer", "Playback Switch", "DAC"}, | 266 | {"Stereo Mixer", "Playback Switch", "DAC"}, |
267 | {"Stereo Mixer", "Mic Sidetone Switch", "Mic"}, | 267 | {"Stereo Mixer", "Mic Sidetone Switch", "Mic"}, |
268 | {"Stereo Mixer", "Aux Bypass Switch", "AUX In"}, | 268 | {"Stereo Mixer", "Aux Bypass Switch", "AUX In"}, |
269 | 269 | ||
270 | /* mono1 mixer */ | 270 | /* mono1 mixer */ |
271 | {"Mono1 Mixer", "Mic Sidetone Switch", "Mic"}, | 271 | {"Mono1 Mixer", "Mic Sidetone Switch", "Mic"}, |
272 | {"Mono1 Mixer", "Mono Playback Switch", "DAC"}, | 272 | {"Mono1 Mixer", "Mono Playback Switch", "DAC"}, |
273 | 273 | ||
274 | /* Mic */ | 274 | /* Mic */ |
275 | {"Mic", NULL, "AIN"}, | 275 | {"Mic", NULL, "AIN"}, |
276 | {"Input Mux", "Internal", "Mic Int Bias"}, | 276 | {"Input Mux", "Internal", "Mic Int Bias"}, |
277 | {"Input Mux", "External", "Mic Ext Bias"}, | 277 | {"Input Mux", "External", "Mic Ext Bias"}, |
278 | {"Mic Int Bias", NULL, "MICIN"}, | 278 | {"Mic Int Bias", NULL, "MICIN"}, |
279 | {"Mic Ext Bias", NULL, "MICEXT"}, | 279 | {"Mic Ext Bias", NULL, "MICEXT"}, |
280 | {"MICOUT", NULL, "Input Mux"}, | 280 | {"MICOUT", NULL, "Input Mux"}, |
281 | 281 | ||
282 | /* line out */ | 282 | /* line out */ |
283 | {"LOUT", NULL, "Line Out Enable"}, | 283 | {"LOUT", NULL, "Line Out Enable"}, |
284 | {"ROUT", NULL, "Line Out Enable"}, | 284 | {"ROUT", NULL, "Line Out Enable"}, |
285 | {"Line Out Enable", "Switch", "Line Out"}, | 285 | {"Line Out Enable", "Switch", "Line Out"}, |
286 | {"Line Out", NULL, "Stereo Mixer"}, | 286 | {"Line Out", NULL, "Stereo Mixer"}, |
287 | 287 | ||
288 | /* mono1 out */ | 288 | /* mono1 out */ |
289 | {"MOUT1", NULL, "Mono Out"}, | 289 | {"MOUT1", NULL, "Mono Out"}, |
290 | {"Mono Out", NULL, "Mono1 Mixer"}, | 290 | {"Mono Out", NULL, "Mono1 Mixer"}, |
291 | 291 | ||
292 | /* left HP */ | 292 | /* left HP */ |
293 | {"HPL", NULL, "Left HP Enable"}, | 293 | {"HPL", NULL, "Left HP Enable"}, |
294 | {"Left HP Enable", "Switch", "HP L Amp"}, | 294 | {"Left HP Enable", "Switch", "HP L Amp"}, |
295 | {"HP L Amp", NULL, "Stereo Mixer"}, | 295 | {"HP L Amp", NULL, "Stereo Mixer"}, |
296 | 296 | ||
297 | /* right HP */ | 297 | /* right HP */ |
298 | {"HPR", NULL, "Right HP Enable"}, | 298 | {"HPR", NULL, "Right HP Enable"}, |
299 | {"Right HP Enable", "Switch", "HP R Amp"}, | 299 | {"Right HP Enable", "Switch", "HP R Amp"}, |
300 | {"HP R Amp", NULL, "Stereo Mixer"}, | 300 | {"HP R Amp", NULL, "Stereo Mixer"}, |
301 | 301 | ||
302 | /* speaker */ | 302 | /* speaker */ |
303 | {"SPP", NULL, "Speaker Enable"}, | 303 | {"SPP", NULL, "Speaker Enable"}, |
304 | {"SPN", NULL, "Speaker Enable"}, | 304 | {"SPN", NULL, "Speaker Enable"}, |
305 | {"Speaker Enable", "Switch", "Spk Amp"}, | 305 | {"Speaker Enable", "Switch", "Spk Amp"}, |
306 | {"Spk Amp", NULL, "MIN"}, | 306 | {"Spk Amp", NULL, "MIN"}, |
307 | 307 | ||
308 | /* mono 2 */ | 308 | /* mono 2 */ |
309 | {"MOUT2", NULL, "Mono 2 Enable"}, | 309 | {"MOUT2", NULL, "Mono 2 Enable"}, |
310 | {"Mono 2 Enable", "Switch", "Stereo Mixer"}, | 310 | {"Mono 2 Enable", "Switch", "Stereo Mixer"}, |
311 | 311 | ||
312 | /* Aux In */ | 312 | /* Aux In */ |
313 | {"Aux In", NULL, "AUX"}, | 313 | {"Aux In", NULL, "AUX"}, |
314 | 314 | ||
315 | /* ADC */ | 315 | /* ADC */ |
316 | {"ADC", NULL, "Input Mixer"}, | 316 | {"ADC", NULL, "Input Mixer"}, |
317 | {"Input Mixer", "Mic Capture Switch", "Mic"}, | 317 | {"Input Mixer", "Mic Capture Switch", "Mic"}, |
318 | {"Input Mixer", "Aux Capture Switch", "Aux In"}, | 318 | {"Input Mixer", "Aux Capture Switch", "Aux In"}, |
319 | }; | 319 | }; |
320 | 320 | ||
321 | static int ak4535_add_widgets(struct snd_soc_codec *codec) | 321 | static int ak4535_add_widgets(struct snd_soc_codec *codec) |
322 | { | 322 | { |
323 | snd_soc_dapm_new_controls(codec, ak4535_dapm_widgets, | 323 | snd_soc_dapm_new_controls(codec, ak4535_dapm_widgets, |
324 | ARRAY_SIZE(ak4535_dapm_widgets)); | 324 | ARRAY_SIZE(ak4535_dapm_widgets)); |
325 | 325 | ||
326 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | 326 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
327 | 327 | ||
328 | snd_soc_dapm_new_widgets(codec); | 328 | snd_soc_dapm_new_widgets(codec); |
329 | return 0; | 329 | return 0; |
330 | } | 330 | } |
331 | 331 | ||
332 | static int ak4535_set_dai_sysclk(struct snd_soc_dai *codec_dai, | 332 | static int ak4535_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
333 | int clk_id, unsigned int freq, int dir) | 333 | int clk_id, unsigned int freq, int dir) |
334 | { | 334 | { |
335 | struct snd_soc_codec *codec = codec_dai->codec; | 335 | struct snd_soc_codec *codec = codec_dai->codec; |
336 | struct ak4535_priv *ak4535 = codec->private_data; | 336 | struct ak4535_priv *ak4535 = codec->private_data; |
337 | 337 | ||
338 | ak4535->sysclk = freq; | 338 | ak4535->sysclk = freq; |
339 | return 0; | 339 | return 0; |
340 | } | 340 | } |
341 | 341 | ||
342 | static int ak4535_hw_params(struct snd_pcm_substream *substream, | 342 | static int ak4535_hw_params(struct snd_pcm_substream *substream, |
343 | struct snd_pcm_hw_params *params) | 343 | struct snd_pcm_hw_params *params) |
344 | { | 344 | { |
345 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 345 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
346 | struct snd_soc_device *socdev = rtd->socdev; | 346 | struct snd_soc_device *socdev = rtd->socdev; |
347 | struct snd_soc_codec *codec = socdev->codec; | 347 | struct snd_soc_codec *codec = socdev->codec; |
348 | struct ak4535_priv *ak4535 = codec->private_data; | 348 | struct ak4535_priv *ak4535 = codec->private_data; |
349 | u8 mode2 = ak4535_read_reg_cache(codec, AK4535_MODE2) & ~(0x3 << 5); | 349 | u8 mode2 = ak4535_read_reg_cache(codec, AK4535_MODE2) & ~(0x3 << 5); |
350 | int rate = params_rate(params), fs = 256; | 350 | int rate = params_rate(params), fs = 256; |
351 | 351 | ||
352 | if (rate) | 352 | if (rate) |
353 | fs = ak4535->sysclk / rate; | 353 | fs = ak4535->sysclk / rate; |
354 | 354 | ||
355 | /* set fs */ | 355 | /* set fs */ |
356 | switch (fs) { | 356 | switch (fs) { |
357 | case 1024: | 357 | case 1024: |
358 | mode2 |= (0x2 << 5); | 358 | mode2 |= (0x2 << 5); |
359 | break; | 359 | break; |
360 | case 512: | 360 | case 512: |
361 | mode2 |= (0x1 << 5); | 361 | mode2 |= (0x1 << 5); |
362 | break; | 362 | break; |
363 | case 256: | 363 | case 256: |
364 | break; | 364 | break; |
365 | } | 365 | } |
366 | 366 | ||
367 | /* set rate */ | 367 | /* set rate */ |
368 | ak4535_write(codec, AK4535_MODE2, mode2); | 368 | ak4535_write(codec, AK4535_MODE2, mode2); |
369 | return 0; | 369 | return 0; |
370 | } | 370 | } |
371 | 371 | ||
372 | static int ak4535_set_dai_fmt(struct snd_soc_dai *codec_dai, | 372 | static int ak4535_set_dai_fmt(struct snd_soc_dai *codec_dai, |
373 | unsigned int fmt) | 373 | unsigned int fmt) |
374 | { | 374 | { |
375 | struct snd_soc_codec *codec = codec_dai->codec; | 375 | struct snd_soc_codec *codec = codec_dai->codec; |
376 | u8 mode1 = 0; | 376 | u8 mode1 = 0; |
377 | 377 | ||
378 | /* interface format */ | 378 | /* interface format */ |
379 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 379 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
380 | case SND_SOC_DAIFMT_I2S: | 380 | case SND_SOC_DAIFMT_I2S: |
381 | mode1 = 0x0002; | 381 | mode1 = 0x0002; |
382 | break; | 382 | break; |
383 | case SND_SOC_DAIFMT_LEFT_J: | 383 | case SND_SOC_DAIFMT_LEFT_J: |
384 | mode1 = 0x0001; | 384 | mode1 = 0x0001; |
385 | break; | 385 | break; |
386 | default: | 386 | default: |
387 | return -EINVAL; | 387 | return -EINVAL; |
388 | } | 388 | } |
389 | 389 | ||
390 | /* use 32 fs for BCLK to save power */ | 390 | /* use 32 fs for BCLK to save power */ |
391 | mode1 |= 0x4; | 391 | mode1 |= 0x4; |
392 | 392 | ||
393 | ak4535_write(codec, AK4535_MODE1, mode1); | 393 | ak4535_write(codec, AK4535_MODE1, mode1); |
394 | return 0; | 394 | return 0; |
395 | } | 395 | } |
396 | 396 | ||
397 | static int ak4535_mute(struct snd_soc_dai *dai, int mute) | 397 | static int ak4535_mute(struct snd_soc_dai *dai, int mute) |
398 | { | 398 | { |
399 | struct snd_soc_codec *codec = dai->codec; | 399 | struct snd_soc_codec *codec = dai->codec; |
400 | u16 mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC) & 0xffdf; | 400 | u16 mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC) & 0xffdf; |
401 | if (!mute) | 401 | if (!mute) |
402 | ak4535_write(codec, AK4535_DAC, mute_reg); | 402 | ak4535_write(codec, AK4535_DAC, mute_reg); |
403 | else | 403 | else |
404 | ak4535_write(codec, AK4535_DAC, mute_reg | 0x20); | 404 | ak4535_write(codec, AK4535_DAC, mute_reg | 0x20); |
405 | return 0; | 405 | return 0; |
406 | } | 406 | } |
407 | 407 | ||
408 | static int ak4535_set_bias_level(struct snd_soc_codec *codec, | 408 | static int ak4535_set_bias_level(struct snd_soc_codec *codec, |
409 | enum snd_soc_bias_level level) | 409 | enum snd_soc_bias_level level) |
410 | { | 410 | { |
411 | u16 i; | 411 | u16 i; |
412 | 412 | ||
413 | switch (level) { | 413 | switch (level) { |
414 | case SND_SOC_BIAS_ON: | 414 | case SND_SOC_BIAS_ON: |
415 | ak4535_mute(codec->dai, 0); | 415 | ak4535_mute(codec->dai, 0); |
416 | break; | 416 | break; |
417 | case SND_SOC_BIAS_PREPARE: | 417 | case SND_SOC_BIAS_PREPARE: |
418 | ak4535_mute(codec->dai, 1); | 418 | ak4535_mute(codec->dai, 1); |
419 | break; | 419 | break; |
420 | case SND_SOC_BIAS_STANDBY: | 420 | case SND_SOC_BIAS_STANDBY: |
421 | i = ak4535_read_reg_cache(codec, AK4535_PM1); | 421 | i = ak4535_read_reg_cache(codec, AK4535_PM1); |
422 | ak4535_write(codec, AK4535_PM1, i | 0x80); | 422 | ak4535_write(codec, AK4535_PM1, i | 0x80); |
423 | i = ak4535_read_reg_cache(codec, AK4535_PM2); | 423 | i = ak4535_read_reg_cache(codec, AK4535_PM2); |
424 | ak4535_write(codec, AK4535_PM2, i & (~0x80)); | 424 | ak4535_write(codec, AK4535_PM2, i & (~0x80)); |
425 | break; | 425 | break; |
426 | case SND_SOC_BIAS_OFF: | 426 | case SND_SOC_BIAS_OFF: |
427 | i = ak4535_read_reg_cache(codec, AK4535_PM1); | 427 | i = ak4535_read_reg_cache(codec, AK4535_PM1); |
428 | ak4535_write(codec, AK4535_PM1, i & (~0x80)); | 428 | ak4535_write(codec, AK4535_PM1, i & (~0x80)); |
429 | break; | 429 | break; |
430 | } | 430 | } |
431 | codec->bias_level = level; | 431 | codec->bias_level = level; |
432 | return 0; | 432 | return 0; |
433 | } | 433 | } |
434 | 434 | ||
435 | #define AK4535_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | 435 | #define AK4535_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ |
436 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ | 436 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ |
437 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) | 437 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) |
438 | 438 | ||
439 | struct snd_soc_dai ak4535_dai = { | 439 | struct snd_soc_dai ak4535_dai = { |
440 | .name = "AK4535", | 440 | .name = "AK4535", |
441 | .playback = { | 441 | .playback = { |
442 | .stream_name = "Playback", | 442 | .stream_name = "Playback", |
443 | .channels_min = 1, | 443 | .channels_min = 1, |
444 | .channels_max = 2, | 444 | .channels_max = 2, |
445 | .rates = AK4535_RATES, | 445 | .rates = AK4535_RATES, |
446 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | 446 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, |
447 | .capture = { | 447 | .capture = { |
448 | .stream_name = "Capture", | 448 | .stream_name = "Capture", |
449 | .channels_min = 1, | 449 | .channels_min = 1, |
450 | .channels_max = 2, | 450 | .channels_max = 2, |
451 | .rates = AK4535_RATES, | 451 | .rates = AK4535_RATES, |
452 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | 452 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, |
453 | .ops = { | 453 | .ops = { |
454 | .hw_params = ak4535_hw_params, | 454 | .hw_params = ak4535_hw_params, |
455 | }, | 455 | }, |
456 | .dai_ops = { | 456 | .dai_ops = { |
457 | .set_fmt = ak4535_set_dai_fmt, | 457 | .set_fmt = ak4535_set_dai_fmt, |
458 | .digital_mute = ak4535_mute, | 458 | .digital_mute = ak4535_mute, |
459 | .set_sysclk = ak4535_set_dai_sysclk, | 459 | .set_sysclk = ak4535_set_dai_sysclk, |
460 | }, | 460 | }, |
461 | }; | 461 | }; |
462 | EXPORT_SYMBOL_GPL(ak4535_dai); | 462 | EXPORT_SYMBOL_GPL(ak4535_dai); |
463 | 463 | ||
464 | static int ak4535_suspend(struct platform_device *pdev, pm_message_t state) | 464 | static int ak4535_suspend(struct platform_device *pdev, pm_message_t state) |
465 | { | 465 | { |
466 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 466 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
467 | struct snd_soc_codec *codec = socdev->codec; | 467 | struct snd_soc_codec *codec = socdev->codec; |
468 | 468 | ||
469 | ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF); | 469 | ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF); |
470 | return 0; | 470 | return 0; |
471 | } | 471 | } |
472 | 472 | ||
473 | static int ak4535_resume(struct platform_device *pdev) | 473 | static int ak4535_resume(struct platform_device *pdev) |
474 | { | 474 | { |
475 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 475 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
476 | struct snd_soc_codec *codec = socdev->codec; | 476 | struct snd_soc_codec *codec = socdev->codec; |
477 | ak4535_sync(codec); | 477 | ak4535_sync(codec); |
478 | ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 478 | ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
479 | ak4535_set_bias_level(codec, codec->suspend_bias_level); | 479 | ak4535_set_bias_level(codec, codec->suspend_bias_level); |
480 | return 0; | 480 | return 0; |
481 | } | 481 | } |
482 | 482 | ||
483 | /* | 483 | /* |
484 | * initialise the AK4535 driver | 484 | * initialise the AK4535 driver |
485 | * register the mixer and dsp interfaces with the kernel | 485 | * register the mixer and dsp interfaces with the kernel |
486 | */ | 486 | */ |
487 | static int ak4535_init(struct snd_soc_device *socdev) | 487 | static int ak4535_init(struct snd_soc_device *socdev) |
488 | { | 488 | { |
489 | struct snd_soc_codec *codec = socdev->codec; | 489 | struct snd_soc_codec *codec = socdev->codec; |
490 | int ret = 0; | 490 | int ret = 0; |
491 | 491 | ||
492 | codec->name = "AK4535"; | 492 | codec->name = "AK4535"; |
493 | codec->owner = THIS_MODULE; | 493 | codec->owner = THIS_MODULE; |
494 | codec->read = ak4535_read_reg_cache; | 494 | codec->read = ak4535_read_reg_cache; |
495 | codec->write = ak4535_write; | 495 | codec->write = ak4535_write; |
496 | codec->set_bias_level = ak4535_set_bias_level; | 496 | codec->set_bias_level = ak4535_set_bias_level; |
497 | codec->dai = &ak4535_dai; | 497 | codec->dai = &ak4535_dai; |
498 | codec->num_dai = 1; | 498 | codec->num_dai = 1; |
499 | codec->reg_cache_size = ARRAY_SIZE(ak4535_reg); | 499 | codec->reg_cache_size = ARRAY_SIZE(ak4535_reg); |
500 | codec->reg_cache = kmemdup(ak4535_reg, sizeof(ak4535_reg), GFP_KERNEL); | 500 | codec->reg_cache = kmemdup(ak4535_reg, sizeof(ak4535_reg), GFP_KERNEL); |
501 | 501 | ||
502 | if (codec->reg_cache == NULL) | 502 | if (codec->reg_cache == NULL) |
503 | return -ENOMEM; | 503 | return -ENOMEM; |
504 | 504 | ||
505 | /* register pcms */ | 505 | /* register pcms */ |
506 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 506 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
507 | if (ret < 0) { | 507 | if (ret < 0) { |
508 | printk(KERN_ERR "ak4535: failed to create pcms\n"); | 508 | printk(KERN_ERR "ak4535: failed to create pcms\n"); |
509 | goto pcm_err; | 509 | goto pcm_err; |
510 | } | 510 | } |
511 | 511 | ||
512 | /* power on device */ | 512 | /* power on device */ |
513 | ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 513 | ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
514 | 514 | ||
515 | ak4535_add_controls(codec); | 515 | ak4535_add_controls(codec); |
516 | ak4535_add_widgets(codec); | 516 | ak4535_add_widgets(codec); |
517 | ret = snd_soc_register_card(socdev); | 517 | ret = snd_soc_register_card(socdev); |
518 | if (ret < 0) { | 518 | if (ret < 0) { |
519 | printk(KERN_ERR "ak4535: failed to register card\n"); | 519 | printk(KERN_ERR "ak4535: failed to register card\n"); |
520 | goto card_err; | 520 | goto card_err; |
521 | } | 521 | } |
522 | 522 | ||
523 | return ret; | 523 | return ret; |
524 | 524 | ||
525 | card_err: | 525 | card_err: |
526 | snd_soc_free_pcms(socdev); | 526 | snd_soc_free_pcms(socdev); |
527 | snd_soc_dapm_free(socdev); | 527 | snd_soc_dapm_free(socdev); |
528 | pcm_err: | 528 | pcm_err: |
529 | kfree(codec->reg_cache); | 529 | kfree(codec->reg_cache); |
530 | 530 | ||
531 | return ret; | 531 | return ret; |
532 | } | 532 | } |
533 | 533 | ||
534 | static struct snd_soc_device *ak4535_socdev; | 534 | static struct snd_soc_device *ak4535_socdev; |
535 | 535 | ||
536 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 536 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
537 | 537 | ||
538 | #define I2C_DRIVERID_AK4535 0xfefe /* liam - need a proper id */ | 538 | #define I2C_DRIVERID_AK4535 0xfefe /* liam - need a proper id */ |
539 | 539 | ||
540 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | 540 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; |
541 | 541 | ||
542 | /* Magic definition of all other variables and things */ | 542 | /* Magic definition of all other variables and things */ |
543 | I2C_CLIENT_INSMOD; | 543 | I2C_CLIENT_INSMOD; |
544 | 544 | ||
545 | static struct i2c_driver ak4535_i2c_driver; | 545 | static struct i2c_driver ak4535_i2c_driver; |
546 | static struct i2c_client client_template; | 546 | static struct i2c_client client_template; |
547 | 547 | ||
548 | /* If the i2c layer weren't so broken, we could pass this kind of data | 548 | /* If the i2c layer weren't so broken, we could pass this kind of data |
549 | around */ | 549 | around */ |
550 | static int ak4535_codec_probe(struct i2c_adapter *adap, int addr, int kind) | 550 | static int ak4535_codec_probe(struct i2c_adapter *adap, int addr, int kind) |
551 | { | 551 | { |
552 | struct snd_soc_device *socdev = ak4535_socdev; | 552 | struct snd_soc_device *socdev = ak4535_socdev; |
553 | struct ak4535_setup_data *setup = socdev->codec_data; | 553 | struct ak4535_setup_data *setup = socdev->codec_data; |
554 | struct snd_soc_codec *codec = socdev->codec; | 554 | struct snd_soc_codec *codec = socdev->codec; |
555 | struct i2c_client *i2c; | 555 | struct i2c_client *i2c; |
556 | int ret; | 556 | int ret; |
557 | 557 | ||
558 | if (addr != setup->i2c_address) | 558 | if (addr != setup->i2c_address) |
559 | return -ENODEV; | 559 | return -ENODEV; |
560 | 560 | ||
561 | client_template.adapter = adap; | 561 | client_template.adapter = adap; |
562 | client_template.addr = addr; | 562 | client_template.addr = addr; |
563 | 563 | ||
564 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | 564 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); |
565 | if (i2c == NULL) { | 565 | if (i2c == NULL) |
566 | kfree(codec); | ||
567 | return -ENOMEM; | 566 | return -ENOMEM; |
568 | } | 567 | |
569 | i2c_set_clientdata(i2c, codec); | 568 | i2c_set_clientdata(i2c, codec); |
570 | codec->control_data = i2c; | 569 | codec->control_data = i2c; |
571 | 570 | ||
572 | ret = i2c_attach_client(i2c); | 571 | ret = i2c_attach_client(i2c); |
573 | if (ret < 0) { | 572 | if (ret < 0) { |
574 | printk(KERN_ERR "failed to attach codec at addr %x\n", addr); | 573 | printk(KERN_ERR "failed to attach codec at addr %x\n", addr); |
575 | goto err; | 574 | goto err; |
576 | } | 575 | } |
577 | 576 | ||
578 | ret = ak4535_init(socdev); | 577 | ret = ak4535_init(socdev); |
579 | if (ret < 0) { | 578 | if (ret < 0) { |
580 | printk(KERN_ERR "failed to initialise AK4535\n"); | 579 | printk(KERN_ERR "failed to initialise AK4535\n"); |
581 | goto err; | 580 | goto err; |
582 | } | 581 | } |
583 | return ret; | 582 | return ret; |
584 | 583 | ||
585 | err: | 584 | err: |
586 | kfree(codec); | ||
587 | kfree(i2c); | 585 | kfree(i2c); |
588 | return ret; | 586 | return ret; |
589 | } | 587 | } |
590 | 588 | ||
591 | static int ak4535_i2c_detach(struct i2c_client *client) | 589 | static int ak4535_i2c_detach(struct i2c_client *client) |
592 | { | 590 | { |
593 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 591 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
594 | i2c_detach_client(client); | 592 | i2c_detach_client(client); |
595 | kfree(codec->reg_cache); | 593 | kfree(codec->reg_cache); |
596 | kfree(client); | 594 | kfree(client); |
597 | return 0; | 595 | return 0; |
598 | } | 596 | } |
599 | 597 | ||
600 | static int ak4535_i2c_attach(struct i2c_adapter *adap) | 598 | static int ak4535_i2c_attach(struct i2c_adapter *adap) |
601 | { | 599 | { |
602 | return i2c_probe(adap, &addr_data, ak4535_codec_probe); | 600 | return i2c_probe(adap, &addr_data, ak4535_codec_probe); |
603 | } | 601 | } |
604 | 602 | ||
605 | /* corgi i2c codec control layer */ | 603 | /* corgi i2c codec control layer */ |
606 | static struct i2c_driver ak4535_i2c_driver = { | 604 | static struct i2c_driver ak4535_i2c_driver = { |
607 | .driver = { | 605 | .driver = { |
608 | .name = "AK4535 I2C Codec", | 606 | .name = "AK4535 I2C Codec", |
609 | .owner = THIS_MODULE, | 607 | .owner = THIS_MODULE, |
610 | }, | 608 | }, |
611 | .id = I2C_DRIVERID_AK4535, | 609 | .id = I2C_DRIVERID_AK4535, |
612 | .attach_adapter = ak4535_i2c_attach, | 610 | .attach_adapter = ak4535_i2c_attach, |
613 | .detach_client = ak4535_i2c_detach, | 611 | .detach_client = ak4535_i2c_detach, |
614 | .command = NULL, | 612 | .command = NULL, |
615 | }; | 613 | }; |
616 | 614 | ||
617 | static struct i2c_client client_template = { | 615 | static struct i2c_client client_template = { |
618 | .name = "AK4535", | 616 | .name = "AK4535", |
619 | .driver = &ak4535_i2c_driver, | 617 | .driver = &ak4535_i2c_driver, |
620 | }; | 618 | }; |
621 | #endif | 619 | #endif |
622 | 620 | ||
623 | static int ak4535_probe(struct platform_device *pdev) | 621 | static int ak4535_probe(struct platform_device *pdev) |
624 | { | 622 | { |
625 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 623 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
626 | struct ak4535_setup_data *setup; | 624 | struct ak4535_setup_data *setup; |
627 | struct snd_soc_codec *codec; | 625 | struct snd_soc_codec *codec; |
628 | struct ak4535_priv *ak4535; | 626 | struct ak4535_priv *ak4535; |
629 | int ret = 0; | 627 | int ret = 0; |
630 | 628 | ||
631 | printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION); | 629 | printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION); |
632 | 630 | ||
633 | setup = socdev->codec_data; | 631 | setup = socdev->codec_data; |
634 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 632 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); |
635 | if (codec == NULL) | 633 | if (codec == NULL) |
636 | return -ENOMEM; | 634 | return -ENOMEM; |
637 | 635 | ||
638 | ak4535 = kzalloc(sizeof(struct ak4535_priv), GFP_KERNEL); | 636 | ak4535 = kzalloc(sizeof(struct ak4535_priv), GFP_KERNEL); |
639 | if (ak4535 == NULL) { | 637 | if (ak4535 == NULL) { |
640 | kfree(codec); | 638 | kfree(codec); |
641 | return -ENOMEM; | 639 | return -ENOMEM; |
642 | } | 640 | } |
643 | 641 | ||
644 | codec->private_data = ak4535; | 642 | codec->private_data = ak4535; |
645 | socdev->codec = codec; | 643 | socdev->codec = codec; |
646 | mutex_init(&codec->mutex); | 644 | mutex_init(&codec->mutex); |
647 | INIT_LIST_HEAD(&codec->dapm_widgets); | 645 | INIT_LIST_HEAD(&codec->dapm_widgets); |
648 | INIT_LIST_HEAD(&codec->dapm_paths); | 646 | INIT_LIST_HEAD(&codec->dapm_paths); |
649 | 647 | ||
650 | ak4535_socdev = socdev; | 648 | ak4535_socdev = socdev; |
651 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 649 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
652 | if (setup->i2c_address) { | 650 | if (setup->i2c_address) { |
653 | normal_i2c[0] = setup->i2c_address; | 651 | normal_i2c[0] = setup->i2c_address; |
654 | codec->hw_write = (hw_write_t)i2c_master_send; | 652 | codec->hw_write = (hw_write_t)i2c_master_send; |
655 | codec->hw_read = (hw_read_t)i2c_master_recv; | 653 | codec->hw_read = (hw_read_t)i2c_master_recv; |
656 | ret = i2c_add_driver(&ak4535_i2c_driver); | 654 | ret = i2c_add_driver(&ak4535_i2c_driver); |
657 | if (ret != 0) | 655 | if (ret != 0) |
658 | printk(KERN_ERR "can't add i2c driver"); | 656 | printk(KERN_ERR "can't add i2c driver"); |
659 | } | 657 | } |
660 | #else | 658 | #else |
661 | /* Add other interfaces here */ | 659 | /* Add other interfaces here */ |
662 | #endif | 660 | #endif |
661 | |||
662 | if (ret != 0) { | ||
663 | kfree(codec->private_data); | ||
664 | kfree(codec); | ||
665 | } | ||
663 | return ret; | 666 | return ret; |
664 | } | 667 | } |
665 | 668 | ||
666 | /* power down chip */ | 669 | /* power down chip */ |
667 | static int ak4535_remove(struct platform_device *pdev) | 670 | static int ak4535_remove(struct platform_device *pdev) |
668 | { | 671 | { |
669 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 672 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
670 | struct snd_soc_codec *codec = socdev->codec; | 673 | struct snd_soc_codec *codec = socdev->codec; |
671 | 674 | ||
672 | if (codec->control_data) | 675 | if (codec->control_data) |
673 | ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF); | 676 | ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF); |
674 | 677 | ||
675 | snd_soc_free_pcms(socdev); | 678 | snd_soc_free_pcms(socdev); |
676 | snd_soc_dapm_free(socdev); | 679 | snd_soc_dapm_free(socdev); |
677 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 680 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
678 | i2c_del_driver(&ak4535_i2c_driver); | 681 | i2c_del_driver(&ak4535_i2c_driver); |
679 | #endif | 682 | #endif |
680 | kfree(codec->private_data); | 683 | kfree(codec->private_data); |
681 | kfree(codec); | 684 | kfree(codec); |
682 | 685 | ||
683 | return 0; | 686 | return 0; |
684 | } | 687 | } |
685 | 688 | ||
686 | struct snd_soc_codec_device soc_codec_dev_ak4535 = { | 689 | struct snd_soc_codec_device soc_codec_dev_ak4535 = { |
687 | .probe = ak4535_probe, | 690 | .probe = ak4535_probe, |
688 | .remove = ak4535_remove, | 691 | .remove = ak4535_remove, |
689 | .suspend = ak4535_suspend, | 692 | .suspend = ak4535_suspend, |
690 | .resume = ak4535_resume, | 693 | .resume = ak4535_resume, |
691 | }; | 694 | }; |
692 | EXPORT_SYMBOL_GPL(soc_codec_dev_ak4535); | 695 | EXPORT_SYMBOL_GPL(soc_codec_dev_ak4535); |
693 | 696 | ||
694 | MODULE_DESCRIPTION("Soc AK4535 driver"); | 697 | MODULE_DESCRIPTION("Soc AK4535 driver"); |
695 | MODULE_AUTHOR("Richard Purdie"); | 698 | MODULE_AUTHOR("Richard Purdie"); |
sound/soc/codecs/tlv320aic3x.c
1 | /* | 1 | /* |
2 | * ALSA SoC TLV320AIC3X codec driver | 2 | * ALSA SoC TLV320AIC3X codec driver |
3 | * | 3 | * |
4 | * Author: Vladimir Barinov, <vbarinov@ru.mvista.com> | 4 | * Author: Vladimir Barinov, <vbarinov@ru.mvista.com> |
5 | * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> | 5 | * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> |
6 | * | 6 | * |
7 | * Based on sound/soc/codecs/wm8753.c by Liam Girdwood | 7 | * Based on sound/soc/codecs/wm8753.c by Liam Girdwood |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
12 | * | 12 | * |
13 | * Notes: | 13 | * Notes: |
14 | * The AIC3X is a driver for a low power stereo audio | 14 | * The AIC3X is a driver for a low power stereo audio |
15 | * codecs aic31, aic32, aic33. | 15 | * codecs aic31, aic32, aic33. |
16 | * | 16 | * |
17 | * It supports full aic33 codec functionality. | 17 | * It supports full aic33 codec functionality. |
18 | * The compatibility with aic32, aic31 is as follows: | 18 | * The compatibility with aic32, aic31 is as follows: |
19 | * aic32 | aic31 | 19 | * aic32 | aic31 |
20 | * --------------------------------------- | 20 | * --------------------------------------- |
21 | * MONO_LOUT -> N/A | MONO_LOUT -> N/A | 21 | * MONO_LOUT -> N/A | MONO_LOUT -> N/A |
22 | * | IN1L -> LINE1L | 22 | * | IN1L -> LINE1L |
23 | * | IN1R -> LINE1R | 23 | * | IN1R -> LINE1R |
24 | * | IN2L -> LINE2L | 24 | * | IN2L -> LINE2L |
25 | * | IN2R -> LINE2R | 25 | * | IN2R -> LINE2R |
26 | * | MIC3L/R -> N/A | 26 | * | MIC3L/R -> N/A |
27 | * truncated internal functionality in | 27 | * truncated internal functionality in |
28 | * accordance with documentation | 28 | * accordance with documentation |
29 | * --------------------------------------- | 29 | * --------------------------------------- |
30 | * | 30 | * |
31 | * Hence the machine layer should disable unsupported inputs/outputs by | 31 | * Hence the machine layer should disable unsupported inputs/outputs by |
32 | * snd_soc_dapm_disable_pin(codec, "MONO_LOUT"), etc. | 32 | * snd_soc_dapm_disable_pin(codec, "MONO_LOUT"), etc. |
33 | */ | 33 | */ |
34 | 34 | ||
35 | #include <linux/module.h> | 35 | #include <linux/module.h> |
36 | #include <linux/moduleparam.h> | 36 | #include <linux/moduleparam.h> |
37 | #include <linux/init.h> | 37 | #include <linux/init.h> |
38 | #include <linux/delay.h> | 38 | #include <linux/delay.h> |
39 | #include <linux/pm.h> | 39 | #include <linux/pm.h> |
40 | #include <linux/i2c.h> | 40 | #include <linux/i2c.h> |
41 | #include <linux/platform_device.h> | 41 | #include <linux/platform_device.h> |
42 | #include <sound/core.h> | 42 | #include <sound/core.h> |
43 | #include <sound/pcm.h> | 43 | #include <sound/pcm.h> |
44 | #include <sound/pcm_params.h> | 44 | #include <sound/pcm_params.h> |
45 | #include <sound/soc.h> | 45 | #include <sound/soc.h> |
46 | #include <sound/soc-dapm.h> | 46 | #include <sound/soc-dapm.h> |
47 | #include <sound/initval.h> | 47 | #include <sound/initval.h> |
48 | 48 | ||
49 | #include "tlv320aic3x.h" | 49 | #include "tlv320aic3x.h" |
50 | 50 | ||
51 | #define AUDIO_NAME "aic3x" | 51 | #define AUDIO_NAME "aic3x" |
52 | #define AIC3X_VERSION "0.2" | 52 | #define AIC3X_VERSION "0.2" |
53 | 53 | ||
54 | /* codec private data */ | 54 | /* codec private data */ |
55 | struct aic3x_priv { | 55 | struct aic3x_priv { |
56 | unsigned int sysclk; | 56 | unsigned int sysclk; |
57 | int master; | 57 | int master; |
58 | }; | 58 | }; |
59 | 59 | ||
60 | /* | 60 | /* |
61 | * AIC3X register cache | 61 | * AIC3X register cache |
62 | * We can't read the AIC3X register space when we are | 62 | * We can't read the AIC3X register space when we are |
63 | * using 2 wire for device control, so we cache them instead. | 63 | * using 2 wire for device control, so we cache them instead. |
64 | * There is no point in caching the reset register | 64 | * There is no point in caching the reset register |
65 | */ | 65 | */ |
66 | static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = { | 66 | static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = { |
67 | 0x00, 0x00, 0x00, 0x10, /* 0 */ | 67 | 0x00, 0x00, 0x00, 0x10, /* 0 */ |
68 | 0x04, 0x00, 0x00, 0x00, /* 4 */ | 68 | 0x04, 0x00, 0x00, 0x00, /* 4 */ |
69 | 0x00, 0x00, 0x00, 0x01, /* 8 */ | 69 | 0x00, 0x00, 0x00, 0x01, /* 8 */ |
70 | 0x00, 0x00, 0x00, 0x80, /* 12 */ | 70 | 0x00, 0x00, 0x00, 0x80, /* 12 */ |
71 | 0x80, 0xff, 0xff, 0x78, /* 16 */ | 71 | 0x80, 0xff, 0xff, 0x78, /* 16 */ |
72 | 0x78, 0x78, 0x78, 0x78, /* 20 */ | 72 | 0x78, 0x78, 0x78, 0x78, /* 20 */ |
73 | 0x78, 0x00, 0x00, 0xfe, /* 24 */ | 73 | 0x78, 0x00, 0x00, 0xfe, /* 24 */ |
74 | 0x00, 0x00, 0xfe, 0x00, /* 28 */ | 74 | 0x00, 0x00, 0xfe, 0x00, /* 28 */ |
75 | 0x18, 0x18, 0x00, 0x00, /* 32 */ | 75 | 0x18, 0x18, 0x00, 0x00, /* 32 */ |
76 | 0x00, 0x00, 0x00, 0x00, /* 36 */ | 76 | 0x00, 0x00, 0x00, 0x00, /* 36 */ |
77 | 0x00, 0x00, 0x00, 0x80, /* 40 */ | 77 | 0x00, 0x00, 0x00, 0x80, /* 40 */ |
78 | 0x80, 0x00, 0x00, 0x00, /* 44 */ | 78 | 0x80, 0x00, 0x00, 0x00, /* 44 */ |
79 | 0x00, 0x00, 0x00, 0x04, /* 48 */ | 79 | 0x00, 0x00, 0x00, 0x04, /* 48 */ |
80 | 0x00, 0x00, 0x00, 0x00, /* 52 */ | 80 | 0x00, 0x00, 0x00, 0x00, /* 52 */ |
81 | 0x00, 0x00, 0x04, 0x00, /* 56 */ | 81 | 0x00, 0x00, 0x04, 0x00, /* 56 */ |
82 | 0x00, 0x00, 0x00, 0x00, /* 60 */ | 82 | 0x00, 0x00, 0x00, 0x00, /* 60 */ |
83 | 0x00, 0x04, 0x00, 0x00, /* 64 */ | 83 | 0x00, 0x04, 0x00, 0x00, /* 64 */ |
84 | 0x00, 0x00, 0x00, 0x00, /* 68 */ | 84 | 0x00, 0x00, 0x00, 0x00, /* 68 */ |
85 | 0x04, 0x00, 0x00, 0x00, /* 72 */ | 85 | 0x04, 0x00, 0x00, 0x00, /* 72 */ |
86 | 0x00, 0x00, 0x00, 0x00, /* 76 */ | 86 | 0x00, 0x00, 0x00, 0x00, /* 76 */ |
87 | 0x00, 0x00, 0x00, 0x00, /* 80 */ | 87 | 0x00, 0x00, 0x00, 0x00, /* 80 */ |
88 | 0x00, 0x00, 0x00, 0x00, /* 84 */ | 88 | 0x00, 0x00, 0x00, 0x00, /* 84 */ |
89 | 0x00, 0x00, 0x00, 0x00, /* 88 */ | 89 | 0x00, 0x00, 0x00, 0x00, /* 88 */ |
90 | 0x00, 0x00, 0x00, 0x00, /* 92 */ | 90 | 0x00, 0x00, 0x00, 0x00, /* 92 */ |
91 | 0x00, 0x00, 0x00, 0x00, /* 96 */ | 91 | 0x00, 0x00, 0x00, 0x00, /* 96 */ |
92 | 0x00, 0x00, 0x02, /* 100 */ | 92 | 0x00, 0x00, 0x02, /* 100 */ |
93 | }; | 93 | }; |
94 | 94 | ||
95 | /* | 95 | /* |
96 | * read aic3x register cache | 96 | * read aic3x register cache |
97 | */ | 97 | */ |
98 | static inline unsigned int aic3x_read_reg_cache(struct snd_soc_codec *codec, | 98 | static inline unsigned int aic3x_read_reg_cache(struct snd_soc_codec *codec, |
99 | unsigned int reg) | 99 | unsigned int reg) |
100 | { | 100 | { |
101 | u8 *cache = codec->reg_cache; | 101 | u8 *cache = codec->reg_cache; |
102 | if (reg >= AIC3X_CACHEREGNUM) | 102 | if (reg >= AIC3X_CACHEREGNUM) |
103 | return -1; | 103 | return -1; |
104 | return cache[reg]; | 104 | return cache[reg]; |
105 | } | 105 | } |
106 | 106 | ||
107 | /* | 107 | /* |
108 | * write aic3x register cache | 108 | * write aic3x register cache |
109 | */ | 109 | */ |
110 | static inline void aic3x_write_reg_cache(struct snd_soc_codec *codec, | 110 | static inline void aic3x_write_reg_cache(struct snd_soc_codec *codec, |
111 | u8 reg, u8 value) | 111 | u8 reg, u8 value) |
112 | { | 112 | { |
113 | u8 *cache = codec->reg_cache; | 113 | u8 *cache = codec->reg_cache; |
114 | if (reg >= AIC3X_CACHEREGNUM) | 114 | if (reg >= AIC3X_CACHEREGNUM) |
115 | return; | 115 | return; |
116 | cache[reg] = value; | 116 | cache[reg] = value; |
117 | } | 117 | } |
118 | 118 | ||
119 | /* | 119 | /* |
120 | * write to the aic3x register space | 120 | * write to the aic3x register space |
121 | */ | 121 | */ |
122 | static int aic3x_write(struct snd_soc_codec *codec, unsigned int reg, | 122 | static int aic3x_write(struct snd_soc_codec *codec, unsigned int reg, |
123 | unsigned int value) | 123 | unsigned int value) |
124 | { | 124 | { |
125 | u8 data[2]; | 125 | u8 data[2]; |
126 | 126 | ||
127 | /* data is | 127 | /* data is |
128 | * D15..D8 aic3x register offset | 128 | * D15..D8 aic3x register offset |
129 | * D7...D0 register data | 129 | * D7...D0 register data |
130 | */ | 130 | */ |
131 | data[0] = reg & 0xff; | 131 | data[0] = reg & 0xff; |
132 | data[1] = value & 0xff; | 132 | data[1] = value & 0xff; |
133 | 133 | ||
134 | aic3x_write_reg_cache(codec, data[0], data[1]); | 134 | aic3x_write_reg_cache(codec, data[0], data[1]); |
135 | if (codec->hw_write(codec->control_data, data, 2) == 2) | 135 | if (codec->hw_write(codec->control_data, data, 2) == 2) |
136 | return 0; | 136 | return 0; |
137 | else | 137 | else |
138 | return -EIO; | 138 | return -EIO; |
139 | } | 139 | } |
140 | 140 | ||
141 | /* | 141 | /* |
142 | * read from the aic3x register space | 142 | * read from the aic3x register space |
143 | */ | 143 | */ |
144 | static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg, | 144 | static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg, |
145 | u8 *value) | 145 | u8 *value) |
146 | { | 146 | { |
147 | *value = reg & 0xff; | 147 | *value = reg & 0xff; |
148 | if (codec->hw_read(codec->control_data, value, 1) != 1) | 148 | if (codec->hw_read(codec->control_data, value, 1) != 1) |
149 | return -EIO; | 149 | return -EIO; |
150 | 150 | ||
151 | aic3x_write_reg_cache(codec, reg, *value); | 151 | aic3x_write_reg_cache(codec, reg, *value); |
152 | return 0; | 152 | return 0; |
153 | } | 153 | } |
154 | 154 | ||
155 | #define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \ | 155 | #define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \ |
156 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 156 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
157 | .info = snd_soc_info_volsw, \ | 157 | .info = snd_soc_info_volsw, \ |
158 | .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw_aic3x, \ | 158 | .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw_aic3x, \ |
159 | .private_value = SOC_SINGLE_VALUE(reg, shift, mask, invert) } | 159 | .private_value = SOC_SINGLE_VALUE(reg, shift, mask, invert) } |
160 | 160 | ||
161 | /* | 161 | /* |
162 | * All input lines are connected when !0xf and disconnected with 0xf bit field, | 162 | * All input lines are connected when !0xf and disconnected with 0xf bit field, |
163 | * so we have to use specific dapm_put call for input mixer | 163 | * so we have to use specific dapm_put call for input mixer |
164 | */ | 164 | */ |
165 | static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol, | 165 | static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol, |
166 | struct snd_ctl_elem_value *ucontrol) | 166 | struct snd_ctl_elem_value *ucontrol) |
167 | { | 167 | { |
168 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | 168 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); |
169 | int reg = kcontrol->private_value & 0xff; | 169 | int reg = kcontrol->private_value & 0xff; |
170 | int shift = (kcontrol->private_value >> 8) & 0x0f; | 170 | int shift = (kcontrol->private_value >> 8) & 0x0f; |
171 | int mask = (kcontrol->private_value >> 16) & 0xff; | 171 | int mask = (kcontrol->private_value >> 16) & 0xff; |
172 | int invert = (kcontrol->private_value >> 24) & 0x01; | 172 | int invert = (kcontrol->private_value >> 24) & 0x01; |
173 | unsigned short val, val_mask; | 173 | unsigned short val, val_mask; |
174 | int ret; | 174 | int ret; |
175 | struct snd_soc_dapm_path *path; | 175 | struct snd_soc_dapm_path *path; |
176 | int found = 0; | 176 | int found = 0; |
177 | 177 | ||
178 | val = (ucontrol->value.integer.value[0] & mask); | 178 | val = (ucontrol->value.integer.value[0] & mask); |
179 | 179 | ||
180 | mask = 0xf; | 180 | mask = 0xf; |
181 | if (val) | 181 | if (val) |
182 | val = mask; | 182 | val = mask; |
183 | 183 | ||
184 | if (invert) | 184 | if (invert) |
185 | val = mask - val; | 185 | val = mask - val; |
186 | val_mask = mask << shift; | 186 | val_mask = mask << shift; |
187 | val = val << shift; | 187 | val = val << shift; |
188 | 188 | ||
189 | mutex_lock(&widget->codec->mutex); | 189 | mutex_lock(&widget->codec->mutex); |
190 | 190 | ||
191 | if (snd_soc_test_bits(widget->codec, reg, val_mask, val)) { | 191 | if (snd_soc_test_bits(widget->codec, reg, val_mask, val)) { |
192 | /* find dapm widget path assoc with kcontrol */ | 192 | /* find dapm widget path assoc with kcontrol */ |
193 | list_for_each_entry(path, &widget->codec->dapm_paths, list) { | 193 | list_for_each_entry(path, &widget->codec->dapm_paths, list) { |
194 | if (path->kcontrol != kcontrol) | 194 | if (path->kcontrol != kcontrol) |
195 | continue; | 195 | continue; |
196 | 196 | ||
197 | /* found, now check type */ | 197 | /* found, now check type */ |
198 | found = 1; | 198 | found = 1; |
199 | if (val) | 199 | if (val) |
200 | /* new connection */ | 200 | /* new connection */ |
201 | path->connect = invert ? 0 : 1; | 201 | path->connect = invert ? 0 : 1; |
202 | else | 202 | else |
203 | /* old connection must be powered down */ | 203 | /* old connection must be powered down */ |
204 | path->connect = invert ? 1 : 0; | 204 | path->connect = invert ? 1 : 0; |
205 | break; | 205 | break; |
206 | } | 206 | } |
207 | 207 | ||
208 | if (found) | 208 | if (found) |
209 | snd_soc_dapm_sync(widget->codec); | 209 | snd_soc_dapm_sync(widget->codec); |
210 | } | 210 | } |
211 | 211 | ||
212 | ret = snd_soc_update_bits(widget->codec, reg, val_mask, val); | 212 | ret = snd_soc_update_bits(widget->codec, reg, val_mask, val); |
213 | 213 | ||
214 | mutex_unlock(&widget->codec->mutex); | 214 | mutex_unlock(&widget->codec->mutex); |
215 | return ret; | 215 | return ret; |
216 | } | 216 | } |
217 | 217 | ||
218 | static const char *aic3x_left_dac_mux[] = { "DAC_L1", "DAC_L3", "DAC_L2" }; | 218 | static const char *aic3x_left_dac_mux[] = { "DAC_L1", "DAC_L3", "DAC_L2" }; |
219 | static const char *aic3x_right_dac_mux[] = { "DAC_R1", "DAC_R3", "DAC_R2" }; | 219 | static const char *aic3x_right_dac_mux[] = { "DAC_R1", "DAC_R3", "DAC_R2" }; |
220 | static const char *aic3x_left_hpcom_mux[] = | 220 | static const char *aic3x_left_hpcom_mux[] = |
221 | { "differential of HPLOUT", "constant VCM", "single-ended" }; | 221 | { "differential of HPLOUT", "constant VCM", "single-ended" }; |
222 | static const char *aic3x_right_hpcom_mux[] = | 222 | static const char *aic3x_right_hpcom_mux[] = |
223 | { "differential of HPROUT", "constant VCM", "single-ended", | 223 | { "differential of HPROUT", "constant VCM", "single-ended", |
224 | "differential of HPLCOM", "external feedback" }; | 224 | "differential of HPLCOM", "external feedback" }; |
225 | static const char *aic3x_linein_mode_mux[] = { "single-ended", "differential" }; | 225 | static const char *aic3x_linein_mode_mux[] = { "single-ended", "differential" }; |
226 | static const char *aic3x_adc_hpf[] = | 226 | static const char *aic3x_adc_hpf[] = |
227 | { "Disabled", "0.0045xFs", "0.0125xFs", "0.025xFs" }; | 227 | { "Disabled", "0.0045xFs", "0.0125xFs", "0.025xFs" }; |
228 | 228 | ||
229 | #define LDAC_ENUM 0 | 229 | #define LDAC_ENUM 0 |
230 | #define RDAC_ENUM 1 | 230 | #define RDAC_ENUM 1 |
231 | #define LHPCOM_ENUM 2 | 231 | #define LHPCOM_ENUM 2 |
232 | #define RHPCOM_ENUM 3 | 232 | #define RHPCOM_ENUM 3 |
233 | #define LINE1L_ENUM 4 | 233 | #define LINE1L_ENUM 4 |
234 | #define LINE1R_ENUM 5 | 234 | #define LINE1R_ENUM 5 |
235 | #define LINE2L_ENUM 6 | 235 | #define LINE2L_ENUM 6 |
236 | #define LINE2R_ENUM 7 | 236 | #define LINE2R_ENUM 7 |
237 | #define ADC_HPF_ENUM 8 | 237 | #define ADC_HPF_ENUM 8 |
238 | 238 | ||
239 | static const struct soc_enum aic3x_enum[] = { | 239 | static const struct soc_enum aic3x_enum[] = { |
240 | SOC_ENUM_SINGLE(DAC_LINE_MUX, 6, 3, aic3x_left_dac_mux), | 240 | SOC_ENUM_SINGLE(DAC_LINE_MUX, 6, 3, aic3x_left_dac_mux), |
241 | SOC_ENUM_SINGLE(DAC_LINE_MUX, 4, 3, aic3x_right_dac_mux), | 241 | SOC_ENUM_SINGLE(DAC_LINE_MUX, 4, 3, aic3x_right_dac_mux), |
242 | SOC_ENUM_SINGLE(HPLCOM_CFG, 4, 3, aic3x_left_hpcom_mux), | 242 | SOC_ENUM_SINGLE(HPLCOM_CFG, 4, 3, aic3x_left_hpcom_mux), |
243 | SOC_ENUM_SINGLE(HPRCOM_CFG, 3, 5, aic3x_right_hpcom_mux), | 243 | SOC_ENUM_SINGLE(HPRCOM_CFG, 3, 5, aic3x_right_hpcom_mux), |
244 | SOC_ENUM_SINGLE(LINE1L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux), | 244 | SOC_ENUM_SINGLE(LINE1L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux), |
245 | SOC_ENUM_SINGLE(LINE1R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), | 245 | SOC_ENUM_SINGLE(LINE1R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), |
246 | SOC_ENUM_SINGLE(LINE2L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux), | 246 | SOC_ENUM_SINGLE(LINE2L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux), |
247 | SOC_ENUM_SINGLE(LINE2R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), | 247 | SOC_ENUM_SINGLE(LINE2R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), |
248 | SOC_ENUM_DOUBLE(AIC3X_CODEC_DFILT_CTRL, 6, 4, 4, aic3x_adc_hpf), | 248 | SOC_ENUM_DOUBLE(AIC3X_CODEC_DFILT_CTRL, 6, 4, 4, aic3x_adc_hpf), |
249 | }; | 249 | }; |
250 | 250 | ||
251 | static const struct snd_kcontrol_new aic3x_snd_controls[] = { | 251 | static const struct snd_kcontrol_new aic3x_snd_controls[] = { |
252 | /* Output */ | 252 | /* Output */ |
253 | SOC_DOUBLE_R("PCM Playback Volume", LDAC_VOL, RDAC_VOL, 0, 0x7f, 1), | 253 | SOC_DOUBLE_R("PCM Playback Volume", LDAC_VOL, RDAC_VOL, 0, 0x7f, 1), |
254 | 254 | ||
255 | SOC_DOUBLE_R("Line DAC Playback Volume", DACL1_2_LLOPM_VOL, | 255 | SOC_DOUBLE_R("Line DAC Playback Volume", DACL1_2_LLOPM_VOL, |
256 | DACR1_2_RLOPM_VOL, 0, 0x7f, 1), | 256 | DACR1_2_RLOPM_VOL, 0, 0x7f, 1), |
257 | SOC_DOUBLE_R("Line DAC Playback Switch", LLOPM_CTRL, RLOPM_CTRL, 3, | 257 | SOC_DOUBLE_R("Line DAC Playback Switch", LLOPM_CTRL, RLOPM_CTRL, 3, |
258 | 0x01, 0), | 258 | 0x01, 0), |
259 | SOC_DOUBLE_R("Line PGA Bypass Playback Volume", PGAL_2_LLOPM_VOL, | 259 | SOC_DOUBLE_R("Line PGA Bypass Playback Volume", PGAL_2_LLOPM_VOL, |
260 | PGAR_2_RLOPM_VOL, 0, 0x7f, 1), | 260 | PGAR_2_RLOPM_VOL, 0, 0x7f, 1), |
261 | SOC_DOUBLE_R("Line Line2 Bypass Playback Volume", LINE2L_2_LLOPM_VOL, | 261 | SOC_DOUBLE_R("Line Line2 Bypass Playback Volume", LINE2L_2_LLOPM_VOL, |
262 | LINE2R_2_RLOPM_VOL, 0, 0x7f, 1), | 262 | LINE2R_2_RLOPM_VOL, 0, 0x7f, 1), |
263 | 263 | ||
264 | SOC_DOUBLE_R("Mono DAC Playback Volume", DACL1_2_MONOLOPM_VOL, | 264 | SOC_DOUBLE_R("Mono DAC Playback Volume", DACL1_2_MONOLOPM_VOL, |
265 | DACR1_2_MONOLOPM_VOL, 0, 0x7f, 1), | 265 | DACR1_2_MONOLOPM_VOL, 0, 0x7f, 1), |
266 | SOC_SINGLE("Mono DAC Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0), | 266 | SOC_SINGLE("Mono DAC Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0), |
267 | SOC_DOUBLE_R("Mono PGA Bypass Playback Volume", PGAL_2_MONOLOPM_VOL, | 267 | SOC_DOUBLE_R("Mono PGA Bypass Playback Volume", PGAL_2_MONOLOPM_VOL, |
268 | PGAR_2_MONOLOPM_VOL, 0, 0x7f, 1), | 268 | PGAR_2_MONOLOPM_VOL, 0, 0x7f, 1), |
269 | SOC_DOUBLE_R("Mono Line2 Bypass Playback Volume", LINE2L_2_MONOLOPM_VOL, | 269 | SOC_DOUBLE_R("Mono Line2 Bypass Playback Volume", LINE2L_2_MONOLOPM_VOL, |
270 | LINE2R_2_MONOLOPM_VOL, 0, 0x7f, 1), | 270 | LINE2R_2_MONOLOPM_VOL, 0, 0x7f, 1), |
271 | 271 | ||
272 | SOC_DOUBLE_R("HP DAC Playback Volume", DACL1_2_HPLOUT_VOL, | 272 | SOC_DOUBLE_R("HP DAC Playback Volume", DACL1_2_HPLOUT_VOL, |
273 | DACR1_2_HPROUT_VOL, 0, 0x7f, 1), | 273 | DACR1_2_HPROUT_VOL, 0, 0x7f, 1), |
274 | SOC_DOUBLE_R("HP DAC Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3, | 274 | SOC_DOUBLE_R("HP DAC Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3, |
275 | 0x01, 0), | 275 | 0x01, 0), |
276 | SOC_DOUBLE_R("HP PGA Bypass Playback Volume", PGAL_2_HPLOUT_VOL, | 276 | SOC_DOUBLE_R("HP PGA Bypass Playback Volume", PGAL_2_HPLOUT_VOL, |
277 | PGAR_2_HPROUT_VOL, 0, 0x7f, 1), | 277 | PGAR_2_HPROUT_VOL, 0, 0x7f, 1), |
278 | SOC_DOUBLE_R("HP Line2 Bypass Playback Volume", LINE2L_2_HPLOUT_VOL, | 278 | SOC_DOUBLE_R("HP Line2 Bypass Playback Volume", LINE2L_2_HPLOUT_VOL, |
279 | LINE2R_2_HPROUT_VOL, 0, 0x7f, 1), | 279 | LINE2R_2_HPROUT_VOL, 0, 0x7f, 1), |
280 | 280 | ||
281 | SOC_DOUBLE_R("HPCOM DAC Playback Volume", DACL1_2_HPLCOM_VOL, | 281 | SOC_DOUBLE_R("HPCOM DAC Playback Volume", DACL1_2_HPLCOM_VOL, |
282 | DACR1_2_HPRCOM_VOL, 0, 0x7f, 1), | 282 | DACR1_2_HPRCOM_VOL, 0, 0x7f, 1), |
283 | SOC_DOUBLE_R("HPCOM DAC Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3, | 283 | SOC_DOUBLE_R("HPCOM DAC Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3, |
284 | 0x01, 0), | 284 | 0x01, 0), |
285 | SOC_DOUBLE_R("HPCOM PGA Bypass Playback Volume", PGAL_2_HPLCOM_VOL, | 285 | SOC_DOUBLE_R("HPCOM PGA Bypass Playback Volume", PGAL_2_HPLCOM_VOL, |
286 | PGAR_2_HPRCOM_VOL, 0, 0x7f, 1), | 286 | PGAR_2_HPRCOM_VOL, 0, 0x7f, 1), |
287 | SOC_DOUBLE_R("HPCOM Line2 Bypass Playback Volume", LINE2L_2_HPLCOM_VOL, | 287 | SOC_DOUBLE_R("HPCOM Line2 Bypass Playback Volume", LINE2L_2_HPLCOM_VOL, |
288 | LINE2R_2_HPRCOM_VOL, 0, 0x7f, 1), | 288 | LINE2R_2_HPRCOM_VOL, 0, 0x7f, 1), |
289 | 289 | ||
290 | /* | 290 | /* |
291 | * Note: enable Automatic input Gain Controller with care. It can | 291 | * Note: enable Automatic input Gain Controller with care. It can |
292 | * adjust PGA to max value when ADC is on and will never go back. | 292 | * adjust PGA to max value when ADC is on and will never go back. |
293 | */ | 293 | */ |
294 | SOC_DOUBLE_R("AGC Switch", LAGC_CTRL_A, RAGC_CTRL_A, 7, 0x01, 0), | 294 | SOC_DOUBLE_R("AGC Switch", LAGC_CTRL_A, RAGC_CTRL_A, 7, 0x01, 0), |
295 | 295 | ||
296 | /* Input */ | 296 | /* Input */ |
297 | SOC_DOUBLE_R("PGA Capture Volume", LADC_VOL, RADC_VOL, 0, 0x7f, 0), | 297 | SOC_DOUBLE_R("PGA Capture Volume", LADC_VOL, RADC_VOL, 0, 0x7f, 0), |
298 | SOC_DOUBLE_R("PGA Capture Switch", LADC_VOL, RADC_VOL, 7, 0x01, 1), | 298 | SOC_DOUBLE_R("PGA Capture Switch", LADC_VOL, RADC_VOL, 7, 0x01, 1), |
299 | 299 | ||
300 | SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]), | 300 | SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]), |
301 | }; | 301 | }; |
302 | 302 | ||
303 | /* add non dapm controls */ | 303 | /* add non dapm controls */ |
304 | static int aic3x_add_controls(struct snd_soc_codec *codec) | 304 | static int aic3x_add_controls(struct snd_soc_codec *codec) |
305 | { | 305 | { |
306 | int err, i; | 306 | int err, i; |
307 | 307 | ||
308 | for (i = 0; i < ARRAY_SIZE(aic3x_snd_controls); i++) { | 308 | for (i = 0; i < ARRAY_SIZE(aic3x_snd_controls); i++) { |
309 | err = snd_ctl_add(codec->card, | 309 | err = snd_ctl_add(codec->card, |
310 | snd_soc_cnew(&aic3x_snd_controls[i], | 310 | snd_soc_cnew(&aic3x_snd_controls[i], |
311 | codec, NULL)); | 311 | codec, NULL)); |
312 | if (err < 0) | 312 | if (err < 0) |
313 | return err; | 313 | return err; |
314 | } | 314 | } |
315 | 315 | ||
316 | return 0; | 316 | return 0; |
317 | } | 317 | } |
318 | 318 | ||
319 | /* Left DAC Mux */ | 319 | /* Left DAC Mux */ |
320 | static const struct snd_kcontrol_new aic3x_left_dac_mux_controls = | 320 | static const struct snd_kcontrol_new aic3x_left_dac_mux_controls = |
321 | SOC_DAPM_ENUM("Route", aic3x_enum[LDAC_ENUM]); | 321 | SOC_DAPM_ENUM("Route", aic3x_enum[LDAC_ENUM]); |
322 | 322 | ||
323 | /* Right DAC Mux */ | 323 | /* Right DAC Mux */ |
324 | static const struct snd_kcontrol_new aic3x_right_dac_mux_controls = | 324 | static const struct snd_kcontrol_new aic3x_right_dac_mux_controls = |
325 | SOC_DAPM_ENUM("Route", aic3x_enum[RDAC_ENUM]); | 325 | SOC_DAPM_ENUM("Route", aic3x_enum[RDAC_ENUM]); |
326 | 326 | ||
327 | /* Left HPCOM Mux */ | 327 | /* Left HPCOM Mux */ |
328 | static const struct snd_kcontrol_new aic3x_left_hpcom_mux_controls = | 328 | static const struct snd_kcontrol_new aic3x_left_hpcom_mux_controls = |
329 | SOC_DAPM_ENUM("Route", aic3x_enum[LHPCOM_ENUM]); | 329 | SOC_DAPM_ENUM("Route", aic3x_enum[LHPCOM_ENUM]); |
330 | 330 | ||
331 | /* Right HPCOM Mux */ | 331 | /* Right HPCOM Mux */ |
332 | static const struct snd_kcontrol_new aic3x_right_hpcom_mux_controls = | 332 | static const struct snd_kcontrol_new aic3x_right_hpcom_mux_controls = |
333 | SOC_DAPM_ENUM("Route", aic3x_enum[RHPCOM_ENUM]); | 333 | SOC_DAPM_ENUM("Route", aic3x_enum[RHPCOM_ENUM]); |
334 | 334 | ||
335 | /* Left DAC_L1 Mixer */ | 335 | /* Left DAC_L1 Mixer */ |
336 | static const struct snd_kcontrol_new aic3x_left_dac_mixer_controls[] = { | 336 | static const struct snd_kcontrol_new aic3x_left_dac_mixer_controls[] = { |
337 | SOC_DAPM_SINGLE("Line Switch", DACL1_2_LLOPM_VOL, 7, 1, 0), | 337 | SOC_DAPM_SINGLE("Line Switch", DACL1_2_LLOPM_VOL, 7, 1, 0), |
338 | SOC_DAPM_SINGLE("Mono Switch", DACL1_2_MONOLOPM_VOL, 7, 1, 0), | 338 | SOC_DAPM_SINGLE("Mono Switch", DACL1_2_MONOLOPM_VOL, 7, 1, 0), |
339 | SOC_DAPM_SINGLE("HP Switch", DACL1_2_HPLOUT_VOL, 7, 1, 0), | 339 | SOC_DAPM_SINGLE("HP Switch", DACL1_2_HPLOUT_VOL, 7, 1, 0), |
340 | SOC_DAPM_SINGLE("HPCOM Switch", DACL1_2_HPLCOM_VOL, 7, 1, 0), | 340 | SOC_DAPM_SINGLE("HPCOM Switch", DACL1_2_HPLCOM_VOL, 7, 1, 0), |
341 | }; | 341 | }; |
342 | 342 | ||
343 | /* Right DAC_R1 Mixer */ | 343 | /* Right DAC_R1 Mixer */ |
344 | static const struct snd_kcontrol_new aic3x_right_dac_mixer_controls[] = { | 344 | static const struct snd_kcontrol_new aic3x_right_dac_mixer_controls[] = { |
345 | SOC_DAPM_SINGLE("Line Switch", DACR1_2_RLOPM_VOL, 7, 1, 0), | 345 | SOC_DAPM_SINGLE("Line Switch", DACR1_2_RLOPM_VOL, 7, 1, 0), |
346 | SOC_DAPM_SINGLE("Mono Switch", DACR1_2_MONOLOPM_VOL, 7, 1, 0), | 346 | SOC_DAPM_SINGLE("Mono Switch", DACR1_2_MONOLOPM_VOL, 7, 1, 0), |
347 | SOC_DAPM_SINGLE("HP Switch", DACR1_2_HPROUT_VOL, 7, 1, 0), | 347 | SOC_DAPM_SINGLE("HP Switch", DACR1_2_HPROUT_VOL, 7, 1, 0), |
348 | SOC_DAPM_SINGLE("HPCOM Switch", DACR1_2_HPRCOM_VOL, 7, 1, 0), | 348 | SOC_DAPM_SINGLE("HPCOM Switch", DACR1_2_HPRCOM_VOL, 7, 1, 0), |
349 | }; | 349 | }; |
350 | 350 | ||
351 | /* Left PGA Mixer */ | 351 | /* Left PGA Mixer */ |
352 | static const struct snd_kcontrol_new aic3x_left_pga_mixer_controls[] = { | 352 | static const struct snd_kcontrol_new aic3x_left_pga_mixer_controls[] = { |
353 | SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_LADC_CTRL, 3, 1, 1), | 353 | SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_LADC_CTRL, 3, 1, 1), |
354 | SOC_DAPM_SINGLE_AIC3X("Line2L Switch", LINE2L_2_LADC_CTRL, 3, 1, 1), | 354 | SOC_DAPM_SINGLE_AIC3X("Line2L Switch", LINE2L_2_LADC_CTRL, 3, 1, 1), |
355 | SOC_DAPM_SINGLE_AIC3X("Mic3L Switch", MIC3LR_2_LADC_CTRL, 4, 1, 1), | 355 | SOC_DAPM_SINGLE_AIC3X("Mic3L Switch", MIC3LR_2_LADC_CTRL, 4, 1, 1), |
356 | }; | 356 | }; |
357 | 357 | ||
358 | /* Right PGA Mixer */ | 358 | /* Right PGA Mixer */ |
359 | static const struct snd_kcontrol_new aic3x_right_pga_mixer_controls[] = { | 359 | static const struct snd_kcontrol_new aic3x_right_pga_mixer_controls[] = { |
360 | SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_RADC_CTRL, 3, 1, 1), | 360 | SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_RADC_CTRL, 3, 1, 1), |
361 | SOC_DAPM_SINGLE_AIC3X("Line2R Switch", LINE2R_2_RADC_CTRL, 3, 1, 1), | 361 | SOC_DAPM_SINGLE_AIC3X("Line2R Switch", LINE2R_2_RADC_CTRL, 3, 1, 1), |
362 | SOC_DAPM_SINGLE_AIC3X("Mic3R Switch", MIC3LR_2_RADC_CTRL, 0, 1, 1), | 362 | SOC_DAPM_SINGLE_AIC3X("Mic3R Switch", MIC3LR_2_RADC_CTRL, 0, 1, 1), |
363 | }; | 363 | }; |
364 | 364 | ||
365 | /* Left Line1 Mux */ | 365 | /* Left Line1 Mux */ |
366 | static const struct snd_kcontrol_new aic3x_left_line1_mux_controls = | 366 | static const struct snd_kcontrol_new aic3x_left_line1_mux_controls = |
367 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE1L_ENUM]); | 367 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE1L_ENUM]); |
368 | 368 | ||
369 | /* Right Line1 Mux */ | 369 | /* Right Line1 Mux */ |
370 | static const struct snd_kcontrol_new aic3x_right_line1_mux_controls = | 370 | static const struct snd_kcontrol_new aic3x_right_line1_mux_controls = |
371 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE1R_ENUM]); | 371 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE1R_ENUM]); |
372 | 372 | ||
373 | /* Left Line2 Mux */ | 373 | /* Left Line2 Mux */ |
374 | static const struct snd_kcontrol_new aic3x_left_line2_mux_controls = | 374 | static const struct snd_kcontrol_new aic3x_left_line2_mux_controls = |
375 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE2L_ENUM]); | 375 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE2L_ENUM]); |
376 | 376 | ||
377 | /* Right Line2 Mux */ | 377 | /* Right Line2 Mux */ |
378 | static const struct snd_kcontrol_new aic3x_right_line2_mux_controls = | 378 | static const struct snd_kcontrol_new aic3x_right_line2_mux_controls = |
379 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE2R_ENUM]); | 379 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE2R_ENUM]); |
380 | 380 | ||
381 | /* Left PGA Bypass Mixer */ | 381 | /* Left PGA Bypass Mixer */ |
382 | static const struct snd_kcontrol_new aic3x_left_pga_bp_mixer_controls[] = { | 382 | static const struct snd_kcontrol_new aic3x_left_pga_bp_mixer_controls[] = { |
383 | SOC_DAPM_SINGLE("Line Switch", PGAL_2_LLOPM_VOL, 7, 1, 0), | 383 | SOC_DAPM_SINGLE("Line Switch", PGAL_2_LLOPM_VOL, 7, 1, 0), |
384 | SOC_DAPM_SINGLE("Mono Switch", PGAL_2_MONOLOPM_VOL, 7, 1, 0), | 384 | SOC_DAPM_SINGLE("Mono Switch", PGAL_2_MONOLOPM_VOL, 7, 1, 0), |
385 | SOC_DAPM_SINGLE("HP Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0), | 385 | SOC_DAPM_SINGLE("HP Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0), |
386 | SOC_DAPM_SINGLE("HPCOM Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0), | 386 | SOC_DAPM_SINGLE("HPCOM Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0), |
387 | }; | 387 | }; |
388 | 388 | ||
389 | /* Right PGA Bypass Mixer */ | 389 | /* Right PGA Bypass Mixer */ |
390 | static const struct snd_kcontrol_new aic3x_right_pga_bp_mixer_controls[] = { | 390 | static const struct snd_kcontrol_new aic3x_right_pga_bp_mixer_controls[] = { |
391 | SOC_DAPM_SINGLE("Line Switch", PGAR_2_RLOPM_VOL, 7, 1, 0), | 391 | SOC_DAPM_SINGLE("Line Switch", PGAR_2_RLOPM_VOL, 7, 1, 0), |
392 | SOC_DAPM_SINGLE("Mono Switch", PGAR_2_MONOLOPM_VOL, 7, 1, 0), | 392 | SOC_DAPM_SINGLE("Mono Switch", PGAR_2_MONOLOPM_VOL, 7, 1, 0), |
393 | SOC_DAPM_SINGLE("HP Switch", PGAR_2_HPROUT_VOL, 7, 1, 0), | 393 | SOC_DAPM_SINGLE("HP Switch", PGAR_2_HPROUT_VOL, 7, 1, 0), |
394 | SOC_DAPM_SINGLE("HPCOM Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0), | 394 | SOC_DAPM_SINGLE("HPCOM Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0), |
395 | }; | 395 | }; |
396 | 396 | ||
397 | /* Left Line2 Bypass Mixer */ | 397 | /* Left Line2 Bypass Mixer */ |
398 | static const struct snd_kcontrol_new aic3x_left_line2_bp_mixer_controls[] = { | 398 | static const struct snd_kcontrol_new aic3x_left_line2_bp_mixer_controls[] = { |
399 | SOC_DAPM_SINGLE("Line Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0), | 399 | SOC_DAPM_SINGLE("Line Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0), |
400 | SOC_DAPM_SINGLE("Mono Switch", LINE2L_2_MONOLOPM_VOL, 7, 1, 0), | 400 | SOC_DAPM_SINGLE("Mono Switch", LINE2L_2_MONOLOPM_VOL, 7, 1, 0), |
401 | SOC_DAPM_SINGLE("HP Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0), | 401 | SOC_DAPM_SINGLE("HP Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0), |
402 | SOC_DAPM_SINGLE("HPCOM Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0), | 402 | SOC_DAPM_SINGLE("HPCOM Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0), |
403 | }; | 403 | }; |
404 | 404 | ||
405 | /* Right Line2 Bypass Mixer */ | 405 | /* Right Line2 Bypass Mixer */ |
406 | static const struct snd_kcontrol_new aic3x_right_line2_bp_mixer_controls[] = { | 406 | static const struct snd_kcontrol_new aic3x_right_line2_bp_mixer_controls[] = { |
407 | SOC_DAPM_SINGLE("Line Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0), | 407 | SOC_DAPM_SINGLE("Line Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0), |
408 | SOC_DAPM_SINGLE("Mono Switch", LINE2R_2_MONOLOPM_VOL, 7, 1, 0), | 408 | SOC_DAPM_SINGLE("Mono Switch", LINE2R_2_MONOLOPM_VOL, 7, 1, 0), |
409 | SOC_DAPM_SINGLE("HP Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0), | 409 | SOC_DAPM_SINGLE("HP Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0), |
410 | SOC_DAPM_SINGLE("HPCOM Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0), | 410 | SOC_DAPM_SINGLE("HPCOM Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0), |
411 | }; | 411 | }; |
412 | 412 | ||
413 | static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { | 413 | static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { |
414 | /* Left DAC to Left Outputs */ | 414 | /* Left DAC to Left Outputs */ |
415 | SND_SOC_DAPM_DAC("Left DAC", "Left Playback", DAC_PWR, 7, 0), | 415 | SND_SOC_DAPM_DAC("Left DAC", "Left Playback", DAC_PWR, 7, 0), |
416 | SND_SOC_DAPM_MUX("Left DAC Mux", SND_SOC_NOPM, 0, 0, | 416 | SND_SOC_DAPM_MUX("Left DAC Mux", SND_SOC_NOPM, 0, 0, |
417 | &aic3x_left_dac_mux_controls), | 417 | &aic3x_left_dac_mux_controls), |
418 | SND_SOC_DAPM_MIXER("Left DAC_L1 Mixer", SND_SOC_NOPM, 0, 0, | 418 | SND_SOC_DAPM_MIXER("Left DAC_L1 Mixer", SND_SOC_NOPM, 0, 0, |
419 | &aic3x_left_dac_mixer_controls[0], | 419 | &aic3x_left_dac_mixer_controls[0], |
420 | ARRAY_SIZE(aic3x_left_dac_mixer_controls)), | 420 | ARRAY_SIZE(aic3x_left_dac_mixer_controls)), |
421 | SND_SOC_DAPM_MUX("Left HPCOM Mux", SND_SOC_NOPM, 0, 0, | 421 | SND_SOC_DAPM_MUX("Left HPCOM Mux", SND_SOC_NOPM, 0, 0, |
422 | &aic3x_left_hpcom_mux_controls), | 422 | &aic3x_left_hpcom_mux_controls), |
423 | SND_SOC_DAPM_PGA("Left Line Out", LLOPM_CTRL, 0, 0, NULL, 0), | 423 | SND_SOC_DAPM_PGA("Left Line Out", LLOPM_CTRL, 0, 0, NULL, 0), |
424 | SND_SOC_DAPM_PGA("Left HP Out", HPLOUT_CTRL, 0, 0, NULL, 0), | 424 | SND_SOC_DAPM_PGA("Left HP Out", HPLOUT_CTRL, 0, 0, NULL, 0), |
425 | SND_SOC_DAPM_PGA("Left HP Com", HPLCOM_CTRL, 0, 0, NULL, 0), | 425 | SND_SOC_DAPM_PGA("Left HP Com", HPLCOM_CTRL, 0, 0, NULL, 0), |
426 | 426 | ||
427 | /* Right DAC to Right Outputs */ | 427 | /* Right DAC to Right Outputs */ |
428 | SND_SOC_DAPM_DAC("Right DAC", "Right Playback", DAC_PWR, 6, 0), | 428 | SND_SOC_DAPM_DAC("Right DAC", "Right Playback", DAC_PWR, 6, 0), |
429 | SND_SOC_DAPM_MUX("Right DAC Mux", SND_SOC_NOPM, 0, 0, | 429 | SND_SOC_DAPM_MUX("Right DAC Mux", SND_SOC_NOPM, 0, 0, |
430 | &aic3x_right_dac_mux_controls), | 430 | &aic3x_right_dac_mux_controls), |
431 | SND_SOC_DAPM_MIXER("Right DAC_R1 Mixer", SND_SOC_NOPM, 0, 0, | 431 | SND_SOC_DAPM_MIXER("Right DAC_R1 Mixer", SND_SOC_NOPM, 0, 0, |
432 | &aic3x_right_dac_mixer_controls[0], | 432 | &aic3x_right_dac_mixer_controls[0], |
433 | ARRAY_SIZE(aic3x_right_dac_mixer_controls)), | 433 | ARRAY_SIZE(aic3x_right_dac_mixer_controls)), |
434 | SND_SOC_DAPM_MUX("Right HPCOM Mux", SND_SOC_NOPM, 0, 0, | 434 | SND_SOC_DAPM_MUX("Right HPCOM Mux", SND_SOC_NOPM, 0, 0, |
435 | &aic3x_right_hpcom_mux_controls), | 435 | &aic3x_right_hpcom_mux_controls), |
436 | SND_SOC_DAPM_PGA("Right Line Out", RLOPM_CTRL, 0, 0, NULL, 0), | 436 | SND_SOC_DAPM_PGA("Right Line Out", RLOPM_CTRL, 0, 0, NULL, 0), |
437 | SND_SOC_DAPM_PGA("Right HP Out", HPROUT_CTRL, 0, 0, NULL, 0), | 437 | SND_SOC_DAPM_PGA("Right HP Out", HPROUT_CTRL, 0, 0, NULL, 0), |
438 | SND_SOC_DAPM_PGA("Right HP Com", HPRCOM_CTRL, 0, 0, NULL, 0), | 438 | SND_SOC_DAPM_PGA("Right HP Com", HPRCOM_CTRL, 0, 0, NULL, 0), |
439 | 439 | ||
440 | /* Mono Output */ | 440 | /* Mono Output */ |
441 | SND_SOC_DAPM_PGA("Mono Out", MONOLOPM_CTRL, 0, 0, NULL, 0), | 441 | SND_SOC_DAPM_PGA("Mono Out", MONOLOPM_CTRL, 0, 0, NULL, 0), |
442 | 442 | ||
443 | /* Left Inputs to Left ADC */ | 443 | /* Left Inputs to Left ADC */ |
444 | SND_SOC_DAPM_ADC("Left ADC", "Left Capture", LINE1L_2_LADC_CTRL, 2, 0), | 444 | SND_SOC_DAPM_ADC("Left ADC", "Left Capture", LINE1L_2_LADC_CTRL, 2, 0), |
445 | SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0, | 445 | SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0, |
446 | &aic3x_left_pga_mixer_controls[0], | 446 | &aic3x_left_pga_mixer_controls[0], |
447 | ARRAY_SIZE(aic3x_left_pga_mixer_controls)), | 447 | ARRAY_SIZE(aic3x_left_pga_mixer_controls)), |
448 | SND_SOC_DAPM_MUX("Left Line1L Mux", SND_SOC_NOPM, 0, 0, | 448 | SND_SOC_DAPM_MUX("Left Line1L Mux", SND_SOC_NOPM, 0, 0, |
449 | &aic3x_left_line1_mux_controls), | 449 | &aic3x_left_line1_mux_controls), |
450 | SND_SOC_DAPM_MUX("Left Line2L Mux", SND_SOC_NOPM, 0, 0, | 450 | SND_SOC_DAPM_MUX("Left Line2L Mux", SND_SOC_NOPM, 0, 0, |
451 | &aic3x_left_line2_mux_controls), | 451 | &aic3x_left_line2_mux_controls), |
452 | 452 | ||
453 | /* Right Inputs to Right ADC */ | 453 | /* Right Inputs to Right ADC */ |
454 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", | 454 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", |
455 | LINE1R_2_RADC_CTRL, 2, 0), | 455 | LINE1R_2_RADC_CTRL, 2, 0), |
456 | SND_SOC_DAPM_MIXER("Right PGA Mixer", SND_SOC_NOPM, 0, 0, | 456 | SND_SOC_DAPM_MIXER("Right PGA Mixer", SND_SOC_NOPM, 0, 0, |
457 | &aic3x_right_pga_mixer_controls[0], | 457 | &aic3x_right_pga_mixer_controls[0], |
458 | ARRAY_SIZE(aic3x_right_pga_mixer_controls)), | 458 | ARRAY_SIZE(aic3x_right_pga_mixer_controls)), |
459 | SND_SOC_DAPM_MUX("Right Line1R Mux", SND_SOC_NOPM, 0, 0, | 459 | SND_SOC_DAPM_MUX("Right Line1R Mux", SND_SOC_NOPM, 0, 0, |
460 | &aic3x_right_line1_mux_controls), | 460 | &aic3x_right_line1_mux_controls), |
461 | SND_SOC_DAPM_MUX("Right Line2R Mux", SND_SOC_NOPM, 0, 0, | 461 | SND_SOC_DAPM_MUX("Right Line2R Mux", SND_SOC_NOPM, 0, 0, |
462 | &aic3x_right_line2_mux_controls), | 462 | &aic3x_right_line2_mux_controls), |
463 | 463 | ||
464 | /* | 464 | /* |
465 | * Not a real mic bias widget but similar function. This is for dynamic | 465 | * Not a real mic bias widget but similar function. This is for dynamic |
466 | * control of GPIO1 digital mic modulator clock output function when | 466 | * control of GPIO1 digital mic modulator clock output function when |
467 | * using digital mic. | 467 | * using digital mic. |
468 | */ | 468 | */ |
469 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "GPIO1 dmic modclk", | 469 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "GPIO1 dmic modclk", |
470 | AIC3X_GPIO1_REG, 4, 0xf, | 470 | AIC3X_GPIO1_REG, 4, 0xf, |
471 | AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK, | 471 | AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK, |
472 | AIC3X_GPIO1_FUNC_DISABLED), | 472 | AIC3X_GPIO1_FUNC_DISABLED), |
473 | 473 | ||
474 | /* | 474 | /* |
475 | * Also similar function like mic bias. Selects digital mic with | 475 | * Also similar function like mic bias. Selects digital mic with |
476 | * configurable oversampling rate instead of ADC converter. | 476 | * configurable oversampling rate instead of ADC converter. |
477 | */ | 477 | */ |
478 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 128", | 478 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 128", |
479 | AIC3X_ASD_INTF_CTRLA, 0, 3, 1, 0), | 479 | AIC3X_ASD_INTF_CTRLA, 0, 3, 1, 0), |
480 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 64", | 480 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 64", |
481 | AIC3X_ASD_INTF_CTRLA, 0, 3, 2, 0), | 481 | AIC3X_ASD_INTF_CTRLA, 0, 3, 2, 0), |
482 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 32", | 482 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 32", |
483 | AIC3X_ASD_INTF_CTRLA, 0, 3, 3, 0), | 483 | AIC3X_ASD_INTF_CTRLA, 0, 3, 3, 0), |
484 | 484 | ||
485 | /* Mic Bias */ | 485 | /* Mic Bias */ |
486 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2V", | 486 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2V", |
487 | MICBIAS_CTRL, 6, 3, 1, 0), | 487 | MICBIAS_CTRL, 6, 3, 1, 0), |
488 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2.5V", | 488 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2.5V", |
489 | MICBIAS_CTRL, 6, 3, 2, 0), | 489 | MICBIAS_CTRL, 6, 3, 2, 0), |
490 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias AVDD", | 490 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias AVDD", |
491 | MICBIAS_CTRL, 6, 3, 3, 0), | 491 | MICBIAS_CTRL, 6, 3, 3, 0), |
492 | 492 | ||
493 | /* Left PGA to Left Output bypass */ | 493 | /* Left PGA to Left Output bypass */ |
494 | SND_SOC_DAPM_MIXER("Left PGA Bypass Mixer", SND_SOC_NOPM, 0, 0, | 494 | SND_SOC_DAPM_MIXER("Left PGA Bypass Mixer", SND_SOC_NOPM, 0, 0, |
495 | &aic3x_left_pga_bp_mixer_controls[0], | 495 | &aic3x_left_pga_bp_mixer_controls[0], |
496 | ARRAY_SIZE(aic3x_left_pga_bp_mixer_controls)), | 496 | ARRAY_SIZE(aic3x_left_pga_bp_mixer_controls)), |
497 | 497 | ||
498 | /* Right PGA to Right Output bypass */ | 498 | /* Right PGA to Right Output bypass */ |
499 | SND_SOC_DAPM_MIXER("Right PGA Bypass Mixer", SND_SOC_NOPM, 0, 0, | 499 | SND_SOC_DAPM_MIXER("Right PGA Bypass Mixer", SND_SOC_NOPM, 0, 0, |
500 | &aic3x_right_pga_bp_mixer_controls[0], | 500 | &aic3x_right_pga_bp_mixer_controls[0], |
501 | ARRAY_SIZE(aic3x_right_pga_bp_mixer_controls)), | 501 | ARRAY_SIZE(aic3x_right_pga_bp_mixer_controls)), |
502 | 502 | ||
503 | /* Left Line2 to Left Output bypass */ | 503 | /* Left Line2 to Left Output bypass */ |
504 | SND_SOC_DAPM_MIXER("Left Line2 Bypass Mixer", SND_SOC_NOPM, 0, 0, | 504 | SND_SOC_DAPM_MIXER("Left Line2 Bypass Mixer", SND_SOC_NOPM, 0, 0, |
505 | &aic3x_left_line2_bp_mixer_controls[0], | 505 | &aic3x_left_line2_bp_mixer_controls[0], |
506 | ARRAY_SIZE(aic3x_left_line2_bp_mixer_controls)), | 506 | ARRAY_SIZE(aic3x_left_line2_bp_mixer_controls)), |
507 | 507 | ||
508 | /* Right Line2 to Right Output bypass */ | 508 | /* Right Line2 to Right Output bypass */ |
509 | SND_SOC_DAPM_MIXER("Right Line2 Bypass Mixer", SND_SOC_NOPM, 0, 0, | 509 | SND_SOC_DAPM_MIXER("Right Line2 Bypass Mixer", SND_SOC_NOPM, 0, 0, |
510 | &aic3x_right_line2_bp_mixer_controls[0], | 510 | &aic3x_right_line2_bp_mixer_controls[0], |
511 | ARRAY_SIZE(aic3x_right_line2_bp_mixer_controls)), | 511 | ARRAY_SIZE(aic3x_right_line2_bp_mixer_controls)), |
512 | 512 | ||
513 | SND_SOC_DAPM_OUTPUT("LLOUT"), | 513 | SND_SOC_DAPM_OUTPUT("LLOUT"), |
514 | SND_SOC_DAPM_OUTPUT("RLOUT"), | 514 | SND_SOC_DAPM_OUTPUT("RLOUT"), |
515 | SND_SOC_DAPM_OUTPUT("MONO_LOUT"), | 515 | SND_SOC_DAPM_OUTPUT("MONO_LOUT"), |
516 | SND_SOC_DAPM_OUTPUT("HPLOUT"), | 516 | SND_SOC_DAPM_OUTPUT("HPLOUT"), |
517 | SND_SOC_DAPM_OUTPUT("HPROUT"), | 517 | SND_SOC_DAPM_OUTPUT("HPROUT"), |
518 | SND_SOC_DAPM_OUTPUT("HPLCOM"), | 518 | SND_SOC_DAPM_OUTPUT("HPLCOM"), |
519 | SND_SOC_DAPM_OUTPUT("HPRCOM"), | 519 | SND_SOC_DAPM_OUTPUT("HPRCOM"), |
520 | 520 | ||
521 | SND_SOC_DAPM_INPUT("MIC3L"), | 521 | SND_SOC_DAPM_INPUT("MIC3L"), |
522 | SND_SOC_DAPM_INPUT("MIC3R"), | 522 | SND_SOC_DAPM_INPUT("MIC3R"), |
523 | SND_SOC_DAPM_INPUT("LINE1L"), | 523 | SND_SOC_DAPM_INPUT("LINE1L"), |
524 | SND_SOC_DAPM_INPUT("LINE1R"), | 524 | SND_SOC_DAPM_INPUT("LINE1R"), |
525 | SND_SOC_DAPM_INPUT("LINE2L"), | 525 | SND_SOC_DAPM_INPUT("LINE2L"), |
526 | SND_SOC_DAPM_INPUT("LINE2R"), | 526 | SND_SOC_DAPM_INPUT("LINE2R"), |
527 | }; | 527 | }; |
528 | 528 | ||
529 | static const struct snd_soc_dapm_route intercon[] = { | 529 | static const struct snd_soc_dapm_route intercon[] = { |
530 | /* Left Output */ | 530 | /* Left Output */ |
531 | {"Left DAC Mux", "DAC_L1", "Left DAC"}, | 531 | {"Left DAC Mux", "DAC_L1", "Left DAC"}, |
532 | {"Left DAC Mux", "DAC_L2", "Left DAC"}, | 532 | {"Left DAC Mux", "DAC_L2", "Left DAC"}, |
533 | {"Left DAC Mux", "DAC_L3", "Left DAC"}, | 533 | {"Left DAC Mux", "DAC_L3", "Left DAC"}, |
534 | 534 | ||
535 | {"Left DAC_L1 Mixer", "Line Switch", "Left DAC Mux"}, | 535 | {"Left DAC_L1 Mixer", "Line Switch", "Left DAC Mux"}, |
536 | {"Left DAC_L1 Mixer", "Mono Switch", "Left DAC Mux"}, | 536 | {"Left DAC_L1 Mixer", "Mono Switch", "Left DAC Mux"}, |
537 | {"Left DAC_L1 Mixer", "HP Switch", "Left DAC Mux"}, | 537 | {"Left DAC_L1 Mixer", "HP Switch", "Left DAC Mux"}, |
538 | {"Left DAC_L1 Mixer", "HPCOM Switch", "Left DAC Mux"}, | 538 | {"Left DAC_L1 Mixer", "HPCOM Switch", "Left DAC Mux"}, |
539 | {"Left Line Out", NULL, "Left DAC Mux"}, | 539 | {"Left Line Out", NULL, "Left DAC Mux"}, |
540 | {"Left HP Out", NULL, "Left DAC Mux"}, | 540 | {"Left HP Out", NULL, "Left DAC Mux"}, |
541 | 541 | ||
542 | {"Left HPCOM Mux", "differential of HPLOUT", "Left DAC_L1 Mixer"}, | 542 | {"Left HPCOM Mux", "differential of HPLOUT", "Left DAC_L1 Mixer"}, |
543 | {"Left HPCOM Mux", "constant VCM", "Left DAC_L1 Mixer"}, | 543 | {"Left HPCOM Mux", "constant VCM", "Left DAC_L1 Mixer"}, |
544 | {"Left HPCOM Mux", "single-ended", "Left DAC_L1 Mixer"}, | 544 | {"Left HPCOM Mux", "single-ended", "Left DAC_L1 Mixer"}, |
545 | 545 | ||
546 | {"Left Line Out", NULL, "Left DAC_L1 Mixer"}, | 546 | {"Left Line Out", NULL, "Left DAC_L1 Mixer"}, |
547 | {"Mono Out", NULL, "Left DAC_L1 Mixer"}, | 547 | {"Mono Out", NULL, "Left DAC_L1 Mixer"}, |
548 | {"Left HP Out", NULL, "Left DAC_L1 Mixer"}, | 548 | {"Left HP Out", NULL, "Left DAC_L1 Mixer"}, |
549 | {"Left HP Com", NULL, "Left HPCOM Mux"}, | 549 | {"Left HP Com", NULL, "Left HPCOM Mux"}, |
550 | 550 | ||
551 | {"LLOUT", NULL, "Left Line Out"}, | 551 | {"LLOUT", NULL, "Left Line Out"}, |
552 | {"LLOUT", NULL, "Left Line Out"}, | 552 | {"LLOUT", NULL, "Left Line Out"}, |
553 | {"HPLOUT", NULL, "Left HP Out"}, | 553 | {"HPLOUT", NULL, "Left HP Out"}, |
554 | {"HPLCOM", NULL, "Left HP Com"}, | 554 | {"HPLCOM", NULL, "Left HP Com"}, |
555 | 555 | ||
556 | /* Right Output */ | 556 | /* Right Output */ |
557 | {"Right DAC Mux", "DAC_R1", "Right DAC"}, | 557 | {"Right DAC Mux", "DAC_R1", "Right DAC"}, |
558 | {"Right DAC Mux", "DAC_R2", "Right DAC"}, | 558 | {"Right DAC Mux", "DAC_R2", "Right DAC"}, |
559 | {"Right DAC Mux", "DAC_R3", "Right DAC"}, | 559 | {"Right DAC Mux", "DAC_R3", "Right DAC"}, |
560 | 560 | ||
561 | {"Right DAC_R1 Mixer", "Line Switch", "Right DAC Mux"}, | 561 | {"Right DAC_R1 Mixer", "Line Switch", "Right DAC Mux"}, |
562 | {"Right DAC_R1 Mixer", "Mono Switch", "Right DAC Mux"}, | 562 | {"Right DAC_R1 Mixer", "Mono Switch", "Right DAC Mux"}, |
563 | {"Right DAC_R1 Mixer", "HP Switch", "Right DAC Mux"}, | 563 | {"Right DAC_R1 Mixer", "HP Switch", "Right DAC Mux"}, |
564 | {"Right DAC_R1 Mixer", "HPCOM Switch", "Right DAC Mux"}, | 564 | {"Right DAC_R1 Mixer", "HPCOM Switch", "Right DAC Mux"}, |
565 | {"Right Line Out", NULL, "Right DAC Mux"}, | 565 | {"Right Line Out", NULL, "Right DAC Mux"}, |
566 | {"Right HP Out", NULL, "Right DAC Mux"}, | 566 | {"Right HP Out", NULL, "Right DAC Mux"}, |
567 | 567 | ||
568 | {"Right HPCOM Mux", "differential of HPROUT", "Right DAC_R1 Mixer"}, | 568 | {"Right HPCOM Mux", "differential of HPROUT", "Right DAC_R1 Mixer"}, |
569 | {"Right HPCOM Mux", "constant VCM", "Right DAC_R1 Mixer"}, | 569 | {"Right HPCOM Mux", "constant VCM", "Right DAC_R1 Mixer"}, |
570 | {"Right HPCOM Mux", "single-ended", "Right DAC_R1 Mixer"}, | 570 | {"Right HPCOM Mux", "single-ended", "Right DAC_R1 Mixer"}, |
571 | {"Right HPCOM Mux", "differential of HPLCOM", "Right DAC_R1 Mixer"}, | 571 | {"Right HPCOM Mux", "differential of HPLCOM", "Right DAC_R1 Mixer"}, |
572 | {"Right HPCOM Mux", "external feedback", "Right DAC_R1 Mixer"}, | 572 | {"Right HPCOM Mux", "external feedback", "Right DAC_R1 Mixer"}, |
573 | 573 | ||
574 | {"Right Line Out", NULL, "Right DAC_R1 Mixer"}, | 574 | {"Right Line Out", NULL, "Right DAC_R1 Mixer"}, |
575 | {"Mono Out", NULL, "Right DAC_R1 Mixer"}, | 575 | {"Mono Out", NULL, "Right DAC_R1 Mixer"}, |
576 | {"Right HP Out", NULL, "Right DAC_R1 Mixer"}, | 576 | {"Right HP Out", NULL, "Right DAC_R1 Mixer"}, |
577 | {"Right HP Com", NULL, "Right HPCOM Mux"}, | 577 | {"Right HP Com", NULL, "Right HPCOM Mux"}, |
578 | 578 | ||
579 | {"RLOUT", NULL, "Right Line Out"}, | 579 | {"RLOUT", NULL, "Right Line Out"}, |
580 | {"RLOUT", NULL, "Right Line Out"}, | 580 | {"RLOUT", NULL, "Right Line Out"}, |
581 | {"HPROUT", NULL, "Right HP Out"}, | 581 | {"HPROUT", NULL, "Right HP Out"}, |
582 | {"HPRCOM", NULL, "Right HP Com"}, | 582 | {"HPRCOM", NULL, "Right HP Com"}, |
583 | 583 | ||
584 | /* Mono Output */ | 584 | /* Mono Output */ |
585 | {"MONO_LOUT", NULL, "Mono Out"}, | 585 | {"MONO_LOUT", NULL, "Mono Out"}, |
586 | {"MONO_LOUT", NULL, "Mono Out"}, | 586 | {"MONO_LOUT", NULL, "Mono Out"}, |
587 | 587 | ||
588 | /* Left Input */ | 588 | /* Left Input */ |
589 | {"Left Line1L Mux", "single-ended", "LINE1L"}, | 589 | {"Left Line1L Mux", "single-ended", "LINE1L"}, |
590 | {"Left Line1L Mux", "differential", "LINE1L"}, | 590 | {"Left Line1L Mux", "differential", "LINE1L"}, |
591 | 591 | ||
592 | {"Left Line2L Mux", "single-ended", "LINE2L"}, | 592 | {"Left Line2L Mux", "single-ended", "LINE2L"}, |
593 | {"Left Line2L Mux", "differential", "LINE2L"}, | 593 | {"Left Line2L Mux", "differential", "LINE2L"}, |
594 | 594 | ||
595 | {"Left PGA Mixer", "Line1L Switch", "Left Line1L Mux"}, | 595 | {"Left PGA Mixer", "Line1L Switch", "Left Line1L Mux"}, |
596 | {"Left PGA Mixer", "Line2L Switch", "Left Line2L Mux"}, | 596 | {"Left PGA Mixer", "Line2L Switch", "Left Line2L Mux"}, |
597 | {"Left PGA Mixer", "Mic3L Switch", "MIC3L"}, | 597 | {"Left PGA Mixer", "Mic3L Switch", "MIC3L"}, |
598 | 598 | ||
599 | {"Left ADC", NULL, "Left PGA Mixer"}, | 599 | {"Left ADC", NULL, "Left PGA Mixer"}, |
600 | {"Left ADC", NULL, "GPIO1 dmic modclk"}, | 600 | {"Left ADC", NULL, "GPIO1 dmic modclk"}, |
601 | 601 | ||
602 | /* Right Input */ | 602 | /* Right Input */ |
603 | {"Right Line1R Mux", "single-ended", "LINE1R"}, | 603 | {"Right Line1R Mux", "single-ended", "LINE1R"}, |
604 | {"Right Line1R Mux", "differential", "LINE1R"}, | 604 | {"Right Line1R Mux", "differential", "LINE1R"}, |
605 | 605 | ||
606 | {"Right Line2R Mux", "single-ended", "LINE2R"}, | 606 | {"Right Line2R Mux", "single-ended", "LINE2R"}, |
607 | {"Right Line2R Mux", "differential", "LINE2R"}, | 607 | {"Right Line2R Mux", "differential", "LINE2R"}, |
608 | 608 | ||
609 | {"Right PGA Mixer", "Line1R Switch", "Right Line1R Mux"}, | 609 | {"Right PGA Mixer", "Line1R Switch", "Right Line1R Mux"}, |
610 | {"Right PGA Mixer", "Line2R Switch", "Right Line2R Mux"}, | 610 | {"Right PGA Mixer", "Line2R Switch", "Right Line2R Mux"}, |
611 | {"Right PGA Mixer", "Mic3R Switch", "MIC3R"}, | 611 | {"Right PGA Mixer", "Mic3R Switch", "MIC3R"}, |
612 | 612 | ||
613 | {"Right ADC", NULL, "Right PGA Mixer"}, | 613 | {"Right ADC", NULL, "Right PGA Mixer"}, |
614 | {"Right ADC", NULL, "GPIO1 dmic modclk"}, | 614 | {"Right ADC", NULL, "GPIO1 dmic modclk"}, |
615 | 615 | ||
616 | /* Left PGA Bypass */ | 616 | /* Left PGA Bypass */ |
617 | {"Left PGA Bypass Mixer", "Line Switch", "Left PGA Mixer"}, | 617 | {"Left PGA Bypass Mixer", "Line Switch", "Left PGA Mixer"}, |
618 | {"Left PGA Bypass Mixer", "Mono Switch", "Left PGA Mixer"}, | 618 | {"Left PGA Bypass Mixer", "Mono Switch", "Left PGA Mixer"}, |
619 | {"Left PGA Bypass Mixer", "HP Switch", "Left PGA Mixer"}, | 619 | {"Left PGA Bypass Mixer", "HP Switch", "Left PGA Mixer"}, |
620 | {"Left PGA Bypass Mixer", "HPCOM Switch", "Left PGA Mixer"}, | 620 | {"Left PGA Bypass Mixer", "HPCOM Switch", "Left PGA Mixer"}, |
621 | 621 | ||
622 | {"Left HPCOM Mux", "differential of HPLOUT", "Left PGA Bypass Mixer"}, | 622 | {"Left HPCOM Mux", "differential of HPLOUT", "Left PGA Bypass Mixer"}, |
623 | {"Left HPCOM Mux", "constant VCM", "Left PGA Bypass Mixer"}, | 623 | {"Left HPCOM Mux", "constant VCM", "Left PGA Bypass Mixer"}, |
624 | {"Left HPCOM Mux", "single-ended", "Left PGA Bypass Mixer"}, | 624 | {"Left HPCOM Mux", "single-ended", "Left PGA Bypass Mixer"}, |
625 | 625 | ||
626 | {"Left Line Out", NULL, "Left PGA Bypass Mixer"}, | 626 | {"Left Line Out", NULL, "Left PGA Bypass Mixer"}, |
627 | {"Mono Out", NULL, "Left PGA Bypass Mixer"}, | 627 | {"Mono Out", NULL, "Left PGA Bypass Mixer"}, |
628 | {"Left HP Out", NULL, "Left PGA Bypass Mixer"}, | 628 | {"Left HP Out", NULL, "Left PGA Bypass Mixer"}, |
629 | 629 | ||
630 | /* Right PGA Bypass */ | 630 | /* Right PGA Bypass */ |
631 | {"Right PGA Bypass Mixer", "Line Switch", "Right PGA Mixer"}, | 631 | {"Right PGA Bypass Mixer", "Line Switch", "Right PGA Mixer"}, |
632 | {"Right PGA Bypass Mixer", "Mono Switch", "Right PGA Mixer"}, | 632 | {"Right PGA Bypass Mixer", "Mono Switch", "Right PGA Mixer"}, |
633 | {"Right PGA Bypass Mixer", "HP Switch", "Right PGA Mixer"}, | 633 | {"Right PGA Bypass Mixer", "HP Switch", "Right PGA Mixer"}, |
634 | {"Right PGA Bypass Mixer", "HPCOM Switch", "Right PGA Mixer"}, | 634 | {"Right PGA Bypass Mixer", "HPCOM Switch", "Right PGA Mixer"}, |
635 | 635 | ||
636 | {"Right HPCOM Mux", "differential of HPROUT", "Right PGA Bypass Mixer"}, | 636 | {"Right HPCOM Mux", "differential of HPROUT", "Right PGA Bypass Mixer"}, |
637 | {"Right HPCOM Mux", "constant VCM", "Right PGA Bypass Mixer"}, | 637 | {"Right HPCOM Mux", "constant VCM", "Right PGA Bypass Mixer"}, |
638 | {"Right HPCOM Mux", "single-ended", "Right PGA Bypass Mixer"}, | 638 | {"Right HPCOM Mux", "single-ended", "Right PGA Bypass Mixer"}, |
639 | {"Right HPCOM Mux", "differential of HPLCOM", "Right PGA Bypass Mixer"}, | 639 | {"Right HPCOM Mux", "differential of HPLCOM", "Right PGA Bypass Mixer"}, |
640 | {"Right HPCOM Mux", "external feedback", "Right PGA Bypass Mixer"}, | 640 | {"Right HPCOM Mux", "external feedback", "Right PGA Bypass Mixer"}, |
641 | 641 | ||
642 | {"Right Line Out", NULL, "Right PGA Bypass Mixer"}, | 642 | {"Right Line Out", NULL, "Right PGA Bypass Mixer"}, |
643 | {"Mono Out", NULL, "Right PGA Bypass Mixer"}, | 643 | {"Mono Out", NULL, "Right PGA Bypass Mixer"}, |
644 | {"Right HP Out", NULL, "Right PGA Bypass Mixer"}, | 644 | {"Right HP Out", NULL, "Right PGA Bypass Mixer"}, |
645 | 645 | ||
646 | /* Left Line2 Bypass */ | 646 | /* Left Line2 Bypass */ |
647 | {"Left Line2 Bypass Mixer", "Line Switch", "Left Line2L Mux"}, | 647 | {"Left Line2 Bypass Mixer", "Line Switch", "Left Line2L Mux"}, |
648 | {"Left Line2 Bypass Mixer", "Mono Switch", "Left Line2L Mux"}, | 648 | {"Left Line2 Bypass Mixer", "Mono Switch", "Left Line2L Mux"}, |
649 | {"Left Line2 Bypass Mixer", "HP Switch", "Left Line2L Mux"}, | 649 | {"Left Line2 Bypass Mixer", "HP Switch", "Left Line2L Mux"}, |
650 | {"Left Line2 Bypass Mixer", "HPCOM Switch", "Left Line2L Mux"}, | 650 | {"Left Line2 Bypass Mixer", "HPCOM Switch", "Left Line2L Mux"}, |
651 | 651 | ||
652 | {"Left HPCOM Mux", "differential of HPLOUT", "Left Line2 Bypass Mixer"}, | 652 | {"Left HPCOM Mux", "differential of HPLOUT", "Left Line2 Bypass Mixer"}, |
653 | {"Left HPCOM Mux", "constant VCM", "Left Line2 Bypass Mixer"}, | 653 | {"Left HPCOM Mux", "constant VCM", "Left Line2 Bypass Mixer"}, |
654 | {"Left HPCOM Mux", "single-ended", "Left Line2 Bypass Mixer"}, | 654 | {"Left HPCOM Mux", "single-ended", "Left Line2 Bypass Mixer"}, |
655 | 655 | ||
656 | {"Left Line Out", NULL, "Left Line2 Bypass Mixer"}, | 656 | {"Left Line Out", NULL, "Left Line2 Bypass Mixer"}, |
657 | {"Mono Out", NULL, "Left Line2 Bypass Mixer"}, | 657 | {"Mono Out", NULL, "Left Line2 Bypass Mixer"}, |
658 | {"Left HP Out", NULL, "Left Line2 Bypass Mixer"}, | 658 | {"Left HP Out", NULL, "Left Line2 Bypass Mixer"}, |
659 | 659 | ||
660 | /* Right Line2 Bypass */ | 660 | /* Right Line2 Bypass */ |
661 | {"Right Line2 Bypass Mixer", "Line Switch", "Right Line2R Mux"}, | 661 | {"Right Line2 Bypass Mixer", "Line Switch", "Right Line2R Mux"}, |
662 | {"Right Line2 Bypass Mixer", "Mono Switch", "Right Line2R Mux"}, | 662 | {"Right Line2 Bypass Mixer", "Mono Switch", "Right Line2R Mux"}, |
663 | {"Right Line2 Bypass Mixer", "HP Switch", "Right Line2R Mux"}, | 663 | {"Right Line2 Bypass Mixer", "HP Switch", "Right Line2R Mux"}, |
664 | {"Right Line2 Bypass Mixer", "HPCOM Switch", "Right Line2R Mux"}, | 664 | {"Right Line2 Bypass Mixer", "HPCOM Switch", "Right Line2R Mux"}, |
665 | 665 | ||
666 | {"Right HPCOM Mux", "differential of HPROUT", "Right Line2 Bypass Mixer"}, | 666 | {"Right HPCOM Mux", "differential of HPROUT", "Right Line2 Bypass Mixer"}, |
667 | {"Right HPCOM Mux", "constant VCM", "Right Line2 Bypass Mixer"}, | 667 | {"Right HPCOM Mux", "constant VCM", "Right Line2 Bypass Mixer"}, |
668 | {"Right HPCOM Mux", "single-ended", "Right Line2 Bypass Mixer"}, | 668 | {"Right HPCOM Mux", "single-ended", "Right Line2 Bypass Mixer"}, |
669 | {"Right HPCOM Mux", "differential of HPLCOM", "Right Line2 Bypass Mixer"}, | 669 | {"Right HPCOM Mux", "differential of HPLCOM", "Right Line2 Bypass Mixer"}, |
670 | {"Right HPCOM Mux", "external feedback", "Right Line2 Bypass Mixer"}, | 670 | {"Right HPCOM Mux", "external feedback", "Right Line2 Bypass Mixer"}, |
671 | 671 | ||
672 | {"Right Line Out", NULL, "Right Line2 Bypass Mixer"}, | 672 | {"Right Line Out", NULL, "Right Line2 Bypass Mixer"}, |
673 | {"Mono Out", NULL, "Right Line2 Bypass Mixer"}, | 673 | {"Mono Out", NULL, "Right Line2 Bypass Mixer"}, |
674 | {"Right HP Out", NULL, "Right Line2 Bypass Mixer"}, | 674 | {"Right HP Out", NULL, "Right Line2 Bypass Mixer"}, |
675 | 675 | ||
676 | /* | 676 | /* |
677 | * Logical path between digital mic enable and GPIO1 modulator clock | 677 | * Logical path between digital mic enable and GPIO1 modulator clock |
678 | * output function | 678 | * output function |
679 | */ | 679 | */ |
680 | {"GPIO1 dmic modclk", NULL, "DMic Rate 128"}, | 680 | {"GPIO1 dmic modclk", NULL, "DMic Rate 128"}, |
681 | {"GPIO1 dmic modclk", NULL, "DMic Rate 64"}, | 681 | {"GPIO1 dmic modclk", NULL, "DMic Rate 64"}, |
682 | {"GPIO1 dmic modclk", NULL, "DMic Rate 32"}, | 682 | {"GPIO1 dmic modclk", NULL, "DMic Rate 32"}, |
683 | }; | 683 | }; |
684 | 684 | ||
685 | static int aic3x_add_widgets(struct snd_soc_codec *codec) | 685 | static int aic3x_add_widgets(struct snd_soc_codec *codec) |
686 | { | 686 | { |
687 | snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets, | 687 | snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets, |
688 | ARRAY_SIZE(aic3x_dapm_widgets)); | 688 | ARRAY_SIZE(aic3x_dapm_widgets)); |
689 | 689 | ||
690 | /* set up audio path interconnects */ | 690 | /* set up audio path interconnects */ |
691 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); | 691 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); |
692 | 692 | ||
693 | snd_soc_dapm_new_widgets(codec); | 693 | snd_soc_dapm_new_widgets(codec); |
694 | return 0; | 694 | return 0; |
695 | } | 695 | } |
696 | 696 | ||
697 | static int aic3x_hw_params(struct snd_pcm_substream *substream, | 697 | static int aic3x_hw_params(struct snd_pcm_substream *substream, |
698 | struct snd_pcm_hw_params *params) | 698 | struct snd_pcm_hw_params *params) |
699 | { | 699 | { |
700 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 700 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
701 | struct snd_soc_device *socdev = rtd->socdev; | 701 | struct snd_soc_device *socdev = rtd->socdev; |
702 | struct snd_soc_codec *codec = socdev->codec; | 702 | struct snd_soc_codec *codec = socdev->codec; |
703 | struct aic3x_priv *aic3x = codec->private_data; | 703 | struct aic3x_priv *aic3x = codec->private_data; |
704 | int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0; | 704 | int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0; |
705 | u8 data, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1; | 705 | u8 data, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1; |
706 | u16 pll_d = 1; | 706 | u16 pll_d = 1; |
707 | 707 | ||
708 | /* select data word length */ | 708 | /* select data word length */ |
709 | data = | 709 | data = |
710 | aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4)); | 710 | aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4)); |
711 | switch (params_format(params)) { | 711 | switch (params_format(params)) { |
712 | case SNDRV_PCM_FORMAT_S16_LE: | 712 | case SNDRV_PCM_FORMAT_S16_LE: |
713 | break; | 713 | break; |
714 | case SNDRV_PCM_FORMAT_S20_3LE: | 714 | case SNDRV_PCM_FORMAT_S20_3LE: |
715 | data |= (0x01 << 4); | 715 | data |= (0x01 << 4); |
716 | break; | 716 | break; |
717 | case SNDRV_PCM_FORMAT_S24_LE: | 717 | case SNDRV_PCM_FORMAT_S24_LE: |
718 | data |= (0x02 << 4); | 718 | data |= (0x02 << 4); |
719 | break; | 719 | break; |
720 | case SNDRV_PCM_FORMAT_S32_LE: | 720 | case SNDRV_PCM_FORMAT_S32_LE: |
721 | data |= (0x03 << 4); | 721 | data |= (0x03 << 4); |
722 | break; | 722 | break; |
723 | } | 723 | } |
724 | aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, data); | 724 | aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, data); |
725 | 725 | ||
726 | /* Fsref can be 44100 or 48000 */ | 726 | /* Fsref can be 44100 or 48000 */ |
727 | fsref = (params_rate(params) % 11025 == 0) ? 44100 : 48000; | 727 | fsref = (params_rate(params) % 11025 == 0) ? 44100 : 48000; |
728 | 728 | ||
729 | /* Try to find a value for Q which allows us to bypass the PLL and | 729 | /* Try to find a value for Q which allows us to bypass the PLL and |
730 | * generate CODEC_CLK directly. */ | 730 | * generate CODEC_CLK directly. */ |
731 | for (pll_q = 2; pll_q < 18; pll_q++) | 731 | for (pll_q = 2; pll_q < 18; pll_q++) |
732 | if (aic3x->sysclk / (128 * pll_q) == fsref) { | 732 | if (aic3x->sysclk / (128 * pll_q) == fsref) { |
733 | bypass_pll = 1; | 733 | bypass_pll = 1; |
734 | break; | 734 | break; |
735 | } | 735 | } |
736 | 736 | ||
737 | if (bypass_pll) { | 737 | if (bypass_pll) { |
738 | pll_q &= 0xf; | 738 | pll_q &= 0xf; |
739 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT); | 739 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT); |
740 | aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV); | 740 | aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV); |
741 | } else | 741 | } else |
742 | aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV); | 742 | aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV); |
743 | 743 | ||
744 | /* Route Left DAC to left channel input and | 744 | /* Route Left DAC to left channel input and |
745 | * right DAC to right channel input */ | 745 | * right DAC to right channel input */ |
746 | data = (LDAC2LCH | RDAC2RCH); | 746 | data = (LDAC2LCH | RDAC2RCH); |
747 | data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000; | 747 | data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000; |
748 | if (params_rate(params) >= 64000) | 748 | if (params_rate(params) >= 64000) |
749 | data |= DUAL_RATE_MODE; | 749 | data |= DUAL_RATE_MODE; |
750 | aic3x_write(codec, AIC3X_CODEC_DATAPATH_REG, data); | 750 | aic3x_write(codec, AIC3X_CODEC_DATAPATH_REG, data); |
751 | 751 | ||
752 | /* codec sample rate select */ | 752 | /* codec sample rate select */ |
753 | data = (fsref * 20) / params_rate(params); | 753 | data = (fsref * 20) / params_rate(params); |
754 | if (params_rate(params) < 64000) | 754 | if (params_rate(params) < 64000) |
755 | data /= 2; | 755 | data /= 2; |
756 | data /= 5; | 756 | data /= 5; |
757 | data -= 2; | 757 | data -= 2; |
758 | data |= (data << 4); | 758 | data |= (data << 4); |
759 | aic3x_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data); | 759 | aic3x_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data); |
760 | 760 | ||
761 | if (bypass_pll) | 761 | if (bypass_pll) |
762 | return 0; | 762 | return 0; |
763 | 763 | ||
764 | /* Use PLL | 764 | /* Use PLL |
765 | * find an apropriate setup for j, d, r and p by iterating over | 765 | * find an apropriate setup for j, d, r and p by iterating over |
766 | * p and r - j and d are calculated for each fraction. | 766 | * p and r - j and d are calculated for each fraction. |
767 | * Up to 128 values are probed, the closest one wins the game. | 767 | * Up to 128 values are probed, the closest one wins the game. |
768 | * The sysclk is divided by 1000 to prevent integer overflows. | 768 | * The sysclk is divided by 1000 to prevent integer overflows. |
769 | */ | 769 | */ |
770 | codec_clk = (2048 * fsref) / (aic3x->sysclk / 1000); | 770 | codec_clk = (2048 * fsref) / (aic3x->sysclk / 1000); |
771 | 771 | ||
772 | for (r = 1; r <= 16; r++) | 772 | for (r = 1; r <= 16; r++) |
773 | for (p = 1; p <= 8; p++) { | 773 | for (p = 1; p <= 8; p++) { |
774 | int clk, tmp = (codec_clk * pll_r * 10) / pll_p; | 774 | int clk, tmp = (codec_clk * pll_r * 10) / pll_p; |
775 | u8 j = tmp / 10000; | 775 | u8 j = tmp / 10000; |
776 | u16 d = tmp % 10000; | 776 | u16 d = tmp % 10000; |
777 | 777 | ||
778 | if (j > 63) | 778 | if (j > 63) |
779 | continue; | 779 | continue; |
780 | 780 | ||
781 | if (d != 0 && aic3x->sysclk < 10000000) | 781 | if (d != 0 && aic3x->sysclk < 10000000) |
782 | continue; | 782 | continue; |
783 | 783 | ||
784 | /* This is actually 1000 * ((j + (d/10000)) * r) / p | 784 | /* This is actually 1000 * ((j + (d/10000)) * r) / p |
785 | * The term had to be converted to get rid of the | 785 | * The term had to be converted to get rid of the |
786 | * division by 10000 */ | 786 | * division by 10000 */ |
787 | clk = ((10000 * j * r) + (d * r)) / (10 * p); | 787 | clk = ((10000 * j * r) + (d * r)) / (10 * p); |
788 | 788 | ||
789 | /* check whether this values get closer than the best | 789 | /* check whether this values get closer than the best |
790 | * ones we had before */ | 790 | * ones we had before */ |
791 | if (abs(codec_clk - clk) < abs(codec_clk - last_clk)) { | 791 | if (abs(codec_clk - clk) < abs(codec_clk - last_clk)) { |
792 | pll_j = j; pll_d = d; pll_r = r; pll_p = p; | 792 | pll_j = j; pll_d = d; pll_r = r; pll_p = p; |
793 | last_clk = clk; | 793 | last_clk = clk; |
794 | } | 794 | } |
795 | 795 | ||
796 | /* Early exit for exact matches */ | 796 | /* Early exit for exact matches */ |
797 | if (clk == codec_clk) | 797 | if (clk == codec_clk) |
798 | break; | 798 | break; |
799 | } | 799 | } |
800 | 800 | ||
801 | if (last_clk == 0) { | 801 | if (last_clk == 0) { |
802 | printk(KERN_ERR "%s(): unable to setup PLL\n", __func__); | 802 | printk(KERN_ERR "%s(): unable to setup PLL\n", __func__); |
803 | return -EINVAL; | 803 | return -EINVAL; |
804 | } | 804 | } |
805 | 805 | ||
806 | data = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); | 806 | data = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); |
807 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT)); | 807 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT)); |
808 | aic3x_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG, pll_r << PLLR_SHIFT); | 808 | aic3x_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG, pll_r << PLLR_SHIFT); |
809 | aic3x_write(codec, AIC3X_PLL_PROGB_REG, pll_j << PLLJ_SHIFT); | 809 | aic3x_write(codec, AIC3X_PLL_PROGB_REG, pll_j << PLLJ_SHIFT); |
810 | aic3x_write(codec, AIC3X_PLL_PROGC_REG, (pll_d >> 6) << PLLD_MSB_SHIFT); | 810 | aic3x_write(codec, AIC3X_PLL_PROGC_REG, (pll_d >> 6) << PLLD_MSB_SHIFT); |
811 | aic3x_write(codec, AIC3X_PLL_PROGD_REG, | 811 | aic3x_write(codec, AIC3X_PLL_PROGD_REG, |
812 | (pll_d & 0x3F) << PLLD_LSB_SHIFT); | 812 | (pll_d & 0x3F) << PLLD_LSB_SHIFT); |
813 | 813 | ||
814 | return 0; | 814 | return 0; |
815 | } | 815 | } |
816 | 816 | ||
817 | static int aic3x_mute(struct snd_soc_dai *dai, int mute) | 817 | static int aic3x_mute(struct snd_soc_dai *dai, int mute) |
818 | { | 818 | { |
819 | struct snd_soc_codec *codec = dai->codec; | 819 | struct snd_soc_codec *codec = dai->codec; |
820 | u8 ldac_reg = aic3x_read_reg_cache(codec, LDAC_VOL) & ~MUTE_ON; | 820 | u8 ldac_reg = aic3x_read_reg_cache(codec, LDAC_VOL) & ~MUTE_ON; |
821 | u8 rdac_reg = aic3x_read_reg_cache(codec, RDAC_VOL) & ~MUTE_ON; | 821 | u8 rdac_reg = aic3x_read_reg_cache(codec, RDAC_VOL) & ~MUTE_ON; |
822 | 822 | ||
823 | if (mute) { | 823 | if (mute) { |
824 | aic3x_write(codec, LDAC_VOL, ldac_reg | MUTE_ON); | 824 | aic3x_write(codec, LDAC_VOL, ldac_reg | MUTE_ON); |
825 | aic3x_write(codec, RDAC_VOL, rdac_reg | MUTE_ON); | 825 | aic3x_write(codec, RDAC_VOL, rdac_reg | MUTE_ON); |
826 | } else { | 826 | } else { |
827 | aic3x_write(codec, LDAC_VOL, ldac_reg); | 827 | aic3x_write(codec, LDAC_VOL, ldac_reg); |
828 | aic3x_write(codec, RDAC_VOL, rdac_reg); | 828 | aic3x_write(codec, RDAC_VOL, rdac_reg); |
829 | } | 829 | } |
830 | 830 | ||
831 | return 0; | 831 | return 0; |
832 | } | 832 | } |
833 | 833 | ||
834 | static int aic3x_set_dai_sysclk(struct snd_soc_dai *codec_dai, | 834 | static int aic3x_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
835 | int clk_id, unsigned int freq, int dir) | 835 | int clk_id, unsigned int freq, int dir) |
836 | { | 836 | { |
837 | struct snd_soc_codec *codec = codec_dai->codec; | 837 | struct snd_soc_codec *codec = codec_dai->codec; |
838 | struct aic3x_priv *aic3x = codec->private_data; | 838 | struct aic3x_priv *aic3x = codec->private_data; |
839 | 839 | ||
840 | aic3x->sysclk = freq; | 840 | aic3x->sysclk = freq; |
841 | return 0; | 841 | return 0; |
842 | } | 842 | } |
843 | 843 | ||
844 | static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, | 844 | static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, |
845 | unsigned int fmt) | 845 | unsigned int fmt) |
846 | { | 846 | { |
847 | struct snd_soc_codec *codec = codec_dai->codec; | 847 | struct snd_soc_codec *codec = codec_dai->codec; |
848 | struct aic3x_priv *aic3x = codec->private_data; | 848 | struct aic3x_priv *aic3x = codec->private_data; |
849 | u8 iface_areg, iface_breg; | 849 | u8 iface_areg, iface_breg; |
850 | 850 | ||
851 | iface_areg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f; | 851 | iface_areg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f; |
852 | iface_breg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f; | 852 | iface_breg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f; |
853 | 853 | ||
854 | /* set master/slave audio interface */ | 854 | /* set master/slave audio interface */ |
855 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 855 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
856 | case SND_SOC_DAIFMT_CBM_CFM: | 856 | case SND_SOC_DAIFMT_CBM_CFM: |
857 | aic3x->master = 1; | 857 | aic3x->master = 1; |
858 | iface_areg |= BIT_CLK_MASTER | WORD_CLK_MASTER; | 858 | iface_areg |= BIT_CLK_MASTER | WORD_CLK_MASTER; |
859 | break; | 859 | break; |
860 | case SND_SOC_DAIFMT_CBS_CFS: | 860 | case SND_SOC_DAIFMT_CBS_CFS: |
861 | aic3x->master = 0; | 861 | aic3x->master = 0; |
862 | break; | 862 | break; |
863 | default: | 863 | default: |
864 | return -EINVAL; | 864 | return -EINVAL; |
865 | } | 865 | } |
866 | 866 | ||
867 | /* interface format */ | 867 | /* interface format */ |
868 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 868 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
869 | case SND_SOC_DAIFMT_I2S: | 869 | case SND_SOC_DAIFMT_I2S: |
870 | break; | 870 | break; |
871 | case SND_SOC_DAIFMT_DSP_A: | 871 | case SND_SOC_DAIFMT_DSP_A: |
872 | iface_breg |= (0x01 << 6); | 872 | iface_breg |= (0x01 << 6); |
873 | break; | 873 | break; |
874 | case SND_SOC_DAIFMT_RIGHT_J: | 874 | case SND_SOC_DAIFMT_RIGHT_J: |
875 | iface_breg |= (0x02 << 6); | 875 | iface_breg |= (0x02 << 6); |
876 | break; | 876 | break; |
877 | case SND_SOC_DAIFMT_LEFT_J: | 877 | case SND_SOC_DAIFMT_LEFT_J: |
878 | iface_breg |= (0x03 << 6); | 878 | iface_breg |= (0x03 << 6); |
879 | break; | 879 | break; |
880 | default: | 880 | default: |
881 | return -EINVAL; | 881 | return -EINVAL; |
882 | } | 882 | } |
883 | 883 | ||
884 | /* set iface */ | 884 | /* set iface */ |
885 | aic3x_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg); | 885 | aic3x_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg); |
886 | aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg); | 886 | aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg); |
887 | 887 | ||
888 | return 0; | 888 | return 0; |
889 | } | 889 | } |
890 | 890 | ||
891 | static int aic3x_set_bias_level(struct snd_soc_codec *codec, | 891 | static int aic3x_set_bias_level(struct snd_soc_codec *codec, |
892 | enum snd_soc_bias_level level) | 892 | enum snd_soc_bias_level level) |
893 | { | 893 | { |
894 | struct aic3x_priv *aic3x = codec->private_data; | 894 | struct aic3x_priv *aic3x = codec->private_data; |
895 | u8 reg; | 895 | u8 reg; |
896 | 896 | ||
897 | switch (level) { | 897 | switch (level) { |
898 | case SND_SOC_BIAS_ON: | 898 | case SND_SOC_BIAS_ON: |
899 | /* all power is driven by DAPM system */ | 899 | /* all power is driven by DAPM system */ |
900 | if (aic3x->master) { | 900 | if (aic3x->master) { |
901 | /* enable pll */ | 901 | /* enable pll */ |
902 | reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); | 902 | reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); |
903 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, | 903 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, |
904 | reg | PLL_ENABLE); | 904 | reg | PLL_ENABLE); |
905 | } | 905 | } |
906 | break; | 906 | break; |
907 | case SND_SOC_BIAS_PREPARE: | 907 | case SND_SOC_BIAS_PREPARE: |
908 | break; | 908 | break; |
909 | case SND_SOC_BIAS_STANDBY: | 909 | case SND_SOC_BIAS_STANDBY: |
910 | /* | 910 | /* |
911 | * all power is driven by DAPM system, | 911 | * all power is driven by DAPM system, |
912 | * so output power is safe if bypass was set | 912 | * so output power is safe if bypass was set |
913 | */ | 913 | */ |
914 | if (aic3x->master) { | 914 | if (aic3x->master) { |
915 | /* disable pll */ | 915 | /* disable pll */ |
916 | reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); | 916 | reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); |
917 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, | 917 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, |
918 | reg & ~PLL_ENABLE); | 918 | reg & ~PLL_ENABLE); |
919 | } | 919 | } |
920 | break; | 920 | break; |
921 | case SND_SOC_BIAS_OFF: | 921 | case SND_SOC_BIAS_OFF: |
922 | /* force all power off */ | 922 | /* force all power off */ |
923 | reg = aic3x_read_reg_cache(codec, LINE1L_2_LADC_CTRL); | 923 | reg = aic3x_read_reg_cache(codec, LINE1L_2_LADC_CTRL); |
924 | aic3x_write(codec, LINE1L_2_LADC_CTRL, reg & ~LADC_PWR_ON); | 924 | aic3x_write(codec, LINE1L_2_LADC_CTRL, reg & ~LADC_PWR_ON); |
925 | reg = aic3x_read_reg_cache(codec, LINE1R_2_RADC_CTRL); | 925 | reg = aic3x_read_reg_cache(codec, LINE1R_2_RADC_CTRL); |
926 | aic3x_write(codec, LINE1R_2_RADC_CTRL, reg & ~RADC_PWR_ON); | 926 | aic3x_write(codec, LINE1R_2_RADC_CTRL, reg & ~RADC_PWR_ON); |
927 | 927 | ||
928 | reg = aic3x_read_reg_cache(codec, DAC_PWR); | 928 | reg = aic3x_read_reg_cache(codec, DAC_PWR); |
929 | aic3x_write(codec, DAC_PWR, reg & ~(LDAC_PWR_ON | RDAC_PWR_ON)); | 929 | aic3x_write(codec, DAC_PWR, reg & ~(LDAC_PWR_ON | RDAC_PWR_ON)); |
930 | 930 | ||
931 | reg = aic3x_read_reg_cache(codec, HPLOUT_CTRL); | 931 | reg = aic3x_read_reg_cache(codec, HPLOUT_CTRL); |
932 | aic3x_write(codec, HPLOUT_CTRL, reg & ~HPLOUT_PWR_ON); | 932 | aic3x_write(codec, HPLOUT_CTRL, reg & ~HPLOUT_PWR_ON); |
933 | reg = aic3x_read_reg_cache(codec, HPROUT_CTRL); | 933 | reg = aic3x_read_reg_cache(codec, HPROUT_CTRL); |
934 | aic3x_write(codec, HPROUT_CTRL, reg & ~HPROUT_PWR_ON); | 934 | aic3x_write(codec, HPROUT_CTRL, reg & ~HPROUT_PWR_ON); |
935 | 935 | ||
936 | reg = aic3x_read_reg_cache(codec, HPLCOM_CTRL); | 936 | reg = aic3x_read_reg_cache(codec, HPLCOM_CTRL); |
937 | aic3x_write(codec, HPLCOM_CTRL, reg & ~HPLCOM_PWR_ON); | 937 | aic3x_write(codec, HPLCOM_CTRL, reg & ~HPLCOM_PWR_ON); |
938 | reg = aic3x_read_reg_cache(codec, HPRCOM_CTRL); | 938 | reg = aic3x_read_reg_cache(codec, HPRCOM_CTRL); |
939 | aic3x_write(codec, HPRCOM_CTRL, reg & ~HPRCOM_PWR_ON); | 939 | aic3x_write(codec, HPRCOM_CTRL, reg & ~HPRCOM_PWR_ON); |
940 | 940 | ||
941 | reg = aic3x_read_reg_cache(codec, MONOLOPM_CTRL); | 941 | reg = aic3x_read_reg_cache(codec, MONOLOPM_CTRL); |
942 | aic3x_write(codec, MONOLOPM_CTRL, reg & ~MONOLOPM_PWR_ON); | 942 | aic3x_write(codec, MONOLOPM_CTRL, reg & ~MONOLOPM_PWR_ON); |
943 | 943 | ||
944 | reg = aic3x_read_reg_cache(codec, LLOPM_CTRL); | 944 | reg = aic3x_read_reg_cache(codec, LLOPM_CTRL); |
945 | aic3x_write(codec, LLOPM_CTRL, reg & ~LLOPM_PWR_ON); | 945 | aic3x_write(codec, LLOPM_CTRL, reg & ~LLOPM_PWR_ON); |
946 | reg = aic3x_read_reg_cache(codec, RLOPM_CTRL); | 946 | reg = aic3x_read_reg_cache(codec, RLOPM_CTRL); |
947 | aic3x_write(codec, RLOPM_CTRL, reg & ~RLOPM_PWR_ON); | 947 | aic3x_write(codec, RLOPM_CTRL, reg & ~RLOPM_PWR_ON); |
948 | 948 | ||
949 | if (aic3x->master) { | 949 | if (aic3x->master) { |
950 | /* disable pll */ | 950 | /* disable pll */ |
951 | reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); | 951 | reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); |
952 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, | 952 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, |
953 | reg & ~PLL_ENABLE); | 953 | reg & ~PLL_ENABLE); |
954 | } | 954 | } |
955 | break; | 955 | break; |
956 | } | 956 | } |
957 | codec->bias_level = level; | 957 | codec->bias_level = level; |
958 | 958 | ||
959 | return 0; | 959 | return 0; |
960 | } | 960 | } |
961 | 961 | ||
962 | void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state) | 962 | void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state) |
963 | { | 963 | { |
964 | u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG; | 964 | u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG; |
965 | u8 bit = gpio ? 3: 0; | 965 | u8 bit = gpio ? 3: 0; |
966 | u8 val = aic3x_read_reg_cache(codec, reg) & ~(1 << bit); | 966 | u8 val = aic3x_read_reg_cache(codec, reg) & ~(1 << bit); |
967 | aic3x_write(codec, reg, val | (!!state << bit)); | 967 | aic3x_write(codec, reg, val | (!!state << bit)); |
968 | } | 968 | } |
969 | EXPORT_SYMBOL_GPL(aic3x_set_gpio); | 969 | EXPORT_SYMBOL_GPL(aic3x_set_gpio); |
970 | 970 | ||
971 | int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio) | 971 | int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio) |
972 | { | 972 | { |
973 | u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG; | 973 | u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG; |
974 | u8 val, bit = gpio ? 2: 1; | 974 | u8 val, bit = gpio ? 2: 1; |
975 | 975 | ||
976 | aic3x_read(codec, reg, &val); | 976 | aic3x_read(codec, reg, &val); |
977 | return (val >> bit) & 1; | 977 | return (val >> bit) & 1; |
978 | } | 978 | } |
979 | EXPORT_SYMBOL_GPL(aic3x_get_gpio); | 979 | EXPORT_SYMBOL_GPL(aic3x_get_gpio); |
980 | 980 | ||
981 | int aic3x_headset_detected(struct snd_soc_codec *codec) | 981 | int aic3x_headset_detected(struct snd_soc_codec *codec) |
982 | { | 982 | { |
983 | u8 val; | 983 | u8 val; |
984 | aic3x_read(codec, AIC3X_RT_IRQ_FLAGS_REG, &val); | 984 | aic3x_read(codec, AIC3X_RT_IRQ_FLAGS_REG, &val); |
985 | return (val >> 2) & 1; | 985 | return (val >> 2) & 1; |
986 | } | 986 | } |
987 | EXPORT_SYMBOL_GPL(aic3x_headset_detected); | 987 | EXPORT_SYMBOL_GPL(aic3x_headset_detected); |
988 | 988 | ||
989 | #define AIC3X_RATES SNDRV_PCM_RATE_8000_96000 | 989 | #define AIC3X_RATES SNDRV_PCM_RATE_8000_96000 |
990 | #define AIC3X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ | 990 | #define AIC3X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ |
991 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) | 991 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) |
992 | 992 | ||
993 | struct snd_soc_dai aic3x_dai = { | 993 | struct snd_soc_dai aic3x_dai = { |
994 | .name = "aic3x", | 994 | .name = "aic3x", |
995 | .playback = { | 995 | .playback = { |
996 | .stream_name = "Playback", | 996 | .stream_name = "Playback", |
997 | .channels_min = 1, | 997 | .channels_min = 1, |
998 | .channels_max = 2, | 998 | .channels_max = 2, |
999 | .rates = AIC3X_RATES, | 999 | .rates = AIC3X_RATES, |
1000 | .formats = AIC3X_FORMATS,}, | 1000 | .formats = AIC3X_FORMATS,}, |
1001 | .capture = { | 1001 | .capture = { |
1002 | .stream_name = "Capture", | 1002 | .stream_name = "Capture", |
1003 | .channels_min = 1, | 1003 | .channels_min = 1, |
1004 | .channels_max = 2, | 1004 | .channels_max = 2, |
1005 | .rates = AIC3X_RATES, | 1005 | .rates = AIC3X_RATES, |
1006 | .formats = AIC3X_FORMATS,}, | 1006 | .formats = AIC3X_FORMATS,}, |
1007 | .ops = { | 1007 | .ops = { |
1008 | .hw_params = aic3x_hw_params, | 1008 | .hw_params = aic3x_hw_params, |
1009 | }, | 1009 | }, |
1010 | .dai_ops = { | 1010 | .dai_ops = { |
1011 | .digital_mute = aic3x_mute, | 1011 | .digital_mute = aic3x_mute, |
1012 | .set_sysclk = aic3x_set_dai_sysclk, | 1012 | .set_sysclk = aic3x_set_dai_sysclk, |
1013 | .set_fmt = aic3x_set_dai_fmt, | 1013 | .set_fmt = aic3x_set_dai_fmt, |
1014 | } | 1014 | } |
1015 | }; | 1015 | }; |
1016 | EXPORT_SYMBOL_GPL(aic3x_dai); | 1016 | EXPORT_SYMBOL_GPL(aic3x_dai); |
1017 | 1017 | ||
1018 | static int aic3x_suspend(struct platform_device *pdev, pm_message_t state) | 1018 | static int aic3x_suspend(struct platform_device *pdev, pm_message_t state) |
1019 | { | 1019 | { |
1020 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1020 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1021 | struct snd_soc_codec *codec = socdev->codec; | 1021 | struct snd_soc_codec *codec = socdev->codec; |
1022 | 1022 | ||
1023 | aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1023 | aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1024 | 1024 | ||
1025 | return 0; | 1025 | return 0; |
1026 | } | 1026 | } |
1027 | 1027 | ||
1028 | static int aic3x_resume(struct platform_device *pdev) | 1028 | static int aic3x_resume(struct platform_device *pdev) |
1029 | { | 1029 | { |
1030 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1030 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1031 | struct snd_soc_codec *codec = socdev->codec; | 1031 | struct snd_soc_codec *codec = socdev->codec; |
1032 | int i; | 1032 | int i; |
1033 | u8 data[2]; | 1033 | u8 data[2]; |
1034 | u8 *cache = codec->reg_cache; | 1034 | u8 *cache = codec->reg_cache; |
1035 | 1035 | ||
1036 | /* Sync reg_cache with the hardware */ | 1036 | /* Sync reg_cache with the hardware */ |
1037 | for (i = 0; i < ARRAY_SIZE(aic3x_reg); i++) { | 1037 | for (i = 0; i < ARRAY_SIZE(aic3x_reg); i++) { |
1038 | data[0] = i; | 1038 | data[0] = i; |
1039 | data[1] = cache[i]; | 1039 | data[1] = cache[i]; |
1040 | codec->hw_write(codec->control_data, data, 2); | 1040 | codec->hw_write(codec->control_data, data, 2); |
1041 | } | 1041 | } |
1042 | 1042 | ||
1043 | aic3x_set_bias_level(codec, codec->suspend_bias_level); | 1043 | aic3x_set_bias_level(codec, codec->suspend_bias_level); |
1044 | 1044 | ||
1045 | return 0; | 1045 | return 0; |
1046 | } | 1046 | } |
1047 | 1047 | ||
1048 | /* | 1048 | /* |
1049 | * initialise the AIC3X driver | 1049 | * initialise the AIC3X driver |
1050 | * register the mixer and dsp interfaces with the kernel | 1050 | * register the mixer and dsp interfaces with the kernel |
1051 | */ | 1051 | */ |
1052 | static int aic3x_init(struct snd_soc_device *socdev) | 1052 | static int aic3x_init(struct snd_soc_device *socdev) |
1053 | { | 1053 | { |
1054 | struct snd_soc_codec *codec = socdev->codec; | 1054 | struct snd_soc_codec *codec = socdev->codec; |
1055 | struct aic3x_setup_data *setup = socdev->codec_data; | 1055 | struct aic3x_setup_data *setup = socdev->codec_data; |
1056 | int reg, ret = 0; | 1056 | int reg, ret = 0; |
1057 | 1057 | ||
1058 | codec->name = "aic3x"; | 1058 | codec->name = "aic3x"; |
1059 | codec->owner = THIS_MODULE; | 1059 | codec->owner = THIS_MODULE; |
1060 | codec->read = aic3x_read_reg_cache; | 1060 | codec->read = aic3x_read_reg_cache; |
1061 | codec->write = aic3x_write; | 1061 | codec->write = aic3x_write; |
1062 | codec->set_bias_level = aic3x_set_bias_level; | 1062 | codec->set_bias_level = aic3x_set_bias_level; |
1063 | codec->dai = &aic3x_dai; | 1063 | codec->dai = &aic3x_dai; |
1064 | codec->num_dai = 1; | 1064 | codec->num_dai = 1; |
1065 | codec->reg_cache_size = ARRAY_SIZE(aic3x_reg); | 1065 | codec->reg_cache_size = ARRAY_SIZE(aic3x_reg); |
1066 | codec->reg_cache = kmemdup(aic3x_reg, sizeof(aic3x_reg), GFP_KERNEL); | 1066 | codec->reg_cache = kmemdup(aic3x_reg, sizeof(aic3x_reg), GFP_KERNEL); |
1067 | if (codec->reg_cache == NULL) | 1067 | if (codec->reg_cache == NULL) |
1068 | return -ENOMEM; | 1068 | return -ENOMEM; |
1069 | 1069 | ||
1070 | aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT); | 1070 | aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT); |
1071 | aic3x_write(codec, AIC3X_RESET, SOFT_RESET); | 1071 | aic3x_write(codec, AIC3X_RESET, SOFT_RESET); |
1072 | 1072 | ||
1073 | /* register pcms */ | 1073 | /* register pcms */ |
1074 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 1074 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
1075 | if (ret < 0) { | 1075 | if (ret < 0) { |
1076 | printk(KERN_ERR "aic3x: failed to create pcms\n"); | 1076 | printk(KERN_ERR "aic3x: failed to create pcms\n"); |
1077 | goto pcm_err; | 1077 | goto pcm_err; |
1078 | } | 1078 | } |
1079 | 1079 | ||
1080 | /* DAC default volume and mute */ | 1080 | /* DAC default volume and mute */ |
1081 | aic3x_write(codec, LDAC_VOL, DEFAULT_VOL | MUTE_ON); | 1081 | aic3x_write(codec, LDAC_VOL, DEFAULT_VOL | MUTE_ON); |
1082 | aic3x_write(codec, RDAC_VOL, DEFAULT_VOL | MUTE_ON); | 1082 | aic3x_write(codec, RDAC_VOL, DEFAULT_VOL | MUTE_ON); |
1083 | 1083 | ||
1084 | /* DAC to HP default volume and route to Output mixer */ | 1084 | /* DAC to HP default volume and route to Output mixer */ |
1085 | aic3x_write(codec, DACL1_2_HPLOUT_VOL, DEFAULT_VOL | ROUTE_ON); | 1085 | aic3x_write(codec, DACL1_2_HPLOUT_VOL, DEFAULT_VOL | ROUTE_ON); |
1086 | aic3x_write(codec, DACR1_2_HPROUT_VOL, DEFAULT_VOL | ROUTE_ON); | 1086 | aic3x_write(codec, DACR1_2_HPROUT_VOL, DEFAULT_VOL | ROUTE_ON); |
1087 | aic3x_write(codec, DACL1_2_HPLCOM_VOL, DEFAULT_VOL | ROUTE_ON); | 1087 | aic3x_write(codec, DACL1_2_HPLCOM_VOL, DEFAULT_VOL | ROUTE_ON); |
1088 | aic3x_write(codec, DACR1_2_HPRCOM_VOL, DEFAULT_VOL | ROUTE_ON); | 1088 | aic3x_write(codec, DACR1_2_HPRCOM_VOL, DEFAULT_VOL | ROUTE_ON); |
1089 | /* DAC to Line Out default volume and route to Output mixer */ | 1089 | /* DAC to Line Out default volume and route to Output mixer */ |
1090 | aic3x_write(codec, DACL1_2_LLOPM_VOL, DEFAULT_VOL | ROUTE_ON); | 1090 | aic3x_write(codec, DACL1_2_LLOPM_VOL, DEFAULT_VOL | ROUTE_ON); |
1091 | aic3x_write(codec, DACR1_2_RLOPM_VOL, DEFAULT_VOL | ROUTE_ON); | 1091 | aic3x_write(codec, DACR1_2_RLOPM_VOL, DEFAULT_VOL | ROUTE_ON); |
1092 | /* DAC to Mono Line Out default volume and route to Output mixer */ | 1092 | /* DAC to Mono Line Out default volume and route to Output mixer */ |
1093 | aic3x_write(codec, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON); | 1093 | aic3x_write(codec, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON); |
1094 | aic3x_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON); | 1094 | aic3x_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON); |
1095 | 1095 | ||
1096 | /* unmute all outputs */ | 1096 | /* unmute all outputs */ |
1097 | reg = aic3x_read_reg_cache(codec, LLOPM_CTRL); | 1097 | reg = aic3x_read_reg_cache(codec, LLOPM_CTRL); |
1098 | aic3x_write(codec, LLOPM_CTRL, reg | UNMUTE); | 1098 | aic3x_write(codec, LLOPM_CTRL, reg | UNMUTE); |
1099 | reg = aic3x_read_reg_cache(codec, RLOPM_CTRL); | 1099 | reg = aic3x_read_reg_cache(codec, RLOPM_CTRL); |
1100 | aic3x_write(codec, RLOPM_CTRL, reg | UNMUTE); | 1100 | aic3x_write(codec, RLOPM_CTRL, reg | UNMUTE); |
1101 | reg = aic3x_read_reg_cache(codec, MONOLOPM_CTRL); | 1101 | reg = aic3x_read_reg_cache(codec, MONOLOPM_CTRL); |
1102 | aic3x_write(codec, MONOLOPM_CTRL, reg | UNMUTE); | 1102 | aic3x_write(codec, MONOLOPM_CTRL, reg | UNMUTE); |
1103 | reg = aic3x_read_reg_cache(codec, HPLOUT_CTRL); | 1103 | reg = aic3x_read_reg_cache(codec, HPLOUT_CTRL); |
1104 | aic3x_write(codec, HPLOUT_CTRL, reg | UNMUTE); | 1104 | aic3x_write(codec, HPLOUT_CTRL, reg | UNMUTE); |
1105 | reg = aic3x_read_reg_cache(codec, HPROUT_CTRL); | 1105 | reg = aic3x_read_reg_cache(codec, HPROUT_CTRL); |
1106 | aic3x_write(codec, HPROUT_CTRL, reg | UNMUTE); | 1106 | aic3x_write(codec, HPROUT_CTRL, reg | UNMUTE); |
1107 | reg = aic3x_read_reg_cache(codec, HPLCOM_CTRL); | 1107 | reg = aic3x_read_reg_cache(codec, HPLCOM_CTRL); |
1108 | aic3x_write(codec, HPLCOM_CTRL, reg | UNMUTE); | 1108 | aic3x_write(codec, HPLCOM_CTRL, reg | UNMUTE); |
1109 | reg = aic3x_read_reg_cache(codec, HPRCOM_CTRL); | 1109 | reg = aic3x_read_reg_cache(codec, HPRCOM_CTRL); |
1110 | aic3x_write(codec, HPRCOM_CTRL, reg | UNMUTE); | 1110 | aic3x_write(codec, HPRCOM_CTRL, reg | UNMUTE); |
1111 | 1111 | ||
1112 | /* ADC default volume and unmute */ | 1112 | /* ADC default volume and unmute */ |
1113 | aic3x_write(codec, LADC_VOL, DEFAULT_GAIN); | 1113 | aic3x_write(codec, LADC_VOL, DEFAULT_GAIN); |
1114 | aic3x_write(codec, RADC_VOL, DEFAULT_GAIN); | 1114 | aic3x_write(codec, RADC_VOL, DEFAULT_GAIN); |
1115 | /* By default route Line1 to ADC PGA mixer */ | 1115 | /* By default route Line1 to ADC PGA mixer */ |
1116 | aic3x_write(codec, LINE1L_2_LADC_CTRL, 0x0); | 1116 | aic3x_write(codec, LINE1L_2_LADC_CTRL, 0x0); |
1117 | aic3x_write(codec, LINE1R_2_RADC_CTRL, 0x0); | 1117 | aic3x_write(codec, LINE1R_2_RADC_CTRL, 0x0); |
1118 | 1118 | ||
1119 | /* PGA to HP Bypass default volume, disconnect from Output Mixer */ | 1119 | /* PGA to HP Bypass default volume, disconnect from Output Mixer */ |
1120 | aic3x_write(codec, PGAL_2_HPLOUT_VOL, DEFAULT_VOL); | 1120 | aic3x_write(codec, PGAL_2_HPLOUT_VOL, DEFAULT_VOL); |
1121 | aic3x_write(codec, PGAR_2_HPROUT_VOL, DEFAULT_VOL); | 1121 | aic3x_write(codec, PGAR_2_HPROUT_VOL, DEFAULT_VOL); |
1122 | aic3x_write(codec, PGAL_2_HPLCOM_VOL, DEFAULT_VOL); | 1122 | aic3x_write(codec, PGAL_2_HPLCOM_VOL, DEFAULT_VOL); |
1123 | aic3x_write(codec, PGAR_2_HPRCOM_VOL, DEFAULT_VOL); | 1123 | aic3x_write(codec, PGAR_2_HPRCOM_VOL, DEFAULT_VOL); |
1124 | /* PGA to Line Out default volume, disconnect from Output Mixer */ | 1124 | /* PGA to Line Out default volume, disconnect from Output Mixer */ |
1125 | aic3x_write(codec, PGAL_2_LLOPM_VOL, DEFAULT_VOL); | 1125 | aic3x_write(codec, PGAL_2_LLOPM_VOL, DEFAULT_VOL); |
1126 | aic3x_write(codec, PGAR_2_RLOPM_VOL, DEFAULT_VOL); | 1126 | aic3x_write(codec, PGAR_2_RLOPM_VOL, DEFAULT_VOL); |
1127 | /* PGA to Mono Line Out default volume, disconnect from Output Mixer */ | 1127 | /* PGA to Mono Line Out default volume, disconnect from Output Mixer */ |
1128 | aic3x_write(codec, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL); | 1128 | aic3x_write(codec, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL); |
1129 | aic3x_write(codec, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL); | 1129 | aic3x_write(codec, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL); |
1130 | 1130 | ||
1131 | /* Line2 to HP Bypass default volume, disconnect from Output Mixer */ | 1131 | /* Line2 to HP Bypass default volume, disconnect from Output Mixer */ |
1132 | aic3x_write(codec, LINE2L_2_HPLOUT_VOL, DEFAULT_VOL); | 1132 | aic3x_write(codec, LINE2L_2_HPLOUT_VOL, DEFAULT_VOL); |
1133 | aic3x_write(codec, LINE2R_2_HPROUT_VOL, DEFAULT_VOL); | 1133 | aic3x_write(codec, LINE2R_2_HPROUT_VOL, DEFAULT_VOL); |
1134 | aic3x_write(codec, LINE2L_2_HPLCOM_VOL, DEFAULT_VOL); | 1134 | aic3x_write(codec, LINE2L_2_HPLCOM_VOL, DEFAULT_VOL); |
1135 | aic3x_write(codec, LINE2R_2_HPRCOM_VOL, DEFAULT_VOL); | 1135 | aic3x_write(codec, LINE2R_2_HPRCOM_VOL, DEFAULT_VOL); |
1136 | /* Line2 Line Out default volume, disconnect from Output Mixer */ | 1136 | /* Line2 Line Out default volume, disconnect from Output Mixer */ |
1137 | aic3x_write(codec, LINE2L_2_LLOPM_VOL, DEFAULT_VOL); | 1137 | aic3x_write(codec, LINE2L_2_LLOPM_VOL, DEFAULT_VOL); |
1138 | aic3x_write(codec, LINE2R_2_RLOPM_VOL, DEFAULT_VOL); | 1138 | aic3x_write(codec, LINE2R_2_RLOPM_VOL, DEFAULT_VOL); |
1139 | /* Line2 to Mono Out default volume, disconnect from Output Mixer */ | 1139 | /* Line2 to Mono Out default volume, disconnect from Output Mixer */ |
1140 | aic3x_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL); | 1140 | aic3x_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL); |
1141 | aic3x_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL); | 1141 | aic3x_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL); |
1142 | 1142 | ||
1143 | /* off, with power on */ | 1143 | /* off, with power on */ |
1144 | aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1144 | aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1145 | 1145 | ||
1146 | /* setup GPIO functions */ | 1146 | /* setup GPIO functions */ |
1147 | aic3x_write(codec, AIC3X_GPIO1_REG, (setup->gpio_func[0] & 0xf) << 4); | 1147 | aic3x_write(codec, AIC3X_GPIO1_REG, (setup->gpio_func[0] & 0xf) << 4); |
1148 | aic3x_write(codec, AIC3X_GPIO2_REG, (setup->gpio_func[1] & 0xf) << 4); | 1148 | aic3x_write(codec, AIC3X_GPIO2_REG, (setup->gpio_func[1] & 0xf) << 4); |
1149 | 1149 | ||
1150 | aic3x_add_controls(codec); | 1150 | aic3x_add_controls(codec); |
1151 | aic3x_add_widgets(codec); | 1151 | aic3x_add_widgets(codec); |
1152 | ret = snd_soc_register_card(socdev); | 1152 | ret = snd_soc_register_card(socdev); |
1153 | if (ret < 0) { | 1153 | if (ret < 0) { |
1154 | printk(KERN_ERR "aic3x: failed to register card\n"); | 1154 | printk(KERN_ERR "aic3x: failed to register card\n"); |
1155 | goto card_err; | 1155 | goto card_err; |
1156 | } | 1156 | } |
1157 | 1157 | ||
1158 | return ret; | 1158 | return ret; |
1159 | 1159 | ||
1160 | card_err: | 1160 | card_err: |
1161 | snd_soc_free_pcms(socdev); | 1161 | snd_soc_free_pcms(socdev); |
1162 | snd_soc_dapm_free(socdev); | 1162 | snd_soc_dapm_free(socdev); |
1163 | pcm_err: | 1163 | pcm_err: |
1164 | kfree(codec->reg_cache); | 1164 | kfree(codec->reg_cache); |
1165 | return ret; | 1165 | return ret; |
1166 | } | 1166 | } |
1167 | 1167 | ||
1168 | static struct snd_soc_device *aic3x_socdev; | 1168 | static struct snd_soc_device *aic3x_socdev; |
1169 | 1169 | ||
1170 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1170 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1171 | /* | 1171 | /* |
1172 | * AIC3X 2 wire address can be up to 4 devices with device addresses | 1172 | * AIC3X 2 wire address can be up to 4 devices with device addresses |
1173 | * 0x18, 0x19, 0x1A, 0x1B | 1173 | * 0x18, 0x19, 0x1A, 0x1B |
1174 | */ | 1174 | */ |
1175 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | 1175 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; |
1176 | 1176 | ||
1177 | /* Magic definition of all other variables and things */ | 1177 | /* Magic definition of all other variables and things */ |
1178 | I2C_CLIENT_INSMOD; | 1178 | I2C_CLIENT_INSMOD; |
1179 | 1179 | ||
1180 | static struct i2c_driver aic3x_i2c_driver; | 1180 | static struct i2c_driver aic3x_i2c_driver; |
1181 | static struct i2c_client client_template; | 1181 | static struct i2c_client client_template; |
1182 | 1182 | ||
1183 | /* | 1183 | /* |
1184 | * If the i2c layer weren't so broken, we could pass this kind of data | 1184 | * If the i2c layer weren't so broken, we could pass this kind of data |
1185 | * around | 1185 | * around |
1186 | */ | 1186 | */ |
1187 | static int aic3x_codec_probe(struct i2c_adapter *adap, int addr, int kind) | 1187 | static int aic3x_codec_probe(struct i2c_adapter *adap, int addr, int kind) |
1188 | { | 1188 | { |
1189 | struct snd_soc_device *socdev = aic3x_socdev; | 1189 | struct snd_soc_device *socdev = aic3x_socdev; |
1190 | struct aic3x_setup_data *setup = socdev->codec_data; | 1190 | struct aic3x_setup_data *setup = socdev->codec_data; |
1191 | struct snd_soc_codec *codec = socdev->codec; | 1191 | struct snd_soc_codec *codec = socdev->codec; |
1192 | struct i2c_client *i2c; | 1192 | struct i2c_client *i2c; |
1193 | int ret; | 1193 | int ret; |
1194 | 1194 | ||
1195 | if (addr != setup->i2c_address) | 1195 | if (addr != setup->i2c_address) |
1196 | return -ENODEV; | 1196 | return -ENODEV; |
1197 | 1197 | ||
1198 | client_template.adapter = adap; | 1198 | client_template.adapter = adap; |
1199 | client_template.addr = addr; | 1199 | client_template.addr = addr; |
1200 | 1200 | ||
1201 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | 1201 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); |
1202 | if (i2c == NULL) { | 1202 | if (i2c == NULL) |
1203 | kfree(codec); | ||
1204 | return -ENOMEM; | 1203 | return -ENOMEM; |
1205 | } | 1204 | |
1206 | i2c_set_clientdata(i2c, codec); | 1205 | i2c_set_clientdata(i2c, codec); |
1207 | codec->control_data = i2c; | 1206 | codec->control_data = i2c; |
1208 | 1207 | ||
1209 | ret = i2c_attach_client(i2c); | 1208 | ret = i2c_attach_client(i2c); |
1210 | if (ret < 0) { | 1209 | if (ret < 0) { |
1211 | printk(KERN_ERR "aic3x: failed to attach codec at addr %x\n", | 1210 | printk(KERN_ERR "aic3x: failed to attach codec at addr %x\n", |
1212 | addr); | 1211 | addr); |
1213 | goto err; | 1212 | goto err; |
1214 | } | 1213 | } |
1215 | 1214 | ||
1216 | ret = aic3x_init(socdev); | 1215 | ret = aic3x_init(socdev); |
1217 | if (ret < 0) { | 1216 | if (ret < 0) { |
1218 | printk(KERN_ERR "aic3x: failed to initialise AIC3X\n"); | 1217 | printk(KERN_ERR "aic3x: failed to initialise AIC3X\n"); |
1219 | goto err; | 1218 | goto err; |
1220 | } | 1219 | } |
1221 | return ret; | 1220 | return ret; |
1222 | 1221 | ||
1223 | err: | 1222 | err: |
1224 | kfree(codec); | ||
1225 | kfree(i2c); | 1223 | kfree(i2c); |
1226 | return ret; | 1224 | return ret; |
1227 | } | 1225 | } |
1228 | 1226 | ||
1229 | static int aic3x_i2c_detach(struct i2c_client *client) | 1227 | static int aic3x_i2c_detach(struct i2c_client *client) |
1230 | { | 1228 | { |
1231 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 1229 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
1232 | i2c_detach_client(client); | 1230 | i2c_detach_client(client); |
1233 | kfree(codec->reg_cache); | 1231 | kfree(codec->reg_cache); |
1234 | kfree(client); | 1232 | kfree(client); |
1235 | return 0; | 1233 | return 0; |
1236 | } | 1234 | } |
1237 | 1235 | ||
1238 | static int aic3x_i2c_attach(struct i2c_adapter *adap) | 1236 | static int aic3x_i2c_attach(struct i2c_adapter *adap) |
1239 | { | 1237 | { |
1240 | return i2c_probe(adap, &addr_data, aic3x_codec_probe); | 1238 | return i2c_probe(adap, &addr_data, aic3x_codec_probe); |
1241 | } | 1239 | } |
1242 | 1240 | ||
1243 | /* machine i2c codec control layer */ | 1241 | /* machine i2c codec control layer */ |
1244 | static struct i2c_driver aic3x_i2c_driver = { | 1242 | static struct i2c_driver aic3x_i2c_driver = { |
1245 | .driver = { | 1243 | .driver = { |
1246 | .name = "aic3x I2C Codec", | 1244 | .name = "aic3x I2C Codec", |
1247 | .owner = THIS_MODULE, | 1245 | .owner = THIS_MODULE, |
1248 | }, | 1246 | }, |
1249 | .attach_adapter = aic3x_i2c_attach, | 1247 | .attach_adapter = aic3x_i2c_attach, |
1250 | .detach_client = aic3x_i2c_detach, | 1248 | .detach_client = aic3x_i2c_detach, |
1251 | }; | 1249 | }; |
1252 | 1250 | ||
1253 | static struct i2c_client client_template = { | 1251 | static struct i2c_client client_template = { |
1254 | .name = "AIC3X", | 1252 | .name = "AIC3X", |
1255 | .driver = &aic3x_i2c_driver, | 1253 | .driver = &aic3x_i2c_driver, |
1256 | }; | 1254 | }; |
1257 | 1255 | ||
1258 | static int aic3x_i2c_read(struct i2c_client *client, u8 *value, int len) | 1256 | static int aic3x_i2c_read(struct i2c_client *client, u8 *value, int len) |
1259 | { | 1257 | { |
1260 | value[0] = i2c_smbus_read_byte_data(client, value[0]); | 1258 | value[0] = i2c_smbus_read_byte_data(client, value[0]); |
1261 | return (len == 1); | 1259 | return (len == 1); |
1262 | } | 1260 | } |
1263 | #endif | 1261 | #endif |
1264 | 1262 | ||
1265 | static int aic3x_probe(struct platform_device *pdev) | 1263 | static int aic3x_probe(struct platform_device *pdev) |
1266 | { | 1264 | { |
1267 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1265 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1268 | struct aic3x_setup_data *setup; | 1266 | struct aic3x_setup_data *setup; |
1269 | struct snd_soc_codec *codec; | 1267 | struct snd_soc_codec *codec; |
1270 | struct aic3x_priv *aic3x; | 1268 | struct aic3x_priv *aic3x; |
1271 | int ret = 0; | 1269 | int ret = 0; |
1272 | 1270 | ||
1273 | printk(KERN_INFO "AIC3X Audio Codec %s\n", AIC3X_VERSION); | 1271 | printk(KERN_INFO "AIC3X Audio Codec %s\n", AIC3X_VERSION); |
1274 | 1272 | ||
1275 | setup = socdev->codec_data; | 1273 | setup = socdev->codec_data; |
1276 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 1274 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); |
1277 | if (codec == NULL) | 1275 | if (codec == NULL) |
1278 | return -ENOMEM; | 1276 | return -ENOMEM; |
1279 | 1277 | ||
1280 | aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL); | 1278 | aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL); |
1281 | if (aic3x == NULL) { | 1279 | if (aic3x == NULL) { |
1282 | kfree(codec); | 1280 | kfree(codec); |
1283 | return -ENOMEM; | 1281 | return -ENOMEM; |
1284 | } | 1282 | } |
1285 | 1283 | ||
1286 | codec->private_data = aic3x; | 1284 | codec->private_data = aic3x; |
1287 | socdev->codec = codec; | 1285 | socdev->codec = codec; |
1288 | mutex_init(&codec->mutex); | 1286 | mutex_init(&codec->mutex); |
1289 | INIT_LIST_HEAD(&codec->dapm_widgets); | 1287 | INIT_LIST_HEAD(&codec->dapm_widgets); |
1290 | INIT_LIST_HEAD(&codec->dapm_paths); | 1288 | INIT_LIST_HEAD(&codec->dapm_paths); |
1291 | 1289 | ||
1292 | aic3x_socdev = socdev; | 1290 | aic3x_socdev = socdev; |
1293 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1291 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1294 | if (setup->i2c_address) { | 1292 | if (setup->i2c_address) { |
1295 | normal_i2c[0] = setup->i2c_address; | 1293 | normal_i2c[0] = setup->i2c_address; |
1296 | codec->hw_write = (hw_write_t) i2c_master_send; | 1294 | codec->hw_write = (hw_write_t) i2c_master_send; |
1297 | codec->hw_read = (hw_read_t) aic3x_i2c_read; | 1295 | codec->hw_read = (hw_read_t) aic3x_i2c_read; |
1298 | ret = i2c_add_driver(&aic3x_i2c_driver); | 1296 | ret = i2c_add_driver(&aic3x_i2c_driver); |
1299 | if (ret != 0) | 1297 | if (ret != 0) |
1300 | printk(KERN_ERR "can't add i2c driver"); | 1298 | printk(KERN_ERR "can't add i2c driver"); |
1301 | } | 1299 | } |
1302 | #else | 1300 | #else |
1303 | /* Add other interfaces here */ | 1301 | /* Add other interfaces here */ |
1304 | #endif | 1302 | #endif |
1303 | |||
1304 | if (ret != 0) { | ||
1305 | kfree(codec->private_data); | ||
1306 | kfree(codec); | ||
1307 | } | ||
1305 | return ret; | 1308 | return ret; |
1306 | } | 1309 | } |
1307 | 1310 | ||
1308 | static int aic3x_remove(struct platform_device *pdev) | 1311 | static int aic3x_remove(struct platform_device *pdev) |
1309 | { | 1312 | { |
1310 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1313 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1311 | struct snd_soc_codec *codec = socdev->codec; | 1314 | struct snd_soc_codec *codec = socdev->codec; |
1312 | 1315 | ||
1313 | /* power down chip */ | 1316 | /* power down chip */ |
1314 | if (codec->control_data) | 1317 | if (codec->control_data) |
1315 | aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1318 | aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1316 | 1319 | ||
1317 | snd_soc_free_pcms(socdev); | 1320 | snd_soc_free_pcms(socdev); |
1318 | snd_soc_dapm_free(socdev); | 1321 | snd_soc_dapm_free(socdev); |
1319 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1322 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1320 | i2c_del_driver(&aic3x_i2c_driver); | 1323 | i2c_del_driver(&aic3x_i2c_driver); |
1321 | #endif | 1324 | #endif |
1322 | kfree(codec->private_data); | 1325 | kfree(codec->private_data); |
1323 | kfree(codec); | 1326 | kfree(codec); |
1324 | 1327 | ||
1325 | return 0; | 1328 | return 0; |
1326 | } | 1329 | } |
1327 | 1330 | ||
1328 | struct snd_soc_codec_device soc_codec_dev_aic3x = { | 1331 | struct snd_soc_codec_device soc_codec_dev_aic3x = { |
1329 | .probe = aic3x_probe, | 1332 | .probe = aic3x_probe, |
1330 | .remove = aic3x_remove, | 1333 | .remove = aic3x_remove, |
1331 | .suspend = aic3x_suspend, | 1334 | .suspend = aic3x_suspend, |
1332 | .resume = aic3x_resume, | 1335 | .resume = aic3x_resume, |
1333 | }; | 1336 | }; |
1334 | EXPORT_SYMBOL_GPL(soc_codec_dev_aic3x); | 1337 | EXPORT_SYMBOL_GPL(soc_codec_dev_aic3x); |
1335 | 1338 | ||
1336 | MODULE_DESCRIPTION("ASoC TLV320AIC3X codec driver"); | 1339 | MODULE_DESCRIPTION("ASoC TLV320AIC3X codec driver"); |
1337 | MODULE_AUTHOR("Vladimir Barinov"); | 1340 | MODULE_AUTHOR("Vladimir Barinov"); |
sound/soc/codecs/uda1380.c
1 | /* | 1 | /* |
2 | * uda1380.c - Philips UDA1380 ALSA SoC audio driver | 2 | * uda1380.c - Philips UDA1380 ALSA SoC audio driver |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License version 2 as | 5 | * it under the terms of the GNU General Public License version 2 as |
6 | * published by the Free Software Foundation. | 6 | * published by the Free Software Foundation. |
7 | * | 7 | * |
8 | * Copyright (c) 2007 Philipp Zabel <philipp.zabel@gmail.com> | 8 | * Copyright (c) 2007 Philipp Zabel <philipp.zabel@gmail.com> |
9 | * Improved support for DAPM and audio routing/mixing capabilities, | 9 | * Improved support for DAPM and audio routing/mixing capabilities, |
10 | * added TLV support. | 10 | * added TLV support. |
11 | * | 11 | * |
12 | * Modified by Richard Purdie <richard@openedhand.com> to fit into SoC | 12 | * Modified by Richard Purdie <richard@openedhand.com> to fit into SoC |
13 | * codec model. | 13 | * codec model. |
14 | * | 14 | * |
15 | * Copyright (c) 2005 Giorgio Padrin <giorgio@mandarinlogiq.org> | 15 | * Copyright (c) 2005 Giorgio Padrin <giorgio@mandarinlogiq.org> |
16 | * Copyright 2005 Openedhand Ltd. | 16 | * Copyright 2005 Openedhand Ltd. |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
21 | #include <linux/types.h> | 21 | #include <linux/types.h> |
22 | #include <linux/string.h> | 22 | #include <linux/string.h> |
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/errno.h> | 24 | #include <linux/errno.h> |
25 | #include <linux/ioctl.h> | 25 | #include <linux/ioctl.h> |
26 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
27 | #include <linux/i2c.h> | 27 | #include <linux/i2c.h> |
28 | #include <sound/core.h> | 28 | #include <sound/core.h> |
29 | #include <sound/control.h> | 29 | #include <sound/control.h> |
30 | #include <sound/initval.h> | 30 | #include <sound/initval.h> |
31 | #include <sound/info.h> | 31 | #include <sound/info.h> |
32 | #include <sound/soc.h> | 32 | #include <sound/soc.h> |
33 | #include <sound/soc-dapm.h> | 33 | #include <sound/soc-dapm.h> |
34 | #include <sound/tlv.h> | 34 | #include <sound/tlv.h> |
35 | 35 | ||
36 | #include "uda1380.h" | 36 | #include "uda1380.h" |
37 | 37 | ||
38 | #define UDA1380_VERSION "0.6" | 38 | #define UDA1380_VERSION "0.6" |
39 | #define AUDIO_NAME "uda1380" | 39 | #define AUDIO_NAME "uda1380" |
40 | 40 | ||
41 | /* | 41 | /* |
42 | * uda1380 register cache | 42 | * uda1380 register cache |
43 | */ | 43 | */ |
44 | static const u16 uda1380_reg[UDA1380_CACHEREGNUM] = { | 44 | static const u16 uda1380_reg[UDA1380_CACHEREGNUM] = { |
45 | 0x0502, 0x0000, 0x0000, 0x3f3f, | 45 | 0x0502, 0x0000, 0x0000, 0x3f3f, |
46 | 0x0202, 0x0000, 0x0000, 0x0000, | 46 | 0x0202, 0x0000, 0x0000, 0x0000, |
47 | 0x0000, 0x0000, 0x0000, 0x0000, | 47 | 0x0000, 0x0000, 0x0000, 0x0000, |
48 | 0x0000, 0x0000, 0x0000, 0x0000, | 48 | 0x0000, 0x0000, 0x0000, 0x0000, |
49 | 0x0000, 0xff00, 0x0000, 0x4800, | 49 | 0x0000, 0xff00, 0x0000, 0x4800, |
50 | 0x0000, 0x0000, 0x0000, 0x0000, | 50 | 0x0000, 0x0000, 0x0000, 0x0000, |
51 | 0x0000, 0x0000, 0x0000, 0x0000, | 51 | 0x0000, 0x0000, 0x0000, 0x0000, |
52 | 0x0000, 0x0000, 0x0000, 0x0000, | 52 | 0x0000, 0x0000, 0x0000, 0x0000, |
53 | 0x0000, 0x8000, 0x0002, 0x0000, | 53 | 0x0000, 0x8000, 0x0002, 0x0000, |
54 | }; | 54 | }; |
55 | 55 | ||
56 | /* | 56 | /* |
57 | * read uda1380 register cache | 57 | * read uda1380 register cache |
58 | */ | 58 | */ |
59 | static inline unsigned int uda1380_read_reg_cache(struct snd_soc_codec *codec, | 59 | static inline unsigned int uda1380_read_reg_cache(struct snd_soc_codec *codec, |
60 | unsigned int reg) | 60 | unsigned int reg) |
61 | { | 61 | { |
62 | u16 *cache = codec->reg_cache; | 62 | u16 *cache = codec->reg_cache; |
63 | if (reg == UDA1380_RESET) | 63 | if (reg == UDA1380_RESET) |
64 | return 0; | 64 | return 0; |
65 | if (reg >= UDA1380_CACHEREGNUM) | 65 | if (reg >= UDA1380_CACHEREGNUM) |
66 | return -1; | 66 | return -1; |
67 | return cache[reg]; | 67 | return cache[reg]; |
68 | } | 68 | } |
69 | 69 | ||
70 | /* | 70 | /* |
71 | * write uda1380 register cache | 71 | * write uda1380 register cache |
72 | */ | 72 | */ |
73 | static inline void uda1380_write_reg_cache(struct snd_soc_codec *codec, | 73 | static inline void uda1380_write_reg_cache(struct snd_soc_codec *codec, |
74 | u16 reg, unsigned int value) | 74 | u16 reg, unsigned int value) |
75 | { | 75 | { |
76 | u16 *cache = codec->reg_cache; | 76 | u16 *cache = codec->reg_cache; |
77 | if (reg >= UDA1380_CACHEREGNUM) | 77 | if (reg >= UDA1380_CACHEREGNUM) |
78 | return; | 78 | return; |
79 | cache[reg] = value; | 79 | cache[reg] = value; |
80 | } | 80 | } |
81 | 81 | ||
82 | /* | 82 | /* |
83 | * write to the UDA1380 register space | 83 | * write to the UDA1380 register space |
84 | */ | 84 | */ |
85 | static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg, | 85 | static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg, |
86 | unsigned int value) | 86 | unsigned int value) |
87 | { | 87 | { |
88 | u8 data[3]; | 88 | u8 data[3]; |
89 | 89 | ||
90 | /* data is | 90 | /* data is |
91 | * data[0] is register offset | 91 | * data[0] is register offset |
92 | * data[1] is MS byte | 92 | * data[1] is MS byte |
93 | * data[2] is LS byte | 93 | * data[2] is LS byte |
94 | */ | 94 | */ |
95 | data[0] = reg; | 95 | data[0] = reg; |
96 | data[1] = (value & 0xff00) >> 8; | 96 | data[1] = (value & 0xff00) >> 8; |
97 | data[2] = value & 0x00ff; | 97 | data[2] = value & 0x00ff; |
98 | 98 | ||
99 | uda1380_write_reg_cache(codec, reg, value); | 99 | uda1380_write_reg_cache(codec, reg, value); |
100 | 100 | ||
101 | /* the interpolator & decimator regs must only be written when the | 101 | /* the interpolator & decimator regs must only be written when the |
102 | * codec DAI is active. | 102 | * codec DAI is active. |
103 | */ | 103 | */ |
104 | if (!codec->active && (reg >= UDA1380_MVOL)) | 104 | if (!codec->active && (reg >= UDA1380_MVOL)) |
105 | return 0; | 105 | return 0; |
106 | pr_debug("uda1380: hw write %x val %x\n", reg, value); | 106 | pr_debug("uda1380: hw write %x val %x\n", reg, value); |
107 | if (codec->hw_write(codec->control_data, data, 3) == 3) { | 107 | if (codec->hw_write(codec->control_data, data, 3) == 3) { |
108 | unsigned int val; | 108 | unsigned int val; |
109 | i2c_master_send(codec->control_data, data, 1); | 109 | i2c_master_send(codec->control_data, data, 1); |
110 | i2c_master_recv(codec->control_data, data, 2); | 110 | i2c_master_recv(codec->control_data, data, 2); |
111 | val = (data[0]<<8) | data[1]; | 111 | val = (data[0]<<8) | data[1]; |
112 | if (val != value) { | 112 | if (val != value) { |
113 | pr_debug("uda1380: READ BACK VAL %x\n", | 113 | pr_debug("uda1380: READ BACK VAL %x\n", |
114 | (data[0]<<8) | data[1]); | 114 | (data[0]<<8) | data[1]); |
115 | return -EIO; | 115 | return -EIO; |
116 | } | 116 | } |
117 | return 0; | 117 | return 0; |
118 | } else | 118 | } else |
119 | return -EIO; | 119 | return -EIO; |
120 | } | 120 | } |
121 | 121 | ||
122 | #define uda1380_reset(c) uda1380_write(c, UDA1380_RESET, 0) | 122 | #define uda1380_reset(c) uda1380_write(c, UDA1380_RESET, 0) |
123 | 123 | ||
124 | /* declarations of ALSA reg_elem_REAL controls */ | 124 | /* declarations of ALSA reg_elem_REAL controls */ |
125 | static const char *uda1380_deemp[] = { | 125 | static const char *uda1380_deemp[] = { |
126 | "None", | 126 | "None", |
127 | "32kHz", | 127 | "32kHz", |
128 | "44.1kHz", | 128 | "44.1kHz", |
129 | "48kHz", | 129 | "48kHz", |
130 | "96kHz", | 130 | "96kHz", |
131 | }; | 131 | }; |
132 | static const char *uda1380_input_sel[] = { | 132 | static const char *uda1380_input_sel[] = { |
133 | "Line", | 133 | "Line", |
134 | "Mic + Line R", | 134 | "Mic + Line R", |
135 | "Line L", | 135 | "Line L", |
136 | "Mic", | 136 | "Mic", |
137 | }; | 137 | }; |
138 | static const char *uda1380_output_sel[] = { | 138 | static const char *uda1380_output_sel[] = { |
139 | "DAC", | 139 | "DAC", |
140 | "Analog Mixer", | 140 | "Analog Mixer", |
141 | }; | 141 | }; |
142 | static const char *uda1380_spf_mode[] = { | 142 | static const char *uda1380_spf_mode[] = { |
143 | "Flat", | 143 | "Flat", |
144 | "Minimum1", | 144 | "Minimum1", |
145 | "Minimum2", | 145 | "Minimum2", |
146 | "Maximum" | 146 | "Maximum" |
147 | }; | 147 | }; |
148 | static const char *uda1380_capture_sel[] = { | 148 | static const char *uda1380_capture_sel[] = { |
149 | "ADC", | 149 | "ADC", |
150 | "Digital Mixer" | 150 | "Digital Mixer" |
151 | }; | 151 | }; |
152 | static const char *uda1380_sel_ns[] = { | 152 | static const char *uda1380_sel_ns[] = { |
153 | "3rd-order", | 153 | "3rd-order", |
154 | "5th-order" | 154 | "5th-order" |
155 | }; | 155 | }; |
156 | static const char *uda1380_mix_control[] = { | 156 | static const char *uda1380_mix_control[] = { |
157 | "off", | 157 | "off", |
158 | "PCM only", | 158 | "PCM only", |
159 | "before sound processing", | 159 | "before sound processing", |
160 | "after sound processing" | 160 | "after sound processing" |
161 | }; | 161 | }; |
162 | static const char *uda1380_sdet_setting[] = { | 162 | static const char *uda1380_sdet_setting[] = { |
163 | "3200", | 163 | "3200", |
164 | "4800", | 164 | "4800", |
165 | "9600", | 165 | "9600", |
166 | "19200" | 166 | "19200" |
167 | }; | 167 | }; |
168 | static const char *uda1380_os_setting[] = { | 168 | static const char *uda1380_os_setting[] = { |
169 | "single-speed", | 169 | "single-speed", |
170 | "double-speed (no mixing)", | 170 | "double-speed (no mixing)", |
171 | "quad-speed (no mixing)" | 171 | "quad-speed (no mixing)" |
172 | }; | 172 | }; |
173 | 173 | ||
174 | static const struct soc_enum uda1380_deemp_enum[] = { | 174 | static const struct soc_enum uda1380_deemp_enum[] = { |
175 | SOC_ENUM_SINGLE(UDA1380_DEEMP, 8, 5, uda1380_deemp), | 175 | SOC_ENUM_SINGLE(UDA1380_DEEMP, 8, 5, uda1380_deemp), |
176 | SOC_ENUM_SINGLE(UDA1380_DEEMP, 0, 5, uda1380_deemp), | 176 | SOC_ENUM_SINGLE(UDA1380_DEEMP, 0, 5, uda1380_deemp), |
177 | }; | 177 | }; |
178 | static const struct soc_enum uda1380_input_sel_enum = | 178 | static const struct soc_enum uda1380_input_sel_enum = |
179 | SOC_ENUM_SINGLE(UDA1380_ADC, 2, 4, uda1380_input_sel); /* SEL_MIC, SEL_LNA */ | 179 | SOC_ENUM_SINGLE(UDA1380_ADC, 2, 4, uda1380_input_sel); /* SEL_MIC, SEL_LNA */ |
180 | static const struct soc_enum uda1380_output_sel_enum = | 180 | static const struct soc_enum uda1380_output_sel_enum = |
181 | SOC_ENUM_SINGLE(UDA1380_PM, 7, 2, uda1380_output_sel); /* R02_EN_AVC */ | 181 | SOC_ENUM_SINGLE(UDA1380_PM, 7, 2, uda1380_output_sel); /* R02_EN_AVC */ |
182 | static const struct soc_enum uda1380_spf_enum = | 182 | static const struct soc_enum uda1380_spf_enum = |
183 | SOC_ENUM_SINGLE(UDA1380_MODE, 14, 4, uda1380_spf_mode); /* M */ | 183 | SOC_ENUM_SINGLE(UDA1380_MODE, 14, 4, uda1380_spf_mode); /* M */ |
184 | static const struct soc_enum uda1380_capture_sel_enum = | 184 | static const struct soc_enum uda1380_capture_sel_enum = |
185 | SOC_ENUM_SINGLE(UDA1380_IFACE, 6, 2, uda1380_capture_sel); /* SEL_SOURCE */ | 185 | SOC_ENUM_SINGLE(UDA1380_IFACE, 6, 2, uda1380_capture_sel); /* SEL_SOURCE */ |
186 | static const struct soc_enum uda1380_sel_ns_enum = | 186 | static const struct soc_enum uda1380_sel_ns_enum = |
187 | SOC_ENUM_SINGLE(UDA1380_MIXER, 14, 2, uda1380_sel_ns); /* SEL_NS */ | 187 | SOC_ENUM_SINGLE(UDA1380_MIXER, 14, 2, uda1380_sel_ns); /* SEL_NS */ |
188 | static const struct soc_enum uda1380_mix_enum = | 188 | static const struct soc_enum uda1380_mix_enum = |
189 | SOC_ENUM_SINGLE(UDA1380_MIXER, 12, 4, uda1380_mix_control); /* MIX, MIX_POS */ | 189 | SOC_ENUM_SINGLE(UDA1380_MIXER, 12, 4, uda1380_mix_control); /* MIX, MIX_POS */ |
190 | static const struct soc_enum uda1380_sdet_enum = | 190 | static const struct soc_enum uda1380_sdet_enum = |
191 | SOC_ENUM_SINGLE(UDA1380_MIXER, 4, 4, uda1380_sdet_setting); /* SD_VALUE */ | 191 | SOC_ENUM_SINGLE(UDA1380_MIXER, 4, 4, uda1380_sdet_setting); /* SD_VALUE */ |
192 | static const struct soc_enum uda1380_os_enum = | 192 | static const struct soc_enum uda1380_os_enum = |
193 | SOC_ENUM_SINGLE(UDA1380_MIXER, 0, 3, uda1380_os_setting); /* OS */ | 193 | SOC_ENUM_SINGLE(UDA1380_MIXER, 0, 3, uda1380_os_setting); /* OS */ |
194 | 194 | ||
195 | /* | 195 | /* |
196 | * from -48 dB in 1.5 dB steps (mute instead of -49.5 dB) | 196 | * from -48 dB in 1.5 dB steps (mute instead of -49.5 dB) |
197 | */ | 197 | */ |
198 | static DECLARE_TLV_DB_SCALE(amix_tlv, -4950, 150, 1); | 198 | static DECLARE_TLV_DB_SCALE(amix_tlv, -4950, 150, 1); |
199 | 199 | ||
200 | /* | 200 | /* |
201 | * from -78 dB in 1 dB steps (3 dB steps, really. LSB are ignored), | 201 | * from -78 dB in 1 dB steps (3 dB steps, really. LSB are ignored), |
202 | * from -66 dB in 0.5 dB steps (2 dB steps, really) and | 202 | * from -66 dB in 0.5 dB steps (2 dB steps, really) and |
203 | * from -52 dB in 0.25 dB steps | 203 | * from -52 dB in 0.25 dB steps |
204 | */ | 204 | */ |
205 | static const unsigned int mvol_tlv[] = { | 205 | static const unsigned int mvol_tlv[] = { |
206 | TLV_DB_RANGE_HEAD(3), | 206 | TLV_DB_RANGE_HEAD(3), |
207 | 0, 15, TLV_DB_SCALE_ITEM(-8200, 100, 1), | 207 | 0, 15, TLV_DB_SCALE_ITEM(-8200, 100, 1), |
208 | 16, 43, TLV_DB_SCALE_ITEM(-6600, 50, 0), | 208 | 16, 43, TLV_DB_SCALE_ITEM(-6600, 50, 0), |
209 | 44, 252, TLV_DB_SCALE_ITEM(-5200, 25, 0), | 209 | 44, 252, TLV_DB_SCALE_ITEM(-5200, 25, 0), |
210 | }; | 210 | }; |
211 | 211 | ||
212 | /* | 212 | /* |
213 | * from -72 dB in 1.5 dB steps (6 dB steps really), | 213 | * from -72 dB in 1.5 dB steps (6 dB steps really), |
214 | * from -66 dB in 0.75 dB steps (3 dB steps really), | 214 | * from -66 dB in 0.75 dB steps (3 dB steps really), |
215 | * from -60 dB in 0.5 dB steps (2 dB steps really) and | 215 | * from -60 dB in 0.5 dB steps (2 dB steps really) and |
216 | * from -46 dB in 0.25 dB steps | 216 | * from -46 dB in 0.25 dB steps |
217 | */ | 217 | */ |
218 | static const unsigned int vc_tlv[] = { | 218 | static const unsigned int vc_tlv[] = { |
219 | TLV_DB_RANGE_HEAD(4), | 219 | TLV_DB_RANGE_HEAD(4), |
220 | 0, 7, TLV_DB_SCALE_ITEM(-7800, 150, 1), | 220 | 0, 7, TLV_DB_SCALE_ITEM(-7800, 150, 1), |
221 | 8, 15, TLV_DB_SCALE_ITEM(-6600, 75, 0), | 221 | 8, 15, TLV_DB_SCALE_ITEM(-6600, 75, 0), |
222 | 16, 43, TLV_DB_SCALE_ITEM(-6000, 50, 0), | 222 | 16, 43, TLV_DB_SCALE_ITEM(-6000, 50, 0), |
223 | 44, 228, TLV_DB_SCALE_ITEM(-4600, 25, 0), | 223 | 44, 228, TLV_DB_SCALE_ITEM(-4600, 25, 0), |
224 | }; | 224 | }; |
225 | 225 | ||
226 | /* from 0 to 6 dB in 2 dB steps if SPF mode != flat */ | 226 | /* from 0 to 6 dB in 2 dB steps if SPF mode != flat */ |
227 | static DECLARE_TLV_DB_SCALE(tr_tlv, 0, 200, 0); | 227 | static DECLARE_TLV_DB_SCALE(tr_tlv, 0, 200, 0); |
228 | 228 | ||
229 | /* from 0 to 24 dB in 2 dB steps, if SPF mode == maximum, otherwise cuts | 229 | /* from 0 to 24 dB in 2 dB steps, if SPF mode == maximum, otherwise cuts |
230 | * off at 18 dB max) */ | 230 | * off at 18 dB max) */ |
231 | static DECLARE_TLV_DB_SCALE(bb_tlv, 0, 200, 0); | 231 | static DECLARE_TLV_DB_SCALE(bb_tlv, 0, 200, 0); |
232 | 232 | ||
233 | /* from -63 to 24 dB in 0.5 dB steps (-128...48) */ | 233 | /* from -63 to 24 dB in 0.5 dB steps (-128...48) */ |
234 | static DECLARE_TLV_DB_SCALE(dec_tlv, -6400, 50, 1); | 234 | static DECLARE_TLV_DB_SCALE(dec_tlv, -6400, 50, 1); |
235 | 235 | ||
236 | /* from 0 to 24 dB in 3 dB steps */ | 236 | /* from 0 to 24 dB in 3 dB steps */ |
237 | static DECLARE_TLV_DB_SCALE(pga_tlv, 0, 300, 0); | 237 | static DECLARE_TLV_DB_SCALE(pga_tlv, 0, 300, 0); |
238 | 238 | ||
239 | /* from 0 to 30 dB in 2 dB steps */ | 239 | /* from 0 to 30 dB in 2 dB steps */ |
240 | static DECLARE_TLV_DB_SCALE(vga_tlv, 0, 200, 0); | 240 | static DECLARE_TLV_DB_SCALE(vga_tlv, 0, 200, 0); |
241 | 241 | ||
242 | static const struct snd_kcontrol_new uda1380_snd_controls[] = { | 242 | static const struct snd_kcontrol_new uda1380_snd_controls[] = { |
243 | SOC_DOUBLE_TLV("Analog Mixer Volume", UDA1380_AMIX, 0, 8, 44, 1, amix_tlv), /* AVCR, AVCL */ | 243 | SOC_DOUBLE_TLV("Analog Mixer Volume", UDA1380_AMIX, 0, 8, 44, 1, amix_tlv), /* AVCR, AVCL */ |
244 | SOC_DOUBLE_TLV("Master Playback Volume", UDA1380_MVOL, 0, 8, 252, 1, mvol_tlv), /* MVCL, MVCR */ | 244 | SOC_DOUBLE_TLV("Master Playback Volume", UDA1380_MVOL, 0, 8, 252, 1, mvol_tlv), /* MVCL, MVCR */ |
245 | SOC_SINGLE_TLV("ADC Playback Volume", UDA1380_MIXVOL, 8, 228, 1, vc_tlv), /* VC2 */ | 245 | SOC_SINGLE_TLV("ADC Playback Volume", UDA1380_MIXVOL, 8, 228, 1, vc_tlv), /* VC2 */ |
246 | SOC_SINGLE_TLV("PCM Playback Volume", UDA1380_MIXVOL, 0, 228, 1, vc_tlv), /* VC1 */ | 246 | SOC_SINGLE_TLV("PCM Playback Volume", UDA1380_MIXVOL, 0, 228, 1, vc_tlv), /* VC1 */ |
247 | SOC_ENUM("Sound Processing Filter", uda1380_spf_enum), /* M */ | 247 | SOC_ENUM("Sound Processing Filter", uda1380_spf_enum), /* M */ |
248 | SOC_DOUBLE_TLV("Tone Control - Treble", UDA1380_MODE, 4, 12, 3, 0, tr_tlv), /* TRL, TRR */ | 248 | SOC_DOUBLE_TLV("Tone Control - Treble", UDA1380_MODE, 4, 12, 3, 0, tr_tlv), /* TRL, TRR */ |
249 | SOC_DOUBLE_TLV("Tone Control - Bass", UDA1380_MODE, 0, 8, 15, 0, bb_tlv), /* BBL, BBR */ | 249 | SOC_DOUBLE_TLV("Tone Control - Bass", UDA1380_MODE, 0, 8, 15, 0, bb_tlv), /* BBL, BBR */ |
250 | /**/ SOC_SINGLE("Master Playback Switch", UDA1380_DEEMP, 14, 1, 1), /* MTM */ | 250 | /**/ SOC_SINGLE("Master Playback Switch", UDA1380_DEEMP, 14, 1, 1), /* MTM */ |
251 | SOC_SINGLE("ADC Playback Switch", UDA1380_DEEMP, 11, 1, 1), /* MT2 from decimation filter */ | 251 | SOC_SINGLE("ADC Playback Switch", UDA1380_DEEMP, 11, 1, 1), /* MT2 from decimation filter */ |
252 | SOC_ENUM("ADC Playback De-emphasis", uda1380_deemp_enum[0]), /* DE2 */ | 252 | SOC_ENUM("ADC Playback De-emphasis", uda1380_deemp_enum[0]), /* DE2 */ |
253 | SOC_SINGLE("PCM Playback Switch", UDA1380_DEEMP, 3, 1, 1), /* MT1, from digital data input */ | 253 | SOC_SINGLE("PCM Playback Switch", UDA1380_DEEMP, 3, 1, 1), /* MT1, from digital data input */ |
254 | SOC_ENUM("PCM Playback De-emphasis", uda1380_deemp_enum[1]), /* DE1 */ | 254 | SOC_ENUM("PCM Playback De-emphasis", uda1380_deemp_enum[1]), /* DE1 */ |
255 | SOC_SINGLE("DAC Polarity inverting Switch", UDA1380_MIXER, 15, 1, 0), /* DA_POL_INV */ | 255 | SOC_SINGLE("DAC Polarity inverting Switch", UDA1380_MIXER, 15, 1, 0), /* DA_POL_INV */ |
256 | SOC_ENUM("Noise Shaper", uda1380_sel_ns_enum), /* SEL_NS */ | 256 | SOC_ENUM("Noise Shaper", uda1380_sel_ns_enum), /* SEL_NS */ |
257 | SOC_ENUM("Digital Mixer Signal Control", uda1380_mix_enum), /* MIX_POS, MIX */ | 257 | SOC_ENUM("Digital Mixer Signal Control", uda1380_mix_enum), /* MIX_POS, MIX */ |
258 | SOC_SINGLE("Silence Switch", UDA1380_MIXER, 7, 1, 0), /* SILENCE, force DAC output to silence */ | 258 | SOC_SINGLE("Silence Switch", UDA1380_MIXER, 7, 1, 0), /* SILENCE, force DAC output to silence */ |
259 | SOC_SINGLE("Silence Detector Switch", UDA1380_MIXER, 6, 1, 0), /* SDET_ON */ | 259 | SOC_SINGLE("Silence Detector Switch", UDA1380_MIXER, 6, 1, 0), /* SDET_ON */ |
260 | SOC_ENUM("Silence Detector Setting", uda1380_sdet_enum), /* SD_VALUE */ | 260 | SOC_ENUM("Silence Detector Setting", uda1380_sdet_enum), /* SD_VALUE */ |
261 | SOC_ENUM("Oversampling Input", uda1380_os_enum), /* OS */ | 261 | SOC_ENUM("Oversampling Input", uda1380_os_enum), /* OS */ |
262 | SOC_DOUBLE_S8_TLV("ADC Capture Volume", UDA1380_DEC, -128, 48, dec_tlv), /* ML_DEC, MR_DEC */ | 262 | SOC_DOUBLE_S8_TLV("ADC Capture Volume", UDA1380_DEC, -128, 48, dec_tlv), /* ML_DEC, MR_DEC */ |
263 | /**/ SOC_SINGLE("ADC Capture Switch", UDA1380_PGA, 15, 1, 1), /* MT_ADC */ | 263 | /**/ SOC_SINGLE("ADC Capture Switch", UDA1380_PGA, 15, 1, 1), /* MT_ADC */ |
264 | SOC_DOUBLE_TLV("Line Capture Volume", UDA1380_PGA, 0, 8, 8, 0, pga_tlv), /* PGA_GAINCTRLL, PGA_GAINCTRLR */ | 264 | SOC_DOUBLE_TLV("Line Capture Volume", UDA1380_PGA, 0, 8, 8, 0, pga_tlv), /* PGA_GAINCTRLL, PGA_GAINCTRLR */ |
265 | SOC_SINGLE("ADC Polarity inverting Switch", UDA1380_ADC, 12, 1, 0), /* ADCPOL_INV */ | 265 | SOC_SINGLE("ADC Polarity inverting Switch", UDA1380_ADC, 12, 1, 0), /* ADCPOL_INV */ |
266 | SOC_SINGLE_TLV("Mic Capture Volume", UDA1380_ADC, 8, 15, 0, vga_tlv), /* VGA_CTRL */ | 266 | SOC_SINGLE_TLV("Mic Capture Volume", UDA1380_ADC, 8, 15, 0, vga_tlv), /* VGA_CTRL */ |
267 | SOC_SINGLE("DC Filter Bypass Switch", UDA1380_ADC, 1, 1, 0), /* SKIP_DCFIL (before decimator) */ | 267 | SOC_SINGLE("DC Filter Bypass Switch", UDA1380_ADC, 1, 1, 0), /* SKIP_DCFIL (before decimator) */ |
268 | SOC_SINGLE("DC Filter Enable Switch", UDA1380_ADC, 0, 1, 0), /* EN_DCFIL (at output of decimator) */ | 268 | SOC_SINGLE("DC Filter Enable Switch", UDA1380_ADC, 0, 1, 0), /* EN_DCFIL (at output of decimator) */ |
269 | SOC_SINGLE("AGC Timing", UDA1380_AGC, 8, 7, 0), /* TODO: enum, see table 62 */ | 269 | SOC_SINGLE("AGC Timing", UDA1380_AGC, 8, 7, 0), /* TODO: enum, see table 62 */ |
270 | SOC_SINGLE("AGC Target level", UDA1380_AGC, 2, 3, 1), /* AGC_LEVEL */ | 270 | SOC_SINGLE("AGC Target level", UDA1380_AGC, 2, 3, 1), /* AGC_LEVEL */ |
271 | /* -5.5, -8, -11.5, -14 dBFS */ | 271 | /* -5.5, -8, -11.5, -14 dBFS */ |
272 | SOC_SINGLE("AGC Switch", UDA1380_AGC, 0, 1, 0), | 272 | SOC_SINGLE("AGC Switch", UDA1380_AGC, 0, 1, 0), |
273 | }; | 273 | }; |
274 | 274 | ||
275 | /* add non dapm controls */ | 275 | /* add non dapm controls */ |
276 | static int uda1380_add_controls(struct snd_soc_codec *codec) | 276 | static int uda1380_add_controls(struct snd_soc_codec *codec) |
277 | { | 277 | { |
278 | int err, i; | 278 | int err, i; |
279 | 279 | ||
280 | for (i = 0; i < ARRAY_SIZE(uda1380_snd_controls); i++) { | 280 | for (i = 0; i < ARRAY_SIZE(uda1380_snd_controls); i++) { |
281 | err = snd_ctl_add(codec->card, | 281 | err = snd_ctl_add(codec->card, |
282 | snd_soc_cnew(&uda1380_snd_controls[i], codec, NULL)); | 282 | snd_soc_cnew(&uda1380_snd_controls[i], codec, NULL)); |
283 | if (err < 0) | 283 | if (err < 0) |
284 | return err; | 284 | return err; |
285 | } | 285 | } |
286 | 286 | ||
287 | return 0; | 287 | return 0; |
288 | } | 288 | } |
289 | 289 | ||
290 | /* Input mux */ | 290 | /* Input mux */ |
291 | static const struct snd_kcontrol_new uda1380_input_mux_control = | 291 | static const struct snd_kcontrol_new uda1380_input_mux_control = |
292 | SOC_DAPM_ENUM("Route", uda1380_input_sel_enum); | 292 | SOC_DAPM_ENUM("Route", uda1380_input_sel_enum); |
293 | 293 | ||
294 | /* Output mux */ | 294 | /* Output mux */ |
295 | static const struct snd_kcontrol_new uda1380_output_mux_control = | 295 | static const struct snd_kcontrol_new uda1380_output_mux_control = |
296 | SOC_DAPM_ENUM("Route", uda1380_output_sel_enum); | 296 | SOC_DAPM_ENUM("Route", uda1380_output_sel_enum); |
297 | 297 | ||
298 | /* Capture mux */ | 298 | /* Capture mux */ |
299 | static const struct snd_kcontrol_new uda1380_capture_mux_control = | 299 | static const struct snd_kcontrol_new uda1380_capture_mux_control = |
300 | SOC_DAPM_ENUM("Route", uda1380_capture_sel_enum); | 300 | SOC_DAPM_ENUM("Route", uda1380_capture_sel_enum); |
301 | 301 | ||
302 | 302 | ||
303 | static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = { | 303 | static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = { |
304 | SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, | 304 | SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, |
305 | &uda1380_input_mux_control), | 305 | &uda1380_input_mux_control), |
306 | SND_SOC_DAPM_MUX("Output Mux", SND_SOC_NOPM, 0, 0, | 306 | SND_SOC_DAPM_MUX("Output Mux", SND_SOC_NOPM, 0, 0, |
307 | &uda1380_output_mux_control), | 307 | &uda1380_output_mux_control), |
308 | SND_SOC_DAPM_MUX("Capture Mux", SND_SOC_NOPM, 0, 0, | 308 | SND_SOC_DAPM_MUX("Capture Mux", SND_SOC_NOPM, 0, 0, |
309 | &uda1380_capture_mux_control), | 309 | &uda1380_capture_mux_control), |
310 | SND_SOC_DAPM_PGA("Left PGA", UDA1380_PM, 3, 0, NULL, 0), | 310 | SND_SOC_DAPM_PGA("Left PGA", UDA1380_PM, 3, 0, NULL, 0), |
311 | SND_SOC_DAPM_PGA("Right PGA", UDA1380_PM, 1, 0, NULL, 0), | 311 | SND_SOC_DAPM_PGA("Right PGA", UDA1380_PM, 1, 0, NULL, 0), |
312 | SND_SOC_DAPM_PGA("Mic LNA", UDA1380_PM, 4, 0, NULL, 0), | 312 | SND_SOC_DAPM_PGA("Mic LNA", UDA1380_PM, 4, 0, NULL, 0), |
313 | SND_SOC_DAPM_ADC("Left ADC", "Left Capture", UDA1380_PM, 2, 0), | 313 | SND_SOC_DAPM_ADC("Left ADC", "Left Capture", UDA1380_PM, 2, 0), |
314 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", UDA1380_PM, 0, 0), | 314 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", UDA1380_PM, 0, 0), |
315 | SND_SOC_DAPM_INPUT("VINM"), | 315 | SND_SOC_DAPM_INPUT("VINM"), |
316 | SND_SOC_DAPM_INPUT("VINL"), | 316 | SND_SOC_DAPM_INPUT("VINL"), |
317 | SND_SOC_DAPM_INPUT("VINR"), | 317 | SND_SOC_DAPM_INPUT("VINR"), |
318 | SND_SOC_DAPM_MIXER("Analog Mixer", UDA1380_PM, 6, 0, NULL, 0), | 318 | SND_SOC_DAPM_MIXER("Analog Mixer", UDA1380_PM, 6, 0, NULL, 0), |
319 | SND_SOC_DAPM_OUTPUT("VOUTLHP"), | 319 | SND_SOC_DAPM_OUTPUT("VOUTLHP"), |
320 | SND_SOC_DAPM_OUTPUT("VOUTRHP"), | 320 | SND_SOC_DAPM_OUTPUT("VOUTRHP"), |
321 | SND_SOC_DAPM_OUTPUT("VOUTL"), | 321 | SND_SOC_DAPM_OUTPUT("VOUTL"), |
322 | SND_SOC_DAPM_OUTPUT("VOUTR"), | 322 | SND_SOC_DAPM_OUTPUT("VOUTR"), |
323 | SND_SOC_DAPM_DAC("DAC", "Playback", UDA1380_PM, 10, 0), | 323 | SND_SOC_DAPM_DAC("DAC", "Playback", UDA1380_PM, 10, 0), |
324 | SND_SOC_DAPM_PGA("HeadPhone Driver", UDA1380_PM, 13, 0, NULL, 0), | 324 | SND_SOC_DAPM_PGA("HeadPhone Driver", UDA1380_PM, 13, 0, NULL, 0), |
325 | }; | 325 | }; |
326 | 326 | ||
327 | static const struct snd_soc_dapm_route audio_map[] = { | 327 | static const struct snd_soc_dapm_route audio_map[] = { |
328 | 328 | ||
329 | /* output mux */ | 329 | /* output mux */ |
330 | {"HeadPhone Driver", NULL, "Output Mux"}, | 330 | {"HeadPhone Driver", NULL, "Output Mux"}, |
331 | {"VOUTR", NULL, "Output Mux"}, | 331 | {"VOUTR", NULL, "Output Mux"}, |
332 | {"VOUTL", NULL, "Output Mux"}, | 332 | {"VOUTL", NULL, "Output Mux"}, |
333 | 333 | ||
334 | {"Analog Mixer", NULL, "VINR"}, | 334 | {"Analog Mixer", NULL, "VINR"}, |
335 | {"Analog Mixer", NULL, "VINL"}, | 335 | {"Analog Mixer", NULL, "VINL"}, |
336 | {"Analog Mixer", NULL, "DAC"}, | 336 | {"Analog Mixer", NULL, "DAC"}, |
337 | 337 | ||
338 | {"Output Mux", "DAC", "DAC"}, | 338 | {"Output Mux", "DAC", "DAC"}, |
339 | {"Output Mux", "Analog Mixer", "Analog Mixer"}, | 339 | {"Output Mux", "Analog Mixer", "Analog Mixer"}, |
340 | 340 | ||
341 | /* {"DAC", "Digital Mixer", "I2S" } */ | 341 | /* {"DAC", "Digital Mixer", "I2S" } */ |
342 | 342 | ||
343 | /* headphone driver */ | 343 | /* headphone driver */ |
344 | {"VOUTLHP", NULL, "HeadPhone Driver"}, | 344 | {"VOUTLHP", NULL, "HeadPhone Driver"}, |
345 | {"VOUTRHP", NULL, "HeadPhone Driver"}, | 345 | {"VOUTRHP", NULL, "HeadPhone Driver"}, |
346 | 346 | ||
347 | /* input mux */ | 347 | /* input mux */ |
348 | {"Left ADC", NULL, "Input Mux"}, | 348 | {"Left ADC", NULL, "Input Mux"}, |
349 | {"Input Mux", "Mic", "Mic LNA"}, | 349 | {"Input Mux", "Mic", "Mic LNA"}, |
350 | {"Input Mux", "Mic + Line R", "Mic LNA"}, | 350 | {"Input Mux", "Mic + Line R", "Mic LNA"}, |
351 | {"Input Mux", "Line L", "Left PGA"}, | 351 | {"Input Mux", "Line L", "Left PGA"}, |
352 | {"Input Mux", "Line", "Left PGA"}, | 352 | {"Input Mux", "Line", "Left PGA"}, |
353 | 353 | ||
354 | /* right input */ | 354 | /* right input */ |
355 | {"Right ADC", "Mic + Line R", "Right PGA"}, | 355 | {"Right ADC", "Mic + Line R", "Right PGA"}, |
356 | {"Right ADC", "Line", "Right PGA"}, | 356 | {"Right ADC", "Line", "Right PGA"}, |
357 | 357 | ||
358 | /* inputs */ | 358 | /* inputs */ |
359 | {"Mic LNA", NULL, "VINM"}, | 359 | {"Mic LNA", NULL, "VINM"}, |
360 | {"Left PGA", NULL, "VINL"}, | 360 | {"Left PGA", NULL, "VINL"}, |
361 | {"Right PGA", NULL, "VINR"}, | 361 | {"Right PGA", NULL, "VINR"}, |
362 | }; | 362 | }; |
363 | 363 | ||
364 | static int uda1380_add_widgets(struct snd_soc_codec *codec) | 364 | static int uda1380_add_widgets(struct snd_soc_codec *codec) |
365 | { | 365 | { |
366 | snd_soc_dapm_new_controls(codec, uda1380_dapm_widgets, | 366 | snd_soc_dapm_new_controls(codec, uda1380_dapm_widgets, |
367 | ARRAY_SIZE(uda1380_dapm_widgets)); | 367 | ARRAY_SIZE(uda1380_dapm_widgets)); |
368 | 368 | ||
369 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | 369 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
370 | 370 | ||
371 | snd_soc_dapm_new_widgets(codec); | 371 | snd_soc_dapm_new_widgets(codec); |
372 | return 0; | 372 | return 0; |
373 | } | 373 | } |
374 | 374 | ||
375 | static int uda1380_set_dai_fmt(struct snd_soc_dai *codec_dai, | 375 | static int uda1380_set_dai_fmt(struct snd_soc_dai *codec_dai, |
376 | unsigned int fmt) | 376 | unsigned int fmt) |
377 | { | 377 | { |
378 | struct snd_soc_codec *codec = codec_dai->codec; | 378 | struct snd_soc_codec *codec = codec_dai->codec; |
379 | int iface; | 379 | int iface; |
380 | 380 | ||
381 | /* set up DAI based upon fmt */ | 381 | /* set up DAI based upon fmt */ |
382 | iface = uda1380_read_reg_cache(codec, UDA1380_IFACE); | 382 | iface = uda1380_read_reg_cache(codec, UDA1380_IFACE); |
383 | iface &= ~(R01_SFORI_MASK | R01_SIM | R01_SFORO_MASK); | 383 | iface &= ~(R01_SFORI_MASK | R01_SIM | R01_SFORO_MASK); |
384 | 384 | ||
385 | /* FIXME: how to select I2S for DATAO and MSB for DATAI correctly? */ | 385 | /* FIXME: how to select I2S for DATAO and MSB for DATAI correctly? */ |
386 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 386 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
387 | case SND_SOC_DAIFMT_I2S: | 387 | case SND_SOC_DAIFMT_I2S: |
388 | iface |= R01_SFORI_I2S | R01_SFORO_I2S; | 388 | iface |= R01_SFORI_I2S | R01_SFORO_I2S; |
389 | break; | 389 | break; |
390 | case SND_SOC_DAIFMT_LSB: | 390 | case SND_SOC_DAIFMT_LSB: |
391 | iface |= R01_SFORI_LSB16 | R01_SFORO_I2S; | 391 | iface |= R01_SFORI_LSB16 | R01_SFORO_I2S; |
392 | break; | 392 | break; |
393 | case SND_SOC_DAIFMT_MSB: | 393 | case SND_SOC_DAIFMT_MSB: |
394 | iface |= R01_SFORI_MSB | R01_SFORO_I2S; | 394 | iface |= R01_SFORI_MSB | R01_SFORO_I2S; |
395 | } | 395 | } |
396 | 396 | ||
397 | if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM) | 397 | if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM) |
398 | iface |= R01_SIM; | 398 | iface |= R01_SIM; |
399 | 399 | ||
400 | uda1380_write(codec, UDA1380_IFACE, iface); | 400 | uda1380_write(codec, UDA1380_IFACE, iface); |
401 | 401 | ||
402 | return 0; | 402 | return 0; |
403 | } | 403 | } |
404 | 404 | ||
405 | /* | 405 | /* |
406 | * Flush reg cache | 406 | * Flush reg cache |
407 | * We can only write the interpolator and decimator registers | 407 | * We can only write the interpolator and decimator registers |
408 | * when the DAI is being clocked by the CPU DAI. It's up to the | 408 | * when the DAI is being clocked by the CPU DAI. It's up to the |
409 | * machine and cpu DAI driver to do this before we are called. | 409 | * machine and cpu DAI driver to do this before we are called. |
410 | */ | 410 | */ |
411 | static int uda1380_pcm_prepare(struct snd_pcm_substream *substream) | 411 | static int uda1380_pcm_prepare(struct snd_pcm_substream *substream) |
412 | { | 412 | { |
413 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 413 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
414 | struct snd_soc_device *socdev = rtd->socdev; | 414 | struct snd_soc_device *socdev = rtd->socdev; |
415 | struct snd_soc_codec *codec = socdev->codec; | 415 | struct snd_soc_codec *codec = socdev->codec; |
416 | int reg, reg_start, reg_end, clk; | 416 | int reg, reg_start, reg_end, clk; |
417 | 417 | ||
418 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 418 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
419 | reg_start = UDA1380_MVOL; | 419 | reg_start = UDA1380_MVOL; |
420 | reg_end = UDA1380_MIXER; | 420 | reg_end = UDA1380_MIXER; |
421 | } else { | 421 | } else { |
422 | reg_start = UDA1380_DEC; | 422 | reg_start = UDA1380_DEC; |
423 | reg_end = UDA1380_AGC; | 423 | reg_end = UDA1380_AGC; |
424 | } | 424 | } |
425 | 425 | ||
426 | /* FIXME disable DAC_CLK */ | 426 | /* FIXME disable DAC_CLK */ |
427 | clk = uda1380_read_reg_cache(codec, UDA1380_CLK); | 427 | clk = uda1380_read_reg_cache(codec, UDA1380_CLK); |
428 | uda1380_write(codec, UDA1380_CLK, clk & ~R00_DAC_CLK); | 428 | uda1380_write(codec, UDA1380_CLK, clk & ~R00_DAC_CLK); |
429 | 429 | ||
430 | for (reg = reg_start; reg <= reg_end; reg++) { | 430 | for (reg = reg_start; reg <= reg_end; reg++) { |
431 | pr_debug("uda1380: flush reg %x val %x:", reg, | 431 | pr_debug("uda1380: flush reg %x val %x:", reg, |
432 | uda1380_read_reg_cache(codec, reg)); | 432 | uda1380_read_reg_cache(codec, reg)); |
433 | uda1380_write(codec, reg, uda1380_read_reg_cache(codec, reg)); | 433 | uda1380_write(codec, reg, uda1380_read_reg_cache(codec, reg)); |
434 | } | 434 | } |
435 | 435 | ||
436 | /* FIXME enable DAC_CLK */ | 436 | /* FIXME enable DAC_CLK */ |
437 | uda1380_write(codec, UDA1380_CLK, clk | R00_DAC_CLK); | 437 | uda1380_write(codec, UDA1380_CLK, clk | R00_DAC_CLK); |
438 | 438 | ||
439 | return 0; | 439 | return 0; |
440 | } | 440 | } |
441 | 441 | ||
442 | static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream, | 442 | static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream, |
443 | struct snd_pcm_hw_params *params) | 443 | struct snd_pcm_hw_params *params) |
444 | { | 444 | { |
445 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 445 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
446 | struct snd_soc_device *socdev = rtd->socdev; | 446 | struct snd_soc_device *socdev = rtd->socdev; |
447 | struct snd_soc_codec *codec = socdev->codec; | 447 | struct snd_soc_codec *codec = socdev->codec; |
448 | u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK); | 448 | u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK); |
449 | 449 | ||
450 | /* set WSPLL power and divider if running from this clock */ | 450 | /* set WSPLL power and divider if running from this clock */ |
451 | if (clk & R00_DAC_CLK) { | 451 | if (clk & R00_DAC_CLK) { |
452 | int rate = params_rate(params); | 452 | int rate = params_rate(params); |
453 | u16 pm = uda1380_read_reg_cache(codec, UDA1380_PM); | 453 | u16 pm = uda1380_read_reg_cache(codec, UDA1380_PM); |
454 | clk &= ~0x3; /* clear SEL_LOOP_DIV */ | 454 | clk &= ~0x3; /* clear SEL_LOOP_DIV */ |
455 | switch (rate) { | 455 | switch (rate) { |
456 | case 6250 ... 12500: | 456 | case 6250 ... 12500: |
457 | clk |= 0x0; | 457 | clk |= 0x0; |
458 | break; | 458 | break; |
459 | case 12501 ... 25000: | 459 | case 12501 ... 25000: |
460 | clk |= 0x1; | 460 | clk |= 0x1; |
461 | break; | 461 | break; |
462 | case 25001 ... 50000: | 462 | case 25001 ... 50000: |
463 | clk |= 0x2; | 463 | clk |= 0x2; |
464 | break; | 464 | break; |
465 | case 50001 ... 100000: | 465 | case 50001 ... 100000: |
466 | clk |= 0x3; | 466 | clk |= 0x3; |
467 | break; | 467 | break; |
468 | } | 468 | } |
469 | uda1380_write(codec, UDA1380_PM, R02_PON_PLL | pm); | 469 | uda1380_write(codec, UDA1380_PM, R02_PON_PLL | pm); |
470 | } | 470 | } |
471 | 471 | ||
472 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 472 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
473 | clk |= R00_EN_DAC | R00_EN_INT; | 473 | clk |= R00_EN_DAC | R00_EN_INT; |
474 | else | 474 | else |
475 | clk |= R00_EN_ADC | R00_EN_DEC; | 475 | clk |= R00_EN_ADC | R00_EN_DEC; |
476 | 476 | ||
477 | uda1380_write(codec, UDA1380_CLK, clk); | 477 | uda1380_write(codec, UDA1380_CLK, clk); |
478 | return 0; | 478 | return 0; |
479 | } | 479 | } |
480 | 480 | ||
481 | static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream) | 481 | static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream) |
482 | { | 482 | { |
483 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 483 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
484 | struct snd_soc_device *socdev = rtd->socdev; | 484 | struct snd_soc_device *socdev = rtd->socdev; |
485 | struct snd_soc_codec *codec = socdev->codec; | 485 | struct snd_soc_codec *codec = socdev->codec; |
486 | u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK); | 486 | u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK); |
487 | 487 | ||
488 | /* shut down WSPLL power if running from this clock */ | 488 | /* shut down WSPLL power if running from this clock */ |
489 | if (clk & R00_DAC_CLK) { | 489 | if (clk & R00_DAC_CLK) { |
490 | u16 pm = uda1380_read_reg_cache(codec, UDA1380_PM); | 490 | u16 pm = uda1380_read_reg_cache(codec, UDA1380_PM); |
491 | uda1380_write(codec, UDA1380_PM, ~R02_PON_PLL & pm); | 491 | uda1380_write(codec, UDA1380_PM, ~R02_PON_PLL & pm); |
492 | } | 492 | } |
493 | 493 | ||
494 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 494 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
495 | clk &= ~(R00_EN_DAC | R00_EN_INT); | 495 | clk &= ~(R00_EN_DAC | R00_EN_INT); |
496 | else | 496 | else |
497 | clk &= ~(R00_EN_ADC | R00_EN_DEC); | 497 | clk &= ~(R00_EN_ADC | R00_EN_DEC); |
498 | 498 | ||
499 | uda1380_write(codec, UDA1380_CLK, clk); | 499 | uda1380_write(codec, UDA1380_CLK, clk); |
500 | } | 500 | } |
501 | 501 | ||
502 | static int uda1380_mute(struct snd_soc_dai *codec_dai, int mute) | 502 | static int uda1380_mute(struct snd_soc_dai *codec_dai, int mute) |
503 | { | 503 | { |
504 | struct snd_soc_codec *codec = codec_dai->codec; | 504 | struct snd_soc_codec *codec = codec_dai->codec; |
505 | u16 mute_reg = uda1380_read_reg_cache(codec, UDA1380_DEEMP) & ~R13_MTM; | 505 | u16 mute_reg = uda1380_read_reg_cache(codec, UDA1380_DEEMP) & ~R13_MTM; |
506 | 506 | ||
507 | /* FIXME: mute(codec,0) is called when the magician clock is already | 507 | /* FIXME: mute(codec,0) is called when the magician clock is already |
508 | * set to WSPLL, but for some unknown reason writing to interpolator | 508 | * set to WSPLL, but for some unknown reason writing to interpolator |
509 | * registers works only when clocked by SYSCLK */ | 509 | * registers works only when clocked by SYSCLK */ |
510 | u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK); | 510 | u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK); |
511 | uda1380_write(codec, UDA1380_CLK, ~R00_DAC_CLK & clk); | 511 | uda1380_write(codec, UDA1380_CLK, ~R00_DAC_CLK & clk); |
512 | if (mute) | 512 | if (mute) |
513 | uda1380_write(codec, UDA1380_DEEMP, mute_reg | R13_MTM); | 513 | uda1380_write(codec, UDA1380_DEEMP, mute_reg | R13_MTM); |
514 | else | 514 | else |
515 | uda1380_write(codec, UDA1380_DEEMP, mute_reg); | 515 | uda1380_write(codec, UDA1380_DEEMP, mute_reg); |
516 | uda1380_write(codec, UDA1380_CLK, clk); | 516 | uda1380_write(codec, UDA1380_CLK, clk); |
517 | return 0; | 517 | return 0; |
518 | } | 518 | } |
519 | 519 | ||
520 | static int uda1380_set_bias_level(struct snd_soc_codec *codec, | 520 | static int uda1380_set_bias_level(struct snd_soc_codec *codec, |
521 | enum snd_soc_bias_level level) | 521 | enum snd_soc_bias_level level) |
522 | { | 522 | { |
523 | int pm = uda1380_read_reg_cache(codec, UDA1380_PM); | 523 | int pm = uda1380_read_reg_cache(codec, UDA1380_PM); |
524 | 524 | ||
525 | switch (level) { | 525 | switch (level) { |
526 | case SND_SOC_BIAS_ON: | 526 | case SND_SOC_BIAS_ON: |
527 | case SND_SOC_BIAS_PREPARE: | 527 | case SND_SOC_BIAS_PREPARE: |
528 | uda1380_write(codec, UDA1380_PM, R02_PON_BIAS | pm); | 528 | uda1380_write(codec, UDA1380_PM, R02_PON_BIAS | pm); |
529 | break; | 529 | break; |
530 | case SND_SOC_BIAS_STANDBY: | 530 | case SND_SOC_BIAS_STANDBY: |
531 | uda1380_write(codec, UDA1380_PM, R02_PON_BIAS); | 531 | uda1380_write(codec, UDA1380_PM, R02_PON_BIAS); |
532 | break; | 532 | break; |
533 | case SND_SOC_BIAS_OFF: | 533 | case SND_SOC_BIAS_OFF: |
534 | uda1380_write(codec, UDA1380_PM, 0x0); | 534 | uda1380_write(codec, UDA1380_PM, 0x0); |
535 | break; | 535 | break; |
536 | } | 536 | } |
537 | codec->bias_level = level; | 537 | codec->bias_level = level; |
538 | return 0; | 538 | return 0; |
539 | } | 539 | } |
540 | 540 | ||
541 | #define UDA1380_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | 541 | #define UDA1380_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ |
542 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ | 542 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ |
543 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) | 543 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) |
544 | 544 | ||
545 | struct snd_soc_dai uda1380_dai[] = { | 545 | struct snd_soc_dai uda1380_dai[] = { |
546 | { | 546 | { |
547 | .name = "UDA1380", | 547 | .name = "UDA1380", |
548 | .playback = { | 548 | .playback = { |
549 | .stream_name = "Playback", | 549 | .stream_name = "Playback", |
550 | .channels_min = 1, | 550 | .channels_min = 1, |
551 | .channels_max = 2, | 551 | .channels_max = 2, |
552 | .rates = UDA1380_RATES, | 552 | .rates = UDA1380_RATES, |
553 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | 553 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, |
554 | .capture = { | 554 | .capture = { |
555 | .stream_name = "Capture", | 555 | .stream_name = "Capture", |
556 | .channels_min = 1, | 556 | .channels_min = 1, |
557 | .channels_max = 2, | 557 | .channels_max = 2, |
558 | .rates = UDA1380_RATES, | 558 | .rates = UDA1380_RATES, |
559 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | 559 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, |
560 | .ops = { | 560 | .ops = { |
561 | .hw_params = uda1380_pcm_hw_params, | 561 | .hw_params = uda1380_pcm_hw_params, |
562 | .shutdown = uda1380_pcm_shutdown, | 562 | .shutdown = uda1380_pcm_shutdown, |
563 | .prepare = uda1380_pcm_prepare, | 563 | .prepare = uda1380_pcm_prepare, |
564 | }, | 564 | }, |
565 | .dai_ops = { | 565 | .dai_ops = { |
566 | .digital_mute = uda1380_mute, | 566 | .digital_mute = uda1380_mute, |
567 | .set_fmt = uda1380_set_dai_fmt, | 567 | .set_fmt = uda1380_set_dai_fmt, |
568 | }, | 568 | }, |
569 | }, | 569 | }, |
570 | { /* playback only - dual interface */ | 570 | { /* playback only - dual interface */ |
571 | .name = "UDA1380", | 571 | .name = "UDA1380", |
572 | .playback = { | 572 | .playback = { |
573 | .stream_name = "Playback", | 573 | .stream_name = "Playback", |
574 | .channels_min = 1, | 574 | .channels_min = 1, |
575 | .channels_max = 2, | 575 | .channels_max = 2, |
576 | .rates = UDA1380_RATES, | 576 | .rates = UDA1380_RATES, |
577 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 577 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
578 | }, | 578 | }, |
579 | .ops = { | 579 | .ops = { |
580 | .hw_params = uda1380_pcm_hw_params, | 580 | .hw_params = uda1380_pcm_hw_params, |
581 | .shutdown = uda1380_pcm_shutdown, | 581 | .shutdown = uda1380_pcm_shutdown, |
582 | .prepare = uda1380_pcm_prepare, | 582 | .prepare = uda1380_pcm_prepare, |
583 | }, | 583 | }, |
584 | .dai_ops = { | 584 | .dai_ops = { |
585 | .digital_mute = uda1380_mute, | 585 | .digital_mute = uda1380_mute, |
586 | .set_fmt = uda1380_set_dai_fmt, | 586 | .set_fmt = uda1380_set_dai_fmt, |
587 | }, | 587 | }, |
588 | }, | 588 | }, |
589 | { /* capture only - dual interface*/ | 589 | { /* capture only - dual interface*/ |
590 | .name = "UDA1380", | 590 | .name = "UDA1380", |
591 | .capture = { | 591 | .capture = { |
592 | .stream_name = "Capture", | 592 | .stream_name = "Capture", |
593 | .channels_min = 1, | 593 | .channels_min = 1, |
594 | .channels_max = 2, | 594 | .channels_max = 2, |
595 | .rates = UDA1380_RATES, | 595 | .rates = UDA1380_RATES, |
596 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 596 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
597 | }, | 597 | }, |
598 | .ops = { | 598 | .ops = { |
599 | .hw_params = uda1380_pcm_hw_params, | 599 | .hw_params = uda1380_pcm_hw_params, |
600 | .shutdown = uda1380_pcm_shutdown, | 600 | .shutdown = uda1380_pcm_shutdown, |
601 | .prepare = uda1380_pcm_prepare, | 601 | .prepare = uda1380_pcm_prepare, |
602 | }, | 602 | }, |
603 | .dai_ops = { | 603 | .dai_ops = { |
604 | .set_fmt = uda1380_set_dai_fmt, | 604 | .set_fmt = uda1380_set_dai_fmt, |
605 | }, | 605 | }, |
606 | }, | 606 | }, |
607 | }; | 607 | }; |
608 | EXPORT_SYMBOL_GPL(uda1380_dai); | 608 | EXPORT_SYMBOL_GPL(uda1380_dai); |
609 | 609 | ||
610 | static int uda1380_suspend(struct platform_device *pdev, pm_message_t state) | 610 | static int uda1380_suspend(struct platform_device *pdev, pm_message_t state) |
611 | { | 611 | { |
612 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 612 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
613 | struct snd_soc_codec *codec = socdev->codec; | 613 | struct snd_soc_codec *codec = socdev->codec; |
614 | 614 | ||
615 | uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF); | 615 | uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF); |
616 | return 0; | 616 | return 0; |
617 | } | 617 | } |
618 | 618 | ||
619 | static int uda1380_resume(struct platform_device *pdev) | 619 | static int uda1380_resume(struct platform_device *pdev) |
620 | { | 620 | { |
621 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 621 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
622 | struct snd_soc_codec *codec = socdev->codec; | 622 | struct snd_soc_codec *codec = socdev->codec; |
623 | int i; | 623 | int i; |
624 | u8 data[2]; | 624 | u8 data[2]; |
625 | u16 *cache = codec->reg_cache; | 625 | u16 *cache = codec->reg_cache; |
626 | 626 | ||
627 | /* Sync reg_cache with the hardware */ | 627 | /* Sync reg_cache with the hardware */ |
628 | for (i = 0; i < ARRAY_SIZE(uda1380_reg); i++) { | 628 | for (i = 0; i < ARRAY_SIZE(uda1380_reg); i++) { |
629 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); | 629 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); |
630 | data[1] = cache[i] & 0x00ff; | 630 | data[1] = cache[i] & 0x00ff; |
631 | codec->hw_write(codec->control_data, data, 2); | 631 | codec->hw_write(codec->control_data, data, 2); |
632 | } | 632 | } |
633 | uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 633 | uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
634 | uda1380_set_bias_level(codec, codec->suspend_bias_level); | 634 | uda1380_set_bias_level(codec, codec->suspend_bias_level); |
635 | return 0; | 635 | return 0; |
636 | } | 636 | } |
637 | 637 | ||
638 | /* | 638 | /* |
639 | * initialise the UDA1380 driver | 639 | * initialise the UDA1380 driver |
640 | * register mixer and dsp interfaces with the kernel | 640 | * register mixer and dsp interfaces with the kernel |
641 | */ | 641 | */ |
642 | static int uda1380_init(struct snd_soc_device *socdev, int dac_clk) | 642 | static int uda1380_init(struct snd_soc_device *socdev, int dac_clk) |
643 | { | 643 | { |
644 | struct snd_soc_codec *codec = socdev->codec; | 644 | struct snd_soc_codec *codec = socdev->codec; |
645 | int ret = 0; | 645 | int ret = 0; |
646 | 646 | ||
647 | codec->name = "UDA1380"; | 647 | codec->name = "UDA1380"; |
648 | codec->owner = THIS_MODULE; | 648 | codec->owner = THIS_MODULE; |
649 | codec->read = uda1380_read_reg_cache; | 649 | codec->read = uda1380_read_reg_cache; |
650 | codec->write = uda1380_write; | 650 | codec->write = uda1380_write; |
651 | codec->set_bias_level = uda1380_set_bias_level; | 651 | codec->set_bias_level = uda1380_set_bias_level; |
652 | codec->dai = uda1380_dai; | 652 | codec->dai = uda1380_dai; |
653 | codec->num_dai = ARRAY_SIZE(uda1380_dai); | 653 | codec->num_dai = ARRAY_SIZE(uda1380_dai); |
654 | codec->reg_cache = kmemdup(uda1380_reg, sizeof(uda1380_reg), | 654 | codec->reg_cache = kmemdup(uda1380_reg, sizeof(uda1380_reg), |
655 | GFP_KERNEL); | 655 | GFP_KERNEL); |
656 | if (codec->reg_cache == NULL) | 656 | if (codec->reg_cache == NULL) |
657 | return -ENOMEM; | 657 | return -ENOMEM; |
658 | codec->reg_cache_size = ARRAY_SIZE(uda1380_reg); | 658 | codec->reg_cache_size = ARRAY_SIZE(uda1380_reg); |
659 | codec->reg_cache_step = 1; | 659 | codec->reg_cache_step = 1; |
660 | uda1380_reset(codec); | 660 | uda1380_reset(codec); |
661 | 661 | ||
662 | /* register pcms */ | 662 | /* register pcms */ |
663 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 663 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
664 | if (ret < 0) { | 664 | if (ret < 0) { |
665 | pr_err("uda1380: failed to create pcms\n"); | 665 | pr_err("uda1380: failed to create pcms\n"); |
666 | goto pcm_err; | 666 | goto pcm_err; |
667 | } | 667 | } |
668 | 668 | ||
669 | /* power on device */ | 669 | /* power on device */ |
670 | uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 670 | uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
671 | /* set clock input */ | 671 | /* set clock input */ |
672 | switch (dac_clk) { | 672 | switch (dac_clk) { |
673 | case UDA1380_DAC_CLK_SYSCLK: | 673 | case UDA1380_DAC_CLK_SYSCLK: |
674 | uda1380_write(codec, UDA1380_CLK, 0); | 674 | uda1380_write(codec, UDA1380_CLK, 0); |
675 | break; | 675 | break; |
676 | case UDA1380_DAC_CLK_WSPLL: | 676 | case UDA1380_DAC_CLK_WSPLL: |
677 | uda1380_write(codec, UDA1380_CLK, R00_DAC_CLK); | 677 | uda1380_write(codec, UDA1380_CLK, R00_DAC_CLK); |
678 | break; | 678 | break; |
679 | } | 679 | } |
680 | 680 | ||
681 | /* uda1380 init */ | 681 | /* uda1380 init */ |
682 | uda1380_add_controls(codec); | 682 | uda1380_add_controls(codec); |
683 | uda1380_add_widgets(codec); | 683 | uda1380_add_widgets(codec); |
684 | ret = snd_soc_register_card(socdev); | 684 | ret = snd_soc_register_card(socdev); |
685 | if (ret < 0) { | 685 | if (ret < 0) { |
686 | pr_err("uda1380: failed to register card\n"); | 686 | pr_err("uda1380: failed to register card\n"); |
687 | goto card_err; | 687 | goto card_err; |
688 | } | 688 | } |
689 | 689 | ||
690 | return ret; | 690 | return ret; |
691 | 691 | ||
692 | card_err: | 692 | card_err: |
693 | snd_soc_free_pcms(socdev); | 693 | snd_soc_free_pcms(socdev); |
694 | snd_soc_dapm_free(socdev); | 694 | snd_soc_dapm_free(socdev); |
695 | pcm_err: | 695 | pcm_err: |
696 | kfree(codec->reg_cache); | 696 | kfree(codec->reg_cache); |
697 | return ret; | 697 | return ret; |
698 | } | 698 | } |
699 | 699 | ||
700 | static struct snd_soc_device *uda1380_socdev; | 700 | static struct snd_soc_device *uda1380_socdev; |
701 | 701 | ||
702 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 702 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
703 | 703 | ||
704 | #define I2C_DRIVERID_UDA1380 0xfefe /* liam - need a proper id */ | 704 | #define I2C_DRIVERID_UDA1380 0xfefe /* liam - need a proper id */ |
705 | 705 | ||
706 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | 706 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; |
707 | 707 | ||
708 | /* Magic definition of all other variables and things */ | 708 | /* Magic definition of all other variables and things */ |
709 | I2C_CLIENT_INSMOD; | 709 | I2C_CLIENT_INSMOD; |
710 | 710 | ||
711 | static struct i2c_driver uda1380_i2c_driver; | 711 | static struct i2c_driver uda1380_i2c_driver; |
712 | static struct i2c_client client_template; | 712 | static struct i2c_client client_template; |
713 | 713 | ||
714 | /* If the i2c layer weren't so broken, we could pass this kind of data | 714 | /* If the i2c layer weren't so broken, we could pass this kind of data |
715 | around */ | 715 | around */ |
716 | 716 | ||
717 | static int uda1380_codec_probe(struct i2c_adapter *adap, int addr, int kind) | 717 | static int uda1380_codec_probe(struct i2c_adapter *adap, int addr, int kind) |
718 | { | 718 | { |
719 | struct snd_soc_device *socdev = uda1380_socdev; | 719 | struct snd_soc_device *socdev = uda1380_socdev; |
720 | struct uda1380_setup_data *setup = socdev->codec_data; | 720 | struct uda1380_setup_data *setup = socdev->codec_data; |
721 | struct snd_soc_codec *codec = socdev->codec; | 721 | struct snd_soc_codec *codec = socdev->codec; |
722 | struct i2c_client *i2c; | 722 | struct i2c_client *i2c; |
723 | int ret; | 723 | int ret; |
724 | 724 | ||
725 | if (addr != setup->i2c_address) | 725 | if (addr != setup->i2c_address) |
726 | return -ENODEV; | 726 | return -ENODEV; |
727 | 727 | ||
728 | client_template.adapter = adap; | 728 | client_template.adapter = adap; |
729 | client_template.addr = addr; | 729 | client_template.addr = addr; |
730 | 730 | ||
731 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | 731 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); |
732 | if (i2c == NULL) { | 732 | if (i2c == NULL) |
733 | kfree(codec); | ||
734 | return -ENOMEM; | 733 | return -ENOMEM; |
735 | } | 734 | |
736 | i2c_set_clientdata(i2c, codec); | 735 | i2c_set_clientdata(i2c, codec); |
737 | codec->control_data = i2c; | 736 | codec->control_data = i2c; |
738 | 737 | ||
739 | ret = i2c_attach_client(i2c); | 738 | ret = i2c_attach_client(i2c); |
740 | if (ret < 0) { | 739 | if (ret < 0) { |
741 | pr_err("uda1380: failed to attach codec at addr %x\n", addr); | 740 | pr_err("uda1380: failed to attach codec at addr %x\n", addr); |
742 | goto err; | 741 | goto err; |
743 | } | 742 | } |
744 | 743 | ||
745 | ret = uda1380_init(socdev, setup->dac_clk); | 744 | ret = uda1380_init(socdev, setup->dac_clk); |
746 | if (ret < 0) { | 745 | if (ret < 0) { |
747 | pr_err("uda1380: failed to initialise UDA1380\n"); | 746 | pr_err("uda1380: failed to initialise UDA1380\n"); |
748 | goto err; | 747 | goto err; |
749 | } | 748 | } |
750 | return ret; | 749 | return ret; |
751 | 750 | ||
752 | err: | 751 | err: |
753 | kfree(codec); | ||
754 | kfree(i2c); | 752 | kfree(i2c); |
755 | return ret; | 753 | return ret; |
756 | } | 754 | } |
757 | 755 | ||
758 | static int uda1380_i2c_detach(struct i2c_client *client) | 756 | static int uda1380_i2c_detach(struct i2c_client *client) |
759 | { | 757 | { |
760 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 758 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
761 | i2c_detach_client(client); | 759 | i2c_detach_client(client); |
762 | kfree(codec->reg_cache); | 760 | kfree(codec->reg_cache); |
763 | kfree(client); | 761 | kfree(client); |
764 | return 0; | 762 | return 0; |
765 | } | 763 | } |
766 | 764 | ||
767 | static int uda1380_i2c_attach(struct i2c_adapter *adap) | 765 | static int uda1380_i2c_attach(struct i2c_adapter *adap) |
768 | { | 766 | { |
769 | return i2c_probe(adap, &addr_data, uda1380_codec_probe); | 767 | return i2c_probe(adap, &addr_data, uda1380_codec_probe); |
770 | } | 768 | } |
771 | 769 | ||
772 | static struct i2c_driver uda1380_i2c_driver = { | 770 | static struct i2c_driver uda1380_i2c_driver = { |
773 | .driver = { | 771 | .driver = { |
774 | .name = "UDA1380 I2C Codec", | 772 | .name = "UDA1380 I2C Codec", |
775 | .owner = THIS_MODULE, | 773 | .owner = THIS_MODULE, |
776 | }, | 774 | }, |
777 | .id = I2C_DRIVERID_UDA1380, | 775 | .id = I2C_DRIVERID_UDA1380, |
778 | .attach_adapter = uda1380_i2c_attach, | 776 | .attach_adapter = uda1380_i2c_attach, |
779 | .detach_client = uda1380_i2c_detach, | 777 | .detach_client = uda1380_i2c_detach, |
780 | .command = NULL, | 778 | .command = NULL, |
781 | }; | 779 | }; |
782 | 780 | ||
783 | static struct i2c_client client_template = { | 781 | static struct i2c_client client_template = { |
784 | .name = "UDA1380", | 782 | .name = "UDA1380", |
785 | .driver = &uda1380_i2c_driver, | 783 | .driver = &uda1380_i2c_driver, |
786 | }; | 784 | }; |
787 | #endif | 785 | #endif |
788 | 786 | ||
789 | static int uda1380_probe(struct platform_device *pdev) | 787 | static int uda1380_probe(struct platform_device *pdev) |
790 | { | 788 | { |
791 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 789 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
792 | struct uda1380_setup_data *setup; | 790 | struct uda1380_setup_data *setup; |
793 | struct snd_soc_codec *codec; | 791 | struct snd_soc_codec *codec; |
794 | int ret = 0; | 792 | int ret = 0; |
795 | 793 | ||
796 | pr_info("UDA1380 Audio Codec %s", UDA1380_VERSION); | 794 | pr_info("UDA1380 Audio Codec %s", UDA1380_VERSION); |
797 | 795 | ||
798 | setup = socdev->codec_data; | 796 | setup = socdev->codec_data; |
799 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 797 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); |
800 | if (codec == NULL) | 798 | if (codec == NULL) |
801 | return -ENOMEM; | 799 | return -ENOMEM; |
802 | 800 | ||
803 | socdev->codec = codec; | 801 | socdev->codec = codec; |
804 | mutex_init(&codec->mutex); | 802 | mutex_init(&codec->mutex); |
805 | INIT_LIST_HEAD(&codec->dapm_widgets); | 803 | INIT_LIST_HEAD(&codec->dapm_widgets); |
806 | INIT_LIST_HEAD(&codec->dapm_paths); | 804 | INIT_LIST_HEAD(&codec->dapm_paths); |
807 | 805 | ||
808 | uda1380_socdev = socdev; | 806 | uda1380_socdev = socdev; |
809 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 807 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
810 | if (setup->i2c_address) { | 808 | if (setup->i2c_address) { |
811 | normal_i2c[0] = setup->i2c_address; | 809 | normal_i2c[0] = setup->i2c_address; |
812 | codec->hw_write = (hw_write_t)i2c_master_send; | 810 | codec->hw_write = (hw_write_t)i2c_master_send; |
813 | ret = i2c_add_driver(&uda1380_i2c_driver); | 811 | ret = i2c_add_driver(&uda1380_i2c_driver); |
814 | if (ret != 0) | 812 | if (ret != 0) |
815 | printk(KERN_ERR "can't add i2c driver"); | 813 | printk(KERN_ERR "can't add i2c driver"); |
816 | } | 814 | } |
817 | #else | 815 | #else |
818 | /* Add other interfaces here */ | 816 | /* Add other interfaces here */ |
819 | #endif | 817 | #endif |
818 | |||
819 | if (ret != 0) | ||
820 | kfree(codec); | ||
820 | return ret; | 821 | return ret; |
821 | } | 822 | } |
822 | 823 | ||
823 | /* power down chip */ | 824 | /* power down chip */ |
824 | static int uda1380_remove(struct platform_device *pdev) | 825 | static int uda1380_remove(struct platform_device *pdev) |
825 | { | 826 | { |
826 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 827 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
827 | struct snd_soc_codec *codec = socdev->codec; | 828 | struct snd_soc_codec *codec = socdev->codec; |
828 | 829 | ||
829 | if (codec->control_data) | 830 | if (codec->control_data) |
830 | uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF); | 831 | uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF); |
831 | 832 | ||
832 | snd_soc_free_pcms(socdev); | 833 | snd_soc_free_pcms(socdev); |
833 | snd_soc_dapm_free(socdev); | 834 | snd_soc_dapm_free(socdev); |
834 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 835 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
835 | i2c_del_driver(&uda1380_i2c_driver); | 836 | i2c_del_driver(&uda1380_i2c_driver); |
836 | #endif | 837 | #endif |
837 | kfree(codec); | 838 | kfree(codec); |
838 | 839 | ||
839 | return 0; | 840 | return 0; |
840 | } | 841 | } |
841 | 842 | ||
842 | struct snd_soc_codec_device soc_codec_dev_uda1380 = { | 843 | struct snd_soc_codec_device soc_codec_dev_uda1380 = { |
843 | .probe = uda1380_probe, | 844 | .probe = uda1380_probe, |
844 | .remove = uda1380_remove, | 845 | .remove = uda1380_remove, |
845 | .suspend = uda1380_suspend, | 846 | .suspend = uda1380_suspend, |
846 | .resume = uda1380_resume, | 847 | .resume = uda1380_resume, |
847 | }; | 848 | }; |
848 | EXPORT_SYMBOL_GPL(soc_codec_dev_uda1380); | 849 | EXPORT_SYMBOL_GPL(soc_codec_dev_uda1380); |
849 | 850 | ||
850 | MODULE_AUTHOR("Giorgio Padrin"); | 851 | MODULE_AUTHOR("Giorgio Padrin"); |
851 | MODULE_DESCRIPTION("Audio support for codec Philips UDA1380"); | 852 | MODULE_DESCRIPTION("Audio support for codec Philips UDA1380"); |
sound/soc/codecs/wm8510.c
1 | /* | 1 | /* |
2 | * wm8510.c -- WM8510 ALSA Soc Audio driver | 2 | * wm8510.c -- WM8510 ALSA Soc Audio driver |
3 | * | 3 | * |
4 | * Copyright 2006 Wolfson Microelectronics PLC. | 4 | * Copyright 2006 Wolfson Microelectronics PLC. |
5 | * | 5 | * |
6 | * Author: Liam Girdwood <liam.girdwood@wolfsonmicro.com> | 6 | * Author: Liam Girdwood <liam.girdwood@wolfsonmicro.com> |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
10 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/moduleparam.h> | 14 | #include <linux/moduleparam.h> |
15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
18 | #include <linux/pm.h> | 18 | #include <linux/pm.h> |
19 | #include <linux/i2c.h> | 19 | #include <linux/i2c.h> |
20 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
21 | #include <sound/core.h> | 21 | #include <sound/core.h> |
22 | #include <sound/pcm.h> | 22 | #include <sound/pcm.h> |
23 | #include <sound/pcm_params.h> | 23 | #include <sound/pcm_params.h> |
24 | #include <sound/soc.h> | 24 | #include <sound/soc.h> |
25 | #include <sound/soc-dapm.h> | 25 | #include <sound/soc-dapm.h> |
26 | #include <sound/initval.h> | 26 | #include <sound/initval.h> |
27 | 27 | ||
28 | #include "wm8510.h" | 28 | #include "wm8510.h" |
29 | 29 | ||
30 | #define AUDIO_NAME "wm8510" | 30 | #define AUDIO_NAME "wm8510" |
31 | #define WM8510_VERSION "0.6" | 31 | #define WM8510_VERSION "0.6" |
32 | 32 | ||
33 | struct snd_soc_codec_device soc_codec_dev_wm8510; | 33 | struct snd_soc_codec_device soc_codec_dev_wm8510; |
34 | 34 | ||
35 | /* | 35 | /* |
36 | * wm8510 register cache | 36 | * wm8510 register cache |
37 | * We can't read the WM8510 register space when we are | 37 | * We can't read the WM8510 register space when we are |
38 | * using 2 wire for device control, so we cache them instead. | 38 | * using 2 wire for device control, so we cache them instead. |
39 | */ | 39 | */ |
40 | static const u16 wm8510_reg[WM8510_CACHEREGNUM] = { | 40 | static const u16 wm8510_reg[WM8510_CACHEREGNUM] = { |
41 | 0x0000, 0x0000, 0x0000, 0x0000, | 41 | 0x0000, 0x0000, 0x0000, 0x0000, |
42 | 0x0050, 0x0000, 0x0140, 0x0000, | 42 | 0x0050, 0x0000, 0x0140, 0x0000, |
43 | 0x0000, 0x0000, 0x0000, 0x00ff, | 43 | 0x0000, 0x0000, 0x0000, 0x00ff, |
44 | 0x0000, 0x0000, 0x0100, 0x00ff, | 44 | 0x0000, 0x0000, 0x0100, 0x00ff, |
45 | 0x0000, 0x0000, 0x012c, 0x002c, | 45 | 0x0000, 0x0000, 0x012c, 0x002c, |
46 | 0x002c, 0x002c, 0x002c, 0x0000, | 46 | 0x002c, 0x002c, 0x002c, 0x0000, |
47 | 0x0032, 0x0000, 0x0000, 0x0000, | 47 | 0x0032, 0x0000, 0x0000, 0x0000, |
48 | 0x0000, 0x0000, 0x0000, 0x0000, | 48 | 0x0000, 0x0000, 0x0000, 0x0000, |
49 | 0x0038, 0x000b, 0x0032, 0x0000, | 49 | 0x0038, 0x000b, 0x0032, 0x0000, |
50 | 0x0008, 0x000c, 0x0093, 0x00e9, | 50 | 0x0008, 0x000c, 0x0093, 0x00e9, |
51 | 0x0000, 0x0000, 0x0000, 0x0000, | 51 | 0x0000, 0x0000, 0x0000, 0x0000, |
52 | 0x0003, 0x0010, 0x0000, 0x0000, | 52 | 0x0003, 0x0010, 0x0000, 0x0000, |
53 | 0x0000, 0x0002, 0x0001, 0x0000, | 53 | 0x0000, 0x0002, 0x0001, 0x0000, |
54 | 0x0000, 0x0000, 0x0039, 0x0000, | 54 | 0x0000, 0x0000, 0x0039, 0x0000, |
55 | 0x0001, | 55 | 0x0001, |
56 | }; | 56 | }; |
57 | 57 | ||
58 | /* | 58 | /* |
59 | * read wm8510 register cache | 59 | * read wm8510 register cache |
60 | */ | 60 | */ |
61 | static inline unsigned int wm8510_read_reg_cache(struct snd_soc_codec *codec, | 61 | static inline unsigned int wm8510_read_reg_cache(struct snd_soc_codec *codec, |
62 | unsigned int reg) | 62 | unsigned int reg) |
63 | { | 63 | { |
64 | u16 *cache = codec->reg_cache; | 64 | u16 *cache = codec->reg_cache; |
65 | if (reg == WM8510_RESET) | 65 | if (reg == WM8510_RESET) |
66 | return 0; | 66 | return 0; |
67 | if (reg >= WM8510_CACHEREGNUM) | 67 | if (reg >= WM8510_CACHEREGNUM) |
68 | return -1; | 68 | return -1; |
69 | return cache[reg]; | 69 | return cache[reg]; |
70 | } | 70 | } |
71 | 71 | ||
72 | /* | 72 | /* |
73 | * write wm8510 register cache | 73 | * write wm8510 register cache |
74 | */ | 74 | */ |
75 | static inline void wm8510_write_reg_cache(struct snd_soc_codec *codec, | 75 | static inline void wm8510_write_reg_cache(struct snd_soc_codec *codec, |
76 | u16 reg, unsigned int value) | 76 | u16 reg, unsigned int value) |
77 | { | 77 | { |
78 | u16 *cache = codec->reg_cache; | 78 | u16 *cache = codec->reg_cache; |
79 | if (reg >= WM8510_CACHEREGNUM) | 79 | if (reg >= WM8510_CACHEREGNUM) |
80 | return; | 80 | return; |
81 | cache[reg] = value; | 81 | cache[reg] = value; |
82 | } | 82 | } |
83 | 83 | ||
84 | /* | 84 | /* |
85 | * write to the WM8510 register space | 85 | * write to the WM8510 register space |
86 | */ | 86 | */ |
87 | static int wm8510_write(struct snd_soc_codec *codec, unsigned int reg, | 87 | static int wm8510_write(struct snd_soc_codec *codec, unsigned int reg, |
88 | unsigned int value) | 88 | unsigned int value) |
89 | { | 89 | { |
90 | u8 data[2]; | 90 | u8 data[2]; |
91 | 91 | ||
92 | /* data is | 92 | /* data is |
93 | * D15..D9 WM8510 register offset | 93 | * D15..D9 WM8510 register offset |
94 | * D8...D0 register data | 94 | * D8...D0 register data |
95 | */ | 95 | */ |
96 | data[0] = (reg << 1) | ((value >> 8) & 0x0001); | 96 | data[0] = (reg << 1) | ((value >> 8) & 0x0001); |
97 | data[1] = value & 0x00ff; | 97 | data[1] = value & 0x00ff; |
98 | 98 | ||
99 | wm8510_write_reg_cache(codec, reg, value); | 99 | wm8510_write_reg_cache(codec, reg, value); |
100 | if (codec->hw_write(codec->control_data, data, 2) == 2) | 100 | if (codec->hw_write(codec->control_data, data, 2) == 2) |
101 | return 0; | 101 | return 0; |
102 | else | 102 | else |
103 | return -EIO; | 103 | return -EIO; |
104 | } | 104 | } |
105 | 105 | ||
106 | #define wm8510_reset(c) wm8510_write(c, WM8510_RESET, 0) | 106 | #define wm8510_reset(c) wm8510_write(c, WM8510_RESET, 0) |
107 | 107 | ||
108 | static const char *wm8510_companding[] = { "Off", "NC", "u-law", "A-law" }; | 108 | static const char *wm8510_companding[] = { "Off", "NC", "u-law", "A-law" }; |
109 | static const char *wm8510_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" }; | 109 | static const char *wm8510_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" }; |
110 | static const char *wm8510_alc[] = { "ALC", "Limiter" }; | 110 | static const char *wm8510_alc[] = { "ALC", "Limiter" }; |
111 | 111 | ||
112 | static const struct soc_enum wm8510_enum[] = { | 112 | static const struct soc_enum wm8510_enum[] = { |
113 | SOC_ENUM_SINGLE(WM8510_COMP, 1, 4, wm8510_companding), /* adc */ | 113 | SOC_ENUM_SINGLE(WM8510_COMP, 1, 4, wm8510_companding), /* adc */ |
114 | SOC_ENUM_SINGLE(WM8510_COMP, 3, 4, wm8510_companding), /* dac */ | 114 | SOC_ENUM_SINGLE(WM8510_COMP, 3, 4, wm8510_companding), /* dac */ |
115 | SOC_ENUM_SINGLE(WM8510_DAC, 4, 4, wm8510_deemp), | 115 | SOC_ENUM_SINGLE(WM8510_DAC, 4, 4, wm8510_deemp), |
116 | SOC_ENUM_SINGLE(WM8510_ALC3, 8, 2, wm8510_alc), | 116 | SOC_ENUM_SINGLE(WM8510_ALC3, 8, 2, wm8510_alc), |
117 | }; | 117 | }; |
118 | 118 | ||
119 | static const struct snd_kcontrol_new wm8510_snd_controls[] = { | 119 | static const struct snd_kcontrol_new wm8510_snd_controls[] = { |
120 | 120 | ||
121 | SOC_SINGLE("Digital Loopback Switch", WM8510_COMP, 0, 1, 0), | 121 | SOC_SINGLE("Digital Loopback Switch", WM8510_COMP, 0, 1, 0), |
122 | 122 | ||
123 | SOC_ENUM("DAC Companding", wm8510_enum[1]), | 123 | SOC_ENUM("DAC Companding", wm8510_enum[1]), |
124 | SOC_ENUM("ADC Companding", wm8510_enum[0]), | 124 | SOC_ENUM("ADC Companding", wm8510_enum[0]), |
125 | 125 | ||
126 | SOC_ENUM("Playback De-emphasis", wm8510_enum[2]), | 126 | SOC_ENUM("Playback De-emphasis", wm8510_enum[2]), |
127 | SOC_SINGLE("DAC Inversion Switch", WM8510_DAC, 0, 1, 0), | 127 | SOC_SINGLE("DAC Inversion Switch", WM8510_DAC, 0, 1, 0), |
128 | 128 | ||
129 | SOC_SINGLE("Master Playback Volume", WM8510_DACVOL, 0, 127, 0), | 129 | SOC_SINGLE("Master Playback Volume", WM8510_DACVOL, 0, 127, 0), |
130 | 130 | ||
131 | SOC_SINGLE("High Pass Filter Switch", WM8510_ADC, 8, 1, 0), | 131 | SOC_SINGLE("High Pass Filter Switch", WM8510_ADC, 8, 1, 0), |
132 | SOC_SINGLE("High Pass Cut Off", WM8510_ADC, 4, 7, 0), | 132 | SOC_SINGLE("High Pass Cut Off", WM8510_ADC, 4, 7, 0), |
133 | SOC_SINGLE("ADC Inversion Switch", WM8510_COMP, 0, 1, 0), | 133 | SOC_SINGLE("ADC Inversion Switch", WM8510_COMP, 0, 1, 0), |
134 | 134 | ||
135 | SOC_SINGLE("Capture Volume", WM8510_ADCVOL, 0, 127, 0), | 135 | SOC_SINGLE("Capture Volume", WM8510_ADCVOL, 0, 127, 0), |
136 | 136 | ||
137 | SOC_SINGLE("DAC Playback Limiter Switch", WM8510_DACLIM1, 8, 1, 0), | 137 | SOC_SINGLE("DAC Playback Limiter Switch", WM8510_DACLIM1, 8, 1, 0), |
138 | SOC_SINGLE("DAC Playback Limiter Decay", WM8510_DACLIM1, 4, 15, 0), | 138 | SOC_SINGLE("DAC Playback Limiter Decay", WM8510_DACLIM1, 4, 15, 0), |
139 | SOC_SINGLE("DAC Playback Limiter Attack", WM8510_DACLIM1, 0, 15, 0), | 139 | SOC_SINGLE("DAC Playback Limiter Attack", WM8510_DACLIM1, 0, 15, 0), |
140 | 140 | ||
141 | SOC_SINGLE("DAC Playback Limiter Threshold", WM8510_DACLIM2, 4, 7, 0), | 141 | SOC_SINGLE("DAC Playback Limiter Threshold", WM8510_DACLIM2, 4, 7, 0), |
142 | SOC_SINGLE("DAC Playback Limiter Boost", WM8510_DACLIM2, 0, 15, 0), | 142 | SOC_SINGLE("DAC Playback Limiter Boost", WM8510_DACLIM2, 0, 15, 0), |
143 | 143 | ||
144 | SOC_SINGLE("ALC Enable Switch", WM8510_ALC1, 8, 1, 0), | 144 | SOC_SINGLE("ALC Enable Switch", WM8510_ALC1, 8, 1, 0), |
145 | SOC_SINGLE("ALC Capture Max Gain", WM8510_ALC1, 3, 7, 0), | 145 | SOC_SINGLE("ALC Capture Max Gain", WM8510_ALC1, 3, 7, 0), |
146 | SOC_SINGLE("ALC Capture Min Gain", WM8510_ALC1, 0, 7, 0), | 146 | SOC_SINGLE("ALC Capture Min Gain", WM8510_ALC1, 0, 7, 0), |
147 | 147 | ||
148 | SOC_SINGLE("ALC Capture ZC Switch", WM8510_ALC2, 8, 1, 0), | 148 | SOC_SINGLE("ALC Capture ZC Switch", WM8510_ALC2, 8, 1, 0), |
149 | SOC_SINGLE("ALC Capture Hold", WM8510_ALC2, 4, 7, 0), | 149 | SOC_SINGLE("ALC Capture Hold", WM8510_ALC2, 4, 7, 0), |
150 | SOC_SINGLE("ALC Capture Target", WM8510_ALC2, 0, 15, 0), | 150 | SOC_SINGLE("ALC Capture Target", WM8510_ALC2, 0, 15, 0), |
151 | 151 | ||
152 | SOC_ENUM("ALC Capture Mode", wm8510_enum[3]), | 152 | SOC_ENUM("ALC Capture Mode", wm8510_enum[3]), |
153 | SOC_SINGLE("ALC Capture Decay", WM8510_ALC3, 4, 15, 0), | 153 | SOC_SINGLE("ALC Capture Decay", WM8510_ALC3, 4, 15, 0), |
154 | SOC_SINGLE("ALC Capture Attack", WM8510_ALC3, 0, 15, 0), | 154 | SOC_SINGLE("ALC Capture Attack", WM8510_ALC3, 0, 15, 0), |
155 | 155 | ||
156 | SOC_SINGLE("ALC Capture Noise Gate Switch", WM8510_NGATE, 3, 1, 0), | 156 | SOC_SINGLE("ALC Capture Noise Gate Switch", WM8510_NGATE, 3, 1, 0), |
157 | SOC_SINGLE("ALC Capture Noise Gate Threshold", WM8510_NGATE, 0, 7, 0), | 157 | SOC_SINGLE("ALC Capture Noise Gate Threshold", WM8510_NGATE, 0, 7, 0), |
158 | 158 | ||
159 | SOC_SINGLE("Capture PGA ZC Switch", WM8510_INPPGA, 7, 1, 0), | 159 | SOC_SINGLE("Capture PGA ZC Switch", WM8510_INPPGA, 7, 1, 0), |
160 | SOC_SINGLE("Capture PGA Volume", WM8510_INPPGA, 0, 63, 0), | 160 | SOC_SINGLE("Capture PGA Volume", WM8510_INPPGA, 0, 63, 0), |
161 | 161 | ||
162 | SOC_SINGLE("Speaker Playback ZC Switch", WM8510_SPKVOL, 7, 1, 0), | 162 | SOC_SINGLE("Speaker Playback ZC Switch", WM8510_SPKVOL, 7, 1, 0), |
163 | SOC_SINGLE("Speaker Playback Switch", WM8510_SPKVOL, 6, 1, 1), | 163 | SOC_SINGLE("Speaker Playback Switch", WM8510_SPKVOL, 6, 1, 1), |
164 | SOC_SINGLE("Speaker Playback Volume", WM8510_SPKVOL, 0, 63, 0), | 164 | SOC_SINGLE("Speaker Playback Volume", WM8510_SPKVOL, 0, 63, 0), |
165 | SOC_SINGLE("Speaker Boost", WM8510_OUTPUT, 2, 1, 0), | 165 | SOC_SINGLE("Speaker Boost", WM8510_OUTPUT, 2, 1, 0), |
166 | 166 | ||
167 | SOC_SINGLE("Capture Boost(+20dB)", WM8510_ADCBOOST, 8, 1, 0), | 167 | SOC_SINGLE("Capture Boost(+20dB)", WM8510_ADCBOOST, 8, 1, 0), |
168 | SOC_SINGLE("Mono Playback Switch", WM8510_MONOMIX, 6, 1, 1), | 168 | SOC_SINGLE("Mono Playback Switch", WM8510_MONOMIX, 6, 1, 1), |
169 | }; | 169 | }; |
170 | 170 | ||
171 | /* add non dapm controls */ | 171 | /* add non dapm controls */ |
172 | static int wm8510_add_controls(struct snd_soc_codec *codec) | 172 | static int wm8510_add_controls(struct snd_soc_codec *codec) |
173 | { | 173 | { |
174 | int err, i; | 174 | int err, i; |
175 | 175 | ||
176 | for (i = 0; i < ARRAY_SIZE(wm8510_snd_controls); i++) { | 176 | for (i = 0; i < ARRAY_SIZE(wm8510_snd_controls); i++) { |
177 | err = snd_ctl_add(codec->card, | 177 | err = snd_ctl_add(codec->card, |
178 | snd_soc_cnew(&wm8510_snd_controls[i], codec, | 178 | snd_soc_cnew(&wm8510_snd_controls[i], codec, |
179 | NULL)); | 179 | NULL)); |
180 | if (err < 0) | 180 | if (err < 0) |
181 | return err; | 181 | return err; |
182 | } | 182 | } |
183 | 183 | ||
184 | return 0; | 184 | return 0; |
185 | } | 185 | } |
186 | 186 | ||
187 | /* Speaker Output Mixer */ | 187 | /* Speaker Output Mixer */ |
188 | static const struct snd_kcontrol_new wm8510_speaker_mixer_controls[] = { | 188 | static const struct snd_kcontrol_new wm8510_speaker_mixer_controls[] = { |
189 | SOC_DAPM_SINGLE("Line Bypass Switch", WM8510_SPKMIX, 1, 1, 0), | 189 | SOC_DAPM_SINGLE("Line Bypass Switch", WM8510_SPKMIX, 1, 1, 0), |
190 | SOC_DAPM_SINGLE("Aux Playback Switch", WM8510_SPKMIX, 5, 1, 0), | 190 | SOC_DAPM_SINGLE("Aux Playback Switch", WM8510_SPKMIX, 5, 1, 0), |
191 | SOC_DAPM_SINGLE("PCM Playback Switch", WM8510_SPKMIX, 0, 1, 0), | 191 | SOC_DAPM_SINGLE("PCM Playback Switch", WM8510_SPKMIX, 0, 1, 0), |
192 | }; | 192 | }; |
193 | 193 | ||
194 | /* Mono Output Mixer */ | 194 | /* Mono Output Mixer */ |
195 | static const struct snd_kcontrol_new wm8510_mono_mixer_controls[] = { | 195 | static const struct snd_kcontrol_new wm8510_mono_mixer_controls[] = { |
196 | SOC_DAPM_SINGLE("Line Bypass Switch", WM8510_MONOMIX, 1, 1, 0), | 196 | SOC_DAPM_SINGLE("Line Bypass Switch", WM8510_MONOMIX, 1, 1, 0), |
197 | SOC_DAPM_SINGLE("Aux Playback Switch", WM8510_MONOMIX, 2, 1, 0), | 197 | SOC_DAPM_SINGLE("Aux Playback Switch", WM8510_MONOMIX, 2, 1, 0), |
198 | SOC_DAPM_SINGLE("PCM Playback Switch", WM8510_MONOMIX, 0, 1, 0), | 198 | SOC_DAPM_SINGLE("PCM Playback Switch", WM8510_MONOMIX, 0, 1, 0), |
199 | }; | 199 | }; |
200 | 200 | ||
201 | static const struct snd_kcontrol_new wm8510_boost_controls[] = { | 201 | static const struct snd_kcontrol_new wm8510_boost_controls[] = { |
202 | SOC_DAPM_SINGLE("Mic PGA Switch", WM8510_INPPGA, 6, 1, 0), | 202 | SOC_DAPM_SINGLE("Mic PGA Switch", WM8510_INPPGA, 6, 1, 0), |
203 | SOC_DAPM_SINGLE("Aux Volume", WM8510_ADCBOOST, 0, 7, 0), | 203 | SOC_DAPM_SINGLE("Aux Volume", WM8510_ADCBOOST, 0, 7, 0), |
204 | SOC_DAPM_SINGLE("Mic Volume", WM8510_ADCBOOST, 4, 7, 0), | 204 | SOC_DAPM_SINGLE("Mic Volume", WM8510_ADCBOOST, 4, 7, 0), |
205 | }; | 205 | }; |
206 | 206 | ||
207 | static const struct snd_kcontrol_new wm8510_micpga_controls[] = { | 207 | static const struct snd_kcontrol_new wm8510_micpga_controls[] = { |
208 | SOC_DAPM_SINGLE("MICP Switch", WM8510_INPUT, 0, 1, 0), | 208 | SOC_DAPM_SINGLE("MICP Switch", WM8510_INPUT, 0, 1, 0), |
209 | SOC_DAPM_SINGLE("MICN Switch", WM8510_INPUT, 1, 1, 0), | 209 | SOC_DAPM_SINGLE("MICN Switch", WM8510_INPUT, 1, 1, 0), |
210 | SOC_DAPM_SINGLE("AUX Switch", WM8510_INPUT, 2, 1, 0), | 210 | SOC_DAPM_SINGLE("AUX Switch", WM8510_INPUT, 2, 1, 0), |
211 | }; | 211 | }; |
212 | 212 | ||
213 | static const struct snd_soc_dapm_widget wm8510_dapm_widgets[] = { | 213 | static const struct snd_soc_dapm_widget wm8510_dapm_widgets[] = { |
214 | SND_SOC_DAPM_MIXER("Speaker Mixer", WM8510_POWER3, 2, 0, | 214 | SND_SOC_DAPM_MIXER("Speaker Mixer", WM8510_POWER3, 2, 0, |
215 | &wm8510_speaker_mixer_controls[0], | 215 | &wm8510_speaker_mixer_controls[0], |
216 | ARRAY_SIZE(wm8510_speaker_mixer_controls)), | 216 | ARRAY_SIZE(wm8510_speaker_mixer_controls)), |
217 | SND_SOC_DAPM_MIXER("Mono Mixer", WM8510_POWER3, 3, 0, | 217 | SND_SOC_DAPM_MIXER("Mono Mixer", WM8510_POWER3, 3, 0, |
218 | &wm8510_mono_mixer_controls[0], | 218 | &wm8510_mono_mixer_controls[0], |
219 | ARRAY_SIZE(wm8510_mono_mixer_controls)), | 219 | ARRAY_SIZE(wm8510_mono_mixer_controls)), |
220 | SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8510_POWER3, 0, 0), | 220 | SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8510_POWER3, 0, 0), |
221 | SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8510_POWER2, 0, 0), | 221 | SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8510_POWER2, 0, 0), |
222 | SND_SOC_DAPM_PGA("Aux Input", WM8510_POWER1, 6, 0, NULL, 0), | 222 | SND_SOC_DAPM_PGA("Aux Input", WM8510_POWER1, 6, 0, NULL, 0), |
223 | SND_SOC_DAPM_PGA("SpkN Out", WM8510_POWER3, 5, 0, NULL, 0), | 223 | SND_SOC_DAPM_PGA("SpkN Out", WM8510_POWER3, 5, 0, NULL, 0), |
224 | SND_SOC_DAPM_PGA("SpkP Out", WM8510_POWER3, 6, 0, NULL, 0), | 224 | SND_SOC_DAPM_PGA("SpkP Out", WM8510_POWER3, 6, 0, NULL, 0), |
225 | SND_SOC_DAPM_PGA("Mono Out", WM8510_POWER3, 7, 0, NULL, 0), | 225 | SND_SOC_DAPM_PGA("Mono Out", WM8510_POWER3, 7, 0, NULL, 0), |
226 | 226 | ||
227 | SND_SOC_DAPM_PGA("Mic PGA", WM8510_POWER2, 2, 0, | 227 | SND_SOC_DAPM_PGA("Mic PGA", WM8510_POWER2, 2, 0, |
228 | &wm8510_micpga_controls[0], | 228 | &wm8510_micpga_controls[0], |
229 | ARRAY_SIZE(wm8510_micpga_controls)), | 229 | ARRAY_SIZE(wm8510_micpga_controls)), |
230 | SND_SOC_DAPM_MIXER("Boost Mixer", WM8510_POWER2, 4, 0, | 230 | SND_SOC_DAPM_MIXER("Boost Mixer", WM8510_POWER2, 4, 0, |
231 | &wm8510_boost_controls[0], | 231 | &wm8510_boost_controls[0], |
232 | ARRAY_SIZE(wm8510_boost_controls)), | 232 | ARRAY_SIZE(wm8510_boost_controls)), |
233 | 233 | ||
234 | SND_SOC_DAPM_MICBIAS("Mic Bias", WM8510_POWER1, 4, 0), | 234 | SND_SOC_DAPM_MICBIAS("Mic Bias", WM8510_POWER1, 4, 0), |
235 | 235 | ||
236 | SND_SOC_DAPM_INPUT("MICN"), | 236 | SND_SOC_DAPM_INPUT("MICN"), |
237 | SND_SOC_DAPM_INPUT("MICP"), | 237 | SND_SOC_DAPM_INPUT("MICP"), |
238 | SND_SOC_DAPM_INPUT("AUX"), | 238 | SND_SOC_DAPM_INPUT("AUX"), |
239 | SND_SOC_DAPM_OUTPUT("MONOOUT"), | 239 | SND_SOC_DAPM_OUTPUT("MONOOUT"), |
240 | SND_SOC_DAPM_OUTPUT("SPKOUTP"), | 240 | SND_SOC_DAPM_OUTPUT("SPKOUTP"), |
241 | SND_SOC_DAPM_OUTPUT("SPKOUTN"), | 241 | SND_SOC_DAPM_OUTPUT("SPKOUTN"), |
242 | }; | 242 | }; |
243 | 243 | ||
244 | static const struct snd_soc_dapm_route audio_map[] = { | 244 | static const struct snd_soc_dapm_route audio_map[] = { |
245 | /* Mono output mixer */ | 245 | /* Mono output mixer */ |
246 | {"Mono Mixer", "PCM Playback Switch", "DAC"}, | 246 | {"Mono Mixer", "PCM Playback Switch", "DAC"}, |
247 | {"Mono Mixer", "Aux Playback Switch", "Aux Input"}, | 247 | {"Mono Mixer", "Aux Playback Switch", "Aux Input"}, |
248 | {"Mono Mixer", "Line Bypass Switch", "Boost Mixer"}, | 248 | {"Mono Mixer", "Line Bypass Switch", "Boost Mixer"}, |
249 | 249 | ||
250 | /* Speaker output mixer */ | 250 | /* Speaker output mixer */ |
251 | {"Speaker Mixer", "PCM Playback Switch", "DAC"}, | 251 | {"Speaker Mixer", "PCM Playback Switch", "DAC"}, |
252 | {"Speaker Mixer", "Aux Playback Switch", "Aux Input"}, | 252 | {"Speaker Mixer", "Aux Playback Switch", "Aux Input"}, |
253 | {"Speaker Mixer", "Line Bypass Switch", "Boost Mixer"}, | 253 | {"Speaker Mixer", "Line Bypass Switch", "Boost Mixer"}, |
254 | 254 | ||
255 | /* Outputs */ | 255 | /* Outputs */ |
256 | {"Mono Out", NULL, "Mono Mixer"}, | 256 | {"Mono Out", NULL, "Mono Mixer"}, |
257 | {"MONOOUT", NULL, "Mono Out"}, | 257 | {"MONOOUT", NULL, "Mono Out"}, |
258 | {"SpkN Out", NULL, "Speaker Mixer"}, | 258 | {"SpkN Out", NULL, "Speaker Mixer"}, |
259 | {"SpkP Out", NULL, "Speaker Mixer"}, | 259 | {"SpkP Out", NULL, "Speaker Mixer"}, |
260 | {"SPKOUTN", NULL, "SpkN Out"}, | 260 | {"SPKOUTN", NULL, "SpkN Out"}, |
261 | {"SPKOUTP", NULL, "SpkP Out"}, | 261 | {"SPKOUTP", NULL, "SpkP Out"}, |
262 | 262 | ||
263 | /* Microphone PGA */ | 263 | /* Microphone PGA */ |
264 | {"Mic PGA", "MICN Switch", "MICN"}, | 264 | {"Mic PGA", "MICN Switch", "MICN"}, |
265 | {"Mic PGA", "MICP Switch", "MICP"}, | 265 | {"Mic PGA", "MICP Switch", "MICP"}, |
266 | { "Mic PGA", "AUX Switch", "Aux Input" }, | 266 | { "Mic PGA", "AUX Switch", "Aux Input" }, |
267 | 267 | ||
268 | /* Boost Mixer */ | 268 | /* Boost Mixer */ |
269 | {"Boost Mixer", "Mic PGA Switch", "Mic PGA"}, | 269 | {"Boost Mixer", "Mic PGA Switch", "Mic PGA"}, |
270 | {"Boost Mixer", "Mic Volume", "MICP"}, | 270 | {"Boost Mixer", "Mic Volume", "MICP"}, |
271 | {"Boost Mixer", "Aux Volume", "Aux Input"}, | 271 | {"Boost Mixer", "Aux Volume", "Aux Input"}, |
272 | 272 | ||
273 | {"ADC", NULL, "Boost Mixer"}, | 273 | {"ADC", NULL, "Boost Mixer"}, |
274 | }; | 274 | }; |
275 | 275 | ||
276 | static int wm8510_add_widgets(struct snd_soc_codec *codec) | 276 | static int wm8510_add_widgets(struct snd_soc_codec *codec) |
277 | { | 277 | { |
278 | snd_soc_dapm_new_controls(codec, wm8510_dapm_widgets, | 278 | snd_soc_dapm_new_controls(codec, wm8510_dapm_widgets, |
279 | ARRAY_SIZE(wm8510_dapm_widgets)); | 279 | ARRAY_SIZE(wm8510_dapm_widgets)); |
280 | 280 | ||
281 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | 281 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
282 | 282 | ||
283 | snd_soc_dapm_new_widgets(codec); | 283 | snd_soc_dapm_new_widgets(codec); |
284 | return 0; | 284 | return 0; |
285 | } | 285 | } |
286 | 286 | ||
287 | struct pll_ { | 287 | struct pll_ { |
288 | unsigned int pre_div:4; /* prescale - 1 */ | 288 | unsigned int pre_div:4; /* prescale - 1 */ |
289 | unsigned int n:4; | 289 | unsigned int n:4; |
290 | unsigned int k; | 290 | unsigned int k; |
291 | }; | 291 | }; |
292 | 292 | ||
293 | static struct pll_ pll_div; | 293 | static struct pll_ pll_div; |
294 | 294 | ||
295 | /* The size in bits of the pll divide multiplied by 10 | 295 | /* The size in bits of the pll divide multiplied by 10 |
296 | * to allow rounding later */ | 296 | * to allow rounding later */ |
297 | #define FIXED_PLL_SIZE ((1 << 24) * 10) | 297 | #define FIXED_PLL_SIZE ((1 << 24) * 10) |
298 | 298 | ||
299 | static void pll_factors(unsigned int target, unsigned int source) | 299 | static void pll_factors(unsigned int target, unsigned int source) |
300 | { | 300 | { |
301 | unsigned long long Kpart; | 301 | unsigned long long Kpart; |
302 | unsigned int K, Ndiv, Nmod; | 302 | unsigned int K, Ndiv, Nmod; |
303 | 303 | ||
304 | Ndiv = target / source; | 304 | Ndiv = target / source; |
305 | if (Ndiv < 6) { | 305 | if (Ndiv < 6) { |
306 | source >>= 1; | 306 | source >>= 1; |
307 | pll_div.pre_div = 1; | 307 | pll_div.pre_div = 1; |
308 | Ndiv = target / source; | 308 | Ndiv = target / source; |
309 | } else | 309 | } else |
310 | pll_div.pre_div = 0; | 310 | pll_div.pre_div = 0; |
311 | 311 | ||
312 | if ((Ndiv < 6) || (Ndiv > 12)) | 312 | if ((Ndiv < 6) || (Ndiv > 12)) |
313 | printk(KERN_WARNING | 313 | printk(KERN_WARNING |
314 | "WM8510 N value %d outwith recommended range!d\n", | 314 | "WM8510 N value %d outwith recommended range!d\n", |
315 | Ndiv); | 315 | Ndiv); |
316 | 316 | ||
317 | pll_div.n = Ndiv; | 317 | pll_div.n = Ndiv; |
318 | Nmod = target % source; | 318 | Nmod = target % source; |
319 | Kpart = FIXED_PLL_SIZE * (long long)Nmod; | 319 | Kpart = FIXED_PLL_SIZE * (long long)Nmod; |
320 | 320 | ||
321 | do_div(Kpart, source); | 321 | do_div(Kpart, source); |
322 | 322 | ||
323 | K = Kpart & 0xFFFFFFFF; | 323 | K = Kpart & 0xFFFFFFFF; |
324 | 324 | ||
325 | /* Check if we need to round */ | 325 | /* Check if we need to round */ |
326 | if ((K % 10) >= 5) | 326 | if ((K % 10) >= 5) |
327 | K += 5; | 327 | K += 5; |
328 | 328 | ||
329 | /* Move down to proper range now rounding is done */ | 329 | /* Move down to proper range now rounding is done */ |
330 | K /= 10; | 330 | K /= 10; |
331 | 331 | ||
332 | pll_div.k = K; | 332 | pll_div.k = K; |
333 | } | 333 | } |
334 | 334 | ||
335 | static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai, | 335 | static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai, |
336 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 336 | int pll_id, unsigned int freq_in, unsigned int freq_out) |
337 | { | 337 | { |
338 | struct snd_soc_codec *codec = codec_dai->codec; | 338 | struct snd_soc_codec *codec = codec_dai->codec; |
339 | u16 reg; | 339 | u16 reg; |
340 | 340 | ||
341 | if (freq_in == 0 || freq_out == 0) { | 341 | if (freq_in == 0 || freq_out == 0) { |
342 | /* Clock CODEC directly from MCLK */ | 342 | /* Clock CODEC directly from MCLK */ |
343 | reg = wm8510_read_reg_cache(codec, WM8510_CLOCK); | 343 | reg = wm8510_read_reg_cache(codec, WM8510_CLOCK); |
344 | wm8510_write(codec, WM8510_CLOCK, reg & 0x0ff); | 344 | wm8510_write(codec, WM8510_CLOCK, reg & 0x0ff); |
345 | 345 | ||
346 | /* Turn off PLL */ | 346 | /* Turn off PLL */ |
347 | reg = wm8510_read_reg_cache(codec, WM8510_POWER1); | 347 | reg = wm8510_read_reg_cache(codec, WM8510_POWER1); |
348 | wm8510_write(codec, WM8510_POWER1, reg & 0x1df); | 348 | wm8510_write(codec, WM8510_POWER1, reg & 0x1df); |
349 | return 0; | 349 | return 0; |
350 | } | 350 | } |
351 | 351 | ||
352 | pll_factors(freq_out*8, freq_in); | 352 | pll_factors(freq_out*8, freq_in); |
353 | 353 | ||
354 | wm8510_write(codec, WM8510_PLLN, (pll_div.pre_div << 4) | pll_div.n); | 354 | wm8510_write(codec, WM8510_PLLN, (pll_div.pre_div << 4) | pll_div.n); |
355 | wm8510_write(codec, WM8510_PLLK1, pll_div.k >> 18); | 355 | wm8510_write(codec, WM8510_PLLK1, pll_div.k >> 18); |
356 | wm8510_write(codec, WM8510_PLLK2, (pll_div.k >> 9) & 0x1ff); | 356 | wm8510_write(codec, WM8510_PLLK2, (pll_div.k >> 9) & 0x1ff); |
357 | wm8510_write(codec, WM8510_PLLK3, pll_div.k & 0x1ff); | 357 | wm8510_write(codec, WM8510_PLLK3, pll_div.k & 0x1ff); |
358 | reg = wm8510_read_reg_cache(codec, WM8510_POWER1); | 358 | reg = wm8510_read_reg_cache(codec, WM8510_POWER1); |
359 | wm8510_write(codec, WM8510_POWER1, reg | 0x020); | 359 | wm8510_write(codec, WM8510_POWER1, reg | 0x020); |
360 | 360 | ||
361 | /* Run CODEC from PLL instead of MCLK */ | 361 | /* Run CODEC from PLL instead of MCLK */ |
362 | reg = wm8510_read_reg_cache(codec, WM8510_CLOCK); | 362 | reg = wm8510_read_reg_cache(codec, WM8510_CLOCK); |
363 | wm8510_write(codec, WM8510_CLOCK, reg | 0x100); | 363 | wm8510_write(codec, WM8510_CLOCK, reg | 0x100); |
364 | 364 | ||
365 | return 0; | 365 | return 0; |
366 | } | 366 | } |
367 | 367 | ||
368 | /* | 368 | /* |
369 | * Configure WM8510 clock dividers. | 369 | * Configure WM8510 clock dividers. |
370 | */ | 370 | */ |
371 | static int wm8510_set_dai_clkdiv(struct snd_soc_dai *codec_dai, | 371 | static int wm8510_set_dai_clkdiv(struct snd_soc_dai *codec_dai, |
372 | int div_id, int div) | 372 | int div_id, int div) |
373 | { | 373 | { |
374 | struct snd_soc_codec *codec = codec_dai->codec; | 374 | struct snd_soc_codec *codec = codec_dai->codec; |
375 | u16 reg; | 375 | u16 reg; |
376 | 376 | ||
377 | switch (div_id) { | 377 | switch (div_id) { |
378 | case WM8510_OPCLKDIV: | 378 | case WM8510_OPCLKDIV: |
379 | reg = wm8510_read_reg_cache(codec, WM8510_GPIO) & 0x1cf; | 379 | reg = wm8510_read_reg_cache(codec, WM8510_GPIO) & 0x1cf; |
380 | wm8510_write(codec, WM8510_GPIO, reg | div); | 380 | wm8510_write(codec, WM8510_GPIO, reg | div); |
381 | break; | 381 | break; |
382 | case WM8510_MCLKDIV: | 382 | case WM8510_MCLKDIV: |
383 | reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1f; | 383 | reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1f; |
384 | wm8510_write(codec, WM8510_CLOCK, reg | div); | 384 | wm8510_write(codec, WM8510_CLOCK, reg | div); |
385 | break; | 385 | break; |
386 | case WM8510_ADCCLK: | 386 | case WM8510_ADCCLK: |
387 | reg = wm8510_read_reg_cache(codec, WM8510_ADC) & 0x1f7; | 387 | reg = wm8510_read_reg_cache(codec, WM8510_ADC) & 0x1f7; |
388 | wm8510_write(codec, WM8510_ADC, reg | div); | 388 | wm8510_write(codec, WM8510_ADC, reg | div); |
389 | break; | 389 | break; |
390 | case WM8510_DACCLK: | 390 | case WM8510_DACCLK: |
391 | reg = wm8510_read_reg_cache(codec, WM8510_DAC) & 0x1f7; | 391 | reg = wm8510_read_reg_cache(codec, WM8510_DAC) & 0x1f7; |
392 | wm8510_write(codec, WM8510_DAC, reg | div); | 392 | wm8510_write(codec, WM8510_DAC, reg | div); |
393 | break; | 393 | break; |
394 | case WM8510_BCLKDIV: | 394 | case WM8510_BCLKDIV: |
395 | reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1e3; | 395 | reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1e3; |
396 | wm8510_write(codec, WM8510_CLOCK, reg | div); | 396 | wm8510_write(codec, WM8510_CLOCK, reg | div); |
397 | break; | 397 | break; |
398 | default: | 398 | default: |
399 | return -EINVAL; | 399 | return -EINVAL; |
400 | } | 400 | } |
401 | 401 | ||
402 | return 0; | 402 | return 0; |
403 | } | 403 | } |
404 | 404 | ||
405 | static int wm8510_set_dai_fmt(struct snd_soc_dai *codec_dai, | 405 | static int wm8510_set_dai_fmt(struct snd_soc_dai *codec_dai, |
406 | unsigned int fmt) | 406 | unsigned int fmt) |
407 | { | 407 | { |
408 | struct snd_soc_codec *codec = codec_dai->codec; | 408 | struct snd_soc_codec *codec = codec_dai->codec; |
409 | u16 iface = 0; | 409 | u16 iface = 0; |
410 | u16 clk = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1fe; | 410 | u16 clk = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1fe; |
411 | 411 | ||
412 | /* set master/slave audio interface */ | 412 | /* set master/slave audio interface */ |
413 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 413 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
414 | case SND_SOC_DAIFMT_CBM_CFM: | 414 | case SND_SOC_DAIFMT_CBM_CFM: |
415 | clk |= 0x0001; | 415 | clk |= 0x0001; |
416 | break; | 416 | break; |
417 | case SND_SOC_DAIFMT_CBS_CFS: | 417 | case SND_SOC_DAIFMT_CBS_CFS: |
418 | break; | 418 | break; |
419 | default: | 419 | default: |
420 | return -EINVAL; | 420 | return -EINVAL; |
421 | } | 421 | } |
422 | 422 | ||
423 | /* interface format */ | 423 | /* interface format */ |
424 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 424 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
425 | case SND_SOC_DAIFMT_I2S: | 425 | case SND_SOC_DAIFMT_I2S: |
426 | iface |= 0x0010; | 426 | iface |= 0x0010; |
427 | break; | 427 | break; |
428 | case SND_SOC_DAIFMT_RIGHT_J: | 428 | case SND_SOC_DAIFMT_RIGHT_J: |
429 | break; | 429 | break; |
430 | case SND_SOC_DAIFMT_LEFT_J: | 430 | case SND_SOC_DAIFMT_LEFT_J: |
431 | iface |= 0x0008; | 431 | iface |= 0x0008; |
432 | break; | 432 | break; |
433 | case SND_SOC_DAIFMT_DSP_A: | 433 | case SND_SOC_DAIFMT_DSP_A: |
434 | iface |= 0x00018; | 434 | iface |= 0x00018; |
435 | break; | 435 | break; |
436 | default: | 436 | default: |
437 | return -EINVAL; | 437 | return -EINVAL; |
438 | } | 438 | } |
439 | 439 | ||
440 | /* clock inversion */ | 440 | /* clock inversion */ |
441 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | 441 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
442 | case SND_SOC_DAIFMT_NB_NF: | 442 | case SND_SOC_DAIFMT_NB_NF: |
443 | break; | 443 | break; |
444 | case SND_SOC_DAIFMT_IB_IF: | 444 | case SND_SOC_DAIFMT_IB_IF: |
445 | iface |= 0x0180; | 445 | iface |= 0x0180; |
446 | break; | 446 | break; |
447 | case SND_SOC_DAIFMT_IB_NF: | 447 | case SND_SOC_DAIFMT_IB_NF: |
448 | iface |= 0x0100; | 448 | iface |= 0x0100; |
449 | break; | 449 | break; |
450 | case SND_SOC_DAIFMT_NB_IF: | 450 | case SND_SOC_DAIFMT_NB_IF: |
451 | iface |= 0x0080; | 451 | iface |= 0x0080; |
452 | break; | 452 | break; |
453 | default: | 453 | default: |
454 | return -EINVAL; | 454 | return -EINVAL; |
455 | } | 455 | } |
456 | 456 | ||
457 | wm8510_write(codec, WM8510_IFACE, iface); | 457 | wm8510_write(codec, WM8510_IFACE, iface); |
458 | wm8510_write(codec, WM8510_CLOCK, clk); | 458 | wm8510_write(codec, WM8510_CLOCK, clk); |
459 | return 0; | 459 | return 0; |
460 | } | 460 | } |
461 | 461 | ||
462 | static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream, | 462 | static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream, |
463 | struct snd_pcm_hw_params *params) | 463 | struct snd_pcm_hw_params *params) |
464 | { | 464 | { |
465 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 465 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
466 | struct snd_soc_device *socdev = rtd->socdev; | 466 | struct snd_soc_device *socdev = rtd->socdev; |
467 | struct snd_soc_codec *codec = socdev->codec; | 467 | struct snd_soc_codec *codec = socdev->codec; |
468 | u16 iface = wm8510_read_reg_cache(codec, WM8510_IFACE) & 0x19f; | 468 | u16 iface = wm8510_read_reg_cache(codec, WM8510_IFACE) & 0x19f; |
469 | u16 adn = wm8510_read_reg_cache(codec, WM8510_ADD) & 0x1f1; | 469 | u16 adn = wm8510_read_reg_cache(codec, WM8510_ADD) & 0x1f1; |
470 | 470 | ||
471 | /* bit size */ | 471 | /* bit size */ |
472 | switch (params_format(params)) { | 472 | switch (params_format(params)) { |
473 | case SNDRV_PCM_FORMAT_S16_LE: | 473 | case SNDRV_PCM_FORMAT_S16_LE: |
474 | break; | 474 | break; |
475 | case SNDRV_PCM_FORMAT_S20_3LE: | 475 | case SNDRV_PCM_FORMAT_S20_3LE: |
476 | iface |= 0x0020; | 476 | iface |= 0x0020; |
477 | break; | 477 | break; |
478 | case SNDRV_PCM_FORMAT_S24_LE: | 478 | case SNDRV_PCM_FORMAT_S24_LE: |
479 | iface |= 0x0040; | 479 | iface |= 0x0040; |
480 | break; | 480 | break; |
481 | case SNDRV_PCM_FORMAT_S32_LE: | 481 | case SNDRV_PCM_FORMAT_S32_LE: |
482 | iface |= 0x0060; | 482 | iface |= 0x0060; |
483 | break; | 483 | break; |
484 | } | 484 | } |
485 | 485 | ||
486 | /* filter coefficient */ | 486 | /* filter coefficient */ |
487 | switch (params_rate(params)) { | 487 | switch (params_rate(params)) { |
488 | case SNDRV_PCM_RATE_8000: | 488 | case SNDRV_PCM_RATE_8000: |
489 | adn |= 0x5 << 1; | 489 | adn |= 0x5 << 1; |
490 | break; | 490 | break; |
491 | case SNDRV_PCM_RATE_11025: | 491 | case SNDRV_PCM_RATE_11025: |
492 | adn |= 0x4 << 1; | 492 | adn |= 0x4 << 1; |
493 | break; | 493 | break; |
494 | case SNDRV_PCM_RATE_16000: | 494 | case SNDRV_PCM_RATE_16000: |
495 | adn |= 0x3 << 1; | 495 | adn |= 0x3 << 1; |
496 | break; | 496 | break; |
497 | case SNDRV_PCM_RATE_22050: | 497 | case SNDRV_PCM_RATE_22050: |
498 | adn |= 0x2 << 1; | 498 | adn |= 0x2 << 1; |
499 | break; | 499 | break; |
500 | case SNDRV_PCM_RATE_32000: | 500 | case SNDRV_PCM_RATE_32000: |
501 | adn |= 0x1 << 1; | 501 | adn |= 0x1 << 1; |
502 | break; | 502 | break; |
503 | case SNDRV_PCM_RATE_44100: | 503 | case SNDRV_PCM_RATE_44100: |
504 | case SNDRV_PCM_RATE_48000: | 504 | case SNDRV_PCM_RATE_48000: |
505 | break; | 505 | break; |
506 | } | 506 | } |
507 | 507 | ||
508 | wm8510_write(codec, WM8510_IFACE, iface); | 508 | wm8510_write(codec, WM8510_IFACE, iface); |
509 | wm8510_write(codec, WM8510_ADD, adn); | 509 | wm8510_write(codec, WM8510_ADD, adn); |
510 | return 0; | 510 | return 0; |
511 | } | 511 | } |
512 | 512 | ||
513 | static int wm8510_mute(struct snd_soc_dai *dai, int mute) | 513 | static int wm8510_mute(struct snd_soc_dai *dai, int mute) |
514 | { | 514 | { |
515 | struct snd_soc_codec *codec = dai->codec; | 515 | struct snd_soc_codec *codec = dai->codec; |
516 | u16 mute_reg = wm8510_read_reg_cache(codec, WM8510_DAC) & 0xffbf; | 516 | u16 mute_reg = wm8510_read_reg_cache(codec, WM8510_DAC) & 0xffbf; |
517 | 517 | ||
518 | if (mute) | 518 | if (mute) |
519 | wm8510_write(codec, WM8510_DAC, mute_reg | 0x40); | 519 | wm8510_write(codec, WM8510_DAC, mute_reg | 0x40); |
520 | else | 520 | else |
521 | wm8510_write(codec, WM8510_DAC, mute_reg); | 521 | wm8510_write(codec, WM8510_DAC, mute_reg); |
522 | return 0; | 522 | return 0; |
523 | } | 523 | } |
524 | 524 | ||
525 | /* liam need to make this lower power with dapm */ | 525 | /* liam need to make this lower power with dapm */ |
526 | static int wm8510_set_bias_level(struct snd_soc_codec *codec, | 526 | static int wm8510_set_bias_level(struct snd_soc_codec *codec, |
527 | enum snd_soc_bias_level level) | 527 | enum snd_soc_bias_level level) |
528 | { | 528 | { |
529 | 529 | ||
530 | switch (level) { | 530 | switch (level) { |
531 | case SND_SOC_BIAS_ON: | 531 | case SND_SOC_BIAS_ON: |
532 | wm8510_write(codec, WM8510_POWER1, 0x1ff); | 532 | wm8510_write(codec, WM8510_POWER1, 0x1ff); |
533 | wm8510_write(codec, WM8510_POWER2, 0x1ff); | 533 | wm8510_write(codec, WM8510_POWER2, 0x1ff); |
534 | wm8510_write(codec, WM8510_POWER3, 0x1ff); | 534 | wm8510_write(codec, WM8510_POWER3, 0x1ff); |
535 | break; | 535 | break; |
536 | case SND_SOC_BIAS_PREPARE: | 536 | case SND_SOC_BIAS_PREPARE: |
537 | case SND_SOC_BIAS_STANDBY: | 537 | case SND_SOC_BIAS_STANDBY: |
538 | break; | 538 | break; |
539 | case SND_SOC_BIAS_OFF: | 539 | case SND_SOC_BIAS_OFF: |
540 | /* everything off, dac mute, inactive */ | 540 | /* everything off, dac mute, inactive */ |
541 | wm8510_write(codec, WM8510_POWER1, 0x0); | 541 | wm8510_write(codec, WM8510_POWER1, 0x0); |
542 | wm8510_write(codec, WM8510_POWER2, 0x0); | 542 | wm8510_write(codec, WM8510_POWER2, 0x0); |
543 | wm8510_write(codec, WM8510_POWER3, 0x0); | 543 | wm8510_write(codec, WM8510_POWER3, 0x0); |
544 | break; | 544 | break; |
545 | } | 545 | } |
546 | codec->bias_level = level; | 546 | codec->bias_level = level; |
547 | return 0; | 547 | return 0; |
548 | } | 548 | } |
549 | 549 | ||
550 | #define WM8510_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | 550 | #define WM8510_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ |
551 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ | 551 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ |
552 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) | 552 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) |
553 | 553 | ||
554 | #define WM8510_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | 554 | #define WM8510_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
555 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | 555 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) |
556 | 556 | ||
557 | struct snd_soc_dai wm8510_dai = { | 557 | struct snd_soc_dai wm8510_dai = { |
558 | .name = "WM8510 HiFi", | 558 | .name = "WM8510 HiFi", |
559 | .playback = { | 559 | .playback = { |
560 | .stream_name = "Playback", | 560 | .stream_name = "Playback", |
561 | .channels_min = 2, | 561 | .channels_min = 2, |
562 | .channels_max = 2, | 562 | .channels_max = 2, |
563 | .rates = WM8510_RATES, | 563 | .rates = WM8510_RATES, |
564 | .formats = WM8510_FORMATS,}, | 564 | .formats = WM8510_FORMATS,}, |
565 | .capture = { | 565 | .capture = { |
566 | .stream_name = "Capture", | 566 | .stream_name = "Capture", |
567 | .channels_min = 2, | 567 | .channels_min = 2, |
568 | .channels_max = 2, | 568 | .channels_max = 2, |
569 | .rates = WM8510_RATES, | 569 | .rates = WM8510_RATES, |
570 | .formats = WM8510_FORMATS,}, | 570 | .formats = WM8510_FORMATS,}, |
571 | .ops = { | 571 | .ops = { |
572 | .hw_params = wm8510_pcm_hw_params, | 572 | .hw_params = wm8510_pcm_hw_params, |
573 | }, | 573 | }, |
574 | .dai_ops = { | 574 | .dai_ops = { |
575 | .digital_mute = wm8510_mute, | 575 | .digital_mute = wm8510_mute, |
576 | .set_fmt = wm8510_set_dai_fmt, | 576 | .set_fmt = wm8510_set_dai_fmt, |
577 | .set_clkdiv = wm8510_set_dai_clkdiv, | 577 | .set_clkdiv = wm8510_set_dai_clkdiv, |
578 | .set_pll = wm8510_set_dai_pll, | 578 | .set_pll = wm8510_set_dai_pll, |
579 | }, | 579 | }, |
580 | }; | 580 | }; |
581 | EXPORT_SYMBOL_GPL(wm8510_dai); | 581 | EXPORT_SYMBOL_GPL(wm8510_dai); |
582 | 582 | ||
583 | static int wm8510_suspend(struct platform_device *pdev, pm_message_t state) | 583 | static int wm8510_suspend(struct platform_device *pdev, pm_message_t state) |
584 | { | 584 | { |
585 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 585 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
586 | struct snd_soc_codec *codec = socdev->codec; | 586 | struct snd_soc_codec *codec = socdev->codec; |
587 | 587 | ||
588 | wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF); | 588 | wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF); |
589 | return 0; | 589 | return 0; |
590 | } | 590 | } |
591 | 591 | ||
592 | static int wm8510_resume(struct platform_device *pdev) | 592 | static int wm8510_resume(struct platform_device *pdev) |
593 | { | 593 | { |
594 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 594 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
595 | struct snd_soc_codec *codec = socdev->codec; | 595 | struct snd_soc_codec *codec = socdev->codec; |
596 | int i; | 596 | int i; |
597 | u8 data[2]; | 597 | u8 data[2]; |
598 | u16 *cache = codec->reg_cache; | 598 | u16 *cache = codec->reg_cache; |
599 | 599 | ||
600 | /* Sync reg_cache with the hardware */ | 600 | /* Sync reg_cache with the hardware */ |
601 | for (i = 0; i < ARRAY_SIZE(wm8510_reg); i++) { | 601 | for (i = 0; i < ARRAY_SIZE(wm8510_reg); i++) { |
602 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); | 602 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); |
603 | data[1] = cache[i] & 0x00ff; | 603 | data[1] = cache[i] & 0x00ff; |
604 | codec->hw_write(codec->control_data, data, 2); | 604 | codec->hw_write(codec->control_data, data, 2); |
605 | } | 605 | } |
606 | wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 606 | wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
607 | wm8510_set_bias_level(codec, codec->suspend_bias_level); | 607 | wm8510_set_bias_level(codec, codec->suspend_bias_level); |
608 | return 0; | 608 | return 0; |
609 | } | 609 | } |
610 | 610 | ||
611 | /* | 611 | /* |
612 | * initialise the WM8510 driver | 612 | * initialise the WM8510 driver |
613 | * register the mixer and dsp interfaces with the kernel | 613 | * register the mixer and dsp interfaces with the kernel |
614 | */ | 614 | */ |
615 | static int wm8510_init(struct snd_soc_device *socdev) | 615 | static int wm8510_init(struct snd_soc_device *socdev) |
616 | { | 616 | { |
617 | struct snd_soc_codec *codec = socdev->codec; | 617 | struct snd_soc_codec *codec = socdev->codec; |
618 | int ret = 0; | 618 | int ret = 0; |
619 | 619 | ||
620 | codec->name = "WM8510"; | 620 | codec->name = "WM8510"; |
621 | codec->owner = THIS_MODULE; | 621 | codec->owner = THIS_MODULE; |
622 | codec->read = wm8510_read_reg_cache; | 622 | codec->read = wm8510_read_reg_cache; |
623 | codec->write = wm8510_write; | 623 | codec->write = wm8510_write; |
624 | codec->set_bias_level = wm8510_set_bias_level; | 624 | codec->set_bias_level = wm8510_set_bias_level; |
625 | codec->dai = &wm8510_dai; | 625 | codec->dai = &wm8510_dai; |
626 | codec->num_dai = 1; | 626 | codec->num_dai = 1; |
627 | codec->reg_cache_size = ARRAY_SIZE(wm8510_reg); | 627 | codec->reg_cache_size = ARRAY_SIZE(wm8510_reg); |
628 | codec->reg_cache = kmemdup(wm8510_reg, sizeof(wm8510_reg), GFP_KERNEL); | 628 | codec->reg_cache = kmemdup(wm8510_reg, sizeof(wm8510_reg), GFP_KERNEL); |
629 | 629 | ||
630 | if (codec->reg_cache == NULL) | 630 | if (codec->reg_cache == NULL) |
631 | return -ENOMEM; | 631 | return -ENOMEM; |
632 | 632 | ||
633 | wm8510_reset(codec); | 633 | wm8510_reset(codec); |
634 | 634 | ||
635 | /* register pcms */ | 635 | /* register pcms */ |
636 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 636 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
637 | if (ret < 0) { | 637 | if (ret < 0) { |
638 | printk(KERN_ERR "wm8510: failed to create pcms\n"); | 638 | printk(KERN_ERR "wm8510: failed to create pcms\n"); |
639 | goto pcm_err; | 639 | goto pcm_err; |
640 | } | 640 | } |
641 | 641 | ||
642 | /* power on device */ | 642 | /* power on device */ |
643 | wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 643 | wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
644 | wm8510_add_controls(codec); | 644 | wm8510_add_controls(codec); |
645 | wm8510_add_widgets(codec); | 645 | wm8510_add_widgets(codec); |
646 | ret = snd_soc_register_card(socdev); | 646 | ret = snd_soc_register_card(socdev); |
647 | if (ret < 0) { | 647 | if (ret < 0) { |
648 | printk(KERN_ERR "wm8510: failed to register card\n"); | 648 | printk(KERN_ERR "wm8510: failed to register card\n"); |
649 | goto card_err; | 649 | goto card_err; |
650 | } | 650 | } |
651 | return ret; | 651 | return ret; |
652 | 652 | ||
653 | card_err: | 653 | card_err: |
654 | snd_soc_free_pcms(socdev); | 654 | snd_soc_free_pcms(socdev); |
655 | snd_soc_dapm_free(socdev); | 655 | snd_soc_dapm_free(socdev); |
656 | pcm_err: | 656 | pcm_err: |
657 | kfree(codec->reg_cache); | 657 | kfree(codec->reg_cache); |
658 | return ret; | 658 | return ret; |
659 | } | 659 | } |
660 | 660 | ||
661 | static struct snd_soc_device *wm8510_socdev; | 661 | static struct snd_soc_device *wm8510_socdev; |
662 | 662 | ||
663 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 663 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
664 | 664 | ||
665 | /* | 665 | /* |
666 | * WM8510 2 wire address is 0x1a | 666 | * WM8510 2 wire address is 0x1a |
667 | */ | 667 | */ |
668 | #define I2C_DRIVERID_WM8510 0xfefe /* liam - need a proper id */ | 668 | #define I2C_DRIVERID_WM8510 0xfefe /* liam - need a proper id */ |
669 | 669 | ||
670 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | 670 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; |
671 | 671 | ||
672 | /* Magic definition of all other variables and things */ | 672 | /* Magic definition of all other variables and things */ |
673 | I2C_CLIENT_INSMOD; | 673 | I2C_CLIENT_INSMOD; |
674 | 674 | ||
675 | static struct i2c_driver wm8510_i2c_driver; | 675 | static struct i2c_driver wm8510_i2c_driver; |
676 | static struct i2c_client client_template; | 676 | static struct i2c_client client_template; |
677 | 677 | ||
678 | /* If the i2c layer weren't so broken, we could pass this kind of data | 678 | /* If the i2c layer weren't so broken, we could pass this kind of data |
679 | around */ | 679 | around */ |
680 | 680 | ||
681 | static int wm8510_codec_probe(struct i2c_adapter *adap, int addr, int kind) | 681 | static int wm8510_codec_probe(struct i2c_adapter *adap, int addr, int kind) |
682 | { | 682 | { |
683 | struct snd_soc_device *socdev = wm8510_socdev; | 683 | struct snd_soc_device *socdev = wm8510_socdev; |
684 | struct wm8510_setup_data *setup = socdev->codec_data; | 684 | struct wm8510_setup_data *setup = socdev->codec_data; |
685 | struct snd_soc_codec *codec = socdev->codec; | 685 | struct snd_soc_codec *codec = socdev->codec; |
686 | struct i2c_client *i2c; | 686 | struct i2c_client *i2c; |
687 | int ret; | 687 | int ret; |
688 | 688 | ||
689 | if (addr != setup->i2c_address) | 689 | if (addr != setup->i2c_address) |
690 | return -ENODEV; | 690 | return -ENODEV; |
691 | 691 | ||
692 | client_template.adapter = adap; | 692 | client_template.adapter = adap; |
693 | client_template.addr = addr; | 693 | client_template.addr = addr; |
694 | 694 | ||
695 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | 695 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); |
696 | if (i2c == NULL) { | 696 | if (i2c == NULL) |
697 | kfree(codec); | ||
698 | return -ENOMEM; | 697 | return -ENOMEM; |
699 | } | 698 | |
700 | i2c_set_clientdata(i2c, codec); | 699 | i2c_set_clientdata(i2c, codec); |
701 | codec->control_data = i2c; | 700 | codec->control_data = i2c; |
702 | 701 | ||
703 | ret = i2c_attach_client(i2c); | 702 | ret = i2c_attach_client(i2c); |
704 | if (ret < 0) { | 703 | if (ret < 0) { |
705 | pr_err("failed to attach codec at addr %x\n", addr); | 704 | pr_err("failed to attach codec at addr %x\n", addr); |
706 | goto err; | 705 | goto err; |
707 | } | 706 | } |
708 | 707 | ||
709 | ret = wm8510_init(socdev); | 708 | ret = wm8510_init(socdev); |
710 | if (ret < 0) { | 709 | if (ret < 0) { |
711 | pr_err("failed to initialise WM8510\n"); | 710 | pr_err("failed to initialise WM8510\n"); |
712 | goto err; | 711 | goto err; |
713 | } | 712 | } |
714 | return ret; | 713 | return ret; |
715 | 714 | ||
716 | err: | 715 | err: |
717 | kfree(codec); | ||
718 | kfree(i2c); | 716 | kfree(i2c); |
719 | return ret; | 717 | return ret; |
720 | } | 718 | } |
721 | 719 | ||
722 | static int wm8510_i2c_detach(struct i2c_client *client) | 720 | static int wm8510_i2c_detach(struct i2c_client *client) |
723 | { | 721 | { |
724 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 722 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
725 | i2c_detach_client(client); | 723 | i2c_detach_client(client); |
726 | kfree(codec->reg_cache); | 724 | kfree(codec->reg_cache); |
727 | kfree(client); | 725 | kfree(client); |
728 | return 0; | 726 | return 0; |
729 | } | 727 | } |
730 | 728 | ||
731 | static int wm8510_i2c_attach(struct i2c_adapter *adap) | 729 | static int wm8510_i2c_attach(struct i2c_adapter *adap) |
732 | { | 730 | { |
733 | return i2c_probe(adap, &addr_data, wm8510_codec_probe); | 731 | return i2c_probe(adap, &addr_data, wm8510_codec_probe); |
734 | } | 732 | } |
735 | 733 | ||
736 | /* corgi i2c codec control layer */ | 734 | /* corgi i2c codec control layer */ |
737 | static struct i2c_driver wm8510_i2c_driver = { | 735 | static struct i2c_driver wm8510_i2c_driver = { |
738 | .driver = { | 736 | .driver = { |
739 | .name = "WM8510 I2C Codec", | 737 | .name = "WM8510 I2C Codec", |
740 | .owner = THIS_MODULE, | 738 | .owner = THIS_MODULE, |
741 | }, | 739 | }, |
742 | .id = I2C_DRIVERID_WM8510, | 740 | .id = I2C_DRIVERID_WM8510, |
743 | .attach_adapter = wm8510_i2c_attach, | 741 | .attach_adapter = wm8510_i2c_attach, |
744 | .detach_client = wm8510_i2c_detach, | 742 | .detach_client = wm8510_i2c_detach, |
745 | .command = NULL, | 743 | .command = NULL, |
746 | }; | 744 | }; |
747 | 745 | ||
748 | static struct i2c_client client_template = { | 746 | static struct i2c_client client_template = { |
749 | .name = "WM8510", | 747 | .name = "WM8510", |
750 | .driver = &wm8510_i2c_driver, | 748 | .driver = &wm8510_i2c_driver, |
751 | }; | 749 | }; |
752 | #endif | 750 | #endif |
753 | 751 | ||
754 | static int wm8510_probe(struct platform_device *pdev) | 752 | static int wm8510_probe(struct platform_device *pdev) |
755 | { | 753 | { |
756 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 754 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
757 | struct wm8510_setup_data *setup; | 755 | struct wm8510_setup_data *setup; |
758 | struct snd_soc_codec *codec; | 756 | struct snd_soc_codec *codec; |
759 | int ret = 0; | 757 | int ret = 0; |
760 | 758 | ||
761 | pr_info("WM8510 Audio Codec %s", WM8510_VERSION); | 759 | pr_info("WM8510 Audio Codec %s", WM8510_VERSION); |
762 | 760 | ||
763 | setup = socdev->codec_data; | 761 | setup = socdev->codec_data; |
764 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 762 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); |
765 | if (codec == NULL) | 763 | if (codec == NULL) |
766 | return -ENOMEM; | 764 | return -ENOMEM; |
767 | 765 | ||
768 | socdev->codec = codec; | 766 | socdev->codec = codec; |
769 | mutex_init(&codec->mutex); | 767 | mutex_init(&codec->mutex); |
770 | INIT_LIST_HEAD(&codec->dapm_widgets); | 768 | INIT_LIST_HEAD(&codec->dapm_widgets); |
771 | INIT_LIST_HEAD(&codec->dapm_paths); | 769 | INIT_LIST_HEAD(&codec->dapm_paths); |
772 | 770 | ||
773 | wm8510_socdev = socdev; | 771 | wm8510_socdev = socdev; |
774 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 772 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
775 | if (setup->i2c_address) { | 773 | if (setup->i2c_address) { |
776 | normal_i2c[0] = setup->i2c_address; | 774 | normal_i2c[0] = setup->i2c_address; |
777 | codec->hw_write = (hw_write_t)i2c_master_send; | 775 | codec->hw_write = (hw_write_t)i2c_master_send; |
778 | ret = i2c_add_driver(&wm8510_i2c_driver); | 776 | ret = i2c_add_driver(&wm8510_i2c_driver); |
779 | if (ret != 0) | 777 | if (ret != 0) |
780 | printk(KERN_ERR "can't add i2c driver"); | 778 | printk(KERN_ERR "can't add i2c driver"); |
781 | } | 779 | } |
782 | #else | 780 | #else |
783 | /* Add other interfaces here */ | 781 | /* Add other interfaces here */ |
784 | #endif | 782 | #endif |
783 | |||
784 | if (ret != 0) | ||
785 | kfree(codec); | ||
785 | return ret; | 786 | return ret; |
786 | } | 787 | } |
787 | 788 | ||
788 | /* power down chip */ | 789 | /* power down chip */ |
789 | static int wm8510_remove(struct platform_device *pdev) | 790 | static int wm8510_remove(struct platform_device *pdev) |
790 | { | 791 | { |
791 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 792 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
792 | struct snd_soc_codec *codec = socdev->codec; | 793 | struct snd_soc_codec *codec = socdev->codec; |
793 | 794 | ||
794 | if (codec->control_data) | 795 | if (codec->control_data) |
795 | wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF); | 796 | wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF); |
796 | 797 | ||
797 | snd_soc_free_pcms(socdev); | 798 | snd_soc_free_pcms(socdev); |
798 | snd_soc_dapm_free(socdev); | 799 | snd_soc_dapm_free(socdev); |
799 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 800 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
800 | i2c_del_driver(&wm8510_i2c_driver); | 801 | i2c_del_driver(&wm8510_i2c_driver); |
801 | #endif | 802 | #endif |
802 | kfree(codec); | 803 | kfree(codec); |
803 | 804 | ||
804 | return 0; | 805 | return 0; |
805 | } | 806 | } |
806 | 807 | ||
807 | struct snd_soc_codec_device soc_codec_dev_wm8510 = { | 808 | struct snd_soc_codec_device soc_codec_dev_wm8510 = { |
808 | .probe = wm8510_probe, | 809 | .probe = wm8510_probe, |
809 | .remove = wm8510_remove, | 810 | .remove = wm8510_remove, |
810 | .suspend = wm8510_suspend, | 811 | .suspend = wm8510_suspend, |
811 | .resume = wm8510_resume, | 812 | .resume = wm8510_resume, |
812 | }; | 813 | }; |
813 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8510); | 814 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8510); |
814 | 815 | ||
815 | MODULE_DESCRIPTION("ASoC WM8510 driver"); | 816 | MODULE_DESCRIPTION("ASoC WM8510 driver"); |
816 | MODULE_AUTHOR("Liam Girdwood"); | 817 | MODULE_AUTHOR("Liam Girdwood"); |
sound/soc/codecs/wm8731.c
1 | /* | 1 | /* |
2 | * wm8731.c -- WM8731 ALSA SoC Audio driver | 2 | * wm8731.c -- WM8731 ALSA SoC Audio driver |
3 | * | 3 | * |
4 | * Copyright 2005 Openedhand Ltd. | 4 | * Copyright 2005 Openedhand Ltd. |
5 | * | 5 | * |
6 | * Author: Richard Purdie <richard@openedhand.com> | 6 | * Author: Richard Purdie <richard@openedhand.com> |
7 | * | 7 | * |
8 | * Based on wm8753.c by Liam Girdwood | 8 | * Based on wm8753.c by Liam Girdwood |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License version 2 as | 11 | * it under the terms of the GNU General Public License version 2 as |
12 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/moduleparam.h> | 16 | #include <linux/moduleparam.h> |
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
19 | #include <linux/pm.h> | 19 | #include <linux/pm.h> |
20 | #include <linux/i2c.h> | 20 | #include <linux/i2c.h> |
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <sound/core.h> | 22 | #include <sound/core.h> |
23 | #include <sound/pcm.h> | 23 | #include <sound/pcm.h> |
24 | #include <sound/pcm_params.h> | 24 | #include <sound/pcm_params.h> |
25 | #include <sound/soc.h> | 25 | #include <sound/soc.h> |
26 | #include <sound/soc-dapm.h> | 26 | #include <sound/soc-dapm.h> |
27 | #include <sound/initval.h> | 27 | #include <sound/initval.h> |
28 | 28 | ||
29 | #include "wm8731.h" | 29 | #include "wm8731.h" |
30 | 30 | ||
31 | #define AUDIO_NAME "wm8731" | 31 | #define AUDIO_NAME "wm8731" |
32 | #define WM8731_VERSION "0.13" | 32 | #define WM8731_VERSION "0.13" |
33 | 33 | ||
34 | struct snd_soc_codec_device soc_codec_dev_wm8731; | 34 | struct snd_soc_codec_device soc_codec_dev_wm8731; |
35 | 35 | ||
36 | /* codec private data */ | 36 | /* codec private data */ |
37 | struct wm8731_priv { | 37 | struct wm8731_priv { |
38 | unsigned int sysclk; | 38 | unsigned int sysclk; |
39 | }; | 39 | }; |
40 | 40 | ||
41 | /* | 41 | /* |
42 | * wm8731 register cache | 42 | * wm8731 register cache |
43 | * We can't read the WM8731 register space when we are | 43 | * We can't read the WM8731 register space when we are |
44 | * using 2 wire for device control, so we cache them instead. | 44 | * using 2 wire for device control, so we cache them instead. |
45 | * There is no point in caching the reset register | 45 | * There is no point in caching the reset register |
46 | */ | 46 | */ |
47 | static const u16 wm8731_reg[WM8731_CACHEREGNUM] = { | 47 | static const u16 wm8731_reg[WM8731_CACHEREGNUM] = { |
48 | 0x0097, 0x0097, 0x0079, 0x0079, | 48 | 0x0097, 0x0097, 0x0079, 0x0079, |
49 | 0x000a, 0x0008, 0x009f, 0x000a, | 49 | 0x000a, 0x0008, 0x009f, 0x000a, |
50 | 0x0000, 0x0000 | 50 | 0x0000, 0x0000 |
51 | }; | 51 | }; |
52 | 52 | ||
53 | /* | 53 | /* |
54 | * read wm8731 register cache | 54 | * read wm8731 register cache |
55 | */ | 55 | */ |
56 | static inline unsigned int wm8731_read_reg_cache(struct snd_soc_codec *codec, | 56 | static inline unsigned int wm8731_read_reg_cache(struct snd_soc_codec *codec, |
57 | unsigned int reg) | 57 | unsigned int reg) |
58 | { | 58 | { |
59 | u16 *cache = codec->reg_cache; | 59 | u16 *cache = codec->reg_cache; |
60 | if (reg == WM8731_RESET) | 60 | if (reg == WM8731_RESET) |
61 | return 0; | 61 | return 0; |
62 | if (reg >= WM8731_CACHEREGNUM) | 62 | if (reg >= WM8731_CACHEREGNUM) |
63 | return -1; | 63 | return -1; |
64 | return cache[reg]; | 64 | return cache[reg]; |
65 | } | 65 | } |
66 | 66 | ||
67 | /* | 67 | /* |
68 | * write wm8731 register cache | 68 | * write wm8731 register cache |
69 | */ | 69 | */ |
70 | static inline void wm8731_write_reg_cache(struct snd_soc_codec *codec, | 70 | static inline void wm8731_write_reg_cache(struct snd_soc_codec *codec, |
71 | u16 reg, unsigned int value) | 71 | u16 reg, unsigned int value) |
72 | { | 72 | { |
73 | u16 *cache = codec->reg_cache; | 73 | u16 *cache = codec->reg_cache; |
74 | if (reg >= WM8731_CACHEREGNUM) | 74 | if (reg >= WM8731_CACHEREGNUM) |
75 | return; | 75 | return; |
76 | cache[reg] = value; | 76 | cache[reg] = value; |
77 | } | 77 | } |
78 | 78 | ||
79 | /* | 79 | /* |
80 | * write to the WM8731 register space | 80 | * write to the WM8731 register space |
81 | */ | 81 | */ |
82 | static int wm8731_write(struct snd_soc_codec *codec, unsigned int reg, | 82 | static int wm8731_write(struct snd_soc_codec *codec, unsigned int reg, |
83 | unsigned int value) | 83 | unsigned int value) |
84 | { | 84 | { |
85 | u8 data[2]; | 85 | u8 data[2]; |
86 | 86 | ||
87 | /* data is | 87 | /* data is |
88 | * D15..D9 WM8731 register offset | 88 | * D15..D9 WM8731 register offset |
89 | * D8...D0 register data | 89 | * D8...D0 register data |
90 | */ | 90 | */ |
91 | data[0] = (reg << 1) | ((value >> 8) & 0x0001); | 91 | data[0] = (reg << 1) | ((value >> 8) & 0x0001); |
92 | data[1] = value & 0x00ff; | 92 | data[1] = value & 0x00ff; |
93 | 93 | ||
94 | wm8731_write_reg_cache(codec, reg, value); | 94 | wm8731_write_reg_cache(codec, reg, value); |
95 | if (codec->hw_write(codec->control_data, data, 2) == 2) | 95 | if (codec->hw_write(codec->control_data, data, 2) == 2) |
96 | return 0; | 96 | return 0; |
97 | else | 97 | else |
98 | return -EIO; | 98 | return -EIO; |
99 | } | 99 | } |
100 | 100 | ||
101 | #define wm8731_reset(c) wm8731_write(c, WM8731_RESET, 0) | 101 | #define wm8731_reset(c) wm8731_write(c, WM8731_RESET, 0) |
102 | 102 | ||
103 | static const char *wm8731_input_select[] = {"Line In", "Mic"}; | 103 | static const char *wm8731_input_select[] = {"Line In", "Mic"}; |
104 | static const char *wm8731_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; | 104 | static const char *wm8731_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; |
105 | 105 | ||
106 | static const struct soc_enum wm8731_enum[] = { | 106 | static const struct soc_enum wm8731_enum[] = { |
107 | SOC_ENUM_SINGLE(WM8731_APANA, 2, 2, wm8731_input_select), | 107 | SOC_ENUM_SINGLE(WM8731_APANA, 2, 2, wm8731_input_select), |
108 | SOC_ENUM_SINGLE(WM8731_APDIGI, 1, 4, wm8731_deemph), | 108 | SOC_ENUM_SINGLE(WM8731_APDIGI, 1, 4, wm8731_deemph), |
109 | }; | 109 | }; |
110 | 110 | ||
111 | static const struct snd_kcontrol_new wm8731_snd_controls[] = { | 111 | static const struct snd_kcontrol_new wm8731_snd_controls[] = { |
112 | 112 | ||
113 | SOC_DOUBLE_R("Master Playback Volume", WM8731_LOUT1V, WM8731_ROUT1V, | 113 | SOC_DOUBLE_R("Master Playback Volume", WM8731_LOUT1V, WM8731_ROUT1V, |
114 | 0, 127, 0), | 114 | 0, 127, 0), |
115 | SOC_DOUBLE_R("Master Playback ZC Switch", WM8731_LOUT1V, WM8731_ROUT1V, | 115 | SOC_DOUBLE_R("Master Playback ZC Switch", WM8731_LOUT1V, WM8731_ROUT1V, |
116 | 7, 1, 0), | 116 | 7, 1, 0), |
117 | 117 | ||
118 | SOC_DOUBLE_R("Capture Volume", WM8731_LINVOL, WM8731_RINVOL, 0, 31, 0), | 118 | SOC_DOUBLE_R("Capture Volume", WM8731_LINVOL, WM8731_RINVOL, 0, 31, 0), |
119 | SOC_DOUBLE_R("Line Capture Switch", WM8731_LINVOL, WM8731_RINVOL, 7, 1, 1), | 119 | SOC_DOUBLE_R("Line Capture Switch", WM8731_LINVOL, WM8731_RINVOL, 7, 1, 1), |
120 | 120 | ||
121 | SOC_SINGLE("Mic Boost (+20dB)", WM8731_APANA, 0, 1, 0), | 121 | SOC_SINGLE("Mic Boost (+20dB)", WM8731_APANA, 0, 1, 0), |
122 | SOC_SINGLE("Capture Mic Switch", WM8731_APANA, 1, 1, 1), | 122 | SOC_SINGLE("Capture Mic Switch", WM8731_APANA, 1, 1, 1), |
123 | 123 | ||
124 | SOC_SINGLE("Sidetone Playback Volume", WM8731_APANA, 6, 3, 1), | 124 | SOC_SINGLE("Sidetone Playback Volume", WM8731_APANA, 6, 3, 1), |
125 | 125 | ||
126 | SOC_SINGLE("ADC High Pass Filter Switch", WM8731_APDIGI, 0, 1, 1), | 126 | SOC_SINGLE("ADC High Pass Filter Switch", WM8731_APDIGI, 0, 1, 1), |
127 | SOC_SINGLE("Store DC Offset Switch", WM8731_APDIGI, 4, 1, 0), | 127 | SOC_SINGLE("Store DC Offset Switch", WM8731_APDIGI, 4, 1, 0), |
128 | 128 | ||
129 | SOC_ENUM("Playback De-emphasis", wm8731_enum[1]), | 129 | SOC_ENUM("Playback De-emphasis", wm8731_enum[1]), |
130 | }; | 130 | }; |
131 | 131 | ||
132 | /* add non dapm controls */ | 132 | /* add non dapm controls */ |
133 | static int wm8731_add_controls(struct snd_soc_codec *codec) | 133 | static int wm8731_add_controls(struct snd_soc_codec *codec) |
134 | { | 134 | { |
135 | int err, i; | 135 | int err, i; |
136 | 136 | ||
137 | for (i = 0; i < ARRAY_SIZE(wm8731_snd_controls); i++) { | 137 | for (i = 0; i < ARRAY_SIZE(wm8731_snd_controls); i++) { |
138 | err = snd_ctl_add(codec->card, | 138 | err = snd_ctl_add(codec->card, |
139 | snd_soc_cnew(&wm8731_snd_controls[i], | 139 | snd_soc_cnew(&wm8731_snd_controls[i], |
140 | codec, NULL)); | 140 | codec, NULL)); |
141 | if (err < 0) | 141 | if (err < 0) |
142 | return err; | 142 | return err; |
143 | } | 143 | } |
144 | 144 | ||
145 | return 0; | 145 | return 0; |
146 | } | 146 | } |
147 | 147 | ||
148 | /* Output Mixer */ | 148 | /* Output Mixer */ |
149 | static const struct snd_kcontrol_new wm8731_output_mixer_controls[] = { | 149 | static const struct snd_kcontrol_new wm8731_output_mixer_controls[] = { |
150 | SOC_DAPM_SINGLE("Line Bypass Switch", WM8731_APANA, 3, 1, 0), | 150 | SOC_DAPM_SINGLE("Line Bypass Switch", WM8731_APANA, 3, 1, 0), |
151 | SOC_DAPM_SINGLE("Mic Sidetone Switch", WM8731_APANA, 5, 1, 0), | 151 | SOC_DAPM_SINGLE("Mic Sidetone Switch", WM8731_APANA, 5, 1, 0), |
152 | SOC_DAPM_SINGLE("HiFi Playback Switch", WM8731_APANA, 4, 1, 0), | 152 | SOC_DAPM_SINGLE("HiFi Playback Switch", WM8731_APANA, 4, 1, 0), |
153 | }; | 153 | }; |
154 | 154 | ||
155 | /* Input mux */ | 155 | /* Input mux */ |
156 | static const struct snd_kcontrol_new wm8731_input_mux_controls = | 156 | static const struct snd_kcontrol_new wm8731_input_mux_controls = |
157 | SOC_DAPM_ENUM("Input Select", wm8731_enum[0]); | 157 | SOC_DAPM_ENUM("Input Select", wm8731_enum[0]); |
158 | 158 | ||
159 | static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = { | 159 | static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = { |
160 | SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1, | 160 | SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1, |
161 | &wm8731_output_mixer_controls[0], | 161 | &wm8731_output_mixer_controls[0], |
162 | ARRAY_SIZE(wm8731_output_mixer_controls)), | 162 | ARRAY_SIZE(wm8731_output_mixer_controls)), |
163 | SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8731_PWR, 3, 1), | 163 | SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8731_PWR, 3, 1), |
164 | SND_SOC_DAPM_OUTPUT("LOUT"), | 164 | SND_SOC_DAPM_OUTPUT("LOUT"), |
165 | SND_SOC_DAPM_OUTPUT("LHPOUT"), | 165 | SND_SOC_DAPM_OUTPUT("LHPOUT"), |
166 | SND_SOC_DAPM_OUTPUT("ROUT"), | 166 | SND_SOC_DAPM_OUTPUT("ROUT"), |
167 | SND_SOC_DAPM_OUTPUT("RHPOUT"), | 167 | SND_SOC_DAPM_OUTPUT("RHPOUT"), |
168 | SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8731_PWR, 2, 1), | 168 | SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8731_PWR, 2, 1), |
169 | SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &wm8731_input_mux_controls), | 169 | SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &wm8731_input_mux_controls), |
170 | SND_SOC_DAPM_PGA("Line Input", WM8731_PWR, 0, 1, NULL, 0), | 170 | SND_SOC_DAPM_PGA("Line Input", WM8731_PWR, 0, 1, NULL, 0), |
171 | SND_SOC_DAPM_MICBIAS("Mic Bias", WM8731_PWR, 1, 1), | 171 | SND_SOC_DAPM_MICBIAS("Mic Bias", WM8731_PWR, 1, 1), |
172 | SND_SOC_DAPM_INPUT("MICIN"), | 172 | SND_SOC_DAPM_INPUT("MICIN"), |
173 | SND_SOC_DAPM_INPUT("RLINEIN"), | 173 | SND_SOC_DAPM_INPUT("RLINEIN"), |
174 | SND_SOC_DAPM_INPUT("LLINEIN"), | 174 | SND_SOC_DAPM_INPUT("LLINEIN"), |
175 | }; | 175 | }; |
176 | 176 | ||
177 | static const struct snd_soc_dapm_route intercon[] = { | 177 | static const struct snd_soc_dapm_route intercon[] = { |
178 | /* output mixer */ | 178 | /* output mixer */ |
179 | {"Output Mixer", "Line Bypass Switch", "Line Input"}, | 179 | {"Output Mixer", "Line Bypass Switch", "Line Input"}, |
180 | {"Output Mixer", "HiFi Playback Switch", "DAC"}, | 180 | {"Output Mixer", "HiFi Playback Switch", "DAC"}, |
181 | {"Output Mixer", "Mic Sidetone Switch", "Mic Bias"}, | 181 | {"Output Mixer", "Mic Sidetone Switch", "Mic Bias"}, |
182 | 182 | ||
183 | /* outputs */ | 183 | /* outputs */ |
184 | {"RHPOUT", NULL, "Output Mixer"}, | 184 | {"RHPOUT", NULL, "Output Mixer"}, |
185 | {"ROUT", NULL, "Output Mixer"}, | 185 | {"ROUT", NULL, "Output Mixer"}, |
186 | {"LHPOUT", NULL, "Output Mixer"}, | 186 | {"LHPOUT", NULL, "Output Mixer"}, |
187 | {"LOUT", NULL, "Output Mixer"}, | 187 | {"LOUT", NULL, "Output Mixer"}, |
188 | 188 | ||
189 | /* input mux */ | 189 | /* input mux */ |
190 | {"Input Mux", "Line In", "Line Input"}, | 190 | {"Input Mux", "Line In", "Line Input"}, |
191 | {"Input Mux", "Mic", "Mic Bias"}, | 191 | {"Input Mux", "Mic", "Mic Bias"}, |
192 | {"ADC", NULL, "Input Mux"}, | 192 | {"ADC", NULL, "Input Mux"}, |
193 | 193 | ||
194 | /* inputs */ | 194 | /* inputs */ |
195 | {"Line Input", NULL, "LLINEIN"}, | 195 | {"Line Input", NULL, "LLINEIN"}, |
196 | {"Line Input", NULL, "RLINEIN"}, | 196 | {"Line Input", NULL, "RLINEIN"}, |
197 | {"Mic Bias", NULL, "MICIN"}, | 197 | {"Mic Bias", NULL, "MICIN"}, |
198 | }; | 198 | }; |
199 | 199 | ||
200 | static int wm8731_add_widgets(struct snd_soc_codec *codec) | 200 | static int wm8731_add_widgets(struct snd_soc_codec *codec) |
201 | { | 201 | { |
202 | snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets, | 202 | snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets, |
203 | ARRAY_SIZE(wm8731_dapm_widgets)); | 203 | ARRAY_SIZE(wm8731_dapm_widgets)); |
204 | 204 | ||
205 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); | 205 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); |
206 | 206 | ||
207 | snd_soc_dapm_new_widgets(codec); | 207 | snd_soc_dapm_new_widgets(codec); |
208 | return 0; | 208 | return 0; |
209 | } | 209 | } |
210 | 210 | ||
211 | struct _coeff_div { | 211 | struct _coeff_div { |
212 | u32 mclk; | 212 | u32 mclk; |
213 | u32 rate; | 213 | u32 rate; |
214 | u16 fs; | 214 | u16 fs; |
215 | u8 sr:4; | 215 | u8 sr:4; |
216 | u8 bosr:1; | 216 | u8 bosr:1; |
217 | u8 usb:1; | 217 | u8 usb:1; |
218 | }; | 218 | }; |
219 | 219 | ||
220 | /* codec mclk clock divider coefficients */ | 220 | /* codec mclk clock divider coefficients */ |
221 | static const struct _coeff_div coeff_div[] = { | 221 | static const struct _coeff_div coeff_div[] = { |
222 | /* 48k */ | 222 | /* 48k */ |
223 | {12288000, 48000, 256, 0x0, 0x0, 0x0}, | 223 | {12288000, 48000, 256, 0x0, 0x0, 0x0}, |
224 | {18432000, 48000, 384, 0x0, 0x1, 0x0}, | 224 | {18432000, 48000, 384, 0x0, 0x1, 0x0}, |
225 | {12000000, 48000, 250, 0x0, 0x0, 0x1}, | 225 | {12000000, 48000, 250, 0x0, 0x0, 0x1}, |
226 | 226 | ||
227 | /* 32k */ | 227 | /* 32k */ |
228 | {12288000, 32000, 384, 0x6, 0x0, 0x0}, | 228 | {12288000, 32000, 384, 0x6, 0x0, 0x0}, |
229 | {18432000, 32000, 576, 0x6, 0x1, 0x0}, | 229 | {18432000, 32000, 576, 0x6, 0x1, 0x0}, |
230 | {12000000, 32000, 375, 0x6, 0x0, 0x1}, | 230 | {12000000, 32000, 375, 0x6, 0x0, 0x1}, |
231 | 231 | ||
232 | /* 8k */ | 232 | /* 8k */ |
233 | {12288000, 8000, 1536, 0x3, 0x0, 0x0}, | 233 | {12288000, 8000, 1536, 0x3, 0x0, 0x0}, |
234 | {18432000, 8000, 2304, 0x3, 0x1, 0x0}, | 234 | {18432000, 8000, 2304, 0x3, 0x1, 0x0}, |
235 | {11289600, 8000, 1408, 0xb, 0x0, 0x0}, | 235 | {11289600, 8000, 1408, 0xb, 0x0, 0x0}, |
236 | {16934400, 8000, 2112, 0xb, 0x1, 0x0}, | 236 | {16934400, 8000, 2112, 0xb, 0x1, 0x0}, |
237 | {12000000, 8000, 1500, 0x3, 0x0, 0x1}, | 237 | {12000000, 8000, 1500, 0x3, 0x0, 0x1}, |
238 | 238 | ||
239 | /* 96k */ | 239 | /* 96k */ |
240 | {12288000, 96000, 128, 0x7, 0x0, 0x0}, | 240 | {12288000, 96000, 128, 0x7, 0x0, 0x0}, |
241 | {18432000, 96000, 192, 0x7, 0x1, 0x0}, | 241 | {18432000, 96000, 192, 0x7, 0x1, 0x0}, |
242 | {12000000, 96000, 125, 0x7, 0x0, 0x1}, | 242 | {12000000, 96000, 125, 0x7, 0x0, 0x1}, |
243 | 243 | ||
244 | /* 44.1k */ | 244 | /* 44.1k */ |
245 | {11289600, 44100, 256, 0x8, 0x0, 0x0}, | 245 | {11289600, 44100, 256, 0x8, 0x0, 0x0}, |
246 | {16934400, 44100, 384, 0x8, 0x1, 0x0}, | 246 | {16934400, 44100, 384, 0x8, 0x1, 0x0}, |
247 | {12000000, 44100, 272, 0x8, 0x1, 0x1}, | 247 | {12000000, 44100, 272, 0x8, 0x1, 0x1}, |
248 | 248 | ||
249 | /* 88.2k */ | 249 | /* 88.2k */ |
250 | {11289600, 88200, 128, 0xf, 0x0, 0x0}, | 250 | {11289600, 88200, 128, 0xf, 0x0, 0x0}, |
251 | {16934400, 88200, 192, 0xf, 0x1, 0x0}, | 251 | {16934400, 88200, 192, 0xf, 0x1, 0x0}, |
252 | {12000000, 88200, 136, 0xf, 0x1, 0x1}, | 252 | {12000000, 88200, 136, 0xf, 0x1, 0x1}, |
253 | }; | 253 | }; |
254 | 254 | ||
255 | static inline int get_coeff(int mclk, int rate) | 255 | static inline int get_coeff(int mclk, int rate) |
256 | { | 256 | { |
257 | int i; | 257 | int i; |
258 | 258 | ||
259 | for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { | 259 | for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { |
260 | if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) | 260 | if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) |
261 | return i; | 261 | return i; |
262 | } | 262 | } |
263 | return 0; | 263 | return 0; |
264 | } | 264 | } |
265 | 265 | ||
266 | static int wm8731_hw_params(struct snd_pcm_substream *substream, | 266 | static int wm8731_hw_params(struct snd_pcm_substream *substream, |
267 | struct snd_pcm_hw_params *params) | 267 | struct snd_pcm_hw_params *params) |
268 | { | 268 | { |
269 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 269 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
270 | struct snd_soc_device *socdev = rtd->socdev; | 270 | struct snd_soc_device *socdev = rtd->socdev; |
271 | struct snd_soc_codec *codec = socdev->codec; | 271 | struct snd_soc_codec *codec = socdev->codec; |
272 | struct wm8731_priv *wm8731 = codec->private_data; | 272 | struct wm8731_priv *wm8731 = codec->private_data; |
273 | u16 iface = wm8731_read_reg_cache(codec, WM8731_IFACE) & 0xfff3; | 273 | u16 iface = wm8731_read_reg_cache(codec, WM8731_IFACE) & 0xfff3; |
274 | int i = get_coeff(wm8731->sysclk, params_rate(params)); | 274 | int i = get_coeff(wm8731->sysclk, params_rate(params)); |
275 | u16 srate = (coeff_div[i].sr << 2) | | 275 | u16 srate = (coeff_div[i].sr << 2) | |
276 | (coeff_div[i].bosr << 1) | coeff_div[i].usb; | 276 | (coeff_div[i].bosr << 1) | coeff_div[i].usb; |
277 | 277 | ||
278 | wm8731_write(codec, WM8731_SRATE, srate); | 278 | wm8731_write(codec, WM8731_SRATE, srate); |
279 | 279 | ||
280 | /* bit size */ | 280 | /* bit size */ |
281 | switch (params_format(params)) { | 281 | switch (params_format(params)) { |
282 | case SNDRV_PCM_FORMAT_S16_LE: | 282 | case SNDRV_PCM_FORMAT_S16_LE: |
283 | break; | 283 | break; |
284 | case SNDRV_PCM_FORMAT_S20_3LE: | 284 | case SNDRV_PCM_FORMAT_S20_3LE: |
285 | iface |= 0x0004; | 285 | iface |= 0x0004; |
286 | break; | 286 | break; |
287 | case SNDRV_PCM_FORMAT_S24_LE: | 287 | case SNDRV_PCM_FORMAT_S24_LE: |
288 | iface |= 0x0008; | 288 | iface |= 0x0008; |
289 | break; | 289 | break; |
290 | } | 290 | } |
291 | 291 | ||
292 | wm8731_write(codec, WM8731_IFACE, iface); | 292 | wm8731_write(codec, WM8731_IFACE, iface); |
293 | return 0; | 293 | return 0; |
294 | } | 294 | } |
295 | 295 | ||
296 | static int wm8731_pcm_prepare(struct snd_pcm_substream *substream) | 296 | static int wm8731_pcm_prepare(struct snd_pcm_substream *substream) |
297 | { | 297 | { |
298 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 298 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
299 | struct snd_soc_device *socdev = rtd->socdev; | 299 | struct snd_soc_device *socdev = rtd->socdev; |
300 | struct snd_soc_codec *codec = socdev->codec; | 300 | struct snd_soc_codec *codec = socdev->codec; |
301 | 301 | ||
302 | /* set active */ | 302 | /* set active */ |
303 | wm8731_write(codec, WM8731_ACTIVE, 0x0001); | 303 | wm8731_write(codec, WM8731_ACTIVE, 0x0001); |
304 | 304 | ||
305 | return 0; | 305 | return 0; |
306 | } | 306 | } |
307 | 307 | ||
308 | static void wm8731_shutdown(struct snd_pcm_substream *substream) | 308 | static void wm8731_shutdown(struct snd_pcm_substream *substream) |
309 | { | 309 | { |
310 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 310 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
311 | struct snd_soc_device *socdev = rtd->socdev; | 311 | struct snd_soc_device *socdev = rtd->socdev; |
312 | struct snd_soc_codec *codec = socdev->codec; | 312 | struct snd_soc_codec *codec = socdev->codec; |
313 | 313 | ||
314 | /* deactivate */ | 314 | /* deactivate */ |
315 | if (!codec->active) { | 315 | if (!codec->active) { |
316 | udelay(50); | 316 | udelay(50); |
317 | wm8731_write(codec, WM8731_ACTIVE, 0x0); | 317 | wm8731_write(codec, WM8731_ACTIVE, 0x0); |
318 | } | 318 | } |
319 | } | 319 | } |
320 | 320 | ||
321 | static int wm8731_mute(struct snd_soc_dai *dai, int mute) | 321 | static int wm8731_mute(struct snd_soc_dai *dai, int mute) |
322 | { | 322 | { |
323 | struct snd_soc_codec *codec = dai->codec; | 323 | struct snd_soc_codec *codec = dai->codec; |
324 | u16 mute_reg = wm8731_read_reg_cache(codec, WM8731_APDIGI) & 0xfff7; | 324 | u16 mute_reg = wm8731_read_reg_cache(codec, WM8731_APDIGI) & 0xfff7; |
325 | 325 | ||
326 | if (mute) | 326 | if (mute) |
327 | wm8731_write(codec, WM8731_APDIGI, mute_reg | 0x8); | 327 | wm8731_write(codec, WM8731_APDIGI, mute_reg | 0x8); |
328 | else | 328 | else |
329 | wm8731_write(codec, WM8731_APDIGI, mute_reg); | 329 | wm8731_write(codec, WM8731_APDIGI, mute_reg); |
330 | return 0; | 330 | return 0; |
331 | } | 331 | } |
332 | 332 | ||
333 | static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai, | 333 | static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
334 | int clk_id, unsigned int freq, int dir) | 334 | int clk_id, unsigned int freq, int dir) |
335 | { | 335 | { |
336 | struct snd_soc_codec *codec = codec_dai->codec; | 336 | struct snd_soc_codec *codec = codec_dai->codec; |
337 | struct wm8731_priv *wm8731 = codec->private_data; | 337 | struct wm8731_priv *wm8731 = codec->private_data; |
338 | 338 | ||
339 | switch (freq) { | 339 | switch (freq) { |
340 | case 11289600: | 340 | case 11289600: |
341 | case 12000000: | 341 | case 12000000: |
342 | case 12288000: | 342 | case 12288000: |
343 | case 16934400: | 343 | case 16934400: |
344 | case 18432000: | 344 | case 18432000: |
345 | wm8731->sysclk = freq; | 345 | wm8731->sysclk = freq; |
346 | return 0; | 346 | return 0; |
347 | } | 347 | } |
348 | return -EINVAL; | 348 | return -EINVAL; |
349 | } | 349 | } |
350 | 350 | ||
351 | 351 | ||
352 | static int wm8731_set_dai_fmt(struct snd_soc_dai *codec_dai, | 352 | static int wm8731_set_dai_fmt(struct snd_soc_dai *codec_dai, |
353 | unsigned int fmt) | 353 | unsigned int fmt) |
354 | { | 354 | { |
355 | struct snd_soc_codec *codec = codec_dai->codec; | 355 | struct snd_soc_codec *codec = codec_dai->codec; |
356 | u16 iface = 0; | 356 | u16 iface = 0; |
357 | 357 | ||
358 | /* set master/slave audio interface */ | 358 | /* set master/slave audio interface */ |
359 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 359 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
360 | case SND_SOC_DAIFMT_CBM_CFM: | 360 | case SND_SOC_DAIFMT_CBM_CFM: |
361 | iface |= 0x0040; | 361 | iface |= 0x0040; |
362 | break; | 362 | break; |
363 | case SND_SOC_DAIFMT_CBS_CFS: | 363 | case SND_SOC_DAIFMT_CBS_CFS: |
364 | break; | 364 | break; |
365 | default: | 365 | default: |
366 | return -EINVAL; | 366 | return -EINVAL; |
367 | } | 367 | } |
368 | 368 | ||
369 | /* interface format */ | 369 | /* interface format */ |
370 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 370 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
371 | case SND_SOC_DAIFMT_I2S: | 371 | case SND_SOC_DAIFMT_I2S: |
372 | iface |= 0x0002; | 372 | iface |= 0x0002; |
373 | break; | 373 | break; |
374 | case SND_SOC_DAIFMT_RIGHT_J: | 374 | case SND_SOC_DAIFMT_RIGHT_J: |
375 | break; | 375 | break; |
376 | case SND_SOC_DAIFMT_LEFT_J: | 376 | case SND_SOC_DAIFMT_LEFT_J: |
377 | iface |= 0x0001; | 377 | iface |= 0x0001; |
378 | break; | 378 | break; |
379 | case SND_SOC_DAIFMT_DSP_A: | 379 | case SND_SOC_DAIFMT_DSP_A: |
380 | iface |= 0x0003; | 380 | iface |= 0x0003; |
381 | break; | 381 | break; |
382 | case SND_SOC_DAIFMT_DSP_B: | 382 | case SND_SOC_DAIFMT_DSP_B: |
383 | iface |= 0x0013; | 383 | iface |= 0x0013; |
384 | break; | 384 | break; |
385 | default: | 385 | default: |
386 | return -EINVAL; | 386 | return -EINVAL; |
387 | } | 387 | } |
388 | 388 | ||
389 | /* clock inversion */ | 389 | /* clock inversion */ |
390 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | 390 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
391 | case SND_SOC_DAIFMT_NB_NF: | 391 | case SND_SOC_DAIFMT_NB_NF: |
392 | break; | 392 | break; |
393 | case SND_SOC_DAIFMT_IB_IF: | 393 | case SND_SOC_DAIFMT_IB_IF: |
394 | iface |= 0x0090; | 394 | iface |= 0x0090; |
395 | break; | 395 | break; |
396 | case SND_SOC_DAIFMT_IB_NF: | 396 | case SND_SOC_DAIFMT_IB_NF: |
397 | iface |= 0x0080; | 397 | iface |= 0x0080; |
398 | break; | 398 | break; |
399 | case SND_SOC_DAIFMT_NB_IF: | 399 | case SND_SOC_DAIFMT_NB_IF: |
400 | iface |= 0x0010; | 400 | iface |= 0x0010; |
401 | break; | 401 | break; |
402 | default: | 402 | default: |
403 | return -EINVAL; | 403 | return -EINVAL; |
404 | } | 404 | } |
405 | 405 | ||
406 | /* set iface */ | 406 | /* set iface */ |
407 | wm8731_write(codec, WM8731_IFACE, iface); | 407 | wm8731_write(codec, WM8731_IFACE, iface); |
408 | return 0; | 408 | return 0; |
409 | } | 409 | } |
410 | 410 | ||
411 | static int wm8731_set_bias_level(struct snd_soc_codec *codec, | 411 | static int wm8731_set_bias_level(struct snd_soc_codec *codec, |
412 | enum snd_soc_bias_level level) | 412 | enum snd_soc_bias_level level) |
413 | { | 413 | { |
414 | u16 reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff7f; | 414 | u16 reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff7f; |
415 | 415 | ||
416 | switch (level) { | 416 | switch (level) { |
417 | case SND_SOC_BIAS_ON: | 417 | case SND_SOC_BIAS_ON: |
418 | /* vref/mid, osc on, dac unmute */ | 418 | /* vref/mid, osc on, dac unmute */ |
419 | wm8731_write(codec, WM8731_PWR, reg); | 419 | wm8731_write(codec, WM8731_PWR, reg); |
420 | break; | 420 | break; |
421 | case SND_SOC_BIAS_PREPARE: | 421 | case SND_SOC_BIAS_PREPARE: |
422 | break; | 422 | break; |
423 | case SND_SOC_BIAS_STANDBY: | 423 | case SND_SOC_BIAS_STANDBY: |
424 | /* everything off except vref/vmid, */ | 424 | /* everything off except vref/vmid, */ |
425 | wm8731_write(codec, WM8731_PWR, reg | 0x0040); | 425 | wm8731_write(codec, WM8731_PWR, reg | 0x0040); |
426 | break; | 426 | break; |
427 | case SND_SOC_BIAS_OFF: | 427 | case SND_SOC_BIAS_OFF: |
428 | /* everything off, dac mute, inactive */ | 428 | /* everything off, dac mute, inactive */ |
429 | wm8731_write(codec, WM8731_ACTIVE, 0x0); | 429 | wm8731_write(codec, WM8731_ACTIVE, 0x0); |
430 | wm8731_write(codec, WM8731_PWR, 0xffff); | 430 | wm8731_write(codec, WM8731_PWR, 0xffff); |
431 | break; | 431 | break; |
432 | } | 432 | } |
433 | codec->bias_level = level; | 433 | codec->bias_level = level; |
434 | return 0; | 434 | return 0; |
435 | } | 435 | } |
436 | 436 | ||
437 | #define WM8731_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | 437 | #define WM8731_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ |
438 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ | 438 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ |
439 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ | 439 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ |
440 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ | 440 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ |
441 | SNDRV_PCM_RATE_96000) | 441 | SNDRV_PCM_RATE_96000) |
442 | 442 | ||
443 | #define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | 443 | #define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
444 | SNDRV_PCM_FMTBIT_S24_LE) | 444 | SNDRV_PCM_FMTBIT_S24_LE) |
445 | 445 | ||
446 | struct snd_soc_dai wm8731_dai = { | 446 | struct snd_soc_dai wm8731_dai = { |
447 | .name = "WM8731", | 447 | .name = "WM8731", |
448 | .playback = { | 448 | .playback = { |
449 | .stream_name = "Playback", | 449 | .stream_name = "Playback", |
450 | .channels_min = 1, | 450 | .channels_min = 1, |
451 | .channels_max = 2, | 451 | .channels_max = 2, |
452 | .rates = WM8731_RATES, | 452 | .rates = WM8731_RATES, |
453 | .formats = WM8731_FORMATS,}, | 453 | .formats = WM8731_FORMATS,}, |
454 | .capture = { | 454 | .capture = { |
455 | .stream_name = "Capture", | 455 | .stream_name = "Capture", |
456 | .channels_min = 1, | 456 | .channels_min = 1, |
457 | .channels_max = 2, | 457 | .channels_max = 2, |
458 | .rates = WM8731_RATES, | 458 | .rates = WM8731_RATES, |
459 | .formats = WM8731_FORMATS,}, | 459 | .formats = WM8731_FORMATS,}, |
460 | .ops = { | 460 | .ops = { |
461 | .prepare = wm8731_pcm_prepare, | 461 | .prepare = wm8731_pcm_prepare, |
462 | .hw_params = wm8731_hw_params, | 462 | .hw_params = wm8731_hw_params, |
463 | .shutdown = wm8731_shutdown, | 463 | .shutdown = wm8731_shutdown, |
464 | }, | 464 | }, |
465 | .dai_ops = { | 465 | .dai_ops = { |
466 | .digital_mute = wm8731_mute, | 466 | .digital_mute = wm8731_mute, |
467 | .set_sysclk = wm8731_set_dai_sysclk, | 467 | .set_sysclk = wm8731_set_dai_sysclk, |
468 | .set_fmt = wm8731_set_dai_fmt, | 468 | .set_fmt = wm8731_set_dai_fmt, |
469 | } | 469 | } |
470 | }; | 470 | }; |
471 | EXPORT_SYMBOL_GPL(wm8731_dai); | 471 | EXPORT_SYMBOL_GPL(wm8731_dai); |
472 | 472 | ||
473 | static int wm8731_suspend(struct platform_device *pdev, pm_message_t state) | 473 | static int wm8731_suspend(struct platform_device *pdev, pm_message_t state) |
474 | { | 474 | { |
475 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 475 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
476 | struct snd_soc_codec *codec = socdev->codec; | 476 | struct snd_soc_codec *codec = socdev->codec; |
477 | 477 | ||
478 | wm8731_write(codec, WM8731_ACTIVE, 0x0); | 478 | wm8731_write(codec, WM8731_ACTIVE, 0x0); |
479 | wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); | 479 | wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); |
480 | return 0; | 480 | return 0; |
481 | } | 481 | } |
482 | 482 | ||
483 | static int wm8731_resume(struct platform_device *pdev) | 483 | static int wm8731_resume(struct platform_device *pdev) |
484 | { | 484 | { |
485 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 485 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
486 | struct snd_soc_codec *codec = socdev->codec; | 486 | struct snd_soc_codec *codec = socdev->codec; |
487 | int i; | 487 | int i; |
488 | u8 data[2]; | 488 | u8 data[2]; |
489 | u16 *cache = codec->reg_cache; | 489 | u16 *cache = codec->reg_cache; |
490 | 490 | ||
491 | /* Sync reg_cache with the hardware */ | 491 | /* Sync reg_cache with the hardware */ |
492 | for (i = 0; i < ARRAY_SIZE(wm8731_reg); i++) { | 492 | for (i = 0; i < ARRAY_SIZE(wm8731_reg); i++) { |
493 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); | 493 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); |
494 | data[1] = cache[i] & 0x00ff; | 494 | data[1] = cache[i] & 0x00ff; |
495 | codec->hw_write(codec->control_data, data, 2); | 495 | codec->hw_write(codec->control_data, data, 2); |
496 | } | 496 | } |
497 | wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 497 | wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
498 | wm8731_set_bias_level(codec, codec->suspend_bias_level); | 498 | wm8731_set_bias_level(codec, codec->suspend_bias_level); |
499 | return 0; | 499 | return 0; |
500 | } | 500 | } |
501 | 501 | ||
502 | /* | 502 | /* |
503 | * initialise the WM8731 driver | 503 | * initialise the WM8731 driver |
504 | * register the mixer and dsp interfaces with the kernel | 504 | * register the mixer and dsp interfaces with the kernel |
505 | */ | 505 | */ |
506 | static int wm8731_init(struct snd_soc_device *socdev) | 506 | static int wm8731_init(struct snd_soc_device *socdev) |
507 | { | 507 | { |
508 | struct snd_soc_codec *codec = socdev->codec; | 508 | struct snd_soc_codec *codec = socdev->codec; |
509 | int reg, ret = 0; | 509 | int reg, ret = 0; |
510 | 510 | ||
511 | codec->name = "WM8731"; | 511 | codec->name = "WM8731"; |
512 | codec->owner = THIS_MODULE; | 512 | codec->owner = THIS_MODULE; |
513 | codec->read = wm8731_read_reg_cache; | 513 | codec->read = wm8731_read_reg_cache; |
514 | codec->write = wm8731_write; | 514 | codec->write = wm8731_write; |
515 | codec->set_bias_level = wm8731_set_bias_level; | 515 | codec->set_bias_level = wm8731_set_bias_level; |
516 | codec->dai = &wm8731_dai; | 516 | codec->dai = &wm8731_dai; |
517 | codec->num_dai = 1; | 517 | codec->num_dai = 1; |
518 | codec->reg_cache_size = ARRAY_SIZE(wm8731_reg); | 518 | codec->reg_cache_size = ARRAY_SIZE(wm8731_reg); |
519 | codec->reg_cache = kmemdup(wm8731_reg, sizeof(wm8731_reg), GFP_KERNEL); | 519 | codec->reg_cache = kmemdup(wm8731_reg, sizeof(wm8731_reg), GFP_KERNEL); |
520 | if (codec->reg_cache == NULL) | 520 | if (codec->reg_cache == NULL) |
521 | return -ENOMEM; | 521 | return -ENOMEM; |
522 | 522 | ||
523 | wm8731_reset(codec); | 523 | wm8731_reset(codec); |
524 | 524 | ||
525 | /* register pcms */ | 525 | /* register pcms */ |
526 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 526 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
527 | if (ret < 0) { | 527 | if (ret < 0) { |
528 | printk(KERN_ERR "wm8731: failed to create pcms\n"); | 528 | printk(KERN_ERR "wm8731: failed to create pcms\n"); |
529 | goto pcm_err; | 529 | goto pcm_err; |
530 | } | 530 | } |
531 | 531 | ||
532 | /* power on device */ | 532 | /* power on device */ |
533 | wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 533 | wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
534 | 534 | ||
535 | /* set the update bits */ | 535 | /* set the update bits */ |
536 | reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V); | 536 | reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V); |
537 | wm8731_write(codec, WM8731_LOUT1V, reg & ~0x0100); | 537 | wm8731_write(codec, WM8731_LOUT1V, reg & ~0x0100); |
538 | reg = wm8731_read_reg_cache(codec, WM8731_ROUT1V); | 538 | reg = wm8731_read_reg_cache(codec, WM8731_ROUT1V); |
539 | wm8731_write(codec, WM8731_ROUT1V, reg & ~0x0100); | 539 | wm8731_write(codec, WM8731_ROUT1V, reg & ~0x0100); |
540 | reg = wm8731_read_reg_cache(codec, WM8731_LINVOL); | 540 | reg = wm8731_read_reg_cache(codec, WM8731_LINVOL); |
541 | wm8731_write(codec, WM8731_LINVOL, reg & ~0x0100); | 541 | wm8731_write(codec, WM8731_LINVOL, reg & ~0x0100); |
542 | reg = wm8731_read_reg_cache(codec, WM8731_RINVOL); | 542 | reg = wm8731_read_reg_cache(codec, WM8731_RINVOL); |
543 | wm8731_write(codec, WM8731_RINVOL, reg & ~0x0100); | 543 | wm8731_write(codec, WM8731_RINVOL, reg & ~0x0100); |
544 | 544 | ||
545 | wm8731_add_controls(codec); | 545 | wm8731_add_controls(codec); |
546 | wm8731_add_widgets(codec); | 546 | wm8731_add_widgets(codec); |
547 | ret = snd_soc_register_card(socdev); | 547 | ret = snd_soc_register_card(socdev); |
548 | if (ret < 0) { | 548 | if (ret < 0) { |
549 | printk(KERN_ERR "wm8731: failed to register card\n"); | 549 | printk(KERN_ERR "wm8731: failed to register card\n"); |
550 | goto card_err; | 550 | goto card_err; |
551 | } | 551 | } |
552 | 552 | ||
553 | return ret; | 553 | return ret; |
554 | 554 | ||
555 | card_err: | 555 | card_err: |
556 | snd_soc_free_pcms(socdev); | 556 | snd_soc_free_pcms(socdev); |
557 | snd_soc_dapm_free(socdev); | 557 | snd_soc_dapm_free(socdev); |
558 | pcm_err: | 558 | pcm_err: |
559 | kfree(codec->reg_cache); | 559 | kfree(codec->reg_cache); |
560 | return ret; | 560 | return ret; |
561 | } | 561 | } |
562 | 562 | ||
563 | static struct snd_soc_device *wm8731_socdev; | 563 | static struct snd_soc_device *wm8731_socdev; |
564 | 564 | ||
565 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 565 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
566 | 566 | ||
567 | /* | 567 | /* |
568 | * WM8731 2 wire address is determined by GPIO5 | 568 | * WM8731 2 wire address is determined by GPIO5 |
569 | * state during powerup. | 569 | * state during powerup. |
570 | * low = 0x1a | 570 | * low = 0x1a |
571 | * high = 0x1b | 571 | * high = 0x1b |
572 | */ | 572 | */ |
573 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | 573 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; |
574 | 574 | ||
575 | /* Magic definition of all other variables and things */ | 575 | /* Magic definition of all other variables and things */ |
576 | I2C_CLIENT_INSMOD; | 576 | I2C_CLIENT_INSMOD; |
577 | 577 | ||
578 | static struct i2c_driver wm8731_i2c_driver; | 578 | static struct i2c_driver wm8731_i2c_driver; |
579 | static struct i2c_client client_template; | 579 | static struct i2c_client client_template; |
580 | 580 | ||
581 | /* If the i2c layer weren't so broken, we could pass this kind of data | 581 | /* If the i2c layer weren't so broken, we could pass this kind of data |
582 | around */ | 582 | around */ |
583 | 583 | ||
584 | static int wm8731_codec_probe(struct i2c_adapter *adap, int addr, int kind) | 584 | static int wm8731_codec_probe(struct i2c_adapter *adap, int addr, int kind) |
585 | { | 585 | { |
586 | struct snd_soc_device *socdev = wm8731_socdev; | 586 | struct snd_soc_device *socdev = wm8731_socdev; |
587 | struct wm8731_setup_data *setup = socdev->codec_data; | 587 | struct wm8731_setup_data *setup = socdev->codec_data; |
588 | struct snd_soc_codec *codec = socdev->codec; | 588 | struct snd_soc_codec *codec = socdev->codec; |
589 | struct i2c_client *i2c; | 589 | struct i2c_client *i2c; |
590 | int ret; | 590 | int ret; |
591 | 591 | ||
592 | if (addr != setup->i2c_address) | 592 | if (addr != setup->i2c_address) |
593 | return -ENODEV; | 593 | return -ENODEV; |
594 | 594 | ||
595 | client_template.adapter = adap; | 595 | client_template.adapter = adap; |
596 | client_template.addr = addr; | 596 | client_template.addr = addr; |
597 | 597 | ||
598 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | 598 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); |
599 | if (i2c == NULL) { | 599 | if (i2c == NULL) |
600 | kfree(codec); | ||
601 | return -ENOMEM; | 600 | return -ENOMEM; |
602 | } | 601 | |
603 | i2c_set_clientdata(i2c, codec); | 602 | i2c_set_clientdata(i2c, codec); |
604 | codec->control_data = i2c; | 603 | codec->control_data = i2c; |
605 | 604 | ||
606 | ret = i2c_attach_client(i2c); | 605 | ret = i2c_attach_client(i2c); |
607 | if (ret < 0) { | 606 | if (ret < 0) { |
608 | pr_err("failed to attach codec at addr %x\n", addr); | 607 | pr_err("failed to attach codec at addr %x\n", addr); |
609 | goto err; | 608 | goto err; |
610 | } | 609 | } |
611 | 610 | ||
612 | ret = wm8731_init(socdev); | 611 | ret = wm8731_init(socdev); |
613 | if (ret < 0) { | 612 | if (ret < 0) { |
614 | pr_err("failed to initialise WM8731\n"); | 613 | pr_err("failed to initialise WM8731\n"); |
615 | goto err; | 614 | goto err; |
616 | } | 615 | } |
617 | return ret; | 616 | return ret; |
618 | 617 | ||
619 | err: | 618 | err: |
620 | kfree(codec); | ||
621 | kfree(i2c); | 619 | kfree(i2c); |
622 | return ret; | 620 | return ret; |
623 | } | 621 | } |
624 | 622 | ||
625 | static int wm8731_i2c_detach(struct i2c_client *client) | 623 | static int wm8731_i2c_detach(struct i2c_client *client) |
626 | { | 624 | { |
627 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 625 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
628 | i2c_detach_client(client); | 626 | i2c_detach_client(client); |
629 | kfree(codec->reg_cache); | 627 | kfree(codec->reg_cache); |
630 | kfree(client); | 628 | kfree(client); |
631 | return 0; | 629 | return 0; |
632 | } | 630 | } |
633 | 631 | ||
634 | static int wm8731_i2c_attach(struct i2c_adapter *adap) | 632 | static int wm8731_i2c_attach(struct i2c_adapter *adap) |
635 | { | 633 | { |
636 | return i2c_probe(adap, &addr_data, wm8731_codec_probe); | 634 | return i2c_probe(adap, &addr_data, wm8731_codec_probe); |
637 | } | 635 | } |
638 | 636 | ||
639 | /* corgi i2c codec control layer */ | 637 | /* corgi i2c codec control layer */ |
640 | static struct i2c_driver wm8731_i2c_driver = { | 638 | static struct i2c_driver wm8731_i2c_driver = { |
641 | .driver = { | 639 | .driver = { |
642 | .name = "WM8731 I2C Codec", | 640 | .name = "WM8731 I2C Codec", |
643 | .owner = THIS_MODULE, | 641 | .owner = THIS_MODULE, |
644 | }, | 642 | }, |
645 | .id = I2C_DRIVERID_WM8731, | 643 | .id = I2C_DRIVERID_WM8731, |
646 | .attach_adapter = wm8731_i2c_attach, | 644 | .attach_adapter = wm8731_i2c_attach, |
647 | .detach_client = wm8731_i2c_detach, | 645 | .detach_client = wm8731_i2c_detach, |
648 | .command = NULL, | 646 | .command = NULL, |
649 | }; | 647 | }; |
650 | 648 | ||
651 | static struct i2c_client client_template = { | 649 | static struct i2c_client client_template = { |
652 | .name = "WM8731", | 650 | .name = "WM8731", |
653 | .driver = &wm8731_i2c_driver, | 651 | .driver = &wm8731_i2c_driver, |
654 | }; | 652 | }; |
655 | #endif | 653 | #endif |
656 | 654 | ||
657 | static int wm8731_probe(struct platform_device *pdev) | 655 | static int wm8731_probe(struct platform_device *pdev) |
658 | { | 656 | { |
659 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 657 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
660 | struct wm8731_setup_data *setup; | 658 | struct wm8731_setup_data *setup; |
661 | struct snd_soc_codec *codec; | 659 | struct snd_soc_codec *codec; |
662 | struct wm8731_priv *wm8731; | 660 | struct wm8731_priv *wm8731; |
663 | int ret = 0; | 661 | int ret = 0; |
664 | 662 | ||
665 | pr_info("WM8731 Audio Codec %s", WM8731_VERSION); | 663 | pr_info("WM8731 Audio Codec %s", WM8731_VERSION); |
666 | 664 | ||
667 | setup = socdev->codec_data; | 665 | setup = socdev->codec_data; |
668 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 666 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); |
669 | if (codec == NULL) | 667 | if (codec == NULL) |
670 | return -ENOMEM; | 668 | return -ENOMEM; |
671 | 669 | ||
672 | wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL); | 670 | wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL); |
673 | if (wm8731 == NULL) { | 671 | if (wm8731 == NULL) { |
674 | kfree(codec); | 672 | kfree(codec); |
675 | return -ENOMEM; | 673 | return -ENOMEM; |
676 | } | 674 | } |
677 | 675 | ||
678 | codec->private_data = wm8731; | 676 | codec->private_data = wm8731; |
679 | socdev->codec = codec; | 677 | socdev->codec = codec; |
680 | mutex_init(&codec->mutex); | 678 | mutex_init(&codec->mutex); |
681 | INIT_LIST_HEAD(&codec->dapm_widgets); | 679 | INIT_LIST_HEAD(&codec->dapm_widgets); |
682 | INIT_LIST_HEAD(&codec->dapm_paths); | 680 | INIT_LIST_HEAD(&codec->dapm_paths); |
683 | 681 | ||
684 | wm8731_socdev = socdev; | 682 | wm8731_socdev = socdev; |
685 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 683 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
686 | if (setup->i2c_address) { | 684 | if (setup->i2c_address) { |
687 | normal_i2c[0] = setup->i2c_address; | 685 | normal_i2c[0] = setup->i2c_address; |
688 | codec->hw_write = (hw_write_t)i2c_master_send; | 686 | codec->hw_write = (hw_write_t)i2c_master_send; |
689 | ret = i2c_add_driver(&wm8731_i2c_driver); | 687 | ret = i2c_add_driver(&wm8731_i2c_driver); |
690 | if (ret != 0) | 688 | if (ret != 0) |
691 | printk(KERN_ERR "can't add i2c driver"); | 689 | printk(KERN_ERR "can't add i2c driver"); |
692 | } | 690 | } |
693 | #else | 691 | #else |
694 | /* Add other interfaces here */ | 692 | /* Add other interfaces here */ |
695 | #endif | 693 | #endif |
694 | |||
695 | if (ret != 0) { | ||
696 | kfree(codec->private_data); | ||
697 | kfree(codec); | ||
698 | } | ||
696 | return ret; | 699 | return ret; |
697 | } | 700 | } |
698 | 701 | ||
699 | /* power down chip */ | 702 | /* power down chip */ |
700 | static int wm8731_remove(struct platform_device *pdev) | 703 | static int wm8731_remove(struct platform_device *pdev) |
701 | { | 704 | { |
702 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 705 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
703 | struct snd_soc_codec *codec = socdev->codec; | 706 | struct snd_soc_codec *codec = socdev->codec; |
704 | 707 | ||
705 | if (codec->control_data) | 708 | if (codec->control_data) |
706 | wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); | 709 | wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); |
707 | 710 | ||
708 | snd_soc_free_pcms(socdev); | 711 | snd_soc_free_pcms(socdev); |
709 | snd_soc_dapm_free(socdev); | 712 | snd_soc_dapm_free(socdev); |
710 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 713 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
711 | i2c_del_driver(&wm8731_i2c_driver); | 714 | i2c_del_driver(&wm8731_i2c_driver); |
712 | #endif | 715 | #endif |
713 | kfree(codec->private_data); | 716 | kfree(codec->private_data); |
714 | kfree(codec); | 717 | kfree(codec); |
715 | 718 | ||
716 | return 0; | 719 | return 0; |
717 | } | 720 | } |
718 | 721 | ||
719 | struct snd_soc_codec_device soc_codec_dev_wm8731 = { | 722 | struct snd_soc_codec_device soc_codec_dev_wm8731 = { |
720 | .probe = wm8731_probe, | 723 | .probe = wm8731_probe, |
721 | .remove = wm8731_remove, | 724 | .remove = wm8731_remove, |
722 | .suspend = wm8731_suspend, | 725 | .suspend = wm8731_suspend, |
723 | .resume = wm8731_resume, | 726 | .resume = wm8731_resume, |
724 | }; | 727 | }; |
725 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731); | 728 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731); |
726 | 729 | ||
727 | MODULE_DESCRIPTION("ASoC WM8731 driver"); | 730 | MODULE_DESCRIPTION("ASoC WM8731 driver"); |
728 | MODULE_AUTHOR("Richard Purdie"); | 731 | MODULE_AUTHOR("Richard Purdie"); |
sound/soc/codecs/wm8750.c
1 | /* | 1 | /* |
2 | * wm8750.c -- WM8750 ALSA SoC audio driver | 2 | * wm8750.c -- WM8750 ALSA SoC audio driver |
3 | * | 3 | * |
4 | * Copyright 2005 Openedhand Ltd. | 4 | * Copyright 2005 Openedhand Ltd. |
5 | * | 5 | * |
6 | * Author: Richard Purdie <richard@openedhand.com> | 6 | * Author: Richard Purdie <richard@openedhand.com> |
7 | * | 7 | * |
8 | * Based on WM8753.c | 8 | * Based on WM8753.c |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License version 2 as | 11 | * it under the terms of the GNU General Public License version 2 as |
12 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/moduleparam.h> | 16 | #include <linux/moduleparam.h> |
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
19 | #include <linux/pm.h> | 19 | #include <linux/pm.h> |
20 | #include <linux/i2c.h> | 20 | #include <linux/i2c.h> |
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <sound/core.h> | 22 | #include <sound/core.h> |
23 | #include <sound/pcm.h> | 23 | #include <sound/pcm.h> |
24 | #include <sound/pcm_params.h> | 24 | #include <sound/pcm_params.h> |
25 | #include <sound/soc.h> | 25 | #include <sound/soc.h> |
26 | #include <sound/soc-dapm.h> | 26 | #include <sound/soc-dapm.h> |
27 | #include <sound/initval.h> | 27 | #include <sound/initval.h> |
28 | 28 | ||
29 | #include "wm8750.h" | 29 | #include "wm8750.h" |
30 | 30 | ||
31 | #define AUDIO_NAME "WM8750" | 31 | #define AUDIO_NAME "WM8750" |
32 | #define WM8750_VERSION "0.12" | 32 | #define WM8750_VERSION "0.12" |
33 | 33 | ||
34 | /* codec private data */ | 34 | /* codec private data */ |
35 | struct wm8750_priv { | 35 | struct wm8750_priv { |
36 | unsigned int sysclk; | 36 | unsigned int sysclk; |
37 | }; | 37 | }; |
38 | 38 | ||
39 | /* | 39 | /* |
40 | * wm8750 register cache | 40 | * wm8750 register cache |
41 | * We can't read the WM8750 register space when we | 41 | * We can't read the WM8750 register space when we |
42 | * are using 2 wire for device control, so we cache them instead. | 42 | * are using 2 wire for device control, so we cache them instead. |
43 | */ | 43 | */ |
44 | static const u16 wm8750_reg[] = { | 44 | static const u16 wm8750_reg[] = { |
45 | 0x0097, 0x0097, 0x0079, 0x0079, /* 0 */ | 45 | 0x0097, 0x0097, 0x0079, 0x0079, /* 0 */ |
46 | 0x0000, 0x0008, 0x0000, 0x000a, /* 4 */ | 46 | 0x0000, 0x0008, 0x0000, 0x000a, /* 4 */ |
47 | 0x0000, 0x0000, 0x00ff, 0x00ff, /* 8 */ | 47 | 0x0000, 0x0000, 0x00ff, 0x00ff, /* 8 */ |
48 | 0x000f, 0x000f, 0x0000, 0x0000, /* 12 */ | 48 | 0x000f, 0x000f, 0x0000, 0x0000, /* 12 */ |
49 | 0x0000, 0x007b, 0x0000, 0x0032, /* 16 */ | 49 | 0x0000, 0x007b, 0x0000, 0x0032, /* 16 */ |
50 | 0x0000, 0x00c3, 0x00c3, 0x00c0, /* 20 */ | 50 | 0x0000, 0x00c3, 0x00c3, 0x00c0, /* 20 */ |
51 | 0x0000, 0x0000, 0x0000, 0x0000, /* 24 */ | 51 | 0x0000, 0x0000, 0x0000, 0x0000, /* 24 */ |
52 | 0x0000, 0x0000, 0x0000, 0x0000, /* 28 */ | 52 | 0x0000, 0x0000, 0x0000, 0x0000, /* 28 */ |
53 | 0x0000, 0x0000, 0x0050, 0x0050, /* 32 */ | 53 | 0x0000, 0x0000, 0x0050, 0x0050, /* 32 */ |
54 | 0x0050, 0x0050, 0x0050, 0x0050, /* 36 */ | 54 | 0x0050, 0x0050, 0x0050, 0x0050, /* 36 */ |
55 | 0x0079, 0x0079, 0x0079, /* 40 */ | 55 | 0x0079, 0x0079, 0x0079, /* 40 */ |
56 | }; | 56 | }; |
57 | 57 | ||
58 | /* | 58 | /* |
59 | * read wm8750 register cache | 59 | * read wm8750 register cache |
60 | */ | 60 | */ |
61 | static inline unsigned int wm8750_read_reg_cache(struct snd_soc_codec *codec, | 61 | static inline unsigned int wm8750_read_reg_cache(struct snd_soc_codec *codec, |
62 | unsigned int reg) | 62 | unsigned int reg) |
63 | { | 63 | { |
64 | u16 *cache = codec->reg_cache; | 64 | u16 *cache = codec->reg_cache; |
65 | if (reg > WM8750_CACHE_REGNUM) | 65 | if (reg > WM8750_CACHE_REGNUM) |
66 | return -1; | 66 | return -1; |
67 | return cache[reg]; | 67 | return cache[reg]; |
68 | } | 68 | } |
69 | 69 | ||
70 | /* | 70 | /* |
71 | * write wm8750 register cache | 71 | * write wm8750 register cache |
72 | */ | 72 | */ |
73 | static inline void wm8750_write_reg_cache(struct snd_soc_codec *codec, | 73 | static inline void wm8750_write_reg_cache(struct snd_soc_codec *codec, |
74 | unsigned int reg, unsigned int value) | 74 | unsigned int reg, unsigned int value) |
75 | { | 75 | { |
76 | u16 *cache = codec->reg_cache; | 76 | u16 *cache = codec->reg_cache; |
77 | if (reg > WM8750_CACHE_REGNUM) | 77 | if (reg > WM8750_CACHE_REGNUM) |
78 | return; | 78 | return; |
79 | cache[reg] = value; | 79 | cache[reg] = value; |
80 | } | 80 | } |
81 | 81 | ||
82 | static int wm8750_write(struct snd_soc_codec *codec, unsigned int reg, | 82 | static int wm8750_write(struct snd_soc_codec *codec, unsigned int reg, |
83 | unsigned int value) | 83 | unsigned int value) |
84 | { | 84 | { |
85 | u8 data[2]; | 85 | u8 data[2]; |
86 | 86 | ||
87 | /* data is | 87 | /* data is |
88 | * D15..D9 WM8753 register offset | 88 | * D15..D9 WM8753 register offset |
89 | * D8...D0 register data | 89 | * D8...D0 register data |
90 | */ | 90 | */ |
91 | data[0] = (reg << 1) | ((value >> 8) & 0x0001); | 91 | data[0] = (reg << 1) | ((value >> 8) & 0x0001); |
92 | data[1] = value & 0x00ff; | 92 | data[1] = value & 0x00ff; |
93 | 93 | ||
94 | wm8750_write_reg_cache(codec, reg, value); | 94 | wm8750_write_reg_cache(codec, reg, value); |
95 | if (codec->hw_write(codec->control_data, data, 2) == 2) | 95 | if (codec->hw_write(codec->control_data, data, 2) == 2) |
96 | return 0; | 96 | return 0; |
97 | else | 97 | else |
98 | return -EIO; | 98 | return -EIO; |
99 | } | 99 | } |
100 | 100 | ||
101 | #define wm8750_reset(c) wm8750_write(c, WM8750_RESET, 0) | 101 | #define wm8750_reset(c) wm8750_write(c, WM8750_RESET, 0) |
102 | 102 | ||
103 | /* | 103 | /* |
104 | * WM8750 Controls | 104 | * WM8750 Controls |
105 | */ | 105 | */ |
106 | static const char *wm8750_bass[] = {"Linear Control", "Adaptive Boost"}; | 106 | static const char *wm8750_bass[] = {"Linear Control", "Adaptive Boost"}; |
107 | static const char *wm8750_bass_filter[] = { "130Hz @ 48kHz", "200Hz @ 48kHz" }; | 107 | static const char *wm8750_bass_filter[] = { "130Hz @ 48kHz", "200Hz @ 48kHz" }; |
108 | static const char *wm8750_treble[] = {"8kHz", "4kHz"}; | 108 | static const char *wm8750_treble[] = {"8kHz", "4kHz"}; |
109 | static const char *wm8750_3d_lc[] = {"200Hz", "500Hz"}; | 109 | static const char *wm8750_3d_lc[] = {"200Hz", "500Hz"}; |
110 | static const char *wm8750_3d_uc[] = {"2.2kHz", "1.5kHz"}; | 110 | static const char *wm8750_3d_uc[] = {"2.2kHz", "1.5kHz"}; |
111 | static const char *wm8750_3d_func[] = {"Capture", "Playback"}; | 111 | static const char *wm8750_3d_func[] = {"Capture", "Playback"}; |
112 | static const char *wm8750_alc_func[] = {"Off", "Right", "Left", "Stereo"}; | 112 | static const char *wm8750_alc_func[] = {"Off", "Right", "Left", "Stereo"}; |
113 | static const char *wm8750_ng_type[] = {"Constant PGA Gain", | 113 | static const char *wm8750_ng_type[] = {"Constant PGA Gain", |
114 | "Mute ADC Output"}; | 114 | "Mute ADC Output"}; |
115 | static const char *wm8750_line_mux[] = {"Line 1", "Line 2", "Line 3", "PGA", | 115 | static const char *wm8750_line_mux[] = {"Line 1", "Line 2", "Line 3", "PGA", |
116 | "Differential"}; | 116 | "Differential"}; |
117 | static const char *wm8750_pga_sel[] = {"Line 1", "Line 2", "Line 3", | 117 | static const char *wm8750_pga_sel[] = {"Line 1", "Line 2", "Line 3", |
118 | "Differential"}; | 118 | "Differential"}; |
119 | static const char *wm8750_out3[] = {"VREF", "ROUT1 + Vol", "MonoOut", | 119 | static const char *wm8750_out3[] = {"VREF", "ROUT1 + Vol", "MonoOut", |
120 | "ROUT1"}; | 120 | "ROUT1"}; |
121 | static const char *wm8750_diff_sel[] = {"Line 1", "Line 2"}; | 121 | static const char *wm8750_diff_sel[] = {"Line 1", "Line 2"}; |
122 | static const char *wm8750_adcpol[] = {"Normal", "L Invert", "R Invert", | 122 | static const char *wm8750_adcpol[] = {"Normal", "L Invert", "R Invert", |
123 | "L + R Invert"}; | 123 | "L + R Invert"}; |
124 | static const char *wm8750_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; | 124 | static const char *wm8750_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; |
125 | static const char *wm8750_mono_mux[] = {"Stereo", "Mono (Left)", | 125 | static const char *wm8750_mono_mux[] = {"Stereo", "Mono (Left)", |
126 | "Mono (Right)", "Digital Mono"}; | 126 | "Mono (Right)", "Digital Mono"}; |
127 | 127 | ||
128 | static const struct soc_enum wm8750_enum[] = { | 128 | static const struct soc_enum wm8750_enum[] = { |
129 | SOC_ENUM_SINGLE(WM8750_BASS, 7, 2, wm8750_bass), | 129 | SOC_ENUM_SINGLE(WM8750_BASS, 7, 2, wm8750_bass), |
130 | SOC_ENUM_SINGLE(WM8750_BASS, 6, 2, wm8750_bass_filter), | 130 | SOC_ENUM_SINGLE(WM8750_BASS, 6, 2, wm8750_bass_filter), |
131 | SOC_ENUM_SINGLE(WM8750_TREBLE, 6, 2, wm8750_treble), | 131 | SOC_ENUM_SINGLE(WM8750_TREBLE, 6, 2, wm8750_treble), |
132 | SOC_ENUM_SINGLE(WM8750_3D, 5, 2, wm8750_3d_lc), | 132 | SOC_ENUM_SINGLE(WM8750_3D, 5, 2, wm8750_3d_lc), |
133 | SOC_ENUM_SINGLE(WM8750_3D, 6, 2, wm8750_3d_uc), | 133 | SOC_ENUM_SINGLE(WM8750_3D, 6, 2, wm8750_3d_uc), |
134 | SOC_ENUM_SINGLE(WM8750_3D, 7, 2, wm8750_3d_func), | 134 | SOC_ENUM_SINGLE(WM8750_3D, 7, 2, wm8750_3d_func), |
135 | SOC_ENUM_SINGLE(WM8750_ALC1, 7, 4, wm8750_alc_func), | 135 | SOC_ENUM_SINGLE(WM8750_ALC1, 7, 4, wm8750_alc_func), |
136 | SOC_ENUM_SINGLE(WM8750_NGATE, 1, 2, wm8750_ng_type), | 136 | SOC_ENUM_SINGLE(WM8750_NGATE, 1, 2, wm8750_ng_type), |
137 | SOC_ENUM_SINGLE(WM8750_LOUTM1, 0, 5, wm8750_line_mux), | 137 | SOC_ENUM_SINGLE(WM8750_LOUTM1, 0, 5, wm8750_line_mux), |
138 | SOC_ENUM_SINGLE(WM8750_ROUTM1, 0, 5, wm8750_line_mux), | 138 | SOC_ENUM_SINGLE(WM8750_ROUTM1, 0, 5, wm8750_line_mux), |
139 | SOC_ENUM_SINGLE(WM8750_LADCIN, 6, 4, wm8750_pga_sel), /* 10 */ | 139 | SOC_ENUM_SINGLE(WM8750_LADCIN, 6, 4, wm8750_pga_sel), /* 10 */ |
140 | SOC_ENUM_SINGLE(WM8750_RADCIN, 6, 4, wm8750_pga_sel), | 140 | SOC_ENUM_SINGLE(WM8750_RADCIN, 6, 4, wm8750_pga_sel), |
141 | SOC_ENUM_SINGLE(WM8750_ADCTL2, 7, 4, wm8750_out3), | 141 | SOC_ENUM_SINGLE(WM8750_ADCTL2, 7, 4, wm8750_out3), |
142 | SOC_ENUM_SINGLE(WM8750_ADCIN, 8, 2, wm8750_diff_sel), | 142 | SOC_ENUM_SINGLE(WM8750_ADCIN, 8, 2, wm8750_diff_sel), |
143 | SOC_ENUM_SINGLE(WM8750_ADCDAC, 5, 4, wm8750_adcpol), | 143 | SOC_ENUM_SINGLE(WM8750_ADCDAC, 5, 4, wm8750_adcpol), |
144 | SOC_ENUM_SINGLE(WM8750_ADCDAC, 1, 4, wm8750_deemph), | 144 | SOC_ENUM_SINGLE(WM8750_ADCDAC, 1, 4, wm8750_deemph), |
145 | SOC_ENUM_SINGLE(WM8750_ADCIN, 6, 4, wm8750_mono_mux), /* 16 */ | 145 | SOC_ENUM_SINGLE(WM8750_ADCIN, 6, 4, wm8750_mono_mux), /* 16 */ |
146 | 146 | ||
147 | }; | 147 | }; |
148 | 148 | ||
149 | static const struct snd_kcontrol_new wm8750_snd_controls[] = { | 149 | static const struct snd_kcontrol_new wm8750_snd_controls[] = { |
150 | 150 | ||
151 | SOC_DOUBLE_R("Capture Volume", WM8750_LINVOL, WM8750_RINVOL, 0, 63, 0), | 151 | SOC_DOUBLE_R("Capture Volume", WM8750_LINVOL, WM8750_RINVOL, 0, 63, 0), |
152 | SOC_DOUBLE_R("Capture ZC Switch", WM8750_LINVOL, WM8750_RINVOL, 6, 1, 0), | 152 | SOC_DOUBLE_R("Capture ZC Switch", WM8750_LINVOL, WM8750_RINVOL, 6, 1, 0), |
153 | SOC_DOUBLE_R("Capture Switch", WM8750_LINVOL, WM8750_RINVOL, 7, 1, 1), | 153 | SOC_DOUBLE_R("Capture Switch", WM8750_LINVOL, WM8750_RINVOL, 7, 1, 1), |
154 | 154 | ||
155 | SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8750_LOUT1V, | 155 | SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8750_LOUT1V, |
156 | WM8750_ROUT1V, 7, 1, 0), | 156 | WM8750_ROUT1V, 7, 1, 0), |
157 | SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8750_LOUT2V, | 157 | SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8750_LOUT2V, |
158 | WM8750_ROUT2V, 7, 1, 0), | 158 | WM8750_ROUT2V, 7, 1, 0), |
159 | 159 | ||
160 | SOC_ENUM("Playback De-emphasis", wm8750_enum[15]), | 160 | SOC_ENUM("Playback De-emphasis", wm8750_enum[15]), |
161 | 161 | ||
162 | SOC_ENUM("Capture Polarity", wm8750_enum[14]), | 162 | SOC_ENUM("Capture Polarity", wm8750_enum[14]), |
163 | SOC_SINGLE("Playback 6dB Attenuate", WM8750_ADCDAC, 7, 1, 0), | 163 | SOC_SINGLE("Playback 6dB Attenuate", WM8750_ADCDAC, 7, 1, 0), |
164 | SOC_SINGLE("Capture 6dB Attenuate", WM8750_ADCDAC, 8, 1, 0), | 164 | SOC_SINGLE("Capture 6dB Attenuate", WM8750_ADCDAC, 8, 1, 0), |
165 | 165 | ||
166 | SOC_DOUBLE_R("PCM Volume", WM8750_LDAC, WM8750_RDAC, 0, 255, 0), | 166 | SOC_DOUBLE_R("PCM Volume", WM8750_LDAC, WM8750_RDAC, 0, 255, 0), |
167 | 167 | ||
168 | SOC_ENUM("Bass Boost", wm8750_enum[0]), | 168 | SOC_ENUM("Bass Boost", wm8750_enum[0]), |
169 | SOC_ENUM("Bass Filter", wm8750_enum[1]), | 169 | SOC_ENUM("Bass Filter", wm8750_enum[1]), |
170 | SOC_SINGLE("Bass Volume", WM8750_BASS, 0, 15, 1), | 170 | SOC_SINGLE("Bass Volume", WM8750_BASS, 0, 15, 1), |
171 | 171 | ||
172 | SOC_SINGLE("Treble Volume", WM8750_TREBLE, 0, 15, 1), | 172 | SOC_SINGLE("Treble Volume", WM8750_TREBLE, 0, 15, 1), |
173 | SOC_ENUM("Treble Cut-off", wm8750_enum[2]), | 173 | SOC_ENUM("Treble Cut-off", wm8750_enum[2]), |
174 | 174 | ||
175 | SOC_SINGLE("3D Switch", WM8750_3D, 0, 1, 0), | 175 | SOC_SINGLE("3D Switch", WM8750_3D, 0, 1, 0), |
176 | SOC_SINGLE("3D Volume", WM8750_3D, 1, 15, 0), | 176 | SOC_SINGLE("3D Volume", WM8750_3D, 1, 15, 0), |
177 | SOC_ENUM("3D Lower Cut-off", wm8750_enum[3]), | 177 | SOC_ENUM("3D Lower Cut-off", wm8750_enum[3]), |
178 | SOC_ENUM("3D Upper Cut-off", wm8750_enum[4]), | 178 | SOC_ENUM("3D Upper Cut-off", wm8750_enum[4]), |
179 | SOC_ENUM("3D Mode", wm8750_enum[5]), | 179 | SOC_ENUM("3D Mode", wm8750_enum[5]), |
180 | 180 | ||
181 | SOC_SINGLE("ALC Capture Target Volume", WM8750_ALC1, 0, 7, 0), | 181 | SOC_SINGLE("ALC Capture Target Volume", WM8750_ALC1, 0, 7, 0), |
182 | SOC_SINGLE("ALC Capture Max Volume", WM8750_ALC1, 4, 7, 0), | 182 | SOC_SINGLE("ALC Capture Max Volume", WM8750_ALC1, 4, 7, 0), |
183 | SOC_ENUM("ALC Capture Function", wm8750_enum[6]), | 183 | SOC_ENUM("ALC Capture Function", wm8750_enum[6]), |
184 | SOC_SINGLE("ALC Capture ZC Switch", WM8750_ALC2, 7, 1, 0), | 184 | SOC_SINGLE("ALC Capture ZC Switch", WM8750_ALC2, 7, 1, 0), |
185 | SOC_SINGLE("ALC Capture Hold Time", WM8750_ALC2, 0, 15, 0), | 185 | SOC_SINGLE("ALC Capture Hold Time", WM8750_ALC2, 0, 15, 0), |
186 | SOC_SINGLE("ALC Capture Decay Time", WM8750_ALC3, 4, 15, 0), | 186 | SOC_SINGLE("ALC Capture Decay Time", WM8750_ALC3, 4, 15, 0), |
187 | SOC_SINGLE("ALC Capture Attack Time", WM8750_ALC3, 0, 15, 0), | 187 | SOC_SINGLE("ALC Capture Attack Time", WM8750_ALC3, 0, 15, 0), |
188 | SOC_SINGLE("ALC Capture NG Threshold", WM8750_NGATE, 3, 31, 0), | 188 | SOC_SINGLE("ALC Capture NG Threshold", WM8750_NGATE, 3, 31, 0), |
189 | SOC_ENUM("ALC Capture NG Type", wm8750_enum[4]), | 189 | SOC_ENUM("ALC Capture NG Type", wm8750_enum[4]), |
190 | SOC_SINGLE("ALC Capture NG Switch", WM8750_NGATE, 0, 1, 0), | 190 | SOC_SINGLE("ALC Capture NG Switch", WM8750_NGATE, 0, 1, 0), |
191 | 191 | ||
192 | SOC_SINGLE("Left ADC Capture Volume", WM8750_LADC, 0, 255, 0), | 192 | SOC_SINGLE("Left ADC Capture Volume", WM8750_LADC, 0, 255, 0), |
193 | SOC_SINGLE("Right ADC Capture Volume", WM8750_RADC, 0, 255, 0), | 193 | SOC_SINGLE("Right ADC Capture Volume", WM8750_RADC, 0, 255, 0), |
194 | 194 | ||
195 | SOC_SINGLE("ZC Timeout Switch", WM8750_ADCTL1, 0, 1, 0), | 195 | SOC_SINGLE("ZC Timeout Switch", WM8750_ADCTL1, 0, 1, 0), |
196 | SOC_SINGLE("Playback Invert Switch", WM8750_ADCTL1, 1, 1, 0), | 196 | SOC_SINGLE("Playback Invert Switch", WM8750_ADCTL1, 1, 1, 0), |
197 | 197 | ||
198 | SOC_SINGLE("Right Speaker Playback Invert Switch", WM8750_ADCTL2, 4, 1, 0), | 198 | SOC_SINGLE("Right Speaker Playback Invert Switch", WM8750_ADCTL2, 4, 1, 0), |
199 | 199 | ||
200 | /* Unimplemented */ | 200 | /* Unimplemented */ |
201 | /* ADCDAC Bit 0 - ADCHPD */ | 201 | /* ADCDAC Bit 0 - ADCHPD */ |
202 | /* ADCDAC Bit 4 - HPOR */ | 202 | /* ADCDAC Bit 4 - HPOR */ |
203 | /* ADCTL1 Bit 2,3 - DATSEL */ | 203 | /* ADCTL1 Bit 2,3 - DATSEL */ |
204 | /* ADCTL1 Bit 4,5 - DMONOMIX */ | 204 | /* ADCTL1 Bit 4,5 - DMONOMIX */ |
205 | /* ADCTL1 Bit 6,7 - VSEL */ | 205 | /* ADCTL1 Bit 6,7 - VSEL */ |
206 | /* ADCTL2 Bit 2 - LRCM */ | 206 | /* ADCTL2 Bit 2 - LRCM */ |
207 | /* ADCTL2 Bit 3 - TRI */ | 207 | /* ADCTL2 Bit 3 - TRI */ |
208 | /* ADCTL3 Bit 5 - HPFLREN */ | 208 | /* ADCTL3 Bit 5 - HPFLREN */ |
209 | /* ADCTL3 Bit 6 - VROI */ | 209 | /* ADCTL3 Bit 6 - VROI */ |
210 | /* ADCTL3 Bit 7,8 - ADCLRM */ | 210 | /* ADCTL3 Bit 7,8 - ADCLRM */ |
211 | /* ADCIN Bit 4 - LDCM */ | 211 | /* ADCIN Bit 4 - LDCM */ |
212 | /* ADCIN Bit 5 - RDCM */ | 212 | /* ADCIN Bit 5 - RDCM */ |
213 | 213 | ||
214 | SOC_DOUBLE_R("Mic Boost", WM8750_LADCIN, WM8750_RADCIN, 4, 3, 0), | 214 | SOC_DOUBLE_R("Mic Boost", WM8750_LADCIN, WM8750_RADCIN, 4, 3, 0), |
215 | 215 | ||
216 | SOC_DOUBLE_R("Bypass Left Playback Volume", WM8750_LOUTM1, | 216 | SOC_DOUBLE_R("Bypass Left Playback Volume", WM8750_LOUTM1, |
217 | WM8750_LOUTM2, 4, 7, 1), | 217 | WM8750_LOUTM2, 4, 7, 1), |
218 | SOC_DOUBLE_R("Bypass Right Playback Volume", WM8750_ROUTM1, | 218 | SOC_DOUBLE_R("Bypass Right Playback Volume", WM8750_ROUTM1, |
219 | WM8750_ROUTM2, 4, 7, 1), | 219 | WM8750_ROUTM2, 4, 7, 1), |
220 | SOC_DOUBLE_R("Bypass Mono Playback Volume", WM8750_MOUTM1, | 220 | SOC_DOUBLE_R("Bypass Mono Playback Volume", WM8750_MOUTM1, |
221 | WM8750_MOUTM2, 4, 7, 1), | 221 | WM8750_MOUTM2, 4, 7, 1), |
222 | 222 | ||
223 | SOC_SINGLE("Mono Playback ZC Switch", WM8750_MOUTV, 7, 1, 0), | 223 | SOC_SINGLE("Mono Playback ZC Switch", WM8750_MOUTV, 7, 1, 0), |
224 | 224 | ||
225 | SOC_DOUBLE_R("Headphone Playback Volume", WM8750_LOUT1V, WM8750_ROUT1V, | 225 | SOC_DOUBLE_R("Headphone Playback Volume", WM8750_LOUT1V, WM8750_ROUT1V, |
226 | 0, 127, 0), | 226 | 0, 127, 0), |
227 | SOC_DOUBLE_R("Speaker Playback Volume", WM8750_LOUT2V, WM8750_ROUT2V, | 227 | SOC_DOUBLE_R("Speaker Playback Volume", WM8750_LOUT2V, WM8750_ROUT2V, |
228 | 0, 127, 0), | 228 | 0, 127, 0), |
229 | 229 | ||
230 | SOC_SINGLE("Mono Playback Volume", WM8750_MOUTV, 0, 127, 0), | 230 | SOC_SINGLE("Mono Playback Volume", WM8750_MOUTV, 0, 127, 0), |
231 | 231 | ||
232 | }; | 232 | }; |
233 | 233 | ||
234 | /* add non dapm controls */ | 234 | /* add non dapm controls */ |
235 | static int wm8750_add_controls(struct snd_soc_codec *codec) | 235 | static int wm8750_add_controls(struct snd_soc_codec *codec) |
236 | { | 236 | { |
237 | int err, i; | 237 | int err, i; |
238 | 238 | ||
239 | for (i = 0; i < ARRAY_SIZE(wm8750_snd_controls); i++) { | 239 | for (i = 0; i < ARRAY_SIZE(wm8750_snd_controls); i++) { |
240 | err = snd_ctl_add(codec->card, | 240 | err = snd_ctl_add(codec->card, |
241 | snd_soc_cnew(&wm8750_snd_controls[i], | 241 | snd_soc_cnew(&wm8750_snd_controls[i], |
242 | codec, NULL)); | 242 | codec, NULL)); |
243 | if (err < 0) | 243 | if (err < 0) |
244 | return err; | 244 | return err; |
245 | } | 245 | } |
246 | return 0; | 246 | return 0; |
247 | } | 247 | } |
248 | 248 | ||
249 | /* | 249 | /* |
250 | * DAPM Controls | 250 | * DAPM Controls |
251 | */ | 251 | */ |
252 | 252 | ||
253 | /* Left Mixer */ | 253 | /* Left Mixer */ |
254 | static const struct snd_kcontrol_new wm8750_left_mixer_controls[] = { | 254 | static const struct snd_kcontrol_new wm8750_left_mixer_controls[] = { |
255 | SOC_DAPM_SINGLE("Playback Switch", WM8750_LOUTM1, 8, 1, 0), | 255 | SOC_DAPM_SINGLE("Playback Switch", WM8750_LOUTM1, 8, 1, 0), |
256 | SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_LOUTM1, 7, 1, 0), | 256 | SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_LOUTM1, 7, 1, 0), |
257 | SOC_DAPM_SINGLE("Right Playback Switch", WM8750_LOUTM2, 8, 1, 0), | 257 | SOC_DAPM_SINGLE("Right Playback Switch", WM8750_LOUTM2, 8, 1, 0), |
258 | SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_LOUTM2, 7, 1, 0), | 258 | SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_LOUTM2, 7, 1, 0), |
259 | }; | 259 | }; |
260 | 260 | ||
261 | /* Right Mixer */ | 261 | /* Right Mixer */ |
262 | static const struct snd_kcontrol_new wm8750_right_mixer_controls[] = { | 262 | static const struct snd_kcontrol_new wm8750_right_mixer_controls[] = { |
263 | SOC_DAPM_SINGLE("Left Playback Switch", WM8750_ROUTM1, 8, 1, 0), | 263 | SOC_DAPM_SINGLE("Left Playback Switch", WM8750_ROUTM1, 8, 1, 0), |
264 | SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_ROUTM1, 7, 1, 0), | 264 | SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_ROUTM1, 7, 1, 0), |
265 | SOC_DAPM_SINGLE("Playback Switch", WM8750_ROUTM2, 8, 1, 0), | 265 | SOC_DAPM_SINGLE("Playback Switch", WM8750_ROUTM2, 8, 1, 0), |
266 | SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_ROUTM2, 7, 1, 0), | 266 | SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_ROUTM2, 7, 1, 0), |
267 | }; | 267 | }; |
268 | 268 | ||
269 | /* Mono Mixer */ | 269 | /* Mono Mixer */ |
270 | static const struct snd_kcontrol_new wm8750_mono_mixer_controls[] = { | 270 | static const struct snd_kcontrol_new wm8750_mono_mixer_controls[] = { |
271 | SOC_DAPM_SINGLE("Left Playback Switch", WM8750_MOUTM1, 8, 1, 0), | 271 | SOC_DAPM_SINGLE("Left Playback Switch", WM8750_MOUTM1, 8, 1, 0), |
272 | SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_MOUTM1, 7, 1, 0), | 272 | SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_MOUTM1, 7, 1, 0), |
273 | SOC_DAPM_SINGLE("Right Playback Switch", WM8750_MOUTM2, 8, 1, 0), | 273 | SOC_DAPM_SINGLE("Right Playback Switch", WM8750_MOUTM2, 8, 1, 0), |
274 | SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_MOUTM2, 7, 1, 0), | 274 | SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_MOUTM2, 7, 1, 0), |
275 | }; | 275 | }; |
276 | 276 | ||
277 | /* Left Line Mux */ | 277 | /* Left Line Mux */ |
278 | static const struct snd_kcontrol_new wm8750_left_line_controls = | 278 | static const struct snd_kcontrol_new wm8750_left_line_controls = |
279 | SOC_DAPM_ENUM("Route", wm8750_enum[8]); | 279 | SOC_DAPM_ENUM("Route", wm8750_enum[8]); |
280 | 280 | ||
281 | /* Right Line Mux */ | 281 | /* Right Line Mux */ |
282 | static const struct snd_kcontrol_new wm8750_right_line_controls = | 282 | static const struct snd_kcontrol_new wm8750_right_line_controls = |
283 | SOC_DAPM_ENUM("Route", wm8750_enum[9]); | 283 | SOC_DAPM_ENUM("Route", wm8750_enum[9]); |
284 | 284 | ||
285 | /* Left PGA Mux */ | 285 | /* Left PGA Mux */ |
286 | static const struct snd_kcontrol_new wm8750_left_pga_controls = | 286 | static const struct snd_kcontrol_new wm8750_left_pga_controls = |
287 | SOC_DAPM_ENUM("Route", wm8750_enum[10]); | 287 | SOC_DAPM_ENUM("Route", wm8750_enum[10]); |
288 | 288 | ||
289 | /* Right PGA Mux */ | 289 | /* Right PGA Mux */ |
290 | static const struct snd_kcontrol_new wm8750_right_pga_controls = | 290 | static const struct snd_kcontrol_new wm8750_right_pga_controls = |
291 | SOC_DAPM_ENUM("Route", wm8750_enum[11]); | 291 | SOC_DAPM_ENUM("Route", wm8750_enum[11]); |
292 | 292 | ||
293 | /* Out 3 Mux */ | 293 | /* Out 3 Mux */ |
294 | static const struct snd_kcontrol_new wm8750_out3_controls = | 294 | static const struct snd_kcontrol_new wm8750_out3_controls = |
295 | SOC_DAPM_ENUM("Route", wm8750_enum[12]); | 295 | SOC_DAPM_ENUM("Route", wm8750_enum[12]); |
296 | 296 | ||
297 | /* Differential Mux */ | 297 | /* Differential Mux */ |
298 | static const struct snd_kcontrol_new wm8750_diffmux_controls = | 298 | static const struct snd_kcontrol_new wm8750_diffmux_controls = |
299 | SOC_DAPM_ENUM("Route", wm8750_enum[13]); | 299 | SOC_DAPM_ENUM("Route", wm8750_enum[13]); |
300 | 300 | ||
301 | /* Mono ADC Mux */ | 301 | /* Mono ADC Mux */ |
302 | static const struct snd_kcontrol_new wm8750_monomux_controls = | 302 | static const struct snd_kcontrol_new wm8750_monomux_controls = |
303 | SOC_DAPM_ENUM("Route", wm8750_enum[16]); | 303 | SOC_DAPM_ENUM("Route", wm8750_enum[16]); |
304 | 304 | ||
305 | static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = { | 305 | static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = { |
306 | SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0, | 306 | SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0, |
307 | &wm8750_left_mixer_controls[0], | 307 | &wm8750_left_mixer_controls[0], |
308 | ARRAY_SIZE(wm8750_left_mixer_controls)), | 308 | ARRAY_SIZE(wm8750_left_mixer_controls)), |
309 | SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0, | 309 | SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0, |
310 | &wm8750_right_mixer_controls[0], | 310 | &wm8750_right_mixer_controls[0], |
311 | ARRAY_SIZE(wm8750_right_mixer_controls)), | 311 | ARRAY_SIZE(wm8750_right_mixer_controls)), |
312 | SND_SOC_DAPM_MIXER("Mono Mixer", WM8750_PWR2, 2, 0, | 312 | SND_SOC_DAPM_MIXER("Mono Mixer", WM8750_PWR2, 2, 0, |
313 | &wm8750_mono_mixer_controls[0], | 313 | &wm8750_mono_mixer_controls[0], |
314 | ARRAY_SIZE(wm8750_mono_mixer_controls)), | 314 | ARRAY_SIZE(wm8750_mono_mixer_controls)), |
315 | 315 | ||
316 | SND_SOC_DAPM_PGA("Right Out 2", WM8750_PWR2, 3, 0, NULL, 0), | 316 | SND_SOC_DAPM_PGA("Right Out 2", WM8750_PWR2, 3, 0, NULL, 0), |
317 | SND_SOC_DAPM_PGA("Left Out 2", WM8750_PWR2, 4, 0, NULL, 0), | 317 | SND_SOC_DAPM_PGA("Left Out 2", WM8750_PWR2, 4, 0, NULL, 0), |
318 | SND_SOC_DAPM_PGA("Right Out 1", WM8750_PWR2, 5, 0, NULL, 0), | 318 | SND_SOC_DAPM_PGA("Right Out 1", WM8750_PWR2, 5, 0, NULL, 0), |
319 | SND_SOC_DAPM_PGA("Left Out 1", WM8750_PWR2, 6, 0, NULL, 0), | 319 | SND_SOC_DAPM_PGA("Left Out 1", WM8750_PWR2, 6, 0, NULL, 0), |
320 | SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8750_PWR2, 7, 0), | 320 | SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8750_PWR2, 7, 0), |
321 | SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8750_PWR2, 8, 0), | 321 | SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8750_PWR2, 8, 0), |
322 | 322 | ||
323 | SND_SOC_DAPM_MICBIAS("Mic Bias", WM8750_PWR1, 1, 0), | 323 | SND_SOC_DAPM_MICBIAS("Mic Bias", WM8750_PWR1, 1, 0), |
324 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8750_PWR1, 2, 0), | 324 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8750_PWR1, 2, 0), |
325 | SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8750_PWR1, 3, 0), | 325 | SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8750_PWR1, 3, 0), |
326 | 326 | ||
327 | SND_SOC_DAPM_MUX("Left PGA Mux", WM8750_PWR1, 5, 0, | 327 | SND_SOC_DAPM_MUX("Left PGA Mux", WM8750_PWR1, 5, 0, |
328 | &wm8750_left_pga_controls), | 328 | &wm8750_left_pga_controls), |
329 | SND_SOC_DAPM_MUX("Right PGA Mux", WM8750_PWR1, 4, 0, | 329 | SND_SOC_DAPM_MUX("Right PGA Mux", WM8750_PWR1, 4, 0, |
330 | &wm8750_right_pga_controls), | 330 | &wm8750_right_pga_controls), |
331 | SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0, | 331 | SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0, |
332 | &wm8750_left_line_controls), | 332 | &wm8750_left_line_controls), |
333 | SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0, | 333 | SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0, |
334 | &wm8750_right_line_controls), | 334 | &wm8750_right_line_controls), |
335 | 335 | ||
336 | SND_SOC_DAPM_MUX("Out3 Mux", SND_SOC_NOPM, 0, 0, &wm8750_out3_controls), | 336 | SND_SOC_DAPM_MUX("Out3 Mux", SND_SOC_NOPM, 0, 0, &wm8750_out3_controls), |
337 | SND_SOC_DAPM_PGA("Out 3", WM8750_PWR2, 1, 0, NULL, 0), | 337 | SND_SOC_DAPM_PGA("Out 3", WM8750_PWR2, 1, 0, NULL, 0), |
338 | SND_SOC_DAPM_PGA("Mono Out 1", WM8750_PWR2, 2, 0, NULL, 0), | 338 | SND_SOC_DAPM_PGA("Mono Out 1", WM8750_PWR2, 2, 0, NULL, 0), |
339 | 339 | ||
340 | SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0, | 340 | SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0, |
341 | &wm8750_diffmux_controls), | 341 | &wm8750_diffmux_controls), |
342 | SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0, | 342 | SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0, |
343 | &wm8750_monomux_controls), | 343 | &wm8750_monomux_controls), |
344 | SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0, | 344 | SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0, |
345 | &wm8750_monomux_controls), | 345 | &wm8750_monomux_controls), |
346 | 346 | ||
347 | SND_SOC_DAPM_OUTPUT("LOUT1"), | 347 | SND_SOC_DAPM_OUTPUT("LOUT1"), |
348 | SND_SOC_DAPM_OUTPUT("ROUT1"), | 348 | SND_SOC_DAPM_OUTPUT("ROUT1"), |
349 | SND_SOC_DAPM_OUTPUT("LOUT2"), | 349 | SND_SOC_DAPM_OUTPUT("LOUT2"), |
350 | SND_SOC_DAPM_OUTPUT("ROUT2"), | 350 | SND_SOC_DAPM_OUTPUT("ROUT2"), |
351 | SND_SOC_DAPM_OUTPUT("MONO1"), | 351 | SND_SOC_DAPM_OUTPUT("MONO1"), |
352 | SND_SOC_DAPM_OUTPUT("OUT3"), | 352 | SND_SOC_DAPM_OUTPUT("OUT3"), |
353 | SND_SOC_DAPM_OUTPUT("VREF"), | 353 | SND_SOC_DAPM_OUTPUT("VREF"), |
354 | 354 | ||
355 | SND_SOC_DAPM_INPUT("LINPUT1"), | 355 | SND_SOC_DAPM_INPUT("LINPUT1"), |
356 | SND_SOC_DAPM_INPUT("LINPUT2"), | 356 | SND_SOC_DAPM_INPUT("LINPUT2"), |
357 | SND_SOC_DAPM_INPUT("LINPUT3"), | 357 | SND_SOC_DAPM_INPUT("LINPUT3"), |
358 | SND_SOC_DAPM_INPUT("RINPUT1"), | 358 | SND_SOC_DAPM_INPUT("RINPUT1"), |
359 | SND_SOC_DAPM_INPUT("RINPUT2"), | 359 | SND_SOC_DAPM_INPUT("RINPUT2"), |
360 | SND_SOC_DAPM_INPUT("RINPUT3"), | 360 | SND_SOC_DAPM_INPUT("RINPUT3"), |
361 | }; | 361 | }; |
362 | 362 | ||
363 | static const struct snd_soc_dapm_route audio_map[] = { | 363 | static const struct snd_soc_dapm_route audio_map[] = { |
364 | /* left mixer */ | 364 | /* left mixer */ |
365 | {"Left Mixer", "Playback Switch", "Left DAC"}, | 365 | {"Left Mixer", "Playback Switch", "Left DAC"}, |
366 | {"Left Mixer", "Left Bypass Switch", "Left Line Mux"}, | 366 | {"Left Mixer", "Left Bypass Switch", "Left Line Mux"}, |
367 | {"Left Mixer", "Right Playback Switch", "Right DAC"}, | 367 | {"Left Mixer", "Right Playback Switch", "Right DAC"}, |
368 | {"Left Mixer", "Right Bypass Switch", "Right Line Mux"}, | 368 | {"Left Mixer", "Right Bypass Switch", "Right Line Mux"}, |
369 | 369 | ||
370 | /* right mixer */ | 370 | /* right mixer */ |
371 | {"Right Mixer", "Left Playback Switch", "Left DAC"}, | 371 | {"Right Mixer", "Left Playback Switch", "Left DAC"}, |
372 | {"Right Mixer", "Left Bypass Switch", "Left Line Mux"}, | 372 | {"Right Mixer", "Left Bypass Switch", "Left Line Mux"}, |
373 | {"Right Mixer", "Playback Switch", "Right DAC"}, | 373 | {"Right Mixer", "Playback Switch", "Right DAC"}, |
374 | {"Right Mixer", "Right Bypass Switch", "Right Line Mux"}, | 374 | {"Right Mixer", "Right Bypass Switch", "Right Line Mux"}, |
375 | 375 | ||
376 | /* left out 1 */ | 376 | /* left out 1 */ |
377 | {"Left Out 1", NULL, "Left Mixer"}, | 377 | {"Left Out 1", NULL, "Left Mixer"}, |
378 | {"LOUT1", NULL, "Left Out 1"}, | 378 | {"LOUT1", NULL, "Left Out 1"}, |
379 | 379 | ||
380 | /* left out 2 */ | 380 | /* left out 2 */ |
381 | {"Left Out 2", NULL, "Left Mixer"}, | 381 | {"Left Out 2", NULL, "Left Mixer"}, |
382 | {"LOUT2", NULL, "Left Out 2"}, | 382 | {"LOUT2", NULL, "Left Out 2"}, |
383 | 383 | ||
384 | /* right out 1 */ | 384 | /* right out 1 */ |
385 | {"Right Out 1", NULL, "Right Mixer"}, | 385 | {"Right Out 1", NULL, "Right Mixer"}, |
386 | {"ROUT1", NULL, "Right Out 1"}, | 386 | {"ROUT1", NULL, "Right Out 1"}, |
387 | 387 | ||
388 | /* right out 2 */ | 388 | /* right out 2 */ |
389 | {"Right Out 2", NULL, "Right Mixer"}, | 389 | {"Right Out 2", NULL, "Right Mixer"}, |
390 | {"ROUT2", NULL, "Right Out 2"}, | 390 | {"ROUT2", NULL, "Right Out 2"}, |
391 | 391 | ||
392 | /* mono mixer */ | 392 | /* mono mixer */ |
393 | {"Mono Mixer", "Left Playback Switch", "Left DAC"}, | 393 | {"Mono Mixer", "Left Playback Switch", "Left DAC"}, |
394 | {"Mono Mixer", "Left Bypass Switch", "Left Line Mux"}, | 394 | {"Mono Mixer", "Left Bypass Switch", "Left Line Mux"}, |
395 | {"Mono Mixer", "Right Playback Switch", "Right DAC"}, | 395 | {"Mono Mixer", "Right Playback Switch", "Right DAC"}, |
396 | {"Mono Mixer", "Right Bypass Switch", "Right Line Mux"}, | 396 | {"Mono Mixer", "Right Bypass Switch", "Right Line Mux"}, |
397 | 397 | ||
398 | /* mono out */ | 398 | /* mono out */ |
399 | {"Mono Out 1", NULL, "Mono Mixer"}, | 399 | {"Mono Out 1", NULL, "Mono Mixer"}, |
400 | {"MONO1", NULL, "Mono Out 1"}, | 400 | {"MONO1", NULL, "Mono Out 1"}, |
401 | 401 | ||
402 | /* out 3 */ | 402 | /* out 3 */ |
403 | {"Out3 Mux", "VREF", "VREF"}, | 403 | {"Out3 Mux", "VREF", "VREF"}, |
404 | {"Out3 Mux", "ROUT1 + Vol", "ROUT1"}, | 404 | {"Out3 Mux", "ROUT1 + Vol", "ROUT1"}, |
405 | {"Out3 Mux", "ROUT1", "Right Mixer"}, | 405 | {"Out3 Mux", "ROUT1", "Right Mixer"}, |
406 | {"Out3 Mux", "MonoOut", "MONO1"}, | 406 | {"Out3 Mux", "MonoOut", "MONO1"}, |
407 | {"Out 3", NULL, "Out3 Mux"}, | 407 | {"Out 3", NULL, "Out3 Mux"}, |
408 | {"OUT3", NULL, "Out 3"}, | 408 | {"OUT3", NULL, "Out 3"}, |
409 | 409 | ||
410 | /* Left Line Mux */ | 410 | /* Left Line Mux */ |
411 | {"Left Line Mux", "Line 1", "LINPUT1"}, | 411 | {"Left Line Mux", "Line 1", "LINPUT1"}, |
412 | {"Left Line Mux", "Line 2", "LINPUT2"}, | 412 | {"Left Line Mux", "Line 2", "LINPUT2"}, |
413 | {"Left Line Mux", "Line 3", "LINPUT3"}, | 413 | {"Left Line Mux", "Line 3", "LINPUT3"}, |
414 | {"Left Line Mux", "PGA", "Left PGA Mux"}, | 414 | {"Left Line Mux", "PGA", "Left PGA Mux"}, |
415 | {"Left Line Mux", "Differential", "Differential Mux"}, | 415 | {"Left Line Mux", "Differential", "Differential Mux"}, |
416 | 416 | ||
417 | /* Right Line Mux */ | 417 | /* Right Line Mux */ |
418 | {"Right Line Mux", "Line 1", "RINPUT1"}, | 418 | {"Right Line Mux", "Line 1", "RINPUT1"}, |
419 | {"Right Line Mux", "Line 2", "RINPUT2"}, | 419 | {"Right Line Mux", "Line 2", "RINPUT2"}, |
420 | {"Right Line Mux", "Line 3", "RINPUT3"}, | 420 | {"Right Line Mux", "Line 3", "RINPUT3"}, |
421 | {"Right Line Mux", "PGA", "Right PGA Mux"}, | 421 | {"Right Line Mux", "PGA", "Right PGA Mux"}, |
422 | {"Right Line Mux", "Differential", "Differential Mux"}, | 422 | {"Right Line Mux", "Differential", "Differential Mux"}, |
423 | 423 | ||
424 | /* Left PGA Mux */ | 424 | /* Left PGA Mux */ |
425 | {"Left PGA Mux", "Line 1", "LINPUT1"}, | 425 | {"Left PGA Mux", "Line 1", "LINPUT1"}, |
426 | {"Left PGA Mux", "Line 2", "LINPUT2"}, | 426 | {"Left PGA Mux", "Line 2", "LINPUT2"}, |
427 | {"Left PGA Mux", "Line 3", "LINPUT3"}, | 427 | {"Left PGA Mux", "Line 3", "LINPUT3"}, |
428 | {"Left PGA Mux", "Differential", "Differential Mux"}, | 428 | {"Left PGA Mux", "Differential", "Differential Mux"}, |
429 | 429 | ||
430 | /* Right PGA Mux */ | 430 | /* Right PGA Mux */ |
431 | {"Right PGA Mux", "Line 1", "RINPUT1"}, | 431 | {"Right PGA Mux", "Line 1", "RINPUT1"}, |
432 | {"Right PGA Mux", "Line 2", "RINPUT2"}, | 432 | {"Right PGA Mux", "Line 2", "RINPUT2"}, |
433 | {"Right PGA Mux", "Line 3", "RINPUT3"}, | 433 | {"Right PGA Mux", "Line 3", "RINPUT3"}, |
434 | {"Right PGA Mux", "Differential", "Differential Mux"}, | 434 | {"Right PGA Mux", "Differential", "Differential Mux"}, |
435 | 435 | ||
436 | /* Differential Mux */ | 436 | /* Differential Mux */ |
437 | {"Differential Mux", "Line 1", "LINPUT1"}, | 437 | {"Differential Mux", "Line 1", "LINPUT1"}, |
438 | {"Differential Mux", "Line 1", "RINPUT1"}, | 438 | {"Differential Mux", "Line 1", "RINPUT1"}, |
439 | {"Differential Mux", "Line 2", "LINPUT2"}, | 439 | {"Differential Mux", "Line 2", "LINPUT2"}, |
440 | {"Differential Mux", "Line 2", "RINPUT2"}, | 440 | {"Differential Mux", "Line 2", "RINPUT2"}, |
441 | 441 | ||
442 | /* Left ADC Mux */ | 442 | /* Left ADC Mux */ |
443 | {"Left ADC Mux", "Stereo", "Left PGA Mux"}, | 443 | {"Left ADC Mux", "Stereo", "Left PGA Mux"}, |
444 | {"Left ADC Mux", "Mono (Left)", "Left PGA Mux"}, | 444 | {"Left ADC Mux", "Mono (Left)", "Left PGA Mux"}, |
445 | {"Left ADC Mux", "Digital Mono", "Left PGA Mux"}, | 445 | {"Left ADC Mux", "Digital Mono", "Left PGA Mux"}, |
446 | 446 | ||
447 | /* Right ADC Mux */ | 447 | /* Right ADC Mux */ |
448 | {"Right ADC Mux", "Stereo", "Right PGA Mux"}, | 448 | {"Right ADC Mux", "Stereo", "Right PGA Mux"}, |
449 | {"Right ADC Mux", "Mono (Right)", "Right PGA Mux"}, | 449 | {"Right ADC Mux", "Mono (Right)", "Right PGA Mux"}, |
450 | {"Right ADC Mux", "Digital Mono", "Right PGA Mux"}, | 450 | {"Right ADC Mux", "Digital Mono", "Right PGA Mux"}, |
451 | 451 | ||
452 | /* ADC */ | 452 | /* ADC */ |
453 | {"Left ADC", NULL, "Left ADC Mux"}, | 453 | {"Left ADC", NULL, "Left ADC Mux"}, |
454 | {"Right ADC", NULL, "Right ADC Mux"}, | 454 | {"Right ADC", NULL, "Right ADC Mux"}, |
455 | }; | 455 | }; |
456 | 456 | ||
457 | static int wm8750_add_widgets(struct snd_soc_codec *codec) | 457 | static int wm8750_add_widgets(struct snd_soc_codec *codec) |
458 | { | 458 | { |
459 | snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets, | 459 | snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets, |
460 | ARRAY_SIZE(wm8750_dapm_widgets)); | 460 | ARRAY_SIZE(wm8750_dapm_widgets)); |
461 | 461 | ||
462 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | 462 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
463 | 463 | ||
464 | snd_soc_dapm_new_widgets(codec); | 464 | snd_soc_dapm_new_widgets(codec); |
465 | return 0; | 465 | return 0; |
466 | } | 466 | } |
467 | 467 | ||
468 | struct _coeff_div { | 468 | struct _coeff_div { |
469 | u32 mclk; | 469 | u32 mclk; |
470 | u32 rate; | 470 | u32 rate; |
471 | u16 fs; | 471 | u16 fs; |
472 | u8 sr:5; | 472 | u8 sr:5; |
473 | u8 usb:1; | 473 | u8 usb:1; |
474 | }; | 474 | }; |
475 | 475 | ||
476 | /* codec hifi mclk clock divider coefficients */ | 476 | /* codec hifi mclk clock divider coefficients */ |
477 | static const struct _coeff_div coeff_div[] = { | 477 | static const struct _coeff_div coeff_div[] = { |
478 | /* 8k */ | 478 | /* 8k */ |
479 | {12288000, 8000, 1536, 0x6, 0x0}, | 479 | {12288000, 8000, 1536, 0x6, 0x0}, |
480 | {11289600, 8000, 1408, 0x16, 0x0}, | 480 | {11289600, 8000, 1408, 0x16, 0x0}, |
481 | {18432000, 8000, 2304, 0x7, 0x0}, | 481 | {18432000, 8000, 2304, 0x7, 0x0}, |
482 | {16934400, 8000, 2112, 0x17, 0x0}, | 482 | {16934400, 8000, 2112, 0x17, 0x0}, |
483 | {12000000, 8000, 1500, 0x6, 0x1}, | 483 | {12000000, 8000, 1500, 0x6, 0x1}, |
484 | 484 | ||
485 | /* 11.025k */ | 485 | /* 11.025k */ |
486 | {11289600, 11025, 1024, 0x18, 0x0}, | 486 | {11289600, 11025, 1024, 0x18, 0x0}, |
487 | {16934400, 11025, 1536, 0x19, 0x0}, | 487 | {16934400, 11025, 1536, 0x19, 0x0}, |
488 | {12000000, 11025, 1088, 0x19, 0x1}, | 488 | {12000000, 11025, 1088, 0x19, 0x1}, |
489 | 489 | ||
490 | /* 16k */ | 490 | /* 16k */ |
491 | {12288000, 16000, 768, 0xa, 0x0}, | 491 | {12288000, 16000, 768, 0xa, 0x0}, |
492 | {18432000, 16000, 1152, 0xb, 0x0}, | 492 | {18432000, 16000, 1152, 0xb, 0x0}, |
493 | {12000000, 16000, 750, 0xa, 0x1}, | 493 | {12000000, 16000, 750, 0xa, 0x1}, |
494 | 494 | ||
495 | /* 22.05k */ | 495 | /* 22.05k */ |
496 | {11289600, 22050, 512, 0x1a, 0x0}, | 496 | {11289600, 22050, 512, 0x1a, 0x0}, |
497 | {16934400, 22050, 768, 0x1b, 0x0}, | 497 | {16934400, 22050, 768, 0x1b, 0x0}, |
498 | {12000000, 22050, 544, 0x1b, 0x1}, | 498 | {12000000, 22050, 544, 0x1b, 0x1}, |
499 | 499 | ||
500 | /* 32k */ | 500 | /* 32k */ |
501 | {12288000, 32000, 384, 0xc, 0x0}, | 501 | {12288000, 32000, 384, 0xc, 0x0}, |
502 | {18432000, 32000, 576, 0xd, 0x0}, | 502 | {18432000, 32000, 576, 0xd, 0x0}, |
503 | {12000000, 32000, 375, 0xa, 0x1}, | 503 | {12000000, 32000, 375, 0xa, 0x1}, |
504 | 504 | ||
505 | /* 44.1k */ | 505 | /* 44.1k */ |
506 | {11289600, 44100, 256, 0x10, 0x0}, | 506 | {11289600, 44100, 256, 0x10, 0x0}, |
507 | {16934400, 44100, 384, 0x11, 0x0}, | 507 | {16934400, 44100, 384, 0x11, 0x0}, |
508 | {12000000, 44100, 272, 0x11, 0x1}, | 508 | {12000000, 44100, 272, 0x11, 0x1}, |
509 | 509 | ||
510 | /* 48k */ | 510 | /* 48k */ |
511 | {12288000, 48000, 256, 0x0, 0x0}, | 511 | {12288000, 48000, 256, 0x0, 0x0}, |
512 | {18432000, 48000, 384, 0x1, 0x0}, | 512 | {18432000, 48000, 384, 0x1, 0x0}, |
513 | {12000000, 48000, 250, 0x0, 0x1}, | 513 | {12000000, 48000, 250, 0x0, 0x1}, |
514 | 514 | ||
515 | /* 88.2k */ | 515 | /* 88.2k */ |
516 | {11289600, 88200, 128, 0x1e, 0x0}, | 516 | {11289600, 88200, 128, 0x1e, 0x0}, |
517 | {16934400, 88200, 192, 0x1f, 0x0}, | 517 | {16934400, 88200, 192, 0x1f, 0x0}, |
518 | {12000000, 88200, 136, 0x1f, 0x1}, | 518 | {12000000, 88200, 136, 0x1f, 0x1}, |
519 | 519 | ||
520 | /* 96k */ | 520 | /* 96k */ |
521 | {12288000, 96000, 128, 0xe, 0x0}, | 521 | {12288000, 96000, 128, 0xe, 0x0}, |
522 | {18432000, 96000, 192, 0xf, 0x0}, | 522 | {18432000, 96000, 192, 0xf, 0x0}, |
523 | {12000000, 96000, 125, 0xe, 0x1}, | 523 | {12000000, 96000, 125, 0xe, 0x1}, |
524 | }; | 524 | }; |
525 | 525 | ||
526 | static inline int get_coeff(int mclk, int rate) | 526 | static inline int get_coeff(int mclk, int rate) |
527 | { | 527 | { |
528 | int i; | 528 | int i; |
529 | 529 | ||
530 | for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { | 530 | for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { |
531 | if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) | 531 | if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) |
532 | return i; | 532 | return i; |
533 | } | 533 | } |
534 | 534 | ||
535 | printk(KERN_ERR "wm8750: could not get coeff for mclk %d @ rate %d\n", | 535 | printk(KERN_ERR "wm8750: could not get coeff for mclk %d @ rate %d\n", |
536 | mclk, rate); | 536 | mclk, rate); |
537 | return -EINVAL; | 537 | return -EINVAL; |
538 | } | 538 | } |
539 | 539 | ||
540 | static int wm8750_set_dai_sysclk(struct snd_soc_dai *codec_dai, | 540 | static int wm8750_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
541 | int clk_id, unsigned int freq, int dir) | 541 | int clk_id, unsigned int freq, int dir) |
542 | { | 542 | { |
543 | struct snd_soc_codec *codec = codec_dai->codec; | 543 | struct snd_soc_codec *codec = codec_dai->codec; |
544 | struct wm8750_priv *wm8750 = codec->private_data; | 544 | struct wm8750_priv *wm8750 = codec->private_data; |
545 | 545 | ||
546 | switch (freq) { | 546 | switch (freq) { |
547 | case 11289600: | 547 | case 11289600: |
548 | case 12000000: | 548 | case 12000000: |
549 | case 12288000: | 549 | case 12288000: |
550 | case 16934400: | 550 | case 16934400: |
551 | case 18432000: | 551 | case 18432000: |
552 | wm8750->sysclk = freq; | 552 | wm8750->sysclk = freq; |
553 | return 0; | 553 | return 0; |
554 | } | 554 | } |
555 | return -EINVAL; | 555 | return -EINVAL; |
556 | } | 556 | } |
557 | 557 | ||
558 | static int wm8750_set_dai_fmt(struct snd_soc_dai *codec_dai, | 558 | static int wm8750_set_dai_fmt(struct snd_soc_dai *codec_dai, |
559 | unsigned int fmt) | 559 | unsigned int fmt) |
560 | { | 560 | { |
561 | struct snd_soc_codec *codec = codec_dai->codec; | 561 | struct snd_soc_codec *codec = codec_dai->codec; |
562 | u16 iface = 0; | 562 | u16 iface = 0; |
563 | 563 | ||
564 | /* set master/slave audio interface */ | 564 | /* set master/slave audio interface */ |
565 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 565 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
566 | case SND_SOC_DAIFMT_CBM_CFM: | 566 | case SND_SOC_DAIFMT_CBM_CFM: |
567 | iface = 0x0040; | 567 | iface = 0x0040; |
568 | break; | 568 | break; |
569 | case SND_SOC_DAIFMT_CBS_CFS: | 569 | case SND_SOC_DAIFMT_CBS_CFS: |
570 | break; | 570 | break; |
571 | default: | 571 | default: |
572 | return -EINVAL; | 572 | return -EINVAL; |
573 | } | 573 | } |
574 | 574 | ||
575 | /* interface format */ | 575 | /* interface format */ |
576 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 576 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
577 | case SND_SOC_DAIFMT_I2S: | 577 | case SND_SOC_DAIFMT_I2S: |
578 | iface |= 0x0002; | 578 | iface |= 0x0002; |
579 | break; | 579 | break; |
580 | case SND_SOC_DAIFMT_RIGHT_J: | 580 | case SND_SOC_DAIFMT_RIGHT_J: |
581 | break; | 581 | break; |
582 | case SND_SOC_DAIFMT_LEFT_J: | 582 | case SND_SOC_DAIFMT_LEFT_J: |
583 | iface |= 0x0001; | 583 | iface |= 0x0001; |
584 | break; | 584 | break; |
585 | case SND_SOC_DAIFMT_DSP_A: | 585 | case SND_SOC_DAIFMT_DSP_A: |
586 | iface |= 0x0003; | 586 | iface |= 0x0003; |
587 | break; | 587 | break; |
588 | case SND_SOC_DAIFMT_DSP_B: | 588 | case SND_SOC_DAIFMT_DSP_B: |
589 | iface |= 0x0013; | 589 | iface |= 0x0013; |
590 | break; | 590 | break; |
591 | default: | 591 | default: |
592 | return -EINVAL; | 592 | return -EINVAL; |
593 | } | 593 | } |
594 | 594 | ||
595 | /* clock inversion */ | 595 | /* clock inversion */ |
596 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | 596 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
597 | case SND_SOC_DAIFMT_NB_NF: | 597 | case SND_SOC_DAIFMT_NB_NF: |
598 | break; | 598 | break; |
599 | case SND_SOC_DAIFMT_IB_IF: | 599 | case SND_SOC_DAIFMT_IB_IF: |
600 | iface |= 0x0090; | 600 | iface |= 0x0090; |
601 | break; | 601 | break; |
602 | case SND_SOC_DAIFMT_IB_NF: | 602 | case SND_SOC_DAIFMT_IB_NF: |
603 | iface |= 0x0080; | 603 | iface |= 0x0080; |
604 | break; | 604 | break; |
605 | case SND_SOC_DAIFMT_NB_IF: | 605 | case SND_SOC_DAIFMT_NB_IF: |
606 | iface |= 0x0010; | 606 | iface |= 0x0010; |
607 | break; | 607 | break; |
608 | default: | 608 | default: |
609 | return -EINVAL; | 609 | return -EINVAL; |
610 | } | 610 | } |
611 | 611 | ||
612 | wm8750_write(codec, WM8750_IFACE, iface); | 612 | wm8750_write(codec, WM8750_IFACE, iface); |
613 | return 0; | 613 | return 0; |
614 | } | 614 | } |
615 | 615 | ||
616 | static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream, | 616 | static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream, |
617 | struct snd_pcm_hw_params *params) | 617 | struct snd_pcm_hw_params *params) |
618 | { | 618 | { |
619 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 619 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
620 | struct snd_soc_device *socdev = rtd->socdev; | 620 | struct snd_soc_device *socdev = rtd->socdev; |
621 | struct snd_soc_codec *codec = socdev->codec; | 621 | struct snd_soc_codec *codec = socdev->codec; |
622 | struct wm8750_priv *wm8750 = codec->private_data; | 622 | struct wm8750_priv *wm8750 = codec->private_data; |
623 | u16 iface = wm8750_read_reg_cache(codec, WM8750_IFACE) & 0x1f3; | 623 | u16 iface = wm8750_read_reg_cache(codec, WM8750_IFACE) & 0x1f3; |
624 | u16 srate = wm8750_read_reg_cache(codec, WM8750_SRATE) & 0x1c0; | 624 | u16 srate = wm8750_read_reg_cache(codec, WM8750_SRATE) & 0x1c0; |
625 | int coeff = get_coeff(wm8750->sysclk, params_rate(params)); | 625 | int coeff = get_coeff(wm8750->sysclk, params_rate(params)); |
626 | 626 | ||
627 | /* bit size */ | 627 | /* bit size */ |
628 | switch (params_format(params)) { | 628 | switch (params_format(params)) { |
629 | case SNDRV_PCM_FORMAT_S16_LE: | 629 | case SNDRV_PCM_FORMAT_S16_LE: |
630 | break; | 630 | break; |
631 | case SNDRV_PCM_FORMAT_S20_3LE: | 631 | case SNDRV_PCM_FORMAT_S20_3LE: |
632 | iface |= 0x0004; | 632 | iface |= 0x0004; |
633 | break; | 633 | break; |
634 | case SNDRV_PCM_FORMAT_S24_LE: | 634 | case SNDRV_PCM_FORMAT_S24_LE: |
635 | iface |= 0x0008; | 635 | iface |= 0x0008; |
636 | break; | 636 | break; |
637 | case SNDRV_PCM_FORMAT_S32_LE: | 637 | case SNDRV_PCM_FORMAT_S32_LE: |
638 | iface |= 0x000c; | 638 | iface |= 0x000c; |
639 | break; | 639 | break; |
640 | } | 640 | } |
641 | 641 | ||
642 | /* set iface & srate */ | 642 | /* set iface & srate */ |
643 | wm8750_write(codec, WM8750_IFACE, iface); | 643 | wm8750_write(codec, WM8750_IFACE, iface); |
644 | if (coeff >= 0) | 644 | if (coeff >= 0) |
645 | wm8750_write(codec, WM8750_SRATE, srate | | 645 | wm8750_write(codec, WM8750_SRATE, srate | |
646 | (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb); | 646 | (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb); |
647 | 647 | ||
648 | return 0; | 648 | return 0; |
649 | } | 649 | } |
650 | 650 | ||
651 | static int wm8750_mute(struct snd_soc_dai *dai, int mute) | 651 | static int wm8750_mute(struct snd_soc_dai *dai, int mute) |
652 | { | 652 | { |
653 | struct snd_soc_codec *codec = dai->codec; | 653 | struct snd_soc_codec *codec = dai->codec; |
654 | u16 mute_reg = wm8750_read_reg_cache(codec, WM8750_ADCDAC) & 0xfff7; | 654 | u16 mute_reg = wm8750_read_reg_cache(codec, WM8750_ADCDAC) & 0xfff7; |
655 | 655 | ||
656 | if (mute) | 656 | if (mute) |
657 | wm8750_write(codec, WM8750_ADCDAC, mute_reg | 0x8); | 657 | wm8750_write(codec, WM8750_ADCDAC, mute_reg | 0x8); |
658 | else | 658 | else |
659 | wm8750_write(codec, WM8750_ADCDAC, mute_reg); | 659 | wm8750_write(codec, WM8750_ADCDAC, mute_reg); |
660 | return 0; | 660 | return 0; |
661 | } | 661 | } |
662 | 662 | ||
663 | static int wm8750_set_bias_level(struct snd_soc_codec *codec, | 663 | static int wm8750_set_bias_level(struct snd_soc_codec *codec, |
664 | enum snd_soc_bias_level level) | 664 | enum snd_soc_bias_level level) |
665 | { | 665 | { |
666 | u16 pwr_reg = wm8750_read_reg_cache(codec, WM8750_PWR1) & 0xfe3e; | 666 | u16 pwr_reg = wm8750_read_reg_cache(codec, WM8750_PWR1) & 0xfe3e; |
667 | 667 | ||
668 | switch (level) { | 668 | switch (level) { |
669 | case SND_SOC_BIAS_ON: | 669 | case SND_SOC_BIAS_ON: |
670 | /* set vmid to 50k and unmute dac */ | 670 | /* set vmid to 50k and unmute dac */ |
671 | wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x00c0); | 671 | wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x00c0); |
672 | break; | 672 | break; |
673 | case SND_SOC_BIAS_PREPARE: | 673 | case SND_SOC_BIAS_PREPARE: |
674 | /* set vmid to 5k for quick power up */ | 674 | /* set vmid to 5k for quick power up */ |
675 | wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x01c1); | 675 | wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x01c1); |
676 | break; | 676 | break; |
677 | case SND_SOC_BIAS_STANDBY: | 677 | case SND_SOC_BIAS_STANDBY: |
678 | /* mute dac and set vmid to 500k, enable VREF */ | 678 | /* mute dac and set vmid to 500k, enable VREF */ |
679 | wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x0141); | 679 | wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x0141); |
680 | break; | 680 | break; |
681 | case SND_SOC_BIAS_OFF: | 681 | case SND_SOC_BIAS_OFF: |
682 | wm8750_write(codec, WM8750_PWR1, 0x0001); | 682 | wm8750_write(codec, WM8750_PWR1, 0x0001); |
683 | break; | 683 | break; |
684 | } | 684 | } |
685 | codec->bias_level = level; | 685 | codec->bias_level = level; |
686 | return 0; | 686 | return 0; |
687 | } | 687 | } |
688 | 688 | ||
689 | #define WM8750_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | 689 | #define WM8750_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ |
690 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ | 690 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ |
691 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) | 691 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) |
692 | 692 | ||
693 | #define WM8750_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | 693 | #define WM8750_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
694 | SNDRV_PCM_FMTBIT_S24_LE) | 694 | SNDRV_PCM_FMTBIT_S24_LE) |
695 | 695 | ||
696 | struct snd_soc_dai wm8750_dai = { | 696 | struct snd_soc_dai wm8750_dai = { |
697 | .name = "WM8750", | 697 | .name = "WM8750", |
698 | .playback = { | 698 | .playback = { |
699 | .stream_name = "Playback", | 699 | .stream_name = "Playback", |
700 | .channels_min = 1, | 700 | .channels_min = 1, |
701 | .channels_max = 2, | 701 | .channels_max = 2, |
702 | .rates = WM8750_RATES, | 702 | .rates = WM8750_RATES, |
703 | .formats = WM8750_FORMATS,}, | 703 | .formats = WM8750_FORMATS,}, |
704 | .capture = { | 704 | .capture = { |
705 | .stream_name = "Capture", | 705 | .stream_name = "Capture", |
706 | .channels_min = 1, | 706 | .channels_min = 1, |
707 | .channels_max = 2, | 707 | .channels_max = 2, |
708 | .rates = WM8750_RATES, | 708 | .rates = WM8750_RATES, |
709 | .formats = WM8750_FORMATS,}, | 709 | .formats = WM8750_FORMATS,}, |
710 | .ops = { | 710 | .ops = { |
711 | .hw_params = wm8750_pcm_hw_params, | 711 | .hw_params = wm8750_pcm_hw_params, |
712 | }, | 712 | }, |
713 | .dai_ops = { | 713 | .dai_ops = { |
714 | .digital_mute = wm8750_mute, | 714 | .digital_mute = wm8750_mute, |
715 | .set_fmt = wm8750_set_dai_fmt, | 715 | .set_fmt = wm8750_set_dai_fmt, |
716 | .set_sysclk = wm8750_set_dai_sysclk, | 716 | .set_sysclk = wm8750_set_dai_sysclk, |
717 | }, | 717 | }, |
718 | }; | 718 | }; |
719 | EXPORT_SYMBOL_GPL(wm8750_dai); | 719 | EXPORT_SYMBOL_GPL(wm8750_dai); |
720 | 720 | ||
721 | static void wm8750_work(struct work_struct *work) | 721 | static void wm8750_work(struct work_struct *work) |
722 | { | 722 | { |
723 | struct snd_soc_codec *codec = | 723 | struct snd_soc_codec *codec = |
724 | container_of(work, struct snd_soc_codec, delayed_work.work); | 724 | container_of(work, struct snd_soc_codec, delayed_work.work); |
725 | wm8750_set_bias_level(codec, codec->bias_level); | 725 | wm8750_set_bias_level(codec, codec->bias_level); |
726 | } | 726 | } |
727 | 727 | ||
728 | static int wm8750_suspend(struct platform_device *pdev, pm_message_t state) | 728 | static int wm8750_suspend(struct platform_device *pdev, pm_message_t state) |
729 | { | 729 | { |
730 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 730 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
731 | struct snd_soc_codec *codec = socdev->codec; | 731 | struct snd_soc_codec *codec = socdev->codec; |
732 | 732 | ||
733 | wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF); | 733 | wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF); |
734 | return 0; | 734 | return 0; |
735 | } | 735 | } |
736 | 736 | ||
737 | static int wm8750_resume(struct platform_device *pdev) | 737 | static int wm8750_resume(struct platform_device *pdev) |
738 | { | 738 | { |
739 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 739 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
740 | struct snd_soc_codec *codec = socdev->codec; | 740 | struct snd_soc_codec *codec = socdev->codec; |
741 | int i; | 741 | int i; |
742 | u8 data[2]; | 742 | u8 data[2]; |
743 | u16 *cache = codec->reg_cache; | 743 | u16 *cache = codec->reg_cache; |
744 | 744 | ||
745 | /* Sync reg_cache with the hardware */ | 745 | /* Sync reg_cache with the hardware */ |
746 | for (i = 0; i < ARRAY_SIZE(wm8750_reg); i++) { | 746 | for (i = 0; i < ARRAY_SIZE(wm8750_reg); i++) { |
747 | if (i == WM8750_RESET) | 747 | if (i == WM8750_RESET) |
748 | continue; | 748 | continue; |
749 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); | 749 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); |
750 | data[1] = cache[i] & 0x00ff; | 750 | data[1] = cache[i] & 0x00ff; |
751 | codec->hw_write(codec->control_data, data, 2); | 751 | codec->hw_write(codec->control_data, data, 2); |
752 | } | 752 | } |
753 | 753 | ||
754 | wm8750_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 754 | wm8750_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
755 | 755 | ||
756 | /* charge wm8750 caps */ | 756 | /* charge wm8750 caps */ |
757 | if (codec->suspend_bias_level == SND_SOC_BIAS_ON) { | 757 | if (codec->suspend_bias_level == SND_SOC_BIAS_ON) { |
758 | wm8750_set_bias_level(codec, SND_SOC_BIAS_PREPARE); | 758 | wm8750_set_bias_level(codec, SND_SOC_BIAS_PREPARE); |
759 | codec->bias_level = SND_SOC_BIAS_ON; | 759 | codec->bias_level = SND_SOC_BIAS_ON; |
760 | schedule_delayed_work(&codec->delayed_work, | 760 | schedule_delayed_work(&codec->delayed_work, |
761 | msecs_to_jiffies(1000)); | 761 | msecs_to_jiffies(1000)); |
762 | } | 762 | } |
763 | 763 | ||
764 | return 0; | 764 | return 0; |
765 | } | 765 | } |
766 | 766 | ||
767 | /* | 767 | /* |
768 | * initialise the WM8750 driver | 768 | * initialise the WM8750 driver |
769 | * register the mixer and dsp interfaces with the kernel | 769 | * register the mixer and dsp interfaces with the kernel |
770 | */ | 770 | */ |
771 | static int wm8750_init(struct snd_soc_device *socdev) | 771 | static int wm8750_init(struct snd_soc_device *socdev) |
772 | { | 772 | { |
773 | struct snd_soc_codec *codec = socdev->codec; | 773 | struct snd_soc_codec *codec = socdev->codec; |
774 | int reg, ret = 0; | 774 | int reg, ret = 0; |
775 | 775 | ||
776 | codec->name = "WM8750"; | 776 | codec->name = "WM8750"; |
777 | codec->owner = THIS_MODULE; | 777 | codec->owner = THIS_MODULE; |
778 | codec->read = wm8750_read_reg_cache; | 778 | codec->read = wm8750_read_reg_cache; |
779 | codec->write = wm8750_write; | 779 | codec->write = wm8750_write; |
780 | codec->set_bias_level = wm8750_set_bias_level; | 780 | codec->set_bias_level = wm8750_set_bias_level; |
781 | codec->dai = &wm8750_dai; | 781 | codec->dai = &wm8750_dai; |
782 | codec->num_dai = 1; | 782 | codec->num_dai = 1; |
783 | codec->reg_cache_size = ARRAY_SIZE(wm8750_reg); | 783 | codec->reg_cache_size = ARRAY_SIZE(wm8750_reg); |
784 | codec->reg_cache = kmemdup(wm8750_reg, sizeof(wm8750_reg), GFP_KERNEL); | 784 | codec->reg_cache = kmemdup(wm8750_reg, sizeof(wm8750_reg), GFP_KERNEL); |
785 | if (codec->reg_cache == NULL) | 785 | if (codec->reg_cache == NULL) |
786 | return -ENOMEM; | 786 | return -ENOMEM; |
787 | 787 | ||
788 | wm8750_reset(codec); | 788 | wm8750_reset(codec); |
789 | 789 | ||
790 | /* register pcms */ | 790 | /* register pcms */ |
791 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 791 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
792 | if (ret < 0) { | 792 | if (ret < 0) { |
793 | printk(KERN_ERR "wm8750: failed to create pcms\n"); | 793 | printk(KERN_ERR "wm8750: failed to create pcms\n"); |
794 | goto pcm_err; | 794 | goto pcm_err; |
795 | } | 795 | } |
796 | 796 | ||
797 | /* charge output caps */ | 797 | /* charge output caps */ |
798 | wm8750_set_bias_level(codec, SND_SOC_BIAS_PREPARE); | 798 | wm8750_set_bias_level(codec, SND_SOC_BIAS_PREPARE); |
799 | codec->bias_level = SND_SOC_BIAS_STANDBY; | 799 | codec->bias_level = SND_SOC_BIAS_STANDBY; |
800 | schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000)); | 800 | schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000)); |
801 | 801 | ||
802 | /* set the update bits */ | 802 | /* set the update bits */ |
803 | reg = wm8750_read_reg_cache(codec, WM8750_LDAC); | 803 | reg = wm8750_read_reg_cache(codec, WM8750_LDAC); |
804 | wm8750_write(codec, WM8750_LDAC, reg | 0x0100); | 804 | wm8750_write(codec, WM8750_LDAC, reg | 0x0100); |
805 | reg = wm8750_read_reg_cache(codec, WM8750_RDAC); | 805 | reg = wm8750_read_reg_cache(codec, WM8750_RDAC); |
806 | wm8750_write(codec, WM8750_RDAC, reg | 0x0100); | 806 | wm8750_write(codec, WM8750_RDAC, reg | 0x0100); |
807 | reg = wm8750_read_reg_cache(codec, WM8750_LOUT1V); | 807 | reg = wm8750_read_reg_cache(codec, WM8750_LOUT1V); |
808 | wm8750_write(codec, WM8750_LOUT1V, reg | 0x0100); | 808 | wm8750_write(codec, WM8750_LOUT1V, reg | 0x0100); |
809 | reg = wm8750_read_reg_cache(codec, WM8750_ROUT1V); | 809 | reg = wm8750_read_reg_cache(codec, WM8750_ROUT1V); |
810 | wm8750_write(codec, WM8750_ROUT1V, reg | 0x0100); | 810 | wm8750_write(codec, WM8750_ROUT1V, reg | 0x0100); |
811 | reg = wm8750_read_reg_cache(codec, WM8750_LOUT2V); | 811 | reg = wm8750_read_reg_cache(codec, WM8750_LOUT2V); |
812 | wm8750_write(codec, WM8750_LOUT2V, reg | 0x0100); | 812 | wm8750_write(codec, WM8750_LOUT2V, reg | 0x0100); |
813 | reg = wm8750_read_reg_cache(codec, WM8750_ROUT2V); | 813 | reg = wm8750_read_reg_cache(codec, WM8750_ROUT2V); |
814 | wm8750_write(codec, WM8750_ROUT2V, reg | 0x0100); | 814 | wm8750_write(codec, WM8750_ROUT2V, reg | 0x0100); |
815 | reg = wm8750_read_reg_cache(codec, WM8750_LINVOL); | 815 | reg = wm8750_read_reg_cache(codec, WM8750_LINVOL); |
816 | wm8750_write(codec, WM8750_LINVOL, reg | 0x0100); | 816 | wm8750_write(codec, WM8750_LINVOL, reg | 0x0100); |
817 | reg = wm8750_read_reg_cache(codec, WM8750_RINVOL); | 817 | reg = wm8750_read_reg_cache(codec, WM8750_RINVOL); |
818 | wm8750_write(codec, WM8750_RINVOL, reg | 0x0100); | 818 | wm8750_write(codec, WM8750_RINVOL, reg | 0x0100); |
819 | 819 | ||
820 | wm8750_add_controls(codec); | 820 | wm8750_add_controls(codec); |
821 | wm8750_add_widgets(codec); | 821 | wm8750_add_widgets(codec); |
822 | ret = snd_soc_register_card(socdev); | 822 | ret = snd_soc_register_card(socdev); |
823 | if (ret < 0) { | 823 | if (ret < 0) { |
824 | printk(KERN_ERR "wm8750: failed to register card\n"); | 824 | printk(KERN_ERR "wm8750: failed to register card\n"); |
825 | goto card_err; | 825 | goto card_err; |
826 | } | 826 | } |
827 | return ret; | 827 | return ret; |
828 | 828 | ||
829 | card_err: | 829 | card_err: |
830 | snd_soc_free_pcms(socdev); | 830 | snd_soc_free_pcms(socdev); |
831 | snd_soc_dapm_free(socdev); | 831 | snd_soc_dapm_free(socdev); |
832 | pcm_err: | 832 | pcm_err: |
833 | kfree(codec->reg_cache); | 833 | kfree(codec->reg_cache); |
834 | return ret; | 834 | return ret; |
835 | } | 835 | } |
836 | 836 | ||
837 | /* If the i2c layer weren't so broken, we could pass this kind of data | 837 | /* If the i2c layer weren't so broken, we could pass this kind of data |
838 | around */ | 838 | around */ |
839 | static struct snd_soc_device *wm8750_socdev; | 839 | static struct snd_soc_device *wm8750_socdev; |
840 | 840 | ||
841 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 841 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
842 | 842 | ||
843 | /* | 843 | /* |
844 | * WM8731 2 wire address is determined by GPIO5 | 844 | * WM8731 2 wire address is determined by GPIO5 |
845 | * state during powerup. | 845 | * state during powerup. |
846 | * low = 0x1a | 846 | * low = 0x1a |
847 | * high = 0x1b | 847 | * high = 0x1b |
848 | */ | 848 | */ |
849 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | 849 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; |
850 | 850 | ||
851 | /* Magic definition of all other variables and things */ | 851 | /* Magic definition of all other variables and things */ |
852 | I2C_CLIENT_INSMOD; | 852 | I2C_CLIENT_INSMOD; |
853 | 853 | ||
854 | static struct i2c_driver wm8750_i2c_driver; | 854 | static struct i2c_driver wm8750_i2c_driver; |
855 | static struct i2c_client client_template; | 855 | static struct i2c_client client_template; |
856 | 856 | ||
857 | static int wm8750_codec_probe(struct i2c_adapter *adap, int addr, int kind) | 857 | static int wm8750_codec_probe(struct i2c_adapter *adap, int addr, int kind) |
858 | { | 858 | { |
859 | struct snd_soc_device *socdev = wm8750_socdev; | 859 | struct snd_soc_device *socdev = wm8750_socdev; |
860 | struct wm8750_setup_data *setup = socdev->codec_data; | 860 | struct wm8750_setup_data *setup = socdev->codec_data; |
861 | struct snd_soc_codec *codec = socdev->codec; | 861 | struct snd_soc_codec *codec = socdev->codec; |
862 | struct i2c_client *i2c; | 862 | struct i2c_client *i2c; |
863 | int ret; | 863 | int ret; |
864 | 864 | ||
865 | if (addr != setup->i2c_address) | 865 | if (addr != setup->i2c_address) |
866 | return -ENODEV; | 866 | return -ENODEV; |
867 | 867 | ||
868 | client_template.adapter = adap; | 868 | client_template.adapter = adap; |
869 | client_template.addr = addr; | 869 | client_template.addr = addr; |
870 | 870 | ||
871 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | 871 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); |
872 | if (i2c == NULL) { | 872 | if (i2c == NULL) |
873 | kfree(codec); | ||
874 | return -ENOMEM; | 873 | return -ENOMEM; |
875 | } | 874 | |
876 | i2c_set_clientdata(i2c, codec); | 875 | i2c_set_clientdata(i2c, codec); |
877 | codec->control_data = i2c; | 876 | codec->control_data = i2c; |
878 | 877 | ||
879 | ret = i2c_attach_client(i2c); | 878 | ret = i2c_attach_client(i2c); |
880 | if (ret < 0) { | 879 | if (ret < 0) { |
881 | pr_err("failed to attach codec at addr %x\n", addr); | 880 | pr_err("failed to attach codec at addr %x\n", addr); |
882 | goto err; | 881 | goto err; |
883 | } | 882 | } |
884 | 883 | ||
885 | ret = wm8750_init(socdev); | 884 | ret = wm8750_init(socdev); |
886 | if (ret < 0) { | 885 | if (ret < 0) { |
887 | pr_err("failed to initialise WM8750\n"); | 886 | pr_err("failed to initialise WM8750\n"); |
888 | goto err; | 887 | goto err; |
889 | } | 888 | } |
890 | return ret; | 889 | return ret; |
891 | 890 | ||
892 | err: | 891 | err: |
893 | kfree(codec); | ||
894 | kfree(i2c); | 892 | kfree(i2c); |
895 | return ret; | 893 | return ret; |
896 | } | 894 | } |
897 | 895 | ||
898 | static int wm8750_i2c_detach(struct i2c_client *client) | 896 | static int wm8750_i2c_detach(struct i2c_client *client) |
899 | { | 897 | { |
900 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 898 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
901 | i2c_detach_client(client); | 899 | i2c_detach_client(client); |
902 | kfree(codec->reg_cache); | 900 | kfree(codec->reg_cache); |
903 | kfree(client); | 901 | kfree(client); |
904 | return 0; | 902 | return 0; |
905 | } | 903 | } |
906 | 904 | ||
907 | static int wm8750_i2c_attach(struct i2c_adapter *adap) | 905 | static int wm8750_i2c_attach(struct i2c_adapter *adap) |
908 | { | 906 | { |
909 | return i2c_probe(adap, &addr_data, wm8750_codec_probe); | 907 | return i2c_probe(adap, &addr_data, wm8750_codec_probe); |
910 | } | 908 | } |
911 | 909 | ||
912 | /* corgi i2c codec control layer */ | 910 | /* corgi i2c codec control layer */ |
913 | static struct i2c_driver wm8750_i2c_driver = { | 911 | static struct i2c_driver wm8750_i2c_driver = { |
914 | .driver = { | 912 | .driver = { |
915 | .name = "WM8750 I2C Codec", | 913 | .name = "WM8750 I2C Codec", |
916 | .owner = THIS_MODULE, | 914 | .owner = THIS_MODULE, |
917 | }, | 915 | }, |
918 | .id = I2C_DRIVERID_WM8750, | 916 | .id = I2C_DRIVERID_WM8750, |
919 | .attach_adapter = wm8750_i2c_attach, | 917 | .attach_adapter = wm8750_i2c_attach, |
920 | .detach_client = wm8750_i2c_detach, | 918 | .detach_client = wm8750_i2c_detach, |
921 | .command = NULL, | 919 | .command = NULL, |
922 | }; | 920 | }; |
923 | 921 | ||
924 | static struct i2c_client client_template = { | 922 | static struct i2c_client client_template = { |
925 | .name = "WM8750", | 923 | .name = "WM8750", |
926 | .driver = &wm8750_i2c_driver, | 924 | .driver = &wm8750_i2c_driver, |
927 | }; | 925 | }; |
928 | #endif | 926 | #endif |
929 | 927 | ||
930 | static int wm8750_probe(struct platform_device *pdev) | 928 | static int wm8750_probe(struct platform_device *pdev) |
931 | { | 929 | { |
932 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 930 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
933 | struct wm8750_setup_data *setup = socdev->codec_data; | 931 | struct wm8750_setup_data *setup = socdev->codec_data; |
934 | struct snd_soc_codec *codec; | 932 | struct snd_soc_codec *codec; |
935 | struct wm8750_priv *wm8750; | 933 | struct wm8750_priv *wm8750; |
936 | int ret = 0; | 934 | int ret = 0; |
937 | 935 | ||
938 | pr_info("WM8750 Audio Codec %s", WM8750_VERSION); | 936 | pr_info("WM8750 Audio Codec %s", WM8750_VERSION); |
939 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 937 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); |
940 | if (codec == NULL) | 938 | if (codec == NULL) |
941 | return -ENOMEM; | 939 | return -ENOMEM; |
942 | 940 | ||
943 | wm8750 = kzalloc(sizeof(struct wm8750_priv), GFP_KERNEL); | 941 | wm8750 = kzalloc(sizeof(struct wm8750_priv), GFP_KERNEL); |
944 | if (wm8750 == NULL) { | 942 | if (wm8750 == NULL) { |
945 | kfree(codec); | 943 | kfree(codec); |
946 | return -ENOMEM; | 944 | return -ENOMEM; |
947 | } | 945 | } |
948 | 946 | ||
949 | codec->private_data = wm8750; | 947 | codec->private_data = wm8750; |
950 | socdev->codec = codec; | 948 | socdev->codec = codec; |
951 | mutex_init(&codec->mutex); | 949 | mutex_init(&codec->mutex); |
952 | INIT_LIST_HEAD(&codec->dapm_widgets); | 950 | INIT_LIST_HEAD(&codec->dapm_widgets); |
953 | INIT_LIST_HEAD(&codec->dapm_paths); | 951 | INIT_LIST_HEAD(&codec->dapm_paths); |
954 | wm8750_socdev = socdev; | 952 | wm8750_socdev = socdev; |
955 | INIT_DELAYED_WORK(&codec->delayed_work, wm8750_work); | 953 | INIT_DELAYED_WORK(&codec->delayed_work, wm8750_work); |
956 | 954 | ||
957 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 955 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
958 | if (setup->i2c_address) { | 956 | if (setup->i2c_address) { |
959 | normal_i2c[0] = setup->i2c_address; | 957 | normal_i2c[0] = setup->i2c_address; |
960 | codec->hw_write = (hw_write_t)i2c_master_send; | 958 | codec->hw_write = (hw_write_t)i2c_master_send; |
961 | ret = i2c_add_driver(&wm8750_i2c_driver); | 959 | ret = i2c_add_driver(&wm8750_i2c_driver); |
962 | if (ret != 0) | 960 | if (ret != 0) |
963 | printk(KERN_ERR "can't add i2c driver"); | 961 | printk(KERN_ERR "can't add i2c driver"); |
964 | } | 962 | } |
965 | #else | 963 | #else |
966 | /* Add other interfaces here */ | 964 | /* Add other interfaces here */ |
967 | #endif | 965 | #endif |
968 | 966 | ||
967 | if (ret != 0) { | ||
968 | kfree(codec->private_data); | ||
969 | kfree(codec); | ||
970 | } | ||
969 | return ret; | 971 | return ret; |
970 | } | 972 | } |
971 | 973 | ||
972 | /* | 974 | /* |
973 | * This function forces any delayed work to be queued and run. | 975 | * This function forces any delayed work to be queued and run. |
974 | */ | 976 | */ |
975 | static int run_delayed_work(struct delayed_work *dwork) | 977 | static int run_delayed_work(struct delayed_work *dwork) |
976 | { | 978 | { |
977 | int ret; | 979 | int ret; |
978 | 980 | ||
979 | /* cancel any work waiting to be queued. */ | 981 | /* cancel any work waiting to be queued. */ |
980 | ret = cancel_delayed_work(dwork); | 982 | ret = cancel_delayed_work(dwork); |
981 | 983 | ||
982 | /* if there was any work waiting then we run it now and | 984 | /* if there was any work waiting then we run it now and |
983 | * wait for it's completion */ | 985 | * wait for it's completion */ |
984 | if (ret) { | 986 | if (ret) { |
985 | schedule_delayed_work(dwork, 0); | 987 | schedule_delayed_work(dwork, 0); |
986 | flush_scheduled_work(); | 988 | flush_scheduled_work(); |
987 | } | 989 | } |
988 | return ret; | 990 | return ret; |
989 | } | 991 | } |
990 | 992 | ||
991 | /* power down chip */ | 993 | /* power down chip */ |
992 | static int wm8750_remove(struct platform_device *pdev) | 994 | static int wm8750_remove(struct platform_device *pdev) |
993 | { | 995 | { |
994 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 996 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
995 | struct snd_soc_codec *codec = socdev->codec; | 997 | struct snd_soc_codec *codec = socdev->codec; |
996 | 998 | ||
997 | if (codec->control_data) | 999 | if (codec->control_data) |
998 | wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1000 | wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF); |
999 | run_delayed_work(&codec->delayed_work); | 1001 | run_delayed_work(&codec->delayed_work); |
1000 | snd_soc_free_pcms(socdev); | 1002 | snd_soc_free_pcms(socdev); |
1001 | snd_soc_dapm_free(socdev); | 1003 | snd_soc_dapm_free(socdev); |
1002 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1004 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1003 | i2c_del_driver(&wm8750_i2c_driver); | 1005 | i2c_del_driver(&wm8750_i2c_driver); |
1004 | #endif | 1006 | #endif |
1005 | kfree(codec->private_data); | 1007 | kfree(codec->private_data); |
1006 | kfree(codec); | 1008 | kfree(codec); |
1007 | 1009 | ||
1008 | return 0; | 1010 | return 0; |
1009 | } | 1011 | } |
1010 | 1012 | ||
1011 | struct snd_soc_codec_device soc_codec_dev_wm8750 = { | 1013 | struct snd_soc_codec_device soc_codec_dev_wm8750 = { |
1012 | .probe = wm8750_probe, | 1014 | .probe = wm8750_probe, |
1013 | .remove = wm8750_remove, | 1015 | .remove = wm8750_remove, |
1014 | .suspend = wm8750_suspend, | 1016 | .suspend = wm8750_suspend, |
1015 | .resume = wm8750_resume, | 1017 | .resume = wm8750_resume, |
1016 | }; | 1018 | }; |
1017 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8750); | 1019 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8750); |
1018 | 1020 | ||
1019 | MODULE_DESCRIPTION("ASoC WM8750 driver"); | 1021 | MODULE_DESCRIPTION("ASoC WM8750 driver"); |
1020 | MODULE_AUTHOR("Liam Girdwood"); | 1022 | MODULE_AUTHOR("Liam Girdwood"); |
sound/soc/codecs/wm8753.c
1 | /* | 1 | /* |
2 | * wm8753.c -- WM8753 ALSA Soc Audio driver | 2 | * wm8753.c -- WM8753 ALSA Soc Audio driver |
3 | * | 3 | * |
4 | * Copyright 2003 Wolfson Microelectronics PLC. | 4 | * Copyright 2003 Wolfson Microelectronics PLC. |
5 | * Author: Liam Girdwood | 5 | * Author: Liam Girdwood |
6 | * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com | 6 | * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify it | 8 | * This program is free software; you can redistribute it and/or modify it |
9 | * under the terms of the GNU General Public License as published by the | 9 | * under the terms of the GNU General Public License as published by the |
10 | * Free Software Foundation; either version 2 of the License, or (at your | 10 | * Free Software Foundation; either version 2 of the License, or (at your |
11 | * option) any later version. | 11 | * option) any later version. |
12 | * | 12 | * |
13 | * Notes: | 13 | * Notes: |
14 | * The WM8753 is a low power, high quality stereo codec with integrated PCM | 14 | * The WM8753 is a low power, high quality stereo codec with integrated PCM |
15 | * codec designed for portable digital telephony applications. | 15 | * codec designed for portable digital telephony applications. |
16 | * | 16 | * |
17 | * Dual DAI:- | 17 | * Dual DAI:- |
18 | * | 18 | * |
19 | * This driver support 2 DAI PCM's. This makes the default PCM available for | 19 | * This driver support 2 DAI PCM's. This makes the default PCM available for |
20 | * HiFi audio (e.g. MP3, ogg) playback/capture and the other PCM available for | 20 | * HiFi audio (e.g. MP3, ogg) playback/capture and the other PCM available for |
21 | * voice. | 21 | * voice. |
22 | * | 22 | * |
23 | * Please note that the voice PCM can be connected directly to a Bluetooth | 23 | * Please note that the voice PCM can be connected directly to a Bluetooth |
24 | * codec or GSM modem and thus cannot be read or written to, although it is | 24 | * codec or GSM modem and thus cannot be read or written to, although it is |
25 | * available to be configured with snd_hw_params(), etc and kcontrols in the | 25 | * available to be configured with snd_hw_params(), etc and kcontrols in the |
26 | * normal alsa manner. | 26 | * normal alsa manner. |
27 | * | 27 | * |
28 | * Fast DAI switching:- | 28 | * Fast DAI switching:- |
29 | * | 29 | * |
30 | * The driver can now fast switch between the DAI configurations via a | 30 | * The driver can now fast switch between the DAI configurations via a |
31 | * an alsa kcontrol. This allows the PCM to remain open. | 31 | * an alsa kcontrol. This allows the PCM to remain open. |
32 | * | 32 | * |
33 | */ | 33 | */ |
34 | 34 | ||
35 | #include <linux/module.h> | 35 | #include <linux/module.h> |
36 | #include <linux/moduleparam.h> | 36 | #include <linux/moduleparam.h> |
37 | #include <linux/kernel.h> | 37 | #include <linux/kernel.h> |
38 | #include <linux/init.h> | 38 | #include <linux/init.h> |
39 | #include <linux/delay.h> | 39 | #include <linux/delay.h> |
40 | #include <linux/pm.h> | 40 | #include <linux/pm.h> |
41 | #include <linux/i2c.h> | 41 | #include <linux/i2c.h> |
42 | #include <linux/platform_device.h> | 42 | #include <linux/platform_device.h> |
43 | #include <sound/core.h> | 43 | #include <sound/core.h> |
44 | #include <sound/pcm.h> | 44 | #include <sound/pcm.h> |
45 | #include <sound/pcm_params.h> | 45 | #include <sound/pcm_params.h> |
46 | #include <sound/soc.h> | 46 | #include <sound/soc.h> |
47 | #include <sound/soc-dapm.h> | 47 | #include <sound/soc-dapm.h> |
48 | #include <sound/initval.h> | 48 | #include <sound/initval.h> |
49 | #include <sound/tlv.h> | 49 | #include <sound/tlv.h> |
50 | #include <asm/div64.h> | 50 | #include <asm/div64.h> |
51 | 51 | ||
52 | #include "wm8753.h" | 52 | #include "wm8753.h" |
53 | 53 | ||
54 | #define AUDIO_NAME "wm8753" | 54 | #define AUDIO_NAME "wm8753" |
55 | #define WM8753_VERSION "0.16" | 55 | #define WM8753_VERSION "0.16" |
56 | 56 | ||
57 | static int caps_charge = 2000; | 57 | static int caps_charge = 2000; |
58 | module_param(caps_charge, int, 0); | 58 | module_param(caps_charge, int, 0); |
59 | MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)"); | 59 | MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)"); |
60 | 60 | ||
61 | static void wm8753_set_dai_mode(struct snd_soc_codec *codec, | 61 | static void wm8753_set_dai_mode(struct snd_soc_codec *codec, |
62 | unsigned int mode); | 62 | unsigned int mode); |
63 | 63 | ||
64 | /* codec private data */ | 64 | /* codec private data */ |
65 | struct wm8753_priv { | 65 | struct wm8753_priv { |
66 | unsigned int sysclk; | 66 | unsigned int sysclk; |
67 | unsigned int pcmclk; | 67 | unsigned int pcmclk; |
68 | }; | 68 | }; |
69 | 69 | ||
70 | /* | 70 | /* |
71 | * wm8753 register cache | 71 | * wm8753 register cache |
72 | * We can't read the WM8753 register space when we | 72 | * We can't read the WM8753 register space when we |
73 | * are using 2 wire for device control, so we cache them instead. | 73 | * are using 2 wire for device control, so we cache them instead. |
74 | */ | 74 | */ |
75 | static const u16 wm8753_reg[] = { | 75 | static const u16 wm8753_reg[] = { |
76 | 0x0008, 0x0000, 0x000a, 0x000a, | 76 | 0x0008, 0x0000, 0x000a, 0x000a, |
77 | 0x0033, 0x0000, 0x0007, 0x00ff, | 77 | 0x0033, 0x0000, 0x0007, 0x00ff, |
78 | 0x00ff, 0x000f, 0x000f, 0x007b, | 78 | 0x00ff, 0x000f, 0x000f, 0x007b, |
79 | 0x0000, 0x0032, 0x0000, 0x00c3, | 79 | 0x0000, 0x0032, 0x0000, 0x00c3, |
80 | 0x00c3, 0x00c0, 0x0000, 0x0000, | 80 | 0x00c3, 0x00c0, 0x0000, 0x0000, |
81 | 0x0000, 0x0000, 0x0000, 0x0000, | 81 | 0x0000, 0x0000, 0x0000, 0x0000, |
82 | 0x0000, 0x0000, 0x0000, 0x0000, | 82 | 0x0000, 0x0000, 0x0000, 0x0000, |
83 | 0x0000, 0x0000, 0x0000, 0x0055, | 83 | 0x0000, 0x0000, 0x0000, 0x0055, |
84 | 0x0005, 0x0050, 0x0055, 0x0050, | 84 | 0x0005, 0x0050, 0x0055, 0x0050, |
85 | 0x0055, 0x0050, 0x0055, 0x0079, | 85 | 0x0055, 0x0050, 0x0055, 0x0079, |
86 | 0x0079, 0x0079, 0x0079, 0x0079, | 86 | 0x0079, 0x0079, 0x0079, 0x0079, |
87 | 0x0000, 0x0000, 0x0000, 0x0000, | 87 | 0x0000, 0x0000, 0x0000, 0x0000, |
88 | 0x0097, 0x0097, 0x0000, 0x0004, | 88 | 0x0097, 0x0097, 0x0000, 0x0004, |
89 | 0x0000, 0x0083, 0x0024, 0x01ba, | 89 | 0x0000, 0x0083, 0x0024, 0x01ba, |
90 | 0x0000, 0x0083, 0x0024, 0x01ba, | 90 | 0x0000, 0x0083, 0x0024, 0x01ba, |
91 | 0x0000, 0x0000 | 91 | 0x0000, 0x0000 |
92 | }; | 92 | }; |
93 | 93 | ||
94 | /* | 94 | /* |
95 | * read wm8753 register cache | 95 | * read wm8753 register cache |
96 | */ | 96 | */ |
97 | static inline unsigned int wm8753_read_reg_cache(struct snd_soc_codec *codec, | 97 | static inline unsigned int wm8753_read_reg_cache(struct snd_soc_codec *codec, |
98 | unsigned int reg) | 98 | unsigned int reg) |
99 | { | 99 | { |
100 | u16 *cache = codec->reg_cache; | 100 | u16 *cache = codec->reg_cache; |
101 | if (reg < 1 || reg > (ARRAY_SIZE(wm8753_reg) + 1)) | 101 | if (reg < 1 || reg > (ARRAY_SIZE(wm8753_reg) + 1)) |
102 | return -1; | 102 | return -1; |
103 | return cache[reg - 1]; | 103 | return cache[reg - 1]; |
104 | } | 104 | } |
105 | 105 | ||
106 | /* | 106 | /* |
107 | * write wm8753 register cache | 107 | * write wm8753 register cache |
108 | */ | 108 | */ |
109 | static inline void wm8753_write_reg_cache(struct snd_soc_codec *codec, | 109 | static inline void wm8753_write_reg_cache(struct snd_soc_codec *codec, |
110 | unsigned int reg, unsigned int value) | 110 | unsigned int reg, unsigned int value) |
111 | { | 111 | { |
112 | u16 *cache = codec->reg_cache; | 112 | u16 *cache = codec->reg_cache; |
113 | if (reg < 1 || reg > 0x3f) | 113 | if (reg < 1 || reg > 0x3f) |
114 | return; | 114 | return; |
115 | cache[reg - 1] = value; | 115 | cache[reg - 1] = value; |
116 | } | 116 | } |
117 | 117 | ||
118 | /* | 118 | /* |
119 | * write to the WM8753 register space | 119 | * write to the WM8753 register space |
120 | */ | 120 | */ |
121 | static int wm8753_write(struct snd_soc_codec *codec, unsigned int reg, | 121 | static int wm8753_write(struct snd_soc_codec *codec, unsigned int reg, |
122 | unsigned int value) | 122 | unsigned int value) |
123 | { | 123 | { |
124 | u8 data[2]; | 124 | u8 data[2]; |
125 | 125 | ||
126 | /* data is | 126 | /* data is |
127 | * D15..D9 WM8753 register offset | 127 | * D15..D9 WM8753 register offset |
128 | * D8...D0 register data | 128 | * D8...D0 register data |
129 | */ | 129 | */ |
130 | data[0] = (reg << 1) | ((value >> 8) & 0x0001); | 130 | data[0] = (reg << 1) | ((value >> 8) & 0x0001); |
131 | data[1] = value & 0x00ff; | 131 | data[1] = value & 0x00ff; |
132 | 132 | ||
133 | wm8753_write_reg_cache(codec, reg, value); | 133 | wm8753_write_reg_cache(codec, reg, value); |
134 | if (codec->hw_write(codec->control_data, data, 2) == 2) | 134 | if (codec->hw_write(codec->control_data, data, 2) == 2) |
135 | return 0; | 135 | return 0; |
136 | else | 136 | else |
137 | return -EIO; | 137 | return -EIO; |
138 | } | 138 | } |
139 | 139 | ||
140 | #define wm8753_reset(c) wm8753_write(c, WM8753_RESET, 0) | 140 | #define wm8753_reset(c) wm8753_write(c, WM8753_RESET, 0) |
141 | 141 | ||
142 | /* | 142 | /* |
143 | * WM8753 Controls | 143 | * WM8753 Controls |
144 | */ | 144 | */ |
145 | static const char *wm8753_base[] = {"Linear Control", "Adaptive Boost"}; | 145 | static const char *wm8753_base[] = {"Linear Control", "Adaptive Boost"}; |
146 | static const char *wm8753_base_filter[] = | 146 | static const char *wm8753_base_filter[] = |
147 | {"130Hz @ 48kHz", "200Hz @ 48kHz", "100Hz @ 16kHz", "400Hz @ 48kHz", | 147 | {"130Hz @ 48kHz", "200Hz @ 48kHz", "100Hz @ 16kHz", "400Hz @ 48kHz", |
148 | "100Hz @ 8kHz", "200Hz @ 8kHz"}; | 148 | "100Hz @ 8kHz", "200Hz @ 8kHz"}; |
149 | static const char *wm8753_treble[] = {"8kHz", "4kHz"}; | 149 | static const char *wm8753_treble[] = {"8kHz", "4kHz"}; |
150 | static const char *wm8753_alc_func[] = {"Off", "Right", "Left", "Stereo"}; | 150 | static const char *wm8753_alc_func[] = {"Off", "Right", "Left", "Stereo"}; |
151 | static const char *wm8753_ng_type[] = {"Constant PGA Gain", "Mute ADC Output"}; | 151 | static const char *wm8753_ng_type[] = {"Constant PGA Gain", "Mute ADC Output"}; |
152 | static const char *wm8753_3d_func[] = {"Capture", "Playback"}; | 152 | static const char *wm8753_3d_func[] = {"Capture", "Playback"}; |
153 | static const char *wm8753_3d_uc[] = {"2.2kHz", "1.5kHz"}; | 153 | static const char *wm8753_3d_uc[] = {"2.2kHz", "1.5kHz"}; |
154 | static const char *wm8753_3d_lc[] = {"200Hz", "500Hz"}; | 154 | static const char *wm8753_3d_lc[] = {"200Hz", "500Hz"}; |
155 | static const char *wm8753_deemp[] = {"None", "32kHz", "44.1kHz", "48kHz"}; | 155 | static const char *wm8753_deemp[] = {"None", "32kHz", "44.1kHz", "48kHz"}; |
156 | static const char *wm8753_mono_mix[] = {"Stereo", "Left", "Right", "Mono"}; | 156 | static const char *wm8753_mono_mix[] = {"Stereo", "Left", "Right", "Mono"}; |
157 | static const char *wm8753_dac_phase[] = {"Non Inverted", "Inverted"}; | 157 | static const char *wm8753_dac_phase[] = {"Non Inverted", "Inverted"}; |
158 | static const char *wm8753_line_mix[] = {"Line 1 + 2", "Line 1 - 2", | 158 | static const char *wm8753_line_mix[] = {"Line 1 + 2", "Line 1 - 2", |
159 | "Line 1", "Line 2"}; | 159 | "Line 1", "Line 2"}; |
160 | static const char *wm8753_mono_mux[] = {"Line Mix", "Rx Mix"}; | 160 | static const char *wm8753_mono_mux[] = {"Line Mix", "Rx Mix"}; |
161 | static const char *wm8753_right_mux[] = {"Line 2", "Rx Mix"}; | 161 | static const char *wm8753_right_mux[] = {"Line 2", "Rx Mix"}; |
162 | static const char *wm8753_left_mux[] = {"Line 1", "Rx Mix"}; | 162 | static const char *wm8753_left_mux[] = {"Line 1", "Rx Mix"}; |
163 | static const char *wm8753_rxmsel[] = {"RXP - RXN", "RXP + RXN", "RXP", "RXN"}; | 163 | static const char *wm8753_rxmsel[] = {"RXP - RXN", "RXP + RXN", "RXP", "RXN"}; |
164 | static const char *wm8753_sidetone_mux[] = {"Left PGA", "Mic 1", "Mic 2", | 164 | static const char *wm8753_sidetone_mux[] = {"Left PGA", "Mic 1", "Mic 2", |
165 | "Right PGA"}; | 165 | "Right PGA"}; |
166 | static const char *wm8753_mono2_src[] = {"Inverted Mono 1", "Left", "Right", | 166 | static const char *wm8753_mono2_src[] = {"Inverted Mono 1", "Left", "Right", |
167 | "Left + Right"}; | 167 | "Left + Right"}; |
168 | static const char *wm8753_out3[] = {"VREF", "ROUT2", "Left + Right"}; | 168 | static const char *wm8753_out3[] = {"VREF", "ROUT2", "Left + Right"}; |
169 | static const char *wm8753_out4[] = {"VREF", "Capture ST", "LOUT2"}; | 169 | static const char *wm8753_out4[] = {"VREF", "Capture ST", "LOUT2"}; |
170 | static const char *wm8753_radcsel[] = {"PGA", "Line or RXP-RXN", "Sidetone"}; | 170 | static const char *wm8753_radcsel[] = {"PGA", "Line or RXP-RXN", "Sidetone"}; |
171 | static const char *wm8753_ladcsel[] = {"PGA", "Line or RXP-RXN", "Line"}; | 171 | static const char *wm8753_ladcsel[] = {"PGA", "Line or RXP-RXN", "Line"}; |
172 | static const char *wm8753_mono_adc[] = {"Stereo", "Analogue Mix Left", | 172 | static const char *wm8753_mono_adc[] = {"Stereo", "Analogue Mix Left", |
173 | "Analogue Mix Right", "Digital Mono Mix"}; | 173 | "Analogue Mix Right", "Digital Mono Mix"}; |
174 | static const char *wm8753_adc_hp[] = {"3.4Hz @ 48kHz", "82Hz @ 16k", | 174 | static const char *wm8753_adc_hp[] = {"3.4Hz @ 48kHz", "82Hz @ 16k", |
175 | "82Hz @ 8kHz", "170Hz @ 8kHz"}; | 175 | "82Hz @ 8kHz", "170Hz @ 8kHz"}; |
176 | static const char *wm8753_adc_filter[] = {"HiFi", "Voice"}; | 176 | static const char *wm8753_adc_filter[] = {"HiFi", "Voice"}; |
177 | static const char *wm8753_mic_sel[] = {"Mic 1", "Mic 2", "Mic 3"}; | 177 | static const char *wm8753_mic_sel[] = {"Mic 1", "Mic 2", "Mic 3"}; |
178 | static const char *wm8753_dai_mode[] = {"DAI 0", "DAI 1", "DAI 2", "DAI 3"}; | 178 | static const char *wm8753_dai_mode[] = {"DAI 0", "DAI 1", "DAI 2", "DAI 3"}; |
179 | static const char *wm8753_dat_sel[] = {"Stereo", "Left ADC", "Right ADC", | 179 | static const char *wm8753_dat_sel[] = {"Stereo", "Left ADC", "Right ADC", |
180 | "Channel Swap"}; | 180 | "Channel Swap"}; |
181 | static const char *wm8753_rout2_phase[] = {"Non Inverted", "Inverted"}; | 181 | static const char *wm8753_rout2_phase[] = {"Non Inverted", "Inverted"}; |
182 | 182 | ||
183 | static const struct soc_enum wm8753_enum[] = { | 183 | static const struct soc_enum wm8753_enum[] = { |
184 | SOC_ENUM_SINGLE(WM8753_BASS, 7, 2, wm8753_base), | 184 | SOC_ENUM_SINGLE(WM8753_BASS, 7, 2, wm8753_base), |
185 | SOC_ENUM_SINGLE(WM8753_BASS, 4, 6, wm8753_base_filter), | 185 | SOC_ENUM_SINGLE(WM8753_BASS, 4, 6, wm8753_base_filter), |
186 | SOC_ENUM_SINGLE(WM8753_TREBLE, 6, 2, wm8753_treble), | 186 | SOC_ENUM_SINGLE(WM8753_TREBLE, 6, 2, wm8753_treble), |
187 | SOC_ENUM_SINGLE(WM8753_ALC1, 7, 4, wm8753_alc_func), | 187 | SOC_ENUM_SINGLE(WM8753_ALC1, 7, 4, wm8753_alc_func), |
188 | SOC_ENUM_SINGLE(WM8753_NGATE, 1, 2, wm8753_ng_type), | 188 | SOC_ENUM_SINGLE(WM8753_NGATE, 1, 2, wm8753_ng_type), |
189 | SOC_ENUM_SINGLE(WM8753_3D, 7, 2, wm8753_3d_func), | 189 | SOC_ENUM_SINGLE(WM8753_3D, 7, 2, wm8753_3d_func), |
190 | SOC_ENUM_SINGLE(WM8753_3D, 6, 2, wm8753_3d_uc), | 190 | SOC_ENUM_SINGLE(WM8753_3D, 6, 2, wm8753_3d_uc), |
191 | SOC_ENUM_SINGLE(WM8753_3D, 5, 2, wm8753_3d_lc), | 191 | SOC_ENUM_SINGLE(WM8753_3D, 5, 2, wm8753_3d_lc), |
192 | SOC_ENUM_SINGLE(WM8753_DAC, 1, 4, wm8753_deemp), | 192 | SOC_ENUM_SINGLE(WM8753_DAC, 1, 4, wm8753_deemp), |
193 | SOC_ENUM_SINGLE(WM8753_DAC, 4, 4, wm8753_mono_mix), | 193 | SOC_ENUM_SINGLE(WM8753_DAC, 4, 4, wm8753_mono_mix), |
194 | SOC_ENUM_SINGLE(WM8753_DAC, 6, 2, wm8753_dac_phase), | 194 | SOC_ENUM_SINGLE(WM8753_DAC, 6, 2, wm8753_dac_phase), |
195 | SOC_ENUM_SINGLE(WM8753_INCTL1, 3, 4, wm8753_line_mix), | 195 | SOC_ENUM_SINGLE(WM8753_INCTL1, 3, 4, wm8753_line_mix), |
196 | SOC_ENUM_SINGLE(WM8753_INCTL1, 2, 2, wm8753_mono_mux), | 196 | SOC_ENUM_SINGLE(WM8753_INCTL1, 2, 2, wm8753_mono_mux), |
197 | SOC_ENUM_SINGLE(WM8753_INCTL1, 1, 2, wm8753_right_mux), | 197 | SOC_ENUM_SINGLE(WM8753_INCTL1, 1, 2, wm8753_right_mux), |
198 | SOC_ENUM_SINGLE(WM8753_INCTL1, 0, 2, wm8753_left_mux), | 198 | SOC_ENUM_SINGLE(WM8753_INCTL1, 0, 2, wm8753_left_mux), |
199 | SOC_ENUM_SINGLE(WM8753_INCTL2, 6, 4, wm8753_rxmsel), | 199 | SOC_ENUM_SINGLE(WM8753_INCTL2, 6, 4, wm8753_rxmsel), |
200 | SOC_ENUM_SINGLE(WM8753_INCTL2, 4, 4, wm8753_sidetone_mux), | 200 | SOC_ENUM_SINGLE(WM8753_INCTL2, 4, 4, wm8753_sidetone_mux), |
201 | SOC_ENUM_SINGLE(WM8753_OUTCTL, 7, 4, wm8753_mono2_src), | 201 | SOC_ENUM_SINGLE(WM8753_OUTCTL, 7, 4, wm8753_mono2_src), |
202 | SOC_ENUM_SINGLE(WM8753_OUTCTL, 0, 3, wm8753_out3), | 202 | SOC_ENUM_SINGLE(WM8753_OUTCTL, 0, 3, wm8753_out3), |
203 | SOC_ENUM_SINGLE(WM8753_ADCTL2, 7, 3, wm8753_out4), | 203 | SOC_ENUM_SINGLE(WM8753_ADCTL2, 7, 3, wm8753_out4), |
204 | SOC_ENUM_SINGLE(WM8753_ADCIN, 2, 3, wm8753_radcsel), | 204 | SOC_ENUM_SINGLE(WM8753_ADCIN, 2, 3, wm8753_radcsel), |
205 | SOC_ENUM_SINGLE(WM8753_ADCIN, 0, 3, wm8753_ladcsel), | 205 | SOC_ENUM_SINGLE(WM8753_ADCIN, 0, 3, wm8753_ladcsel), |
206 | SOC_ENUM_SINGLE(WM8753_ADCIN, 4, 4, wm8753_mono_adc), | 206 | SOC_ENUM_SINGLE(WM8753_ADCIN, 4, 4, wm8753_mono_adc), |
207 | SOC_ENUM_SINGLE(WM8753_ADC, 2, 4, wm8753_adc_hp), | 207 | SOC_ENUM_SINGLE(WM8753_ADC, 2, 4, wm8753_adc_hp), |
208 | SOC_ENUM_SINGLE(WM8753_ADC, 4, 2, wm8753_adc_filter), | 208 | SOC_ENUM_SINGLE(WM8753_ADC, 4, 2, wm8753_adc_filter), |
209 | SOC_ENUM_SINGLE(WM8753_MICBIAS, 6, 3, wm8753_mic_sel), | 209 | SOC_ENUM_SINGLE(WM8753_MICBIAS, 6, 3, wm8753_mic_sel), |
210 | SOC_ENUM_SINGLE(WM8753_IOCTL, 2, 4, wm8753_dai_mode), | 210 | SOC_ENUM_SINGLE(WM8753_IOCTL, 2, 4, wm8753_dai_mode), |
211 | SOC_ENUM_SINGLE(WM8753_ADC, 7, 4, wm8753_dat_sel), | 211 | SOC_ENUM_SINGLE(WM8753_ADC, 7, 4, wm8753_dat_sel), |
212 | SOC_ENUM_SINGLE(WM8753_OUTCTL, 2, 2, wm8753_rout2_phase), | 212 | SOC_ENUM_SINGLE(WM8753_OUTCTL, 2, 2, wm8753_rout2_phase), |
213 | }; | 213 | }; |
214 | 214 | ||
215 | 215 | ||
216 | static int wm8753_get_dai(struct snd_kcontrol *kcontrol, | 216 | static int wm8753_get_dai(struct snd_kcontrol *kcontrol, |
217 | struct snd_ctl_elem_value *ucontrol) | 217 | struct snd_ctl_elem_value *ucontrol) |
218 | { | 218 | { |
219 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 219 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
220 | int mode = wm8753_read_reg_cache(codec, WM8753_IOCTL); | 220 | int mode = wm8753_read_reg_cache(codec, WM8753_IOCTL); |
221 | 221 | ||
222 | ucontrol->value.integer.value[0] = (mode & 0xc) >> 2; | 222 | ucontrol->value.integer.value[0] = (mode & 0xc) >> 2; |
223 | return 0; | 223 | return 0; |
224 | } | 224 | } |
225 | 225 | ||
226 | static int wm8753_set_dai(struct snd_kcontrol *kcontrol, | 226 | static int wm8753_set_dai(struct snd_kcontrol *kcontrol, |
227 | struct snd_ctl_elem_value *ucontrol) | 227 | struct snd_ctl_elem_value *ucontrol) |
228 | { | 228 | { |
229 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 229 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
230 | int mode = wm8753_read_reg_cache(codec, WM8753_IOCTL); | 230 | int mode = wm8753_read_reg_cache(codec, WM8753_IOCTL); |
231 | 231 | ||
232 | if (((mode & 0xc) >> 2) == ucontrol->value.integer.value[0]) | 232 | if (((mode & 0xc) >> 2) == ucontrol->value.integer.value[0]) |
233 | return 0; | 233 | return 0; |
234 | 234 | ||
235 | mode &= 0xfff3; | 235 | mode &= 0xfff3; |
236 | mode |= (ucontrol->value.integer.value[0] << 2); | 236 | mode |= (ucontrol->value.integer.value[0] << 2); |
237 | 237 | ||
238 | wm8753_write(codec, WM8753_IOCTL, mode); | 238 | wm8753_write(codec, WM8753_IOCTL, mode); |
239 | wm8753_set_dai_mode(codec, ucontrol->value.integer.value[0]); | 239 | wm8753_set_dai_mode(codec, ucontrol->value.integer.value[0]); |
240 | return 1; | 240 | return 1; |
241 | } | 241 | } |
242 | 242 | ||
243 | static const DECLARE_TLV_DB_SCALE(rec_mix_tlv, -1500, 300, 0); | 243 | static const DECLARE_TLV_DB_SCALE(rec_mix_tlv, -1500, 300, 0); |
244 | static const DECLARE_TLV_DB_SCALE(mic_preamp_tlv, 1200, 600, 0); | 244 | static const DECLARE_TLV_DB_SCALE(mic_preamp_tlv, 1200, 600, 0); |
245 | static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1); | 245 | static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1); |
246 | static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); | 246 | static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); |
247 | static const unsigned int out_tlv[] = { | 247 | static const unsigned int out_tlv[] = { |
248 | TLV_DB_RANGE_HEAD(2), | 248 | TLV_DB_RANGE_HEAD(2), |
249 | /* 0000000 - 0101111 = "Analogue mute" */ | 249 | /* 0000000 - 0101111 = "Analogue mute" */ |
250 | 0, 48, TLV_DB_SCALE_ITEM(-25500, 0, 0), | 250 | 0, 48, TLV_DB_SCALE_ITEM(-25500, 0, 0), |
251 | 48, 127, TLV_DB_SCALE_ITEM(-7300, 100, 0), | 251 | 48, 127, TLV_DB_SCALE_ITEM(-7300, 100, 0), |
252 | }; | 252 | }; |
253 | static const DECLARE_TLV_DB_SCALE(mix_tlv, -1500, 300, 0); | 253 | static const DECLARE_TLV_DB_SCALE(mix_tlv, -1500, 300, 0); |
254 | static const DECLARE_TLV_DB_SCALE(voice_mix_tlv, -1200, 300, 0); | 254 | static const DECLARE_TLV_DB_SCALE(voice_mix_tlv, -1200, 300, 0); |
255 | static const DECLARE_TLV_DB_SCALE(pga_tlv, -1725, 75, 0); | 255 | static const DECLARE_TLV_DB_SCALE(pga_tlv, -1725, 75, 0); |
256 | 256 | ||
257 | static const struct snd_kcontrol_new wm8753_snd_controls[] = { | 257 | static const struct snd_kcontrol_new wm8753_snd_controls[] = { |
258 | SOC_DOUBLE_R_TLV("PCM Volume", WM8753_LDAC, WM8753_RDAC, 0, 255, 0, dac_tlv), | 258 | SOC_DOUBLE_R_TLV("PCM Volume", WM8753_LDAC, WM8753_RDAC, 0, 255, 0, dac_tlv), |
259 | 259 | ||
260 | SOC_DOUBLE_R_TLV("ADC Capture Volume", WM8753_LADC, WM8753_RADC, 0, 255, 0, | 260 | SOC_DOUBLE_R_TLV("ADC Capture Volume", WM8753_LADC, WM8753_RADC, 0, 255, 0, |
261 | adc_tlv), | 261 | adc_tlv), |
262 | 262 | ||
263 | SOC_DOUBLE_R_TLV("Headphone Playback Volume", WM8753_LOUT1V, WM8753_ROUT1V, | 263 | SOC_DOUBLE_R_TLV("Headphone Playback Volume", WM8753_LOUT1V, WM8753_ROUT1V, |
264 | 0, 127, 0, out_tlv), | 264 | 0, 127, 0, out_tlv), |
265 | SOC_DOUBLE_R_TLV("Speaker Playback Volume", WM8753_LOUT2V, WM8753_ROUT2V, 0, | 265 | SOC_DOUBLE_R_TLV("Speaker Playback Volume", WM8753_LOUT2V, WM8753_ROUT2V, 0, |
266 | 127, 0, out_tlv), | 266 | 127, 0, out_tlv), |
267 | 267 | ||
268 | SOC_SINGLE_TLV("Mono Playback Volume", WM8753_MOUTV, 0, 127, 0, out_tlv), | 268 | SOC_SINGLE_TLV("Mono Playback Volume", WM8753_MOUTV, 0, 127, 0, out_tlv), |
269 | 269 | ||
270 | SOC_DOUBLE_R_TLV("Bypass Playback Volume", WM8753_LOUTM1, WM8753_ROUTM1, 4, 7, | 270 | SOC_DOUBLE_R_TLV("Bypass Playback Volume", WM8753_LOUTM1, WM8753_ROUTM1, 4, 7, |
271 | 1, mix_tlv), | 271 | 1, mix_tlv), |
272 | SOC_DOUBLE_R_TLV("Sidetone Playback Volume", WM8753_LOUTM2, WM8753_ROUTM2, 4, | 272 | SOC_DOUBLE_R_TLV("Sidetone Playback Volume", WM8753_LOUTM2, WM8753_ROUTM2, 4, |
273 | 7, 1, mix_tlv), | 273 | 7, 1, mix_tlv), |
274 | SOC_DOUBLE_R_TLV("Voice Playback Volume", WM8753_LOUTM2, WM8753_ROUTM2, 0, 7, | 274 | SOC_DOUBLE_R_TLV("Voice Playback Volume", WM8753_LOUTM2, WM8753_ROUTM2, 0, 7, |
275 | 1, voice_mix_tlv), | 275 | 1, voice_mix_tlv), |
276 | 276 | ||
277 | SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8753_LOUT1V, WM8753_ROUT1V, 7, | 277 | SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8753_LOUT1V, WM8753_ROUT1V, 7, |
278 | 1, 0), | 278 | 1, 0), |
279 | SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8753_LOUT2V, WM8753_ROUT2V, 7, | 279 | SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8753_LOUT2V, WM8753_ROUT2V, 7, |
280 | 1, 0), | 280 | 1, 0), |
281 | 281 | ||
282 | SOC_SINGLE_TLV("Mono Bypass Playback Volume", WM8753_MOUTM1, 4, 7, 1, mix_tlv), | 282 | SOC_SINGLE_TLV("Mono Bypass Playback Volume", WM8753_MOUTM1, 4, 7, 1, mix_tlv), |
283 | SOC_SINGLE_TLV("Mono Sidetone Playback Volume", WM8753_MOUTM2, 4, 7, 1, | 283 | SOC_SINGLE_TLV("Mono Sidetone Playback Volume", WM8753_MOUTM2, 4, 7, 1, |
284 | mix_tlv), | 284 | mix_tlv), |
285 | SOC_SINGLE_TLV("Mono Voice Playback Volume", WM8753_MOUTM2, 0, 7, 1, | 285 | SOC_SINGLE_TLV("Mono Voice Playback Volume", WM8753_MOUTM2, 0, 7, 1, |
286 | voice_mix_tlv), | 286 | voice_mix_tlv), |
287 | SOC_SINGLE("Mono Playback ZC Switch", WM8753_MOUTV, 7, 1, 0), | 287 | SOC_SINGLE("Mono Playback ZC Switch", WM8753_MOUTV, 7, 1, 0), |
288 | 288 | ||
289 | SOC_ENUM("Bass Boost", wm8753_enum[0]), | 289 | SOC_ENUM("Bass Boost", wm8753_enum[0]), |
290 | SOC_ENUM("Bass Filter", wm8753_enum[1]), | 290 | SOC_ENUM("Bass Filter", wm8753_enum[1]), |
291 | SOC_SINGLE("Bass Volume", WM8753_BASS, 0, 15, 1), | 291 | SOC_SINGLE("Bass Volume", WM8753_BASS, 0, 15, 1), |
292 | 292 | ||
293 | SOC_SINGLE("Treble Volume", WM8753_TREBLE, 0, 15, 1), | 293 | SOC_SINGLE("Treble Volume", WM8753_TREBLE, 0, 15, 1), |
294 | SOC_ENUM("Treble Cut-off", wm8753_enum[2]), | 294 | SOC_ENUM("Treble Cut-off", wm8753_enum[2]), |
295 | 295 | ||
296 | SOC_DOUBLE_TLV("Sidetone Capture Volume", WM8753_RECMIX1, 0, 4, 7, 1, | 296 | SOC_DOUBLE_TLV("Sidetone Capture Volume", WM8753_RECMIX1, 0, 4, 7, 1, |
297 | rec_mix_tlv), | 297 | rec_mix_tlv), |
298 | SOC_SINGLE_TLV("Voice Sidetone Capture Volume", WM8753_RECMIX2, 0, 7, 1, | 298 | SOC_SINGLE_TLV("Voice Sidetone Capture Volume", WM8753_RECMIX2, 0, 7, 1, |
299 | rec_mix_tlv), | 299 | rec_mix_tlv), |
300 | 300 | ||
301 | SOC_DOUBLE_R_TLV("Capture Volume", WM8753_LINVOL, WM8753_RINVOL, 0, 63, 0, | 301 | SOC_DOUBLE_R_TLV("Capture Volume", WM8753_LINVOL, WM8753_RINVOL, 0, 63, 0, |
302 | pga_tlv), | 302 | pga_tlv), |
303 | SOC_DOUBLE_R("Capture ZC Switch", WM8753_LINVOL, WM8753_RINVOL, 6, 1, 0), | 303 | SOC_DOUBLE_R("Capture ZC Switch", WM8753_LINVOL, WM8753_RINVOL, 6, 1, 0), |
304 | SOC_DOUBLE_R("Capture Switch", WM8753_LINVOL, WM8753_RINVOL, 7, 1, 1), | 304 | SOC_DOUBLE_R("Capture Switch", WM8753_LINVOL, WM8753_RINVOL, 7, 1, 1), |
305 | 305 | ||
306 | SOC_ENUM("Capture Filter Select", wm8753_enum[23]), | 306 | SOC_ENUM("Capture Filter Select", wm8753_enum[23]), |
307 | SOC_ENUM("Capture Filter Cut-off", wm8753_enum[24]), | 307 | SOC_ENUM("Capture Filter Cut-off", wm8753_enum[24]), |
308 | SOC_SINGLE("Capture Filter Switch", WM8753_ADC, 0, 1, 1), | 308 | SOC_SINGLE("Capture Filter Switch", WM8753_ADC, 0, 1, 1), |
309 | 309 | ||
310 | SOC_SINGLE("ALC Capture Target Volume", WM8753_ALC1, 0, 7, 0), | 310 | SOC_SINGLE("ALC Capture Target Volume", WM8753_ALC1, 0, 7, 0), |
311 | SOC_SINGLE("ALC Capture Max Volume", WM8753_ALC1, 4, 7, 0), | 311 | SOC_SINGLE("ALC Capture Max Volume", WM8753_ALC1, 4, 7, 0), |
312 | SOC_ENUM("ALC Capture Function", wm8753_enum[3]), | 312 | SOC_ENUM("ALC Capture Function", wm8753_enum[3]), |
313 | SOC_SINGLE("ALC Capture ZC Switch", WM8753_ALC2, 8, 1, 0), | 313 | SOC_SINGLE("ALC Capture ZC Switch", WM8753_ALC2, 8, 1, 0), |
314 | SOC_SINGLE("ALC Capture Hold Time", WM8753_ALC2, 0, 15, 1), | 314 | SOC_SINGLE("ALC Capture Hold Time", WM8753_ALC2, 0, 15, 1), |
315 | SOC_SINGLE("ALC Capture Decay Time", WM8753_ALC3, 4, 15, 1), | 315 | SOC_SINGLE("ALC Capture Decay Time", WM8753_ALC3, 4, 15, 1), |
316 | SOC_SINGLE("ALC Capture Attack Time", WM8753_ALC3, 0, 15, 0), | 316 | SOC_SINGLE("ALC Capture Attack Time", WM8753_ALC3, 0, 15, 0), |
317 | SOC_SINGLE("ALC Capture NG Threshold", WM8753_NGATE, 3, 31, 0), | 317 | SOC_SINGLE("ALC Capture NG Threshold", WM8753_NGATE, 3, 31, 0), |
318 | SOC_ENUM("ALC Capture NG Type", wm8753_enum[4]), | 318 | SOC_ENUM("ALC Capture NG Type", wm8753_enum[4]), |
319 | SOC_SINGLE("ALC Capture NG Switch", WM8753_NGATE, 0, 1, 0), | 319 | SOC_SINGLE("ALC Capture NG Switch", WM8753_NGATE, 0, 1, 0), |
320 | 320 | ||
321 | SOC_ENUM("3D Function", wm8753_enum[5]), | 321 | SOC_ENUM("3D Function", wm8753_enum[5]), |
322 | SOC_ENUM("3D Upper Cut-off", wm8753_enum[6]), | 322 | SOC_ENUM("3D Upper Cut-off", wm8753_enum[6]), |
323 | SOC_ENUM("3D Lower Cut-off", wm8753_enum[7]), | 323 | SOC_ENUM("3D Lower Cut-off", wm8753_enum[7]), |
324 | SOC_SINGLE("3D Volume", WM8753_3D, 1, 15, 0), | 324 | SOC_SINGLE("3D Volume", WM8753_3D, 1, 15, 0), |
325 | SOC_SINGLE("3D Switch", WM8753_3D, 0, 1, 0), | 325 | SOC_SINGLE("3D Switch", WM8753_3D, 0, 1, 0), |
326 | 326 | ||
327 | SOC_SINGLE("Capture 6dB Attenuate", WM8753_ADCTL1, 2, 1, 0), | 327 | SOC_SINGLE("Capture 6dB Attenuate", WM8753_ADCTL1, 2, 1, 0), |
328 | SOC_SINGLE("Playback 6dB Attenuate", WM8753_ADCTL1, 1, 1, 0), | 328 | SOC_SINGLE("Playback 6dB Attenuate", WM8753_ADCTL1, 1, 1, 0), |
329 | 329 | ||
330 | SOC_ENUM("De-emphasis", wm8753_enum[8]), | 330 | SOC_ENUM("De-emphasis", wm8753_enum[8]), |
331 | SOC_ENUM("Playback Mono Mix", wm8753_enum[9]), | 331 | SOC_ENUM("Playback Mono Mix", wm8753_enum[9]), |
332 | SOC_ENUM("Playback Phase", wm8753_enum[10]), | 332 | SOC_ENUM("Playback Phase", wm8753_enum[10]), |
333 | 333 | ||
334 | SOC_SINGLE_TLV("Mic2 Capture Volume", WM8753_INCTL1, 7, 3, 0, mic_preamp_tlv), | 334 | SOC_SINGLE_TLV("Mic2 Capture Volume", WM8753_INCTL1, 7, 3, 0, mic_preamp_tlv), |
335 | SOC_SINGLE_TLV("Mic1 Capture Volume", WM8753_INCTL1, 5, 3, 0, mic_preamp_tlv), | 335 | SOC_SINGLE_TLV("Mic1 Capture Volume", WM8753_INCTL1, 5, 3, 0, mic_preamp_tlv), |
336 | 336 | ||
337 | SOC_ENUM_EXT("DAI Mode", wm8753_enum[26], wm8753_get_dai, wm8753_set_dai), | 337 | SOC_ENUM_EXT("DAI Mode", wm8753_enum[26], wm8753_get_dai, wm8753_set_dai), |
338 | 338 | ||
339 | SOC_ENUM("ADC Data Select", wm8753_enum[27]), | 339 | SOC_ENUM("ADC Data Select", wm8753_enum[27]), |
340 | SOC_ENUM("ROUT2 Phase", wm8753_enum[28]), | 340 | SOC_ENUM("ROUT2 Phase", wm8753_enum[28]), |
341 | }; | 341 | }; |
342 | 342 | ||
343 | /* add non dapm controls */ | 343 | /* add non dapm controls */ |
344 | static int wm8753_add_controls(struct snd_soc_codec *codec) | 344 | static int wm8753_add_controls(struct snd_soc_codec *codec) |
345 | { | 345 | { |
346 | int err, i; | 346 | int err, i; |
347 | 347 | ||
348 | for (i = 0; i < ARRAY_SIZE(wm8753_snd_controls); i++) { | 348 | for (i = 0; i < ARRAY_SIZE(wm8753_snd_controls); i++) { |
349 | err = snd_ctl_add(codec->card, | 349 | err = snd_ctl_add(codec->card, |
350 | snd_soc_cnew(&wm8753_snd_controls[i], | 350 | snd_soc_cnew(&wm8753_snd_controls[i], |
351 | codec, NULL)); | 351 | codec, NULL)); |
352 | if (err < 0) | 352 | if (err < 0) |
353 | return err; | 353 | return err; |
354 | } | 354 | } |
355 | return 0; | 355 | return 0; |
356 | } | 356 | } |
357 | 357 | ||
358 | /* | 358 | /* |
359 | * _DAPM_ Controls | 359 | * _DAPM_ Controls |
360 | */ | 360 | */ |
361 | 361 | ||
362 | /* Left Mixer */ | 362 | /* Left Mixer */ |
363 | static const struct snd_kcontrol_new wm8753_left_mixer_controls[] = { | 363 | static const struct snd_kcontrol_new wm8753_left_mixer_controls[] = { |
364 | SOC_DAPM_SINGLE("Voice Playback Switch", WM8753_LOUTM2, 8, 1, 0), | 364 | SOC_DAPM_SINGLE("Voice Playback Switch", WM8753_LOUTM2, 8, 1, 0), |
365 | SOC_DAPM_SINGLE("Sidetone Playback Switch", WM8753_LOUTM2, 7, 1, 0), | 365 | SOC_DAPM_SINGLE("Sidetone Playback Switch", WM8753_LOUTM2, 7, 1, 0), |
366 | SOC_DAPM_SINGLE("Left Playback Switch", WM8753_LOUTM1, 8, 1, 0), | 366 | SOC_DAPM_SINGLE("Left Playback Switch", WM8753_LOUTM1, 8, 1, 0), |
367 | SOC_DAPM_SINGLE("Bypass Playback Switch", WM8753_LOUTM1, 7, 1, 0), | 367 | SOC_DAPM_SINGLE("Bypass Playback Switch", WM8753_LOUTM1, 7, 1, 0), |
368 | }; | 368 | }; |
369 | 369 | ||
370 | /* Right mixer */ | 370 | /* Right mixer */ |
371 | static const struct snd_kcontrol_new wm8753_right_mixer_controls[] = { | 371 | static const struct snd_kcontrol_new wm8753_right_mixer_controls[] = { |
372 | SOC_DAPM_SINGLE("Voice Playback Switch", WM8753_ROUTM2, 8, 1, 0), | 372 | SOC_DAPM_SINGLE("Voice Playback Switch", WM8753_ROUTM2, 8, 1, 0), |
373 | SOC_DAPM_SINGLE("Sidetone Playback Switch", WM8753_ROUTM2, 7, 1, 0), | 373 | SOC_DAPM_SINGLE("Sidetone Playback Switch", WM8753_ROUTM2, 7, 1, 0), |
374 | SOC_DAPM_SINGLE("Right Playback Switch", WM8753_ROUTM1, 8, 1, 0), | 374 | SOC_DAPM_SINGLE("Right Playback Switch", WM8753_ROUTM1, 8, 1, 0), |
375 | SOC_DAPM_SINGLE("Bypass Playback Switch", WM8753_ROUTM1, 7, 1, 0), | 375 | SOC_DAPM_SINGLE("Bypass Playback Switch", WM8753_ROUTM1, 7, 1, 0), |
376 | }; | 376 | }; |
377 | 377 | ||
378 | /* Mono mixer */ | 378 | /* Mono mixer */ |
379 | static const struct snd_kcontrol_new wm8753_mono_mixer_controls[] = { | 379 | static const struct snd_kcontrol_new wm8753_mono_mixer_controls[] = { |
380 | SOC_DAPM_SINGLE("Left Playback Switch", WM8753_MOUTM1, 8, 1, 0), | 380 | SOC_DAPM_SINGLE("Left Playback Switch", WM8753_MOUTM1, 8, 1, 0), |
381 | SOC_DAPM_SINGLE("Right Playback Switch", WM8753_MOUTM2, 8, 1, 0), | 381 | SOC_DAPM_SINGLE("Right Playback Switch", WM8753_MOUTM2, 8, 1, 0), |
382 | SOC_DAPM_SINGLE("Voice Playback Switch", WM8753_MOUTM2, 3, 1, 0), | 382 | SOC_DAPM_SINGLE("Voice Playback Switch", WM8753_MOUTM2, 3, 1, 0), |
383 | SOC_DAPM_SINGLE("Sidetone Playback Switch", WM8753_MOUTM2, 7, 1, 0), | 383 | SOC_DAPM_SINGLE("Sidetone Playback Switch", WM8753_MOUTM2, 7, 1, 0), |
384 | SOC_DAPM_SINGLE("Bypass Playback Switch", WM8753_MOUTM1, 7, 1, 0), | 384 | SOC_DAPM_SINGLE("Bypass Playback Switch", WM8753_MOUTM1, 7, 1, 0), |
385 | }; | 385 | }; |
386 | 386 | ||
387 | /* Mono 2 Mux */ | 387 | /* Mono 2 Mux */ |
388 | static const struct snd_kcontrol_new wm8753_mono2_controls = | 388 | static const struct snd_kcontrol_new wm8753_mono2_controls = |
389 | SOC_DAPM_ENUM("Route", wm8753_enum[17]); | 389 | SOC_DAPM_ENUM("Route", wm8753_enum[17]); |
390 | 390 | ||
391 | /* Out 3 Mux */ | 391 | /* Out 3 Mux */ |
392 | static const struct snd_kcontrol_new wm8753_out3_controls = | 392 | static const struct snd_kcontrol_new wm8753_out3_controls = |
393 | SOC_DAPM_ENUM("Route", wm8753_enum[18]); | 393 | SOC_DAPM_ENUM("Route", wm8753_enum[18]); |
394 | 394 | ||
395 | /* Out 4 Mux */ | 395 | /* Out 4 Mux */ |
396 | static const struct snd_kcontrol_new wm8753_out4_controls = | 396 | static const struct snd_kcontrol_new wm8753_out4_controls = |
397 | SOC_DAPM_ENUM("Route", wm8753_enum[19]); | 397 | SOC_DAPM_ENUM("Route", wm8753_enum[19]); |
398 | 398 | ||
399 | /* ADC Mono Mix */ | 399 | /* ADC Mono Mix */ |
400 | static const struct snd_kcontrol_new wm8753_adc_mono_controls = | 400 | static const struct snd_kcontrol_new wm8753_adc_mono_controls = |
401 | SOC_DAPM_ENUM("Route", wm8753_enum[22]); | 401 | SOC_DAPM_ENUM("Route", wm8753_enum[22]); |
402 | 402 | ||
403 | /* Record mixer */ | 403 | /* Record mixer */ |
404 | static const struct snd_kcontrol_new wm8753_record_mixer_controls[] = { | 404 | static const struct snd_kcontrol_new wm8753_record_mixer_controls[] = { |
405 | SOC_DAPM_SINGLE("Voice Capture Switch", WM8753_RECMIX2, 3, 1, 0), | 405 | SOC_DAPM_SINGLE("Voice Capture Switch", WM8753_RECMIX2, 3, 1, 0), |
406 | SOC_DAPM_SINGLE("Left Capture Switch", WM8753_RECMIX1, 3, 1, 0), | 406 | SOC_DAPM_SINGLE("Left Capture Switch", WM8753_RECMIX1, 3, 1, 0), |
407 | SOC_DAPM_SINGLE("Right Capture Switch", WM8753_RECMIX1, 7, 1, 0), | 407 | SOC_DAPM_SINGLE("Right Capture Switch", WM8753_RECMIX1, 7, 1, 0), |
408 | }; | 408 | }; |
409 | 409 | ||
410 | /* Left ADC mux */ | 410 | /* Left ADC mux */ |
411 | static const struct snd_kcontrol_new wm8753_adc_left_controls = | 411 | static const struct snd_kcontrol_new wm8753_adc_left_controls = |
412 | SOC_DAPM_ENUM("Route", wm8753_enum[21]); | 412 | SOC_DAPM_ENUM("Route", wm8753_enum[21]); |
413 | 413 | ||
414 | /* Right ADC mux */ | 414 | /* Right ADC mux */ |
415 | static const struct snd_kcontrol_new wm8753_adc_right_controls = | 415 | static const struct snd_kcontrol_new wm8753_adc_right_controls = |
416 | SOC_DAPM_ENUM("Route", wm8753_enum[20]); | 416 | SOC_DAPM_ENUM("Route", wm8753_enum[20]); |
417 | 417 | ||
418 | /* MIC mux */ | 418 | /* MIC mux */ |
419 | static const struct snd_kcontrol_new wm8753_mic_mux_controls = | 419 | static const struct snd_kcontrol_new wm8753_mic_mux_controls = |
420 | SOC_DAPM_ENUM("Route", wm8753_enum[16]); | 420 | SOC_DAPM_ENUM("Route", wm8753_enum[16]); |
421 | 421 | ||
422 | /* ALC mixer */ | 422 | /* ALC mixer */ |
423 | static const struct snd_kcontrol_new wm8753_alc_mixer_controls[] = { | 423 | static const struct snd_kcontrol_new wm8753_alc_mixer_controls[] = { |
424 | SOC_DAPM_SINGLE("Line Capture Switch", WM8753_INCTL2, 3, 1, 0), | 424 | SOC_DAPM_SINGLE("Line Capture Switch", WM8753_INCTL2, 3, 1, 0), |
425 | SOC_DAPM_SINGLE("Mic2 Capture Switch", WM8753_INCTL2, 2, 1, 0), | 425 | SOC_DAPM_SINGLE("Mic2 Capture Switch", WM8753_INCTL2, 2, 1, 0), |
426 | SOC_DAPM_SINGLE("Mic1 Capture Switch", WM8753_INCTL2, 1, 1, 0), | 426 | SOC_DAPM_SINGLE("Mic1 Capture Switch", WM8753_INCTL2, 1, 1, 0), |
427 | SOC_DAPM_SINGLE("Rx Capture Switch", WM8753_INCTL2, 0, 1, 0), | 427 | SOC_DAPM_SINGLE("Rx Capture Switch", WM8753_INCTL2, 0, 1, 0), |
428 | }; | 428 | }; |
429 | 429 | ||
430 | /* Left Line mux */ | 430 | /* Left Line mux */ |
431 | static const struct snd_kcontrol_new wm8753_line_left_controls = | 431 | static const struct snd_kcontrol_new wm8753_line_left_controls = |
432 | SOC_DAPM_ENUM("Route", wm8753_enum[14]); | 432 | SOC_DAPM_ENUM("Route", wm8753_enum[14]); |
433 | 433 | ||
434 | /* Right Line mux */ | 434 | /* Right Line mux */ |
435 | static const struct snd_kcontrol_new wm8753_line_right_controls = | 435 | static const struct snd_kcontrol_new wm8753_line_right_controls = |
436 | SOC_DAPM_ENUM("Route", wm8753_enum[13]); | 436 | SOC_DAPM_ENUM("Route", wm8753_enum[13]); |
437 | 437 | ||
438 | /* Mono Line mux */ | 438 | /* Mono Line mux */ |
439 | static const struct snd_kcontrol_new wm8753_line_mono_controls = | 439 | static const struct snd_kcontrol_new wm8753_line_mono_controls = |
440 | SOC_DAPM_ENUM("Route", wm8753_enum[12]); | 440 | SOC_DAPM_ENUM("Route", wm8753_enum[12]); |
441 | 441 | ||
442 | /* Line mux and mixer */ | 442 | /* Line mux and mixer */ |
443 | static const struct snd_kcontrol_new wm8753_line_mux_mix_controls = | 443 | static const struct snd_kcontrol_new wm8753_line_mux_mix_controls = |
444 | SOC_DAPM_ENUM("Route", wm8753_enum[11]); | 444 | SOC_DAPM_ENUM("Route", wm8753_enum[11]); |
445 | 445 | ||
446 | /* Rx mux and mixer */ | 446 | /* Rx mux and mixer */ |
447 | static const struct snd_kcontrol_new wm8753_rx_mux_mix_controls = | 447 | static const struct snd_kcontrol_new wm8753_rx_mux_mix_controls = |
448 | SOC_DAPM_ENUM("Route", wm8753_enum[15]); | 448 | SOC_DAPM_ENUM("Route", wm8753_enum[15]); |
449 | 449 | ||
450 | /* Mic Selector Mux */ | 450 | /* Mic Selector Mux */ |
451 | static const struct snd_kcontrol_new wm8753_mic_sel_mux_controls = | 451 | static const struct snd_kcontrol_new wm8753_mic_sel_mux_controls = |
452 | SOC_DAPM_ENUM("Route", wm8753_enum[25]); | 452 | SOC_DAPM_ENUM("Route", wm8753_enum[25]); |
453 | 453 | ||
454 | static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = { | 454 | static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = { |
455 | SND_SOC_DAPM_MICBIAS("Mic Bias", WM8753_PWR1, 5, 0), | 455 | SND_SOC_DAPM_MICBIAS("Mic Bias", WM8753_PWR1, 5, 0), |
456 | SND_SOC_DAPM_MIXER("Left Mixer", WM8753_PWR4, 0, 0, | 456 | SND_SOC_DAPM_MIXER("Left Mixer", WM8753_PWR4, 0, 0, |
457 | &wm8753_left_mixer_controls[0], ARRAY_SIZE(wm8753_left_mixer_controls)), | 457 | &wm8753_left_mixer_controls[0], ARRAY_SIZE(wm8753_left_mixer_controls)), |
458 | SND_SOC_DAPM_PGA("Left Out 1", WM8753_PWR3, 8, 0, NULL, 0), | 458 | SND_SOC_DAPM_PGA("Left Out 1", WM8753_PWR3, 8, 0, NULL, 0), |
459 | SND_SOC_DAPM_PGA("Left Out 2", WM8753_PWR3, 6, 0, NULL, 0), | 459 | SND_SOC_DAPM_PGA("Left Out 2", WM8753_PWR3, 6, 0, NULL, 0), |
460 | SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback", WM8753_PWR1, 3, 0), | 460 | SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback", WM8753_PWR1, 3, 0), |
461 | SND_SOC_DAPM_OUTPUT("LOUT1"), | 461 | SND_SOC_DAPM_OUTPUT("LOUT1"), |
462 | SND_SOC_DAPM_OUTPUT("LOUT2"), | 462 | SND_SOC_DAPM_OUTPUT("LOUT2"), |
463 | SND_SOC_DAPM_MIXER("Right Mixer", WM8753_PWR4, 1, 0, | 463 | SND_SOC_DAPM_MIXER("Right Mixer", WM8753_PWR4, 1, 0, |
464 | &wm8753_right_mixer_controls[0], ARRAY_SIZE(wm8753_right_mixer_controls)), | 464 | &wm8753_right_mixer_controls[0], ARRAY_SIZE(wm8753_right_mixer_controls)), |
465 | SND_SOC_DAPM_PGA("Right Out 1", WM8753_PWR3, 7, 0, NULL, 0), | 465 | SND_SOC_DAPM_PGA("Right Out 1", WM8753_PWR3, 7, 0, NULL, 0), |
466 | SND_SOC_DAPM_PGA("Right Out 2", WM8753_PWR3, 5, 0, NULL, 0), | 466 | SND_SOC_DAPM_PGA("Right Out 2", WM8753_PWR3, 5, 0, NULL, 0), |
467 | SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback", WM8753_PWR1, 2, 0), | 467 | SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback", WM8753_PWR1, 2, 0), |
468 | SND_SOC_DAPM_OUTPUT("ROUT1"), | 468 | SND_SOC_DAPM_OUTPUT("ROUT1"), |
469 | SND_SOC_DAPM_OUTPUT("ROUT2"), | 469 | SND_SOC_DAPM_OUTPUT("ROUT2"), |
470 | SND_SOC_DAPM_MIXER("Mono Mixer", WM8753_PWR4, 2, 0, | 470 | SND_SOC_DAPM_MIXER("Mono Mixer", WM8753_PWR4, 2, 0, |
471 | &wm8753_mono_mixer_controls[0], ARRAY_SIZE(wm8753_mono_mixer_controls)), | 471 | &wm8753_mono_mixer_controls[0], ARRAY_SIZE(wm8753_mono_mixer_controls)), |
472 | SND_SOC_DAPM_PGA("Mono Out 1", WM8753_PWR3, 2, 0, NULL, 0), | 472 | SND_SOC_DAPM_PGA("Mono Out 1", WM8753_PWR3, 2, 0, NULL, 0), |
473 | SND_SOC_DAPM_PGA("Mono Out 2", WM8753_PWR3, 1, 0, NULL, 0), | 473 | SND_SOC_DAPM_PGA("Mono Out 2", WM8753_PWR3, 1, 0, NULL, 0), |
474 | SND_SOC_DAPM_DAC("Voice DAC", "Voice Playback", WM8753_PWR1, 4, 0), | 474 | SND_SOC_DAPM_DAC("Voice DAC", "Voice Playback", WM8753_PWR1, 4, 0), |
475 | SND_SOC_DAPM_OUTPUT("MONO1"), | 475 | SND_SOC_DAPM_OUTPUT("MONO1"), |
476 | SND_SOC_DAPM_MUX("Mono 2 Mux", SND_SOC_NOPM, 0, 0, &wm8753_mono2_controls), | 476 | SND_SOC_DAPM_MUX("Mono 2 Mux", SND_SOC_NOPM, 0, 0, &wm8753_mono2_controls), |
477 | SND_SOC_DAPM_OUTPUT("MONO2"), | 477 | SND_SOC_DAPM_OUTPUT("MONO2"), |
478 | SND_SOC_DAPM_MIXER("Out3 Left + Right", -1, 0, 0, NULL, 0), | 478 | SND_SOC_DAPM_MIXER("Out3 Left + Right", -1, 0, 0, NULL, 0), |
479 | SND_SOC_DAPM_MUX("Out3 Mux", SND_SOC_NOPM, 0, 0, &wm8753_out3_controls), | 479 | SND_SOC_DAPM_MUX("Out3 Mux", SND_SOC_NOPM, 0, 0, &wm8753_out3_controls), |
480 | SND_SOC_DAPM_PGA("Out 3", WM8753_PWR3, 4, 0, NULL, 0), | 480 | SND_SOC_DAPM_PGA("Out 3", WM8753_PWR3, 4, 0, NULL, 0), |
481 | SND_SOC_DAPM_OUTPUT("OUT3"), | 481 | SND_SOC_DAPM_OUTPUT("OUT3"), |
482 | SND_SOC_DAPM_MUX("Out4 Mux", SND_SOC_NOPM, 0, 0, &wm8753_out4_controls), | 482 | SND_SOC_DAPM_MUX("Out4 Mux", SND_SOC_NOPM, 0, 0, &wm8753_out4_controls), |
483 | SND_SOC_DAPM_PGA("Out 4", WM8753_PWR3, 3, 0, NULL, 0), | 483 | SND_SOC_DAPM_PGA("Out 4", WM8753_PWR3, 3, 0, NULL, 0), |
484 | SND_SOC_DAPM_OUTPUT("OUT4"), | 484 | SND_SOC_DAPM_OUTPUT("OUT4"), |
485 | SND_SOC_DAPM_MIXER("Playback Mixer", WM8753_PWR4, 3, 0, | 485 | SND_SOC_DAPM_MIXER("Playback Mixer", WM8753_PWR4, 3, 0, |
486 | &wm8753_record_mixer_controls[0], | 486 | &wm8753_record_mixer_controls[0], |
487 | ARRAY_SIZE(wm8753_record_mixer_controls)), | 487 | ARRAY_SIZE(wm8753_record_mixer_controls)), |
488 | SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8753_PWR2, 3, 0), | 488 | SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8753_PWR2, 3, 0), |
489 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8753_PWR2, 2, 0), | 489 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8753_PWR2, 2, 0), |
490 | SND_SOC_DAPM_MUX("Capture Left Mixer", SND_SOC_NOPM, 0, 0, | 490 | SND_SOC_DAPM_MUX("Capture Left Mixer", SND_SOC_NOPM, 0, 0, |
491 | &wm8753_adc_mono_controls), | 491 | &wm8753_adc_mono_controls), |
492 | SND_SOC_DAPM_MUX("Capture Right Mixer", SND_SOC_NOPM, 0, 0, | 492 | SND_SOC_DAPM_MUX("Capture Right Mixer", SND_SOC_NOPM, 0, 0, |
493 | &wm8753_adc_mono_controls), | 493 | &wm8753_adc_mono_controls), |
494 | SND_SOC_DAPM_MUX("Capture Left Mux", SND_SOC_NOPM, 0, 0, | 494 | SND_SOC_DAPM_MUX("Capture Left Mux", SND_SOC_NOPM, 0, 0, |
495 | &wm8753_adc_left_controls), | 495 | &wm8753_adc_left_controls), |
496 | SND_SOC_DAPM_MUX("Capture Right Mux", SND_SOC_NOPM, 0, 0, | 496 | SND_SOC_DAPM_MUX("Capture Right Mux", SND_SOC_NOPM, 0, 0, |
497 | &wm8753_adc_right_controls), | 497 | &wm8753_adc_right_controls), |
498 | SND_SOC_DAPM_MUX("Mic Sidetone Mux", SND_SOC_NOPM, 0, 0, | 498 | SND_SOC_DAPM_MUX("Mic Sidetone Mux", SND_SOC_NOPM, 0, 0, |
499 | &wm8753_mic_mux_controls), | 499 | &wm8753_mic_mux_controls), |
500 | SND_SOC_DAPM_PGA("Left Capture Volume", WM8753_PWR2, 5, 0, NULL, 0), | 500 | SND_SOC_DAPM_PGA("Left Capture Volume", WM8753_PWR2, 5, 0, NULL, 0), |
501 | SND_SOC_DAPM_PGA("Right Capture Volume", WM8753_PWR2, 4, 0, NULL, 0), | 501 | SND_SOC_DAPM_PGA("Right Capture Volume", WM8753_PWR2, 4, 0, NULL, 0), |
502 | SND_SOC_DAPM_MIXER("ALC Mixer", WM8753_PWR2, 6, 0, | 502 | SND_SOC_DAPM_MIXER("ALC Mixer", WM8753_PWR2, 6, 0, |
503 | &wm8753_alc_mixer_controls[0], ARRAY_SIZE(wm8753_alc_mixer_controls)), | 503 | &wm8753_alc_mixer_controls[0], ARRAY_SIZE(wm8753_alc_mixer_controls)), |
504 | SND_SOC_DAPM_MUX("Line Left Mux", SND_SOC_NOPM, 0, 0, | 504 | SND_SOC_DAPM_MUX("Line Left Mux", SND_SOC_NOPM, 0, 0, |
505 | &wm8753_line_left_controls), | 505 | &wm8753_line_left_controls), |
506 | SND_SOC_DAPM_MUX("Line Right Mux", SND_SOC_NOPM, 0, 0, | 506 | SND_SOC_DAPM_MUX("Line Right Mux", SND_SOC_NOPM, 0, 0, |
507 | &wm8753_line_right_controls), | 507 | &wm8753_line_right_controls), |
508 | SND_SOC_DAPM_MUX("Line Mono Mux", SND_SOC_NOPM, 0, 0, | 508 | SND_SOC_DAPM_MUX("Line Mono Mux", SND_SOC_NOPM, 0, 0, |
509 | &wm8753_line_mono_controls), | 509 | &wm8753_line_mono_controls), |
510 | SND_SOC_DAPM_MUX("Line Mixer", WM8753_PWR2, 0, 0, | 510 | SND_SOC_DAPM_MUX("Line Mixer", WM8753_PWR2, 0, 0, |
511 | &wm8753_line_mux_mix_controls), | 511 | &wm8753_line_mux_mix_controls), |
512 | SND_SOC_DAPM_MUX("Rx Mixer", WM8753_PWR2, 1, 0, | 512 | SND_SOC_DAPM_MUX("Rx Mixer", WM8753_PWR2, 1, 0, |
513 | &wm8753_rx_mux_mix_controls), | 513 | &wm8753_rx_mux_mix_controls), |
514 | SND_SOC_DAPM_PGA("Mic 1 Volume", WM8753_PWR2, 8, 0, NULL, 0), | 514 | SND_SOC_DAPM_PGA("Mic 1 Volume", WM8753_PWR2, 8, 0, NULL, 0), |
515 | SND_SOC_DAPM_PGA("Mic 2 Volume", WM8753_PWR2, 7, 0, NULL, 0), | 515 | SND_SOC_DAPM_PGA("Mic 2 Volume", WM8753_PWR2, 7, 0, NULL, 0), |
516 | SND_SOC_DAPM_MUX("Mic Selection Mux", SND_SOC_NOPM, 0, 0, | 516 | SND_SOC_DAPM_MUX("Mic Selection Mux", SND_SOC_NOPM, 0, 0, |
517 | &wm8753_mic_sel_mux_controls), | 517 | &wm8753_mic_sel_mux_controls), |
518 | SND_SOC_DAPM_INPUT("LINE1"), | 518 | SND_SOC_DAPM_INPUT("LINE1"), |
519 | SND_SOC_DAPM_INPUT("LINE2"), | 519 | SND_SOC_DAPM_INPUT("LINE2"), |
520 | SND_SOC_DAPM_INPUT("RXP"), | 520 | SND_SOC_DAPM_INPUT("RXP"), |
521 | SND_SOC_DAPM_INPUT("RXN"), | 521 | SND_SOC_DAPM_INPUT("RXN"), |
522 | SND_SOC_DAPM_INPUT("ACIN"), | 522 | SND_SOC_DAPM_INPUT("ACIN"), |
523 | SND_SOC_DAPM_OUTPUT("ACOP"), | 523 | SND_SOC_DAPM_OUTPUT("ACOP"), |
524 | SND_SOC_DAPM_INPUT("MIC1N"), | 524 | SND_SOC_DAPM_INPUT("MIC1N"), |
525 | SND_SOC_DAPM_INPUT("MIC1"), | 525 | SND_SOC_DAPM_INPUT("MIC1"), |
526 | SND_SOC_DAPM_INPUT("MIC2N"), | 526 | SND_SOC_DAPM_INPUT("MIC2N"), |
527 | SND_SOC_DAPM_INPUT("MIC2"), | 527 | SND_SOC_DAPM_INPUT("MIC2"), |
528 | SND_SOC_DAPM_VMID("VREF"), | 528 | SND_SOC_DAPM_VMID("VREF"), |
529 | }; | 529 | }; |
530 | 530 | ||
531 | static const struct snd_soc_dapm_route audio_map[] = { | 531 | static const struct snd_soc_dapm_route audio_map[] = { |
532 | /* left mixer */ | 532 | /* left mixer */ |
533 | {"Left Mixer", "Left Playback Switch", "Left DAC"}, | 533 | {"Left Mixer", "Left Playback Switch", "Left DAC"}, |
534 | {"Left Mixer", "Voice Playback Switch", "Voice DAC"}, | 534 | {"Left Mixer", "Voice Playback Switch", "Voice DAC"}, |
535 | {"Left Mixer", "Sidetone Playback Switch", "Mic Sidetone Mux"}, | 535 | {"Left Mixer", "Sidetone Playback Switch", "Mic Sidetone Mux"}, |
536 | {"Left Mixer", "Bypass Playback Switch", "Line Left Mux"}, | 536 | {"Left Mixer", "Bypass Playback Switch", "Line Left Mux"}, |
537 | 537 | ||
538 | /* right mixer */ | 538 | /* right mixer */ |
539 | {"Right Mixer", "Right Playback Switch", "Right DAC"}, | 539 | {"Right Mixer", "Right Playback Switch", "Right DAC"}, |
540 | {"Right Mixer", "Voice Playback Switch", "Voice DAC"}, | 540 | {"Right Mixer", "Voice Playback Switch", "Voice DAC"}, |
541 | {"Right Mixer", "Sidetone Playback Switch", "Mic Sidetone Mux"}, | 541 | {"Right Mixer", "Sidetone Playback Switch", "Mic Sidetone Mux"}, |
542 | {"Right Mixer", "Bypass Playback Switch", "Line Right Mux"}, | 542 | {"Right Mixer", "Bypass Playback Switch", "Line Right Mux"}, |
543 | 543 | ||
544 | /* mono mixer */ | 544 | /* mono mixer */ |
545 | {"Mono Mixer", "Voice Playback Switch", "Voice DAC"}, | 545 | {"Mono Mixer", "Voice Playback Switch", "Voice DAC"}, |
546 | {"Mono Mixer", "Left Playback Switch", "Left DAC"}, | 546 | {"Mono Mixer", "Left Playback Switch", "Left DAC"}, |
547 | {"Mono Mixer", "Right Playback Switch", "Right DAC"}, | 547 | {"Mono Mixer", "Right Playback Switch", "Right DAC"}, |
548 | {"Mono Mixer", "Sidetone Playback Switch", "Mic Sidetone Mux"}, | 548 | {"Mono Mixer", "Sidetone Playback Switch", "Mic Sidetone Mux"}, |
549 | {"Mono Mixer", "Bypass Playback Switch", "Line Mono Mux"}, | 549 | {"Mono Mixer", "Bypass Playback Switch", "Line Mono Mux"}, |
550 | 550 | ||
551 | /* left out */ | 551 | /* left out */ |
552 | {"Left Out 1", NULL, "Left Mixer"}, | 552 | {"Left Out 1", NULL, "Left Mixer"}, |
553 | {"Left Out 2", NULL, "Left Mixer"}, | 553 | {"Left Out 2", NULL, "Left Mixer"}, |
554 | {"LOUT1", NULL, "Left Out 1"}, | 554 | {"LOUT1", NULL, "Left Out 1"}, |
555 | {"LOUT2", NULL, "Left Out 2"}, | 555 | {"LOUT2", NULL, "Left Out 2"}, |
556 | 556 | ||
557 | /* right out */ | 557 | /* right out */ |
558 | {"Right Out 1", NULL, "Right Mixer"}, | 558 | {"Right Out 1", NULL, "Right Mixer"}, |
559 | {"Right Out 2", NULL, "Right Mixer"}, | 559 | {"Right Out 2", NULL, "Right Mixer"}, |
560 | {"ROUT1", NULL, "Right Out 1"}, | 560 | {"ROUT1", NULL, "Right Out 1"}, |
561 | {"ROUT2", NULL, "Right Out 2"}, | 561 | {"ROUT2", NULL, "Right Out 2"}, |
562 | 562 | ||
563 | /* mono 1 out */ | 563 | /* mono 1 out */ |
564 | {"Mono Out 1", NULL, "Mono Mixer"}, | 564 | {"Mono Out 1", NULL, "Mono Mixer"}, |
565 | {"MONO1", NULL, "Mono Out 1"}, | 565 | {"MONO1", NULL, "Mono Out 1"}, |
566 | 566 | ||
567 | /* mono 2 out */ | 567 | /* mono 2 out */ |
568 | {"Mono 2 Mux", "Left + Right", "Out3 Left + Right"}, | 568 | {"Mono 2 Mux", "Left + Right", "Out3 Left + Right"}, |
569 | {"Mono 2 Mux", "Inverted Mono 1", "MONO1"}, | 569 | {"Mono 2 Mux", "Inverted Mono 1", "MONO1"}, |
570 | {"Mono 2 Mux", "Left", "Left Mixer"}, | 570 | {"Mono 2 Mux", "Left", "Left Mixer"}, |
571 | {"Mono 2 Mux", "Right", "Right Mixer"}, | 571 | {"Mono 2 Mux", "Right", "Right Mixer"}, |
572 | {"Mono Out 2", NULL, "Mono 2 Mux"}, | 572 | {"Mono Out 2", NULL, "Mono 2 Mux"}, |
573 | {"MONO2", NULL, "Mono Out 2"}, | 573 | {"MONO2", NULL, "Mono Out 2"}, |
574 | 574 | ||
575 | /* out 3 */ | 575 | /* out 3 */ |
576 | {"Out3 Left + Right", NULL, "Left Mixer"}, | 576 | {"Out3 Left + Right", NULL, "Left Mixer"}, |
577 | {"Out3 Left + Right", NULL, "Right Mixer"}, | 577 | {"Out3 Left + Right", NULL, "Right Mixer"}, |
578 | {"Out3 Mux", "VREF", "VREF"}, | 578 | {"Out3 Mux", "VREF", "VREF"}, |
579 | {"Out3 Mux", "Left + Right", "Out3 Left + Right"}, | 579 | {"Out3 Mux", "Left + Right", "Out3 Left + Right"}, |
580 | {"Out3 Mux", "ROUT2", "ROUT2"}, | 580 | {"Out3 Mux", "ROUT2", "ROUT2"}, |
581 | {"Out 3", NULL, "Out3 Mux"}, | 581 | {"Out 3", NULL, "Out3 Mux"}, |
582 | {"OUT3", NULL, "Out 3"}, | 582 | {"OUT3", NULL, "Out 3"}, |
583 | 583 | ||
584 | /* out 4 */ | 584 | /* out 4 */ |
585 | {"Out4 Mux", "VREF", "VREF"}, | 585 | {"Out4 Mux", "VREF", "VREF"}, |
586 | {"Out4 Mux", "Capture ST", "Capture ST Mixer"}, | 586 | {"Out4 Mux", "Capture ST", "Capture ST Mixer"}, |
587 | {"Out4 Mux", "LOUT2", "LOUT2"}, | 587 | {"Out4 Mux", "LOUT2", "LOUT2"}, |
588 | {"Out 4", NULL, "Out4 Mux"}, | 588 | {"Out 4", NULL, "Out4 Mux"}, |
589 | {"OUT4", NULL, "Out 4"}, | 589 | {"OUT4", NULL, "Out 4"}, |
590 | 590 | ||
591 | /* record mixer */ | 591 | /* record mixer */ |
592 | {"Playback Mixer", "Left Capture Switch", "Left Mixer"}, | 592 | {"Playback Mixer", "Left Capture Switch", "Left Mixer"}, |
593 | {"Playback Mixer", "Voice Capture Switch", "Mono Mixer"}, | 593 | {"Playback Mixer", "Voice Capture Switch", "Mono Mixer"}, |
594 | {"Playback Mixer", "Right Capture Switch", "Right Mixer"}, | 594 | {"Playback Mixer", "Right Capture Switch", "Right Mixer"}, |
595 | 595 | ||
596 | /* Mic/SideTone Mux */ | 596 | /* Mic/SideTone Mux */ |
597 | {"Mic Sidetone Mux", "Left PGA", "Left Capture Volume"}, | 597 | {"Mic Sidetone Mux", "Left PGA", "Left Capture Volume"}, |
598 | {"Mic Sidetone Mux", "Right PGA", "Right Capture Volume"}, | 598 | {"Mic Sidetone Mux", "Right PGA", "Right Capture Volume"}, |
599 | {"Mic Sidetone Mux", "Mic 1", "Mic 1 Volume"}, | 599 | {"Mic Sidetone Mux", "Mic 1", "Mic 1 Volume"}, |
600 | {"Mic Sidetone Mux", "Mic 2", "Mic 2 Volume"}, | 600 | {"Mic Sidetone Mux", "Mic 2", "Mic 2 Volume"}, |
601 | 601 | ||
602 | /* Capture Left Mux */ | 602 | /* Capture Left Mux */ |
603 | {"Capture Left Mux", "PGA", "Left Capture Volume"}, | 603 | {"Capture Left Mux", "PGA", "Left Capture Volume"}, |
604 | {"Capture Left Mux", "Line or RXP-RXN", "Line Left Mux"}, | 604 | {"Capture Left Mux", "Line or RXP-RXN", "Line Left Mux"}, |
605 | {"Capture Left Mux", "Line", "LINE1"}, | 605 | {"Capture Left Mux", "Line", "LINE1"}, |
606 | 606 | ||
607 | /* Capture Right Mux */ | 607 | /* Capture Right Mux */ |
608 | {"Capture Right Mux", "PGA", "Right Capture Volume"}, | 608 | {"Capture Right Mux", "PGA", "Right Capture Volume"}, |
609 | {"Capture Right Mux", "Line or RXP-RXN", "Line Right Mux"}, | 609 | {"Capture Right Mux", "Line or RXP-RXN", "Line Right Mux"}, |
610 | {"Capture Right Mux", "Sidetone", "Capture ST Mixer"}, | 610 | {"Capture Right Mux", "Sidetone", "Capture ST Mixer"}, |
611 | 611 | ||
612 | /* Mono Capture mixer-mux */ | 612 | /* Mono Capture mixer-mux */ |
613 | {"Capture Right Mixer", "Stereo", "Capture Right Mux"}, | 613 | {"Capture Right Mixer", "Stereo", "Capture Right Mux"}, |
614 | {"Capture Left Mixer", "Analogue Mix Left", "Capture Left Mux"}, | 614 | {"Capture Left Mixer", "Analogue Mix Left", "Capture Left Mux"}, |
615 | {"Capture Left Mixer", "Analogue Mix Left", "Capture Right Mux"}, | 615 | {"Capture Left Mixer", "Analogue Mix Left", "Capture Right Mux"}, |
616 | {"Capture Right Mixer", "Analogue Mix Right", "Capture Left Mux"}, | 616 | {"Capture Right Mixer", "Analogue Mix Right", "Capture Left Mux"}, |
617 | {"Capture Right Mixer", "Analogue Mix Right", "Capture Right Mux"}, | 617 | {"Capture Right Mixer", "Analogue Mix Right", "Capture Right Mux"}, |
618 | {"Capture Left Mixer", "Digital Mono Mix", "Capture Left Mux"}, | 618 | {"Capture Left Mixer", "Digital Mono Mix", "Capture Left Mux"}, |
619 | {"Capture Left Mixer", "Digital Mono Mix", "Capture Right Mux"}, | 619 | {"Capture Left Mixer", "Digital Mono Mix", "Capture Right Mux"}, |
620 | {"Capture Right Mixer", "Digital Mono Mix", "Capture Left Mux"}, | 620 | {"Capture Right Mixer", "Digital Mono Mix", "Capture Left Mux"}, |
621 | {"Capture Right Mixer", "Digital Mono Mix", "Capture Right Mux"}, | 621 | {"Capture Right Mixer", "Digital Mono Mix", "Capture Right Mux"}, |
622 | 622 | ||
623 | /* ADC */ | 623 | /* ADC */ |
624 | {"Left ADC", NULL, "Capture Left Mixer"}, | 624 | {"Left ADC", NULL, "Capture Left Mixer"}, |
625 | {"Right ADC", NULL, "Capture Right Mixer"}, | 625 | {"Right ADC", NULL, "Capture Right Mixer"}, |
626 | 626 | ||
627 | /* Left Capture Volume */ | 627 | /* Left Capture Volume */ |
628 | {"Left Capture Volume", NULL, "ACIN"}, | 628 | {"Left Capture Volume", NULL, "ACIN"}, |
629 | 629 | ||
630 | /* Right Capture Volume */ | 630 | /* Right Capture Volume */ |
631 | {"Right Capture Volume", NULL, "Mic 2 Volume"}, | 631 | {"Right Capture Volume", NULL, "Mic 2 Volume"}, |
632 | 632 | ||
633 | /* ALC Mixer */ | 633 | /* ALC Mixer */ |
634 | {"ALC Mixer", "Line Capture Switch", "Line Mixer"}, | 634 | {"ALC Mixer", "Line Capture Switch", "Line Mixer"}, |
635 | {"ALC Mixer", "Mic2 Capture Switch", "Mic 2 Volume"}, | 635 | {"ALC Mixer", "Mic2 Capture Switch", "Mic 2 Volume"}, |
636 | {"ALC Mixer", "Mic1 Capture Switch", "Mic 1 Volume"}, | 636 | {"ALC Mixer", "Mic1 Capture Switch", "Mic 1 Volume"}, |
637 | {"ALC Mixer", "Rx Capture Switch", "Rx Mixer"}, | 637 | {"ALC Mixer", "Rx Capture Switch", "Rx Mixer"}, |
638 | 638 | ||
639 | /* Line Left Mux */ | 639 | /* Line Left Mux */ |
640 | {"Line Left Mux", "Line 1", "LINE1"}, | 640 | {"Line Left Mux", "Line 1", "LINE1"}, |
641 | {"Line Left Mux", "Rx Mix", "Rx Mixer"}, | 641 | {"Line Left Mux", "Rx Mix", "Rx Mixer"}, |
642 | 642 | ||
643 | /* Line Right Mux */ | 643 | /* Line Right Mux */ |
644 | {"Line Right Mux", "Line 2", "LINE2"}, | 644 | {"Line Right Mux", "Line 2", "LINE2"}, |
645 | {"Line Right Mux", "Rx Mix", "Rx Mixer"}, | 645 | {"Line Right Mux", "Rx Mix", "Rx Mixer"}, |
646 | 646 | ||
647 | /* Line Mono Mux */ | 647 | /* Line Mono Mux */ |
648 | {"Line Mono Mux", "Line Mix", "Line Mixer"}, | 648 | {"Line Mono Mux", "Line Mix", "Line Mixer"}, |
649 | {"Line Mono Mux", "Rx Mix", "Rx Mixer"}, | 649 | {"Line Mono Mux", "Rx Mix", "Rx Mixer"}, |
650 | 650 | ||
651 | /* Line Mixer/Mux */ | 651 | /* Line Mixer/Mux */ |
652 | {"Line Mixer", "Line 1 + 2", "LINE1"}, | 652 | {"Line Mixer", "Line 1 + 2", "LINE1"}, |
653 | {"Line Mixer", "Line 1 - 2", "LINE1"}, | 653 | {"Line Mixer", "Line 1 - 2", "LINE1"}, |
654 | {"Line Mixer", "Line 1 + 2", "LINE2"}, | 654 | {"Line Mixer", "Line 1 + 2", "LINE2"}, |
655 | {"Line Mixer", "Line 1 - 2", "LINE2"}, | 655 | {"Line Mixer", "Line 1 - 2", "LINE2"}, |
656 | {"Line Mixer", "Line 1", "LINE1"}, | 656 | {"Line Mixer", "Line 1", "LINE1"}, |
657 | {"Line Mixer", "Line 2", "LINE2"}, | 657 | {"Line Mixer", "Line 2", "LINE2"}, |
658 | 658 | ||
659 | /* Rx Mixer/Mux */ | 659 | /* Rx Mixer/Mux */ |
660 | {"Rx Mixer", "RXP - RXN", "RXP"}, | 660 | {"Rx Mixer", "RXP - RXN", "RXP"}, |
661 | {"Rx Mixer", "RXP + RXN", "RXP"}, | 661 | {"Rx Mixer", "RXP + RXN", "RXP"}, |
662 | {"Rx Mixer", "RXP - RXN", "RXN"}, | 662 | {"Rx Mixer", "RXP - RXN", "RXN"}, |
663 | {"Rx Mixer", "RXP + RXN", "RXN"}, | 663 | {"Rx Mixer", "RXP + RXN", "RXN"}, |
664 | {"Rx Mixer", "RXP", "RXP"}, | 664 | {"Rx Mixer", "RXP", "RXP"}, |
665 | {"Rx Mixer", "RXN", "RXN"}, | 665 | {"Rx Mixer", "RXN", "RXN"}, |
666 | 666 | ||
667 | /* Mic 1 Volume */ | 667 | /* Mic 1 Volume */ |
668 | {"Mic 1 Volume", NULL, "MIC1N"}, | 668 | {"Mic 1 Volume", NULL, "MIC1N"}, |
669 | {"Mic 1 Volume", NULL, "Mic Selection Mux"}, | 669 | {"Mic 1 Volume", NULL, "Mic Selection Mux"}, |
670 | 670 | ||
671 | /* Mic 2 Volume */ | 671 | /* Mic 2 Volume */ |
672 | {"Mic 2 Volume", NULL, "MIC2N"}, | 672 | {"Mic 2 Volume", NULL, "MIC2N"}, |
673 | {"Mic 2 Volume", NULL, "MIC2"}, | 673 | {"Mic 2 Volume", NULL, "MIC2"}, |
674 | 674 | ||
675 | /* Mic Selector Mux */ | 675 | /* Mic Selector Mux */ |
676 | {"Mic Selection Mux", "Mic 1", "MIC1"}, | 676 | {"Mic Selection Mux", "Mic 1", "MIC1"}, |
677 | {"Mic Selection Mux", "Mic 2", "MIC2N"}, | 677 | {"Mic Selection Mux", "Mic 2", "MIC2N"}, |
678 | {"Mic Selection Mux", "Mic 3", "MIC2"}, | 678 | {"Mic Selection Mux", "Mic 3", "MIC2"}, |
679 | 679 | ||
680 | /* ACOP */ | 680 | /* ACOP */ |
681 | {"ACOP", NULL, "ALC Mixer"}, | 681 | {"ACOP", NULL, "ALC Mixer"}, |
682 | }; | 682 | }; |
683 | 683 | ||
684 | static int wm8753_add_widgets(struct snd_soc_codec *codec) | 684 | static int wm8753_add_widgets(struct snd_soc_codec *codec) |
685 | { | 685 | { |
686 | snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets, | 686 | snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets, |
687 | ARRAY_SIZE(wm8753_dapm_widgets)); | 687 | ARRAY_SIZE(wm8753_dapm_widgets)); |
688 | 688 | ||
689 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | 689 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
690 | 690 | ||
691 | snd_soc_dapm_new_widgets(codec); | 691 | snd_soc_dapm_new_widgets(codec); |
692 | return 0; | 692 | return 0; |
693 | } | 693 | } |
694 | 694 | ||
695 | /* PLL divisors */ | 695 | /* PLL divisors */ |
696 | struct _pll_div { | 696 | struct _pll_div { |
697 | u32 div2:1; | 697 | u32 div2:1; |
698 | u32 n:4; | 698 | u32 n:4; |
699 | u32 k:24; | 699 | u32 k:24; |
700 | }; | 700 | }; |
701 | 701 | ||
702 | /* The size in bits of the pll divide multiplied by 10 | 702 | /* The size in bits of the pll divide multiplied by 10 |
703 | * to allow rounding later */ | 703 | * to allow rounding later */ |
704 | #define FIXED_PLL_SIZE ((1 << 22) * 10) | 704 | #define FIXED_PLL_SIZE ((1 << 22) * 10) |
705 | 705 | ||
706 | static void pll_factors(struct _pll_div *pll_div, unsigned int target, | 706 | static void pll_factors(struct _pll_div *pll_div, unsigned int target, |
707 | unsigned int source) | 707 | unsigned int source) |
708 | { | 708 | { |
709 | u64 Kpart; | 709 | u64 Kpart; |
710 | unsigned int K, Ndiv, Nmod; | 710 | unsigned int K, Ndiv, Nmod; |
711 | 711 | ||
712 | Ndiv = target / source; | 712 | Ndiv = target / source; |
713 | if (Ndiv < 6) { | 713 | if (Ndiv < 6) { |
714 | source >>= 1; | 714 | source >>= 1; |
715 | pll_div->div2 = 1; | 715 | pll_div->div2 = 1; |
716 | Ndiv = target / source; | 716 | Ndiv = target / source; |
717 | } else | 717 | } else |
718 | pll_div->div2 = 0; | 718 | pll_div->div2 = 0; |
719 | 719 | ||
720 | if ((Ndiv < 6) || (Ndiv > 12)) | 720 | if ((Ndiv < 6) || (Ndiv > 12)) |
721 | printk(KERN_WARNING | 721 | printk(KERN_WARNING |
722 | "wm8753: unsupported N = %d\n", Ndiv); | 722 | "wm8753: unsupported N = %d\n", Ndiv); |
723 | 723 | ||
724 | pll_div->n = Ndiv; | 724 | pll_div->n = Ndiv; |
725 | Nmod = target % source; | 725 | Nmod = target % source; |
726 | Kpart = FIXED_PLL_SIZE * (long long)Nmod; | 726 | Kpart = FIXED_PLL_SIZE * (long long)Nmod; |
727 | 727 | ||
728 | do_div(Kpart, source); | 728 | do_div(Kpart, source); |
729 | 729 | ||
730 | K = Kpart & 0xFFFFFFFF; | 730 | K = Kpart & 0xFFFFFFFF; |
731 | 731 | ||
732 | /* Check if we need to round */ | 732 | /* Check if we need to round */ |
733 | if ((K % 10) >= 5) | 733 | if ((K % 10) >= 5) |
734 | K += 5; | 734 | K += 5; |
735 | 735 | ||
736 | /* Move down to proper range now rounding is done */ | 736 | /* Move down to proper range now rounding is done */ |
737 | K /= 10; | 737 | K /= 10; |
738 | 738 | ||
739 | pll_div->k = K; | 739 | pll_div->k = K; |
740 | } | 740 | } |
741 | 741 | ||
742 | static int wm8753_set_dai_pll(struct snd_soc_dai *codec_dai, | 742 | static int wm8753_set_dai_pll(struct snd_soc_dai *codec_dai, |
743 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 743 | int pll_id, unsigned int freq_in, unsigned int freq_out) |
744 | { | 744 | { |
745 | u16 reg, enable; | 745 | u16 reg, enable; |
746 | int offset; | 746 | int offset; |
747 | struct snd_soc_codec *codec = codec_dai->codec; | 747 | struct snd_soc_codec *codec = codec_dai->codec; |
748 | 748 | ||
749 | if (pll_id < WM8753_PLL1 || pll_id > WM8753_PLL2) | 749 | if (pll_id < WM8753_PLL1 || pll_id > WM8753_PLL2) |
750 | return -ENODEV; | 750 | return -ENODEV; |
751 | 751 | ||
752 | if (pll_id == WM8753_PLL1) { | 752 | if (pll_id == WM8753_PLL1) { |
753 | offset = 0; | 753 | offset = 0; |
754 | enable = 0x10; | 754 | enable = 0x10; |
755 | reg = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xffef; | 755 | reg = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xffef; |
756 | } else { | 756 | } else { |
757 | offset = 4; | 757 | offset = 4; |
758 | enable = 0x8; | 758 | enable = 0x8; |
759 | reg = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xfff7; | 759 | reg = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xfff7; |
760 | } | 760 | } |
761 | 761 | ||
762 | if (!freq_in || !freq_out) { | 762 | if (!freq_in || !freq_out) { |
763 | /* disable PLL */ | 763 | /* disable PLL */ |
764 | wm8753_write(codec, WM8753_PLL1CTL1 + offset, 0x0026); | 764 | wm8753_write(codec, WM8753_PLL1CTL1 + offset, 0x0026); |
765 | wm8753_write(codec, WM8753_CLOCK, reg); | 765 | wm8753_write(codec, WM8753_CLOCK, reg); |
766 | return 0; | 766 | return 0; |
767 | } else { | 767 | } else { |
768 | u16 value = 0; | 768 | u16 value = 0; |
769 | struct _pll_div pll_div; | 769 | struct _pll_div pll_div; |
770 | 770 | ||
771 | pll_factors(&pll_div, freq_out * 8, freq_in); | 771 | pll_factors(&pll_div, freq_out * 8, freq_in); |
772 | 772 | ||
773 | /* set up N and K PLL divisor ratios */ | 773 | /* set up N and K PLL divisor ratios */ |
774 | /* bits 8:5 = PLL_N, bits 3:0 = PLL_K[21:18] */ | 774 | /* bits 8:5 = PLL_N, bits 3:0 = PLL_K[21:18] */ |
775 | value = (pll_div.n << 5) + ((pll_div.k & 0x3c0000) >> 18); | 775 | value = (pll_div.n << 5) + ((pll_div.k & 0x3c0000) >> 18); |
776 | wm8753_write(codec, WM8753_PLL1CTL2 + offset, value); | 776 | wm8753_write(codec, WM8753_PLL1CTL2 + offset, value); |
777 | 777 | ||
778 | /* bits 8:0 = PLL_K[17:9] */ | 778 | /* bits 8:0 = PLL_K[17:9] */ |
779 | value = (pll_div.k & 0x03fe00) >> 9; | 779 | value = (pll_div.k & 0x03fe00) >> 9; |
780 | wm8753_write(codec, WM8753_PLL1CTL3 + offset, value); | 780 | wm8753_write(codec, WM8753_PLL1CTL3 + offset, value); |
781 | 781 | ||
782 | /* bits 8:0 = PLL_K[8:0] */ | 782 | /* bits 8:0 = PLL_K[8:0] */ |
783 | value = pll_div.k & 0x0001ff; | 783 | value = pll_div.k & 0x0001ff; |
784 | wm8753_write(codec, WM8753_PLL1CTL4 + offset, value); | 784 | wm8753_write(codec, WM8753_PLL1CTL4 + offset, value); |
785 | 785 | ||
786 | /* set PLL as input and enable */ | 786 | /* set PLL as input and enable */ |
787 | wm8753_write(codec, WM8753_PLL1CTL1 + offset, 0x0027 | | 787 | wm8753_write(codec, WM8753_PLL1CTL1 + offset, 0x0027 | |
788 | (pll_div.div2 << 3)); | 788 | (pll_div.div2 << 3)); |
789 | wm8753_write(codec, WM8753_CLOCK, reg | enable); | 789 | wm8753_write(codec, WM8753_CLOCK, reg | enable); |
790 | } | 790 | } |
791 | return 0; | 791 | return 0; |
792 | } | 792 | } |
793 | 793 | ||
794 | struct _coeff_div { | 794 | struct _coeff_div { |
795 | u32 mclk; | 795 | u32 mclk; |
796 | u32 rate; | 796 | u32 rate; |
797 | u8 sr:5; | 797 | u8 sr:5; |
798 | u8 usb:1; | 798 | u8 usb:1; |
799 | }; | 799 | }; |
800 | 800 | ||
801 | /* codec hifi mclk (after PLL) clock divider coefficients */ | 801 | /* codec hifi mclk (after PLL) clock divider coefficients */ |
802 | static const struct _coeff_div coeff_div[] = { | 802 | static const struct _coeff_div coeff_div[] = { |
803 | /* 8k */ | 803 | /* 8k */ |
804 | {12288000, 8000, 0x6, 0x0}, | 804 | {12288000, 8000, 0x6, 0x0}, |
805 | {11289600, 8000, 0x16, 0x0}, | 805 | {11289600, 8000, 0x16, 0x0}, |
806 | {18432000, 8000, 0x7, 0x0}, | 806 | {18432000, 8000, 0x7, 0x0}, |
807 | {16934400, 8000, 0x17, 0x0}, | 807 | {16934400, 8000, 0x17, 0x0}, |
808 | {12000000, 8000, 0x6, 0x1}, | 808 | {12000000, 8000, 0x6, 0x1}, |
809 | 809 | ||
810 | /* 11.025k */ | 810 | /* 11.025k */ |
811 | {11289600, 11025, 0x18, 0x0}, | 811 | {11289600, 11025, 0x18, 0x0}, |
812 | {16934400, 11025, 0x19, 0x0}, | 812 | {16934400, 11025, 0x19, 0x0}, |
813 | {12000000, 11025, 0x19, 0x1}, | 813 | {12000000, 11025, 0x19, 0x1}, |
814 | 814 | ||
815 | /* 16k */ | 815 | /* 16k */ |
816 | {12288000, 16000, 0xa, 0x0}, | 816 | {12288000, 16000, 0xa, 0x0}, |
817 | {18432000, 16000, 0xb, 0x0}, | 817 | {18432000, 16000, 0xb, 0x0}, |
818 | {12000000, 16000, 0xa, 0x1}, | 818 | {12000000, 16000, 0xa, 0x1}, |
819 | 819 | ||
820 | /* 22.05k */ | 820 | /* 22.05k */ |
821 | {11289600, 22050, 0x1a, 0x0}, | 821 | {11289600, 22050, 0x1a, 0x0}, |
822 | {16934400, 22050, 0x1b, 0x0}, | 822 | {16934400, 22050, 0x1b, 0x0}, |
823 | {12000000, 22050, 0x1b, 0x1}, | 823 | {12000000, 22050, 0x1b, 0x1}, |
824 | 824 | ||
825 | /* 32k */ | 825 | /* 32k */ |
826 | {12288000, 32000, 0xc, 0x0}, | 826 | {12288000, 32000, 0xc, 0x0}, |
827 | {18432000, 32000, 0xd, 0x0}, | 827 | {18432000, 32000, 0xd, 0x0}, |
828 | {12000000, 32000, 0xa, 0x1}, | 828 | {12000000, 32000, 0xa, 0x1}, |
829 | 829 | ||
830 | /* 44.1k */ | 830 | /* 44.1k */ |
831 | {11289600, 44100, 0x10, 0x0}, | 831 | {11289600, 44100, 0x10, 0x0}, |
832 | {16934400, 44100, 0x11, 0x0}, | 832 | {16934400, 44100, 0x11, 0x0}, |
833 | {12000000, 44100, 0x11, 0x1}, | 833 | {12000000, 44100, 0x11, 0x1}, |
834 | 834 | ||
835 | /* 48k */ | 835 | /* 48k */ |
836 | {12288000, 48000, 0x0, 0x0}, | 836 | {12288000, 48000, 0x0, 0x0}, |
837 | {18432000, 48000, 0x1, 0x0}, | 837 | {18432000, 48000, 0x1, 0x0}, |
838 | {12000000, 48000, 0x0, 0x1}, | 838 | {12000000, 48000, 0x0, 0x1}, |
839 | 839 | ||
840 | /* 88.2k */ | 840 | /* 88.2k */ |
841 | {11289600, 88200, 0x1e, 0x0}, | 841 | {11289600, 88200, 0x1e, 0x0}, |
842 | {16934400, 88200, 0x1f, 0x0}, | 842 | {16934400, 88200, 0x1f, 0x0}, |
843 | {12000000, 88200, 0x1f, 0x1}, | 843 | {12000000, 88200, 0x1f, 0x1}, |
844 | 844 | ||
845 | /* 96k */ | 845 | /* 96k */ |
846 | {12288000, 96000, 0xe, 0x0}, | 846 | {12288000, 96000, 0xe, 0x0}, |
847 | {18432000, 96000, 0xf, 0x0}, | 847 | {18432000, 96000, 0xf, 0x0}, |
848 | {12000000, 96000, 0xe, 0x1}, | 848 | {12000000, 96000, 0xe, 0x1}, |
849 | }; | 849 | }; |
850 | 850 | ||
851 | static int get_coeff(int mclk, int rate) | 851 | static int get_coeff(int mclk, int rate) |
852 | { | 852 | { |
853 | int i; | 853 | int i; |
854 | 854 | ||
855 | for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { | 855 | for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { |
856 | if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) | 856 | if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) |
857 | return i; | 857 | return i; |
858 | } | 858 | } |
859 | return -EINVAL; | 859 | return -EINVAL; |
860 | } | 860 | } |
861 | 861 | ||
862 | /* | 862 | /* |
863 | * Clock after PLL and dividers | 863 | * Clock after PLL and dividers |
864 | */ | 864 | */ |
865 | static int wm8753_set_dai_sysclk(struct snd_soc_dai *codec_dai, | 865 | static int wm8753_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
866 | int clk_id, unsigned int freq, int dir) | 866 | int clk_id, unsigned int freq, int dir) |
867 | { | 867 | { |
868 | struct snd_soc_codec *codec = codec_dai->codec; | 868 | struct snd_soc_codec *codec = codec_dai->codec; |
869 | struct wm8753_priv *wm8753 = codec->private_data; | 869 | struct wm8753_priv *wm8753 = codec->private_data; |
870 | 870 | ||
871 | switch (freq) { | 871 | switch (freq) { |
872 | case 11289600: | 872 | case 11289600: |
873 | case 12000000: | 873 | case 12000000: |
874 | case 12288000: | 874 | case 12288000: |
875 | case 16934400: | 875 | case 16934400: |
876 | case 18432000: | 876 | case 18432000: |
877 | if (clk_id == WM8753_MCLK) { | 877 | if (clk_id == WM8753_MCLK) { |
878 | wm8753->sysclk = freq; | 878 | wm8753->sysclk = freq; |
879 | return 0; | 879 | return 0; |
880 | } else if (clk_id == WM8753_PCMCLK) { | 880 | } else if (clk_id == WM8753_PCMCLK) { |
881 | wm8753->pcmclk = freq; | 881 | wm8753->pcmclk = freq; |
882 | return 0; | 882 | return 0; |
883 | } | 883 | } |
884 | break; | 884 | break; |
885 | } | 885 | } |
886 | return -EINVAL; | 886 | return -EINVAL; |
887 | } | 887 | } |
888 | 888 | ||
889 | /* | 889 | /* |
890 | * Set's ADC and Voice DAC format. | 890 | * Set's ADC and Voice DAC format. |
891 | */ | 891 | */ |
892 | static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_dai *codec_dai, | 892 | static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_dai *codec_dai, |
893 | unsigned int fmt) | 893 | unsigned int fmt) |
894 | { | 894 | { |
895 | struct snd_soc_codec *codec = codec_dai->codec; | 895 | struct snd_soc_codec *codec = codec_dai->codec; |
896 | u16 voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x01ec; | 896 | u16 voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x01ec; |
897 | 897 | ||
898 | /* interface format */ | 898 | /* interface format */ |
899 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 899 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
900 | case SND_SOC_DAIFMT_I2S: | 900 | case SND_SOC_DAIFMT_I2S: |
901 | voice |= 0x0002; | 901 | voice |= 0x0002; |
902 | break; | 902 | break; |
903 | case SND_SOC_DAIFMT_RIGHT_J: | 903 | case SND_SOC_DAIFMT_RIGHT_J: |
904 | break; | 904 | break; |
905 | case SND_SOC_DAIFMT_LEFT_J: | 905 | case SND_SOC_DAIFMT_LEFT_J: |
906 | voice |= 0x0001; | 906 | voice |= 0x0001; |
907 | break; | 907 | break; |
908 | case SND_SOC_DAIFMT_DSP_A: | 908 | case SND_SOC_DAIFMT_DSP_A: |
909 | voice |= 0x0003; | 909 | voice |= 0x0003; |
910 | break; | 910 | break; |
911 | case SND_SOC_DAIFMT_DSP_B: | 911 | case SND_SOC_DAIFMT_DSP_B: |
912 | voice |= 0x0013; | 912 | voice |= 0x0013; |
913 | break; | 913 | break; |
914 | default: | 914 | default: |
915 | return -EINVAL; | 915 | return -EINVAL; |
916 | } | 916 | } |
917 | 917 | ||
918 | wm8753_write(codec, WM8753_PCM, voice); | 918 | wm8753_write(codec, WM8753_PCM, voice); |
919 | return 0; | 919 | return 0; |
920 | } | 920 | } |
921 | 921 | ||
922 | /* | 922 | /* |
923 | * Set PCM DAI bit size and sample rate. | 923 | * Set PCM DAI bit size and sample rate. |
924 | */ | 924 | */ |
925 | static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream, | 925 | static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream, |
926 | struct snd_pcm_hw_params *params) | 926 | struct snd_pcm_hw_params *params) |
927 | { | 927 | { |
928 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 928 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
929 | struct snd_soc_device *socdev = rtd->socdev; | 929 | struct snd_soc_device *socdev = rtd->socdev; |
930 | struct snd_soc_codec *codec = socdev->codec; | 930 | struct snd_soc_codec *codec = socdev->codec; |
931 | struct wm8753_priv *wm8753 = codec->private_data; | 931 | struct wm8753_priv *wm8753 = codec->private_data; |
932 | u16 voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x01f3; | 932 | u16 voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x01f3; |
933 | u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x017f; | 933 | u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x017f; |
934 | 934 | ||
935 | /* bit size */ | 935 | /* bit size */ |
936 | switch (params_format(params)) { | 936 | switch (params_format(params)) { |
937 | case SNDRV_PCM_FORMAT_S16_LE: | 937 | case SNDRV_PCM_FORMAT_S16_LE: |
938 | break; | 938 | break; |
939 | case SNDRV_PCM_FORMAT_S20_3LE: | 939 | case SNDRV_PCM_FORMAT_S20_3LE: |
940 | voice |= 0x0004; | 940 | voice |= 0x0004; |
941 | break; | 941 | break; |
942 | case SNDRV_PCM_FORMAT_S24_LE: | 942 | case SNDRV_PCM_FORMAT_S24_LE: |
943 | voice |= 0x0008; | 943 | voice |= 0x0008; |
944 | break; | 944 | break; |
945 | case SNDRV_PCM_FORMAT_S32_LE: | 945 | case SNDRV_PCM_FORMAT_S32_LE: |
946 | voice |= 0x000c; | 946 | voice |= 0x000c; |
947 | break; | 947 | break; |
948 | } | 948 | } |
949 | 949 | ||
950 | /* sample rate */ | 950 | /* sample rate */ |
951 | if (params_rate(params) * 384 == wm8753->pcmclk) | 951 | if (params_rate(params) * 384 == wm8753->pcmclk) |
952 | srate |= 0x80; | 952 | srate |= 0x80; |
953 | wm8753_write(codec, WM8753_SRATE1, srate); | 953 | wm8753_write(codec, WM8753_SRATE1, srate); |
954 | 954 | ||
955 | wm8753_write(codec, WM8753_PCM, voice); | 955 | wm8753_write(codec, WM8753_PCM, voice); |
956 | return 0; | 956 | return 0; |
957 | } | 957 | } |
958 | 958 | ||
959 | /* | 959 | /* |
960 | * Set's PCM dai fmt and BCLK. | 960 | * Set's PCM dai fmt and BCLK. |
961 | */ | 961 | */ |
962 | static int wm8753_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai, | 962 | static int wm8753_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai, |
963 | unsigned int fmt) | 963 | unsigned int fmt) |
964 | { | 964 | { |
965 | struct snd_soc_codec *codec = codec_dai->codec; | 965 | struct snd_soc_codec *codec = codec_dai->codec; |
966 | u16 voice, ioctl; | 966 | u16 voice, ioctl; |
967 | 967 | ||
968 | voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x011f; | 968 | voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x011f; |
969 | ioctl = wm8753_read_reg_cache(codec, WM8753_IOCTL) & 0x015d; | 969 | ioctl = wm8753_read_reg_cache(codec, WM8753_IOCTL) & 0x015d; |
970 | 970 | ||
971 | /* set master/slave audio interface */ | 971 | /* set master/slave audio interface */ |
972 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 972 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
973 | case SND_SOC_DAIFMT_CBS_CFS: | 973 | case SND_SOC_DAIFMT_CBS_CFS: |
974 | break; | 974 | break; |
975 | case SND_SOC_DAIFMT_CBM_CFM: | 975 | case SND_SOC_DAIFMT_CBM_CFM: |
976 | ioctl |= 0x2; | 976 | ioctl |= 0x2; |
977 | case SND_SOC_DAIFMT_CBM_CFS: | 977 | case SND_SOC_DAIFMT_CBM_CFS: |
978 | voice |= 0x0040; | 978 | voice |= 0x0040; |
979 | break; | 979 | break; |
980 | default: | 980 | default: |
981 | return -EINVAL; | 981 | return -EINVAL; |
982 | } | 982 | } |
983 | 983 | ||
984 | /* clock inversion */ | 984 | /* clock inversion */ |
985 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 985 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
986 | case SND_SOC_DAIFMT_DSP_A: | 986 | case SND_SOC_DAIFMT_DSP_A: |
987 | case SND_SOC_DAIFMT_DSP_B: | 987 | case SND_SOC_DAIFMT_DSP_B: |
988 | /* frame inversion not valid for DSP modes */ | 988 | /* frame inversion not valid for DSP modes */ |
989 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | 989 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
990 | case SND_SOC_DAIFMT_NB_NF: | 990 | case SND_SOC_DAIFMT_NB_NF: |
991 | break; | 991 | break; |
992 | case SND_SOC_DAIFMT_IB_NF: | 992 | case SND_SOC_DAIFMT_IB_NF: |
993 | voice |= 0x0080; | 993 | voice |= 0x0080; |
994 | break; | 994 | break; |
995 | default: | 995 | default: |
996 | return -EINVAL; | 996 | return -EINVAL; |
997 | } | 997 | } |
998 | break; | 998 | break; |
999 | case SND_SOC_DAIFMT_I2S: | 999 | case SND_SOC_DAIFMT_I2S: |
1000 | case SND_SOC_DAIFMT_RIGHT_J: | 1000 | case SND_SOC_DAIFMT_RIGHT_J: |
1001 | case SND_SOC_DAIFMT_LEFT_J: | 1001 | case SND_SOC_DAIFMT_LEFT_J: |
1002 | voice &= ~0x0010; | 1002 | voice &= ~0x0010; |
1003 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | 1003 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
1004 | case SND_SOC_DAIFMT_NB_NF: | 1004 | case SND_SOC_DAIFMT_NB_NF: |
1005 | break; | 1005 | break; |
1006 | case SND_SOC_DAIFMT_IB_IF: | 1006 | case SND_SOC_DAIFMT_IB_IF: |
1007 | voice |= 0x0090; | 1007 | voice |= 0x0090; |
1008 | break; | 1008 | break; |
1009 | case SND_SOC_DAIFMT_IB_NF: | 1009 | case SND_SOC_DAIFMT_IB_NF: |
1010 | voice |= 0x0080; | 1010 | voice |= 0x0080; |
1011 | break; | 1011 | break; |
1012 | case SND_SOC_DAIFMT_NB_IF: | 1012 | case SND_SOC_DAIFMT_NB_IF: |
1013 | voice |= 0x0010; | 1013 | voice |= 0x0010; |
1014 | break; | 1014 | break; |
1015 | default: | 1015 | default: |
1016 | return -EINVAL; | 1016 | return -EINVAL; |
1017 | } | 1017 | } |
1018 | break; | 1018 | break; |
1019 | default: | 1019 | default: |
1020 | return -EINVAL; | 1020 | return -EINVAL; |
1021 | } | 1021 | } |
1022 | 1022 | ||
1023 | wm8753_write(codec, WM8753_PCM, voice); | 1023 | wm8753_write(codec, WM8753_PCM, voice); |
1024 | wm8753_write(codec, WM8753_IOCTL, ioctl); | 1024 | wm8753_write(codec, WM8753_IOCTL, ioctl); |
1025 | return 0; | 1025 | return 0; |
1026 | } | 1026 | } |
1027 | 1027 | ||
1028 | static int wm8753_set_dai_clkdiv(struct snd_soc_dai *codec_dai, | 1028 | static int wm8753_set_dai_clkdiv(struct snd_soc_dai *codec_dai, |
1029 | int div_id, int div) | 1029 | int div_id, int div) |
1030 | { | 1030 | { |
1031 | struct snd_soc_codec *codec = codec_dai->codec; | 1031 | struct snd_soc_codec *codec = codec_dai->codec; |
1032 | u16 reg; | 1032 | u16 reg; |
1033 | 1033 | ||
1034 | switch (div_id) { | 1034 | switch (div_id) { |
1035 | case WM8753_PCMDIV: | 1035 | case WM8753_PCMDIV: |
1036 | reg = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0x003f; | 1036 | reg = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0x003f; |
1037 | wm8753_write(codec, WM8753_CLOCK, reg | div); | 1037 | wm8753_write(codec, WM8753_CLOCK, reg | div); |
1038 | break; | 1038 | break; |
1039 | case WM8753_BCLKDIV: | 1039 | case WM8753_BCLKDIV: |
1040 | reg = wm8753_read_reg_cache(codec, WM8753_SRATE2) & 0x01c7; | 1040 | reg = wm8753_read_reg_cache(codec, WM8753_SRATE2) & 0x01c7; |
1041 | wm8753_write(codec, WM8753_SRATE2, reg | div); | 1041 | wm8753_write(codec, WM8753_SRATE2, reg | div); |
1042 | break; | 1042 | break; |
1043 | case WM8753_VXCLKDIV: | 1043 | case WM8753_VXCLKDIV: |
1044 | reg = wm8753_read_reg_cache(codec, WM8753_SRATE2) & 0x003f; | 1044 | reg = wm8753_read_reg_cache(codec, WM8753_SRATE2) & 0x003f; |
1045 | wm8753_write(codec, WM8753_SRATE2, reg | div); | 1045 | wm8753_write(codec, WM8753_SRATE2, reg | div); |
1046 | break; | 1046 | break; |
1047 | default: | 1047 | default: |
1048 | return -EINVAL; | 1048 | return -EINVAL; |
1049 | } | 1049 | } |
1050 | return 0; | 1050 | return 0; |
1051 | } | 1051 | } |
1052 | 1052 | ||
1053 | /* | 1053 | /* |
1054 | * Set's HiFi DAC format. | 1054 | * Set's HiFi DAC format. |
1055 | */ | 1055 | */ |
1056 | static int wm8753_hdac_set_dai_fmt(struct snd_soc_dai *codec_dai, | 1056 | static int wm8753_hdac_set_dai_fmt(struct snd_soc_dai *codec_dai, |
1057 | unsigned int fmt) | 1057 | unsigned int fmt) |
1058 | { | 1058 | { |
1059 | struct snd_soc_codec *codec = codec_dai->codec; | 1059 | struct snd_soc_codec *codec = codec_dai->codec; |
1060 | u16 hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x01e0; | 1060 | u16 hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x01e0; |
1061 | 1061 | ||
1062 | /* interface format */ | 1062 | /* interface format */ |
1063 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 1063 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
1064 | case SND_SOC_DAIFMT_I2S: | 1064 | case SND_SOC_DAIFMT_I2S: |
1065 | hifi |= 0x0002; | 1065 | hifi |= 0x0002; |
1066 | break; | 1066 | break; |
1067 | case SND_SOC_DAIFMT_RIGHT_J: | 1067 | case SND_SOC_DAIFMT_RIGHT_J: |
1068 | break; | 1068 | break; |
1069 | case SND_SOC_DAIFMT_LEFT_J: | 1069 | case SND_SOC_DAIFMT_LEFT_J: |
1070 | hifi |= 0x0001; | 1070 | hifi |= 0x0001; |
1071 | break; | 1071 | break; |
1072 | case SND_SOC_DAIFMT_DSP_A: | 1072 | case SND_SOC_DAIFMT_DSP_A: |
1073 | hifi |= 0x0003; | 1073 | hifi |= 0x0003; |
1074 | break; | 1074 | break; |
1075 | case SND_SOC_DAIFMT_DSP_B: | 1075 | case SND_SOC_DAIFMT_DSP_B: |
1076 | hifi |= 0x0013; | 1076 | hifi |= 0x0013; |
1077 | break; | 1077 | break; |
1078 | default: | 1078 | default: |
1079 | return -EINVAL; | 1079 | return -EINVAL; |
1080 | } | 1080 | } |
1081 | 1081 | ||
1082 | wm8753_write(codec, WM8753_HIFI, hifi); | 1082 | wm8753_write(codec, WM8753_HIFI, hifi); |
1083 | return 0; | 1083 | return 0; |
1084 | } | 1084 | } |
1085 | 1085 | ||
1086 | /* | 1086 | /* |
1087 | * Set's I2S DAI format. | 1087 | * Set's I2S DAI format. |
1088 | */ | 1088 | */ |
1089 | static int wm8753_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai, | 1089 | static int wm8753_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai, |
1090 | unsigned int fmt) | 1090 | unsigned int fmt) |
1091 | { | 1091 | { |
1092 | struct snd_soc_codec *codec = codec_dai->codec; | 1092 | struct snd_soc_codec *codec = codec_dai->codec; |
1093 | u16 ioctl, hifi; | 1093 | u16 ioctl, hifi; |
1094 | 1094 | ||
1095 | hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x011f; | 1095 | hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x011f; |
1096 | ioctl = wm8753_read_reg_cache(codec, WM8753_IOCTL) & 0x00ae; | 1096 | ioctl = wm8753_read_reg_cache(codec, WM8753_IOCTL) & 0x00ae; |
1097 | 1097 | ||
1098 | /* set master/slave audio interface */ | 1098 | /* set master/slave audio interface */ |
1099 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 1099 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
1100 | case SND_SOC_DAIFMT_CBS_CFS: | 1100 | case SND_SOC_DAIFMT_CBS_CFS: |
1101 | break; | 1101 | break; |
1102 | case SND_SOC_DAIFMT_CBM_CFM: | 1102 | case SND_SOC_DAIFMT_CBM_CFM: |
1103 | ioctl |= 0x1; | 1103 | ioctl |= 0x1; |
1104 | case SND_SOC_DAIFMT_CBM_CFS: | 1104 | case SND_SOC_DAIFMT_CBM_CFS: |
1105 | hifi |= 0x0040; | 1105 | hifi |= 0x0040; |
1106 | break; | 1106 | break; |
1107 | default: | 1107 | default: |
1108 | return -EINVAL; | 1108 | return -EINVAL; |
1109 | } | 1109 | } |
1110 | 1110 | ||
1111 | /* clock inversion */ | 1111 | /* clock inversion */ |
1112 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 1112 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
1113 | case SND_SOC_DAIFMT_DSP_A: | 1113 | case SND_SOC_DAIFMT_DSP_A: |
1114 | case SND_SOC_DAIFMT_DSP_B: | 1114 | case SND_SOC_DAIFMT_DSP_B: |
1115 | /* frame inversion not valid for DSP modes */ | 1115 | /* frame inversion not valid for DSP modes */ |
1116 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | 1116 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
1117 | case SND_SOC_DAIFMT_NB_NF: | 1117 | case SND_SOC_DAIFMT_NB_NF: |
1118 | break; | 1118 | break; |
1119 | case SND_SOC_DAIFMT_IB_NF: | 1119 | case SND_SOC_DAIFMT_IB_NF: |
1120 | hifi |= 0x0080; | 1120 | hifi |= 0x0080; |
1121 | break; | 1121 | break; |
1122 | default: | 1122 | default: |
1123 | return -EINVAL; | 1123 | return -EINVAL; |
1124 | } | 1124 | } |
1125 | break; | 1125 | break; |
1126 | case SND_SOC_DAIFMT_I2S: | 1126 | case SND_SOC_DAIFMT_I2S: |
1127 | case SND_SOC_DAIFMT_RIGHT_J: | 1127 | case SND_SOC_DAIFMT_RIGHT_J: |
1128 | case SND_SOC_DAIFMT_LEFT_J: | 1128 | case SND_SOC_DAIFMT_LEFT_J: |
1129 | hifi &= ~0x0010; | 1129 | hifi &= ~0x0010; |
1130 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | 1130 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
1131 | case SND_SOC_DAIFMT_NB_NF: | 1131 | case SND_SOC_DAIFMT_NB_NF: |
1132 | break; | 1132 | break; |
1133 | case SND_SOC_DAIFMT_IB_IF: | 1133 | case SND_SOC_DAIFMT_IB_IF: |
1134 | hifi |= 0x0090; | 1134 | hifi |= 0x0090; |
1135 | break; | 1135 | break; |
1136 | case SND_SOC_DAIFMT_IB_NF: | 1136 | case SND_SOC_DAIFMT_IB_NF: |
1137 | hifi |= 0x0080; | 1137 | hifi |= 0x0080; |
1138 | break; | 1138 | break; |
1139 | case SND_SOC_DAIFMT_NB_IF: | 1139 | case SND_SOC_DAIFMT_NB_IF: |
1140 | hifi |= 0x0010; | 1140 | hifi |= 0x0010; |
1141 | break; | 1141 | break; |
1142 | default: | 1142 | default: |
1143 | return -EINVAL; | 1143 | return -EINVAL; |
1144 | } | 1144 | } |
1145 | break; | 1145 | break; |
1146 | default: | 1146 | default: |
1147 | return -EINVAL; | 1147 | return -EINVAL; |
1148 | } | 1148 | } |
1149 | 1149 | ||
1150 | wm8753_write(codec, WM8753_HIFI, hifi); | 1150 | wm8753_write(codec, WM8753_HIFI, hifi); |
1151 | wm8753_write(codec, WM8753_IOCTL, ioctl); | 1151 | wm8753_write(codec, WM8753_IOCTL, ioctl); |
1152 | return 0; | 1152 | return 0; |
1153 | } | 1153 | } |
1154 | 1154 | ||
1155 | /* | 1155 | /* |
1156 | * Set PCM DAI bit size and sample rate. | 1156 | * Set PCM DAI bit size and sample rate. |
1157 | */ | 1157 | */ |
1158 | static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream, | 1158 | static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream, |
1159 | struct snd_pcm_hw_params *params) | 1159 | struct snd_pcm_hw_params *params) |
1160 | { | 1160 | { |
1161 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 1161 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
1162 | struct snd_soc_device *socdev = rtd->socdev; | 1162 | struct snd_soc_device *socdev = rtd->socdev; |
1163 | struct snd_soc_codec *codec = socdev->codec; | 1163 | struct snd_soc_codec *codec = socdev->codec; |
1164 | struct wm8753_priv *wm8753 = codec->private_data; | 1164 | struct wm8753_priv *wm8753 = codec->private_data; |
1165 | u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x01c0; | 1165 | u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x01c0; |
1166 | u16 hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x01f3; | 1166 | u16 hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x01f3; |
1167 | int coeff; | 1167 | int coeff; |
1168 | 1168 | ||
1169 | /* is digital filter coefficient valid ? */ | 1169 | /* is digital filter coefficient valid ? */ |
1170 | coeff = get_coeff(wm8753->sysclk, params_rate(params)); | 1170 | coeff = get_coeff(wm8753->sysclk, params_rate(params)); |
1171 | if (coeff < 0) { | 1171 | if (coeff < 0) { |
1172 | printk(KERN_ERR "wm8753 invalid MCLK or rate\n"); | 1172 | printk(KERN_ERR "wm8753 invalid MCLK or rate\n"); |
1173 | return coeff; | 1173 | return coeff; |
1174 | } | 1174 | } |
1175 | wm8753_write(codec, WM8753_SRATE1, srate | (coeff_div[coeff].sr << 1) | | 1175 | wm8753_write(codec, WM8753_SRATE1, srate | (coeff_div[coeff].sr << 1) | |
1176 | coeff_div[coeff].usb); | 1176 | coeff_div[coeff].usb); |
1177 | 1177 | ||
1178 | /* bit size */ | 1178 | /* bit size */ |
1179 | switch (params_format(params)) { | 1179 | switch (params_format(params)) { |
1180 | case SNDRV_PCM_FORMAT_S16_LE: | 1180 | case SNDRV_PCM_FORMAT_S16_LE: |
1181 | break; | 1181 | break; |
1182 | case SNDRV_PCM_FORMAT_S20_3LE: | 1182 | case SNDRV_PCM_FORMAT_S20_3LE: |
1183 | hifi |= 0x0004; | 1183 | hifi |= 0x0004; |
1184 | break; | 1184 | break; |
1185 | case SNDRV_PCM_FORMAT_S24_LE: | 1185 | case SNDRV_PCM_FORMAT_S24_LE: |
1186 | hifi |= 0x0008; | 1186 | hifi |= 0x0008; |
1187 | break; | 1187 | break; |
1188 | case SNDRV_PCM_FORMAT_S32_LE: | 1188 | case SNDRV_PCM_FORMAT_S32_LE: |
1189 | hifi |= 0x000c; | 1189 | hifi |= 0x000c; |
1190 | break; | 1190 | break; |
1191 | } | 1191 | } |
1192 | 1192 | ||
1193 | wm8753_write(codec, WM8753_HIFI, hifi); | 1193 | wm8753_write(codec, WM8753_HIFI, hifi); |
1194 | return 0; | 1194 | return 0; |
1195 | } | 1195 | } |
1196 | 1196 | ||
1197 | static int wm8753_mode1v_set_dai_fmt(struct snd_soc_dai *codec_dai, | 1197 | static int wm8753_mode1v_set_dai_fmt(struct snd_soc_dai *codec_dai, |
1198 | unsigned int fmt) | 1198 | unsigned int fmt) |
1199 | { | 1199 | { |
1200 | struct snd_soc_codec *codec = codec_dai->codec; | 1200 | struct snd_soc_codec *codec = codec_dai->codec; |
1201 | u16 clock; | 1201 | u16 clock; |
1202 | 1202 | ||
1203 | /* set clk source as pcmclk */ | 1203 | /* set clk source as pcmclk */ |
1204 | clock = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xfffb; | 1204 | clock = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xfffb; |
1205 | wm8753_write(codec, WM8753_CLOCK, clock); | 1205 | wm8753_write(codec, WM8753_CLOCK, clock); |
1206 | 1206 | ||
1207 | if (wm8753_vdac_adc_set_dai_fmt(codec_dai, fmt) < 0) | 1207 | if (wm8753_vdac_adc_set_dai_fmt(codec_dai, fmt) < 0) |
1208 | return -EINVAL; | 1208 | return -EINVAL; |
1209 | return wm8753_pcm_set_dai_fmt(codec_dai, fmt); | 1209 | return wm8753_pcm_set_dai_fmt(codec_dai, fmt); |
1210 | } | 1210 | } |
1211 | 1211 | ||
1212 | static int wm8753_mode1h_set_dai_fmt(struct snd_soc_dai *codec_dai, | 1212 | static int wm8753_mode1h_set_dai_fmt(struct snd_soc_dai *codec_dai, |
1213 | unsigned int fmt) | 1213 | unsigned int fmt) |
1214 | { | 1214 | { |
1215 | if (wm8753_hdac_set_dai_fmt(codec_dai, fmt) < 0) | 1215 | if (wm8753_hdac_set_dai_fmt(codec_dai, fmt) < 0) |
1216 | return -EINVAL; | 1216 | return -EINVAL; |
1217 | return wm8753_i2s_set_dai_fmt(codec_dai, fmt); | 1217 | return wm8753_i2s_set_dai_fmt(codec_dai, fmt); |
1218 | } | 1218 | } |
1219 | 1219 | ||
1220 | static int wm8753_mode2_set_dai_fmt(struct snd_soc_dai *codec_dai, | 1220 | static int wm8753_mode2_set_dai_fmt(struct snd_soc_dai *codec_dai, |
1221 | unsigned int fmt) | 1221 | unsigned int fmt) |
1222 | { | 1222 | { |
1223 | struct snd_soc_codec *codec = codec_dai->codec; | 1223 | struct snd_soc_codec *codec = codec_dai->codec; |
1224 | u16 clock; | 1224 | u16 clock; |
1225 | 1225 | ||
1226 | /* set clk source as pcmclk */ | 1226 | /* set clk source as pcmclk */ |
1227 | clock = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xfffb; | 1227 | clock = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xfffb; |
1228 | wm8753_write(codec, WM8753_CLOCK, clock); | 1228 | wm8753_write(codec, WM8753_CLOCK, clock); |
1229 | 1229 | ||
1230 | if (wm8753_vdac_adc_set_dai_fmt(codec_dai, fmt) < 0) | 1230 | if (wm8753_vdac_adc_set_dai_fmt(codec_dai, fmt) < 0) |
1231 | return -EINVAL; | 1231 | return -EINVAL; |
1232 | return wm8753_i2s_set_dai_fmt(codec_dai, fmt); | 1232 | return wm8753_i2s_set_dai_fmt(codec_dai, fmt); |
1233 | } | 1233 | } |
1234 | 1234 | ||
1235 | static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_dai *codec_dai, | 1235 | static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_dai *codec_dai, |
1236 | unsigned int fmt) | 1236 | unsigned int fmt) |
1237 | { | 1237 | { |
1238 | struct snd_soc_codec *codec = codec_dai->codec; | 1238 | struct snd_soc_codec *codec = codec_dai->codec; |
1239 | u16 clock; | 1239 | u16 clock; |
1240 | 1240 | ||
1241 | /* set clk source as mclk */ | 1241 | /* set clk source as mclk */ |
1242 | clock = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xfffb; | 1242 | clock = wm8753_read_reg_cache(codec, WM8753_CLOCK) & 0xfffb; |
1243 | wm8753_write(codec, WM8753_CLOCK, clock | 0x4); | 1243 | wm8753_write(codec, WM8753_CLOCK, clock | 0x4); |
1244 | 1244 | ||
1245 | if (wm8753_hdac_set_dai_fmt(codec_dai, fmt) < 0) | 1245 | if (wm8753_hdac_set_dai_fmt(codec_dai, fmt) < 0) |
1246 | return -EINVAL; | 1246 | return -EINVAL; |
1247 | if (wm8753_vdac_adc_set_dai_fmt(codec_dai, fmt) < 0) | 1247 | if (wm8753_vdac_adc_set_dai_fmt(codec_dai, fmt) < 0) |
1248 | return -EINVAL; | 1248 | return -EINVAL; |
1249 | return wm8753_i2s_set_dai_fmt(codec_dai, fmt); | 1249 | return wm8753_i2s_set_dai_fmt(codec_dai, fmt); |
1250 | } | 1250 | } |
1251 | 1251 | ||
1252 | static int wm8753_mute(struct snd_soc_dai *dai, int mute) | 1252 | static int wm8753_mute(struct snd_soc_dai *dai, int mute) |
1253 | { | 1253 | { |
1254 | struct snd_soc_codec *codec = dai->codec; | 1254 | struct snd_soc_codec *codec = dai->codec; |
1255 | u16 mute_reg = wm8753_read_reg_cache(codec, WM8753_DAC) & 0xfff7; | 1255 | u16 mute_reg = wm8753_read_reg_cache(codec, WM8753_DAC) & 0xfff7; |
1256 | 1256 | ||
1257 | /* the digital mute covers the HiFi and Voice DAC's on the WM8753. | 1257 | /* the digital mute covers the HiFi and Voice DAC's on the WM8753. |
1258 | * make sure we check if they are not both active when we mute */ | 1258 | * make sure we check if they are not both active when we mute */ |
1259 | if (mute && dai->id == 1) { | 1259 | if (mute && dai->id == 1) { |
1260 | if (!wm8753_dai[WM8753_DAI_VOICE].playback.active || | 1260 | if (!wm8753_dai[WM8753_DAI_VOICE].playback.active || |
1261 | !wm8753_dai[WM8753_DAI_HIFI].playback.active) | 1261 | !wm8753_dai[WM8753_DAI_HIFI].playback.active) |
1262 | wm8753_write(codec, WM8753_DAC, mute_reg | 0x8); | 1262 | wm8753_write(codec, WM8753_DAC, mute_reg | 0x8); |
1263 | } else { | 1263 | } else { |
1264 | if (mute) | 1264 | if (mute) |
1265 | wm8753_write(codec, WM8753_DAC, mute_reg | 0x8); | 1265 | wm8753_write(codec, WM8753_DAC, mute_reg | 0x8); |
1266 | else | 1266 | else |
1267 | wm8753_write(codec, WM8753_DAC, mute_reg); | 1267 | wm8753_write(codec, WM8753_DAC, mute_reg); |
1268 | } | 1268 | } |
1269 | 1269 | ||
1270 | return 0; | 1270 | return 0; |
1271 | } | 1271 | } |
1272 | 1272 | ||
1273 | static int wm8753_set_bias_level(struct snd_soc_codec *codec, | 1273 | static int wm8753_set_bias_level(struct snd_soc_codec *codec, |
1274 | enum snd_soc_bias_level level) | 1274 | enum snd_soc_bias_level level) |
1275 | { | 1275 | { |
1276 | u16 pwr_reg = wm8753_read_reg_cache(codec, WM8753_PWR1) & 0xfe3e; | 1276 | u16 pwr_reg = wm8753_read_reg_cache(codec, WM8753_PWR1) & 0xfe3e; |
1277 | 1277 | ||
1278 | switch (level) { | 1278 | switch (level) { |
1279 | case SND_SOC_BIAS_ON: | 1279 | case SND_SOC_BIAS_ON: |
1280 | /* set vmid to 50k and unmute dac */ | 1280 | /* set vmid to 50k and unmute dac */ |
1281 | wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x00c0); | 1281 | wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x00c0); |
1282 | break; | 1282 | break; |
1283 | case SND_SOC_BIAS_PREPARE: | 1283 | case SND_SOC_BIAS_PREPARE: |
1284 | /* set vmid to 5k for quick power up */ | 1284 | /* set vmid to 5k for quick power up */ |
1285 | wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x01c1); | 1285 | wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x01c1); |
1286 | break; | 1286 | break; |
1287 | case SND_SOC_BIAS_STANDBY: | 1287 | case SND_SOC_BIAS_STANDBY: |
1288 | /* mute dac and set vmid to 500k, enable VREF */ | 1288 | /* mute dac and set vmid to 500k, enable VREF */ |
1289 | wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x0141); | 1289 | wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x0141); |
1290 | break; | 1290 | break; |
1291 | case SND_SOC_BIAS_OFF: | 1291 | case SND_SOC_BIAS_OFF: |
1292 | wm8753_write(codec, WM8753_PWR1, 0x0001); | 1292 | wm8753_write(codec, WM8753_PWR1, 0x0001); |
1293 | break; | 1293 | break; |
1294 | } | 1294 | } |
1295 | codec->bias_level = level; | 1295 | codec->bias_level = level; |
1296 | return 0; | 1296 | return 0; |
1297 | } | 1297 | } |
1298 | 1298 | ||
1299 | #define WM8753_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | 1299 | #define WM8753_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ |
1300 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ | 1300 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ |
1301 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ | 1301 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ |
1302 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) | 1302 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) |
1303 | 1303 | ||
1304 | #define WM8753_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | 1304 | #define WM8753_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
1305 | SNDRV_PCM_FMTBIT_S24_LE) | 1305 | SNDRV_PCM_FMTBIT_S24_LE) |
1306 | 1306 | ||
1307 | /* | 1307 | /* |
1308 | * The WM8753 supports upto 4 different and mutually exclusive DAI | 1308 | * The WM8753 supports upto 4 different and mutually exclusive DAI |
1309 | * configurations. This gives 2 PCM's available for use, hifi and voice. | 1309 | * configurations. This gives 2 PCM's available for use, hifi and voice. |
1310 | * NOTE: The Voice PCM cannot play or capture audio to the CPU as it's DAI | 1310 | * NOTE: The Voice PCM cannot play or capture audio to the CPU as it's DAI |
1311 | * is connected between the wm8753 and a BT codec or GSM modem. | 1311 | * is connected between the wm8753 and a BT codec or GSM modem. |
1312 | * | 1312 | * |
1313 | * 1. Voice over PCM DAI - HIFI DAC over HIFI DAI | 1313 | * 1. Voice over PCM DAI - HIFI DAC over HIFI DAI |
1314 | * 2. Voice over HIFI DAI - HIFI disabled | 1314 | * 2. Voice over HIFI DAI - HIFI disabled |
1315 | * 3. Voice disabled - HIFI over HIFI | 1315 | * 3. Voice disabled - HIFI over HIFI |
1316 | * 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture | 1316 | * 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture |
1317 | */ | 1317 | */ |
1318 | static const struct snd_soc_dai wm8753_all_dai[] = { | 1318 | static const struct snd_soc_dai wm8753_all_dai[] = { |
1319 | /* DAI HiFi mode 1 */ | 1319 | /* DAI HiFi mode 1 */ |
1320 | { .name = "WM8753 HiFi", | 1320 | { .name = "WM8753 HiFi", |
1321 | .id = 1, | 1321 | .id = 1, |
1322 | .playback = { | 1322 | .playback = { |
1323 | .stream_name = "HiFi Playback", | 1323 | .stream_name = "HiFi Playback", |
1324 | .channels_min = 1, | 1324 | .channels_min = 1, |
1325 | .channels_max = 2, | 1325 | .channels_max = 2, |
1326 | .rates = WM8753_RATES, | 1326 | .rates = WM8753_RATES, |
1327 | .formats = WM8753_FORMATS,}, | 1327 | .formats = WM8753_FORMATS,}, |
1328 | .capture = { /* dummy for fast DAI switching */ | 1328 | .capture = { /* dummy for fast DAI switching */ |
1329 | .stream_name = "Capture", | 1329 | .stream_name = "Capture", |
1330 | .channels_min = 1, | 1330 | .channels_min = 1, |
1331 | .channels_max = 2, | 1331 | .channels_max = 2, |
1332 | .rates = WM8753_RATES, | 1332 | .rates = WM8753_RATES, |
1333 | .formats = WM8753_FORMATS,}, | 1333 | .formats = WM8753_FORMATS,}, |
1334 | .ops = { | 1334 | .ops = { |
1335 | .hw_params = wm8753_i2s_hw_params,}, | 1335 | .hw_params = wm8753_i2s_hw_params,}, |
1336 | .dai_ops = { | 1336 | .dai_ops = { |
1337 | .digital_mute = wm8753_mute, | 1337 | .digital_mute = wm8753_mute, |
1338 | .set_fmt = wm8753_mode1h_set_dai_fmt, | 1338 | .set_fmt = wm8753_mode1h_set_dai_fmt, |
1339 | .set_clkdiv = wm8753_set_dai_clkdiv, | 1339 | .set_clkdiv = wm8753_set_dai_clkdiv, |
1340 | .set_pll = wm8753_set_dai_pll, | 1340 | .set_pll = wm8753_set_dai_pll, |
1341 | .set_sysclk = wm8753_set_dai_sysclk, | 1341 | .set_sysclk = wm8753_set_dai_sysclk, |
1342 | }, | 1342 | }, |
1343 | }, | 1343 | }, |
1344 | /* DAI Voice mode 1 */ | 1344 | /* DAI Voice mode 1 */ |
1345 | { .name = "WM8753 Voice", | 1345 | { .name = "WM8753 Voice", |
1346 | .id = 1, | 1346 | .id = 1, |
1347 | .playback = { | 1347 | .playback = { |
1348 | .stream_name = "Voice Playback", | 1348 | .stream_name = "Voice Playback", |
1349 | .channels_min = 1, | 1349 | .channels_min = 1, |
1350 | .channels_max = 1, | 1350 | .channels_max = 1, |
1351 | .rates = WM8753_RATES, | 1351 | .rates = WM8753_RATES, |
1352 | .formats = WM8753_FORMATS,}, | 1352 | .formats = WM8753_FORMATS,}, |
1353 | .capture = { | 1353 | .capture = { |
1354 | .stream_name = "Capture", | 1354 | .stream_name = "Capture", |
1355 | .channels_min = 1, | 1355 | .channels_min = 1, |
1356 | .channels_max = 2, | 1356 | .channels_max = 2, |
1357 | .rates = WM8753_RATES, | 1357 | .rates = WM8753_RATES, |
1358 | .formats = WM8753_FORMATS,}, | 1358 | .formats = WM8753_FORMATS,}, |
1359 | .ops = { | 1359 | .ops = { |
1360 | .hw_params = wm8753_pcm_hw_params,}, | 1360 | .hw_params = wm8753_pcm_hw_params,}, |
1361 | .dai_ops = { | 1361 | .dai_ops = { |
1362 | .digital_mute = wm8753_mute, | 1362 | .digital_mute = wm8753_mute, |
1363 | .set_fmt = wm8753_mode1v_set_dai_fmt, | 1363 | .set_fmt = wm8753_mode1v_set_dai_fmt, |
1364 | .set_clkdiv = wm8753_set_dai_clkdiv, | 1364 | .set_clkdiv = wm8753_set_dai_clkdiv, |
1365 | .set_pll = wm8753_set_dai_pll, | 1365 | .set_pll = wm8753_set_dai_pll, |
1366 | .set_sysclk = wm8753_set_dai_sysclk, | 1366 | .set_sysclk = wm8753_set_dai_sysclk, |
1367 | }, | 1367 | }, |
1368 | }, | 1368 | }, |
1369 | /* DAI HiFi mode 2 - dummy */ | 1369 | /* DAI HiFi mode 2 - dummy */ |
1370 | { .name = "WM8753 HiFi", | 1370 | { .name = "WM8753 HiFi", |
1371 | .id = 2, | 1371 | .id = 2, |
1372 | }, | 1372 | }, |
1373 | /* DAI Voice mode 2 */ | 1373 | /* DAI Voice mode 2 */ |
1374 | { .name = "WM8753 Voice", | 1374 | { .name = "WM8753 Voice", |
1375 | .id = 2, | 1375 | .id = 2, |
1376 | .playback = { | 1376 | .playback = { |
1377 | .stream_name = "Voice Playback", | 1377 | .stream_name = "Voice Playback", |
1378 | .channels_min = 1, | 1378 | .channels_min = 1, |
1379 | .channels_max = 1, | 1379 | .channels_max = 1, |
1380 | .rates = WM8753_RATES, | 1380 | .rates = WM8753_RATES, |
1381 | .formats = WM8753_FORMATS,}, | 1381 | .formats = WM8753_FORMATS,}, |
1382 | .capture = { | 1382 | .capture = { |
1383 | .stream_name = "Capture", | 1383 | .stream_name = "Capture", |
1384 | .channels_min = 1, | 1384 | .channels_min = 1, |
1385 | .channels_max = 2, | 1385 | .channels_max = 2, |
1386 | .rates = WM8753_RATES, | 1386 | .rates = WM8753_RATES, |
1387 | .formats = WM8753_FORMATS,}, | 1387 | .formats = WM8753_FORMATS,}, |
1388 | .ops = { | 1388 | .ops = { |
1389 | .hw_params = wm8753_pcm_hw_params,}, | 1389 | .hw_params = wm8753_pcm_hw_params,}, |
1390 | .dai_ops = { | 1390 | .dai_ops = { |
1391 | .digital_mute = wm8753_mute, | 1391 | .digital_mute = wm8753_mute, |
1392 | .set_fmt = wm8753_mode2_set_dai_fmt, | 1392 | .set_fmt = wm8753_mode2_set_dai_fmt, |
1393 | .set_clkdiv = wm8753_set_dai_clkdiv, | 1393 | .set_clkdiv = wm8753_set_dai_clkdiv, |
1394 | .set_pll = wm8753_set_dai_pll, | 1394 | .set_pll = wm8753_set_dai_pll, |
1395 | .set_sysclk = wm8753_set_dai_sysclk, | 1395 | .set_sysclk = wm8753_set_dai_sysclk, |
1396 | }, | 1396 | }, |
1397 | }, | 1397 | }, |
1398 | /* DAI HiFi mode 3 */ | 1398 | /* DAI HiFi mode 3 */ |
1399 | { .name = "WM8753 HiFi", | 1399 | { .name = "WM8753 HiFi", |
1400 | .id = 3, | 1400 | .id = 3, |
1401 | .playback = { | 1401 | .playback = { |
1402 | .stream_name = "HiFi Playback", | 1402 | .stream_name = "HiFi Playback", |
1403 | .channels_min = 1, | 1403 | .channels_min = 1, |
1404 | .channels_max = 2, | 1404 | .channels_max = 2, |
1405 | .rates = WM8753_RATES, | 1405 | .rates = WM8753_RATES, |
1406 | .formats = WM8753_FORMATS,}, | 1406 | .formats = WM8753_FORMATS,}, |
1407 | .capture = { | 1407 | .capture = { |
1408 | .stream_name = "Capture", | 1408 | .stream_name = "Capture", |
1409 | .channels_min = 1, | 1409 | .channels_min = 1, |
1410 | .channels_max = 2, | 1410 | .channels_max = 2, |
1411 | .rates = WM8753_RATES, | 1411 | .rates = WM8753_RATES, |
1412 | .formats = WM8753_FORMATS,}, | 1412 | .formats = WM8753_FORMATS,}, |
1413 | .ops = { | 1413 | .ops = { |
1414 | .hw_params = wm8753_i2s_hw_params,}, | 1414 | .hw_params = wm8753_i2s_hw_params,}, |
1415 | .dai_ops = { | 1415 | .dai_ops = { |
1416 | .digital_mute = wm8753_mute, | 1416 | .digital_mute = wm8753_mute, |
1417 | .set_fmt = wm8753_mode3_4_set_dai_fmt, | 1417 | .set_fmt = wm8753_mode3_4_set_dai_fmt, |
1418 | .set_clkdiv = wm8753_set_dai_clkdiv, | 1418 | .set_clkdiv = wm8753_set_dai_clkdiv, |
1419 | .set_pll = wm8753_set_dai_pll, | 1419 | .set_pll = wm8753_set_dai_pll, |
1420 | .set_sysclk = wm8753_set_dai_sysclk, | 1420 | .set_sysclk = wm8753_set_dai_sysclk, |
1421 | }, | 1421 | }, |
1422 | }, | 1422 | }, |
1423 | /* DAI Voice mode 3 - dummy */ | 1423 | /* DAI Voice mode 3 - dummy */ |
1424 | { .name = "WM8753 Voice", | 1424 | { .name = "WM8753 Voice", |
1425 | .id = 3, | 1425 | .id = 3, |
1426 | }, | 1426 | }, |
1427 | /* DAI HiFi mode 4 */ | 1427 | /* DAI HiFi mode 4 */ |
1428 | { .name = "WM8753 HiFi", | 1428 | { .name = "WM8753 HiFi", |
1429 | .id = 4, | 1429 | .id = 4, |
1430 | .playback = { | 1430 | .playback = { |
1431 | .stream_name = "HiFi Playback", | 1431 | .stream_name = "HiFi Playback", |
1432 | .channels_min = 1, | 1432 | .channels_min = 1, |
1433 | .channels_max = 2, | 1433 | .channels_max = 2, |
1434 | .rates = WM8753_RATES, | 1434 | .rates = WM8753_RATES, |
1435 | .formats = WM8753_FORMATS,}, | 1435 | .formats = WM8753_FORMATS,}, |
1436 | .capture = { | 1436 | .capture = { |
1437 | .stream_name = "Capture", | 1437 | .stream_name = "Capture", |
1438 | .channels_min = 1, | 1438 | .channels_min = 1, |
1439 | .channels_max = 2, | 1439 | .channels_max = 2, |
1440 | .rates = WM8753_RATES, | 1440 | .rates = WM8753_RATES, |
1441 | .formats = WM8753_FORMATS,}, | 1441 | .formats = WM8753_FORMATS,}, |
1442 | .ops = { | 1442 | .ops = { |
1443 | .hw_params = wm8753_i2s_hw_params,}, | 1443 | .hw_params = wm8753_i2s_hw_params,}, |
1444 | .dai_ops = { | 1444 | .dai_ops = { |
1445 | .digital_mute = wm8753_mute, | 1445 | .digital_mute = wm8753_mute, |
1446 | .set_fmt = wm8753_mode3_4_set_dai_fmt, | 1446 | .set_fmt = wm8753_mode3_4_set_dai_fmt, |
1447 | .set_clkdiv = wm8753_set_dai_clkdiv, | 1447 | .set_clkdiv = wm8753_set_dai_clkdiv, |
1448 | .set_pll = wm8753_set_dai_pll, | 1448 | .set_pll = wm8753_set_dai_pll, |
1449 | .set_sysclk = wm8753_set_dai_sysclk, | 1449 | .set_sysclk = wm8753_set_dai_sysclk, |
1450 | }, | 1450 | }, |
1451 | }, | 1451 | }, |
1452 | /* DAI Voice mode 4 - dummy */ | 1452 | /* DAI Voice mode 4 - dummy */ |
1453 | { .name = "WM8753 Voice", | 1453 | { .name = "WM8753 Voice", |
1454 | .id = 4, | 1454 | .id = 4, |
1455 | }, | 1455 | }, |
1456 | }; | 1456 | }; |
1457 | 1457 | ||
1458 | struct snd_soc_dai wm8753_dai[2]; | 1458 | struct snd_soc_dai wm8753_dai[2]; |
1459 | EXPORT_SYMBOL_GPL(wm8753_dai); | 1459 | EXPORT_SYMBOL_GPL(wm8753_dai); |
1460 | 1460 | ||
1461 | static void wm8753_set_dai_mode(struct snd_soc_codec *codec, unsigned int mode) | 1461 | static void wm8753_set_dai_mode(struct snd_soc_codec *codec, unsigned int mode) |
1462 | { | 1462 | { |
1463 | if (mode < 4) { | 1463 | if (mode < 4) { |
1464 | int playback_active, capture_active, codec_active, pop_wait; | 1464 | int playback_active, capture_active, codec_active, pop_wait; |
1465 | void *private_data; | 1465 | void *private_data; |
1466 | 1466 | ||
1467 | playback_active = wm8753_dai[0].playback.active; | 1467 | playback_active = wm8753_dai[0].playback.active; |
1468 | capture_active = wm8753_dai[0].capture.active; | 1468 | capture_active = wm8753_dai[0].capture.active; |
1469 | codec_active = wm8753_dai[0].active; | 1469 | codec_active = wm8753_dai[0].active; |
1470 | private_data = wm8753_dai[0].private_data; | 1470 | private_data = wm8753_dai[0].private_data; |
1471 | pop_wait = wm8753_dai[0].pop_wait; | 1471 | pop_wait = wm8753_dai[0].pop_wait; |
1472 | wm8753_dai[0] = wm8753_all_dai[mode << 1]; | 1472 | wm8753_dai[0] = wm8753_all_dai[mode << 1]; |
1473 | wm8753_dai[0].playback.active = playback_active; | 1473 | wm8753_dai[0].playback.active = playback_active; |
1474 | wm8753_dai[0].capture.active = capture_active; | 1474 | wm8753_dai[0].capture.active = capture_active; |
1475 | wm8753_dai[0].active = codec_active; | 1475 | wm8753_dai[0].active = codec_active; |
1476 | wm8753_dai[0].private_data = private_data; | 1476 | wm8753_dai[0].private_data = private_data; |
1477 | wm8753_dai[0].pop_wait = pop_wait; | 1477 | wm8753_dai[0].pop_wait = pop_wait; |
1478 | 1478 | ||
1479 | playback_active = wm8753_dai[1].playback.active; | 1479 | playback_active = wm8753_dai[1].playback.active; |
1480 | capture_active = wm8753_dai[1].capture.active; | 1480 | capture_active = wm8753_dai[1].capture.active; |
1481 | codec_active = wm8753_dai[1].active; | 1481 | codec_active = wm8753_dai[1].active; |
1482 | private_data = wm8753_dai[1].private_data; | 1482 | private_data = wm8753_dai[1].private_data; |
1483 | pop_wait = wm8753_dai[1].pop_wait; | 1483 | pop_wait = wm8753_dai[1].pop_wait; |
1484 | wm8753_dai[1] = wm8753_all_dai[(mode << 1) + 1]; | 1484 | wm8753_dai[1] = wm8753_all_dai[(mode << 1) + 1]; |
1485 | wm8753_dai[1].playback.active = playback_active; | 1485 | wm8753_dai[1].playback.active = playback_active; |
1486 | wm8753_dai[1].capture.active = capture_active; | 1486 | wm8753_dai[1].capture.active = capture_active; |
1487 | wm8753_dai[1].active = codec_active; | 1487 | wm8753_dai[1].active = codec_active; |
1488 | wm8753_dai[1].private_data = private_data; | 1488 | wm8753_dai[1].private_data = private_data; |
1489 | wm8753_dai[1].pop_wait = pop_wait; | 1489 | wm8753_dai[1].pop_wait = pop_wait; |
1490 | } | 1490 | } |
1491 | wm8753_dai[0].codec = codec; | 1491 | wm8753_dai[0].codec = codec; |
1492 | wm8753_dai[1].codec = codec; | 1492 | wm8753_dai[1].codec = codec; |
1493 | } | 1493 | } |
1494 | 1494 | ||
1495 | static void wm8753_work(struct work_struct *work) | 1495 | static void wm8753_work(struct work_struct *work) |
1496 | { | 1496 | { |
1497 | struct snd_soc_codec *codec = | 1497 | struct snd_soc_codec *codec = |
1498 | container_of(work, struct snd_soc_codec, delayed_work.work); | 1498 | container_of(work, struct snd_soc_codec, delayed_work.work); |
1499 | wm8753_set_bias_level(codec, codec->bias_level); | 1499 | wm8753_set_bias_level(codec, codec->bias_level); |
1500 | } | 1500 | } |
1501 | 1501 | ||
1502 | static int wm8753_suspend(struct platform_device *pdev, pm_message_t state) | 1502 | static int wm8753_suspend(struct platform_device *pdev, pm_message_t state) |
1503 | { | 1503 | { |
1504 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1504 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1505 | struct snd_soc_codec *codec = socdev->codec; | 1505 | struct snd_soc_codec *codec = socdev->codec; |
1506 | 1506 | ||
1507 | /* we only need to suspend if we are a valid card */ | 1507 | /* we only need to suspend if we are a valid card */ |
1508 | if (!codec->card) | 1508 | if (!codec->card) |
1509 | return 0; | 1509 | return 0; |
1510 | 1510 | ||
1511 | wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1511 | wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1512 | return 0; | 1512 | return 0; |
1513 | } | 1513 | } |
1514 | 1514 | ||
1515 | static int wm8753_resume(struct platform_device *pdev) | 1515 | static int wm8753_resume(struct platform_device *pdev) |
1516 | { | 1516 | { |
1517 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1517 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1518 | struct snd_soc_codec *codec = socdev->codec; | 1518 | struct snd_soc_codec *codec = socdev->codec; |
1519 | int i; | 1519 | int i; |
1520 | u8 data[2]; | 1520 | u8 data[2]; |
1521 | u16 *cache = codec->reg_cache; | 1521 | u16 *cache = codec->reg_cache; |
1522 | 1522 | ||
1523 | /* we only need to resume if we are a valid card */ | 1523 | /* we only need to resume if we are a valid card */ |
1524 | if (!codec->card) | 1524 | if (!codec->card) |
1525 | return 0; | 1525 | return 0; |
1526 | 1526 | ||
1527 | /* Sync reg_cache with the hardware */ | 1527 | /* Sync reg_cache with the hardware */ |
1528 | for (i = 0; i < ARRAY_SIZE(wm8753_reg); i++) { | 1528 | for (i = 0; i < ARRAY_SIZE(wm8753_reg); i++) { |
1529 | if (i + 1 == WM8753_RESET) | 1529 | if (i + 1 == WM8753_RESET) |
1530 | continue; | 1530 | continue; |
1531 | data[0] = ((i + 1) << 1) | ((cache[i] >> 8) & 0x0001); | 1531 | data[0] = ((i + 1) << 1) | ((cache[i] >> 8) & 0x0001); |
1532 | data[1] = cache[i] & 0x00ff; | 1532 | data[1] = cache[i] & 0x00ff; |
1533 | codec->hw_write(codec->control_data, data, 2); | 1533 | codec->hw_write(codec->control_data, data, 2); |
1534 | } | 1534 | } |
1535 | 1535 | ||
1536 | wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1536 | wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1537 | 1537 | ||
1538 | /* charge wm8753 caps */ | 1538 | /* charge wm8753 caps */ |
1539 | if (codec->suspend_bias_level == SND_SOC_BIAS_ON) { | 1539 | if (codec->suspend_bias_level == SND_SOC_BIAS_ON) { |
1540 | wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE); | 1540 | wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE); |
1541 | codec->bias_level = SND_SOC_BIAS_ON; | 1541 | codec->bias_level = SND_SOC_BIAS_ON; |
1542 | schedule_delayed_work(&codec->delayed_work, | 1542 | schedule_delayed_work(&codec->delayed_work, |
1543 | msecs_to_jiffies(caps_charge)); | 1543 | msecs_to_jiffies(caps_charge)); |
1544 | } | 1544 | } |
1545 | 1545 | ||
1546 | return 0; | 1546 | return 0; |
1547 | } | 1547 | } |
1548 | 1548 | ||
1549 | /* | 1549 | /* |
1550 | * initialise the WM8753 driver | 1550 | * initialise the WM8753 driver |
1551 | * register the mixer and dsp interfaces with the kernel | 1551 | * register the mixer and dsp interfaces with the kernel |
1552 | */ | 1552 | */ |
1553 | static int wm8753_init(struct snd_soc_device *socdev) | 1553 | static int wm8753_init(struct snd_soc_device *socdev) |
1554 | { | 1554 | { |
1555 | struct snd_soc_codec *codec = socdev->codec; | 1555 | struct snd_soc_codec *codec = socdev->codec; |
1556 | int reg, ret = 0; | 1556 | int reg, ret = 0; |
1557 | 1557 | ||
1558 | codec->name = "WM8753"; | 1558 | codec->name = "WM8753"; |
1559 | codec->owner = THIS_MODULE; | 1559 | codec->owner = THIS_MODULE; |
1560 | codec->read = wm8753_read_reg_cache; | 1560 | codec->read = wm8753_read_reg_cache; |
1561 | codec->write = wm8753_write; | 1561 | codec->write = wm8753_write; |
1562 | codec->set_bias_level = wm8753_set_bias_level; | 1562 | codec->set_bias_level = wm8753_set_bias_level; |
1563 | codec->dai = wm8753_dai; | 1563 | codec->dai = wm8753_dai; |
1564 | codec->num_dai = 2; | 1564 | codec->num_dai = 2; |
1565 | codec->reg_cache_size = ARRAY_SIZE(wm8753_reg); | 1565 | codec->reg_cache_size = ARRAY_SIZE(wm8753_reg); |
1566 | codec->reg_cache = kmemdup(wm8753_reg, sizeof(wm8753_reg), GFP_KERNEL); | 1566 | codec->reg_cache = kmemdup(wm8753_reg, sizeof(wm8753_reg), GFP_KERNEL); |
1567 | 1567 | ||
1568 | if (codec->reg_cache == NULL) | 1568 | if (codec->reg_cache == NULL) |
1569 | return -ENOMEM; | 1569 | return -ENOMEM; |
1570 | 1570 | ||
1571 | wm8753_set_dai_mode(codec, 0); | 1571 | wm8753_set_dai_mode(codec, 0); |
1572 | 1572 | ||
1573 | wm8753_reset(codec); | 1573 | wm8753_reset(codec); |
1574 | 1574 | ||
1575 | /* register pcms */ | 1575 | /* register pcms */ |
1576 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 1576 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
1577 | if (ret < 0) { | 1577 | if (ret < 0) { |
1578 | printk(KERN_ERR "wm8753: failed to create pcms\n"); | 1578 | printk(KERN_ERR "wm8753: failed to create pcms\n"); |
1579 | goto pcm_err; | 1579 | goto pcm_err; |
1580 | } | 1580 | } |
1581 | 1581 | ||
1582 | /* charge output caps */ | 1582 | /* charge output caps */ |
1583 | wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE); | 1583 | wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE); |
1584 | codec->bias_level = SND_SOC_BIAS_STANDBY; | 1584 | codec->bias_level = SND_SOC_BIAS_STANDBY; |
1585 | schedule_delayed_work(&codec->delayed_work, | 1585 | schedule_delayed_work(&codec->delayed_work, |
1586 | msecs_to_jiffies(caps_charge)); | 1586 | msecs_to_jiffies(caps_charge)); |
1587 | 1587 | ||
1588 | /* set the update bits */ | 1588 | /* set the update bits */ |
1589 | reg = wm8753_read_reg_cache(codec, WM8753_LDAC); | 1589 | reg = wm8753_read_reg_cache(codec, WM8753_LDAC); |
1590 | wm8753_write(codec, WM8753_LDAC, reg | 0x0100); | 1590 | wm8753_write(codec, WM8753_LDAC, reg | 0x0100); |
1591 | reg = wm8753_read_reg_cache(codec, WM8753_RDAC); | 1591 | reg = wm8753_read_reg_cache(codec, WM8753_RDAC); |
1592 | wm8753_write(codec, WM8753_RDAC, reg | 0x0100); | 1592 | wm8753_write(codec, WM8753_RDAC, reg | 0x0100); |
1593 | reg = wm8753_read_reg_cache(codec, WM8753_LADC); | 1593 | reg = wm8753_read_reg_cache(codec, WM8753_LADC); |
1594 | wm8753_write(codec, WM8753_LADC, reg | 0x0100); | 1594 | wm8753_write(codec, WM8753_LADC, reg | 0x0100); |
1595 | reg = wm8753_read_reg_cache(codec, WM8753_RADC); | 1595 | reg = wm8753_read_reg_cache(codec, WM8753_RADC); |
1596 | wm8753_write(codec, WM8753_RADC, reg | 0x0100); | 1596 | wm8753_write(codec, WM8753_RADC, reg | 0x0100); |
1597 | reg = wm8753_read_reg_cache(codec, WM8753_LOUT1V); | 1597 | reg = wm8753_read_reg_cache(codec, WM8753_LOUT1V); |
1598 | wm8753_write(codec, WM8753_LOUT1V, reg | 0x0100); | 1598 | wm8753_write(codec, WM8753_LOUT1V, reg | 0x0100); |
1599 | reg = wm8753_read_reg_cache(codec, WM8753_ROUT1V); | 1599 | reg = wm8753_read_reg_cache(codec, WM8753_ROUT1V); |
1600 | wm8753_write(codec, WM8753_ROUT1V, reg | 0x0100); | 1600 | wm8753_write(codec, WM8753_ROUT1V, reg | 0x0100); |
1601 | reg = wm8753_read_reg_cache(codec, WM8753_LOUT2V); | 1601 | reg = wm8753_read_reg_cache(codec, WM8753_LOUT2V); |
1602 | wm8753_write(codec, WM8753_LOUT2V, reg | 0x0100); | 1602 | wm8753_write(codec, WM8753_LOUT2V, reg | 0x0100); |
1603 | reg = wm8753_read_reg_cache(codec, WM8753_ROUT2V); | 1603 | reg = wm8753_read_reg_cache(codec, WM8753_ROUT2V); |
1604 | wm8753_write(codec, WM8753_ROUT2V, reg | 0x0100); | 1604 | wm8753_write(codec, WM8753_ROUT2V, reg | 0x0100); |
1605 | reg = wm8753_read_reg_cache(codec, WM8753_LINVOL); | 1605 | reg = wm8753_read_reg_cache(codec, WM8753_LINVOL); |
1606 | wm8753_write(codec, WM8753_LINVOL, reg | 0x0100); | 1606 | wm8753_write(codec, WM8753_LINVOL, reg | 0x0100); |
1607 | reg = wm8753_read_reg_cache(codec, WM8753_RINVOL); | 1607 | reg = wm8753_read_reg_cache(codec, WM8753_RINVOL); |
1608 | wm8753_write(codec, WM8753_RINVOL, reg | 0x0100); | 1608 | wm8753_write(codec, WM8753_RINVOL, reg | 0x0100); |
1609 | 1609 | ||
1610 | wm8753_add_controls(codec); | 1610 | wm8753_add_controls(codec); |
1611 | wm8753_add_widgets(codec); | 1611 | wm8753_add_widgets(codec); |
1612 | ret = snd_soc_register_card(socdev); | 1612 | ret = snd_soc_register_card(socdev); |
1613 | if (ret < 0) { | 1613 | if (ret < 0) { |
1614 | printk(KERN_ERR "wm8753: failed to register card\n"); | 1614 | printk(KERN_ERR "wm8753: failed to register card\n"); |
1615 | goto card_err; | 1615 | goto card_err; |
1616 | } | 1616 | } |
1617 | 1617 | ||
1618 | return ret; | 1618 | return ret; |
1619 | 1619 | ||
1620 | card_err: | 1620 | card_err: |
1621 | snd_soc_free_pcms(socdev); | 1621 | snd_soc_free_pcms(socdev); |
1622 | snd_soc_dapm_free(socdev); | 1622 | snd_soc_dapm_free(socdev); |
1623 | pcm_err: | 1623 | pcm_err: |
1624 | kfree(codec->reg_cache); | 1624 | kfree(codec->reg_cache); |
1625 | return ret; | 1625 | return ret; |
1626 | } | 1626 | } |
1627 | 1627 | ||
1628 | /* If the i2c layer weren't so broken, we could pass this kind of data | 1628 | /* If the i2c layer weren't so broken, we could pass this kind of data |
1629 | around */ | 1629 | around */ |
1630 | static struct snd_soc_device *wm8753_socdev; | 1630 | static struct snd_soc_device *wm8753_socdev; |
1631 | 1631 | ||
1632 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1632 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1633 | 1633 | ||
1634 | /* | 1634 | /* |
1635 | * WM8753 2 wire address is determined by GPIO5 | 1635 | * WM8753 2 wire address is determined by GPIO5 |
1636 | * state during powerup. | 1636 | * state during powerup. |
1637 | * low = 0x1a | 1637 | * low = 0x1a |
1638 | * high = 0x1b | 1638 | * high = 0x1b |
1639 | */ | 1639 | */ |
1640 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | 1640 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; |
1641 | 1641 | ||
1642 | /* Magic definition of all other variables and things */ | 1642 | /* Magic definition of all other variables and things */ |
1643 | I2C_CLIENT_INSMOD; | 1643 | I2C_CLIENT_INSMOD; |
1644 | 1644 | ||
1645 | static struct i2c_driver wm8753_i2c_driver; | 1645 | static struct i2c_driver wm8753_i2c_driver; |
1646 | static struct i2c_client client_template; | 1646 | static struct i2c_client client_template; |
1647 | 1647 | ||
1648 | static int wm8753_codec_probe(struct i2c_adapter *adap, int addr, int kind) | 1648 | static int wm8753_codec_probe(struct i2c_adapter *adap, int addr, int kind) |
1649 | { | 1649 | { |
1650 | struct snd_soc_device *socdev = wm8753_socdev; | 1650 | struct snd_soc_device *socdev = wm8753_socdev; |
1651 | struct wm8753_setup_data *setup = socdev->codec_data; | 1651 | struct wm8753_setup_data *setup = socdev->codec_data; |
1652 | struct snd_soc_codec *codec = socdev->codec; | 1652 | struct snd_soc_codec *codec = socdev->codec; |
1653 | struct i2c_client *i2c; | 1653 | struct i2c_client *i2c; |
1654 | int ret; | 1654 | int ret; |
1655 | 1655 | ||
1656 | if (addr != setup->i2c_address) | 1656 | if (addr != setup->i2c_address) |
1657 | return -ENODEV; | 1657 | return -ENODEV; |
1658 | 1658 | ||
1659 | client_template.adapter = adap; | 1659 | client_template.adapter = adap; |
1660 | client_template.addr = addr; | 1660 | client_template.addr = addr; |
1661 | 1661 | ||
1662 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | 1662 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); |
1663 | if (!i2c) { | 1663 | if (!i2c) |
1664 | kfree(codec); | ||
1665 | return -ENOMEM; | 1664 | return -ENOMEM; |
1666 | } | 1665 | |
1667 | i2c_set_clientdata(i2c, codec); | 1666 | i2c_set_clientdata(i2c, codec); |
1668 | codec->control_data = i2c; | 1667 | codec->control_data = i2c; |
1669 | 1668 | ||
1670 | ret = i2c_attach_client(i2c); | 1669 | ret = i2c_attach_client(i2c); |
1671 | if (ret < 0) { | 1670 | if (ret < 0) { |
1672 | pr_err("failed to attach codec at addr %x\n", addr); | 1671 | pr_err("failed to attach codec at addr %x\n", addr); |
1673 | goto err; | 1672 | goto err; |
1674 | } | 1673 | } |
1675 | 1674 | ||
1676 | ret = wm8753_init(socdev); | 1675 | ret = wm8753_init(socdev); |
1677 | if (ret < 0) { | 1676 | if (ret < 0) { |
1678 | pr_err("failed to initialise WM8753\n"); | 1677 | pr_err("failed to initialise WM8753\n"); |
1679 | goto err; | 1678 | goto err; |
1680 | } | 1679 | } |
1681 | 1680 | ||
1682 | return ret; | 1681 | return ret; |
1683 | 1682 | ||
1684 | err: | 1683 | err: |
1685 | kfree(codec); | ||
1686 | kfree(i2c); | 1684 | kfree(i2c); |
1687 | return ret; | 1685 | return ret; |
1688 | } | 1686 | } |
1689 | 1687 | ||
1690 | static int wm8753_i2c_detach(struct i2c_client *client) | 1688 | static int wm8753_i2c_detach(struct i2c_client *client) |
1691 | { | 1689 | { |
1692 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 1690 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
1693 | i2c_detach_client(client); | 1691 | i2c_detach_client(client); |
1694 | kfree(codec->reg_cache); | 1692 | kfree(codec->reg_cache); |
1695 | kfree(client); | 1693 | kfree(client); |
1696 | return 0; | 1694 | return 0; |
1697 | } | 1695 | } |
1698 | 1696 | ||
1699 | static int wm8753_i2c_attach(struct i2c_adapter *adap) | 1697 | static int wm8753_i2c_attach(struct i2c_adapter *adap) |
1700 | { | 1698 | { |
1701 | return i2c_probe(adap, &addr_data, wm8753_codec_probe); | 1699 | return i2c_probe(adap, &addr_data, wm8753_codec_probe); |
1702 | } | 1700 | } |
1703 | 1701 | ||
1704 | /* corgi i2c codec control layer */ | 1702 | /* corgi i2c codec control layer */ |
1705 | static struct i2c_driver wm8753_i2c_driver = { | 1703 | static struct i2c_driver wm8753_i2c_driver = { |
1706 | .driver = { | 1704 | .driver = { |
1707 | .name = "WM8753 I2C Codec", | 1705 | .name = "WM8753 I2C Codec", |
1708 | .owner = THIS_MODULE, | 1706 | .owner = THIS_MODULE, |
1709 | }, | 1707 | }, |
1710 | .id = I2C_DRIVERID_WM8753, | 1708 | .id = I2C_DRIVERID_WM8753, |
1711 | .attach_adapter = wm8753_i2c_attach, | 1709 | .attach_adapter = wm8753_i2c_attach, |
1712 | .detach_client = wm8753_i2c_detach, | 1710 | .detach_client = wm8753_i2c_detach, |
1713 | .command = NULL, | 1711 | .command = NULL, |
1714 | }; | 1712 | }; |
1715 | 1713 | ||
1716 | static struct i2c_client client_template = { | 1714 | static struct i2c_client client_template = { |
1717 | .name = "WM8753", | 1715 | .name = "WM8753", |
1718 | .driver = &wm8753_i2c_driver, | 1716 | .driver = &wm8753_i2c_driver, |
1719 | }; | 1717 | }; |
1720 | #endif | 1718 | #endif |
1721 | 1719 | ||
1722 | static int wm8753_probe(struct platform_device *pdev) | 1720 | static int wm8753_probe(struct platform_device *pdev) |
1723 | { | 1721 | { |
1724 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1722 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1725 | struct wm8753_setup_data *setup; | 1723 | struct wm8753_setup_data *setup; |
1726 | struct snd_soc_codec *codec; | 1724 | struct snd_soc_codec *codec; |
1727 | struct wm8753_priv *wm8753; | 1725 | struct wm8753_priv *wm8753; |
1728 | int ret = 0; | 1726 | int ret = 0; |
1729 | 1727 | ||
1730 | pr_info("WM8753 Audio Codec %s", WM8753_VERSION); | 1728 | pr_info("WM8753 Audio Codec %s", WM8753_VERSION); |
1731 | 1729 | ||
1732 | setup = socdev->codec_data; | 1730 | setup = socdev->codec_data; |
1733 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 1731 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); |
1734 | if (codec == NULL) | 1732 | if (codec == NULL) |
1735 | return -ENOMEM; | 1733 | return -ENOMEM; |
1736 | 1734 | ||
1737 | wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL); | 1735 | wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL); |
1738 | if (wm8753 == NULL) { | 1736 | if (wm8753 == NULL) { |
1739 | kfree(codec); | 1737 | kfree(codec); |
1740 | return -ENOMEM; | 1738 | return -ENOMEM; |
1741 | } | 1739 | } |
1742 | 1740 | ||
1743 | codec->private_data = wm8753; | 1741 | codec->private_data = wm8753; |
1744 | socdev->codec = codec; | 1742 | socdev->codec = codec; |
1745 | mutex_init(&codec->mutex); | 1743 | mutex_init(&codec->mutex); |
1746 | INIT_LIST_HEAD(&codec->dapm_widgets); | 1744 | INIT_LIST_HEAD(&codec->dapm_widgets); |
1747 | INIT_LIST_HEAD(&codec->dapm_paths); | 1745 | INIT_LIST_HEAD(&codec->dapm_paths); |
1748 | wm8753_socdev = socdev; | 1746 | wm8753_socdev = socdev; |
1749 | INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work); | 1747 | INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work); |
1750 | 1748 | ||
1751 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1749 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1752 | if (setup->i2c_address) { | 1750 | if (setup->i2c_address) { |
1753 | normal_i2c[0] = setup->i2c_address; | 1751 | normal_i2c[0] = setup->i2c_address; |
1754 | codec->hw_write = (hw_write_t)i2c_master_send; | 1752 | codec->hw_write = (hw_write_t)i2c_master_send; |
1755 | ret = i2c_add_driver(&wm8753_i2c_driver); | 1753 | ret = i2c_add_driver(&wm8753_i2c_driver); |
1756 | if (ret != 0) | 1754 | if (ret != 0) |
1757 | printk(KERN_ERR "can't add i2c driver"); | 1755 | printk(KERN_ERR "can't add i2c driver"); |
1758 | } | 1756 | } |
1759 | #else | 1757 | #else |
1760 | /* Add other interfaces here */ | 1758 | /* Add other interfaces here */ |
1761 | #endif | 1759 | #endif |
1760 | |||
1761 | if (ret != 0) { | ||
1762 | kfree(codec->private_data); | ||
1763 | kfree(codec); | ||
1764 | } | ||
1762 | return ret; | 1765 | return ret; |
1763 | } | 1766 | } |
1764 | 1767 | ||
1765 | /* | 1768 | /* |
1766 | * This function forces any delayed work to be queued and run. | 1769 | * This function forces any delayed work to be queued and run. |
1767 | */ | 1770 | */ |
1768 | static int run_delayed_work(struct delayed_work *dwork) | 1771 | static int run_delayed_work(struct delayed_work *dwork) |
1769 | { | 1772 | { |
1770 | int ret; | 1773 | int ret; |
1771 | 1774 | ||
1772 | /* cancel any work waiting to be queued. */ | 1775 | /* cancel any work waiting to be queued. */ |
1773 | ret = cancel_delayed_work(dwork); | 1776 | ret = cancel_delayed_work(dwork); |
1774 | 1777 | ||
1775 | /* if there was any work waiting then we run it now and | 1778 | /* if there was any work waiting then we run it now and |
1776 | * wait for it's completion */ | 1779 | * wait for it's completion */ |
1777 | if (ret) { | 1780 | if (ret) { |
1778 | schedule_delayed_work(dwork, 0); | 1781 | schedule_delayed_work(dwork, 0); |
1779 | flush_scheduled_work(); | 1782 | flush_scheduled_work(); |
1780 | } | 1783 | } |
1781 | return ret; | 1784 | return ret; |
1782 | } | 1785 | } |
1783 | 1786 | ||
1784 | /* power down chip */ | 1787 | /* power down chip */ |
1785 | static int wm8753_remove(struct platform_device *pdev) | 1788 | static int wm8753_remove(struct platform_device *pdev) |
1786 | { | 1789 | { |
1787 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1790 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1788 | struct snd_soc_codec *codec = socdev->codec; | 1791 | struct snd_soc_codec *codec = socdev->codec; |
1789 | 1792 | ||
1790 | if (codec->control_data) | 1793 | if (codec->control_data) |
1791 | wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1794 | wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1792 | run_delayed_work(&codec->delayed_work); | 1795 | run_delayed_work(&codec->delayed_work); |
1793 | snd_soc_free_pcms(socdev); | 1796 | snd_soc_free_pcms(socdev); |
1794 | snd_soc_dapm_free(socdev); | 1797 | snd_soc_dapm_free(socdev); |
1795 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1798 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1796 | i2c_del_driver(&wm8753_i2c_driver); | 1799 | i2c_del_driver(&wm8753_i2c_driver); |
1797 | #endif | 1800 | #endif |
1798 | kfree(codec->private_data); | 1801 | kfree(codec->private_data); |
1799 | kfree(codec); | 1802 | kfree(codec); |
1800 | 1803 | ||
1801 | return 0; | 1804 | return 0; |
1802 | } | 1805 | } |
1803 | 1806 | ||
1804 | struct snd_soc_codec_device soc_codec_dev_wm8753 = { | 1807 | struct snd_soc_codec_device soc_codec_dev_wm8753 = { |
1805 | .probe = wm8753_probe, | 1808 | .probe = wm8753_probe, |
1806 | .remove = wm8753_remove, | 1809 | .remove = wm8753_remove, |
1807 | .suspend = wm8753_suspend, | 1810 | .suspend = wm8753_suspend, |
1808 | .resume = wm8753_resume, | 1811 | .resume = wm8753_resume, |
1809 | }; | 1812 | }; |
1810 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8753); | 1813 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8753); |
1811 | 1814 | ||
1812 | MODULE_DESCRIPTION("ASoC WM8753 driver"); | 1815 | MODULE_DESCRIPTION("ASoC WM8753 driver"); |
1813 | MODULE_AUTHOR("Liam Girdwood"); | 1816 | MODULE_AUTHOR("Liam Girdwood"); |
sound/soc/codecs/wm8990.c
1 | /* | 1 | /* |
2 | * wm8990.c -- WM8990 ALSA Soc Audio driver | 2 | * wm8990.c -- WM8990 ALSA Soc Audio driver |
3 | * | 3 | * |
4 | * Copyright 2008 Wolfson Microelectronics PLC. | 4 | * Copyright 2008 Wolfson Microelectronics PLC. |
5 | * Author: Liam Girdwood | 5 | * Author: Liam Girdwood |
6 | * lg@opensource.wolfsonmicro.com or linux@wolfsonmicro.com | 6 | * lg@opensource.wolfsonmicro.com or linux@wolfsonmicro.com |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify it | 8 | * This program is free software; you can redistribute it and/or modify it |
9 | * under the terms of the GNU General Public License as published by the | 9 | * under the terms of the GNU General Public License as published by the |
10 | * Free Software Foundation; either version 2 of the License, or (at your | 10 | * Free Software Foundation; either version 2 of the License, or (at your |
11 | * option) any later version. | 11 | * option) any later version. |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/moduleparam.h> | 15 | #include <linux/moduleparam.h> |
16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
19 | #include <linux/pm.h> | 19 | #include <linux/pm.h> |
20 | #include <linux/i2c.h> | 20 | #include <linux/i2c.h> |
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <sound/core.h> | 22 | #include <sound/core.h> |
23 | #include <sound/pcm.h> | 23 | #include <sound/pcm.h> |
24 | #include <sound/pcm_params.h> | 24 | #include <sound/pcm_params.h> |
25 | #include <sound/soc.h> | 25 | #include <sound/soc.h> |
26 | #include <sound/soc-dapm.h> | 26 | #include <sound/soc-dapm.h> |
27 | #include <sound/initval.h> | 27 | #include <sound/initval.h> |
28 | #include <sound/tlv.h> | 28 | #include <sound/tlv.h> |
29 | #include <asm/div64.h> | 29 | #include <asm/div64.h> |
30 | 30 | ||
31 | #include "wm8990.h" | 31 | #include "wm8990.h" |
32 | 32 | ||
33 | #define AUDIO_NAME "wm8990" | 33 | #define AUDIO_NAME "wm8990" |
34 | #define WM8990_VERSION "0.2" | 34 | #define WM8990_VERSION "0.2" |
35 | 35 | ||
36 | /* codec private data */ | 36 | /* codec private data */ |
37 | struct wm8990_priv { | 37 | struct wm8990_priv { |
38 | unsigned int sysclk; | 38 | unsigned int sysclk; |
39 | unsigned int pcmclk; | 39 | unsigned int pcmclk; |
40 | }; | 40 | }; |
41 | 41 | ||
42 | /* | 42 | /* |
43 | * wm8990 register cache. Note that register 0 is not included in the | 43 | * wm8990 register cache. Note that register 0 is not included in the |
44 | * cache. | 44 | * cache. |
45 | */ | 45 | */ |
46 | static const u16 wm8990_reg[] = { | 46 | static const u16 wm8990_reg[] = { |
47 | 0x8990, /* R0 - Reset */ | 47 | 0x8990, /* R0 - Reset */ |
48 | 0x0000, /* R1 - Power Management (1) */ | 48 | 0x0000, /* R1 - Power Management (1) */ |
49 | 0x6000, /* R2 - Power Management (2) */ | 49 | 0x6000, /* R2 - Power Management (2) */ |
50 | 0x0000, /* R3 - Power Management (3) */ | 50 | 0x0000, /* R3 - Power Management (3) */ |
51 | 0x4050, /* R4 - Audio Interface (1) */ | 51 | 0x4050, /* R4 - Audio Interface (1) */ |
52 | 0x4000, /* R5 - Audio Interface (2) */ | 52 | 0x4000, /* R5 - Audio Interface (2) */ |
53 | 0x01C8, /* R6 - Clocking (1) */ | 53 | 0x01C8, /* R6 - Clocking (1) */ |
54 | 0x0000, /* R7 - Clocking (2) */ | 54 | 0x0000, /* R7 - Clocking (2) */ |
55 | 0x0040, /* R8 - Audio Interface (3) */ | 55 | 0x0040, /* R8 - Audio Interface (3) */ |
56 | 0x0040, /* R9 - Audio Interface (4) */ | 56 | 0x0040, /* R9 - Audio Interface (4) */ |
57 | 0x0004, /* R10 - DAC CTRL */ | 57 | 0x0004, /* R10 - DAC CTRL */ |
58 | 0x00C0, /* R11 - Left DAC Digital Volume */ | 58 | 0x00C0, /* R11 - Left DAC Digital Volume */ |
59 | 0x00C0, /* R12 - Right DAC Digital Volume */ | 59 | 0x00C0, /* R12 - Right DAC Digital Volume */ |
60 | 0x0000, /* R13 - Digital Side Tone */ | 60 | 0x0000, /* R13 - Digital Side Tone */ |
61 | 0x0100, /* R14 - ADC CTRL */ | 61 | 0x0100, /* R14 - ADC CTRL */ |
62 | 0x00C0, /* R15 - Left ADC Digital Volume */ | 62 | 0x00C0, /* R15 - Left ADC Digital Volume */ |
63 | 0x00C0, /* R16 - Right ADC Digital Volume */ | 63 | 0x00C0, /* R16 - Right ADC Digital Volume */ |
64 | 0x0000, /* R17 */ | 64 | 0x0000, /* R17 */ |
65 | 0x0000, /* R18 - GPIO CTRL 1 */ | 65 | 0x0000, /* R18 - GPIO CTRL 1 */ |
66 | 0x1000, /* R19 - GPIO1 & GPIO2 */ | 66 | 0x1000, /* R19 - GPIO1 & GPIO2 */ |
67 | 0x1010, /* R20 - GPIO3 & GPIO4 */ | 67 | 0x1010, /* R20 - GPIO3 & GPIO4 */ |
68 | 0x1010, /* R21 - GPIO5 & GPIO6 */ | 68 | 0x1010, /* R21 - GPIO5 & GPIO6 */ |
69 | 0x8000, /* R22 - GPIOCTRL 2 */ | 69 | 0x8000, /* R22 - GPIOCTRL 2 */ |
70 | 0x0800, /* R23 - GPIO_POL */ | 70 | 0x0800, /* R23 - GPIO_POL */ |
71 | 0x008B, /* R24 - Left Line Input 1&2 Volume */ | 71 | 0x008B, /* R24 - Left Line Input 1&2 Volume */ |
72 | 0x008B, /* R25 - Left Line Input 3&4 Volume */ | 72 | 0x008B, /* R25 - Left Line Input 3&4 Volume */ |
73 | 0x008B, /* R26 - Right Line Input 1&2 Volume */ | 73 | 0x008B, /* R26 - Right Line Input 1&2 Volume */ |
74 | 0x008B, /* R27 - Right Line Input 3&4 Volume */ | 74 | 0x008B, /* R27 - Right Line Input 3&4 Volume */ |
75 | 0x0000, /* R28 - Left Output Volume */ | 75 | 0x0000, /* R28 - Left Output Volume */ |
76 | 0x0000, /* R29 - Right Output Volume */ | 76 | 0x0000, /* R29 - Right Output Volume */ |
77 | 0x0066, /* R30 - Line Outputs Volume */ | 77 | 0x0066, /* R30 - Line Outputs Volume */ |
78 | 0x0022, /* R31 - Out3/4 Volume */ | 78 | 0x0022, /* R31 - Out3/4 Volume */ |
79 | 0x0079, /* R32 - Left OPGA Volume */ | 79 | 0x0079, /* R32 - Left OPGA Volume */ |
80 | 0x0079, /* R33 - Right OPGA Volume */ | 80 | 0x0079, /* R33 - Right OPGA Volume */ |
81 | 0x0003, /* R34 - Speaker Volume */ | 81 | 0x0003, /* R34 - Speaker Volume */ |
82 | 0x0003, /* R35 - ClassD1 */ | 82 | 0x0003, /* R35 - ClassD1 */ |
83 | 0x0000, /* R36 */ | 83 | 0x0000, /* R36 */ |
84 | 0x0100, /* R37 - ClassD3 */ | 84 | 0x0100, /* R37 - ClassD3 */ |
85 | 0x0079, /* R38 - ClassD4 */ | 85 | 0x0079, /* R38 - ClassD4 */ |
86 | 0x0000, /* R39 - Input Mixer1 */ | 86 | 0x0000, /* R39 - Input Mixer1 */ |
87 | 0x0000, /* R40 - Input Mixer2 */ | 87 | 0x0000, /* R40 - Input Mixer2 */ |
88 | 0x0000, /* R41 - Input Mixer3 */ | 88 | 0x0000, /* R41 - Input Mixer3 */ |
89 | 0x0000, /* R42 - Input Mixer4 */ | 89 | 0x0000, /* R42 - Input Mixer4 */ |
90 | 0x0000, /* R43 - Input Mixer5 */ | 90 | 0x0000, /* R43 - Input Mixer5 */ |
91 | 0x0000, /* R44 - Input Mixer6 */ | 91 | 0x0000, /* R44 - Input Mixer6 */ |
92 | 0x0000, /* R45 - Output Mixer1 */ | 92 | 0x0000, /* R45 - Output Mixer1 */ |
93 | 0x0000, /* R46 - Output Mixer2 */ | 93 | 0x0000, /* R46 - Output Mixer2 */ |
94 | 0x0000, /* R47 - Output Mixer3 */ | 94 | 0x0000, /* R47 - Output Mixer3 */ |
95 | 0x0000, /* R48 - Output Mixer4 */ | 95 | 0x0000, /* R48 - Output Mixer4 */ |
96 | 0x0000, /* R49 - Output Mixer5 */ | 96 | 0x0000, /* R49 - Output Mixer5 */ |
97 | 0x0000, /* R50 - Output Mixer6 */ | 97 | 0x0000, /* R50 - Output Mixer6 */ |
98 | 0x0180, /* R51 - Out3/4 Mixer */ | 98 | 0x0180, /* R51 - Out3/4 Mixer */ |
99 | 0x0000, /* R52 - Line Mixer1 */ | 99 | 0x0000, /* R52 - Line Mixer1 */ |
100 | 0x0000, /* R53 - Line Mixer2 */ | 100 | 0x0000, /* R53 - Line Mixer2 */ |
101 | 0x0000, /* R54 - Speaker Mixer */ | 101 | 0x0000, /* R54 - Speaker Mixer */ |
102 | 0x0000, /* R55 - Additional Control */ | 102 | 0x0000, /* R55 - Additional Control */ |
103 | 0x0000, /* R56 - AntiPOP1 */ | 103 | 0x0000, /* R56 - AntiPOP1 */ |
104 | 0x0000, /* R57 - AntiPOP2 */ | 104 | 0x0000, /* R57 - AntiPOP2 */ |
105 | 0x0000, /* R58 - MICBIAS */ | 105 | 0x0000, /* R58 - MICBIAS */ |
106 | 0x0000, /* R59 */ | 106 | 0x0000, /* R59 */ |
107 | 0x0008, /* R60 - PLL1 */ | 107 | 0x0008, /* R60 - PLL1 */ |
108 | 0x0031, /* R61 - PLL2 */ | 108 | 0x0031, /* R61 - PLL2 */ |
109 | 0x0026, /* R62 - PLL3 */ | 109 | 0x0026, /* R62 - PLL3 */ |
110 | }; | 110 | }; |
111 | 111 | ||
112 | /* | 112 | /* |
113 | * read wm8990 register cache | 113 | * read wm8990 register cache |
114 | */ | 114 | */ |
115 | static inline unsigned int wm8990_read_reg_cache(struct snd_soc_codec *codec, | 115 | static inline unsigned int wm8990_read_reg_cache(struct snd_soc_codec *codec, |
116 | unsigned int reg) | 116 | unsigned int reg) |
117 | { | 117 | { |
118 | u16 *cache = codec->reg_cache; | 118 | u16 *cache = codec->reg_cache; |
119 | BUG_ON(reg > (ARRAY_SIZE(wm8990_reg)) - 1); | 119 | BUG_ON(reg > (ARRAY_SIZE(wm8990_reg)) - 1); |
120 | return cache[reg]; | 120 | return cache[reg]; |
121 | } | 121 | } |
122 | 122 | ||
123 | /* | 123 | /* |
124 | * write wm8990 register cache | 124 | * write wm8990 register cache |
125 | */ | 125 | */ |
126 | static inline void wm8990_write_reg_cache(struct snd_soc_codec *codec, | 126 | static inline void wm8990_write_reg_cache(struct snd_soc_codec *codec, |
127 | unsigned int reg, unsigned int value) | 127 | unsigned int reg, unsigned int value) |
128 | { | 128 | { |
129 | u16 *cache = codec->reg_cache; | 129 | u16 *cache = codec->reg_cache; |
130 | BUG_ON(reg > (ARRAY_SIZE(wm8990_reg)) - 1); | 130 | BUG_ON(reg > (ARRAY_SIZE(wm8990_reg)) - 1); |
131 | 131 | ||
132 | /* Reset register is uncached */ | 132 | /* Reset register is uncached */ |
133 | if (reg == 0) | 133 | if (reg == 0) |
134 | return; | 134 | return; |
135 | 135 | ||
136 | cache[reg] = value; | 136 | cache[reg] = value; |
137 | } | 137 | } |
138 | 138 | ||
139 | /* | 139 | /* |
140 | * write to the wm8990 register space | 140 | * write to the wm8990 register space |
141 | */ | 141 | */ |
142 | static int wm8990_write(struct snd_soc_codec *codec, unsigned int reg, | 142 | static int wm8990_write(struct snd_soc_codec *codec, unsigned int reg, |
143 | unsigned int value) | 143 | unsigned int value) |
144 | { | 144 | { |
145 | u8 data[3]; | 145 | u8 data[3]; |
146 | 146 | ||
147 | data[0] = reg & 0xFF; | 147 | data[0] = reg & 0xFF; |
148 | data[1] = (value >> 8) & 0xFF; | 148 | data[1] = (value >> 8) & 0xFF; |
149 | data[2] = value & 0xFF; | 149 | data[2] = value & 0xFF; |
150 | 150 | ||
151 | wm8990_write_reg_cache(codec, reg, value); | 151 | wm8990_write_reg_cache(codec, reg, value); |
152 | 152 | ||
153 | if (codec->hw_write(codec->control_data, data, 3) == 2) | 153 | if (codec->hw_write(codec->control_data, data, 3) == 2) |
154 | return 0; | 154 | return 0; |
155 | else | 155 | else |
156 | return -EIO; | 156 | return -EIO; |
157 | } | 157 | } |
158 | 158 | ||
159 | #define wm8990_reset(c) wm8990_write(c, WM8990_RESET, 0) | 159 | #define wm8990_reset(c) wm8990_write(c, WM8990_RESET, 0) |
160 | 160 | ||
161 | static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600); | 161 | static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600); |
162 | 162 | ||
163 | static const DECLARE_TLV_DB_LINEAR(in_pga_tlv, -1650, 3000); | 163 | static const DECLARE_TLV_DB_LINEAR(in_pga_tlv, -1650, 3000); |
164 | 164 | ||
165 | static const DECLARE_TLV_DB_LINEAR(out_mix_tlv, 0, -2100); | 165 | static const DECLARE_TLV_DB_LINEAR(out_mix_tlv, 0, -2100); |
166 | 166 | ||
167 | static const DECLARE_TLV_DB_LINEAR(out_pga_tlv, -7300, 600); | 167 | static const DECLARE_TLV_DB_LINEAR(out_pga_tlv, -7300, 600); |
168 | 168 | ||
169 | static const DECLARE_TLV_DB_LINEAR(out_omix_tlv, -600, 0); | 169 | static const DECLARE_TLV_DB_LINEAR(out_omix_tlv, -600, 0); |
170 | 170 | ||
171 | static const DECLARE_TLV_DB_LINEAR(out_dac_tlv, -7163, 0); | 171 | static const DECLARE_TLV_DB_LINEAR(out_dac_tlv, -7163, 0); |
172 | 172 | ||
173 | static const DECLARE_TLV_DB_LINEAR(in_adc_tlv, -7163, 1763); | 173 | static const DECLARE_TLV_DB_LINEAR(in_adc_tlv, -7163, 1763); |
174 | 174 | ||
175 | static const DECLARE_TLV_DB_LINEAR(out_sidetone_tlv, -3600, 0); | 175 | static const DECLARE_TLV_DB_LINEAR(out_sidetone_tlv, -3600, 0); |
176 | 176 | ||
177 | static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, | 177 | static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, |
178 | struct snd_ctl_elem_value *ucontrol) | 178 | struct snd_ctl_elem_value *ucontrol) |
179 | { | 179 | { |
180 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 180 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
181 | int reg = kcontrol->private_value & 0xff; | 181 | int reg = kcontrol->private_value & 0xff; |
182 | int ret; | 182 | int ret; |
183 | u16 val; | 183 | u16 val; |
184 | 184 | ||
185 | ret = snd_soc_put_volsw(kcontrol, ucontrol); | 185 | ret = snd_soc_put_volsw(kcontrol, ucontrol); |
186 | if (ret < 0) | 186 | if (ret < 0) |
187 | return ret; | 187 | return ret; |
188 | 188 | ||
189 | /* now hit the volume update bits (always bit 8) */ | 189 | /* now hit the volume update bits (always bit 8) */ |
190 | val = wm8990_read_reg_cache(codec, reg); | 190 | val = wm8990_read_reg_cache(codec, reg); |
191 | return wm8990_write(codec, reg, val | 0x0100); | 191 | return wm8990_write(codec, reg, val | 0x0100); |
192 | } | 192 | } |
193 | 193 | ||
194 | #define SOC_WM899X_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert,\ | 194 | #define SOC_WM899X_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert,\ |
195 | tlv_array) {\ | 195 | tlv_array) {\ |
196 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | 196 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ |
197 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | 197 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ |
198 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ | 198 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ |
199 | .tlv.p = (tlv_array), \ | 199 | .tlv.p = (tlv_array), \ |
200 | .info = snd_soc_info_volsw, \ | 200 | .info = snd_soc_info_volsw, \ |
201 | .get = snd_soc_get_volsw, .put = wm899x_outpga_put_volsw_vu, \ | 201 | .get = snd_soc_get_volsw, .put = wm899x_outpga_put_volsw_vu, \ |
202 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } | 202 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } |
203 | 203 | ||
204 | 204 | ||
205 | static const char *wm8990_digital_sidetone[] = | 205 | static const char *wm8990_digital_sidetone[] = |
206 | {"None", "Left ADC", "Right ADC", "Reserved"}; | 206 | {"None", "Left ADC", "Right ADC", "Reserved"}; |
207 | 207 | ||
208 | static const struct soc_enum wm8990_left_digital_sidetone_enum = | 208 | static const struct soc_enum wm8990_left_digital_sidetone_enum = |
209 | SOC_ENUM_SINGLE(WM8990_DIGITAL_SIDE_TONE, | 209 | SOC_ENUM_SINGLE(WM8990_DIGITAL_SIDE_TONE, |
210 | WM8990_ADC_TO_DACL_SHIFT, | 210 | WM8990_ADC_TO_DACL_SHIFT, |
211 | WM8990_ADC_TO_DACL_MASK, | 211 | WM8990_ADC_TO_DACL_MASK, |
212 | wm8990_digital_sidetone); | 212 | wm8990_digital_sidetone); |
213 | 213 | ||
214 | static const struct soc_enum wm8990_right_digital_sidetone_enum = | 214 | static const struct soc_enum wm8990_right_digital_sidetone_enum = |
215 | SOC_ENUM_SINGLE(WM8990_DIGITAL_SIDE_TONE, | 215 | SOC_ENUM_SINGLE(WM8990_DIGITAL_SIDE_TONE, |
216 | WM8990_ADC_TO_DACR_SHIFT, | 216 | WM8990_ADC_TO_DACR_SHIFT, |
217 | WM8990_ADC_TO_DACR_MASK, | 217 | WM8990_ADC_TO_DACR_MASK, |
218 | wm8990_digital_sidetone); | 218 | wm8990_digital_sidetone); |
219 | 219 | ||
220 | static const char *wm8990_adcmode[] = | 220 | static const char *wm8990_adcmode[] = |
221 | {"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"}; | 221 | {"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"}; |
222 | 222 | ||
223 | static const struct soc_enum wm8990_right_adcmode_enum = | 223 | static const struct soc_enum wm8990_right_adcmode_enum = |
224 | SOC_ENUM_SINGLE(WM8990_ADC_CTRL, | 224 | SOC_ENUM_SINGLE(WM8990_ADC_CTRL, |
225 | WM8990_ADC_HPF_CUT_SHIFT, | 225 | WM8990_ADC_HPF_CUT_SHIFT, |
226 | WM8990_ADC_HPF_CUT_MASK, | 226 | WM8990_ADC_HPF_CUT_MASK, |
227 | wm8990_adcmode); | 227 | wm8990_adcmode); |
228 | 228 | ||
229 | static const struct snd_kcontrol_new wm8990_snd_controls[] = { | 229 | static const struct snd_kcontrol_new wm8990_snd_controls[] = { |
230 | /* INMIXL */ | 230 | /* INMIXL */ |
231 | SOC_SINGLE("LIN12 PGA Boost", WM8990_INPUT_MIXER3, WM8990_L12MNBST_BIT, 1, 0), | 231 | SOC_SINGLE("LIN12 PGA Boost", WM8990_INPUT_MIXER3, WM8990_L12MNBST_BIT, 1, 0), |
232 | SOC_SINGLE("LIN34 PGA Boost", WM8990_INPUT_MIXER3, WM8990_L34MNBST_BIT, 1, 0), | 232 | SOC_SINGLE("LIN34 PGA Boost", WM8990_INPUT_MIXER3, WM8990_L34MNBST_BIT, 1, 0), |
233 | /* INMIXR */ | 233 | /* INMIXR */ |
234 | SOC_SINGLE("RIN12 PGA Boost", WM8990_INPUT_MIXER3, WM8990_R12MNBST_BIT, 1, 0), | 234 | SOC_SINGLE("RIN12 PGA Boost", WM8990_INPUT_MIXER3, WM8990_R12MNBST_BIT, 1, 0), |
235 | SOC_SINGLE("RIN34 PGA Boost", WM8990_INPUT_MIXER3, WM8990_R34MNBST_BIT, 1, 0), | 235 | SOC_SINGLE("RIN34 PGA Boost", WM8990_INPUT_MIXER3, WM8990_R34MNBST_BIT, 1, 0), |
236 | 236 | ||
237 | /* LOMIX */ | 237 | /* LOMIX */ |
238 | SOC_SINGLE_TLV("LOMIX LIN3 Bypass Volume", WM8990_OUTPUT_MIXER3, | 238 | SOC_SINGLE_TLV("LOMIX LIN3 Bypass Volume", WM8990_OUTPUT_MIXER3, |
239 | WM8990_LLI3LOVOL_SHIFT, WM8990_LLI3LOVOL_MASK, 1, out_mix_tlv), | 239 | WM8990_LLI3LOVOL_SHIFT, WM8990_LLI3LOVOL_MASK, 1, out_mix_tlv), |
240 | SOC_SINGLE_TLV("LOMIX RIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER3, | 240 | SOC_SINGLE_TLV("LOMIX RIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER3, |
241 | WM8990_LR12LOVOL_SHIFT, WM8990_LR12LOVOL_MASK, 1, out_mix_tlv), | 241 | WM8990_LR12LOVOL_SHIFT, WM8990_LR12LOVOL_MASK, 1, out_mix_tlv), |
242 | SOC_SINGLE_TLV("LOMIX LIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER3, | 242 | SOC_SINGLE_TLV("LOMIX LIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER3, |
243 | WM8990_LL12LOVOL_SHIFT, WM8990_LL12LOVOL_MASK, 1, out_mix_tlv), | 243 | WM8990_LL12LOVOL_SHIFT, WM8990_LL12LOVOL_MASK, 1, out_mix_tlv), |
244 | SOC_SINGLE_TLV("LOMIX RIN3 Bypass Volume", WM8990_OUTPUT_MIXER5, | 244 | SOC_SINGLE_TLV("LOMIX RIN3 Bypass Volume", WM8990_OUTPUT_MIXER5, |
245 | WM8990_LRI3LOVOL_SHIFT, WM8990_LRI3LOVOL_MASK, 1, out_mix_tlv), | 245 | WM8990_LRI3LOVOL_SHIFT, WM8990_LRI3LOVOL_MASK, 1, out_mix_tlv), |
246 | SOC_SINGLE_TLV("LOMIX AINRMUX Bypass Volume", WM8990_OUTPUT_MIXER5, | 246 | SOC_SINGLE_TLV("LOMIX AINRMUX Bypass Volume", WM8990_OUTPUT_MIXER5, |
247 | WM8990_LRBLOVOL_SHIFT, WM8990_LRBLOVOL_MASK, 1, out_mix_tlv), | 247 | WM8990_LRBLOVOL_SHIFT, WM8990_LRBLOVOL_MASK, 1, out_mix_tlv), |
248 | SOC_SINGLE_TLV("LOMIX AINLMUX Bypass Volume", WM8990_OUTPUT_MIXER5, | 248 | SOC_SINGLE_TLV("LOMIX AINLMUX Bypass Volume", WM8990_OUTPUT_MIXER5, |
249 | WM8990_LRBLOVOL_SHIFT, WM8990_LRBLOVOL_MASK, 1, out_mix_tlv), | 249 | WM8990_LRBLOVOL_SHIFT, WM8990_LRBLOVOL_MASK, 1, out_mix_tlv), |
250 | 250 | ||
251 | /* ROMIX */ | 251 | /* ROMIX */ |
252 | SOC_SINGLE_TLV("ROMIX RIN3 Bypass Volume", WM8990_OUTPUT_MIXER4, | 252 | SOC_SINGLE_TLV("ROMIX RIN3 Bypass Volume", WM8990_OUTPUT_MIXER4, |
253 | WM8990_RRI3ROVOL_SHIFT, WM8990_RRI3ROVOL_MASK, 1, out_mix_tlv), | 253 | WM8990_RRI3ROVOL_SHIFT, WM8990_RRI3ROVOL_MASK, 1, out_mix_tlv), |
254 | SOC_SINGLE_TLV("ROMIX LIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER4, | 254 | SOC_SINGLE_TLV("ROMIX LIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER4, |
255 | WM8990_RL12ROVOL_SHIFT, WM8990_RL12ROVOL_MASK, 1, out_mix_tlv), | 255 | WM8990_RL12ROVOL_SHIFT, WM8990_RL12ROVOL_MASK, 1, out_mix_tlv), |
256 | SOC_SINGLE_TLV("ROMIX RIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER4, | 256 | SOC_SINGLE_TLV("ROMIX RIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER4, |
257 | WM8990_RR12ROVOL_SHIFT, WM8990_RR12ROVOL_MASK, 1, out_mix_tlv), | 257 | WM8990_RR12ROVOL_SHIFT, WM8990_RR12ROVOL_MASK, 1, out_mix_tlv), |
258 | SOC_SINGLE_TLV("ROMIX LIN3 Bypass Volume", WM8990_OUTPUT_MIXER6, | 258 | SOC_SINGLE_TLV("ROMIX LIN3 Bypass Volume", WM8990_OUTPUT_MIXER6, |
259 | WM8990_RLI3ROVOL_SHIFT, WM8990_RLI3ROVOL_MASK, 1, out_mix_tlv), | 259 | WM8990_RLI3ROVOL_SHIFT, WM8990_RLI3ROVOL_MASK, 1, out_mix_tlv), |
260 | SOC_SINGLE_TLV("ROMIX AINLMUX Bypass Volume", WM8990_OUTPUT_MIXER6, | 260 | SOC_SINGLE_TLV("ROMIX AINLMUX Bypass Volume", WM8990_OUTPUT_MIXER6, |
261 | WM8990_RLBROVOL_SHIFT, WM8990_RLBROVOL_MASK, 1, out_mix_tlv), | 261 | WM8990_RLBROVOL_SHIFT, WM8990_RLBROVOL_MASK, 1, out_mix_tlv), |
262 | SOC_SINGLE_TLV("ROMIX AINRMUX Bypass Volume", WM8990_OUTPUT_MIXER6, | 262 | SOC_SINGLE_TLV("ROMIX AINRMUX Bypass Volume", WM8990_OUTPUT_MIXER6, |
263 | WM8990_RRBROVOL_SHIFT, WM8990_RRBROVOL_MASK, 1, out_mix_tlv), | 263 | WM8990_RRBROVOL_SHIFT, WM8990_RRBROVOL_MASK, 1, out_mix_tlv), |
264 | 264 | ||
265 | /* LOUT */ | 265 | /* LOUT */ |
266 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("LOUT Volume", WM8990_LEFT_OUTPUT_VOLUME, | 266 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("LOUT Volume", WM8990_LEFT_OUTPUT_VOLUME, |
267 | WM8990_LOUTVOL_SHIFT, WM8990_LOUTVOL_MASK, 0, out_pga_tlv), | 267 | WM8990_LOUTVOL_SHIFT, WM8990_LOUTVOL_MASK, 0, out_pga_tlv), |
268 | SOC_SINGLE("LOUT ZC", WM8990_LEFT_OUTPUT_VOLUME, WM8990_LOZC_BIT, 1, 0), | 268 | SOC_SINGLE("LOUT ZC", WM8990_LEFT_OUTPUT_VOLUME, WM8990_LOZC_BIT, 1, 0), |
269 | 269 | ||
270 | /* ROUT */ | 270 | /* ROUT */ |
271 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("ROUT Volume", WM8990_RIGHT_OUTPUT_VOLUME, | 271 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("ROUT Volume", WM8990_RIGHT_OUTPUT_VOLUME, |
272 | WM8990_ROUTVOL_SHIFT, WM8990_ROUTVOL_MASK, 0, out_pga_tlv), | 272 | WM8990_ROUTVOL_SHIFT, WM8990_ROUTVOL_MASK, 0, out_pga_tlv), |
273 | SOC_SINGLE("ROUT ZC", WM8990_RIGHT_OUTPUT_VOLUME, WM8990_ROZC_BIT, 1, 0), | 273 | SOC_SINGLE("ROUT ZC", WM8990_RIGHT_OUTPUT_VOLUME, WM8990_ROZC_BIT, 1, 0), |
274 | 274 | ||
275 | /* LOPGA */ | 275 | /* LOPGA */ |
276 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("LOPGA Volume", WM8990_LEFT_OPGA_VOLUME, | 276 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("LOPGA Volume", WM8990_LEFT_OPGA_VOLUME, |
277 | WM8990_LOPGAVOL_SHIFT, WM8990_LOPGAVOL_MASK, 0, out_pga_tlv), | 277 | WM8990_LOPGAVOL_SHIFT, WM8990_LOPGAVOL_MASK, 0, out_pga_tlv), |
278 | SOC_SINGLE("LOPGA ZC Switch", WM8990_LEFT_OPGA_VOLUME, | 278 | SOC_SINGLE("LOPGA ZC Switch", WM8990_LEFT_OPGA_VOLUME, |
279 | WM8990_LOPGAZC_BIT, 1, 0), | 279 | WM8990_LOPGAZC_BIT, 1, 0), |
280 | 280 | ||
281 | /* ROPGA */ | 281 | /* ROPGA */ |
282 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("ROPGA Volume", WM8990_RIGHT_OPGA_VOLUME, | 282 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("ROPGA Volume", WM8990_RIGHT_OPGA_VOLUME, |
283 | WM8990_ROPGAVOL_SHIFT, WM8990_ROPGAVOL_MASK, 0, out_pga_tlv), | 283 | WM8990_ROPGAVOL_SHIFT, WM8990_ROPGAVOL_MASK, 0, out_pga_tlv), |
284 | SOC_SINGLE("ROPGA ZC Switch", WM8990_RIGHT_OPGA_VOLUME, | 284 | SOC_SINGLE("ROPGA ZC Switch", WM8990_RIGHT_OPGA_VOLUME, |
285 | WM8990_ROPGAZC_BIT, 1, 0), | 285 | WM8990_ROPGAZC_BIT, 1, 0), |
286 | 286 | ||
287 | SOC_SINGLE("LON Mute Switch", WM8990_LINE_OUTPUTS_VOLUME, | 287 | SOC_SINGLE("LON Mute Switch", WM8990_LINE_OUTPUTS_VOLUME, |
288 | WM8990_LONMUTE_BIT, 1, 0), | 288 | WM8990_LONMUTE_BIT, 1, 0), |
289 | SOC_SINGLE("LOP Mute Switch", WM8990_LINE_OUTPUTS_VOLUME, | 289 | SOC_SINGLE("LOP Mute Switch", WM8990_LINE_OUTPUTS_VOLUME, |
290 | WM8990_LOPMUTE_BIT, 1, 0), | 290 | WM8990_LOPMUTE_BIT, 1, 0), |
291 | SOC_SINGLE("LOP Attenuation Switch", WM8990_LINE_OUTPUTS_VOLUME, | 291 | SOC_SINGLE("LOP Attenuation Switch", WM8990_LINE_OUTPUTS_VOLUME, |
292 | WM8990_LOATTN_BIT, 1, 0), | 292 | WM8990_LOATTN_BIT, 1, 0), |
293 | SOC_SINGLE("RON Mute Switch", WM8990_LINE_OUTPUTS_VOLUME, | 293 | SOC_SINGLE("RON Mute Switch", WM8990_LINE_OUTPUTS_VOLUME, |
294 | WM8990_RONMUTE_BIT, 1, 0), | 294 | WM8990_RONMUTE_BIT, 1, 0), |
295 | SOC_SINGLE("ROP Mute Switch", WM8990_LINE_OUTPUTS_VOLUME, | 295 | SOC_SINGLE("ROP Mute Switch", WM8990_LINE_OUTPUTS_VOLUME, |
296 | WM8990_ROPMUTE_BIT, 1, 0), | 296 | WM8990_ROPMUTE_BIT, 1, 0), |
297 | SOC_SINGLE("ROP Attenuation Switch", WM8990_LINE_OUTPUTS_VOLUME, | 297 | SOC_SINGLE("ROP Attenuation Switch", WM8990_LINE_OUTPUTS_VOLUME, |
298 | WM8990_ROATTN_BIT, 1, 0), | 298 | WM8990_ROATTN_BIT, 1, 0), |
299 | 299 | ||
300 | SOC_SINGLE("OUT3 Mute Switch", WM8990_OUT3_4_VOLUME, | 300 | SOC_SINGLE("OUT3 Mute Switch", WM8990_OUT3_4_VOLUME, |
301 | WM8990_OUT3MUTE_BIT, 1, 0), | 301 | WM8990_OUT3MUTE_BIT, 1, 0), |
302 | SOC_SINGLE("OUT3 Attenuation Switch", WM8990_OUT3_4_VOLUME, | 302 | SOC_SINGLE("OUT3 Attenuation Switch", WM8990_OUT3_4_VOLUME, |
303 | WM8990_OUT3ATTN_BIT, 1, 0), | 303 | WM8990_OUT3ATTN_BIT, 1, 0), |
304 | 304 | ||
305 | SOC_SINGLE("OUT4 Mute Switch", WM8990_OUT3_4_VOLUME, | 305 | SOC_SINGLE("OUT4 Mute Switch", WM8990_OUT3_4_VOLUME, |
306 | WM8990_OUT4MUTE_BIT, 1, 0), | 306 | WM8990_OUT4MUTE_BIT, 1, 0), |
307 | SOC_SINGLE("OUT4 Attenuation Switch", WM8990_OUT3_4_VOLUME, | 307 | SOC_SINGLE("OUT4 Attenuation Switch", WM8990_OUT3_4_VOLUME, |
308 | WM8990_OUT4ATTN_BIT, 1, 0), | 308 | WM8990_OUT4ATTN_BIT, 1, 0), |
309 | 309 | ||
310 | SOC_SINGLE("Speaker Mode Switch", WM8990_CLASSD1, | 310 | SOC_SINGLE("Speaker Mode Switch", WM8990_CLASSD1, |
311 | WM8990_CDMODE_BIT, 1, 0), | 311 | WM8990_CDMODE_BIT, 1, 0), |
312 | 312 | ||
313 | SOC_SINGLE("Speaker Output Attenuation Volume", WM8990_SPEAKER_VOLUME, | 313 | SOC_SINGLE("Speaker Output Attenuation Volume", WM8990_SPEAKER_VOLUME, |
314 | WM8990_SPKATTN_SHIFT, WM8990_SPKATTN_MASK, 0), | 314 | WM8990_SPKATTN_SHIFT, WM8990_SPKATTN_MASK, 0), |
315 | SOC_SINGLE("Speaker DC Boost Volume", WM8990_CLASSD3, | 315 | SOC_SINGLE("Speaker DC Boost Volume", WM8990_CLASSD3, |
316 | WM8990_DCGAIN_SHIFT, WM8990_DCGAIN_MASK, 0), | 316 | WM8990_DCGAIN_SHIFT, WM8990_DCGAIN_MASK, 0), |
317 | SOC_SINGLE("Speaker AC Boost Volume", WM8990_CLASSD3, | 317 | SOC_SINGLE("Speaker AC Boost Volume", WM8990_CLASSD3, |
318 | WM8990_ACGAIN_SHIFT, WM8990_ACGAIN_MASK, 0), | 318 | WM8990_ACGAIN_SHIFT, WM8990_ACGAIN_MASK, 0), |
319 | SOC_SINGLE_TLV("Speaker Volume", WM8990_CLASSD4, | 319 | SOC_SINGLE_TLV("Speaker Volume", WM8990_CLASSD4, |
320 | WM8990_SPKVOL_SHIFT, WM8990_SPKVOL_MASK, 0, out_pga_tlv), | 320 | WM8990_SPKVOL_SHIFT, WM8990_SPKVOL_MASK, 0, out_pga_tlv), |
321 | SOC_SINGLE("Speaker ZC Switch", WM8990_CLASSD4, | 321 | SOC_SINGLE("Speaker ZC Switch", WM8990_CLASSD4, |
322 | WM8990_SPKZC_SHIFT, WM8990_SPKZC_MASK, 0), | 322 | WM8990_SPKZC_SHIFT, WM8990_SPKZC_MASK, 0), |
323 | 323 | ||
324 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("Left DAC Digital Volume", | 324 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("Left DAC Digital Volume", |
325 | WM8990_LEFT_DAC_DIGITAL_VOLUME, | 325 | WM8990_LEFT_DAC_DIGITAL_VOLUME, |
326 | WM8990_DACL_VOL_SHIFT, | 326 | WM8990_DACL_VOL_SHIFT, |
327 | WM8990_DACL_VOL_MASK, | 327 | WM8990_DACL_VOL_MASK, |
328 | 0, | 328 | 0, |
329 | out_dac_tlv), | 329 | out_dac_tlv), |
330 | 330 | ||
331 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("Right DAC Digital Volume", | 331 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("Right DAC Digital Volume", |
332 | WM8990_RIGHT_DAC_DIGITAL_VOLUME, | 332 | WM8990_RIGHT_DAC_DIGITAL_VOLUME, |
333 | WM8990_DACR_VOL_SHIFT, | 333 | WM8990_DACR_VOL_SHIFT, |
334 | WM8990_DACR_VOL_MASK, | 334 | WM8990_DACR_VOL_MASK, |
335 | 0, | 335 | 0, |
336 | out_dac_tlv), | 336 | out_dac_tlv), |
337 | 337 | ||
338 | SOC_ENUM("Left Digital Sidetone", wm8990_left_digital_sidetone_enum), | 338 | SOC_ENUM("Left Digital Sidetone", wm8990_left_digital_sidetone_enum), |
339 | SOC_ENUM("Right Digital Sidetone", wm8990_right_digital_sidetone_enum), | 339 | SOC_ENUM("Right Digital Sidetone", wm8990_right_digital_sidetone_enum), |
340 | 340 | ||
341 | SOC_SINGLE_TLV("Left Digital Sidetone Volume", WM8990_DIGITAL_SIDE_TONE, | 341 | SOC_SINGLE_TLV("Left Digital Sidetone Volume", WM8990_DIGITAL_SIDE_TONE, |
342 | WM8990_ADCL_DAC_SVOL_SHIFT, WM8990_ADCL_DAC_SVOL_MASK, 0, | 342 | WM8990_ADCL_DAC_SVOL_SHIFT, WM8990_ADCL_DAC_SVOL_MASK, 0, |
343 | out_sidetone_tlv), | 343 | out_sidetone_tlv), |
344 | SOC_SINGLE_TLV("Right Digital Sidetone Volume", WM8990_DIGITAL_SIDE_TONE, | 344 | SOC_SINGLE_TLV("Right Digital Sidetone Volume", WM8990_DIGITAL_SIDE_TONE, |
345 | WM8990_ADCR_DAC_SVOL_SHIFT, WM8990_ADCR_DAC_SVOL_MASK, 0, | 345 | WM8990_ADCR_DAC_SVOL_SHIFT, WM8990_ADCR_DAC_SVOL_MASK, 0, |
346 | out_sidetone_tlv), | 346 | out_sidetone_tlv), |
347 | 347 | ||
348 | SOC_SINGLE("ADC Digital High Pass Filter Switch", WM8990_ADC_CTRL, | 348 | SOC_SINGLE("ADC Digital High Pass Filter Switch", WM8990_ADC_CTRL, |
349 | WM8990_ADC_HPF_ENA_BIT, 1, 0), | 349 | WM8990_ADC_HPF_ENA_BIT, 1, 0), |
350 | 350 | ||
351 | SOC_ENUM("ADC HPF Mode", wm8990_right_adcmode_enum), | 351 | SOC_ENUM("ADC HPF Mode", wm8990_right_adcmode_enum), |
352 | 352 | ||
353 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("Left ADC Digital Volume", | 353 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("Left ADC Digital Volume", |
354 | WM8990_LEFT_ADC_DIGITAL_VOLUME, | 354 | WM8990_LEFT_ADC_DIGITAL_VOLUME, |
355 | WM8990_ADCL_VOL_SHIFT, | 355 | WM8990_ADCL_VOL_SHIFT, |
356 | WM8990_ADCL_VOL_MASK, | 356 | WM8990_ADCL_VOL_MASK, |
357 | 0, | 357 | 0, |
358 | in_adc_tlv), | 358 | in_adc_tlv), |
359 | 359 | ||
360 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("Right ADC Digital Volume", | 360 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("Right ADC Digital Volume", |
361 | WM8990_RIGHT_ADC_DIGITAL_VOLUME, | 361 | WM8990_RIGHT_ADC_DIGITAL_VOLUME, |
362 | WM8990_ADCR_VOL_SHIFT, | 362 | WM8990_ADCR_VOL_SHIFT, |
363 | WM8990_ADCR_VOL_MASK, | 363 | WM8990_ADCR_VOL_MASK, |
364 | 0, | 364 | 0, |
365 | in_adc_tlv), | 365 | in_adc_tlv), |
366 | 366 | ||
367 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("LIN12 Volume", | 367 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("LIN12 Volume", |
368 | WM8990_LEFT_LINE_INPUT_1_2_VOLUME, | 368 | WM8990_LEFT_LINE_INPUT_1_2_VOLUME, |
369 | WM8990_LIN12VOL_SHIFT, | 369 | WM8990_LIN12VOL_SHIFT, |
370 | WM8990_LIN12VOL_MASK, | 370 | WM8990_LIN12VOL_MASK, |
371 | 0, | 371 | 0, |
372 | in_pga_tlv), | 372 | in_pga_tlv), |
373 | 373 | ||
374 | SOC_SINGLE("LIN12 ZC Switch", WM8990_LEFT_LINE_INPUT_1_2_VOLUME, | 374 | SOC_SINGLE("LIN12 ZC Switch", WM8990_LEFT_LINE_INPUT_1_2_VOLUME, |
375 | WM8990_LI12ZC_BIT, 1, 0), | 375 | WM8990_LI12ZC_BIT, 1, 0), |
376 | 376 | ||
377 | SOC_SINGLE("LIN12 Mute Switch", WM8990_LEFT_LINE_INPUT_1_2_VOLUME, | 377 | SOC_SINGLE("LIN12 Mute Switch", WM8990_LEFT_LINE_INPUT_1_2_VOLUME, |
378 | WM8990_LI12MUTE_BIT, 1, 0), | 378 | WM8990_LI12MUTE_BIT, 1, 0), |
379 | 379 | ||
380 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("LIN34 Volume", | 380 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("LIN34 Volume", |
381 | WM8990_LEFT_LINE_INPUT_3_4_VOLUME, | 381 | WM8990_LEFT_LINE_INPUT_3_4_VOLUME, |
382 | WM8990_LIN34VOL_SHIFT, | 382 | WM8990_LIN34VOL_SHIFT, |
383 | WM8990_LIN34VOL_MASK, | 383 | WM8990_LIN34VOL_MASK, |
384 | 0, | 384 | 0, |
385 | in_pga_tlv), | 385 | in_pga_tlv), |
386 | 386 | ||
387 | SOC_SINGLE("LIN34 ZC Switch", WM8990_LEFT_LINE_INPUT_3_4_VOLUME, | 387 | SOC_SINGLE("LIN34 ZC Switch", WM8990_LEFT_LINE_INPUT_3_4_VOLUME, |
388 | WM8990_LI34ZC_BIT, 1, 0), | 388 | WM8990_LI34ZC_BIT, 1, 0), |
389 | 389 | ||
390 | SOC_SINGLE("LIN34 Mute Switch", WM8990_LEFT_LINE_INPUT_3_4_VOLUME, | 390 | SOC_SINGLE("LIN34 Mute Switch", WM8990_LEFT_LINE_INPUT_3_4_VOLUME, |
391 | WM8990_LI34MUTE_BIT, 1, 0), | 391 | WM8990_LI34MUTE_BIT, 1, 0), |
392 | 392 | ||
393 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("RIN12 Volume", | 393 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("RIN12 Volume", |
394 | WM8990_RIGHT_LINE_INPUT_1_2_VOLUME, | 394 | WM8990_RIGHT_LINE_INPUT_1_2_VOLUME, |
395 | WM8990_RIN12VOL_SHIFT, | 395 | WM8990_RIN12VOL_SHIFT, |
396 | WM8990_RIN12VOL_MASK, | 396 | WM8990_RIN12VOL_MASK, |
397 | 0, | 397 | 0, |
398 | in_pga_tlv), | 398 | in_pga_tlv), |
399 | 399 | ||
400 | SOC_SINGLE("RIN12 ZC Switch", WM8990_RIGHT_LINE_INPUT_1_2_VOLUME, | 400 | SOC_SINGLE("RIN12 ZC Switch", WM8990_RIGHT_LINE_INPUT_1_2_VOLUME, |
401 | WM8990_RI12ZC_BIT, 1, 0), | 401 | WM8990_RI12ZC_BIT, 1, 0), |
402 | 402 | ||
403 | SOC_SINGLE("RIN12 Mute Switch", WM8990_RIGHT_LINE_INPUT_1_2_VOLUME, | 403 | SOC_SINGLE("RIN12 Mute Switch", WM8990_RIGHT_LINE_INPUT_1_2_VOLUME, |
404 | WM8990_RI12MUTE_BIT, 1, 0), | 404 | WM8990_RI12MUTE_BIT, 1, 0), |
405 | 405 | ||
406 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("RIN34 Volume", | 406 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("RIN34 Volume", |
407 | WM8990_RIGHT_LINE_INPUT_3_4_VOLUME, | 407 | WM8990_RIGHT_LINE_INPUT_3_4_VOLUME, |
408 | WM8990_RIN34VOL_SHIFT, | 408 | WM8990_RIN34VOL_SHIFT, |
409 | WM8990_RIN34VOL_MASK, | 409 | WM8990_RIN34VOL_MASK, |
410 | 0, | 410 | 0, |
411 | in_pga_tlv), | 411 | in_pga_tlv), |
412 | 412 | ||
413 | SOC_SINGLE("RIN34 ZC Switch", WM8990_RIGHT_LINE_INPUT_3_4_VOLUME, | 413 | SOC_SINGLE("RIN34 ZC Switch", WM8990_RIGHT_LINE_INPUT_3_4_VOLUME, |
414 | WM8990_RI34ZC_BIT, 1, 0), | 414 | WM8990_RI34ZC_BIT, 1, 0), |
415 | 415 | ||
416 | SOC_SINGLE("RIN34 Mute Switch", WM8990_RIGHT_LINE_INPUT_3_4_VOLUME, | 416 | SOC_SINGLE("RIN34 Mute Switch", WM8990_RIGHT_LINE_INPUT_3_4_VOLUME, |
417 | WM8990_RI34MUTE_BIT, 1, 0), | 417 | WM8990_RI34MUTE_BIT, 1, 0), |
418 | 418 | ||
419 | }; | 419 | }; |
420 | 420 | ||
421 | /* add non dapm controls */ | 421 | /* add non dapm controls */ |
422 | static int wm8990_add_controls(struct snd_soc_codec *codec) | 422 | static int wm8990_add_controls(struct snd_soc_codec *codec) |
423 | { | 423 | { |
424 | int err, i; | 424 | int err, i; |
425 | 425 | ||
426 | for (i = 0; i < ARRAY_SIZE(wm8990_snd_controls); i++) { | 426 | for (i = 0; i < ARRAY_SIZE(wm8990_snd_controls); i++) { |
427 | err = snd_ctl_add(codec->card, | 427 | err = snd_ctl_add(codec->card, |
428 | snd_soc_cnew(&wm8990_snd_controls[i], codec, | 428 | snd_soc_cnew(&wm8990_snd_controls[i], codec, |
429 | NULL)); | 429 | NULL)); |
430 | if (err < 0) | 430 | if (err < 0) |
431 | return err; | 431 | return err; |
432 | } | 432 | } |
433 | return 0; | 433 | return 0; |
434 | } | 434 | } |
435 | 435 | ||
436 | /* | 436 | /* |
437 | * _DAPM_ Controls | 437 | * _DAPM_ Controls |
438 | */ | 438 | */ |
439 | 439 | ||
440 | static int inmixer_event(struct snd_soc_dapm_widget *w, | 440 | static int inmixer_event(struct snd_soc_dapm_widget *w, |
441 | struct snd_kcontrol *kcontrol, int event) | 441 | struct snd_kcontrol *kcontrol, int event) |
442 | { | 442 | { |
443 | u16 reg, fakepower; | 443 | u16 reg, fakepower; |
444 | 444 | ||
445 | reg = wm8990_read_reg_cache(w->codec, WM8990_POWER_MANAGEMENT_2); | 445 | reg = wm8990_read_reg_cache(w->codec, WM8990_POWER_MANAGEMENT_2); |
446 | fakepower = wm8990_read_reg_cache(w->codec, WM8990_INTDRIVBITS); | 446 | fakepower = wm8990_read_reg_cache(w->codec, WM8990_INTDRIVBITS); |
447 | 447 | ||
448 | if (fakepower & ((1 << WM8990_INMIXL_PWR_BIT) | | 448 | if (fakepower & ((1 << WM8990_INMIXL_PWR_BIT) | |
449 | (1 << WM8990_AINLMUX_PWR_BIT))) { | 449 | (1 << WM8990_AINLMUX_PWR_BIT))) { |
450 | reg |= WM8990_AINL_ENA; | 450 | reg |= WM8990_AINL_ENA; |
451 | } else { | 451 | } else { |
452 | reg &= ~WM8990_AINL_ENA; | 452 | reg &= ~WM8990_AINL_ENA; |
453 | } | 453 | } |
454 | 454 | ||
455 | if (fakepower & ((1 << WM8990_INMIXR_PWR_BIT) | | 455 | if (fakepower & ((1 << WM8990_INMIXR_PWR_BIT) | |
456 | (1 << WM8990_AINRMUX_PWR_BIT))) { | 456 | (1 << WM8990_AINRMUX_PWR_BIT))) { |
457 | reg |= WM8990_AINR_ENA; | 457 | reg |= WM8990_AINR_ENA; |
458 | } else { | 458 | } else { |
459 | reg &= ~WM8990_AINL_ENA; | 459 | reg &= ~WM8990_AINL_ENA; |
460 | } | 460 | } |
461 | wm8990_write(w->codec, WM8990_POWER_MANAGEMENT_2, reg); | 461 | wm8990_write(w->codec, WM8990_POWER_MANAGEMENT_2, reg); |
462 | 462 | ||
463 | return 0; | 463 | return 0; |
464 | } | 464 | } |
465 | 465 | ||
466 | static int outmixer_event(struct snd_soc_dapm_widget *w, | 466 | static int outmixer_event(struct snd_soc_dapm_widget *w, |
467 | struct snd_kcontrol *kcontrol, int event) | 467 | struct snd_kcontrol *kcontrol, int event) |
468 | { | 468 | { |
469 | u32 reg_shift = kcontrol->private_value & 0xfff; | 469 | u32 reg_shift = kcontrol->private_value & 0xfff; |
470 | int ret = 0; | 470 | int ret = 0; |
471 | u16 reg; | 471 | u16 reg; |
472 | 472 | ||
473 | switch (reg_shift) { | 473 | switch (reg_shift) { |
474 | case WM8990_SPEAKER_MIXER | (WM8990_LDSPK_BIT << 8) : | 474 | case WM8990_SPEAKER_MIXER | (WM8990_LDSPK_BIT << 8) : |
475 | reg = wm8990_read_reg_cache(w->codec, WM8990_OUTPUT_MIXER1); | 475 | reg = wm8990_read_reg_cache(w->codec, WM8990_OUTPUT_MIXER1); |
476 | if (reg & WM8990_LDLO) { | 476 | if (reg & WM8990_LDLO) { |
477 | printk(KERN_WARNING | 477 | printk(KERN_WARNING |
478 | "Cannot set as Output Mixer 1 LDLO Set\n"); | 478 | "Cannot set as Output Mixer 1 LDLO Set\n"); |
479 | ret = -1; | 479 | ret = -1; |
480 | } | 480 | } |
481 | break; | 481 | break; |
482 | case WM8990_SPEAKER_MIXER | (WM8990_RDSPK_BIT << 8): | 482 | case WM8990_SPEAKER_MIXER | (WM8990_RDSPK_BIT << 8): |
483 | reg = wm8990_read_reg_cache(w->codec, WM8990_OUTPUT_MIXER2); | 483 | reg = wm8990_read_reg_cache(w->codec, WM8990_OUTPUT_MIXER2); |
484 | if (reg & WM8990_RDRO) { | 484 | if (reg & WM8990_RDRO) { |
485 | printk(KERN_WARNING | 485 | printk(KERN_WARNING |
486 | "Cannot set as Output Mixer 2 RDRO Set\n"); | 486 | "Cannot set as Output Mixer 2 RDRO Set\n"); |
487 | ret = -1; | 487 | ret = -1; |
488 | } | 488 | } |
489 | break; | 489 | break; |
490 | case WM8990_OUTPUT_MIXER1 | (WM8990_LDLO_BIT << 8): | 490 | case WM8990_OUTPUT_MIXER1 | (WM8990_LDLO_BIT << 8): |
491 | reg = wm8990_read_reg_cache(w->codec, WM8990_SPEAKER_MIXER); | 491 | reg = wm8990_read_reg_cache(w->codec, WM8990_SPEAKER_MIXER); |
492 | if (reg & WM8990_LDSPK) { | 492 | if (reg & WM8990_LDSPK) { |
493 | printk(KERN_WARNING | 493 | printk(KERN_WARNING |
494 | "Cannot set as Speaker Mixer LDSPK Set\n"); | 494 | "Cannot set as Speaker Mixer LDSPK Set\n"); |
495 | ret = -1; | 495 | ret = -1; |
496 | } | 496 | } |
497 | break; | 497 | break; |
498 | case WM8990_OUTPUT_MIXER2 | (WM8990_RDRO_BIT << 8): | 498 | case WM8990_OUTPUT_MIXER2 | (WM8990_RDRO_BIT << 8): |
499 | reg = wm8990_read_reg_cache(w->codec, WM8990_SPEAKER_MIXER); | 499 | reg = wm8990_read_reg_cache(w->codec, WM8990_SPEAKER_MIXER); |
500 | if (reg & WM8990_RDSPK) { | 500 | if (reg & WM8990_RDSPK) { |
501 | printk(KERN_WARNING | 501 | printk(KERN_WARNING |
502 | "Cannot set as Speaker Mixer RDSPK Set\n"); | 502 | "Cannot set as Speaker Mixer RDSPK Set\n"); |
503 | ret = -1; | 503 | ret = -1; |
504 | } | 504 | } |
505 | break; | 505 | break; |
506 | } | 506 | } |
507 | 507 | ||
508 | return ret; | 508 | return ret; |
509 | } | 509 | } |
510 | 510 | ||
511 | /* INMIX dB values */ | 511 | /* INMIX dB values */ |
512 | static const unsigned int in_mix_tlv[] = { | 512 | static const unsigned int in_mix_tlv[] = { |
513 | TLV_DB_RANGE_HEAD(1), | 513 | TLV_DB_RANGE_HEAD(1), |
514 | 0, 7, TLV_DB_LINEAR_ITEM(-1200, 600), | 514 | 0, 7, TLV_DB_LINEAR_ITEM(-1200, 600), |
515 | }; | 515 | }; |
516 | 516 | ||
517 | /* Left In PGA Connections */ | 517 | /* Left In PGA Connections */ |
518 | static const struct snd_kcontrol_new wm8990_dapm_lin12_pga_controls[] = { | 518 | static const struct snd_kcontrol_new wm8990_dapm_lin12_pga_controls[] = { |
519 | SOC_DAPM_SINGLE("LIN1 Switch", WM8990_INPUT_MIXER2, WM8990_LMN1_BIT, 1, 0), | 519 | SOC_DAPM_SINGLE("LIN1 Switch", WM8990_INPUT_MIXER2, WM8990_LMN1_BIT, 1, 0), |
520 | SOC_DAPM_SINGLE("LIN2 Switch", WM8990_INPUT_MIXER2, WM8990_LMP2_BIT, 1, 0), | 520 | SOC_DAPM_SINGLE("LIN2 Switch", WM8990_INPUT_MIXER2, WM8990_LMP2_BIT, 1, 0), |
521 | }; | 521 | }; |
522 | 522 | ||
523 | static const struct snd_kcontrol_new wm8990_dapm_lin34_pga_controls[] = { | 523 | static const struct snd_kcontrol_new wm8990_dapm_lin34_pga_controls[] = { |
524 | SOC_DAPM_SINGLE("LIN3 Switch", WM8990_INPUT_MIXER2, WM8990_LMN3_BIT, 1, 0), | 524 | SOC_DAPM_SINGLE("LIN3 Switch", WM8990_INPUT_MIXER2, WM8990_LMN3_BIT, 1, 0), |
525 | SOC_DAPM_SINGLE("LIN4 Switch", WM8990_INPUT_MIXER2, WM8990_LMP4_BIT, 1, 0), | 525 | SOC_DAPM_SINGLE("LIN4 Switch", WM8990_INPUT_MIXER2, WM8990_LMP4_BIT, 1, 0), |
526 | }; | 526 | }; |
527 | 527 | ||
528 | /* Right In PGA Connections */ | 528 | /* Right In PGA Connections */ |
529 | static const struct snd_kcontrol_new wm8990_dapm_rin12_pga_controls[] = { | 529 | static const struct snd_kcontrol_new wm8990_dapm_rin12_pga_controls[] = { |
530 | SOC_DAPM_SINGLE("RIN1 Switch", WM8990_INPUT_MIXER2, WM8990_RMN1_BIT, 1, 0), | 530 | SOC_DAPM_SINGLE("RIN1 Switch", WM8990_INPUT_MIXER2, WM8990_RMN1_BIT, 1, 0), |
531 | SOC_DAPM_SINGLE("RIN2 Switch", WM8990_INPUT_MIXER2, WM8990_RMP2_BIT, 1, 0), | 531 | SOC_DAPM_SINGLE("RIN2 Switch", WM8990_INPUT_MIXER2, WM8990_RMP2_BIT, 1, 0), |
532 | }; | 532 | }; |
533 | 533 | ||
534 | static const struct snd_kcontrol_new wm8990_dapm_rin34_pga_controls[] = { | 534 | static const struct snd_kcontrol_new wm8990_dapm_rin34_pga_controls[] = { |
535 | SOC_DAPM_SINGLE("RIN3 Switch", WM8990_INPUT_MIXER2, WM8990_RMN3_BIT, 1, 0), | 535 | SOC_DAPM_SINGLE("RIN3 Switch", WM8990_INPUT_MIXER2, WM8990_RMN3_BIT, 1, 0), |
536 | SOC_DAPM_SINGLE("RIN4 Switch", WM8990_INPUT_MIXER2, WM8990_RMP4_BIT, 1, 0), | 536 | SOC_DAPM_SINGLE("RIN4 Switch", WM8990_INPUT_MIXER2, WM8990_RMP4_BIT, 1, 0), |
537 | }; | 537 | }; |
538 | 538 | ||
539 | /* INMIXL */ | 539 | /* INMIXL */ |
540 | static const struct snd_kcontrol_new wm8990_dapm_inmixl_controls[] = { | 540 | static const struct snd_kcontrol_new wm8990_dapm_inmixl_controls[] = { |
541 | SOC_DAPM_SINGLE_TLV("Record Left Volume", WM8990_INPUT_MIXER3, | 541 | SOC_DAPM_SINGLE_TLV("Record Left Volume", WM8990_INPUT_MIXER3, |
542 | WM8990_LDBVOL_SHIFT, WM8990_LDBVOL_MASK, 0, in_mix_tlv), | 542 | WM8990_LDBVOL_SHIFT, WM8990_LDBVOL_MASK, 0, in_mix_tlv), |
543 | SOC_DAPM_SINGLE_TLV("LIN2 Volume", WM8990_INPUT_MIXER5, WM8990_LI2BVOL_SHIFT, | 543 | SOC_DAPM_SINGLE_TLV("LIN2 Volume", WM8990_INPUT_MIXER5, WM8990_LI2BVOL_SHIFT, |
544 | 7, 0, in_mix_tlv), | 544 | 7, 0, in_mix_tlv), |
545 | SOC_DAPM_SINGLE("LINPGA12 Switch", WM8990_INPUT_MIXER3, WM8990_L12MNB_BIT, | 545 | SOC_DAPM_SINGLE("LINPGA12 Switch", WM8990_INPUT_MIXER3, WM8990_L12MNB_BIT, |
546 | 1, 0), | 546 | 1, 0), |
547 | SOC_DAPM_SINGLE("LINPGA34 Switch", WM8990_INPUT_MIXER3, WM8990_L34MNB_BIT, | 547 | SOC_DAPM_SINGLE("LINPGA34 Switch", WM8990_INPUT_MIXER3, WM8990_L34MNB_BIT, |
548 | 1, 0), | 548 | 1, 0), |
549 | }; | 549 | }; |
550 | 550 | ||
551 | /* INMIXR */ | 551 | /* INMIXR */ |
552 | static const struct snd_kcontrol_new wm8990_dapm_inmixr_controls[] = { | 552 | static const struct snd_kcontrol_new wm8990_dapm_inmixr_controls[] = { |
553 | SOC_DAPM_SINGLE_TLV("Record Right Volume", WM8990_INPUT_MIXER4, | 553 | SOC_DAPM_SINGLE_TLV("Record Right Volume", WM8990_INPUT_MIXER4, |
554 | WM8990_RDBVOL_SHIFT, WM8990_RDBVOL_MASK, 0, in_mix_tlv), | 554 | WM8990_RDBVOL_SHIFT, WM8990_RDBVOL_MASK, 0, in_mix_tlv), |
555 | SOC_DAPM_SINGLE_TLV("RIN2 Volume", WM8990_INPUT_MIXER6, WM8990_RI2BVOL_SHIFT, | 555 | SOC_DAPM_SINGLE_TLV("RIN2 Volume", WM8990_INPUT_MIXER6, WM8990_RI2BVOL_SHIFT, |
556 | 7, 0, in_mix_tlv), | 556 | 7, 0, in_mix_tlv), |
557 | SOC_DAPM_SINGLE("RINPGA12 Switch", WM8990_INPUT_MIXER3, WM8990_L12MNB_BIT, | 557 | SOC_DAPM_SINGLE("RINPGA12 Switch", WM8990_INPUT_MIXER3, WM8990_L12MNB_BIT, |
558 | 1, 0), | 558 | 1, 0), |
559 | SOC_DAPM_SINGLE("RINPGA34 Switch", WM8990_INPUT_MIXER3, WM8990_L34MNB_BIT, | 559 | SOC_DAPM_SINGLE("RINPGA34 Switch", WM8990_INPUT_MIXER3, WM8990_L34MNB_BIT, |
560 | 1, 0), | 560 | 1, 0), |
561 | }; | 561 | }; |
562 | 562 | ||
563 | /* AINLMUX */ | 563 | /* AINLMUX */ |
564 | static const char *wm8990_ainlmux[] = | 564 | static const char *wm8990_ainlmux[] = |
565 | {"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"}; | 565 | {"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"}; |
566 | 566 | ||
567 | static const struct soc_enum wm8990_ainlmux_enum = | 567 | static const struct soc_enum wm8990_ainlmux_enum = |
568 | SOC_ENUM_SINGLE(WM8990_INPUT_MIXER1, WM8990_AINLMODE_SHIFT, | 568 | SOC_ENUM_SINGLE(WM8990_INPUT_MIXER1, WM8990_AINLMODE_SHIFT, |
569 | ARRAY_SIZE(wm8990_ainlmux), wm8990_ainlmux); | 569 | ARRAY_SIZE(wm8990_ainlmux), wm8990_ainlmux); |
570 | 570 | ||
571 | static const struct snd_kcontrol_new wm8990_dapm_ainlmux_controls = | 571 | static const struct snd_kcontrol_new wm8990_dapm_ainlmux_controls = |
572 | SOC_DAPM_ENUM("Route", wm8990_ainlmux_enum); | 572 | SOC_DAPM_ENUM("Route", wm8990_ainlmux_enum); |
573 | 573 | ||
574 | /* DIFFINL */ | 574 | /* DIFFINL */ |
575 | 575 | ||
576 | /* AINRMUX */ | 576 | /* AINRMUX */ |
577 | static const char *wm8990_ainrmux[] = | 577 | static const char *wm8990_ainrmux[] = |
578 | {"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"}; | 578 | {"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"}; |
579 | 579 | ||
580 | static const struct soc_enum wm8990_ainrmux_enum = | 580 | static const struct soc_enum wm8990_ainrmux_enum = |
581 | SOC_ENUM_SINGLE(WM8990_INPUT_MIXER1, WM8990_AINRMODE_SHIFT, | 581 | SOC_ENUM_SINGLE(WM8990_INPUT_MIXER1, WM8990_AINRMODE_SHIFT, |
582 | ARRAY_SIZE(wm8990_ainrmux), wm8990_ainrmux); | 582 | ARRAY_SIZE(wm8990_ainrmux), wm8990_ainrmux); |
583 | 583 | ||
584 | static const struct snd_kcontrol_new wm8990_dapm_ainrmux_controls = | 584 | static const struct snd_kcontrol_new wm8990_dapm_ainrmux_controls = |
585 | SOC_DAPM_ENUM("Route", wm8990_ainrmux_enum); | 585 | SOC_DAPM_ENUM("Route", wm8990_ainrmux_enum); |
586 | 586 | ||
587 | /* RXVOICE */ | 587 | /* RXVOICE */ |
588 | static const struct snd_kcontrol_new wm8990_dapm_rxvoice_controls[] = { | 588 | static const struct snd_kcontrol_new wm8990_dapm_rxvoice_controls[] = { |
589 | SOC_DAPM_SINGLE_TLV("LIN4/RXN", WM8990_INPUT_MIXER5, WM8990_LR4BVOL_SHIFT, | 589 | SOC_DAPM_SINGLE_TLV("LIN4/RXN", WM8990_INPUT_MIXER5, WM8990_LR4BVOL_SHIFT, |
590 | WM8990_LR4BVOL_MASK, 0, in_mix_tlv), | 590 | WM8990_LR4BVOL_MASK, 0, in_mix_tlv), |
591 | SOC_DAPM_SINGLE_TLV("RIN4/RXP", WM8990_INPUT_MIXER6, WM8990_RL4BVOL_SHIFT, | 591 | SOC_DAPM_SINGLE_TLV("RIN4/RXP", WM8990_INPUT_MIXER6, WM8990_RL4BVOL_SHIFT, |
592 | WM8990_RL4BVOL_MASK, 0, in_mix_tlv), | 592 | WM8990_RL4BVOL_MASK, 0, in_mix_tlv), |
593 | }; | 593 | }; |
594 | 594 | ||
595 | /* LOMIX */ | 595 | /* LOMIX */ |
596 | static const struct snd_kcontrol_new wm8990_dapm_lomix_controls[] = { | 596 | static const struct snd_kcontrol_new wm8990_dapm_lomix_controls[] = { |
597 | SOC_DAPM_SINGLE("LOMIX Right ADC Bypass Switch", WM8990_OUTPUT_MIXER1, | 597 | SOC_DAPM_SINGLE("LOMIX Right ADC Bypass Switch", WM8990_OUTPUT_MIXER1, |
598 | WM8990_LRBLO_BIT, 1, 0), | 598 | WM8990_LRBLO_BIT, 1, 0), |
599 | SOC_DAPM_SINGLE("LOMIX Left ADC Bypass Switch", WM8990_OUTPUT_MIXER1, | 599 | SOC_DAPM_SINGLE("LOMIX Left ADC Bypass Switch", WM8990_OUTPUT_MIXER1, |
600 | WM8990_LLBLO_BIT, 1, 0), | 600 | WM8990_LLBLO_BIT, 1, 0), |
601 | SOC_DAPM_SINGLE("LOMIX RIN3 Bypass Switch", WM8990_OUTPUT_MIXER1, | 601 | SOC_DAPM_SINGLE("LOMIX RIN3 Bypass Switch", WM8990_OUTPUT_MIXER1, |
602 | WM8990_LRI3LO_BIT, 1, 0), | 602 | WM8990_LRI3LO_BIT, 1, 0), |
603 | SOC_DAPM_SINGLE("LOMIX LIN3 Bypass Switch", WM8990_OUTPUT_MIXER1, | 603 | SOC_DAPM_SINGLE("LOMIX LIN3 Bypass Switch", WM8990_OUTPUT_MIXER1, |
604 | WM8990_LLI3LO_BIT, 1, 0), | 604 | WM8990_LLI3LO_BIT, 1, 0), |
605 | SOC_DAPM_SINGLE("LOMIX RIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER1, | 605 | SOC_DAPM_SINGLE("LOMIX RIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER1, |
606 | WM8990_LR12LO_BIT, 1, 0), | 606 | WM8990_LR12LO_BIT, 1, 0), |
607 | SOC_DAPM_SINGLE("LOMIX LIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER1, | 607 | SOC_DAPM_SINGLE("LOMIX LIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER1, |
608 | WM8990_LL12LO_BIT, 1, 0), | 608 | WM8990_LL12LO_BIT, 1, 0), |
609 | SOC_DAPM_SINGLE("LOMIX Left DAC Switch", WM8990_OUTPUT_MIXER1, | 609 | SOC_DAPM_SINGLE("LOMIX Left DAC Switch", WM8990_OUTPUT_MIXER1, |
610 | WM8990_LDLO_BIT, 1, 0), | 610 | WM8990_LDLO_BIT, 1, 0), |
611 | }; | 611 | }; |
612 | 612 | ||
613 | /* ROMIX */ | 613 | /* ROMIX */ |
614 | static const struct snd_kcontrol_new wm8990_dapm_romix_controls[] = { | 614 | static const struct snd_kcontrol_new wm8990_dapm_romix_controls[] = { |
615 | SOC_DAPM_SINGLE("ROMIX Left ADC Bypass Switch", WM8990_OUTPUT_MIXER2, | 615 | SOC_DAPM_SINGLE("ROMIX Left ADC Bypass Switch", WM8990_OUTPUT_MIXER2, |
616 | WM8990_RLBRO_BIT, 1, 0), | 616 | WM8990_RLBRO_BIT, 1, 0), |
617 | SOC_DAPM_SINGLE("ROMIX Right ADC Bypass Switch", WM8990_OUTPUT_MIXER2, | 617 | SOC_DAPM_SINGLE("ROMIX Right ADC Bypass Switch", WM8990_OUTPUT_MIXER2, |
618 | WM8990_RRBRO_BIT, 1, 0), | 618 | WM8990_RRBRO_BIT, 1, 0), |
619 | SOC_DAPM_SINGLE("ROMIX LIN3 Bypass Switch", WM8990_OUTPUT_MIXER2, | 619 | SOC_DAPM_SINGLE("ROMIX LIN3 Bypass Switch", WM8990_OUTPUT_MIXER2, |
620 | WM8990_RLI3RO_BIT, 1, 0), | 620 | WM8990_RLI3RO_BIT, 1, 0), |
621 | SOC_DAPM_SINGLE("ROMIX RIN3 Bypass Switch", WM8990_OUTPUT_MIXER2, | 621 | SOC_DAPM_SINGLE("ROMIX RIN3 Bypass Switch", WM8990_OUTPUT_MIXER2, |
622 | WM8990_RRI3RO_BIT, 1, 0), | 622 | WM8990_RRI3RO_BIT, 1, 0), |
623 | SOC_DAPM_SINGLE("ROMIX LIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER2, | 623 | SOC_DAPM_SINGLE("ROMIX LIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER2, |
624 | WM8990_RL12RO_BIT, 1, 0), | 624 | WM8990_RL12RO_BIT, 1, 0), |
625 | SOC_DAPM_SINGLE("ROMIX RIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER2, | 625 | SOC_DAPM_SINGLE("ROMIX RIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER2, |
626 | WM8990_RR12RO_BIT, 1, 0), | 626 | WM8990_RR12RO_BIT, 1, 0), |
627 | SOC_DAPM_SINGLE("ROMIX Right DAC Switch", WM8990_OUTPUT_MIXER2, | 627 | SOC_DAPM_SINGLE("ROMIX Right DAC Switch", WM8990_OUTPUT_MIXER2, |
628 | WM8990_RDRO_BIT, 1, 0), | 628 | WM8990_RDRO_BIT, 1, 0), |
629 | }; | 629 | }; |
630 | 630 | ||
631 | /* LONMIX */ | 631 | /* LONMIX */ |
632 | static const struct snd_kcontrol_new wm8990_dapm_lonmix_controls[] = { | 632 | static const struct snd_kcontrol_new wm8990_dapm_lonmix_controls[] = { |
633 | SOC_DAPM_SINGLE("LONMIX Left Mixer PGA Switch", WM8990_LINE_MIXER1, | 633 | SOC_DAPM_SINGLE("LONMIX Left Mixer PGA Switch", WM8990_LINE_MIXER1, |
634 | WM8990_LLOPGALON_BIT, 1, 0), | 634 | WM8990_LLOPGALON_BIT, 1, 0), |
635 | SOC_DAPM_SINGLE("LONMIX Right Mixer PGA Switch", WM8990_LINE_MIXER1, | 635 | SOC_DAPM_SINGLE("LONMIX Right Mixer PGA Switch", WM8990_LINE_MIXER1, |
636 | WM8990_LROPGALON_BIT, 1, 0), | 636 | WM8990_LROPGALON_BIT, 1, 0), |
637 | SOC_DAPM_SINGLE("LONMIX Inverted LOP Switch", WM8990_LINE_MIXER1, | 637 | SOC_DAPM_SINGLE("LONMIX Inverted LOP Switch", WM8990_LINE_MIXER1, |
638 | WM8990_LOPLON_BIT, 1, 0), | 638 | WM8990_LOPLON_BIT, 1, 0), |
639 | }; | 639 | }; |
640 | 640 | ||
641 | /* LOPMIX */ | 641 | /* LOPMIX */ |
642 | static const struct snd_kcontrol_new wm8990_dapm_lopmix_controls[] = { | 642 | static const struct snd_kcontrol_new wm8990_dapm_lopmix_controls[] = { |
643 | SOC_DAPM_SINGLE("LOPMIX Right Mic Bypass Switch", WM8990_LINE_MIXER1, | 643 | SOC_DAPM_SINGLE("LOPMIX Right Mic Bypass Switch", WM8990_LINE_MIXER1, |
644 | WM8990_LR12LOP_BIT, 1, 0), | 644 | WM8990_LR12LOP_BIT, 1, 0), |
645 | SOC_DAPM_SINGLE("LOPMIX Left Mic Bypass Switch", WM8990_LINE_MIXER1, | 645 | SOC_DAPM_SINGLE("LOPMIX Left Mic Bypass Switch", WM8990_LINE_MIXER1, |
646 | WM8990_LL12LOP_BIT, 1, 0), | 646 | WM8990_LL12LOP_BIT, 1, 0), |
647 | SOC_DAPM_SINGLE("LOPMIX Left Mixer PGA Switch", WM8990_LINE_MIXER1, | 647 | SOC_DAPM_SINGLE("LOPMIX Left Mixer PGA Switch", WM8990_LINE_MIXER1, |
648 | WM8990_LLOPGALOP_BIT, 1, 0), | 648 | WM8990_LLOPGALOP_BIT, 1, 0), |
649 | }; | 649 | }; |
650 | 650 | ||
651 | /* RONMIX */ | 651 | /* RONMIX */ |
652 | static const struct snd_kcontrol_new wm8990_dapm_ronmix_controls[] = { | 652 | static const struct snd_kcontrol_new wm8990_dapm_ronmix_controls[] = { |
653 | SOC_DAPM_SINGLE("RONMIX Right Mixer PGA Switch", WM8990_LINE_MIXER2, | 653 | SOC_DAPM_SINGLE("RONMIX Right Mixer PGA Switch", WM8990_LINE_MIXER2, |
654 | WM8990_RROPGARON_BIT, 1, 0), | 654 | WM8990_RROPGARON_BIT, 1, 0), |
655 | SOC_DAPM_SINGLE("RONMIX Left Mixer PGA Switch", WM8990_LINE_MIXER2, | 655 | SOC_DAPM_SINGLE("RONMIX Left Mixer PGA Switch", WM8990_LINE_MIXER2, |
656 | WM8990_RLOPGARON_BIT, 1, 0), | 656 | WM8990_RLOPGARON_BIT, 1, 0), |
657 | SOC_DAPM_SINGLE("RONMIX Inverted ROP Switch", WM8990_LINE_MIXER2, | 657 | SOC_DAPM_SINGLE("RONMIX Inverted ROP Switch", WM8990_LINE_MIXER2, |
658 | WM8990_ROPRON_BIT, 1, 0), | 658 | WM8990_ROPRON_BIT, 1, 0), |
659 | }; | 659 | }; |
660 | 660 | ||
661 | /* ROPMIX */ | 661 | /* ROPMIX */ |
662 | static const struct snd_kcontrol_new wm8990_dapm_ropmix_controls[] = { | 662 | static const struct snd_kcontrol_new wm8990_dapm_ropmix_controls[] = { |
663 | SOC_DAPM_SINGLE("ROPMIX Left Mic Bypass Switch", WM8990_LINE_MIXER2, | 663 | SOC_DAPM_SINGLE("ROPMIX Left Mic Bypass Switch", WM8990_LINE_MIXER2, |
664 | WM8990_RL12ROP_BIT, 1, 0), | 664 | WM8990_RL12ROP_BIT, 1, 0), |
665 | SOC_DAPM_SINGLE("ROPMIX Right Mic Bypass Switch", WM8990_LINE_MIXER2, | 665 | SOC_DAPM_SINGLE("ROPMIX Right Mic Bypass Switch", WM8990_LINE_MIXER2, |
666 | WM8990_RR12ROP_BIT, 1, 0), | 666 | WM8990_RR12ROP_BIT, 1, 0), |
667 | SOC_DAPM_SINGLE("ROPMIX Right Mixer PGA Switch", WM8990_LINE_MIXER2, | 667 | SOC_DAPM_SINGLE("ROPMIX Right Mixer PGA Switch", WM8990_LINE_MIXER2, |
668 | WM8990_RROPGAROP_BIT, 1, 0), | 668 | WM8990_RROPGAROP_BIT, 1, 0), |
669 | }; | 669 | }; |
670 | 670 | ||
671 | /* OUT3MIX */ | 671 | /* OUT3MIX */ |
672 | static const struct snd_kcontrol_new wm8990_dapm_out3mix_controls[] = { | 672 | static const struct snd_kcontrol_new wm8990_dapm_out3mix_controls[] = { |
673 | SOC_DAPM_SINGLE("OUT3MIX LIN4/RXP Bypass Switch", WM8990_OUT3_4_MIXER, | 673 | SOC_DAPM_SINGLE("OUT3MIX LIN4/RXP Bypass Switch", WM8990_OUT3_4_MIXER, |
674 | WM8990_LI4O3_BIT, 1, 0), | 674 | WM8990_LI4O3_BIT, 1, 0), |
675 | SOC_DAPM_SINGLE("OUT3MIX Left Out PGA Switch", WM8990_OUT3_4_MIXER, | 675 | SOC_DAPM_SINGLE("OUT3MIX Left Out PGA Switch", WM8990_OUT3_4_MIXER, |
676 | WM8990_LPGAO3_BIT, 1, 0), | 676 | WM8990_LPGAO3_BIT, 1, 0), |
677 | }; | 677 | }; |
678 | 678 | ||
679 | /* OUT4MIX */ | 679 | /* OUT4MIX */ |
680 | static const struct snd_kcontrol_new wm8990_dapm_out4mix_controls[] = { | 680 | static const struct snd_kcontrol_new wm8990_dapm_out4mix_controls[] = { |
681 | SOC_DAPM_SINGLE("OUT4MIX Right Out PGA Switch", WM8990_OUT3_4_MIXER, | 681 | SOC_DAPM_SINGLE("OUT4MIX Right Out PGA Switch", WM8990_OUT3_4_MIXER, |
682 | WM8990_RPGAO4_BIT, 1, 0), | 682 | WM8990_RPGAO4_BIT, 1, 0), |
683 | SOC_DAPM_SINGLE("OUT4MIX RIN4/RXP Bypass Switch", WM8990_OUT3_4_MIXER, | 683 | SOC_DAPM_SINGLE("OUT4MIX RIN4/RXP Bypass Switch", WM8990_OUT3_4_MIXER, |
684 | WM8990_RI4O4_BIT, 1, 0), | 684 | WM8990_RI4O4_BIT, 1, 0), |
685 | }; | 685 | }; |
686 | 686 | ||
687 | /* SPKMIX */ | 687 | /* SPKMIX */ |
688 | static const struct snd_kcontrol_new wm8990_dapm_spkmix_controls[] = { | 688 | static const struct snd_kcontrol_new wm8990_dapm_spkmix_controls[] = { |
689 | SOC_DAPM_SINGLE("SPKMIX LIN2 Bypass Switch", WM8990_SPEAKER_MIXER, | 689 | SOC_DAPM_SINGLE("SPKMIX LIN2 Bypass Switch", WM8990_SPEAKER_MIXER, |
690 | WM8990_LI2SPK_BIT, 1, 0), | 690 | WM8990_LI2SPK_BIT, 1, 0), |
691 | SOC_DAPM_SINGLE("SPKMIX LADC Bypass Switch", WM8990_SPEAKER_MIXER, | 691 | SOC_DAPM_SINGLE("SPKMIX LADC Bypass Switch", WM8990_SPEAKER_MIXER, |
692 | WM8990_LB2SPK_BIT, 1, 0), | 692 | WM8990_LB2SPK_BIT, 1, 0), |
693 | SOC_DAPM_SINGLE("SPKMIX Left Mixer PGA Switch", WM8990_SPEAKER_MIXER, | 693 | SOC_DAPM_SINGLE("SPKMIX Left Mixer PGA Switch", WM8990_SPEAKER_MIXER, |
694 | WM8990_LOPGASPK_BIT, 1, 0), | 694 | WM8990_LOPGASPK_BIT, 1, 0), |
695 | SOC_DAPM_SINGLE("SPKMIX Left DAC Switch", WM8990_SPEAKER_MIXER, | 695 | SOC_DAPM_SINGLE("SPKMIX Left DAC Switch", WM8990_SPEAKER_MIXER, |
696 | WM8990_LDSPK_BIT, 1, 0), | 696 | WM8990_LDSPK_BIT, 1, 0), |
697 | SOC_DAPM_SINGLE("SPKMIX Right DAC Switch", WM8990_SPEAKER_MIXER, | 697 | SOC_DAPM_SINGLE("SPKMIX Right DAC Switch", WM8990_SPEAKER_MIXER, |
698 | WM8990_RDSPK_BIT, 1, 0), | 698 | WM8990_RDSPK_BIT, 1, 0), |
699 | SOC_DAPM_SINGLE("SPKMIX Right Mixer PGA Switch", WM8990_SPEAKER_MIXER, | 699 | SOC_DAPM_SINGLE("SPKMIX Right Mixer PGA Switch", WM8990_SPEAKER_MIXER, |
700 | WM8990_ROPGASPK_BIT, 1, 0), | 700 | WM8990_ROPGASPK_BIT, 1, 0), |
701 | SOC_DAPM_SINGLE("SPKMIX RADC Bypass Switch", WM8990_SPEAKER_MIXER, | 701 | SOC_DAPM_SINGLE("SPKMIX RADC Bypass Switch", WM8990_SPEAKER_MIXER, |
702 | WM8990_RL12ROP_BIT, 1, 0), | 702 | WM8990_RL12ROP_BIT, 1, 0), |
703 | SOC_DAPM_SINGLE("SPKMIX RIN2 Bypass Switch", WM8990_SPEAKER_MIXER, | 703 | SOC_DAPM_SINGLE("SPKMIX RIN2 Bypass Switch", WM8990_SPEAKER_MIXER, |
704 | WM8990_RI2SPK_BIT, 1, 0), | 704 | WM8990_RI2SPK_BIT, 1, 0), |
705 | }; | 705 | }; |
706 | 706 | ||
707 | static const struct snd_soc_dapm_widget wm8990_dapm_widgets[] = { | 707 | static const struct snd_soc_dapm_widget wm8990_dapm_widgets[] = { |
708 | /* Input Side */ | 708 | /* Input Side */ |
709 | /* Input Lines */ | 709 | /* Input Lines */ |
710 | SND_SOC_DAPM_INPUT("LIN1"), | 710 | SND_SOC_DAPM_INPUT("LIN1"), |
711 | SND_SOC_DAPM_INPUT("LIN2"), | 711 | SND_SOC_DAPM_INPUT("LIN2"), |
712 | SND_SOC_DAPM_INPUT("LIN3"), | 712 | SND_SOC_DAPM_INPUT("LIN3"), |
713 | SND_SOC_DAPM_INPUT("LIN4/RXN"), | 713 | SND_SOC_DAPM_INPUT("LIN4/RXN"), |
714 | SND_SOC_DAPM_INPUT("RIN3"), | 714 | SND_SOC_DAPM_INPUT("RIN3"), |
715 | SND_SOC_DAPM_INPUT("RIN4/RXP"), | 715 | SND_SOC_DAPM_INPUT("RIN4/RXP"), |
716 | SND_SOC_DAPM_INPUT("RIN1"), | 716 | SND_SOC_DAPM_INPUT("RIN1"), |
717 | SND_SOC_DAPM_INPUT("RIN2"), | 717 | SND_SOC_DAPM_INPUT("RIN2"), |
718 | SND_SOC_DAPM_INPUT("Internal ADC Source"), | 718 | SND_SOC_DAPM_INPUT("Internal ADC Source"), |
719 | 719 | ||
720 | /* DACs */ | 720 | /* DACs */ |
721 | SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8990_POWER_MANAGEMENT_2, | 721 | SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8990_POWER_MANAGEMENT_2, |
722 | WM8990_ADCL_ENA_BIT, 0), | 722 | WM8990_ADCL_ENA_BIT, 0), |
723 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8990_POWER_MANAGEMENT_2, | 723 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8990_POWER_MANAGEMENT_2, |
724 | WM8990_ADCR_ENA_BIT, 0), | 724 | WM8990_ADCR_ENA_BIT, 0), |
725 | 725 | ||
726 | /* Input PGAs */ | 726 | /* Input PGAs */ |
727 | SND_SOC_DAPM_MIXER("LIN12 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_LIN12_ENA_BIT, | 727 | SND_SOC_DAPM_MIXER("LIN12 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_LIN12_ENA_BIT, |
728 | 0, &wm8990_dapm_lin12_pga_controls[0], | 728 | 0, &wm8990_dapm_lin12_pga_controls[0], |
729 | ARRAY_SIZE(wm8990_dapm_lin12_pga_controls)), | 729 | ARRAY_SIZE(wm8990_dapm_lin12_pga_controls)), |
730 | SND_SOC_DAPM_MIXER("LIN34 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_LIN34_ENA_BIT, | 730 | SND_SOC_DAPM_MIXER("LIN34 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_LIN34_ENA_BIT, |
731 | 0, &wm8990_dapm_lin34_pga_controls[0], | 731 | 0, &wm8990_dapm_lin34_pga_controls[0], |
732 | ARRAY_SIZE(wm8990_dapm_lin34_pga_controls)), | 732 | ARRAY_SIZE(wm8990_dapm_lin34_pga_controls)), |
733 | SND_SOC_DAPM_MIXER("RIN12 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_RIN12_ENA_BIT, | 733 | SND_SOC_DAPM_MIXER("RIN12 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_RIN12_ENA_BIT, |
734 | 0, &wm8990_dapm_rin12_pga_controls[0], | 734 | 0, &wm8990_dapm_rin12_pga_controls[0], |
735 | ARRAY_SIZE(wm8990_dapm_rin12_pga_controls)), | 735 | ARRAY_SIZE(wm8990_dapm_rin12_pga_controls)), |
736 | SND_SOC_DAPM_MIXER("RIN34 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_RIN34_ENA_BIT, | 736 | SND_SOC_DAPM_MIXER("RIN34 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_RIN34_ENA_BIT, |
737 | 0, &wm8990_dapm_rin34_pga_controls[0], | 737 | 0, &wm8990_dapm_rin34_pga_controls[0], |
738 | ARRAY_SIZE(wm8990_dapm_rin34_pga_controls)), | 738 | ARRAY_SIZE(wm8990_dapm_rin34_pga_controls)), |
739 | 739 | ||
740 | /* INMIXL */ | 740 | /* INMIXL */ |
741 | SND_SOC_DAPM_MIXER_E("INMIXL", WM8990_INTDRIVBITS, WM8990_INMIXL_PWR_BIT, 0, | 741 | SND_SOC_DAPM_MIXER_E("INMIXL", WM8990_INTDRIVBITS, WM8990_INMIXL_PWR_BIT, 0, |
742 | &wm8990_dapm_inmixl_controls[0], | 742 | &wm8990_dapm_inmixl_controls[0], |
743 | ARRAY_SIZE(wm8990_dapm_inmixl_controls), | 743 | ARRAY_SIZE(wm8990_dapm_inmixl_controls), |
744 | inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | 744 | inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), |
745 | 745 | ||
746 | /* AINLMUX */ | 746 | /* AINLMUX */ |
747 | SND_SOC_DAPM_MUX_E("AILNMUX", WM8990_INTDRIVBITS, WM8990_AINLMUX_PWR_BIT, 0, | 747 | SND_SOC_DAPM_MUX_E("AILNMUX", WM8990_INTDRIVBITS, WM8990_AINLMUX_PWR_BIT, 0, |
748 | &wm8990_dapm_ainlmux_controls, inmixer_event, | 748 | &wm8990_dapm_ainlmux_controls, inmixer_event, |
749 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | 749 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), |
750 | 750 | ||
751 | /* INMIXR */ | 751 | /* INMIXR */ |
752 | SND_SOC_DAPM_MIXER_E("INMIXR", WM8990_INTDRIVBITS, WM8990_INMIXR_PWR_BIT, 0, | 752 | SND_SOC_DAPM_MIXER_E("INMIXR", WM8990_INTDRIVBITS, WM8990_INMIXR_PWR_BIT, 0, |
753 | &wm8990_dapm_inmixr_controls[0], | 753 | &wm8990_dapm_inmixr_controls[0], |
754 | ARRAY_SIZE(wm8990_dapm_inmixr_controls), | 754 | ARRAY_SIZE(wm8990_dapm_inmixr_controls), |
755 | inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | 755 | inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), |
756 | 756 | ||
757 | /* AINRMUX */ | 757 | /* AINRMUX */ |
758 | SND_SOC_DAPM_MUX_E("AIRNMUX", WM8990_INTDRIVBITS, WM8990_AINRMUX_PWR_BIT, 0, | 758 | SND_SOC_DAPM_MUX_E("AIRNMUX", WM8990_INTDRIVBITS, WM8990_AINRMUX_PWR_BIT, 0, |
759 | &wm8990_dapm_ainrmux_controls, inmixer_event, | 759 | &wm8990_dapm_ainrmux_controls, inmixer_event, |
760 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | 760 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), |
761 | 761 | ||
762 | /* Output Side */ | 762 | /* Output Side */ |
763 | /* DACs */ | 763 | /* DACs */ |
764 | SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8990_POWER_MANAGEMENT_3, | 764 | SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8990_POWER_MANAGEMENT_3, |
765 | WM8990_DACL_ENA_BIT, 0), | 765 | WM8990_DACL_ENA_BIT, 0), |
766 | SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8990_POWER_MANAGEMENT_3, | 766 | SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8990_POWER_MANAGEMENT_3, |
767 | WM8990_DACR_ENA_BIT, 0), | 767 | WM8990_DACR_ENA_BIT, 0), |
768 | 768 | ||
769 | /* LOMIX */ | 769 | /* LOMIX */ |
770 | SND_SOC_DAPM_MIXER_E("LOMIX", WM8990_POWER_MANAGEMENT_3, WM8990_LOMIX_ENA_BIT, | 770 | SND_SOC_DAPM_MIXER_E("LOMIX", WM8990_POWER_MANAGEMENT_3, WM8990_LOMIX_ENA_BIT, |
771 | 0, &wm8990_dapm_lomix_controls[0], | 771 | 0, &wm8990_dapm_lomix_controls[0], |
772 | ARRAY_SIZE(wm8990_dapm_lomix_controls), | 772 | ARRAY_SIZE(wm8990_dapm_lomix_controls), |
773 | outmixer_event, SND_SOC_DAPM_PRE_REG), | 773 | outmixer_event, SND_SOC_DAPM_PRE_REG), |
774 | 774 | ||
775 | /* LONMIX */ | 775 | /* LONMIX */ |
776 | SND_SOC_DAPM_MIXER("LONMIX", WM8990_POWER_MANAGEMENT_3, WM8990_LON_ENA_BIT, 0, | 776 | SND_SOC_DAPM_MIXER("LONMIX", WM8990_POWER_MANAGEMENT_3, WM8990_LON_ENA_BIT, 0, |
777 | &wm8990_dapm_lonmix_controls[0], | 777 | &wm8990_dapm_lonmix_controls[0], |
778 | ARRAY_SIZE(wm8990_dapm_lonmix_controls)), | 778 | ARRAY_SIZE(wm8990_dapm_lonmix_controls)), |
779 | 779 | ||
780 | /* LOPMIX */ | 780 | /* LOPMIX */ |
781 | SND_SOC_DAPM_MIXER("LOPMIX", WM8990_POWER_MANAGEMENT_3, WM8990_LOP_ENA_BIT, 0, | 781 | SND_SOC_DAPM_MIXER("LOPMIX", WM8990_POWER_MANAGEMENT_3, WM8990_LOP_ENA_BIT, 0, |
782 | &wm8990_dapm_lopmix_controls[0], | 782 | &wm8990_dapm_lopmix_controls[0], |
783 | ARRAY_SIZE(wm8990_dapm_lopmix_controls)), | 783 | ARRAY_SIZE(wm8990_dapm_lopmix_controls)), |
784 | 784 | ||
785 | /* OUT3MIX */ | 785 | /* OUT3MIX */ |
786 | SND_SOC_DAPM_MIXER("OUT3MIX", WM8990_POWER_MANAGEMENT_1, WM8990_OUT3_ENA_BIT, 0, | 786 | SND_SOC_DAPM_MIXER("OUT3MIX", WM8990_POWER_MANAGEMENT_1, WM8990_OUT3_ENA_BIT, 0, |
787 | &wm8990_dapm_out3mix_controls[0], | 787 | &wm8990_dapm_out3mix_controls[0], |
788 | ARRAY_SIZE(wm8990_dapm_out3mix_controls)), | 788 | ARRAY_SIZE(wm8990_dapm_out3mix_controls)), |
789 | 789 | ||
790 | /* SPKMIX */ | 790 | /* SPKMIX */ |
791 | SND_SOC_DAPM_MIXER_E("SPKMIX", WM8990_POWER_MANAGEMENT_1, WM8990_SPK_ENA_BIT, 0, | 791 | SND_SOC_DAPM_MIXER_E("SPKMIX", WM8990_POWER_MANAGEMENT_1, WM8990_SPK_ENA_BIT, 0, |
792 | &wm8990_dapm_spkmix_controls[0], | 792 | &wm8990_dapm_spkmix_controls[0], |
793 | ARRAY_SIZE(wm8990_dapm_spkmix_controls), outmixer_event, | 793 | ARRAY_SIZE(wm8990_dapm_spkmix_controls), outmixer_event, |
794 | SND_SOC_DAPM_PRE_REG), | 794 | SND_SOC_DAPM_PRE_REG), |
795 | 795 | ||
796 | /* OUT4MIX */ | 796 | /* OUT4MIX */ |
797 | SND_SOC_DAPM_MIXER("OUT4MIX", WM8990_POWER_MANAGEMENT_1, WM8990_OUT4_ENA_BIT, 0, | 797 | SND_SOC_DAPM_MIXER("OUT4MIX", WM8990_POWER_MANAGEMENT_1, WM8990_OUT4_ENA_BIT, 0, |
798 | &wm8990_dapm_out4mix_controls[0], | 798 | &wm8990_dapm_out4mix_controls[0], |
799 | ARRAY_SIZE(wm8990_dapm_out4mix_controls)), | 799 | ARRAY_SIZE(wm8990_dapm_out4mix_controls)), |
800 | 800 | ||
801 | /* ROPMIX */ | 801 | /* ROPMIX */ |
802 | SND_SOC_DAPM_MIXER("ROPMIX", WM8990_POWER_MANAGEMENT_3, WM8990_ROP_ENA_BIT, 0, | 802 | SND_SOC_DAPM_MIXER("ROPMIX", WM8990_POWER_MANAGEMENT_3, WM8990_ROP_ENA_BIT, 0, |
803 | &wm8990_dapm_ropmix_controls[0], | 803 | &wm8990_dapm_ropmix_controls[0], |
804 | ARRAY_SIZE(wm8990_dapm_ropmix_controls)), | 804 | ARRAY_SIZE(wm8990_dapm_ropmix_controls)), |
805 | 805 | ||
806 | /* RONMIX */ | 806 | /* RONMIX */ |
807 | SND_SOC_DAPM_MIXER("RONMIX", WM8990_POWER_MANAGEMENT_3, WM8990_RON_ENA_BIT, 0, | 807 | SND_SOC_DAPM_MIXER("RONMIX", WM8990_POWER_MANAGEMENT_3, WM8990_RON_ENA_BIT, 0, |
808 | &wm8990_dapm_ronmix_controls[0], | 808 | &wm8990_dapm_ronmix_controls[0], |
809 | ARRAY_SIZE(wm8990_dapm_ronmix_controls)), | 809 | ARRAY_SIZE(wm8990_dapm_ronmix_controls)), |
810 | 810 | ||
811 | /* ROMIX */ | 811 | /* ROMIX */ |
812 | SND_SOC_DAPM_MIXER_E("ROMIX", WM8990_POWER_MANAGEMENT_3, WM8990_ROMIX_ENA_BIT, | 812 | SND_SOC_DAPM_MIXER_E("ROMIX", WM8990_POWER_MANAGEMENT_3, WM8990_ROMIX_ENA_BIT, |
813 | 0, &wm8990_dapm_romix_controls[0], | 813 | 0, &wm8990_dapm_romix_controls[0], |
814 | ARRAY_SIZE(wm8990_dapm_romix_controls), | 814 | ARRAY_SIZE(wm8990_dapm_romix_controls), |
815 | outmixer_event, SND_SOC_DAPM_PRE_REG), | 815 | outmixer_event, SND_SOC_DAPM_PRE_REG), |
816 | 816 | ||
817 | /* LOUT PGA */ | 817 | /* LOUT PGA */ |
818 | SND_SOC_DAPM_PGA("LOUT PGA", WM8990_POWER_MANAGEMENT_1, WM8990_LOUT_ENA_BIT, 0, | 818 | SND_SOC_DAPM_PGA("LOUT PGA", WM8990_POWER_MANAGEMENT_1, WM8990_LOUT_ENA_BIT, 0, |
819 | NULL, 0), | 819 | NULL, 0), |
820 | 820 | ||
821 | /* ROUT PGA */ | 821 | /* ROUT PGA */ |
822 | SND_SOC_DAPM_PGA("ROUT PGA", WM8990_POWER_MANAGEMENT_1, WM8990_ROUT_ENA_BIT, 0, | 822 | SND_SOC_DAPM_PGA("ROUT PGA", WM8990_POWER_MANAGEMENT_1, WM8990_ROUT_ENA_BIT, 0, |
823 | NULL, 0), | 823 | NULL, 0), |
824 | 824 | ||
825 | /* LOPGA */ | 825 | /* LOPGA */ |
826 | SND_SOC_DAPM_PGA("LOPGA", WM8990_POWER_MANAGEMENT_3, WM8990_LOPGA_ENA_BIT, 0, | 826 | SND_SOC_DAPM_PGA("LOPGA", WM8990_POWER_MANAGEMENT_3, WM8990_LOPGA_ENA_BIT, 0, |
827 | NULL, 0), | 827 | NULL, 0), |
828 | 828 | ||
829 | /* ROPGA */ | 829 | /* ROPGA */ |
830 | SND_SOC_DAPM_PGA("ROPGA", WM8990_POWER_MANAGEMENT_3, WM8990_ROPGA_ENA_BIT, 0, | 830 | SND_SOC_DAPM_PGA("ROPGA", WM8990_POWER_MANAGEMENT_3, WM8990_ROPGA_ENA_BIT, 0, |
831 | NULL, 0), | 831 | NULL, 0), |
832 | 832 | ||
833 | /* MICBIAS */ | 833 | /* MICBIAS */ |
834 | SND_SOC_DAPM_MICBIAS("MICBIAS", WM8990_POWER_MANAGEMENT_1, | 834 | SND_SOC_DAPM_MICBIAS("MICBIAS", WM8990_POWER_MANAGEMENT_1, |
835 | WM8990_MICBIAS_ENA_BIT, 0), | 835 | WM8990_MICBIAS_ENA_BIT, 0), |
836 | 836 | ||
837 | SND_SOC_DAPM_OUTPUT("LON"), | 837 | SND_SOC_DAPM_OUTPUT("LON"), |
838 | SND_SOC_DAPM_OUTPUT("LOP"), | 838 | SND_SOC_DAPM_OUTPUT("LOP"), |
839 | SND_SOC_DAPM_OUTPUT("OUT3"), | 839 | SND_SOC_DAPM_OUTPUT("OUT3"), |
840 | SND_SOC_DAPM_OUTPUT("LOUT"), | 840 | SND_SOC_DAPM_OUTPUT("LOUT"), |
841 | SND_SOC_DAPM_OUTPUT("SPKN"), | 841 | SND_SOC_DAPM_OUTPUT("SPKN"), |
842 | SND_SOC_DAPM_OUTPUT("SPKP"), | 842 | SND_SOC_DAPM_OUTPUT("SPKP"), |
843 | SND_SOC_DAPM_OUTPUT("ROUT"), | 843 | SND_SOC_DAPM_OUTPUT("ROUT"), |
844 | SND_SOC_DAPM_OUTPUT("OUT4"), | 844 | SND_SOC_DAPM_OUTPUT("OUT4"), |
845 | SND_SOC_DAPM_OUTPUT("ROP"), | 845 | SND_SOC_DAPM_OUTPUT("ROP"), |
846 | SND_SOC_DAPM_OUTPUT("RON"), | 846 | SND_SOC_DAPM_OUTPUT("RON"), |
847 | 847 | ||
848 | SND_SOC_DAPM_OUTPUT("Internal DAC Sink"), | 848 | SND_SOC_DAPM_OUTPUT("Internal DAC Sink"), |
849 | }; | 849 | }; |
850 | 850 | ||
851 | static const struct snd_soc_dapm_route audio_map[] = { | 851 | static const struct snd_soc_dapm_route audio_map[] = { |
852 | /* Make DACs turn on when playing even if not mixed into any outputs */ | 852 | /* Make DACs turn on when playing even if not mixed into any outputs */ |
853 | {"Internal DAC Sink", NULL, "Left DAC"}, | 853 | {"Internal DAC Sink", NULL, "Left DAC"}, |
854 | {"Internal DAC Sink", NULL, "Right DAC"}, | 854 | {"Internal DAC Sink", NULL, "Right DAC"}, |
855 | 855 | ||
856 | /* Make ADCs turn on when recording even if not mixed from any inputs */ | 856 | /* Make ADCs turn on when recording even if not mixed from any inputs */ |
857 | {"Left ADC", NULL, "Internal ADC Source"}, | 857 | {"Left ADC", NULL, "Internal ADC Source"}, |
858 | {"Right ADC", NULL, "Internal ADC Source"}, | 858 | {"Right ADC", NULL, "Internal ADC Source"}, |
859 | 859 | ||
860 | /* Input Side */ | 860 | /* Input Side */ |
861 | /* LIN12 PGA */ | 861 | /* LIN12 PGA */ |
862 | {"LIN12 PGA", "LIN1 Switch", "LIN1"}, | 862 | {"LIN12 PGA", "LIN1 Switch", "LIN1"}, |
863 | {"LIN12 PGA", "LIN2 Switch", "LIN2"}, | 863 | {"LIN12 PGA", "LIN2 Switch", "LIN2"}, |
864 | /* LIN34 PGA */ | 864 | /* LIN34 PGA */ |
865 | {"LIN34 PGA", "LIN3 Switch", "LIN3"}, | 865 | {"LIN34 PGA", "LIN3 Switch", "LIN3"}, |
866 | {"LIN34 PGA", "LIN4 Switch", "LIN4"}, | 866 | {"LIN34 PGA", "LIN4 Switch", "LIN4"}, |
867 | /* INMIXL */ | 867 | /* INMIXL */ |
868 | {"INMIXL", "Record Left Volume", "LOMIX"}, | 868 | {"INMIXL", "Record Left Volume", "LOMIX"}, |
869 | {"INMIXL", "LIN2 Volume", "LIN2"}, | 869 | {"INMIXL", "LIN2 Volume", "LIN2"}, |
870 | {"INMIXL", "LINPGA12 Switch", "LIN12 PGA"}, | 870 | {"INMIXL", "LINPGA12 Switch", "LIN12 PGA"}, |
871 | {"INMIXL", "LINPGA34 Switch", "LIN34 PGA"}, | 871 | {"INMIXL", "LINPGA34 Switch", "LIN34 PGA"}, |
872 | /* AILNMUX */ | 872 | /* AILNMUX */ |
873 | {"AILNMUX", "INMIXL Mix", "INMIXL"}, | 873 | {"AILNMUX", "INMIXL Mix", "INMIXL"}, |
874 | {"AILNMUX", "DIFFINL Mix", "LIN12PGA"}, | 874 | {"AILNMUX", "DIFFINL Mix", "LIN12PGA"}, |
875 | {"AILNMUX", "DIFFINL Mix", "LIN34PGA"}, | 875 | {"AILNMUX", "DIFFINL Mix", "LIN34PGA"}, |
876 | {"AILNMUX", "RXVOICE Mix", "LIN4/RXN"}, | 876 | {"AILNMUX", "RXVOICE Mix", "LIN4/RXN"}, |
877 | {"AILNMUX", "RXVOICE Mix", "RIN4/RXP"}, | 877 | {"AILNMUX", "RXVOICE Mix", "RIN4/RXP"}, |
878 | /* ADC */ | 878 | /* ADC */ |
879 | {"Left ADC", NULL, "AILNMUX"}, | 879 | {"Left ADC", NULL, "AILNMUX"}, |
880 | 880 | ||
881 | /* RIN12 PGA */ | 881 | /* RIN12 PGA */ |
882 | {"RIN12 PGA", "RIN1 Switch", "RIN1"}, | 882 | {"RIN12 PGA", "RIN1 Switch", "RIN1"}, |
883 | {"RIN12 PGA", "RIN2 Switch", "RIN2"}, | 883 | {"RIN12 PGA", "RIN2 Switch", "RIN2"}, |
884 | /* RIN34 PGA */ | 884 | /* RIN34 PGA */ |
885 | {"RIN34 PGA", "RIN3 Switch", "RIN3"}, | 885 | {"RIN34 PGA", "RIN3 Switch", "RIN3"}, |
886 | {"RIN34 PGA", "RIN4 Switch", "RIN4"}, | 886 | {"RIN34 PGA", "RIN4 Switch", "RIN4"}, |
887 | /* INMIXL */ | 887 | /* INMIXL */ |
888 | {"INMIXR", "Record Right Volume", "ROMIX"}, | 888 | {"INMIXR", "Record Right Volume", "ROMIX"}, |
889 | {"INMIXR", "RIN2 Volume", "RIN2"}, | 889 | {"INMIXR", "RIN2 Volume", "RIN2"}, |
890 | {"INMIXR", "RINPGA12 Switch", "RIN12 PGA"}, | 890 | {"INMIXR", "RINPGA12 Switch", "RIN12 PGA"}, |
891 | {"INMIXR", "RINPGA34 Switch", "RIN34 PGA"}, | 891 | {"INMIXR", "RINPGA34 Switch", "RIN34 PGA"}, |
892 | /* AIRNMUX */ | 892 | /* AIRNMUX */ |
893 | {"AIRNMUX", "INMIXR Mix", "INMIXR"}, | 893 | {"AIRNMUX", "INMIXR Mix", "INMIXR"}, |
894 | {"AIRNMUX", "DIFFINR Mix", "RIN12PGA"}, | 894 | {"AIRNMUX", "DIFFINR Mix", "RIN12PGA"}, |
895 | {"AIRNMUX", "DIFFINR Mix", "RIN34PGA"}, | 895 | {"AIRNMUX", "DIFFINR Mix", "RIN34PGA"}, |
896 | {"AIRNMUX", "RXVOICE Mix", "RIN4/RXN"}, | 896 | {"AIRNMUX", "RXVOICE Mix", "RIN4/RXN"}, |
897 | {"AIRNMUX", "RXVOICE Mix", "RIN4/RXP"}, | 897 | {"AIRNMUX", "RXVOICE Mix", "RIN4/RXP"}, |
898 | /* ADC */ | 898 | /* ADC */ |
899 | {"Right ADC", NULL, "AIRNMUX"}, | 899 | {"Right ADC", NULL, "AIRNMUX"}, |
900 | 900 | ||
901 | /* LOMIX */ | 901 | /* LOMIX */ |
902 | {"LOMIX", "LOMIX RIN3 Bypass Switch", "RIN3"}, | 902 | {"LOMIX", "LOMIX RIN3 Bypass Switch", "RIN3"}, |
903 | {"LOMIX", "LOMIX LIN3 Bypass Switch", "LIN3"}, | 903 | {"LOMIX", "LOMIX LIN3 Bypass Switch", "LIN3"}, |
904 | {"LOMIX", "LOMIX LIN12 PGA Bypass Switch", "LIN12 PGA"}, | 904 | {"LOMIX", "LOMIX LIN12 PGA Bypass Switch", "LIN12 PGA"}, |
905 | {"LOMIX", "LOMIX RIN12 PGA Bypass Switch", "RIN12 PGA"}, | 905 | {"LOMIX", "LOMIX RIN12 PGA Bypass Switch", "RIN12 PGA"}, |
906 | {"LOMIX", "LOMIX Right ADC Bypass Switch", "AINRMUX"}, | 906 | {"LOMIX", "LOMIX Right ADC Bypass Switch", "AINRMUX"}, |
907 | {"LOMIX", "LOMIX Left ADC Bypass Switch", "AINLMUX"}, | 907 | {"LOMIX", "LOMIX Left ADC Bypass Switch", "AINLMUX"}, |
908 | {"LOMIX", "LOMIX Left DAC Switch", "Left DAC"}, | 908 | {"LOMIX", "LOMIX Left DAC Switch", "Left DAC"}, |
909 | 909 | ||
910 | /* ROMIX */ | 910 | /* ROMIX */ |
911 | {"ROMIX", "ROMIX RIN3 Bypass Switch", "RIN3"}, | 911 | {"ROMIX", "ROMIX RIN3 Bypass Switch", "RIN3"}, |
912 | {"ROMIX", "ROMIX LIN3 Bypass Switch", "LIN3"}, | 912 | {"ROMIX", "ROMIX LIN3 Bypass Switch", "LIN3"}, |
913 | {"ROMIX", "ROMIX LIN12 PGA Bypass Switch", "LIN12 PGA"}, | 913 | {"ROMIX", "ROMIX LIN12 PGA Bypass Switch", "LIN12 PGA"}, |
914 | {"ROMIX", "ROMIX RIN12 PGA Bypass Switch", "RIN12 PGA"}, | 914 | {"ROMIX", "ROMIX RIN12 PGA Bypass Switch", "RIN12 PGA"}, |
915 | {"ROMIX", "ROMIX Right ADC Bypass Switch", "AINRMUX"}, | 915 | {"ROMIX", "ROMIX Right ADC Bypass Switch", "AINRMUX"}, |
916 | {"ROMIX", "ROMIX Left ADC Bypass Switch", "AINLMUX"}, | 916 | {"ROMIX", "ROMIX Left ADC Bypass Switch", "AINLMUX"}, |
917 | {"ROMIX", "ROMIX Right DAC Switch", "Right DAC"}, | 917 | {"ROMIX", "ROMIX Right DAC Switch", "Right DAC"}, |
918 | 918 | ||
919 | /* SPKMIX */ | 919 | /* SPKMIX */ |
920 | {"SPKMIX", "SPKMIX LIN2 Bypass Switch", "LIN2"}, | 920 | {"SPKMIX", "SPKMIX LIN2 Bypass Switch", "LIN2"}, |
921 | {"SPKMIX", "SPKMIX RIN2 Bypass Switch", "RIN2"}, | 921 | {"SPKMIX", "SPKMIX RIN2 Bypass Switch", "RIN2"}, |
922 | {"SPKMIX", "SPKMIX LADC Bypass Switch", "AINLMUX"}, | 922 | {"SPKMIX", "SPKMIX LADC Bypass Switch", "AINLMUX"}, |
923 | {"SPKMIX", "SPKMIX RADC Bypass Switch", "AINRMUX"}, | 923 | {"SPKMIX", "SPKMIX RADC Bypass Switch", "AINRMUX"}, |
924 | {"SPKMIX", "SPKMIX Left Mixer PGA Switch", "LOPGA"}, | 924 | {"SPKMIX", "SPKMIX Left Mixer PGA Switch", "LOPGA"}, |
925 | {"SPKMIX", "SPKMIX Right Mixer PGA Switch", "ROPGA"}, | 925 | {"SPKMIX", "SPKMIX Right Mixer PGA Switch", "ROPGA"}, |
926 | {"SPKMIX", "SPKMIX Right DAC Switch", "Right DAC"}, | 926 | {"SPKMIX", "SPKMIX Right DAC Switch", "Right DAC"}, |
927 | {"SPKMIX", "SPKMIX Left DAC Switch", "Left DAC"}, | 927 | {"SPKMIX", "SPKMIX Left DAC Switch", "Left DAC"}, |
928 | 928 | ||
929 | /* LONMIX */ | 929 | /* LONMIX */ |
930 | {"LONMIX", "LONMIX Left Mixer PGA Switch", "LOPGA"}, | 930 | {"LONMIX", "LONMIX Left Mixer PGA Switch", "LOPGA"}, |
931 | {"LONMIX", "LONMIX Right Mixer PGA Switch", "ROPGA"}, | 931 | {"LONMIX", "LONMIX Right Mixer PGA Switch", "ROPGA"}, |
932 | {"LONMIX", "LONMIX Inverted LOP Switch", "LOPMIX"}, | 932 | {"LONMIX", "LONMIX Inverted LOP Switch", "LOPMIX"}, |
933 | 933 | ||
934 | /* LOPMIX */ | 934 | /* LOPMIX */ |
935 | {"LOPMIX", "LOPMIX Right Mic Bypass Switch", "RIN12 PGA"}, | 935 | {"LOPMIX", "LOPMIX Right Mic Bypass Switch", "RIN12 PGA"}, |
936 | {"LOPMIX", "LOPMIX Left Mic Bypass Switch", "LIN12 PGA"}, | 936 | {"LOPMIX", "LOPMIX Left Mic Bypass Switch", "LIN12 PGA"}, |
937 | {"LOPMIX", "LOPMIX Left Mixer PGA Switch", "LOPGA"}, | 937 | {"LOPMIX", "LOPMIX Left Mixer PGA Switch", "LOPGA"}, |
938 | 938 | ||
939 | /* OUT3MIX */ | 939 | /* OUT3MIX */ |
940 | {"OUT3MIX", "OUT3MIX LIN4/RXP Bypass Switch", "LIN4/RXP"}, | 940 | {"OUT3MIX", "OUT3MIX LIN4/RXP Bypass Switch", "LIN4/RXP"}, |
941 | {"OUT3MIX", "OUT3MIX Left Out PGA Switch", "LOPGA"}, | 941 | {"OUT3MIX", "OUT3MIX Left Out PGA Switch", "LOPGA"}, |
942 | 942 | ||
943 | /* OUT4MIX */ | 943 | /* OUT4MIX */ |
944 | {"OUT4MIX", "OUT4MIX Right Out PGA Switch", "ROPGA"}, | 944 | {"OUT4MIX", "OUT4MIX Right Out PGA Switch", "ROPGA"}, |
945 | {"OUT4MIX", "OUT4MIX RIN4/RXP Bypass Switch", "RIN4/RXP"}, | 945 | {"OUT4MIX", "OUT4MIX RIN4/RXP Bypass Switch", "RIN4/RXP"}, |
946 | 946 | ||
947 | /* RONMIX */ | 947 | /* RONMIX */ |
948 | {"RONMIX", "RONMIX Right Mixer PGA Switch", "ROPGA"}, | 948 | {"RONMIX", "RONMIX Right Mixer PGA Switch", "ROPGA"}, |
949 | {"RONMIX", "RONMIX Left Mixer PGA Switch", "LOPGA"}, | 949 | {"RONMIX", "RONMIX Left Mixer PGA Switch", "LOPGA"}, |
950 | {"RONMIX", "RONMIX Inverted ROP Switch", "ROPMIX"}, | 950 | {"RONMIX", "RONMIX Inverted ROP Switch", "ROPMIX"}, |
951 | 951 | ||
952 | /* ROPMIX */ | 952 | /* ROPMIX */ |
953 | {"ROPMIX", "ROPMIX Left Mic Bypass Switch", "LIN12 PGA"}, | 953 | {"ROPMIX", "ROPMIX Left Mic Bypass Switch", "LIN12 PGA"}, |
954 | {"ROPMIX", "ROPMIX Right Mic Bypass Switch", "RIN12 PGA"}, | 954 | {"ROPMIX", "ROPMIX Right Mic Bypass Switch", "RIN12 PGA"}, |
955 | {"ROPMIX", "ROPMIX Right Mixer PGA Switch", "ROPGA"}, | 955 | {"ROPMIX", "ROPMIX Right Mixer PGA Switch", "ROPGA"}, |
956 | 956 | ||
957 | /* Out Mixer PGAs */ | 957 | /* Out Mixer PGAs */ |
958 | {"LOPGA", NULL, "LOMIX"}, | 958 | {"LOPGA", NULL, "LOMIX"}, |
959 | {"ROPGA", NULL, "ROMIX"}, | 959 | {"ROPGA", NULL, "ROMIX"}, |
960 | 960 | ||
961 | {"LOUT PGA", NULL, "LOMIX"}, | 961 | {"LOUT PGA", NULL, "LOMIX"}, |
962 | {"ROUT PGA", NULL, "ROMIX"}, | 962 | {"ROUT PGA", NULL, "ROMIX"}, |
963 | 963 | ||
964 | /* Output Pins */ | 964 | /* Output Pins */ |
965 | {"LON", NULL, "LONMIX"}, | 965 | {"LON", NULL, "LONMIX"}, |
966 | {"LOP", NULL, "LOPMIX"}, | 966 | {"LOP", NULL, "LOPMIX"}, |
967 | {"OUT", NULL, "OUT3MIX"}, | 967 | {"OUT", NULL, "OUT3MIX"}, |
968 | {"LOUT", NULL, "LOUT PGA"}, | 968 | {"LOUT", NULL, "LOUT PGA"}, |
969 | {"SPKN", NULL, "SPKMIX"}, | 969 | {"SPKN", NULL, "SPKMIX"}, |
970 | {"ROUT", NULL, "ROUT PGA"}, | 970 | {"ROUT", NULL, "ROUT PGA"}, |
971 | {"OUT4", NULL, "OUT4MIX"}, | 971 | {"OUT4", NULL, "OUT4MIX"}, |
972 | {"ROP", NULL, "ROPMIX"}, | 972 | {"ROP", NULL, "ROPMIX"}, |
973 | {"RON", NULL, "RONMIX"}, | 973 | {"RON", NULL, "RONMIX"}, |
974 | }; | 974 | }; |
975 | 975 | ||
976 | static int wm8990_add_widgets(struct snd_soc_codec *codec) | 976 | static int wm8990_add_widgets(struct snd_soc_codec *codec) |
977 | { | 977 | { |
978 | snd_soc_dapm_new_controls(codec, wm8990_dapm_widgets, | 978 | snd_soc_dapm_new_controls(codec, wm8990_dapm_widgets, |
979 | ARRAY_SIZE(wm8990_dapm_widgets)); | 979 | ARRAY_SIZE(wm8990_dapm_widgets)); |
980 | 980 | ||
981 | /* set up the WM8990 audio map */ | 981 | /* set up the WM8990 audio map */ |
982 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | 982 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
983 | 983 | ||
984 | snd_soc_dapm_new_widgets(codec); | 984 | snd_soc_dapm_new_widgets(codec); |
985 | return 0; | 985 | return 0; |
986 | } | 986 | } |
987 | 987 | ||
988 | /* PLL divisors */ | 988 | /* PLL divisors */ |
989 | struct _pll_div { | 989 | struct _pll_div { |
990 | u32 div2; | 990 | u32 div2; |
991 | u32 n; | 991 | u32 n; |
992 | u32 k; | 992 | u32 k; |
993 | }; | 993 | }; |
994 | 994 | ||
995 | /* The size in bits of the pll divide multiplied by 10 | 995 | /* The size in bits of the pll divide multiplied by 10 |
996 | * to allow rounding later */ | 996 | * to allow rounding later */ |
997 | #define FIXED_PLL_SIZE ((1 << 16) * 10) | 997 | #define FIXED_PLL_SIZE ((1 << 16) * 10) |
998 | 998 | ||
999 | static void pll_factors(struct _pll_div *pll_div, unsigned int target, | 999 | static void pll_factors(struct _pll_div *pll_div, unsigned int target, |
1000 | unsigned int source) | 1000 | unsigned int source) |
1001 | { | 1001 | { |
1002 | u64 Kpart; | 1002 | u64 Kpart; |
1003 | unsigned int K, Ndiv, Nmod; | 1003 | unsigned int K, Ndiv, Nmod; |
1004 | 1004 | ||
1005 | 1005 | ||
1006 | Ndiv = target / source; | 1006 | Ndiv = target / source; |
1007 | if (Ndiv < 6) { | 1007 | if (Ndiv < 6) { |
1008 | source >>= 1; | 1008 | source >>= 1; |
1009 | pll_div->div2 = 1; | 1009 | pll_div->div2 = 1; |
1010 | Ndiv = target / source; | 1010 | Ndiv = target / source; |
1011 | } else | 1011 | } else |
1012 | pll_div->div2 = 0; | 1012 | pll_div->div2 = 0; |
1013 | 1013 | ||
1014 | if ((Ndiv < 6) || (Ndiv > 12)) | 1014 | if ((Ndiv < 6) || (Ndiv > 12)) |
1015 | printk(KERN_WARNING | 1015 | printk(KERN_WARNING |
1016 | "WM8990 N value outwith recommended range! N = %d\n", Ndiv); | 1016 | "WM8990 N value outwith recommended range! N = %d\n", Ndiv); |
1017 | 1017 | ||
1018 | pll_div->n = Ndiv; | 1018 | pll_div->n = Ndiv; |
1019 | Nmod = target % source; | 1019 | Nmod = target % source; |
1020 | Kpart = FIXED_PLL_SIZE * (long long)Nmod; | 1020 | Kpart = FIXED_PLL_SIZE * (long long)Nmod; |
1021 | 1021 | ||
1022 | do_div(Kpart, source); | 1022 | do_div(Kpart, source); |
1023 | 1023 | ||
1024 | K = Kpart & 0xFFFFFFFF; | 1024 | K = Kpart & 0xFFFFFFFF; |
1025 | 1025 | ||
1026 | /* Check if we need to round */ | 1026 | /* Check if we need to round */ |
1027 | if ((K % 10) >= 5) | 1027 | if ((K % 10) >= 5) |
1028 | K += 5; | 1028 | K += 5; |
1029 | 1029 | ||
1030 | /* Move down to proper range now rounding is done */ | 1030 | /* Move down to proper range now rounding is done */ |
1031 | K /= 10; | 1031 | K /= 10; |
1032 | 1032 | ||
1033 | pll_div->k = K; | 1033 | pll_div->k = K; |
1034 | } | 1034 | } |
1035 | 1035 | ||
1036 | static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai, | 1036 | static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai, |
1037 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 1037 | int pll_id, unsigned int freq_in, unsigned int freq_out) |
1038 | { | 1038 | { |
1039 | u16 reg; | 1039 | u16 reg; |
1040 | struct snd_soc_codec *codec = codec_dai->codec; | 1040 | struct snd_soc_codec *codec = codec_dai->codec; |
1041 | struct _pll_div pll_div; | 1041 | struct _pll_div pll_div; |
1042 | 1042 | ||
1043 | if (freq_in && freq_out) { | 1043 | if (freq_in && freq_out) { |
1044 | pll_factors(&pll_div, freq_out * 4, freq_in); | 1044 | pll_factors(&pll_div, freq_out * 4, freq_in); |
1045 | 1045 | ||
1046 | /* Turn on PLL */ | 1046 | /* Turn on PLL */ |
1047 | reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2); | 1047 | reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2); |
1048 | reg |= WM8990_PLL_ENA; | 1048 | reg |= WM8990_PLL_ENA; |
1049 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg); | 1049 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg); |
1050 | 1050 | ||
1051 | /* sysclk comes from PLL */ | 1051 | /* sysclk comes from PLL */ |
1052 | reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2); | 1052 | reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2); |
1053 | wm8990_write(codec, WM8990_CLOCKING_2, reg | WM8990_SYSCLK_SRC); | 1053 | wm8990_write(codec, WM8990_CLOCKING_2, reg | WM8990_SYSCLK_SRC); |
1054 | 1054 | ||
1055 | /* set up N , fractional mode and pre-divisor if neccessary */ | 1055 | /* set up N , fractional mode and pre-divisor if neccessary */ |
1056 | wm8990_write(codec, WM8990_PLL1, pll_div.n | WM8990_SDM | | 1056 | wm8990_write(codec, WM8990_PLL1, pll_div.n | WM8990_SDM | |
1057 | (pll_div.div2?WM8990_PRESCALE:0)); | 1057 | (pll_div.div2?WM8990_PRESCALE:0)); |
1058 | wm8990_write(codec, WM8990_PLL2, (u8)(pll_div.k>>8)); | 1058 | wm8990_write(codec, WM8990_PLL2, (u8)(pll_div.k>>8)); |
1059 | wm8990_write(codec, WM8990_PLL3, (u8)(pll_div.k & 0xFF)); | 1059 | wm8990_write(codec, WM8990_PLL3, (u8)(pll_div.k & 0xFF)); |
1060 | } else { | 1060 | } else { |
1061 | /* Turn on PLL */ | 1061 | /* Turn on PLL */ |
1062 | reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2); | 1062 | reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2); |
1063 | reg &= ~WM8990_PLL_ENA; | 1063 | reg &= ~WM8990_PLL_ENA; |
1064 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg); | 1064 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg); |
1065 | } | 1065 | } |
1066 | return 0; | 1066 | return 0; |
1067 | } | 1067 | } |
1068 | 1068 | ||
1069 | /* | 1069 | /* |
1070 | * Clock after PLL and dividers | 1070 | * Clock after PLL and dividers |
1071 | */ | 1071 | */ |
1072 | static int wm8990_set_dai_sysclk(struct snd_soc_dai *codec_dai, | 1072 | static int wm8990_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
1073 | int clk_id, unsigned int freq, int dir) | 1073 | int clk_id, unsigned int freq, int dir) |
1074 | { | 1074 | { |
1075 | struct snd_soc_codec *codec = codec_dai->codec; | 1075 | struct snd_soc_codec *codec = codec_dai->codec; |
1076 | struct wm8990_priv *wm8990 = codec->private_data; | 1076 | struct wm8990_priv *wm8990 = codec->private_data; |
1077 | 1077 | ||
1078 | wm8990->sysclk = freq; | 1078 | wm8990->sysclk = freq; |
1079 | return 0; | 1079 | return 0; |
1080 | } | 1080 | } |
1081 | 1081 | ||
1082 | /* | 1082 | /* |
1083 | * Set's ADC and Voice DAC format. | 1083 | * Set's ADC and Voice DAC format. |
1084 | */ | 1084 | */ |
1085 | static int wm8990_set_dai_fmt(struct snd_soc_dai *codec_dai, | 1085 | static int wm8990_set_dai_fmt(struct snd_soc_dai *codec_dai, |
1086 | unsigned int fmt) | 1086 | unsigned int fmt) |
1087 | { | 1087 | { |
1088 | struct snd_soc_codec *codec = codec_dai->codec; | 1088 | struct snd_soc_codec *codec = codec_dai->codec; |
1089 | u16 audio1, audio3; | 1089 | u16 audio1, audio3; |
1090 | 1090 | ||
1091 | audio1 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_1); | 1091 | audio1 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_1); |
1092 | audio3 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_3); | 1092 | audio3 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_3); |
1093 | 1093 | ||
1094 | /* set master/slave audio interface */ | 1094 | /* set master/slave audio interface */ |
1095 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 1095 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
1096 | case SND_SOC_DAIFMT_CBS_CFS: | 1096 | case SND_SOC_DAIFMT_CBS_CFS: |
1097 | audio3 &= ~WM8990_AIF_MSTR1; | 1097 | audio3 &= ~WM8990_AIF_MSTR1; |
1098 | break; | 1098 | break; |
1099 | case SND_SOC_DAIFMT_CBM_CFM: | 1099 | case SND_SOC_DAIFMT_CBM_CFM: |
1100 | audio3 |= WM8990_AIF_MSTR1; | 1100 | audio3 |= WM8990_AIF_MSTR1; |
1101 | break; | 1101 | break; |
1102 | default: | 1102 | default: |
1103 | return -EINVAL; | 1103 | return -EINVAL; |
1104 | } | 1104 | } |
1105 | 1105 | ||
1106 | audio1 &= ~WM8990_AIF_FMT_MASK; | 1106 | audio1 &= ~WM8990_AIF_FMT_MASK; |
1107 | 1107 | ||
1108 | /* interface format */ | 1108 | /* interface format */ |
1109 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 1109 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
1110 | case SND_SOC_DAIFMT_I2S: | 1110 | case SND_SOC_DAIFMT_I2S: |
1111 | audio1 |= WM8990_AIF_TMF_I2S; | 1111 | audio1 |= WM8990_AIF_TMF_I2S; |
1112 | audio1 &= ~WM8990_AIF_LRCLK_INV; | 1112 | audio1 &= ~WM8990_AIF_LRCLK_INV; |
1113 | break; | 1113 | break; |
1114 | case SND_SOC_DAIFMT_RIGHT_J: | 1114 | case SND_SOC_DAIFMT_RIGHT_J: |
1115 | audio1 |= WM8990_AIF_TMF_RIGHTJ; | 1115 | audio1 |= WM8990_AIF_TMF_RIGHTJ; |
1116 | audio1 &= ~WM8990_AIF_LRCLK_INV; | 1116 | audio1 &= ~WM8990_AIF_LRCLK_INV; |
1117 | break; | 1117 | break; |
1118 | case SND_SOC_DAIFMT_LEFT_J: | 1118 | case SND_SOC_DAIFMT_LEFT_J: |
1119 | audio1 |= WM8990_AIF_TMF_LEFTJ; | 1119 | audio1 |= WM8990_AIF_TMF_LEFTJ; |
1120 | audio1 &= ~WM8990_AIF_LRCLK_INV; | 1120 | audio1 &= ~WM8990_AIF_LRCLK_INV; |
1121 | break; | 1121 | break; |
1122 | case SND_SOC_DAIFMT_DSP_A: | 1122 | case SND_SOC_DAIFMT_DSP_A: |
1123 | audio1 |= WM8990_AIF_TMF_DSP; | 1123 | audio1 |= WM8990_AIF_TMF_DSP; |
1124 | audio1 &= ~WM8990_AIF_LRCLK_INV; | 1124 | audio1 &= ~WM8990_AIF_LRCLK_INV; |
1125 | break; | 1125 | break; |
1126 | case SND_SOC_DAIFMT_DSP_B: | 1126 | case SND_SOC_DAIFMT_DSP_B: |
1127 | audio1 |= WM8990_AIF_TMF_DSP | WM8990_AIF_LRCLK_INV; | 1127 | audio1 |= WM8990_AIF_TMF_DSP | WM8990_AIF_LRCLK_INV; |
1128 | break; | 1128 | break; |
1129 | default: | 1129 | default: |
1130 | return -EINVAL; | 1130 | return -EINVAL; |
1131 | } | 1131 | } |
1132 | 1132 | ||
1133 | wm8990_write(codec, WM8990_AUDIO_INTERFACE_1, audio1); | 1133 | wm8990_write(codec, WM8990_AUDIO_INTERFACE_1, audio1); |
1134 | wm8990_write(codec, WM8990_AUDIO_INTERFACE_3, audio3); | 1134 | wm8990_write(codec, WM8990_AUDIO_INTERFACE_3, audio3); |
1135 | return 0; | 1135 | return 0; |
1136 | } | 1136 | } |
1137 | 1137 | ||
1138 | static int wm8990_set_dai_clkdiv(struct snd_soc_dai *codec_dai, | 1138 | static int wm8990_set_dai_clkdiv(struct snd_soc_dai *codec_dai, |
1139 | int div_id, int div) | 1139 | int div_id, int div) |
1140 | { | 1140 | { |
1141 | struct snd_soc_codec *codec = codec_dai->codec; | 1141 | struct snd_soc_codec *codec = codec_dai->codec; |
1142 | u16 reg; | 1142 | u16 reg; |
1143 | 1143 | ||
1144 | switch (div_id) { | 1144 | switch (div_id) { |
1145 | case WM8990_MCLK_DIV: | 1145 | case WM8990_MCLK_DIV: |
1146 | reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) & | 1146 | reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) & |
1147 | ~WM8990_MCLK_DIV_MASK; | 1147 | ~WM8990_MCLK_DIV_MASK; |
1148 | wm8990_write(codec, WM8990_CLOCKING_2, reg | div); | 1148 | wm8990_write(codec, WM8990_CLOCKING_2, reg | div); |
1149 | break; | 1149 | break; |
1150 | case WM8990_DACCLK_DIV: | 1150 | case WM8990_DACCLK_DIV: |
1151 | reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) & | 1151 | reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) & |
1152 | ~WM8990_DAC_CLKDIV_MASK; | 1152 | ~WM8990_DAC_CLKDIV_MASK; |
1153 | wm8990_write(codec, WM8990_CLOCKING_2, reg | div); | 1153 | wm8990_write(codec, WM8990_CLOCKING_2, reg | div); |
1154 | break; | 1154 | break; |
1155 | case WM8990_ADCCLK_DIV: | 1155 | case WM8990_ADCCLK_DIV: |
1156 | reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) & | 1156 | reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) & |
1157 | ~WM8990_ADC_CLKDIV_MASK; | 1157 | ~WM8990_ADC_CLKDIV_MASK; |
1158 | wm8990_write(codec, WM8990_CLOCKING_2, reg | div); | 1158 | wm8990_write(codec, WM8990_CLOCKING_2, reg | div); |
1159 | break; | 1159 | break; |
1160 | case WM8990_BCLK_DIV: | 1160 | case WM8990_BCLK_DIV: |
1161 | reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_1) & | 1161 | reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_1) & |
1162 | ~WM8990_BCLK_DIV_MASK; | 1162 | ~WM8990_BCLK_DIV_MASK; |
1163 | wm8990_write(codec, WM8990_CLOCKING_1, reg | div); | 1163 | wm8990_write(codec, WM8990_CLOCKING_1, reg | div); |
1164 | break; | 1164 | break; |
1165 | default: | 1165 | default: |
1166 | return -EINVAL; | 1166 | return -EINVAL; |
1167 | } | 1167 | } |
1168 | 1168 | ||
1169 | return 0; | 1169 | return 0; |
1170 | } | 1170 | } |
1171 | 1171 | ||
1172 | /* | 1172 | /* |
1173 | * Set PCM DAI bit size and sample rate. | 1173 | * Set PCM DAI bit size and sample rate. |
1174 | */ | 1174 | */ |
1175 | static int wm8990_hw_params(struct snd_pcm_substream *substream, | 1175 | static int wm8990_hw_params(struct snd_pcm_substream *substream, |
1176 | struct snd_pcm_hw_params *params) | 1176 | struct snd_pcm_hw_params *params) |
1177 | { | 1177 | { |
1178 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 1178 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
1179 | struct snd_soc_device *socdev = rtd->socdev; | 1179 | struct snd_soc_device *socdev = rtd->socdev; |
1180 | struct snd_soc_codec *codec = socdev->codec; | 1180 | struct snd_soc_codec *codec = socdev->codec; |
1181 | u16 audio1 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_1); | 1181 | u16 audio1 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_1); |
1182 | 1182 | ||
1183 | audio1 &= ~WM8990_AIF_WL_MASK; | 1183 | audio1 &= ~WM8990_AIF_WL_MASK; |
1184 | /* bit size */ | 1184 | /* bit size */ |
1185 | switch (params_format(params)) { | 1185 | switch (params_format(params)) { |
1186 | case SNDRV_PCM_FORMAT_S16_LE: | 1186 | case SNDRV_PCM_FORMAT_S16_LE: |
1187 | break; | 1187 | break; |
1188 | case SNDRV_PCM_FORMAT_S20_3LE: | 1188 | case SNDRV_PCM_FORMAT_S20_3LE: |
1189 | audio1 |= WM8990_AIF_WL_20BITS; | 1189 | audio1 |= WM8990_AIF_WL_20BITS; |
1190 | break; | 1190 | break; |
1191 | case SNDRV_PCM_FORMAT_S24_LE: | 1191 | case SNDRV_PCM_FORMAT_S24_LE: |
1192 | audio1 |= WM8990_AIF_WL_24BITS; | 1192 | audio1 |= WM8990_AIF_WL_24BITS; |
1193 | break; | 1193 | break; |
1194 | case SNDRV_PCM_FORMAT_S32_LE: | 1194 | case SNDRV_PCM_FORMAT_S32_LE: |
1195 | audio1 |= WM8990_AIF_WL_32BITS; | 1195 | audio1 |= WM8990_AIF_WL_32BITS; |
1196 | break; | 1196 | break; |
1197 | } | 1197 | } |
1198 | 1198 | ||
1199 | wm8990_write(codec, WM8990_AUDIO_INTERFACE_1, audio1); | 1199 | wm8990_write(codec, WM8990_AUDIO_INTERFACE_1, audio1); |
1200 | return 0; | 1200 | return 0; |
1201 | } | 1201 | } |
1202 | 1202 | ||
1203 | static int wm8990_mute(struct snd_soc_dai *dai, int mute) | 1203 | static int wm8990_mute(struct snd_soc_dai *dai, int mute) |
1204 | { | 1204 | { |
1205 | struct snd_soc_codec *codec = dai->codec; | 1205 | struct snd_soc_codec *codec = dai->codec; |
1206 | u16 val; | 1206 | u16 val; |
1207 | 1207 | ||
1208 | val = wm8990_read_reg_cache(codec, WM8990_DAC_CTRL) & ~WM8990_DAC_MUTE; | 1208 | val = wm8990_read_reg_cache(codec, WM8990_DAC_CTRL) & ~WM8990_DAC_MUTE; |
1209 | 1209 | ||
1210 | if (mute) | 1210 | if (mute) |
1211 | wm8990_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE); | 1211 | wm8990_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE); |
1212 | else | 1212 | else |
1213 | wm8990_write(codec, WM8990_DAC_CTRL, val); | 1213 | wm8990_write(codec, WM8990_DAC_CTRL, val); |
1214 | 1214 | ||
1215 | return 0; | 1215 | return 0; |
1216 | } | 1216 | } |
1217 | 1217 | ||
1218 | static int wm8990_set_bias_level(struct snd_soc_codec *codec, | 1218 | static int wm8990_set_bias_level(struct snd_soc_codec *codec, |
1219 | enum snd_soc_bias_level level) | 1219 | enum snd_soc_bias_level level) |
1220 | { | 1220 | { |
1221 | u16 val; | 1221 | u16 val; |
1222 | 1222 | ||
1223 | switch (level) { | 1223 | switch (level) { |
1224 | case SND_SOC_BIAS_ON: | 1224 | case SND_SOC_BIAS_ON: |
1225 | break; | 1225 | break; |
1226 | case SND_SOC_BIAS_PREPARE: | 1226 | case SND_SOC_BIAS_PREPARE: |
1227 | break; | 1227 | break; |
1228 | case SND_SOC_BIAS_STANDBY: | 1228 | case SND_SOC_BIAS_STANDBY: |
1229 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | 1229 | if (codec->bias_level == SND_SOC_BIAS_OFF) { |
1230 | /* Enable all output discharge bits */ | 1230 | /* Enable all output discharge bits */ |
1231 | wm8990_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE | | 1231 | wm8990_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE | |
1232 | WM8990_DIS_RLINE | WM8990_DIS_OUT3 | | 1232 | WM8990_DIS_RLINE | WM8990_DIS_OUT3 | |
1233 | WM8990_DIS_OUT4 | WM8990_DIS_LOUT | | 1233 | WM8990_DIS_OUT4 | WM8990_DIS_LOUT | |
1234 | WM8990_DIS_ROUT); | 1234 | WM8990_DIS_ROUT); |
1235 | 1235 | ||
1236 | /* Enable POBCTRL, SOFT_ST, VMIDTOG and BUFDCOPEN */ | 1236 | /* Enable POBCTRL, SOFT_ST, VMIDTOG and BUFDCOPEN */ |
1237 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | | 1237 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | |
1238 | WM8990_BUFDCOPEN | WM8990_POBCTRL | | 1238 | WM8990_BUFDCOPEN | WM8990_POBCTRL | |
1239 | WM8990_VMIDTOG); | 1239 | WM8990_VMIDTOG); |
1240 | 1240 | ||
1241 | /* Delay to allow output caps to discharge */ | 1241 | /* Delay to allow output caps to discharge */ |
1242 | msleep(msecs_to_jiffies(300)); | 1242 | msleep(msecs_to_jiffies(300)); |
1243 | 1243 | ||
1244 | /* Disable VMIDTOG */ | 1244 | /* Disable VMIDTOG */ |
1245 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | | 1245 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | |
1246 | WM8990_BUFDCOPEN | WM8990_POBCTRL); | 1246 | WM8990_BUFDCOPEN | WM8990_POBCTRL); |
1247 | 1247 | ||
1248 | /* disable all output discharge bits */ | 1248 | /* disable all output discharge bits */ |
1249 | wm8990_write(codec, WM8990_ANTIPOP1, 0); | 1249 | wm8990_write(codec, WM8990_ANTIPOP1, 0); |
1250 | 1250 | ||
1251 | /* Enable outputs */ | 1251 | /* Enable outputs */ |
1252 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1b00); | 1252 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1b00); |
1253 | 1253 | ||
1254 | msleep(msecs_to_jiffies(50)); | 1254 | msleep(msecs_to_jiffies(50)); |
1255 | 1255 | ||
1256 | /* Enable VMID at 2x50k */ | 1256 | /* Enable VMID at 2x50k */ |
1257 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f02); | 1257 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f02); |
1258 | 1258 | ||
1259 | msleep(msecs_to_jiffies(100)); | 1259 | msleep(msecs_to_jiffies(100)); |
1260 | 1260 | ||
1261 | /* Enable VREF */ | 1261 | /* Enable VREF */ |
1262 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03); | 1262 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03); |
1263 | 1263 | ||
1264 | msleep(msecs_to_jiffies(600)); | 1264 | msleep(msecs_to_jiffies(600)); |
1265 | 1265 | ||
1266 | /* Enable BUFIOEN */ | 1266 | /* Enable BUFIOEN */ |
1267 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | | 1267 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | |
1268 | WM8990_BUFDCOPEN | WM8990_POBCTRL | | 1268 | WM8990_BUFDCOPEN | WM8990_POBCTRL | |
1269 | WM8990_BUFIOEN); | 1269 | WM8990_BUFIOEN); |
1270 | 1270 | ||
1271 | /* Disable outputs */ | 1271 | /* Disable outputs */ |
1272 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x3); | 1272 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x3); |
1273 | 1273 | ||
1274 | /* disable POBCTRL, SOFT_ST and BUFDCOPEN */ | 1274 | /* disable POBCTRL, SOFT_ST and BUFDCOPEN */ |
1275 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_BUFIOEN); | 1275 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_BUFIOEN); |
1276 | } else { | 1276 | } else { |
1277 | /* ON -> standby */ | 1277 | /* ON -> standby */ |
1278 | 1278 | ||
1279 | } | 1279 | } |
1280 | break; | 1280 | break; |
1281 | 1281 | ||
1282 | case SND_SOC_BIAS_OFF: | 1282 | case SND_SOC_BIAS_OFF: |
1283 | /* Enable POBCTRL and SOFT_ST */ | 1283 | /* Enable POBCTRL and SOFT_ST */ |
1284 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | | 1284 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | |
1285 | WM8990_POBCTRL | WM8990_BUFIOEN); | 1285 | WM8990_POBCTRL | WM8990_BUFIOEN); |
1286 | 1286 | ||
1287 | /* Enable POBCTRL, SOFT_ST and BUFDCOPEN */ | 1287 | /* Enable POBCTRL, SOFT_ST and BUFDCOPEN */ |
1288 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | | 1288 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | |
1289 | WM8990_BUFDCOPEN | WM8990_POBCTRL | | 1289 | WM8990_BUFDCOPEN | WM8990_POBCTRL | |
1290 | WM8990_BUFIOEN); | 1290 | WM8990_BUFIOEN); |
1291 | 1291 | ||
1292 | /* mute DAC */ | 1292 | /* mute DAC */ |
1293 | val = wm8990_read_reg_cache(codec, WM8990_DAC_CTRL); | 1293 | val = wm8990_read_reg_cache(codec, WM8990_DAC_CTRL); |
1294 | wm8990_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE); | 1294 | wm8990_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE); |
1295 | 1295 | ||
1296 | /* Enable any disabled outputs */ | 1296 | /* Enable any disabled outputs */ |
1297 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03); | 1297 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03); |
1298 | 1298 | ||
1299 | /* Disable VMID */ | 1299 | /* Disable VMID */ |
1300 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f01); | 1300 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f01); |
1301 | 1301 | ||
1302 | msleep(msecs_to_jiffies(300)); | 1302 | msleep(msecs_to_jiffies(300)); |
1303 | 1303 | ||
1304 | /* Enable all output discharge bits */ | 1304 | /* Enable all output discharge bits */ |
1305 | wm8990_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE | | 1305 | wm8990_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE | |
1306 | WM8990_DIS_RLINE | WM8990_DIS_OUT3 | | 1306 | WM8990_DIS_RLINE | WM8990_DIS_OUT3 | |
1307 | WM8990_DIS_OUT4 | WM8990_DIS_LOUT | | 1307 | WM8990_DIS_OUT4 | WM8990_DIS_LOUT | |
1308 | WM8990_DIS_ROUT); | 1308 | WM8990_DIS_ROUT); |
1309 | 1309 | ||
1310 | /* Disable VREF */ | 1310 | /* Disable VREF */ |
1311 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x0); | 1311 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x0); |
1312 | 1312 | ||
1313 | /* disable POBCTRL, SOFT_ST and BUFDCOPEN */ | 1313 | /* disable POBCTRL, SOFT_ST and BUFDCOPEN */ |
1314 | wm8990_write(codec, WM8990_ANTIPOP2, 0x0); | 1314 | wm8990_write(codec, WM8990_ANTIPOP2, 0x0); |
1315 | break; | 1315 | break; |
1316 | } | 1316 | } |
1317 | 1317 | ||
1318 | codec->bias_level = level; | 1318 | codec->bias_level = level; |
1319 | return 0; | 1319 | return 0; |
1320 | } | 1320 | } |
1321 | 1321 | ||
1322 | #define WM8990_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | 1322 | #define WM8990_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ |
1323 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ | 1323 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ |
1324 | SNDRV_PCM_RATE_48000) | 1324 | SNDRV_PCM_RATE_48000) |
1325 | 1325 | ||
1326 | #define WM8990_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | 1326 | #define WM8990_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
1327 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | 1327 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) |
1328 | 1328 | ||
1329 | /* | 1329 | /* |
1330 | * The WM8990 supports 2 different and mutually exclusive DAI | 1330 | * The WM8990 supports 2 different and mutually exclusive DAI |
1331 | * configurations. | 1331 | * configurations. |
1332 | * | 1332 | * |
1333 | * 1. ADC/DAC on Primary Interface | 1333 | * 1. ADC/DAC on Primary Interface |
1334 | * 2. ADC on Primary Interface/DAC on secondary | 1334 | * 2. ADC on Primary Interface/DAC on secondary |
1335 | */ | 1335 | */ |
1336 | struct snd_soc_dai wm8990_dai = { | 1336 | struct snd_soc_dai wm8990_dai = { |
1337 | /* ADC/DAC on primary */ | 1337 | /* ADC/DAC on primary */ |
1338 | .name = "WM8990 ADC/DAC Primary", | 1338 | .name = "WM8990 ADC/DAC Primary", |
1339 | .id = 1, | 1339 | .id = 1, |
1340 | .playback = { | 1340 | .playback = { |
1341 | .stream_name = "Playback", | 1341 | .stream_name = "Playback", |
1342 | .channels_min = 1, | 1342 | .channels_min = 1, |
1343 | .channels_max = 2, | 1343 | .channels_max = 2, |
1344 | .rates = WM8990_RATES, | 1344 | .rates = WM8990_RATES, |
1345 | .formats = WM8990_FORMATS,}, | 1345 | .formats = WM8990_FORMATS,}, |
1346 | .capture = { | 1346 | .capture = { |
1347 | .stream_name = "Capture", | 1347 | .stream_name = "Capture", |
1348 | .channels_min = 1, | 1348 | .channels_min = 1, |
1349 | .channels_max = 2, | 1349 | .channels_max = 2, |
1350 | .rates = WM8990_RATES, | 1350 | .rates = WM8990_RATES, |
1351 | .formats = WM8990_FORMATS,}, | 1351 | .formats = WM8990_FORMATS,}, |
1352 | .ops = { | 1352 | .ops = { |
1353 | .hw_params = wm8990_hw_params,}, | 1353 | .hw_params = wm8990_hw_params,}, |
1354 | .dai_ops = { | 1354 | .dai_ops = { |
1355 | .digital_mute = wm8990_mute, | 1355 | .digital_mute = wm8990_mute, |
1356 | .set_fmt = wm8990_set_dai_fmt, | 1356 | .set_fmt = wm8990_set_dai_fmt, |
1357 | .set_clkdiv = wm8990_set_dai_clkdiv, | 1357 | .set_clkdiv = wm8990_set_dai_clkdiv, |
1358 | .set_pll = wm8990_set_dai_pll, | 1358 | .set_pll = wm8990_set_dai_pll, |
1359 | .set_sysclk = wm8990_set_dai_sysclk, | 1359 | .set_sysclk = wm8990_set_dai_sysclk, |
1360 | }, | 1360 | }, |
1361 | }; | 1361 | }; |
1362 | EXPORT_SYMBOL_GPL(wm8990_dai); | 1362 | EXPORT_SYMBOL_GPL(wm8990_dai); |
1363 | 1363 | ||
1364 | static int wm8990_suspend(struct platform_device *pdev, pm_message_t state) | 1364 | static int wm8990_suspend(struct platform_device *pdev, pm_message_t state) |
1365 | { | 1365 | { |
1366 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1366 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1367 | struct snd_soc_codec *codec = socdev->codec; | 1367 | struct snd_soc_codec *codec = socdev->codec; |
1368 | 1368 | ||
1369 | /* we only need to suspend if we are a valid card */ | 1369 | /* we only need to suspend if we are a valid card */ |
1370 | if (!codec->card) | 1370 | if (!codec->card) |
1371 | return 0; | 1371 | return 0; |
1372 | 1372 | ||
1373 | wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1373 | wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1374 | return 0; | 1374 | return 0; |
1375 | } | 1375 | } |
1376 | 1376 | ||
1377 | static int wm8990_resume(struct platform_device *pdev) | 1377 | static int wm8990_resume(struct platform_device *pdev) |
1378 | { | 1378 | { |
1379 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1379 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1380 | struct snd_soc_codec *codec = socdev->codec; | 1380 | struct snd_soc_codec *codec = socdev->codec; |
1381 | int i; | 1381 | int i; |
1382 | u8 data[2]; | 1382 | u8 data[2]; |
1383 | u16 *cache = codec->reg_cache; | 1383 | u16 *cache = codec->reg_cache; |
1384 | 1384 | ||
1385 | /* we only need to resume if we are a valid card */ | 1385 | /* we only need to resume if we are a valid card */ |
1386 | if (!codec->card) | 1386 | if (!codec->card) |
1387 | return 0; | 1387 | return 0; |
1388 | 1388 | ||
1389 | /* Sync reg_cache with the hardware */ | 1389 | /* Sync reg_cache with the hardware */ |
1390 | for (i = 0; i < ARRAY_SIZE(wm8990_reg); i++) { | 1390 | for (i = 0; i < ARRAY_SIZE(wm8990_reg); i++) { |
1391 | if (i + 1 == WM8990_RESET) | 1391 | if (i + 1 == WM8990_RESET) |
1392 | continue; | 1392 | continue; |
1393 | data[0] = ((i + 1) << 1) | ((cache[i] >> 8) & 0x0001); | 1393 | data[0] = ((i + 1) << 1) | ((cache[i] >> 8) & 0x0001); |
1394 | data[1] = cache[i] & 0x00ff; | 1394 | data[1] = cache[i] & 0x00ff; |
1395 | codec->hw_write(codec->control_data, data, 2); | 1395 | codec->hw_write(codec->control_data, data, 2); |
1396 | } | 1396 | } |
1397 | 1397 | ||
1398 | wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1398 | wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1399 | return 0; | 1399 | return 0; |
1400 | } | 1400 | } |
1401 | 1401 | ||
1402 | /* | 1402 | /* |
1403 | * initialise the WM8990 driver | 1403 | * initialise the WM8990 driver |
1404 | * register the mixer and dsp interfaces with the kernel | 1404 | * register the mixer and dsp interfaces with the kernel |
1405 | */ | 1405 | */ |
1406 | static int wm8990_init(struct snd_soc_device *socdev) | 1406 | static int wm8990_init(struct snd_soc_device *socdev) |
1407 | { | 1407 | { |
1408 | struct snd_soc_codec *codec = socdev->codec; | 1408 | struct snd_soc_codec *codec = socdev->codec; |
1409 | u16 reg; | 1409 | u16 reg; |
1410 | int ret = 0; | 1410 | int ret = 0; |
1411 | 1411 | ||
1412 | codec->name = "WM8990"; | 1412 | codec->name = "WM8990"; |
1413 | codec->owner = THIS_MODULE; | 1413 | codec->owner = THIS_MODULE; |
1414 | codec->read = wm8990_read_reg_cache; | 1414 | codec->read = wm8990_read_reg_cache; |
1415 | codec->write = wm8990_write; | 1415 | codec->write = wm8990_write; |
1416 | codec->set_bias_level = wm8990_set_bias_level; | 1416 | codec->set_bias_level = wm8990_set_bias_level; |
1417 | codec->dai = &wm8990_dai; | 1417 | codec->dai = &wm8990_dai; |
1418 | codec->num_dai = 2; | 1418 | codec->num_dai = 2; |
1419 | codec->reg_cache_size = ARRAY_SIZE(wm8990_reg); | 1419 | codec->reg_cache_size = ARRAY_SIZE(wm8990_reg); |
1420 | codec->reg_cache = kmemdup(wm8990_reg, sizeof(wm8990_reg), GFP_KERNEL); | 1420 | codec->reg_cache = kmemdup(wm8990_reg, sizeof(wm8990_reg), GFP_KERNEL); |
1421 | 1421 | ||
1422 | if (codec->reg_cache == NULL) | 1422 | if (codec->reg_cache == NULL) |
1423 | return -ENOMEM; | 1423 | return -ENOMEM; |
1424 | 1424 | ||
1425 | wm8990_reset(codec); | 1425 | wm8990_reset(codec); |
1426 | 1426 | ||
1427 | /* register pcms */ | 1427 | /* register pcms */ |
1428 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 1428 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
1429 | if (ret < 0) { | 1429 | if (ret < 0) { |
1430 | printk(KERN_ERR "wm8990: failed to create pcms\n"); | 1430 | printk(KERN_ERR "wm8990: failed to create pcms\n"); |
1431 | goto pcm_err; | 1431 | goto pcm_err; |
1432 | } | 1432 | } |
1433 | 1433 | ||
1434 | /* charge output caps */ | 1434 | /* charge output caps */ |
1435 | codec->bias_level = SND_SOC_BIAS_OFF; | 1435 | codec->bias_level = SND_SOC_BIAS_OFF; |
1436 | wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1436 | wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1437 | 1437 | ||
1438 | reg = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_4); | 1438 | reg = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_4); |
1439 | wm8990_write(codec, WM8990_AUDIO_INTERFACE_4, reg | WM8990_ALRCGPIO1); | 1439 | wm8990_write(codec, WM8990_AUDIO_INTERFACE_4, reg | WM8990_ALRCGPIO1); |
1440 | 1440 | ||
1441 | reg = wm8990_read_reg_cache(codec, WM8990_GPIO1_GPIO2) & | 1441 | reg = wm8990_read_reg_cache(codec, WM8990_GPIO1_GPIO2) & |
1442 | ~WM8990_GPIO1_SEL_MASK; | 1442 | ~WM8990_GPIO1_SEL_MASK; |
1443 | wm8990_write(codec, WM8990_GPIO1_GPIO2, reg | 1); | 1443 | wm8990_write(codec, WM8990_GPIO1_GPIO2, reg | 1); |
1444 | 1444 | ||
1445 | reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2); | 1445 | reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2); |
1446 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg | WM8990_OPCLK_ENA); | 1446 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg | WM8990_OPCLK_ENA); |
1447 | 1447 | ||
1448 | wm8990_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); | 1448 | wm8990_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); |
1449 | wm8990_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); | 1449 | wm8990_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); |
1450 | 1450 | ||
1451 | wm8990_add_controls(codec); | 1451 | wm8990_add_controls(codec); |
1452 | wm8990_add_widgets(codec); | 1452 | wm8990_add_widgets(codec); |
1453 | ret = snd_soc_register_card(socdev); | 1453 | ret = snd_soc_register_card(socdev); |
1454 | if (ret < 0) { | 1454 | if (ret < 0) { |
1455 | printk(KERN_ERR "wm8990: failed to register card\n"); | 1455 | printk(KERN_ERR "wm8990: failed to register card\n"); |
1456 | goto card_err; | 1456 | goto card_err; |
1457 | } | 1457 | } |
1458 | return ret; | 1458 | return ret; |
1459 | 1459 | ||
1460 | card_err: | 1460 | card_err: |
1461 | snd_soc_free_pcms(socdev); | 1461 | snd_soc_free_pcms(socdev); |
1462 | snd_soc_dapm_free(socdev); | 1462 | snd_soc_dapm_free(socdev); |
1463 | pcm_err: | 1463 | pcm_err: |
1464 | kfree(codec->reg_cache); | 1464 | kfree(codec->reg_cache); |
1465 | return ret; | 1465 | return ret; |
1466 | } | 1466 | } |
1467 | 1467 | ||
1468 | /* If the i2c layer weren't so broken, we could pass this kind of data | 1468 | /* If the i2c layer weren't so broken, we could pass this kind of data |
1469 | around */ | 1469 | around */ |
1470 | static struct snd_soc_device *wm8990_socdev; | 1470 | static struct snd_soc_device *wm8990_socdev; |
1471 | 1471 | ||
1472 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1472 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1473 | 1473 | ||
1474 | /* | 1474 | /* |
1475 | * WM891 2 wire address is determined by GPIO5 | 1475 | * WM891 2 wire address is determined by GPIO5 |
1476 | * state during powerup. | 1476 | * state during powerup. |
1477 | * low = 0x34 | 1477 | * low = 0x34 |
1478 | * high = 0x36 | 1478 | * high = 0x36 |
1479 | */ | 1479 | */ |
1480 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | 1480 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; |
1481 | 1481 | ||
1482 | /* Magic definition of all other variables and things */ | 1482 | /* Magic definition of all other variables and things */ |
1483 | I2C_CLIENT_INSMOD; | 1483 | I2C_CLIENT_INSMOD; |
1484 | 1484 | ||
1485 | static struct i2c_driver wm8990_i2c_driver; | 1485 | static struct i2c_driver wm8990_i2c_driver; |
1486 | static struct i2c_client client_template; | 1486 | static struct i2c_client client_template; |
1487 | 1487 | ||
1488 | static int wm8990_codec_probe(struct i2c_adapter *adap, int addr, int kind) | 1488 | static int wm8990_codec_probe(struct i2c_adapter *adap, int addr, int kind) |
1489 | { | 1489 | { |
1490 | struct snd_soc_device *socdev = wm8990_socdev; | 1490 | struct snd_soc_device *socdev = wm8990_socdev; |
1491 | struct wm8990_setup_data *setup = socdev->codec_data; | 1491 | struct wm8990_setup_data *setup = socdev->codec_data; |
1492 | struct snd_soc_codec *codec = socdev->codec; | 1492 | struct snd_soc_codec *codec = socdev->codec; |
1493 | struct i2c_client *i2c; | 1493 | struct i2c_client *i2c; |
1494 | int ret; | 1494 | int ret; |
1495 | 1495 | ||
1496 | if (addr != setup->i2c_address) | 1496 | if (addr != setup->i2c_address) |
1497 | return -ENODEV; | 1497 | return -ENODEV; |
1498 | 1498 | ||
1499 | client_template.adapter = adap; | 1499 | client_template.adapter = adap; |
1500 | client_template.addr = addr; | 1500 | client_template.addr = addr; |
1501 | 1501 | ||
1502 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | 1502 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); |
1503 | if (i2c == NULL) { | 1503 | if (i2c == NULL) |
1504 | kfree(codec); | ||
1505 | return -ENOMEM; | 1504 | return -ENOMEM; |
1506 | } | 1505 | |
1507 | i2c_set_clientdata(i2c, codec); | 1506 | i2c_set_clientdata(i2c, codec); |
1508 | codec->control_data = i2c; | 1507 | codec->control_data = i2c; |
1509 | 1508 | ||
1510 | ret = i2c_attach_client(i2c); | 1509 | ret = i2c_attach_client(i2c); |
1511 | if (ret < 0) { | 1510 | if (ret < 0) { |
1512 | pr_err("failed to attach codec at addr %x\n", addr); | 1511 | pr_err("failed to attach codec at addr %x\n", addr); |
1513 | goto err; | 1512 | goto err; |
1514 | } | 1513 | } |
1515 | 1514 | ||
1516 | ret = wm8990_init(socdev); | 1515 | ret = wm8990_init(socdev); |
1517 | if (ret < 0) { | 1516 | if (ret < 0) { |
1518 | pr_err("failed to initialise WM8990\n"); | 1517 | pr_err("failed to initialise WM8990\n"); |
1519 | goto err; | 1518 | goto err; |
1520 | } | 1519 | } |
1521 | return ret; | 1520 | return ret; |
1522 | 1521 | ||
1523 | err: | 1522 | err: |
1524 | kfree(codec); | ||
1525 | kfree(i2c); | 1523 | kfree(i2c); |
1526 | return ret; | 1524 | return ret; |
1527 | } | 1525 | } |
1528 | 1526 | ||
1529 | static int wm8990_i2c_detach(struct i2c_client *client) | 1527 | static int wm8990_i2c_detach(struct i2c_client *client) |
1530 | { | 1528 | { |
1531 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 1529 | struct snd_soc_codec *codec = i2c_get_clientdata(client); |
1532 | i2c_detach_client(client); | 1530 | i2c_detach_client(client); |
1533 | kfree(codec->reg_cache); | 1531 | kfree(codec->reg_cache); |
1534 | kfree(client); | 1532 | kfree(client); |
1535 | return 0; | 1533 | return 0; |
1536 | } | 1534 | } |
1537 | 1535 | ||
1538 | static int wm8990_i2c_attach(struct i2c_adapter *adap) | 1536 | static int wm8990_i2c_attach(struct i2c_adapter *adap) |
1539 | { | 1537 | { |
1540 | return i2c_probe(adap, &addr_data, wm8990_codec_probe); | 1538 | return i2c_probe(adap, &addr_data, wm8990_codec_probe); |
1541 | } | 1539 | } |
1542 | 1540 | ||
1543 | static struct i2c_driver wm8990_i2c_driver = { | 1541 | static struct i2c_driver wm8990_i2c_driver = { |
1544 | .driver = { | 1542 | .driver = { |
1545 | .name = "WM8990 I2C Codec", | 1543 | .name = "WM8990 I2C Codec", |
1546 | .owner = THIS_MODULE, | 1544 | .owner = THIS_MODULE, |
1547 | }, | 1545 | }, |
1548 | .attach_adapter = wm8990_i2c_attach, | 1546 | .attach_adapter = wm8990_i2c_attach, |
1549 | .detach_client = wm8990_i2c_detach, | 1547 | .detach_client = wm8990_i2c_detach, |
1550 | .command = NULL, | 1548 | .command = NULL, |
1551 | }; | 1549 | }; |
1552 | 1550 | ||
1553 | static struct i2c_client client_template = { | 1551 | static struct i2c_client client_template = { |
1554 | .name = "WM8990", | 1552 | .name = "WM8990", |
1555 | .driver = &wm8990_i2c_driver, | 1553 | .driver = &wm8990_i2c_driver, |
1556 | }; | 1554 | }; |
1557 | #endif | 1555 | #endif |
1558 | 1556 | ||
1559 | static int wm8990_probe(struct platform_device *pdev) | 1557 | static int wm8990_probe(struct platform_device *pdev) |
1560 | { | 1558 | { |
1561 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1559 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1562 | struct wm8990_setup_data *setup; | 1560 | struct wm8990_setup_data *setup; |
1563 | struct snd_soc_codec *codec; | 1561 | struct snd_soc_codec *codec; |
1564 | struct wm8990_priv *wm8990; | 1562 | struct wm8990_priv *wm8990; |
1565 | int ret = 0; | 1563 | int ret = 0; |
1566 | 1564 | ||
1567 | pr_info("WM8990 Audio Codec %s\n", WM8990_VERSION); | 1565 | pr_info("WM8990 Audio Codec %s\n", WM8990_VERSION); |
1568 | 1566 | ||
1569 | setup = socdev->codec_data; | 1567 | setup = socdev->codec_data; |
1570 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 1568 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); |
1571 | if (codec == NULL) | 1569 | if (codec == NULL) |
1572 | return -ENOMEM; | 1570 | return -ENOMEM; |
1573 | 1571 | ||
1574 | wm8990 = kzalloc(sizeof(struct wm8990_priv), GFP_KERNEL); | 1572 | wm8990 = kzalloc(sizeof(struct wm8990_priv), GFP_KERNEL); |
1575 | if (wm8990 == NULL) { | 1573 | if (wm8990 == NULL) { |
1576 | kfree(codec); | 1574 | kfree(codec); |
1577 | return -ENOMEM; | 1575 | return -ENOMEM; |
1578 | } | 1576 | } |
1579 | 1577 | ||
1580 | codec->private_data = wm8990; | 1578 | codec->private_data = wm8990; |
1581 | socdev->codec = codec; | 1579 | socdev->codec = codec; |
1582 | mutex_init(&codec->mutex); | 1580 | mutex_init(&codec->mutex); |
1583 | INIT_LIST_HEAD(&codec->dapm_widgets); | 1581 | INIT_LIST_HEAD(&codec->dapm_widgets); |
1584 | INIT_LIST_HEAD(&codec->dapm_paths); | 1582 | INIT_LIST_HEAD(&codec->dapm_paths); |
1585 | wm8990_socdev = socdev; | 1583 | wm8990_socdev = socdev; |
1586 | 1584 | ||
1587 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1585 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1588 | if (setup->i2c_address) { | 1586 | if (setup->i2c_address) { |
1589 | normal_i2c[0] = setup->i2c_address; | 1587 | normal_i2c[0] = setup->i2c_address; |
1590 | codec->hw_write = (hw_write_t)i2c_master_send; | 1588 | codec->hw_write = (hw_write_t)i2c_master_send; |
1591 | ret = i2c_add_driver(&wm8990_i2c_driver); | 1589 | ret = i2c_add_driver(&wm8990_i2c_driver); |
1592 | if (ret != 0) | 1590 | if (ret != 0) |
1593 | printk(KERN_ERR "can't add i2c driver"); | 1591 | printk(KERN_ERR "can't add i2c driver"); |
1594 | } | 1592 | } |
1595 | #else | 1593 | #else |
1596 | /* Add other interfaces here */ | 1594 | /* Add other interfaces here */ |
1597 | #endif | 1595 | #endif |
1596 | |||
1597 | if (ret != 0) { | ||
1598 | kfree(codec->private_data); | ||
1599 | kfree(codec); | ||
1600 | } | ||
1598 | return ret; | 1601 | return ret; |
1599 | } | 1602 | } |
1600 | 1603 | ||
1601 | /* power down chip */ | 1604 | /* power down chip */ |
1602 | static int wm8990_remove(struct platform_device *pdev) | 1605 | static int wm8990_remove(struct platform_device *pdev) |
1603 | { | 1606 | { |
1604 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1607 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1605 | struct snd_soc_codec *codec = socdev->codec; | 1608 | struct snd_soc_codec *codec = socdev->codec; |
1606 | 1609 | ||
1607 | if (codec->control_data) | 1610 | if (codec->control_data) |
1608 | wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1611 | wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1609 | snd_soc_free_pcms(socdev); | 1612 | snd_soc_free_pcms(socdev); |
1610 | snd_soc_dapm_free(socdev); | 1613 | snd_soc_dapm_free(socdev); |
1611 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1614 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1612 | i2c_del_driver(&wm8990_i2c_driver); | 1615 | i2c_del_driver(&wm8990_i2c_driver); |
1613 | #endif | 1616 | #endif |
1614 | kfree(codec->private_data); | 1617 | kfree(codec->private_data); |
1615 | kfree(codec); | 1618 | kfree(codec); |
1616 | 1619 | ||
1617 | return 0; | 1620 | return 0; |
1618 | } | 1621 | } |
1619 | 1622 | ||
1620 | struct snd_soc_codec_device soc_codec_dev_wm8990 = { | 1623 | struct snd_soc_codec_device soc_codec_dev_wm8990 = { |
1621 | .probe = wm8990_probe, | 1624 | .probe = wm8990_probe, |
1622 | .remove = wm8990_remove, | 1625 | .remove = wm8990_remove, |
1623 | .suspend = wm8990_suspend, | 1626 | .suspend = wm8990_suspend, |
1624 | .resume = wm8990_resume, | 1627 | .resume = wm8990_resume, |
1625 | }; | 1628 | }; |
1626 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8990); | 1629 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8990); |
1627 | 1630 | ||
1628 | MODULE_DESCRIPTION("ASoC WM8990 driver"); | 1631 | MODULE_DESCRIPTION("ASoC WM8990 driver"); |
1629 | MODULE_AUTHOR("Liam Girdwood"); | 1632 | MODULE_AUTHOR("Liam Girdwood"); |