ASoC: rsnd: dvc enables non-stereo sound
[deliverable/linux.git] / sound / soc / sh / rcar / dvc.c
index 58f690900e6d36a704be976b5a440550df76726a..66aeea8e00691fa0ac3cd61d1b4c6709e81038ad 100644 (file)
@@ -15,7 +15,6 @@
 #define DVC_NAME "dvc"
 
 struct rsnd_dvc {
-       struct rsnd_dvc_platform_info *info; /* rcar_snd.h */
        struct rsnd_mod mod;
        struct rsnd_kctrl_cfg_m volume;
        struct rsnd_kctrl_cfg_m mute;
@@ -24,6 +23,7 @@ struct rsnd_dvc {
        struct rsnd_kctrl_cfg_s rdown;  /* Ramp Rate Down */
 };
 
+#define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id)
 #define rsnd_dvc_nr(priv) ((priv)->dvc_nr)
 #define rsnd_dvc_of_node(priv) \
        of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc")
@@ -64,79 +64,142 @@ static const char * const dvc_ramp_rate[] = {
        "0.125 dB/8192 steps",   /* 10111 */
 };
 
-static void rsnd_dvc_soft_reset(struct rsnd_mod *mod)
+static void rsnd_dvc_activation(struct rsnd_mod *mod)
 {
        rsnd_mod_write(mod, DVC_SWRSR, 0);
        rsnd_mod_write(mod, DVC_SWRSR, 1);
 }
 
-#define rsnd_dvc_initialize_lock(mod)  __rsnd_dvc_initialize_lock(mod, 1)
-#define rsnd_dvc_initialize_unlock(mod)        __rsnd_dvc_initialize_lock(mod, 0)
-static void __rsnd_dvc_initialize_lock(struct rsnd_mod *mod, u32 enable)
+static void rsnd_dvc_halt(struct rsnd_mod *mod)
 {
-       rsnd_mod_write(mod, DVC_DVUIR, enable);
+       rsnd_mod_write(mod, DVC_DVUIR, 1);
+       rsnd_mod_write(mod, DVC_SWRSR, 0);
 }
 
-static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io,
-                                  struct rsnd_mod *mod)
+#define rsnd_dvc_get_vrpdr(dvc) (dvc->rup.val << 8 | dvc->rdown.val)
+#define rsnd_dvc_get_vrdbr(dvc) (0x3ff - (dvc->volume.val[0] >> 13))
+
+static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io,
+                                             struct rsnd_mod *mod)
 {
        struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
        u32 val[RSND_DVC_CHANNELS];
-       u32 dvucr = 0;
-       u32 mute = 0;
        int i;
 
-       for (i = 0; i < dvc->mute.cfg.size; i++)
-               mute |= (!!dvc->mute.cfg.val[i]) << i;
+       /* Enable Ramp */
+       if (dvc->ren.val)
+               for (i = 0; i < RSND_DVC_CHANNELS; i++)
+                       val[i] = dvc->volume.cfg.max;
+       else
+               for (i = 0; i < RSND_DVC_CHANNELS; i++)
+                       val[i] = dvc->volume.val[i];
 
-       /* Disable DVC Register access */
-       rsnd_mod_write(mod, DVC_DVUER, 0);
+       /* Enable Digital Volume */
+       rsnd_mod_write(mod, DVC_VOL0R, val[0]);
+       rsnd_mod_write(mod, DVC_VOL1R, val[1]);
+       rsnd_mod_write(mod, DVC_VOL2R, val[2]);
+       rsnd_mod_write(mod, DVC_VOL3R, val[3]);
+       rsnd_mod_write(mod, DVC_VOL4R, val[4]);
+       rsnd_mod_write(mod, DVC_VOL5R, val[5]);
+       rsnd_mod_write(mod, DVC_VOL6R, val[6]);
+       rsnd_mod_write(mod, DVC_VOL7R, val[7]);
+}
+
+static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io,
+                                struct rsnd_mod *mod)
+{
+       struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
+       u32 adinr = 0;
+       u32 dvucr = 0;
+       u32 vrctr = 0;
+       u32 vrpdr = 0;
+       u32 vrdbr = 0;
+
+       adinr = rsnd_get_adinr_bit(mod, io) |
+               rsnd_get_adinr_chan(mod, io);
+
+       /* Enable Digital Volume, Zero Cross Mute Mode */
+       dvucr |= 0x101;
 
        /* Enable Ramp */
        if (dvc->ren.val) {
                dvucr |= 0x10;
 
-               /* Digital Volume Max */
-               for (i = 0; i < RSND_DVC_CHANNELS; i++)
-                       val[i] = dvc->volume.cfg.max;
-
-               rsnd_mod_write(mod, DVC_VRCTR, 0xff);
-               rsnd_mod_write(mod, DVC_VRPDR, dvc->rup.val << 8 |
-                                              dvc->rdown.val);
                /*
                 * FIXME !!
                 * use scale-downed Digital Volume
                 * as Volume Ramp
                 * 7F FFFF -> 3FF
                 */
-               rsnd_mod_write(mod, DVC_VRDBR,
-                              0x3ff - (dvc->volume.val[0] >> 13));
-
-       } else {
-               for (i = 0; i < RSND_DVC_CHANNELS; i++)
-                       val[i] = dvc->volume.val[i];
+               vrctr = 0xff;
+               vrpdr = rsnd_dvc_get_vrpdr(dvc);
+               vrdbr = rsnd_dvc_get_vrdbr(dvc);
        }
 
-       /* Enable Digital Volume */
-       dvucr |= 0x100;
-       rsnd_mod_write(mod, DVC_VOL0R, val[0]);
-       rsnd_mod_write(mod, DVC_VOL1R, val[1]);
+       /* Initialize operation */
+       rsnd_mod_write(mod, DVC_DVUIR, 1);
+
+       /* General Information */
+       rsnd_mod_write(mod, DVC_ADINR, adinr);
+       rsnd_mod_write(mod, DVC_DVUCR, dvucr);
+
+       /* Volume Ramp Parameter */
+       rsnd_mod_write(mod, DVC_VRCTR, vrctr);
+       rsnd_mod_write(mod, DVC_VRPDR, vrpdr);
+       rsnd_mod_write(mod, DVC_VRDBR, vrdbr);
+
+       /* Digital Volume Function Parameter */
+       rsnd_dvc_volume_parameter(io, mod);
+
+       /* cancel operation */
+       rsnd_mod_write(mod, DVC_DVUIR, 0);
+}
+
+static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io,
+                                  struct rsnd_mod *mod)
+{
+       struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
+       u32 zcmcr = 0;
+       u32 vrpdr = 0;
+       u32 vrdbr = 0;
+       int i;
+
+       for (i = 0; i < dvc->mute.cfg.size; i++)
+               zcmcr |= (!!dvc->mute.cfg.val[i]) << i;
 
-       /*  Enable Mute */
-       if (mute) {
-               dvucr |= 0x1;
-               rsnd_mod_write(mod, DVC_ZCMCR, mute);
+       if (dvc->ren.val) {
+               vrpdr = rsnd_dvc_get_vrpdr(dvc);
+               vrdbr = rsnd_dvc_get_vrdbr(dvc);
        }
 
-       rsnd_mod_write(mod, DVC_DVUCR, dvucr);
+       /* Disable DVC Register access */
+       rsnd_mod_write(mod, DVC_DVUER, 0);
+
+       /* Zero Cross Mute Function */
+       rsnd_mod_write(mod, DVC_ZCMCR, zcmcr);
+
+       /* Volume Ramp Function */
+       rsnd_mod_write(mod, DVC_VRPDR, vrpdr);
+       rsnd_mod_write(mod, DVC_VRDBR, vrdbr);
+       /* add DVC_VRWTR here */
+
+       /* Digital Volume Function Parameter */
+       rsnd_dvc_volume_parameter(io, mod);
 
        /* Enable DVC Register access */
        rsnd_mod_write(mod, DVC_DVUER, 1);
 }
 
-static int rsnd_dvc_remove_gen2(struct rsnd_mod *mod,
-                               struct rsnd_dai_stream *io,
-                               struct rsnd_priv *priv)
+static int rsnd_dvc_probe_(struct rsnd_mod *mod,
+                          struct rsnd_dai_stream *io,
+                          struct rsnd_priv *priv)
+{
+       return rsnd_cmd_attach(io, rsnd_mod_id(mod));
+}
+
+static int rsnd_dvc_remove_(struct rsnd_mod *mod,
+                           struct rsnd_dai_stream *io,
+                           struct rsnd_priv *priv)
 {
        struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
 
@@ -155,19 +218,12 @@ static int rsnd_dvc_init(struct rsnd_mod *mod,
 {
        rsnd_mod_power_on(mod);
 
-       rsnd_dvc_soft_reset(mod);
-
-       rsnd_dvc_initialize_lock(mod);
-
-       rsnd_path_parse(priv, io);
+       rsnd_dvc_activation(mod);
 
-       rsnd_mod_write(mod, DVC_ADINR, rsnd_get_adinr_bit(mod, io));
+       rsnd_dvc_volume_init(io, mod);
 
-       /* ch0/ch1 Volume */
        rsnd_dvc_volume_update(io, mod);
 
-       rsnd_adg_set_cmd_timsel_gen2(mod, io);
-
        return 0;
 }
 
@@ -175,27 +231,9 @@ static int rsnd_dvc_quit(struct rsnd_mod *mod,
                         struct rsnd_dai_stream *io,
                         struct rsnd_priv *priv)
 {
-       rsnd_mod_power_off(mod);
+       rsnd_dvc_halt(mod);
 
-       return 0;
-}
-
-static int rsnd_dvc_start(struct rsnd_mod *mod,
-                         struct rsnd_dai_stream *io,
-                         struct rsnd_priv *priv)
-{
-       rsnd_dvc_initialize_unlock(mod);
-
-       rsnd_mod_write(mod, CMD_CTRL, 0x10);
-
-       return 0;
-}
-
-static int rsnd_dvc_stop(struct rsnd_mod *mod,
-                        struct rsnd_dai_stream *io,
-                        struct rsnd_priv *priv)
-{
-       rsnd_mod_write(mod, CMD_CTRL, 0);
+       rsnd_mod_power_off(mod);
 
        return 0;
 }
@@ -204,8 +242,10 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
                            struct rsnd_dai_stream *io,
                            struct snd_soc_pcm_runtime *rtd)
 {
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
        struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
        int is_play = rsnd_io_is_play(io);
+       int slots = rsnd_get_slot_rdai(rdai);
        int ret;
 
        /* Volume */
@@ -213,7 +253,8 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
                        is_play ?
                        "DVC Out Playback Volume" : "DVC In Capture Volume",
                        rsnd_dvc_volume_update,
-                       &dvc->volume, 0x00800000 - 1);
+                       &dvc->volume, slots,
+                       0x00800000 - 1);
        if (ret < 0)
                return ret;
 
@@ -222,7 +263,8 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
                        is_play ?
                        "DVC Out Mute Switch" : "DVC In Mute Switch",
                        rsnd_dvc_volume_update,
-                       &dvc->mute, 1);
+                       &dvc->mute,  slots,
+                       1);
        if (ret < 0)
                return ret;
 
