diff options
Diffstat (limited to 'sound/pci/ca0106/ca0106_mixer.c')
-rw-r--r-- | sound/pci/ca0106/ca0106_mixer.c | 182 |
1 files changed, 130 insertions, 52 deletions
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 3025ed1b6e1..9845a20f542 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c | |||
@@ -75,6 +75,84 @@ | |||
75 | 75 | ||
76 | #include "ca0106.h" | 76 | #include "ca0106.h" |
77 | 77 | ||
78 | static void ca0106_spdif_enable(struct snd_ca0106 *emu) | ||
79 | { | ||
80 | unsigned int val; | ||
81 | |||
82 | if (emu->spdif_enable) { | ||
83 | /* Digital */ | ||
84 | snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); | ||
85 | snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x0b000000); | ||
86 | val = snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) & ~0x1000; | ||
87 | snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, val); | ||
88 | val = inl(emu->port + GPIO) & ~0x101; | ||
89 | outl(val, emu->port + GPIO); | ||
90 | |||
91 | } else { | ||
92 | /* Analog */ | ||
93 | snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); | ||
94 | snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000f0000); | ||
95 | val = snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000; | ||
96 | snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, val); | ||
97 | val = inl(emu->port + GPIO) | 0x101; | ||
98 | outl(val, emu->port + GPIO); | ||
99 | } | ||
100 | } | ||
101 | |||
102 | static void ca0106_set_capture_source(struct snd_ca0106 *emu) | ||
103 | { | ||
104 | unsigned int val = emu->capture_source; | ||
105 | unsigned int source, mask; | ||
106 | source = (val << 28) | (val << 24) | (val << 20) | (val << 16); | ||
107 | mask = snd_ca0106_ptr_read(emu, CAPTURE_SOURCE, 0) & 0xffff; | ||
108 | snd_ca0106_ptr_write(emu, CAPTURE_SOURCE, 0, source | mask); | ||
109 | } | ||
110 | |||
111 | static void ca0106_set_i2c_capture_source(struct snd_ca0106 *emu, | ||
112 | unsigned int val, int force) | ||
113 | { | ||
114 | unsigned int ngain, ogain; | ||
115 | u32 source; | ||
116 | |||
117 | snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ | ||
118 | ngain = emu->i2c_capture_volume[val][0]; /* Left */ | ||
119 | ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ | ||
120 | if (force || ngain != ogain) | ||
121 | snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ngain & 0xff); | ||
122 | ngain = emu->i2c_capture_volume[val][1]; /* Right */ | ||
123 | ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */ | ||
124 | if (force || ngain != ogain) | ||
125 | snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ngain & 0xff); | ||
126 | source = 1 << val; | ||
127 | snd_ca0106_i2c_write(emu, ADC_MUX, source); /* Set source */ | ||
128 | emu->i2c_capture_source = val; | ||
129 | } | ||
130 | |||
131 | static void ca0106_set_capture_mic_line_in(struct snd_ca0106 *emu) | ||
132 | { | ||
133 | u32 tmp; | ||
134 | |||
135 | if (emu->capture_mic_line_in) { | ||
136 | /* snd_ca0106_i2c_write(emu, ADC_MUX, 0); */ /* Mute input */ | ||
137 | tmp = inl(emu->port+GPIO) & ~0x400; | ||
138 | tmp = tmp | 0x400; | ||
139 | outl(tmp, emu->port+GPIO); | ||
140 | /* snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC); */ | ||
141 | } else { | ||
142 | /* snd_ca0106_i2c_write(emu, ADC_MUX, 0); */ /* Mute input */ | ||
143 | tmp = inl(emu->port+GPIO) & ~0x400; | ||
144 | outl(tmp, emu->port+GPIO); | ||
145 | /* snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN); */ | ||
146 | } | ||
147 | } | ||
148 | |||
149 | static void ca0106_set_spdif_bits(struct snd_ca0106 *emu, int idx) | ||
150 | { | ||
151 | snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, emu->spdif_bits[idx]); | ||
152 | } | ||
153 | |||
154 | /* | ||
155 | */ | ||
78 | static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1); | 156 | static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1); |
79 | static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1); | 157 | static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1); |
80 | 158 | ||
@@ -95,30 +173,12 @@ static int snd_ca0106_shared_spdif_put(struct snd_kcontrol *kcontrol, | |||
95 | struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); | 173 | struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); |
96 | unsigned int val; | 174 | unsigned int val; |
97 | int change = 0; | 175 | int change = 0; |
98 | u32 mask; | ||
99 | 176 | ||
100 | val = !!ucontrol->value.integer.value[0]; | 177 | val = !!ucontrol->value.integer.value[0]; |
101 | change = (emu->spdif_enable != val); | 178 | change = (emu->spdif_enable != val); |
102 | if (change) { | 179 | if (change) { |
103 | emu->spdif_enable = val; | 180 | emu->spdif_enable = val; |
104 | if (val) { | 181 | ca0106_spdif_enable(emu); |
105 | /* Digital */ | ||
106 | snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); | ||
107 | snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x0b000000); | ||
108 | snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, | ||
109 | snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) & ~0x1000); | ||
110 | mask = inl(emu->port + GPIO) & ~0x101; | ||
111 | outl(mask, emu->port + GPIO); | ||
112 | |||
113 | } else { | ||
114 | /* Analog */ | ||
115 | snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); | ||
116 | snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000f0000); | ||
117 | snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, | ||
118 | snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000); | ||
119 | mask = inl(emu->port + GPIO) | 0x101; | ||
120 | outl(mask, emu->port + GPIO); | ||
121 | } | ||
122 | } | 182 | } |
123 | return change; | 183 | return change; |
124 | } | 184 | } |
@@ -154,8 +214,6 @@ static int snd_ca0106_capture_source_put(struct snd_kcontrol *kcontrol, | |||
154 | struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); | 214 | struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); |
155 | unsigned int val; | 215 | unsigned int val; |
156 | int change = 0; | 216 | int change = 0; |
157 | u32 mask; | ||
158 | u32 source; | ||
159 | 217 | ||
160 | val = ucontrol->value.enumerated.item[0] ; | 218 | val = ucontrol->value.enumerated.item[0] ; |
161 | if (val >= 6) | 219 | if (val >= 6) |
@@ -163,9 +221,7 @@ static int snd_ca0106_capture_source_put(struct snd_kcontrol *kcontrol, | |||
163 | change = (emu->capture_source != val); | 221 | change = (emu->capture_source != val); |
164 | if (change) { | 222 | if (change) { |
165 | emu->capture_source = val; | 223 | emu->capture_source = val; |
166 | source = (val << 28) | (val << 24) | (val << 20) | (val << 16); | 224 | ca0106_set_capture_source(emu); |
167 | mask = snd_ca0106_ptr_read(emu, CAPTURE_SOURCE, 0) & 0xffff; | ||
168 | snd_ca0106_ptr_write(emu, CAPTURE_SOURCE, 0, source | mask); | ||
169 | } | 225 | } |
170 | return change; | 226 | return change; |
171 | } | 227 | } |
@@ -200,9 +256,7 @@ static int snd_ca0106_i2c_capture_source_put(struct snd_kcontrol *kcontrol, | |||
200 | { | 256 | { |
201 | struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); | 257 | struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); |
202 | unsigned int source_id; | 258 | unsigned int source_id; |
203 | unsigned int ngain, ogain; | ||
204 | int change = 0; | 259 | int change = 0; |
205 | u32 source; | ||
206 | /* If the capture source has changed, | 260 | /* If the capture source has changed, |
207 | * update the capture volume from the cached value | 261 | * update the capture volume from the cached value |
208 | * for the particular source. | 262 | * for the particular source. |
@@ -212,18 +266,7 @@ static int snd_ca0106_i2c_capture_source_put(struct snd_kcontrol *kcontrol, | |||
212 | return -EINVAL; | 266 | return -EINVAL; |
213 | change = (emu->i2c_capture_source != source_id); | 267 | change = (emu->i2c_capture_source != source_id); |
214 | if (change) { | 268 | if (change) { |
215 | snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ | 269 | ca0106_set_i2c_capture_source(emu, source_id, 0); |
216 | ngain = emu->i2c_capture_volume[source_id][0]; /* Left */ | ||
217 | ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ | ||
218 | if (ngain != ogain) | ||
219 | snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff)); | ||
220 | ngain = emu->i2c_capture_volume[source_id][1]; /* Left */ | ||
221 | ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Left */ | ||
222 | if (ngain != ogain) | ||
223 | snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); | ||
224 | source = 1 << source_id; | ||
225 | snd_ca0106_i2c_write(emu, ADC_MUX, source); /* Set source */ | ||
226 | emu->i2c_capture_source = source_id; | ||
227 | } | 270 | } |
228 | return change; | 271 | return change; |
229 | } | 272 | } |
@@ -271,7 +314,6 @@ static int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol, | |||
271 | struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); | 314 | struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); |
272 | unsigned int val; | 315 | unsigned int val; |
273 | int change = 0; | 316 | int change = 0; |
274 | u32 tmp; | ||
275 | 317 | ||
276 | val = ucontrol->value.enumerated.item[0] ; | 318 | val = ucontrol->value.enumerated.item[0] ; |
277 | if (val > 1) | 319 | if (val > 1) |
@@ -279,18 +321,7 @@ static int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol, | |||
279 | change = (emu->capture_mic_line_in != val); | 321 | change = (emu->capture_mic_line_in != val); |
280 | if (change) { | 322 | if (change) { |
281 | emu->capture_mic_line_in = val; | 323 | emu->capture_mic_line_in = val; |
282 | if (val) { | 324 | ca0106_set_capture_mic_line_in(emu); |
283 | //snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ | ||
284 | tmp = inl(emu->port+GPIO) & ~0x400; | ||
285 | tmp = tmp | 0x400; | ||
286 | outl(tmp, emu->port+GPIO); | ||
287 | //snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC); | ||
288 | } else { | ||
289 | //snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ | ||
290 | tmp = inl(emu->port+GPIO) & ~0x400; | ||
291 | outl(tmp, emu->port+GPIO); | ||
292 | //snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN); | ||
293 | } | ||
294 | } | 325 | } |
295 | return change; | 326 | return change; |
296 | } | 327 | } |
@@ -359,8 +390,8 @@ static int snd_ca0106_spdif_put(struct snd_kcontrol *kcontrol, | |||
359 | (ucontrol->value.iec958.status[3] << 24); | 390 | (ucontrol->value.iec958.status[3] << 24); |
360 | change = val != emu->spdif_bits[idx]; | 391 | change = val != emu->spdif_bits[idx]; |
361 | if (change) { | 392 | if (change) { |
362 | snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, val); | ||
363 | emu->spdif_bits[idx] = val; | 393 | emu->spdif_bits[idx] = val; |
394 | ca0106_set_spdif_bits(emu, idx); | ||
364 | } | 395 | } |
365 | return change; | 396 | return change; |
366 | } | 397 | } |
@@ -773,3 +804,50 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) | |||
773 | return 0; | 804 | return 0; |
774 | } | 805 | } |
775 | 806 | ||
807 | #ifdef CONFIG_PM | ||
808 | struct ca0106_vol_tbl { | ||
809 | unsigned int channel_id; | ||
810 | unsigned int reg; | ||
811 | }; | ||
812 | |||
813 | static struct ca0106_vol_tbl saved_volumes[NUM_SAVED_VOLUMES] = { | ||
814 | { CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2 }, | ||
815 | { CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME2 }, | ||
816 | { CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME2 }, | ||
817 | { CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME2 }, | ||
818 | { CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME1 }, | ||
819 | { CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME1 }, | ||
820 | { CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME1 }, | ||
821 | { CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME1 }, | ||
822 | { 1, CAPTURE_CONTROL }, | ||
823 | }; | ||
824 | |||
825 | void snd_ca0106_mixer_suspend(struct snd_ca0106 *chip) | ||
826 | { | ||
827 | int i; | ||
828 | |||
829 | /* save volumes */ | ||
830 | for (i = 0; i < NUM_SAVED_VOLUMES; i++) | ||
831 | chip->saved_vol[i] = | ||
832 | snd_ca0106_ptr_read(chip, saved_volumes[i].reg, | ||
833 | saved_volumes[i].channel_id); | ||
834 | } | ||
835 | |||
836 | void snd_ca0106_mixer_resume(struct snd_ca0106 *chip) | ||
837 | { | ||
838 | int i; | ||
839 | |||
840 | for (i = 0; i < NUM_SAVED_VOLUMES; i++) | ||
841 | snd_ca0106_ptr_write(chip, saved_volumes[i].reg, | ||
842 | saved_volumes[i].channel_id, | ||
843 | chip->saved_vol[i]); | ||
844 | |||
845 | ca0106_spdif_enable(chip); | ||
846 | ca0106_set_capture_source(chip); | ||
847 | ca0106_set_i2c_capture_source(chip, chip->i2c_capture_source, 1); | ||
848 | for (i = 0; i < 4; i++) | ||
849 | ca0106_set_spdif_bits(chip, i); | ||
850 | if (chip->details->i2c_adc) | ||
851 | ca0106_set_capture_mic_line_in(chip); | ||
852 | } | ||
853 | #endif /* CONFIG_PM */ | ||