Merge branch 'topic/sh' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
authorMark Brown <broonie@kernel.org>
Mon, 14 Aug 2017 16:53:16 +0000 (17:53 +0100)
committerMark Brown <broonie@kernel.org>
Mon, 14 Aug 2017 16:53:16 +0000 (17:53 +0100)
sound/soc/sh/rcar/adg.c
sound/soc/sh/rcar/core.c
sound/soc/sh/rcar/ctu.c
sound/soc/sh/rcar/dvc.c
sound/soc/sh/rcar/gen.c
sound/soc/sh/rcar/mix.c
sound/soc/sh/rcar/rsnd.h
sound/soc/sh/rcar/src.c
sound/soc/sh/rcar/ssi.c
sound/soc/sh/rcar/ssiu.c

index 197cb3ec075f3de5905d4ccf002b0700311154e0..938baff86ef280a9b6f6d93a4e4e7283a3ea9eb8 100644 (file)
@@ -586,10 +586,8 @@ int rsnd_adg_probe(struct rsnd_priv *priv)
        int ret;
 
        adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL);
-       if (!adg) {
-               dev_err(dev, "ADG allocate failed\n");
+       if (!adg)
                return -ENOMEM;
-       }
 
        ret = rsnd_mod_init(priv, &adg->mod, &adg_ops,
                      NULL, NULL, 0, 0);
@@ -610,6 +608,13 @@ void rsnd_adg_remove(struct rsnd_priv *priv)
 {
        struct device *dev = rsnd_priv_to_dev(priv);
        struct device_node *np = dev->of_node;
+       struct rsnd_adg *adg = priv->adg;
+       struct clk *clk;
+       int i;
+
+       for_each_rsnd_clkout(clk, adg, i)
+               if (adg->clkout[i])
+                       clk_unregister_fixed_rate(adg->clkout[i]);
 
        of_clk_del_provider(np);
 
index 08f3a06978e102107882d2ab1fd86f81bcdd4ddb..df39831b8e8f44ffb21b51ca004deb01695c7c54 100644 (file)
@@ -726,7 +726,6 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
        case 2:
        case 6:
        case 8:
-       case 16:
                /* TDM Extend Mode */
                rsnd_rdai_channels_set(rdai, slots);
                rsnd_rdai_ssi_lane_set(rdai, 1);
@@ -740,7 +739,7 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
 }
 
 static unsigned int rsnd_soc_hw_channels_list[] = {
-       2, 6, 8, 16,
+       2, 6, 8,
 };
 
 static unsigned int rsnd_soc_hw_rate_list[] = {
@@ -844,12 +843,28 @@ static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params,
                                ir, &ic);
 }
 
-static void rsnd_soc_hw_constraint(struct snd_pcm_runtime *runtime,
-                                  struct snd_soc_dai *dai)
+static struct snd_pcm_hardware rsnd_pcm_hardware = {
+       .info =         SNDRV_PCM_INFO_INTERLEAVED      |
+                       SNDRV_PCM_INFO_MMAP             |
+                       SNDRV_PCM_INFO_MMAP_VALID,
+       .buffer_bytes_max       = 64 * 1024,
+       .period_bytes_min       = 32,
+       .period_bytes_max       = 8192,
+       .periods_min            = 1,
+       .periods_max            = 32,
+       .fifo_size              = 256,
+};
+
+static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
 {
        struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+       struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+       struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
        struct snd_pcm_hw_constraint_list *constraint = &rdai->constraint;
+       struct snd_pcm_runtime *runtime = substream->runtime;
        unsigned int max_channels = rsnd_rdai_channels_get(rdai);
+       int ret;
        int i;
 
        /*
@@ -866,34 +881,26 @@ static void rsnd_soc_hw_constraint(struct snd_pcm_runtime *runtime,
                constraint->count = i + 1;
        }
 
+       snd_soc_set_runtime_hwparams(substream, &rsnd_pcm_hardware);
+
        snd_pcm_hw_constraint_list(runtime, 0,
                                   SNDRV_PCM_HW_PARAM_CHANNELS, constraint);
 
+       snd_pcm_hw_constraint_integer(runtime,
+                                     SNDRV_PCM_HW_PARAM_PERIODS);
+
        /*
         * Sampling Rate / Channel Limitation
         * It depends on Clock Master Mode
         */
-       if (!rsnd_rdai_is_clk_master(rdai))
-               return;
-
-       snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
-                           rsnd_soc_hw_rule_rate, dai,
-                           SNDRV_PCM_HW_PARAM_CHANNELS, -1);
-       snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
-                           rsnd_soc_hw_rule_channels, dai,
-                           SNDRV_PCM_HW_PARAM_RATE, -1);
-}
-
-static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream,
-                               struct snd_soc_dai *dai)
-{
-       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
-       struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
-       struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
-       int ret;
-
-       /* rsnd_io_to_runtime() is not yet enabled here */
-       rsnd_soc_hw_constraint(substream->runtime, dai);
+       if (rsnd_rdai_is_clk_master(rdai)) {
+               snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+                                   rsnd_soc_hw_rule_rate, dai,
+                                   SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+               snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+                                   rsnd_soc_hw_rule_channels, dai,
+                                   SNDRV_PCM_HW_PARAM_RATE, -1);
+       }
 
        /*
         * call rsnd_dai_call without spinlock
@@ -1017,7 +1024,7 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
        drv->playback.rates             = RSND_RATES;
        drv->playback.formats           = RSND_FMTS;
        drv->playback.channels_min      = 2;
-       drv->playback.channels_max      = 16;
+       drv->playback.channels_max      = 8;
        drv->playback.stream_name       = rdai->playback.name;
 
        snprintf(rdai->capture.name, RSND_DAI_NAME_SIZE,
@@ -1025,7 +1032,7 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
        drv->capture.rates              = RSND_RATES;
        drv->capture.formats            = RSND_FMTS;
        drv->capture.channels_min       = 2;
-       drv->capture.channels_max       = 16;
+       drv->capture.channels_max       = 8;
        drv->capture.stream_name        = rdai->capture.name;
 
        rdai->playback.rdai             = rdai;
@@ -1105,31 +1112,6 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
 /*
  *             pcm ops
  */
