Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux...
[firefly-linux-kernel-4.4.55.git] / sound / soc / sh / rcar / core.c
index e8e585de7251ed8bae10b3d64bc6f68cc79e9728..215b668166be6c50d01963cac2ef62598cf6f7b2 100644 (file)
  *   |  +- ssi[2]
  *   |  ...
  *   |
- *   | ** these control scu
+ *   | ** these control src
  *   |
- *   +- scu
+ *   +- src
  *      |
- *      +- scu[0]
- *      +- scu[1]
- *      +- scu[2]
+ *      +- src[0]
+ *      +- src[1]
+ *      +- src[2]
  *      ...
  *
  *
 #define RSND_RATES SNDRV_PCM_RATE_8000_96000
 #define RSND_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
 
+static struct rsnd_of_data rsnd_of_data_gen1 = {
+       .flags = RSND_GEN1,
+};
+
+static struct rsnd_of_data rsnd_of_data_gen2 = {
+       .flags = RSND_GEN2,
+};
+
+static struct of_device_id rsnd_of_match[] = {
+       { .compatible = "renesas,rcar_sound-gen1", .data = &rsnd_of_data_gen1 },
+       { .compatible = "renesas,rcar_sound-gen2", .data = &rsnd_of_data_gen2 },
+       {},
+};
+MODULE_DEVICE_TABLE(of, rsnd_of_match);
+
 /*
  *     rsnd_platform functions
  */
@@ -348,14 +363,6 @@ static int rsnd_dai_connect(struct rsnd_mod *mod,
        return 0;
 }
 
