summaryrefslogtreecommitdiffstats
path: root/sound/pci/ac97
diff options
context:
space:
mode:
authorJeff Garzik <jgarzik@pretzel.yyz.us>2005-06-27 05:38:58 +0200
committerJeff Garzik <jgarzik@pobox.com>2005-06-27 05:38:58 +0200
commit5696c1944a33b4434a9a1ebb6383b906afd43a10 (patch)
tree16fbe6ba431bcf949ee8645510b0c2fd39b5810f /sound/pci/ac97
parent[wireless] ipw2100: fix build after applying SuSE cleanups (diff)
parentMerge rsync://rsync.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6 (diff)
downloadlinux-5696c1944a33b4434a9a1ebb6383b906afd43a10.tar.xz
linux-5696c1944a33b4434a9a1ebb6383b906afd43a10.zip
Merge /spare/repo/linux-2.6/
Diffstat (limited to 'sound/pci/ac97')
-rw-r--r--sound/pci/ac97/ac97_codec.c71
-rw-r--r--sound/pci/ac97/ac97_patch.c585
-rw-r--r--sound/pci/ac97/ac97_patch.h1
3 files changed, 429 insertions, 228 deletions
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index 0b024ec1f709..a4b72cd2eea0 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -120,6 +120,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = {
{ 0x414c4770, 0xfffffff0, "ALC203", NULL, NULL },
{ 0x434d4941, 0xffffffff, "CMI9738", patch_cm9738, NULL },
{ 0x434d4961, 0xffffffff, "CMI9739", patch_cm9739, NULL },
+{ 0x434d4969, 0xffffffff, "CMI9780", patch_cm9780, NULL },
{ 0x434d4978, 0xffffffff, "CMI9761", patch_cm9761, NULL },
{ 0x434d4982, 0xffffffff, "CMI9761", patch_cm9761, NULL },
{ 0x434d4983, 0xffffffff, "CMI9761", patch_cm9761, NULL },
@@ -149,7 +150,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = {
{ 0x4e534331, 0xffffffff, "LM4549", NULL, NULL },
{ 0x4e534350, 0xffffffff, "LM4550", NULL, NULL },
{ 0x50534304, 0xffffffff, "UCB1400", NULL, NULL },
-{ 0x53494c20, 0xffffffe0, "Si3036,8", NULL, mpatch_si3036 },
+{ 0x53494c20, 0xffffffe0, "Si3036,8", mpatch_si3036, mpatch_si3036, AC97_MODEM_PATCH },
{ 0x54524102, 0xffffffff, "TR28022", NULL, NULL },
{ 0x54524106, 0xffffffff, "TR28026", NULL, NULL },
{ 0x54524108, 0xffffffff, "TR28028", patch_tritech_tr28028, NULL }, // added by xin jin [07/09/99]
@@ -462,12 +463,14 @@ int snd_ac97_get_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * u
{
ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value;
- unsigned short val;
+ unsigned short val, bitmask;
+ for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
+ ;
val = snd_ac97_read_cache(ac97, e->reg);
- ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (e->mask - 1);
+ ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1);
if (e->shift_l != e->shift_r)
- ucontrol->value.enumerated.item[1] = (val >> e->shift_r) & (e->mask - 1);
+ ucontrol->value.enumerated.item[1] = (val >> e->shift_r) & (bitmask - 1);
return 0;
}
@@ -477,17 +480,19 @@ int snd_ac97_put_enum_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * u
ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value;
unsigned short val;
- unsigned short mask;
+ unsigned short mask, bitmask;
+ for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
+ ;
if (ucontrol->value.enumerated.item[0] > e->mask - 1)
return -EINVAL;
val = ucontrol->value.enumerated.item[0] << e->shift_l;
- mask = (e->mask - 1) << e->shift_l;
+ mask = (bitmask - 1) << e->shift_l;
if (e->shift_l != e->shift_r) {
if (ucontrol->value.enumerated.item[1] > e->mask - 1)
return -EINVAL;
val |= ucontrol->value.enumerated.item[1] << e->shift_r;
- mask |= (e->mask - 1) << e->shift_r;
+ mask |= (bitmask - 1) << e->shift_r;
}
return snd_ac97_update_bits(ac97, e->reg, mask, val);
}
@@ -658,14 +663,14 @@ AC97_SINGLE("LFE Playback Switch", AC97_CENTER_LFE_MASTER, 15, 1, 1),
AC97_SINGLE("LFE Playback Volume", AC97_CENTER_LFE_MASTER, 8, 31, 1)
};
-static const snd_kcontrol_new_t snd_ac97_controls_surround[2] = {
-AC97_DOUBLE("Surround Playback Switch", AC97_SURROUND_MASTER, 15, 7, 1, 1),
-AC97_DOUBLE("Surround Playback Volume", AC97_SURROUND_MASTER, 8, 0, 31, 1),
-};
-
static const snd_kcontrol_new_t snd_ac97_control_eapd =
AC97_SINGLE("External Amplifier", AC97_POWERDOWN, 15, 1, 1);
+static const snd_kcontrol_new_t snd_ac97_controls_modem_switches[2] = {
+AC97_SINGLE("Off-hook Switch", AC97_GPIO_STATUS, 0, 1, 0),
+AC97_SINGLE("Caller ID Switch", AC97_GPIO_STATUS, 2, 1, 0)
+};
+
/* change the existing EAPD control as inverted */
static void set_inv_eapd(ac97_t *ac97, snd_kcontrol_t *kctl)
{
@@ -1072,9 +1077,9 @@ static void check_volume_resolution(ac97_t *ac97, int reg, unsigned char *lo_max
unsigned short val;
snd_ac97_write(ac97, reg, 0x8080 | cbit[i] | (cbit[i] << 8));
val = snd_ac97_read(ac97, reg);
- if (! *lo_max && (val & cbit[i]))
+ if (! *lo_max && (val & 0x7f) == cbit[i])
*lo_max = max[i];
- if (! *hi_max && (val & (cbit[i] << 8)))
+ if (! *hi_max && ((val >> 8) & 0x7f) == cbit[i])
*hi_max = max[i];
if (*lo_max && *hi_max)
break;
@@ -1526,13 +1531,25 @@ static int snd_ac97_mixer_build(ac97_t * ac97)
static int snd_ac97_modem_build(snd_card_t * card, ac97_t * ac97)
{
- /* TODO */
+ int err, idx;
+
//printk("AC97_GPIO_CFG = %x\n",snd_ac97_read(ac97,AC97_GPIO_CFG));
snd_ac97_write(ac97, AC97_GPIO_CFG, 0xffff & ~(AC97_GPIO_LINE1_OH));
snd_ac97_write(ac97, AC97_GPIO_POLARITY, 0xffff & ~(AC97_GPIO_LINE1_OH));
snd_ac97_write(ac97, AC97_GPIO_STICKY, 0xffff);
snd_ac97_write(ac97, AC97_GPIO_WAKEUP, 0x0);
snd_ac97_write(ac97, AC97_MISC_AFE, 0x0);
+
+ /* build modem switches */
+ for (idx = 0; idx < ARRAY_SIZE(snd_ac97_controls_modem_switches); idx++)
+ if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_modem_switches[idx], ac97))) < 0)
+ return err;
+
+ /* build chip specific controls */
+ if (ac97->build_ops->build_specific)
+ if ((err = ac97->build_ops->build_specific(ac97)) < 0)
+ return err;
+
return 0;
}
@@ -1872,7 +1889,11 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97)
goto __access_ok;
}
- snd_ac97_write(ac97, AC97_RESET, 0); /* reset to defaults */
+ /* reset to defaults */
+ if (!(ac97->scaps & AC97_SCAP_SKIP_AUDIO))
+ snd_ac97_write(ac97, AC97_RESET, 0);
+ if (!(ac97->scaps & AC97_SCAP_SKIP_MODEM))
+ snd_ac97_write(ac97, AC97_EXTENDED_MID, 0);
if (bus->ops->wait)
bus->ops->wait(ac97);
else {
@@ -1964,21 +1985,21 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97)
/* note: it's important to set the rate at first */
tmp = AC97_MEA_GPIO;
if (ac97->ext_mid & AC97_MEI_LINE1) {
- snd_ac97_write_cache(ac97, AC97_LINE1_RATE, 12000);
+ snd_ac97_write_cache(ac97, AC97_LINE1_RATE, 8000);
tmp |= AC97_MEA_ADC1 | AC97_MEA_DAC1;
}
if (ac97->ext_mid & AC97_MEI_LINE2) {
- snd_ac97_write_cache(ac97, AC97_LINE2_RATE, 12000);
+ snd_ac97_write_cache(ac97, AC97_LINE2_RATE, 8000);
tmp |= AC97_MEA_ADC2 | AC97_MEA_DAC2;
}
if (ac97->ext_mid & AC97_MEI_HANDSET) {
- snd_ac97_write_cache(ac97, AC97_HANDSET_RATE, 12000);
+ snd_ac97_write_cache(ac97, AC97_HANDSET_RATE, 8000);
tmp |= AC97_MEA_HADC | AC97_MEA_HDAC;
}
- snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8));
+ snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0);
udelay(100);
/* nothing should be in powerdown mode */
- snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8));
+ snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0);
end_time = jiffies + (HZ / 10);
do {
if ((snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS) & tmp) == tmp)
@@ -2521,11 +2542,11 @@ int snd_ac97_tune_hardware(ac97_t *ac97, struct ac97_quirk *quirk, const char *o
return result;
}
- for (; quirk->vendor; quirk++) {
- if (quirk->vendor != ac97->subsystem_vendor)
+ for (; quirk->subvendor; quirk++) {
+ if (quirk->subvendor != ac97->subsystem_vendor)
continue;
- if ((! quirk->mask && quirk->device == ac97->subsystem_device) ||
- quirk->device == (quirk->mask & ac97->subsystem_device)) {
+ if ((! quirk->mask && quirk->subdevice == ac97->subsystem_device) ||
+ quirk->subdevice == (quirk->mask & ac97->subsystem_device)) {
if (quirk->codec_id && quirk->codec_id != ac97->id)
continue;
snd_printdd("ac97 quirk for %s (%04x:%04x)\n", quirk->name, ac97->subsystem_vendor, ac97->subsystem_device);
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index 13c34a5d8206..a15eb8522b7c 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -64,6 +64,116 @@ static int ac97_update_bits_page(ac97_t *ac97, unsigned short reg, unsigned shor
return ret;
}
+/*
+ * shared line-in/mic controls
+ */
+static int ac97_enum_text_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo,
+ const char **texts, unsigned int nums)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = nums;
+ if (uinfo->value.enumerated.item > nums - 1)
+ uinfo->value.enumerated.item = nums - 1;
+ strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int ac97_surround_jack_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+ static const char *texts[] = { "Shared", "Independent" };
+ return ac97_enum_text_info(kcontrol, uinfo, texts, 2);
+}
+
+static int ac97_surround_jack_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.enumerated.item[0] = ac97->indep_surround;
+ return 0;
+}
+
+static int ac97_surround_jack_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+ unsigned char indep = !!ucontrol->value.enumerated.item[0];
+
+ if (indep != ac97->indep_surround) {
+ ac97->indep_surround = indep;
+ if (ac97->build_ops->update_jacks)
+ ac97->build_ops->update_jacks(ac97);
+ return 1;
+ }
+ return 0;
+}
+
+static int ac97_channel_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+ static const char *texts[] = { "2ch", "4ch", "6ch" };
+ if (kcontrol->private_value)
+ return ac97_enum_text_info(kcontrol, uinfo, texts, 2); /* 4ch only */
+ return ac97_enum_text_info(kcontrol, uinfo, texts, 3);
+}
+
+static int ac97_channel_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.enumerated.item[0] = ac97->channel_mode;
+ return 0;
+}
+
+static int ac97_channel_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+ unsigned char mode = ucontrol->value.enumerated.item[0];
+
+ if (mode != ac97->channel_mode) {
+ ac97->channel_mode = mode;
+ if (ac97->build_ops->update_jacks)
+ ac97->build_ops->update_jacks(ac97);
+ return 1;
+ }
+ return 0;
+}
+
+#define AC97_SURROUND_JACK_MODE_CTL \
+ { \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = "Surround Jack Mode", \
+ .info = ac97_surround_jack_mode_info, \
+ .get = ac97_surround_jack_mode_get, \
+ .put = ac97_surround_jack_mode_put, \
+ }
+#define AC97_CHANNEL_MODE_CTL \
+ { \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = "Channel Mode", \
+ .info = ac97_channel_mode_info, \
+ .get = ac97_channel_mode_get, \
+ .put = ac97_channel_mode_put, \
+ }
+#define AC97_CHANNEL_MODE_4CH_CTL \
+ { \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = "Channel Mode", \
+ .info = ac97_channel_mode_info, \
+ .get = ac97_channel_mode_get, \
+ .put = ac97_channel_mode_put, \
+ .private_value = 1, \
+ }
+
+static inline int is_shared_linein(ac97_t *ac97)
+{
+ return ! ac97->indep_surround && ac97->channel_mode >= 1;
+}
+
+static inline int is_shared_micin(ac97_t *ac97)
+{
+ return ! ac97->indep_surround && ac97->channel_mode >= 2;
+}
+
+
/* The following snd_ac97_ymf753_... items added by David Shust (dshust@shustring.com) */
/* It is possible to indicate to the Yamaha YMF753 the type of speakers being used. */
@@ -1390,6 +1500,16 @@ static int snd_ac97_ad1888_downmix_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_va
AC97_AD198X_DMIX0 | AC97_AD198X_DMIX1, val);
}
+static void ad1888_update_jacks(ac97_t *ac97)
+{
+ /* shared Line-In */
+ snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 12,
+ is_shared_linein(ac97) ? 0 : 1 << 12);
+ /* shared Mic */
+ snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 11,
+ is_shared_micin(ac97) ? 0 : 1 << 11);
+}
+
static const snd_kcontrol_new_t snd_ac97_ad1888_controls[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -1406,8 +1526,8 @@ static const snd_kcontrol_new_t snd_ac97_ad1888_controls[] = {
.get = snd_ac97_ad1888_downmix_get,
.put = snd_ac97_ad1888_downmix_put
},
- AC97_SINGLE("Surround Jack as Input", AC97_AD_MISC, 12, 1, 0),
- AC97_SINGLE("Center/LFE Jack as Input", AC97_AD_MISC, 11, 1, 0),
+ AC97_SURROUND_JACK_MODE_CTL,
+ AC97_CHANNEL_MODE_CTL,
};
static int patch_ad1888_specific(ac97_t *ac97)
@@ -1422,8 +1542,9 @@ static struct snd_ac97_build_ops patch_ad1888_build_ops = {
.build_post_spdif = patch_ad198x_post_spdif,
.build_specific = patch_ad1888_specific,
#ifdef CONFIG_PM
- .resume = ad18xx_resume
+ .resume = ad18xx_resume,
#endif
+ .update_jacks = ad1888_update_jacks,
};
int patch_ad1888(ac97_t * ac97)
@@ -1459,8 +1580,9 @@ static struct snd_ac97_build_ops patch_ad1980_build_ops = {
.build_post_spdif = patch_ad198x_post_spdif,
.build_specific = patch_ad1980_specific,
#ifdef CONFIG_PM
- .resume = ad18xx_resume
+ .resume = ad18xx_resume,
#endif
+ .update_jacks = ad1888_update_jacks,
};
int patch_ad1980(ac97_t * ac97)
@@ -1471,10 +1593,21 @@ int patch_ad1980(ac97_t * ac97)
}
static const snd_kcontrol_new_t snd_ac97_ad1985_controls[] = {
- AC97_SINGLE("Center/LFE Jack as Mic", AC97_AD_SERIAL_CFG, 9, 1, 0),
AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0)
};
+static void ad1985_update_jacks(ac97_t *ac97)
+{
+ /* shared Line-In */
+ snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 12,
+ is_shared_linein(ac97) ? 0 : 1 << 12);
+ /* shared Mic */
+ snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 11,
+ is_shared_micin(ac97) ? 0 : 1 << 11);
+ snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 1 << 9,
+ is_shared_micin(ac97) ? 0 : 1 << 9);
+}
+
static int patch_ad1985_specific(ac97_t *ac97)
{
int err;
@@ -1488,8 +1621,9 @@ static struct snd_ac97_build_ops patch_ad1985_build_ops = {
.build_post_spdif = patch_ad198x_post_spdif,
.build_specific = patch_ad1985_specific,
#ifdef CONFIG_PM
- .resume = ad18xx_resume
+ .resume = ad18xx_resume,
#endif
+ .update_jacks = ad1985_update_jacks,
};
int patch_ad1985(ac97_t * ac97)
@@ -1521,31 +1655,25 @@ int patch_ad1985(ac97_t * ac97)
/*
* realtek ALC65x/850 codecs
*/
-static int snd_ac97_alc650_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
- ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
- ucontrol->value.integer.value[0] = (ac97->regs[AC97_ALC650_MULTICH] >> 10) & 1;
- return 0;
-}
-
-static int snd_ac97_alc650_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
+static void alc650_update_jacks(ac97_t *ac97)
{
- ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
- int change, val;
- val = !!(snd_ac97_read(ac97, AC97_ALC650_MULTICH) & (1 << 10));
- change = (ucontrol->value.integer.value[0] != val);
- if (change) {
- /* disable/enable vref */
- snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12,
- ucontrol->value.integer.value[0] ? (1 << 12) : 0);
- /* turn on/off center-on-mic */
- snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10,
- ucontrol->value.integer.value[0] ? (1 << 10) : 0);
- /* GPIO0 high for mic */
- snd_ac97_update_bits(ac97, AC97_ALC650_GPIO_STATUS, 0x100,
- ucontrol->value.integer.value[0] ? 0 : 0x100);
- }
- return change;
+ int shared;
+
+ /* shared Line-In */
+ shared = is_shared_linein(ac97);
+ snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 9,
+ shared ? (1 << 9) : 0);
+ /* update shared Mic */
+ shared = is_shared_micin(ac97);
+ /* disable/enable vref */
+ snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12,
+ shared ? (1 << 12) : 0);
+ /* turn on/off center-on-mic */
+ snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10,
+ shared ? (1 << 10) : 0);
+ /* GPIO0 high for mic */
+ snd_ac97_update_bits(ac97, AC97_ALC650_GPIO_STATUS, 0x100,
+ shared ? 0 : 0x100);
}
static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = {
@@ -1558,8 +1686,8 @@ static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = {
/* 6: Independent Master Volume Right */
/* 7: Independent Master Volume Left */
/* 8: reserved */
- AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0),
- /* 10: mic, see below */
+ /* 9: Line-In/Surround share */
+ /* 10: Mic/CLFE share */
/* 11-13: in IEC958 controls */
AC97_SINGLE("Swap Surround Slot", AC97_ALC650_MULTICH, 14, 1, 0),
#if 0 /* always set in patch_alc650 */
@@ -1570,14 +1698,8 @@ static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = {
AC97_SINGLE("Center/LFE DAC Switch", AC97_ALC650_LFE_DAC_VOL, 15, 1, 1),
AC97_DOUBLE("Center/LFE DAC Volume", AC97_ALC650_LFE_DAC_VOL, 8, 0, 31, 1),
#endif
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Mic As Center/LFE",
- .info = snd_ac97_info_volsw,
- .get = snd_ac97_alc650_mic_get,
- .put = snd_ac97_alc650_mic_put,
- .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */
- },
+ AC97_SURROUND_JACK_MODE_CTL,
+ AC97_CHANNEL_MODE_CTL,
};
static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc650[] = {
@@ -1601,7 +1723,8 @@ static int patch_alc650_specific(ac97_t * ac97)
}
static struct snd_ac97_build_ops patch_alc650_ops = {
- .build_specific = patch_alc650_specific
+ .build_specific = patch_alc650_specific,
+ .update_jacks = alc650_update_jacks
};
int patch_alc650(ac97_t * ac97)
@@ -1659,37 +1782,27 @@ int patch_alc650(ac97_t * ac97)
return 0;
}
-static int snd_ac97_alc655_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
- ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
- ucontrol->value.integer.value[0] = (ac97->regs[AC97_ALC650_MULTICH] >> 10) & 1;
- return 0;
-}
-
-static int snd_ac97_alc655_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
+static void alc655_update_jacks(ac97_t *ac97)
{
- ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
-
+ int shared;
+
+ /* shared Line-In */
+ shared = is_shared_linein(ac97);
+ ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 9,
+ shared ? (1 << 9) : 0, 0);
+ /* update shared mic */
+ shared = is_shared_micin(ac97);
/* misc control; vrefout disable */
snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12,
- ucontrol->value.integer.value[0] ? (1 << 12) : 0);
- return ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 10,
- ucontrol->value.integer.value[0] ? (1 << 10) : 0,
- 0);
+ shared ? (1 << 12) : 0);
+ ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 10,
+ shared ? (1 << 10) : 0, 0);
}
-
static const snd_kcontrol_new_t snd_ac97_controls_alc655[] = {
AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0),
- AC97_PAGE_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0, 0),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Mic As Center/LFE",
- .info = snd_ac97_info_volsw,
- .get = snd_ac97_alc655_mic_get,
- .put = snd_ac97_alc655_mic_put,
- .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */
- },
+ AC97_SURROUND_JACK_MODE_CTL,
+ AC97_CHANNEL_MODE_CTL,
};
static int alc655_iec958_route_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
@@ -1759,7 +1872,8 @@ static int patch_alc655_specific(ac97_t * ac97)
}
static struct snd_ac97_build_ops patch_alc655_ops = {
- .build_specific = patch_alc655_specific
+ .build_specific = patch_alc655_specific,
+ .update_jacks = alc655_update_jacks
};
int patch_alc655(ac97_t * ac97)
@@ -1798,63 +1912,33 @@ int patch_alc655(ac97_t * ac97)
#define AC97_ALC850_JACK_SELECT 0x76
#define AC97_ALC850_MISC1 0x7a
-static int ac97_alc850_surround_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
- ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
- ucontrol->value.integer.value[0] = ((ac97->regs[AC97_ALC850_JACK_SELECT] >> 12) & 7) == 2;
- return 0;
-}
-
-static int ac97_alc850_surround_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
+static void alc850_update_jacks(ac97_t *ac97)
{
- ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
-
+ int shared;
+
+ /* shared Line-In */
+ shared = is_shared_linein(ac97);
/* SURR 1kOhm (bit4), Amp (bit5) */
snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<4)|(1<<5),
- ucontrol->value.integer.value[0] ? (1<<5) : (1<<4));
+ shared ? (1<<5) : (1<<4));
/* LINE-IN = 0, SURROUND = 2 */
- return snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 12,
- ucontrol->value.integer.value[0] ? (2<<12) : (0<<12));
-}
-
-static int ac97_alc850_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
- ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
- ucontrol->value.integer.value[0] = ((ac97->regs[AC97_ALC850_JACK_SELECT] >> 4) & 7) == 2;
- return 0;
-}
-
-static int ac97_alc850_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
- ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
-
+ snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 12,
+ shared ? (2<<12) : (0<<12));
+ /* update shared mic */
+ shared = is_shared_micin(ac97);
/* Vref disable (bit12), 1kOhm (bit13) */
snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<12)|(1<<13),
- ucontrol->value.integer.value[0] ? (1<<12) : (1<<13));
+ shared ? (1<<12) : (1<<13));
/* MIC-IN = 1, CENTER-LFE = 2 */
- return snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 4,
- ucontrol->value.integer.value[0] ? (2<<4) : (1<<4));
+ snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 4,
+ shared ? (2<<4) : (1<<4));
}
static const snd_kcontrol_new_t snd_ac97_controls_alc850[] = {
AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Line-In As Surround",
- .info = snd_ac97_info_volsw,
- .get = ac97_alc850_surround_get,
- .put = ac97_alc850_surround_put,
- .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */
- },
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Mic As Center/LFE",
- .info = snd_ac97_info_volsw,
- .get = ac97_alc850_mic_get,
- .put = ac97_alc850_mic_put,
- .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */
- },
-
+ AC97_SINGLE("Mic Front Input Switch", AC97_ALC850_JACK_SELECT, 15, 1, 1),
+ AC97_SURROUND_JACK_MODE_CTL,
+ AC97_CHANNEL_MODE_CTL,
};
static int patch_alc850_specific(ac97_t *ac97)
@@ -1871,7 +1955,8 @@ static int patch_alc850_specific(ac97_t *ac97)
}
static struct snd_ac97_build_ops patch_alc850_ops = {
- .build_specific = patch_alc850_specific
+ .build_specific = patch_alc850_specific,
+ .update_jacks = alc850_update_jacks
};
int patch_alc850(ac97_t *ac97)
@@ -1911,9 +1996,17 @@ int patch_alc850(ac97_t *ac97)
/*
* C-Media CM97xx codecs
*/
+static void cm9738_update_jacks(ac97_t *ac97)
+{
+ /* shared Line-In */
+ snd_ac97_update_bits(ac97, AC97_CM9738_VENDOR_CTRL, 1 << 10,
+ is_shared_linein(ac97) ? (1 << 10) : 0);
+}
+
static const snd_kcontrol_new_t snd_ac97_cm9738_controls[] = {
- AC97_SINGLE("Line-In As Surround", AC97_CM9738_VENDOR_CTRL, 10, 1, 0),
AC97_SINGLE("Duplicate Front", AC97_CM9738_VENDOR_CTRL, 13, 1, 0),
+ AC97_SURROUND_JACK_MODE_CTL,
+ AC97_CHANNEL_MODE_4CH_CTL,
};
static int patch_cm9738_specific(ac97_t * ac97)
@@ -1922,7 +2015,8 @@ static int patch_cm9738_specific(ac97_t * ac97)
}
static struct snd_ac97_build_ops patch_cm9738_ops = {
- .build_specific = patch_cm9738_specific
+ .build_specific = patch_cm9738_specific,
+ .update_jacks = cm9738_update_jacks
};
int patch_cm9738(ac97_t * ac97)
@@ -1986,34 +2080,19 @@ static const snd_kcontrol_new_t snd_ac97_cm9739_controls_spdif[] = {
/* BIT 8: SPD32 - 32bit SPDIF - not supported yet */
};
-static int snd_ac97_cm9739_center_mic_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
- ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
- if (ac97->regs[AC97_CM9739_MULTI_CHAN] & 0x1000)
- ucontrol->value.integer.value[0] = 1;
- else
- ucontrol->value.integer.value[0] = 0;
- return 0;
-}
-
-static int snd_ac97_cm9739_center_mic_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static void cm9739_update_jacks(ac97_t *ac97)
{
- ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
- return snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3000,
- ucontrol->value.integer.value[0] ?
- 0x1000 : 0x2000);
+ /* shared Line-In */
+ snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 1 << 10,
+ is_shared_linein(ac97) ? (1 << 10) : 0);
+ /* shared Mic */
+ snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3000,
+ is_shared_micin(ac97) ? 0x1000 : 0x2000);
}
static const snd_kcontrol_new_t snd_ac97_cm9739_controls[] = {
- AC97_SINGLE("Line-In As Surround", AC97_CM9739_MULTI_CHAN, 10, 1, 0),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Mic As Center/LFE",
- .info = snd_ac97_info_volsw,
- .get = snd_ac97_cm9739_center_mic_get,
- .put = snd_ac97_cm9739_center_mic_put,
- .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */
- },
+ AC97_SURROUND_JACK_MODE_CTL,
+ AC97_CHANNEL_MODE_CTL,
};
static int patch_cm9739_specific(ac97_t * ac97)
@@ -2028,7 +2107,8 @@ static int patch_cm9739_post_spdif(ac97_t * ac97)
static struct snd_ac97_build_ops patch_cm9739_ops = {
.build_specific = patch_cm9739_specific,
- .build_post_spdif = patch_cm9739_post_spdif
+ .build_post_spdif = patch_cm9739_post_spdif,
+ .update_jacks = cm9739_update_jacks
};
int patch_cm9739(ac97_t * ac97)
@@ -2087,71 +2167,97 @@ int patch_cm9739(ac97_t * ac97)
}
#define AC97_CM9761_MULTI_CHAN 0x64
+#define AC97_CM9761_FUNC 0x66
#define AC97_CM9761_SPDIF_CTRL 0x6c
-static int snd_ac97_cm9761_linein_rear_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
-{
- ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
- if (ac97->regs[AC97_CM9739_MULTI_CHAN] & 0x0400)
- ucontrol->value.integer.value[0] = 1;
- else
- ucontrol->value.integer.value[0] = 0;
- return 0;
-}
-
-static int snd_ac97_cm9761_linein_rear_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static void cm9761_update_jacks(ac97_t *ac97)
{
- ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
- unsigned short vals[2][2] = {
+ unsigned short surr_vals[2][2] = {
{ 0x0008, 0x0400 }, /* off, on */
{ 0x0000, 0x0408 }, /* off, on (9761-82 rev.B) */
};
- return snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x0408,
- vals[ac97->spec.dev_flags][!!ucontrol->value.integer.value[0]]);
+ unsigned short clfe_vals[2][2] = {
+ { 0x2000, 0x1880 }, /* off, on */
+ { 0x1000, 0x2880 }, /* off, on (9761-82 rev.B) */
+ };
+
+ /* shared Line-In */
+ snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x0408,
+ surr_vals[ac97->spec.dev_flags][is_shared_linein(ac97)]);
+ /* shared Mic */
+ snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x3880,
+ clfe_vals[ac97->spec.dev_flags][is_shared_micin(ac97)]);
+}
+
+static const snd_kcontrol_new_t snd_ac97_cm9761_controls[] = {
+ AC97_SURROUND_JACK_MODE_CTL,
+ AC97_CHANNEL_MODE_CTL,
+};
+
+static int cm9761_spdif_out_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+ static char *texts[] = { "AC-Link", "ADC", "SPDIF-In" };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 3;
+ if (uinfo->value.enumerated.item > 2)
+ uinfo->value.enumerated.item = 2;
+ strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+ return 0;
}
-static int snd_ac97_cm9761_center_mic_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static int cm9761_spdif_out_source_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
- if (ac97->regs[AC97_CM9739_MULTI_CHAN] & 0x1000)
- ucontrol->value.integer.value[0] = 1;
+
+ if (ac97->regs[AC97_CM9761_FUNC] & 0x1)
+ ucontrol->value.enumerated.item[0] = 2; /* SPDIF-loopback */
+ else if (ac97->regs[AC97_CM9761_SPDIF_CTRL] & 0x2)
+ ucontrol->value.enumerated.item[0] = 1; /* ADC loopback */
else
- ucontrol->value.integer.value[0] = 0;
- if (ac97->spec.dev_flags) /* 9761-82 rev.B */
- ucontrol->value.integer.value[0] = !ucontrol->value.integer.value[0];
+ ucontrol->value.enumerated.item[0] = 0; /* AC-link */
return 0;
}
-static int snd_ac97_cm9761_center_mic_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static int cm9761_spdif_out_source_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
- unsigned short vals[2][2] = {
- { 0x2000, 0x1880 }, /* off, on */
- { 0x1000, 0x2880 }, /* off, on (9761-82 rev.B) */
- };
- return snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3880,
- vals[ac97->spec.dev_flags][!!ucontrol->value.integer.value[0]]);
+
+ if (ucontrol->value.enumerated.item[0] == 2)
+ return snd_ac97_update_bits(ac97, AC97_CM9761_FUNC, 0x1, 0x1);
+ snd_ac97_update_bits(ac97, AC97_CM9761_FUNC, 0x1, 0);
+ return snd_ac97_update_bits(ac97, AC97_CM9761_SPDIF_CTRL, 0x2,
+ ucontrol->value.enumerated.item[0] == 1 ? 0x2 : 0);
}
-static const snd_kcontrol_new_t snd_ac97_cm9761_controls[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Line-In As Surround",
- .info = snd_ac97_info_volsw,
- .get = snd_ac97_cm9761_linein_rear_get,
- .put = snd_ac97_cm9761_linein_rear_put,
- .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */
- },
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Mic As Center/LFE",
- .info = snd_ac97_info_volsw,
- .get = snd_ac97_cm9761_center_mic_get,
- .put = snd_ac97_cm9761_center_mic_put,
- .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */
+static const char *cm9761_dac_clock[] = { "AC-Link", "SPDIF-In", "Both" };
+static const struct ac97_enum cm9761_dac_clock_enum =
+ AC97_ENUM_SINGLE(AC97_CM9761_SPDIF_CTRL, 9, 3, cm9761_dac_clock);
+
+static const snd_kcontrol_new_t snd_ac97_cm9761_controls_spdif[] = {
+ { /* BIT 1: SPDIFS */
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
+ .info = cm9761_spdif_out_source_info,
+ .get = cm9761_spdif_out_source_get,
+ .put = cm9761_spdif_out_source_put,
},
+ /* BIT 2: IG_SPIV */
+ AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Valid Switch", AC97_CM9761_SPDIF_CTRL, 2, 1, 0),
+ /* BIT 3: SPI2F */
+ AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Monitor", AC97_CM9761_SPDIF_CTRL, 3, 1, 0),
+ /* BIT 4: SPI2SDI */
+ AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), AC97_CM9761_SPDIF_CTRL, 4, 1, 0),
+ /* BIT 9-10: DAC_CTL */
+ AC97_ENUM("DAC Clock Source", cm9761_dac_clock_enum),
};
+static int patch_cm9761_post_spdif(ac97_t * ac97)
+{
+ return patch_build_controls(ac97, snd_ac97_cm9761_controls_spdif, ARRAY_SIZE(snd_ac97_cm9761_controls_spdif));
+}
+
static int patch_cm9761_specific(ac97_t * ac97)
{
return patch_build_controls(ac97, snd_ac97_cm9761_controls, ARRAY_SIZE(snd_ac97_cm9761_controls));
@@ -2159,7 +2265,8 @@ static int patch_cm9761_specific(ac97_t * ac97)
static struct snd_ac97_build_ops patch_cm9761_ops = {
.build_specific = patch_cm9761_specific,
- .build_post_spdif = patch_cm9739_post_spdif /* hope it's identical... */
+ .build_post_spdif = patch_cm9761_post_spdif,
+ .update_jacks = cm9761_update_jacks
};
int patch_cm9761(ac97_t *ac97)
@@ -2193,24 +2300,25 @@ int patch_cm9761(ac97_t *ac97)
/* to be sure: we overwrite the ext status bits */
snd_ac97_write_cache(ac97, AC97_EXTENDED_STATUS, 0x05c0);
/* Don't set 0x0200 here. This results in the silent analog output */
- snd_ac97_write_cache(ac97, AC97_CM9761_SPDIF_CTRL, 0x0009);
+ snd_ac97_write_cache(ac97, AC97_CM9761_SPDIF_CTRL, 0x0001); /* enable spdif-in */
ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */
/* set-up multi channel */
/* bit 15: pc master beep off
- * bit 14: ??
+ * bit 14: pin47 = EAPD/SPDIF
* bit 13: vref ctl [= cm9739]
- * bit 12: center/mic [= cm9739] (reverted on rev B)
- * bit 11: ?? (mic/center/lfe) (reverted on rev B)
- * bit 10: suddound/line [= cm9739]
- * bit 9: mix 2 surround
- * bit 8: ?
- * bit 7: ?? (mic/center/lfe)
- * bit 4: ?? (front)
- * bit 3: ?? (line-in/rear share) (revereted with rev B)
- * bit 2: ?? (surround)
- * bit 1: front mic
- * bit 0: mic boost
+ * bit 12: CLFE control (reverted on rev B)
+ * bit 11: Mic/center share (reverted on rev B)
+ * bit 10: suddound/line share
+ * bit 9: Analog-in mix -> surround
+ * bit 8: Analog-in mix -> CLFE
+ * bit 7: Mic/LFE share (mic/center/lfe)
+ * bit 5: vref select (9761A)
+ * bit 4: front control
+ * bit 3: surround control (revereted with rev B)
+ * bit 2: front mic
+ * bit 1: stereo mic
+ * bit 0: mic boost level (0=20dB, 1=30dB)
*/
#if 0
@@ -2230,6 +2338,47 @@ int patch_cm9761(ac97_t *ac97)
return 0;
}
+#define AC97_CM9780_SIDE 0x60
+#define AC97_CM9780_JACK 0x62
+#define AC97_CM9780_MIXER 0x64
+#define AC97_CM9780_MULTI_CHAN 0x66
+#define AC97_CM9780_SPDIF 0x6c
+
+static const char *cm9780_ch_select[] = { "Front", "Side", "Center/LFE", "Rear" };
+static const struct ac97_enum cm9780_ch_select_enum =
+ AC97_ENUM_SINGLE(AC97_CM9780_MULTI_CHAN, 6, 4, cm9780_ch_select);
+static const snd_kcontrol_new_t cm9780_controls[] = {
+ AC97_DOUBLE("Side Playback Switch", AC97_CM9780_SIDE, 15, 7, 1, 1),
+ AC97_DOUBLE("Side Playback Volume", AC97_CM9780_SIDE, 8, 0, 31, 0),
+ AC97_ENUM("Side Playback Route", cm9780_ch_select_enum),
+};
+
+static int patch_cm9780_specific(ac97_t *ac97)
+{
+ return patch_build_controls(ac97, cm9780_controls, ARRAY_SIZE(cm9780_controls));
+}
+
+static struct snd_ac97_build_ops patch_cm9780_ops = {
+ .build_specific = patch_cm9780_specific,
+ .build_post_spdif = patch_cm9761_post_spdif /* identical with CM9761 */
+};
+
+int patch_cm9780(ac97_t *ac97)
+{
+ unsigned short val;
+
+ ac97->build_ops = &patch_cm9780_ops;
+
+ /* enable spdif */
+ if (ac97->ext_id & AC97_EI_SPDIF) {
+ ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */
+ val = snd_ac97_read(ac97, AC97_CM9780_SPDIF);
+ val |= 0x1; /* SPDI_EN */
+ snd_ac97_write_cache(ac97, AC97_CM9780_SPDIF, val);
+ }
+
+ return 0;
+}
/*
* VIA VT1616 codec
@@ -2263,9 +2412,21 @@ int patch_vt1616(ac97_t * ac97)
return 0;
}
+/*
+ */
+static void it2646_update_jacks(ac97_t *ac97)
+{
+ /* shared Line-In */
+ snd_ac97_update_bits(ac97, 0x76, 1 << 9,
+ is_shared_linein(ac97) ? (1<<9) : 0);
+ /* shared Mic */
+ snd_ac97_update_bits(ac97, 0x76, 1 << 10,
+ is_shared_micin(ac97) ? (1<<10) : 0);
+}
+
static const snd_kcontrol_new_t snd_ac97_controls_it2646[] = {
- AC97_SINGLE("Line-In As Surround", 0x76, 9, 1, 0),
- AC97_SINGLE("Mic As Center/LFE", 0x76, 10, 1, 0),
+ AC97_SURROUND_JACK_MODE_CTL,
+ AC97_CHANNEL_MODE_CTL,
};
static const snd_kcontrol_new_t snd_ac97_spdif_controls_it2646[] = {
@@ -2285,7 +2446,8 @@ static int patch_it2646_specific(ac97_t * ac97)
}
static struct snd_ac97_build_ops patch_it2646_ops = {
- .build_specific = patch_it2646_specific
+ .build_specific = patch_it2646_specific,
+ .update_jacks = it2646_update_jacks
};
int patch_it2646(ac97_t * ac97)
@@ -2297,12 +2459,29 @@ int patch_it2646(ac97_t * ac97)
return 0;
}
-/* Si3036/8 specific registers */
+/*
+ * Si3036 codec
+ */
+
#define AC97_SI3036_CHIP_ID 0x5a
+#define AC97_SI3036_LINE_CFG 0x5c
+
+static const snd_kcontrol_new_t snd_ac97_controls_si3036[] = {
+AC97_DOUBLE("Modem Speaker Volume", 0x5c, 14, 12, 3, 1)
+};
+
+static int patch_si3036_specific(ac97_t * ac97)
+{
+ return patch_build_controls(ac97, snd_ac97_controls_si3036, ARRAY_SIZE(snd_ac97_controls_si3036));
+}
+
+static struct snd_ac97_build_ops patch_si3036_ops = {
+ .build_specific = patch_si3036_specific,
+};
int mpatch_si3036(ac97_t * ac97)
{
- //printk("mpatch_si3036: chip id = %x\n", snd_ac97_read(ac97, 0x5a));
+ ac97->build_ops = &patch_si3036_ops;
snd_ac97_write_cache(ac97, 0x5c, 0xf210 );
snd_ac97_write_cache(ac97, 0x68, 0);
return 0;
diff --git a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h
index 6db51c96f5d0..7b7377d0f2ae 100644
--- a/sound/pci/ac97/ac97_patch.h
+++ b/sound/pci/ac97/ac97_patch.h
@@ -54,6 +54,7 @@ int patch_alc850(ac97_t * ac97);
int patch_cm9738(ac97_t * ac97);
int patch_cm9739(ac97_t * ac97);
int patch_cm9761(ac97_t * ac97);
+int patch_cm9780(ac97_t * ac97);
int patch_vt1616(ac97_t * ac97);
int patch_it2646(ac97_t * ac97);
int mpatch_si3036(ac97_t * ac97);