summaryrefslogtreecommitdiffstats
path: root/sound/pci/hda
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/hda_codec.c14
-rw-r--r--sound/pci/hda/hda_intel.c47
-rw-r--r--sound/pci/hda/patch_analog.c10
-rw-r--r--sound/pci/hda/patch_conexant.c21
-rw-r--r--sound/pci/hda/patch_realtek.c10
-rw-r--r--sound/pci/hda/patch_sigmatel.c57
6 files changed, 120 insertions, 39 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index a4e5e59..8820faf 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -642,19 +642,21 @@ static int get_codec_name(struct hda_codec *codec)
*/
static void /*__devinit*/ setup_fg_nodes(struct hda_codec *codec)
{
- int i, total_nodes;
+ int i, total_nodes, function_id;
hda_nid_t nid;
total_nodes = snd_hda_get_sub_nodes(codec, AC_NODE_ROOT, &nid);
for (i = 0; i < total_nodes; i++, nid++) {
- codec->function_id = snd_hda_param_read(codec, nid,
+ function_id = snd_hda_param_read(codec, nid,
AC_PAR_FUNCTION_TYPE) & 0xff;
- switch (codec->function_id) {
+ switch (function_id) {
case AC_GRP_AUDIO_FUNCTION:
codec->afg = nid;
+ codec->function_id = function_id;
break;
case AC_GRP_MODEM_FUNCTION:
codec->mfg = nid;
+ codec->function_id = function_id;
break;
default:
break;
@@ -2250,7 +2252,11 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
err = bus->ops.command(bus, res);
if (!err) {
struct hda_cache_head *c;
- u32 key = build_cmd_cache_key(nid, verb);
+ u32 key;
+ /* parm may contain the verb stuff for get/set amp */
+ verb = verb | (parm >> 8);
+ parm &= 0xff;
+ key = build_cmd_cache_key(nid, verb);
c = get_alloc_hash(&codec->cmd_cache, key);
if (c)
c->val = parm;
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 30829ee..21e99cf 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -312,6 +312,8 @@ struct azx_dev {
unsigned int period_bytes; /* size of the period in bytes */
unsigned int frags; /* number for period in the play buffer */
unsigned int fifo_size; /* FIFO size */
+ unsigned long start_jiffies; /* start + minimum jiffies */
+ unsigned long min_jiffies; /* minimum jiffies before position is valid */
void __iomem *sd_addr; /* stream descriptor pointer */
@@ -330,7 +332,7 @@ struct azx_dev {
unsigned int opened :1;
unsigned int running :1;
unsigned int irq_pending :1;
- unsigned int irq_ignore :1;
+ unsigned int start_flag: 1; /* stream full start flag */
/*
* For VIA:
* A flag to ensure DMA position is 0
@@ -975,7 +977,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
struct azx *chip = dev_id;
struct azx_dev *azx_dev;
u32 status;
- int i;
+ int i, ok;
spin_lock(&chip->reg_lock);
@@ -991,18 +993,14 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);
if (!azx_dev->substream || !azx_dev->running)
continue;
- /* ignore the first dummy IRQ (due to pos_adj) */
- if (azx_dev->irq_ignore) {
- azx_dev->irq_ignore = 0;
- continue;
- }
/* check whether this IRQ is really acceptable */
- if (azx_position_ok(chip, azx_dev)) {
+ ok = azx_position_ok(chip, azx_dev);
+ if (ok == 1) {
azx_dev->irq_pending = 0;
spin_unlock(&chip->reg_lock);
snd_pcm_period_elapsed(azx_dev->substream);
spin_lock(&chip->reg_lock);
- } else if (chip->bus && chip->bus->workq) {
+ } else if (ok == 0 && chip->bus && chip->bus->workq) {
/* bogus IRQ, process it later */
azx_dev->irq_pending = 1;
queue_work(chip->bus->workq,
@@ -1088,7 +1086,6 @@ static int azx_setup_periods(struct azx *chip,
bdl = (u32 *)azx_dev->bdl.area;
ofs = 0;
azx_dev->frags = 0;
- azx_dev->irq_ignore = 0;
pos_adj = bdl_pos_adj[chip->dev_index];
if (pos_adj > 0) {
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -1109,7 +1106,6 @@ static int azx_setup_periods(struct azx *chip,
&bdl, ofs, pos_adj, 1);
if (ofs < 0)
goto error;
- azx_dev->irq_ignore = 1;
}
} else
pos_adj = 0;
@@ -1155,6 +1151,9 @@ static void azx_stream_reset(struct azx *chip, struct azx_dev *azx_dev)
while (((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) &&
--timeout)
;
+
+ /* reset first position - may not be synced with hw at this time */
+ *azx_dev->posbuf = 0;
}
/*
@@ -1409,7 +1408,6 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
snd_pcm_set_sync(substream);
mutex_unlock(&chip->open_mutex);
- azx_stream_reset(chip, azx_dev);
return 0;
}
@@ -1474,6 +1472,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
unsigned int bufsize, period_bytes, format_val;
int err;
+ azx_stream_reset(chip, azx_dev);
format_val = snd_hda_calc_stream_format(runtime->rate,
runtime->channels,
runtime->format,
@@ -1502,6 +1501,8 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
return err;
}
+ azx_dev->min_jiffies = (runtime->period_size * HZ) /
+ (runtime->rate * 2);
azx_setup_controller(chip, azx_dev);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1;
@@ -1518,13 +1519,14 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
struct azx *chip = apcm->chip;
struct azx_dev *azx_dev;
struct snd_pcm_substream *s;
- int start, nsync = 0, sbits = 0;
+ int rstart = 0, start, nsync = 0, sbits = 0;
int nwait, timeout;
switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ rstart = 1;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_START:
start = 1;
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
@@ -1554,6 +1556,10 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
if (s->pcm->card != substream->pcm->card)
continue;
azx_dev = get_azx_dev(s);
+ if (rstart) {
+ azx_dev->start_flag = 1;
+ azx_dev->start_jiffies = jiffies + azx_dev->min_jiffies;
+ }
if (start)
azx_stream_start(chip, azx_dev);
else
@@ -1703,6 +1709,11 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
{
unsigned int pos;
+ if (azx_dev->start_flag &&
+ time_before_eq(jiffies, azx_dev->start_jiffies))
+ return -1; /* bogus (too early) interrupt */
+ azx_dev->start_flag = 0;
+
pos = azx_get_position(chip, azx_dev);
if (chip->position_fix == POS_FIX_AUTO) {
if (!pos) {
@@ -2260,11 +2271,11 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
gcap &= ~0x01;
/* allow 64bit DMA address if supported by H/W */
- if ((gcap & 0x01) && !pci_set_dma_mask(pci, DMA_64BIT_MASK))
- pci_set_consistent_dma_mask(pci, DMA_64BIT_MASK);
+ if ((gcap & 0x01) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64)))
+ pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64));
else {
- pci_set_dma_mask(pci, DMA_32BIT_MASK);
- pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK);
+ pci_set_dma_mask(pci, DMA_BIT_MASK(32));
+ pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32));
}
/* read number of streams from GCAP register instead of using
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 5bb48ee..9bcd8ab 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -3256,7 +3256,7 @@ static const char *ad1884_slave_vols[] = {
"Mic Playback Volume",
"CD Playback Volume",
"Internal Mic Playback Volume",
- "Docking Mic Playback Volume"
+ "Docking Mic Playback Volume",
/* "Beep Playback Volume", */
"IEC958 Playback Volume",
NULL
@@ -3977,6 +3977,14 @@ static int patch_ad1884a(struct hda_codec *codec)
spec->input_mux = &ad1884a_laptop_capture_source;
codec->patch_ops.unsol_event = ad1884a_hp_unsol_event;
codec->patch_ops.init = ad1884a_hp_init;
+ /* set the upper-limit for mixer amp to 0dB for avoiding the
+ * possible damage by overloading
+ */
+ snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
+ (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
+ (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
+ (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+ (1 << AC_AMPCAP_MUTE_SHIFT));
break;
case AD1884A_MOBILE:
spec->mixers[0] = ad1884a_mobile_mixers;
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 1f2ad76..56ce19e 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -350,12 +350,20 @@ static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol,
}
#ifdef CONFIG_SND_JACK
+static void conexant_free_jack_priv(struct snd_jack *jack)
+{
+ struct conexant_jack *jacks = jack->private_data;
+ jacks->nid = 0;
+ jacks->jack = NULL;
+}
+
static int conexant_add_jack(struct hda_codec *codec,
hda_nid_t nid, int type)
{
struct conexant_spec *spec;
struct conexant_jack *jack;
const char *name;
+ int err;
spec = codec->spec;
snd_array_init(&spec->jacks, sizeof(*jack), 32);
@@ -368,7 +376,12 @@ static int conexant_add_jack(struct hda_codec *codec,
jack->nid = nid;
jack->type = type;
- return snd_jack_new(codec->bus->card, name, type, &jack->jack);
+ err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
+ if (err < 0)
+ return err;
+ jack->jack->private_data = jack;
+ jack->jack->private_free = conexant_free_jack_priv;
+ return 0;
}
static void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid)
@@ -455,8 +468,10 @@ static void conexant_free(struct hda_codec *codec)
if (spec->jacks.list) {
struct conexant_jack *jacks = spec->jacks.list;
int i;
- for (i = 0; i < spec->jacks.used; i++)
- snd_device_free(codec->bus->card, &jacks[i].jack);
+ for (i = 0; i < spec->jacks.used; i++, jacks++) {
+ if (jacks->jack)
+ snd_device_free(codec->bus->card, jacks->jack);
+ }
snd_array_free(&spec->jacks);
}
#endif
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 8209779..6ed787e 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -8742,10 +8742,9 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
- SND_PCI_QUIRK(0x1734, 0x1107, "FSC AMILO Xi2550",
+ SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx",
ALC883_FUJITSU_PI2515),
- SND_PCI_QUIRK(0x1734, 0x1108, "Fujitsu AMILO Pi2515", ALC883_FUJITSU_PI2515),
- SND_PCI_QUIRK(0x1734, 0x113d, "Fujitsu AMILO Xa3530",
+ SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx",
ALC888_FUJITSU_XA3530),
SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
@@ -8764,6 +8763,10 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
{}
};
+static hda_nid_t alc883_slave_dig_outs[] = {
+ ALC1200_DIGOUT_NID, 0,
+};
+
static hda_nid_t alc1200_slave_dig_outs[] = {
ALC883_DIGOUT_NID, 0,
};
@@ -8809,6 +8812,7 @@ static struct alc_config_preset alc883_presets[] = {
.dac_nids = alc883_dac_nids,
.dig_out_nid = ALC883_DIGOUT_NID,
.dig_in_nid = ALC883_DIGIN_NID,
+ .slave_dig_outs = alc883_slave_dig_outs,
.num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
.channel_mode = alc883_3ST_6ch_intel_modes,
.need_dac_fix = 1,
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index b5e108a..917bc5d 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -3076,6 +3076,11 @@ static int create_multi_out_ctls(struct hda_codec *codec, int num_outs,
unsigned int wid_caps;
for (i = 0; i < num_outs && i < ARRAY_SIZE(chname); i++) {
+ if (type == AUTO_PIN_HP_OUT && !spec->hp_detect) {
+ wid_caps = get_wcaps(codec, pins[i]);
+ if (wid_caps & AC_WCAP_UNSOL_CAP)
+ spec->hp_detect = 1;
+ }
nid = dac_nids[i];
if (!nid)
continue;
@@ -3119,11 +3124,6 @@ static int create_multi_out_ctls(struct hda_codec *codec, int num_outs,
err = create_controls_idx(codec, name, idx, nid, 3);
if (err < 0)
return err;
- if (type == AUTO_PIN_HP_OUT && !spec->hp_detect) {
- wid_caps = get_wcaps(codec, pins[i]);
- if (wid_caps & AC_WCAP_UNSOL_CAP)
- spec->hp_detect = 1;
- }
}
}
return 0;
@@ -3851,6 +3851,15 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
}
+#ifdef CONFIG_SND_JACK
+static void stac92xx_free_jack_priv(struct snd_jack *jack)
+{
+ struct sigmatel_jack *jacks = jack->private_data;
+ jacks->nid = 0;
+ jacks->jack = NULL;
+}
+#endif
+
static int stac92xx_add_jack(struct hda_codec *codec,
hda_nid_t nid, int type)
{
@@ -3860,6 +3869,7 @@ static int stac92xx_add_jack(struct hda_codec *codec,
int def_conf = snd_hda_codec_get_pincfg(codec, nid);
int connectivity = get_defcfg_connect(def_conf);
char name[32];
+ int err;
if (connectivity && connectivity != AC_JACK_PORT_FIXED)
return 0;
@@ -3876,10 +3886,15 @@ static int stac92xx_add_jack(struct hda_codec *codec,
snd_hda_get_jack_connectivity(def_conf),
snd_hda_get_jack_location(def_conf));
- return snd_jack_new(codec->bus->card, name, type, &jack->jack);
-#else
- return 0;
+ err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
+ if (err < 0) {
+ jack->nid = 0;
+ return err;
+ }
+ jack->jack->private_data = jack;
+ jack->jack->private_free = stac92xx_free_jack_priv;
#endif
+ return 0;
}
static int stac_add_event(struct sigmatel_spec *spec, hda_nid_t nid,
@@ -4138,8 +4153,10 @@ static void stac92xx_free_jacks(struct hda_codec *codec)
if (!codec->bus->shutdown && spec->jacks.list) {
struct sigmatel_jack *jacks = spec->jacks.list;
int i;
- for (i = 0; i < spec->jacks.used; i++)
- snd_device_free(codec->bus->card, &jacks[i].jack);
+ for (i = 0; i < spec->jacks.used; i++, jacks++) {
+ if (jacks->jack)
+ snd_device_free(codec->bus->card, jacks->jack);
+ }
}
snd_array_free(&spec->jacks);
#endif
@@ -4413,6 +4430,24 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
if (spec->num_pwrs > 0)
stac92xx_pin_sense(codec, event->nid);
stac92xx_report_jack(codec, event->nid);
+
+ switch (codec->subsystem_id) {
+ case 0x103c308f:
+ if (event->nid == 0xb) {
+ int pin = AC_PINCTL_IN_EN;
+
+ if (get_pin_presence(codec, 0xa)
+ && get_pin_presence(codec, 0xb))
+ pin |= AC_PINCTL_VREF_80;
+ if (!get_pin_presence(codec, 0xb))
+ pin |= AC_PINCTL_VREF_80;
+
+ /* toggle VREF state based on mic + hp pin
+ * status
+ */
+ stac92xx_auto_set_pinctl(codec, 0x0a, pin);
+ }
+ }
break;
case STAC_VREF_EVENT:
data = snd_hda_codec_read(codec, codec->afg, 0,
@@ -4895,6 +4930,7 @@ again:
switch (codec->vendor_id) {
case 0x111d7604:
case 0x111d7605:
+ case 0x111d76d5:
if (spec->board_config == STAC_92HD83XXX_PWR_REF)
break;
spec->num_pwrs = 0;
@@ -5707,6 +5743,7 @@ static struct hda_codec_preset snd_hda_preset_sigmatel[] = {
{ .id = 0x111d7603, .name = "92HD75B3X5", .patch = patch_stac92hd71bxx},
{ .id = 0x111d7604, .name = "92HD83C1X5", .patch = patch_stac92hd83xxx},
{ .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx},
+ { .id = 0x111d76d5, .name = "92HD81B1C5", .patch = patch_stac92hd83xxx},
{ .id = 0x111d7608, .name = "92HD75B2X5", .patch = patch_stac92hd71bxx},
{ .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx },
{ .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx },
OpenPOWER on IntegriCloud