Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // Copyright (C) 2017 Samsung Electronics Co., Ltd.
0004 
0005 #include <linux/clk.h>
0006 #include <linux/clk-provider.h>
0007 #include <linux/of.h>
0008 #include <linux/of_device.h>
0009 #include <linux/module.h>
0010 #include <sound/soc.h>
0011 #include <sound/pcm_params.h>
0012 #include "i2s.h"
0013 #include "i2s-regs.h"
0014 
0015 struct odroid_priv {
0016     struct snd_soc_card card;
0017     struct clk *clk_i2s_bus;
0018     struct clk *sclk_i2s;
0019 
0020     /* Spinlock protecting fields below */
0021     spinlock_t lock;
0022     unsigned int be_sample_rate;
0023     bool be_active;
0024 };
0025 
0026 static int odroid_card_fe_startup(struct snd_pcm_substream *substream)
0027 {
0028     struct snd_pcm_runtime *runtime = substream->runtime;
0029 
0030     snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2);
0031 
0032     return 0;
0033 }
0034 
0035 static int odroid_card_fe_hw_params(struct snd_pcm_substream *substream,
0036                       struct snd_pcm_hw_params *params)
0037 {
0038     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0039     struct odroid_priv *priv = snd_soc_card_get_drvdata(rtd->card);
0040     unsigned long flags;
0041     int ret = 0;
0042 
0043     spin_lock_irqsave(&priv->lock, flags);
0044     if (priv->be_active && priv->be_sample_rate != params_rate(params))
0045         ret = -EINVAL;
0046     spin_unlock_irqrestore(&priv->lock, flags);
0047 
0048     return ret;
0049 }
0050 
0051 static const struct snd_soc_ops odroid_card_fe_ops = {
0052     .startup = odroid_card_fe_startup,
0053     .hw_params = odroid_card_fe_hw_params,
0054 };
0055 
0056 static int odroid_card_be_hw_params(struct snd_pcm_substream *substream,
0057                       struct snd_pcm_hw_params *params)
0058 {
0059     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0060     struct odroid_priv *priv = snd_soc_card_get_drvdata(rtd->card);
0061     unsigned int pll_freq, rclk_freq, rfs;
0062     unsigned long flags;
0063     int ret;
0064 
0065     switch (params_rate(params)) {
0066     case 64000:
0067         pll_freq = 196608001U;
0068         rfs = 384;
0069         break;
0070     case 44100:
0071     case 88200:
0072         pll_freq = 180633609U;
0073         rfs = 512;
0074         break;
0075     case 32000:
0076     case 48000:
0077     case 96000:
0078         pll_freq = 196608001U;
0079         rfs = 512;
0080         break;
0081     default:
0082         return -EINVAL;
0083     }
0084 
0085     ret = clk_set_rate(priv->clk_i2s_bus, pll_freq / 2 + 1);
0086     if (ret < 0)
0087         return ret;
0088 
0089     /*
0090      *  We add 2 to the rclk_freq value in order to avoid too low clock
0091      *  frequency values due to the EPLL output frequency not being exact
0092      *  multiple of the audio sampling rate.
0093      */
0094     rclk_freq = params_rate(params) * rfs + 2;
0095 
0096     ret = clk_set_rate(priv->sclk_i2s, rclk_freq);
0097     if (ret < 0)
0098         return ret;
0099 
0100     if (rtd->num_codecs > 1) {
0101         struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 1);
0102 
0103         ret = snd_soc_dai_set_sysclk(codec_dai, 0, rclk_freq,
0104                          SND_SOC_CLOCK_IN);
0105         if (ret < 0)
0106             return ret;
0107     }
0108 
0109     spin_lock_irqsave(&priv->lock, flags);
0110     priv->be_sample_rate = params_rate(params);
0111     spin_unlock_irqrestore(&priv->lock, flags);
0112 
0113     return 0;
0114 }
0115 
0116 static int odroid_card_be_trigger(struct snd_pcm_substream *substream, int cmd)
0117 {
0118     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0119     struct odroid_priv *priv = snd_soc_card_get_drvdata(rtd->card);
0120     unsigned long flags;
0121 
0122     spin_lock_irqsave(&priv->lock, flags);
0123 
0124     switch (cmd) {
0125     case SNDRV_PCM_TRIGGER_START:
0126     case SNDRV_PCM_TRIGGER_RESUME:
0127     case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
0128         priv->be_active = true;
0129         break;
0130 
0131     case SNDRV_PCM_TRIGGER_STOP:
0132     case SNDRV_PCM_TRIGGER_SUSPEND:
0133     case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
0134         priv->be_active = false;
0135         break;
0136     }
0137 
0138     spin_unlock_irqrestore(&priv->lock, flags);
0139 
0140     return 0;
0141 }
0142 
0143 static const struct snd_soc_ops odroid_card_be_ops = {
0144     .hw_params = odroid_card_be_hw_params,
0145     .trigger = odroid_card_be_trigger,
0146 };
0147 
0148 /* DAPM routes for backward compatibility with old DTS */
0149 static const struct snd_soc_dapm_route odroid_dapm_routes[] = {
0150     { "I2S Playback", NULL, "Mixer DAI TX" },
0151     { "HiFi Playback", NULL, "Mixer DAI TX" },
0152 };
0153 
0154 SND_SOC_DAILINK_DEFS(primary,
0155     DAILINK_COMP_ARRAY(COMP_EMPTY()),
0156     DAILINK_COMP_ARRAY(COMP_DUMMY()),
0157     DAILINK_COMP_ARRAY(COMP_PLATFORM("3830000.i2s")));
0158 
0159 SND_SOC_DAILINK_DEFS(mixer,
0160     DAILINK_COMP_ARRAY(COMP_DUMMY()),
0161     DAILINK_COMP_ARRAY(COMP_EMPTY()),
0162     DAILINK_COMP_ARRAY(COMP_DUMMY()));
0163 
0164 SND_SOC_DAILINK_DEFS(secondary,
0165     DAILINK_COMP_ARRAY(COMP_EMPTY()),
0166     DAILINK_COMP_ARRAY(COMP_DUMMY()),
0167     DAILINK_COMP_ARRAY(COMP_PLATFORM("3830000.i2s-sec")));
0168 
0169 static struct snd_soc_dai_link odroid_card_dais[] = {
0170     {
0171         /* Primary FE <-> BE link */
0172         .ops = &odroid_card_fe_ops,
0173         .name = "Primary",
0174         .stream_name = "Primary",
0175         .dynamic = 1,
0176         .dpcm_playback = 1,
0177         SND_SOC_DAILINK_REG(primary),
0178     }, {
0179         /* BE <-> CODECs link */
0180         .name = "I2S Mixer",
0181         .ops = &odroid_card_be_ops,
0182         .no_pcm = 1,
0183         .dpcm_playback = 1,
0184         .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
0185                 SND_SOC_DAIFMT_CBS_CFS,
0186         SND_SOC_DAILINK_REG(mixer),
0187     }, {
0188         /* Secondary FE <-> BE link */
0189         .playback_only = 1,
0190         .ops = &odroid_card_fe_ops,
0191         .name = "Secondary",
0192         .stream_name = "Secondary",
0193         .dynamic = 1,
0194         .dpcm_playback = 1,
0195         SND_SOC_DAILINK_REG(secondary),
0196     }
0197 };
0198 
0199 static int odroid_audio_probe(struct platform_device *pdev)
0200 {
0201     struct device *dev = &pdev->dev;
0202     struct device_node *cpu_dai = NULL;
0203     struct device_node *cpu, *codec;
0204     struct odroid_priv *priv;
0205     struct snd_soc_card *card;
0206     struct snd_soc_dai_link *link, *codec_link;
0207     int num_pcms, ret, i;
0208     struct of_phandle_args args = {};
0209 
0210     priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0211     if (!priv)
0212         return -ENOMEM;
0213 
0214     card = &priv->card;
0215     card->dev = dev;
0216 
0217     card->owner = THIS_MODULE;
0218     card->fully_routed = true;
0219 
0220     spin_lock_init(&priv->lock);
0221     snd_soc_card_set_drvdata(card, priv);
0222 
0223     ret = snd_soc_of_parse_card_name(card, "model");
0224     if (ret < 0)
0225         return ret;
0226 
0227     if (of_property_read_bool(dev->of_node, "samsung,audio-widgets")) {
0228         ret = snd_soc_of_parse_audio_simple_widgets(card,
0229                         "samsung,audio-widgets");
0230         if (ret < 0)
0231             return ret;
0232     }
0233 
0234     if (of_property_read_bool(dev->of_node, "samsung,audio-routing")) {
0235         ret = snd_soc_of_parse_audio_routing(card,
0236                         "samsung,audio-routing");
0237         if (ret < 0)
0238             return ret;
0239     }
0240 
0241     card->dai_link = odroid_card_dais;
0242     card->num_links = ARRAY_SIZE(odroid_card_dais);
0243 
0244     cpu = of_get_child_by_name(dev->of_node, "cpu");
0245     codec = of_get_child_by_name(dev->of_node, "codec");
0246     link = card->dai_link;
0247     codec_link = &card->dai_link[1];
0248 
0249     /*
0250      * For backwards compatibility create the secondary CPU DAI link only
0251      * if there are 2 CPU DAI entries in the cpu sound-dai property in DT.
0252      * Also add required DAPM routes not available in old DTS.
0253      */
0254     num_pcms = of_count_phandle_with_args(cpu, "sound-dai",
0255                           "#sound-dai-cells");
0256     if (num_pcms == 1) {
0257         card->dapm_routes = odroid_dapm_routes;
0258         card->num_dapm_routes = ARRAY_SIZE(odroid_dapm_routes);
0259         card->num_links--;
0260     }
0261 
0262     for (i = 0; i < num_pcms; i++, link += 2) {
0263         ret = of_parse_phandle_with_args(cpu, "sound-dai",
0264                          "#sound-dai-cells", i, &args);
0265         if (ret < 0)
0266             break;
0267 
0268         if (!args.np) {
0269             dev_err(dev, "sound-dai property parse error: %d\n", ret);
0270             ret = -EINVAL;
0271             break;
0272         }
0273 
0274         ret = snd_soc_get_dai_name(&args, &link->cpus->dai_name);
0275         of_node_put(args.np);
0276 
0277         if (ret < 0)
0278             break;
0279     }
0280     if (ret == 0) {
0281         cpu_dai = of_parse_phandle(cpu, "sound-dai", 0);
0282         if (!cpu_dai)
0283             ret = -EINVAL;
0284     }
0285 
0286     of_node_put(cpu);
0287     if (ret < 0)
0288         goto err_put_node;
0289 
0290     ret = snd_soc_of_get_dai_link_codecs(dev, codec, codec_link);
0291     if (ret < 0)
0292         goto err_put_cpu_dai;
0293 
0294     /* Set capture capability only for boards with the MAX98090 CODEC */
0295     if (codec_link->num_codecs > 1) {
0296         card->dai_link[0].dpcm_capture = 1;
0297         card->dai_link[1].dpcm_capture = 1;
0298     }
0299 
0300     priv->sclk_i2s = of_clk_get_by_name(cpu_dai, "i2s_opclk1");
0301     if (IS_ERR(priv->sclk_i2s)) {
0302         ret = PTR_ERR(priv->sclk_i2s);
0303         goto err_put_cpu_dai;
0304     }
0305 
0306     priv->clk_i2s_bus = of_clk_get_by_name(cpu_dai, "iis");
0307     if (IS_ERR(priv->clk_i2s_bus)) {
0308         ret = PTR_ERR(priv->clk_i2s_bus);
0309         goto err_put_sclk;
0310     }
0311 
0312     ret = devm_snd_soc_register_card(dev, card);
0313     if (ret < 0) {
0314         dev_err_probe(dev, ret, "snd_soc_register_card() failed\n");
0315         goto err_put_clk_i2s;
0316     }
0317 
0318     of_node_put(cpu_dai);
0319     of_node_put(codec);
0320     return 0;
0321 
0322 err_put_clk_i2s:
0323     clk_put(priv->clk_i2s_bus);
0324 err_put_sclk:
0325     clk_put(priv->sclk_i2s);
0326 err_put_cpu_dai:
0327     of_node_put(cpu_dai);
0328     snd_soc_of_put_dai_link_codecs(codec_link);
0329 err_put_node:
0330     of_node_put(codec);
0331     return ret;
0332 }
0333 
0334 static int odroid_audio_remove(struct platform_device *pdev)
0335 {
0336     struct odroid_priv *priv = platform_get_drvdata(pdev);
0337 
0338     snd_soc_of_put_dai_link_codecs(&priv->card.dai_link[1]);
0339     clk_put(priv->sclk_i2s);
0340     clk_put(priv->clk_i2s_bus);
0341 
0342     return 0;
0343 }
0344 
0345 static const struct of_device_id odroid_audio_of_match[] = {
0346     { .compatible   = "hardkernel,odroid-xu3-audio" },
0347     { .compatible   = "hardkernel,odroid-xu4-audio" },
0348     { .compatible   = "samsung,odroid-xu3-audio" },
0349     { .compatible   = "samsung,odroid-xu4-audio" },
0350     { },
0351 };
0352 MODULE_DEVICE_TABLE(of, odroid_audio_of_match);
0353 
0354 static struct platform_driver odroid_audio_driver = {
0355     .driver = {
0356         .name       = "odroid-audio",
0357         .of_match_table = odroid_audio_of_match,
0358         .pm     = &snd_soc_pm_ops,
0359     },
0360     .probe  = odroid_audio_probe,
0361     .remove = odroid_audio_remove,
0362 };
0363 module_platform_driver(odroid_audio_driver);
0364 
0365 MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
0366 MODULE_DESCRIPTION("Odroid XU3/XU4 audio support");
0367 MODULE_LICENSE("GPL v2");