diff options
Diffstat (limited to 'sound')
187 files changed, 16248 insertions, 3795 deletions
diff --git a/sound/Kconfig b/sound/Kconfig index 4247406160e7..a37bee094eba 100644 --- a/sound/Kconfig +++ b/sound/Kconfig | |||
@@ -1,11 +1,9 @@ | |||
1 | # sound/Config.in | 1 | # sound/Config.in |
2 | # | 2 | # |
3 | 3 | ||
4 | menu "Sound" | 4 | menuconfig SOUND |
5 | depends on HAS_IOMEM | ||
6 | |||
7 | config SOUND | ||
8 | tristate "Sound card support" | 5 | tristate "Sound card support" |
6 | depends on HAS_IOMEM | ||
9 | help | 7 | help |
10 | If you have a sound card in your computer, i.e. if it can say more | 8 | If you have a sound card in your computer, i.e. if it can say more |
11 | than an occasional beep, say Y. Be sure to have all the information | 9 | than an occasional beep, say Y. Be sure to have all the information |
@@ -28,22 +26,22 @@ config SOUND | |||
28 | and read <file:Documentation/sound/oss/README.modules>; the module | 26 | and read <file:Documentation/sound/oss/README.modules>; the module |
29 | will be called soundcore. | 27 | will be called soundcore. |
30 | 28 | ||
29 | if SOUND | ||
30 | |||
31 | source "sound/oss/dmasound/Kconfig" | 31 | source "sound/oss/dmasound/Kconfig" |
32 | 32 | ||
33 | if !M68K | 33 | if !M68K |
34 | 34 | ||
35 | menu "Advanced Linux Sound Architecture" | 35 | menuconfig SND |
36 | depends on SOUND!=n | ||
37 | |||
38 | config SND | ||
39 | tristate "Advanced Linux Sound Architecture" | 36 | tristate "Advanced Linux Sound Architecture" |
40 | depends on SOUND | ||
41 | help | 37 | help |
42 | Say 'Y' or 'M' to enable ALSA (Advanced Linux Sound Architecture), | 38 | Say 'Y' or 'M' to enable ALSA (Advanced Linux Sound Architecture), |
43 | the new base sound system. | 39 | the new base sound system. |
44 | 40 | ||
45 | For more information, see <http://www.alsa-project.org/> | 41 | For more information, see <http://www.alsa-project.org/> |
46 | 42 | ||
43 | if SND | ||
44 | |||
47 | source "sound/core/Kconfig" | 45 | source "sound/core/Kconfig" |
48 | 46 | ||
49 | source "sound/drivers/Kconfig" | 47 | source "sound/drivers/Kconfig" |
@@ -58,9 +56,7 @@ source "sound/aoa/Kconfig" | |||
58 | 56 | ||
59 | source "sound/arm/Kconfig" | 57 | source "sound/arm/Kconfig" |
60 | 58 | ||
61 | if SPI | ||
62 | source "sound/spi/Kconfig" | 59 | source "sound/spi/Kconfig" |
63 | endif | ||
64 | 60 | ||
65 | source "sound/mips/Kconfig" | 61 | source "sound/mips/Kconfig" |
66 | 62 | ||
@@ -80,22 +76,20 @@ source "sound/parisc/Kconfig" | |||
80 | 76 | ||
81 | source "sound/soc/Kconfig" | 77 | source "sound/soc/Kconfig" |
82 | 78 | ||
83 | endmenu | 79 | endif # SND |
84 | 80 | ||
85 | menu "Open Sound System" | 81 | menuconfig SOUND_PRIME |
86 | depends on SOUND!=n | ||
87 | |||
88 | config SOUND_PRIME | ||
89 | tristate "Open Sound System (DEPRECATED)" | 82 | tristate "Open Sound System (DEPRECATED)" |
90 | depends on SOUND | ||
91 | help | 83 | help |
92 | Say 'Y' or 'M' to enable Open Sound System drivers. | 84 | Say 'Y' or 'M' to enable Open Sound System drivers. |
93 | 85 | ||
86 | if SOUND_PRIME | ||
87 | |||
94 | source "sound/oss/Kconfig" | 88 | source "sound/oss/Kconfig" |
95 | 89 | ||
96 | endmenu | 90 | endif # SOUND_PRIME |
97 | 91 | ||
98 | endif | 92 | endif # !M68K |
99 | 93 | ||
100 | config AC97_BUS | 94 | config AC97_BUS |
101 | tristate | 95 | tristate |
@@ -105,4 +99,4 @@ config AC97_BUS | |||
105 | sound although they're sharing the AC97 bus. Concerned drivers | 99 | sound although they're sharing the AC97 bus. Concerned drivers |
106 | should "select" this. | 100 | should "select" this. |
107 | 101 | ||
108 | endmenu | 102 | endif # SOUND |
diff --git a/sound/aoa/Kconfig b/sound/aoa/Kconfig index 5d5813cec4c8..c081e18b9540 100644 --- a/sound/aoa/Kconfig +++ b/sound/aoa/Kconfig | |||
@@ -1,18 +1,17 @@ | |||
1 | menu "Apple Onboard Audio driver" | 1 | menuconfig SND_AOA |
2 | depends on SND!=n && PPC_PMAC | ||
3 | |||
4 | config SND_AOA | ||
5 | tristate "Apple Onboard Audio driver" | 2 | tristate "Apple Onboard Audio driver" |
6 | depends on SND | 3 | depends on PPC_PMAC |
7 | select SND_PCM | 4 | select SND_PCM |
8 | ---help--- | 5 | ---help--- |
9 | This option enables the new driver for the various | 6 | This option enables the new driver for the various |
10 | Apple Onboard Audio components. | 7 | Apple Onboard Audio components. |
11 | 8 | ||
9 | if SND_AOA | ||
10 | |||
12 | source "sound/aoa/fabrics/Kconfig" | 11 | source "sound/aoa/fabrics/Kconfig" |
13 | 12 | ||
14 | source "sound/aoa/codecs/Kconfig" | 13 | source "sound/aoa/codecs/Kconfig" |
15 | 14 | ||
16 | source "sound/aoa/soundbus/Kconfig" | 15 | source "sound/aoa/soundbus/Kconfig" |
17 | 16 | ||
18 | endmenu | 17 | endif # SND_AOA |
diff --git a/sound/aoa/codecs/Kconfig b/sound/aoa/codecs/Kconfig index d5fbd6016e93..808eb11ebacd 100644 --- a/sound/aoa/codecs/Kconfig +++ b/sound/aoa/codecs/Kconfig | |||
@@ -1,6 +1,5 @@ | |||
1 | config SND_AOA_ONYX | 1 | config SND_AOA_ONYX |
2 | tristate "support Onyx chip" | 2 | tristate "support Onyx chip" |
3 | depends on SND_AOA | ||
4 | select I2C | 3 | select I2C |
5 | select I2C_POWERMAC | 4 | select I2C_POWERMAC |
6 | ---help--- | 5 | ---help--- |
@@ -10,7 +9,6 @@ config SND_AOA_ONYX | |||
10 | 9 | ||
11 | #config SND_AOA_TOPAZ | 10 | #config SND_AOA_TOPAZ |
12 | # tristate "support Topaz chips" | 11 | # tristate "support Topaz chips" |
13 | # depends on SND_AOA | ||
14 | # ---help--- | 12 | # ---help--- |
15 | # This option enables support for the Topaz (CS84xx) | 13 | # This option enables support for the Topaz (CS84xx) |
16 | # codec chips found in the latest Apple machines, | 14 | # codec chips found in the latest Apple machines, |
@@ -19,7 +17,6 @@ config SND_AOA_ONYX | |||
19 | 17 | ||
20 | config SND_AOA_TAS | 18 | config SND_AOA_TAS |
21 | tristate "support TAS chips" | 19 | tristate "support TAS chips" |
22 | depends on SND_AOA | ||
23 | select I2C | 20 | select I2C |
24 | select I2C_POWERMAC | 21 | select I2C_POWERMAC |
25 | ---help--- | 22 | ---help--- |
@@ -29,7 +26,6 @@ config SND_AOA_TAS | |||
29 | 26 | ||
30 | config SND_AOA_TOONIE | 27 | config SND_AOA_TOONIE |
31 | tristate "support Toonie chip" | 28 | tristate "support Toonie chip" |
32 | depends on SND_AOA | ||
33 | ---help--- | 29 | ---help--- |
34 | This option enables support for the toonie codec | 30 | This option enables support for the toonie codec |
35 | found in the Mac Mini. If you have a Mac Mini and | 31 | found in the Mac Mini. If you have a Mac Mini and |
diff --git a/sound/aoa/fabrics/Kconfig b/sound/aoa/fabrics/Kconfig index 50d7021ff677..3ca475a886b1 100644 --- a/sound/aoa/fabrics/Kconfig +++ b/sound/aoa/fabrics/Kconfig | |||
@@ -1,6 +1,5 @@ | |||
1 | config SND_AOA_FABRIC_LAYOUT | 1 | config SND_AOA_FABRIC_LAYOUT |
2 | tristate "layout-id fabric" | 2 | tristate "layout-id fabric" |
3 | depends on SND_AOA | ||
4 | select SND_AOA_SOUNDBUS | 3 | select SND_AOA_SOUNDBUS |
5 | select SND_AOA_SOUNDBUS_I2S | 4 | select SND_AOA_SOUNDBUS_I2S |
6 | ---help--- | 5 | ---help--- |
diff --git a/sound/aoa/soundbus/Kconfig b/sound/aoa/soundbus/Kconfig index 7368b7ddfe0d..839d1137b9b2 100644 --- a/sound/aoa/soundbus/Kconfig +++ b/sound/aoa/soundbus/Kconfig | |||
@@ -1,6 +1,5 @@ | |||
1 | config SND_AOA_SOUNDBUS | 1 | config SND_AOA_SOUNDBUS |
2 | tristate "Apple Soundbus support" | 2 | tristate "Apple Soundbus support" |
3 | depends on SOUND | ||
4 | select SND_PCM | 3 | select SND_PCM |
5 | ---help--- | 4 | ---help--- |
6 | This option enables the generic driver for the soundbus | 5 | This option enables the generic driver for the soundbus |
diff --git a/sound/arm/Kconfig b/sound/arm/Kconfig index 2e4a5e0d16db..351e19ea3785 100644 --- a/sound/arm/Kconfig +++ b/sound/arm/Kconfig | |||
@@ -1,11 +1,19 @@ | |||
1 | # ALSA ARM drivers | 1 | # ALSA ARM drivers |
2 | 2 | ||
3 | menu "ALSA ARM devices" | 3 | menuconfig SND_ARM |
4 | depends on SND!=n && ARM | 4 | bool "ARM sound devices" |
5 | depends on ARM | ||
6 | default y | ||
7 | help | ||
8 | Support for sound devices specific to ARM architectures. | ||
9 | Drivers that are implemented on ASoC can be found in | ||
10 | "ALSA for SoC audio support" section. | ||
11 | |||
12 | if SND_ARM | ||
5 | 13 | ||
6 | config SND_SA11XX_UDA1341 | 14 | config SND_SA11XX_UDA1341 |
7 | tristate "SA11xx UDA1341TS driver (iPaq H3600)" | 15 | tristate "SA11xx UDA1341TS driver (iPaq H3600)" |
8 | depends on ARCH_SA1100 && SND && L3 | 16 | depends on ARCH_SA1100 && L3 |
9 | select SND_PCM | 17 | select SND_PCM |
10 | help | 18 | help |
11 | Say Y here if you have a Compaq iPaq H3x00 handheld computer | 19 | Say Y here if you have a Compaq iPaq H3x00 handheld computer |
@@ -16,7 +24,7 @@ config SND_SA11XX_UDA1341 | |||
16 | 24 | ||
17 | config SND_ARMAACI | 25 | config SND_ARMAACI |
18 | tristate "ARM PrimeCell PL041 AC Link support" | 26 | tristate "ARM PrimeCell PL041 AC Link support" |
19 | depends on SND && ARM_AMBA | 27 | depends on ARM_AMBA |
20 | select SND_PCM | 28 | select SND_PCM |
21 | select SND_AC97_CODEC | 29 | select SND_AC97_CODEC |
22 | 30 | ||
@@ -26,11 +34,12 @@ config SND_PXA2XX_PCM | |||
26 | 34 | ||
27 | config SND_PXA2XX_AC97 | 35 | config SND_PXA2XX_AC97 |
28 | tristate "AC97 driver for the Intel PXA2xx chip" | 36 | tristate "AC97 driver for the Intel PXA2xx chip" |
29 | depends on ARCH_PXA && SND | 37 | depends on ARCH_PXA |
30 | select SND_PXA2XX_PCM | 38 | select SND_PXA2XX_PCM |
31 | select SND_AC97_CODEC | 39 | select SND_AC97_CODEC |
32 | help | 40 | help |
33 | Say Y or M if you want to support any AC97 codec attached to | 41 | Say Y or M if you want to support any AC97 codec attached to |
34 | the PXA2xx AC97 interface. | 42 | the PXA2xx AC97 interface. |
35 | 43 | ||
36 | endmenu | 44 | endif # SND_ARM |
45 | |||
diff --git a/sound/arm/sa11xx-uda1341.c b/sound/arm/sa11xx-uda1341.c index 0eff33ca0f79..faeddf3ecedb 100644 --- a/sound/arm/sa11xx-uda1341.c +++ b/sound/arm/sa11xx-uda1341.c | |||
@@ -21,8 +21,6 @@ | |||
21 | * merged HAL layer (patches from Brian) | 21 | * merged HAL layer (patches from Brian) |
22 | */ | 22 | */ |
23 | 23 | ||
24 | /* $Id: sa11xx-uda1341.c,v 1.27 2005/12/07 09:13:42 cladisch Exp $ */ | ||
25 | |||
26 | /*************************************************************************************************** | 24 | /*************************************************************************************************** |
27 | * | 25 | * |
28 | * To understand what Alsa Drivers should be doing look at "Writing an Alsa Driver" by Takashi Iwai | 26 | * To understand what Alsa Drivers should be doing look at "Writing an Alsa Driver" by Takashi Iwai |
diff --git a/sound/core/Kconfig b/sound/core/Kconfig index a8d71c6c8e75..335d45ecde6a 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig | |||
@@ -1,24 +1,19 @@ | |||
1 | # ALSA soundcard-configuration | 1 | # ALSA soundcard-configuration |
2 | config SND_TIMER | 2 | config SND_TIMER |
3 | tristate | 3 | tristate |
4 | depends on SND | ||
5 | 4 | ||
6 | config SND_PCM | 5 | config SND_PCM |
7 | tristate | 6 | tristate |
8 | select SND_TIMER | 7 | select SND_TIMER |
9 | depends on SND | ||
10 | 8 | ||
11 | config SND_HWDEP | 9 | config SND_HWDEP |
12 | tristate | 10 | tristate |
13 | depends on SND | ||
14 | 11 | ||
15 | config SND_RAWMIDI | 12 | config SND_RAWMIDI |
16 | tristate | 13 | tristate |
17 | depends on SND | ||
18 | 14 | ||
19 | config SND_SEQUENCER | 15 | config SND_SEQUENCER |
20 | tristate "Sequencer support" | 16 | tristate "Sequencer support" |
21 | depends on SND | ||
22 | select SND_TIMER | 17 | select SND_TIMER |
23 | help | 18 | help |
24 | Say Y or M to enable MIDI sequencer and router support. This | 19 | Say Y or M to enable MIDI sequencer and router support. This |
@@ -44,11 +39,9 @@ config SND_SEQ_DUMMY | |||
44 | 39 | ||
45 | config SND_OSSEMUL | 40 | config SND_OSSEMUL |
46 | bool | 41 | bool |
47 | depends on SND | ||
48 | 42 | ||
49 | config SND_MIXER_OSS | 43 | config SND_MIXER_OSS |
50 | tristate "OSS Mixer API" | 44 | tristate "OSS Mixer API" |
51 | depends on SND | ||
52 | select SND_OSSEMUL | 45 | select SND_OSSEMUL |
53 | help | 46 | help |
54 | To enable OSS mixer API emulation (/dev/mixer*), say Y here | 47 | To enable OSS mixer API emulation (/dev/mixer*), say Y here |
@@ -61,7 +54,6 @@ config SND_MIXER_OSS | |||
61 | 54 | ||
62 | config SND_PCM_OSS | 55 | config SND_PCM_OSS |
63 | tristate "OSS PCM (digital audio) API" | 56 | tristate "OSS PCM (digital audio) API" |
64 | depends on SND | ||
65 | select SND_OSSEMUL | 57 | select SND_OSSEMUL |
66 | select SND_PCM | 58 | select SND_PCM |
67 | help | 59 | help |
@@ -84,7 +76,7 @@ config SND_PCM_OSS_PLUGINS | |||
84 | 76 | ||
85 | config SND_SEQUENCER_OSS | 77 | config SND_SEQUENCER_OSS |
86 | bool "OSS Sequencer API" | 78 | bool "OSS Sequencer API" |
87 | depends on SND && SND_SEQUENCER | 79 | depends on SND_SEQUENCER |
88 | select SND_OSSEMUL | 80 | select SND_OSSEMUL |
89 | help | 81 | help |
90 | Say Y here to enable OSS sequencer emulation (both | 82 | Say Y here to enable OSS sequencer emulation (both |
@@ -98,7 +90,7 @@ config SND_SEQUENCER_OSS | |||
98 | 90 | ||
99 | config SND_RTCTIMER | 91 | config SND_RTCTIMER |
100 | tristate "RTC Timer support" | 92 | tristate "RTC Timer support" |
101 | depends on SND && RTC | 93 | depends on RTC |
102 | select SND_TIMER | 94 | select SND_TIMER |
103 | help | 95 | help |
104 | Say Y here to enable RTC timer support for ALSA. ALSA uses | 96 | Say Y here to enable RTC timer support for ALSA. ALSA uses |
@@ -123,7 +115,6 @@ config SND_SEQ_RTCTIMER_DEFAULT | |||
123 | 115 | ||
124 | config SND_DYNAMIC_MINORS | 116 | config SND_DYNAMIC_MINORS |
125 | bool "Dynamic device file minor numbers" | 117 | bool "Dynamic device file minor numbers" |
126 | depends on SND | ||
127 | help | 118 | help |
128 | If you say Y here, the minor numbers of ALSA device files in | 119 | If you say Y here, the minor numbers of ALSA device files in |
129 | /dev/snd/ are allocated dynamically. This allows you to have | 120 | /dev/snd/ are allocated dynamically. This allows you to have |
@@ -134,7 +125,6 @@ config SND_DYNAMIC_MINORS | |||
134 | 125 | ||
135 | config SND_SUPPORT_OLD_API | 126 | config SND_SUPPORT_OLD_API |
136 | bool "Support old ALSA API" | 127 | bool "Support old ALSA API" |
137 | depends on SND | ||
138 | default y | 128 | default y |
139 | help | 129 | help |
140 | Say Y here to support the obsolete ALSA PCM API (ver.0.9.0 rc3 | 130 | Say Y here to support the obsolete ALSA PCM API (ver.0.9.0 rc3 |
@@ -142,7 +132,7 @@ config SND_SUPPORT_OLD_API | |||
142 | 132 | ||
143 | config SND_VERBOSE_PROCFS | 133 | config SND_VERBOSE_PROCFS |
144 | bool "Verbose procfs contents" | 134 | bool "Verbose procfs contents" |
145 | depends on SND && PROC_FS | 135 | depends on PROC_FS |
146 | default y | 136 | default y |
147 | help | 137 | help |
148 | Say Y here to include code for verbose procfs contents (provides | 138 | Say Y here to include code for verbose procfs contents (provides |
@@ -151,7 +141,6 @@ config SND_VERBOSE_PROCFS | |||
151 | 141 | ||
152 | config SND_VERBOSE_PRINTK | 142 | config SND_VERBOSE_PRINTK |
153 | bool "Verbose printk" | 143 | bool "Verbose printk" |
154 | depends on SND | ||
155 | help | 144 | help |
156 | Say Y here to enable verbose log messages. These messages | 145 | Say Y here to enable verbose log messages. These messages |
157 | will help to identify source file and position containing | 146 | will help to identify source file and position containing |
@@ -161,16 +150,17 @@ config SND_VERBOSE_PRINTK | |||
161 | 150 | ||
162 | config SND_DEBUG | 151 | config SND_DEBUG |
163 | bool "Debug" | 152 | bool "Debug" |
164 | depends on SND | ||
165 | help | 153 | help |
166 | Say Y here to enable ALSA debug code. | 154 | Say Y here to enable ALSA debug code. |
167 | 155 | ||
168 | config SND_DEBUG_DETECT | 156 | config SND_DEBUG_VERBOSE |
169 | bool "Debug detection" | 157 | bool "More verbose debug" |
170 | depends on SND_DEBUG | 158 | depends on SND_DEBUG |
171 | help | 159 | help |
172 | Say Y here to enable extra-verbose log messages printed when | 160 | Say Y here to enable extra-verbose debugging messages. |
173 | detecting devices. | 161 | |
162 | Let me repeat: it enables EXTRA-VERBOSE DEBUGGING messages. | ||
163 | So, say Y only if you are ready to be annoyed. | ||
174 | 164 | ||
175 | config SND_PCM_XRUN_DEBUG | 165 | config SND_PCM_XRUN_DEBUG |
176 | bool "Enable PCM ring buffer overrun/underrun debugging" | 166 | bool "Enable PCM ring buffer overrun/underrun debugging" |
@@ -184,4 +174,3 @@ config SND_PCM_XRUN_DEBUG | |||
184 | 174 | ||
185 | config SND_VMASTER | 175 | config SND_VMASTER |
186 | bool | 176 | bool |
187 | depends on SND | ||
diff --git a/sound/core/control.c b/sound/core/control.c index 01a1a5af47bb..281b2e2ef0ea 100644 --- a/sound/core/control.c +++ b/sound/core/control.c | |||
@@ -684,7 +684,8 @@ static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl, | |||
684 | return result; | 684 | return result; |
685 | } | 685 | } |
686 | 686 | ||
687 | int snd_ctl_elem_read(struct snd_card *card, struct snd_ctl_elem_value *control) | 687 | static int snd_ctl_elem_read(struct snd_card *card, |
688 | struct snd_ctl_elem_value *control) | ||
688 | { | 689 | { |
689 | struct snd_kcontrol *kctl; | 690 | struct snd_kcontrol *kctl; |
690 | struct snd_kcontrol_volatile *vd; | 691 | struct snd_kcontrol_volatile *vd; |
@@ -734,8 +735,8 @@ static int snd_ctl_elem_read_user(struct snd_card *card, | |||
734 | return result; | 735 | return result; |
735 | } | 736 | } |
736 | 737 | ||
737 | int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, | 738 | static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, |
738 | struct snd_ctl_elem_value *control) | 739 | struct snd_ctl_elem_value *control) |
739 | { | 740 | { |
740 | struct snd_kcontrol *kctl; | 741 | struct snd_kcontrol *kctl; |
741 | struct snd_kcontrol_volatile *vd; | 742 | struct snd_kcontrol_volatile *vd; |
diff --git a/sound/core/init.c b/sound/core/init.c index ac0573416130..5c254d498ae0 100644 --- a/sound/core/init.c +++ b/sound/core/init.c | |||
@@ -46,17 +46,24 @@ static char *slots[SNDRV_CARDS]; | |||
46 | module_param_array(slots, charp, NULL, 0444); | 46 | module_param_array(slots, charp, NULL, 0444); |
47 | MODULE_PARM_DESC(slots, "Module names assigned to the slots."); | 47 | MODULE_PARM_DESC(slots, "Module names assigned to the slots."); |
48 | 48 | ||
49 | /* return non-zero if the given index is already reserved for another | 49 | /* return non-zero if the given index is reserved for the given |
50 | * module via slots option | 50 | * module via slots option |
51 | */ | 51 | */ |
52 | static int module_slot_mismatch(struct module *module, int idx) | 52 | static int module_slot_match(struct module *module, int idx) |
53 | { | 53 | { |
54 | int match = 1; | ||
54 | #ifdef MODULE | 55 | #ifdef MODULE |
55 | char *s1, *s2; | 56 | const char *s1, *s2; |
57 | |||
56 | if (!module || !module->name || !slots[idx]) | 58 | if (!module || !module->name || !slots[idx]) |
57 | return 0; | 59 | return 0; |
58 | s1 = slots[idx]; | 60 | |
59 | s2 = module->name; | 61 | s1 = module->name; |
62 | s2 = slots[idx]; | ||
63 | if (*s2 == '!') { | ||
64 | match = 0; /* negative match */ | ||
65 | s2++; | ||
66 | } | ||
60 | /* compare module name strings | 67 | /* compare module name strings |
61 | * hyphens are handled as equivalent with underscore | 68 | * hyphens are handled as equivalent with underscore |
62 | */ | 69 | */ |
@@ -68,12 +75,12 @@ static int module_slot_mismatch(struct module *module, int idx) | |||
68 | if (c2 == '-') | 75 | if (c2 == '-') |
69 | c2 = '_'; | 76 | c2 = '_'; |
70 | if (c1 != c2) | 77 | if (c1 != c2) |
71 | return 1; | 78 | return !match; |
72 | if (!c1) | 79 | if (!c1) |
73 | break; | 80 | break; |
74 | } | 81 | } |
75 | #endif | 82 | #endif /* MODULE */ |
76 | return 0; | 83 | return match; |
77 | } | 84 | } |
78 | 85 | ||
79 | #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) | 86 | #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) |
@@ -129,7 +136,7 @@ struct snd_card *snd_card_new(int idx, const char *xid, | |||
129 | struct module *module, int extra_size) | 136 | struct module *module, int extra_size) |
130 | { | 137 | { |
131 | struct snd_card *card; | 138 | struct snd_card *card; |
132 | int err; | 139 | int err, idx2; |
133 | 140 | ||
134 | if (extra_size < 0) | 141 | if (extra_size < 0) |
135 | extra_size = 0; | 142 | extra_size = 0; |
@@ -144,35 +151,41 @@ struct snd_card *snd_card_new(int idx, const char *xid, | |||
144 | err = 0; | 151 | err = 0; |
145 | mutex_lock(&snd_card_mutex); | 152 | mutex_lock(&snd_card_mutex); |
146 | if (idx < 0) { | 153 | if (idx < 0) { |
147 | int idx2; | ||
148 | for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) | 154 | for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) |
149 | /* idx == -1 == 0xffff means: take any free slot */ | 155 | /* idx == -1 == 0xffff means: take any free slot */ |
150 | if (~snd_cards_lock & idx & 1<<idx2) { | 156 | if (~snd_cards_lock & idx & 1<<idx2) { |
151 | if (module_slot_mismatch(module, idx2)) | 157 | if (module_slot_match(module, idx2)) { |
152 | continue; | 158 | idx = idx2; |
153 | idx = idx2; | 159 | break; |
154 | if (idx >= snd_ecards_limit) | 160 | } |
155 | snd_ecards_limit = idx + 1; | 161 | } |
156 | break; | 162 | } |
163 | if (idx < 0) { | ||
164 | for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) | ||
165 | /* idx == -1 == 0xffff means: take any free slot */ | ||
166 | if (~snd_cards_lock & idx & 1<<idx2) { | ||
167 | if (!slots[idx2] || !*slots[idx2]) { | ||
168 | idx = idx2; | ||
169 | break; | ||
170 | } | ||
157 | } | 171 | } |
158 | } else { | ||
159 | if (idx < snd_ecards_limit) { | ||
160 | if (snd_cards_lock & (1 << idx)) | ||
161 | err = -EBUSY; /* invalid */ | ||
162 | } else { | ||
163 | if (idx < SNDRV_CARDS) | ||
164 | snd_ecards_limit = idx + 1; /* increase the limit */ | ||
165 | else | ||
166 | err = -ENODEV; | ||
167 | } | ||
168 | } | 172 | } |
169 | if (idx < 0 || err < 0) { | 173 | if (idx < 0) |
174 | err = -ENODEV; | ||
175 | else if (idx < snd_ecards_limit) { | ||
176 | if (snd_cards_lock & (1 << idx)) | ||
177 | err = -EBUSY; /* invalid */ | ||
178 | } else if (idx >= SNDRV_CARDS) | ||
179 | err = -ENODEV; | ||
180 | if (err < 0) { | ||
170 | mutex_unlock(&snd_card_mutex); | 181 | mutex_unlock(&snd_card_mutex); |
171 | snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i), error: %d\n", | 182 | snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i), error: %d\n", |
172 | idx, snd_ecards_limit - 1, err); | 183 | idx, snd_ecards_limit - 1, err); |
173 | goto __error; | 184 | goto __error; |
174 | } | 185 | } |
175 | snd_cards_lock |= 1 << idx; /* lock it */ | 186 | snd_cards_lock |= 1 << idx; /* lock it */ |
187 | if (idx >= snd_ecards_limit) | ||
188 | snd_ecards_limit = idx + 1; /* increase the limit */ | ||
176 | mutex_unlock(&snd_card_mutex); | 189 | mutex_unlock(&snd_card_mutex); |
177 | card->number = idx; | 190 | card->number = idx; |
178 | card->module = module; | 191 | card->module = module; |
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index 23b7bc02728b..f5d6d8d12979 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c | |||
@@ -80,68 +80,6 @@ struct snd_mem_list { | |||
80 | #endif | 80 | #endif |
81 | 81 | ||
82 | /* | 82 | /* |
83 | * Hacks | ||
84 | */ | ||
85 | |||
86 | #if defined(__i386__) | ||
87 | /* | ||
88 | * A hack to allocate large buffers via dma_alloc_coherent() | ||
89 | * | ||
90 | * since dma_alloc_coherent always tries GFP_DMA when the requested | ||
91 | * pci memory region is below 32bit, it happens quite often that even | ||
92 | * 2 order of pages cannot be allocated. | ||
93 | * | ||
94 | * so in the following, we allocate at first without dma_mask, so that | ||
95 | * allocation will be done without GFP_DMA. if the area doesn't match | ||
96 | * with the requested region, then realloate with the original dma_mask | ||
97 | * again. | ||
98 | * | ||
99 | * Really, we want to move this type of thing into dma_alloc_coherent() | ||
100 | * so dma_mask doesn't have to be messed with. | ||
101 | */ | ||
102 | |||
103 | static void *snd_dma_hack_alloc_coherent(struct device *dev, size_t size, | ||
104 | dma_addr_t *dma_handle, | ||
105 | gfp_t flags) | ||
106 | { | ||
107 | void *ret; | ||
108 | u64 dma_mask, coherent_dma_mask; | ||
109 | |||
110 | if (dev == NULL || !dev->dma_mask) | ||
111 | return dma_alloc_coherent(dev, size, dma_handle, flags); | ||
112 | dma_mask = *dev->dma_mask; | ||
113 | coherent_dma_mask = dev->coherent_dma_mask; | ||
114 | *dev->dma_mask = 0xffffffff; /* do without masking */ | ||
115 | dev->coherent_dma_mask = 0xffffffff; /* do without masking */ | ||
116 | ret = dma_alloc_coherent(dev, size, dma_handle, flags); | ||
117 | *dev->dma_mask = dma_mask; /* restore */ | ||
118 | dev->coherent_dma_mask = coherent_dma_mask; /* restore */ | ||
119 | if (ret) { | ||
120 | /* obtained address is out of range? */ | ||
121 | if (((unsigned long)*dma_handle + size - 1) & ~dma_mask) { | ||
122 | /* reallocate with the proper mask */ | ||
123 | dma_free_coherent(dev, size, ret, *dma_handle); | ||
124 | ret = dma_alloc_coherent(dev, size, dma_handle, flags); | ||
125 | } | ||
126 | } else { | ||
127 | /* wish to success now with the proper mask... */ | ||
128 | if (dma_mask != 0xffffffffUL) { | ||
129 | /* allocation with GFP_ATOMIC to avoid the long stall */ | ||
130 | flags &= ~GFP_KERNEL; | ||
131 | flags |= GFP_ATOMIC; | ||
132 | ret = dma_alloc_coherent(dev, size, dma_handle, flags); | ||
133 | } | ||
134 | } | ||
135 | return ret; | ||
136 | } | ||
137 | |||
138 | /* redefine dma_alloc_coherent for some architectures */ | ||
139 | #undef dma_alloc_coherent | ||
140 | #define dma_alloc_coherent snd_dma_hack_alloc_coherent | ||
141 | |||
142 | #endif /* arch */ | ||
143 | |||
144 | /* | ||
145 | * | 83 | * |
146 | * Generic memory allocators | 84 | * Generic memory allocators |
147 | * | 85 | * |
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 47cfa5186e34..7a1545d2d953 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c | |||
@@ -148,7 +148,7 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid) | |||
148 | return NULL; | 148 | return NULL; |
149 | } | 149 | } |
150 | spin_unlock_irqrestore(&clients_lock, flags); | 150 | spin_unlock_irqrestore(&clients_lock, flags); |
151 | #ifdef CONFIG_KMOD | 151 | #ifdef CONFIG_MODULES |
152 | if (!in_interrupt()) { | 152 | if (!in_interrupt()) { |
153 | static char client_requested[SNDRV_SEQ_GLOBAL_CLIENTS]; | 153 | static char client_requested[SNDRV_SEQ_GLOBAL_CLIENTS]; |
154 | static char card_requested[SNDRV_CARDS]; | 154 | static char card_requested[SNDRV_CARDS]; |
diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index 2f00ad28a2b7..05410e536a4f 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c | |||
@@ -124,7 +124,7 @@ static void snd_seq_device_info(struct snd_info_entry *entry, | |||
124 | * load all registered drivers (called from seq_clientmgr.c) | 124 | * load all registered drivers (called from seq_clientmgr.c) |
125 | */ | 125 | */ |
126 | 126 | ||
127 | #ifdef CONFIG_KMOD | 127 | #ifdef CONFIG_MODULES |
128 | /* avoid auto-loading during module_init() */ | 128 | /* avoid auto-loading during module_init() */ |
129 | static int snd_seq_in_init; | 129 | static int snd_seq_in_init; |
130 | void snd_seq_autoload_lock(void) | 130 | void snd_seq_autoload_lock(void) |
@@ -140,7 +140,7 @@ void snd_seq_autoload_unlock(void) | |||
140 | 140 | ||
141 | void snd_seq_device_load_drivers(void) | 141 | void snd_seq_device_load_drivers(void) |
142 | { | 142 | { |
143 | #ifdef CONFIG_KMOD | 143 | #ifdef CONFIG_MODULES |
144 | struct ops_list *ops; | 144 | struct ops_list *ops; |
145 | 145 | ||
146 | /* Calling request_module during module_init() | 146 | /* Calling request_module during module_init() |
@@ -566,7 +566,5 @@ EXPORT_SYMBOL(snd_seq_device_load_drivers); | |||
566 | EXPORT_SYMBOL(snd_seq_device_new); | 566 | EXPORT_SYMBOL(snd_seq_device_new); |
567 | EXPORT_SYMBOL(snd_seq_device_register_driver); | 567 | EXPORT_SYMBOL(snd_seq_device_register_driver); |
568 | EXPORT_SYMBOL(snd_seq_device_unregister_driver); | 568 | EXPORT_SYMBOL(snd_seq_device_unregister_driver); |
569 | #ifdef CONFIG_KMOD | ||
570 | EXPORT_SYMBOL(snd_seq_autoload_lock); | 569 | EXPORT_SYMBOL(snd_seq_autoload_lock); |
571 | EXPORT_SYMBOL(snd_seq_autoload_unlock); | 570 | EXPORT_SYMBOL(snd_seq_autoload_unlock); |
572 | #endif | ||
diff --git a/sound/core/sound.c b/sound/core/sound.c index 6c8ab48c689a..09a94953745a 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c | |||
@@ -60,14 +60,14 @@ EXPORT_SYMBOL(snd_ecards_limit); | |||
60 | static struct snd_minor *snd_minors[SNDRV_OS_MINORS]; | 60 | static struct snd_minor *snd_minors[SNDRV_OS_MINORS]; |
61 | static DEFINE_MUTEX(sound_mutex); | 61 | static DEFINE_MUTEX(sound_mutex); |
62 | 62 | ||
63 | #ifdef CONFIG_KMOD | 63 | #ifdef CONFIG_MODULES |
64 | 64 | ||
65 | /** | 65 | /** |
66 | * snd_request_card - try to load the card module | 66 | * snd_request_card - try to load the card module |
67 | * @card: the card number | 67 | * @card: the card number |
68 | * | 68 | * |
69 | * Tries to load the module "snd-card-X" for the given card number | 69 | * Tries to load the module "snd-card-X" for the given card number |
70 | * via KMOD. Returns immediately if already loaded. | 70 | * via request_module. Returns immediately if already loaded. |
71 | */ | 71 | */ |
72 | void snd_request_card(int card) | 72 | void snd_request_card(int card) |
73 | { | 73 | { |
@@ -92,7 +92,7 @@ static void snd_request_other(int minor) | |||
92 | request_module(str); | 92 | request_module(str); |
93 | } | 93 | } |
94 | 94 | ||
95 | #endif /* request_module support */ | 95 | #endif /* modular kernel */ |
96 | 96 | ||
97 | /** | 97 | /** |
98 | * snd_lookup_minor_data - get user data of a registered device | 98 | * snd_lookup_minor_data - get user data of a registered device |
@@ -132,7 +132,7 @@ static int snd_open(struct inode *inode, struct file *file) | |||
132 | return -ENODEV; | 132 | return -ENODEV; |
133 | mptr = snd_minors[minor]; | 133 | mptr = snd_minors[minor]; |
134 | if (mptr == NULL) { | 134 | if (mptr == NULL) { |
135 | #ifdef CONFIG_KMOD | 135 | #ifdef CONFIG_MODULES |
136 | int dev = SNDRV_MINOR_DEVICE(minor); | 136 | int dev = SNDRV_MINOR_DEVICE(minor); |
137 | if (dev == SNDRV_MINOR_CONTROL) { | 137 | if (dev == SNDRV_MINOR_CONTROL) { |
138 | /* /dev/aloadC? */ | 138 | /* /dev/aloadC? */ |
diff --git a/sound/core/timer.c b/sound/core/timer.c index 9d8184a2c2d0..0af337efc64e 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c | |||
@@ -146,7 +146,7 @@ static struct snd_timer *snd_timer_find(struct snd_timer_id *tid) | |||
146 | return NULL; | 146 | return NULL; |
147 | } | 147 | } |
148 | 148 | ||
149 | #ifdef CONFIG_KMOD | 149 | #ifdef CONFIG_MODULES |
150 | 150 | ||
151 | static void snd_timer_request(struct snd_timer_id *tid) | 151 | static void snd_timer_request(struct snd_timer_id *tid) |
152 | { | 152 | { |
@@ -259,8 +259,8 @@ int snd_timer_open(struct snd_timer_instance **ti, | |||
259 | /* open a master instance */ | 259 | /* open a master instance */ |
260 | mutex_lock(®ister_mutex); | 260 | mutex_lock(®ister_mutex); |
261 | timer = snd_timer_find(tid); | 261 | timer = snd_timer_find(tid); |
262 | #ifdef CONFIG_KMOD | 262 | #ifdef CONFIG_MODULES |
263 | if (timer == NULL) { | 263 | if (!timer) { |
264 | mutex_unlock(®ister_mutex); | 264 | mutex_unlock(®ister_mutex); |
265 | snd_timer_request(tid); | 265 | snd_timer_request(tid); |
266 | mutex_lock(®ister_mutex); | 266 | mutex_lock(®ister_mutex); |
diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig index 602b58e3b55d..255fd18b9aec 100644 --- a/sound/drivers/Kconfig +++ b/sound/drivers/Kconfig | |||
@@ -1,15 +1,41 @@ | |||
1 | # ALSA generic drivers | 1 | config SND_MPU401_UART |
2 | tristate | ||
3 | select SND_RAWMIDI | ||
2 | 4 | ||
3 | menu "Generic devices" | 5 | config SND_OPL3_LIB |
4 | depends on SND!=n | 6 | tristate |
7 | select SND_TIMER | ||
8 | select SND_HWDEP | ||
5 | 9 | ||
10 | config SND_OPL4_LIB | ||
11 | tristate | ||
12 | select SND_TIMER | ||
13 | select SND_HWDEP | ||
14 | |||
15 | config SND_VX_LIB | ||
16 | tristate | ||
17 | select SND_HWDEP | ||
18 | select SND_PCM | ||
19 | |||
20 | config SND_AC97_CODEC | ||
21 | tristate | ||
22 | select SND_PCM | ||
23 | select AC97_BUS | ||
24 | select SND_VMASTER | ||
25 | |||
26 | menuconfig SND_DRIVERS | ||
27 | bool "Generic sound devices" | ||
28 | default y | ||
29 | help | ||
30 | Support for generic sound devices. | ||
31 | |||
32 | if SND_DRIVERS | ||
6 | 33 | ||
7 | config SND_PCSP | 34 | config SND_PCSP |
8 | tristate "PC-Speaker support (READ HELP!)" | 35 | tristate "PC-Speaker support (READ HELP!)" |
9 | depends on PCSPKR_PLATFORM && X86_PC && HIGH_RES_TIMERS | 36 | depends on PCSPKR_PLATFORM && X86_PC && HIGH_RES_TIMERS |
10 | depends on INPUT | 37 | depends on INPUT |
11 | depends on EXPERIMENTAL | 38 | depends on EXPERIMENTAL |
12 | depends on SND | ||
13 | select SND_PCM | 39 | select SND_PCM |
14 | help | 40 | help |
15 | If you don't have a sound card in your computer, you can include a | 41 | If you don't have a sound card in your computer, you can include a |
@@ -35,33 +61,8 @@ config SND_PCSP | |||
35 | Say M if you don't. | 61 | Say M if you don't. |
36 | Say Y only if you really know what you do. | 62 | Say Y only if you really know what you do. |
37 | 63 | ||
38 | config SND_MPU401_UART | ||
39 | tristate | ||
40 | select SND_RAWMIDI | ||
41 | |||
42 | config SND_OPL3_LIB | ||
43 | tristate | ||
44 | select SND_TIMER | ||
45 | select SND_HWDEP | ||
46 | |||
47 | config SND_OPL4_LIB | ||
48 | tristate | ||
49 | select SND_TIMER | ||
50 | select SND_HWDEP | ||
51 | |||
52 | config SND_VX_LIB | ||
53 | tristate | ||
54 | select SND_HWDEP | ||
55 | select SND_PCM | ||
56 | |||
57 | config SND_AC97_CODEC | ||
58 | tristate | ||
59 | select SND_PCM | ||
60 | select AC97_BUS | ||
61 | |||
62 | config SND_DUMMY | 64 | config SND_DUMMY |
63 | tristate "Dummy (/dev/null) soundcard" | 65 | tristate "Dummy (/dev/null) soundcard" |
64 | depends on SND | ||
65 | select SND_PCM | 66 | select SND_PCM |
66 | help | 67 | help |
67 | Say Y here to include the dummy driver. This driver does | 68 | Say Y here to include the dummy driver. This driver does |
@@ -90,7 +91,6 @@ config SND_VIRMIDI | |||
90 | 91 | ||
91 | config SND_MTPAV | 92 | config SND_MTPAV |
92 | tristate "MOTU MidiTimePiece AV multiport MIDI" | 93 | tristate "MOTU MidiTimePiece AV multiport MIDI" |
93 | depends on SND | ||
94 | select SND_RAWMIDI | 94 | select SND_RAWMIDI |
95 | help | 95 | help |
96 | To use a MOTU MidiTimePiece AV multiport MIDI adapter | 96 | To use a MOTU MidiTimePiece AV multiport MIDI adapter |
@@ -102,7 +102,7 @@ config SND_MTPAV | |||
102 | 102 | ||
103 | config SND_MTS64 | 103 | config SND_MTS64 |
104 | tristate "ESI Miditerminal 4140 driver" | 104 | tristate "ESI Miditerminal 4140 driver" |
105 | depends on SND && PARPORT | 105 | depends on PARPORT |
106 | select SND_RAWMIDI | 106 | select SND_RAWMIDI |
107 | help | 107 | help |
108 | The ESI Miditerminal 4140 is a 4 In 4 Out MIDI Interface with | 108 | The ESI Miditerminal 4140 is a 4 In 4 Out MIDI Interface with |
@@ -115,7 +115,6 @@ config SND_MTS64 | |||
115 | 115 | ||
116 | config SND_SERIAL_U16550 | 116 | config SND_SERIAL_U16550 |
117 | tristate "UART16550 serial MIDI driver" | 117 | tristate "UART16550 serial MIDI driver" |
118 | depends on SND | ||
119 | select SND_RAWMIDI | 118 | select SND_RAWMIDI |
120 | help | 119 | help |
121 | To include support for MIDI serial port interfaces, say Y here | 120 | To include support for MIDI serial port interfaces, say Y here |
@@ -131,7 +130,6 @@ config SND_SERIAL_U16550 | |||
131 | 130 | ||
132 | config SND_MPU401 | 131 | config SND_MPU401 |
133 | tristate "Generic MPU-401 UART driver" | 132 | tristate "Generic MPU-401 UART driver" |
134 | depends on SND | ||
135 | select SND_MPU401_UART | 133 | select SND_MPU401_UART |
136 | help | 134 | help |
137 | Say Y here to include support for MIDI ports compatible with | 135 | Say Y here to include support for MIDI ports compatible with |
@@ -142,7 +140,7 @@ config SND_MPU401 | |||
142 | 140 | ||
143 | config SND_PORTMAN2X4 | 141 | config SND_PORTMAN2X4 |
144 | tristate "Portman 2x4 driver" | 142 | tristate "Portman 2x4 driver" |
145 | depends on SND && PARPORT | 143 | depends on PARPORT |
146 | select SND_RAWMIDI | 144 | select SND_RAWMIDI |
147 | help | 145 | help |
148 | Say Y here to include support for Midiman Portman 2x4 parallel | 146 | Say Y here to include support for Midiman Portman 2x4 parallel |
@@ -153,7 +151,7 @@ config SND_PORTMAN2X4 | |||
153 | 151 | ||
154 | config SND_ML403_AC97CR | 152 | config SND_ML403_AC97CR |
155 | tristate "Xilinx ML403 AC97 Controller Reference" | 153 | tristate "Xilinx ML403 AC97 Controller Reference" |
156 | depends on SND && XILINX_VIRTEX | 154 | depends on XILINX_VIRTEX |
157 | select SND_AC97_CODEC | 155 | select SND_AC97_CODEC |
158 | help | 156 | help |
159 | Say Y here to include support for the | 157 | Say Y here to include support for the |
@@ -163,4 +161,25 @@ config SND_ML403_AC97CR | |||
163 | To compile this driver as a module, choose M here: the module | 161 | To compile this driver as a module, choose M here: the module |
164 | will be called snd-ml403_ac97cr. | 162 | will be called snd-ml403_ac97cr. |
165 | 163 | ||
166 | endmenu | 164 | config SND_AC97_POWER_SAVE |
165 | bool "AC97 Power-Saving Mode" | ||
166 | depends on SND_AC97_CODEC && EXPERIMENTAL | ||
167 | default n | ||
168 | help | ||
169 | Say Y here to enable the aggressive power-saving support of | ||
170 | AC97 codecs. In this mode, the power-mode is dynamically | ||
171 | controlled at each open/close. | ||
172 | |||
173 | The mode is activated by passing power_save=1 option to | ||
174 | snd-ac97-codec driver. You can toggle it dynamically over | ||
175 | sysfs, too. | ||
176 | |||
177 | config SND_AC97_POWER_SAVE_DEFAULT | ||
178 | int "Default time-out for AC97 power-save mode" | ||
179 | depends on SND_AC97_POWER_SAVE | ||
180 | default 0 | ||
181 | help | ||
182 | The default time-out value in seconds for AC97 automatic | ||
183 | power-save mode. 0 means to disable the power-save mode. | ||
184 | |||
185 | endif # SND_DRIVERS | ||
diff --git a/sound/drivers/vx/vx_hwdep.c b/sound/drivers/vx/vx_hwdep.c index 1dfe6948e6ff..efd22e92bced 100644 --- a/sound/drivers/vx/vx_hwdep.c +++ b/sound/drivers/vx/vx_hwdep.c | |||
@@ -183,7 +183,7 @@ static int vx_hwdep_dsp_load(struct snd_hwdep *hw, | |||
183 | kfree(fw); | 183 | kfree(fw); |
184 | return -ENOMEM; | 184 | return -ENOMEM; |
185 | } | 185 | } |
186 | if (copy_from_user(fw->data, dsp->image, dsp->length)) { | 186 | if (copy_from_user((void *)fw->data, dsp->image, dsp->length)) { |
187 | free_fw(fw); | 187 | free_fw(fw); |
188 | return -EFAULT; | 188 | return -EFAULT; |
189 | } | 189 | } |
diff --git a/sound/i2c/cs8427.c b/sound/i2c/cs8427.c index e57e9cbe6a0f..9c3d361accfb 100644 --- a/sound/i2c/cs8427.c +++ b/sound/i2c/cs8427.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
25 | #include <linux/init.h> | 25 | #include <linux/init.h> |
26 | #include <asm/unaligned.h> | ||
26 | #include <sound/core.h> | 27 | #include <sound/core.h> |
27 | #include <sound/control.h> | 28 | #include <sound/control.h> |
28 | #include <sound/pcm.h> | 29 | #include <sound/pcm.h> |
@@ -264,10 +265,7 @@ int snd_cs8427_create(struct snd_i2c_bus *bus, | |||
264 | goto __fail; | 265 | goto __fail; |
265 | } | 266 | } |
266 | /* write default channel status bytes */ | 267 | /* write default channel status bytes */ |
267 | buf[0] = ((unsigned char)(SNDRV_PCM_DEFAULT_CON_SPDIF >> 0)); | 268 | put_unaligned_le32(SNDRV_PCM_DEFAULT_CON_SPDIF, buf); |
268 | buf[1] = ((unsigned char)(SNDRV_PCM_DEFAULT_CON_SPDIF >> 8)); | ||
269 | buf[2] = ((unsigned char)(SNDRV_PCM_DEFAULT_CON_SPDIF >> 16)); | ||
270 | buf[3] = ((unsigned char)(SNDRV_PCM_DEFAULT_CON_SPDIF >> 24)); | ||
271 | memset(buf + 4, 0, 24 - 4); | 269 | memset(buf + 4, 0, 24 - 4); |
272 | if (snd_cs8427_send_corudata(device, 0, buf, 24) < 0) | 270 | if (snd_cs8427_send_corudata(device, 0, buf, 24) < 0) |
273 | goto __fail; | 271 | goto __fail; |
diff --git a/sound/i2c/l3/uda1341.c b/sound/i2c/l3/uda1341.c index bfa5d2c3608b..1f4942ea1414 100644 --- a/sound/i2c/l3/uda1341.c +++ b/sound/i2c/l3/uda1341.c | |||
@@ -17,8 +17,6 @@ | |||
17 | * 2002-05-12 Tomas Kasparek another code cleanup | 17 | * 2002-05-12 Tomas Kasparek another code cleanup |
18 | */ | 18 | */ |
19 | 19 | ||
20 | /* $Id: uda1341.c,v 1.18 2005/11/17 14:17:21 tiwai Exp $ */ | ||
21 | |||
22 | #include <linux/module.h> | 20 | #include <linux/module.h> |
23 | #include <linux/init.h> | 21 | #include <linux/init.h> |
24 | #include <linux/types.h> | 22 | #include <linux/types.h> |
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index 2639a6ab8f2e..25347a25d63c 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig | |||
@@ -21,12 +21,17 @@ config SND_SB16_DSP | |||
21 | select SND_PCM | 21 | select SND_PCM |
22 | select SND_SB_COMMON | 22 | select SND_SB_COMMON |
23 | 23 | ||
24 | menu "ISA devices" | 24 | menuconfig SND_ISA |
25 | depends on SND!=n && ISA && ISA_DMA_API | 25 | bool "ISA sound devices" |
26 | depends on ISA && ISA_DMA_API | ||
27 | default y | ||
28 | help | ||
29 | Support for sound devices connected via the ISA bus. | ||
30 | |||
31 | if SND_ISA | ||
26 | 32 | ||
27 | config SND_ADLIB | 33 | config SND_ADLIB |
28 | tristate "AdLib FM card" | 34 | tristate "AdLib FM card" |
29 | depends on SND | ||
30 | select SND_OPL3_LIB | 35 | select SND_OPL3_LIB |
31 | help | 36 | help |
32 | Say Y here to include support for AdLib FM cards. | 37 | Say Y here to include support for AdLib FM cards. |
@@ -36,7 +41,7 @@ config SND_ADLIB | |||
36 | 41 | ||
37 | config SND_AD1816A | 42 | config SND_AD1816A |
38 | tristate "Analog Devices SoundPort AD1816A" | 43 | tristate "Analog Devices SoundPort AD1816A" |
39 | depends on SND && PNP && ISA | 44 | depends on PNP |
40 | select ISAPNP | 45 | select ISAPNP |
41 | select SND_OPL3_LIB | 46 | select SND_OPL3_LIB |
42 | select SND_MPU401_UART | 47 | select SND_MPU401_UART |
@@ -50,7 +55,6 @@ config SND_AD1816A | |||
50 | 55 | ||
51 | config SND_AD1848 | 56 | config SND_AD1848 |
52 | tristate "Generic AD1848/CS4248 driver" | 57 | tristate "Generic AD1848/CS4248 driver" |
53 | depends on SND | ||
54 | select SND_AD1848_LIB | 58 | select SND_AD1848_LIB |
55 | help | 59 | help |
56 | Say Y here to include support for AD1848 (Analog Devices) or | 60 | Say Y here to include support for AD1848 (Analog Devices) or |
@@ -64,7 +68,7 @@ config SND_AD1848 | |||
64 | 68 | ||
65 | config SND_ALS100 | 69 | config SND_ALS100 |
66 | tristate "Avance Logic ALS100/ALS120" | 70 | tristate "Avance Logic ALS100/ALS120" |
67 | depends on SND && PNP && ISA | 71 | depends on PNP |
68 | select ISAPNP | 72 | select ISAPNP |
69 | select SND_OPL3_LIB | 73 | select SND_OPL3_LIB |
70 | select SND_MPU401_UART | 74 | select SND_MPU401_UART |
@@ -78,7 +82,7 @@ config SND_ALS100 | |||
78 | 82 | ||
79 | config SND_AZT2320 | 83 | config SND_AZT2320 |
80 | tristate "Aztech Systems AZT2320" | 84 | tristate "Aztech Systems AZT2320" |
81 | depends on SND && PNP && ISA | 85 | depends on PNP |
82 | select ISAPNP | 86 | select ISAPNP |
83 | select SND_OPL3_LIB | 87 | select SND_OPL3_LIB |
84 | select SND_MPU401_UART | 88 | select SND_MPU401_UART |
@@ -92,7 +96,6 @@ config SND_AZT2320 | |||
92 | 96 | ||
93 | config SND_CMI8330 | 97 | config SND_CMI8330 |
94 | tristate "C-Media CMI8330" | 98 | tristate "C-Media CMI8330" |
95 | depends on SND | ||
96 | select SND_AD1848_LIB | 99 | select SND_AD1848_LIB |
97 | select SND_SB16_DSP | 100 | select SND_SB16_DSP |
98 | help | 101 | help |
@@ -104,7 +107,6 @@ config SND_CMI8330 | |||
104 | 107 | ||
105 | config SND_CS4231 | 108 | config SND_CS4231 |
106 | tristate "Generic Cirrus Logic CS4231 driver" | 109 | tristate "Generic Cirrus Logic CS4231 driver" |
107 | depends on SND | ||
108 | select SND_MPU401_UART | 110 | select SND_MPU401_UART |
109 | select SND_CS4231_LIB | 111 | select SND_CS4231_LIB |
110 | help | 112 | help |
@@ -116,7 +118,6 @@ config SND_CS4231 | |||
116 | 118 | ||
117 | config SND_CS4232 | 119 | config SND_CS4232 |
118 | tristate "Generic Cirrus Logic CS4232 driver" | 120 | tristate "Generic Cirrus Logic CS4232 driver" |
119 | depends on SND | ||
120 | select SND_OPL3_LIB | 121 | select SND_OPL3_LIB |
121 | select SND_MPU401_UART | 122 | select SND_MPU401_UART |
122 | select SND_CS4231_LIB | 123 | select SND_CS4231_LIB |
@@ -129,7 +130,6 @@ config SND_CS4232 | |||
129 | 130 | ||
130 | config SND_CS4236 | 131 | config SND_CS4236 |
131 | tristate "Generic Cirrus Logic CS4236+ driver" | 132 | tristate "Generic Cirrus Logic CS4236+ driver" |
132 | depends on SND | ||
133 | select SND_OPL3_LIB | 133 | select SND_OPL3_LIB |
134 | select SND_MPU401_UART | 134 | select SND_MPU401_UART |
135 | select SND_CS4231_LIB | 135 | select SND_CS4231_LIB |
@@ -142,7 +142,7 @@ config SND_CS4236 | |||
142 | 142 | ||
143 | config SND_DT019X | 143 | config SND_DT019X |
144 | tristate "Diamond Technologies DT-019X, Avance Logic ALS-007" | 144 | tristate "Diamond Technologies DT-019X, Avance Logic ALS-007" |
145 | depends on SND && PNP && ISA | 145 | depends on PNP |
146 | select ISAPNP | 146 | select ISAPNP |
147 | select SND_OPL3_LIB | 147 | select SND_OPL3_LIB |
148 | select SND_MPU401_UART | 148 | select SND_MPU401_UART |
@@ -156,7 +156,7 @@ config SND_DT019X | |||
156 | 156 | ||
157 | config SND_ES968 | 157 | config SND_ES968 |
158 | tristate "Generic ESS ES968 driver" | 158 | tristate "Generic ESS ES968 driver" |
159 | depends on SND && PNP && ISA | 159 | depends on PNP |
160 | select ISAPNP | 160 | select ISAPNP |
161 | select SND_MPU401_UART | 161 | select SND_MPU401_UART |
162 | select SND_SB8_DSP | 162 | select SND_SB8_DSP |
@@ -168,7 +168,6 @@ config SND_ES968 | |||
168 | 168 | ||
169 | config SND_ES1688 | 169 | config SND_ES1688 |
170 | tristate "Generic ESS ES688/ES1688 driver" | 170 | tristate "Generic ESS ES688/ES1688 driver" |
171 | depends on SND | ||
172 | select SND_OPL3_LIB | 171 | select SND_OPL3_LIB |
173 | select SND_MPU401_UART | 172 | select SND_MPU401_UART |
174 | select SND_PCM | 173 | select SND_PCM |
@@ -181,7 +180,6 @@ config SND_ES1688 | |||
181 | 180 | ||
182 | config SND_ES18XX | 181 | config SND_ES18XX |
183 | tristate "Generic ESS ES18xx driver" | 182 | tristate "Generic ESS ES18xx driver" |
184 | depends on SND | ||
185 | select SND_OPL3_LIB | 183 | select SND_OPL3_LIB |
186 | select SND_MPU401_UART | 184 | select SND_MPU401_UART |
187 | select SND_PCM | 185 | select SND_PCM |
@@ -193,7 +191,7 @@ config SND_ES18XX | |||
193 | 191 | ||
194 | config SND_SC6000 | 192 | config SND_SC6000 |
195 | tristate "Gallant SC-6000, Audio Excel DSP 16" | 193 | tristate "Gallant SC-6000, Audio Excel DSP 16" |
196 | depends on SND && HAS_IOPORT | 194 | depends on HAS_IOPORT |
197 | select SND_AD1848_LIB | 195 | select SND_AD1848_LIB |
198 | select SND_OPL3_LIB | 196 | select SND_OPL3_LIB |
199 | select SND_MPU401_UART | 197 | select SND_MPU401_UART |
@@ -204,15 +202,10 @@ config SND_SC6000 | |||
204 | To compile this driver as a module, choose M here: the module | 202 | To compile this driver as a module, choose M here: the module |
205 | will be called snd-sc6000. | 203 | will be called snd-sc6000. |
206 | 204 | ||
207 | config SND_GUS_SYNTH | ||
208 | tristate | ||
209 | |||
210 | config SND_GUSCLASSIC | 205 | config SND_GUSCLASSIC |
211 | tristate "Gravis UltraSound Classic" | 206 | tristate "Gravis UltraSound Classic" |
212 | depends on SND | ||
213 | select SND_RAWMIDI | 207 | select SND_RAWMIDI |
214 | select SND_PCM | 208 | select SND_PCM |
215 | select SND_GUS_SYNTH | ||
216 | help | 209 | help |
217 | Say Y here to include support for Gravis UltraSound Classic | 210 | Say Y here to include support for Gravis UltraSound Classic |
218 | soundcards. | 211 | soundcards. |
@@ -222,11 +215,9 @@ config SND_GUSCLASSIC | |||
222 | 215 | ||
223 | config SND_GUSEXTREME | 216 | config SND_GUSEXTREME |
224 | tristate "Gravis UltraSound Extreme" | 217 | tristate "Gravis UltraSound Extreme" |
225 | depends on SND | ||
226 | select SND_HWDEP | 218 | select SND_HWDEP |
227 | select SND_MPU401_UART | 219 | select SND_MPU401_UART |
228 | select SND_PCM | 220 | select SND_PCM |
229 | select SND_GUS_SYNTH | ||
230 | help | 221 | help |
231 | Say Y here to include support for Gravis UltraSound Extreme | 222 | Say Y here to include support for Gravis UltraSound Extreme |
232 | soundcards. | 223 | soundcards. |
@@ -236,10 +227,8 @@ config SND_GUSEXTREME | |||
236 | 227 | ||
237 | config SND_GUSMAX | 228 | config SND_GUSMAX |
238 | tristate "Gravis UltraSound MAX" | 229 | tristate "Gravis UltraSound MAX" |
239 | depends on SND | ||
240 | select SND_RAWMIDI | 230 | select SND_RAWMIDI |
241 | select SND_CS4231_LIB | 231 | select SND_CS4231_LIB |
242 | select SND_GUS_SYNTH | ||
243 | help | 232 | help |
244 | Say Y here to include support for Gravis UltraSound MAX | 233 | Say Y here to include support for Gravis UltraSound MAX |
245 | soundcards. | 234 | soundcards. |
@@ -249,10 +238,9 @@ config SND_GUSMAX | |||
249 | 238 | ||
250 | config SND_INTERWAVE | 239 | config SND_INTERWAVE |
251 | tristate "AMD InterWave, Gravis UltraSound PnP" | 240 | tristate "AMD InterWave, Gravis UltraSound PnP" |
252 | depends on SND && PNP && ISA | 241 | depends on PNP |
253 | select SND_RAWMIDI | 242 | select SND_RAWMIDI |
254 | select SND_CS4231_LIB | 243 | select SND_CS4231_LIB |
255 | select SND_GUS_SYNTH | ||
256 | help | 244 | help |
257 | Say Y here to include support for AMD InterWave based | 245 | Say Y here to include support for AMD InterWave based |
258 | soundcards (Gravis UltraSound Plug & Play, STB SoundRage32, | 246 | soundcards (Gravis UltraSound Plug & Play, STB SoundRage32, |
@@ -263,10 +251,9 @@ config SND_INTERWAVE | |||
263 | 251 | ||
264 | config SND_INTERWAVE_STB | 252 | config SND_INTERWAVE_STB |
265 | tristate "AMD InterWave + TEA6330T (UltraSound 32-Pro)" | 253 | tristate "AMD InterWave + TEA6330T (UltraSound 32-Pro)" |
266 | depends on SND && PNP && ISA | 254 | depends on PNP |
267 | select SND_RAWMIDI | 255 | select SND_RAWMIDI |
268 | select SND_CS4231_LIB | 256 | select SND_CS4231_LIB |
269 | select SND_GUS_SYNTH | ||
270 | help | 257 | help |
271 | Say Y here to include support for AMD InterWave based | 258 | Say Y here to include support for AMD InterWave based |
272 | soundcards with a TEA6330T bass and treble regulator | 259 | soundcards with a TEA6330T bass and treble regulator |
@@ -277,7 +264,6 @@ config SND_INTERWAVE_STB | |||
277 | 264 | ||
278 | config SND_OPL3SA2 | 265 | config SND_OPL3SA2 |
279 | tristate "Yamaha OPL3-SA2/SA3" | 266 | tristate "Yamaha OPL3-SA2/SA3" |
280 | depends on SND | ||
281 | select SND_OPL3_LIB | 267 | select SND_OPL3_LIB |
282 | select SND_MPU401_UART | 268 | select SND_MPU401_UART |
283 | select SND_CS4231_LIB | 269 | select SND_CS4231_LIB |
@@ -290,7 +276,6 @@ config SND_OPL3SA2 | |||
290 | 276 | ||
291 | config SND_OPTI92X_AD1848 | 277 | config SND_OPTI92X_AD1848 |
292 | tristate "OPTi 82C92x - AD1848" | 278 | tristate "OPTi 82C92x - AD1848" |
293 | depends on SND | ||
294 | select SND_OPL3_LIB | 279 | select SND_OPL3_LIB |
295 | select SND_OPL4_LIB | 280 | select SND_OPL4_LIB |
296 | select SND_MPU401_UART | 281 | select SND_MPU401_UART |
@@ -304,7 +289,6 @@ config SND_OPTI92X_AD1848 | |||
304 | 289 | ||
305 | config SND_OPTI92X_CS4231 | 290 | config SND_OPTI92X_CS4231 |
306 | tristate "OPTi 82C92x - CS4231" | 291 | tristate "OPTi 82C92x - CS4231" |
307 | depends on SND | ||
308 | select SND_OPL3_LIB | 292 | select SND_OPL3_LIB |
309 | select SND_OPL4_LIB | 293 | select SND_OPL4_LIB |
310 | select SND_MPU401_UART | 294 | select SND_MPU401_UART |
@@ -318,10 +302,9 @@ config SND_OPTI92X_CS4231 | |||
318 | 302 | ||
319 | config SND_OPTI93X | 303 | config SND_OPTI93X |
320 | tristate "OPTi 82C93x" | 304 | tristate "OPTi 82C93x" |
321 | depends on SND | ||
322 | select SND_OPL3_LIB | 305 | select SND_OPL3_LIB |
323 | select SND_MPU401_UART | 306 | select SND_MPU401_UART |
324 | select SND_PCM | 307 | select SND_CS4231_LIB |
325 | help | 308 | help |
326 | Say Y here to include support for soundcards based on Opti | 309 | Say Y here to include support for soundcards based on Opti |
327 | 82C93x chips. | 310 | 82C93x chips. |
@@ -331,7 +314,6 @@ config SND_OPTI93X | |||
331 | 314 | ||
332 | config SND_MIRO | 315 | config SND_MIRO |
333 | tristate "Miro miroSOUND PCM1pro/PCM12/PCM20radio driver" | 316 | tristate "Miro miroSOUND PCM1pro/PCM12/PCM20radio driver" |
334 | depends on SND | ||
335 | select SND_OPL4_LIB | 317 | select SND_OPL4_LIB |
336 | select SND_CS4231_LIB | 318 | select SND_CS4231_LIB |
337 | select SND_MPU401_UART | 319 | select SND_MPU401_UART |
@@ -345,7 +327,6 @@ config SND_MIRO | |||
345 | 327 | ||
346 | config SND_SB8 | 328 | config SND_SB8 |
347 | tristate "Sound Blaster 1.0/2.0/Pro (8-bit)" | 329 | tristate "Sound Blaster 1.0/2.0/Pro (8-bit)" |
348 | depends on SND | ||
349 | select SND_OPL3_LIB | 330 | select SND_OPL3_LIB |
350 | select SND_RAWMIDI | 331 | select SND_RAWMIDI |
351 | select SND_SB8_DSP | 332 | select SND_SB8_DSP |
@@ -358,7 +339,6 @@ config SND_SB8 | |||
358 | 339 | ||
359 | config SND_SB16 | 340 | config SND_SB16 |
360 | tristate "Sound Blaster 16 (PnP)" | 341 | tristate "Sound Blaster 16 (PnP)" |
361 | depends on SND | ||
362 | select SND_OPL3_LIB | 342 | select SND_OPL3_LIB |
363 | select SND_MPU401_UART | 343 | select SND_MPU401_UART |
364 | select SND_SB16_DSP | 344 | select SND_SB16_DSP |
@@ -371,7 +351,6 @@ config SND_SB16 | |||
371 | 351 | ||
372 | config SND_SBAWE | 352 | config SND_SBAWE |
373 | tristate "Sound Blaster AWE (32,64) (PnP)" | 353 | tristate "Sound Blaster AWE (32,64) (PnP)" |
374 | depends on SND | ||
375 | select SND_OPL3_LIB | 354 | select SND_OPL3_LIB |
376 | select SND_MPU401_UART | 355 | select SND_MPU401_UART |
377 | select SND_SB16_DSP | 356 | select SND_SB16_DSP |
@@ -402,7 +381,6 @@ config SND_SB16_CSP_FIRMWARE_IN_KERNEL | |||
402 | 381 | ||
403 | config SND_SGALAXY | 382 | config SND_SGALAXY |
404 | tristate "Aztech Sound Galaxy" | 383 | tristate "Aztech Sound Galaxy" |
405 | depends on SND | ||
406 | select SND_AD1848_LIB | 384 | select SND_AD1848_LIB |
407 | help | 385 | help |
408 | Say Y here to include support for Aztech Sound Galaxy | 386 | Say Y here to include support for Aztech Sound Galaxy |
@@ -413,7 +391,6 @@ config SND_SGALAXY | |||
413 | 391 | ||
414 | config SND_SSCAPE | 392 | config SND_SSCAPE |
415 | tristate "Ensoniq SoundScape PnP driver" | 393 | tristate "Ensoniq SoundScape PnP driver" |
416 | depends on SND | ||
417 | select SND_HWDEP | 394 | select SND_HWDEP |
418 | select SND_MPU401_UART | 395 | select SND_MPU401_UART |
419 | select SND_CS4231_LIB | 396 | select SND_CS4231_LIB |
@@ -426,7 +403,6 @@ config SND_SSCAPE | |||
426 | 403 | ||
427 | config SND_WAVEFRONT | 404 | config SND_WAVEFRONT |
428 | tristate "Turtle Beach Maui,Tropez,Tropez+ (Wavefront)" | 405 | tristate "Turtle Beach Maui,Tropez,Tropez+ (Wavefront)" |
429 | depends on SND | ||
430 | select FW_LOADER | 406 | select FW_LOADER |
431 | select SND_OPL3_LIB | 407 | select SND_OPL3_LIB |
432 | select SND_MPU401_UART | 408 | select SND_MPU401_UART |
@@ -448,4 +424,5 @@ config SND_WAVEFRONT_FIRMWARE_IN_KERNEL | |||
448 | you need to install the firmware files from the | 424 | you need to install the firmware files from the |
449 | alsa-firmware package. | 425 | alsa-firmware package. |
450 | 426 | ||
451 | endmenu | 427 | endif # SND_ISA |
428 | |||
diff --git a/sound/isa/cs423x/cs4231_lib.c b/sound/isa/cs423x/cs4231_lib.c index 0aa8649e5c7f..521db705d179 100644 --- a/sound/isa/cs423x/cs4231_lib.c +++ b/sound/isa/cs423x/cs4231_lib.c | |||
@@ -119,6 +119,42 @@ static unsigned char snd_cs4231_original_image[32] = | |||
119 | 0x00, /* 1f/31 - cbrl */ | 119 | 0x00, /* 1f/31 - cbrl */ |
120 | }; | 120 | }; |
121 | 121 | ||
122 | static unsigned char snd_opti93x_original_image[32] = | ||
123 | { | ||
124 | 0x00, /* 00/00 - l_mixout_outctrl */ | ||
125 | 0x00, /* 01/01 - r_mixout_outctrl */ | ||
126 | 0x88, /* 02/02 - l_cd_inctrl */ | ||
127 | 0x88, /* 03/03 - r_cd_inctrl */ | ||
128 | 0x88, /* 04/04 - l_a1/fm_inctrl */ | ||
129 | 0x88, /* 05/05 - r_a1/fm_inctrl */ | ||
130 | 0x80, /* 06/06 - l_dac_inctrl */ | ||
131 | 0x80, /* 07/07 - r_dac_inctrl */ | ||
132 | 0x00, /* 08/08 - ply_dataform_reg */ | ||
133 | 0x00, /* 09/09 - if_conf */ | ||
134 | 0x00, /* 0a/10 - pin_ctrl */ | ||
135 | 0x00, /* 0b/11 - err_init_reg */ | ||
136 | 0x0a, /* 0c/12 - id_reg */ | ||
137 | 0x00, /* 0d/13 - reserved */ | ||
138 | 0x00, /* 0e/14 - ply_upcount_reg */ | ||
139 | 0x00, /* 0f/15 - ply_lowcount_reg */ | ||
140 | 0x88, /* 10/16 - reserved/l_a1_inctrl */ | ||
141 | 0x88, /* 11/17 - reserved/r_a1_inctrl */ | ||
142 | 0x88, /* 12/18 - l_line_inctrl */ | ||
143 | 0x88, /* 13/19 - r_line_inctrl */ | ||
144 | 0x88, /* 14/20 - l_mic_inctrl */ | ||
145 | 0x88, /* 15/21 - r_mic_inctrl */ | ||
146 | 0x80, /* 16/22 - l_out_outctrl */ | ||
147 | 0x80, /* 17/23 - r_out_outctrl */ | ||
148 | 0x00, /* 18/24 - reserved */ | ||
149 | 0x00, /* 19/25 - reserved */ | ||
150 | 0x00, /* 1a/26 - reserved */ | ||
151 | 0x00, /* 1b/27 - reserved */ | ||
152 | 0x00, /* 1c/28 - cap_dataform_reg */ | ||
153 | 0x00, /* 1d/29 - reserved */ | ||
154 | 0x00, /* 1e/30 - cap_upcount_reg */ | ||
155 | 0x00 /* 1f/31 - cap_lowcount_reg */ | ||
156 | }; | ||
157 | |||
122 | /* | 158 | /* |
123 | * Basic I/O functions | 159 | * Basic I/O functions |
124 | */ | 160 | */ |
@@ -895,7 +931,7 @@ static int snd_cs4231_capture_prepare(struct snd_pcm_substream *substream) | |||
895 | return 0; | 931 | return 0; |
896 | } | 932 | } |
897 | 933 | ||
898 | static void snd_cs4231_overrange(struct snd_cs4231 *chip) | 934 | void snd_cs4231_overrange(struct snd_cs4231 *chip) |
899 | { | 935 | { |
900 | unsigned long flags; | 936 | unsigned long flags; |
901 | unsigned char res; | 937 | unsigned char res; |
@@ -1054,8 +1090,11 @@ static int snd_cs4231_probe(struct snd_cs4231 *chip) | |||
1054 | chip->image[CS4231_IFACE_CTRL] = | 1090 | chip->image[CS4231_IFACE_CTRL] = |
1055 | (chip->image[CS4231_IFACE_CTRL] & ~CS4231_SINGLE_DMA) | | 1091 | (chip->image[CS4231_IFACE_CTRL] & ~CS4231_SINGLE_DMA) | |
1056 | (chip->single_dma ? CS4231_SINGLE_DMA : 0); | 1092 | (chip->single_dma ? CS4231_SINGLE_DMA : 0); |
1057 | chip->image[CS4231_ALT_FEATURE_1] = 0x80; | 1093 | if (chip->hardware != CS4231_HW_OPTI93X) { |
1058 | chip->image[CS4231_ALT_FEATURE_2] = chip->hardware == CS4231_HW_INTERWAVE ? 0xc2 : 0x01; | 1094 | chip->image[CS4231_ALT_FEATURE_1] = 0x80; |
1095 | chip->image[CS4231_ALT_FEATURE_2] = | ||
1096 | chip->hardware == CS4231_HW_INTERWAVE ? 0xc2 : 0x01; | ||
1097 | } | ||
1059 | ptr = (unsigned char *) &chip->image; | 1098 | ptr = (unsigned char *) &chip->image; |
1060 | snd_cs4231_mce_down(chip); | 1099 | snd_cs4231_mce_down(chip); |
1061 | spin_lock_irqsave(&chip->reg_lock, flags); | 1100 | spin_lock_irqsave(&chip->reg_lock, flags); |
@@ -1376,6 +1415,7 @@ const char *snd_cs4231_chip_id(struct snd_cs4231 *chip) | |||
1376 | case CS4231_HW_INTERWAVE: return "AMD InterWave"; | 1415 | case CS4231_HW_INTERWAVE: return "AMD InterWave"; |
1377 | case CS4231_HW_OPL3SA2: return chip->card->shortname; | 1416 | case CS4231_HW_OPL3SA2: return chip->card->shortname; |
1378 | case CS4231_HW_AD1845: return "AD1845"; | 1417 | case CS4231_HW_AD1845: return "AD1845"; |
1418 | case CS4231_HW_OPTI93X: return "OPTi 93x"; | ||
1379 | default: return "???"; | 1419 | default: return "???"; |
1380 | } | 1420 | } |
1381 | } | 1421 | } |
@@ -1401,8 +1441,13 @@ static int snd_cs4231_new(struct snd_card *card, | |||
1401 | chip->rate_constraint = snd_cs4231_xrate; | 1441 | chip->rate_constraint = snd_cs4231_xrate; |
1402 | chip->set_playback_format = snd_cs4231_playback_format; | 1442 | chip->set_playback_format = snd_cs4231_playback_format; |
1403 | chip->set_capture_format = snd_cs4231_capture_format; | 1443 | chip->set_capture_format = snd_cs4231_capture_format; |
1404 | memcpy(&chip->image, &snd_cs4231_original_image, sizeof(snd_cs4231_original_image)); | 1444 | if (chip->hardware == CS4231_HW_OPTI93X) |
1405 | 1445 | memcpy(&chip->image, &snd_opti93x_original_image, | |
1446 | sizeof(snd_opti93x_original_image)); | ||
1447 | else | ||
1448 | memcpy(&chip->image, &snd_cs4231_original_image, | ||
1449 | sizeof(snd_cs4231_original_image)); | ||
1450 | |||
1406 | *rchip = chip; | 1451 | *rchip = chip; |
1407 | return 0; | 1452 | return 0; |
1408 | } | 1453 | } |
@@ -1790,6 +1835,48 @@ CS4231_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0), | |||
1790 | CS4231_SINGLE("Loopback Capture Volume", 0, CS4231_LOOPBACK, 2, 63, 1) | 1835 | CS4231_SINGLE("Loopback Capture Volume", 0, CS4231_LOOPBACK, 2, 63, 1) |
1791 | }; | 1836 | }; |
1792 | 1837 | ||
1838 | static struct snd_kcontrol_new snd_opti93x_controls[] = { | ||
1839 | CS4231_DOUBLE("Master Playback Switch", 0, | ||
1840 | OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1), | ||
1841 | CS4231_DOUBLE("Master Playback Volume", 0, | ||
1842 | OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1), | ||
1843 | CS4231_DOUBLE("PCM Playback Switch", 0, | ||
1844 | CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), | ||
1845 | CS4231_DOUBLE("PCM Playback Volume", 0, | ||
1846 | CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 31, 1), | ||
1847 | CS4231_DOUBLE("FM Playback Switch", 0, | ||
1848 | CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), | ||
1849 | CS4231_DOUBLE("FM Playback Volume", 0, | ||
1850 | CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 1, 1, 15, 1), | ||
1851 | CS4231_DOUBLE("Line Playback Switch", 0, | ||
1852 | CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), | ||
1853 | CS4231_DOUBLE("Line Playback Volume", 0, | ||
1854 | CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 15, 1), | ||
1855 | CS4231_DOUBLE("Mic Playback Switch", 0, | ||
1856 | OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1), | ||
1857 | CS4231_DOUBLE("Mic Playback Volume", 0, | ||
1858 | OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1), | ||
1859 | CS4231_DOUBLE("Mic Boost", 0, | ||
1860 | CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0), | ||
1861 | CS4231_DOUBLE("CD Playback Switch", 0, | ||
1862 | CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), | ||
1863 | CS4231_DOUBLE("CD Playback Volume", 0, | ||
1864 | CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 1, 1, 15, 1), | ||
1865 | CS4231_DOUBLE("Aux Playback Switch", 0, | ||
1866 | OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1), | ||
1867 | CS4231_DOUBLE("Aux Playback Volume", 0, | ||
1868 | OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1), | ||
1869 | CS4231_DOUBLE("Capture Volume", 0, | ||
1870 | CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0), | ||
1871 | { | ||
1872 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1873 | .name = "Capture Source", | ||
1874 | .info = snd_cs4231_info_mux, | ||
1875 | .get = snd_cs4231_get_mux, | ||
1876 | .put = snd_cs4231_put_mux, | ||
1877 | } | ||
1878 | }; | ||
1879 | |||
1793 | int snd_cs4231_mixer(struct snd_cs4231 *chip) | 1880 | int snd_cs4231_mixer(struct snd_cs4231 *chip) |
1794 | { | 1881 | { |
1795 | struct snd_card *card; | 1882 | struct snd_card *card; |
@@ -1802,10 +1889,22 @@ int snd_cs4231_mixer(struct snd_cs4231 *chip) | |||
1802 | 1889 | ||
1803 | strcpy(card->mixername, chip->pcm->name); | 1890 | strcpy(card->mixername, chip->pcm->name); |
1804 | 1891 | ||
1805 | for (idx = 0; idx < ARRAY_SIZE(snd_cs4231_controls); idx++) { | 1892 | if (chip->hardware == CS4231_HW_OPTI93X) |
1806 | if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4231_controls[idx], chip))) < 0) | 1893 | for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) { |
1807 | return err; | 1894 | err = snd_ctl_add(card, |
1808 | } | 1895 | snd_ctl_new1(&snd_opti93x_controls[idx], |
1896 | chip)); | ||
1897 | if (err < 0) | ||
1898 | return err; | ||
1899 | } | ||
1900 | else | ||
1901 | for (idx = 0; idx < ARRAY_SIZE(snd_cs4231_controls); idx++) { | ||
1902 | err = snd_ctl_add(card, | ||
1903 | snd_ctl_new1(&snd_cs4231_controls[idx], | ||
1904 | chip)); | ||
1905 | if (err < 0) | ||
1906 | return err; | ||
1907 | } | ||
1809 | return 0; | 1908 | return 0; |
1810 | } | 1909 | } |
1811 | 1910 | ||
@@ -1815,6 +1914,7 @@ EXPORT_SYMBOL(snd_cs4236_ext_out); | |||
1815 | EXPORT_SYMBOL(snd_cs4236_ext_in); | 1914 | EXPORT_SYMBOL(snd_cs4236_ext_in); |
1816 | EXPORT_SYMBOL(snd_cs4231_mce_up); | 1915 | EXPORT_SYMBOL(snd_cs4231_mce_up); |
1817 | EXPORT_SYMBOL(snd_cs4231_mce_down); | 1916 | EXPORT_SYMBOL(snd_cs4231_mce_down); |
1917 | EXPORT_SYMBOL(snd_cs4231_overrange); | ||
1818 | EXPORT_SYMBOL(snd_cs4231_interrupt); | 1918 | EXPORT_SYMBOL(snd_cs4231_interrupt); |
1819 | EXPORT_SYMBOL(snd_cs4231_chip_id); | 1919 | EXPORT_SYMBOL(snd_cs4231_chip_id); |
1820 | EXPORT_SYMBOL(snd_cs4231_create); | 1920 | EXPORT_SYMBOL(snd_cs4231_create); |
diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index fe1afc13a01d..41c047e665ec 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c | |||
@@ -33,15 +33,10 @@ | |||
33 | #include <asm/io.h> | 33 | #include <asm/io.h> |
34 | #include <asm/dma.h> | 34 | #include <asm/dma.h> |
35 | #include <sound/core.h> | 35 | #include <sound/core.h> |
36 | #ifdef CS4231 | 36 | #if defined(CS4231) || defined(OPTi93X) |
37 | #include <sound/cs4231.h> | 37 | #include <sound/cs4231.h> |
38 | #else | 38 | #else |
39 | #ifndef OPTi93X | ||
40 | #include <sound/ad1848.h> | 39 | #include <sound/ad1848.h> |
41 | #else | ||
42 | #include <sound/control.h> | ||
43 | #include <sound/pcm.h> | ||
44 | #endif /* OPTi93X */ | ||
45 | #endif /* CS4231 */ | 40 | #endif /* CS4231 */ |
46 | #include <sound/mpu401.h> | 41 | #include <sound/mpu401.h> |
47 | #include <sound/opl3.h> | 42 | #include <sound/opl3.h> |
@@ -109,7 +104,6 @@ module_param(dma2, int, 0444); | |||
109 | MODULE_PARM_DESC(dma2, "2nd dma # for opti9xx driver."); | 104 | MODULE_PARM_DESC(dma2, "2nd dma # for opti9xx driver."); |
110 | #endif /* CS4231 || OPTi93X */ | 105 | #endif /* CS4231 || OPTi93X */ |
111 | 106 | ||
112 | #define OPTi9XX_HW_DETECT 0 | ||
113 | #define OPTi9XX_HW_82C928 1 | 107 | #define OPTi9XX_HW_82C928 1 |
114 | #define OPTi9XX_HW_82C929 2 | 108 | #define OPTi9XX_HW_82C929 2 |
115 | #define OPTi9XX_HW_82C924 3 | 109 | #define OPTi9XX_HW_82C924 3 |
@@ -123,105 +117,12 @@ MODULE_PARM_DESC(dma2, "2nd dma # for opti9xx driver."); | |||
123 | 117 | ||
124 | #ifdef OPTi93X | 118 | #ifdef OPTi93X |
125 | 119 | ||
126 | #define OPTi93X_INDEX 0x00 | ||
127 | #define OPTi93X_DATA 0x01 | ||
128 | #define OPTi93X_STATUS 0x02 | 120 | #define OPTi93X_STATUS 0x02 |
129 | #define OPTi93X_DDATA 0x03 | ||
130 | #define OPTi93X_PORT(chip, r) ((chip)->port + OPTi93X_##r) | 121 | #define OPTi93X_PORT(chip, r) ((chip)->port + OPTi93X_##r) |
131 | 122 | ||
132 | #define OPTi93X_MIXOUT_LEFT 0x00 | ||
133 | #define OPTi93X_MIXOUT_RIGHT 0x01 | ||
134 | #define OPTi93X_CD_LEFT_INPUT 0x02 | ||
135 | #define OPTi93X_CD_RIGHT_INPUT 0x03 | ||
136 | #define OPTi930_AUX_LEFT_INPUT 0x04 | ||
137 | #define OPTi930_AUX_RIGHT_INPUT 0x05 | ||
138 | #define OPTi931_FM_LEFT_INPUT 0x04 | ||
139 | #define OPTi931_FM_RIGHT_INPUT 0x05 | ||
140 | #define OPTi93X_DAC_LEFT 0x06 | ||
141 | #define OPTi93X_DAC_RIGHT 0x07 | ||
142 | #define OPTi93X_PLAY_FORMAT 0x08 | ||
143 | #define OPTi93X_IFACE_CONF 0x09 | ||
144 | #define OPTi93X_PIN_CTRL 0x0a | ||
145 | #define OPTi93X_ERR_INIT 0x0b | ||
146 | #define OPTi93X_ID 0x0c | ||
147 | #define OPTi93X_PLAY_UPR_CNT 0x0e | ||
148 | #define OPTi93X_PLAY_LWR_CNT 0x0f | ||
149 | #define OPTi931_AUX_LEFT_INPUT 0x10 | ||
150 | #define OPTi931_AUX_RIGHT_INPUT 0x11 | ||
151 | #define OPTi93X_LINE_LEFT_INPUT 0x12 | ||
152 | #define OPTi93X_LINE_RIGHT_INPUT 0x13 | ||
153 | #define OPTi93X_MIC_LEFT_INPUT 0x14 | ||
154 | #define OPTi93X_MIC_RIGHT_INPUT 0x15 | ||
155 | #define OPTi93X_OUT_LEFT 0x16 | ||
156 | #define OPTi93X_OUT_RIGHT 0x17 | ||
157 | #define OPTi93X_CAPT_FORMAT 0x1c | ||
158 | #define OPTi93X_CAPT_UPR_CNT 0x1e | ||
159 | #define OPTi93X_CAPT_LWR_CNT 0x1f | ||
160 | |||
161 | #define OPTi93X_TRD 0x20 | ||
162 | #define OPTi93X_MCE 0x40 | ||
163 | #define OPTi93X_INIT 0x80 | ||
164 | |||
165 | #define OPTi93X_MIXOUT_MIC_GAIN 0x20 | ||
166 | #define OPTi93X_MIXOUT_LINE 0x00 | ||
167 | #define OPTi93X_MIXOUT_CD 0x40 | ||
168 | #define OPTi93X_MIXOUT_MIC 0x80 | ||
169 | #define OPTi93X_MIXOUT_MIXER 0xc0 | ||
170 | |||
171 | #define OPTi93X_STEREO 0x10 | ||
172 | #define OPTi93X_LINEAR_8 0x00 | ||
173 | #define OPTi93X_ULAW_8 0x20 | ||
174 | #define OPTi93X_LINEAR_16_LIT 0x40 | ||
175 | #define OPTi93X_ALAW_8 0x60 | ||
176 | #define OPTi93X_ADPCM_16 0xa0 | ||
177 | #define OPTi93X_LINEAR_16_BIG 0xc0 | ||
178 | |||
179 | #define OPTi93X_CAPTURE_PIO 0x80 | ||
180 | #define OPTi93X_PLAYBACK_PIO 0x40 | ||
181 | #define OPTi93X_AUTOCALIB 0x08 | ||
182 | #define OPTi93X_SINGLE_DMA 0x04 | ||
183 | #define OPTi93X_CAPTURE_ENABLE 0x02 | ||
184 | #define OPTi93X_PLAYBACK_ENABLE 0x01 | ||
185 | |||
186 | #define OPTi93X_IRQ_ENABLE 0x02 | ||
187 | |||
188 | #define OPTi93X_DMA_REQUEST 0x10 | ||
189 | #define OPTi93X_CALIB_IN_PROGRESS 0x20 | ||
190 | |||
191 | #define OPTi93X_IRQ_PLAYBACK 0x04 | 123 | #define OPTi93X_IRQ_PLAYBACK 0x04 |
192 | #define OPTi93X_IRQ_CAPTURE 0x08 | 124 | #define OPTi93X_IRQ_CAPTURE 0x08 |
193 | 125 | ||
194 | |||
195 | struct snd_opti93x { | ||
196 | unsigned long port; | ||
197 | struct resource *res_port; | ||
198 | int irq; | ||
199 | int dma1; | ||
200 | int dma2; | ||
201 | |||
202 | struct snd_opti9xx *chip; | ||
203 | unsigned short hardware; | ||
204 | unsigned char image[32]; | ||
205 | |||
206 | unsigned char mce_bit; | ||
207 | unsigned short mode; | ||
208 | int mute; | ||
209 | |||
210 | spinlock_t lock; | ||
211 | |||
212 | struct snd_card *card; | ||
213 | struct snd_pcm *pcm; | ||
214 | struct snd_pcm_substream *playback_substream; | ||
215 | struct snd_pcm_substream *capture_substream; | ||
216 | unsigned int p_dma_size; | ||
217 | unsigned int c_dma_size; | ||
218 | }; | ||
219 | |||
220 | #define OPTi93X_MODE_NONE 0x00 | ||
221 | #define OPTi93X_MODE_PLAY 0x01 | ||
222 | #define OPTi93X_MODE_CAPTURE 0x02 | ||
223 | #define OPTi93X_MODE_OPEN (OPTi93X_MODE_PLAY | OPTi93X_MODE_CAPTURE) | ||
224 | |||
225 | #endif /* OPTi93X */ | 126 | #endif /* OPTi93X */ |
226 | 127 | ||
227 | struct snd_opti9xx { | 128 | struct snd_opti9xx { |
@@ -234,6 +135,7 @@ struct snd_opti9xx { | |||
234 | unsigned long mc_base_size; | 135 | unsigned long mc_base_size; |
235 | #ifdef OPTi93X | 136 | #ifdef OPTi93X |
236 | unsigned long mc_indir_index; | 137 | unsigned long mc_indir_index; |
138 | struct snd_cs4231 *codec; | ||
237 | #endif /* OPTi93X */ | 139 | #endif /* OPTi93X */ |
238 | unsigned long pwd_reg; | 140 | unsigned long pwd_reg; |
239 | 141 | ||
@@ -491,16 +393,9 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip) | |||
491 | break; | 393 | break; |
492 | 394 | ||
493 | #else /* OPTi93X */ | 395 | #else /* OPTi93X */ |
494 | case OPTi9XX_HW_82C930: | ||
495 | case OPTi9XX_HW_82C931: | 396 | case OPTi9XX_HW_82C931: |
496 | case OPTi9XX_HW_82C933: | 397 | case OPTi9XX_HW_82C933: |
497 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x03); | 398 | /* |
498 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(3), 0x00, 0xff); | ||
499 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(4), 0x10 | | ||
500 | (chip->hardware == OPTi9XX_HW_82C930 ? 0x00 : 0x04), | ||
501 | 0x34); | ||
502 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(5), 0x20, 0xbf); | ||
503 | /* | ||
504 | * The BTC 1817DW has QS1000 wavetable which is connected | 399 | * The BTC 1817DW has QS1000 wavetable which is connected |
505 | * to the serial digital input of the OPTI931. | 400 | * to the serial digital input of the OPTI931. |
506 | */ | 401 | */ |
@@ -510,6 +405,13 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip) | |||
510 | * or digital input signal. | 405 | * or digital input signal. |
511 | */ | 406 | */ |
512 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(26), 0x01, 0x01); | 407 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(26), 0x01, 0x01); |
408 | case OPTi9XX_HW_82C930: /* FALL THROUGH */ | ||
409 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x03); | ||
410 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(3), 0x00, 0xff); | ||
411 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(4), 0x10 | | ||
412 | (chip->hardware == OPTi9XX_HW_82C930 ? 0x00 : 0x04), | ||
413 | 0x34); | ||
414 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(5), 0x20, 0xbf); | ||
513 | break; | 415 | break; |
514 | #endif /* OPTi93X */ | 416 | #endif /* OPTi93X */ |
515 | 417 | ||
@@ -654,979 +556,23 @@ __skip_mpu: | |||
654 | 556 | ||
655 | #ifdef OPTi93X | 557 | #ifdef OPTi93X |
656 | 558 | ||
657 | static unsigned char snd_opti93x_default_image[32] = | ||
658 | { | ||
659 | 0x00, /* 00/00 - l_mixout_outctrl */ | ||
660 | 0x00, /* 01/01 - r_mixout_outctrl */ | ||
661 | 0x88, /* 02/02 - l_cd_inctrl */ | ||
662 | 0x88, /* 03/03 - r_cd_inctrl */ | ||
663 | 0x88, /* 04/04 - l_a1/fm_inctrl */ | ||
664 | 0x88, /* 05/05 - r_a1/fm_inctrl */ | ||
665 | 0x80, /* 06/06 - l_dac_inctrl */ | ||
666 | 0x80, /* 07/07 - r_dac_inctrl */ | ||
667 | 0x00, /* 08/08 - ply_dataform_reg */ | ||
668 | 0x00, /* 09/09 - if_conf */ | ||
669 | 0x00, /* 0a/10 - pin_ctrl */ | ||
670 | 0x00, /* 0b/11 - err_init_reg */ | ||
671 | 0x0a, /* 0c/12 - id_reg */ | ||
672 | 0x00, /* 0d/13 - reserved */ | ||
673 | 0x00, /* 0e/14 - ply_upcount_reg */ | ||
674 | 0x00, /* 0f/15 - ply_lowcount_reg */ | ||
675 | 0x88, /* 10/16 - reserved/l_a1_inctrl */ | ||
676 | 0x88, /* 11/17 - reserved/r_a1_inctrl */ | ||
677 | 0x88, /* 12/18 - l_line_inctrl */ | ||
678 | 0x88, /* 13/19 - r_line_inctrl */ | ||
679 | 0x88, /* 14/20 - l_mic_inctrl */ | ||
680 | 0x88, /* 15/21 - r_mic_inctrl */ | ||
681 | 0x80, /* 16/22 - l_out_outctrl */ | ||
682 | 0x80, /* 17/23 - r_out_outctrl */ | ||
683 | 0x00, /* 18/24 - reserved */ | ||
684 | 0x00, /* 19/25 - reserved */ | ||
685 | 0x00, /* 1a/26 - reserved */ | ||
686 | 0x00, /* 1b/27 - reserved */ | ||
687 | 0x00, /* 1c/28 - cap_dataform_reg */ | ||
688 | 0x00, /* 1d/29 - reserved */ | ||
689 | 0x00, /* 1e/30 - cap_upcount_reg */ | ||
690 | 0x00 /* 1f/31 - cap_lowcount_reg */ | ||
691 | }; | ||
692 | |||
693 | |||
694 | static int snd_opti93x_busy_wait(struct snd_opti93x *chip) | ||
695 | { | ||
696 | int timeout; | ||
697 | |||
698 | for (timeout = 250; timeout-- > 0; udelay(10)) | ||
699 | if (!(inb(OPTi93X_PORT(chip, INDEX)) & OPTi93X_INIT)) | ||
700 | return 0; | ||
701 | |||
702 | snd_printk("chip still busy.\n"); | ||
703 | return -EBUSY; | ||
704 | } | ||
705 | |||
706 | static unsigned char snd_opti93x_in(struct snd_opti93x *chip, unsigned char reg) | ||
707 | { | ||
708 | snd_opti93x_busy_wait(chip); | ||
709 | outb(chip->mce_bit | (reg & 0x1f), OPTi93X_PORT(chip, INDEX)); | ||
710 | return inb(OPTi93X_PORT(chip, DATA)); | ||
711 | } | ||
712 | |||
713 | static void snd_opti93x_out(struct snd_opti93x *chip, unsigned char reg, | ||
714 | unsigned char value) | ||
715 | { | ||
716 | snd_opti93x_busy_wait(chip); | ||
717 | outb(chip->mce_bit | (reg & 0x1f), OPTi93X_PORT(chip, INDEX)); | ||
718 | outb(value, OPTi93X_PORT(chip, DATA)); | ||
719 | } | ||
720 | |||
721 | static void snd_opti93x_out_image(struct snd_opti93x *chip, unsigned char reg, | ||
722 | unsigned char value) | ||
723 | { | ||
724 | snd_opti93x_out(chip, reg, chip->image[reg] = value); | ||
725 | } | ||
726 | |||
727 | static void snd_opti93x_out_mask(struct snd_opti93x *chip, unsigned char reg, | ||
728 | unsigned char mask, unsigned char value) | ||
729 | { | ||
730 | snd_opti93x_out_image(chip, reg, | ||
731 | (chip->image[reg] & ~mask) | (value & mask)); | ||
732 | } | ||
733 | |||
734 | |||
735 | static void snd_opti93x_mce_up(struct snd_opti93x *chip) | ||
736 | { | ||
737 | snd_opti93x_busy_wait(chip); | ||
738 | |||
739 | chip->mce_bit = OPTi93X_MCE; | ||
740 | if (!(inb(OPTi93X_PORT(chip, INDEX)) & OPTi93X_MCE)) | ||
741 | outb(chip->mce_bit, OPTi93X_PORT(chip, INDEX)); | ||
742 | } | ||
743 | |||
744 | static void snd_opti93x_mce_down(struct snd_opti93x *chip) | ||
745 | { | ||
746 | snd_opti93x_busy_wait(chip); | ||
747 | |||
748 | chip->mce_bit = 0; | ||
749 | if (inb(OPTi93X_PORT(chip, INDEX)) & OPTi93X_MCE) | ||
750 | outb(chip->mce_bit, OPTi93X_PORT(chip, INDEX)); | ||
751 | } | ||
752 | |||
753 | #define snd_opti93x_mute_reg(chip, reg, mute) \ | ||
754 | snd_opti93x_out(chip, reg, mute ? 0x80 : chip->image[reg]); | ||
755 | |||
756 | static void snd_opti93x_mute(struct snd_opti93x *chip, int mute) | ||
757 | { | ||
758 | mute = mute ? 1 : 0; | ||
759 | if (chip->mute == mute) | ||
760 | return; | ||
761 | |||
762 | chip->mute = mute; | ||
763 | |||
764 | snd_opti93x_mute_reg(chip, OPTi93X_CD_LEFT_INPUT, mute); | ||
765 | snd_opti93x_mute_reg(chip, OPTi93X_CD_RIGHT_INPUT, mute); | ||
766 | switch (chip->hardware) { | ||
767 | case OPTi9XX_HW_82C930: | ||
768 | snd_opti93x_mute_reg(chip, OPTi930_AUX_LEFT_INPUT, mute); | ||
769 | snd_opti93x_mute_reg(chip, OPTi930_AUX_RIGHT_INPUT, mute); | ||
770 | break; | ||
771 | case OPTi9XX_HW_82C931: | ||
772 | case OPTi9XX_HW_82C933: | ||
773 | snd_opti93x_mute_reg(chip, OPTi931_FM_LEFT_INPUT, mute); | ||
774 | snd_opti93x_mute_reg(chip, OPTi931_FM_RIGHT_INPUT, mute); | ||
775 | snd_opti93x_mute_reg(chip, OPTi931_AUX_LEFT_INPUT, mute); | ||
776 | snd_opti93x_mute_reg(chip, OPTi931_AUX_RIGHT_INPUT, mute); | ||
777 | } | ||
778 | snd_opti93x_mute_reg(chip, OPTi93X_DAC_LEFT, mute); | ||
779 | snd_opti93x_mute_reg(chip, OPTi93X_DAC_RIGHT, mute); | ||
780 | snd_opti93x_mute_reg(chip, OPTi93X_LINE_LEFT_INPUT, mute); | ||
781 | snd_opti93x_mute_reg(chip, OPTi93X_LINE_RIGHT_INPUT, mute); | ||
782 | snd_opti93x_mute_reg(chip, OPTi93X_MIC_LEFT_INPUT, mute); | ||
783 | snd_opti93x_mute_reg(chip, OPTi93X_MIC_RIGHT_INPUT, mute); | ||
784 | snd_opti93x_mute_reg(chip, OPTi93X_OUT_LEFT, mute); | ||
785 | snd_opti93x_mute_reg(chip, OPTi93X_OUT_RIGHT, mute); | ||
786 | } | ||
787 | |||
788 | |||
789 | static unsigned int snd_opti93x_get_count(unsigned char format, | ||
790 | unsigned int size) | ||
791 | { | ||
792 | switch (format & 0xe0) { | ||
793 | case OPTi93X_LINEAR_16_LIT: | ||
794 | case OPTi93X_LINEAR_16_BIG: | ||
795 | size >>= 1; | ||
796 | break; | ||
797 | case OPTi93X_ADPCM_16: | ||
798 | return size >> 2; | ||
799 | } | ||
800 | return (format & OPTi93X_STEREO) ? (size >> 1) : size; | ||
801 | } | ||
802 | |||
803 | static unsigned int rates[] = { 5512, 6615, 8000, 9600, 11025, 16000, | ||
804 | 18900, 22050, 27428, 32000, 33075, 37800, | ||
805 | 44100, 48000 }; | ||
806 | #define RATES ARRAY_SIZE(rates) | ||
807 | |||
808 | static struct snd_pcm_hw_constraint_list hw_constraints_rates = { | ||
809 | .count = RATES, | ||
810 | .list = rates, | ||
811 | .mask = 0, | ||
812 | }; | ||
813 | |||
814 | static unsigned char bits[] = { 0x01, 0x0f, 0x00, 0x0e, 0x03, 0x02, | ||
815 | 0x05, 0x07, 0x04, 0x06, 0x0d, 0x09, | ||
816 | 0x0b, 0x0c}; | ||
817 | |||
818 | static unsigned char snd_opti93x_get_freq(unsigned int rate) | ||
819 | { | ||
820 | unsigned int i; | ||
821 | |||
822 | for (i = 0; i < RATES; i++) { | ||
823 | if (rate == rates[i]) | ||
824 | return bits[i]; | ||
825 | } | ||
826 | snd_BUG(); | ||
827 | return bits[RATES-1]; | ||
828 | } | ||
829 | |||
830 | static unsigned char snd_opti93x_get_format(struct snd_opti93x *chip, | ||
831 | unsigned int format, int channels) | ||
832 | { | ||
833 | unsigned char retval = OPTi93X_LINEAR_8; | ||
834 | |||
835 | switch (format) { | ||
836 | case SNDRV_PCM_FORMAT_MU_LAW: | ||
837 | retval = OPTi93X_ULAW_8; | ||
838 | break; | ||
839 | case SNDRV_PCM_FORMAT_A_LAW: | ||
840 | retval = OPTi93X_ALAW_8; | ||
841 | break; | ||
842 | case SNDRV_PCM_FORMAT_S16_LE: | ||
843 | retval = OPTi93X_LINEAR_16_LIT; | ||
844 | break; | ||
845 | case SNDRV_PCM_FORMAT_S16_BE: | ||
846 | retval = OPTi93X_LINEAR_16_BIG; | ||
847 | break; | ||
848 | case SNDRV_PCM_FORMAT_IMA_ADPCM: | ||
849 | retval = OPTi93X_ADPCM_16; | ||
850 | } | ||
851 | return (channels > 1) ? (retval | OPTi93X_STEREO) : retval; | ||
852 | } | ||
853 | |||
854 | |||
855 | static void snd_opti93x_playback_format(struct snd_opti93x *chip, unsigned char fmt) | ||
856 | { | ||
857 | unsigned char mask; | ||
858 | |||
859 | snd_opti93x_mute(chip, 1); | ||
860 | |||
861 | snd_opti93x_mce_up(chip); | ||
862 | mask = (chip->mode & OPTi93X_MODE_CAPTURE) ? 0xf0 : 0xff; | ||
863 | snd_opti93x_out_mask(chip, OPTi93X_PLAY_FORMAT, mask, fmt); | ||
864 | snd_opti93x_mce_down(chip); | ||
865 | |||
866 | snd_opti93x_mute(chip, 0); | ||
867 | } | ||
868 | |||
869 | static void snd_opti93x_capture_format(struct snd_opti93x *chip, unsigned char fmt) | ||
870 | { | ||
871 | snd_opti93x_mute(chip, 1); | ||
872 | |||
873 | snd_opti93x_mce_up(chip); | ||
874 | if (!(chip->mode & OPTi93X_MODE_PLAY)) | ||
875 | snd_opti93x_out_mask(chip, OPTi93X_PLAY_FORMAT, 0x0f, fmt); | ||
876 | else | ||
877 | fmt = chip->image[OPTi93X_PLAY_FORMAT] & 0xf0; | ||
878 | snd_opti93x_out_image(chip, OPTi93X_CAPT_FORMAT, fmt); | ||
879 | snd_opti93x_mce_down(chip); | ||
880 | |||
881 | snd_opti93x_mute(chip, 0); | ||
882 | } | ||
883 | |||
884 | |||
885 | static int snd_opti93x_open(struct snd_opti93x *chip, unsigned int mode) | ||
886 | { | ||
887 | unsigned long flags; | ||
888 | |||
889 | spin_lock_irqsave(&chip->lock, flags); | ||
890 | |||
891 | if (chip->mode & mode) { | ||
892 | spin_unlock_irqrestore(&chip->lock, flags); | ||
893 | return -EAGAIN; | ||
894 | } | ||
895 | |||
896 | if (!(chip->mode & OPTi93X_MODE_OPEN)) { | ||
897 | outb(0x00, OPTi93X_PORT(chip, STATUS)); | ||
898 | snd_opti93x_out_mask(chip, OPTi93X_PIN_CTRL, | ||
899 | OPTi93X_IRQ_ENABLE, OPTi93X_IRQ_ENABLE); | ||
900 | chip->mode = mode; | ||
901 | } | ||
902 | else | ||
903 | chip->mode |= mode; | ||
904 | |||
905 | spin_unlock_irqrestore(&chip->lock, flags); | ||
906 | return 0; | ||
907 | } | ||
908 | |||
909 | static void snd_opti93x_close(struct snd_opti93x *chip, unsigned int mode) | ||
910 | { | ||
911 | unsigned long flags; | ||
912 | |||
913 | spin_lock_irqsave(&chip->lock, flags); | ||
914 | |||
915 | chip->mode &= ~mode; | ||
916 | if (chip->mode & OPTi93X_MODE_OPEN) { | ||
917 | spin_unlock_irqrestore(&chip->lock, flags); | ||
918 | return; | ||
919 | } | ||
920 | |||
921 | snd_opti93x_mute(chip, 1); | ||
922 | |||
923 | outb(0, OPTi93X_PORT(chip, STATUS)); | ||
924 | snd_opti93x_out_mask(chip, OPTi93X_PIN_CTRL, OPTi93X_IRQ_ENABLE, | ||
925 | ~OPTi93X_IRQ_ENABLE); | ||
926 | |||
927 | snd_opti93x_mce_up(chip); | ||
928 | snd_opti93x_out_image(chip, OPTi93X_IFACE_CONF, 0x00); | ||
929 | snd_opti93x_mce_down(chip); | ||
930 | chip->mode = 0; | ||
931 | |||
932 | snd_opti93x_mute(chip, 0); | ||
933 | spin_unlock_irqrestore(&chip->lock, flags); | ||
934 | } | ||
935 | |||
936 | static int snd_opti93x_trigger(struct snd_pcm_substream *substream, | ||
937 | unsigned char what, int cmd) | ||
938 | { | ||
939 | struct snd_opti93x *chip = snd_pcm_substream_chip(substream); | ||
940 | |||
941 | switch (cmd) { | ||
942 | case SNDRV_PCM_TRIGGER_START: | ||
943 | case SNDRV_PCM_TRIGGER_STOP: | ||
944 | { | ||
945 | unsigned int what = 0; | ||
946 | struct snd_pcm_substream *s; | ||
947 | snd_pcm_group_for_each_entry(s, substream) { | ||
948 | if (s == chip->playback_substream) { | ||
949 | what |= OPTi93X_PLAYBACK_ENABLE; | ||
950 | snd_pcm_trigger_done(s, substream); | ||
951 | } else if (s == chip->capture_substream) { | ||
952 | what |= OPTi93X_CAPTURE_ENABLE; | ||
953 | snd_pcm_trigger_done(s, substream); | ||
954 | } | ||
955 | } | ||
956 | spin_lock(&chip->lock); | ||
957 | if (cmd == SNDRV_PCM_TRIGGER_START) { | ||
958 | snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, what, what); | ||
959 | if (what & OPTi93X_CAPTURE_ENABLE) | ||
960 | udelay(50); | ||
961 | } else | ||
962 | snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, what, 0x00); | ||
963 | spin_unlock(&chip->lock); | ||
964 | break; | ||
965 | } | ||
966 | default: | ||
967 | return -EINVAL; | ||
968 | } | ||
969 | return 0; | ||
970 | } | ||
971 | |||
972 | static int snd_opti93x_playback_trigger(struct snd_pcm_substream *substream, int cmd) | ||
973 | { | ||
974 | return snd_opti93x_trigger(substream, | ||
975 | OPTi93X_PLAYBACK_ENABLE, cmd); | ||
976 | } | ||
977 | |||
978 | static int snd_opti93x_capture_trigger(struct snd_pcm_substream *substream, int cmd) | ||
979 | { | ||
980 | return snd_opti93x_trigger(substream, | ||
981 | OPTi93X_CAPTURE_ENABLE, cmd); | ||
982 | } | ||
983 | |||
984 | static int snd_opti93x_hw_params(struct snd_pcm_substream *substream, | ||
985 | struct snd_pcm_hw_params *hw_params) | ||
986 | { | ||
987 | return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); | ||
988 | } | ||
989 | |||
990 | |||
991 | static int snd_opti93x_hw_free(struct snd_pcm_substream *substream) | ||
992 | { | ||
993 | snd_pcm_lib_free_pages(substream); | ||
994 | return 0; | ||
995 | } | ||
996 | |||
997 | |||
998 | static int snd_opti93x_playback_prepare(struct snd_pcm_substream *substream) | ||
999 | { | ||
1000 | struct snd_opti93x *chip = snd_pcm_substream_chip(substream); | ||
1001 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
1002 | unsigned long flags; | ||
1003 | unsigned char format; | ||
1004 | unsigned int count = snd_pcm_lib_period_bytes(substream); | ||
1005 | unsigned int size = snd_pcm_lib_buffer_bytes(substream); | ||
1006 | |||
1007 | spin_lock_irqsave(&chip->lock, flags); | ||
1008 | |||
1009 | chip->p_dma_size = size; | ||
1010 | snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, | ||
1011 | OPTi93X_PLAYBACK_ENABLE | OPTi93X_PLAYBACK_PIO, | ||
1012 | ~(OPTi93X_PLAYBACK_ENABLE | OPTi93X_PLAYBACK_PIO)); | ||
1013 | |||
1014 | snd_dma_program(chip->dma1, runtime->dma_addr, size, | ||
1015 | DMA_MODE_WRITE | DMA_AUTOINIT); | ||
1016 | |||
1017 | format = snd_opti93x_get_freq(runtime->rate); | ||
1018 | format |= snd_opti93x_get_format(chip, runtime->format, | ||
1019 | runtime->channels); | ||
1020 | snd_opti93x_playback_format(chip, format); | ||
1021 | format = chip->image[OPTi93X_PLAY_FORMAT]; | ||
1022 | |||
1023 | count = snd_opti93x_get_count(format, count) - 1; | ||
1024 | snd_opti93x_out_image(chip, OPTi93X_PLAY_LWR_CNT, count); | ||
1025 | snd_opti93x_out_image(chip, OPTi93X_PLAY_UPR_CNT, count >> 8); | ||
1026 | |||
1027 | spin_unlock_irqrestore(&chip->lock, flags); | ||
1028 | return 0; | ||
1029 | } | ||
1030 | |||
1031 | static int snd_opti93x_capture_prepare(struct snd_pcm_substream *substream) | ||
1032 | { | ||
1033 | struct snd_opti93x *chip = snd_pcm_substream_chip(substream); | ||
1034 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
1035 | unsigned long flags; | ||
1036 | unsigned char format; | ||
1037 | unsigned int count = snd_pcm_lib_period_bytes(substream); | ||
1038 | unsigned int size = snd_pcm_lib_buffer_bytes(substream); | ||
1039 | |||
1040 | spin_lock_irqsave(&chip->lock, flags); | ||
1041 | |||
1042 | chip->c_dma_size = size; | ||
1043 | snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, | ||
1044 | OPTi93X_CAPTURE_ENABLE | OPTi93X_CAPTURE_PIO, 0); | ||
1045 | |||
1046 | snd_dma_program(chip->dma2, runtime->dma_addr, size, | ||
1047 | DMA_MODE_READ | DMA_AUTOINIT); | ||
1048 | |||
1049 | format = snd_opti93x_get_freq(runtime->rate); | ||
1050 | format |= snd_opti93x_get_format(chip, runtime->format, | ||
1051 | runtime->channels); | ||
1052 | snd_opti93x_capture_format(chip, format); | ||
1053 | format = chip->image[OPTi93X_CAPT_FORMAT]; | ||
1054 | |||
1055 | count = snd_opti93x_get_count(format, count) - 1; | ||
1056 | snd_opti93x_out_image(chip, OPTi93X_CAPT_LWR_CNT, count); | ||
1057 | snd_opti93x_out_image(chip, OPTi93X_CAPT_UPR_CNT, count >> 8); | ||
1058 | |||
1059 | spin_unlock_irqrestore(&chip->lock, flags); | ||
1060 | return 0; | ||
1061 | } | ||
1062 | |||
1063 | static snd_pcm_uframes_t snd_opti93x_playback_pointer(struct snd_pcm_substream *substream) | ||
1064 | { | ||
1065 | struct snd_opti93x *chip = snd_pcm_substream_chip(substream); | ||
1066 | size_t ptr; | ||
1067 | |||
1068 | if (!(chip->image[OPTi93X_IFACE_CONF] & OPTi93X_PLAYBACK_ENABLE)) | ||
1069 | return 0; | ||
1070 | |||
1071 | ptr = snd_dma_pointer(chip->dma1, chip->p_dma_size); | ||
1072 | return bytes_to_frames(substream->runtime, ptr); | ||
1073 | } | ||
1074 | |||
1075 | static snd_pcm_uframes_t snd_opti93x_capture_pointer(struct snd_pcm_substream *substream) | ||
1076 | { | ||
1077 | struct snd_opti93x *chip = snd_pcm_substream_chip(substream); | ||
1078 | size_t ptr; | ||
1079 | |||
1080 | if (!(chip->image[OPTi93X_IFACE_CONF] & OPTi93X_CAPTURE_ENABLE)) | ||
1081 | return 0; | ||
1082 | |||
1083 | ptr = snd_dma_pointer(chip->dma2, chip->c_dma_size); | ||
1084 | return bytes_to_frames(substream->runtime, ptr); | ||
1085 | } | ||
1086 | |||
1087 | |||
1088 | static void snd_opti93x_overrange(struct snd_opti93x *chip) | ||
1089 | { | ||
1090 | unsigned long flags; | ||
1091 | |||
1092 | spin_lock_irqsave(&chip->lock, flags); | ||
1093 | |||
1094 | if (snd_opti93x_in(chip, OPTi93X_ERR_INIT) & (0x08 | 0x02)) | ||
1095 | chip->capture_substream->runtime->overrange++; | ||
1096 | |||
1097 | spin_unlock_irqrestore(&chip->lock, flags); | ||
1098 | } | ||
1099 | |||
1100 | static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id) | 559 | static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id) |
1101 | { | 560 | { |
1102 | struct snd_opti93x *codec = dev_id; | 561 | struct snd_cs4231 *codec = dev_id; |
562 | struct snd_opti9xx *chip = codec->card->private_data; | ||
1103 | unsigned char status; | 563 | unsigned char status; |
1104 | 564 | ||
1105 | status = snd_opti9xx_read(codec->chip, OPTi9XX_MC_REG(11)); | 565 | status = snd_opti9xx_read(chip, OPTi9XX_MC_REG(11)); |
1106 | if ((status & OPTi93X_IRQ_PLAYBACK) && codec->playback_substream) | 566 | if ((status & OPTi93X_IRQ_PLAYBACK) && codec->playback_substream) |
1107 | snd_pcm_period_elapsed(codec->playback_substream); | 567 | snd_pcm_period_elapsed(codec->playback_substream); |
1108 | if ((status & OPTi93X_IRQ_CAPTURE) && codec->capture_substream) { | 568 | if ((status & OPTi93X_IRQ_CAPTURE) && codec->capture_substream) { |
1109 | snd_opti93x_overrange(codec); | 569 | snd_cs4231_overrange(codec); |
1110 | snd_pcm_period_elapsed(codec->capture_substream); | 570 | snd_pcm_period_elapsed(codec->capture_substream); |
1111 | } | 571 | } |
1112 | outb(0x00, OPTi93X_PORT(codec, STATUS)); | 572 | outb(0x00, OPTi93X_PORT(codec, STATUS)); |
1113 | return IRQ_HANDLED; | 573 | return IRQ_HANDLED; |
1114 | } | 574 | } |
1115 | 575 | ||
1116 | |||
1117 | static struct snd_pcm_hardware snd_opti93x_playback = { | ||
1118 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | ||
1119 | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START), | ||
1120 | .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM | | ||
1121 | SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE), | ||
1122 | .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000, | ||
1123 | .rate_min = 5512, | ||
1124 | .rate_max = 48000, | ||
1125 | .channels_min = 1, | ||
1126 | .channels_max = 2, | ||
1127 | .buffer_bytes_max = (128*1024), | ||
1128 | .period_bytes_min = 64, | ||
1129 | .period_bytes_max = (128*1024), | ||
1130 | .periods_min = 1, | ||
1131 | .periods_max = 1024, | ||
1132 | .fifo_size = 0, | ||
1133 | }; | ||
1134 | |||
1135 | static struct snd_pcm_hardware snd_opti93x_capture = { | ||
1136 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | ||
1137 | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START), | ||
1138 | .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM | | ||
1139 | SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE), | ||
1140 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
1141 | .rate_min = 5512, | ||
1142 | .rate_max = 48000, | ||
1143 | .channels_min = 1, | ||
1144 | .channels_max = 2, | ||
1145 | .buffer_bytes_max = (128*1024), | ||
1146 | .period_bytes_min = 64, | ||
1147 | .period_bytes_max = (128*1024), | ||
1148 | .periods_min = 1, | ||
1149 | .periods_max = 1024, | ||
1150 | .fifo_size = 0, | ||
1151 | }; | ||
1152 | |||
1153 | static int snd_opti93x_playback_open(struct snd_pcm_substream *substream) | ||
1154 | { | ||
1155 | int error; | ||
1156 | struct snd_opti93x *chip = snd_pcm_substream_chip(substream); | ||
1157 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
1158 | |||
1159 | if ((error = snd_opti93x_open(chip, OPTi93X_MODE_PLAY)) < 0) | ||
1160 | return error; | ||
1161 | snd_pcm_set_sync(substream); | ||
1162 | chip->playback_substream = substream; | ||
1163 | runtime->hw = snd_opti93x_playback; | ||
1164 | snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.buffer_bytes_max); | ||
1165 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); | ||
1166 | return error; | ||
1167 | } | ||
1168 | |||
1169 | static int snd_opti93x_capture_open(struct snd_pcm_substream *substream) | ||
1170 | { | ||
1171 | int error; | ||
1172 | struct snd_opti93x *chip = snd_pcm_substream_chip(substream); | ||
1173 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
1174 | |||
1175 | if ((error = snd_opti93x_open(chip, OPTi93X_MODE_CAPTURE)) < 0) | ||
1176 | return error; | ||
1177 | runtime->hw = snd_opti93x_capture; | ||
1178 | snd_pcm_set_sync(substream); | ||
1179 | chip->capture_substream = substream; | ||
1180 | snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.buffer_bytes_max); | ||
1181 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); | ||
1182 | return error; | ||
1183 | } | ||
1184 | |||
1185 | static int snd_opti93x_playback_close(struct snd_pcm_substream *substream) | ||
1186 | { | ||
1187 | struct snd_opti93x *chip = snd_pcm_substream_chip(substream); | ||
1188 | |||
1189 | chip->playback_substream = NULL; | ||
1190 | snd_opti93x_close(chip, OPTi93X_MODE_PLAY); | ||
1191 | return 0; | ||
1192 | } | ||
1193 | |||
1194 | static int snd_opti93x_capture_close(struct snd_pcm_substream *substream) | ||
1195 | { | ||
1196 | struct snd_opti93x *chip = snd_pcm_substream_chip(substream); | ||
1197 | |||
1198 | chip->capture_substream = NULL; | ||
1199 | snd_opti93x_close(chip, OPTi93X_MODE_CAPTURE); | ||
1200 | return 0; | ||
1201 | } | ||
1202 | |||
1203 | |||
1204 | static void snd_opti93x_init(struct snd_opti93x *chip) | ||
1205 | { | ||
1206 | unsigned long flags; | ||
1207 | int i; | ||
1208 | |||
1209 | spin_lock_irqsave(&chip->lock, flags); | ||
1210 | snd_opti93x_mce_up(chip); | ||
1211 | |||
1212 | for (i = 0; i < 32; i++) | ||
1213 | snd_opti93x_out_image(chip, i, snd_opti93x_default_image[i]); | ||
1214 | |||
1215 | snd_opti93x_mce_down(chip); | ||
1216 | spin_unlock_irqrestore(&chip->lock, flags); | ||
1217 | } | ||
1218 | |||
1219 | static int snd_opti93x_probe(struct snd_opti93x *chip) | ||
1220 | { | ||
1221 | unsigned long flags; | ||
1222 | unsigned char val; | ||
1223 | |||
1224 | spin_lock_irqsave(&chip->lock, flags); | ||
1225 | val = snd_opti93x_in(chip, OPTi93X_ID) & 0x0f; | ||
1226 | spin_unlock_irqrestore(&chip->lock, flags); | ||
1227 | |||
1228 | return (val == 0x0a) ? 0 : -ENODEV; | ||
1229 | } | ||
1230 | |||
1231 | static int snd_opti93x_free(struct snd_opti93x *chip) | ||
1232 | { | ||
1233 | release_and_free_resource(chip->res_port); | ||
1234 | if (chip->dma1 >= 0) { | ||
1235 | disable_dma(chip->dma1); | ||
1236 | free_dma(chip->dma1); | ||
1237 | } | ||
1238 | if (chip->dma2 >= 0) { | ||
1239 | disable_dma(chip->dma2); | ||
1240 | free_dma(chip->dma2); | ||
1241 | } | ||
1242 | if (chip->irq >= 0) { | ||
1243 | free_irq(chip->irq, chip); | ||
1244 | } | ||
1245 | kfree(chip); | ||
1246 | return 0; | ||
1247 | } | ||
1248 | |||
1249 | static int snd_opti93x_dev_free(struct snd_device *device) | ||
1250 | { | ||
1251 | struct snd_opti93x *chip = device->device_data; | ||
1252 | return snd_opti93x_free(chip); | ||
1253 | } | ||
1254 | |||
1255 | static const char *snd_opti93x_chip_id(struct snd_opti93x *codec) | ||
1256 | { | ||
1257 | switch (codec->hardware) { | ||
1258 | case OPTi9XX_HW_82C930: return "82C930"; | ||
1259 | case OPTi9XX_HW_82C931: return "82C931"; | ||
1260 | case OPTi9XX_HW_82C933: return "82C933"; | ||
1261 | default: return "???"; | ||
1262 | } | ||
1263 | } | ||
1264 | |||
1265 | static int snd_opti93x_create(struct snd_card *card, struct snd_opti9xx *chip, | ||
1266 | int dma1, int dma2, | ||
1267 | struct snd_opti93x **rcodec) | ||
1268 | { | ||
1269 | static struct snd_device_ops ops = { | ||
1270 | .dev_free = snd_opti93x_dev_free, | ||
1271 | }; | ||
1272 | int error; | ||
1273 | struct snd_opti93x *codec; | ||
1274 | |||
1275 | *rcodec = NULL; | ||
1276 | codec = kzalloc(sizeof(*codec), GFP_KERNEL); | ||
1277 | if (codec == NULL) | ||
1278 | return -ENOMEM; | ||
1279 | codec->irq = -1; | ||
1280 | codec->dma1 = -1; | ||
1281 | codec->dma2 = -1; | ||
1282 | |||
1283 | if ((codec->res_port = request_region(chip->wss_base + 4, 4, "OPTI93x CODEC")) == NULL) { | ||
1284 | snd_printk(KERN_ERR "opti9xx: can't grab port 0x%lx\n", chip->wss_base + 4); | ||
1285 | snd_opti93x_free(codec); | ||
1286 | return -EBUSY; | ||
1287 | } | ||
1288 | if (request_dma(dma1, "OPTI93x - 1")) { | ||
1289 | snd_printk(KERN_ERR "opti9xx: can't grab DMA1 %d\n", dma1); | ||
1290 | snd_opti93x_free(codec); | ||
1291 | return -EBUSY; | ||
1292 | } | ||
1293 | codec->dma1 = chip->dma1; | ||
1294 | if (request_dma(dma2, "OPTI93x - 2")) { | ||
1295 | snd_printk(KERN_ERR "opti9xx: can't grab DMA2 %d\n", dma2); | ||
1296 | snd_opti93x_free(codec); | ||
1297 | return -EBUSY; | ||
1298 | } | ||
1299 | codec->dma2 = chip->dma2; | ||
1300 | |||
1301 | if (request_irq(chip->irq, snd_opti93x_interrupt, IRQF_DISABLED, DEV_NAME" - WSS", codec)) { | ||
1302 | snd_printk(KERN_ERR "opti9xx: can't grab IRQ %d\n", chip->irq); | ||
1303 | snd_opti93x_free(codec); | ||
1304 | return -EBUSY; | ||
1305 | } | ||
1306 | |||
1307 | codec->card = card; | ||
1308 | codec->port = chip->wss_base + 4; | ||
1309 | codec->irq = chip->irq; | ||
1310 | |||
1311 | spin_lock_init(&codec->lock); | ||
1312 | codec->hardware = chip->hardware; | ||
1313 | codec->chip = chip; | ||
1314 | |||
1315 | if ((error = snd_opti93x_probe(codec))) { | ||
1316 | snd_opti93x_free(codec); | ||
1317 | return error; | ||
1318 | } | ||
1319 | |||
1320 | snd_opti93x_init(codec); | ||
1321 | |||
1322 | /* Register device */ | ||
1323 | if ((error = snd_device_new(card, SNDRV_DEV_LOWLEVEL, codec, &ops)) < 0) { | ||
1324 | snd_opti93x_free(codec); | ||
1325 | return error; | ||
1326 | } | ||
1327 | |||
1328 | *rcodec = codec; | ||
1329 | return 0; | ||
1330 | } | ||
1331 | |||
1332 | static struct snd_pcm_ops snd_opti93x_playback_ops = { | ||
1333 | .open = snd_opti93x_playback_open, | ||
1334 | .close = snd_opti93x_playback_close, | ||
1335 | .ioctl = snd_pcm_lib_ioctl, | ||
1336 | .hw_params = snd_opti93x_hw_params, | ||
1337 | .hw_free = snd_opti93x_hw_free, | ||
1338 | .prepare = snd_opti93x_playback_prepare, | ||
1339 | .trigger = snd_opti93x_playback_trigger, | ||
1340 | .pointer = snd_opti93x_playback_pointer, | ||
1341 | }; | ||
1342 | |||
1343 | static struct snd_pcm_ops snd_opti93x_capture_ops = { | ||
1344 | .open = snd_opti93x_capture_open, | ||
1345 | .close = snd_opti93x_capture_close, | ||
1346 | .ioctl = snd_pcm_lib_ioctl, | ||
1347 | .hw_params = snd_opti93x_hw_params, | ||
1348 | .hw_free = snd_opti93x_hw_free, | ||
1349 | .prepare = snd_opti93x_capture_prepare, | ||
1350 | .trigger = snd_opti93x_capture_trigger, | ||
1351 | .pointer = snd_opti93x_capture_pointer, | ||
1352 | }; | ||
1353 | |||
1354 | static int snd_opti93x_pcm(struct snd_opti93x *codec, int device, struct snd_pcm **rpcm) | ||
1355 | { | ||
1356 | int error; | ||
1357 | struct snd_pcm *pcm; | ||
1358 | |||
1359 | if ((error = snd_pcm_new(codec->card, "OPTi 82C93X", device, 1, 1, &pcm)) < 0) | ||
1360 | return error; | ||
1361 | |||
1362 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_opti93x_playback_ops); | ||
1363 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_opti93x_capture_ops); | ||
1364 | |||
1365 | pcm->private_data = codec; | ||
1366 | pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; | ||
1367 | |||
1368 | strcpy(pcm->name, snd_opti93x_chip_id(codec)); | ||
1369 | |||
1370 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | ||
1371 | snd_dma_isa_data(), | ||
1372 | 64*1024, codec->dma1 > 3 || codec->dma2 > 3 ? 128*1024 : 64*1024); | ||
1373 | |||
1374 | codec->pcm = pcm; | ||
1375 | if (rpcm) | ||
1376 | *rpcm = pcm; | ||
1377 | return 0; | ||
1378 | } | ||
1379 | |||
1380 | /* | ||
1381 | * MIXER part | ||
1382 | */ | ||
1383 | |||
1384 | static int snd_opti93x_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | ||
1385 | { | ||
1386 | static char *texts[4] = { | ||
1387 | "Line1", "Aux", "Mic", "Mix" | ||
1388 | }; | ||
1389 | |||
1390 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
1391 | uinfo->count = 2; | ||
1392 | uinfo->value.enumerated.items = 4; | ||
1393 | if (uinfo->value.enumerated.item > 3) | ||
1394 | uinfo->value.enumerated.item = 3; | ||
1395 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
1396 | return 0; | ||
1397 | } | ||
1398 | |||
1399 | static int snd_opti93x_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
1400 | { | ||
1401 | struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol); | ||
1402 | unsigned long flags; | ||
1403 | |||
1404 | spin_lock_irqsave(&chip->lock, flags); | ||
1405 | ucontrol->value.enumerated.item[0] = (chip->image[OPTi93X_MIXOUT_LEFT] & OPTi93X_MIXOUT_MIXER) >> 6; | ||
1406 | ucontrol->value.enumerated.item[1] = (chip->image[OPTi93X_MIXOUT_RIGHT] & OPTi93X_MIXOUT_MIXER) >> 6; | ||
1407 | spin_unlock_irqrestore(&chip->lock, flags); | ||
1408 | return 0; | ||
1409 | } | ||
1410 | |||
1411 | static int snd_opti93x_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
1412 | { | ||
1413 | struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol); | ||
1414 | unsigned long flags; | ||
1415 | unsigned short left, right; | ||
1416 | int change; | ||
1417 | |||
1418 | if (ucontrol->value.enumerated.item[0] > 3 || | ||
1419 | ucontrol->value.enumerated.item[1] > 3) | ||
1420 | return -EINVAL; | ||
1421 | left = ucontrol->value.enumerated.item[0] << 6; | ||
1422 | right = ucontrol->value.enumerated.item[1] << 6; | ||
1423 | spin_lock_irqsave(&chip->lock, flags); | ||
1424 | left = (chip->image[OPTi93X_MIXOUT_LEFT] & ~OPTi93X_MIXOUT_MIXER) | left; | ||
1425 | right = (chip->image[OPTi93X_MIXOUT_RIGHT] & ~OPTi93X_MIXOUT_MIXER) | right; | ||
1426 | change = left != chip->image[OPTi93X_MIXOUT_LEFT] || | ||
1427 | right != chip->image[OPTi93X_MIXOUT_RIGHT]; | ||
1428 | snd_opti93x_out_image(chip, OPTi93X_MIXOUT_LEFT, left); | ||
1429 | snd_opti93x_out_image(chip, OPTi93X_MIXOUT_RIGHT, right); | ||
1430 | spin_unlock_irqrestore(&chip->lock, flags); | ||
1431 | return change; | ||
1432 | } | ||
1433 | |||
1434 | #if 0 | ||
1435 | |||
1436 | #define OPTi93X_SINGLE(xname, xindex, reg, shift, mask, invert) \ | ||
1437 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ | ||
1438 | .info = snd_opti93x_info_single, \ | ||
1439 | .get = snd_opti93x_get_single, .put = snd_opti93x_put_single, \ | ||
1440 | .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) } | ||
1441 | |||
1442 | static int snd_opti93x_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | ||
1443 | { | ||
1444 | int mask = (kcontrol->private_value >> 16) & 0xff; | ||
1445 | |||
1446 | uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1447 | uinfo->count = 1; | ||
1448 | uinfo->value.integer.min = 0; | ||
1449 | uinfo->value.integer.max = mask; | ||
1450 | return 0; | ||
1451 | } | ||
1452 | |||
1453 | static int snd_opti93x_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
1454 | { | ||
1455 | struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol); | ||
1456 | unsigned long flags; | ||
1457 | int reg = kcontrol->private_value & 0xff; | ||
1458 | int shift = (kcontrol->private_value >> 8) & 0xff; | ||
1459 | int mask = (kcontrol->private_value >> 16) & 0xff; | ||
1460 | int invert = (kcontrol->private_value >> 24) & 0xff; | ||
1461 | |||
1462 | spin_lock_irqsave(&chip->lock, flags); | ||
1463 | ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask; | ||
1464 | spin_unlock_irqrestore(&chip->lock, flags); | ||
1465 | if (invert) | ||
1466 | ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; | ||
1467 | return 0; | ||
1468 | } | ||
1469 | |||
1470 | static int snd_opti93x_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
1471 | { | ||
1472 | struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol); | ||
1473 | unsigned long flags; | ||
1474 | int reg = kcontrol->private_value & 0xff; | ||
1475 | int shift = (kcontrol->private_value >> 8) & 0xff; | ||
1476 | int mask = (kcontrol->private_value >> 16) & 0xff; | ||
1477 | int invert = (kcontrol->private_value >> 24) & 0xff; | ||
1478 | int change; | ||
1479 | unsigned short val; | ||
1480 | |||
1481 | val = (ucontrol->value.integer.value[0] & mask); | ||
1482 | if (invert) | ||
1483 | val = mask - val; | ||
1484 | val <<= shift; | ||
1485 | spin_lock_irqsave(&chip->lock, flags); | ||
1486 | val = (chip->image[reg] & ~(mask << shift)) | val; | ||
1487 | change = val != chip->image[reg]; | ||
1488 | snd_opti93x_out(chip, reg, val); | ||
1489 | spin_unlock_irqrestore(&chip->lock, flags); | ||
1490 | return change; | ||
1491 | } | ||
1492 | |||
1493 | #endif /* single */ | ||
1494 | |||
1495 | #define OPTi93X_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \ | ||
1496 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ | ||
1497 | .info = snd_opti93x_info_double, \ | ||
1498 | .get = snd_opti93x_get_double, .put = snd_opti93x_put_double, \ | ||
1499 | .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) } | ||
1500 | |||
1501 | #define OPTi93X_DOUBLE_INVERT_INVERT(xctl) \ | ||
1502 | do { xctl.private_value ^= 22; } while (0) | ||
1503 | #define OPTi93X_DOUBLE_CHANGE_REGS(xctl, left_reg, right_reg) \ | ||
1504 | do { xctl.private_value &= ~0x0000ffff; \ | ||
1505 | xctl.private_value |= left_reg | (right_reg << 8); } while (0) | ||
1506 | |||
1507 | static int snd_opti93x_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | ||
1508 | { | ||
1509 | int mask = (kcontrol->private_value >> 24) & 0xff; | ||
1510 | |||
1511 | uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1512 | uinfo->count = 2; | ||
1513 | uinfo->value.integer.min = 0; | ||
1514 | uinfo->value.integer.max = mask; | ||
1515 | return 0; | ||
1516 | } | ||
1517 | |||
1518 | static int snd_opti93x_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
1519 | { | ||
1520 | struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol); | ||
1521 | unsigned long flags; | ||
1522 | int left_reg = kcontrol->private_value & 0xff; | ||
1523 | int right_reg = (kcontrol->private_value >> 8) & 0xff; | ||
1524 | int shift_left = (kcontrol->private_value >> 16) & 0x07; | ||
1525 | int shift_right = (kcontrol->private_value >> 19) & 0x07; | ||
1526 | int mask = (kcontrol->private_value >> 24) & 0xff; | ||
1527 | int invert = (kcontrol->private_value >> 22) & 1; | ||
1528 | |||
1529 | spin_lock_irqsave(&chip->lock, flags); | ||
1530 | ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask; | ||
1531 | ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask; | ||
1532 | spin_unlock_irqrestore(&chip->lock, flags); | ||
1533 | if (invert) { | ||
1534 | ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; | ||
1535 | ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1]; | ||
1536 | } | ||
1537 | return 0; | ||
1538 | } | ||
1539 | |||
1540 | static int snd_opti93x_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
1541 | { | ||
1542 | struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol); | ||
1543 | unsigned long flags; | ||
1544 | int left_reg = kcontrol->private_value & 0xff; | ||
1545 | int right_reg = (kcontrol->private_value >> 8) & 0xff; | ||
1546 | int shift_left = (kcontrol->private_value >> 16) & 0x07; | ||
1547 | int shift_right = (kcontrol->private_value >> 19) & 0x07; | ||
1548 | int mask = (kcontrol->private_value >> 24) & 0xff; | ||
1549 | int invert = (kcontrol->private_value >> 22) & 1; | ||
1550 | int change; | ||
1551 | unsigned short val1, val2; | ||
1552 | |||
1553 | val1 = ucontrol->value.integer.value[0] & mask; | ||
1554 | val2 = ucontrol->value.integer.value[1] & mask; | ||
1555 | if (invert) { | ||
1556 | val1 = mask - val1; | ||
1557 | val2 = mask - val2; | ||
1558 | } | ||
1559 | val1 <<= shift_left; | ||
1560 | val2 <<= shift_right; | ||
1561 | spin_lock_irqsave(&chip->lock, flags); | ||
1562 | val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1; | ||
1563 | val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2; | ||
1564 | change = val1 != chip->image[left_reg] || val2 != chip->image[right_reg]; | ||
1565 | snd_opti93x_out_image(chip, left_reg, val1); | ||
1566 | snd_opti93x_out_image(chip, right_reg, val2); | ||
1567 | spin_unlock_irqrestore(&chip->lock, flags); | ||
1568 | return change; | ||
1569 | } | ||
1570 | |||
1571 | static struct snd_kcontrol_new snd_opti93x_controls[] __devinitdata = { | ||
1572 | OPTi93X_DOUBLE("Master Playback Switch", 0, OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1), | ||
1573 | OPTi93X_DOUBLE("Master Playback Volume", 0, OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1), | ||
1574 | OPTi93X_DOUBLE("PCM Playback Switch", 0, OPTi93X_DAC_LEFT, OPTi93X_DAC_RIGHT, 7, 7, 1, 1), | ||
1575 | OPTi93X_DOUBLE("PCM Playback Volume", 0, OPTi93X_DAC_LEFT, OPTi93X_DAC_RIGHT, 0, 0, 31, 1), | ||
1576 | OPTi93X_DOUBLE("FM Playback Switch", 0, OPTi931_FM_LEFT_INPUT, OPTi931_FM_RIGHT_INPUT, 7, 7, 1, 1), | ||
1577 | OPTi93X_DOUBLE("FM Playback Volume", 0, OPTi931_FM_LEFT_INPUT, OPTi931_FM_RIGHT_INPUT, 1, 1, 15, 1), | ||
1578 | OPTi93X_DOUBLE("Line Playback Switch", 0, OPTi93X_LINE_LEFT_INPUT, OPTi93X_LINE_RIGHT_INPUT, 7, 7, 1, 1), | ||
1579 | OPTi93X_DOUBLE("Line Playback Volume", 0, OPTi93X_LINE_LEFT_INPUT, OPTi93X_LINE_RIGHT_INPUT, 1, 1, 15, 1), | ||
1580 | OPTi93X_DOUBLE("Mic Playback Switch", 0, OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1), | ||
1581 | OPTi93X_DOUBLE("Mic Playback Volume", 0, OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1), | ||
1582 | OPTi93X_DOUBLE("Mic Boost", 0, OPTi93X_MIXOUT_LEFT, OPTi93X_MIXOUT_RIGHT, 5, 5, 1, 1), | ||
1583 | OPTi93X_DOUBLE("CD Playback Switch", 0, OPTi93X_CD_LEFT_INPUT, OPTi93X_CD_RIGHT_INPUT, 7, 7, 1, 1), | ||
1584 | OPTi93X_DOUBLE("CD Playback Volume", 0, OPTi93X_CD_LEFT_INPUT, OPTi93X_CD_RIGHT_INPUT, 1, 1, 15, 1), | ||
1585 | OPTi93X_DOUBLE("Aux Playback Switch", 0, OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1), | ||
1586 | OPTi93X_DOUBLE("Aux Playback Volume", 0, OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1), | ||
1587 | OPTi93X_DOUBLE("Capture Volume", 0, OPTi93X_MIXOUT_LEFT, OPTi93X_MIXOUT_RIGHT, 0, 0, 15, 0), | ||
1588 | { | ||
1589 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1590 | .name = "Capture Source", | ||
1591 | .info = snd_opti93x_info_mux, | ||
1592 | .get = snd_opti93x_get_mux, | ||
1593 | .put = snd_opti93x_put_mux, | ||
1594 | } | ||
1595 | }; | ||
1596 | |||
1597 | static int __devinit snd_opti93x_mixer(struct snd_opti93x *chip) | ||
1598 | { | ||
1599 | struct snd_card *card; | ||
1600 | struct snd_kcontrol_new knew; | ||
1601 | int err; | ||
1602 | unsigned int idx; | ||
1603 | |||
1604 | snd_assert(chip != NULL && chip->card != NULL, return -EINVAL); | ||
1605 | |||
1606 | card = chip->card; | ||
1607 | |||
1608 | strcpy(card->mixername, snd_opti93x_chip_id(chip)); | ||
1609 | |||
1610 | for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) { | ||
1611 | knew = snd_opti93x_controls[idx]; | ||
1612 | if (chip->hardware == OPTi9XX_HW_82C930) { | ||
1613 | if (strstr(knew.name, "FM")) /* skip FM controls */ | ||
1614 | continue; | ||
1615 | else if (strcmp(knew.name, "Mic Playback Volume")) | ||
1616 | OPTi93X_DOUBLE_INVERT_INVERT(knew); | ||
1617 | else if (strstr(knew.name, "Aux")) | ||
1618 | OPTi93X_DOUBLE_CHANGE_REGS(knew, OPTi930_AUX_LEFT_INPUT, OPTi930_AUX_RIGHT_INPUT); | ||
1619 | else if (strcmp(knew.name, "PCM Playback Volume")) | ||
1620 | OPTi93X_DOUBLE_INVERT_INVERT(knew); | ||
1621 | else if (strcmp(knew.name, "Master Playback Volume")) | ||
1622 | OPTi93X_DOUBLE_INVERT_INVERT(knew); | ||
1623 | } | ||
1624 | if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_opti93x_controls[idx], chip))) < 0) | ||
1625 | return err; | ||
1626 | } | ||
1627 | return 0; | ||
1628 | } | ||
1629 | |||
1630 | #endif /* OPTi93X */ | 576 | #endif /* OPTi93X */ |
1631 | 577 | ||
1632 | static int __devinit snd_card_opti9xx_detect(struct snd_card *card, | 578 | static int __devinit snd_card_opti9xx_detect(struct snd_card *card, |
@@ -1739,8 +685,16 @@ static void snd_card_opti9xx_free(struct snd_card *card) | |||
1739 | { | 685 | { |
1740 | struct snd_opti9xx *chip = card->private_data; | 686 | struct snd_opti9xx *chip = card->private_data; |
1741 | 687 | ||
1742 | if (chip) | 688 | if (chip) { |
689 | #ifdef OPTi93X | ||
690 | struct snd_cs4231 *codec = chip->codec; | ||
691 | if (codec->irq > 0) { | ||
692 | disable_irq(codec->irq); | ||
693 | free_irq(codec->irq, codec); | ||
694 | } | ||
695 | #endif | ||
1743 | release_and_free_resource(chip->res_mc_base); | 696 | release_and_free_resource(chip->res_mc_base); |
697 | } | ||
1744 | } | 698 | } |
1745 | 699 | ||
1746 | static int __devinit snd_opti9xx_probe(struct snd_card *card) | 700 | static int __devinit snd_opti9xx_probe(struct snd_card *card) |
@@ -1748,11 +702,11 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) | |||
1748 | static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1}; | 702 | static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1}; |
1749 | int error; | 703 | int error; |
1750 | struct snd_opti9xx *chip = card->private_data; | 704 | struct snd_opti9xx *chip = card->private_data; |
1751 | #if defined(OPTi93X) | 705 | #if defined(CS4231) || defined(OPTi93X) |
1752 | struct snd_opti93x *codec; | ||
1753 | #elif defined(CS4231) | ||
1754 | struct snd_cs4231 *codec; | 706 | struct snd_cs4231 *codec; |
707 | #ifdef CS4231 | ||
1755 | struct snd_timer *timer; | 708 | struct snd_timer *timer; |
709 | #endif | ||
1756 | #else | 710 | #else |
1757 | struct snd_ad1848 *codec; | 711 | struct snd_ad1848 *codec; |
1758 | #endif | 712 | #endif |
@@ -1784,26 +738,34 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) | |||
1784 | if ((error = snd_opti9xx_configure(chip))) | 738 | if ((error = snd_opti9xx_configure(chip))) |
1785 | return error; | 739 | return error; |
1786 | 740 | ||
1787 | #if defined(OPTi93X) | 741 | #if defined(CS4231) || defined(OPTi93X) |
1788 | if ((error = snd_opti93x_create(card, chip, chip->dma1, chip->dma2, &codec))) | ||
1789 | return error; | ||
1790 | if ((error = snd_opti93x_pcm(codec, 0, &pcm)) < 0) | ||
1791 | return error; | ||
1792 | if ((error = snd_opti93x_mixer(codec)) < 0) | ||
1793 | return error; | ||
1794 | #elif defined(CS4231) | ||
1795 | if ((error = snd_cs4231_create(card, chip->wss_base + 4, -1, | 742 | if ((error = snd_cs4231_create(card, chip->wss_base + 4, -1, |
1796 | chip->irq, chip->dma1, chip->dma2, | 743 | chip->irq, chip->dma1, chip->dma2, |
1797 | CS4231_HW_DETECT, | 744 | #ifdef CS4231 |
1798 | 0, | 745 | CS4231_HW_DETECT, 0, |
746 | #else /* OPTi93x */ | ||
747 | CS4231_HW_OPTI93X, CS4231_HWSHARE_IRQ, | ||
748 | #endif | ||
1799 | &codec)) < 0) | 749 | &codec)) < 0) |
1800 | return error; | 750 | return error; |
751 | #ifdef OPTi93X | ||
752 | chip->codec = codec; | ||
753 | #endif | ||
1801 | if ((error = snd_cs4231_pcm(codec, 0, &pcm)) < 0) | 754 | if ((error = snd_cs4231_pcm(codec, 0, &pcm)) < 0) |
1802 | return error; | 755 | return error; |
1803 | if ((error = snd_cs4231_mixer(codec)) < 0) | 756 | if ((error = snd_cs4231_mixer(codec)) < 0) |
1804 | return error; | 757 | return error; |
758 | #ifdef CS4231 | ||
1805 | if ((error = snd_cs4231_timer(codec, 0, &timer)) < 0) | 759 | if ((error = snd_cs4231_timer(codec, 0, &timer)) < 0) |
1806 | return error; | 760 | return error; |
761 | #else /* OPTI93X */ | ||
762 | error = request_irq(chip->irq, snd_opti93x_interrupt, | ||
763 | IRQF_DISABLED, DEV_NAME" - WSS", codec); | ||
764 | if (error < 0) { | ||
765 | snd_printk(KERN_ERR "opti9xx: can't grab IRQ %d\n", chip->irq); | ||
766 | return error; | ||
767 | } | ||
768 | #endif | ||
1807 | #else | 769 | #else |
1808 | if ((error = snd_ad1848_create(card, chip->wss_base + 4, | 770 | if ((error = snd_ad1848_create(card, chip->wss_base + 4, |
1809 | chip->irq, chip->dma1, | 771 | chip->irq, chip->dma1, |
diff --git a/sound/isa/sb/Makefile b/sound/isa/sb/Makefile index c9d1c986d70e..1098a56b2f4b 100644 --- a/sound/isa/sb/Makefile +++ b/sound/isa/sb/Makefile | |||
@@ -34,5 +34,3 @@ ifeq ($(CONFIG_SND_SB16_CSP),y) | |||
34 | obj-$(CONFIG_SND_SBAWE) += snd-sb16-csp.o | 34 | obj-$(CONFIG_SND_SBAWE) += snd-sb16-csp.o |
35 | endif | 35 | endif |
36 | obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-emu8000-synth.o | 36 | obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-emu8000-synth.o |
37 | |||
38 | obj-m := $(sort $(obj-m)) | ||
diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c index 95eeca163354..0bb9b9256601 100644 --- a/sound/isa/wavefront/wavefront_synth.c +++ b/sound/isa/wavefront/wavefront_synth.c | |||
@@ -1939,7 +1939,7 @@ static int __devinit | |||
1939 | wavefront_download_firmware (snd_wavefront_t *dev, char *path) | 1939 | wavefront_download_firmware (snd_wavefront_t *dev, char *path) |
1940 | 1940 | ||
1941 | { | 1941 | { |
1942 | unsigned char *buf; | 1942 | const unsigned char *buf; |
1943 | int len, err; | 1943 | int len, err; |
1944 | int section_cnt_downloaded = 0; | 1944 | int section_cnt_downloaded = 0; |
1945 | const struct firmware *firmware; | 1945 | const struct firmware *firmware; |
diff --git a/sound/mips/Kconfig b/sound/mips/Kconfig index 531f8ba96a71..a9823fad85c2 100644 --- a/sound/mips/Kconfig +++ b/sound/mips/Kconfig | |||
@@ -1,15 +1,34 @@ | |||
1 | # ALSA MIPS drivers | 1 | # ALSA MIPS drivers |
2 | 2 | ||
3 | menu "ALSA MIPS devices" | 3 | menuconfig SND_MIPS |
4 | depends on SND!=n && MIPS | 4 | bool "MIPS sound devices" |
5 | depends on MIPS | ||
6 | default y | ||
7 | help | ||
8 | Support for sound devices of MIPS architectures. | ||
9 | |||
10 | if SND_MIPS | ||
11 | |||
12 | config SND_SGI_O2 | ||
13 | tristate "SGI O2 Audio" | ||
14 | depends on SGI_IP32 | ||
15 | help | ||
16 | Sound support for the SGI O2 Workstation. | ||
17 | |||
18 | config SND_SGI_HAL2 | ||
19 | tristate "SGI HAL2 Audio" | ||
20 | depends on SGI_HAS_HAL2 | ||
21 | help | ||
22 | Sound support for the SGI Indy and Indigo2 Workstation. | ||
23 | |||
5 | 24 | ||
6 | config SND_AU1X00 | 25 | config SND_AU1X00 |
7 | tristate "Au1x00 AC97 Port Driver" | 26 | tristate "Au1x00 AC97 Port Driver" |
8 | depends on (SOC_AU1000 || SOC_AU1100 || SOC_AU1500) && SND | 27 | depends on SOC_AU1000 || SOC_AU1100 || SOC_AU1500 |
9 | select SND_PCM | 28 | select SND_PCM |
10 | select SND_AC97_CODEC | 29 | select SND_AC97_CODEC |
11 | help | 30 | help |
12 | ALSA Sound driver for the Au1x00's AC97 port. | 31 | ALSA Sound driver for the Au1x00's AC97 port. |
13 | 32 | ||
14 | endmenu | 33 | endif # SND_MIPS |
15 | 34 | ||
diff --git a/sound/mips/Makefile b/sound/mips/Makefile index 47afed971fba..861ec0a574b4 100644 --- a/sound/mips/Makefile +++ b/sound/mips/Makefile | |||
@@ -3,6 +3,10 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | snd-au1x00-objs := au1x00.o | 5 | snd-au1x00-objs := au1x00.o |
6 | snd-sgi-o2-objs := sgio2audio.o ad1843.o | ||
7 | snd-sgi-hal2-objs := hal2.o | ||
6 | 8 | ||
7 | # Toplevel Module Dependency | 9 | # Toplevel Module Dependency |
8 | obj-$(CONFIG_SND_AU1X00) += snd-au1x00.o | 10 | obj-$(CONFIG_SND_AU1X00) += snd-au1x00.o |
11 | obj-$(CONFIG_SND_SGI_O2) += snd-sgi-o2.o | ||
12 | obj-$(CONFIG_SND_SGI_HAL2) += snd-sgi-hal2.o | ||
diff --git a/sound/mips/ad1843.c b/sound/mips/ad1843.c new file mode 100644 index 000000000000..c624510ec374 --- /dev/null +++ b/sound/mips/ad1843.c | |||
@@ -0,0 +1,561 @@ | |||
1 | /* | ||
2 | * AD1843 low level driver | ||
3 | * | ||
4 | * Copyright 2003 Vivien Chappelier <vivien.chappelier@linux-mips.org> | ||
5 | * Copyright 2008 Thomas Bogendoerfer <tsbogend@alpha.franken.de> | ||
6 | * | ||
7 | * inspired from vwsnd.c (SGI VW audio driver) | ||
8 | * Copyright 1999 Silicon Graphics, Inc. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #include <linux/init.h> | ||
27 | #include <linux/sched.h> | ||
28 | #include <linux/errno.h> | ||
29 | #include <sound/core.h> | ||
30 | #include <sound/pcm.h> | ||
31 | #include <sound/ad1843.h> | ||
32 | |||
33 | /* | ||
34 | * AD1843 bitfield definitions. All are named as in the AD1843 data | ||
35 | * sheet, with ad1843_ prepended and individual bit numbers removed. | ||
36 | * | ||
37 | * E.g., bits LSS0 through LSS2 become ad1843_LSS. | ||
38 | * | ||
39 | * Only the bitfields we need are defined. | ||
40 | */ | ||
41 | |||
42 | struct ad1843_bitfield { | ||
43 | char reg; | ||
44 | char lo_bit; | ||
45 | char nbits; | ||
46 | }; | ||
47 | |||
48 | static const struct ad1843_bitfield | ||
49 | ad1843_PDNO = { 0, 14, 1 }, /* Converter Power-Down Flag */ | ||
50 | ad1843_INIT = { 0, 15, 1 }, /* Clock Initialization Flag */ | ||
51 | ad1843_RIG = { 2, 0, 4 }, /* Right ADC Input Gain */ | ||
52 | ad1843_RMGE = { 2, 4, 1 }, /* Right ADC Mic Gain Enable */ | ||
53 | ad1843_RSS = { 2, 5, 3 }, /* Right ADC Source Select */ | ||
54 | ad1843_LIG = { 2, 8, 4 }, /* Left ADC Input Gain */ | ||
55 | ad1843_LMGE = { 2, 12, 1 }, /* Left ADC Mic Gain Enable */ | ||
56 | ad1843_LSS = { 2, 13, 3 }, /* Left ADC Source Select */ | ||
57 | ad1843_RD2M = { 3, 0, 5 }, /* Right DAC 2 Mix Gain/Atten */ | ||
58 | ad1843_RD2MM = { 3, 7, 1 }, /* Right DAC 2 Mix Mute */ | ||
59 | ad1843_LD2M = { 3, 8, 5 }, /* Left DAC 2 Mix Gain/Atten */ | ||
60 | ad1843_LD2MM = { 3, 15, 1 }, /* Left DAC 2 Mix Mute */ | ||
61 | ad1843_RX1M = { 4, 0, 5 }, /* Right Aux 1 Mix Gain/Atten */ | ||
62 | ad1843_RX1MM = { 4, 7, 1 }, /* Right Aux 1 Mix Mute */ | ||
63 | ad1843_LX1M = { 4, 8, 5 }, /* Left Aux 1 Mix Gain/Atten */ | ||
64 | ad1843_LX1MM = { 4, 15, 1 }, /* Left Aux 1 Mix Mute */ | ||
65 | ad1843_RX2M = { 5, 0, 5 }, /* Right Aux 2 Mix Gain/Atten */ | ||
66 | ad1843_RX2MM = { 5, 7, 1 }, /* Right Aux 2 Mix Mute */ | ||
67 | ad1843_LX2M = { 5, 8, 5 }, /* Left Aux 2 Mix Gain/Atten */ | ||
68 | ad1843_LX2MM = { 5, 15, 1 }, /* Left Aux 2 Mix Mute */ | ||
69 | ad1843_RMCM = { 7, 0, 5 }, /* Right Mic Mix Gain/Atten */ | ||
70 | ad1843_RMCMM = { 7, 7, 1 }, /* Right Mic Mix Mute */ | ||
71 | ad1843_LMCM = { 7, 8, 5 }, /* Left Mic Mix Gain/Atten */ | ||
72 | ad1843_LMCMM = { 7, 15, 1 }, /* Left Mic Mix Mute */ | ||
73 | ad1843_HPOS = { 8, 4, 1 }, /* Headphone Output Voltage Swing */ | ||
74 | ad1843_HPOM = { 8, 5, 1 }, /* Headphone Output Mute */ | ||
75 | ad1843_MPOM = { 8, 6, 1 }, /* Mono Output Mute */ | ||
76 | ad1843_RDA1G = { 9, 0, 6 }, /* Right DAC1 Analog/Digital Gain */ | ||
77 | ad1843_RDA1GM = { 9, 7, 1 }, /* Right DAC1 Analog Mute */ | ||
78 | ad1843_LDA1G = { 9, 8, 6 }, /* Left DAC1 Analog/Digital Gain */ | ||
79 | ad1843_LDA1GM = { 9, 15, 1 }, /* Left DAC1 Analog Mute */ | ||
80 | ad1843_RDA2G = { 10, 0, 6 }, /* Right DAC2 Analog/Digital Gain */ | ||
81 | ad1843_RDA2GM = { 10, 7, 1 }, /* Right DAC2 Analog Mute */ | ||
82 | ad1843_LDA2G = { 10, 8, 6 }, /* Left DAC2 Analog/Digital Gain */ | ||
83 | ad1843_LDA2GM = { 10, 15, 1 }, /* Left DAC2 Analog Mute */ | ||
84 | ad1843_RDA1AM = { 11, 7, 1 }, /* Right DAC1 Digital Mute */ | ||
85 | ad1843_LDA1AM = { 11, 15, 1 }, /* Left DAC1 Digital Mute */ | ||
86 | ad1843_RDA2AM = { 12, 7, 1 }, /* Right DAC2 Digital Mute */ | ||
87 | ad1843_LDA2AM = { 12, 15, 1 }, /* Left DAC2 Digital Mute */ | ||
88 | ad1843_ADLC = { 15, 0, 2 }, /* ADC Left Sample Rate Source */ | ||
89 | ad1843_ADRC = { 15, 2, 2 }, /* ADC Right Sample Rate Source */ | ||
90 | ad1843_DA1C = { 15, 8, 2 }, /* DAC1 Sample Rate Source */ | ||
91 | ad1843_DA2C = { 15, 10, 2 }, /* DAC2 Sample Rate Source */ | ||
92 | ad1843_C1C = { 17, 0, 16 }, /* Clock 1 Sample Rate Select */ | ||
93 | ad1843_C2C = { 20, 0, 16 }, /* Clock 2 Sample Rate Select */ | ||
94 | ad1843_C3C = { 23, 0, 16 }, /* Clock 3 Sample Rate Select */ | ||
95 | ad1843_DAADL = { 25, 4, 2 }, /* Digital ADC Left Source Select */ | ||
96 | ad1843_DAADR = { 25, 6, 2 }, /* Digital ADC Right Source Select */ | ||
97 | ad1843_DAMIX = { 25, 14, 1 }, /* DAC Digital Mix Enable */ | ||
98 | ad1843_DRSFLT = { 25, 15, 1 }, /* Digital Reampler Filter Mode */ | ||
99 | ad1843_ADLF = { 26, 0, 2 }, /* ADC Left Channel Data Format */ | ||
100 | ad1843_ADRF = { 26, 2, 2 }, /* ADC Right Channel Data Format */ | ||
101 | ad1843_ADTLK = { 26, 4, 1 }, /* ADC Transmit Lock Mode Select */ | ||
102 | ad1843_SCF = { 26, 7, 1 }, /* SCLK Frequency Select */ | ||
103 | ad1843_DA1F = { 26, 8, 2 }, /* DAC1 Data Format Select */ | ||
104 | ad1843_DA2F = { 26, 10, 2 }, /* DAC2 Data Format Select */ | ||
105 | ad1843_DA1SM = { 26, 14, 1 }, /* DAC1 Stereo/Mono Mode Select */ | ||
106 | ad1843_DA2SM = { 26, 15, 1 }, /* DAC2 Stereo/Mono Mode Select */ | ||
107 | ad1843_ADLEN = { 27, 0, 1 }, /* ADC Left Channel Enable */ | ||
108 | ad1843_ADREN = { 27, 1, 1 }, /* ADC Right Channel Enable */ | ||
109 | ad1843_AAMEN = { 27, 4, 1 }, /* Analog to Analog Mix Enable */ | ||
110 | ad1843_ANAEN = { 27, 7, 1 }, /* Analog Channel Enable */ | ||
111 | ad1843_DA1EN = { 27, 8, 1 }, /* DAC1 Enable */ | ||
112 | ad1843_DA2EN = { 27, 9, 1 }, /* DAC2 Enable */ | ||
113 | ad1843_DDMEN = { 27, 12, 1 }, /* DAC2 to DAC1 Mix Enable */ | ||
114 | ad1843_C1EN = { 28, 11, 1 }, /* Clock Generator 1 Enable */ | ||
115 | ad1843_C2EN = { 28, 12, 1 }, /* Clock Generator 2 Enable */ | ||
116 | ad1843_C3EN = { 28, 13, 1 }, /* Clock Generator 3 Enable */ | ||
117 | ad1843_PDNI = { 28, 15, 1 }; /* Converter Power Down */ | ||
118 | |||
119 | /* | ||
120 | * The various registers of the AD1843 use three different formats for | ||
121 | * specifying gain. The ad1843_gain structure parameterizes the | ||
122 | * formats. | ||
123 | */ | ||
124 | |||
125 | struct ad1843_gain { | ||
126 | int negative; /* nonzero if gain is negative. */ | ||
127 | const struct ad1843_bitfield *lfield; | ||
128 | const struct ad1843_bitfield *rfield; | ||
129 | const struct ad1843_bitfield *lmute; | ||
130 | const struct ad1843_bitfield *rmute; | ||
131 | }; | ||
132 | |||
133 | static const struct ad1843_gain ad1843_gain_RECLEV = { | ||
134 | .negative = 0, | ||
135 | .lfield = &ad1843_LIG, | ||
136 | .rfield = &ad1843_RIG | ||
137 | }; | ||
138 | static const struct ad1843_gain ad1843_gain_LINE = { | ||
139 | .negative = 1, | ||
140 | .lfield = &ad1843_LX1M, | ||
141 | .rfield = &ad1843_RX1M, | ||
142 | .lmute = &ad1843_LX1MM, | ||
143 | .rmute = &ad1843_RX1MM | ||
144 | }; | ||
145 | static const struct ad1843_gain ad1843_gain_LINE_2 = { | ||
146 | .negative = 1, | ||
147 | .lfield = &ad1843_LDA2G, | ||
148 | .rfield = &ad1843_RDA2G, | ||
149 | .lmute = &ad1843_LDA2GM, | ||
150 | .rmute = &ad1843_RDA2GM | ||
151 | }; | ||
152 | static const struct ad1843_gain ad1843_gain_MIC = { | ||
153 | .negative = 1, | ||
154 | .lfield = &ad1843_LMCM, | ||
155 | .rfield = &ad1843_RMCM, | ||
156 | .lmute = &ad1843_LMCMM, | ||
157 | .rmute = &ad1843_RMCMM | ||
158 | }; | ||
159 | static const struct ad1843_gain ad1843_gain_PCM_0 = { | ||
160 | .negative = 1, | ||
161 | .lfield = &ad1843_LDA1G, | ||
162 | .rfield = &ad1843_RDA1G, | ||
163 | .lmute = &ad1843_LDA1GM, | ||
164 | .rmute = &ad1843_RDA1GM | ||
165 | }; | ||
166 | static const struct ad1843_gain ad1843_gain_PCM_1 = { | ||
167 | .negative = 1, | ||
168 | .lfield = &ad1843_LD2M, | ||
169 | .rfield = &ad1843_RD2M, | ||
170 | .lmute = &ad1843_LD2MM, | ||
171 | .rmute = &ad1843_RD2MM | ||
172 | }; | ||
173 | |||
174 | static const struct ad1843_gain *ad1843_gain[AD1843_GAIN_SIZE] = | ||
175 | { | ||
176 | &ad1843_gain_RECLEV, | ||
177 | &ad1843_gain_LINE, | ||
178 | &ad1843_gain_LINE_2, | ||
179 | &ad1843_gain_MIC, | ||
180 | &ad1843_gain_PCM_0, | ||
181 | &ad1843_gain_PCM_1, | ||
182 | }; | ||
183 | |||
184 | /* read the current value of an AD1843 bitfield. */ | ||
185 | |||
186 | static int ad1843_read_bits(struct snd_ad1843 *ad1843, | ||
187 | const struct ad1843_bitfield *field) | ||
188 | { | ||
189 | int w; | ||
190 | |||
191 | w = ad1843->read(ad1843->chip, field->reg); | ||
192 | return w >> field->lo_bit & ((1 << field->nbits) - 1); | ||
193 | } | ||
194 | |||
195 | /* | ||
196 | * write a new value to an AD1843 bitfield and return the old value. | ||
197 | */ | ||
198 | |||
199 | static int ad1843_write_bits(struct snd_ad1843 *ad1843, | ||
200 | const struct ad1843_bitfield *field, | ||
201 | int newval) | ||
202 | { | ||
203 | int w, mask, oldval, newbits; | ||
204 | |||
205 | w = ad1843->read(ad1843->chip, field->reg); | ||
206 | mask = ((1 << field->nbits) - 1) << field->lo_bit; | ||
207 | oldval = (w & mask) >> field->lo_bit; | ||
208 | newbits = (newval << field->lo_bit) & mask; | ||
209 | w = (w & ~mask) | newbits; | ||
210 | ad1843->write(ad1843->chip, field->reg, w); | ||
211 | |||
212 | return oldval; | ||
213 | } | ||
214 | |||
215 | /* | ||
216 | * ad1843_read_multi reads multiple bitfields from the same AD1843 | ||
217 | * register. It uses a single read cycle to do it. (Reading the | ||
218 | * ad1843 requires 256 bit times at 12.288 MHz, or nearly 20 | ||
219 | * microseconds.) | ||
220 | * | ||
221 | * Called like this. | ||
222 | * | ||
223 | * ad1843_read_multi(ad1843, nfields, | ||
224 | * &ad1843_FIELD1, &val1, | ||
225 | * &ad1843_FIELD2, &val2, ...); | ||
226 | */ | ||
227 | |||
228 | static void ad1843_read_multi(struct snd_ad1843 *ad1843, int argcount, ...) | ||
229 | { | ||
230 | va_list ap; | ||
231 | const struct ad1843_bitfield *fp; | ||
232 | int w = 0, mask, *value, reg = -1; | ||
233 | |||
234 | va_start(ap, argcount); | ||
235 | while (--argcount >= 0) { | ||
236 | fp = va_arg(ap, const struct ad1843_bitfield *); | ||
237 | value = va_arg(ap, int *); | ||
238 | if (reg == -1) { | ||
239 | reg = fp->reg; | ||
240 | w = ad1843->read(ad1843->chip, reg); | ||
241 | } | ||
242 | |||
243 | mask = (1 << fp->nbits) - 1; | ||
244 | *value = w >> fp->lo_bit & mask; | ||
245 | } | ||
246 | va_end(ap); | ||
247 | } | ||
248 | |||
249 | /* | ||
250 | * ad1843_write_multi stores multiple bitfields into the same AD1843 | ||
251 | * register. It uses one read and one write cycle to do it. | ||
252 | * | ||
253 | * Called like this. | ||
254 | * | ||
255 | * ad1843_write_multi(ad1843, nfields, | ||
256 | * &ad1843_FIELD1, val1, | ||
257 | * &ad1843_FIELF2, val2, ...); | ||
258 | */ | ||
259 | |||
260 | static void ad1843_write_multi(struct snd_ad1843 *ad1843, int argcount, ...) | ||
261 | { | ||
262 | va_list ap; | ||
263 | int reg; | ||
264 | const struct ad1843_bitfield *fp; | ||
265 | int value; | ||
266 | int w, m, mask, bits; | ||
267 | |||
268 | mask = 0; | ||
269 | bits = 0; | ||
270 | reg = -1; | ||
271 | |||
272 | va_start(ap, argcount); | ||
273 | while (--argcount >= 0) { | ||
274 | fp = va_arg(ap, const struct ad1843_bitfield *); | ||
275 | value = va_arg(ap, int); | ||
276 | if (reg == -1) | ||
277 | reg = fp->reg; | ||
278 | else | ||
279 | BUG_ON(reg != fp->reg); | ||
280 | m = ((1 << fp->nbits) - 1) << fp->lo_bit; | ||
281 | mask |= m; | ||
282 | bits |= (value << fp->lo_bit) & m; | ||
283 | } | ||
284 | va_end(ap); | ||
285 | |||
286 | if (~mask & 0xFFFF) | ||
287 | w = ad1843->read(ad1843->chip, reg); | ||
288 | else | ||
289 | w = 0; | ||
290 | w = (w & ~mask) | bits; | ||
291 | ad1843->write(ad1843->chip, reg, w); | ||
292 | } | ||
293 | |||
294 | int ad1843_get_gain_max(struct snd_ad1843 *ad1843, int id) | ||
295 | { | ||
296 | const struct ad1843_gain *gp = ad1843_gain[id]; | ||
297 | int ret; | ||
298 | |||
299 | ret = (1 << gp->lfield->nbits); | ||
300 | if (!gp->lmute) | ||
301 | ret -= 1; | ||
302 | return ret; | ||
303 | } | ||
304 | |||
305 | /* | ||
306 | * ad1843_get_gain reads the specified register and extracts the gain value | ||
307 | * using the supplied gain type. | ||
308 | */ | ||
309 | |||
310 | int ad1843_get_gain(struct snd_ad1843 *ad1843, int id) | ||
311 | { | ||
312 | int lg, rg, lm, rm; | ||
313 | const struct ad1843_gain *gp = ad1843_gain[id]; | ||
314 | unsigned short mask = (1 << gp->lfield->nbits) - 1; | ||
315 | |||
316 | ad1843_read_multi(ad1843, 2, gp->lfield, &lg, gp->rfield, &rg); | ||
317 | if (gp->negative) { | ||
318 | lg = mask - lg; | ||
319 | rg = mask - rg; | ||
320 | } | ||
321 | if (gp->lmute) { | ||
322 | ad1843_read_multi(ad1843, 2, gp->lmute, &lm, gp->rmute, &rm); | ||
323 | if (lm) | ||
324 | lg = 0; | ||
325 | if (rm) | ||
326 | rg = 0; | ||
327 | } | ||
328 | return lg << 0 | rg << 8; | ||
329 | } | ||
330 | |||
331 | /* | ||
332 | * Set an audio channel's gain. | ||
333 | * | ||
334 | * Returns the new gain, which may be lower than the old gain. | ||
335 | */ | ||
336 | |||
337 | int ad1843_set_gain(struct snd_ad1843 *ad1843, int id, int newval) | ||
338 | { | ||
339 | const struct ad1843_gain *gp = ad1843_gain[id]; | ||
340 | unsigned short mask = (1 << gp->lfield->nbits) - 1; | ||
341 | |||
342 | int lg = (newval >> 0) & mask; | ||
343 | int rg = (newval >> 8) & mask; | ||
344 | int lm = (lg == 0) ? 1 : 0; | ||
345 | int rm = (rg == 0) ? 1 : 0; | ||
346 | |||
347 | if (gp->negative) { | ||
348 | lg = mask - lg; | ||
349 | rg = mask - rg; | ||
350 | } | ||
351 | if (gp->lmute) | ||
352 | ad1843_write_multi(ad1843, 2, gp->lmute, lm, gp->rmute, rm); | ||
353 | ad1843_write_multi(ad1843, 2, gp->lfield, lg, gp->rfield, rg); | ||
354 | return ad1843_get_gain(ad1843, id); | ||
355 | } | ||
356 | |||
357 | /* Returns the current recording source */ | ||
358 | |||
359 | int ad1843_get_recsrc(struct snd_ad1843 *ad1843) | ||
360 | { | ||
361 | int val = ad1843_read_bits(ad1843, &ad1843_LSS); | ||
362 | |||
363 | if (val < 0 || val > 2) { | ||
364 | val = 2; | ||
365 | ad1843_write_multi(ad1843, 2, | ||
366 | &ad1843_LSS, val, &ad1843_RSS, val); | ||
367 | } | ||
368 | return val; | ||
369 | } | ||
370 | |||
371 | /* | ||
372 | * Set recording source. | ||
373 | * | ||
374 | * Returns newsrc on success, -errno on failure. | ||
375 | */ | ||
376 | |||
377 | int ad1843_set_recsrc(struct snd_ad1843 *ad1843, int newsrc) | ||
378 | { | ||
379 | if (newsrc < 0 || newsrc > 2) | ||
380 | return -EINVAL; | ||
381 | |||
382 | ad1843_write_multi(ad1843, 2, &ad1843_LSS, newsrc, &ad1843_RSS, newsrc); | ||
383 | return newsrc; | ||
384 | } | ||
385 | |||
386 | /* Setup ad1843 for D/A conversion. */ | ||
387 | |||
388 | void ad1843_setup_dac(struct snd_ad1843 *ad1843, | ||
389 | unsigned int id, | ||
390 | unsigned int framerate, | ||
391 | snd_pcm_format_t fmt, | ||
392 | unsigned int channels) | ||
393 | { | ||
394 | int ad_fmt = 0, ad_mode = 0; | ||
395 | |||
396 | switch (fmt) { | ||
397 | case SNDRV_PCM_FORMAT_S8: | ||
398 | ad_fmt = 0; | ||
399 | break; | ||
400 | case SNDRV_PCM_FORMAT_U8: | ||
401 | ad_fmt = 0; | ||
402 | break; | ||
403 | case SNDRV_PCM_FORMAT_S16_LE: | ||
404 | ad_fmt = 1; | ||
405 | break; | ||
406 | case SNDRV_PCM_FORMAT_MU_LAW: | ||
407 | ad_fmt = 2; | ||
408 | break; | ||
409 | case SNDRV_PCM_FORMAT_A_LAW: | ||
410 | ad_fmt = 3; | ||
411 | break; | ||
412 | default: | ||
413 | break; | ||
414 | } | ||
415 | |||
416 | switch (channels) { | ||
417 | case 2: | ||
418 | ad_mode = 0; | ||
419 | break; | ||
420 | case 1: | ||
421 | ad_mode = 1; | ||
422 | break; | ||
423 | default: | ||
424 | break; | ||
425 | } | ||
426 | |||
427 | if (id) { | ||
428 | ad1843_write_bits(ad1843, &ad1843_C2C, framerate); | ||
429 | ad1843_write_multi(ad1843, 2, | ||
430 | &ad1843_DA2SM, ad_mode, | ||
431 | &ad1843_DA2F, ad_fmt); | ||
432 | } else { | ||
433 | ad1843_write_bits(ad1843, &ad1843_C1C, framerate); | ||
434 | ad1843_write_multi(ad1843, 2, | ||
435 | &ad1843_DA1SM, ad_mode, | ||
436 | &ad1843_DA1F, ad_fmt); | ||
437 | } | ||
438 | } | ||
439 | |||
440 | void ad1843_shutdown_dac(struct snd_ad1843 *ad1843, unsigned int id) | ||
441 | { | ||
442 | if (id) | ||
443 | ad1843_write_bits(ad1843, &ad1843_DA2F, 1); | ||
444 | else | ||
445 | ad1843_write_bits(ad1843, &ad1843_DA1F, 1); | ||
446 | } | ||
447 | |||
448 | void ad1843_setup_adc(struct snd_ad1843 *ad1843, | ||
449 | unsigned int framerate, | ||
450 | snd_pcm_format_t fmt, | ||
451 | unsigned int channels) | ||
452 | { | ||
453 | int da_fmt = 0; | ||
454 | |||
455 | switch (fmt) { | ||
456 | case SNDRV_PCM_FORMAT_S8: da_fmt = 0; break; | ||
457 | case SNDRV_PCM_FORMAT_U8: da_fmt = 0; break; | ||
458 | case SNDRV_PCM_FORMAT_S16_LE: da_fmt = 1; break; | ||
459 | case SNDRV_PCM_FORMAT_MU_LAW: da_fmt = 2; break; | ||
460 | case SNDRV_PCM_FORMAT_A_LAW: da_fmt = 3; break; | ||
461 | default: break; | ||
462 | } | ||
463 | |||
464 | ad1843_write_bits(ad1843, &ad1843_C3C, framerate); | ||
465 | ad1843_write_multi(ad1843, 2, | ||
466 | &ad1843_ADLF, da_fmt, &ad1843_ADRF, da_fmt); | ||
467 | } | ||
468 | |||
469 | void ad1843_shutdown_adc(struct snd_ad1843 *ad1843) | ||
470 | { | ||
471 | /* nothing to do */ | ||
472 | } | ||
473 | |||
474 | /* | ||
475 | * Fully initialize the ad1843. As described in the AD1843 data | ||
476 | * sheet, section "START-UP SEQUENCE". The numbered comments are | ||
477 | * subsection headings from the data sheet. See the data sheet, pages | ||
478 | * 52-54, for more info. | ||
479 | * | ||
480 | * return 0 on success, -errno on failure. */ | ||
481 | |||
482 | int ad1843_init(struct snd_ad1843 *ad1843) | ||
483 | { | ||
484 | unsigned long later; | ||
485 | |||
486 | if (ad1843_read_bits(ad1843, &ad1843_INIT) != 0) { | ||
487 | printk(KERN_ERR "ad1843: AD1843 won't initialize\n"); | ||
488 | return -EIO; | ||
489 | } | ||
490 | |||
491 | ad1843_write_bits(ad1843, &ad1843_SCF, 1); | ||
492 | |||
493 | /* 4. Put the conversion resources into standby. */ | ||
494 | ad1843_write_bits(ad1843, &ad1843_PDNI, 0); | ||
495 | later = jiffies + msecs_to_jiffies(500); | ||
496 | |||
497 | while (ad1843_read_bits(ad1843, &ad1843_PDNO)) { | ||
498 | if (time_after(jiffies, later)) { | ||
499 | printk(KERN_ERR | ||
500 | "ad1843: AD1843 won't power up\n"); | ||
501 | return -EIO; | ||
502 | } | ||
503 | schedule_timeout_interruptible(5); | ||
504 | } | ||
505 | |||
506 | /* 5. Power up the clock generators and enable clock output pins. */ | ||
507 | ad1843_write_multi(ad1843, 3, | ||
508 | &ad1843_C1EN, 1, | ||
509 | &ad1843_C2EN, 1, | ||
510 | &ad1843_C3EN, 1); | ||
511 | |||
512 | /* 6. Configure conversion resources while they are in standby. */ | ||
513 | |||
514 | /* DAC1/2 use clock 1/2 as source, ADC uses clock 3. Always. */ | ||
515 | ad1843_write_multi(ad1843, 4, | ||
516 | &ad1843_DA1C, 1, | ||
517 | &ad1843_DA2C, 2, | ||
518 | &ad1843_ADLC, 3, | ||
519 | &ad1843_ADRC, 3); | ||
520 | |||
521 | /* 7. Enable conversion resources. */ | ||
522 | ad1843_write_bits(ad1843, &ad1843_ADTLK, 1); | ||
523 | ad1843_write_multi(ad1843, 7, | ||
524 | &ad1843_ANAEN, 1, | ||
525 | &ad1843_AAMEN, 1, | ||
526 | &ad1843_DA1EN, 1, | ||
527 | &ad1843_DA2EN, 1, | ||
528 | &ad1843_DDMEN, 1, | ||
529 | &ad1843_ADLEN, 1, | ||
530 | &ad1843_ADREN, 1); | ||
531 | |||
532 | /* 8. Configure conversion resources while they are enabled. */ | ||
533 | |||
534 | /* set gain to 0 for all channels */ | ||
535 | ad1843_set_gain(ad1843, AD1843_GAIN_RECLEV, 0); | ||
536 | ad1843_set_gain(ad1843, AD1843_GAIN_LINE, 0); | ||
537 | ad1843_set_gain(ad1843, AD1843_GAIN_LINE_2, 0); | ||
538 | ad1843_set_gain(ad1843, AD1843_GAIN_MIC, 0); | ||
539 | ad1843_set_gain(ad1843, AD1843_GAIN_PCM_0, 0); | ||
540 | ad1843_set_gain(ad1843, AD1843_GAIN_PCM_1, 0); | ||
541 | |||
542 | /* Unmute all channels. */ | ||
543 | /* DAC1 */ | ||
544 | ad1843_write_multi(ad1843, 2, &ad1843_LDA1GM, 0, &ad1843_RDA1GM, 0); | ||
545 | /* DAC2 */ | ||
546 | ad1843_write_multi(ad1843, 2, &ad1843_LDA2GM, 0, &ad1843_RDA2GM, 0); | ||
547 | |||
548 | /* Set default recording source to Line In and set | ||
549 | * mic gain to +20 dB. | ||
550 | */ | ||
551 | ad1843_set_recsrc(ad1843, 2); | ||
552 | ad1843_write_multi(ad1843, 2, &ad1843_LMGE, 1, &ad1843_RMGE, 1); | ||
553 | |||
554 | /* Set Speaker Out level to +/- 4V and unmute it. */ | ||
555 | ad1843_write_multi(ad1843, 3, | ||
556 | &ad1843_HPOS, 1, | ||
557 | &ad1843_HPOM, 0, | ||
558 | &ad1843_MPOM, 0); | ||
559 | |||
560 | return 0; | ||
561 | } | ||
diff --git a/sound/mips/hal2.c b/sound/mips/hal2.c new file mode 100644 index 000000000000..db495be01861 --- /dev/null +++ b/sound/mips/hal2.c | |||
@@ -0,0 +1,947 @@ | |||
1 | /* | ||
2 | * Driver for A2 audio system used in SGI machines | ||
3 | * Copyright (c) 2008 Thomas Bogendoerfer <tsbogend@alpha.fanken.de> | ||
4 | * | ||
5 | * Based on OSS code from Ladislav Michl <ladis@linux-mips.org>, which | ||
6 | * was based on code from Ulf Carlsson | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | * | ||
21 | */ | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/dma-mapping.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/io.h> | ||
28 | |||
29 | #include <asm/sgi/hpc3.h> | ||
30 | #include <asm/sgi/ip22.h> | ||
31 | |||
32 | #include <sound/core.h> | ||
33 | #include <sound/control.h> | ||
34 | #include <sound/pcm.h> | ||
35 | #include <sound/pcm-indirect.h> | ||
36 | #include <sound/initval.h> | ||
37 | |||
38 | #include "hal2.h" | ||
39 | |||
40 | static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ | ||
41 | static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ | ||
42 | |||
43 | module_param(index, int, 0444); | ||
44 | MODULE_PARM_DESC(index, "Index value for SGI HAL2 soundcard."); | ||
45 | module_param(id, charp, 0444); | ||
46 | MODULE_PARM_DESC(id, "ID string for SGI HAL2 soundcard."); | ||
47 | MODULE_DESCRIPTION("ALSA driver for SGI HAL2 audio"); | ||
48 | MODULE_AUTHOR("Thomas Bogendoerfer"); | ||
49 | MODULE_LICENSE("GPL"); | ||
50 | |||
51 | |||
52 | #define H2_BLOCK_SIZE 1024 | ||
53 | #define H2_BUF_SIZE 16384 | ||
54 | |||
55 | struct hal2_pbus { | ||
56 | struct hpc3_pbus_dmacregs *pbus; | ||
57 | int pbusnr; | ||
58 | unsigned int ctrl; /* Current state of pbus->pbdma_ctrl */ | ||
59 | }; | ||
60 | |||
61 | struct hal2_desc { | ||
62 | struct hpc_dma_desc desc; | ||
63 | u32 pad; /* padding */ | ||
64 | }; | ||
65 | |||
66 | struct hal2_codec { | ||
67 | struct snd_pcm_indirect pcm_indirect; | ||
68 | struct snd_pcm_substream *substream; | ||
69 | |||
70 | unsigned char *buffer; | ||
71 | dma_addr_t buffer_dma; | ||
72 | struct hal2_desc *desc; | ||
73 | dma_addr_t desc_dma; | ||
74 | int desc_count; | ||
75 | struct hal2_pbus pbus; | ||
76 | int voices; /* mono/stereo */ | ||
77 | unsigned int sample_rate; | ||
78 | unsigned int master; /* Master frequency */ | ||
79 | unsigned short mod; /* MOD value */ | ||
80 | unsigned short inc; /* INC value */ | ||
81 | }; | ||
82 | |||
83 | #define H2_MIX_OUTPUT_ATT 0 | ||
84 | #define H2_MIX_INPUT_GAIN 1 | ||
85 | |||
86 | struct snd_hal2 { | ||
87 | struct snd_card *card; | ||
88 | |||
89 | struct hal2_ctl_regs *ctl_regs; /* HAL2 ctl registers */ | ||
90 | struct hal2_aes_regs *aes_regs; /* HAL2 aes registers */ | ||
91 | struct hal2_vol_regs *vol_regs; /* HAL2 vol registers */ | ||
92 | struct hal2_syn_regs *syn_regs; /* HAL2 syn registers */ | ||
93 | |||
94 | struct hal2_codec dac; | ||
95 | struct hal2_codec adc; | ||
96 | }; | ||
97 | |||
98 | #define H2_INDIRECT_WAIT(regs) while (hal2_read(®s->isr) & H2_ISR_TSTATUS); | ||
99 | |||
100 | #define H2_READ_ADDR(addr) (addr | (1<<7)) | ||
101 | #define H2_WRITE_ADDR(addr) (addr) | ||
102 | |||
103 | static inline u32 hal2_read(u32 *reg) | ||
104 | { | ||
105 | return __raw_readl(reg); | ||
106 | } | ||
107 | |||
108 | static inline void hal2_write(u32 val, u32 *reg) | ||
109 | { | ||
110 | __raw_writel(val, reg); | ||
111 | } | ||
112 | |||
113 | |||
114 | static u32 hal2_i_read32(struct snd_hal2 *hal2, u16 addr) | ||
115 | { | ||
116 | u32 ret; | ||
117 | struct hal2_ctl_regs *regs = hal2->ctl_regs; | ||
118 | |||
119 | hal2_write(H2_READ_ADDR(addr), ®s->iar); | ||
120 | H2_INDIRECT_WAIT(regs); | ||
121 | ret = hal2_read(®s->idr0) & 0xffff; | ||
122 | hal2_write(H2_READ_ADDR(addr) | 0x1, ®s->iar); | ||
123 | H2_INDIRECT_WAIT(regs); | ||
124 | ret |= (hal2_read(®s->idr0) & 0xffff) << 16; | ||
125 | return ret; | ||
126 | } | ||
127 | |||
128 | static void hal2_i_write16(struct snd_hal2 *hal2, u16 addr, u16 val) | ||
129 | { | ||
130 | struct hal2_ctl_regs *regs = hal2->ctl_regs; | ||
131 | |||
132 | hal2_write(val, ®s->idr0); | ||
133 | hal2_write(0, ®s->idr1); | ||
134 | hal2_write(0, ®s->idr2); | ||
135 | hal2_write(0, ®s->idr3); | ||
136 | hal2_write(H2_WRITE_ADDR(addr), ®s->iar); | ||
137 | H2_INDIRECT_WAIT(regs); | ||
138 | } | ||
139 | |||
140 | static void hal2_i_write32(struct snd_hal2 *hal2, u16 addr, u32 val) | ||
141 | { | ||
142 | struct hal2_ctl_regs *regs = hal2->ctl_regs; | ||
143 | |||
144 | hal2_write(val & 0xffff, ®s->idr0); | ||
145 | hal2_write(val >> 16, ®s->idr1); | ||
146 | hal2_write(0, ®s->idr2); | ||
147 | hal2_write(0, ®s->idr3); | ||
148 | hal2_write(H2_WRITE_ADDR(addr), ®s->iar); | ||
149 | H2_INDIRECT_WAIT(regs); | ||
150 | } | ||
151 | |||
152 | static void hal2_i_setbit16(struct snd_hal2 *hal2, u16 addr, u16 bit) | ||
153 | { | ||
154 | struct hal2_ctl_regs *regs = hal2->ctl_regs; | ||
155 | |||
156 | hal2_write(H2_READ_ADDR(addr), ®s->iar); | ||
157 | H2_INDIRECT_WAIT(regs); | ||
158 | hal2_write((hal2_read(®s->idr0) & 0xffff) | bit, ®s->idr0); | ||
159 | hal2_write(0, ®s->idr1); | ||
160 | hal2_write(0, ®s->idr2); | ||
161 | hal2_write(0, ®s->idr3); | ||
162 | hal2_write(H2_WRITE_ADDR(addr), ®s->iar); | ||
163 | H2_INDIRECT_WAIT(regs); | ||
164 | } | ||
165 | |||
166 | static void hal2_i_clearbit16(struct snd_hal2 *hal2, u16 addr, u16 bit) | ||
167 | { | ||
168 | struct hal2_ctl_regs *regs = hal2->ctl_regs; | ||
169 | |||
170 | hal2_write(H2_READ_ADDR(addr), ®s->iar); | ||
171 | H2_INDIRECT_WAIT(regs); | ||
172 | hal2_write((hal2_read(®s->idr0) & 0xffff) & ~bit, ®s->idr0); | ||
173 | hal2_write(0, ®s->idr1); | ||
174 | hal2_write(0, ®s->idr2); | ||
175 | hal2_write(0, ®s->idr3); | ||
176 | hal2_write(H2_WRITE_ADDR(addr), ®s->iar); | ||
177 | H2_INDIRECT_WAIT(regs); | ||
178 | } | ||
179 | |||
180 | static int hal2_gain_info(struct snd_kcontrol *kcontrol, | ||
181 | struct snd_ctl_elem_info *uinfo) | ||
182 | { | ||
183 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
184 | uinfo->count = 2; | ||
185 | uinfo->value.integer.min = 0; | ||
186 | switch ((int)kcontrol->private_value) { | ||
187 | case H2_MIX_OUTPUT_ATT: | ||
188 | uinfo->value.integer.max = 31; | ||
189 | break; | ||
190 | case H2_MIX_INPUT_GAIN: | ||
191 | uinfo->value.integer.max = 15; | ||
192 | break; | ||
193 | } | ||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | static int hal2_gain_get(struct snd_kcontrol *kcontrol, | ||
198 | struct snd_ctl_elem_value *ucontrol) | ||
199 | { | ||
200 | struct snd_hal2 *hal2 = snd_kcontrol_chip(kcontrol); | ||
201 | u32 tmp; | ||
202 | int l, r; | ||
203 | |||
204 | switch ((int)kcontrol->private_value) { | ||
205 | case H2_MIX_OUTPUT_ATT: | ||
206 | tmp = hal2_i_read32(hal2, H2I_DAC_C2); | ||
207 | if (tmp & H2I_C2_MUTE) { | ||
208 | l = 0; | ||
209 | r = 0; | ||
210 | } else { | ||
211 | l = 31 - ((tmp >> H2I_C2_L_ATT_SHIFT) & 31); | ||
212 | r = 31 - ((tmp >> H2I_C2_R_ATT_SHIFT) & 31); | ||
213 | } | ||
214 | break; | ||
215 | case H2_MIX_INPUT_GAIN: | ||
216 | tmp = hal2_i_read32(hal2, H2I_ADC_C2); | ||
217 | l = (tmp >> H2I_C2_L_GAIN_SHIFT) & 15; | ||
218 | r = (tmp >> H2I_C2_R_GAIN_SHIFT) & 15; | ||
219 | break; | ||
220 | } | ||
221 | ucontrol->value.integer.value[0] = l; | ||
222 | ucontrol->value.integer.value[1] = r; | ||
223 | |||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | static int hal2_gain_put(struct snd_kcontrol *kcontrol, | ||
228 | struct snd_ctl_elem_value *ucontrol) | ||
229 | { | ||
230 | struct snd_hal2 *hal2 = snd_kcontrol_chip(kcontrol); | ||
231 | u32 old, new; | ||
232 | int l, r; | ||
233 | |||
234 | l = ucontrol->value.integer.value[0]; | ||
235 | r = ucontrol->value.integer.value[1]; | ||
236 | |||
237 | switch ((int)kcontrol->private_value) { | ||
238 | case H2_MIX_OUTPUT_ATT: | ||
239 | old = hal2_i_read32(hal2, H2I_DAC_C2); | ||
240 | new = old & ~(H2I_C2_L_ATT_M | H2I_C2_R_ATT_M | H2I_C2_MUTE); | ||
241 | if (l | r) { | ||
242 | l = 31 - l; | ||
243 | r = 31 - r; | ||
244 | new |= (l << H2I_C2_L_ATT_SHIFT); | ||
245 | new |= (r << H2I_C2_R_ATT_SHIFT); | ||
246 | } else | ||
247 | new |= H2I_C2_L_ATT_M | H2I_C2_R_ATT_M | H2I_C2_MUTE; | ||
248 | hal2_i_write32(hal2, H2I_DAC_C2, new); | ||
249 | break; | ||
250 | case H2_MIX_INPUT_GAIN: | ||
251 | old = hal2_i_read32(hal2, H2I_ADC_C2); | ||
252 | new = old & ~(H2I_C2_L_GAIN_M | H2I_C2_R_GAIN_M); | ||
253 | new |= (l << H2I_C2_L_GAIN_SHIFT); | ||
254 | new |= (r << H2I_C2_R_GAIN_SHIFT); | ||
255 | hal2_i_write32(hal2, H2I_ADC_C2, new); | ||
256 | break; | ||
257 | } | ||
258 | return old != new; | ||
259 | } | ||
260 | |||
261 | static struct snd_kcontrol_new hal2_ctrl_headphone __devinitdata = { | ||
262 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
263 | .name = "Headphone Playback Volume", | ||
264 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
265 | .private_value = H2_MIX_OUTPUT_ATT, | ||
266 | .info = hal2_gain_info, | ||
267 | .get = hal2_gain_get, | ||
268 | .put = hal2_gain_put, | ||
269 | }; | ||
270 | |||
271 | static struct snd_kcontrol_new hal2_ctrl_mic __devinitdata = { | ||
272 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
273 | .name = "Mic Capture Volume", | ||
274 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
275 | .private_value = H2_MIX_INPUT_GAIN, | ||
276 | .info = hal2_gain_info, | ||
277 | .get = hal2_gain_get, | ||
278 | .put = hal2_gain_put, | ||
279 | }; | ||
280 | |||
281 | static int __devinit hal2_mixer_create(struct snd_hal2 *hal2) | ||
282 | { | ||
283 | int err; | ||
284 | |||
285 | /* mute DAC */ | ||
286 | hal2_i_write32(hal2, H2I_DAC_C2, | ||
287 | H2I_C2_L_ATT_M | H2I_C2_R_ATT_M | H2I_C2_MUTE); | ||
288 | /* mute ADC */ | ||
289 | hal2_i_write32(hal2, H2I_ADC_C2, 0); | ||
290 | |||
291 | err = snd_ctl_add(hal2->card, | ||
292 | snd_ctl_new1(&hal2_ctrl_headphone, hal2)); | ||
293 | if (err < 0) | ||
294 | return err; | ||
295 | |||
296 | err = snd_ctl_add(hal2->card, | ||
297 | snd_ctl_new1(&hal2_ctrl_mic, hal2)); | ||
298 | if (err < 0) | ||
299 | return err; | ||
300 | |||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | static irqreturn_t hal2_interrupt(int irq, void *dev_id) | ||
305 | { | ||
306 | struct snd_hal2 *hal2 = dev_id; | ||
307 | irqreturn_t ret = IRQ_NONE; | ||
308 | |||
309 | /* decide what caused this interrupt */ | ||
310 | if (hal2->dac.pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_INT) { | ||
311 | snd_pcm_period_elapsed(hal2->dac.substream); | ||
312 | ret = IRQ_HANDLED; | ||
313 | } | ||
314 | if (hal2->adc.pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_INT) { | ||
315 | snd_pcm_period_elapsed(hal2->adc.substream); | ||
316 | ret = IRQ_HANDLED; | ||
317 | } | ||
318 | return ret; | ||
319 | } | ||
320 | |||
321 | static int hal2_compute_rate(struct hal2_codec *codec, unsigned int rate) | ||
322 | { | ||
323 | unsigned short mod; | ||
324 | |||
325 | if (44100 % rate < 48000 % rate) { | ||
326 | mod = 4 * 44100 / rate; | ||
327 | codec->master = 44100; | ||
328 | } else { | ||
329 | mod = 4 * 48000 / rate; | ||
330 | codec->master = 48000; | ||
331 | } | ||
332 | |||
333 | codec->inc = 4; | ||
334 | codec->mod = mod; | ||
335 | rate = 4 * codec->master / mod; | ||
336 | |||
337 | return rate; | ||
338 | } | ||
339 | |||
340 | static void hal2_set_dac_rate(struct snd_hal2 *hal2) | ||
341 | { | ||
342 | unsigned int master = hal2->dac.master; | ||
343 | int inc = hal2->dac.inc; | ||
344 | int mod = hal2->dac.mod; | ||
345 | |||
346 | hal2_i_write16(hal2, H2I_BRES1_C1, (master == 44100) ? 1 : 0); | ||
347 | hal2_i_write32(hal2, H2I_BRES1_C2, | ||
348 | ((0xffff & (inc - mod - 1)) << 16) | inc); | ||
349 | } | ||
350 | |||
351 | static void hal2_set_adc_rate(struct snd_hal2 *hal2) | ||
352 | { | ||
353 | unsigned int master = hal2->adc.master; | ||
354 | int inc = hal2->adc.inc; | ||
355 | int mod = hal2->adc.mod; | ||
356 | |||
357 | hal2_i_write16(hal2, H2I_BRES2_C1, (master == 44100) ? 1 : 0); | ||
358 | hal2_i_write32(hal2, H2I_BRES2_C2, | ||
359 | ((0xffff & (inc - mod - 1)) << 16) | inc); | ||
360 | } | ||
361 | |||
362 | static void hal2_setup_dac(struct snd_hal2 *hal2) | ||
363 | { | ||
364 | unsigned int fifobeg, fifoend, highwater, sample_size; | ||
365 | struct hal2_pbus *pbus = &hal2->dac.pbus; | ||
366 | |||
367 | /* Now we set up some PBUS information. The PBUS needs information about | ||
368 | * what portion of the fifo it will use. If it's receiving or | ||
369 | * transmitting, and finally whether the stream is little endian or big | ||
370 | * endian. The information is written later, on the start call. | ||
371 | */ | ||
372 | sample_size = 2 * hal2->dac.voices; | ||
373 | /* Fifo should be set to hold exactly four samples. Highwater mark | ||
374 | * should be set to two samples. */ | ||
375 | highwater = (sample_size * 2) >> 1; /* halfwords */ | ||
376 | fifobeg = 0; /* playback is first */ | ||
377 | fifoend = (sample_size * 4) >> 3; /* doublewords */ | ||
378 | pbus->ctrl = HPC3_PDMACTRL_RT | HPC3_PDMACTRL_LD | | ||
379 | (highwater << 8) | (fifobeg << 16) | (fifoend << 24); | ||
380 | /* We disable everything before we do anything at all */ | ||
381 | pbus->pbus->pbdma_ctrl = HPC3_PDMACTRL_LD; | ||
382 | hal2_i_clearbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECTX); | ||
383 | /* Setup the HAL2 for playback */ | ||
384 | hal2_set_dac_rate(hal2); | ||
385 | /* Set endianess */ | ||
386 | hal2_i_clearbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECTX); | ||
387 | /* Set DMA bus */ | ||
388 | hal2_i_setbit16(hal2, H2I_DMA_DRV, (1 << pbus->pbusnr)); | ||
389 | /* We are using 1st Bresenham clock generator for playback */ | ||
390 | hal2_i_write16(hal2, H2I_DAC_C1, (pbus->pbusnr << H2I_C1_DMA_SHIFT) | ||
391 | | (1 << H2I_C1_CLKID_SHIFT) | ||
392 | | (hal2->dac.voices << H2I_C1_DATAT_SHIFT)); | ||
393 | } | ||
394 | |||
395 | static void hal2_setup_adc(struct snd_hal2 *hal2) | ||
396 | { | ||
397 | unsigned int fifobeg, fifoend, highwater, sample_size; | ||
398 | struct hal2_pbus *pbus = &hal2->adc.pbus; | ||
399 | |||
400 | sample_size = 2 * hal2->adc.voices; | ||
401 | highwater = (sample_size * 2) >> 1; /* halfwords */ | ||
402 | fifobeg = (4 * 4) >> 3; /* record is second */ | ||
403 | fifoend = (4 * 4 + sample_size * 4) >> 3; /* doublewords */ | ||
404 | pbus->ctrl = HPC3_PDMACTRL_RT | HPC3_PDMACTRL_RCV | HPC3_PDMACTRL_LD | | ||
405 | (highwater << 8) | (fifobeg << 16) | (fifoend << 24); | ||
406 | pbus->pbus->pbdma_ctrl = HPC3_PDMACTRL_LD; | ||
407 | hal2_i_clearbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECR); | ||
408 | /* Setup the HAL2 for record */ | ||
409 | hal2_set_adc_rate(hal2); | ||
410 | /* Set endianess */ | ||
411 | hal2_i_clearbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECR); | ||
412 | /* Set DMA bus */ | ||
413 | hal2_i_setbit16(hal2, H2I_DMA_DRV, (1 << pbus->pbusnr)); | ||
414 | /* We are using 2nd Bresenham clock generator for record */ | ||
415 | hal2_i_write16(hal2, H2I_ADC_C1, (pbus->pbusnr << H2I_C1_DMA_SHIFT) | ||
416 | | (2 << H2I_C1_CLKID_SHIFT) | ||
417 | | (hal2->adc.voices << H2I_C1_DATAT_SHIFT)); | ||
418 | } | ||
419 | |||
420 | static void hal2_start_dac(struct snd_hal2 *hal2) | ||
421 | { | ||
422 | struct hal2_pbus *pbus = &hal2->dac.pbus; | ||
423 | |||
424 | pbus->pbus->pbdma_dptr = hal2->dac.desc_dma; | ||
425 | pbus->pbus->pbdma_ctrl = pbus->ctrl | HPC3_PDMACTRL_ACT; | ||
426 | /* enable DAC */ | ||
427 | hal2_i_setbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECTX); | ||
428 | } | ||
429 | |||
430 | static void hal2_start_adc(struct snd_hal2 *hal2) | ||
431 | { | ||
432 | struct hal2_pbus *pbus = &hal2->adc.pbus; | ||
433 | |||
434 | pbus->pbus->pbdma_dptr = hal2->adc.desc_dma; | ||
435 | pbus->pbus->pbdma_ctrl = pbus->ctrl | HPC3_PDMACTRL_ACT; | ||
436 | /* enable ADC */ | ||
437 | hal2_i_setbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECR); | ||
438 | } | ||
439 | |||
440 | static inline void hal2_stop_dac(struct snd_hal2 *hal2) | ||
441 | { | ||
442 | hal2->dac.pbus.pbus->pbdma_ctrl = HPC3_PDMACTRL_LD; | ||
443 | /* The HAL2 itself may remain enabled safely */ | ||
444 | } | ||
445 | |||
446 | static inline void hal2_stop_adc(struct snd_hal2 *hal2) | ||
447 | { | ||
448 | hal2->adc.pbus.pbus->pbdma_ctrl = HPC3_PDMACTRL_LD; | ||
449 | } | ||
450 | |||
451 | static int hal2_alloc_dmabuf(struct hal2_codec *codec) | ||
452 | { | ||
453 | struct hal2_desc *desc; | ||
454 | dma_addr_t desc_dma, buffer_dma; | ||
455 | int count = H2_BUF_SIZE / H2_BLOCK_SIZE; | ||
456 | int i; | ||
457 | |||
458 | codec->buffer = dma_alloc_noncoherent(NULL, H2_BUF_SIZE, | ||
459 | &buffer_dma, GFP_KERNEL); | ||
460 | if (!codec->buffer) | ||
461 | return -ENOMEM; | ||
462 | desc = dma_alloc_noncoherent(NULL, count * sizeof(struct hal2_desc), | ||
463 | &desc_dma, GFP_KERNEL); | ||
464 | if (!desc) { | ||
465 | dma_free_noncoherent(NULL, H2_BUF_SIZE, | ||
466 | codec->buffer, buffer_dma); | ||
467 | return -ENOMEM; | ||
468 | } | ||
469 | codec->buffer_dma = buffer_dma; | ||
470 | codec->desc_dma = desc_dma; | ||
471 | codec->desc = desc; | ||
472 | for (i = 0; i < count; i++) { | ||
473 | desc->desc.pbuf = buffer_dma + i * H2_BLOCK_SIZE; | ||
474 | desc->desc.cntinfo = HPCDMA_XIE | H2_BLOCK_SIZE; | ||
475 | desc->desc.pnext = (i == count - 1) ? | ||
476 | desc_dma : desc_dma + (i + 1) * sizeof(struct hal2_desc); | ||
477 | desc++; | ||
478 | } | ||
479 | dma_cache_sync(NULL, codec->desc, count * sizeof(struct hal2_desc), | ||
480 | DMA_TO_DEVICE); | ||
481 | codec->desc_count = count; | ||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | static void hal2_free_dmabuf(struct hal2_codec *codec) | ||
486 | { | ||
487 | dma_free_noncoherent(NULL, codec->desc_count * sizeof(struct hal2_desc), | ||
488 | codec->desc, codec->desc_dma); | ||
489 | dma_free_noncoherent(NULL, H2_BUF_SIZE, codec->buffer, | ||
490 | codec->buffer_dma); | ||
491 | } | ||
492 | |||
493 | static struct snd_pcm_hardware hal2_pcm_hw = { | ||
494 | .info = (SNDRV_PCM_INFO_MMAP | | ||
495 | SNDRV_PCM_INFO_MMAP_VALID | | ||
496 | SNDRV_PCM_INFO_INTERLEAVED | | ||
497 | SNDRV_PCM_INFO_BLOCK_TRANSFER), | ||
498 | .formats = SNDRV_PCM_FMTBIT_S16_BE, | ||
499 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
500 | .rate_min = 8000, | ||
501 | .rate_max = 48000, | ||
502 | .channels_min = 2, | ||
503 | .channels_max = 2, | ||
504 | .buffer_bytes_max = 65536, | ||
505 | .period_bytes_min = 1024, | ||
506 | .period_bytes_max = 65536, | ||
507 | .periods_min = 2, | ||
508 | .periods_max = 1024, | ||
509 | }; | ||
510 | |||
511 | static int hal2_pcm_hw_params(struct snd_pcm_substream *substream, | ||
512 | struct snd_pcm_hw_params *params) | ||
513 | { | ||
514 | int err; | ||
515 | |||
516 | err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); | ||
517 | if (err < 0) | ||
518 | return err; | ||
519 | |||
520 | return 0; | ||
521 | } | ||
522 | |||
523 | static int hal2_pcm_hw_free(struct snd_pcm_substream *substream) | ||
524 | { | ||
525 | return snd_pcm_lib_free_pages(substream); | ||
526 | } | ||
527 | |||
528 | static int hal2_playback_open(struct snd_pcm_substream *substream) | ||
529 | { | ||
530 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
531 | struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); | ||
532 | int err; | ||
533 | |||
534 | runtime->hw = hal2_pcm_hw; | ||
535 | |||
536 | err = hal2_alloc_dmabuf(&hal2->dac); | ||
537 | if (err) | ||
538 | return err; | ||
539 | return 0; | ||
540 | } | ||
541 | |||
542 | static int hal2_playback_close(struct snd_pcm_substream *substream) | ||
543 | { | ||
544 | struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); | ||
545 | |||
546 | hal2_free_dmabuf(&hal2->dac); | ||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | static int hal2_playback_prepare(struct snd_pcm_substream *substream) | ||
551 | { | ||
552 | struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); | ||
553 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
554 | struct hal2_codec *dac = &hal2->dac; | ||
555 | |||
556 | dac->voices = runtime->channels; | ||
557 | dac->sample_rate = hal2_compute_rate(dac, runtime->rate); | ||
558 | memset(&dac->pcm_indirect, 0, sizeof(dac->pcm_indirect)); | ||
559 | dac->pcm_indirect.hw_buffer_size = H2_BUF_SIZE; | ||
560 | dac->pcm_indirect.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream); | ||
561 | dac->substream = substream; | ||
562 | hal2_setup_dac(hal2); | ||
563 | return 0; | ||
564 | } | ||
565 | |||
566 | static int hal2_playback_trigger(struct snd_pcm_substream *substream, int cmd) | ||
567 | { | ||
568 | struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); | ||
569 | |||
570 | switch (cmd) { | ||
571 | case SNDRV_PCM_TRIGGER_START: | ||
572 | hal2->dac.pcm_indirect.hw_io = hal2->dac.buffer_dma; | ||
573 | hal2->dac.pcm_indirect.hw_data = 0; | ||
574 | substream->ops->ack(substream); | ||
575 | hal2_start_dac(hal2); | ||
576 | break; | ||
577 | case SNDRV_PCM_TRIGGER_STOP: | ||
578 | hal2_stop_dac(hal2); | ||
579 | break; | ||
580 | default: | ||
581 | return -EINVAL; | ||
582 | } | ||
583 | return 0; | ||
584 | } | ||
585 | |||
586 | static snd_pcm_uframes_t | ||
587 | hal2_playback_pointer(struct snd_pcm_substream *substream) | ||
588 | { | ||
589 | struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); | ||
590 | struct hal2_codec *dac = &hal2->dac; | ||
591 | |||
592 | return snd_pcm_indirect_playback_pointer(substream, &dac->pcm_indirect, | ||
593 | dac->pbus.pbus->pbdma_bptr); | ||
594 | } | ||
595 | |||
596 | static void hal2_playback_transfer(struct snd_pcm_substream *substream, | ||
597 | struct snd_pcm_indirect *rec, size_t bytes) | ||
598 | { | ||
599 | struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); | ||
600 | unsigned char *buf = hal2->dac.buffer + rec->hw_data; | ||
601 | |||
602 | memcpy(buf, substream->runtime->dma_area + rec->sw_data, bytes); | ||
603 | dma_cache_sync(NULL, buf, bytes, DMA_TO_DEVICE); | ||
604 | |||
605 | } | ||
606 | |||
607 | static int hal2_playback_ack(struct snd_pcm_substream *substream) | ||
608 | { | ||
609 | struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); | ||
610 | struct hal2_codec *dac = &hal2->dac; | ||
611 | |||
612 | dac->pcm_indirect.hw_queue_size = H2_BUF_SIZE / 2; | ||
613 | snd_pcm_indirect_playback_transfer(substream, | ||
614 | &dac->pcm_indirect, | ||
615 | hal2_playback_transfer); | ||
616 | return 0; | ||
617 | } | ||
618 | |||
619 | static int hal2_capture_open(struct snd_pcm_substream *substream) | ||
620 | { | ||
621 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
622 | struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); | ||
623 | struct hal2_codec *adc = &hal2->adc; | ||
624 | int err; | ||
625 | |||
626 | runtime->hw = hal2_pcm_hw; | ||
627 | |||
628 | err = hal2_alloc_dmabuf(adc); | ||
629 | if (err) | ||
630 | return err; | ||
631 | return 0; | ||
632 | } | ||
633 | |||
634 | static int hal2_capture_close(struct snd_pcm_substream *substream) | ||
635 | { | ||
636 | struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); | ||
637 | |||
638 | hal2_free_dmabuf(&hal2->adc); | ||
639 | return 0; | ||
640 | } | ||
641 | |||
642 | static int hal2_capture_prepare(struct snd_pcm_substream *substream) | ||
643 | { | ||
644 | struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); | ||
645 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
646 | struct hal2_codec *adc = &hal2->adc; | ||
647 | |||
648 | adc->voices = runtime->channels; | ||
649 | adc->sample_rate = hal2_compute_rate(adc, runtime->rate); | ||
650 | memset(&adc->pcm_indirect, 0, sizeof(adc->pcm_indirect)); | ||
651 | adc->pcm_indirect.hw_buffer_size = H2_BUF_SIZE; | ||
652 | adc->pcm_indirect.hw_queue_size = H2_BUF_SIZE / 2; | ||
653 | adc->pcm_indirect.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream); | ||
654 | adc->substream = substream; | ||
655 | hal2_setup_adc(hal2); | ||
656 | return 0; | ||
657 | } | ||
658 | |||
659 | static int hal2_capture_trigger(struct snd_pcm_substream *substream, int cmd) | ||
660 | { | ||
661 | struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); | ||
662 | |||
663 | switch (cmd) { | ||
664 | case SNDRV_PCM_TRIGGER_START: | ||
665 | hal2->adc.pcm_indirect.hw_io = hal2->adc.buffer_dma; | ||
666 | hal2->adc.pcm_indirect.hw_data = 0; | ||
667 | printk(KERN_DEBUG "buffer_dma %x\n", hal2->adc.buffer_dma); | ||
668 | hal2_start_adc(hal2); | ||
669 | break; | ||
670 | case SNDRV_PCM_TRIGGER_STOP: | ||
671 | hal2_stop_adc(hal2); | ||
672 | break; | ||
673 | default: | ||
674 | return -EINVAL; | ||
675 | } | ||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | static snd_pcm_uframes_t | ||
680 | hal2_capture_pointer(struct snd_pcm_substream *substream) | ||
681 | { | ||
682 | struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); | ||
683 | struct hal2_codec *adc = &hal2->adc; | ||
684 | |||
685 | return snd_pcm_indirect_capture_pointer(substream, &adc->pcm_indirect, | ||
686 | adc->pbus.pbus->pbdma_bptr); | ||
687 | } | ||
688 | |||
689 | static void hal2_capture_transfer(struct snd_pcm_substream *substream, | ||
690 | struct snd_pcm_indirect *rec, size_t bytes) | ||
691 | { | ||
692 | struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); | ||
693 | unsigned char *buf = hal2->adc.buffer + rec->hw_data; | ||
694 | |||
695 | dma_cache_sync(NULL, buf, bytes, DMA_FROM_DEVICE); | ||
696 | memcpy(substream->runtime->dma_area + rec->sw_data, buf, bytes); | ||
697 | } | ||
698 | |||
699 | static int hal2_capture_ack(struct snd_pcm_substream *substream) | ||
700 | { | ||
701 | struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream); | ||
702 | struct hal2_codec *adc = &hal2->adc; | ||
703 | |||
704 | snd_pcm_indirect_capture_transfer(substream, | ||
705 | &adc->pcm_indirect, | ||
706 | hal2_capture_transfer); | ||
707 | return 0; | ||
708 | } | ||
709 | |||
710 | static struct snd_pcm_ops hal2_playback_ops = { | ||
711 | .open = hal2_playback_open, | ||
712 | .close = hal2_playback_close, | ||
713 | .ioctl = snd_pcm_lib_ioctl, | ||
714 | .hw_params = hal2_pcm_hw_params, | ||
715 | .hw_free = hal2_pcm_hw_free, | ||
716 | .prepare = hal2_playback_prepare, | ||
717 | .trigger = hal2_playback_trigger, | ||
718 | .pointer = hal2_playback_pointer, | ||
719 | .ack = hal2_playback_ack, | ||
720 | }; | ||
721 | |||
722 | static struct snd_pcm_ops hal2_capture_ops = { | ||
723 | .open = hal2_capture_open, | ||
724 | .close = hal2_capture_close, | ||
725 | .ioctl = snd_pcm_lib_ioctl, | ||
726 | .hw_params = hal2_pcm_hw_params, | ||
727 | .hw_free = hal2_pcm_hw_free, | ||
728 | .prepare = hal2_capture_prepare, | ||
729 | .trigger = hal2_capture_trigger, | ||
730 | .pointer = hal2_capture_pointer, | ||
731 | .ack = hal2_capture_ack, | ||
732 | }; | ||
733 | |||
734 | static int __devinit hal2_pcm_create(struct snd_hal2 *hal2) | ||
735 | { | ||
736 | struct snd_pcm *pcm; | ||
737 | int err; | ||
738 | |||
739 | /* create first pcm device with one outputs and one input */ | ||
740 | err = snd_pcm_new(hal2->card, "SGI HAL2 Audio", 0, 1, 1, &pcm); | ||
741 | if (err < 0) | ||
742 | return err; | ||
743 | |||
744 | pcm->private_data = hal2; | ||
745 | strcpy(pcm->name, "SGI HAL2"); | ||
746 | |||
747 | /* set operators */ | ||
748 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, | ||
749 | &hal2_playback_ops); | ||
750 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, | ||
751 | &hal2_capture_ops); | ||
752 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, | ||
753 | snd_dma_continuous_data(GFP_KERNEL), | ||
754 | 0, 1024 * 1024); | ||
755 | |||
756 | return 0; | ||
757 | } | ||
758 | |||
759 | static int hal2_dev_free(struct snd_device *device) | ||
760 | { | ||
761 | struct snd_hal2 *hal2 = device->device_data; | ||
762 | |||
763 | free_irq(SGI_HPCDMA_IRQ, hal2); | ||
764 | kfree(hal2); | ||
765 | return 0; | ||
766 | } | ||
767 | |||
768 | static struct snd_device_ops hal2_ops = { | ||
769 | .dev_free = hal2_dev_free, | ||
770 | }; | ||
771 | |||
772 | static void hal2_init_codec(struct hal2_codec *codec, struct hpc3_regs *hpc3, | ||
773 | int index) | ||
774 | { | ||
775 | codec->pbus.pbusnr = index; | ||
776 | codec->pbus.pbus = &hpc3->pbdma[index]; | ||
777 | } | ||
778 | |||
779 | static int hal2_detect(struct snd_hal2 *hal2) | ||
780 | { | ||
781 | unsigned short board, major, minor; | ||
782 | unsigned short rev; | ||
783 | |||
784 | /* reset HAL2 */ | ||
785 | hal2_write(0, &hal2->ctl_regs->isr); | ||
786 | |||
787 | /* release reset */ | ||
788 | hal2_write(H2_ISR_GLOBAL_RESET_N | H2_ISR_CODEC_RESET_N, | ||
789 | &hal2->ctl_regs->isr); | ||
790 | |||
791 | |||
792 | hal2_i_write16(hal2, H2I_RELAY_C, H2I_RELAY_C_STATE); | ||
793 | rev = hal2_read(&hal2->ctl_regs->rev); | ||
794 | if (rev & H2_REV_AUDIO_PRESENT) | ||
795 | return -ENODEV; | ||
796 | |||
797 | board = (rev & H2_REV_BOARD_M) >> 12; | ||
798 | major = (rev & H2_REV_MAJOR_CHIP_M) >> 4; | ||
799 | minor = (rev & H2_REV_MINOR_CHIP_M); | ||
800 | |||
801 | printk(KERN_INFO "SGI HAL2 revision %i.%i.%i\n", | ||
802 | board, major, minor); | ||
803 | |||
804 | return 0; | ||
805 | } | ||
806 | |||
807 | static int hal2_create(struct snd_card *card, struct snd_hal2 **rchip) | ||
808 | { | ||
809 | struct snd_hal2 *hal2; | ||
810 | struct hpc3_regs *hpc3 = hpc3c0; | ||
811 | int err; | ||
812 | |||
813 | hal2 = kzalloc(sizeof(struct snd_hal2), GFP_KERNEL); | ||
814 | if (!hal2) | ||
815 | return -ENOMEM; | ||
816 | |||
817 | hal2->card = card; | ||
818 | |||
819 | if (request_irq(SGI_HPCDMA_IRQ, hal2_interrupt, IRQF_SHARED, | ||
820 | "SGI HAL2", hal2)) { | ||
821 | printk(KERN_ERR "HAL2: Can't get irq %d\n", SGI_HPCDMA_IRQ); | ||
822 | kfree(hal2); | ||
823 | return -EAGAIN; | ||
824 | } | ||
825 | |||
826 | hal2->ctl_regs = (struct hal2_ctl_regs *)hpc3->pbus_extregs[0]; | ||
827 | hal2->aes_regs = (struct hal2_aes_regs *)hpc3->pbus_extregs[1]; | ||
828 | hal2->vol_regs = (struct hal2_vol_regs *)hpc3->pbus_extregs[2]; | ||
829 | hal2->syn_regs = (struct hal2_syn_regs *)hpc3->pbus_extregs[3]; | ||
830 | |||
831 | if (hal2_detect(hal2) < 0) { | ||
832 | kfree(hal2); | ||
833 | return -ENODEV; | ||
834 | } | ||
835 | |||
836 | hal2_init_codec(&hal2->dac, hpc3, 0); | ||
837 | hal2_init_codec(&hal2->adc, hpc3, 1); | ||
838 | |||
839 | /* | ||
840 | * All DMA channel interfaces in HAL2 are designed to operate with | ||
841 | * PBUS programmed for 2 cycles in D3, 2 cycles in D4 and 2 cycles | ||
842 | * in D5. HAL2 is a 16-bit device which can accept both big and little | ||
843 | * endian format. It assumes that even address bytes are on high | ||
844 | * portion of PBUS (15:8) and assumes that HPC3 is programmed to | ||
845 | * accept a live (unsynchronized) version of P_DREQ_N from HAL2. | ||
846 | */ | ||
847 | #define HAL2_PBUS_DMACFG ((0 << HPC3_DMACFG_D3R_SHIFT) | \ | ||
848 | (2 << HPC3_DMACFG_D4R_SHIFT) | \ | ||
849 | (2 << HPC3_DMACFG_D5R_SHIFT) | \ | ||
850 | (0 << HPC3_DMACFG_D3W_SHIFT) | \ | ||
851 | (2 << HPC3_DMACFG_D4W_SHIFT) | \ | ||
852 | (2 << HPC3_DMACFG_D5W_SHIFT) | \ | ||
853 | HPC3_DMACFG_DS16 | \ | ||
854 | HPC3_DMACFG_EVENHI | \ | ||
855 | HPC3_DMACFG_RTIME | \ | ||
856 | (8 << HPC3_DMACFG_BURST_SHIFT) | \ | ||
857 | HPC3_DMACFG_DRQLIVE) | ||
858 | /* | ||
859 | * Ignore what's mentioned in the specification and write value which | ||
860 | * works in The Real World (TM) | ||
861 | */ | ||
862 | hpc3->pbus_dmacfg[hal2->dac.pbus.pbusnr][0] = 0x8208844; | ||
863 | hpc3->pbus_dmacfg[hal2->adc.pbus.pbusnr][0] = 0x8208844; | ||
864 | |||
865 | err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, hal2, &hal2_ops); | ||
866 | if (err < 0) { | ||
867 | free_irq(SGI_HPCDMA_IRQ, hal2); | ||
868 | kfree(hal2); | ||
869 | return err; | ||
870 | } | ||
871 | *rchip = hal2; | ||
872 | return 0; | ||
873 | } | ||
874 | |||
875 | static int __devinit hal2_probe(struct platform_device *pdev) | ||
876 | { | ||
877 | struct snd_card *card; | ||
878 | struct snd_hal2 *chip; | ||
879 | int err; | ||
880 | |||
881 | card = snd_card_new(index, id, THIS_MODULE, 0); | ||
882 | if (card == NULL) | ||
883 | return -ENOMEM; | ||
884 | |||
885 | err = hal2_create(card, &chip); | ||
886 | if (err < 0) { | ||
887 | snd_card_free(card); | ||
888 | return err; | ||
889 | } | ||
890 | snd_card_set_dev(card, &pdev->dev); | ||
891 | |||
892 | err = hal2_pcm_create(chip); | ||
893 | if (err < 0) { | ||
894 | snd_card_free(card); | ||
895 | return err; | ||
896 | } | ||
897 | err = hal2_mixer_create(chip); | ||
898 | if (err < 0) { | ||
899 | snd_card_free(card); | ||
900 | return err; | ||
901 | } | ||
902 | |||
903 | strcpy(card->driver, "SGI HAL2 Audio"); | ||
904 | strcpy(card->shortname, "SGI HAL2 Audio"); | ||
905 | sprintf(card->longname, "%s irq %i", | ||
906 | card->shortname, | ||
907 | SGI_HPCDMA_IRQ); | ||
908 | |||
909 | err = snd_card_register(card); | ||
910 | if (err < 0) { | ||
911 | snd_card_free(card); | ||
912 | return err; | ||
913 | } | ||
914 | platform_set_drvdata(pdev, card); | ||
915 | return 0; | ||
916 | } | ||
917 | |||
918 | static int __exit hal2_remove(struct platform_device *pdev) | ||
919 | { | ||
920 | struct snd_card *card = platform_get_drvdata(pdev); | ||
921 | |||
922 | snd_card_free(card); | ||
923 | platform_set_drvdata(pdev, NULL); | ||
924 | return 0; | ||
925 | } | ||
926 | |||
927 | static struct platform_driver hal2_driver = { | ||
928 | .probe = hal2_probe, | ||
929 | .remove = __devexit_p(hal2_remove), | ||
930 | .driver = { | ||
931 | .name = "sgihal2", | ||
932 | .owner = THIS_MODULE, | ||
933 | } | ||
934 | }; | ||
935 | |||
936 | static int __init alsa_card_hal2_init(void) | ||
937 | { | ||
938 | return platform_driver_register(&hal2_driver); | ||
939 | } | ||
940 | |||
941 | static void __exit alsa_card_hal2_exit(void) | ||
942 | { | ||
943 | platform_driver_unregister(&hal2_driver); | ||
944 | } | ||
945 | |||
946 | module_init(alsa_card_hal2_init); | ||
947 | module_exit(alsa_card_hal2_exit); | ||
diff --git a/sound/mips/hal2.h b/sound/mips/hal2.h new file mode 100644 index 000000000000..f19828bc64e0 --- /dev/null +++ b/sound/mips/hal2.h | |||
@@ -0,0 +1,245 @@ | |||
1 | #ifndef __HAL2_H | ||
2 | #define __HAL2_H | ||
3 | |||
4 | /* | ||
5 | * Driver for HAL2 sound processors | ||
6 | * Copyright (c) 1999 Ulf Carlsson <ulfc@bun.falkenberg.se> | ||
7 | * Copyright (c) 2001, 2002, 2003 Ladislav Michl <ladis@linux-mips.org> | ||
8 | * | ||
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 | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/types.h> | ||
25 | |||
26 | /* Indirect status register */ | ||
27 | |||
28 | #define H2_ISR_TSTATUS 0x01 /* RO: transaction status 1=busy */ | ||
29 | #define H2_ISR_USTATUS 0x02 /* RO: utime status bit 1=armed */ | ||
30 | #define H2_ISR_QUAD_MODE 0x04 /* codec mode 0=indigo 1=quad */ | ||
31 | #define H2_ISR_GLOBAL_RESET_N 0x08 /* chip global reset 0=reset */ | ||
32 | #define H2_ISR_CODEC_RESET_N 0x10 /* codec/synth reset 0=reset */ | ||
33 | |||
34 | /* Revision register */ | ||
35 | |||
36 | #define H2_REV_AUDIO_PRESENT 0x8000 /* RO: audio present 0=present */ | ||
37 | #define H2_REV_BOARD_M 0x7000 /* RO: bits 14:12, board revision */ | ||
38 | #define H2_REV_MAJOR_CHIP_M 0x00F0 /* RO: bits 7:4, major chip revision */ | ||
39 | #define H2_REV_MINOR_CHIP_M 0x000F /* RO: bits 3:0, minor chip revision */ | ||
40 | |||
41 | /* Indirect address register */ | ||
42 | |||
43 | /* | ||
44 | * Address of indirect internal register to be accessed. A write to this | ||
45 | * register initiates read or write access to the indirect registers in the | ||
46 | * HAL2. Note that there af four indirect data registers for write access to | ||
47 | * registers larger than 16 byte. | ||
48 | */ | ||
49 | |||
50 | #define H2_IAR_TYPE_M 0xF000 /* bits 15:12, type of functional */ | ||
51 | /* block the register resides in */ | ||
52 | /* 1=DMA Port */ | ||
53 | /* 9=Global DMA Control */ | ||
54 | /* 2=Bresenham */ | ||
55 | /* 3=Unix Timer */ | ||
56 | #define H2_IAR_NUM_M 0x0F00 /* bits 11:8 instance of the */ | ||
57 | /* blockin which the indirect */ | ||
58 | /* register resides */ | ||
59 | /* If IAR_TYPE_M=DMA Port: */ | ||
60 | /* 1=Synth In */ | ||
61 | /* 2=AES In */ | ||
62 | /* 3=AES Out */ | ||
63 | /* 4=DAC Out */ | ||
64 | /* 5=ADC Out */ | ||
65 | /* 6=Synth Control */ | ||
66 | /* If IAR_TYPE_M=Global DMA Control: */ | ||
67 | /* 1=Control */ | ||
68 | /* If IAR_TYPE_M=Bresenham: */ | ||
69 | /* 1=Bresenham Clock Gen 1 */ | ||
70 | /* 2=Bresenham Clock Gen 2 */ | ||
71 | /* 3=Bresenham Clock Gen 3 */ | ||
72 | /* If IAR_TYPE_M=Unix Timer: */ | ||
73 | /* 1=Unix Timer */ | ||
74 | #define H2_IAR_ACCESS_SELECT 0x0080 /* 1=read 0=write */ | ||
75 | #define H2_IAR_PARAM 0x000C /* Parameter Select */ | ||
76 | #define H2_IAR_RB_INDEX_M 0x0003 /* Read Back Index */ | ||
77 | /* 00:word0 */ | ||
78 | /* 01:word1 */ | ||
79 | /* 10:word2 */ | ||
80 | /* 11:word3 */ | ||
81 | /* | ||
82 | * HAL2 internal addressing | ||
83 | * | ||
84 | * The HAL2 has "indirect registers" (idr) which are accessed by writing to the | ||
85 | * Indirect Data registers. Write the address to the Indirect Address register | ||
86 | * to transfer the data. | ||
87 | * | ||
88 | * We define the H2IR_* to the read address and H2IW_* to the write address and | ||
89 | * H2I_* to be fields in whatever register is referred to. | ||
90 | * | ||
91 | * When we write to indirect registers which are larger than one word (16 bit) | ||
92 | * we have to fill more than one indirect register before writing. When we read | ||
93 | * back however we have to read several times, each time with different Read | ||
94 | * Back Indexes (there are defs for doing this easily). | ||
95 | */ | ||
96 | |||
97 | /* | ||
98 | * Relay Control | ||
99 | */ | ||
100 | #define H2I_RELAY_C 0x9100 | ||
101 | #define H2I_RELAY_C_STATE 0x01 /* state of RELAY pin signal */ | ||
102 | |||
103 | /* DMA port enable */ | ||
104 | |||
105 | #define H2I_DMA_PORT_EN 0x9104 | ||
106 | #define H2I_DMA_PORT_EN_SY_IN 0x01 /* Synth_in DMA port */ | ||
107 | #define H2I_DMA_PORT_EN_AESRX 0x02 /* AES receiver DMA port */ | ||
108 | #define H2I_DMA_PORT_EN_AESTX 0x04 /* AES transmitter DMA port */ | ||
109 | #define H2I_DMA_PORT_EN_CODECTX 0x08 /* CODEC transmit DMA port */ | ||
110 | #define H2I_DMA_PORT_EN_CODECR 0x10 /* CODEC receive DMA port */ | ||
111 | |||
112 | #define H2I_DMA_END 0x9108 /* global dma endian select */ | ||
113 | #define H2I_DMA_END_SY_IN 0x01 /* Synth_in DMA port */ | ||
114 | #define H2I_DMA_END_AESRX 0x02 /* AES receiver DMA port */ | ||
115 | #define H2I_DMA_END_AESTX 0x04 /* AES transmitter DMA port */ | ||
116 | #define H2I_DMA_END_CODECTX 0x08 /* CODEC transmit DMA port */ | ||
117 | #define H2I_DMA_END_CODECR 0x10 /* CODEC receive DMA port */ | ||
118 | /* 0=b_end 1=l_end */ | ||
119 | |||
120 | #define H2I_DMA_DRV 0x910C /* global PBUS DMA enable */ | ||
121 | |||
122 | #define H2I_SYNTH_C 0x1104 /* Synth DMA control */ | ||
123 | |||
124 | #define H2I_AESRX_C 0x1204 /* AES RX dma control */ | ||
125 | |||
126 | #define H2I_C_TS_EN 0x20 /* Timestamp enable */ | ||
127 | #define H2I_C_TS_FRMT 0x40 /* Timestamp format */ | ||
128 | #define H2I_C_NAUDIO 0x80 /* Sign extend */ | ||
129 | |||
130 | /* AESRX CTL, 16 bit */ | ||
131 | |||
132 | #define H2I_AESTX_C 0x1304 /* AES TX DMA control */ | ||
133 | #define H2I_AESTX_C_CLKID_SHIFT 3 /* Bresenham Clock Gen 1-3 */ | ||
134 | #define H2I_AESTX_C_CLKID_M 0x18 | ||
135 | #define H2I_AESTX_C_DATAT_SHIFT 8 /* 1=mono 2=stereo (3=quad) */ | ||
136 | #define H2I_AESTX_C_DATAT_M 0x300 | ||
137 | |||
138 | /* CODEC registers */ | ||
139 | |||
140 | #define H2I_DAC_C1 0x1404 /* DAC DMA control, 16 bit */ | ||
141 | #define H2I_DAC_C2 0x1408 /* DAC DMA control, 32 bit */ | ||
142 | #define H2I_ADC_C1 0x1504 /* ADC DMA control, 16 bit */ | ||
143 | #define H2I_ADC_C2 0x1508 /* ADC DMA control, 32 bit */ | ||
144 | |||
145 | /* Bits in CTL1 register */ | ||
146 | |||
147 | #define H2I_C1_DMA_SHIFT 0 /* DMA channel */ | ||
148 | #define H2I_C1_DMA_M 0x7 | ||
149 | #define H2I_C1_CLKID_SHIFT 3 /* Bresenham Clock Gen 1-3 */ | ||
150 | #define H2I_C1_CLKID_M 0x18 | ||
151 | #define H2I_C1_DATAT_SHIFT 8 /* 1=mono 2=stereo (3=quad) */ | ||
152 | #define H2I_C1_DATAT_M 0x300 | ||
153 | |||
154 | /* Bits in CTL2 register */ | ||
155 | |||
156 | #define H2I_C2_R_GAIN_SHIFT 0 /* right a/d input gain */ | ||
157 | #define H2I_C2_R_GAIN_M 0xf | ||
158 | #define H2I_C2_L_GAIN_SHIFT 4 /* left a/d input gain */ | ||
159 | #define H2I_C2_L_GAIN_M 0xf0 | ||
160 | #define H2I_C2_R_SEL 0x100 /* right input select */ | ||
161 | #define H2I_C2_L_SEL 0x200 /* left input select */ | ||
162 | #define H2I_C2_MUTE 0x400 /* mute */ | ||
163 | #define H2I_C2_DO1 0x00010000 /* digital output port bit 0 */ | ||
164 | #define H2I_C2_DO2 0x00020000 /* digital output port bit 1 */ | ||
165 | #define H2I_C2_R_ATT_SHIFT 18 /* right d/a output - */ | ||
166 | #define H2I_C2_R_ATT_M 0x007c0000 /* attenuation */ | ||
167 | #define H2I_C2_L_ATT_SHIFT 23 /* left d/a output - */ | ||
168 | #define H2I_C2_L_ATT_M 0x0f800000 /* attenuation */ | ||
169 | |||
170 | #define H2I_SYNTH_MAP_C 0x1104 /* synth dma handshake ctrl */ | ||
171 | |||
172 | /* Clock generator CTL 1, 16 bit */ | ||
173 | |||
174 | #define H2I_BRES1_C1 0x2104 | ||
175 | #define H2I_BRES2_C1 0x2204 | ||
176 | #define H2I_BRES3_C1 0x2304 | ||
177 | |||
178 | #define H2I_BRES_C1_SHIFT 0 /* 0=48.0 1=44.1 2=aes_rx */ | ||
179 | #define H2I_BRES_C1_M 0x03 | ||
180 | |||
181 | /* Clock generator CTL 2, 32 bit */ | ||
182 | |||
183 | #define H2I_BRES1_C2 0x2108 | ||
184 | #define H2I_BRES2_C2 0x2208 | ||
185 | #define H2I_BRES3_C2 0x2308 | ||
186 | |||
187 | #define H2I_BRES_C2_INC_SHIFT 0 /* increment value */ | ||
188 | #define H2I_BRES_C2_INC_M 0xffff | ||
189 | #define H2I_BRES_C2_MOD_SHIFT 16 /* modcontrol value */ | ||
190 | #define H2I_BRES_C2_MOD_M 0xffff0000 /* modctrl=0xffff&(modinc-1) */ | ||
191 | |||
192 | /* Unix timer, 64 bit */ | ||
193 | |||
194 | #define H2I_UTIME 0x3104 | ||
195 | #define H2I_UTIME_0_LD 0xffff /* microseconds, LSB's */ | ||
196 | #define H2I_UTIME_1_LD0 0x0f /* microseconds, MSB's */ | ||
197 | #define H2I_UTIME_1_LD1 0xf0 /* tenths of microseconds */ | ||
198 | #define H2I_UTIME_2_LD 0xffff /* seconds, LSB's */ | ||
199 | #define H2I_UTIME_3_LD 0xffff /* seconds, MSB's */ | ||
200 | |||
201 | struct hal2_ctl_regs { | ||
202 | u32 _unused0[4]; | ||
203 | u32 isr; /* 0x10 Status Register */ | ||
204 | u32 _unused1[3]; | ||
205 | u32 rev; /* 0x20 Revision Register */ | ||
206 | u32 _unused2[3]; | ||
207 | u32 iar; /* 0x30 Indirect Address Register */ | ||
208 | u32 _unused3[3]; | ||
209 | u32 idr0; /* 0x40 Indirect Data Register 0 */ | ||
210 | u32 _unused4[3]; | ||
211 | u32 idr1; /* 0x50 Indirect Data Register 1 */ | ||
212 | u32 _unused5[3]; | ||
213 | u32 idr2; /* 0x60 Indirect Data Register 2 */ | ||
214 | u32 _unused6[3]; | ||
215 | u32 idr3; /* 0x70 Indirect Data Register 3 */ | ||
216 | }; | ||
217 | |||
218 | struct hal2_aes_regs { | ||
219 | u32 rx_stat[2]; /* Status registers */ | ||
220 | u32 rx_cr[2]; /* Control registers */ | ||
221 | u32 rx_ud[4]; /* User data window */ | ||
222 | u32 rx_st[24]; /* Channel status data */ | ||
223 | |||
224 | u32 tx_stat[1]; /* Status register */ | ||
225 | u32 tx_cr[3]; /* Control registers */ | ||
226 | u32 tx_ud[4]; /* User data window */ | ||
227 | u32 tx_st[24]; /* Channel status data */ | ||
228 | }; | ||
229 | |||
230 | struct hal2_vol_regs { | ||
231 | u32 right; /* Right volume */ | ||
232 | u32 left; /* Left volume */ | ||
233 | }; | ||
234 | |||
235 | struct hal2_syn_regs { | ||
236 | u32 _unused0[2]; | ||
237 | u32 page; /* DOC Page register */ | ||
238 | u32 regsel; /* DOC Register selection */ | ||
239 | u32 dlow; /* DOC Data low */ | ||
240 | u32 dhigh; /* DOC Data high */ | ||
241 | u32 irq; /* IRQ Status */ | ||
242 | u32 dram; /* DRAM Access */ | ||
243 | }; | ||
244 | |||
245 | #endif /* __HAL2_H */ | ||
diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c new file mode 100644 index 000000000000..4c63504348dc --- /dev/null +++ b/sound/mips/sgio2audio.c | |||
@@ -0,0 +1,1006 @@ | |||
1 | /* | ||
2 | * Sound driver for Silicon Graphics O2 Workstations A/V board audio. | ||
3 | * | ||
4 | * Copyright 2003 Vivien Chappelier <vivien.chappelier@linux-mips.org> | ||
5 | * Copyright 2008 Thomas Bogendoerfer <tsbogend@alpha.franken.de> | ||
6 | * Mxier part taken from mace_audio.c: | ||
7 | * Copyright 2007 Thorben Jändling <tj.trevelyan@gmail.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include <linux/init.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/spinlock.h> | ||
28 | #include <linux/gfp.h> | ||
29 | #include <linux/vmalloc.h> | ||
30 | #include <linux/interrupt.h> | ||
31 | #include <linux/dma-mapping.h> | ||
32 | #include <linux/platform_device.h> | ||
33 | #include <linux/io.h> | ||
34 | |||
35 | #include <asm/ip32/ip32_ints.h> | ||
36 | #include <asm/ip32/mace.h> | ||
37 | |||
38 | #include <sound/core.h> | ||
39 | #include <sound/control.h> | ||
40 | #include <sound/pcm.h> | ||
41 | #define SNDRV_GET_ID | ||
42 | #include <sound/initval.h> | ||
43 | #include <sound/ad1843.h> | ||
44 | |||
45 | |||
46 | MODULE_AUTHOR("Vivien Chappelier <vivien.chappelier@linux-mips.org>"); | ||
47 | MODULE_DESCRIPTION("SGI O2 Audio"); | ||
48 | MODULE_LICENSE("GPL"); | ||
49 | MODULE_SUPPORTED_DEVICE("{{Silicon Graphics, O2 Audio}}"); | ||
50 | |||
51 | static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ | ||
52 | static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ | ||
53 | |||
54 | module_param(index, int, 0444); | ||
55 | MODULE_PARM_DESC(index, "Index value for SGI O2 soundcard."); | ||
56 | module_param(id, charp, 0444); | ||
57 | MODULE_PARM_DESC(id, "ID string for SGI O2 soundcard."); | ||
58 | |||
59 | |||
60 | #define AUDIO_CONTROL_RESET BIT(0) /* 1: reset audio interface */ | ||
61 | #define AUDIO_CONTROL_CODEC_PRESENT BIT(1) /* 1: codec detected */ | ||
62 | |||
63 | #define CODEC_CONTROL_WORD_SHIFT 0 | ||
64 | #define CODEC_CONTROL_READ BIT(16) | ||
65 | #define CODEC_CONTROL_ADDRESS_SHIFT 17 | ||
66 | |||
67 | #define CHANNEL_CONTROL_RESET BIT(10) /* 1: reset channel */ | ||
68 | #define CHANNEL_DMA_ENABLE BIT(9) /* 1: enable DMA transfer */ | ||
69 | #define CHANNEL_INT_THRESHOLD_DISABLED (0 << 5) /* interrupt disabled */ | ||
70 | #define CHANNEL_INT_THRESHOLD_25 (1 << 5) /* int on buffer >25% full */ | ||
71 | #define CHANNEL_INT_THRESHOLD_50 (2 << 5) /* int on buffer >50% full */ | ||
72 | #define CHANNEL_INT_THRESHOLD_75 (3 << 5) /* int on buffer >75% full */ | ||
73 | #define CHANNEL_INT_THRESHOLD_EMPTY (4 << 5) /* int on buffer empty */ | ||
74 | #define CHANNEL_INT_THRESHOLD_NOT_EMPTY (5 << 5) /* int on buffer !empty */ | ||
75 | #define CHANNEL_INT_THRESHOLD_FULL (6 << 5) /* int on buffer empty */ | ||
76 | #define CHANNEL_INT_THRESHOLD_NOT_FULL (7 << 5) /* int on buffer !empty */ | ||
77 | |||
78 | #define CHANNEL_RING_SHIFT 12 | ||
79 | #define CHANNEL_RING_SIZE (1 << CHANNEL_RING_SHIFT) | ||
80 | #define CHANNEL_RING_MASK (CHANNEL_RING_SIZE - 1) | ||
81 | |||
82 | #define CHANNEL_LEFT_SHIFT 40 | ||
83 | #define CHANNEL_RIGHT_SHIFT 8 | ||
84 | |||
85 | struct snd_sgio2audio_chan { | ||
86 | int idx; | ||
87 | struct snd_pcm_substream *substream; | ||
88 | int pos; | ||
89 | snd_pcm_uframes_t size; | ||
90 | spinlock_t lock; | ||
91 | }; | ||
92 | |||
93 | /* definition of the chip-specific record */ | ||
94 | struct snd_sgio2audio { | ||
95 | struct snd_card *card; | ||
96 | |||
97 | /* codec */ | ||
98 | struct snd_ad1843 ad1843; | ||
99 | spinlock_t ad1843_lock; | ||
100 | |||
101 | /* channels */ | ||
102 | struct snd_sgio2audio_chan channel[3]; | ||
103 | |||
104 | /* resources */ | ||
105 | void *ring_base; | ||
106 | dma_addr_t ring_base_dma; | ||
107 | }; | ||
108 | |||
109 | /* AD1843 access */ | ||
110 | |||
111 | /* | ||
112 | * read_ad1843_reg returns the current contents of a 16 bit AD1843 register. | ||
113 | * | ||
114 | * Returns unsigned register value on success, -errno on failure. | ||
115 | */ | ||
116 | static int read_ad1843_reg(void *priv, int reg) | ||
117 | { | ||
118 | struct snd_sgio2audio *chip = priv; | ||
119 | int val; | ||
120 | unsigned long flags; | ||
121 | |||
122 | spin_lock_irqsave(&chip->ad1843_lock, flags); | ||
123 | |||
124 | writeq((reg << CODEC_CONTROL_ADDRESS_SHIFT) | | ||
125 | CODEC_CONTROL_READ, &mace->perif.audio.codec_control); | ||
126 | wmb(); | ||
127 | val = readq(&mace->perif.audio.codec_control); /* flush bus */ | ||
128 | udelay(200); | ||
129 | |||
130 | val = readq(&mace->perif.audio.codec_read); | ||
131 | |||
132 | spin_unlock_irqrestore(&chip->ad1843_lock, flags); | ||
133 | return val; | ||
134 | } | ||
135 | |||
136 | /* | ||
137 | * write_ad1843_reg writes the specified value to a 16 bit AD1843 register. | ||
138 | */ | ||
139 | static int write_ad1843_reg(void *priv, int reg, int word) | ||
140 | { | ||
141 | struct snd_sgio2audio *chip = priv; | ||
142 | int val; | ||
143 | unsigned long flags; | ||
144 | |||
145 | spin_lock_irqsave(&chip->ad1843_lock, flags); | ||
146 | |||
147 | writeq((reg << CODEC_CONTROL_ADDRESS_SHIFT) | | ||
148 | (word << CODEC_CONTROL_WORD_SHIFT), | ||
149 | &mace->perif.audio.codec_control); | ||
150 | wmb(); | ||
151 | val = readq(&mace->perif.audio.codec_control); /* flush bus */ | ||
152 | udelay(200); | ||
153 | |||
154 | spin_unlock_irqrestore(&chip->ad1843_lock, flags); | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | static int sgio2audio_gain_info(struct snd_kcontrol *kcontrol, | ||
159 | struct snd_ctl_elem_info *uinfo) | ||
160 | { | ||
161 | struct snd_sgio2audio *chip = snd_kcontrol_chip(kcontrol); | ||
162 | |||
163 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
164 | uinfo->count = 2; | ||
165 | uinfo->value.integer.min = 0; | ||
166 | uinfo->value.integer.max = ad1843_get_gain_max(&chip->ad1843, | ||
167 | (int)kcontrol->private_value); | ||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | static int sgio2audio_gain_get(struct snd_kcontrol *kcontrol, | ||
172 | struct snd_ctl_elem_value *ucontrol) | ||
173 | { | ||
174 | struct snd_sgio2audio *chip = snd_kcontrol_chip(kcontrol); | ||
175 | int vol; | ||
176 | |||
177 | vol = ad1843_get_gain(&chip->ad1843, (int)kcontrol->private_value); | ||
178 | |||
179 | ucontrol->value.integer.value[0] = (vol >> 8) & 0xFF; | ||
180 | ucontrol->value.integer.value[1] = vol & 0xFF; | ||
181 | |||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | static int sgio2audio_gain_put(struct snd_kcontrol *kcontrol, | ||
186 | struct snd_ctl_elem_value *ucontrol) | ||
187 | { | ||
188 | struct snd_sgio2audio *chip = snd_kcontrol_chip(kcontrol); | ||
189 | int newvol, oldvol; | ||
190 | |||
191 | oldvol = ad1843_get_gain(&chip->ad1843, kcontrol->private_value); | ||
192 | newvol = (ucontrol->value.integer.value[0] << 8) | | ||
193 | ucontrol->value.integer.value[1]; | ||
194 | |||
195 | newvol = ad1843_set_gain(&chip->ad1843, kcontrol->private_value, | ||
196 | newvol); | ||
197 | |||
198 | return newvol != oldvol; | ||
199 | } | ||
200 | |||
201 | static int sgio2audio_source_info(struct snd_kcontrol *kcontrol, | ||
202 | struct snd_ctl_elem_info *uinfo) | ||
203 | { | ||
204 | static const char *texts[3] = { | ||
205 | "Cam Mic", "Mic", "Line" | ||
206 | }; | ||
207 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
208 | uinfo->count = 1; | ||
209 | uinfo->value.enumerated.items = 3; | ||
210 | if (uinfo->value.enumerated.item >= 3) | ||
211 | uinfo->value.enumerated.item = 1; | ||
212 | strcpy(uinfo->value.enumerated.name, | ||
213 | texts[uinfo->value.enumerated.item]); | ||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | static int sgio2audio_source_get(struct snd_kcontrol *kcontrol, | ||
218 | struct snd_ctl_elem_value *ucontrol) | ||
219 | { | ||
220 | struct snd_sgio2audio *chip = snd_kcontrol_chip(kcontrol); | ||
221 | |||
222 | ucontrol->value.enumerated.item[0] = ad1843_get_recsrc(&chip->ad1843); | ||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static int sgio2audio_source_put(struct snd_kcontrol *kcontrol, | ||
227 | struct snd_ctl_elem_value *ucontrol) | ||
228 | { | ||
229 | struct snd_sgio2audio *chip = snd_kcontrol_chip(kcontrol); | ||
230 | int newsrc, oldsrc; | ||
231 | |||
232 | oldsrc = ad1843_get_recsrc(&chip->ad1843); | ||
233 | newsrc = ad1843_set_recsrc(&chip->ad1843, | ||
234 | ucontrol->value.enumerated.item[0]); | ||
235 | |||
236 | return newsrc != oldsrc; | ||
237 | } | ||
238 | |||
239 | /* dac1/pcm0 mixer control */ | ||
240 | static struct snd_kcontrol_new sgio2audio_ctrl_pcm0 __devinitdata = { | ||
241 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
242 | .name = "PCM Playback Volume", | ||
243 | .index = 0, | ||
244 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
245 | .private_value = AD1843_GAIN_PCM_0, | ||
246 | .info = sgio2audio_gain_info, | ||
247 | .get = sgio2audio_gain_get, | ||
248 | .put = sgio2audio_gain_put, | ||
249 | }; | ||
250 | |||
251 | /* dac2/pcm1 mixer control */ | ||
252 | static struct snd_kcontrol_new sgio2audio_ctrl_pcm1 __devinitdata = { | ||
253 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
254 | .name = "PCM Playback Volume", | ||
255 | .index = 1, | ||
256 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
257 | .private_value = AD1843_GAIN_PCM_1, | ||
258 | .info = sgio2audio_gain_info, | ||
259 | .get = sgio2audio_gain_get, | ||
260 | .put = sgio2audio_gain_put, | ||
261 | }; | ||
262 | |||
263 | /* record level mixer control */ | ||
264 | static struct snd_kcontrol_new sgio2audio_ctrl_reclevel __devinitdata = { | ||
265 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
266 | .name = "Capture Volume", | ||
267 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
268 | .private_value = AD1843_GAIN_RECLEV, | ||
269 | .info = sgio2audio_gain_info, | ||
270 | .get = sgio2audio_gain_get, | ||
271 | .put = sgio2audio_gain_put, | ||
272 | }; | ||
273 | |||
274 | /* record level source control */ | ||
275 | static struct snd_kcontrol_new sgio2audio_ctrl_recsource __devinitdata = { | ||
276 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
277 | .name = "Capture Source", | ||
278 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
279 | .info = sgio2audio_source_info, | ||
280 | .get = sgio2audio_source_get, | ||
281 | .put = sgio2audio_source_put, | ||
282 | }; | ||
283 | |||
284 | /* line mixer control */ | ||
285 | static struct snd_kcontrol_new sgio2audio_ctrl_line __devinitdata = { | ||
286 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
287 | .name = "Line Playback Volume", | ||
288 | .index = 0, | ||
289 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
290 | .private_value = AD1843_GAIN_LINE, | ||
291 | .info = sgio2audio_gain_info, | ||
292 | .get = sgio2audio_gain_get, | ||
293 | .put = sgio2audio_gain_put, | ||
294 | }; | ||
295 | |||
296 | /* cd mixer control */ | ||
297 | static struct snd_kcontrol_new sgio2audio_ctrl_cd __devinitdata = { | ||
298 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
299 | .name = "Line Playback Volume", | ||
300 | .index = 1, | ||
301 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
302 | .private_value = AD1843_GAIN_LINE_2, | ||
303 | .info = sgio2audio_gain_info, | ||
304 | .get = sgio2audio_gain_get, | ||
305 | .put = sgio2audio_gain_put, | ||
306 | }; | ||
307 | |||
308 | /* mic mixer control */ | ||
309 | static struct snd_kcontrol_new sgio2audio_ctrl_mic __devinitdata = { | ||
310 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
311 | .name = "Mic Playback Volume", | ||
312 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
313 | .private_value = AD1843_GAIN_MIC, | ||
314 | .info = sgio2audio_gain_info, | ||
315 | .get = sgio2audio_gain_get, | ||
316 | .put = sgio2audio_gain_put, | ||
317 | }; | ||
318 | |||
319 | |||
320 | static int __devinit snd_sgio2audio_new_mixer(struct snd_sgio2audio *chip) | ||
321 | { | ||
322 | int err; | ||
323 | |||
324 | err = snd_ctl_add(chip->card, | ||
325 | snd_ctl_new1(&sgio2audio_ctrl_pcm0, chip)); | ||
326 | if (err < 0) | ||
327 | return err; | ||
328 | |||
329 | err = snd_ctl_add(chip->card, | ||
330 | snd_ctl_new1(&sgio2audio_ctrl_pcm1, chip)); | ||
331 | if (err < 0) | ||
332 | return err; | ||
333 | |||
334 | err = snd_ctl_add(chip->card, | ||
335 | snd_ctl_new1(&sgio2audio_ctrl_reclevel, chip)); | ||
336 | if (err < 0) | ||
337 | return err; | ||
338 | |||
339 | err = snd_ctl_add(chip->card, | ||
340 | snd_ctl_new1(&sgio2audio_ctrl_recsource, chip)); | ||
341 | if (err < 0) | ||
342 | return err; | ||
343 | err = snd_ctl_add(chip->card, | ||
344 | snd_ctl_new1(&sgio2audio_ctrl_line, chip)); | ||
345 | if (err < 0) | ||
346 | return err; | ||
347 | |||
348 | err = snd_ctl_add(chip->card, | ||
349 | snd_ctl_new1(&sgio2audio_ctrl_cd, chip)); | ||
350 | if (err < 0) | ||
351 | return err; | ||
352 | |||
353 | err = snd_ctl_add(chip->card, | ||
354 | snd_ctl_new1(&sgio2audio_ctrl_mic, chip)); | ||
355 | if (err < 0) | ||
356 | return err; | ||
357 | |||
358 | return 0; | ||
359 | } | ||
360 | |||
361 | /* low-level audio interface DMA */ | ||
362 | |||
363 | /* get data out of bounce buffer, count must be a multiple of 32 */ | ||
364 | /* returns 1 if a period has elapsed */ | ||
365 | static int snd_sgio2audio_dma_pull_frag(struct snd_sgio2audio *chip, | ||
366 | unsigned int ch, unsigned int count) | ||
367 | { | ||
368 | int ret; | ||
369 | unsigned long src_base, src_pos, dst_mask; | ||
370 | unsigned char *dst_base; | ||
371 | int dst_pos; | ||
372 | u64 *src; | ||
373 | s16 *dst; | ||
374 | u64 x; | ||
375 | unsigned long flags; | ||
376 | struct snd_pcm_runtime *runtime = chip->channel[ch].substream->runtime; | ||
377 | |||
378 | spin_lock_irqsave(&chip->channel[ch].lock, flags); | ||
379 | |||
380 | src_base = (unsigned long) chip->ring_base | (ch << CHANNEL_RING_SHIFT); | ||
381 | src_pos = readq(&mace->perif.audio.chan[ch].read_ptr); | ||
382 | dst_base = runtime->dma_area; | ||
383 | dst_pos = chip->channel[ch].pos; | ||
384 | dst_mask = frames_to_bytes(runtime, runtime->buffer_size) - 1; | ||
385 | |||
386 | /* check if a period has elapsed */ | ||
387 | chip->channel[ch].size += (count >> 3); /* in frames */ | ||
388 | ret = chip->channel[ch].size >= runtime->period_size; | ||
389 | chip->channel[ch].size %= runtime->period_size; | ||
390 | |||
391 | while (count) { | ||
392 | src = (u64 *)(src_base + src_pos); | ||
393 | dst = (s16 *)(dst_base + dst_pos); | ||
394 | |||
395 | x = *src; | ||
396 | dst[0] = (x >> CHANNEL_LEFT_SHIFT) & 0xffff; | ||
397 | dst[1] = (x >> CHANNEL_RIGHT_SHIFT) & 0xffff; | ||
398 | |||
399 | src_pos = (src_pos + sizeof(u64)) & CHANNEL_RING_MASK; | ||
400 | dst_pos = (dst_pos + 2 * sizeof(s16)) & dst_mask; | ||
401 | count -= sizeof(u64); | ||
402 | } | ||
403 | |||
404 | writeq(src_pos, &mace->perif.audio.chan[ch].read_ptr); /* in bytes */ | ||
405 | chip->channel[ch].pos = dst_pos; | ||
406 | |||
407 | spin_unlock_irqrestore(&chip->channel[ch].lock, flags); | ||
408 | return ret; | ||
409 | } | ||
410 | |||
411 | /* put some DMA data in bounce buffer, count must be a multiple of 32 */ | ||
412 | /* returns 1 if a period has elapsed */ | ||
413 | static int snd_sgio2audio_dma_push_frag(struct snd_sgio2audio *chip, | ||
414 | unsigned int ch, unsigned int count) | ||
415 | { | ||
416 | int ret; | ||
417 | s64 l, r; | ||
418 | unsigned long dst_base, dst_pos, src_mask; | ||
419 | unsigned char *src_base; | ||
420 | int src_pos; | ||
421 | u64 *dst; | ||
422 | s16 *src; | ||
423 | unsigned long flags; | ||
424 | struct snd_pcm_runtime *runtime = chip->channel[ch].substream->runtime; | ||
425 | |||
426 | spin_lock_irqsave(&chip->channel[ch].lock, flags); | ||
427 | |||
428 | dst_base = (unsigned long)chip->ring_base | (ch << CHANNEL_RING_SHIFT); | ||
429 | dst_pos = readq(&mace->perif.audio.chan[ch].write_ptr); | ||
430 | src_base = runtime->dma_area; | ||
431 | src_pos = chip->channel[ch].pos; | ||
432 | src_mask = frames_to_bytes(runtime, runtime->buffer_size) - 1; | ||
433 | |||
434 | /* check if a period has elapsed */ | ||
435 | chip->channel[ch].size += (count >> 3); /* in frames */ | ||
436 | ret = chip->channel[ch].size >= runtime->period_size; | ||
437 | chip->channel[ch].size %= runtime->period_size; | ||
438 | |||
439 | while (count) { | ||
440 | src = (s16 *)(src_base + src_pos); | ||
441 | dst = (u64 *)(dst_base + dst_pos); | ||
442 | |||
443 | l = src[0]; /* sign extend */ | ||
444 | r = src[1]; /* sign extend */ | ||
445 | |||
446 | *dst = ((l & 0x00ffffff) << CHANNEL_LEFT_SHIFT) | | ||
447 | ((r & 0x00ffffff) << CHANNEL_RIGHT_SHIFT); | ||
448 | |||
449 | dst_pos = (dst_pos + sizeof(u64)) & CHANNEL_RING_MASK; | ||
450 | src_pos = (src_pos + 2 * sizeof(s16)) & src_mask; | ||
451 | count -= sizeof(u64); | ||
452 | } | ||
453 | |||
454 | writeq(dst_pos, &mace->perif.audio.chan[ch].write_ptr); /* in bytes */ | ||
455 | chip->channel[ch].pos = src_pos; | ||
456 | |||
457 | spin_unlock_irqrestore(&chip->channel[ch].lock, flags); | ||
458 | return ret; | ||
459 | } | ||
460 | |||
461 | static int snd_sgio2audio_dma_start(struct snd_pcm_substream *substream) | ||
462 | { | ||
463 | struct snd_sgio2audio *chip = snd_pcm_substream_chip(substream); | ||
464 | struct snd_sgio2audio_chan *chan = substream->runtime->private_data; | ||
465 | int ch = chan->idx; | ||
466 | |||
467 | /* reset DMA channel */ | ||
468 | writeq(CHANNEL_CONTROL_RESET, &mace->perif.audio.chan[ch].control); | ||
469 | udelay(10); | ||
470 | writeq(0, &mace->perif.audio.chan[ch].control); | ||
471 | |||
472 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
473 | /* push a full buffer */ | ||
474 | snd_sgio2audio_dma_push_frag(chip, ch, CHANNEL_RING_SIZE - 32); | ||
475 | } | ||
476 | /* set DMA to wake on 50% empty and enable interrupt */ | ||
477 | writeq(CHANNEL_DMA_ENABLE | CHANNEL_INT_THRESHOLD_50, | ||
478 | &mace->perif.audio.chan[ch].control); | ||
479 | return 0; | ||
480 | } | ||
481 | |||
482 | static int snd_sgio2audio_dma_stop(struct snd_pcm_substream *substream) | ||
483 | { | ||
484 | struct snd_sgio2audio_chan *chan = substream->runtime->private_data; | ||
485 | |||
486 | writeq(0, &mace->perif.audio.chan[chan->idx].control); | ||
487 | return 0; | ||
488 | } | ||
489 | |||
490 | static irqreturn_t snd_sgio2audio_dma_in_isr(int irq, void *dev_id) | ||
491 | { | ||
492 | struct snd_sgio2audio_chan *chan = dev_id; | ||
493 | struct snd_pcm_substream *substream; | ||
494 | struct snd_sgio2audio *chip; | ||
495 | int count, ch; | ||
496 | |||
497 | substream = chan->substream; | ||
498 | chip = snd_pcm_substream_chip(substream); | ||
499 | ch = chan->idx; | ||
500 | |||
501 | /* empty the ring */ | ||
502 | count = CHANNEL_RING_SIZE - | ||
503 | readq(&mace->perif.audio.chan[ch].depth) - 32; | ||
504 | if (snd_sgio2audio_dma_pull_frag(chip, ch, count)) | ||
505 | snd_pcm_period_elapsed(substream); | ||
506 | |||
507 | return IRQ_HANDLED; | ||
508 | } | ||
509 | |||
510 | static irqreturn_t snd_sgio2audio_dma_out_isr(int irq, void *dev_id) | ||
511 | { | ||
512 | struct snd_sgio2audio_chan *chan = dev_id; | ||
513 | struct snd_pcm_substream *substream; | ||
514 | struct snd_sgio2audio *chip; | ||
515 | int count, ch; | ||
516 | |||
517 | substream = chan->substream; | ||
518 | chip = snd_pcm_substream_chip(substream); | ||
519 | ch = chan->idx; | ||
520 | /* fill the ring */ | ||
521 | count = CHANNEL_RING_SIZE - | ||
522 | readq(&mace->perif.audio.chan[ch].depth) - 32; | ||
523 | if (snd_sgio2audio_dma_push_frag(chip, ch, count)) | ||
524 | snd_pcm_period_elapsed(substream); | ||
525 | |||
526 | return IRQ_HANDLED; | ||
527 | } | ||
528 | |||
529 | static irqreturn_t snd_sgio2audio_error_isr(int irq, void *dev_id) | ||
530 | { | ||
531 | struct snd_sgio2audio_chan *chan = dev_id; | ||
532 | struct snd_pcm_substream *substream; | ||
533 | |||
534 | substream = chan->substream; | ||
535 | snd_sgio2audio_dma_stop(substream); | ||
536 | snd_sgio2audio_dma_start(substream); | ||
537 | return IRQ_HANDLED; | ||
538 | } | ||
539 | |||
540 | /* PCM part */ | ||
541 | /* PCM hardware definition */ | ||
542 | static struct snd_pcm_hardware snd_sgio2audio_pcm_hw = { | ||
543 | .info = (SNDRV_PCM_INFO_MMAP | | ||
544 | SNDRV_PCM_INFO_MMAP_VALID | | ||
545 | SNDRV_PCM_INFO_INTERLEAVED | | ||
546 | SNDRV_PCM_INFO_BLOCK_TRANSFER), | ||
547 | .formats = SNDRV_PCM_FMTBIT_S16_BE, | ||
548 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
549 | .rate_min = 8000, | ||
550 | .rate_max = 48000, | ||
551 | .channels_min = 2, | ||
552 | .channels_max = 2, | ||
553 | .buffer_bytes_max = 65536, | ||
554 | .period_bytes_min = 32768, | ||
555 | .period_bytes_max = 65536, | ||
556 | .periods_min = 1, | ||
557 | .periods_max = 1024, | ||
558 | }; | ||
559 | |||
560 | /* PCM playback open callback */ | ||
561 | static int snd_sgio2audio_playback1_open(struct snd_pcm_substream *substream) | ||
562 | { | ||
563 | struct snd_sgio2audio *chip = snd_pcm_substream_chip(substream); | ||
564 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
565 | |||
566 | runtime->hw = snd_sgio2audio_pcm_hw; | ||
567 | runtime->private_data = &chip->channel[1]; | ||
568 | return 0; | ||
569 | } | ||
570 | |||
571 | static int snd_sgio2audio_playback2_open(struct snd_pcm_substream *substream) | ||
572 | { | ||
573 | struct snd_sgio2audio *chip = snd_pcm_substream_chip(substream); | ||
574 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
575 | |||
576 | runtime->hw = snd_sgio2audio_pcm_hw; | ||
577 | runtime->private_data = &chip->channel[2]; | ||
578 | return 0; | ||
579 | } | ||
580 | |||
581 | /* PCM capture open callback */ | ||
582 | static int snd_sgio2audio_capture_open(struct snd_pcm_substream *substream) | ||
583 | { | ||
584 | struct snd_sgio2audio *chip = snd_pcm_substream_chip(substream); | ||
585 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
586 | |||
587 | runtime->hw = snd_sgio2audio_pcm_hw; | ||
588 | runtime->private_data = &chip->channel[0]; | ||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | /* PCM close callback */ | ||
593 | static int snd_sgio2audio_pcm_close(struct snd_pcm_substream *substream) | ||
594 | { | ||
595 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
596 | |||
597 | runtime->private_data = NULL; | ||
598 | return 0; | ||
599 | } | ||
600 | |||
601 | |||
602 | /* hw_params callback */ | ||
603 | static int snd_sgio2audio_pcm_hw_params(struct snd_pcm_substream *substream, | ||
604 | struct snd_pcm_hw_params *hw_params) | ||
605 | { | ||
606 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
607 | int size = params_buffer_bytes(hw_params); | ||
608 | |||
609 | /* alloc virtual 'dma' area */ | ||
610 | if (runtime->dma_area) | ||
611 | vfree(runtime->dma_area); | ||
612 | runtime->dma_area = vmalloc(size); | ||
613 | if (runtime->dma_area == NULL) | ||
614 | return -ENOMEM; | ||
615 | runtime->dma_bytes = size; | ||
616 | return 0; | ||
617 | } | ||
618 | |||
619 | /* hw_free callback */ | ||
620 | static int snd_sgio2audio_pcm_hw_free(struct snd_pcm_substream *substream) | ||
621 | { | ||
622 | if (substream->runtime->dma_area) | ||
623 | vfree(substream->runtime->dma_area); | ||
624 | substream->runtime->dma_area = NULL; | ||
625 | return 0; | ||
626 | } | ||
627 | |||
628 | /* prepare callback */ | ||
629 | static int snd_sgio2audio_pcm_prepare(struct snd_pcm_substream *substream) | ||
630 | { | ||
631 | struct snd_sgio2audio *chip = snd_pcm_substream_chip(substream); | ||
632 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
633 | struct snd_sgio2audio_chan *chan = substream->runtime->private_data; | ||
634 | int ch = chan->idx; | ||
635 | unsigned long flags; | ||
636 | |||
637 | spin_lock_irqsave(&chip->channel[ch].lock, flags); | ||
638 | |||
639 | /* Setup the pseudo-dma transfer pointers. */ | ||
640 | chip->channel[ch].pos = 0; | ||
641 | chip->channel[ch].size = 0; | ||
642 | chip->channel[ch].substream = substream; | ||
643 | |||
644 | /* set AD1843 format */ | ||
645 | /* hardware format is always S16_LE */ | ||
646 | switch (substream->stream) { | ||
647 | case SNDRV_PCM_STREAM_PLAYBACK: | ||
648 | ad1843_setup_dac(&chip->ad1843, | ||
649 | ch - 1, | ||
650 | runtime->rate, | ||
651 | SNDRV_PCM_FORMAT_S16_LE, | ||
652 | runtime->channels); | ||
653 | break; | ||
654 | case SNDRV_PCM_STREAM_CAPTURE: | ||
655 | ad1843_setup_adc(&chip->ad1843, | ||
656 | runtime->rate, | ||
657 | SNDRV_PCM_FORMAT_S16_LE, | ||
658 | runtime->channels); | ||
659 | break; | ||
660 | } | ||
661 | spin_unlock_irqrestore(&chip->channel[ch].lock, flags); | ||
662 | return 0; | ||
663 | } | ||
664 | |||
665 | /* trigger callback */ | ||
666 | static int snd_sgio2audio_pcm_trigger(struct snd_pcm_substream *substream, | ||
667 | int cmd) | ||
668 | { | ||
669 | switch (cmd) { | ||
670 | case SNDRV_PCM_TRIGGER_START: | ||
671 | /* start the PCM engine */ | ||
672 | snd_sgio2audio_dma_start(substream); | ||
673 | break; | ||
674 | case SNDRV_PCM_TRIGGER_STOP: | ||
675 | /* stop the PCM engine */ | ||
676 | snd_sgio2audio_dma_stop(substream); | ||
677 | break; | ||
678 | default: | ||
679 | return -EINVAL; | ||
680 | } | ||
681 | return 0; | ||
682 | } | ||
683 | |||
684 | /* pointer callback */ | ||
685 | static snd_pcm_uframes_t | ||
686 | snd_sgio2audio_pcm_pointer(struct snd_pcm_substream *substream) | ||
687 | { | ||
688 | struct snd_sgio2audio *chip = snd_pcm_substream_chip(substream); | ||
689 | struct snd_sgio2audio_chan *chan = substream->runtime->private_data; | ||
690 | |||
691 | /* get the current hardware pointer */ | ||
692 | return bytes_to_frames(substream->runtime, | ||
693 | chip->channel[chan->idx].pos); | ||
694 | } | ||
695 | |||
696 | /* get the physical page pointer on the given offset */ | ||
697 | static struct page *snd_sgio2audio_page(struct snd_pcm_substream *substream, | ||
698 | unsigned long offset) | ||
699 | { | ||
700 | return vmalloc_to_page(substream->runtime->dma_area + offset); | ||
701 | } | ||
702 | |||
703 | /* operators */ | ||
704 | static struct snd_pcm_ops snd_sgio2audio_playback1_ops = { | ||
705 | .open = snd_sgio2audio_playback1_open, | ||
706 | .close = snd_sgio2audio_pcm_close, | ||
707 | .ioctl = snd_pcm_lib_ioctl, | ||
708 | .hw_params = snd_sgio2audio_pcm_hw_params, | ||
709 | .hw_free = snd_sgio2audio_pcm_hw_free, | ||
710 | .prepare = snd_sgio2audio_pcm_prepare, | ||
711 | .trigger = snd_sgio2audio_pcm_trigger, | ||
712 | .pointer = snd_sgio2audio_pcm_pointer, | ||
713 | .page = snd_sgio2audio_page, | ||
714 | }; | ||
715 | |||
716 | static struct snd_pcm_ops snd_sgio2audio_playback2_ops = { | ||
717 | .open = snd_sgio2audio_playback2_open, | ||
718 | .close = snd_sgio2audio_pcm_close, | ||
719 | .ioctl = snd_pcm_lib_ioctl, | ||
720 | .hw_params = snd_sgio2audio_pcm_hw_params, | ||
721 | .hw_free = snd_sgio2audio_pcm_hw_free, | ||
722 | .prepare = snd_sgio2audio_pcm_prepare, | ||
723 | .trigger = snd_sgio2audio_pcm_trigger, | ||
724 | .pointer = snd_sgio2audio_pcm_pointer, | ||
725 | .page = snd_sgio2audio_page, | ||
726 | }; | ||
727 | |||
728 | static struct snd_pcm_ops snd_sgio2audio_capture_ops = { | ||
729 | .open = snd_sgio2audio_capture_open, | ||
730 | .close = snd_sgio2audio_pcm_close, | ||
731 | .ioctl = snd_pcm_lib_ioctl, | ||
732 | .hw_params = snd_sgio2audio_pcm_hw_params, | ||
733 | .hw_free = snd_sgio2audio_pcm_hw_free, | ||
734 | .prepare = snd_sgio2audio_pcm_prepare, | ||
735 | .trigger = snd_sgio2audio_pcm_trigger, | ||
736 | .pointer = snd_sgio2audio_pcm_pointer, | ||
737 | .page = snd_sgio2audio_page, | ||
738 | }; | ||
739 | |||
740 | /* | ||
741 | * definitions of capture are omitted here... | ||
742 | */ | ||
743 | |||
744 | /* create a pcm device */ | ||
745 | static int __devinit snd_sgio2audio_new_pcm(struct snd_sgio2audio *chip) | ||
746 | { | ||
747 | struct snd_pcm *pcm; | ||
748 | int err; | ||
749 | |||
750 | /* create first pcm device with one outputs and one input */ | ||
751 | err = snd_pcm_new(chip->card, "SGI O2 Audio", 0, 1, 1, &pcm); | ||
752 | if (err < 0) | ||
753 | return err; | ||
754 | |||
755 | pcm->private_data = chip; | ||
756 | strcpy(pcm->name, "SGI O2 DAC1"); | ||
757 | |||
758 | /* set operators */ | ||
759 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, | ||
760 | &snd_sgio2audio_playback1_ops); | ||
761 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, | ||
762 | &snd_sgio2audio_capture_ops); | ||
763 | |||
764 | /* create second pcm device with one outputs and no input */ | ||
765 | err = snd_pcm_new(chip->card, "SGI O2 Audio", 1, 1, 0, &pcm); | ||
766 | if (err < 0) | ||
767 | return err; | ||
768 | |||
769 | pcm->private_data = chip; | ||
770 | strcpy(pcm->name, "SGI O2 DAC2"); | ||
771 | |||
772 | /* set operators */ | ||
773 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, | ||
774 | &snd_sgio2audio_playback2_ops); | ||
775 | |||
776 | return 0; | ||
777 | } | ||
778 | |||
779 | static struct { | ||
780 | int idx; | ||
781 | int irq; | ||
782 | irqreturn_t (*isr)(int, void *); | ||
783 | const char *desc; | ||
784 | } snd_sgio2_isr_table[] = { | ||
785 | { | ||
786 | .idx = 0, | ||
787 | .irq = MACEISA_AUDIO1_DMAT_IRQ, | ||
788 | .isr = snd_sgio2audio_dma_in_isr, | ||
789 | .desc = "Capture DMA Channel 0" | ||
790 | }, { | ||
791 | .idx = 0, | ||
792 | .irq = MACEISA_AUDIO1_OF_IRQ, | ||
793 | .isr = snd_sgio2audio_error_isr, | ||
794 | .desc = "Capture Overflow" | ||
795 | }, { | ||
796 | .idx = 1, | ||
797 | .irq = MACEISA_AUDIO2_DMAT_IRQ, | ||
798 | .isr = snd_sgio2audio_dma_out_isr, | ||
799 | .desc = "Playback DMA Channel 1" | ||
800 | }, { | ||
801 | .idx = 1, | ||
802 | .irq = MACEISA_AUDIO2_MERR_IRQ, | ||
803 | .isr = snd_sgio2audio_error_isr, | ||
804 | .desc = "Memory Error Channel 1" | ||
805 | }, { | ||
806 | .idx = 2, | ||
807 | .irq = MACEISA_AUDIO3_DMAT_IRQ, | ||
808 | .isr = snd_sgio2audio_dma_out_isr, | ||
809 | .desc = "Playback DMA Channel 2" | ||
810 | }, { | ||
811 | .idx = 2, | ||
812 | .irq = MACEISA_AUDIO3_MERR_IRQ, | ||
813 | .isr = snd_sgio2audio_error_isr, | ||
814 | .desc = "Memory Error Channel 2" | ||
815 | } | ||
816 | }; | ||
817 | |||
818 | /* ALSA driver */ | ||
819 | |||
820 | static int snd_sgio2audio_free(struct snd_sgio2audio *chip) | ||
821 | { | ||
822 | int i; | ||
823 | |||
824 | /* reset interface */ | ||
825 | writeq(AUDIO_CONTROL_RESET, &mace->perif.audio.control); | ||
826 | udelay(1); | ||
827 | writeq(0, &mace->perif.audio.control); | ||
828 | |||
829 | /* release IRQ's */ | ||
830 | for (i = 0; i < ARRAY_SIZE(snd_sgio2_isr_table); i++) | ||
831 | free_irq(snd_sgio2_isr_table[i].irq, | ||
832 | &chip->channel[snd_sgio2_isr_table[i].idx]); | ||
833 | |||
834 | dma_free_coherent(NULL, MACEISA_RINGBUFFERS_SIZE, | ||
835 | chip->ring_base, chip->ring_base_dma); | ||
836 | |||
837 | /* release card data */ | ||
838 | kfree(chip); | ||
839 | return 0; | ||
840 | } | ||
841 | |||
842 | static int snd_sgio2audio_dev_free(struct snd_device *device) | ||
843 | { | ||
844 | struct snd_sgio2audio *chip = device->device_data; | ||
845 | |||
846 | return snd_sgio2audio_free(chip); | ||
847 | } | ||
848 | |||
849 | static struct snd_device_ops ops = { | ||
850 | .dev_free = snd_sgio2audio_dev_free, | ||
851 | }; | ||
852 | |||
853 | static int __devinit snd_sgio2audio_create(struct snd_card *card, | ||
854 | struct snd_sgio2audio **rchip) | ||
855 | { | ||
856 | struct snd_sgio2audio *chip; | ||
857 | int i, err; | ||
858 | |||
859 | *rchip = NULL; | ||
860 | |||
861 | /* check if a codec is attached to the interface */ | ||
862 | /* (Audio or Audio/Video board present) */ | ||
863 | if (!(readq(&mace->perif.audio.control) & AUDIO_CONTROL_CODEC_PRESENT)) | ||
864 | return -ENOENT; | ||
865 | |||
866 | chip = kzalloc(sizeof(struct snd_sgio2audio), GFP_KERNEL); | ||
867 | if (chip == NULL) | ||
868 | return -ENOMEM; | ||
869 | |||
870 | chip->card = card; | ||
871 | |||
872 | chip->ring_base = dma_alloc_coherent(NULL, MACEISA_RINGBUFFERS_SIZE, | ||
873 | &chip->ring_base_dma, GFP_USER); | ||
874 | if (chip->ring_base == NULL) { | ||
875 | printk(KERN_ERR | ||
876 | "sgio2audio: could not allocate ring buffers\n"); | ||
877 | kfree(chip); | ||
878 | return -ENOMEM; | ||
879 | } | ||
880 | |||
881 | spin_lock_init(&chip->ad1843_lock); | ||
882 | |||
883 | /* initialize channels */ | ||
884 | for (i = 0; i < 3; i++) { | ||
885 | spin_lock_init(&chip->channel[i].lock); | ||
886 | chip->channel[i].idx = i; | ||
887 | } | ||
888 | |||
889 | /* allocate IRQs */ | ||
890 | for (i = 0; i < ARRAY_SIZE(snd_sgio2_isr_table); i++) { | ||
891 | if (request_irq(snd_sgio2_isr_table[i].irq, | ||
892 | snd_sgio2_isr_table[i].isr, | ||
893 | 0, | ||
894 | snd_sgio2_isr_table[i].desc, | ||
895 | &chip->channel[snd_sgio2_isr_table[i].idx])) { | ||
896 | snd_sgio2audio_free(chip); | ||
897 | printk(KERN_ERR "sgio2audio: cannot allocate irq %d\n", | ||
898 | snd_sgio2_isr_table[i].irq); | ||
899 | return -EBUSY; | ||
900 | } | ||
901 | } | ||
902 | |||
903 | /* reset the interface */ | ||
904 | writeq(AUDIO_CONTROL_RESET, &mace->perif.audio.control); | ||
905 | udelay(1); | ||
906 | writeq(0, &mace->perif.audio.control); | ||
907 | msleep_interruptible(1); /* give time to recover */ | ||
908 | |||
909 | /* set ring base */ | ||
910 | writeq(chip->ring_base_dma, &mace->perif.ctrl.ringbase); | ||
911 | |||
912 | /* attach the AD1843 codec */ | ||
913 | chip->ad1843.read = read_ad1843_reg; | ||
914 | chip->ad1843.write = write_ad1843_reg; | ||
915 | chip->ad1843.chip = chip; | ||
916 | |||
917 | /* initialize the AD1843 codec */ | ||
918 | err = ad1843_init(&chip->ad1843); | ||
919 | if (err < 0) { | ||
920 | snd_sgio2audio_free(chip); | ||
921 | return err; | ||
922 | } | ||
923 | |||
924 | err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); | ||
925 | if (err < 0) { | ||
926 | snd_sgio2audio_free(chip); | ||
927 | return err; | ||
928 | } | ||
929 | *rchip = chip; | ||
930 | return 0; | ||
931 | } | ||
932 | |||
933 | static int __devinit snd_sgio2audio_probe(struct platform_device *pdev) | ||
934 | { | ||
935 | struct snd_card *card; | ||
936 | struct snd_sgio2audio *chip; | ||
937 | int err; | ||
938 | |||
939 | card = snd_card_new(index, id, THIS_MODULE, 0); | ||
940 | if (card == NULL) | ||
941 | return -ENOMEM; | ||
942 | |||
943 | err = snd_sgio2audio_create(card, &chip); | ||
944 | if (err < 0) { | ||
945 | snd_card_free(card); | ||
946 | return err; | ||
947 | } | ||
948 | snd_card_set_dev(card, &pdev->dev); | ||
949 | |||
950 | err = snd_sgio2audio_new_pcm(chip); | ||
951 | if (err < 0) { | ||
952 | snd_card_free(card); | ||
953 | return err; | ||
954 | } | ||
955 | err = snd_sgio2audio_new_mixer(chip); | ||
956 | if (err < 0) { | ||
957 | snd_card_free(card); | ||
958 | return err; | ||
959 | } | ||
960 | |||
961 | strcpy(card->driver, "SGI O2 Audio"); | ||
962 | strcpy(card->shortname, "SGI O2 Audio"); | ||
963 | sprintf(card->longname, "%s irq %i-%i", | ||
964 | card->shortname, | ||
965 | MACEISA_AUDIO1_DMAT_IRQ, | ||
966 | MACEISA_AUDIO3_MERR_IRQ); | ||
967 | |||
968 | err = snd_card_register(card); | ||
969 | if (err < 0) { | ||
970 | snd_card_free(card); | ||
971 | return err; | ||
972 | } | ||
973 | platform_set_drvdata(pdev, card); | ||
974 | return 0; | ||
975 | } | ||
976 | |||
977 | static int __exit snd_sgio2audio_remove(struct platform_device *pdev) | ||
978 | { | ||
979 | struct snd_card *card = platform_get_drvdata(pdev); | ||
980 | |||
981 | snd_card_free(card); | ||
982 | platform_set_drvdata(pdev, NULL); | ||
983 | return 0; | ||
984 | } | ||
985 | |||
986 | static struct platform_driver sgio2audio_driver = { | ||
987 | .probe = snd_sgio2audio_probe, | ||
988 | .remove = __devexit_p(snd_sgio2audio_remove), | ||
989 | .driver = { | ||
990 | .name = "sgio2audio", | ||
991 | .owner = THIS_MODULE, | ||
992 | } | ||
993 | }; | ||
994 | |||
995 | static int __init alsa_card_sgio2audio_init(void) | ||
996 | { | ||
997 | return platform_driver_register(&sgio2audio_driver); | ||
998 | } | ||
999 | |||
1000 | static void __exit alsa_card_sgio2audio_exit(void) | ||
1001 | { | ||
1002 | platform_driver_unregister(&sgio2audio_driver); | ||
1003 | } | ||
1004 | |||
1005 | module_init(alsa_card_sgio2audio_init) | ||
1006 | module_exit(alsa_card_sgio2audio_exit) | ||
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig index 3be2dc1025b5..33940139844b 100644 --- a/sound/oss/Kconfig +++ b/sound/oss/Kconfig | |||
@@ -7,7 +7,7 @@ | |||
7 | 7 | ||
8 | config SOUND_BCM_CS4297A | 8 | config SOUND_BCM_CS4297A |
9 | tristate "Crystal Sound CS4297a (for Swarm)" | 9 | tristate "Crystal Sound CS4297a (for Swarm)" |
10 | depends on SOUND_PRIME && SIBYTE_SWARM | 10 | depends on SIBYTE_SWARM |
11 | help | 11 | help |
12 | The BCM91250A has a Crystal CS4297a on synchronous serial | 12 | The BCM91250A has a Crystal CS4297a on synchronous serial |
13 | port B (in addition to the DB-9 serial port). Say Y or M | 13 | port B (in addition to the DB-9 serial port). Say Y or M |
@@ -17,7 +17,7 @@ config SOUND_BCM_CS4297A | |||
17 | 17 | ||
18 | config SOUND_VWSND | 18 | config SOUND_VWSND |
19 | tristate "SGI Visual Workstation Sound" | 19 | tristate "SGI Visual Workstation Sound" |
20 | depends on SOUND_PRIME && X86_VISWS | 20 | depends on X86_VISWS |
21 | help | 21 | help |
22 | Say Y or M if you have an SGI Visual Workstation and you want to be | 22 | Say Y or M if you have an SGI Visual Workstation and you want to be |
23 | able to use its on-board audio. Read | 23 | able to use its on-board audio. Read |
@@ -26,19 +26,18 @@ config SOUND_VWSND | |||
26 | 26 | ||
27 | config SOUND_HAL2 | 27 | config SOUND_HAL2 |
28 | tristate "SGI HAL2 sound (EXPERIMENTAL)" | 28 | tristate "SGI HAL2 sound (EXPERIMENTAL)" |
29 | depends on SOUND_PRIME && SGI_IP22 && EXPERIMENTAL | 29 | depends on SGI_IP22 && EXPERIMENTAL |
30 | help | 30 | help |
31 | Say Y or M if you have an SGI Indy or Indigo2 system and want to be able to | 31 | Say Y or M if you have an SGI Indy or Indigo2 system and want to be able to |
32 | use its on-board A2 audio system. | 32 | use its on-board A2 audio system. |
33 | 33 | ||
34 | config SOUND_AU1550_AC97 | 34 | config SOUND_AU1550_AC97 |
35 | tristate "Au1550/Au1200 AC97 Sound" | 35 | tristate "Au1550/Au1200 AC97 Sound" |
36 | select SND_AC97_CODEC | 36 | depends on SOC_AU1550 || SOC_AU1200 |
37 | depends on SOUND_PRIME && (SOC_AU1550 || SOC_AU1200) | ||
38 | 37 | ||
39 | config SOUND_TRIDENT | 38 | config SOUND_TRIDENT |
40 | tristate "Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core" | 39 | tristate "Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core" |
41 | depends on SOUND_PRIME && PCI | 40 | depends on PCI |
42 | ---help--- | 41 | ---help--- |
43 | Say Y or M if you have a PCI sound card utilizing the Trident | 42 | Say Y or M if you have a PCI sound card utilizing the Trident |
44 | 4DWave-DX/NX chipset or your mother board chipset has SiS 7018 | 43 | 4DWave-DX/NX chipset or your mother board chipset has SiS 7018 |
@@ -79,7 +78,7 @@ config SOUND_TRIDENT | |||
79 | 78 | ||
80 | config SOUND_MSNDCLAS | 79 | config SOUND_MSNDCLAS |
81 | tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey" | 80 | tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey" |
82 | depends on SOUND_PRIME && (m || !STANDALONE) && ISA | 81 | depends on (m || !STANDALONE) && ISA |
83 | help | 82 | help |
84 | Say M here if you have a Turtle Beach MultiSound Classic, Tahiti or | 83 | Say M here if you have a Turtle Beach MultiSound Classic, Tahiti or |
85 | Monterey (not for the Pinnacle or Fiji). | 84 | Monterey (not for the Pinnacle or Fiji). |
@@ -143,7 +142,7 @@ config MSNDCLAS_IO | |||
143 | 142 | ||
144 | config SOUND_MSNDPIN | 143 | config SOUND_MSNDPIN |
145 | tristate "Support for Turtle Beach MultiSound Pinnacle, Fiji" | 144 | tristate "Support for Turtle Beach MultiSound Pinnacle, Fiji" |
146 | depends on SOUND_PRIME && (m || !STANDALONE) && ISA | 145 | depends on (m || !STANDALONE) && ISA |
147 | help | 146 | help |
148 | Say M here if you have a Turtle Beach MultiSound Pinnacle or Fiji. | 147 | Say M here if you have a Turtle Beach MultiSound Pinnacle or Fiji. |
149 | See <file:Documentation/sound/oss/MultiSound> for important information | 148 | See <file:Documentation/sound/oss/MultiSound> for important information |
@@ -229,7 +228,7 @@ config MSNDPIN_NONPNP | |||
229 | configure the card's resources. | 228 | configure the card's resources. |
230 | 229 | ||
231 | comment "MSND Pinnacle DSP section will be configured to above parameters." | 230 | comment "MSND Pinnacle DSP section will be configured to above parameters." |
232 | depends on SOUND_PRIME && SOUND_MSNDPIN=y && MSNDPIN_NONPNP | 231 | depends on SOUND_MSNDPIN=y && MSNDPIN_NONPNP |
233 | 232 | ||
234 | config MSNDPIN_CFG | 233 | config MSNDPIN_CFG |
235 | hex "MSND Pinnacle config port 250,260,270" | 234 | hex "MSND Pinnacle config port 250,260,270" |
@@ -242,7 +241,7 @@ config MSNDPIN_CFG | |||
242 | Mode". | 241 | Mode". |
243 | 242 | ||
244 | comment "Pinnacle-specific Device Configuration (0 disables)" | 243 | comment "Pinnacle-specific Device Configuration (0 disables)" |
245 | depends on SOUND_PRIME && SOUND_MSNDPIN=y && MSNDPIN_NONPNP | 244 | depends on SOUND_MSNDPIN=y && MSNDPIN_NONPNP |
246 | 245 | ||
247 | config MSNDPIN_MPU_IO | 246 | config MSNDPIN_MPU_IO |
248 | hex "MSND Pinnacle MPU I/O (e.g. 330)" | 247 | hex "MSND Pinnacle MPU I/O (e.g. 330)" |
@@ -294,7 +293,7 @@ config MSNDPIN_JOYSTICK_IO | |||
294 | 293 | ||
295 | config MSND_FIFOSIZE | 294 | config MSND_FIFOSIZE |
296 | int "MSND buffer size (kB)" | 295 | int "MSND buffer size (kB)" |
297 | depends on SOUND_PRIME && (SOUND_MSNDPIN=y || SOUND_MSNDCLAS=y) | 296 | depends on SOUND_MSNDPIN=y || SOUND_MSNDCLAS=y |
298 | default "128" | 297 | default "128" |
299 | help | 298 | help |
300 | Configures the size of each audio buffer, in kilobytes, for | 299 | Configures the size of each audio buffer, in kilobytes, for |
@@ -302,9 +301,9 @@ config MSND_FIFOSIZE | |||
302 | and Pinnacle). Larger values reduce the chance of data overruns at | 301 | and Pinnacle). Larger values reduce the chance of data overruns at |
303 | the expense of overall latency. If unsure, use the default. | 302 | the expense of overall latency. If unsure, use the default. |
304 | 303 | ||
305 | config SOUND_OSS | 304 | menuconfig SOUND_OSS |
306 | tristate "OSS sound modules" | 305 | tristate "OSS sound modules" |
307 | depends on SOUND_PRIME && ISA_DMA_API && VIRT_TO_BUS | 306 | depends on ISA_DMA_API && VIRT_TO_BUS |
308 | help | 307 | help |
309 | OSS is the Open Sound System suite of sound card drivers. They make | 308 | OSS is the Open Sound System suite of sound card drivers. They make |
310 | sound programming easier since they provide a common API. Say Y or | 309 | sound programming easier since they provide a common API. Say Y or |
@@ -312,16 +311,16 @@ config SOUND_OSS | |||
312 | driver for your sound card above, then pick your driver from the | 311 | driver for your sound card above, then pick your driver from the |
313 | list below. | 312 | list below. |
314 | 313 | ||
314 | if SOUND_OSS | ||
315 | |||
315 | config SOUND_TRACEINIT | 316 | config SOUND_TRACEINIT |
316 | bool "Verbose initialisation" | 317 | bool "Verbose initialisation" |
317 | depends on SOUND_OSS | ||
318 | help | 318 | help |
319 | Verbose soundcard initialization -- affects the format of autoprobe | 319 | Verbose soundcard initialization -- affects the format of autoprobe |
320 | and initialization messages at boot time. | 320 | and initialization messages at boot time. |
321 | 321 | ||
322 | config SOUND_DMAP | 322 | config SOUND_DMAP |
323 | bool "Persistent DMA buffers" | 323 | bool "Persistent DMA buffers" |
324 | depends on SOUND_OSS | ||
325 | ---help--- | 324 | ---help--- |
326 | Linux can often have problems allocating DMA buffers for ISA sound | 325 | Linux can often have problems allocating DMA buffers for ISA sound |
327 | cards on machines with more than 16MB of RAM. This is because ISA | 326 | cards on machines with more than 16MB of RAM. This is because ISA |
@@ -338,8 +337,6 @@ config SOUND_DMAP | |||
338 | 337 | ||
339 | config SOUND_SSCAPE | 338 | config SOUND_SSCAPE |
340 | tristate "Ensoniq SoundScape support" | 339 | tristate "Ensoniq SoundScape support" |
341 | depends on SOUND_OSS | ||
342 | depends on VIRT_TO_BUS | ||
343 | help | 340 | help |
344 | Answer Y if you have a sound card based on the Ensoniq SoundScape | 341 | Answer Y if you have a sound card based on the Ensoniq SoundScape |
345 | chipset. Such cards are being manufactured at least by Ensoniq, Spea | 342 | chipset. Such cards are being manufactured at least by Ensoniq, Spea |
@@ -352,13 +349,11 @@ config SOUND_SSCAPE | |||
352 | 349 | ||
353 | config SOUND_VMIDI | 350 | config SOUND_VMIDI |
354 | tristate "Loopback MIDI device support" | 351 | tristate "Loopback MIDI device support" |
355 | depends on SOUND_OSS | ||
356 | help | 352 | help |
357 | Support for MIDI loopback on port 1 or 2. | 353 | Support for MIDI loopback on port 1 or 2. |
358 | 354 | ||
359 | config SOUND_TRIX | 355 | config SOUND_TRIX |
360 | tristate "MediaTrix AudioTrix Pro support" | 356 | tristate "MediaTrix AudioTrix Pro support" |
361 | depends on SOUND_OSS | ||
362 | help | 357 | help |
363 | Answer Y if you have the AudioTriX Pro sound card manufactured | 358 | Answer Y if you have the AudioTriX Pro sound card manufactured |
364 | by MediaTrix. | 359 | by MediaTrix. |
@@ -382,7 +377,6 @@ config TRIX_BOOT_FILE | |||
382 | 377 | ||
383 | config SOUND_MSS | 378 | config SOUND_MSS |
384 | tristate "Microsoft Sound System support" | 379 | tristate "Microsoft Sound System support" |
385 | depends on SOUND_OSS | ||
386 | ---help--- | 380 | ---help--- |
387 | Again think carefully before answering Y to this question. It's | 381 | Again think carefully before answering Y to this question. It's |
388 | safe to answer Y if you have the original Windows Sound System card | 382 | safe to answer Y if you have the original Windows Sound System card |
@@ -414,7 +408,6 @@ config SOUND_MSS | |||
414 | 408 | ||
415 | config SOUND_MPU401 | 409 | config SOUND_MPU401 |
416 | tristate "MPU-401 support (NOT for SB16)" | 410 | tristate "MPU-401 support (NOT for SB16)" |
417 | depends on SOUND_OSS | ||
418 | ---help--- | 411 | ---help--- |
419 | Be careful with this question. The MPU401 interface is supported by | 412 | Be careful with this question. The MPU401 interface is supported by |
420 | all sound cards. However, some natively supported cards have their | 413 | all sound cards. However, some natively supported cards have their |
@@ -430,7 +423,6 @@ config SOUND_MPU401 | |||
430 | 423 | ||
431 | config SOUND_PAS | 424 | config SOUND_PAS |
432 | tristate "ProAudioSpectrum 16 support" | 425 | tristate "ProAudioSpectrum 16 support" |
433 | depends on SOUND_OSS | ||
434 | ---help--- | 426 | ---help--- |
435 | Answer Y only if you have a Pro Audio Spectrum 16, ProAudio Studio | 427 | Answer Y only if you have a Pro Audio Spectrum 16, ProAudio Studio |
436 | 16 or Logitech SoundMan 16 sound card. Answer N if you have some | 428 | 16 or Logitech SoundMan 16 sound card. Answer N if you have some |
@@ -452,7 +444,6 @@ config PAS_JOYSTICK | |||
452 | 444 | ||
453 | config SOUND_PSS | 445 | config SOUND_PSS |
454 | tristate "PSS (AD1848, ADSP-2115, ESC614) support" | 446 | tristate "PSS (AD1848, ADSP-2115, ESC614) support" |
455 | depends on SOUND_OSS | ||
456 | help | 447 | help |
457 | Answer Y or M if you have an Orchid SW32, Cardinal DSP16, Beethoven | 448 | Answer Y or M if you have an Orchid SW32, Cardinal DSP16, Beethoven |
458 | ADSP-16 or some other card based on the PSS chipset (AD1848 codec + | 449 | ADSP-16 or some other card based on the PSS chipset (AD1848 codec + |
@@ -495,7 +486,6 @@ config PSS_BOOT_FILE | |||
495 | 486 | ||
496 | config SOUND_SB | 487 | config SOUND_SB |
497 | tristate "100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support" | 488 | tristate "100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support" |
498 | depends on SOUND_OSS | ||
499 | ---help--- | 489 | ---help--- |
500 | Answer Y if you have an original Sound Blaster card made by Creative | 490 | Answer Y if you have an original Sound Blaster card made by Creative |
501 | Labs or a 100% hardware compatible clone (like the Thunderboard or | 491 | Labs or a 100% hardware compatible clone (like the Thunderboard or |
@@ -522,7 +512,6 @@ config SOUND_SB | |||
522 | 512 | ||
523 | config SOUND_YM3812 | 513 | config SOUND_YM3812 |
524 | tristate "Yamaha FM synthesizer (YM3812/OPL-3) support" | 514 | tristate "Yamaha FM synthesizer (YM3812/OPL-3) support" |
525 | depends on SOUND_OSS | ||
526 | ---help--- | 515 | ---help--- |
527 | Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4). | 516 | Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4). |
528 | Answering Y is usually a safe and recommended choice, however some | 517 | Answering Y is usually a safe and recommended choice, however some |
@@ -538,7 +527,6 @@ config SOUND_YM3812 | |||
538 | 527 | ||
539 | config SOUND_UART6850 | 528 | config SOUND_UART6850 |
540 | tristate "6850 UART support" | 529 | tristate "6850 UART support" |
541 | depends on SOUND_OSS | ||
542 | help | 530 | help |
543 | This option enables support for MIDI interfaces based on the 6850 | 531 | This option enables support for MIDI interfaces based on the 6850 |
544 | UART chip. This interface is rarely found on sound cards. It's safe | 532 | UART chip. This interface is rarely found on sound cards. It's safe |
@@ -549,7 +537,6 @@ config SOUND_UART6850 | |||
549 | 537 | ||
550 | config SOUND_AEDSP16 | 538 | config SOUND_AEDSP16 |
551 | tristate "Gallant Audio Cards (SC-6000 and SC-6600 based)" | 539 | tristate "Gallant Audio Cards (SC-6000 and SC-6600 based)" |
552 | depends on SOUND_OSS | ||
553 | ---help--- | 540 | ---help--- |
554 | Answer Y if you have a Gallant's Audio Excel DSP 16 card. This | 541 | Answer Y if you have a Gallant's Audio Excel DSP 16 card. This |
555 | driver supports Audio Excel DSP 16 but not the III nor PnP versions | 542 | driver supports Audio Excel DSP 16 but not the III nor PnP versions |
@@ -630,14 +617,14 @@ endchoice | |||
630 | 617 | ||
631 | config SOUND_VIDC | 618 | config SOUND_VIDC |
632 | tristate "VIDC 16-bit sound" | 619 | tristate "VIDC 16-bit sound" |
633 | depends on ARM && (ARCH_ACORN || ARCH_CLPS7500) && SOUND_OSS | 620 | depends on ARM && (ARCH_ACORN || ARCH_CLPS7500) |
634 | help | 621 | help |
635 | 16-bit support for the VIDC onboard sound hardware found on Acorn | 622 | 16-bit support for the VIDC onboard sound hardware found on Acorn |
636 | machines. | 623 | machines. |
637 | 624 | ||
638 | config SOUND_WAVEARTIST | 625 | config SOUND_WAVEARTIST |
639 | tristate "Netwinder WaveArtist" | 626 | tristate "Netwinder WaveArtist" |
640 | depends on ARM && SOUND_OSS && ARCH_NETWINDER | 627 | depends on ARM && ARCH_NETWINDER |
641 | help | 628 | help |
642 | Say Y here to include support for the Rockwell WaveArtist sound | 629 | Say Y here to include support for the Rockwell WaveArtist sound |
643 | system. This driver is mainly for the NetWinder. | 630 | system. This driver is mainly for the NetWinder. |
@@ -646,9 +633,11 @@ config SOUND_KAHLUA | |||
646 | tristate "XpressAudio Sound Blaster emulation" | 633 | tristate "XpressAudio Sound Blaster emulation" |
647 | depends on SOUND_SB | 634 | depends on SOUND_SB |
648 | 635 | ||
636 | endif # SOUND_OSS | ||
637 | |||
649 | config SOUND_SH_DAC_AUDIO | 638 | config SOUND_SH_DAC_AUDIO |
650 | tristate "SuperH DAC audio support" | 639 | tristate "SuperH DAC audio support" |
651 | depends on SOUND_PRIME && CPU_SH3 | 640 | depends on CPU_SH3 |
652 | 641 | ||
653 | config SOUND_SH_DAC_AUDIO_CHANNEL | 642 | config SOUND_SH_DAC_AUDIO_CHANNEL |
654 | int "DAC channel" | 643 | int "DAC channel" |
diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c index a003c0ea9303..95fc5c681755 100644 --- a/sound/oss/dmasound/dmasound_core.c +++ b/sound/oss/dmasound/dmasound_core.c | |||
@@ -211,10 +211,6 @@ static int state_unit = -1; | |||
211 | static int irq_installed; | 211 | static int irq_installed; |
212 | #endif /* MODULE */ | 212 | #endif /* MODULE */ |
213 | 213 | ||
214 | /* software implemented recording volume! */ | ||
215 | uint software_input_volume = SW_INPUT_VOLUME_SCALE * SW_INPUT_VOLUME_DEFAULT; | ||
216 | EXPORT_SYMBOL(software_input_volume); | ||
217 | |||
218 | /* control over who can modify resources shared between play/record */ | 214 | /* control over who can modify resources shared between play/record */ |
219 | static mode_t shared_resource_owner; | 215 | static mode_t shared_resource_owner; |
220 | static int shared_resources_initialised; | 216 | static int shared_resources_initialised; |
@@ -1188,7 +1184,7 @@ static struct { | |||
1188 | 1184 | ||
1189 | /* publish this function for use by low-level code, if required */ | 1185 | /* publish this function for use by low-level code, if required */ |
1190 | 1186 | ||
1191 | char *get_afmt_string(int afmt) | 1187 | static char *get_afmt_string(int afmt) |
1192 | { | 1188 | { |
1193 | switch(afmt) { | 1189 | switch(afmt) { |
1194 | case AFMT_MU_LAW: | 1190 | case AFMT_MU_LAW: |
@@ -1551,4 +1547,3 @@ EXPORT_SYMBOL(dmasound_catchRadius); | |||
1551 | EXPORT_SYMBOL(dmasound_ulaw2dma8); | 1547 | EXPORT_SYMBOL(dmasound_ulaw2dma8); |
1552 | EXPORT_SYMBOL(dmasound_alaw2dma8); | 1548 | EXPORT_SYMBOL(dmasound_alaw2dma8); |
1553 | #endif | 1549 | #endif |
1554 | EXPORT_SYMBOL(get_afmt_string) ; | ||
diff --git a/sound/oss/dmasound/dmasound_paula.c b/sound/oss/dmasound/dmasound_paula.c index 202e8103dc4d..06e9e88e4c05 100644 --- a/sound/oss/dmasound/dmasound_paula.c +++ b/sound/oss/dmasound/dmasound_paula.c | |||
@@ -710,7 +710,7 @@ static MACHINE machAmiga = { | |||
710 | /*** Config & Setup **********************************************************/ | 710 | /*** Config & Setup **********************************************************/ |
711 | 711 | ||
712 | 712 | ||
713 | int __init dmasound_paula_init(void) | 713 | static int __init dmasound_paula_init(void) |
714 | { | 714 | { |
715 | int err; | 715 | int err; |
716 | 716 | ||
diff --git a/sound/oss/dmasound/dmasound_q40.c b/sound/oss/dmasound/dmasound_q40.c index b3379dd7ca5e..1855b14d90c3 100644 --- a/sound/oss/dmasound/dmasound_q40.c +++ b/sound/oss/dmasound/dmasound_q40.c | |||
@@ -611,7 +611,7 @@ static MACHINE machQ40 = { | |||
611 | /*** Config & Setup **********************************************************/ | 611 | /*** Config & Setup **********************************************************/ |
612 | 612 | ||
613 | 613 | ||
614 | int __init dmasound_q40_init(void) | 614 | static int __init dmasound_q40_init(void) |
615 | { | 615 | { |
616 | if (MACH_IS_Q40) { | 616 | if (MACH_IS_Q40) { |
617 | dmasound.mach = machQ40; | 617 | dmasound.mach = machQ40; |
diff --git a/sound/oss/msnd.c b/sound/oss/msnd.c index ba38d6200099..e4282d93a1aa 100644 --- a/sound/oss/msnd.c +++ b/sound/oss/msnd.c | |||
@@ -20,8 +20,6 @@ | |||
20 | * along with this program; if not, write to the Free Software | 20 | * along with this program; if not, write to the Free Software |
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
22 | * | 22 | * |
23 | * $Id: msnd.c,v 1.17 1999/03/21 16:50:09 andrewtv Exp $ | ||
24 | * | ||
25 | ********************************************************************/ | 23 | ********************************************************************/ |
26 | 24 | ||
27 | #include <linux/module.h> | 25 | #include <linux/module.h> |
diff --git a/sound/oss/msnd.h b/sound/oss/msnd.h index d0ca582c4583..61b3955481c5 100644 --- a/sound/oss/msnd.h +++ b/sound/oss/msnd.h | |||
@@ -24,8 +24,6 @@ | |||
24 | * along with this program; if not, write to the Free Software | 24 | * along with this program; if not, write to the Free Software |
25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
26 | * | 26 | * |
27 | * $Id: msnd.h,v 1.36 1999/03/21 17:05:42 andrewtv Exp $ | ||
28 | * | ||
29 | ********************************************************************/ | 27 | ********************************************************************/ |
30 | #ifndef __MSND_H | 28 | #ifndef __MSND_H |
31 | #define __MSND_H | 29 | #define __MSND_H |
diff --git a/sound/oss/msnd_classic.h b/sound/oss/msnd_classic.h index 7ffea5267f96..1a17dde2f650 100644 --- a/sound/oss/msnd_classic.h +++ b/sound/oss/msnd_classic.h | |||
@@ -24,8 +24,6 @@ | |||
24 | * along with this program; if not, write to the Free Software | 24 | * along with this program; if not, write to the Free Software |
25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
26 | * | 26 | * |
27 | * $Id: msnd_classic.h,v 1.10 1999/03/21 17:36:09 andrewtv Exp $ | ||
28 | * | ||
29 | ********************************************************************/ | 27 | ********************************************************************/ |
30 | #ifndef __MSND_CLASSIC_H | 28 | #ifndef __MSND_CLASSIC_H |
31 | #define __MSND_CLASSIC_H | 29 | #define __MSND_CLASSIC_H |
diff --git a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c index f1f49ebf752e..bf27e008f465 100644 --- a/sound/oss/msnd_pinnacle.c +++ b/sound/oss/msnd_pinnacle.c | |||
@@ -29,13 +29,8 @@ | |||
29 | * along with this program; if not, write to the Free Software | 29 | * along with this program; if not, write to the Free Software |
30 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 30 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
31 | * | 31 | * |
32 | * $Id: msnd_pinnacle.c,v 1.8 2000/12/30 00:33:21 sycamore Exp $ | ||
33 | * | ||
34 | * 12-3-2000 Modified IO port validation Steve Sycamore | 32 | * 12-3-2000 Modified IO port validation Steve Sycamore |
35 | * | 33 | * |
36 | * | ||
37 | * $$$: msnd_pinnacle.c,v 1.75 1999/03/21 16:50:09 andrewtv $$$ $ | ||
38 | * | ||
39 | ********************************************************************/ | 34 | ********************************************************************/ |
40 | 35 | ||
41 | #include <linux/kernel.h> | 36 | #include <linux/kernel.h> |
diff --git a/sound/oss/msnd_pinnacle.h b/sound/oss/msnd_pinnacle.h index cce911487004..c18d66cbbe3f 100644 --- a/sound/oss/msnd_pinnacle.h +++ b/sound/oss/msnd_pinnacle.h | |||
@@ -24,8 +24,6 @@ | |||
24 | * along with this program; if not, write to the Free Software | 24 | * along with this program; if not, write to the Free Software |
25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
26 | * | 26 | * |
27 | * $Id: msnd_pinnacle.h,v 1.11 1999/03/21 17:36:09 andrewtv Exp $ | ||
28 | * | ||
29 | ********************************************************************/ | 27 | ********************************************************************/ |
30 | #ifndef __MSND_PINNACLE_H | 28 | #ifndef __MSND_PINNACLE_H |
31 | #define __MSND_PINNACLE_H | 29 | #define __MSND_PINNACLE_H |
diff --git a/sound/parisc/Kconfig b/sound/parisc/Kconfig index a5a7f9d75d05..9b61d95010f0 100644 --- a/sound/parisc/Kconfig +++ b/sound/parisc/Kconfig | |||
@@ -1,15 +1,20 @@ | |||
1 | # ALSA PA-RISC drivers | 1 | # ALSA PA-RISC drivers |
2 | 2 | ||
3 | menu "GSC devices" | 3 | menuconfig SND_GSC |
4 | depends on SND!=n && GSC | 4 | bool "GSC sound devices" |
5 | depends on GSC | ||
6 | default y | ||
7 | help | ||
8 | Support for GSC sound devices on PA-RISC architectures. | ||
9 | |||
10 | if SND_GSC | ||
5 | 11 | ||
6 | config SND_HARMONY | 12 | config SND_HARMONY |
7 | tristate "Harmony/Vivace sound chip" | 13 | tristate "Harmony/Vivace sound chip" |
8 | depends on SND | ||
9 | select SND_PCM | 14 | select SND_PCM |
10 | help | 15 | help |
11 | Say 'Y' or 'M' to include support for the Harmony/Vivace sound | 16 | Say 'Y' or 'M' to include support for the Harmony/Vivace sound |
12 | chip found in most GSC-based PA-RISC workstations. It's frequently | 17 | chip found in most GSC-based PA-RISC workstations. It's frequently |
13 | provided as part of the Lasi multi-function IC. | 18 | provided as part of the Lasi multi-function IC. |
14 | 19 | ||
15 | endmenu | 20 | endif # SND_GSC |
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 7e4742109572..8fe5dac39428 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig | |||
@@ -1,11 +1,16 @@ | |||
1 | # ALSA PCI drivers | 1 | # ALSA PCI drivers |
2 | 2 | ||
3 | menu "PCI devices" | 3 | menuconfig SND_PCI |
4 | depends on SND!=n && PCI | 4 | bool "PCI sound devices" |
5 | depends on PCI | ||
6 | default y | ||
7 | help | ||
8 | Support for sound devices connected via the PCI bus. | ||
9 | |||
10 | if SND_PCI | ||
5 | 11 | ||
6 | config SND_AD1889 | 12 | config SND_AD1889 |
7 | tristate "Analog Devices AD1889" | 13 | tristate "Analog Devices AD1889" |
8 | depends on SND | ||
9 | select SND_AC97_CODEC | 14 | select SND_AC97_CODEC |
10 | help | 15 | help |
11 | Say Y here to include support for the integrated AC97 sound | 16 | Say Y here to include support for the integrated AC97 sound |
@@ -17,7 +22,6 @@ config SND_AD1889 | |||
17 | 22 | ||
18 | config SND_ALS300 | 23 | config SND_ALS300 |
19 | tristate "Avance Logic ALS300/ALS300+" | 24 | tristate "Avance Logic ALS300/ALS300+" |
20 | depends on SND | ||
21 | select SND_PCM | 25 | select SND_PCM |
22 | select SND_AC97_CODEC | 26 | select SND_AC97_CODEC |
23 | select SND_OPL3_LIB | 27 | select SND_OPL3_LIB |
@@ -29,7 +33,7 @@ config SND_ALS300 | |||
29 | 33 | ||
30 | config SND_ALS4000 | 34 | config SND_ALS4000 |
31 | tristate "Avance Logic ALS4000" | 35 | tristate "Avance Logic ALS4000" |
32 | depends on SND && ISA_DMA_API | 36 | depends on ISA_DMA_API |
33 | select SND_OPL3_LIB | 37 | select SND_OPL3_LIB |
34 | select SND_MPU401_UART | 38 | select SND_MPU401_UART |
35 | select SND_PCM | 39 | select SND_PCM |
@@ -43,7 +47,6 @@ config SND_ALS4000 | |||
43 | 47 | ||
44 | config SND_ALI5451 | 48 | config SND_ALI5451 |
45 | tristate "ALi M5451 PCI Audio Controller" | 49 | tristate "ALi M5451 PCI Audio Controller" |
46 | depends on SND | ||
47 | select SND_MPU401_UART | 50 | select SND_MPU401_UART |
48 | select SND_AC97_CODEC | 51 | select SND_AC97_CODEC |
49 | help | 52 | help |
@@ -57,7 +60,6 @@ config SND_ALI5451 | |||
57 | 60 | ||
58 | config SND_ATIIXP | 61 | config SND_ATIIXP |
59 | tristate "ATI IXP AC97 Controller" | 62 | tristate "ATI IXP AC97 Controller" |
60 | depends on SND | ||
61 | select SND_AC97_CODEC | 63 | select SND_AC97_CODEC |
62 | help | 64 | help |
63 | Say Y here to include support for the integrated AC97 sound | 65 | Say Y here to include support for the integrated AC97 sound |
@@ -69,7 +71,6 @@ config SND_ATIIXP | |||
69 | 71 | ||
70 | config SND_ATIIXP_MODEM | 72 | config SND_ATIIXP_MODEM |
71 | tristate "ATI IXP Modem" | 73 | tristate "ATI IXP Modem" |
72 | depends on SND | ||
73 | select SND_AC97_CODEC | 74 | select SND_AC97_CODEC |
74 | help | 75 | help |
75 | Say Y here to include support for the integrated MC97 modem on | 76 | Say Y here to include support for the integrated MC97 modem on |
@@ -80,7 +81,6 @@ config SND_ATIIXP_MODEM | |||
80 | 81 | ||
81 | config SND_AU8810 | 82 | config SND_AU8810 |
82 | tristate "Aureal Advantage" | 83 | tristate "Aureal Advantage" |
83 | depends on SND | ||
84 | select SND_MPU401_UART | 84 | select SND_MPU401_UART |
85 | select SND_AC97_CODEC | 85 | select SND_AC97_CODEC |
86 | help | 86 | help |
@@ -95,7 +95,6 @@ config SND_AU8810 | |||
95 | 95 | ||
96 | config SND_AU8820 | 96 | config SND_AU8820 |
97 | tristate "Aureal Vortex" | 97 | tristate "Aureal Vortex" |
98 | depends on SND | ||
99 | select SND_MPU401_UART | 98 | select SND_MPU401_UART |
100 | select SND_AC97_CODEC | 99 | select SND_AC97_CODEC |
101 | help | 100 | help |
@@ -109,7 +108,6 @@ config SND_AU8820 | |||
109 | 108 | ||
110 | config SND_AU8830 | 109 | config SND_AU8830 |
111 | tristate "Aureal Vortex 2" | 110 | tristate "Aureal Vortex 2" |
112 | depends on SND | ||
113 | select SND_MPU401_UART | 111 | select SND_MPU401_UART |
114 | select SND_AC97_CODEC | 112 | select SND_AC97_CODEC |
115 | help | 113 | help |
@@ -124,7 +122,6 @@ config SND_AU8830 | |||
124 | 122 | ||
125 | config SND_AW2 | 123 | config SND_AW2 |
126 | tristate "Emagic Audiowerk 2" | 124 | tristate "Emagic Audiowerk 2" |
127 | depends on SND | ||
128 | help | 125 | help |
129 | Say Y here to include support for Emagic Audiowerk 2 soundcards. | 126 | Say Y here to include support for Emagic Audiowerk 2 soundcards. |
130 | 127 | ||
@@ -139,7 +136,7 @@ config SND_AW2 | |||
139 | 136 | ||
140 | config SND_AZT3328 | 137 | config SND_AZT3328 |
141 | tristate "Aztech AZF3328 / PCI168 (EXPERIMENTAL)" | 138 | tristate "Aztech AZF3328 / PCI168 (EXPERIMENTAL)" |
142 | depends on SND && EXPERIMENTAL | 139 | depends on EXPERIMENTAL |
143 | select SND_OPL3_LIB | 140 | select SND_OPL3_LIB |
144 | select SND_MPU401_UART | 141 | select SND_MPU401_UART |
145 | select SND_PCM | 142 | select SND_PCM |
@@ -152,7 +149,6 @@ config SND_AZT3328 | |||
152 | 149 | ||
153 | config SND_BT87X | 150 | config SND_BT87X |
154 | tristate "Bt87x Audio Capture" | 151 | tristate "Bt87x Audio Capture" |
155 | depends on SND | ||
156 | select SND_PCM | 152 | select SND_PCM |
157 | help | 153 | help |
158 | If you want to record audio from TV cards based on | 154 | If you want to record audio from TV cards based on |
@@ -174,7 +170,6 @@ config SND_BT87X_OVERCLOCK | |||
174 | 170 | ||
175 | config SND_CA0106 | 171 | config SND_CA0106 |
176 | tristate "SB Audigy LS / Live 24bit" | 172 | tristate "SB Audigy LS / Live 24bit" |
177 | depends on SND | ||
178 | select SND_AC97_CODEC | 173 | select SND_AC97_CODEC |
179 | select SND_RAWMIDI | 174 | select SND_RAWMIDI |
180 | select SND_VMASTER | 175 | select SND_VMASTER |
@@ -187,7 +182,6 @@ config SND_CA0106 | |||
187 | 182 | ||
188 | config SND_CMIPCI | 183 | config SND_CMIPCI |
189 | tristate "C-Media 8338, 8738, 8768, 8770" | 184 | tristate "C-Media 8338, 8738, 8768, 8770" |
190 | depends on SND | ||
191 | select SND_OPL3_LIB | 185 | select SND_OPL3_LIB |
192 | select SND_MPU401_UART | 186 | select SND_MPU401_UART |
193 | select SND_PCM | 187 | select SND_PCM |
@@ -201,13 +195,11 @@ config SND_CMIPCI | |||
201 | 195 | ||
202 | config SND_OXYGEN_LIB | 196 | config SND_OXYGEN_LIB |
203 | tristate | 197 | tristate |
204 | depends on SND | ||
205 | select SND_PCM | 198 | select SND_PCM |
206 | select SND_MPU401_UART | 199 | select SND_MPU401_UART |
207 | 200 | ||
208 | config SND_OXYGEN | 201 | config SND_OXYGEN |
209 | tristate "C-Media 8788 (Oxygen)" | 202 | tristate "C-Media 8788 (Oxygen)" |
210 | depends on SND | ||
211 | select SND_OXYGEN_LIB | 203 | select SND_OXYGEN_LIB |
212 | help | 204 | help |
213 | Say Y here to include support for sound cards based on the | 205 | Say Y here to include support for sound cards based on the |
@@ -225,7 +217,6 @@ config SND_OXYGEN | |||
225 | 217 | ||
226 | config SND_CS4281 | 218 | config SND_CS4281 |
227 | tristate "Cirrus Logic (Sound Fusion) CS4281" | 219 | tristate "Cirrus Logic (Sound Fusion) CS4281" |
228 | depends on SND | ||
229 | select SND_OPL3_LIB | 220 | select SND_OPL3_LIB |
230 | select SND_RAWMIDI | 221 | select SND_RAWMIDI |
231 | select SND_AC97_CODEC | 222 | select SND_AC97_CODEC |
@@ -237,7 +228,6 @@ config SND_CS4281 | |||
237 | 228 | ||
238 | config SND_CS46XX | 229 | config SND_CS46XX |
239 | tristate "Cirrus Logic (Sound Fusion) CS4280/CS461x/CS462x/CS463x" | 230 | tristate "Cirrus Logic (Sound Fusion) CS4280/CS461x/CS462x/CS463x" |
240 | depends on SND | ||
241 | select SND_RAWMIDI | 231 | select SND_RAWMIDI |
242 | select SND_AC97_CODEC | 232 | select SND_AC97_CODEC |
243 | help | 233 | help |
@@ -258,7 +248,7 @@ config SND_CS46XX_NEW_DSP | |||
258 | 248 | ||
259 | config SND_CS5530 | 249 | config SND_CS5530 |
260 | tristate "CS5530 Audio" | 250 | tristate "CS5530 Audio" |
261 | depends on SND && ISA_DMA_API | 251 | depends on ISA_DMA_API |
262 | select SND_SB16_DSP | 252 | select SND_SB16_DSP |
263 | help | 253 | help |
264 | Say Y here to include support for audio on Cyrix/NatSemi CS5530 chips. | 254 | Say Y here to include support for audio on Cyrix/NatSemi CS5530 chips. |
@@ -268,7 +258,7 @@ config SND_CS5530 | |||
268 | 258 | ||
269 | config SND_CS5535AUDIO | 259 | config SND_CS5535AUDIO |
270 | tristate "CS5535/CS5536 Audio" | 260 | tristate "CS5535/CS5536 Audio" |
271 | depends on SND && X86 && !X86_64 | 261 | depends on X86 && !X86_64 |
272 | select SND_PCM | 262 | select SND_PCM |
273 | select SND_AC97_CODEC | 263 | select SND_AC97_CODEC |
274 | help | 264 | help |
@@ -286,7 +276,6 @@ config SND_CS5535AUDIO | |||
286 | 276 | ||
287 | config SND_DARLA20 | 277 | config SND_DARLA20 |
288 | tristate "(Echoaudio) Darla20" | 278 | tristate "(Echoaudio) Darla20" |
289 | depends on SND | ||
290 | select FW_LOADER | 279 | select FW_LOADER |
291 | select SND_PCM | 280 | select SND_PCM |
292 | help | 281 | help |
@@ -297,7 +286,6 @@ config SND_DARLA20 | |||
297 | 286 | ||
298 | config SND_GINA20 | 287 | config SND_GINA20 |
299 | tristate "(Echoaudio) Gina20" | 288 | tristate "(Echoaudio) Gina20" |
300 | depends on SND | ||
301 | select FW_LOADER | 289 | select FW_LOADER |
302 | select SND_PCM | 290 | select SND_PCM |
303 | help | 291 | help |
@@ -308,7 +296,6 @@ config SND_GINA20 | |||
308 | 296 | ||
309 | config SND_LAYLA20 | 297 | config SND_LAYLA20 |
310 | tristate "(Echoaudio) Layla20" | 298 | tristate "(Echoaudio) Layla20" |
311 | depends on SND | ||
312 | select FW_LOADER | 299 | select FW_LOADER |
313 | select SND_RAWMIDI | 300 | select SND_RAWMIDI |
314 | select SND_PCM | 301 | select SND_PCM |
@@ -320,7 +307,6 @@ config SND_LAYLA20 | |||
320 | 307 | ||
321 | config SND_DARLA24 | 308 | config SND_DARLA24 |
322 | tristate "(Echoaudio) Darla24" | 309 | tristate "(Echoaudio) Darla24" |
323 | depends on SND | ||
324 | select FW_LOADER | 310 | select FW_LOADER |
325 | select SND_PCM | 311 | select SND_PCM |
326 | help | 312 | help |
@@ -331,7 +317,6 @@ config SND_DARLA24 | |||
331 | 317 | ||
332 | config SND_GINA24 | 318 | config SND_GINA24 |
333 | tristate "(Echoaudio) Gina24" | 319 | tristate "(Echoaudio) Gina24" |
334 | depends on SND | ||
335 | select FW_LOADER | 320 | select FW_LOADER |
336 | select SND_PCM | 321 | select SND_PCM |
337 | help | 322 | help |
@@ -342,7 +327,6 @@ config SND_GINA24 | |||
342 | 327 | ||
343 | config SND_LAYLA24 | 328 | config SND_LAYLA24 |
344 | tristate "(Echoaudio) Layla24" | 329 | tristate "(Echoaudio) Layla24" |
345 | depends on SND | ||
346 | select FW_LOADER | 330 | select FW_LOADER |
347 | select SND_RAWMIDI | 331 | select SND_RAWMIDI |
348 | select SND_PCM | 332 | select SND_PCM |
@@ -354,7 +338,6 @@ config SND_LAYLA24 | |||
354 | 338 | ||
355 | config SND_MONA | 339 | config SND_MONA |
356 | tristate "(Echoaudio) Mona" | 340 | tristate "(Echoaudio) Mona" |
357 | depends on SND | ||
358 | select FW_LOADER | 341 | select FW_LOADER |
359 | select SND_RAWMIDI | 342 | select SND_RAWMIDI |
360 | select SND_PCM | 343 | select SND_PCM |
@@ -366,7 +349,6 @@ config SND_MONA | |||
366 | 349 | ||
367 | config SND_MIA | 350 | config SND_MIA |
368 | tristate "(Echoaudio) Mia" | 351 | tristate "(Echoaudio) Mia" |
369 | depends on SND | ||
370 | select FW_LOADER | 352 | select FW_LOADER |
371 | select SND_RAWMIDI | 353 | select SND_RAWMIDI |
372 | select SND_PCM | 354 | select SND_PCM |
@@ -378,7 +360,6 @@ config SND_MIA | |||
378 | 360 | ||
379 | config SND_ECHO3G | 361 | config SND_ECHO3G |
380 | tristate "(Echoaudio) 3G cards" | 362 | tristate "(Echoaudio) 3G cards" |
381 | depends on SND | ||
382 | select FW_LOADER | 363 | select FW_LOADER |
383 | select SND_RAWMIDI | 364 | select SND_RAWMIDI |
384 | select SND_PCM | 365 | select SND_PCM |
@@ -390,7 +371,6 @@ config SND_ECHO3G | |||
390 | 371 | ||
391 | config SND_INDIGO | 372 | config SND_INDIGO |
392 | tristate "(Echoaudio) Indigo" | 373 | tristate "(Echoaudio) Indigo" |
393 | depends on SND | ||
394 | select FW_LOADER | 374 | select FW_LOADER |
395 | select SND_PCM | 375 | select SND_PCM |
396 | help | 376 | help |
@@ -401,7 +381,6 @@ config SND_INDIGO | |||
401 | 381 | ||
402 | config SND_INDIGOIO | 382 | config SND_INDIGOIO |
403 | tristate "(Echoaudio) Indigo IO" | 383 | tristate "(Echoaudio) Indigo IO" |
404 | depends on SND | ||
405 | select FW_LOADER | 384 | select FW_LOADER |
406 | select SND_PCM | 385 | select SND_PCM |
407 | help | 386 | help |
@@ -412,7 +391,6 @@ config SND_INDIGOIO | |||
412 | 391 | ||
413 | config SND_INDIGODJ | 392 | config SND_INDIGODJ |
414 | tristate "(Echoaudio) Indigo DJ" | 393 | tristate "(Echoaudio) Indigo DJ" |
415 | depends on SND | ||
416 | select FW_LOADER | 394 | select FW_LOADER |
417 | select SND_PCM | 395 | select SND_PCM |
418 | help | 396 | help |
@@ -423,7 +401,6 @@ config SND_INDIGODJ | |||
423 | 401 | ||
424 | config SND_EMU10K1 | 402 | config SND_EMU10K1 |
425 | tristate "Emu10k1 (SB Live!, Audigy, E-mu APS)" | 403 | tristate "Emu10k1 (SB Live!, Audigy, E-mu APS)" |
426 | depends on SND | ||
427 | select FW_LOADER | 404 | select FW_LOADER |
428 | select SND_HWDEP | 405 | select SND_HWDEP |
429 | select SND_RAWMIDI | 406 | select SND_RAWMIDI |
@@ -441,7 +418,6 @@ config SND_EMU10K1 | |||
441 | 418 | ||
442 | config SND_EMU10K1X | 419 | config SND_EMU10K1X |
443 | tristate "Emu10k1X (Dell OEM Version)" | 420 | tristate "Emu10k1X (Dell OEM Version)" |
444 | depends on SND | ||
445 | select SND_AC97_CODEC | 421 | select SND_AC97_CODEC |
446 | select SND_RAWMIDI | 422 | select SND_RAWMIDI |
447 | help | 423 | help |
@@ -453,7 +429,6 @@ config SND_EMU10K1X | |||
453 | 429 | ||
454 | config SND_ENS1370 | 430 | config SND_ENS1370 |
455 | tristate "(Creative) Ensoniq AudioPCI 1370" | 431 | tristate "(Creative) Ensoniq AudioPCI 1370" |
456 | depends on SND | ||
457 | select SND_RAWMIDI | 432 | select SND_RAWMIDI |
458 | select SND_PCM | 433 | select SND_PCM |
459 | help | 434 | help |
@@ -464,7 +439,6 @@ config SND_ENS1370 | |||
464 | 439 | ||
465 | config SND_ENS1371 | 440 | config SND_ENS1371 |
466 | tristate "(Creative) Ensoniq AudioPCI 1371/1373" | 441 | tristate "(Creative) Ensoniq AudioPCI 1371/1373" |
467 | depends on SND | ||
468 | select SND_RAWMIDI | 442 | select SND_RAWMIDI |
469 | select SND_AC97_CODEC | 443 | select SND_AC97_CODEC |
470 | help | 444 | help |
@@ -476,7 +450,6 @@ config SND_ENS1371 | |||
476 | 450 | ||
477 | config SND_ES1938 | 451 | config SND_ES1938 |
478 | tristate "ESS ES1938/1946/1969 (Solo-1)" | 452 | tristate "ESS ES1938/1946/1969 (Solo-1)" |
479 | depends on SND | ||
480 | select SND_OPL3_LIB | 453 | select SND_OPL3_LIB |
481 | select SND_MPU401_UART | 454 | select SND_MPU401_UART |
482 | select SND_AC97_CODEC | 455 | select SND_AC97_CODEC |
@@ -489,7 +462,6 @@ config SND_ES1938 | |||
489 | 462 | ||
490 | config SND_ES1968 | 463 | config SND_ES1968 |
491 | tristate "ESS ES1968/1978 (Maestro-1/2/2E)" | 464 | tristate "ESS ES1968/1978 (Maestro-1/2/2E)" |
492 | depends on SND | ||
493 | select SND_MPU401_UART | 465 | select SND_MPU401_UART |
494 | select SND_AC97_CODEC | 466 | select SND_AC97_CODEC |
495 | help | 467 | help |
@@ -501,7 +473,6 @@ config SND_ES1968 | |||
501 | 473 | ||
502 | config SND_FM801 | 474 | config SND_FM801 |
503 | tristate "ForteMedia FM801" | 475 | tristate "ForteMedia FM801" |
504 | depends on SND | ||
505 | select SND_OPL3_LIB | 476 | select SND_OPL3_LIB |
506 | select SND_MPU401_UART | 477 | select SND_MPU401_UART |
507 | select SND_AC97_CODEC | 478 | select SND_AC97_CODEC |
@@ -528,7 +499,6 @@ config SND_FM801_TEA575X | |||
528 | 499 | ||
529 | config SND_HDA_INTEL | 500 | config SND_HDA_INTEL |
530 | tristate "Intel HD Audio" | 501 | tristate "Intel HD Audio" |
531 | depends on SND | ||
532 | select SND_PCM | 502 | select SND_PCM |
533 | select SND_VMASTER | 503 | select SND_VMASTER |
534 | help | 504 | help |
@@ -637,7 +607,6 @@ config SND_HDA_POWER_SAVE_DEFAULT | |||
637 | 607 | ||
638 | config SND_HDSP | 608 | config SND_HDSP |
639 | tristate "RME Hammerfall DSP Audio" | 609 | tristate "RME Hammerfall DSP Audio" |
640 | depends on SND | ||
641 | select SND_HWDEP | 610 | select SND_HWDEP |
642 | select SND_RAWMIDI | 611 | select SND_RAWMIDI |
643 | select SND_PCM | 612 | select SND_PCM |
@@ -650,7 +619,6 @@ config SND_HDSP | |||
650 | 619 | ||
651 | config SND_HDSPM | 620 | config SND_HDSPM |
652 | tristate "RME Hammerfall DSP MADI" | 621 | tristate "RME Hammerfall DSP MADI" |
653 | depends on SND | ||
654 | select SND_HWDEP | 622 | select SND_HWDEP |
655 | select SND_RAWMIDI | 623 | select SND_RAWMIDI |
656 | select SND_PCM | 624 | select SND_PCM |
@@ -663,7 +631,6 @@ config SND_HDSPM | |||
663 | 631 | ||
664 | config SND_HIFIER | 632 | config SND_HIFIER |
665 | tristate "TempoTec HiFier Fantasia" | 633 | tristate "TempoTec HiFier Fantasia" |
666 | depends on SND | ||
667 | select SND_OXYGEN_LIB | 634 | select SND_OXYGEN_LIB |
668 | help | 635 | help |
669 | Say Y here to include support for the MediaTek/TempoTec HiFier | 636 | Say Y here to include support for the MediaTek/TempoTec HiFier |
@@ -674,7 +641,6 @@ config SND_HIFIER | |||
674 | 641 | ||
675 | config SND_ICE1712 | 642 | config SND_ICE1712 |
676 | tristate "ICEnsemble ICE1712 (Envy24)" | 643 | tristate "ICEnsemble ICE1712 (Envy24)" |
677 | depends on SND | ||
678 | select SND_MPU401_UART | 644 | select SND_MPU401_UART |
679 | select SND_AC97_CODEC | 645 | select SND_AC97_CODEC |
680 | help | 646 | help |
@@ -691,8 +657,7 @@ config SND_ICE1712 | |||
691 | 657 | ||
692 | config SND_ICE1724 | 658 | config SND_ICE1724 |
693 | tristate "ICE/VT1724/1720 (Envy24HT/PT)" | 659 | tristate "ICE/VT1724/1720 (Envy24HT/PT)" |
694 | depends on SND | 660 | select SND_RAWMIDI |
695 | select SND_MPU401_UART | ||
696 | select SND_AC97_CODEC | 661 | select SND_AC97_CODEC |
697 | select SND_VMASTER | 662 | select SND_VMASTER |
698 | help | 663 | help |
@@ -709,7 +674,6 @@ config SND_ICE1724 | |||
709 | 674 | ||
710 | config SND_INTEL8X0 | 675 | config SND_INTEL8X0 |
711 | tristate "Intel/SiS/nVidia/AMD/ALi AC97 Controller" | 676 | tristate "Intel/SiS/nVidia/AMD/ALi AC97 Controller" |
712 | depends on SND | ||
713 | select SND_AC97_CODEC | 677 | select SND_AC97_CODEC |
714 | help | 678 | help |
715 | Say Y here to include support for the integrated AC97 sound | 679 | Say Y here to include support for the integrated AC97 sound |
@@ -722,7 +686,6 @@ config SND_INTEL8X0 | |||
722 | 686 | ||
723 | config SND_INTEL8X0M | 687 | config SND_INTEL8X0M |
724 | tristate "Intel/SiS/nVidia/AMD MC97 Modem" | 688 | tristate "Intel/SiS/nVidia/AMD MC97 Modem" |
725 | depends on SND | ||
726 | select SND_AC97_CODEC | 689 | select SND_AC97_CODEC |
727 | help | 690 | help |
728 | Say Y here to include support for the integrated MC97 modem on | 691 | Say Y here to include support for the integrated MC97 modem on |
@@ -733,7 +696,6 @@ config SND_INTEL8X0M | |||
733 | 696 | ||
734 | config SND_KORG1212 | 697 | config SND_KORG1212 |
735 | tristate "Korg 1212 IO" | 698 | tristate "Korg 1212 IO" |
736 | depends on SND | ||
737 | select FW_LOADER if !SND_KORG1212_FIRMWARE_IN_KERNEL | 699 | select FW_LOADER if !SND_KORG1212_FIRMWARE_IN_KERNEL |
738 | select SND_PCM | 700 | select SND_PCM |
739 | help | 701 | help |
@@ -753,7 +715,6 @@ config SND_KORG1212_FIRMWARE_IN_KERNEL | |||
753 | 715 | ||
754 | config SND_MAESTRO3 | 716 | config SND_MAESTRO3 |
755 | tristate "ESS Allegro/Maestro3" | 717 | tristate "ESS Allegro/Maestro3" |
756 | depends on SND | ||
757 | select FW_LOADER if !SND_MAESTRO3_FIRMWARE_IN_KERNEL | 718 | select FW_LOADER if !SND_MAESTRO3_FIRMWARE_IN_KERNEL |
758 | select SND_AC97_CODEC | 719 | select SND_AC97_CODEC |
759 | help | 720 | help |
@@ -774,7 +735,6 @@ config SND_MAESTRO3_FIRMWARE_IN_KERNEL | |||
774 | 735 | ||
775 | config SND_MIXART | 736 | config SND_MIXART |
776 | tristate "Digigram miXart" | 737 | tristate "Digigram miXart" |
777 | depends on SND | ||
778 | select SND_HWDEP | 738 | select SND_HWDEP |
779 | select SND_PCM | 739 | select SND_PCM |
780 | help | 740 | help |
@@ -786,7 +746,6 @@ config SND_MIXART | |||
786 | 746 | ||
787 | config SND_NM256 | 747 | config SND_NM256 |
788 | tristate "NeoMagic NM256AV/ZX" | 748 | tristate "NeoMagic NM256AV/ZX" |
789 | depends on SND | ||
790 | select SND_AC97_CODEC | 749 | select SND_AC97_CODEC |
791 | help | 750 | help |
792 | Say Y here to include support for NeoMagic NM256AV/ZX chips. | 751 | Say Y here to include support for NeoMagic NM256AV/ZX chips. |
@@ -796,7 +755,6 @@ config SND_NM256 | |||
796 | 755 | ||
797 | config SND_PCXHR | 756 | config SND_PCXHR |
798 | tristate "Digigram PCXHR" | 757 | tristate "Digigram PCXHR" |
799 | depends on SND | ||
800 | select SND_PCM | 758 | select SND_PCM |
801 | select SND_HWDEP | 759 | select SND_HWDEP |
802 | help | 760 | help |
@@ -807,7 +765,6 @@ config SND_PCXHR | |||
807 | 765 | ||
808 | config SND_RIPTIDE | 766 | config SND_RIPTIDE |
809 | tristate "Conexant Riptide" | 767 | tristate "Conexant Riptide" |
810 | depends on SND | ||
811 | select FW_LOADER | 768 | select FW_LOADER |
812 | select SND_OPL3_LIB | 769 | select SND_OPL3_LIB |
813 | select SND_MPU401_UART | 770 | select SND_MPU401_UART |
@@ -820,7 +777,6 @@ config SND_RIPTIDE | |||
820 | 777 | ||
821 | config SND_RME32 | 778 | config SND_RME32 |
822 | tristate "RME Digi32, 32/8, 32 PRO" | 779 | tristate "RME Digi32, 32/8, 32 PRO" |
823 | depends on SND | ||
824 | select SND_PCM | 780 | select SND_PCM |
825 | help | 781 | help |
826 | Say Y to include support for RME Digi32, Digi32 PRO and | 782 | Say Y to include support for RME Digi32, Digi32 PRO and |
@@ -832,7 +788,6 @@ config SND_RME32 | |||
832 | 788 | ||
833 | config SND_RME96 | 789 | config SND_RME96 |
834 | tristate "RME Digi96, 96/8, 96/8 PRO" | 790 | tristate "RME Digi96, 96/8, 96/8 PRO" |
835 | depends on SND | ||
836 | select SND_PCM | 791 | select SND_PCM |
837 | help | 792 | help |
838 | Say Y here to include support for RME Digi96, Digi96/8 and | 793 | Say Y here to include support for RME Digi96, Digi96/8 and |
@@ -843,7 +798,6 @@ config SND_RME96 | |||
843 | 798 | ||
844 | config SND_RME9652 | 799 | config SND_RME9652 |
845 | tristate "RME Digi9652 (Hammerfall)" | 800 | tristate "RME Digi9652 (Hammerfall)" |
846 | depends on SND | ||
847 | select SND_PCM | 801 | select SND_PCM |
848 | help | 802 | help |
849 | Say Y here to include support for RME Hammerfall (RME | 803 | Say Y here to include support for RME Hammerfall (RME |
@@ -854,7 +808,7 @@ config SND_RME9652 | |||
854 | 808 | ||
855 | config SND_SIS7019 | 809 | config SND_SIS7019 |
856 | tristate "SiS 7019 Audio Accelerator" | 810 | tristate "SiS 7019 Audio Accelerator" |
857 | depends on SND && X86 && !X86_64 | 811 | depends on X86 && !X86_64 |
858 | select SND_AC97_CODEC | 812 | select SND_AC97_CODEC |
859 | help | 813 | help |
860 | Say Y here to include support for the SiS 7019 Audio Accelerator. | 814 | Say Y here to include support for the SiS 7019 Audio Accelerator. |
@@ -864,7 +818,6 @@ config SND_SIS7019 | |||
864 | 818 | ||
865 | config SND_SONICVIBES | 819 | config SND_SONICVIBES |
866 | tristate "S3 SonicVibes" | 820 | tristate "S3 SonicVibes" |
867 | depends on SND | ||
868 | select SND_OPL3_LIB | 821 | select SND_OPL3_LIB |
869 | select SND_MPU401_UART | 822 | select SND_MPU401_UART |
870 | select SND_AC97_CODEC | 823 | select SND_AC97_CODEC |
@@ -877,7 +830,6 @@ config SND_SONICVIBES | |||
877 | 830 | ||
878 | config SND_TRIDENT | 831 | config SND_TRIDENT |
879 | tristate "Trident 4D-Wave DX/NX; SiS 7018" | 832 | tristate "Trident 4D-Wave DX/NX; SiS 7018" |
880 | depends on SND | ||
881 | select SND_MPU401_UART | 833 | select SND_MPU401_UART |
882 | select SND_AC97_CODEC | 834 | select SND_AC97_CODEC |
883 | help | 835 | help |
@@ -889,7 +841,6 @@ config SND_TRIDENT | |||
889 | 841 | ||
890 | config SND_VIA82XX | 842 | config SND_VIA82XX |
891 | tristate "VIA 82C686A/B, 8233/8235 AC97 Controller" | 843 | tristate "VIA 82C686A/B, 8233/8235 AC97 Controller" |
892 | depends on SND | ||
893 | select SND_MPU401_UART | 844 | select SND_MPU401_UART |
894 | select SND_AC97_CODEC | 845 | select SND_AC97_CODEC |
895 | help | 846 | help |
@@ -901,7 +852,6 @@ config SND_VIA82XX | |||
901 | 852 | ||
902 | config SND_VIA82XX_MODEM | 853 | config SND_VIA82XX_MODEM |
903 | tristate "VIA 82C686A/B, 8233 based Modems" | 854 | tristate "VIA 82C686A/B, 8233 based Modems" |
904 | depends on SND | ||
905 | select SND_AC97_CODEC | 855 | select SND_AC97_CODEC |
906 | help | 856 | help |
907 | Say Y here to include support for the integrated MC97 modem on | 857 | Say Y here to include support for the integrated MC97 modem on |
@@ -912,7 +862,6 @@ config SND_VIA82XX_MODEM | |||
912 | 862 | ||
913 | config SND_VIRTUOSO | 863 | config SND_VIRTUOSO |
914 | tristate "Asus Virtuoso 100/200 (Xonar)" | 864 | tristate "Asus Virtuoso 100/200 (Xonar)" |
915 | depends on SND | ||
916 | select SND_OXYGEN_LIB | 865 | select SND_OXYGEN_LIB |
917 | help | 866 | help |
918 | Say Y here to include support for sound cards based on the | 867 | Say Y here to include support for sound cards based on the |
@@ -923,7 +872,6 @@ config SND_VIRTUOSO | |||
923 | 872 | ||
924 | config SND_VX222 | 873 | config SND_VX222 |
925 | tristate "Digigram VX222" | 874 | tristate "Digigram VX222" |
926 | depends on SND | ||
927 | select SND_VX_LIB | 875 | select SND_VX_LIB |
928 | help | 876 | help |
929 | Say Y here to include support for Digigram VX222 soundcards. | 877 | Say Y here to include support for Digigram VX222 soundcards. |
@@ -933,7 +881,6 @@ config SND_VX222 | |||
933 | 881 | ||
934 | config SND_YMFPCI | 882 | config SND_YMFPCI |
935 | tristate "Yamaha YMF724/740/744/754" | 883 | tristate "Yamaha YMF724/740/744/754" |
936 | depends on SND | ||
937 | select FW_LOADER if !SND_YMFPCI_FIRMWARE_IN_KERNEL | 884 | select FW_LOADER if !SND_YMFPCI_FIRMWARE_IN_KERNEL |
938 | select SND_OPL3_LIB | 885 | select SND_OPL3_LIB |
939 | select SND_MPU401_UART | 886 | select SND_MPU401_UART |
@@ -954,25 +901,4 @@ config SND_YMFPCI_FIRMWARE_IN_KERNEL | |||
954 | for the YMFPCI driver. If you choose N here, you need to | 901 | for the YMFPCI driver. If you choose N here, you need to |
955 | install the firmware files from the alsa-firmware package. | 902 | install the firmware files from the alsa-firmware package. |
956 | 903 | ||
957 | config SND_AC97_POWER_SAVE | 904 | endif # SND_PCI |
958 | bool "AC97 Power-Saving Mode" | ||
959 | depends on SND_AC97_CODEC && EXPERIMENTAL | ||
960 | default n | ||
961 | help | ||
962 | Say Y here to enable the aggressive power-saving support of | ||
963 | AC97 codecs. In this mode, the power-mode is dynamically | ||
964 | controlled at each open/close. | ||
965 | |||
966 | The mode is activated by passing power_save=1 option to | ||
967 | snd-ac97-codec driver. You can toggle it dynamically over | ||
968 | sysfs, too. | ||
969 | |||
970 | config SND_AC97_POWER_SAVE_DEFAULT | ||
971 | int "Default time-out for AC97 power-save mode" | ||
972 | depends on SND_AC97_POWER_SAVE | ||
973 | default 0 | ||
974 | help | ||
975 | The default time-out value in seconds for AC97 automatic | ||
976 | power-save mode. 0 means to disable the power-save mode. | ||
977 | |||
978 | endmenu | ||
diff --git a/sound/pci/Makefile b/sound/pci/Makefile index 85ef14bc8056..65b25d221cd2 100644 --- a/sound/pci/Makefile +++ b/sound/pci/Makefile | |||
@@ -13,7 +13,7 @@ snd-bt87x-objs := bt87x.o | |||
13 | snd-cmipci-objs := cmipci.o | 13 | snd-cmipci-objs := cmipci.o |
14 | snd-cs4281-objs := cs4281.o | 14 | snd-cs4281-objs := cs4281.o |
15 | snd-cs5530-objs := cs5530.o | 15 | snd-cs5530-objs := cs5530.o |
16 | snd-ens1370-objs := ens1370.o | 16 | snd-ens1370-objs := ens1370.o ak4531_codec.o |
17 | snd-ens1371-objs := ens1371.o | 17 | snd-ens1371-objs := ens1371.o |
18 | snd-es1938-objs := es1938.o | 18 | snd-es1938-objs := es1938.o |
19 | snd-es1968-objs := es1968.o | 19 | snd-es1968-objs := es1968.o |
diff --git a/sound/pci/ac97/Makefile b/sound/pci/ac97/Makefile index 0be48b1a22d0..41fa322f0971 100644 --- a/sound/pci/ac97/Makefile +++ b/sound/pci/ac97/Makefile | |||
@@ -3,16 +3,8 @@ | |||
3 | # Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz> | 3 | # Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz> |
4 | # | 4 | # |
5 | 5 | ||
6 | snd-ac97-codec-objs := ac97_codec.o ac97_pcm.o | 6 | snd-ac97-codec-y := ac97_codec.o ac97_pcm.o |
7 | 7 | snd-ac97-codec-$(CONFIG_PROC_FS) += ac97_proc.o | |
8 | ifneq ($(CONFIG_PROC_FS),) | ||
9 | snd-ac97-codec-objs += ac97_proc.o | ||
10 | endif | ||
11 | |||
12 | snd-ak4531-codec-objs := ak4531_codec.o | ||
13 | 8 | ||
14 | # Toplevel Module Dependency | 9 | # Toplevel Module Dependency |
15 | obj-$(CONFIG_SND_AC97_CODEC) += snd-ac97-codec.o | 10 | obj-$(CONFIG_SND_AC97_CODEC) += snd-ac97-codec.o |
16 | obj-$(CONFIG_SND_ENS1370) += snd-ak4531-codec.o | ||
17 | |||
18 | obj-m := $(sort $(obj-m)) | ||
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 45fd29017ddd..07364c00768a 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c | |||
@@ -49,8 +49,9 @@ MODULE_PARM_DESC(enable_loopback, "Enable AC97 ADC/DAC Loopback Control"); | |||
49 | 49 | ||
50 | #ifdef CONFIG_SND_AC97_POWER_SAVE | 50 | #ifdef CONFIG_SND_AC97_POWER_SAVE |
51 | static int power_save = CONFIG_SND_AC97_POWER_SAVE_DEFAULT; | 51 | static int power_save = CONFIG_SND_AC97_POWER_SAVE_DEFAULT; |
52 | module_param(power_save, bool, 0644); | 52 | module_param(power_save, int, 0644); |
53 | MODULE_PARM_DESC(power_save, "Enable AC97 power-saving control"); | 53 | MODULE_PARM_DESC(power_save, "Automatic power-saving timeout " |
54 | "(in second, 0 = disable)."); | ||
54 | #endif | 55 | #endif |
55 | /* | 56 | /* |
56 | 57 | ||
@@ -2294,9 +2295,11 @@ static void snd_ac97_powerdown(struct snd_ac97 *ac97) | |||
2294 | power |= AC97_PD_PR0 | AC97_PD_PR1; /* ADC & DAC powerdown */ | 2295 | power |= AC97_PD_PR0 | AC97_PD_PR1; /* ADC & DAC powerdown */ |
2295 | snd_ac97_write(ac97, AC97_POWERDOWN, power); | 2296 | snd_ac97_write(ac97, AC97_POWERDOWN, power); |
2296 | udelay(100); | 2297 | udelay(100); |
2297 | power |= AC97_PD_PR2 | AC97_PD_PR3; /* Analog Mixer powerdown */ | 2298 | power |= AC97_PD_PR2; /* Analog Mixer powerdown (Vref on) */ |
2298 | snd_ac97_write(ac97, AC97_POWERDOWN, power); | 2299 | snd_ac97_write(ac97, AC97_POWERDOWN, power); |
2299 | if (ac97_is_power_save_mode(ac97)) { | 2300 | if (ac97_is_power_save_mode(ac97)) { |
2301 | power |= AC97_PD_PR3; /* Analog Mixer powerdown */ | ||
2302 | snd_ac97_write(ac97, AC97_POWERDOWN, power); | ||
2300 | udelay(100); | 2303 | udelay(100); |
2301 | /* AC-link powerdown, internal Clk disable */ | 2304 | /* AC-link powerdown, internal Clk disable */ |
2302 | /* FIXME: this may cause click noises on some boards */ | 2305 | /* FIXME: this may cause click noises on some boards */ |
@@ -2362,7 +2365,7 @@ int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup) | |||
2362 | * that open/close frequently) | 2365 | * that open/close frequently) |
2363 | */ | 2366 | */ |
2364 | schedule_delayed_work(&ac97->power_work, | 2367 | schedule_delayed_work(&ac97->power_work, |
2365 | msecs_to_jiffies(2000)); | 2368 | msecs_to_jiffies(power_save * 1000)); |
2366 | else { | 2369 | else { |
2367 | cancel_delayed_work(&ac97->power_work); | 2370 | cancel_delayed_work(&ac97->power_work); |
2368 | update_power_regs(ac97); | 2371 | update_power_regs(ac97); |
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 1292dcee072d..0746e9ccc20b 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c | |||
@@ -669,6 +669,7 @@ AC97_SINGLE("Mic 1 Volume", AC97_MIC, 8, 31, 1), | |||
669 | AC97_SINGLE("Mic 2 Volume", AC97_MIC, 0, 31, 1), | 669 | AC97_SINGLE("Mic 2 Volume", AC97_MIC, 0, 31, 1), |
670 | AC97_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 7, 1, 0), | 670 | AC97_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 7, 1, 0), |
671 | 671 | ||
672 | AC97_SINGLE("Master Left Inv Switch", AC97_MASTER, 6, 1, 0), | ||
672 | AC97_SINGLE("Master ZC Switch", AC97_MASTER, 7, 1, 0), | 673 | AC97_SINGLE("Master ZC Switch", AC97_MASTER, 7, 1, 0), |
673 | AC97_SINGLE("Headphone ZC Switch", AC97_HEADPHONE, 7, 1, 0), | 674 | AC97_SINGLE("Headphone ZC Switch", AC97_HEADPHONE, 7, 1, 0), |
674 | AC97_SINGLE("Mono ZC Switch", AC97_MASTER_MONO, 7, 1, 0), | 675 | AC97_SINGLE("Mono ZC Switch", AC97_MASTER_MONO, 7, 1, 0), |
@@ -3352,8 +3353,66 @@ AC97_SINGLE("Downmix LFE and Center to Front", 0x5a, 12, 1, 0), | |||
3352 | AC97_SINGLE("Downmix Surround to Front", 0x5a, 11, 1, 0), | 3353 | AC97_SINGLE("Downmix Surround to Front", 0x5a, 11, 1, 0), |
3353 | }; | 3354 | }; |
3354 | 3355 | ||
3356 | static const char *slave_vols_vt1616[] = { | ||
3357 | "Front Playback Volume", | ||
3358 | "Surround Playback Volume", | ||
3359 | "Center Playback Volume", | ||
3360 | "LFE Playback Volume", | ||
3361 | NULL | ||
3362 | }; | ||
3363 | |||
3364 | static const char *slave_sws_vt1616[] = { | ||
3365 | "Front Playback Switch", | ||
3366 | "Surround Playback Switch", | ||
3367 | "Center Playback Switch", | ||
3368 | "LFE Playback Switch", | ||
3369 | NULL | ||
3370 | }; | ||
3371 | |||
3372 | /* find a mixer control element with the given name */ | ||
3373 | static struct snd_kcontrol *snd_ac97_find_mixer_ctl(struct snd_ac97 *ac97, | ||
3374 | const char *name) | ||
3375 | { | ||
3376 | struct snd_ctl_elem_id id; | ||
3377 | memset(&id, 0, sizeof(id)); | ||
3378 | id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
3379 | strcpy(id.name, name); | ||
3380 | return snd_ctl_find_id(ac97->bus->card, &id); | ||
3381 | } | ||
3382 | |||
3383 | /* create a virtual master control and add slaves */ | ||
3384 | int snd_ac97_add_vmaster(struct snd_ac97 *ac97, char *name, | ||
3385 | const unsigned int *tlv, const char **slaves) | ||
3386 | { | ||
3387 | struct snd_kcontrol *kctl; | ||
3388 | const char **s; | ||
3389 | int err; | ||
3390 | |||
3391 | kctl = snd_ctl_make_virtual_master(name, tlv); | ||
3392 | if (!kctl) | ||
3393 | return -ENOMEM; | ||
3394 | err = snd_ctl_add(ac97->bus->card, kctl); | ||
3395 | if (err < 0) | ||
3396 | return err; | ||
3397 | |||
3398 | for (s = slaves; *s; s++) { | ||
3399 | struct snd_kcontrol *sctl; | ||
3400 | |||
3401 | sctl = snd_ac97_find_mixer_ctl(ac97, *s); | ||
3402 | if (!sctl) { | ||
3403 | snd_printdd("Cannot find slave %s, skipped\n", *s); | ||
3404 | continue; | ||
3405 | } | ||
3406 | err = snd_ctl_add_slave(kctl, sctl); | ||
3407 | if (err < 0) | ||
3408 | return err; | ||
3409 | } | ||
3410 | return 0; | ||
3411 | } | ||
3412 | |||
3355 | static int patch_vt1616_specific(struct snd_ac97 * ac97) | 3413 | static int patch_vt1616_specific(struct snd_ac97 * ac97) |
3356 | { | 3414 | { |
3415 | struct snd_kcontrol *kctl; | ||
3357 | int err; | 3416 | int err; |
3358 | 3417 | ||
3359 | if (snd_ac97_try_bit(ac97, 0x5a, 9)) | 3418 | if (snd_ac97_try_bit(ac97, 0x5a, 9)) |
@@ -3361,6 +3420,24 @@ static int patch_vt1616_specific(struct snd_ac97 * ac97) | |||
3361 | return err; | 3420 | return err; |
3362 | if ((err = patch_build_controls(ac97, &snd_ac97_controls_vt1616[1], ARRAY_SIZE(snd_ac97_controls_vt1616) - 1)) < 0) | 3421 | if ((err = patch_build_controls(ac97, &snd_ac97_controls_vt1616[1], ARRAY_SIZE(snd_ac97_controls_vt1616) - 1)) < 0) |
3363 | return err; | 3422 | return err; |
3423 | |||
3424 | /* There is already a misnamed master switch. Rename it. */ | ||
3425 | kctl = snd_ac97_find_mixer_ctl(ac97, "Master Playback Volume"); | ||
3426 | if (!kctl) | ||
3427 | return -EINVAL; | ||
3428 | |||
3429 | snd_ac97_rename_vol_ctl(ac97, "Master Playback", "Front Playback"); | ||
3430 | |||
3431 | err = snd_ac97_add_vmaster(ac97, "Master Playback Volume", | ||
3432 | kctl->tlv.p, slave_vols_vt1616); | ||
3433 | if (err < 0) | ||
3434 | return err; | ||
3435 | |||
3436 | err = snd_ac97_add_vmaster(ac97, "Master Playback Switch", | ||
3437 | NULL, slave_sws_vt1616); | ||
3438 | if (err < 0) | ||
3439 | return err; | ||
3440 | |||
3364 | return 0; | 3441 | return 0; |
3365 | } | 3442 | } |
3366 | 3443 | ||
@@ -3633,7 +3710,7 @@ static int patch_ucb1400(struct snd_ac97 * ac97) | |||
3633 | { | 3710 | { |
3634 | ac97->build_ops = &patch_ucb1400_ops; | 3711 | ac97->build_ops = &patch_ucb1400_ops; |
3635 | /* enable headphone driver and smart low power mode by default */ | 3712 | /* enable headphone driver and smart low power mode by default */ |
3636 | snd_ac97_write(ac97, 0x6a, 0x0050); | 3713 | snd_ac97_write_cache(ac97, 0x6a, 0x0050); |
3637 | snd_ac97_write(ac97, 0x6c, 0x0030); | 3714 | snd_ac97_write_cache(ac97, 0x6c, 0x0030); |
3638 | return 0; | 3715 | return 0; |
3639 | } | 3716 | } |
diff --git a/sound/pci/ac97/ak4531_codec.c b/sound/pci/ak4531_codec.c index c0c1633999ea..33d37b1c42fc 100644 --- a/sound/pci/ac97/ak4531_codec.c +++ b/sound/pci/ak4531_codec.c | |||
@@ -28,9 +28,11 @@ | |||
28 | #include <sound/ak4531_codec.h> | 28 | #include <sound/ak4531_codec.h> |
29 | #include <sound/tlv.h> | 29 | #include <sound/tlv.h> |
30 | 30 | ||
31 | /* | ||
31 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); | 32 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); |
32 | MODULE_DESCRIPTION("Universal routines for AK4531 codec"); | 33 | MODULE_DESCRIPTION("Universal routines for AK4531 codec"); |
33 | MODULE_LICENSE("GPL"); | 34 | MODULE_LICENSE("GPL"); |
35 | */ | ||
34 | 36 | ||
35 | #ifdef CONFIG_PROC_FS | 37 | #ifdef CONFIG_PROC_FS |
36 | static void snd_ak4531_proc_init(struct snd_card *card, struct snd_ak4531 *ak4531); | 38 | static void snd_ak4531_proc_init(struct snd_card *card, struct snd_ak4531 *ak4531); |
@@ -270,7 +272,7 @@ static const DECLARE_TLV_DB_SCALE(db_scale_master, -6200, 200, 0); | |||
270 | static const DECLARE_TLV_DB_SCALE(db_scale_mono, -2800, 400, 0); | 272 | static const DECLARE_TLV_DB_SCALE(db_scale_mono, -2800, 400, 0); |
271 | static const DECLARE_TLV_DB_SCALE(db_scale_input, -5000, 200, 0); | 273 | static const DECLARE_TLV_DB_SCALE(db_scale_input, -5000, 200, 0); |
272 | 274 | ||
273 | static struct snd_kcontrol_new snd_ak4531_controls[] = { | 275 | static struct snd_kcontrol_new snd_ak4531_controls[] __devinitdata = { |
274 | 276 | ||
275 | AK4531_DOUBLE_TLV("Master Playback Switch", 0, | 277 | AK4531_DOUBLE_TLV("Master Playback Switch", 0, |
276 | AK4531_LMASTER, AK4531_RMASTER, 7, 7, 1, 1, | 278 | AK4531_LMASTER, AK4531_RMASTER, 7, 7, 1, 1, |
@@ -379,8 +381,9 @@ static u8 snd_ak4531_initial_map[0x19 + 1] = { | |||
379 | 0x01 /* 19: Mic Amp Setup */ | 381 | 0x01 /* 19: Mic Amp Setup */ |
380 | }; | 382 | }; |
381 | 383 | ||
382 | int snd_ak4531_mixer(struct snd_card *card, struct snd_ak4531 *_ak4531, | 384 | int __devinit snd_ak4531_mixer(struct snd_card *card, |
383 | struct snd_ak4531 **rak4531) | 385 | struct snd_ak4531 *_ak4531, |
386 | struct snd_ak4531 **rak4531) | ||
384 | { | 387 | { |
385 | unsigned int idx; | 388 | unsigned int idx; |
386 | int err; | 389 | int err; |
@@ -476,7 +479,8 @@ static void snd_ak4531_proc_read(struct snd_info_entry *entry, | |||
476 | ak4531->regs[AK4531_MIC_GAIN] & 1 ? "+30dB" : "+0dB"); | 479 | ak4531->regs[AK4531_MIC_GAIN] & 1 ? "+30dB" : "+0dB"); |
477 | } | 480 | } |
478 | 481 | ||
479 | static void snd_ak4531_proc_init(struct snd_card *card, struct snd_ak4531 *ak4531) | 482 | static void __devinit |
483 | snd_ak4531_proc_init(struct snd_card *card, struct snd_ak4531 *ak4531) | ||
480 | { | 484 | { |
481 | struct snd_info_entry *entry; | 485 | struct snd_info_entry *entry; |
482 | 486 | ||
@@ -484,25 +488,3 @@ static void snd_ak4531_proc_init(struct snd_card *card, struct snd_ak4531 *ak453 | |||
484 | snd_info_set_text_ops(entry, ak4531, snd_ak4531_proc_read); | 488 | snd_info_set_text_ops(entry, ak4531, snd_ak4531_proc_read); |
485 | } | 489 | } |
486 | #endif | 490 | #endif |
487 | |||
488 | EXPORT_SYMBOL(snd_ak4531_mixer); | ||
489 | #ifdef CONFIG_PM | ||
490 | EXPORT_SYMBOL(snd_ak4531_suspend); | ||
491 | EXPORT_SYMBOL(snd_ak4531_resume); | ||
492 | #endif | ||
493 | |||
494 | /* | ||
495 | * INIT part | ||
496 | */ | ||
497 | |||
498 | static int __init alsa_ak4531_init(void) | ||
499 | { | ||
500 | return 0; | ||
501 | } | ||
502 | |||
503 | static void __exit alsa_ak4531_exit(void) | ||
504 | { | ||
505 | } | ||
506 | |||
507 | module_init(alsa_ak4531_init) | ||
508 | module_exit(alsa_ak4531_exit) | ||
diff --git a/sound/pci/au88x0/au88x0_game.c b/sound/pci/au88x0/au88x0_game.c index bc212f41a38a..e291aa59742e 100644 --- a/sound/pci/au88x0/au88x0_game.c +++ b/sound/pci/au88x0/au88x0_game.c | |||
@@ -1,6 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: au88x0_game.c,v 1.9 2003/09/22 03:51:28 mjander Exp $ | ||
3 | * | ||
4 | * Manuel Jander. | 2 | * Manuel Jander. |
5 | * | 3 | * |
6 | * Based on the work of: | 4 | * Based on the work of: |
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index 5f63af6b88a2..22f18f3cfbc9 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * azt3328.c - driver for Aztech AZF3328 based soundcards (e.g. PCI168). | 2 | * azt3328.c - driver for Aztech AZF3328 based soundcards (e.g. PCI168). |
3 | * Copyright (C) 2002, 2005, 2006, 2007 by Andreas Mohr <andi AT lisas.de> | 3 | * Copyright (C) 2002, 2005 - 2008 by Andreas Mohr <andi AT lisas.de> |
4 | * | 4 | * |
5 | * Framework borrowed from Bart Hartgers's als4000.c. | 5 | * Framework borrowed from Bart Hartgers's als4000.c. |
6 | * Driver developed on PCI168 AP(W) version (PCI rev. 10, subsystem ID 1801), | 6 | * Driver developed on PCI168 AP(W) version (PCI rev. 10, subsystem ID 1801), |
@@ -35,9 +35,20 @@ | |||
35 | * (3 weeks' worth of evenings filled with driver work). | 35 | * (3 weeks' worth of evenings filled with driver work). |
36 | * (and no, I did NOT go the easy way: to pick up a SB PCI128 for 9 Euros) | 36 | * (and no, I did NOT go the easy way: to pick up a SB PCI128 for 9 Euros) |
37 | * | 37 | * |
38 | * It is quite likely that the AZF3328 chip is the PCI cousin of the | ||
39 | * AZF3318 ("azt1020 pnp", "MM Pro 16") ISA chip, given very similar specs. | ||
40 | * | ||
38 | * The AZF3328 chip (note: AZF3328, *not* AZT3328, that's just the driver name | 41 | * The AZF3328 chip (note: AZF3328, *not* AZT3328, that's just the driver name |
39 | * for compatibility reasons) has the following features: | 42 | * for compatibility reasons) from Azfin (joint-venture of Aztech and Fincitec, |
43 | * Fincitec acquired by National Semiconductor in 2002, together with the | ||
44 | * Fincitec-related company ARSmikro) has the following features: | ||
40 | * | 45 | * |
46 | * - compatibility & compliance: | ||
47 | * - Microsoft PC 97 ("PC 97 Hardware Design Guide", | ||
48 | * http://www.microsoft.com/whdc/archive/pcguides.mspx) | ||
49 | * - Microsoft PC 98 Baseline Audio | ||
50 | * - MPU401 UART | ||
51 | * - Sound Blaster Emulation (DOS Box) | ||
41 | * - builtin AC97 conformant codec (SNR over 80dB) | 52 | * - builtin AC97 conformant codec (SNR over 80dB) |
42 | * Note that "conformant" != "compliant"!! this chip's mixer register layout | 53 | * Note that "conformant" != "compliant"!! this chip's mixer register layout |
43 | * *differs* from the standard AC97 layout: | 54 | * *differs* from the standard AC97 layout: |
@@ -48,21 +59,28 @@ | |||
48 | * addresses illegally. So far unfortunately it looks like the very flexible | 59 | * addresses illegally. So far unfortunately it looks like the very flexible |
49 | * ALSA AC97 support is still not enough to easily compensate for such a | 60 | * ALSA AC97 support is still not enough to easily compensate for such a |
50 | * grave layout violation despite all tweaks and quirks mechanisms it offers. | 61 | * grave layout violation despite all tweaks and quirks mechanisms it offers. |
51 | * - builtin genuine OPL3 | 62 | * - builtin genuine OPL3 - verified to work fine, 20080506 |
52 | * - full duplex 16bit playback/record at independent sampling rate | 63 | * - full duplex 16bit playback/record at independent sampling rate |
53 | * - MPU401 (+ legacy address support) FIXME: how to enable legacy addr?? | 64 | * - MPU401 (+ legacy address support, claimed by one official spec sheet) |
65 | * FIXME: how to enable legacy addr?? | ||
54 | * - game port (legacy address support) | 66 | * - game port (legacy address support) |
55 | * - builtin 3D enhancement (said to be YAMAHA Ymersion) | ||
56 | * - builtin DirectInput support, helps reduce CPU overhead (interrupt-driven | 67 | * - builtin DirectInput support, helps reduce CPU overhead (interrupt-driven |
57 | * features supported) | 68 | * features supported). - See common term "Digital Enhanced Game Port"... |
69 | * (probably DirectInput 3.0 spec - confirm) | ||
70 | * - builtin 3D enhancement (said to be YAMAHA Ymersion) | ||
58 | * - built-in General DirectX timer having a 20 bits counter | 71 | * - built-in General DirectX timer having a 20 bits counter |
59 | * with 1us resolution (see below!) | 72 | * with 1us resolution (see below!) |
60 | * - I2S serial port for external DAC | 73 | * - I2S serial output port for external DAC |
61 | * - supports 33MHz PCI spec 2.1, PCI power management 1.0, compliant with ACPI | 74 | * - supports 33MHz PCI spec 2.1, PCI power management 1.0, compliant with ACPI |
62 | * - supports hardware volume control | 75 | * - supports hardware volume control |
63 | * - single chip low cost solution (128 pin QFP) | 76 | * - single chip low cost solution (128 pin QFP) |
64 | * - supports programmable Sub-vendor and Sub-system ID | 77 | * - supports programmable Sub-vendor and Sub-system ID |
65 | * required for Microsoft's logo compliance (FIXME: where?) | 78 | * required for Microsoft's logo compliance (FIXME: where?) |
79 | * At least the Trident 4D Wave DX has one bit somewhere | ||
80 | * to enable writes to PCI subsystem VID registers, that should be it. | ||
81 | * This might easily be in extended PCI reg space, since PCI168 also has | ||
82 | * some custom data starting at 0x80. What kind of config settings | ||
83 | * are located in our extended PCI space anyway?? | ||
66 | * - PCI168 AP(W) card: power amplifier with 4 Watts/channel at 4 Ohms | 84 | * - PCI168 AP(W) card: power amplifier with 4 Watts/channel at 4 Ohms |
67 | * | 85 | * |
68 | * Note that this driver now is actually *better* than the Windows driver, | 86 | * Note that this driver now is actually *better* than the Windows driver, |
@@ -74,6 +92,24 @@ | |||
74 | * - "timidity -iAv -B2,8 -Os -EFreverb=0" | 92 | * - "timidity -iAv -B2,8 -Os -EFreverb=0" |
75 | * - "pmidi -p 128:0 jazz.mid" | 93 | * - "pmidi -p 128:0 jazz.mid" |
76 | * | 94 | * |
95 | * OPL3 hardware playback testing, try something like: | ||
96 | * cat /proc/asound/hwdep | ||
97 | * and | ||
98 | * aconnect -o | ||
99 | * Then use | ||
100 | * sbiload -Dhw:x,y --opl3 /usr/share/sounds/opl3/std.o3 ......./drums.o3 | ||
101 | * where x,y is the xx-yy number as given in hwdep. | ||
102 | * Then try | ||
103 | * pmidi -p a:b jazz.mid | ||
104 | * where a:b is the client number plus 0 usually, as given by aconnect above. | ||
105 | * Oh, and make sure to unmute the FM mixer control (doh!) | ||
106 | * NOTE: power use during OPL3 playback is _VERY_ high (70W --> 90W!) | ||
107 | * despite no CPU activity, possibly due to hindering ACPI idling somehow. | ||
108 | * Shouldn't be a problem of the AZF3328 chip itself, I'd hope. | ||
109 | * Higher PCM / FM mixer levels seem to conflict (causes crackling), | ||
110 | * at least sometimes. Maybe even use with hardware sequencer timer above :) | ||
111 | * adplay/adplug-utils might soon offer hardware-based OPL3 playback, too. | ||
112 | * | ||
77 | * Certain PCI versions of this card are susceptible to DMA traffic underruns | 113 | * Certain PCI versions of this card are susceptible to DMA traffic underruns |
78 | * in some systems (resulting in sound crackling/clicking/popping), | 114 | * in some systems (resulting in sound crackling/clicking/popping), |
79 | * probably because they don't have a DMA FIFO buffer or so. | 115 | * probably because they don't have a DMA FIFO buffer or so. |
@@ -87,6 +123,8 @@ | |||
87 | * better than a VIA, yet ironically I still get crackling, like many other | 123 | * better than a VIA, yet ironically I still get crackling, like many other |
88 | * people with the same chipset. | 124 | * people with the same chipset. |
89 | * Possible remedies: | 125 | * Possible remedies: |
126 | * - use speaker (amplifier) output instead of headphone output | ||
127 | * (in case crackling is due to overloaded output clipping) | ||
90 | * - plug card into a different PCI slot, preferrably one that isn't shared | 128 | * - plug card into a different PCI slot, preferrably one that isn't shared |
91 | * too much (this helps a lot, but not completely!) | 129 | * too much (this helps a lot, but not completely!) |
92 | * - get rid of PCI VGA card, use AGP instead | 130 | * - get rid of PCI VGA card, use AGP instead |
@@ -94,18 +132,23 @@ | |||
94 | * - fiddle with PCI latency settings (setpci -v -s BUSID latency_timer=XX) | 132 | * - fiddle with PCI latency settings (setpci -v -s BUSID latency_timer=XX) |
95 | * Not too helpful. | 133 | * Not too helpful. |
96 | * - Disable ACPI/power management/"Auto Detect RAM/PCI Clk" in BIOS | 134 | * - Disable ACPI/power management/"Auto Detect RAM/PCI Clk" in BIOS |
97 | * | 135 | * |
98 | * BUGS | 136 | * BUGS |
99 | * - full-duplex might *still* be problematic, not fully tested recently | 137 | * - full-duplex might *still* be problematic, however a recent test was fine |
100 | * - (non-bug) "Bass/Treble or 3D settings don't work" - they do get evaluated | 138 | * - (non-bug) "Bass/Treble or 3D settings don't work" - they do get evaluated |
101 | * if you set PCM output switch to "pre 3D" instead of "post 3D". | 139 | * if you set PCM output switch to "pre 3D" instead of "post 3D". |
102 | * If this can't be set, then get a mixer application that Isn't Stupid (tm) | 140 | * If this can't be set, then get a mixer application that Isn't Stupid (tm) |
103 | * (e.g. kmix, gamix) - unfortunately several are!! | 141 | * (e.g. kmix, gamix) - unfortunately several are!! |
104 | * | 142 | * - locking is not entirely clean, especially the audio stream activity |
143 | * ints --> may be racy | ||
144 | * - an _unconnected_ secondary joystick at the gameport will be reported | ||
145 | * to be "active" (floating values, not precisely -1) due to the way we need | ||
146 | * to read the Digital Enhanced Game Port. Not sure whether it is fixable. | ||
147 | * | ||
105 | * TODO | 148 | * TODO |
106 | * - test MPU401 MIDI playback etc. | 149 | * - test MPU401 MIDI playback etc. |
107 | * - add some power micro-management (disable various units of the card | 150 | * - add more power micro-management (disable various units of the card |
108 | * as long as they're unused). However this requires I/O ports which I | 151 | * as long as they're unused). However this requires more I/O ports which I |
109 | * haven't figured out yet and which thus might not even exist... | 152 | * haven't figured out yet and which thus might not even exist... |
110 | * The standard suspend/resume functionality could probably make use of | 153 | * The standard suspend/resume functionality could probably make use of |
111 | * some improvement, too... | 154 | * some improvement, too... |
@@ -113,6 +156,7 @@ | |||
113 | * - figure out some cleverly evil scheme to possibly make ALSA AC97 code | 156 | * - figure out some cleverly evil scheme to possibly make ALSA AC97 code |
114 | * fully accept our quite incompatible ""AC97"" mixer and thus save some | 157 | * fully accept our quite incompatible ""AC97"" mixer and thus save some |
115 | * code (but I'm not too optimistic that doing this is possible at all) | 158 | * code (but I'm not too optimistic that doing this is possible at all) |
159 | * - use MMIO (memory-mapped I/O)? Slightly faster access, e.g. for gameport. | ||
116 | */ | 160 | */ |
117 | 161 | ||
118 | #include <asm/io.h> | 162 | #include <asm/io.h> |
@@ -138,7 +182,7 @@ MODULE_LICENSE("GPL"); | |||
138 | MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}"); | 182 | MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}"); |
139 | 183 | ||
140 | #if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) | 184 | #if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) |
141 | #define SUPPORT_JOYSTICK 1 | 185 | #define SUPPORT_GAMEPORT 1 |
142 | #endif | 186 | #endif |
143 | 187 | ||
144 | #define DEBUG_MISC 0 | 188 | #define DEBUG_MISC 0 |
@@ -147,13 +191,14 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}"); | |||
147 | #define DEBUG_PLAY_REC 0 | 191 | #define DEBUG_PLAY_REC 0 |
148 | #define DEBUG_IO 0 | 192 | #define DEBUG_IO 0 |
149 | #define DEBUG_TIMER 0 | 193 | #define DEBUG_TIMER 0 |
194 | #define DEBUG_GAME 0 | ||
150 | #define MIXER_TESTING 0 | 195 | #define MIXER_TESTING 0 |
151 | 196 | ||
152 | #if DEBUG_MISC | 197 | #if DEBUG_MISC |
153 | #define snd_azf3328_dbgmisc(format, args...) printk(KERN_ERR format, ##args) | 198 | #define snd_azf3328_dbgmisc(format, args...) printk(KERN_ERR format, ##args) |
154 | #else | 199 | #else |
155 | #define snd_azf3328_dbgmisc(format, args...) | 200 | #define snd_azf3328_dbgmisc(format, args...) |
156 | #endif | 201 | #endif |
157 | 202 | ||
158 | #if DEBUG_CALLS | 203 | #if DEBUG_CALLS |
159 | #define snd_azf3328_dbgcalls(format, args...) printk(format, ##args) | 204 | #define snd_azf3328_dbgcalls(format, args...) printk(format, ##args) |
@@ -163,25 +208,31 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}"); | |||
163 | #define snd_azf3328_dbgcalls(format, args...) | 208 | #define snd_azf3328_dbgcalls(format, args...) |
164 | #define snd_azf3328_dbgcallenter() | 209 | #define snd_azf3328_dbgcallenter() |
165 | #define snd_azf3328_dbgcallleave() | 210 | #define snd_azf3328_dbgcallleave() |
166 | #endif | 211 | #endif |
167 | 212 | ||
168 | #if DEBUG_MIXER | 213 | #if DEBUG_MIXER |
169 | #define snd_azf3328_dbgmixer(format, args...) printk(format, ##args) | 214 | #define snd_azf3328_dbgmixer(format, args...) printk(format, ##args) |
170 | #else | 215 | #else |
171 | #define snd_azf3328_dbgmixer(format, args...) | 216 | #define snd_azf3328_dbgmixer(format, args...) |
172 | #endif | 217 | #endif |
173 | 218 | ||
174 | #if DEBUG_PLAY_REC | 219 | #if DEBUG_PLAY_REC |
175 | #define snd_azf3328_dbgplay(format, args...) printk(KERN_ERR format, ##args) | 220 | #define snd_azf3328_dbgplay(format, args...) printk(KERN_ERR format, ##args) |
176 | #else | 221 | #else |
177 | #define snd_azf3328_dbgplay(format, args...) | 222 | #define snd_azf3328_dbgplay(format, args...) |
178 | #endif | 223 | #endif |
179 | 224 | ||
180 | #if DEBUG_MISC | 225 | #if DEBUG_MISC |
181 | #define snd_azf3328_dbgtimer(format, args...) printk(KERN_ERR format, ##args) | 226 | #define snd_azf3328_dbgtimer(format, args...) printk(KERN_ERR format, ##args) |
182 | #else | 227 | #else |
183 | #define snd_azf3328_dbgtimer(format, args...) | 228 | #define snd_azf3328_dbgtimer(format, args...) |
184 | #endif | 229 | #endif |
230 | |||
231 | #if DEBUG_GAME | ||
232 | #define snd_azf3328_dbggame(format, args...) printk(KERN_ERR format, ##args) | ||
233 | #else | ||
234 | #define snd_azf3328_dbggame(format, args...) | ||
235 | #endif | ||
185 | 236 | ||
186 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | 237 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ |
187 | module_param_array(index, int, NULL, 0444); | 238 | module_param_array(index, int, NULL, 0444); |
@@ -195,51 +246,62 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card * | |||
195 | module_param_array(enable, bool, NULL, 0444); | 246 | module_param_array(enable, bool, NULL, 0444); |
196 | MODULE_PARM_DESC(enable, "Enable AZF3328 soundcard."); | 247 | MODULE_PARM_DESC(enable, "Enable AZF3328 soundcard."); |
197 | 248 | ||
198 | #ifdef SUPPORT_JOYSTICK | ||
199 | static int joystick[SNDRV_CARDS]; | ||
200 | module_param_array(joystick, bool, NULL, 0444); | ||
201 | MODULE_PARM_DESC(joystick, "Enable joystick for AZF3328 soundcard."); | ||
202 | #endif | ||
203 | |||
204 | static int seqtimer_scaling = 128; | 249 | static int seqtimer_scaling = 128; |
205 | module_param(seqtimer_scaling, int, 0444); | 250 | module_param(seqtimer_scaling, int, 0444); |
206 | MODULE_PARM_DESC(seqtimer_scaling, "Set 1024000Hz sequencer timer scale factor (lockup danger!). Default 128."); | 251 | MODULE_PARM_DESC(seqtimer_scaling, "Set 1024000Hz sequencer timer scale factor (lockup danger!). Default 128."); |
207 | 252 | ||
253 | struct snd_azf3328_audio_stream { | ||
254 | struct snd_pcm_substream *substream; | ||
255 | int enabled; | ||
256 | int running; | ||
257 | unsigned long portbase; | ||
258 | }; | ||
259 | |||
260 | enum snd_azf3328_stream_index { | ||
261 | AZF_PLAYBACK = 0, | ||
262 | AZF_CAPTURE = 1, | ||
263 | }; | ||
264 | |||
208 | struct snd_azf3328 { | 265 | struct snd_azf3328 { |
209 | /* often-used fields towards beginning, then grouped */ | 266 | /* often-used fields towards beginning, then grouped */ |
210 | unsigned long codec_port; | 267 | |
211 | unsigned long io2_port; | 268 | unsigned long codec_io; /* usually 0xb000, size 128 */ |
212 | unsigned long mpu_port; | 269 | unsigned long game_io; /* usually 0xb400, size 8 */ |
213 | unsigned long synth_port; | 270 | unsigned long mpu_io; /* usually 0xb800, size 4 */ |
214 | unsigned long mixer_port; | 271 | unsigned long opl3_io; /* usually 0xbc00, size 8 */ |
272 | unsigned long mixer_io; /* usually 0xc000, size 64 */ | ||
215 | 273 | ||
216 | spinlock_t reg_lock; | 274 | spinlock_t reg_lock; |
217 | 275 | ||
218 | struct snd_timer *timer; | 276 | struct snd_timer *timer; |
219 | 277 | ||
220 | struct snd_pcm *pcm; | 278 | struct snd_pcm *pcm; |
221 | struct snd_pcm_substream *playback_substream; | 279 | struct snd_azf3328_audio_stream audio_stream[2]; |
222 | struct snd_pcm_substream *capture_substream; | ||
223 | unsigned int is_playing; | ||
224 | unsigned int is_recording; | ||
225 | 280 | ||
226 | struct snd_card *card; | 281 | struct snd_card *card; |
227 | struct snd_rawmidi *rmidi; | 282 | struct snd_rawmidi *rmidi; |
228 | 283 | ||
229 | #ifdef SUPPORT_JOYSTICK | 284 | #ifdef SUPPORT_GAMEPORT |
230 | struct gameport *gameport; | 285 | struct gameport *gameport; |
286 | int axes[4]; | ||
231 | #endif | 287 | #endif |
232 | 288 | ||
233 | struct pci_dev *pci; | 289 | struct pci_dev *pci; |
234 | int irq; | 290 | int irq; |
235 | 291 | ||
292 | /* register 0x6a is write-only, thus need to remember setting. | ||
293 | * If we need to add more registers here, then we might try to fold this | ||
294 | * into some transparent combined shadow register handling with | ||
295 | * CONFIG_PM register storage below, but that's slightly difficult. */ | ||
296 | u16 shadow_reg_codec_6AH; | ||
297 | |||
236 | #ifdef CONFIG_PM | 298 | #ifdef CONFIG_PM |
237 | /* register value containers for power management | 299 | /* register value containers for power management |
238 | * Note: not always full I/O range preserved (just like Win driver!) */ | 300 | * Note: not always full I/O range preserved (just like Win driver!) */ |
239 | u16 saved_regs_codec [AZF_IO_SIZE_CODEC_PM / 2]; | 301 | u16 saved_regs_codec[AZF_IO_SIZE_CODEC_PM / 2]; |
240 | u16 saved_regs_io2 [AZF_IO_SIZE_IO2_PM / 2]; | 302 | u16 saved_regs_game [AZF_IO_SIZE_GAME_PM / 2]; |
241 | u16 saved_regs_mpu [AZF_IO_SIZE_MPU_PM / 2]; | 303 | u16 saved_regs_mpu [AZF_IO_SIZE_MPU_PM / 2]; |
242 | u16 saved_regs_synth[AZF_IO_SIZE_SYNTH_PM / 2]; | 304 | u16 saved_regs_opl3 [AZF_IO_SIZE_OPL3_PM / 2]; |
243 | u16 saved_regs_mixer[AZF_IO_SIZE_MIXER_PM / 2]; | 305 | u16 saved_regs_mixer[AZF_IO_SIZE_MIXER_PM / 2]; |
244 | #endif | 306 | #endif |
245 | }; | 307 | }; |
@@ -252,126 +314,166 @@ static const struct pci_device_id snd_azf3328_ids[] = { | |||
252 | 314 | ||
253 | MODULE_DEVICE_TABLE(pci, snd_azf3328_ids); | 315 | MODULE_DEVICE_TABLE(pci, snd_azf3328_ids); |
254 | 316 | ||
317 | |||
318 | static int | ||
319 | snd_azf3328_io_reg_setb(unsigned reg, u8 mask, int do_set) | ||
320 | { | ||
321 | u8 prev = inb(reg), new; | ||
322 | |||
323 | new = (do_set) ? (prev|mask) : (prev & ~mask); | ||
324 | /* we need to always write the new value no matter whether it differs | ||
325 | * or not, since some register bits don't indicate their setting */ | ||
326 | outb(new, reg); | ||
327 | if (new != prev) | ||
328 | return 1; | ||
329 | |||
330 | return 0; | ||
331 | } | ||
332 | |||
255 | static inline void | 333 | static inline void |
256 | snd_azf3328_codec_outb(const struct snd_azf3328 *chip, int reg, u8 value) | 334 | snd_azf3328_codec_outb(const struct snd_azf3328 *chip, unsigned reg, u8 value) |
257 | { | 335 | { |
258 | outb(value, chip->codec_port + reg); | 336 | outb(value, chip->codec_io + reg); |
259 | } | 337 | } |
260 | 338 | ||
261 | static inline u8 | 339 | static inline u8 |
262 | snd_azf3328_codec_inb(const struct snd_azf3328 *chip, int reg) | 340 | snd_azf3328_codec_inb(const struct snd_azf3328 *chip, unsigned reg) |
263 | { | 341 | { |
264 | return inb(chip->codec_port + reg); | 342 | return inb(chip->codec_io + reg); |
265 | } | 343 | } |
266 | 344 | ||
267 | static inline void | 345 | static inline void |
268 | snd_azf3328_codec_outw(const struct snd_azf3328 *chip, int reg, u16 value) | 346 | snd_azf3328_codec_outw(const struct snd_azf3328 *chip, unsigned reg, u16 value) |
269 | { | 347 | { |
270 | outw(value, chip->codec_port + reg); | 348 | outw(value, chip->codec_io + reg); |
271 | } | 349 | } |
272 | 350 | ||
273 | static inline u16 | 351 | static inline u16 |
274 | snd_azf3328_codec_inw(const struct snd_azf3328 *chip, int reg) | 352 | snd_azf3328_codec_inw(const struct snd_azf3328 *chip, unsigned reg) |
353 | { | ||
354 | return inw(chip->codec_io + reg); | ||
355 | } | ||
356 | |||
357 | static inline void | ||
358 | snd_azf3328_codec_outl(const struct snd_azf3328 *chip, unsigned reg, u32 value) | ||
359 | { | ||
360 | outl(value, chip->codec_io + reg); | ||
361 | } | ||
362 | |||
363 | static inline u32 | ||
364 | snd_azf3328_codec_inl(const struct snd_azf3328 *chip, unsigned reg) | ||
275 | { | 365 | { |
276 | return inw(chip->codec_port + reg); | 366 | return inl(chip->codec_io + reg); |
277 | } | 367 | } |
278 | 368 | ||
279 | static inline void | 369 | static inline void |
280 | snd_azf3328_codec_outl(const struct snd_azf3328 *chip, int reg, u32 value) | 370 | snd_azf3328_game_outb(const struct snd_azf3328 *chip, unsigned reg, u8 value) |
281 | { | 371 | { |
282 | outl(value, chip->codec_port + reg); | 372 | outb(value, chip->game_io + reg); |
283 | } | 373 | } |
284 | 374 | ||
285 | static inline void | 375 | static inline void |
286 | snd_azf3328_io2_outb(const struct snd_azf3328 *chip, int reg, u8 value) | 376 | snd_azf3328_game_outw(const struct snd_azf3328 *chip, unsigned reg, u16 value) |
287 | { | 377 | { |
288 | outb(value, chip->io2_port + reg); | 378 | outw(value, chip->game_io + reg); |
289 | } | 379 | } |
290 | 380 | ||
291 | static inline u8 | 381 | static inline u8 |
292 | snd_azf3328_io2_inb(const struct snd_azf3328 *chip, int reg) | 382 | snd_azf3328_game_inb(const struct snd_azf3328 *chip, unsigned reg) |
293 | { | 383 | { |
294 | return inb(chip->io2_port + reg); | 384 | return inb(chip->game_io + reg); |
385 | } | ||
386 | |||
387 | static inline u16 | ||
388 | snd_azf3328_game_inw(const struct snd_azf3328 *chip, unsigned reg) | ||
389 | { | ||
390 | return inw(chip->game_io + reg); | ||
295 | } | 391 | } |
296 | 392 | ||
297 | static inline void | 393 | static inline void |
298 | snd_azf3328_mixer_outw(const struct snd_azf3328 *chip, int reg, u16 value) | 394 | snd_azf3328_mixer_outw(const struct snd_azf3328 *chip, unsigned reg, u16 value) |
299 | { | 395 | { |
300 | outw(value, chip->mixer_port + reg); | 396 | outw(value, chip->mixer_io + reg); |
301 | } | 397 | } |
302 | 398 | ||
303 | static inline u16 | 399 | static inline u16 |
304 | snd_azf3328_mixer_inw(const struct snd_azf3328 *chip, int reg) | 400 | snd_azf3328_mixer_inw(const struct snd_azf3328 *chip, unsigned reg) |
305 | { | 401 | { |
306 | return inw(chip->mixer_port + reg); | 402 | return inw(chip->mixer_io + reg); |
307 | } | 403 | } |
308 | 404 | ||
309 | static void | 405 | #define AZF_MUTE_BIT 0x80 |
310 | snd_azf3328_mixer_set_mute(const struct snd_azf3328 *chip, int reg, int do_mute) | 406 | |
407 | static int | ||
408 | snd_azf3328_mixer_set_mute(const struct snd_azf3328 *chip, | ||
409 | unsigned reg, int do_mute | ||
410 | ) | ||
311 | { | 411 | { |
312 | unsigned long portbase = chip->mixer_port + reg + 1; | 412 | unsigned long portbase = chip->mixer_io + reg + 1; |
313 | unsigned char oldval; | 413 | int updated; |
314 | 414 | ||
315 | /* the mute bit is on the *second* (i.e. right) register of a | 415 | /* the mute bit is on the *second* (i.e. right) register of a |
316 | * left/right channel setting */ | 416 | * left/right channel setting */ |
317 | oldval = inb(portbase); | 417 | updated = snd_azf3328_io_reg_setb(portbase, AZF_MUTE_BIT, do_mute); |
318 | if (do_mute) | 418 | |
319 | oldval |= 0x80; | 419 | /* indicate whether it was muted before */ |
320 | else | 420 | return (do_mute) ? !updated : updated; |
321 | oldval &= ~0x80; | ||
322 | outb(oldval, portbase); | ||
323 | } | 421 | } |
324 | 422 | ||
325 | static void | 423 | static void |
326 | snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip, int reg, unsigned char dst_vol_left, unsigned char dst_vol_right, int chan_sel, int delay) | 424 | snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip, |
425 | unsigned reg, | ||
426 | unsigned char dst_vol_left, | ||
427 | unsigned char dst_vol_right, | ||
428 | int chan_sel, int delay | ||
429 | ) | ||
327 | { | 430 | { |
328 | unsigned long portbase = chip->mixer_port + reg; | 431 | unsigned long portbase = chip->mixer_io + reg; |
329 | unsigned char curr_vol_left = 0, curr_vol_right = 0; | 432 | unsigned char curr_vol_left = 0, curr_vol_right = 0; |
330 | int left_done = 0, right_done = 0; | 433 | int left_change = 0, right_change = 0; |
331 | 434 | ||
332 | snd_azf3328_dbgcallenter(); | 435 | snd_azf3328_dbgcallenter(); |
333 | if (chan_sel & SET_CHAN_LEFT) | 436 | |
437 | if (chan_sel & SET_CHAN_LEFT) { | ||
334 | curr_vol_left = inb(portbase + 1); | 438 | curr_vol_left = inb(portbase + 1); |
335 | else | 439 | |
336 | left_done = 1; | 440 | /* take care of muting flag contained in left channel */ |
337 | if (chan_sel & SET_CHAN_RIGHT) | 441 | if (curr_vol_left & AZF_MUTE_BIT) |
442 | dst_vol_left |= AZF_MUTE_BIT; | ||
443 | else | ||
444 | dst_vol_left &= ~AZF_MUTE_BIT; | ||
445 | |||
446 | left_change = (curr_vol_left > dst_vol_left) ? -1 : 1; | ||
447 | } | ||
448 | |||
449 | if (chan_sel & SET_CHAN_RIGHT) { | ||
338 | curr_vol_right = inb(portbase + 0); | 450 | curr_vol_right = inb(portbase + 0); |
339 | else | 451 | |
340 | right_done = 1; | 452 | right_change = (curr_vol_right > dst_vol_right) ? -1 : 1; |
341 | 453 | } | |
342 | /* take care of muting flag (0x80) contained in left channel */ | ||
343 | if (curr_vol_left & 0x80) | ||
344 | dst_vol_left |= 0x80; | ||
345 | else | ||
346 | dst_vol_left &= ~0x80; | ||
347 | 454 | ||
348 | do { | 455 | do { |
349 | if (!left_done) { | 456 | if (left_change) { |
350 | if (curr_vol_left > dst_vol_left) | 457 | if (curr_vol_left != dst_vol_left) { |
351 | curr_vol_left--; | 458 | curr_vol_left += left_change; |
352 | else | 459 | outb(curr_vol_left, portbase + 1); |
353 | if (curr_vol_left < dst_vol_left) | 460 | } else |
354 | curr_vol_left++; | 461 | left_change = 0; |
355 | else | ||
356 | left_done = 1; | ||
357 | outb(curr_vol_left, portbase + 1); | ||
358 | } | 462 | } |
359 | if (!right_done) { | 463 | if (right_change) { |
360 | if (curr_vol_right > dst_vol_right) | 464 | if (curr_vol_right != dst_vol_right) { |
361 | curr_vol_right--; | 465 | curr_vol_right += right_change; |
362 | else | 466 | |
363 | if (curr_vol_right < dst_vol_right) | ||
364 | curr_vol_right++; | ||
365 | else | ||
366 | right_done = 1; | ||
367 | /* during volume change, the right channel is crackling | 467 | /* during volume change, the right channel is crackling |
368 | * somewhat more than the left channel, unfortunately. | 468 | * somewhat more than the left channel, unfortunately. |
369 | * This seems to be a hardware issue. */ | 469 | * This seems to be a hardware issue. */ |
370 | outb(curr_vol_right, portbase + 0); | 470 | outb(curr_vol_right, portbase + 0); |
471 | } else | ||
472 | right_change = 0; | ||
371 | } | 473 | } |
372 | if (delay) | 474 | if (delay) |
373 | mdelay(delay); | 475 | mdelay(delay); |
374 | } while ((!left_done) || (!right_done)); | 476 | } while ((left_change) || (right_change)); |
375 | snd_azf3328_dbgcallleave(); | 477 | snd_azf3328_dbgcallleave(); |
376 | } | 478 | } |
377 | 479 | ||
@@ -379,7 +481,7 @@ snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip, int reg | |||
379 | * general mixer element | 481 | * general mixer element |
380 | */ | 482 | */ |
381 | struct azf3328_mixer_reg { | 483 | struct azf3328_mixer_reg { |
382 | unsigned int reg; | 484 | unsigned reg; |
383 | unsigned int lchan_shift, rchan_shift; | 485 | unsigned int lchan_shift, rchan_shift; |
384 | unsigned int mask; | 486 | unsigned int mask; |
385 | unsigned int invert: 1; | 487 | unsigned int invert: 1; |
@@ -544,13 +646,14 @@ snd_azf3328_info_mixer_enum(struct snd_kcontrol *kcontrol, | |||
544 | "Mix", "Mic" | 646 | "Mix", "Mic" |
545 | }; | 647 | }; |
546 | static const char * const texts3[] = { | 648 | static const char * const texts3[] = { |
547 | "Mic", "CD", "Video", "Aux", | 649 | "Mic", "CD", "Video", "Aux", |
548 | "Line", "Mix", "Mix Mono", "Phone" | 650 | "Line", "Mix", "Mix Mono", "Phone" |
549 | }; | 651 | }; |
550 | static const char * const texts4[] = { | 652 | static const char * const texts4[] = { |
551 | "pre 3D", "post 3D" | 653 | "pre 3D", "post 3D" |
552 | }; | 654 | }; |
553 | struct azf3328_mixer_reg reg; | 655 | struct azf3328_mixer_reg reg; |
656 | const char * const *p = NULL; | ||
554 | 657 | ||
555 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); | 658 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); |
556 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 659 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
@@ -561,18 +664,20 @@ snd_azf3328_info_mixer_enum(struct snd_kcontrol *kcontrol, | |||
561 | if (reg.reg == IDX_MIXER_ADVCTL2) { | 664 | if (reg.reg == IDX_MIXER_ADVCTL2) { |
562 | switch(reg.lchan_shift) { | 665 | switch(reg.lchan_shift) { |
563 | case 8: /* modem out sel */ | 666 | case 8: /* modem out sel */ |
564 | strcpy(uinfo->value.enumerated.name, texts1[uinfo->value.enumerated.item]); | 667 | p = texts1; |
565 | break; | 668 | break; |
566 | case 9: /* mono sel source */ | 669 | case 9: /* mono sel source */ |
567 | strcpy(uinfo->value.enumerated.name, texts2[uinfo->value.enumerated.item]); | 670 | p = texts2; |
568 | break; | 671 | break; |
569 | case 15: /* PCM Out Path */ | 672 | case 15: /* PCM Out Path */ |
570 | strcpy(uinfo->value.enumerated.name, texts4[uinfo->value.enumerated.item]); | 673 | p = texts4; |
571 | break; | 674 | break; |
572 | } | 675 | } |
573 | } else | 676 | } else |
574 | strcpy(uinfo->value.enumerated.name, texts3[uinfo->value.enumerated.item] | 677 | if (reg.reg == IDX_MIXER_REC_SELECT) |
575 | ); | 678 | p = texts3; |
679 | |||
680 | strcpy(uinfo->value.enumerated.name, p[uinfo->value.enumerated.item]); | ||
576 | return 0; | 681 | return 0; |
577 | } | 682 | } |
578 | 683 | ||
@@ -583,7 +688,7 @@ snd_azf3328_get_mixer_enum(struct snd_kcontrol *kcontrol, | |||
583 | struct snd_azf3328 *chip = snd_kcontrol_chip(kcontrol); | 688 | struct snd_azf3328 *chip = snd_kcontrol_chip(kcontrol); |
584 | struct azf3328_mixer_reg reg; | 689 | struct azf3328_mixer_reg reg; |
585 | unsigned short val; | 690 | unsigned short val; |
586 | 691 | ||
587 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); | 692 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); |
588 | val = snd_azf3328_mixer_inw(chip, reg.reg); | 693 | val = snd_azf3328_mixer_inw(chip, reg.reg); |
589 | if (reg.reg == IDX_MIXER_REC_SELECT) { | 694 | if (reg.reg == IDX_MIXER_REC_SELECT) { |
@@ -605,7 +710,7 @@ snd_azf3328_put_mixer_enum(struct snd_kcontrol *kcontrol, | |||
605 | struct snd_azf3328 *chip = snd_kcontrol_chip(kcontrol); | 710 | struct snd_azf3328 *chip = snd_kcontrol_chip(kcontrol); |
606 | struct azf3328_mixer_reg reg; | 711 | struct azf3328_mixer_reg reg; |
607 | unsigned int oreg, nreg, val; | 712 | unsigned int oreg, nreg, val; |
608 | 713 | ||
609 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); | 714 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); |
610 | oreg = snd_azf3328_mixer_inw(chip, reg.reg); | 715 | oreg = snd_azf3328_mixer_inw(chip, reg.reg); |
611 | val = oreg; | 716 | val = oreg; |
@@ -631,9 +736,11 @@ snd_azf3328_put_mixer_enum(struct snd_kcontrol *kcontrol, | |||
631 | static struct snd_kcontrol_new snd_azf3328_mixer_controls[] __devinitdata = { | 736 | static struct snd_kcontrol_new snd_azf3328_mixer_controls[] __devinitdata = { |
632 | AZF3328_MIXER_SWITCH("Master Playback Switch", IDX_MIXER_PLAY_MASTER, 15, 1), | 737 | AZF3328_MIXER_SWITCH("Master Playback Switch", IDX_MIXER_PLAY_MASTER, 15, 1), |
633 | AZF3328_MIXER_VOL_STEREO("Master Playback Volume", IDX_MIXER_PLAY_MASTER, 0x1f, 1), | 738 | AZF3328_MIXER_VOL_STEREO("Master Playback Volume", IDX_MIXER_PLAY_MASTER, 0x1f, 1), |
634 | AZF3328_MIXER_SWITCH("Wave Playback Switch", IDX_MIXER_WAVEOUT, 15, 1), | 739 | AZF3328_MIXER_SWITCH("PCM Playback Switch", IDX_MIXER_WAVEOUT, 15, 1), |
635 | AZF3328_MIXER_VOL_STEREO("Wave Playback Volume", IDX_MIXER_WAVEOUT, 0x1f, 1), | 740 | AZF3328_MIXER_VOL_STEREO("PCM Playback Volume", |
636 | AZF3328_MIXER_SWITCH("Wave 3D Bypass Playback Switch", IDX_MIXER_ADVCTL2, 7, 1), | 741 | IDX_MIXER_WAVEOUT, 0x1f, 1), |
742 | AZF3328_MIXER_SWITCH("PCM 3D Bypass Playback Switch", | ||
743 | IDX_MIXER_ADVCTL2, 7, 1), | ||
637 | AZF3328_MIXER_SWITCH("FM Playback Switch", IDX_MIXER_FMSYNTH, 15, 1), | 744 | AZF3328_MIXER_SWITCH("FM Playback Switch", IDX_MIXER_FMSYNTH, 15, 1), |
638 | AZF3328_MIXER_VOL_STEREO("FM Playback Volume", IDX_MIXER_FMSYNTH, 0x1f, 1), | 745 | AZF3328_MIXER_VOL_STEREO("FM Playback Volume", IDX_MIXER_FMSYNTH, 0x1f, 1), |
639 | AZF3328_MIXER_SWITCH("CD Playback Switch", IDX_MIXER_CDAUDIO, 15, 1), | 746 | AZF3328_MIXER_SWITCH("CD Playback Switch", IDX_MIXER_CDAUDIO, 15, 1), |
@@ -717,15 +824,16 @@ snd_azf3328_mixer_new(struct snd_azf3328 *chip) | |||
717 | snd_azf3328_mixer_outw(chip, IDX_MIXER_RESET, 0x0000); | 824 | snd_azf3328_mixer_outw(chip, IDX_MIXER_RESET, 0x0000); |
718 | 825 | ||
719 | /* mute and zero volume channels */ | 826 | /* mute and zero volume channels */ |
720 | for (idx = 0; idx < ARRAY_SIZE(snd_azf3328_init_values); idx++) { | 827 | for (idx = 0; idx < ARRAY_SIZE(snd_azf3328_init_values); ++idx) { |
721 | snd_azf3328_mixer_outw(chip, | 828 | snd_azf3328_mixer_outw(chip, |
722 | snd_azf3328_init_values[idx][0], | 829 | snd_azf3328_init_values[idx][0], |
723 | snd_azf3328_init_values[idx][1]); | 830 | snd_azf3328_init_values[idx][1]); |
724 | } | 831 | } |
725 | 832 | ||
726 | /* add mixer controls */ | 833 | /* add mixer controls */ |
727 | sw = snd_azf3328_mixer_controls; | 834 | sw = snd_azf3328_mixer_controls; |
728 | for (idx = 0; idx < ARRAY_SIZE(snd_azf3328_mixer_controls); idx++, sw++) { | 835 | for (idx = 0; idx < ARRAY_SIZE(snd_azf3328_mixer_controls); |
836 | ++idx, ++sw) { | ||
729 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(sw, chip))) < 0) | 837 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(sw, chip))) < 0) |
730 | return err; | 838 | return err; |
731 | } | 839 | } |
@@ -757,9 +865,9 @@ snd_azf3328_hw_free(struct snd_pcm_substream *substream) | |||
757 | } | 865 | } |
758 | 866 | ||
759 | static void | 867 | static void |
760 | snd_azf3328_setfmt(struct snd_azf3328 *chip, | 868 | snd_azf3328_codec_setfmt(struct snd_azf3328 *chip, |
761 | unsigned int reg, | 869 | unsigned reg, |
762 | unsigned int bitrate, | 870 | enum azf_freq_t bitrate, |
763 | unsigned int format_width, | 871 | unsigned int format_width, |
764 | unsigned int channels | 872 | unsigned int channels |
765 | ) | 873 | ) |
@@ -769,24 +877,25 @@ snd_azf3328_setfmt(struct snd_azf3328 *chip, | |||
769 | 877 | ||
770 | snd_azf3328_dbgcallenter(); | 878 | snd_azf3328_dbgcallenter(); |
771 | switch (bitrate) { | 879 | switch (bitrate) { |
772 | case 4000: val |= SOUNDFORMAT_FREQ_SUSPECTED_4000; break; | 880 | case AZF_FREQ_4000: val |= SOUNDFORMAT_FREQ_SUSPECTED_4000; break; |
773 | case 4800: val |= SOUNDFORMAT_FREQ_SUSPECTED_4800; break; | 881 | case AZF_FREQ_4800: val |= SOUNDFORMAT_FREQ_SUSPECTED_4800; break; |
774 | case 5512: val |= SOUNDFORMAT_FREQ_5510; break; /* the AZF3328 names it "5510" for some strange reason */ | 882 | case AZF_FREQ_5512: |
775 | case 6620: val |= SOUNDFORMAT_FREQ_6620; break; | 883 | /* the AZF3328 names it "5510" for some strange reason */ |
776 | case 8000: val |= SOUNDFORMAT_FREQ_8000; break; | 884 | val |= SOUNDFORMAT_FREQ_5510; break; |
777 | case 9600: val |= SOUNDFORMAT_FREQ_9600; break; | 885 | case AZF_FREQ_6620: val |= SOUNDFORMAT_FREQ_6620; break; |
778 | case 11025: val |= SOUNDFORMAT_FREQ_11025; break; | 886 | case AZF_FREQ_8000: val |= SOUNDFORMAT_FREQ_8000; break; |
779 | case 13240: val |= SOUNDFORMAT_FREQ_SUSPECTED_13240; break; | 887 | case AZF_FREQ_9600: val |= SOUNDFORMAT_FREQ_9600; break; |
780 | case 16000: val |= SOUNDFORMAT_FREQ_16000; break; | 888 | case AZF_FREQ_11025: val |= SOUNDFORMAT_FREQ_11025; break; |
781 | case 22050: val |= SOUNDFORMAT_FREQ_22050; break; | 889 | case AZF_FREQ_13240: val |= SOUNDFORMAT_FREQ_SUSPECTED_13240; break; |
782 | case 32000: val |= SOUNDFORMAT_FREQ_32000; break; | 890 | case AZF_FREQ_16000: val |= SOUNDFORMAT_FREQ_16000; break; |
783 | case 44100: val |= SOUNDFORMAT_FREQ_44100; break; | 891 | case AZF_FREQ_22050: val |= SOUNDFORMAT_FREQ_22050; break; |
784 | case 48000: val |= SOUNDFORMAT_FREQ_48000; break; | 892 | case AZF_FREQ_32000: val |= SOUNDFORMAT_FREQ_32000; break; |
785 | case 66200: val |= SOUNDFORMAT_FREQ_SUSPECTED_66200; break; | ||
786 | default: | 893 | default: |
787 | snd_printk(KERN_WARNING "unknown bitrate %d, assuming 44.1kHz!\n", bitrate); | 894 | snd_printk(KERN_WARNING "unknown bitrate %d, assuming 44.1kHz!\n", bitrate); |
788 | val |= SOUNDFORMAT_FREQ_44100; | 895 | /* fall-through */ |
789 | break; | 896 | case AZF_FREQ_44100: val |= SOUNDFORMAT_FREQ_44100; break; |
897 | case AZF_FREQ_48000: val |= SOUNDFORMAT_FREQ_48000; break; | ||
898 | case AZF_FREQ_66200: val |= SOUNDFORMAT_FREQ_SUSPECTED_66200; break; | ||
790 | } | 899 | } |
791 | /* val = 0xff07; 3m27.993s (65301Hz; -> 64000Hz???) hmm, 66120, 65967, 66123 */ | 900 | /* val = 0xff07; 3m27.993s (65301Hz; -> 64000Hz???) hmm, 66120, 65967, 66123 */ |
792 | /* val = 0xff09; 17m15.098s (13123,478Hz; -> 12000Hz???) hmm, 13237.2Hz? */ | 901 | /* val = 0xff09; 17m15.098s (13123,478Hz; -> 12000Hz???) hmm, 13237.2Hz? */ |
@@ -805,10 +914,10 @@ snd_azf3328_setfmt(struct snd_azf3328 *chip, | |||
805 | val |= SOUNDFORMAT_FLAG_16BIT; | 914 | val |= SOUNDFORMAT_FLAG_16BIT; |
806 | 915 | ||
807 | spin_lock_irqsave(&chip->reg_lock, flags); | 916 | spin_lock_irqsave(&chip->reg_lock, flags); |
808 | 917 | ||
809 | /* set bitrate/format */ | 918 | /* set bitrate/format */ |
810 | snd_azf3328_codec_outw(chip, reg, val); | 919 | snd_azf3328_codec_outw(chip, reg, val); |
811 | 920 | ||
812 | /* changing the bitrate/format settings switches off the | 921 | /* changing the bitrate/format settings switches off the |
813 | * audio output with an annoying click in case of 8/16bit format change | 922 | * audio output with an annoying click in case of 8/16bit format change |
814 | * (maybe shutting down DAC/ADC?), thus immediately | 923 | * (maybe shutting down DAC/ADC?), thus immediately |
@@ -830,31 +939,95 @@ snd_azf3328_setfmt(struct snd_azf3328 *chip, | |||
830 | snd_azf3328_dbgcallleave(); | 939 | snd_azf3328_dbgcallleave(); |
831 | } | 940 | } |
832 | 941 | ||
942 | static inline void | ||
943 | snd_azf3328_codec_setfmt_lowpower(struct snd_azf3328 *chip, | ||
944 | unsigned reg | ||
945 | ) | ||
946 | { | ||
947 | /* choose lowest frequency for low power consumption. | ||
948 | * While this will cause louder noise due to rather coarse frequency, | ||
949 | * it should never matter since output should always | ||
950 | * get disabled properly when idle anyway. */ | ||
951 | snd_azf3328_codec_setfmt(chip, reg, AZF_FREQ_4000, 8, 1); | ||
952 | } | ||
953 | |||
954 | static void | ||
955 | snd_azf3328_codec_reg_6AH_update(struct snd_azf3328 *chip, | ||
956 | unsigned bitmask, | ||
957 | int enable | ||
958 | ) | ||
959 | { | ||
960 | if (enable) | ||
961 | chip->shadow_reg_codec_6AH &= ~bitmask; | ||
962 | else | ||
963 | chip->shadow_reg_codec_6AH |= bitmask; | ||
964 | snd_azf3328_dbgplay("6AH_update mask 0x%04x enable %d: val 0x%04x\n", | ||
965 | bitmask, enable, chip->shadow_reg_codec_6AH); | ||
966 | snd_azf3328_codec_outw(chip, IDX_IO_6AH, chip->shadow_reg_codec_6AH); | ||
967 | } | ||
968 | |||
969 | static inline void | ||
970 | snd_azf3328_codec_enable(struct snd_azf3328 *chip, int enable) | ||
971 | { | ||
972 | snd_azf3328_dbgplay("codec_enable %d\n", enable); | ||
973 | /* no idea what exactly is being done here, but I strongly assume it's | ||
974 | * PM related */ | ||
975 | snd_azf3328_codec_reg_6AH_update( | ||
976 | chip, IO_6A_PAUSE_PLAYBACK_BIT8, enable | ||
977 | ); | ||
978 | } | ||
979 | |||
980 | static void | ||
981 | snd_azf3328_codec_activity(struct snd_azf3328 *chip, | ||
982 | enum snd_azf3328_stream_index stream_type, | ||
983 | int enable | ||
984 | ) | ||
985 | { | ||
986 | int need_change = (chip->audio_stream[stream_type].running != enable); | ||
987 | |||
988 | snd_azf3328_dbgplay( | ||
989 | "codec_activity: type %d, enable %d, need_change %d\n", | ||
990 | stream_type, enable, need_change | ||
991 | ); | ||
992 | if (need_change) { | ||
993 | enum snd_azf3328_stream_index other = | ||
994 | (stream_type == AZF_PLAYBACK) ? | ||
995 | AZF_CAPTURE : AZF_PLAYBACK; | ||
996 | /* small check to prevent shutting down the other party | ||
997 | * in case it's active */ | ||
998 | if ((enable) || !(chip->audio_stream[other].running)) | ||
999 | snd_azf3328_codec_enable(chip, enable); | ||
1000 | |||
1001 | /* ...and adjust clock, too | ||
1002 | * (reduce noise and power consumption) */ | ||
1003 | if (!enable) | ||
1004 | snd_azf3328_codec_setfmt_lowpower( | ||
1005 | chip, | ||
1006 | chip->audio_stream[stream_type].portbase | ||
1007 | + IDX_IO_PLAY_SOUNDFORMAT | ||
1008 | ); | ||
1009 | } | ||
1010 | chip->audio_stream[stream_type].running = enable; | ||
1011 | } | ||
1012 | |||
833 | static void | 1013 | static void |
834 | snd_azf3328_setdmaa(struct snd_azf3328 *chip, | 1014 | snd_azf3328_setdmaa(struct snd_azf3328 *chip, |
835 | long unsigned int addr, | 1015 | long unsigned int addr, |
836 | unsigned int count, | 1016 | unsigned int count, |
837 | unsigned int size, | 1017 | unsigned int size, |
838 | int do_recording) | 1018 | enum snd_azf3328_stream_index stream_type |
1019 | ) | ||
839 | { | 1020 | { |
840 | unsigned long flags, portbase; | ||
841 | unsigned int is_running; | ||
842 | |||
843 | snd_azf3328_dbgcallenter(); | 1021 | snd_azf3328_dbgcallenter(); |
844 | if (do_recording) { | 1022 | if (!chip->audio_stream[stream_type].running) { |
845 | /* access capture registers, i.e. skip playback reg section */ | 1023 | /* AZF3328 uses a two buffer pointer DMA playback approach */ |
846 | portbase = chip->codec_port + 0x20; | ||
847 | is_running = chip->is_recording; | ||
848 | } else { | ||
849 | /* access the playback register section */ | ||
850 | portbase = chip->codec_port + 0x00; | ||
851 | is_running = chip->is_playing; | ||
852 | } | ||
853 | 1024 | ||
854 | /* AZF3328 uses a two buffer pointer DMA playback approach */ | 1025 | unsigned long flags, portbase, addr_area2; |
855 | if (!is_running) { | 1026 | |
856 | unsigned long addr_area2; | 1027 | /* width 32bit (prevent overflow): */ |
857 | unsigned long count_areas, count_tmp; /* width 32bit -- overflow!! */ | 1028 | unsigned long count_areas, count_tmp; |
1029 | |||
1030 | portbase = chip->audio_stream[stream_type].portbase; | ||
858 | count_areas = size/2; | 1031 | count_areas = size/2; |
859 | addr_area2 = addr+count_areas; | 1032 | addr_area2 = addr+count_areas; |
860 | count_areas--; /* max. index */ | 1033 | count_areas--; /* max. index */ |
@@ -884,11 +1057,11 @@ snd_azf3328_playback_prepare(struct snd_pcm_substream *substream) | |||
884 | 1057 | ||
885 | snd_azf3328_dbgcallenter(); | 1058 | snd_azf3328_dbgcallenter(); |
886 | #if 0 | 1059 | #if 0 |
887 | snd_azf3328_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, | 1060 | snd_azf3328_codec_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, |
888 | runtime->rate, | 1061 | runtime->rate, |
889 | snd_pcm_format_width(runtime->format), | 1062 | snd_pcm_format_width(runtime->format), |
890 | runtime->channels); | 1063 | runtime->channels); |
891 | snd_azf3328_setdmaa(chip, runtime->dma_addr, count, size, 0); | 1064 | snd_azf3328_setdmaa(chip, runtime->dma_addr, count, size, AZF_PLAYBACK); |
892 | #endif | 1065 | #endif |
893 | snd_azf3328_dbgcallleave(); | 1066 | snd_azf3328_dbgcallleave(); |
894 | return 0; | 1067 | return 0; |
@@ -906,11 +1079,11 @@ snd_azf3328_capture_prepare(struct snd_pcm_substream *substream) | |||
906 | 1079 | ||
907 | snd_azf3328_dbgcallenter(); | 1080 | snd_azf3328_dbgcallenter(); |
908 | #if 0 | 1081 | #if 0 |
909 | snd_azf3328_setfmt(chip, IDX_IO_REC_SOUNDFORMAT, | 1082 | snd_azf3328_codec_setfmt(chip, IDX_IO_REC_SOUNDFORMAT, |
910 | runtime->rate, | 1083 | runtime->rate, |
911 | snd_pcm_format_width(runtime->format), | 1084 | snd_pcm_format_width(runtime->format), |
912 | runtime->channels); | 1085 | runtime->channels); |
913 | snd_azf3328_setdmaa(chip, runtime->dma_addr, count, size, 1); | 1086 | snd_azf3328_setdmaa(chip, runtime->dma_addr, count, size, AZF_CAPTURE); |
914 | #endif | 1087 | #endif |
915 | snd_azf3328_dbgcallleave(); | 1088 | snd_azf3328_dbgcallleave(); |
916 | return 0; | 1089 | return 0; |
@@ -923,6 +1096,7 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd) | |||
923 | struct snd_pcm_runtime *runtime = substream->runtime; | 1096 | struct snd_pcm_runtime *runtime = substream->runtime; |
924 | int result = 0; | 1097 | int result = 0; |
925 | unsigned int status1; | 1098 | unsigned int status1; |
1099 | int previously_muted; | ||
926 | 1100 | ||
927 | snd_azf3328_dbgcalls("snd_azf3328_playback_trigger cmd %d\n", cmd); | 1101 | snd_azf3328_dbgcalls("snd_azf3328_playback_trigger cmd %d\n", cmd); |
928 | 1102 | ||
@@ -930,20 +1104,23 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd) | |||
930 | case SNDRV_PCM_TRIGGER_START: | 1104 | case SNDRV_PCM_TRIGGER_START: |
931 | snd_azf3328_dbgplay("START PLAYBACK\n"); | 1105 | snd_azf3328_dbgplay("START PLAYBACK\n"); |
932 | 1106 | ||
933 | /* mute WaveOut */ | 1107 | /* mute WaveOut (avoid clicking during setup) */ |
934 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); | 1108 | previously_muted = |
1109 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); | ||
935 | 1110 | ||
936 | snd_azf3328_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, | 1111 | snd_azf3328_codec_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, |
937 | runtime->rate, | 1112 | runtime->rate, |
938 | snd_pcm_format_width(runtime->format), | 1113 | snd_pcm_format_width(runtime->format), |
939 | runtime->channels); | 1114 | runtime->channels); |
940 | 1115 | ||
941 | spin_lock(&chip->reg_lock); | 1116 | spin_lock(&chip->reg_lock); |
942 | /* stop playback */ | 1117 | /* first, remember current value: */ |
943 | status1 = snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS); | 1118 | status1 = snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS); |
1119 | |||
1120 | /* stop playback */ | ||
944 | status1 &= ~DMA_RESUME; | 1121 | status1 &= ~DMA_RESUME; |
945 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); | 1122 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); |
946 | 1123 | ||
947 | /* FIXME: clear interrupts or what??? */ | 1124 | /* FIXME: clear interrupts or what??? */ |
948 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_IRQTYPE, 0xffff); | 1125 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_IRQTYPE, 0xffff); |
949 | spin_unlock(&chip->reg_lock); | 1126 | spin_unlock(&chip->reg_lock); |
@@ -951,7 +1128,7 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd) | |||
951 | snd_azf3328_setdmaa(chip, runtime->dma_addr, | 1128 | snd_azf3328_setdmaa(chip, runtime->dma_addr, |
952 | snd_pcm_lib_period_bytes(substream), | 1129 | snd_pcm_lib_period_bytes(substream), |
953 | snd_pcm_lib_buffer_bytes(substream), | 1130 | snd_pcm_lib_buffer_bytes(substream), |
954 | 0); | 1131 | AZF_PLAYBACK); |
955 | 1132 | ||
956 | spin_lock(&chip->reg_lock); | 1133 | spin_lock(&chip->reg_lock); |
957 | #ifdef WIN9X | 1134 | #ifdef WIN9X |
@@ -978,30 +1155,35 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd) | |||
978 | DMA_SOMETHING_ELSE); | 1155 | DMA_SOMETHING_ELSE); |
979 | #endif | 1156 | #endif |
980 | spin_unlock(&chip->reg_lock); | 1157 | spin_unlock(&chip->reg_lock); |
1158 | snd_azf3328_codec_activity(chip, AZF_PLAYBACK, 1); | ||
981 | 1159 | ||
982 | /* now unmute WaveOut */ | 1160 | /* now unmute WaveOut */ |
983 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 0); | 1161 | if (!previously_muted) |
1162 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 0); | ||
984 | 1163 | ||
985 | chip->is_playing = 1; | ||
986 | snd_azf3328_dbgplay("STARTED PLAYBACK\n"); | 1164 | snd_azf3328_dbgplay("STARTED PLAYBACK\n"); |
987 | break; | 1165 | break; |
988 | case SNDRV_PCM_TRIGGER_RESUME: | 1166 | case SNDRV_PCM_TRIGGER_RESUME: |
989 | snd_azf3328_dbgplay("RESUME PLAYBACK\n"); | 1167 | snd_azf3328_dbgplay("RESUME PLAYBACK\n"); |
990 | /* resume playback if we were active */ | 1168 | /* resume playback if we were active */ |
991 | if (chip->is_playing) | 1169 | spin_lock(&chip->reg_lock); |
1170 | if (chip->audio_stream[AZF_PLAYBACK].running) | ||
992 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, | 1171 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, |
993 | snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) | DMA_RESUME); | 1172 | snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) | DMA_RESUME); |
1173 | spin_unlock(&chip->reg_lock); | ||
994 | break; | 1174 | break; |
995 | case SNDRV_PCM_TRIGGER_STOP: | 1175 | case SNDRV_PCM_TRIGGER_STOP: |
996 | snd_azf3328_dbgplay("STOP PLAYBACK\n"); | 1176 | snd_azf3328_dbgplay("STOP PLAYBACK\n"); |
997 | 1177 | ||
998 | /* mute WaveOut */ | 1178 | /* mute WaveOut (avoid clicking during setup) */ |
999 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); | 1179 | previously_muted = |
1180 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); | ||
1000 | 1181 | ||
1001 | spin_lock(&chip->reg_lock); | 1182 | spin_lock(&chip->reg_lock); |
1002 | /* stop playback */ | 1183 | /* first, remember current value: */ |
1003 | status1 = snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS); | 1184 | status1 = snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS); |
1004 | 1185 | ||
1186 | /* stop playback */ | ||
1005 | status1 &= ~DMA_RESUME; | 1187 | status1 &= ~DMA_RESUME; |
1006 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); | 1188 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); |
1007 | 1189 | ||
@@ -1013,10 +1195,12 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd) | |||
1013 | status1 &= ~DMA_PLAY_SOMETHING1; | 1195 | status1 &= ~DMA_PLAY_SOMETHING1; |
1014 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); | 1196 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); |
1015 | spin_unlock(&chip->reg_lock); | 1197 | spin_unlock(&chip->reg_lock); |
1016 | 1198 | snd_azf3328_codec_activity(chip, AZF_PLAYBACK, 0); | |
1199 | |||
1017 | /* now unmute WaveOut */ | 1200 | /* now unmute WaveOut */ |
1018 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 0); | 1201 | if (!previously_muted) |
1019 | chip->is_playing = 0; | 1202 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 0); |
1203 | |||
1020 | snd_azf3328_dbgplay("STOPPED PLAYBACK\n"); | 1204 | snd_azf3328_dbgplay("STOPPED PLAYBACK\n"); |
1021 | break; | 1205 | break; |
1022 | case SNDRV_PCM_TRIGGER_SUSPEND: | 1206 | case SNDRV_PCM_TRIGGER_SUSPEND: |
@@ -1035,7 +1219,7 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd) | |||
1035 | printk(KERN_ERR "FIXME: unknown trigger mode!\n"); | 1219 | printk(KERN_ERR "FIXME: unknown trigger mode!\n"); |
1036 | return -EINVAL; | 1220 | return -EINVAL; |
1037 | } | 1221 | } |
1038 | 1222 | ||
1039 | snd_azf3328_dbgcallleave(); | 1223 | snd_azf3328_dbgcallleave(); |
1040 | return result; | 1224 | return result; |
1041 | } | 1225 | } |
@@ -1057,17 +1241,19 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd) | |||
1057 | 1241 | ||
1058 | snd_azf3328_dbgplay("START CAPTURE\n"); | 1242 | snd_azf3328_dbgplay("START CAPTURE\n"); |
1059 | 1243 | ||
1060 | snd_azf3328_setfmt(chip, IDX_IO_REC_SOUNDFORMAT, | 1244 | snd_azf3328_codec_setfmt(chip, IDX_IO_REC_SOUNDFORMAT, |
1061 | runtime->rate, | 1245 | runtime->rate, |
1062 | snd_pcm_format_width(runtime->format), | 1246 | snd_pcm_format_width(runtime->format), |
1063 | runtime->channels); | 1247 | runtime->channels); |
1064 | 1248 | ||
1065 | spin_lock(&chip->reg_lock); | 1249 | spin_lock(&chip->reg_lock); |
1066 | /* stop recording */ | 1250 | /* first, remember current value: */ |
1067 | status1 = snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS); | 1251 | status1 = snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS); |
1252 | |||
1253 | /* stop recording */ | ||
1068 | status1 &= ~DMA_RESUME; | 1254 | status1 &= ~DMA_RESUME; |
1069 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); | 1255 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); |
1070 | 1256 | ||
1071 | /* FIXME: clear interrupts or what??? */ | 1257 | /* FIXME: clear interrupts or what??? */ |
1072 | snd_azf3328_codec_outw(chip, IDX_IO_REC_IRQTYPE, 0xffff); | 1258 | snd_azf3328_codec_outw(chip, IDX_IO_REC_IRQTYPE, 0xffff); |
1073 | spin_unlock(&chip->reg_lock); | 1259 | spin_unlock(&chip->reg_lock); |
@@ -1075,7 +1261,7 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd) | |||
1075 | snd_azf3328_setdmaa(chip, runtime->dma_addr, | 1261 | snd_azf3328_setdmaa(chip, runtime->dma_addr, |
1076 | snd_pcm_lib_period_bytes(substream), | 1262 | snd_pcm_lib_period_bytes(substream), |
1077 | snd_pcm_lib_buffer_bytes(substream), | 1263 | snd_pcm_lib_buffer_bytes(substream), |
1078 | 1); | 1264 | AZF_CAPTURE); |
1079 | 1265 | ||
1080 | spin_lock(&chip->reg_lock); | 1266 | spin_lock(&chip->reg_lock); |
1081 | #ifdef WIN9X | 1267 | #ifdef WIN9X |
@@ -1102,24 +1288,27 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd) | |||
1102 | DMA_SOMETHING_ELSE); | 1288 | DMA_SOMETHING_ELSE); |
1103 | #endif | 1289 | #endif |
1104 | spin_unlock(&chip->reg_lock); | 1290 | spin_unlock(&chip->reg_lock); |
1291 | snd_azf3328_codec_activity(chip, AZF_CAPTURE, 1); | ||
1105 | 1292 | ||
1106 | chip->is_recording = 1; | ||
1107 | snd_azf3328_dbgplay("STARTED CAPTURE\n"); | 1293 | snd_azf3328_dbgplay("STARTED CAPTURE\n"); |
1108 | break; | 1294 | break; |
1109 | case SNDRV_PCM_TRIGGER_RESUME: | 1295 | case SNDRV_PCM_TRIGGER_RESUME: |
1110 | snd_azf3328_dbgplay("RESUME CAPTURE\n"); | 1296 | snd_azf3328_dbgplay("RESUME CAPTURE\n"); |
1111 | /* resume recording if we were active */ | 1297 | /* resume recording if we were active */ |
1112 | if (chip->is_recording) | 1298 | spin_lock(&chip->reg_lock); |
1299 | if (chip->audio_stream[AZF_CAPTURE].running) | ||
1113 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, | 1300 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, |
1114 | snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS) | DMA_RESUME); | 1301 | snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS) | DMA_RESUME); |
1302 | spin_unlock(&chip->reg_lock); | ||
1115 | break; | 1303 | break; |
1116 | case SNDRV_PCM_TRIGGER_STOP: | 1304 | case SNDRV_PCM_TRIGGER_STOP: |
1117 | snd_azf3328_dbgplay("STOP CAPTURE\n"); | 1305 | snd_azf3328_dbgplay("STOP CAPTURE\n"); |
1118 | 1306 | ||
1119 | spin_lock(&chip->reg_lock); | 1307 | spin_lock(&chip->reg_lock); |
1120 | /* stop recording */ | 1308 | /* first, remember current value: */ |
1121 | status1 = snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS); | 1309 | status1 = snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS); |
1122 | 1310 | ||
1311 | /* stop recording */ | ||
1123 | status1 &= ~DMA_RESUME; | 1312 | status1 &= ~DMA_RESUME; |
1124 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); | 1313 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); |
1125 | 1314 | ||
@@ -1129,8 +1318,8 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd) | |||
1129 | status1 &= ~DMA_PLAY_SOMETHING1; | 1318 | status1 &= ~DMA_PLAY_SOMETHING1; |
1130 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); | 1319 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); |
1131 | spin_unlock(&chip->reg_lock); | 1320 | spin_unlock(&chip->reg_lock); |
1132 | 1321 | snd_azf3328_codec_activity(chip, AZF_CAPTURE, 0); | |
1133 | chip->is_recording = 0; | 1322 | |
1134 | snd_azf3328_dbgplay("STOPPED CAPTURE\n"); | 1323 | snd_azf3328_dbgplay("STOPPED CAPTURE\n"); |
1135 | break; | 1324 | break; |
1136 | case SNDRV_PCM_TRIGGER_SUSPEND: | 1325 | case SNDRV_PCM_TRIGGER_SUSPEND: |
@@ -1149,7 +1338,7 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd) | |||
1149 | printk(KERN_ERR "FIXME: unknown trigger mode!\n"); | 1338 | printk(KERN_ERR "FIXME: unknown trigger mode!\n"); |
1150 | return -EINVAL; | 1339 | return -EINVAL; |
1151 | } | 1340 | } |
1152 | 1341 | ||
1153 | snd_azf3328_dbgcallleave(); | 1342 | snd_azf3328_dbgcallleave(); |
1154 | return result; | 1343 | return result; |
1155 | } | 1344 | } |
@@ -1162,11 +1351,11 @@ snd_azf3328_playback_pointer(struct snd_pcm_substream *substream) | |||
1162 | snd_pcm_uframes_t frmres; | 1351 | snd_pcm_uframes_t frmres; |
1163 | 1352 | ||
1164 | #ifdef QUERY_HARDWARE | 1353 | #ifdef QUERY_HARDWARE |
1165 | bufptr = inl(chip->codec_port+IDX_IO_PLAY_DMA_START_1); | 1354 | bufptr = snd_azf3328_codec_inl(chip, IDX_IO_PLAY_DMA_START_1); |
1166 | #else | 1355 | #else |
1167 | bufptr = substream->runtime->dma_addr; | 1356 | bufptr = substream->runtime->dma_addr; |
1168 | #endif | 1357 | #endif |
1169 | result = inl(chip->codec_port+IDX_IO_PLAY_DMA_CURRPOS); | 1358 | result = snd_azf3328_codec_inl(chip, IDX_IO_PLAY_DMA_CURRPOS); |
1170 | 1359 | ||
1171 | /* calculate offset */ | 1360 | /* calculate offset */ |
1172 | result -= bufptr; | 1361 | result -= bufptr; |
@@ -1183,11 +1372,11 @@ snd_azf3328_capture_pointer(struct snd_pcm_substream *substream) | |||
1183 | snd_pcm_uframes_t frmres; | 1372 | snd_pcm_uframes_t frmres; |
1184 | 1373 | ||
1185 | #ifdef QUERY_HARDWARE | 1374 | #ifdef QUERY_HARDWARE |
1186 | bufptr = inl(chip->codec_port+IDX_IO_REC_DMA_START_1); | 1375 | bufptr = snd_azf3328_codec_inl(chip, IDX_IO_REC_DMA_START_1); |
1187 | #else | 1376 | #else |
1188 | bufptr = substream->runtime->dma_addr; | 1377 | bufptr = substream->runtime->dma_addr; |
1189 | #endif | 1378 | #endif |
1190 | result = inl(chip->codec_port+IDX_IO_REC_DMA_CURRPOS); | 1379 | result = snd_azf3328_codec_inl(chip, IDX_IO_REC_DMA_CURRPOS); |
1191 | 1380 | ||
1192 | /* calculate offset */ | 1381 | /* calculate offset */ |
1193 | result -= bufptr; | 1382 | result -= bufptr; |
@@ -1196,27 +1385,241 @@ snd_azf3328_capture_pointer(struct snd_pcm_substream *substream) | |||
1196 | return frmres; | 1385 | return frmres; |
1197 | } | 1386 | } |
1198 | 1387 | ||
1388 | /******************************************************************/ | ||
1389 | |||
1390 | #ifdef SUPPORT_GAMEPORT | ||
1391 | static inline void | ||
1392 | snd_azf3328_gameport_irq_enable(struct snd_azf3328 *chip, int enable) | ||
1393 | { | ||
1394 | snd_azf3328_io_reg_setb( | ||
1395 | chip->game_io+IDX_GAME_HWCONFIG, | ||
1396 | GAME_HWCFG_IRQ_ENABLE, | ||
1397 | enable | ||
1398 | ); | ||
1399 | } | ||
1400 | |||
1401 | static inline void | ||
1402 | snd_azf3328_gameport_legacy_address_enable(struct snd_azf3328 *chip, int enable) | ||
1403 | { | ||
1404 | snd_azf3328_io_reg_setb( | ||
1405 | chip->game_io+IDX_GAME_HWCONFIG, | ||
1406 | GAME_HWCFG_LEGACY_ADDRESS_ENABLE, | ||
1407 | enable | ||
1408 | ); | ||
1409 | } | ||
1410 | |||
1411 | static inline void | ||
1412 | snd_azf3328_gameport_axis_circuit_enable(struct snd_azf3328 *chip, int enable) | ||
1413 | { | ||
1414 | snd_azf3328_codec_reg_6AH_update( | ||
1415 | chip, IO_6A_SOMETHING2_GAMEPORT, enable | ||
1416 | ); | ||
1417 | } | ||
1418 | |||
1419 | static inline void | ||
1420 | snd_azf3328_gameport_interrupt(struct snd_azf3328 *chip) | ||
1421 | { | ||
1422 | /* | ||
1423 | * skeleton handler only | ||
1424 | * (we do not want axis reading in interrupt handler - too much load!) | ||
1425 | */ | ||
1426 | snd_azf3328_dbggame("gameport irq\n"); | ||
1427 | |||
1428 | /* this should ACK the gameport IRQ properly, hopefully. */ | ||
1429 | snd_azf3328_game_inw(chip, IDX_GAME_AXIS_VALUE); | ||
1430 | } | ||
1431 | |||
1432 | static int | ||
1433 | snd_azf3328_gameport_open(struct gameport *gameport, int mode) | ||
1434 | { | ||
1435 | struct snd_azf3328 *chip = gameport_get_port_data(gameport); | ||
1436 | int res; | ||
1437 | |||
1438 | snd_azf3328_dbggame("gameport_open, mode %d\n", mode); | ||
1439 | switch (mode) { | ||
1440 | case GAMEPORT_MODE_COOKED: | ||
1441 | case GAMEPORT_MODE_RAW: | ||
1442 | res = 0; | ||
1443 | break; | ||
1444 | default: | ||
1445 | res = -1; | ||
1446 | break; | ||
1447 | } | ||
1448 | |||
1449 | snd_azf3328_gameport_axis_circuit_enable(chip, (res == 0)); | ||
1450 | |||
1451 | return res; | ||
1452 | } | ||
1453 | |||
1454 | static void | ||
1455 | snd_azf3328_gameport_close(struct gameport *gameport) | ||
1456 | { | ||
1457 | struct snd_azf3328 *chip = gameport_get_port_data(gameport); | ||
1458 | |||
1459 | snd_azf3328_dbggame("gameport_close\n"); | ||
1460 | snd_azf3328_gameport_axis_circuit_enable(chip, 0); | ||
1461 | } | ||
1462 | |||
1463 | static int | ||
1464 | snd_azf3328_gameport_cooked_read(struct gameport *gameport, | ||
1465 | int *axes, | ||
1466 | int *buttons | ||
1467 | ) | ||
1468 | { | ||
1469 | struct snd_azf3328 *chip = gameport_get_port_data(gameport); | ||
1470 | int i; | ||
1471 | u8 val; | ||
1472 | unsigned long flags; | ||
1473 | |||
1474 | snd_assert(chip, return 0); | ||
1475 | |||
1476 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
1477 | val = snd_azf3328_game_inb(chip, IDX_GAME_LEGACY_COMPATIBLE); | ||
1478 | *buttons = (~(val) >> 4) & 0xf; | ||
1479 | |||
1480 | /* ok, this one is a bit dirty: cooked_read is being polled by a timer, | ||
1481 | * thus we're atomic and cannot actively wait in here | ||
1482 | * (which would be useful for us since it probably would be better | ||
1483 | * to trigger a measurement in here, then wait a short amount of | ||
1484 | * time until it's finished, then read values of _this_ measurement). | ||
1485 | * | ||
1486 | * Thus we simply resort to reading values if they're available already | ||
1487 | * and trigger the next measurement. | ||
1488 | */ | ||
1489 | |||
1490 | val = snd_azf3328_game_inb(chip, IDX_GAME_AXES_CONFIG); | ||
1491 | if (val & GAME_AXES_SAMPLING_READY) { | ||
1492 | for (i = 0; i < 4; ++i) { | ||
1493 | /* configure the axis to read */ | ||
1494 | val = (i << 4) | 0x0f; | ||
1495 | snd_azf3328_game_outb(chip, IDX_GAME_AXES_CONFIG, val); | ||
1496 | |||
1497 | chip->axes[i] = snd_azf3328_game_inw( | ||
1498 | chip, IDX_GAME_AXIS_VALUE | ||
1499 | ); | ||
1500 | } | ||
1501 | } | ||
1502 | |||
1503 | /* trigger next axes sampling, to be evaluated the next time we | ||
1504 | * enter this function */ | ||
1505 | |||
1506 | /* for some very, very strange reason we cannot enable | ||
1507 | * Measurement Ready monitoring for all axes here, | ||
1508 | * at least not when only one joystick connected */ | ||
1509 | val = 0x03; /* we're able to monitor axes 1 and 2 only */ | ||
1510 | snd_azf3328_game_outb(chip, IDX_GAME_AXES_CONFIG, val); | ||
1511 | |||
1512 | snd_azf3328_game_outw(chip, IDX_GAME_AXIS_VALUE, 0xffff); | ||
1513 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
1514 | |||
1515 | for (i = 0; i < 4; i++) { | ||
1516 | axes[i] = chip->axes[i]; | ||
1517 | if (axes[i] == 0xffff) | ||
1518 | axes[i] = -1; | ||
1519 | } | ||
1520 | |||
1521 | snd_azf3328_dbggame("cooked_read: axes %d %d %d %d buttons %d\n", | ||
1522 | axes[0], axes[1], axes[2], axes[3], *buttons | ||
1523 | ); | ||
1524 | |||
1525 | return 0; | ||
1526 | } | ||
1527 | |||
1528 | static int __devinit | ||
1529 | snd_azf3328_gameport(struct snd_azf3328 *chip, int dev) | ||
1530 | { | ||
1531 | struct gameport *gp; | ||
1532 | |||
1533 | chip->gameport = gp = gameport_allocate_port(); | ||
1534 | if (!gp) { | ||
1535 | printk(KERN_ERR "azt3328: cannot alloc memory for gameport\n"); | ||
1536 | return -ENOMEM; | ||
1537 | } | ||
1538 | |||
1539 | gameport_set_name(gp, "AZF3328 Gameport"); | ||
1540 | gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci)); | ||
1541 | gameport_set_dev_parent(gp, &chip->pci->dev); | ||
1542 | gp->io = chip->game_io; | ||
1543 | gameport_set_port_data(gp, chip); | ||
1544 | |||
1545 | gp->open = snd_azf3328_gameport_open; | ||
1546 | gp->close = snd_azf3328_gameport_close; | ||
1547 | gp->fuzz = 16; /* seems ok */ | ||
1548 | gp->cooked_read = snd_azf3328_gameport_cooked_read; | ||
1549 | |||
1550 | /* DISABLE legacy address: we don't need it! */ | ||
1551 | snd_azf3328_gameport_legacy_address_enable(chip, 0); | ||
1552 | |||
1553 | snd_azf3328_gameport_axis_circuit_enable(chip, 0); | ||
1554 | |||
1555 | gameport_register_port(chip->gameport); | ||
1556 | |||
1557 | return 0; | ||
1558 | } | ||
1559 | |||
1560 | static void | ||
1561 | snd_azf3328_gameport_free(struct snd_azf3328 *chip) | ||
1562 | { | ||
1563 | if (chip->gameport) { | ||
1564 | gameport_unregister_port(chip->gameport); | ||
1565 | chip->gameport = NULL; | ||
1566 | } | ||
1567 | snd_azf3328_gameport_irq_enable(chip, 0); | ||
1568 | } | ||
1569 | #else | ||
1570 | static inline int | ||
1571 | snd_azf3328_gameport(struct snd_azf3328 *chip, int dev) { return -ENOSYS; } | ||
1572 | static inline void | ||
1573 | snd_azf3328_gameport_free(struct snd_azf3328 *chip) { } | ||
1574 | static inline void | ||
1575 | snd_azf3328_gameport_interrupt(struct snd_azf3328 *chip) | ||
1576 | { | ||
1577 | printk(KERN_WARNING "huh, game port IRQ occurred!?\n"); | ||
1578 | } | ||
1579 | #endif /* SUPPORT_GAMEPORT */ | ||
1580 | |||
1581 | /******************************************************************/ | ||
1582 | |||
1583 | static inline void | ||
1584 | snd_azf3328_irq_log_unknown_type(u8 which) | ||
1585 | { | ||
1586 | snd_azf3328_dbgplay( | ||
1587 | "azt3328: unknown IRQ type (%x) occurred, please report!\n", | ||
1588 | which | ||
1589 | ); | ||
1590 | } | ||
1591 | |||
1199 | static irqreturn_t | 1592 | static irqreturn_t |
1200 | snd_azf3328_interrupt(int irq, void *dev_id) | 1593 | snd_azf3328_interrupt(int irq, void *dev_id) |
1201 | { | 1594 | { |
1202 | struct snd_azf3328 *chip = dev_id; | 1595 | struct snd_azf3328 *chip = dev_id; |
1203 | u8 status, which; | 1596 | u8 status, which; |
1597 | #if DEBUG_PLAY_REC | ||
1204 | static unsigned long irq_count; | 1598 | static unsigned long irq_count; |
1599 | #endif | ||
1205 | 1600 | ||
1206 | status = snd_azf3328_codec_inb(chip, IDX_IO_IRQSTATUS); | 1601 | status = snd_azf3328_codec_inb(chip, IDX_IO_IRQSTATUS); |
1207 | 1602 | ||
1208 | /* fast path out, to ease interrupt sharing */ | 1603 | /* fast path out, to ease interrupt sharing */ |
1209 | if (!(status & (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_MPU401|IRQ_TIMER))) | 1604 | if (!(status & |
1605 | (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_GAMEPORT|IRQ_MPU401|IRQ_TIMER) | ||
1606 | )) | ||
1210 | return IRQ_NONE; /* must be interrupt for another device */ | 1607 | return IRQ_NONE; /* must be interrupt for another device */ |
1211 | 1608 | ||
1212 | snd_azf3328_dbgplay("Interrupt %ld!\nIDX_IO_PLAY_FLAGS %04x, IDX_IO_PLAY_IRQTYPE %04x, IDX_IO_IRQSTATUS %04x\n", | 1609 | snd_azf3328_dbgplay( |
1213 | irq_count, | 1610 | "irq_count %ld! IDX_IO_PLAY_FLAGS %04x, " |
1214 | snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS), | 1611 | "IDX_IO_PLAY_IRQTYPE %04x, IDX_IO_IRQSTATUS %04x\n", |
1215 | snd_azf3328_codec_inw(chip, IDX_IO_PLAY_IRQTYPE), | 1612 | irq_count++ /* debug-only */, |
1216 | status); | 1613 | snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS), |
1217 | 1614 | snd_azf3328_codec_inw(chip, IDX_IO_PLAY_IRQTYPE), | |
1615 | status | ||
1616 | ); | ||
1617 | |||
1218 | if (status & IRQ_TIMER) { | 1618 | if (status & IRQ_TIMER) { |
1219 | /* snd_azf3328_dbgplay("timer %ld\n", inl(chip->codec_port+IDX_IO_TIMER_VALUE) & TIMER_VALUE_MASK); */ | 1619 | /* snd_azf3328_dbgplay("timer %ld\n", |
1620 | snd_azf3328_codec_inl(chip, IDX_IO_TIMER_VALUE) | ||
1621 | & TIMER_VALUE_MASK | ||
1622 | ); */ | ||
1220 | if (chip->timer) | 1623 | if (chip->timer) |
1221 | snd_timer_interrupt(chip->timer, chip->timer->sticks); | 1624 | snd_timer_interrupt(chip->timer, chip->timer->sticks); |
1222 | /* ACK timer */ | 1625 | /* ACK timer */ |
@@ -1232,15 +1635,20 @@ snd_azf3328_interrupt(int irq, void *dev_id) | |||
1232 | snd_azf3328_codec_outb(chip, IDX_IO_PLAY_IRQTYPE, which); | 1635 | snd_azf3328_codec_outb(chip, IDX_IO_PLAY_IRQTYPE, which); |
1233 | spin_unlock(&chip->reg_lock); | 1636 | spin_unlock(&chip->reg_lock); |
1234 | 1637 | ||
1235 | if (chip->pcm && chip->playback_substream) { | 1638 | if (chip->pcm && chip->audio_stream[AZF_PLAYBACK].substream) { |
1236 | snd_pcm_period_elapsed(chip->playback_substream); | 1639 | snd_pcm_period_elapsed( |
1640 | chip->audio_stream[AZF_PLAYBACK].substream | ||
1641 | ); | ||
1237 | snd_azf3328_dbgplay("PLAY period done (#%x), @ %x\n", | 1642 | snd_azf3328_dbgplay("PLAY period done (#%x), @ %x\n", |
1238 | which, | 1643 | which, |
1239 | inl(chip->codec_port+IDX_IO_PLAY_DMA_CURRPOS)); | 1644 | snd_azf3328_codec_inl( |
1645 | chip, IDX_IO_PLAY_DMA_CURRPOS | ||
1646 | ) | ||
1647 | ); | ||
1240 | } else | 1648 | } else |
1241 | snd_azf3328_dbgplay("azt3328: ouch, irq handler problem!\n"); | 1649 | printk(KERN_WARNING "azt3328: irq handler problem!\n"); |
1242 | if (which & IRQ_PLAY_SOMETHING) | 1650 | if (which & IRQ_PLAY_SOMETHING) |
1243 | snd_azf3328_dbgplay("azt3328: unknown play IRQ type occurred, please report!\n"); | 1651 | snd_azf3328_irq_log_unknown_type(which); |
1244 | } | 1652 | } |
1245 | if (status & IRQ_RECORDING) { | 1653 | if (status & IRQ_RECORDING) { |
1246 | spin_lock(&chip->reg_lock); | 1654 | spin_lock(&chip->reg_lock); |
@@ -1249,16 +1657,23 @@ snd_azf3328_interrupt(int irq, void *dev_id) | |||
1249 | snd_azf3328_codec_outb(chip, IDX_IO_REC_IRQTYPE, which); | 1657 | snd_azf3328_codec_outb(chip, IDX_IO_REC_IRQTYPE, which); |
1250 | spin_unlock(&chip->reg_lock); | 1658 | spin_unlock(&chip->reg_lock); |
1251 | 1659 | ||
1252 | if (chip->pcm && chip->capture_substream) { | 1660 | if (chip->pcm && chip->audio_stream[AZF_CAPTURE].substream) { |
1253 | snd_pcm_period_elapsed(chip->capture_substream); | 1661 | snd_pcm_period_elapsed( |
1662 | chip->audio_stream[AZF_CAPTURE].substream | ||
1663 | ); | ||
1254 | snd_azf3328_dbgplay("REC period done (#%x), @ %x\n", | 1664 | snd_azf3328_dbgplay("REC period done (#%x), @ %x\n", |
1255 | which, | 1665 | which, |
1256 | inl(chip->codec_port+IDX_IO_REC_DMA_CURRPOS)); | 1666 | snd_azf3328_codec_inl( |
1667 | chip, IDX_IO_REC_DMA_CURRPOS | ||
1668 | ) | ||
1669 | ); | ||
1257 | } else | 1670 | } else |
1258 | snd_azf3328_dbgplay("azt3328: ouch, irq handler problem!\n"); | 1671 | printk(KERN_WARNING "azt3328: irq handler problem!\n"); |
1259 | if (which & IRQ_REC_SOMETHING) | 1672 | if (which & IRQ_REC_SOMETHING) |
1260 | snd_azf3328_dbgplay("azt3328: unknown rec IRQ type occurred, please report!\n"); | 1673 | snd_azf3328_irq_log_unknown_type(which); |
1261 | } | 1674 | } |
1675 | if (status & IRQ_GAMEPORT) | ||
1676 | snd_azf3328_gameport_interrupt(chip); | ||
1262 | /* MPU401 has less critical IRQ requirements | 1677 | /* MPU401 has less critical IRQ requirements |
1263 | * than timer and playback/recording, right? */ | 1678 | * than timer and playback/recording, right? */ |
1264 | if (status & IRQ_MPU401) { | 1679 | if (status & IRQ_MPU401) { |
@@ -1268,7 +1683,6 @@ snd_azf3328_interrupt(int irq, void *dev_id) | |||
1268 | * If so, then I don't know how... */ | 1683 | * If so, then I don't know how... */ |
1269 | snd_azf3328_dbgplay("azt3328: MPU401 IRQ\n"); | 1684 | snd_azf3328_dbgplay("azt3328: MPU401 IRQ\n"); |
1270 | } | 1685 | } |
1271 | irq_count++; | ||
1272 | return IRQ_HANDLED; | 1686 | return IRQ_HANDLED; |
1273 | } | 1687 | } |
1274 | 1688 | ||
@@ -1287,8 +1701,8 @@ static const struct snd_pcm_hardware snd_azf3328_playback = | |||
1287 | .rates = SNDRV_PCM_RATE_5512 | | 1701 | .rates = SNDRV_PCM_RATE_5512 | |
1288 | SNDRV_PCM_RATE_8000_48000 | | 1702 | SNDRV_PCM_RATE_8000_48000 | |
1289 | SNDRV_PCM_RATE_KNOT, | 1703 | SNDRV_PCM_RATE_KNOT, |
1290 | .rate_min = 4000, | 1704 | .rate_min = AZF_FREQ_4000, |
1291 | .rate_max = 66200, | 1705 | .rate_max = AZF_FREQ_66200, |
1292 | .channels_min = 1, | 1706 | .channels_min = 1, |
1293 | .channels_max = 2, | 1707 | .channels_max = 2, |
1294 | .buffer_bytes_max = 65536, | 1708 | .buffer_bytes_max = 65536, |
@@ -1315,8 +1729,8 @@ static const struct snd_pcm_hardware snd_azf3328_capture = | |||
1315 | .rates = SNDRV_PCM_RATE_5512 | | 1729 | .rates = SNDRV_PCM_RATE_5512 | |
1316 | SNDRV_PCM_RATE_8000_48000 | | 1730 | SNDRV_PCM_RATE_8000_48000 | |
1317 | SNDRV_PCM_RATE_KNOT, | 1731 | SNDRV_PCM_RATE_KNOT, |
1318 | .rate_min = 4000, | 1732 | .rate_min = AZF_FREQ_4000, |
1319 | .rate_max = 66200, | 1733 | .rate_max = AZF_FREQ_66200, |
1320 | .channels_min = 1, | 1734 | .channels_min = 1, |
1321 | .channels_max = 2, | 1735 | .channels_max = 2, |
1322 | .buffer_bytes_max = 65536, | 1736 | .buffer_bytes_max = 65536, |
@@ -1329,10 +1743,24 @@ static const struct snd_pcm_hardware snd_azf3328_capture = | |||
1329 | 1743 | ||
1330 | 1744 | ||
1331 | static unsigned int snd_azf3328_fixed_rates[] = { | 1745 | static unsigned int snd_azf3328_fixed_rates[] = { |
1332 | 4000, 4800, 5512, 6620, 8000, 9600, 11025, 13240, 16000, 22050, 32000, | 1746 | AZF_FREQ_4000, |
1333 | 44100, 48000, 66200 }; | 1747 | AZF_FREQ_4800, |
1748 | AZF_FREQ_5512, | ||
1749 | AZF_FREQ_6620, | ||
1750 | AZF_FREQ_8000, | ||
1751 | AZF_FREQ_9600, | ||
1752 | AZF_FREQ_11025, | ||
1753 | AZF_FREQ_13240, | ||
1754 | AZF_FREQ_16000, | ||
1755 | AZF_FREQ_22050, | ||
1756 | AZF_FREQ_32000, | ||
1757 | AZF_FREQ_44100, | ||
1758 | AZF_FREQ_48000, | ||
1759 | AZF_FREQ_66200 | ||
1760 | }; | ||
1761 | |||
1334 | static struct snd_pcm_hw_constraint_list snd_azf3328_hw_constraints_rates = { | 1762 | static struct snd_pcm_hw_constraint_list snd_azf3328_hw_constraints_rates = { |
1335 | .count = ARRAY_SIZE(snd_azf3328_fixed_rates), | 1763 | .count = ARRAY_SIZE(snd_azf3328_fixed_rates), |
1336 | .list = snd_azf3328_fixed_rates, | 1764 | .list = snd_azf3328_fixed_rates, |
1337 | .mask = 0, | 1765 | .mask = 0, |
1338 | }; | 1766 | }; |
@@ -1346,7 +1774,7 @@ snd_azf3328_playback_open(struct snd_pcm_substream *substream) | |||
1346 | struct snd_pcm_runtime *runtime = substream->runtime; | 1774 | struct snd_pcm_runtime *runtime = substream->runtime; |
1347 | 1775 | ||
1348 | snd_azf3328_dbgcallenter(); | 1776 | snd_azf3328_dbgcallenter(); |
1349 | chip->playback_substream = substream; | 1777 | chip->audio_stream[AZF_PLAYBACK].substream = substream; |
1350 | runtime->hw = snd_azf3328_playback; | 1778 | runtime->hw = snd_azf3328_playback; |
1351 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | 1779 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, |
1352 | &snd_azf3328_hw_constraints_rates); | 1780 | &snd_azf3328_hw_constraints_rates); |
@@ -1361,7 +1789,7 @@ snd_azf3328_capture_open(struct snd_pcm_substream *substream) | |||
1361 | struct snd_pcm_runtime *runtime = substream->runtime; | 1789 | struct snd_pcm_runtime *runtime = substream->runtime; |
1362 | 1790 | ||
1363 | snd_azf3328_dbgcallenter(); | 1791 | snd_azf3328_dbgcallenter(); |
1364 | chip->capture_substream = substream; | 1792 | chip->audio_stream[AZF_CAPTURE].substream = substream; |
1365 | runtime->hw = snd_azf3328_capture; | 1793 | runtime->hw = snd_azf3328_capture; |
1366 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | 1794 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, |
1367 | &snd_azf3328_hw_constraints_rates); | 1795 | &snd_azf3328_hw_constraints_rates); |
@@ -1375,7 +1803,7 @@ snd_azf3328_playback_close(struct snd_pcm_substream *substream) | |||
1375 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | 1803 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); |
1376 | 1804 | ||
1377 | snd_azf3328_dbgcallenter(); | 1805 | snd_azf3328_dbgcallenter(); |
1378 | chip->playback_substream = NULL; | 1806 | chip->audio_stream[AZF_PLAYBACK].substream = NULL; |
1379 | snd_azf3328_dbgcallleave(); | 1807 | snd_azf3328_dbgcallleave(); |
1380 | return 0; | 1808 | return 0; |
1381 | } | 1809 | } |
@@ -1386,7 +1814,7 @@ snd_azf3328_capture_close(struct snd_pcm_substream *substream) | |||
1386 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | 1814 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); |
1387 | 1815 | ||
1388 | snd_azf3328_dbgcallenter(); | 1816 | snd_azf3328_dbgcallenter(); |
1389 | chip->capture_substream = NULL; | 1817 | chip->audio_stream[AZF_CAPTURE].substream = NULL; |
1390 | snd_azf3328_dbgcallleave(); | 1818 | snd_azf3328_dbgcallleave(); |
1391 | return 0; | 1819 | return 0; |
1392 | } | 1820 | } |
@@ -1441,102 +1869,8 @@ snd_azf3328_pcm(struct snd_azf3328 *chip, int device) | |||
1441 | 1869 | ||
1442 | /******************************************************************/ | 1870 | /******************************************************************/ |
1443 | 1871 | ||
1444 | #ifdef SUPPORT_JOYSTICK | 1872 | /*** NOTE: the physical timer resolution actually is 1024000 ticks per second |
1445 | static int __devinit | 1873 | *** (probably derived from main crystal via a divider of 24), |
1446 | snd_azf3328_config_joystick(struct snd_azf3328 *chip, int dev) | ||
1447 | { | ||
1448 | struct gameport *gp; | ||
1449 | struct resource *r; | ||
1450 | |||
1451 | if (!joystick[dev]) | ||
1452 | return -ENODEV; | ||
1453 | |||
1454 | if (!(r = request_region(0x200, 8, "AZF3328 gameport"))) { | ||
1455 | printk(KERN_WARNING "azt3328: cannot reserve joystick ports\n"); | ||
1456 | return -EBUSY; | ||
1457 | } | ||
1458 | |||
1459 | chip->gameport = gp = gameport_allocate_port(); | ||
1460 | if (!gp) { | ||
1461 | printk(KERN_ERR "azt3328: cannot allocate memory for gameport\n"); | ||
1462 | release_and_free_resource(r); | ||
1463 | return -ENOMEM; | ||
1464 | } | ||
1465 | |||
1466 | gameport_set_name(gp, "AZF3328 Gameport"); | ||
1467 | gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci)); | ||
1468 | gameport_set_dev_parent(gp, &chip->pci->dev); | ||
1469 | gp->io = 0x200; | ||
1470 | gameport_set_port_data(gp, r); | ||
1471 | |||
1472 | snd_azf3328_io2_outb(chip, IDX_IO2_LEGACY_ADDR, | ||
1473 | snd_azf3328_io2_inb(chip, IDX_IO2_LEGACY_ADDR) | LEGACY_JOY); | ||
1474 | |||
1475 | gameport_register_port(chip->gameport); | ||
1476 | |||
1477 | return 0; | ||
1478 | } | ||
1479 | |||
1480 | static void | ||
1481 | snd_azf3328_free_joystick(struct snd_azf3328 *chip) | ||
1482 | { | ||
1483 | if (chip->gameport) { | ||
1484 | struct resource *r = gameport_get_port_data(chip->gameport); | ||
1485 | |||
1486 | gameport_unregister_port(chip->gameport); | ||
1487 | chip->gameport = NULL; | ||
1488 | /* disable gameport */ | ||
1489 | snd_azf3328_io2_outb(chip, IDX_IO2_LEGACY_ADDR, | ||
1490 | snd_azf3328_io2_inb(chip, IDX_IO2_LEGACY_ADDR) & ~LEGACY_JOY); | ||
1491 | release_and_free_resource(r); | ||
1492 | } | ||
1493 | } | ||
1494 | #else | ||
1495 | static inline int | ||
1496 | snd_azf3328_config_joystick(struct snd_azf3328 *chip, int dev) { return -ENOSYS; } | ||
1497 | static inline void | ||
1498 | snd_azf3328_free_joystick(struct snd_azf3328 *chip) { } | ||
1499 | #endif | ||
1500 | |||
1501 | /******************************************************************/ | ||
1502 | |||
1503 | static int | ||
1504 | snd_azf3328_free(struct snd_azf3328 *chip) | ||
1505 | { | ||
1506 | if (chip->irq < 0) | ||
1507 | goto __end_hw; | ||
1508 | |||
1509 | /* reset (close) mixer */ | ||
1510 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1); /* first mute master volume */ | ||
1511 | snd_azf3328_mixer_outw(chip, IDX_MIXER_RESET, 0x0000); | ||
1512 | |||
1513 | /* interrupt setup - mask everything (FIXME!) */ | ||
1514 | /* well, at least we know how to disable the timer IRQ */ | ||
1515 | snd_azf3328_codec_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x00); | ||
1516 | |||
1517 | if (chip->irq >= 0) | ||
1518 | synchronize_irq(chip->irq); | ||
1519 | __end_hw: | ||
1520 | snd_azf3328_free_joystick(chip); | ||
1521 | if (chip->irq >= 0) | ||
1522 | free_irq(chip->irq, chip); | ||
1523 | pci_release_regions(chip->pci); | ||
1524 | pci_disable_device(chip->pci); | ||
1525 | |||
1526 | kfree(chip); | ||
1527 | return 0; | ||
1528 | } | ||
1529 | |||
1530 | static int | ||
1531 | snd_azf3328_dev_free(struct snd_device *device) | ||
1532 | { | ||
1533 | struct snd_azf3328 *chip = device->device_data; | ||
1534 | return snd_azf3328_free(chip); | ||
1535 | } | ||
1536 | |||
1537 | /******************************************************************/ | ||
1538 | |||
1539 | /*** NOTE: the physical timer resolution actually is 1024000 ticks per second, | ||
1540 | *** but announcing those attributes to user-space would make programs | 1874 | *** but announcing those attributes to user-space would make programs |
1541 | *** configure the timer to a 1 tick value, resulting in an absolutely fatal | 1875 | *** configure the timer to a 1 tick value, resulting in an absolutely fatal |
1542 | *** timer IRQ storm. | 1876 | *** timer IRQ storm. |
@@ -1564,7 +1898,7 @@ snd_azf3328_timer_start(struct snd_timer *timer) | |||
1564 | delay = 49; /* minimum time is 49 ticks */ | 1898 | delay = 49; /* minimum time is 49 ticks */ |
1565 | } | 1899 | } |
1566 | snd_azf3328_dbgtimer("setting timer countdown value %d, add COUNTDOWN|IRQ\n", delay); | 1900 | snd_azf3328_dbgtimer("setting timer countdown value %d, add COUNTDOWN|IRQ\n", delay); |
1567 | delay |= TIMER_ENABLE_COUNTDOWN | TIMER_ENABLE_IRQ; | 1901 | delay |= TIMER_COUNTDOWN_ENABLE | TIMER_IRQ_ENABLE; |
1568 | spin_lock_irqsave(&chip->reg_lock, flags); | 1902 | spin_lock_irqsave(&chip->reg_lock, flags); |
1569 | snd_azf3328_codec_outl(chip, IDX_IO_TIMER_VALUE, delay); | 1903 | snd_azf3328_codec_outl(chip, IDX_IO_TIMER_VALUE, delay); |
1570 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 1904 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
@@ -1582,7 +1916,7 @@ snd_azf3328_timer_stop(struct snd_timer *timer) | |||
1582 | chip = snd_timer_chip(timer); | 1916 | chip = snd_timer_chip(timer); |
1583 | spin_lock_irqsave(&chip->reg_lock, flags); | 1917 | spin_lock_irqsave(&chip->reg_lock, flags); |
1584 | /* disable timer countdown and interrupt */ | 1918 | /* disable timer countdown and interrupt */ |
1585 | /* FIXME: should we write TIMER_ACK_IRQ here? */ | 1919 | /* FIXME: should we write TIMER_IRQ_ACK here? */ |
1586 | snd_azf3328_codec_outb(chip, IDX_IO_TIMER_VALUE + 3, 0); | 1920 | snd_azf3328_codec_outb(chip, IDX_IO_TIMER_VALUE + 3, 0); |
1587 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 1921 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
1588 | snd_azf3328_dbgcallleave(); | 1922 | snd_azf3328_dbgcallleave(); |
@@ -1626,9 +1960,10 @@ snd_azf3328_timer(struct snd_azf3328 *chip, int device) | |||
1626 | 1960 | ||
1627 | snd_azf3328_timer_hw.resolution *= seqtimer_scaling; | 1961 | snd_azf3328_timer_hw.resolution *= seqtimer_scaling; |
1628 | snd_azf3328_timer_hw.ticks /= seqtimer_scaling; | 1962 | snd_azf3328_timer_hw.ticks /= seqtimer_scaling; |
1629 | if ((err = snd_timer_new(chip->card, "AZF3328", &tid, &timer)) < 0) { | 1963 | |
1964 | err = snd_timer_new(chip->card, "AZF3328", &tid, &timer); | ||
1965 | if (err < 0) | ||
1630 | goto out; | 1966 | goto out; |
1631 | } | ||
1632 | 1967 | ||
1633 | strcpy(timer->name, "AZF3328 timer"); | 1968 | strcpy(timer->name, "AZF3328 timer"); |
1634 | timer->private_data = chip; | 1969 | timer->private_data = chip; |
@@ -1636,6 +1971,8 @@ snd_azf3328_timer(struct snd_azf3328 *chip, int device) | |||
1636 | 1971 | ||
1637 | chip->timer = timer; | 1972 | chip->timer = timer; |
1638 | 1973 | ||
1974 | snd_azf3328_timer_stop(timer); | ||
1975 | |||
1639 | err = 0; | 1976 | err = 0; |
1640 | 1977 | ||
1641 | out: | 1978 | out: |
@@ -1645,10 +1982,44 @@ out: | |||
1645 | 1982 | ||
1646 | /******************************************************************/ | 1983 | /******************************************************************/ |
1647 | 1984 | ||
1985 | static int | ||
1986 | snd_azf3328_free(struct snd_azf3328 *chip) | ||
1987 | { | ||
1988 | if (chip->irq < 0) | ||
1989 | goto __end_hw; | ||
1990 | |||
1991 | /* reset (close) mixer: | ||
1992 | * first mute master volume, then reset | ||
1993 | */ | ||
1994 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1); | ||
1995 | snd_azf3328_mixer_outw(chip, IDX_MIXER_RESET, 0x0000); | ||
1996 | |||
1997 | snd_azf3328_timer_stop(chip->timer); | ||
1998 | snd_azf3328_gameport_free(chip); | ||
1999 | |||
2000 | if (chip->irq >= 0) | ||
2001 | synchronize_irq(chip->irq); | ||
2002 | __end_hw: | ||
2003 | if (chip->irq >= 0) | ||
2004 | free_irq(chip->irq, chip); | ||
2005 | pci_release_regions(chip->pci); | ||
2006 | pci_disable_device(chip->pci); | ||
2007 | |||
2008 | kfree(chip); | ||
2009 | return 0; | ||
2010 | } | ||
2011 | |||
2012 | static int | ||
2013 | snd_azf3328_dev_free(struct snd_device *device) | ||
2014 | { | ||
2015 | struct snd_azf3328 *chip = device->device_data; | ||
2016 | return snd_azf3328_free(chip); | ||
2017 | } | ||
2018 | |||
1648 | #if 0 | 2019 | #if 0 |
1649 | /* check whether a bit can be modified */ | 2020 | /* check whether a bit can be modified */ |
1650 | static void | 2021 | static void |
1651 | snd_azf3328_test_bit(unsigned int reg, int bit) | 2022 | snd_azf3328_test_bit(unsigned unsigned reg, int bit) |
1652 | { | 2023 | { |
1653 | unsigned char val, valoff, valon; | 2024 | unsigned char val, valoff, valon; |
1654 | 2025 | ||
@@ -1659,42 +2030,74 @@ snd_azf3328_test_bit(unsigned int reg, int bit) | |||
1659 | 2030 | ||
1660 | outb(val|(1 << bit), reg); | 2031 | outb(val|(1 << bit), reg); |
1661 | valon = inb(reg); | 2032 | valon = inb(reg); |
1662 | 2033 | ||
1663 | outb(val, reg); | 2034 | outb(val, reg); |
1664 | 2035 | ||
1665 | printk(KERN_ERR "reg %04x bit %d: %02x %02x %02x\n", reg, bit, val, valoff, valon); | 2036 | printk(KERN_ERR "reg %04x bit %d: %02x %02x %02x\n", |
2037 | reg, bit, val, valoff, valon | ||
2038 | ); | ||
1666 | } | 2039 | } |
1667 | #endif | 2040 | #endif |
1668 | 2041 | ||
1669 | #if DEBUG_MISC | 2042 | static inline void |
1670 | static void | ||
1671 | snd_azf3328_debug_show_ports(const struct snd_azf3328 *chip) | 2043 | snd_azf3328_debug_show_ports(const struct snd_azf3328 *chip) |
1672 | { | 2044 | { |
2045 | #if DEBUG_MISC | ||
1673 | u16 tmp; | 2046 | u16 tmp; |
1674 | 2047 | ||
1675 | snd_azf3328_dbgmisc("codec_port 0x%lx, io2_port 0x%lx, mpu_port 0x%lx, synth_port 0x%lx, mixer_port 0x%lx, irq %d\n", chip->codec_port, chip->io2_port, chip->mpu_port, chip->synth_port, chip->mixer_port, chip->irq); | 2048 | snd_azf3328_dbgmisc( |
1676 | 2049 | "codec_io 0x%lx, game_io 0x%lx, mpu_io 0x%lx, " | |
1677 | snd_azf3328_dbgmisc("io2 %02x %02x %02x %02x %02x %02x\n", snd_azf3328_io2_inb(chip, 0), snd_azf3328_io2_inb(chip, 1), snd_azf3328_io2_inb(chip, 2), snd_azf3328_io2_inb(chip, 3), snd_azf3328_io2_inb(chip, 4), snd_azf3328_io2_inb(chip, 5)); | 2050 | "opl3_io 0x%lx, mixer_io 0x%lx, irq %d\n", |
1678 | 2051 | chip->codec_io, chip->game_io, chip->mpu_io, | |
1679 | for (tmp=0; tmp <= 0x01; tmp += 1) | 2052 | chip->opl3_io, chip->mixer_io, chip->irq |
1680 | snd_azf3328_dbgmisc("0x%02x: opl 0x%04x, mpu300 0x%04x, mpu310 0x%04x, mpu320 0x%04x, mpu330 0x%04x\n", tmp, inb(0x388 + tmp), inb(0x300 + tmp), inb(0x310 + tmp), inb(0x320 + tmp), inb(0x330 + tmp)); | 2053 | ); |
2054 | |||
2055 | snd_azf3328_dbgmisc("game %02x %02x %02x %02x %02x %02x\n", | ||
2056 | snd_azf3328_game_inb(chip, 0), | ||
2057 | snd_azf3328_game_inb(chip, 1), | ||
2058 | snd_azf3328_game_inb(chip, 2), | ||
2059 | snd_azf3328_game_inb(chip, 3), | ||
2060 | snd_azf3328_game_inb(chip, 4), | ||
2061 | snd_azf3328_game_inb(chip, 5) | ||
2062 | ); | ||
2063 | |||
2064 | for (tmp = 0; tmp < 0x07; tmp += 1) | ||
2065 | snd_azf3328_dbgmisc("mpu_io 0x%04x\n", inb(chip->mpu_io + tmp)); | ||
2066 | |||
2067 | for (tmp = 0; tmp <= 0x07; tmp += 1) | ||
2068 | snd_azf3328_dbgmisc("0x%02x: game200 0x%04x, game208 0x%04x\n", | ||
2069 | tmp, inb(0x200 + tmp), inb(0x208 + tmp)); | ||
2070 | |||
2071 | for (tmp = 0; tmp <= 0x01; tmp += 1) | ||
2072 | snd_azf3328_dbgmisc( | ||
2073 | "0x%02x: mpu300 0x%04x, mpu310 0x%04x, mpu320 0x%04x, " | ||
2074 | "mpu330 0x%04x opl388 0x%04x opl38c 0x%04x\n", | ||
2075 | tmp, | ||
2076 | inb(0x300 + tmp), | ||
2077 | inb(0x310 + tmp), | ||
2078 | inb(0x320 + tmp), | ||
2079 | inb(0x330 + tmp), | ||
2080 | inb(0x388 + tmp), | ||
2081 | inb(0x38c + tmp) | ||
2082 | ); | ||
1681 | 2083 | ||
1682 | for (tmp = 0; tmp < AZF_IO_SIZE_CODEC; tmp += 2) | 2084 | for (tmp = 0; tmp < AZF_IO_SIZE_CODEC; tmp += 2) |
1683 | snd_azf3328_dbgmisc("codec 0x%02x: 0x%04x\n", tmp, snd_azf3328_codec_inw(chip, tmp)); | 2085 | snd_azf3328_dbgmisc("codec 0x%02x: 0x%04x\n", |
2086 | tmp, snd_azf3328_codec_inw(chip, tmp) | ||
2087 | ); | ||
1684 | 2088 | ||
1685 | for (tmp = 0; tmp < AZF_IO_SIZE_MIXER; tmp += 2) | 2089 | for (tmp = 0; tmp < AZF_IO_SIZE_MIXER; tmp += 2) |
1686 | snd_azf3328_dbgmisc("mixer 0x%02x: 0x%04x\n", tmp, snd_azf3328_mixer_inw(chip, tmp)); | 2090 | snd_azf3328_dbgmisc("mixer 0x%02x: 0x%04x\n", |
2091 | tmp, snd_azf3328_mixer_inw(chip, tmp) | ||
2092 | ); | ||
2093 | #endif /* DEBUG_MISC */ | ||
1687 | } | 2094 | } |
1688 | #else | ||
1689 | static inline void | ||
1690 | snd_azf3328_debug_show_ports(const struct snd_azf3328 *chip) {} | ||
1691 | #endif | ||
1692 | 2095 | ||
1693 | static int __devinit | 2096 | static int __devinit |
1694 | snd_azf3328_create(struct snd_card *card, | 2097 | snd_azf3328_create(struct snd_card *card, |
1695 | struct pci_dev *pci, | 2098 | struct pci_dev *pci, |
1696 | unsigned long device_type, | 2099 | unsigned long device_type, |
1697 | struct snd_azf3328 ** rchip) | 2100 | struct snd_azf3328 **rchip) |
1698 | { | 2101 | { |
1699 | struct snd_azf3328 *chip; | 2102 | struct snd_azf3328 *chip; |
1700 | int err; | 2103 | int err; |
@@ -1705,7 +2108,8 @@ snd_azf3328_create(struct snd_card *card, | |||
1705 | 2108 | ||
1706 | *rchip = NULL; | 2109 | *rchip = NULL; |
1707 | 2110 | ||
1708 | if ((err = pci_enable_device(pci)) < 0) | 2111 | err = pci_enable_device(pci); |
2112 | if (err < 0) | ||
1709 | return err; | 2113 | return err; |
1710 | 2114 | ||
1711 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | 2115 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); |
@@ -1721,20 +2125,25 @@ snd_azf3328_create(struct snd_card *card, | |||
1721 | /* check if we can restrict PCI DMA transfers to 24 bits */ | 2125 | /* check if we can restrict PCI DMA transfers to 24 bits */ |
1722 | if (pci_set_dma_mask(pci, DMA_24BIT_MASK) < 0 || | 2126 | if (pci_set_dma_mask(pci, DMA_24BIT_MASK) < 0 || |
1723 | pci_set_consistent_dma_mask(pci, DMA_24BIT_MASK) < 0) { | 2127 | pci_set_consistent_dma_mask(pci, DMA_24BIT_MASK) < 0) { |
1724 | snd_printk(KERN_ERR "architecture does not support 24bit PCI busmaster DMA\n"); | 2128 | snd_printk(KERN_ERR "architecture does not support " |
2129 | "24bit PCI busmaster DMA\n" | ||
2130 | ); | ||
1725 | err = -ENXIO; | 2131 | err = -ENXIO; |
1726 | goto out_err; | 2132 | goto out_err; |
1727 | } | 2133 | } |
1728 | 2134 | ||
1729 | if ((err = pci_request_regions(pci, "Aztech AZF3328")) < 0) { | 2135 | err = pci_request_regions(pci, "Aztech AZF3328"); |
2136 | if (err < 0) | ||
1730 | goto out_err; | 2137 | goto out_err; |
1731 | } | ||
1732 | 2138 | ||
1733 | chip->codec_port = pci_resource_start(pci, 0); | 2139 | chip->codec_io = pci_resource_start(pci, 0); |
1734 | chip->io2_port = pci_resource_start(pci, 1); | 2140 | chip->game_io = pci_resource_start(pci, 1); |
1735 | chip->mpu_port = pci_resource_start(pci, 2); | 2141 | chip->mpu_io = pci_resource_start(pci, 2); |
1736 | chip->synth_port = pci_resource_start(pci, 3); | 2142 | chip->opl3_io = pci_resource_start(pci, 3); |
1737 | chip->mixer_port = pci_resource_start(pci, 4); | 2143 | chip->mixer_io = pci_resource_start(pci, 4); |
2144 | |||
2145 | chip->audio_stream[AZF_PLAYBACK].portbase = chip->codec_io + 0x00; | ||
2146 | chip->audio_stream[AZF_CAPTURE].portbase = chip->codec_io + 0x20; | ||
1738 | 2147 | ||
1739 | if (request_irq(pci->irq, snd_azf3328_interrupt, | 2148 | if (request_irq(pci->irq, snd_azf3328_interrupt, |
1740 | IRQF_SHARED, card->shortname, chip)) { | 2149 | IRQF_SHARED, card->shortname, chip)) { |
@@ -1747,29 +2156,29 @@ snd_azf3328_create(struct snd_card *card, | |||
1747 | synchronize_irq(chip->irq); | 2156 | synchronize_irq(chip->irq); |
1748 | 2157 | ||
1749 | snd_azf3328_debug_show_ports(chip); | 2158 | snd_azf3328_debug_show_ports(chip); |
1750 | 2159 | ||
1751 | if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { | 2160 | err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); |
2161 | if (err < 0) | ||
1752 | goto out_err; | 2162 | goto out_err; |
1753 | } | ||
1754 | 2163 | ||
1755 | /* create mixer interface & switches */ | 2164 | /* create mixer interface & switches */ |
1756 | if ((err = snd_azf3328_mixer_new(chip)) < 0) | 2165 | err = snd_azf3328_mixer_new(chip); |
2166 | if (err < 0) | ||
1757 | goto out_err; | 2167 | goto out_err; |
1758 | 2168 | ||
1759 | #if 0 | 2169 | /* shutdown codecs to save power */ |
1760 | /* set very low bitrate to reduce noise and power consumption? */ | 2170 | /* have snd_azf3328_codec_activity() act properly */ |
1761 | snd_azf3328_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, 5512, 8, 1); | 2171 | chip->audio_stream[AZF_PLAYBACK].running = 1; |
1762 | #endif | 2172 | snd_azf3328_codec_activity(chip, AZF_PLAYBACK, 0); |
1763 | 2173 | ||
1764 | /* standard chip init stuff */ | 2174 | /* standard chip init stuff */ |
1765 | /* default IRQ init value */ | 2175 | /* default IRQ init value */ |
1766 | tmp = DMA_PLAY_SOMETHING2|DMA_EPILOGUE_SOMETHING|DMA_SOMETHING_ELSE; | 2176 | tmp = DMA_PLAY_SOMETHING2|DMA_EPILOGUE_SOMETHING|DMA_SOMETHING_ELSE; |
1767 | 2177 | ||
1768 | spin_lock_irq(&chip->reg_lock); | 2178 | spin_lock_irq(&chip->reg_lock); |
1769 | snd_azf3328_codec_outb(chip, IDX_IO_PLAY_FLAGS, tmp); | 2179 | snd_azf3328_codec_outb(chip, IDX_IO_PLAY_FLAGS, tmp); |
1770 | snd_azf3328_codec_outb(chip, IDX_IO_REC_FLAGS, tmp); | 2180 | snd_azf3328_codec_outb(chip, IDX_IO_REC_FLAGS, tmp); |
1771 | snd_azf3328_codec_outb(chip, IDX_IO_SOMETHING_FLAGS, tmp); | 2181 | snd_azf3328_codec_outb(chip, IDX_IO_SOMETHING_FLAGS, tmp); |
1772 | snd_azf3328_codec_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x00); /* disable timer */ | ||
1773 | spin_unlock_irq(&chip->reg_lock); | 2182 | spin_unlock_irq(&chip->reg_lock); |
1774 | 2183 | ||
1775 | snd_card_set_dev(card, &pci->dev); | 2184 | snd_card_set_dev(card, &pci->dev); |
@@ -1805,52 +2214,61 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) | |||
1805 | return -ENOENT; | 2214 | return -ENOENT; |
1806 | } | 2215 | } |
1807 | 2216 | ||
1808 | card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0 ); | 2217 | card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); |
1809 | if (card == NULL) | 2218 | if (card == NULL) |
1810 | return -ENOMEM; | 2219 | return -ENOMEM; |
1811 | 2220 | ||
1812 | strcpy(card->driver, "AZF3328"); | 2221 | strcpy(card->driver, "AZF3328"); |
1813 | strcpy(card->shortname, "Aztech AZF3328 (PCI168)"); | 2222 | strcpy(card->shortname, "Aztech AZF3328 (PCI168)"); |
1814 | 2223 | ||
1815 | if ((err = snd_azf3328_create(card, pci, pci_id->driver_data, &chip)) < 0) { | 2224 | err = snd_azf3328_create(card, pci, pci_id->driver_data, &chip); |
2225 | if (err < 0) | ||
1816 | goto out_err; | 2226 | goto out_err; |
1817 | } | ||
1818 | 2227 | ||
1819 | card->private_data = chip; | 2228 | card->private_data = chip; |
1820 | 2229 | ||
1821 | if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_MPU401, | 2230 | err = snd_mpu401_uart_new( |
1822 | chip->mpu_port, MPU401_INFO_INTEGRATED, | 2231 | card, 0, MPU401_HW_MPU401, chip->mpu_io, MPU401_INFO_INTEGRATED, |
1823 | pci->irq, 0, &chip->rmidi)) < 0) { | 2232 | pci->irq, 0, &chip->rmidi |
1824 | snd_printk(KERN_ERR "azf3328: no MPU-401 device at 0x%lx?\n", chip->mpu_port); | 2233 | ); |
2234 | if (err < 0) { | ||
2235 | snd_printk(KERN_ERR "azf3328: no MPU-401 device at 0x%lx?\n", | ||
2236 | chip->mpu_io | ||
2237 | ); | ||
1825 | goto out_err; | 2238 | goto out_err; |
1826 | } | 2239 | } |
1827 | 2240 | ||
1828 | if ((err = snd_azf3328_timer(chip, 0)) < 0) { | 2241 | err = snd_azf3328_timer(chip, 0); |
2242 | if (err < 0) | ||
1829 | goto out_err; | 2243 | goto out_err; |
1830 | } | ||
1831 | 2244 | ||
1832 | if ((err = snd_azf3328_pcm(chip, 0)) < 0) { | 2245 | err = snd_azf3328_pcm(chip, 0); |
2246 | if (err < 0) | ||
1833 | goto out_err; | 2247 | goto out_err; |
1834 | } | ||
1835 | 2248 | ||
1836 | if (snd_opl3_create(card, chip->synth_port, chip->synth_port+2, | 2249 | if (snd_opl3_create(card, chip->opl3_io, chip->opl3_io+2, |
1837 | OPL3_HW_AUTO, 1, &opl3) < 0) { | 2250 | OPL3_HW_AUTO, 1, &opl3) < 0) { |
1838 | snd_printk(KERN_ERR "azf3328: no OPL3 device at 0x%lx-0x%lx?\n", | 2251 | snd_printk(KERN_ERR "azf3328: no OPL3 device at 0x%lx-0x%lx?\n", |
1839 | chip->synth_port, chip->synth_port+2 ); | 2252 | chip->opl3_io, chip->opl3_io+2 |
2253 | ); | ||
1840 | } else { | 2254 | } else { |
1841 | if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { | 2255 | /* need to use IDs 1, 2 since ID 0 is snd_azf3328_timer above */ |
2256 | err = snd_opl3_timer_new(opl3, 1, 2); | ||
2257 | if (err < 0) | ||
2258 | goto out_err; | ||
2259 | err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); | ||
2260 | if (err < 0) | ||
1842 | goto out_err; | 2261 | goto out_err; |
1843 | } | ||
1844 | } | 2262 | } |
1845 | 2263 | ||
1846 | opl3->private_data = chip; | 2264 | opl3->private_data = chip; |
1847 | 2265 | ||
1848 | sprintf(card->longname, "%s at 0x%lx, irq %i", | 2266 | sprintf(card->longname, "%s at 0x%lx, irq %i", |
1849 | card->shortname, chip->codec_port, chip->irq); | 2267 | card->shortname, chip->codec_io, chip->irq); |
1850 | 2268 | ||
1851 | if ((err = snd_card_register(card)) < 0) { | 2269 | err = snd_card_register(card); |
2270 | if (err < 0) | ||
1852 | goto out_err; | 2271 | goto out_err; |
1853 | } | ||
1854 | 2272 | ||
1855 | #ifdef MODULE | 2273 | #ifdef MODULE |
1856 | printk( | 2274 | printk( |
@@ -1861,19 +2279,18 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) | |||
1861 | 1024000 / seqtimer_scaling, seqtimer_scaling); | 2279 | 1024000 / seqtimer_scaling, seqtimer_scaling); |
1862 | #endif | 2280 | #endif |
1863 | 2281 | ||
1864 | if (snd_azf3328_config_joystick(chip, dev) < 0) | 2282 | snd_azf3328_gameport(chip, dev); |
1865 | snd_azf3328_io2_outb(chip, IDX_IO2_LEGACY_ADDR, | ||
1866 | snd_azf3328_io2_inb(chip, IDX_IO2_LEGACY_ADDR) & ~LEGACY_JOY); | ||
1867 | 2283 | ||
1868 | pci_set_drvdata(pci, card); | 2284 | pci_set_drvdata(pci, card); |
1869 | dev++; | 2285 | dev++; |
1870 | 2286 | ||
1871 | err = 0; | 2287 | err = 0; |
1872 | goto out; | 2288 | goto out; |
1873 | 2289 | ||
1874 | out_err: | 2290 | out_err: |
2291 | snd_printk(KERN_ERR "azf3328: something failed, exiting\n"); | ||
1875 | snd_card_free(card); | 2292 | snd_card_free(card); |
1876 | 2293 | ||
1877 | out: | 2294 | out: |
1878 | snd_azf3328_dbgcallleave(); | 2295 | snd_azf3328_dbgcallleave(); |
1879 | return err; | 2296 | return err; |
@@ -1894,27 +2311,31 @@ snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state) | |||
1894 | { | 2311 | { |
1895 | struct snd_card *card = pci_get_drvdata(pci); | 2312 | struct snd_card *card = pci_get_drvdata(pci); |
1896 | struct snd_azf3328 *chip = card->private_data; | 2313 | struct snd_azf3328 *chip = card->private_data; |
1897 | int reg; | 2314 | unsigned reg; |
1898 | 2315 | ||
1899 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | 2316 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); |
1900 | 2317 | ||
1901 | snd_pcm_suspend_all(chip->pcm); | 2318 | snd_pcm_suspend_all(chip->pcm); |
1902 | 2319 | ||
1903 | for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; reg++) | 2320 | for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; ++reg) |
1904 | chip->saved_regs_mixer[reg] = inw(chip->mixer_port + reg * 2); | 2321 | chip->saved_regs_mixer[reg] = inw(chip->mixer_io + reg * 2); |
1905 | 2322 | ||
1906 | /* make sure to disable master volume etc. to prevent looping sound */ | 2323 | /* make sure to disable master volume etc. to prevent looping sound */ |
1907 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1); | 2324 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1); |
1908 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); | 2325 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); |
1909 | 2326 | ||
1910 | for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; reg++) | 2327 | for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; ++reg) |
1911 | chip->saved_regs_codec[reg] = inw(chip->codec_port + reg * 2); | 2328 | chip->saved_regs_codec[reg] = inw(chip->codec_io + reg * 2); |
1912 | for (reg = 0; reg < AZF_IO_SIZE_IO2_PM / 2; reg++) | 2329 | |
1913 | chip->saved_regs_io2[reg] = inw(chip->io2_port + reg * 2); | 2330 | /* manually store the one currently relevant write-only reg, too */ |
1914 | for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; reg++) | 2331 | chip->saved_regs_codec[IDX_IO_6AH / 2] = chip->shadow_reg_codec_6AH; |
1915 | chip->saved_regs_mpu[reg] = inw(chip->mpu_port + reg * 2); | 2332 | |
1916 | for (reg = 0; reg < AZF_IO_SIZE_SYNTH_PM / 2; reg++) | 2333 | for (reg = 0; reg < AZF_IO_SIZE_GAME_PM / 2; ++reg) |
1917 | chip->saved_regs_synth[reg] = inw(chip->synth_port + reg * 2); | 2334 | chip->saved_regs_game[reg] = inw(chip->game_io + reg * 2); |
2335 | for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; ++reg) | ||
2336 | chip->saved_regs_mpu[reg] = inw(chip->mpu_io + reg * 2); | ||
2337 | for (reg = 0; reg < AZF_IO_SIZE_OPL3_PM / 2; ++reg) | ||
2338 | chip->saved_regs_opl3[reg] = inw(chip->opl3_io + reg * 2); | ||
1918 | 2339 | ||
1919 | pci_disable_device(pci); | 2340 | pci_disable_device(pci); |
1920 | pci_save_state(pci); | 2341 | pci_save_state(pci); |
@@ -1927,7 +2348,7 @@ snd_azf3328_resume(struct pci_dev *pci) | |||
1927 | { | 2348 | { |
1928 | struct snd_card *card = pci_get_drvdata(pci); | 2349 | struct snd_card *card = pci_get_drvdata(pci); |
1929 | struct snd_azf3328 *chip = card->private_data; | 2350 | struct snd_azf3328 *chip = card->private_data; |
1930 | int reg; | 2351 | unsigned reg; |
1931 | 2352 | ||
1932 | pci_set_power_state(pci, PCI_D0); | 2353 | pci_set_power_state(pci, PCI_D0); |
1933 | pci_restore_state(pci); | 2354 | pci_restore_state(pci); |
@@ -1939,23 +2360,21 @@ snd_azf3328_resume(struct pci_dev *pci) | |||
1939 | } | 2360 | } |
1940 | pci_set_master(pci); | 2361 | pci_set_master(pci); |
1941 | 2362 | ||
1942 | for (reg = 0; reg < AZF_IO_SIZE_IO2_PM / 2; reg++) | 2363 | for (reg = 0; reg < AZF_IO_SIZE_GAME_PM / 2; ++reg) |
1943 | outw(chip->saved_regs_io2[reg], chip->io2_port + reg * 2); | 2364 | outw(chip->saved_regs_game[reg], chip->game_io + reg * 2); |
1944 | for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; reg++) | 2365 | for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; ++reg) |
1945 | outw(chip->saved_regs_mpu[reg], chip->mpu_port + reg * 2); | 2366 | outw(chip->saved_regs_mpu[reg], chip->mpu_io + reg * 2); |
1946 | for (reg = 0; reg < AZF_IO_SIZE_SYNTH_PM / 2; reg++) | 2367 | for (reg = 0; reg < AZF_IO_SIZE_OPL3_PM / 2; ++reg) |
1947 | outw(chip->saved_regs_synth[reg], chip->synth_port + reg * 2); | 2368 | outw(chip->saved_regs_opl3[reg], chip->opl3_io + reg * 2); |
1948 | for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; reg++) | 2369 | for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; ++reg) |
1949 | outw(chip->saved_regs_mixer[reg], chip->mixer_port + reg * 2); | 2370 | outw(chip->saved_regs_mixer[reg], chip->mixer_io + reg * 2); |
1950 | for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; reg++) | 2371 | for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; ++reg) |
1951 | outw(chip->saved_regs_codec[reg], chip->codec_port + reg * 2); | 2372 | outw(chip->saved_regs_codec[reg], chip->codec_io + reg * 2); |
1952 | 2373 | ||
1953 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | 2374 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); |
1954 | return 0; | 2375 | return 0; |
1955 | } | 2376 | } |
1956 | #endif | 2377 | #endif /* CONFIG_PM */ |
1957 | |||
1958 | |||
1959 | 2378 | ||
1960 | 2379 | ||
1961 | static struct pci_driver driver = { | 2380 | static struct pci_driver driver = { |
diff --git a/sound/pci/azt3328.h b/sound/pci/azt3328.h index 679fa992e2bc..7e3e8942d073 100644 --- a/sound/pci/azt3328.h +++ b/sound/pci/azt3328.h | |||
@@ -1,7 +1,8 @@ | |||
1 | #ifndef __SOUND_AZT3328_H | 1 | #ifndef __SOUND_AZT3328_H |
2 | #define __SOUND_AZT3328_H | 2 | #define __SOUND_AZT3328_H |
3 | 3 | ||
4 | /* "PU" == "power-up value", as tested on PCI168 PCI rev. 10 */ | 4 | /* "PU" == "power-up value", as tested on PCI168 PCI rev. 10 |
5 | * "WRITE_ONLY" == register does not indicate actual bit values */ | ||
5 | 6 | ||
6 | /*** main I/O area port indices ***/ | 7 | /*** main I/O area port indices ***/ |
7 | /* (only 0x70 of 0x80 bytes saved/restored by Windows driver) */ | 8 | /* (only 0x70 of 0x80 bytes saved/restored by Windows driver) */ |
@@ -54,7 +55,10 @@ | |||
54 | #define SOUNDFORMAT_XTAL1 0x00 | 55 | #define SOUNDFORMAT_XTAL1 0x00 |
55 | #define SOUNDFORMAT_XTAL2 0x01 | 56 | #define SOUNDFORMAT_XTAL2 0x01 |
56 | /* all _SUSPECTED_ values are not used by Windows drivers, so we don't | 57 | /* all _SUSPECTED_ values are not used by Windows drivers, so we don't |
57 | * have any hard facts, only rough measurements */ | 58 | * have any hard facts, only rough measurements. |
59 | * All we know is that the crystal used on the board has 24.576MHz, | ||
60 | * like many soundcards (which results in the frequencies below when | ||
61 | * using certain divider values selected by the values below) */ | ||
58 | #define SOUNDFORMAT_FREQ_SUSPECTED_4000 0x0c | SOUNDFORMAT_XTAL1 | 62 | #define SOUNDFORMAT_FREQ_SUSPECTED_4000 0x0c | SOUNDFORMAT_XTAL1 |
59 | #define SOUNDFORMAT_FREQ_SUSPECTED_4800 0x0a | SOUNDFORMAT_XTAL1 | 63 | #define SOUNDFORMAT_FREQ_SUSPECTED_4800 0x0a | SOUNDFORMAT_XTAL1 |
60 | #define SOUNDFORMAT_FREQ_5510 0x0c | SOUNDFORMAT_XTAL2 | 64 | #define SOUNDFORMAT_FREQ_5510 0x0c | SOUNDFORMAT_XTAL2 |
@@ -72,6 +76,26 @@ | |||
72 | #define SOUNDFORMAT_FLAG_16BIT 0x0010 | 76 | #define SOUNDFORMAT_FLAG_16BIT 0x0010 |
73 | #define SOUNDFORMAT_FLAG_2CHANNELS 0x0020 | 77 | #define SOUNDFORMAT_FLAG_2CHANNELS 0x0020 |
74 | 78 | ||
79 | /* define frequency helpers, for maximum value safety */ | ||
80 | enum azf_freq_t { | ||
81 | #define AZF_FREQ(rate) AZF_FREQ_##rate = rate | ||
82 | AZF_FREQ(4000), | ||
83 | AZF_FREQ(4800), | ||
84 | AZF_FREQ(5512), | ||
85 | AZF_FREQ(6620), | ||
86 | AZF_FREQ(8000), | ||
87 | AZF_FREQ(9600), | ||
88 | AZF_FREQ(11025), | ||
89 | AZF_FREQ(13240), | ||
90 | AZF_FREQ(16000), | ||
91 | AZF_FREQ(22050), | ||
92 | AZF_FREQ(32000), | ||
93 | AZF_FREQ(44100), | ||
94 | AZF_FREQ(48000), | ||
95 | AZF_FREQ(66200), | ||
96 | #undef AZF_FREQ | ||
97 | } AZF_FREQUENCIES; | ||
98 | |||
75 | /** recording area (see also: playback bit flag definitions) **/ | 99 | /** recording area (see also: playback bit flag definitions) **/ |
76 | #define IDX_IO_REC_FLAGS 0x20 /* ??, PU:0x0000 */ | 100 | #define IDX_IO_REC_FLAGS 0x20 /* ??, PU:0x0000 */ |
77 | #define IDX_IO_REC_IRQTYPE 0x22 /* ??, PU:0x0000 */ | 101 | #define IDX_IO_REC_IRQTYPE 0x22 /* ??, PU:0x0000 */ |
@@ -97,40 +121,171 @@ | |||
97 | 121 | ||
98 | /** DirectX timer, main interrupt area (FIXME: and something else?) **/ | 122 | /** DirectX timer, main interrupt area (FIXME: and something else?) **/ |
99 | #define IDX_IO_TIMER_VALUE 0x60 /* found this timer area by pure luck :-) */ | 123 | #define IDX_IO_TIMER_VALUE 0x60 /* found this timer area by pure luck :-) */ |
100 | #define TIMER_VALUE_MASK 0x000fffffUL /* timer countdown value; triggers IRQ when timer is finished */ | 124 | /* timer countdown value; triggers IRQ when timer is finished */ |
101 | #define TIMER_ENABLE_COUNTDOWN 0x01000000UL /* activate the timer countdown */ | 125 | #define TIMER_VALUE_MASK 0x000fffffUL |
102 | #define TIMER_ENABLE_IRQ 0x02000000UL /* trigger timer IRQ on zero transition */ | 126 | /* activate timer countdown */ |
103 | #define TIMER_ACK_IRQ 0x04000000UL /* being set in IRQ handler in case port 0x00 (hmm, not port 0x64!?!?) had 0x0020 set upon IRQ handler */ | 127 | #define TIMER_COUNTDOWN_ENABLE 0x01000000UL |
128 | /* trigger timer IRQ on zero transition */ | ||
129 | #define TIMER_IRQ_ENABLE 0x02000000UL | ||
130 | /* being set in IRQ handler in case port 0x00 (hmm, not port 0x64!?!?) | ||
131 | * had 0x0020 set upon IRQ handler */ | ||
132 | #define TIMER_IRQ_ACK 0x04000000UL | ||
104 | #define IDX_IO_IRQSTATUS 0x64 | 133 | #define IDX_IO_IRQSTATUS 0x64 |
105 | #define IRQ_PLAYBACK 0x0001 | 134 | /* some IRQ bit in here might also be used to signal a power-management timer |
106 | #define IRQ_RECORDING 0x0002 | 135 | * timeout, to request shutdown of the chip (e.g. AD1815JS has such a thing). |
107 | #define IRQ_MPU401 0x0010 | 136 | * Some OPL3 hardware (e.g. in LM4560) has some special timer hardware which |
108 | #define IRQ_TIMER 0x0020 /* DirectX timer */ | 137 | * can trigger an OPL3 timer IRQ, so maybe there's such a thing as well... */ |
109 | #define IRQ_UNKNOWN1 0x0040 /* probably unused, or possibly I2S port? or gameport IRQ? */ | 138 | |
110 | #define IRQ_UNKNOWN2 0x0080 /* probably unused, or possibly I2S port? or gameport IRQ? */ | 139 | #define IRQ_PLAYBACK 0x0001 |
140 | #define IRQ_RECORDING 0x0002 | ||
141 | #define IRQ_UNKNOWN1 0x0004 /* most probably I2S port */ | ||
142 | #define IRQ_GAMEPORT 0x0008 /* Interrupt of Digital(ly) Enhanced Game Port */ | ||
143 | #define IRQ_MPU401 0x0010 | ||
144 | #define IRQ_TIMER 0x0020 /* DirectX timer */ | ||
145 | #define IRQ_UNKNOWN2 0x0040 /* probably unused, or possibly I2S port? */ | ||
146 | #define IRQ_UNKNOWN3 0x0080 /* probably unused, or possibly I2S port? */ | ||
111 | #define IDX_IO_66H 0x66 /* writing 0xffff returns 0x0000 */ | 147 | #define IDX_IO_66H 0x66 /* writing 0xffff returns 0x0000 */ |
112 | #define IDX_IO_SOME_VALUE 0x68 /* this is set to e.g. 0x3ff or 0x300, and writable; maybe some buffer limit, but I couldn't find out more, PU:0x00ff */ | 148 | /* this is set to e.g. 0x3ff or 0x300, and writable; |
113 | #define IDX_IO_6AH 0x6A /* this WORD can be set to have bits 0x0028 activated (FIXME: correct??); actually inhibits PCM playback!!! maybe power management?? */ | 149 | * maybe some buffer limit, but I couldn't find out more, PU:0x00ff: */ |
114 | #define IO_6A_PAUSE_PLAYBACK 0x0200 /* bit 9; sure, this pauses playback, but what the heck is this really about?? */ | 150 | #define IDX_IO_SOME_VALUE 0x68 |
115 | #define IDX_IO_6CH 0x6C | 151 | #define IO_68_RANDOM_TOGGLE1 0x0100 /* toggles randomly */ |
116 | #define IDX_IO_6EH 0x6E /* writing 0xffff returns 0x83fe */ | 152 | #define IO_68_RANDOM_TOGGLE2 0x0200 /* toggles randomly */ |
117 | /* further I/O indices not saved/restored, so probably not used */ | 153 | /* umm, nope, behaviour of these bits changes depending on what we wrote |
154 | * to 0x6b!! | ||
155 | * And they change upon playback/stop, too: | ||
156 | * Writing a value to 0x68 will display this exact value during playback, | ||
157 | * too but when stopped it can fall back to a rather different | ||
158 | * seemingly random value). Hmm, possibly this is a register which | ||
159 | * has a remote shadow which needs proper device supply which only exists | ||
160 | * in case playback is active? Or is this driver-induced? | ||
161 | */ | ||
162 | |||
163 | /* this WORD can be set to have bits 0x0028 activated (FIXME: correct??); | ||
164 | * actually inhibits PCM playback!!! maybe power management??: */ | ||
165 | #define IDX_IO_6AH 0x6A /* WRITE_ONLY! */ | ||
166 | /* bit 5: enabling this will activate permanent counting of bytes 2/3 | ||
167 | * at gameport I/O (0xb402/3) (equal values each) and cause | ||
168 | * gameport legacy I/O at 0x0200 to be _DISABLED_! | ||
169 | * Is this Digital Enhanced Game Port Enable??? Or maybe it's Testmode | ||
170 | * for Enhanced Digital Gameport (see 4D Wave DX card): */ | ||
171 | #define IO_6A_SOMETHING1_GAMEPORT 0x0020 | ||
172 | /* bit 8; sure, this _pauses_ playback (later resumes at same spot!), | ||
173 | * but what the heck is this really about??: */ | ||
174 | #define IO_6A_PAUSE_PLAYBACK_BIT8 0x0100 | ||
175 | /* bit 9; sure, this _pauses_ playback (later resumes at same spot!), | ||
176 | * but what the heck is this really about??: */ | ||
177 | #define IO_6A_PAUSE_PLAYBACK_BIT9 0x0200 | ||
178 | /* BIT8 and BIT9 are _NOT_ able to affect OPL3 MIDI playback, | ||
179 | * thus it suggests influence on PCM only!! | ||
180 | * However OTOH there seems to be no bit anywhere around here | ||
181 | * which is able to disable OPL3... */ | ||
182 | /* bit 10: enabling this actually changes values at legacy gameport | ||
183 | * I/O address (0x200); is this enabling of the Digital Enhanced Game Port??? | ||
184 | * Or maybe this simply switches off the NE558 circuit, since enabling this | ||
185 | * still lets us evaluate button states, but not axis states */ | ||
186 | #define IO_6A_SOMETHING2_GAMEPORT 0x0400 | ||
187 | /* writing 0x0300: causes quite some crackling during | ||
188 | * PC activity such as switching windows (PCI traffic?? | ||
189 | * --> FIFO/timing settings???) */ | ||
190 | /* writing 0x0100 plus/or 0x0200 inhibits playback */ | ||
191 | /* since the Windows .INF file has Flag_Enable_JoyStick and | ||
192 | * Flag_Enable_SB_DOS_Emulation directly together, it stands to reason | ||
193 | * that some other bit in this same register might be responsible | ||
194 | * for SB DOS Emulation activation (note that the file did NOT define | ||
195 | * a switch for OPL3!) */ | ||
196 | #define IDX_IO_6CH 0x6C /* unknown; fully read-writable */ | ||
197 | #define IDX_IO_6EH 0x6E | ||
198 | /* writing 0xffff returns 0x83fe (or 0x03fe only). | ||
199 | * writing 0x83 (and only 0x83!!) to 0x6f will cause 0x6c to switch | ||
200 | * from 0000 to ffff. */ | ||
118 | 201 | ||
202 | /* further I/O indices not saved/restored and not readable after writing, | ||
203 | * so probably not used */ | ||
119 | 204 | ||
120 | /*** I/O 2 area port indices ***/ | 205 | |
206 | /*** Gameport area port indices ***/ | ||
121 | /* (only 0x06 of 0x08 bytes saved/restored by Windows driver) */ | 207 | /* (only 0x06 of 0x08 bytes saved/restored by Windows driver) */ |
122 | #define AZF_IO_SIZE_IO2 0x08 | 208 | #define AZF_IO_SIZE_GAME 0x08 |
123 | #define AZF_IO_SIZE_IO2_PM 0x06 | 209 | #define AZF_IO_SIZE_GAME_PM 0x06 |
210 | |||
211 | enum { | ||
212 | AZF_GAME_LEGACY_IO_PORT = 0x200 | ||
213 | } AZF_GAME_CONFIGS; | ||
214 | |||
215 | #define IDX_GAME_LEGACY_COMPATIBLE 0x00 | ||
216 | /* in some operation mode, writing anything to this port | ||
217 | * triggers an interrupt: | ||
218 | * yup, that's in case IDX_GAME_01H has one of the | ||
219 | * axis measurement bits enabled | ||
220 | * (and of course one needs to have GAME_HWCFG_IRQ_ENABLE, too) */ | ||
221 | |||
222 | #define IDX_GAME_AXES_CONFIG 0x01 | ||
223 | /* NOTE: layout of this register awfully similar (read: "identical??") | ||
224 | * to AD1815JS.pdf (p.29) */ | ||
225 | |||
226 | /* enables axis 1 (X axis) measurement: */ | ||
227 | #define GAME_AXES_ENABLE_1 0x01 | ||
228 | /* enables axis 2 (Y axis) measurement: */ | ||
229 | #define GAME_AXES_ENABLE_2 0x02 | ||
230 | /* enables axis 3 (X axis) measurement: */ | ||
231 | #define GAME_AXES_ENABLE_3 0x04 | ||
232 | /* enables axis 4 (Y axis) measurement: */ | ||
233 | #define GAME_AXES_ENABLE_4 0x08 | ||
234 | /* selects the current axis to read the measured value of | ||
235 | * (at IDX_GAME_AXIS_VALUE): | ||
236 | * 00 = axis 1, 01 = axis 2, 10 = axis 3, 11 = axis 4: */ | ||
237 | #define GAME_AXES_READ_MASK 0x30 | ||
238 | /* enable to have the latch continuously accept ADC values | ||
239 | * (and continuously cause interrupts in case interrupts are enabled); | ||
240 | * AD1815JS.pdf says it's ~16ms interval there: */ | ||
241 | #define GAME_AXES_LATCH_ENABLE 0x40 | ||
242 | /* joystick data (measured axes) ready for reading: */ | ||
243 | #define GAME_AXES_SAMPLING_READY 0x80 | ||
244 | |||
245 | /* NOTE: other card specs (SiS960 and others!) state that the | ||
246 | * game position latches should be frozen when reading and be freed | ||
247 | * (== reset?) after reading!!! | ||
248 | * Freezing most likely means disabling 0x40 (GAME_AXES_LATCH_ENABLE), | ||
249 | * but how to free the value? */ | ||
250 | /* An internet search for "gameport latch ADC" should provide some insight | ||
251 | * into how to program such a gameport system. */ | ||
252 | |||
253 | /* writing 0xf0 to 01H once reset both counters to 0, in some special mode!? | ||
254 | * yup, in case 6AH 0x20 is not enabled | ||
255 | * (and 0x40 is sufficient, 0xf0 is not needed) */ | ||
256 | |||
257 | #define IDX_GAME_AXIS_VALUE 0x02 | ||
258 | /* R: value of currently configured axis (word value!); | ||
259 | * W: trigger axis measurement */ | ||
260 | |||
261 | #define IDX_GAME_HWCONFIG 0x04 | ||
262 | /* note: bits 4 to 7 are never set (== 0) when reading! | ||
263 | * --> reserved bits? */ | ||
264 | /* enables IRQ notification upon axes measurement ready: */ | ||
265 | #define GAME_HWCFG_IRQ_ENABLE 0x01 | ||
266 | /* these bits choose a different frequency for the | ||
267 | * internal ADC counter increment. | ||
268 | * hmm, seems to be a combo of bits: | ||
269 | * 00 --> standard frequency | ||
270 | * 10 --> 1/2 | ||
271 | * 01 --> 1/20 | ||
272 | * 11 --> 1/200: */ | ||
273 | #define GAME_HWCFG_ADC_COUNTER_FREQ_MASK 0x06 | ||
124 | 274 | ||
125 | #define IDX_IO2_LEGACY_ADDR 0x04 | 275 | /* enable gameport legacy I/O address (0x200) |
126 | #define LEGACY_SOMETHING 0x01 /* OPL3?? */ | 276 | * I was unable to locate any configurability for a different address: */ |
127 | #define LEGACY_JOY 0x08 | 277 | #define GAME_HWCFG_LEGACY_ADDRESS_ENABLE 0x08 |
128 | 278 | ||
279 | /*** MPU401 ***/ | ||
129 | #define AZF_IO_SIZE_MPU 0x04 | 280 | #define AZF_IO_SIZE_MPU 0x04 |
130 | #define AZF_IO_SIZE_MPU_PM 0x04 | 281 | #define AZF_IO_SIZE_MPU_PM 0x04 |
131 | 282 | ||
132 | #define AZF_IO_SIZE_SYNTH 0x08 | 283 | /*** OPL3 synth ***/ |
133 | #define AZF_IO_SIZE_SYNTH_PM 0x06 | 284 | #define AZF_IO_SIZE_OPL3 0x08 |
285 | #define AZF_IO_SIZE_OPL3_PM 0x06 | ||
286 | /* hmm, given that a standard OPL3 has 4 registers only, | ||
287 | * there might be some enhanced functionality lurking at the end | ||
288 | * (especially since register 0x04 has a "non-empty" value 0xfe) */ | ||
134 | 289 | ||
135 | /*** mixer I/O area port indices ***/ | 290 | /*** mixer I/O area port indices ***/ |
136 | /* (only 0x22 of 0x40 bytes saved/restored by Windows driver) | 291 | /* (only 0x22 of 0x40 bytes saved/restored by Windows driver) |
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index ecbe79b67e43..2f8b28add276 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c | |||
@@ -249,6 +249,11 @@ static struct snd_ca0106_details ca0106_chip_details[] = { | |||
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 */ | ||
253 | { .serial = 0x10091102, | ||
254 | .name = "MSI K8N Diamond MB", | ||
255 | .gpio_type = 2, | ||
256 | .i2c_adc = 1 } , | ||
252 | /* Shuttle XPC SD31P which has an onboard Creative Labs | 257 | /* Shuttle XPC SD31P which has an onboard Creative Labs |
253 | * Sound Blaster Live! 24-bit EAX | 258 | * Sound Blaster Live! 24-bit EAX |
254 | * high-definition 7.1 audio processor". | 259 | * high-definition 7.1 audio processor". |
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 548c9cc81af5..2f283ea6ad9a 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c | |||
@@ -1528,6 +1528,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { | |||
1528 | .ca0151_chip = 1, | 1528 | .ca0151_chip = 1, |
1529 | .spk71 = 1, | 1529 | .spk71 = 1, |
1530 | .spdif_bug = 1, | 1530 | .spdif_bug = 1, |
1531 | .invert_shared_spdif = 1, /* digital/analog switch swapped */ | ||
1531 | .adc_1361t = 1, /* 24 bit capture instead of 16bit. Fixes ALSA bug#324 */ | 1532 | .adc_1361t = 1, /* 24 bit capture instead of 16bit. Fixes ALSA bug#324 */ |
1532 | .ac97_chip = 1} , | 1533 | .ac97_chip = 1} , |
1533 | {.vendor = 0x1102, .device = 0x0004, .revision = 0x04, | 1534 | {.vendor = 0x1102, .device = 0x0004, .revision = 0x04, |
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index fd221209abcb..f34bbfb705f5 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c | |||
@@ -1578,6 +1578,10 @@ static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol, | |||
1578 | ucontrol->value.integer.value[0] = inl(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0; | 1578 | ucontrol->value.integer.value[0] = inl(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0; |
1579 | else | 1579 | else |
1580 | ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0; | 1580 | ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0; |
1581 | if (emu->card_capabilities->invert_shared_spdif) | ||
1582 | ucontrol->value.integer.value[0] = | ||
1583 | !ucontrol->value.integer.value[0]; | ||
1584 | |||
1581 | return 0; | 1585 | return 0; |
1582 | } | 1586 | } |
1583 | 1587 | ||
@@ -1586,15 +1590,18 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, | |||
1586 | { | 1590 | { |
1587 | unsigned long flags; | 1591 | unsigned long flags; |
1588 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | 1592 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); |
1589 | unsigned int reg, val; | 1593 | unsigned int reg, val, sw; |
1590 | int change = 0; | 1594 | int change = 0; |
1591 | 1595 | ||
1596 | sw = ucontrol->value.integer.value[0]; | ||
1597 | if (emu->card_capabilities->invert_shared_spdif) | ||
1598 | sw = !sw; | ||
1592 | spin_lock_irqsave(&emu->reg_lock, flags); | 1599 | spin_lock_irqsave(&emu->reg_lock, flags); |
1593 | if ( emu->card_capabilities->i2c_adc) { | 1600 | if ( emu->card_capabilities->i2c_adc) { |
1594 | /* Do nothing for Audigy 2 ZS Notebook */ | 1601 | /* Do nothing for Audigy 2 ZS Notebook */ |
1595 | } else if (emu->audigy) { | 1602 | } else if (emu->audigy) { |
1596 | reg = inl(emu->port + A_IOCFG); | 1603 | reg = inl(emu->port + A_IOCFG); |
1597 | val = ucontrol->value.integer.value[0] ? A_IOCFG_GPOUT0 : 0; | 1604 | val = sw ? A_IOCFG_GPOUT0 : 0; |
1598 | change = (reg & A_IOCFG_GPOUT0) != val; | 1605 | change = (reg & A_IOCFG_GPOUT0) != val; |
1599 | if (change) { | 1606 | if (change) { |
1600 | reg &= ~A_IOCFG_GPOUT0; | 1607 | reg &= ~A_IOCFG_GPOUT0; |
@@ -1603,7 +1610,7 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, | |||
1603 | } | 1610 | } |
1604 | } | 1611 | } |
1605 | reg = inl(emu->port + HCFG); | 1612 | reg = inl(emu->port + HCFG); |
1606 | val = ucontrol->value.integer.value[0] ? HCFG_GPOUT0 : 0; | 1613 | val = sw ? HCFG_GPOUT0 : 0; |
1607 | change |= (reg & HCFG_GPOUT0) != val; | 1614 | change |= (reg & HCFG_GPOUT0) != val; |
1608 | if (change) { | 1615 | if (change) { |
1609 | reg &= ~HCFG_GPOUT0; | 1616 | reg &= ~HCFG_GPOUT0; |
diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index 916c1dbcd53c..7d379f5131fb 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c | |||
@@ -437,43 +437,49 @@ static void get_single_page_range(struct snd_util_memhdr *hdr, | |||
437 | *last_page_ret = last_page; | 437 | *last_page_ret = last_page; |
438 | } | 438 | } |
439 | 439 | ||
440 | /* release allocated pages */ | ||
441 | static void __synth_free_pages(struct snd_emu10k1 *emu, int first_page, | ||
442 | int last_page) | ||
443 | { | ||
444 | int page; | ||
445 | |||
446 | for (page = first_page; page <= last_page; page++) { | ||
447 | free_page((unsigned long)emu->page_ptr_table[page]); | ||
448 | emu->page_addr_table[page] = 0; | ||
449 | emu->page_ptr_table[page] = NULL; | ||
450 | } | ||
451 | } | ||
452 | |||
440 | /* | 453 | /* |
441 | * allocate kernel pages | 454 | * allocate kernel pages |
442 | */ | 455 | */ |
443 | static int synth_alloc_pages(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk) | 456 | static int synth_alloc_pages(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk) |
444 | { | 457 | { |
445 | int page, first_page, last_page; | 458 | int page, first_page, last_page; |
446 | struct snd_dma_buffer dmab; | ||
447 | 459 | ||
448 | emu10k1_memblk_init(blk); | 460 | emu10k1_memblk_init(blk); |
449 | get_single_page_range(emu->memhdr, blk, &first_page, &last_page); | 461 | get_single_page_range(emu->memhdr, blk, &first_page, &last_page); |
450 | /* allocate kernel pages */ | 462 | /* allocate kernel pages */ |
451 | for (page = first_page; page <= last_page; page++) { | 463 | for (page = first_page; page <= last_page; page++) { |
452 | if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), | 464 | /* first try to allocate from <4GB zone */ |
453 | PAGE_SIZE, &dmab) < 0) | 465 | struct page *p = alloc_page(GFP_KERNEL | GFP_DMA32 | |
454 | goto __fail; | 466 | __GFP_NOWARN); |
455 | if (! is_valid_page(emu, dmab.addr)) { | 467 | if (!p || (page_to_pfn(p) & ~(emu->dma_mask >> PAGE_SHIFT))) { |
456 | snd_dma_free_pages(&dmab); | 468 | if (p) |
457 | goto __fail; | 469 | __free_page(p); |
470 | /* try to allocate from <16MB zone */ | ||
471 | p = alloc_page(GFP_ATOMIC | GFP_DMA | | ||
472 | __GFP_NORETRY | /* no OOM-killer */ | ||
473 | __GFP_NOWARN); | ||
474 | } | ||
475 | if (!p) { | ||
476 | __synth_free_pages(emu, first_page, page - 1); | ||
477 | return -ENOMEM; | ||
458 | } | 478 | } |
459 | emu->page_addr_table[page] = dmab.addr; | 479 | emu->page_addr_table[page] = page_to_phys(p); |
460 | emu->page_ptr_table[page] = dmab.area; | 480 | emu->page_ptr_table[page] = page_address(p); |
461 | } | 481 | } |
462 | return 0; | 482 | return 0; |
463 | |||
464 | __fail: | ||
465 | /* release allocated pages */ | ||
466 | last_page = page - 1; | ||
467 | for (page = first_page; page <= last_page; page++) { | ||
468 | dmab.area = emu->page_ptr_table[page]; | ||
469 | dmab.addr = emu->page_addr_table[page]; | ||
470 | dmab.bytes = PAGE_SIZE; | ||
471 | snd_dma_free_pages(&dmab); | ||
472 | emu->page_addr_table[page] = 0; | ||
473 | emu->page_ptr_table[page] = NULL; | ||
474 | } | ||
475 | |||
476 | return -ENOMEM; | ||
477 | } | 483 | } |
478 | 484 | ||
479 | /* | 485 | /* |
@@ -481,23 +487,10 @@ __fail: | |||
481 | */ | 487 | */ |
482 | static int synth_free_pages(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk) | 488 | static int synth_free_pages(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk) |
483 | { | 489 | { |
484 | int page, first_page, last_page; | 490 | int first_page, last_page; |
485 | struct snd_dma_buffer dmab; | ||
486 | 491 | ||
487 | get_single_page_range(emu->memhdr, blk, &first_page, &last_page); | 492 | get_single_page_range(emu->memhdr, blk, &first_page, &last_page); |
488 | dmab.dev.type = SNDRV_DMA_TYPE_DEV; | 493 | __synth_free_pages(emu, first_page, last_page); |
489 | dmab.dev.dev = snd_dma_pci_data(emu->pci); | ||
490 | for (page = first_page; page <= last_page; page++) { | ||
491 | if (emu->page_ptr_table[page] == NULL) | ||
492 | continue; | ||
493 | dmab.area = emu->page_ptr_table[page]; | ||
494 | dmab.addr = emu->page_addr_table[page]; | ||
495 | dmab.bytes = PAGE_SIZE; | ||
496 | snd_dma_free_pages(&dmab); | ||
497 | emu->page_addr_table[page] = 0; | ||
498 | emu->page_ptr_table[page] = NULL; | ||
499 | } | ||
500 | |||
501 | return 0; | 494 | return 0; |
502 | } | 495 | } |
503 | 496 | ||
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index a6be6e3e8716..d2e1093f8e97 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -2335,7 +2335,7 @@ int snd_hda_check_board_config(struct hda_codec *codec, | |||
2335 | if (!tbl) | 2335 | if (!tbl) |
2336 | return -1; | 2336 | return -1; |
2337 | if (tbl->value >= 0 && tbl->value < num_configs) { | 2337 | if (tbl->value >= 0 && tbl->value < num_configs) { |
2338 | #ifdef CONFIG_SND_DEBUG_DETECT | 2338 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
2339 | char tmp[10]; | 2339 | char tmp[10]; |
2340 | const char *model = NULL; | 2340 | const char *model = NULL; |
2341 | if (models) | 2341 | if (models) |
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index dcd390b2bbaa..efc682888b31 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h | |||
@@ -78,7 +78,7 @@ enum { | |||
78 | #define AC_VERB_GET_BEEP_CONTROL 0x0f0a | 78 | #define AC_VERB_GET_BEEP_CONTROL 0x0f0a |
79 | #define AC_VERB_GET_EAPD_BTLENABLE 0x0f0c | 79 | #define AC_VERB_GET_EAPD_BTLENABLE 0x0f0c |
80 | #define AC_VERB_GET_DIGI_CONVERT_1 0x0f0d | 80 | #define AC_VERB_GET_DIGI_CONVERT_1 0x0f0d |
81 | #define AC_VERB_GET_DIGI_CONVERT_2 0x0f0e | 81 | #define AC_VERB_GET_DIGI_CONVERT_2 0x0f0e /* unused */ |
82 | #define AC_VERB_GET_VOLUME_KNOB_CONTROL 0x0f0f | 82 | #define AC_VERB_GET_VOLUME_KNOB_CONTROL 0x0f0f |
83 | /* f10-f1a: GPIO */ | 83 | /* f10-f1a: GPIO */ |
84 | #define AC_VERB_GET_GPIO_DATA 0x0f15 | 84 | #define AC_VERB_GET_GPIO_DATA 0x0f15 |
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 2177d9af5334..6e18a422d993 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c | |||
@@ -88,7 +88,7 @@ static int hda_hwdep_ioctl_compat(struct snd_hwdep *hw, struct file *file, | |||
88 | 88 | ||
89 | static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file) | 89 | static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file) |
90 | { | 90 | { |
91 | #ifndef CONFIG_SND_DEBUG_DETECT | 91 | #ifndef CONFIG_SND_DEBUG_VERBOSE |
92 | if (!capable(CAP_SYS_RAWIO)) | 92 | if (!capable(CAP_SYS_RAWIO)) |
93 | return -EACCES; | 93 | return -EACCES; |
94 | #endif | 94 | #endif |
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index b3a618eb42cd..16715a68ba5e 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -55,6 +55,7 @@ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | |||
55 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | 55 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; |
56 | static char *model[SNDRV_CARDS]; | 56 | static char *model[SNDRV_CARDS]; |
57 | static int position_fix[SNDRV_CARDS]; | 57 | static int position_fix[SNDRV_CARDS]; |
58 | static int bdl_pos_adj[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; | ||
58 | static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; | 59 | static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; |
59 | static int single_cmd; | 60 | static int single_cmd; |
60 | static int enable_msi; | 61 | static int enable_msi; |
@@ -69,7 +70,9 @@ module_param_array(model, charp, NULL, 0444); | |||
69 | MODULE_PARM_DESC(model, "Use the given board model."); | 70 | MODULE_PARM_DESC(model, "Use the given board model."); |
70 | module_param_array(position_fix, int, NULL, 0444); | 71 | module_param_array(position_fix, int, NULL, 0444); |
71 | MODULE_PARM_DESC(position_fix, "Fix DMA pointer " | 72 | MODULE_PARM_DESC(position_fix, "Fix DMA pointer " |
72 | "(0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)."); | 73 | "(0 = auto, 1 = none, 2 = POSBUF)."); |
74 | module_param_array(bdl_pos_adj, int, NULL, 0644); | ||
75 | MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset."); | ||
73 | module_param_array(probe_mask, int, NULL, 0444); | 76 | module_param_array(probe_mask, int, NULL, 0444); |
74 | MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1)."); | 77 | MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1)."); |
75 | module_param(single_cmd, bool, 0444); | 78 | module_param(single_cmd, bool, 0444); |
@@ -197,6 +200,10 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; | |||
197 | #define ATIHDMI_NUM_CAPTURE 0 | 200 | #define ATIHDMI_NUM_CAPTURE 0 |
198 | #define ATIHDMI_NUM_PLAYBACK 1 | 201 | #define ATIHDMI_NUM_PLAYBACK 1 |
199 | 202 | ||
203 | /* TERA has 4 playback and 3 capture */ | ||
204 | #define TERA_NUM_CAPTURE 3 | ||
205 | #define TERA_NUM_PLAYBACK 4 | ||
206 | |||
200 | /* this number is statically defined for simplicity */ | 207 | /* this number is statically defined for simplicity */ |
201 | #define MAX_AZX_DEV 16 | 208 | #define MAX_AZX_DEV 16 |
202 | 209 | ||
@@ -259,9 +266,8 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; | |||
259 | /* position fix mode */ | 266 | /* position fix mode */ |
260 | enum { | 267 | enum { |
261 | POS_FIX_AUTO, | 268 | POS_FIX_AUTO, |
262 | POS_FIX_NONE, | 269 | POS_FIX_LPIB, |
263 | POS_FIX_POSBUF, | 270 | POS_FIX_POSBUF, |
264 | POS_FIX_FIFO, | ||
265 | }; | 271 | }; |
266 | 272 | ||
267 | /* Defines for ATI HD Audio support in SB450 south bridge */ | 273 | /* Defines for ATI HD Audio support in SB450 south bridge */ |
@@ -285,6 +291,7 @@ struct azx_dev { | |||
285 | u32 *posbuf; /* position buffer pointer */ | 291 | u32 *posbuf; /* position buffer pointer */ |
286 | 292 | ||
287 | unsigned int bufsize; /* size of the play buffer in bytes */ | 293 | unsigned int bufsize; /* size of the play buffer in bytes */ |
294 | unsigned int period_bytes; /* size of the period in bytes */ | ||
288 | unsigned int frags; /* number for period in the play buffer */ | 295 | unsigned int frags; /* number for period in the play buffer */ |
289 | unsigned int fifo_size; /* FIFO size */ | 296 | unsigned int fifo_size; /* FIFO size */ |
290 | 297 | ||
@@ -301,11 +308,11 @@ struct azx_dev { | |||
301 | */ | 308 | */ |
302 | unsigned char stream_tag; /* assigned stream */ | 309 | unsigned char stream_tag; /* assigned stream */ |
303 | unsigned char index; /* stream index */ | 310 | unsigned char index; /* stream index */ |
304 | /* for sanity check of position buffer */ | ||
305 | unsigned int period_intr; | ||
306 | 311 | ||
307 | unsigned int opened :1; | 312 | unsigned int opened :1; |
308 | unsigned int running :1; | 313 | unsigned int running :1; |
314 | unsigned int irq_pending :1; | ||
315 | unsigned int irq_ignore :1; | ||
309 | }; | 316 | }; |
310 | 317 | ||
311 | /* CORB/RIRB */ | 318 | /* CORB/RIRB */ |
@@ -323,6 +330,7 @@ struct azx_rb { | |||
323 | struct azx { | 330 | struct azx { |
324 | struct snd_card *card; | 331 | struct snd_card *card; |
325 | struct pci_dev *pci; | 332 | struct pci_dev *pci; |
333 | int dev_index; | ||
326 | 334 | ||
327 | /* chip type specific */ | 335 | /* chip type specific */ |
328 | int driver_type; | 336 | int driver_type; |
@@ -366,9 +374,13 @@ struct azx { | |||
366 | unsigned int single_cmd :1; | 374 | unsigned int single_cmd :1; |
367 | unsigned int polling_mode :1; | 375 | unsigned int polling_mode :1; |
368 | unsigned int msi :1; | 376 | unsigned int msi :1; |
377 | unsigned int irq_pending_warned :1; | ||
369 | 378 | ||
370 | /* for debugging */ | 379 | /* for debugging */ |
371 | unsigned int last_cmd; /* last issued command (to sync) */ | 380 | unsigned int last_cmd; /* last issued command (to sync) */ |
381 | |||
382 | /* for pending irqs */ | ||
383 | struct work_struct irq_pending_work; | ||
372 | }; | 384 | }; |
373 | 385 | ||
374 | /* driver types */ | 386 | /* driver types */ |
@@ -381,6 +393,7 @@ enum { | |||
381 | AZX_DRIVER_SIS, | 393 | AZX_DRIVER_SIS, |
382 | AZX_DRIVER_ULI, | 394 | AZX_DRIVER_ULI, |
383 | AZX_DRIVER_NVIDIA, | 395 | AZX_DRIVER_NVIDIA, |
396 | AZX_DRIVER_TERA, | ||
384 | }; | 397 | }; |
385 | 398 | ||
386 | static char *driver_short_names[] __devinitdata = { | 399 | static char *driver_short_names[] __devinitdata = { |
@@ -392,6 +405,7 @@ static char *driver_short_names[] __devinitdata = { | |||
392 | [AZX_DRIVER_SIS] = "HDA SIS966", | 405 | [AZX_DRIVER_SIS] = "HDA SIS966", |
393 | [AZX_DRIVER_ULI] = "HDA ULI M5461", | 406 | [AZX_DRIVER_ULI] = "HDA ULI M5461", |
394 | [AZX_DRIVER_NVIDIA] = "HDA NVidia", | 407 | [AZX_DRIVER_NVIDIA] = "HDA NVidia", |
408 | [AZX_DRIVER_TERA] = "HDA Teradici", | ||
395 | }; | 409 | }; |
396 | 410 | ||
397 | /* | 411 | /* |
@@ -426,11 +440,6 @@ static char *driver_short_names[] __devinitdata = { | |||
426 | /* for pcm support */ | 440 | /* for pcm support */ |
427 | #define get_azx_dev(substream) (substream->runtime->private_data) | 441 | #define get_azx_dev(substream) (substream->runtime->private_data) |
428 | 442 | ||
429 | /* Get the upper 32bit of the given dma_addr_t | ||
430 | * Compiler should optimize and eliminate the code if dma_addr_t is 32bit | ||
431 | */ | ||
432 | #define upper_32bit(addr) (sizeof(addr) > 4 ? (u32)((addr) >> 32) : (u32)0) | ||
433 | |||
434 | static int azx_acquire_irq(struct azx *chip, int do_disconnect); | 443 | static int azx_acquire_irq(struct azx *chip, int do_disconnect); |
435 | 444 | ||
436 | /* | 445 | /* |
@@ -461,7 +470,7 @@ static void azx_init_cmd_io(struct azx *chip) | |||
461 | chip->corb.addr = chip->rb.addr; | 470 | chip->corb.addr = chip->rb.addr; |
462 | chip->corb.buf = (u32 *)chip->rb.area; | 471 | chip->corb.buf = (u32 *)chip->rb.area; |
463 | azx_writel(chip, CORBLBASE, (u32)chip->corb.addr); | 472 | azx_writel(chip, CORBLBASE, (u32)chip->corb.addr); |
464 | azx_writel(chip, CORBUBASE, upper_32bit(chip->corb.addr)); | 473 | azx_writel(chip, CORBUBASE, upper_32_bits(chip->corb.addr)); |
465 | 474 | ||
466 | /* set the corb size to 256 entries (ULI requires explicitly) */ | 475 | /* set the corb size to 256 entries (ULI requires explicitly) */ |
467 | azx_writeb(chip, CORBSIZE, 0x02); | 476 | azx_writeb(chip, CORBSIZE, 0x02); |
@@ -476,7 +485,7 @@ static void azx_init_cmd_io(struct azx *chip) | |||
476 | chip->rirb.addr = chip->rb.addr + 2048; | 485 | chip->rirb.addr = chip->rb.addr + 2048; |
477 | chip->rirb.buf = (u32 *)(chip->rb.area + 2048); | 486 | chip->rirb.buf = (u32 *)(chip->rb.area + 2048); |
478 | azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr); | 487 | azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr); |
479 | azx_writel(chip, RIRBUBASE, upper_32bit(chip->rirb.addr)); | 488 | azx_writel(chip, RIRBUBASE, upper_32_bits(chip->rirb.addr)); |
480 | 489 | ||
481 | /* set the rirb size to 256 entries (ULI requires explicitly) */ | 490 | /* set the rirb size to 256 entries (ULI requires explicitly) */ |
482 | azx_writeb(chip, RIRBSIZE, 0x02); | 491 | azx_writeb(chip, RIRBSIZE, 0x02); |
@@ -847,7 +856,7 @@ static void azx_init_chip(struct azx *chip) | |||
847 | 856 | ||
848 | /* program the position buffer */ | 857 | /* program the position buffer */ |
849 | azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); | 858 | azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); |
850 | azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr)); | 859 | azx_writel(chip, DPUBASE, upper_32_bits(chip->posbuf.addr)); |
851 | 860 | ||
852 | chip->initialized = 1; | 861 | chip->initialized = 1; |
853 | } | 862 | } |
@@ -908,6 +917,8 @@ static void azx_init_pci(struct azx *chip) | |||
908 | } | 917 | } |
909 | 918 | ||
910 | 919 | ||
920 | static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev); | ||
921 | |||
911 | /* | 922 | /* |
912 | * interrupt handler | 923 | * interrupt handler |
913 | */ | 924 | */ |
@@ -930,11 +941,23 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id) | |||
930 | azx_dev = &chip->azx_dev[i]; | 941 | azx_dev = &chip->azx_dev[i]; |
931 | if (status & azx_dev->sd_int_sta_mask) { | 942 | if (status & azx_dev->sd_int_sta_mask) { |
932 | azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); | 943 | azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); |
933 | if (azx_dev->substream && azx_dev->running) { | 944 | if (!azx_dev->substream || !azx_dev->running) |
934 | azx_dev->period_intr++; | 945 | continue; |
946 | /* ignore the first dummy IRQ (due to pos_adj) */ | ||
947 | if (azx_dev->irq_ignore) { | ||
948 | azx_dev->irq_ignore = 0; | ||
949 | continue; | ||
950 | } | ||
951 | /* check whether this IRQ is really acceptable */ | ||
952 | if (azx_position_ok(chip, azx_dev)) { | ||
953 | azx_dev->irq_pending = 0; | ||
935 | spin_unlock(&chip->reg_lock); | 954 | spin_unlock(&chip->reg_lock); |
936 | snd_pcm_period_elapsed(azx_dev->substream); | 955 | snd_pcm_period_elapsed(azx_dev->substream); |
937 | spin_lock(&chip->reg_lock); | 956 | spin_lock(&chip->reg_lock); |
957 | } else { | ||
958 | /* bogus IRQ, process it later */ | ||
959 | azx_dev->irq_pending = 1; | ||
960 | schedule_work(&chip->irq_pending_work); | ||
938 | } | 961 | } |
939 | } | 962 | } |
940 | } | 963 | } |
@@ -959,59 +982,107 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id) | |||
959 | 982 | ||
960 | 983 | ||
961 | /* | 984 | /* |
985 | * set up a BDL entry | ||
986 | */ | ||
987 | static int setup_bdle(struct snd_pcm_substream *substream, | ||
988 | struct azx_dev *azx_dev, u32 **bdlp, | ||
989 | int ofs, int size, int with_ioc) | ||
990 | { | ||
991 | struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream); | ||
992 | u32 *bdl = *bdlp; | ||
993 | |||
994 | while (size > 0) { | ||
995 | dma_addr_t addr; | ||
996 | int chunk; | ||
997 | |||
998 | if (azx_dev->frags >= AZX_MAX_BDL_ENTRIES) | ||
999 | return -EINVAL; | ||
1000 | |||
1001 | addr = snd_pcm_sgbuf_get_addr(sgbuf, ofs); | ||
1002 | /* program the address field of the BDL entry */ | ||
1003 | bdl[0] = cpu_to_le32((u32)addr); | ||
1004 | bdl[1] = cpu_to_le32(upper_32_bits(addr)); | ||
1005 | /* program the size field of the BDL entry */ | ||
1006 | chunk = PAGE_SIZE - (ofs % PAGE_SIZE); | ||
1007 | if (size < chunk) | ||
1008 | chunk = size; | ||
1009 | bdl[2] = cpu_to_le32(chunk); | ||
1010 | /* program the IOC to enable interrupt | ||
1011 | * only when the whole fragment is processed | ||
1012 | */ | ||
1013 | size -= chunk; | ||
1014 | bdl[3] = (size || !with_ioc) ? 0 : cpu_to_le32(0x01); | ||
1015 | bdl += 4; | ||
1016 | azx_dev->frags++; | ||
1017 | ofs += chunk; | ||
1018 | } | ||
1019 | *bdlp = bdl; | ||
1020 | return ofs; | ||
1021 | } | ||
1022 | |||
1023 | /* | ||
962 | * set up BDL entries | 1024 | * set up BDL entries |
963 | */ | 1025 | */ |
964 | static int azx_setup_periods(struct snd_pcm_substream *substream, | 1026 | static int azx_setup_periods(struct azx *chip, |
1027 | struct snd_pcm_substream *substream, | ||
965 | struct azx_dev *azx_dev) | 1028 | struct azx_dev *azx_dev) |
966 | { | 1029 | { |
967 | struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream); | ||
968 | u32 *bdl; | 1030 | u32 *bdl; |
969 | int i, ofs, periods, period_bytes; | 1031 | int i, ofs, periods, period_bytes; |
1032 | int pos_adj; | ||
970 | 1033 | ||
971 | /* reset BDL address */ | 1034 | /* reset BDL address */ |
972 | azx_sd_writel(azx_dev, SD_BDLPL, 0); | 1035 | azx_sd_writel(azx_dev, SD_BDLPL, 0); |
973 | azx_sd_writel(azx_dev, SD_BDLPU, 0); | 1036 | azx_sd_writel(azx_dev, SD_BDLPU, 0); |
974 | 1037 | ||
975 | period_bytes = snd_pcm_lib_period_bytes(substream); | 1038 | period_bytes = snd_pcm_lib_period_bytes(substream); |
1039 | azx_dev->period_bytes = period_bytes; | ||
976 | periods = azx_dev->bufsize / period_bytes; | 1040 | periods = azx_dev->bufsize / period_bytes; |
977 | 1041 | ||
978 | /* program the initial BDL entries */ | 1042 | /* program the initial BDL entries */ |
979 | bdl = (u32 *)azx_dev->bdl.area; | 1043 | bdl = (u32 *)azx_dev->bdl.area; |
980 | ofs = 0; | 1044 | ofs = 0; |
981 | azx_dev->frags = 0; | 1045 | azx_dev->frags = 0; |
982 | for (i = 0; i < periods; i++) { | 1046 | azx_dev->irq_ignore = 0; |
983 | int size, rest; | 1047 | pos_adj = bdl_pos_adj[chip->dev_index]; |
984 | if (i >= AZX_MAX_BDL_ENTRIES) { | 1048 | if (pos_adj > 0) { |
985 | snd_printk(KERN_ERR "Too many BDL entries: " | 1049 | struct snd_pcm_runtime *runtime = substream->runtime; |
986 | "buffer=%d, period=%d\n", | 1050 | pos_adj = (pos_adj * runtime->rate + 47999) / 48000; |
987 | azx_dev->bufsize, period_bytes); | 1051 | if (!pos_adj) |
988 | /* reset */ | 1052 | pos_adj = 1; |
989 | azx_sd_writel(azx_dev, SD_BDLPL, 0); | 1053 | pos_adj = frames_to_bytes(runtime, pos_adj); |
990 | azx_sd_writel(azx_dev, SD_BDLPU, 0); | 1054 | if (pos_adj >= period_bytes) { |
991 | return -EINVAL; | 1055 | snd_printk(KERN_WARNING "Too big adjustment %d\n", |
1056 | bdl_pos_adj[chip->dev_index]); | ||
1057 | pos_adj = 0; | ||
1058 | } else { | ||
1059 | ofs = setup_bdle(substream, azx_dev, | ||
1060 | &bdl, ofs, pos_adj, 1); | ||
1061 | if (ofs < 0) | ||
1062 | goto error; | ||
1063 | azx_dev->irq_ignore = 1; | ||
992 | } | 1064 | } |
993 | rest = period_bytes; | 1065 | } else |
994 | do { | 1066 | pos_adj = 0; |
995 | dma_addr_t addr = snd_pcm_sgbuf_get_addr(sgbuf, ofs); | 1067 | for (i = 0; i < periods; i++) { |
996 | /* program the address field of the BDL entry */ | 1068 | if (i == periods - 1 && pos_adj) |
997 | bdl[0] = cpu_to_le32((u32)addr); | 1069 | ofs = setup_bdle(substream, azx_dev, &bdl, ofs, |
998 | bdl[1] = cpu_to_le32(upper_32bit(addr)); | 1070 | period_bytes - pos_adj, 0); |
999 | /* program the size field of the BDL entry */ | 1071 | else |
1000 | size = PAGE_SIZE - (ofs % PAGE_SIZE); | 1072 | ofs = setup_bdle(substream, azx_dev, &bdl, ofs, |
1001 | if (rest < size) | 1073 | period_bytes, 1); |
1002 | size = rest; | 1074 | if (ofs < 0) |
1003 | bdl[2] = cpu_to_le32(size); | 1075 | goto error; |
1004 | /* program the IOC to enable interrupt | ||
1005 | * only when the whole fragment is processed | ||
1006 | */ | ||
1007 | rest -= size; | ||
1008 | bdl[3] = rest ? 0 : cpu_to_le32(0x01); | ||
1009 | bdl += 4; | ||
1010 | azx_dev->frags++; | ||
1011 | ofs += size; | ||
1012 | } while (rest > 0); | ||
1013 | } | 1076 | } |
1014 | return 0; | 1077 | return 0; |
1078 | |||
1079 | error: | ||
1080 | snd_printk(KERN_ERR "Too many BDL entries: buffer=%d, period=%d\n", | ||
1081 | azx_dev->bufsize, period_bytes); | ||
1082 | /* reset */ | ||
1083 | azx_sd_writel(azx_dev, SD_BDLPL, 0); | ||
1084 | azx_sd_writel(azx_dev, SD_BDLPU, 0); | ||
1085 | return -EINVAL; | ||
1015 | } | 1086 | } |
1016 | 1087 | ||
1017 | /* | 1088 | /* |
@@ -1062,7 +1133,7 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) | |||
1062 | /* lower BDL address */ | 1133 | /* lower BDL address */ |
1063 | azx_sd_writel(azx_dev, SD_BDLPL, (u32)azx_dev->bdl.addr); | 1134 | azx_sd_writel(azx_dev, SD_BDLPL, (u32)azx_dev->bdl.addr); |
1064 | /* upper BDL address */ | 1135 | /* upper BDL address */ |
1065 | azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl.addr)); | 1136 | azx_sd_writel(azx_dev, SD_BDLPU, upper_32_bits(azx_dev->bdl.addr)); |
1066 | 1137 | ||
1067 | /* enable the position buffer */ | 1138 | /* enable the position buffer */ |
1068 | if (chip->position_fix == POS_FIX_POSBUF || | 1139 | if (chip->position_fix == POS_FIX_POSBUF || |
@@ -1085,7 +1156,7 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) | |||
1085 | */ | 1156 | */ |
1086 | 1157 | ||
1087 | static unsigned int azx_max_codecs[] __devinitdata = { | 1158 | static unsigned int azx_max_codecs[] __devinitdata = { |
1088 | [AZX_DRIVER_ICH] = 3, | 1159 | [AZX_DRIVER_ICH] = 4, /* Some ICH9 boards use SD3 */ |
1089 | [AZX_DRIVER_SCH] = 3, | 1160 | [AZX_DRIVER_SCH] = 3, |
1090 | [AZX_DRIVER_ATI] = 4, | 1161 | [AZX_DRIVER_ATI] = 4, |
1091 | [AZX_DRIVER_ATIHDMI] = 4, | 1162 | [AZX_DRIVER_ATIHDMI] = 4, |
@@ -1093,6 +1164,7 @@ static unsigned int azx_max_codecs[] __devinitdata = { | |||
1093 | [AZX_DRIVER_SIS] = 3, /* FIXME: correct? */ | 1164 | [AZX_DRIVER_SIS] = 3, /* FIXME: correct? */ |
1094 | [AZX_DRIVER_ULI] = 3, /* FIXME: correct? */ | 1165 | [AZX_DRIVER_ULI] = 3, /* FIXME: correct? */ |
1095 | [AZX_DRIVER_NVIDIA] = 3, /* FIXME: correct? */ | 1166 | [AZX_DRIVER_NVIDIA] = 3, /* FIXME: correct? */ |
1167 | [AZX_DRIVER_TERA] = 1, | ||
1096 | }; | 1168 | }; |
1097 | 1169 | ||
1098 | static int __devinit azx_codec_create(struct azx *chip, const char *model, | 1170 | static int __devinit azx_codec_create(struct azx *chip, const char *model, |
@@ -1316,7 +1388,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) | |||
1316 | 1388 | ||
1317 | snd_printdd("azx_pcm_prepare: bufsize=0x%x, format=0x%x\n", | 1389 | snd_printdd("azx_pcm_prepare: bufsize=0x%x, format=0x%x\n", |
1318 | azx_dev->bufsize, azx_dev->format_val); | 1390 | azx_dev->bufsize, azx_dev->format_val); |
1319 | if (azx_setup_periods(substream, azx_dev) < 0) | 1391 | if (azx_setup_periods(chip, substream, azx_dev) < 0) |
1320 | return -EINVAL; | 1392 | return -EINVAL; |
1321 | azx_setup_controller(chip, azx_dev); | 1393 | azx_setup_controller(chip, azx_dev); |
1322 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 1394 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
@@ -1421,35 +1493,113 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
1421 | return 0; | 1493 | return 0; |
1422 | } | 1494 | } |
1423 | 1495 | ||
1424 | static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream) | 1496 | static unsigned int azx_get_position(struct azx *chip, |
1497 | struct azx_dev *azx_dev) | ||
1425 | { | 1498 | { |
1426 | struct azx_pcm *apcm = snd_pcm_substream_chip(substream); | ||
1427 | struct azx *chip = apcm->chip; | ||
1428 | struct azx_dev *azx_dev = get_azx_dev(substream); | ||
1429 | unsigned int pos; | 1499 | unsigned int pos; |
1430 | 1500 | ||
1431 | if (chip->position_fix == POS_FIX_POSBUF || | 1501 | if (chip->position_fix == POS_FIX_POSBUF || |
1432 | chip->position_fix == POS_FIX_AUTO) { | 1502 | chip->position_fix == POS_FIX_AUTO) { |
1433 | /* use the position buffer */ | 1503 | /* use the position buffer */ |
1434 | pos = le32_to_cpu(*azx_dev->posbuf); | 1504 | pos = le32_to_cpu(*azx_dev->posbuf); |
1435 | if (chip->position_fix == POS_FIX_AUTO && | ||
1436 | azx_dev->period_intr == 1 && !pos) { | ||
1437 | printk(KERN_WARNING | ||
1438 | "hda-intel: Invalid position buffer, " | ||
1439 | "using LPIB read method instead.\n"); | ||
1440 | chip->position_fix = POS_FIX_NONE; | ||
1441 | goto read_lpib; | ||
1442 | } | ||
1443 | } else { | 1505 | } else { |
1444 | read_lpib: | ||
1445 | /* read LPIB */ | 1506 | /* read LPIB */ |
1446 | pos = azx_sd_readl(azx_dev, SD_LPIB); | 1507 | pos = azx_sd_readl(azx_dev, SD_LPIB); |
1447 | if (chip->position_fix == POS_FIX_FIFO) | ||
1448 | pos += azx_dev->fifo_size; | ||
1449 | } | 1508 | } |
1450 | if (pos >= azx_dev->bufsize) | 1509 | if (pos >= azx_dev->bufsize) |
1451 | pos = 0; | 1510 | pos = 0; |
1452 | return bytes_to_frames(substream->runtime, pos); | 1511 | return pos; |
1512 | } | ||
1513 | |||
1514 | static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream) | ||
1515 | { | ||
1516 | struct azx_pcm *apcm = snd_pcm_substream_chip(substream); | ||
1517 | struct azx *chip = apcm->chip; | ||
1518 | struct azx_dev *azx_dev = get_azx_dev(substream); | ||
1519 | return bytes_to_frames(substream->runtime, | ||
1520 | azx_get_position(chip, azx_dev)); | ||
1521 | } | ||
1522 | |||
1523 | /* | ||
1524 | * Check whether the current DMA position is acceptable for updating | ||
1525 | * periods. Returns non-zero if it's OK. | ||
1526 | * | ||
1527 | * Many HD-audio controllers appear pretty inaccurate about | ||
1528 | * the update-IRQ timing. The IRQ is issued before actually the | ||
1529 | * data is processed. So, we need to process it afterwords in a | ||
1530 | * workqueue. | ||
1531 | */ | ||
1532 | static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) | ||
1533 | { | ||
1534 | unsigned int pos; | ||
1535 | |||
1536 | pos = azx_get_position(chip, azx_dev); | ||
1537 | if (chip->position_fix == POS_FIX_AUTO) { | ||
1538 | if (!pos) { | ||
1539 | printk(KERN_WARNING | ||
1540 | "hda-intel: Invalid position buffer, " | ||
1541 | "using LPIB read method instead.\n"); | ||
1542 | chip->position_fix = POS_FIX_LPIB; | ||
1543 | pos = azx_get_position(chip, azx_dev); | ||
1544 | } else | ||
1545 | chip->position_fix = POS_FIX_POSBUF; | ||
1546 | } | ||
1547 | |||
1548 | if (pos % azx_dev->period_bytes > azx_dev->period_bytes / 2) | ||
1549 | return 0; /* NG - it's below the period boundary */ | ||
1550 | return 1; /* OK, it's fine */ | ||
1551 | } | ||
1552 | |||
1553 | /* | ||
1554 | * The work for pending PCM period updates. | ||
1555 | */ | ||
1556 | static void azx_irq_pending_work(struct work_struct *work) | ||
1557 | { | ||
1558 | struct azx *chip = container_of(work, struct azx, irq_pending_work); | ||
1559 | int i, pending; | ||
1560 | |||
1561 | if (!chip->irq_pending_warned) { | ||
1562 | printk(KERN_WARNING | ||
1563 | "hda-intel: IRQ timing workaround is activated " | ||
1564 | "for card #%d. Suggest a bigger bdl_pos_adj.\n", | ||
1565 | chip->card->number); | ||
1566 | chip->irq_pending_warned = 1; | ||
1567 | } | ||
1568 | |||
1569 | for (;;) { | ||
1570 | pending = 0; | ||
1571 | spin_lock_irq(&chip->reg_lock); | ||
1572 | for (i = 0; i < chip->num_streams; i++) { | ||
1573 | struct azx_dev *azx_dev = &chip->azx_dev[i]; | ||
1574 | if (!azx_dev->irq_pending || | ||
1575 | !azx_dev->substream || | ||
1576 | !azx_dev->running) | ||
1577 | continue; | ||
1578 | if (azx_position_ok(chip, azx_dev)) { | ||
1579 | azx_dev->irq_pending = 0; | ||
1580 | spin_unlock(&chip->reg_lock); | ||
1581 | snd_pcm_period_elapsed(azx_dev->substream); | ||
1582 | spin_lock(&chip->reg_lock); | ||
1583 | } else | ||
1584 | pending++; | ||
1585 | } | ||
1586 | spin_unlock_irq(&chip->reg_lock); | ||
1587 | if (!pending) | ||
1588 | return; | ||
1589 | cond_resched(); | ||
1590 | } | ||
1591 | } | ||
1592 | |||
1593 | /* clear irq_pending flags and assure no on-going workq */ | ||
1594 | static void azx_clear_irq_pending(struct azx *chip) | ||
1595 | { | ||
1596 | int i; | ||
1597 | |||
1598 | spin_lock_irq(&chip->reg_lock); | ||
1599 | for (i = 0; i < chip->num_streams; i++) | ||
1600 | chip->azx_dev[i].irq_pending = 0; | ||
1601 | spin_unlock_irq(&chip->reg_lock); | ||
1602 | flush_scheduled_work(); | ||
1453 | } | 1603 | } |
1454 | 1604 | ||
1455 | static struct snd_pcm_ops azx_pcm_ops = { | 1605 | static struct snd_pcm_ops azx_pcm_ops = { |
@@ -1676,6 +1826,7 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state) | |||
1676 | int i; | 1826 | int i; |
1677 | 1827 | ||
1678 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | 1828 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); |
1829 | azx_clear_irq_pending(chip); | ||
1679 | for (i = 0; i < AZX_MAX_PCMS; i++) | 1830 | for (i = 0; i < AZX_MAX_PCMS; i++) |
1680 | snd_pcm_suspend_all(chip->pcm[i]); | 1831 | snd_pcm_suspend_all(chip->pcm[i]); |
1681 | if (chip->initialized) | 1832 | if (chip->initialized) |
@@ -1732,6 +1883,7 @@ static int azx_free(struct azx *chip) | |||
1732 | int i; | 1883 | int i; |
1733 | 1884 | ||
1734 | if (chip->initialized) { | 1885 | if (chip->initialized) { |
1886 | azx_clear_irq_pending(chip); | ||
1735 | for (i = 0; i < chip->num_streams; i++) | 1887 | for (i = 0; i < chip->num_streams; i++) |
1736 | azx_stream_stop(chip, &chip->azx_dev[i]); | 1888 | azx_stream_stop(chip, &chip->azx_dev[i]); |
1737 | azx_stop_chip(chip); | 1889 | azx_stop_chip(chip); |
@@ -1770,9 +1922,9 @@ static int azx_dev_free(struct snd_device *device) | |||
1770 | * white/black-listing for position_fix | 1922 | * white/black-listing for position_fix |
1771 | */ | 1923 | */ |
1772 | static struct snd_pci_quirk position_fix_list[] __devinitdata = { | 1924 | static struct snd_pci_quirk position_fix_list[] __devinitdata = { |
1773 | SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_NONE), | 1925 | SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB), |
1774 | SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_NONE), | 1926 | SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB), |
1775 | SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_NONE), | 1927 | SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB), |
1776 | {} | 1928 | {} |
1777 | }; | 1929 | }; |
1778 | 1930 | ||
@@ -1857,12 +2009,25 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | |||
1857 | chip->irq = -1; | 2009 | chip->irq = -1; |
1858 | chip->driver_type = driver_type; | 2010 | chip->driver_type = driver_type; |
1859 | chip->msi = enable_msi; | 2011 | chip->msi = enable_msi; |
2012 | chip->dev_index = dev; | ||
2013 | INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work); | ||
1860 | 2014 | ||
1861 | chip->position_fix = check_position_fix(chip, position_fix[dev]); | 2015 | chip->position_fix = check_position_fix(chip, position_fix[dev]); |
1862 | check_probe_mask(chip, dev); | 2016 | check_probe_mask(chip, dev); |
1863 | 2017 | ||
1864 | chip->single_cmd = single_cmd; | 2018 | chip->single_cmd = single_cmd; |
1865 | 2019 | ||
2020 | if (bdl_pos_adj[dev] < 0) { | ||
2021 | switch (chip->driver_type) { | ||
2022 | case AZX_DRIVER_ICH: | ||
2023 | bdl_pos_adj[dev] = 1; | ||
2024 | break; | ||
2025 | default: | ||
2026 | bdl_pos_adj[dev] = 32; | ||
2027 | break; | ||
2028 | } | ||
2029 | } | ||
2030 | |||
1866 | #if BITS_PER_LONG != 64 | 2031 | #if BITS_PER_LONG != 64 |
1867 | /* Fix up base address on ULI M5461 */ | 2032 | /* Fix up base address on ULI M5461 */ |
1868 | if (chip->driver_type == AZX_DRIVER_ULI) { | 2033 | if (chip->driver_type == AZX_DRIVER_ULI) { |
@@ -2089,6 +2254,7 @@ static struct pci_device_id azx_ids[] = { | |||
2089 | { PCI_DEVICE(0x8086, 0x27d8), .driver_data = AZX_DRIVER_ICH }, | 2254 | { PCI_DEVICE(0x8086, 0x27d8), .driver_data = AZX_DRIVER_ICH }, |
2090 | { PCI_DEVICE(0x8086, 0x269a), .driver_data = AZX_DRIVER_ICH }, | 2255 | { PCI_DEVICE(0x8086, 0x269a), .driver_data = AZX_DRIVER_ICH }, |
2091 | { PCI_DEVICE(0x8086, 0x284b), .driver_data = AZX_DRIVER_ICH }, | 2256 | { PCI_DEVICE(0x8086, 0x284b), .driver_data = AZX_DRIVER_ICH }, |
2257 | { PCI_DEVICE(0x8086, 0x2911), .driver_data = AZX_DRIVER_ICH }, | ||
2092 | { PCI_DEVICE(0x8086, 0x293e), .driver_data = AZX_DRIVER_ICH }, | 2258 | { PCI_DEVICE(0x8086, 0x293e), .driver_data = AZX_DRIVER_ICH }, |
2093 | { PCI_DEVICE(0x8086, 0x293f), .driver_data = AZX_DRIVER_ICH }, | 2259 | { PCI_DEVICE(0x8086, 0x293f), .driver_data = AZX_DRIVER_ICH }, |
2094 | { PCI_DEVICE(0x8086, 0x3a3e), .driver_data = AZX_DRIVER_ICH }, | 2260 | { PCI_DEVICE(0x8086, 0x3a3e), .driver_data = AZX_DRIVER_ICH }, |
@@ -2141,6 +2307,8 @@ static struct pci_device_id azx_ids[] = { | |||
2141 | { PCI_DEVICE(0x10de, 0x0bd5), .driver_data = AZX_DRIVER_NVIDIA }, | 2307 | { PCI_DEVICE(0x10de, 0x0bd5), .driver_data = AZX_DRIVER_NVIDIA }, |
2142 | { PCI_DEVICE(0x10de, 0x0bd6), .driver_data = AZX_DRIVER_NVIDIA }, | 2308 | { PCI_DEVICE(0x10de, 0x0bd6), .driver_data = AZX_DRIVER_NVIDIA }, |
2143 | { PCI_DEVICE(0x10de, 0x0bd7), .driver_data = AZX_DRIVER_NVIDIA }, | 2309 | { PCI_DEVICE(0x10de, 0x0bd7), .driver_data = AZX_DRIVER_NVIDIA }, |
2310 | /* Teradici */ | ||
2311 | { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA }, | ||
2144 | { 0, } | 2312 | { 0, } |
2145 | }; | 2313 | }; |
2146 | MODULE_DEVICE_TABLE(pci, azx_ids); | 2314 | MODULE_DEVICE_TABLE(pci, azx_ids); |
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 5633f77f8f3b..1e5aff5c48d1 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c | |||
@@ -366,8 +366,6 @@ static void print_digital_conv(struct snd_info_buffer *buffer, | |||
366 | { | 366 | { |
367 | unsigned int digi1 = snd_hda_codec_read(codec, nid, 0, | 367 | unsigned int digi1 = snd_hda_codec_read(codec, nid, 0, |
368 | AC_VERB_GET_DIGI_CONVERT_1, 0); | 368 | AC_VERB_GET_DIGI_CONVERT_1, 0); |
369 | unsigned int digi2 = snd_hda_codec_read(codec, nid, 0, | ||
370 | AC_VERB_GET_DIGI_CONVERT_2, 0); | ||
371 | snd_iprintf(buffer, " Digital:"); | 369 | snd_iprintf(buffer, " Digital:"); |
372 | if (digi1 & AC_DIG1_ENABLE) | 370 | if (digi1 & AC_DIG1_ENABLE) |
373 | snd_iprintf(buffer, " Enabled"); | 371 | snd_iprintf(buffer, " Enabled"); |
@@ -386,7 +384,8 @@ static void print_digital_conv(struct snd_info_buffer *buffer, | |||
386 | if (digi1 & AC_DIG1_LEVEL) | 384 | if (digi1 & AC_DIG1_LEVEL) |
387 | snd_iprintf(buffer, " GenLevel"); | 385 | snd_iprintf(buffer, " GenLevel"); |
388 | snd_iprintf(buffer, "\n"); | 386 | snd_iprintf(buffer, "\n"); |
389 | snd_iprintf(buffer, " Digital category: 0x%x\n", digi2 & AC_DIG2_CC); | 387 | snd_iprintf(buffer, " Digital category: 0x%x\n", |
388 | (digi1 >> 8) & AC_DIG2_CC); | ||
390 | } | 389 | } |
391 | 390 | ||
392 | static const char *get_pwr_state(u32 state) | 391 | static const char *get_pwr_state(u32 state) |
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index a99e86d74278..e8003d99f0bf 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
@@ -23,7 +23,6 @@ | |||
23 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #include <linux/pci.h> | 25 | #include <linux/pci.h> |
26 | #include <linux/mutex.h> | ||
27 | 26 | ||
28 | #include <sound/core.h> | 27 | #include <sound/core.h> |
29 | #include "hda_codec.h" | 28 | #include "hda_codec.h" |
@@ -64,7 +63,6 @@ struct ad198x_spec { | |||
64 | /* PCM information */ | 63 | /* PCM information */ |
65 | struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */ | 64 | struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */ |
66 | 65 | ||
67 | struct mutex amp_mutex; /* PCM volume/mute control mutex */ | ||
68 | unsigned int spdif_route; | 66 | unsigned int spdif_route; |
69 | 67 | ||
70 | /* dynamic controls, init_verbs and input_mux */ | 68 | /* dynamic controls, init_verbs and input_mux */ |
@@ -1618,6 +1616,7 @@ static const char *ad1981_models[AD1981_MODELS] = { | |||
1618 | 1616 | ||
1619 | static struct snd_pci_quirk ad1981_cfg_tbl[] = { | 1617 | static struct snd_pci_quirk ad1981_cfg_tbl[] = { |
1620 | SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD), | 1618 | SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD), |
1619 | SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD), | ||
1621 | /* All HP models */ | 1620 | /* All HP models */ |
1622 | SND_PCI_QUIRK(0x103c, 0, "HP nx", AD1981_HP), | 1621 | SND_PCI_QUIRK(0x103c, 0, "HP nx", AD1981_HP), |
1623 | SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA), | 1622 | SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA), |
@@ -2623,7 +2622,7 @@ static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, | |||
2623 | { | 2622 | { |
2624 | struct ad198x_spec *spec = codec->spec; | 2623 | struct ad198x_spec *spec = codec->spec; |
2625 | hda_nid_t nid; | 2624 | hda_nid_t nid; |
2626 | int idx, err; | 2625 | int i, idx, err; |
2627 | char name[32]; | 2626 | char name[32]; |
2628 | 2627 | ||
2629 | if (! pin) | 2628 | if (! pin) |
@@ -2631,16 +2630,26 @@ static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, | |||
2631 | 2630 | ||
2632 | idx = ad1988_pin_idx(pin); | 2631 | idx = ad1988_pin_idx(pin); |
2633 | nid = ad1988_idx_to_dac(codec, idx); | 2632 | nid = ad1988_idx_to_dac(codec, idx); |
2634 | /* specify the DAC as the extra output */ | 2633 | /* check whether the corresponding DAC was already taken */ |
2635 | if (! spec->multiout.hp_nid) | 2634 | for (i = 0; i < spec->autocfg.line_outs; i++) { |
2636 | spec->multiout.hp_nid = nid; | 2635 | hda_nid_t pin = spec->autocfg.line_out_pins[i]; |
2637 | else | 2636 | hda_nid_t dac = ad1988_idx_to_dac(codec, ad1988_pin_idx(pin)); |
2638 | spec->multiout.extra_out_nid[0] = nid; | 2637 | if (dac == nid) |
2639 | /* control HP volume/switch on the output mixer amp */ | 2638 | break; |
2640 | sprintf(name, "%s Playback Volume", pfx); | 2639 | } |
2641 | if ((err = add_control(spec, AD_CTL_WIDGET_VOL, name, | 2640 | if (i >= spec->autocfg.line_outs) { |
2642 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) | 2641 | /* specify the DAC as the extra output */ |
2643 | return err; | 2642 | if (!spec->multiout.hp_nid) |
2643 | spec->multiout.hp_nid = nid; | ||
2644 | else | ||
2645 | spec->multiout.extra_out_nid[0] = nid; | ||
2646 | /* control HP volume/switch on the output mixer amp */ | ||
2647 | sprintf(name, "%s Playback Volume", pfx); | ||
2648 | err = add_control(spec, AD_CTL_WIDGET_VOL, name, | ||
2649 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); | ||
2650 | if (err < 0) | ||
2651 | return err; | ||
2652 | } | ||
2644 | nid = ad1988_mixer_nids[idx]; | 2653 | nid = ad1988_mixer_nids[idx]; |
2645 | sprintf(name, "%s Playback Switch", pfx); | 2654 | sprintf(name, "%s Playback Switch", pfx); |
2646 | if ((err = add_control(spec, AD_CTL_BIND_MUTE, name, | 2655 | if ((err = add_control(spec, AD_CTL_BIND_MUTE, name, |
@@ -3177,7 +3186,6 @@ static int patch_ad1884(struct hda_codec *codec) | |||
3177 | if (spec == NULL) | 3186 | if (spec == NULL) |
3178 | return -ENOMEM; | 3187 | return -ENOMEM; |
3179 | 3188 | ||
3180 | mutex_init(&spec->amp_mutex); | ||
3181 | codec->spec = spec; | 3189 | codec->spec = spec; |
3182 | 3190 | ||
3183 | spec->multiout.max_channels = 2; | 3191 | spec->multiout.max_channels = 2; |
@@ -3847,7 +3855,6 @@ static int patch_ad1884a(struct hda_codec *codec) | |||
3847 | if (spec == NULL) | 3855 | if (spec == NULL) |
3848 | return -ENOMEM; | 3856 | return -ENOMEM; |
3849 | 3857 | ||
3850 | mutex_init(&spec->amp_mutex); | ||
3851 | codec->spec = spec; | 3858 | codec->spec = spec; |
3852 | 3859 | ||
3853 | spec->multiout.max_channels = 2; | 3860 | spec->multiout.max_channels = 2; |
@@ -4152,7 +4159,6 @@ static int patch_ad1882(struct hda_codec *codec) | |||
4152 | if (spec == NULL) | 4159 | if (spec == NULL) |
4153 | return -ENOMEM; | 4160 | return -ENOMEM; |
4154 | 4161 | ||
4155 | mutex_init(&spec->amp_mutex); | ||
4156 | codec->spec = spec; | 4162 | codec->spec = spec; |
4157 | 4163 | ||
4158 | spec->multiout.max_channels = 6; | 4164 | spec->multiout.max_channels = 6; |
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 36fd85260035..7c1eb23f0cec 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -82,7 +82,6 @@ struct conexant_spec { | |||
82 | /* PCM information */ | 82 | /* PCM information */ |
83 | struct hda_pcm pcm_rec[2]; /* used in build_pcms() */ | 83 | struct hda_pcm pcm_rec[2]; /* used in build_pcms() */ |
84 | 84 | ||
85 | struct mutex amp_mutex; /* PCM volume/mute control mutex */ | ||
86 | unsigned int spdif_route; | 85 | unsigned int spdif_route; |
87 | 86 | ||
88 | /* dynamic controls, init_verbs and input_mux */ | 87 | /* dynamic controls, init_verbs and input_mux */ |
@@ -687,7 +686,7 @@ static struct snd_kcontrol_new cxt5045_mixers_hp530[] = { | |||
687 | 686 | ||
688 | static struct hda_verb cxt5045_init_verbs[] = { | 687 | static struct hda_verb cxt5045_init_verbs[] = { |
689 | /* Line in, Mic */ | 688 | /* Line in, Mic */ |
690 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, | 689 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, |
691 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, | 690 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, |
692 | /* HP, Amp */ | 691 | /* HP, Amp */ |
693 | {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | 692 | {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
@@ -907,10 +906,12 @@ static struct snd_pci_quirk cxt5045_cfg_tbl[] = { | |||
907 | SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV9533EG", CXT5045_LAPTOP_HPSENSE), | 906 | SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV9533EG", CXT5045_LAPTOP_HPSENSE), |
908 | SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530), | 907 | SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530), |
909 | SND_PCI_QUIRK(0x103c, 0x30d9, "HP Spartan", CXT5045_LAPTOP_HPSENSE), | 908 | SND_PCI_QUIRK(0x103c, 0x30d9, "HP Spartan", CXT5045_LAPTOP_HPSENSE), |
909 | SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P105", CXT5045_LAPTOP_MICSENSE), | ||
910 | SND_PCI_QUIRK(0x152d, 0x0753, "Benq R55E", CXT5045_BENQ), | 910 | SND_PCI_QUIRK(0x152d, 0x0753, "Benq R55E", CXT5045_BENQ), |
911 | SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP_MICSENSE), | 911 | SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP_MICSENSE), |
912 | SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP_HPMICSENSE), | 912 | SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP_HPMICSENSE), |
913 | SND_PCI_QUIRK(0x1734, 0x110e, "Fujitsu V5505", CXT5045_LAPTOP_HPSENSE), | 913 | SND_PCI_QUIRK(0x1734, 0x110e, "Fujitsu V5505", |
914 | CXT5045_LAPTOP_HPMICSENSE), | ||
914 | SND_PCI_QUIRK(0x1509, 0x1e40, "FIC", CXT5045_LAPTOP_HPMICSENSE), | 915 | SND_PCI_QUIRK(0x1509, 0x1e40, "FIC", CXT5045_LAPTOP_HPMICSENSE), |
915 | SND_PCI_QUIRK(0x1509, 0x2f05, "FIC", CXT5045_LAPTOP_HPMICSENSE), | 916 | SND_PCI_QUIRK(0x1509, 0x2f05, "FIC", CXT5045_LAPTOP_HPMICSENSE), |
916 | SND_PCI_QUIRK(0x1509, 0x2f06, "FIC", CXT5045_LAPTOP_HPMICSENSE), | 917 | SND_PCI_QUIRK(0x1509, 0x2f06, "FIC", CXT5045_LAPTOP_HPMICSENSE), |
@@ -928,7 +929,6 @@ static int patch_cxt5045(struct hda_codec *codec) | |||
928 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 929 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
929 | if (!spec) | 930 | if (!spec) |
930 | return -ENOMEM; | 931 | return -ENOMEM; |
931 | mutex_init(&spec->amp_mutex); | ||
932 | codec->spec = spec; | 932 | codec->spec = spec; |
933 | 933 | ||
934 | spec->multiout.max_channels = 2; | 934 | spec->multiout.max_channels = 2; |
@@ -963,6 +963,7 @@ static int patch_cxt5045(struct hda_codec *codec) | |||
963 | codec->patch_ops.init = cxt5045_init; | 963 | codec->patch_ops.init = cxt5045_init; |
964 | break; | 964 | break; |
965 | case CXT5045_LAPTOP_MICSENSE: | 965 | case CXT5045_LAPTOP_MICSENSE: |
966 | codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; | ||
966 | spec->input_mux = &cxt5045_capture_source; | 967 | spec->input_mux = &cxt5045_capture_source; |
967 | spec->num_init_verbs = 2; | 968 | spec->num_init_verbs = 2; |
968 | spec->init_verbs[1] = cxt5045_mic_sense_init_verbs; | 969 | spec->init_verbs[1] = cxt5045_mic_sense_init_verbs; |
@@ -1007,15 +1008,19 @@ static int patch_cxt5045(struct hda_codec *codec) | |||
1007 | #endif | 1008 | #endif |
1008 | } | 1009 | } |
1009 | 1010 | ||
1010 | /* | 1011 | switch (codec->subsystem_id >> 16) { |
1011 | * Fix max PCM level to 0 dB | 1012 | case 0x103c: |
1012 | * (originall it has 0x2b steps with 0dB offset 0x14) | 1013 | /* HP laptop has a really bad sound over 0dB on NID 0x17. |
1013 | */ | 1014 | * Fix max PCM level to 0 dB |
1014 | snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT, | 1015 | * (originall it has 0x2b steps with 0dB offset 0x14) |
1015 | (0x14 << AC_AMPCAP_OFFSET_SHIFT) | | 1016 | */ |
1016 | (0x14 << AC_AMPCAP_NUM_STEPS_SHIFT) | | 1017 | snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT, |
1017 | (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | | 1018 | (0x14 << AC_AMPCAP_OFFSET_SHIFT) | |
1018 | (1 << AC_AMPCAP_MUTE_SHIFT)); | 1019 | (0x14 << AC_AMPCAP_NUM_STEPS_SHIFT) | |
1020 | (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | | ||
1021 | (1 << AC_AMPCAP_MUTE_SHIFT)); | ||
1022 | break; | ||
1023 | } | ||
1019 | 1024 | ||
1020 | return 0; | 1025 | return 0; |
1021 | } | 1026 | } |
@@ -1477,7 +1482,6 @@ static int patch_cxt5047(struct hda_codec *codec) | |||
1477 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 1482 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
1478 | if (!spec) | 1483 | if (!spec) |
1479 | return -ENOMEM; | 1484 | return -ENOMEM; |
1480 | mutex_init(&spec->amp_mutex); | ||
1481 | codec->spec = spec; | 1485 | codec->spec = spec; |
1482 | 1486 | ||
1483 | spec->multiout.max_channels = 2; | 1487 | spec->multiout.max_channels = 2; |
@@ -1736,7 +1740,6 @@ static int patch_cxt5051(struct hda_codec *codec) | |||
1736 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 1740 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
1737 | if (!spec) | 1741 | if (!spec) |
1738 | return -ENOMEM; | 1742 | return -ENOMEM; |
1739 | mutex_init(&spec->amp_mutex); | ||
1740 | codec->spec = spec; | 1743 | codec->spec = spec; |
1741 | 1744 | ||
1742 | codec->patch_ops = conexant_patch_ops; | 1745 | codec->patch_ops = conexant_patch_ops; |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b0a2a262ece2..2807bc840d26 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -163,6 +163,10 @@ enum { | |||
163 | ALC662_LENOVO_101E, | 163 | ALC662_LENOVO_101E, |
164 | ALC662_ASUS_EEEPC_P701, | 164 | ALC662_ASUS_EEEPC_P701, |
165 | ALC662_ASUS_EEEPC_EP20, | 165 | ALC662_ASUS_EEEPC_EP20, |
166 | ALC663_ASUS_M51VA, | ||
167 | ALC663_ASUS_G71V, | ||
168 | ALC663_ASUS_H13, | ||
169 | ALC663_ASUS_G50V, | ||
166 | ALC662_AUTO, | 170 | ALC662_AUTO, |
167 | ALC662_MODEL_LAST, | 171 | ALC662_MODEL_LAST, |
168 | }; | 172 | }; |
@@ -205,6 +209,7 @@ enum { | |||
205 | ALC883_MITAC, | 209 | ALC883_MITAC, |
206 | ALC883_CLEVO_M720, | 210 | ALC883_CLEVO_M720, |
207 | ALC883_FUJITSU_PI2515, | 211 | ALC883_FUJITSU_PI2515, |
212 | ALC883_3ST_6ch_INTEL, | ||
208 | ALC883_AUTO, | 213 | ALC883_AUTO, |
209 | ALC883_MODEL_LAST, | 214 | ALC883_MODEL_LAST, |
210 | }; | 215 | }; |
@@ -280,6 +285,10 @@ struct alc_spec { | |||
280 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 285 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
281 | struct hda_loopback_check loopback; | 286 | struct hda_loopback_check loopback; |
282 | #endif | 287 | #endif |
288 | |||
289 | /* for PLL fix */ | ||
290 | hda_nid_t pll_nid; | ||
291 | unsigned int pll_coef_idx, pll_coef_bit; | ||
283 | }; | 292 | }; |
284 | 293 | ||
285 | /* | 294 | /* |
@@ -747,6 +756,38 @@ static struct hda_verb alc_gpio3_init_verbs[] = { | |||
747 | { } | 756 | { } |
748 | }; | 757 | }; |
749 | 758 | ||
759 | /* | ||
760 | * Fix hardware PLL issue | ||
761 | * On some codecs, the analog PLL gating control must be off while | ||
762 | * the default value is 1. | ||
763 | */ | ||
764 | static void alc_fix_pll(struct hda_codec *codec) | ||
765 | { | ||
766 | struct alc_spec *spec = codec->spec; | ||
767 | unsigned int val; | ||
768 | |||
769 | if (!spec->pll_nid) | ||
770 | return; | ||
771 | snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX, | ||
772 | spec->pll_coef_idx); | ||
773 | val = snd_hda_codec_read(codec, spec->pll_nid, 0, | ||
774 | AC_VERB_GET_PROC_COEF, 0); | ||
775 | snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX, | ||
776 | spec->pll_coef_idx); | ||
777 | snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF, | ||
778 | val & ~(1 << spec->pll_coef_bit)); | ||
779 | } | ||
780 | |||
781 | static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid, | ||
782 | unsigned int coef_idx, unsigned int coef_bit) | ||
783 | { | ||
784 | struct alc_spec *spec = codec->spec; | ||
785 | spec->pll_nid = nid; | ||
786 | spec->pll_coef_idx = coef_idx; | ||
787 | spec->pll_coef_bit = coef_bit; | ||
788 | alc_fix_pll(codec); | ||
789 | } | ||
790 | |||
750 | static void alc_sku_automute(struct hda_codec *codec) | 791 | static void alc_sku_automute(struct hda_codec *codec) |
751 | { | 792 | { |
752 | struct alc_spec *spec = codec->spec; | 793 | struct alc_spec *spec = codec->spec; |
@@ -776,6 +817,24 @@ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res) | |||
776 | alc_sku_automute(codec); | 817 | alc_sku_automute(codec); |
777 | } | 818 | } |
778 | 819 | ||
820 | /* additional initialization for ALC888 variants */ | ||
821 | static void alc888_coef_init(struct hda_codec *codec) | ||
822 | { | ||
823 | unsigned int tmp; | ||
824 | |||
825 | snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0); | ||
826 | tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0); | ||
827 | snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7); | ||
828 | if ((tmp & 0xf0) == 2) | ||
829 | /* alc888S-VC */ | ||
830 | snd_hda_codec_read(codec, 0x20, 0, | ||
831 | AC_VERB_SET_PROC_COEF, 0x830); | ||
832 | else | ||
833 | /* alc888-VB */ | ||
834 | snd_hda_codec_read(codec, 0x20, 0, | ||
835 | AC_VERB_SET_PROC_COEF, 0x3030); | ||
836 | } | ||
837 | |||
779 | /* 32-bit subsystem ID for BIOS loading in HD Audio codec. | 838 | /* 32-bit subsystem ID for BIOS loading in HD Audio codec. |
780 | * 31 ~ 16 : Manufacture ID | 839 | * 31 ~ 16 : Manufacture ID |
781 | * 15 ~ 8 : SKU ID | 840 | * 15 ~ 8 : SKU ID |
@@ -851,8 +910,10 @@ do_sku: | |||
851 | case 0x10ec0267: | 910 | case 0x10ec0267: |
852 | case 0x10ec0268: | 911 | case 0x10ec0268: |
853 | case 0x10ec0269: | 912 | case 0x10ec0269: |
913 | case 0x10ec0660: | ||
914 | case 0x10ec0662: | ||
915 | case 0x10ec0663: | ||
854 | case 0x10ec0862: | 916 | case 0x10ec0862: |
855 | case 0x10ec0662: | ||
856 | case 0x10ec0889: | 917 | case 0x10ec0889: |
857 | snd_hda_codec_write(codec, 0x14, 0, | 918 | snd_hda_codec_write(codec, 0x14, 0, |
858 | AC_VERB_SET_EAPD_BTLENABLE, 2); | 919 | AC_VERB_SET_EAPD_BTLENABLE, 2); |
@@ -877,7 +938,6 @@ do_sku: | |||
877 | case 0x10ec0882: | 938 | case 0x10ec0882: |
878 | case 0x10ec0883: | 939 | case 0x10ec0883: |
879 | case 0x10ec0885: | 940 | case 0x10ec0885: |
880 | case 0x10ec0888: | ||
881 | case 0x10ec0889: | 941 | case 0x10ec0889: |
882 | snd_hda_codec_write(codec, 0x20, 0, | 942 | snd_hda_codec_write(codec, 0x20, 0, |
883 | AC_VERB_SET_COEF_INDEX, 7); | 943 | AC_VERB_SET_COEF_INDEX, 7); |
@@ -889,6 +949,9 @@ do_sku: | |||
889 | AC_VERB_SET_PROC_COEF, | 949 | AC_VERB_SET_PROC_COEF, |
890 | tmp | 0x2010); | 950 | tmp | 0x2010); |
891 | break; | 951 | break; |
952 | case 0x10ec0888: | ||
953 | alc888_coef_init(codec); | ||
954 | break; | ||
892 | case 0x10ec0267: | 955 | case 0x10ec0267: |
893 | case 0x10ec0268: | 956 | case 0x10ec0268: |
894 | snd_hda_codec_write(codec, 0x20, 0, | 957 | snd_hda_codec_write(codec, 0x20, 0, |
@@ -2373,6 +2436,8 @@ static int alc_init(struct hda_codec *codec) | |||
2373 | struct alc_spec *spec = codec->spec; | 2436 | struct alc_spec *spec = codec->spec; |
2374 | unsigned int i; | 2437 | unsigned int i; |
2375 | 2438 | ||
2439 | alc_fix_pll(codec); | ||
2440 | |||
2376 | for (i = 0; i < spec->num_init_verbs; i++) | 2441 | for (i = 0; i < spec->num_init_verbs; i++) |
2377 | snd_hda_sequence_write(codec, spec->init_verbs[i]); | 2442 | snd_hda_sequence_write(codec, spec->init_verbs[i]); |
2378 | 2443 | ||
@@ -3009,6 +3074,7 @@ static struct snd_pci_quirk alc880_cfg_tbl[] = { | |||
3009 | SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG), | 3074 | SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG), |
3010 | SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG), | 3075 | SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG), |
3011 | SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734), | 3076 | SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734), |
3077 | SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU), | ||
3012 | SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL), | 3078 | SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL), |
3013 | SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU), | 3079 | SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU), |
3014 | SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW), | 3080 | SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW), |
@@ -5101,7 +5167,7 @@ static struct snd_pci_quirk alc260_cfg_tbl[] = { | |||
5101 | SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013), | 5167 | SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013), |
5102 | SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013), | 5168 | SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013), |
5103 | SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013), | 5169 | SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013), |
5104 | SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP), | 5170 | SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013), |
5105 | SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_3013), | 5171 | SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_3013), |
5106 | SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013), | 5172 | SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013), |
5107 | SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP), | 5173 | SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP), |
@@ -6127,6 +6193,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = { | |||
6127 | SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG), | 6193 | SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG), |
6128 | SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG), | 6194 | SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG), |
6129 | SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG), | 6195 | SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG), |
6196 | SND_PCI_QUIRK(0x106b, 0x00a0, "Apple iMac 24''", ALC885_IMAC24), | ||
6130 | SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG), | 6197 | SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG), |
6131 | SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */ | 6198 | SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */ |
6132 | SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG), | 6199 | SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG), |
@@ -6353,7 +6420,9 @@ static void alc882_auto_init_analog_input(struct hda_codec *codec) | |||
6353 | continue; | 6420 | continue; |
6354 | vref = PIN_IN; | 6421 | vref = PIN_IN; |
6355 | if (1 /*i <= AUTO_PIN_FRONT_MIC*/) { | 6422 | if (1 /*i <= AUTO_PIN_FRONT_MIC*/) { |
6356 | if (snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP) & | 6423 | unsigned int pincap; |
6424 | pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); | ||
6425 | if ((pincap >> AC_PINCAP_VREF_SHIFT) & | ||
6357 | AC_PINCAP_VREF_80) | 6426 | AC_PINCAP_VREF_80) |
6358 | vref = PIN_VREF80; | 6427 | vref = PIN_VREF80; |
6359 | } | 6428 | } |
@@ -6450,8 +6519,9 @@ static int patch_alc882(struct hda_codec *codec) | |||
6450 | case 0x106b1000: /* iMac 24 */ | 6519 | case 0x106b1000: /* iMac 24 */ |
6451 | board_config = ALC885_IMAC24; | 6520 | board_config = ALC885_IMAC24; |
6452 | break; | 6521 | break; |
6453 | case 0x106b00a1: /* Macbook */ | 6522 | case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */ |
6454 | case 0x106b2c00: /* Macbook Pro rev3 */ | 6523 | case 0x106b2c00: /* Macbook Pro rev3 */ |
6524 | case 0x106b3600: /* Macbook 3.1 */ | ||
6455 | board_config = ALC885_MBP3; | 6525 | board_config = ALC885_MBP3; |
6456 | break; | 6526 | break; |
6457 | default: | 6527 | default: |
@@ -6485,14 +6555,20 @@ static int patch_alc882(struct hda_codec *codec) | |||
6485 | if (board_config != ALC882_AUTO) | 6555 | if (board_config != ALC882_AUTO) |
6486 | setup_preset(spec, &alc882_presets[board_config]); | 6556 | setup_preset(spec, &alc882_presets[board_config]); |
6487 | 6557 | ||
6488 | spec->stream_name_analog = "ALC882 Analog"; | 6558 | if (codec->vendor_id == 0x10ec0885) { |
6559 | spec->stream_name_analog = "ALC885 Analog"; | ||
6560 | spec->stream_name_digital = "ALC885 Digital"; | ||
6561 | } else { | ||
6562 | spec->stream_name_analog = "ALC882 Analog"; | ||
6563 | spec->stream_name_digital = "ALC882 Digital"; | ||
6564 | } | ||
6565 | |||
6489 | spec->stream_analog_playback = &alc882_pcm_analog_playback; | 6566 | spec->stream_analog_playback = &alc882_pcm_analog_playback; |
6490 | spec->stream_analog_capture = &alc882_pcm_analog_capture; | 6567 | spec->stream_analog_capture = &alc882_pcm_analog_capture; |
6491 | /* FIXME: setup DAC5 */ | 6568 | /* FIXME: setup DAC5 */ |
6492 | /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/ | 6569 | /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/ |
6493 | spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture; | 6570 | spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture; |
6494 | 6571 | ||
6495 | spec->stream_name_digital = "ALC882 Digital"; | ||
6496 | spec->stream_digital_playback = &alc882_pcm_digital_playback; | 6572 | spec->stream_digital_playback = &alc882_pcm_digital_playback; |
6497 | spec->stream_digital_capture = &alc882_pcm_digital_capture; | 6573 | spec->stream_digital_capture = &alc882_pcm_digital_capture; |
6498 | 6574 | ||
@@ -6569,6 +6645,16 @@ static struct hda_input_mux alc883_capture_source = { | |||
6569 | }, | 6645 | }, |
6570 | }; | 6646 | }; |
6571 | 6647 | ||
6648 | static struct hda_input_mux alc883_3stack_6ch_intel = { | ||
6649 | .num_items = 4, | ||
6650 | .items = { | ||
6651 | { "Mic", 0x1 }, | ||
6652 | { "Front Mic", 0x0 }, | ||
6653 | { "Line", 0x2 }, | ||
6654 | { "CD", 0x4 }, | ||
6655 | }, | ||
6656 | }; | ||
6657 | |||
6572 | static struct hda_input_mux alc883_lenovo_101e_capture_source = { | 6658 | static struct hda_input_mux alc883_lenovo_101e_capture_source = { |
6573 | .num_items = 2, | 6659 | .num_items = 2, |
6574 | .items = { | 6660 | .items = { |
@@ -6650,6 +6736,48 @@ static struct hda_channel_mode alc883_3ST_6ch_modes[3] = { | |||
6650 | }; | 6736 | }; |
6651 | 6737 | ||
6652 | /* | 6738 | /* |
6739 | * 2ch mode | ||
6740 | */ | ||
6741 | static struct hda_verb alc883_3ST_ch2_intel_init[] = { | ||
6742 | { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, | ||
6743 | { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | ||
6744 | { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, | ||
6745 | { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | ||
6746 | { } /* end */ | ||
6747 | }; | ||
6748 | |||
6749 | /* | ||
6750 | * 4ch mode | ||
6751 | */ | ||
6752 | static struct hda_verb alc883_3ST_ch4_intel_init[] = { | ||
6753 | { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, | ||
6754 | { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | ||
6755 | { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
6756 | { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
6757 | { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, | ||
6758 | { } /* end */ | ||
6759 | }; | ||
6760 | |||
6761 | /* | ||
6762 | * 6ch mode | ||
6763 | */ | ||
6764 | static struct hda_verb alc883_3ST_ch6_intel_init[] = { | ||
6765 | { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
6766 | { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
6767 | { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 }, | ||
6768 | { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
6769 | { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
6770 | { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, | ||
6771 | { } /* end */ | ||
6772 | }; | ||
6773 | |||
6774 | static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = { | ||
6775 | { 2, alc883_3ST_ch2_intel_init }, | ||
6776 | { 4, alc883_3ST_ch4_intel_init }, | ||
6777 | { 6, alc883_3ST_ch6_intel_init }, | ||
6778 | }; | ||
6779 | |||
6780 | /* | ||
6653 | * 6ch mode | 6781 | * 6ch mode |
6654 | */ | 6782 | */ |
6655 | static struct hda_verb alc883_sixstack_ch6_init[] = { | 6783 | static struct hda_verb alc883_sixstack_ch6_init[] = { |
@@ -6881,15 +7009,54 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = { | |||
6881 | { } /* end */ | 7009 | { } /* end */ |
6882 | }; | 7010 | }; |
6883 | 7011 | ||
7012 | static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = { | ||
7013 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
7014 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), | ||
7015 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | ||
7016 | HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), | ||
7017 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, | ||
7018 | HDA_OUTPUT), | ||
7019 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), | ||
7020 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), | ||
7021 | HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), | ||
7022 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
7023 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | ||
7024 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | ||
7025 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | ||
7026 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | ||
7027 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), | ||
7028 | HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT), | ||
7029 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | ||
7030 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
7031 | HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT), | ||
7032 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
7033 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), | ||
7034 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), | ||
7035 | HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), | ||
7036 | HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), | ||
7037 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), | ||
7038 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), | ||
7039 | { | ||
7040 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
7041 | /* .name = "Capture Source", */ | ||
7042 | .name = "Input Source", | ||
7043 | .count = 2, | ||
7044 | .info = alc883_mux_enum_info, | ||
7045 | .get = alc883_mux_enum_get, | ||
7046 | .put = alc883_mux_enum_put, | ||
7047 | }, | ||
7048 | { } /* end */ | ||
7049 | }; | ||
7050 | |||
6884 | static struct snd_kcontrol_new alc883_fivestack_mixer[] = { | 7051 | static struct snd_kcontrol_new alc883_fivestack_mixer[] = { |
6885 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 7052 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
6886 | HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), | 7053 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), |
6887 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | 7054 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), |
6888 | HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT), | 7055 | HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), |
6889 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), | 7056 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), |
6890 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), | 7057 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), |
6891 | HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT), | 7058 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), |
6892 | HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), | 7059 | HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), |
6893 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | 7060 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), |
6894 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | 7061 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), |
6895 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | 7062 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), |
@@ -7729,6 +7896,7 @@ static const char *alc883_models[ALC883_MODEL_LAST] = { | |||
7729 | [ALC883_MITAC] = "mitac", | 7896 | [ALC883_MITAC] = "mitac", |
7730 | [ALC883_CLEVO_M720] = "clevo-m720", | 7897 | [ALC883_CLEVO_M720] = "clevo-m720", |
7731 | [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515", | 7898 | [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515", |
7899 | [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel", | ||
7732 | [ALC883_AUTO] = "auto", | 7900 | [ALC883_AUTO] = "auto", |
7733 | }; | 7901 | }; |
7734 | 7902 | ||
@@ -7786,6 +7954,8 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { | |||
7786 | SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2), | 7954 | SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2), |
7787 | SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG), | 7955 | SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG), |
7788 | SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66), | 7956 | SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66), |
7957 | SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL), | ||
7958 | SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL), | ||
7789 | SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch), | 7959 | SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch), |
7790 | {} | 7960 | {} |
7791 | }; | 7961 | }; |
@@ -7824,6 +7994,18 @@ static struct alc_config_preset alc883_presets[] = { | |||
7824 | .need_dac_fix = 1, | 7994 | .need_dac_fix = 1, |
7825 | .input_mux = &alc883_capture_source, | 7995 | .input_mux = &alc883_capture_source, |
7826 | }, | 7996 | }, |
7997 | [ALC883_3ST_6ch_INTEL] = { | ||
7998 | .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer }, | ||
7999 | .init_verbs = { alc883_init_verbs }, | ||
8000 | .num_dacs = ARRAY_SIZE(alc883_dac_nids), | ||
8001 | .dac_nids = alc883_dac_nids, | ||
8002 | .dig_out_nid = ALC883_DIGOUT_NID, | ||
8003 | .dig_in_nid = ALC883_DIGIN_NID, | ||
8004 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes), | ||
8005 | .channel_mode = alc883_3ST_6ch_intel_modes, | ||
8006 | .need_dac_fix = 1, | ||
8007 | .input_mux = &alc883_3stack_6ch_intel, | ||
8008 | }, | ||
7827 | [ALC883_6ST_DIG] = { | 8009 | [ALC883_6ST_DIG] = { |
7828 | .mixers = { alc883_base_mixer, alc883_chmode_mixer }, | 8010 | .mixers = { alc883_base_mixer, alc883_chmode_mixer }, |
7829 | .init_verbs = { alc883_init_verbs }, | 8011 | .init_verbs = { alc883_init_verbs }, |
@@ -8145,6 +8327,8 @@ static int patch_alc883(struct hda_codec *codec) | |||
8145 | 8327 | ||
8146 | codec->spec = spec; | 8328 | codec->spec = spec; |
8147 | 8329 | ||
8330 | alc_fix_pll_init(codec, 0x20, 0x0a, 10); | ||
8331 | |||
8148 | board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST, | 8332 | board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST, |
8149 | alc883_models, | 8333 | alc883_models, |
8150 | alc883_cfg_tbl); | 8334 | alc883_cfg_tbl); |
@@ -8171,12 +8355,25 @@ static int patch_alc883(struct hda_codec *codec) | |||
8171 | if (board_config != ALC883_AUTO) | 8355 | if (board_config != ALC883_AUTO) |
8172 | setup_preset(spec, &alc883_presets[board_config]); | 8356 | setup_preset(spec, &alc883_presets[board_config]); |
8173 | 8357 | ||
8174 | spec->stream_name_analog = "ALC883 Analog"; | 8358 | switch (codec->vendor_id) { |
8359 | case 0x10ec0888: | ||
8360 | spec->stream_name_analog = "ALC888 Analog"; | ||
8361 | spec->stream_name_digital = "ALC888 Digital"; | ||
8362 | break; | ||
8363 | case 0x10ec0889: | ||
8364 | spec->stream_name_analog = "ALC889 Analog"; | ||
8365 | spec->stream_name_digital = "ALC889 Digital"; | ||
8366 | break; | ||
8367 | default: | ||
8368 | spec->stream_name_analog = "ALC883 Analog"; | ||
8369 | spec->stream_name_digital = "ALC883 Digital"; | ||
8370 | break; | ||
8371 | } | ||
8372 | |||
8175 | spec->stream_analog_playback = &alc883_pcm_analog_playback; | 8373 | spec->stream_analog_playback = &alc883_pcm_analog_playback; |
8176 | spec->stream_analog_capture = &alc883_pcm_analog_capture; | 8374 | spec->stream_analog_capture = &alc883_pcm_analog_capture; |
8177 | spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture; | 8375 | spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture; |
8178 | 8376 | ||
8179 | spec->stream_name_digital = "ALC883 Digital"; | ||
8180 | spec->stream_digital_playback = &alc883_pcm_digital_playback; | 8377 | spec->stream_digital_playback = &alc883_pcm_digital_playback; |
8181 | spec->stream_digital_capture = &alc883_pcm_digital_capture; | 8378 | spec->stream_digital_capture = &alc883_pcm_digital_capture; |
8182 | 8379 | ||
@@ -8189,6 +8386,9 @@ static int patch_alc883(struct hda_codec *codec) | |||
8189 | codec->patch_ops = alc_patch_ops; | 8386 | codec->patch_ops = alc_patch_ops; |
8190 | if (board_config == ALC883_AUTO) | 8387 | if (board_config == ALC883_AUTO) |
8191 | spec->init_hook = alc883_auto_init; | 8388 | spec->init_hook = alc883_auto_init; |
8389 | else if (codec->vendor_id == 0x10ec0888) | ||
8390 | spec->init_hook = alc888_coef_init; | ||
8391 | |||
8192 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 8392 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
8193 | if (!spec->loopback.amplist) | 8393 | if (!spec->loopback.amplist) |
8194 | spec->loopback.amplist = alc883_loopbacks; | 8394 | spec->loopback.amplist = alc883_loopbacks; |
@@ -9522,6 +9722,8 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = { | |||
9522 | SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD), | 9722 | SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD), |
9523 | SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD), | 9723 | SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD), |
9524 | SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD), | 9724 | SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD), |
9725 | SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1", | ||
9726 | ALC262_SONY_ASSAMD), | ||
9525 | SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU), | 9727 | SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU), |
9526 | SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU), | 9728 | SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU), |
9527 | SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA), | 9729 | SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA), |
@@ -9729,6 +9931,8 @@ static int patch_alc262(struct hda_codec *codec) | |||
9729 | } | 9931 | } |
9730 | #endif | 9932 | #endif |
9731 | 9933 | ||
9934 | alc_fix_pll_init(codec, 0x20, 0x0a, 10); | ||
9935 | |||
9732 | board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST, | 9936 | board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST, |
9733 | alc262_models, | 9937 | alc262_models, |
9734 | alc262_cfg_tbl); | 9938 | alc262_cfg_tbl); |
@@ -10674,12 +10878,18 @@ static int patch_alc268(struct hda_codec *codec) | |||
10674 | if (board_config != ALC268_AUTO) | 10878 | if (board_config != ALC268_AUTO) |
10675 | setup_preset(spec, &alc268_presets[board_config]); | 10879 | setup_preset(spec, &alc268_presets[board_config]); |
10676 | 10880 | ||
10677 | spec->stream_name_analog = "ALC268 Analog"; | 10881 | if (codec->vendor_id == 0x10ec0267) { |
10882 | spec->stream_name_analog = "ALC267 Analog"; | ||
10883 | spec->stream_name_digital = "ALC267 Digital"; | ||
10884 | } else { | ||
10885 | spec->stream_name_analog = "ALC268 Analog"; | ||
10886 | spec->stream_name_digital = "ALC268 Digital"; | ||
10887 | } | ||
10888 | |||
10678 | spec->stream_analog_playback = &alc268_pcm_analog_playback; | 10889 | spec->stream_analog_playback = &alc268_pcm_analog_playback; |
10679 | spec->stream_analog_capture = &alc268_pcm_analog_capture; | 10890 | spec->stream_analog_capture = &alc268_pcm_analog_capture; |
10680 | spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture; | 10891 | spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture; |
10681 | 10892 | ||
10682 | spec->stream_name_digital = "ALC268 Digital"; | ||
10683 | spec->stream_digital_playback = &alc268_pcm_digital_playback; | 10893 | spec->stream_digital_playback = &alc268_pcm_digital_playback; |
10684 | 10894 | ||
10685 | if (!query_amp_caps(codec, 0x1d, HDA_INPUT)) | 10895 | if (!query_amp_caps(codec, 0x1d, HDA_INPUT)) |
@@ -11033,6 +11243,8 @@ static int patch_alc269(struct hda_codec *codec) | |||
11033 | 11243 | ||
11034 | codec->spec = spec; | 11244 | codec->spec = spec; |
11035 | 11245 | ||
11246 | alc_fix_pll_init(codec, 0x20, 0x04, 15); | ||
11247 | |||
11036 | board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST, | 11248 | board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST, |
11037 | alc269_models, | 11249 | alc269_models, |
11038 | alc269_cfg_tbl); | 11250 | alc269_cfg_tbl); |
@@ -12631,6 +12843,12 @@ static struct hda_verb alc861vd_eapd_verbs[] = { | |||
12631 | { } | 12843 | { } |
12632 | }; | 12844 | }; |
12633 | 12845 | ||
12846 | static struct hda_verb alc660vd_eapd_verbs[] = { | ||
12847 | {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, | ||
12848 | {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, | ||
12849 | { } | ||
12850 | }; | ||
12851 | |||
12634 | static struct hda_verb alc861vd_lenovo_unsol_verbs[] = { | 12852 | static struct hda_verb alc861vd_lenovo_unsol_verbs[] = { |
12635 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 12853 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
12636 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 12854 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, |
@@ -12786,6 +13004,7 @@ static struct snd_pci_quirk alc861vd_cfg_tbl[] = { | |||
12786 | SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG), | 13004 | SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG), |
12787 | SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO), | 13005 | SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO), |
12788 | SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO), | 13006 | SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO), |
13007 | SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 N200", ALC861VD_LENOVO), | ||
12789 | SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG), | 13008 | SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG), |
12790 | {} | 13009 | {} |
12791 | }; | 13010 | }; |
@@ -13168,11 +13387,19 @@ static int patch_alc861vd(struct hda_codec *codec) | |||
13168 | if (board_config != ALC861VD_AUTO) | 13387 | if (board_config != ALC861VD_AUTO) |
13169 | setup_preset(spec, &alc861vd_presets[board_config]); | 13388 | setup_preset(spec, &alc861vd_presets[board_config]); |
13170 | 13389 | ||
13171 | spec->stream_name_analog = "ALC861VD Analog"; | 13390 | if (codec->vendor_id == 0x10ec0660) { |
13391 | spec->stream_name_analog = "ALC660-VD Analog"; | ||
13392 | spec->stream_name_digital = "ALC660-VD Digital"; | ||
13393 | /* always turn on EAPD */ | ||
13394 | spec->init_verbs[spec->num_init_verbs++] = alc660vd_eapd_verbs; | ||
13395 | } else { | ||
13396 | spec->stream_name_analog = "ALC861VD Analog"; | ||
13397 | spec->stream_name_digital = "ALC861VD Digital"; | ||
13398 | } | ||
13399 | |||
13172 | spec->stream_analog_playback = &alc861vd_pcm_analog_playback; | 13400 | spec->stream_analog_playback = &alc861vd_pcm_analog_playback; |
13173 | spec->stream_analog_capture = &alc861vd_pcm_analog_capture; | 13401 | spec->stream_analog_capture = &alc861vd_pcm_analog_capture; |
13174 | 13402 | ||
13175 | spec->stream_name_digital = "ALC861VD Digital"; | ||
13176 | spec->stream_digital_playback = &alc861vd_pcm_digital_playback; | 13403 | spec->stream_digital_playback = &alc861vd_pcm_digital_playback; |
13177 | spec->stream_digital_capture = &alc861vd_pcm_digital_capture; | 13404 | spec->stream_digital_capture = &alc861vd_pcm_digital_capture; |
13178 | 13405 | ||
@@ -13251,6 +13478,23 @@ static struct hda_input_mux alc662_eeepc_capture_source = { | |||
13251 | }, | 13478 | }, |
13252 | }; | 13479 | }; |
13253 | 13480 | ||
13481 | static struct hda_input_mux alc663_capture_source = { | ||
13482 | .num_items = 3, | ||
13483 | .items = { | ||
13484 | { "Mic", 0x0 }, | ||
13485 | { "Front Mic", 0x1 }, | ||
13486 | { "Line", 0x2 }, | ||
13487 | }, | ||
13488 | }; | ||
13489 | |||
13490 | static struct hda_input_mux alc663_m51va_capture_source = { | ||
13491 | .num_items = 2, | ||
13492 | .items = { | ||
13493 | { "Ext-Mic", 0x0 }, | ||
13494 | { "D-Mic", 0x9 }, | ||
13495 | }, | ||
13496 | }; | ||
13497 | |||
13254 | #define alc662_mux_enum_info alc_mux_enum_info | 13498 | #define alc662_mux_enum_info alc_mux_enum_info |
13255 | #define alc662_mux_enum_get alc_mux_enum_get | 13499 | #define alc662_mux_enum_get alc_mux_enum_get |
13256 | #define alc662_mux_enum_put alc882_mux_enum_put | 13500 | #define alc662_mux_enum_put alc882_mux_enum_put |
@@ -13431,6 +13675,44 @@ static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = { | |||
13431 | { } /* end */ | 13675 | { } /* end */ |
13432 | }; | 13676 | }; |
13433 | 13677 | ||
13678 | static struct snd_kcontrol_new alc663_m51va_mixer[] = { | ||
13679 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), | ||
13680 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
13681 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
13682 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
13683 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
13684 | HDA_CODEC_MUTE("DMic Playback Switch", 0x23, 0x9, HDA_INPUT), | ||
13685 | { } /* end */ | ||
13686 | }; | ||
13687 | |||
13688 | static struct snd_kcontrol_new alc663_g71v_mixer[] = { | ||
13689 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), | ||
13690 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
13691 | HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
13692 | HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
13693 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
13694 | |||
13695 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
13696 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
13697 | HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), | ||
13698 | HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | ||
13699 | { } /* end */ | ||
13700 | }; | ||
13701 | |||
13702 | static struct snd_kcontrol_new alc663_g50v_mixer[] = { | ||
13703 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), | ||
13704 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
13705 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
13706 | |||
13707 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
13708 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
13709 | HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), | ||
13710 | HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | ||
13711 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | ||
13712 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | ||
13713 | { } /* end */ | ||
13714 | }; | ||
13715 | |||
13434 | static struct snd_kcontrol_new alc662_chmode_mixer[] = { | 13716 | static struct snd_kcontrol_new alc662_chmode_mixer[] = { |
13435 | { | 13717 | { |
13436 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 13718 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -13501,6 +13783,11 @@ static struct hda_verb alc662_init_verbs[] = { | |||
13501 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 13783 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, |
13502 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | 13784 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, |
13503 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | 13785 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, |
13786 | |||
13787 | /* always trun on EAPD */ | ||
13788 | {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, | ||
13789 | {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, | ||
13790 | |||
13504 | { } | 13791 | { } |
13505 | }; | 13792 | }; |
13506 | 13793 | ||
@@ -13571,6 +13858,43 @@ static struct hda_verb alc662_auto_init_verbs[] = { | |||
13571 | { } | 13858 | { } |
13572 | }; | 13859 | }; |
13573 | 13860 | ||
13861 | static struct hda_verb alc663_m51va_init_verbs[] = { | ||
13862 | {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
13863 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
13864 | {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */ | ||
13865 | |||
13866 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, | ||
13867 | |||
13868 | {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, | ||
13869 | {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, | ||
13870 | {} | ||
13871 | }; | ||
13872 | |||
13873 | static struct hda_verb alc663_g71v_init_verbs[] = { | ||
13874 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
13875 | /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */ | ||
13876 | /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */ | ||
13877 | |||
13878 | {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
13879 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
13880 | {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */ | ||
13881 | |||
13882 | {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT}, | ||
13883 | {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT}, | ||
13884 | {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT}, | ||
13885 | {} | ||
13886 | }; | ||
13887 | |||
13888 | static struct hda_verb alc663_g50v_init_verbs[] = { | ||
13889 | {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
13890 | {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
13891 | {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */ | ||
13892 | |||
13893 | {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, | ||
13894 | {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, | ||
13895 | {} | ||
13896 | }; | ||
13897 | |||
13574 | /* capture mixer elements */ | 13898 | /* capture mixer elements */ |
13575 | static struct snd_kcontrol_new alc662_capture_mixer[] = { | 13899 | static struct snd_kcontrol_new alc662_capture_mixer[] = { |
13576 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), | 13900 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), |
@@ -13692,6 +14016,125 @@ static void alc662_eeepc_ep20_inithook(struct hda_codec *codec) | |||
13692 | alc662_eeepc_ep20_automute(codec); | 14016 | alc662_eeepc_ep20_automute(codec); |
13693 | } | 14017 | } |
13694 | 14018 | ||
14019 | static void alc663_m51va_speaker_automute(struct hda_codec *codec) | ||
14020 | { | ||
14021 | unsigned int present; | ||
14022 | unsigned char bits; | ||
14023 | |||
14024 | present = snd_hda_codec_read(codec, 0x21, 0, | ||
14025 | AC_VERB_GET_PIN_SENSE, 0) | ||
14026 | & AC_PINSENSE_PRESENCE; | ||
14027 | bits = present ? HDA_AMP_MUTE : 0; | ||
14028 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
14029 | HDA_AMP_MUTE, bits); | ||
14030 | } | ||
14031 | |||
14032 | static void alc663_m51va_mic_automute(struct hda_codec *codec) | ||
14033 | { | ||
14034 | unsigned int present; | ||
14035 | |||
14036 | present = snd_hda_codec_read(codec, 0x18, 0, | ||
14037 | AC_VERB_GET_PIN_SENSE, 0) | ||
14038 | & AC_PINSENSE_PRESENCE; | ||
14039 | snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE, | ||
14040 | 0x7000 | (0x00 << 8) | (present ? 0 : 0x80)); | ||
14041 | snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, | ||
14042 | 0x7000 | (0x00 << 8) | (present ? 0 : 0x80)); | ||
14043 | snd_hda_codec_write_cache(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE, | ||
14044 | 0x7000 | (0x09 << 8) | (present ? 0x80 : 0)); | ||
14045 | snd_hda_codec_write_cache(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, | ||
14046 | 0x7000 | (0x09 << 8) | (present ? 0x80 : 0)); | ||
14047 | } | ||
14048 | |||
14049 | static void alc663_m51va_unsol_event(struct hda_codec *codec, | ||
14050 | unsigned int res) | ||
14051 | { | ||
14052 | switch (res >> 26) { | ||
14053 | case ALC880_HP_EVENT: | ||
14054 | alc663_m51va_speaker_automute(codec); | ||
14055 | break; | ||
14056 | case ALC880_MIC_EVENT: | ||
14057 | alc663_m51va_mic_automute(codec); | ||
14058 | break; | ||
14059 | } | ||
14060 | } | ||
14061 | |||
14062 | static void alc663_m51va_inithook(struct hda_codec *codec) | ||
14063 | { | ||
14064 | alc663_m51va_speaker_automute(codec); | ||
14065 | alc663_m51va_mic_automute(codec); | ||
14066 | } | ||
14067 | |||
14068 | static void alc663_g71v_hp_automute(struct hda_codec *codec) | ||
14069 | { | ||
14070 | unsigned int present; | ||
14071 | unsigned char bits; | ||
14072 | |||
14073 | present = snd_hda_codec_read(codec, 0x21, 0, | ||
14074 | AC_VERB_GET_PIN_SENSE, 0) | ||
14075 | & AC_PINSENSE_PRESENCE; | ||
14076 | bits = present ? HDA_AMP_MUTE : 0; | ||
14077 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, | ||
14078 | HDA_AMP_MUTE, bits); | ||
14079 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
14080 | HDA_AMP_MUTE, bits); | ||
14081 | } | ||
14082 | |||
14083 | static void alc663_g71v_front_automute(struct hda_codec *codec) | ||
14084 | { | ||
14085 | unsigned int present; | ||
14086 | unsigned char bits; | ||
14087 | |||
14088 | present = snd_hda_codec_read(codec, 0x15, 0, | ||
14089 | AC_VERB_GET_PIN_SENSE, 0) | ||
14090 | & AC_PINSENSE_PRESENCE; | ||
14091 | bits = present ? HDA_AMP_MUTE : 0; | ||
14092 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
14093 | HDA_AMP_MUTE, bits); | ||
14094 | } | ||
14095 | |||
14096 | static void alc663_g71v_unsol_event(struct hda_codec *codec, | ||
14097 | unsigned int res) | ||
14098 | { | ||
14099 | switch (res >> 26) { | ||
14100 | case ALC880_HP_EVENT: | ||
14101 | alc663_g71v_hp_automute(codec); | ||
14102 | break; | ||
14103 | case ALC880_FRONT_EVENT: | ||
14104 | alc663_g71v_front_automute(codec); | ||
14105 | break; | ||
14106 | case ALC880_MIC_EVENT: | ||
14107 | alc662_eeepc_mic_automute(codec); | ||
14108 | break; | ||
14109 | } | ||
14110 | } | ||
14111 | |||
14112 | static void alc663_g71v_inithook(struct hda_codec *codec) | ||
14113 | { | ||
14114 | alc663_g71v_front_automute(codec); | ||
14115 | alc663_g71v_hp_automute(codec); | ||
14116 | alc662_eeepc_mic_automute(codec); | ||
14117 | } | ||
14118 | |||
14119 | static void alc663_g50v_unsol_event(struct hda_codec *codec, | ||
14120 | unsigned int res) | ||
14121 | { | ||
14122 | switch (res >> 26) { | ||
14123 | case ALC880_HP_EVENT: | ||
14124 | alc663_m51va_speaker_automute(codec); | ||
14125 | break; | ||
14126 | case ALC880_MIC_EVENT: | ||
14127 | alc662_eeepc_mic_automute(codec); | ||
14128 | break; | ||
14129 | } | ||
14130 | } | ||
14131 | |||
14132 | static void alc663_g50v_inithook(struct hda_codec *codec) | ||
14133 | { | ||
14134 | alc663_m51va_speaker_automute(codec); | ||
14135 | alc662_eeepc_mic_automute(codec); | ||
14136 | } | ||
14137 | |||
13695 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 14138 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
13696 | #define alc662_loopbacks alc880_loopbacks | 14139 | #define alc662_loopbacks alc880_loopbacks |
13697 | #endif | 14140 | #endif |
@@ -13714,14 +14157,24 @@ static const char *alc662_models[ALC662_MODEL_LAST] = { | |||
13714 | [ALC662_LENOVO_101E] = "lenovo-101e", | 14157 | [ALC662_LENOVO_101E] = "lenovo-101e", |
13715 | [ALC662_ASUS_EEEPC_P701] = "eeepc-p701", | 14158 | [ALC662_ASUS_EEEPC_P701] = "eeepc-p701", |
13716 | [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20", | 14159 | [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20", |
14160 | [ALC663_ASUS_M51VA] = "m51va", | ||
14161 | [ALC663_ASUS_G71V] = "g71v", | ||
14162 | [ALC663_ASUS_H13] = "h13", | ||
14163 | [ALC663_ASUS_G50V] = "g50v", | ||
13717 | [ALC662_AUTO] = "auto", | 14164 | [ALC662_AUTO] = "auto", |
13718 | }; | 14165 | }; |
13719 | 14166 | ||
13720 | static struct snd_pci_quirk alc662_cfg_tbl[] = { | 14167 | static struct snd_pci_quirk alc662_cfg_tbl[] = { |
14168 | SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS G71V", ALC663_ASUS_G71V), | ||
14169 | SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA), | ||
14170 | SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS M51VA", ALC663_ASUS_G50V), | ||
13721 | SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG), | 14171 | SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG), |
13722 | SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701), | 14172 | SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701), |
13723 | SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20), | 14173 | SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20), |
13724 | SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E), | 14174 | SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E), |
14175 | SND_PCI_QUIRK(0x1854, 0x2000, "ASUS H13-2000", ALC663_ASUS_H13), | ||
14176 | SND_PCI_QUIRK(0x1854, 0x2001, "ASUS H13-2001", ALC663_ASUS_H13), | ||
14177 | SND_PCI_QUIRK(0x1854, 0x2002, "ASUS H13-2002", ALC663_ASUS_H13), | ||
13725 | {} | 14178 | {} |
13726 | }; | 14179 | }; |
13727 | 14180 | ||
@@ -13809,7 +14262,53 @@ static struct alc_config_preset alc662_presets[] = { | |||
13809 | .unsol_event = alc662_eeepc_ep20_unsol_event, | 14262 | .unsol_event = alc662_eeepc_ep20_unsol_event, |
13810 | .init_hook = alc662_eeepc_ep20_inithook, | 14263 | .init_hook = alc662_eeepc_ep20_inithook, |
13811 | }, | 14264 | }, |
13812 | 14265 | [ALC663_ASUS_M51VA] = { | |
14266 | .mixers = { alc663_m51va_mixer, alc662_capture_mixer}, | ||
14267 | .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs }, | ||
14268 | .num_dacs = ARRAY_SIZE(alc662_dac_nids), | ||
14269 | .dac_nids = alc662_dac_nids, | ||
14270 | .dig_out_nid = ALC662_DIGOUT_NID, | ||
14271 | .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), | ||
14272 | .channel_mode = alc662_3ST_2ch_modes, | ||
14273 | .input_mux = &alc663_m51va_capture_source, | ||
14274 | .unsol_event = alc663_m51va_unsol_event, | ||
14275 | .init_hook = alc663_m51va_inithook, | ||
14276 | }, | ||
14277 | [ALC663_ASUS_G71V] = { | ||
14278 | .mixers = { alc663_g71v_mixer, alc662_capture_mixer}, | ||
14279 | .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs }, | ||
14280 | .num_dacs = ARRAY_SIZE(alc662_dac_nids), | ||
14281 | .dac_nids = alc662_dac_nids, | ||
14282 | .dig_out_nid = ALC662_DIGOUT_NID, | ||
14283 | .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), | ||
14284 | .channel_mode = alc662_3ST_2ch_modes, | ||
14285 | .input_mux = &alc662_eeepc_capture_source, | ||
14286 | .unsol_event = alc663_g71v_unsol_event, | ||
14287 | .init_hook = alc663_g71v_inithook, | ||
14288 | }, | ||
14289 | [ALC663_ASUS_H13] = { | ||
14290 | .mixers = { alc663_m51va_mixer, alc662_capture_mixer}, | ||
14291 | .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs }, | ||
14292 | .num_dacs = ARRAY_SIZE(alc662_dac_nids), | ||
14293 | .dac_nids = alc662_dac_nids, | ||
14294 | .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), | ||
14295 | .channel_mode = alc662_3ST_2ch_modes, | ||
14296 | .input_mux = &alc663_m51va_capture_source, | ||
14297 | .unsol_event = alc663_m51va_unsol_event, | ||
14298 | .init_hook = alc663_m51va_inithook, | ||
14299 | }, | ||
14300 | [ALC663_ASUS_G50V] = { | ||
14301 | .mixers = { alc663_g50v_mixer, alc662_capture_mixer}, | ||
14302 | .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs }, | ||
14303 | .num_dacs = ARRAY_SIZE(alc662_dac_nids), | ||
14304 | .dac_nids = alc662_dac_nids, | ||
14305 | .dig_out_nid = ALC662_DIGOUT_NID, | ||
14306 | .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), | ||
14307 | .channel_mode = alc662_3ST_6ch_modes, | ||
14308 | .input_mux = &alc663_capture_source, | ||
14309 | .unsol_event = alc663_g50v_unsol_event, | ||
14310 | .init_hook = alc663_g50v_inithook, | ||
14311 | }, | ||
13813 | }; | 14312 | }; |
13814 | 14313 | ||
13815 | 14314 | ||
@@ -14082,6 +14581,8 @@ static int patch_alc662(struct hda_codec *codec) | |||
14082 | 14581 | ||
14083 | codec->spec = spec; | 14582 | codec->spec = spec; |
14084 | 14583 | ||
14584 | alc_fix_pll_init(codec, 0x20, 0x04, 15); | ||
14585 | |||
14085 | board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST, | 14586 | board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST, |
14086 | alc662_models, | 14587 | alc662_models, |
14087 | alc662_cfg_tbl); | 14588 | alc662_cfg_tbl); |
@@ -14108,11 +14609,17 @@ static int patch_alc662(struct hda_codec *codec) | |||
14108 | if (board_config != ALC662_AUTO) | 14609 | if (board_config != ALC662_AUTO) |
14109 | setup_preset(spec, &alc662_presets[board_config]); | 14610 | setup_preset(spec, &alc662_presets[board_config]); |
14110 | 14611 | ||
14111 | spec->stream_name_analog = "ALC662 Analog"; | 14612 | if (codec->vendor_id == 0x10ec0663) { |
14613 | spec->stream_name_analog = "ALC663 Analog"; | ||
14614 | spec->stream_name_digital = "ALC663 Digital"; | ||
14615 | } else { | ||
14616 | spec->stream_name_analog = "ALC662 Analog"; | ||
14617 | spec->stream_name_digital = "ALC662 Digital"; | ||
14618 | } | ||
14619 | |||
14112 | spec->stream_analog_playback = &alc662_pcm_analog_playback; | 14620 | spec->stream_analog_playback = &alc662_pcm_analog_playback; |
14113 | spec->stream_analog_capture = &alc662_pcm_analog_capture; | 14621 | spec->stream_analog_capture = &alc662_pcm_analog_capture; |
14114 | 14622 | ||
14115 | spec->stream_name_digital = "ALC662 Digital"; | ||
14116 | spec->stream_digital_playback = &alc662_pcm_digital_playback; | 14623 | spec->stream_digital_playback = &alc662_pcm_digital_playback; |
14117 | spec->stream_digital_capture = &alc662_pcm_digital_capture; | 14624 | spec->stream_digital_capture = &alc662_pcm_digital_capture; |
14118 | 14625 | ||
@@ -14151,6 +14658,7 @@ struct hda_codec_preset snd_hda_preset_realtek[] = { | |||
14151 | .patch = patch_alc883 }, | 14658 | .patch = patch_alc883 }, |
14152 | { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1", | 14659 | { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1", |
14153 | .patch = patch_alc662 }, | 14660 | .patch = patch_alc662 }, |
14661 | { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 }, | ||
14154 | { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, | 14662 | { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, |
14155 | { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, | 14663 | { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, |
14156 | { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 }, | 14664 | { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 }, |
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index a4f44a00bae8..08cb77f51880 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -636,21 +636,28 @@ static struct hda_verb stac92hd71bxx_core_init[] = { | |||
636 | { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 636 | { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
637 | }; | 637 | }; |
638 | 638 | ||
639 | #define HD_DISABLE_PORTF 3 | ||
639 | static struct hda_verb stac92hd71bxx_analog_core_init[] = { | 640 | static struct hda_verb stac92hd71bxx_analog_core_init[] = { |
641 | /* start of config #1 */ | ||
642 | |||
643 | /* connect port 0f to audio mixer */ | ||
644 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2}, | ||
645 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */ | ||
646 | /* unmute right and left channels for node 0x0f */ | ||
647 | { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
648 | /* start of config #2 */ | ||
649 | |||
640 | /* set master volume and direct control */ | 650 | /* set master volume and direct control */ |
641 | { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, | 651 | { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, |
642 | /* connect headphone jack to dac1 */ | 652 | /* connect headphone jack to dac1 */ |
643 | { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01}, | 653 | { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01}, |
644 | /* connect ports 0d and 0f to audio mixer */ | 654 | /* connect port 0d to audio mixer */ |
645 | { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2}, | 655 | { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2}, |
646 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2}, | ||
647 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */ | ||
648 | /* unmute dac0 input in audio mixer */ | 656 | /* unmute dac0 input in audio mixer */ |
649 | { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f}, | 657 | { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f}, |
650 | /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */ | 658 | /* unmute right and left channels for nodes 0x0a, 0xd */ |
651 | { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 659 | { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
652 | { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 660 | { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
653 | { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
654 | {} | 661 | {} |
655 | }; | 662 | }; |
656 | 663 | ||
@@ -818,6 +825,9 @@ static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = { | |||
818 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT), | 825 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT), |
819 | HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT), | 826 | HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT), |
820 | 827 | ||
828 | HDA_CODEC_VOLUME("PC Beep Volume", 0x17, 0x2, HDA_INPUT), | ||
829 | HDA_CODEC_MUTE("PC Beep Switch", 0x17, 0x2, HDA_INPUT), | ||
830 | |||
821 | HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT), | 831 | HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT), |
822 | HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT), | 832 | HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT), |
823 | { } /* end */ | 833 | { } /* end */ |
@@ -1317,13 +1327,13 @@ static unsigned int ref92hd71bxx_pin_configs[10] = { | |||
1317 | 0x90a000f0, 0x01452050, | 1327 | 0x90a000f0, 0x01452050, |
1318 | }; | 1328 | }; |
1319 | 1329 | ||
1320 | static unsigned int dell_m4_1_pin_configs[13] = { | 1330 | static unsigned int dell_m4_1_pin_configs[10] = { |
1321 | 0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110, | 1331 | 0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110, |
1322 | 0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0, | 1332 | 0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0, |
1323 | 0x40f000f0, 0x4f0000f0, | 1333 | 0x40f000f0, 0x4f0000f0, |
1324 | }; | 1334 | }; |
1325 | 1335 | ||
1326 | static unsigned int dell_m4_2_pin_configs[13] = { | 1336 | static unsigned int dell_m4_2_pin_configs[10] = { |
1327 | 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110, | 1337 | 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110, |
1328 | 0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0, | 1338 | 0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0, |
1329 | 0x40f000f0, 0x044413b0, | 1339 | 0x40f000f0, 0x044413b0, |
@@ -1754,12 +1764,8 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = { | |||
1754 | "unknown Dell", STAC_9205_DELL_M42), | 1764 | "unknown Dell", STAC_9205_DELL_M42), |
1755 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8, | 1765 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8, |
1756 | "Dell Precision", STAC_9205_DELL_M43), | 1766 | "Dell Precision", STAC_9205_DELL_M43), |
1757 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c, | ||
1758 | "Dell Precision", STAC_9205_DELL_M43), | ||
1759 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9, | 1767 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9, |
1760 | "Dell Precision", STAC_9205_DELL_M43), | 1768 | "Dell Precision", STAC_9205_DELL_M43), |
1761 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b, | ||
1762 | "Dell Precision", STAC_9205_DELL_M43), | ||
1763 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa, | 1769 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa, |
1764 | "Dell Precision", STAC_9205_DELL_M43), | 1770 | "Dell Precision", STAC_9205_DELL_M43), |
1765 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc, | 1771 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc, |
@@ -1770,18 +1776,14 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = { | |||
1770 | "Dell Precision", STAC_9205_DELL_M43), | 1776 | "Dell Precision", STAC_9205_DELL_M43), |
1771 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff, | 1777 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff, |
1772 | "Dell Precision M4300", STAC_9205_DELL_M43), | 1778 | "Dell Precision M4300", STAC_9205_DELL_M43), |
1773 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206, | ||
1774 | "Dell Precision", STAC_9205_DELL_M43), | ||
1775 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1, | ||
1776 | "Dell Inspiron", STAC_9205_DELL_M44), | ||
1777 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2, | ||
1778 | "Dell Inspiron", STAC_9205_DELL_M44), | ||
1779 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc, | ||
1780 | "Dell Inspiron", STAC_9205_DELL_M44), | ||
1781 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd, | ||
1782 | "Dell Inspiron", STAC_9205_DELL_M44), | ||
1783 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204, | 1779 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204, |
1784 | "unknown Dell", STAC_9205_DELL_M42), | 1780 | "unknown Dell", STAC_9205_DELL_M42), |
1781 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206, | ||
1782 | "Dell Precision", STAC_9205_DELL_M43), | ||
1783 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b, | ||
1784 | "Dell Precision", STAC_9205_DELL_M43), | ||
1785 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c, | ||
1786 | "Dell Precision", STAC_9205_DELL_M43), | ||
1785 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f, | 1787 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f, |
1786 | "Dell Inspiron", STAC_9205_DELL_M44), | 1788 | "Dell Inspiron", STAC_9205_DELL_M44), |
1787 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228, | 1789 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228, |
@@ -3103,13 +3105,16 @@ static int stac92xx_init(struct hda_codec *codec) | |||
3103 | 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | 3105 | 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); |
3104 | int def_conf = snd_hda_codec_read(codec, spec->pwr_nids[i], | 3106 | int def_conf = snd_hda_codec_read(codec, spec->pwr_nids[i], |
3105 | 0, AC_VERB_GET_CONFIG_DEFAULT, 0); | 3107 | 0, AC_VERB_GET_CONFIG_DEFAULT, 0); |
3108 | def_conf = get_defcfg_connect(def_conf); | ||
3106 | /* outputs are only ports capable of power management | 3109 | /* outputs are only ports capable of power management |
3107 | * any attempts on powering down a input port cause the | 3110 | * any attempts on powering down a input port cause the |
3108 | * referenced VREF to act quirky. | 3111 | * referenced VREF to act quirky. |
3109 | */ | 3112 | */ |
3110 | if (pinctl & AC_PINCTL_IN_EN) | 3113 | if (pinctl & AC_PINCTL_IN_EN) |
3111 | continue; | 3114 | continue; |
3112 | if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) | 3115 | /* skip any ports that don't have jacks since presence |
3116 | * detection is useless */ | ||
3117 | if (def_conf && def_conf != AC_JACK_PORT_FIXED) | ||
3113 | continue; | 3118 | continue; |
3114 | enable_pin_detect(codec, spec->pwr_nids[i], event | i); | 3119 | enable_pin_detect(codec, spec->pwr_nids[i], event | i); |
3115 | codec->patch_ops.unsol_event(codec, (event | i) << 26); | 3120 | codec->patch_ops.unsol_event(codec, (event | i) << 26); |
@@ -3614,6 +3619,7 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) | |||
3614 | 3619 | ||
3615 | codec->spec = spec; | 3620 | codec->spec = spec; |
3616 | spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids); | 3621 | spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids); |
3622 | spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids); | ||
3617 | spec->pin_nids = stac92hd71bxx_pin_nids; | 3623 | spec->pin_nids = stac92hd71bxx_pin_nids; |
3618 | spec->board_config = snd_hda_check_board_config(codec, | 3624 | spec->board_config = snd_hda_check_board_config(codec, |
3619 | STAC_92HD71BXX_MODELS, | 3625 | STAC_92HD71BXX_MODELS, |
@@ -3642,6 +3648,19 @@ again: | |||
3642 | spec->mixer = stac92hd71bxx_mixer; | 3648 | spec->mixer = stac92hd71bxx_mixer; |
3643 | spec->init = stac92hd71bxx_core_init; | 3649 | spec->init = stac92hd71bxx_core_init; |
3644 | break; | 3650 | break; |
3651 | case 0x111d7608: /* 5 Port with Analog Mixer */ | ||
3652 | /* no output amps */ | ||
3653 | spec->num_pwrs = 0; | ||
3654 | spec->mixer = stac92hd71bxx_analog_mixer; | ||
3655 | |||
3656 | /* disable VSW */ | ||
3657 | spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF]; | ||
3658 | stac92xx_set_config_reg(codec, 0xf, 0x40f000f0); | ||
3659 | break; | ||
3660 | case 0x111d7603: /* 6 Port with Analog Mixer */ | ||
3661 | /* no output amps */ | ||
3662 | spec->num_pwrs = 0; | ||
3663 | /* fallthru */ | ||
3645 | default: | 3664 | default: |
3646 | spec->mixer = stac92hd71bxx_analog_mixer; | 3665 | spec->mixer = stac92hd71bxx_analog_mixer; |
3647 | spec->init = stac92hd71bxx_analog_core_init; | 3666 | spec->init = stac92hd71bxx_analog_core_init; |
@@ -3653,22 +3672,19 @@ again: | |||
3653 | /* GPIO0 High = EAPD */ | 3672 | /* GPIO0 High = EAPD */ |
3654 | spec->gpio_mask = 0x01; | 3673 | spec->gpio_mask = 0x01; |
3655 | spec->gpio_dir = 0x01; | 3674 | spec->gpio_dir = 0x01; |
3656 | spec->gpio_mask = 0x01; | ||
3657 | spec->gpio_data = 0x01; | 3675 | spec->gpio_data = 0x01; |
3658 | 3676 | ||
3659 | spec->mux_nids = stac92hd71bxx_mux_nids; | 3677 | spec->mux_nids = stac92hd71bxx_mux_nids; |
3660 | spec->adc_nids = stac92hd71bxx_adc_nids; | 3678 | spec->adc_nids = stac92hd71bxx_adc_nids; |
3661 | spec->dmic_nids = stac92hd71bxx_dmic_nids; | 3679 | spec->dmic_nids = stac92hd71bxx_dmic_nids; |
3662 | spec->dmux_nids = stac92hd71bxx_dmux_nids; | 3680 | spec->dmux_nids = stac92hd71bxx_dmux_nids; |
3681 | spec->pwr_nids = stac92hd71bxx_pwr_nids; | ||
3663 | 3682 | ||
3664 | spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids); | 3683 | spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids); |
3665 | spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids); | 3684 | spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids); |
3666 | spec->num_dmics = STAC92HD71BXX_NUM_DMICS; | 3685 | spec->num_dmics = STAC92HD71BXX_NUM_DMICS; |
3667 | spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids); | 3686 | spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids); |
3668 | 3687 | ||
3669 | spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids); | ||
3670 | spec->pwr_nids = stac92hd71bxx_pwr_nids; | ||
3671 | |||
3672 | spec->multiout.num_dacs = 1; | 3688 | spec->multiout.num_dacs = 1; |
3673 | spec->multiout.hp_nid = 0x11; | 3689 | spec->multiout.hp_nid = 0x11; |
3674 | spec->multiout.dac_nids = stac92hd71bxx_dac_nids; | 3690 | spec->multiout.dac_nids = stac92hd71bxx_dac_nids; |
@@ -4306,10 +4322,11 @@ struct hda_codec_preset snd_hda_preset_sigmatel[] = { | |||
4306 | { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 }, | 4322 | { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 }, |
4307 | { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 }, | 4323 | { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 }, |
4308 | { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 }, | 4324 | { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 }, |
4325 | { .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx}, | ||
4326 | { .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx}, | ||
4309 | { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx }, | 4327 | { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx }, |
4310 | { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx }, | 4328 | { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx }, |
4311 | { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx }, | 4329 | { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx }, |
4312 | { .id = 0x111d7608, .name = "92HD71BXX", .patch = patch_stac92hd71bxx }, | ||
4313 | { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx }, | 4330 | { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx }, |
4314 | { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx }, | 4331 | { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx }, |
4315 | { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx }, | 4332 | { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx }, |
diff --git a/sound/pci/ice1712/envy24ht.h b/sound/pci/ice1712/envy24ht.h index 43b9e3e858be..a0c5e009bb4a 100644 --- a/sound/pci/ice1712/envy24ht.h +++ b/sound/pci/ice1712/envy24ht.h | |||
@@ -93,9 +93,13 @@ enum { | |||
93 | #define VT1724_REG_MPU_TXFIFO 0x0a /*byte ro. number of bytes in TX fifo*/ | 93 | #define VT1724_REG_MPU_TXFIFO 0x0a /*byte ro. number of bytes in TX fifo*/ |
94 | #define VT1724_REG_MPU_RXFIFO 0x0b /*byte ro. number of bytes in RX fifo*/ | 94 | #define VT1724_REG_MPU_RXFIFO 0x0b /*byte ro. number of bytes in RX fifo*/ |
95 | 95 | ||
96 | //are these 2 the wrong way around? they don't seem to be used yet anyway | 96 | #define VT1724_REG_MPU_DATA 0x0c /* byte */ |
97 | #define VT1724_REG_MPU_CTRL 0x0c /* byte */ | 97 | #define VT1724_REG_MPU_CTRL 0x0d /* byte */ |
98 | #define VT1724_REG_MPU_DATA 0x0d /* byte */ | 98 | #define VT1724_MPU_UART 0x01 |
99 | #define VT1724_MPU_TX_EMPTY 0x02 | ||
100 | #define VT1724_MPU_TX_FULL 0x04 | ||
101 | #define VT1724_MPU_RX_EMPTY 0x08 | ||
102 | #define VT1724_MPU_RX_FULL 0x10 | ||
99 | 103 | ||
100 | #define VT1724_REG_MPU_FIFO_WM 0x0e /*byte set the high/low watermarks for RX/TX fifos*/ | 104 | #define VT1724_REG_MPU_FIFO_WM 0x0e /*byte set the high/low watermarks for RX/TX fifos*/ |
101 | #define VT1724_MPU_RX_FIFO 0x20 //1=rx fifo watermark 0=tx fifo watermark | 105 | #define VT1724_MPU_RX_FIFO 0x20 //1=rx fifo watermark 0=tx fifo watermark |
diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index 3208901c740e..762fbd7a7507 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h | |||
@@ -333,6 +333,8 @@ struct snd_ice1712 { | |||
333 | unsigned int has_spdif: 1; /* VT1720/4 - has SPDIF I/O */ | 333 | unsigned int has_spdif: 1; /* VT1720/4 - has SPDIF I/O */ |
334 | unsigned int force_pdma4: 1; /* VT1720/4 - PDMA4 as non-spdif */ | 334 | unsigned int force_pdma4: 1; /* VT1720/4 - PDMA4 as non-spdif */ |
335 | unsigned int force_rdma1: 1; /* VT1720/4 - RDMA1 as non-spdif */ | 335 | unsigned int force_rdma1: 1; /* VT1720/4 - RDMA1 as non-spdif */ |
336 | unsigned int midi_output: 1; /* VT1720/4: MIDI output triggered */ | ||
337 | unsigned int midi_input: 1; /* VT1720/4: MIDI input triggered */ | ||
336 | unsigned int num_total_dacs; /* total DACs */ | 338 | unsigned int num_total_dacs; /* total DACs */ |
337 | unsigned int num_total_adcs; /* total ADCs */ | 339 | unsigned int num_total_adcs; /* total ADCs */ |
338 | unsigned int cur_rate; /* current rate */ | 340 | unsigned int cur_rate; /* current rate */ |
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 67350901772c..e596d777d9dd 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c | |||
@@ -32,7 +32,7 @@ | |||
32 | #include <linux/mutex.h> | 32 | #include <linux/mutex.h> |
33 | #include <sound/core.h> | 33 | #include <sound/core.h> |
34 | #include <sound/info.h> | 34 | #include <sound/info.h> |
35 | #include <sound/mpu401.h> | 35 | #include <sound/rawmidi.h> |
36 | #include <sound/initval.h> | 36 | #include <sound/initval.h> |
37 | 37 | ||
38 | #include <sound/asoundef.h> | 38 | #include <sound/asoundef.h> |
@@ -223,30 +223,153 @@ static unsigned int snd_vt1724_get_gpio_data(struct snd_ice1712 *ice) | |||
223 | } | 223 | } |
224 | 224 | ||
225 | /* | 225 | /* |
226 | * MPU401 accessor | 226 | * MIDI |
227 | */ | 227 | */ |
228 | static unsigned char snd_vt1724_mpu401_read(struct snd_mpu401 *mpu, | 228 | |
229 | unsigned long addr) | 229 | static void vt1724_midi_clear_rx(struct snd_ice1712 *ice) |
230 | { | ||
231 | unsigned int count; | ||
232 | |||
233 | for (count = inb(ICEREG1724(ice, MPU_RXFIFO)); count > 0; --count) | ||
234 | inb(ICEREG1724(ice, MPU_DATA)); | ||
235 | } | ||
236 | |||
237 | static inline struct snd_rawmidi_substream * | ||
238 | get_rawmidi_substream(struct snd_ice1712 *ice, unsigned int stream) | ||
230 | { | 239 | { |
231 | /* fix status bits to the standard position */ | 240 | return list_first_entry(&ice->rmidi[0]->streams[stream].substreams, |
232 | /* only RX_EMPTY and TX_FULL are checked */ | 241 | struct snd_rawmidi_substream, list); |
233 | if (addr == MPU401C(mpu)) | 242 | } |
234 | return (inb(addr) & 0x0c) << 4; | 243 | |
244 | static void vt1724_midi_write(struct snd_ice1712 *ice) | ||
245 | { | ||
246 | struct snd_rawmidi_substream *s; | ||
247 | int count, i; | ||
248 | u8 buffer[32]; | ||
249 | |||
250 | s = get_rawmidi_substream(ice, SNDRV_RAWMIDI_STREAM_OUTPUT); | ||
251 | count = 31 - inb(ICEREG1724(ice, MPU_TXFIFO)); | ||
252 | if (count > 0) { | ||
253 | count = snd_rawmidi_transmit(s, buffer, count); | ||
254 | for (i = 0; i < count; ++i) | ||
255 | outb(buffer[i], ICEREG1724(ice, MPU_DATA)); | ||
256 | } | ||
257 | } | ||
258 | |||
259 | static void vt1724_midi_read(struct snd_ice1712 *ice) | ||
260 | { | ||
261 | struct snd_rawmidi_substream *s; | ||
262 | int count, i; | ||
263 | u8 buffer[32]; | ||
264 | |||
265 | s = get_rawmidi_substream(ice, SNDRV_RAWMIDI_STREAM_INPUT); | ||
266 | count = inb(ICEREG1724(ice, MPU_RXFIFO)); | ||
267 | if (count > 0) { | ||
268 | count = min(count, 32); | ||
269 | for (i = 0; i < count; ++i) | ||
270 | buffer[i] = inb(ICEREG1724(ice, MPU_DATA)); | ||
271 | snd_rawmidi_receive(s, buffer, count); | ||
272 | } | ||
273 | } | ||
274 | |||
275 | static void vt1724_enable_midi_irq(struct snd_rawmidi_substream *substream, | ||
276 | u8 flag, int enable) | ||
277 | { | ||
278 | struct snd_ice1712 *ice = substream->rmidi->private_data; | ||
279 | u8 mask; | ||
280 | |||
281 | spin_lock_irq(&ice->reg_lock); | ||
282 | mask = inb(ICEREG1724(ice, IRQMASK)); | ||
283 | if (enable) | ||
284 | mask &= ~flag; | ||
235 | else | 285 | else |
236 | return inb(addr); | 286 | mask |= flag; |
287 | outb(mask, ICEREG1724(ice, IRQMASK)); | ||
288 | spin_unlock_irq(&ice->reg_lock); | ||
237 | } | 289 | } |
238 | 290 | ||
239 | static void snd_vt1724_mpu401_write(struct snd_mpu401 *mpu, | 291 | static int vt1724_midi_output_open(struct snd_rawmidi_substream *s) |
240 | unsigned char data, unsigned long addr) | ||
241 | { | 292 | { |
242 | if (addr == MPU401C(mpu)) { | 293 | vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_TX, 1); |
243 | if (data == MPU401_ENTER_UART) | 294 | return 0; |
244 | outb(0x01, addr); | 295 | } |
245 | /* what else? */ | 296 | |
246 | } else | 297 | static int vt1724_midi_output_close(struct snd_rawmidi_substream *s) |
247 | outb(data, addr); | 298 | { |
299 | vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_TX, 0); | ||
300 | return 0; | ||
248 | } | 301 | } |
249 | 302 | ||
303 | static void vt1724_midi_output_trigger(struct snd_rawmidi_substream *s, int up) | ||
304 | { | ||
305 | struct snd_ice1712 *ice = s->rmidi->private_data; | ||
306 | unsigned long flags; | ||
307 | |||
308 | spin_lock_irqsave(&ice->reg_lock, flags); | ||
309 | if (up) { | ||
310 | ice->midi_output = 1; | ||
311 | vt1724_midi_write(ice); | ||
312 | } else { | ||
313 | ice->midi_output = 0; | ||
314 | } | ||
315 | spin_unlock_irqrestore(&ice->reg_lock, flags); | ||
316 | } | ||
317 | |||
318 | static void vt1724_midi_output_drain(struct snd_rawmidi_substream *s) | ||
319 | { | ||
320 | struct snd_ice1712 *ice = s->rmidi->private_data; | ||
321 | unsigned long timeout; | ||
322 | |||
323 | /* 32 bytes should be transmitted in less than about 12 ms */ | ||
324 | timeout = jiffies + msecs_to_jiffies(15); | ||
325 | do { | ||
326 | if (inb(ICEREG1724(ice, MPU_CTRL)) & VT1724_MPU_TX_EMPTY) | ||
327 | break; | ||
328 | schedule_timeout_uninterruptible(1); | ||
329 | } while (time_after(timeout, jiffies)); | ||
330 | } | ||
331 | |||
332 | static struct snd_rawmidi_ops vt1724_midi_output_ops = { | ||
333 | .open = vt1724_midi_output_open, | ||
334 | .close = vt1724_midi_output_close, | ||
335 | .trigger = vt1724_midi_output_trigger, | ||
336 | .drain = vt1724_midi_output_drain, | ||
337 | }; | ||
338 | |||
339 | static int vt1724_midi_input_open(struct snd_rawmidi_substream *s) | ||
340 | { | ||
341 | vt1724_midi_clear_rx(s->rmidi->private_data); | ||
342 | vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_RX, 1); | ||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | static int vt1724_midi_input_close(struct snd_rawmidi_substream *s) | ||
347 | { | ||
348 | vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_RX, 0); | ||
349 | return 0; | ||
350 | } | ||
351 | |||
352 | static void vt1724_midi_input_trigger(struct snd_rawmidi_substream *s, int up) | ||
353 | { | ||
354 | struct snd_ice1712 *ice = s->rmidi->private_data; | ||
355 | unsigned long flags; | ||
356 | |||
357 | spin_lock_irqsave(&ice->reg_lock, flags); | ||
358 | if (up) { | ||
359 | ice->midi_input = 1; | ||
360 | vt1724_midi_read(ice); | ||
361 | } else { | ||
362 | ice->midi_input = 0; | ||
363 | } | ||
364 | spin_unlock_irqrestore(&ice->reg_lock, flags); | ||
365 | } | ||
366 | |||
367 | static struct snd_rawmidi_ops vt1724_midi_input_ops = { | ||
368 | .open = vt1724_midi_input_open, | ||
369 | .close = vt1724_midi_input_close, | ||
370 | .trigger = vt1724_midi_input_trigger, | ||
371 | }; | ||
372 | |||
250 | 373 | ||
251 | /* | 374 | /* |
252 | * Interrupt handler | 375 | * Interrupt handler |
@@ -278,13 +401,10 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id) | |||
278 | #endif | 401 | #endif |
279 | handled = 1; | 402 | handled = 1; |
280 | if (status & VT1724_IRQ_MPU_TX) { | 403 | if (status & VT1724_IRQ_MPU_TX) { |
281 | if (ice->rmidi[0]) | 404 | spin_lock(&ice->reg_lock); |
282 | snd_mpu401_uart_interrupt_tx(irq, | 405 | if (ice->midi_output) |
283 | ice->rmidi[0]->private_data); | 406 | vt1724_midi_write(ice); |
284 | else /* disable TX to be sure */ | 407 | spin_unlock(&ice->reg_lock); |
285 | outb(inb(ICEREG1724(ice, IRQMASK)) | | ||
286 | VT1724_IRQ_MPU_TX, | ||
287 | ICEREG1724(ice, IRQMASK)); | ||
288 | /* Due to mysterical reasons, MPU_TX is always | 408 | /* Due to mysterical reasons, MPU_TX is always |
289 | * generated (and can't be cleared) when a PCM | 409 | * generated (and can't be cleared) when a PCM |
290 | * playback is going. So let's ignore at the | 410 | * playback is going. So let's ignore at the |
@@ -293,13 +413,12 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id) | |||
293 | status_mask &= ~VT1724_IRQ_MPU_TX; | 413 | status_mask &= ~VT1724_IRQ_MPU_TX; |
294 | } | 414 | } |
295 | if (status & VT1724_IRQ_MPU_RX) { | 415 | if (status & VT1724_IRQ_MPU_RX) { |
296 | if (ice->rmidi[0]) | 416 | spin_lock(&ice->reg_lock); |
297 | snd_mpu401_uart_interrupt(irq, | 417 | if (ice->midi_input) |
298 | ice->rmidi[0]->private_data); | 418 | vt1724_midi_read(ice); |
299 | else /* disable RX to be sure */ | 419 | else |
300 | outb(inb(ICEREG1724(ice, IRQMASK)) | | 420 | vt1724_midi_clear_rx(ice); |
301 | VT1724_IRQ_MPU_RX, | 421 | spin_unlock(&ice->reg_lock); |
302 | ICEREG1724(ice, IRQMASK)); | ||
303 | } | 422 | } |
304 | /* ack MPU irq */ | 423 | /* ack MPU irq */ |
305 | outb(status, ICEREG1724(ice, IRQSTAT)); | 424 | outb(status, ICEREG1724(ice, IRQSTAT)); |
@@ -2425,28 +2544,30 @@ static int __devinit snd_vt1724_probe(struct pci_dev *pci, | |||
2425 | 2544 | ||
2426 | if (! c->no_mpu401) { | 2545 | if (! c->no_mpu401) { |
2427 | if (ice->eeprom.data[ICE_EEP2_SYSCONF] & VT1724_CFG_MPU401) { | 2546 | if (ice->eeprom.data[ICE_EEP2_SYSCONF] & VT1724_CFG_MPU401) { |
2428 | struct snd_mpu401 *mpu; | 2547 | struct snd_rawmidi *rmidi; |
2429 | if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712, | 2548 | |
2430 | ICEREG1724(ice, MPU_CTRL), | 2549 | err = snd_rawmidi_new(card, "MIDI", 0, 1, 1, &rmidi); |
2431 | (MPU401_INFO_INTEGRATED | | 2550 | if (err < 0) { |
2432 | MPU401_INFO_NO_ACK | | ||
2433 | MPU401_INFO_TX_IRQ), | ||
2434 | ice->irq, 0, | ||
2435 | &ice->rmidi[0])) < 0) { | ||
2436 | snd_card_free(card); | 2551 | snd_card_free(card); |
2437 | return err; | 2552 | return err; |
2438 | } | 2553 | } |
2439 | mpu = ice->rmidi[0]->private_data; | 2554 | ice->rmidi[0] = rmidi; |
2440 | mpu->read = snd_vt1724_mpu401_read; | 2555 | rmidi->private_data = ice; |
2441 | mpu->write = snd_vt1724_mpu401_write; | 2556 | strcpy(rmidi->name, "ICE1724 MIDI"); |
2442 | /* unmask MPU RX/TX irqs */ | 2557 | rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | |
2443 | outb(inb(ICEREG1724(ice, IRQMASK)) & | 2558 | SNDRV_RAWMIDI_INFO_INPUT | |
2444 | ~(VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX), | 2559 | SNDRV_RAWMIDI_INFO_DUPLEX; |
2445 | ICEREG1724(ice, IRQMASK)); | 2560 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, |
2561 | &vt1724_midi_output_ops); | ||
2562 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, | ||
2563 | &vt1724_midi_input_ops); | ||
2564 | |||
2446 | /* set watermarks */ | 2565 | /* set watermarks */ |
2447 | outb(VT1724_MPU_RX_FIFO | 0x1, | 2566 | outb(VT1724_MPU_RX_FIFO | 0x1, |
2448 | ICEREG1724(ice, MPU_FIFO_WM)); | 2567 | ICEREG1724(ice, MPU_FIFO_WM)); |
2449 | outb(0x1, ICEREG1724(ice, MPU_FIFO_WM)); | 2568 | outb(0x1, ICEREG1724(ice, MPU_FIFO_WM)); |
2569 | /* set UART mode */ | ||
2570 | outb(VT1724_MPU_UART, ICEREG1724(ice, MPU_CTRL)); | ||
2450 | } | 2571 | } |
2451 | } | 2572 | } |
2452 | 2573 | ||
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index a536c59fbea1..f4788dee05c3 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c | |||
@@ -2427,6 +2427,29 @@ snd_m3_amp_enable(struct snd_m3 *chip, int enable) | |||
2427 | outw(0xffff, io + GPIO_MASK); | 2427 | outw(0xffff, io + GPIO_MASK); |
2428 | } | 2428 | } |
2429 | 2429 | ||
2430 | static void | ||
2431 | snd_m3_hv_init(struct snd_m3 *chip) | ||
2432 | { | ||
2433 | unsigned long io = chip->iobase; | ||
2434 | u16 val = GPI_VOL_DOWN | GPI_VOL_UP; | ||
2435 | |||
2436 | if (!chip->is_omnibook) | ||
2437 | return; | ||
2438 | |||
2439 | /* | ||
2440 | * Volume buttons on some HP OmniBook laptops | ||
2441 | * require some GPIO magic to work correctly. | ||
2442 | */ | ||
2443 | outw(0xffff, io + GPIO_MASK); | ||
2444 | outw(0x0000, io + GPIO_DATA); | ||
2445 | |||
2446 | outw(~val, io + GPIO_MASK); | ||
2447 | outw(inw(io + GPIO_DIRECTION) & ~val, io + GPIO_DIRECTION); | ||
2448 | outw(val, io + GPIO_MASK); | ||
2449 | |||
2450 | outw(0xffff, io + GPIO_MASK); | ||
2451 | } | ||
2452 | |||
2430 | static int | 2453 | static int |
2431 | snd_m3_chip_init(struct snd_m3 *chip) | 2454 | snd_m3_chip_init(struct snd_m3 *chip) |
2432 | { | 2455 | { |
@@ -2442,21 +2465,6 @@ snd_m3_chip_init(struct snd_m3 *chip) | |||
2442 | DISABLE_LEGACY); | 2465 | DISABLE_LEGACY); |
2443 | pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w); | 2466 | pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w); |
2444 | 2467 | ||
2445 | if (chip->is_omnibook) { | ||
2446 | /* | ||
2447 | * Volume buttons on some HP OmniBook laptops don't work | ||
2448 | * correctly. This makes them work for the most part. | ||
2449 | * | ||
2450 | * Volume up and down buttons on the laptop side work. | ||
2451 | * Fn+cursor_up (volme up) works. | ||
2452 | * Fn+cursor_down (volume down) doesn't work. | ||
2453 | * Fn+F7 (mute) works acts as volume up. | ||
2454 | */ | ||
2455 | outw(~(GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_MASK); | ||
2456 | outw(inw(io + GPIO_DIRECTION) & ~(GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_DIRECTION); | ||
2457 | outw((GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_DATA); | ||
2458 | outw(0xffff, io + GPIO_MASK); | ||
2459 | } | ||
2460 | pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n); | 2468 | pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n); |
2461 | n &= ~(HV_CTRL_ENABLE | REDUCED_DEBOUNCE | HV_BUTTON_FROM_GD); | 2469 | n &= ~(HV_CTRL_ENABLE | REDUCED_DEBOUNCE | HV_BUTTON_FROM_GD); |
2462 | n |= chip->hv_config; | 2470 | n |= chip->hv_config; |
@@ -2642,6 +2650,8 @@ static int m3_resume(struct pci_dev *pci) | |||
2642 | snd_m3_enable_ints(chip); | 2650 | snd_m3_enable_ints(chip); |
2643 | snd_m3_amp_enable(chip, 1); | 2651 | snd_m3_amp_enable(chip, 1); |
2644 | 2652 | ||
2653 | snd_m3_hv_init(chip); | ||
2654 | |||
2645 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | 2655 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); |
2646 | return 0; | 2656 | return 0; |
2647 | } | 2657 | } |
@@ -2781,6 +2791,8 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, | |||
2781 | 2791 | ||
2782 | snd_m3_amp_enable(chip, 1); | 2792 | snd_m3_amp_enable(chip, 1); |
2783 | 2793 | ||
2794 | snd_m3_hv_init(chip); | ||
2795 | |||
2784 | tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip); | 2796 | tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip); |
2785 | 2797 | ||
2786 | if (request_irq(pci->irq, snd_m3_interrupt, IRQF_SHARED, | 2798 | if (request_irq(pci->irq, snd_m3_interrupt, IRQF_SHARED, |
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 7efb838d18a6..06d13e717114 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c | |||
@@ -1302,8 +1302,8 @@ snd_nm256_mixer(struct nm256 *chip) | |||
1302 | .read = snd_nm256_ac97_read, | 1302 | .read = snd_nm256_ac97_read, |
1303 | }; | 1303 | }; |
1304 | 1304 | ||
1305 | chip->ac97_regs = kcalloc(sizeof(short), | 1305 | chip->ac97_regs = kcalloc(ARRAY_SIZE(nm256_ac97_init_val), |
1306 | ARRAY_SIZE(nm256_ac97_init_val), GFP_KERNEL); | 1306 | sizeof(short), GFP_KERNEL); |
1307 | if (! chip->ac97_regs) | 1307 | if (! chip->ac97_regs) |
1308 | return -ENOMEM; | 1308 | return -ENOMEM; |
1309 | 1309 | ||
diff --git a/sound/pci/oxygen/hifier.c b/sound/pci/oxygen/hifier.c index 090dd4354a28..7442460583dd 100644 --- a/sound/pci/oxygen/hifier.c +++ b/sound/pci/oxygen/hifier.c | |||
@@ -28,7 +28,7 @@ | |||
28 | 28 | ||
29 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | 29 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); |
30 | MODULE_DESCRIPTION("TempoTec HiFier driver"); | 30 | MODULE_DESCRIPTION("TempoTec HiFier driver"); |
31 | MODULE_LICENSE("GPL"); | 31 | MODULE_LICENSE("GPL v2"); |
32 | 32 | ||
33 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | 33 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; |
34 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | 34 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; |
@@ -62,16 +62,28 @@ static void ak4396_write(struct oxygen *chip, u8 reg, u8 value) | |||
62 | AK4396_WRITE | (reg << 8) | value); | 62 | AK4396_WRITE | (reg << 8) | value); |
63 | } | 63 | } |
64 | 64 | ||
65 | static void hifier_init(struct oxygen *chip) | 65 | static void update_ak4396_volume(struct oxygen *chip) |
66 | { | ||
67 | ak4396_write(chip, AK4396_LCH_ATT, chip->dac_volume[0]); | ||
68 | ak4396_write(chip, AK4396_RCH_ATT, chip->dac_volume[1]); | ||
69 | } | ||
70 | |||
71 | static void hifier_registers_init(struct oxygen *chip) | ||
66 | { | 72 | { |
67 | struct hifier_data *data = chip->model_data; | 73 | struct hifier_data *data = chip->model_data; |
68 | 74 | ||
69 | data->ak4396_ctl2 = AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL; | ||
70 | ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); | 75 | ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); |
71 | ak4396_write(chip, AK4396_CONTROL_2, data->ak4396_ctl2); | 76 | ak4396_write(chip, AK4396_CONTROL_2, data->ak4396_ctl2); |
72 | ak4396_write(chip, AK4396_CONTROL_3, AK4396_PCM); | 77 | ak4396_write(chip, AK4396_CONTROL_3, AK4396_PCM); |
73 | ak4396_write(chip, AK4396_LCH_ATT, 0); | 78 | update_ak4396_volume(chip); |
74 | ak4396_write(chip, AK4396_RCH_ATT, 0); | 79 | } |
80 | |||
81 | static void hifier_init(struct oxygen *chip) | ||
82 | { | ||
83 | struct hifier_data *data = chip->model_data; | ||
84 | |||
85 | data->ak4396_ctl2 = AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL; | ||
86 | hifier_registers_init(chip); | ||
75 | 87 | ||
76 | snd_component_add(chip->card, "AK4396"); | 88 | snd_component_add(chip->card, "AK4396"); |
77 | snd_component_add(chip->card, "CS5340"); | 89 | snd_component_add(chip->card, "CS5340"); |
@@ -100,12 +112,6 @@ static void set_ak4396_params(struct oxygen *chip, | |||
100 | ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); | 112 | ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); |
101 | } | 113 | } |
102 | 114 | ||
103 | static void update_ak4396_volume(struct oxygen *chip) | ||
104 | { | ||
105 | ak4396_write(chip, AK4396_LCH_ATT, chip->dac_volume[0]); | ||
106 | ak4396_write(chip, AK4396_RCH_ATT, chip->dac_volume[1]); | ||
107 | } | ||
108 | |||
109 | static void update_ak4396_mute(struct oxygen *chip) | 115 | static void update_ak4396_mute(struct oxygen *chip) |
110 | { | 116 | { |
111 | struct hifier_data *data = chip->model_data; | 117 | struct hifier_data *data = chip->model_data; |
@@ -140,6 +146,7 @@ static const struct oxygen_model model_hifier = { | |||
140 | .init = hifier_init, | 146 | .init = hifier_init, |
141 | .control_filter = hifier_control_filter, | 147 | .control_filter = hifier_control_filter, |
142 | .cleanup = hifier_cleanup, | 148 | .cleanup = hifier_cleanup, |
149 | .resume = hifier_registers_init, | ||
143 | .set_dac_params = set_ak4396_params, | 150 | .set_dac_params = set_ak4396_params, |
144 | .set_adc_params = set_cs5340_params, | 151 | .set_adc_params = set_cs5340_params, |
145 | .update_dac_volume = update_ak4396_volume, | 152 | .update_dac_volume = update_ak4396_volume, |
@@ -180,6 +187,10 @@ static struct pci_driver hifier_driver = { | |||
180 | .id_table = hifier_ids, | 187 | .id_table = hifier_ids, |
181 | .probe = hifier_probe, | 188 | .probe = hifier_probe, |
182 | .remove = __devexit_p(oxygen_pci_remove), | 189 | .remove = __devexit_p(oxygen_pci_remove), |
190 | #ifdef CONFIG_PM | ||
191 | .suspend = oxygen_pci_suspend, | ||
192 | .resume = oxygen_pci_resume, | ||
193 | #endif | ||
183 | }; | 194 | }; |
184 | 195 | ||
185 | static int __init alsa_card_hifier_init(void) | 196 | static int __init alsa_card_hifier_init(void) |
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index 63f185c1ed1e..7c8ae31eb468 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c | |||
@@ -43,7 +43,7 @@ | |||
43 | 43 | ||
44 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | 44 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); |
45 | MODULE_DESCRIPTION("C-Media CMI8788 driver"); | 45 | MODULE_DESCRIPTION("C-Media CMI8788 driver"); |
46 | MODULE_LICENSE("GPL"); | 46 | MODULE_LICENSE("GPL v2"); |
47 | MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8788}}"); | 47 | MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8788}}"); |
48 | 48 | ||
49 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | 49 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; |
@@ -80,6 +80,7 @@ MODULE_DEVICE_TABLE(pci, oxygen_ids); | |||
80 | 80 | ||
81 | struct generic_data { | 81 | struct generic_data { |
82 | u8 ak4396_ctl2; | 82 | u8 ak4396_ctl2; |
83 | u16 saved_wm8785_registers[2]; | ||
83 | }; | 84 | }; |
84 | 85 | ||
85 | static void ak4396_write(struct oxygen *chip, unsigned int codec, | 86 | static void ak4396_write(struct oxygen *chip, unsigned int codec, |
@@ -99,20 +100,35 @@ static void ak4396_write(struct oxygen *chip, unsigned int codec, | |||
99 | 100 | ||
100 | static void wm8785_write(struct oxygen *chip, u8 reg, unsigned int value) | 101 | static void wm8785_write(struct oxygen *chip, u8 reg, unsigned int value) |
101 | { | 102 | { |
103 | struct generic_data *data = chip->model_data; | ||
104 | |||
102 | oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | | 105 | oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | |
103 | OXYGEN_SPI_DATA_LENGTH_2 | | 106 | OXYGEN_SPI_DATA_LENGTH_2 | |
104 | OXYGEN_SPI_CLOCK_160 | | 107 | OXYGEN_SPI_CLOCK_160 | |
105 | (3 << OXYGEN_SPI_CODEC_SHIFT) | | 108 | (3 << OXYGEN_SPI_CODEC_SHIFT) | |
106 | OXYGEN_SPI_CEN_LATCH_CLOCK_LO, | 109 | OXYGEN_SPI_CEN_LATCH_CLOCK_LO, |
107 | (reg << 9) | value); | 110 | (reg << 9) | value); |
111 | if (reg < ARRAY_SIZE(data->saved_wm8785_registers)) | ||
112 | data->saved_wm8785_registers[reg] = value; | ||
108 | } | 113 | } |
109 | 114 | ||
110 | static void ak4396_init(struct oxygen *chip) | 115 | static void update_ak4396_volume(struct oxygen *chip) |
116 | { | ||
117 | unsigned int i; | ||
118 | |||
119 | for (i = 0; i < 4; ++i) { | ||
120 | ak4396_write(chip, i, | ||
121 | AK4396_LCH_ATT, chip->dac_volume[i * 2]); | ||
122 | ak4396_write(chip, i, | ||
123 | AK4396_RCH_ATT, chip->dac_volume[i * 2 + 1]); | ||
124 | } | ||
125 | } | ||
126 | |||
127 | static void ak4396_registers_init(struct oxygen *chip) | ||
111 | { | 128 | { |
112 | struct generic_data *data = chip->model_data; | 129 | struct generic_data *data = chip->model_data; |
113 | unsigned int i; | 130 | unsigned int i; |
114 | 131 | ||
115 | data->ak4396_ctl2 = AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL; | ||
116 | for (i = 0; i < 4; ++i) { | 132 | for (i = 0; i < 4; ++i) { |
117 | ak4396_write(chip, i, | 133 | ak4396_write(chip, i, |
118 | AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); | 134 | AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); |
@@ -120,9 +136,16 @@ static void ak4396_init(struct oxygen *chip) | |||
120 | AK4396_CONTROL_2, data->ak4396_ctl2); | 136 | AK4396_CONTROL_2, data->ak4396_ctl2); |
121 | ak4396_write(chip, i, | 137 | ak4396_write(chip, i, |
122 | AK4396_CONTROL_3, AK4396_PCM); | 138 | AK4396_CONTROL_3, AK4396_PCM); |
123 | ak4396_write(chip, i, AK4396_LCH_ATT, 0); | ||
124 | ak4396_write(chip, i, AK4396_RCH_ATT, 0); | ||
125 | } | 139 | } |
140 | update_ak4396_volume(chip); | ||
141 | } | ||
142 | |||
143 | static void ak4396_init(struct oxygen *chip) | ||
144 | { | ||
145 | struct generic_data *data = chip->model_data; | ||
146 | |||
147 | data->ak4396_ctl2 = AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL; | ||
148 | ak4396_registers_init(chip); | ||
126 | snd_component_add(chip->card, "AK4396"); | 149 | snd_component_add(chip->card, "AK4396"); |
127 | } | 150 | } |
128 | 151 | ||
@@ -133,12 +156,23 @@ static void ak5385_init(struct oxygen *chip) | |||
133 | snd_component_add(chip->card, "AK5385"); | 156 | snd_component_add(chip->card, "AK5385"); |
134 | } | 157 | } |
135 | 158 | ||
136 | static void wm8785_init(struct oxygen *chip) | 159 | static void wm8785_registers_init(struct oxygen *chip) |
137 | { | 160 | { |
161 | struct generic_data *data = chip->model_data; | ||
162 | |||
138 | wm8785_write(chip, WM8785_R7, 0); | 163 | wm8785_write(chip, WM8785_R7, 0); |
139 | wm8785_write(chip, WM8785_R0, WM8785_MCR_SLAVE | | 164 | wm8785_write(chip, WM8785_R0, data->saved_wm8785_registers[0]); |
140 | WM8785_OSR_SINGLE | WM8785_FORMAT_LJUST); | 165 | wm8785_write(chip, WM8785_R1, data->saved_wm8785_registers[1]); |
141 | wm8785_write(chip, WM8785_R1, WM8785_WL_24); | 166 | } |
167 | |||
168 | static void wm8785_init(struct oxygen *chip) | ||
169 | { | ||
170 | struct generic_data *data = chip->model_data; | ||
171 | |||
172 | data->saved_wm8785_registers[0] = WM8785_MCR_SLAVE | | ||
173 | WM8785_OSR_SINGLE | WM8785_FORMAT_LJUST; | ||
174 | data->saved_wm8785_registers[1] = WM8785_WL_24; | ||
175 | wm8785_registers_init(chip); | ||
142 | snd_component_add(chip->card, "WM8785"); | 176 | snd_component_add(chip->card, "WM8785"); |
143 | } | 177 | } |
144 | 178 | ||
@@ -158,6 +192,12 @@ static void generic_cleanup(struct oxygen *chip) | |||
158 | { | 192 | { |
159 | } | 193 | } |
160 | 194 | ||
195 | static void generic_resume(struct oxygen *chip) | ||
196 | { | ||
197 | ak4396_registers_init(chip); | ||
198 | wm8785_registers_init(chip); | ||
199 | } | ||
200 | |||
161 | static void set_ak4396_params(struct oxygen *chip, | 201 | static void set_ak4396_params(struct oxygen *chip, |
162 | struct snd_pcm_hw_params *params) | 202 | struct snd_pcm_hw_params *params) |
163 | { | 203 | { |
@@ -183,18 +223,6 @@ static void set_ak4396_params(struct oxygen *chip, | |||
183 | } | 223 | } |
184 | } | 224 | } |
185 | 225 | ||
186 | static void update_ak4396_volume(struct oxygen *chip) | ||
187 | { | ||
188 | unsigned int i; | ||
189 | |||
190 | for (i = 0; i < 4; ++i) { | ||
191 | ak4396_write(chip, i, | ||
192 | AK4396_LCH_ATT, chip->dac_volume[i * 2]); | ||
193 | ak4396_write(chip, i, | ||
194 | AK4396_RCH_ATT, chip->dac_volume[i * 2 + 1]); | ||
195 | } | ||
196 | } | ||
197 | |||
198 | static void update_ak4396_mute(struct oxygen *chip) | 226 | static void update_ak4396_mute(struct oxygen *chip) |
199 | { | 227 | { |
200 | struct generic_data *data = chip->model_data; | 228 | struct generic_data *data = chip->model_data; |
@@ -256,6 +284,7 @@ static const struct oxygen_model model_generic = { | |||
256 | .owner = THIS_MODULE, | 284 | .owner = THIS_MODULE, |
257 | .init = generic_init, | 285 | .init = generic_init, |
258 | .cleanup = generic_cleanup, | 286 | .cleanup = generic_cleanup, |
287 | .resume = generic_resume, | ||
259 | .set_dac_params = set_ak4396_params, | 288 | .set_dac_params = set_ak4396_params, |
260 | .set_adc_params = set_wm8785_params, | 289 | .set_adc_params = set_wm8785_params, |
261 | .update_dac_volume = update_ak4396_volume, | 290 | .update_dac_volume = update_ak4396_volume, |
@@ -283,6 +312,7 @@ static const struct oxygen_model model_meridian = { | |||
283 | .owner = THIS_MODULE, | 312 | .owner = THIS_MODULE, |
284 | .init = meridian_init, | 313 | .init = meridian_init, |
285 | .cleanup = generic_cleanup, | 314 | .cleanup = generic_cleanup, |
315 | .resume = ak4396_registers_init, | ||
286 | .set_dac_params = set_ak4396_params, | 316 | .set_dac_params = set_ak4396_params, |
287 | .set_adc_params = set_ak5385_params, | 317 | .set_adc_params = set_ak5385_params, |
288 | .update_dac_volume = update_ak4396_volume, | 318 | .update_dac_volume = update_ak4396_volume, |
@@ -331,6 +361,10 @@ static struct pci_driver oxygen_driver = { | |||
331 | .id_table = oxygen_ids, | 361 | .id_table = oxygen_ids, |
332 | .probe = generic_oxygen_probe, | 362 | .probe = generic_oxygen_probe, |
333 | .remove = __devexit_p(oxygen_pci_remove), | 363 | .remove = __devexit_p(oxygen_pci_remove), |
364 | #ifdef CONFIG_PM | ||
365 | .suspend = oxygen_pci_suspend, | ||
366 | .resume = oxygen_pci_resume, | ||
367 | #endif | ||
334 | }; | 368 | }; |
335 | 369 | ||
336 | static int __init alsa_card_oxygen_init(void) | 370 | static int __init alsa_card_oxygen_init(void) |
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h index a71c6e059260..74a644880074 100644 --- a/sound/pci/oxygen/oxygen.h +++ b/sound/pci/oxygen/oxygen.h | |||
@@ -16,6 +16,8 @@ | |||
16 | #define PCM_AC97 5 | 16 | #define PCM_AC97 5 |
17 | #define PCM_COUNT 6 | 17 | #define PCM_COUNT 6 |
18 | 18 | ||
19 | #define OXYGEN_IO_SIZE 0x100 | ||
20 | |||
19 | /* model-specific configuration of outputs/inputs */ | 21 | /* model-specific configuration of outputs/inputs */ |
20 | #define PLAYBACK_0_TO_I2S 0x001 | 22 | #define PLAYBACK_0_TO_I2S 0x001 |
21 | #define PLAYBACK_1_TO_SPDIF 0x004 | 23 | #define PLAYBACK_1_TO_SPDIF 0x004 |
@@ -78,6 +80,12 @@ struct oxygen { | |||
78 | struct work_struct spdif_input_bits_work; | 80 | struct work_struct spdif_input_bits_work; |
79 | struct work_struct gpio_work; | 81 | struct work_struct gpio_work; |
80 | wait_queue_head_t ac97_waitqueue; | 82 | wait_queue_head_t ac97_waitqueue; |
83 | union { | ||
84 | u8 _8[OXYGEN_IO_SIZE]; | ||
85 | __le16 _16[OXYGEN_IO_SIZE / 2]; | ||
86 | __le32 _32[OXYGEN_IO_SIZE / 4]; | ||
87 | } saved_registers; | ||
88 | u16 saved_ac97_registers[2][0x40]; | ||
81 | }; | 89 | }; |
82 | 90 | ||
83 | struct oxygen_model { | 91 | struct oxygen_model { |
@@ -89,6 +97,8 @@ struct oxygen_model { | |||
89 | int (*control_filter)(struct snd_kcontrol_new *template); | 97 | int (*control_filter)(struct snd_kcontrol_new *template); |
90 | int (*mixer_init)(struct oxygen *chip); | 98 | int (*mixer_init)(struct oxygen *chip); |
91 | void (*cleanup)(struct oxygen *chip); | 99 | void (*cleanup)(struct oxygen *chip); |
100 | void (*suspend)(struct oxygen *chip); | ||
101 | void (*resume)(struct oxygen *chip); | ||
92 | void (*pcm_hardware_filter)(unsigned int channel, | 102 | void (*pcm_hardware_filter)(unsigned int channel, |
93 | struct snd_pcm_hardware *hardware); | 103 | struct snd_pcm_hardware *hardware); |
94 | void (*set_dac_params)(struct oxygen *chip, | 104 | void (*set_dac_params)(struct oxygen *chip, |
@@ -117,6 +127,10 @@ struct oxygen_model { | |||
117 | int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, | 127 | int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, |
118 | const struct oxygen_model *model); | 128 | const struct oxygen_model *model); |
119 | void oxygen_pci_remove(struct pci_dev *pci); | 129 | void oxygen_pci_remove(struct pci_dev *pci); |
130 | #ifdef CONFIG_PM | ||
131 | int oxygen_pci_suspend(struct pci_dev *pci, pm_message_t state); | ||
132 | int oxygen_pci_resume(struct pci_dev *pci); | ||
133 | #endif | ||
120 | 134 | ||
121 | /* oxygen_mixer.c */ | 135 | /* oxygen_mixer.c */ |
122 | 136 | ||
diff --git a/sound/pci/oxygen/oxygen_io.c b/sound/pci/oxygen/oxygen_io.c index 5569606ee87f..83f135f80df4 100644 --- a/sound/pci/oxygen/oxygen_io.c +++ b/sound/pci/oxygen/oxygen_io.c | |||
@@ -44,18 +44,21 @@ EXPORT_SYMBOL(oxygen_read32); | |||
44 | void oxygen_write8(struct oxygen *chip, unsigned int reg, u8 value) | 44 | void oxygen_write8(struct oxygen *chip, unsigned int reg, u8 value) |
45 | { | 45 | { |
46 | outb(value, chip->addr + reg); | 46 | outb(value, chip->addr + reg); |
47 | chip->saved_registers._8[reg] = value; | ||
47 | } | 48 | } |
48 | EXPORT_SYMBOL(oxygen_write8); | 49 | EXPORT_SYMBOL(oxygen_write8); |
49 | 50 | ||
50 | void oxygen_write16(struct oxygen *chip, unsigned int reg, u16 value) | 51 | void oxygen_write16(struct oxygen *chip, unsigned int reg, u16 value) |
51 | { | 52 | { |
52 | outw(value, chip->addr + reg); | 53 | outw(value, chip->addr + reg); |
54 | chip->saved_registers._16[reg / 2] = cpu_to_le16(value); | ||
53 | } | 55 | } |
54 | EXPORT_SYMBOL(oxygen_write16); | 56 | EXPORT_SYMBOL(oxygen_write16); |
55 | 57 | ||
56 | void oxygen_write32(struct oxygen *chip, unsigned int reg, u32 value) | 58 | void oxygen_write32(struct oxygen *chip, unsigned int reg, u32 value) |
57 | { | 59 | { |
58 | outl(value, chip->addr + reg); | 60 | outl(value, chip->addr + reg); |
61 | chip->saved_registers._32[reg / 4] = cpu_to_le32(value); | ||
59 | } | 62 | } |
60 | EXPORT_SYMBOL(oxygen_write32); | 63 | EXPORT_SYMBOL(oxygen_write32); |
61 | 64 | ||
@@ -63,7 +66,10 @@ void oxygen_write8_masked(struct oxygen *chip, unsigned int reg, | |||
63 | u8 value, u8 mask) | 66 | u8 value, u8 mask) |
64 | { | 67 | { |
65 | u8 tmp = inb(chip->addr + reg); | 68 | u8 tmp = inb(chip->addr + reg); |
66 | outb((tmp & ~mask) | (value & mask), chip->addr + reg); | 69 | tmp &= ~mask; |
70 | tmp |= value & mask; | ||
71 | outb(tmp, chip->addr + reg); | ||
72 | chip->saved_registers._8[reg] = tmp; | ||
67 | } | 73 | } |
68 | EXPORT_SYMBOL(oxygen_write8_masked); | 74 | EXPORT_SYMBOL(oxygen_write8_masked); |
69 | 75 | ||
@@ -71,7 +77,10 @@ void oxygen_write16_masked(struct oxygen *chip, unsigned int reg, | |||
71 | u16 value, u16 mask) | 77 | u16 value, u16 mask) |
72 | { | 78 | { |
73 | u16 tmp = inw(chip->addr + reg); | 79 | u16 tmp = inw(chip->addr + reg); |
74 | outw((tmp & ~mask) | (value & mask), chip->addr + reg); | 80 | tmp &= ~mask; |
81 | tmp |= value & mask; | ||
82 | outw(tmp, chip->addr + reg); | ||
83 | chip->saved_registers._16[reg / 2] = cpu_to_le16(tmp); | ||
75 | } | 84 | } |
76 | EXPORT_SYMBOL(oxygen_write16_masked); | 85 | EXPORT_SYMBOL(oxygen_write16_masked); |
77 | 86 | ||
@@ -79,7 +88,10 @@ void oxygen_write32_masked(struct oxygen *chip, unsigned int reg, | |||
79 | u32 value, u32 mask) | 88 | u32 value, u32 mask) |
80 | { | 89 | { |
81 | u32 tmp = inl(chip->addr + reg); | 90 | u32 tmp = inl(chip->addr + reg); |
82 | outl((tmp & ~mask) | (value & mask), chip->addr + reg); | 91 | tmp &= ~mask; |
92 | tmp |= value & mask; | ||
93 | outl(tmp, chip->addr + reg); | ||
94 | chip->saved_registers._32[reg / 4] = cpu_to_le32(tmp); | ||
83 | } | 95 | } |
84 | EXPORT_SYMBOL(oxygen_write32_masked); | 96 | EXPORT_SYMBOL(oxygen_write32_masked); |
85 | 97 | ||
@@ -128,8 +140,10 @@ void oxygen_write_ac97(struct oxygen *chip, unsigned int codec, | |||
128 | oxygen_write32(chip, OXYGEN_AC97_REGS, reg); | 140 | oxygen_write32(chip, OXYGEN_AC97_REGS, reg); |
129 | /* require two "completed" writes, just to be sure */ | 141 | /* require two "completed" writes, just to be sure */ |
130 | if (oxygen_ac97_wait(chip, OXYGEN_AC97_INT_WRITE_DONE) >= 0 && | 142 | if (oxygen_ac97_wait(chip, OXYGEN_AC97_INT_WRITE_DONE) >= 0 && |
131 | ++succeeded >= 2) | 143 | ++succeeded >= 2) { |
144 | chip->saved_ac97_registers[codec][index / 2] = data; | ||
132 | return; | 145 | return; |
146 | } | ||
133 | } | 147 | } |
134 | snd_printk(KERN_ERR "AC'97 write timeout\n"); | 148 | snd_printk(KERN_ERR "AC'97 write timeout\n"); |
135 | } | 149 | } |
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index 897697d43506..22f37851045e 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c | |||
@@ -32,7 +32,7 @@ | |||
32 | 32 | ||
33 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | 33 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); |
34 | MODULE_DESCRIPTION("C-Media CMI8788 helper library"); | 34 | MODULE_DESCRIPTION("C-Media CMI8788 helper library"); |
35 | MODULE_LICENSE("GPL"); | 35 | MODULE_LICENSE("GPL v2"); |
36 | 36 | ||
37 | 37 | ||
38 | static irqreturn_t oxygen_interrupt(int dummy, void *dev_id) | 38 | static irqreturn_t oxygen_interrupt(int dummy, void *dev_id) |
@@ -173,7 +173,7 @@ static void oxygen_proc_read(struct snd_info_entry *entry, | |||
173 | int i, j; | 173 | int i, j; |
174 | 174 | ||
175 | snd_iprintf(buffer, "CMI8788\n\n"); | 175 | snd_iprintf(buffer, "CMI8788\n\n"); |
176 | for (i = 0; i < 0x100; i += 0x10) { | 176 | for (i = 0; i < OXYGEN_IO_SIZE; i += 0x10) { |
177 | snd_iprintf(buffer, "%02x:", i); | 177 | snd_iprintf(buffer, "%02x:", i); |
178 | for (j = 0; j < 0x10; ++j) | 178 | for (j = 0; j < 0x10; ++j) |
179 | snd_iprintf(buffer, " %02x", oxygen_read8(chip, i + j)); | 179 | snd_iprintf(buffer, " %02x", oxygen_read8(chip, i + j)); |
@@ -314,6 +314,10 @@ static void oxygen_init(struct oxygen *chip) | |||
314 | OXYGEN_SPDIF_LOCK_MASK | | 314 | OXYGEN_SPDIF_LOCK_MASK | |
315 | OXYGEN_SPDIF_RATE_MASK); | 315 | OXYGEN_SPDIF_RATE_MASK); |
316 | oxygen_write32(chip, OXYGEN_SPDIF_OUTPUT_BITS, chip->spdif_bits); | 316 | oxygen_write32(chip, OXYGEN_SPDIF_OUTPUT_BITS, chip->spdif_bits); |
317 | oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, | ||
318 | OXYGEN_2WIRE_LENGTH_8 | | ||
319 | OXYGEN_2WIRE_INTERRUPT_MASK | | ||
320 | OXYGEN_2WIRE_SPEED_STANDARD); | ||
317 | oxygen_clear_bits8(chip, OXYGEN_MPU401_CONTROL, OXYGEN_MPU401_LOOPBACK); | 321 | oxygen_clear_bits8(chip, OXYGEN_MPU401_CONTROL, OXYGEN_MPU401_LOOPBACK); |
318 | oxygen_write8(chip, OXYGEN_GPI_INTERRUPT_MASK, 0); | 322 | oxygen_write8(chip, OXYGEN_GPI_INTERRUPT_MASK, 0); |
319 | oxygen_write16(chip, OXYGEN_GPIO_INTERRUPT_MASK, 0); | 323 | oxygen_write16(chip, OXYGEN_GPIO_INTERRUPT_MASK, 0); |
@@ -455,7 +459,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, | |||
455 | } | 459 | } |
456 | 460 | ||
457 | if (!(pci_resource_flags(pci, 0) & IORESOURCE_IO) || | 461 | if (!(pci_resource_flags(pci, 0) & IORESOURCE_IO) || |
458 | pci_resource_len(pci, 0) < 0x100) { | 462 | pci_resource_len(pci, 0) < OXYGEN_IO_SIZE) { |
459 | snd_printk(KERN_ERR "invalid PCI I/O range\n"); | 463 | snd_printk(KERN_ERR "invalid PCI I/O range\n"); |
460 | err = -ENXIO; | 464 | err = -ENXIO; |
461 | goto err_pci_regions; | 465 | goto err_pci_regions; |
@@ -534,3 +538,99 @@ void oxygen_pci_remove(struct pci_dev *pci) | |||
534 | pci_set_drvdata(pci, NULL); | 538 | pci_set_drvdata(pci, NULL); |
535 | } | 539 | } |
536 | EXPORT_SYMBOL(oxygen_pci_remove); | 540 | EXPORT_SYMBOL(oxygen_pci_remove); |
541 | |||
542 | #ifdef CONFIG_PM | ||
543 | int oxygen_pci_suspend(struct pci_dev *pci, pm_message_t state) | ||
544 | { | ||
545 | struct snd_card *card = pci_get_drvdata(pci); | ||
546 | struct oxygen *chip = card->private_data; | ||
547 | unsigned int i, saved_interrupt_mask; | ||
548 | |||
549 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | ||
550 | |||
551 | for (i = 0; i < PCM_COUNT; ++i) | ||
552 | if (chip->streams[i]) | ||
553 | snd_pcm_suspend(chip->streams[i]); | ||
554 | |||
555 | if (chip->model->suspend) | ||
556 | chip->model->suspend(chip); | ||
557 | |||
558 | spin_lock_irq(&chip->reg_lock); | ||
559 | saved_interrupt_mask = chip->interrupt_mask; | ||
560 | chip->interrupt_mask = 0; | ||
561 | oxygen_write16(chip, OXYGEN_DMA_STATUS, 0); | ||
562 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0); | ||
563 | spin_unlock_irq(&chip->reg_lock); | ||
564 | |||
565 | synchronize_irq(chip->irq); | ||
566 | flush_scheduled_work(); | ||
567 | chip->interrupt_mask = saved_interrupt_mask; | ||
568 | |||
569 | pci_disable_device(pci); | ||
570 | pci_save_state(pci); | ||
571 | pci_set_power_state(pci, pci_choose_state(pci, state)); | ||
572 | return 0; | ||
573 | } | ||
574 | EXPORT_SYMBOL(oxygen_pci_suspend); | ||
575 | |||
576 | static const u32 registers_to_restore[OXYGEN_IO_SIZE / 32] = { | ||
577 | 0xffffffff, 0x00ff077f, 0x00011d08, 0x007f00ff, | ||
578 | 0x00300000, 0x00000fe4, 0x0ff7001f, 0x00000000 | ||
579 | }; | ||
580 | static const u32 ac97_registers_to_restore[2][0x40 / 32] = { | ||
581 | { 0x18284fa2, 0x03060000 }, | ||
582 | { 0x00007fa6, 0x00200000 } | ||
583 | }; | ||
584 | |||
585 | static inline int is_bit_set(const u32 *bitmap, unsigned int bit) | ||
586 | { | ||
587 | return bitmap[bit / 32] & (1 << (bit & 31)); | ||
588 | } | ||
589 | |||
590 | static void oxygen_restore_ac97(struct oxygen *chip, unsigned int codec) | ||
591 | { | ||
592 | unsigned int i; | ||
593 | |||
594 | oxygen_write_ac97(chip, codec, AC97_RESET, 0); | ||
595 | msleep(1); | ||
596 | for (i = 1; i < 0x40; ++i) | ||
597 | if (is_bit_set(ac97_registers_to_restore[codec], i)) | ||
598 | oxygen_write_ac97(chip, codec, i * 2, | ||
599 | chip->saved_ac97_registers[codec][i]); | ||
600 | } | ||
601 | |||
602 | int oxygen_pci_resume(struct pci_dev *pci) | ||
603 | { | ||
604 | struct snd_card *card = pci_get_drvdata(pci); | ||
605 | struct oxygen *chip = card->private_data; | ||
606 | unsigned int i; | ||
607 | |||
608 | pci_set_power_state(pci, PCI_D0); | ||
609 | pci_restore_state(pci); | ||
610 | if (pci_enable_device(pci) < 0) { | ||
611 | snd_printk(KERN_ERR "cannot reenable device"); | ||
612 | snd_card_disconnect(card); | ||
613 | return -EIO; | ||
614 | } | ||
615 | pci_set_master(pci); | ||
616 | |||
617 | oxygen_write16(chip, OXYGEN_DMA_STATUS, 0); | ||
618 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0); | ||
619 | for (i = 0; i < OXYGEN_IO_SIZE; ++i) | ||
620 | if (is_bit_set(registers_to_restore, i)) | ||
621 | oxygen_write8(chip, i, chip->saved_registers._8[i]); | ||
622 | if (chip->has_ac97_0) | ||
623 | oxygen_restore_ac97(chip, 0); | ||
624 | if (chip->has_ac97_1) | ||
625 | oxygen_restore_ac97(chip, 1); | ||
626 | |||
627 | if (chip->model->resume) | ||
628 | chip->model->resume(chip); | ||
629 | |||
630 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask); | ||
631 | |||
632 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | ||
633 | return 0; | ||
634 | } | ||
635 | EXPORT_SYMBOL(oxygen_pci_resume); | ||
636 | #endif /* CONFIG_PM */ | ||
diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c index b17c405e069d..c4ad65a3406f 100644 --- a/sound/pci/oxygen/oxygen_pcm.c +++ b/sound/pci/oxygen/oxygen_pcm.c | |||
@@ -24,6 +24,16 @@ | |||
24 | #include <sound/pcm_params.h> | 24 | #include <sound/pcm_params.h> |
25 | #include "oxygen.h" | 25 | #include "oxygen.h" |
26 | 26 | ||
27 | /* most DMA channels have a 16-bit counter for 32-bit words */ | ||
28 | #define BUFFER_BYTES_MAX ((1 << 16) * 4) | ||
29 | /* the multichannel DMA channel has a 24-bit counter */ | ||
30 | #define BUFFER_BYTES_MAX_MULTICH ((1 << 24) * 4) | ||
31 | |||
32 | #define PERIOD_BYTES_MIN 64 | ||
33 | |||
34 | #define DEFAULT_BUFFER_BYTES (BUFFER_BYTES_MAX / 2) | ||
35 | #define DEFAULT_BUFFER_BYTES_MULTICH (1024 * 1024) | ||
36 | |||
27 | static const struct snd_pcm_hardware oxygen_stereo_hardware = { | 37 | static const struct snd_pcm_hardware oxygen_stereo_hardware = { |
28 | .info = SNDRV_PCM_INFO_MMAP | | 38 | .info = SNDRV_PCM_INFO_MMAP | |
29 | SNDRV_PCM_INFO_MMAP_VALID | | 39 | SNDRV_PCM_INFO_MMAP_VALID | |
@@ -44,11 +54,11 @@ static const struct snd_pcm_hardware oxygen_stereo_hardware = { | |||
44 | .rate_max = 192000, | 54 | .rate_max = 192000, |
45 | .channels_min = 2, | 55 | .channels_min = 2, |
46 | .channels_max = 2, | 56 | .channels_max = 2, |
47 | .buffer_bytes_max = 256 * 1024, | 57 | .buffer_bytes_max = BUFFER_BYTES_MAX, |
48 | .period_bytes_min = 128, | 58 | .period_bytes_min = PERIOD_BYTES_MIN, |
49 | .period_bytes_max = 128 * 1024, | 59 | .period_bytes_max = BUFFER_BYTES_MAX / 2, |
50 | .periods_min = 2, | 60 | .periods_min = 2, |
51 | .periods_max = 2048, | 61 | .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, |
52 | }; | 62 | }; |
53 | static const struct snd_pcm_hardware oxygen_multichannel_hardware = { | 63 | static const struct snd_pcm_hardware oxygen_multichannel_hardware = { |
54 | .info = SNDRV_PCM_INFO_MMAP | | 64 | .info = SNDRV_PCM_INFO_MMAP | |
@@ -70,11 +80,11 @@ static const struct snd_pcm_hardware oxygen_multichannel_hardware = { | |||
70 | .rate_max = 192000, | 80 | .rate_max = 192000, |
71 | .channels_min = 2, | 81 | .channels_min = 2, |
72 | .channels_max = 8, | 82 | .channels_max = 8, |
73 | .buffer_bytes_max = 2048 * 1024, | 83 | .buffer_bytes_max = BUFFER_BYTES_MAX_MULTICH, |
74 | .period_bytes_min = 128, | 84 | .period_bytes_min = PERIOD_BYTES_MIN, |
75 | .period_bytes_max = 256 * 1024, | 85 | .period_bytes_max = BUFFER_BYTES_MAX_MULTICH / 2, |
76 | .periods_min = 2, | 86 | .periods_min = 2, |
77 | .periods_max = 16384, | 87 | .periods_max = BUFFER_BYTES_MAX_MULTICH / PERIOD_BYTES_MIN, |
78 | }; | 88 | }; |
79 | static const struct snd_pcm_hardware oxygen_ac97_hardware = { | 89 | static const struct snd_pcm_hardware oxygen_ac97_hardware = { |
80 | .info = SNDRV_PCM_INFO_MMAP | | 90 | .info = SNDRV_PCM_INFO_MMAP | |
@@ -88,11 +98,11 @@ static const struct snd_pcm_hardware oxygen_ac97_hardware = { | |||
88 | .rate_max = 48000, | 98 | .rate_max = 48000, |
89 | .channels_min = 2, | 99 | .channels_min = 2, |
90 | .channels_max = 2, | 100 | .channels_max = 2, |
91 | .buffer_bytes_max = 256 * 1024, | 101 | .buffer_bytes_max = BUFFER_BYTES_MAX, |
92 | .period_bytes_min = 128, | 102 | .period_bytes_min = PERIOD_BYTES_MIN, |
93 | .period_bytes_max = 128 * 1024, | 103 | .period_bytes_max = BUFFER_BYTES_MAX / 2, |
94 | .periods_min = 2, | 104 | .periods_min = 2, |
95 | .periods_max = 2048, | 105 | .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, |
96 | }; | 106 | }; |
97 | 107 | ||
98 | static const struct snd_pcm_hardware *const oxygen_hardware[PCM_COUNT] = { | 108 | static const struct snd_pcm_hardware *const oxygen_hardware[PCM_COUNT] = { |
@@ -155,6 +165,12 @@ static int oxygen_open(struct snd_pcm_substream *substream, | |||
155 | if (err < 0) | 165 | if (err < 0) |
156 | return err; | 166 | return err; |
157 | } | 167 | } |
168 | if (channel == PCM_MULTICH) { | ||
169 | err = snd_pcm_hw_constraint_minmax | ||
170 | (runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 0, 8192000); | ||
171 | if (err < 0) | ||
172 | return err; | ||
173 | } | ||
158 | snd_pcm_set_sync(substream); | 174 | snd_pcm_set_sync(substream); |
159 | chip->streams[channel] = substream; | 175 | chip->streams[channel] = substream; |
160 | 176 | ||
@@ -517,6 +533,7 @@ static int oxygen_trigger(struct snd_pcm_substream *substream, int cmd) | |||
517 | switch (cmd) { | 533 | switch (cmd) { |
518 | case SNDRV_PCM_TRIGGER_STOP: | 534 | case SNDRV_PCM_TRIGGER_STOP: |
519 | case SNDRV_PCM_TRIGGER_START: | 535 | case SNDRV_PCM_TRIGGER_START: |
536 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
520 | pausing = 0; | 537 | pausing = 0; |
521 | break; | 538 | break; |
522 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 539 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
@@ -663,12 +680,14 @@ int oxygen_pcm_init(struct oxygen *chip) | |||
663 | snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream, | 680 | snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream, |
664 | SNDRV_DMA_TYPE_DEV, | 681 | SNDRV_DMA_TYPE_DEV, |
665 | snd_dma_pci_data(chip->pci), | 682 | snd_dma_pci_data(chip->pci), |
666 | 512 * 1024, 2048 * 1024); | 683 | DEFAULT_BUFFER_BYTES_MULTICH, |
684 | BUFFER_BYTES_MAX_MULTICH); | ||
667 | if (ins) | 685 | if (ins) |
668 | snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream, | 686 | snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream, |
669 | SNDRV_DMA_TYPE_DEV, | 687 | SNDRV_DMA_TYPE_DEV, |
670 | snd_dma_pci_data(chip->pci), | 688 | snd_dma_pci_data(chip->pci), |
671 | 128 * 1024, 256 * 1024); | 689 | DEFAULT_BUFFER_BYTES, |
690 | BUFFER_BYTES_MAX); | ||
672 | } | 691 | } |
673 | 692 | ||
674 | outs = !!(chip->model->pcm_dev_cfg & PLAYBACK_1_TO_SPDIF); | 693 | outs = !!(chip->model->pcm_dev_cfg & PLAYBACK_1_TO_SPDIF); |
@@ -688,7 +707,8 @@ int oxygen_pcm_init(struct oxygen *chip) | |||
688 | strcpy(pcm->name, "Digital"); | 707 | strcpy(pcm->name, "Digital"); |
689 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | 708 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, |
690 | snd_dma_pci_data(chip->pci), | 709 | snd_dma_pci_data(chip->pci), |
691 | 128 * 1024, 256 * 1024); | 710 | DEFAULT_BUFFER_BYTES, |
711 | BUFFER_BYTES_MAX); | ||
692 | } | 712 | } |
693 | 713 | ||
694 | if (chip->has_ac97_1) { | 714 | if (chip->has_ac97_1) { |
@@ -718,7 +738,8 @@ int oxygen_pcm_init(struct oxygen *chip) | |||
718 | strcpy(pcm->name, outs ? "Front Panel" : "Analog 2"); | 738 | strcpy(pcm->name, outs ? "Front Panel" : "Analog 2"); |
719 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | 739 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, |
720 | snd_dma_pci_data(chip->pci), | 740 | snd_dma_pci_data(chip->pci), |
721 | 128 * 1024, 256 * 1024); | 741 | DEFAULT_BUFFER_BYTES, |
742 | BUFFER_BYTES_MAX); | ||
722 | } | 743 | } |
723 | return 0; | 744 | return 0; |
724 | } | 745 | } |
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index 7f84fa5deca2..9a2c16bf94e0 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c | |||
@@ -79,7 +79,7 @@ | |||
79 | 79 | ||
80 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | 80 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); |
81 | MODULE_DESCRIPTION("Asus AVx00 driver"); | 81 | MODULE_DESCRIPTION("Asus AVx00 driver"); |
82 | MODULE_LICENSE("GPL"); | 82 | MODULE_LICENSE("GPL v2"); |
83 | MODULE_SUPPORTED_DEVICE("{{Asus,AV100},{Asus,AV200}}"); | 83 | MODULE_SUPPORTED_DEVICE("{{Asus,AV100},{Asus,AV200}}"); |
84 | 84 | ||
85 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | 85 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; |
@@ -132,6 +132,9 @@ struct xonar_data { | |||
132 | u8 ext_power_int_reg; | 132 | u8 ext_power_int_reg; |
133 | u8 ext_power_bit; | 133 | u8 ext_power_bit; |
134 | u8 has_power; | 134 | u8 has_power; |
135 | u8 pcm1796_oversampling; | ||
136 | u8 cs4398_fm; | ||
137 | u8 cs4362a_fm; | ||
135 | }; | 138 | }; |
136 | 139 | ||
137 | static void pcm1796_write(struct oxygen *chip, unsigned int codec, | 140 | static void pcm1796_write(struct oxygen *chip, unsigned int codec, |
@@ -159,6 +162,14 @@ static void cs4362a_write(struct oxygen *chip, u8 reg, u8 value) | |||
159 | oxygen_write_i2c(chip, I2C_DEVICE_CS4362A, reg, value); | 162 | oxygen_write_i2c(chip, I2C_DEVICE_CS4362A, reg, value); |
160 | } | 163 | } |
161 | 164 | ||
165 | static void xonar_enable_output(struct oxygen *chip) | ||
166 | { | ||
167 | struct xonar_data *data = chip->model_data; | ||
168 | |||
169 | msleep(data->anti_pop_delay); | ||
170 | oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit); | ||
171 | } | ||
172 | |||
162 | static void xonar_common_init(struct oxygen *chip) | 173 | static void xonar_common_init(struct oxygen *chip) |
163 | { | 174 | { |
164 | struct xonar_data *data = chip->model_data; | 175 | struct xonar_data *data = chip->model_data; |
@@ -170,32 +181,59 @@ static void xonar_common_init(struct oxygen *chip) | |||
170 | data->has_power = !!(oxygen_read8(chip, data->ext_power_reg) | 181 | data->has_power = !!(oxygen_read8(chip, data->ext_power_reg) |
171 | & data->ext_power_bit); | 182 | & data->ext_power_bit); |
172 | } | 183 | } |
173 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CS53x1_M_MASK); | 184 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, |
185 | GPIO_CS53x1_M_MASK | data->output_enable_bit); | ||
174 | oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, | 186 | oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, |
175 | GPIO_CS53x1_M_SINGLE, GPIO_CS53x1_M_MASK); | 187 | GPIO_CS53x1_M_SINGLE, GPIO_CS53x1_M_MASK); |
176 | oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC); | 188 | oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC); |
177 | msleep(data->anti_pop_delay); | 189 | xonar_enable_output(chip); |
178 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, data->output_enable_bit); | ||
179 | oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit); | ||
180 | } | 190 | } |
181 | 191 | ||
182 | static void xonar_d2_init(struct oxygen *chip) | 192 | static void update_pcm1796_volume(struct oxygen *chip) |
183 | { | 193 | { |
184 | struct xonar_data *data = chip->model_data; | ||
185 | unsigned int i; | 194 | unsigned int i; |
186 | 195 | ||
187 | data->anti_pop_delay = 300; | 196 | for (i = 0; i < 4; ++i) { |
188 | data->output_enable_bit = GPIO_D2_OUTPUT_ENABLE; | 197 | pcm1796_write(chip, i, 16, chip->dac_volume[i * 2]); |
198 | pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1]); | ||
199 | } | ||
200 | } | ||
201 | |||
202 | static void update_pcm1796_mute(struct oxygen *chip) | ||
203 | { | ||
204 | unsigned int i; | ||
205 | u8 value; | ||
206 | |||
207 | value = PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD; | ||
208 | if (chip->dac_mute) | ||
209 | value |= PCM1796_MUTE; | ||
210 | for (i = 0; i < 4; ++i) | ||
211 | pcm1796_write(chip, i, 18, value); | ||
212 | } | ||
213 | |||
214 | static void pcm1796_init(struct oxygen *chip) | ||
215 | { | ||
216 | struct xonar_data *data = chip->model_data; | ||
217 | unsigned int i; | ||
189 | 218 | ||
190 | for (i = 0; i < 4; ++i) { | 219 | for (i = 0; i < 4; ++i) { |
191 | pcm1796_write(chip, i, 18, PCM1796_MUTE | PCM1796_DMF_DISABLED | | ||
192 | PCM1796_FMT_24_LJUST | PCM1796_ATLD); | ||
193 | pcm1796_write(chip, i, 19, PCM1796_FLT_SHARP | PCM1796_ATS_1); | 220 | pcm1796_write(chip, i, 19, PCM1796_FLT_SHARP | PCM1796_ATS_1); |
194 | pcm1796_write(chip, i, 20, PCM1796_OS_64); | 221 | pcm1796_write(chip, i, 20, data->pcm1796_oversampling); |
195 | pcm1796_write(chip, i, 21, 0); | 222 | pcm1796_write(chip, i, 21, 0); |
196 | pcm1796_write(chip, i, 16, 0x0f); /* set ATL/ATR after ATLD */ | ||
197 | pcm1796_write(chip, i, 17, 0x0f); | ||
198 | } | 223 | } |
224 | update_pcm1796_mute(chip); /* set ATLD before ATL/ATR */ | ||
225 | update_pcm1796_volume(chip); | ||
226 | } | ||
227 | |||
228 | static void xonar_d2_init(struct oxygen *chip) | ||
229 | { | ||
230 | struct xonar_data *data = chip->model_data; | ||
231 | |||
232 | data->anti_pop_delay = 300; | ||
233 | data->output_enable_bit = GPIO_D2_OUTPUT_ENABLE; | ||
234 | data->pcm1796_oversampling = PCM1796_OS_64; | ||
235 | |||
236 | pcm1796_init(chip); | ||
199 | 237 | ||
200 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2_ALT); | 238 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2_ALT); |
201 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_D2_ALT); | 239 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_D2_ALT); |
@@ -217,31 +255,47 @@ static void xonar_d2x_init(struct oxygen *chip) | |||
217 | xonar_d2_init(chip); | 255 | xonar_d2_init(chip); |
218 | } | 256 | } |
219 | 257 | ||
220 | static void xonar_dx_init(struct oxygen *chip) | 258 | static void update_cs4362a_volumes(struct oxygen *chip) |
221 | { | 259 | { |
222 | struct xonar_data *data = chip->model_data; | 260 | u8 mute; |
223 | 261 | ||
224 | data->anti_pop_delay = 800; | 262 | mute = chip->dac_mute ? CS4362A_MUTE : 0; |
225 | data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE; | 263 | cs4362a_write(chip, 7, (127 - chip->dac_volume[2]) | mute); |
226 | data->ext_power_reg = OXYGEN_GPI_DATA; | 264 | cs4362a_write(chip, 8, (127 - chip->dac_volume[3]) | mute); |
227 | data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; | 265 | cs4362a_write(chip, 10, (127 - chip->dac_volume[4]) | mute); |
228 | data->ext_power_bit = GPI_DX_EXT_POWER; | 266 | cs4362a_write(chip, 11, (127 - chip->dac_volume[5]) | mute); |
267 | cs4362a_write(chip, 13, (127 - chip->dac_volume[6]) | mute); | ||
268 | cs4362a_write(chip, 14, (127 - chip->dac_volume[7]) | mute); | ||
269 | } | ||
229 | 270 | ||
230 | oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, | 271 | static void update_cs43xx_volume(struct oxygen *chip) |
231 | OXYGEN_2WIRE_LENGTH_8 | | 272 | { |
232 | OXYGEN_2WIRE_INTERRUPT_MASK | | 273 | cs4398_write(chip, 5, (127 - chip->dac_volume[0]) * 2); |
233 | OXYGEN_2WIRE_SPEED_FAST); | 274 | cs4398_write(chip, 6, (127 - chip->dac_volume[1]) * 2); |
275 | update_cs4362a_volumes(chip); | ||
276 | } | ||
277 | |||
278 | static void update_cs43xx_mute(struct oxygen *chip) | ||
279 | { | ||
280 | u8 reg; | ||
281 | |||
282 | reg = CS4398_MUTEP_LOW | CS4398_PAMUTE; | ||
283 | if (chip->dac_mute) | ||
284 | reg |= CS4398_MUTE_B | CS4398_MUTE_A; | ||
285 | cs4398_write(chip, 4, reg); | ||
286 | update_cs4362a_volumes(chip); | ||
287 | } | ||
288 | |||
289 | static void cs43xx_init(struct oxygen *chip) | ||
290 | { | ||
291 | struct xonar_data *data = chip->model_data; | ||
234 | 292 | ||
235 | /* set CPEN (control port mode) and power down */ | 293 | /* set CPEN (control port mode) and power down */ |
236 | cs4398_write(chip, 8, CS4398_CPEN | CS4398_PDN); | 294 | cs4398_write(chip, 8, CS4398_CPEN | CS4398_PDN); |
237 | cs4362a_write(chip, 0x01, CS4362A_PDN | CS4362A_CPEN); | 295 | cs4362a_write(chip, 0x01, CS4362A_PDN | CS4362A_CPEN); |
238 | /* configure */ | 296 | /* configure */ |
239 | cs4398_write(chip, 2, CS4398_FM_SINGLE | | 297 | cs4398_write(chip, 2, data->cs4398_fm); |
240 | CS4398_DEM_NONE | CS4398_DIF_LJUST); | ||
241 | cs4398_write(chip, 3, CS4398_ATAPI_B_R | CS4398_ATAPI_A_L); | 298 | cs4398_write(chip, 3, CS4398_ATAPI_B_R | CS4398_ATAPI_A_L); |
242 | cs4398_write(chip, 4, CS4398_MUTEP_LOW | CS4398_PAMUTE); | ||
243 | cs4398_write(chip, 5, 0xfe); | ||
244 | cs4398_write(chip, 6, 0xfe); | ||
245 | cs4398_write(chip, 7, CS4398_RMP_DN | CS4398_RMP_UP | | 299 | cs4398_write(chip, 7, CS4398_RMP_DN | CS4398_RMP_UP | |
246 | CS4398_ZERO_CROSS | CS4398_SOFT_RAMP); | 300 | CS4398_ZERO_CROSS | CS4398_SOFT_RAMP); |
247 | cs4362a_write(chip, 0x02, CS4362A_DIF_LJUST); | 301 | cs4362a_write(chip, 0x02, CS4362A_DIF_LJUST); |
@@ -249,21 +303,35 @@ static void xonar_dx_init(struct oxygen *chip) | |||
249 | CS4362A_RMP_UP | CS4362A_ZERO_CROSS | CS4362A_SOFT_RAMP); | 303 | CS4362A_RMP_UP | CS4362A_ZERO_CROSS | CS4362A_SOFT_RAMP); |
250 | cs4362a_write(chip, 0x04, CS4362A_RMP_DN | CS4362A_DEM_NONE); | 304 | cs4362a_write(chip, 0x04, CS4362A_RMP_DN | CS4362A_DEM_NONE); |
251 | cs4362a_write(chip, 0x05, 0); | 305 | cs4362a_write(chip, 0x05, 0); |
252 | cs4362a_write(chip, 0x06, CS4362A_FM_SINGLE | | 306 | cs4362a_write(chip, 0x06, data->cs4362a_fm); |
253 | CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L); | 307 | cs4362a_write(chip, 0x09, data->cs4362a_fm); |
254 | cs4362a_write(chip, 0x07, 0x7f | CS4362A_MUTE); | 308 | cs4362a_write(chip, 0x0c, data->cs4362a_fm); |
255 | cs4362a_write(chip, 0x08, 0x7f | CS4362A_MUTE); | 309 | update_cs43xx_volume(chip); |
256 | cs4362a_write(chip, 0x09, CS4362A_FM_SINGLE | | 310 | update_cs43xx_mute(chip); |
257 | CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L); | ||
258 | cs4362a_write(chip, 0x0a, 0x7f | CS4362A_MUTE); | ||
259 | cs4362a_write(chip, 0x0b, 0x7f | CS4362A_MUTE); | ||
260 | cs4362a_write(chip, 0x0c, CS4362A_FM_SINGLE | | ||
261 | CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L); | ||
262 | cs4362a_write(chip, 0x0d, 0x7f | CS4362A_MUTE); | ||
263 | cs4362a_write(chip, 0x0e, 0x7f | CS4362A_MUTE); | ||
264 | /* clear power down */ | 311 | /* clear power down */ |
265 | cs4398_write(chip, 8, CS4398_CPEN); | 312 | cs4398_write(chip, 8, CS4398_CPEN); |
266 | cs4362a_write(chip, 0x01, CS4362A_CPEN); | 313 | cs4362a_write(chip, 0x01, CS4362A_CPEN); |
314 | } | ||
315 | |||
316 | static void xonar_dx_init(struct oxygen *chip) | ||
317 | { | ||
318 | struct xonar_data *data = chip->model_data; | ||
319 | |||
320 | data->anti_pop_delay = 800; | ||
321 | data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE; | ||
322 | data->ext_power_reg = OXYGEN_GPI_DATA; | ||
323 | data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; | ||
324 | data->ext_power_bit = GPI_DX_EXT_POWER; | ||
325 | data->cs4398_fm = CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST; | ||
326 | data->cs4362a_fm = CS4362A_FM_SINGLE | | ||
327 | CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; | ||
328 | |||
329 | oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, | ||
330 | OXYGEN_2WIRE_LENGTH_8 | | ||
331 | OXYGEN_2WIRE_INTERRUPT_MASK | | ||
332 | OXYGEN_2WIRE_SPEED_FAST); | ||
333 | |||
334 | cs43xx_init(chip); | ||
267 | 335 | ||
268 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, | 336 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, |
269 | GPIO_DX_FRONT_PANEL | GPIO_DX_INPUT_ROUTE); | 337 | GPIO_DX_FRONT_PANEL | GPIO_DX_INPUT_ROUTE); |
@@ -291,37 +359,28 @@ static void xonar_dx_cleanup(struct oxygen *chip) | |||
291 | oxygen_clear_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC); | 359 | oxygen_clear_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC); |
292 | } | 360 | } |
293 | 361 | ||
294 | static void set_pcm1796_params(struct oxygen *chip, | 362 | static void xonar_d2_resume(struct oxygen *chip) |
295 | struct snd_pcm_hw_params *params) | ||
296 | { | 363 | { |
297 | unsigned int i; | 364 | pcm1796_init(chip); |
298 | u8 value; | 365 | xonar_enable_output(chip); |
299 | |||
300 | value = params_rate(params) >= 96000 ? PCM1796_OS_32 : PCM1796_OS_64; | ||
301 | for (i = 0; i < 4; ++i) | ||
302 | pcm1796_write(chip, i, 20, value); | ||
303 | } | 366 | } |
304 | 367 | ||
305 | static void update_pcm1796_volume(struct oxygen *chip) | 368 | static void xonar_dx_resume(struct oxygen *chip) |
306 | { | 369 | { |
307 | unsigned int i; | 370 | cs43xx_init(chip); |
308 | 371 | xonar_enable_output(chip); | |
309 | for (i = 0; i < 4; ++i) { | ||
310 | pcm1796_write(chip, i, 16, chip->dac_volume[i * 2]); | ||
311 | pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1]); | ||
312 | } | ||
313 | } | 372 | } |
314 | 373 | ||
315 | static void update_pcm1796_mute(struct oxygen *chip) | 374 | static void set_pcm1796_params(struct oxygen *chip, |
375 | struct snd_pcm_hw_params *params) | ||
316 | { | 376 | { |
377 | struct xonar_data *data = chip->model_data; | ||
317 | unsigned int i; | 378 | unsigned int i; |
318 | u8 value; | ||
319 | 379 | ||
320 | value = PCM1796_FMT_24_LJUST | PCM1796_ATLD; | 380 | data->pcm1796_oversampling = |
321 | if (chip->dac_mute) | 381 | params_rate(params) >= 96000 ? PCM1796_OS_32 : PCM1796_OS_64; |
322 | value |= PCM1796_MUTE; | ||
323 | for (i = 0; i < 4; ++i) | 382 | for (i = 0; i < 4; ++i) |
324 | pcm1796_write(chip, i, 18, value); | 383 | pcm1796_write(chip, i, 20, data->pcm1796_oversampling); |
325 | } | 384 | } |
326 | 385 | ||
327 | static void set_cs53x1_params(struct oxygen *chip, | 386 | static void set_cs53x1_params(struct oxygen *chip, |
@@ -342,55 +401,24 @@ static void set_cs53x1_params(struct oxygen *chip, | |||
342 | static void set_cs43xx_params(struct oxygen *chip, | 401 | static void set_cs43xx_params(struct oxygen *chip, |
343 | struct snd_pcm_hw_params *params) | 402 | struct snd_pcm_hw_params *params) |
344 | { | 403 | { |
345 | u8 fm_cs4398, fm_cs4362a; | 404 | struct xonar_data *data = chip->model_data; |
346 | 405 | ||
347 | fm_cs4398 = CS4398_DEM_NONE | CS4398_DIF_LJUST; | 406 | data->cs4398_fm = CS4398_DEM_NONE | CS4398_DIF_LJUST; |
348 | fm_cs4362a = CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; | 407 | data->cs4362a_fm = CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; |
349 | if (params_rate(params) <= 50000) { | 408 | if (params_rate(params) <= 50000) { |
350 | fm_cs4398 |= CS4398_FM_SINGLE; | 409 | data->cs4398_fm |= CS4398_FM_SINGLE; |
351 | fm_cs4362a |= CS4362A_FM_SINGLE; | 410 | data->cs4362a_fm |= CS4362A_FM_SINGLE; |
352 | } else if (params_rate(params) <= 100000) { | 411 | } else if (params_rate(params) <= 100000) { |
353 | fm_cs4398 |= CS4398_FM_DOUBLE; | 412 | data->cs4398_fm |= CS4398_FM_DOUBLE; |
354 | fm_cs4362a |= CS4362A_FM_DOUBLE; | 413 | data->cs4362a_fm |= CS4362A_FM_DOUBLE; |
355 | } else { | 414 | } else { |
356 | fm_cs4398 |= CS4398_FM_QUAD; | 415 | data->cs4398_fm |= CS4398_FM_QUAD; |
357 | fm_cs4362a |= CS4362A_FM_QUAD; | 416 | data->cs4362a_fm |= CS4362A_FM_QUAD; |
358 | } | 417 | } |
359 | cs4398_write(chip, 2, fm_cs4398); | 418 | cs4398_write(chip, 2, data->cs4398_fm); |
360 | cs4362a_write(chip, 0x06, fm_cs4362a); | 419 | cs4362a_write(chip, 0x06, data->cs4362a_fm); |
361 | cs4362a_write(chip, 0x09, fm_cs4362a); | 420 | cs4362a_write(chip, 0x09, data->cs4362a_fm); |
362 | cs4362a_write(chip, 0x0c, fm_cs4362a); | 421 | cs4362a_write(chip, 0x0c, data->cs4362a_fm); |
363 | } | ||
364 | |||
365 | static void update_cs4362a_volumes(struct oxygen *chip) | ||
366 | { | ||
367 | u8 mute; | ||
368 | |||
369 | mute = chip->dac_mute ? CS4362A_MUTE : 0; | ||
370 | cs4362a_write(chip, 7, (127 - chip->dac_volume[2]) | mute); | ||
371 | cs4362a_write(chip, 8, (127 - chip->dac_volume[3]) | mute); | ||
372 | cs4362a_write(chip, 10, (127 - chip->dac_volume[4]) | mute); | ||
373 | cs4362a_write(chip, 11, (127 - chip->dac_volume[5]) | mute); | ||
374 | cs4362a_write(chip, 13, (127 - chip->dac_volume[6]) | mute); | ||
375 | cs4362a_write(chip, 14, (127 - chip->dac_volume[7]) | mute); | ||
376 | } | ||
377 | |||
378 | static void update_cs43xx_volume(struct oxygen *chip) | ||
379 | { | ||
380 | cs4398_write(chip, 5, (127 - chip->dac_volume[0]) * 2); | ||
381 | cs4398_write(chip, 6, (127 - chip->dac_volume[1]) * 2); | ||
382 | update_cs4362a_volumes(chip); | ||
383 | } | ||
384 | |||
385 | static void update_cs43xx_mute(struct oxygen *chip) | ||
386 | { | ||
387 | u8 reg; | ||
388 | |||
389 | reg = CS4398_MUTEP_LOW | CS4398_PAMUTE; | ||
390 | if (chip->dac_mute) | ||
391 | reg |= CS4398_MUTE_B | CS4398_MUTE_A; | ||
392 | cs4398_write(chip, 4, reg); | ||
393 | update_cs4362a_volumes(chip); | ||
394 | } | 422 | } |
395 | 423 | ||
396 | static void xonar_gpio_changed(struct oxygen *chip) | 424 | static void xonar_gpio_changed(struct oxygen *chip) |
@@ -535,6 +563,8 @@ static const struct oxygen_model xonar_models[] = { | |||
535 | .control_filter = xonar_d2_control_filter, | 563 | .control_filter = xonar_d2_control_filter, |
536 | .mixer_init = xonar_mixer_init, | 564 | .mixer_init = xonar_mixer_init, |
537 | .cleanup = xonar_cleanup, | 565 | .cleanup = xonar_cleanup, |
566 | .suspend = xonar_cleanup, | ||
567 | .resume = xonar_d2_resume, | ||
538 | .set_dac_params = set_pcm1796_params, | 568 | .set_dac_params = set_pcm1796_params, |
539 | .set_adc_params = set_cs53x1_params, | 569 | .set_adc_params = set_cs53x1_params, |
540 | .update_dac_volume = update_pcm1796_volume, | 570 | .update_dac_volume = update_pcm1796_volume, |
@@ -563,6 +593,8 @@ static const struct oxygen_model xonar_models[] = { | |||
563 | .control_filter = xonar_d2_control_filter, | 593 | .control_filter = xonar_d2_control_filter, |
564 | .mixer_init = xonar_mixer_init, | 594 | .mixer_init = xonar_mixer_init, |
565 | .cleanup = xonar_cleanup, | 595 | .cleanup = xonar_cleanup, |
596 | .suspend = xonar_cleanup, | ||
597 | .resume = xonar_d2_resume, | ||
566 | .set_dac_params = set_pcm1796_params, | 598 | .set_dac_params = set_pcm1796_params, |
567 | .set_adc_params = set_cs53x1_params, | 599 | .set_adc_params = set_cs53x1_params, |
568 | .update_dac_volume = update_pcm1796_volume, | 600 | .update_dac_volume = update_pcm1796_volume, |
@@ -592,6 +624,8 @@ static const struct oxygen_model xonar_models[] = { | |||
592 | .control_filter = xonar_dx_control_filter, | 624 | .control_filter = xonar_dx_control_filter, |
593 | .mixer_init = xonar_dx_mixer_init, | 625 | .mixer_init = xonar_dx_mixer_init, |
594 | .cleanup = xonar_dx_cleanup, | 626 | .cleanup = xonar_dx_cleanup, |
627 | .suspend = xonar_dx_cleanup, | ||
628 | .resume = xonar_dx_resume, | ||
595 | .set_dac_params = set_cs43xx_params, | 629 | .set_dac_params = set_cs43xx_params, |
596 | .set_adc_params = set_cs53x1_params, | 630 | .set_adc_params = set_cs53x1_params, |
597 | .update_dac_volume = update_cs43xx_volume, | 631 | .update_dac_volume = update_cs43xx_volume, |
@@ -636,6 +670,10 @@ static struct pci_driver xonar_driver = { | |||
636 | .id_table = xonar_ids, | 670 | .id_table = xonar_ids, |
637 | .probe = xonar_probe, | 671 | .probe = xonar_probe, |
638 | .remove = __devexit_p(oxygen_pci_remove), | 672 | .remove = __devexit_p(oxygen_pci_remove), |
673 | #ifdef CONFIG_PM | ||
674 | .suspend = oxygen_pci_suspend, | ||
675 | .resume = oxygen_pci_resume, | ||
676 | #endif | ||
639 | }; | 677 | }; |
640 | 678 | ||
641 | static int __init alsa_card_xonar_init(void) | 679 | static int __init alsa_card_xonar_init(void) |
diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index 7fdcdc8c6b64..2c7e25336795 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c | |||
@@ -516,7 +516,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg) | |||
516 | int capture_mask = 0; | 516 | int capture_mask = 0; |
517 | int playback_mask = 0; | 517 | int playback_mask = 0; |
518 | 518 | ||
519 | #ifdef CONFIG_SND_DEBUG_DETECT | 519 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
520 | struct timeval my_tv1, my_tv2; | 520 | struct timeval my_tv1, my_tv2; |
521 | do_gettimeofday(&my_tv1); | 521 | do_gettimeofday(&my_tv1); |
522 | #endif | 522 | #endif |
@@ -623,7 +623,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg) | |||
623 | 623 | ||
624 | mutex_unlock(&mgr->setup_mutex); | 624 | mutex_unlock(&mgr->setup_mutex); |
625 | 625 | ||
626 | #ifdef CONFIG_SND_DEBUG_DETECT | 626 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
627 | do_gettimeofday(&my_tv2); | 627 | do_gettimeofday(&my_tv2); |
628 | snd_printdd("***TRIGGER TASKLET*** TIME = %ld (err = %x)\n", | 628 | snd_printdd("***TRIGGER TASKLET*** TIME = %ld (err = %x)\n", |
629 | (long)(my_tv2.tv_usec - my_tv1.tv_usec), err); | 629 | (long)(my_tv2.tv_usec - my_tv1.tv_usec), err); |
diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c index 78aa81feaa4a..abe5c59b72df 100644 --- a/sound/pci/pcxhr/pcxhr_core.c +++ b/sound/pci/pcxhr/pcxhr_core.c | |||
@@ -473,7 +473,7 @@ static struct pcxhr_cmd_info pcxhr_dsp_cmds[] = { | |||
473 | [CMD_AUDIO_LEVEL_ADJUST] = { 0xc22000, 0, RMH_SSIZE_FIXED }, | 473 | [CMD_AUDIO_LEVEL_ADJUST] = { 0xc22000, 0, RMH_SSIZE_FIXED }, |
474 | }; | 474 | }; |
475 | 475 | ||
476 | #ifdef CONFIG_SND_DEBUG_DETECT | 476 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
477 | static char* cmd_names[] = { | 477 | static char* cmd_names[] = { |
478 | [CMD_VERSION] = "CMD_VERSION", | 478 | [CMD_VERSION] = "CMD_VERSION", |
479 | [CMD_SUPPORTED] = "CMD_SUPPORTED", | 479 | [CMD_SUPPORTED] = "CMD_SUPPORTED", |
@@ -549,7 +549,7 @@ static int pcxhr_read_rmh_status(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) | |||
549 | } | 549 | } |
550 | } | 550 | } |
551 | } | 551 | } |
552 | #ifdef CONFIG_SND_DEBUG_DETECT | 552 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
553 | if (rmh->cmd_idx < CMD_LAST_INDEX) | 553 | if (rmh->cmd_idx < CMD_LAST_INDEX) |
554 | snd_printdd(" stat[%d]=%x\n", i, data); | 554 | snd_printdd(" stat[%d]=%x\n", i, data); |
555 | #endif | 555 | #endif |
@@ -597,7 +597,7 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) | |||
597 | data |= 0x008000; /* MASK_MORE_THAN_1_WORD_COMMAND */ | 597 | data |= 0x008000; /* MASK_MORE_THAN_1_WORD_COMMAND */ |
598 | else | 598 | else |
599 | data &= 0xff7fff; /* MASK_1_WORD_COMMAND */ | 599 | data &= 0xff7fff; /* MASK_1_WORD_COMMAND */ |
600 | #ifdef CONFIG_SND_DEBUG_DETECT | 600 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
601 | if (rmh->cmd_idx < CMD_LAST_INDEX) | 601 | if (rmh->cmd_idx < CMD_LAST_INDEX) |
602 | snd_printdd("MSG cmd[0]=%x (%s)\n", data, cmd_names[rmh->cmd_idx]); | 602 | snd_printdd("MSG cmd[0]=%x (%s)\n", data, cmd_names[rmh->cmd_idx]); |
603 | #endif | 603 | #endif |
@@ -624,7 +624,7 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) | |||
624 | for (i=1; i < rmh->cmd_len; i++) { | 624 | for (i=1; i < rmh->cmd_len; i++) { |
625 | /* send other words */ | 625 | /* send other words */ |
626 | data = rmh->cmd[i]; | 626 | data = rmh->cmd[i]; |
627 | #ifdef CONFIG_SND_DEBUG_DETECT | 627 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
628 | if (rmh->cmd_idx < CMD_LAST_INDEX) | 628 | if (rmh->cmd_idx < CMD_LAST_INDEX) |
629 | snd_printdd(" cmd[%d]=%x\n", i, data); | 629 | snd_printdd(" cmd[%d]=%x\n", i, data); |
630 | #endif | 630 | #endif |
@@ -847,7 +847,7 @@ int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask, int capture_m | |||
847 | int state, i, err; | 847 | int state, i, err; |
848 | int audio_mask; | 848 | int audio_mask; |
849 | 849 | ||
850 | #ifdef CONFIG_SND_DEBUG_DETECT | 850 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
851 | struct timeval my_tv1, my_tv2; | 851 | struct timeval my_tv1, my_tv2; |
852 | do_gettimeofday(&my_tv1); | 852 | do_gettimeofday(&my_tv1); |
853 | #endif | 853 | #endif |
@@ -894,7 +894,7 @@ int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask, int capture_m | |||
894 | if (err) | 894 | if (err) |
895 | return err; | 895 | return err; |
896 | } | 896 | } |
897 | #ifdef CONFIG_SND_DEBUG_DETECT | 897 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
898 | do_gettimeofday(&my_tv2); | 898 | do_gettimeofday(&my_tv2); |
899 | snd_printdd("***SET PIPE STATE*** TIME = %ld (err = %x)\n", | 899 | snd_printdd("***SET PIPE STATE*** TIME = %ld (err = %x)\n", |
900 | (long)(my_tv2.tv_usec - my_tv1.tv_usec), err); | 900 | (long)(my_tv2.tv_usec - my_tv1.tv_usec), err); |
@@ -951,7 +951,7 @@ static int pcxhr_handle_async_err(struct pcxhr_mgr *mgr, u32 err, | |||
951 | enum pcxhr_async_err_src err_src, int pipe, | 951 | enum pcxhr_async_err_src err_src, int pipe, |
952 | int is_capture) | 952 | int is_capture) |
953 | { | 953 | { |
954 | #ifdef CONFIG_SND_DEBUG_DETECT | 954 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
955 | static char* err_src_name[] = { | 955 | static char* err_src_name[] = { |
956 | [PCXHR_ERR_PIPE] = "Pipe", | 956 | [PCXHR_ERR_PIPE] = "Pipe", |
957 | [PCXHR_ERR_STREAM] = "Stream", | 957 | [PCXHR_ERR_STREAM] = "Stream", |
@@ -1169,7 +1169,7 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id) | |||
1169 | mgr->dsp_time_last, dsp_time_new); | 1169 | mgr->dsp_time_last, dsp_time_new); |
1170 | mgr->dsp_time_err++; | 1170 | mgr->dsp_time_err++; |
1171 | } | 1171 | } |
1172 | #ifdef CONFIG_SND_DEBUG_DETECT | 1172 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
1173 | if (dsp_time_diff == 0) | 1173 | if (dsp_time_diff == 0) |
1174 | snd_printdd("ERROR DSP TIME NO DIFF time(%d)\n", dsp_time_new); | 1174 | snd_printdd("ERROR DSP TIME NO DIFF time(%d)\n", dsp_time_new); |
1175 | else if (dsp_time_diff >= (2*PCXHR_GRANULARITY)) | 1175 | else if (dsp_time_diff >= (2*PCXHR_GRANULARITY)) |
@@ -1208,7 +1208,7 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id) | |||
1208 | mgr->src_it_dsp = reg; | 1208 | mgr->src_it_dsp = reg; |
1209 | tasklet_hi_schedule(&mgr->msg_taskq); | 1209 | tasklet_hi_schedule(&mgr->msg_taskq); |
1210 | } | 1210 | } |
1211 | #ifdef CONFIG_SND_DEBUG_DETECT | 1211 | #ifdef CONFIG_SND_DEBUG_VERBOSE |
1212 | if (reg & PCXHR_FATAL_DSP_ERR) | 1212 | if (reg & PCXHR_FATAL_DSP_ERR) |
1213 | snd_printdd("FATAL DSP ERROR : %x\n", reg); | 1213 | snd_printdd("FATAL DSP ERROR : %x\n", reg); |
1214 | #endif | 1214 | #endif |
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index bbcee2c09ae4..a69b4206c69e 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c | |||
@@ -1590,7 +1590,10 @@ static int snd_trident_trigger(struct snd_pcm_substream *substream, | |||
1590 | if (spdif_flag) { | 1590 | if (spdif_flag) { |
1591 | if (trident->device != TRIDENT_DEVICE_ID_SI7018) { | 1591 | if (trident->device != TRIDENT_DEVICE_ID_SI7018) { |
1592 | outl(trident->spdif_pcm_bits, TRID_REG(trident, NX_SPCSTATUS)); | 1592 | outl(trident->spdif_pcm_bits, TRID_REG(trident, NX_SPCSTATUS)); |
1593 | outb(trident->spdif_pcm_ctrl, TRID_REG(trident, NX_SPCTRL_SPCSO + 3)); | 1593 | val = trident->spdif_pcm_ctrl; |
1594 | if (!go) | ||
1595 | val &= ~(0x28); | ||
1596 | outb(val, TRID_REG(trident, NX_SPCTRL_SPCSO + 3)); | ||
1594 | } else { | 1597 | } else { |
1595 | outl(trident->spdif_pcm_bits, TRID_REG(trident, SI_SPDIF_CS)); | 1598 | outl(trident->spdif_pcm_bits, TRID_REG(trident, SI_SPDIF_CS)); |
1596 | val = inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL)) | SPDIF_EN; | 1599 | val = inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL)) | SPDIF_EN; |
diff --git a/sound/pci/trident/trident_memory.c b/sound/pci/trident/trident_memory.c index df9b487fa17e..3fd7f1b29b0f 100644 --- a/sound/pci/trident/trident_memory.c +++ b/sound/pci/trident/trident_memory.c | |||
@@ -310,181 +310,3 @@ int snd_trident_free_pages(struct snd_trident *trident, | |||
310 | mutex_unlock(&hdr->block_mutex); | 310 | mutex_unlock(&hdr->block_mutex); |
311 | return 0; | 311 | return 0; |
312 | } | 312 | } |
313 | |||
314 | |||
315 | /*---------------------------------------------------------------- | ||
316 | * memory allocation using multiple pages (for synth) | ||
317 | *---------------------------------------------------------------- | ||
318 | * Unlike the DMA allocation above, non-contiguous pages are | ||
319 | * assigned to TLB. | ||
320 | *----------------------------------------------------------------*/ | ||
321 | |||
322 | /* | ||
323 | */ | ||
324 | static int synth_alloc_pages(struct snd_trident *hw, struct snd_util_memblk *blk); | ||
325 | static int synth_free_pages(struct snd_trident *hw, struct snd_util_memblk *blk); | ||
326 | |||
327 | /* | ||
328 | * allocate a synth sample area | ||
329 | */ | ||
330 | struct snd_util_memblk * | ||
331 | snd_trident_synth_alloc(struct snd_trident *hw, unsigned int size) | ||
332 | { | ||
333 | struct snd_util_memblk *blk; | ||
334 | struct snd_util_memhdr *hdr = hw->tlb.memhdr; | ||
335 | |||
336 | mutex_lock(&hdr->block_mutex); | ||
337 | blk = __snd_util_mem_alloc(hdr, size); | ||
338 | if (blk == NULL) { | ||
339 | mutex_unlock(&hdr->block_mutex); | ||
340 | return NULL; | ||
341 | } | ||
342 | if (synth_alloc_pages(hw, blk)) { | ||
343 | __snd_util_mem_free(hdr, blk); | ||
344 | mutex_unlock(&hdr->block_mutex); | ||
345 | return NULL; | ||
346 | } | ||
347 | mutex_unlock(&hdr->block_mutex); | ||
348 | return blk; | ||
349 | } | ||
350 | |||
351 | EXPORT_SYMBOL(snd_trident_synth_alloc); | ||
352 | |||
353 | /* | ||
354 | * free a synth sample area | ||
355 | */ | ||
356 | int | ||
357 | snd_trident_synth_free(struct snd_trident *hw, struct snd_util_memblk *blk) | ||
358 | { | ||
359 | struct snd_util_memhdr *hdr = hw->tlb.memhdr; | ||
360 | |||
361 | mutex_lock(&hdr->block_mutex); | ||
362 | synth_free_pages(hw, blk); | ||
363 | __snd_util_mem_free(hdr, blk); | ||
364 | mutex_unlock(&hdr->block_mutex); | ||
365 | return 0; | ||
366 | } | ||
367 | |||
368 | EXPORT_SYMBOL(snd_trident_synth_free); | ||
369 | |||
370 | /* | ||
371 | * reset TLB entry and free kernel page | ||
372 | */ | ||
373 | static void clear_tlb(struct snd_trident *trident, int page) | ||
374 | { | ||
375 | void *ptr = page_to_ptr(trident, page); | ||
376 | dma_addr_t addr = page_to_addr(trident, page); | ||
377 | set_silent_tlb(trident, page); | ||
378 | if (ptr) { | ||
379 | struct snd_dma_buffer dmab; | ||
380 | dmab.dev.type = SNDRV_DMA_TYPE_DEV; | ||
381 | dmab.dev.dev = snd_dma_pci_data(trident->pci); | ||
382 | dmab.area = ptr; | ||
383 | dmab.addr = addr; | ||
384 | dmab.bytes = ALIGN_PAGE_SIZE; | ||
385 | snd_dma_free_pages(&dmab); | ||
386 | } | ||
387 | } | ||
388 | |||
389 | /* check new allocation range */ | ||
390 | static void get_single_page_range(struct snd_util_memhdr *hdr, | ||
391 | struct snd_util_memblk *blk, | ||
392 | int *first_page_ret, int *last_page_ret) | ||
393 | { | ||
394 | struct list_head *p; | ||
395 | struct snd_util_memblk *q; | ||
396 | int first_page, last_page; | ||
397 | first_page = firstpg(blk); | ||
398 | if ((p = blk->list.prev) != &hdr->block) { | ||
399 | q = list_entry(p, struct snd_util_memblk, list); | ||
400 | if (lastpg(q) == first_page) | ||
401 | first_page++; /* first page was already allocated */ | ||
402 | } | ||
403 | last_page = lastpg(blk); | ||
404 | if ((p = blk->list.next) != &hdr->block) { | ||
405 | q = list_entry(p, struct snd_util_memblk, list); | ||
406 | if (firstpg(q) == last_page) | ||
407 | last_page--; /* last page was already allocated */ | ||
408 | } | ||
409 | *first_page_ret = first_page; | ||
410 | *last_page_ret = last_page; | ||
411 | } | ||
412 | |||
413 | /* | ||
414 | * allocate kernel pages and assign them to TLB | ||
415 | */ | ||
416 | static int synth_alloc_pages(struct snd_trident *hw, struct snd_util_memblk *blk) | ||
417 | { | ||
418 | int page, first_page, last_page; | ||
419 | struct snd_dma_buffer dmab; | ||
420 | |||
421 | firstpg(blk) = get_aligned_page(blk->offset); | ||
422 | lastpg(blk) = get_aligned_page(blk->offset + blk->size - 1); | ||
423 | get_single_page_range(hw->tlb.memhdr, blk, &first_page, &last_page); | ||
424 | |||
425 | /* allocate a kernel page for each Trident page - | ||
426 | * fortunately Trident page size and kernel PAGE_SIZE is identical! | ||
427 | */ | ||
428 | for (page = first_page; page <= last_page; page++) { | ||
429 | if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(hw->pci), | ||
430 | ALIGN_PAGE_SIZE, &dmab) < 0) | ||
431 | goto __fail; | ||
432 | if (! is_valid_page(dmab.addr)) { | ||
433 | snd_dma_free_pages(&dmab); | ||
434 | goto __fail; | ||
435 | } | ||
436 | set_tlb_bus(hw, page, (unsigned long)dmab.area, dmab.addr); | ||
437 | } | ||
438 | return 0; | ||
439 | |||
440 | __fail: | ||
441 | /* release allocated pages */ | ||
442 | last_page = page - 1; | ||
443 | for (page = first_page; page <= last_page; page++) | ||
444 | clear_tlb(hw, page); | ||
445 | |||
446 | return -ENOMEM; | ||
447 | } | ||
448 | |||
449 | /* | ||
450 | * free pages | ||
451 | */ | ||
452 | static int synth_free_pages(struct snd_trident *trident, struct snd_util_memblk *blk) | ||
453 | { | ||
454 | int page, first_page, last_page; | ||
455 | |||
456 | get_single_page_range(trident->tlb.memhdr, blk, &first_page, &last_page); | ||
457 | for (page = first_page; page <= last_page; page++) | ||
458 | clear_tlb(trident, page); | ||
459 | |||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | /* | ||
464 | * copy_from_user(blk + offset, data, size) | ||
465 | */ | ||
466 | int snd_trident_synth_copy_from_user(struct snd_trident *trident, | ||
467 | struct snd_util_memblk *blk, | ||
468 | int offset, const char __user *data, int size) | ||
469 | { | ||
470 | int page, nextofs, end_offset, temp, temp1; | ||
471 | |||
472 | offset += blk->offset; | ||
473 | end_offset = offset + size; | ||
474 | page = get_aligned_page(offset) + 1; | ||
475 | do { | ||
476 | nextofs = aligned_page_offset(page); | ||
477 | temp = nextofs - offset; | ||
478 | temp1 = end_offset - offset; | ||
479 | if (temp1 < temp) | ||
480 | temp = temp1; | ||
481 | if (copy_from_user(offset_ptr(trident, offset), data, temp)) | ||
482 | return -EFAULT; | ||
483 | offset = nextofs; | ||
484 | data += temp; | ||
485 | page++; | ||
486 | } while (offset < end_offset); | ||
487 | return 0; | ||
488 | } | ||
489 | |||
490 | EXPORT_SYMBOL(snd_trident_synth_copy_from_user); | ||
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index b585cc3e4c47..6781be9e3078 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c | |||
@@ -1757,6 +1757,12 @@ static struct ac97_quirk ac97_quirks[] = { | |||
1757 | .type = AC97_TUNE_HP_ONLY | 1757 | .type = AC97_TUNE_HP_ONLY |
1758 | }, | 1758 | }, |
1759 | { | 1759 | { |
1760 | .subvendor = 0x1019, | ||
1761 | .subdevice = 0x1841, | ||
1762 | .name = "ECS K7VTA3", | ||
1763 | .type = AC97_TUNE_HP_ONLY | ||
1764 | }, | ||
1765 | { | ||
1760 | .subvendor = 0x1849, | 1766 | .subvendor = 0x1849, |
1761 | .subdevice = 0x3059, | 1767 | .subdevice = 0x3059, |
1762 | .name = "ASRock K7VM2", | 1768 | .name = "ASRock K7VM2", |
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 29b3056c5109..7129df5f315b 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c | |||
@@ -2205,6 +2205,7 @@ static int __devinit snd_ymfpci_memalloc(struct snd_ymfpci *chip) | |||
2205 | for (reg = 0x80; reg < 0xc0; reg += 4) | 2205 | for (reg = 0x80; reg < 0xc0; reg += 4) |
2206 | snd_ymfpci_writel(chip, reg, 0); | 2206 | snd_ymfpci_writel(chip, reg, 0); |
2207 | snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0x3fff3fff); | 2207 | snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0x3fff3fff); |
2208 | snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0x3fff3fff); | ||
2208 | snd_ymfpci_writel(chip, YDSXGR_ZVOUTVOL, 0x3fff3fff); | 2209 | snd_ymfpci_writel(chip, YDSXGR_ZVOUTVOL, 0x3fff3fff); |
2209 | snd_ymfpci_writel(chip, YDSXGR_SPDIFOUTVOL, 0x3fff3fff); | 2210 | snd_ymfpci_writel(chip, YDSXGR_SPDIFOUTVOL, 0x3fff3fff); |
2210 | snd_ymfpci_writel(chip, YDSXGR_NATIVEADCINVOL, 0x3fff3fff); | 2211 | snd_ymfpci_writel(chip, YDSXGR_NATIVEADCINVOL, 0x3fff3fff); |
@@ -2324,6 +2325,7 @@ int snd_ymfpci_suspend(struct pci_dev *pci, pm_message_t state) | |||
2324 | chip->saved_regs[i] = snd_ymfpci_readl(chip, saved_regs_index[i]); | 2325 | chip->saved_regs[i] = snd_ymfpci_readl(chip, saved_regs_index[i]); |
2325 | chip->saved_ydsxgr_mode = snd_ymfpci_readl(chip, YDSXGR_MODE); | 2326 | chip->saved_ydsxgr_mode = snd_ymfpci_readl(chip, YDSXGR_MODE); |
2326 | snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0); | 2327 | snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0); |
2328 | snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0); | ||
2327 | snd_ymfpci_disable_dsp(chip); | 2329 | snd_ymfpci_disable_dsp(chip); |
2328 | pci_disable_device(pci); | 2330 | pci_disable_device(pci); |
2329 | pci_save_state(pci); | 2331 | pci_save_state(pci); |
diff --git a/sound/pcmcia/Kconfig b/sound/pcmcia/Kconfig index c9fa1a2bc58b..7fbb190adf6d 100644 --- a/sound/pcmcia/Kconfig +++ b/sound/pcmcia/Kconfig | |||
@@ -1,11 +1,16 @@ | |||
1 | # ALSA PCMCIA drivers | 1 | # ALSA PCMCIA drivers |
2 | 2 | ||
3 | menu "PCMCIA devices" | 3 | menuconfig SND_PCMCIA |
4 | depends on SND!=n && PCMCIA | 4 | bool "PCMCIA sound devices" |
5 | depends on PCMCIA | ||
6 | default y | ||
7 | help | ||
8 | Support for sound devices connected via the PCMCIA bus. | ||
9 | |||
10 | if SND_PCMCIA && PCMCIA | ||
5 | 11 | ||
6 | config SND_VXPOCKET | 12 | config SND_VXPOCKET |
7 | tristate "Digigram VXpocket" | 13 | tristate "Digigram VXpocket" |
8 | depends on SND && PCMCIA | ||
9 | select SND_VX_LIB | 14 | select SND_VX_LIB |
10 | help | 15 | help |
11 | Say Y here to include support for Digigram VXpocket and | 16 | Say Y here to include support for Digigram VXpocket and |
@@ -16,7 +21,6 @@ config SND_VXPOCKET | |||
16 | 21 | ||
17 | config SND_PDAUDIOCF | 22 | config SND_PDAUDIOCF |
18 | tristate "Sound Core PDAudioCF" | 23 | tristate "Sound Core PDAudioCF" |
19 | depends on SND && PCMCIA | ||
20 | select SND_PCM | 24 | select SND_PCM |
21 | help | 25 | help |
22 | Say Y here to include support for Sound Core PDAudioCF | 26 | Say Y here to include support for Sound Core PDAudioCF |
@@ -25,4 +29,5 @@ config SND_PDAUDIOCF | |||
25 | To compile this driver as a module, choose M here: the module | 29 | To compile this driver as a module, choose M here: the module |
26 | will be called snd-pdaudiocf. | 30 | will be called snd-pdaudiocf. |
27 | 31 | ||
28 | endmenu | 32 | endif # SND_PCMCIA |
33 | |||
diff --git a/sound/pcmcia/vx/vxp_ops.c b/sound/pcmcia/vx/vxp_ops.c index 157b0b539f39..99bf2a65a6f5 100644 --- a/sound/pcmcia/vx/vxp_ops.c +++ b/sound/pcmcia/vx/vxp_ops.c | |||
@@ -151,7 +151,7 @@ static int vxp_load_xilinx_binary(struct vx_core *_chip, const struct firmware * | |||
151 | unsigned int i; | 151 | unsigned int i; |
152 | int c; | 152 | int c; |
153 | int regCSUER, regRUER; | 153 | int regCSUER, regRUER; |
154 | unsigned char *image; | 154 | const unsigned char *image; |
155 | unsigned char data; | 155 | unsigned char data; |
156 | 156 | ||
157 | /* Switch to programmation mode */ | 157 | /* Switch to programmation mode */ |
diff --git a/sound/ppc/Kconfig b/sound/ppc/Kconfig index cacb0b136883..777de2b17178 100644 --- a/sound/ppc/Kconfig +++ b/sound/ppc/Kconfig | |||
@@ -1,17 +1,17 @@ | |||
1 | # ALSA PowerMac drivers | 1 | # ALSA PowerMac drivers |
2 | 2 | ||
3 | menu "ALSA PowerMac devices" | 3 | menuconfig SND_PPC |
4 | depends on SND!=n && PPC | 4 | bool "PowerPC sound devices" |
5 | 5 | depends on PPC64 || PPC32 | |
6 | comment "ALSA PowerMac requires I2C" | 6 | default y |
7 | depends on SND && I2C=n | 7 | help |
8 | Support for sound devices specific to PowerPC architectures. | ||
8 | 9 | ||
9 | comment "ALSA PowerMac requires INPUT" | 10 | if SND_PPC |
10 | depends on SND && INPUT=n | ||
11 | 11 | ||
12 | config SND_POWERMAC | 12 | config SND_POWERMAC |
13 | tristate "PowerMac (AWACS, DACA, Burgundy, Tumbler, Keywest)" | 13 | tristate "PowerMac (AWACS, DACA, Burgundy, Tumbler, Keywest)" |
14 | depends on SND && I2C && INPUT && PPC_PMAC | 14 | depends on I2C && INPUT && PPC_PMAC |
15 | select SND_PCM | 15 | select SND_PCM |
16 | help | 16 | help |
17 | Say Y here to include support for the integrated sound device. | 17 | Say Y here to include support for the integrated sound device. |
@@ -32,14 +32,9 @@ config SND_POWERMAC_AUTO_DRC | |||
32 | Note that you can turn on/off DRC manually even without this | 32 | Note that you can turn on/off DRC manually even without this |
33 | option. | 33 | option. |
34 | 34 | ||
35 | endmenu | ||
36 | |||
37 | menu "ALSA PowerPC devices" | ||
38 | depends on SND!=n && ( PPC64 || PPC32 ) | ||
39 | |||
40 | config SND_PS3 | 35 | config SND_PS3 |
41 | tristate "PS3 Audio support" | 36 | tristate "PS3 Audio support" |
42 | depends on SND && PS3_PS3AV | 37 | depends on PS3_PS3AV |
43 | select SND_PCM | 38 | select SND_PCM |
44 | default m | 39 | default m |
45 | help | 40 | help |
@@ -52,4 +47,5 @@ config SND_PS3_DEFAULT_START_DELAY | |||
52 | int "Startup delay time in ms" | 47 | int "Startup delay time in ms" |
53 | depends on SND_PS3 | 48 | depends on SND_PS3 |
54 | default "2000" | 49 | default "2000" |
55 | endmenu | 50 | |
51 | endif # SND_PPC | ||
diff --git a/sound/ppc/daca.c b/sound/ppc/daca.c index ca9452901a50..8a5b29031933 100644 --- a/sound/ppc/daca.c +++ b/sound/ppc/daca.c | |||
@@ -249,9 +249,7 @@ int __init snd_pmac_daca_init(struct snd_pmac *chip) | |||
249 | int i, err; | 249 | int i, err; |
250 | struct pmac_daca *mix; | 250 | struct pmac_daca *mix; |
251 | 251 | ||
252 | #ifdef CONFIG_KMOD | ||
253 | request_module("i2c-powermac"); | 252 | request_module("i2c-powermac"); |
254 | #endif /* CONFIG_KMOD */ | ||
255 | 253 | ||
256 | mix = kzalloc(sizeof(*mix), GFP_KERNEL); | 254 | mix = kzalloc(sizeof(*mix), GFP_KERNEL); |
257 | if (! mix) | 255 | if (! mix) |
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index 3f8d7164cef9..009df8dd37a8 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c | |||
@@ -1350,9 +1350,7 @@ int __init snd_pmac_tumbler_init(struct snd_pmac *chip) | |||
1350 | struct device_node *tas_node, *np; | 1350 | struct device_node *tas_node, *np; |
1351 | char *chipname; | 1351 | char *chipname; |
1352 | 1352 | ||
1353 | #ifdef CONFIG_KMOD | ||
1354 | request_module("i2c-powermac"); | 1353 | request_module("i2c-powermac"); |
1355 | #endif /* CONFIG_KMOD */ | ||
1356 | 1354 | ||
1357 | mix = kzalloc(sizeof(*mix), GFP_KERNEL); | 1355 | mix = kzalloc(sizeof(*mix), GFP_KERNEL); |
1358 | if (! mix) | 1356 | if (! mix) |
diff --git a/sound/sh/Kconfig b/sound/sh/Kconfig index b7e08ef22a94..cfc143985802 100644 --- a/sound/sh/Kconfig +++ b/sound/sh/Kconfig | |||
@@ -1,14 +1,22 @@ | |||
1 | # ALSA SH drivers | 1 | # ALSA SH drivers |
2 | 2 | ||
3 | menu "SUPERH devices" | 3 | menuconfig SND_SUPERH |
4 | depends on SND!=n && SUPERH | 4 | bool "SUPERH sound devices" |
5 | depends on SUPERH | ||
6 | default y | ||
7 | help | ||
8 | Support for sound devices specific to SUPERH architectures. | ||
9 | Drivers that are implemented on ASoC can be found in | ||
10 | "ALSA for SoC audio support" section. | ||
11 | |||
12 | if SND_SUPERH | ||
5 | 13 | ||
6 | config SND_AICA | 14 | config SND_AICA |
7 | tristate "Dreamcast Yamaha AICA sound" | 15 | tristate "Dreamcast Yamaha AICA sound" |
8 | depends on SH_DREAMCAST && SND | 16 | depends on SH_DREAMCAST |
9 | select SND_PCM | 17 | select SND_PCM |
10 | help | 18 | help |
11 | ALSA Sound driver for the SEGA Dreamcast console. | 19 | ALSA Sound driver for the SEGA Dreamcast console. |
12 | 20 | ||
13 | endmenu | 21 | endif # SND_SUPERH |
14 | 22 | ||
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 18f28ac4bfe8..f743530add8f 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig | |||
@@ -2,15 +2,8 @@ | |||
2 | # SoC audio configuration | 2 | # SoC audio configuration |
3 | # | 3 | # |
4 | 4 | ||
5 | menu "System on Chip audio support" | 5 | menuconfig SND_SOC |
6 | depends on SND!=n | ||
7 | |||
8 | config SND_SOC_AC97_BUS | ||
9 | bool | ||
10 | |||
11 | config SND_SOC | ||
12 | tristate "ALSA for SoC audio support" | 6 | tristate "ALSA for SoC audio support" |
13 | depends on SND | ||
14 | select SND_PCM | 7 | select SND_PCM |
15 | ---help--- | 8 | ---help--- |
16 | 9 | ||
@@ -23,8 +16,15 @@ config SND_SOC | |||
23 | This ASoC audio support can also be built as a module. If so, the module | 16 | This ASoC audio support can also be built as a module. If so, the module |
24 | will be called snd-soc-core. | 17 | will be called snd-soc-core. |
25 | 18 | ||
19 | if SND_SOC | ||
20 | |||
21 | config SND_SOC_AC97_BUS | ||
22 | bool | ||
23 | |||
26 | # All the supported Soc's | 24 | # All the supported Soc's |
25 | source "sound/soc/at32/Kconfig" | ||
27 | source "sound/soc/at91/Kconfig" | 26 | source "sound/soc/at91/Kconfig" |
27 | source "sound/soc/au1x/Kconfig" | ||
28 | source "sound/soc/pxa/Kconfig" | 28 | source "sound/soc/pxa/Kconfig" |
29 | source "sound/soc/s3c24xx/Kconfig" | 29 | source "sound/soc/s3c24xx/Kconfig" |
30 | source "sound/soc/sh/Kconfig" | 30 | source "sound/soc/sh/Kconfig" |
@@ -35,4 +35,5 @@ source "sound/soc/omap/Kconfig" | |||
35 | # Supported codecs | 35 | # Supported codecs |
36 | source "sound/soc/codecs/Kconfig" | 36 | source "sound/soc/codecs/Kconfig" |
37 | 37 | ||
38 | endmenu | 38 | endif # SND_SOC |
39 | |||
diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 782db2127108..933a66d30804 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile | |||
@@ -1,4 +1,5 @@ | |||
1 | snd-soc-core-objs := soc-core.o soc-dapm.o | 1 | snd-soc-core-objs := soc-core.o soc-dapm.o |
2 | 2 | ||
3 | obj-$(CONFIG_SND_SOC) += snd-soc-core.o | 3 | obj-$(CONFIG_SND_SOC) += snd-soc-core.o |
4 | obj-$(CONFIG_SND_SOC) += codecs/ at91/ pxa/ s3c24xx/ sh/ fsl/ davinci/ omap/ | 4 | obj-$(CONFIG_SND_SOC) += codecs/ at32/ at91/ pxa/ s3c24xx/ sh/ fsl/ davinci/ |
5 | obj-$(CONFIG_SND_SOC) += omap/ au1x/ | ||
diff --git a/sound/soc/at32/Kconfig b/sound/soc/at32/Kconfig new file mode 100644 index 000000000000..b0765e86c085 --- /dev/null +++ b/sound/soc/at32/Kconfig | |||
@@ -0,0 +1,34 @@ | |||
1 | config SND_AT32_SOC | ||
2 | tristate "SoC Audio for the Atmel AT32 System-on-a-Chip" | ||
3 | depends on AVR32 && SND_SOC | ||
4 | help | ||
5 | Say Y or M if you want to add support for codecs attached to | ||
6 | the AT32 SSC interface. You will also need to | ||
7 | to select the audio interfaces to support below. | ||
8 | |||
9 | |||
10 | config SND_AT32_SOC_SSC | ||
11 | tristate | ||
12 | |||
13 | |||
14 | |||
15 | config SND_AT32_SOC_PLAYPAQ | ||
16 | tristate "SoC Audio support for PlayPaq with WM8510" | ||
17 | depends on SND_AT32_SOC && BOARD_PLAYPAQ | ||
18 | select SND_AT32_SOC_SSC | ||
19 | select SND_SOC_WM8510 | ||
20 | help | ||
21 | Say Y or M here if you want to add support for SoC audio | ||
22 | on the LRS PlayPaq. | ||
23 | |||
24 | |||
25 | |||
26 | config SND_AT32_SOC_PLAYPAQ_SLAVE | ||
27 | bool "Run CODEC on PlayPaq in slave mode" | ||
28 | depends on SND_AT32_SOC_PLAYPAQ | ||
29 | default n | ||
30 | help | ||
31 | Say Y if you want to run with the AT32 SSC generating the BCLK | ||
32 | and FRAME signals on the PlayPaq. Unless you want to play | ||
33 | with the AT32 as the SSC master, you probably want to say N here, | ||
34 | as this will give you better sound quality. | ||
diff --git a/sound/soc/at32/Makefile b/sound/soc/at32/Makefile new file mode 100644 index 000000000000..c03e55ececeb --- /dev/null +++ b/sound/soc/at32/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | # AT32 Platform Support | ||
2 | snd-soc-at32-objs := at32-pcm.o | ||
3 | snd-soc-at32-ssc-objs := at32-ssc.o | ||
4 | |||
5 | obj-$(CONFIG_SND_AT32_SOC) += snd-soc-at32.o | ||
6 | obj-$(CONFIG_SND_AT32_SOC_SSC) += snd-soc-at32-ssc.o | ||
7 | |||
8 | # AT32 Machine Support | ||
9 | snd-soc-playpaq-objs := playpaq_wm8510.o | ||
10 | |||
11 | obj-$(CONFIG_SND_AT32_SOC_PLAYPAQ) += snd-soc-playpaq.o | ||
diff --git a/sound/soc/at32/at32-pcm.c b/sound/soc/at32/at32-pcm.c new file mode 100644 index 000000000000..435f1daf177c --- /dev/null +++ b/sound/soc/at32/at32-pcm.c | |||
@@ -0,0 +1,491 @@ | |||
1 | /* sound/soc/at32/at32-pcm.c | ||
2 | * ASoC PCM interface for Atmel AT32 SoC | ||
3 | * | ||
4 | * Copyright (C) 2008 Long Range Systems | ||
5 | * Geoffrey Wossum <gwossum@acm.org> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * Note that this is basically a port of the sound/soc/at91-pcm.c to | ||
12 | * the AVR32 kernel. Thanks to Frank Mandarino for that code. | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/dma-mapping.h> | ||
20 | #include <linux/atmel_pdc.h> | ||
21 | |||
22 | #include <sound/core.h> | ||
23 | #include <sound/pcm.h> | ||
24 | #include <sound/pcm_params.h> | ||
25 | #include <sound/soc.h> | ||
26 | |||
27 | #include "at32-pcm.h" | ||
28 | |||
29 | |||
30 | |||
31 | /*--------------------------------------------------------------------------*\ | ||
32 | * Hardware definition | ||
33 | \*--------------------------------------------------------------------------*/ | ||
34 | /* TODO: These values were taken from the AT91 platform driver, check | ||
35 | * them against real values for AT32 | ||
36 | */ | ||
37 | static const struct snd_pcm_hardware at32_pcm_hardware = { | ||
38 | .info = (SNDRV_PCM_INFO_MMAP | | ||
39 | SNDRV_PCM_INFO_MMAP_VALID | | ||
40 | SNDRV_PCM_INFO_INTERLEAVED | | ||
41 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
42 | SNDRV_PCM_INFO_PAUSE), | ||
43 | |||
44 | .formats = SNDRV_PCM_FMTBIT_S16, | ||
45 | .period_bytes_min = 32, | ||
46 | .period_bytes_max = 8192, /* 512 frames * 16 bytes / frame */ | ||
47 | .periods_min = 2, | ||
48 | .periods_max = 1024, | ||
49 | .buffer_bytes_max = 32 * 1024, | ||
50 | }; | ||
51 | |||
52 | |||
53 | |||
54 | /*--------------------------------------------------------------------------*\ | ||
55 | * Data types | ||
56 | \*--------------------------------------------------------------------------*/ | ||
57 | struct at32_runtime_data { | ||
58 | struct at32_pcm_dma_params *params; | ||
59 | dma_addr_t dma_buffer; /* physical address of DMA buffer */ | ||
60 | dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */ | ||
61 | size_t period_size; | ||
62 | |||
63 | dma_addr_t period_ptr; /* physical address of next period */ | ||
64 | int periods; /* period index of period_ptr */ | ||
65 | |||
66 | /* Save PDC registers (for power management) */ | ||
67 | u32 pdc_xpr_save; | ||
68 | u32 pdc_xcr_save; | ||
69 | u32 pdc_xnpr_save; | ||
70 | u32 pdc_xncr_save; | ||
71 | }; | ||
72 | |||
73 | |||
74 | |||
75 | /*--------------------------------------------------------------------------*\ | ||
76 | * Helper functions | ||
77 | \*--------------------------------------------------------------------------*/ | ||
78 | static int at32_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) | ||
79 | { | ||
80 | struct snd_pcm_substream *substream = pcm->streams[stream].substream; | ||
81 | struct snd_dma_buffer *dmabuf = &substream->dma_buffer; | ||
82 | size_t size = at32_pcm_hardware.buffer_bytes_max; | ||
83 | |||
84 | dmabuf->dev.type = SNDRV_DMA_TYPE_DEV; | ||
85 | dmabuf->dev.dev = pcm->card->dev; | ||
86 | dmabuf->private_data = NULL; | ||
87 | dmabuf->area = dma_alloc_coherent(pcm->card->dev, size, | ||
88 | &dmabuf->addr, GFP_KERNEL); | ||
89 | pr_debug("at32_pcm: preallocate_dma_buffer: " | ||
90 | "area=%p, addr=%p, size=%ld\n", | ||
91 | (void *)dmabuf->area, (void *)dmabuf->addr, size); | ||
92 | |||
93 | if (!dmabuf->area) | ||
94 | return -ENOMEM; | ||
95 | |||
96 | dmabuf->bytes = size; | ||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | |||
101 | |||
102 | /*--------------------------------------------------------------------------*\ | ||
103 | * ISR | ||
104 | \*--------------------------------------------------------------------------*/ | ||
105 | static void at32_pcm_dma_irq(u32 ssc_sr, struct snd_pcm_substream *substream) | ||
106 | { | ||
107 | struct snd_pcm_runtime *rtd = substream->runtime; | ||
108 | struct at32_runtime_data *prtd = rtd->private_data; | ||
109 | struct at32_pcm_dma_params *params = prtd->params; | ||
110 | static int count; | ||
111 | |||
112 | count++; | ||
113 | if (ssc_sr & params->mask->ssc_endbuf) { | ||
114 | pr_warning("at32-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n", | ||
115 | substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? | ||
116 | "underrun" : "overrun", params->name, ssc_sr, count); | ||
117 | |||
118 | /* re-start the PDC */ | ||
119 | ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, | ||
120 | params->mask->pdc_disable); | ||
121 | prtd->period_ptr += prtd->period_size; | ||
122 | if (prtd->period_ptr >= prtd->dma_buffer_end) | ||
123 | prtd->period_ptr = prtd->dma_buffer; | ||
124 | |||
125 | |||
126 | ssc_writex(params->ssc->regs, params->pdc->xpr, | ||
127 | prtd->period_ptr); | ||
128 | ssc_writex(params->ssc->regs, params->pdc->xcr, | ||
129 | prtd->period_size / params->pdc_xfer_size); | ||
130 | ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, | ||
131 | params->mask->pdc_enable); | ||
132 | } | ||
133 | |||
134 | |||
135 | if (ssc_sr & params->mask->ssc_endx) { | ||
136 | /* Load the PDC next pointer and counter registers */ | ||
137 | prtd->period_ptr += prtd->period_size; | ||
138 | if (prtd->period_ptr >= prtd->dma_buffer_end) | ||
139 | prtd->period_ptr = prtd->dma_buffer; | ||
140 | ssc_writex(params->ssc->regs, params->pdc->xnpr, | ||
141 | prtd->period_ptr); | ||
142 | ssc_writex(params->ssc->regs, params->pdc->xncr, | ||
143 | prtd->period_size / params->pdc_xfer_size); | ||
144 | } | ||
145 | |||
146 | |||
147 | snd_pcm_period_elapsed(substream); | ||
148 | } | ||
149 | |||
150 | |||
151 | |||
152 | /*--------------------------------------------------------------------------*\ | ||
153 | * PCM operations | ||
154 | \*--------------------------------------------------------------------------*/ | ||
155 | static int at32_pcm_hw_params(struct snd_pcm_substream *substream, | ||
156 | struct snd_pcm_hw_params *params) | ||
157 | { | ||
158 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
159 | struct at32_runtime_data *prtd = runtime->private_data; | ||
160 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
161 | |||
162 | /* this may get called several times by oss emulation | ||
163 | * with different params | ||
164 | */ | ||
165 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | ||
166 | runtime->dma_bytes = params_buffer_bytes(params); | ||
167 | |||
168 | prtd->params = rtd->dai->cpu_dai->dma_data; | ||
169 | prtd->params->dma_intr_handler = at32_pcm_dma_irq; | ||
170 | |||
171 | prtd->dma_buffer = runtime->dma_addr; | ||
172 | prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes; | ||
173 | prtd->period_size = params_period_bytes(params); | ||
174 | |||
175 | pr_debug("hw_params: DMA for %s initialized " | ||
176 | "(dma_bytes=%ld, period_size=%ld)\n", | ||
177 | prtd->params->name, runtime->dma_bytes, prtd->period_size); | ||
178 | |||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | |||
183 | |||
184 | static int at32_pcm_hw_free(struct snd_pcm_substream *substream) | ||
185 | { | ||
186 | struct at32_runtime_data *prtd = substream->runtime->private_data; | ||
187 | struct at32_pcm_dma_params *params = prtd->params; | ||
188 | |||
189 | if (params != NULL) { | ||
190 | ssc_writex(params->ssc->regs, SSC_PDC_PTCR, | ||
191 | params->mask->pdc_disable); | ||
192 | prtd->params->dma_intr_handler = NULL; | ||
193 | } | ||
194 | |||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | |||
199 | |||
200 | static int at32_pcm_prepare(struct snd_pcm_substream *substream) | ||
201 | { | ||
202 | struct at32_runtime_data *prtd = substream->runtime->private_data; | ||
203 | struct at32_pcm_dma_params *params = prtd->params; | ||
204 | |||
205 | ssc_writex(params->ssc->regs, SSC_IDR, | ||
206 | params->mask->ssc_endx | params->mask->ssc_endbuf); | ||
207 | ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, | ||
208 | params->mask->pdc_disable); | ||
209 | |||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | |||
214 | static int at32_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
215 | { | ||
216 | struct snd_pcm_runtime *rtd = substream->runtime; | ||
217 | struct at32_runtime_data *prtd = rtd->private_data; | ||
218 | struct at32_pcm_dma_params *params = prtd->params; | ||
219 | int ret = 0; | ||
220 | |||
221 | pr_debug("at32_pcm_trigger: buffer_size = %ld, " | ||
222 | "dma_area = %p, dma_bytes = %ld\n", | ||
223 | rtd->buffer_size, rtd->dma_area, rtd->dma_bytes); | ||
224 | |||
225 | switch (cmd) { | ||
226 | case SNDRV_PCM_TRIGGER_START: | ||
227 | prtd->period_ptr = prtd->dma_buffer; | ||
228 | |||
229 | ssc_writex(params->ssc->regs, params->pdc->xpr, | ||
230 | prtd->period_ptr); | ||
231 | ssc_writex(params->ssc->regs, params->pdc->xcr, | ||
232 | prtd->period_size / params->pdc_xfer_size); | ||
233 | |||
234 | prtd->period_ptr += prtd->period_size; | ||
235 | ssc_writex(params->ssc->regs, params->pdc->xnpr, | ||
236 | prtd->period_ptr); | ||
237 | ssc_writex(params->ssc->regs, params->pdc->xncr, | ||
238 | prtd->period_size / params->pdc_xfer_size); | ||
239 | |||
240 | pr_debug("trigger: period_ptr=%lx, xpr=%x, " | ||
241 | "xcr=%d, xnpr=%x, xncr=%d\n", | ||
242 | (unsigned long)prtd->period_ptr, | ||
243 | ssc_readx(params->ssc->regs, params->pdc->xpr), | ||
244 | ssc_readx(params->ssc->regs, params->pdc->xcr), | ||
245 | ssc_readx(params->ssc->regs, params->pdc->xnpr), | ||
246 | ssc_readx(params->ssc->regs, params->pdc->xncr)); | ||
247 | |||
248 | ssc_writex(params->ssc->regs, SSC_IER, | ||
249 | params->mask->ssc_endx | params->mask->ssc_endbuf); | ||
250 | ssc_writex(params->ssc->regs, SSC_PDC_PTCR, | ||
251 | params->mask->pdc_enable); | ||
252 | |||
253 | pr_debug("sr=%x, imr=%x\n", | ||
254 | ssc_readx(params->ssc->regs, SSC_SR), | ||
255 | ssc_readx(params->ssc->regs, SSC_IER)); | ||
256 | break; /* SNDRV_PCM_TRIGGER_START */ | ||
257 | |||
258 | |||
259 | |||
260 | case SNDRV_PCM_TRIGGER_STOP: | ||
261 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
262 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
263 | ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, | ||
264 | params->mask->pdc_disable); | ||
265 | break; | ||
266 | |||
267 | |||
268 | case SNDRV_PCM_TRIGGER_RESUME: | ||
269 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
270 | ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, | ||
271 | params->mask->pdc_enable); | ||
272 | break; | ||
273 | |||
274 | default: | ||
275 | ret = -EINVAL; | ||
276 | } | ||
277 | |||
278 | return ret; | ||
279 | } | ||
280 | |||
281 | |||
282 | |||
283 | static snd_pcm_uframes_t at32_pcm_pointer(struct snd_pcm_substream *substream) | ||
284 | { | ||
285 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
286 | struct at32_runtime_data *prtd = runtime->private_data; | ||
287 | struct at32_pcm_dma_params *params = prtd->params; | ||
288 | dma_addr_t ptr; | ||
289 | snd_pcm_uframes_t x; | ||
290 | |||
291 | ptr = (dma_addr_t) ssc_readx(params->ssc->regs, params->pdc->xpr); | ||
292 | x = bytes_to_frames(runtime, ptr - prtd->dma_buffer); | ||
293 | |||
294 | if (x == runtime->buffer_size) | ||
295 | x = 0; | ||
296 | |||
297 | return x; | ||
298 | } | ||
299 | |||
300 | |||
301 | |||
302 | static int at32_pcm_open(struct snd_pcm_substream *substream) | ||
303 | { | ||
304 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
305 | struct at32_runtime_data *prtd; | ||
306 | int ret = 0; | ||
307 | |||
308 | snd_soc_set_runtime_hwparams(substream, &at32_pcm_hardware); | ||
309 | |||
310 | /* ensure that buffer size is a multiple of period size */ | ||
311 | ret = snd_pcm_hw_constraint_integer(runtime, | ||
312 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
313 | if (ret < 0) | ||
314 | goto out; | ||
315 | |||
316 | prtd = kzalloc(sizeof(*prtd), GFP_KERNEL); | ||
317 | if (prtd == NULL) { | ||
318 | ret = -ENOMEM; | ||
319 | goto out; | ||
320 | } | ||
321 | runtime->private_data = prtd; | ||
322 | |||
323 | |||
324 | out: | ||
325 | return ret; | ||
326 | } | ||
327 | |||
328 | |||
329 | |||
330 | static int at32_pcm_close(struct snd_pcm_substream *substream) | ||
331 | { | ||
332 | struct at32_runtime_data *prtd = substream->runtime->private_data; | ||
333 | |||
334 | kfree(prtd); | ||
335 | return 0; | ||
336 | } | ||
337 | |||
338 | |||
339 | static int at32_pcm_mmap(struct snd_pcm_substream *substream, | ||
340 | struct vm_area_struct *vma) | ||
341 | { | ||
342 | return remap_pfn_range(vma, vma->vm_start, | ||
343 | substream->dma_buffer.addr >> PAGE_SHIFT, | ||
344 | vma->vm_end - vma->vm_start, vma->vm_page_prot); | ||
345 | } | ||
346 | |||
347 | |||
348 | |||
349 | static struct snd_pcm_ops at32_pcm_ops = { | ||
350 | .open = at32_pcm_open, | ||
351 | .close = at32_pcm_close, | ||
352 | .ioctl = snd_pcm_lib_ioctl, | ||
353 | .hw_params = at32_pcm_hw_params, | ||
354 | .hw_free = at32_pcm_hw_free, | ||
355 | .prepare = at32_pcm_prepare, | ||
356 | .trigger = at32_pcm_trigger, | ||
357 | .pointer = at32_pcm_pointer, | ||
358 | .mmap = at32_pcm_mmap, | ||
359 | }; | ||
360 | |||
361 | |||
362 | |||
363 | /*--------------------------------------------------------------------------*\ | ||
364 | * ASoC platform driver | ||
365 | \*--------------------------------------------------------------------------*/ | ||
366 | static u64 at32_pcm_dmamask = 0xffffffff; | ||
367 | |||
368 | static int at32_pcm_new(struct snd_card *card, | ||
369 | struct snd_soc_dai *dai, | ||
370 | struct snd_pcm *pcm) | ||
371 | { | ||
372 | int ret = 0; | ||
373 | |||
374 | if (!card->dev->dma_mask) | ||
375 | card->dev->dma_mask = &at32_pcm_dmamask; | ||
376 | if (!card->dev->coherent_dma_mask) | ||
377 | card->dev->coherent_dma_mask = 0xffffffff; | ||
378 | |||
379 | if (dai->playback.channels_min) { | ||
380 | ret = at32_pcm_preallocate_dma_buffer( | ||
381 | pcm, SNDRV_PCM_STREAM_PLAYBACK); | ||
382 | if (ret) | ||
383 | goto out; | ||
384 | } | ||
385 | |||
386 | if (dai->capture.channels_min) { | ||
387 | pr_debug("at32-pcm: Allocating PCM capture DMA buffer\n"); | ||
388 | ret = at32_pcm_preallocate_dma_buffer( | ||
389 | pcm, SNDRV_PCM_STREAM_CAPTURE); | ||
390 | if (ret) | ||
391 | goto out; | ||
392 | } | ||
393 | |||
394 | |||
395 | out: | ||
396 | return ret; | ||
397 | } | ||
398 | |||
399 | |||
400 | |||
401 | static void at32_pcm_free_dma_buffers(struct snd_pcm *pcm) | ||
402 | { | ||
403 | struct snd_pcm_substream *substream; | ||
404 | struct snd_dma_buffer *buf; | ||
405 | int stream; | ||
406 | |||
407 | for (stream = 0; stream < 2; stream++) { | ||
408 | substream = pcm->streams[stream].substream; | ||
409 | if (substream == NULL) | ||
410 | continue; | ||
411 | |||
412 | buf = &substream->dma_buffer; | ||
413 | if (!buf->area) | ||
414 | continue; | ||
415 | dma_free_coherent(pcm->card->dev, buf->bytes, | ||
416 | buf->area, buf->addr); | ||
417 | buf->area = NULL; | ||
418 | } | ||
419 | } | ||
420 | |||
421 | |||
422 | |||
423 | #ifdef CONFIG_PM | ||
424 | static int at32_pcm_suspend(struct platform_device *pdev, | ||
425 | struct snd_soc_dai *dai) | ||
426 | { | ||
427 | struct snd_pcm_runtime *runtime = dai->runtime; | ||
428 | struct at32_runtime_data *prtd; | ||
429 | struct at32_pcm_dma_params *params; | ||
430 | |||
431 | if (runtime == NULL) | ||
432 | return 0; | ||
433 | prtd = runtime->private_data; | ||
434 | params = prtd->params; | ||
435 | |||
436 | /* Disable the PDC and save the PDC registers */ | ||
437 | ssc_writex(params->ssc->regs, PDC_PTCR, params->mask->pdc_disable); | ||
438 | |||
439 | prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr); | ||
440 | prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr); | ||
441 | prtd->pdc_xnpr_save = ssc_readx(params->ssc->regs, params->pdc->xnpr); | ||
442 | prtd->pdc_xncr_save = ssc_readx(params->ssc->regs, params->pdc->xncr); | ||
443 | |||
444 | return 0; | ||
445 | } | ||
446 | |||
447 | |||
448 | |||
449 | static int at32_pcm_resume(struct platform_device *pdev, | ||
450 | struct snd_soc_dai *dai) | ||
451 | { | ||
452 | struct snd_pcm_runtime *runtime = dai->runtime; | ||
453 | struct at32_runtime_data *prtd; | ||
454 | struct at32_pcm_dma_params *params; | ||
455 | |||
456 | if (runtime == NULL) | ||
457 | return 0; | ||
458 | prtd = runtime->private_data; | ||
459 | params = prtd->params; | ||
460 | |||
461 | /* Restore the PDC registers and enable the PDC */ | ||
462 | ssc_writex(params->ssc->regs, params->pdc->xpr, prtd->pdc_xpr_save); | ||
463 | ssc_writex(params->ssc->regs, params->pdc->xcr, prtd->pdc_xcr_save); | ||
464 | ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save); | ||
465 | ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save); | ||
466 | |||
467 | ssc_writex(params->ssc->regs, PDC_PTCR, params->mask->pdc_enable); | ||
468 | return 0; | ||
469 | } | ||
470 | #else /* CONFIG_PM */ | ||
471 | # define at32_pcm_suspend NULL | ||
472 | # define at32_pcm_resume NULL | ||
473 | #endif /* CONFIG_PM */ | ||
474 | |||
475 | |||
476 | |||
477 | struct snd_soc_platform at32_soc_platform = { | ||
478 | .name = "at32-audio", | ||
479 | .pcm_ops = &at32_pcm_ops, | ||
480 | .pcm_new = at32_pcm_new, | ||
481 | .pcm_free = at32_pcm_free_dma_buffers, | ||
482 | .suspend = at32_pcm_suspend, | ||
483 | .resume = at32_pcm_resume, | ||
484 | }; | ||
485 | EXPORT_SYMBOL_GPL(at32_soc_platform); | ||
486 | |||
487 | |||
488 | |||
489 | MODULE_AUTHOR("Geoffrey Wossum <gwossum@acm.org>"); | ||
490 | MODULE_DESCRIPTION("Atmel AT32 PCM module"); | ||
491 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/at32/at32-pcm.h b/sound/soc/at32/at32-pcm.h new file mode 100644 index 000000000000..2a52430417da --- /dev/null +++ b/sound/soc/at32/at32-pcm.h | |||
@@ -0,0 +1,79 @@ | |||
1 | /* sound/soc/at32/at32-pcm.h | ||
2 | * ASoC PCM interface for Atmel AT32 SoC | ||
3 | * | ||
4 | * Copyright (C) 2008 Long Range Systems | ||
5 | * Geoffrey Wossum <gwossum@acm.org> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef __SOUND_SOC_AT32_AT32_PCM_H | ||
13 | #define __SOUND_SOC_AT32_AT32_PCM_H __FILE__ | ||
14 | |||
15 | #include <linux/atmel-ssc.h> | ||
16 | |||
17 | |||
18 | /* | ||
19 | * Registers and status bits that are required by the PCM driver | ||
20 | * TODO: Is ptcr really used? | ||
21 | */ | ||
22 | struct at32_pdc_regs { | ||
23 | u32 xpr; /* PDC RX/TX pointer */ | ||
24 | u32 xcr; /* PDC RX/TX counter */ | ||
25 | u32 xnpr; /* PDC next RX/TX pointer */ | ||
26 | u32 xncr; /* PDC next RX/TX counter */ | ||
27 | u32 ptcr; /* PDC transfer control */ | ||
28 | }; | ||
29 | |||
30 | |||
31 | |||
32 | /* | ||
33 | * SSC mask info | ||
34 | */ | ||
35 | struct at32_ssc_mask { | ||
36 | u32 ssc_enable; /* SSC RX/TX enable */ | ||
37 | u32 ssc_disable; /* SSC RX/TX disable */ | ||
38 | u32 ssc_endx; /* SSC ENDTX or ENDRX */ | ||
39 | u32 ssc_endbuf; /* SSC TXBUFF or RXBUFF */ | ||
40 | u32 pdc_enable; /* PDC RX/TX enable */ | ||
41 | u32 pdc_disable; /* PDC RX/TX disable */ | ||
42 | }; | ||
43 | |||
44 | |||
45 | |||
46 | /* | ||
47 | * This structure, shared between the PCM driver and the interface, | ||
48 | * contains all information required by the PCM driver to perform the | ||
49 | * PDC DMA operation. All fields except dma_intr_handler() are initialized | ||
50 | * by the interface. The dms_intr_handler() pointer is set by the PCM | ||
51 | * driver and called by the interface SSC interrupt handler if it is | ||
52 | * non-NULL. | ||
53 | */ | ||
54 | struct at32_pcm_dma_params { | ||
55 | char *name; /* stream identifier */ | ||
56 | int pdc_xfer_size; /* PDC counter increment in bytes */ | ||
57 | struct ssc_device *ssc; /* SSC device for stream */ | ||
58 | struct at32_pdc_regs *pdc; /* PDC register info */ | ||
59 | struct at32_ssc_mask *mask; /* SSC mask info */ | ||
60 | struct snd_pcm_substream *substream; | ||
61 | void (*dma_intr_handler) (u32, struct snd_pcm_substream *); | ||
62 | }; | ||
63 | |||
64 | |||
65 | |||
66 | /* | ||
67 | * The AT32 ASoC platform driver | ||
68 | */ | ||
69 | extern struct snd_soc_platform at32_soc_platform; | ||
70 | |||
71 | |||
72 | |||
73 | /* | ||
74 | * SSC register access (since ssc_writel() / ssc_readl() require literal name) | ||
75 | */ | ||
76 | #define ssc_readx(base, reg) (__raw_readl((base) + (reg))) | ||
77 | #define ssc_writex(base, reg, value) __raw_writel((value), (base) + (reg)) | ||
78 | |||
79 | #endif /* __SOUND_SOC_AT32_AT32_PCM_H */ | ||
diff --git a/sound/soc/at32/at32-ssc.c b/sound/soc/at32/at32-ssc.c new file mode 100644 index 000000000000..4ef6492c902e --- /dev/null +++ b/sound/soc/at32/at32-ssc.c | |||
@@ -0,0 +1,849 @@ | |||
1 | /* sound/soc/at32/at32-ssc.c | ||
2 | * ASoC platform driver for AT32 using SSC as DAI | ||
3 | * | ||
4 | * Copyright (C) 2008 Long Range Systems | ||
5 | * Geoffrey Wossum <gwossum@acm.org> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * Note that this is basically a port of the sound/soc/at91-ssc.c to | ||
12 | * the AVR32 kernel. Thanks to Frank Mandarino for that code. | ||
13 | */ | ||
14 | |||
15 | /* #define DEBUG */ | ||
16 | |||
17 | #include <linux/init.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/device.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/clk.h> | ||
23 | #include <linux/io.h> | ||
24 | #include <linux/atmel_pdc.h> | ||
25 | #include <linux/atmel-ssc.h> | ||
26 | |||
27 | #include <sound/core.h> | ||
28 | #include <sound/pcm.h> | ||
29 | #include <sound/pcm_params.h> | ||
30 | #include <sound/initval.h> | ||
31 | #include <sound/soc.h> | ||
32 | |||
33 | #include "at32-pcm.h" | ||
34 | #include "at32-ssc.h" | ||
35 | |||
36 | |||
37 | |||
38 | /*-------------------------------------------------------------------------*\ | ||
39 | * Constants | ||
40 | \*-------------------------------------------------------------------------*/ | ||
41 | #define NUM_SSC_DEVICES 3 | ||
42 | |||
43 | /* | ||
44 | * SSC direction masks | ||
45 | */ | ||
46 | #define SSC_DIR_MASK_UNUSED 0 | ||
47 | #define SSC_DIR_MASK_PLAYBACK 1 | ||
48 | #define SSC_DIR_MASK_CAPTURE 2 | ||
49 | |||
50 | /* | ||
51 | * SSC register values that Atmel left out of <linux/atmel-ssc.h>. These | ||
52 | * are expected to be used with SSC_BF | ||
53 | */ | ||
54 | /* START bit field values */ | ||
55 | #define SSC_START_CONTINUOUS 0 | ||
56 | #define SSC_START_TX_RX 1 | ||
57 | #define SSC_START_LOW_RF 2 | ||
58 | #define SSC_START_HIGH_RF 3 | ||
59 | #define SSC_START_FALLING_RF 4 | ||
60 | #define SSC_START_RISING_RF 5 | ||
61 | #define SSC_START_LEVEL_RF 6 | ||
62 | #define SSC_START_EDGE_RF 7 | ||
63 | #define SSS_START_COMPARE_0 8 | ||
64 | |||
65 | /* CKI bit field values */ | ||
66 | #define SSC_CKI_FALLING 0 | ||
67 | #define SSC_CKI_RISING 1 | ||
68 | |||
69 | /* CKO bit field values */ | ||
70 | #define SSC_CKO_NONE 0 | ||
71 | #define SSC_CKO_CONTINUOUS 1 | ||
72 | #define SSC_CKO_TRANSFER 2 | ||
73 | |||
74 | /* CKS bit field values */ | ||
75 | #define SSC_CKS_DIV 0 | ||
76 | #define SSC_CKS_CLOCK 1 | ||
77 | #define SSC_CKS_PIN 2 | ||
78 | |||
79 | /* FSEDGE bit field values */ | ||
80 | #define SSC_FSEDGE_POSITIVE 0 | ||
81 | #define SSC_FSEDGE_NEGATIVE 1 | ||
82 | |||
83 | /* FSOS bit field values */ | ||
84 | #define SSC_FSOS_NONE 0 | ||
85 | #define SSC_FSOS_NEGATIVE 1 | ||
86 | #define SSC_FSOS_POSITIVE 2 | ||
87 | #define SSC_FSOS_LOW 3 | ||
88 | #define SSC_FSOS_HIGH 4 | ||
89 | #define SSC_FSOS_TOGGLE 5 | ||
90 | |||
91 | #define START_DELAY 1 | ||
92 | |||
93 | |||
94 | |||
95 | /*-------------------------------------------------------------------------*\ | ||
96 | * Module data | ||
97 | \*-------------------------------------------------------------------------*/ | ||
98 | /* | ||
99 | * SSC PDC registered required by the PCM DMA engine | ||
100 | */ | ||
101 | static struct at32_pdc_regs pdc_tx_reg = { | ||
102 | .xpr = SSC_PDC_TPR, | ||
103 | .xcr = SSC_PDC_TCR, | ||
104 | .xnpr = SSC_PDC_TNPR, | ||
105 | .xncr = SSC_PDC_TNCR, | ||
106 | }; | ||
107 | |||
108 | |||
109 | |||
110 | static struct at32_pdc_regs pdc_rx_reg = { | ||
111 | .xpr = SSC_PDC_RPR, | ||
112 | .xcr = SSC_PDC_RCR, | ||
113 | .xnpr = SSC_PDC_RNPR, | ||
114 | .xncr = SSC_PDC_RNCR, | ||
115 | }; | ||
116 | |||
117 | |||
118 | |||
119 | /* | ||
120 | * SSC and PDC status bits for transmit and receive | ||
121 | */ | ||
122 | static struct at32_ssc_mask ssc_tx_mask = { | ||
123 | .ssc_enable = SSC_BIT(CR_TXEN), | ||
124 | .ssc_disable = SSC_BIT(CR_TXDIS), | ||
125 | .ssc_endx = SSC_BIT(SR_ENDTX), | ||
126 | .ssc_endbuf = SSC_BIT(SR_TXBUFE), | ||
127 | .pdc_enable = SSC_BIT(PDC_PTCR_TXTEN), | ||
128 | .pdc_disable = SSC_BIT(PDC_PTCR_TXTDIS), | ||
129 | }; | ||
130 | |||
131 | |||
132 | |||
133 | static struct at32_ssc_mask ssc_rx_mask = { | ||
134 | .ssc_enable = SSC_BIT(CR_RXEN), | ||
135 | .ssc_disable = SSC_BIT(CR_RXDIS), | ||
136 | .ssc_endx = SSC_BIT(SR_ENDRX), | ||
137 | .ssc_endbuf = SSC_BIT(SR_RXBUFF), | ||
138 | .pdc_enable = SSC_BIT(PDC_PTCR_RXTEN), | ||
139 | .pdc_disable = SSC_BIT(PDC_PTCR_RXTDIS), | ||
140 | }; | ||
141 | |||
142 | |||
143 | |||
144 | /* | ||
145 | * DMA parameters for each SSC | ||
146 | */ | ||
147 | static struct at32_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = { | ||
148 | { | ||
149 | { | ||
150 | .name = "SSC0 PCM out", | ||
151 | .pdc = &pdc_tx_reg, | ||
152 | .mask = &ssc_tx_mask, | ||
153 | }, | ||
154 | { | ||
155 | .name = "SSC0 PCM in", | ||
156 | .pdc = &pdc_rx_reg, | ||
157 | .mask = &ssc_rx_mask, | ||
158 | }, | ||
159 | }, | ||
160 | { | ||
161 | { | ||
162 | .name = "SSC1 PCM out", | ||
163 | .pdc = &pdc_tx_reg, | ||
164 | .mask = &ssc_tx_mask, | ||
165 | }, | ||
166 | { | ||
167 | .name = "SSC1 PCM in", | ||
168 | .pdc = &pdc_rx_reg, | ||
169 | .mask = &ssc_rx_mask, | ||
170 | }, | ||
171 | }, | ||
172 | { | ||
173 | { | ||
174 | .name = "SSC2 PCM out", | ||
175 | .pdc = &pdc_tx_reg, | ||
176 | .mask = &ssc_tx_mask, | ||
177 | }, | ||
178 | { | ||
179 | .name = "SSC2 PCM in", | ||
180 | .pdc = &pdc_rx_reg, | ||
181 | .mask = &ssc_rx_mask, | ||
182 | }, | ||
183 | }, | ||
184 | }; | ||
185 | |||
186 | |||
187 | |||
188 | static struct at32_ssc_info ssc_info[NUM_SSC_DEVICES] = { | ||
189 | { | ||
190 | .name = "ssc0", | ||
191 | .lock = __SPIN_LOCK_UNLOCKED(ssc_info[0].lock), | ||
192 | .dir_mask = SSC_DIR_MASK_UNUSED, | ||
193 | .initialized = 0, | ||
194 | }, | ||
195 | { | ||
196 | .name = "ssc1", | ||
197 | .lock = __SPIN_LOCK_UNLOCKED(ssc_info[1].lock), | ||
198 | .dir_mask = SSC_DIR_MASK_UNUSED, | ||
199 | .initialized = 0, | ||
200 | }, | ||
201 | { | ||
202 | .name = "ssc2", | ||
203 | .lock = __SPIN_LOCK_UNLOCKED(ssc_info[2].lock), | ||
204 | .dir_mask = SSC_DIR_MASK_UNUSED, | ||
205 | .initialized = 0, | ||
206 | }, | ||
207 | }; | ||
208 | |||
209 | |||
210 | |||
211 | |||
212 | /*-------------------------------------------------------------------------*\ | ||
213 | * ISR | ||
214 | \*-------------------------------------------------------------------------*/ | ||
215 | /* | ||
216 | * SSC interrupt handler. Passes PDC interrupts to the DMA interrupt | ||
217 | * handler in the PCM driver. | ||
218 | */ | ||
219 | static irqreturn_t at32_ssc_interrupt(int irq, void *dev_id) | ||
220 | { | ||
221 | struct at32_ssc_info *ssc_p = dev_id; | ||
222 | struct at32_pcm_dma_params *dma_params; | ||
223 | u32 ssc_sr; | ||
224 | u32 ssc_substream_mask; | ||
225 | int i; | ||
226 | |||
227 | ssc_sr = (ssc_readl(ssc_p->ssc->regs, SR) & | ||
228 | ssc_readl(ssc_p->ssc->regs, IMR)); | ||
229 | |||
230 | /* | ||
231 | * Loop through substreams attached to this SSC. If a DMA-related | ||
232 | * interrupt occured on that substream, call the DMA interrupt | ||
233 | * handler function, if one has been registered in the dma_param | ||
234 | * structure by the PCM driver. | ||
235 | */ | ||
236 | for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) { | ||
237 | dma_params = ssc_p->dma_params[i]; | ||
238 | |||
239 | if ((dma_params != NULL) && | ||
240 | (dma_params->dma_intr_handler != NULL)) { | ||
241 | ssc_substream_mask = (dma_params->mask->ssc_endx | | ||
242 | dma_params->mask->ssc_endbuf); | ||
243 | if (ssc_sr & ssc_substream_mask) { | ||
244 | dma_params->dma_intr_handler(ssc_sr, | ||
245 | dma_params-> | ||
246 | substream); | ||
247 | } | ||
248 | } | ||
249 | } | ||
250 | |||
251 | |||
252 | return IRQ_HANDLED; | ||
253 | } | ||
254 | |||
255 | /*-------------------------------------------------------------------------*\ | ||
256 | * DAI functions | ||
257 | \*-------------------------------------------------------------------------*/ | ||
258 | /* | ||
259 | * Startup. Only that one substream allowed in each direction. | ||
260 | */ | ||
261 | static int at32_ssc_startup(struct snd_pcm_substream *substream) | ||
262 | { | ||
263 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
264 | struct at32_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; | ||
265 | int dir_mask; | ||
266 | |||
267 | dir_mask = ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? | ||
268 | SSC_DIR_MASK_PLAYBACK : SSC_DIR_MASK_CAPTURE); | ||
269 | |||
270 | spin_lock_irq(&ssc_p->lock); | ||
271 | if (ssc_p->dir_mask & dir_mask) { | ||
272 | spin_unlock_irq(&ssc_p->lock); | ||
273 | return -EBUSY; | ||
274 | } | ||
275 | ssc_p->dir_mask |= dir_mask; | ||
276 | spin_unlock_irq(&ssc_p->lock); | ||
277 | |||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | |||
282 | |||
283 | /* | ||
284 | * Shutdown. Clear DMA parameters and shutdown the SSC if there | ||
285 | * are no other substreams open. | ||
286 | */ | ||
287 | static void at32_ssc_shutdown(struct snd_pcm_substream *substream) | ||
288 | { | ||
289 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
290 | struct at32_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; | ||
291 | struct at32_pcm_dma_params *dma_params; | ||
292 | int dir_mask; | ||
293 | |||
294 | dma_params = ssc_p->dma_params[substream->stream]; | ||
295 | |||
296 | if (dma_params != NULL) { | ||
297 | ssc_writel(dma_params->ssc->regs, CR, | ||
298 | dma_params->mask->ssc_disable); | ||
299 | pr_debug("%s disabled SSC_SR=0x%08x\n", | ||
300 | (substream->stream ? "receiver" : "transmit"), | ||
301 | ssc_readl(ssc_p->ssc->regs, SR)); | ||
302 | |||
303 | dma_params->ssc = NULL; | ||
304 | dma_params->substream = NULL; | ||
305 | ssc_p->dma_params[substream->stream] = NULL; | ||
306 | } | ||
307 | |||
308 | |||
309 | dir_mask = 1 << substream->stream; | ||
310 | spin_lock_irq(&ssc_p->lock); | ||
311 | ssc_p->dir_mask &= ~dir_mask; | ||
312 | if (!ssc_p->dir_mask) { | ||
313 | /* Shutdown the SSC clock */ | ||
314 | pr_debug("at32-ssc: Stopping user %d clock\n", | ||
315 | ssc_p->ssc->user); | ||
316 | clk_disable(ssc_p->ssc->clk); | ||
317 | |||
318 | if (ssc_p->initialized) { | ||
319 | free_irq(ssc_p->ssc->irq, ssc_p); | ||
320 | ssc_p->initialized = 0; | ||
321 | } | ||
322 | |||
323 | /* Reset the SSC */ | ||
324 | ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); | ||
325 | |||
326 | /* clear the SSC dividers */ | ||
327 | ssc_p->cmr_div = 0; | ||
328 | ssc_p->tcmr_period = 0; | ||
329 | ssc_p->rcmr_period = 0; | ||
330 | } | ||
331 | spin_unlock_irq(&ssc_p->lock); | ||
332 | } | ||
333 | |||
334 | |||
335 | |||
336 | /* | ||
337 | * Set the SSC system clock rate | ||
338 | */ | ||
339 | static int at32_ssc_set_dai_sysclk(struct snd_soc_dai *cpu_dai, | ||
340 | int clk_id, unsigned int freq, int dir) | ||
341 | { | ||
342 | /* TODO: What the heck do I do here? */ | ||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | |||
347 | |||
348 | /* | ||
349 | * Record DAI format for use by hw_params() | ||
350 | */ | ||
351 | static int at32_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai, | ||
352 | unsigned int fmt) | ||
353 | { | ||
354 | struct at32_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; | ||
355 | |||
356 | ssc_p->daifmt = fmt; | ||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | |||
361 | |||
362 | /* | ||
363 | * Record SSC clock dividers for use in hw_params() | ||
364 | */ | ||
365 | static int at32_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, | ||
366 | int div_id, int div) | ||
367 | { | ||
368 | struct at32_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; | ||
369 | |||
370 | switch (div_id) { | ||
371 | case AT32_SSC_CMR_DIV: | ||
372 | /* | ||
373 | * The same master clock divider is used for both | ||
374 | * transmit and receive, so if a value has already | ||
375 | * been set, it must match this value | ||
376 | */ | ||
377 | if (ssc_p->cmr_div == 0) | ||
378 | ssc_p->cmr_div = div; | ||
379 | else if (div != ssc_p->cmr_div) | ||
380 | return -EBUSY; | ||
381 | break; | ||
382 | |||
383 | case AT32_SSC_TCMR_PERIOD: | ||
384 | ssc_p->tcmr_period = div; | ||
385 | break; | ||
386 | |||
387 | case AT32_SSC_RCMR_PERIOD: | ||
388 | ssc_p->rcmr_period = div; | ||
389 | break; | ||
390 | |||
391 | default: | ||
392 | return -EINVAL; | ||
393 | } | ||
394 | |||
395 | return 0; | ||
396 | } | ||
397 | |||
398 | |||
399 | |||
400 | /* | ||
401 | * Configure the SSC | ||
402 | */ | ||
403 | static int at32_ssc_hw_params(struct snd_pcm_substream *substream, | ||
404 | struct snd_pcm_hw_params *params) | ||
405 | { | ||
406 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
407 | int id = rtd->dai->cpu_dai->id; | ||
408 | struct at32_ssc_info *ssc_p = &ssc_info[id]; | ||
409 | struct at32_pcm_dma_params *dma_params; | ||
410 | int channels, bits; | ||
411 | u32 tfmr, rfmr, tcmr, rcmr; | ||
412 | int start_event; | ||
413 | int ret; | ||
414 | |||
415 | |||
416 | /* | ||
417 | * Currently, there is only one set of dma_params for each direction. | ||
418 | * If more are added, this code will have to be changed to select | ||
419 | * the proper set | ||
420 | */ | ||
421 | dma_params = &ssc_dma_params[id][substream->stream]; | ||
422 | dma_params->ssc = ssc_p->ssc; | ||
423 | dma_params->substream = substream; | ||
424 | |||
425 | ssc_p->dma_params[substream->stream] = dma_params; | ||
426 | |||
427 | |||
428 | /* | ||
429 | * The cpu_dai->dma_data field is only used to communicate the | ||
430 | * appropriate DMA parameters to the PCM driver's hw_params() | ||
431 | * function. It should not be used for other purposes as it | ||
432 | * is common to all substreams. | ||
433 | */ | ||
434 | rtd->dai->cpu_dai->dma_data = dma_params; | ||
435 | |||
436 | channels = params_channels(params); | ||
437 | |||
438 | |||
439 | /* | ||
440 | * Determine sample size in bits and the PDC increment | ||
441 | */ | ||
442 | switch (params_format(params)) { | ||
443 | case SNDRV_PCM_FORMAT_S8: | ||
444 | bits = 8; | ||
445 | dma_params->pdc_xfer_size = 1; | ||
446 | break; | ||
447 | |||
448 | case SNDRV_PCM_FORMAT_S16: | ||
449 | bits = 16; | ||
450 | dma_params->pdc_xfer_size = 2; | ||
451 | break; | ||
452 | |||
453 | case SNDRV_PCM_FORMAT_S24: | ||
454 | bits = 24; | ||
455 | dma_params->pdc_xfer_size = 4; | ||
456 | break; | ||
457 | |||
458 | case SNDRV_PCM_FORMAT_S32: | ||
459 | bits = 32; | ||
460 | dma_params->pdc_xfer_size = 4; | ||
461 | break; | ||
462 | |||
463 | default: | ||
464 | pr_warning("at32-ssc: Unsupported PCM format %d", | ||
465 | params_format(params)); | ||
466 | return -EINVAL; | ||
467 | } | ||
468 | pr_debug("at32-ssc: bits = %d, pdc_xfer_size = %d, channels = %d\n", | ||
469 | bits, dma_params->pdc_xfer_size, channels); | ||
470 | |||
471 | |||
472 | /* | ||
473 | * The SSC only supports up to 16-bit samples in I2S format, due | ||
474 | * to the size of the Frame Mode Register FSLEN field. | ||
475 | */ | ||
476 | if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S) | ||
477 | if (bits > 16) { | ||
478 | pr_warning("at32-ssc: " | ||
479 | "sample size %d is too large for I2S\n", | ||
480 | bits); | ||
481 | return -EINVAL; | ||
482 | } | ||
483 | |||
484 | |||
485 | /* | ||
486 | * Compute the SSC register settings | ||
487 | */ | ||
488 | switch (ssc_p->daifmt & (SND_SOC_DAIFMT_FORMAT_MASK | | ||
489 | SND_SOC_DAIFMT_MASTER_MASK)) { | ||
490 | case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS: | ||
491 | /* | ||
492 | * I2S format, SSC provides BCLK and LRS clocks. | ||
493 | * | ||
494 | * The SSC transmit and receive clocks are generated from the | ||
495 | * MCK divider, and the BCLK signal is output on the SSC TK line | ||
496 | */ | ||
497 | pr_debug("at32-ssc: SSC mode is I2S BCLK / FRAME master\n"); | ||
498 | rcmr = (SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) | | ||
499 | SSC_BF(RCMR_STTDLY, START_DELAY) | | ||
500 | SSC_BF(RCMR_START, SSC_START_FALLING_RF) | | ||
501 | SSC_BF(RCMR_CKI, SSC_CKI_RISING) | | ||
502 | SSC_BF(RCMR_CKO, SSC_CKO_NONE) | | ||
503 | SSC_BF(RCMR_CKS, SSC_CKS_DIV)); | ||
504 | |||
505 | rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | | ||
506 | SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE) | | ||
507 | SSC_BF(RFMR_FSLEN, bits - 1) | | ||
508 | SSC_BF(RFMR_DATNB, channels - 1) | | ||
509 | SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1)); | ||
510 | |||
511 | tcmr = (SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) | | ||
512 | SSC_BF(TCMR_STTDLY, START_DELAY) | | ||
513 | SSC_BF(TCMR_START, SSC_START_FALLING_RF) | | ||
514 | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) | | ||
515 | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) | | ||
516 | SSC_BF(TCMR_CKS, SSC_CKS_DIV)); | ||
517 | |||
518 | tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | | ||
519 | SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE) | | ||
520 | SSC_BF(TFMR_FSLEN, bits - 1) | | ||
521 | SSC_BF(TFMR_DATNB, channels - 1) | SSC_BIT(TFMR_MSBF) | | ||
522 | SSC_BF(TFMR_DATLEN, bits - 1)); | ||
523 | break; | ||
524 | |||
525 | |||
526 | case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: | ||
527 | /* | ||
528 | * I2S format, CODEC supplies BCLK and LRC clock. | ||
529 | * | ||
530 | * The SSC transmit clock is obtained from the BCLK signal | ||
531 | * on the TK line, and the SSC receive clock is generated from | ||
532 | * the transmit clock. | ||
533 | * | ||
534 | * For single channel data, one sample is transferred on the | ||
535 | * falling edge of the LRC clock. For two channel data, one | ||
536 | * sample is transferred on both edges of the LRC clock. | ||
537 | */ | ||
538 | pr_debug("at32-ssc: SSC mode is I2S BCLK / FRAME slave\n"); | ||
539 | start_event = ((channels == 1) ? | ||
540 | SSC_START_FALLING_RF : SSC_START_EDGE_RF); | ||
541 | |||
542 | rcmr = (SSC_BF(RCMR_STTDLY, START_DELAY) | | ||
543 | SSC_BF(RCMR_START, start_event) | | ||
544 | SSC_BF(RCMR_CKI, SSC_CKI_RISING) | | ||
545 | SSC_BF(RCMR_CKO, SSC_CKO_NONE) | | ||
546 | SSC_BF(RCMR_CKS, SSC_CKS_CLOCK)); | ||
547 | |||
548 | rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | | ||
549 | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) | | ||
550 | SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1)); | ||
551 | |||
552 | tcmr = (SSC_BF(TCMR_STTDLY, START_DELAY) | | ||
553 | SSC_BF(TCMR_START, start_event) | | ||
554 | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) | | ||
555 | SSC_BF(TCMR_CKO, SSC_CKO_NONE) | | ||
556 | SSC_BF(TCMR_CKS, SSC_CKS_PIN)); | ||
557 | |||
558 | tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | | ||
559 | SSC_BF(TFMR_FSOS, SSC_FSOS_NONE) | | ||
560 | SSC_BIT(TFMR_MSBF) | SSC_BF(TFMR_DATLEN, bits - 1)); | ||
561 | break; | ||
562 | |||
563 | |||
564 | case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS: | ||
565 | /* | ||
566 | * DSP/PCM Mode A format, SSC provides BCLK and LRC clocks. | ||
567 | * | ||
568 | * The SSC transmit and receive clocks are generated from the | ||
569 | * MCK divider, and the BCLK signal is output on the SSC TK line | ||
570 | */ | ||
571 | pr_debug("at32-ssc: SSC mode is DSP A BCLK / FRAME master\n"); | ||
572 | rcmr = (SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) | | ||
573 | SSC_BF(RCMR_STTDLY, 1) | | ||
574 | SSC_BF(RCMR_START, SSC_START_RISING_RF) | | ||
575 | SSC_BF(RCMR_CKI, SSC_CKI_RISING) | | ||
576 | SSC_BF(RCMR_CKO, SSC_CKO_NONE) | | ||
577 | SSC_BF(RCMR_CKS, SSC_CKS_DIV)); | ||
578 | |||
579 | rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | | ||
580 | SSC_BF(RFMR_FSOS, SSC_FSOS_POSITIVE) | | ||
581 | SSC_BF(RFMR_DATNB, channels - 1) | | ||
582 | SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1)); | ||
583 | |||
584 | tcmr = (SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) | | ||
585 | SSC_BF(TCMR_STTDLY, 1) | | ||
586 | SSC_BF(TCMR_START, SSC_START_RISING_RF) | | ||
587 | SSC_BF(TCMR_CKI, SSC_CKI_RISING) | | ||
588 | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) | | ||
589 | SSC_BF(TCMR_CKS, SSC_CKS_DIV)); | ||
590 | |||
591 | tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | | ||
592 | SSC_BF(TFMR_FSOS, SSC_FSOS_POSITIVE) | | ||
593 | SSC_BF(TFMR_DATNB, channels - 1) | | ||
594 | SSC_BIT(TFMR_MSBF) | SSC_BF(TFMR_DATLEN, bits - 1)); | ||
595 | break; | ||
596 | |||
597 | |||
598 | case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: | ||
599 | default: | ||
600 | pr_warning("at32-ssc: unsupported DAI format 0x%x\n", | ||
601 | ssc_p->daifmt); | ||
602 | return -EINVAL; | ||
603 | break; | ||
604 | } | ||
605 | pr_debug("at32-ssc: RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", | ||
606 | rcmr, rfmr, tcmr, tfmr); | ||
607 | |||
608 | |||
609 | if (!ssc_p->initialized) { | ||
610 | /* enable peripheral clock */ | ||
611 | pr_debug("at32-ssc: Starting clock\n"); | ||
612 | clk_enable(ssc_p->ssc->clk); | ||
613 | |||
614 | /* Reset the SSC and its PDC registers */ | ||
615 | ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); | ||
616 | |||
617 | ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0); | ||
618 | ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0); | ||
619 | ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0); | ||
620 | ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0); | ||
621 | |||
622 | ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0); | ||
623 | ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0); | ||
624 | ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0); | ||
625 | ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0); | ||
626 | |||
627 | ret = request_irq(ssc_p->ssc->irq, at32_ssc_interrupt, 0, | ||
628 | ssc_p->name, ssc_p); | ||
629 | if (ret < 0) { | ||
630 | pr_warning("at32-ssc: request irq failed (%d)\n", ret); | ||
631 | pr_debug("at32-ssc: Stopping clock\n"); | ||
632 | clk_disable(ssc_p->ssc->clk); | ||
633 | return ret; | ||
634 | } | ||
635 | |||
636 | ssc_p->initialized = 1; | ||
637 | } | ||
638 | |||
639 | /* Set SSC clock mode register */ | ||
640 | ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->cmr_div); | ||
641 | |||
642 | /* set receive clock mode and format */ | ||
643 | ssc_writel(ssc_p->ssc->regs, RCMR, rcmr); | ||
644 | ssc_writel(ssc_p->ssc->regs, RFMR, rfmr); | ||
645 | |||
646 | /* set transmit clock mode and format */ | ||
647 | ssc_writel(ssc_p->ssc->regs, TCMR, tcmr); | ||
648 | ssc_writel(ssc_p->ssc->regs, TFMR, tfmr); | ||
649 | |||
650 | pr_debug("at32-ssc: SSC initialized\n"); | ||
651 | return 0; | ||
652 | } | ||
653 | |||
654 | |||
655 | |||
656 | static int at32_ssc_prepare(struct snd_pcm_substream *substream) | ||
657 | { | ||
658 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
659 | struct at32_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; | ||
660 | struct at32_pcm_dma_params *dma_params; | ||
661 | |||
662 | dma_params = ssc_p->dma_params[substream->stream]; | ||
663 | |||
664 | ssc_writel(dma_params->ssc->regs, CR, dma_params->mask->ssc_enable); | ||
665 | |||
666 | return 0; | ||
667 | } | ||
668 | |||
669 | |||
670 | |||
671 | #ifdef CONFIG_PM | ||
672 | static int at32_ssc_suspend(struct platform_device *pdev, | ||
673 | struct snd_soc_dai *cpu_dai) | ||
674 | { | ||
675 | struct at32_ssc_info *ssc_p; | ||
676 | |||
677 | if (!cpu_dai->active) | ||
678 | return 0; | ||
679 | |||
680 | ssc_p = &ssc_info[cpu_dai->id]; | ||
681 | |||
682 | /* Save the status register before disabling transmit and receive */ | ||
683 | ssc_p->ssc_state.ssc_sr = ssc_readl(ssc_p->ssc->regs, SR); | ||
684 | ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_TXDIS) | SSC_BIT(CR_RXDIS)); | ||
685 | |||
686 | /* Save the current interrupt mask, then disable unmasked interrupts */ | ||
687 | ssc_p->ssc_state.ssc_imr = ssc_readl(ssc_p->ssc->regs, IMR); | ||
688 | ssc_writel(ssc_p->ssc->regs, IDR, ssc_p->ssc_state.ssc_imr); | ||
689 | |||
690 | ssc_p->ssc_state.ssc_cmr = ssc_readl(ssc_p->ssc->regs, CMR); | ||
691 | ssc_p->ssc_state.ssc_rcmr = ssc_readl(ssc_p->ssc->regs, RCMR); | ||
692 | ssc_p->ssc_state.ssc_rfmr = ssc_readl(ssc_p->ssc->regs, RFMR); | ||
693 | ssc_p->ssc_state.ssc_tcmr = ssc_readl(ssc_p->ssc->regs, TCMR); | ||
694 | ssc_p->ssc_state.ssc_tfmr = ssc_readl(ssc_p->ssc->regs, TFMR); | ||
695 | |||
696 | return 0; | ||
697 | } | ||
698 | |||
699 | |||
700 | |||
701 | static int at32_ssc_resume(struct platform_device *pdev, | ||
702 | struct snd_soc_dai *cpu_dai) | ||
703 | { | ||
704 | struct at32_ssc_info *ssc_p; | ||
705 | u32 cr; | ||
706 | |||
707 | if (!cpu_dai->active) | ||
708 | return 0; | ||
709 | |||
710 | ssc_p = &ssc_info[cpu_dai->id]; | ||
711 | |||
712 | /* restore SSC register settings */ | ||
713 | ssc_writel(ssc_p->ssc->regs, TFMR, ssc_p->ssc_state.ssc_tfmr); | ||
714 | ssc_writel(ssc_p->ssc->regs, TCMR, ssc_p->ssc_state.ssc_tcmr); | ||
715 | ssc_writel(ssc_p->ssc->regs, RFMR, ssc_p->ssc_state.ssc_rfmr); | ||
716 | ssc_writel(ssc_p->ssc->regs, RCMR, ssc_p->ssc_state.ssc_rcmr); | ||
717 | ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->ssc_state.ssc_cmr); | ||
718 | |||
719 | /* re-enable interrupts */ | ||
720 | ssc_writel(ssc_p->ssc->regs, IER, ssc_p->ssc_state.ssc_imr); | ||
721 | |||
722 | /* Re-enable recieve and transmit as appropriate */ | ||
723 | cr = 0; | ||
724 | cr |= | ||
725 | (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_RXEN)) ? SSC_BIT(CR_RXEN) : 0; | ||
726 | cr |= | ||
727 | (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_TXEN)) ? SSC_BIT(CR_TXEN) : 0; | ||
728 | ssc_writel(ssc_p->ssc->regs, CR, cr); | ||
729 | |||
730 | return 0; | ||
731 | } | ||
732 | #else /* CONFIG_PM */ | ||
733 | # define at32_ssc_suspend NULL | ||
734 | # define at32_ssc_resume NULL | ||
735 | #endif /* CONFIG_PM */ | ||
736 | |||
737 | |||
738 | #define AT32_SSC_RATES \ | ||
739 | (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ | ||
740 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | ||
741 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) | ||
742 | |||
743 | |||
744 | #define AT32_SSC_FORMATS \ | ||
745 | (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16 | \ | ||
746 | SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_S32) | ||
747 | |||
748 | |||
749 | struct snd_soc_dai at32_ssc_dai[NUM_SSC_DEVICES] = { | ||
750 | { | ||
751 | .name = "at32-ssc0", | ||
752 | .id = 0, | ||
753 | .type = SND_SOC_DAI_PCM, | ||
754 | .suspend = at32_ssc_suspend, | ||
755 | .resume = at32_ssc_resume, | ||
756 | .playback = { | ||
757 | .channels_min = 1, | ||
758 | .channels_max = 2, | ||
759 | .rates = AT32_SSC_RATES, | ||
760 | .formats = AT32_SSC_FORMATS, | ||
761 | }, | ||
762 | .capture = { | ||
763 | .channels_min = 1, | ||
764 | .channels_max = 2, | ||
765 | .rates = AT32_SSC_RATES, | ||
766 | .formats = AT32_SSC_FORMATS, | ||
767 | }, | ||
768 | .ops = { | ||
769 | .startup = at32_ssc_startup, | ||
770 | .shutdown = at32_ssc_shutdown, | ||
771 | .prepare = at32_ssc_prepare, | ||
772 | .hw_params = at32_ssc_hw_params, | ||
773 | }, | ||
774 | .dai_ops = { | ||
775 | .set_sysclk = at32_ssc_set_dai_sysclk, | ||
776 | .set_fmt = at32_ssc_set_dai_fmt, | ||
777 | .set_clkdiv = at32_ssc_set_dai_clkdiv, | ||
778 | }, | ||
779 | .private_data = &ssc_info[0], | ||
780 | }, | ||
781 | { | ||
782 | .name = "at32-ssc1", | ||
783 | .id = 1, | ||
784 | .type = SND_SOC_DAI_PCM, | ||
785 | .suspend = at32_ssc_suspend, | ||
786 | .resume = at32_ssc_resume, | ||
787 | .playback = { | ||
788 | .channels_min = 1, | ||
789 | .channels_max = 2, | ||
790 | .rates = AT32_SSC_RATES, | ||
791 | .formats = AT32_SSC_FORMATS, | ||
792 | }, | ||
793 | .capture = { | ||
794 | .channels_min = 1, | ||
795 | .channels_max = 2, | ||
796 | .rates = AT32_SSC_RATES, | ||
797 | .formats = AT32_SSC_FORMATS, | ||
798 | }, | ||
799 | .ops = { | ||
800 | .startup = at32_ssc_startup, | ||
801 | .shutdown = at32_ssc_shutdown, | ||
802 | .prepare = at32_ssc_prepare, | ||
803 | .hw_params = at32_ssc_hw_params, | ||
804 | }, | ||
805 | .dai_ops = { | ||
806 | .set_sysclk = at32_ssc_set_dai_sysclk, | ||
807 | .set_fmt = at32_ssc_set_dai_fmt, | ||
808 | .set_clkdiv = at32_ssc_set_dai_clkdiv, | ||
809 | }, | ||
810 | .private_data = &ssc_info[1], | ||
811 | }, | ||
812 | { | ||
813 | .name = "at32-ssc2", | ||
814 | .id = 2, | ||
815 | .type = SND_SOC_DAI_PCM, | ||
816 | .suspend = at32_ssc_suspend, | ||
817 | .resume = at32_ssc_resume, | ||
818 | .playback = { | ||
819 | .channels_min = 1, | ||
820 | .channels_max = 2, | ||
821 | .rates = AT32_SSC_RATES, | ||
822 | .formats = AT32_SSC_FORMATS, | ||
823 | }, | ||
824 | .capture = { | ||
825 | .channels_min = 1, | ||
826 | .channels_max = 2, | ||
827 | .rates = AT32_SSC_RATES, | ||
828 | .formats = AT32_SSC_FORMATS, | ||
829 | }, | ||
830 | .ops = { | ||
831 | .startup = at32_ssc_startup, | ||
832 | .shutdown = at32_ssc_shutdown, | ||
833 | .prepare = at32_ssc_prepare, | ||
834 | .hw_params = at32_ssc_hw_params, | ||
835 | }, | ||
836 | .dai_ops = { | ||
837 | .set_sysclk = at32_ssc_set_dai_sysclk, | ||
838 | .set_fmt = at32_ssc_set_dai_fmt, | ||
839 | .set_clkdiv = at32_ssc_set_dai_clkdiv, | ||
840 | }, | ||
841 | .private_data = &ssc_info[2], | ||
842 | }, | ||
843 | }; | ||
844 | EXPORT_SYMBOL_GPL(at32_ssc_dai); | ||
845 | |||
846 | |||
847 | MODULE_AUTHOR("Geoffrey Wossum <gwossum@acm.org>"); | ||
848 | MODULE_DESCRIPTION("AT32 SSC ASoC Interface"); | ||
849 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/at32/at32-ssc.h b/sound/soc/at32/at32-ssc.h new file mode 100644 index 000000000000..3c052dbbe460 --- /dev/null +++ b/sound/soc/at32/at32-ssc.h | |||
@@ -0,0 +1,59 @@ | |||
1 | /* sound/soc/at32/at32-ssc.h | ||
2 | * ASoC SSC interface for Atmel AT32 SoC | ||
3 | * | ||
4 | * Copyright (C) 2008 Long Range Systems | ||
5 | * Geoffrey Wossum <gwossum@acm.org> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef __SOUND_SOC_AT32_AT32_SSC_H | ||
13 | #define __SOUND_SOC_AT32_AT32_SSC_H __FILE__ | ||
14 | |||
15 | #include <linux/types.h> | ||
16 | #include <linux/atmel-ssc.h> | ||
17 | |||
18 | #include "at32-pcm.h" | ||
19 | |||
20 | |||
21 | |||
22 | struct at32_ssc_state { | ||
23 | u32 ssc_cmr; | ||
24 | u32 ssc_rcmr; | ||
25 | u32 ssc_rfmr; | ||
26 | u32 ssc_tcmr; | ||
27 | u32 ssc_tfmr; | ||
28 | u32 ssc_sr; | ||
29 | u32 ssc_imr; | ||
30 | }; | ||
31 | |||
32 | |||
33 | |||
34 | struct at32_ssc_info { | ||
35 | char *name; | ||
36 | struct ssc_device *ssc; | ||
37 | spinlock_t lock; /* lock for dir_mask */ | ||
38 | unsigned short dir_mask; /* 0=unused, 1=playback, 2=capture */ | ||
39 | unsigned short initialized; /* true if SSC has been initialized */ | ||
40 | unsigned short daifmt; | ||
41 | unsigned short cmr_div; | ||
42 | unsigned short tcmr_period; | ||
43 | unsigned short rcmr_period; | ||
44 | struct at32_pcm_dma_params *dma_params[2]; | ||
45 | struct at32_ssc_state ssc_state; | ||
46 | }; | ||
47 | |||
48 | |||
49 | /* SSC divider ids */ | ||
50 | #define AT32_SSC_CMR_DIV 0 /* MCK divider for BCLK */ | ||
51 | #define AT32_SSC_TCMR_PERIOD 1 /* BCLK divider for transmit FS */ | ||
52 | #define AT32_SSC_RCMR_PERIOD 2 /* BCLK divider for receive FS */ | ||
53 | |||
54 | |||
55 | extern struct snd_soc_dai at32_ssc_dai[]; | ||
56 | |||
57 | |||
58 | |||
59 | #endif /* __SOUND_SOC_AT32_AT32_SSC_H */ | ||
diff --git a/sound/soc/at32/playpaq_wm8510.c b/sound/soc/at32/playpaq_wm8510.c new file mode 100644 index 000000000000..fee5f8e58957 --- /dev/null +++ b/sound/soc/at32/playpaq_wm8510.c | |||
@@ -0,0 +1,522 @@ | |||
1 | /* sound/soc/at32/playpaq_wm8510.c | ||
2 | * ASoC machine driver for PlayPaq using WM8510 codec | ||
3 | * | ||
4 | * Copyright (C) 2008 Long Range Systems | ||
5 | * Geoffrey Wossum <gwossum@acm.org> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This code is largely inspired by sound/soc/at91/eti_b1_wm8731.c | ||
12 | * | ||
13 | * NOTE: If you don't have the AT32 enhanced portmux configured (which | ||
14 | * isn't currently in the mainline or Atmel patched kernel), you will | ||
15 | * need to set the MCLK pin (PA30) to peripheral A in your board initialization | ||
16 | * code. Something like: | ||
17 | * at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0); | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | /* #define DEBUG */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/moduleparam.h> | ||
25 | #include <linux/version.h> | ||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/errno.h> | ||
28 | #include <linux/clk.h> | ||
29 | #include <linux/timer.h> | ||
30 | #include <linux/interrupt.h> | ||
31 | #include <linux/platform_device.h> | ||
32 | |||
33 | #include <sound/core.h> | ||
34 | #include <sound/pcm.h> | ||
35 | #include <sound/pcm_params.h> | ||
36 | #include <sound/soc.h> | ||
37 | #include <sound/soc-dapm.h> | ||
38 | |||
39 | #include <asm/arch/at32ap700x.h> | ||
40 | #include <asm/arch/portmux.h> | ||
41 | |||
42 | #include "../codecs/wm8510.h" | ||
43 | #include "at32-pcm.h" | ||
44 | #include "at32-ssc.h" | ||
45 | |||
46 | |||
47 | /*-------------------------------------------------------------------------*\ | ||
48 | * constants | ||
49 | \*-------------------------------------------------------------------------*/ | ||
50 | #define MCLK_PIN GPIO_PIN_PA(30) | ||
51 | #define MCLK_PERIPH GPIO_PERIPH_A | ||
52 | |||
53 | |||
54 | /*-------------------------------------------------------------------------*\ | ||
55 | * data types | ||
56 | \*-------------------------------------------------------------------------*/ | ||
57 | /* SSC clocking data */ | ||
58 | struct ssc_clock_data { | ||
59 | /* CMR div */ | ||
60 | unsigned int cmr_div; | ||
61 | |||
62 | /* Frame period (as needed by xCMR.PERIOD) */ | ||
63 | unsigned int period; | ||
64 | |||
65 | /* The SSC clock rate these settings where calculated for */ | ||
66 | unsigned long ssc_rate; | ||
67 | }; | ||
68 | |||
69 | |||
70 | /*-------------------------------------------------------------------------*\ | ||
71 | * module data | ||
72 | \*-------------------------------------------------------------------------*/ | ||
73 | static struct clk *_gclk0; | ||
74 | static struct clk *_pll0; | ||
75 | |||
76 | #define CODEC_CLK (_gclk0) | ||
77 | |||
78 | |||
79 | /*-------------------------------------------------------------------------*\ | ||
80 | * Sound SOC operations | ||
81 | \*-------------------------------------------------------------------------*/ | ||
82 | #if defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE | ||
83 | static struct ssc_clock_data playpaq_wm8510_calc_ssc_clock( | ||
84 | struct snd_pcm_hw_params *params, | ||
85 | struct snd_soc_dai *cpu_dai) | ||
86 | { | ||
87 | struct at32_ssc_info *ssc_p = cpu_dai->private_data; | ||
88 | struct ssc_device *ssc = ssc_p->ssc; | ||
89 | struct ssc_clock_data cd; | ||
90 | unsigned int rate, width_bits, channels; | ||
91 | unsigned int bitrate, ssc_div; | ||
92 | unsigned actual_rate; | ||
93 | |||
94 | |||
95 | /* | ||
96 | * Figure out required bitrate | ||
97 | */ | ||
98 | rate = params_rate(params); | ||
99 | channels = params_channels(params); | ||
100 | width_bits = snd_pcm_format_physical_width(params_format(params)); | ||
101 | bitrate = rate * width_bits * channels; | ||
102 | |||
103 | |||
104 | /* | ||
105 | * Figure out required SSC divider and period for required bitrate | ||
106 | */ | ||
107 | cd.ssc_rate = clk_get_rate(ssc->clk); | ||
108 | ssc_div = cd.ssc_rate / bitrate; | ||
109 | cd.cmr_div = ssc_div / 2; | ||
110 | if (ssc_div & 1) { | ||
111 | /* round cmr_div up */ | ||
112 | cd.cmr_div++; | ||
113 | } | ||
114 | cd.period = width_bits - 1; | ||
115 | |||
116 | |||
117 | /* | ||
118 | * Find actual rate, compare to requested rate | ||
119 | */ | ||
120 | actual_rate = (cd.ssc_rate / (cd.cmr_div * 2)) / (2 * (cd.period + 1)); | ||
121 | pr_debug("playpaq_wm8510: Request rate = %d, actual rate = %d\n", | ||
122 | rate, actual_rate); | ||
123 | |||
124 | |||
125 | return cd; | ||
126 | } | ||
127 | #endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */ | ||
128 | |||
129 | |||
130 | |||
131 | static int playpaq_wm8510_hw_params(struct snd_pcm_substream *substream, | ||
132 | struct snd_pcm_hw_params *params) | ||
133 | { | ||
134 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
135 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
136 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
137 | struct at32_ssc_info *ssc_p = cpu_dai->private_data; | ||
138 | struct ssc_device *ssc = ssc_p->ssc; | ||
139 | unsigned int pll_out = 0, bclk = 0, mclk_div = 0; | ||
140 | int ret; | ||
141 | |||
142 | |||
143 | /* Due to difficulties with getting the correct clocks from the AT32's | ||
144 | * PLL0, we're going to let the CODEC be in charge of all the clocks | ||
145 | */ | ||
146 | #if !defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE | ||
147 | const unsigned int fmt = (SND_SOC_DAIFMT_I2S | | ||
148 | SND_SOC_DAIFMT_NB_NF | | ||
149 | SND_SOC_DAIFMT_CBM_CFM); | ||
150 | #else | ||
151 | struct ssc_clock_data cd; | ||
152 | const unsigned int fmt = (SND_SOC_DAIFMT_I2S | | ||
153 | SND_SOC_DAIFMT_NB_NF | | ||
154 | SND_SOC_DAIFMT_CBS_CFS); | ||
155 | #endif | ||
156 | |||
157 | if (ssc == NULL) { | ||
158 | pr_warning("playpaq_wm8510_hw_params: ssc is NULL!\n"); | ||
159 | return -EINVAL; | ||
160 | } | ||
161 | |||
162 | |||
163 | /* | ||
164 | * Figure out PLL and BCLK dividers for WM8510 | ||
165 | */ | ||
166 | switch (params_rate(params)) { | ||
167 | case 48000: | ||
168 | pll_out = 12288000; | ||
169 | mclk_div = WM8510_MCLKDIV_1; | ||
170 | bclk = WM8510_BCLKDIV_8; | ||
171 | break; | ||
172 | |||
173 | case 44100: | ||
174 | pll_out = 11289600; | ||
175 | mclk_div = WM8510_MCLKDIV_1; | ||
176 | bclk = WM8510_BCLKDIV_8; | ||
177 | break; | ||
178 | |||
179 | case 22050: | ||
180 | pll_out = 11289600; | ||
181 | mclk_div = WM8510_MCLKDIV_2; | ||
182 | bclk = WM8510_BCLKDIV_8; | ||
183 | break; | ||
184 | |||
185 | case 16000: | ||
186 | pll_out = 12288000; | ||
187 | mclk_div = WM8510_MCLKDIV_3; | ||
188 | bclk = WM8510_BCLKDIV_8; | ||
189 | break; | ||
190 | |||
191 | case 11025: | ||
192 | pll_out = 11289600; | ||
193 | mclk_div = WM8510_MCLKDIV_4; | ||
194 | bclk = WM8510_BCLKDIV_8; | ||
195 | break; | ||
196 | |||
197 | case 8000: | ||
198 | pll_out = 12288000; | ||
199 | mclk_div = WM8510_MCLKDIV_6; | ||
200 | bclk = WM8510_BCLKDIV_8; | ||
201 | break; | ||
202 | |||
203 | default: | ||
204 | pr_warning("playpaq_wm8510: Unsupported sample rate %d\n", | ||
205 | params_rate(params)); | ||
206 | return -EINVAL; | ||
207 | } | ||
208 | |||
209 | |||
210 | /* | ||
211 | * set CPU and CODEC DAI configuration | ||
212 | */ | ||
213 | ret = snd_soc_dai_set_fmt(codec_dai, fmt); | ||
214 | if (ret < 0) { | ||
215 | pr_warning("playpaq_wm8510: " | ||
216 | "Failed to set CODEC DAI format (%d)\n", | ||
217 | ret); | ||
218 | return ret; | ||
219 | } | ||
220 | ret = snd_soc_dai_set_fmt(cpu_dai, fmt); | ||
221 | if (ret < 0) { | ||
222 | pr_warning("playpaq_wm8510: " | ||
223 | "Failed to set CPU DAI format (%d)\n", | ||
224 | ret); | ||
225 | return ret; | ||
226 | } | ||
227 | |||
228 | |||
229 | /* | ||
230 | * Set CPU clock configuration | ||
231 | */ | ||
232 | #if defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE | ||
233 | cd = playpaq_wm8510_calc_ssc_clock(params, cpu_dai); | ||
234 | pr_debug("playpaq_wm8510: cmr_div = %d, period = %d\n", | ||
235 | cd.cmr_div, cd.period); | ||
236 | ret = snd_soc_dai_set_clkdiv(cpu_dai, AT32_SSC_CMR_DIV, cd.cmr_div); | ||
237 | if (ret < 0) { | ||
238 | pr_warning("playpaq_wm8510: Failed to set CPU CMR_DIV (%d)\n", | ||
239 | ret); | ||
240 | return ret; | ||
241 | } | ||
242 | ret = snd_soc_dai_set_clkdiv(cpu_dai, AT32_SSC_TCMR_PERIOD, | ||
243 | cd.period); | ||
244 | if (ret < 0) { | ||
245 | pr_warning("playpaq_wm8510: " | ||
246 | "Failed to set CPU transmit period (%d)\n", | ||
247 | ret); | ||
248 | return ret; | ||
249 | } | ||
250 | #endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */ | ||
251 | |||
252 | |||
253 | /* | ||
254 | * Set CODEC clock configuration | ||
255 | */ | ||
256 | pr_debug("playpaq_wm8510: " | ||
257 | "pll_in = %ld, pll_out = %u, bclk = %x, mclk = %x\n", | ||
258 | clk_get_rate(CODEC_CLK), pll_out, bclk, mclk_div); | ||
259 | |||
260 | |||
261 | #if !defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE | ||
262 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM8510_BCLKDIV, bclk); | ||
263 | if (ret < 0) { | ||
264 | pr_warning | ||
265 | ("playpaq_wm8510: Failed to set CODEC DAI BCLKDIV (%d)\n", | ||
266 | ret); | ||
267 | return ret; | ||
268 | } | ||
269 | #endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */ | ||
270 | |||
271 | |||
272 | ret = snd_soc_dai_set_pll(codec_dai, 0, | ||
273 | clk_get_rate(CODEC_CLK), pll_out); | ||
274 | if (ret < 0) { | ||
275 | pr_warning("playpaq_wm8510: Failed to set CODEC DAI PLL (%d)\n", | ||
276 | ret); | ||
277 | return ret; | ||
278 | } | ||
279 | |||
280 | |||
281 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM8510_MCLKDIV, mclk_div); | ||
282 | if (ret < 0) { | ||
283 | pr_warning("playpaq_wm8510: Failed to set CODEC MCLKDIV (%d)\n", | ||
284 | ret); | ||
285 | return ret; | ||
286 | } | ||
287 | |||
288 | |||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | |||
293 | |||
294 | static struct snd_soc_ops playpaq_wm8510_ops = { | ||
295 | .hw_params = playpaq_wm8510_hw_params, | ||
296 | }; | ||
297 | |||
298 | |||
299 | |||
300 | static const struct snd_soc_dapm_widget playpaq_dapm_widgets[] = { | ||
301 | SND_SOC_DAPM_MIC("Int Mic", NULL), | ||
302 | SND_SOC_DAPM_SPK("Ext Spk", NULL), | ||
303 | }; | ||
304 | |||
305 | |||
306 | |||
307 | static const char *intercon[][3] = { | ||
308 | /* speaker connected to SPKOUT */ | ||
309 | {"Ext Spk", NULL, "SPKOUTP"}, | ||
310 | {"Ext Spk", NULL, "SPKOUTN"}, | ||
311 | |||
312 | {"Mic Bias", NULL, "Int Mic"}, | ||
313 | {"MICN", NULL, "Mic Bias"}, | ||
314 | {"MICP", NULL, "Mic Bias"}, | ||
315 | |||
316 | /* Terminator */ | ||
317 | {NULL, NULL, NULL}, | ||
318 | }; | ||
319 | |||
320 | |||
321 | |||
322 | static int playpaq_wm8510_init(struct snd_soc_codec *codec) | ||
323 | { | ||
324 | int i; | ||
325 | |||
326 | /* | ||
327 | * Add DAPM widgets | ||
328 | */ | ||
329 | for (i = 0; i < ARRAY_SIZE(playpaq_dapm_widgets); i++) | ||
330 | snd_soc_dapm_new_control(codec, &playpaq_dapm_widgets[i]); | ||
331 | |||
332 | |||
333 | |||
334 | /* | ||
335 | * Setup audio path interconnects | ||
336 | */ | ||
337 | for (i = 0; intercon[i][0] != NULL; i++) { | ||
338 | snd_soc_dapm_connect_input(codec, | ||
339 | intercon[i][0], | ||
340 | intercon[i][1], intercon[i][2]); | ||
341 | } | ||
342 | |||
343 | |||
344 | /* always connected pins */ | ||
345 | snd_soc_dapm_enable_pin(codec, "Int Mic"); | ||
346 | snd_soc_dapm_enable_pin(codec, "Ext Spk"); | ||
347 | snd_soc_dapm_sync(codec); | ||
348 | |||
349 | |||
350 | |||
351 | /* Make CSB show PLL rate */ | ||
352 | snd_soc_dai_set_clkdiv(codec->dai, WM8510_OPCLKDIV, | ||
353 | WM8510_OPCLKDIV_1 | 4); | ||
354 | |||
355 | return 0; | ||
356 | } | ||
357 | |||
358 | |||
359 | |||
360 | static struct snd_soc_dai_link playpaq_wm8510_dai = { | ||
361 | .name = "WM8510", | ||
362 | .stream_name = "WM8510 PCM", | ||
363 | .cpu_dai = &at32_ssc_dai[0], | ||
364 | .codec_dai = &wm8510_dai, | ||
365 | .init = playpaq_wm8510_init, | ||
366 | .ops = &playpaq_wm8510_ops, | ||
367 | }; | ||
368 | |||
369 | |||
370 | |||
371 | static struct snd_soc_machine snd_soc_machine_playpaq = { | ||
372 | .name = "LRS_PlayPaq_WM8510", | ||
373 | .dai_link = &playpaq_wm8510_dai, | ||
374 | .num_links = 1, | ||
375 | }; | ||
376 | |||
377 | |||
378 | |||
379 | static struct wm8510_setup_data playpaq_wm8510_setup = { | ||
380 | .i2c_address = 0x1a, | ||
381 | }; | ||
382 | |||
383 | |||
384 | |||
385 | static struct snd_soc_device playpaq_wm8510_snd_devdata = { | ||
386 | .machine = &snd_soc_machine_playpaq, | ||
387 | .platform = &at32_soc_platform, | ||
388 | .codec_dev = &soc_codec_dev_wm8510, | ||
389 | .codec_data = &playpaq_wm8510_setup, | ||
390 | }; | ||
391 | |||
392 | static struct platform_device *playpaq_snd_device; | ||
393 | |||
394 | |||
395 | static int __init playpaq_asoc_init(void) | ||
396 | { | ||
397 | int ret = 0; | ||
398 | struct at32_ssc_info *ssc_p = playpaq_wm8510_dai.cpu_dai->private_data; | ||
399 | struct ssc_device *ssc = NULL; | ||
400 | |||
401 | |||
402 | /* | ||
403 | * Request SSC device | ||
404 | */ | ||
405 | ssc = ssc_request(0); | ||
406 | if (IS_ERR(ssc)) { | ||
407 | ret = PTR_ERR(ssc); | ||
408 | ssc = NULL; | ||
409 | goto err_ssc; | ||
410 | } | ||
411 | ssc_p->ssc = ssc; | ||
412 | |||
413 | |||
414 | /* | ||
415 | * Configure MCLK for WM8510 | ||
416 | */ | ||
417 | _gclk0 = clk_get(NULL, "gclk0"); | ||
418 | if (IS_ERR(_gclk0)) { | ||
419 | _gclk0 = NULL; | ||
420 | goto err_gclk0; | ||
421 | } | ||
422 | _pll0 = clk_get(NULL, "pll0"); | ||
423 | if (IS_ERR(_pll0)) { | ||
424 | _pll0 = NULL; | ||
425 | goto err_pll0; | ||
426 | } | ||
427 | if (clk_set_parent(_gclk0, _pll0)) { | ||
428 | pr_warning("snd-soc-playpaq: " | ||
429 | "Failed to set PLL0 as parent for DAC clock\n"); | ||
430 | goto err_set_clk; | ||
431 | } | ||
432 | clk_set_rate(CODEC_CLK, 12000000); | ||
433 | clk_enable(CODEC_CLK); | ||
434 | |||
435 | #if defined CONFIG_AT32_ENHANCED_PORTMUX | ||
436 | at32_select_periph(MCLK_PIN, MCLK_PERIPH, 0); | ||
437 | #endif | ||
438 | |||
439 | |||
440 | /* | ||
441 | * Create and register platform device | ||
442 | */ | ||
443 | playpaq_snd_device = platform_device_alloc("soc-audio", 0); | ||
444 | if (playpaq_snd_device == NULL) { | ||
445 | ret = -ENOMEM; | ||
446 | goto err_device_alloc; | ||
447 | } | ||
448 | |||
449 | platform_set_drvdata(playpaq_snd_device, &playpaq_wm8510_snd_devdata); | ||
450 | playpaq_wm8510_snd_devdata.dev = &playpaq_snd_device->dev; | ||
451 | |||
452 | ret = platform_device_add(playpaq_snd_device); | ||
453 | if (ret) { | ||
454 | pr_warning("playpaq_wm8510: platform_device_add failed (%d)\n", | ||
455 | ret); | ||
456 | goto err_device_add; | ||
457 | } | ||
458 | |||
459 | return 0; | ||
460 | |||
461 | |||
462 | err_device_add: | ||
463 | if (playpaq_snd_device != NULL) { | ||
464 | platform_device_put(playpaq_snd_device); | ||
465 | playpaq_snd_device = NULL; | ||
466 | } | ||
467 | err_device_alloc: | ||
468 | err_set_clk: | ||
469 | if (_pll0 != NULL) { | ||
470 | clk_put(_pll0); | ||
471 | _pll0 = NULL; | ||
472 | } | ||
473 | err_pll0: | ||
474 | if (_gclk0 != NULL) { | ||
475 | clk_put(_gclk0); | ||
476 | _gclk0 = NULL; | ||
477 | } | ||
478 | err_gclk0: | ||
479 | if (ssc != NULL) { | ||
480 | ssc_free(ssc); | ||
481 | ssc = NULL; | ||
482 | } | ||
483 | err_ssc: | ||
484 | return ret; | ||
485 | } | ||
486 | |||
487 | |||
488 | static void __exit playpaq_asoc_exit(void) | ||
489 | { | ||
490 | struct at32_ssc_info *ssc_p = playpaq_wm8510_dai.cpu_dai->private_data; | ||
491 | struct ssc_device *ssc; | ||
492 | |||
493 | if (ssc_p != NULL) { | ||
494 | ssc = ssc_p->ssc; | ||
495 | if (ssc != NULL) | ||
496 | ssc_free(ssc); | ||
497 | ssc_p->ssc = NULL; | ||
498 | } | ||
499 | |||
500 | if (_gclk0 != NULL) { | ||
501 | clk_put(_gclk0); | ||
502 | _gclk0 = NULL; | ||
503 | } | ||
504 | if (_pll0 != NULL) { | ||
505 | clk_put(_pll0); | ||
506 | _pll0 = NULL; | ||
507 | } | ||
508 | |||
509 | #if defined CONFIG_AT32_ENHANCED_PORTMUX | ||
510 | at32_free_pin(MCLK_PIN); | ||
511 | #endif | ||
512 | |||
513 | platform_device_unregister(playpaq_snd_device); | ||
514 | playpaq_snd_device = NULL; | ||
515 | } | ||
516 | |||
517 | module_init(playpaq_asoc_init); | ||
518 | module_exit(playpaq_asoc_exit); | ||
519 | |||
520 | MODULE_AUTHOR("Geoffrey Wossum <gwossum@acm.org>"); | ||
521 | MODULE_DESCRIPTION("ASoC machine driver for LRS PlayPaq"); | ||
522 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/at91/Kconfig b/sound/soc/at91/Kconfig index 5cb93fd3a407..905186502e00 100644 --- a/sound/soc/at91/Kconfig +++ b/sound/soc/at91/Kconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | config SND_AT91_SOC | 1 | config SND_AT91_SOC |
2 | tristate "SoC Audio for the Atmel AT91 System-on-Chip" | 2 | tristate "SoC Audio for the Atmel AT91 System-on-Chip" |
3 | depends on ARCH_AT91 && SND_SOC | 3 | depends on ARCH_AT91 |
4 | help | 4 | help |
5 | Say Y or M if you want to add support for codecs attached to | 5 | Say Y or M if you want to add support for codecs attached to |
6 | the AT91 SSC interface. You will also need | 6 | the AT91 SSC interface. You will also need |
diff --git a/sound/soc/at91/at91-pcm.c b/sound/soc/at91/at91-pcm.c index ccac6bd2889c..d47492b2b6e5 100644 --- a/sound/soc/at91/at91-pcm.c +++ b/sound/soc/at91/at91-pcm.c | |||
@@ -318,7 +318,7 @@ static int at91_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, | |||
318 | static u64 at91_pcm_dmamask = 0xffffffff; | 318 | static u64 at91_pcm_dmamask = 0xffffffff; |
319 | 319 | ||
320 | static int at91_pcm_new(struct snd_card *card, | 320 | static int at91_pcm_new(struct snd_card *card, |
321 | struct snd_soc_codec_dai *dai, struct snd_pcm *pcm) | 321 | struct snd_soc_dai *dai, struct snd_pcm *pcm) |
322 | { | 322 | { |
323 | int ret = 0; | 323 | int ret = 0; |
324 | 324 | ||
@@ -367,7 +367,7 @@ static void at91_pcm_free_dma_buffers(struct snd_pcm *pcm) | |||
367 | 367 | ||
368 | #ifdef CONFIG_PM | 368 | #ifdef CONFIG_PM |
369 | static int at91_pcm_suspend(struct platform_device *pdev, | 369 | static int at91_pcm_suspend(struct platform_device *pdev, |
370 | struct snd_soc_cpu_dai *dai) | 370 | struct snd_soc_dai *dai) |
371 | { | 371 | { |
372 | struct snd_pcm_runtime *runtime = dai->runtime; | 372 | struct snd_pcm_runtime *runtime = dai->runtime; |
373 | struct at91_runtime_data *prtd; | 373 | struct at91_runtime_data *prtd; |
@@ -392,7 +392,7 @@ static int at91_pcm_suspend(struct platform_device *pdev, | |||
392 | } | 392 | } |
393 | 393 | ||
394 | static int at91_pcm_resume(struct platform_device *pdev, | 394 | static int at91_pcm_resume(struct platform_device *pdev, |
395 | struct snd_soc_cpu_dai *dai) | 395 | struct snd_soc_dai *dai) |
396 | { | 396 | { |
397 | struct snd_pcm_runtime *runtime = dai->runtime; | 397 | struct snd_pcm_runtime *runtime = dai->runtime; |
398 | struct at91_runtime_data *prtd; | 398 | struct at91_runtime_data *prtd; |
diff --git a/sound/soc/at91/at91-ssc.c b/sound/soc/at91/at91-ssc.c index bc35d00a38f8..c3625b665c5a 100644 --- a/sound/soc/at91/at91-ssc.c +++ b/sound/soc/at91/at91-ssc.c | |||
@@ -281,7 +281,7 @@ static void at91_ssc_shutdown(struct snd_pcm_substream *substream) | |||
281 | /* | 281 | /* |
282 | * Record the SSC system clock rate. | 282 | * Record the SSC system clock rate. |
283 | */ | 283 | */ |
284 | static int at91_ssc_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai, | 284 | static int at91_ssc_set_dai_sysclk(struct snd_soc_dai *cpu_dai, |
285 | int clk_id, unsigned int freq, int dir) | 285 | int clk_id, unsigned int freq, int dir) |
286 | { | 286 | { |
287 | /* | 287 | /* |
@@ -303,7 +303,7 @@ static int at91_ssc_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai, | |||
303 | /* | 303 | /* |
304 | * Record the DAI format for use in hw_params(). | 304 | * Record the DAI format for use in hw_params(). |
305 | */ | 305 | */ |
306 | static int at91_ssc_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai, | 306 | static int at91_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai, |
307 | unsigned int fmt) | 307 | unsigned int fmt) |
308 | { | 308 | { |
309 | struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; | 309 | struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; |
@@ -315,7 +315,7 @@ static int at91_ssc_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai, | |||
315 | /* | 315 | /* |
316 | * Record SSC clock dividers for use in hw_params(). | 316 | * Record SSC clock dividers for use in hw_params(). |
317 | */ | 317 | */ |
318 | static int at91_ssc_set_dai_clkdiv(struct snd_soc_cpu_dai *cpu_dai, | 318 | static int at91_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, |
319 | int div_id, int div) | 319 | int div_id, int div) |
320 | { | 320 | { |
321 | struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; | 321 | struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; |
@@ -634,7 +634,7 @@ static int at91_ssc_prepare(struct snd_pcm_substream *substream) | |||
634 | 634 | ||
635 | #ifdef CONFIG_PM | 635 | #ifdef CONFIG_PM |
636 | static int at91_ssc_suspend(struct platform_device *pdev, | 636 | static int at91_ssc_suspend(struct platform_device *pdev, |
637 | struct snd_soc_cpu_dai *cpu_dai) | 637 | struct snd_soc_dai *cpu_dai) |
638 | { | 638 | { |
639 | struct at91_ssc_info *ssc_p; | 639 | struct at91_ssc_info *ssc_p; |
640 | 640 | ||
@@ -662,7 +662,7 @@ static int at91_ssc_suspend(struct platform_device *pdev, | |||
662 | } | 662 | } |
663 | 663 | ||
664 | static int at91_ssc_resume(struct platform_device *pdev, | 664 | static int at91_ssc_resume(struct platform_device *pdev, |
665 | struct snd_soc_cpu_dai *cpu_dai) | 665 | struct snd_soc_dai *cpu_dai) |
666 | { | 666 | { |
667 | struct at91_ssc_info *ssc_p; | 667 | struct at91_ssc_info *ssc_p; |
668 | 668 | ||
@@ -700,7 +700,7 @@ static int at91_ssc_resume(struct platform_device *pdev, | |||
700 | #define AT91_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ | 700 | #define AT91_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ |
701 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | 701 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) |
702 | 702 | ||
703 | struct snd_soc_cpu_dai at91_ssc_dai[NUM_SSC_DEVICES] = { | 703 | struct snd_soc_dai at91_ssc_dai[NUM_SSC_DEVICES] = { |
704 | { .name = "at91-ssc0", | 704 | { .name = "at91-ssc0", |
705 | .id = 0, | 705 | .id = 0, |
706 | .type = SND_SOC_DAI_PCM, | 706 | .type = SND_SOC_DAI_PCM, |
diff --git a/sound/soc/at91/at91-ssc.h b/sound/soc/at91/at91-ssc.h index b188f973df9f..6b7bf382d06f 100644 --- a/sound/soc/at91/at91-ssc.h +++ b/sound/soc/at91/at91-ssc.h | |||
@@ -21,7 +21,7 @@ | |||
21 | #define AT91SSC_TCMR_PERIOD 1 /* BCLK divider for transmit FS */ | 21 | #define AT91SSC_TCMR_PERIOD 1 /* BCLK divider for transmit FS */ |
22 | #define AT91SSC_RCMR_PERIOD 2 /* BCLK divider for receive FS */ | 22 | #define AT91SSC_RCMR_PERIOD 2 /* BCLK divider for receive FS */ |
23 | 23 | ||
24 | extern struct snd_soc_cpu_dai at91_ssc_dai[]; | 24 | extern struct snd_soc_dai at91_ssc_dai[]; |
25 | 25 | ||
26 | #endif /* _AT91_SSC_H */ | 26 | #endif /* _AT91_SSC_H */ |
27 | 27 | ||
diff --git a/sound/soc/at91/eti_b1_wm8731.c b/sound/soc/at91/eti_b1_wm8731.c index 1347dcf3f80b..d532de954241 100644 --- a/sound/soc/at91/eti_b1_wm8731.c +++ b/sound/soc/at91/eti_b1_wm8731.c | |||
@@ -53,18 +53,18 @@ static struct clk *pllb_clk; | |||
53 | static int eti_b1_startup(struct snd_pcm_substream *substream) | 53 | static int eti_b1_startup(struct snd_pcm_substream *substream) |
54 | { | 54 | { |
55 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 55 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
56 | struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; | 56 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
57 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 57 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
58 | int ret; | 58 | int ret; |
59 | 59 | ||
60 | /* cpu clock is the AT91 master clock sent to the SSC */ | 60 | /* cpu clock is the AT91 master clock sent to the SSC */ |
61 | ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, AT91_SYSCLK_MCK, | 61 | ret = snd_soc_dai_set_sysclk(cpu_dai, AT91_SYSCLK_MCK, |
62 | 60000000, SND_SOC_CLOCK_IN); | 62 | 60000000, SND_SOC_CLOCK_IN); |
63 | if (ret < 0) | 63 | if (ret < 0) |
64 | return ret; | 64 | return ret; |
65 | 65 | ||
66 | /* codec system clock is supplied by PCK1, set to 12MHz */ | 66 | /* codec system clock is supplied by PCK1, set to 12MHz */ |
67 | ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8731_SYSCLK, | 67 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, |
68 | 12000000, SND_SOC_CLOCK_IN); | 68 | 12000000, SND_SOC_CLOCK_IN); |
69 | if (ret < 0) | 69 | if (ret < 0) |
70 | return ret; | 70 | return ret; |
@@ -87,8 +87,8 @@ static int eti_b1_hw_params(struct snd_pcm_substream *substream, | |||
87 | struct snd_pcm_hw_params *params) | 87 | struct snd_pcm_hw_params *params) |
88 | { | 88 | { |
89 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 89 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
90 | struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; | 90 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
91 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 91 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
92 | int ret; | 92 | int ret; |
93 | 93 | ||
94 | #ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE | 94 | #ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE |
@@ -96,13 +96,13 @@ static int eti_b1_hw_params(struct snd_pcm_substream *substream, | |||
96 | int cmr_div, period; | 96 | int cmr_div, period; |
97 | 97 | ||
98 | /* set codec DAI configuration */ | 98 | /* set codec DAI configuration */ |
99 | ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | 99 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | |
100 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | 100 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); |
101 | if (ret < 0) | 101 | if (ret < 0) |
102 | return ret; | 102 | return ret; |
103 | 103 | ||
104 | /* set cpu DAI configuration */ | 104 | /* set cpu DAI configuration */ |
105 | ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | 105 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | |
106 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | 106 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); |
107 | if (ret < 0) | 107 | if (ret < 0) |
108 | return ret; | 108 | return ret; |
@@ -141,17 +141,17 @@ static int eti_b1_hw_params(struct snd_pcm_substream *substream, | |||
141 | } | 141 | } |
142 | 142 | ||
143 | /* set the MCK divider for BCLK */ | 143 | /* set the MCK divider for BCLK */ |
144 | ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, AT91SSC_CMR_DIV, cmr_div); | 144 | ret = snd_soc_dai_set_clkdiv(cpu_dai, AT91SSC_CMR_DIV, cmr_div); |
145 | if (ret < 0) | 145 | if (ret < 0) |
146 | return ret; | 146 | return ret; |
147 | 147 | ||
148 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 148 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
149 | /* set the BCLK divider for DACLRC */ | 149 | /* set the BCLK divider for DACLRC */ |
150 | ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, | 150 | ret = snd_soc_dai_set_clkdiv(cpu_dai, |
151 | AT91SSC_TCMR_PERIOD, period); | 151 | AT91SSC_TCMR_PERIOD, period); |
152 | } else { | 152 | } else { |
153 | /* set the BCLK divider for ADCLRC */ | 153 | /* set the BCLK divider for ADCLRC */ |
154 | ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, | 154 | ret = snd_soc_dai_set_clkdiv(cpu_dai, |
155 | AT91SSC_RCMR_PERIOD, period); | 155 | AT91SSC_RCMR_PERIOD, period); |
156 | } | 156 | } |
157 | if (ret < 0) | 157 | if (ret < 0) |
@@ -163,13 +163,13 @@ static int eti_b1_hw_params(struct snd_pcm_substream *substream, | |||
163 | */ | 163 | */ |
164 | 164 | ||
165 | /* set codec DAI configuration */ | 165 | /* set codec DAI configuration */ |
166 | ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | 166 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | |
167 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); | 167 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); |
168 | if (ret < 0) | 168 | if (ret < 0) |
169 | return ret; | 169 | return ret; |
170 | 170 | ||
171 | /* set cpu DAI configuration */ | 171 | /* set cpu DAI configuration */ |
172 | ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | 172 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | |
173 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); | 173 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); |
174 | if (ret < 0) | 174 | if (ret < 0) |
175 | return ret; | 175 | return ret; |
@@ -191,7 +191,7 @@ static const struct snd_soc_dapm_widget eti_b1_dapm_widgets[] = { | |||
191 | SND_SOC_DAPM_SPK("Ext Spk", NULL), | 191 | SND_SOC_DAPM_SPK("Ext Spk", NULL), |
192 | }; | 192 | }; |
193 | 193 | ||
194 | static const char *intercon[][3] = { | 194 | static const struct snd_soc_dapm_route intercon[] = { |
195 | 195 | ||
196 | /* speaker connected to LHPOUT */ | 196 | /* speaker connected to LHPOUT */ |
197 | {"Ext Spk", NULL, "LHPOUT"}, | 197 | {"Ext Spk", NULL, "LHPOUT"}, |
@@ -199,9 +199,6 @@ static const char *intercon[][3] = { | |||
199 | /* mic is connected to Mic Jack, with WM8731 Mic Bias */ | 199 | /* mic is connected to Mic Jack, with WM8731 Mic Bias */ |
200 | {"MICIN", NULL, "Mic Bias"}, | 200 | {"MICIN", NULL, "Mic Bias"}, |
201 | {"Mic Bias", NULL, "Int Mic"}, | 201 | {"Mic Bias", NULL, "Int Mic"}, |
202 | |||
203 | /* terminator */ | ||
204 | {NULL, NULL, NULL}, | ||
205 | }; | 202 | }; |
206 | 203 | ||
207 | /* | 204 | /* |
@@ -209,30 +206,24 @@ static const char *intercon[][3] = { | |||
209 | */ | 206 | */ |
210 | static int eti_b1_wm8731_init(struct snd_soc_codec *codec) | 207 | static int eti_b1_wm8731_init(struct snd_soc_codec *codec) |
211 | { | 208 | { |
212 | int i; | ||
213 | |||
214 | DBG("eti_b1_wm8731_init() called\n"); | 209 | DBG("eti_b1_wm8731_init() called\n"); |
215 | 210 | ||
216 | /* Add specific widgets */ | 211 | /* Add specific widgets */ |
217 | for(i = 0; i < ARRAY_SIZE(eti_b1_dapm_widgets); i++) { | 212 | snd_soc_dapm_new_controls(codec, eti_b1_dapm_widgets, |
218 | snd_soc_dapm_new_control(codec, &eti_b1_dapm_widgets[i]); | 213 | ARRAY_SIZE(eti_b1_dapm_widgets)); |
219 | } | ||
220 | 214 | ||
221 | /* Set up specific audio path interconnects */ | 215 | /* Set up specific audio path interconnects */ |
222 | for(i = 0; intercon[i][0] != NULL; i++) { | 216 | snd_soc_dapm_add_route(codec, intercon, ARRAY_SIZE(intercon)); |
223 | snd_soc_dapm_connect_input(codec, intercon[i][0], | ||
224 | intercon[i][1], intercon[i][2]); | ||
225 | } | ||
226 | 217 | ||
227 | /* not connected */ | 218 | /* not connected */ |
228 | snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0); | 219 | snd_soc_dapm_disable_pin(codec, "RLINEIN"); |
229 | snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0); | 220 | snd_soc_dapm_disable_pin(codec, "LLINEIN"); |
230 | 221 | ||
231 | /* always connected */ | 222 | /* always connected */ |
232 | snd_soc_dapm_set_endpoint(codec, "Int Mic", 1); | 223 | snd_soc_dapm_enable_pin(codec, "Int Mic"); |
233 | snd_soc_dapm_set_endpoint(codec, "Ext Spk", 1); | 224 | snd_soc_dapm_enable_pin(codec, "Ext Spk"); |
234 | 225 | ||
235 | snd_soc_dapm_sync_endpoints(codec); | 226 | snd_soc_dapm_sync(codec); |
236 | 227 | ||
237 | return 0; | 228 | return 0; |
238 | } | 229 | } |
diff --git a/sound/soc/au1x/Kconfig b/sound/soc/au1x/Kconfig new file mode 100644 index 000000000000..410a893aa66b --- /dev/null +++ b/sound/soc/au1x/Kconfig | |||
@@ -0,0 +1,32 @@ | |||
1 | ## | ||
2 | ## Au1200/Au1550 PSC + DBDMA | ||
3 | ## | ||
4 | config SND_SOC_AU1XPSC | ||
5 | tristate "SoC Audio for Au1200/Au1250/Au1550" | ||
6 | depends on SOC_AU1200 || SOC_AU1550 | ||
7 | help | ||
8 | This option enables support for the Programmable Serial | ||
9 | Controllers in AC97 and I2S mode, and the Descriptor-Based DMA | ||
10 | Controller (DBDMA) as found on the Au1200/Au1250/Au1550 SoC. | ||
11 | |||
12 | config SND_SOC_AU1XPSC_I2S | ||
13 | tristate | ||
14 | |||
15 | config SND_SOC_AU1XPSC_AC97 | ||
16 | tristate | ||
17 | select AC97_BUS | ||
18 | select SND_AC97_CODEC | ||
19 | select SND_SOC_AC97_BUS | ||
20 | |||
21 | |||
22 | ## | ||
23 | ## Boards | ||
24 | ## | ||
25 | config SND_SOC_SAMPLE_PSC_AC97 | ||
26 | tristate "Sample Au12x0/Au1550 PSC AC97 sound machine" | ||
27 | depends on SND_SOC_AU1XPSC | ||
28 | select SND_SOC_AU1XPSC_AC97 | ||
29 | select SND_SOC_AC97_CODEC | ||
30 | help | ||
31 | This is a sample AC97 sound machine for use in Au12x0/Au1550 | ||
32 | based systems which have audio on PSC1 (e.g. Db1200 demoboard). | ||
diff --git a/sound/soc/au1x/Makefile b/sound/soc/au1x/Makefile new file mode 100644 index 000000000000..6c6950b8003a --- /dev/null +++ b/sound/soc/au1x/Makefile | |||
@@ -0,0 +1,13 @@ | |||
1 | # Au1200/Au1550 PSC audio | ||
2 | snd-soc-au1xpsc-dbdma-objs := dbdma2.o | ||
3 | snd-soc-au1xpsc-i2s-objs := psc-i2s.o | ||
4 | snd-soc-au1xpsc-ac97-objs := psc-ac97.o | ||
5 | |||
6 | obj-$(CONFIG_SND_SOC_AU1XPSC) += snd-soc-au1xpsc-dbdma.o | ||
7 | obj-$(CONFIG_SND_SOC_AU1XPSC_I2S) += snd-soc-au1xpsc-i2s.o | ||
8 | obj-$(CONFIG_SND_SOC_AU1XPSC_AC97) += snd-soc-au1xpsc-ac97.o | ||
9 | |||
10 | # Boards | ||
11 | snd-soc-sample-ac97-objs := sample-ac97.o | ||
12 | |||
13 | obj-$(CONFIG_SND_SOC_SAMPLE_PSC_AC97) += snd-soc-sample-ac97.o | ||
diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c new file mode 100644 index 000000000000..1466d9328800 --- /dev/null +++ b/sound/soc/au1x/dbdma2.c | |||
@@ -0,0 +1,421 @@ | |||
1 | /* | ||
2 | * Au12x0/Au1550 PSC ALSA ASoC audio support. | ||
3 | * | ||
4 | * (c) 2007-2008 MSC Vertriebsges.m.b.H., | ||
5 | * Manuel Lauss <mano@roarinelk.homelinux.net> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * DMA glue for Au1x-PSC audio. | ||
12 | * | ||
13 | * NOTE: all of these drivers can only work with a SINGLE instance | ||
14 | * of a PSC. Multiple independent audio devices are impossible | ||
15 | * with ASoC v1. | ||
16 | */ | ||
17 | |||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/dma-mapping.h> | ||
24 | |||
25 | #include <sound/core.h> | ||
26 | #include <sound/pcm.h> | ||
27 | #include <sound/pcm_params.h> | ||
28 | #include <sound/soc.h> | ||
29 | |||
30 | #include <asm/mach-au1x00/au1000.h> | ||
31 | #include <asm/mach-au1x00/au1xxx_dbdma.h> | ||
32 | #include <asm/mach-au1x00/au1xxx_psc.h> | ||
33 | |||
34 | #include "psc.h" | ||
35 | |||
36 | /*#define PCM_DEBUG*/ | ||
37 | |||
38 | #define MSG(x...) printk(KERN_INFO "au1xpsc_pcm: " x) | ||
39 | #ifdef PCM_DEBUG | ||
40 | #define DBG MSG | ||
41 | #else | ||
42 | #define DBG(x...) do {} while (0) | ||
43 | #endif | ||
44 | |||
45 | struct au1xpsc_audio_dmadata { | ||
46 | /* DDMA control data */ | ||
47 | unsigned int ddma_id; /* DDMA direction ID for this PSC */ | ||
48 | u32 ddma_chan; /* DDMA context */ | ||
49 | |||
50 | /* PCM context (for irq handlers) */ | ||
51 | struct snd_pcm_substream *substream; | ||
52 | unsigned long curr_period; /* current segment DDMA is working on */ | ||
53 | unsigned long q_period; /* queue period(s) */ | ||
54 | unsigned long dma_area; /* address of queued DMA area */ | ||
55 | unsigned long dma_area_s; /* start address of DMA area */ | ||
56 | unsigned long pos; /* current byte position being played */ | ||
57 | unsigned long periods; /* number of SG segments in total */ | ||
58 | unsigned long period_bytes; /* size in bytes of one SG segment */ | ||
59 | |||
60 | /* runtime data */ | ||
61 | int msbits; | ||
62 | }; | ||
63 | |||
64 | /* instance data. There can be only one, MacLeod!!!! */ | ||
65 | static struct au1xpsc_audio_dmadata *au1xpsc_audio_pcmdma[2]; | ||
66 | |||
67 | /* | ||
68 | * These settings are somewhat okay, at least on my machine audio plays | ||
69 | * almost skip-free. Especially the 64kB buffer seems to help a LOT. | ||
70 | */ | ||
71 | #define AU1XPSC_PERIOD_MIN_BYTES 1024 | ||
72 | #define AU1XPSC_BUFFER_MIN_BYTES 65536 | ||
73 | |||
74 | #define AU1XPSC_PCM_FMTS \ | ||
75 | (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | \ | ||
76 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ | ||
77 | SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE | \ | ||
78 | SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE | \ | ||
79 | SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE | \ | ||
80 | 0) | ||
81 | |||
82 | /* PCM hardware DMA capabilities - platform specific */ | ||
83 | static const struct snd_pcm_hardware au1xpsc_pcm_hardware = { | ||
84 | .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | | ||
85 | SNDRV_PCM_INFO_INTERLEAVED, | ||
86 | .formats = AU1XPSC_PCM_FMTS, | ||
87 | .period_bytes_min = AU1XPSC_PERIOD_MIN_BYTES, | ||
88 | .period_bytes_max = 4096 * 1024 - 1, | ||
89 | .periods_min = 2, | ||
90 | .periods_max = 4096, /* 2 to as-much-as-you-like */ | ||
91 | .buffer_bytes_max = 4096 * 1024 - 1, | ||
92 | .fifo_size = 16, /* fifo entries of AC97/I2S PSC */ | ||
93 | }; | ||
94 | |||
95 | static void au1x_pcm_queue_tx(struct au1xpsc_audio_dmadata *cd) | ||
96 | { | ||
97 | au1xxx_dbdma_put_source_flags(cd->ddma_chan, | ||
98 | (void *)phys_to_virt(cd->dma_area), | ||
99 | cd->period_bytes, DDMA_FLAGS_IE); | ||
100 | |||
101 | /* update next-to-queue period */ | ||
102 | ++cd->q_period; | ||
103 | cd->dma_area += cd->period_bytes; | ||
104 | if (cd->q_period >= cd->periods) { | ||
105 | cd->q_period = 0; | ||
106 | cd->dma_area = cd->dma_area_s; | ||
107 | } | ||
108 | } | ||
109 | |||
110 | static void au1x_pcm_queue_rx(struct au1xpsc_audio_dmadata *cd) | ||
111 | { | ||
112 | au1xxx_dbdma_put_dest_flags(cd->ddma_chan, | ||
113 | (void *)phys_to_virt(cd->dma_area), | ||
114 | cd->period_bytes, DDMA_FLAGS_IE); | ||
115 | |||
116 | /* update next-to-queue period */ | ||
117 | ++cd->q_period; | ||
118 | cd->dma_area += cd->period_bytes; | ||
119 | if (cd->q_period >= cd->periods) { | ||
120 | cd->q_period = 0; | ||
121 | cd->dma_area = cd->dma_area_s; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | static void au1x_pcm_dmatx_cb(int irq, void *dev_id) | ||
126 | { | ||
127 | struct au1xpsc_audio_dmadata *cd = dev_id; | ||
128 | |||
129 | cd->pos += cd->period_bytes; | ||
130 | if (++cd->curr_period >= cd->periods) { | ||
131 | cd->pos = 0; | ||
132 | cd->curr_period = 0; | ||
133 | } | ||
134 | snd_pcm_period_elapsed(cd->substream); | ||
135 | au1x_pcm_queue_tx(cd); | ||
136 | } | ||
137 | |||
138 | static void au1x_pcm_dmarx_cb(int irq, void *dev_id) | ||
139 | { | ||
140 | struct au1xpsc_audio_dmadata *cd = dev_id; | ||
141 | |||
142 | cd->pos += cd->period_bytes; | ||
143 | if (++cd->curr_period >= cd->periods) { | ||
144 | cd->pos = 0; | ||
145 | cd->curr_period = 0; | ||
146 | } | ||
147 | snd_pcm_period_elapsed(cd->substream); | ||
148 | au1x_pcm_queue_rx(cd); | ||
149 | } | ||
150 | |||
151 | static void au1x_pcm_dbdma_free(struct au1xpsc_audio_dmadata *pcd) | ||
152 | { | ||
153 | if (pcd->ddma_chan) { | ||
154 | au1xxx_dbdma_stop(pcd->ddma_chan); | ||
155 | au1xxx_dbdma_reset(pcd->ddma_chan); | ||
156 | au1xxx_dbdma_chan_free(pcd->ddma_chan); | ||
157 | pcd->ddma_chan = 0; | ||
158 | pcd->msbits = 0; | ||
159 | } | ||
160 | } | ||
161 | |||
162 | /* in case of missing DMA ring or changed TX-source / RX-dest bit widths, | ||
163 | * allocate (or reallocate) a 2-descriptor DMA ring with bit depth according | ||
164 | * to ALSA-supplied sample depth. This is due to limitations in the dbdma api | ||
165 | * (cannot adjust source/dest widths of already allocated descriptor ring). | ||
166 | */ | ||
167 | static int au1x_pcm_dbdma_realloc(struct au1xpsc_audio_dmadata *pcd, | ||
168 | int stype, int msbits) | ||
169 | { | ||
170 | /* DMA only in 8/16/32 bit widths */ | ||
171 | if (msbits == 24) | ||
172 | msbits = 32; | ||
173 | |||
174 | /* check current config: correct bits and descriptors allocated? */ | ||
175 | if ((pcd->ddma_chan) && (msbits == pcd->msbits)) | ||
176 | goto out; /* all ok! */ | ||
177 | |||
178 | au1x_pcm_dbdma_free(pcd); | ||
179 | |||
180 | if (stype == PCM_RX) | ||
181 | pcd->ddma_chan = au1xxx_dbdma_chan_alloc(pcd->ddma_id, | ||
182 | DSCR_CMD0_ALWAYS, | ||
183 | au1x_pcm_dmarx_cb, (void *)pcd); | ||
184 | else | ||
185 | pcd->ddma_chan = au1xxx_dbdma_chan_alloc(DSCR_CMD0_ALWAYS, | ||
186 | pcd->ddma_id, | ||
187 | au1x_pcm_dmatx_cb, (void *)pcd); | ||
188 | |||
189 | if (!pcd->ddma_chan) | ||
190 | return -ENOMEM;; | ||
191 | |||
192 | au1xxx_dbdma_set_devwidth(pcd->ddma_chan, msbits); | ||
193 | au1xxx_dbdma_ring_alloc(pcd->ddma_chan, 2); | ||
194 | |||
195 | pcd->msbits = msbits; | ||
196 | |||
197 | au1xxx_dbdma_stop(pcd->ddma_chan); | ||
198 | au1xxx_dbdma_reset(pcd->ddma_chan); | ||
199 | |||
200 | out: | ||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream, | ||
205 | struct snd_pcm_hw_params *params) | ||
206 | { | ||
207 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
208 | struct au1xpsc_audio_dmadata *pcd; | ||
209 | int stype, ret; | ||
210 | |||
211 | ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); | ||
212 | if (ret < 0) | ||
213 | goto out; | ||
214 | |||
215 | stype = SUBSTREAM_TYPE(substream); | ||
216 | pcd = au1xpsc_audio_pcmdma[stype]; | ||
217 | |||
218 | DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %d " | ||
219 | "runtime->min_align %d\n", | ||
220 | (unsigned long)runtime->dma_area, | ||
221 | (unsigned long)runtime->dma_addr, runtime->dma_bytes, | ||
222 | runtime->min_align); | ||
223 | |||
224 | DBG("bits %d frags %d frag_bytes %d is_rx %d\n", params->msbits, | ||
225 | params_periods(params), params_period_bytes(params), stype); | ||
226 | |||
227 | ret = au1x_pcm_dbdma_realloc(pcd, stype, params->msbits); | ||
228 | if (ret) { | ||
229 | MSG("DDMA channel (re)alloc failed!\n"); | ||
230 | goto out; | ||
231 | } | ||
232 | |||
233 | pcd->substream = substream; | ||
234 | pcd->period_bytes = params_period_bytes(params); | ||
235 | pcd->periods = params_periods(params); | ||
236 | pcd->dma_area_s = pcd->dma_area = (unsigned long)runtime->dma_addr; | ||
237 | pcd->q_period = 0; | ||
238 | pcd->curr_period = 0; | ||
239 | pcd->pos = 0; | ||
240 | |||
241 | ret = 0; | ||
242 | out: | ||
243 | return ret; | ||
244 | } | ||
245 | |||
246 | static int au1xpsc_pcm_hw_free(struct snd_pcm_substream *substream) | ||
247 | { | ||
248 | snd_pcm_lib_free_pages(substream); | ||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream) | ||
253 | { | ||
254 | struct au1xpsc_audio_dmadata *pcd = | ||
255 | au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]; | ||
256 | |||
257 | au1xxx_dbdma_reset(pcd->ddma_chan); | ||
258 | |||
259 | if (SUBSTREAM_TYPE(substream) == PCM_RX) { | ||
260 | au1x_pcm_queue_rx(pcd); | ||
261 | au1x_pcm_queue_rx(pcd); | ||
262 | } else { | ||
263 | au1x_pcm_queue_tx(pcd); | ||
264 | au1x_pcm_queue_tx(pcd); | ||
265 | } | ||
266 | |||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | static int au1xpsc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
271 | { | ||
272 | u32 c = au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]->ddma_chan; | ||
273 | |||
274 | switch (cmd) { | ||
275 | case SNDRV_PCM_TRIGGER_START: | ||
276 | case SNDRV_PCM_TRIGGER_RESUME: | ||
277 | au1xxx_dbdma_start(c); | ||
278 | break; | ||
279 | case SNDRV_PCM_TRIGGER_STOP: | ||
280 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
281 | au1xxx_dbdma_stop(c); | ||
282 | break; | ||
283 | default: | ||
284 | return -EINVAL; | ||
285 | } | ||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | static snd_pcm_uframes_t | ||
290 | au1xpsc_pcm_pointer(struct snd_pcm_substream *substream) | ||
291 | { | ||
292 | return bytes_to_frames(substream->runtime, | ||
293 | au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]->pos); | ||
294 | } | ||
295 | |||
296 | static int au1xpsc_pcm_open(struct snd_pcm_substream *substream) | ||
297 | { | ||
298 | snd_soc_set_runtime_hwparams(substream, &au1xpsc_pcm_hardware); | ||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | static int au1xpsc_pcm_close(struct snd_pcm_substream *substream) | ||
303 | { | ||
304 | au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]); | ||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | struct snd_pcm_ops au1xpsc_pcm_ops = { | ||
309 | .open = au1xpsc_pcm_open, | ||
310 | .close = au1xpsc_pcm_close, | ||
311 | .ioctl = snd_pcm_lib_ioctl, | ||
312 | .hw_params = au1xpsc_pcm_hw_params, | ||
313 | .hw_free = au1xpsc_pcm_hw_free, | ||
314 | .prepare = au1xpsc_pcm_prepare, | ||
315 | .trigger = au1xpsc_pcm_trigger, | ||
316 | .pointer = au1xpsc_pcm_pointer, | ||
317 | }; | ||
318 | |||
319 | static void au1xpsc_pcm_free_dma_buffers(struct snd_pcm *pcm) | ||
320 | { | ||
321 | snd_pcm_lib_preallocate_free_for_all(pcm); | ||
322 | } | ||
323 | |||
324 | static int au1xpsc_pcm_new(struct snd_card *card, | ||
325 | struct snd_soc_dai *dai, | ||
326 | struct snd_pcm *pcm) | ||
327 | { | ||
328 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | ||
329 | card->dev, AU1XPSC_BUFFER_MIN_BYTES, (4096 * 1024) - 1); | ||
330 | |||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | static int au1xpsc_pcm_probe(struct platform_device *pdev) | ||
335 | { | ||
336 | struct resource *r; | ||
337 | int ret; | ||
338 | |||
339 | if (au1xpsc_audio_pcmdma[PCM_TX] || au1xpsc_audio_pcmdma[PCM_RX]) | ||
340 | return -EBUSY; | ||
341 | |||
342 | /* TX DMA */ | ||
343 | au1xpsc_audio_pcmdma[PCM_TX] | ||
344 | = kzalloc(sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL); | ||
345 | if (!au1xpsc_audio_pcmdma[PCM_TX]) | ||
346 | return -ENOMEM; | ||
347 | |||
348 | r = platform_get_resource(pdev, IORESOURCE_DMA, 0); | ||
349 | if (!r) { | ||
350 | ret = -ENODEV; | ||
351 | goto out1; | ||
352 | } | ||
353 | (au1xpsc_audio_pcmdma[PCM_TX])->ddma_id = r->start; | ||
354 | |||
355 | /* RX DMA */ | ||
356 | au1xpsc_audio_pcmdma[PCM_RX] | ||
357 | = kzalloc(sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL); | ||
358 | if (!au1xpsc_audio_pcmdma[PCM_RX]) | ||
359 | return -ENOMEM; | ||
360 | |||
361 | r = platform_get_resource(pdev, IORESOURCE_DMA, 1); | ||
362 | if (!r) { | ||
363 | ret = -ENODEV; | ||
364 | goto out2; | ||
365 | } | ||
366 | (au1xpsc_audio_pcmdma[PCM_RX])->ddma_id = r->start; | ||
367 | |||
368 | return 0; | ||
369 | |||
370 | out2: | ||
371 | kfree(au1xpsc_audio_pcmdma[PCM_RX]); | ||
372 | au1xpsc_audio_pcmdma[PCM_RX] = NULL; | ||
373 | out1: | ||
374 | kfree(au1xpsc_audio_pcmdma[PCM_TX]); | ||
375 | au1xpsc_audio_pcmdma[PCM_TX] = NULL; | ||
376 | return ret; | ||
377 | } | ||
378 | |||
379 | static int au1xpsc_pcm_remove(struct platform_device *pdev) | ||
380 | { | ||
381 | int i; | ||
382 | |||
383 | for (i = 0; i < 2; i++) { | ||
384 | if (au1xpsc_audio_pcmdma[i]) { | ||
385 | au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[i]); | ||
386 | kfree(au1xpsc_audio_pcmdma[i]); | ||
387 | au1xpsc_audio_pcmdma[i] = NULL; | ||
388 | } | ||
389 | } | ||
390 | |||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | /* au1xpsc audio platform */ | ||
395 | struct snd_soc_platform au1xpsc_soc_platform = { | ||
396 | .name = "au1xpsc-pcm-dbdma", | ||
397 | .probe = au1xpsc_pcm_probe, | ||
398 | .remove = au1xpsc_pcm_remove, | ||
399 | .pcm_ops = &au1xpsc_pcm_ops, | ||
400 | .pcm_new = au1xpsc_pcm_new, | ||
401 | .pcm_free = au1xpsc_pcm_free_dma_buffers, | ||
402 | }; | ||
403 | EXPORT_SYMBOL_GPL(au1xpsc_soc_platform); | ||
404 | |||
405 | static int __init au1xpsc_audio_dbdma_init(void) | ||
406 | { | ||
407 | au1xpsc_audio_pcmdma[PCM_TX] = NULL; | ||
408 | au1xpsc_audio_pcmdma[PCM_RX] = NULL; | ||
409 | return 0; | ||
410 | } | ||
411 | |||
412 | static void __exit au1xpsc_audio_dbdma_exit(void) | ||
413 | { | ||
414 | } | ||
415 | |||
416 | module_init(au1xpsc_audio_dbdma_init); | ||
417 | module_exit(au1xpsc_audio_dbdma_exit); | ||
418 | |||
419 | MODULE_LICENSE("GPL"); | ||
420 | MODULE_DESCRIPTION("Au12x0/Au1550 PSC Audio DMA driver"); | ||
421 | MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>"); | ||
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c new file mode 100644 index 000000000000..57facbad6825 --- /dev/null +++ b/sound/soc/au1x/psc-ac97.c | |||
@@ -0,0 +1,387 @@ | |||
1 | /* | ||
2 | * Au12x0/Au1550 PSC ALSA ASoC audio support. | ||
3 | * | ||
4 | * (c) 2007-2008 MSC Vertriebsges.m.b.H., | ||
5 | * Manuel Lauss <mano@roarinelk.homelinux.net> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * Au1xxx-PSC AC97 glue. | ||
12 | * | ||
13 | * NOTE: all of these drivers can only work with a SINGLE instance | ||
14 | * of a PSC. Multiple independent audio devices are impossible | ||
15 | * with ASoC v1. | ||
16 | */ | ||
17 | |||
18 | #include <linux/init.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/device.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/suspend.h> | ||
23 | #include <sound/core.h> | ||
24 | #include <sound/pcm.h> | ||
25 | #include <sound/initval.h> | ||
26 | #include <sound/soc.h> | ||
27 | #include <asm/mach-au1x00/au1000.h> | ||
28 | #include <asm/mach-au1x00/au1xxx_psc.h> | ||
29 | |||
30 | #include "psc.h" | ||
31 | |||
32 | #define AC97_DIR \ | ||
33 | (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) | ||
34 | |||
35 | #define AC97_RATES \ | ||
36 | SNDRV_PCM_RATE_8000_48000 | ||
37 | |||
38 | #define AC97_FMTS \ | ||
39 | (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3BE) | ||
40 | |||
41 | #define AC97PCR_START(stype) \ | ||
42 | ((stype) == PCM_TX ? PSC_AC97PCR_TS : PSC_AC97PCR_RS) | ||
43 | #define AC97PCR_STOP(stype) \ | ||
44 | ((stype) == PCM_TX ? PSC_AC97PCR_TP : PSC_AC97PCR_RP) | ||
45 | #define AC97PCR_CLRFIFO(stype) \ | ||
46 | ((stype) == PCM_TX ? PSC_AC97PCR_TC : PSC_AC97PCR_RC) | ||
47 | |||
48 | /* instance data. There can be only one, MacLeod!!!! */ | ||
49 | static struct au1xpsc_audio_data *au1xpsc_ac97_workdata; | ||
50 | |||
51 | /* AC97 controller reads codec register */ | ||
52 | static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97, | ||
53 | unsigned short reg) | ||
54 | { | ||
55 | /* FIXME */ | ||
56 | struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; | ||
57 | unsigned short data, tmo; | ||
58 | |||
59 | au_writel(PSC_AC97CDC_RD | PSC_AC97CDC_INDX(reg), AC97_CDC(pscdata)); | ||
60 | au_sync(); | ||
61 | |||
62 | tmo = 1000; | ||
63 | while ((!(au_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD)) && --tmo) | ||
64 | udelay(2); | ||
65 | |||
66 | if (!tmo) | ||
67 | data = 0xffff; | ||
68 | else | ||
69 | data = au_readl(AC97_CDC(pscdata)) & 0xffff; | ||
70 | |||
71 | au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); | ||
72 | au_sync(); | ||
73 | |||
74 | return data; | ||
75 | } | ||
76 | |||
77 | /* AC97 controller writes to codec register */ | ||
78 | static void au1xpsc_ac97_write(struct snd_ac97 *ac97, unsigned short reg, | ||
79 | unsigned short val) | ||
80 | { | ||
81 | /* FIXME */ | ||
82 | struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; | ||
83 | unsigned int tmo; | ||
84 | |||
85 | au_writel(PSC_AC97CDC_INDX(reg) | (val & 0xffff), AC97_CDC(pscdata)); | ||
86 | au_sync(); | ||
87 | tmo = 1000; | ||
88 | while ((!(au_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD)) && --tmo) | ||
89 | au_sync(); | ||
90 | |||
91 | au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); | ||
92 | au_sync(); | ||
93 | } | ||
94 | |||
95 | /* AC97 controller asserts a warm reset */ | ||
96 | static void au1xpsc_ac97_warm_reset(struct snd_ac97 *ac97) | ||
97 | { | ||
98 | /* FIXME */ | ||
99 | struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; | ||
100 | |||
101 | au_writel(PSC_AC97RST_SNC, AC97_RST(pscdata)); | ||
102 | au_sync(); | ||
103 | msleep(10); | ||
104 | au_writel(0, AC97_RST(pscdata)); | ||
105 | au_sync(); | ||
106 | } | ||
107 | |||
108 | static void au1xpsc_ac97_cold_reset(struct snd_ac97 *ac97) | ||
109 | { | ||
110 | /* FIXME */ | ||
111 | struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; | ||
112 | int i; | ||
113 | |||
114 | /* disable PSC during cold reset */ | ||
115 | au_writel(0, AC97_CFG(au1xpsc_ac97_workdata)); | ||
116 | au_sync(); | ||
117 | au_writel(PSC_CTRL_DISABLE, PSC_CTRL(pscdata)); | ||
118 | au_sync(); | ||
119 | |||
120 | /* issue cold reset */ | ||
121 | au_writel(PSC_AC97RST_RST, AC97_RST(pscdata)); | ||
122 | au_sync(); | ||
123 | msleep(500); | ||
124 | au_writel(0, AC97_RST(pscdata)); | ||
125 | au_sync(); | ||
126 | |||
127 | /* enable PSC */ | ||
128 | au_writel(PSC_CTRL_ENABLE, PSC_CTRL(pscdata)); | ||
129 | au_sync(); | ||
130 | |||
131 | /* wait for PSC to indicate it's ready */ | ||
132 | i = 100000; | ||
133 | while (!((au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_SR)) && (--i)) | ||
134 | au_sync(); | ||
135 | |||
136 | if (i == 0) { | ||
137 | printk(KERN_ERR "au1xpsc-ac97: PSC not ready!\n"); | ||
138 | return; | ||
139 | } | ||
140 | |||
141 | /* enable the ac97 function */ | ||
142 | au_writel(pscdata->cfg | PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata)); | ||
143 | au_sync(); | ||
144 | |||
145 | /* wait for AC97 core to become ready */ | ||
146 | i = 100000; | ||
147 | while (!((au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR)) && (--i)) | ||
148 | au_sync(); | ||
149 | if (i == 0) | ||
150 | printk(KERN_ERR "au1xpsc-ac97: AC97 ctrl not ready\n"); | ||
151 | } | ||
152 | |||
153 | /* AC97 controller operations */ | ||
154 | struct snd_ac97_bus_ops soc_ac97_ops = { | ||
155 | .read = au1xpsc_ac97_read, | ||
156 | .write = au1xpsc_ac97_write, | ||
157 | .reset = au1xpsc_ac97_cold_reset, | ||
158 | .warm_reset = au1xpsc_ac97_warm_reset, | ||
159 | }; | ||
160 | EXPORT_SYMBOL_GPL(soc_ac97_ops); | ||
161 | |||
162 | static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream, | ||
163 | struct snd_pcm_hw_params *params) | ||
164 | { | ||
165 | /* FIXME */ | ||
166 | struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; | ||
167 | unsigned long r, stat; | ||
168 | int chans, stype = SUBSTREAM_TYPE(substream); | ||
169 | |||
170 | chans = params_channels(params); | ||
171 | |||
172 | r = au_readl(AC97_CFG(pscdata)); | ||
173 | stat = au_readl(AC97_STAT(pscdata)); | ||
174 | |||
175 | /* already active? */ | ||
176 | if (stat & (PSC_AC97STAT_TB | PSC_AC97STAT_RB)) { | ||
177 | /* reject parameters not currently set up */ | ||
178 | if ((PSC_AC97CFG_GET_LEN(r) != params->msbits) || | ||
179 | (pscdata->rate != params_rate(params))) | ||
180 | return -EINVAL; | ||
181 | } else { | ||
182 | /* disable AC97 device controller first */ | ||
183 | au_writel(r & ~PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata)); | ||
184 | au_sync(); | ||
185 | |||
186 | /* set sample bitdepth: REG[24:21]=(BITS-2)/2 */ | ||
187 | r &= ~PSC_AC97CFG_LEN_MASK; | ||
188 | r |= PSC_AC97CFG_SET_LEN(params->msbits); | ||
189 | |||
190 | /* channels: enable slots for front L/R channel */ | ||
191 | if (stype == PCM_TX) { | ||
192 | r &= ~PSC_AC97CFG_TXSLOT_MASK; | ||
193 | r |= PSC_AC97CFG_TXSLOT_ENA(3); | ||
194 | r |= PSC_AC97CFG_TXSLOT_ENA(4); | ||
195 | } else { | ||
196 | r &= ~PSC_AC97CFG_RXSLOT_MASK; | ||
197 | r |= PSC_AC97CFG_RXSLOT_ENA(3); | ||
198 | r |= PSC_AC97CFG_RXSLOT_ENA(4); | ||
199 | } | ||
200 | |||
201 | /* finally enable the AC97 controller again */ | ||
202 | au_writel(r | PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata)); | ||
203 | au_sync(); | ||
204 | |||
205 | pscdata->cfg = r; | ||
206 | pscdata->rate = params_rate(params); | ||
207 | } | ||
208 | |||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream, | ||
213 | int cmd) | ||
214 | { | ||
215 | /* FIXME */ | ||
216 | struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; | ||
217 | int ret, stype = SUBSTREAM_TYPE(substream); | ||
218 | |||
219 | ret = 0; | ||
220 | |||
221 | switch (cmd) { | ||
222 | case SNDRV_PCM_TRIGGER_START: | ||
223 | case SNDRV_PCM_TRIGGER_RESUME: | ||
224 | au_writel(AC97PCR_START(stype), AC97_PCR(pscdata)); | ||
225 | au_sync(); | ||
226 | break; | ||
227 | case SNDRV_PCM_TRIGGER_STOP: | ||
228 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
229 | au_writel(AC97PCR_STOP(stype), AC97_PCR(pscdata)); | ||
230 | au_sync(); | ||
231 | break; | ||
232 | default: | ||
233 | ret = -EINVAL; | ||
234 | } | ||
235 | return ret; | ||
236 | } | ||
237 | |||
238 | static int au1xpsc_ac97_probe(struct platform_device *pdev, | ||
239 | struct snd_soc_dai *dai) | ||
240 | { | ||
241 | int ret; | ||
242 | struct resource *r; | ||
243 | unsigned long sel; | ||
244 | |||
245 | if (au1xpsc_ac97_workdata) | ||
246 | return -EBUSY; | ||
247 | |||
248 | au1xpsc_ac97_workdata = | ||
249 | kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL); | ||
250 | if (!au1xpsc_ac97_workdata) | ||
251 | return -ENOMEM; | ||
252 | |||
253 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
254 | if (!r) { | ||
255 | ret = -ENODEV; | ||
256 | goto out0; | ||
257 | } | ||
258 | |||
259 | ret = -EBUSY; | ||
260 | au1xpsc_ac97_workdata->ioarea = | ||
261 | request_mem_region(r->start, r->end - r->start + 1, | ||
262 | "au1xpsc_ac97"); | ||
263 | if (!au1xpsc_ac97_workdata->ioarea) | ||
264 | goto out0; | ||
265 | |||
266 | au1xpsc_ac97_workdata->mmio = ioremap(r->start, 0xffff); | ||
267 | if (!au1xpsc_ac97_workdata->mmio) | ||
268 | goto out1; | ||
269 | |||
270 | /* configuration: max dma trigger threshold, enable ac97 */ | ||
271 | au1xpsc_ac97_workdata->cfg = PSC_AC97CFG_RT_FIFO8 | | ||
272 | PSC_AC97CFG_TT_FIFO8 | | ||
273 | PSC_AC97CFG_DE_ENABLE; | ||
274 | |||
275 | /* preserve PSC clock source set up by platform (dev.platform_data | ||
276 | * is already occupied by soc layer) | ||
277 | */ | ||
278 | sel = au_readl(PSC_SEL(au1xpsc_ac97_workdata)) & PSC_SEL_CLK_MASK; | ||
279 | au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_ac97_workdata)); | ||
280 | au_sync(); | ||
281 | au_writel(0, PSC_SEL(au1xpsc_ac97_workdata)); | ||
282 | au_sync(); | ||
283 | au_writel(PSC_SEL_PS_AC97MODE | sel, PSC_SEL(au1xpsc_ac97_workdata)); | ||
284 | au_sync(); | ||
285 | /* next up: cold reset. Dont check for PSC-ready now since | ||
286 | * there may not be any codec clock yet. | ||
287 | */ | ||
288 | |||
289 | return 0; | ||
290 | |||
291 | out1: | ||
292 | release_resource(au1xpsc_ac97_workdata->ioarea); | ||
293 | kfree(au1xpsc_ac97_workdata->ioarea); | ||
294 | out0: | ||
295 | kfree(au1xpsc_ac97_workdata); | ||
296 | au1xpsc_ac97_workdata = NULL; | ||
297 | return ret; | ||
298 | } | ||
299 | |||
300 | static void au1xpsc_ac97_remove(struct platform_device *pdev, | ||
301 | struct snd_soc_dai *dai) | ||
302 | { | ||
303 | /* disable PSC completely */ | ||
304 | au_writel(0, AC97_CFG(au1xpsc_ac97_workdata)); | ||
305 | au_sync(); | ||
306 | au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_ac97_workdata)); | ||
307 | au_sync(); | ||
308 | |||
309 | iounmap(au1xpsc_ac97_workdata->mmio); | ||
310 | release_resource(au1xpsc_ac97_workdata->ioarea); | ||
311 | kfree(au1xpsc_ac97_workdata->ioarea); | ||
312 | kfree(au1xpsc_ac97_workdata); | ||
313 | au1xpsc_ac97_workdata = NULL; | ||
314 | } | ||
315 | |||
316 | static int au1xpsc_ac97_suspend(struct platform_device *pdev, | ||
317 | struct snd_soc_dai *dai) | ||
318 | { | ||
319 | /* save interesting registers and disable PSC */ | ||
320 | au1xpsc_ac97_workdata->pm[0] = | ||
321 | au_readl(PSC_SEL(au1xpsc_ac97_workdata)); | ||
322 | |||
323 | au_writel(0, AC97_CFG(au1xpsc_ac97_workdata)); | ||
324 | au_sync(); | ||
325 | au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_ac97_workdata)); | ||
326 | au_sync(); | ||
327 | |||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | static int au1xpsc_ac97_resume(struct platform_device *pdev, | ||
332 | struct snd_soc_dai *dai) | ||
333 | { | ||
334 | /* restore PSC clock config */ | ||
335 | au_writel(au1xpsc_ac97_workdata->pm[0] | PSC_SEL_PS_AC97MODE, | ||
336 | PSC_SEL(au1xpsc_ac97_workdata)); | ||
337 | au_sync(); | ||
338 | |||
339 | /* after this point the ac97 core will cold-reset the codec. | ||
340 | * During cold-reset the PSC is reinitialized and the last | ||
341 | * configuration set up in hw_params() is restored. | ||
342 | */ | ||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | struct snd_soc_dai au1xpsc_ac97_dai = { | ||
347 | .name = "au1xpsc_ac97", | ||
348 | .type = SND_SOC_DAI_AC97, | ||
349 | .probe = au1xpsc_ac97_probe, | ||
350 | .remove = au1xpsc_ac97_remove, | ||
351 | .suspend = au1xpsc_ac97_suspend, | ||
352 | .resume = au1xpsc_ac97_resume, | ||
353 | .playback = { | ||
354 | .rates = AC97_RATES, | ||
355 | .formats = AC97_FMTS, | ||
356 | .channels_min = 2, | ||
357 | .channels_max = 2, | ||
358 | }, | ||
359 | .capture = { | ||
360 | .rates = AC97_RATES, | ||
361 | .formats = AC97_FMTS, | ||
362 | .channels_min = 2, | ||
363 | .channels_max = 2, | ||
364 | }, | ||
365 | .ops = { | ||
366 | .trigger = au1xpsc_ac97_trigger, | ||
367 | .hw_params = au1xpsc_ac97_hw_params, | ||
368 | }, | ||
369 | }; | ||
370 | EXPORT_SYMBOL_GPL(au1xpsc_ac97_dai); | ||
371 | |||
372 | static int __init au1xpsc_ac97_init(void) | ||
373 | { | ||
374 | au1xpsc_ac97_workdata = NULL; | ||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | static void __exit au1xpsc_ac97_exit(void) | ||
379 | { | ||
380 | } | ||
381 | |||
382 | module_init(au1xpsc_ac97_init); | ||
383 | module_exit(au1xpsc_ac97_exit); | ||
384 | |||
385 | MODULE_LICENSE("GPL"); | ||
386 | MODULE_DESCRIPTION("Au12x0/Au1550 PSC AC97 ALSA ASoC audio driver"); | ||
387 | MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>"); | ||
diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c new file mode 100644 index 000000000000..ba4b5c199f21 --- /dev/null +++ b/sound/soc/au1x/psc-i2s.c | |||
@@ -0,0 +1,414 @@ | |||
1 | /* | ||
2 | * Au12x0/Au1550 PSC ALSA ASoC audio support. | ||
3 | * | ||
4 | * (c) 2007-2008 MSC Vertriebsges.m.b.H., | ||
5 | * Manuel Lauss <mano@roarinelk.homelinux.net> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * Au1xxx-PSC I2S glue. | ||
12 | * | ||
13 | * NOTE: all of these drivers can only work with a SINGLE instance | ||
14 | * of a PSC. Multiple independent audio devices are impossible | ||
15 | * with ASoC v1. | ||
16 | * NOTE: so far only PSC slave mode (bit- and frameclock) is supported. | ||
17 | */ | ||
18 | |||
19 | #include <linux/init.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/suspend.h> | ||
22 | #include <sound/core.h> | ||
23 | #include <sound/pcm.h> | ||
24 | #include <sound/initval.h> | ||
25 | #include <sound/soc.h> | ||
26 | #include <asm/mach-au1x00/au1000.h> | ||
27 | #include <asm/mach-au1x00/au1xxx_psc.h> | ||
28 | |||
29 | #include "psc.h" | ||
30 | |||
31 | /* supported I2S DAI hardware formats */ | ||
32 | #define AU1XPSC_I2S_DAIFMT \ | ||
33 | (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J | \ | ||
34 | SND_SOC_DAIFMT_NB_NF) | ||
35 | |||
36 | /* supported I2S direction */ | ||
37 | #define AU1XPSC_I2S_DIR \ | ||
38 | (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) | ||
39 | |||
40 | #define AU1XPSC_I2S_RATES \ | ||
41 | SNDRV_PCM_RATE_8000_192000 | ||
42 | |||
43 | #define AU1XPSC_I2S_FMTS \ | ||
44 | (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) | ||
45 | |||
46 | #define I2SSTAT_BUSY(stype) \ | ||
47 | ((stype) == PCM_TX ? PSC_I2SSTAT_TB : PSC_I2SSTAT_RB) | ||
48 | #define I2SPCR_START(stype) \ | ||
49 | ((stype) == PCM_TX ? PSC_I2SPCR_TS : PSC_I2SPCR_RS) | ||
50 | #define I2SPCR_STOP(stype) \ | ||
51 | ((stype) == PCM_TX ? PSC_I2SPCR_TP : PSC_I2SPCR_RP) | ||
52 | #define I2SPCR_CLRFIFO(stype) \ | ||
53 | ((stype) == PCM_TX ? PSC_I2SPCR_TC : PSC_I2SPCR_RC) | ||
54 | |||
55 | |||
56 | /* instance data. There can be only one, MacLeod!!!! */ | ||
57 | static struct au1xpsc_audio_data *au1xpsc_i2s_workdata; | ||
58 | |||
59 | static int au1xpsc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, | ||
60 | unsigned int fmt) | ||
61 | { | ||
62 | struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata; | ||
63 | unsigned long ct; | ||
64 | int ret; | ||
65 | |||
66 | ret = -EINVAL; | ||
67 | |||
68 | ct = pscdata->cfg; | ||
69 | |||
70 | ct &= ~(PSC_I2SCFG_XM | PSC_I2SCFG_MLJ); /* left-justified */ | ||
71 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
72 | case SND_SOC_DAIFMT_I2S: | ||
73 | ct |= PSC_I2SCFG_XM; /* enable I2S mode */ | ||
74 | break; | ||
75 | case SND_SOC_DAIFMT_MSB: | ||
76 | break; | ||
77 | case SND_SOC_DAIFMT_LSB: | ||
78 | ct |= PSC_I2SCFG_MLJ; /* LSB (right-) justified */ | ||
79 | break; | ||
80 | default: | ||
81 | goto out; | ||
82 | } | ||
83 | |||
84 | ct &= ~(PSC_I2SCFG_BI | PSC_I2SCFG_WI); /* IB-IF */ | ||
85 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
86 | case SND_SOC_DAIFMT_NB_NF: | ||
87 | ct |= PSC_I2SCFG_BI | PSC_I2SCFG_WI; | ||
88 | break; | ||
89 | case SND_SOC_DAIFMT_NB_IF: | ||
90 | ct |= PSC_I2SCFG_BI; | ||
91 | break; | ||
92 | case SND_SOC_DAIFMT_IB_NF: | ||
93 | ct |= PSC_I2SCFG_WI; | ||
94 | break; | ||
95 | case SND_SOC_DAIFMT_IB_IF: | ||
96 | break; | ||
97 | default: | ||
98 | goto out; | ||
99 | } | ||
100 | |||
101 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
102 | case SND_SOC_DAIFMT_CBM_CFM: /* CODEC master */ | ||
103 | ct |= PSC_I2SCFG_MS; /* PSC I2S slave mode */ | ||
104 | break; | ||
105 | case SND_SOC_DAIFMT_CBS_CFS: /* CODEC slave */ | ||
106 | ct &= ~PSC_I2SCFG_MS; /* PSC I2S Master mode */ | ||
107 | break; | ||
108 | default: | ||
109 | goto out; | ||
110 | } | ||
111 | |||
112 | pscdata->cfg = ct; | ||
113 | ret = 0; | ||
114 | out: | ||
115 | return ret; | ||
116 | } | ||
117 | |||
118 | static int au1xpsc_i2s_hw_params(struct snd_pcm_substream *substream, | ||
119 | struct snd_pcm_hw_params *params) | ||
120 | { | ||
121 | struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata; | ||
122 | |||
123 | int cfgbits; | ||
124 | unsigned long stat; | ||
125 | |||
126 | /* check if the PSC is already streaming data */ | ||
127 | stat = au_readl(I2S_STAT(pscdata)); | ||
128 | if (stat & (PSC_I2SSTAT_TB | PSC_I2SSTAT_RB)) { | ||
129 | /* reject parameters not currently set up in hardware */ | ||
130 | cfgbits = au_readl(I2S_CFG(pscdata)); | ||
131 | if ((PSC_I2SCFG_GET_LEN(cfgbits) != params->msbits) || | ||
132 | (params_rate(params) != pscdata->rate)) | ||
133 | return -EINVAL; | ||
134 | } else { | ||
135 | /* set sample bitdepth */ | ||
136 | pscdata->cfg &= ~(0x1f << 4); | ||
137 | pscdata->cfg |= PSC_I2SCFG_SET_LEN(params->msbits); | ||
138 | /* remember current rate for other stream */ | ||
139 | pscdata->rate = params_rate(params); | ||
140 | } | ||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | /* Configure PSC late: on my devel systems the codec is I2S master and | ||
145 | * supplies the i2sbitclock __AND__ i2sMclk (!) to the PSC unit. ASoC | ||
146 | * uses aggressive PM and switches the codec off when it is not in use | ||
147 | * which also means the PSC unit doesn't get any clocks and is therefore | ||
148 | * dead. That's why this chunk here gets called from the trigger callback | ||
149 | * because I can be reasonably certain the codec is driving the clocks. | ||
150 | */ | ||
151 | static int au1xpsc_i2s_configure(struct au1xpsc_audio_data *pscdata) | ||
152 | { | ||
153 | unsigned long tmo; | ||
154 | |||
155 | /* bring PSC out of sleep, and configure I2S unit */ | ||
156 | au_writel(PSC_CTRL_ENABLE, PSC_CTRL(pscdata)); | ||
157 | au_sync(); | ||
158 | |||
159 | tmo = 1000000; | ||
160 | while (!(au_readl(I2S_STAT(pscdata)) & PSC_I2SSTAT_SR) && tmo) | ||
161 | tmo--; | ||
162 | |||
163 | if (!tmo) | ||
164 | goto psc_err; | ||
165 | |||
166 | au_writel(0, I2S_CFG(pscdata)); | ||
167 | au_sync(); | ||
168 | au_writel(pscdata->cfg | PSC_I2SCFG_DE_ENABLE, I2S_CFG(pscdata)); | ||
169 | au_sync(); | ||
170 | |||
171 | /* wait for I2S controller to become ready */ | ||
172 | tmo = 1000000; | ||
173 | while (!(au_readl(I2S_STAT(pscdata)) & PSC_I2SSTAT_DR) && tmo) | ||
174 | tmo--; | ||
175 | |||
176 | if (tmo) | ||
177 | return 0; | ||
178 | |||
179 | psc_err: | ||
180 | au_writel(0, I2S_CFG(pscdata)); | ||
181 | au_writel(PSC_CTRL_SUSPEND, PSC_CTRL(pscdata)); | ||
182 | au_sync(); | ||
183 | return -ETIMEDOUT; | ||
184 | } | ||
185 | |||
186 | static int au1xpsc_i2s_start(struct au1xpsc_audio_data *pscdata, int stype) | ||
187 | { | ||
188 | unsigned long tmo, stat; | ||
189 | int ret; | ||
190 | |||
191 | ret = 0; | ||
192 | |||
193 | /* if both TX and RX are idle, configure the PSC */ | ||
194 | stat = au_readl(I2S_STAT(pscdata)); | ||
195 | if (!(stat & (PSC_I2SSTAT_TB | PSC_I2SSTAT_RB))) { | ||
196 | ret = au1xpsc_i2s_configure(pscdata); | ||
197 | if (ret) | ||
198 | goto out; | ||
199 | } | ||
200 | |||
201 | au_writel(I2SPCR_CLRFIFO(stype), I2S_PCR(pscdata)); | ||
202 | au_sync(); | ||
203 | au_writel(I2SPCR_START(stype), I2S_PCR(pscdata)); | ||
204 | au_sync(); | ||
205 | |||
206 | /* wait for start confirmation */ | ||
207 | tmo = 1000000; | ||
208 | while (!(au_readl(I2S_STAT(pscdata)) & I2SSTAT_BUSY(stype)) && tmo) | ||
209 | tmo--; | ||
210 | |||
211 | if (!tmo) { | ||
212 | au_writel(I2SPCR_STOP(stype), I2S_PCR(pscdata)); | ||
213 | au_sync(); | ||
214 | ret = -ETIMEDOUT; | ||
215 | } | ||
216 | out: | ||
217 | return ret; | ||
218 | } | ||
219 | |||
220 | static int au1xpsc_i2s_stop(struct au1xpsc_audio_data *pscdata, int stype) | ||
221 | { | ||
222 | unsigned long tmo, stat; | ||
223 | |||
224 | au_writel(I2SPCR_STOP(stype), I2S_PCR(pscdata)); | ||
225 | au_sync(); | ||
226 | |||
227 | /* wait for stop confirmation */ | ||
228 | tmo = 1000000; | ||
229 | while ((au_readl(I2S_STAT(pscdata)) & I2SSTAT_BUSY(stype)) && tmo) | ||
230 | tmo--; | ||
231 | |||
232 | /* if both TX and RX are idle, disable PSC */ | ||
233 | stat = au_readl(I2S_STAT(pscdata)); | ||
234 | if (!(stat & (PSC_I2SSTAT_RB | PSC_I2SSTAT_RB))) { | ||
235 | au_writel(0, I2S_CFG(pscdata)); | ||
236 | au_sync(); | ||
237 | au_writel(PSC_CTRL_SUSPEND, PSC_CTRL(pscdata)); | ||
238 | au_sync(); | ||
239 | } | ||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd) | ||
244 | { | ||
245 | struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata; | ||
246 | int ret, stype = SUBSTREAM_TYPE(substream); | ||
247 | |||
248 | switch (cmd) { | ||
249 | case SNDRV_PCM_TRIGGER_START: | ||
250 | case SNDRV_PCM_TRIGGER_RESUME: | ||
251 | ret = au1xpsc_i2s_start(pscdata, stype); | ||
252 | break; | ||
253 | case SNDRV_PCM_TRIGGER_STOP: | ||
254 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
255 | ret = au1xpsc_i2s_stop(pscdata, stype); | ||
256 | break; | ||
257 | default: | ||
258 | ret = -EINVAL; | ||
259 | } | ||
260 | return ret; | ||
261 | } | ||
262 | |||
263 | static int au1xpsc_i2s_probe(struct platform_device *pdev, | ||
264 | struct snd_soc_dai *dai) | ||
265 | { | ||
266 | struct resource *r; | ||
267 | unsigned long sel; | ||
268 | int ret; | ||
269 | |||
270 | if (au1xpsc_i2s_workdata) | ||
271 | return -EBUSY; | ||
272 | |||
273 | au1xpsc_i2s_workdata = | ||
274 | kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL); | ||
275 | if (!au1xpsc_i2s_workdata) | ||
276 | return -ENOMEM; | ||
277 | |||
278 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
279 | if (!r) { | ||
280 | ret = -ENODEV; | ||
281 | goto out0; | ||
282 | } | ||
283 | |||
284 | ret = -EBUSY; | ||
285 | au1xpsc_i2s_workdata->ioarea = | ||
286 | request_mem_region(r->start, r->end - r->start + 1, | ||
287 | "au1xpsc_i2s"); | ||
288 | if (!au1xpsc_i2s_workdata->ioarea) | ||
289 | goto out0; | ||
290 | |||
291 | au1xpsc_i2s_workdata->mmio = ioremap(r->start, 0xffff); | ||
292 | if (!au1xpsc_i2s_workdata->mmio) | ||
293 | goto out1; | ||
294 | |||
295 | /* preserve PSC clock source set up by platform (dev.platform_data | ||
296 | * is already occupied by soc layer) | ||
297 | */ | ||
298 | sel = au_readl(PSC_SEL(au1xpsc_i2s_workdata)) & PSC_SEL_CLK_MASK; | ||
299 | au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata)); | ||
300 | au_sync(); | ||
301 | au_writel(PSC_SEL_PS_I2SMODE | sel, PSC_SEL(au1xpsc_i2s_workdata)); | ||
302 | au_writel(0, I2S_CFG(au1xpsc_i2s_workdata)); | ||
303 | au_sync(); | ||
304 | |||
305 | /* preconfigure: set max rx/tx fifo depths */ | ||
306 | au1xpsc_i2s_workdata->cfg |= | ||
307 | PSC_I2SCFG_RT_FIFO8 | PSC_I2SCFG_TT_FIFO8; | ||
308 | |||
309 | /* don't wait for I2S core to become ready now; clocks may not | ||
310 | * be running yet; depending on clock input for PSC a wait might | ||
311 | * time out. | ||
312 | */ | ||
313 | |||
314 | return 0; | ||
315 | |||
316 | out1: | ||
317 | release_resource(au1xpsc_i2s_workdata->ioarea); | ||
318 | kfree(au1xpsc_i2s_workdata->ioarea); | ||
319 | out0: | ||
320 | kfree(au1xpsc_i2s_workdata); | ||
321 | au1xpsc_i2s_workdata = NULL; | ||
322 | return ret; | ||
323 | } | ||
324 | |||
325 | static void au1xpsc_i2s_remove(struct platform_device *pdev, | ||
326 | struct snd_soc_dai *dai) | ||
327 | { | ||
328 | au_writel(0, I2S_CFG(au1xpsc_i2s_workdata)); | ||
329 | au_sync(); | ||
330 | au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata)); | ||
331 | au_sync(); | ||
332 | |||
333 | iounmap(au1xpsc_i2s_workdata->mmio); | ||
334 | release_resource(au1xpsc_i2s_workdata->ioarea); | ||
335 | kfree(au1xpsc_i2s_workdata->ioarea); | ||
336 | kfree(au1xpsc_i2s_workdata); | ||
337 | au1xpsc_i2s_workdata = NULL; | ||
338 | } | ||
339 | |||
340 | static int au1xpsc_i2s_suspend(struct platform_device *pdev, | ||
341 | struct snd_soc_dai *cpu_dai) | ||
342 | { | ||
343 | /* save interesting register and disable PSC */ | ||
344 | au1xpsc_i2s_workdata->pm[0] = | ||
345 | au_readl(PSC_SEL(au1xpsc_i2s_workdata)); | ||
346 | |||
347 | au_writel(0, I2S_CFG(au1xpsc_i2s_workdata)); | ||
348 | au_sync(); | ||
349 | au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata)); | ||
350 | au_sync(); | ||
351 | |||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | static int au1xpsc_i2s_resume(struct platform_device *pdev, | ||
356 | struct snd_soc_dai *cpu_dai) | ||
357 | { | ||
358 | /* select I2S mode and PSC clock */ | ||
359 | au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata)); | ||
360 | au_sync(); | ||
361 | au_writel(0, PSC_SEL(au1xpsc_i2s_workdata)); | ||
362 | au_sync(); | ||
363 | au_writel(au1xpsc_i2s_workdata->pm[0], | ||
364 | PSC_SEL(au1xpsc_i2s_workdata)); | ||
365 | au_sync(); | ||
366 | |||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | struct snd_soc_dai au1xpsc_i2s_dai = { | ||
371 | .name = "au1xpsc_i2s", | ||
372 | .type = SND_SOC_DAI_I2S, | ||
373 | .probe = au1xpsc_i2s_probe, | ||
374 | .remove = au1xpsc_i2s_remove, | ||
375 | .suspend = au1xpsc_i2s_suspend, | ||
376 | .resume = au1xpsc_i2s_resume, | ||
377 | .playback = { | ||
378 | .rates = AU1XPSC_I2S_RATES, | ||
379 | .formats = AU1XPSC_I2S_FMTS, | ||
380 | .channels_min = 2, | ||
381 | .channels_max = 8, /* 2 without external help */ | ||
382 | }, | ||
383 | .capture = { | ||
384 | .rates = AU1XPSC_I2S_RATES, | ||
385 | .formats = AU1XPSC_I2S_FMTS, | ||
386 | .channels_min = 2, | ||
387 | .channels_max = 8, /* 2 without external help */ | ||
388 | }, | ||
389 | .ops = { | ||
390 | .trigger = au1xpsc_i2s_trigger, | ||
391 | .hw_params = au1xpsc_i2s_hw_params, | ||
392 | }, | ||
393 | .dai_ops = { | ||
394 | .set_fmt = au1xpsc_i2s_set_fmt, | ||
395 | }, | ||
396 | }; | ||
397 | EXPORT_SYMBOL(au1xpsc_i2s_dai); | ||
398 | |||
399 | static int __init au1xpsc_i2s_init(void) | ||
400 | { | ||
401 | au1xpsc_i2s_workdata = NULL; | ||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | static void __exit au1xpsc_i2s_exit(void) | ||
406 | { | ||
407 | } | ||
408 | |||
409 | module_init(au1xpsc_i2s_init); | ||
410 | module_exit(au1xpsc_i2s_exit); | ||
411 | |||
412 | MODULE_LICENSE("GPL"); | ||
413 | MODULE_DESCRIPTION("Au12x0/Au1550 PSC I2S ALSA ASoC audio driver"); | ||
414 | MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>"); | ||
diff --git a/sound/soc/au1x/psc.h b/sound/soc/au1x/psc.h new file mode 100644 index 000000000000..8fdb1a04a07b --- /dev/null +++ b/sound/soc/au1x/psc.h | |||
@@ -0,0 +1,53 @@ | |||
1 | /* | ||
2 | * Au12x0/Au1550 PSC ALSA ASoC audio support. | ||
3 | * | ||
4 | * (c) 2007-2008 MSC Vertriebsges.m.b.H., | ||
5 | * Manuel Lauss <mano@roarinelk.homelinux.net> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * NOTE: all of these drivers can only work with a SINGLE instance | ||
12 | * of a PSC. Multiple independent audio devices are impossible | ||
13 | * with ASoC v1. | ||
14 | */ | ||
15 | |||
16 | #ifndef _AU1X_PCM_H | ||
17 | #define _AU1X_PCM_H | ||
18 | |||
19 | extern struct snd_soc_dai au1xpsc_ac97_dai; | ||
20 | extern struct snd_soc_dai au1xpsc_i2s_dai; | ||
21 | extern struct snd_soc_platform au1xpsc_soc_platform; | ||
22 | extern struct snd_ac97_bus_ops soc_ac97_ops; | ||
23 | |||
24 | struct au1xpsc_audio_data { | ||
25 | void __iomem *mmio; | ||
26 | |||
27 | unsigned long cfg; | ||
28 | unsigned long rate; | ||
29 | |||
30 | unsigned long pm[2]; | ||
31 | struct resource *ioarea; | ||
32 | }; | ||
33 | |||
34 | #define PCM_TX 0 | ||
35 | #define PCM_RX 1 | ||
36 | |||
37 | #define SUBSTREAM_TYPE(substream) \ | ||
38 | ((substream)->stream == SNDRV_PCM_STREAM_PLAYBACK ? PCM_TX : PCM_RX) | ||
39 | |||
40 | /* easy access macros */ | ||
41 | #define PSC_CTRL(x) ((unsigned long)((x)->mmio) + PSC_CTRL_OFFSET) | ||
42 | #define PSC_SEL(x) ((unsigned long)((x)->mmio) + PSC_SEL_OFFSET) | ||
43 | #define I2S_STAT(x) ((unsigned long)((x)->mmio) + PSC_I2SSTAT_OFFSET) | ||
44 | #define I2S_CFG(x) ((unsigned long)((x)->mmio) + PSC_I2SCFG_OFFSET) | ||
45 | #define I2S_PCR(x) ((unsigned long)((x)->mmio) + PSC_I2SPCR_OFFSET) | ||
46 | #define AC97_CFG(x) ((unsigned long)((x)->mmio) + PSC_AC97CFG_OFFSET) | ||
47 | #define AC97_CDC(x) ((unsigned long)((x)->mmio) + PSC_AC97CDC_OFFSET) | ||
48 | #define AC97_EVNT(x) ((unsigned long)((x)->mmio) + PSC_AC97EVNT_OFFSET) | ||
49 | #define AC97_PCR(x) ((unsigned long)((x)->mmio) + PSC_AC97PCR_OFFSET) | ||
50 | #define AC97_RST(x) ((unsigned long)((x)->mmio) + PSC_AC97RST_OFFSET) | ||
51 | #define AC97_STAT(x) ((unsigned long)((x)->mmio) + PSC_AC97STAT_OFFSET) | ||
52 | |||
53 | #endif | ||
diff --git a/sound/soc/au1x/sample-ac97.c b/sound/soc/au1x/sample-ac97.c new file mode 100644 index 000000000000..f75ae7f62c3d --- /dev/null +++ b/sound/soc/au1x/sample-ac97.c | |||
@@ -0,0 +1,144 @@ | |||
1 | /* | ||
2 | * Sample Au12x0/Au1550 PSC AC97 sound machine. | ||
3 | * | ||
4 | * Copyright (c) 2007-2008 Manuel Lauss <mano@roarinelk.homelinux.net> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms outlined in the file COPYING at the root of this | ||
8 | * source archive. | ||
9 | * | ||
10 | * This is a very generic AC97 sound machine driver for boards which | ||
11 | * have (AC97) audio at PSC1 (e.g. DB1200 demoboards). | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/moduleparam.h> | ||
16 | #include <linux/timer.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <sound/core.h> | ||
20 | #include <sound/pcm.h> | ||
21 | #include <sound/soc.h> | ||
22 | #include <sound/soc-dapm.h> | ||
23 | #include <asm/mach-au1x00/au1000.h> | ||
24 | #include <asm/mach-au1x00/au1xxx_psc.h> | ||
25 | #include <asm/mach-au1x00/au1xxx_dbdma.h> | ||
26 | |||
27 | #include "../codecs/ac97.h" | ||
28 | #include "psc.h" | ||
29 | |||
30 | static int au1xpsc_sample_ac97_init(struct snd_soc_codec *codec) | ||
31 | { | ||
32 | snd_soc_dapm_sync(codec); | ||
33 | return 0; | ||
34 | } | ||
35 | |||
36 | static struct snd_soc_dai_link au1xpsc_sample_ac97_dai = { | ||
37 | .name = "AC97", | ||
38 | .stream_name = "AC97 HiFi", | ||
39 | .cpu_dai = &au1xpsc_ac97_dai, /* see psc-ac97.c */ | ||
40 | .codec_dai = &ac97_dai, /* see codecs/ac97.c */ | ||
41 | .init = au1xpsc_sample_ac97_init, | ||
42 | .ops = NULL, | ||
43 | }; | ||
44 | |||
45 | static struct snd_soc_machine au1xpsc_sample_ac97_machine = { | ||
46 | .name = "Au1xxx PSC AC97 Audio", | ||
47 | .dai_link = &au1xpsc_sample_ac97_dai, | ||
48 | .num_links = 1, | ||
49 | }; | ||
50 | |||
51 | static struct snd_soc_device au1xpsc_sample_ac97_devdata = { | ||
52 | .machine = &au1xpsc_sample_ac97_machine, | ||
53 | .platform = &au1xpsc_soc_platform, /* see dbdma2.c */ | ||
54 | .codec_dev = &soc_codec_dev_ac97, | ||
55 | }; | ||
56 | |||
57 | static struct resource au1xpsc_psc1_res[] = { | ||
58 | [0] = { | ||
59 | .start = CPHYSADDR(PSC1_BASE_ADDR), | ||
60 | .end = CPHYSADDR(PSC1_BASE_ADDR) + 0x000fffff, | ||
61 | .flags = IORESOURCE_MEM, | ||
62 | }, | ||
63 | [1] = { | ||
64 | #ifdef CONFIG_SOC_AU1200 | ||
65 | .start = AU1200_PSC1_INT, | ||
66 | .end = AU1200_PSC1_INT, | ||
67 | #elif defined(CONFIG_SOC_AU1550) | ||
68 | .start = AU1550_PSC1_INT, | ||
69 | .end = AU1550_PSC1_INT, | ||
70 | #endif | ||
71 | .flags = IORESOURCE_IRQ, | ||
72 | }, | ||
73 | [2] = { | ||
74 | .start = DSCR_CMD0_PSC1_TX, | ||
75 | .end = DSCR_CMD0_PSC1_TX, | ||
76 | .flags = IORESOURCE_DMA, | ||
77 | }, | ||
78 | [3] = { | ||
79 | .start = DSCR_CMD0_PSC1_RX, | ||
80 | .end = DSCR_CMD0_PSC1_RX, | ||
81 | .flags = IORESOURCE_DMA, | ||
82 | }, | ||
83 | }; | ||
84 | |||
85 | static struct platform_device *au1xpsc_sample_ac97_dev; | ||
86 | |||
87 | static int __init au1xpsc_sample_ac97_load(void) | ||
88 | { | ||
89 | int ret; | ||
90 | |||
91 | #ifdef CONFIG_SOC_AU1200 | ||
92 | unsigned long io; | ||
93 | |||
94 | /* modify sys_pinfunc for AC97 on PSC1 */ | ||
95 | io = au_readl(SYS_PINFUNC); | ||
96 | io |= SYS_PINFUNC_P1C; | ||
97 | io &= ~(SYS_PINFUNC_P1A | SYS_PINFUNC_P1B); | ||
98 | au_writel(io, SYS_PINFUNC); | ||
99 | au_sync(); | ||
100 | #endif | ||
101 | |||
102 | ret = -ENOMEM; | ||
103 | |||
104 | /* setup PSC clock source for AC97 part: external clock provided | ||
105 | * by codec. The psc-ac97.c driver depends on this setting! | ||
106 | */ | ||
107 | au_writel(PSC_SEL_CLK_SERCLK, PSC1_BASE_ADDR + PSC_SEL_OFFSET); | ||
108 | au_sync(); | ||
109 | |||
110 | au1xpsc_sample_ac97_dev = platform_device_alloc("soc-audio", -1); | ||
111 | if (!au1xpsc_sample_ac97_dev) | ||
112 | goto out; | ||
113 | |||
114 | au1xpsc_sample_ac97_dev->resource = | ||
115 | kmemdup(au1xpsc_psc1_res, sizeof(struct resource) * | ||
116 | ARRAY_SIZE(au1xpsc_psc1_res), GFP_KERNEL); | ||
117 | au1xpsc_sample_ac97_dev->num_resources = ARRAY_SIZE(au1xpsc_psc1_res); | ||
118 | au1xpsc_sample_ac97_dev->id = 1; | ||
119 | |||
120 | platform_set_drvdata(au1xpsc_sample_ac97_dev, | ||
121 | &au1xpsc_sample_ac97_devdata); | ||
122 | au1xpsc_sample_ac97_devdata.dev = &au1xpsc_sample_ac97_dev->dev; | ||
123 | ret = platform_device_add(au1xpsc_sample_ac97_dev); | ||
124 | |||
125 | if (ret) { | ||
126 | platform_device_put(au1xpsc_sample_ac97_dev); | ||
127 | au1xpsc_sample_ac97_dev = NULL; | ||
128 | } | ||
129 | |||
130 | out: | ||
131 | return ret; | ||
132 | } | ||
133 | |||
134 | static void __exit au1xpsc_sample_ac97_exit(void) | ||
135 | { | ||
136 | platform_device_unregister(au1xpsc_sample_ac97_dev); | ||
137 | } | ||
138 | |||
139 | module_init(au1xpsc_sample_ac97_load); | ||
140 | module_exit(au1xpsc_sample_ac97_exit); | ||
141 | |||
142 | MODULE_LICENSE("GPL"); | ||
143 | MODULE_DESCRIPTION("Au1xxx PSC sample AC97 machine"); | ||
144 | MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>"); | ||
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 3903ab7dfa4a..1db04a28a53d 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -1,31 +1,37 @@ | |||
1 | config SND_SOC_AC97_CODEC | 1 | config SND_SOC_AC97_CODEC |
2 | tristate | 2 | tristate |
3 | depends on SND_SOC | 3 | select SND_AC97_CODEC |
4 | |||
5 | config SND_SOC_AK4535 | ||
6 | tristate | ||
7 | |||
8 | config SND_SOC_UDA1380 | ||
9 | tristate | ||
10 | |||
11 | config SND_SOC_WM8510 | ||
12 | tristate | ||
4 | 13 | ||
5 | config SND_SOC_WM8731 | 14 | config SND_SOC_WM8731 |
6 | tristate | 15 | tristate |
7 | depends on SND_SOC | ||
8 | 16 | ||
9 | config SND_SOC_WM8750 | 17 | config SND_SOC_WM8750 |
10 | tristate | 18 | tristate |
11 | depends on SND_SOC | ||
12 | 19 | ||
13 | config SND_SOC_WM8753 | 20 | config SND_SOC_WM8753 |
14 | tristate | 21 | tristate |
15 | depends on SND_SOC | 22 | |
23 | config SND_SOC_WM8990 | ||
24 | tristate | ||
16 | 25 | ||
17 | config SND_SOC_WM9712 | 26 | config SND_SOC_WM9712 |
18 | tristate | 27 | tristate |
19 | depends on SND_SOC | ||
20 | 28 | ||
21 | config SND_SOC_WM9713 | 29 | config SND_SOC_WM9713 |
22 | tristate | 30 | tristate |
23 | depends on SND_SOC | ||
24 | 31 | ||
25 | # Cirrus Logic CS4270 Codec | 32 | # Cirrus Logic CS4270 Codec |
26 | config SND_SOC_CS4270 | 33 | config SND_SOC_CS4270 |
27 | tristate | 34 | tristate |
28 | depends on SND_SOC | ||
29 | 35 | ||
30 | # Cirrus Logic CS4270 Codec Hardware Mute Support | 36 | # Cirrus Logic CS4270 Codec Hardware Mute Support |
31 | # Select if you have external muting circuitry attached to your CS4270. | 37 | # Select if you have external muting circuitry attached to your CS4270. |
@@ -43,4 +49,4 @@ config SND_SOC_CS4270_VD33_ERRATA | |||
43 | 49 | ||
44 | config SND_SOC_TLV320AIC3X | 50 | config SND_SOC_TLV320AIC3X |
45 | tristate | 51 | tristate |
46 | depends on SND_SOC && I2C | 52 | depends on I2C |
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 4e1314c9d3ec..d7b97abcf729 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -1,16 +1,24 @@ | |||
1 | snd-soc-ac97-objs := ac97.o | 1 | snd-soc-ac97-objs := ac97.o |
2 | snd-soc-ak4535-objs := ak4535.o | ||
3 | snd-soc-uda1380-objs := uda1380.o | ||
4 | snd-soc-wm8510-objs := wm8510.o | ||
2 | snd-soc-wm8731-objs := wm8731.o | 5 | snd-soc-wm8731-objs := wm8731.o |
3 | snd-soc-wm8750-objs := wm8750.o | 6 | snd-soc-wm8750-objs := wm8750.o |
4 | snd-soc-wm8753-objs := wm8753.o | 7 | snd-soc-wm8753-objs := wm8753.o |
8 | snd-soc-wm8990-objs := wm8990.o | ||
5 | snd-soc-wm9712-objs := wm9712.o | 9 | snd-soc-wm9712-objs := wm9712.o |
6 | snd-soc-wm9713-objs := wm9713.o | 10 | snd-soc-wm9713-objs := wm9713.o |
7 | snd-soc-cs4270-objs := cs4270.o | 11 | snd-soc-cs4270-objs := cs4270.o |
8 | snd-soc-tlv320aic3x-objs := tlv320aic3x.o | 12 | snd-soc-tlv320aic3x-objs := tlv320aic3x.o |
9 | 13 | ||
10 | obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o | 14 | obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o |
15 | obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o | ||
16 | obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o | ||
17 | obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o | ||
11 | obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o | 18 | obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o |
12 | obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o | 19 | obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o |
13 | obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o | 20 | obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o |
21 | obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o | ||
14 | obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o | 22 | obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o |
15 | obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o | 23 | obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o |
16 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o | 24 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o |
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index 2a1ffe396908..61fd96ca7bc7 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c | |||
@@ -10,9 +10,6 @@ | |||
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 | * Revision history | ||
14 | * 17th Oct 2005 Initial version. | ||
15 | * | ||
16 | * Generic AC97 support. | 13 | * Generic AC97 support. |
17 | */ | 14 | */ |
18 | 15 | ||
@@ -24,6 +21,7 @@ | |||
24 | #include <sound/ac97_codec.h> | 21 | #include <sound/ac97_codec.h> |
25 | #include <sound/initval.h> | 22 | #include <sound/initval.h> |
26 | #include <sound/soc.h> | 23 | #include <sound/soc.h> |
24 | #include "ac97.h" | ||
27 | 25 | ||
28 | #define AC97_VERSION "0.6" | 26 | #define AC97_VERSION "0.6" |
29 | 27 | ||
@@ -43,7 +41,7 @@ static int ac97_prepare(struct snd_pcm_substream *substream) | |||
43 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\ | 41 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\ |
44 | SNDRV_PCM_RATE_48000) | 42 | SNDRV_PCM_RATE_48000) |
45 | 43 | ||
46 | struct snd_soc_codec_dai ac97_dai = { | 44 | struct snd_soc_dai ac97_dai = { |
47 | .name = "AC97 HiFi", | 45 | .name = "AC97 HiFi", |
48 | .type = SND_SOC_DAI_AC97, | 46 | .type = SND_SOC_DAI_AC97, |
49 | .playback = { | 47 | .playback = { |
@@ -146,9 +144,34 @@ static int ac97_soc_remove(struct platform_device *pdev) | |||
146 | return 0; | 144 | return 0; |
147 | } | 145 | } |
148 | 146 | ||
147 | #ifdef CONFIG_PM | ||
148 | static int ac97_soc_suspend(struct platform_device *pdev, pm_message_t msg) | ||
149 | { | ||
150 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
151 | |||
152 | snd_ac97_suspend(socdev->codec->ac97); | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | static int ac97_soc_resume(struct platform_device *pdev) | ||
158 | { | ||
159 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
160 | |||
161 | snd_ac97_resume(socdev->codec->ac97); | ||
162 | |||
163 | return 0; | ||
164 | } | ||
165 | #else | ||
166 | #define ac97_soc_suspend NULL | ||
167 | #define ac97_soc_resume NULL | ||
168 | #endif | ||
169 | |||
149 | struct snd_soc_codec_device soc_codec_dev_ac97 = { | 170 | struct snd_soc_codec_device soc_codec_dev_ac97 = { |
150 | .probe = ac97_soc_probe, | 171 | .probe = ac97_soc_probe, |
151 | .remove = ac97_soc_remove, | 172 | .remove = ac97_soc_remove, |
173 | .suspend = ac97_soc_suspend, | ||
174 | .resume = ac97_soc_resume, | ||
152 | }; | 175 | }; |
153 | EXPORT_SYMBOL_GPL(soc_codec_dev_ac97); | 176 | EXPORT_SYMBOL_GPL(soc_codec_dev_ac97); |
154 | 177 | ||
diff --git a/sound/soc/codecs/ac97.h b/sound/soc/codecs/ac97.h index 2bf6d69fd069..281aa42e2bbb 100644 --- a/sound/soc/codecs/ac97.h +++ b/sound/soc/codecs/ac97.h | |||
@@ -14,6 +14,6 @@ | |||
14 | #define __LINUX_SND_SOC_AC97_H | 14 | #define __LINUX_SND_SOC_AC97_H |
15 | 15 | ||
16 | extern struct snd_soc_codec_device soc_codec_dev_ac97; | 16 | extern struct snd_soc_codec_device soc_codec_dev_ac97; |
17 | extern struct snd_soc_codec_dai ac97_dai; | 17 | extern struct snd_soc_dai ac97_dai; |
18 | 18 | ||
19 | #endif | 19 | #endif |
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c new file mode 100644 index 000000000000..b26003c4f3e8 --- /dev/null +++ b/sound/soc/codecs/ak4535.c | |||
@@ -0,0 +1,696 @@ | |||
1 | /* | ||
2 | * ak4535.c -- AK4535 ALSA Soc Audio driver | ||
3 | * | ||
4 | * Copyright 2005 Openedhand Ltd. | ||
5 | * | ||
6 | * Author: Richard Purdie <richard@openedhand.com> | ||
7 | * | ||
8 | * Based on wm8753.c by Liam Girdwood | ||
9 | * | ||
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 | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/moduleparam.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/pm.h> | ||
20 | #include <linux/i2c.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <sound/core.h> | ||
23 | #include <sound/pcm.h> | ||
24 | #include <sound/pcm_params.h> | ||
25 | #include <sound/soc.h> | ||
26 | #include <sound/soc-dapm.h> | ||
27 | #include <sound/initval.h> | ||
28 | |||
29 | #include "ak4535.h" | ||
30 | |||
31 | #define AUDIO_NAME "ak4535" | ||
32 | #define AK4535_VERSION "0.3" | ||
33 | |||
34 | struct snd_soc_codec_device soc_codec_dev_ak4535; | ||
35 | |||
36 | /* codec private data */ | ||
37 | struct ak4535_priv { | ||
38 | unsigned int sysclk; | ||
39 | }; | ||
40 | |||
41 | /* | ||
42 | * ak4535 register cache | ||
43 | */ | ||
44 | static const u16 ak4535_reg[AK4535_CACHEREGNUM] = { | ||
45 | 0x0000, 0x0080, 0x0000, 0x0003, | ||
46 | 0x0002, 0x0000, 0x0011, 0x0001, | ||
47 | 0x0000, 0x0040, 0x0036, 0x0010, | ||
48 | 0x0000, 0x0000, 0x0057, 0x0000, | ||
49 | }; | ||
50 | |||
51 | /* | ||
52 | * read ak4535 register cache | ||
53 | */ | ||
54 | static inline unsigned int ak4535_read_reg_cache(struct snd_soc_codec *codec, | ||
55 | unsigned int reg) | ||
56 | { | ||
57 | u16 *cache = codec->reg_cache; | ||
58 | if (reg >= AK4535_CACHEREGNUM) | ||
59 | return -1; | ||
60 | return cache[reg]; | ||
61 | } | ||
62 | |||
63 | static inline unsigned int ak4535_read(struct snd_soc_codec *codec, | ||
64 | unsigned int reg) | ||
65 | { | ||
66 | u8 data; | ||
67 | data = reg; | ||
68 | |||
69 | if (codec->hw_write(codec->control_data, &data, 1) != 1) | ||
70 | return -EIO; | ||
71 | |||
72 | if (codec->hw_read(codec->control_data, &data, 1) != 1) | ||
73 | return -EIO; | ||
74 | |||
75 | return data; | ||
76 | }; | ||
77 | |||
78 | /* | ||
79 | * write ak4535 register cache | ||
80 | */ | ||
81 | static inline void ak4535_write_reg_cache(struct snd_soc_codec *codec, | ||
82 | u16 reg, unsigned int value) | ||
83 | { | ||
84 | u16 *cache = codec->reg_cache; | ||
85 | if (reg >= AK4535_CACHEREGNUM) | ||
86 | return; | ||
87 | cache[reg] = value; | ||
88 | } | ||
89 | |||
90 | /* | ||
91 | * write to the AK4535 register space | ||
92 | */ | ||
93 | static int ak4535_write(struct snd_soc_codec *codec, unsigned int reg, | ||
94 | unsigned int value) | ||
95 | { | ||
96 | u8 data[2]; | ||
97 | |||
98 | /* data is | ||
99 | * D15..D8 AK4535 register offset | ||
100 | * D7...D0 register data | ||
101 | */ | ||
102 | data[0] = reg & 0xff; | ||
103 | data[1] = value & 0xff; | ||
104 | |||
105 | ak4535_write_reg_cache(codec, reg, value); | ||
106 | if (codec->hw_write(codec->control_data, data, 2) == 2) | ||
107 | return 0; | ||
108 | else | ||
109 | return -EIO; | ||
110 | } | ||
111 | |||
112 | static int ak4535_sync(struct snd_soc_codec *codec) | ||
113 | { | ||
114 | u16 *cache = codec->reg_cache; | ||
115 | int i, r = 0; | ||
116 | |||
117 | for (i = 0; i < AK4535_CACHEREGNUM; i++) | ||
118 | r |= ak4535_write(codec, i, cache[i]); | ||
119 | |||
120 | return r; | ||
121 | }; | ||
122 | |||
123 | static const char *ak4535_mono_gain[] = {"+6dB", "-17dB"}; | ||
124 | static const char *ak4535_mono_out[] = {"(L + R)/2", "Hi-Z"}; | ||
125 | static const char *ak4535_hp_out[] = {"Stereo", "Mono"}; | ||
126 | static const char *ak4535_deemp[] = {"44.1kHz", "Off", "48kHz", "32kHz"}; | ||
127 | static const char *ak4535_mic_select[] = {"Internal", "External"}; | ||
128 | |||
129 | static const struct soc_enum ak4535_enum[] = { | ||
130 | SOC_ENUM_SINGLE(AK4535_SIG1, 7, 2, ak4535_mono_gain), | ||
131 | SOC_ENUM_SINGLE(AK4535_SIG1, 6, 2, ak4535_mono_out), | ||
132 | SOC_ENUM_SINGLE(AK4535_MODE2, 2, 2, ak4535_hp_out), | ||
133 | SOC_ENUM_SINGLE(AK4535_DAC, 0, 4, ak4535_deemp), | ||
134 | SOC_ENUM_SINGLE(AK4535_MIC, 1, 2, ak4535_mic_select), | ||
135 | }; | ||
136 | |||
137 | static const struct snd_kcontrol_new ak4535_snd_controls[] = { | ||
138 | SOC_SINGLE("ALC2 Switch", AK4535_SIG1, 1, 1, 0), | ||
139 | SOC_ENUM("Mono 1 Output", ak4535_enum[1]), | ||
140 | SOC_ENUM("Mono 1 Gain", ak4535_enum[0]), | ||
141 | SOC_ENUM("Headphone Output", ak4535_enum[2]), | ||
142 | SOC_ENUM("Playback Deemphasis", ak4535_enum[3]), | ||
143 | SOC_SINGLE("Bass Volume", AK4535_DAC, 2, 3, 0), | ||
144 | SOC_SINGLE("Mic Boost (+20dB) Switch", AK4535_MIC, 0, 1, 0), | ||
145 | SOC_ENUM("Mic Select", ak4535_enum[4]), | ||
146 | SOC_SINGLE("ALC Operation Time", AK4535_TIMER, 0, 3, 0), | ||
147 | SOC_SINGLE("ALC Recovery Time", AK4535_TIMER, 2, 3, 0), | ||
148 | SOC_SINGLE("ALC ZC Time", AK4535_TIMER, 4, 3, 0), | ||
149 | SOC_SINGLE("ALC 1 Switch", AK4535_ALC1, 5, 1, 0), | ||
150 | SOC_SINGLE("ALC 2 Switch", AK4535_ALC1, 6, 1, 0), | ||
151 | SOC_SINGLE("ALC Volume", AK4535_ALC2, 0, 127, 0), | ||
152 | SOC_SINGLE("Capture Volume", AK4535_PGA, 0, 127, 0), | ||
153 | SOC_SINGLE("Left Playback Volume", AK4535_LATT, 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), | ||
156 | SOC_SINGLE("Mic Sidetone Volume", AK4535_VOL, 4, 7, 0), | ||
157 | }; | ||
158 | |||
159 | /* add non dapm controls */ | ||
160 | static int ak4535_add_controls(struct snd_soc_codec *codec) | ||
161 | { | ||
162 | int err, i; | ||
163 | |||
164 | for (i = 0; i < ARRAY_SIZE(ak4535_snd_controls); i++) { | ||
165 | err = snd_ctl_add(codec->card, | ||
166 | snd_soc_cnew(&ak4535_snd_controls[i], codec, NULL)); | ||
167 | if (err < 0) | ||
168 | return err; | ||
169 | } | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | /* Mono 1 Mixer */ | ||
175 | static const struct snd_kcontrol_new ak4535_mono1_mixer_controls[] = { | ||
176 | SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4535_SIG1, 4, 1, 0), | ||
177 | SOC_DAPM_SINGLE("Mono Playback Switch", AK4535_SIG1, 5, 1, 0), | ||
178 | }; | ||
179 | |||
180 | /* Stereo Mixer */ | ||
181 | static const struct snd_kcontrol_new ak4535_stereo_mixer_controls[] = { | ||
182 | SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4535_SIG2, 4, 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), | ||
185 | }; | ||
186 | |||
187 | /* Input Mixer */ | ||
188 | static const struct snd_kcontrol_new ak4535_input_mixer_controls[] = { | ||
189 | SOC_DAPM_SINGLE("Mic Capture Switch", AK4535_MIC, 2, 1, 0), | ||
190 | SOC_DAPM_SINGLE("Aux Capture Switch", AK4535_MIC, 5, 1, 0), | ||
191 | }; | ||
192 | |||
193 | /* Input mux */ | ||
194 | static const struct snd_kcontrol_new ak4535_input_mux_control = | ||
195 | SOC_DAPM_ENUM("Input Select", ak4535_enum[4]); | ||
196 | |||
197 | /* HP L switch */ | ||
198 | static const struct snd_kcontrol_new ak4535_hpl_control = | ||
199 | SOC_DAPM_SINGLE("Switch", AK4535_SIG2, 1, 1, 1); | ||
200 | |||
201 | /* HP R switch */ | ||
202 | static const struct snd_kcontrol_new ak4535_hpr_control = | ||
203 | SOC_DAPM_SINGLE("Switch", AK4535_SIG2, 0, 1, 1); | ||
204 | |||
205 | /* mono 2 switch */ | ||
206 | static const struct snd_kcontrol_new ak4535_mono2_control = | ||
207 | SOC_DAPM_SINGLE("Switch", AK4535_SIG1, 0, 1, 0); | ||
208 | |||
209 | /* Line out switch */ | ||
210 | static const struct snd_kcontrol_new ak4535_line_control = | ||
211 | SOC_DAPM_SINGLE("Switch", AK4535_SIG2, 6, 1, 0); | ||
212 | |||
213 | /* 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, | ||
216 | &ak4535_stereo_mixer_controls[0], | ||
217 | ARRAY_SIZE(ak4535_stereo_mixer_controls)), | ||
218 | SND_SOC_DAPM_MIXER("Mono1 Mixer", SND_SOC_NOPM, 0, 0, | ||
219 | &ak4535_mono1_mixer_controls[0], | ||
220 | ARRAY_SIZE(ak4535_mono1_mixer_controls)), | ||
221 | SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0, | ||
222 | &ak4535_input_mixer_controls[0], | ||
223 | ARRAY_SIZE(ak4535_input_mixer_controls)), | ||
224 | SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, | ||
225 | &ak4535_input_mux_control), | ||
226 | SND_SOC_DAPM_DAC("DAC", "Playback", AK4535_PM2, 0, 0), | ||
227 | SND_SOC_DAPM_SWITCH("Mono 2 Enable", SND_SOC_NOPM, 0, 0, | ||
228 | &ak4535_mono2_control), | ||
229 | /* speaker powersave bit */ | ||
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, | ||
232 | &ak4535_line_control), | ||
233 | SND_SOC_DAPM_SWITCH("Left HP Enable", SND_SOC_NOPM, 0, 0, | ||
234 | &ak4535_hpl_control), | ||
235 | SND_SOC_DAPM_SWITCH("Right HP Enable", SND_SOC_NOPM, 0, 0, | ||
236 | &ak4535_hpr_control), | ||
237 | SND_SOC_DAPM_OUTPUT("LOUT"), | ||
238 | SND_SOC_DAPM_OUTPUT("HPL"), | ||
239 | SND_SOC_DAPM_OUTPUT("ROUT"), | ||
240 | SND_SOC_DAPM_OUTPUT("HPR"), | ||
241 | SND_SOC_DAPM_OUTPUT("SPP"), | ||
242 | SND_SOC_DAPM_OUTPUT("SPN"), | ||
243 | SND_SOC_DAPM_OUTPUT("MOUT1"), | ||
244 | SND_SOC_DAPM_OUTPUT("MOUT2"), | ||
245 | SND_SOC_DAPM_OUTPUT("MICOUT"), | ||
246 | SND_SOC_DAPM_ADC("ADC", "Capture", AK4535_PM1, 0, 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), | ||
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), | ||
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), | ||
253 | SND_SOC_DAPM_PGA("AUX In", AK4535_PM1, 2, 0, NULL, 0), | ||
254 | |||
255 | SND_SOC_DAPM_MICBIAS("Mic Int Bias", AK4535_MIC, 3, 0), | ||
256 | SND_SOC_DAPM_MICBIAS("Mic Ext Bias", AK4535_MIC, 4, 0), | ||
257 | SND_SOC_DAPM_INPUT("MICIN"), | ||
258 | SND_SOC_DAPM_INPUT("MICEXT"), | ||
259 | SND_SOC_DAPM_INPUT("AUX"), | ||
260 | SND_SOC_DAPM_INPUT("MIN"), | ||
261 | SND_SOC_DAPM_INPUT("AIN"), | ||
262 | }; | ||
263 | |||
264 | static const struct snd_soc_dapm_route audio_map[] = { | ||
265 | /*stereo mixer */ | ||
266 | {"Stereo Mixer", "Playback Switch", "DAC"}, | ||
267 | {"Stereo Mixer", "Mic Sidetone Switch", "Mic"}, | ||
268 | {"Stereo Mixer", "Aux Bypass Switch", "AUX In"}, | ||
269 | |||
270 | /* mono1 mixer */ | ||
271 | {"Mono1 Mixer", "Mic Sidetone Switch", "Mic"}, | ||
272 | {"Mono1 Mixer", "Mono Playback Switch", "DAC"}, | ||
273 | |||
274 | /* Mic */ | ||
275 | {"Mic", NULL, "AIN"}, | ||
276 | {"Input Mux", "Internal", "Mic Int Bias"}, | ||
277 | {"Input Mux", "External", "Mic Ext Bias"}, | ||
278 | {"Mic Int Bias", NULL, "MICIN"}, | ||
279 | {"Mic Ext Bias", NULL, "MICEXT"}, | ||
280 | {"MICOUT", NULL, "Input Mux"}, | ||
281 | |||
282 | /* line out */ | ||
283 | {"LOUT", NULL, "Line Out Enable"}, | ||
284 | {"ROUT", NULL, "Line Out Enable"}, | ||
285 | {"Line Out Enable", "Switch", "Line Out"}, | ||
286 | {"Line Out", NULL, "Stereo Mixer"}, | ||
287 | |||
288 | /* mono1 out */ | ||
289 | {"MOUT1", NULL, "Mono Out"}, | ||
290 | {"Mono Out", NULL, "Mono1 Mixer"}, | ||
291 | |||
292 | /* left HP */ | ||
293 | {"HPL", NULL, "Left HP Enable"}, | ||
294 | {"Left HP Enable", "Switch", "HP L Amp"}, | ||
295 | {"HP L Amp", NULL, "Stereo Mixer"}, | ||
296 | |||
297 | /* right HP */ | ||
298 | {"HPR", NULL, "Right HP Enable"}, | ||
299 | {"Right HP Enable", "Switch", "HP R Amp"}, | ||
300 | {"HP R Amp", NULL, "Stereo Mixer"}, | ||
301 | |||
302 | /* speaker */ | ||
303 | {"SPP", NULL, "Speaker Enable"}, | ||
304 | {"SPN", NULL, "Speaker Enable"}, | ||
305 | {"Speaker Enable", "Switch", "Spk Amp"}, | ||
306 | {"Spk Amp", NULL, "MIN"}, | ||
307 | |||
308 | /* mono 2 */ | ||
309 | {"MOUT2", NULL, "Mono 2 Enable"}, | ||
310 | {"Mono 2 Enable", "Switch", "Stereo Mixer"}, | ||
311 | |||
312 | /* Aux In */ | ||
313 | {"Aux In", NULL, "AUX"}, | ||
314 | |||
315 | /* ADC */ | ||
316 | {"ADC", NULL, "Input Mixer"}, | ||
317 | {"Input Mixer", "Mic Capture Switch", "Mic"}, | ||
318 | {"Input Mixer", "Aux Capture Switch", "Aux In"}, | ||
319 | }; | ||
320 | |||
321 | static int ak4535_add_widgets(struct snd_soc_codec *codec) | ||
322 | { | ||
323 | snd_soc_dapm_new_controls(codec, ak4535_dapm_widgets, | ||
324 | ARRAY_SIZE(ak4535_dapm_widgets)); | ||
325 | |||
326 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
327 | |||
328 | snd_soc_dapm_new_widgets(codec); | ||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | static int ak4535_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
333 | int clk_id, unsigned int freq, int dir) | ||
334 | { | ||
335 | struct snd_soc_codec *codec = codec_dai->codec; | ||
336 | struct ak4535_priv *ak4535 = codec->private_data; | ||
337 | |||
338 | ak4535->sysclk = freq; | ||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | static int ak4535_hw_params(struct snd_pcm_substream *substream, | ||
343 | struct snd_pcm_hw_params *params) | ||
344 | { | ||
345 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
346 | struct snd_soc_device *socdev = rtd->socdev; | ||
347 | struct snd_soc_codec *codec = socdev->codec; | ||
348 | struct ak4535_priv *ak4535 = codec->private_data; | ||
349 | u8 mode2 = ak4535_read_reg_cache(codec, AK4535_MODE2) & ~(0x3 << 5); | ||
350 | int rate = params_rate(params), fs = 256; | ||
351 | |||
352 | if (rate) | ||
353 | fs = ak4535->sysclk / rate; | ||
354 | |||
355 | /* set fs */ | ||
356 | switch (fs) { | ||
357 | case 1024: | ||
358 | mode2 |= (0x2 << 5); | ||
359 | break; | ||
360 | case 512: | ||
361 | mode2 |= (0x1 << 5); | ||
362 | break; | ||
363 | case 256: | ||
364 | break; | ||
365 | } | ||
366 | |||
367 | /* set rate */ | ||
368 | ak4535_write(codec, AK4535_MODE2, mode2); | ||
369 | return 0; | ||
370 | } | ||
371 | |||
372 | static int ak4535_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
373 | unsigned int fmt) | ||
374 | { | ||
375 | struct snd_soc_codec *codec = codec_dai->codec; | ||
376 | u8 mode1 = 0; | ||
377 | |||
378 | /* interface format */ | ||
379 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
380 | case SND_SOC_DAIFMT_I2S: | ||
381 | mode1 = 0x0002; | ||
382 | break; | ||
383 | case SND_SOC_DAIFMT_LEFT_J: | ||
384 | mode1 = 0x0001; | ||
385 | break; | ||
386 | default: | ||
387 | return -EINVAL; | ||
388 | } | ||
389 | |||
390 | /* use 32 fs for BCLK to save power */ | ||
391 | mode1 |= 0x4; | ||
392 | |||
393 | ak4535_write(codec, AK4535_MODE1, mode1); | ||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | static int ak4535_mute(struct snd_soc_dai *dai, int mute) | ||
398 | { | ||
399 | struct snd_soc_codec *codec = dai->codec; | ||
400 | u16 mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC) & 0xffdf; | ||
401 | if (!mute) | ||
402 | ak4535_write(codec, AK4535_DAC, mute_reg); | ||
403 | else | ||
404 | ak4535_write(codec, AK4535_DAC, mute_reg | 0x20); | ||
405 | return 0; | ||
406 | } | ||
407 | |||
408 | static int ak4535_set_bias_level(struct snd_soc_codec *codec, | ||
409 | enum snd_soc_bias_level level) | ||
410 | { | ||
411 | u16 i; | ||
412 | |||
413 | switch (level) { | ||
414 | case SND_SOC_BIAS_ON: | ||
415 | ak4535_mute(codec->dai, 0); | ||
416 | break; | ||
417 | case SND_SOC_BIAS_PREPARE: | ||
418 | ak4535_mute(codec->dai, 1); | ||
419 | break; | ||
420 | case SND_SOC_BIAS_STANDBY: | ||
421 | i = ak4535_read_reg_cache(codec, AK4535_PM1); | ||
422 | ak4535_write(codec, AK4535_PM1, i | 0x80); | ||
423 | i = ak4535_read_reg_cache(codec, AK4535_PM2); | ||
424 | ak4535_write(codec, AK4535_PM2, i & (~0x80)); | ||
425 | break; | ||
426 | case SND_SOC_BIAS_OFF: | ||
427 | i = ak4535_read_reg_cache(codec, AK4535_PM1); | ||
428 | ak4535_write(codec, AK4535_PM1, i & (~0x80)); | ||
429 | break; | ||
430 | } | ||
431 | codec->bias_level = level; | ||
432 | return 0; | ||
433 | } | ||
434 | |||
435 | #define AK4535_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
436 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ | ||
437 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) | ||
438 | |||
439 | struct snd_soc_dai ak4535_dai = { | ||
440 | .name = "AK4535", | ||
441 | .playback = { | ||
442 | .stream_name = "Playback", | ||
443 | .channels_min = 1, | ||
444 | .channels_max = 2, | ||
445 | .rates = AK4535_RATES, | ||
446 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
447 | .capture = { | ||
448 | .stream_name = "Capture", | ||
449 | .channels_min = 1, | ||
450 | .channels_max = 2, | ||
451 | .rates = AK4535_RATES, | ||
452 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
453 | .ops = { | ||
454 | .hw_params = ak4535_hw_params, | ||
455 | }, | ||
456 | .dai_ops = { | ||
457 | .set_fmt = ak4535_set_dai_fmt, | ||
458 | .digital_mute = ak4535_mute, | ||
459 | .set_sysclk = ak4535_set_dai_sysclk, | ||
460 | }, | ||
461 | }; | ||
462 | EXPORT_SYMBOL_GPL(ak4535_dai); | ||
463 | |||
464 | static int ak4535_suspend(struct platform_device *pdev, pm_message_t state) | ||
465 | { | ||
466 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
467 | struct snd_soc_codec *codec = socdev->codec; | ||
468 | |||
469 | ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
470 | return 0; | ||
471 | } | ||
472 | |||
473 | static int ak4535_resume(struct platform_device *pdev) | ||
474 | { | ||
475 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
476 | struct snd_soc_codec *codec = socdev->codec; | ||
477 | ak4535_sync(codec); | ||
478 | ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
479 | ak4535_set_bias_level(codec, codec->suspend_bias_level); | ||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | /* | ||
484 | * initialise the AK4535 driver | ||
485 | * register the mixer and dsp interfaces with the kernel | ||
486 | */ | ||
487 | static int ak4535_init(struct snd_soc_device *socdev) | ||
488 | { | ||
489 | struct snd_soc_codec *codec = socdev->codec; | ||
490 | int ret = 0; | ||
491 | |||
492 | codec->name = "AK4535"; | ||
493 | codec->owner = THIS_MODULE; | ||
494 | codec->read = ak4535_read_reg_cache; | ||
495 | codec->write = ak4535_write; | ||
496 | codec->set_bias_level = ak4535_set_bias_level; | ||
497 | codec->dai = &ak4535_dai; | ||
498 | codec->num_dai = 1; | ||
499 | codec->reg_cache_size = ARRAY_SIZE(ak4535_reg); | ||
500 | codec->reg_cache = kmemdup(ak4535_reg, sizeof(ak4535_reg), GFP_KERNEL); | ||
501 | |||
502 | if (codec->reg_cache == NULL) | ||
503 | return -ENOMEM; | ||
504 | |||
505 | /* register pcms */ | ||
506 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
507 | if (ret < 0) { | ||
508 | printk(KERN_ERR "ak4535: failed to create pcms\n"); | ||
509 | goto pcm_err; | ||
510 | } | ||
511 | |||
512 | /* power on device */ | ||
513 | ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
514 | |||
515 | ak4535_add_controls(codec); | ||
516 | ak4535_add_widgets(codec); | ||
517 | ret = snd_soc_register_card(socdev); | ||
518 | if (ret < 0) { | ||
519 | printk(KERN_ERR "ak4535: failed to register card\n"); | ||
520 | goto card_err; | ||
521 | } | ||
522 | |||
523 | return ret; | ||
524 | |||
525 | card_err: | ||
526 | snd_soc_free_pcms(socdev); | ||
527 | snd_soc_dapm_free(socdev); | ||
528 | pcm_err: | ||
529 | kfree(codec->reg_cache); | ||
530 | |||
531 | return ret; | ||
532 | } | ||
533 | |||
534 | static struct snd_soc_device *ak4535_socdev; | ||
535 | |||
536 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
537 | |||
538 | #define I2C_DRIVERID_AK4535 0xfefe /* liam - need a proper id */ | ||
539 | |||
540 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
541 | |||
542 | /* Magic definition of all other variables and things */ | ||
543 | I2C_CLIENT_INSMOD; | ||
544 | |||
545 | static struct i2c_driver ak4535_i2c_driver; | ||
546 | static struct i2c_client client_template; | ||
547 | |||
548 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
549 | around */ | ||
550 | static int ak4535_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
551 | { | ||
552 | struct snd_soc_device *socdev = ak4535_socdev; | ||
553 | struct ak4535_setup_data *setup = socdev->codec_data; | ||
554 | struct snd_soc_codec *codec = socdev->codec; | ||
555 | struct i2c_client *i2c; | ||
556 | int ret; | ||
557 | |||
558 | if (addr != setup->i2c_address) | ||
559 | return -ENODEV; | ||
560 | |||
561 | client_template.adapter = adap; | ||
562 | client_template.addr = addr; | ||
563 | |||
564 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
565 | if (i2c == NULL) { | ||
566 | kfree(codec); | ||
567 | return -ENOMEM; | ||
568 | } | ||
569 | i2c_set_clientdata(i2c, codec); | ||
570 | codec->control_data = i2c; | ||
571 | |||
572 | ret = i2c_attach_client(i2c); | ||
573 | if (ret < 0) { | ||
574 | printk(KERN_ERR "failed to attach codec at addr %x\n", addr); | ||
575 | goto err; | ||
576 | } | ||
577 | |||
578 | ret = ak4535_init(socdev); | ||
579 | if (ret < 0) { | ||
580 | printk(KERN_ERR "failed to initialise AK4535\n"); | ||
581 | goto err; | ||
582 | } | ||
583 | return ret; | ||
584 | |||
585 | err: | ||
586 | kfree(codec); | ||
587 | kfree(i2c); | ||
588 | return ret; | ||
589 | } | ||
590 | |||
591 | static int ak4535_i2c_detach(struct i2c_client *client) | ||
592 | { | ||
593 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
594 | i2c_detach_client(client); | ||
595 | kfree(codec->reg_cache); | ||
596 | kfree(client); | ||
597 | return 0; | ||
598 | } | ||
599 | |||
600 | static int ak4535_i2c_attach(struct i2c_adapter *adap) | ||
601 | { | ||
602 | return i2c_probe(adap, &addr_data, ak4535_codec_probe); | ||
603 | } | ||
604 | |||
605 | /* corgi i2c codec control layer */ | ||
606 | static struct i2c_driver ak4535_i2c_driver = { | ||
607 | .driver = { | ||
608 | .name = "AK4535 I2C Codec", | ||
609 | .owner = THIS_MODULE, | ||
610 | }, | ||
611 | .id = I2C_DRIVERID_AK4535, | ||
612 | .attach_adapter = ak4535_i2c_attach, | ||
613 | .detach_client = ak4535_i2c_detach, | ||
614 | .command = NULL, | ||
615 | }; | ||
616 | |||
617 | static struct i2c_client client_template = { | ||
618 | .name = "AK4535", | ||
619 | .driver = &ak4535_i2c_driver, | ||
620 | }; | ||
621 | #endif | ||
622 | |||
623 | static int ak4535_probe(struct platform_device *pdev) | ||
624 | { | ||
625 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
626 | struct ak4535_setup_data *setup; | ||
627 | struct snd_soc_codec *codec; | ||
628 | struct ak4535_priv *ak4535; | ||
629 | int ret = 0; | ||
630 | |||
631 | printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION); | ||
632 | |||
633 | setup = socdev->codec_data; | ||
634 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
635 | if (codec == NULL) | ||
636 | return -ENOMEM; | ||
637 | |||
638 | ak4535 = kzalloc(sizeof(struct ak4535_priv), GFP_KERNEL); | ||
639 | if (ak4535 == NULL) { | ||
640 | kfree(codec); | ||
641 | return -ENOMEM; | ||
642 | } | ||
643 | |||
644 | codec->private_data = ak4535; | ||
645 | socdev->codec = codec; | ||
646 | mutex_init(&codec->mutex); | ||
647 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
648 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
649 | |||
650 | ak4535_socdev = socdev; | ||
651 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
652 | if (setup->i2c_address) { | ||
653 | normal_i2c[0] = setup->i2c_address; | ||
654 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
655 | codec->hw_read = (hw_read_t)i2c_master_recv; | ||
656 | ret = i2c_add_driver(&ak4535_i2c_driver); | ||
657 | if (ret != 0) | ||
658 | printk(KERN_ERR "can't add i2c driver"); | ||
659 | } | ||
660 | #else | ||
661 | /* Add other interfaces here */ | ||
662 | #endif | ||
663 | return ret; | ||
664 | } | ||
665 | |||
666 | /* power down chip */ | ||
667 | static int ak4535_remove(struct platform_device *pdev) | ||
668 | { | ||
669 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
670 | struct snd_soc_codec *codec = socdev->codec; | ||
671 | |||
672 | if (codec->control_data) | ||
673 | ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
674 | |||
675 | snd_soc_free_pcms(socdev); | ||
676 | snd_soc_dapm_free(socdev); | ||
677 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
678 | i2c_del_driver(&ak4535_i2c_driver); | ||
679 | #endif | ||
680 | kfree(codec->private_data); | ||
681 | kfree(codec); | ||
682 | |||
683 | return 0; | ||
684 | } | ||
685 | |||
686 | struct snd_soc_codec_device soc_codec_dev_ak4535 = { | ||
687 | .probe = ak4535_probe, | ||
688 | .remove = ak4535_remove, | ||
689 | .suspend = ak4535_suspend, | ||
690 | .resume = ak4535_resume, | ||
691 | }; | ||
692 | EXPORT_SYMBOL_GPL(soc_codec_dev_ak4535); | ||
693 | |||
694 | MODULE_DESCRIPTION("Soc AK4535 driver"); | ||
695 | MODULE_AUTHOR("Richard Purdie"); | ||
696 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/ak4535.h b/sound/soc/codecs/ak4535.h new file mode 100644 index 000000000000..e9fe30e2c056 --- /dev/null +++ b/sound/soc/codecs/ak4535.h | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * ak4535.h -- AK4535 Soc Audio driver | ||
3 | * | ||
4 | * Copyright 2005 Openedhand Ltd. | ||
5 | * | ||
6 | * Author: Richard Purdie <richard@openedhand.com> | ||
7 | * | ||
8 | * Based on wm8753.h | ||
9 | * | ||
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 | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #ifndef _AK4535_H | ||
16 | #define _AK4535_H | ||
17 | |||
18 | /* AK4535 register space */ | ||
19 | |||
20 | #define AK4535_PM1 0x0 | ||
21 | #define AK4535_PM2 0x1 | ||
22 | #define AK4535_SIG1 0x2 | ||
23 | #define AK4535_SIG2 0x3 | ||
24 | #define AK4535_MODE1 0x4 | ||
25 | #define AK4535_MODE2 0x5 | ||
26 | #define AK4535_DAC 0x6 | ||
27 | #define AK4535_MIC 0x7 | ||
28 | #define AK4535_TIMER 0x8 | ||
29 | #define AK4535_ALC1 0x9 | ||
30 | #define AK4535_ALC2 0xa | ||
31 | #define AK4535_PGA 0xb | ||
32 | #define AK4535_LATT 0xc | ||
33 | #define AK4535_RATT 0xd | ||
34 | #define AK4535_VOL 0xe | ||
35 | #define AK4535_STATUS 0xf | ||
36 | |||
37 | #define AK4535_CACHEREGNUM 0x10 | ||
38 | |||
39 | struct ak4535_setup_data { | ||
40 | unsigned short i2c_address; | ||
41 | }; | ||
42 | |||
43 | extern struct snd_soc_dai ak4535_dai; | ||
44 | extern struct snd_soc_codec_device soc_codec_dev_ak4535; | ||
45 | |||
46 | #endif | ||
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index e73fcfd9f5cd..9deb8c74fdfd 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c | |||
@@ -201,7 +201,7 @@ static struct { | |||
201 | * driver what the input settings can be. This would need to be implemented | 201 | * driver what the input settings can be. This would need to be implemented |
202 | * for stand-alone mode to work. | 202 | * for stand-alone mode to work. |
203 | */ | 203 | */ |
204 | static int cs4270_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | 204 | static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
205 | int clk_id, unsigned int freq, int dir) | 205 | int clk_id, unsigned int freq, int dir) |
206 | { | 206 | { |
207 | struct snd_soc_codec *codec = codec_dai->codec; | 207 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -251,7 +251,7 @@ static int cs4270_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | |||
251 | * data for playback only, but ASoC currently does not support different | 251 | * data for playback only, but ASoC currently does not support different |
252 | * formats for playback vs. record. | 252 | * formats for playback vs. record. |
253 | */ | 253 | */ |
254 | static int cs4270_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 254 | static int cs4270_set_dai_fmt(struct snd_soc_dai *codec_dai, |
255 | unsigned int format) | 255 | unsigned int format) |
256 | { | 256 | { |
257 | struct snd_soc_codec *codec = codec_dai->codec; | 257 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -471,7 +471,7 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream, | |||
471 | * board does not have the MUTEA or MUTEB pins connected to such circuitry, | 471 | * board does not have the MUTEA or MUTEB pins connected to such circuitry, |
472 | * then this function will do nothing. | 472 | * then this function will do nothing. |
473 | */ | 473 | */ |
474 | static int cs4270_mute(struct snd_soc_codec_dai *dai, int mute) | 474 | static int cs4270_mute(struct snd_soc_dai *dai, int mute) |
475 | { | 475 | { |
476 | struct snd_soc_codec *codec = dai->codec; | 476 | struct snd_soc_codec *codec = dai->codec; |
477 | int reg6; | 477 | int reg6; |
@@ -667,7 +667,7 @@ error: | |||
667 | 667 | ||
668 | #endif /* USE_I2C*/ | 668 | #endif /* USE_I2C*/ |
669 | 669 | ||
670 | struct snd_soc_codec_dai cs4270_dai = { | 670 | struct snd_soc_dai cs4270_dai = { |
671 | .name = "CS4270", | 671 | .name = "CS4270", |
672 | .playback = { | 672 | .playback = { |
673 | .stream_name = "Playback", | 673 | .stream_name = "Playback", |
diff --git a/sound/soc/codecs/cs4270.h b/sound/soc/codecs/cs4270.h index 0ced49b7804d..adc6cd9667d4 100644 --- a/sound/soc/codecs/cs4270.h +++ b/sound/soc/codecs/cs4270.h | |||
@@ -16,7 +16,7 @@ | |||
16 | * The ASoC codec DAI structure for the CS4270. Assign this structure to | 16 | * The ASoC codec DAI structure for the CS4270. Assign this structure to |
17 | * the .codec_dai field of your machine driver's snd_soc_dai_link structure. | 17 | * the .codec_dai field of your machine driver's snd_soc_dai_link structure. |
18 | */ | 18 | */ |
19 | extern struct snd_soc_codec_dai cs4270_dai; | 19 | extern struct snd_soc_dai cs4270_dai; |
20 | 20 | ||
21 | /* | 21 | /* |
22 | * The ASoC codec device structure for the CS4270. Assign this structure | 22 | * The ASoC codec device structure for the CS4270. Assign this structure |
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 09b1661b8a3a..b1dce5f459db 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c | |||
@@ -29,7 +29,7 @@ | |||
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_set_endpoint(codec, "MONO_LOUT", 0), 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> |
@@ -49,7 +49,7 @@ | |||
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.1" | 52 | #define AIC3X_VERSION "0.2" |
53 | 53 | ||
54 | /* codec private data */ | 54 | /* codec private data */ |
55 | struct aic3x_priv { | 55 | struct aic3x_priv { |
@@ -138,6 +138,20 @@ static int aic3x_write(struct snd_soc_codec *codec, unsigned int reg, | |||
138 | return -EIO; | 138 | return -EIO; |
139 | } | 139 | } |
140 | 140 | ||
141 | /* | ||
142 | * read from the aic3x register space | ||
143 | */ | ||
144 | static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg, | ||
145 | u8 *value) | ||
146 | { | ||
147 | *value = reg & 0xff; | ||
148 | if (codec->hw_read(codec->control_data, value, 1) != 1) | ||
149 | return -EIO; | ||
150 | |||
151 | aic3x_write_reg_cache(codec, reg, *value); | ||
152 | return 0; | ||
153 | } | ||
154 | |||
141 | #define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \ | 155 | #define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \ |
142 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 156 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
143 | .info = snd_soc_info_volsw, \ | 157 | .info = snd_soc_info_volsw, \ |
@@ -192,7 +206,7 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol, | |||
192 | } | 206 | } |
193 | 207 | ||
194 | if (found) | 208 | if (found) |
195 | snd_soc_dapm_sync_endpoints(widget->codec); | 209 | snd_soc_dapm_sync(widget->codec); |
196 | } | 210 | } |
197 | 211 | ||
198 | ret = snd_soc_update_bits(widget->codec, reg, val_mask, val); | 212 | ret = snd_soc_update_bits(widget->codec, reg, val_mask, val); |
@@ -209,6 +223,8 @@ static const char *aic3x_right_hpcom_mux[] = | |||
209 | { "differential of HPROUT", "constant VCM", "single-ended", | 223 | { "differential of HPROUT", "constant VCM", "single-ended", |
210 | "differential of HPLCOM", "external feedback" }; | 224 | "differential of HPLCOM", "external feedback" }; |
211 | 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[] = | ||
227 | { "Disabled", "0.0045xFs", "0.0125xFs", "0.025xFs" }; | ||
212 | 228 | ||
213 | #define LDAC_ENUM 0 | 229 | #define LDAC_ENUM 0 |
214 | #define RDAC_ENUM 1 | 230 | #define RDAC_ENUM 1 |
@@ -218,6 +234,7 @@ static const char *aic3x_linein_mode_mux[] = { "single-ended", "differential" }; | |||
218 | #define LINE1R_ENUM 5 | 234 | #define LINE1R_ENUM 5 |
219 | #define LINE2L_ENUM 6 | 235 | #define LINE2L_ENUM 6 |
220 | #define LINE2R_ENUM 7 | 236 | #define LINE2R_ENUM 7 |
237 | #define ADC_HPF_ENUM 8 | ||
221 | 238 | ||
222 | static const struct soc_enum aic3x_enum[] = { | 239 | static const struct soc_enum aic3x_enum[] = { |
223 | 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), |
@@ -228,6 +245,7 @@ static const struct soc_enum aic3x_enum[] = { | |||
228 | 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), |
229 | 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), |
230 | 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), | ||
231 | }; | 249 | }; |
232 | 250 | ||
233 | static const struct snd_kcontrol_new aic3x_snd_controls[] = { | 251 | static const struct snd_kcontrol_new aic3x_snd_controls[] = { |
@@ -278,6 +296,8 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { | |||
278 | /* Input */ | 296 | /* Input */ |
279 | 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), |
280 | 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 | |||
300 | SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]), | ||
281 | }; | 301 | }; |
282 | 302 | ||
283 | /* add non dapm controls */ | 303 | /* add non dapm controls */ |
@@ -441,11 +461,34 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { | |||
441 | 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, |
442 | &aic3x_right_line2_mux_controls), | 462 | &aic3x_right_line2_mux_controls), |
443 | 463 | ||
464 | /* | ||
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 | ||
467 | * using digital mic. | ||
468 | */ | ||
469 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "GPIO1 dmic modclk", | ||
470 | AIC3X_GPIO1_REG, 4, 0xf, | ||
471 | AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK, | ||
472 | AIC3X_GPIO1_FUNC_DISABLED), | ||
473 | |||
474 | /* | ||
475 | * Also similar function like mic bias. Selects digital mic with | ||
476 | * configurable oversampling rate instead of ADC converter. | ||
477 | */ | ||
478 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 128", | ||
479 | AIC3X_ASD_INTF_CTRLA, 0, 3, 1, 0), | ||
480 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 64", | ||
481 | AIC3X_ASD_INTF_CTRLA, 0, 3, 2, 0), | ||
482 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 32", | ||
483 | AIC3X_ASD_INTF_CTRLA, 0, 3, 3, 0), | ||
484 | |||
444 | /* Mic Bias */ | 485 | /* Mic Bias */ |
445 | SND_SOC_DAPM_MICBIAS("Mic Bias 2V", MICBIAS_CTRL, 6, 0), | 486 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2V", |
446 | SND_SOC_DAPM_MICBIAS("Mic Bias 2.5V", MICBIAS_CTRL, 7, 0), | 487 | MICBIAS_CTRL, 6, 3, 1, 0), |
447 | SND_SOC_DAPM_MICBIAS("Mic Bias AVDD", MICBIAS_CTRL, 6, 0), | 488 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias 2.5V", |
448 | SND_SOC_DAPM_MICBIAS("Mic Bias AVDD", MICBIAS_CTRL, 7, 0), | 489 | MICBIAS_CTRL, 6, 3, 2, 0), |
490 | SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias AVDD", | ||
491 | MICBIAS_CTRL, 6, 3, 3, 0), | ||
449 | 492 | ||
450 | /* Left PGA to Left Output bypass */ | 493 | /* Left PGA to Left Output bypass */ |
451 | 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, |
@@ -483,7 +526,7 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { | |||
483 | SND_SOC_DAPM_INPUT("LINE2R"), | 526 | SND_SOC_DAPM_INPUT("LINE2R"), |
484 | }; | 527 | }; |
485 | 528 | ||
486 | static const char *intercon[][3] = { | 529 | static const struct snd_soc_dapm_route intercon[] = { |
487 | /* Left Output */ | 530 | /* Left Output */ |
488 | {"Left DAC Mux", "DAC_L1", "Left DAC"}, | 531 | {"Left DAC Mux", "DAC_L1", "Left DAC"}, |
489 | {"Left DAC Mux", "DAC_L2", "Left DAC"}, | 532 | {"Left DAC Mux", "DAC_L2", "Left DAC"}, |
@@ -554,6 +597,7 @@ static const char *intercon[][3] = { | |||
554 | {"Left PGA Mixer", "Mic3L Switch", "MIC3L"}, | 597 | {"Left PGA Mixer", "Mic3L Switch", "MIC3L"}, |
555 | 598 | ||
556 | {"Left ADC", NULL, "Left PGA Mixer"}, | 599 | {"Left ADC", NULL, "Left PGA Mixer"}, |
600 | {"Left ADC", NULL, "GPIO1 dmic modclk"}, | ||
557 | 601 | ||
558 | /* Right Input */ | 602 | /* Right Input */ |
559 | {"Right Line1R Mux", "single-ended", "LINE1R"}, | 603 | {"Right Line1R Mux", "single-ended", "LINE1R"}, |
@@ -567,6 +611,7 @@ static const char *intercon[][3] = { | |||
567 | {"Right PGA Mixer", "Mic3R Switch", "MIC3R"}, | 611 | {"Right PGA Mixer", "Mic3R Switch", "MIC3R"}, |
568 | 612 | ||
569 | {"Right ADC", NULL, "Right PGA Mixer"}, | 613 | {"Right ADC", NULL, "Right PGA Mixer"}, |
614 | {"Right ADC", NULL, "GPIO1 dmic modclk"}, | ||
570 | 615 | ||
571 | /* Left PGA Bypass */ | 616 | /* Left PGA Bypass */ |
572 | {"Left PGA Bypass Mixer", "Line Switch", "Left PGA Mixer"}, | 617 | {"Left PGA Bypass Mixer", "Line Switch", "Left PGA Mixer"}, |
@@ -628,101 +673,27 @@ static const char *intercon[][3] = { | |||
628 | {"Mono Out", NULL, "Right Line2 Bypass Mixer"}, | 673 | {"Mono Out", NULL, "Right Line2 Bypass Mixer"}, |
629 | {"Right HP Out", NULL, "Right Line2 Bypass Mixer"}, | 674 | {"Right HP Out", NULL, "Right Line2 Bypass Mixer"}, |
630 | 675 | ||
631 | /* terminator */ | 676 | /* |
632 | {NULL, NULL, NULL}, | 677 | * Logical path between digital mic enable and GPIO1 modulator clock |
678 | * output function | ||
679 | */ | ||
680 | {"GPIO1 dmic modclk", NULL, "DMic Rate 128"}, | ||
681 | {"GPIO1 dmic modclk", NULL, "DMic Rate 64"}, | ||
682 | {"GPIO1 dmic modclk", NULL, "DMic Rate 32"}, | ||
633 | }; | 683 | }; |
634 | 684 | ||
635 | static int aic3x_add_widgets(struct snd_soc_codec *codec) | 685 | static int aic3x_add_widgets(struct snd_soc_codec *codec) |
636 | { | 686 | { |
637 | int i; | 687 | snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets, |
638 | 688 | ARRAY_SIZE(aic3x_dapm_widgets)); | |
639 | for (i = 0; i < ARRAY_SIZE(aic3x_dapm_widgets); i++) | ||
640 | snd_soc_dapm_new_control(codec, &aic3x_dapm_widgets[i]); | ||
641 | 689 | ||
642 | /* set up audio path interconnects */ | 690 | /* set up audio path interconnects */ |
643 | for (i = 0; intercon[i][0] != NULL; i++) | 691 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); |
644 | snd_soc_dapm_connect_input(codec, intercon[i][0], | ||
645 | intercon[i][1], intercon[i][2]); | ||
646 | 692 | ||
647 | snd_soc_dapm_new_widgets(codec); | 693 | snd_soc_dapm_new_widgets(codec); |
648 | return 0; | 694 | return 0; |
649 | } | 695 | } |
650 | 696 | ||
651 | struct aic3x_rate_divs { | ||
652 | u32 mclk; | ||
653 | u32 rate; | ||
654 | u32 fsref_reg; | ||
655 | u8 sr_reg:4; | ||
656 | u8 pllj_reg; | ||
657 | u16 plld_reg; | ||
658 | }; | ||
659 | |||
660 | /* AIC3X codec mclk clock divider coefficients */ | ||
661 | static const struct aic3x_rate_divs aic3x_divs[] = { | ||
662 | /* 8k */ | ||
663 | {12000000, 8000, 48000, 0xa, 16, 3840}, | ||
664 | {19200000, 8000, 48000, 0xa, 10, 2400}, | ||
665 | {22579200, 8000, 48000, 0xa, 8, 7075}, | ||
666 | {33868800, 8000, 48000, 0xa, 5, 8049}, | ||
667 | /* 11.025k */ | ||
668 | {12000000, 11025, 44100, 0x6, 15, 528}, | ||
669 | {19200000, 11025, 44100, 0x6, 9, 4080}, | ||
670 | {22579200, 11025, 44100, 0x6, 8, 0}, | ||
671 | {33868800, 11025, 44100, 0x6, 5, 3333}, | ||
672 | /* 16k */ | ||
673 | {12000000, 16000, 48000, 0x4, 16, 3840}, | ||
674 | {19200000, 16000, 48000, 0x4, 10, 2400}, | ||
675 | {22579200, 16000, 48000, 0x4, 8, 7075}, | ||
676 | {33868800, 16000, 48000, 0x4, 5, 8049}, | ||
677 | /* 22.05k */ | ||
678 | {12000000, 22050, 44100, 0x2, 15, 528}, | ||
679 | {19200000, 22050, 44100, 0x2, 9, 4080}, | ||
680 | {22579200, 22050, 44100, 0x2, 8, 0}, | ||
681 | {33868800, 22050, 44100, 0x2, 5, 3333}, | ||
682 | /* 32k */ | ||
683 | {12000000, 32000, 48000, 0x1, 16, 3840}, | ||
684 | {19200000, 32000, 48000, 0x1, 10, 2400}, | ||
685 | {22579200, 32000, 48000, 0x1, 8, 7075}, | ||
686 | {33868800, 32000, 48000, 0x1, 5, 8049}, | ||
687 | /* 44.1k */ | ||
688 | {12000000, 44100, 44100, 0x0, 15, 528}, | ||
689 | {19200000, 44100, 44100, 0x0, 9, 4080}, | ||
690 | {22579200, 44100, 44100, 0x0, 8, 0}, | ||
691 | {33868800, 44100, 44100, 0x0, 5, 3333}, | ||
692 | /* 48k */ | ||
693 | {12000000, 48000, 48000, 0x0, 16, 3840}, | ||
694 | {19200000, 48000, 48000, 0x0, 10, 2400}, | ||
695 | {22579200, 48000, 48000, 0x0, 8, 7075}, | ||
696 | {33868800, 48000, 48000, 0x0, 5, 8049}, | ||
697 | /* 64k */ | ||
698 | {12000000, 64000, 96000, 0x1, 16, 3840}, | ||
699 | {19200000, 64000, 96000, 0x1, 10, 2400}, | ||
700 | {22579200, 64000, 96000, 0x1, 8, 7075}, | ||
701 | {33868800, 64000, 96000, 0x1, 5, 8049}, | ||
702 | /* 88.2k */ | ||
703 | {12000000, 88200, 88200, 0x0, 15, 528}, | ||
704 | {19200000, 88200, 88200, 0x0, 9, 4080}, | ||
705 | {22579200, 88200, 88200, 0x0, 8, 0}, | ||
706 | {33868800, 88200, 88200, 0x0, 5, 3333}, | ||
707 | /* 96k */ | ||
708 | {12000000, 96000, 96000, 0x0, 16, 3840}, | ||
709 | {19200000, 96000, 96000, 0x0, 10, 2400}, | ||
710 | {22579200, 96000, 96000, 0x0, 8, 7075}, | ||
711 | {33868800, 96000, 96000, 0x0, 5, 8049}, | ||
712 | }; | ||
713 | |||
714 | static inline int aic3x_get_divs(int mclk, int rate) | ||
715 | { | ||
716 | int i; | ||
717 | |||
718 | for (i = 0; i < ARRAY_SIZE(aic3x_divs); i++) { | ||
719 | if (aic3x_divs[i].rate == rate && aic3x_divs[i].mclk == mclk) | ||
720 | return i; | ||
721 | } | ||
722 | |||
723 | return 0; | ||
724 | } | ||
725 | |||
726 | static int aic3x_hw_params(struct snd_pcm_substream *substream, | 697 | static int aic3x_hw_params(struct snd_pcm_substream *substream, |
727 | struct snd_pcm_hw_params *params) | 698 | struct snd_pcm_hw_params *params) |
728 | { | 699 | { |
@@ -730,49 +701,107 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, | |||
730 | struct snd_soc_device *socdev = rtd->socdev; | 701 | struct snd_soc_device *socdev = rtd->socdev; |
731 | struct snd_soc_codec *codec = socdev->codec; | 702 | struct snd_soc_codec *codec = socdev->codec; |
732 | struct aic3x_priv *aic3x = codec->private_data; | 703 | struct aic3x_priv *aic3x = codec->private_data; |
733 | int i; | 704 | int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0; |
734 | u8 data, pll_p, pll_r, pll_j; | 705 | u8 data, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1; |
735 | u16 pll_d; | 706 | u16 pll_d = 1; |
736 | |||
737 | i = aic3x_get_divs(aic3x->sysclk, params_rate(params)); | ||
738 | 707 | ||
739 | /* Route Left DAC to left channel input and | 708 | /* select data word length */ |
740 | * right DAC to right channel input */ | 709 | data = |
741 | data = (LDAC2LCH | RDAC2RCH); | 710 | aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4)); |
742 | switch (aic3x_divs[i].fsref_reg) { | 711 | switch (params_format(params)) { |
743 | case 44100: | 712 | case SNDRV_PCM_FORMAT_S16_LE: |
744 | data |= FSREF_44100; | ||
745 | break; | 713 | break; |
746 | case 48000: | 714 | case SNDRV_PCM_FORMAT_S20_3LE: |
747 | data |= FSREF_48000; | 715 | data |= (0x01 << 4); |
748 | break; | 716 | break; |
749 | case 88200: | 717 | case SNDRV_PCM_FORMAT_S24_LE: |
750 | data |= FSREF_44100 | DUAL_RATE_MODE; | 718 | data |= (0x02 << 4); |
751 | break; | 719 | break; |
752 | case 96000: | 720 | case SNDRV_PCM_FORMAT_S32_LE: |
753 | data |= FSREF_48000 | DUAL_RATE_MODE; | 721 | data |= (0x03 << 4); |
754 | break; | 722 | break; |
755 | } | 723 | } |
724 | aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, data); | ||
725 | |||
726 | /* Fsref can be 44100 or 48000 */ | ||
727 | fsref = (params_rate(params) % 11025 == 0) ? 44100 : 48000; | ||
728 | |||
729 | /* Try to find a value for Q which allows us to bypass the PLL and | ||
730 | * generate CODEC_CLK directly. */ | ||
731 | for (pll_q = 2; pll_q < 18; pll_q++) | ||
732 | if (aic3x->sysclk / (128 * pll_q) == fsref) { | ||
733 | bypass_pll = 1; | ||
734 | break; | ||
735 | } | ||
736 | |||
737 | if (bypass_pll) { | ||
738 | pll_q &= 0xf; | ||
739 | aic3x_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT); | ||
740 | aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV); | ||
741 | } else | ||
742 | aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV); | ||
743 | |||
744 | /* Route Left DAC to left channel input and | ||
745 | * right DAC to right channel input */ | ||
746 | data = (LDAC2LCH | RDAC2RCH); | ||
747 | data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000; | ||
748 | if (params_rate(params) >= 64000) | ||
749 | data |= DUAL_RATE_MODE; | ||
756 | aic3x_write(codec, AIC3X_CODEC_DATAPATH_REG, data); | 750 | aic3x_write(codec, AIC3X_CODEC_DATAPATH_REG, data); |
757 | 751 | ||
758 | /* codec sample rate select */ | 752 | /* codec sample rate select */ |
759 | data = aic3x_divs[i].sr_reg; | 753 | data = (fsref * 20) / params_rate(params); |
754 | if (params_rate(params) < 64000) | ||
755 | data /= 2; | ||
756 | data /= 5; | ||
757 | data -= 2; | ||
760 | data |= (data << 4); | 758 | data |= (data << 4); |
761 | aic3x_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data); | 759 | aic3x_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data); |
762 | 760 | ||
763 | /* Use PLL for generation Fsref by equation: | 761 | if (bypass_pll) |
764 | * Fsref = (MCLK * K * R)/(2048 * P); | 762 | return 0; |
765 | * Fix P = 2 and R = 1 and calculate K, if | 763 | |
766 | * K = J.D, i.e. J - an interger portion of K and D is the fractional | 764 | /* Use PLL |
767 | * one with 4 digits of precision; | 765 | * find an apropriate setup for j, d, r and p by iterating over |
768 | * Example: | 766 | * p and r - j and d are calculated for each fraction. |
769 | * For MCLK = 22.5792 MHz and Fsref = 48kHz: | 767 | * Up to 128 values are probed, the closest one wins the game. |
770 | * Select P = 2, R= 1, K = 8.7074, which results in J = 8, D = 7074 | 768 | * The sysclk is divided by 1000 to prevent integer overflows. |
771 | */ | 769 | */ |
772 | pll_p = 2; | 770 | codec_clk = (2048 * fsref) / (aic3x->sysclk / 1000); |
773 | pll_r = 1; | 771 | |
774 | pll_j = aic3x_divs[i].pllj_reg; | 772 | for (r = 1; r <= 16; r++) |
775 | pll_d = aic3x_divs[i].plld_reg; | 773 | for (p = 1; p <= 8; p++) { |
774 | int clk, tmp = (codec_clk * pll_r * 10) / pll_p; | ||
775 | u8 j = tmp / 10000; | ||
776 | u16 d = tmp % 10000; | ||
777 | |||
778 | if (j > 63) | ||
779 | continue; | ||
780 | |||
781 | if (d != 0 && aic3x->sysclk < 10000000) | ||
782 | continue; | ||
783 | |||
784 | /* This is actually 1000 * ((j + (d/10000)) * r) / p | ||
785 | * The term had to be converted to get rid of the | ||
786 | * division by 10000 */ | ||
787 | clk = ((10000 * j * r) + (d * r)) / (10 * p); | ||
788 | |||
789 | /* check whether this values get closer than the best | ||
790 | * ones we had before */ | ||
791 | if (abs(codec_clk - clk) < abs(codec_clk - last_clk)) { | ||
792 | pll_j = j; pll_d = d; pll_r = r; pll_p = p; | ||
793 | last_clk = clk; | ||
794 | } | ||
795 | |||
796 | /* Early exit for exact matches */ | ||
797 | if (clk == codec_clk) | ||
798 | break; | ||
799 | } | ||
800 | |||
801 | if (last_clk == 0) { | ||
802 | printk(KERN_ERR "%s(): unable to setup PLL\n", __func__); | ||
803 | return -EINVAL; | ||
804 | } | ||
776 | 805 | ||
777 | data = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); | 806 | data = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); |
778 | 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)); |
@@ -782,28 +811,10 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, | |||
782 | aic3x_write(codec, AIC3X_PLL_PROGD_REG, | 811 | aic3x_write(codec, AIC3X_PLL_PROGD_REG, |
783 | (pll_d & 0x3F) << PLLD_LSB_SHIFT); | 812 | (pll_d & 0x3F) << PLLD_LSB_SHIFT); |
784 | 813 | ||
785 | /* select data word length */ | ||
786 | data = | ||
787 | aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4)); | ||
788 | switch (params_format(params)) { | ||
789 | case SNDRV_PCM_FORMAT_S16_LE: | ||
790 | break; | ||
791 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
792 | data |= (0x01 << 4); | ||
793 | break; | ||
794 | case SNDRV_PCM_FORMAT_S24_LE: | ||
795 | data |= (0x02 << 4); | ||
796 | break; | ||
797 | case SNDRV_PCM_FORMAT_S32_LE: | ||
798 | data |= (0x03 << 4); | ||
799 | break; | ||
800 | } | ||
801 | aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, data); | ||
802 | |||
803 | return 0; | 814 | return 0; |
804 | } | 815 | } |
805 | 816 | ||
806 | static int aic3x_mute(struct snd_soc_codec_dai *dai, int mute) | 817 | static int aic3x_mute(struct snd_soc_dai *dai, int mute) |
807 | { | 818 | { |
808 | struct snd_soc_codec *codec = dai->codec; | 819 | struct snd_soc_codec *codec = dai->codec; |
809 | 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; |
@@ -820,31 +831,25 @@ static int aic3x_mute(struct snd_soc_codec_dai *dai, int mute) | |||
820 | return 0; | 831 | return 0; |
821 | } | 832 | } |
822 | 833 | ||
823 | static int aic3x_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | 834 | static int aic3x_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
824 | int clk_id, unsigned int freq, int dir) | 835 | int clk_id, unsigned int freq, int dir) |
825 | { | 836 | { |
826 | struct snd_soc_codec *codec = codec_dai->codec; | 837 | struct snd_soc_codec *codec = codec_dai->codec; |
827 | struct aic3x_priv *aic3x = codec->private_data; | 838 | struct aic3x_priv *aic3x = codec->private_data; |
828 | 839 | ||
829 | switch (freq) { | 840 | aic3x->sysclk = freq; |
830 | case 12000000: | 841 | return 0; |
831 | case 19200000: | ||
832 | case 22579200: | ||
833 | case 33868800: | ||
834 | aic3x->sysclk = freq; | ||
835 | return 0; | ||
836 | } | ||
837 | |||
838 | return -EINVAL; | ||
839 | } | 842 | } |
840 | 843 | ||
841 | static int aic3x_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 844 | static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, |
842 | unsigned int fmt) | 845 | unsigned int fmt) |
843 | { | 846 | { |
844 | struct snd_soc_codec *codec = codec_dai->codec; | 847 | struct snd_soc_codec *codec = codec_dai->codec; |
845 | struct aic3x_priv *aic3x = codec->private_data; | 848 | struct aic3x_priv *aic3x = codec->private_data; |
846 | u8 iface_areg = 0; | 849 | u8 iface_areg, iface_breg; |
847 | u8 iface_breg = 0; | 850 | |
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; | ||
848 | 853 | ||
849 | /* set master/slave audio interface */ | 854 | /* set master/slave audio interface */ |
850 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 855 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
@@ -883,13 +888,14 @@ static int aic3x_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | |||
883 | return 0; | 888 | return 0; |
884 | } | 889 | } |
885 | 890 | ||
886 | static int aic3x_dapm_event(struct snd_soc_codec *codec, int event) | 891 | static int aic3x_set_bias_level(struct snd_soc_codec *codec, |
892 | enum snd_soc_bias_level level) | ||
887 | { | 893 | { |
888 | struct aic3x_priv *aic3x = codec->private_data; | 894 | struct aic3x_priv *aic3x = codec->private_data; |
889 | u8 reg; | 895 | u8 reg; |
890 | 896 | ||
891 | switch (event) { | 897 | switch (level) { |
892 | case SNDRV_CTL_POWER_D0: | 898 | case SND_SOC_BIAS_ON: |
893 | /* all power is driven by DAPM system */ | 899 | /* all power is driven by DAPM system */ |
894 | if (aic3x->master) { | 900 | if (aic3x->master) { |
895 | /* enable pll */ | 901 | /* enable pll */ |
@@ -898,10 +904,9 @@ static int aic3x_dapm_event(struct snd_soc_codec *codec, int event) | |||
898 | reg | PLL_ENABLE); | 904 | reg | PLL_ENABLE); |
899 | } | 905 | } |
900 | break; | 906 | break; |
901 | case SNDRV_CTL_POWER_D1: | 907 | case SND_SOC_BIAS_PREPARE: |
902 | case SNDRV_CTL_POWER_D2: | ||
903 | break; | 908 | break; |
904 | case SNDRV_CTL_POWER_D3hot: | 909 | case SND_SOC_BIAS_STANDBY: |
905 | /* | 910 | /* |
906 | * all power is driven by DAPM system, | 911 | * all power is driven by DAPM system, |
907 | * so output power is safe if bypass was set | 912 | * so output power is safe if bypass was set |
@@ -913,7 +918,7 @@ static int aic3x_dapm_event(struct snd_soc_codec *codec, int event) | |||
913 | reg & ~PLL_ENABLE); | 918 | reg & ~PLL_ENABLE); |
914 | } | 919 | } |
915 | break; | 920 | break; |
916 | case SNDRV_CTL_POWER_D3cold: | 921 | case SND_SOC_BIAS_OFF: |
917 | /* force all power off */ | 922 | /* force all power off */ |
918 | reg = aic3x_read_reg_cache(codec, LINE1L_2_LADC_CTRL); | 923 | reg = aic3x_read_reg_cache(codec, LINE1L_2_LADC_CTRL); |
919 | aic3x_write(codec, LINE1L_2_LADC_CTRL, reg & ~LADC_PWR_ON); | 924 | aic3x_write(codec, LINE1L_2_LADC_CTRL, reg & ~LADC_PWR_ON); |
@@ -949,16 +954,43 @@ static int aic3x_dapm_event(struct snd_soc_codec *codec, int event) | |||
949 | } | 954 | } |
950 | break; | 955 | break; |
951 | } | 956 | } |
952 | codec->dapm_state = event; | 957 | codec->bias_level = level; |
953 | 958 | ||
954 | return 0; | 959 | return 0; |
955 | } | 960 | } |
956 | 961 | ||
962 | void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state) | ||
963 | { | ||
964 | u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG; | ||
965 | u8 bit = gpio ? 3: 0; | ||
966 | u8 val = aic3x_read_reg_cache(codec, reg) & ~(1 << bit); | ||
967 | aic3x_write(codec, reg, val | (!!state << bit)); | ||
968 | } | ||
969 | EXPORT_SYMBOL_GPL(aic3x_set_gpio); | ||
970 | |||
971 | int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio) | ||
972 | { | ||
973 | u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG; | ||
974 | u8 val, bit = gpio ? 2: 1; | ||
975 | |||
976 | aic3x_read(codec, reg, &val); | ||
977 | return (val >> bit) & 1; | ||
978 | } | ||
979 | EXPORT_SYMBOL_GPL(aic3x_get_gpio); | ||
980 | |||
981 | int aic3x_headset_detected(struct snd_soc_codec *codec) | ||
982 | { | ||
983 | u8 val; | ||
984 | aic3x_read(codec, AIC3X_RT_IRQ_FLAGS_REG, &val); | ||
985 | return (val >> 2) & 1; | ||
986 | } | ||
987 | EXPORT_SYMBOL_GPL(aic3x_headset_detected); | ||
988 | |||
957 | #define AIC3X_RATES SNDRV_PCM_RATE_8000_96000 | 989 | #define AIC3X_RATES SNDRV_PCM_RATE_8000_96000 |
958 | #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 | \ |
959 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) | 991 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) |
960 | 992 | ||
961 | struct snd_soc_codec_dai aic3x_dai = { | 993 | struct snd_soc_dai aic3x_dai = { |
962 | .name = "aic3x", | 994 | .name = "aic3x", |
963 | .playback = { | 995 | .playback = { |
964 | .stream_name = "Playback", | 996 | .stream_name = "Playback", |
@@ -988,7 +1020,7 @@ static int aic3x_suspend(struct platform_device *pdev, pm_message_t state) | |||
988 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1020 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
989 | struct snd_soc_codec *codec = socdev->codec; | 1021 | struct snd_soc_codec *codec = socdev->codec; |
990 | 1022 | ||
991 | aic3x_dapm_event(codec, SNDRV_CTL_POWER_D3cold); | 1023 | aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); |
992 | 1024 | ||
993 | return 0; | 1025 | return 0; |
994 | } | 1026 | } |
@@ -1008,7 +1040,7 @@ static int aic3x_resume(struct platform_device *pdev) | |||
1008 | codec->hw_write(codec->control_data, data, 2); | 1040 | codec->hw_write(codec->control_data, data, 2); |
1009 | } | 1041 | } |
1010 | 1042 | ||
1011 | aic3x_dapm_event(codec, codec->suspend_dapm_state); | 1043 | aic3x_set_bias_level(codec, codec->suspend_bias_level); |
1012 | 1044 | ||
1013 | return 0; | 1045 | return 0; |
1014 | } | 1046 | } |
@@ -1020,16 +1052,17 @@ static int aic3x_resume(struct platform_device *pdev) | |||
1020 | static int aic3x_init(struct snd_soc_device *socdev) | 1052 | static int aic3x_init(struct snd_soc_device *socdev) |
1021 | { | 1053 | { |
1022 | struct snd_soc_codec *codec = socdev->codec; | 1054 | struct snd_soc_codec *codec = socdev->codec; |
1055 | struct aic3x_setup_data *setup = socdev->codec_data; | ||
1023 | int reg, ret = 0; | 1056 | int reg, ret = 0; |
1024 | 1057 | ||
1025 | codec->name = "aic3x"; | 1058 | codec->name = "aic3x"; |
1026 | codec->owner = THIS_MODULE; | 1059 | codec->owner = THIS_MODULE; |
1027 | codec->read = aic3x_read_reg_cache; | 1060 | codec->read = aic3x_read_reg_cache; |
1028 | codec->write = aic3x_write; | 1061 | codec->write = aic3x_write; |
1029 | codec->dapm_event = aic3x_dapm_event; | 1062 | codec->set_bias_level = aic3x_set_bias_level; |
1030 | codec->dai = &aic3x_dai; | 1063 | codec->dai = &aic3x_dai; |
1031 | codec->num_dai = 1; | 1064 | codec->num_dai = 1; |
1032 | codec->reg_cache_size = sizeof(aic3x_reg); | 1065 | codec->reg_cache_size = ARRAY_SIZE(aic3x_reg); |
1033 | codec->reg_cache = kmemdup(aic3x_reg, sizeof(aic3x_reg), GFP_KERNEL); | 1066 | codec->reg_cache = kmemdup(aic3x_reg, sizeof(aic3x_reg), GFP_KERNEL); |
1034 | if (codec->reg_cache == NULL) | 1067 | if (codec->reg_cache == NULL) |
1035 | return -ENOMEM; | 1068 | return -ENOMEM; |
@@ -1108,7 +1141,11 @@ static int aic3x_init(struct snd_soc_device *socdev) | |||
1108 | aic3x_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL); | 1141 | aic3x_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL); |
1109 | 1142 | ||
1110 | /* off, with power on */ | 1143 | /* off, with power on */ |
1111 | aic3x_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | 1144 | aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1145 | |||
1146 | /* setup GPIO functions */ | ||
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); | ||
1112 | 1149 | ||
1113 | aic3x_add_controls(codec); | 1150 | aic3x_add_controls(codec); |
1114 | aic3x_add_widgets(codec); | 1151 | aic3x_add_widgets(codec); |
@@ -1217,6 +1254,12 @@ static struct i2c_client client_template = { | |||
1217 | .name = "AIC3X", | 1254 | .name = "AIC3X", |
1218 | .driver = &aic3x_i2c_driver, | 1255 | .driver = &aic3x_i2c_driver, |
1219 | }; | 1256 | }; |
1257 | |||
1258 | static int aic3x_i2c_read(struct i2c_client *client, u8 *value, int len) | ||
1259 | { | ||
1260 | value[0] = i2c_smbus_read_byte_data(client, value[0]); | ||
1261 | return (len == 1); | ||
1262 | } | ||
1220 | #endif | 1263 | #endif |
1221 | 1264 | ||
1222 | static int aic3x_probe(struct platform_device *pdev) | 1265 | static int aic3x_probe(struct platform_device *pdev) |
@@ -1251,6 +1294,7 @@ static int aic3x_probe(struct platform_device *pdev) | |||
1251 | if (setup->i2c_address) { | 1294 | if (setup->i2c_address) { |
1252 | normal_i2c[0] = setup->i2c_address; | 1295 | normal_i2c[0] = setup->i2c_address; |
1253 | codec->hw_write = (hw_write_t) i2c_master_send; | 1296 | codec->hw_write = (hw_write_t) i2c_master_send; |
1297 | codec->hw_read = (hw_read_t) aic3x_i2c_read; | ||
1254 | ret = i2c_add_driver(&aic3x_i2c_driver); | 1298 | ret = i2c_add_driver(&aic3x_i2c_driver); |
1255 | if (ret != 0) | 1299 | if (ret != 0) |
1256 | printk(KERN_ERR "can't add i2c driver"); | 1300 | printk(KERN_ERR "can't add i2c driver"); |
@@ -1268,7 +1312,7 @@ static int aic3x_remove(struct platform_device *pdev) | |||
1268 | 1312 | ||
1269 | /* power down chip */ | 1313 | /* power down chip */ |
1270 | if (codec->control_data) | 1314 | if (codec->control_data) |
1271 | aic3x_dapm_event(codec, SNDRV_CTL_POWER_D3); | 1315 | aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1272 | 1316 | ||
1273 | snd_soc_free_pcms(socdev); | 1317 | snd_soc_free_pcms(socdev); |
1274 | snd_soc_dapm_free(socdev); | 1318 | snd_soc_dapm_free(socdev); |
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h index d0cdeeb629de..d76c079b86e7 100644 --- a/sound/soc/codecs/tlv320aic3x.h +++ b/sound/soc/codecs/tlv320aic3x.h | |||
@@ -37,6 +37,8 @@ | |||
37 | #define AIC3X_ASD_INTF_CTRLB 9 | 37 | #define AIC3X_ASD_INTF_CTRLB 9 |
38 | /* Audio overflow status and PLL R value programming register */ | 38 | /* Audio overflow status and PLL R value programming register */ |
39 | #define AIC3X_OVRF_STATUS_AND_PLLR_REG 11 | 39 | #define AIC3X_OVRF_STATUS_AND_PLLR_REG 11 |
40 | /* Audio codec digital filter control register */ | ||
41 | #define AIC3X_CODEC_DFILT_CTRL 12 | ||
40 | 42 | ||
41 | /* ADC PGA Gain control registers */ | 43 | /* ADC PGA Gain control registers */ |
42 | #define LADC_VOL 15 | 44 | #define LADC_VOL 15 |
@@ -108,6 +110,13 @@ | |||
108 | #define DACR1_2_RLOPM_VOL 92 | 110 | #define DACR1_2_RLOPM_VOL 92 |
109 | #define LLOPM_CTRL 86 | 111 | #define LLOPM_CTRL 86 |
110 | #define RLOPM_CTRL 93 | 112 | #define RLOPM_CTRL 93 |
113 | /* GPIO/IRQ registers */ | ||
114 | #define AIC3X_STICKY_IRQ_FLAGS_REG 96 | ||
115 | #define AIC3X_RT_IRQ_FLAGS_REG 97 | ||
116 | #define AIC3X_GPIO1_REG 98 | ||
117 | #define AIC3X_GPIO2_REG 99 | ||
118 | #define AIC3X_GPIOA_REG 100 | ||
119 | #define AIC3X_GPIOB_REG 101 | ||
111 | /* Clock generation control register */ | 120 | /* Clock generation control register */ |
112 | #define AIC3X_CLKGEN_CTRL_REG 102 | 121 | #define AIC3X_CLKGEN_CTRL_REG 102 |
113 | 122 | ||
@@ -128,12 +137,15 @@ | |||
128 | 137 | ||
129 | /* PLL registers bitfields */ | 138 | /* PLL registers bitfields */ |
130 | #define PLLP_SHIFT 0 | 139 | #define PLLP_SHIFT 0 |
140 | #define PLLQ_SHIFT 3 | ||
131 | #define PLLR_SHIFT 0 | 141 | #define PLLR_SHIFT 0 |
132 | #define PLLJ_SHIFT 2 | 142 | #define PLLJ_SHIFT 2 |
133 | #define PLLD_MSB_SHIFT 0 | 143 | #define PLLD_MSB_SHIFT 0 |
134 | #define PLLD_LSB_SHIFT 2 | 144 | #define PLLD_LSB_SHIFT 2 |
135 | 145 | ||
136 | /* Clock generation register bits */ | 146 | /* Clock generation register bits */ |
147 | #define CODEC_CLKIN_PLLDIV 0 | ||
148 | #define CODEC_CLKIN_CLKDIV 1 | ||
137 | #define PLL_CLKIN_SHIFT 4 | 149 | #define PLL_CLKIN_SHIFT 4 |
138 | #define MCLK_SOURCE 0x0 | 150 | #define MCLK_SOURCE 0x0 |
139 | #define PLL_CLKDIV_SHIFT 0 | 151 | #define PLL_CLKDIV_SHIFT 0 |
@@ -171,11 +183,52 @@ | |||
171 | /* Default input volume */ | 183 | /* Default input volume */ |
172 | #define DEFAULT_GAIN 0x20 | 184 | #define DEFAULT_GAIN 0x20 |
173 | 185 | ||
186 | /* GPIO API */ | ||
187 | enum { | ||
188 | AIC3X_GPIO1_FUNC_DISABLED = 0, | ||
189 | AIC3X_GPIO1_FUNC_AUDIO_WORDCLK_ADC = 1, | ||
190 | AIC3X_GPIO1_FUNC_CLOCK_MUX = 2, | ||
191 | AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV2 = 3, | ||
192 | AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV4 = 4, | ||
193 | AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV8 = 5, | ||
194 | AIC3X_GPIO1_FUNC_SHORT_CIRCUIT_IRQ = 6, | ||
195 | AIC3X_GPIO1_FUNC_AGC_NOISE_IRQ = 7, | ||
196 | AIC3X_GPIO1_FUNC_INPUT = 8, | ||
197 | AIC3X_GPIO1_FUNC_OUTPUT = 9, | ||
198 | AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK = 10, | ||
199 | AIC3X_GPIO1_FUNC_AUDIO_WORDCLK = 11, | ||
200 | AIC3X_GPIO1_FUNC_BUTTON_IRQ = 12, | ||
201 | AIC3X_GPIO1_FUNC_HEADSET_DETECT_IRQ = 13, | ||
202 | AIC3X_GPIO1_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 14, | ||
203 | AIC3X_GPIO1_FUNC_ALL_IRQ = 16 | ||
204 | }; | ||
205 | |||
206 | enum { | ||
207 | AIC3X_GPIO2_FUNC_DISABLED = 0, | ||
208 | AIC3X_GPIO2_FUNC_HEADSET_DETECT_IRQ = 2, | ||
209 | AIC3X_GPIO2_FUNC_INPUT = 3, | ||
210 | AIC3X_GPIO2_FUNC_OUTPUT = 4, | ||
211 | AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT = 5, | ||
212 | AIC3X_GPIO2_FUNC_AUDIO_BITCLK = 8, | ||
213 | AIC3X_GPIO2_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 9, | ||
214 | AIC3X_GPIO2_FUNC_ALL_IRQ = 10, | ||
215 | AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_OR_AGC_IRQ = 11, | ||
216 | AIC3X_GPIO2_FUNC_HEADSET_OR_BUTTON_PRESS_OR_SHORT_CIRCUIT_IRQ = 12, | ||
217 | AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_IRQ = 13, | ||
218 | AIC3X_GPIO2_FUNC_AGC_NOISE_IRQ = 14, | ||
219 | AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ = 15 | ||
220 | }; | ||
221 | |||
222 | void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state); | ||
223 | int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio); | ||
224 | int aic3x_headset_detected(struct snd_soc_codec *codec); | ||
225 | |||
174 | struct aic3x_setup_data { | 226 | struct aic3x_setup_data { |
175 | unsigned short i2c_address; | 227 | unsigned short i2c_address; |
228 | unsigned int gpio_func[2]; | ||
176 | }; | 229 | }; |
177 | 230 | ||
178 | extern struct snd_soc_codec_dai aic3x_dai; | 231 | extern struct snd_soc_dai aic3x_dai; |
179 | extern struct snd_soc_codec_device soc_codec_dev_aic3x; | 232 | extern struct snd_soc_codec_device soc_codec_dev_aic3x; |
180 | 233 | ||
181 | #endif /* _AIC3X_H */ | 234 | #endif /* _AIC3X_H */ |
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c new file mode 100644 index 000000000000..a52d6d9e007a --- /dev/null +++ b/sound/soc/codecs/uda1380.c | |||
@@ -0,0 +1,852 @@ | |||
1 | /* | ||
2 | * uda1380.c - Philips UDA1380 ALSA SoC audio driver | ||
3 | * | ||
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 | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * Copyright (c) 2007 Philipp Zabel <philipp.zabel@gmail.com> | ||
9 | * Improved support for DAPM and audio routing/mixing capabilities, | ||
10 | * added TLV support. | ||
11 | * | ||
12 | * Modified by Richard Purdie <richard@openedhand.com> to fit into SoC | ||
13 | * codec model. | ||
14 | * | ||
15 | * Copyright (c) 2005 Giorgio Padrin <giorgio@mandarinlogiq.org> | ||
16 | * Copyright 2005 Openedhand Ltd. | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/types.h> | ||
22 | #include <linux/string.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/errno.h> | ||
25 | #include <linux/ioctl.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/i2c.h> | ||
28 | #include <sound/core.h> | ||
29 | #include <sound/control.h> | ||
30 | #include <sound/initval.h> | ||
31 | #include <sound/info.h> | ||
32 | #include <sound/soc.h> | ||
33 | #include <sound/soc-dapm.h> | ||
34 | #include <sound/tlv.h> | ||
35 | |||
36 | #include "uda1380.h" | ||
37 | |||
38 | #define UDA1380_VERSION "0.6" | ||
39 | #define AUDIO_NAME "uda1380" | ||
40 | |||
41 | /* | ||
42 | * uda1380 register cache | ||
43 | */ | ||
44 | static const u16 uda1380_reg[UDA1380_CACHEREGNUM] = { | ||
45 | 0x0502, 0x0000, 0x0000, 0x3f3f, | ||
46 | 0x0202, 0x0000, 0x0000, 0x0000, | ||
47 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
48 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
49 | 0x0000, 0xff00, 0x0000, 0x4800, | ||
50 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
51 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
52 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
53 | 0x0000, 0x8000, 0x0002, 0x0000, | ||
54 | }; | ||
55 | |||
56 | /* | ||
57 | * read uda1380 register cache | ||
58 | */ | ||
59 | static inline unsigned int uda1380_read_reg_cache(struct snd_soc_codec *codec, | ||
60 | unsigned int reg) | ||
61 | { | ||
62 | u16 *cache = codec->reg_cache; | ||
63 | if (reg == UDA1380_RESET) | ||
64 | return 0; | ||
65 | if (reg >= UDA1380_CACHEREGNUM) | ||
66 | return -1; | ||
67 | return cache[reg]; | ||
68 | } | ||
69 | |||
70 | /* | ||
71 | * write uda1380 register cache | ||
72 | */ | ||
73 | static inline void uda1380_write_reg_cache(struct snd_soc_codec *codec, | ||
74 | u16 reg, unsigned int value) | ||
75 | { | ||
76 | u16 *cache = codec->reg_cache; | ||
77 | if (reg >= UDA1380_CACHEREGNUM) | ||
78 | return; | ||
79 | cache[reg] = value; | ||
80 | } | ||
81 | |||
82 | /* | ||
83 | * write to the UDA1380 register space | ||
84 | */ | ||
85 | static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg, | ||
86 | unsigned int value) | ||
87 | { | ||
88 | u8 data[3]; | ||
89 | |||
90 | /* data is | ||
91 | * data[0] is register offset | ||
92 | * data[1] is MS byte | ||
93 | * data[2] is LS byte | ||
94 | */ | ||
95 | data[0] = reg; | ||
96 | data[1] = (value & 0xff00) >> 8; | ||
97 | data[2] = value & 0x00ff; | ||
98 | |||
99 | uda1380_write_reg_cache(codec, reg, value); | ||
100 | |||
101 | /* the interpolator & decimator regs must only be written when the | ||
102 | * codec DAI is active. | ||
103 | */ | ||
104 | if (!codec->active && (reg >= UDA1380_MVOL)) | ||
105 | return 0; | ||
106 | pr_debug("uda1380: hw write %x val %x\n", reg, value); | ||
107 | if (codec->hw_write(codec->control_data, data, 3) == 3) { | ||
108 | unsigned int val; | ||
109 | i2c_master_send(codec->control_data, data, 1); | ||
110 | i2c_master_recv(codec->control_data, data, 2); | ||
111 | val = (data[0]<<8) | data[1]; | ||
112 | if (val != value) { | ||
113 | pr_debug("uda1380: READ BACK VAL %x\n", | ||
114 | (data[0]<<8) | data[1]); | ||
115 | return -EIO; | ||
116 | } | ||
117 | return 0; | ||
118 | } else | ||
119 | return -EIO; | ||
120 | } | ||
121 | |||
122 | #define uda1380_reset(c) uda1380_write(c, UDA1380_RESET, 0) | ||
123 | |||
124 | /* declarations of ALSA reg_elem_REAL controls */ | ||
125 | static const char *uda1380_deemp[] = { | ||
126 | "None", | ||
127 | "32kHz", | ||
128 | "44.1kHz", | ||
129 | "48kHz", | ||
130 | "96kHz", | ||
131 | }; | ||
132 | static const char *uda1380_input_sel[] = { | ||
133 | "Line", | ||
134 | "Mic + Line R", | ||
135 | "Line L", | ||
136 | "Mic", | ||
137 | }; | ||
138 | static const char *uda1380_output_sel[] = { | ||
139 | "DAC", | ||
140 | "Analog Mixer", | ||
141 | }; | ||
142 | static const char *uda1380_spf_mode[] = { | ||
143 | "Flat", | ||
144 | "Minimum1", | ||
145 | "Minimum2", | ||
146 | "Maximum" | ||
147 | }; | ||
148 | static const char *uda1380_capture_sel[] = { | ||
149 | "ADC", | ||
150 | "Digital Mixer" | ||
151 | }; | ||
152 | static const char *uda1380_sel_ns[] = { | ||
153 | "3rd-order", | ||
154 | "5th-order" | ||
155 | }; | ||
156 | static const char *uda1380_mix_control[] = { | ||
157 | "off", | ||
158 | "PCM only", | ||
159 | "before sound processing", | ||
160 | "after sound processing" | ||
161 | }; | ||
162 | static const char *uda1380_sdet_setting[] = { | ||
163 | "3200", | ||
164 | "4800", | ||
165 | "9600", | ||
166 | "19200" | ||
167 | }; | ||
168 | static const char *uda1380_os_setting[] = { | ||
169 | "single-speed", | ||
170 | "double-speed (no mixing)", | ||
171 | "quad-speed (no mixing)" | ||
172 | }; | ||
173 | |||
174 | static const struct soc_enum uda1380_deemp_enum[] = { | ||
175 | SOC_ENUM_SINGLE(UDA1380_DEEMP, 8, 5, uda1380_deemp), | ||
176 | SOC_ENUM_SINGLE(UDA1380_DEEMP, 0, 5, uda1380_deemp), | ||
177 | }; | ||
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 */ | ||
180 | static const struct soc_enum uda1380_output_sel_enum = | ||
181 | SOC_ENUM_SINGLE(UDA1380_PM, 7, 2, uda1380_output_sel); /* R02_EN_AVC */ | ||
182 | static const struct soc_enum uda1380_spf_enum = | ||
183 | SOC_ENUM_SINGLE(UDA1380_MODE, 14, 4, uda1380_spf_mode); /* M */ | ||
184 | static const struct soc_enum uda1380_capture_sel_enum = | ||
185 | SOC_ENUM_SINGLE(UDA1380_IFACE, 6, 2, uda1380_capture_sel); /* SEL_SOURCE */ | ||
186 | static const struct soc_enum uda1380_sel_ns_enum = | ||
187 | SOC_ENUM_SINGLE(UDA1380_MIXER, 14, 2, uda1380_sel_ns); /* SEL_NS */ | ||
188 | static const struct soc_enum uda1380_mix_enum = | ||
189 | SOC_ENUM_SINGLE(UDA1380_MIXER, 12, 4, uda1380_mix_control); /* MIX, MIX_POS */ | ||
190 | static const struct soc_enum uda1380_sdet_enum = | ||
191 | SOC_ENUM_SINGLE(UDA1380_MIXER, 4, 4, uda1380_sdet_setting); /* SD_VALUE */ | ||
192 | static const struct soc_enum uda1380_os_enum = | ||
193 | SOC_ENUM_SINGLE(UDA1380_MIXER, 0, 3, uda1380_os_setting); /* OS */ | ||
194 | |||
195 | /* | ||
196 | * from -48 dB in 1.5 dB steps (mute instead of -49.5 dB) | ||
197 | */ | ||
198 | static DECLARE_TLV_DB_SCALE(amix_tlv, -4950, 150, 1); | ||
199 | |||
200 | /* | ||
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 | ||
203 | * from -52 dB in 0.25 dB steps | ||
204 | */ | ||
205 | static const unsigned int mvol_tlv[] = { | ||
206 | TLV_DB_RANGE_HEAD(3), | ||
207 | 0, 15, TLV_DB_SCALE_ITEM(-8200, 100, 1), | ||
208 | 16, 43, TLV_DB_SCALE_ITEM(-6600, 50, 0), | ||
209 | 44, 252, TLV_DB_SCALE_ITEM(-5200, 25, 0), | ||
210 | }; | ||
211 | |||
212 | /* | ||
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), | ||
215 | * from -60 dB in 0.5 dB steps (2 dB steps really) and | ||
216 | * from -46 dB in 0.25 dB steps | ||
217 | */ | ||
218 | static const unsigned int vc_tlv[] = { | ||
219 | TLV_DB_RANGE_HEAD(4), | ||
220 | 0, 7, TLV_DB_SCALE_ITEM(-7800, 150, 1), | ||
221 | 8, 15, TLV_DB_SCALE_ITEM(-6600, 75, 0), | ||
222 | 16, 43, TLV_DB_SCALE_ITEM(-6000, 50, 0), | ||
223 | 44, 228, TLV_DB_SCALE_ITEM(-4600, 25, 0), | ||
224 | }; | ||
225 | |||
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); | ||
228 | |||
229 | /* from 0 to 24 dB in 2 dB steps, if SPF mode == maximum, otherwise cuts | ||
230 | * off at 18 dB max) */ | ||
231 | static DECLARE_TLV_DB_SCALE(bb_tlv, 0, 200, 0); | ||
232 | |||
233 | /* from -63 to 24 dB in 0.5 dB steps (-128...48) */ | ||
234 | static DECLARE_TLV_DB_SCALE(dec_tlv, -6400, 50, 1); | ||
235 | |||
236 | /* from 0 to 24 dB in 3 dB steps */ | ||
237 | static DECLARE_TLV_DB_SCALE(pga_tlv, 0, 300, 0); | ||
238 | |||
239 | /* from 0 to 30 dB in 2 dB steps */ | ||
240 | static DECLARE_TLV_DB_SCALE(vga_tlv, 0, 200, 0); | ||
241 | |||
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 */ | ||
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 */ | ||
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 */ | ||
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 */ | ||
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 */ | ||
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 */ | ||
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 */ | ||
256 | SOC_ENUM("Noise Shaper", uda1380_sel_ns_enum), /* SEL_NS */ | ||
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 */ | ||
259 | SOC_SINGLE("Silence Detector Switch", UDA1380_MIXER, 6, 1, 0), /* SDET_ON */ | ||
260 | SOC_ENUM("Silence Detector Setting", uda1380_sdet_enum), /* SD_VALUE */ | ||
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 */ | ||
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 */ | ||
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 */ | ||
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) */ | ||
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 */ | ||
271 | /* -5.5, -8, -11.5, -14 dBFS */ | ||
272 | SOC_SINGLE("AGC Switch", UDA1380_AGC, 0, 1, 0), | ||
273 | }; | ||
274 | |||
275 | /* add non dapm controls */ | ||
276 | static int uda1380_add_controls(struct snd_soc_codec *codec) | ||
277 | { | ||
278 | int err, i; | ||
279 | |||
280 | for (i = 0; i < ARRAY_SIZE(uda1380_snd_controls); i++) { | ||
281 | err = snd_ctl_add(codec->card, | ||
282 | snd_soc_cnew(&uda1380_snd_controls[i], codec, NULL)); | ||
283 | if (err < 0) | ||
284 | return err; | ||
285 | } | ||
286 | |||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | /* Input mux */ | ||
291 | static const struct snd_kcontrol_new uda1380_input_mux_control = | ||
292 | SOC_DAPM_ENUM("Route", uda1380_input_sel_enum); | ||
293 | |||
294 | /* Output mux */ | ||
295 | static const struct snd_kcontrol_new uda1380_output_mux_control = | ||
296 | SOC_DAPM_ENUM("Route", uda1380_output_sel_enum); | ||
297 | |||
298 | /* Capture mux */ | ||
299 | static const struct snd_kcontrol_new uda1380_capture_mux_control = | ||
300 | SOC_DAPM_ENUM("Route", uda1380_capture_sel_enum); | ||
301 | |||
302 | |||
303 | static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = { | ||
304 | SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, | ||
305 | &uda1380_input_mux_control), | ||
306 | SND_SOC_DAPM_MUX("Output Mux", SND_SOC_NOPM, 0, 0, | ||
307 | &uda1380_output_mux_control), | ||
308 | SND_SOC_DAPM_MUX("Capture Mux", SND_SOC_NOPM, 0, 0, | ||
309 | &uda1380_capture_mux_control), | ||
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), | ||
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), | ||
314 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", UDA1380_PM, 0, 0), | ||
315 | SND_SOC_DAPM_INPUT("VINM"), | ||
316 | SND_SOC_DAPM_INPUT("VINL"), | ||
317 | SND_SOC_DAPM_INPUT("VINR"), | ||
318 | SND_SOC_DAPM_MIXER("Analog Mixer", UDA1380_PM, 6, 0, NULL, 0), | ||
319 | SND_SOC_DAPM_OUTPUT("VOUTLHP"), | ||
320 | SND_SOC_DAPM_OUTPUT("VOUTRHP"), | ||
321 | SND_SOC_DAPM_OUTPUT("VOUTL"), | ||
322 | SND_SOC_DAPM_OUTPUT("VOUTR"), | ||
323 | SND_SOC_DAPM_DAC("DAC", "Playback", UDA1380_PM, 10, 0), | ||
324 | SND_SOC_DAPM_PGA("HeadPhone Driver", UDA1380_PM, 13, 0, NULL, 0), | ||
325 | }; | ||
326 | |||
327 | static const struct snd_soc_dapm_route audio_map[] = { | ||
328 | |||
329 | /* output mux */ | ||
330 | {"HeadPhone Driver", NULL, "Output Mux"}, | ||
331 | {"VOUTR", NULL, "Output Mux"}, | ||
332 | {"VOUTL", NULL, "Output Mux"}, | ||
333 | |||
334 | {"Analog Mixer", NULL, "VINR"}, | ||
335 | {"Analog Mixer", NULL, "VINL"}, | ||
336 | {"Analog Mixer", NULL, "DAC"}, | ||
337 | |||
338 | {"Output Mux", "DAC", "DAC"}, | ||
339 | {"Output Mux", "Analog Mixer", "Analog Mixer"}, | ||
340 | |||
341 | /* {"DAC", "Digital Mixer", "I2S" } */ | ||
342 | |||
343 | /* headphone driver */ | ||
344 | {"VOUTLHP", NULL, "HeadPhone Driver"}, | ||
345 | {"VOUTRHP", NULL, "HeadPhone Driver"}, | ||
346 | |||
347 | /* input mux */ | ||
348 | {"Left ADC", NULL, "Input Mux"}, | ||
349 | {"Input Mux", "Mic", "Mic LNA"}, | ||
350 | {"Input Mux", "Mic + Line R", "Mic LNA"}, | ||
351 | {"Input Mux", "Line L", "Left PGA"}, | ||
352 | {"Input Mux", "Line", "Left PGA"}, | ||
353 | |||
354 | /* right input */ | ||
355 | {"Right ADC", "Mic + Line R", "Right PGA"}, | ||
356 | {"Right ADC", "Line", "Right PGA"}, | ||
357 | |||
358 | /* inputs */ | ||
359 | {"Mic LNA", NULL, "VINM"}, | ||
360 | {"Left PGA", NULL, "VINL"}, | ||
361 | {"Right PGA", NULL, "VINR"}, | ||
362 | }; | ||
363 | |||
364 | static int uda1380_add_widgets(struct snd_soc_codec *codec) | ||
365 | { | ||
366 | snd_soc_dapm_new_controls(codec, uda1380_dapm_widgets, | ||
367 | ARRAY_SIZE(uda1380_dapm_widgets)); | ||
368 | |||
369 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
370 | |||
371 | snd_soc_dapm_new_widgets(codec); | ||
372 | return 0; | ||
373 | } | ||
374 | |||
375 | static int uda1380_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
376 | unsigned int fmt) | ||
377 | { | ||
378 | struct snd_soc_codec *codec = codec_dai->codec; | ||
379 | int iface; | ||
380 | |||
381 | /* set up DAI based upon fmt */ | ||
382 | iface = uda1380_read_reg_cache(codec, UDA1380_IFACE); | ||
383 | iface &= ~(R01_SFORI_MASK | R01_SIM | R01_SFORO_MASK); | ||
384 | |||
385 | /* FIXME: how to select I2S for DATAO and MSB for DATAI correctly? */ | ||
386 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
387 | case SND_SOC_DAIFMT_I2S: | ||
388 | iface |= R01_SFORI_I2S | R01_SFORO_I2S; | ||
389 | break; | ||
390 | case SND_SOC_DAIFMT_LSB: | ||
391 | iface |= R01_SFORI_LSB16 | R01_SFORO_I2S; | ||
392 | break; | ||
393 | case SND_SOC_DAIFMT_MSB: | ||
394 | iface |= R01_SFORI_MSB | R01_SFORO_I2S; | ||
395 | } | ||
396 | |||
397 | if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM) | ||
398 | iface |= R01_SIM; | ||
399 | |||
400 | uda1380_write(codec, UDA1380_IFACE, iface); | ||
401 | |||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | /* | ||
406 | * Flush reg cache | ||
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 | ||
409 | * machine and cpu DAI driver to do this before we are called. | ||
410 | */ | ||
411 | static int uda1380_pcm_prepare(struct snd_pcm_substream *substream) | ||
412 | { | ||
413 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
414 | struct snd_soc_device *socdev = rtd->socdev; | ||
415 | struct snd_soc_codec *codec = socdev->codec; | ||
416 | int reg, reg_start, reg_end, clk; | ||
417 | |||
418 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
419 | reg_start = UDA1380_MVOL; | ||
420 | reg_end = UDA1380_MIXER; | ||
421 | } else { | ||
422 | reg_start = UDA1380_DEC; | ||
423 | reg_end = UDA1380_AGC; | ||
424 | } | ||
425 | |||
426 | /* FIXME disable DAC_CLK */ | ||
427 | clk = uda1380_read_reg_cache(codec, UDA1380_CLK); | ||
428 | uda1380_write(codec, UDA1380_CLK, clk & ~R00_DAC_CLK); | ||
429 | |||
430 | for (reg = reg_start; reg <= reg_end; reg++) { | ||
431 | pr_debug("uda1380: flush reg %x val %x:", reg, | ||
432 | uda1380_read_reg_cache(codec, reg)); | ||
433 | uda1380_write(codec, reg, uda1380_read_reg_cache(codec, reg)); | ||
434 | } | ||
435 | |||
436 | /* FIXME enable DAC_CLK */ | ||
437 | uda1380_write(codec, UDA1380_CLK, clk | R00_DAC_CLK); | ||
438 | |||
439 | return 0; | ||
440 | } | ||
441 | |||
442 | static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream, | ||
443 | struct snd_pcm_hw_params *params) | ||
444 | { | ||
445 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
446 | struct snd_soc_device *socdev = rtd->socdev; | ||
447 | struct snd_soc_codec *codec = socdev->codec; | ||
448 | u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK); | ||
449 | |||
450 | /* set WSPLL power and divider if running from this clock */ | ||
451 | if (clk & R00_DAC_CLK) { | ||
452 | int rate = params_rate(params); | ||
453 | u16 pm = uda1380_read_reg_cache(codec, UDA1380_PM); | ||
454 | clk &= ~0x3; /* clear SEL_LOOP_DIV */ | ||
455 | switch (rate) { | ||
456 | case 6250 ... 12500: | ||
457 | clk |= 0x0; | ||
458 | break; | ||
459 | case 12501 ... 25000: | ||
460 | clk |= 0x1; | ||
461 | break; | ||
462 | case 25001 ... 50000: | ||
463 | clk |= 0x2; | ||
464 | break; | ||
465 | case 50001 ... 100000: | ||
466 | clk |= 0x3; | ||
467 | break; | ||
468 | } | ||
469 | uda1380_write(codec, UDA1380_PM, R02_PON_PLL | pm); | ||
470 | } | ||
471 | |||
472 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
473 | clk |= R00_EN_DAC | R00_EN_INT; | ||
474 | else | ||
475 | clk |= R00_EN_ADC | R00_EN_DEC; | ||
476 | |||
477 | uda1380_write(codec, UDA1380_CLK, clk); | ||
478 | return 0; | ||
479 | } | ||
480 | |||
481 | static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream) | ||
482 | { | ||
483 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
484 | struct snd_soc_device *socdev = rtd->socdev; | ||
485 | struct snd_soc_codec *codec = socdev->codec; | ||
486 | u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK); | ||
487 | |||
488 | /* shut down WSPLL power if running from this clock */ | ||
489 | if (clk & R00_DAC_CLK) { | ||
490 | u16 pm = uda1380_read_reg_cache(codec, UDA1380_PM); | ||
491 | uda1380_write(codec, UDA1380_PM, ~R02_PON_PLL & pm); | ||
492 | } | ||
493 | |||
494 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
495 | clk &= ~(R00_EN_DAC | R00_EN_INT); | ||
496 | else | ||
497 | clk &= ~(R00_EN_ADC | R00_EN_DEC); | ||
498 | |||
499 | uda1380_write(codec, UDA1380_CLK, clk); | ||
500 | } | ||
501 | |||
502 | static int uda1380_mute(struct snd_soc_dai *codec_dai, int mute) | ||
503 | { | ||
504 | struct snd_soc_codec *codec = codec_dai->codec; | ||
505 | u16 mute_reg = uda1380_read_reg_cache(codec, UDA1380_DEEMP) & ~R13_MTM; | ||
506 | |||
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 | ||
509 | * registers works only when clocked by SYSCLK */ | ||
510 | u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK); | ||
511 | uda1380_write(codec, UDA1380_CLK, ~R00_DAC_CLK & clk); | ||
512 | if (mute) | ||
513 | uda1380_write(codec, UDA1380_DEEMP, mute_reg | R13_MTM); | ||
514 | else | ||
515 | uda1380_write(codec, UDA1380_DEEMP, mute_reg); | ||
516 | uda1380_write(codec, UDA1380_CLK, clk); | ||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | static int uda1380_set_bias_level(struct snd_soc_codec *codec, | ||
521 | enum snd_soc_bias_level level) | ||
522 | { | ||
523 | int pm = uda1380_read_reg_cache(codec, UDA1380_PM); | ||
524 | |||
525 | switch (level) { | ||
526 | case SND_SOC_BIAS_ON: | ||
527 | case SND_SOC_BIAS_PREPARE: | ||
528 | uda1380_write(codec, UDA1380_PM, R02_PON_BIAS | pm); | ||
529 | break; | ||
530 | case SND_SOC_BIAS_STANDBY: | ||
531 | uda1380_write(codec, UDA1380_PM, R02_PON_BIAS); | ||
532 | break; | ||
533 | case SND_SOC_BIAS_OFF: | ||
534 | uda1380_write(codec, UDA1380_PM, 0x0); | ||
535 | break; | ||
536 | } | ||
537 | codec->bias_level = level; | ||
538 | return 0; | ||
539 | } | ||
540 | |||
541 | #define UDA1380_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
542 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ | ||
543 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) | ||
544 | |||
545 | struct snd_soc_dai uda1380_dai[] = { | ||
546 | { | ||
547 | .name = "UDA1380", | ||
548 | .playback = { | ||
549 | .stream_name = "Playback", | ||
550 | .channels_min = 1, | ||
551 | .channels_max = 2, | ||
552 | .rates = UDA1380_RATES, | ||
553 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
554 | .capture = { | ||
555 | .stream_name = "Capture", | ||
556 | .channels_min = 1, | ||
557 | .channels_max = 2, | ||
558 | .rates = UDA1380_RATES, | ||
559 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
560 | .ops = { | ||
561 | .hw_params = uda1380_pcm_hw_params, | ||
562 | .shutdown = uda1380_pcm_shutdown, | ||
563 | .prepare = uda1380_pcm_prepare, | ||
564 | }, | ||
565 | .dai_ops = { | ||
566 | .digital_mute = uda1380_mute, | ||
567 | .set_fmt = uda1380_set_dai_fmt, | ||
568 | }, | ||
569 | }, | ||
570 | { /* playback only - dual interface */ | ||
571 | .name = "UDA1380", | ||
572 | .playback = { | ||
573 | .stream_name = "Playback", | ||
574 | .channels_min = 1, | ||
575 | .channels_max = 2, | ||
576 | .rates = UDA1380_RATES, | ||
577 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
578 | }, | ||
579 | .ops = { | ||
580 | .hw_params = uda1380_pcm_hw_params, | ||
581 | .shutdown = uda1380_pcm_shutdown, | ||
582 | .prepare = uda1380_pcm_prepare, | ||
583 | }, | ||
584 | .dai_ops = { | ||
585 | .digital_mute = uda1380_mute, | ||
586 | .set_fmt = uda1380_set_dai_fmt, | ||
587 | }, | ||
588 | }, | ||
589 | { /* capture only - dual interface*/ | ||
590 | .name = "UDA1380", | ||
591 | .capture = { | ||
592 | .stream_name = "Capture", | ||
593 | .channels_min = 1, | ||
594 | .channels_max = 2, | ||
595 | .rates = UDA1380_RATES, | ||
596 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
597 | }, | ||
598 | .ops = { | ||
599 | .hw_params = uda1380_pcm_hw_params, | ||
600 | .shutdown = uda1380_pcm_shutdown, | ||
601 | .prepare = uda1380_pcm_prepare, | ||
602 | }, | ||
603 | .dai_ops = { | ||
604 | .set_fmt = uda1380_set_dai_fmt, | ||
605 | }, | ||
606 | }, | ||
607 | }; | ||
608 | EXPORT_SYMBOL_GPL(uda1380_dai); | ||
609 | |||
610 | static int uda1380_suspend(struct platform_device *pdev, pm_message_t state) | ||
611 | { | ||
612 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
613 | struct snd_soc_codec *codec = socdev->codec; | ||
614 | |||
615 | uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
616 | return 0; | ||
617 | } | ||
618 | |||
619 | static int uda1380_resume(struct platform_device *pdev) | ||
620 | { | ||
621 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
622 | struct snd_soc_codec *codec = socdev->codec; | ||
623 | int i; | ||
624 | u8 data[2]; | ||
625 | u16 *cache = codec->reg_cache; | ||
626 | |||
627 | /* Sync reg_cache with the hardware */ | ||
628 | for (i = 0; i < ARRAY_SIZE(uda1380_reg); i++) { | ||
629 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); | ||
630 | data[1] = cache[i] & 0x00ff; | ||
631 | codec->hw_write(codec->control_data, data, 2); | ||
632 | } | ||
633 | uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
634 | uda1380_set_bias_level(codec, codec->suspend_bias_level); | ||
635 | return 0; | ||
636 | } | ||
637 | |||
638 | /* | ||
639 | * initialise the UDA1380 driver | ||
640 | * register mixer and dsp interfaces with the kernel | ||
641 | */ | ||
642 | static int uda1380_init(struct snd_soc_device *socdev, int dac_clk) | ||
643 | { | ||
644 | struct snd_soc_codec *codec = socdev->codec; | ||
645 | int ret = 0; | ||
646 | |||
647 | codec->name = "UDA1380"; | ||
648 | codec->owner = THIS_MODULE; | ||
649 | codec->read = uda1380_read_reg_cache; | ||
650 | codec->write = uda1380_write; | ||
651 | codec->set_bias_level = uda1380_set_bias_level; | ||
652 | codec->dai = uda1380_dai; | ||
653 | codec->num_dai = ARRAY_SIZE(uda1380_dai); | ||
654 | codec->reg_cache = kmemdup(uda1380_reg, sizeof(uda1380_reg), | ||
655 | GFP_KERNEL); | ||
656 | if (codec->reg_cache == NULL) | ||
657 | return -ENOMEM; | ||
658 | codec->reg_cache_size = ARRAY_SIZE(uda1380_reg); | ||
659 | codec->reg_cache_step = 1; | ||
660 | uda1380_reset(codec); | ||
661 | |||
662 | /* register pcms */ | ||
663 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
664 | if (ret < 0) { | ||
665 | pr_err("uda1380: failed to create pcms\n"); | ||
666 | goto pcm_err; | ||
667 | } | ||
668 | |||
669 | /* power on device */ | ||
670 | uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
671 | /* set clock input */ | ||
672 | switch (dac_clk) { | ||
673 | case UDA1380_DAC_CLK_SYSCLK: | ||
674 | uda1380_write(codec, UDA1380_CLK, 0); | ||
675 | break; | ||
676 | case UDA1380_DAC_CLK_WSPLL: | ||
677 | uda1380_write(codec, UDA1380_CLK, R00_DAC_CLK); | ||
678 | break; | ||
679 | } | ||
680 | |||
681 | /* uda1380 init */ | ||
682 | uda1380_add_controls(codec); | ||
683 | uda1380_add_widgets(codec); | ||
684 | ret = snd_soc_register_card(socdev); | ||
685 | if (ret < 0) { | ||
686 | pr_err("uda1380: failed to register card\n"); | ||
687 | goto card_err; | ||
688 | } | ||
689 | |||
690 | return ret; | ||
691 | |||
692 | card_err: | ||
693 | snd_soc_free_pcms(socdev); | ||
694 | snd_soc_dapm_free(socdev); | ||
695 | pcm_err: | ||
696 | kfree(codec->reg_cache); | ||
697 | return ret; | ||
698 | } | ||
699 | |||
700 | static struct snd_soc_device *uda1380_socdev; | ||
701 | |||
702 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
703 | |||
704 | #define I2C_DRIVERID_UDA1380 0xfefe /* liam - need a proper id */ | ||
705 | |||
706 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
707 | |||
708 | /* Magic definition of all other variables and things */ | ||
709 | I2C_CLIENT_INSMOD; | ||
710 | |||
711 | static struct i2c_driver uda1380_i2c_driver; | ||
712 | static struct i2c_client client_template; | ||
713 | |||
714 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
715 | around */ | ||
716 | |||
717 | static int uda1380_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
718 | { | ||
719 | struct snd_soc_device *socdev = uda1380_socdev; | ||
720 | struct uda1380_setup_data *setup = socdev->codec_data; | ||
721 | struct snd_soc_codec *codec = socdev->codec; | ||
722 | struct i2c_client *i2c; | ||
723 | int ret; | ||
724 | |||
725 | if (addr != setup->i2c_address) | ||
726 | return -ENODEV; | ||
727 | |||
728 | client_template.adapter = adap; | ||
729 | client_template.addr = addr; | ||
730 | |||
731 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
732 | if (i2c == NULL) { | ||
733 | kfree(codec); | ||
734 | return -ENOMEM; | ||
735 | } | ||
736 | i2c_set_clientdata(i2c, codec); | ||
737 | codec->control_data = i2c; | ||
738 | |||
739 | ret = i2c_attach_client(i2c); | ||
740 | if (ret < 0) { | ||
741 | pr_err("uda1380: failed to attach codec at addr %x\n", addr); | ||
742 | goto err; | ||
743 | } | ||
744 | |||
745 | ret = uda1380_init(socdev, setup->dac_clk); | ||
746 | if (ret < 0) { | ||
747 | pr_err("uda1380: failed to initialise UDA1380\n"); | ||
748 | goto err; | ||
749 | } | ||
750 | return ret; | ||
751 | |||
752 | err: | ||
753 | kfree(codec); | ||
754 | kfree(i2c); | ||
755 | return ret; | ||
756 | } | ||
757 | |||
758 | static int uda1380_i2c_detach(struct i2c_client *client) | ||
759 | { | ||
760 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
761 | i2c_detach_client(client); | ||
762 | kfree(codec->reg_cache); | ||
763 | kfree(client); | ||
764 | return 0; | ||
765 | } | ||
766 | |||
767 | static int uda1380_i2c_attach(struct i2c_adapter *adap) | ||
768 | { | ||
769 | return i2c_probe(adap, &addr_data, uda1380_codec_probe); | ||
770 | } | ||
771 | |||
772 | static struct i2c_driver uda1380_i2c_driver = { | ||
773 | .driver = { | ||
774 | .name = "UDA1380 I2C Codec", | ||
775 | .owner = THIS_MODULE, | ||
776 | }, | ||
777 | .id = I2C_DRIVERID_UDA1380, | ||
778 | .attach_adapter = uda1380_i2c_attach, | ||
779 | .detach_client = uda1380_i2c_detach, | ||
780 | .command = NULL, | ||
781 | }; | ||
782 | |||
783 | static struct i2c_client client_template = { | ||
784 | .name = "UDA1380", | ||
785 | .driver = &uda1380_i2c_driver, | ||
786 | }; | ||
787 | #endif | ||
788 | |||
789 | static int uda1380_probe(struct platform_device *pdev) | ||
790 | { | ||
791 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
792 | struct uda1380_setup_data *setup; | ||
793 | struct snd_soc_codec *codec; | ||
794 | int ret = 0; | ||
795 | |||
796 | pr_info("UDA1380 Audio Codec %s", UDA1380_VERSION); | ||
797 | |||
798 | setup = socdev->codec_data; | ||
799 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
800 | if (codec == NULL) | ||
801 | return -ENOMEM; | ||
802 | |||
803 | socdev->codec = codec; | ||
804 | mutex_init(&codec->mutex); | ||
805 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
806 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
807 | |||
808 | uda1380_socdev = socdev; | ||
809 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
810 | if (setup->i2c_address) { | ||
811 | normal_i2c[0] = setup->i2c_address; | ||
812 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
813 | ret = i2c_add_driver(&uda1380_i2c_driver); | ||
814 | if (ret != 0) | ||
815 | printk(KERN_ERR "can't add i2c driver"); | ||
816 | } | ||
817 | #else | ||
818 | /* Add other interfaces here */ | ||
819 | #endif | ||
820 | return ret; | ||
821 | } | ||
822 | |||
823 | /* power down chip */ | ||
824 | static int uda1380_remove(struct platform_device *pdev) | ||
825 | { | ||
826 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
827 | struct snd_soc_codec *codec = socdev->codec; | ||
828 | |||
829 | if (codec->control_data) | ||
830 | uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
831 | |||
832 | snd_soc_free_pcms(socdev); | ||
833 | snd_soc_dapm_free(socdev); | ||
834 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
835 | i2c_del_driver(&uda1380_i2c_driver); | ||
836 | #endif | ||
837 | kfree(codec); | ||
838 | |||
839 | return 0; | ||
840 | } | ||
841 | |||
842 | struct snd_soc_codec_device soc_codec_dev_uda1380 = { | ||
843 | .probe = uda1380_probe, | ||
844 | .remove = uda1380_remove, | ||
845 | .suspend = uda1380_suspend, | ||
846 | .resume = uda1380_resume, | ||
847 | }; | ||
848 | EXPORT_SYMBOL_GPL(soc_codec_dev_uda1380); | ||
849 | |||
850 | MODULE_AUTHOR("Giorgio Padrin"); | ||
851 | MODULE_DESCRIPTION("Audio support for codec Philips UDA1380"); | ||
852 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/uda1380.h b/sound/soc/codecs/uda1380.h new file mode 100644 index 000000000000..50c603e2c9f2 --- /dev/null +++ b/sound/soc/codecs/uda1380.h | |||
@@ -0,0 +1,89 @@ | |||
1 | /* | ||
2 | * Audio support for Philips UDA1380 | ||
3 | * | ||
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 | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * Copyright (c) 2005 Giorgio Padrin <giorgio@mandarinlogiq.org> | ||
9 | */ | ||
10 | |||
11 | #ifndef _UDA1380_H | ||
12 | #define _UDA1380_H | ||
13 | |||
14 | #define UDA1380_CLK 0x00 | ||
15 | #define UDA1380_IFACE 0x01 | ||
16 | #define UDA1380_PM 0x02 | ||
17 | #define UDA1380_AMIX 0x03 | ||
18 | #define UDA1380_HP 0x04 | ||
19 | #define UDA1380_MVOL 0x10 | ||
20 | #define UDA1380_MIXVOL 0x11 | ||
21 | #define UDA1380_MODE 0x12 | ||
22 | #define UDA1380_DEEMP 0x13 | ||
23 | #define UDA1380_MIXER 0x14 | ||
24 | #define UDA1380_INTSTAT 0x18 | ||
25 | #define UDA1380_DEC 0x20 | ||
26 | #define UDA1380_PGA 0x21 | ||
27 | #define UDA1380_ADC 0x22 | ||
28 | #define UDA1380_AGC 0x23 | ||
29 | #define UDA1380_DECSTAT 0x28 | ||
30 | #define UDA1380_RESET 0x7f | ||
31 | |||
32 | #define UDA1380_CACHEREGNUM 0x24 | ||
33 | |||
34 | /* Register flags */ | ||
35 | #define R00_EN_ADC 0x0800 | ||
36 | #define R00_EN_DEC 0x0400 | ||
37 | #define R00_EN_DAC 0x0200 | ||
38 | #define R00_EN_INT 0x0100 | ||
39 | #define R00_DAC_CLK 0x0010 | ||
40 | #define R01_SFORI_I2S 0x0000 | ||
41 | #define R01_SFORI_LSB16 0x0100 | ||
42 | #define R01_SFORI_LSB18 0x0200 | ||
43 | #define R01_SFORI_LSB20 0x0300 | ||
44 | #define R01_SFORI_MSB 0x0500 | ||
45 | #define R01_SFORI_MASK 0x0700 | ||
46 | #define R01_SFORO_I2S 0x0000 | ||
47 | #define R01_SFORO_LSB16 0x0001 | ||
48 | #define R01_SFORO_LSB18 0x0002 | ||
49 | #define R01_SFORO_LSB20 0x0003 | ||
50 | #define R01_SFORO_LSB24 0x0004 | ||
51 | #define R01_SFORO_MSB 0x0005 | ||
52 | #define R01_SFORO_MASK 0x0007 | ||
53 | #define R01_SEL_SOURCE 0x0040 | ||
54 | #define R01_SIM 0x0010 | ||
55 | #define R02_PON_PLL 0x8000 | ||
56 | #define R02_PON_HP 0x2000 | ||
57 | #define R02_PON_DAC 0x0400 | ||
58 | #define R02_PON_BIAS 0x0100 | ||
59 | #define R02_EN_AVC 0x0080 | ||
60 | #define R02_PON_AVC 0x0040 | ||
61 | #define R02_PON_LNA 0x0010 | ||
62 | #define R02_PON_PGAL 0x0008 | ||
63 | #define R02_PON_ADCL 0x0004 | ||
64 | #define R02_PON_PGAR 0x0002 | ||
65 | #define R02_PON_ADCR 0x0001 | ||
66 | #define R13_MTM 0x4000 | ||
67 | #define R14_SILENCE 0x0080 | ||
68 | #define R14_SDET_ON 0x0040 | ||
69 | #define R21_MT_ADC 0x8000 | ||
70 | #define R22_SEL_LNA 0x0008 | ||
71 | #define R22_SEL_MIC 0x0004 | ||
72 | #define R22_SKIP_DCFIL 0x0002 | ||
73 | #define R23_AGC_EN 0x0001 | ||
74 | |||
75 | struct uda1380_setup_data { | ||
76 | unsigned short i2c_address; | ||
77 | int dac_clk; | ||
78 | #define UDA1380_DAC_CLK_SYSCLK 0 | ||
79 | #define UDA1380_DAC_CLK_WSPLL 1 | ||
80 | }; | ||
81 | |||
82 | #define UDA1380_DAI_DUPLEX 0 /* playback and capture on single DAI */ | ||
83 | #define UDA1380_DAI_PLAYBACK 1 /* playback DAI */ | ||
84 | #define UDA1380_DAI_CAPTURE 2 /* capture DAI */ | ||
85 | |||
86 | extern struct snd_soc_dai uda1380_dai[3]; | ||
87 | extern struct snd_soc_codec_device soc_codec_dev_uda1380; | ||
88 | |||
89 | #endif /* _UDA1380_H */ | ||
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c new file mode 100644 index 000000000000..67325fd95447 --- /dev/null +++ b/sound/soc/codecs/wm8510.c | |||
@@ -0,0 +1,817 @@ | |||
1 | /* | ||
2 | * wm8510.c -- WM8510 ALSA Soc Audio driver | ||
3 | * | ||
4 | * Copyright 2006 Wolfson Microelectronics PLC. | ||
5 | * | ||
6 | * Author: Liam Girdwood <liam.girdwood@wolfsonmicro.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/moduleparam.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/pm.h> | ||
19 | #include <linux/i2c.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <sound/core.h> | ||
22 | #include <sound/pcm.h> | ||
23 | #include <sound/pcm_params.h> | ||
24 | #include <sound/soc.h> | ||
25 | #include <sound/soc-dapm.h> | ||
26 | #include <sound/initval.h> | ||
27 | |||
28 | #include "wm8510.h" | ||
29 | |||
30 | #define AUDIO_NAME "wm8510" | ||
31 | #define WM8510_VERSION "0.6" | ||
32 | |||
33 | struct snd_soc_codec_device soc_codec_dev_wm8510; | ||
34 | |||
35 | /* | ||
36 | * wm8510 register cache | ||
37 | * We can't read the WM8510 register space when we are | ||
38 | * using 2 wire for device control, so we cache them instead. | ||
39 | */ | ||
40 | static const u16 wm8510_reg[WM8510_CACHEREGNUM] = { | ||
41 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
42 | 0x0050, 0x0000, 0x0140, 0x0000, | ||
43 | 0x0000, 0x0000, 0x0000, 0x00ff, | ||
44 | 0x0000, 0x0000, 0x0100, 0x00ff, | ||
45 | 0x0000, 0x0000, 0x012c, 0x002c, | ||
46 | 0x002c, 0x002c, 0x002c, 0x0000, | ||
47 | 0x0032, 0x0000, 0x0000, 0x0000, | ||
48 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
49 | 0x0038, 0x000b, 0x0032, 0x0000, | ||
50 | 0x0008, 0x000c, 0x0093, 0x00e9, | ||
51 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
52 | 0x0003, 0x0010, 0x0000, 0x0000, | ||
53 | 0x0000, 0x0002, 0x0001, 0x0000, | ||
54 | 0x0000, 0x0000, 0x0039, 0x0000, | ||
55 | 0x0001, | ||
56 | }; | ||
57 | |||
58 | /* | ||
59 | * read wm8510 register cache | ||
60 | */ | ||
61 | static inline unsigned int wm8510_read_reg_cache(struct snd_soc_codec *codec, | ||
62 | unsigned int reg) | ||
63 | { | ||
64 | u16 *cache = codec->reg_cache; | ||
65 | if (reg == WM8510_RESET) | ||
66 | return 0; | ||
67 | if (reg >= WM8510_CACHEREGNUM) | ||
68 | return -1; | ||
69 | return cache[reg]; | ||
70 | } | ||
71 | |||
72 | /* | ||
73 | * write wm8510 register cache | ||
74 | */ | ||
75 | static inline void wm8510_write_reg_cache(struct snd_soc_codec *codec, | ||
76 | u16 reg, unsigned int value) | ||
77 | { | ||
78 | u16 *cache = codec->reg_cache; | ||
79 | if (reg >= WM8510_CACHEREGNUM) | ||
80 | return; | ||
81 | cache[reg] = value; | ||
82 | } | ||
83 | |||
84 | /* | ||
85 | * write to the WM8510 register space | ||
86 | */ | ||
87 | static int wm8510_write(struct snd_soc_codec *codec, unsigned int reg, | ||
88 | unsigned int value) | ||
89 | { | ||
90 | u8 data[2]; | ||
91 | |||
92 | /* data is | ||
93 | * D15..D9 WM8510 register offset | ||
94 | * D8...D0 register data | ||
95 | */ | ||
96 | data[0] = (reg << 1) | ((value >> 8) & 0x0001); | ||
97 | data[1] = value & 0x00ff; | ||
98 | |||
99 | wm8510_write_reg_cache(codec, reg, value); | ||
100 | if (codec->hw_write(codec->control_data, data, 2) == 2) | ||
101 | return 0; | ||
102 | else | ||
103 | return -EIO; | ||
104 | } | ||
105 | |||
106 | #define wm8510_reset(c) wm8510_write(c, WM8510_RESET, 0) | ||
107 | |||
108 | static const char *wm8510_companding[] = { "Off", "NC", "u-law", "A-law" }; | ||
109 | static const char *wm8510_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" }; | ||
110 | static const char *wm8510_alc[] = { "ALC", "Limiter" }; | ||
111 | |||
112 | static const struct soc_enum wm8510_enum[] = { | ||
113 | SOC_ENUM_SINGLE(WM8510_COMP, 1, 4, wm8510_companding), /* adc */ | ||
114 | SOC_ENUM_SINGLE(WM8510_COMP, 3, 4, wm8510_companding), /* dac */ | ||
115 | SOC_ENUM_SINGLE(WM8510_DAC, 4, 4, wm8510_deemp), | ||
116 | SOC_ENUM_SINGLE(WM8510_ALC3, 8, 2, wm8510_alc), | ||
117 | }; | ||
118 | |||
119 | static const struct snd_kcontrol_new wm8510_snd_controls[] = { | ||
120 | |||
121 | SOC_SINGLE("Digital Loopback Switch", WM8510_COMP, 0, 1, 0), | ||
122 | |||
123 | SOC_ENUM("DAC Companding", wm8510_enum[1]), | ||
124 | SOC_ENUM("ADC Companding", wm8510_enum[0]), | ||
125 | |||
126 | SOC_ENUM("Playback De-emphasis", wm8510_enum[2]), | ||
127 | SOC_SINGLE("DAC Inversion Switch", WM8510_DAC, 0, 1, 0), | ||
128 | |||
129 | SOC_SINGLE("Master Playback Volume", WM8510_DACVOL, 0, 127, 0), | ||
130 | |||
131 | SOC_SINGLE("High Pass Filter Switch", WM8510_ADC, 8, 1, 0), | ||
132 | SOC_SINGLE("High Pass Cut Off", WM8510_ADC, 4, 7, 0), | ||
133 | SOC_SINGLE("ADC Inversion Switch", WM8510_COMP, 0, 1, 0), | ||
134 | |||
135 | SOC_SINGLE("Capture Volume", WM8510_ADCVOL, 0, 127, 0), | ||
136 | |||
137 | SOC_SINGLE("DAC Playback Limiter Switch", WM8510_DACLIM1, 8, 1, 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), | ||
140 | |||
141 | SOC_SINGLE("DAC Playback Limiter Threshold", WM8510_DACLIM2, 4, 7, 0), | ||
142 | SOC_SINGLE("DAC Playback Limiter Boost", WM8510_DACLIM2, 0, 15, 0), | ||
143 | |||
144 | SOC_SINGLE("ALC Enable Switch", WM8510_ALC1, 8, 1, 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), | ||
147 | |||
148 | SOC_SINGLE("ALC Capture ZC Switch", WM8510_ALC2, 8, 1, 0), | ||
149 | SOC_SINGLE("ALC Capture Hold", WM8510_ALC2, 4, 7, 0), | ||
150 | SOC_SINGLE("ALC Capture Target", WM8510_ALC2, 0, 15, 0), | ||
151 | |||
152 | SOC_ENUM("ALC Capture Mode", wm8510_enum[3]), | ||
153 | SOC_SINGLE("ALC Capture Decay", WM8510_ALC3, 4, 15, 0), | ||
154 | SOC_SINGLE("ALC Capture Attack", WM8510_ALC3, 0, 15, 0), | ||
155 | |||
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), | ||
158 | |||
159 | SOC_SINGLE("Capture PGA ZC Switch", WM8510_INPPGA, 7, 1, 0), | ||
160 | SOC_SINGLE("Capture PGA Volume", WM8510_INPPGA, 0, 63, 0), | ||
161 | |||
162 | SOC_SINGLE("Speaker Playback ZC Switch", WM8510_SPKVOL, 7, 1, 0), | ||
163 | SOC_SINGLE("Speaker Playback Switch", WM8510_SPKVOL, 6, 1, 1), | ||
164 | SOC_SINGLE("Speaker Playback Volume", WM8510_SPKVOL, 0, 63, 0), | ||
165 | SOC_SINGLE("Speaker Boost", WM8510_OUTPUT, 2, 1, 0), | ||
166 | |||
167 | SOC_SINGLE("Capture Boost(+20dB)", WM8510_ADCBOOST, 8, 1, 0), | ||
168 | SOC_SINGLE("Mono Playback Switch", WM8510_MONOMIX, 6, 1, 1), | ||
169 | }; | ||
170 | |||
171 | /* add non dapm controls */ | ||
172 | static int wm8510_add_controls(struct snd_soc_codec *codec) | ||
173 | { | ||
174 | int err, i; | ||
175 | |||
176 | for (i = 0; i < ARRAY_SIZE(wm8510_snd_controls); i++) { | ||
177 | err = snd_ctl_add(codec->card, | ||
178 | snd_soc_cnew(&wm8510_snd_controls[i], codec, | ||
179 | NULL)); | ||
180 | if (err < 0) | ||
181 | return err; | ||
182 | } | ||
183 | |||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | /* Speaker Output Mixer */ | ||
188 | static const struct snd_kcontrol_new wm8510_speaker_mixer_controls[] = { | ||
189 | SOC_DAPM_SINGLE("Line Bypass Switch", WM8510_SPKMIX, 1, 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), | ||
192 | }; | ||
193 | |||
194 | /* Mono Output Mixer */ | ||
195 | static const struct snd_kcontrol_new wm8510_mono_mixer_controls[] = { | ||
196 | SOC_DAPM_SINGLE("Line Bypass Switch", WM8510_MONOMIX, 1, 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), | ||
199 | }; | ||
200 | |||
201 | static const struct snd_kcontrol_new wm8510_boost_controls[] = { | ||
202 | SOC_DAPM_SINGLE("Mic PGA Switch", WM8510_INPPGA, 6, 1, 0), | ||
203 | SOC_DAPM_SINGLE("Aux Volume", WM8510_ADCBOOST, 0, 7, 0), | ||
204 | SOC_DAPM_SINGLE("Mic Volume", WM8510_ADCBOOST, 4, 7, 0), | ||
205 | }; | ||
206 | |||
207 | static const struct snd_kcontrol_new wm8510_micpga_controls[] = { | ||
208 | SOC_DAPM_SINGLE("MICP Switch", WM8510_INPUT, 0, 1, 0), | ||
209 | SOC_DAPM_SINGLE("MICN Switch", WM8510_INPUT, 1, 1, 0), | ||
210 | SOC_DAPM_SINGLE("AUX Switch", WM8510_INPUT, 2, 1, 0), | ||
211 | }; | ||
212 | |||
213 | static const struct snd_soc_dapm_widget wm8510_dapm_widgets[] = { | ||
214 | SND_SOC_DAPM_MIXER("Speaker Mixer", WM8510_POWER3, 2, 0, | ||
215 | &wm8510_speaker_mixer_controls[0], | ||
216 | ARRAY_SIZE(wm8510_speaker_mixer_controls)), | ||
217 | SND_SOC_DAPM_MIXER("Mono Mixer", WM8510_POWER3, 3, 0, | ||
218 | &wm8510_mono_mixer_controls[0], | ||
219 | ARRAY_SIZE(wm8510_mono_mixer_controls)), | ||
220 | SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8510_POWER3, 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), | ||
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), | ||
225 | SND_SOC_DAPM_PGA("Mono Out", WM8510_POWER3, 7, 0, NULL, 0), | ||
226 | |||
227 | SND_SOC_DAPM_PGA("Mic PGA", WM8510_POWER2, 2, 0, | ||
228 | &wm8510_micpga_controls[0], | ||
229 | ARRAY_SIZE(wm8510_micpga_controls)), | ||
230 | SND_SOC_DAPM_MIXER("Boost Mixer", WM8510_POWER2, 4, 0, | ||
231 | &wm8510_boost_controls[0], | ||
232 | ARRAY_SIZE(wm8510_boost_controls)), | ||
233 | |||
234 | SND_SOC_DAPM_MICBIAS("Mic Bias", WM8510_POWER1, 4, 0), | ||
235 | |||
236 | SND_SOC_DAPM_INPUT("MICN"), | ||
237 | SND_SOC_DAPM_INPUT("MICP"), | ||
238 | SND_SOC_DAPM_INPUT("AUX"), | ||
239 | SND_SOC_DAPM_OUTPUT("MONOOUT"), | ||
240 | SND_SOC_DAPM_OUTPUT("SPKOUTP"), | ||
241 | SND_SOC_DAPM_OUTPUT("SPKOUTN"), | ||
242 | }; | ||
243 | |||
244 | static const struct snd_soc_dapm_route audio_map[] = { | ||
245 | /* Mono output mixer */ | ||
246 | {"Mono Mixer", "PCM Playback Switch", "DAC"}, | ||
247 | {"Mono Mixer", "Aux Playback Switch", "Aux Input"}, | ||
248 | {"Mono Mixer", "Line Bypass Switch", "Boost Mixer"}, | ||
249 | |||
250 | /* Speaker output mixer */ | ||
251 | {"Speaker Mixer", "PCM Playback Switch", "DAC"}, | ||
252 | {"Speaker Mixer", "Aux Playback Switch", "Aux Input"}, | ||
253 | {"Speaker Mixer", "Line Bypass Switch", "Boost Mixer"}, | ||
254 | |||
255 | /* Outputs */ | ||
256 | {"Mono Out", NULL, "Mono Mixer"}, | ||
257 | {"MONOOUT", NULL, "Mono Out"}, | ||
258 | {"SpkN Out", NULL, "Speaker Mixer"}, | ||
259 | {"SpkP Out", NULL, "Speaker Mixer"}, | ||
260 | {"SPKOUTN", NULL, "SpkN Out"}, | ||
261 | {"SPKOUTP", NULL, "SpkP Out"}, | ||
262 | |||
263 | /* Microphone PGA */ | ||
264 | {"Mic PGA", "MICN Switch", "MICN"}, | ||
265 | {"Mic PGA", "MICP Switch", "MICP"}, | ||
266 | { "Mic PGA", "AUX Switch", "Aux Input" }, | ||
267 | |||
268 | /* Boost Mixer */ | ||
269 | {"Boost Mixer", "Mic PGA Switch", "Mic PGA"}, | ||
270 | {"Boost Mixer", "Mic Volume", "MICP"}, | ||
271 | {"Boost Mixer", "Aux Volume", "Aux Input"}, | ||
272 | |||
273 | {"ADC", NULL, "Boost Mixer"}, | ||
274 | }; | ||
275 | |||
276 | static int wm8510_add_widgets(struct snd_soc_codec *codec) | ||
277 | { | ||
278 | snd_soc_dapm_new_controls(codec, wm8510_dapm_widgets, | ||
279 | ARRAY_SIZE(wm8510_dapm_widgets)); | ||
280 | |||
281 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
282 | |||
283 | snd_soc_dapm_new_widgets(codec); | ||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | struct pll_ { | ||
288 | unsigned int pre_div:4; /* prescale - 1 */ | ||
289 | unsigned int n:4; | ||
290 | unsigned int k; | ||
291 | }; | ||
292 | |||
293 | static struct pll_ pll_div; | ||
294 | |||
295 | /* The size in bits of the pll divide multiplied by 10 | ||
296 | * to allow rounding later */ | ||
297 | #define FIXED_PLL_SIZE ((1 << 24) * 10) | ||
298 | |||
299 | static void pll_factors(unsigned int target, unsigned int source) | ||
300 | { | ||
301 | unsigned long long Kpart; | ||
302 | unsigned int K, Ndiv, Nmod; | ||
303 | |||
304 | Ndiv = target / source; | ||
305 | if (Ndiv < 6) { | ||
306 | source >>= 1; | ||
307 | pll_div.pre_div = 1; | ||
308 | Ndiv = target / source; | ||
309 | } else | ||
310 | pll_div.pre_div = 0; | ||
311 | |||
312 | if ((Ndiv < 6) || (Ndiv > 12)) | ||
313 | printk(KERN_WARNING | ||
314 | "WM8510 N value %d outwith recommended range!d\n", | ||
315 | Ndiv); | ||
316 | |||
317 | pll_div.n = Ndiv; | ||
318 | Nmod = target % source; | ||
319 | Kpart = FIXED_PLL_SIZE * (long long)Nmod; | ||
320 | |||
321 | do_div(Kpart, source); | ||
322 | |||
323 | K = Kpart & 0xFFFFFFFF; | ||
324 | |||
325 | /* Check if we need to round */ | ||
326 | if ((K % 10) >= 5) | ||
327 | K += 5; | ||
328 | |||
329 | /* Move down to proper range now rounding is done */ | ||
330 | K /= 10; | ||
331 | |||
332 | pll_div.k = K; | ||
333 | } | ||
334 | |||
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) | ||
337 | { | ||
338 | struct snd_soc_codec *codec = codec_dai->codec; | ||
339 | u16 reg; | ||
340 | |||
341 | if (freq_in == 0 || freq_out == 0) { | ||
342 | /* Clock CODEC directly from MCLK */ | ||
343 | reg = wm8510_read_reg_cache(codec, WM8510_CLOCK); | ||
344 | wm8510_write(codec, WM8510_CLOCK, reg & 0x0ff); | ||
345 | |||
346 | /* Turn off PLL */ | ||
347 | reg = wm8510_read_reg_cache(codec, WM8510_POWER1); | ||
348 | wm8510_write(codec, WM8510_POWER1, reg & 0x1df); | ||
349 | return 0; | ||
350 | } | ||
351 | |||
352 | pll_factors(freq_out*8, freq_in); | ||
353 | |||
354 | wm8510_write(codec, WM8510_PLLN, (pll_div.pre_div << 4) | pll_div.n); | ||
355 | wm8510_write(codec, WM8510_PLLK1, pll_div.k >> 18); | ||
356 | wm8510_write(codec, WM8510_PLLK2, (pll_div.k >> 9) & 0x1ff); | ||
357 | wm8510_write(codec, WM8510_PLLK3, pll_div.k & 0x1ff); | ||
358 | reg = wm8510_read_reg_cache(codec, WM8510_POWER1); | ||
359 | wm8510_write(codec, WM8510_POWER1, reg | 0x020); | ||
360 | |||
361 | /* Run CODEC from PLL instead of MCLK */ | ||
362 | reg = wm8510_read_reg_cache(codec, WM8510_CLOCK); | ||
363 | wm8510_write(codec, WM8510_CLOCK, reg | 0x100); | ||
364 | |||
365 | return 0; | ||
366 | } | ||
367 | |||
368 | /* | ||
369 | * Configure WM8510 clock dividers. | ||
370 | */ | ||
371 | static int wm8510_set_dai_clkdiv(struct snd_soc_dai *codec_dai, | ||
372 | int div_id, int div) | ||
373 | { | ||
374 | struct snd_soc_codec *codec = codec_dai->codec; | ||
375 | u16 reg; | ||
376 | |||
377 | switch (div_id) { | ||
378 | case WM8510_OPCLKDIV: | ||
379 | reg = wm8510_read_reg_cache(codec, WM8510_GPIO) & 0x1cf; | ||
380 | wm8510_write(codec, WM8510_GPIO, reg | div); | ||
381 | break; | ||
382 | case WM8510_MCLKDIV: | ||
383 | reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1f; | ||
384 | wm8510_write(codec, WM8510_CLOCK, reg | div); | ||
385 | break; | ||
386 | case WM8510_ADCCLK: | ||
387 | reg = wm8510_read_reg_cache(codec, WM8510_ADC) & 0x1f7; | ||
388 | wm8510_write(codec, WM8510_ADC, reg | div); | ||
389 | break; | ||
390 | case WM8510_DACCLK: | ||
391 | reg = wm8510_read_reg_cache(codec, WM8510_DAC) & 0x1f7; | ||
392 | wm8510_write(codec, WM8510_DAC, reg | div); | ||
393 | break; | ||
394 | case WM8510_BCLKDIV: | ||
395 | reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1e3; | ||
396 | wm8510_write(codec, WM8510_CLOCK, reg | div); | ||
397 | break; | ||
398 | default: | ||
399 | return -EINVAL; | ||
400 | } | ||
401 | |||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | static int wm8510_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
406 | unsigned int fmt) | ||
407 | { | ||
408 | struct snd_soc_codec *codec = codec_dai->codec; | ||
409 | u16 iface = 0; | ||
410 | u16 clk = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1fe; | ||
411 | |||
412 | /* set master/slave audio interface */ | ||
413 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
414 | case SND_SOC_DAIFMT_CBM_CFM: | ||
415 | clk |= 0x0001; | ||
416 | break; | ||
417 | case SND_SOC_DAIFMT_CBS_CFS: | ||
418 | break; | ||
419 | default: | ||
420 | return -EINVAL; | ||
421 | } | ||
422 | |||
423 | /* interface format */ | ||
424 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
425 | case SND_SOC_DAIFMT_I2S: | ||
426 | iface |= 0x0010; | ||
427 | break; | ||
428 | case SND_SOC_DAIFMT_RIGHT_J: | ||
429 | break; | ||
430 | case SND_SOC_DAIFMT_LEFT_J: | ||
431 | iface |= 0x0008; | ||
432 | break; | ||
433 | case SND_SOC_DAIFMT_DSP_A: | ||
434 | iface |= 0x00018; | ||
435 | break; | ||
436 | default: | ||
437 | return -EINVAL; | ||
438 | } | ||
439 | |||
440 | /* clock inversion */ | ||
441 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
442 | case SND_SOC_DAIFMT_NB_NF: | ||
443 | break; | ||
444 | case SND_SOC_DAIFMT_IB_IF: | ||
445 | iface |= 0x0180; | ||
446 | break; | ||
447 | case SND_SOC_DAIFMT_IB_NF: | ||
448 | iface |= 0x0100; | ||
449 | break; | ||
450 | case SND_SOC_DAIFMT_NB_IF: | ||
451 | iface |= 0x0080; | ||
452 | break; | ||
453 | default: | ||
454 | return -EINVAL; | ||
455 | } | ||
456 | |||
457 | wm8510_write(codec, WM8510_IFACE, iface); | ||
458 | wm8510_write(codec, WM8510_CLOCK, clk); | ||
459 | return 0; | ||
460 | } | ||
461 | |||
462 | static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream, | ||
463 | struct snd_pcm_hw_params *params) | ||
464 | { | ||
465 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
466 | struct snd_soc_device *socdev = rtd->socdev; | ||
467 | struct snd_soc_codec *codec = socdev->codec; | ||
468 | u16 iface = wm8510_read_reg_cache(codec, WM8510_IFACE) & 0x19f; | ||
469 | u16 adn = wm8510_read_reg_cache(codec, WM8510_ADD) & 0x1f1; | ||
470 | |||
471 | /* bit size */ | ||
472 | switch (params_format(params)) { | ||
473 | case SNDRV_PCM_FORMAT_S16_LE: | ||
474 | break; | ||
475 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
476 | iface |= 0x0020; | ||
477 | break; | ||
478 | case SNDRV_PCM_FORMAT_S24_LE: | ||
479 | iface |= 0x0040; | ||
480 | break; | ||
481 | case SNDRV_PCM_FORMAT_S32_LE: | ||
482 | iface |= 0x0060; | ||
483 | break; | ||
484 | } | ||
485 | |||
486 | /* filter coefficient */ | ||
487 | switch (params_rate(params)) { | ||
488 | case SNDRV_PCM_RATE_8000: | ||
489 | adn |= 0x5 << 1; | ||
490 | break; | ||
491 | case SNDRV_PCM_RATE_11025: | ||
492 | adn |= 0x4 << 1; | ||
493 | break; | ||
494 | case SNDRV_PCM_RATE_16000: | ||
495 | adn |= 0x3 << 1; | ||
496 | break; | ||
497 | case SNDRV_PCM_RATE_22050: | ||
498 | adn |= 0x2 << 1; | ||
499 | break; | ||
500 | case SNDRV_PCM_RATE_32000: | ||
501 | adn |= 0x1 << 1; | ||
502 | break; | ||
503 | case SNDRV_PCM_RATE_44100: | ||
504 | case SNDRV_PCM_RATE_48000: | ||
505 | break; | ||
506 | } | ||
507 | |||
508 | wm8510_write(codec, WM8510_IFACE, iface); | ||
509 | wm8510_write(codec, WM8510_ADD, adn); | ||
510 | return 0; | ||
511 | } | ||
512 | |||
513 | static int wm8510_mute(struct snd_soc_dai *dai, int mute) | ||
514 | { | ||
515 | struct snd_soc_codec *codec = dai->codec; | ||
516 | u16 mute_reg = wm8510_read_reg_cache(codec, WM8510_DAC) & 0xffbf; | ||
517 | |||
518 | if (mute) | ||
519 | wm8510_write(codec, WM8510_DAC, mute_reg | 0x40); | ||
520 | else | ||
521 | wm8510_write(codec, WM8510_DAC, mute_reg); | ||
522 | return 0; | ||
523 | } | ||
524 | |||
525 | /* liam need to make this lower power with dapm */ | ||
526 | static int wm8510_set_bias_level(struct snd_soc_codec *codec, | ||
527 | enum snd_soc_bias_level level) | ||
528 | { | ||
529 | |||
530 | switch (level) { | ||
531 | case SND_SOC_BIAS_ON: | ||
532 | wm8510_write(codec, WM8510_POWER1, 0x1ff); | ||
533 | wm8510_write(codec, WM8510_POWER2, 0x1ff); | ||
534 | wm8510_write(codec, WM8510_POWER3, 0x1ff); | ||
535 | break; | ||
536 | case SND_SOC_BIAS_PREPARE: | ||
537 | case SND_SOC_BIAS_STANDBY: | ||
538 | break; | ||
539 | case SND_SOC_BIAS_OFF: | ||
540 | /* everything off, dac mute, inactive */ | ||
541 | wm8510_write(codec, WM8510_POWER1, 0x0); | ||
542 | wm8510_write(codec, WM8510_POWER2, 0x0); | ||
543 | wm8510_write(codec, WM8510_POWER3, 0x0); | ||
544 | break; | ||
545 | } | ||
546 | codec->bias_level = level; | ||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | #define WM8510_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
551 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ | ||
552 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) | ||
553 | |||
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) | ||
556 | |||
557 | struct snd_soc_dai wm8510_dai = { | ||
558 | .name = "WM8510 HiFi", | ||
559 | .playback = { | ||
560 | .stream_name = "Playback", | ||
561 | .channels_min = 2, | ||
562 | .channels_max = 2, | ||
563 | .rates = WM8510_RATES, | ||
564 | .formats = WM8510_FORMATS,}, | ||
565 | .capture = { | ||
566 | .stream_name = "Capture", | ||
567 | .channels_min = 2, | ||
568 | .channels_max = 2, | ||
569 | .rates = WM8510_RATES, | ||
570 | .formats = WM8510_FORMATS,}, | ||
571 | .ops = { | ||
572 | .hw_params = wm8510_pcm_hw_params, | ||
573 | }, | ||
574 | .dai_ops = { | ||
575 | .digital_mute = wm8510_mute, | ||
576 | .set_fmt = wm8510_set_dai_fmt, | ||
577 | .set_clkdiv = wm8510_set_dai_clkdiv, | ||
578 | .set_pll = wm8510_set_dai_pll, | ||
579 | }, | ||
580 | }; | ||
581 | EXPORT_SYMBOL_GPL(wm8510_dai); | ||
582 | |||
583 | static int wm8510_suspend(struct platform_device *pdev, pm_message_t state) | ||
584 | { | ||
585 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
586 | struct snd_soc_codec *codec = socdev->codec; | ||
587 | |||
588 | wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | static int wm8510_resume(struct platform_device *pdev) | ||
593 | { | ||
594 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
595 | struct snd_soc_codec *codec = socdev->codec; | ||
596 | int i; | ||
597 | u8 data[2]; | ||
598 | u16 *cache = codec->reg_cache; | ||
599 | |||
600 | /* Sync reg_cache with the hardware */ | ||
601 | for (i = 0; i < ARRAY_SIZE(wm8510_reg); i++) { | ||
602 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); | ||
603 | data[1] = cache[i] & 0x00ff; | ||
604 | codec->hw_write(codec->control_data, data, 2); | ||
605 | } | ||
606 | wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
607 | wm8510_set_bias_level(codec, codec->suspend_bias_level); | ||
608 | return 0; | ||
609 | } | ||
610 | |||
611 | /* | ||
612 | * initialise the WM8510 driver | ||
613 | * register the mixer and dsp interfaces with the kernel | ||
614 | */ | ||
615 | static int wm8510_init(struct snd_soc_device *socdev) | ||
616 | { | ||
617 | struct snd_soc_codec *codec = socdev->codec; | ||
618 | int ret = 0; | ||
619 | |||
620 | codec->name = "WM8510"; | ||
621 | codec->owner = THIS_MODULE; | ||
622 | codec->read = wm8510_read_reg_cache; | ||
623 | codec->write = wm8510_write; | ||
624 | codec->set_bias_level = wm8510_set_bias_level; | ||
625 | codec->dai = &wm8510_dai; | ||
626 | codec->num_dai = 1; | ||
627 | codec->reg_cache_size = ARRAY_SIZE(wm8510_reg); | ||
628 | codec->reg_cache = kmemdup(wm8510_reg, sizeof(wm8510_reg), GFP_KERNEL); | ||
629 | |||
630 | if (codec->reg_cache == NULL) | ||
631 | return -ENOMEM; | ||
632 | |||
633 | wm8510_reset(codec); | ||
634 | |||
635 | /* register pcms */ | ||
636 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
637 | if (ret < 0) { | ||
638 | printk(KERN_ERR "wm8510: failed to create pcms\n"); | ||
639 | goto pcm_err; | ||
640 | } | ||
641 | |||
642 | /* power on device */ | ||
643 | wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
644 | wm8510_add_controls(codec); | ||
645 | wm8510_add_widgets(codec); | ||
646 | ret = snd_soc_register_card(socdev); | ||
647 | if (ret < 0) { | ||
648 | printk(KERN_ERR "wm8510: failed to register card\n"); | ||
649 | goto card_err; | ||
650 | } | ||
651 | return ret; | ||
652 | |||
653 | card_err: | ||
654 | snd_soc_free_pcms(socdev); | ||
655 | snd_soc_dapm_free(socdev); | ||
656 | pcm_err: | ||
657 | kfree(codec->reg_cache); | ||
658 | return ret; | ||
659 | } | ||
660 | |||
661 | static struct snd_soc_device *wm8510_socdev; | ||
662 | |||
663 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
664 | |||
665 | /* | ||
666 | * WM8510 2 wire address is 0x1a | ||
667 | */ | ||
668 | #define I2C_DRIVERID_WM8510 0xfefe /* liam - need a proper id */ | ||
669 | |||
670 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
671 | |||
672 | /* Magic definition of all other variables and things */ | ||
673 | I2C_CLIENT_INSMOD; | ||
674 | |||
675 | static struct i2c_driver wm8510_i2c_driver; | ||
676 | static struct i2c_client client_template; | ||
677 | |||
678 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
679 | around */ | ||
680 | |||
681 | static int wm8510_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
682 | { | ||
683 | struct snd_soc_device *socdev = wm8510_socdev; | ||
684 | struct wm8510_setup_data *setup = socdev->codec_data; | ||
685 | struct snd_soc_codec *codec = socdev->codec; | ||
686 | struct i2c_client *i2c; | ||
687 | int ret; | ||
688 | |||
689 | if (addr != setup->i2c_address) | ||
690 | return -ENODEV; | ||
691 | |||
692 | client_template.adapter = adap; | ||
693 | client_template.addr = addr; | ||
694 | |||
695 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
696 | if (i2c == NULL) { | ||
697 | kfree(codec); | ||
698 | return -ENOMEM; | ||
699 | } | ||
700 | i2c_set_clientdata(i2c, codec); | ||
701 | codec->control_data = i2c; | ||
702 | |||
703 | ret = i2c_attach_client(i2c); | ||
704 | if (ret < 0) { | ||
705 | pr_err("failed to attach codec at addr %x\n", addr); | ||
706 | goto err; | ||
707 | } | ||
708 | |||
709 | ret = wm8510_init(socdev); | ||
710 | if (ret < 0) { | ||
711 | pr_err("failed to initialise WM8510\n"); | ||
712 | goto err; | ||
713 | } | ||
714 | return ret; | ||
715 | |||
716 | err: | ||
717 | kfree(codec); | ||
718 | kfree(i2c); | ||
719 | return ret; | ||
720 | } | ||
721 | |||
722 | static int wm8510_i2c_detach(struct i2c_client *client) | ||
723 | { | ||
724 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
725 | i2c_detach_client(client); | ||
726 | kfree(codec->reg_cache); | ||
727 | kfree(client); | ||
728 | return 0; | ||
729 | } | ||
730 | |||
731 | static int wm8510_i2c_attach(struct i2c_adapter *adap) | ||
732 | { | ||
733 | return i2c_probe(adap, &addr_data, wm8510_codec_probe); | ||
734 | } | ||
735 | |||
736 | /* corgi i2c codec control layer */ | ||
737 | static struct i2c_driver wm8510_i2c_driver = { | ||
738 | .driver = { | ||
739 | .name = "WM8510 I2C Codec", | ||
740 | .owner = THIS_MODULE, | ||
741 | }, | ||
742 | .id = I2C_DRIVERID_WM8510, | ||
743 | .attach_adapter = wm8510_i2c_attach, | ||
744 | .detach_client = wm8510_i2c_detach, | ||
745 | .command = NULL, | ||
746 | }; | ||
747 | |||
748 | static struct i2c_client client_template = { | ||
749 | .name = "WM8510", | ||
750 | .driver = &wm8510_i2c_driver, | ||
751 | }; | ||
752 | #endif | ||
753 | |||
754 | static int wm8510_probe(struct platform_device *pdev) | ||
755 | { | ||
756 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
757 | struct wm8510_setup_data *setup; | ||
758 | struct snd_soc_codec *codec; | ||
759 | int ret = 0; | ||
760 | |||
761 | pr_info("WM8510 Audio Codec %s", WM8510_VERSION); | ||
762 | |||
763 | setup = socdev->codec_data; | ||
764 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
765 | if (codec == NULL) | ||
766 | return -ENOMEM; | ||
767 | |||
768 | socdev->codec = codec; | ||
769 | mutex_init(&codec->mutex); | ||
770 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
771 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
772 | |||
773 | wm8510_socdev = socdev; | ||
774 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
775 | if (setup->i2c_address) { | ||
776 | normal_i2c[0] = setup->i2c_address; | ||
777 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
778 | ret = i2c_add_driver(&wm8510_i2c_driver); | ||
779 | if (ret != 0) | ||
780 | printk(KERN_ERR "can't add i2c driver"); | ||
781 | } | ||
782 | #else | ||
783 | /* Add other interfaces here */ | ||
784 | #endif | ||
785 | return ret; | ||
786 | } | ||
787 | |||
788 | /* power down chip */ | ||
789 | static int wm8510_remove(struct platform_device *pdev) | ||
790 | { | ||
791 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
792 | struct snd_soc_codec *codec = socdev->codec; | ||
793 | |||
794 | if (codec->control_data) | ||
795 | wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
796 | |||
797 | snd_soc_free_pcms(socdev); | ||
798 | snd_soc_dapm_free(socdev); | ||
799 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
800 | i2c_del_driver(&wm8510_i2c_driver); | ||
801 | #endif | ||
802 | kfree(codec); | ||
803 | |||
804 | return 0; | ||
805 | } | ||
806 | |||
807 | struct snd_soc_codec_device soc_codec_dev_wm8510 = { | ||
808 | .probe = wm8510_probe, | ||
809 | .remove = wm8510_remove, | ||
810 | .suspend = wm8510_suspend, | ||
811 | .resume = wm8510_resume, | ||
812 | }; | ||
813 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8510); | ||
814 | |||
815 | MODULE_DESCRIPTION("ASoC WM8510 driver"); | ||
816 | MODULE_AUTHOR("Liam Girdwood"); | ||
817 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8510.h b/sound/soc/codecs/wm8510.h new file mode 100644 index 000000000000..f5d2e42eb3f4 --- /dev/null +++ b/sound/soc/codecs/wm8510.h | |||
@@ -0,0 +1,103 @@ | |||
1 | /* | ||
2 | * wm8510.h -- WM8510 Soc Audio driver | ||
3 | * | ||
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 | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #ifndef _WM8510_H | ||
10 | #define _WM8510_H | ||
11 | |||
12 | /* WM8510 register space */ | ||
13 | |||
14 | #define WM8510_RESET 0x0 | ||
15 | #define WM8510_POWER1 0x1 | ||
16 | #define WM8510_POWER2 0x2 | ||
17 | #define WM8510_POWER3 0x3 | ||
18 | #define WM8510_IFACE 0x4 | ||
19 | #define WM8510_COMP 0x5 | ||
20 | #define WM8510_CLOCK 0x6 | ||
21 | #define WM8510_ADD 0x7 | ||
22 | #define WM8510_GPIO 0x8 | ||
23 | #define WM8510_DAC 0xa | ||
24 | #define WM8510_DACVOL 0xb | ||
25 | #define WM8510_ADC 0xe | ||
26 | #define WM8510_ADCVOL 0xf | ||
27 | #define WM8510_EQ1 0x12 | ||
28 | #define WM8510_EQ2 0x13 | ||
29 | #define WM8510_EQ3 0x14 | ||
30 | #define WM8510_EQ4 0x15 | ||
31 | #define WM8510_EQ5 0x16 | ||
32 | #define WM8510_DACLIM1 0x18 | ||
33 | #define WM8510_DACLIM2 0x19 | ||
34 | #define WM8510_NOTCH1 0x1b | ||
35 | #define WM8510_NOTCH2 0x1c | ||
36 | #define WM8510_NOTCH3 0x1d | ||
37 | #define WM8510_NOTCH4 0x1e | ||
38 | #define WM8510_ALC1 0x20 | ||
39 | #define WM8510_ALC2 0x21 | ||
40 | #define WM8510_ALC3 0x22 | ||
41 | #define WM8510_NGATE 0x23 | ||
42 | #define WM8510_PLLN 0x24 | ||
43 | #define WM8510_PLLK1 0x25 | ||
44 | #define WM8510_PLLK2 0x26 | ||
45 | #define WM8510_PLLK3 0x27 | ||
46 | #define WM8510_ATTEN 0x28 | ||
47 | #define WM8510_INPUT 0x2c | ||
48 | #define WM8510_INPPGA 0x2d | ||
49 | #define WM8510_ADCBOOST 0x2f | ||
50 | #define WM8510_OUTPUT 0x31 | ||
51 | #define WM8510_SPKMIX 0x32 | ||
52 | #define WM8510_SPKVOL 0x36 | ||
53 | #define WM8510_MONOMIX 0x38 | ||
54 | |||
55 | #define WM8510_CACHEREGNUM 57 | ||
56 | |||
57 | /* Clock divider Id's */ | ||
58 | #define WM8510_OPCLKDIV 0 | ||
59 | #define WM8510_MCLKDIV 1 | ||
60 | #define WM8510_ADCCLK 2 | ||
61 | #define WM8510_DACCLK 3 | ||
62 | #define WM8510_BCLKDIV 4 | ||
63 | |||
64 | /* DAC clock dividers */ | ||
65 | #define WM8510_DACCLK_F2 (1 << 3) | ||
66 | #define WM8510_DACCLK_F4 (0 << 3) | ||
67 | |||
68 | /* ADC clock dividers */ | ||
69 | #define WM8510_ADCCLK_F2 (1 << 3) | ||
70 | #define WM8510_ADCCLK_F4 (0 << 3) | ||
71 | |||
72 | /* PLL Out dividers */ | ||
73 | #define WM8510_OPCLKDIV_1 (0 << 4) | ||
74 | #define WM8510_OPCLKDIV_2 (1 << 4) | ||
75 | #define WM8510_OPCLKDIV_3 (2 << 4) | ||
76 | #define WM8510_OPCLKDIV_4 (3 << 4) | ||
77 | |||
78 | /* BCLK clock dividers */ | ||
79 | #define WM8510_BCLKDIV_1 (0 << 2) | ||
80 | #define WM8510_BCLKDIV_2 (1 << 2) | ||
81 | #define WM8510_BCLKDIV_4 (2 << 2) | ||
82 | #define WM8510_BCLKDIV_8 (3 << 2) | ||
83 | #define WM8510_BCLKDIV_16 (4 << 2) | ||
84 | #define WM8510_BCLKDIV_32 (5 << 2) | ||
85 | |||
86 | /* MCLK clock dividers */ | ||
87 | #define WM8510_MCLKDIV_1 (0 << 5) | ||
88 | #define WM8510_MCLKDIV_1_5 (1 << 5) | ||
89 | #define WM8510_MCLKDIV_2 (2 << 5) | ||
90 | #define WM8510_MCLKDIV_3 (3 << 5) | ||
91 | #define WM8510_MCLKDIV_4 (4 << 5) | ||
92 | #define WM8510_MCLKDIV_6 (5 << 5) | ||
93 | #define WM8510_MCLKDIV_8 (6 << 5) | ||
94 | #define WM8510_MCLKDIV_12 (7 << 5) | ||
95 | |||
96 | struct wm8510_setup_data { | ||
97 | unsigned short i2c_address; | ||
98 | }; | ||
99 | |||
100 | extern struct snd_soc_dai wm8510_dai; | ||
101 | extern struct snd_soc_codec_device soc_codec_dev_wm8510; | ||
102 | |||
103 | #endif | ||
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 0cf9265fca8f..369d39c3f745 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c | |||
@@ -31,25 +31,6 @@ | |||
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 | /* | ||
35 | * Debug | ||
36 | */ | ||
37 | |||
38 | #define WM8731_DEBUG 0 | ||
39 | |||
40 | #ifdef WM8731_DEBUG | ||
41 | #define dbg(format, arg...) \ | ||
42 | printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg) | ||
43 | #else | ||
44 | #define dbg(format, arg...) do {} while (0) | ||
45 | #endif | ||
46 | #define err(format, arg...) \ | ||
47 | printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg) | ||
48 | #define info(format, arg...) \ | ||
49 | printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg) | ||
50 | #define warn(format, arg...) \ | ||
51 | printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg) | ||
52 | |||
53 | struct snd_soc_codec_device soc_codec_dev_wm8731; | 34 | struct snd_soc_codec_device soc_codec_dev_wm8731; |
54 | 35 | ||
55 | /* codec private data */ | 36 | /* codec private data */ |
@@ -193,7 +174,7 @@ SND_SOC_DAPM_INPUT("RLINEIN"), | |||
193 | SND_SOC_DAPM_INPUT("LLINEIN"), | 174 | SND_SOC_DAPM_INPUT("LLINEIN"), |
194 | }; | 175 | }; |
195 | 176 | ||
196 | static const char *intercon[][3] = { | 177 | static const struct snd_soc_dapm_route intercon[] = { |
197 | /* output mixer */ | 178 | /* output mixer */ |
198 | {"Output Mixer", "Line Bypass Switch", "Line Input"}, | 179 | {"Output Mixer", "Line Bypass Switch", "Line Input"}, |
199 | {"Output Mixer", "HiFi Playback Switch", "DAC"}, | 180 | {"Output Mixer", "HiFi Playback Switch", "DAC"}, |
@@ -214,22 +195,14 @@ static const char *intercon[][3] = { | |||
214 | {"Line Input", NULL, "LLINEIN"}, | 195 | {"Line Input", NULL, "LLINEIN"}, |
215 | {"Line Input", NULL, "RLINEIN"}, | 196 | {"Line Input", NULL, "RLINEIN"}, |
216 | {"Mic Bias", NULL, "MICIN"}, | 197 | {"Mic Bias", NULL, "MICIN"}, |
217 | |||
218 | /* terminator */ | ||
219 | {NULL, NULL, NULL}, | ||
220 | }; | 198 | }; |
221 | 199 | ||
222 | static int wm8731_add_widgets(struct snd_soc_codec *codec) | 200 | static int wm8731_add_widgets(struct snd_soc_codec *codec) |
223 | { | 201 | { |
224 | int i; | 202 | snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets, |
225 | 203 | ARRAY_SIZE(wm8731_dapm_widgets)); | |
226 | for (i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++) | ||
227 | snd_soc_dapm_new_control(codec, &wm8731_dapm_widgets[i]); | ||
228 | 204 | ||
229 | /* set up audio path interconnects */ | 205 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); |
230 | for (i = 0; intercon[i][0] != NULL; i++) | ||
231 | snd_soc_dapm_connect_input(codec, intercon[i][0], | ||
232 | intercon[i][1], intercon[i][2]); | ||
233 | 206 | ||
234 | snd_soc_dapm_new_widgets(codec); | 207 | snd_soc_dapm_new_widgets(codec); |
235 | return 0; | 208 | return 0; |
@@ -345,7 +318,7 @@ static void wm8731_shutdown(struct snd_pcm_substream *substream) | |||
345 | } | 318 | } |
346 | } | 319 | } |
347 | 320 | ||
348 | static int wm8731_mute(struct snd_soc_codec_dai *dai, int mute) | 321 | static int wm8731_mute(struct snd_soc_dai *dai, int mute) |
349 | { | 322 | { |
350 | struct snd_soc_codec *codec = dai->codec; | 323 | struct snd_soc_codec *codec = dai->codec; |
351 | u16 mute_reg = wm8731_read_reg_cache(codec, WM8731_APDIGI) & 0xfff7; | 324 | u16 mute_reg = wm8731_read_reg_cache(codec, WM8731_APDIGI) & 0xfff7; |
@@ -357,7 +330,7 @@ static int wm8731_mute(struct snd_soc_codec_dai *dai, int mute) | |||
357 | return 0; | 330 | return 0; |
358 | } | 331 | } |
359 | 332 | ||
360 | static int wm8731_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | 333 | static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
361 | int clk_id, unsigned int freq, int dir) | 334 | int clk_id, unsigned int freq, int dir) |
362 | { | 335 | { |
363 | struct snd_soc_codec *codec = codec_dai->codec; | 336 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -376,7 +349,7 @@ static int wm8731_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | |||
376 | } | 349 | } |
377 | 350 | ||
378 | 351 | ||
379 | static int wm8731_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 352 | static int wm8731_set_dai_fmt(struct snd_soc_dai *codec_dai, |
380 | unsigned int fmt) | 353 | unsigned int fmt) |
381 | { | 354 | { |
382 | struct snd_soc_codec *codec = codec_dai->codec; | 355 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -435,29 +408,29 @@ static int wm8731_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | |||
435 | return 0; | 408 | return 0; |
436 | } | 409 | } |
437 | 410 | ||
438 | static int wm8731_dapm_event(struct snd_soc_codec *codec, int event) | 411 | static int wm8731_set_bias_level(struct snd_soc_codec *codec, |
412 | enum snd_soc_bias_level level) | ||
439 | { | 413 | { |
440 | u16 reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff7f; | 414 | u16 reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff7f; |
441 | 415 | ||
442 | switch (event) { | 416 | switch (level) { |
443 | case SNDRV_CTL_POWER_D0: /* full On */ | 417 | case SND_SOC_BIAS_ON: |
444 | /* vref/mid, osc on, dac unmute */ | 418 | /* vref/mid, osc on, dac unmute */ |
445 | wm8731_write(codec, WM8731_PWR, reg); | 419 | wm8731_write(codec, WM8731_PWR, reg); |
446 | break; | 420 | break; |
447 | case SNDRV_CTL_POWER_D1: /* partial On */ | 421 | case SND_SOC_BIAS_PREPARE: |
448 | case SNDRV_CTL_POWER_D2: /* partial On */ | ||
449 | break; | 422 | break; |
450 | case SNDRV_CTL_POWER_D3hot: /* Off, with power */ | 423 | case SND_SOC_BIAS_STANDBY: |
451 | /* everything off except vref/vmid, */ | 424 | /* everything off except vref/vmid, */ |
452 | wm8731_write(codec, WM8731_PWR, reg | 0x0040); | 425 | wm8731_write(codec, WM8731_PWR, reg | 0x0040); |
453 | break; | 426 | break; |
454 | case SNDRV_CTL_POWER_D3cold: /* Off, without power */ | 427 | case SND_SOC_BIAS_OFF: |
455 | /* everything off, dac mute, inactive */ | 428 | /* everything off, dac mute, inactive */ |
456 | wm8731_write(codec, WM8731_ACTIVE, 0x0); | 429 | wm8731_write(codec, WM8731_ACTIVE, 0x0); |
457 | wm8731_write(codec, WM8731_PWR, 0xffff); | 430 | wm8731_write(codec, WM8731_PWR, 0xffff); |
458 | break; | 431 | break; |
459 | } | 432 | } |
460 | codec->dapm_state = event; | 433 | codec->bias_level = level; |
461 | return 0; | 434 | return 0; |
462 | } | 435 | } |
463 | 436 | ||
@@ -470,7 +443,7 @@ static int wm8731_dapm_event(struct snd_soc_codec *codec, int event) | |||
470 | #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 |\ |
471 | SNDRV_PCM_FMTBIT_S24_LE) | 444 | SNDRV_PCM_FMTBIT_S24_LE) |
472 | 445 | ||
473 | struct snd_soc_codec_dai wm8731_dai = { | 446 | struct snd_soc_dai wm8731_dai = { |
474 | .name = "WM8731", | 447 | .name = "WM8731", |
475 | .playback = { | 448 | .playback = { |
476 | .stream_name = "Playback", | 449 | .stream_name = "Playback", |
@@ -503,7 +476,7 @@ static int wm8731_suspend(struct platform_device *pdev, pm_message_t state) | |||
503 | struct snd_soc_codec *codec = socdev->codec; | 476 | struct snd_soc_codec *codec = socdev->codec; |
504 | 477 | ||
505 | wm8731_write(codec, WM8731_ACTIVE, 0x0); | 478 | wm8731_write(codec, WM8731_ACTIVE, 0x0); |
506 | wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3cold); | 479 | wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); |
507 | return 0; | 480 | return 0; |
508 | } | 481 | } |
509 | 482 | ||
@@ -521,8 +494,8 @@ static int wm8731_resume(struct platform_device *pdev) | |||
521 | data[1] = cache[i] & 0x00ff; | 494 | data[1] = cache[i] & 0x00ff; |
522 | codec->hw_write(codec->control_data, data, 2); | 495 | codec->hw_write(codec->control_data, data, 2); |
523 | } | 496 | } |
524 | wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | 497 | wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
525 | wm8731_dapm_event(codec, codec->suspend_dapm_state); | 498 | wm8731_set_bias_level(codec, codec->suspend_bias_level); |
526 | return 0; | 499 | return 0; |
527 | } | 500 | } |
528 | 501 | ||
@@ -539,10 +512,10 @@ static int wm8731_init(struct snd_soc_device *socdev) | |||
539 | codec->owner = THIS_MODULE; | 512 | codec->owner = THIS_MODULE; |
540 | codec->read = wm8731_read_reg_cache; | 513 | codec->read = wm8731_read_reg_cache; |
541 | codec->write = wm8731_write; | 514 | codec->write = wm8731_write; |
542 | codec->dapm_event = wm8731_dapm_event; | 515 | codec->set_bias_level = wm8731_set_bias_level; |
543 | codec->dai = &wm8731_dai; | 516 | codec->dai = &wm8731_dai; |
544 | codec->num_dai = 1; | 517 | codec->num_dai = 1; |
545 | codec->reg_cache_size = sizeof(wm8731_reg); | 518 | codec->reg_cache_size = ARRAY_SIZE(wm8731_reg); |
546 | codec->reg_cache = kmemdup(wm8731_reg, sizeof(wm8731_reg), GFP_KERNEL); | 519 | codec->reg_cache = kmemdup(wm8731_reg, sizeof(wm8731_reg), GFP_KERNEL); |
547 | if (codec->reg_cache == NULL) | 520 | if (codec->reg_cache == NULL) |
548 | return -ENOMEM; | 521 | return -ENOMEM; |
@@ -557,7 +530,7 @@ static int wm8731_init(struct snd_soc_device *socdev) | |||
557 | } | 530 | } |
558 | 531 | ||
559 | /* power on device */ | 532 | /* power on device */ |
560 | wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | 533 | wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
561 | 534 | ||
562 | /* set the update bits */ | 535 | /* set the update bits */ |
563 | reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V); | 536 | reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V); |
@@ -632,13 +605,13 @@ static int wm8731_codec_probe(struct i2c_adapter *adap, int addr, int kind) | |||
632 | 605 | ||
633 | ret = i2c_attach_client(i2c); | 606 | ret = i2c_attach_client(i2c); |
634 | if (ret < 0) { | 607 | if (ret < 0) { |
635 | err("failed to attach codec at addr %x\n", addr); | 608 | pr_err("failed to attach codec at addr %x\n", addr); |
636 | goto err; | 609 | goto err; |
637 | } | 610 | } |
638 | 611 | ||
639 | ret = wm8731_init(socdev); | 612 | ret = wm8731_init(socdev); |
640 | if (ret < 0) { | 613 | if (ret < 0) { |
641 | err("failed to initialise WM8731\n"); | 614 | pr_err("failed to initialise WM8731\n"); |
642 | goto err; | 615 | goto err; |
643 | } | 616 | } |
644 | return ret; | 617 | return ret; |
@@ -689,7 +662,7 @@ static int wm8731_probe(struct platform_device *pdev) | |||
689 | struct wm8731_priv *wm8731; | 662 | struct wm8731_priv *wm8731; |
690 | int ret = 0; | 663 | int ret = 0; |
691 | 664 | ||
692 | info("WM8731 Audio Codec %s", WM8731_VERSION); | 665 | pr_info("WM8731 Audio Codec %s", WM8731_VERSION); |
693 | 666 | ||
694 | setup = socdev->codec_data; | 667 | setup = socdev->codec_data; |
695 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 668 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); |
@@ -730,7 +703,7 @@ static int wm8731_remove(struct platform_device *pdev) | |||
730 | struct snd_soc_codec *codec = socdev->codec; | 703 | struct snd_soc_codec *codec = socdev->codec; |
731 | 704 | ||
732 | if (codec->control_data) | 705 | if (codec->control_data) |
733 | wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3cold); | 706 | wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); |
734 | 707 | ||
735 | snd_soc_free_pcms(socdev); | 708 | snd_soc_free_pcms(socdev); |
736 | snd_soc_dapm_free(socdev); | 709 | snd_soc_dapm_free(socdev); |
diff --git a/sound/soc/codecs/wm8731.h b/sound/soc/codecs/wm8731.h index 5bcab6a7afb4..99f2e3c60e33 100644 --- a/sound/soc/codecs/wm8731.h +++ b/sound/soc/codecs/wm8731.h | |||
@@ -38,7 +38,7 @@ struct wm8731_setup_data { | |||
38 | unsigned short i2c_address; | 38 | unsigned short i2c_address; |
39 | }; | 39 | }; |
40 | 40 | ||
41 | extern struct snd_soc_codec_dai wm8731_dai; | 41 | extern struct snd_soc_dai wm8731_dai; |
42 | extern struct snd_soc_codec_device soc_codec_dev_wm8731; | 42 | extern struct snd_soc_codec_device soc_codec_dev_wm8731; |
43 | 43 | ||
44 | #endif | 44 | #endif |
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 16cd5d4d5ad9..e23cb09f0d14 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c | |||
@@ -31,25 +31,6 @@ | |||
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 | /* | ||
35 | * Debug | ||
36 | */ | ||
37 | |||
38 | #define WM8750_DEBUG 0 | ||
39 | |||
40 | #ifdef WM8750_DEBUG | ||
41 | #define dbg(format, arg...) \ | ||
42 | printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg) | ||
43 | #else | ||
44 | #define dbg(format, arg...) do {} while (0) | ||
45 | #endif | ||
46 | #define err(format, arg...) \ | ||
47 | printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg) | ||
48 | #define info(format, arg...) \ | ||
49 | printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg) | ||
50 | #define warn(format, arg...) \ | ||
51 | printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg) | ||
52 | |||
53 | /* codec private data */ | 34 | /* codec private data */ |
54 | struct wm8750_priv { | 35 | struct wm8750_priv { |
55 | unsigned int sysclk; | 36 | unsigned int sysclk; |
@@ -378,7 +359,7 @@ static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = { | |||
378 | SND_SOC_DAPM_INPUT("RINPUT3"), | 359 | SND_SOC_DAPM_INPUT("RINPUT3"), |
379 | }; | 360 | }; |
380 | 361 | ||
381 | static const char *audio_map[][3] = { | 362 | static const struct snd_soc_dapm_route audio_map[] = { |
382 | /* left mixer */ | 363 | /* left mixer */ |
383 | {"Left Mixer", "Playback Switch", "Left DAC"}, | 364 | {"Left Mixer", "Playback Switch", "Left DAC"}, |
384 | {"Left Mixer", "Left Bypass Switch", "Left Line Mux"}, | 365 | {"Left Mixer", "Left Bypass Switch", "Left Line Mux"}, |
@@ -470,22 +451,14 @@ static const char *audio_map[][3] = { | |||
470 | /* ADC */ | 451 | /* ADC */ |
471 | {"Left ADC", NULL, "Left ADC Mux"}, | 452 | {"Left ADC", NULL, "Left ADC Mux"}, |
472 | {"Right ADC", NULL, "Right ADC Mux"}, | 453 | {"Right ADC", NULL, "Right ADC Mux"}, |
473 | |||
474 | /* terminator */ | ||
475 | {NULL, NULL, NULL}, | ||
476 | }; | 454 | }; |
477 | 455 | ||
478 | static int wm8750_add_widgets(struct snd_soc_codec *codec) | 456 | static int wm8750_add_widgets(struct snd_soc_codec *codec) |
479 | { | 457 | { |
480 | int i; | 458 | snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets, |
481 | 459 | ARRAY_SIZE(wm8750_dapm_widgets)); | |
482 | for (i = 0; i < ARRAY_SIZE(wm8750_dapm_widgets); i++) | ||
483 | snd_soc_dapm_new_control(codec, &wm8750_dapm_widgets[i]); | ||
484 | 460 | ||
485 | /* set up audio path audio_mapnects */ | 461 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
486 | for (i = 0; audio_map[i][0] != NULL; i++) | ||
487 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | ||
488 | audio_map[i][1], audio_map[i][2]); | ||
489 | 462 | ||
490 | snd_soc_dapm_new_widgets(codec); | 463 | snd_soc_dapm_new_widgets(codec); |
491 | return 0; | 464 | return 0; |
@@ -563,7 +536,7 @@ static inline int get_coeff(int mclk, int rate) | |||
563 | return -EINVAL; | 536 | return -EINVAL; |
564 | } | 537 | } |
565 | 538 | ||
566 | static int wm8750_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | 539 | static int wm8750_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
567 | int clk_id, unsigned int freq, int dir) | 540 | int clk_id, unsigned int freq, int dir) |
568 | { | 541 | { |
569 | struct snd_soc_codec *codec = codec_dai->codec; | 542 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -581,7 +554,7 @@ static int wm8750_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | |||
581 | return -EINVAL; | 554 | return -EINVAL; |
582 | } | 555 | } |
583 | 556 | ||
584 | static int wm8750_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 557 | static int wm8750_set_dai_fmt(struct snd_soc_dai *codec_dai, |
585 | unsigned int fmt) | 558 | unsigned int fmt) |
586 | { | 559 | { |
587 | struct snd_soc_codec *codec = codec_dai->codec; | 560 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -674,7 +647,7 @@ static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream, | |||
674 | return 0; | 647 | return 0; |
675 | } | 648 | } |
676 | 649 | ||
677 | static int wm8750_mute(struct snd_soc_codec_dai *dai, int mute) | 650 | static int wm8750_mute(struct snd_soc_dai *dai, int mute) |
678 | { | 651 | { |
679 | struct snd_soc_codec *codec = dai->codec; | 652 | struct snd_soc_codec *codec = dai->codec; |
680 | u16 mute_reg = wm8750_read_reg_cache(codec, WM8750_ADCDAC) & 0xfff7; | 653 | u16 mute_reg = wm8750_read_reg_cache(codec, WM8750_ADCDAC) & 0xfff7; |
@@ -686,29 +659,29 @@ static int wm8750_mute(struct snd_soc_codec_dai *dai, int mute) | |||
686 | return 0; | 659 | return 0; |
687 | } | 660 | } |
688 | 661 | ||
689 | static int wm8750_dapm_event(struct snd_soc_codec *codec, int event) | 662 | static int wm8750_set_bias_level(struct snd_soc_codec *codec, |
663 | enum snd_soc_bias_level level) | ||
690 | { | 664 | { |
691 | u16 pwr_reg = wm8750_read_reg_cache(codec, WM8750_PWR1) & 0xfe3e; | 665 | u16 pwr_reg = wm8750_read_reg_cache(codec, WM8750_PWR1) & 0xfe3e; |
692 | 666 | ||
693 | switch (event) { | 667 | switch (level) { |
694 | case SNDRV_CTL_POWER_D0: /* full On */ | 668 | case SND_SOC_BIAS_ON: |
695 | /* set vmid to 50k and unmute dac */ | 669 | /* set vmid to 50k and unmute dac */ |
696 | wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x00c0); | 670 | wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x00c0); |
697 | break; | 671 | break; |
698 | case SNDRV_CTL_POWER_D1: /* partial On */ | 672 | case SND_SOC_BIAS_PREPARE: |
699 | case SNDRV_CTL_POWER_D2: /* partial On */ | ||
700 | /* set vmid to 5k for quick power up */ | 673 | /* set vmid to 5k for quick power up */ |
701 | wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x01c1); | 674 | wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x01c1); |
702 | break; | 675 | break; |
703 | case SNDRV_CTL_POWER_D3hot: /* Off, with power */ | 676 | case SND_SOC_BIAS_STANDBY: |
704 | /* mute dac and set vmid to 500k, enable VREF */ | 677 | /* mute dac and set vmid to 500k, enable VREF */ |
705 | wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x0141); | 678 | wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x0141); |
706 | break; | 679 | break; |
707 | case SNDRV_CTL_POWER_D3cold: /* Off, without power */ | 680 | case SND_SOC_BIAS_OFF: |
708 | wm8750_write(codec, WM8750_PWR1, 0x0001); | 681 | wm8750_write(codec, WM8750_PWR1, 0x0001); |
709 | break; | 682 | break; |
710 | } | 683 | } |
711 | codec->dapm_state = event; | 684 | codec->bias_level = level; |
712 | return 0; | 685 | return 0; |
713 | } | 686 | } |
714 | 687 | ||
@@ -719,7 +692,7 @@ static int wm8750_dapm_event(struct snd_soc_codec *codec, int event) | |||
719 | #define WM8750_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | 692 | #define WM8750_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
720 | SNDRV_PCM_FMTBIT_S24_LE) | 693 | SNDRV_PCM_FMTBIT_S24_LE) |
721 | 694 | ||
722 | struct snd_soc_codec_dai wm8750_dai = { | 695 | struct snd_soc_dai wm8750_dai = { |
723 | .name = "WM8750", | 696 | .name = "WM8750", |
724 | .playback = { | 697 | .playback = { |
725 | .stream_name = "Playback", | 698 | .stream_name = "Playback", |
@@ -748,7 +721,7 @@ static void wm8750_work(struct work_struct *work) | |||
748 | { | 721 | { |
749 | struct snd_soc_codec *codec = | 722 | struct snd_soc_codec *codec = |
750 | container_of(work, struct snd_soc_codec, delayed_work.work); | 723 | container_of(work, struct snd_soc_codec, delayed_work.work); |
751 | wm8750_dapm_event(codec, codec->dapm_state); | 724 | wm8750_set_bias_level(codec, codec->bias_level); |
752 | } | 725 | } |
753 | 726 | ||
754 | static int wm8750_suspend(struct platform_device *pdev, pm_message_t state) | 727 | static int wm8750_suspend(struct platform_device *pdev, pm_message_t state) |
@@ -756,7 +729,7 @@ static int wm8750_suspend(struct platform_device *pdev, pm_message_t state) | |||
756 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 729 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
757 | struct snd_soc_codec *codec = socdev->codec; | 730 | struct snd_soc_codec *codec = socdev->codec; |
758 | 731 | ||
759 | wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3cold); | 732 | wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF); |
760 | return 0; | 733 | return 0; |
761 | } | 734 | } |
762 | 735 | ||
@@ -777,12 +750,12 @@ static int wm8750_resume(struct platform_device *pdev) | |||
777 | codec->hw_write(codec->control_data, data, 2); | 750 | codec->hw_write(codec->control_data, data, 2); |
778 | } | 751 | } |
779 | 752 | ||
780 | wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | 753 | wm8750_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
781 | 754 | ||
782 | /* charge wm8750 caps */ | 755 | /* charge wm8750 caps */ |
783 | if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) { | 756 | if (codec->suspend_bias_level == SND_SOC_BIAS_ON) { |
784 | wm8750_dapm_event(codec, SNDRV_CTL_POWER_D2); | 757 | wm8750_set_bias_level(codec, SND_SOC_BIAS_PREPARE); |
785 | codec->dapm_state = SNDRV_CTL_POWER_D0; | 758 | codec->bias_level = SND_SOC_BIAS_ON; |
786 | schedule_delayed_work(&codec->delayed_work, | 759 | schedule_delayed_work(&codec->delayed_work, |
787 | msecs_to_jiffies(1000)); | 760 | msecs_to_jiffies(1000)); |
788 | } | 761 | } |
@@ -803,10 +776,10 @@ static int wm8750_init(struct snd_soc_device *socdev) | |||
803 | codec->owner = THIS_MODULE; | 776 | codec->owner = THIS_MODULE; |
804 | codec->read = wm8750_read_reg_cache; | 777 | codec->read = wm8750_read_reg_cache; |
805 | codec->write = wm8750_write; | 778 | codec->write = wm8750_write; |
806 | codec->dapm_event = wm8750_dapm_event; | 779 | codec->set_bias_level = wm8750_set_bias_level; |
807 | codec->dai = &wm8750_dai; | 780 | codec->dai = &wm8750_dai; |
808 | codec->num_dai = 1; | 781 | codec->num_dai = 1; |
809 | codec->reg_cache_size = sizeof(wm8750_reg); | 782 | codec->reg_cache_size = ARRAY_SIZE(wm8750_reg); |
810 | codec->reg_cache = kmemdup(wm8750_reg, sizeof(wm8750_reg), GFP_KERNEL); | 783 | codec->reg_cache = kmemdup(wm8750_reg, sizeof(wm8750_reg), GFP_KERNEL); |
811 | if (codec->reg_cache == NULL) | 784 | if (codec->reg_cache == NULL) |
812 | return -ENOMEM; | 785 | return -ENOMEM; |
@@ -821,8 +794,8 @@ static int wm8750_init(struct snd_soc_device *socdev) | |||
821 | } | 794 | } |
822 | 795 | ||
823 | /* charge output caps */ | 796 | /* charge output caps */ |
824 | wm8750_dapm_event(codec, SNDRV_CTL_POWER_D2); | 797 | wm8750_set_bias_level(codec, SND_SOC_BIAS_PREPARE); |
825 | codec->dapm_state = SNDRV_CTL_POWER_D3hot; | 798 | codec->bias_level = SND_SOC_BIAS_STANDBY; |
826 | schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000)); | 799 | schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000)); |
827 | 800 | ||
828 | /* set the update bits */ | 801 | /* set the update bits */ |
@@ -904,13 +877,13 @@ static int wm8750_codec_probe(struct i2c_adapter *adap, int addr, int kind) | |||
904 | 877 | ||
905 | ret = i2c_attach_client(i2c); | 878 | ret = i2c_attach_client(i2c); |
906 | if (ret < 0) { | 879 | if (ret < 0) { |
907 | err("failed to attach codec at addr %x\n", addr); | 880 | pr_err("failed to attach codec at addr %x\n", addr); |
908 | goto err; | 881 | goto err; |
909 | } | 882 | } |
910 | 883 | ||
911 | ret = wm8750_init(socdev); | 884 | ret = wm8750_init(socdev); |
912 | if (ret < 0) { | 885 | if (ret < 0) { |
913 | err("failed to initialise WM8750\n"); | 886 | pr_err("failed to initialise WM8750\n"); |
914 | goto err; | 887 | goto err; |
915 | } | 888 | } |
916 | return ret; | 889 | return ret; |
@@ -961,7 +934,7 @@ static int wm8750_probe(struct platform_device *pdev) | |||
961 | struct wm8750_priv *wm8750; | 934 | struct wm8750_priv *wm8750; |
962 | int ret = 0; | 935 | int ret = 0; |
963 | 936 | ||
964 | info("WM8750 Audio Codec %s", WM8750_VERSION); | 937 | pr_info("WM8750 Audio Codec %s", WM8750_VERSION); |
965 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 938 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); |
966 | if (codec == NULL) | 939 | if (codec == NULL) |
967 | return -ENOMEM; | 940 | return -ENOMEM; |
@@ -1021,7 +994,7 @@ static int wm8750_remove(struct platform_device *pdev) | |||
1021 | struct snd_soc_codec *codec = socdev->codec; | 994 | struct snd_soc_codec *codec = socdev->codec; |
1022 | 995 | ||
1023 | if (codec->control_data) | 996 | if (codec->control_data) |
1024 | wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3cold); | 997 | wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1025 | run_delayed_work(&codec->delayed_work); | 998 | run_delayed_work(&codec->delayed_work); |
1026 | snd_soc_free_pcms(socdev); | 999 | snd_soc_free_pcms(socdev); |
1027 | snd_soc_dapm_free(socdev); | 1000 | snd_soc_dapm_free(socdev); |
diff --git a/sound/soc/codecs/wm8750.h b/sound/soc/codecs/wm8750.h index a97a54a6348e..8ef30e628b21 100644 --- a/sound/soc/codecs/wm8750.h +++ b/sound/soc/codecs/wm8750.h | |||
@@ -61,7 +61,7 @@ struct wm8750_setup_data { | |||
61 | unsigned short i2c_address; | 61 | unsigned short i2c_address; |
62 | }; | 62 | }; |
63 | 63 | ||
64 | extern struct snd_soc_codec_dai wm8750_dai; | 64 | extern struct snd_soc_dai wm8750_dai; |
65 | extern struct snd_soc_codec_device soc_codec_dev_wm8750; | 65 | extern struct snd_soc_codec_device soc_codec_dev_wm8750; |
66 | 66 | ||
67 | #endif | 67 | #endif |
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index fb41826c4c4c..8604809f0c36 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c | |||
@@ -55,25 +55,6 @@ | |||
55 | #define AUDIO_NAME "wm8753" | 55 | #define AUDIO_NAME "wm8753" |
56 | #define WM8753_VERSION "0.16" | 56 | #define WM8753_VERSION "0.16" |
57 | 57 | ||
58 | /* | ||
59 | * Debug | ||
60 | */ | ||
61 | |||
62 | #define WM8753_DEBUG 0 | ||
63 | |||
64 | #ifdef WM8753_DEBUG | ||
65 | #define dbg(format, arg...) \ | ||
66 | printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg) | ||
67 | #else | ||
68 | #define dbg(format, arg...) do {} while (0) | ||
69 | #endif | ||
70 | #define err(format, arg...) \ | ||
71 | printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg) | ||
72 | #define info(format, arg...) \ | ||
73 | printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg) | ||
74 | #define warn(format, arg...) \ | ||
75 | printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg) | ||
76 | |||
77 | static int caps_charge = 2000; | 58 | static int caps_charge = 2000; |
78 | module_param(caps_charge, int, 0); | 59 | module_param(caps_charge, int, 0); |
79 | MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)"); | 60 | MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)"); |
@@ -260,28 +241,50 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol, | |||
260 | return 1; | 241 | return 1; |
261 | } | 242 | } |
262 | 243 | ||
263 | static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600); | 244 | static const DECLARE_TLV_DB_SCALE(rec_mix_tlv, -1500, 300, 0); |
245 | static const DECLARE_TLV_DB_SCALE(mic_preamp_tlv, 1200, 600, 0); | ||
246 | static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1); | ||
247 | static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); | ||
248 | static const unsigned int out_tlv[] = { | ||
249 | TLV_DB_RANGE_HEAD(2), | ||
250 | /* 0000000 - 0101111 = "Analogue mute" */ | ||
251 | 0, 48, TLV_DB_SCALE_ITEM(-25500, 0, 0), | ||
252 | 48, 127, TLV_DB_SCALE_ITEM(-7300, 100, 0), | ||
253 | }; | ||
254 | static const DECLARE_TLV_DB_SCALE(mix_tlv, -1500, 300, 0); | ||
255 | static const DECLARE_TLV_DB_SCALE(voice_mix_tlv, -1200, 300, 0); | ||
256 | static const DECLARE_TLV_DB_SCALE(pga_tlv, -1725, 75, 0); | ||
264 | 257 | ||
265 | static const struct snd_kcontrol_new wm8753_snd_controls[] = { | 258 | static const struct snd_kcontrol_new wm8753_snd_controls[] = { |
266 | SOC_DOUBLE_R("PCM Volume", WM8753_LDAC, WM8753_RDAC, 0, 255, 0), | 259 | SOC_DOUBLE_R_TLV("PCM Volume", WM8753_LDAC, WM8753_RDAC, 0, 255, 0, dac_tlv), |
267 | 260 | ||
268 | SOC_DOUBLE_R("ADC Capture Volume", WM8753_LADC, WM8753_RADC, 0, 255, 0), | 261 | SOC_DOUBLE_R_TLV("ADC Capture Volume", WM8753_LADC, WM8753_RADC, 0, 255, 0, |
269 | 262 | adc_tlv), | |
270 | SOC_DOUBLE_R("Headphone Playback Volume", WM8753_LOUT1V, WM8753_ROUT1V, 0, 127, 0), | 263 | |
271 | SOC_DOUBLE_R("Speaker Playback Volume", WM8753_LOUT2V, WM8753_ROUT2V, 0, 127, 0), | 264 | SOC_DOUBLE_R_TLV("Headphone Playback Volume", WM8753_LOUT1V, WM8753_ROUT1V, |
272 | 265 | 0, 127, 0, out_tlv), | |
273 | SOC_SINGLE("Mono Playback Volume", WM8753_MOUTV, 0, 127, 0), | 266 | SOC_DOUBLE_R_TLV("Speaker Playback Volume", WM8753_LOUT2V, WM8753_ROUT2V, 0, |
274 | 267 | 127, 0, out_tlv), | |
275 | SOC_DOUBLE_R("Bypass Playback Volume", WM8753_LOUTM1, WM8753_ROUTM1, 4, 7, 1), | 268 | |
276 | SOC_DOUBLE_R("Sidetone Playback Volume", WM8753_LOUTM2, WM8753_ROUTM2, 4, 7, 1), | 269 | SOC_SINGLE_TLV("Mono Playback Volume", WM8753_MOUTV, 0, 127, 0, out_tlv), |
277 | SOC_DOUBLE_R("Voice Playback Volume", WM8753_LOUTM2, WM8753_ROUTM2, 0, 7, 1), | 270 | |
278 | 271 | SOC_DOUBLE_R_TLV("Bypass Playback Volume", WM8753_LOUTM1, WM8753_ROUTM1, 4, 7, | |
279 | SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8753_LOUT1V, WM8753_ROUT1V, 7, 1, 0), | 272 | 1, mix_tlv), |
280 | SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8753_LOUT2V, WM8753_ROUT2V, 7, 1, 0), | 273 | SOC_DOUBLE_R_TLV("Sidetone Playback Volume", WM8753_LOUTM2, WM8753_ROUTM2, 4, |
281 | 274 | 7, 1, mix_tlv), | |
282 | SOC_SINGLE("Mono Bypass Playback Volume", WM8753_MOUTM1, 4, 7, 1), | 275 | SOC_DOUBLE_R_TLV("Voice Playback Volume", WM8753_LOUTM2, WM8753_ROUTM2, 0, 7, |
283 | SOC_SINGLE("Mono Sidetone Playback Volume", WM8753_MOUTM2, 4, 7, 1), | 276 | 1, voice_mix_tlv), |
284 | SOC_SINGLE("Mono Voice Playback Volume", WM8753_MOUTM2, 0, 7, 1), | 277 | |
278 | SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8753_LOUT1V, WM8753_ROUT1V, 7, | ||
279 | 1, 0), | ||
280 | SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8753_LOUT2V, WM8753_ROUT2V, 7, | ||
281 | 1, 0), | ||
282 | |||
283 | SOC_SINGLE_TLV("Mono Bypass Playback Volume", WM8753_MOUTM1, 4, 7, 1, mix_tlv), | ||
284 | SOC_SINGLE_TLV("Mono Sidetone Playback Volume", WM8753_MOUTM2, 4, 7, 1, | ||
285 | mix_tlv), | ||
286 | SOC_SINGLE_TLV("Mono Voice Playback Volume", WM8753_MOUTM2, 0, 7, 1, | ||
287 | voice_mix_tlv), | ||
285 | SOC_SINGLE("Mono Playback ZC Switch", WM8753_MOUTV, 7, 1, 0), | 288 | SOC_SINGLE("Mono Playback ZC Switch", WM8753_MOUTV, 7, 1, 0), |
286 | 289 | ||
287 | SOC_ENUM("Bass Boost", wm8753_enum[0]), | 290 | SOC_ENUM("Bass Boost", wm8753_enum[0]), |
@@ -291,10 +294,13 @@ SOC_SINGLE("Bass Volume", WM8753_BASS, 0, 15, 1), | |||
291 | SOC_SINGLE("Treble Volume", WM8753_TREBLE, 0, 15, 1), | 294 | SOC_SINGLE("Treble Volume", WM8753_TREBLE, 0, 15, 1), |
292 | SOC_ENUM("Treble Cut-off", wm8753_enum[2]), | 295 | SOC_ENUM("Treble Cut-off", wm8753_enum[2]), |
293 | 296 | ||
294 | SOC_DOUBLE_TLV("Sidetone Capture Volume", WM8753_RECMIX1, 0, 4, 7, 1, rec_mix_tlv), | 297 | SOC_DOUBLE_TLV("Sidetone Capture Volume", WM8753_RECMIX1, 0, 4, 7, 1, |
295 | SOC_SINGLE_TLV("Voice Sidetone Capture Volume", WM8753_RECMIX2, 0, 7, 1, rec_mix_tlv), | 298 | rec_mix_tlv), |
299 | SOC_SINGLE_TLV("Voice Sidetone Capture Volume", WM8753_RECMIX2, 0, 7, 1, | ||
300 | rec_mix_tlv), | ||
296 | 301 | ||
297 | SOC_DOUBLE_R("Capture Volume", WM8753_LINVOL, WM8753_RINVOL, 0, 63, 0), | 302 | SOC_DOUBLE_R_TLV("Capture Volume", WM8753_LINVOL, WM8753_RINVOL, 0, 63, 0, |
303 | pga_tlv), | ||
298 | SOC_DOUBLE_R("Capture ZC Switch", WM8753_LINVOL, WM8753_RINVOL, 6, 1, 0), | 304 | SOC_DOUBLE_R("Capture ZC Switch", WM8753_LINVOL, WM8753_RINVOL, 6, 1, 0), |
299 | SOC_DOUBLE_R("Capture Switch", WM8753_LINVOL, WM8753_RINVOL, 7, 1, 1), | 305 | SOC_DOUBLE_R("Capture Switch", WM8753_LINVOL, WM8753_RINVOL, 7, 1, 1), |
300 | 306 | ||
@@ -326,8 +332,8 @@ SOC_ENUM("De-emphasis", wm8753_enum[8]), | |||
326 | SOC_ENUM("Playback Mono Mix", wm8753_enum[9]), | 332 | SOC_ENUM("Playback Mono Mix", wm8753_enum[9]), |
327 | SOC_ENUM("Playback Phase", wm8753_enum[10]), | 333 | SOC_ENUM("Playback Phase", wm8753_enum[10]), |
328 | 334 | ||
329 | SOC_SINGLE("Mic2 Capture Volume", WM8753_INCTL1, 7, 3, 0), | 335 | SOC_SINGLE_TLV("Mic2 Capture Volume", WM8753_INCTL1, 7, 3, 0, mic_preamp_tlv), |
330 | SOC_SINGLE("Mic1 Capture Volume", WM8753_INCTL1, 5, 3, 0), | 336 | SOC_SINGLE_TLV("Mic1 Capture Volume", WM8753_INCTL1, 5, 3, 0, mic_preamp_tlv), |
331 | 337 | ||
332 | SOC_ENUM_EXT("DAI Mode", wm8753_enum[26], wm8753_get_dai, wm8753_set_dai), | 338 | SOC_ENUM_EXT("DAI Mode", wm8753_enum[26], wm8753_get_dai, wm8753_set_dai), |
333 | 339 | ||
@@ -523,7 +529,7 @@ SND_SOC_DAPM_INPUT("MIC2"), | |||
523 | SND_SOC_DAPM_VMID("VREF"), | 529 | SND_SOC_DAPM_VMID("VREF"), |
524 | }; | 530 | }; |
525 | 531 | ||
526 | static const char *audio_map[][3] = { | 532 | static const struct snd_soc_dapm_route audio_map[] = { |
527 | /* left mixer */ | 533 | /* left mixer */ |
528 | {"Left Mixer", "Left Playback Switch", "Left DAC"}, | 534 | {"Left Mixer", "Left Playback Switch", "Left DAC"}, |
529 | {"Left Mixer", "Voice Playback Switch", "Voice DAC"}, | 535 | {"Left Mixer", "Voice Playback Switch", "Voice DAC"}, |
@@ -674,23 +680,14 @@ static const char *audio_map[][3] = { | |||
674 | 680 | ||
675 | /* ACOP */ | 681 | /* ACOP */ |
676 | {"ACOP", NULL, "ALC Mixer"}, | 682 | {"ACOP", NULL, "ALC Mixer"}, |
677 | |||
678 | /* terminator */ | ||
679 | {NULL, NULL, NULL}, | ||
680 | }; | 683 | }; |
681 | 684 | ||
682 | static int wm8753_add_widgets(struct snd_soc_codec *codec) | 685 | static int wm8753_add_widgets(struct snd_soc_codec *codec) |
683 | { | 686 | { |
684 | int i; | 687 | snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets, |
688 | ARRAY_SIZE(wm8753_dapm_widgets)); | ||
685 | 689 | ||
686 | for (i = 0; i < ARRAY_SIZE(wm8753_dapm_widgets); i++) | 690 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
687 | snd_soc_dapm_new_control(codec, &wm8753_dapm_widgets[i]); | ||
688 | |||
689 | /* set up the WM8753 audio map */ | ||
690 | for (i = 0; audio_map[i][0] != NULL; i++) { | ||
691 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | ||
692 | audio_map[i][1], audio_map[i][2]); | ||
693 | } | ||
694 | 691 | ||
695 | snd_soc_dapm_new_widgets(codec); | 692 | snd_soc_dapm_new_widgets(codec); |
696 | return 0; | 693 | return 0; |
@@ -743,7 +740,7 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int target, | |||
743 | pll_div->k = K; | 740 | pll_div->k = K; |
744 | } | 741 | } |
745 | 742 | ||
746 | static int wm8753_set_dai_pll(struct snd_soc_codec_dai *codec_dai, | 743 | static int wm8753_set_dai_pll(struct snd_soc_dai *codec_dai, |
747 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 744 | int pll_id, unsigned int freq_in, unsigned int freq_out) |
748 | { | 745 | { |
749 | u16 reg, enable; | 746 | u16 reg, enable; |
@@ -866,7 +863,7 @@ static int get_coeff(int mclk, int rate) | |||
866 | /* | 863 | /* |
867 | * Clock after PLL and dividers | 864 | * Clock after PLL and dividers |
868 | */ | 865 | */ |
869 | static int wm8753_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | 866 | static int wm8753_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
870 | int clk_id, unsigned int freq, int dir) | 867 | int clk_id, unsigned int freq, int dir) |
871 | { | 868 | { |
872 | struct snd_soc_codec *codec = codec_dai->codec; | 869 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -893,7 +890,7 @@ static int wm8753_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, | |||
893 | /* | 890 | /* |
894 | * Set's ADC and Voice DAC format. | 891 | * Set's ADC and Voice DAC format. |
895 | */ | 892 | */ |
896 | static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 893 | static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_dai *codec_dai, |
897 | unsigned int fmt) | 894 | unsigned int fmt) |
898 | { | 895 | { |
899 | struct snd_soc_codec *codec = codec_dai->codec; | 896 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -963,7 +960,7 @@ static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream, | |||
963 | /* | 960 | /* |
964 | * Set's PCM dai fmt and BCLK. | 961 | * Set's PCM dai fmt and BCLK. |
965 | */ | 962 | */ |
966 | static int wm8753_pcm_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 963 | static int wm8753_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai, |
967 | unsigned int fmt) | 964 | unsigned int fmt) |
968 | { | 965 | { |
969 | struct snd_soc_codec *codec = codec_dai->codec; | 966 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -1029,7 +1026,7 @@ static int wm8753_pcm_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | |||
1029 | return 0; | 1026 | return 0; |
1030 | } | 1027 | } |
1031 | 1028 | ||
1032 | static int wm8753_set_dai_clkdiv(struct snd_soc_codec_dai *codec_dai, | 1029 | static int wm8753_set_dai_clkdiv(struct snd_soc_dai *codec_dai, |
1033 | int div_id, int div) | 1030 | int div_id, int div) |
1034 | { | 1031 | { |
1035 | struct snd_soc_codec *codec = codec_dai->codec; | 1032 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -1057,7 +1054,7 @@ static int wm8753_set_dai_clkdiv(struct snd_soc_codec_dai *codec_dai, | |||
1057 | /* | 1054 | /* |
1058 | * Set's HiFi DAC format. | 1055 | * Set's HiFi DAC format. |
1059 | */ | 1056 | */ |
1060 | static int wm8753_hdac_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 1057 | static int wm8753_hdac_set_dai_fmt(struct snd_soc_dai *codec_dai, |
1061 | unsigned int fmt) | 1058 | unsigned int fmt) |
1062 | { | 1059 | { |
1063 | struct snd_soc_codec *codec = codec_dai->codec; | 1060 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -1090,7 +1087,7 @@ static int wm8753_hdac_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | |||
1090 | /* | 1087 | /* |
1091 | * Set's I2S DAI format. | 1088 | * Set's I2S DAI format. |
1092 | */ | 1089 | */ |
1093 | static int wm8753_i2s_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 1090 | static int wm8753_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai, |
1094 | unsigned int fmt) | 1091 | unsigned int fmt) |
1095 | { | 1092 | { |
1096 | struct snd_soc_codec *codec = codec_dai->codec; | 1093 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -1198,7 +1195,7 @@ static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream, | |||
1198 | return 0; | 1195 | return 0; |
1199 | } | 1196 | } |
1200 | 1197 | ||
1201 | static int wm8753_mode1v_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 1198 | static int wm8753_mode1v_set_dai_fmt(struct snd_soc_dai *codec_dai, |
1202 | unsigned int fmt) | 1199 | unsigned int fmt) |
1203 | { | 1200 | { |
1204 | struct snd_soc_codec *codec = codec_dai->codec; | 1201 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -1213,7 +1210,7 @@ static int wm8753_mode1v_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | |||
1213 | return wm8753_pcm_set_dai_fmt(codec_dai, fmt); | 1210 | return wm8753_pcm_set_dai_fmt(codec_dai, fmt); |
1214 | } | 1211 | } |
1215 | 1212 | ||
1216 | static int wm8753_mode1h_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 1213 | static int wm8753_mode1h_set_dai_fmt(struct snd_soc_dai *codec_dai, |
1217 | unsigned int fmt) | 1214 | unsigned int fmt) |
1218 | { | 1215 | { |
1219 | if (wm8753_hdac_set_dai_fmt(codec_dai, fmt) < 0) | 1216 | if (wm8753_hdac_set_dai_fmt(codec_dai, fmt) < 0) |
@@ -1221,7 +1218,7 @@ static int wm8753_mode1h_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | |||
1221 | return wm8753_i2s_set_dai_fmt(codec_dai, fmt); | 1218 | return wm8753_i2s_set_dai_fmt(codec_dai, fmt); |
1222 | } | 1219 | } |
1223 | 1220 | ||
1224 | static int wm8753_mode2_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 1221 | static int wm8753_mode2_set_dai_fmt(struct snd_soc_dai *codec_dai, |
1225 | unsigned int fmt) | 1222 | unsigned int fmt) |
1226 | { | 1223 | { |
1227 | struct snd_soc_codec *codec = codec_dai->codec; | 1224 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -1236,7 +1233,7 @@ static int wm8753_mode2_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | |||
1236 | return wm8753_i2s_set_dai_fmt(codec_dai, fmt); | 1233 | return wm8753_i2s_set_dai_fmt(codec_dai, fmt); |
1237 | } | 1234 | } |
1238 | 1235 | ||
1239 | static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 1236 | static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_dai *codec_dai, |
1240 | unsigned int fmt) | 1237 | unsigned int fmt) |
1241 | { | 1238 | { |
1242 | struct snd_soc_codec *codec = codec_dai->codec; | 1239 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -1253,7 +1250,7 @@ static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | |||
1253 | return wm8753_i2s_set_dai_fmt(codec_dai, fmt); | 1250 | return wm8753_i2s_set_dai_fmt(codec_dai, fmt); |
1254 | } | 1251 | } |
1255 | 1252 | ||
1256 | static int wm8753_mute(struct snd_soc_codec_dai *dai, int mute) | 1253 | static int wm8753_mute(struct snd_soc_dai *dai, int mute) |
1257 | { | 1254 | { |
1258 | struct snd_soc_codec *codec = dai->codec; | 1255 | struct snd_soc_codec *codec = dai->codec; |
1259 | u16 mute_reg = wm8753_read_reg_cache(codec, WM8753_DAC) & 0xfff7; | 1256 | u16 mute_reg = wm8753_read_reg_cache(codec, WM8753_DAC) & 0xfff7; |
@@ -1274,29 +1271,29 @@ static int wm8753_mute(struct snd_soc_codec_dai *dai, int mute) | |||
1274 | return 0; | 1271 | return 0; |
1275 | } | 1272 | } |
1276 | 1273 | ||
1277 | static int wm8753_dapm_event(struct snd_soc_codec *codec, int event) | 1274 | static int wm8753_set_bias_level(struct snd_soc_codec *codec, |
1275 | enum snd_soc_bias_level level) | ||
1278 | { | 1276 | { |
1279 | u16 pwr_reg = wm8753_read_reg_cache(codec, WM8753_PWR1) & 0xfe3e; | 1277 | u16 pwr_reg = wm8753_read_reg_cache(codec, WM8753_PWR1) & 0xfe3e; |
1280 | 1278 | ||
1281 | switch (event) { | 1279 | switch (level) { |
1282 | case SNDRV_CTL_POWER_D0: /* full On */ | 1280 | case SND_SOC_BIAS_ON: |
1283 | /* set vmid to 50k and unmute dac */ | 1281 | /* set vmid to 50k and unmute dac */ |
1284 | wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x00c0); | 1282 | wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x00c0); |
1285 | break; | 1283 | break; |
1286 | case SNDRV_CTL_POWER_D1: /* partial On */ | 1284 | case SND_SOC_BIAS_PREPARE: |
1287 | case SNDRV_CTL_POWER_D2: /* partial On */ | ||
1288 | /* set vmid to 5k for quick power up */ | 1285 | /* set vmid to 5k for quick power up */ |
1289 | wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x01c1); | 1286 | wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x01c1); |
1290 | break; | 1287 | break; |
1291 | case SNDRV_CTL_POWER_D3hot: /* Off, with power */ | 1288 | case SND_SOC_BIAS_STANDBY: |
1292 | /* mute dac and set vmid to 500k, enable VREF */ | 1289 | /* mute dac and set vmid to 500k, enable VREF */ |
1293 | wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x0141); | 1290 | wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x0141); |
1294 | break; | 1291 | break; |
1295 | case SNDRV_CTL_POWER_D3cold: /* Off, without power */ | 1292 | case SND_SOC_BIAS_OFF: |
1296 | wm8753_write(codec, WM8753_PWR1, 0x0001); | 1293 | wm8753_write(codec, WM8753_PWR1, 0x0001); |
1297 | break; | 1294 | break; |
1298 | } | 1295 | } |
1299 | codec->dapm_state = event; | 1296 | codec->bias_level = level; |
1300 | return 0; | 1297 | return 0; |
1301 | } | 1298 | } |
1302 | 1299 | ||
@@ -1319,7 +1316,7 @@ static int wm8753_dapm_event(struct snd_soc_codec *codec, int event) | |||
1319 | * 3. Voice disabled - HIFI over HIFI | 1316 | * 3. Voice disabled - HIFI over HIFI |
1320 | * 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture | 1317 | * 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture |
1321 | */ | 1318 | */ |
1322 | static const struct snd_soc_codec_dai wm8753_all_dai[] = { | 1319 | static const struct snd_soc_dai wm8753_all_dai[] = { |
1323 | /* DAI HiFi mode 1 */ | 1320 | /* DAI HiFi mode 1 */ |
1324 | { .name = "WM8753 HiFi", | 1321 | { .name = "WM8753 HiFi", |
1325 | .id = 1, | 1322 | .id = 1, |
@@ -1459,7 +1456,7 @@ static const struct snd_soc_codec_dai wm8753_all_dai[] = { | |||
1459 | }, | 1456 | }, |
1460 | }; | 1457 | }; |
1461 | 1458 | ||
1462 | struct snd_soc_codec_dai wm8753_dai[2]; | 1459 | struct snd_soc_dai wm8753_dai[2]; |
1463 | EXPORT_SYMBOL_GPL(wm8753_dai); | 1460 | EXPORT_SYMBOL_GPL(wm8753_dai); |
1464 | 1461 | ||
1465 | static void wm8753_set_dai_mode(struct snd_soc_codec *codec, unsigned int mode) | 1462 | static void wm8753_set_dai_mode(struct snd_soc_codec *codec, unsigned int mode) |
@@ -1500,7 +1497,7 @@ static void wm8753_work(struct work_struct *work) | |||
1500 | { | 1497 | { |
1501 | struct snd_soc_codec *codec = | 1498 | struct snd_soc_codec *codec = |
1502 | container_of(work, struct snd_soc_codec, delayed_work.work); | 1499 | container_of(work, struct snd_soc_codec, delayed_work.work); |
1503 | wm8753_dapm_event(codec, codec->dapm_state); | 1500 | wm8753_set_bias_level(codec, codec->bias_level); |
1504 | } | 1501 | } |
1505 | 1502 | ||
1506 | static int wm8753_suspend(struct platform_device *pdev, pm_message_t state) | 1503 | static int wm8753_suspend(struct platform_device *pdev, pm_message_t state) |
@@ -1512,7 +1509,7 @@ static int wm8753_suspend(struct platform_device *pdev, pm_message_t state) | |||
1512 | if (!codec->card) | 1509 | if (!codec->card) |
1513 | return 0; | 1510 | return 0; |
1514 | 1511 | ||
1515 | wm8753_dapm_event(codec, SNDRV_CTL_POWER_D3cold); | 1512 | wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1516 | return 0; | 1513 | return 0; |
1517 | } | 1514 | } |
1518 | 1515 | ||
@@ -1537,12 +1534,12 @@ static int wm8753_resume(struct platform_device *pdev) | |||
1537 | codec->hw_write(codec->control_data, data, 2); | 1534 | codec->hw_write(codec->control_data, data, 2); |
1538 | } | 1535 | } |
1539 | 1536 | ||
1540 | wm8753_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | 1537 | wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1541 | 1538 | ||
1542 | /* charge wm8753 caps */ | 1539 | /* charge wm8753 caps */ |
1543 | if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) { | 1540 | if (codec->suspend_bias_level == SND_SOC_BIAS_ON) { |
1544 | wm8753_dapm_event(codec, SNDRV_CTL_POWER_D2); | 1541 | wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE); |
1545 | codec->dapm_state = SNDRV_CTL_POWER_D0; | 1542 | codec->bias_level = SND_SOC_BIAS_ON; |
1546 | schedule_delayed_work(&codec->delayed_work, | 1543 | schedule_delayed_work(&codec->delayed_work, |
1547 | msecs_to_jiffies(caps_charge)); | 1544 | msecs_to_jiffies(caps_charge)); |
1548 | } | 1545 | } |
@@ -1563,10 +1560,10 @@ static int wm8753_init(struct snd_soc_device *socdev) | |||
1563 | codec->owner = THIS_MODULE; | 1560 | codec->owner = THIS_MODULE; |
1564 | codec->read = wm8753_read_reg_cache; | 1561 | codec->read = wm8753_read_reg_cache; |
1565 | codec->write = wm8753_write; | 1562 | codec->write = wm8753_write; |
1566 | codec->dapm_event = wm8753_dapm_event; | 1563 | codec->set_bias_level = wm8753_set_bias_level; |
1567 | codec->dai = wm8753_dai; | 1564 | codec->dai = wm8753_dai; |
1568 | codec->num_dai = 2; | 1565 | codec->num_dai = 2; |
1569 | codec->reg_cache_size = sizeof(wm8753_reg); | 1566 | codec->reg_cache_size = ARRAY_SIZE(wm8753_reg); |
1570 | codec->reg_cache = kmemdup(wm8753_reg, sizeof(wm8753_reg), GFP_KERNEL); | 1567 | codec->reg_cache = kmemdup(wm8753_reg, sizeof(wm8753_reg), GFP_KERNEL); |
1571 | 1568 | ||
1572 | if (codec->reg_cache == NULL) | 1569 | if (codec->reg_cache == NULL) |
@@ -1584,8 +1581,8 @@ static int wm8753_init(struct snd_soc_device *socdev) | |||
1584 | } | 1581 | } |
1585 | 1582 | ||
1586 | /* charge output caps */ | 1583 | /* charge output caps */ |
1587 | wm8753_dapm_event(codec, SNDRV_CTL_POWER_D2); | 1584 | wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE); |
1588 | codec->dapm_state = SNDRV_CTL_POWER_D3hot; | 1585 | codec->bias_level = SND_SOC_BIAS_STANDBY; |
1589 | schedule_delayed_work(&codec->delayed_work, | 1586 | schedule_delayed_work(&codec->delayed_work, |
1590 | msecs_to_jiffies(caps_charge)); | 1587 | msecs_to_jiffies(caps_charge)); |
1591 | 1588 | ||
@@ -1673,13 +1670,13 @@ static int wm8753_codec_probe(struct i2c_adapter *adap, int addr, int kind) | |||
1673 | 1670 | ||
1674 | ret = i2c_attach_client(i2c); | 1671 | ret = i2c_attach_client(i2c); |
1675 | if (ret < 0) { | 1672 | if (ret < 0) { |
1676 | err("failed to attach codec at addr %x\n", addr); | 1673 | pr_err("failed to attach codec at addr %x\n", addr); |
1677 | goto err; | 1674 | goto err; |
1678 | } | 1675 | } |
1679 | 1676 | ||
1680 | ret = wm8753_init(socdev); | 1677 | ret = wm8753_init(socdev); |
1681 | if (ret < 0) { | 1678 | if (ret < 0) { |
1682 | err("failed to initialise WM8753\n"); | 1679 | pr_err("failed to initialise WM8753\n"); |
1683 | goto err; | 1680 | goto err; |
1684 | } | 1681 | } |
1685 | 1682 | ||
@@ -1731,7 +1728,7 @@ static int wm8753_probe(struct platform_device *pdev) | |||
1731 | struct wm8753_priv *wm8753; | 1728 | struct wm8753_priv *wm8753; |
1732 | int ret = 0; | 1729 | int ret = 0; |
1733 | 1730 | ||
1734 | info("WM8753 Audio Codec %s", WM8753_VERSION); | 1731 | pr_info("WM8753 Audio Codec %s", WM8753_VERSION); |
1735 | 1732 | ||
1736 | setup = socdev->codec_data; | 1733 | setup = socdev->codec_data; |
1737 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 1734 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); |
@@ -1792,7 +1789,7 @@ static int wm8753_remove(struct platform_device *pdev) | |||
1792 | struct snd_soc_codec *codec = socdev->codec; | 1789 | struct snd_soc_codec *codec = socdev->codec; |
1793 | 1790 | ||
1794 | if (codec->control_data) | 1791 | if (codec->control_data) |
1795 | wm8753_dapm_event(codec, SNDRV_CTL_POWER_D3cold); | 1792 | wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1796 | run_delayed_work(&codec->delayed_work); | 1793 | run_delayed_work(&codec->delayed_work); |
1797 | snd_soc_free_pcms(socdev); | 1794 | snd_soc_free_pcms(socdev); |
1798 | snd_soc_dapm_free(socdev); | 1795 | snd_soc_dapm_free(socdev); |
diff --git a/sound/soc/codecs/wm8753.h b/sound/soc/codecs/wm8753.h index 95e2a1f53169..44f5f1ff0cc7 100644 --- a/sound/soc/codecs/wm8753.h +++ b/sound/soc/codecs/wm8753.h | |||
@@ -120,7 +120,7 @@ struct wm8753_setup_data { | |||
120 | #define WM8753_DAI_HIFI 0 | 120 | #define WM8753_DAI_HIFI 0 |
121 | #define WM8753_DAI_VOICE 1 | 121 | #define WM8753_DAI_VOICE 1 |
122 | 122 | ||
123 | extern struct snd_soc_codec_dai wm8753_dai[2]; | 123 | extern struct snd_soc_dai wm8753_dai[2]; |
124 | extern struct snd_soc_codec_device soc_codec_dev_wm8753; | 124 | extern struct snd_soc_codec_device soc_codec_dev_wm8753; |
125 | 125 | ||
126 | #endif | 126 | #endif |
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c new file mode 100644 index 000000000000..3ecce5168e94 --- /dev/null +++ b/sound/soc/codecs/wm8990.c | |||
@@ -0,0 +1,1626 @@ | |||
1 | /* | ||
2 | * wm8990.c -- WM8990 ALSA Soc Audio driver | ||
3 | * | ||
4 | * Copyright 2008 Wolfson Microelectronics PLC. | ||
5 | * Author: Liam Girdwood | ||
6 | * lg@opensource.wolfsonmicro.com or linux@wolfsonmicro.com | ||
7 | * | ||
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 | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/moduleparam.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/pm.h> | ||
20 | #include <linux/i2c.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <sound/core.h> | ||
23 | #include <sound/pcm.h> | ||
24 | #include <sound/pcm_params.h> | ||
25 | #include <sound/soc.h> | ||
26 | #include <sound/soc-dapm.h> | ||
27 | #include <sound/initval.h> | ||
28 | #include <sound/tlv.h> | ||
29 | #include <asm/div64.h> | ||
30 | |||
31 | #include "wm8990.h" | ||
32 | |||
33 | #define AUDIO_NAME "wm8990" | ||
34 | #define WM8990_VERSION "0.2" | ||
35 | |||
36 | /* codec private data */ | ||
37 | struct wm8990_priv { | ||
38 | unsigned int sysclk; | ||
39 | unsigned int pcmclk; | ||
40 | }; | ||
41 | |||
42 | /* | ||
43 | * wm8990 register cache. Note that register 0 is not included in the | ||
44 | * cache. | ||
45 | */ | ||
46 | static const u16 wm8990_reg[] = { | ||
47 | 0x8990, /* R0 - Reset */ | ||
48 | 0x0000, /* R1 - Power Management (1) */ | ||
49 | 0x6000, /* R2 - Power Management (2) */ | ||
50 | 0x0000, /* R3 - Power Management (3) */ | ||
51 | 0x4050, /* R4 - Audio Interface (1) */ | ||
52 | 0x4000, /* R5 - Audio Interface (2) */ | ||
53 | 0x01C8, /* R6 - Clocking (1) */ | ||
54 | 0x0000, /* R7 - Clocking (2) */ | ||
55 | 0x0040, /* R8 - Audio Interface (3) */ | ||
56 | 0x0040, /* R9 - Audio Interface (4) */ | ||
57 | 0x0004, /* R10 - DAC CTRL */ | ||
58 | 0x00C0, /* R11 - Left DAC Digital Volume */ | ||
59 | 0x00C0, /* R12 - Right DAC Digital Volume */ | ||
60 | 0x0000, /* R13 - Digital Side Tone */ | ||
61 | 0x0100, /* R14 - ADC CTRL */ | ||
62 | 0x00C0, /* R15 - Left ADC Digital Volume */ | ||
63 | 0x00C0, /* R16 - Right ADC Digital Volume */ | ||
64 | 0x0000, /* R17 */ | ||
65 | 0x0000, /* R18 - GPIO CTRL 1 */ | ||
66 | 0x1000, /* R19 - GPIO1 & GPIO2 */ | ||
67 | 0x1010, /* R20 - GPIO3 & GPIO4 */ | ||
68 | 0x1010, /* R21 - GPIO5 & GPIO6 */ | ||
69 | 0x8000, /* R22 - GPIOCTRL 2 */ | ||
70 | 0x0800, /* R23 - GPIO_POL */ | ||
71 | 0x008B, /* R24 - Left Line Input 1&2 Volume */ | ||
72 | 0x008B, /* R25 - Left Line Input 3&4 Volume */ | ||
73 | 0x008B, /* R26 - Right Line Input 1&2 Volume */ | ||
74 | 0x008B, /* R27 - Right Line Input 3&4 Volume */ | ||
75 | 0x0000, /* R28 - Left Output Volume */ | ||
76 | 0x0000, /* R29 - Right Output Volume */ | ||
77 | 0x0066, /* R30 - Line Outputs Volume */ | ||
78 | 0x0022, /* R31 - Out3/4 Volume */ | ||
79 | 0x0079, /* R32 - Left OPGA Volume */ | ||
80 | 0x0079, /* R33 - Right OPGA Volume */ | ||
81 | 0x0003, /* R34 - Speaker Volume */ | ||
82 | 0x0003, /* R35 - ClassD1 */ | ||
83 | 0x0000, /* R36 */ | ||
84 | 0x0100, /* R37 - ClassD3 */ | ||
85 | 0x0000, /* R38 */ | ||
86 | 0x0000, /* R39 - Input Mixer1 */ | ||
87 | 0x0000, /* R40 - Input Mixer2 */ | ||
88 | 0x0000, /* R41 - Input Mixer3 */ | ||
89 | 0x0000, /* R42 - Input Mixer4 */ | ||
90 | 0x0000, /* R43 - Input Mixer5 */ | ||
91 | 0x0000, /* R44 - Input Mixer6 */ | ||
92 | 0x0000, /* R45 - Output Mixer1 */ | ||
93 | 0x0000, /* R46 - Output Mixer2 */ | ||
94 | 0x0000, /* R47 - Output Mixer3 */ | ||
95 | 0x0000, /* R48 - Output Mixer4 */ | ||
96 | 0x0000, /* R49 - Output Mixer5 */ | ||
97 | 0x0000, /* R50 - Output Mixer6 */ | ||
98 | 0x0180, /* R51 - Out3/4 Mixer */ | ||
99 | 0x0000, /* R52 - Line Mixer1 */ | ||
100 | 0x0000, /* R53 - Line Mixer2 */ | ||
101 | 0x0000, /* R54 - Speaker Mixer */ | ||
102 | 0x0000, /* R55 - Additional Control */ | ||
103 | 0x0000, /* R56 - AntiPOP1 */ | ||
104 | 0x0000, /* R57 - AntiPOP2 */ | ||
105 | 0x0000, /* R58 - MICBIAS */ | ||
106 | 0x0000, /* R59 */ | ||
107 | 0x0008, /* R60 - PLL1 */ | ||
108 | 0x0031, /* R61 - PLL2 */ | ||
109 | 0x0026, /* R62 - PLL3 */ | ||
110 | }; | ||
111 | |||
112 | /* | ||
113 | * read wm8990 register cache | ||
114 | */ | ||
115 | static inline unsigned int wm8990_read_reg_cache(struct snd_soc_codec *codec, | ||
116 | unsigned int reg) | ||
117 | { | ||
118 | u16 *cache = codec->reg_cache; | ||
119 | BUG_ON(reg > (ARRAY_SIZE(wm8990_reg)) - 1); | ||
120 | return cache[reg]; | ||
121 | } | ||
122 | |||
123 | /* | ||
124 | * write wm8990 register cache | ||
125 | */ | ||
126 | static inline void wm8990_write_reg_cache(struct snd_soc_codec *codec, | ||
127 | unsigned int reg, unsigned int value) | ||
128 | { | ||
129 | u16 *cache = codec->reg_cache; | ||
130 | BUG_ON(reg > (ARRAY_SIZE(wm8990_reg)) - 1); | ||
131 | |||
132 | /* Reset register is uncached */ | ||
133 | if (reg == 0) | ||
134 | return; | ||
135 | |||
136 | cache[reg] = value; | ||
137 | } | ||
138 | |||
139 | /* | ||
140 | * write to the wm8990 register space | ||
141 | */ | ||
142 | static int wm8990_write(struct snd_soc_codec *codec, unsigned int reg, | ||
143 | unsigned int value) | ||
144 | { | ||
145 | u8 data[3]; | ||
146 | |||
147 | data[0] = reg & 0xFF; | ||
148 | data[1] = (value >> 8) & 0xFF; | ||
149 | data[2] = value & 0xFF; | ||
150 | |||
151 | wm8990_write_reg_cache(codec, reg, value); | ||
152 | |||
153 | if (codec->hw_write(codec->control_data, data, 3) == 2) | ||
154 | return 0; | ||
155 | else | ||
156 | return -EIO; | ||
157 | } | ||
158 | |||
159 | #define wm8990_reset(c) wm8990_write(c, WM8990_RESET, 0) | ||
160 | |||
161 | static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600); | ||
162 | |||
163 | static const DECLARE_TLV_DB_LINEAR(in_pga_tlv, -1650, 3000); | ||
164 | |||
165 | static const DECLARE_TLV_DB_LINEAR(out_mix_tlv, 0, -2100); | ||
166 | |||
167 | static const DECLARE_TLV_DB_LINEAR(out_pga_tlv, -7300, 600); | ||
168 | |||
169 | static const DECLARE_TLV_DB_LINEAR(out_omix_tlv, -600, 0); | ||
170 | |||
171 | static const DECLARE_TLV_DB_LINEAR(out_dac_tlv, -7163, 0); | ||
172 | |||
173 | static const DECLARE_TLV_DB_LINEAR(in_adc_tlv, -7163, 1763); | ||
174 | |||
175 | static const DECLARE_TLV_DB_LINEAR(out_sidetone_tlv, -3600, 0); | ||
176 | |||
177 | static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, | ||
178 | struct snd_ctl_elem_value *ucontrol) | ||
179 | { | ||
180 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
181 | int reg = kcontrol->private_value & 0xff; | ||
182 | int ret; | ||
183 | u16 val; | ||
184 | |||
185 | ret = snd_soc_put_volsw(kcontrol, ucontrol); | ||
186 | if (ret < 0) | ||
187 | return ret; | ||
188 | |||
189 | /* now hit the volume update bits (always bit 8) */ | ||
190 | val = wm8990_read_reg_cache(codec, reg); | ||
191 | return wm8990_write(codec, reg, val | 0x0100); | ||
192 | } | ||
193 | |||
194 | #define SOC_WM899X_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert,\ | ||
195 | tlv_array) {\ | ||
196 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | ||
197 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | ||
198 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ | ||
199 | .tlv.p = (tlv_array), \ | ||
200 | .info = snd_soc_info_volsw, \ | ||
201 | .get = snd_soc_get_volsw, .put = wm899x_outpga_put_volsw_vu, \ | ||
202 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } | ||
203 | |||
204 | |||
205 | static const char *wm8990_digital_sidetone[] = | ||
206 | {"None", "Left ADC", "Right ADC", "Reserved"}; | ||
207 | |||
208 | static const struct soc_enum wm8990_left_digital_sidetone_enum = | ||
209 | SOC_ENUM_SINGLE(WM8990_DIGITAL_SIDE_TONE, | ||
210 | WM8990_ADC_TO_DACL_SHIFT, | ||
211 | WM8990_ADC_TO_DACL_MASK, | ||
212 | wm8990_digital_sidetone); | ||
213 | |||
214 | static const struct soc_enum wm8990_right_digital_sidetone_enum = | ||
215 | SOC_ENUM_SINGLE(WM8990_DIGITAL_SIDE_TONE, | ||
216 | WM8990_ADC_TO_DACR_SHIFT, | ||
217 | WM8990_ADC_TO_DACR_MASK, | ||
218 | wm8990_digital_sidetone); | ||
219 | |||
220 | static const char *wm8990_adcmode[] = | ||
221 | {"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"}; | ||
222 | |||
223 | static const struct soc_enum wm8990_right_adcmode_enum = | ||
224 | SOC_ENUM_SINGLE(WM8990_ADC_CTRL, | ||
225 | WM8990_ADC_HPF_CUT_SHIFT, | ||
226 | WM8990_ADC_HPF_CUT_MASK, | ||
227 | wm8990_adcmode); | ||
228 | |||
229 | static const struct snd_kcontrol_new wm8990_snd_controls[] = { | ||
230 | /* INMIXL */ | ||
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), | ||
233 | /* INMIXR */ | ||
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), | ||
236 | |||
237 | /* LOMIX */ | ||
238 | SOC_SINGLE_TLV("LOMIX LIN3 Bypass Volume", WM8990_OUTPUT_MIXER3, | ||
239 | WM8990_LLI3LOVOL_SHIFT, WM8990_LLI3LOVOL_MASK, 1, out_mix_tlv), | ||
240 | SOC_SINGLE_TLV("LOMIX RIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER3, | ||
241 | WM8990_LR12LOVOL_SHIFT, WM8990_LR12LOVOL_MASK, 1, out_mix_tlv), | ||
242 | SOC_SINGLE_TLV("LOMIX LIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER3, | ||
243 | WM8990_LL12LOVOL_SHIFT, WM8990_LL12LOVOL_MASK, 1, out_mix_tlv), | ||
244 | SOC_SINGLE_TLV("LOMIX RIN3 Bypass Volume", WM8990_OUTPUT_MIXER5, | ||
245 | WM8990_LRI3LOVOL_SHIFT, WM8990_LRI3LOVOL_MASK, 1, out_mix_tlv), | ||
246 | SOC_SINGLE_TLV("LOMIX AINRMUX Bypass Volume", WM8990_OUTPUT_MIXER5, | ||
247 | WM8990_LRBLOVOL_SHIFT, WM8990_LRBLOVOL_MASK, 1, out_mix_tlv), | ||
248 | SOC_SINGLE_TLV("LOMIX AINLMUX Bypass Volume", WM8990_OUTPUT_MIXER5, | ||
249 | WM8990_LRBLOVOL_SHIFT, WM8990_LRBLOVOL_MASK, 1, out_mix_tlv), | ||
250 | |||
251 | /* ROMIX */ | ||
252 | SOC_SINGLE_TLV("ROMIX RIN3 Bypass Volume", WM8990_OUTPUT_MIXER4, | ||
253 | WM8990_RRI3ROVOL_SHIFT, WM8990_RRI3ROVOL_MASK, 1, out_mix_tlv), | ||
254 | SOC_SINGLE_TLV("ROMIX LIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER4, | ||
255 | WM8990_RL12ROVOL_SHIFT, WM8990_RL12ROVOL_MASK, 1, out_mix_tlv), | ||
256 | SOC_SINGLE_TLV("ROMIX RIN12 PGA Bypass Volume", WM8990_OUTPUT_MIXER4, | ||
257 | WM8990_RR12ROVOL_SHIFT, WM8990_RR12ROVOL_MASK, 1, out_mix_tlv), | ||
258 | SOC_SINGLE_TLV("ROMIX LIN3 Bypass Volume", WM8990_OUTPUT_MIXER6, | ||
259 | WM8990_RLI3ROVOL_SHIFT, WM8990_RLI3ROVOL_MASK, 1, out_mix_tlv), | ||
260 | SOC_SINGLE_TLV("ROMIX AINLMUX Bypass Volume", WM8990_OUTPUT_MIXER6, | ||
261 | WM8990_RLBROVOL_SHIFT, WM8990_RLBROVOL_MASK, 1, out_mix_tlv), | ||
262 | SOC_SINGLE_TLV("ROMIX AINRMUX Bypass Volume", WM8990_OUTPUT_MIXER6, | ||
263 | WM8990_RRBROVOL_SHIFT, WM8990_RRBROVOL_MASK, 1, out_mix_tlv), | ||
264 | |||
265 | /* LOUT */ | ||
266 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("LOUT Volume", WM8990_LEFT_OUTPUT_VOLUME, | ||
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), | ||
269 | |||
270 | /* ROUT */ | ||
271 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("ROUT Volume", WM8990_RIGHT_OUTPUT_VOLUME, | ||
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), | ||
274 | |||
275 | /* LOPGA */ | ||
276 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("LOPGA Volume", WM8990_LEFT_OPGA_VOLUME, | ||
277 | WM8990_LOPGAVOL_SHIFT, WM8990_LOPGAVOL_MASK, 0, out_pga_tlv), | ||
278 | SOC_SINGLE("LOPGA ZC Switch", WM8990_LEFT_OPGA_VOLUME, | ||
279 | WM8990_LOPGAZC_BIT, 1, 0), | ||
280 | |||
281 | /* ROPGA */ | ||
282 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("ROPGA Volume", WM8990_RIGHT_OPGA_VOLUME, | ||
283 | WM8990_ROPGAVOL_SHIFT, WM8990_ROPGAVOL_MASK, 0, out_pga_tlv), | ||
284 | SOC_SINGLE("ROPGA ZC Switch", WM8990_RIGHT_OPGA_VOLUME, | ||
285 | WM8990_ROPGAZC_BIT, 1, 0), | ||
286 | |||
287 | SOC_SINGLE("LON Mute Switch", WM8990_LINE_OUTPUTS_VOLUME, | ||
288 | WM8990_LONMUTE_BIT, 1, 0), | ||
289 | SOC_SINGLE("LOP Mute Switch", WM8990_LINE_OUTPUTS_VOLUME, | ||
290 | WM8990_LOPMUTE_BIT, 1, 0), | ||
291 | SOC_SINGLE("LOP Attenuation Switch", WM8990_LINE_OUTPUTS_VOLUME, | ||
292 | WM8990_LOATTN_BIT, 1, 0), | ||
293 | SOC_SINGLE("RON Mute Switch", WM8990_LINE_OUTPUTS_VOLUME, | ||
294 | WM8990_RONMUTE_BIT, 1, 0), | ||
295 | SOC_SINGLE("ROP Mute Switch", WM8990_LINE_OUTPUTS_VOLUME, | ||
296 | WM8990_ROPMUTE_BIT, 1, 0), | ||
297 | SOC_SINGLE("ROP Attenuation Switch", WM8990_LINE_OUTPUTS_VOLUME, | ||
298 | WM8990_ROATTN_BIT, 1, 0), | ||
299 | |||
300 | SOC_SINGLE("OUT3 Mute Switch", WM8990_OUT3_4_VOLUME, | ||
301 | WM8990_OUT3MUTE_BIT, 1, 0), | ||
302 | SOC_SINGLE("OUT3 Attenuation Switch", WM8990_OUT3_4_VOLUME, | ||
303 | WM8990_OUT3ATTN_BIT, 1, 0), | ||
304 | |||
305 | SOC_SINGLE("OUT4 Mute Switch", WM8990_OUT3_4_VOLUME, | ||
306 | WM8990_OUT4MUTE_BIT, 1, 0), | ||
307 | SOC_SINGLE("OUT4 Attenuation Switch", WM8990_OUT3_4_VOLUME, | ||
308 | WM8990_OUT4ATTN_BIT, 1, 0), | ||
309 | |||
310 | SOC_SINGLE("Speaker Mode Switch", WM8990_CLASSD1, | ||
311 | WM8990_CDMODE_BIT, 1, 0), | ||
312 | |||
313 | SOC_SINGLE("Speaker Output Attenuation Volume", WM8990_SPEAKER_VOLUME, | ||
314 | WM8990_SPKVOL_SHIFT, WM8990_SPKVOL_MASK, 0), | ||
315 | SOC_SINGLE("Speaker DC Boost Volume", WM8990_CLASSD3, | ||
316 | WM8990_DCGAIN_SHIFT, WM8990_DCGAIN_MASK, 0), | ||
317 | SOC_SINGLE("Speaker AC Boost Volume", WM8990_CLASSD3, | ||
318 | WM8990_ACGAIN_SHIFT, WM8990_ACGAIN_MASK, 0), | ||
319 | |||
320 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("Left DAC Digital Volume", | ||
321 | WM8990_LEFT_DAC_DIGITAL_VOLUME, | ||
322 | WM8990_DACL_VOL_SHIFT, | ||
323 | WM8990_DACL_VOL_MASK, | ||
324 | 0, | ||
325 | out_dac_tlv), | ||
326 | |||
327 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("Right DAC Digital Volume", | ||
328 | WM8990_RIGHT_DAC_DIGITAL_VOLUME, | ||
329 | WM8990_DACR_VOL_SHIFT, | ||
330 | WM8990_DACR_VOL_MASK, | ||
331 | 0, | ||
332 | out_dac_tlv), | ||
333 | |||
334 | SOC_ENUM("Left Digital Sidetone", wm8990_left_digital_sidetone_enum), | ||
335 | SOC_ENUM("Right Digital Sidetone", wm8990_right_digital_sidetone_enum), | ||
336 | |||
337 | SOC_SINGLE_TLV("Left Digital Sidetone Volume", WM8990_DIGITAL_SIDE_TONE, | ||
338 | WM8990_ADCL_DAC_SVOL_SHIFT, WM8990_ADCL_DAC_SVOL_MASK, 0, | ||
339 | out_sidetone_tlv), | ||
340 | SOC_SINGLE_TLV("Right Digital Sidetone Volume", WM8990_DIGITAL_SIDE_TONE, | ||
341 | WM8990_ADCR_DAC_SVOL_SHIFT, WM8990_ADCR_DAC_SVOL_MASK, 0, | ||
342 | out_sidetone_tlv), | ||
343 | |||
344 | SOC_SINGLE("ADC Digital High Pass Filter Switch", WM8990_ADC_CTRL, | ||
345 | WM8990_ADC_HPF_ENA_BIT, 1, 0), | ||
346 | |||
347 | SOC_ENUM("ADC HPF Mode", wm8990_right_adcmode_enum), | ||
348 | |||
349 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("Left ADC Digital Volume", | ||
350 | WM8990_LEFT_ADC_DIGITAL_VOLUME, | ||
351 | WM8990_ADCL_VOL_SHIFT, | ||
352 | WM8990_ADCL_VOL_MASK, | ||
353 | 0, | ||
354 | in_adc_tlv), | ||
355 | |||
356 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("Right ADC Digital Volume", | ||
357 | WM8990_RIGHT_ADC_DIGITAL_VOLUME, | ||
358 | WM8990_ADCR_VOL_SHIFT, | ||
359 | WM8990_ADCR_VOL_MASK, | ||
360 | 0, | ||
361 | in_adc_tlv), | ||
362 | |||
363 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("LIN12 Volume", | ||
364 | WM8990_LEFT_LINE_INPUT_1_2_VOLUME, | ||
365 | WM8990_LIN12VOL_SHIFT, | ||
366 | WM8990_LIN12VOL_MASK, | ||
367 | 0, | ||
368 | in_pga_tlv), | ||
369 | |||
370 | SOC_SINGLE("LIN12 ZC Switch", WM8990_LEFT_LINE_INPUT_1_2_VOLUME, | ||
371 | WM8990_LI12ZC_BIT, 1, 0), | ||
372 | |||
373 | SOC_SINGLE("LIN12 Mute Switch", WM8990_LEFT_LINE_INPUT_1_2_VOLUME, | ||
374 | WM8990_LI12MUTE_BIT, 1, 0), | ||
375 | |||
376 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("LIN34 Volume", | ||
377 | WM8990_LEFT_LINE_INPUT_3_4_VOLUME, | ||
378 | WM8990_LIN34VOL_SHIFT, | ||
379 | WM8990_LIN34VOL_MASK, | ||
380 | 0, | ||
381 | in_pga_tlv), | ||
382 | |||
383 | SOC_SINGLE("LIN34 ZC Switch", WM8990_LEFT_LINE_INPUT_3_4_VOLUME, | ||
384 | WM8990_LI34ZC_BIT, 1, 0), | ||
385 | |||
386 | SOC_SINGLE("LIN34 Mute Switch", WM8990_LEFT_LINE_INPUT_3_4_VOLUME, | ||
387 | WM8990_LI34MUTE_BIT, 1, 0), | ||
388 | |||
389 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("RIN12 Volume", | ||
390 | WM8990_RIGHT_LINE_INPUT_1_2_VOLUME, | ||
391 | WM8990_RIN12VOL_SHIFT, | ||
392 | WM8990_RIN12VOL_MASK, | ||
393 | 0, | ||
394 | in_pga_tlv), | ||
395 | |||
396 | SOC_SINGLE("RIN12 ZC Switch", WM8990_RIGHT_LINE_INPUT_1_2_VOLUME, | ||
397 | WM8990_RI12ZC_BIT, 1, 0), | ||
398 | |||
399 | SOC_SINGLE("RIN12 Mute Switch", WM8990_RIGHT_LINE_INPUT_1_2_VOLUME, | ||
400 | WM8990_RI12MUTE_BIT, 1, 0), | ||
401 | |||
402 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("RIN34 Volume", | ||
403 | WM8990_RIGHT_LINE_INPUT_3_4_VOLUME, | ||
404 | WM8990_RIN34VOL_SHIFT, | ||
405 | WM8990_RIN34VOL_MASK, | ||
406 | 0, | ||
407 | in_pga_tlv), | ||
408 | |||
409 | SOC_SINGLE("RIN34 ZC Switch", WM8990_RIGHT_LINE_INPUT_3_4_VOLUME, | ||
410 | WM8990_RI34ZC_BIT, 1, 0), | ||
411 | |||
412 | SOC_SINGLE("RIN34 Mute Switch", WM8990_RIGHT_LINE_INPUT_3_4_VOLUME, | ||
413 | WM8990_RI34MUTE_BIT, 1, 0), | ||
414 | |||
415 | }; | ||
416 | |||
417 | /* add non dapm controls */ | ||
418 | static int wm8990_add_controls(struct snd_soc_codec *codec) | ||
419 | { | ||
420 | int err, i; | ||
421 | |||
422 | for (i = 0; i < ARRAY_SIZE(wm8990_snd_controls); i++) { | ||
423 | err = snd_ctl_add(codec->card, | ||
424 | snd_soc_cnew(&wm8990_snd_controls[i], codec, | ||
425 | NULL)); | ||
426 | if (err < 0) | ||
427 | return err; | ||
428 | } | ||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | /* | ||
433 | * _DAPM_ Controls | ||
434 | */ | ||
435 | |||
436 | static int inmixer_event(struct snd_soc_dapm_widget *w, | ||
437 | struct snd_kcontrol *kcontrol, int event) | ||
438 | { | ||
439 | u16 reg, fakepower; | ||
440 | |||
441 | reg = wm8990_read_reg_cache(w->codec, WM8990_POWER_MANAGEMENT_2); | ||
442 | fakepower = wm8990_read_reg_cache(w->codec, WM8990_INTDRIVBITS); | ||
443 | |||
444 | if (fakepower & ((1 << WM8990_INMIXL_PWR_BIT) | | ||
445 | (1 << WM8990_AINLMUX_PWR_BIT))) { | ||
446 | reg |= WM8990_AINL_ENA; | ||
447 | } else { | ||
448 | reg &= ~WM8990_AINL_ENA; | ||
449 | } | ||
450 | |||
451 | if (fakepower & ((1 << WM8990_INMIXR_PWR_BIT) | | ||
452 | (1 << WM8990_AINRMUX_PWR_BIT))) { | ||
453 | reg |= WM8990_AINR_ENA; | ||
454 | } else { | ||
455 | reg &= ~WM8990_AINL_ENA; | ||
456 | } | ||
457 | wm8990_write(w->codec, WM8990_POWER_MANAGEMENT_2, reg); | ||
458 | |||
459 | return 0; | ||
460 | } | ||
461 | |||
462 | static int outmixer_event(struct snd_soc_dapm_widget *w, | ||
463 | struct snd_kcontrol *kcontrol, int event) | ||
464 | { | ||
465 | u32 reg_shift = kcontrol->private_value & 0xfff; | ||
466 | int ret = 0; | ||
467 | u16 reg; | ||
468 | |||
469 | switch (reg_shift) { | ||
470 | case WM8990_SPEAKER_MIXER | (WM8990_LDSPK_BIT << 8) : | ||
471 | reg = wm8990_read_reg_cache(w->codec, WM8990_OUTPUT_MIXER1); | ||
472 | if (reg & WM8990_LDLO) { | ||
473 | printk(KERN_WARNING | ||
474 | "Cannot set as Output Mixer 1 LDLO Set\n"); | ||
475 | ret = -1; | ||
476 | } | ||
477 | break; | ||
478 | case WM8990_SPEAKER_MIXER | (WM8990_RDSPK_BIT << 8): | ||
479 | reg = wm8990_read_reg_cache(w->codec, WM8990_OUTPUT_MIXER2); | ||
480 | if (reg & WM8990_RDRO) { | ||
481 | printk(KERN_WARNING | ||
482 | "Cannot set as Output Mixer 2 RDRO Set\n"); | ||
483 | ret = -1; | ||
484 | } | ||
485 | break; | ||
486 | case WM8990_OUTPUT_MIXER1 | (WM8990_LDLO_BIT << 8): | ||
487 | reg = wm8990_read_reg_cache(w->codec, WM8990_SPEAKER_MIXER); | ||
488 | if (reg & WM8990_LDSPK) { | ||
489 | printk(KERN_WARNING | ||
490 | "Cannot set as Speaker Mixer LDSPK Set\n"); | ||
491 | ret = -1; | ||
492 | } | ||
493 | break; | ||
494 | case WM8990_OUTPUT_MIXER2 | (WM8990_RDRO_BIT << 8): | ||
495 | reg = wm8990_read_reg_cache(w->codec, WM8990_SPEAKER_MIXER); | ||
496 | if (reg & WM8990_RDSPK) { | ||
497 | printk(KERN_WARNING | ||
498 | "Cannot set as Speaker Mixer RDSPK Set\n"); | ||
499 | ret = -1; | ||
500 | } | ||
501 | break; | ||
502 | } | ||
503 | |||
504 | return ret; | ||
505 | } | ||
506 | |||
507 | /* INMIX dB values */ | ||
508 | static const unsigned int in_mix_tlv[] = { | ||
509 | TLV_DB_RANGE_HEAD(1), | ||
510 | 0, 7, TLV_DB_LINEAR_ITEM(-1200, 600), | ||
511 | }; | ||
512 | |||
513 | /* Left In PGA Connections */ | ||
514 | static const struct snd_kcontrol_new wm8990_dapm_lin12_pga_controls[] = { | ||
515 | SOC_DAPM_SINGLE("LIN1 Switch", WM8990_INPUT_MIXER2, WM8990_LMN1_BIT, 1, 0), | ||
516 | SOC_DAPM_SINGLE("LIN2 Switch", WM8990_INPUT_MIXER2, WM8990_LMP2_BIT, 1, 0), | ||
517 | }; | ||
518 | |||
519 | static const struct snd_kcontrol_new wm8990_dapm_lin34_pga_controls[] = { | ||
520 | SOC_DAPM_SINGLE("LIN3 Switch", WM8990_INPUT_MIXER2, WM8990_LMN3_BIT, 1, 0), | ||
521 | SOC_DAPM_SINGLE("LIN4 Switch", WM8990_INPUT_MIXER2, WM8990_LMP4_BIT, 1, 0), | ||
522 | }; | ||
523 | |||
524 | /* Right In PGA Connections */ | ||
525 | static const struct snd_kcontrol_new wm8990_dapm_rin12_pga_controls[] = { | ||
526 | SOC_DAPM_SINGLE("RIN1 Switch", WM8990_INPUT_MIXER2, WM8990_RMN1_BIT, 1, 0), | ||
527 | SOC_DAPM_SINGLE("RIN2 Switch", WM8990_INPUT_MIXER2, WM8990_RMP2_BIT, 1, 0), | ||
528 | }; | ||
529 | |||
530 | static const struct snd_kcontrol_new wm8990_dapm_rin34_pga_controls[] = { | ||
531 | SOC_DAPM_SINGLE("RIN3 Switch", WM8990_INPUT_MIXER2, WM8990_RMN3_BIT, 1, 0), | ||
532 | SOC_DAPM_SINGLE("RIN4 Switch", WM8990_INPUT_MIXER2, WM8990_RMP4_BIT, 1, 0), | ||
533 | }; | ||
534 | |||
535 | /* INMIXL */ | ||
536 | static const struct snd_kcontrol_new wm8990_dapm_inmixl_controls[] = { | ||
537 | SOC_DAPM_SINGLE_TLV("Record Left Volume", WM8990_INPUT_MIXER3, | ||
538 | WM8990_LDBVOL_SHIFT, WM8990_LDBVOL_MASK, 0, in_mix_tlv), | ||
539 | SOC_DAPM_SINGLE_TLV("LIN2 Volume", WM8990_INPUT_MIXER5, WM8990_LI2BVOL_SHIFT, | ||
540 | 7, 0, in_mix_tlv), | ||
541 | SOC_DAPM_SINGLE("LINPGA12 Switch", WM8990_INPUT_MIXER3, WM8990_L12MNB_BIT, | ||
542 | 1, 0), | ||
543 | SOC_DAPM_SINGLE("LINPGA34 Switch", WM8990_INPUT_MIXER3, WM8990_L34MNB_BIT, | ||
544 | 1, 0), | ||
545 | }; | ||
546 | |||
547 | /* INMIXR */ | ||
548 | static const struct snd_kcontrol_new wm8990_dapm_inmixr_controls[] = { | ||
549 | SOC_DAPM_SINGLE_TLV("Record Right Volume", WM8990_INPUT_MIXER4, | ||
550 | WM8990_RDBVOL_SHIFT, WM8990_RDBVOL_MASK, 0, in_mix_tlv), | ||
551 | SOC_DAPM_SINGLE_TLV("RIN2 Volume", WM8990_INPUT_MIXER6, WM8990_RI2BVOL_SHIFT, | ||
552 | 7, 0, in_mix_tlv), | ||
553 | SOC_DAPM_SINGLE("RINPGA12 Switch", WM8990_INPUT_MIXER3, WM8990_L12MNB_BIT, | ||
554 | 1, 0), | ||
555 | SOC_DAPM_SINGLE("RINPGA34 Switch", WM8990_INPUT_MIXER3, WM8990_L34MNB_BIT, | ||
556 | 1, 0), | ||
557 | }; | ||
558 | |||
559 | /* AINLMUX */ | ||
560 | static const char *wm8990_ainlmux[] = | ||
561 | {"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"}; | ||
562 | |||
563 | static const struct soc_enum wm8990_ainlmux_enum = | ||
564 | SOC_ENUM_SINGLE(WM8990_INPUT_MIXER1, WM8990_AINLMODE_SHIFT, | ||
565 | ARRAY_SIZE(wm8990_ainlmux), wm8990_ainlmux); | ||
566 | |||
567 | static const struct snd_kcontrol_new wm8990_dapm_ainlmux_controls = | ||
568 | SOC_DAPM_ENUM("Route", wm8990_ainlmux_enum); | ||
569 | |||
570 | /* DIFFINL */ | ||
571 | |||
572 | /* AINRMUX */ | ||
573 | static const char *wm8990_ainrmux[] = | ||
574 | {"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"}; | ||
575 | |||
576 | static const struct soc_enum wm8990_ainrmux_enum = | ||
577 | SOC_ENUM_SINGLE(WM8990_INPUT_MIXER1, WM8990_AINRMODE_SHIFT, | ||
578 | ARRAY_SIZE(wm8990_ainrmux), wm8990_ainrmux); | ||
579 | |||
580 | static const struct snd_kcontrol_new wm8990_dapm_ainrmux_controls = | ||
581 | SOC_DAPM_ENUM("Route", wm8990_ainrmux_enum); | ||
582 | |||
583 | /* RXVOICE */ | ||
584 | static const struct snd_kcontrol_new wm8990_dapm_rxvoice_controls[] = { | ||
585 | SOC_DAPM_SINGLE_TLV("LIN4/RXN", WM8990_INPUT_MIXER5, WM8990_LR4BVOL_SHIFT, | ||
586 | WM8990_LR4BVOL_MASK, 0, in_mix_tlv), | ||
587 | SOC_DAPM_SINGLE_TLV("RIN4/RXP", WM8990_INPUT_MIXER6, WM8990_RL4BVOL_SHIFT, | ||
588 | WM8990_RL4BVOL_MASK, 0, in_mix_tlv), | ||
589 | }; | ||
590 | |||
591 | /* LOMIX */ | ||
592 | static const struct snd_kcontrol_new wm8990_dapm_lomix_controls[] = { | ||
593 | SOC_DAPM_SINGLE("LOMIX Right ADC Bypass Switch", WM8990_OUTPUT_MIXER1, | ||
594 | WM8990_LRBLO_BIT, 1, 0), | ||
595 | SOC_DAPM_SINGLE("LOMIX Left ADC Bypass Switch", WM8990_OUTPUT_MIXER1, | ||
596 | WM8990_LLBLO_BIT, 1, 0), | ||
597 | SOC_DAPM_SINGLE("LOMIX RIN3 Bypass Switch", WM8990_OUTPUT_MIXER1, | ||
598 | WM8990_LRI3LO_BIT, 1, 0), | ||
599 | SOC_DAPM_SINGLE("LOMIX LIN3 Bypass Switch", WM8990_OUTPUT_MIXER1, | ||
600 | WM8990_LLI3LO_BIT, 1, 0), | ||
601 | SOC_DAPM_SINGLE("LOMIX RIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER1, | ||
602 | WM8990_LR12LO_BIT, 1, 0), | ||
603 | SOC_DAPM_SINGLE("LOMIX LIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER1, | ||
604 | WM8990_LL12LO_BIT, 1, 0), | ||
605 | SOC_DAPM_SINGLE("LOMIX Left DAC Switch", WM8990_OUTPUT_MIXER1, | ||
606 | WM8990_LDLO_BIT, 1, 0), | ||
607 | }; | ||
608 | |||
609 | /* ROMIX */ | ||
610 | static const struct snd_kcontrol_new wm8990_dapm_romix_controls[] = { | ||
611 | SOC_DAPM_SINGLE("ROMIX Left ADC Bypass Switch", WM8990_OUTPUT_MIXER2, | ||
612 | WM8990_RLBRO_BIT, 1, 0), | ||
613 | SOC_DAPM_SINGLE("ROMIX Right ADC Bypass Switch", WM8990_OUTPUT_MIXER2, | ||
614 | WM8990_RRBRO_BIT, 1, 0), | ||
615 | SOC_DAPM_SINGLE("ROMIX LIN3 Bypass Switch", WM8990_OUTPUT_MIXER2, | ||
616 | WM8990_RLI3RO_BIT, 1, 0), | ||
617 | SOC_DAPM_SINGLE("ROMIX RIN3 Bypass Switch", WM8990_OUTPUT_MIXER2, | ||
618 | WM8990_RRI3RO_BIT, 1, 0), | ||
619 | SOC_DAPM_SINGLE("ROMIX LIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER2, | ||
620 | WM8990_RL12RO_BIT, 1, 0), | ||
621 | SOC_DAPM_SINGLE("ROMIX RIN12 PGA Bypass Switch", WM8990_OUTPUT_MIXER2, | ||
622 | WM8990_RR12RO_BIT, 1, 0), | ||
623 | SOC_DAPM_SINGLE("ROMIX Right DAC Switch", WM8990_OUTPUT_MIXER2, | ||
624 | WM8990_RDRO_BIT, 1, 0), | ||
625 | }; | ||
626 | |||
627 | /* LONMIX */ | ||
628 | static const struct snd_kcontrol_new wm8990_dapm_lonmix_controls[] = { | ||
629 | SOC_DAPM_SINGLE("LONMIX Left Mixer PGA Switch", WM8990_LINE_MIXER1, | ||
630 | WM8990_LLOPGALON_BIT, 1, 0), | ||
631 | SOC_DAPM_SINGLE("LONMIX Right Mixer PGA Switch", WM8990_LINE_MIXER1, | ||
632 | WM8990_LROPGALON_BIT, 1, 0), | ||
633 | SOC_DAPM_SINGLE("LONMIX Inverted LOP Switch", WM8990_LINE_MIXER1, | ||
634 | WM8990_LOPLON_BIT, 1, 0), | ||
635 | }; | ||
636 | |||
637 | /* LOPMIX */ | ||
638 | static const struct snd_kcontrol_new wm8990_dapm_lopmix_controls[] = { | ||
639 | SOC_DAPM_SINGLE("LOPMIX Right Mic Bypass Switch", WM8990_LINE_MIXER1, | ||
640 | WM8990_LR12LOP_BIT, 1, 0), | ||
641 | SOC_DAPM_SINGLE("LOPMIX Left Mic Bypass Switch", WM8990_LINE_MIXER1, | ||
642 | WM8990_LL12LOP_BIT, 1, 0), | ||
643 | SOC_DAPM_SINGLE("LOPMIX Left Mixer PGA Switch", WM8990_LINE_MIXER1, | ||
644 | WM8990_LLOPGALOP_BIT, 1, 0), | ||
645 | }; | ||
646 | |||
647 | /* RONMIX */ | ||
648 | static const struct snd_kcontrol_new wm8990_dapm_ronmix_controls[] = { | ||
649 | SOC_DAPM_SINGLE("RONMIX Right Mixer PGA Switch", WM8990_LINE_MIXER2, | ||
650 | WM8990_RROPGARON_BIT, 1, 0), | ||
651 | SOC_DAPM_SINGLE("RONMIX Left Mixer PGA Switch", WM8990_LINE_MIXER2, | ||
652 | WM8990_RLOPGARON_BIT, 1, 0), | ||
653 | SOC_DAPM_SINGLE("RONMIX Inverted ROP Switch", WM8990_LINE_MIXER2, | ||
654 | WM8990_ROPRON_BIT, 1, 0), | ||
655 | }; | ||
656 | |||
657 | /* ROPMIX */ | ||
658 | static const struct snd_kcontrol_new wm8990_dapm_ropmix_controls[] = { | ||
659 | SOC_DAPM_SINGLE("ROPMIX Left Mic Bypass Switch", WM8990_LINE_MIXER2, | ||
660 | WM8990_RL12ROP_BIT, 1, 0), | ||
661 | SOC_DAPM_SINGLE("ROPMIX Right Mic Bypass Switch", WM8990_LINE_MIXER2, | ||
662 | WM8990_RR12ROP_BIT, 1, 0), | ||
663 | SOC_DAPM_SINGLE("ROPMIX Right Mixer PGA Switch", WM8990_LINE_MIXER2, | ||
664 | WM8990_RROPGAROP_BIT, 1, 0), | ||
665 | }; | ||
666 | |||
667 | /* OUT3MIX */ | ||
668 | static const struct snd_kcontrol_new wm8990_dapm_out3mix_controls[] = { | ||
669 | SOC_DAPM_SINGLE("OUT3MIX LIN4/RXP Bypass Switch", WM8990_OUT3_4_MIXER, | ||
670 | WM8990_LI4O3_BIT, 1, 0), | ||
671 | SOC_DAPM_SINGLE("OUT3MIX Left Out PGA Switch", WM8990_OUT3_4_MIXER, | ||
672 | WM8990_LPGAO3_BIT, 1, 0), | ||
673 | }; | ||
674 | |||
675 | /* OUT4MIX */ | ||
676 | static const struct snd_kcontrol_new wm8990_dapm_out4mix_controls[] = { | ||
677 | SOC_DAPM_SINGLE("OUT4MIX Right Out PGA Switch", WM8990_OUT3_4_MIXER, | ||
678 | WM8990_RPGAO4_BIT, 1, 0), | ||
679 | SOC_DAPM_SINGLE("OUT4MIX RIN4/RXP Bypass Switch", WM8990_OUT3_4_MIXER, | ||
680 | WM8990_RI4O4_BIT, 1, 0), | ||
681 | }; | ||
682 | |||
683 | /* SPKMIX */ | ||
684 | static const struct snd_kcontrol_new wm8990_dapm_spkmix_controls[] = { | ||
685 | SOC_DAPM_SINGLE("SPKMIX LIN2 Bypass Switch", WM8990_SPEAKER_MIXER, | ||
686 | WM8990_LI2SPK_BIT, 1, 0), | ||
687 | SOC_DAPM_SINGLE("SPKMIX LADC Bypass Switch", WM8990_SPEAKER_MIXER, | ||
688 | WM8990_LB2SPK_BIT, 1, 0), | ||
689 | SOC_DAPM_SINGLE("SPKMIX Left Mixer PGA Switch", WM8990_SPEAKER_MIXER, | ||
690 | WM8990_LOPGASPK_BIT, 1, 0), | ||
691 | SOC_DAPM_SINGLE("SPKMIX Left DAC Switch", WM8990_SPEAKER_MIXER, | ||
692 | WM8990_LDSPK_BIT, 1, 0), | ||
693 | SOC_DAPM_SINGLE("SPKMIX Right DAC Switch", WM8990_SPEAKER_MIXER, | ||
694 | WM8990_RDSPK_BIT, 1, 0), | ||
695 | SOC_DAPM_SINGLE("SPKMIX Right Mixer PGA Switch", WM8990_SPEAKER_MIXER, | ||
696 | WM8990_ROPGASPK_BIT, 1, 0), | ||
697 | SOC_DAPM_SINGLE("SPKMIX RADC Bypass Switch", WM8990_SPEAKER_MIXER, | ||
698 | WM8990_RL12ROP_BIT, 1, 0), | ||
699 | SOC_DAPM_SINGLE("SPKMIX RIN2 Bypass Switch", WM8990_SPEAKER_MIXER, | ||
700 | WM8990_RI2SPK_BIT, 1, 0), | ||
701 | }; | ||
702 | |||
703 | static const struct snd_soc_dapm_widget wm8990_dapm_widgets[] = { | ||
704 | /* Input Side */ | ||
705 | /* Input Lines */ | ||
706 | SND_SOC_DAPM_INPUT("LIN1"), | ||
707 | SND_SOC_DAPM_INPUT("LIN2"), | ||
708 | SND_SOC_DAPM_INPUT("LIN3"), | ||
709 | SND_SOC_DAPM_INPUT("LIN4/RXN"), | ||
710 | SND_SOC_DAPM_INPUT("RIN3"), | ||
711 | SND_SOC_DAPM_INPUT("RIN4/RXP"), | ||
712 | SND_SOC_DAPM_INPUT("RIN1"), | ||
713 | SND_SOC_DAPM_INPUT("RIN2"), | ||
714 | SND_SOC_DAPM_INPUT("Internal ADC Source"), | ||
715 | |||
716 | /* DACs */ | ||
717 | SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8990_POWER_MANAGEMENT_2, | ||
718 | WM8990_ADCL_ENA_BIT, 0), | ||
719 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8990_POWER_MANAGEMENT_2, | ||
720 | WM8990_ADCR_ENA_BIT, 0), | ||
721 | |||
722 | /* Input PGAs */ | ||
723 | SND_SOC_DAPM_MIXER("LIN12 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_LIN12_ENA_BIT, | ||
724 | 0, &wm8990_dapm_lin12_pga_controls[0], | ||
725 | ARRAY_SIZE(wm8990_dapm_lin12_pga_controls)), | ||
726 | SND_SOC_DAPM_MIXER("LIN34 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_LIN34_ENA_BIT, | ||
727 | 0, &wm8990_dapm_lin34_pga_controls[0], | ||
728 | ARRAY_SIZE(wm8990_dapm_lin34_pga_controls)), | ||
729 | SND_SOC_DAPM_MIXER("RIN12 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_RIN12_ENA_BIT, | ||
730 | 0, &wm8990_dapm_rin12_pga_controls[0], | ||
731 | ARRAY_SIZE(wm8990_dapm_rin12_pga_controls)), | ||
732 | SND_SOC_DAPM_MIXER("RIN34 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_RIN34_ENA_BIT, | ||
733 | 0, &wm8990_dapm_rin34_pga_controls[0], | ||
734 | ARRAY_SIZE(wm8990_dapm_rin34_pga_controls)), | ||
735 | |||
736 | /* INMIXL */ | ||
737 | SND_SOC_DAPM_MIXER_E("INMIXL", WM8990_INTDRIVBITS, WM8990_INMIXL_PWR_BIT, 0, | ||
738 | &wm8990_dapm_inmixl_controls[0], | ||
739 | ARRAY_SIZE(wm8990_dapm_inmixl_controls), | ||
740 | inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | ||
741 | |||
742 | /* AINLMUX */ | ||
743 | SND_SOC_DAPM_MUX_E("AILNMUX", WM8990_INTDRIVBITS, WM8990_AINLMUX_PWR_BIT, 0, | ||
744 | &wm8990_dapm_ainlmux_controls, inmixer_event, | ||
745 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | ||
746 | |||
747 | /* INMIXR */ | ||
748 | SND_SOC_DAPM_MIXER_E("INMIXR", WM8990_INTDRIVBITS, WM8990_INMIXR_PWR_BIT, 0, | ||
749 | &wm8990_dapm_inmixr_controls[0], | ||
750 | ARRAY_SIZE(wm8990_dapm_inmixr_controls), | ||
751 | inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | ||
752 | |||
753 | /* AINRMUX */ | ||
754 | SND_SOC_DAPM_MUX_E("AIRNMUX", WM8990_INTDRIVBITS, WM8990_AINRMUX_PWR_BIT, 0, | ||
755 | &wm8990_dapm_ainrmux_controls, inmixer_event, | ||
756 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | ||
757 | |||
758 | /* Output Side */ | ||
759 | /* DACs */ | ||
760 | SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8990_POWER_MANAGEMENT_3, | ||
761 | WM8990_DACL_ENA_BIT, 0), | ||
762 | SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8990_POWER_MANAGEMENT_3, | ||
763 | WM8990_DACR_ENA_BIT, 0), | ||
764 | |||
765 | /* LOMIX */ | ||
766 | SND_SOC_DAPM_MIXER_E("LOMIX", WM8990_POWER_MANAGEMENT_3, WM8990_LOMIX_ENA_BIT, | ||
767 | 0, &wm8990_dapm_lomix_controls[0], | ||
768 | ARRAY_SIZE(wm8990_dapm_lomix_controls), | ||
769 | outmixer_event, SND_SOC_DAPM_PRE_REG), | ||
770 | |||
771 | /* LONMIX */ | ||
772 | SND_SOC_DAPM_MIXER("LONMIX", WM8990_POWER_MANAGEMENT_3, WM8990_LON_ENA_BIT, 0, | ||
773 | &wm8990_dapm_lonmix_controls[0], | ||
774 | ARRAY_SIZE(wm8990_dapm_lonmix_controls)), | ||
775 | |||
776 | /* LOPMIX */ | ||
777 | SND_SOC_DAPM_MIXER("LOPMIX", WM8990_POWER_MANAGEMENT_3, WM8990_LOP_ENA_BIT, 0, | ||
778 | &wm8990_dapm_lopmix_controls[0], | ||
779 | ARRAY_SIZE(wm8990_dapm_lopmix_controls)), | ||
780 | |||
781 | /* OUT3MIX */ | ||
782 | SND_SOC_DAPM_MIXER("OUT3MIX", WM8990_POWER_MANAGEMENT_1, WM8990_OUT3_ENA_BIT, 0, | ||
783 | &wm8990_dapm_out3mix_controls[0], | ||
784 | ARRAY_SIZE(wm8990_dapm_out3mix_controls)), | ||
785 | |||
786 | /* SPKMIX */ | ||
787 | SND_SOC_DAPM_MIXER_E("SPKMIX", WM8990_POWER_MANAGEMENT_1, WM8990_SPK_ENA_BIT, 0, | ||
788 | &wm8990_dapm_spkmix_controls[0], | ||
789 | ARRAY_SIZE(wm8990_dapm_spkmix_controls), outmixer_event, | ||
790 | SND_SOC_DAPM_PRE_REG), | ||
791 | |||
792 | /* OUT4MIX */ | ||
793 | SND_SOC_DAPM_MIXER("OUT4MIX", WM8990_POWER_MANAGEMENT_1, WM8990_OUT4_ENA_BIT, 0, | ||
794 | &wm8990_dapm_out4mix_controls[0], | ||
795 | ARRAY_SIZE(wm8990_dapm_out4mix_controls)), | ||
796 | |||
797 | /* ROPMIX */ | ||
798 | SND_SOC_DAPM_MIXER("ROPMIX", WM8990_POWER_MANAGEMENT_3, WM8990_ROP_ENA_BIT, 0, | ||
799 | &wm8990_dapm_ropmix_controls[0], | ||
800 | ARRAY_SIZE(wm8990_dapm_ropmix_controls)), | ||
801 | |||
802 | /* RONMIX */ | ||
803 | SND_SOC_DAPM_MIXER("RONMIX", WM8990_POWER_MANAGEMENT_3, WM8990_RON_ENA_BIT, 0, | ||
804 | &wm8990_dapm_ronmix_controls[0], | ||
805 | ARRAY_SIZE(wm8990_dapm_ronmix_controls)), | ||
806 | |||
807 | /* ROMIX */ | ||
808 | SND_SOC_DAPM_MIXER_E("ROMIX", WM8990_POWER_MANAGEMENT_3, WM8990_ROMIX_ENA_BIT, | ||
809 | 0, &wm8990_dapm_romix_controls[0], | ||
810 | ARRAY_SIZE(wm8990_dapm_romix_controls), | ||
811 | outmixer_event, SND_SOC_DAPM_PRE_REG), | ||
812 | |||
813 | /* LOUT PGA */ | ||
814 | SND_SOC_DAPM_PGA("LOUT PGA", WM8990_POWER_MANAGEMENT_1, WM8990_LOUT_ENA_BIT, 0, | ||
815 | NULL, 0), | ||
816 | |||
817 | /* ROUT PGA */ | ||
818 | SND_SOC_DAPM_PGA("ROUT PGA", WM8990_POWER_MANAGEMENT_1, WM8990_ROUT_ENA_BIT, 0, | ||
819 | NULL, 0), | ||
820 | |||
821 | /* LOPGA */ | ||
822 | SND_SOC_DAPM_PGA("LOPGA", WM8990_POWER_MANAGEMENT_3, WM8990_LOPGA_ENA_BIT, 0, | ||
823 | NULL, 0), | ||
824 | |||
825 | /* ROPGA */ | ||
826 | SND_SOC_DAPM_PGA("ROPGA", WM8990_POWER_MANAGEMENT_3, WM8990_ROPGA_ENA_BIT, 0, | ||
827 | NULL, 0), | ||
828 | |||
829 | /* MICBIAS */ | ||
830 | SND_SOC_DAPM_MICBIAS("MICBIAS", WM8990_POWER_MANAGEMENT_1, | ||
831 | WM8990_MICBIAS_ENA_BIT, 0), | ||
832 | |||
833 | SND_SOC_DAPM_OUTPUT("LON"), | ||
834 | SND_SOC_DAPM_OUTPUT("LOP"), | ||
835 | SND_SOC_DAPM_OUTPUT("OUT3"), | ||
836 | SND_SOC_DAPM_OUTPUT("LOUT"), | ||
837 | SND_SOC_DAPM_OUTPUT("SPKN"), | ||
838 | SND_SOC_DAPM_OUTPUT("SPKP"), | ||
839 | SND_SOC_DAPM_OUTPUT("ROUT"), | ||
840 | SND_SOC_DAPM_OUTPUT("OUT4"), | ||
841 | SND_SOC_DAPM_OUTPUT("ROP"), | ||
842 | SND_SOC_DAPM_OUTPUT("RON"), | ||
843 | |||
844 | SND_SOC_DAPM_OUTPUT("Internal DAC Sink"), | ||
845 | }; | ||
846 | |||
847 | static const struct snd_soc_dapm_route audio_map[] = { | ||
848 | /* Make DACs turn on when playing even if not mixed into any outputs */ | ||
849 | {"Internal DAC Sink", NULL, "Left DAC"}, | ||
850 | {"Internal DAC Sink", NULL, "Right DAC"}, | ||
851 | |||
852 | /* Make ADCs turn on when recording even if not mixed from any inputs */ | ||
853 | {"Left ADC", NULL, "Internal ADC Source"}, | ||
854 | {"Right ADC", NULL, "Internal ADC Source"}, | ||
855 | |||
856 | /* Input Side */ | ||
857 | /* LIN12 PGA */ | ||
858 | {"LIN12 PGA", "LIN1 Switch", "LIN1"}, | ||
859 | {"LIN12 PGA", "LIN2 Switch", "LIN2"}, | ||
860 | /* LIN34 PGA */ | ||
861 | {"LIN34 PGA", "LIN3 Switch", "LIN3"}, | ||
862 | {"LIN34 PGA", "LIN4 Switch", "LIN4"}, | ||
863 | /* INMIXL */ | ||
864 | {"INMIXL", "Record Left Volume", "LOMIX"}, | ||
865 | {"INMIXL", "LIN2 Volume", "LIN2"}, | ||
866 | {"INMIXL", "LINPGA12 Switch", "LIN12 PGA"}, | ||
867 | {"INMIXL", "LINPGA34 Switch", "LIN34 PGA"}, | ||
868 | /* AILNMUX */ | ||
869 | {"AILNMUX", "INMIXL Mix", "INMIXL"}, | ||
870 | {"AILNMUX", "DIFFINL Mix", "LIN12PGA"}, | ||
871 | {"AILNMUX", "DIFFINL Mix", "LIN34PGA"}, | ||
872 | {"AILNMUX", "RXVOICE Mix", "LIN4/RXN"}, | ||
873 | {"AILNMUX", "RXVOICE Mix", "RIN4/RXP"}, | ||
874 | /* ADC */ | ||
875 | {"Left ADC", NULL, "AILNMUX"}, | ||
876 | |||
877 | /* RIN12 PGA */ | ||
878 | {"RIN12 PGA", "RIN1 Switch", "RIN1"}, | ||
879 | {"RIN12 PGA", "RIN2 Switch", "RIN2"}, | ||
880 | /* RIN34 PGA */ | ||
881 | {"RIN34 PGA", "RIN3 Switch", "RIN3"}, | ||
882 | {"RIN34 PGA", "RIN4 Switch", "RIN4"}, | ||
883 | /* INMIXL */ | ||
884 | {"INMIXR", "Record Right Volume", "ROMIX"}, | ||
885 | {"INMIXR", "RIN2 Volume", "RIN2"}, | ||
886 | {"INMIXR", "RINPGA12 Switch", "RIN12 PGA"}, | ||
887 | {"INMIXR", "RINPGA34 Switch", "RIN34 PGA"}, | ||
888 | /* AIRNMUX */ | ||
889 | {"AIRNMUX", "INMIXR Mix", "INMIXR"}, | ||
890 | {"AIRNMUX", "DIFFINR Mix", "RIN12PGA"}, | ||
891 | {"AIRNMUX", "DIFFINR Mix", "RIN34PGA"}, | ||
892 | {"AIRNMUX", "RXVOICE Mix", "RIN4/RXN"}, | ||
893 | {"AIRNMUX", "RXVOICE Mix", "RIN4/RXP"}, | ||
894 | /* ADC */ | ||
895 | {"Right ADC", NULL, "AIRNMUX"}, | ||
896 | |||
897 | /* LOMIX */ | ||
898 | {"LOMIX", "LOMIX RIN3 Bypass Switch", "RIN3"}, | ||
899 | {"LOMIX", "LOMIX LIN3 Bypass Switch", "LIN3"}, | ||
900 | {"LOMIX", "LOMIX LIN12 PGA Bypass Switch", "LIN12 PGA"}, | ||
901 | {"LOMIX", "LOMIX RIN12 PGA Bypass Switch", "RIN12 PGA"}, | ||
902 | {"LOMIX", "LOMIX Right ADC Bypass Switch", "AINRMUX"}, | ||
903 | {"LOMIX", "LOMIX Left ADC Bypass Switch", "AINLMUX"}, | ||
904 | {"LOMIX", "LOMIX Left DAC Switch", "Left DAC"}, | ||
905 | |||
906 | /* ROMIX */ | ||
907 | {"ROMIX", "ROMIX RIN3 Bypass Switch", "RIN3"}, | ||
908 | {"ROMIX", "ROMIX LIN3 Bypass Switch", "LIN3"}, | ||
909 | {"ROMIX", "ROMIX LIN12 PGA Bypass Switch", "LIN12 PGA"}, | ||
910 | {"ROMIX", "ROMIX RIN12 PGA Bypass Switch", "RIN12 PGA"}, | ||
911 | {"ROMIX", "ROMIX Right ADC Bypass Switch", "AINRMUX"}, | ||
912 | {"ROMIX", "ROMIX Left ADC Bypass Switch", "AINLMUX"}, | ||
913 | {"ROMIX", "ROMIX Right DAC Switch", "Right DAC"}, | ||
914 | |||
915 | /* SPKMIX */ | ||
916 | {"SPKMIX", "SPKMIX LIN2 Bypass Switch", "LIN2"}, | ||
917 | {"SPKMIX", "SPKMIX RIN2 Bypass Switch", "RIN2"}, | ||
918 | {"SPKMIX", "SPKMIX LADC Bypass Switch", "AINLMUX"}, | ||
919 | {"SPKMIX", "SPKMIX RADC Bypass Switch", "AINRMUX"}, | ||
920 | {"SPKMIX", "SPKMIX Left Mixer PGA Switch", "LOPGA"}, | ||
921 | {"SPKMIX", "SPKMIX Right Mixer PGA Switch", "ROPGA"}, | ||
922 | {"SPKMIX", "SPKMIX Right DAC Switch", "Right DAC"}, | ||
923 | {"SPKMIX", "SPKMIX Left DAC Switch", "Right DAC"}, | ||
924 | |||
925 | /* LONMIX */ | ||
926 | {"LONMIX", "LONMIX Left Mixer PGA Switch", "LOPGA"}, | ||
927 | {"LONMIX", "LONMIX Right Mixer PGA Switch", "ROPGA"}, | ||
928 | {"LONMIX", "LONMIX Inverted LOP Switch", "LOPMIX"}, | ||
929 | |||
930 | /* LOPMIX */ | ||
931 | {"LOPMIX", "LOPMIX Right Mic Bypass Switch", "RIN12 PGA"}, | ||
932 | {"LOPMIX", "LOPMIX Left Mic Bypass Switch", "LIN12 PGA"}, | ||
933 | {"LOPMIX", "LOPMIX Left Mixer PGA Switch", "LOPGA"}, | ||
934 | |||
935 | /* OUT3MIX */ | ||
936 | {"OUT3MIX", "OUT3MIX LIN4/RXP Bypass Switch", "LIN4/RXP"}, | ||
937 | {"OUT3MIX", "OUT3MIX Left Out PGA Switch", "LOPGA"}, | ||
938 | |||
939 | /* OUT4MIX */ | ||
940 | {"OUT4MIX", "OUT4MIX Right Out PGA Switch", "ROPGA"}, | ||
941 | {"OUT4MIX", "OUT4MIX RIN4/RXP Bypass Switch", "RIN4/RXP"}, | ||
942 | |||
943 | /* RONMIX */ | ||
944 | {"RONMIX", "RONMIX Right Mixer PGA Switch", "ROPGA"}, | ||
945 | {"RONMIX", "RONMIX Left Mixer PGA Switch", "LOPGA"}, | ||
946 | {"RONMIX", "RONMIX Inverted ROP Switch", "ROPMIX"}, | ||
947 | |||
948 | /* ROPMIX */ | ||
949 | {"ROPMIX", "ROPMIX Left Mic Bypass Switch", "LIN12 PGA"}, | ||
950 | {"ROPMIX", "ROPMIX Right Mic Bypass Switch", "RIN12 PGA"}, | ||
951 | {"ROPMIX", "ROPMIX Right Mixer PGA Switch", "ROPGA"}, | ||
952 | |||
953 | /* Out Mixer PGAs */ | ||
954 | {"LOPGA", NULL, "LOMIX"}, | ||
955 | {"ROPGA", NULL, "ROMIX"}, | ||
956 | |||
957 | {"LOUT PGA", NULL, "LOMIX"}, | ||
958 | {"ROUT PGA", NULL, "ROMIX"}, | ||
959 | |||
960 | /* Output Pins */ | ||
961 | {"LON", NULL, "LONMIX"}, | ||
962 | {"LOP", NULL, "LOPMIX"}, | ||
963 | {"OUT", NULL, "OUT3MIX"}, | ||
964 | {"LOUT", NULL, "LOUT PGA"}, | ||
965 | {"SPKN", NULL, "SPKMIX"}, | ||
966 | {"ROUT", NULL, "ROUT PGA"}, | ||
967 | {"OUT4", NULL, "OUT4MIX"}, | ||
968 | {"ROP", NULL, "ROPMIX"}, | ||
969 | {"RON", NULL, "RONMIX"}, | ||
970 | }; | ||
971 | |||
972 | static int wm8990_add_widgets(struct snd_soc_codec *codec) | ||
973 | { | ||
974 | snd_soc_dapm_new_controls(codec, wm8990_dapm_widgets, | ||
975 | ARRAY_SIZE(wm8990_dapm_widgets)); | ||
976 | |||
977 | /* set up the WM8990 audio map */ | ||
978 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
979 | |||
980 | snd_soc_dapm_new_widgets(codec); | ||
981 | return 0; | ||
982 | } | ||
983 | |||
984 | /* PLL divisors */ | ||
985 | struct _pll_div { | ||
986 | u32 div2; | ||
987 | u32 n; | ||
988 | u32 k; | ||
989 | }; | ||
990 | |||
991 | /* The size in bits of the pll divide multiplied by 10 | ||
992 | * to allow rounding later */ | ||
993 | #define FIXED_PLL_SIZE ((1 << 16) * 10) | ||
994 | |||
995 | static void pll_factors(struct _pll_div *pll_div, unsigned int target, | ||
996 | unsigned int source) | ||
997 | { | ||
998 | u64 Kpart; | ||
999 | unsigned int K, Ndiv, Nmod; | ||
1000 | |||
1001 | |||
1002 | Ndiv = target / source; | ||
1003 | if (Ndiv < 6) { | ||
1004 | source >>= 1; | ||
1005 | pll_div->div2 = 1; | ||
1006 | Ndiv = target / source; | ||
1007 | } else | ||
1008 | pll_div->div2 = 0; | ||
1009 | |||
1010 | if ((Ndiv < 6) || (Ndiv > 12)) | ||
1011 | printk(KERN_WARNING | ||
1012 | "WM8990 N value outwith recommended range! N = %d\n", Ndiv); | ||
1013 | |||
1014 | pll_div->n = Ndiv; | ||
1015 | Nmod = target % source; | ||
1016 | Kpart = FIXED_PLL_SIZE * (long long)Nmod; | ||
1017 | |||
1018 | do_div(Kpart, source); | ||
1019 | |||
1020 | K = Kpart & 0xFFFFFFFF; | ||
1021 | |||
1022 | /* Check if we need to round */ | ||
1023 | if ((K % 10) >= 5) | ||
1024 | K += 5; | ||
1025 | |||
1026 | /* Move down to proper range now rounding is done */ | ||
1027 | K /= 10; | ||
1028 | |||
1029 | pll_div->k = K; | ||
1030 | } | ||
1031 | |||
1032 | static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai, | ||
1033 | int pll_id, unsigned int freq_in, unsigned int freq_out) | ||
1034 | { | ||
1035 | u16 reg; | ||
1036 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1037 | struct _pll_div pll_div; | ||
1038 | |||
1039 | if (freq_in && freq_out) { | ||
1040 | pll_factors(&pll_div, freq_out * 4, freq_in); | ||
1041 | |||
1042 | /* Turn on PLL */ | ||
1043 | reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2); | ||
1044 | reg |= WM8990_PLL_ENA; | ||
1045 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg); | ||
1046 | |||
1047 | /* sysclk comes from PLL */ | ||
1048 | reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2); | ||
1049 | wm8990_write(codec, WM8990_CLOCKING_2, reg | WM8990_SYSCLK_SRC); | ||
1050 | |||
1051 | /* set up N , fractional mode and pre-divisor if neccessary */ | ||
1052 | wm8990_write(codec, WM8990_PLL1, pll_div.n | WM8990_SDM | | ||
1053 | (pll_div.div2?WM8990_PRESCALE:0)); | ||
1054 | wm8990_write(codec, WM8990_PLL2, (u8)(pll_div.k>>8)); | ||
1055 | wm8990_write(codec, WM8990_PLL3, (u8)(pll_div.k & 0xFF)); | ||
1056 | } else { | ||
1057 | /* Turn on PLL */ | ||
1058 | reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2); | ||
1059 | reg &= ~WM8990_PLL_ENA; | ||
1060 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg); | ||
1061 | } | ||
1062 | return 0; | ||
1063 | } | ||
1064 | |||
1065 | /* | ||
1066 | * Clock after PLL and dividers | ||
1067 | */ | ||
1068 | static int wm8990_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
1069 | int clk_id, unsigned int freq, int dir) | ||
1070 | { | ||
1071 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1072 | struct wm8990_priv *wm8990 = codec->private_data; | ||
1073 | |||
1074 | wm8990->sysclk = freq; | ||
1075 | return 0; | ||
1076 | } | ||
1077 | |||
1078 | /* | ||
1079 | * Set's ADC and Voice DAC format. | ||
1080 | */ | ||
1081 | static int wm8990_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
1082 | unsigned int fmt) | ||
1083 | { | ||
1084 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1085 | u16 audio1, audio3; | ||
1086 | |||
1087 | audio1 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_1); | ||
1088 | audio3 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_3); | ||
1089 | |||
1090 | /* set master/slave audio interface */ | ||
1091 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
1092 | case SND_SOC_DAIFMT_CBS_CFS: | ||
1093 | audio3 &= ~WM8990_AIF_MSTR1; | ||
1094 | break; | ||
1095 | case SND_SOC_DAIFMT_CBM_CFM: | ||
1096 | audio3 |= WM8990_AIF_MSTR1; | ||
1097 | break; | ||
1098 | default: | ||
1099 | return -EINVAL; | ||
1100 | } | ||
1101 | |||
1102 | audio1 &= ~WM8990_AIF_FMT_MASK; | ||
1103 | |||
1104 | /* interface format */ | ||
1105 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
1106 | case SND_SOC_DAIFMT_I2S: | ||
1107 | audio1 |= WM8990_AIF_TMF_I2S; | ||
1108 | audio1 &= ~WM8990_AIF_LRCLK_INV; | ||
1109 | break; | ||
1110 | case SND_SOC_DAIFMT_RIGHT_J: | ||
1111 | audio1 |= WM8990_AIF_TMF_RIGHTJ; | ||
1112 | audio1 &= ~WM8990_AIF_LRCLK_INV; | ||
1113 | break; | ||
1114 | case SND_SOC_DAIFMT_LEFT_J: | ||
1115 | audio1 |= WM8990_AIF_TMF_LEFTJ; | ||
1116 | audio1 &= ~WM8990_AIF_LRCLK_INV; | ||
1117 | break; | ||
1118 | case SND_SOC_DAIFMT_DSP_A: | ||
1119 | audio1 |= WM8990_AIF_TMF_DSP; | ||
1120 | audio1 &= ~WM8990_AIF_LRCLK_INV; | ||
1121 | break; | ||
1122 | case SND_SOC_DAIFMT_DSP_B: | ||
1123 | audio1 |= WM8990_AIF_TMF_DSP | WM8990_AIF_LRCLK_INV; | ||
1124 | break; | ||
1125 | default: | ||
1126 | return -EINVAL; | ||
1127 | } | ||
1128 | |||
1129 | wm8990_write(codec, WM8990_AUDIO_INTERFACE_1, audio1); | ||
1130 | wm8990_write(codec, WM8990_AUDIO_INTERFACE_3, audio3); | ||
1131 | return 0; | ||
1132 | } | ||
1133 | |||
1134 | static int wm8990_set_dai_clkdiv(struct snd_soc_dai *codec_dai, | ||
1135 | int div_id, int div) | ||
1136 | { | ||
1137 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1138 | u16 reg; | ||
1139 | |||
1140 | switch (div_id) { | ||
1141 | case WM8990_MCLK_DIV: | ||
1142 | reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) & | ||
1143 | ~WM8990_MCLK_DIV_MASK; | ||
1144 | wm8990_write(codec, WM8990_CLOCKING_2, reg | div); | ||
1145 | break; | ||
1146 | case WM8990_DACCLK_DIV: | ||
1147 | reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) & | ||
1148 | ~WM8990_DAC_CLKDIV_MASK; | ||
1149 | wm8990_write(codec, WM8990_CLOCKING_2, reg | div); | ||
1150 | break; | ||
1151 | case WM8990_ADCCLK_DIV: | ||
1152 | reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) & | ||
1153 | ~WM8990_ADC_CLKDIV_MASK; | ||
1154 | wm8990_write(codec, WM8990_CLOCKING_2, reg | div); | ||
1155 | break; | ||
1156 | case WM8990_BCLK_DIV: | ||
1157 | reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_1) & | ||
1158 | ~WM8990_BCLK_DIV_MASK; | ||
1159 | wm8990_write(codec, WM8990_CLOCKING_1, reg | div); | ||
1160 | break; | ||
1161 | default: | ||
1162 | return -EINVAL; | ||
1163 | } | ||
1164 | |||
1165 | return 0; | ||
1166 | } | ||
1167 | |||
1168 | /* | ||
1169 | * Set PCM DAI bit size and sample rate. | ||
1170 | */ | ||
1171 | static int wm8990_hw_params(struct snd_pcm_substream *substream, | ||
1172 | struct snd_pcm_hw_params *params) | ||
1173 | { | ||
1174 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
1175 | struct snd_soc_device *socdev = rtd->socdev; | ||
1176 | struct snd_soc_codec *codec = socdev->codec; | ||
1177 | u16 audio1 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_1); | ||
1178 | |||
1179 | audio1 &= ~WM8990_AIF_WL_MASK; | ||
1180 | /* bit size */ | ||
1181 | switch (params_format(params)) { | ||
1182 | case SNDRV_PCM_FORMAT_S16_LE: | ||
1183 | break; | ||
1184 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
1185 | audio1 |= WM8990_AIF_WL_20BITS; | ||
1186 | break; | ||
1187 | case SNDRV_PCM_FORMAT_S24_LE: | ||
1188 | audio1 |= WM8990_AIF_WL_24BITS; | ||
1189 | break; | ||
1190 | case SNDRV_PCM_FORMAT_S32_LE: | ||
1191 | audio1 |= WM8990_AIF_WL_32BITS; | ||
1192 | break; | ||
1193 | } | ||
1194 | |||
1195 | wm8990_write(codec, WM8990_AUDIO_INTERFACE_1, audio1); | ||
1196 | return 0; | ||
1197 | } | ||
1198 | |||
1199 | static int wm8990_mute(struct snd_soc_dai *dai, int mute) | ||
1200 | { | ||
1201 | struct snd_soc_codec *codec = dai->codec; | ||
1202 | u16 val; | ||
1203 | |||
1204 | val = wm8990_read_reg_cache(codec, WM8990_DAC_CTRL) & ~WM8990_DAC_MUTE; | ||
1205 | |||
1206 | if (mute) | ||
1207 | wm8990_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE); | ||
1208 | else | ||
1209 | wm8990_write(codec, WM8990_DAC_CTRL, val); | ||
1210 | |||
1211 | return 0; | ||
1212 | } | ||
1213 | |||
1214 | static int wm8990_set_bias_level(struct snd_soc_codec *codec, | ||
1215 | enum snd_soc_bias_level level) | ||
1216 | { | ||
1217 | u16 val; | ||
1218 | |||
1219 | switch (level) { | ||
1220 | case SND_SOC_BIAS_ON: | ||
1221 | break; | ||
1222 | case SND_SOC_BIAS_PREPARE: | ||
1223 | break; | ||
1224 | case SND_SOC_BIAS_STANDBY: | ||
1225 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | ||
1226 | /* Enable all output discharge bits */ | ||
1227 | wm8990_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE | | ||
1228 | WM8990_DIS_RLINE | WM8990_DIS_OUT3 | | ||
1229 | WM8990_DIS_OUT4 | WM8990_DIS_LOUT | | ||
1230 | WM8990_DIS_ROUT); | ||
1231 | |||
1232 | /* Enable POBCTRL, SOFT_ST, VMIDTOG and BUFDCOPEN */ | ||
1233 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | | ||
1234 | WM8990_BUFDCOPEN | WM8990_POBCTRL | | ||
1235 | WM8990_VMIDTOG); | ||
1236 | |||
1237 | /* Delay to allow output caps to discharge */ | ||
1238 | msleep(msecs_to_jiffies(300)); | ||
1239 | |||
1240 | /* Disable VMIDTOG */ | ||
1241 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | | ||
1242 | WM8990_BUFDCOPEN | WM8990_POBCTRL); | ||
1243 | |||
1244 | /* disable all output discharge bits */ | ||
1245 | wm8990_write(codec, WM8990_ANTIPOP1, 0); | ||
1246 | |||
1247 | /* Enable outputs */ | ||
1248 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1b00); | ||
1249 | |||
1250 | msleep(msecs_to_jiffies(50)); | ||
1251 | |||
1252 | /* Enable VMID at 2x50k */ | ||
1253 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f02); | ||
1254 | |||
1255 | msleep(msecs_to_jiffies(100)); | ||
1256 | |||
1257 | /* Enable VREF */ | ||
1258 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03); | ||
1259 | |||
1260 | msleep(msecs_to_jiffies(600)); | ||
1261 | |||
1262 | /* Enable BUFIOEN */ | ||
1263 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | | ||
1264 | WM8990_BUFDCOPEN | WM8990_POBCTRL | | ||
1265 | WM8990_BUFIOEN); | ||
1266 | |||
1267 | /* Disable outputs */ | ||
1268 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x3); | ||
1269 | |||
1270 | /* disable POBCTRL, SOFT_ST and BUFDCOPEN */ | ||
1271 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_BUFIOEN); | ||
1272 | } else { | ||
1273 | /* ON -> standby */ | ||
1274 | |||
1275 | } | ||
1276 | break; | ||
1277 | |||
1278 | case SND_SOC_BIAS_OFF: | ||
1279 | /* Enable POBCTRL and SOFT_ST */ | ||
1280 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | | ||
1281 | WM8990_POBCTRL | WM8990_BUFIOEN); | ||
1282 | |||
1283 | /* Enable POBCTRL, SOFT_ST and BUFDCOPEN */ | ||
1284 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | | ||
1285 | WM8990_BUFDCOPEN | WM8990_POBCTRL | | ||
1286 | WM8990_BUFIOEN); | ||
1287 | |||
1288 | /* mute DAC */ | ||
1289 | val = wm8990_read_reg_cache(codec, WM8990_DAC_CTRL); | ||
1290 | wm8990_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE); | ||
1291 | |||
1292 | /* Enable any disabled outputs */ | ||
1293 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03); | ||
1294 | |||
1295 | /* Disable VMID */ | ||
1296 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f01); | ||
1297 | |||
1298 | msleep(msecs_to_jiffies(300)); | ||
1299 | |||
1300 | /* Enable all output discharge bits */ | ||
1301 | wm8990_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE | | ||
1302 | WM8990_DIS_RLINE | WM8990_DIS_OUT3 | | ||
1303 | WM8990_DIS_OUT4 | WM8990_DIS_LOUT | | ||
1304 | WM8990_DIS_ROUT); | ||
1305 | |||
1306 | /* Disable VREF */ | ||
1307 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x0); | ||
1308 | |||
1309 | /* disable POBCTRL, SOFT_ST and BUFDCOPEN */ | ||
1310 | wm8990_write(codec, WM8990_ANTIPOP2, 0x0); | ||
1311 | break; | ||
1312 | } | ||
1313 | |||
1314 | codec->bias_level = level; | ||
1315 | return 0; | ||
1316 | } | ||
1317 | |||
1318 | #define WM8990_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
1319 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ | ||
1320 | SNDRV_PCM_RATE_48000) | ||
1321 | |||
1322 | #define WM8990_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
1323 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | ||
1324 | |||
1325 | /* | ||
1326 | * The WM8990 supports 2 different and mutually exclusive DAI | ||
1327 | * configurations. | ||
1328 | * | ||
1329 | * 1. ADC/DAC on Primary Interface | ||
1330 | * 2. ADC on Primary Interface/DAC on secondary | ||
1331 | */ | ||
1332 | struct snd_soc_dai wm8990_dai = { | ||
1333 | /* ADC/DAC on primary */ | ||
1334 | .name = "WM8990 ADC/DAC Primary", | ||
1335 | .id = 1, | ||
1336 | .playback = { | ||
1337 | .stream_name = "Playback", | ||
1338 | .channels_min = 1, | ||
1339 | .channels_max = 2, | ||
1340 | .rates = WM8990_RATES, | ||
1341 | .formats = WM8990_FORMATS,}, | ||
1342 | .capture = { | ||
1343 | .stream_name = "Capture", | ||
1344 | .channels_min = 1, | ||
1345 | .channels_max = 2, | ||
1346 | .rates = WM8990_RATES, | ||
1347 | .formats = WM8990_FORMATS,}, | ||
1348 | .ops = { | ||
1349 | .hw_params = wm8990_hw_params,}, | ||
1350 | .dai_ops = { | ||
1351 | .digital_mute = wm8990_mute, | ||
1352 | .set_fmt = wm8990_set_dai_fmt, | ||
1353 | .set_clkdiv = wm8990_set_dai_clkdiv, | ||
1354 | .set_pll = wm8990_set_dai_pll, | ||
1355 | .set_sysclk = wm8990_set_dai_sysclk, | ||
1356 | }, | ||
1357 | }; | ||
1358 | EXPORT_SYMBOL_GPL(wm8990_dai); | ||
1359 | |||
1360 | static int wm8990_suspend(struct platform_device *pdev, pm_message_t state) | ||
1361 | { | ||
1362 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1363 | struct snd_soc_codec *codec = socdev->codec; | ||
1364 | |||
1365 | /* we only need to suspend if we are a valid card */ | ||
1366 | if (!codec->card) | ||
1367 | return 0; | ||
1368 | |||
1369 | wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1370 | return 0; | ||
1371 | } | ||
1372 | |||
1373 | static int wm8990_resume(struct platform_device *pdev) | ||
1374 | { | ||
1375 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1376 | struct snd_soc_codec *codec = socdev->codec; | ||
1377 | int i; | ||
1378 | u8 data[2]; | ||
1379 | u16 *cache = codec->reg_cache; | ||
1380 | |||
1381 | /* we only need to resume if we are a valid card */ | ||
1382 | if (!codec->card) | ||
1383 | return 0; | ||
1384 | |||
1385 | /* Sync reg_cache with the hardware */ | ||
1386 | for (i = 0; i < ARRAY_SIZE(wm8990_reg); i++) { | ||
1387 | if (i + 1 == WM8990_RESET) | ||
1388 | continue; | ||
1389 | data[0] = ((i + 1) << 1) | ((cache[i] >> 8) & 0x0001); | ||
1390 | data[1] = cache[i] & 0x00ff; | ||
1391 | codec->hw_write(codec->control_data, data, 2); | ||
1392 | } | ||
1393 | |||
1394 | wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1395 | return 0; | ||
1396 | } | ||
1397 | |||
1398 | /* | ||
1399 | * initialise the WM8990 driver | ||
1400 | * register the mixer and dsp interfaces with the kernel | ||
1401 | */ | ||
1402 | static int wm8990_init(struct snd_soc_device *socdev) | ||
1403 | { | ||
1404 | struct snd_soc_codec *codec = socdev->codec; | ||
1405 | u16 reg; | ||
1406 | int ret = 0; | ||
1407 | |||
1408 | codec->name = "WM8990"; | ||
1409 | codec->owner = THIS_MODULE; | ||
1410 | codec->read = wm8990_read_reg_cache; | ||
1411 | codec->write = wm8990_write; | ||
1412 | codec->set_bias_level = wm8990_set_bias_level; | ||
1413 | codec->dai = &wm8990_dai; | ||
1414 | codec->num_dai = 2; | ||
1415 | codec->reg_cache_size = ARRAY_SIZE(wm8990_reg); | ||
1416 | codec->reg_cache = kmemdup(wm8990_reg, sizeof(wm8990_reg), GFP_KERNEL); | ||
1417 | |||
1418 | if (codec->reg_cache == NULL) | ||
1419 | return -ENOMEM; | ||
1420 | |||
1421 | wm8990_reset(codec); | ||
1422 | |||
1423 | /* register pcms */ | ||
1424 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
1425 | if (ret < 0) { | ||
1426 | printk(KERN_ERR "wm8990: failed to create pcms\n"); | ||
1427 | goto pcm_err; | ||
1428 | } | ||
1429 | |||
1430 | /* charge output caps */ | ||
1431 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
1432 | wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1433 | |||
1434 | reg = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_4); | ||
1435 | wm8990_write(codec, WM8990_AUDIO_INTERFACE_4, reg | WM8990_ALRCGPIO1); | ||
1436 | |||
1437 | reg = wm8990_read_reg_cache(codec, WM8990_GPIO1_GPIO2) & | ||
1438 | ~WM8990_GPIO1_SEL_MASK; | ||
1439 | wm8990_write(codec, WM8990_GPIO1_GPIO2, reg | 1); | ||
1440 | |||
1441 | reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2); | ||
1442 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg | WM8990_OPCLK_ENA); | ||
1443 | |||
1444 | wm8990_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); | ||
1445 | wm8990_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); | ||
1446 | |||
1447 | wm8990_add_controls(codec); | ||
1448 | wm8990_add_widgets(codec); | ||
1449 | ret = snd_soc_register_card(socdev); | ||
1450 | if (ret < 0) { | ||
1451 | printk(KERN_ERR "wm8990: failed to register card\n"); | ||
1452 | goto card_err; | ||
1453 | } | ||
1454 | return ret; | ||
1455 | |||
1456 | card_err: | ||
1457 | snd_soc_free_pcms(socdev); | ||
1458 | snd_soc_dapm_free(socdev); | ||
1459 | pcm_err: | ||
1460 | kfree(codec->reg_cache); | ||
1461 | return ret; | ||
1462 | } | ||
1463 | |||
1464 | /* If the i2c layer weren't so broken, we could pass this kind of data | ||
1465 | around */ | ||
1466 | static struct snd_soc_device *wm8990_socdev; | ||
1467 | |||
1468 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1469 | |||
1470 | /* | ||
1471 | * WM891 2 wire address is determined by GPIO5 | ||
1472 | * state during powerup. | ||
1473 | * low = 0x34 | ||
1474 | * high = 0x36 | ||
1475 | */ | ||
1476 | static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; | ||
1477 | |||
1478 | /* Magic definition of all other variables and things */ | ||
1479 | I2C_CLIENT_INSMOD; | ||
1480 | |||
1481 | static struct i2c_driver wm8990_i2c_driver; | ||
1482 | static struct i2c_client client_template; | ||
1483 | |||
1484 | static int wm8990_codec_probe(struct i2c_adapter *adap, int addr, int kind) | ||
1485 | { | ||
1486 | struct snd_soc_device *socdev = wm8990_socdev; | ||
1487 | struct wm8990_setup_data *setup = socdev->codec_data; | ||
1488 | struct snd_soc_codec *codec = socdev->codec; | ||
1489 | struct i2c_client *i2c; | ||
1490 | int ret; | ||
1491 | |||
1492 | if (addr != setup->i2c_address) | ||
1493 | return -ENODEV; | ||
1494 | |||
1495 | client_template.adapter = adap; | ||
1496 | client_template.addr = addr; | ||
1497 | |||
1498 | i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); | ||
1499 | if (i2c == NULL) { | ||
1500 | kfree(codec); | ||
1501 | return -ENOMEM; | ||
1502 | } | ||
1503 | i2c_set_clientdata(i2c, codec); | ||
1504 | codec->control_data = i2c; | ||
1505 | |||
1506 | ret = i2c_attach_client(i2c); | ||
1507 | if (ret < 0) { | ||
1508 | pr_err("failed to attach codec at addr %x\n", addr); | ||
1509 | goto err; | ||
1510 | } | ||
1511 | |||
1512 | ret = wm8990_init(socdev); | ||
1513 | if (ret < 0) { | ||
1514 | pr_err("failed to initialise WM8990\n"); | ||
1515 | goto err; | ||
1516 | } | ||
1517 | return ret; | ||
1518 | |||
1519 | err: | ||
1520 | kfree(codec); | ||
1521 | kfree(i2c); | ||
1522 | return ret; | ||
1523 | } | ||
1524 | |||
1525 | static int wm8990_i2c_detach(struct i2c_client *client) | ||
1526 | { | ||
1527 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
1528 | i2c_detach_client(client); | ||
1529 | kfree(codec->reg_cache); | ||
1530 | kfree(client); | ||
1531 | return 0; | ||
1532 | } | ||
1533 | |||
1534 | static int wm8990_i2c_attach(struct i2c_adapter *adap) | ||
1535 | { | ||
1536 | return i2c_probe(adap, &addr_data, wm8990_codec_probe); | ||
1537 | } | ||
1538 | |||
1539 | static struct i2c_driver wm8990_i2c_driver = { | ||
1540 | .driver = { | ||
1541 | .name = "WM8990 I2C Codec", | ||
1542 | .owner = THIS_MODULE, | ||
1543 | }, | ||
1544 | .attach_adapter = wm8990_i2c_attach, | ||
1545 | .detach_client = wm8990_i2c_detach, | ||
1546 | .command = NULL, | ||
1547 | }; | ||
1548 | |||
1549 | static struct i2c_client client_template = { | ||
1550 | .name = "WM8990", | ||
1551 | .driver = &wm8990_i2c_driver, | ||
1552 | }; | ||
1553 | #endif | ||
1554 | |||
1555 | static int wm8990_probe(struct platform_device *pdev) | ||
1556 | { | ||
1557 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1558 | struct wm8990_setup_data *setup; | ||
1559 | struct snd_soc_codec *codec; | ||
1560 | struct wm8990_priv *wm8990; | ||
1561 | int ret = 0; | ||
1562 | |||
1563 | pr_info("WM8990 Audio Codec %s\n", WM8990_VERSION); | ||
1564 | |||
1565 | setup = socdev->codec_data; | ||
1566 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
1567 | if (codec == NULL) | ||
1568 | return -ENOMEM; | ||
1569 | |||
1570 | wm8990 = kzalloc(sizeof(struct wm8990_priv), GFP_KERNEL); | ||
1571 | if (wm8990 == NULL) { | ||
1572 | kfree(codec); | ||
1573 | return -ENOMEM; | ||
1574 | } | ||
1575 | |||
1576 | codec->private_data = wm8990; | ||
1577 | socdev->codec = codec; | ||
1578 | mutex_init(&codec->mutex); | ||
1579 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
1580 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
1581 | wm8990_socdev = socdev; | ||
1582 | |||
1583 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1584 | if (setup->i2c_address) { | ||
1585 | normal_i2c[0] = setup->i2c_address; | ||
1586 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
1587 | ret = i2c_add_driver(&wm8990_i2c_driver); | ||
1588 | if (ret != 0) | ||
1589 | printk(KERN_ERR "can't add i2c driver"); | ||
1590 | } | ||
1591 | #else | ||
1592 | /* Add other interfaces here */ | ||
1593 | #endif | ||
1594 | return ret; | ||
1595 | } | ||
1596 | |||
1597 | /* power down chip */ | ||
1598 | static int wm8990_remove(struct platform_device *pdev) | ||
1599 | { | ||
1600 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1601 | struct snd_soc_codec *codec = socdev->codec; | ||
1602 | |||
1603 | if (codec->control_data) | ||
1604 | wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1605 | snd_soc_free_pcms(socdev); | ||
1606 | snd_soc_dapm_free(socdev); | ||
1607 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1608 | i2c_del_driver(&wm8990_i2c_driver); | ||
1609 | #endif | ||
1610 | kfree(codec->private_data); | ||
1611 | kfree(codec); | ||
1612 | |||
1613 | return 0; | ||
1614 | } | ||
1615 | |||
1616 | struct snd_soc_codec_device soc_codec_dev_wm8990 = { | ||
1617 | .probe = wm8990_probe, | ||
1618 | .remove = wm8990_remove, | ||
1619 | .suspend = wm8990_suspend, | ||
1620 | .resume = wm8990_resume, | ||
1621 | }; | ||
1622 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8990); | ||
1623 | |||
1624 | MODULE_DESCRIPTION("ASoC WM8990 driver"); | ||
1625 | MODULE_AUTHOR("Liam Girdwood"); | ||
1626 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8990.h b/sound/soc/codecs/wm8990.h new file mode 100644 index 000000000000..6bea57485283 --- /dev/null +++ b/sound/soc/codecs/wm8990.h | |||
@@ -0,0 +1,832 @@ | |||
1 | /* | ||
2 | * wm8990.h -- audio driver for WM8990 | ||
3 | * | ||
4 | * Copyright 2007 Wolfson Microelectronics PLC. | ||
5 | * Author: Graeme Gregory | ||
6 | * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com | ||
7 | * | ||
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 | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #ifndef __WM8990REGISTERDEFS_H__ | ||
16 | #define __WM8990REGISTERDEFS_H__ | ||
17 | |||
18 | /* | ||
19 | * Register values. | ||
20 | */ | ||
21 | #define WM8990_RESET 0x00 | ||
22 | #define WM8990_POWER_MANAGEMENT_1 0x01 | ||
23 | #define WM8990_POWER_MANAGEMENT_2 0x02 | ||
24 | #define WM8990_POWER_MANAGEMENT_3 0x03 | ||
25 | #define WM8990_AUDIO_INTERFACE_1 0x04 | ||
26 | #define WM8990_AUDIO_INTERFACE_2 0x05 | ||
27 | #define WM8990_CLOCKING_1 0x06 | ||
28 | #define WM8990_CLOCKING_2 0x07 | ||
29 | #define WM8990_AUDIO_INTERFACE_3 0x08 | ||
30 | #define WM8990_AUDIO_INTERFACE_4 0x09 | ||
31 | #define WM8990_DAC_CTRL 0x0A | ||
32 | #define WM8990_LEFT_DAC_DIGITAL_VOLUME 0x0B | ||
33 | #define WM8990_RIGHT_DAC_DIGITAL_VOLUME 0x0C | ||
34 | #define WM8990_DIGITAL_SIDE_TONE 0x0D | ||
35 | #define WM8990_ADC_CTRL 0x0E | ||
36 | #define WM8990_LEFT_ADC_DIGITAL_VOLUME 0x0F | ||
37 | #define WM8990_RIGHT_ADC_DIGITAL_VOLUME 0x10 | ||
38 | #define WM8990_GPIO_CTRL_1 0x12 | ||
39 | #define WM8990_GPIO1_GPIO2 0x13 | ||
40 | #define WM8990_GPIO3_GPIO4 0x14 | ||
41 | #define WM8990_GPIO5_GPIO6 0x15 | ||
42 | #define WM8990_GPIOCTRL_2 0x16 | ||
43 | #define WM8990_GPIO_POL 0x17 | ||
44 | #define WM8990_LEFT_LINE_INPUT_1_2_VOLUME 0x18 | ||
45 | #define WM8990_LEFT_LINE_INPUT_3_4_VOLUME 0x19 | ||
46 | #define WM8990_RIGHT_LINE_INPUT_1_2_VOLUME 0x1A | ||
47 | #define WM8990_RIGHT_LINE_INPUT_3_4_VOLUME 0x1B | ||
48 | #define WM8990_LEFT_OUTPUT_VOLUME 0x1C | ||
49 | #define WM8990_RIGHT_OUTPUT_VOLUME 0x1D | ||
50 | #define WM8990_LINE_OUTPUTS_VOLUME 0x1E | ||
51 | #define WM8990_OUT3_4_VOLUME 0x1F | ||
52 | #define WM8990_LEFT_OPGA_VOLUME 0x20 | ||
53 | #define WM8990_RIGHT_OPGA_VOLUME 0x21 | ||
54 | #define WM8990_SPEAKER_VOLUME 0x22 | ||
55 | #define WM8990_CLASSD1 0x23 | ||
56 | #define WM8990_CLASSD3 0x25 | ||
57 | #define WM8990_INPUT_MIXER1 0x27 | ||
58 | #define WM8990_INPUT_MIXER2 0x28 | ||
59 | #define WM8990_INPUT_MIXER3 0x29 | ||
60 | #define WM8990_INPUT_MIXER4 0x2A | ||
61 | #define WM8990_INPUT_MIXER5 0x2B | ||
62 | #define WM8990_INPUT_MIXER6 0x2C | ||
63 | #define WM8990_OUTPUT_MIXER1 0x2D | ||
64 | #define WM8990_OUTPUT_MIXER2 0x2E | ||
65 | #define WM8990_OUTPUT_MIXER3 0x2F | ||
66 | #define WM8990_OUTPUT_MIXER4 0x30 | ||
67 | #define WM8990_OUTPUT_MIXER5 0x31 | ||
68 | #define WM8990_OUTPUT_MIXER6 0x32 | ||
69 | #define WM8990_OUT3_4_MIXER 0x33 | ||
70 | #define WM8990_LINE_MIXER1 0x34 | ||
71 | #define WM8990_LINE_MIXER2 0x35 | ||
72 | #define WM8990_SPEAKER_MIXER 0x36 | ||
73 | #define WM8990_ADDITIONAL_CONTROL 0x37 | ||
74 | #define WM8990_ANTIPOP1 0x38 | ||
75 | #define WM8990_ANTIPOP2 0x39 | ||
76 | #define WM8990_MICBIAS 0x3A | ||
77 | #define WM8990_PLL1 0x3C | ||
78 | #define WM8990_PLL2 0x3D | ||
79 | #define WM8990_PLL3 0x3E | ||
80 | #define WM8990_INTDRIVBITS 0x3F | ||
81 | |||
82 | #define WM8990_REGISTER_COUNT 60 | ||
83 | #define WM8990_MAX_REGISTER 0x3F | ||
84 | |||
85 | /* | ||
86 | * Field Definitions. | ||
87 | */ | ||
88 | |||
89 | /* | ||
90 | * R0 (0x00) - Reset | ||
91 | */ | ||
92 | #define WM8990_SW_RESET_CHIP_ID_MASK 0xFFFF /* SW_RESET_CHIP_ID */ | ||
93 | |||
94 | /* | ||
95 | * R1 (0x01) - Power Management (1) | ||
96 | */ | ||
97 | #define WM8990_SPK_ENA 0x1000 /* SPK_ENA */ | ||
98 | #define WM8990_SPK_ENA_BIT 12 | ||
99 | #define WM8990_OUT3_ENA 0x0800 /* OUT3_ENA */ | ||
100 | #define WM8990_OUT3_ENA_BIT 11 | ||
101 | #define WM8990_OUT4_ENA 0x0400 /* OUT4_ENA */ | ||
102 | #define WM8990_OUT4_ENA_BIT 10 | ||
103 | #define WM8990_LOUT_ENA 0x0200 /* LOUT_ENA */ | ||
104 | #define WM8990_LOUT_ENA_BIT 9 | ||
105 | #define WM8990_ROUT_ENA 0x0100 /* ROUT_ENA */ | ||
106 | #define WM8990_ROUT_ENA_BIT 8 | ||
107 | #define WM8990_MICBIAS_ENA 0x0010 /* MICBIAS_ENA */ | ||
108 | #define WM8990_MICBIAS_ENA_BIT 4 | ||
109 | #define WM8990_VMID_MODE_MASK 0x0006 /* VMID_MODE - [2:1] */ | ||
110 | #define WM8990_VREF_ENA 0x0001 /* VREF_ENA */ | ||
111 | #define WM8990_VREF_ENA_BIT 0 | ||
112 | |||
113 | /* | ||
114 | * R2 (0x02) - Power Management (2) | ||
115 | */ | ||
116 | #define WM8990_PLL_ENA 0x8000 /* PLL_ENA */ | ||
117 | #define WM8990_PLL_ENA_BIT 15 | ||
118 | #define WM8990_TSHUT_ENA 0x4000 /* TSHUT_ENA */ | ||
119 | #define WM8990_TSHUT_ENA_BIT 14 | ||
120 | #define WM8990_TSHUT_OPDIS 0x2000 /* TSHUT_OPDIS */ | ||
121 | #define WM8990_TSHUT_OPDIS_BIT 13 | ||
122 | #define WM8990_OPCLK_ENA 0x0800 /* OPCLK_ENA */ | ||
123 | #define WM8990_OPCLK_ENA_BIT 11 | ||
124 | #define WM8990_AINL_ENA 0x0200 /* AINL_ENA */ | ||
125 | #define WM8990_AINL_ENA_BIT 9 | ||
126 | #define WM8990_AINR_ENA 0x0100 /* AINR_ENA */ | ||
127 | #define WM8990_AINR_ENA_BIT 8 | ||
128 | #define WM8990_LIN34_ENA 0x0080 /* LIN34_ENA */ | ||
129 | #define WM8990_LIN34_ENA_BIT 7 | ||
130 | #define WM8990_LIN12_ENA 0x0040 /* LIN12_ENA */ | ||
131 | #define WM8990_LIN12_ENA_BIT 6 | ||
132 | #define WM8990_RIN34_ENA 0x0020 /* RIN34_ENA */ | ||
133 | #define WM8990_RIN34_ENA_BIT 5 | ||
134 | #define WM8990_RIN12_ENA 0x0010 /* RIN12_ENA */ | ||
135 | #define WM8990_RIN12_ENA_BIT 4 | ||
136 | #define WM8990_ADCL_ENA 0x0002 /* ADCL_ENA */ | ||
137 | #define WM8990_ADCL_ENA_BIT 1 | ||
138 | #define WM8990_ADCR_ENA 0x0001 /* ADCR_ENA */ | ||
139 | #define WM8990_ADCR_ENA_BIT 0 | ||
140 | |||
141 | /* | ||
142 | * R3 (0x03) - Power Management (3) | ||
143 | */ | ||
144 | #define WM8990_LON_ENA 0x2000 /* LON_ENA */ | ||
145 | #define WM8990_LON_ENA_BIT 13 | ||
146 | #define WM8990_LOP_ENA 0x1000 /* LOP_ENA */ | ||
147 | #define WM8990_LOP_ENA_BIT 12 | ||
148 | #define WM8990_RON_ENA 0x0800 /* RON_ENA */ | ||
149 | #define WM8990_RON_ENA_BIT 11 | ||
150 | #define WM8990_ROP_ENA 0x0400 /* ROP_ENA */ | ||
151 | #define WM8990_ROP_ENA_BIT 10 | ||
152 | #define WM8990_LOPGA_ENA 0x0080 /* LOPGA_ENA */ | ||
153 | #define WM8990_LOPGA_ENA_BIT 7 | ||
154 | #define WM8990_ROPGA_ENA 0x0040 /* ROPGA_ENA */ | ||
155 | #define WM8990_ROPGA_ENA_BIT 6 | ||
156 | #define WM8990_LOMIX_ENA 0x0020 /* LOMIX_ENA */ | ||
157 | #define WM8990_LOMIX_ENA_BIT 5 | ||
158 | #define WM8990_ROMIX_ENA 0x0010 /* ROMIX_ENA */ | ||
159 | #define WM8990_ROMIX_ENA_BIT 4 | ||
160 | #define WM8990_DACL_ENA 0x0002 /* DACL_ENA */ | ||
161 | #define WM8990_DACL_ENA_BIT 1 | ||
162 | #define WM8990_DACR_ENA 0x0001 /* DACR_ENA */ | ||
163 | #define WM8990_DACR_ENA_BIT 0 | ||
164 | |||
165 | /* | ||
166 | * R4 (0x04) - Audio Interface (1) | ||
167 | */ | ||
168 | #define WM8990_AIFADCL_SRC 0x8000 /* AIFADCL_SRC */ | ||
169 | #define WM8990_AIFADCR_SRC 0x4000 /* AIFADCR_SRC */ | ||
170 | #define WM8990_AIFADC_TDM 0x2000 /* AIFADC_TDM */ | ||
171 | #define WM8990_AIFADC_TDM_CHAN 0x1000 /* AIFADC_TDM_CHAN */ | ||
172 | #define WM8990_AIF_BCLK_INV 0x0100 /* AIF_BCLK_INV */ | ||
173 | #define WM8990_AIF_LRCLK_INV 0x0080 /* AIF_LRCLK_INV */ | ||
174 | #define WM8990_AIF_WL_MASK 0x0060 /* AIF_WL - [6:5] */ | ||
175 | #define WM8990_AIF_WL_16BITS (0 << 5) | ||
176 | #define WM8990_AIF_WL_20BITS (1 << 5) | ||
177 | #define WM8990_AIF_WL_24BITS (2 << 5) | ||
178 | #define WM8990_AIF_WL_32BITS (3 << 5) | ||
179 | #define WM8990_AIF_FMT_MASK 0x0018 /* AIF_FMT - [4:3] */ | ||
180 | #define WM8990_AIF_TMF_RIGHTJ (0 << 3) | ||
181 | #define WM8990_AIF_TMF_LEFTJ (1 << 3) | ||
182 | #define WM8990_AIF_TMF_I2S (2 << 3) | ||
183 | #define WM8990_AIF_TMF_DSP (3 << 3) | ||
184 | |||
185 | /* | ||
186 | * R5 (0x05) - Audio Interface (2) | ||
187 | */ | ||
188 | #define WM8990_DACL_SRC 0x8000 /* DACL_SRC */ | ||
189 | #define WM8990_DACR_SRC 0x4000 /* DACR_SRC */ | ||
190 | #define WM8990_AIFDAC_TDM 0x2000 /* AIFDAC_TDM */ | ||
191 | #define WM8990_AIFDAC_TDM_CHAN 0x1000 /* AIFDAC_TDM_CHAN */ | ||
192 | #define WM8990_DAC_BOOST_MASK 0x0C00 /* DAC_BOOST */ | ||
193 | #define WM8990_DAC_COMP 0x0010 /* DAC_COMP */ | ||
194 | #define WM8990_DAC_COMPMODE 0x0008 /* DAC_COMPMODE */ | ||
195 | #define WM8990_ADC_COMP 0x0004 /* ADC_COMP */ | ||
196 | #define WM8990_ADC_COMPMODE 0x0002 /* ADC_COMPMODE */ | ||
197 | #define WM8990_LOOPBACK 0x0001 /* LOOPBACK */ | ||
198 | |||
199 | /* | ||
200 | * R6 (0x06) - Clocking (1) | ||
201 | */ | ||
202 | #define WM8990_TOCLK_RATE 0x8000 /* TOCLK_RATE */ | ||
203 | #define WM8990_TOCLK_ENA 0x4000 /* TOCLK_ENA */ | ||
204 | #define WM8990_OPCLKDIV_MASK 0x1E00 /* OPCLKDIV - [12:9] */ | ||
205 | #define WM8990_DCLKDIV_MASK 0x01C0 /* DCLKDIV - [8:6] */ | ||
206 | #define WM8990_BCLK_DIV_MASK 0x001E /* BCLK_DIV - [4:1] */ | ||
207 | #define WM8990_BCLK_DIV_1 (0x0 << 1) | ||
208 | #define WM8990_BCLK_DIV_1_5 (0x1 << 1) | ||
209 | #define WM8990_BCLK_DIV_2 (0x2 << 1) | ||
210 | #define WM8990_BCLK_DIV_3 (0x3 << 1) | ||
211 | #define WM8990_BCLK_DIV_4 (0x4 << 1) | ||
212 | #define WM8990_BCLK_DIV_5_5 (0x5 << 1) | ||
213 | #define WM8990_BCLK_DIV_6 (0x6 << 1) | ||
214 | #define WM8990_BCLK_DIV_8 (0x7 << 1) | ||
215 | #define WM8990_BCLK_DIV_11 (0x8 << 1) | ||
216 | #define WM8990_BCLK_DIV_12 (0x9 << 1) | ||
217 | #define WM8990_BCLK_DIV_16 (0xA << 1) | ||
218 | #define WM8990_BCLK_DIV_22 (0xB << 1) | ||
219 | #define WM8990_BCLK_DIV_24 (0xC << 1) | ||
220 | #define WM8990_BCLK_DIV_32 (0xD << 1) | ||
221 | #define WM8990_BCLK_DIV_44 (0xE << 1) | ||
222 | #define WM8990_BCLK_DIV_48 (0xF << 1) | ||
223 | |||
224 | /* | ||
225 | * R7 (0x07) - Clocking (2) | ||
226 | */ | ||
227 | #define WM8990_MCLK_SRC 0x8000 /* MCLK_SRC */ | ||
228 | #define WM8990_SYSCLK_SRC 0x4000 /* SYSCLK_SRC */ | ||
229 | #define WM8990_CLK_FORCE 0x2000 /* CLK_FORCE */ | ||
230 | #define WM8990_MCLK_DIV_MASK 0x1800 /* MCLK_DIV - [12:11] */ | ||
231 | #define WM8990_MCLK_DIV_1 (0 << 11) | ||
232 | #define WM8990_MCLK_DIV_2 (2 << 11) | ||
233 | #define WM8990_MCLK_INV 0x0400 /* MCLK_INV */ | ||
234 | #define WM8990_ADC_CLKDIV_MASK 0x00E0 /* ADC_CLKDIV */ | ||
235 | #define WM8990_ADC_CLKDIV_1 (0 << 5) | ||
236 | #define WM8990_ADC_CLKDIV_1_5 (1 << 5) | ||
237 | #define WM8990_ADC_CLKDIV_2 (2 << 5) | ||
238 | #define WM8990_ADC_CLKDIV_3 (3 << 5) | ||
239 | #define WM8990_ADC_CLKDIV_4 (4 << 5) | ||
240 | #define WM8990_ADC_CLKDIV_5_5 (5 << 5) | ||
241 | #define WM8990_ADC_CLKDIV_6 (6 << 5) | ||
242 | #define WM8990_DAC_CLKDIV_MASK 0x001C /* DAC_CLKDIV - [4:2] */ | ||
243 | #define WM8990_DAC_CLKDIV_1 (0 << 2) | ||
244 | #define WM8990_DAC_CLKDIV_1_5 (1 << 2) | ||
245 | #define WM8990_DAC_CLKDIV_2 (2 << 2) | ||
246 | #define WM8990_DAC_CLKDIV_3 (3 << 2) | ||
247 | #define WM8990_DAC_CLKDIV_4 (4 << 2) | ||
248 | #define WM8990_DAC_CLKDIV_5_5 (5 << 2) | ||
249 | #define WM8990_DAC_CLKDIV_6 (6 << 2) | ||
250 | |||
251 | /* | ||
252 | * R8 (0x08) - Audio Interface (3) | ||
253 | */ | ||
254 | #define WM8990_AIF_MSTR1 0x8000 /* AIF_MSTR1 */ | ||
255 | #define WM8990_AIF_MSTR2 0x4000 /* AIF_MSTR2 */ | ||
256 | #define WM8990_AIF_SEL 0x2000 /* AIF_SEL */ | ||
257 | #define WM8990_ADCLRC_DIR 0x0800 /* ADCLRC_DIR */ | ||
258 | #define WM8990_ADCLRC_RATE_MASK 0x07FF /* ADCLRC_RATE */ | ||
259 | |||
260 | /* | ||
261 | * R9 (0x09) - Audio Interface (4) | ||
262 | */ | ||
263 | #define WM8990_ALRCGPIO1 0x8000 /* ALRCGPIO1 */ | ||
264 | #define WM8990_ALRCBGPIO6 0x4000 /* ALRCBGPIO6 */ | ||
265 | #define WM8990_AIF_TRIS 0x2000 /* AIF_TRIS */ | ||
266 | #define WM8990_DACLRC_DIR 0x0800 /* DACLRC_DIR */ | ||
267 | #define WM8990_DACLRC_RATE_MASK 0x07FF /* DACLRC_RATE */ | ||
268 | |||
269 | /* | ||
270 | * R10 (0x0A) - DAC CTRL | ||
271 | */ | ||
272 | #define WM8990_AIF_LRCLKRATE 0x0400 /* AIF_LRCLKRATE */ | ||
273 | #define WM8990_DAC_MONO 0x0200 /* DAC_MONO */ | ||
274 | #define WM8990_DAC_SB_FILT 0x0100 /* DAC_SB_FILT */ | ||
275 | #define WM8990_DAC_MUTERATE 0x0080 /* DAC_MUTERATE */ | ||
276 | #define WM8990_DAC_MUTEMODE 0x0040 /* DAC_MUTEMODE */ | ||
277 | #define WM8990_DEEMP_MASK 0x0030 /* DEEMP - [5:4] */ | ||
278 | #define WM8990_DAC_MUTE 0x0004 /* DAC_MUTE */ | ||
279 | #define WM8990_DACL_DATINV 0x0002 /* DACL_DATINV */ | ||
280 | #define WM8990_DACR_DATINV 0x0001 /* DACR_DATINV */ | ||
281 | |||
282 | /* | ||
283 | * R11 (0x0B) - Left DAC Digital Volume | ||
284 | */ | ||
285 | #define WM8990_DAC_VU 0x0100 /* DAC_VU */ | ||
286 | #define WM8990_DACL_VOL_MASK 0x00FF /* DACL_VOL - [7:0] */ | ||
287 | #define WM8990_DACL_VOL_SHIFT 0 | ||
288 | /* | ||
289 | * R12 (0x0C) - Right DAC Digital Volume | ||
290 | */ | ||
291 | #define WM8990_DAC_VU 0x0100 /* DAC_VU */ | ||
292 | #define WM8990_DACR_VOL_MASK 0x00FF /* DACR_VOL - [7:0] */ | ||
293 | #define WM8990_DACR_VOL_SHIFT 0 | ||
294 | /* | ||
295 | * R13 (0x0D) - Digital Side Tone | ||
296 | */ | ||
297 | #define WM8990_ADCL_DAC_SVOL_MASK 0x0F /* ADCL_DAC_SVOL */ | ||
298 | #define WM8990_ADCL_DAC_SVOL_SHIFT 9 | ||
299 | #define WM8990_ADCR_DAC_SVOL_MASK 0x0F /* ADCR_DAC_SVOL */ | ||
300 | #define WM8990_ADCR_DAC_SVOL_SHIFT 5 | ||
301 | #define WM8990_ADC_TO_DACL_MASK 0x03 /* ADC_TO_DACL - [3:2] */ | ||
302 | #define WM8990_ADC_TO_DACL_SHIFT 2 | ||
303 | #define WM8990_ADC_TO_DACR_MASK 0x03 /* ADC_TO_DACR - [1:0] */ | ||
304 | #define WM8990_ADC_TO_DACR_SHIFT 0 | ||
305 | |||
306 | /* | ||
307 | * R14 (0x0E) - ADC CTRL | ||
308 | */ | ||
309 | #define WM8990_ADC_HPF_ENA 0x0100 /* ADC_HPF_ENA */ | ||
310 | #define WM8990_ADC_HPF_ENA_BIT 8 | ||
311 | #define WM8990_ADC_HPF_CUT_MASK 0x03 /* ADC_HPF_CUT - [6:5] */ | ||
312 | #define WM8990_ADC_HPF_CUT_SHIFT 5 | ||
313 | #define WM8990_ADCL_DATINV 0x0002 /* ADCL_DATINV */ | ||
314 | #define WM8990_ADCL_DATINV_BIT 1 | ||
315 | #define WM8990_ADCR_DATINV 0x0001 /* ADCR_DATINV */ | ||
316 | #define WM8990_ADCR_DATINV_BIT 0 | ||
317 | |||
318 | /* | ||
319 | * R15 (0x0F) - Left ADC Digital Volume | ||
320 | */ | ||
321 | #define WM8990_ADC_VU 0x0100 /* ADC_VU */ | ||
322 | #define WM8990_ADCL_VOL_MASK 0x00FF /* ADCL_VOL - [7:0] */ | ||
323 | #define WM8990_ADCL_VOL_SHIFT 0 | ||
324 | |||
325 | /* | ||
326 | * R16 (0x10) - Right ADC Digital Volume | ||
327 | */ | ||
328 | #define WM8990_ADC_VU 0x0100 /* ADC_VU */ | ||
329 | #define WM8990_ADCR_VOL_MASK 0x00FF /* ADCR_VOL - [7:0] */ | ||
330 | #define WM8990_ADCR_VOL_SHIFT 0 | ||
331 | |||
332 | /* | ||
333 | * R18 (0x12) - GPIO CTRL 1 | ||
334 | */ | ||
335 | #define WM8990_IRQ 0x1000 /* IRQ */ | ||
336 | #define WM8990_TEMPOK 0x0800 /* TEMPOK */ | ||
337 | #define WM8990_MICSHRT 0x0400 /* MICSHRT */ | ||
338 | #define WM8990_MICDET 0x0200 /* MICDET */ | ||
339 | #define WM8990_PLL_LCK 0x0100 /* PLL_LCK */ | ||
340 | #define WM8990_GPI8_STATUS 0x0080 /* GPI8_STATUS */ | ||
341 | #define WM8990_GPI7_STATUS 0x0040 /* GPI7_STATUS */ | ||
342 | #define WM8990_GPIO6_STATUS 0x0020 /* GPIO6_STATUS */ | ||
343 | #define WM8990_GPIO5_STATUS 0x0010 /* GPIO5_STATUS */ | ||
344 | #define WM8990_GPIO4_STATUS 0x0008 /* GPIO4_STATUS */ | ||
345 | #define WM8990_GPIO3_STATUS 0x0004 /* GPIO3_STATUS */ | ||
346 | #define WM8990_GPIO2_STATUS 0x0002 /* GPIO2_STATUS */ | ||
347 | #define WM8990_GPIO1_STATUS 0x0001 /* GPIO1_STATUS */ | ||
348 | |||
349 | /* | ||
350 | * R19 (0x13) - GPIO1 & GPIO2 | ||
351 | */ | ||
352 | #define WM8990_GPIO2_DEB_ENA 0x8000 /* GPIO2_DEB_ENA */ | ||
353 | #define WM8990_GPIO2_IRQ_ENA 0x4000 /* GPIO2_IRQ_ENA */ | ||
354 | #define WM8990_GPIO2_PU 0x2000 /* GPIO2_PU */ | ||
355 | #define WM8990_GPIO2_PD 0x1000 /* GPIO2_PD */ | ||
356 | #define WM8990_GPIO2_SEL_MASK 0x0F00 /* GPIO2_SEL - [11:8] */ | ||
357 | #define WM8990_GPIO1_DEB_ENA 0x0080 /* GPIO1_DEB_ENA */ | ||
358 | #define WM8990_GPIO1_IRQ_ENA 0x0040 /* GPIO1_IRQ_ENA */ | ||
359 | #define WM8990_GPIO1_PU 0x0020 /* GPIO1_PU */ | ||
360 | #define WM8990_GPIO1_PD 0x0010 /* GPIO1_PD */ | ||
361 | #define WM8990_GPIO1_SEL_MASK 0x000F /* GPIO1_SEL - [3:0] */ | ||
362 | |||
363 | /* | ||
364 | * R20 (0x14) - GPIO3 & GPIO4 | ||
365 | */ | ||
366 | #define WM8990_GPIO4_DEB_ENA 0x8000 /* GPIO4_DEB_ENA */ | ||
367 | #define WM8990_GPIO4_IRQ_ENA 0x4000 /* GPIO4_IRQ_ENA */ | ||
368 | #define WM8990_GPIO4_PU 0x2000 /* GPIO4_PU */ | ||
369 | #define WM8990_GPIO4_PD 0x1000 /* GPIO4_PD */ | ||
370 | #define WM8990_GPIO4_SEL_MASK 0x0F00 /* GPIO4_SEL - [11:8] */ | ||
371 | #define WM8990_GPIO3_DEB_ENA 0x0080 /* GPIO3_DEB_ENA */ | ||
372 | #define WM8990_GPIO3_IRQ_ENA 0x0040 /* GPIO3_IRQ_ENA */ | ||
373 | #define WM8990_GPIO3_PU 0x0020 /* GPIO3_PU */ | ||
374 | #define WM8990_GPIO3_PD 0x0010 /* GPIO3_PD */ | ||
375 | #define WM8990_GPIO3_SEL_MASK 0x000F /* GPIO3_SEL - [3:0] */ | ||
376 | |||
377 | /* | ||
378 | * R21 (0x15) - GPIO5 & GPIO6 | ||
379 | */ | ||
380 | #define WM8990_GPIO6_DEB_ENA 0x8000 /* GPIO6_DEB_ENA */ | ||
381 | #define WM8990_GPIO6_IRQ_ENA 0x4000 /* GPIO6_IRQ_ENA */ | ||
382 | #define WM8990_GPIO6_PU 0x2000 /* GPIO6_PU */ | ||
383 | #define WM8990_GPIO6_PD 0x1000 /* GPIO6_PD */ | ||
384 | #define WM8990_GPIO6_SEL_MASK 0x0F00 /* GPIO6_SEL - [11:8] */ | ||
385 | #define WM8990_GPIO5_DEB_ENA 0x0080 /* GPIO5_DEB_ENA */ | ||
386 | #define WM8990_GPIO5_IRQ_ENA 0x0040 /* GPIO5_IRQ_ENA */ | ||
387 | #define WM8990_GPIO5_PU 0x0020 /* GPIO5_PU */ | ||
388 | #define WM8990_GPIO5_PD 0x0010 /* GPIO5_PD */ | ||
389 | #define WM8990_GPIO5_SEL_MASK 0x000F /* GPIO5_SEL - [3:0] */ | ||
390 | |||
391 | /* | ||
392 | * R22 (0x16) - GPIOCTRL 2 | ||
393 | */ | ||
394 | #define WM8990_RD_3W_ENA 0x8000 /* RD_3W_ENA */ | ||
395 | #define WM8990_MODE_3W4W 0x4000 /* MODE_3W4W */ | ||
396 | #define WM8990_TEMPOK_IRQ_ENA 0x0800 /* TEMPOK_IRQ_ENA */ | ||
397 | #define WM8990_MICSHRT_IRQ_ENA 0x0400 /* MICSHRT_IRQ_ENA */ | ||
398 | #define WM8990_MICDET_IRQ_ENA 0x0200 /* MICDET_IRQ_ENA */ | ||
399 | #define WM8990_PLL_LCK_IRQ_ENA 0x0100 /* PLL_LCK_IRQ_ENA */ | ||
400 | #define WM8990_GPI8_DEB_ENA 0x0080 /* GPI8_DEB_ENA */ | ||
401 | #define WM8990_GPI8_IRQ_ENA 0x0040 /* GPI8_IRQ_ENA */ | ||
402 | #define WM8990_GPI8_ENA 0x0010 /* GPI8_ENA */ | ||
403 | #define WM8990_GPI7_DEB_ENA 0x0008 /* GPI7_DEB_ENA */ | ||
404 | #define WM8990_GPI7_IRQ_ENA 0x0004 /* GPI7_IRQ_ENA */ | ||
405 | #define WM8990_GPI7_ENA 0x0001 /* GPI7_ENA */ | ||
406 | |||
407 | /* | ||
408 | * R23 (0x17) - GPIO_POL | ||
409 | */ | ||
410 | #define WM8990_IRQ_INV 0x1000 /* IRQ_INV */ | ||
411 | #define WM8990_TEMPOK_POL 0x0800 /* TEMPOK_POL */ | ||
412 | #define WM8990_MICSHRT_POL 0x0400 /* MICSHRT_POL */ | ||
413 | #define WM8990_MICDET_POL 0x0200 /* MICDET_POL */ | ||
414 | #define WM8990_PLL_LCK_POL 0x0100 /* PLL_LCK_POL */ | ||
415 | #define WM8990_GPI8_POL 0x0080 /* GPI8_POL */ | ||
416 | #define WM8990_GPI7_POL 0x0040 /* GPI7_POL */ | ||
417 | #define WM8990_GPIO6_POL 0x0020 /* GPIO6_POL */ | ||
418 | #define WM8990_GPIO5_POL 0x0010 /* GPIO5_POL */ | ||
419 | #define WM8990_GPIO4_POL 0x0008 /* GPIO4_POL */ | ||
420 | #define WM8990_GPIO3_POL 0x0004 /* GPIO3_POL */ | ||
421 | #define WM8990_GPIO2_POL 0x0002 /* GPIO2_POL */ | ||
422 | #define WM8990_GPIO1_POL 0x0001 /* GPIO1_POL */ | ||
423 | |||
424 | /* | ||
425 | * R24 (0x18) - Left Line Input 1&2 Volume | ||
426 | */ | ||
427 | #define WM8990_IPVU 0x0100 /* IPVU */ | ||
428 | #define WM8990_LI12MUTE 0x0080 /* LI12MUTE */ | ||
429 | #define WM8990_LI12MUTE_BIT 7 | ||
430 | #define WM8990_LI12ZC 0x0040 /* LI12ZC */ | ||
431 | #define WM8990_LI12ZC_BIT 6 | ||
432 | #define WM8990_LIN12VOL_MASK 0x001F /* LIN12VOL - [4:0] */ | ||
433 | #define WM8990_LIN12VOL_SHIFT 0 | ||
434 | /* | ||
435 | * R25 (0x19) - Left Line Input 3&4 Volume | ||
436 | */ | ||
437 | #define WM8990_IPVU 0x0100 /* IPVU */ | ||
438 | #define WM8990_LI34MUTE 0x0080 /* LI34MUTE */ | ||
439 | #define WM8990_LI34MUTE_BIT 7 | ||
440 | #define WM8990_LI34ZC 0x0040 /* LI34ZC */ | ||
441 | #define WM8990_LI34ZC_BIT 6 | ||
442 | #define WM8990_LIN34VOL_MASK 0x001F /* LIN34VOL - [4:0] */ | ||
443 | #define WM8990_LIN34VOL_SHIFT 0 | ||
444 | |||
445 | /* | ||
446 | * R26 (0x1A) - Right Line Input 1&2 Volume | ||
447 | */ | ||
448 | #define WM8990_IPVU 0x0100 /* IPVU */ | ||
449 | #define WM8990_RI12MUTE 0x0080 /* RI12MUTE */ | ||
450 | #define WM8990_RI12MUTE_BIT 7 | ||
451 | #define WM8990_RI12ZC 0x0040 /* RI12ZC */ | ||
452 | #define WM8990_RI12ZC_BIT 6 | ||
453 | #define WM8990_RIN12VOL_MASK 0x001F /* RIN12VOL - [4:0] */ | ||
454 | #define WM8990_RIN12VOL_SHIFT 0 | ||
455 | |||
456 | /* | ||
457 | * R27 (0x1B) - Right Line Input 3&4 Volume | ||
458 | */ | ||
459 | #define WM8990_IPVU 0x0100 /* IPVU */ | ||
460 | #define WM8990_RI34MUTE 0x0080 /* RI34MUTE */ | ||
461 | #define WM8990_RI34MUTE_BIT 7 | ||
462 | #define WM8990_RI34ZC 0x0040 /* RI34ZC */ | ||
463 | #define WM8990_RI34ZC_BIT 6 | ||
464 | #define WM8990_RIN34VOL_MASK 0x001F /* RIN34VOL - [4:0] */ | ||
465 | #define WM8990_RIN34VOL_SHIFT 0 | ||
466 | |||
467 | /* | ||
468 | * R28 (0x1C) - Left Output Volume | ||
469 | */ | ||
470 | #define WM8990_OPVU 0x0100 /* OPVU */ | ||
471 | #define WM8990_LOZC 0x0080 /* LOZC */ | ||
472 | #define WM8990_LOZC_BIT 7 | ||
473 | #define WM8990_LOUTVOL_MASK 0x007F /* LOUTVOL - [6:0] */ | ||
474 | #define WM8990_LOUTVOL_SHIFT 0 | ||
475 | /* | ||
476 | * R29 (0x1D) - Right Output Volume | ||
477 | */ | ||
478 | #define WM8990_OPVU 0x0100 /* OPVU */ | ||
479 | #define WM8990_ROZC 0x0080 /* ROZC */ | ||
480 | #define WM8990_ROZC_BIT 7 | ||
481 | #define WM8990_ROUTVOL_MASK 0x007F /* ROUTVOL - [6:0] */ | ||
482 | #define WM8990_ROUTVOL_SHIFT 0 | ||
483 | /* | ||
484 | * R30 (0x1E) - Line Outputs Volume | ||
485 | */ | ||
486 | #define WM8990_LONMUTE 0x0040 /* LONMUTE */ | ||
487 | #define WM8990_LONMUTE_BIT 6 | ||
488 | #define WM8990_LOPMUTE 0x0020 /* LOPMUTE */ | ||
489 | #define WM8990_LOPMUTE_BIT 5 | ||
490 | #define WM8990_LOATTN 0x0010 /* LOATTN */ | ||
491 | #define WM8990_LOATTN_BIT 4 | ||
492 | #define WM8990_RONMUTE 0x0004 /* RONMUTE */ | ||
493 | #define WM8990_RONMUTE_BIT 2 | ||
494 | #define WM8990_ROPMUTE 0x0002 /* ROPMUTE */ | ||
495 | #define WM8990_ROPMUTE_BIT 1 | ||
496 | #define WM8990_ROATTN 0x0001 /* ROATTN */ | ||
497 | #define WM8990_ROATTN_BIT 0 | ||
498 | |||
499 | /* | ||
500 | * R31 (0x1F) - Out3/4 Volume | ||
501 | */ | ||
502 | #define WM8990_OUT3MUTE 0x0020 /* OUT3MUTE */ | ||
503 | #define WM8990_OUT3MUTE_BIT 5 | ||
504 | #define WM8990_OUT3ATTN 0x0010 /* OUT3ATTN */ | ||
505 | #define WM8990_OUT3ATTN_BIT 4 | ||
506 | #define WM8990_OUT4MUTE 0x0002 /* OUT4MUTE */ | ||
507 | #define WM8990_OUT4MUTE_BIT 1 | ||
508 | #define WM8990_OUT4ATTN 0x0001 /* OUT4ATTN */ | ||
509 | #define WM8990_OUT4ATTN_BIT 0 | ||
510 | |||
511 | /* | ||
512 | * R32 (0x20) - Left OPGA Volume | ||
513 | */ | ||
514 | #define WM8990_OPVU 0x0100 /* OPVU */ | ||
515 | #define WM8990_LOPGAZC 0x0080 /* LOPGAZC */ | ||
516 | #define WM8990_LOPGAZC_BIT 7 | ||
517 | #define WM8990_LOPGAVOL_MASK 0x007F /* LOPGAVOL - [6:0] */ | ||
518 | #define WM8990_LOPGAVOL_SHIFT 0 | ||
519 | |||
520 | /* | ||
521 | * R33 (0x21) - Right OPGA Volume | ||
522 | */ | ||
523 | #define WM8990_OPVU 0x0100 /* OPVU */ | ||
524 | #define WM8990_ROPGAZC 0x0080 /* ROPGAZC */ | ||
525 | #define WM8990_ROPGAZC_BIT 7 | ||
526 | #define WM8990_ROPGAVOL_MASK 0x007F /* ROPGAVOL - [6:0] */ | ||
527 | #define WM8990_ROPGAVOL_SHIFT 0 | ||
528 | /* | ||
529 | * R34 (0x22) - Speaker Volume | ||
530 | */ | ||
531 | #define WM8990_SPKVOL_MASK 0x0003 /* SPKVOL - [1:0] */ | ||
532 | #define WM8990_SPKVOL_SHIFT 0 | ||
533 | |||
534 | /* | ||
535 | * R35 (0x23) - ClassD1 | ||
536 | */ | ||
537 | #define WM8990_CDMODE 0x0100 /* CDMODE */ | ||
538 | #define WM8990_CDMODE_BIT 8 | ||
539 | |||
540 | /* | ||
541 | * R37 (0x25) - ClassD3 | ||
542 | */ | ||
543 | #define WM8990_DCGAIN_MASK 0x0007 /* DCGAIN - [5:3] */ | ||
544 | #define WM8990_DCGAIN_SHIFT 3 | ||
545 | #define WM8990_ACGAIN_MASK 0x0007 /* ACGAIN - [2:0] */ | ||
546 | #define WM8990_ACGAIN_SHIFT 0 | ||
547 | /* | ||
548 | * R39 (0x27) - Input Mixer1 | ||
549 | */ | ||
550 | #define WM8990_AINLMODE_MASK 0x000C /* AINLMODE - [3:2] */ | ||
551 | #define WM8990_AINLMODE_SHIFT 2 | ||
552 | #define WM8990_AINRMODE_MASK 0x0003 /* AINRMODE - [1:0] */ | ||
553 | #define WM8990_AINRMODE_SHIFT 0 | ||
554 | |||
555 | /* | ||
556 | * R40 (0x28) - Input Mixer2 | ||
557 | */ | ||
558 | #define WM8990_LMP4 0x0080 /* LMP4 */ | ||
559 | #define WM8990_LMP4_BIT 7 /* LMP4 */ | ||
560 | #define WM8990_LMN3 0x0040 /* LMN3 */ | ||
561 | #define WM8990_LMN3_BIT 6 /* LMN3 */ | ||
562 | #define WM8990_LMP2 0x0020 /* LMP2 */ | ||
563 | #define WM8990_LMP2_BIT 5 /* LMP2 */ | ||
564 | #define WM8990_LMN1 0x0010 /* LMN1 */ | ||
565 | #define WM8990_LMN1_BIT 4 /* LMN1 */ | ||
566 | #define WM8990_RMP4 0x0008 /* RMP4 */ | ||
567 | #define WM8990_RMP4_BIT 3 /* RMP4 */ | ||
568 | #define WM8990_RMN3 0x0004 /* RMN3 */ | ||
569 | #define WM8990_RMN3_BIT 2 /* RMN3 */ | ||
570 | #define WM8990_RMP2 0x0002 /* RMP2 */ | ||
571 | #define WM8990_RMP2_BIT 1 /* RMP2 */ | ||
572 | #define WM8990_RMN1 0x0001 /* RMN1 */ | ||
573 | #define WM8990_RMN1_BIT 0 /* RMN1 */ | ||
574 | |||
575 | /* | ||
576 | * R41 (0x29) - Input Mixer3 | ||
577 | */ | ||
578 | #define WM8990_L34MNB 0x0100 /* L34MNB */ | ||
579 | #define WM8990_L34MNB_BIT 8 | ||
580 | #define WM8990_L34MNBST 0x0080 /* L34MNBST */ | ||
581 | #define WM8990_L34MNBST_BIT 7 | ||
582 | #define WM8990_L12MNB 0x0020 /* L12MNB */ | ||
583 | #define WM8990_L12MNB_BIT 5 | ||
584 | #define WM8990_L12MNBST 0x0010 /* L12MNBST */ | ||
585 | #define WM8990_L12MNBST_BIT 4 | ||
586 | #define WM8990_LDBVOL_MASK 0x0007 /* LDBVOL - [2:0] */ | ||
587 | #define WM8990_LDBVOL_SHIFT 0 | ||
588 | |||
589 | /* | ||
590 | * R42 (0x2A) - Input Mixer4 | ||
591 | */ | ||
592 | #define WM8990_R34MNB 0x0100 /* R34MNB */ | ||
593 | #define WM8990_R34MNB_BIT 8 | ||
594 | #define WM8990_R34MNBST 0x0080 /* R34MNBST */ | ||
595 | #define WM8990_R34MNBST_BIT 7 | ||
596 | #define WM8990_R12MNB 0x0020 /* R12MNB */ | ||
597 | #define WM8990_R12MNB_BIT 5 | ||
598 | #define WM8990_R12MNBST 0x0010 /* R12MNBST */ | ||
599 | #define WM8990_R12MNBST_BIT 4 | ||
600 | #define WM8990_RDBVOL_MASK 0x0007 /* RDBVOL - [2:0] */ | ||
601 | #define WM8990_RDBVOL_SHIFT 0 | ||
602 | |||
603 | /* | ||
604 | * R43 (0x2B) - Input Mixer5 | ||
605 | */ | ||
606 | #define WM8990_LI2BVOL_MASK 0x07 /* LI2BVOL - [8:6] */ | ||
607 | #define WM8990_LI2BVOL_SHIFT 6 | ||
608 | #define WM8990_LR4BVOL_MASK 0x07 /* LR4BVOL - [5:3] */ | ||
609 | #define WM8990_LR4BVOL_SHIFT 3 | ||
610 | #define WM8990_LL4BVOL_MASK 0x07 /* LL4BVOL - [2:0] */ | ||
611 | #define WM8990_LL4BVOL_SHIFT 0 | ||
612 | |||
613 | /* | ||
614 | * R44 (0x2C) - Input Mixer6 | ||
615 | */ | ||
616 | #define WM8990_RI2BVOL_MASK 0x07 /* RI2BVOL - [8:6] */ | ||
617 | #define WM8990_RI2BVOL_SHIFT 6 | ||
618 | #define WM8990_RL4BVOL_MASK 0x07 /* RL4BVOL - [5:3] */ | ||
619 | #define WM8990_RL4BVOL_SHIFT 3 | ||
620 | #define WM8990_RR4BVOL_MASK 0x07 /* RR4BVOL - [2:0] */ | ||
621 | #define WM8990_RR4BVOL_SHIFT 0 | ||
622 | |||
623 | /* | ||
624 | * R45 (0x2D) - Output Mixer1 | ||
625 | */ | ||
626 | #define WM8990_LRBLO 0x0080 /* LRBLO */ | ||
627 | #define WM8990_LRBLO_BIT 7 | ||
628 | #define WM8990_LLBLO 0x0040 /* LLBLO */ | ||
629 | #define WM8990_LLBLO_BIT 6 | ||
630 | #define WM8990_LRI3LO 0x0020 /* LRI3LO */ | ||
631 | #define WM8990_LRI3LO_BIT 5 | ||
632 | #define WM8990_LLI3LO 0x0010 /* LLI3LO */ | ||
633 | #define WM8990_LLI3LO_BIT 4 | ||
634 | #define WM8990_LR12LO 0x0008 /* LR12LO */ | ||
635 | #define WM8990_LR12LO_BIT 3 | ||
636 | #define WM8990_LL12LO 0x0004 /* LL12LO */ | ||
637 | #define WM8990_LL12LO_BIT 2 | ||
638 | #define WM8990_LDLO 0x0001 /* LDLO */ | ||
639 | #define WM8990_LDLO_BIT 0 | ||
640 | |||
641 | /* | ||
642 | * R46 (0x2E) - Output Mixer2 | ||
643 | */ | ||
644 | #define WM8990_RLBRO 0x0080 /* RLBRO */ | ||
645 | #define WM8990_RLBRO_BIT 7 | ||
646 | #define WM8990_RRBRO 0x0040 /* RRBRO */ | ||
647 | #define WM8990_RRBRO_BIT 6 | ||
648 | #define WM8990_RLI3RO 0x0020 /* RLI3RO */ | ||
649 | #define WM8990_RLI3RO_BIT 5 | ||
650 | #define WM8990_RRI3RO 0x0010 /* RRI3RO */ | ||
651 | #define WM8990_RRI3RO_BIT 4 | ||
652 | #define WM8990_RL12RO 0x0008 /* RL12RO */ | ||
653 | #define WM8990_RL12RO_BIT 3 | ||
654 | #define WM8990_RR12RO 0x0004 /* RR12RO */ | ||
655 | #define WM8990_RR12RO_BIT 2 | ||
656 | #define WM8990_RDRO 0x0001 /* RDRO */ | ||
657 | #define WM8990_RDRO_BIT 0 | ||
658 | |||
659 | /* | ||
660 | * R47 (0x2F) - Output Mixer3 | ||
661 | */ | ||
662 | #define WM8990_LLI3LOVOL_MASK 0x07 /* LLI3LOVOL - [8:6] */ | ||
663 | #define WM8990_LLI3LOVOL_SHIFT 6 | ||
664 | #define WM8990_LR12LOVOL_MASK 0x07 /* LR12LOVOL - [5:3] */ | ||
665 | #define WM8990_LR12LOVOL_SHIFT 3 | ||
666 | #define WM8990_LL12LOVOL_MASK 0x07 /* LL12LOVOL - [2:0] */ | ||
667 | #define WM8990_LL12LOVOL_SHIFT 0 | ||
668 | |||
669 | /* | ||
670 | * R48 (0x30) - Output Mixer4 | ||
671 | */ | ||
672 | #define WM8990_RRI3ROVOL_MASK 0x07 /* RRI3ROVOL - [8:6] */ | ||
673 | #define WM8990_RRI3ROVOL_SHIFT 6 | ||
674 | #define WM8990_RL12ROVOL_MASK 0x07 /* RL12ROVOL - [5:3] */ | ||
675 | #define WM8990_RL12ROVOL_SHIFT 3 | ||
676 | #define WM8990_RR12ROVOL_MASK 0x07 /* RR12ROVOL - [2:0] */ | ||
677 | #define WM8990_RR12ROVOL_SHIFT 0 | ||
678 | |||
679 | /* | ||
680 | * R49 (0x31) - Output Mixer5 | ||
681 | */ | ||
682 | #define WM8990_LRI3LOVOL_MASK 0x07 /* LRI3LOVOL - [8:6] */ | ||
683 | #define WM8990_LRI3LOVOL_SHIFT 6 | ||
684 | #define WM8990_LRBLOVOL_MASK 0x07 /* LRBLOVOL - [5:3] */ | ||
685 | #define WM8990_LRBLOVOL_SHIFT 3 | ||
686 | #define WM8990_LLBLOVOL_MASK 0x07 /* LLBLOVOL - [2:0] */ | ||
687 | #define WM8990_LLBLOVOL_SHIFT 0 | ||
688 | |||
689 | /* | ||
690 | * R50 (0x32) - Output Mixer6 | ||
691 | */ | ||
692 | #define WM8990_RLI3ROVOL_MASK 0x07 /* RLI3ROVOL - [8:6] */ | ||
693 | #define WM8990_RLI3ROVOL_SHIFT 6 | ||
694 | #define WM8990_RLBROVOL_MASK 0x07 /* RLBROVOL - [5:3] */ | ||
695 | #define WM8990_RLBROVOL_SHIFT 3 | ||
696 | #define WM8990_RRBROVOL_MASK 0x07 /* RRBROVOL - [2:0] */ | ||
697 | #define WM8990_RRBROVOL_SHIFT 0 | ||
698 | |||
699 | /* | ||
700 | * R51 (0x33) - Out3/4 Mixer | ||
701 | */ | ||
702 | #define WM8990_VSEL_MASK 0x0180 /* VSEL - [8:7] */ | ||
703 | #define WM8990_LI4O3 0x0020 /* LI4O3 */ | ||
704 | #define WM8990_LI4O3_BIT 5 | ||
705 | #define WM8990_LPGAO3 0x0010 /* LPGAO3 */ | ||
706 | #define WM8990_LPGAO3_BIT 4 | ||
707 | #define WM8990_RI4O4 0x0002 /* RI4O4 */ | ||
708 | #define WM8990_RI4O4_BIT 1 | ||
709 | #define WM8990_RPGAO4 0x0001 /* RPGAO4 */ | ||
710 | #define WM8990_RPGAO4_BIT 0 | ||
711 | /* | ||
712 | * R52 (0x34) - Line Mixer1 | ||
713 | */ | ||
714 | #define WM8990_LLOPGALON 0x0040 /* LLOPGALON */ | ||
715 | #define WM8990_LLOPGALON_BIT 6 | ||
716 | #define WM8990_LROPGALON 0x0020 /* LROPGALON */ | ||
717 | #define WM8990_LROPGALON_BIT 5 | ||
718 | #define WM8990_LOPLON 0x0010 /* LOPLON */ | ||
719 | #define WM8990_LOPLON_BIT 4 | ||
720 | #define WM8990_LR12LOP 0x0004 /* LR12LOP */ | ||
721 | #define WM8990_LR12LOP_BIT 2 | ||
722 | #define WM8990_LL12LOP 0x0002 /* LL12LOP */ | ||
723 | #define WM8990_LL12LOP_BIT 1 | ||
724 | #define WM8990_LLOPGALOP 0x0001 /* LLOPGALOP */ | ||
725 | #define WM8990_LLOPGALOP_BIT 0 | ||
726 | /* | ||
727 | * R53 (0x35) - Line Mixer2 | ||
728 | */ | ||
729 | #define WM8990_RROPGARON 0x0040 /* RROPGARON */ | ||
730 | #define WM8990_RROPGARON_BIT 6 | ||
731 | #define WM8990_RLOPGARON 0x0020 /* RLOPGARON */ | ||
732 | #define WM8990_RLOPGARON_BIT 5 | ||
733 | #define WM8990_ROPRON 0x0010 /* ROPRON */ | ||
734 | #define WM8990_ROPRON_BIT 4 | ||
735 | #define WM8990_RL12ROP 0x0004 /* RL12ROP */ | ||
736 | #define WM8990_RL12ROP_BIT 2 | ||
737 | #define WM8990_RR12ROP 0x0002 /* RR12ROP */ | ||
738 | #define WM8990_RR12ROP_BIT 1 | ||
739 | #define WM8990_RROPGAROP 0x0001 /* RROPGAROP */ | ||
740 | #define WM8990_RROPGAROP_BIT 0 | ||
741 | |||
742 | /* | ||
743 | * R54 (0x36) - Speaker Mixer | ||
744 | */ | ||
745 | #define WM8990_LB2SPK 0x0080 /* LB2SPK */ | ||
746 | #define WM8990_LB2SPK_BIT 7 | ||
747 | #define WM8990_RB2SPK 0x0040 /* RB2SPK */ | ||
748 | #define WM8990_RB2SPK_BIT 6 | ||
749 | #define WM8990_LI2SPK 0x0020 /* LI2SPK */ | ||
750 | #define WM8990_LI2SPK_BIT 5 | ||
751 | #define WM8990_RI2SPK 0x0010 /* RI2SPK */ | ||
752 | #define WM8990_RI2SPK_BIT 4 | ||
753 | #define WM8990_LOPGASPK 0x0008 /* LOPGASPK */ | ||
754 | #define WM8990_LOPGASPK_BIT 3 | ||
755 | #define WM8990_ROPGASPK 0x0004 /* ROPGASPK */ | ||
756 | #define WM8990_ROPGASPK_BIT 2 | ||
757 | #define WM8990_LDSPK 0x0002 /* LDSPK */ | ||
758 | #define WM8990_LDSPK_BIT 1 | ||
759 | #define WM8990_RDSPK 0x0001 /* RDSPK */ | ||
760 | #define WM8990_RDSPK_BIT 0 | ||
761 | |||
762 | /* | ||
763 | * R55 (0x37) - Additional Control | ||
764 | */ | ||
765 | #define WM8990_VROI 0x0001 /* VROI */ | ||
766 | |||
767 | /* | ||
768 | * R56 (0x38) - AntiPOP1 | ||
769 | */ | ||
770 | #define WM8990_DIS_LLINE 0x0020 /* DIS_LLINE */ | ||
771 | #define WM8990_DIS_RLINE 0x0010 /* DIS_RLINE */ | ||
772 | #define WM8990_DIS_OUT3 0x0008 /* DIS_OUT3 */ | ||
773 | #define WM8990_DIS_OUT4 0x0004 /* DIS_OUT4 */ | ||
774 | #define WM8990_DIS_LOUT 0x0002 /* DIS_LOUT */ | ||
775 | #define WM8990_DIS_ROUT 0x0001 /* DIS_ROUT */ | ||
776 | |||
777 | /* | ||
778 | * R57 (0x39) - AntiPOP2 | ||
779 | */ | ||
780 | #define WM8990_SOFTST 0x0040 /* SOFTST */ | ||
781 | #define WM8990_BUFIOEN 0x0008 /* BUFIOEN */ | ||
782 | #define WM8990_BUFDCOPEN 0x0004 /* BUFDCOPEN */ | ||
783 | #define WM8990_POBCTRL 0x0002 /* POBCTRL */ | ||
784 | #define WM8990_VMIDTOG 0x0001 /* VMIDTOG */ | ||
785 | |||
786 | /* | ||
787 | * R58 (0x3A) - MICBIAS | ||
788 | */ | ||
789 | #define WM8990_MCDSCTH_MASK 0x00C0 /* MCDSCTH - [7:6] */ | ||
790 | #define WM8990_MCDTHR_MASK 0x0038 /* MCDTHR - [5:3] */ | ||
791 | #define WM8990_MCD 0x0004 /* MCD */ | ||
792 | #define WM8990_MBSEL 0x0001 /* MBSEL */ | ||
793 | |||
794 | /* | ||
795 | * R60 (0x3C) - PLL1 | ||
796 | */ | ||
797 | #define WM8990_SDM 0x0080 /* SDM */ | ||
798 | #define WM8990_PRESCALE 0x0040 /* PRESCALE */ | ||
799 | #define WM8990_PLLN_MASK 0x000F /* PLLN - [3:0] */ | ||
800 | |||
801 | /* | ||
802 | * R61 (0x3D) - PLL2 | ||
803 | */ | ||
804 | #define WM8990_PLLK1_MASK 0x00FF /* PLLK1 - [7:0] */ | ||
805 | |||
806 | /* | ||
807 | * R62 (0x3E) - PLL3 | ||
808 | */ | ||
809 | #define WM8990_PLLK2_MASK 0x00FF /* PLLK2 - [7:0] */ | ||
810 | |||
811 | /* | ||
812 | * R63 (0x3F) - Internal Driver Bits | ||
813 | */ | ||
814 | #define WM8990_INMIXL_PWR_BIT 0 | ||
815 | #define WM8990_AINLMUX_PWR_BIT 1 | ||
816 | #define WM8990_INMIXR_PWR_BIT 2 | ||
817 | #define WM8990_AINRMUX_PWR_BIT 3 | ||
818 | |||
819 | struct wm8990_setup_data { | ||
820 | unsigned short i2c_address; | ||
821 | }; | ||
822 | |||
823 | #define WM8990_MCLK_DIV 0 | ||
824 | #define WM8990_DACCLK_DIV 1 | ||
825 | #define WM8990_ADCCLK_DIV 2 | ||
826 | #define WM8990_BCLK_DIV 3 | ||
827 | |||
828 | extern struct snd_soc_dai wm8990_dai; | ||
829 | extern struct snd_soc_codec_device soc_codec_dev_wm8990; | ||
830 | |||
831 | #endif /* __WM8990REGISTERDEFS_H__ */ | ||
832 | /*------------------------------ END OF FILE ---------------------------------*/ | ||
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 76c1e2d33e7d..9fc8edd82225 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c | |||
@@ -9,9 +9,6 @@ | |||
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 | * | ||
13 | * Revision history | ||
14 | * 4th Feb 2006 Initial version. | ||
15 | */ | 12 | */ |
16 | 13 | ||
17 | #include <linux/init.h> | 14 | #include <linux/init.h> |
@@ -25,6 +22,7 @@ | |||
25 | #include <sound/initval.h> | 22 | #include <sound/initval.h> |
26 | #include <sound/soc.h> | 23 | #include <sound/soc.h> |
27 | #include <sound/soc-dapm.h> | 24 | #include <sound/soc-dapm.h> |
25 | #include "wm9712.h" | ||
28 | 26 | ||
29 | #define WM9712_VERSION "0.4" | 27 | #define WM9712_VERSION "0.4" |
30 | 28 | ||
@@ -351,7 +349,7 @@ SND_SOC_DAPM_INPUT("MIC1"), | |||
351 | SND_SOC_DAPM_INPUT("MIC2"), | 349 | SND_SOC_DAPM_INPUT("MIC2"), |
352 | }; | 350 | }; |
353 | 351 | ||
354 | static const char *audio_map[][3] = { | 352 | static const struct snd_soc_dapm_route audio_map[] = { |
355 | /* virtual mixer - mixes left & right channels for spk and mono */ | 353 | /* virtual mixer - mixes left & right channels for spk and mono */ |
356 | {"AC97 Mixer", NULL, "Left DAC"}, | 354 | {"AC97 Mixer", NULL, "Left DAC"}, |
357 | {"AC97 Mixer", NULL, "Right DAC"}, | 355 | {"AC97 Mixer", NULL, "Right DAC"}, |
@@ -446,21 +444,14 @@ static const char *audio_map[][3] = { | |||
446 | {"Speaker PGA", NULL, "Speaker Mux"}, | 444 | {"Speaker PGA", NULL, "Speaker Mux"}, |
447 | {"LOUT2", NULL, "Speaker PGA"}, | 445 | {"LOUT2", NULL, "Speaker PGA"}, |
448 | {"ROUT2", NULL, "Speaker PGA"}, | 446 | {"ROUT2", NULL, "Speaker PGA"}, |
449 | |||
450 | {NULL, NULL, NULL}, | ||
451 | }; | 447 | }; |
452 | 448 | ||
453 | static int wm9712_add_widgets(struct snd_soc_codec *codec) | 449 | static int wm9712_add_widgets(struct snd_soc_codec *codec) |
454 | { | 450 | { |
455 | int i; | 451 | snd_soc_dapm_new_controls(codec, wm9712_dapm_widgets, |
456 | 452 | ARRAY_SIZE(wm9712_dapm_widgets)); | |
457 | for (i = 0; i < ARRAY_SIZE(wm9712_dapm_widgets); i++) | ||
458 | snd_soc_dapm_new_control(codec, &wm9712_dapm_widgets[i]); | ||
459 | 453 | ||
460 | /* set up audio path connects */ | 454 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
461 | for (i = 0; audio_map[i][0] != NULL; i++) | ||
462 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | ||
463 | audio_map[i][1], audio_map[i][2]); | ||
464 | 455 | ||
465 | snd_soc_dapm_new_widgets(codec); | 456 | snd_soc_dapm_new_widgets(codec); |
466 | return 0; | 457 | return 0; |
@@ -541,7 +532,7 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream) | |||
541 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\ | 532 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\ |
542 | SNDRV_PCM_RATE_48000) | 533 | SNDRV_PCM_RATE_48000) |
543 | 534 | ||
544 | struct snd_soc_codec_dai wm9712_dai[] = { | 535 | struct snd_soc_dai wm9712_dai[] = { |
545 | { | 536 | { |
546 | .name = "AC97 HiFi", | 537 | .name = "AC97 HiFi", |
547 | .type = SND_SOC_DAI_AC97_BUS, | 538 | .type = SND_SOC_DAI_AC97_BUS, |
@@ -574,23 +565,23 @@ struct snd_soc_codec_dai wm9712_dai[] = { | |||
574 | }; | 565 | }; |
575 | EXPORT_SYMBOL_GPL(wm9712_dai); | 566 | EXPORT_SYMBOL_GPL(wm9712_dai); |
576 | 567 | ||
577 | static int wm9712_dapm_event(struct snd_soc_codec *codec, int event) | 568 | static int wm9712_set_bias_level(struct snd_soc_codec *codec, |
569 | enum snd_soc_bias_level level) | ||
578 | { | 570 | { |
579 | switch (event) { | 571 | switch (level) { |
580 | case SNDRV_CTL_POWER_D0: /* full On */ | 572 | case SND_SOC_BIAS_ON: |
581 | case SNDRV_CTL_POWER_D1: /* partial On */ | 573 | case SND_SOC_BIAS_PREPARE: |
582 | case SNDRV_CTL_POWER_D2: /* partial On */ | ||
583 | break; | 574 | break; |
584 | case SNDRV_CTL_POWER_D3hot: /* Off, with power */ | 575 | case SND_SOC_BIAS_STANDBY: |
585 | ac97_write(codec, AC97_POWERDOWN, 0x0000); | 576 | ac97_write(codec, AC97_POWERDOWN, 0x0000); |
586 | break; | 577 | break; |
587 | case SNDRV_CTL_POWER_D3cold: /* Off, without power */ | 578 | case SND_SOC_BIAS_OFF: |
588 | /* disable everything including AC link */ | 579 | /* disable everything including AC link */ |
589 | ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff); | 580 | ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff); |
590 | ac97_write(codec, AC97_POWERDOWN, 0xffff); | 581 | ac97_write(codec, AC97_POWERDOWN, 0xffff); |
591 | break; | 582 | break; |
592 | } | 583 | } |
593 | codec->dapm_state = event; | 584 | codec->bias_level = level; |
594 | return 0; | 585 | return 0; |
595 | } | 586 | } |
596 | 587 | ||
@@ -598,12 +589,12 @@ static int wm9712_reset(struct snd_soc_codec *codec, int try_warm) | |||
598 | { | 589 | { |
599 | if (try_warm && soc_ac97_ops.warm_reset) { | 590 | if (try_warm && soc_ac97_ops.warm_reset) { |
600 | soc_ac97_ops.warm_reset(codec->ac97); | 591 | soc_ac97_ops.warm_reset(codec->ac97); |
601 | if (!(ac97_read(codec, 0) & 0x8000)) | 592 | if (ac97_read(codec, 0) == wm9712_reg[0]) |
602 | return 1; | 593 | return 1; |
603 | } | 594 | } |
604 | 595 | ||
605 | soc_ac97_ops.reset(codec->ac97); | 596 | soc_ac97_ops.reset(codec->ac97); |
606 | if (ac97_read(codec, 0) & 0x8000) | 597 | if (ac97_read(codec, 0) != wm9712_reg[0]) |
607 | goto err; | 598 | goto err; |
608 | return 0; | 599 | return 0; |
609 | 600 | ||
@@ -618,7 +609,7 @@ static int wm9712_soc_suspend(struct platform_device *pdev, | |||
618 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 609 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
619 | struct snd_soc_codec *codec = socdev->codec; | 610 | struct snd_soc_codec *codec = socdev->codec; |
620 | 611 | ||
621 | wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3cold); | 612 | wm9712_set_bias_level(codec, SND_SOC_BIAS_OFF); |
622 | return 0; | 613 | return 0; |
623 | } | 614 | } |
624 | 615 | ||
@@ -635,7 +626,7 @@ static int wm9712_soc_resume(struct platform_device *pdev) | |||
635 | return ret; | 626 | return ret; |
636 | } | 627 | } |
637 | 628 | ||
638 | wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | 629 | wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
639 | 630 | ||
640 | if (ret == 0) { | 631 | if (ret == 0) { |
641 | /* Sync reg_cache with the hardware after cold reset */ | 632 | /* Sync reg_cache with the hardware after cold reset */ |
@@ -647,8 +638,8 @@ static int wm9712_soc_resume(struct platform_device *pdev) | |||
647 | } | 638 | } |
648 | } | 639 | } |
649 | 640 | ||
650 | if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) | 641 | if (codec->suspend_bias_level == SND_SOC_BIAS_ON) |
651 | wm9712_dapm_event(codec, SNDRV_CTL_POWER_D0); | 642 | wm9712_set_bias_level(codec, SND_SOC_BIAS_ON); |
652 | 643 | ||
653 | return ret; | 644 | return ret; |
654 | } | 645 | } |
@@ -682,7 +673,7 @@ static int wm9712_soc_probe(struct platform_device *pdev) | |||
682 | codec->num_dai = ARRAY_SIZE(wm9712_dai); | 673 | codec->num_dai = ARRAY_SIZE(wm9712_dai); |
683 | codec->write = ac97_write; | 674 | codec->write = ac97_write; |
684 | codec->read = ac97_read; | 675 | codec->read = ac97_read; |
685 | codec->dapm_event = wm9712_dapm_event; | 676 | codec->set_bias_level = wm9712_set_bias_level; |
686 | INIT_LIST_HEAD(&codec->dapm_widgets); | 677 | INIT_LIST_HEAD(&codec->dapm_widgets); |
687 | INIT_LIST_HEAD(&codec->dapm_paths); | 678 | INIT_LIST_HEAD(&codec->dapm_paths); |
688 | 679 | ||
@@ -706,7 +697,7 @@ static int wm9712_soc_probe(struct platform_device *pdev) | |||
706 | /* set alc mux to none */ | 697 | /* set alc mux to none */ |
707 | ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000); | 698 | ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000); |
708 | 699 | ||
709 | wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | 700 | wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
710 | wm9712_add_controls(codec); | 701 | wm9712_add_controls(codec); |
711 | wm9712_add_widgets(codec); | 702 | wm9712_add_widgets(codec); |
712 | ret = snd_soc_register_card(socdev); | 703 | ret = snd_soc_register_card(socdev); |
diff --git a/sound/soc/codecs/wm9712.h b/sound/soc/codecs/wm9712.h index 719105d61e65..d29e8a18ca6d 100644 --- a/sound/soc/codecs/wm9712.h +++ b/sound/soc/codecs/wm9712.h | |||
@@ -8,7 +8,7 @@ | |||
8 | #define WM9712_DAI_AC97_HIFI 0 | 8 | #define WM9712_DAI_AC97_HIFI 0 |
9 | #define WM9712_DAI_AC97_AUX 1 | 9 | #define WM9712_DAI_AC97_AUX 1 |
10 | 10 | ||
11 | extern struct snd_soc_codec_dai wm9712_dai[2]; | 11 | extern struct snd_soc_dai wm9712_dai[2]; |
12 | extern struct snd_soc_codec_device soc_codec_dev_wm9712; | 12 | extern struct snd_soc_codec_device soc_codec_dev_wm9712; |
13 | 13 | ||
14 | #endif | 14 | #endif |
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 1f241161445c..38d1fe0971fc 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c | |||
@@ -10,9 +10,6 @@ | |||
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 | * Revision history | ||
14 | * 4th Feb 2006 Initial version. | ||
15 | * | ||
16 | * Features:- | 13 | * Features:- |
17 | * | 14 | * |
18 | * o Support for AC97 Codec, Voice DAC and Aux DAC | 15 | * o Support for AC97 Codec, Voice DAC and Aux DAC |
@@ -456,7 +453,7 @@ SND_SOC_DAPM_INPUT("MIC2B"), | |||
456 | SND_SOC_DAPM_VMID("VMID"), | 453 | SND_SOC_DAPM_VMID("VMID"), |
457 | }; | 454 | }; |
458 | 455 | ||
459 | static const char *audio_map[][3] = { | 456 | static const struct snd_soc_dapm_route audio_map[] = { |
460 | /* left HP mixer */ | 457 | /* left HP mixer */ |
461 | {"Left HP Mixer", "PC Beep Playback Switch", "PCBEEP"}, | 458 | {"Left HP Mixer", "PC Beep Playback Switch", "PCBEEP"}, |
462 | {"Left HP Mixer", "Voice Playback Switch", "Voice DAC"}, | 459 | {"Left HP Mixer", "Voice Playback Switch", "Voice DAC"}, |
@@ -607,21 +604,14 @@ static const char *audio_map[][3] = { | |||
607 | {"Capture Mono Mux", "Stereo", "Capture Mixer"}, | 604 | {"Capture Mono Mux", "Stereo", "Capture Mixer"}, |
608 | {"Capture Mono Mux", "Left", "Left Capture Source"}, | 605 | {"Capture Mono Mux", "Left", "Left Capture Source"}, |
609 | {"Capture Mono Mux", "Right", "Right Capture Source"}, | 606 | {"Capture Mono Mux", "Right", "Right Capture Source"}, |
610 | |||
611 | {NULL, NULL, NULL}, | ||
612 | }; | 607 | }; |
613 | 608 | ||
614 | static int wm9713_add_widgets(struct snd_soc_codec *codec) | 609 | static int wm9713_add_widgets(struct snd_soc_codec *codec) |
615 | { | 610 | { |
616 | int i; | 611 | snd_soc_dapm_new_controls(codec, wm9713_dapm_widgets, |
617 | 612 | ARRAY_SIZE(wm9713_dapm_widgets)); | |
618 | for (i = 0; i < ARRAY_SIZE(wm9713_dapm_widgets); i++) | ||
619 | snd_soc_dapm_new_control(codec, &wm9713_dapm_widgets[i]); | ||
620 | 613 | ||
621 | /* set up audio path audio_mapnects */ | 614 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
622 | for (i = 0; audio_map[i][0] != NULL; i++) | ||
623 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | ||
624 | audio_map[i][1], audio_map[i][2]); | ||
625 | 615 | ||
626 | snd_soc_dapm_new_widgets(codec); | 616 | snd_soc_dapm_new_widgets(codec); |
627 | return 0; | 617 | return 0; |
@@ -799,7 +789,7 @@ static int wm9713_set_pll(struct snd_soc_codec *codec, | |||
799 | return 0; | 789 | return 0; |
800 | } | 790 | } |
801 | 791 | ||
802 | static int wm9713_set_dai_pll(struct snd_soc_codec_dai *codec_dai, | 792 | static int wm9713_set_dai_pll(struct snd_soc_dai *codec_dai, |
803 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 793 | int pll_id, unsigned int freq_in, unsigned int freq_out) |
804 | { | 794 | { |
805 | struct snd_soc_codec *codec = codec_dai->codec; | 795 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -810,7 +800,7 @@ static int wm9713_set_dai_pll(struct snd_soc_codec_dai *codec_dai, | |||
810 | * Tristate the PCM DAI lines, tristate can be disabled by calling | 800 | * Tristate the PCM DAI lines, tristate can be disabled by calling |
811 | * wm9713_set_dai_fmt() | 801 | * wm9713_set_dai_fmt() |
812 | */ | 802 | */ |
813 | static int wm9713_set_dai_tristate(struct snd_soc_codec_dai *codec_dai, | 803 | static int wm9713_set_dai_tristate(struct snd_soc_dai *codec_dai, |
814 | int tristate) | 804 | int tristate) |
815 | { | 805 | { |
816 | struct snd_soc_codec *codec = codec_dai->codec; | 806 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -826,7 +816,7 @@ static int wm9713_set_dai_tristate(struct snd_soc_codec_dai *codec_dai, | |||
826 | * Configure WM9713 clock dividers. | 816 | * Configure WM9713 clock dividers. |
827 | * Voice DAC needs 256 FS | 817 | * Voice DAC needs 256 FS |
828 | */ | 818 | */ |
829 | static int wm9713_set_dai_clkdiv(struct snd_soc_codec_dai *codec_dai, | 819 | static int wm9713_set_dai_clkdiv(struct snd_soc_dai *codec_dai, |
830 | int div_id, int div) | 820 | int div_id, int div) |
831 | { | 821 | { |
832 | struct snd_soc_codec *codec = codec_dai->codec; | 822 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -868,7 +858,7 @@ static int wm9713_set_dai_clkdiv(struct snd_soc_codec_dai *codec_dai, | |||
868 | return 0; | 858 | return 0; |
869 | } | 859 | } |
870 | 860 | ||
871 | static int wm9713_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | 861 | static int wm9713_set_dai_fmt(struct snd_soc_dai *codec_dai, |
872 | unsigned int fmt) | 862 | unsigned int fmt) |
873 | { | 863 | { |
874 | struct snd_soc_codec *codec = codec_dai->codec; | 864 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -886,7 +876,7 @@ static int wm9713_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, | |||
886 | gpio |= 0x0018; | 876 | gpio |= 0x0018; |
887 | break; | 877 | break; |
888 | case SND_SOC_DAIFMT_CBS_CFS: | 878 | case SND_SOC_DAIFMT_CBS_CFS: |
889 | reg |= 0x0200; | 879 | reg |= 0x2000; |
890 | gpio |= 0x001a; | 880 | gpio |= 0x001a; |
891 | break; | 881 | break; |
892 | case SND_SOC_DAIFMT_CBS_CFM: | 882 | case SND_SOC_DAIFMT_CBS_CFM: |
@@ -1011,15 +1001,24 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream) | |||
1011 | return ac97_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate); | 1001 | return ac97_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate); |
1012 | } | 1002 | } |
1013 | 1003 | ||
1014 | #define WM9713_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | 1004 | #define WM9713_RATES (SNDRV_PCM_RATE_8000 | \ |
1015 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\ | 1005 | SNDRV_PCM_RATE_11025 | \ |
1016 | SNDRV_PCM_RATE_48000) | 1006 | SNDRV_PCM_RATE_22050 | \ |
1007 | SNDRV_PCM_RATE_44100 | \ | ||
1008 | SNDRV_PCM_RATE_48000) | ||
1009 | |||
1010 | #define WM9713_PCM_RATES (SNDRV_PCM_RATE_8000 | \ | ||
1011 | SNDRV_PCM_RATE_11025 | \ | ||
1012 | SNDRV_PCM_RATE_16000 | \ | ||
1013 | SNDRV_PCM_RATE_22050 | \ | ||
1014 | SNDRV_PCM_RATE_44100 | \ | ||
1015 | SNDRV_PCM_RATE_48000) | ||
1017 | 1016 | ||
1018 | #define WM9713_PCM_FORMATS \ | 1017 | #define WM9713_PCM_FORMATS \ |
1019 | (SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \ | 1018 | (SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \ |
1020 | SNDRV_PCM_FORMAT_S24_LE) | 1019 | SNDRV_PCM_FORMAT_S24_LE) |
1021 | 1020 | ||
1022 | struct snd_soc_codec_dai wm9713_dai[] = { | 1021 | struct snd_soc_dai wm9713_dai[] = { |
1023 | { | 1022 | { |
1024 | .name = "AC97 HiFi", | 1023 | .name = "AC97 HiFi", |
1025 | .type = SND_SOC_DAI_AC97_BUS, | 1024 | .type = SND_SOC_DAI_AC97_BUS, |
@@ -1061,13 +1060,13 @@ struct snd_soc_codec_dai wm9713_dai[] = { | |||
1061 | .stream_name = "Voice Playback", | 1060 | .stream_name = "Voice Playback", |
1062 | .channels_min = 1, | 1061 | .channels_min = 1, |
1063 | .channels_max = 1, | 1062 | .channels_max = 1, |
1064 | .rates = WM9713_RATES, | 1063 | .rates = WM9713_PCM_RATES, |
1065 | .formats = WM9713_PCM_FORMATS,}, | 1064 | .formats = WM9713_PCM_FORMATS,}, |
1066 | .capture = { | 1065 | .capture = { |
1067 | .stream_name = "Voice Capture", | 1066 | .stream_name = "Voice Capture", |
1068 | .channels_min = 1, | 1067 | .channels_min = 1, |
1069 | .channels_max = 2, | 1068 | .channels_max = 2, |
1070 | .rates = WM9713_RATES, | 1069 | .rates = WM9713_PCM_RATES, |
1071 | .formats = WM9713_PCM_FORMATS,}, | 1070 | .formats = WM9713_PCM_FORMATS,}, |
1072 | .ops = { | 1071 | .ops = { |
1073 | .hw_params = wm9713_pcm_hw_params, | 1072 | .hw_params = wm9713_pcm_hw_params, |
@@ -1086,44 +1085,44 @@ int wm9713_reset(struct snd_soc_codec *codec, int try_warm) | |||
1086 | { | 1085 | { |
1087 | if (try_warm && soc_ac97_ops.warm_reset) { | 1086 | if (try_warm && soc_ac97_ops.warm_reset) { |
1088 | soc_ac97_ops.warm_reset(codec->ac97); | 1087 | soc_ac97_ops.warm_reset(codec->ac97); |
1089 | if (!(ac97_read(codec, 0) & 0x8000)) | 1088 | if (ac97_read(codec, 0) == wm9713_reg[0]) |
1090 | return 1; | 1089 | return 1; |
1091 | } | 1090 | } |
1092 | 1091 | ||
1093 | soc_ac97_ops.reset(codec->ac97); | 1092 | soc_ac97_ops.reset(codec->ac97); |
1094 | if (ac97_read(codec, 0) & 0x8000) | 1093 | if (ac97_read(codec, 0) != wm9713_reg[0]) |
1095 | return -EIO; | 1094 | return -EIO; |
1096 | return 0; | 1095 | return 0; |
1097 | } | 1096 | } |
1098 | EXPORT_SYMBOL_GPL(wm9713_reset); | 1097 | EXPORT_SYMBOL_GPL(wm9713_reset); |
1099 | 1098 | ||
1100 | static int wm9713_dapm_event(struct snd_soc_codec *codec, int event) | 1099 | static int wm9713_set_bias_level(struct snd_soc_codec *codec, |
1100 | enum snd_soc_bias_level level) | ||
1101 | { | 1101 | { |
1102 | u16 reg; | 1102 | u16 reg; |
1103 | 1103 | ||
1104 | switch (event) { | 1104 | switch (level) { |
1105 | case SNDRV_CTL_POWER_D0: /* full On */ | 1105 | case SND_SOC_BIAS_ON: |
1106 | /* enable thermal shutdown */ | 1106 | /* enable thermal shutdown */ |
1107 | reg = ac97_read(codec, AC97_EXTENDED_MID) & 0x1bff; | 1107 | reg = ac97_read(codec, AC97_EXTENDED_MID) & 0x1bff; |
1108 | ac97_write(codec, AC97_EXTENDED_MID, reg); | 1108 | ac97_write(codec, AC97_EXTENDED_MID, reg); |
1109 | break; | 1109 | break; |
1110 | case SNDRV_CTL_POWER_D1: /* partial On */ | 1110 | case SND_SOC_BIAS_PREPARE: |
1111 | case SNDRV_CTL_POWER_D2: /* partial On */ | ||
1112 | break; | 1111 | break; |
1113 | case SNDRV_CTL_POWER_D3hot: /* Off, with power */ | 1112 | case SND_SOC_BIAS_STANDBY: |
1114 | /* enable master bias and vmid */ | 1113 | /* enable master bias and vmid */ |
1115 | reg = ac97_read(codec, AC97_EXTENDED_MID) & 0x3bff; | 1114 | reg = ac97_read(codec, AC97_EXTENDED_MID) & 0x3bff; |
1116 | ac97_write(codec, AC97_EXTENDED_MID, reg); | 1115 | ac97_write(codec, AC97_EXTENDED_MID, reg); |
1117 | ac97_write(codec, AC97_POWERDOWN, 0x0000); | 1116 | ac97_write(codec, AC97_POWERDOWN, 0x0000); |
1118 | break; | 1117 | break; |
1119 | case SNDRV_CTL_POWER_D3cold: /* Off, without power */ | 1118 | case SND_SOC_BIAS_OFF: |
1120 | /* disable everything including AC link */ | 1119 | /* disable everything including AC link */ |
1121 | ac97_write(codec, AC97_EXTENDED_MID, 0xffff); | 1120 | ac97_write(codec, AC97_EXTENDED_MID, 0xffff); |
1122 | ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff); | 1121 | ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff); |
1123 | ac97_write(codec, AC97_POWERDOWN, 0xffff); | 1122 | ac97_write(codec, AC97_POWERDOWN, 0xffff); |
1124 | break; | 1123 | break; |
1125 | } | 1124 | } |
1126 | codec->dapm_state = event; | 1125 | codec->bias_level = level; |
1127 | return 0; | 1126 | return 0; |
1128 | } | 1127 | } |
1129 | 1128 | ||
@@ -1160,7 +1159,7 @@ static int wm9713_soc_resume(struct platform_device *pdev) | |||
1160 | return ret; | 1159 | return ret; |
1161 | } | 1160 | } |
1162 | 1161 | ||
1163 | wm9713_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | 1162 | wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1164 | 1163 | ||
1165 | /* do we need to re-start the PLL ? */ | 1164 | /* do we need to re-start the PLL ? */ |
1166 | if (wm9713->pll_out) | 1165 | if (wm9713->pll_out) |
@@ -1176,8 +1175,8 @@ static int wm9713_soc_resume(struct platform_device *pdev) | |||
1176 | } | 1175 | } |
1177 | } | 1176 | } |
1178 | 1177 | ||
1179 | if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) | 1178 | if (codec->suspend_bias_level == SND_SOC_BIAS_ON) |
1180 | wm9713_dapm_event(codec, SNDRV_CTL_POWER_D0); | 1179 | wm9713_set_bias_level(codec, SND_SOC_BIAS_ON); |
1181 | 1180 | ||
1182 | return ret; | 1181 | return ret; |
1183 | } | 1182 | } |
@@ -1216,7 +1215,7 @@ static int wm9713_soc_probe(struct platform_device *pdev) | |||
1216 | codec->num_dai = ARRAY_SIZE(wm9713_dai); | 1215 | codec->num_dai = ARRAY_SIZE(wm9713_dai); |
1217 | codec->write = ac97_write; | 1216 | codec->write = ac97_write; |
1218 | codec->read = ac97_read; | 1217 | codec->read = ac97_read; |
1219 | codec->dapm_event = wm9713_dapm_event; | 1218 | codec->set_bias_level = wm9713_set_bias_level; |
1220 | INIT_LIST_HEAD(&codec->dapm_widgets); | 1219 | INIT_LIST_HEAD(&codec->dapm_widgets); |
1221 | INIT_LIST_HEAD(&codec->dapm_paths); | 1220 | INIT_LIST_HEAD(&codec->dapm_paths); |
1222 | 1221 | ||
@@ -1238,7 +1237,7 @@ static int wm9713_soc_probe(struct platform_device *pdev) | |||
1238 | goto reset_err; | 1237 | goto reset_err; |
1239 | } | 1238 | } |
1240 | 1239 | ||
1241 | wm9713_dapm_event(codec, SNDRV_CTL_POWER_D3hot); | 1240 | wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1242 | 1241 | ||
1243 | /* unmute the adc - move to kcontrol */ | 1242 | /* unmute the adc - move to kcontrol */ |
1244 | reg = ac97_read(codec, AC97_CD) & 0x7fff; | 1243 | reg = ac97_read(codec, AC97_CD) & 0x7fff; |
diff --git a/sound/soc/codecs/wm9713.h b/sound/soc/codecs/wm9713.h index d357b6c8134b..63b8d81756e3 100644 --- a/sound/soc/codecs/wm9713.h +++ b/sound/soc/codecs/wm9713.h | |||
@@ -46,7 +46,7 @@ | |||
46 | #define WM9713_DAI_PCM_VOICE 2 | 46 | #define WM9713_DAI_PCM_VOICE 2 |
47 | 47 | ||
48 | extern struct snd_soc_codec_device soc_codec_dev_wm9713; | 48 | extern struct snd_soc_codec_device soc_codec_dev_wm9713; |
49 | extern struct snd_soc_codec_dai wm9713_dai[3]; | 49 | extern struct snd_soc_dai wm9713_dai[3]; |
50 | 50 | ||
51 | int wm9713_reset(struct snd_soc_codec *codec, int try_warm); | 51 | int wm9713_reset(struct snd_soc_codec *codec, int try_warm); |
52 | 52 | ||
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig index 20680c551aab..8f7e33834902 100644 --- a/sound/soc/davinci/Kconfig +++ b/sound/soc/davinci/Kconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | config SND_DAVINCI_SOC | 1 | config SND_DAVINCI_SOC |
2 | tristate "SoC Audio for the TI DAVINCI chip" | 2 | tristate "SoC Audio for the TI DAVINCI chip" |
3 | depends on ARCH_DAVINCI && SND_SOC | 3 | depends on ARCH_DAVINCI |
4 | help | 4 | help |
5 | Say Y or M if you want to add support for codecs attached to | 5 | Say Y or M if you want to add support for codecs attached to |
6 | the DAVINCI AC97 or I2S interface. You will also need | 6 | the DAVINCI AC97 or I2S interface. You will also need |
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index fcd165240333..5e2c306399ed 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c | |||
@@ -33,24 +33,24 @@ static int evm_hw_params(struct snd_pcm_substream *substream, | |||
33 | struct snd_pcm_hw_params *params) | 33 | struct snd_pcm_hw_params *params) |
34 | { | 34 | { |
35 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 35 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
36 | struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; | 36 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
37 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 37 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
38 | int ret = 0; | 38 | int ret = 0; |
39 | 39 | ||
40 | /* set codec DAI configuration */ | 40 | /* set codec DAI configuration */ |
41 | ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | 41 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | |
42 | SND_SOC_DAIFMT_CBM_CFM); | 42 | SND_SOC_DAIFMT_CBM_CFM); |
43 | if (ret < 0) | 43 | if (ret < 0) |
44 | return ret; | 44 | return ret; |
45 | 45 | ||
46 | /* set cpu DAI configuration */ | 46 | /* set cpu DAI configuration */ |
47 | ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM | | 47 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM | |
48 | SND_SOC_DAIFMT_IB_NF); | 48 | SND_SOC_DAIFMT_IB_NF); |
49 | if (ret < 0) | 49 | if (ret < 0) |
50 | return ret; | 50 | return ret; |
51 | 51 | ||
52 | /* set the codec system clock */ | 52 | /* set the codec system clock */ |
53 | ret = codec_dai->dai_ops.set_sysclk(codec_dai, 0, EVM_CODEC_CLOCK, | 53 | ret = snd_soc_dai_set_sysclk(codec_dai, 0, EVM_CODEC_CLOCK, |
54 | SND_SOC_CLOCK_OUT); | 54 | SND_SOC_CLOCK_OUT); |
55 | if (ret < 0) | 55 | if (ret < 0) |
56 | return ret; | 56 | return ret; |
@@ -71,7 +71,7 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { | |||
71 | }; | 71 | }; |
72 | 72 | ||
73 | /* davinci-evm machine audio_mapnections to the codec pins */ | 73 | /* davinci-evm machine audio_mapnections to the codec pins */ |
74 | static const char *audio_map[][3] = { | 74 | static const struct snd_soc_dapm_route audio_map[] = { |
75 | /* Headphone connected to HPLOUT, HPROUT */ | 75 | /* Headphone connected to HPLOUT, HPROUT */ |
76 | {"Headphone Jack", NULL, "HPLOUT"}, | 76 | {"Headphone Jack", NULL, "HPLOUT"}, |
77 | {"Headphone Jack", NULL, "HPROUT"}, | 77 | {"Headphone Jack", NULL, "HPROUT"}, |
@@ -90,36 +90,30 @@ static const char *audio_map[][3] = { | |||
90 | {"LINE2L", NULL, "Line In"}, | 90 | {"LINE2L", NULL, "Line In"}, |
91 | {"LINE1R", NULL, "Line In"}, | 91 | {"LINE1R", NULL, "Line In"}, |
92 | {"LINE2R", NULL, "Line In"}, | 92 | {"LINE2R", NULL, "Line In"}, |
93 | |||
94 | {NULL, NULL, NULL}, | ||
95 | }; | 93 | }; |
96 | 94 | ||
97 | /* Logic for a aic3x as connected on a davinci-evm */ | 95 | /* Logic for a aic3x as connected on a davinci-evm */ |
98 | static int evm_aic3x_init(struct snd_soc_codec *codec) | 96 | static int evm_aic3x_init(struct snd_soc_codec *codec) |
99 | { | 97 | { |
100 | int i; | ||
101 | |||
102 | /* Add davinci-evm specific widgets */ | 98 | /* Add davinci-evm specific widgets */ |
103 | for (i = 0; i < ARRAY_SIZE(aic3x_dapm_widgets); i++) | 99 | snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets, |
104 | snd_soc_dapm_new_control(codec, &aic3x_dapm_widgets[i]); | 100 | ARRAY_SIZE(aic3x_dapm_widgets)); |
105 | 101 | ||
106 | /* Set up davinci-evm specific audio path audio_map */ | 102 | /* Set up davinci-evm specific audio path audio_map */ |
107 | for (i = 0; audio_map[i][0] != NULL; i++) | 103 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
108 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | ||
109 | audio_map[i][1], audio_map[i][2]); | ||
110 | 104 | ||
111 | /* not connected */ | 105 | /* not connected */ |
112 | snd_soc_dapm_set_endpoint(codec, "MONO_LOUT", 0); | 106 | snd_soc_dapm_disable_pin(codec, "MONO_LOUT"); |
113 | snd_soc_dapm_set_endpoint(codec, "HPLCOM", 0); | 107 | snd_soc_dapm_disable_pin(codec, "HPLCOM"); |
114 | snd_soc_dapm_set_endpoint(codec, "HPRCOM", 0); | 108 | snd_soc_dapm_disable_pin(codec, "HPRCOM"); |
115 | 109 | ||
116 | /* always connected */ | 110 | /* always connected */ |
117 | snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 1); | 111 | snd_soc_dapm_enable_pin(codec, "Headphone Jack"); |
118 | snd_soc_dapm_set_endpoint(codec, "Line Out", 1); | 112 | snd_soc_dapm_enable_pin(codec, "Line Out"); |
119 | snd_soc_dapm_set_endpoint(codec, "Mic Jack", 1); | 113 | snd_soc_dapm_enable_pin(codec, "Mic Jack"); |
120 | snd_soc_dapm_set_endpoint(codec, "Line In", 1); | 114 | snd_soc_dapm_enable_pin(codec, "Line In"); |
121 | 115 | ||
122 | snd_soc_dapm_sync_endpoints(codec); | 116 | snd_soc_dapm_sync(codec); |
123 | 117 | ||
124 | return 0; | 118 | return 0; |
125 | } | 119 | } |
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index c421774b33ee..5ebf1ff71c4c 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c | |||
@@ -147,7 +147,7 @@ static void davinci_mcbsp_stop(struct snd_pcm_substream *substream) | |||
147 | static int davinci_i2s_startup(struct snd_pcm_substream *substream) | 147 | static int davinci_i2s_startup(struct snd_pcm_substream *substream) |
148 | { | 148 | { |
149 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 149 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
150 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 150 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
151 | struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; | 151 | struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; |
152 | 152 | ||
153 | cpu_dai->dma_data = dev->dma_params[substream->stream]; | 153 | cpu_dai->dma_data = dev->dma_params[substream->stream]; |
@@ -155,7 +155,7 @@ static int davinci_i2s_startup(struct snd_pcm_substream *substream) | |||
155 | return 0; | 155 | return 0; |
156 | } | 156 | } |
157 | 157 | ||
158 | static int davinci_i2s_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai, | 158 | static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, |
159 | unsigned int fmt) | 159 | unsigned int fmt) |
160 | { | 160 | { |
161 | struct davinci_mcbsp_dev *dev = cpu_dai->private_data; | 161 | struct davinci_mcbsp_dev *dev = cpu_dai->private_data; |
@@ -295,11 +295,12 @@ static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd) | |||
295 | return ret; | 295 | return ret; |
296 | } | 296 | } |
297 | 297 | ||
298 | static int davinci_i2s_probe(struct platform_device *pdev) | 298 | static int davinci_i2s_probe(struct platform_device *pdev, |
299 | struct snd_soc_dai *dai) | ||
299 | { | 300 | { |
300 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 301 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
301 | struct snd_soc_machine *machine = socdev->machine; | 302 | struct snd_soc_machine *machine = socdev->machine; |
302 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai; | 303 | struct snd_soc_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai; |
303 | struct davinci_mcbsp_dev *dev; | 304 | struct davinci_mcbsp_dev *dev; |
304 | struct resource *mem, *ioarea; | 305 | struct resource *mem, *ioarea; |
305 | struct evm_snd_platform_data *pdata; | 306 | struct evm_snd_platform_data *pdata; |
@@ -356,11 +357,12 @@ err_release_region: | |||
356 | return ret; | 357 | return ret; |
357 | } | 358 | } |
358 | 359 | ||
359 | static void davinci_i2s_remove(struct platform_device *pdev) | 360 | static void davinci_i2s_remove(struct platform_device *pdev, |
361 | struct snd_soc_dai *dai) | ||
360 | { | 362 | { |
361 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 363 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
362 | struct snd_soc_machine *machine = socdev->machine; | 364 | struct snd_soc_machine *machine = socdev->machine; |
363 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai; | 365 | struct snd_soc_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai; |
364 | struct davinci_mcbsp_dev *dev = cpu_dai->private_data; | 366 | struct davinci_mcbsp_dev *dev = cpu_dai->private_data; |
365 | struct resource *mem; | 367 | struct resource *mem; |
366 | 368 | ||
@@ -376,7 +378,7 @@ static void davinci_i2s_remove(struct platform_device *pdev) | |||
376 | 378 | ||
377 | #define DAVINCI_I2S_RATES SNDRV_PCM_RATE_8000_96000 | 379 | #define DAVINCI_I2S_RATES SNDRV_PCM_RATE_8000_96000 |
378 | 380 | ||
379 | struct snd_soc_cpu_dai davinci_i2s_dai = { | 381 | struct snd_soc_dai davinci_i2s_dai = { |
380 | .name = "davinci-i2s", | 382 | .name = "davinci-i2s", |
381 | .id = 0, | 383 | .id = 0, |
382 | .type = SND_SOC_DAI_I2S, | 384 | .type = SND_SOC_DAI_I2S, |
diff --git a/sound/soc/davinci/davinci-i2s.h b/sound/soc/davinci/davinci-i2s.h index 9592d17db320..c5b091807eec 100644 --- a/sound/soc/davinci/davinci-i2s.h +++ b/sound/soc/davinci/davinci-i2s.h | |||
@@ -12,6 +12,6 @@ | |||
12 | #ifndef _DAVINCI_I2S_H | 12 | #ifndef _DAVINCI_I2S_H |
13 | #define _DAVINCI_I2S_H | 13 | #define _DAVINCI_I2S_H |
14 | 14 | ||
15 | extern struct snd_soc_cpu_dai davinci_i2s_dai; | 15 | extern struct snd_soc_dai davinci_i2s_dai; |
16 | 16 | ||
17 | #endif | 17 | #endif |
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index 6a76927c9971..6a5e56a782bb 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c | |||
@@ -350,7 +350,7 @@ static void davinci_pcm_free(struct snd_pcm *pcm) | |||
350 | static u64 davinci_pcm_dmamask = 0xffffffff; | 350 | static u64 davinci_pcm_dmamask = 0xffffffff; |
351 | 351 | ||
352 | static int davinci_pcm_new(struct snd_card *card, | 352 | static int davinci_pcm_new(struct snd_card *card, |
353 | struct snd_soc_codec_dai *dai, struct snd_pcm *pcm) | 353 | struct snd_soc_dai *dai, struct snd_pcm *pcm) |
354 | { | 354 | { |
355 | int ret; | 355 | int ret; |
356 | 356 | ||
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 257101f44e9e..3368ace60977 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig | |||
@@ -1,8 +1,6 @@ | |||
1 | menu "ALSA SoC audio for Freescale SOCs" | ||
2 | |||
3 | config SND_SOC_MPC8610 | 1 | config SND_SOC_MPC8610 |
4 | bool "ALSA SoC support for the MPC8610 SOC" | 2 | bool "ALSA SoC support for the MPC8610 SOC" |
5 | depends on SND_SOC && MPC8610_HPCD | 3 | depends on MPC8610_HPCD |
6 | default y if MPC8610 | 4 | default y if MPC8610 |
7 | help | 5 | help |
8 | Say Y if you want to add support for codecs attached to the SSI | 6 | Say Y if you want to add support for codecs attached to the SSI |
@@ -16,5 +14,3 @@ config SND_SOC_MPC8610_HPCD | |||
16 | default y if MPC8610_HPCD | 14 | default y if MPC8610_HPCD |
17 | help | 15 | help |
18 | Say Y if you want to enable audio on the Freescale MPC8610 HPCD. | 16 | Say Y if you want to enable audio on the Freescale MPC8610 HPCD. |
19 | |||
20 | endmenu | ||
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index 78de7168d2ba..da2bc5902864 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c | |||
@@ -282,7 +282,7 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id) | |||
282 | * once for each .dai_link in the machine driver's snd_soc_machine | 282 | * once for each .dai_link in the machine driver's snd_soc_machine |
283 | * structure. | 283 | * structure. |
284 | */ | 284 | */ |
285 | static int fsl_dma_new(struct snd_card *card, struct snd_soc_codec_dai *dai, | 285 | static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai, |
286 | struct snd_pcm *pcm) | 286 | struct snd_pcm *pcm) |
287 | { | 287 | { |
288 | static u64 fsl_dma_dmamask = DMA_BIT_MASK(32); | 288 | static u64 fsl_dma_dmamask = DMA_BIT_MASK(32); |
diff --git a/sound/soc/fsl/fsl_dma.h b/sound/soc/fsl/fsl_dma.h index 430a6ce8b0d0..385d4a42603c 100644 --- a/sound/soc/fsl/fsl_dma.h +++ b/sound/soc/fsl/fsl_dma.h | |||
@@ -126,7 +126,7 @@ struct fsl_dma_link_descriptor { | |||
126 | u8 res[4]; /* Reserved */ | 126 | u8 res[4]; /* Reserved */ |
127 | } __attribute__ ((aligned(32), packed)); | 127 | } __attribute__ ((aligned(32), packed)); |
128 | 128 | ||
129 | /* DMA information needed to create a snd_soc_cpu_dai object | 129 | /* DMA information needed to create a snd_soc_dai object |
130 | * | 130 | * |
131 | * ssi_stx_phys: bus address of SSI STX register to use | 131 | * ssi_stx_phys: bus address of SSI STX register to use |
132 | * ssi_srx_phys: bus address of SSI SRX register to use | 132 | * ssi_srx_phys: bus address of SSI SRX register to use |
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index f588545698f3..71bff33f5528 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c | |||
@@ -82,7 +82,7 @@ struct fsl_ssi_private { | |||
82 | struct device *dev; | 82 | struct device *dev; |
83 | unsigned int playback; | 83 | unsigned int playback; |
84 | unsigned int capture; | 84 | unsigned int capture; |
85 | struct snd_soc_cpu_dai cpu_dai; | 85 | struct snd_soc_dai cpu_dai; |
86 | struct device_attribute dev_attr; | 86 | struct device_attribute dev_attr; |
87 | 87 | ||
88 | struct { | 88 | struct { |
@@ -479,7 +479,7 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream) | |||
479 | * @freq: the frequency of the given clock ID, currently ignored | 479 | * @freq: the frequency of the given clock ID, currently ignored |
480 | * @dir: SND_SOC_CLOCK_IN (clock slave) or SND_SOC_CLOCK_OUT (clock master) | 480 | * @dir: SND_SOC_CLOCK_IN (clock slave) or SND_SOC_CLOCK_OUT (clock master) |
481 | */ | 481 | */ |
482 | static int fsl_ssi_set_sysclk(struct snd_soc_cpu_dai *cpu_dai, | 482 | static int fsl_ssi_set_sysclk(struct snd_soc_dai *cpu_dai, |
483 | int clk_id, unsigned int freq, int dir) | 483 | int clk_id, unsigned int freq, int dir) |
484 | { | 484 | { |
485 | 485 | ||
@@ -497,7 +497,7 @@ static int fsl_ssi_set_sysclk(struct snd_soc_cpu_dai *cpu_dai, | |||
497 | * | 497 | * |
498 | * @format: one of SND_SOC_DAIFMT_xxx | 498 | * @format: one of SND_SOC_DAIFMT_xxx |
499 | */ | 499 | */ |
500 | static int fsl_ssi_set_fmt(struct snd_soc_cpu_dai *cpu_dai, unsigned int format) | 500 | static int fsl_ssi_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format) |
501 | { | 501 | { |
502 | return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL; | 502 | return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL; |
503 | } | 503 | } |
@@ -505,7 +505,7 @@ static int fsl_ssi_set_fmt(struct snd_soc_cpu_dai *cpu_dai, unsigned int format) | |||
505 | /** | 505 | /** |
506 | * fsl_ssi_dai_template: template CPU DAI for the SSI | 506 | * fsl_ssi_dai_template: template CPU DAI for the SSI |
507 | */ | 507 | */ |
508 | static struct snd_soc_cpu_dai fsl_ssi_dai_template = { | 508 | static struct snd_soc_dai fsl_ssi_dai_template = { |
509 | .playback = { | 509 | .playback = { |
510 | /* The SSI does not support monaural audio. */ | 510 | /* The SSI does not support monaural audio. */ |
511 | .channels_min = 2, | 511 | .channels_min = 2, |
@@ -569,15 +569,15 @@ static ssize_t fsl_sysfs_ssi_show(struct device *dev, | |||
569 | } | 569 | } |
570 | 570 | ||
571 | /** | 571 | /** |
572 | * fsl_ssi_create_dai: create a snd_soc_cpu_dai structure | 572 | * fsl_ssi_create_dai: create a snd_soc_dai structure |
573 | * | 573 | * |
574 | * This function is called by the machine driver to create a snd_soc_cpu_dai | 574 | * This function is called by the machine driver to create a snd_soc_dai |
575 | * structure. The function creates an ssi_private object, which contains | 575 | * structure. The function creates an ssi_private object, which contains |
576 | * the snd_soc_cpu_dai. It also creates the sysfs statistics device. | 576 | * the snd_soc_dai. It also creates the sysfs statistics device. |
577 | */ | 577 | */ |
578 | struct snd_soc_cpu_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info) | 578 | struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info) |
579 | { | 579 | { |
580 | struct snd_soc_cpu_dai *fsl_ssi_dai; | 580 | struct snd_soc_dai *fsl_ssi_dai; |
581 | struct fsl_ssi_private *ssi_private; | 581 | struct fsl_ssi_private *ssi_private; |
582 | int ret = 0; | 582 | int ret = 0; |
583 | struct device_attribute *dev_attr; | 583 | struct device_attribute *dev_attr; |
@@ -588,7 +588,7 @@ struct snd_soc_cpu_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info) | |||
588 | return NULL; | 588 | return NULL; |
589 | } | 589 | } |
590 | memcpy(&ssi_private->cpu_dai, &fsl_ssi_dai_template, | 590 | memcpy(&ssi_private->cpu_dai, &fsl_ssi_dai_template, |
591 | sizeof(struct snd_soc_cpu_dai)); | 591 | sizeof(struct snd_soc_dai)); |
592 | 592 | ||
593 | fsl_ssi_dai = &ssi_private->cpu_dai; | 593 | fsl_ssi_dai = &ssi_private->cpu_dai; |
594 | dev_attr = &ssi_private->dev_attr; | 594 | dev_attr = &ssi_private->dev_attr; |
@@ -623,11 +623,11 @@ struct snd_soc_cpu_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info) | |||
623 | EXPORT_SYMBOL_GPL(fsl_ssi_create_dai); | 623 | EXPORT_SYMBOL_GPL(fsl_ssi_create_dai); |
624 | 624 | ||
625 | /** | 625 | /** |
626 | * fsl_ssi_destroy_dai: destroy the snd_soc_cpu_dai object | 626 | * fsl_ssi_destroy_dai: destroy the snd_soc_dai object |
627 | * | 627 | * |
628 | * This function undoes the operations of fsl_ssi_create_dai() | 628 | * This function undoes the operations of fsl_ssi_create_dai() |
629 | */ | 629 | */ |
630 | void fsl_ssi_destroy_dai(struct snd_soc_cpu_dai *fsl_ssi_dai) | 630 | void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai) |
631 | { | 631 | { |
632 | struct fsl_ssi_private *ssi_private = | 632 | struct fsl_ssi_private *ssi_private = |
633 | container_of(fsl_ssi_dai, struct fsl_ssi_private, cpu_dai); | 633 | container_of(fsl_ssi_dai, struct fsl_ssi_private, cpu_dai); |
diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h index c5ce88e15651..83b44d700e33 100644 --- a/sound/soc/fsl/fsl_ssi.h +++ b/sound/soc/fsl/fsl_ssi.h | |||
@@ -217,8 +217,8 @@ struct fsl_ssi_info { | |||
217 | struct device *dev; | 217 | struct device *dev; |
218 | }; | 218 | }; |
219 | 219 | ||
220 | struct snd_soc_cpu_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info); | 220 | struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info); |
221 | void fsl_ssi_destroy_dai(struct snd_soc_cpu_dai *fsl_ssi_dai); | 221 | void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai); |
222 | 222 | ||
223 | #endif | 223 | #endif |
224 | 224 | ||
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c index a00aac7a71f1..4bdc9d8fc90e 100644 --- a/sound/soc/fsl/mpc8610_hpcd.c +++ b/sound/soc/fsl/mpc8610_hpcd.c | |||
@@ -58,9 +58,9 @@ static int mpc8610_hpcd_machine_probe(struct platform_device *sound_device) | |||
58 | sound_device->dev.platform_data; | 58 | sound_device->dev.platform_data; |
59 | 59 | ||
60 | /* Program the signal routing between the SSI and the DMA */ | 60 | /* Program the signal routing between the SSI and the DMA */ |
61 | guts_set_dmacr(machine_data->guts, machine_data->dma_id + 1, | 61 | guts_set_dmacr(machine_data->guts, machine_data->dma_id, |
62 | machine_data->dma_channel_id[0], CCSR_GUTS_DMACR_DEV_SSI); | 62 | machine_data->dma_channel_id[0], CCSR_GUTS_DMACR_DEV_SSI); |
63 | guts_set_dmacr(machine_data->guts, machine_data->dma_id + 1, | 63 | guts_set_dmacr(machine_data->guts, machine_data->dma_id, |
64 | machine_data->dma_channel_id[1], CCSR_GUTS_DMACR_DEV_SSI); | 64 | machine_data->dma_channel_id[1], CCSR_GUTS_DMACR_DEV_SSI); |
65 | 65 | ||
66 | guts_set_pmuxcr_dma(machine_data->guts, machine_data->dma_id, | 66 | guts_set_pmuxcr_dma(machine_data->guts, machine_data->dma_id, |
@@ -96,62 +96,52 @@ static int mpc8610_hpcd_machine_probe(struct platform_device *sound_device) | |||
96 | static int mpc8610_hpcd_startup(struct snd_pcm_substream *substream) | 96 | static int mpc8610_hpcd_startup(struct snd_pcm_substream *substream) |
97 | { | 97 | { |
98 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 98 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
99 | struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; | 99 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
100 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 100 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
101 | struct mpc8610_hpcd_data *machine_data = | 101 | struct mpc8610_hpcd_data *machine_data = |
102 | rtd->socdev->dev->platform_data; | 102 | rtd->socdev->dev->platform_data; |
103 | int ret = 0; | 103 | int ret = 0; |
104 | 104 | ||
105 | /* Tell the CPU driver what the serial protocol is. */ | 105 | /* Tell the CPU driver what the serial protocol is. */ |
106 | if (cpu_dai->dai_ops.set_fmt) { | 106 | ret = snd_soc_dai_set_fmt(cpu_dai, machine_data->dai_format); |
107 | ret = cpu_dai->dai_ops.set_fmt(cpu_dai, | 107 | if (ret < 0) { |
108 | machine_data->dai_format); | 108 | dev_err(substream->pcm->card->dev, |
109 | if (ret < 0) { | 109 | "could not set CPU driver audio format\n"); |
110 | dev_err(substream->pcm->card->dev, | 110 | return ret; |
111 | "could not set CPU driver audio format\n"); | ||
112 | return ret; | ||
113 | } | ||
114 | } | 111 | } |
115 | 112 | ||
116 | /* Tell the codec driver what the serial protocol is. */ | 113 | /* Tell the codec driver what the serial protocol is. */ |
117 | if (codec_dai->dai_ops.set_fmt) { | 114 | ret = snd_soc_dai_set_fmt(codec_dai, machine_data->dai_format); |
118 | ret = codec_dai->dai_ops.set_fmt(codec_dai, | 115 | if (ret < 0) { |
119 | machine_data->dai_format); | 116 | dev_err(substream->pcm->card->dev, |
120 | if (ret < 0) { | 117 | "could not set codec driver audio format\n"); |
121 | dev_err(substream->pcm->card->dev, | 118 | return ret; |
122 | "could not set codec driver audio format\n"); | ||
123 | return ret; | ||
124 | } | ||
125 | } | 119 | } |
126 | 120 | ||
127 | /* | 121 | /* |
128 | * Tell the CPU driver what the clock frequency is, and whether it's a | 122 | * Tell the CPU driver what the clock frequency is, and whether it's a |
129 | * slave or master. | 123 | * slave or master. |
130 | */ | 124 | */ |
131 | if (cpu_dai->dai_ops.set_sysclk) { | 125 | ret = snd_soc_dai_set_sysclk(cpu_dai, 0, |
132 | ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, 0, | 126 | machine_data->clk_frequency, |
133 | machine_data->clk_frequency, | 127 | machine_data->cpu_clk_direction); |
134 | machine_data->cpu_clk_direction); | 128 | if (ret < 0) { |
135 | if (ret < 0) { | 129 | dev_err(substream->pcm->card->dev, |
136 | dev_err(substream->pcm->card->dev, | 130 | "could not set CPU driver clock parameters\n"); |
137 | "could not set CPU driver clock parameters\n"); | 131 | return ret; |
138 | return ret; | ||
139 | } | ||
140 | } | 132 | } |
141 | 133 | ||
142 | /* | 134 | /* |
143 | * Tell the codec driver what the MCLK frequency is, and whether it's | 135 | * Tell the codec driver what the MCLK frequency is, and whether it's |
144 | * a slave or master. | 136 | * a slave or master. |
145 | */ | 137 | */ |
146 | if (codec_dai->dai_ops.set_sysclk) { | 138 | ret = snd_soc_dai_set_sysclk(codec_dai, 0, |
147 | ret = codec_dai->dai_ops.set_sysclk(codec_dai, 0, | 139 | machine_data->clk_frequency, |
148 | machine_data->clk_frequency, | 140 | machine_data->codec_clk_direction); |
149 | machine_data->codec_clk_direction); | 141 | if (ret < 0) { |
150 | if (ret < 0) { | 142 | dev_err(substream->pcm->card->dev, |
151 | dev_err(substream->pcm->card->dev, | 143 | "could not set codec driver clock params\n"); |
152 | "could not set codec driver clock params\n"); | 144 | return ret; |
153 | return ret; | ||
154 | } | ||
155 | } | 145 | } |
156 | 146 | ||
157 | return 0; | 147 | return 0; |
@@ -170,9 +160,9 @@ int mpc8610_hpcd_machine_remove(struct platform_device *sound_device) | |||
170 | 160 | ||
171 | /* Restore the signal routing */ | 161 | /* Restore the signal routing */ |
172 | 162 | ||
173 | guts_set_dmacr(machine_data->guts, machine_data->dma_id + 1, | 163 | guts_set_dmacr(machine_data->guts, machine_data->dma_id, |
174 | machine_data->dma_channel_id[0], 0); | 164 | machine_data->dma_channel_id[0], 0); |
175 | guts_set_dmacr(machine_data->guts, machine_data->dma_id + 1, | 165 | guts_set_dmacr(machine_data->guts, machine_data->dma_id, |
176 | machine_data->dma_channel_id[1], 0); | 166 | machine_data->dma_channel_id[1], 0); |
177 | 167 | ||
178 | switch (machine_data->ssi_id) { | 168 | switch (machine_data->ssi_id) { |
@@ -182,7 +172,7 @@ int mpc8610_hpcd_machine_remove(struct platform_device *sound_device) | |||
182 | break; | 172 | break; |
183 | case 1: | 173 | case 1: |
184 | clrsetbits_be32(&machine_data->guts->pmuxcr, | 174 | clrsetbits_be32(&machine_data->guts->pmuxcr, |
185 | CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI1_LA); | 175 | CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI2_LA); |
186 | break; | 176 | break; |
187 | } | 177 | } |
188 | 178 | ||
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 0230d83e8e5e..aea27e70043c 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig | |||
@@ -1,5 +1,3 @@ | |||
1 | menu "SoC Audio for the Texas Instruments OMAP" | ||
2 | |||
3 | config SND_OMAP_SOC | 1 | config SND_OMAP_SOC |
4 | tristate "SoC Audio for the Texas Instruments OMAP chips" | 2 | tristate "SoC Audio for the Texas Instruments OMAP chips" |
5 | depends on ARCH_OMAP && SND_SOC | 3 | depends on ARCH_OMAP && SND_SOC |
@@ -15,5 +13,3 @@ config SND_OMAP_SOC_N810 | |||
15 | select SND_SOC_TLV320AIC3X | 13 | select SND_SOC_TLV320AIC3X |
16 | help | 14 | help |
17 | Say Y if you want to add support for SoC audio on Nokia N810. | 15 | Say Y if you want to add support for SoC audio on Nokia N810. |
18 | |||
19 | endmenu | ||
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c index 6533563a6011..02cec96859b8 100644 --- a/sound/soc/omap/n810.c +++ b/sound/soc/omap/n810.c | |||
@@ -30,15 +30,15 @@ | |||
30 | 30 | ||
31 | #include <asm/mach-types.h> | 31 | #include <asm/mach-types.h> |
32 | #include <asm/arch/hardware.h> | 32 | #include <asm/arch/hardware.h> |
33 | #include <asm/arch/gpio.h> | 33 | #include <linux/gpio.h> |
34 | #include <asm/arch/mcbsp.h> | 34 | #include <asm/arch/mcbsp.h> |
35 | 35 | ||
36 | #include "omap-mcbsp.h" | 36 | #include "omap-mcbsp.h" |
37 | #include "omap-pcm.h" | 37 | #include "omap-pcm.h" |
38 | #include "../codecs/tlv320aic3x.h" | 38 | #include "../codecs/tlv320aic3x.h" |
39 | 39 | ||
40 | #define RX44_HEADSET_AMP_GPIO 10 | 40 | #define N810_HEADSET_AMP_GPIO 10 |
41 | #define RX44_SPEAKER_AMP_GPIO 101 | 41 | #define N810_SPEAKER_AMP_GPIO 101 |
42 | 42 | ||
43 | static struct clk *sys_clkout2; | 43 | static struct clk *sys_clkout2; |
44 | static struct clk *sys_clkout2_src; | 44 | static struct clk *sys_clkout2_src; |
@@ -46,13 +46,26 @@ static struct clk *func96m_clk; | |||
46 | 46 | ||
47 | static int n810_spk_func; | 47 | static int n810_spk_func; |
48 | static int n810_jack_func; | 48 | static int n810_jack_func; |
49 | static int n810_dmic_func; | ||
49 | 50 | ||
50 | static void n810_ext_control(struct snd_soc_codec *codec) | 51 | static void n810_ext_control(struct snd_soc_codec *codec) |
51 | { | 52 | { |
52 | snd_soc_dapm_set_endpoint(codec, "Ext Spk", n810_spk_func); | 53 | if (n810_spk_func) |
53 | snd_soc_dapm_set_endpoint(codec, "Headphone Jack", n810_jack_func); | 54 | snd_soc_dapm_enable_pin(codec, "Ext Spk"); |
55 | else | ||
56 | snd_soc_dapm_disable_pin(codec, "Ext Spk"); | ||
57 | |||
58 | if (n810_jack_func) | ||
59 | snd_soc_dapm_enable_pin(codec, "Headphone Jack"); | ||
60 | else | ||
61 | snd_soc_dapm_disable_pin(codec, "Headphone Jack"); | ||
54 | 62 | ||
55 | snd_soc_dapm_sync_endpoints(codec); | 63 | if (n810_dmic_func) |
64 | snd_soc_dapm_enable_pin(codec, "DMic"); | ||
65 | else | ||
66 | snd_soc_dapm_disable_pin(codec, "DMic"); | ||
67 | |||
68 | snd_soc_dapm_sync(codec); | ||
56 | } | 69 | } |
57 | 70 | ||
58 | static int n810_startup(struct snd_pcm_substream *substream) | 71 | static int n810_startup(struct snd_pcm_substream *substream) |
@@ -73,12 +86,12 @@ static int n810_hw_params(struct snd_pcm_substream *substream, | |||
73 | struct snd_pcm_hw_params *params) | 86 | struct snd_pcm_hw_params *params) |
74 | { | 87 | { |
75 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 88 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
76 | struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; | 89 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
77 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 90 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
78 | int err; | 91 | int err; |
79 | 92 | ||
80 | /* Set codec DAI configuration */ | 93 | /* Set codec DAI configuration */ |
81 | err = codec_dai->dai_ops.set_fmt(codec_dai, | 94 | err = snd_soc_dai_set_fmt(codec_dai, |
82 | SND_SOC_DAIFMT_I2S | | 95 | SND_SOC_DAIFMT_I2S | |
83 | SND_SOC_DAIFMT_NB_NF | | 96 | SND_SOC_DAIFMT_NB_NF | |
84 | SND_SOC_DAIFMT_CBM_CFM); | 97 | SND_SOC_DAIFMT_CBM_CFM); |
@@ -86,7 +99,7 @@ static int n810_hw_params(struct snd_pcm_substream *substream, | |||
86 | return err; | 99 | return err; |
87 | 100 | ||
88 | /* Set cpu DAI configuration */ | 101 | /* Set cpu DAI configuration */ |
89 | err = cpu_dai->dai_ops.set_fmt(cpu_dai, | 102 | err = snd_soc_dai_set_fmt(cpu_dai, |
90 | SND_SOC_DAIFMT_I2S | | 103 | SND_SOC_DAIFMT_I2S | |
91 | SND_SOC_DAIFMT_NB_NF | | 104 | SND_SOC_DAIFMT_NB_NF | |
92 | SND_SOC_DAIFMT_CBM_CFM); | 105 | SND_SOC_DAIFMT_CBM_CFM); |
@@ -94,7 +107,7 @@ static int n810_hw_params(struct snd_pcm_substream *substream, | |||
94 | return err; | 107 | return err; |
95 | 108 | ||
96 | /* Set the codec system clock for DAC and ADC */ | 109 | /* Set the codec system clock for DAC and ADC */ |
97 | err = codec_dai->dai_ops.set_sysclk(codec_dai, 0, 12000000, | 110 | err = snd_soc_dai_set_sysclk(codec_dai, 0, 12000000, |
98 | SND_SOC_CLOCK_IN); | 111 | SND_SOC_CLOCK_IN); |
99 | 112 | ||
100 | return err; | 113 | return err; |
@@ -150,13 +163,35 @@ static int n810_set_jack(struct snd_kcontrol *kcontrol, | |||
150 | return 1; | 163 | return 1; |
151 | } | 164 | } |
152 | 165 | ||
166 | static int n810_get_input(struct snd_kcontrol *kcontrol, | ||
167 | struct snd_ctl_elem_value *ucontrol) | ||
168 | { | ||
169 | ucontrol->value.integer.value[0] = n810_dmic_func; | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | static int n810_set_input(struct snd_kcontrol *kcontrol, | ||
175 | struct snd_ctl_elem_value *ucontrol) | ||
176 | { | ||
177 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
178 | |||
179 | if (n810_dmic_func == ucontrol->value.integer.value[0]) | ||
180 | return 0; | ||
181 | |||
182 | n810_dmic_func = ucontrol->value.integer.value[0]; | ||
183 | n810_ext_control(codec); | ||
184 | |||
185 | return 1; | ||
186 | } | ||
187 | |||
153 | static int n810_spk_event(struct snd_soc_dapm_widget *w, | 188 | static int n810_spk_event(struct snd_soc_dapm_widget *w, |
154 | struct snd_kcontrol *k, int event) | 189 | struct snd_kcontrol *k, int event) |
155 | { | 190 | { |
156 | if (SND_SOC_DAPM_EVENT_ON(event)) | 191 | if (SND_SOC_DAPM_EVENT_ON(event)) |
157 | omap_set_gpio_dataout(RX44_SPEAKER_AMP_GPIO, 1); | 192 | gpio_set_value(N810_SPEAKER_AMP_GPIO, 1); |
158 | else | 193 | else |
159 | omap_set_gpio_dataout(RX44_SPEAKER_AMP_GPIO, 0); | 194 | gpio_set_value(N810_SPEAKER_AMP_GPIO, 0); |
160 | 195 | ||
161 | return 0; | 196 | return 0; |
162 | } | 197 | } |
@@ -165,9 +200,9 @@ static int n810_jack_event(struct snd_soc_dapm_widget *w, | |||
165 | struct snd_kcontrol *k, int event) | 200 | struct snd_kcontrol *k, int event) |
166 | { | 201 | { |
167 | if (SND_SOC_DAPM_EVENT_ON(event)) | 202 | if (SND_SOC_DAPM_EVENT_ON(event)) |
168 | omap_set_gpio_dataout(RX44_HEADSET_AMP_GPIO, 1); | 203 | gpio_set_value(N810_HEADSET_AMP_GPIO, 1); |
169 | else | 204 | else |
170 | omap_set_gpio_dataout(RX44_HEADSET_AMP_GPIO, 0); | 205 | gpio_set_value(N810_HEADSET_AMP_GPIO, 0); |
171 | 206 | ||
172 | return 0; | 207 | return 0; |
173 | } | 208 | } |
@@ -175,21 +210,27 @@ static int n810_jack_event(struct snd_soc_dapm_widget *w, | |||
175 | static const struct snd_soc_dapm_widget aic33_dapm_widgets[] = { | 210 | static const struct snd_soc_dapm_widget aic33_dapm_widgets[] = { |
176 | SND_SOC_DAPM_SPK("Ext Spk", n810_spk_event), | 211 | SND_SOC_DAPM_SPK("Ext Spk", n810_spk_event), |
177 | SND_SOC_DAPM_HP("Headphone Jack", n810_jack_event), | 212 | SND_SOC_DAPM_HP("Headphone Jack", n810_jack_event), |
213 | SND_SOC_DAPM_MIC("DMic", NULL), | ||
178 | }; | 214 | }; |
179 | 215 | ||
180 | static const char *audio_map[][3] = { | 216 | static const struct snd_soc_dapm_route audio_map[] = { |
181 | {"Headphone Jack", NULL, "HPLOUT"}, | 217 | {"Headphone Jack", NULL, "HPLOUT"}, |
182 | {"Headphone Jack", NULL, "HPROUT"}, | 218 | {"Headphone Jack", NULL, "HPROUT"}, |
183 | 219 | ||
184 | {"Ext Spk", NULL, "LLOUT"}, | 220 | {"Ext Spk", NULL, "LLOUT"}, |
185 | {"Ext Spk", NULL, "RLOUT"}, | 221 | {"Ext Spk", NULL, "RLOUT"}, |
222 | |||
223 | {"DMic Rate 64", NULL, "Mic Bias 2V"}, | ||
224 | {"Mic Bias 2V", NULL, "DMic"}, | ||
186 | }; | 225 | }; |
187 | 226 | ||
188 | static const char *spk_function[] = {"Off", "On"}; | 227 | static const char *spk_function[] = {"Off", "On"}; |
189 | static const char *jack_function[] = {"Off", "Headphone"}; | 228 | static const char *jack_function[] = {"Off", "Headphone"}; |
229 | static const char *input_function[] = {"ADC", "Digital Mic"}; | ||
190 | static const struct soc_enum n810_enum[] = { | 230 | static const struct soc_enum n810_enum[] = { |
191 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function), | 231 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function), |
192 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function), | 232 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function), |
233 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function), | ||
193 | }; | 234 | }; |
194 | 235 | ||
195 | static const struct snd_kcontrol_new aic33_n810_controls[] = { | 236 | static const struct snd_kcontrol_new aic33_n810_controls[] = { |
@@ -197,6 +238,8 @@ static const struct snd_kcontrol_new aic33_n810_controls[] = { | |||
197 | n810_get_spk, n810_set_spk), | 238 | n810_get_spk, n810_set_spk), |
198 | SOC_ENUM_EXT("Jack Function", n810_enum[1], | 239 | SOC_ENUM_EXT("Jack Function", n810_enum[1], |
199 | n810_get_jack, n810_set_jack), | 240 | n810_get_jack, n810_set_jack), |
241 | SOC_ENUM_EXT("Input Select", n810_enum[2], | ||
242 | n810_get_input, n810_set_input), | ||
200 | }; | 243 | }; |
201 | 244 | ||
202 | static int n810_aic33_init(struct snd_soc_codec *codec) | 245 | static int n810_aic33_init(struct snd_soc_codec *codec) |
@@ -204,9 +247,9 @@ static int n810_aic33_init(struct snd_soc_codec *codec) | |||
204 | int i, err; | 247 | int i, err; |
205 | 248 | ||
206 | /* Not connected */ | 249 | /* Not connected */ |
207 | snd_soc_dapm_set_endpoint(codec, "MONO_LOUT", 0); | 250 | snd_soc_dapm_disable_pin(codec, "MONO_LOUT"); |
208 | snd_soc_dapm_set_endpoint(codec, "HPLCOM", 0); | 251 | snd_soc_dapm_disable_pin(codec, "HPLCOM"); |
209 | snd_soc_dapm_set_endpoint(codec, "HPRCOM", 0); | 252 | snd_soc_dapm_disable_pin(codec, "HPRCOM"); |
210 | 253 | ||
211 | /* Add N810 specific controls */ | 254 | /* Add N810 specific controls */ |
212 | for (i = 0; i < ARRAY_SIZE(aic33_n810_controls); i++) { | 255 | for (i = 0; i < ARRAY_SIZE(aic33_n810_controls); i++) { |
@@ -217,15 +260,13 @@ static int n810_aic33_init(struct snd_soc_codec *codec) | |||
217 | } | 260 | } |
218 | 261 | ||
219 | /* Add N810 specific widgets */ | 262 | /* Add N810 specific widgets */ |
220 | for (i = 0; i < ARRAY_SIZE(aic33_dapm_widgets); i++) | 263 | snd_soc_dapm_new_controls(codec, aic33_dapm_widgets, |
221 | snd_soc_dapm_new_control(codec, &aic33_dapm_widgets[i]); | 264 | ARRAY_SIZE(aic33_dapm_widgets)); |
222 | 265 | ||
223 | /* Set up N810 specific audio path audio_map */ | 266 | /* Set up N810 specific audio path audio_map */ |
224 | for (i = 0; i < ARRAY_SIZE(audio_map); i++) | 267 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
225 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | ||
226 | audio_map[i][1], audio_map[i][2]); | ||
227 | 268 | ||
228 | snd_soc_dapm_sync_endpoints(codec); | 269 | snd_soc_dapm_sync(codec); |
229 | 270 | ||
230 | return 0; | 271 | return 0; |
231 | } | 272 | } |
@@ -250,6 +291,8 @@ static struct snd_soc_machine snd_soc_machine_n810 = { | |||
250 | /* Audio private data */ | 291 | /* Audio private data */ |
251 | static struct aic3x_setup_data n810_aic33_setup = { | 292 | static struct aic3x_setup_data n810_aic33_setup = { |
252 | .i2c_address = 0x18, | 293 | .i2c_address = 0x18, |
294 | .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED, | ||
295 | .gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT, | ||
253 | }; | 296 | }; |
254 | 297 | ||
255 | /* Audio subsystem */ | 298 | /* Audio subsystem */ |
@@ -267,7 +310,7 @@ static int __init n810_soc_init(void) | |||
267 | int err; | 310 | int err; |
268 | struct device *dev; | 311 | struct device *dev; |
269 | 312 | ||
270 | if (!machine_is_nokia_n810()) | 313 | if (!(machine_is_nokia_n810() || machine_is_nokia_n810_wimax())) |
271 | return -ENODEV; | 314 | return -ENODEV; |
272 | 315 | ||
273 | n810_snd_device = platform_device_alloc("soc-audio", -1); | 316 | n810_snd_device = platform_device_alloc("soc-audio", -1); |
@@ -305,12 +348,12 @@ static int __init n810_soc_init(void) | |||
305 | clk_set_parent(sys_clkout2_src, func96m_clk); | 348 | clk_set_parent(sys_clkout2_src, func96m_clk); |
306 | clk_set_rate(sys_clkout2, 12000000); | 349 | clk_set_rate(sys_clkout2, 12000000); |
307 | 350 | ||
308 | if (omap_request_gpio(RX44_HEADSET_AMP_GPIO) < 0) | 351 | if (gpio_request(N810_HEADSET_AMP_GPIO, "hs_amp") < 0) |
309 | BUG(); | 352 | BUG(); |
310 | if (omap_request_gpio(RX44_SPEAKER_AMP_GPIO) < 0) | 353 | if (gpio_request(N810_SPEAKER_AMP_GPIO, "spk_amp") < 0) |
311 | BUG(); | 354 | BUG(); |
312 | omap_set_gpio_direction(RX44_HEADSET_AMP_GPIO, 0); | 355 | gpio_direction_output(N810_HEADSET_AMP_GPIO, 0); |
313 | omap_set_gpio_direction(RX44_SPEAKER_AMP_GPIO, 0); | 356 | gpio_direction_output(N810_SPEAKER_AMP_GPIO, 0); |
314 | 357 | ||
315 | return 0; | 358 | return 0; |
316 | err2: | 359 | err2: |
@@ -325,6 +368,9 @@ err1: | |||
325 | 368 | ||
326 | static void __exit n810_soc_exit(void) | 369 | static void __exit n810_soc_exit(void) |
327 | { | 370 | { |
371 | gpio_free(N810_SPEAKER_AMP_GPIO); | ||
372 | gpio_free(N810_HEADSET_AMP_GPIO); | ||
373 | |||
328 | platform_device_unregister(n810_snd_device); | 374 | platform_device_unregister(n810_snd_device); |
329 | } | 375 | } |
330 | 376 | ||
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 40d87e6d0de8..00b0c9d73cd4 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c | |||
@@ -103,7 +103,7 @@ static const unsigned long omap2420_mcbsp_port[][2] = {}; | |||
103 | static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream) | 103 | static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream) |
104 | { | 104 | { |
105 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 105 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
106 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 106 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
107 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); | 107 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); |
108 | int err = 0; | 108 | int err = 0; |
109 | 109 | ||
@@ -116,7 +116,7 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream) | |||
116 | static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream) | 116 | static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream) |
117 | { | 117 | { |
118 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 118 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
119 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 119 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
120 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); | 120 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); |
121 | 121 | ||
122 | if (!cpu_dai->active) { | 122 | if (!cpu_dai->active) { |
@@ -128,7 +128,7 @@ static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream) | |||
128 | static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd) | 128 | static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd) |
129 | { | 129 | { |
130 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 130 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
131 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 131 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
132 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); | 132 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); |
133 | int err = 0; | 133 | int err = 0; |
134 | 134 | ||
@@ -157,7 +157,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, | |||
157 | struct snd_pcm_hw_params *params) | 157 | struct snd_pcm_hw_params *params) |
158 | { | 158 | { |
159 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 159 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
160 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 160 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
161 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); | 161 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); |
162 | struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; | 162 | struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; |
163 | int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id; | 163 | int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id; |
@@ -223,7 +223,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, | |||
223 | * This must be called before _set_clkdiv and _set_sysclk since McBSP register | 223 | * This must be called before _set_clkdiv and _set_sysclk since McBSP register |
224 | * cache is initialized here | 224 | * cache is initialized here |
225 | */ | 225 | */ |
226 | static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai, | 226 | static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, |
227 | unsigned int fmt) | 227 | unsigned int fmt) |
228 | { | 228 | { |
229 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); | 229 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); |
@@ -292,7 +292,7 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai, | |||
292 | return 0; | 292 | return 0; |
293 | } | 293 | } |
294 | 294 | ||
295 | static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_cpu_dai *cpu_dai, | 295 | static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_dai *cpu_dai, |
296 | int div_id, int div) | 296 | int div_id, int div) |
297 | { | 297 | { |
298 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); | 298 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); |
@@ -347,7 +347,7 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data, | |||
347 | return 0; | 347 | return 0; |
348 | } | 348 | } |
349 | 349 | ||
350 | static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai, | 350 | static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, |
351 | int clk_id, unsigned int freq, | 351 | int clk_id, unsigned int freq, |
352 | int dir) | 352 | int dir) |
353 | { | 353 | { |
@@ -376,7 +376,7 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai, | |||
376 | return err; | 376 | return err; |
377 | } | 377 | } |
378 | 378 | ||
379 | struct snd_soc_cpu_dai omap_mcbsp_dai[NUM_LINKS] = { | 379 | struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS] = { |
380 | { | 380 | { |
381 | .name = "omap-mcbsp-dai", | 381 | .name = "omap-mcbsp-dai", |
382 | .id = 0, | 382 | .id = 0, |
diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h index 9965fd4b0427..ed8afb550671 100644 --- a/sound/soc/omap/omap-mcbsp.h +++ b/sound/soc/omap/omap-mcbsp.h | |||
@@ -44,6 +44,6 @@ enum omap_mcbsp_div { | |||
44 | */ | 44 | */ |
45 | #define NUM_LINKS 1 | 45 | #define NUM_LINKS 1 |
46 | 46 | ||
47 | extern struct snd_soc_cpu_dai omap_mcbsp_dai[NUM_LINKS]; | 47 | extern struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS]; |
48 | 48 | ||
49 | #endif | 49 | #endif |
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 62370202c649..e092f3d836d0 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c | |||
@@ -316,7 +316,7 @@ static void omap_pcm_free_dma_buffers(struct snd_pcm *pcm) | |||
316 | } | 316 | } |
317 | } | 317 | } |
318 | 318 | ||
319 | int omap_pcm_new(struct snd_card *card, struct snd_soc_codec_dai *dai, | 319 | int omap_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, |
320 | struct snd_pcm *pcm) | 320 | struct snd_pcm *pcm) |
321 | { | 321 | { |
322 | int ret = 0; | 322 | int ret = 0; |
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index 484f883459e0..12f6ac99b04c 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | config SND_PXA2XX_SOC | 1 | config SND_PXA2XX_SOC |
2 | tristate "SoC Audio for the Intel PXA2xx chip" | 2 | tristate "SoC Audio for the Intel PXA2xx chip" |
3 | depends on ARCH_PXA && SND_SOC | 3 | depends on ARCH_PXA |
4 | help | 4 | help |
5 | Say Y or M if you want to add support for codecs attached to | 5 | Say Y or M if you want to add support for codecs attached to |
6 | the PXA2xx AC97, I2S or SSP interface. You will also need | 6 | the PXA2xx AC97, I2S or SSP interface. You will also need |
@@ -62,3 +62,12 @@ config SND_PXA2XX_SOC_E800 | |||
62 | help | 62 | help |
63 | Say Y if you want to add support for SoC audio on the | 63 | Say Y if you want to add support for SoC audio on the |
64 | Toshiba e800 PDA | 64 | Toshiba e800 PDA |
65 | |||
66 | config SND_PXA2XX_SOC_EM_X270 | ||
67 | tristate "SoC Audio support for CompuLab EM-x270" | ||
68 | depends on SND_PXA2XX_SOC && MACH_EM_X270 | ||
69 | select SND_PXA2XX_SOC_AC97 | ||
70 | select SND_SOC_WM9712 | ||
71 | help | ||
72 | Say Y if you want to add support for SoC audio on | ||
73 | CompuLab EM-x270. | ||
diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile index 04e5646f75ba..5bc8edf9dca9 100644 --- a/sound/soc/pxa/Makefile +++ b/sound/soc/pxa/Makefile | |||
@@ -13,10 +13,11 @@ snd-soc-poodle-objs := poodle.o | |||
13 | snd-soc-tosa-objs := tosa.o | 13 | snd-soc-tosa-objs := tosa.o |
14 | snd-soc-e800-objs := e800_wm9712.o | 14 | snd-soc-e800-objs := e800_wm9712.o |
15 | snd-soc-spitz-objs := spitz.o | 15 | snd-soc-spitz-objs := spitz.o |
16 | snd-soc-em-x270-objs := em-x270.o | ||
16 | 17 | ||
17 | obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o | 18 | obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o |
18 | obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o | 19 | obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o |
19 | obj-$(CONFIG_SND_PXA2XX_SOC_TOSA) += snd-soc-tosa.o | 20 | obj-$(CONFIG_SND_PXA2XX_SOC_TOSA) += snd-soc-tosa.o |
20 | obj-$(CONFIG_SND_PXA2XX_SOC_E800) += snd-soc-e800.o | 21 | obj-$(CONFIG_SND_PXA2XX_SOC_E800) += snd-soc-e800.o |
21 | obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o | 22 | obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o |
22 | 23 | obj-$(CONFIG_SND_PXA2XX_SOC_EM_X270) += snd-soc-em-x270.o | |
diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index 7f32a1167572..c0294464a23a 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c | |||
@@ -11,10 +11,6 @@ | |||
11 | * under the terms of the GNU General Public License as published by the | 11 | * under the terms of the GNU General Public License as published by the |
12 | * Free Software Foundation; either version 2 of the License, or (at your | 12 | * Free Software Foundation; either version 2 of the License, or (at your |
13 | * option) any later version. | 13 | * option) any later version. |
14 | * | ||
15 | * Revision history | ||
16 | * 30th Nov 2005 Initial version. | ||
17 | * | ||
18 | */ | 14 | */ |
19 | 15 | ||
20 | #include <linux/module.h> | 16 | #include <linux/module.h> |
@@ -54,47 +50,51 @@ static int corgi_spk_func; | |||
54 | 50 | ||
55 | static void corgi_ext_control(struct snd_soc_codec *codec) | 51 | static void corgi_ext_control(struct snd_soc_codec *codec) |
56 | { | 52 | { |
57 | int spk = 0, mic = 0, line = 0, hp = 0, hs = 0; | ||
58 | |||
59 | /* set up jack connection */ | 53 | /* set up jack connection */ |
60 | switch (corgi_jack_func) { | 54 | switch (corgi_jack_func) { |
61 | case CORGI_HP: | 55 | case CORGI_HP: |
62 | hp = 1; | ||
63 | /* set = unmute headphone */ | 56 | /* set = unmute headphone */ |
64 | set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); | 57 | set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); |
65 | set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); | 58 | set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); |
59 | snd_soc_dapm_disable_pin(codec, "Mic Jack"); | ||
60 | snd_soc_dapm_disable_pin(codec, "Line Jack"); | ||
61 | snd_soc_dapm_enable_pin(codec, "Headphone Jack"); | ||
62 | snd_soc_dapm_disable_pin(codec, "Headset Jack"); | ||
66 | break; | 63 | break; |
67 | case CORGI_MIC: | 64 | case CORGI_MIC: |
68 | mic = 1; | ||
69 | /* reset = mute headphone */ | 65 | /* reset = mute headphone */ |
70 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); | 66 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); |
71 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); | 67 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); |
68 | snd_soc_dapm_enable_pin(codec, "Mic Jack"); | ||
69 | snd_soc_dapm_disable_pin(codec, "Line Jack"); | ||
70 | snd_soc_dapm_disable_pin(codec, "Headphone Jack"); | ||
71 | snd_soc_dapm_disable_pin(codec, "Headset Jack"); | ||
72 | break; | 72 | break; |
73 | case CORGI_LINE: | 73 | case CORGI_LINE: |
74 | line = 1; | ||
75 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); | 74 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); |
76 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); | 75 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); |
76 | snd_soc_dapm_disable_pin(codec, "Mic Jack"); | ||
77 | snd_soc_dapm_enable_pin(codec, "Line Jack"); | ||
78 | snd_soc_dapm_disable_pin(codec, "Headphone Jack"); | ||
79 | snd_soc_dapm_disable_pin(codec, "Headset Jack"); | ||
77 | break; | 80 | break; |
78 | case CORGI_HEADSET: | 81 | case CORGI_HEADSET: |
79 | hs = 1; | ||
80 | mic = 1; | ||
81 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); | 82 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_L); |
82 | set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); | 83 | set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_MUTE_R); |
84 | snd_soc_dapm_enable_pin(codec, "Mic Jack"); | ||
85 | snd_soc_dapm_disable_pin(codec, "Line Jack"); | ||
86 | snd_soc_dapm_disable_pin(codec, "Headphone Jack"); | ||
87 | snd_soc_dapm_enable_pin(codec, "Headset Jack"); | ||
83 | break; | 88 | break; |
84 | } | 89 | } |
85 | 90 | ||
86 | if (corgi_spk_func == CORGI_SPK_ON) | 91 | if (corgi_spk_func == CORGI_SPK_ON) |
87 | spk = 1; | 92 | snd_soc_dapm_enable_pin(codec, "Ext Spk"); |
88 | 93 | else | |
89 | /* set the enpoints to their new connetion states */ | 94 | snd_soc_dapm_disable_pin(codec, "Ext Spk"); |
90 | snd_soc_dapm_set_endpoint(codec, "Ext Spk", spk); | ||
91 | snd_soc_dapm_set_endpoint(codec, "Mic Jack", mic); | ||
92 | snd_soc_dapm_set_endpoint(codec, "Line Jack", line); | ||
93 | snd_soc_dapm_set_endpoint(codec, "Headphone Jack", hp); | ||
94 | snd_soc_dapm_set_endpoint(codec, "Headset Jack", hs); | ||
95 | 95 | ||
96 | /* signal a DAPM event */ | 96 | /* signal a DAPM event */ |
97 | snd_soc_dapm_sync_endpoints(codec); | 97 | snd_soc_dapm_sync(codec); |
98 | } | 98 | } |
99 | 99 | ||
100 | static int corgi_startup(struct snd_pcm_substream *substream) | 100 | static int corgi_startup(struct snd_pcm_substream *substream) |
@@ -123,8 +123,8 @@ static int corgi_hw_params(struct snd_pcm_substream *substream, | |||
123 | struct snd_pcm_hw_params *params) | 123 | struct snd_pcm_hw_params *params) |
124 | { | 124 | { |
125 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 125 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
126 | struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; | 126 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
127 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 127 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
128 | unsigned int clk = 0; | 128 | unsigned int clk = 0; |
129 | int ret = 0; | 129 | int ret = 0; |
130 | 130 | ||
@@ -143,25 +143,25 @@ static int corgi_hw_params(struct snd_pcm_substream *substream, | |||
143 | } | 143 | } |
144 | 144 | ||
145 | /* set codec DAI configuration */ | 145 | /* set codec DAI configuration */ |
146 | ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | 146 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | |
147 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | 147 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); |
148 | if (ret < 0) | 148 | if (ret < 0) |
149 | return ret; | 149 | return ret; |
150 | 150 | ||
151 | /* set cpu DAI configuration */ | 151 | /* set cpu DAI configuration */ |
152 | ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | 152 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | |
153 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | 153 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); |
154 | if (ret < 0) | 154 | if (ret < 0) |
155 | return ret; | 155 | return ret; |
156 | 156 | ||
157 | /* set the codec system clock for DAC and ADC */ | 157 | /* set the codec system clock for DAC and ADC */ |
158 | ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8731_SYSCLK, clk, | 158 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, clk, |
159 | SND_SOC_CLOCK_IN); | 159 | SND_SOC_CLOCK_IN); |
160 | if (ret < 0) | 160 | if (ret < 0) |
161 | return ret; | 161 | return ret; |
162 | 162 | ||
163 | /* set the I2S system clock as input (unused) */ | 163 | /* set the I2S system clock as input (unused) */ |
164 | ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, | 164 | ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, |
165 | SND_SOC_CLOCK_IN); | 165 | SND_SOC_CLOCK_IN); |
166 | if (ret < 0) | 166 | if (ret < 0) |
167 | return ret; | 167 | return ret; |
@@ -247,7 +247,7 @@ SND_SOC_DAPM_HP("Headset Jack", NULL), | |||
247 | }; | 247 | }; |
248 | 248 | ||
249 | /* Corgi machine audio map (connections to the codec pins) */ | 249 | /* Corgi machine audio map (connections to the codec pins) */ |
250 | static const char *audio_map[][3] = { | 250 | static const struct snd_soc_dapm_route audio_map[] = { |
251 | 251 | ||
252 | /* headset Jack - in = micin, out = LHPOUT*/ | 252 | /* headset Jack - in = micin, out = LHPOUT*/ |
253 | {"Headset Jack", NULL, "LHPOUT"}, | 253 | {"Headset Jack", NULL, "LHPOUT"}, |
@@ -265,8 +265,6 @@ static const char *audio_map[][3] = { | |||
265 | 265 | ||
266 | /* Same as the above but no mic bias for line signals */ | 266 | /* Same as the above but no mic bias for line signals */ |
267 | {"MICIN", NULL, "Line Jack"}, | 267 | {"MICIN", NULL, "Line Jack"}, |
268 | |||
269 | {NULL, NULL, NULL}, | ||
270 | }; | 268 | }; |
271 | 269 | ||
272 | static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", | 270 | static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", |
@@ -291,8 +289,8 @@ static int corgi_wm8731_init(struct snd_soc_codec *codec) | |||
291 | { | 289 | { |
292 | int i, err; | 290 | int i, err; |
293 | 291 | ||
294 | snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0); | 292 | snd_soc_dapm_disable_pin(codec, "LLINEIN"); |
295 | snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0); | 293 | snd_soc_dapm_disable_pin(codec, "RLINEIN"); |
296 | 294 | ||
297 | /* Add corgi specific controls */ | 295 | /* Add corgi specific controls */ |
298 | for (i = 0; i < ARRAY_SIZE(wm8731_corgi_controls); i++) { | 296 | for (i = 0; i < ARRAY_SIZE(wm8731_corgi_controls); i++) { |
@@ -303,15 +301,13 @@ static int corgi_wm8731_init(struct snd_soc_codec *codec) | |||
303 | } | 301 | } |
304 | 302 | ||
305 | /* Add corgi specific widgets */ | 303 | /* Add corgi specific widgets */ |
306 | for (i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++) | 304 | snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets, |
307 | snd_soc_dapm_new_control(codec, &wm8731_dapm_widgets[i]); | 305 | ARRAY_SIZE(wm8731_dapm_widgets)); |
308 | 306 | ||
309 | /* Set up corgi specific audio path audio_map */ | 307 | /* Set up corgi specific audio path audio_map */ |
310 | for (i = 0; audio_map[i][0] != NULL; i++) | 308 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
311 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | ||
312 | audio_map[i][1], audio_map[i][2]); | ||
313 | 309 | ||
314 | snd_soc_dapm_sync_endpoints(codec); | 310 | snd_soc_dapm_sync(codec); |
315 | return 0; | 311 | return 0; |
316 | } | 312 | } |
317 | 313 | ||
diff --git a/sound/soc/pxa/em-x270.c b/sound/soc/pxa/em-x270.c new file mode 100644 index 000000000000..02dcac39cdf6 --- /dev/null +++ b/sound/soc/pxa/em-x270.c | |||
@@ -0,0 +1,102 @@ | |||
1 | /* | ||
2 | * em-x270.c -- SoC audio for EM-X270 | ||
3 | * | ||
4 | * Copyright 2007 CompuLab, Ltd. | ||
5 | * | ||
6 | * Author: Mike Rapoport <mike@compulab.co.il> | ||
7 | * | ||
8 | * Copied from tosa.c: | ||
9 | * Copyright 2005 Wolfson Microelectronics PLC. | ||
10 | * Copyright 2005 Openedhand Ltd. | ||
11 | * | ||
12 | * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com> | ||
13 | * Richard Purdie <richard@openedhand.com> | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or modify it | ||
16 | * under the terms of the GNU General Public License as published by the | ||
17 | * Free Software Foundation; either version 2 of the License, or (at your | ||
18 | * option) any later version. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/moduleparam.h> | ||
24 | #include <linux/device.h> | ||
25 | |||
26 | #include <sound/driver.h> | ||
27 | #include <sound/core.h> | ||
28 | #include <sound/pcm.h> | ||
29 | #include <sound/soc.h> | ||
30 | #include <sound/soc-dapm.h> | ||
31 | |||
32 | #include <asm/mach-types.h> | ||
33 | #include <asm/arch/pxa-regs.h> | ||
34 | #include <asm/arch/hardware.h> | ||
35 | #include <asm/arch/audio.h> | ||
36 | |||
37 | #include "../codecs/wm9712.h" | ||
38 | #include "pxa2xx-pcm.h" | ||
39 | #include "pxa2xx-ac97.h" | ||
40 | |||
41 | static struct snd_soc_dai_link em_x270_dai[] = { | ||
42 | { | ||
43 | .name = "AC97", | ||
44 | .stream_name = "AC97 HiFi", | ||
45 | .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], | ||
46 | .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI], | ||
47 | }, | ||
48 | { | ||
49 | .name = "AC97 Aux", | ||
50 | .stream_name = "AC97 Aux", | ||
51 | .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], | ||
52 | .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX], | ||
53 | }, | ||
54 | }; | ||
55 | |||
56 | static struct snd_soc_machine em_x270 = { | ||
57 | .name = "EM-X270", | ||
58 | .dai_link = em_x270_dai, | ||
59 | .num_links = ARRAY_SIZE(em_x270_dai), | ||
60 | }; | ||
61 | |||
62 | static struct snd_soc_device em_x270_snd_devdata = { | ||
63 | .machine = &em_x270, | ||
64 | .platform = &pxa2xx_soc_platform, | ||
65 | .codec_dev = &soc_codec_dev_wm9712, | ||
66 | }; | ||
67 | |||
68 | static struct platform_device *em_x270_snd_device; | ||
69 | |||
70 | static int __init em_x270_init(void) | ||
71 | { | ||
72 | int ret; | ||
73 | |||
74 | if (!machine_is_em_x270()) | ||
75 | return -ENODEV; | ||
76 | |||
77 | em_x270_snd_device = platform_device_alloc("soc-audio", -1); | ||
78 | if (!em_x270_snd_device) | ||
79 | return -ENOMEM; | ||
80 | |||
81 | platform_set_drvdata(em_x270_snd_device, &em_x270_snd_devdata); | ||
82 | em_x270_snd_devdata.dev = &em_x270_snd_device->dev; | ||
83 | ret = platform_device_add(em_x270_snd_device); | ||
84 | |||
85 | if (ret) | ||
86 | platform_device_put(em_x270_snd_device); | ||
87 | |||
88 | return ret; | ||
89 | } | ||
90 | |||
91 | static void __exit em_x270_exit(void) | ||
92 | { | ||
93 | platform_device_unregister(em_x270_snd_device); | ||
94 | } | ||
95 | |||
96 | module_init(em_x270_init); | ||
97 | module_exit(em_x270_exit); | ||
98 | |||
99 | /* Module information */ | ||
100 | MODULE_AUTHOR("Mike Rapoport"); | ||
101 | MODULE_DESCRIPTION("ALSA SoC EM-X270"); | ||
102 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c index 7e830b218943..65a4e9a8c39e 100644 --- a/sound/soc/pxa/poodle.c +++ b/sound/soc/pxa/poodle.c | |||
@@ -48,8 +48,6 @@ static int poodle_spk_func; | |||
48 | 48 | ||
49 | static void poodle_ext_control(struct snd_soc_codec *codec) | 49 | static void poodle_ext_control(struct snd_soc_codec *codec) |
50 | { | 50 | { |
51 | int spk = 0; | ||
52 | |||
53 | /* set up jack connection */ | 51 | /* set up jack connection */ |
54 | if (poodle_jack_func == POODLE_HP) { | 52 | if (poodle_jack_func == POODLE_HP) { |
55 | /* set = unmute headphone */ | 53 | /* set = unmute headphone */ |
@@ -57,23 +55,23 @@ static void poodle_ext_control(struct snd_soc_codec *codec) | |||
57 | POODLE_LOCOMO_GPIO_MUTE_L, 1); | 55 | POODLE_LOCOMO_GPIO_MUTE_L, 1); |
58 | locomo_gpio_write(&poodle_locomo_device.dev, | 56 | locomo_gpio_write(&poodle_locomo_device.dev, |
59 | POODLE_LOCOMO_GPIO_MUTE_R, 1); | 57 | POODLE_LOCOMO_GPIO_MUTE_R, 1); |
60 | snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 1); | 58 | snd_soc_dapm_enable_pin(codec, "Headphone Jack"); |
61 | } else { | 59 | } else { |
62 | locomo_gpio_write(&poodle_locomo_device.dev, | 60 | locomo_gpio_write(&poodle_locomo_device.dev, |
63 | POODLE_LOCOMO_GPIO_MUTE_L, 0); | 61 | POODLE_LOCOMO_GPIO_MUTE_L, 0); |
64 | locomo_gpio_write(&poodle_locomo_device.dev, | 62 | locomo_gpio_write(&poodle_locomo_device.dev, |
65 | POODLE_LOCOMO_GPIO_MUTE_R, 0); | 63 | POODLE_LOCOMO_GPIO_MUTE_R, 0); |
66 | snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0); | 64 | snd_soc_dapm_disable_pin(codec, "Headphone Jack"); |
67 | } | 65 | } |
68 | 66 | ||
69 | if (poodle_spk_func == POODLE_SPK_ON) | ||
70 | spk = 1; | ||
71 | |||
72 | /* set the enpoints to their new connetion states */ | 67 | /* set the enpoints to their new connetion states */ |
73 | snd_soc_dapm_set_endpoint(codec, "Ext Spk", spk); | 68 | if (poodle_spk_func == POODLE_SPK_ON) |
69 | snd_soc_dapm_enable_pin(codec, "Ext Spk"); | ||
70 | else | ||
71 | snd_soc_dapm_disable_pin(codec, "Ext Spk"); | ||
74 | 72 | ||
75 | /* signal a DAPM event */ | 73 | /* signal a DAPM event */ |
76 | snd_soc_dapm_sync_endpoints(codec); | 74 | snd_soc_dapm_sync(codec); |
77 | } | 75 | } |
78 | 76 | ||
79 | static int poodle_startup(struct snd_pcm_substream *substream) | 77 | static int poodle_startup(struct snd_pcm_substream *substream) |
@@ -104,8 +102,8 @@ static int poodle_hw_params(struct snd_pcm_substream *substream, | |||
104 | struct snd_pcm_hw_params *params) | 102 | struct snd_pcm_hw_params *params) |
105 | { | 103 | { |
106 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 104 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
107 | struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; | 105 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
108 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 106 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
109 | unsigned int clk = 0; | 107 | unsigned int clk = 0; |
110 | int ret = 0; | 108 | int ret = 0; |
111 | 109 | ||
@@ -124,25 +122,25 @@ static int poodle_hw_params(struct snd_pcm_substream *substream, | |||
124 | } | 122 | } |
125 | 123 | ||
126 | /* set codec DAI configuration */ | 124 | /* set codec DAI configuration */ |
127 | ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | 125 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | |
128 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | 126 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); |
129 | if (ret < 0) | 127 | if (ret < 0) |
130 | return ret; | 128 | return ret; |
131 | 129 | ||
132 | /* set cpu DAI configuration */ | 130 | /* set cpu DAI configuration */ |
133 | ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | 131 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | |
134 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | 132 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); |
135 | if (ret < 0) | 133 | if (ret < 0) |
136 | return ret; | 134 | return ret; |
137 | 135 | ||
138 | /* set the codec system clock for DAC and ADC */ | 136 | /* set the codec system clock for DAC and ADC */ |
139 | ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8731_SYSCLK, clk, | 137 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, clk, |
140 | SND_SOC_CLOCK_IN); | 138 | SND_SOC_CLOCK_IN); |
141 | if (ret < 0) | 139 | if (ret < 0) |
142 | return ret; | 140 | return ret; |
143 | 141 | ||
144 | /* set the I2S system clock as input (unused) */ | 142 | /* set the I2S system clock as input (unused) */ |
145 | ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, | 143 | ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, |
146 | SND_SOC_CLOCK_IN); | 144 | SND_SOC_CLOCK_IN); |
147 | if (ret < 0) | 145 | if (ret < 0) |
148 | return ret; | 146 | return ret; |
@@ -215,8 +213,8 @@ SND_SOC_DAPM_HP("Headphone Jack", NULL), | |||
215 | SND_SOC_DAPM_SPK("Ext Spk", poodle_amp_event), | 213 | SND_SOC_DAPM_SPK("Ext Spk", poodle_amp_event), |
216 | }; | 214 | }; |
217 | 215 | ||
218 | /* Corgi machine audio_mapnections to the codec pins */ | 216 | /* Corgi machine connections to the codec pins */ |
219 | static const char *audio_map[][3] = { | 217 | static const struct snd_soc_dapm_route audio_map[] = { |
220 | 218 | ||
221 | /* headphone connected to LHPOUT1, RHPOUT1 */ | 219 | /* headphone connected to LHPOUT1, RHPOUT1 */ |
222 | {"Headphone Jack", NULL, "LHPOUT"}, | 220 | {"Headphone Jack", NULL, "LHPOUT"}, |
@@ -225,8 +223,6 @@ static const char *audio_map[][3] = { | |||
225 | /* speaker connected to LOUT, ROUT */ | 223 | /* speaker connected to LOUT, ROUT */ |
226 | {"Ext Spk", NULL, "ROUT"}, | 224 | {"Ext Spk", NULL, "ROUT"}, |
227 | {"Ext Spk", NULL, "LOUT"}, | 225 | {"Ext Spk", NULL, "LOUT"}, |
228 | |||
229 | {NULL, NULL, NULL}, | ||
230 | }; | 226 | }; |
231 | 227 | ||
232 | static const char *jack_function[] = {"Off", "Headphone"}; | 228 | static const char *jack_function[] = {"Off", "Headphone"}; |
@@ -250,9 +246,9 @@ static int poodle_wm8731_init(struct snd_soc_codec *codec) | |||
250 | { | 246 | { |
251 | int i, err; | 247 | int i, err; |
252 | 248 | ||
253 | snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0); | 249 | snd_soc_dapm_disable_pin(codec, "LLINEIN"); |
254 | snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0); | 250 | snd_soc_dapm_disable_pin(codec, "RLINEIN"); |
255 | snd_soc_dapm_set_endpoint(codec, "MICIN", 1); | 251 | snd_soc_dapm_enable_pin(codec, "MICIN"); |
256 | 252 | ||
257 | /* Add poodle specific controls */ | 253 | /* Add poodle specific controls */ |
258 | for (i = 0; i < ARRAY_SIZE(wm8731_poodle_controls); i++) { | 254 | for (i = 0; i < ARRAY_SIZE(wm8731_poodle_controls); i++) { |
@@ -263,15 +259,13 @@ static int poodle_wm8731_init(struct snd_soc_codec *codec) | |||
263 | } | 259 | } |
264 | 260 | ||
265 | /* Add poodle specific widgets */ | 261 | /* Add poodle specific widgets */ |
266 | for (i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++) | 262 | snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets, |
267 | snd_soc_dapm_new_control(codec, &wm8731_dapm_widgets[i]); | 263 | ARRAY_SIZE(wm8731_dapm_widgets)); |
268 | 264 | ||
269 | /* Set up poodle specific audio path audio_map */ | 265 | /* Set up poodle specific audio path audio_map */ |
270 | for (i = 0; audio_map[i][0] != NULL; i++) | 266 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
271 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | ||
272 | audio_map[i][1], audio_map[i][2]); | ||
273 | 267 | ||
274 | snd_soc_dapm_sync_endpoints(codec); | 268 | snd_soc_dapm_sync(codec); |
275 | return 0; | 269 | return 0; |
276 | } | 270 | } |
277 | 271 | ||
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index 97ec2d90547c..059af815ea0c 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c | |||
@@ -283,7 +283,7 @@ static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_mic_mono_in = { | |||
283 | 283 | ||
284 | #ifdef CONFIG_PM | 284 | #ifdef CONFIG_PM |
285 | static int pxa2xx_ac97_suspend(struct platform_device *pdev, | 285 | static int pxa2xx_ac97_suspend(struct platform_device *pdev, |
286 | struct snd_soc_cpu_dai *dai) | 286 | struct snd_soc_dai *dai) |
287 | { | 287 | { |
288 | GCR |= GCR_ACLINK_OFF; | 288 | GCR |= GCR_ACLINK_OFF; |
289 | clk_disable(ac97_clk); | 289 | clk_disable(ac97_clk); |
@@ -291,7 +291,7 @@ static int pxa2xx_ac97_suspend(struct platform_device *pdev, | |||
291 | } | 291 | } |
292 | 292 | ||
293 | static int pxa2xx_ac97_resume(struct platform_device *pdev, | 293 | static int pxa2xx_ac97_resume(struct platform_device *pdev, |
294 | struct snd_soc_cpu_dai *dai) | 294 | struct snd_soc_dai *dai) |
295 | { | 295 | { |
296 | pxa_gpio_mode(GPIO31_SYNC_AC97_MD); | 296 | pxa_gpio_mode(GPIO31_SYNC_AC97_MD); |
297 | pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD); | 297 | pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD); |
@@ -310,7 +310,8 @@ static int pxa2xx_ac97_resume(struct platform_device *pdev, | |||
310 | #define pxa2xx_ac97_resume NULL | 310 | #define pxa2xx_ac97_resume NULL |
311 | #endif | 311 | #endif |
312 | 312 | ||
313 | static int pxa2xx_ac97_probe(struct platform_device *pdev) | 313 | static int pxa2xx_ac97_probe(struct platform_device *pdev, |
314 | struct snd_soc_dai *dai) | ||
314 | { | 315 | { |
315 | int ret; | 316 | int ret; |
316 | 317 | ||
@@ -355,7 +356,8 @@ static int pxa2xx_ac97_probe(struct platform_device *pdev) | |||
355 | return ret; | 356 | return ret; |
356 | } | 357 | } |
357 | 358 | ||
358 | static void pxa2xx_ac97_remove(struct platform_device *pdev) | 359 | static void pxa2xx_ac97_remove(struct platform_device *pdev, |
360 | struct snd_soc_dai *dai) | ||
359 | { | 361 | { |
360 | GCR |= GCR_ACLINK_OFF; | 362 | GCR |= GCR_ACLINK_OFF; |
361 | free_irq(IRQ_AC97, NULL); | 363 | free_irq(IRQ_AC97, NULL); |
@@ -372,7 +374,7 @@ static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream, | |||
372 | struct snd_pcm_hw_params *params) | 374 | struct snd_pcm_hw_params *params) |
373 | { | 375 | { |
374 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 376 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
375 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 377 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
376 | 378 | ||
377 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 379 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
378 | cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_out; | 380 | cpu_dai->dma_data = &pxa2xx_ac97_pcm_stereo_out; |
@@ -386,7 +388,7 @@ static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream, | |||
386 | struct snd_pcm_hw_params *params) | 388 | struct snd_pcm_hw_params *params) |
387 | { | 389 | { |
388 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 390 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
389 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 391 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
390 | 392 | ||
391 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 393 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
392 | cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_out; | 394 | cpu_dai->dma_data = &pxa2xx_ac97_pcm_aux_mono_out; |
@@ -400,7 +402,7 @@ static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream, | |||
400 | struct snd_pcm_hw_params *params) | 402 | struct snd_pcm_hw_params *params) |
401 | { | 403 | { |
402 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 404 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
403 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 405 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
404 | 406 | ||
405 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 407 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
406 | return -ENODEV; | 408 | return -ENODEV; |
@@ -418,7 +420,7 @@ static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream, | |||
418 | * There is only 1 physical AC97 interface for pxa2xx, but it | 420 | * There is only 1 physical AC97 interface for pxa2xx, but it |
419 | * has extra fifo's that can be used for aux DACs and ADCs. | 421 | * has extra fifo's that can be used for aux DACs and ADCs. |
420 | */ | 422 | */ |
421 | struct snd_soc_cpu_dai pxa_ac97_dai[] = { | 423 | struct snd_soc_dai pxa_ac97_dai[] = { |
422 | { | 424 | { |
423 | .name = "pxa2xx-ac97", | 425 | .name = "pxa2xx-ac97", |
424 | .id = 0, | 426 | .id = 0, |
diff --git a/sound/soc/pxa/pxa2xx-ac97.h b/sound/soc/pxa/pxa2xx-ac97.h index b8ccfee095c4..e390de8edcd4 100644 --- a/sound/soc/pxa/pxa2xx-ac97.h +++ b/sound/soc/pxa/pxa2xx-ac97.h | |||
@@ -14,7 +14,7 @@ | |||
14 | #define PXA2XX_DAI_AC97_AUX 1 | 14 | #define PXA2XX_DAI_AC97_AUX 1 |
15 | #define PXA2XX_DAI_AC97_MIC 2 | 15 | #define PXA2XX_DAI_AC97_MIC 2 |
16 | 16 | ||
17 | extern struct snd_soc_cpu_dai pxa_ac97_dai[3]; | 17 | extern struct snd_soc_dai pxa_ac97_dai[3]; |
18 | 18 | ||
19 | /* platform data */ | 19 | /* platform data */ |
20 | extern struct snd_ac97_bus_ops pxa2xx_ac97_ops; | 20 | extern struct snd_ac97_bus_ops pxa2xx_ac97_ops; |
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 425071030970..9c06553b9267 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c | |||
@@ -9,9 +9,6 @@ | |||
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 | * | ||
13 | * Revision history | ||
14 | * 12th Aug 2005 Initial version. | ||
15 | */ | 12 | */ |
16 | 13 | ||
17 | #include <linux/init.h> | 14 | #include <linux/init.h> |
@@ -80,7 +77,7 @@ static struct pxa2xx_gpio gpio_bus[] = { | |||
80 | static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream) | 77 | static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream) |
81 | { | 78 | { |
82 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 79 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
83 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 80 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
84 | 81 | ||
85 | if (!cpu_dai->active) { | 82 | if (!cpu_dai->active) { |
86 | SACR0 |= SACR0_RST; | 83 | SACR0 |= SACR0_RST; |
@@ -101,7 +98,7 @@ static int pxa_i2s_wait(void) | |||
101 | return 0; | 98 | return 0; |
102 | } | 99 | } |
103 | 100 | ||
104 | static int pxa2xx_i2s_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai, | 101 | static int pxa2xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, |
105 | unsigned int fmt) | 102 | unsigned int fmt) |
106 | { | 103 | { |
107 | /* interface format */ | 104 | /* interface format */ |
@@ -127,7 +124,7 @@ static int pxa2xx_i2s_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai, | |||
127 | return 0; | 124 | return 0; |
128 | } | 125 | } |
129 | 126 | ||
130 | static int pxa2xx_i2s_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai, | 127 | static int pxa2xx_i2s_set_dai_sysclk(struct snd_soc_dai *cpu_dai, |
131 | int clk_id, unsigned int freq, int dir) | 128 | int clk_id, unsigned int freq, int dir) |
132 | { | 129 | { |
133 | if (clk_id != PXA2XX_I2S_SYSCLK) | 130 | if (clk_id != PXA2XX_I2S_SYSCLK) |
@@ -143,7 +140,7 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, | |||
143 | struct snd_pcm_hw_params *params) | 140 | struct snd_pcm_hw_params *params) |
144 | { | 141 | { |
145 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 142 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
146 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 143 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
147 | 144 | ||
148 | pxa_gpio_mode(gpio_bus[pxa_i2s.master].rx); | 145 | pxa_gpio_mode(gpio_bus[pxa_i2s.master].rx); |
149 | pxa_gpio_mode(gpio_bus[pxa_i2s.master].tx); | 146 | pxa_gpio_mode(gpio_bus[pxa_i2s.master].tx); |
@@ -240,7 +237,7 @@ static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream) | |||
240 | 237 | ||
241 | #ifdef CONFIG_PM | 238 | #ifdef CONFIG_PM |
242 | static int pxa2xx_i2s_suspend(struct platform_device *dev, | 239 | static int pxa2xx_i2s_suspend(struct platform_device *dev, |
243 | struct snd_soc_cpu_dai *dai) | 240 | struct snd_soc_dai *dai) |
244 | { | 241 | { |
245 | if (!dai->active) | 242 | if (!dai->active) |
246 | return 0; | 243 | return 0; |
@@ -258,7 +255,7 @@ static int pxa2xx_i2s_suspend(struct platform_device *dev, | |||
258 | } | 255 | } |
259 | 256 | ||
260 | static int pxa2xx_i2s_resume(struct platform_device *pdev, | 257 | static int pxa2xx_i2s_resume(struct platform_device *pdev, |
261 | struct snd_soc_cpu_dai *dai) | 258 | struct snd_soc_dai *dai) |
262 | { | 259 | { |
263 | if (!dai->active) | 260 | if (!dai->active) |
264 | return 0; | 261 | return 0; |
@@ -283,7 +280,7 @@ static int pxa2xx_i2s_resume(struct platform_device *pdev, | |||
283 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ | 280 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ |
284 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) | 281 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) |
285 | 282 | ||
286 | struct snd_soc_cpu_dai pxa_i2s_dai = { | 283 | struct snd_soc_dai pxa_i2s_dai = { |
287 | .name = "pxa2xx-i2s", | 284 | .name = "pxa2xx-i2s", |
288 | .id = 0, | 285 | .id = 0, |
289 | .type = SND_SOC_DAI_I2S, | 286 | .type = SND_SOC_DAI_I2S, |
diff --git a/sound/soc/pxa/pxa2xx-i2s.h b/sound/soc/pxa/pxa2xx-i2s.h index 4435bd9f884f..e2def441153e 100644 --- a/sound/soc/pxa/pxa2xx-i2s.h +++ b/sound/soc/pxa/pxa2xx-i2s.h | |||
@@ -15,6 +15,6 @@ | |||
15 | /* I2S clock */ | 15 | /* I2S clock */ |
16 | #define PXA2XX_I2S_SYSCLK 0 | 16 | #define PXA2XX_I2S_SYSCLK 0 |
17 | 17 | ||
18 | extern struct snd_soc_cpu_dai pxa_i2s_dai; | 18 | extern struct snd_soc_dai pxa_i2s_dai; |
19 | 19 | ||
20 | #endif | 20 | #endif |
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c index 01ad7bf716b7..2df03ee5819e 100644 --- a/sound/soc/pxa/pxa2xx-pcm.c +++ b/sound/soc/pxa/pxa2xx-pcm.c | |||
@@ -330,7 +330,7 @@ static void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm) | |||
330 | 330 | ||
331 | static u64 pxa2xx_pcm_dmamask = DMA_32BIT_MASK; | 331 | static u64 pxa2xx_pcm_dmamask = DMA_32BIT_MASK; |
332 | 332 | ||
333 | int pxa2xx_pcm_new(struct snd_card *card, struct snd_soc_codec_dai *dai, | 333 | int pxa2xx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, |
334 | struct snd_pcm *pcm) | 334 | struct snd_pcm *pcm) |
335 | { | 335 | { |
336 | int ret = 0; | 336 | int ret = 0; |
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index d8b8372db00e..64385797da5d 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c | |||
@@ -12,9 +12,6 @@ | |||
12 | * Free Software Foundation; either version 2 of the License, or (at your | 12 | * Free Software Foundation; either version 2 of the License, or (at your |
13 | * option) any later version. | 13 | * option) any later version. |
14 | * | 14 | * |
15 | * Revision history | ||
16 | * 30th Nov 2005 Initial version. | ||
17 | * | ||
18 | */ | 15 | */ |
19 | 16 | ||
20 | #include <linux/module.h> | 17 | #include <linux/module.h> |
@@ -54,60 +51,60 @@ static int spitz_spk_func; | |||
54 | static void spitz_ext_control(struct snd_soc_codec *codec) | 51 | static void spitz_ext_control(struct snd_soc_codec *codec) |
55 | { | 52 | { |
56 | if (spitz_spk_func == SPITZ_SPK_ON) | 53 | if (spitz_spk_func == SPITZ_SPK_ON) |
57 | snd_soc_dapm_set_endpoint(codec, "Ext Spk", 1); | 54 | snd_soc_dapm_enable_pin(codec, "Ext Spk"); |
58 | else | 55 | else |
59 | snd_soc_dapm_set_endpoint(codec, "Ext Spk", 0); | 56 | snd_soc_dapm_disable_pin(codec, "Ext Spk"); |
60 | 57 | ||
61 | /* set up jack connection */ | 58 | /* set up jack connection */ |
62 | switch (spitz_jack_func) { | 59 | switch (spitz_jack_func) { |
63 | case SPITZ_HP: | 60 | case SPITZ_HP: |
64 | /* enable and unmute hp jack, disable mic bias */ | 61 | /* enable and unmute hp jack, disable mic bias */ |
65 | snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0); | 62 | snd_soc_dapm_disable_pin(codec, "Headset Jack"); |
66 | snd_soc_dapm_set_endpoint(codec, "Mic Jack", 0); | 63 | snd_soc_dapm_disable_pin(codec, "Mic Jack"); |
67 | snd_soc_dapm_set_endpoint(codec, "Line Jack", 0); | 64 | snd_soc_dapm_disable_pin(codec, "Line Jack"); |
68 | snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 1); | 65 | snd_soc_dapm_enable_pin(codec, "Headphone Jack"); |
69 | set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); | 66 | set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); |
70 | set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); | 67 | set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); |
71 | break; | 68 | break; |
72 | case SPITZ_MIC: | 69 | case SPITZ_MIC: |
73 | /* enable mic jack and bias, mute hp */ | 70 | /* enable mic jack and bias, mute hp */ |
74 | snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0); | 71 | snd_soc_dapm_disable_pin(codec, "Headphone Jack"); |
75 | snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0); | 72 | snd_soc_dapm_disable_pin(codec, "Headset Jack"); |
76 | snd_soc_dapm_set_endpoint(codec, "Line Jack", 0); | 73 | snd_soc_dapm_disable_pin(codec, "Line Jack"); |
77 | snd_soc_dapm_set_endpoint(codec, "Mic Jack", 1); | 74 | snd_soc_dapm_enable_pin(codec, "Mic Jack"); |
78 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); | 75 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); |
79 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); | 76 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); |
80 | break; | 77 | break; |
81 | case SPITZ_LINE: | 78 | case SPITZ_LINE: |
82 | /* enable line jack, disable mic bias and mute hp */ | 79 | /* enable line jack, disable mic bias and mute hp */ |
83 | snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0); | 80 | snd_soc_dapm_disable_pin(codec, "Headphone Jack"); |
84 | snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0); | 81 | snd_soc_dapm_disable_pin(codec, "Headset Jack"); |
85 | snd_soc_dapm_set_endpoint(codec, "Mic Jack", 0); | 82 | snd_soc_dapm_disable_pin(codec, "Mic Jack"); |
86 | snd_soc_dapm_set_endpoint(codec, "Line Jack", 1); | 83 | snd_soc_dapm_enable_pin(codec, "Line Jack"); |
87 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); | 84 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); |
88 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); | 85 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); |
89 | break; | 86 | break; |
90 | case SPITZ_HEADSET: | 87 | case SPITZ_HEADSET: |
91 | /* enable and unmute headset jack enable mic bias, mute L hp */ | 88 | /* enable and unmute headset jack enable mic bias, mute L hp */ |
92 | snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0); | 89 | snd_soc_dapm_disable_pin(codec, "Headphone Jack"); |
93 | snd_soc_dapm_set_endpoint(codec, "Mic Jack", 1); | 90 | snd_soc_dapm_enable_pin(codec, "Mic Jack"); |
94 | snd_soc_dapm_set_endpoint(codec, "Line Jack", 0); | 91 | snd_soc_dapm_disable_pin(codec, "Line Jack"); |
95 | snd_soc_dapm_set_endpoint(codec, "Headset Jack", 1); | 92 | snd_soc_dapm_enable_pin(codec, "Headset Jack"); |
96 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); | 93 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); |
97 | set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); | 94 | set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); |
98 | break; | 95 | break; |
99 | case SPITZ_HP_OFF: | 96 | case SPITZ_HP_OFF: |
100 | 97 | ||
101 | /* jack removed, everything off */ | 98 | /* jack removed, everything off */ |
102 | snd_soc_dapm_set_endpoint(codec, "Headphone Jack", 0); | 99 | snd_soc_dapm_disable_pin(codec, "Headphone Jack"); |
103 | snd_soc_dapm_set_endpoint(codec, "Headset Jack", 0); | 100 | snd_soc_dapm_disable_pin(codec, "Headset Jack"); |
104 | snd_soc_dapm_set_endpoint(codec, "Mic Jack", 0); | 101 | snd_soc_dapm_disable_pin(codec, "Mic Jack"); |
105 | snd_soc_dapm_set_endpoint(codec, "Line Jack", 0); | 102 | snd_soc_dapm_disable_pin(codec, "Line Jack"); |
106 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); | 103 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_L); |
107 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); | 104 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_MUTE_R); |
108 | break; | 105 | break; |
109 | } | 106 | } |
110 | snd_soc_dapm_sync_endpoints(codec); | 107 | snd_soc_dapm_sync(codec); |
111 | } | 108 | } |
112 | 109 | ||
113 | static int spitz_startup(struct snd_pcm_substream *substream) | 110 | static int spitz_startup(struct snd_pcm_substream *substream) |
@@ -124,8 +121,8 @@ static int spitz_hw_params(struct snd_pcm_substream *substream, | |||
124 | struct snd_pcm_hw_params *params) | 121 | struct snd_pcm_hw_params *params) |
125 | { | 122 | { |
126 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 123 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
127 | struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; | 124 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
128 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 125 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
129 | unsigned int clk = 0; | 126 | unsigned int clk = 0; |
130 | int ret = 0; | 127 | int ret = 0; |
131 | 128 | ||
@@ -144,25 +141,25 @@ static int spitz_hw_params(struct snd_pcm_substream *substream, | |||
144 | } | 141 | } |
145 | 142 | ||
146 | /* set codec DAI configuration */ | 143 | /* set codec DAI configuration */ |
147 | ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | 144 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | |
148 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | 145 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); |
149 | if (ret < 0) | 146 | if (ret < 0) |
150 | return ret; | 147 | return ret; |
151 | 148 | ||
152 | /* set cpu DAI configuration */ | 149 | /* set cpu DAI configuration */ |
153 | ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | 150 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | |
154 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | 151 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); |
155 | if (ret < 0) | 152 | if (ret < 0) |
156 | return ret; | 153 | return ret; |
157 | 154 | ||
158 | /* set the codec system clock for DAC and ADC */ | 155 | /* set the codec system clock for DAC and ADC */ |
159 | ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8750_SYSCLK, clk, | 156 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk, |
160 | SND_SOC_CLOCK_IN); | 157 | SND_SOC_CLOCK_IN); |
161 | if (ret < 0) | 158 | if (ret < 0) |
162 | return ret; | 159 | return ret; |
163 | 160 | ||
164 | /* set the I2S system clock as input (unused) */ | 161 | /* set the I2S system clock as input (unused) */ |
165 | ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, | 162 | ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, |
166 | SND_SOC_CLOCK_IN); | 163 | SND_SOC_CLOCK_IN); |
167 | if (ret < 0) | 164 | if (ret < 0) |
168 | return ret; | 165 | return ret; |
@@ -250,7 +247,7 @@ static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = { | |||
250 | }; | 247 | }; |
251 | 248 | ||
252 | /* Spitz machine audio_map */ | 249 | /* Spitz machine audio_map */ |
253 | static const char *audio_map[][3] = { | 250 | static const struct snd_soc_dapm_route audio_map[] = { |
254 | 251 | ||
255 | /* headphone connected to LOUT1, ROUT1 */ | 252 | /* headphone connected to LOUT1, ROUT1 */ |
256 | {"Headphone Jack", NULL, "LOUT1"}, | 253 | {"Headphone Jack", NULL, "LOUT1"}, |
@@ -269,8 +266,6 @@ static const char *audio_map[][3] = { | |||
269 | 266 | ||
270 | /* line is connected to input 1 - no bias */ | 267 | /* line is connected to input 1 - no bias */ |
271 | {"LINPUT1", NULL, "Line Jack"}, | 268 | {"LINPUT1", NULL, "Line Jack"}, |
272 | |||
273 | {NULL, NULL, NULL}, | ||
274 | }; | 269 | }; |
275 | 270 | ||
276 | static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", | 271 | static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", |
@@ -296,13 +291,13 @@ static int spitz_wm8750_init(struct snd_soc_codec *codec) | |||
296 | int i, err; | 291 | int i, err; |
297 | 292 | ||
298 | /* NC codec pins */ | 293 | /* NC codec pins */ |
299 | snd_soc_dapm_set_endpoint(codec, "RINPUT1", 0); | 294 | snd_soc_dapm_disable_pin(codec, "RINPUT1"); |
300 | snd_soc_dapm_set_endpoint(codec, "LINPUT2", 0); | 295 | snd_soc_dapm_disable_pin(codec, "LINPUT2"); |
301 | snd_soc_dapm_set_endpoint(codec, "RINPUT2", 0); | 296 | snd_soc_dapm_disable_pin(codec, "RINPUT2"); |
302 | snd_soc_dapm_set_endpoint(codec, "LINPUT3", 0); | 297 | snd_soc_dapm_disable_pin(codec, "LINPUT3"); |
303 | snd_soc_dapm_set_endpoint(codec, "RINPUT3", 0); | 298 | snd_soc_dapm_disable_pin(codec, "RINPUT3"); |
304 | snd_soc_dapm_set_endpoint(codec, "OUT3", 0); | 299 | snd_soc_dapm_disable_pin(codec, "OUT3"); |
305 | snd_soc_dapm_set_endpoint(codec, "MONO", 0); | 300 | snd_soc_dapm_disable_pin(codec, "MONO"); |
306 | 301 | ||
307 | /* Add spitz specific controls */ | 302 | /* Add spitz specific controls */ |
308 | for (i = 0; i < ARRAY_SIZE(wm8750_spitz_controls); i++) { | 303 | for (i = 0; i < ARRAY_SIZE(wm8750_spitz_controls); i++) { |
@@ -313,15 +308,13 @@ static int spitz_wm8750_init(struct snd_soc_codec *codec) | |||
313 | } | 308 | } |
314 | 309 | ||
315 | /* Add spitz specific widgets */ | 310 | /* Add spitz specific widgets */ |
316 | for (i = 0; i < ARRAY_SIZE(wm8750_dapm_widgets); i++) | 311 | snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets, |
317 | snd_soc_dapm_new_control(codec, &wm8750_dapm_widgets[i]); | 312 | ARRAY_SIZE(wm8750_dapm_widgets)); |
318 | 313 | ||
319 | /* Set up spitz specific audio path audio_map */ | 314 | /* Set up spitz specific audio paths */ |
320 | for (i = 0; audio_map[i][0] != NULL; i++) | 315 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
321 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | ||
322 | audio_map[i][1], audio_map[i][2]); | ||
323 | 316 | ||
324 | snd_soc_dapm_sync_endpoints(codec); | 317 | snd_soc_dapm_sync(codec); |
325 | return 0; | 318 | return 0; |
326 | } | 319 | } |
327 | 320 | ||
diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index 7346d7e5d066..b6edb61a3a30 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c | |||
@@ -12,9 +12,6 @@ | |||
12 | * Free Software Foundation; either version 2 of the License, or (at your | 12 | * Free Software Foundation; either version 2 of the License, or (at your |
13 | * option) any later version. | 13 | * option) any later version. |
14 | * | 14 | * |
15 | * Revision history | ||
16 | * 30th Nov 2005 Initial version. | ||
17 | * | ||
18 | * GPIO's | 15 | * GPIO's |
19 | * 1 - Jack Insertion | 16 | * 1 - Jack Insertion |
20 | * 5 - Hookswitch (headset answer/hang up switch) | 17 | * 5 - Hookswitch (headset answer/hang up switch) |
@@ -55,29 +52,31 @@ static int tosa_spk_func; | |||
55 | 52 | ||
56 | static void tosa_ext_control(struct snd_soc_codec *codec) | 53 | static void tosa_ext_control(struct snd_soc_codec *codec) |
57 | { | 54 | { |
58 | int spk = 0, mic_int = 0, hp = 0, hs = 0; | ||
59 | |||
60 | /* set up jack connection */ | 55 | /* set up jack connection */ |
61 | switch (tosa_jack_func) { | 56 | switch (tosa_jack_func) { |
62 | case TOSA_HP: | 57 | case TOSA_HP: |
63 | hp = 1; | 58 | snd_soc_dapm_disable_pin(codec, "Mic (Internal)"); |
59 | snd_soc_dapm_enable_pin(codec, "Headphone Jack"); | ||
60 | snd_soc_dapm_disable_pin(codec, "Headset Jack"); | ||
64 | break; | 61 | break; |
65 | case TOSA_MIC_INT: | 62 | case TOSA_MIC_INT: |
66 | mic_int = 1; | 63 | snd_soc_dapm_enable_pin(codec, "Mic (Internal)"); |
64 | snd_soc_dapm_disable_pin(codec, "Headphone Jack"); | ||
65 | snd_soc_dapm_disable_pin(codec, "Headset Jack"); | ||
67 | break; | 66 | break; |
68 | case TOSA_HEADSET: | 67 | case TOSA_HEADSET: |
69 | hs = 1; | 68 | snd_soc_dapm_disable_pin(codec, "Mic (Internal)"); |
69 | snd_soc_dapm_disable_pin(codec, "Headphone Jack"); | ||
70 | snd_soc_dapm_enable_pin(codec, "Headset Jack"); | ||
70 | break; | 71 | break; |
71 | } | 72 | } |
72 | 73 | ||
73 | if (tosa_spk_func == TOSA_SPK_ON) | 74 | if (tosa_spk_func == TOSA_SPK_ON) |
74 | spk = 1; | 75 | snd_soc_dapm_enable_pin(codec, "Speaker"); |
76 | else | ||
77 | snd_soc_dapm_disable_pin(codec, "Speaker"); | ||
75 | 78 | ||
76 | snd_soc_dapm_set_endpoint(codec, "Speaker", spk); | 79 | snd_soc_dapm_sync(codec); |
77 | snd_soc_dapm_set_endpoint(codec, "Mic (Internal)", mic_int); | ||
78 | snd_soc_dapm_set_endpoint(codec, "Headphone Jack", hp); | ||
79 | snd_soc_dapm_set_endpoint(codec, "Headset Jack", hs); | ||
80 | snd_soc_dapm_sync_endpoints(codec); | ||
81 | } | 80 | } |
82 | 81 | ||
83 | static int tosa_startup(struct snd_pcm_substream *substream) | 82 | static int tosa_startup(struct snd_pcm_substream *substream) |
@@ -154,7 +153,7 @@ SND_SOC_DAPM_SPK("Speaker", NULL), | |||
154 | }; | 153 | }; |
155 | 154 | ||
156 | /* tosa audio map */ | 155 | /* tosa audio map */ |
157 | static const char *audio_map[][3] = { | 156 | static const struct snd_soc_dapm_route audio_map[] = { |
158 | 157 | ||
159 | /* headphone connected to HPOUTL, HPOUTR */ | 158 | /* headphone connected to HPOUTL, HPOUTR */ |
160 | {"Headphone Jack", NULL, "HPOUTL"}, | 159 | {"Headphone Jack", NULL, "HPOUTL"}, |
@@ -173,8 +172,6 @@ static const char *audio_map[][3] = { | |||
173 | {"Headset Jack", NULL, "HPOUTR"}, | 172 | {"Headset Jack", NULL, "HPOUTR"}, |
174 | {"LINEINR", NULL, "Mic Bias"}, | 173 | {"LINEINR", NULL, "Mic Bias"}, |
175 | {"Mic Bias", NULL, "Headset Jack"}, | 174 | {"Mic Bias", NULL, "Headset Jack"}, |
176 | |||
177 | {NULL, NULL, NULL}, | ||
178 | }; | 175 | }; |
179 | 176 | ||
180 | static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", | 177 | static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", |
@@ -196,8 +193,8 @@ static int tosa_ac97_init(struct snd_soc_codec *codec) | |||
196 | { | 193 | { |
197 | int i, err; | 194 | int i, err; |
198 | 195 | ||
199 | snd_soc_dapm_set_endpoint(codec, "OUT3", 0); | 196 | snd_soc_dapm_disable_pin(codec, "OUT3"); |
200 | snd_soc_dapm_set_endpoint(codec, "MONOOUT", 0); | 197 | snd_soc_dapm_disable_pin(codec, "MONOOUT"); |
201 | 198 | ||
202 | /* add tosa specific controls */ | 199 | /* add tosa specific controls */ |
203 | for (i = 0; i < ARRAY_SIZE(tosa_controls); i++) { | 200 | for (i = 0; i < ARRAY_SIZE(tosa_controls); i++) { |
@@ -208,17 +205,13 @@ static int tosa_ac97_init(struct snd_soc_codec *codec) | |||
208 | } | 205 | } |
209 | 206 | ||
210 | /* add tosa specific widgets */ | 207 | /* add tosa specific widgets */ |
211 | for (i = 0; i < ARRAY_SIZE(tosa_dapm_widgets); i++) { | 208 | snd_soc_dapm_new_controls(codec, tosa_dapm_widgets, |
212 | snd_soc_dapm_new_control(codec, &tosa_dapm_widgets[i]); | 209 | ARRAY_SIZE(tosa_dapm_widgets)); |
213 | } | ||
214 | 210 | ||
215 | /* set up tosa specific audio path audio_map */ | 211 | /* set up tosa specific audio path audio_map */ |
216 | for (i = 0; audio_map[i][0] != NULL; i++) { | 212 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); |
217 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | ||
218 | audio_map[i][1], audio_map[i][2]); | ||
219 | } | ||
220 | 213 | ||
221 | snd_soc_dapm_sync_endpoints(codec); | 214 | snd_soc_dapm_sync(codec); |
222 | return 0; | 215 | return 0; |
223 | } | 216 | } |
224 | 217 | ||
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index 1f6dbfc4caa8..b9f2353effeb 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig | |||
@@ -1,7 +1,6 @@ | |||
1 | config SND_S3C24XX_SOC | 1 | config SND_S3C24XX_SOC |
2 | tristate "SoC Audio for the Samsung S3C24XX chips" | 2 | tristate "SoC Audio for the Samsung S3C24XX chips" |
3 | depends on ARCH_S3C2410 && SND_SOC | 3 | depends on ARCH_S3C2410 |
4 | select SND_PCM | ||
5 | help | 4 | help |
6 | Say Y or M if you want to add support for codecs attached to | 5 | Say Y or M if you want to add support for codecs attached to |
7 | the S3C24XX AC97, I2S or SSP interface. You will also need | 6 | the S3C24XX AC97, I2S or SSP interface. You will also need |
@@ -16,7 +15,6 @@ config SND_S3C2412_SOC_I2S | |||
16 | config SND_S3C2443_SOC_AC97 | 15 | config SND_S3C2443_SOC_AC97 |
17 | tristate | 16 | tristate |
18 | select AC97_BUS | 17 | select AC97_BUS |
19 | select SND_AC97_CODEC | ||
20 | select SND_SOC_AC97_BUS | 18 | select SND_SOC_AC97_BUS |
21 | 19 | ||
22 | config SND_S3C24XX_SOC_NEO1973_WM8753 | 20 | config SND_S3C24XX_SOC_NEO1973_WM8753 |
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index 0e9d1c5f2484..4d7a9aa15f1a 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c | |||
@@ -10,10 +10,6 @@ | |||
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 | * Revision history | ||
14 | * 20th Jan 2007 Initial version. | ||
15 | * 05th Feb 2007 Rename all to Neo1973 | ||
16 | * | ||
17 | */ | 13 | */ |
18 | 14 | ||
19 | #include <linux/module.h> | 15 | #include <linux/module.h> |
@@ -26,6 +22,7 @@ | |||
26 | #include <sound/pcm.h> | 22 | #include <sound/pcm.h> |
27 | #include <sound/soc.h> | 23 | #include <sound/soc.h> |
28 | #include <sound/soc-dapm.h> | 24 | #include <sound/soc-dapm.h> |
25 | #include <sound/tlv.h> | ||
29 | 26 | ||
30 | #include <asm/mach-types.h> | 27 | #include <asm/mach-types.h> |
31 | #include <asm/hardware/scoop.h> | 28 | #include <asm/hardware/scoop.h> |
@@ -43,6 +40,14 @@ | |||
43 | #include "s3c24xx-pcm.h" | 40 | #include "s3c24xx-pcm.h" |
44 | #include "s3c24xx-i2s.h" | 41 | #include "s3c24xx-i2s.h" |
45 | 42 | ||
43 | /* Debugging stuff */ | ||
44 | #define S3C24XX_SOC_NEO1973_WM8753_DEBUG 0 | ||
45 | #if S3C24XX_SOC_NEO1973_WM8753_DEBUG | ||
46 | #define DBG(x...) printk(KERN_DEBUG "s3c24xx-soc-neo1973-wm8753: " x) | ||
47 | #else | ||
48 | #define DBG(x...) | ||
49 | #endif | ||
50 | |||
46 | /* define the scenarios */ | 51 | /* define the scenarios */ |
47 | #define NEO_AUDIO_OFF 0 | 52 | #define NEO_AUDIO_OFF 0 |
48 | #define NEO_GSM_CALL_AUDIO_HANDSET 1 | 53 | #define NEO_GSM_CALL_AUDIO_HANDSET 1 |
@@ -61,12 +66,14 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, | |||
61 | struct snd_pcm_hw_params *params) | 66 | struct snd_pcm_hw_params *params) |
62 | { | 67 | { |
63 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 68 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
64 | struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; | 69 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
65 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 70 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
66 | unsigned int pll_out = 0, bclk = 0; | 71 | unsigned int pll_out = 0, bclk = 0; |
67 | int ret = 0; | 72 | int ret = 0; |
68 | unsigned long iis_clkrate; | 73 | unsigned long iis_clkrate; |
69 | 74 | ||
75 | DBG("Entered %s\n", __func__); | ||
76 | |||
70 | iis_clkrate = s3c24xx_i2s_get_clockrate(); | 77 | iis_clkrate = s3c24xx_i2s_get_clockrate(); |
71 | 78 | ||
72 | switch (params_rate(params)) { | 79 | switch (params_rate(params)) { |
@@ -101,44 +108,44 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, | |||
101 | } | 108 | } |
102 | 109 | ||
103 | /* set codec DAI configuration */ | 110 | /* set codec DAI configuration */ |
104 | ret = codec_dai->dai_ops.set_fmt(codec_dai, | 111 | ret = snd_soc_dai_set_fmt(codec_dai, |
105 | SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | 112 | SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | |
106 | SND_SOC_DAIFMT_CBM_CFM); | 113 | SND_SOC_DAIFMT_CBM_CFM); |
107 | if (ret < 0) | 114 | if (ret < 0) |
108 | return ret; | 115 | return ret; |
109 | 116 | ||
110 | /* set cpu DAI configuration */ | 117 | /* set cpu DAI configuration */ |
111 | ret = cpu_dai->dai_ops.set_fmt(cpu_dai, | 118 | ret = snd_soc_dai_set_fmt(cpu_dai, |
112 | SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | 119 | SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | |
113 | SND_SOC_DAIFMT_CBM_CFM); | 120 | SND_SOC_DAIFMT_CBM_CFM); |
114 | if (ret < 0) | 121 | if (ret < 0) |
115 | return ret; | 122 | return ret; |
116 | 123 | ||
117 | /* set the codec system clock for DAC and ADC */ | 124 | /* set the codec system clock for DAC and ADC */ |
118 | ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8753_MCLK, pll_out, | 125 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out, |
119 | SND_SOC_CLOCK_IN); | 126 | SND_SOC_CLOCK_IN); |
120 | if (ret < 0) | 127 | if (ret < 0) |
121 | return ret; | 128 | return ret; |
122 | 129 | ||
123 | /* set MCLK division for sample rate */ | 130 | /* set MCLK division for sample rate */ |
124 | ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, | 131 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, |
125 | S3C2410_IISMOD_32FS); | 132 | S3C2410_IISMOD_32FS); |
126 | if (ret < 0) | 133 | if (ret < 0) |
127 | return ret; | 134 | return ret; |
128 | 135 | ||
129 | /* set codec BCLK division for sample rate */ | 136 | /* set codec BCLK division for sample rate */ |
130 | ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk); | 137 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk); |
131 | if (ret < 0) | 138 | if (ret < 0) |
132 | return ret; | 139 | return ret; |
133 | 140 | ||
134 | /* set prescaler division for sample rate */ | 141 | /* set prescaler division for sample rate */ |
135 | ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, | 142 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, |
136 | S3C24XX_PRESCALE(4, 4)); | 143 | S3C24XX_PRESCALE(4, 4)); |
137 | if (ret < 0) | 144 | if (ret < 0) |
138 | return ret; | 145 | return ret; |
139 | 146 | ||
140 | /* codec PLL input is PCLK/4 */ | 147 | /* codec PLL input is PCLK/4 */ |
141 | ret = codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL1, | 148 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, |
142 | iis_clkrate / 4, pll_out); | 149 | iis_clkrate / 4, pll_out); |
143 | if (ret < 0) | 150 | if (ret < 0) |
144 | return ret; | 151 | return ret; |
@@ -149,10 +156,12 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, | |||
149 | static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream) | 156 | static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream) |
150 | { | 157 | { |
151 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 158 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
152 | struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; | 159 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
160 | |||
161 | DBG("Entered %s\n", __func__); | ||
153 | 162 | ||
154 | /* disable the PLL */ | 163 | /* disable the PLL */ |
155 | return codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL1, 0, 0); | 164 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0); |
156 | } | 165 | } |
157 | 166 | ||
158 | /* | 167 | /* |
@@ -167,11 +176,13 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream, | |||
167 | struct snd_pcm_hw_params *params) | 176 | struct snd_pcm_hw_params *params) |
168 | { | 177 | { |
169 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 178 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
170 | struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; | 179 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
171 | unsigned int pcmdiv = 0; | 180 | unsigned int pcmdiv = 0; |
172 | int ret = 0; | 181 | int ret = 0; |
173 | unsigned long iis_clkrate; | 182 | unsigned long iis_clkrate; |
174 | 183 | ||
184 | DBG("Entered %s\n", __func__); | ||
185 | |||
175 | iis_clkrate = s3c24xx_i2s_get_clockrate(); | 186 | iis_clkrate = s3c24xx_i2s_get_clockrate(); |
176 | 187 | ||
177 | if (params_rate(params) != 8000) | 188 | if (params_rate(params) != 8000) |
@@ -183,24 +194,24 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream, | |||
183 | 194 | ||
184 | /* todo: gg check mode (DSP_B) against CSR datasheet */ | 195 | /* todo: gg check mode (DSP_B) against CSR datasheet */ |
185 | /* set codec DAI configuration */ | 196 | /* set codec DAI configuration */ |
186 | ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B | | 197 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B | |
187 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | 198 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); |
188 | if (ret < 0) | 199 | if (ret < 0) |
189 | return ret; | 200 | return ret; |
190 | 201 | ||
191 | /* set the codec system clock for DAC and ADC */ | 202 | /* set the codec system clock for DAC and ADC */ |
192 | ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8753_PCMCLK, 12288000, | 203 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK, 12288000, |
193 | SND_SOC_CLOCK_IN); | 204 | SND_SOC_CLOCK_IN); |
194 | if (ret < 0) | 205 | if (ret < 0) |
195 | return ret; | 206 | return ret; |
196 | 207 | ||
197 | /* set codec PCM division for sample rate */ | 208 | /* set codec PCM division for sample rate */ |
198 | ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv); | 209 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv); |
199 | if (ret < 0) | 210 | if (ret < 0) |
200 | return ret; | 211 | return ret; |
201 | 212 | ||
202 | /* configue and enable PLL for 12.288MHz output */ | 213 | /* configue and enable PLL for 12.288MHz output */ |
203 | ret = codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL2, | 214 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, |
204 | iis_clkrate / 4, 12288000); | 215 | iis_clkrate / 4, 12288000); |
205 | if (ret < 0) | 216 | if (ret < 0) |
206 | return ret; | 217 | return ret; |
@@ -211,10 +222,12 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream, | |||
211 | static int neo1973_voice_hw_free(struct snd_pcm_substream *substream) | 222 | static int neo1973_voice_hw_free(struct snd_pcm_substream *substream) |
212 | { | 223 | { |
213 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 224 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
214 | struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai; | 225 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
226 | |||
227 | DBG("Entered %s\n", __func__); | ||
215 | 228 | ||
216 | /* disable the PLL */ | 229 | /* disable the PLL */ |
217 | return codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL2, 0, 0); | 230 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0); |
218 | } | 231 | } |
219 | 232 | ||
220 | static struct snd_soc_ops neo1973_voice_ops = { | 233 | static struct snd_soc_ops neo1973_voice_ops = { |
@@ -233,79 +246,81 @@ static int neo1973_get_scenario(struct snd_kcontrol *kcontrol, | |||
233 | 246 | ||
234 | static int set_scenario_endpoints(struct snd_soc_codec *codec, int scenario) | 247 | static int set_scenario_endpoints(struct snd_soc_codec *codec, int scenario) |
235 | { | 248 | { |
249 | DBG("Entered %s\n", __func__); | ||
250 | |||
236 | switch (neo1973_scenario) { | 251 | switch (neo1973_scenario) { |
237 | case NEO_AUDIO_OFF: | 252 | case NEO_AUDIO_OFF: |
238 | snd_soc_dapm_set_endpoint(codec, "Audio Out", 0); | 253 | snd_soc_dapm_disable_pin(codec, "Audio Out"); |
239 | snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0); | 254 | snd_soc_dapm_disable_pin(codec, "GSM Line Out"); |
240 | snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0); | 255 | snd_soc_dapm_disable_pin(codec, "GSM Line In"); |
241 | snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); | 256 | snd_soc_dapm_disable_pin(codec, "Headset Mic"); |
242 | snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); | 257 | snd_soc_dapm_disable_pin(codec, "Call Mic"); |
243 | break; | 258 | break; |
244 | case NEO_GSM_CALL_AUDIO_HANDSET: | 259 | case NEO_GSM_CALL_AUDIO_HANDSET: |
245 | snd_soc_dapm_set_endpoint(codec, "Audio Out", 1); | 260 | snd_soc_dapm_enable_pin(codec, "Audio Out"); |
246 | snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 1); | 261 | snd_soc_dapm_enable_pin(codec, "GSM Line Out"); |
247 | snd_soc_dapm_set_endpoint(codec, "GSM Line In", 1); | 262 | snd_soc_dapm_enable_pin(codec, "GSM Line In"); |
248 | snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); | 263 | snd_soc_dapm_disable_pin(codec, "Headset Mic"); |
249 | snd_soc_dapm_set_endpoint(codec, "Call Mic", 1); | 264 | snd_soc_dapm_enable_pin(codec, "Call Mic"); |
250 | break; | 265 | break; |
251 | case NEO_GSM_CALL_AUDIO_HEADSET: | 266 | case NEO_GSM_CALL_AUDIO_HEADSET: |
252 | snd_soc_dapm_set_endpoint(codec, "Audio Out", 1); | 267 | snd_soc_dapm_enable_pin(codec, "Audio Out"); |
253 | snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 1); | 268 | snd_soc_dapm_enable_pin(codec, "GSM Line Out"); |
254 | snd_soc_dapm_set_endpoint(codec, "GSM Line In", 1); | 269 | snd_soc_dapm_enable_pin(codec, "GSM Line In"); |
255 | snd_soc_dapm_set_endpoint(codec, "Headset Mic", 1); | 270 | snd_soc_dapm_enable_pin(codec, "Headset Mic"); |
256 | snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); | 271 | snd_soc_dapm_disable_pin(codec, "Call Mic"); |
257 | break; | 272 | break; |
258 | case NEO_GSM_CALL_AUDIO_BLUETOOTH: | 273 | case NEO_GSM_CALL_AUDIO_BLUETOOTH: |
259 | snd_soc_dapm_set_endpoint(codec, "Audio Out", 0); | 274 | snd_soc_dapm_disable_pin(codec, "Audio Out"); |
260 | snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 1); | 275 | snd_soc_dapm_enable_pin(codec, "GSM Line Out"); |
261 | snd_soc_dapm_set_endpoint(codec, "GSM Line In", 1); | 276 | snd_soc_dapm_enable_pin(codec, "GSM Line In"); |
262 | snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); | 277 | snd_soc_dapm_disable_pin(codec, "Headset Mic"); |
263 | snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); | 278 | snd_soc_dapm_disable_pin(codec, "Call Mic"); |
264 | break; | 279 | break; |
265 | case NEO_STEREO_TO_SPEAKERS: | 280 | case NEO_STEREO_TO_SPEAKERS: |
266 | snd_soc_dapm_set_endpoint(codec, "Audio Out", 1); | 281 | snd_soc_dapm_enable_pin(codec, "Audio Out"); |
267 | snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0); | 282 | snd_soc_dapm_disable_pin(codec, "GSM Line Out"); |
268 | snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0); | 283 | snd_soc_dapm_disable_pin(codec, "GSM Line In"); |
269 | snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); | 284 | snd_soc_dapm_disable_pin(codec, "Headset Mic"); |
270 | snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); | 285 | snd_soc_dapm_disable_pin(codec, "Call Mic"); |
271 | break; | 286 | break; |
272 | case NEO_STEREO_TO_HEADPHONES: | 287 | case NEO_STEREO_TO_HEADPHONES: |
273 | snd_soc_dapm_set_endpoint(codec, "Audio Out", 1); | 288 | snd_soc_dapm_enable_pin(codec, "Audio Out"); |
274 | snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0); | 289 | snd_soc_dapm_disable_pin(codec, "GSM Line Out"); |
275 | snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0); | 290 | snd_soc_dapm_disable_pin(codec, "GSM Line In"); |
276 | snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); | 291 | snd_soc_dapm_disable_pin(codec, "Headset Mic"); |
277 | snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); | 292 | snd_soc_dapm_disable_pin(codec, "Call Mic"); |
278 | break; | 293 | break; |
279 | case NEO_CAPTURE_HANDSET: | 294 | case NEO_CAPTURE_HANDSET: |
280 | snd_soc_dapm_set_endpoint(codec, "Audio Out", 0); | 295 | snd_soc_dapm_disable_pin(codec, "Audio Out"); |
281 | snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0); | 296 | snd_soc_dapm_disable_pin(codec, "GSM Line Out"); |
282 | snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0); | 297 | snd_soc_dapm_disable_pin(codec, "GSM Line In"); |
283 | snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); | 298 | snd_soc_dapm_disable_pin(codec, "Headset Mic"); |
284 | snd_soc_dapm_set_endpoint(codec, "Call Mic", 1); | 299 | snd_soc_dapm_enable_pin(codec, "Call Mic"); |
285 | break; | 300 | break; |
286 | case NEO_CAPTURE_HEADSET: | 301 | case NEO_CAPTURE_HEADSET: |
287 | snd_soc_dapm_set_endpoint(codec, "Audio Out", 0); | 302 | snd_soc_dapm_disable_pin(codec, "Audio Out"); |
288 | snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0); | 303 | snd_soc_dapm_disable_pin(codec, "GSM Line Out"); |
289 | snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0); | 304 | snd_soc_dapm_disable_pin(codec, "GSM Line In"); |
290 | snd_soc_dapm_set_endpoint(codec, "Headset Mic", 1); | 305 | snd_soc_dapm_enable_pin(codec, "Headset Mic"); |
291 | snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); | 306 | snd_soc_dapm_disable_pin(codec, "Call Mic"); |
292 | break; | 307 | break; |
293 | case NEO_CAPTURE_BLUETOOTH: | 308 | case NEO_CAPTURE_BLUETOOTH: |
294 | snd_soc_dapm_set_endpoint(codec, "Audio Out", 0); | 309 | snd_soc_dapm_disable_pin(codec, "Audio Out"); |
295 | snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0); | 310 | snd_soc_dapm_disable_pin(codec, "GSM Line Out"); |
296 | snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0); | 311 | snd_soc_dapm_disable_pin(codec, "GSM Line In"); |
297 | snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); | 312 | snd_soc_dapm_disable_pin(codec, "Headset Mic"); |
298 | snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); | 313 | snd_soc_dapm_disable_pin(codec, "Call Mic"); |
299 | break; | 314 | break; |
300 | default: | 315 | default: |
301 | snd_soc_dapm_set_endpoint(codec, "Audio Out", 0); | 316 | snd_soc_dapm_disable_pin(codec, "Audio Out"); |
302 | snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0); | 317 | snd_soc_dapm_disable_pin(codec, "GSM Line Out"); |
303 | snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0); | 318 | snd_soc_dapm_disable_pin(codec, "GSM Line In"); |
304 | snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0); | 319 | snd_soc_dapm_disable_pin(codec, "Headset Mic"); |
305 | snd_soc_dapm_set_endpoint(codec, "Call Mic", 0); | 320 | snd_soc_dapm_disable_pin(codec, "Call Mic"); |
306 | } | 321 | } |
307 | 322 | ||
308 | snd_soc_dapm_sync_endpoints(codec); | 323 | snd_soc_dapm_sync(codec); |
309 | 324 | ||
310 | return 0; | 325 | return 0; |
311 | } | 326 | } |
@@ -315,6 +330,8 @@ static int neo1973_set_scenario(struct snd_kcontrol *kcontrol, | |||
315 | { | 330 | { |
316 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 331 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
317 | 332 | ||
333 | DBG("Entered %s\n", __func__); | ||
334 | |||
318 | if (neo1973_scenario == ucontrol->value.integer.value[0]) | 335 | if (neo1973_scenario == ucontrol->value.integer.value[0]) |
319 | return 0; | 336 | return 0; |
320 | 337 | ||
@@ -327,6 +344,8 @@ static u8 lm4857_regs[4] = {0x00, 0x40, 0x80, 0xC0}; | |||
327 | 344 | ||
328 | static void lm4857_write_regs(void) | 345 | static void lm4857_write_regs(void) |
329 | { | 346 | { |
347 | DBG("Entered %s\n", __func__); | ||
348 | |||
330 | if (i2c_master_send(i2c, lm4857_regs, 4) != 4) | 349 | if (i2c_master_send(i2c, lm4857_regs, 4) != 4) |
331 | printk(KERN_ERR "lm4857: i2c write failed\n"); | 350 | printk(KERN_ERR "lm4857: i2c write failed\n"); |
332 | } | 351 | } |
@@ -338,6 +357,8 @@ static int lm4857_get_reg(struct snd_kcontrol *kcontrol, | |||
338 | int shift = (kcontrol->private_value >> 8) & 0x0F; | 357 | int shift = (kcontrol->private_value >> 8) & 0x0F; |
339 | int mask = (kcontrol->private_value >> 16) & 0xFF; | 358 | int mask = (kcontrol->private_value >> 16) & 0xFF; |
340 | 359 | ||
360 | DBG("Entered %s\n", __func__); | ||
361 | |||
341 | ucontrol->value.integer.value[0] = (lm4857_regs[reg] >> shift) & mask; | 362 | ucontrol->value.integer.value[0] = (lm4857_regs[reg] >> shift) & mask; |
342 | return 0; | 363 | return 0; |
343 | } | 364 | } |
@@ -364,6 +385,8 @@ static int lm4857_get_mode(struct snd_kcontrol *kcontrol, | |||
364 | { | 385 | { |
365 | u8 value = lm4857_regs[LM4857_CTRL] & 0x0F; | 386 | u8 value = lm4857_regs[LM4857_CTRL] & 0x0F; |
366 | 387 | ||
388 | DBG("Entered %s\n", __func__); | ||
389 | |||
367 | if (value) | 390 | if (value) |
368 | value -= 5; | 391 | value -= 5; |
369 | 392 | ||
@@ -376,6 +399,8 @@ static int lm4857_set_mode(struct snd_kcontrol *kcontrol, | |||
376 | { | 399 | { |
377 | u8 value = ucontrol->value.integer.value[0]; | 400 | u8 value = ucontrol->value.integer.value[0]; |
378 | 401 | ||
402 | DBG("Entered %s\n", __func__); | ||
403 | |||
379 | if (value) | 404 | if (value) |
380 | value += 5; | 405 | value += 5; |
381 | 406 | ||
@@ -397,8 +422,7 @@ static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = { | |||
397 | }; | 422 | }; |
398 | 423 | ||
399 | 424 | ||
400 | /* example machine audio_mapnections */ | 425 | static const struct snd_soc_dapm_route dapm_routes[] = { |
401 | static const char *audio_map[][3] = { | ||
402 | 426 | ||
403 | /* Connections to the lm4857 amp */ | 427 | /* Connections to the lm4857 amp */ |
404 | {"Audio Out", NULL, "LOUT1"}, | 428 | {"Audio Out", NULL, "LOUT1"}, |
@@ -421,8 +445,6 @@ static const char *audio_map[][3] = { | |||
421 | 445 | ||
422 | /* Connect the ALC pins */ | 446 | /* Connect the ALC pins */ |
423 | {"ACIN", NULL, "ACOP"}, | 447 | {"ACIN", NULL, "ACOP"}, |
424 | |||
425 | {NULL, NULL, NULL}, | ||
426 | }; | 448 | }; |
427 | 449 | ||
428 | static const char *lm4857_mode[] = { | 450 | static const char *lm4857_mode[] = { |
@@ -453,13 +475,16 @@ static const struct soc_enum neo_scenario_enum[] = { | |||
453 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(neo_scenarios), neo_scenarios), | 475 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(neo_scenarios), neo_scenarios), |
454 | }; | 476 | }; |
455 | 477 | ||
478 | static const DECLARE_TLV_DB_SCALE(stereo_tlv, -4050, 150, 0); | ||
479 | static const DECLARE_TLV_DB_SCALE(mono_tlv, -3450, 150, 0); | ||
480 | |||
456 | static const struct snd_kcontrol_new wm8753_neo1973_controls[] = { | 481 | static const struct snd_kcontrol_new wm8753_neo1973_controls[] = { |
457 | SOC_SINGLE_EXT("Amp Left Playback Volume", LM4857_LVOL, 0, 31, 0, | 482 | SOC_SINGLE_EXT_TLV("Amp Left Playback Volume", LM4857_LVOL, 0, 31, 0, |
458 | lm4857_get_reg, lm4857_set_reg), | 483 | lm4857_get_reg, lm4857_set_reg, stereo_tlv), |
459 | SOC_SINGLE_EXT("Amp Right Playback Volume", LM4857_RVOL, 0, 31, 0, | 484 | SOC_SINGLE_EXT_TLV("Amp Right Playback Volume", LM4857_RVOL, 0, 31, 0, |
460 | lm4857_get_reg, lm4857_set_reg), | 485 | lm4857_get_reg, lm4857_set_reg, stereo_tlv), |
461 | SOC_SINGLE_EXT("Amp Mono Playback Volume", LM4857_MVOL, 0, 31, 0, | 486 | SOC_SINGLE_EXT_TLV("Amp Mono Playback Volume", LM4857_MVOL, 0, 31, 0, |
462 | lm4857_get_reg, lm4857_set_reg), | 487 | lm4857_get_reg, lm4857_set_reg, mono_tlv), |
463 | SOC_ENUM_EXT("Amp Mode", lm4857_mode_enum[0], | 488 | SOC_ENUM_EXT("Amp Mode", lm4857_mode_enum[0], |
464 | lm4857_get_mode, lm4857_set_mode), | 489 | lm4857_get_mode, lm4857_set_mode), |
465 | SOC_ENUM_EXT("Neo Mode", neo_scenario_enum[0], | 490 | SOC_ENUM_EXT("Neo Mode", neo_scenario_enum[0], |
@@ -483,21 +508,23 @@ static int neo1973_wm8753_init(struct snd_soc_codec *codec) | |||
483 | { | 508 | { |
484 | int i, err; | 509 | int i, err; |
485 | 510 | ||
511 | DBG("Entered %s\n", __func__); | ||
512 | |||
486 | /* set up NC codec pins */ | 513 | /* set up NC codec pins */ |
487 | snd_soc_dapm_set_endpoint(codec, "LOUT2", 0); | 514 | snd_soc_dapm_disable_pin(codec, "LOUT2"); |
488 | snd_soc_dapm_set_endpoint(codec, "ROUT2", 0); | 515 | snd_soc_dapm_disable_pin(codec, "ROUT2"); |
489 | snd_soc_dapm_set_endpoint(codec, "OUT3", 0); | 516 | snd_soc_dapm_disable_pin(codec, "OUT3"); |
490 | snd_soc_dapm_set_endpoint(codec, "OUT4", 0); | 517 | snd_soc_dapm_disable_pin(codec, "OUT4"); |
491 | snd_soc_dapm_set_endpoint(codec, "LINE1", 0); | 518 | snd_soc_dapm_disable_pin(codec, "LINE1"); |
492 | snd_soc_dapm_set_endpoint(codec, "LINE2", 0); | 519 | snd_soc_dapm_disable_pin(codec, "LINE2"); |
493 | 520 | ||
494 | 521 | ||
495 | /* set endpoints to default mode */ | 522 | /* set endpoints to default mode */ |
496 | set_scenario_endpoints(codec, NEO_AUDIO_OFF); | 523 | set_scenario_endpoints(codec, NEO_AUDIO_OFF); |
497 | 524 | ||
498 | /* Add neo1973 specific widgets */ | 525 | /* Add neo1973 specific widgets */ |
499 | for (i = 0; i < ARRAY_SIZE(wm8753_dapm_widgets); i++) | 526 | snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets, |
500 | snd_soc_dapm_new_control(codec, &wm8753_dapm_widgets[i]); | 527 | ARRAY_SIZE(wm8753_dapm_widgets)); |
501 | 528 | ||
502 | /* add neo1973 specific controls */ | 529 | /* add neo1973 specific controls */ |
503 | for (i = 0; i < ARRAY_SIZE(wm8753_neo1973_controls); i++) { | 530 | for (i = 0; i < ARRAY_SIZE(wm8753_neo1973_controls); i++) { |
@@ -508,20 +535,18 @@ static int neo1973_wm8753_init(struct snd_soc_codec *codec) | |||
508 | return err; | 535 | return err; |
509 | } | 536 | } |
510 | 537 | ||
511 | /* set up neo1973 specific audio path audio_mapnects */ | 538 | /* set up neo1973 specific audio routes */ |
512 | for (i = 0; audio_map[i][0] != NULL; i++) { | 539 | err = snd_soc_dapm_add_routes(codec, dapm_routes, |
513 | snd_soc_dapm_connect_input(codec, audio_map[i][0], | 540 | ARRAY_SIZE(dapm_routes)); |
514 | audio_map[i][1], audio_map[i][2]); | ||
515 | } | ||
516 | 541 | ||
517 | snd_soc_dapm_sync_endpoints(codec); | 542 | snd_soc_dapm_sync(codec); |
518 | return 0; | 543 | return 0; |
519 | } | 544 | } |
520 | 545 | ||
521 | /* | 546 | /* |
522 | * BT Codec DAI | 547 | * BT Codec DAI |
523 | */ | 548 | */ |
524 | static struct snd_soc_cpu_dai bt_dai = { | 549 | static struct snd_soc_dai bt_dai = { |
525 | .name = "Bluetooth", | 550 | .name = "Bluetooth", |
526 | .id = 0, | 551 | .id = 0, |
527 | .type = SND_SOC_DAI_PCM, | 552 | .type = SND_SOC_DAI_PCM, |
@@ -583,6 +608,8 @@ static int lm4857_amp_probe(struct i2c_adapter *adap, int addr, int kind) | |||
583 | { | 608 | { |
584 | int ret; | 609 | int ret; |
585 | 610 | ||
611 | DBG("Entered %s\n", __func__); | ||
612 | |||
586 | client_template.adapter = adap; | 613 | client_template.adapter = adap; |
587 | client_template.addr = addr; | 614 | client_template.addr = addr; |
588 | 615 | ||
@@ -606,6 +633,8 @@ exit_err: | |||
606 | 633 | ||
607 | static int lm4857_i2c_detach(struct i2c_client *client) | 634 | static int lm4857_i2c_detach(struct i2c_client *client) |
608 | { | 635 | { |
636 | DBG("Entered %s\n", __func__); | ||
637 | |||
609 | i2c_detach_client(client); | 638 | i2c_detach_client(client); |
610 | kfree(client); | 639 | kfree(client); |
611 | return 0; | 640 | return 0; |
@@ -613,6 +642,8 @@ static int lm4857_i2c_detach(struct i2c_client *client) | |||
613 | 642 | ||
614 | static int lm4857_i2c_attach(struct i2c_adapter *adap) | 643 | static int lm4857_i2c_attach(struct i2c_adapter *adap) |
615 | { | 644 | { |
645 | DBG("Entered %s\n", __func__); | ||
646 | |||
616 | return i2c_probe(adap, &addr_data, lm4857_amp_probe); | 647 | return i2c_probe(adap, &addr_data, lm4857_amp_probe); |
617 | } | 648 | } |
618 | 649 | ||
@@ -620,6 +651,8 @@ static u8 lm4857_state; | |||
620 | 651 | ||
621 | static int lm4857_suspend(struct i2c_client *dev, pm_message_t state) | 652 | static int lm4857_suspend(struct i2c_client *dev, pm_message_t state) |
622 | { | 653 | { |
654 | DBG("Entered %s\n", __func__); | ||
655 | |||
623 | dev_dbg(&dev->dev, "lm4857_suspend\n"); | 656 | dev_dbg(&dev->dev, "lm4857_suspend\n"); |
624 | lm4857_state = lm4857_regs[LM4857_CTRL] & 0xf; | 657 | lm4857_state = lm4857_regs[LM4857_CTRL] & 0xf; |
625 | if (lm4857_state) { | 658 | if (lm4857_state) { |
@@ -631,6 +664,8 @@ static int lm4857_suspend(struct i2c_client *dev, pm_message_t state) | |||
631 | 664 | ||
632 | static int lm4857_resume(struct i2c_client *dev) | 665 | static int lm4857_resume(struct i2c_client *dev) |
633 | { | 666 | { |
667 | DBG("Entered %s\n", __func__); | ||
668 | |||
634 | if (lm4857_state) { | 669 | if (lm4857_state) { |
635 | lm4857_regs[LM4857_CTRL] |= (lm4857_state & 0x0f); | 670 | lm4857_regs[LM4857_CTRL] |= (lm4857_state & 0x0f); |
636 | lm4857_write_regs(); | 671 | lm4857_write_regs(); |
@@ -640,6 +675,8 @@ static int lm4857_resume(struct i2c_client *dev) | |||
640 | 675 | ||
641 | static void lm4857_shutdown(struct i2c_client *dev) | 676 | static void lm4857_shutdown(struct i2c_client *dev) |
642 | { | 677 | { |
678 | DBG("Entered %s\n", __func__); | ||
679 | |||
643 | dev_dbg(&dev->dev, "lm4857_shutdown\n"); | 680 | dev_dbg(&dev->dev, "lm4857_shutdown\n"); |
644 | lm4857_regs[LM4857_CTRL] &= 0xf0; | 681 | lm4857_regs[LM4857_CTRL] &= 0xf0; |
645 | lm4857_write_regs(); | 682 | lm4857_write_regs(); |
@@ -671,6 +708,8 @@ static int __init neo1973_init(void) | |||
671 | { | 708 | { |
672 | int ret; | 709 | int ret; |
673 | 710 | ||
711 | DBG("Entered %s\n", __func__); | ||
712 | |||
674 | neo1973_snd_device = platform_device_alloc("soc-audio", -1); | 713 | neo1973_snd_device = platform_device_alloc("soc-audio", -1); |
675 | if (!neo1973_snd_device) | 714 | if (!neo1973_snd_device) |
676 | return -ENOMEM; | 715 | return -ENOMEM; |
@@ -691,6 +730,8 @@ static int __init neo1973_init(void) | |||
691 | 730 | ||
692 | static void __exit neo1973_exit(void) | 731 | static void __exit neo1973_exit(void) |
693 | { | 732 | { |
733 | DBG("Entered %s\n", __func__); | ||
734 | |||
694 | i2c_del_driver(&lm4857_i2c_driver); | 735 | i2c_del_driver(&lm4857_i2c_driver); |
695 | platform_device_unregister(neo1973_snd_device); | 736 | platform_device_unregister(neo1973_snd_device); |
696 | } | 737 | } |
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c index c4a46dd589b3..ee4676ed1283 100644 --- a/sound/soc/s3c24xx/s3c2412-i2s.c +++ b/sound/soc/s3c24xx/s3c2412-i2s.c | |||
@@ -295,7 +295,7 @@ static inline int s3c2412_snd_is_clkmaster(void) | |||
295 | /* | 295 | /* |
296 | * Set S3C2412 I2S DAI format | 296 | * Set S3C2412 I2S DAI format |
297 | */ | 297 | */ |
298 | static int s3c2412_i2s_set_fmt(struct snd_soc_cpu_dai *cpu_dai, | 298 | static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai, |
299 | unsigned int fmt) | 299 | unsigned int fmt) |
300 | { | 300 | { |
301 | u32 iismod; | 301 | u32 iismod; |
@@ -500,7 +500,7 @@ EXPORT_SYMBOL_GPL(s3c2412_iis_calc_rate); | |||
500 | /* | 500 | /* |
501 | * Set S3C2412 Clock source | 501 | * Set S3C2412 Clock source |
502 | */ | 502 | */ |
503 | static int s3c2412_i2s_set_sysclk(struct snd_soc_cpu_dai *cpu_dai, | 503 | static int s3c2412_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, |
504 | int clk_id, unsigned int freq, int dir) | 504 | int clk_id, unsigned int freq, int dir) |
505 | { | 505 | { |
506 | u32 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD); | 506 | u32 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD); |
@@ -528,7 +528,7 @@ static int s3c2412_i2s_set_sysclk(struct snd_soc_cpu_dai *cpu_dai, | |||
528 | /* | 528 | /* |
529 | * Set S3C2412 Clock dividers | 529 | * Set S3C2412 Clock dividers |
530 | */ | 530 | */ |
531 | static int s3c2412_i2s_set_clkdiv(struct snd_soc_cpu_dai *cpu_dai, | 531 | static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai, |
532 | int div_id, int div) | 532 | int div_id, int div) |
533 | { | 533 | { |
534 | struct s3c2412_i2s_info *i2s = &s3c2412_i2s; | 534 | struct s3c2412_i2s_info *i2s = &s3c2412_i2s; |
@@ -601,7 +601,8 @@ struct clk *s3c2412_get_iisclk(void) | |||
601 | EXPORT_SYMBOL_GPL(s3c2412_get_iisclk); | 601 | EXPORT_SYMBOL_GPL(s3c2412_get_iisclk); |
602 | 602 | ||
603 | 603 | ||
604 | static int s3c2412_i2s_probe(struct platform_device *pdev) | 604 | static int s3c2412_i2s_probe(struct platform_device *pdev, |
605 | struct snd_soc_dai *dai) | ||
605 | { | 606 | { |
606 | DBG("Entered %s\n", __func__); | 607 | DBG("Entered %s\n", __func__); |
607 | 608 | ||
@@ -647,7 +648,7 @@ static int s3c2412_i2s_probe(struct platform_device *pdev) | |||
647 | 648 | ||
648 | #ifdef CONFIG_PM | 649 | #ifdef CONFIG_PM |
649 | static int s3c2412_i2s_suspend(struct platform_device *dev, | 650 | static int s3c2412_i2s_suspend(struct platform_device *dev, |
650 | struct snd_soc_cpu_dai *dai) | 651 | struct snd_soc_dai *dai) |
651 | { | 652 | { |
652 | struct s3c2412_i2s_info *i2s = &s3c2412_i2s; | 653 | struct s3c2412_i2s_info *i2s = &s3c2412_i2s; |
653 | u32 iismod; | 654 | u32 iismod; |
@@ -675,7 +676,7 @@ static int s3c2412_i2s_suspend(struct platform_device *dev, | |||
675 | } | 676 | } |
676 | 677 | ||
677 | static int s3c2412_i2s_resume(struct platform_device *pdev, | 678 | static int s3c2412_i2s_resume(struct platform_device *pdev, |
678 | struct snd_soc_cpu_dai *dai) | 679 | struct snd_soc_dai *dai) |
679 | { | 680 | { |
680 | struct s3c2412_i2s_info *i2s = &s3c2412_i2s; | 681 | struct s3c2412_i2s_info *i2s = &s3c2412_i2s; |
681 | 682 | ||
@@ -707,7 +708,7 @@ static int s3c2412_i2s_resume(struct platform_device *pdev, | |||
707 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | 708 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ |
708 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) | 709 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) |
709 | 710 | ||
710 | struct snd_soc_cpu_dai s3c2412_i2s_dai = { | 711 | struct snd_soc_dai s3c2412_i2s_dai = { |
711 | .name = "s3c2412-i2s", | 712 | .name = "s3c2412-i2s", |
712 | .id = 0, | 713 | .id = 0, |
713 | .type = SND_SOC_DAI_I2S, | 714 | .type = SND_SOC_DAI_I2S, |
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.h b/sound/soc/s3c24xx/s3c2412-i2s.h index 27f48e1ffa86..aac08a25e541 100644 --- a/sound/soc/s3c24xx/s3c2412-i2s.h +++ b/sound/soc/s3c24xx/s3c2412-i2s.h | |||
@@ -24,7 +24,7 @@ | |||
24 | 24 | ||
25 | extern struct clk *s3c2412_get_iisclk(void); | 25 | extern struct clk *s3c2412_get_iisclk(void); |
26 | 26 | ||
27 | extern struct snd_soc_cpu_dai s3c2412_i2s_dai; | 27 | extern struct snd_soc_dai s3c2412_i2s_dai; |
28 | 28 | ||
29 | struct s3c2412_rate_calc { | 29 | struct s3c2412_rate_calc { |
30 | unsigned int clk_div; /* for prescaler */ | 30 | unsigned int clk_div; /* for prescaler */ |
diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c index e81d9a6c83da..783349b7fede 100644 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/sound/soc/s3c24xx/s3c2443-ac97.c | |||
@@ -10,9 +10,6 @@ | |||
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 | * | ||
14 | * Revision history | ||
15 | * 21st Mar 2007 Initial Version | ||
16 | */ | 13 | */ |
17 | 14 | ||
18 | #include <linux/init.h> | 15 | #include <linux/init.h> |
@@ -212,7 +209,8 @@ static struct s3c24xx_pcm_dma_params s3c2443_ac97_mic_mono_in = { | |||
212 | .dma_size = 4, | 209 | .dma_size = 4, |
213 | }; | 210 | }; |
214 | 211 | ||
215 | static int s3c2443_ac97_probe(struct platform_device *pdev) | 212 | static int s3c2443_ac97_probe(struct platform_device *pdev, |
213 | struct snd_soc_dai *dai) | ||
216 | { | 214 | { |
217 | int ret; | 215 | int ret; |
218 | u32 ac_glbctrl; | 216 | u32 ac_glbctrl; |
@@ -263,7 +261,8 @@ static int s3c2443_ac97_probe(struct platform_device *pdev) | |||
263 | return ret; | 261 | return ret; |
264 | } | 262 | } |
265 | 263 | ||
266 | static void s3c2443_ac97_remove(struct platform_device *pdev) | 264 | static void s3c2443_ac97_remove(struct platform_device *pdev, |
265 | struct snd_soc_dai *dai) | ||
267 | { | 266 | { |
268 | free_irq(IRQ_S3C244x_AC97, NULL); | 267 | free_irq(IRQ_S3C244x_AC97, NULL); |
269 | clk_disable(s3c24xx_ac97.ac97_clk); | 268 | clk_disable(s3c24xx_ac97.ac97_clk); |
@@ -275,7 +274,7 @@ static int s3c2443_ac97_hw_params(struct snd_pcm_substream *substream, | |||
275 | struct snd_pcm_hw_params *params) | 274 | struct snd_pcm_hw_params *params) |
276 | { | 275 | { |
277 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 276 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
278 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 277 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
279 | 278 | ||
280 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 279 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
281 | cpu_dai->dma_data = &s3c2443_ac97_pcm_stereo_out; | 280 | cpu_dai->dma_data = &s3c2443_ac97_pcm_stereo_out; |
@@ -317,7 +316,7 @@ static int s3c2443_ac97_hw_mic_params(struct snd_pcm_substream *substream, | |||
317 | struct snd_pcm_hw_params *params) | 316 | struct snd_pcm_hw_params *params) |
318 | { | 317 | { |
319 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 318 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
320 | struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai; | 319 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
321 | 320 | ||
322 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 321 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
323 | return -ENODEV; | 322 | return -ENODEV; |
@@ -353,7 +352,7 @@ static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream, | |||
353 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ | 352 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ |
354 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) | 353 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) |
355 | 354 | ||
356 | struct snd_soc_cpu_dai s3c2443_ac97_dai[] = { | 355 | struct snd_soc_dai s3c2443_ac97_dai[] = { |
357 | { | 356 | { |
358 | .name = "s3c2443-ac97", | 357 | .name = "s3c2443-ac97", |
359 | .id = 0, | 358 | .id = 0, |
diff --git a/sound/soc/s3c24xx/s3c24xx-ac97.h b/sound/soc/s3c24xx/s3c24xx-ac97.h index bf03e8ed16c3..a96dcadf28b4 100644 --- a/sound/soc/s3c24xx/s3c24xx-ac97.h +++ b/sound/soc/s3c24xx/s3c24xx-ac97.h | |||
@@ -26,6 +26,6 @@ | |||
26 | #define IRQ_S3C244x_AC97 IRQ_S3C2443_AC97 | 26 | #define IRQ_S3C244x_AC97 IRQ_S3C2443_AC97 |
27 | #endif | 27 | #endif |
28 | 28 | ||
29 | extern struct snd_soc_cpu_dai s3c2443_ac97_dai[]; | 29 | extern struct snd_soc_dai s3c2443_ac97_dai[]; |
30 | 30 | ||
31 | #endif /*S3C24XXAC97_H_*/ | 31 | #endif /*S3C24XXAC97_H_*/ |
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index 1ed6afd45459..397524282b57 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c | |||
@@ -12,11 +12,6 @@ | |||
12 | * under the terms of the GNU General Public License as published by the | 12 | * under the terms of the GNU General Public License as published by the |
13 | * Free Software Foundation; either version 2 of the License, or (at your | 13 | * Free Software Foundation; either version 2 of the License, or (at your |
14 | * option) any later version. | 14 | * option) any later version. |
15 | * | ||
16 | * | ||
17 | * Revision history | ||
18 | * 11th Dec 2006 Merged with Simtec driver | ||
19 | * 10th Nov 2006 Initial version. | ||
20 | */ | 15 | */ |
21 | 16 | ||
22 | #include <linux/init.h> | 17 | #include <linux/init.h> |
@@ -180,7 +175,7 @@ static void s3c24xx_snd_rxctrl(int on) | |||
180 | static int s3c24xx_snd_lrsync(void) | 175 | static int s3c24xx_snd_lrsync(void) |
181 | { | 176 | { |
182 | u32 iiscon; | 177 | u32 iiscon; |
183 | unsigned long timeout = jiffies + msecs_to_jiffies(5); | 178 | int timeout = 50; /* 5ms */ |
184 | 179 | ||
185 | DBG("Entered %s\n", __func__); | 180 | DBG("Entered %s\n", __func__); |
186 | 181 | ||
@@ -189,8 +184,9 @@ static int s3c24xx_snd_lrsync(void) | |||
189 | if (iiscon & S3C2410_IISCON_LRINDEX) | 184 | if (iiscon & S3C2410_IISCON_LRINDEX) |
190 | break; | 185 | break; |
191 | 186 | ||
192 | if (time_after(jiffies, timeout)) | 187 | if (!timeout--) |
193 | return -ETIMEDOUT; | 188 | return -ETIMEDOUT; |
189 | udelay(100); | ||
194 | } | 190 | } |
195 | 191 | ||
196 | return 0; | 192 | return 0; |
@@ -209,7 +205,7 @@ static inline int s3c24xx_snd_is_clkmaster(void) | |||
209 | /* | 205 | /* |
210 | * Set S3C24xx I2S DAI format | 206 | * Set S3C24xx I2S DAI format |
211 | */ | 207 | */ |
212 | static int s3c24xx_i2s_set_fmt(struct snd_soc_cpu_dai *cpu_dai, | 208 | static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai, |
213 | unsigned int fmt) | 209 | unsigned int fmt) |
214 | { | 210 | { |
215 | u32 iismod; | 211 | u32 iismod; |
@@ -317,7 +313,7 @@ exit_err: | |||
317 | /* | 313 | /* |
318 | * Set S3C24xx Clock source | 314 | * Set S3C24xx Clock source |
319 | */ | 315 | */ |
320 | static int s3c24xx_i2s_set_sysclk(struct snd_soc_cpu_dai *cpu_dai, | 316 | static int s3c24xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, |
321 | int clk_id, unsigned int freq, int dir) | 317 | int clk_id, unsigned int freq, int dir) |
322 | { | 318 | { |
323 | u32 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); | 319 | u32 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); |
@@ -343,7 +339,7 @@ static int s3c24xx_i2s_set_sysclk(struct snd_soc_cpu_dai *cpu_dai, | |||
343 | /* | 339 | /* |
344 | * Set S3C24xx Clock dividers | 340 | * Set S3C24xx Clock dividers |
345 | */ | 341 | */ |
346 | static int s3c24xx_i2s_set_clkdiv(struct snd_soc_cpu_dai *cpu_dai, | 342 | static int s3c24xx_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai, |
347 | int div_id, int div) | 343 | int div_id, int div) |
348 | { | 344 | { |
349 | u32 reg; | 345 | u32 reg; |
@@ -381,7 +377,8 @@ u32 s3c24xx_i2s_get_clockrate(void) | |||
381 | } | 377 | } |
382 | EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate); | 378 | EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate); |
383 | 379 | ||
384 | static int s3c24xx_i2s_probe(struct platform_device *pdev) | 380 | static int s3c24xx_i2s_probe(struct platform_device *pdev, |
381 | struct snd_soc_dai *dai) | ||
385 | { | 382 | { |
386 | DBG("Entered %s\n", __func__); | 383 | DBG("Entered %s\n", __func__); |
387 | 384 | ||
@@ -414,7 +411,7 @@ static int s3c24xx_i2s_probe(struct platform_device *pdev) | |||
414 | 411 | ||
415 | #ifdef CONFIG_PM | 412 | #ifdef CONFIG_PM |
416 | static int s3c24xx_i2s_suspend(struct platform_device *pdev, | 413 | static int s3c24xx_i2s_suspend(struct platform_device *pdev, |
417 | struct snd_soc_cpu_dai *cpu_dai) | 414 | struct snd_soc_dai *cpu_dai) |
418 | { | 415 | { |
419 | DBG("Entered %s\n", __func__); | 416 | DBG("Entered %s\n", __func__); |
420 | 417 | ||
@@ -429,7 +426,7 @@ static int s3c24xx_i2s_suspend(struct platform_device *pdev, | |||
429 | } | 426 | } |
430 | 427 | ||
431 | static int s3c24xx_i2s_resume(struct platform_device *pdev, | 428 | static int s3c24xx_i2s_resume(struct platform_device *pdev, |
432 | struct snd_soc_cpu_dai *cpu_dai) | 429 | struct snd_soc_dai *cpu_dai) |
433 | { | 430 | { |
434 | DBG("Entered %s\n", __func__); | 431 | DBG("Entered %s\n", __func__); |
435 | clk_enable(s3c24xx_i2s.iis_clk); | 432 | clk_enable(s3c24xx_i2s.iis_clk); |
@@ -452,7 +449,7 @@ static int s3c24xx_i2s_resume(struct platform_device *pdev, | |||
452 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | 449 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ |
453 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) | 450 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) |
454 | 451 | ||
455 | struct snd_soc_cpu_dai s3c24xx_i2s_dai = { | 452 | struct snd_soc_dai s3c24xx_i2s_dai = { |
456 | .name = "s3c24xx-i2s", | 453 | .name = "s3c24xx-i2s", |
457 | .id = 0, | 454 | .id = 0, |
458 | .type = SND_SOC_DAI_I2S, | 455 | .type = SND_SOC_DAI_I2S, |
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.h b/sound/soc/s3c24xx/s3c24xx-i2s.h index 537b4ecce8a3..726d91cf4e1c 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.h +++ b/sound/soc/s3c24xx/s3c24xx-i2s.h | |||
@@ -32,6 +32,6 @@ | |||
32 | 32 | ||
33 | u32 s3c24xx_i2s_get_clockrate(void); | 33 | u32 s3c24xx_i2s_get_clockrate(void); |
34 | 34 | ||
35 | extern struct snd_soc_cpu_dai s3c24xx_i2s_dai; | 35 | extern struct snd_soc_dai s3c24xx_i2s_dai; |
36 | 36 | ||
37 | #endif /*S3C24XXI2S_H_*/ | 37 | #endif /*S3C24XXI2S_H_*/ |
diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c index 7806ae614617..cef79b34dc6f 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/sound/soc/s3c24xx/s3c24xx-pcm.c | |||
@@ -12,10 +12,6 @@ | |||
12 | * under the terms of the GNU General Public License as published by the | 12 | * under the terms of the GNU General Public License as published by the |
13 | * Free Software Foundation; either version 2 of the License, or (at your | 13 | * Free Software Foundation; either version 2 of the License, or (at your |
14 | * option) any later version. | 14 | * option) any later version. |
15 | * | ||
16 | * Revision history | ||
17 | * 11th Dec 2006 Merged with Simtec driver | ||
18 | * 10th Nov 2006 Initial version. | ||
19 | */ | 15 | */ |
20 | 16 | ||
21 | #include <linux/module.h> | 17 | #include <linux/module.h> |
@@ -433,7 +429,7 @@ static void s3c24xx_pcm_free_dma_buffers(struct snd_pcm *pcm) | |||
433 | static u64 s3c24xx_pcm_dmamask = DMA_32BIT_MASK; | 429 | static u64 s3c24xx_pcm_dmamask = DMA_32BIT_MASK; |
434 | 430 | ||
435 | static int s3c24xx_pcm_new(struct snd_card *card, | 431 | static int s3c24xx_pcm_new(struct snd_card *card, |
436 | struct snd_soc_codec_dai *dai, struct snd_pcm *pcm) | 432 | struct snd_soc_dai *dai, struct snd_pcm *pcm) |
437 | { | 433 | { |
438 | int ret = 0; | 434 | int ret = 0; |
439 | 435 | ||
diff --git a/sound/soc/s3c24xx/smdk2443_wm9710.c b/sound/soc/s3c24xx/smdk2443_wm9710.c index b4a56302b9ab..8515d6ff03f2 100644 --- a/sound/soc/s3c24xx/smdk2443_wm9710.c +++ b/sound/soc/s3c24xx/smdk2443_wm9710.c | |||
@@ -10,9 +10,6 @@ | |||
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 | * Revision history | ||
14 | * 8th Mar 2007 Initial version. | ||
15 | * | ||
16 | */ | 13 | */ |
17 | 14 | ||
18 | #include <linux/module.h> | 15 | #include <linux/module.h> |
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index 4c1e013381c9..54bd604012af 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig | |||
@@ -3,7 +3,7 @@ menu "SoC Audio support for SuperH" | |||
3 | 3 | ||
4 | config SND_SOC_PCM_SH7760 | 4 | config SND_SOC_PCM_SH7760 |
5 | tristate "SoC Audio support for Renesas SH7760" | 5 | tristate "SoC Audio support for Renesas SH7760" |
6 | depends on CPU_SUBTYPE_SH7760 && SND_SOC && SH_DMABRG | 6 | depends on CPU_SUBTYPE_SH7760 && SH_DMABRG |
7 | help | 7 | help |
8 | Enable this option for SH7760 AC97/I2S audio support. | 8 | Enable this option for SH7760 AC97/I2S audio support. |
9 | 9 | ||
@@ -13,10 +13,9 @@ config SND_SOC_PCM_SH7760 | |||
13 | ## | 13 | ## |
14 | 14 | ||
15 | config SND_SOC_SH4_HAC | 15 | config SND_SOC_SH4_HAC |
16 | tristate | ||
16 | select AC97_BUS | 17 | select AC97_BUS |
17 | select SND_SOC_AC97_BUS | 18 | select SND_SOC_AC97_BUS |
18 | select SND_AC97_CODEC | ||
19 | tristate | ||
20 | 19 | ||
21 | config SND_SOC_SH4_SSI | 20 | config SND_SOC_SH4_SSI |
22 | tristate | 21 | tristate |
diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c index 7a3ce80d6727..9faa12622d09 100644 --- a/sound/soc/sh/dma-sh7760.c +++ b/sound/soc/sh/dma-sh7760.c | |||
@@ -326,7 +326,7 @@ static void camelot_pcm_free(struct snd_pcm *pcm) | |||
326 | } | 326 | } |
327 | 327 | ||
328 | static int camelot_pcm_new(struct snd_card *card, | 328 | static int camelot_pcm_new(struct snd_card *card, |
329 | struct snd_soc_codec_dai *dai, | 329 | struct snd_soc_dai *dai, |
330 | struct snd_pcm *pcm) | 330 | struct snd_pcm *pcm) |
331 | { | 331 | { |
332 | /* dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel | 332 | /* dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel |
diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c index b7b676b3d671..df7bc345c320 100644 --- a/sound/soc/sh/hac.c +++ b/sound/soc/sh/hac.c | |||
@@ -266,7 +266,7 @@ static int hac_hw_params(struct snd_pcm_substream *substream, | |||
266 | #define AC97_FMTS \ | 266 | #define AC97_FMTS \ |
267 | SNDRV_PCM_FMTBIT_S16_LE | 267 | SNDRV_PCM_FMTBIT_S16_LE |
268 | 268 | ||
269 | struct snd_soc_cpu_dai sh4_hac_dai[] = { | 269 | struct snd_soc_dai sh4_hac_dai[] = { |
270 | { | 270 | { |
271 | .name = "HAC0", | 271 | .name = "HAC0", |
272 | .id = 0, | 272 | .id = 0, |
diff --git a/sound/soc/sh/sh7760-ac97.c b/sound/soc/sh/sh7760-ac97.c index 2f91de84c5c7..92bfaf4774a7 100644 --- a/sound/soc/sh/sh7760-ac97.c +++ b/sound/soc/sh/sh7760-ac97.c | |||
@@ -20,12 +20,12 @@ | |||
20 | #define IPSEL 0xFE400034 | 20 | #define IPSEL 0xFE400034 |
21 | 21 | ||
22 | /* platform specific structs can be declared here */ | 22 | /* platform specific structs can be declared here */ |
23 | extern struct snd_soc_cpu_dai sh4_hac_dai[2]; | 23 | extern struct snd_soc_dai sh4_hac_dai[2]; |
24 | extern struct snd_soc_platform sh7760_soc_platform; | 24 | extern struct snd_soc_platform sh7760_soc_platform; |
25 | 25 | ||
26 | static int machine_init(struct snd_soc_codec *codec) | 26 | static int machine_init(struct snd_soc_codec *codec) |
27 | { | 27 | { |
28 | snd_soc_dapm_sync_endpoints(codec); | 28 | snd_soc_dapm_sync(codec); |
29 | return 0; | 29 | return 0; |
30 | } | 30 | } |
31 | 31 | ||
diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c index 3388bc3d62d1..55c3464163ab 100644 --- a/sound/soc/sh/ssi.c +++ b/sound/soc/sh/ssi.c | |||
@@ -208,7 +208,7 @@ static int ssi_hw_params(struct snd_pcm_substream *substream, | |||
208 | return 0; | 208 | return 0; |
209 | } | 209 | } |
210 | 210 | ||
211 | static int ssi_set_sysclk(struct snd_soc_cpu_dai *cpu_dai, int clk_id, | 211 | static int ssi_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, |
212 | unsigned int freq, int dir) | 212 | unsigned int freq, int dir) |
213 | { | 213 | { |
214 | struct ssi_priv *ssi = &ssi_cpu_data[cpu_dai->id]; | 214 | struct ssi_priv *ssi = &ssi_cpu_data[cpu_dai->id]; |
@@ -222,7 +222,7 @@ static int ssi_set_sysclk(struct snd_soc_cpu_dai *cpu_dai, int clk_id, | |||
222 | * This divider is used to generate the SSI_SCK (I2S bitclock) from the | 222 | * This divider is used to generate the SSI_SCK (I2S bitclock) from the |
223 | * clock at the HAC_BIT_CLK ("oversampling clock") pin. | 223 | * clock at the HAC_BIT_CLK ("oversampling clock") pin. |
224 | */ | 224 | */ |
225 | static int ssi_set_clkdiv(struct snd_soc_cpu_dai *dai, int did, int div) | 225 | static int ssi_set_clkdiv(struct snd_soc_dai *dai, int did, int div) |
226 | { | 226 | { |
227 | struct ssi_priv *ssi = &ssi_cpu_data[dai->id]; | 227 | struct ssi_priv *ssi = &ssi_cpu_data[dai->id]; |
228 | unsigned long ssicr; | 228 | unsigned long ssicr; |
@@ -245,7 +245,7 @@ static int ssi_set_clkdiv(struct snd_soc_cpu_dai *dai, int did, int div) | |||
245 | return 0; | 245 | return 0; |
246 | } | 246 | } |
247 | 247 | ||
248 | static int ssi_set_fmt(struct snd_soc_cpu_dai *dai, unsigned int fmt) | 248 | static int ssi_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) |
249 | { | 249 | { |
250 | struct ssi_priv *ssi = &ssi_cpu_data[dai->id]; | 250 | struct ssi_priv *ssi = &ssi_cpu_data[dai->id]; |
251 | unsigned long ssicr = SSIREG(SSICR); | 251 | unsigned long ssicr = SSIREG(SSICR); |
@@ -332,7 +332,7 @@ static int ssi_set_fmt(struct snd_soc_cpu_dai *dai, unsigned int fmt) | |||
332 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3LE | \ | 332 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3LE | \ |
333 | SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE) | 333 | SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE) |
334 | 334 | ||
335 | struct snd_soc_cpu_dai sh4_ssi_dai[] = { | 335 | struct snd_soc_dai sh4_ssi_dai[] = { |
336 | { | 336 | { |
337 | .name = "SSI0", | 337 | .name = "SSI0", |
338 | .id = 0, | 338 | .id = 0, |
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e148db940cfc..83f1190293a8 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -14,10 +14,6 @@ | |||
14 | * Free Software Foundation; either version 2 of the License, or (at your | 14 | * Free Software Foundation; either version 2 of the License, or (at your |
15 | * option) any later version. | 15 | * option) any later version. |
16 | * | 16 | * |
17 | * Revision history | ||
18 | * 12th Aug 2005 Initial version. | ||
19 | * 25th Oct 2005 Working Codec, Interface and Platform registration. | ||
20 | * | ||
21 | * TODO: | 17 | * TODO: |
22 | * o Add hw rules to enforce rates, etc. | 18 | * o Add hw rules to enforce rates, etc. |
23 | * o More testing with other codecs/machines. | 19 | * o More testing with other codecs/machines. |
@@ -112,9 +108,9 @@ static int soc_ac97_dev_register(struct snd_soc_codec *codec) | |||
112 | } | 108 | } |
113 | #endif | 109 | #endif |
114 | 110 | ||
115 | static inline const char* get_dai_name(int type) | 111 | static inline const char *get_dai_name(int type) |
116 | { | 112 | { |
117 | switch(type) { | 113 | switch (type) { |
118 | case SND_SOC_DAI_AC97_BUS: | 114 | case SND_SOC_DAI_AC97_BUS: |
119 | case SND_SOC_DAI_AC97: | 115 | case SND_SOC_DAI_AC97: |
120 | return "AC97"; | 116 | return "AC97"; |
@@ -138,8 +134,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
138 | struct snd_pcm_runtime *runtime = substream->runtime; | 134 | struct snd_pcm_runtime *runtime = substream->runtime; |
139 | struct snd_soc_dai_link *machine = rtd->dai; | 135 | struct snd_soc_dai_link *machine = rtd->dai; |
140 | struct snd_soc_platform *platform = socdev->platform; | 136 | struct snd_soc_platform *platform = socdev->platform; |
141 | struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; | 137 | struct snd_soc_dai *cpu_dai = machine->cpu_dai; |
142 | struct snd_soc_codec_dai *codec_dai = machine->codec_dai; | 138 | struct snd_soc_dai *codec_dai = machine->codec_dai; |
143 | int ret = 0; | 139 | int ret = 0; |
144 | 140 | ||
145 | mutex_lock(&pcm_mutex); | 141 | mutex_lock(&pcm_mutex); |
@@ -182,9 +178,11 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
182 | /* Check that the codec and cpu DAI's are compatible */ | 178 | /* Check that the codec and cpu DAI's are compatible */ |
183 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 179 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
184 | runtime->hw.rate_min = | 180 | runtime->hw.rate_min = |
185 | max(codec_dai->playback.rate_min, cpu_dai->playback.rate_min); | 181 | max(codec_dai->playback.rate_min, |
182 | cpu_dai->playback.rate_min); | ||
186 | runtime->hw.rate_max = | 183 | runtime->hw.rate_max = |
187 | min(codec_dai->playback.rate_max, cpu_dai->playback.rate_max); | 184 | min(codec_dai->playback.rate_max, |
185 | cpu_dai->playback.rate_max); | ||
188 | runtime->hw.channels_min = | 186 | runtime->hw.channels_min = |
189 | max(codec_dai->playback.channels_min, | 187 | max(codec_dai->playback.channels_min, |
190 | cpu_dai->playback.channels_min); | 188 | cpu_dai->playback.channels_min); |
@@ -197,9 +195,11 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
197 | codec_dai->playback.rates & cpu_dai->playback.rates; | 195 | codec_dai->playback.rates & cpu_dai->playback.rates; |
198 | } else { | 196 | } else { |
199 | runtime->hw.rate_min = | 197 | runtime->hw.rate_min = |
200 | max(codec_dai->capture.rate_min, cpu_dai->capture.rate_min); | 198 | max(codec_dai->capture.rate_min, |
199 | cpu_dai->capture.rate_min); | ||
201 | runtime->hw.rate_max = | 200 | runtime->hw.rate_max = |
202 | min(codec_dai->capture.rate_max, cpu_dai->capture.rate_max); | 201 | min(codec_dai->capture.rate_max, |
202 | cpu_dai->capture.rate_max); | ||
203 | runtime->hw.channels_min = | 203 | runtime->hw.channels_min = |
204 | max(codec_dai->capture.channels_min, | 204 | max(codec_dai->capture.channels_min, |
205 | cpu_dai->capture.channels_min); | 205 | cpu_dai->capture.channels_min); |
@@ -229,7 +229,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
229 | goto machine_err; | 229 | goto machine_err; |
230 | } | 230 | } |
231 | 231 | ||
232 | dbg("asoc: %s <-> %s info:\n",codec_dai->name, cpu_dai->name); | 232 | dbg("asoc: %s <-> %s info:\n", codec_dai->name, cpu_dai->name); |
233 | dbg("asoc: rate mask 0x%x\n", runtime->hw.rates); | 233 | dbg("asoc: rate mask 0x%x\n", runtime->hw.rates); |
234 | dbg("asoc: min ch %d max ch %d\n", runtime->hw.channels_min, | 234 | dbg("asoc: min ch %d max ch %d\n", runtime->hw.channels_min, |
235 | runtime->hw.channels_max); | 235 | runtime->hw.channels_max); |
@@ -272,11 +272,11 @@ static void close_delayed_work(struct work_struct *work) | |||
272 | struct snd_soc_device *socdev = | 272 | struct snd_soc_device *socdev = |
273 | container_of(work, struct snd_soc_device, delayed_work.work); | 273 | container_of(work, struct snd_soc_device, delayed_work.work); |
274 | struct snd_soc_codec *codec = socdev->codec; | 274 | struct snd_soc_codec *codec = socdev->codec; |
275 | struct snd_soc_codec_dai *codec_dai; | 275 | struct snd_soc_dai *codec_dai; |
276 | int i; | 276 | int i; |
277 | 277 | ||
278 | mutex_lock(&pcm_mutex); | 278 | mutex_lock(&pcm_mutex); |
279 | for(i = 0; i < codec->num_dai; i++) { | 279 | for (i = 0; i < codec->num_dai; i++) { |
280 | codec_dai = &codec->dai[i]; | 280 | codec_dai = &codec->dai[i]; |
281 | 281 | ||
282 | dbg("pop wq checking: %s status: %s waiting: %s\n", | 282 | dbg("pop wq checking: %s status: %s waiting: %s\n", |
@@ -287,12 +287,12 @@ static void close_delayed_work(struct work_struct *work) | |||
287 | /* are we waiting on this codec DAI stream */ | 287 | /* are we waiting on this codec DAI stream */ |
288 | if (codec_dai->pop_wait == 1) { | 288 | if (codec_dai->pop_wait == 1) { |
289 | 289 | ||
290 | /* power down the codec to D1 if no longer active */ | 290 | /* Reduce power if no longer active */ |
291 | if (codec->active == 0) { | 291 | if (codec->active == 0) { |
292 | dbg("pop wq D1 %s %s\n", codec->name, | 292 | dbg("pop wq D1 %s %s\n", codec->name, |
293 | codec_dai->playback.stream_name); | 293 | codec_dai->playback.stream_name); |
294 | snd_soc_dapm_device_event(socdev, | 294 | snd_soc_dapm_set_bias_level(socdev, |
295 | SNDRV_CTL_POWER_D1); | 295 | SND_SOC_BIAS_PREPARE); |
296 | } | 296 | } |
297 | 297 | ||
298 | codec_dai->pop_wait = 0; | 298 | codec_dai->pop_wait = 0; |
@@ -300,12 +300,12 @@ static void close_delayed_work(struct work_struct *work) | |||
300 | codec_dai->playback.stream_name, | 300 | codec_dai->playback.stream_name, |
301 | SND_SOC_DAPM_STREAM_STOP); | 301 | SND_SOC_DAPM_STREAM_STOP); |
302 | 302 | ||
303 | /* power down the codec power domain if no longer active */ | 303 | /* Fall into standby if no longer active */ |
304 | if (codec->active == 0) { | 304 | if (codec->active == 0) { |
305 | dbg("pop wq D3 %s %s\n", codec->name, | 305 | dbg("pop wq D3 %s %s\n", codec->name, |
306 | codec_dai->playback.stream_name); | 306 | codec_dai->playback.stream_name); |
307 | snd_soc_dapm_device_event(socdev, | 307 | snd_soc_dapm_set_bias_level(socdev, |
308 | SNDRV_CTL_POWER_D3hot); | 308 | SND_SOC_BIAS_STANDBY); |
309 | } | 309 | } |
310 | } | 310 | } |
311 | } | 311 | } |
@@ -323,8 +323,8 @@ static int soc_codec_close(struct snd_pcm_substream *substream) | |||
323 | struct snd_soc_device *socdev = rtd->socdev; | 323 | struct snd_soc_device *socdev = rtd->socdev; |
324 | struct snd_soc_dai_link *machine = rtd->dai; | 324 | struct snd_soc_dai_link *machine = rtd->dai; |
325 | struct snd_soc_platform *platform = socdev->platform; | 325 | struct snd_soc_platform *platform = socdev->platform; |
326 | struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; | 326 | struct snd_soc_dai *cpu_dai = machine->cpu_dai; |
327 | struct snd_soc_codec_dai *codec_dai = machine->codec_dai; | 327 | struct snd_soc_dai *codec_dai = machine->codec_dai; |
328 | struct snd_soc_codec *codec = socdev->codec; | 328 | struct snd_soc_codec *codec = socdev->codec; |
329 | 329 | ||
330 | mutex_lock(&pcm_mutex); | 330 | mutex_lock(&pcm_mutex); |
@@ -365,8 +365,8 @@ static int soc_codec_close(struct snd_pcm_substream *substream) | |||
365 | SND_SOC_DAPM_STREAM_STOP); | 365 | SND_SOC_DAPM_STREAM_STOP); |
366 | 366 | ||
367 | if (codec->active == 0 && codec_dai->pop_wait == 0) | 367 | if (codec->active == 0 && codec_dai->pop_wait == 0) |
368 | snd_soc_dapm_device_event(socdev, | 368 | snd_soc_dapm_set_bias_level(socdev, |
369 | SNDRV_CTL_POWER_D3hot); | 369 | SND_SOC_BIAS_STANDBY); |
370 | } | 370 | } |
371 | 371 | ||
372 | mutex_unlock(&pcm_mutex); | 372 | mutex_unlock(&pcm_mutex); |
@@ -384,8 +384,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) | |||
384 | struct snd_soc_device *socdev = rtd->socdev; | 384 | struct snd_soc_device *socdev = rtd->socdev; |
385 | struct snd_soc_dai_link *machine = rtd->dai; | 385 | struct snd_soc_dai_link *machine = rtd->dai; |
386 | struct snd_soc_platform *platform = socdev->platform; | 386 | struct snd_soc_platform *platform = socdev->platform; |
387 | struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; | 387 | struct snd_soc_dai *cpu_dai = machine->cpu_dai; |
388 | struct snd_soc_codec_dai *codec_dai = machine->codec_dai; | 388 | struct snd_soc_dai *codec_dai = machine->codec_dai; |
389 | struct snd_soc_codec *codec = socdev->codec; | 389 | struct snd_soc_codec *codec = socdev->codec; |
390 | int ret = 0; | 390 | int ret = 0; |
391 | 391 | ||
@@ -434,14 +434,14 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) | |||
434 | else { | 434 | else { |
435 | codec_dai->pop_wait = 0; | 435 | codec_dai->pop_wait = 0; |
436 | cancel_delayed_work(&socdev->delayed_work); | 436 | cancel_delayed_work(&socdev->delayed_work); |
437 | if (codec_dai->dai_ops.digital_mute) | 437 | snd_soc_dai_digital_mute(codec_dai, 0); |
438 | codec_dai->dai_ops.digital_mute(codec_dai, 0); | ||
439 | } | 438 | } |
440 | } else { | 439 | } else { |
441 | /* no delayed work - do we need to power up codec */ | 440 | /* no delayed work - do we need to power up codec */ |
442 | if (codec->dapm_state != SNDRV_CTL_POWER_D0) { | 441 | if (codec->bias_level != SND_SOC_BIAS_ON) { |
443 | 442 | ||
444 | snd_soc_dapm_device_event(socdev, SNDRV_CTL_POWER_D1); | 443 | snd_soc_dapm_set_bias_level(socdev, |
444 | SND_SOC_BIAS_PREPARE); | ||
445 | 445 | ||
446 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 446 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
447 | snd_soc_dapm_stream_event(codec, | 447 | snd_soc_dapm_stream_event(codec, |
@@ -452,9 +452,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) | |||
452 | codec_dai->capture.stream_name, | 452 | codec_dai->capture.stream_name, |
453 | SND_SOC_DAPM_STREAM_START); | 453 | SND_SOC_DAPM_STREAM_START); |
454 | 454 | ||
455 | snd_soc_dapm_device_event(socdev, SNDRV_CTL_POWER_D0); | 455 | snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_ON); |
456 | if (codec_dai->dai_ops.digital_mute) | 456 | snd_soc_dai_digital_mute(codec_dai, 0); |
457 | codec_dai->dai_ops.digital_mute(codec_dai, 0); | ||
458 | 457 | ||
459 | } else { | 458 | } else { |
460 | /* codec already powered - power on widgets */ | 459 | /* codec already powered - power on widgets */ |
@@ -466,8 +465,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) | |||
466 | snd_soc_dapm_stream_event(codec, | 465 | snd_soc_dapm_stream_event(codec, |
467 | codec_dai->capture.stream_name, | 466 | codec_dai->capture.stream_name, |
468 | SND_SOC_DAPM_STREAM_START); | 467 | SND_SOC_DAPM_STREAM_START); |
469 | if (codec_dai->dai_ops.digital_mute) | 468 | |
470 | codec_dai->dai_ops.digital_mute(codec_dai, 0); | 469 | snd_soc_dai_digital_mute(codec_dai, 0); |
471 | } | 470 | } |
472 | } | 471 | } |
473 | 472 | ||
@@ -488,8 +487,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, | |||
488 | struct snd_soc_device *socdev = rtd->socdev; | 487 | struct snd_soc_device *socdev = rtd->socdev; |
489 | struct snd_soc_dai_link *machine = rtd->dai; | 488 | struct snd_soc_dai_link *machine = rtd->dai; |
490 | struct snd_soc_platform *platform = socdev->platform; | 489 | struct snd_soc_platform *platform = socdev->platform; |
491 | struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; | 490 | struct snd_soc_dai *cpu_dai = machine->cpu_dai; |
492 | struct snd_soc_codec_dai *codec_dai = machine->codec_dai; | 491 | struct snd_soc_dai *codec_dai = machine->codec_dai; |
493 | int ret = 0; | 492 | int ret = 0; |
494 | 493 | ||
495 | mutex_lock(&pcm_mutex); | 494 | mutex_lock(&pcm_mutex); |
@@ -514,7 +513,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, | |||
514 | if (cpu_dai->ops.hw_params) { | 513 | if (cpu_dai->ops.hw_params) { |
515 | ret = cpu_dai->ops.hw_params(substream, params); | 514 | ret = cpu_dai->ops.hw_params(substream, params); |
516 | if (ret < 0) { | 515 | if (ret < 0) { |
517 | printk(KERN_ERR "asoc: can't set interface %s hw params\n", | 516 | printk(KERN_ERR "asoc: interface %s hw params failed\n", |
518 | cpu_dai->name); | 517 | cpu_dai->name); |
519 | goto interface_err; | 518 | goto interface_err; |
520 | } | 519 | } |
@@ -523,7 +522,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, | |||
523 | if (platform->pcm_ops->hw_params) { | 522 | if (platform->pcm_ops->hw_params) { |
524 | ret = platform->pcm_ops->hw_params(substream, params); | 523 | ret = platform->pcm_ops->hw_params(substream, params); |
525 | if (ret < 0) { | 524 | if (ret < 0) { |
526 | printk(KERN_ERR "asoc: can't set platform %s hw params\n", | 525 | printk(KERN_ERR "asoc: platform %s hw params failed\n", |
527 | platform->name); | 526 | platform->name); |
528 | goto platform_err; | 527 | goto platform_err; |
529 | } | 528 | } |
@@ -542,7 +541,7 @@ interface_err: | |||
542 | codec_dai->ops.hw_free(substream); | 541 | codec_dai->ops.hw_free(substream); |
543 | 542 | ||
544 | codec_err: | 543 | codec_err: |
545 | if(machine->ops && machine->ops->hw_free) | 544 | if (machine->ops && machine->ops->hw_free) |
546 | machine->ops->hw_free(substream); | 545 | machine->ops->hw_free(substream); |
547 | 546 | ||
548 | mutex_unlock(&pcm_mutex); | 547 | mutex_unlock(&pcm_mutex); |
@@ -558,15 +557,15 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) | |||
558 | struct snd_soc_device *socdev = rtd->socdev; | 557 | struct snd_soc_device *socdev = rtd->socdev; |
559 | struct snd_soc_dai_link *machine = rtd->dai; | 558 | struct snd_soc_dai_link *machine = rtd->dai; |
560 | struct snd_soc_platform *platform = socdev->platform; | 559 | struct snd_soc_platform *platform = socdev->platform; |
561 | struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; | 560 | struct snd_soc_dai *cpu_dai = machine->cpu_dai; |
562 | struct snd_soc_codec_dai *codec_dai = machine->codec_dai; | 561 | struct snd_soc_dai *codec_dai = machine->codec_dai; |
563 | struct snd_soc_codec *codec = socdev->codec; | 562 | struct snd_soc_codec *codec = socdev->codec; |
564 | 563 | ||
565 | mutex_lock(&pcm_mutex); | 564 | mutex_lock(&pcm_mutex); |
566 | 565 | ||
567 | /* apply codec digital mute */ | 566 | /* apply codec digital mute */ |
568 | if (!codec->active && codec_dai->dai_ops.digital_mute) | 567 | if (!codec->active) |
569 | codec_dai->dai_ops.digital_mute(codec_dai, 1); | 568 | snd_soc_dai_digital_mute(codec_dai, 1); |
570 | 569 | ||
571 | /* free any machine hw params */ | 570 | /* free any machine hw params */ |
572 | if (machine->ops && machine->ops->hw_free) | 571 | if (machine->ops && machine->ops->hw_free) |
@@ -593,8 +592,8 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
593 | struct snd_soc_device *socdev = rtd->socdev; | 592 | struct snd_soc_device *socdev = rtd->socdev; |
594 | struct snd_soc_dai_link *machine = rtd->dai; | 593 | struct snd_soc_dai_link *machine = rtd->dai; |
595 | struct snd_soc_platform *platform = socdev->platform; | 594 | struct snd_soc_platform *platform = socdev->platform; |
596 | struct snd_soc_cpu_dai *cpu_dai = machine->cpu_dai; | 595 | struct snd_soc_dai *cpu_dai = machine->cpu_dai; |
597 | struct snd_soc_codec_dai *codec_dai = machine->codec_dai; | 596 | struct snd_soc_dai *codec_dai = machine->codec_dai; |
598 | int ret; | 597 | int ret; |
599 | 598 | ||
600 | if (codec_dai->ops.trigger) { | 599 | if (codec_dai->ops.trigger) { |
@@ -631,16 +630,26 @@ static struct snd_pcm_ops soc_pcm_ops = { | |||
631 | /* powers down audio subsystem for suspend */ | 630 | /* powers down audio subsystem for suspend */ |
632 | static int soc_suspend(struct platform_device *pdev, pm_message_t state) | 631 | static int soc_suspend(struct platform_device *pdev, pm_message_t state) |
633 | { | 632 | { |
634 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 633 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
635 | struct snd_soc_machine *machine = socdev->machine; | 634 | struct snd_soc_machine *machine = socdev->machine; |
636 | struct snd_soc_platform *platform = socdev->platform; | 635 | struct snd_soc_platform *platform = socdev->platform; |
637 | struct snd_soc_codec_device *codec_dev = socdev->codec_dev; | 636 | struct snd_soc_codec_device *codec_dev = socdev->codec_dev; |
638 | struct snd_soc_codec *codec = socdev->codec; | 637 | struct snd_soc_codec *codec = socdev->codec; |
639 | int i; | 638 | int i; |
640 | 639 | ||
640 | /* Due to the resume being scheduled into a workqueue we could | ||
641 | * suspend before that's finished - wait for it to complete. | ||
642 | */ | ||
643 | snd_power_lock(codec->card); | ||
644 | snd_power_wait(codec->card, SNDRV_CTL_POWER_D0); | ||
645 | snd_power_unlock(codec->card); | ||
646 | |||
647 | /* we're going to block userspace touching us until resume completes */ | ||
648 | snd_power_change_state(codec->card, SNDRV_CTL_POWER_D3hot); | ||
649 | |||
641 | /* mute any active DAC's */ | 650 | /* mute any active DAC's */ |
642 | for(i = 0; i < machine->num_links; i++) { | 651 | for (i = 0; i < machine->num_links; i++) { |
643 | struct snd_soc_codec_dai *dai = machine->dai_link[i].codec_dai; | 652 | struct snd_soc_dai *dai = machine->dai_link[i].codec_dai; |
644 | if (dai->dai_ops.digital_mute && dai->playback.active) | 653 | if (dai->dai_ops.digital_mute && dai->playback.active) |
645 | dai->dai_ops.digital_mute(dai, 1); | 654 | dai->dai_ops.digital_mute(dai, 1); |
646 | } | 655 | } |
@@ -652,8 +661,8 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) | |||
652 | if (machine->suspend_pre) | 661 | if (machine->suspend_pre) |
653 | machine->suspend_pre(pdev, state); | 662 | machine->suspend_pre(pdev, state); |
654 | 663 | ||
655 | for(i = 0; i < machine->num_links; i++) { | 664 | for (i = 0; i < machine->num_links; i++) { |
656 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; | 665 | struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; |
657 | if (cpu_dai->suspend && cpu_dai->type != SND_SOC_DAI_AC97) | 666 | if (cpu_dai->suspend && cpu_dai->type != SND_SOC_DAI_AC97) |
658 | cpu_dai->suspend(pdev, cpu_dai); | 667 | cpu_dai->suspend(pdev, cpu_dai); |
659 | if (platform->suspend) | 668 | if (platform->suspend) |
@@ -662,9 +671,9 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) | |||
662 | 671 | ||
663 | /* close any waiting streams and save state */ | 672 | /* close any waiting streams and save state */ |
664 | run_delayed_work(&socdev->delayed_work); | 673 | run_delayed_work(&socdev->delayed_work); |
665 | codec->suspend_dapm_state = codec->dapm_state; | 674 | codec->suspend_bias_level = codec->bias_level; |
666 | 675 | ||
667 | for(i = 0; i < codec->num_dai; i++) { | 676 | for (i = 0; i < codec->num_dai; i++) { |
668 | char *stream = codec->dai[i].playback.stream_name; | 677 | char *stream = codec->dai[i].playback.stream_name; |
669 | if (stream != NULL) | 678 | if (stream != NULL) |
670 | snd_soc_dapm_stream_event(codec, stream, | 679 | snd_soc_dapm_stream_event(codec, stream, |
@@ -678,8 +687,8 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) | |||
678 | if (codec_dev->suspend) | 687 | if (codec_dev->suspend) |
679 | codec_dev->suspend(pdev, state); | 688 | codec_dev->suspend(pdev, state); |
680 | 689 | ||
681 | for(i = 0; i < machine->num_links; i++) { | 690 | for (i = 0; i < machine->num_links; i++) { |
682 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; | 691 | struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; |
683 | if (cpu_dai->suspend && cpu_dai->type == SND_SOC_DAI_AC97) | 692 | if (cpu_dai->suspend && cpu_dai->type == SND_SOC_DAI_AC97) |
684 | cpu_dai->suspend(pdev, cpu_dai); | 693 | cpu_dai->suspend(pdev, cpu_dai); |
685 | } | 694 | } |
@@ -690,21 +699,32 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) | |||
690 | return 0; | 699 | return 0; |
691 | } | 700 | } |
692 | 701 | ||
693 | /* powers up audio subsystem after a suspend */ | 702 | /* deferred resume work, so resume can complete before we finished |
694 | static int soc_resume(struct platform_device *pdev) | 703 | * setting our codec back up, which can be very slow on I2C |
704 | */ | ||
705 | static void soc_resume_deferred(struct work_struct *work) | ||
695 | { | 706 | { |
696 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 707 | struct snd_soc_device *socdev = container_of(work, |
697 | struct snd_soc_machine *machine = socdev->machine; | 708 | struct snd_soc_device, |
698 | struct snd_soc_platform *platform = socdev->platform; | 709 | deferred_resume_work); |
699 | struct snd_soc_codec_device *codec_dev = socdev->codec_dev; | 710 | struct snd_soc_machine *machine = socdev->machine; |
711 | struct snd_soc_platform *platform = socdev->platform; | ||
712 | struct snd_soc_codec_device *codec_dev = socdev->codec_dev; | ||
700 | struct snd_soc_codec *codec = socdev->codec; | 713 | struct snd_soc_codec *codec = socdev->codec; |
714 | struct platform_device *pdev = to_platform_device(socdev->dev); | ||
701 | int i; | 715 | int i; |
702 | 716 | ||
717 | /* our power state is still SNDRV_CTL_POWER_D3hot from suspend time, | ||
718 | * so userspace apps are blocked from touching us | ||
719 | */ | ||
720 | |||
721 | dev_info(socdev->dev, "starting resume work\n"); | ||
722 | |||
703 | if (machine->resume_pre) | 723 | if (machine->resume_pre) |
704 | machine->resume_pre(pdev); | 724 | machine->resume_pre(pdev); |
705 | 725 | ||
706 | for(i = 0; i < machine->num_links; i++) { | 726 | for (i = 0; i < machine->num_links; i++) { |
707 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; | 727 | struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; |
708 | if (cpu_dai->resume && cpu_dai->type == SND_SOC_DAI_AC97) | 728 | if (cpu_dai->resume && cpu_dai->type == SND_SOC_DAI_AC97) |
709 | cpu_dai->resume(pdev, cpu_dai); | 729 | cpu_dai->resume(pdev, cpu_dai); |
710 | } | 730 | } |
@@ -712,8 +732,8 @@ static int soc_resume(struct platform_device *pdev) | |||
712 | if (codec_dev->resume) | 732 | if (codec_dev->resume) |
713 | codec_dev->resume(pdev); | 733 | codec_dev->resume(pdev); |
714 | 734 | ||
715 | for(i = 0; i < codec->num_dai; i++) { | 735 | for (i = 0; i < codec->num_dai; i++) { |
716 | char* stream = codec->dai[i].playback.stream_name; | 736 | char *stream = codec->dai[i].playback.stream_name; |
717 | if (stream != NULL) | 737 | if (stream != NULL) |
718 | snd_soc_dapm_stream_event(codec, stream, | 738 | snd_soc_dapm_stream_event(codec, stream, |
719 | SND_SOC_DAPM_STREAM_RESUME); | 739 | SND_SOC_DAPM_STREAM_RESUME); |
@@ -723,15 +743,15 @@ static int soc_resume(struct platform_device *pdev) | |||
723 | SND_SOC_DAPM_STREAM_RESUME); | 743 | SND_SOC_DAPM_STREAM_RESUME); |
724 | } | 744 | } |
725 | 745 | ||
726 | /* unmute any active DAC's */ | 746 | /* unmute any active DACs */ |
727 | for(i = 0; i < machine->num_links; i++) { | 747 | for (i = 0; i < machine->num_links; i++) { |
728 | struct snd_soc_codec_dai *dai = machine->dai_link[i].codec_dai; | 748 | struct snd_soc_dai *dai = machine->dai_link[i].codec_dai; |
729 | if (dai->dai_ops.digital_mute && dai->playback.active) | 749 | if (dai->dai_ops.digital_mute && dai->playback.active) |
730 | dai->dai_ops.digital_mute(dai, 0); | 750 | dai->dai_ops.digital_mute(dai, 0); |
731 | } | 751 | } |
732 | 752 | ||
733 | for(i = 0; i < machine->num_links; i++) { | 753 | for (i = 0; i < machine->num_links; i++) { |
734 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; | 754 | struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; |
735 | if (cpu_dai->resume && cpu_dai->type != SND_SOC_DAI_AC97) | 755 | if (cpu_dai->resume && cpu_dai->type != SND_SOC_DAI_AC97) |
736 | cpu_dai->resume(pdev, cpu_dai); | 756 | cpu_dai->resume(pdev, cpu_dai); |
737 | if (platform->resume) | 757 | if (platform->resume) |
@@ -741,6 +761,22 @@ static int soc_resume(struct platform_device *pdev) | |||
741 | if (machine->resume_post) | 761 | if (machine->resume_post) |
742 | machine->resume_post(pdev); | 762 | machine->resume_post(pdev); |
743 | 763 | ||
764 | dev_info(socdev->dev, "resume work completed\n"); | ||
765 | |||
766 | /* userspace can access us now we are back as we were before */ | ||
767 | snd_power_change_state(codec->card, SNDRV_CTL_POWER_D0); | ||
768 | } | ||
769 | |||
770 | /* powers up audio subsystem after a suspend */ | ||
771 | static int soc_resume(struct platform_device *pdev) | ||
772 | { | ||
773 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
774 | |||
775 | dev_info(socdev->dev, "scheduling resume work\n"); | ||
776 | |||
777 | if (!schedule_work(&socdev->deferred_resume_work)) | ||
778 | dev_err(socdev->dev, "work item may be lost\n"); | ||
779 | |||
744 | return 0; | 780 | return 0; |
745 | } | 781 | } |
746 | 782 | ||
@@ -760,33 +796,38 @@ static int soc_probe(struct platform_device *pdev) | |||
760 | 796 | ||
761 | if (machine->probe) { | 797 | if (machine->probe) { |
762 | ret = machine->probe(pdev); | 798 | ret = machine->probe(pdev); |
763 | if(ret < 0) | 799 | if (ret < 0) |
764 | return ret; | 800 | return ret; |
765 | } | 801 | } |
766 | 802 | ||
767 | for (i = 0; i < machine->num_links; i++) { | 803 | for (i = 0; i < machine->num_links; i++) { |
768 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; | 804 | struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; |
769 | if (cpu_dai->probe) { | 805 | if (cpu_dai->probe) { |
770 | ret = cpu_dai->probe(pdev); | 806 | ret = cpu_dai->probe(pdev, cpu_dai); |
771 | if(ret < 0) | 807 | if (ret < 0) |
772 | goto cpu_dai_err; | 808 | goto cpu_dai_err; |
773 | } | 809 | } |
774 | } | 810 | } |
775 | 811 | ||
776 | if (codec_dev->probe) { | 812 | if (codec_dev->probe) { |
777 | ret = codec_dev->probe(pdev); | 813 | ret = codec_dev->probe(pdev); |
778 | if(ret < 0) | 814 | if (ret < 0) |
779 | goto cpu_dai_err; | 815 | goto cpu_dai_err; |
780 | } | 816 | } |
781 | 817 | ||
782 | if (platform->probe) { | 818 | if (platform->probe) { |
783 | ret = platform->probe(pdev); | 819 | ret = platform->probe(pdev); |
784 | if(ret < 0) | 820 | if (ret < 0) |
785 | goto platform_err; | 821 | goto platform_err; |
786 | } | 822 | } |
787 | 823 | ||
788 | /* DAPM stream work */ | 824 | /* DAPM stream work */ |
789 | INIT_DELAYED_WORK(&socdev->delayed_work, close_delayed_work); | 825 | INIT_DELAYED_WORK(&socdev->delayed_work, close_delayed_work); |
826 | #ifdef CONFIG_PM | ||
827 | /* deferred resume work */ | ||
828 | INIT_WORK(&socdev->deferred_resume_work, soc_resume_deferred); | ||
829 | #endif | ||
830 | |||
790 | return 0; | 831 | return 0; |
791 | 832 | ||
792 | platform_err: | 833 | platform_err: |
@@ -795,9 +836,9 @@ platform_err: | |||
795 | 836 | ||
796 | cpu_dai_err: | 837 | cpu_dai_err: |
797 | for (i--; i >= 0; i--) { | 838 | for (i--; i >= 0; i--) { |
798 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; | 839 | struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; |
799 | if (cpu_dai->remove) | 840 | if (cpu_dai->remove) |
800 | cpu_dai->remove(pdev); | 841 | cpu_dai->remove(pdev, cpu_dai); |
801 | } | 842 | } |
802 | 843 | ||
803 | if (machine->remove) | 844 | if (machine->remove) |
@@ -824,9 +865,9 @@ static int soc_remove(struct platform_device *pdev) | |||
824 | codec_dev->remove(pdev); | 865 | codec_dev->remove(pdev); |
825 | 866 | ||
826 | for (i = 0; i < machine->num_links; i++) { | 867 | for (i = 0; i < machine->num_links; i++) { |
827 | struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai; | 868 | struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; |
828 | if (cpu_dai->remove) | 869 | if (cpu_dai->remove) |
829 | cpu_dai->remove(pdev); | 870 | cpu_dai->remove(pdev, cpu_dai); |
830 | } | 871 | } |
831 | 872 | ||
832 | if (machine->remove) | 873 | if (machine->remove) |
@@ -852,8 +893,8 @@ static int soc_new_pcm(struct snd_soc_device *socdev, | |||
852 | struct snd_soc_dai_link *dai_link, int num) | 893 | struct snd_soc_dai_link *dai_link, int num) |
853 | { | 894 | { |
854 | struct snd_soc_codec *codec = socdev->codec; | 895 | struct snd_soc_codec *codec = socdev->codec; |
855 | struct snd_soc_codec_dai *codec_dai = dai_link->codec_dai; | 896 | struct snd_soc_dai *codec_dai = dai_link->codec_dai; |
856 | struct snd_soc_cpu_dai *cpu_dai = dai_link->cpu_dai; | 897 | struct snd_soc_dai *cpu_dai = dai_link->cpu_dai; |
857 | struct snd_soc_pcm_runtime *rtd; | 898 | struct snd_soc_pcm_runtime *rtd; |
858 | struct snd_pcm *pcm; | 899 | struct snd_pcm *pcm; |
859 | char new_name[64]; | 900 | char new_name[64]; |
@@ -868,7 +909,7 @@ static int soc_new_pcm(struct snd_soc_device *socdev, | |||
868 | codec_dai->codec = socdev->codec; | 909 | codec_dai->codec = socdev->codec; |
869 | 910 | ||
870 | /* check client and interface hw capabilities */ | 911 | /* check client and interface hw capabilities */ |
871 | sprintf(new_name, "%s %s-%s-%d",dai_link->stream_name, codec_dai->name, | 912 | sprintf(new_name, "%s %s-%s-%d", dai_link->stream_name, codec_dai->name, |
872 | get_dai_name(cpu_dai->type), num); | 913 | get_dai_name(cpu_dai->type), num); |
873 | 914 | ||
874 | if (codec_dai->playback.channels_min) | 915 | if (codec_dai->playback.channels_min) |
@@ -879,7 +920,8 @@ static int soc_new_pcm(struct snd_soc_device *socdev, | |||
879 | ret = snd_pcm_new(codec->card, new_name, codec->pcm_devs++, playback, | 920 | ret = snd_pcm_new(codec->card, new_name, codec->pcm_devs++, playback, |
880 | capture, &pcm); | 921 | capture, &pcm); |
881 | if (ret < 0) { | 922 | if (ret < 0) { |
882 | printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name); | 923 | printk(KERN_ERR "asoc: can't create pcm for codec %s\n", |
924 | codec->name); | ||
883 | kfree(rtd); | 925 | kfree(rtd); |
884 | return ret; | 926 | return ret; |
885 | } | 927 | } |
@@ -928,8 +970,9 @@ static ssize_t codec_reg_show(struct device *dev, | |||
928 | step = codec->reg_cache_step; | 970 | step = codec->reg_cache_step; |
929 | 971 | ||
930 | count += sprintf(buf, "%s registers\n", codec->name); | 972 | count += sprintf(buf, "%s registers\n", codec->name); |
931 | for(i = 0; i < codec->reg_cache_size; i += step) | 973 | for (i = 0; i < codec->reg_cache_size; i += step) |
932 | count += sprintf(buf + count, "%2x: %4x\n", i, codec->read(codec, i)); | 974 | count += sprintf(buf + count, "%2x: %4x\n", i, |
975 | codec->read(codec, i)); | ||
933 | 976 | ||
934 | return count; | 977 | return count; |
935 | } | 978 | } |
@@ -1072,7 +1115,7 @@ int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid) | |||
1072 | strncpy(codec->card->driver, codec->name, sizeof(codec->card->driver)); | 1115 | strncpy(codec->card->driver, codec->name, sizeof(codec->card->driver)); |
1073 | 1116 | ||
1074 | /* create the pcms */ | 1117 | /* create the pcms */ |
1075 | for(i = 0; i < machine->num_links; i++) { | 1118 | for (i = 0; i < machine->num_links; i++) { |
1076 | ret = soc_new_pcm(socdev, &machine->dai_link[i], i); | 1119 | ret = soc_new_pcm(socdev, &machine->dai_link[i], i); |
1077 | if (ret < 0) { | 1120 | if (ret < 0) { |
1078 | printk(KERN_ERR "asoc: can't create pcm %s\n", | 1121 | printk(KERN_ERR "asoc: can't create pcm %s\n", |
@@ -1102,7 +1145,7 @@ int snd_soc_register_card(struct snd_soc_device *socdev) | |||
1102 | struct snd_soc_machine *machine = socdev->machine; | 1145 | struct snd_soc_machine *machine = socdev->machine; |
1103 | int ret = 0, i, ac97 = 0, err = 0; | 1146 | int ret = 0, i, ac97 = 0, err = 0; |
1104 | 1147 | ||
1105 | for(i = 0; i < machine->num_links; i++) { | 1148 | for (i = 0; i < machine->num_links; i++) { |
1106 | if (socdev->machine->dai_link[i].init) { | 1149 | if (socdev->machine->dai_link[i].init) { |
1107 | err = socdev->machine->dai_link[i].init(codec); | 1150 | err = socdev->machine->dai_link[i].init(codec); |
1108 | if (err < 0) { | 1151 | if (err < 0) { |
@@ -1111,7 +1154,7 @@ int snd_soc_register_card(struct snd_soc_device *socdev) | |||
1111 | continue; | 1154 | continue; |
1112 | } | 1155 | } |
1113 | } | 1156 | } |
1114 | if (socdev->machine->dai_link[i].codec_dai->type == | 1157 | if (socdev->machine->dai_link[i].codec_dai->type == |
1115 | SND_SOC_DAI_AC97_BUS) | 1158 | SND_SOC_DAI_AC97_BUS) |
1116 | ac97 = 1; | 1159 | ac97 = 1; |
1117 | } | 1160 | } |
@@ -1122,7 +1165,7 @@ int snd_soc_register_card(struct snd_soc_device *socdev) | |||
1122 | 1165 | ||
1123 | ret = snd_card_register(codec->card); | 1166 | ret = snd_card_register(codec->card); |
1124 | if (ret < 0) { | 1167 | if (ret < 0) { |
1125 | printk(KERN_ERR "asoc: failed to register soundcard for codec %s\n", | 1168 | printk(KERN_ERR "asoc: failed to register soundcard for %s\n", |
1126 | codec->name); | 1169 | codec->name); |
1127 | goto out; | 1170 | goto out; |
1128 | } | 1171 | } |
@@ -1146,7 +1189,7 @@ int snd_soc_register_card(struct snd_soc_device *socdev) | |||
1146 | 1189 | ||
1147 | err = device_create_file(socdev->dev, &dev_attr_codec_reg); | 1190 | err = device_create_file(socdev->dev, &dev_attr_codec_reg); |
1148 | if (err < 0) | 1191 | if (err < 0) |
1149 | printk(KERN_WARNING "asoc: failed to add codec sysfs entries\n"); | 1192 | printk(KERN_WARNING "asoc: failed to add codec sysfs files\n"); |
1150 | 1193 | ||
1151 | mutex_unlock(&codec->mutex); | 1194 | mutex_unlock(&codec->mutex); |
1152 | 1195 | ||
@@ -1166,13 +1209,13 @@ void snd_soc_free_pcms(struct snd_soc_device *socdev) | |||
1166 | { | 1209 | { |
1167 | struct snd_soc_codec *codec = socdev->codec; | 1210 | struct snd_soc_codec *codec = socdev->codec; |
1168 | #ifdef CONFIG_SND_SOC_AC97_BUS | 1211 | #ifdef CONFIG_SND_SOC_AC97_BUS |
1169 | struct snd_soc_codec_dai *codec_dai; | 1212 | struct snd_soc_dai *codec_dai; |
1170 | int i; | 1213 | int i; |
1171 | #endif | 1214 | #endif |
1172 | 1215 | ||
1173 | mutex_lock(&codec->mutex); | 1216 | mutex_lock(&codec->mutex); |
1174 | #ifdef CONFIG_SND_SOC_AC97_BUS | 1217 | #ifdef CONFIG_SND_SOC_AC97_BUS |
1175 | for(i = 0; i < codec->num_dai; i++) { | 1218 | for (i = 0; i < codec->num_dai; i++) { |
1176 | codec_dai = &codec->dai[i]; | 1219 | codec_dai = &codec->dai[i]; |
1177 | if (codec_dai->type == SND_SOC_DAI_AC97_BUS && codec->ac97) { | 1220 | if (codec_dai->type == SND_SOC_DAI_AC97_BUS && codec->ac97) { |
1178 | soc_ac97_dev_unregister(codec); | 1221 | soc_ac97_dev_unregister(codec); |
@@ -1282,7 +1325,8 @@ int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, | |||
1282 | for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) | 1325 | for (bitmask = 1; bitmask < e->mask; bitmask <<= 1) |
1283 | ; | 1326 | ; |
1284 | val = snd_soc_read(codec, e->reg); | 1327 | val = snd_soc_read(codec, e->reg); |
1285 | ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1); | 1328 | ucontrol->value.enumerated.item[0] |
1329 | = (val >> e->shift_l) & (bitmask - 1); | ||
1286 | if (e->shift_l != e->shift_r) | 1330 | if (e->shift_l != e->shift_r) |
1287 | ucontrol->value.enumerated.item[1] = | 1331 | ucontrol->value.enumerated.item[1] = |
1288 | (val >> e->shift_r) & (bitmask - 1); | 1332 | (val >> e->shift_r) & (bitmask - 1); |
@@ -1576,7 +1620,8 @@ int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol, | |||
1576 | val = val << shift; | 1620 | val = val << shift; |
1577 | val2 = val2 << shift; | 1621 | val2 = val2 << shift; |
1578 | 1622 | ||
1579 | if ((err = snd_soc_update_bits(codec, reg, val_mask, val)) < 0) | 1623 | err = snd_soc_update_bits(codec, reg, val_mask, val); |
1624 | if (err < 0) | ||
1580 | return err; | 1625 | return err; |
1581 | 1626 | ||
1582 | err = snd_soc_update_bits(codec, reg2, val_mask, val2); | 1627 | err = snd_soc_update_bits(codec, reg2, val_mask, val2); |
@@ -1584,6 +1629,204 @@ int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol, | |||
1584 | } | 1629 | } |
1585 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r); | 1630 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r); |
1586 | 1631 | ||
1632 | /** | ||
1633 | * snd_soc_info_volsw_s8 - signed mixer info callback | ||
1634 | * @kcontrol: mixer control | ||
1635 | * @uinfo: control element information | ||
1636 | * | ||
1637 | * Callback to provide information about a signed mixer control. | ||
1638 | * | ||
1639 | * Returns 0 for success. | ||
1640 | */ | ||
1641 | int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol, | ||
1642 | struct snd_ctl_elem_info *uinfo) | ||
1643 | { | ||
1644 | int max = (signed char)((kcontrol->private_value >> 16) & 0xff); | ||
1645 | int min = (signed char)((kcontrol->private_value >> 24) & 0xff); | ||
1646 | |||
1647 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1648 | uinfo->count = 2; | ||
1649 | uinfo->value.integer.min = 0; | ||
1650 | uinfo->value.integer.max = max-min; | ||
1651 | return 0; | ||
1652 | } | ||
1653 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_s8); | ||
1654 | |||
1655 | /** | ||
1656 | * snd_soc_get_volsw_s8 - signed mixer get callback | ||
1657 | * @kcontrol: mixer control | ||
1658 | * @uinfo: control element information | ||
1659 | * | ||
1660 | * Callback to get the value of a signed mixer control. | ||
1661 | * | ||
1662 | * Returns 0 for success. | ||
1663 | */ | ||
1664 | int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol, | ||
1665 | struct snd_ctl_elem_value *ucontrol) | ||
1666 | { | ||
1667 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1668 | int reg = kcontrol->private_value & 0xff; | ||
1669 | int min = (signed char)((kcontrol->private_value >> 24) & 0xff); | ||
1670 | int val = snd_soc_read(codec, reg); | ||
1671 | |||
1672 | ucontrol->value.integer.value[0] = | ||
1673 | ((signed char)(val & 0xff))-min; | ||
1674 | ucontrol->value.integer.value[1] = | ||
1675 | ((signed char)((val >> 8) & 0xff))-min; | ||
1676 | return 0; | ||
1677 | } | ||
1678 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw_s8); | ||
1679 | |||
1680 | /** | ||
1681 | * snd_soc_put_volsw_sgn - signed mixer put callback | ||
1682 | * @kcontrol: mixer control | ||
1683 | * @uinfo: control element information | ||
1684 | * | ||
1685 | * Callback to set the value of a signed mixer control. | ||
1686 | * | ||
1687 | * Returns 0 for success. | ||
1688 | */ | ||
1689 | int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, | ||
1690 | struct snd_ctl_elem_value *ucontrol) | ||
1691 | { | ||
1692 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1693 | int reg = kcontrol->private_value & 0xff; | ||
1694 | int min = (signed char)((kcontrol->private_value >> 24) & 0xff); | ||
1695 | unsigned short val; | ||
1696 | |||
1697 | val = (ucontrol->value.integer.value[0]+min) & 0xff; | ||
1698 | val |= ((ucontrol->value.integer.value[1]+min) & 0xff) << 8; | ||
1699 | |||
1700 | return snd_soc_update_bits(codec, reg, 0xffff, val); | ||
1701 | } | ||
1702 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8); | ||
1703 | |||
1704 | /** | ||
1705 | * snd_soc_dai_set_sysclk - configure DAI system or master clock. | ||
1706 | * @dai: DAI | ||
1707 | * @clk_id: DAI specific clock ID | ||
1708 | * @freq: new clock frequency in Hz | ||
1709 | * @dir: new clock direction - input/output. | ||
1710 | * | ||
1711 | * Configures the DAI master (MCLK) or system (SYSCLK) clocking. | ||
1712 | */ | ||
1713 | int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, | ||
1714 | unsigned int freq, int dir) | ||
1715 | { | ||
1716 | if (dai->dai_ops.set_sysclk) | ||
1717 | return dai->dai_ops.set_sysclk(dai, clk_id, freq, dir); | ||
1718 | else | ||
1719 | return -EINVAL; | ||
1720 | } | ||
1721 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk); | ||
1722 | |||
1723 | /** | ||
1724 | * snd_soc_dai_set_clkdiv - configure DAI clock dividers. | ||
1725 | * @dai: DAI | ||
1726 | * @clk_id: DAI specific clock divider ID | ||
1727 | * @div: new clock divisor. | ||
1728 | * | ||
1729 | * Configures the clock dividers. This is used to derive the best DAI bit and | ||
1730 | * frame clocks from the system or master clock. It's best to set the DAI bit | ||
1731 | * and frame clocks as low as possible to save system power. | ||
1732 | */ | ||
1733 | int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, | ||
1734 | int div_id, int div) | ||
1735 | { | ||
1736 | if (dai->dai_ops.set_clkdiv) | ||
1737 | return dai->dai_ops.set_clkdiv(dai, div_id, div); | ||
1738 | else | ||
1739 | return -EINVAL; | ||
1740 | } | ||
1741 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv); | ||
1742 | |||
1743 | /** | ||
1744 | * snd_soc_dai_set_pll - configure DAI PLL. | ||
1745 | * @dai: DAI | ||
1746 | * @pll_id: DAI specific PLL ID | ||
1747 | * @freq_in: PLL input clock frequency in Hz | ||
1748 | * @freq_out: requested PLL output clock frequency in Hz | ||
1749 | * | ||
1750 | * Configures and enables PLL to generate output clock based on input clock. | ||
1751 | */ | ||
1752 | int snd_soc_dai_set_pll(struct snd_soc_dai *dai, | ||
1753 | int pll_id, unsigned int freq_in, unsigned int freq_out) | ||
1754 | { | ||
1755 | if (dai->dai_ops.set_pll) | ||
1756 | return dai->dai_ops.set_pll(dai, pll_id, freq_in, freq_out); | ||
1757 | else | ||
1758 | return -EINVAL; | ||
1759 | } | ||
1760 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll); | ||
1761 | |||
1762 | /** | ||
1763 | * snd_soc_dai_set_fmt - configure DAI hardware audio format. | ||
1764 | * @dai: DAI | ||
1765 | * @clk_id: DAI specific clock ID | ||
1766 | * @fmt: SND_SOC_DAIFMT_ format value. | ||
1767 | * | ||
1768 | * Configures the DAI hardware format and clocking. | ||
1769 | */ | ||
1770 | int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
1771 | { | ||
1772 | if (dai->dai_ops.set_fmt) | ||
1773 | return dai->dai_ops.set_fmt(dai, fmt); | ||
1774 | else | ||
1775 | return -EINVAL; | ||
1776 | } | ||
1777 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); | ||
1778 | |||
1779 | /** | ||
1780 | * snd_soc_dai_set_tdm_slot - configure DAI TDM. | ||
1781 | * @dai: DAI | ||
1782 | * @mask: DAI specific mask representing used slots. | ||
1783 | * @slots: Number of slots in use. | ||
1784 | * | ||
1785 | * Configures a DAI for TDM operation. Both mask and slots are codec and DAI | ||
1786 | * specific. | ||
1787 | */ | ||
1788 | int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, | ||
1789 | unsigned int mask, int slots) | ||
1790 | { | ||
1791 | if (dai->dai_ops.set_sysclk) | ||
1792 | return dai->dai_ops.set_tdm_slot(dai, mask, slots); | ||
1793 | else | ||
1794 | return -EINVAL; | ||
1795 | } | ||
1796 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); | ||
1797 | |||
1798 | /** | ||
1799 | * snd_soc_dai_set_tristate - configure DAI system or master clock. | ||
1800 | * @dai: DAI | ||
1801 | * @tristate: tristate enable | ||
1802 | * | ||
1803 | * Tristates the DAI so that others can use it. | ||
1804 | */ | ||
1805 | int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate) | ||
1806 | { | ||
1807 | if (dai->dai_ops.set_sysclk) | ||
1808 | return dai->dai_ops.set_tristate(dai, tristate); | ||
1809 | else | ||
1810 | return -EINVAL; | ||
1811 | } | ||
1812 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate); | ||
1813 | |||
1814 | /** | ||
1815 | * snd_soc_dai_digital_mute - configure DAI system or master clock. | ||
1816 | * @dai: DAI | ||
1817 | * @mute: mute enable | ||
1818 | * | ||
1819 | * Mutes the DAI DAC. | ||
1820 | */ | ||
1821 | int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute) | ||
1822 | { | ||
1823 | if (dai->dai_ops.digital_mute) | ||
1824 | return dai->dai_ops.digital_mute(dai, mute); | ||
1825 | else | ||
1826 | return -EINVAL; | ||
1827 | } | ||
1828 | EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); | ||
1829 | |||
1587 | static int __devinit snd_soc_init(void) | 1830 | static int __devinit snd_soc_init(void) |
1588 | { | 1831 | { |
1589 | printk(KERN_INFO "ASoC version %s\n", SND_SOC_VERSION); | 1832 | printk(KERN_INFO "ASoC version %s\n", SND_SOC_VERSION); |
@@ -1592,7 +1835,7 @@ static int __devinit snd_soc_init(void) | |||
1592 | 1835 | ||
1593 | static void snd_soc_exit(void) | 1836 | static void snd_soc_exit(void) |
1594 | { | 1837 | { |
1595 | platform_driver_unregister(&soc_driver); | 1838 | platform_driver_unregister(&soc_driver); |
1596 | } | 1839 | } |
1597 | 1840 | ||
1598 | module_init(snd_soc_init); | 1841 | module_init(snd_soc_init); |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index af3326c63504..2c87061c2a6b 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -10,11 +10,6 @@ | |||
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 | * Revision history | ||
14 | * 12th Aug 2005 Initial version. | ||
15 | * 25th Oct 2005 Implemented path power domain. | ||
16 | * 18th Dec 2005 Implemented machine and stream level power domain. | ||
17 | * | ||
18 | * Features: | 13 | * Features: |
19 | * o Changes power status of internal codec blocks depending on the | 14 | * o Changes power status of internal codec blocks depending on the |
20 | * dynamic configuration of codec internal audio paths and active | 15 | * dynamic configuration of codec internal audio paths and active |
@@ -50,23 +45,10 @@ | |||
50 | #include <sound/initval.h> | 45 | #include <sound/initval.h> |
51 | 46 | ||
52 | /* debug */ | 47 | /* debug */ |
53 | #define DAPM_DEBUG 0 | 48 | #ifdef DEBUG |
54 | #if DAPM_DEBUG | ||
55 | #define dump_dapm(codec, action) dbg_dump_dapm(codec, action) | 49 | #define dump_dapm(codec, action) dbg_dump_dapm(codec, action) |
56 | #define dbg(format, arg...) printk(format, ## arg) | ||
57 | #else | 50 | #else |
58 | #define dump_dapm(codec, action) | 51 | #define dump_dapm(codec, action) |
59 | #define dbg(format, arg...) | ||
60 | #endif | ||
61 | |||
62 | #define POP_DEBUG 0 | ||
63 | #if POP_DEBUG | ||
64 | #define POP_TIME 500 /* 500 msecs - change if pop debug is too fast */ | ||
65 | #define pop_wait(time) schedule_timeout_uninterruptible(msecs_to_jiffies(time)) | ||
66 | #define pop_dbg(format, arg...) printk(format, ## arg); pop_wait(POP_TIME) | ||
67 | #else | ||
68 | #define pop_dbg(format, arg...) | ||
69 | #define pop_wait(time) | ||
70 | #endif | 52 | #endif |
71 | 53 | ||
72 | /* dapm power sequences - make this per codec in the future */ | 54 | /* dapm power sequences - make this per codec in the future */ |
@@ -85,6 +67,28 @@ static int dapm_status = 1; | |||
85 | module_param(dapm_status, int, 0); | 67 | module_param(dapm_status, int, 0); |
86 | MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries"); | 68 | MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries"); |
87 | 69 | ||
70 | static unsigned int pop_time; | ||
71 | |||
72 | static void pop_wait(void) | ||
73 | { | ||
74 | if (pop_time) | ||
75 | schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time)); | ||
76 | } | ||
77 | |||
78 | static void pop_dbg(const char *fmt, ...) | ||
79 | { | ||
80 | va_list args; | ||
81 | |||
82 | va_start(args, fmt); | ||
83 | |||
84 | if (pop_time) { | ||
85 | vprintk(fmt, args); | ||
86 | pop_wait(); | ||
87 | } | ||
88 | |||
89 | va_end(args); | ||
90 | } | ||
91 | |||
88 | /* create a new dapm widget */ | 92 | /* create a new dapm widget */ |
89 | static inline struct snd_soc_dapm_widget *dapm_cnew_widget( | 93 | static inline struct snd_soc_dapm_widget *dapm_cnew_widget( |
90 | const struct snd_soc_dapm_widget *_widget) | 94 | const struct snd_soc_dapm_widget *_widget) |
@@ -222,11 +226,12 @@ static int dapm_update_bits(struct snd_soc_dapm_widget *widget) | |||
222 | change = old != new; | 226 | change = old != new; |
223 | if (change) { | 227 | if (change) { |
224 | pop_dbg("pop test %s : %s in %d ms\n", widget->name, | 228 | pop_dbg("pop test %s : %s in %d ms\n", widget->name, |
225 | widget->power ? "on" : "off", POP_TIME); | 229 | widget->power ? "on" : "off", pop_time); |
226 | snd_soc_write(codec, widget->reg, new); | 230 | snd_soc_write(codec, widget->reg, new); |
227 | pop_wait(POP_TIME); | 231 | pop_wait(); |
228 | } | 232 | } |
229 | dbg("reg %x old %x new %x change %d\n", widget->reg, old, new, change); | 233 | pr_debug("reg %x old %x new %x change %d\n", widget->reg, |
234 | old, new, change); | ||
230 | return change; | 235 | return change; |
231 | } | 236 | } |
232 | 237 | ||
@@ -448,6 +453,25 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget) | |||
448 | } | 453 | } |
449 | 454 | ||
450 | /* | 455 | /* |
456 | * Handler for generic register modifier widget. | ||
457 | */ | ||
458 | int dapm_reg_event(struct snd_soc_dapm_widget *w, | ||
459 | struct snd_kcontrol *kcontrol, int event) | ||
460 | { | ||
461 | unsigned int val; | ||
462 | |||
463 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
464 | val = w->on_val; | ||
465 | else | ||
466 | val = w->off_val; | ||
467 | |||
468 | snd_soc_update_bits(w->codec, -(w->reg + 1), | ||
469 | w->mask << w->shift, val << w->shift); | ||
470 | |||
471 | return 0; | ||
472 | } | ||
473 | |||
474 | /* | ||
451 | * Scan each dapm widget for complete audio path. | 475 | * Scan each dapm widget for complete audio path. |
452 | * A complete path is a route that has valid endpoints i.e.:- | 476 | * A complete path is a route that has valid endpoints i.e.:- |
453 | * | 477 | * |
@@ -565,8 +589,8 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) | |||
565 | /* call any power change event handlers */ | 589 | /* call any power change event handlers */ |
566 | if (power_change) { | 590 | if (power_change) { |
567 | if (w->event) { | 591 | if (w->event) { |
568 | dbg("power %s event for %s flags %x\n", | 592 | pr_debug("power %s event for %s flags %x\n", |
569 | w->power ? "on" : "off", w->name, w->event_flags); | 593 | w->power ? "on" : "off", w->name, w->event_flags); |
570 | if (power) { | 594 | if (power) { |
571 | /* power up event */ | 595 | /* power up event */ |
572 | if (w->event_flags & SND_SOC_DAPM_PRE_PMU) { | 596 | if (w->event_flags & SND_SOC_DAPM_PRE_PMU) { |
@@ -608,7 +632,7 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) | |||
608 | return ret; | 632 | return ret; |
609 | } | 633 | } |
610 | 634 | ||
611 | #if DAPM_DEBUG | 635 | #ifdef DEBUG |
612 | static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action) | 636 | static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action) |
613 | { | 637 | { |
614 | struct snd_soc_dapm_widget *w; | 638 | struct snd_soc_dapm_widget *w; |
@@ -693,8 +717,10 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | |||
693 | path->connect = 0; /* old connection must be powered down */ | 717 | path->connect = 0; /* old connection must be powered down */ |
694 | } | 718 | } |
695 | 719 | ||
696 | if (found) | 720 | if (found) { |
697 | dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); | 721 | dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); |
722 | dump_dapm(widget->codec, "mux power update"); | ||
723 | } | ||
698 | 724 | ||
699 | return 0; | 725 | return 0; |
700 | } | 726 | } |
@@ -730,8 +756,10 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | |||
730 | break; | 756 | break; |
731 | } | 757 | } |
732 | 758 | ||
733 | if (found) | 759 | if (found) { |
734 | dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); | 760 | dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); |
761 | dump_dapm(widget->codec, "mixer power update"); | ||
762 | } | ||
735 | 763 | ||
736 | return 0; | 764 | return 0; |
737 | } | 765 | } |
@@ -768,21 +796,18 @@ static ssize_t dapm_widget_show(struct device *dev, | |||
768 | } | 796 | } |
769 | } | 797 | } |
770 | 798 | ||
771 | switch(codec->dapm_state){ | 799 | switch (codec->bias_level) { |
772 | case SNDRV_CTL_POWER_D0: | 800 | case SND_SOC_BIAS_ON: |
773 | state = "D0"; | 801 | state = "On"; |
774 | break; | 802 | break; |
775 | case SNDRV_CTL_POWER_D1: | 803 | case SND_SOC_BIAS_PREPARE: |
776 | state = "D1"; | 804 | state = "Prepare"; |
777 | break; | 805 | break; |
778 | case SNDRV_CTL_POWER_D2: | 806 | case SND_SOC_BIAS_STANDBY: |
779 | state = "D2"; | 807 | state = "Standby"; |
780 | break; | 808 | break; |
781 | case SNDRV_CTL_POWER_D3hot: | 809 | case SND_SOC_BIAS_OFF: |
782 | state = "D3hot"; | 810 | state = "Off"; |
783 | break; | ||
784 | case SNDRV_CTL_POWER_D3cold: | ||
785 | state = "D3cold"; | ||
786 | break; | 811 | break; |
787 | } | 812 | } |
788 | count += sprintf(buf + count, "PM State: %s\n", state); | 813 | count += sprintf(buf + count, "PM State: %s\n", state); |
@@ -792,20 +817,51 @@ static ssize_t dapm_widget_show(struct device *dev, | |||
792 | 817 | ||
793 | static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL); | 818 | static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL); |
794 | 819 | ||
820 | /* pop/click delay times */ | ||
821 | static ssize_t dapm_pop_time_show(struct device *dev, | ||
822 | struct device_attribute *attr, char *buf) | ||
823 | { | ||
824 | return sprintf(buf, "%d\n", pop_time); | ||
825 | } | ||
826 | |||
827 | static ssize_t dapm_pop_time_store(struct device *dev, | ||
828 | struct device_attribute *attr, | ||
829 | const char *buf, size_t count) | ||
830 | |||
831 | { | ||
832 | unsigned long val; | ||
833 | |||
834 | if (strict_strtoul(buf, 10, &val) >= 0) | ||
835 | pop_time = val; | ||
836 | else | ||
837 | printk(KERN_ERR "Unable to parse pop_time setting\n"); | ||
838 | |||
839 | return count; | ||
840 | } | ||
841 | |||
842 | static DEVICE_ATTR(dapm_pop_time, 0744, dapm_pop_time_show, | ||
843 | dapm_pop_time_store); | ||
844 | |||
795 | int snd_soc_dapm_sys_add(struct device *dev) | 845 | int snd_soc_dapm_sys_add(struct device *dev) |
796 | { | 846 | { |
797 | int ret = 0; | 847 | int ret = 0; |
798 | 848 | ||
799 | if (dapm_status) | 849 | if (dapm_status) { |
800 | ret = device_create_file(dev, &dev_attr_dapm_widget); | 850 | ret = device_create_file(dev, &dev_attr_dapm_widget); |
801 | 851 | ||
852 | if (ret == 0) | ||
853 | ret = device_create_file(dev, &dev_attr_dapm_pop_time); | ||
854 | } | ||
855 | |||
802 | return ret; | 856 | return ret; |
803 | } | 857 | } |
804 | 858 | ||
805 | static void snd_soc_dapm_sys_remove(struct device *dev) | 859 | static void snd_soc_dapm_sys_remove(struct device *dev) |
806 | { | 860 | { |
807 | if (dapm_status) | 861 | if (dapm_status) { |
862 | device_remove_file(dev, &dev_attr_dapm_pop_time); | ||
808 | device_remove_file(dev, &dev_attr_dapm_widget); | 863 | device_remove_file(dev, &dev_attr_dapm_widget); |
864 | } | ||
809 | } | 865 | } |
810 | 866 | ||
811 | /* free all dapm widgets and resources */ | 867 | /* free all dapm widgets and resources */ |
@@ -826,8 +882,25 @@ static void dapm_free_widgets(struct snd_soc_codec *codec) | |||
826 | } | 882 | } |
827 | } | 883 | } |
828 | 884 | ||
885 | static int snd_soc_dapm_set_pin(struct snd_soc_codec *codec, | ||
886 | char *pin, int status) | ||
887 | { | ||
888 | struct snd_soc_dapm_widget *w; | ||
889 | |||
890 | list_for_each_entry(w, &codec->dapm_widgets, list) { | ||
891 | if (!strcmp(w->name, pin)) { | ||
892 | pr_debug("dapm: %s: pin %s\n", codec->name, pin); | ||
893 | w->connected = status; | ||
894 | return 0; | ||
895 | } | ||
896 | } | ||
897 | |||
898 | pr_err("dapm: %s: configuring unknown pin %s\n", codec->name, pin); | ||
899 | return -EINVAL; | ||
900 | } | ||
901 | |||
829 | /** | 902 | /** |
830 | * snd_soc_dapm_sync_endpoints - scan and power dapm paths | 903 | * snd_soc_dapm_sync - scan and power dapm paths |
831 | * @codec: audio codec | 904 | * @codec: audio codec |
832 | * | 905 | * |
833 | * Walks all dapm audio paths and powers widgets according to their | 906 | * Walks all dapm audio paths and powers widgets according to their |
@@ -835,27 +908,16 @@ static void dapm_free_widgets(struct snd_soc_codec *codec) | |||
835 | * | 908 | * |
836 | * Returns 0 for success. | 909 | * Returns 0 for success. |
837 | */ | 910 | */ |
838 | int snd_soc_dapm_sync_endpoints(struct snd_soc_codec *codec) | 911 | int snd_soc_dapm_sync(struct snd_soc_codec *codec) |
839 | { | 912 | { |
840 | return dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP); | 913 | int ret = dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP); |
914 | dump_dapm(codec, "sync"); | ||
915 | return ret; | ||
841 | } | 916 | } |
842 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_endpoints); | 917 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); |
843 | 918 | ||
844 | /** | 919 | static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, |
845 | * snd_soc_dapm_connect_input - connect dapm widgets | 920 | const char *sink, const char *control, const char *source) |
846 | * @codec: audio codec | ||
847 | * @sink: name of target widget | ||
848 | * @control: mixer control name | ||
849 | * @source: name of source name | ||
850 | * | ||
851 | * Connects 2 dapm widgets together via a named audio path. The sink is | ||
852 | * the widget receiving the audio signal, whilst the source is the sender | ||
853 | * of the audio signal. | ||
854 | * | ||
855 | * Returns 0 for success else error. | ||
856 | */ | ||
857 | int snd_soc_dapm_connect_input(struct snd_soc_codec *codec, const char *sink, | ||
858 | const char * control, const char *source) | ||
859 | { | 921 | { |
860 | struct snd_soc_dapm_path *path; | 922 | struct snd_soc_dapm_path *path; |
861 | struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; | 923 | struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; |
@@ -957,9 +1019,64 @@ err: | |||
957 | kfree(path); | 1019 | kfree(path); |
958 | return ret; | 1020 | return ret; |
959 | } | 1021 | } |
1022 | |||
1023 | /** | ||
1024 | * snd_soc_dapm_connect_input - connect dapm widgets | ||
1025 | * @codec: audio codec | ||
1026 | * @sink: name of target widget | ||
1027 | * @control: mixer control name | ||
1028 | * @source: name of source name | ||
1029 | * | ||
1030 | * Connects 2 dapm widgets together via a named audio path. The sink is | ||
1031 | * the widget receiving the audio signal, whilst the source is the sender | ||
1032 | * of the audio signal. | ||
1033 | * | ||
1034 | * This function has been deprecated in favour of snd_soc_dapm_add_routes(). | ||
1035 | * | ||
1036 | * Returns 0 for success else error. | ||
1037 | */ | ||
1038 | int snd_soc_dapm_connect_input(struct snd_soc_codec *codec, const char *sink, | ||
1039 | const char *control, const char *source) | ||
1040 | { | ||
1041 | return snd_soc_dapm_add_route(codec, sink, control, source); | ||
1042 | } | ||
960 | EXPORT_SYMBOL_GPL(snd_soc_dapm_connect_input); | 1043 | EXPORT_SYMBOL_GPL(snd_soc_dapm_connect_input); |
961 | 1044 | ||
962 | /** | 1045 | /** |
1046 | * snd_soc_dapm_add_routes - Add routes between DAPM widgets | ||
1047 | * @codec: codec | ||
1048 | * @route: audio routes | ||
1049 | * @num: number of routes | ||
1050 | * | ||
1051 | * Connects 2 dapm widgets together via a named audio path. The sink is | ||
1052 | * the widget receiving the audio signal, whilst the source is the sender | ||
1053 | * of the audio signal. | ||
1054 | * | ||
1055 | * Returns 0 for success else error. On error all resources can be freed | ||
1056 | * with a call to snd_soc_card_free(). | ||
1057 | */ | ||
1058 | int snd_soc_dapm_add_routes(struct snd_soc_codec *codec, | ||
1059 | const struct snd_soc_dapm_route *route, int num) | ||
1060 | { | ||
1061 | int i, ret; | ||
1062 | |||
1063 | for (i = 0; i < num; i++) { | ||
1064 | ret = snd_soc_dapm_add_route(codec, route->sink, | ||
1065 | route->control, route->source); | ||
1066 | if (ret < 0) { | ||
1067 | printk(KERN_ERR "Failed to add route %s->%s\n", | ||
1068 | route->source, | ||
1069 | route->sink); | ||
1070 | return ret; | ||
1071 | } | ||
1072 | route++; | ||
1073 | } | ||
1074 | |||
1075 | return 0; | ||
1076 | } | ||
1077 | EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes); | ||
1078 | |||
1079 | /** | ||
963 | * snd_soc_dapm_new_widgets - add new dapm widgets | 1080 | * snd_soc_dapm_new_widgets - add new dapm widgets |
964 | * @codec: audio codec | 1081 | * @codec: audio codec |
965 | * | 1082 | * |
@@ -1234,6 +1351,33 @@ int snd_soc_dapm_new_control(struct snd_soc_codec *codec, | |||
1234 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control); | 1351 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control); |
1235 | 1352 | ||
1236 | /** | 1353 | /** |
1354 | * snd_soc_dapm_new_controls - create new dapm controls | ||
1355 | * @codec: audio codec | ||
1356 | * @widget: widget array | ||
1357 | * @num: number of widgets | ||
1358 | * | ||
1359 | * Creates new DAPM controls based upon the templates. | ||
1360 | * | ||
1361 | * Returns 0 for success else error. | ||
1362 | */ | ||
1363 | int snd_soc_dapm_new_controls(struct snd_soc_codec *codec, | ||
1364 | const struct snd_soc_dapm_widget *widget, | ||
1365 | int num) | ||
1366 | { | ||
1367 | int i, ret; | ||
1368 | |||
1369 | for (i = 0; i < num; i++) { | ||
1370 | ret = snd_soc_dapm_new_control(codec, widget); | ||
1371 | if (ret < 0) | ||
1372 | return ret; | ||
1373 | widget++; | ||
1374 | } | ||
1375 | return 0; | ||
1376 | } | ||
1377 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls); | ||
1378 | |||
1379 | |||
1380 | /** | ||
1237 | * snd_soc_dapm_stream_event - send a stream event to the dapm core | 1381 | * snd_soc_dapm_stream_event - send a stream event to the dapm core |
1238 | * @codec: audio codec | 1382 | * @codec: audio codec |
1239 | * @stream: stream name | 1383 | * @stream: stream name |
@@ -1257,8 +1401,8 @@ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, | |||
1257 | { | 1401 | { |
1258 | if (!w->sname) | 1402 | if (!w->sname) |
1259 | continue; | 1403 | continue; |
1260 | dbg("widget %s\n %s stream %s event %d\n", w->name, w->sname, | 1404 | pr_debug("widget %s\n %s stream %s event %d\n", |
1261 | stream, event); | 1405 | w->name, w->sname, stream, event); |
1262 | if (strstr(w->sname, stream)) { | 1406 | if (strstr(w->sname, stream)) { |
1263 | switch(event) { | 1407 | switch(event) { |
1264 | case SND_SOC_DAPM_STREAM_START: | 1408 | case SND_SOC_DAPM_STREAM_START: |
@@ -1294,53 +1438,81 @@ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, | |||
1294 | EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event); | 1438 | EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event); |
1295 | 1439 | ||
1296 | /** | 1440 | /** |
1297 | * snd_soc_dapm_device_event - send a device event to the dapm core | 1441 | * snd_soc_dapm_set_bias_level - set the bias level for the system |
1298 | * @socdev: audio device | 1442 | * @socdev: audio device |
1299 | * @event: device event | 1443 | * @level: level to configure |
1300 | * | 1444 | * |
1301 | * Sends a device event to the dapm core. The core then makes any | 1445 | * Configure the bias (power) levels for the SoC audio device. |
1302 | * necessary machine or codec power changes.. | ||
1303 | * | 1446 | * |
1304 | * Returns 0 for success else error. | 1447 | * Returns 0 for success else error. |
1305 | */ | 1448 | */ |
1306 | int snd_soc_dapm_device_event(struct snd_soc_device *socdev, int event) | 1449 | int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev, |
1450 | enum snd_soc_bias_level level) | ||
1307 | { | 1451 | { |
1308 | struct snd_soc_codec *codec = socdev->codec; | 1452 | struct snd_soc_codec *codec = socdev->codec; |
1309 | struct snd_soc_machine *machine = socdev->machine; | 1453 | struct snd_soc_machine *machine = socdev->machine; |
1454 | int ret = 0; | ||
1310 | 1455 | ||
1311 | if (machine->dapm_event) | 1456 | if (machine->set_bias_level) |
1312 | machine->dapm_event(machine, event); | 1457 | ret = machine->set_bias_level(machine, level); |
1313 | if (codec->dapm_event) | 1458 | if (ret == 0 && codec->set_bias_level) |
1314 | codec->dapm_event(codec, event); | 1459 | ret = codec->set_bias_level(codec, level); |
1315 | return 0; | 1460 | |
1461 | return ret; | ||
1316 | } | 1462 | } |
1317 | EXPORT_SYMBOL_GPL(snd_soc_dapm_device_event); | ||
1318 | 1463 | ||
1319 | /** | 1464 | /** |
1320 | * snd_soc_dapm_set_endpoint - set audio endpoint status | 1465 | * snd_soc_dapm_enable_pin - enable pin. |
1466 | * @snd_soc_codec: SoC codec | ||
1467 | * @pin: pin name | ||
1468 | * | ||
1469 | * Enables input/output pin and it's parents or children widgets iff there is | ||
1470 | * a valid audio route and active audio stream. | ||
1471 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to | ||
1472 | * do any widget power switching. | ||
1473 | */ | ||
1474 | int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, char *pin) | ||
1475 | { | ||
1476 | return snd_soc_dapm_set_pin(codec, pin, 1); | ||
1477 | } | ||
1478 | EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin); | ||
1479 | |||
1480 | /** | ||
1481 | * snd_soc_dapm_disable_pin - disable pin. | ||
1482 | * @codec: SoC codec | ||
1483 | * @pin: pin name | ||
1484 | * | ||
1485 | * Disables input/output pin and it's parents or children widgets. | ||
1486 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to | ||
1487 | * do any widget power switching. | ||
1488 | */ | ||
1489 | int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, char *pin) | ||
1490 | { | ||
1491 | return snd_soc_dapm_set_pin(codec, pin, 0); | ||
1492 | } | ||
1493 | EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin); | ||
1494 | |||
1495 | /** | ||
1496 | * snd_soc_dapm_get_pin_status - get audio pin status | ||
1321 | * @codec: audio codec | 1497 | * @codec: audio codec |
1322 | * @endpoint: audio signal endpoint (or start point) | 1498 | * @pin: audio signal pin endpoint (or start point) |
1323 | * @status: point status | ||
1324 | * | 1499 | * |
1325 | * Set audio endpoint status - connected or disconnected. | 1500 | * Get audio pin status - connected or disconnected. |
1326 | * | 1501 | * |
1327 | * Returns 0 for success else error. | 1502 | * Returns 1 for connected otherwise 0. |
1328 | */ | 1503 | */ |
1329 | int snd_soc_dapm_set_endpoint(struct snd_soc_codec *codec, | 1504 | int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, char *pin) |
1330 | char *endpoint, int status) | ||
1331 | { | 1505 | { |
1332 | struct snd_soc_dapm_widget *w; | 1506 | struct snd_soc_dapm_widget *w; |
1333 | 1507 | ||
1334 | list_for_each_entry(w, &codec->dapm_widgets, list) { | 1508 | list_for_each_entry(w, &codec->dapm_widgets, list) { |
1335 | if (!strcmp(w->name, endpoint)) { | 1509 | if (!strcmp(w->name, pin)) |
1336 | w->connected = status; | 1510 | return w->connected; |
1337 | return 0; | ||
1338 | } | ||
1339 | } | 1511 | } |
1340 | 1512 | ||
1341 | return -ENODEV; | 1513 | return 0; |
1342 | } | 1514 | } |
1343 | EXPORT_SYMBOL_GPL(snd_soc_dapm_set_endpoint); | 1515 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status); |
1344 | 1516 | ||
1345 | /** | 1517 | /** |
1346 | * snd_soc_dapm_free - free dapm resources | 1518 | * snd_soc_dapm_free - free dapm resources |
diff --git a/sound/sparc/Kconfig b/sound/sparc/Kconfig index 079e22af074c..d75deba5617d 100644 --- a/sound/sparc/Kconfig +++ b/sound/sparc/Kconfig | |||
@@ -1,11 +1,17 @@ | |||
1 | # ALSA Sparc drivers | 1 | # ALSA Sparc drivers |
2 | 2 | ||
3 | menu "ALSA Sparc devices" | 3 | menuconfig SND_SPARC |
4 | depends on SND!=n && SPARC | 4 | bool "Sparc sound devices" |
5 | depends on SPARC | ||
6 | default y | ||
7 | help | ||
8 | Support for sound devices specific to Sun SPARC architectures. | ||
9 | |||
10 | if SND_SPARC | ||
5 | 11 | ||
6 | config SND_SUN_AMD7930 | 12 | config SND_SUN_AMD7930 |
7 | tristate "Sun AMD7930" | 13 | tristate "Sun AMD7930" |
8 | depends on SBUS && SND | 14 | depends on SBUS |
9 | select SND_PCM | 15 | select SND_PCM |
10 | help | 16 | help |
11 | Say Y here to include support for AMD7930 sound device on Sun. | 17 | Say Y here to include support for AMD7930 sound device on Sun. |
@@ -15,7 +21,6 @@ config SND_SUN_AMD7930 | |||
15 | 21 | ||
16 | config SND_SUN_CS4231 | 22 | config SND_SUN_CS4231 |
17 | tristate "Sun CS4231" | 23 | tristate "Sun CS4231" |
18 | depends on SND | ||
19 | select SND_PCM | 24 | select SND_PCM |
20 | help | 25 | help |
21 | Say Y here to include support for CS4231 sound device on Sun. | 26 | Say Y here to include support for CS4231 sound device on Sun. |
@@ -25,7 +30,7 @@ config SND_SUN_CS4231 | |||
25 | 30 | ||
26 | config SND_SUN_DBRI | 31 | config SND_SUN_DBRI |
27 | tristate "Sun DBRI" | 32 | tristate "Sun DBRI" |
28 | depends on SND && SBUS | 33 | depends on SBUS |
29 | select SND_PCM | 34 | select SND_PCM |
30 | help | 35 | help |
31 | Say Y here to include support for DBRI sound device on Sun. | 36 | Say Y here to include support for DBRI sound device on Sun. |
@@ -33,4 +38,4 @@ config SND_SUN_DBRI | |||
33 | To compile this driver as a module, choose M here: the module | 38 | To compile this driver as a module, choose M here: the module |
34 | will be called snd-sun-dbri. | 39 | will be called snd-sun-dbri. |
35 | 40 | ||
36 | endmenu | 41 | endif # SND_SPARC |
diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index 3d00e0797b11..ee2e1b4f3551 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c | |||
@@ -2490,7 +2490,7 @@ static void dbri_debug_read(struct snd_info_entry *entry, | |||
2490 | } | 2490 | } |
2491 | #endif | 2491 | #endif |
2492 | 2492 | ||
2493 | void __devinit snd_dbri_proc(struct snd_card *card) | 2493 | static void __devinit snd_dbri_proc(struct snd_card *card) |
2494 | { | 2494 | { |
2495 | struct snd_dbri *dbri = card->private_data; | 2495 | struct snd_dbri *dbri = card->private_data; |
2496 | struct snd_info_entry *entry; | 2496 | struct snd_info_entry *entry; |
diff --git a/sound/spi/Kconfig b/sound/spi/Kconfig index 0d08c29213c8..e6485be2e6f7 100644 --- a/sound/spi/Kconfig +++ b/sound/spi/Kconfig | |||
@@ -1,7 +1,13 @@ | |||
1 | #SPI drivers | 1 | #SPI drivers |
2 | 2 | ||
3 | menu "SPI devices" | 3 | menuconfig SND_SPI |
4 | depends on SND != n | 4 | bool "SPI sound devices" |
5 | depends on SPI | ||
6 | default y | ||
7 | help | ||
8 | Support for sound devices connected via the SPI bus. | ||
9 | |||
10 | if SND_SPI | ||
5 | 11 | ||
6 | config SND_AT73C213 | 12 | config SND_AT73C213 |
7 | tristate "Atmel AT73C213 DAC driver" | 13 | tristate "Atmel AT73C213 DAC driver" |
@@ -28,4 +34,5 @@ config SND_AT73C213_TARGET_BITRATE | |||
28 | 34 | ||
29 | Set to 48000 Hz by default. | 35 | Set to 48000 Hz by default. |
30 | 36 | ||
31 | endmenu | 37 | endif # SND_SPI |
38 | |||
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 9351b8a765b9..ffcdc8f4ef66 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig | |||
@@ -1,11 +1,16 @@ | |||
1 | # ALSA USB drivers | 1 | # ALSA USB drivers |
2 | 2 | ||
3 | menu "USB devices" | 3 | menuconfig SND_USB |
4 | depends on SND!=n && USB!=n | 4 | bool "USB sound devices" |
5 | depends on USB | ||
6 | default y | ||
7 | help | ||
8 | Support for sound devices connected via the USB bus. | ||
9 | |||
10 | if SND_USB && USB | ||
5 | 11 | ||
6 | config SND_USB_AUDIO | 12 | config SND_USB_AUDIO |
7 | tristate "USB Audio/MIDI driver" | 13 | tristate "USB Audio/MIDI driver" |
8 | depends on SND && USB | ||
9 | select SND_HWDEP | 14 | select SND_HWDEP |
10 | select SND_RAWMIDI | 15 | select SND_RAWMIDI |
11 | select SND_PCM | 16 | select SND_PCM |
@@ -18,7 +23,7 @@ config SND_USB_AUDIO | |||
18 | 23 | ||
19 | config SND_USB_USX2Y | 24 | config SND_USB_USX2Y |
20 | tristate "Tascam US-122, US-224 and US-428 USB driver" | 25 | tristate "Tascam US-122, US-224 and US-428 USB driver" |
21 | depends on SND && USB && (X86 || PPC || ALPHA) | 26 | depends on X86 || PPC || ALPHA |
22 | select SND_HWDEP | 27 | select SND_HWDEP |
23 | select SND_RAWMIDI | 28 | select SND_RAWMIDI |
24 | select SND_PCM | 29 | select SND_PCM |
@@ -31,7 +36,6 @@ config SND_USB_USX2Y | |||
31 | 36 | ||
32 | config SND_USB_CAIAQ | 37 | config SND_USB_CAIAQ |
33 | tristate "Native Instruments USB audio devices" | 38 | tristate "Native Instruments USB audio devices" |
34 | depends on SND && USB | ||
35 | select SND_HWDEP | 39 | select SND_HWDEP |
36 | select SND_RAWMIDI | 40 | select SND_RAWMIDI |
37 | select SND_PCM | 41 | select SND_PCM |
@@ -63,5 +67,5 @@ config SND_USB_CAIAQ_INPUT | |||
63 | * Native Instruments Kore Controller 2 | 67 | * Native Instruments Kore Controller 2 |
64 | * Native Instruments Audio Kontrol 1 | 68 | * Native Instruments Audio Kontrol 1 |
65 | 69 | ||
66 | endmenu | 70 | endif # SND_USB |
67 | 71 | ||
diff --git a/sound/usb/caiaq/caiaq-audio.c b/sound/usb/caiaq/caiaq-audio.c index 24970a5c888f..b3a603325835 100644 --- a/sound/usb/caiaq/caiaq-audio.c +++ b/sound/usb/caiaq/caiaq-audio.c | |||
@@ -637,6 +637,7 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev) | |||
637 | switch (dev->chip.usb_id) { | 637 | switch (dev->chip.usb_id) { |
638 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): | 638 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): |
639 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): | 639 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): |
640 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_SESSIONIO): | ||
640 | dev->samplerates |= SNDRV_PCM_RATE_88200; | 641 | dev->samplerates |= SNDRV_PCM_RATE_88200; |
641 | dev->samplerates |= SNDRV_PCM_RATE_192000; | 642 | dev->samplerates |= SNDRV_PCM_RATE_192000; |
642 | break; | 643 | break; |
diff --git a/sound/usb/caiaq/caiaq-device.c b/sound/usb/caiaq/caiaq-device.c index a972f77bd785..83175083e50f 100644 --- a/sound/usb/caiaq/caiaq-device.c +++ b/sound/usb/caiaq/caiaq-device.c | |||
@@ -42,14 +42,15 @@ | |||
42 | #endif | 42 | #endif |
43 | 43 | ||
44 | MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); | 44 | MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); |
45 | MODULE_DESCRIPTION("caiaq USB audio, version 1.3.6"); | 45 | MODULE_DESCRIPTION("caiaq USB audio, version 1.3.8"); |
46 | MODULE_LICENSE("GPL"); | 46 | MODULE_LICENSE("GPL"); |
47 | MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," | 47 | MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," |
48 | "{Native Instruments, RigKontrol3}," | 48 | "{Native Instruments, RigKontrol3}," |
49 | "{Native Instruments, Kore Controller}," | 49 | "{Native Instruments, Kore Controller}," |
50 | "{Native Instruments, Kore Controller 2}," | 50 | "{Native Instruments, Kore Controller 2}," |
51 | "{Native Instruments, Audio Kontrol 1}" | 51 | "{Native Instruments, Audio Kontrol 1}," |
52 | "{Native Instruments, Audio 8 DJ}}"); | 52 | "{Native Instruments, Audio 8 DJ}," |
53 | "{Native Instruments, Session I/O}}"); | ||
53 | 54 | ||
54 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */ | 55 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */ |
55 | static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */ | 56 | static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */ |
@@ -110,6 +111,11 @@ static struct usb_device_id snd_usb_id_table[] = { | |||
110 | .idVendor = USB_VID_NATIVEINSTRUMENTS, | 111 | .idVendor = USB_VID_NATIVEINSTRUMENTS, |
111 | .idProduct = USB_PID_AUDIO8DJ | 112 | .idProduct = USB_PID_AUDIO8DJ |
112 | }, | 113 | }, |
114 | { | ||
115 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE, | ||
116 | .idVendor = USB_VID_NATIVEINSTRUMENTS, | ||
117 | .idProduct = USB_PID_SESSIONIO | ||
118 | }, | ||
113 | { /* terminator */ } | 119 | { /* terminator */ } |
114 | }; | 120 | }; |
115 | 121 | ||
diff --git a/sound/usb/caiaq/caiaq-device.h b/sound/usb/caiaq/caiaq-device.h index 96a491379c60..f9fbdbae269d 100644 --- a/sound/usb/caiaq/caiaq-device.h +++ b/sound/usb/caiaq/caiaq-device.h | |||
@@ -11,6 +11,7 @@ | |||
11 | #define USB_PID_KORECONTROLLER2 0x4712 | 11 | #define USB_PID_KORECONTROLLER2 0x4712 |
12 | #define USB_PID_AK1 0x0815 | 12 | #define USB_PID_AK1 0x0815 |
13 | #define USB_PID_AUDIO8DJ 0x1978 | 13 | #define USB_PID_AUDIO8DJ 0x1978 |
14 | #define USB_PID_SESSIONIO 0x1915 | ||
14 | 15 | ||
15 | #define EP1_BUFSIZE 64 | 16 | #define EP1_BUFSIZE 64 |
16 | #define CAIAQ_USB_STR_LEN 0xff | 17 | #define CAIAQ_USB_STR_LEN 0xff |
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 410be4aff1ba..b8cfb7c22768 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c | |||
@@ -819,10 +819,6 @@ static const char *usb_error_string(int err) | |||
819 | return "device disabled"; | 819 | return "device disabled"; |
820 | case -EHOSTUNREACH: | 820 | case -EHOSTUNREACH: |
821 | return "device suspended"; | 821 | return "device suspended"; |
822 | #ifndef CONFIG_USB_EHCI_SPLIT_ISO | ||
823 | case -ENOSYS: | ||
824 | return "enable CONFIG_USB_EHCI_SPLIT_ISO to play through a hub"; | ||
825 | #endif | ||
826 | case -EINVAL: | 822 | case -EINVAL: |
827 | case -EAGAIN: | 823 | case -EAGAIN: |
828 | case -EFBIG: | 824 | case -EFBIG: |
diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index 82a8d14c26af..9ea726c049c6 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h | |||
@@ -210,6 +210,11 @@ YAMAHA_DEVICE(0x1042, NULL), | |||
210 | YAMAHA_DEVICE(0x1043, NULL), | 210 | YAMAHA_DEVICE(0x1043, NULL), |
211 | YAMAHA_DEVICE(0x1044, NULL), | 211 | YAMAHA_DEVICE(0x1044, NULL), |
212 | YAMAHA_DEVICE(0x1045, NULL), | 212 | YAMAHA_DEVICE(0x1045, NULL), |
213 | YAMAHA_INTERFACE(0x104e, 0, NULL), | ||
214 | YAMAHA_DEVICE(0x104f, NULL), | ||
215 | YAMAHA_DEVICE(0x1050, NULL), | ||
216 | YAMAHA_DEVICE(0x1051, NULL), | ||
217 | YAMAHA_DEVICE(0x1052, NULL), | ||
213 | YAMAHA_DEVICE(0x2000, "DGP-7"), | 218 | YAMAHA_DEVICE(0x2000, "DGP-7"), |
214 | YAMAHA_DEVICE(0x2001, "DGP-5"), | 219 | YAMAHA_DEVICE(0x2001, "DGP-5"), |
215 | YAMAHA_DEVICE(0x2002, NULL), | 220 | YAMAHA_DEVICE(0x2002, NULL), |
@@ -1379,6 +1384,39 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
1379 | } | 1384 | } |
1380 | }, | 1385 | }, |
1381 | 1386 | ||
1387 | { | ||
1388 | /* Roland SonicCell */ | ||
1389 | USB_DEVICE(0x0582, 0x00c2), | ||
1390 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | ||
1391 | .vendor_name = "Roland", | ||
1392 | .product_name = "SonicCell", | ||
1393 | .ifnum = QUIRK_ANY_INTERFACE, | ||
1394 | .type = QUIRK_COMPOSITE, | ||
1395 | .data = (const struct snd_usb_audio_quirk[]) { | ||
1396 | { | ||
1397 | .ifnum = 0, | ||
1398 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | ||
1399 | }, | ||
1400 | { | ||
1401 | .ifnum = 1, | ||
1402 | .type = QUIRK_AUDIO_STANDARD_INTERFACE | ||
1403 | }, | ||
1404 | { | ||
1405 | .ifnum = 2, | ||
1406 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | ||
1407 | .data = & (const struct snd_usb_midi_endpoint_info) { | ||
1408 | .out_cables = 0x0001, | ||
1409 | .in_cables = 0x0001 | ||
1410 | } | ||
1411 | }, | ||
1412 | { | ||
1413 | .ifnum = -1 | ||
1414 | } | ||
1415 | } | ||
1416 | } | ||
1417 | }, | ||
1418 | |||
1419 | |||
1382 | /* Guillemot devices */ | 1420 | /* Guillemot devices */ |
1383 | { | 1421 | { |
1384 | /* | 1422 | /* |