ASoC: rsnd: call clk_prepare/unprepare() in probe/remove
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Thu, 26 Mar 2015 04:02:09 +0000 (04:02 +0000)
committerMark Brown <broonie@kernel.org>
Fri, 27 Mar 2015 22:59:17 +0000 (15:59 -0700)
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>
sound/soc/sh/rcar/core.c
sound/soc/sh/rcar/dvc.c
sound/soc/sh/rcar/rsnd.h
sound/soc/sh/rcar/src.c
sound/soc/sh/rcar/ssi.c

index 1b53605f7154394d1746cb0a692953e296848c2a..6046c10ef3c7f94d9f192ce3c8a48cb59c0cc6dc 100644 (file)
@@ -149,16 +149,29 @@ char *rsnd_mod_dma_name(struct rsnd_mod *mod)
        return mod->ops->dma_name(mod);
 }
 
-void rsnd_mod_init(struct rsnd_mod *mod,
+int rsnd_mod_init(struct rsnd_mod *mod,
                   struct rsnd_mod_ops *ops,
                   struct clk *clk,
                   enum rsnd_mod_type type,
                   int id)
 {
+       int ret = clk_prepare(clk);
+
+       if (ret)
+               return ret;
+
        mod->id         = id;
        mod->ops        = ops;
        mod->type       = type;
        mod->clk        = clk;
+
+       return ret;
+}
+
+void rsnd_mod_quit(struct rsnd_mod *mod)
+{
+       if (mod->clk)
+               clk_unprepare(mod->clk);
 }
 
 /*
@@ -1290,6 +1303,12 @@ static int rsnd_remove(struct platform_device *pdev)
 {
        struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev);
        struct rsnd_dai *rdai;
+       void (*remove_func[])(struct platform_device *pdev,
+                             struct rsnd_priv *priv) = {
+               rsnd_ssi_remove,
+               rsnd_src_remove,
+               rsnd_dvc_remove,
+       };
        int ret = 0, i;
 
        pm_runtime_disable(&pdev->dev);
@@ -1299,6 +1318,9 @@ static int rsnd_remove(struct platform_device *pdev)
                ret |= rsnd_dai_call(remove, &rdai->capture, priv);
        }
 
+       for (i = 0; i < ARRAY_SIZE(remove_func); i++)
+               remove_func[i](pdev, priv);
+
        snd_soc_unregister_component(&pdev->dev);
        snd_soc_unregister_platform(&pdev->dev);
 
index d7f9ed959c4e208a8126174f76daee5a79af133f..261997a3f5899d0b3ed357211181eeb00bf7310c 100644 (file)
@@ -333,7 +333,7 @@ int rsnd_dvc_probe(struct platform_device *pdev,
        struct rsnd_dvc *dvc;
        struct clk *clk;
        char name[RSND_DVC_NAME_SIZE];
-       int i, nr;
+       int i, nr, ret;
 
        rsnd_of_parse_dvc(pdev, of_data, priv);
 
@@ -366,11 +366,24 @@ int rsnd_dvc_probe(struct platform_device *pdev,
 
                dvc->info = &info->dvc_info[i];
 
-               rsnd_mod_init(&dvc->mod, &rsnd_dvc_ops,
+               ret = rsnd_mod_init(&dvc->mod, &rsnd_dvc_ops,
                              clk, RSND_MOD_DVC, i);
+               if (ret)
+                       return ret;
 
                dev_dbg(dev, "CMD%d probed\n", i);
        }
 
        return 0;
 }
+
+void rsnd_dvc_remove(struct platform_device *pdev,
+                    struct rsnd_priv *priv)
+{
+       struct rsnd_dvc *dvc;
+       int i;
+
+       for_each_rsnd_dvc(dvc, priv, i) {
+               rsnd_mod_quit(&dvc->mod);
+       }
+}
index e7914bd610e2120644f616e6500bdf3ad9ec24d3..1bccc5515b5a9bbbb2e7c57255aa6a9707b11593 100644 (file)
@@ -260,14 +260,15 @@ struct rsnd_mod {
 #define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma)
 #define rsnd_mod_to_io(mod) ((mod)->io)
 #define rsnd_mod_id(mod) ((mod)->id)
-#define rsnd_mod_hw_start(mod) clk_prepare_enable((mod)->clk)
-#define rsnd_mod_hw_stop(mod)  clk_disable_unprepare((mod)->clk)
+#define rsnd_mod_hw_start(mod) clk_enable((mod)->clk)
+#define rsnd_mod_hw_stop(mod)  clk_disable((mod)->clk)
 
-void rsnd_mod_init(struct rsnd_mod *mod,
+int rsnd_mod_init(struct rsnd_mod *mod,
                   struct rsnd_mod_ops *ops,
                   struct clk *clk,
                   enum rsnd_mod_type type,
                   int id);
+void rsnd_mod_quit(struct rsnd_mod *mod);
 char *rsnd_mod_name(struct rsnd_mod *mod);
 char *rsnd_mod_dma_name(struct rsnd_mod *mod);
 
@@ -480,6 +481,8 @@ int rsnd_kctrl_new_e(struct rsnd_mod *mod,
 int rsnd_src_probe(struct platform_device *pdev,
                   const struct rsnd_of_data *of_data,
                   struct rsnd_priv *priv);
+void rsnd_src_remove(struct platform_device *pdev,
+                    struct rsnd_priv *priv);
 struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id);
 unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
                                   struct rsnd_dai_stream *io,
@@ -498,6 +501,8 @@ int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod);
 int rsnd_ssi_probe(struct platform_device *pdev,
                   const struct rsnd_of_data *of_data,
                   struct rsnd_priv *priv);
+void rsnd_ssi_remove(struct platform_device *pdev,
+                    struct rsnd_priv *priv);
 struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
 int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
 int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
index 81c182b4bad531c8afe3a071da4c9ad41c4d868f..c77d059edc84ce0b63dbd2e82414864d91edf956 100644 (file)
@@ -850,7 +850,7 @@ int rsnd_src_probe(struct platform_device *pdev,
        struct rsnd_mod_ops *ops;
        struct clk *clk;
        char name[RSND_SRC_NAME_SIZE];
-       int i, nr;
+       int i, nr, ret;
 
        ops = NULL;
        if (rsnd_is_gen1(priv))
@@ -890,10 +890,23 @@ int rsnd_src_probe(struct platform_device *pdev,
 
                src->info = &info->src_info[i];
 
-               rsnd_mod_init(&src->mod, ops, clk, RSND_MOD_SRC, i);
+               ret = rsnd_mod_init(&src->mod, ops, clk, RSND_MOD_SRC, i);
+               if (ret)
+                       return ret;
 
                dev_dbg(dev, "SRC%d probed\n", i);
        }
 
        return 0;
 }
+
+void rsnd_src_remove(struct platform_device *pdev,
+                    struct rsnd_priv *priv)
+{
+       struct rsnd_src *src;
+       int i;
+
+       for_each_rsnd_src(src, priv, i) {
+               rsnd_mod_quit(&src->mod);
+       }
+}
index 9e7b627c08e2256dbe09acd063432b7b3b7c1107..f7cb1fd635a0eb32e9e17f82e411356fea3532d7 100644 (file)
@@ -697,7 +697,7 @@ int rsnd_ssi_probe(struct platform_device *pdev,
        struct clk *clk;
        struct rsnd_ssi *ssi;
        char name[RSND_SSI_NAME_SIZE];
-       int i, nr;
+       int i, nr, ret;
 
        rsnd_of_parse_ssi(pdev, of_data, priv);
 
@@ -732,10 +732,23 @@ int rsnd_ssi_probe(struct platform_device *pdev,
                else if (rsnd_ssi_pio_available(ssi))
                        ops = &rsnd_ssi_pio_ops;
 
-               rsnd_mod_init(&ssi->mod, ops, clk, RSND_MOD_SSI, i);
+               ret = rsnd_mod_init(&ssi->mod, ops, clk, RSND_MOD_SSI, i);
+               if (ret)
+                       return ret;
 
                rsnd_ssi_parent_clk_setup(priv, ssi);
        }
 
        return 0;
 }
+
+void rsnd_ssi_remove(struct platform_device *pdev,
+                    struct rsnd_priv *priv)
+{
+       struct rsnd_ssi *ssi;
+       int i;
+
+       for_each_rsnd_ssi(ssi, priv, i) {
+               rsnd_mod_quit(&ssi->mod);
+       }
+}