aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/ca0106/ca0106_mixer.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2008-11-24 08:06:08 -0500
committerTakashi Iwai <tiwai@suse.de>2008-12-04 09:25:03 -0500
commit5da95273c2e63c9607652b5e8dd39808b6992d7c (patch)
treef4f7b0c7af29c29524ea93855552d326a0cc58ff /sound/pci/ca0106/ca0106_mixer.c
parent9bf1a2445f3c569098b8de7097ca324e65abecc2 (diff)
ALSA: ca0106 - Add power-management support
Added the missing PM support for snd-ca0106 driver. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/ca0106/ca0106_mixer.c')
-rw-r--r--sound/pci/ca0106/ca0106_mixer.c182
1 files changed, 130 insertions, 52 deletions
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c
index 3025ed1b6e1e..cccc32cdb943 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
78static 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
102static 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
111static 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
131static 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
149static 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 */
78static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1); 156static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1);
79static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1); 157static 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
808struct ca0106_vol_tbl {
809 unsigned int reg;
810 unsigned int channel_id;
811};
812
813static 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
825void 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
836void 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 */