-static struct snd_pcm_hardware rsnd_pcm_hardware = {
-       .info =         SNDRV_PCM_INFO_INTERLEAVED      |
-                       SNDRV_PCM_INFO_MMAP             |
-                       SNDRV_PCM_INFO_MMAP_VALID,
-       .buffer_bytes_max       = 64 * 1024,
-       .period_bytes_min       = 32,
-       .period_bytes_max       = 8192,
-       .periods_min            = 1,
-       .periods_max            = 32,
-       .fifo_size              = 256,
-};
-
-static int rsnd_pcm_open(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       int ret = 0;
-
-       snd_soc_set_runtime_hwparams(substream, &rsnd_pcm_hardware);
-
-       ret = snd_pcm_hw_constraint_integer(runtime,
-                                           SNDRV_PCM_HW_PARAM_PERIODS);
-
-       return ret;
-}
-
 static int rsnd_hw_params(struct snd_pcm_substream *substream,
                         struct snd_pcm_hw_params *hw_params)
 {
@@ -1159,7 +1141,6 @@ static snd_pcm_uframes_t rsnd_pointer(struct snd_pcm_substream *substream)
 }
 
 static const struct snd_pcm_ops rsnd_pcm_ops = {
-       .open           = rsnd_pcm_open,
        .ioctl          = snd_pcm_lib_ioctl,
        .hw_params      = rsnd_hw_params,
        .hw_free        = snd_pcm_lib_free_pages,
@@ -1169,11 +1150,10 @@ static const struct snd_pcm_ops rsnd_pcm_ops = {
 /*
  *             snd_kcontrol
  */
-#define kcontrol_to_cfg(kctrl) ((struct rsnd_kctrl_cfg *)kctrl->private_value)
 static int rsnd_kctrl_info(struct snd_kcontrol *kctrl,
                           struct snd_ctl_elem_info *uinfo)
 {
-       struct rsnd_kctrl_cfg *cfg = kcontrol_to_cfg(kctrl);
+       struct rsnd_kctrl_cfg *cfg = snd_kcontrol_chip(kctrl);
 
        if (cfg->texts) {
                uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
@@ -1199,7 +1179,7 @@ static int rsnd_kctrl_info(struct snd_kcontrol *kctrl,
 static int rsnd_kctrl_get(struct snd_kcontrol *kctrl,
                          struct snd_ctl_elem_value *uc)
 {
-       struct rsnd_kctrl_cfg *cfg = kcontrol_to_cfg(kctrl);
+       struct rsnd_kctrl_cfg *cfg = snd_kcontrol_chip(kctrl);
        int i;
 
        for (i = 0; i < cfg->size; i++)
@@ -1214,8 +1194,7 @@ static int rsnd_kctrl_get(struct snd_kcontrol *kctrl,
 static int rsnd_kctrl_put(struct snd_kcontrol *kctrl,
                          struct snd_ctl_elem_value *uc)
 {
-       struct rsnd_mod *mod = snd_kcontrol_chip(kctrl);
-       struct rsnd_kctrl_cfg *cfg = kcontrol_to_cfg(kctrl);
+       struct rsnd_kctrl_cfg *cfg = snd_kcontrol_chip(kctrl);
        int i, change = 0;
 
        if (!cfg->accept(cfg->io))
@@ -1232,7 +1211,7 @@ static int rsnd_kctrl_put(struct snd_kcontrol *kctrl,
        }
 
        if (change && cfg->update)
-               cfg->update(cfg->io, mod);
+               cfg->update(cfg->io, cfg->mod);
 
        return change;
 }
@@ -1284,14 +1263,13 @@ int rsnd_kctrl_new(struct rsnd_mod *mod,
                .index          = rtd->num,
                .get            = rsnd_kctrl_get,
                .put            = rsnd_kctrl_put,
-               .private_value  = (unsigned long)cfg,
        };
        int ret;
 
        if (size > RSND_MAX_CHANNELS)
                return -EINVAL;
 
-       kctrl = snd_ctl_new1(&knew, mod);
+       kctrl = snd_ctl_new1(&knew, cfg);
        if (!kctrl)
                return -ENOMEM;
 
@@ -1307,6 +1285,7 @@ int rsnd_kctrl_new(struct rsnd_mod *mod,
        cfg->card       = card;
        cfg->kctrl      = kctrl;
        cfg->io         = io;
+       cfg->mod        = mod;
 
        return 0;
 }
@@ -1422,10 +1401,8 @@ static int rsnd_probe(struct platform_device *pdev)
         *      init priv data
         */
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-       if (!priv) {
-               dev_err(dev, "priv allocate failed\n");
+       if (!priv)
                return -ENODEV;
-       }
 
        priv->pdev      = pdev;
        priv->flags     = (unsigned long)of_device_get_match_data(dev);
index 4ba8f2fe7a4c47f08f046de4062e8ff7e9279cc4..e7f53f44165d78b423c56a1623bbc2cfe965e0e6 100644 (file)
@@ -394,13 +394,16 @@ int rsnd_ctu_probe(struct rsnd_priv *priv)
                clk = devm_clk_get(dev, name);
                if (IS_ERR(clk)) {
                        ret = PTR_ERR(clk);
+                       of_node_put(np);
                        goto rsnd_ctu_probe_done;
                }
 
                ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops,
                                    clk, rsnd_mod_get_status, RSND_MOD_CTU, i);
-               if (ret)
+               if (ret) {
+                       of_node_put(np);
                        goto rsnd_ctu_probe_done;
+               }
 
                i++;
        }
index 99d2d9459e755a46f630b36f93611e88c4feeae6..1743ade3cc55563c04204b37b70d57254f41cae8 100644 (file)
@@ -380,13 +380,16 @@ int rsnd_dvc_probe(struct rsnd_priv *priv)
                clk = devm_clk_get(dev, name);
                if (IS_ERR(clk)) {
                        ret = PTR_ERR(clk);
+                       of_node_put(np);
                        goto rsnd_dvc_probe_done;
                }
 
                ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops,
                                    clk, rsnd_mod_get_status, RSND_MOD_DVC, i);
-               if (ret)
+               if (ret) {
+                       of_node_put(np);
                        goto rsnd_dvc_probe_done;
+               }
 
                i++;
        }
index ee00e3516911ef32b6fbdd3113f49776231b96a1..f04c4100043a11f39c68d55bca3c99f8dca6ea04 100644 (file)
@@ -406,10 +406,8 @@ int rsnd_gen_probe(struct rsnd_priv *priv)
        int ret;
 
        gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
-       if (!gen) {
-               dev_err(dev, "GEN allocate failed\n");
+       if (!gen)
                return -ENOMEM;
-       }
 
        priv->gen = gen;
 
index 195fc7bb22afb6519fb574af7b28832d2defda6b..6c4826c189a42d06eec412cf0086b9721faa28be 100644 (file)
@@ -168,13 +168,16 @@ int rsnd_mix_probe(struct rsnd_priv *priv)
                clk = devm_clk_get(dev, name);
                if (IS_ERR(clk)) {
                        ret = PTR_ERR(clk);
+                       of_node_put(np);
                        goto rsnd_mix_probe_done;
                }
 
                ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops,
                                    clk, rsnd_mod_get_status, RSND_MOD_MIX, i);
-               if (ret)
+               if (ret) {
+                       of_node_put(np);
                        goto rsnd_mix_probe_done;
+               }
 
                i++;
        }
index 99c57611df886a0700f7978cb93b5279b7c2498d..c5de71f2dc8c429b9ed3aabab509ded1651b92f9 100644 (file)
@@ -614,6 +614,7 @@ struct rsnd_kctrl_cfg {
        struct rsnd_dai_stream *io;
        struct snd_card *card;
        struct snd_kcontrol *kctrl;
+       struct rsnd_mod *mod;
 };
 
 #define RSND_MAX_CHANNELS      8
index 7aa239e28491525053d4dd957bf2cc4d2f4b056c..8e9a1de0ec251af2b1bb12195cc0ca442db4f80e 100644 (file)
@@ -581,20 +581,24 @@ int rsnd_src_probe(struct rsnd_priv *priv)
                src->irq = irq_of_parse_and_map(np, 0);
                if (!src->irq) {
                        ret = -EINVAL;
+                       of_node_put(np);
                        goto rsnd_src_probe_done;
                }
 
                clk = devm_clk_get(dev, name);
                if (IS_ERR(clk)) {
                        ret = PTR_ERR(clk);
+                       of_node_put(np);
                        goto rsnd_src_probe_done;
                }
 
                ret = rsnd_mod_init(priv, rsnd_mod_get(src),
                                    &rsnd_src_ops, clk, rsnd_mod_get_status,
                                    RSND_MOD_SRC, i);
-               if (ret)
+               if (ret) {
+                       of_node_put(np);
                        goto rsnd_src_probe_done;
+               }
 
 skip:
                i++;
index 46feddd78ee26f0e7fa90e40500914ef5b4edfe3..8bb47144660b0bde92b33c0ea436f56d1cc20ea9 100644 (file)
@@ -72,6 +72,7 @@ struct rsnd_ssi {
        u32 cr_own;
        u32 cr_clk;
        u32 cr_mode;
+       u32 cr_en;
        u32 wsr;
        int chan;
        int rate;
@@ -89,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;                                                     \
@@ -100,22 +102,25 @@ 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_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)))
 #define rsnd_ssi_is_run_mods(mod, io) \
        (rsnd_ssi_run_mods(io) & (1 << rsnd_mod_id(mod)))
