diff options
Diffstat (limited to 'sound')
33 files changed, 497 insertions, 238 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 45b4a8d..39e1a6a 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1328,7 +1328,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, for (i = 0; i < c->cvt_setups.used; i++) { p = snd_array_elem(&c->cvt_setups, i); if (!p->active && p->stream_tag == stream_tag && - get_wcaps_type(get_wcaps(codec, p->nid)) == type) + get_wcaps_type(get_wcaps(c, p->nid)) == type) p->dirty = 1; } } @@ -1651,7 +1651,11 @@ static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info, parm = ch ? AC_AMP_SET_RIGHT : AC_AMP_SET_LEFT; parm |= direction == HDA_OUTPUT ? AC_AMP_SET_OUTPUT : AC_AMP_SET_INPUT; parm |= index << AC_AMP_SET_INDEX_SHIFT; - parm |= val; + if ((val & HDA_AMP_MUTE) && !(info->amp_caps & AC_AMPCAP_MUTE) && + (info->amp_caps & AC_AMPCAP_MIN_MUTE)) + ; /* set the zero value as a fake mute */ + else + parm |= val; snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, parm); info->vol[ch] = val; } @@ -1918,7 +1922,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT); val1 += ofs; val1 = ((int)val1) * ((int)val2); - if (min_mute) + if (min_mute || (caps & AC_AMPCAP_MIN_MUTE)) val2 |= TLV_DB_SCALE_MUTE; if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv)) return -EFAULT; @@ -2187,6 +2191,39 @@ int snd_hda_codec_reset(struct hda_codec *codec) return 0; } +typedef int (*map_slave_func_t)(void *, struct snd_kcontrol *); + +/* apply the function to all matching slave ctls in the mixer list */ +static int map_slaves(struct hda_codec *codec, const char * const *slaves, + map_slave_func_t func, void *data) +{ + struct hda_nid_item *items; + const char * const *s; + int i, err; + + items = codec->mixers.list; + for (i = 0; i < codec->mixers.used; i++) { + struct snd_kcontrol *sctl = items[i].kctl; + if (!sctl || !sctl->id.name || + sctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER) + continue; + for (s = slaves; *s; s++) { + if (!strcmp(sctl->id.name, *s)) { + err = func(data, sctl); + if (err) + return err; + break; + } + } + } + return 0; +} + +static int check_slave_present(void *data, struct snd_kcontrol *sctl) +{ + return 1; +} + /** * snd_hda_add_vmaster - create a virtual master control and add slaves * @codec: HD-audio codec @@ -2207,12 +2244,10 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, unsigned int *tlv, const char * const *slaves) { struct snd_kcontrol *kctl; - const char * const *s; int err; - for (s = slaves; *s && !snd_hda_find_mixer_ctl(codec, *s); s++) - ; - if (!*s) { + err = map_slaves(codec, slaves, check_slave_present, NULL); + if (err != 1) { snd_printdd("No slave found for %s\n", name); return 0; } @@ -2223,23 +2258,10 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, if (err < 0) return err; - for (s = slaves; *s; s++) { - struct snd_kcontrol *sctl; - int i = 0; - for (;;) { - sctl = _snd_hda_find_mixer_ctl(codec, *s, i); - if (!sctl) { - if (!i) - snd_printdd("Cannot find slave %s, " - "skipped\n", *s); - break; - } - err = snd_ctl_add_slave(kctl, sctl); - if (err < 0) - return err; - i++; - } - } + err = map_slaves(codec, slaves, (map_slave_func_t)snd_ctl_add_slave, + kctl); + if (err < 0) + return err; return 0; } EXPORT_SYMBOL_HDA(snd_hda_add_vmaster); diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 59c9730..eff1fc5 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -302,6 +302,9 @@ enum { #define AC_AMPCAP_MUTE (1<<31) /* mute capable */ #define AC_AMPCAP_MUTE_SHIFT 31 +/* driver-specific amp-caps: using bits 24-30 */ +#define AC_AMPCAP_MIN_MUTE (1 << 30) /* min-volume = mute */ + /* Connection list */ #define AC_CLIST_LENGTH (0x7f<<0) #define AC_CLIST_LONG (1<<7) diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 08ec073..e289a13 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -474,7 +474,12 @@ static inline u32 get_wcaps(struct hda_codec *codec, hda_nid_t nid) } /* get the widget type from widget capability bits */ -#define get_wcaps_type(wcaps) (((wcaps) & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT) +static inline int get_wcaps_type(unsigned int wcaps) +{ + if (!wcaps) + return -1; /* invalid type */ + return (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; +} static inline unsigned int get_wcaps_channels(u32 wcaps) { diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index bfe74c2..6fe944a 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -54,6 +54,8 @@ static const char *get_wid_type_name(unsigned int wid_value) [AC_WID_BEEP] = "Beep Generator Widget", [AC_WID_VENDOR] = "Vendor Defined Widget", }; + if (wid_value == -1) + return "UNKNOWN Widget"; wid_value &= 0xf; if (names[wid_value]) return names[wid_value]; diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index cf1fa36..4ad20a6 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -136,6 +136,7 @@ struct conexant_spec { unsigned int thinkpad:1; unsigned int hp_laptop:1; unsigned int asus:1; + unsigned int single_adc_amp:1; unsigned int adc_switching:1; @@ -1916,6 +1917,10 @@ static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid, snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | event); +} + +static void cxt5051_init_mic_jack(struct hda_codec *codec, hda_nid_t nid) +{ snd_hda_input_jack_add(codec, nid, SND_JACK_MICROPHONE, NULL); snd_hda_input_jack_report(codec, nid); } @@ -1933,7 +1938,6 @@ static int cxt5051_init(struct hda_codec *codec) struct conexant_spec *spec = codec->spec; conexant_init(codec); - conexant_init_jacks(codec); if (spec->auto_mic & AUTO_MIC_PORTB) cxt5051_init_mic_port(codec, 0x17, CXT5051_PORTB_EVENT); @@ -2066,6 +2070,12 @@ static int patch_cxt5051(struct hda_codec *codec) if (spec->beep_amp) snd_hda_attach_beep_device(codec, spec->beep_amp); + conexant_init_jacks(codec); + if (spec->auto_mic & AUTO_MIC_PORTB) + cxt5051_init_mic_jack(codec, 0x17); + if (spec->auto_mic & AUTO_MIC_PORTC) + cxt5051_init_mic_jack(codec, 0x18); + return 0; } @@ -4117,7 +4127,8 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename, err = snd_hda_ctl_add(codec, nid, kctl); if (err < 0) return err; - if (!(query_amp_caps(codec, nid, hda_dir) & AC_AMPCAP_MUTE)) + if (!(query_amp_caps(codec, nid, hda_dir) & + (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE))) break; } return 0; @@ -4205,6 +4216,8 @@ static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid, int idx = get_input_connection(codec, adc_nid, nid); if (idx < 0) continue; + if (spec->single_adc_amp) + idx = 0; return cx_auto_add_volume_idx(codec, label, pfx, cidx, adc_nid, HDA_INPUT, idx); } @@ -4245,14 +4258,21 @@ static int cx_auto_build_input_controls(struct hda_codec *codec) struct hda_input_mux *imux = &spec->private_imux; const char *prev_label; int input_conn[HDA_MAX_NUM_INPUTS]; - int i, err, cidx; + int i, j, err, cidx; int multi_connection; + if (!imux->num_items) + return 0; + multi_connection = 0; for (i = 0; i < imux->num_items; i++) { cidx = get_input_connection(codec, spec->imux_info[i].adc, spec->imux_info[i].pin); - input_conn[i] = (spec->imux_info[i].adc << 8) | cidx; + if (cidx < 0) + continue; + input_conn[i] = spec->imux_info[i].adc; + if (!spec->single_adc_amp) + input_conn[i] |= cidx << 8; if (i > 0 && input_conn[i] != input_conn[0]) multi_connection = 1; } @@ -4281,6 +4301,15 @@ static int cx_auto_build_input_controls(struct hda_codec *codec) err = cx_auto_add_capture_volume(codec, nid, "Capture", "", cidx); } else { + bool dup_found = false; + for (j = 0; j < i; j++) { + if (input_conn[j] == input_conn[i]) { + dup_found = true; + break; + } + } + if (dup_found) + continue; err = cx_auto_add_capture_volume(codec, nid, label, " Capture", cidx); } @@ -4344,6 +4373,22 @@ static const struct hda_codec_ops cx_auto_patch_ops = { .reboot_notify = snd_hda_shutup_pins, }; +/* add "fake" mute amp-caps to DACs on cx5051 so that mixer mute switches + * can be created (bko#42825) + */ +static void add_cx5051_fake_mutes(struct hda_codec *codec) +{ + static hda_nid_t out_nids[] = { + 0x10, 0x11, 0 + }; + hda_nid_t *p; + + for (p = out_nids; *p; p++) + snd_hda_override_amp_caps(codec, *p, HDA_OUTPUT, + AC_AMPCAP_MIN_MUTE | + query_amp_caps(codec, *p, HDA_OUTPUT)); +} + static int patch_conexant_auto(struct hda_codec *codec) { struct conexant_spec *spec; @@ -4357,6 +4402,16 @@ static int patch_conexant_auto(struct hda_codec *codec) return -ENOMEM; codec->spec = spec; codec->pin_amp_workaround = 1; + + switch (codec->vendor_id) { + case 0x14f15045: + spec->single_adc_amp = 1; + break; + case 0x14f15051: + add_cx5051_fake_mutes(codec); + break; + } + err = cx_auto_search_adcs(codec); if (err < 0) return err; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 4c7cd6b..51412e1 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -509,6 +509,8 @@ static int alc_mux_enum_put(struct snd_kcontrol *kcontrol, imux = &spec->input_mux[mux_idx]; if (!imux->num_items && mux_idx > 0) imux = &spec->input_mux[0]; + if (!imux->num_items) + return 0; type = get_wcaps_type(get_wcaps(codec, nid)); if (type == AC_WID_AUD_MIX) { @@ -2088,25 +2090,27 @@ static void alc_auto_init_digital(struct hda_codec *codec) static void alc_auto_parse_digital(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - int i, err; + int i, err, nums; hda_nid_t dig_nid; /* support multiple SPDIFs; the secondary is set up as a slave */ + nums = 0; for (i = 0; i < spec->autocfg.dig_outs; i++) { err = snd_hda_get_connections(codec, spec->autocfg.dig_out_pins[i], &dig_nid, 1); - if (err < 0) + if (err <= 0) continue; - if (!i) { + if (!nums) { spec->multiout.dig_out_nid = dig_nid; spec->dig_out_type = spec->autocfg.dig_out_type[0]; } else { spec->multiout.slave_dig_outs = spec->slave_dig_outs; - if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1) + if (nums >= ARRAY_SIZE(spec->slave_dig_outs) - 1) break; - spec->slave_dig_outs[i - 1] = dig_nid; + spec->slave_dig_outs[nums - 1] = dig_nid; } + nums++; } if (spec->autocfg.dig_in_pin) { @@ -16415,6 +16419,7 @@ static const struct alc_config_preset alc861_presets[] = { /* Pin config fixes */ enum { PINFIX_FSC_AMILO_PI1505, + PINFIX_ASUS_A6RP, }; static const struct alc_fixup alc861_fixups[] = { @@ -16426,9 +16431,19 @@ static const struct alc_fixup alc861_fixups[] = { { } } }, + [PINFIX_ASUS_A6RP] = { + .type = ALC_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + /* node 0x0f VREF seems controlling the master output */ + { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 }, + { } + }, + }, }; static const struct snd_pci_quirk alc861_fixup_tbl[] = { + SND_PCI_QUIRK(0x1043, 0x1393, "ASUS A6Rp", PINFIX_ASUS_A6RP), + SND_PCI_QUIRK(0x1584, 0x2b01, "Haier W18", PINFIX_ASUS_A6RP), SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505), {} }; @@ -20126,6 +20141,8 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = { .patch = patch_alc882 }, { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1", .patch = patch_alc662 }, + { .id = 0x10ec0662, .rev = 0x100300, .name = "ALC662 rev3", + .patch = patch_alc662 }, { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 }, { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 }, { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 }, diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 5c42f3e..8670682 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1602,7 +1602,7 @@ static const struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02bd, "Dell Studio 1557", STAC_DELL_M6_DMIC), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02fe, - "Dell Studio XPS 1645", STAC_DELL_M6_BOTH), + "Dell Studio XPS 1645", STAC_DELL_M6_DMIC), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0413, "Dell Studio 1558", STAC_DELL_M6_DMIC), {} /* terminator */ @@ -4162,13 +4162,15 @@ static int enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, return 1; } -static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid) +static int is_nid_out_jack_pin(struct auto_pin_cfg *cfg, hda_nid_t nid) { int i; for (i = 0; i < cfg->hp_outs; i++) if (cfg->hp_pins[i] == nid) return 1; /* nid is a HP-Out */ - + for (i = 0; i < cfg->line_outs; i++) + if (cfg->line_out_pins[i] == nid) + return 1; /* nid is a line-Out */ return 0; /* nid is not a HP-Out */ }; @@ -4354,7 +4356,7 @@ static int stac92xx_init(struct hda_codec *codec) continue; } - if (is_nid_hp_pin(cfg, nid)) + if (is_nid_out_jack_pin(cfg, nid)) continue; /* already has an unsol event */ pinctl = snd_hda_codec_read(codec, nid, 0, @@ -4587,7 +4589,7 @@ static void stac92xx_hp_detect(struct hda_codec *codec) unsigned int val = AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN; if (no_hp_sensing(spec, i)) continue; - if (presence) + if (1 /*presence*/) stac92xx_set_pinctl(codec, cfg->hp_pins[i], val); #if 0 /* FIXME */ /* Resetting the pinctl like below may lead to (a sort of) regressions @@ -5425,9 +5427,7 @@ static void stac92hd8x_fill_auto_spec(struct hda_codec *codec) static int patch_stac92hd83xxx(struct hda_codec *codec) { struct sigmatel_spec *spec; - hda_nid_t conn[STAC92HD83_DAC_COUNT + 1]; int err; - int num_dacs; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -5467,26 +5467,8 @@ again: stac92xx_set_config_regs(codec, stac92hd83xxx_brd_tbl[spec->board_config]); - switch (codec->vendor_id) { - case 0x111d76d1: - case 0x111d76d9: - case 0x111d76df: - case 0x111d76e5: - case 0x111d7666: - case 0x111d7667: - case 0x111d7668: - case 0x111d7669: - case 0x111d76e3: - case 0x111d7604: - case 0x111d76d4: - case 0x111d7605: - case 0x111d76d5: - case 0x111d76e7: - if (spec->board_config == STAC_92HD83XXX_PWR_REF) - break; + if (spec->board_config != STAC_92HD83XXX_PWR_REF) spec->num_pwrs = 0; - break; - } codec->patch_ops = stac92xx_patch_ops; @@ -5506,7 +5488,11 @@ again: } #endif - err = stac92xx_parse_auto_config(codec, 0x1d, 0); + /* 92HD65/66 series has S/PDIF-IN */ + if (codec->vendor_id >= 0x111d76e8 && codec->vendor_id <= 0x111d76f3) + err = stac92xx_parse_auto_config(codec, 0x1d, 0x22); + else + err = stac92xx_parse_auto_config(codec, 0x1d, 0); if (!err) { if (spec->board_config < 0) { printk(KERN_WARNING "hda_codec: No auto-config is " @@ -5522,22 +5508,6 @@ again: return err; } - /* docking output support */ - num_dacs = snd_hda_get_connections(codec, 0xF, - conn, STAC92HD83_DAC_COUNT + 1) - 1; - /* skip non-DAC connections */ - while (num_dacs >= 0 && - (get_wcaps_type(get_wcaps(codec, conn[num_dacs])) - != AC_WID_AUD_OUT)) - num_dacs--; - /* set port E and F to select the last DAC */ - if (num_dacs >= 0) { - snd_hda_codec_write_cache(codec, 0xE, 0, - AC_VERB_SET_CONNECT_SEL, num_dacs); - snd_hda_codec_write_cache(codec, 0xF, 0, - AC_VERB_SET_CONNECT_SEL, num_dacs); - } - codec->proc_widget_hook = stac92hd_proc_hook; return 0; @@ -6405,6 +6375,18 @@ static const struct hda_codec_preset snd_hda_preset_sigmatel[] = { { .id = 0x111d76e3, .name = "92HD98BXX", .patch = patch_stac92hd83xxx}, { .id = 0x111d76e5, .name = "92HD99BXX", .patch = patch_stac92hd83xxx}, { .id = 0x111d76e7, .name = "92HD90BXX", .patch = patch_stac92hd83xxx}, + { .id = 0x111d76e8, .name = "92HD66B1X5", .patch = patch_stac92hd83xxx}, + { .id = 0x111d76e9, .name = "92HD66B2X5", .patch = patch_stac92hd83xxx}, + { .id = 0x111d76ea, .name = "92HD66B3X5", .patch = patch_stac92hd83xxx}, + { .id = 0x111d76eb, .name = "92HD66C1X5", .patch = patch_stac92hd83xxx}, + { .id = 0x111d76ec, .name = "92HD66C2X5", .patch = patch_stac92hd83xxx}, + { .id = 0x111d76ed, .name = "92HD66C3X5", .patch = patch_stac92hd83xxx}, + { .id = 0x111d76ee, .name = "92HD66B1X3", .patch = patch_stac92hd83xxx}, + { .id = 0x111d76ef, .name = "92HD66B2X3", .patch = patch_stac92hd83xxx}, + { .id = 0x111d76f0, .name = "92HD66B3X3", .patch = patch_stac92hd83xxx}, + { .id = 0x111d76f1, .name = "92HD66C1X3", .patch = patch_stac92hd83xxx}, + { .id = 0x111d76f2, .name = "92HD66C2X3", .patch = patch_stac92hd83xxx}, + { .id = 0x111d76f3, .name = "92HD66C3/65", .patch = patch_stac92hd83xxx}, {} /* terminator */ }; diff --git a/sound/pci/ice1712/amp.c b/sound/pci/ice1712/amp.c index e328cfb..e525da2 100644 --- a/sound/pci/ice1712/amp.c +++ b/sound/pci/ice1712/amp.c @@ -68,8 +68,11 @@ static int __devinit snd_vt1724_amp_init(struct snd_ice1712 *ice) static int __devinit snd_vt1724_amp_add_controls(struct snd_ice1712 *ice) { - /* we use pins 39 and 41 of the VT1616 for left and right read outputs */ - snd_ac97_write_cache(ice->ac97, 0x5a, snd_ac97_read(ice->ac97, 0x5a) & ~0x8000); + if (ice->ac97) + /* we use pins 39 and 41 of the VT1616 for left and right + read outputs */ + snd_ac97_write_cache(ice->ac97, 0x5a, + snd_ac97_read(ice->ac97, 0x5a) & ~0x8000); return 0; } diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 6c896db..2e799a9 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -2076,6 +2076,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { }, { .subvendor = 0x161f, + .subdevice = 0x202f, + .name = "Gateway M520", + .type = AC97_TUNE_INV_EAPD + }, + { + .subvendor = 0x161f, .subdevice = 0x203a, .name = "Gateway 4525GZ", /* AD1981B */ .type = AC97_TUNE_INV_EAPD diff --git a/sound/pci/lx6464es/lx_core.c b/sound/pci/lx6464es/lx_core.c index 617f98b..713f798 100644 --- a/sound/pci/lx6464es/lx_core.c +++ b/sound/pci/lx6464es/lx_core.c @@ -80,8 +80,12 @@ unsigned long lx_dsp_reg_read(struct lx6464es *chip, int port) void lx_dsp_reg_readbuf(struct lx6464es *chip, int port, u32 *data, u32 len) { - void __iomem *address = lx_dsp_register(chip, port); - memcpy_fromio(data, address, len*sizeof(u32)); + u32 __iomem *address = lx_dsp_register(chip, port); + int i; + + /* we cannot use memcpy_fromio */ + for (i = 0; i != len; ++i) + data[i] = ioread32(address + i); } @@ -94,8 +98,12 @@ void lx_dsp_reg_write(struct lx6464es *chip, int port, unsigned data) void lx_dsp_reg_writebuf(struct lx6464es *chip, int port, const u32 *data, u32 len) { - void __iomem *address = lx_dsp_register(chip, port); - memcpy_toio(address, data, len*sizeof(u32)); + u32 __iomem *address = lx_dsp_register(chip, port); + int i; + + /* we cannot use memcpy_to */ + for (i = 0; i != len; ++i) + iowrite32(data[i], address + i); } diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index 42d1ab1..915546a 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c @@ -177,6 +177,7 @@ static void wm8776_registers_init(struct oxygen *chip) struct xonar_wm87x6 *data = chip->model_data; wm8776_write(chip, WM8776_RESET, 0); + wm8776_write(chip, WM8776_PHASESWAP, WM8776_PH_MASK); wm8776_write(chip, WM8776_DACCTRL1, WM8776_DZCEN | WM8776_PL_LEFT_LEFT | WM8776_PL_RIGHT_RIGHT); wm8776_write(chip, WM8776_DACMUTE, chip->dac_mute ? WM8776_DMUTE : 0); diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c index 2b5c7a95..5fe840b 100644 --- a/sound/pci/sis7019.c +++ b/sound/pci/sis7019.c @@ -41,6 +41,7 @@ MODULE_SUPPORTED_DEVICE("{{SiS,SiS7019 Audio Accelerator}}"); static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ static int enable = 1; +static int codecs = 1; module_param(index, int, 0444); MODULE_PARM_DESC(index, "Index value for SiS7019 Audio Accelerator."); @@ -48,6 +49,8 @@ module_param(id, charp, 0444); MODULE_PARM_DESC(id, "ID string for SiS7019 Audio Accelerator."); module_param(enable, bool, 0444); MODULE_PARM_DESC(enable, "Enable SiS7019 Audio Accelerator."); +module_param(codecs, int, 0444); +MODULE_PARM_DESC(codecs, "Set bit to indicate that codec number is expected to be present (default 1)"); static DEFINE_PCI_DEVICE_TABLE(snd_sis7019_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x7019) }, @@ -140,6 +143,9 @@ struct sis7019 { dma_addr_t silence_dma_addr; }; +/* These values are also used by the module param 'codecs' to indicate + * which codecs should be present. + */ #define SIS_PRIMARY_CODEC_PRESENT 0x0001 #define SIS_SECONDARY_CODEC_PRESENT 0x0002 #define SIS_TERTIARY_CODEC_PRESENT 0x0004 @@ -1078,6 +1084,7 @@ static int sis_chip_init(struct sis7019 *sis) { unsigned long io = sis->ioport; void __iomem *ioaddr = sis->ioaddr; + unsigned long timeout; u16 status; int count; int i; @@ -1104,21 +1111,45 @@ static int sis_chip_init(struct sis7019 *sis) while ((inw(io + SIS_AC97_STATUS) & SIS_AC97_STATUS_BUSY) && --count) udelay(1); + /* Command complete, we can let go of the semaphore now. + */ + outl(SIS_AC97_SEMA_RELEASE, io + SIS_AC97_SEMA); + if (!count) + return -EIO; + /* Now that we've finished the reset, find out what's attached. + * There are some codec/board combinations that take an extremely + * long time to come up. 350+ ms has been observed in the field, + * so we'll give them up to 500ms. */ - status = inl(io + SIS_AC97_STATUS); - if (status & SIS_AC97_STATUS_CODEC_READY) - sis->codecs_present |= SIS_PRIMARY_CODEC_PRESENT; - if (status & SIS_AC97_STATUS_CODEC2_READY) - sis->codecs_present |= SIS_SECONDARY_CODEC_PRESENT; - if (status & SIS_AC97_STATUS_CODEC3_READY) - sis->codecs_present |= SIS_TERTIARY_CODEC_PRESENT; - - /* All done, let go of the semaphore, and check for errors + sis->codecs_present = 0; + timeout = msecs_to_jiffies(500) + jiffies; + while (time_before_eq(jiffies, timeout)) { + status = inl(io + SIS_AC97_STATUS); + if (status & SIS_AC97_STATUS_CODEC_READY) + sis->codecs_present |= SIS_PRIMARY_CODEC_PRESENT; + if (status & SIS_AC97_STATUS_CODEC2_READY) + sis->codecs_present |= SIS_SECONDARY_CODEC_PRESENT; + if (status & SIS_AC97_STATUS_CODEC3_READY) + sis->codecs_present |= SIS_TERTIARY_CODEC_PRESENT; + + if (sis->codecs_present == codecs) + break; + + msleep(1); + } + + /* All done, check for errors. */ - outl(SIS_AC97_SEMA_RELEASE, io + SIS_AC97_SEMA); - if (!sis->codecs_present || !count) + if (!sis->codecs_present) { + printk(KERN_ERR "sis7019: could not find any codecs\n"); return -EIO; + } + + if (sis->codecs_present != codecs) { + printk(KERN_WARNING "sis7019: missing codecs, found %0x, expected %0x\n", + sis->codecs_present, codecs); + } /* Let the hardware know that the audio driver is alive, * and enable PCM slots on the AC-link for L/R playback (3 & 4) and @@ -1390,6 +1421,17 @@ static int __devinit snd_sis7019_probe(struct pci_dev *pci, if (!enable) goto error_out; + /* The user can specify which codecs should be present so that we + * can wait for them to show up if they are slow to recover from + * the AC97 cold reset. We default to a single codec, the primary. + * + * We assume that SIS_PRIMARY_*_PRESENT matches bits 0-2. + */ + codecs &= SIS_PRIMARY_CODEC_PRESENT | SIS_SECONDARY_CODEC_PRESENT | + SIS_TERTIARY_CODEC_PRESENT; + if (!codecs) + codecs = SIS_PRIMARY_CODEC_PRESENT; + rc = snd_card_create(index, id, THIS_MODULE, sizeof(*sis), &card); if (rc < 0) goto error_out; diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index e1a214e..65abd09 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c @@ -40,11 +40,11 @@ struct ak4535_priv { /* * ak4535 register cache */ -static const u16 ak4535_reg[AK4535_CACHEREGNUM] = { - 0x0000, 0x0080, 0x0000, 0x0003, - 0x0002, 0x0000, 0x0011, 0x0001, - 0x0000, 0x0040, 0x0036, 0x0010, - 0x0000, 0x0000, 0x0057, 0x0000, +static const u8 ak4535_reg[AK4535_CACHEREGNUM] = { + 0x00, 0x80, 0x00, 0x03, + 0x02, 0x00, 0x11, 0x01, + 0x00, 0x40, 0x36, 0x10, + 0x00, 0x00, 0x57, 0x00, }; /* diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 65f4604..7d45197 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -143,7 +143,7 @@ * min : 0xFE : -115.0 dB * mute: 0xFF */ -static const DECLARE_TLV_DB_SCALE(out_tlv, -11500, 50, 1); +static const DECLARE_TLV_DB_SCALE(out_tlv, -11550, 50, 1); static const struct snd_kcontrol_new ak4642_snd_controls[] = { @@ -162,17 +162,17 @@ struct ak4642_priv { /* * ak4642 register cache */ -static const u16 ak4642_reg[AK4642_CACHEREGNUM] = { - 0x0000, 0x0000, 0x0001, 0x0000, - 0x0002, 0x0000, 0x0000, 0x0000, - 0x00e1, 0x00e1, 0x0018, 0x0000, - 0x00e1, 0x0018, 0x0011, 0x0008, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, +static const u8 ak4642_reg[AK4642_CACHEREGNUM] = { + 0x00, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x00, 0x00, + 0xe1, 0xe1, 0x18, 0x00, + 0xe1, 0x18, 0x11, 0x08, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, }; /* diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index a537e4a..1dae5c4 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c @@ -150,7 +150,7 @@ static int wm8711_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_codec *codec = dai->codec; struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec); - u16 iface = snd_soc_read(codec, WM8711_IFACE) & 0xfffc; + u16 iface = snd_soc_read(codec, WM8711_IFACE) & 0xfff3; int i = get_coeff(wm8711->sysclk, params_rate(params)); u16 srate = (coeff_div[i].sr << 2) | (coeff_div[i].bosr << 1) | coeff_div[i].usb; @@ -231,7 +231,7 @@ static int wm8711_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; - u16 iface = 0; + u16 iface = snd_soc_read(codec, WM8711_IFACE) & 0x000c; /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 76b4361..f5a0ec4 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -463,6 +463,7 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec, snd_soc_write(codec, WM8731_PWR, 0xffff); regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); + codec->cache_sync = 1; break; } codec->dapm.bias_level = level; diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c index 25af901..c173aee 100644 --- a/sound/soc/codecs/wm8741.c +++ b/sound/soc/codecs/wm8741.c @@ -337,10 +337,10 @@ static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai, iface |= 0x0004; break; case SND_SOC_DAIFMT_DSP_A: - iface |= 0x0003; + iface |= 0x000C; break; case SND_SOC_DAIFMT_DSP_B: - iface |= 0x0013; + iface |= 0x001C; break; default: return -EINVAL; diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index aa091a0..66d18a3 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -189,6 +189,9 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol, struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); u16 ioctl; + if (wm8753->dai_func == ucontrol->value.integer.value[0]) + return 0; + if (codec->active) return -EBUSY; diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 9b3bba4..0fce199 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -868,7 +868,7 @@ SOC_ENUM("Right Capture Mode", rin_mode), SOC_DOUBLE_R("Capture Volume", WM8904_ANALOGUE_LEFT_INPUT_0, WM8904_ANALOGUE_RIGHT_INPUT_0, 0, 31, 0), SOC_DOUBLE_R("Capture Switch", WM8904_ANALOGUE_LEFT_INPUT_0, - WM8904_ANALOGUE_RIGHT_INPUT_0, 7, 1, 0), + WM8904_ANALOGUE_RIGHT_INPUT_0, 7, 1, 1), SOC_SINGLE("High Pass Filter Switch", WM8904_ADC_DIGITAL_0, 4, 1, 0), SOC_ENUM("High Pass Filter Mode", hpf_mode), diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index 25580e3..d4ecb3f 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -472,6 +472,8 @@ static int wm8940_set_bias_level(struct snd_soc_codec *codec, break; } + codec->dapm.bias_level = level; + return ret; } diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 5e05eed..c850e3d 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -1957,7 +1957,13 @@ static int wm8962_readable_register(struct snd_soc_codec *codec, unsigned int re static int wm8962_reset(struct snd_soc_codec *codec) { - return snd_soc_write(codec, WM8962_SOFTWARE_RESET, 0x6243); + int ret; + + ret = snd_soc_write(codec, WM8962_SOFTWARE_RESET, 0x6243); + if (ret != 0) + return ret; + + return snd_soc_write(codec, WM8962_PLL_SOFTWARE_RESET, 0); } static const DECLARE_TLV_DB_SCALE(inpga_tlv, -2325, 75, 0); @@ -2018,7 +2024,6 @@ static int wm8962_put_spk_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - u16 *reg_cache = codec->reg_cache; int ret; /* Apply the update (if any) */ @@ -2027,16 +2032,19 @@ static int wm8962_put_spk_sw(struct snd_kcontrol *kcontrol, return 0; /* If the left PGA is enabled hit that VU bit... */ - if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_SPKOUTL_PGA_ENA) - return snd_soc_write(codec, WM8962_SPKOUTL_VOLUME, - reg_cache[WM8962_SPKOUTL_VOLUME]); + ret = snd_soc_read(codec, WM8962_PWR_MGMT_2); + if (ret & WM8962_SPKOUTL_PGA_ENA) { + snd_soc_write(codec, WM8962_SPKOUTL_VOLUME, + snd_soc_read(codec, WM8962_SPKOUTL_VOLUME)); + return 1; + } /* ...otherwise the right. The VU is stereo. */ - if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_SPKOUTR_PGA_ENA) - return snd_soc_write(codec, WM8962_SPKOUTR_VOLUME, - reg_cache[WM8962_SPKOUTR_VOLUME]); + if (ret & WM8962_SPKOUTR_PGA_ENA) + snd_soc_write(codec, WM8962_SPKOUTR_VOLUME, + snd_soc_read(codec, WM8962_SPKOUTR_VOLUME)); - return 0; + return 1; } static const char *cap_hpf_mode_text[] = { @@ -2336,7 +2344,6 @@ static int out_pga_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; - u16 *reg_cache = codec->reg_cache; int reg; switch (w->shift) { @@ -2359,14 +2366,14 @@ static int out_pga_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_POST_PMU: - return snd_soc_write(codec, reg, reg_cache[reg]); + return snd_soc_write(codec, reg, snd_soc_read(codec, reg)); default: BUG(); return -EINVAL; } } -static const char *st_text[] = { "None", "Right", "Left" }; +static const char *st_text[] = { "None", "Left", "Right" }; static const struct soc_enum str_enum = SOC_ENUM_SINGLE(WM8962_DAC_DSP_MIXING_1, 2, 3, st_text); @@ -2968,13 +2975,13 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream, case SNDRV_PCM_FORMAT_S16_LE: break; case SNDRV_PCM_FORMAT_S20_3LE: - aif0 |= 0x40; + aif0 |= 0x4; break; case SNDRV_PCM_FORMAT_S24_LE: - aif0 |= 0x80; + aif0 |= 0x8; break; case SNDRV_PCM_FORMAT_S32_LE: - aif0 |= 0xc0; + aif0 |= 0xc; break; default: return -EINVAL; @@ -3027,9 +3034,9 @@ static int wm8962_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) int aif0 = 0; switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_DSP_A: - aif0 |= WM8962_LRCLK_INV; case SND_SOC_DAIFMT_DSP_B: + aif0 |= WM8962_LRCLK_INV | 3; + case SND_SOC_DAIFMT_DSP_A: aif0 |= 3; switch (fmt & SND_SOC_DAIFMT_INV_MASK) { @@ -3822,6 +3829,11 @@ static int wm8962_probe(struct snd_soc_codec *codec) */ snd_soc_update_bits(codec, WM8962_CLOCKING2, WM8962_SYSCLK_ENA, 0); + /* Ensure that the oscillator and PLLs are disabled */ + snd_soc_update_bits(codec, WM8962_PLL2, + WM8962_OSC_ENA | WM8962_PLL2_ENA | WM8962_PLL3_ENA, + 0); + regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), wm8962->supplies); if (pdata) { diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 83014a7..2194912 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -56,7 +56,7 @@ static int wm8994_retune_mobile_base[] = { static int wm8994_readable(struct snd_soc_codec *codec, unsigned int reg) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - struct wm8994 *control = wm8994->control_data; + struct wm8994 *control = codec->control_data; switch (reg) { case WM8994_GPIO_1: @@ -1266,7 +1266,7 @@ SND_SOC_DAPM_MUX("AIF2DAC Mux", SND_SOC_NOPM, 0, 0, &aif2dac_mux), SND_SOC_DAPM_MUX("AIF2ADC Mux", SND_SOC_NOPM, 0, 0, &aif2adc_mux), SND_SOC_DAPM_AIF_IN("AIF3DACDAT", "AIF3 Playback", 0, SND_SOC_NOPM, 0, 0), -SND_SOC_DAPM_AIF_IN("AIF3ADCDAT", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_OUT("AIF3ADCDAT", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_SUPPLY("TOCLK", WM8994_CLOCKING_1, 4, 0, NULL, 0), diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 9e370d1..8712a9f 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -562,14 +562,14 @@ SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER1, 0, 1, 0), }; static const struct snd_kcontrol_new line2_mix[] = { -SOC_DAPM_SINGLE("IN2R Switch", WM8993_LINE_MIXER2, 2, 1, 0), -SOC_DAPM_SINGLE("IN2L Switch", WM8993_LINE_MIXER2, 1, 1, 0), +SOC_DAPM_SINGLE("IN1L Switch", WM8993_LINE_MIXER2, 2, 1, 0), +SOC_DAPM_SINGLE("IN1R Switch", WM8993_LINE_MIXER2, 1, 1, 0), SOC_DAPM_SINGLE("Output Switch", WM8993_LINE_MIXER2, 0, 1, 0), }; static const struct snd_kcontrol_new line2n_mix[] = { -SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER2, 6, 1, 0), -SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 5, 1, 0), +SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER2, 5, 1, 0), +SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 6, 1, 0), }; static const struct snd_kcontrol_new line2p_mix[] = { @@ -589,6 +589,8 @@ SND_SOC_DAPM_INPUT("IN2RP:VXRP"), SND_SOC_DAPM_MICBIAS("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0), SND_SOC_DAPM_MICBIAS("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0), +SND_SOC_DAPM_SUPPLY("LINEOUT_VMID_BUF", WM8993_ANTIPOP1, 7, 0, NULL, 0), + SND_SOC_DAPM_MIXER("IN1L PGA", WM8993_POWER_MANAGEMENT_2, 6, 0, in1l_pga, ARRAY_SIZE(in1l_pga)), SND_SOC_DAPM_MIXER("IN1R PGA", WM8993_POWER_MANAGEMENT_2, 4, 0, @@ -794,9 +796,11 @@ static const struct snd_soc_dapm_route lineout1_diff_routes[] = { }; static const struct snd_soc_dapm_route lineout1_se_routes[] = { + { "LINEOUT1N Mixer", NULL, "LINEOUT_VMID_BUF" }, { "LINEOUT1N Mixer", "Left Output Switch", "Left Output PGA" }, { "LINEOUT1N Mixer", "Right Output Switch", "Right Output PGA" }, + { "LINEOUT1P Mixer", NULL, "LINEOUT_VMID_BUF" }, { "LINEOUT1P Mixer", "Left Output Switch", "Left Output PGA" }, { "LINEOUT1N Driver", NULL, "LINEOUT1N Mixer" }, @@ -804,8 +808,8 @@ static const struct snd_soc_dapm_route lineout1_se_routes[] = { }; static const struct snd_soc_dapm_route lineout2_diff_routes[] = { - { "LINEOUT2 Mixer", "IN2L Switch", "IN2L PGA" }, - { "LINEOUT2 Mixer", "IN2R Switch", "IN2R PGA" }, + { "LINEOUT2 Mixer", "IN1L Switch", "IN1L PGA" }, + { "LINEOUT2 Mixer", "IN1R Switch", "IN1R PGA" }, { "LINEOUT2 Mixer", "Output Switch", "Right Output PGA" }, { "LINEOUT2N Driver", NULL, "LINEOUT2 Mixer" }, @@ -813,9 +817,11 @@ static const struct snd_soc_dapm_route lineout2_diff_routes[] = { }; static const struct snd_soc_dapm_route lineout2_se_routes[] = { + { "LINEOUT2N Mixer", NULL, "LINEOUT_VMID_BUF" }, { "LINEOUT2N Mixer", "Left Output Switch", "Left Output PGA" }, { "LINEOUT2N Mixer", "Right Output Switch", "Right Output PGA" }, + { "LINEOUT2P Mixer", NULL, "LINEOUT_VMID_BUF" }, { "LINEOUT2P Mixer", "Right Output Switch", "Right Output PGA" }, { "LINEOUT2N Driver", NULL, "LINEOUT2N Mixer" }, diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 313e0cc..bd811a0 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -698,6 +698,7 @@ static int __devinit fsl_ssi_probe(struct platform_device *pdev) /* Initialize the the device_attribute structure */ dev_attr = &ssi_private->dev_attr; + sysfs_attr_init(&dev_attr->attr); dev_attr->attr.name = "statistics"; dev_attr->attr.mode = S_IRUGO; dev_attr->show = fsl_sysfs_ssi_show; diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c index 61fceb0..3b56254 100644 --- a/sound/soc/imx/imx-ssi.c +++ b/sound/soc/imx/imx-ssi.c @@ -112,7 +112,7 @@ static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) break; case SND_SOC_DAIFMT_DSP_A: /* data on rising edge of bclk, frame high 1clk before data */ - strcr |= SSI_STCR_TFSL | SSI_STCR_TEFS; + strcr |= SSI_STCR_TFSL | SSI_STCR_TXBIT0 | SSI_STCR_TEFS; break; } diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 8ad93ee..b583e60 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -668,6 +668,38 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, return 0; } +static void pxa_ssp_set_running_bit(struct snd_pcm_substream *substream, + struct ssp_device *ssp, int value) +{ + uint32_t sscr0 = pxa_ssp_read_reg(ssp, SSCR0); + uint32_t sscr1 = pxa_ssp_read_reg(ssp, SSCR1); + uint32_t sspsp = pxa_ssp_read_reg(ssp, SSPSP); + uint32_t sssr = pxa_ssp_read_reg(ssp, SSSR); + + if (value && (sscr0 & SSCR0_SSE)) + pxa_ssp_write_reg(ssp, SSCR0, sscr0 & ~SSCR0_SSE); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (value) + sscr1 |= SSCR1_TSRE; + else + sscr1 &= ~SSCR1_TSRE; + } else { + if (value) + sscr1 |= SSCR1_RSRE; + else + sscr1 &= ~SSCR1_RSRE; + } + + pxa_ssp_write_reg(ssp, SSCR1, sscr1); + + if (value) { + pxa_ssp_write_reg(ssp, SSSR, sssr); + pxa_ssp_write_reg(ssp, SSPSP, sspsp); + pxa_ssp_write_reg(ssp, SSCR0, sscr0 | SSCR0_SSE); + } +} + static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *cpu_dai) { @@ -681,42 +713,21 @@ static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd, pxa_ssp_enable(ssp); break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - val = pxa_ssp_read_reg(ssp, SSCR1); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - val |= SSCR1_TSRE; - else - val |= SSCR1_RSRE; - pxa_ssp_write_reg(ssp, SSCR1, val); + pxa_ssp_set_running_bit(substream, ssp, 1); val = pxa_ssp_read_reg(ssp, SSSR); pxa_ssp_write_reg(ssp, SSSR, val); break; case SNDRV_PCM_TRIGGER_START: - val = pxa_ssp_read_reg(ssp, SSCR1); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - val |= SSCR1_TSRE; - else - val |= SSCR1_RSRE; - pxa_ssp_write_reg(ssp, SSCR1, val); - pxa_ssp_enable(ssp); + pxa_ssp_set_running_bit(substream, ssp, 1); break; case SNDRV_PCM_TRIGGER_STOP: - val = pxa_ssp_read_reg(ssp, SSCR1); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - val &= ~SSCR1_TSRE; - else - val &= ~SSCR1_RSRE; - pxa_ssp_write_reg(ssp, SSCR1, val); + pxa_ssp_set_running_bit(substream, ssp, 0); break; case SNDRV_PCM_TRIGGER_SUSPEND: pxa_ssp_disable(ssp); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - val = pxa_ssp_read_reg(ssp, SSCR1); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - val &= ~SSCR1_TSRE; - else - val &= ~SSCR1_RSRE; - pxa_ssp_write_reg(ssp, SSCR1, val); + pxa_ssp_set_running_bit(substream, ssp, 0); break; default: diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c index 16152ed..c1290da 100644 --- a/sound/soc/samsung/neo1973_wm8753.c +++ b/sound/soc/samsung/neo1973_wm8753.c @@ -425,7 +425,7 @@ static struct snd_soc_dai_link neo1973_dai[] = { .platform_name = "samsung-audio", .cpu_dai_name = "s3c24xx-iis", .codec_dai_name = "wm8753-hifi", - .codec_name = "wm8753-codec.0-001a", + .codec_name = "wm8753.0-001a", .init = neo1973_wm8753_init, .ops = &neo1973_hifi_ops, }, @@ -434,7 +434,7 @@ static struct snd_soc_dai_link neo1973_dai[] = { .stream_name = "Voice", .cpu_dai_name = "dfbmcs320-pcm", .codec_dai_name = "wm8753-voice", - .codec_name = "wm8753-codec.0-001a", + .codec_name = "wm8753.0-001a", .ops = &neo1973_voice_ops, }, }; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 493ae7c..e2bfe1d 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -30,6 +30,7 @@ #include <linux/bitops.h> #include <linux/debugfs.h> #include <linux/platform_device.h> +#include <linux/ctype.h> #include <linux/slab.h> #include <sound/ac97_codec.h> #include <sound/core.h> @@ -1931,9 +1932,20 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) "%s", card->name); snprintf(card->snd_card->longname, sizeof(card->snd_card->longname), "%s", card->long_name ? card->long_name : card->name); - if (card->driver_name) - strlcpy(card->snd_card->driver, card->driver_name, - sizeof(card->snd_card->driver)); + snprintf(card->snd_card->driver, sizeof(card->snd_card->driver), + "%s", card->driver_name ? card->driver_name : card->name); + for (i = 0; i < ARRAY_SIZE(card->snd_card->driver); i++) { + switch (card->snd_card->driver[i]) { + case '_': + case '-': + case '\0': + break; + default: + if (!isalnum(card->snd_card->driver[i])) + card->snd_card->driver[i] = '_'; + break; + } + } if (card->late_probe) { ret = card->late_probe(card); diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 32ab7fc..058c0a8 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2615,9 +2615,13 @@ static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm) * standby. */ if (powerdown) { - snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_PREPARE); + if (dapm->bias_level == SND_SOC_BIAS_ON) + snd_soc_dapm_set_bias_level(dapm, + SND_SOC_BIAS_PREPARE); dapm_seq_run(dapm, &down_list, 0, false); - snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_STANDBY); + if (dapm->bias_level == SND_SOC_BIAS_PREPARE) + snd_soc_dapm_set_bias_level(dapm, + SND_SOC_BIAS_STANDBY); } } @@ -2630,7 +2634,9 @@ void snd_soc_dapm_shutdown(struct snd_soc_card *card) list_for_each_entry(codec, &card->codec_dev_list, list) { soc_dapm_shutdown_codec(&codec->dapm); - snd_soc_dapm_set_bias_level(&codec->dapm, SND_SOC_BIAS_OFF); + if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) + snd_soc_dapm_set_bias_level(&codec->dapm, + SND_SOC_BIAS_OFF); } } diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index ec921ec..cd987de 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -57,7 +57,36 @@ int snd_soc_params_to_bclk(struct snd_pcm_hw_params *params) } EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk); -static struct snd_soc_platform_driver dummy_platform; +static const struct snd_pcm_hardware dummy_dma_hardware = { + .formats = 0xffffffff, + .channels_min = 1, + .channels_max = UINT_MAX, + + /* Random values to keep userspace happy when checking constraints */ + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER, + .buffer_bytes_max = 128*1024, + .period_bytes_min = PAGE_SIZE, + .period_bytes_max = PAGE_SIZE*2, + .periods_min = 2, + .periods_max = 128, +}; + +static int dummy_dma_open(struct snd_pcm_substream *substream) +{ + snd_soc_set_runtime_hwparams(substream, &dummy_dma_hardware); + + return 0; +} + +static struct snd_pcm_ops dummy_dma_ops = { + .open = dummy_dma_open, + .ioctl = snd_pcm_lib_ioctl, +}; + +static struct snd_soc_platform_driver dummy_platform = { + .ops = &dummy_dma_ops, +}; static __devinit int snd_soc_dummy_probe(struct platform_device *pdev) { diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c index fb5d68f..96c381e 100644 --- a/sound/usb/misc/ua101.c +++ b/sound/usb/misc/ua101.c @@ -459,7 +459,8 @@ static void kill_stream_urbs(struct ua101_stream *stream) unsigned int i; for (i = 0; i < stream->queue_length; ++i) - usb_kill_urb(&stream->urbs[i]->urb); + if (stream->urbs[i]) + usb_kill_urb(&stream->urbs[i]->urb); } static int enable_iso_interface(struct ua101 *ua, unsigned int intf_index) @@ -484,6 +485,9 @@ static void disable_iso_interface(struct ua101 *ua, unsigned int intf_index) { struct usb_host_interface *alts; + if (!ua->intf[intf_index]) + return; + alts = ua->intf[intf_index]->cur_altsetting; if (alts->desc.bAlternateSetting != 0) { int err = usb_set_interface(ua->dev, @@ -1144,27 +1148,37 @@ static void free_stream_urbs(struct ua101_stream *stream) { unsigned int i; - for (i = 0; i < stream->queue_length; ++i) + for (i = 0; i < stream->queue_length; ++i) { kfree(stream->urbs[i]); + stream->urbs[i] = NULL; + } } static void free_usb_related_resources(struct ua101 *ua, struct usb_interface *interface) { unsigned int i; + struct usb_interface *intf; + mutex_lock(&ua->mutex); free_stream_urbs(&ua->capture); free_stream_urbs(&ua->playback); + mutex_unlock(&ua->mutex); free_stream_buffers(ua, &ua->capture); free_stream_buffers(ua, &ua->playback); - for (i = 0; i < ARRAY_SIZE(ua->intf); ++i) - if (ua->intf[i]) { - usb_set_intfdata(ua->intf[i], NULL); - if (ua->intf[i] != interface) + for (i = 0; i < ARRAY_SIZE(ua->intf); ++i) { + mutex_lock(&ua->mutex); + intf = ua->intf[i]; + ua->intf[i] = NULL; + mutex_unlock(&ua->mutex); + if (intf) { + usb_set_intfdata(intf, NULL); + if (intf != interface) usb_driver_release_interface(&ua101_driver, - ua->intf[i]); + intf); } + } } static void ua101_card_free(struct snd_card *card) diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index cdd19d7..0de7cbd 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -765,10 +765,60 @@ static void usb_mixer_elem_free(struct snd_kcontrol *kctl) * interface to ALSA control for feature/mixer units */ +/* volume control quirks */ +static void volume_control_quirks(struct usb_mixer_elem_info *cval, + struct snd_kcontrol *kctl) +{ + switch (cval->mixer->chip->usb_id) { + case USB_ID(0x0471, 0x0101): + case USB_ID(0x0471, 0x0104): + case USB_ID(0x0471, 0x0105): + case USB_ID(0x0672, 0x1041): + /* quirk for UDA1321/N101. + * note that detection between firmware 2.1.1.7 (N101) + * and later 2.1.1.21 is not very clear from datasheets. + * I hope that the min value is -15360 for newer firmware --jk + */ + if (!strcmp(kctl->id.name, "PCM Playback Volume") && + cval->min == -15616) { + snd_printk(KERN_INFO + "set volume quirk for UDA1321/N101 chip\n"); + cval->max = -256; + } + break; + + case USB_ID(0x046d, 0x09a4): + if (!strcmp(kctl->id.name, "Mic Capture Volume")) { + snd_printk(KERN_INFO + "set volume quirk for QuickCam E3500\n"); + cval->min = 6080; + cval->max = 8768; + cval->res = 192; + } + break; + + case USB_ID(0x046d, 0x0808): + case USB_ID(0x046d, 0x0809): + case USB_ID(0x046d, 0x0991): + /* Most audio usb devices lie about volume resolution. + * Most Logitech webcams have res = 384. + * Proboly there is some logitech magic behind this number --fishor + */ + if (!strcmp(kctl->id.name, "Mic Capture Volume")) { + snd_printk(KERN_INFO + "set resolution quirk: cval->res = 384\n"); + cval->res = 384; + } + break; + + } +} + /* * retrieve the minimum and maximum values for the specified control */ -static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) +static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval, + int default_min, struct snd_kcontrol *kctl) { /* for failsafe */ cval->min = default_min; @@ -844,6 +894,9 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) cval->initialized = 1; } + if (kctl) + volume_control_quirks(cval, kctl); + /* USB descriptions contain the dB scale in 1/256 dB unit * while ALSA TLV contains in 1/100 dB unit */ @@ -864,6 +917,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) return 0; } +#define get_min_max(cval, def) get_min_max_with_quirks(cval, def, NULL) /* get a feature/mixer unit info */ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) @@ -881,8 +935,17 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol, struct snd_ctl_ uinfo->value.integer.min = 0; uinfo->value.integer.max = 1; } else { - if (! cval->initialized) - get_min_max(cval, 0); + if (!cval->initialized) { + get_min_max_with_quirks(cval, 0, kcontrol); + if (cval->initialized && cval->dBmin >= cval->dBmax) { + kcontrol->vd[0].access &= + ~(SNDRV_CTL_ELEM_ACCESS_TLV_READ | + SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK); + snd_ctl_notify(cval->mixer->chip->card, + SNDRV_CTL_EVENT_MASK_INFO, + &kcontrol->id); + } + } uinfo->value.integer.min = 0; uinfo->value.integer.max = (cval->max - cval->min + cval->res - 1) / cval->res; @@ -1036,9 +1099,6 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, cval->ch_readonly = readonly_mask; } - /* get min/max values */ - get_min_max(cval, 0); - /* if all channels in the mask are marked read-only, make the control * read-only. set_cur_mix_value() will check the mask again and won't * issue write commands to read-only channels. */ @@ -1060,6 +1120,9 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, len = snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name)); + /* get min/max values */ + get_min_max_with_quirks(cval, 0, kctl); + switch (control) { case UAC_FU_MUTE: case UAC_FU_VOLUME: @@ -1109,51 +1172,6 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, break; } - /* volume control quirks */ - switch (state->chip->usb_id) { - case USB_ID(0x0471, 0x0101): - case USB_ID(0x0471, 0x0104): - case USB_ID(0x0471, 0x0105): - case USB_ID(0x0672, 0x1041): - /* quirk for UDA1321/N101. - * note that detection between firmware 2.1.1.7 (N101) - * and later 2.1.1.21 is not very clear from datasheets. - * I hope that the min value is -15360 for newer firmware --jk - */ - if (!strcmp(kctl->id.name, "PCM Playback Volume") && - cval->min == -15616) { - snd_printk(KERN_INFO - "set volume quirk for UDA1321/N101 chip\n"); - cval->max = -256; - } - break; - - case USB_ID(0x046d, 0x09a4): - if (!strcmp(kctl->id.name, "Mic Capture Volume")) { - snd_printk(KERN_INFO - "set volume quirk for QuickCam E3500\n"); - cval->min = 6080; - cval->max = 8768; - cval->res = 192; - } - break; - - case USB_ID(0x046d, 0x0808): - case USB_ID(0x046d, 0x0809): - case USB_ID(0x046d, 0x0991): - /* Most audio usb devices lie about volume resolution. - * Most Logitech webcams have res = 384. - * Proboly there is some logitech magic behind this number --fishor - */ - if (!strcmp(kctl->id.name, "Mic Capture Volume")) { - snd_printk(KERN_INFO - "set resolution quirk: cval->res = 384\n"); - cval->res = 384; - } - break; - - } - range = (cval->max - cval->min) / cval->res; /* Are there devices with volume range more than 255? I use a bit more * to be sure. 384 is a resolution magic number found on Logitech diff --git a/sound/usb/usx2y/usb_stream.c b/sound/usb/usx2y/usb_stream.c index c400ade..1e7a47a 100644 --- a/sound/usb/usx2y/usb_stream.c +++ b/sound/usb/usx2y/usb_stream.c @@ -674,7 +674,7 @@ dotry: inurb->transfer_buffer_length = inurb->number_of_packets * inurb->iso_frame_desc[0].length; - preempt_disable(); + if (u == 0) { int now; struct usb_device *dev = inurb->dev; @@ -686,19 +686,17 @@ dotry: } err = usb_submit_urb(inurb, GFP_ATOMIC); if (err < 0) { - preempt_enable(); snd_printk(KERN_ERR"usb_submit_urb(sk->inurb[%i])" " returned %i\n", u, err); return err; } err = usb_submit_urb(outurb, GFP_ATOMIC); if (err < 0) { - preempt_enable(); snd_printk(KERN_ERR"usb_submit_urb(sk->outurb[%i])" " returned %i\n", u, err); return err; } - preempt_enable(); + if (inurb->start_frame != outurb->start_frame) { snd_printd(KERN_DEBUG "u[%i] start_frames differ in:%u out:%u\n", |