diff options
-rw-r--r-- | Documentation/devicetree/bindings/sound/renesas,rsnd.txt | 2 | ||||
-rw-r--r-- | sound/soc/sh/rcar/core.c | 20 | ||||
-rw-r--r-- | sound/soc/sh/rcar/ssi.c | 56 |
3 files changed, 62 insertions, 16 deletions
diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index f316ce1f214a..62ece4c59da7 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -47,7 +47,7 @@ DAI subnode properties: Example: -rcar_sound: rcar_sound@ec500000 { +rcar_sound: sound@ec500000 { #sound-dai-cells = <1>; compatible = "renesas,rcar_sound-r8a7791", "renesas,rcar_sound-gen2"; reg = <0 0xec500000 0 0x1000>, /* SCU */ diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 9f48d75fa992..2b7323c92994 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -272,9 +272,10 @@ struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id) return priv->rdai + id; } +#define rsnd_dai_to_priv(dai) snd_soc_dai_get_drvdata(dai) static struct rsnd_dai *rsnd_dai_to_rdai(struct snd_soc_dai *dai) { - struct rsnd_priv *priv = snd_soc_dai_get_drvdata(dai); + struct rsnd_priv *priv = rsnd_dai_to_priv(dai); return rsnd_rdai_get(priv, dai->id); } @@ -314,7 +315,7 @@ void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int byte) } } -static int rsnd_dai_stream_init(struct rsnd_dai_stream *io, +static void rsnd_dai_stream_init(struct rsnd_dai_stream *io, struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -326,8 +327,11 @@ static int rsnd_dai_stream_init(struct rsnd_dai_stream *io, runtime->channels * samples_to_bytes(runtime, 1); io->next_period_byte = io->byte_per_period; +} - return 0; +static void rsnd_dai_stream_quit(struct rsnd_dai_stream *io) +{ + io->substream = NULL; } static @@ -351,7 +355,7 @@ struct rsnd_dai_stream *rsnd_rdai_to_io(struct rsnd_dai *rdai, static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { - struct rsnd_priv *priv = snd_soc_dai_get_drvdata(dai); + struct rsnd_priv *priv = rsnd_dai_to_priv(dai); struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); int ssi_id = rsnd_mod_id(rsnd_io_to_mod_ssi(io)); @@ -362,9 +366,7 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, switch (cmd) { case SNDRV_PCM_TRIGGER_START: - ret = rsnd_dai_stream_init(io, substream); - if (ret < 0) - goto dai_trigger_end; + rsnd_dai_stream_init(io, substream); ret = rsnd_platform_call(priv, dai, start, ssi_id); if (ret < 0) @@ -390,6 +392,8 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, ret = rsnd_platform_call(priv, dai, stop, ssi_id); if (ret < 0) goto dai_trigger_end; + + rsnd_dai_stream_quit(io); break; default: ret = -EINVAL; @@ -833,12 +837,14 @@ static int __rsnd_kctrl_new(struct rsnd_mod *mod, struct rsnd_kctrl_cfg *cfg, void (*update)(struct rsnd_mod *mod)) { + struct snd_soc_card *soc_card = rtd->card; struct snd_card *card = rtd->card->snd_card; struct snd_kcontrol *kctrl; struct snd_kcontrol_new knew = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = name, .info = rsnd_kctrl_info, + .index = rtd - soc_card->rtd, .get = rsnd_kctrl_get, .put = rsnd_kctrl_put, .private_value = (unsigned long)cfg, diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 7bb9c087f3dc..927ac52a6d1e 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -66,6 +66,7 @@ struct rsnd_ssi { u32 cr_own; u32 cr_clk; + int chan; int err; unsigned int usrcnt; }; @@ -80,7 +81,7 @@ struct rsnd_ssi { #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) #define rsnd_dma_to_ssi(dma) rsnd_mod_to_ssi(rsnd_dma_to_mod(dma)) #define rsnd_ssi_pio_available(ssi) ((ssi)->info->irq > 0) -#define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent) +#define rsnd_ssi_parent(ssi) ((ssi)->parent) #define rsnd_ssi_mode_flags(p) ((p)->info->flags) #define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id) #define rsnd_ssi_of_node(priv) \ @@ -189,8 +190,10 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi, rsnd_mod_hw_start(&ssi->mod); if (rsnd_rdai_is_clk_master(rdai)) { - if (rsnd_ssi_clk_from_parent(ssi)) - rsnd_ssi_hw_start(ssi->parent, io); + struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi); + + if (ssi_parent) + rsnd_ssi_hw_start(ssi_parent, io); else rsnd_ssi_master_clk_start(ssi, io); } @@ -229,8 +232,10 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi) struct device *dev = rsnd_priv_to_dev(priv); u32 cr; - if (0 == ssi->usrcnt) /* stop might be called without start */ + if (0 == ssi->usrcnt) { + dev_err(dev, "%s called without starting\n", __func__); return; + } ssi->usrcnt--; @@ -253,13 +258,17 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi) rsnd_ssi_status_check(&ssi->mod, IIRQ); if (rsnd_rdai_is_clk_master(rdai)) { - if (rsnd_ssi_clk_from_parent(ssi)) - rsnd_ssi_hw_stop(ssi->parent); + struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi); + + if (ssi_parent) + rsnd_ssi_hw_stop(ssi_parent); else rsnd_ssi_master_clk_stop(ssi); } rsnd_mod_hw_stop(&ssi->mod); + + ssi->chan = 0; } dev_dbg(dev, "%s[%d] hw stopped\n", @@ -336,6 +345,35 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod, return 0; } +static int rsnd_ssi_hw_params(struct rsnd_mod *mod, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi); + int chan = params_channels(params); + + /* + * Already working. + * It will happen if SSI has parent/child connection. + */ + if (ssi->usrcnt) { + /* + * it is error if child <-> parent SSI uses + * different channels. + */ + if (ssi->chan != chan) + return -EIO; + } + + /* It will be removed on rsnd_ssi_hw_stop */ + ssi->chan = chan; + if (ssi_parent) + return rsnd_ssi_hw_params(&ssi_parent->mod, substream, params); + + return 0; +} + static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status) { /* under/over flow error */ @@ -456,6 +494,7 @@ static struct rsnd_mod_ops rsnd_ssi_pio_ops = { .quit = rsnd_ssi_quit, .start = rsnd_ssi_start, .stop = rsnd_ssi_stop, + .hw_params = rsnd_ssi_hw_params, }; static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, @@ -565,6 +604,7 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = { .start = rsnd_ssi_dma_start, .stop = rsnd_ssi_dma_stop, .fallback = rsnd_ssi_fallback, + .hw_params = rsnd_ssi_hw_params, }; int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod) @@ -598,7 +638,7 @@ int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod) return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE); } -static void rsnd_ssi_parent_clk_setup(struct rsnd_priv *priv, struct rsnd_ssi *ssi) +static void rsnd_ssi_parent_setup(struct rsnd_priv *priv, struct rsnd_ssi *ssi) { if (!rsnd_ssi_is_pin_sharing(&ssi->mod)) return; @@ -732,7 +772,7 @@ int rsnd_ssi_probe(struct platform_device *pdev, if (ret) return ret; - rsnd_ssi_parent_clk_setup(priv, ssi); + rsnd_ssi_parent_setup(priv, ssi); } return 0; |