aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_via.c
diff options
context:
space:
mode:
authorLydia Wang <lydiawang@viatech.com.cn>2009-10-10 07:08:17 -0400
committerTakashi Iwai <tiwai@suse.de>2009-10-11 11:57:25 -0400
commit1f2e99febd5dd0c91f0d0752674029a4376649e5 (patch)
tree3ea14111718b1779c62ef80587b89c331a35d283 /sound/pci/hda/patch_via.c
parentdcf34c8cc685781cebbe1f4c75272a3269eba3a1 (diff)
ALSA: HDA VIA: Add Jack detect feature for VT1708.
VT1708 does not support unsolicited response, but we need hp detect to automute speaker. Implemented in workqueue. Signed-off-by: Lydia Wang <lydiawang@viatech.com.cn> Signed-off-by: Logan Li <loganli@viatech.com.cn> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/patch_via.c')
-rw-r--r--sound/pci/hda/patch_via.c230
1 files changed, 173 insertions, 57 deletions
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index c1f4307feaae..38418a53acd7 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -89,6 +89,64 @@ enum VIA_HDA_CODEC {
89 CODEC_TYPES, 89 CODEC_TYPES,
90}; 90};
91 91
92struct via_spec {
93 /* codec parameterization */
94 struct snd_kcontrol_new *mixers[4];
95 unsigned int num_mixers;
96
97 struct hda_verb *init_verbs[5];
98 unsigned int num_iverbs;
99
100 char *stream_name_analog;
101 struct hda_pcm_stream *stream_analog_playback;
102 struct hda_pcm_stream *stream_analog_capture;
103
104 char *stream_name_digital;
105 struct hda_pcm_stream *stream_digital_playback;
106 struct hda_pcm_stream *stream_digital_capture;
107
108 /* playback */
109 struct hda_multi_out multiout;
110 hda_nid_t slave_dig_outs[2];
111
112 /* capture */
113 unsigned int num_adc_nids;
114 hda_nid_t *adc_nids;
115 hda_nid_t mux_nids[3];
116 hda_nid_t dig_in_nid;
117 hda_nid_t dig_in_pin;
118
119 /* capture source */
120 const struct hda_input_mux *input_mux;
121 unsigned int cur_mux[3];
122
123 /* PCM information */
124 struct hda_pcm pcm_rec[3];
125
126 /* dynamic controls, init_verbs and input_mux */
127 struct auto_pin_cfg autocfg;
128 struct snd_array kctls;
129 struct hda_input_mux private_imux[2];
130 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
131
132 /* HP mode source */
133 const struct hda_input_mux *hp_mux;
134 unsigned int hp_independent_mode;
135 unsigned int hp_independent_mode_index;
136 unsigned int smart51_enabled;
137
138 enum VIA_HDA_CODEC codec_type;
139
140 /* work to check hp jack state */
141 struct hda_codec *codec;
142 struct delayed_work vt1708_hp_work;
143 int vt1708_jack_detectect;
144 int vt1708_hp_present;
145#ifdef CONFIG_SND_HDA_POWER_SAVE
146 struct hda_loopback_check loopback;
147#endif
148};
149
92static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) 150static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec)
93{ 151{
94 u32 vendor_id = codec->vendor_id; 152 u32 vendor_id = codec->vendor_id;
@@ -181,6 +239,31 @@ static int mic_boost_volume_info(struct snd_kcontrol *kcontrol,
181 239
182static void analog_low_current_mode(struct hda_codec *codec, int stream_idle); 240static void analog_low_current_mode(struct hda_codec *codec, int stream_idle);
183static void set_jack_power_state(struct hda_codec *codec); 241static void set_jack_power_state(struct hda_codec *codec);
242static int is_aa_path_mute(struct hda_codec *codec);
243
244static void vt1708_start_hp_work(struct via_spec *spec)
245{
246 if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0)
247 return;
248 snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81,
249 !spec->vt1708_jack_detectect);
250 if (!delayed_work_pending(&spec->vt1708_hp_work))
251 schedule_delayed_work(&spec->vt1708_hp_work,
252 msecs_to_jiffies(100));
253}
254
255static void vt1708_stop_hp_work(struct via_spec *spec)
256{
257 if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0)
258 return;
259 if (snd_hda_get_bool_hint(spec->codec, "analog_loopback_hp_detect") == 1
260 && !is_aa_path_mute(spec->codec))
261 return;
262 snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81,
263 !spec->vt1708_jack_detectect);
264 cancel_delayed_work(&spec->vt1708_hp_work);
265 flush_scheduled_work();
266}
184 267
185static int analog_input_switch_put(struct snd_kcontrol *kcontrol, 268static int analog_input_switch_put(struct snd_kcontrol *kcontrol,
186 struct snd_ctl_elem_value *ucontrol) 269 struct snd_ctl_elem_value *ucontrol)
@@ -190,6 +273,12 @@ static int analog_input_switch_put(struct snd_kcontrol *kcontrol,
190 273
191 set_jack_power_state(codec); 274 set_jack_power_state(codec);
192 analog_low_current_mode(snd_kcontrol_chip(kcontrol), -1); 275 analog_low_current_mode(snd_kcontrol_chip(kcontrol), -1);
276 if (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1) {
277 if (is_aa_path_mute(codec))
278 vt1708_start_hp_work(codec->spec);
279 else
280 vt1708_stop_hp_work(codec->spec);
281 }
193 return change; 282 return change;
194} 283}
195 284
@@ -210,59 +299,6 @@ static struct snd_kcontrol_new vt1708_control_templates[] = {
210}; 299};
211 300
212 301
213struct via_spec {
214 /* codec parameterization */
215 struct snd_kcontrol_new *mixers[4];
216 unsigned int num_mixers;
217
218 struct hda_verb *init_verbs[5];
219 unsigned int num_iverbs;
220
221 char *stream_name_analog;
222 struct hda_pcm_stream *stream_analog_playback;
223 struct hda_pcm_stream *stream_analog_capture;
224
225 char *stream_name_digital;
226 struct hda_pcm_stream *stream_digital_playback;
227 struct hda_pcm_stream *stream_digital_capture;
228
229 /* playback */
230 struct hda_multi_out multiout;
231 hda_nid_t slave_dig_outs[2];
232
233 /* capture */
234 unsigned int num_adc_nids;
235 hda_nid_t *adc_nids;
236 hda_nid_t mux_nids[3];
237 hda_nid_t dig_in_nid;
238 hda_nid_t dig_in_pin;
239
240 /* capture source */
241 const struct hda_input_mux *input_mux;
242 unsigned int cur_mux[3];
243
244 /* PCM information */
245 struct hda_pcm pcm_rec[3];
246
247 /* dynamic controls, init_verbs and input_mux */
248 struct auto_pin_cfg autocfg;
249 struct snd_array kctls;
250 struct hda_input_mux private_imux[2];
251 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
252
253 /* HP mode source */
254 const struct hda_input_mux *hp_mux;
255 unsigned int hp_independent_mode;
256 unsigned int hp_independent_mode_index;
257 unsigned int smart51_enabled;
258
259 enum VIA_HDA_CODEC codec_type;
260
261#ifdef CONFIG_SND_HDA_POWER_SAVE
262 struct hda_loopback_check loopback;
263#endif
264};
265
266static hda_nid_t vt1708_adc_nids[2] = { 302static hda_nid_t vt1708_adc_nids[2] = {
267 /* ADC1-2 */ 303 /* ADC1-2 */
268 0x15, 0x27 304 0x15, 0x27
@@ -981,7 +1017,6 @@ static int via_playback_pcm_open(struct hda_pcm_stream *hinfo,
981 struct via_spec *spec = codec->spec; 1017 struct via_spec *spec = codec->spec;
982 int idle = substream->pstr->substream_opened == 1 1018 int idle = substream->pstr->substream_opened == 1
983 && substream->ref_count == 0; 1019 && substream->ref_count == 0;
984
985 analog_low_current_mode(codec, idle); 1020 analog_low_current_mode(codec, idle);
986 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, 1021 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
987 hinfo); 1022 hinfo);
@@ -994,6 +1029,7 @@ static int via_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
994 struct snd_pcm_substream *substream) 1029 struct snd_pcm_substream *substream)
995{ 1030{
996 struct via_spec *spec = codec->spec; 1031 struct via_spec *spec = codec->spec;
1032 vt1708_start_hp_work(spec);
997 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, 1033 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
998 stream_tag, format, substream); 1034 stream_tag, format, substream);
999} 1035}
@@ -1003,6 +1039,7 @@ static int via_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
1003 struct snd_pcm_substream *substream) 1039 struct snd_pcm_substream *substream)
1004{ 1040{
1005 struct via_spec *spec = codec->spec; 1041 struct via_spec *spec = codec->spec;
1042 vt1708_stop_hp_work(spec);
1006 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); 1043 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
1007} 1044}
1008 1045
@@ -1094,7 +1131,7 @@ static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo,
1094 snd_hda_codec_setup_stream(codec, mout->hp_nid, 1131 snd_hda_codec_setup_stream(codec, mout->hp_nid,
1095 stream_tag, 0, format); 1132 stream_tag, 0, format);
1096 } 1133 }
1097 1134 vt1708_start_hp_work(spec);
1098 return 0; 1135 return 0;
1099} 1136}
1100 1137
@@ -1134,7 +1171,7 @@ static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo,
1134 snd_hda_codec_setup_stream(codec, mout->hp_nid, 1171 snd_hda_codec_setup_stream(codec, mout->hp_nid,
1135 0, 0, 0); 1172 0, 0, 0);
1136 } 1173 }
1137 1174 vt1708_stop_hp_work(spec);
1138 return 0; 1175 return 0;
1139} 1176}
1140 1177
@@ -1345,6 +1382,7 @@ static void via_free(struct hda_codec *codec)
1345 return; 1382 return;
1346 1383
1347 via_free_kctls(codec); 1384 via_free_kctls(codec);
1385 vt1708_stop_hp_work(spec);
1348 kfree(codec->spec); 1386 kfree(codec->spec);
1349} 1387}
1350 1388
@@ -1464,6 +1502,15 @@ static int via_init(struct hda_codec *codec)
1464 return 0; 1502 return 0;
1465} 1503}
1466 1504
1505#ifdef SND_HDA_NEEDS_RESUME
1506static int via_suspend(struct hda_codec *codec, pm_message_t state)
1507{
1508 struct via_spec *spec = codec->spec;
1509 vt1708_stop_hp_work(spec);
1510 return 0;
1511}
1512#endif
1513
1467#ifdef CONFIG_SND_HDA_POWER_SAVE 1514#ifdef CONFIG_SND_HDA_POWER_SAVE
1468static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid) 1515static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
1469{ 1516{
@@ -1479,6 +1526,9 @@ static struct hda_codec_ops via_patch_ops = {
1479 .build_pcms = via_build_pcms, 1526 .build_pcms = via_build_pcms,
1480 .init = via_init, 1527 .init = via_init,
1481 .free = via_free, 1528 .free = via_free,
1529#ifdef SND_HDA_NEEDS_RESUME
1530 .suspend = via_suspend,
1531#endif
1482#ifdef CONFIG_SND_HDA_POWER_SAVE 1532#ifdef CONFIG_SND_HDA_POWER_SAVE
1483 .check_power_status = via_check_power_status, 1533 .check_power_status = via_check_power_status,
1484#endif 1534#endif
@@ -1728,6 +1778,51 @@ static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid)
1728 return; 1778 return;
1729} 1779}
1730 1780
1781static int vt1708_jack_detectect_get(struct snd_kcontrol *kcontrol,
1782 struct snd_ctl_elem_value *ucontrol)
1783{
1784 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1785 struct via_spec *spec = codec->spec;
1786
1787 if (spec->codec_type != VT1708)
1788 return 0;
1789 spec->vt1708_jack_detectect =
1790 !((snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8) & 0x1);
1791 ucontrol->value.integer.value[0] = spec->vt1708_jack_detectect;
1792 return 0;
1793}
1794
1795static int vt1708_jack_detectect_put(struct snd_kcontrol *kcontrol,
1796 struct snd_ctl_elem_value *ucontrol)
1797{
1798 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1799 struct via_spec *spec = codec->spec;
1800 int change;
1801
1802 if (spec->codec_type != VT1708)
1803 return 0;
1804 spec->vt1708_jack_detectect = ucontrol->value.integer.value[0];
1805 change = (0x1 & (snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8))
1806 == !spec->vt1708_jack_detectect;
1807 if (spec->vt1708_jack_detectect) {
1808 mute_aa_path(codec, 1);
1809 notify_aa_path_ctls(codec);
1810 }
1811 return change;
1812}
1813
1814static struct snd_kcontrol_new vt1708_jack_detectect[] = {
1815 {
1816 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1817 .name = "Jack Detect",
1818 .count = 1,
1819 .info = snd_ctl_boolean_mono_info,
1820 .get = vt1708_jack_detectect_get,
1821 .put = vt1708_jack_detectect_put,
1822 },
1823 {} /* end */
1824};
1825
1731static int vt1708_parse_auto_config(struct hda_codec *codec) 1826static int vt1708_parse_auto_config(struct hda_codec *codec)
1732{ 1827{
1733 struct via_spec *spec = codec->spec; 1828 struct via_spec *spec = codec->spec;
@@ -1755,6 +1850,10 @@ static int vt1708_parse_auto_config(struct hda_codec *codec)
1755 err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg); 1850 err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg);
1756 if (err < 0) 1851 if (err < 0)
1757 return err; 1852 return err;
1853 /* add jack detect on/off control */
1854 err = snd_hda_add_new_ctls(codec, vt1708_jack_detectect);
1855 if (err < 0)
1856 return err;
1758 1857
1759 spec->multiout.max_channels = spec->multiout.num_dacs * 2; 1858 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
1760 1859
@@ -1788,6 +1887,22 @@ static int via_auto_init(struct hda_codec *codec)
1788 return 0; 1887 return 0;
1789} 1888}
1790 1889
1890static void vt1708_update_hp_jack_state(struct work_struct *work)
1891{
1892 struct via_spec *spec = container_of(work, struct via_spec,
1893 vt1708_hp_work.work);
1894 if (spec->codec_type != VT1708)
1895 return;
1896 /* if jack state toggled */
1897 if (spec->vt1708_hp_present
1898 != (snd_hda_codec_read(spec->codec, spec->autocfg.hp_pins[0], 0,
1899 AC_VERB_GET_PIN_SENSE, 0) >> 31)) {
1900 spec->vt1708_hp_present ^= 1;
1901 via_hp_automute(spec->codec);
1902 }
1903 vt1708_start_hp_work(spec);
1904}
1905
1791static int get_mux_nids(struct hda_codec *codec) 1906static int get_mux_nids(struct hda_codec *codec)
1792{ 1907{
1793 struct via_spec *spec = codec->spec; 1908 struct via_spec *spec = codec->spec;
@@ -1864,7 +1979,8 @@ static int patch_vt1708(struct hda_codec *codec)
1864#ifdef CONFIG_SND_HDA_POWER_SAVE 1979#ifdef CONFIG_SND_HDA_POWER_SAVE
1865 spec->loopback.amplist = vt1708_loopbacks; 1980 spec->loopback.amplist = vt1708_loopbacks;
1866#endif 1981#endif
1867 1982 spec->codec = codec;
1983 INIT_DELAYED_WORK(&spec->vt1708_hp_work, vt1708_update_hp_jack_state);
1868 return 0; 1984 return 0;
1869} 1985}
1870 1986