@@ -269,11 +311,10 @@ static struct dma_chan *rsnd_dvc_dma_req(struct rsnd_dai_stream *io,
 static struct rsnd_mod_ops rsnd_dvc_ops = {
        .name           = DVC_NAME,
        .dma_req        = rsnd_dvc_dma_req,
-       .remove         = rsnd_dvc_remove_gen2,
+       .probe          = rsnd_dvc_probe_,
+       .remove         = rsnd_dvc_remove_,
        .init           = rsnd_dvc_init,
        .quit           = rsnd_dvc_quit,
-       .start          = rsnd_dvc_start,
-       .stop           = rsnd_dvc_stop,
        .pcm_new        = rsnd_dvc_pcm_new,
 };
 
@@ -282,50 +323,13 @@ struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id)
        if (WARN_ON(id < 0 || id >= rsnd_dvc_nr(priv)))
                id = 0;
 
-       return rsnd_mod_get((struct rsnd_dvc *)(priv->dvc) + id);
+       return rsnd_mod_get(rsnd_dvc_get(priv, id));
 }
 
-static void rsnd_of_parse_dvc(struct platform_device *pdev,
-                             const struct rsnd_of_data *of_data,
-                             struct rsnd_priv *priv)
+int rsnd_dvc_probe(struct rsnd_priv *priv)
 {
        struct device_node *node;
-       struct rsnd_dvc_platform_info *dvc_info;
-       struct rcar_snd_info *info = rsnd_priv_to_info(priv);
-       struct device *dev = &pdev->dev;
-       int nr;
-
-       if (!of_data)
-               return;
-
-       node = of_get_child_by_name(dev->of_node, "rcar_sound,dvc");
-       if (!node)
-               return;
-
-       nr = of_get_child_count(node);
-       if (!nr)
-               goto rsnd_of_parse_dvc_end;
-
-       dvc_info = devm_kzalloc(dev,
-                               sizeof(struct rsnd_dvc_platform_info) * nr,
-                               GFP_KERNEL);
-       if (!dvc_info) {
-               dev_err(dev, "dvc info allocation error\n");
-               goto rsnd_of_parse_dvc_end;
-       }
-
-       info->dvc_info          = dvc_info;
-       info->dvc_info_nr       = nr;
-
-rsnd_of_parse_dvc_end:
-       of_node_put(node);
-}
-
-int rsnd_dvc_probe(struct platform_device *pdev,
-                  const struct rsnd_of_data *of_data,
-                  struct rsnd_priv *priv)
-{
-       struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+       struct device_node *np;
        struct device *dev = rsnd_priv_to_dev(priv);
        struct rsnd_dvc *dvc;
        struct clk *clk;
@@ -336,40 +340,53 @@ int rsnd_dvc_probe(struct platform_device *pdev,
        if (rsnd_is_gen1(priv))
                return 0;
 
-       rsnd_of_parse_dvc(pdev, of_data, priv);
+       node = rsnd_dvc_of_node(priv);
+       if (!node)
+               return 0; /* not used is not error */
 
-       nr = info->dvc_info_nr;
-       if (!nr)
-               return 0;
+       nr = of_get_child_count(node);
+       if (!nr) {
+               ret = -EINVAL;
+               goto rsnd_dvc_probe_done;
+       }
 
        dvc     = devm_kzalloc(dev, sizeof(*dvc) * nr, GFP_KERNEL);
-       if (!dvc)
-               return -ENOMEM;
+       if (!dvc) {
+               ret = -ENOMEM;
+               goto rsnd_dvc_probe_done;
+       }
 
        priv->dvc_nr    = nr;
        priv->dvc       = dvc;
 
-       for_each_rsnd_dvc(dvc, priv, i) {
+       i = 0;
+       for_each_child_of_node(node, np) {
+               dvc = rsnd_dvc_get(priv, i);
+
                snprintf(name, RSND_DVC_NAME_SIZE, "%s.%d",
                         DVC_NAME, i);
 
                clk = devm_clk_get(dev, name);
-               if (IS_ERR(clk))
-                       return PTR_ERR(clk);
-
-               dvc->info = &info->dvc_info[i];
+               if (IS_ERR(clk)) {
+                       ret = PTR_ERR(clk);
+                       goto rsnd_dvc_probe_done;
+               }
 
                ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops,
                              clk, RSND_MOD_DVC, i);
                if (ret)
-                       return ret;
+                       goto rsnd_dvc_probe_done;
+
+               i++;
        }
 
-       return 0;
+rsnd_dvc_probe_done:
+       of_node_put(node);
+
+       return ret;
 }
 
-void rsnd_dvc_remove(struct platform_device *pdev,
-                    struct rsnd_priv *priv)
+void rsnd_dvc_remove(struct rsnd_priv *priv)
 {
        struct rsnd_dvc *dvc;
        int i;
This page took 0.029899 seconds and 5 git commands to generate.