Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // Copyright (c) 2020 BayLibre, SAS.
0004 // Author: Jerome Brunet <jbrunet@baylibre.com>
0005 
0006 #include <linux/module.h>
0007 #include <linux/of_platform.h>
0008 #include <sound/soc.h>
0009 
0010 #include "meson-card.h"
0011 
0012 int meson_card_i2s_set_sysclk(struct snd_pcm_substream *substream,
0013                   struct snd_pcm_hw_params *params,
0014                   unsigned int mclk_fs)
0015 {
0016     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0017     struct snd_soc_dai *codec_dai;
0018     unsigned int mclk;
0019     int ret, i;
0020 
0021     if (!mclk_fs)
0022         return 0;
0023 
0024     mclk = params_rate(params) * mclk_fs;
0025 
0026     for_each_rtd_codec_dais(rtd, i, codec_dai) {
0027         ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
0028                          SND_SOC_CLOCK_IN);
0029         if (ret && ret != -ENOTSUPP)
0030             return ret;
0031     }
0032 
0033     ret = snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(rtd, 0), 0, mclk,
0034                      SND_SOC_CLOCK_OUT);
0035     if (ret && ret != -ENOTSUPP)
0036         return ret;
0037 
0038     return 0;
0039 }
0040 EXPORT_SYMBOL_GPL(meson_card_i2s_set_sysclk);
0041 
0042 int meson_card_reallocate_links(struct snd_soc_card *card,
0043                 unsigned int num_links)
0044 {
0045     struct meson_card *priv = snd_soc_card_get_drvdata(card);
0046     struct snd_soc_dai_link *links;
0047     void **ldata;
0048 
0049     links = krealloc(priv->card.dai_link,
0050              num_links * sizeof(*priv->card.dai_link),
0051              GFP_KERNEL | __GFP_ZERO);
0052     if (!links)
0053         goto err_links;
0054 
0055     ldata = krealloc(priv->link_data,
0056              num_links * sizeof(*priv->link_data),
0057              GFP_KERNEL | __GFP_ZERO);
0058     if (!ldata)
0059         goto err_ldata;
0060 
0061     priv->card.dai_link = links;
0062     priv->link_data = ldata;
0063     priv->card.num_links = num_links;
0064     return 0;
0065 
0066 err_ldata:
0067     kfree(links);
0068 err_links:
0069     dev_err(priv->card.dev, "failed to allocate links\n");
0070     return -ENOMEM;
0071 
0072 }
0073 EXPORT_SYMBOL_GPL(meson_card_reallocate_links);
0074 
0075 int meson_card_parse_dai(struct snd_soc_card *card,
0076              struct device_node *node,
0077              struct device_node **dai_of_node,
0078              const char **dai_name)
0079 {
0080     struct of_phandle_args args;
0081     int ret;
0082 
0083     if (!dai_name || !dai_of_node || !node)
0084         return -EINVAL;
0085 
0086     ret = of_parse_phandle_with_args(node, "sound-dai",
0087                      "#sound-dai-cells", 0, &args);
0088     if (ret)
0089         return dev_err_probe(card->dev, ret, "can't parse dai\n");
0090 
0091     *dai_of_node = args.np;
0092 
0093     return snd_soc_get_dai_name(&args, dai_name);
0094 }
0095 EXPORT_SYMBOL_GPL(meson_card_parse_dai);
0096 
0097 static int meson_card_set_link_name(struct snd_soc_card *card,
0098                     struct snd_soc_dai_link *link,
0099                     struct device_node *node,
0100                     const char *prefix)
0101 {
0102     char *name = devm_kasprintf(card->dev, GFP_KERNEL, "%s.%s",
0103                     prefix, node->full_name);
0104     if (!name)
0105         return -ENOMEM;
0106 
0107     link->name = name;
0108     link->stream_name = name;
0109 
0110     return 0;
0111 }
0112 
0113 unsigned int meson_card_parse_daifmt(struct device_node *node,
0114                      struct device_node *cpu_node)
0115 {
0116     struct device_node *bitclkmaster = NULL;
0117     struct device_node *framemaster = NULL;
0118     unsigned int daifmt;
0119 
0120     daifmt = snd_soc_daifmt_parse_format(node, NULL);
0121 
0122     snd_soc_daifmt_parse_clock_provider_as_phandle(node, NULL, &bitclkmaster, &framemaster);
0123 
0124     /* If no master is provided, default to cpu master */
0125     if (!bitclkmaster || bitclkmaster == cpu_node) {
0126         daifmt |= (!framemaster || framemaster == cpu_node) ?
0127             SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBS_CFM;
0128     } else {
0129         daifmt |= (!framemaster || framemaster == cpu_node) ?
0130             SND_SOC_DAIFMT_CBM_CFS : SND_SOC_DAIFMT_CBM_CFM;
0131     }
0132 
0133     of_node_put(bitclkmaster);
0134     of_node_put(framemaster);
0135 
0136     return daifmt;
0137 }
0138 EXPORT_SYMBOL_GPL(meson_card_parse_daifmt);
0139 
0140 int meson_card_set_be_link(struct snd_soc_card *card,
0141                struct snd_soc_dai_link *link,
0142                struct device_node *node)
0143 {
0144     struct snd_soc_dai_link_component *codec;
0145     struct device_node *np;
0146     int ret, num_codecs;
0147 
0148     num_codecs = of_get_child_count(node);
0149     if (!num_codecs) {
0150         dev_err(card->dev, "be link %s has no codec\n",
0151             node->full_name);
0152         return -EINVAL;
0153     }
0154 
0155     codec = devm_kcalloc(card->dev, num_codecs, sizeof(*codec), GFP_KERNEL);
0156     if (!codec)
0157         return -ENOMEM;
0158 
0159     link->codecs = codec;
0160     link->num_codecs = num_codecs;
0161 
0162     for_each_child_of_node(node, np) {
0163         ret = meson_card_parse_dai(card, np, &codec->of_node,
0164                        &codec->dai_name);
0165         if (ret) {
0166             of_node_put(np);
0167             return ret;
0168         }
0169 
0170         codec++;
0171     }
0172 
0173     ret = meson_card_set_link_name(card, link, node, "be");
0174     if (ret)
0175         dev_err(card->dev, "error setting %pOFn link name\n", np);
0176 
0177     return ret;
0178 }
0179 EXPORT_SYMBOL_GPL(meson_card_set_be_link);
0180 
0181 int meson_card_set_fe_link(struct snd_soc_card *card,
0182                struct snd_soc_dai_link *link,
0183                struct device_node *node,
0184                bool is_playback)
0185 {
0186     struct snd_soc_dai_link_component *codec;
0187 
0188     codec = devm_kzalloc(card->dev, sizeof(*codec), GFP_KERNEL);
0189     if (!codec)
0190         return -ENOMEM;
0191 
0192     link->codecs = codec;
0193     link->num_codecs = 1;
0194 
0195     link->dynamic = 1;
0196     link->dpcm_merged_format = 1;
0197     link->dpcm_merged_chan = 1;
0198     link->dpcm_merged_rate = 1;
0199     link->codecs->dai_name = "snd-soc-dummy-dai";
0200     link->codecs->name = "snd-soc-dummy";
0201 
0202     if (is_playback)
0203         link->dpcm_playback = 1;
0204     else
0205         link->dpcm_capture = 1;
0206 
0207     return meson_card_set_link_name(card, link, node, "fe");
0208 }
0209 EXPORT_SYMBOL_GPL(meson_card_set_fe_link);
0210 
0211 static int meson_card_add_links(struct snd_soc_card *card)
0212 {
0213     struct meson_card *priv = snd_soc_card_get_drvdata(card);
0214     struct device_node *node = card->dev->of_node;
0215     struct device_node *np;
0216     int num, i, ret;
0217 
0218     num = of_get_child_count(node);
0219     if (!num) {
0220         dev_err(card->dev, "card has no links\n");
0221         return -EINVAL;
0222     }
0223 
0224     ret = meson_card_reallocate_links(card, num);
0225     if (ret)
0226         return ret;
0227 
0228     i = 0;
0229     for_each_child_of_node(node, np) {
0230         ret = priv->match_data->add_link(card, np, &i);
0231         if (ret) {
0232             of_node_put(np);
0233             return ret;
0234         }
0235 
0236         i++;
0237     }
0238 
0239     return 0;
0240 }
0241 
0242 static int meson_card_parse_of_optional(struct snd_soc_card *card,
0243                     const char *propname,
0244                     int (*func)(struct snd_soc_card *c,
0245                             const char *p))
0246 {
0247     /* If property is not provided, don't fail ... */
0248     if (!of_property_read_bool(card->dev->of_node, propname))
0249         return 0;
0250 
0251     /* ... but do fail if it is provided and the parsing fails */
0252     return func(card, propname);
0253 }
0254 
0255 static void meson_card_clean_references(struct meson_card *priv)
0256 {
0257     struct snd_soc_card *card = &priv->card;
0258     struct snd_soc_dai_link *link;
0259     struct snd_soc_dai_link_component *codec;
0260     struct snd_soc_aux_dev *aux;
0261     int i, j;
0262 
0263     if (card->dai_link) {
0264         for_each_card_prelinks(card, i, link) {
0265             if (link->cpus)
0266                 of_node_put(link->cpus->of_node);
0267             for_each_link_codecs(link, j, codec)
0268                 of_node_put(codec->of_node);
0269         }
0270     }
0271 
0272     if (card->aux_dev) {
0273         for_each_card_pre_auxs(card, i, aux)
0274             of_node_put(aux->dlc.of_node);
0275     }
0276 
0277     kfree(card->dai_link);
0278     kfree(priv->link_data);
0279 }
0280 
0281 int meson_card_probe(struct platform_device *pdev)
0282 {
0283     const struct meson_card_match_data *data;
0284     struct device *dev = &pdev->dev;
0285     struct meson_card *priv;
0286     int ret;
0287 
0288     data = of_device_get_match_data(dev);
0289     if (!data) {
0290         dev_err(dev, "failed to match device\n");
0291         return -ENODEV;
0292     }
0293 
0294     priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0295     if (!priv)
0296         return -ENOMEM;
0297 
0298     platform_set_drvdata(pdev, priv);
0299     snd_soc_card_set_drvdata(&priv->card, priv);
0300 
0301     priv->card.owner = THIS_MODULE;
0302     priv->card.dev = dev;
0303     priv->card.driver_name = dev->driver->name;
0304     priv->match_data = data;
0305 
0306     ret = snd_soc_of_parse_card_name(&priv->card, "model");
0307     if (ret < 0)
0308         return ret;
0309 
0310     ret = meson_card_parse_of_optional(&priv->card, "audio-routing",
0311                        snd_soc_of_parse_audio_routing);
0312     if (ret) {
0313         dev_err(dev, "error while parsing routing\n");
0314         return ret;
0315     }
0316 
0317     ret = meson_card_parse_of_optional(&priv->card, "audio-widgets",
0318                        snd_soc_of_parse_audio_simple_widgets);
0319     if (ret) {
0320         dev_err(dev, "error while parsing widgets\n");
0321         return ret;
0322     }
0323 
0324     ret = meson_card_add_links(&priv->card);
0325     if (ret)
0326         goto out_err;
0327 
0328     ret = snd_soc_of_parse_aux_devs(&priv->card, "audio-aux-devs");
0329     if (ret)
0330         goto out_err;
0331 
0332     ret = devm_snd_soc_register_card(dev, &priv->card);
0333     if (ret)
0334         goto out_err;
0335 
0336     return 0;
0337 
0338 out_err:
0339     meson_card_clean_references(priv);
0340     return ret;
0341 }
0342 EXPORT_SYMBOL_GPL(meson_card_probe);
0343 
0344 int meson_card_remove(struct platform_device *pdev)
0345 {
0346     struct meson_card *priv = platform_get_drvdata(pdev);
0347 
0348     meson_card_clean_references(priv);
0349 
0350     return 0;
0351 }
0352 EXPORT_SYMBOL_GPL(meson_card_remove);
0353 
0354 MODULE_DESCRIPTION("Amlogic Sound Card Utils");
0355 MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
0356 MODULE_LICENSE("GPL v2");