diff options
Diffstat (limited to 'sound/soc/sh/rcar/rsrc-card.c')
-rw-r--r-- | sound/soc/sh/rcar/rsrc-card.c | 439 |
1 files changed, 192 insertions, 247 deletions
diff --git a/sound/soc/sh/rcar/rsrc-card.c b/sound/soc/sh/rcar/rsrc-card.c index a68517afe615..84e935711e29 100644 --- a/sound/soc/sh/rcar/rsrc-card.c +++ b/sound/soc/sh/rcar/rsrc-card.c @@ -45,61 +45,48 @@ static const struct of_device_id rsrc_card_of_match[] = { }; MODULE_DEVICE_TABLE(of, rsrc_card_of_match); +#define DAI_NAME_NUM 32 struct rsrc_card_dai { - const char *name; unsigned int fmt; unsigned int sysclk; struct clk *clk; + char dai_name[DAI_NAME_NUM]; }; -#define RSRC_FB_NUM 2 /* FE/BE */ #define IDX_CPU 0 #define IDX_CODEC 1 struct rsrc_card_priv { struct snd_soc_card snd_card; - struct rsrc_card_dai_props { - struct rsrc_card_dai cpu_dai; - struct rsrc_card_dai codec_dai; - } dai_props[RSRC_FB_NUM]; struct snd_soc_codec_conf codec_conf; - struct snd_soc_dai_link dai_link[RSRC_FB_NUM]; + struct rsrc_card_dai *dai_props; + struct snd_soc_dai_link *dai_link; + int dai_num; u32 convert_rate; }; #define rsrc_priv_to_dev(priv) ((priv)->snd_card.dev) -#define rsrc_priv_to_link(priv, i) ((priv)->snd_card.dai_link + i) -#define rsrc_priv_to_props(priv, i) ((priv)->dai_props + i) +#define rsrc_priv_to_link(priv, i) ((priv)->snd_card.dai_link + (i)) +#define rsrc_priv_to_props(priv, i) ((priv)->dai_props + (i)) #define rsrc_dev_to_of_data(dev) (of_match_device(rsrc_card_of_match, (dev))->data) static int rsrc_card_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); - struct rsrc_card_dai_props *dai_props = - &priv->dai_props[rtd - rtd->card->rtd]; - int ret; - - ret = clk_prepare_enable(dai_props->cpu_dai.clk); - if (ret) - return ret; + struct rsrc_card_dai *dai_props = + rsrc_priv_to_props(priv, rtd - rtd->card->rtd); - ret = clk_prepare_enable(dai_props->codec_dai.clk); - if (ret) - clk_disable_unprepare(dai_props->cpu_dai.clk); - - return ret; + return clk_prepare_enable(dai_props->clk); } static void rsrc_card_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); - struct rsrc_card_dai_props *dai_props = - &priv->dai_props[rtd - rtd->card->rtd]; - - clk_disable_unprepare(dai_props->cpu_dai.clk); + struct rsrc_card_dai *dai_props = + rsrc_priv_to_props(priv, rtd - rtd->card->rtd); - clk_disable_unprepare(dai_props->codec_dai.clk); + clk_disable_unprepare(dai_props->clk); } static struct snd_soc_ops rsrc_card_ops = { @@ -107,21 +94,31 @@ static struct snd_soc_ops rsrc_card_ops = { .shutdown = rsrc_card_shutdown, }; -static int __rsrc_card_dai_init(struct snd_soc_dai *dai, - struct rsrc_card_dai *set) +static int rsrc_card_dai_init(struct snd_soc_pcm_runtime *rtd) { + struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *dai; + struct snd_soc_dai_link *dai_link; + struct rsrc_card_dai *dai_props; + int num = rtd - rtd->card->rtd; int ret; - if (set->fmt) { - ret = snd_soc_dai_set_fmt(dai, set->fmt); + dai_link = rsrc_priv_to_link(priv, num); + dai_props = rsrc_priv_to_props(priv, num); + dai = dai_link->dynamic ? + rtd->cpu_dai : + rtd->codec_dai; + + if (dai_props->fmt) { + ret = snd_soc_dai_set_fmt(dai, dai_props->fmt); if (ret && ret != -ENOTSUPP) { dev_err(dai->dev, "set_fmt error\n"); goto err; } } - if (set->sysclk) { - ret = snd_soc_dai_set_sysclk(dai, 0, set->sysclk, 0); + if (dai_props->sysclk) { + ret = snd_soc_dai_set_sysclk(dai, 0, dai_props->sysclk, 0); if (ret && ret != -ENOTSUPP) { dev_err(dai->dev, "set_sysclk error\n"); goto err; @@ -134,27 +131,6 @@ err: return ret; } -static int rsrc_card_dai_init(struct snd_soc_pcm_runtime *rtd) -{ - struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *codec = rtd->codec_dai; - struct snd_soc_dai *cpu = rtd->cpu_dai; - struct rsrc_card_dai_props *dai_props; - int num, ret; - - num = rtd - rtd->card->rtd; - dai_props = &priv->dai_props[num]; - ret = __rsrc_card_dai_init(codec, &dai_props->codec_dai); - if (ret < 0) - return ret; - - ret = __rsrc_card_dai_init(cpu, &dai_props->cpu_dai); - if (ret < 0) - return ret; - - return 0; -} - static int rsrc_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -170,40 +146,47 @@ static int rsrc_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } -static int -rsrc_card_sub_parse_of(struct rsrc_card_priv *priv, - struct device_node *np, - struct rsrc_card_dai *dai, - struct snd_soc_dai_link *dai_link, - int *args_count) +static int rsrc_card_parse_daifmt(struct device_node *node, + struct device_node *np, + struct rsrc_card_priv *priv, + int idx, bool is_fe) { - struct device *dev = rsrc_priv_to_dev(priv); - const struct rsrc_card_of_data *of_data = rsrc_dev_to_of_data(dev); - struct of_phandle_args args; - struct device_node **p_node; - struct clk *clk; - const char **dai_name; - const char **name; - u32 val; - int ret; + struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx); + struct device_node *bitclkmaster = NULL; + struct device_node *framemaster = NULL; + struct device_node *codec = is_fe ? NULL : np; + unsigned int daifmt; - if (args_count) { - p_node = &dai_link->cpu_of_node; - dai_name = &dai_link->cpu_dai_name; - name = &dai_link->cpu_name; - } else { - p_node = &dai_link->codec_of_node; - dai_name = &dai_link->codec_dai_name; - name = &dai_link->codec_name; - } + daifmt = snd_soc_of_parse_daifmt(node, NULL, + &bitclkmaster, &framemaster); + daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK; - if (!np) { - /* use snd-soc-dummy */ - *p_node = NULL; - *dai_name = "snd-soc-dummy-dai"; - *name = "snd-soc-dummy"; - return 0; - } + if (!bitclkmaster && !framemaster) + return -EINVAL; + + if (codec == bitclkmaster) + daifmt |= (codec == framemaster) ? + SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBM_CFS; + else + daifmt |= (codec == framemaster) ? + SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS; + + dai_props->fmt = daifmt; + + of_node_put(bitclkmaster); + of_node_put(framemaster); + + return 0; +} + +static int rsrc_card_parse_links(struct device_node *np, + struct rsrc_card_priv *priv, + int idx, bool is_fe) +{ + struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx); + struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx); + struct of_phandle_args args; + int ret; /* * Get node via "sound-dai = <&phandle port>" @@ -214,30 +197,82 @@ rsrc_card_sub_parse_of(struct rsrc_card_priv *priv, if (ret) return ret; - *p_node = args.np; + if (is_fe) { + /* BE is dummy */ + dai_link->codec_of_node = NULL; + dai_link->codec_dai_name = "snd-soc-dummy-dai"; + dai_link->codec_name = "snd-soc-dummy"; + + /* FE settings */ + dai_link->dynamic = 1; + dai_link->dpcm_merged_format = 1; + dai_link->cpu_of_node = args.np; + snd_soc_of_get_dai_name(np, &dai_link->cpu_dai_name); + + /* set dai_name */ + snprintf(dai_props->dai_name, DAI_NAME_NUM, "fe.%s", + dai_link->cpu_dai_name); + + /* + * In soc_bind_dai_link() will check cpu name after + * of_node matching if dai_link has cpu_dai_name. + * but, it will never match if name was created by + * fmt_single_name() remove cpu_dai_name if cpu_args + * was 0. See: + * fmt_single_name() + * fmt_multiple_name() + */ + if (!args.args_count) + dai_link->cpu_dai_name = NULL; + } else { + struct device *dev = rsrc_priv_to_dev(priv); + const struct rsrc_card_of_data *of_data; - /* Get dai->name */ - ret = snd_soc_of_get_dai_name(np, dai_name); - if (ret < 0) - return ret; + of_data = rsrc_dev_to_of_data(dev); - /* - * FIXME - * - * rsrc assumes DPCM playback/capture - */ - dai_link->dpcm_playback = 1; - dai_link->dpcm_capture = 1; + /* 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"; - if (args_count) { - *args_count = args.args_count; - dai_link->dynamic = 1; - } else { - dai_link->no_pcm = 1; - priv->codec_conf.of_node = (*p_node); - priv->codec_conf.name_prefix = of_data->prefix; + /* BE settings */ + dai_link->no_pcm = 1; + dai_link->be_hw_params_fixup = rsrc_card_be_hw_params_fixup; + dai_link->codec_of_node = args.np; + snd_soc_of_get_dai_name(np, &dai_link->codec_dai_name); + + /* additional name prefix */ + priv->codec_conf.of_node = dai_link->codec_of_node; + priv->codec_conf.name_prefix = of_data->prefix; + + /* set dai_name */ + snprintf(dai_props->dai_name, DAI_NAME_NUM, "be.%s", + dai_link->codec_dai_name); } + /* Simple Card assumes platform == cpu */ + dai_link->platform_of_node = dai_link->cpu_of_node; + dai_link->dpcm_playback = 1; + dai_link->dpcm_capture = 1; + dai_link->name = dai_props->dai_name; + dai_link->stream_name = dai_props->dai_name; + dai_link->ops = &rsrc_card_ops; + dai_link->init = rsrc_card_dai_init; + + return 0; +} + +static int rsrc_card_parse_clk(struct device_node *np, + struct rsrc_card_priv *priv, + int idx, bool is_fe) +{ + struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx); + struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx); + struct clk *clk; + struct device_node *of_np = is_fe ? dai_link->cpu_of_node : + dai_link->codec_of_node; + u32 val; + /* * Parse dai->sysclk come from "clocks = <&xxx>" * (if system has common clock) @@ -246,173 +281,92 @@ rsrc_card_sub_parse_of(struct rsrc_card_priv *priv, */ if (of_property_read_bool(np, "clocks")) { clk = of_clk_get(np, 0); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - return ret; - } + if (IS_ERR(clk)) + return PTR_ERR(clk); - dai->sysclk = clk_get_rate(clk); - dai->clk = clk; + dai_props->sysclk = clk_get_rate(clk); + dai_props->clk = clk; } else if (!of_property_read_u32(np, "system-clock-frequency", &val)) { - dai->sysclk = val; + dai_props->sysclk = val; } else { - clk = of_clk_get(args.np, 0); + clk = of_clk_get(of_np, 0); if (!IS_ERR(clk)) - dai->sysclk = clk_get_rate(clk); + dai_props->sysclk = clk_get_rate(clk); } return 0; } -static int rsrc_card_parse_daifmt(struct device_node *node, - struct rsrc_card_priv *priv, - struct device_node *codec, - int idx) -{ - struct device_node *bitclkmaster = NULL; - struct device_node *framemaster = NULL; - struct rsrc_card_dai_props *dai_props = rsrc_priv_to_props(priv, idx); - struct rsrc_card_dai *cpu_dai = &dai_props->cpu_dai; - struct rsrc_card_dai *codec_dai = &dai_props->codec_dai; - unsigned int daifmt; - - daifmt = snd_soc_of_parse_daifmt(node, NULL, - &bitclkmaster, &framemaster); - daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK; - - if (!bitclkmaster && !framemaster) - return -EINVAL; - - if (codec == bitclkmaster) - daifmt |= (codec == framemaster) ? - SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBM_CFS; - else - daifmt |= (codec == framemaster) ? - SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS; - - cpu_dai->fmt = daifmt; - codec_dai->fmt = daifmt; - - of_node_put(bitclkmaster); - of_node_put(framemaster); - - return 0; -} - static int rsrc_card_dai_link_of(struct device_node *node, + struct device_node *np, struct rsrc_card_priv *priv, int idx) { struct device *dev = rsrc_priv_to_dev(priv); - struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx); - struct rsrc_card_dai_props *dai_props = rsrc_priv_to_props(priv, idx); - struct device_node *cpu = NULL; - struct device_node *codec = NULL; - char *name; - char prop[128]; - int ret, cpu_args; - - cpu = of_get_child_by_name(node, "cpu"); - codec = of_get_child_by_name(node, "codec"); - - if (!cpu || !codec) { - ret = -EINVAL; - dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); - goto dai_link_of_err; - } + struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx); + bool is_fe = false; + int ret; - ret = rsrc_card_parse_daifmt(node, priv, codec, idx); - if (ret < 0) - goto dai_link_of_err; + if (0 == strcmp(np->name, "cpu")) + is_fe = true; - ret = rsrc_card_sub_parse_of(priv, (idx == IDX_CPU) ? cpu : NULL, - &dai_props->cpu_dai, - dai_link, - &cpu_args); + ret = rsrc_card_parse_daifmt(node, np, priv, idx, is_fe); if (ret < 0) - goto dai_link_of_err; + return ret; - ret = rsrc_card_sub_parse_of(priv, (idx == IDX_CODEC) ? codec : NULL, - &dai_props->codec_dai, - dai_link, - NULL); + ret = rsrc_card_parse_links(np, priv, idx, is_fe); if (ret < 0) - goto dai_link_of_err; - - if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) { - ret = -EINVAL; - goto dai_link_of_err; - } - - /* Simple Card assumes platform == cpu */ - dai_link->platform_of_node = dai_link->cpu_of_node; - - /* DAI link name is created from CPU/CODEC dai name */ - name = devm_kzalloc(dev, - strlen(dai_link->cpu_dai_name) + - strlen(dai_link->codec_dai_name) + 2, - GFP_KERNEL); - if (!name) { - ret = -ENOMEM; - goto dai_link_of_err; - } - - sprintf(name, "%s-%s", dai_link->cpu_dai_name, - dai_link->codec_dai_name); - dai_link->name = dai_link->stream_name = name; - dai_link->ops = &rsrc_card_ops; - dai_link->init = rsrc_card_dai_init; - - if (idx == IDX_CODEC) - dai_link->be_hw_params_fixup = rsrc_card_be_hw_params_fixup; - - dev_dbg(dev, "\tname : %s\n", dai_link->stream_name); - dev_dbg(dev, "\tcpu : %s / %04x / %d\n", - dai_link->cpu_dai_name, - dai_props->cpu_dai.fmt, - dai_props->cpu_dai.sysclk); - dev_dbg(dev, "\tcodec : %s / %04x / %d\n", - dai_link->codec_dai_name, - dai_props->codec_dai.fmt, - dai_props->codec_dai.sysclk); + return ret; - /* - * In soc_bind_dai_link() will check cpu name after - * of_node matching if dai_link has cpu_dai_name. - * but, it will never match if name was created by - * fmt_single_name() remove cpu_dai_name if cpu_args - * was 0. See: - * fmt_single_name() - * fmt_multiple_name() - */ - if (!cpu_args) - dai_link->cpu_dai_name = NULL; + ret = rsrc_card_parse_clk(np, priv, idx, is_fe); + if (ret < 0) + return ret; -dai_link_of_err: - of_node_put(cpu); - of_node_put(codec); + dev_dbg(dev, "\t%s / %04x / %d\n", + dai_props->dai_name, + dai_props->fmt, + dai_props->sysclk); return ret; } static int rsrc_card_parse_of(struct device_node *node, - struct rsrc_card_priv *priv) + struct rsrc_card_priv *priv, + struct device *dev) { - struct device *dev = rsrc_priv_to_dev(priv); const struct rsrc_card_of_data *of_data = rsrc_dev_to_of_data(dev); + struct rsrc_card_dai *props; + struct snd_soc_dai_link *links; + struct device_node *np; int ret; - int i; + int i, num; if (!node) return -EINVAL; - /* Parse the card name from DT */ - snd_soc_of_parse_card_name(&priv->snd_card, "card-name"); + num = of_get_child_count(node); + props = devm_kzalloc(dev, sizeof(*props) * num, GFP_KERNEL); + links = devm_kzalloc(dev, sizeof(*links) * num, GFP_KERNEL); + if (!props || !links) + return -ENOMEM; + + priv->dai_props = props; + priv->dai_link = links; + priv->dai_num = num; - /* DAPM routes */ + /* Init snd_soc_card */ + priv->snd_card.owner = THIS_MODULE; + priv->snd_card.dev = dev; + priv->snd_card.dai_link = priv->dai_link; + priv->snd_card.num_links = num; + priv->snd_card.codec_conf = &priv->codec_conf; + priv->snd_card.num_configs = 1; priv->snd_card.of_dapm_routes = of_data->routes; priv->snd_card.num_of_dapm_routes = of_data->num_routes; + /* Parse the card name from DT */ + snd_soc_of_parse_card_name(&priv->snd_card, "card-name"); + /* sampling rate convert */ of_property_read_u32(node, "convert-rate", &priv->convert_rate); @@ -420,11 +374,12 @@ static int rsrc_card_parse_of(struct device_node *node, priv->snd_card.name ? priv->snd_card.name : "", priv->convert_rate); - /* FE/BE */ - for (i = 0; i < RSRC_FB_NUM; i++) { - ret = rsrc_card_dai_link_of(node, priv, i); + i = 0; + for_each_child_of_node(node, np) { + ret = rsrc_card_dai_link_of(node, np, priv, i); if (ret < 0) return ret; + i++; } if (!priv->snd_card.name) @@ -451,7 +406,6 @@ static int rsrc_card_unref(struct snd_soc_card *card) static int rsrc_card_probe(struct platform_device *pdev) { struct rsrc_card_priv *priv; - struct snd_soc_dai_link *dai_link; struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev; int ret; @@ -461,16 +415,7 @@ static int rsrc_card_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - /* Init snd_soc_card */ - priv->snd_card.owner = THIS_MODULE; - priv->snd_card.dev = dev; - dai_link = priv->dai_link; - priv->snd_card.dai_link = dai_link; - priv->snd_card.num_links = RSRC_FB_NUM; - priv->snd_card.codec_conf = &priv->codec_conf; - priv->snd_card.num_configs = 1; - - ret = rsrc_card_parse_of(np, priv); + ret = rsrc_card_parse_of(np, priv, dev); if (ret < 0) { if (ret != -EPROBE_DEFER) dev_err(dev, "parse error %d\n", ret); |