diff options
| -rw-r--r-- | drivers/firmware/cirrus/cs_dsp.c | 2 | ||||
| -rw-r--r-- | sound/soc/codecs/rt5665.c | 24 | ||||
| -rw-r--r-- | sound/soc/codecs/sma1307.c | 11 | ||||
| -rw-r--r-- | sound/soc/codecs/wsa883x.c | 2 | ||||
| -rw-r--r-- | sound/soc/codecs/wsa884x.c | 2 | ||||
| -rw-r--r-- | sound/soc/fsl/imx-card.c | 4 | ||||
| -rw-r--r-- | sound/soc/qcom/qdsp6/q6apm-dai.c | 60 | ||||
| -rw-r--r-- | sound/soc/qcom/qdsp6/q6apm.c | 18 | ||||
| -rw-r--r-- | sound/soc/qcom/qdsp6/q6apm.h | 3 | ||||
| -rw-r--r-- | sound/soc/qcom/qdsp6/q6asm-dai.c | 19 | ||||
| -rw-r--r-- | sound/soc/sof/intel/hda-dsp.c | 8 | ||||
| -rw-r--r-- | sound/soc/sof/intel/hda.c | 4 | ||||
| -rw-r--r-- | sound/soc/sof/intel/hda.h | 8 | ||||
| -rw-r--r-- | sound/soc/sof/intel/ptl.c | 33 | 
14 files changed, 128 insertions, 70 deletions
| diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c index 42433c19eb30..560724ce21aa 100644 --- a/drivers/firmware/cirrus/cs_dsp.c +++ b/drivers/firmware/cirrus/cs_dsp.c @@ -1631,6 +1631,7 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,  	cs_dsp_debugfs_save_wmfwname(dsp, file); +	ret = 0;  out_fw:  	cs_dsp_buf_free(&buf_list); @@ -2338,6 +2339,7 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware  	cs_dsp_debugfs_save_binname(dsp, file); +	ret = 0;  out_fw:  	cs_dsp_buf_free(&buf_list); diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index e0d1991cffdb..bcb6d7c6f301 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -31,9 +31,7 @@  #include "rl6231.h"  #include "rt5665.h" -#define RT5665_NUM_SUPPLIES 3 - -static const char *rt5665_supply_names[RT5665_NUM_SUPPLIES] = { +static const char * const rt5665_supply_names[] = {  	"AVDD",  	"MICVDD",  	"VBAT", @@ -46,7 +44,6 @@ struct rt5665_priv {  	struct gpio_desc *gpiod_ldo1_en;  	struct gpio_desc *gpiod_reset;  	struct snd_soc_jack *hs_jack; -	struct regulator_bulk_data supplies[RT5665_NUM_SUPPLIES];  	struct delayed_work jack_detect_work;  	struct delayed_work calibrate_work;  	struct delayed_work jd_check_work; @@ -4471,8 +4468,6 @@ static void rt5665_remove(struct snd_soc_component *component)  	struct rt5665_priv *rt5665 = snd_soc_component_get_drvdata(component);  	regmap_write(rt5665->regmap, RT5665_RESET, 0); - -	regulator_bulk_disable(ARRAY_SIZE(rt5665->supplies), rt5665->supplies);  }  #ifdef CONFIG_PM @@ -4758,7 +4753,7 @@ static int rt5665_i2c_probe(struct i2c_client *i2c)  {  	struct rt5665_platform_data *pdata = dev_get_platdata(&i2c->dev);  	struct rt5665_priv *rt5665; -	int i, ret; +	int ret;  	unsigned int val;  	rt5665 = devm_kzalloc(&i2c->dev, sizeof(struct rt5665_priv), @@ -4774,24 +4769,13 @@ static int rt5665_i2c_probe(struct i2c_client *i2c)  	else  		rt5665_parse_dt(rt5665, &i2c->dev); -	for (i = 0; i < ARRAY_SIZE(rt5665->supplies); i++) -		rt5665->supplies[i].supply = rt5665_supply_names[i]; - -	ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(rt5665->supplies), -				      rt5665->supplies); +	ret = devm_regulator_bulk_get_enable(&i2c->dev, ARRAY_SIZE(rt5665_supply_names), +					     rt5665_supply_names);  	if (ret != 0) {  		dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);  		return ret;  	} -	ret = regulator_bulk_enable(ARRAY_SIZE(rt5665->supplies), -				    rt5665->supplies); -	if (ret != 0) { -		dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); -		return ret; -	} - -  	rt5665->gpiod_ldo1_en = devm_gpiod_get_optional(&i2c->dev,  							"realtek,ldo1-en",  							GPIOD_OUT_HIGH); diff --git a/sound/soc/codecs/sma1307.c b/sound/soc/codecs/sma1307.c index f5c303d4bb62..498189ab691c 100644 --- a/sound/soc/codecs/sma1307.c +++ b/sound/soc/codecs/sma1307.c @@ -1705,7 +1705,7 @@ static void sma1307_check_fault_worker(struct work_struct *work)  static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *file)  {  	const struct firmware *fw; -	int *data, size, offset, num_mode; +	int size, offset, num_mode;  	int ret;  	ret = request_firmware(&fw, file, sma1307->dev); @@ -1722,7 +1722,7 @@ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *fil  		return;  	} -	data = kzalloc(fw->size, GFP_KERNEL); +	int *data __free(kfree) = kzalloc(fw->size, GFP_KERNEL);  	if (!data) {  		release_firmware(fw);  		sma1307->set.status = false; @@ -1742,7 +1742,6 @@ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *fil  					   sma1307->set.header_size,  					   GFP_KERNEL);  	if (!sma1307->set.header) { -		kfree(data);  		sma1307->set.status = false;  		return;  	} @@ -1763,8 +1762,6 @@ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *fil  	    = devm_kzalloc(sma1307->dev,  			   sma1307->set.def_size * sizeof(int), GFP_KERNEL);  	if (!sma1307->set.def) { -		kfree(data); -		kfree(sma1307->set.header);  		sma1307->set.status = false;  		return;  	} @@ -1782,9 +1779,6 @@ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *fil  				   sma1307->set.mode_size * 2 * sizeof(int),  				   GFP_KERNEL);  		if (!sma1307->set.mode_set[i]) { -			kfree(data); -			kfree(sma1307->set.header); -			kfree(sma1307->set.def);  			for (int j = 0; j < i; j++)  				kfree(sma1307->set.mode_set[j]);  			sma1307->set.status = false; @@ -1799,7 +1793,6 @@ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *fil  		}  	} -	kfree(data);  	sma1307->set.status = true;  } diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c index d259e1d4d83d..1c9df7c061bd 100644 --- a/sound/soc/codecs/wsa883x.c +++ b/sound/soc/codecs/wsa883x.c @@ -568,7 +568,7 @@ static const struct sdw_port_config wsa883x_pconfig[WSA883X_MAX_SWR_PORTS] = {  	},  	[WSA883X_PORT_VISENSE] = {  		.num = WSA883X_PORT_VISENSE + 1, -		.ch_mask = 0x3, +		.ch_mask = 0x1,  	},  }; diff --git a/sound/soc/codecs/wsa884x.c b/sound/soc/codecs/wsa884x.c index 8051483aa1ac..daada1a2a34c 100644 --- a/sound/soc/codecs/wsa884x.c +++ b/sound/soc/codecs/wsa884x.c @@ -891,7 +891,7 @@ static const struct sdw_port_config wsa884x_pconfig[WSA884X_MAX_SWR_PORTS] = {  	},  	[WSA884X_PORT_VISENSE] = {  		.num = WSA884X_PORT_VISENSE + 1, -		.ch_mask = 0x3, +		.ch_mask = 0x1,  	},  	[WSA884X_PORT_CPS] = {  		.num = WSA884X_PORT_CPS + 1, diff --git a/sound/soc/fsl/imx-card.c b/sound/soc/fsl/imx-card.c index 905294682996..3686d468506b 100644 --- a/sound/soc/fsl/imx-card.c +++ b/sound/soc/fsl/imx-card.c @@ -772,6 +772,8 @@ static int imx_card_probe(struct platform_device *pdev)  				data->dapm_routes[i].sink =  					devm_kasprintf(&pdev->dev, GFP_KERNEL, "%d %s",  						       i + 1, "Playback"); +				if (!data->dapm_routes[i].sink) +					return -ENOMEM;  				data->dapm_routes[i].source = "CPU-Playback";  			}  		} @@ -789,6 +791,8 @@ static int imx_card_probe(struct platform_device *pdev)  				data->dapm_routes[i].source =  					devm_kasprintf(&pdev->dev, GFP_KERNEL, "%d %s",  						       i + 1, "Capture"); +				if (!data->dapm_routes[i].source) +					return -ENOMEM;  				data->dapm_routes[i].sink = "CPU-Capture";  			}  		} diff --git a/sound/soc/qcom/qdsp6/q6apm-dai.c b/sound/soc/qcom/qdsp6/q6apm-dai.c index c9404b5934c7..2cd522108221 100644 --- a/sound/soc/qcom/qdsp6/q6apm-dai.c +++ b/sound/soc/qcom/qdsp6/q6apm-dai.c @@ -24,8 +24,8 @@  #define PLAYBACK_MIN_PERIOD_SIZE	128  #define CAPTURE_MIN_NUM_PERIODS		2  #define CAPTURE_MAX_NUM_PERIODS		8 -#define CAPTURE_MAX_PERIOD_SIZE		4096 -#define CAPTURE_MIN_PERIOD_SIZE		320 +#define CAPTURE_MAX_PERIOD_SIZE		65536 +#define CAPTURE_MIN_PERIOD_SIZE		6144  #define BUFFER_BYTES_MAX (PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE)  #define BUFFER_BYTES_MIN (PLAYBACK_MIN_NUM_PERIODS * PLAYBACK_MIN_PERIOD_SIZE)  #define COMPR_PLAYBACK_MAX_FRAGMENT_SIZE (128 * 1024) @@ -64,12 +64,12 @@ struct q6apm_dai_rtd {  	phys_addr_t phys;  	unsigned int pcm_size;  	unsigned int pcm_count; -	unsigned int pos;       /* Buffer position */  	unsigned int periods;  	unsigned int bytes_sent;  	unsigned int bytes_received;  	unsigned int copied_total;  	uint16_t bits_per_sample; +	snd_pcm_uframes_t queue_ptr;  	bool next_track;  	enum stream_state state;  	struct q6apm_graph *graph; @@ -123,25 +123,16 @@ static void event_handler(uint32_t opcode, uint32_t token, void *payload, void *  {  	struct q6apm_dai_rtd *prtd = priv;  	struct snd_pcm_substream *substream = prtd->substream; -	unsigned long flags;  	switch (opcode) {  	case APM_CLIENT_EVENT_CMD_EOS_DONE:  		prtd->state = Q6APM_STREAM_STOPPED;  		break;  	case APM_CLIENT_EVENT_DATA_WRITE_DONE: -		spin_lock_irqsave(&prtd->lock, flags); -		prtd->pos += prtd->pcm_count; -		spin_unlock_irqrestore(&prtd->lock, flags);  		snd_pcm_period_elapsed(substream); -		if (prtd->state == Q6APM_STREAM_RUNNING) -			q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, 0);  		break;  	case APM_CLIENT_EVENT_DATA_READ_DONE: -		spin_lock_irqsave(&prtd->lock, flags); -		prtd->pos += prtd->pcm_count; -		spin_unlock_irqrestore(&prtd->lock, flags);  		snd_pcm_period_elapsed(substream);  		if (prtd->state == Q6APM_STREAM_RUNNING)  			q6apm_read(prtd->graph); @@ -248,7 +239,6 @@ static int q6apm_dai_prepare(struct snd_soc_component *component,  	}  	prtd->pcm_count = snd_pcm_lib_period_bytes(substream); -	prtd->pos = 0;  	/* rate and channels are sent to audio driver */  	ret = q6apm_graph_media_format_shmem(prtd->graph, &cfg);  	if (ret < 0) { @@ -294,6 +284,27 @@ static int q6apm_dai_prepare(struct snd_soc_component *component,  	return 0;  } +static int q6apm_dai_ack(struct snd_soc_component *component, struct snd_pcm_substream *substream) +{ +	struct snd_pcm_runtime *runtime = substream->runtime; +	struct q6apm_dai_rtd *prtd = runtime->private_data; +	int i, ret = 0, avail_periods; + +	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { +		avail_periods = (runtime->control->appl_ptr - prtd->queue_ptr)/runtime->period_size; +		for (i = 0; i < avail_periods; i++) { +			ret = q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, NO_TIMESTAMP); +			if (ret < 0) { +				dev_err(component->dev, "Error queuing playback buffer %d\n", ret); +				return ret; +			} +			prtd->queue_ptr += runtime->period_size; +		} +	} + +	return ret; +} +  static int q6apm_dai_trigger(struct snd_soc_component *component,  			     struct snd_pcm_substream *substream, int cmd)  { @@ -305,9 +316,6 @@ static int q6apm_dai_trigger(struct snd_soc_component *component,  	case SNDRV_PCM_TRIGGER_START:  	case SNDRV_PCM_TRIGGER_RESUME:  	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -		 /* start writing buffers for playback only as we already queued capture buffers */ -		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) -			ret = q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, 0);  		break;  	case SNDRV_PCM_TRIGGER_STOP:  		/* TODO support be handled via SoftPause Module */ @@ -377,13 +385,14 @@ static int q6apm_dai_open(struct snd_soc_component *component,  		}  	} -	ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32); +	/* setup 10ms latency to accommodate DSP restrictions */ +	ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 480);  	if (ret < 0) {  		dev_err(dev, "constraint for period bytes step ret = %d\n", ret);  		goto err;  	} -	ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32); +	ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 480);  	if (ret < 0) {  		dev_err(dev, "constraint for buffer bytes step ret = %d\n", ret);  		goto err; @@ -428,16 +437,12 @@ static snd_pcm_uframes_t q6apm_dai_pointer(struct snd_soc_component *component,  	struct snd_pcm_runtime *runtime = substream->runtime;  	struct q6apm_dai_rtd *prtd = runtime->private_data;  	snd_pcm_uframes_t ptr; -	unsigned long flags; -	spin_lock_irqsave(&prtd->lock, flags); -	if (prtd->pos == prtd->pcm_size) -		prtd->pos = 0; - -	ptr =  bytes_to_frames(runtime, prtd->pos); -	spin_unlock_irqrestore(&prtd->lock, flags); +	ptr = q6apm_get_hw_pointer(prtd->graph, substream->stream) * runtime->period_size; +	if (ptr) +		return ptr - 1; -	return ptr; +	return 0;  }  static int q6apm_dai_hw_params(struct snd_soc_component *component, @@ -652,8 +657,6 @@ static int q6apm_dai_compr_set_params(struct snd_soc_component *component,  	prtd->pcm_size = runtime->fragments * runtime->fragment_size;  	prtd->bits_per_sample = 16; -	prtd->pos = 0; -  	if (prtd->next_track != true) {  		memcpy(&prtd->codec, codec, sizeof(*codec)); @@ -836,6 +839,7 @@ static const struct snd_soc_component_driver q6apm_fe_dai_component = {  	.hw_params	= q6apm_dai_hw_params,  	.pointer	= q6apm_dai_pointer,  	.trigger	= q6apm_dai_trigger, +	.ack		= q6apm_dai_ack,  	.compress_ops	= &q6apm_dai_compress_ops,  	.use_dai_pcm_id = true,  }; diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c index 11e252a70f69..b4ffa0f0b188 100644 --- a/sound/soc/qcom/qdsp6/q6apm.c +++ b/sound/soc/qcom/qdsp6/q6apm.c @@ -494,6 +494,19 @@ int q6apm_read(struct q6apm_graph *graph)  }  EXPORT_SYMBOL_GPL(q6apm_read); +int q6apm_get_hw_pointer(struct q6apm_graph *graph, int dir) +{ +	struct audioreach_graph_data *data; + +	if (dir == SNDRV_PCM_STREAM_PLAYBACK) +		data = &graph->rx_data; +	else +		data = &graph->tx_data; + +	return (int)atomic_read(&data->hw_ptr); +} +EXPORT_SYMBOL_GPL(q6apm_get_hw_pointer); +  static int graph_callback(struct gpr_resp_pkt *data, void *priv, int op)  {  	struct data_cmd_rsp_rd_sh_mem_ep_data_buffer_done_v2 *rd_done; @@ -520,7 +533,8 @@ static int graph_callback(struct gpr_resp_pkt *data, void *priv, int op)  		done = data->payload;  		phys = graph->rx_data.buf[token].phys;  		mutex_unlock(&graph->lock); - +		/* token numbering starts at 0 */ +		atomic_set(&graph->rx_data.hw_ptr, token + 1);  		if (lower_32_bits(phys) == done->buf_addr_lsw &&  		    upper_32_bits(phys) == done->buf_addr_msw) {  			graph->result.opcode = hdr->opcode; @@ -553,6 +567,8 @@ static int graph_callback(struct gpr_resp_pkt *data, void *priv, int op)  		rd_done = data->payload;  		phys = graph->tx_data.buf[hdr->token].phys;  		mutex_unlock(&graph->lock); +		/* token numbering starts at 0 */ +		atomic_set(&graph->tx_data.hw_ptr, hdr->token + 1);  		if (upper_32_bits(phys) == rd_done->buf_addr_msw &&  		    lower_32_bits(phys) == rd_done->buf_addr_lsw) { diff --git a/sound/soc/qcom/qdsp6/q6apm.h b/sound/soc/qcom/qdsp6/q6apm.h index c248c8d2b1ab..7ce08b401e31 100644 --- a/sound/soc/qcom/qdsp6/q6apm.h +++ b/sound/soc/qcom/qdsp6/q6apm.h @@ -2,6 +2,7 @@  #ifndef __Q6APM_H__  #define __Q6APM_H__  #include <linux/types.h> +#include <linux/atomic.h>  #include <linux/slab.h>  #include <linux/wait.h>  #include <linux/kernel.h> @@ -77,6 +78,7 @@ struct audioreach_graph_data {  	uint32_t num_periods;  	uint32_t dsp_buf;  	uint32_t mem_map_handle; +	atomic_t hw_ptr;  };  struct audioreach_graph { @@ -150,4 +152,5 @@ int q6apm_enable_compress_module(struct device *dev, struct q6apm_graph *graph,  int q6apm_remove_initial_silence(struct device *dev, struct q6apm_graph *graph, uint32_t samples);  int q6apm_remove_trailing_silence(struct device *dev, struct q6apm_graph *graph, uint32_t samples);  int q6apm_set_real_module_id(struct device *dev, struct q6apm_graph *graph, uint32_t codec_id); +int q6apm_get_hw_pointer(struct q6apm_graph *graph, int dir);  #endif /* __APM_GRAPH_ */ diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c index 045100c94352..a400c9a31fea 100644 --- a/sound/soc/qcom/qdsp6/q6asm-dai.c +++ b/sound/soc/qcom/qdsp6/q6asm-dai.c @@ -892,9 +892,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,  		if (ret < 0) {  			dev_err(dev, "q6asm_open_write failed\n"); -			q6asm_audio_client_free(prtd->audio_client); -			prtd->audio_client = NULL; -			return ret; +			goto open_err;  		}  	} @@ -903,7 +901,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,  			      prtd->session_id, dir);  	if (ret) {  		dev_err(dev, "Stream reg failed ret:%d\n", ret); -		return ret; +		goto q6_err;  	}  	ret = __q6asm_dai_compr_set_codec_params(component, stream, @@ -911,7 +909,7 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,  						 prtd->stream_id);  	if (ret) {  		dev_err(dev, "codec param setup failed ret:%d\n", ret); -		return ret; +		goto q6_err;  	}  	ret = q6asm_map_memory_regions(dir, prtd->audio_client, prtd->phys, @@ -920,12 +918,21 @@ static int q6asm_dai_compr_set_params(struct snd_soc_component *component,  	if (ret < 0) {  		dev_err(dev, "Buffer Mapping failed ret:%d\n", ret); -		return -ENOMEM; +		ret = -ENOMEM; +		goto q6_err;  	}  	prtd->state = Q6ASM_STREAM_RUNNING;  	return 0; + +q6_err: +	q6asm_cmd(prtd->audio_client, prtd->stream_id, CMD_CLOSE); + +open_err: +	q6asm_audio_client_free(prtd->audio_client); +	prtd->audio_client = NULL; +	return ret;  }  static int q6asm_dai_compr_set_metadata(struct snd_soc_component *component, diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index ccf8eefdca70..f64e8a6a9a33 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -991,6 +991,10 @@ int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev)  	if (!sdev->dspless_mode_selected) {  		/* cancel any attempt for DSP D0I3 */  		cancel_delayed_work_sync(&hda->d0i3_work); + +		/* Cancel the microphone privacy work if mic privacy is active */ +		if (hda->mic_privacy.active) +			cancel_work_sync(&hda->mic_privacy.work);  	}  	/* stop hda controller and power dsp off */ @@ -1017,6 +1021,10 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state)  	if (!sdev->dspless_mode_selected) {  		/* cancel any attempt for DSP D0I3 */  		cancel_delayed_work_sync(&hda->d0i3_work); + +		/* Cancel the microphone privacy work if mic privacy is active */ +		if (hda->mic_privacy.active) +			cancel_work_sync(&hda->mic_privacy.work);  	}  	if (target_state == SOF_DSP_PM_D0) { diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 6b1ada566476..b34e5fdf10f1 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -968,6 +968,10 @@ void hda_dsp_remove(struct snd_sof_dev *sdev)  	if (sdev->dspless_mode_selected)  		goto skip_disable_dsp; +	/* Cancel the microphone privacy work if mic privacy is active */ +	if (hda->mic_privacy.active) +		cancel_work_sync(&hda->mic_privacy.work); +  	/* no need to check for error as the DSP will be disabled anyway */  	if (chip && chip->power_down_dsp)  		chip->power_down_dsp(sdev); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 76154627fc17..108cad04879e 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -487,6 +487,11 @@ enum sof_hda_D0_substate {  	SOF_HDA_DSP_PM_D0I3,	/* low power D0 substate */  }; +struct sof_ace3_mic_privacy { +	bool active; +	struct work_struct work; +}; +  /* represents DSP HDA controller frontend - i.e. host facing control */  struct sof_intel_hda_dev {  	bool imrboot_supported; @@ -542,6 +547,9 @@ struct sof_intel_hda_dev {  	/* Intel NHLT information */  	struct nhlt_acpi_table *nhlt; +	/* work queue for mic privacy state change notification sending */ +	struct sof_ace3_mic_privacy mic_privacy; +  	/*  	 * Pointing to the IPC message if immediate sending was not possible  	 * because the downlink communication channel was BUSY at the time. diff --git a/sound/soc/sof/intel/ptl.c b/sound/soc/sof/intel/ptl.c index 8fa4bdceedd9..aa0b772178bc 100644 --- a/sound/soc/sof/intel/ptl.c +++ b/sound/soc/sof/intel/ptl.c @@ -27,22 +27,44 @@ static bool sof_ptl_check_mic_privacy_irq(struct snd_sof_dev *sdev, bool alt,  	return hdac_bus_eml_is_mic_privacy_changed(sof_to_bus(sdev), alt, elid);  } +static void sof_ptl_mic_privacy_work(struct work_struct *work) +{ +	struct sof_intel_hda_dev *hdev = container_of(work, +						      struct sof_intel_hda_dev, +						      mic_privacy.work); +	struct hdac_bus *bus = &hdev->hbus.core; +	struct snd_sof_dev *sdev = dev_get_drvdata(bus->dev); +	bool state; + +	/* +	 * The microphone privacy state is only available via Soundwire shim +	 * in PTL +	 * The work is only scheduled on change. +	 */ +	state = hdac_bus_eml_get_mic_privacy_state(bus, 1, +						   AZX_REG_ML_LEPTR_ID_SDW); +	sof_ipc4_mic_privacy_state_change(sdev, state); +} +  static void sof_ptl_process_mic_privacy(struct snd_sof_dev *sdev, bool alt,  					int elid)  { -	bool state; +	struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;  	if (!alt || elid != AZX_REG_ML_LEPTR_ID_SDW)  		return; -	state = hdac_bus_eml_get_mic_privacy_state(sof_to_bus(sdev), alt, elid); - -	sof_ipc4_mic_privacy_state_change(sdev, state); +	/* +	 * Schedule the work to read the microphone privacy state and send IPC +	 * message about the new state to the firmware +	 */ +	schedule_work(&hdev->mic_privacy.work);  }  static void sof_ptl_set_mic_privacy(struct snd_sof_dev *sdev,  				    struct sof_ipc4_intel_mic_privacy_cap *caps)  { +	struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;  	u32 micpvcp;  	if (!caps || !caps->capabilities_length) @@ -58,6 +80,9 @@ static void sof_ptl_set_mic_privacy(struct snd_sof_dev *sdev,  	hdac_bus_eml_set_mic_privacy_mask(sof_to_bus(sdev), true,  					  AZX_REG_ML_LEPTR_ID_SDW,  					  PTL_MICPVCP_GET_SDW_MASK(micpvcp)); + +	INIT_WORK(&hdev->mic_privacy.work, sof_ptl_mic_privacy_work); +	hdev->mic_privacy.active = true;  }  int sof_ptl_set_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *dsp_ops) | 
