aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/pci/hda/patch_sigmatel.c59
1 files changed, 45 insertions, 14 deletions
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index a51160106df3..4300a679cd86 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -212,7 +212,7 @@ struct sigmatel_spec {
212 /* i/o switches */ 212 /* i/o switches */
213 unsigned int io_switch[2]; 213 unsigned int io_switch[2];
214 unsigned int clfe_swap; 214 unsigned int clfe_swap;
215 unsigned int hp_switch; 215 unsigned int hp_switch; /* NID of HP as line-out */
216 unsigned int aloopback; 216 unsigned int aloopback;
217 217
218 struct hda_pcm pcm_rec[2]; /* PCM information */ 218 struct hda_pcm pcm_rec[2]; /* PCM information */
@@ -2443,7 +2443,7 @@ static int stac92xx_hp_switch_get(struct snd_kcontrol *kcontrol,
2443 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2443 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2444 struct sigmatel_spec *spec = codec->spec; 2444 struct sigmatel_spec *spec = codec->spec;
2445 2445
2446 ucontrol->value.integer.value[0] = spec->hp_switch; 2446 ucontrol->value.integer.value[0] = !!spec->hp_switch;
2447 return 0; 2447 return 0;
2448} 2448}
2449 2449
@@ -2452,8 +2452,9 @@ static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
2452{ 2452{
2453 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2453 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2454 struct sigmatel_spec *spec = codec->spec; 2454 struct sigmatel_spec *spec = codec->spec;
2455 2455 int nid = kcontrol->private_value;
2456 spec->hp_switch = ucontrol->value.integer.value[0]; 2456
2457 spec->hp_switch = ucontrol->value.integer.value[0] ? nid : 0;
2457 2458
2458 /* check to be sure that the ports are upto date with 2459 /* check to be sure that the ports are upto date with
2459 * switch changes 2460 * switch changes
@@ -2862,7 +2863,8 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
2862 if (cfg->hp_outs > 1) { 2863 if (cfg->hp_outs > 1) {
2863 err = stac92xx_add_control(spec, 2864 err = stac92xx_add_control(spec,
2864 STAC_CTL_WIDGET_HP_SWITCH, 2865 STAC_CTL_WIDGET_HP_SWITCH,
2865 "Headphone as Line Out Switch", 0); 2866 "Headphone as Line Out Switch",
2867 cfg->hp_pins[cfg->hp_outs - 1]);
2866 if (err < 0) 2868 if (err < 0)
2867 return err; 2869 return err;
2868 } 2870 }
@@ -3786,11 +3788,30 @@ static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid)
3786 return 0; 3788 return 0;
3787} 3789}
3788 3790
3791/* return non-zero if the hp-pin of the given array index isn't
3792 * a jack-detection target
3793 */
3794static int no_hp_sensing(struct sigmatel_spec *spec, int i)
3795{
3796 struct auto_pin_cfg *cfg = &spec->autocfg;
3797
3798 /* ignore sensing of shared line and mic jacks */
3799 if (spec->line_switch &&
3800 cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_LINE])
3801 return 1;
3802 if (spec->mic_switch &&
3803 cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_MIC])
3804 return 1;
3805 /* ignore if the pin is set as line-out */
3806 if (cfg->hp_pins[i] == spec->hp_switch)
3807 return 1;
3808 return 0;
3809}
3810
3789static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) 3811static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
3790{ 3812{
3791 struct sigmatel_spec *spec = codec->spec; 3813 struct sigmatel_spec *spec = codec->spec;
3792 struct auto_pin_cfg *cfg = &spec->autocfg; 3814 struct auto_pin_cfg *cfg = &spec->autocfg;
3793 int nid = cfg->hp_pins[cfg->hp_outs - 1];
3794 int i, presence; 3815 int i, presence;
3795 3816
3796 presence = 0; 3817 presence = 0;
@@ -3801,15 +3822,16 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
3801 for (i = 0; i < cfg->hp_outs; i++) { 3822 for (i = 0; i < cfg->hp_outs; i++) {
3802 if (presence) 3823 if (presence)
3803 break; 3824 break;
3804 if (spec->hp_switch && cfg->hp_pins[i] == nid) 3825 if (no_hp_sensing(spec, i))
3805 break; 3826 continue;
3806 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]); 3827 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
3807 } 3828 }
3808 3829
3809 if (presence) { 3830 if (presence) {
3810 /* disable lineouts, enable hp */ 3831 /* disable lineouts */
3811 if (spec->hp_switch) 3832 if (spec->hp_switch)
3812 stac92xx_reset_pinctl(codec, nid, AC_PINCTL_OUT_EN); 3833 stac92xx_reset_pinctl(codec, spec->hp_switch,
3834 AC_PINCTL_OUT_EN);
3813 for (i = 0; i < cfg->line_outs; i++) 3835 for (i = 0; i < cfg->line_outs; i++)
3814 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i], 3836 stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
3815 AC_PINCTL_OUT_EN); 3837 AC_PINCTL_OUT_EN);
@@ -3821,9 +3843,10 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
3821 spec->gpio_dir, spec->gpio_data & 3843 spec->gpio_dir, spec->gpio_data &
3822 ~spec->eapd_mask); 3844 ~spec->eapd_mask);
3823 } else { 3845 } else {
3824 /* enable lineouts, disable hp */ 3846 /* enable lineouts */
3825 if (spec->hp_switch) 3847 if (spec->hp_switch)
3826 stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); 3848 stac92xx_set_pinctl(codec, spec->hp_switch,
3849 AC_PINCTL_OUT_EN);
3827 for (i = 0; i < cfg->line_outs; i++) 3850 for (i = 0; i < cfg->line_outs; i++)
3828 stac92xx_set_pinctl(codec, cfg->line_out_pins[i], 3851 stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
3829 AC_PINCTL_OUT_EN); 3852 AC_PINCTL_OUT_EN);
@@ -3835,8 +3858,16 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
3835 spec->gpio_dir, spec->gpio_data | 3858 spec->gpio_dir, spec->gpio_data |
3836 spec->eapd_mask); 3859 spec->eapd_mask);
3837 } 3860 }
3838 if (!spec->hp_switch && cfg->hp_outs > 1 && presence) 3861 /* toggle hp outs */
3839 stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); 3862 for (i = 0; i < cfg->hp_outs; i++) {
3863 unsigned int val = AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN;
3864 if (no_hp_sensing(spec, i))
3865 continue;
3866 if (presence)
3867 stac92xx_set_pinctl(codec, cfg->hp_pins[i], val);
3868 else
3869 stac92xx_reset_pinctl(codec, cfg->hp_pins[i], val);
3870 }
3840} 3871}
3841 3872
3842static void stac92xx_pin_sense(struct hda_codec *codec, int idx) 3873static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
class="hl kwa">return ret; } static int snd_solo_pcm_prepare(struct snd_pcm_substream *ss) { return 0; } static snd_pcm_uframes_t snd_solo_pcm_pointer(struct snd_pcm_substream *ss) { struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss); struct solo6010_dev *solo_dev = solo_pcm->solo_dev; snd_pcm_uframes_t idx = solo_reg_read(solo_dev, SOLO_AUDIO_STA) & 0x1f; return idx * G723_FRAMES_PER_PAGE; } static int snd_solo_pcm_copy(struct snd_pcm_substream *ss, int channel, snd_pcm_uframes_t pos, void __user *dst, snd_pcm_uframes_t count) { struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss); struct solo6010_dev *solo_dev = solo_pcm->solo_dev; int err, i; for (i = 0; i < (count / G723_FRAMES_PER_PAGE); i++) { int page = (pos / G723_FRAMES_PER_PAGE) + i; err = solo_p2m_dma(solo_dev, SOLO_P2M_DMA_ID_G723E, 0, solo_pcm->g723_buf, SOLO_G723_EXT_ADDR(solo_dev) + (page * G723_PERIOD_BLOCK) + (ss->number * G723_PERIOD_BYTES), G723_PERIOD_BYTES); if (err) return err; err = copy_to_user(dst + (i * G723_PERIOD_BYTES), solo_pcm->g723_buf, G723_PERIOD_BYTES); if (err) return -EFAULT; } return 0; } static struct snd_pcm_ops snd_solo_pcm_ops = { .open = snd_solo_pcm_open, .close = snd_solo_pcm_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_solo_hw_params, .hw_free = snd_solo_hw_free, .prepare = snd_solo_pcm_prepare, .trigger = snd_solo_pcm_trigger, .pointer = snd_solo_pcm_pointer, .copy = snd_solo_pcm_copy, }; static int snd_solo_capture_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *info) { info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; info->count = 1; info->value.integer.min = 0; info->value.integer.max = 15; info->value.integer.step = 1; return 0; } static int snd_solo_capture_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value) { struct solo6010_dev *solo_dev = snd_kcontrol_chip(kcontrol); u8 ch = value->id.numid - 1; value->value.integer.value[0] = tw28_get_audio_gain(solo_dev, ch); return 0; } static int snd_solo_capture_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value) { struct solo6010_dev *solo_dev = snd_kcontrol_chip(kcontrol); u8 ch = value->id.numid - 1; u8 old_val; old_val = tw28_get_audio_gain(solo_dev, ch); if (old_val == value->value.integer.value[0]) return 0; tw28_set_audio_gain(solo_dev, ch, value->value.integer.value[0]); return 1; } static struct snd_kcontrol_new snd_solo_capture_volume = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Volume", .info = snd_solo_capture_volume_info, .get = snd_solo_capture_volume_get, .put = snd_solo_capture_volume_put, }; static int solo_snd_pcm_init(struct solo6010_dev *solo_dev) { struct snd_card *card = solo_dev->snd_card; struct snd_pcm *pcm; struct snd_pcm_substream *ss; int ret; int i; ret = snd_pcm_new(card, card->driver, 0, 0, solo_dev->nr_chans, &pcm); if (ret < 0) return ret; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_solo_pcm_ops); snd_pcm_chip(pcm) = solo_dev; pcm->info_flags = 0; strcpy(pcm->name, card->shortname); for (i = 0, ss = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; ss; ss = ss->next, i++) sprintf(ss->name, "Camera #%d Audio", i);