diff options
author | Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | 2015-03-26 00:02:09 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2015-03-27 18:59:17 -0400 |
commit | 2f78dd7f40264697afed4c2ac0890df8f0588e49 (patch) | |
tree | 9d37d40fef4bbf1161f9d447def5273d242dbf93 /sound/soc/sh | |
parent | c517d838eb7d07bbe9507871fab3931deccff539 (diff) |
ASoC: rsnd: call clk_prepare/unprepare() in probe/remove
clk_prepare_enable()/clk_disable_unprepare() uses mutex inside,
in concretely clk_prepare()/clk_unprepare().And it uses __schedule().
Then, raw_spin_lock/unlock_irq() is called, and it breaks Renesas
sound driver's spin lock irq.
This patch separates thesse into clk_prepare()/clk_unprepare() and
clk_enable/clk_disable. And call clk_prepare()/clk_unprepare() from
probe/remove function. Special thanks to Das Biju.
Reported-by: Das Biju <biju.das@bp.renesas.com>
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/sh')
-rw-r--r-- | sound/soc/sh/rcar/core.c | 24 | ||||
-rw-r--r-- | sound/soc/sh/rcar/dvc.c | 17 | ||||
-rw-r--r-- | sound/soc/sh/rcar/rsnd.h | 11 | ||||
-rw-r--r-- | sound/soc/sh/rcar/src.c | 17 | ||||
-rw-r--r-- | sound/soc/sh/rcar/ssi.c | 17 |
5 files changed, 76 insertions, 10 deletions
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 1b53605f7154..6046c10ef3c7 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c | |||
@@ -149,16 +149,29 @@ char *rsnd_mod_dma_name(struct rsnd_mod *mod) | |||
149 | return mod->ops->dma_name(mod); | 149 | return mod->ops->dma_name(mod); |
150 | } | 150 | } |
151 | 151 | ||
152 | void rsnd_mod_init(struct rsnd_mod *mod, | 152 | int rsnd_mod_init(struct rsnd_mod *mod, |
153 | struct rsnd_mod_ops *ops, | 153 | struct rsnd_mod_ops *ops, |
154 | struct clk *clk, | 154 | struct clk *clk, |
155 | enum rsnd_mod_type type, | 155 | enum rsnd_mod_type type, |
156 | int id) | 156 | int id) |
157 | { | 157 | { |
158 | int ret = clk_prepare(clk); | ||
159 | |||
160 | if (ret) | ||
161 | return ret; | ||
162 | |||
158 | mod->id = id; | 163 | mod->id = id; |
159 | mod->ops = ops; | 164 | mod->ops = ops; |
160 | mod->type = type; | 165 | mod->type = type; |
161 | mod->clk = clk; | 166 | mod->clk = clk; |
167 | |||
168 | return ret; | ||
169 | } | ||
170 | |||
171 | void rsnd_mod_quit(struct rsnd_mod *mod) | ||
172 | { | ||
173 | if (mod->clk) | ||
174 | clk_unprepare(mod->clk); | ||
162 | } | 175 | } |
163 | 176 | ||
164 | /* | 177 | /* |
@@ -1290,6 +1303,12 @@ static int rsnd_remove(struct platform_device *pdev) | |||
1290 | { | 1303 | { |
1291 | struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev); | 1304 | struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev); |
1292 | struct rsnd_dai *rdai; | 1305 | struct rsnd_dai *rdai; |
1306 | void (*remove_func[])(struct platform_device *pdev, | ||
1307 | struct rsnd_priv *priv) = { | ||
1308 | rsnd_ssi_remove, | ||
1309 | rsnd_src_remove, | ||
1310 | rsnd_dvc_remove, | ||
1311 | }; | ||
1293 | int ret = 0, i; | 1312 | int ret = 0, i; |
1294 | 1313 | ||
1295 | pm_runtime_disable(&pdev->dev); | 1314 | pm_runtime_disable(&pdev->dev); |
@@ -1299,6 +1318,9 @@ static int rsnd_remove(struct platform_device *pdev) | |||
1299 | ret |= rsnd_dai_call(remove, &rdai->capture, priv); | 1318 | ret |= rsnd_dai_call(remove, &rdai->capture, priv); |
1300 | } | 1319 | } |
1301 | 1320 | ||
1321 | for (i = 0; i < ARRAY_SIZE(remove_func); i++) | ||
1322 | remove_func[i](pdev, priv); | ||
1323 | |||
1302 | snd_soc_unregister_component(&pdev->dev); | 1324 | snd_soc_unregister_component(&pdev->dev); |
1303 | snd_soc_unregister_platform(&pdev->dev); | 1325 | snd_soc_unregister_platform(&pdev->dev); |
1304 | 1326 | ||
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index d7f9ed959c4e..261997a3f589 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c | |||
@@ -333,7 +333,7 @@ int rsnd_dvc_probe(struct platform_device *pdev, | |||
333 | struct rsnd_dvc *dvc; | 333 | struct rsnd_dvc *dvc; |
334 | struct clk *clk; | 334 | struct clk *clk; |
335 | char name[RSND_DVC_NAME_SIZE]; | 335 | char name[RSND_DVC_NAME_SIZE]; |
336 | int i, nr; | 336 | int i, nr, ret; |
337 | 337 | ||
338 | rsnd_of_parse_dvc(pdev, of_data, priv); | 338 | rsnd_of_parse_dvc(pdev, of_data, priv); |
339 | 339 | ||
@@ -366,11 +366,24 @@ int rsnd_dvc_probe(struct platform_device *pdev, | |||
366 | 366 | ||
367 | dvc->info = &info->dvc_info[i]; | 367 | dvc->info = &info->dvc_info[i]; |
368 | 368 | ||
369 | rsnd_mod_init(&dvc->mod, &rsnd_dvc_ops, | 369 | ret = rsnd_mod_init(&dvc->mod, &rsnd_dvc_ops, |
370 | clk, RSND_MOD_DVC, i); | 370 | clk, RSND_MOD_DVC, i); |
371 | if (ret) | ||
372 | return ret; | ||
371 | 373 | ||
372 | dev_dbg(dev, "CMD%d probed\n", i); | 374 | dev_dbg(dev, "CMD%d probed\n", i); |
373 | } | 375 | } |
374 | 376 | ||
375 | return 0; | 377 | return 0; |
376 | } | 378 | } |
379 | |||
380 | void rsnd_dvc_remove(struct platform_device *pdev, | ||
381 | struct rsnd_priv *priv) | ||
382 | { | ||
383 | struct rsnd_dvc *dvc; | ||
384 | int i; | ||
385 | |||
386 | for_each_rsnd_dvc(dvc, priv, i) { | ||
387 | rsnd_mod_quit(&dvc->mod); | ||
388 | } | ||
389 | } | ||
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index e7914bd610e2..1bccc5515b5a 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h | |||
@@ -260,14 +260,15 @@ struct rsnd_mod { | |||
260 | #define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma) | 260 | #define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma) |
261 | #define rsnd_mod_to_io(mod) ((mod)->io) | 261 | #define rsnd_mod_to_io(mod) ((mod)->io) |
262 | #define rsnd_mod_id(mod) ((mod)->id) | 262 | #define rsnd_mod_id(mod) ((mod)->id) |
263 | #define rsnd_mod_hw_start(mod) clk_prepare_enable((mod)->clk) | 263 | #define rsnd_mod_hw_start(mod) clk_enable((mod)->clk) |
264 | #define rsnd_mod_hw_stop(mod) clk_disable_unprepare((mod)->clk) | 264 | #define rsnd_mod_hw_stop(mod) clk_disable((mod)->clk) |
265 | 265 | ||
266 | void rsnd_mod_init(struct rsnd_mod *mod, | 266 | int rsnd_mod_init(struct rsnd_mod *mod, |
267 | struct rsnd_mod_ops *ops, | 267 | struct rsnd_mod_ops *ops, |
268 | struct clk *clk, | 268 | struct clk *clk, |
269 | enum rsnd_mod_type type, | 269 | enum rsnd_mod_type type, |
270 | int id); | 270 | int id); |
271 | void rsnd_mod_quit(struct rsnd_mod *mod); | ||
271 | char *rsnd_mod_name(struct rsnd_mod *mod); | 272 | char *rsnd_mod_name(struct rsnd_mod *mod); |
272 | char *rsnd_mod_dma_name(struct rsnd_mod *mod); | 273 | char *rsnd_mod_dma_name(struct rsnd_mod *mod); |
273 | 274 | ||
@@ -480,6 +481,8 @@ int rsnd_kctrl_new_e(struct rsnd_mod *mod, | |||
480 | int rsnd_src_probe(struct platform_device *pdev, | 481 | int rsnd_src_probe(struct platform_device *pdev, |
481 | const struct rsnd_of_data *of_data, | 482 | const struct rsnd_of_data *of_data, |
482 | struct rsnd_priv *priv); | 483 | struct rsnd_priv *priv); |
484 | void rsnd_src_remove(struct platform_device *pdev, | ||
485 | struct rsnd_priv *priv); | ||
483 | struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id); | 486 | struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id); |
484 | unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, | 487 | unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, |
485 | struct rsnd_dai_stream *io, | 488 | struct rsnd_dai_stream *io, |
@@ -498,6 +501,8 @@ int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod); | |||
498 | int rsnd_ssi_probe(struct platform_device *pdev, | 501 | int rsnd_ssi_probe(struct platform_device *pdev, |
499 | const struct rsnd_of_data *of_data, | 502 | const struct rsnd_of_data *of_data, |
500 | struct rsnd_priv *priv); | 503 | struct rsnd_priv *priv); |
504 | void rsnd_ssi_remove(struct platform_device *pdev, | ||
505 | struct rsnd_priv *priv); | ||
501 | struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); | 506 | struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); |
502 | int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); | 507 | int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); |
503 | int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); | 508 | int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); |
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 81c182b4bad5..c77d059edc84 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c | |||
@@ -850,7 +850,7 @@ int rsnd_src_probe(struct platform_device *pdev, | |||
850 | struct rsnd_mod_ops *ops; | 850 | struct rsnd_mod_ops *ops; |
851 | struct clk *clk; | 851 | struct clk *clk; |
852 | char name[RSND_SRC_NAME_SIZE]; | 852 | char name[RSND_SRC_NAME_SIZE]; |
853 | int i, nr; | 853 | int i, nr, ret; |
854 | 854 | ||
855 | ops = NULL; | 855 | ops = NULL; |
856 | if (rsnd_is_gen1(priv)) | 856 | if (rsnd_is_gen1(priv)) |
@@ -890,10 +890,23 @@ int rsnd_src_probe(struct platform_device *pdev, | |||
890 | 890 | ||
891 | src->info = &info->src_info[i]; | 891 | src->info = &info->src_info[i]; |
892 | 892 | ||
893 | rsnd_mod_init(&src->mod, ops, clk, RSND_MOD_SRC, i); | 893 | ret = rsnd_mod_init(&src->mod, ops, clk, RSND_MOD_SRC, i); |
894 | if (ret) | ||
895 | return ret; | ||
894 | 896 | ||
895 | dev_dbg(dev, "SRC%d probed\n", i); | 897 | dev_dbg(dev, "SRC%d probed\n", i); |
896 | } | 898 | } |
897 | 899 | ||
898 | return 0; | 900 | return 0; |
899 | } | 901 | } |
902 | |||
903 | void rsnd_src_remove(struct platform_device *pdev, | ||
904 | struct rsnd_priv *priv) | ||
905 | { | ||
906 | struct rsnd_src *src; | ||
907 | int i; | ||
908 | |||
909 | for_each_rsnd_src(src, priv, i) { | ||
910 | rsnd_mod_quit(&src->mod); | ||
911 | } | ||
912 | } | ||
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 9e7b627c08e2..f7cb1fd635a0 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c | |||
@@ -697,7 +697,7 @@ int rsnd_ssi_probe(struct platform_device *pdev, | |||
697 | struct clk *clk; | 697 | struct clk *clk; |
698 | struct rsnd_ssi *ssi; | 698 | struct rsnd_ssi *ssi; |
699 | char name[RSND_SSI_NAME_SIZE]; | 699 | char name[RSND_SSI_NAME_SIZE]; |
700 | int i, nr; | 700 | int i, nr, ret; |
701 | 701 | ||
702 | rsnd_of_parse_ssi(pdev, of_data, priv); | 702 | rsnd_of_parse_ssi(pdev, of_data, priv); |
703 | 703 | ||
@@ -732,10 +732,23 @@ int rsnd_ssi_probe(struct platform_device *pdev, | |||
732 | else if (rsnd_ssi_pio_available(ssi)) | 732 | else if (rsnd_ssi_pio_available(ssi)) |
733 | ops = &rsnd_ssi_pio_ops; | 733 | ops = &rsnd_ssi_pio_ops; |
734 | 734 | ||
735 | rsnd_mod_init(&ssi->mod, ops, clk, RSND_MOD_SSI, i); | 735 | ret = rsnd_mod_init(&ssi->mod, ops, clk, RSND_MOD_SSI, i); |
736 | if (ret) | ||
737 | return ret; | ||
736 | 738 | ||
737 | rsnd_ssi_parent_clk_setup(priv, ssi); | 739 | rsnd_ssi_parent_clk_setup(priv, ssi); |
738 | } | 740 | } |
739 | 741 | ||
740 | return 0; | 742 | return 0; |
741 | } | 743 | } |
744 | |||
745 | void rsnd_ssi_remove(struct platform_device *pdev, | ||
746 | struct rsnd_priv *priv) | ||
747 | { | ||
748 | struct rsnd_ssi *ssi; | ||
749 | int i; | ||
750 | |||
751 | for_each_rsnd_ssi(ssi, priv, i) { | ||
752 | rsnd_mod_quit(&ssi->mod); | ||
753 | } | ||
754 | } | ||