[alsa-devel] [PATCH 0/3] ASoC: rsnd: request_irq/free_irq
Hi Mark
Renesas sound driver supports many features, thus, it has many data path. I noticed request_irq/free_irq balance are not correct when MIXer case, and PIO mode case. These patches solve these issue.
Kuninori Morimoto (3): ASoC: rsnd: call free_irq() both DMA/PIO mode ASoC: rsnd: add rsnd_ssi_flags_has/add() macro ASoC: rsnd: call request_irq/free_irq once in MIX case
sound/soc/sh/rcar/ssi.c | 81 ++++++++++++++++++++++++++++++------------------- 1 file changed, 50 insertions(+), 31 deletions(-)
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
commit 701172dca15b ("ASoC: rsnd: don't use devm_request_irq() for SSI") exchanged devm_request_irq() to request_irq() for SSI, because SSI will fallback into PIO mode if DMA doesn't work. But, because of it, PIO mode needed to call free_irq() when removing, not only DMA mode. This patch call free_irq() both PIO/DMA. Otherwise, rsnd IRQ handler will be increased if user tried many unbind/bind.
Fixes: 701172dca15b ("ASoC: rsnd: don't use devm_request_irq() for SSI") Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/rcar/ssi.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-)
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 0309de5..281ed0d 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -792,6 +792,23 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod, return ret; }
+static int rsnd_ssi_common_remove(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + struct rsnd_mod *pure_ssi_mod = rsnd_io_to_mod_ssi(io); + + /* Do nothing if non SSI (= SSI parent, multi SSI) mod */ + if (pure_ssi_mod != mod) + return 0; + + /* PIO will request IRQ again */ + free_irq(ssi->irq, mod); + + return 0; +} + static int rsnd_ssi_pointer(struct rsnd_mod *mod, struct rsnd_dai_stream *io, snd_pcm_uframes_t *pointer) @@ -807,6 +824,7 @@ static int rsnd_ssi_pointer(struct rsnd_mod *mod, 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, .quit = rsnd_ssi_quit, .start = rsnd_ssi_start, @@ -841,23 +859,6 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, return ret; }
-static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - struct rsnd_mod *pure_ssi_mod = rsnd_io_to_mod_ssi(io); - - /* Do nothing if non SSI (= SSI parent, multi SSI) mod */ - if (pure_ssi_mod != mod) - return 0; - - /* PIO will request IRQ again */ - free_irq(ssi->irq, mod); - - return 0; -} - static int rsnd_ssi_fallback(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) @@ -899,7 +900,7 @@ static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_dai_stream *io, .name = SSI_NAME, .dma_req = rsnd_ssi_dma_req, .probe = rsnd_ssi_dma_probe, - .remove = rsnd_ssi_dma_remove, + .remove = rsnd_ssi_common_remove, .init = rsnd_ssi_init, .quit = rsnd_ssi_quit, .start = rsnd_ssi_start,
The patch
ASoC: rsnd: call free_irq() both DMA/PIO mode
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 213691c7e873206742b39751895d15b41a02b3d1 Mon Sep 17 00:00:00 2001
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com Date: Thu, 10 Aug 2017 00:07:00 +0000 Subject: [PATCH] ASoC: rsnd: call free_irq() both DMA/PIO mode
commit 701172dca15b ("ASoC: rsnd: don't use devm_request_irq() for SSI") exchanged devm_request_irq() to request_irq() for SSI, because SSI will fallback into PIO mode if DMA doesn't work. But, because of it, PIO mode needed to call free_irq() when removing, not only DMA mode. This patch call free_irq() both PIO/DMA. Otherwise, rsnd IRQ handler will be increased if user tried many unbind/bind.
Fixes: 701172dca15b ("ASoC: rsnd: don't use devm_request_irq() for SSI") Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sh/rcar/ssi.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-)
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 0309de58bf18..281ed0da6ba1 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -792,6 +792,23 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod, return ret; }
+static int rsnd_ssi_common_remove(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + struct rsnd_mod *pure_ssi_mod = rsnd_io_to_mod_ssi(io); + + /* Do nothing if non SSI (= SSI parent, multi SSI) mod */ + if (pure_ssi_mod != mod) + return 0; + + /* PIO will request IRQ again */ + free_irq(ssi->irq, mod); + + return 0; +} + static int rsnd_ssi_pointer(struct rsnd_mod *mod, struct rsnd_dai_stream *io, snd_pcm_uframes_t *pointer) @@ -807,6 +824,7 @@ static int rsnd_ssi_pointer(struct rsnd_mod *mod, 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, .quit = rsnd_ssi_quit, .start = rsnd_ssi_start, @@ -841,23 +859,6 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, return ret; }
-static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - struct rsnd_mod *pure_ssi_mod = rsnd_io_to_mod_ssi(io); - - /* Do nothing if non SSI (= SSI parent, multi SSI) mod */ - if (pure_ssi_mod != mod) - return 0; - - /* PIO will request IRQ again */ - free_irq(ssi->irq, mod); - - return 0; -} - static int rsnd_ssi_fallback(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) @@ -899,7 +900,7 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = { .name = SSI_NAME, .dma_req = rsnd_ssi_dma_req, .probe = rsnd_ssi_dma_probe, - .remove = rsnd_ssi_dma_remove, + .remove = rsnd_ssi_common_remove, .init = rsnd_ssi_init, .quit = rsnd_ssi_quit, .start = rsnd_ssi_start,
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
Current rsnd_ssi_mode_flags() is not useful. This patch adds new rsnd_ssi_flags_has/add() macro for it.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/rcar/ssi.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-)
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 281ed0d..ca9355b 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -101,7 +101,8 @@ struct rsnd_ssi { #define rsnd_ssi_to_dma(mod) ((ssi)->dma) #define rsnd_ssi_nr(priv) ((priv)->ssi_nr) #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) -#define rsnd_ssi_mode_flags(p) ((p)->flags) +#define rsnd_ssi_flags_has(p, f) ((p)->flags & f) +#define rsnd_ssi_flags_set(p, f) ((p)->flags |= f) #define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io)) #define rsnd_ssi_is_multi_slave(mod, io) \ (rsnd_ssi_multi_slaves(io) & (1 << rsnd_mod_id(mod))) @@ -114,10 +115,10 @@ int rsnd_ssi_hdmi_port(struct rsnd_dai_stream *io) struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io); struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
- if (rsnd_ssi_mode_flags(ssi) & RSND_SSI_HDMI0) + if (rsnd_ssi_flags_has(ssi, RSND_SSI_HDMI0)) return RSND_SSI_HDMI_PORT0;
- if (rsnd_ssi_mode_flags(ssi) & RSND_SSI_HDMI1) + if (rsnd_ssi_flags_has(ssi, RSND_SSI_HDMI1)) return RSND_SSI_HDMI_PORT1;
return 0; @@ -132,7 +133,7 @@ int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) if (!rsnd_ssi_is_dma_mode(mod)) return 0;
- if (!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_NO_BUSIF)) + if (!(rsnd_ssi_flags_has(ssi, RSND_SSI_NO_BUSIF))) use_busif = 1; if (rsnd_io_to_mod_src(io)) use_busif = 1; @@ -986,13 +987,13 @@ static void __rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv, ssi = rsnd_mod_to_ssi(mod);
if (strstr(remote_ep->full_name, "hdmi0")) { - ssi->flags |= RSND_SSI_HDMI0; + rsnd_ssi_flags_set(ssi, RSND_SSI_HDMI0); dev_dbg(dev, "%s[%d] connected to HDMI0\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); }
if (strstr(remote_ep->full_name, "hdmi1")) { - ssi->flags |= RSND_SSI_HDMI1; + rsnd_ssi_flags_set(ssi, RSND_SSI_HDMI1); dev_dbg(dev, "%s[%d] connected to HDMI1\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); } @@ -1025,7 +1026,7 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
- return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE); + return !!(rsnd_ssi_flags_has(ssi, RSND_SSI_CLK_PIN_SHARE)); }
static u32 *rsnd_ssi_get_status(struct rsnd_dai_stream *io, @@ -1108,10 +1109,10 @@ int rsnd_ssi_probe(struct rsnd_priv *priv) }
if (of_get_property(np, "shared-pin", NULL)) - ssi->flags |= RSND_SSI_CLK_PIN_SHARE; + rsnd_ssi_flags_set(ssi, RSND_SSI_CLK_PIN_SHARE);
if (of_get_property(np, "no-busif", NULL)) - ssi->flags |= RSND_SSI_NO_BUSIF; + rsnd_ssi_flags_set(ssi, RSND_SSI_NO_BUSIF);
ssi->irq = irq_of_parse_and_map(np, 0); if (!ssi->irq) {
The patch
ASoC: rsnd: add rsnd_ssi_flags_has/add() macro
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From bf9b29c784b393d1e506945f1e24e871d2587eb3 Mon Sep 17 00:00:00 2001
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com Date: Thu, 10 Aug 2017 00:07:20 +0000 Subject: [PATCH] ASoC: rsnd: add rsnd_ssi_flags_has/add() macro
Current rsnd_ssi_mode_flags() is not useful. This patch adds new rsnd_ssi_flags_has/add() macro for it.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sh/rcar/ssi.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-)
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 281ed0da6ba1..ca9355b86bd9 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -101,7 +101,8 @@ struct rsnd_ssi { #define rsnd_ssi_to_dma(mod) ((ssi)->dma) #define rsnd_ssi_nr(priv) ((priv)->ssi_nr) #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) -#define rsnd_ssi_mode_flags(p) ((p)->flags) +#define rsnd_ssi_flags_has(p, f) ((p)->flags & f) +#define rsnd_ssi_flags_set(p, f) ((p)->flags |= f) #define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io)) #define rsnd_ssi_is_multi_slave(mod, io) \ (rsnd_ssi_multi_slaves(io) & (1 << rsnd_mod_id(mod))) @@ -114,10 +115,10 @@ int rsnd_ssi_hdmi_port(struct rsnd_dai_stream *io) struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io); struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
- if (rsnd_ssi_mode_flags(ssi) & RSND_SSI_HDMI0) + if (rsnd_ssi_flags_has(ssi, RSND_SSI_HDMI0)) return RSND_SSI_HDMI_PORT0;
- if (rsnd_ssi_mode_flags(ssi) & RSND_SSI_HDMI1) + if (rsnd_ssi_flags_has(ssi, RSND_SSI_HDMI1)) return RSND_SSI_HDMI_PORT1;
return 0; @@ -132,7 +133,7 @@ int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) if (!rsnd_ssi_is_dma_mode(mod)) return 0;
- if (!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_NO_BUSIF)) + if (!(rsnd_ssi_flags_has(ssi, RSND_SSI_NO_BUSIF))) use_busif = 1; if (rsnd_io_to_mod_src(io)) use_busif = 1; @@ -986,13 +987,13 @@ static void __rsnd_ssi_parse_hdmi_connection(struct rsnd_priv *priv, ssi = rsnd_mod_to_ssi(mod);
if (strstr(remote_ep->full_name, "hdmi0")) { - ssi->flags |= RSND_SSI_HDMI0; + rsnd_ssi_flags_set(ssi, RSND_SSI_HDMI0); dev_dbg(dev, "%s[%d] connected to HDMI0\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); }
if (strstr(remote_ep->full_name, "hdmi1")) { - ssi->flags |= RSND_SSI_HDMI1; + rsnd_ssi_flags_set(ssi, RSND_SSI_HDMI1); dev_dbg(dev, "%s[%d] connected to HDMI1\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); } @@ -1025,7 +1026,7 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
- return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE); + return !!(rsnd_ssi_flags_has(ssi, RSND_SSI_CLK_PIN_SHARE)); }
static u32 *rsnd_ssi_get_status(struct rsnd_dai_stream *io, @@ -1108,10 +1109,10 @@ int rsnd_ssi_probe(struct rsnd_priv *priv) }
if (of_get_property(np, "shared-pin", NULL)) - ssi->flags |= RSND_SSI_CLK_PIN_SHARE; + rsnd_ssi_flags_set(ssi, RSND_SSI_CLK_PIN_SHARE);
if (of_get_property(np, "no-busif", NULL)) - ssi->flags |= RSND_SSI_NO_BUSIF; + rsnd_ssi_flags_set(ssi, RSND_SSI_NO_BUSIF);
ssi->irq = irq_of_parse_and_map(np, 0); if (!ssi->irq) {
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
Each module's dai callback function availability is controlled by mod->status. For example "always called", "call once". In .probe/.remove case, it needs to be called always, because .probe will call xxx_attach() function on .probe, especially if platform is using MIXer. For example, below case, MIX0/DVC0/SSI0 needs to be called twice.
playback = <&src0 &ctu02 &mix0 &dvc0 &ssi0>; playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>;
But in this case, SSI0 will call request_irq() twice. This patch add new RSND_SSI_PROBED flag and control it
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/rcar/ssi.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-)
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index ca9355b..8bb4714 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -90,6 +90,7 @@ struct rsnd_ssi { #define RSND_SSI_NO_BUSIF (1 << 1) /* SSI+DMA without BUSIF */ #define RSND_SSI_HDMI0 (1 << 2) /* for HDMI0 */ #define RSND_SSI_HDMI1 (1 << 3) /* for HDMI1 */ +#define RSND_SSI_PROBED (1 << 4)
#define for_each_rsnd_ssi(pos, priv, i) \ for (i = 0; \ @@ -103,6 +104,7 @@ struct rsnd_ssi { #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) #define rsnd_ssi_flags_has(p, f) ((p)->flags & f) #define rsnd_ssi_flags_set(p, f) ((p)->flags |= f) +#define rsnd_ssi_flags_del(p, f) ((p)->flags = ((p)->flags & ~f)) #define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io)) #define rsnd_ssi_is_multi_slave(mod, io) \ (rsnd_ssi_multi_slaves(io) & (1 << rsnd_mod_id(mod))) @@ -784,11 +786,22 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod, /* * SSI might be called again as PIO fallback * It is easy to manual handling for IRQ request/free + * + * OTOH, this function might be called many times if platform is + * using MIX. It needs xxx_attach() many times on xxx_probe(). + * Because of it, we can't control .probe/.remove calling count by + * mod->status. + * But it don't need to call request_irq() many times. + * Let's control it by RSND_SSI_PROBED flag. */ - ret = request_irq(ssi->irq, - rsnd_ssi_interrupt, - IRQF_SHARED, - dev_name(dev), mod); + if (!rsnd_ssi_flags_has(ssi, RSND_SSI_PROBED)) { + ret = request_irq(ssi->irq, + rsnd_ssi_interrupt, + IRQF_SHARED, + dev_name(dev), mod); + + rsnd_ssi_flags_set(ssi, RSND_SSI_PROBED); + }
return ret; } @@ -805,7 +818,11 @@ static int rsnd_ssi_common_remove(struct rsnd_mod *mod, return 0;
/* PIO will request IRQ again */ - free_irq(ssi->irq, mod); + if (rsnd_ssi_flags_has(ssi, RSND_SSI_PROBED)) { + free_irq(ssi->irq, mod); + + rsnd_ssi_flags_del(ssi, RSND_SSI_PROBED); + }
return 0; }
The patch
ASoC: rsnd: call request_irq/free_irq once in MIX case
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From b6e58fcacb3edc6245ecf700207ba675cba18018 Mon Sep 17 00:00:00 2001
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com Date: Thu, 10 Aug 2017 00:07:38 +0000 Subject: [PATCH] ASoC: rsnd: call request_irq/free_irq once in MIX case
Each module's dai callback function availability is controlled by mod->status. For example "always called", "call once". In .probe/.remove case, it needs to be called always, because .probe will call xxx_attach() function on .probe, especially if platform is using MIXer. For example, below case, MIX0/DVC0/SSI0 needs to be called twice.
playback = <&src0 &ctu02 &mix0 &dvc0 &ssi0>; playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>;
But in this case, SSI0 will call request_irq() twice. This patch add new RSND_SSI_PROBED flag and control it
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sh/rcar/ssi.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-)
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index ca9355b86bd9..8bb47144660b 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -90,6 +90,7 @@ struct rsnd_ssi { #define RSND_SSI_NO_BUSIF (1 << 1) /* SSI+DMA without BUSIF */ #define RSND_SSI_HDMI0 (1 << 2) /* for HDMI0 */ #define RSND_SSI_HDMI1 (1 << 3) /* for HDMI1 */ +#define RSND_SSI_PROBED (1 << 4)
#define for_each_rsnd_ssi(pos, priv, i) \ for (i = 0; \ @@ -103,6 +104,7 @@ struct rsnd_ssi { #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) #define rsnd_ssi_flags_has(p, f) ((p)->flags & f) #define rsnd_ssi_flags_set(p, f) ((p)->flags |= f) +#define rsnd_ssi_flags_del(p, f) ((p)->flags = ((p)->flags & ~f)) #define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io)) #define rsnd_ssi_is_multi_slave(mod, io) \ (rsnd_ssi_multi_slaves(io) & (1 << rsnd_mod_id(mod))) @@ -784,11 +786,22 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod, /* * SSI might be called again as PIO fallback * It is easy to manual handling for IRQ request/free + * + * OTOH, this function might be called many times if platform is + * using MIX. It needs xxx_attach() many times on xxx_probe(). + * Because of it, we can't control .probe/.remove calling count by + * mod->status. + * But it don't need to call request_irq() many times. + * Let's control it by RSND_SSI_PROBED flag. */ - ret = request_irq(ssi->irq, - rsnd_ssi_interrupt, - IRQF_SHARED, - dev_name(dev), mod); + if (!rsnd_ssi_flags_has(ssi, RSND_SSI_PROBED)) { + ret = request_irq(ssi->irq, + rsnd_ssi_interrupt, + IRQF_SHARED, + dev_name(dev), mod); + + rsnd_ssi_flags_set(ssi, RSND_SSI_PROBED); + }
return ret; } @@ -805,7 +818,11 @@ static int rsnd_ssi_common_remove(struct rsnd_mod *mod, return 0;
/* PIO will request IRQ again */ - free_irq(ssi->irq, mod); + if (rsnd_ssi_flags_has(ssi, RSND_SSI_PROBED)) { + free_irq(ssi->irq, mod); + + rsnd_ssi_flags_del(ssi, RSND_SSI_PROBED); + }
return 0; }
participants (2)
-
Kuninori Morimoto
-
Mark Brown