Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit 078b3a02 authored by Mark Brown's avatar Mark Brown
Browse files

Merge remote-tracking branch 'asoc/topic/rcar' into asoc-next

parents 5f7a0ea9 2ca69d73
Loading
Loading
Loading
Loading
+11 −4
Original line number Diff line number Diff line
@@ -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)
+2 −0
Original line number Diff line number Diff line
@@ -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,
+2 −1
Original line number Diff line number Diff line
@@ -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(
+86 −57
Original line number Diff line number Diff line
@@ -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);

	/*
	 * 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_channels(struct snd_pcm_hw_params *params,
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,
				       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 @@ static struct device_node *rsnd_dai_of_node(struct rsnd_priv *priv,

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) {
+0 −18
Original line number Diff line number Diff line
@@ -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);
}

Loading