aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/oxygen
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2009-09-28 05:16:41 -0400
committerTakashi Iwai <tiwai@suse.de>2009-09-28 05:54:11 -0400
commit3d8bb454c4fbe18cea1adfd4183a4a9ef5f0ef04 (patch)
tree77cc05fe4547c3945940d20002e41a48acaa0db6 /sound/pci/oxygen
parent75919d7c057be888c7cd7b192fad02182260b04a (diff)
sound: oxygen: add stereo upmixing to center/LFE channels
Add the possibility to route a mix of the two channels of stereo data to the center and LFE outputs. This is implemented only for models where the DACs support this, i.e., for the Xonar D1 and DX. Signed-off-by: Clemens Ladisch <clemens@ladisch.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/oxygen')
-rw-r--r--sound/pci/oxygen/oxygen.h1
-rw-r--r--sound/pci/oxygen/oxygen_mixer.c33
-rw-r--r--sound/pci/oxygen/oxygen_pcm.c6
-rw-r--r--sound/pci/oxygen/xonar_cs43xx.c39
4 files changed, 58 insertions, 21 deletions
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h
index bd615dbffadb..2ac3b3c8253f 100644
--- a/sound/pci/oxygen/oxygen.h
+++ b/sound/pci/oxygen/oxygen.h
@@ -84,6 +84,7 @@ struct oxygen_model {
84 struct snd_pcm_hw_params *params); 84 struct snd_pcm_hw_params *params);
85 void (*update_dac_volume)(struct oxygen *chip); 85 void (*update_dac_volume)(struct oxygen *chip);
86 void (*update_dac_mute)(struct oxygen *chip); 86 void (*update_dac_mute)(struct oxygen *chip);
87 void (*update_center_lfe_mix)(struct oxygen *chip, bool mixed);
87 void (*gpio_changed)(struct oxygen *chip); 88 void (*gpio_changed)(struct oxygen *chip);
88 void (*uart_input)(struct oxygen *chip); 89 void (*uart_input)(struct oxygen *chip);
89 void (*ac97_switch)(struct oxygen *chip, 90 void (*ac97_switch)(struct oxygen *chip,
diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c
index e8e911a86c8e..5dfb5fb73381 100644
--- a/sound/pci/oxygen/oxygen_mixer.c
+++ b/sound/pci/oxygen/oxygen_mixer.c
@@ -99,11 +99,15 @@ static int dac_mute_put(struct snd_kcontrol *ctl,
99 99
100static int upmix_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) 100static int upmix_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
101{ 101{
102 static const char *const names[3] = { 102 static const char *const names[5] = {
103 "Front", "Front+Surround", "Front+Surround+Back" 103 "Front",
104 "Front+Surround",
105 "Front+Surround+Back",
106 "Front+Surround+Center/LFE",
107 "Front+Surround+Center/LFE+Back",
104 }; 108 };
105 struct oxygen *chip = ctl->private_data; 109 struct oxygen *chip = ctl->private_data;
106 unsigned int count = 2 + (chip->model.dac_channels == 8); 110 unsigned int count = chip->model.update_center_lfe_mix ? 5 : 3;
107 111
108 info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 112 info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
109 info->count = 1; 113 info->count = 1;
@@ -127,7 +131,7 @@ static int upmix_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
127void oxygen_update_dac_routing(struct oxygen *chip) 131void oxygen_update_dac_routing(struct oxygen *chip)
128{ 132{
129 /* DAC 0: front, DAC 1: surround, DAC 2: center/LFE, DAC 3: back */ 133 /* DAC 0: front, DAC 1: surround, DAC 2: center/LFE, DAC 3: back */
130 static const unsigned int reg_values[3] = { 134 static const unsigned int reg_values[5] = {
131 /* stereo -> front */ 135 /* stereo -> front */
132 (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | 136 (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
133 (1 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | 137 (1 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
@@ -143,6 +147,16 @@ void oxygen_update_dac_routing(struct oxygen *chip)
143 (0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | 147 (0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
144 (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | 148 (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
145 (0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT), 149 (0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT),
150 /* stereo -> front+surround+center/LFE */
151 (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
152 (0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
153 (0 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
154 (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT),
155 /* stereo -> front+surround+center/LFE+back */
156 (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
157 (0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
158 (0 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
159 (0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT),
146 }; 160 };
147 u8 channels; 161 u8 channels;
148 unsigned int reg_value; 162 unsigned int reg_value;
@@ -167,22 +181,23 @@ void oxygen_update_dac_routing(struct oxygen *chip)
167 OXYGEN_PLAY_DAC1_SOURCE_MASK | 181 OXYGEN_PLAY_DAC1_SOURCE_MASK |
168 OXYGEN_PLAY_DAC2_SOURCE_MASK | 182 OXYGEN_PLAY_DAC2_SOURCE_MASK |
169 OXYGEN_PLAY_DAC3_SOURCE_MASK); 183 OXYGEN_PLAY_DAC3_SOURCE_MASK);
184 if (chip->model.update_center_lfe_mix)
185 chip->model.update_center_lfe_mix(chip, chip->dac_routing > 2);
170} 186}
171 187
172static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) 188static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
173{ 189{
174 struct oxygen *chip = ctl->private_data; 190 struct oxygen *chip = ctl->private_data;
175 unsigned int count = 2 + (chip->model.dac_channels == 8); 191 unsigned int count = chip->model.update_center_lfe_mix ? 5 : 3;
176 int changed; 192 int changed;
177 193
194 if (value->value.enumerated.item[0] >= count)
195 return -EINVAL;
178 mutex_lock(&chip->mutex); 196 mutex_lock(&chip->mutex);
179 changed = value->value.enumerated.item[0] != chip->dac_routing; 197 changed = value->value.enumerated.item[0] != chip->dac_routing;
180 if (changed) { 198 if (changed) {
181 chip->dac_routing = min(value->value.enumerated.item[0], 199 chip->dac_routing = value->value.enumerated.item[0];
182 count - 1);
183 spin_lock_irq(&chip->reg_lock);
184 oxygen_update_dac_routing(chip); 200 oxygen_update_dac_routing(chip);
185 spin_unlock_irq(&chip->reg_lock);
186 } 201 }
187 mutex_unlock(&chip->mutex); 202 mutex_unlock(&chip->mutex);
188 return changed; 203 return changed;
diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c
index ef2345d82b86..1e98333366df 100644
--- a/sound/pci/oxygen/oxygen_pcm.c
+++ b/sound/pci/oxygen/oxygen_pcm.c
@@ -435,6 +435,7 @@ static int oxygen_spdif_hw_params(struct snd_pcm_substream *substream,
435 if (err < 0) 435 if (err < 0)
436 return err; 436 return err;
437 437
438 mutex_lock(&chip->mutex);
438 spin_lock_irq(&chip->reg_lock); 439 spin_lock_irq(&chip->reg_lock);
439 oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL, 440 oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL,
440 OXYGEN_SPDIF_OUT_ENABLE); 441 OXYGEN_SPDIF_OUT_ENABLE);
@@ -446,6 +447,7 @@ static int oxygen_spdif_hw_params(struct snd_pcm_substream *substream,
446 OXYGEN_SPDIF_OUT_RATE_MASK); 447 OXYGEN_SPDIF_OUT_RATE_MASK);
447 oxygen_update_spdif_source(chip); 448 oxygen_update_spdif_source(chip);
448 spin_unlock_irq(&chip->reg_lock); 449 spin_unlock_irq(&chip->reg_lock);
450 mutex_unlock(&chip->mutex);
449 return 0; 451 return 0;
450} 452}
451 453
@@ -459,6 +461,7 @@ static int oxygen_multich_hw_params(struct snd_pcm_substream *substream,
459 if (err < 0) 461 if (err < 0)
460 return err; 462 return err;
461 463
464 mutex_lock(&chip->mutex);
462 spin_lock_irq(&chip->reg_lock); 465 spin_lock_irq(&chip->reg_lock);
463 oxygen_write8_masked(chip, OXYGEN_PLAY_CHANNELS, 466 oxygen_write8_masked(chip, OXYGEN_PLAY_CHANNELS,
464 oxygen_play_channels(hw_params), 467 oxygen_play_channels(hw_params),
@@ -475,12 +478,11 @@ static int oxygen_multich_hw_params(struct snd_pcm_substream *substream,
475 OXYGEN_I2S_FORMAT_MASK | 478 OXYGEN_I2S_FORMAT_MASK |
476 OXYGEN_I2S_MCLK_MASK | 479 OXYGEN_I2S_MCLK_MASK |
477 OXYGEN_I2S_BITS_MASK); 480 OXYGEN_I2S_BITS_MASK);
478 oxygen_update_dac_routing(chip);
479 oxygen_update_spdif_source(chip); 481 oxygen_update_spdif_source(chip);
480 spin_unlock_irq(&chip->reg_lock); 482 spin_unlock_irq(&chip->reg_lock);
481 483
482 mutex_lock(&chip->mutex);
483 chip->model.set_dac_params(chip, hw_params); 484 chip->model.set_dac_params(chip, hw_params);
485 oxygen_update_dac_routing(chip);
484 mutex_unlock(&chip->mutex); 486 mutex_unlock(&chip->mutex);
485 return 0; 487 return 0;
486} 488}
diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c
index 8fb5797577dd..0fa05ed6681d 100644
--- a/sound/pci/oxygen/xonar_cs43xx.c
+++ b/sound/pci/oxygen/xonar_cs43xx.c
@@ -67,6 +67,7 @@ struct xonar_cs43xx {
67 struct xonar_generic generic; 67 struct xonar_generic generic;
68 u8 cs4398_fm; 68 u8 cs4398_fm;
69 u8 cs4362a_fm; 69 u8 cs4362a_fm;
70 u8 cs4362a_fm_c;
70}; 71};
71 72
72static void cs4398_write(struct oxygen *chip, u8 reg, u8 value) 73static void cs4398_write(struct oxygen *chip, u8 reg, u8 value)
@@ -128,7 +129,7 @@ static void cs43xx_init(struct oxygen *chip)
128 cs4362a_write(chip, 0x04, CS4362A_RMP_DN | CS4362A_DEM_NONE); 129 cs4362a_write(chip, 0x04, CS4362A_RMP_DN | CS4362A_DEM_NONE);
129 cs4362a_write(chip, 0x05, 0); 130 cs4362a_write(chip, 0x05, 0);
130 cs4362a_write(chip, 0x06, data->cs4362a_fm); 131 cs4362a_write(chip, 0x06, data->cs4362a_fm);
131 cs4362a_write(chip, 0x09, data->cs4362a_fm); 132 cs4362a_write(chip, 0x09, data->cs4362a_fm_c);
132 cs4362a_write(chip, 0x0c, data->cs4362a_fm); 133 cs4362a_write(chip, 0x0c, data->cs4362a_fm);
133 update_cs43xx_volume(chip); 134 update_cs43xx_volume(chip);
134 update_cs43xx_mute(chip); 135 update_cs43xx_mute(chip);
@@ -146,6 +147,7 @@ static void xonar_d1_init(struct oxygen *chip)
146 data->cs4398_fm = CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST; 147 data->cs4398_fm = CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST;
147 data->cs4362a_fm = CS4362A_FM_SINGLE | 148 data->cs4362a_fm = CS4362A_FM_SINGLE |
148 CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; 149 CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L;
150 data->cs4362a_fm_c = data->cs4362a_fm;
149 151
150 oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, 152 oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
151 OXYGEN_2WIRE_LENGTH_8 | 153 OXYGEN_2WIRE_LENGTH_8 |
@@ -202,25 +204,41 @@ static void set_cs43xx_params(struct oxygen *chip,
202 struct snd_pcm_hw_params *params) 204 struct snd_pcm_hw_params *params)
203{ 205{
204 struct xonar_cs43xx *data = chip->model_data; 206 struct xonar_cs43xx *data = chip->model_data;
207 u8 cs4398_fm, cs4362a_fm;
205 208
206 data->cs4398_fm = CS4398_DEM_NONE | CS4398_DIF_LJUST;
207 data->cs4362a_fm = CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L;
208 if (params_rate(params) <= 50000) { 209 if (params_rate(params) <= 50000) {
209 data->cs4398_fm |= CS4398_FM_SINGLE; 210 cs4398_fm = CS4398_FM_SINGLE;
210 data->cs4362a_fm |= CS4362A_FM_SINGLE; 211 cs4362a_fm = CS4362A_FM_SINGLE;
211 } else if (params_rate(params) <= 100000) { 212 } else if (params_rate(params) <= 100000) {
212 data->cs4398_fm |= CS4398_FM_DOUBLE; 213 cs4398_fm = CS4398_FM_DOUBLE;
213 data->cs4362a_fm |= CS4362A_FM_DOUBLE; 214 cs4362a_fm = CS4362A_FM_DOUBLE;
214 } else { 215 } else {
215 data->cs4398_fm |= CS4398_FM_QUAD; 216 cs4398_fm = CS4398_FM_QUAD;
216 data->cs4362a_fm |= CS4362A_FM_QUAD; 217 cs4362a_fm = CS4362A_FM_QUAD;
217 } 218 }
219 data->cs4398_fm = CS4398_DEM_NONE | CS4398_DIF_LJUST | cs4398_fm;
220 data->cs4362a_fm =
221 (data->cs4362a_fm & ~CS4362A_FM_MASK) | cs4362a_fm;
222 data->cs4362a_fm_c =
223 (data->cs4362a_fm_c & ~CS4362A_FM_MASK) | cs4362a_fm;
218 cs4398_write(chip, 2, data->cs4398_fm); 224 cs4398_write(chip, 2, data->cs4398_fm);
219 cs4362a_write(chip, 0x06, data->cs4362a_fm); 225 cs4362a_write(chip, 0x06, data->cs4362a_fm);
220 cs4362a_write(chip, 0x09, data->cs4362a_fm); 226 cs4362a_write(chip, 0x09, data->cs4362a_fm_c);
221 cs4362a_write(chip, 0x0c, data->cs4362a_fm); 227 cs4362a_write(chip, 0x0c, data->cs4362a_fm);
222} 228}
223 229
230static void update_cs43xx_center_lfe_mix(struct oxygen *chip, bool mixed)
231{
232 struct xonar_cs43xx *data = chip->model_data;
233
234 data->cs4362a_fm_c &= ~CS4362A_ATAPI_MASK;
235 if (mixed)
236 data->cs4362a_fm_c |= CS4362A_ATAPI_B_LR | CS4362A_ATAPI_A_LR;
237 else
238 data->cs4362a_fm_c |= CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L;
239 cs4362a_write(chip, 0x09, data->cs4362a_fm_c);
240}
241
224static const struct snd_kcontrol_new front_panel_switch = { 242static const struct snd_kcontrol_new front_panel_switch = {
225 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 243 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
226 .name = "Front Panel Switch", 244 .name = "Front Panel Switch",
@@ -269,6 +287,7 @@ static const struct oxygen_model model_xonar_d1 = {
269 .set_adc_params = xonar_set_cs53x1_params, 287 .set_adc_params = xonar_set_cs53x1_params,
270 .update_dac_volume = update_cs43xx_volume, 288 .update_dac_volume = update_cs43xx_volume,
271 .update_dac_mute = update_cs43xx_mute, 289 .update_dac_mute = update_cs43xx_mute,
290 .update_center_lfe_mix = update_cs43xx_center_lfe_mix,
272 .ac97_switch = xonar_d1_line_mic_ac97_switch, 291 .ac97_switch = xonar_d1_line_mic_ac97_switch,
273 .dac_tlv = cs4362a_db_scale, 292 .dac_tlv = cs4362a_db_scale,
274 .model_data_size = sizeof(struct xonar_cs43xx), 293 .model_data_size = sizeof(struct xonar_cs43xx),