@@ -1,4 +1,4 @@
-snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o src.o ctu.o mix.o dvc.o
+snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o src.o ctu.o mix.o dvc.o cmd.o
obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o
snd-soc-rsrc-card-objs := rsrc-card.o
new file mode 100644
@@ -0,0 +1,153 @@
+/*
+ * Renesas R-Car CMD support
+ *
+ * Copyright (C) 2015 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include "rsnd.h"
+
+struct rsnd_cmd {
+ struct rsnd_mod mod;
+};
+
+#define CMD_NAME "cmd"
+
+#define rsnd_cmd_nr(priv) ((priv)->cmd_nr)
+#define for_each_rsnd_cmd(pos, priv, i) \
+ for ((i) = 0; \
+ ((i) < rsnd_cmd_nr(priv)) && \
+ ((pos) = (struct rsnd_cmd *)(priv)->cmd + i); \
+ i++)
+
+static int rsnd_cmd_init(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
+{
+ struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
+ struct rsnd_mod *mix = rsnd_io_to_mod_mix(io);
+ struct rsnd_mod *src = rsnd_io_to_mod_src(io);
+ struct device *dev = rsnd_priv_to_dev(priv);
+ u32 data;
+
+ if (!mix && !dvc)
+ return 0;
+
+ if (mix) {
+ struct rsnd_dai *rdai;
+ int i;
+ u32 path[] = {
+ [0] = 0,
+ [1] = 1 << 0,
+ [2] = 0,
+ [3] = 0,
+ [4] = 0,
+ [5] = 1 << 8
+ };
+
+ /*
+ * it is assuming that integrater is well understanding about
+ * data path. Here doesn't check impossible connection,
+ * like src2 + src5
+ */
+ data = 0;
+ for_each_rsnd_dai(rdai, priv, i) {
+ io = &rdai->playback;
+ if (mix == rsnd_io_to_mod_mix(io))
+ data |= path[rsnd_mod_id(src)];
+
+ io = &rdai->capture;
+ if (mix == rsnd_io_to_mod_mix(io))
+ data |= path[rsnd_mod_id(src)];
+ }
+
+ } else {
+ u32 path[] = {
+ [0] = 0x30000,
+ [1] = 0x30001,
+ [2] = 0x40000,
+ [3] = 0x10000,
+ [4] = 0x20000,
+ [5] = 0x40100
+ };
+
+ data = path[rsnd_mod_id(src)];
+ }
+
+ dev_dbg(dev, "ctu/mix path = 0x%08x", data);
+
+ rsnd_mod_write(mod, CMD_ROUTE_SLCT, data);
+
+ rsnd_mod_write(mod, CMD_CTRL, 0x10);
+
+ return 0;
+}
+
+static struct rsnd_mod_ops rsnd_cmd_ops = {
+ .name = CMD_NAME,
+ .init = rsnd_cmd_init,
+};
+
+int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id)
+{
+ struct rsnd_priv *priv = rsnd_io_to_priv(io);
+ struct rsnd_mod *mod = rsnd_cmd_mod_get(priv, id);
+
+ return rsnd_dai_connect(mod, io, mod->type);
+}
+
+struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id)
+{
+ if (WARN_ON(id < 0 || id >= rsnd_cmd_nr(priv)))
+ id = 0;
+
+ return rsnd_mod_get((struct rsnd_cmd *)(priv->cmd) + id);
+}
+
+int rsnd_cmd_probe(struct platform_device *pdev,
+ const struct rsnd_of_data *of_data,
+ struct rsnd_priv *priv)
+{
+ struct device *dev = rsnd_priv_to_dev(priv);
+ struct rsnd_cmd *cmd;
+ int i, nr, ret;
+
+ /* This driver doesn't support Gen1 at this point */
+ if (rsnd_is_gen1(priv))
+ return 0;
+
+ /* same number as DVC */
+ nr = priv->dvc_nr;
+ if (!nr)
+ return 0;
+
+ cmd = devm_kzalloc(dev, sizeof(*cmd) * nr, GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
+ priv->cmd_nr = nr;
+ priv->cmd = cmd;
+
+ for_each_rsnd_cmd(cmd, priv, i) {
+ ret = rsnd_mod_init(priv, rsnd_mod_get(cmd),
+ &rsnd_cmd_ops, NULL, RSND_MOD_CMD, i);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+void rsnd_cmd_remove(struct platform_device *pdev,
+ struct rsnd_priv *priv)
+{
+ struct rsnd_cmd *cmd;
+ int i;
+
+ for_each_rsnd_cmd(cmd, priv, i) {
+ rsnd_mod_quit(rsnd_mod_get(cmd));
+ }
+}
@@ -589,79 +589,6 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
ret; \
})
-void rsnd_path_parse(struct rsnd_priv *priv,
- struct rsnd_dai_stream *io)
-{
- struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
- struct rsnd_mod *mix = rsnd_io_to_mod_mix(io);
- struct rsnd_mod *src = rsnd_io_to_mod_src(io);
- struct rsnd_mod *cmd;
- struct device *dev = rsnd_priv_to_dev(priv);
- u32 data;
-
- /* Gen1 is not supported */
- if (rsnd_is_gen1(priv))
- return;
-
- if (!mix && !dvc)
- return;
-
- if (mix) {
- struct rsnd_dai *rdai;
- int i;
- u32 path[] = {
- [0] = 0,
- [1] = 1 << 0,
- [2] = 0,
- [3] = 0,
- [4] = 0,
- [5] = 1 << 8
- };
-
- /*
- * it is assuming that integrater is well understanding about
- * data path. Here doesn't check impossible connection,
- * like src2 + src5
- */
- data = 0;
- for_each_rsnd_dai(rdai, priv, i) {
- io = &rdai->playback;
- if (mix == rsnd_io_to_mod_mix(io))
- data |= path[rsnd_mod_id(src)];
-
- io = &rdai->capture;
- if (mix == rsnd_io_to_mod_mix(io))
- data |= path[rsnd_mod_id(src)];
- }
-
- /*
- * We can't use ctu = rsnd_io_ctu() here.
- * Since, ID of dvc/mix are 0 or 1 (= same as CMD number)
- * but ctu IDs are 0 - 7 (= CTU00 - CTU13)
- */
- cmd = mix;
- } else {
- u32 path[] = {
- [0] = 0x30000,
- [1] = 0x30001,
- [2] = 0x40000,
- [3] = 0x10000,
- [4] = 0x20000,
- [5] = 0x40100
- };
-
- data = path[rsnd_mod_id(src)];
-
- cmd = dvc;
- }
-
- dev_dbg(dev, "ctu/mix path = 0x%08x", data);
-
- rsnd_mod_write(cmd, CMD_ROUTE_SLCT, data);
-
- rsnd_mod_write(cmd, CMD_CTRL, 0x10);
-}
-
static int rsnd_path_init(struct rsnd_priv *priv,
struct rsnd_dai *rdai,
struct rsnd_dai_stream *io)
@@ -1208,6 +1135,7 @@ static int rsnd_probe(struct platform_device *pdev)
rsnd_ctu_probe,
rsnd_mix_probe,
rsnd_dvc_probe,
+ rsnd_cmd_probe,
rsnd_adg_probe,
rsnd_dai_probe,
};
@@ -1296,6 +1224,7 @@ static int rsnd_remove(struct platform_device *pdev)
rsnd_ctu_remove,
rsnd_mix_remove,
rsnd_dvc_remove,
+ rsnd_cmd_remove,
};
int ret = 0, i;
@@ -31,6 +31,13 @@ static void __rsnd_ctu_initialize_lock(struct rsnd_mod *mod, u32 enable)
rsnd_mod_write(mod, CTU_CTUIR, enable);
}
+static int rsnd_ctu_probe_(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ struct rsnd_priv *priv)
+{
+ return rsnd_cmd_attach(io, rsnd_mod_id(mod) / 4);
+}
+
static int rsnd_ctu_init(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
@@ -57,6 +64,7 @@ static int rsnd_ctu_quit(struct rsnd_mod *mod,
static struct rsnd_mod_ops rsnd_ctu_ops = {
.name = CTU_NAME,
+ .probe = rsnd_ctu_probe_,
.init = rsnd_ctu_init,
.quit = rsnd_ctu_quit,
};
@@ -134,9 +134,16 @@ static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io,
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);
@@ -159,8 +166,6 @@ static int rsnd_dvc_init(struct rsnd_mod *mod,
rsnd_dvc_initialize_lock(mod);
- rsnd_path_parse(priv, io);
-
rsnd_mod_write(mod, DVC_ADINR, rsnd_get_adinr_bit(mod, io));
/* ch0/ch1 Volume */
@@ -269,7 +274,8 @@ 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,
@@ -54,6 +54,13 @@ static void rsnd_mix_volume_update(struct rsnd_dai_stream *io,
rsnd_mod_write(mod, MIX_MDBER, 1);
}
+static int rsnd_mix_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_mix_init(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
@@ -66,8 +73,6 @@ static int rsnd_mix_init(struct rsnd_mod *mod,
rsnd_mod_write(mod, MIX_ADINR, rsnd_get_adinr_chan(mod, io));
- rsnd_path_parse(priv, io);
-
/* volume step */
rsnd_mod_write(mod, MIX_MIXMR, 0);
rsnd_mod_write(mod, MIX_MVPDR, 0);
@@ -90,6 +95,7 @@ static int rsnd_mix_quit(struct rsnd_mod *mod,
static struct rsnd_mod_ops rsnd_mix_ops = {
.name = MIX_NAME,
+ .probe = rsnd_mix_probe_,
.init = rsnd_mix_init,
.quit = rsnd_mix_quit,
};
@@ -187,8 +187,6 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg,
u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
-void rsnd_path_parse(struct rsnd_priv *priv,
- struct rsnd_dai_stream *io);
/*
* R-Car DMA
@@ -210,6 +208,7 @@ enum rsnd_mod_type {
RSND_MOD_DVC,
RSND_MOD_MIX,
RSND_MOD_CTU,
+ RSND_MOD_CMD,
RSND_MOD_SRC,
RSND_MOD_SSI,
RSND_MOD_MAX,
@@ -475,6 +474,12 @@ struct rsnd_priv {
int dvc_nr;
/*
+ * below value will be filled on rsnd_cmd_probe()
+ */
+ void *cmd;
+ int cmd_nr;
+
+ /*
* below value will be filled on rsnd_dai_probe()
*/
struct snd_soc_dai_driver *daidrv;
@@ -606,6 +611,17 @@ void rsnd_dvc_remove(struct platform_device *pdev,
struct rsnd_priv *priv);
struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id);
+/*
+ * R-Car CMD
+ */
+int rsnd_cmd_probe(struct platform_device *pdev,
+ const struct rsnd_of_data *of_data,
+ struct rsnd_priv *priv);
+void rsnd_cmd_remove(struct platform_device *pdev,
+ struct rsnd_priv *priv);
+int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id);
+struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id);
+
#ifdef DEBUG
void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type);
#define rsnd_mod_confirm_ssi(mssi) rsnd_mod_make_sure(mssi, RSND_MOD_SSI)