* | +- 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
*/
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;
/* 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;
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
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,
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;
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;
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++) {
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
*/
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;
* 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;
}
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,