+#define rsnd_ssi_can_output_clk(mod) (!__rsnd_ssi_is_pin_sharing(mod))
 
 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;
@@ -130,7 +135,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;
@@ -255,7 +260,6 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
        struct device *dev = rsnd_priv_to_dev(priv);
        struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-       struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io);
        int chan = rsnd_runtime_channel_for_ssi(io);
        int idx, ret;
        unsigned int main_rate;
@@ -266,7 +270,7 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
        if (!rsnd_rdai_is_clk_master(rdai))
                return 0;
 
-       if (ssi_parent_mod && !rsnd_ssi_is_parent(mod, io))
+       if (!rsnd_ssi_can_output_clk(mod))
                return 0;
 
        if (rsnd_ssi_is_multi_slave(mod, io))
@@ -291,6 +295,16 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
        if (ret < 0)
                return ret;
 
+       /*
+        * SSI clock will be output contiguously
+        * by below settings.
+        * This means, rsnd_ssi_master_clk_start()
+        * and rsnd_ssi_register_setup() are necessary
+        * for SSI parent
+        *
+        * SSICR  : FORCE, SCKD, SWSD
+        * SSIWSR : CONT
+        */
        ssi->cr_clk = FORCE | SWL_32 | SCKD | SWSD | CKDV(idx);
        ssi->wsr = CONT;
        ssi->rate = rate;
