diff options
Diffstat (limited to 'sound')
| -rw-r--r-- | sound/core/control.c | 2 | ||||
| -rw-r--r-- | sound/core/oss/pcm_oss.c | 10 | ||||
| -rw-r--r-- | sound/core/seq/seq_clientmgr.c | 26 | ||||
| -rw-r--r-- | sound/core/seq/seq_fifo.c | 2 | ||||
| -rw-r--r-- | sound/core/seq/seq_memory.c | 14 | ||||
| -rw-r--r-- | sound/core/seq/seq_memory.h | 3 | ||||
| -rw-r--r-- | sound/core/seq/seq_prioq.c | 28 | ||||
| -rw-r--r-- | sound/core/seq/seq_prioq.h | 6 | ||||
| -rw-r--r-- | sound/core/seq/seq_queue.c | 28 | ||||
| -rw-r--r-- | sound/pci/hda/hda_intel.c | 39 | ||||
| -rw-r--r-- | sound/pci/hda/patch_conexant.c | 2 | ||||
| -rw-r--r-- | sound/pci/hda/patch_realtek.c | 48 | ||||
| -rw-r--r-- | sound/soc/amd/acp-pcm-dma.c | 16 | ||||
| -rw-r--r-- | sound/soc/amd/acp.h | 2 | ||||
| -rw-r--r-- | sound/soc/codecs/hdmi-codec.c | 7 | ||||
| -rw-r--r-- | sound/soc/codecs/rt5651.c | 1 | ||||
| -rw-r--r-- | sound/soc/codecs/sgtl5000.c | 26 | ||||
| -rw-r--r-- | sound/soc/codecs/wm_adsp.c | 14 | ||||
| -rw-r--r-- | sound/soc/sunxi/sun4i-i2s.c | 2 | ||||
| -rw-r--r-- | sound/usb/quirks-table.h | 47 | ||||
| -rw-r--r-- | sound/x86/intel_hdmi_audio.c | 37 | 
21 files changed, 266 insertions, 94 deletions
| diff --git a/sound/core/control.c b/sound/core/control.c index 0b3026d937b1..8a77620a3854 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -889,7 +889,7 @@ static int snd_ctl_elem_read(struct snd_card *card,  	index_offset = snd_ctl_get_ioff(kctl, &control->id);  	vd = &kctl->vd[index_offset]; -	if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) && kctl->get == NULL) +	if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) || kctl->get == NULL)  		return -EPERM;  	snd_ctl_build_ioff(&control->id, kctl, index_offset); diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index b044c0a5a674..02298c9c6020 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -1762,10 +1762,9 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)  		return -ENOMEM;  	_snd_pcm_hw_params_any(params);  	err = snd_pcm_hw_refine(substream, params); -	format_mask = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT); -	kfree(params);  	if (err < 0) -		return err; +		goto error; +	format_mask = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);  	for (fmt = 0; fmt < 32; ++fmt) {  		if (snd_mask_test(format_mask, fmt)) {  			int f = snd_pcm_oss_format_to(fmt); @@ -1773,7 +1772,10 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)  				formats |= f;  		}  	} -	return formats; + + error: +	kfree(params); +	return err < 0 ? err : formats;  }  static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int format) diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 04d4db44fae5..61a07fe34cd2 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -255,12 +255,12 @@ static int seq_free_client1(struct snd_seq_client *client)  	if (!client)  		return 0; -	snd_seq_delete_all_ports(client); -	snd_seq_queue_client_leave(client->number);  	spin_lock_irqsave(&clients_lock, flags);  	clienttablock[client->number] = 1;  	clienttab[client->number] = NULL;  	spin_unlock_irqrestore(&clients_lock, flags); +	snd_seq_delete_all_ports(client); +	snd_seq_queue_client_leave(client->number);  	snd_use_lock_sync(&client->use_lock);  	snd_seq_queue_client_termination(client->number);  	if (client->pool) @@ -910,7 +910,8 @@ int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop)  static int snd_seq_client_enqueue_event(struct snd_seq_client *client,  					struct snd_seq_event *event,  					struct file *file, int blocking, -					int atomic, int hop) +					int atomic, int hop, +					struct mutex *mutexp)  {  	struct snd_seq_event_cell *cell;  	int err; @@ -948,7 +949,8 @@ static int snd_seq_client_enqueue_event(struct snd_seq_client *client,  		return -ENXIO; /* queue is not allocated */  	/* allocate an event cell */ -	err = snd_seq_event_dup(client->pool, event, &cell, !blocking || atomic, file); +	err = snd_seq_event_dup(client->pool, event, &cell, !blocking || atomic, +				file, mutexp);  	if (err < 0)  		return err; @@ -1017,12 +1019,11 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf,  		return -ENXIO;  	/* allocate the pool now if the pool is not allocated yet */  +	mutex_lock(&client->ioctl_mutex);  	if (client->pool->size > 0 && !snd_seq_write_pool_allocated(client)) { -		mutex_lock(&client->ioctl_mutex);  		err = snd_seq_pool_init(client->pool); -		mutex_unlock(&client->ioctl_mutex);  		if (err < 0) -			return -ENOMEM; +			goto out;  	}  	/* only process whole events */ @@ -1073,7 +1074,7 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf,  		/* ok, enqueue it */  		err = snd_seq_client_enqueue_event(client, &event, file,  						   !(file->f_flags & O_NONBLOCK), -						   0, 0); +						   0, 0, &client->ioctl_mutex);  		if (err < 0)  			break; @@ -1084,6 +1085,8 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf,  		written += len;  	} + out: +	mutex_unlock(&client->ioctl_mutex);  	return written ? written : err;  } @@ -1838,9 +1841,11 @@ static int snd_seq_ioctl_set_client_pool(struct snd_seq_client *client,  	    (! snd_seq_write_pool_allocated(client) ||  	     info->output_pool != client->pool->size)) {  		if (snd_seq_write_pool_allocated(client)) { +			/* is the pool in use? */ +			if (atomic_read(&client->pool->counter)) +				return -EBUSY;  			/* remove all existing cells */  			snd_seq_pool_mark_closing(client->pool); -			snd_seq_queue_client_leave_cells(client->number);  			snd_seq_pool_done(client->pool);  		}  		client->pool->size = info->output_pool; @@ -2260,7 +2265,8 @@ static int kernel_client_enqueue(int client, struct snd_seq_event *ev,  	if (! cptr->accept_output)  		result = -EPERM;  	else /* send it */ -		result = snd_seq_client_enqueue_event(cptr, ev, file, blocking, atomic, hop); +		result = snd_seq_client_enqueue_event(cptr, ev, file, blocking, +						      atomic, hop, NULL);  	snd_seq_client_unlock(cptr);  	return result; diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c index a8c2822e0198..72c0302a55d2 100644 --- a/sound/core/seq/seq_fifo.c +++ b/sound/core/seq/seq_fifo.c @@ -125,7 +125,7 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f,  		return -EINVAL;  	snd_use_lock_use(&f->use_lock); -	err = snd_seq_event_dup(f->pool, event, &cell, 1, NULL); /* always non-blocking */ +	err = snd_seq_event_dup(f->pool, event, &cell, 1, NULL, NULL); /* always non-blocking */  	if (err < 0) {  		if ((err == -ENOMEM) || (err == -EAGAIN))  			atomic_inc(&f->overflow); diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c index f763682584a8..ab1112e90f88 100644 --- a/sound/core/seq/seq_memory.c +++ b/sound/core/seq/seq_memory.c @@ -220,7 +220,8 @@ void snd_seq_cell_free(struct snd_seq_event_cell * cell)   */  static int snd_seq_cell_alloc(struct snd_seq_pool *pool,  			      struct snd_seq_event_cell **cellp, -			      int nonblock, struct file *file) +			      int nonblock, struct file *file, +			      struct mutex *mutexp)  {  	struct snd_seq_event_cell *cell;  	unsigned long flags; @@ -244,7 +245,11 @@ static int snd_seq_cell_alloc(struct snd_seq_pool *pool,  		set_current_state(TASK_INTERRUPTIBLE);  		add_wait_queue(&pool->output_sleep, &wait);  		spin_unlock_irq(&pool->lock); +		if (mutexp) +			mutex_unlock(mutexp);  		schedule(); +		if (mutexp) +			mutex_lock(mutexp);  		spin_lock_irq(&pool->lock);  		remove_wait_queue(&pool->output_sleep, &wait);  		/* interrupted? */ @@ -287,7 +292,7 @@ __error:   */  int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event,  		      struct snd_seq_event_cell **cellp, int nonblock, -		      struct file *file) +		      struct file *file, struct mutex *mutexp)  {  	int ncells, err;  	unsigned int extlen; @@ -304,7 +309,7 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event,  	if (ncells >= pool->total_elements)  		return -ENOMEM; -	err = snd_seq_cell_alloc(pool, &cell, nonblock, file); +	err = snd_seq_cell_alloc(pool, &cell, nonblock, file, mutexp);  	if (err < 0)  		return err; @@ -330,7 +335,8 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event,  			int size = sizeof(struct snd_seq_event);  			if (len < size)  				size = len; -			err = snd_seq_cell_alloc(pool, &tmp, nonblock, file); +			err = snd_seq_cell_alloc(pool, &tmp, nonblock, file, +						 mutexp);  			if (err < 0)  				goto __error;  			if (cell->event.data.ext.ptr == NULL) diff --git a/sound/core/seq/seq_memory.h b/sound/core/seq/seq_memory.h index 32f959c17786..3abe306c394a 100644 --- a/sound/core/seq/seq_memory.h +++ b/sound/core/seq/seq_memory.h @@ -66,7 +66,8 @@ struct snd_seq_pool {  void snd_seq_cell_free(struct snd_seq_event_cell *cell);  int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event, -		      struct snd_seq_event_cell **cellp, int nonblock, struct file *file); +		      struct snd_seq_event_cell **cellp, int nonblock, +		      struct file *file, struct mutex *mutexp);  /* return number of unused (free) cells */  static inline int snd_seq_unused_cells(struct snd_seq_pool *pool) diff --git a/sound/core/seq/seq_prioq.c b/sound/core/seq/seq_prioq.c index bc1c8488fc2a..2bc6759e4adc 100644 --- a/sound/core/seq/seq_prioq.c +++ b/sound/core/seq/seq_prioq.c @@ -87,7 +87,7 @@ void snd_seq_prioq_delete(struct snd_seq_prioq **fifo)  	if (f->cells > 0) {  		/* drain prioQ */  		while (f->cells > 0) -			snd_seq_cell_free(snd_seq_prioq_cell_out(f)); +			snd_seq_cell_free(snd_seq_prioq_cell_out(f, NULL));  	}  	kfree(f); @@ -214,8 +214,18 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,  	return 0;  } +/* return 1 if the current time >= event timestamp */ +static int event_is_ready(struct snd_seq_event *ev, void *current_time) +{ +	if ((ev->flags & SNDRV_SEQ_TIME_STAMP_MASK) == SNDRV_SEQ_TIME_STAMP_TICK) +		return snd_seq_compare_tick_time(current_time, &ev->time.tick); +	else +		return snd_seq_compare_real_time(current_time, &ev->time.time); +} +  /* dequeue cell from prioq */ -struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f) +struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f, +						  void *current_time)  {  	struct snd_seq_event_cell *cell;  	unsigned long flags; @@ -227,6 +237,8 @@ struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f)  	spin_lock_irqsave(&f->lock, flags);  	cell = f->head; +	if (cell && current_time && !event_is_ready(&cell->event, current_time)) +		cell = NULL;  	if (cell) {  		f->head = cell->next; @@ -252,18 +264,6 @@ int snd_seq_prioq_avail(struct snd_seq_prioq * f)  	return f->cells;  } - -/* peek at cell at the head of the prioq */ -struct snd_seq_event_cell *snd_seq_prioq_cell_peek(struct snd_seq_prioq * f) -{ -	if (f == NULL) { -		pr_debug("ALSA: seq: snd_seq_prioq_cell_in() called with NULL prioq\n"); -		return NULL; -	} -	return f->head; -} - -  static inline int prioq_match(struct snd_seq_event_cell *cell,  			      int client, int timestamp)  { diff --git a/sound/core/seq/seq_prioq.h b/sound/core/seq/seq_prioq.h index d38bb78d9345..2c315ca10fc4 100644 --- a/sound/core/seq/seq_prioq.h +++ b/sound/core/seq/seq_prioq.h @@ -44,14 +44,12 @@ void snd_seq_prioq_delete(struct snd_seq_prioq **fifo);  int snd_seq_prioq_cell_in(struct snd_seq_prioq *f, struct snd_seq_event_cell *cell);  /* dequeue cell from prioq */  -struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f); +struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f, +						  void *current_time);  /* return number of events available in prioq */  int snd_seq_prioq_avail(struct snd_seq_prioq *f); -/* peek at cell at the head of the prioq */ -struct snd_seq_event_cell *snd_seq_prioq_cell_peek(struct snd_seq_prioq *f); -  /* client left queue */  void snd_seq_prioq_leave(struct snd_seq_prioq *f, int client, int timestamp);         diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c index 0428e9061b47..b377f5048352 100644 --- a/sound/core/seq/seq_queue.c +++ b/sound/core/seq/seq_queue.c @@ -277,30 +277,20 @@ void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop)        __again:  	/* Process tick queue... */ -	while ((cell = snd_seq_prioq_cell_peek(q->tickq)) != NULL) { -		if (snd_seq_compare_tick_time(&q->timer->tick.cur_tick, -					      &cell->event.time.tick)) { -			cell = snd_seq_prioq_cell_out(q->tickq); -			if (cell) -				snd_seq_dispatch_event(cell, atomic, hop); -		} else { -			/* event remains in the queue */ +	for (;;) { +		cell = snd_seq_prioq_cell_out(q->tickq, +					      &q->timer->tick.cur_tick); +		if (!cell)  			break; -		} +		snd_seq_dispatch_event(cell, atomic, hop);  	} -  	/* Process time queue... */ -	while ((cell = snd_seq_prioq_cell_peek(q->timeq)) != NULL) { -		if (snd_seq_compare_real_time(&q->timer->cur_time, -					      &cell->event.time.time)) { -			cell = snd_seq_prioq_cell_out(q->timeq); -			if (cell) -				snd_seq_dispatch_event(cell, atomic, hop); -		} else { -			/* event remains in the queue */ +	for (;;) { +		cell = snd_seq_prioq_cell_out(q->timeq, &q->timer->cur_time); +		if (!cell)  			break; -		} +		snd_seq_dispatch_event(cell, atomic, hop);  	}  	/* free lock */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index c71dcacea807..d5017adf9feb 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -186,6 +186,10 @@ module_param(power_save, xint, 0644);  MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "  		 "(in second, 0 = disable)."); +static bool pm_blacklist = true; +module_param(pm_blacklist, bool, 0644); +MODULE_PARM_DESC(pm_blacklist, "Enable power-management blacklist"); +  /* reset the HD-audio controller in power save mode.   * this may give more power-saving, but will take longer time to   * wake up. @@ -2186,6 +2190,24 @@ out_free:  	return err;  } +#ifdef CONFIG_PM +/* On some boards setting power_save to a non 0 value leads to clicking / + * popping sounds when ever we enter/leave powersaving mode. Ideally we would + * figure out how to avoid these sounds, but that is not always feasible. + * So we keep a list of devices where we disable powersaving as its known + * to causes problems on these devices. + */ +static struct snd_pci_quirk power_save_blacklist[] = { +	/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */ +	SND_PCI_QUIRK(0x1849, 0x0c0c, "Asrock B85M-ITX", 0), +	/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */ +	SND_PCI_QUIRK(0x1043, 0x8733, "Asus Prime X370-Pro", 0), +	/* https://bugzilla.kernel.org/show_bug.cgi?id=198611 */ +	SND_PCI_QUIRK(0x17aa, 0x2227, "Lenovo X1 Carbon 3rd Gen", 0), +	{} +}; +#endif /* CONFIG_PM */ +  /* number of codec slots for each chipset: 0 = default slots (i.e. 4) */  static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] = {  	[AZX_DRIVER_NVIDIA] = 8, @@ -2198,6 +2220,7 @@ static int azx_probe_continue(struct azx *chip)  	struct hdac_bus *bus = azx_bus(chip);  	struct pci_dev *pci = chip->pci;  	int dev = chip->dev_index; +	int val;  	int err;  	hda->probe_continued = 1; @@ -2278,7 +2301,21 @@ static int azx_probe_continue(struct azx *chip)  	chip->running = 1;  	azx_add_card_list(chip); -	snd_hda_set_power_save(&chip->bus, power_save * 1000); + +	val = power_save; +#ifdef CONFIG_PM +	if (pm_blacklist) { +		const struct snd_pci_quirk *q; + +		q = snd_pci_quirk_lookup(chip->pci, power_save_blacklist); +		if (q && val) { +			dev_info(chip->card->dev, "device %04x:%04x is on the power_save blacklist, forcing power_save to 0\n", +				 q->subvendor, q->subdevice); +			val = 0; +		} +	} +#endif /* CONFIG_PM */ +	snd_hda_set_power_save(&chip->bus, val * 1000);  	if (azx_has_pm_runtime(chip) || hda->use_vga_switcheroo)  		pm_runtime_put_autosuspend(&pci->dev); diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 37e1cf8218ff..5b4dbcec6de8 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -957,6 +957,8 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {  	SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_ASPIRE_DMIC),  	SND_PCI_QUIRK(0x1025, 0x054f, "Acer Aspire 4830T", CXT_FIXUP_ASPIRE_DMIC),  	SND_PCI_QUIRK(0x103c, 0x8079, "HP EliteBook 840 G3", CXT_FIXUP_HP_DOCK), +	SND_PCI_QUIRK(0x103c, 0x807C, "HP EliteBook 820 G3", CXT_FIXUP_HP_DOCK), +	SND_PCI_QUIRK(0x103c, 0x80FD, "HP ProBook 640 G2", CXT_FIXUP_HP_DOCK),  	SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE),  	SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC),  	SND_PCI_QUIRK(0x103c, 0x814f, "HP ZBook 15u G3", CXT_FIXUP_MUTE_LED_GPIO), diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index ce28f7ce64e6..9af301c6bba2 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4997,13 +4997,14 @@ static void alc_fixup_tpt470_dock(struct hda_codec *codec,  	if (action == HDA_FIXUP_ACT_PRE_PROBE) {  		spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP; +		snd_hda_apply_pincfgs(codec, pincfgs); +	} else if (action == HDA_FIXUP_ACT_INIT) {  		/* Enable DOCK device */  		snd_hda_codec_write(codec, 0x17, 0,  			    AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0);  		/* Enable DOCK device */  		snd_hda_codec_write(codec, 0x19, 0,  			    AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0); -		snd_hda_apply_pincfgs(codec, pincfgs);  	}  } @@ -5273,6 +5274,16 @@ static void alc298_fixup_speaker_volume(struct hda_codec *codec,  	}  } +/* disable DAC3 (0x06) selection on NID 0x17 as it has no volume amp control */ +static void alc295_fixup_disable_dac3(struct hda_codec *codec, +				      const struct hda_fixup *fix, int action) +{ +	if (action == HDA_FIXUP_ACT_PRE_PROBE) { +		hda_nid_t conn[2] = { 0x02, 0x03 }; +		snd_hda_override_conn_list(codec, 0x17, 2, conn); +	} +} +  /* Hook to update amp GPIO4 for automute */  static void alc280_hp_gpio4_automute_hook(struct hda_codec *codec,  					  struct hda_jack_callback *jack) @@ -5465,6 +5476,7 @@ enum {  	ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY,  	ALC255_FIXUP_DELL_SPK_NOISE,  	ALC225_FIXUP_DELL1_MIC_NO_PRESENCE, +	ALC295_FIXUP_DISABLE_DAC3,  	ALC280_FIXUP_HP_HEADSET_MIC,  	ALC221_FIXUP_HP_FRONT_MIC,  	ALC292_FIXUP_TPT460, @@ -5479,10 +5491,12 @@ enum {  	ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE,  	ALC233_FIXUP_LENOVO_MULTI_CODECS,  	ALC294_FIXUP_LENOVO_MIC_LOCATION, +	ALC225_FIXUP_DELL_WYSE_MIC_NO_PRESENCE,  	ALC700_FIXUP_INTEL_REFERENCE,  	ALC274_FIXUP_DELL_BIND_DACS,  	ALC274_FIXUP_DELL_AIO_LINEOUT_VERB,  	ALC298_FIXUP_TPT470_DOCK, +	ALC255_FIXUP_DUMMY_LINEOUT_VERB,  };  static const struct hda_fixup alc269_fixups[] = { @@ -6197,6 +6211,10 @@ static const struct hda_fixup alc269_fixups[] = {  		.chained = true,  		.chain_id = ALC298_FIXUP_DELL_AIO_MIC_NO_PRESENCE,  	}, +	[ALC295_FIXUP_DISABLE_DAC3] = { +		.type = HDA_FIXUP_FUNC, +		.v.func = alc295_fixup_disable_dac3, +	},  	[ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER] = {  		.type = HDA_FIXUP_PINS,  		.v.pins = (const struct hda_pintbl[]) { @@ -6282,6 +6300,18 @@ static const struct hda_fixup alc269_fixups[] = {  			{ }  		},  	}, +	[ALC225_FIXUP_DELL_WYSE_MIC_NO_PRESENCE] = { +		.type = HDA_FIXUP_PINS, +		.v.pins = (const struct hda_pintbl[]) { +			{ 0x16, 0x0101102f }, /* Rear Headset HP */ +			{ 0x19, 0x02a1913c }, /* use as Front headset mic, without its own jack detect */ +			{ 0x1a, 0x01a19030 }, /* Rear Headset MIC */ +			{ 0x1b, 0x02011020 }, +			{ } +		}, +		.chained = true, +		.chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC +	},  	[ALC700_FIXUP_INTEL_REFERENCE] = {  		.type = HDA_FIXUP_VERBS,  		.v.verbs = (const struct hda_verb[]) { @@ -6318,6 +6348,15 @@ static const struct hda_fixup alc269_fixups[] = {  		.chained = true,  		.chain_id = ALC293_FIXUP_LENOVO_SPK_NOISE  	}, +	[ALC255_FIXUP_DUMMY_LINEOUT_VERB] = { +		.type = HDA_FIXUP_PINS, +		.v.pins = (const struct hda_pintbl[]) { +			{ 0x14, 0x0201101f }, +			{ } +		}, +		.chained = true, +		.chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE +	},  };  static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -6366,10 +6405,13 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {  	SND_PCI_QUIRK(0x1028, 0x0725, "Dell Inspiron 3162", ALC255_FIXUP_DELL_SPK_NOISE),  	SND_PCI_QUIRK(0x1028, 0x075b, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE),  	SND_PCI_QUIRK(0x1028, 0x075d, "Dell AIO", ALC298_FIXUP_SPK_VOLUME), +	SND_PCI_QUIRK(0x1028, 0x07b0, "Dell Precision 7520", ALC295_FIXUP_DISABLE_DAC3),  	SND_PCI_QUIRK(0x1028, 0x0798, "Dell Inspiron 17 7000 Gaming", ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER), +	SND_PCI_QUIRK(0x1028, 0x080c, "Dell WYSE", ALC225_FIXUP_DELL_WYSE_MIC_NO_PRESENCE),  	SND_PCI_QUIRK(0x1028, 0x082a, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE),  	SND_PCI_QUIRK(0x1028, 0x084b, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB),  	SND_PCI_QUIRK(0x1028, 0x084e, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB), +	SND_PCI_QUIRK(0x1028, 0x0873, "Dell Precision 3930", ALC255_FIXUP_DUMMY_LINEOUT_VERB),  	SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),  	SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),  	SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), @@ -6507,9 +6549,11 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {  	SND_PCI_QUIRK(0x17aa, 0x2245, "Thinkpad T470", ALC298_FIXUP_TPT470_DOCK),  	SND_PCI_QUIRK(0x17aa, 0x2246, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),  	SND_PCI_QUIRK(0x17aa, 0x2247, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), +	SND_PCI_QUIRK(0x17aa, 0x2249, "Thinkpad", ALC292_FIXUP_TPT460),  	SND_PCI_QUIRK(0x17aa, 0x224b, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),  	SND_PCI_QUIRK(0x17aa, 0x224c, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),  	SND_PCI_QUIRK(0x17aa, 0x224d, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), +	SND_PCI_QUIRK(0x17aa, 0x225d, "Thinkpad T480", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),  	SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),  	SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),  	SND_PCI_QUIRK(0x17aa, 0x310c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION), @@ -6871,7 +6915,7 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {  		{0x12, 0x90a60120},  		{0x14, 0x90170110},  		{0x21, 0x0321101f}), -	SND_HDA_PIN_QUIRK(0x10ec0289, 0x1028, "Dell", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE, +	SND_HDA_PIN_QUIRK(0x10ec0289, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,  		{0x12, 0xb7a60130},  		{0x14, 0x90170110},  		{0x21, 0x04211020}), diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c index c33a512283a4..9fb356db3ab2 100644 --- a/sound/soc/amd/acp-pcm-dma.c +++ b/sound/soc/amd/acp-pcm-dma.c @@ -579,13 +579,6 @@ static int acp_init(void __iomem *acp_mmio, u32 asic_type)  		for (bank = 1; bank < 48; bank++)  			acp_set_sram_bank_state(acp_mmio, bank, false);  	} - -	/* Stoney supports 16bit resolution */ -	if (asic_type == CHIP_STONEY) { -		val = acp_reg_read(acp_mmio, mmACP_I2S_16BIT_RESOLUTION_EN); -		val |= 0x03; -		acp_reg_write(val, acp_mmio, mmACP_I2S_16BIT_RESOLUTION_EN); -	}  	return 0;  } @@ -774,6 +767,7 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,  {  	int status;  	uint64_t size; +	u32 val = 0;  	struct page *pg;  	struct snd_pcm_runtime *runtime;  	struct audio_substream_data *rtd; @@ -786,6 +780,14 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,  	if (WARN_ON(!rtd))  		return -EINVAL; +	if (adata->asic_type == CHIP_STONEY) { +		val = acp_reg_read(adata->acp_mmio, mmACP_I2S_16BIT_RESOLUTION_EN); +		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) +			val |= ACP_I2S_SP_16BIT_RESOLUTION_EN; +		else +			val |= ACP_I2S_MIC_16BIT_RESOLUTION_EN; +		acp_reg_write(val, adata->acp_mmio, mmACP_I2S_16BIT_RESOLUTION_EN); +	}  	size = params_buffer_bytes(params);  	status = snd_pcm_lib_malloc_pages(substream, size);  	if (status < 0) diff --git a/sound/soc/amd/acp.h b/sound/soc/amd/acp.h index ecb458935d1e..9293f179f272 100644 --- a/sound/soc/amd/acp.h +++ b/sound/soc/amd/acp.h @@ -70,6 +70,8 @@  #define CAPTURE_END_DMA_DESCR_CH15 7  #define mmACP_I2S_16BIT_RESOLUTION_EN       0x5209 +#define ACP_I2S_MIC_16BIT_RESOLUTION_EN 0x01 +#define ACP_I2S_SP_16BIT_RESOLUTION_EN	0x02  enum acp_dma_priority_level {  	/* 0x0 Specifies the DMA channel is given normal priority */  	ACP_DMA_PRIORITY_LEVEL_NORMAL = 0x0, diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 5672e516bec3..c1830ccd3bb8 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -798,12 +798,7 @@ static int hdmi_codec_probe(struct platform_device *pdev)  static int hdmi_codec_remove(struct platform_device *pdev)  { -	struct device *dev = &pdev->dev; -	struct hdmi_codec_priv *hcp; - -	hcp = dev_get_drvdata(dev); -	kfree(hcp->chmap_info); -	snd_soc_unregister_codec(dev); +	snd_soc_unregister_codec(&pdev->dev);  	return 0;  } diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index 831b297978a4..45a73049cf64 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -1722,6 +1722,7 @@ static const struct regmap_config rt5651_regmap = {  	.num_reg_defaults = ARRAY_SIZE(rt5651_reg),  	.ranges = rt5651_ranges,  	.num_ranges = ARRAY_SIZE(rt5651_ranges), +	.use_single_rw = true,  };  #if defined(CONFIG_OF) diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index e1ab5537d27a..c5c76ab8ccf1 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -529,10 +529,15 @@ static const struct snd_kcontrol_new sgtl5000_snd_controls[] = {  static int sgtl5000_digital_mute(struct snd_soc_dai *codec_dai, int mute)  {  	struct snd_soc_codec *codec = codec_dai->codec; -	u16 adcdac_ctrl = SGTL5000_DAC_MUTE_LEFT | SGTL5000_DAC_MUTE_RIGHT; +	u16 i2s_pwr = SGTL5000_I2S_IN_POWERUP; -	snd_soc_update_bits(codec, SGTL5000_CHIP_ADCDAC_CTRL, -			adcdac_ctrl, mute ? adcdac_ctrl : 0); +	/* +	 * During 'digital mute' do not mute DAC +	 * because LINE_IN would be muted aswell. We want to mute +	 * only I2S block - this can be done by powering it off +	 */ +	snd_soc_update_bits(codec, SGTL5000_CHIP_DIG_POWER, +			i2s_pwr, mute ? 0 : i2s_pwr);  	return 0;  } @@ -871,15 +876,26 @@ static int sgtl5000_pcm_hw_params(struct snd_pcm_substream *substream,  static int sgtl5000_set_bias_level(struct snd_soc_codec *codec,  				   enum snd_soc_bias_level level)  { +	struct sgtl5000_priv *sgtl = snd_soc_codec_get_drvdata(codec); +	int ret; +  	switch (level) {  	case SND_SOC_BIAS_ON:  	case SND_SOC_BIAS_PREPARE:  	case SND_SOC_BIAS_STANDBY: +		regcache_cache_only(sgtl->regmap, false); +		ret = regcache_sync(sgtl->regmap); +		if (ret) { +			regcache_cache_only(sgtl->regmap, true); +			return ret; +		} +  		snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,  				    SGTL5000_REFTOP_POWERUP,  				    SGTL5000_REFTOP_POWERUP);  		break;  	case SND_SOC_BIAS_OFF: +		regcache_cache_only(sgtl->regmap, true);  		snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,  				    SGTL5000_REFTOP_POWERUP, 0);  		break; @@ -1237,6 +1253,10 @@ static int sgtl5000_probe(struct snd_soc_codec *codec)  	 */  	snd_soc_write(codec, SGTL5000_DAP_CTRL, 0); +	/* Unmute DAC after start */ +	snd_soc_update_bits(codec, SGTL5000_CHIP_ADCDAC_CTRL, +		SGTL5000_DAC_MUTE_LEFT | SGTL5000_DAC_MUTE_RIGHT, 0); +  	return 0;  err: diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 66e32f5d2917..989d093abda7 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -1204,12 +1204,14 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl)  		kcontrol->put = wm_coeff_put_acked;  		break;  	default: -		kcontrol->get = wm_coeff_get; -		kcontrol->put = wm_coeff_put; - -		ctl->bytes_ext.max = ctl->len; -		ctl->bytes_ext.get = wm_coeff_tlv_get; -		ctl->bytes_ext.put = wm_coeff_tlv_put; +		if (kcontrol->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { +			ctl->bytes_ext.max = ctl->len; +			ctl->bytes_ext.get = wm_coeff_tlv_get; +			ctl->bytes_ext.put = wm_coeff_tlv_put; +		} else { +			kcontrol->get = wm_coeff_get; +			kcontrol->put = wm_coeff_put; +		}  		break;  	} diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index dca1143c1150..a4aa931ebfae 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -104,7 +104,7 @@  #define SUN8I_I2S_CHAN_CFG_REG		0x30  #define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK	GENMASK(6, 4) -#define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(chan)	(chan - 1) +#define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(chan)	((chan - 1) << 4)  #define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK	GENMASK(2, 0)  #define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(chan)	(chan - 1) diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 50252046b01d..754e632a27bd 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -3325,4 +3325,51 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),  	}  }, +{ +	/* +	 * Bower's & Wilkins PX headphones only support the 48 kHz sample rate +	 * even though it advertises more. The capture interface doesn't work +	 * even on windows. +	 */ +	USB_DEVICE(0x19b5, 0x0021), +	.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { +		.ifnum = QUIRK_ANY_INTERFACE, +		.type = QUIRK_COMPOSITE, +		.data = (const struct snd_usb_audio_quirk[]) { +			{ +				.ifnum = 0, +				.type = QUIRK_AUDIO_STANDARD_MIXER, +			}, +			/* Capture */ +			{ +				.ifnum = 1, +				.type = QUIRK_IGNORE_INTERFACE, +			}, +			/* Playback */ +			{ +				.ifnum = 2, +				.type = QUIRK_AUDIO_FIXED_ENDPOINT, +				.data = &(const struct audioformat) { +					.formats = SNDRV_PCM_FMTBIT_S16_LE, +					.channels = 2, +					.iface = 2, +					.altsetting = 1, +					.altset_idx = 1, +					.attributes = UAC_EP_CS_ATTR_FILL_MAX | +						UAC_EP_CS_ATTR_SAMPLE_RATE, +					.endpoint = 0x03, +					.ep_attr = USB_ENDPOINT_XFER_ISOC, +					.rates = SNDRV_PCM_RATE_48000, +					.rate_min = 48000, +					.rate_max = 48000, +					.nr_rates = 1, +					.rate_table = (unsigned int[]) { +						48000 +					} +				} +			}, +		} +	} +}, +  #undef USB_DEVICE_VENDOR_SPEC diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index a0951505c7f5..4ed9d0c41843 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -50,6 +50,7 @@  /*standard module options for ALSA. This module supports only one card*/  static int hdmi_card_index = SNDRV_DEFAULT_IDX1;  static char *hdmi_card_id = SNDRV_DEFAULT_STR1; +static bool single_port;  module_param_named(index, hdmi_card_index, int, 0444);  MODULE_PARM_DESC(index, @@ -57,6 +58,9 @@ MODULE_PARM_DESC(index,  module_param_named(id, hdmi_card_id, charp, 0444);  MODULE_PARM_DESC(id,  		"ID string for INTEL Intel HDMI Audio controller."); +module_param(single_port, bool, 0444); +MODULE_PARM_DESC(single_port, +		"Single-port mode (for compatibility)");  /*   * ELD SA bits in the CEA Speaker Allocation data block @@ -1579,7 +1583,11 @@ static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id)  static void notify_audio_lpe(struct platform_device *pdev, int port)  {  	struct snd_intelhad_card *card_ctx = platform_get_drvdata(pdev); -	struct snd_intelhad *ctx = &card_ctx->pcm_ctx[port]; +	struct snd_intelhad *ctx; + +	ctx = &card_ctx->pcm_ctx[single_port ? 0 : port]; +	if (single_port) +		ctx->port = port;  	schedule_work(&ctx->hdmi_audio_wq);  } @@ -1743,6 +1751,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev)  {  	struct snd_card *card;  	struct snd_intelhad_card *card_ctx; +	struct snd_intelhad *ctx;  	struct snd_pcm *pcm;  	struct intel_hdmi_lpe_audio_pdata *pdata;  	int irq; @@ -1787,6 +1796,21 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev)  	platform_set_drvdata(pdev, card_ctx); +	card_ctx->num_pipes = pdata->num_pipes; +	card_ctx->num_ports = single_port ? 1 : pdata->num_ports; + +	for_each_port(card_ctx, port) { +		ctx = &card_ctx->pcm_ctx[port]; +		ctx->card_ctx = card_ctx; +		ctx->dev = card_ctx->dev; +		ctx->port = single_port ? -1 : port; +		ctx->pipe = -1; + +		spin_lock_init(&ctx->had_spinlock); +		mutex_init(&ctx->mutex); +		INIT_WORK(&ctx->hdmi_audio_wq, had_audio_wq); +	} +  	dev_dbg(&pdev->dev, "%s: mmio_start = 0x%x, mmio_end = 0x%x\n",  		__func__, (unsigned int)res_mmio->start,  		(unsigned int)res_mmio->end); @@ -1816,19 +1840,12 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev)  	init_channel_allocations();  	card_ctx->num_pipes = pdata->num_pipes; -	card_ctx->num_ports = pdata->num_ports; +	card_ctx->num_ports = single_port ? 1 : pdata->num_ports;  	for_each_port(card_ctx, port) { -		struct snd_intelhad *ctx = &card_ctx->pcm_ctx[port];  		int i; -		ctx->card_ctx = card_ctx; -		ctx->dev = card_ctx->dev; -		ctx->port = port; -		ctx->pipe = -1; - -		INIT_WORK(&ctx->hdmi_audio_wq, had_audio_wq); - +		ctx = &card_ctx->pcm_ctx[port];  		ret = snd_pcm_new(card, INTEL_HAD, port, MAX_PB_STREAMS,  				  MAX_CAP_STREAMS, &pcm);  		if (ret) | 