-static int rsnd_dai_disconnect(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
-{
-       io->mod[mod->type] = NULL;
-       mod->io = NULL;
-
-       return 0;
-}
-
 int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai)
 {
        int id = rdai - priv->rdai;
@@ -518,10 +525,10 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        /* set master/slave audio interface */
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBM_CFM:
-               rdai->clk_master = 1;
+               rdai->clk_master = 0;
                break;
        case SND_SOC_DAIFMT_CBS_CFS:
-               rdai->clk_master = 0;
+               rdai->clk_master = 1; /* codec is slave, cpu is master */
                break;
        default:
                return -EINVAL;
@@ -580,7 +587,7 @@ static int rsnd_path_init(struct rsnd_priv *priv,
        struct rsnd_dai_platform_info *dai_info = rdai->info;
        int ret;
        int ssi_id = -1;
-       int scu_id = -1;
+       int src_id = -1;
 
        /*
         * Gen1 is created by SRU/SSI, and this SRU is base module of
@@ -595,8 +602,8 @@ static int rsnd_path_init(struct rsnd_priv *priv,
        if (dai_info) {
                if (rsnd_is_enable_path(io, ssi))
                        ssi_id = rsnd_info_id(priv, io, ssi);
-               if (rsnd_is_enable_path(io, scu))
-                       scu_id = rsnd_info_id(priv, io, scu);
+               if (rsnd_is_enable_path(io, src))
+                       src_id = rsnd_info_id(priv, io, src);
        } else {
                /* get SSI's ID */
                mod = rsnd_ssi_mod_get_frm_dai(priv,
@@ -604,14 +611,14 @@ static int rsnd_path_init(struct rsnd_priv *priv,
                                               rsnd_dai_is_play(rdai, io));
                if (!mod)
                        return 0;
-               ssi_id = scu_id = rsnd_mod_id(mod);
+               ssi_id = src_id = rsnd_mod_id(mod);
        }
 
        ret = 0;
 
-       /* SCU */
-       if (scu_id >= 0) {
-               mod = rsnd_scu_mod_get(priv, scu_id);
+       /* SRC */
+       if (src_id >= 0) {
+               mod = rsnd_src_mod_get(priv, src_id);
                ret = rsnd_dai_connect(mod, io);
                if (ret < 0)
                        return ret;
@@ -628,27 +635,92 @@ static int rsnd_path_init(struct rsnd_priv *priv,
        return ret;
 }
 
-static int rsnd_path_exit(struct rsnd_priv *priv,
-                         struct rsnd_dai *rdai,
-                         struct rsnd_dai_stream *io)
+static void rsnd_of_parse_dai(struct platform_device *pdev,
+                             const struct rsnd_of_data *of_data,
+                             struct rsnd_priv *priv)
 {
-       struct rsnd_mod *mod;
-       int ret = 0, i;
+       struct device_node *dai_node,   *dai_np;
+       struct device_node *ssi_node,   *ssi_np;
+       struct device_node *src_node,   *src_np;
+       struct device_node *playback, *capture;
+       struct rsnd_dai_platform_info *dai_info;
+       struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+       struct device *dev = &pdev->dev;
+       int nr, i;
+       int dai_i, ssi_i, src_i;
+
+       if (!of_data)
+               return;
+
+       dai_node = of_get_child_by_name(dev->of_node, "rcar_sound,dai");
+       if (!dai_node)
+               return;
+
+       nr = of_get_child_count(dai_node);
+       if (!nr)
+               return;
+
+       dai_info = devm_kzalloc(dev,
+                               sizeof(struct rsnd_dai_platform_info) * nr,
+                               GFP_KERNEL);
+       if (!dai_info) {
+               dev_err(dev, "dai info allocation error\n");
+               return;
+       }
+
+       info->dai_info_nr       = nr;
+       info->dai_info          = dai_info;
+
+       ssi_node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi");
+       src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src");
+
+#define mod_parse(name)                                                        \
+if (name##_node) {                                                     \
+       struct rsnd_##name##_platform_info *name##_info;                \
+                                                                       \
+       name##_i = 0;                                                   \
+       for_each_child_of_node(name##_node, name##_np) {                \
+               name##_info = info->name##_info + name##_i;             \
+                                                                       \
+               if (name##_np == playback)                              \
+                       dai_info->playback.name = name##_info;          \
+               if (name##_np == capture)                               \
+                       dai_info->capture.name = name##_info;           \
+                                                                       \
+               name##_i++;                                             \
+       }                                                               \
+}
 
        /*
-        * remove all mod from rdai
+        * parse all dai
         */
-       for (i = 0; i < RSND_MOD_MAX; i++) {
-               mod = io->mod[i];
-               if (!mod)
-                       continue;
-               ret |= rsnd_dai_disconnect(mod, io);
-       }
+       dai_i = 0;
+       for_each_child_of_node(dai_node, dai_np) {
+               dai_info = info->dai_info + dai_i;
 
-       return ret;
+               for (i = 0;; i++) {
+
+                       playback = of_parse_phandle(dai_np, "playback", i);
+                       capture  = of_parse_phandle(dai_np, "capture", i);
+
+                       if (!playback && !capture)
+                               break;
+
+                       mod_parse(ssi);
+                       mod_parse(src);
+
+                       if (playback)
+                               of_node_put(playback);
+                       if (capture)
+                               of_node_put(capture);
+               }
+
+               dai_i++;
+       }
 }
 
 static int rsnd_dai_probe(struct platform_device *pdev,
+                         const struct rsnd_of_data *of_data,
                          struct rsnd_priv *priv)
 {
        struct snd_soc_dai_driver *drv;
@@ -656,13 +728,16 @@ static int rsnd_dai_probe(struct platform_device *pdev,
        struct rsnd_dai *rdai;
        struct rsnd_mod *pmod, *cmod;
        struct device *dev = rsnd_priv_to_dev(priv);
-       int dai_nr = info->dai_info_nr;
+       int dai_nr;
        int i;
 
+       rsnd_of_parse_dai(pdev, of_data, priv);
+
        /*
         * dai_nr should be set via dai_info_nr,
         * but allow it to keeping compatible
         */
+       dai_nr = info->dai_info_nr;
        if (!dai_nr) {
                /* get max dai nr */
                for (dai_nr = 0; dai_nr < 32; dai_nr++) {
@@ -736,19 +811,6 @@ static int rsnd_dai_probe(struct platform_device *pdev,
        return 0;
 }
 
-static void rsnd_dai_remove(struct platform_device *pdev,
-                         struct rsnd_priv *priv)
-{
-       struct rsnd_dai *rdai;
-       int i;
-
-       for (i = 0; i < rsnd_rdai_nr(priv); i++) {
-               rdai = rsnd_dai_get(priv, i);
-               rsnd_path_exit(priv, rdai, &rdai->playback);
-               rsnd_path_exit(priv, rdai, &rdai->capture);
-       }
-}
-
 /*
  *             pcm ops
  */
@@ -843,17 +905,29 @@ static int rsnd_probe(struct platform_device *pdev)
        struct rsnd_priv *priv;
        struct device *dev = &pdev->dev;
        struct rsnd_dai *rdai;
+       const struct of_device_id *of_id = of_match_device(rsnd_of_match, dev);
+       const struct rsnd_of_data *of_data;
        int (*probe_func[])(struct platform_device *pdev,
+                           const struct rsnd_of_data *of_data,
                            struct rsnd_priv *priv) = {
                rsnd_gen_probe,
                rsnd_ssi_probe,
-               rsnd_scu_probe,
+               rsnd_src_probe,
                rsnd_adg_probe,
                rsnd_dai_probe,
        };
        int ret, i;
 
-       info = pdev->dev.platform_data;
+       info = NULL;
+       of_data = NULL;
+       if (of_id) {
+               info = devm_kzalloc(&pdev->dev,
+                                   sizeof(struct rcar_snd_info), GFP_KERNEL);
+               of_data = of_id->data;
+       } else {
+               info = pdev->dev.platform_data;
+       }
+
        if (!info) {
                dev_err(dev, "driver needs R-Car sound information\n");
                return -ENODEV;
@@ -876,7 +950,7 @@ static int rsnd_probe(struct platform_device *pdev)
         *      init each module
         */
        for (i = 0; i < ARRAY_SIZE(probe_func); i++) {
-               ret = probe_func[i](pdev, priv);
+               ret = probe_func[i](pdev, of_data, priv);
                if (ret)
                        return ret;
        }
@@ -938,21 +1012,13 @@ static int rsnd_remove(struct platform_device *pdev)
                        return ret;
        }
 
-       /*
-        *      remove each module
-        */
-       rsnd_ssi_remove(pdev, priv);
-       rsnd_adg_remove(pdev, priv);
-       rsnd_scu_remove(pdev, priv);
-       rsnd_dai_remove(pdev, priv);
-       rsnd_gen_remove(pdev, priv);
-
        return 0;
 }
 
 static struct platform_driver rsnd_driver = {
        .driver = {
                .name   = "rcar_sound",
+               .of_match_table = rsnd_of_match,
        },
        .probe          = rsnd_probe,
        .remove         = rsnd_remove,