@@ -307,12 +321,11 @@ static void rsnd_ssi_master_clk_stop(struct rsnd_mod *mod,
 {
        struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-       struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io);
 
        if (!rsnd_rdai_is_clk_master(rdai))
                return;
 
-       if (ssi_parent_mod && !rsnd_ssi_is_parent(mod, io))
+       if (!rsnd_ssi_can_output_clk(mod))
                return;
 
        if (ssi->usrcnt > 1)
@@ -335,6 +348,9 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
        u32 wsr;
        int is_tdm;
 
+       if (rsnd_ssi_is_parent(mod, io))
+               return;
+
        is_tdm = rsnd_runtime_is_ssi_tdm(io);
 
        /*
@@ -393,7 +409,8 @@ static void rsnd_ssi_register_setup(struct rsnd_mod *mod)
        rsnd_mod_write(mod, SSIWSR,     ssi->wsr);
        rsnd_mod_write(mod, SSICR,      ssi->cr_own     |
                                        ssi->cr_clk     |
-                                       ssi->cr_mode); /* without EN */
+                                       ssi->cr_mode    |
+                                       ssi->cr_en);
 }
 
 static void rsnd_ssi_pointer_init(struct rsnd_mod *mod,
@@ -472,8 +489,7 @@ static int rsnd_ssi_init(struct rsnd_mod *mod,
        if (ret < 0)
                return ret;
 
-       if (!rsnd_ssi_is_parent(mod, io))
-               rsnd_ssi_config_init(mod, io);
+       rsnd_ssi_config_init(mod, io);
 
        rsnd_ssi_register_setup(mod);
 
@@ -544,6 +560,8 @@ static int rsnd_ssi_start(struct rsnd_mod *mod,
                          struct rsnd_dai_stream *io,
                          struct rsnd_priv *priv)
 {
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+
        if (!rsnd_ssi_is_run_mods(mod, io))
                return 0;
 
@@ -554,7 +572,19 @@ static int rsnd_ssi_start(struct rsnd_mod *mod,
        if (rsnd_ssi_multi_slaves_runtime(io))
                return 0;
 
-       rsnd_mod_bset(mod, SSICR, EN, EN);
+       /*
+        * EN is for data output.
+        * SSI parent EN is not needed.
+        */
+       if (rsnd_ssi_is_parent(mod, io))
+               return 0;
+
+       ssi->cr_en = EN;
+
+       rsnd_mod_write(mod, SSICR,      ssi->cr_own     |
+                                       ssi->cr_clk     |
+                                       ssi->cr_mode    |
+                                       ssi->cr_en);
 
        return 0;
 }
@@ -569,13 +599,7 @@ static int rsnd_ssi_stop(struct rsnd_mod *mod,
        if (!rsnd_ssi_is_run_mods(mod, io))
                return 0;
 
-       /*
-        * don't stop if not last user
-        * see also
-        *      rsnd_ssi_start
-        *      rsnd_ssi_interrupt
-        */
-       if (ssi->usrcnt > 1)
+       if (rsnd_ssi_is_parent(mod, io))
                return 0;
 
        /*
@@ -595,6 +619,8 @@ static int rsnd_ssi_stop(struct rsnd_mod *mod,
        rsnd_mod_write(mod, SSICR, cr); /* disabled all */
        rsnd_ssi_status_check(mod, IIRQ);
 
+       ssi->cr_en = 0;
+
        return 0;
 }
 
@@ -760,15 +786,47 @@ 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;
 }
 
+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 */
+       if (rsnd_ssi_flags_has(ssi, RSND_SSI_PROBED)) {
+               free_irq(ssi->irq, mod);
+
+               rsnd_ssi_flags_del(ssi, RSND_SSI_PROBED);
+       }
+
+       return 0;
+}
+
 static int rsnd_ssi_pointer(struct rsnd_mod *mod,
                            struct rsnd_dai_stream *io,
                            snd_pcm_uframes_t *pointer)
@@ -784,6 +842,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,
@@ -818,23 +877,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 *ssi_parent_mod = rsnd_io_to_mod_ssip(io);
-
-       /* Do nothing for SSI parent mod */
-       if (ssi_parent_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)
@@ -876,7 +918,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,
@@ -962,13 +1004,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));
        }
