diff options
| author | Mark Brown <broonie@kernel.org> | 2018-01-18 11:55:37 +0000 | 
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2018-01-18 11:55:37 +0000 | 
| commit | 078b3a0205cba12302d40ce04a24c0edaa6842ce (patch) | |
| tree | 69d5b79691fd894866b89798329c42efc7c641b5 | |
| parent | 5f7a0ea9fe0e1874ff339ab42fdde89f0ccee411 (diff) | |
| parent | 2ca69d73bc05a55edb95689d436ce87974a3162e (diff) | |
| download | talos-op-linux-078b3a0205cba12302d40ce04a24c0edaa6842ce.tar.gz talos-op-linux-078b3a0205cba12302d40ce04a24c0edaa6842ce.zip  | |
Merge remote-tracking branch 'asoc/topic/rcar' into asoc-next
| -rw-r--r-- | Documentation/devicetree/bindings/sound/renesas,rsnd.txt | 15 | ||||
| -rw-r--r-- | include/sound/soc.h | 2 | ||||
| -rw-r--r-- | sound/soc/rockchip/rk3399_gru_sound.c | 3 | ||||
| -rw-r--r-- | sound/soc/sh/rcar/core.c | 143 | ||||
| -rw-r--r-- | sound/soc/sh/rcar/dma.c | 18 | ||||
| -rw-r--r-- | sound/soc/sh/rcar/rsnd.h | 15 | ||||
| -rw-r--r-- | sound/soc/sh/rcar/ssi.c | 163 | ||||
| -rw-r--r-- | sound/soc/soc-core.c | 10 | 
8 files changed, 197 insertions, 172 deletions
diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index 085bec364caf..5bed9a595772 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -4,7 +4,7 @@ Renesas R-Car sound  * Modules  ============================================= -Renesas R-Car sound is constructed from below modules +Renesas R-Car and RZ/G sound is constructed from below modules  (for Gen2 or later)   SCU		: Sampling Rate Converter Unit @@ -197,12 +197,17 @@ Ex)  	[MEM] -> [SRC2] -> [CTU03] -+  	sound { +		#address-cells = <1>; +		#size-cells = <0>; +  		compatible = "simple-scu-audio-card";  		... -		simple-audio-card,cpu-0 { +		simple-audio-card,cpu@0 { +			reg = <0>;  			sound-dai = <&rcar_sound 0>;  		}; -		simple-audio-card,cpu-1 { +		simple-audio-card,cpu@1 { +			reg = <1>;  			sound-dai = <&rcar_sound 1>;  		};  		simple-audio-card,codec { @@ -334,9 +339,11 @@ Required properties:  - compatible			: "renesas,rcar_sound-<soctype>", fallbacks  				  "renesas,rcar_sound-gen1" if generation1, and -				  "renesas,rcar_sound-gen2" if generation2 +				  "renesas,rcar_sound-gen2" if generation2 (or RZ/G1)  				  "renesas,rcar_sound-gen3" if generation3  				  Examples with soctypes are: +				    - "renesas,rcar_sound-r8a7743" (RZ/G1M) +				    - "renesas,rcar_sound-r8a7745" (RZ/G1E)  				    - "renesas,rcar_sound-r8a7778" (R-Car M1A)  				    - "renesas,rcar_sound-r8a7779" (R-Car H1)  				    - "renesas,rcar_sound-r8a7790" (R-Car H2) diff --git a/include/sound/soc.h b/include/sound/soc.h index 6e865c2bcffe..8fd59dadaf01 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -494,6 +494,8 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num);  int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num);  #endif +void snd_soc_disconnect_sync(struct device *dev); +  struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,  		const char *dai_link, int stream);  struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c index d64fbbd50544..fa6cd1de828b 100644 --- a/sound/soc/rockchip/rk3399_gru_sound.c +++ b/sound/soc/rockchip/rk3399_gru_sound.c @@ -206,7 +206,8 @@ static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd)  		return ret;  	} -	snd_jack_set_key(rockchip_sound_jack.jack, SND_JACK_BTN_0, KEY_MEDIA); +	snd_jack_set_key( +		rockchip_sound_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);  	snd_jack_set_key(  		rockchip_sound_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP);  	snd_jack_set_key( diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index f12a88a21dfa..64d5ecb86528 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -197,16 +197,27 @@ int rsnd_io_is_working(struct rsnd_dai_stream *io)  	return 0;  } -int rsnd_runtime_channel_original(struct rsnd_dai_stream *io) +int rsnd_runtime_channel_original_with_params(struct rsnd_dai_stream *io, +					      struct snd_pcm_hw_params *params)  {  	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); -	return runtime->channels; +	/* +	 * params will be added when refine +	 * see +	 *	__rsnd_soc_hw_rule_rate() +	 *	__rsnd_soc_hw_rule_channels() +	 */ +	if (params) +		return params_channels(params); +	else +		return runtime->channels;  } -int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io) +int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io, +					       struct snd_pcm_hw_params *params)  { -	int chan = rsnd_runtime_channel_original(io); +	int chan = rsnd_runtime_channel_original_with_params(io, params);  	struct rsnd_mod *ctu_mod = rsnd_io_to_mod_ctu(io);  	if (ctu_mod) { @@ -219,12 +230,13 @@ int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io)  	return chan;  } -int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io) +int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io, +					     struct snd_pcm_hw_params *params)  {  	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);  	int chan = rsnd_io_is_play(io) ? -		rsnd_runtime_channel_after_ctu(io) : -		rsnd_runtime_channel_original(io); +		rsnd_runtime_channel_after_ctu_with_params(io, params) : +		rsnd_runtime_channel_original_with_params(io, params);  	/* Use Multi SSI */  	if (rsnd_runtime_is_ssi_multi(io)) @@ -262,10 +274,10 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io)  	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);  	struct device *dev = rsnd_priv_to_dev(priv); -	switch (runtime->sample_bits) { +	switch (snd_pcm_format_width(runtime->format)) {  	case 16:  		return 8 << 16; -	case 32: +	case 24:  		return 0 << 16;  	} @@ -282,11 +294,12 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)  	struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io);  	struct rsnd_mod *target;  	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); -	u32 val = 0x76543210; -	u32 mask = ~0;  	/* -	 * *Hardware* L/R and *Software* L/R are inverted. +	 * *Hardware* L/R and *Software* L/R are inverted for 16bit data. +	 *	    31..16 15...0 +	 *	HW: [L ch] [R ch] +	 *	SW: [R ch] [L ch]  	 * We need to care about inversion timing to control  	 * Playback/Capture correctly.  	 * The point is [DVC] needs *Hardware* L/R, [MEM] needs *Software* L/R @@ -313,27 +326,13 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)  		target = cmd ? cmd : ssiu;  	} -	mask <<= runtime->channels * 4; -	val = val & mask; - -	switch (runtime->sample_bits) { -	case 16: -		val |= 0x67452301 & ~mask; -		break; -	case 32: -		val |= 0x76543210 & ~mask; -		break; -	} - -	/* -	 * exchange channeles on SRC if possible, -	 * otherwise, R/L volume settings on DVC -	 * changes inverted channels -	 */ -	if (mod == target) -		return val; -	else +	/* Non target mod or 24bit data needs normal DALIGN */ +	if ((snd_pcm_format_width(runtime->format) != 16) || +	    (mod != target))  		return 0x76543210; +	/* Target mod needs inverted DALIGN when 16bit */ +	else +		return 0x67452301;  }  u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod) @@ -363,12 +362,8 @@ u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod)  	 * HW    24bit data is located as 0x******00  	 *  	 */ -	switch (runtime->sample_bits) { -	case 16: +	if (snd_pcm_format_width(runtime->format) == 16)  		return 0; -	case 32: -		break; -	}  	for (i = 0; i < ARRAY_SIZE(playback_mods); i++) {  		tmod = rsnd_io_to_mod(io, mods[i]); @@ -616,8 +611,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,  	switch (cmd) {  	case SNDRV_PCM_TRIGGER_START:  	case SNDRV_PCM_TRIGGER_RESUME: -		rsnd_dai_stream_init(io, substream); -  		ret = rsnd_dai_call(init, io, priv);  		if (ret < 0)  			goto dai_trigger_end; @@ -639,7 +632,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,  		ret |= rsnd_dai_call(quit, io, priv); -		rsnd_dai_stream_quit(io);  		break;  	default:  		ret = -EINVAL; @@ -784,8 +776,9 @@ static int rsnd_soc_hw_rule(struct rsnd_priv *priv,  	return snd_interval_refine(iv, &p);  } -static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, -				 struct snd_pcm_hw_rule *rule) +static int __rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, +				   struct snd_pcm_hw_rule *rule, +				   int is_play)  {  	struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);  	struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); @@ -793,25 +786,37 @@ static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params,  	struct snd_soc_dai *dai = rule->private;  	struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);  	struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); +	struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture;  	/*  	 * possible sampling rate limitation is same as  	 * 2ch if it supports multi ssi +	 * and same as 8ch if TDM 6ch (see rsnd_ssi_config_init())  	 */  	ic = *ic_; -	if (1 < rsnd_rdai_ssi_lane_get(rdai)) { -		ic.min = 2; -		ic.max = 2; -	} +	ic.min = +	ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params);  	return rsnd_soc_hw_rule(priv, rsnd_soc_hw_rate_list,  				ARRAY_SIZE(rsnd_soc_hw_rate_list),  				&ic, ir);  } +static int rsnd_soc_hw_rule_rate_playback(struct snd_pcm_hw_params *params, +				 struct snd_pcm_hw_rule *rule) +{ +	return __rsnd_soc_hw_rule_rate(params, rule, 1); +} + +static int rsnd_soc_hw_rule_rate_capture(struct snd_pcm_hw_params *params, +					  struct snd_pcm_hw_rule *rule) +{ +	return __rsnd_soc_hw_rule_rate(params, rule, 0); +} -static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, -				     struct snd_pcm_hw_rule *rule) +static int __rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, +				       struct snd_pcm_hw_rule *rule, +				       int is_play)  {  	struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);  	struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); @@ -819,22 +824,34 @@ static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params,  	struct snd_soc_dai *dai = rule->private;  	struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);  	struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); +	struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture;  	/*  	 * possible sampling rate limitation is same as  	 * 2ch if it supports multi ssi +	 * and same as 8ch if TDM 6ch (see rsnd_ssi_config_init())  	 */  	ic = *ic_; -	if (1 < rsnd_rdai_ssi_lane_get(rdai)) { -		ic.min = 2; -		ic.max = 2; -	} +	ic.min = +	ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params);  	return rsnd_soc_hw_rule(priv, rsnd_soc_hw_channels_list,  				ARRAY_SIZE(rsnd_soc_hw_channels_list),  				ir, &ic);  } +static int rsnd_soc_hw_rule_channels_playback(struct snd_pcm_hw_params *params, +					      struct snd_pcm_hw_rule *rule) +{ +	return __rsnd_soc_hw_rule_channels(params, rule, 1); +} + +static int rsnd_soc_hw_rule_channels_capture(struct snd_pcm_hw_params *params, +					     struct snd_pcm_hw_rule *rule) +{ +	return __rsnd_soc_hw_rule_channels(params, rule, 0); +} +  static const struct snd_pcm_hardware rsnd_pcm_hardware = {  	.info =		SNDRV_PCM_INFO_INTERLEAVED	|  			SNDRV_PCM_INFO_MMAP		| @@ -859,6 +876,8 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream,  	int ret;  	int i; +	rsnd_dai_stream_init(io, substream); +  	/*  	 * Channel Limitation  	 * It depends on Platform design @@ -886,11 +905,17 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream,  	 * It depends on Clock Master Mode  	 */  	if (rsnd_rdai_is_clk_master(rdai)) { +		int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; +  		snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, -				    rsnd_soc_hw_rule_rate, dai, +				    is_play ? rsnd_soc_hw_rule_rate_playback : +					      rsnd_soc_hw_rule_rate_capture, +				    dai,  				    SNDRV_PCM_HW_PARAM_CHANNELS, -1);  		snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, -				    rsnd_soc_hw_rule_channels, dai, +				    is_play ? rsnd_soc_hw_rule_channels_playback : +					      rsnd_soc_hw_rule_channels_capture, +				    dai,  				    SNDRV_PCM_HW_PARAM_RATE, -1);  	} @@ -915,6 +940,8 @@ static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream,  	 * call rsnd_dai_call without spinlock  	 */  	rsnd_dai_call(nolock_stop, io, priv); + +	rsnd_dai_stream_quit(io);  }  static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { @@ -990,7 +1017,7 @@ of_node_compatible:  static void __rsnd_dai_probe(struct rsnd_priv *priv,  			     struct device_node *dai_np, -			     int dai_i, int is_graph) +			     int dai_i)  {  	struct device_node *playback, *capture;  	struct rsnd_dai_stream *io_playback; @@ -1089,13 +1116,13 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)  	dai_i = 0;  	if (is_graph) {  		for_each_endpoint_of_node(dai_node, dai_np) { -			__rsnd_dai_probe(priv, dai_np, dai_i, is_graph); +			__rsnd_dai_probe(priv, dai_np, dai_i);  			rsnd_ssi_parse_hdmi_connection(priv, dai_np, dai_i);  			dai_i++;  		}  	} else {  		for_each_child_of_node(dai_node, dai_np) -			__rsnd_dai_probe(priv, dai_np, dai_i++, is_graph); +			__rsnd_dai_probe(priv, dai_np, dai_i++);  	}  	return 0; @@ -1496,6 +1523,8 @@ static int rsnd_remove(struct platform_device *pdev)  	};  	int ret = 0, i; +	snd_soc_disconnect_sync(&pdev->dev); +  	pm_runtime_disable(&pdev->dev);  	for_each_rsnd_dai(rdai, priv, i) { diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 4d750bdf8e24..41de23417c4a 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -71,25 +71,7 @@ static struct rsnd_mod mem = {  static void __rsnd_dmaen_complete(struct rsnd_mod *mod,  				  struct rsnd_dai_stream *io)  { -	struct rsnd_priv *priv = rsnd_mod_to_priv(mod); -	bool elapsed = false; -	unsigned long flags; - -	/* -	 * Renesas sound Gen1 needs 1 DMAC, -	 * Gen2 needs 2 DMAC. -	 * In Gen2 case, it are Audio-DMAC, and Audio-DMAC-peri-peri. -	 * But, Audio-DMAC-peri-peri doesn't have interrupt, -	 * and this driver is assuming that here. -	 */ -	spin_lock_irqsave(&priv->lock, flags); -  	if (rsnd_io_is_working(io)) -		elapsed = true; - -	spin_unlock_irqrestore(&priv->lock, flags); - -	if (elapsed)  		rsnd_dai_period_elapsed(io);  } diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 57cd2bc773c2..ad6523595b0a 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -399,9 +399,18 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai,  		struct device_node *playback,  		struct device_node *capture); -int rsnd_runtime_channel_original(struct rsnd_dai_stream *io); -int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io); -int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io); +#define rsnd_runtime_channel_original(io) \ +	rsnd_runtime_channel_original_with_params(io, NULL) +int rsnd_runtime_channel_original_with_params(struct rsnd_dai_stream *io, +				struct snd_pcm_hw_params *params); +#define rsnd_runtime_channel_after_ctu(io)			\ +	rsnd_runtime_channel_after_ctu_with_params(io, NULL) +int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io, +				struct snd_pcm_hw_params *params); +#define rsnd_runtime_channel_for_ssi(io) \ +	rsnd_runtime_channel_for_ssi_with_params(io, NULL) +int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io, +				 struct snd_pcm_hw_params *params);  int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io);  int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io); diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index cbf3bf312d23..97a9db892a8f 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -79,8 +79,8 @@ struct rsnd_ssi {  	int irq;  	unsigned int usrcnt; +	/* for PIO */  	int byte_pos; -	int period_pos;  	int byte_per_period;  	int next_period_byte;  }; @@ -371,11 +371,11 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,  	if (rsnd_io_is_play(io))  		cr_own |= TRMD; -	switch (runtime->sample_bits) { +	switch (snd_pcm_format_width(runtime->format)) {  	case 16:  		cr_own |= DWL_16;  		break; -	case 32: +	case 24:  		cr_own |= DWL_24;  		break;  	} @@ -414,63 +414,6 @@ static void rsnd_ssi_register_setup(struct rsnd_mod *mod)  					ssi->cr_en);  } -static void rsnd_ssi_pointer_init(struct rsnd_mod *mod, -				  struct rsnd_dai_stream *io) -{ -	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); -	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - -	ssi->byte_pos		= 0; -	ssi->period_pos		= 0; -	ssi->byte_per_period	= runtime->period_size * -				  runtime->channels * -				  samples_to_bytes(runtime, 1); -	ssi->next_period_byte	= ssi->byte_per_period; -} - -static int rsnd_ssi_pointer_offset(struct rsnd_mod *mod, -				   struct rsnd_dai_stream *io, -				   int additional) -{ -	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); -	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); -	int pos = ssi->byte_pos + additional; - -	pos %= (runtime->periods * ssi->byte_per_period); - -	return pos; -} - -static bool rsnd_ssi_pointer_update(struct rsnd_mod *mod, -				    struct rsnd_dai_stream *io, -				    int byte) -{ -	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); -	bool ret = false; -	int byte_pos; - -	byte_pos = ssi->byte_pos + byte; - -	if (byte_pos >= ssi->next_period_byte) { -		struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - -		ssi->period_pos++; -		ssi->next_period_byte += ssi->byte_per_period; - -		if (ssi->period_pos >= runtime->periods) { -			byte_pos = 0; -			ssi->period_pos = 0; -			ssi->next_period_byte = ssi->byte_per_period; -		} - -		ret = true; -	} - -	WRITE_ONCE(ssi->byte_pos, byte_pos); - -	return ret; -} -  /*   *	SSI mod common functions   */ @@ -484,8 +427,6 @@ static int rsnd_ssi_init(struct rsnd_mod *mod,  	if (!rsnd_ssi_is_run_mods(mod, io))  		return 0; -	rsnd_ssi_pointer_init(mod, io); -  	ssi->usrcnt++;  	rsnd_mod_power_on(mod); @@ -656,6 +597,8 @@ static int rsnd_ssi_irq(struct rsnd_mod *mod,  	return 0;  } +static bool rsnd_ssi_pio_interrupt(struct rsnd_mod *mod, +				   struct rsnd_dai_stream *io);  static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,  				 struct rsnd_dai_stream *io)  { @@ -674,30 +617,8 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,  	status = rsnd_ssi_status_get(mod);  	/* PIO only */ -	if (!is_dma && (status & DIRQ)) { -		struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); -		u32 *buf = (u32 *)(runtime->dma_area + -				   rsnd_ssi_pointer_offset(mod, io, 0)); -		int shift = 0; - -		switch (runtime->sample_bits) { -		case 32: -			shift = 8; -			break; -		} - -		/* -		 * 8/16/32 data can be assesse to TDR/RDR register -		 * directly as 32bit data -		 * see rsnd_ssi_init() -		 */ -		if (rsnd_io_is_play(io)) -			rsnd_mod_write(mod, SSITDR, (*buf) << shift); -		else -			*buf = (rsnd_mod_read(mod, SSIRDR) >> shift); - -		elapsed = rsnd_ssi_pointer_update(mod, io, sizeof(*buf)); -	} +	if (!is_dma && (status & DIRQ)) +		elapsed = rsnd_ssi_pio_interrupt(mod, io);  	/* DMA only */  	if (is_dma && (status & (UIRQ | OIRQ))) @@ -835,7 +756,71 @@ static int rsnd_ssi_common_remove(struct rsnd_mod *mod,  	return 0;  } -static int rsnd_ssi_pointer(struct rsnd_mod *mod, +/* + *	SSI PIO functions + */ +static bool rsnd_ssi_pio_interrupt(struct rsnd_mod *mod, +				   struct rsnd_dai_stream *io) +{ +	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); +	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); +	u32 *buf = (u32 *)(runtime->dma_area + ssi->byte_pos); +	int shift = 0; +	int byte_pos; +	bool elapsed = false; + +	if (snd_pcm_format_width(runtime->format) == 24) +		shift = 8; + +	/* +	 * 8/16/32 data can be assesse to TDR/RDR register +	 * directly as 32bit data +	 * see rsnd_ssi_init() +	 */ +	if (rsnd_io_is_play(io)) +		rsnd_mod_write(mod, SSITDR, (*buf) << shift); +	else +		*buf = (rsnd_mod_read(mod, SSIRDR) >> shift); + +	byte_pos = ssi->byte_pos + sizeof(*buf); + +	if (byte_pos >= ssi->next_period_byte) { +		int period_pos = byte_pos / ssi->byte_per_period; + +		if (period_pos >= runtime->periods) { +			byte_pos = 0; +			period_pos = 0; +		} + +		ssi->next_period_byte = (period_pos + 1) * ssi->byte_per_period; + +		elapsed = true; +	} + +	WRITE_ONCE(ssi->byte_pos, byte_pos); + +	return elapsed; +} + +static int rsnd_ssi_pio_init(struct rsnd_mod *mod, +			     struct rsnd_dai_stream *io, +			     struct rsnd_priv *priv) +{ +	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); +	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + +	if (!rsnd_ssi_is_parent(mod, io)) { +		ssi->byte_pos		= 0; +		ssi->byte_per_period	= runtime->period_size * +					  runtime->channels * +					  samples_to_bytes(runtime, 1); +		ssi->next_period_byte	= ssi->byte_per_period; +	} + +	return rsnd_ssi_init(mod, io, priv); +} + +static int rsnd_ssi_pio_pointer(struct rsnd_mod *mod,  			    struct rsnd_dai_stream *io,  			    snd_pcm_uframes_t *pointer)  { @@ -851,12 +836,12 @@ static struct rsnd_mod_ops rsnd_ssi_pio_ops = {  	.name	= SSI_NAME,  	.probe	= rsnd_ssi_common_probe,  	.remove	= rsnd_ssi_common_remove, -	.init	= rsnd_ssi_init, +	.init	= rsnd_ssi_pio_init,  	.quit	= rsnd_ssi_quit,  	.start	= rsnd_ssi_start,  	.stop	= rsnd_ssi_stop,  	.irq	= rsnd_ssi_irq, -	.pointer= rsnd_ssi_pointer, +	.pointer = rsnd_ssi_pio_pointer,  	.pcm_new = rsnd_ssi_pcm_new,  	.hw_params = rsnd_ssi_hw_params,  }; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 9b79c2199781..e018a2badfde 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1393,6 +1393,16 @@ static int soc_init_dai_link(struct snd_soc_card *card,  	return 0;  } +void snd_soc_disconnect_sync(struct device *dev) +{ +	struct snd_soc_component *component = snd_soc_lookup_component(dev, NULL); + +	if (!component || !component->card) +		return; + +	snd_card_disconnect_sync(component->card->snd_card); +} +  /**   * snd_soc_add_dai_link - Add a DAI link dynamically   * @card: The ASoC card to which the DAI link is added  | 

