2018-07-02 14:30:58 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
//
|
|
|
|
// ASoC simple SCU sound card support
|
|
|
|
//
|
|
|
|
// Copyright (C) 2015 Renesas Solutions Corp.
|
|
|
|
// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
|
|
|
|
//
|
|
|
|
// based on ${LINUX}/sound/soc/generic/simple-card.c
|
|
|
|
|
2015-03-26 12:01:27 +08:00
|
|
|
#include <linux/clk.h>
|
|
|
|
#include <linux/device.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/of.h>
|
|
|
|
#include <linux/of_device.h>
|
|
|
|
#include <linux/platform_device.h>
|
|
|
|
#include <linux/string.h>
|
|
|
|
#include <sound/jack.h>
|
|
|
|
#include <sound/soc.h>
|
|
|
|
#include <sound/soc-dai.h>
|
2016-06-30 14:03:13 +08:00
|
|
|
#include <sound/simple_card_utils.h>
|
2015-03-26 12:01:27 +08:00
|
|
|
|
2016-10-28 11:37:44 +08:00
|
|
|
struct simple_card_data {
|
2015-03-26 12:01:27 +08:00
|
|
|
struct snd_soc_card snd_card;
|
|
|
|
struct snd_soc_codec_conf codec_conf;
|
2018-08-31 11:08:38 +08:00
|
|
|
struct simple_dai_props {
|
|
|
|
struct asoc_simple_dai dai;
|
2018-08-31 11:08:51 +08:00
|
|
|
struct snd_soc_dai_link_component codecs;
|
2018-08-31 11:10:46 +08:00
|
|
|
struct snd_soc_dai_link_component platform;
|
2018-12-11 11:25:18 +08:00
|
|
|
struct asoc_simple_card_data adata;
|
2018-08-31 11:08:38 +08:00
|
|
|
} *dai_props;
|
2015-06-15 14:22:30 +08:00
|
|
|
struct snd_soc_dai_link *dai_link;
|
2017-06-15 08:24:28 +08:00
|
|
|
struct asoc_simple_card_data adata;
|
2015-03-26 12:01:27 +08:00
|
|
|
};
|
|
|
|
|
2017-03-15 12:44:16 +08:00
|
|
|
#define simple_priv_to_card(priv) (&(priv)->snd_card)
|
2016-08-23 09:34:17 +08:00
|
|
|
#define simple_priv_to_props(priv, i) ((priv)->dai_props + (i))
|
2017-03-15 12:44:16 +08:00
|
|
|
#define simple_priv_to_dev(priv) (simple_priv_to_card(priv)->dev)
|
|
|
|
#define simple_priv_to_link(priv, i) (simple_priv_to_card(priv)->dai_link + (i))
|
2015-03-26 12:01:27 +08:00
|
|
|
|
2016-08-08 14:02:31 +08:00
|
|
|
#define DAI "sound-dai"
|
|
|
|
#define CELL "#sound-dai-cells"
|
ASoC: rsrc-card: rename rsrc-card to simple-scu-card phase2
rsrc-card which is using DPCM feature was created for Renesas sound.
But not only Renesas, but many SoC can use this driver, because
it is based on simple-card driver.
To use it as more open driver, rsrc-card will be renamed to
simple-scu-card. In order to easy patch review, as 2nd step,
this patch adds new compatible "simple-scu-audio-card";
rcar-card used specific property, not "simple-audio-card",
but it should be now. Actually, rsrc-card is upstreamed driver,
but noone is using it on upstream. The user is only local,
and it is only me. Thus, there is no compatible break by this patch.
This patch uses "simple-audio-card" prefix.
And it removes rcar-card specifix compatible too.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
2016-08-23 09:34:43 +08:00
|
|
|
#define PREFIX "simple-audio-card,"
|
2016-08-08 14:02:31 +08:00
|
|
|
|
2016-08-23 09:34:17 +08:00
|
|
|
static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
|
2015-03-26 12:01:27 +08:00
|
|
|
{
|
|
|
|
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
2016-10-28 11:37:44 +08:00
|
|
|
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
2018-08-31 11:08:38 +08:00
|
|
|
struct simple_dai_props *dai_props =
|
2016-08-23 09:34:17 +08:00
|
|
|
simple_priv_to_props(priv, rtd->num);
|
2015-03-26 12:01:27 +08:00
|
|
|
|
2018-08-31 11:08:38 +08:00
|
|
|
return asoc_simple_card_clk_enable(&dai_props->dai);
|
2015-03-26 12:01:27 +08:00
|
|
|
}
|
|
|
|
|
2016-08-23 09:34:17 +08:00
|
|
|
static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
|
2015-03-26 12:01:27 +08:00
|
|
|
{
|
|
|
|
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
2016-10-28 11:37:44 +08:00
|
|
|
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
2018-08-31 11:08:38 +08:00
|
|
|
struct simple_dai_props *dai_props =
|
2016-08-23 09:34:17 +08:00
|
|
|
simple_priv_to_props(priv, rtd->num);
|
2015-03-26 12:01:27 +08:00
|
|
|
|
2018-08-31 11:08:38 +08:00
|
|
|
asoc_simple_card_clk_disable(&dai_props->dai);
|
2015-03-26 12:01:27 +08:00
|
|
|
}
|
|
|
|
|
2016-10-15 22:55:49 +08:00
|
|
|
static const struct snd_soc_ops asoc_simple_card_ops = {
|
2016-08-23 09:34:17 +08:00
|
|
|
.startup = asoc_simple_card_startup,
|
|
|
|
.shutdown = asoc_simple_card_shutdown,
|
2015-03-26 12:01:27 +08:00
|
|
|
};
|
|
|
|
|
2016-08-23 09:34:17 +08:00
|
|
|
static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
|
2015-03-26 12:01:27 +08:00
|
|
|
{
|
2016-10-28 11:37:44 +08:00
|
|
|
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
2015-06-15 14:24:15 +08:00
|
|
|
struct snd_soc_dai *dai;
|
|
|
|
struct snd_soc_dai_link *dai_link;
|
2018-08-31 11:08:38 +08:00
|
|
|
struct simple_dai_props *dai_props;
|
2015-11-18 15:34:11 +08:00
|
|
|
int num = rtd->num;
|
2015-03-26 12:01:27 +08:00
|
|
|
|
2016-08-23 09:34:17 +08:00
|
|
|
dai_link = simple_priv_to_link(priv, num);
|
|
|
|
dai_props = simple_priv_to_props(priv, num);
|
2015-06-15 14:24:15 +08:00
|
|
|
dai = dai_link->dynamic ?
|
|
|
|
rtd->cpu_dai :
|
|
|
|
rtd->codec_dai;
|
|
|
|
|
2018-08-31 11:08:38 +08:00
|
|
|
return asoc_simple_card_init_dai(dai, &dai_props->dai);
|
2015-03-26 12:01:27 +08:00
|
|
|
}
|
|
|
|
|
2016-08-23 09:34:17 +08:00
|
|
|
static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
|
2015-03-26 12:01:46 +08:00
|
|
|
struct snd_pcm_hw_params *params)
|
|
|
|
{
|
2016-10-28 11:37:44 +08:00
|
|
|
struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
|
2018-12-11 11:25:18 +08:00
|
|
|
struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num);
|
2015-03-26 12:01:46 +08:00
|
|
|
|
2018-12-11 11:25:18 +08:00
|
|
|
asoc_simple_card_convert_fixup(&dai_props->adata, params);
|
|
|
|
|
|
|
|
/* overwrite by top level adata if exist */
|
2017-06-15 08:24:28 +08:00
|
|
|
asoc_simple_card_convert_fixup(&priv->adata, params);
|
2015-03-26 12:01:46 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-12-04 16:20:13 +08:00
|
|
|
static int asoc_simple_card_dai_link_of(struct device_node *link,
|
|
|
|
struct device_node *np,
|
|
|
|
struct device_node *codec,
|
2016-10-28 11:37:44 +08:00
|
|
|
struct simple_card_data *priv,
|
2018-12-04 16:20:13 +08:00
|
|
|
int idx, bool is_fe,
|
|
|
|
bool is_top_level_node)
|
2015-03-26 12:01:27 +08:00
|
|
|
{
|
2016-08-23 09:34:17 +08:00
|
|
|
struct device *dev = simple_priv_to_dev(priv);
|
|
|
|
struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
|
2018-08-31 11:08:38 +08:00
|
|
|
struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx);
|
2017-03-15 12:44:16 +08:00
|
|
|
struct snd_soc_card *card = simple_priv_to_card(priv);
|
2018-12-04 16:20:13 +08:00
|
|
|
char *prefix = "";
|
2015-03-26 12:01:27 +08:00
|
|
|
int ret;
|
|
|
|
|
2018-12-04 16:20:13 +08:00
|
|
|
/* For single DAI link & old style of DT node */
|
|
|
|
if (is_top_level_node)
|
|
|
|
prefix = PREFIX;
|
|
|
|
|
2015-06-15 14:24:15 +08:00
|
|
|
if (is_fe) {
|
2016-08-10 10:21:03 +08:00
|
|
|
int is_single_links = 0;
|
2018-08-31 11:08:51 +08:00
|
|
|
struct snd_soc_dai_link_component *codecs;
|
2016-08-10 10:21:03 +08:00
|
|
|
|
2015-06-15 14:24:15 +08:00
|
|
|
/* BE is dummy */
|
2018-08-31 11:08:51 +08:00
|
|
|
codecs = dai_link->codecs;
|
|
|
|
codecs->of_node = NULL;
|
|
|
|
codecs->dai_name = "snd-soc-dummy-dai";
|
|
|
|
codecs->name = "snd-soc-dummy";
|
2015-06-15 14:24:15 +08:00
|
|
|
|
|
|
|
/* FE settings */
|
|
|
|
dai_link->dynamic = 1;
|
|
|
|
dai_link->dpcm_merged_format = 1;
|
2016-08-08 14:02:31 +08:00
|
|
|
|
|
|
|
ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL,
|
|
|
|
&is_single_links);
|
|
|
|
if (ret)
|
2015-12-01 16:33:23 +08:00
|
|
|
return ret;
|
2015-06-15 14:24:15 +08:00
|
|
|
|
2018-08-31 11:08:38 +08:00
|
|
|
ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, &dai_props->dai);
|
2016-07-19 10:53:32 +08:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2016-07-12 07:58:25 +08:00
|
|
|
ret = asoc_simple_card_set_dailink_name(dev, dai_link,
|
|
|
|
"fe.%s",
|
|
|
|
dai_link->cpu_dai_name);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2015-06-15 14:24:15 +08:00
|
|
|
|
2016-08-10 10:21:03 +08:00
|
|
|
asoc_simple_card_canonicalize_cpu(dai_link, is_single_links);
|
2015-06-15 14:24:15 +08:00
|
|
|
} else {
|
|
|
|
/* FE is dummy */
|
|
|
|
dai_link->cpu_of_node = NULL;
|
|
|
|
dai_link->cpu_dai_name = "snd-soc-dummy-dai";
|
|
|
|
dai_link->cpu_name = "snd-soc-dummy";
|
2015-03-26 12:01:27 +08:00
|
|
|
|
2015-06-15 14:24:15 +08:00
|
|
|
/* BE settings */
|
|
|
|
dai_link->no_pcm = 1;
|
2016-08-23 09:34:17 +08:00
|
|
|
dai_link->be_hw_params_fixup = asoc_simple_card_be_hw_params_fixup;
|
2016-08-08 14:02:31 +08:00
|
|
|
|
|
|
|
ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL);
|
2015-12-01 16:33:23 +08:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2015-06-15 14:24:15 +08:00
|
|
|
|
2018-08-31 11:08:38 +08:00
|
|
|
ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, &dai_props->dai);
|
2016-07-19 10:53:32 +08:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2016-07-12 07:58:25 +08:00
|
|
|
ret = asoc_simple_card_set_dailink_name(dev, dai_link,
|
|
|
|
"be.%s",
|
2018-08-31 11:08:51 +08:00
|
|
|
dai_link->codecs->dai_name);
|
2016-07-12 07:58:25 +08:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2018-11-22 08:55:40 +08:00
|
|
|
/* check "prefix" from top node */
|
2017-03-15 12:44:16 +08:00
|
|
|
snd_soc_of_parse_audio_prefix(card,
|
ASoC: rsrc-card: rename rsrc-card to simple-scu-card phase2
rsrc-card which is using DPCM feature was created for Renesas sound.
But not only Renesas, but many SoC can use this driver, because
it is based on simple-card driver.
To use it as more open driver, rsrc-card will be renamed to
simple-scu-card. In order to easy patch review, as 2nd step,
this patch adds new compatible "simple-scu-audio-card";
rcar-card used specific property, not "simple-audio-card",
but it should be now. Actually, rsrc-card is upstreamed driver,
but noone is using it on upstream. The user is only local,
and it is only me. Thus, there is no compatible break by this patch.
This patch uses "simple-audio-card" prefix.
And it removes rcar-card specifix compatible too.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
2016-08-23 09:34:43 +08:00
|
|
|
&priv->codec_conf,
|
2018-08-31 11:08:51 +08:00
|
|
|
dai_link->codecs->of_node,
|
ASoC: rsrc-card: rename rsrc-card to simple-scu-card phase2
rsrc-card which is using DPCM feature was created for Renesas sound.
But not only Renesas, but many SoC can use this driver, because
it is based on simple-card driver.
To use it as more open driver, rsrc-card will be renamed to
simple-scu-card. In order to easy patch review, as 2nd step,
this patch adds new compatible "simple-scu-audio-card";
rcar-card used specific property, not "simple-audio-card",
but it should be now. Actually, rsrc-card is upstreamed driver,
but noone is using it on upstream. The user is only local,
and it is only me. Thus, there is no compatible break by this patch.
This patch uses "simple-audio-card" prefix.
And it removes rcar-card specifix compatible too.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
2016-08-23 09:34:43 +08:00
|
|
|
PREFIX "prefix");
|
2018-11-22 08:55:40 +08:00
|
|
|
/* check "prefix" from each node if top doesn't have */
|
|
|
|
if (!priv->codec_conf.of_node)
|
|
|
|
snd_soc_of_parse_node_prefix(np,
|
|
|
|
&priv->codec_conf,
|
|
|
|
dai_link->codecs->of_node,
|
|
|
|
"prefix");
|
2015-03-26 12:01:27 +08:00
|
|
|
}
|
|
|
|
|
2018-12-11 11:25:18 +08:00
|
|
|
asoc_simple_card_parse_convert(dev, link, prefix, &dai_props->adata);
|
|
|
|
|
2018-08-31 11:08:38 +08:00
|
|
|
ret = asoc_simple_card_of_parse_tdm(np, &dai_props->dai);
|
2016-08-25 09:58:55 +08:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2016-08-09 13:50:19 +08:00
|
|
|
ret = asoc_simple_card_canonicalize_dailink(dai_link);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2018-12-04 16:20:13 +08:00
|
|
|
ret = asoc_simple_card_parse_daifmt(dev, link, codec,
|
|
|
|
prefix, &dai_link->dai_fmt);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2015-06-15 14:24:15 +08:00
|
|
|
dai_link->dpcm_playback = 1;
|
|
|
|
dai_link->dpcm_capture = 1;
|
2016-08-23 09:34:17 +08:00
|
|
|
dai_link->ops = &asoc_simple_card_ops;
|
|
|
|
dai_link->init = asoc_simple_card_dai_init;
|
2015-06-15 14:24:15 +08:00
|
|
|
|
2016-07-19 10:53:32 +08:00
|
|
|
return 0;
|
2015-03-26 12:01:27 +08:00
|
|
|
}
|
|
|
|
|
2017-06-07 08:37:30 +08:00
|
|
|
static int asoc_simple_card_parse_of(struct simple_card_data *priv)
|
2016-10-28 11:37:26 +08:00
|
|
|
|
2015-12-17 10:49:43 +08:00
|
|
|
{
|
2016-08-23 09:34:17 +08:00
|
|
|
struct device *dev = simple_priv_to_dev(priv);
|
2018-12-11 11:24:57 +08:00
|
|
|
struct device_node *top = dev->of_node;
|
|
|
|
struct device_node *node;
|
2015-12-17 10:49:43 +08:00
|
|
|
struct device_node *np;
|
2018-12-04 16:20:13 +08:00
|
|
|
struct device_node *codec;
|
2017-03-15 12:44:16 +08:00
|
|
|
struct snd_soc_card *card = simple_priv_to_card(priv);
|
2015-12-17 10:49:43 +08:00
|
|
|
bool is_fe;
|
2018-12-11 11:24:57 +08:00
|
|
|
int ret, i, loop;
|
2016-10-28 11:37:26 +08:00
|
|
|
|
2018-12-11 11:24:57 +08:00
|
|
|
if (!top)
|
2016-10-28 11:37:26 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2017-08-11 22:12:19 +08:00
|
|
|
ret = asoc_simple_card_of_parse_widgets(card, PREFIX);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2018-11-21 10:11:13 +08:00
|
|
|
ret = asoc_simple_card_of_parse_routing(card, PREFIX);
|
2016-10-28 11:37:26 +08:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2018-12-11 11:24:57 +08:00
|
|
|
asoc_simple_card_parse_convert(dev, top, PREFIX, &priv->adata);
|
2015-12-17 10:49:43 +08:00
|
|
|
|
2018-12-11 11:24:57 +08:00
|
|
|
loop = 1;
|
2018-12-04 16:20:13 +08:00
|
|
|
i = 0;
|
2018-12-11 11:24:57 +08:00
|
|
|
node = of_get_child_by_name(top, PREFIX "dai-link");
|
|
|
|
if (!node) {
|
|
|
|
node = dev->of_node;
|
|
|
|
loop = 0;
|
2015-12-17 10:49:43 +08:00
|
|
|
}
|
|
|
|
|
2018-12-11 11:24:57 +08:00
|
|
|
do {
|
|
|
|
codec = of_get_child_by_name(node,
|
|
|
|
loop ? "codec" : PREFIX "codec");
|
|
|
|
if (!codec)
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
for_each_child_of_node(node, np) {
|
|
|
|
is_fe = (np != codec);
|
|
|
|
|
|
|
|
ret = asoc_simple_card_dai_link_of(node, np, codec, priv,
|
|
|
|
i, is_fe, !loop);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
node = of_get_next_child(top, node);
|
|
|
|
} while (loop && node);
|
|
|
|
|
2017-03-15 12:44:16 +08:00
|
|
|
ret = asoc_simple_card_parse_card_name(card, PREFIX);
|
2016-07-12 08:00:00 +08:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2015-03-26 12:01:27 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-12-11 11:25:08 +08:00
|
|
|
static void asoc_simple_card_get_dais_count(struct device *dev,
|
|
|
|
int *link_num,
|
|
|
|
int *dais_num,
|
|
|
|
int *ccnf_num)
|
|
|
|
{
|
|
|
|
struct device_node *top = dev->of_node;
|
|
|
|
struct device_node *node;
|
|
|
|
int loop;
|
|
|
|
int num;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* link_num : number of links.
|
|
|
|
* CPU-Codec / CPU-dummy / dummy-Codec
|
|
|
|
* dais_num : number of DAIs
|
|
|
|
* ccnf_num : number of codec_conf
|
|
|
|
* same number for "dummy-Codec"
|
|
|
|
*
|
|
|
|
* ex1)
|
|
|
|
* CPU0 --- Codec0 link : 5
|
|
|
|
* CPU1 --- Codec1 dais : 7
|
|
|
|
* CPU2 -/ ccnf : 1
|
|
|
|
* CPU3 --- Codec2
|
|
|
|
*
|
|
|
|
* => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
|
|
|
|
* => 7 DAIs = 4xCPU + 3xCodec
|
|
|
|
* => 1 ccnf = 1xdummy-Codec
|
|
|
|
*
|
|
|
|
* ex2)
|
|
|
|
* CPU0 --- Codec0 link : 5
|
|
|
|
* CPU1 --- Codec1 dais : 6
|
|
|
|
* CPU2 -/ ccnf : 1
|
|
|
|
* CPU3 -/
|
|
|
|
*
|
|
|
|
* => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
|
|
|
|
* => 6 DAIs = 4xCPU + 2xCodec
|
|
|
|
* => 1 ccnf = 1xdummy-Codec
|
|
|
|
*
|
|
|
|
* ex3)
|
|
|
|
* CPU0 --- Codec0 link : 6
|
|
|
|
* CPU1 -/ dais : 6
|
|
|
|
* CPU2 --- Codec1 ccnf : 2
|
|
|
|
* CPU3 -/
|
|
|
|
*
|
|
|
|
* => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
|
|
|
|
* => 6 DAIs = 4xCPU + 2xCodec
|
|
|
|
* => 2 ccnf = 2xdummy-Codec
|
|
|
|
*/
|
|
|
|
if (!top) {
|
|
|
|
(*link_num) = 1;
|
|
|
|
(*dais_num) = 2;
|
|
|
|
(*ccnf_num) = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
loop = 1;
|
|
|
|
node = of_get_child_by_name(top, PREFIX "dai-link");
|
|
|
|
if (!node) {
|
|
|
|
node = top;
|
|
|
|
loop = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
|
|
|
num = of_get_child_count(node);
|
|
|
|
(*dais_num) += num;
|
|
|
|
if (num > 2) {
|
|
|
|
(*link_num) += num;
|
|
|
|
(*ccnf_num)++;
|
|
|
|
} else {
|
|
|
|
(*link_num)++;
|
|
|
|
}
|
|
|
|
node = of_get_next_child(top, node);
|
|
|
|
} while (loop && node);
|
|
|
|
}
|
|
|
|
|
2016-08-23 09:34:17 +08:00
|
|
|
static int asoc_simple_card_probe(struct platform_device *pdev)
|
2015-03-26 12:01:27 +08:00
|
|
|
{
|
2016-10-28 11:37:44 +08:00
|
|
|
struct simple_card_data *priv;
|
2016-10-28 11:38:00 +08:00
|
|
|
struct snd_soc_dai_link *dai_link;
|
2018-08-31 11:08:38 +08:00
|
|
|
struct simple_dai_props *dai_props;
|
2017-03-15 12:44:16 +08:00
|
|
|
struct snd_soc_card *card;
|
2015-03-26 12:01:27 +08:00
|
|
|
struct device *dev = &pdev->dev;
|
2018-12-11 11:25:08 +08:00
|
|
|
int ret, i;
|
|
|
|
int lnum = 0, dnum = 0, cnum = 0;
|
2015-03-26 12:01:27 +08:00
|
|
|
|
|
|
|
/* Allocate the private data */
|
|
|
|
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
|
|
|
if (!priv)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2018-12-11 11:25:08 +08:00
|
|
|
asoc_simple_card_get_dais_count(dev, &lnum, &dnum, &cnum);
|
|
|
|
if (!lnum || !dnum)
|
|
|
|
return -EINVAL;
|
2016-10-28 11:37:26 +08:00
|
|
|
|
2018-12-11 11:25:08 +08:00
|
|
|
dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL);
|
|
|
|
dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL);
|
2016-10-28 11:38:00 +08:00
|
|
|
if (!dai_props || !dai_link)
|
2016-10-28 11:37:26 +08:00
|
|
|
return -ENOMEM;
|
|
|
|
|
2018-08-31 11:08:51 +08:00
|
|
|
/*
|
|
|
|
* Use snd_soc_dai_link_component instead of legacy style
|
|
|
|
* It is codec only. but cpu/platform will be supported in the future.
|
|
|
|
* see
|
|
|
|
* soc-core.c :: snd_soc_init_multicodec()
|
|
|
|
*/
|
2018-12-11 11:25:08 +08:00
|
|
|
for (i = 0; i < lnum; i++) {
|
2018-08-31 11:08:51 +08:00
|
|
|
dai_link[i].codecs = &dai_props[i].codecs;
|
|
|
|
dai_link[i].num_codecs = 1;
|
2018-08-31 11:10:46 +08:00
|
|
|
dai_link[i].platform = &dai_props[i].platform;
|
2018-08-31 11:08:51 +08:00
|
|
|
}
|
|
|
|
|
2016-10-28 11:38:00 +08:00
|
|
|
priv->dai_props = dai_props;
|
|
|
|
priv->dai_link = dai_link;
|
2016-10-28 11:37:26 +08:00
|
|
|
|
|
|
|
/* Init snd_soc_card */
|
2017-03-15 12:44:16 +08:00
|
|
|
card = simple_priv_to_card(priv);
|
|
|
|
card->owner = THIS_MODULE;
|
|
|
|
card->dev = dev;
|
|
|
|
card->dai_link = priv->dai_link;
|
2018-12-11 11:25:08 +08:00
|
|
|
card->num_links = lnum;
|
2017-03-15 12:44:16 +08:00
|
|
|
card->codec_conf = &priv->codec_conf;
|
|
|
|
card->num_configs = 1;
|
2016-10-28 11:37:26 +08:00
|
|
|
|
2017-06-07 08:37:30 +08:00
|
|
|
ret = asoc_simple_card_parse_of(priv);
|
2015-03-26 12:01:27 +08:00
|
|
|
if (ret < 0) {
|
|
|
|
if (ret != -EPROBE_DEFER)
|
|
|
|
dev_err(dev, "parse error %d\n", ret);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2017-03-15 12:44:16 +08:00
|
|
|
snd_soc_card_set_drvdata(card, priv);
|
2015-03-26 12:01:27 +08:00
|
|
|
|
2017-03-15 12:44:16 +08:00
|
|
|
ret = devm_snd_soc_register_card(dev, card);
|
2017-05-19 08:57:44 +08:00
|
|
|
if (ret < 0)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
return 0;
|
2015-03-26 12:01:27 +08:00
|
|
|
err:
|
2017-03-15 12:44:16 +08:00
|
|
|
asoc_simple_card_clean_reference(card);
|
2015-03-26 12:01:27 +08:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-08-23 09:34:17 +08:00
|
|
|
static int asoc_simple_card_remove(struct platform_device *pdev)
|
2015-03-26 12:01:27 +08:00
|
|
|
{
|
|
|
|
struct snd_soc_card *card = platform_get_drvdata(pdev);
|
|
|
|
|
2016-08-10 10:22:01 +08:00
|
|
|
return asoc_simple_card_clean_reference(card);
|
2015-03-26 12:01:27 +08:00
|
|
|
}
|
|
|
|
|
2016-08-25 09:58:31 +08:00
|
|
|
static const struct of_device_id asoc_simple_of_match[] = {
|
|
|
|
{ .compatible = "renesas,rsrc-card", },
|
|
|
|
{ .compatible = "simple-scu-audio-card", },
|
|
|
|
{},
|
|
|
|
};
|
|
|
|
MODULE_DEVICE_TABLE(of, asoc_simple_of_match);
|
|
|
|
|
2016-08-23 09:34:17 +08:00
|
|
|
static struct platform_driver asoc_simple_card = {
|
2015-03-26 12:01:27 +08:00
|
|
|
.driver = {
|
ASoC: rsrc-card: rename rsrc-card to simple-scu-card phase2
rsrc-card which is using DPCM feature was created for Renesas sound.
But not only Renesas, but many SoC can use this driver, because
it is based on simple-card driver.
To use it as more open driver, rsrc-card will be renamed to
simple-scu-card. In order to easy patch review, as 2nd step,
this patch adds new compatible "simple-scu-audio-card";
rcar-card used specific property, not "simple-audio-card",
but it should be now. Actually, rsrc-card is upstreamed driver,
but noone is using it on upstream. The user is only local,
and it is only me. Thus, there is no compatible break by this patch.
This patch uses "simple-audio-card" prefix.
And it removes rcar-card specifix compatible too.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
2016-08-23 09:34:43 +08:00
|
|
|
.name = "simple-scu-audio-card",
|
2017-08-22 12:56:06 +08:00
|
|
|
.pm = &snd_soc_pm_ops,
|
2016-08-25 09:58:31 +08:00
|
|
|
.of_match_table = asoc_simple_of_match,
|
2015-03-26 12:01:27 +08:00
|
|
|
},
|
2016-08-23 09:34:17 +08:00
|
|
|
.probe = asoc_simple_card_probe,
|
|
|
|
.remove = asoc_simple_card_remove,
|
2015-03-26 12:01:27 +08:00
|
|
|
};
|
|
|
|
|
2016-08-23 09:34:17 +08:00
|
|
|
module_platform_driver(asoc_simple_card);
|
2015-03-26 12:01:27 +08:00
|
|
|
|
2016-08-23 09:34:17 +08:00
|
|
|
MODULE_ALIAS("platform:asoc-simple-scu-card");
|
2016-08-25 09:56:38 +08:00
|
|
|
MODULE_LICENSE("GPL v2");
|
2016-08-23 09:34:17 +08:00
|
|
|
MODULE_DESCRIPTION("ASoC Simple SCU Sound Card");
|
2015-03-26 12:01:27 +08:00
|
|
|
MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
|