@@ -1001,7 +1043,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,
@@ -1079,18 +1121,20 @@ int rsnd_ssi_probe(struct rsnd_priv *priv)
                clk = devm_clk_get(dev, name);
                if (IS_ERR(clk)) {
                        ret = PTR_ERR(clk);
+                       of_node_put(np);
                        goto rsnd_ssi_probe_done;
                }
 
                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) {
                        ret = -EINVAL;
+                       of_node_put(np);
                        goto rsnd_ssi_probe_done;
                }
 
@@ -1101,8 +1145,10 @@ int rsnd_ssi_probe(struct rsnd_priv *priv)
 
                ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk,
                                    rsnd_ssi_get_status, RSND_MOD_SSI, i);
-               if (ret)
+               if (ret) {
+                       of_node_put(np);
                        goto rsnd_ssi_probe_done;
+               }
 
                i++;
        }
index bed2c9c0004b8fb0c6ccb1d9215443f4846e1eba..4d948757d300d04be3bfca3c63f78c68085a8506 100644 (file)
@@ -250,7 +250,7 @@ int rsnd_ssiu_probe(struct rsnd_priv *priv)
 {
        struct device *dev = rsnd_priv_to_dev(priv);
        struct rsnd_ssiu *ssiu;
-       static struct rsnd_mod_ops *ops;
+       struct rsnd_mod_ops *ops;
        int i, nr, ret;
 
        /* same number to SSI */