Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // Modifications by Christian Pellegrin <chripell@evolware.org>
0004 //
0005 // s3c24xx_uda134x.c - S3C24XX_UDA134X ALSA SoC Audio board driver
0006 //
0007 // Copyright 2007 Dension Audio Systems Ltd.
0008 // Author: Zoltan Devai
0009 
0010 #include <linux/clk.h>
0011 #include <linux/gpio.h>
0012 #include <linux/module.h>
0013 
0014 #include <sound/soc.h>
0015 #include <sound/s3c24xx_uda134x.h>
0016 
0017 #include "regs-iis.h"
0018 #include "s3c24xx-i2s.h"
0019 
0020 struct s3c24xx_uda134x {
0021     struct clk *xtal;
0022     struct clk *pclk;
0023     struct mutex clk_lock;
0024     int clk_users;
0025 };
0026 
0027 /* #define ENFORCE_RATES 1 */
0028 /*
0029   Unfortunately the S3C24XX in master mode has a limited capacity of
0030   generating the clock for the codec. If you define this only rates
0031   that are really available will be enforced. But be careful, most
0032   user level application just want the usual sampling frequencies (8,
0033   11.025, 22.050, 44.1 kHz) and anyway resampling is a costly
0034   operation for embedded systems. So if you aren't very lucky or your
0035   hardware engineer wasn't very forward-looking it's better to leave
0036   this undefined. If you do so an approximate value for the requested
0037   sampling rate in the range -/+ 5% will be chosen. If this in not
0038   possible an error will be returned.
0039 */
0040 
0041 static unsigned int rates[33 * 2];
0042 #ifdef ENFORCE_RATES
0043 static const struct snd_pcm_hw_constraint_list hw_constraints_rates = {
0044     .count  = ARRAY_SIZE(rates),
0045     .list   = rates,
0046     .mask   = 0,
0047 };
0048 #endif
0049 
0050 static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream)
0051 {
0052     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0053     struct s3c24xx_uda134x *priv = snd_soc_card_get_drvdata(rtd->card);
0054     struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
0055     int ret = 0;
0056 
0057     mutex_lock(&priv->clk_lock);
0058 
0059     if (priv->clk_users == 0) {
0060         priv->xtal = clk_get(rtd->dev, "xtal");
0061         if (IS_ERR(priv->xtal)) {
0062             dev_err(rtd->dev, "%s cannot get xtal\n", __func__);
0063             ret = PTR_ERR(priv->xtal);
0064         } else {
0065             priv->pclk = clk_get(cpu_dai->dev, "iis");
0066             if (IS_ERR(priv->pclk)) {
0067                 dev_err(rtd->dev, "%s cannot get pclk\n",
0068                     __func__);
0069                 clk_put(priv->xtal);
0070                 ret = PTR_ERR(priv->pclk);
0071             }
0072         }
0073         if (!ret) {
0074             int i, j;
0075 
0076             for (i = 0; i < 2; i++) {
0077                 int fs = i ? 256 : 384;
0078 
0079                 rates[i*33] = clk_get_rate(priv->xtal) / fs;
0080                 for (j = 1; j < 33; j++)
0081                     rates[i*33 + j] = clk_get_rate(priv->pclk) /
0082                         (j * fs);
0083             }
0084         }
0085     }
0086     priv->clk_users += 1;
0087     mutex_unlock(&priv->clk_lock);
0088 
0089     if (!ret) {
0090 #ifdef ENFORCE_RATES
0091         ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
0092                          SNDRV_PCM_HW_PARAM_RATE,
0093                          &hw_constraints_rates);
0094         if (ret < 0)
0095             dev_err(rtd->dev, "%s cannot set constraints\n",
0096                 __func__);
0097 #endif
0098     }
0099     return ret;
0100 }
0101 
0102 static void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream)
0103 {
0104     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0105     struct s3c24xx_uda134x *priv = snd_soc_card_get_drvdata(rtd->card);
0106 
0107     mutex_lock(&priv->clk_lock);
0108     priv->clk_users -= 1;
0109     if (priv->clk_users == 0) {
0110         clk_put(priv->xtal);
0111         priv->xtal = NULL;
0112         clk_put(priv->pclk);
0113         priv->pclk = NULL;
0114     }
0115     mutex_unlock(&priv->clk_lock);
0116 }
0117 
0118 static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream,
0119                     struct snd_pcm_hw_params *params)
0120 {
0121     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0122     struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
0123     struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
0124     unsigned int clk = 0;
0125     int ret = 0;
0126     int clk_source, fs_mode;
0127     unsigned long rate = params_rate(params);
0128     long err, cerr;
0129     unsigned int div;
0130     int i, bi;
0131 
0132     err = 999999;
0133     bi = 0;
0134     for (i = 0; i < 2*33; i++) {
0135         cerr = rates[i] - rate;
0136         if (cerr < 0)
0137             cerr = -cerr;
0138         if (cerr < err) {
0139             err = cerr;
0140             bi = i;
0141         }
0142     }
0143     if (bi / 33 == 1)
0144         fs_mode = S3C2410_IISMOD_256FS;
0145     else
0146         fs_mode = S3C2410_IISMOD_384FS;
0147     if (bi % 33 == 0) {
0148         clk_source = S3C24XX_CLKSRC_MPLL;
0149         div = 1;
0150     } else {
0151         clk_source = S3C24XX_CLKSRC_PCLK;
0152         div = bi % 33;
0153     }
0154 
0155     dev_dbg(rtd->dev, "%s desired rate %lu, %d\n", __func__, rate, bi);
0156 
0157     clk = (fs_mode == S3C2410_IISMOD_384FS ? 384 : 256) * rate;
0158 
0159     dev_dbg(rtd->dev, "%s will use: %s %s %d sysclk %d err %ld\n", __func__,
0160         fs_mode == S3C2410_IISMOD_384FS ? "384FS" : "256FS",
0161         clk_source == S3C24XX_CLKSRC_MPLL ? "MPLLin" : "PCLK",
0162         div, clk, err);
0163 
0164     if ((err * 100 / rate) > 5) {
0165         dev_err(rtd->dev, "effective frequency too different "
0166                   "from desired (%ld%%)\n", err * 100 / rate);
0167         return -EINVAL;
0168     }
0169 
0170     ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source , clk,
0171             SND_SOC_CLOCK_IN);
0172     if (ret < 0)
0173         return ret;
0174 
0175     ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, fs_mode);
0176     if (ret < 0)
0177         return ret;
0178 
0179     ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK,
0180             S3C2410_IISMOD_32FS);
0181     if (ret < 0)
0182         return ret;
0183 
0184     ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
0185             S3C24XX_PRESCALE(div, div));
0186     if (ret < 0)
0187         return ret;
0188 
0189     /* set the codec system clock for DAC and ADC */
0190     ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk,
0191             SND_SOC_CLOCK_OUT);
0192     if (ret < 0)
0193         return ret;
0194 
0195     return 0;
0196 }
0197 
0198 static const struct snd_soc_ops s3c24xx_uda134x_ops = {
0199     .startup = s3c24xx_uda134x_startup,
0200     .shutdown = s3c24xx_uda134x_shutdown,
0201     .hw_params = s3c24xx_uda134x_hw_params,
0202 };
0203 
0204 SND_SOC_DAILINK_DEFS(uda134x,
0205     DAILINK_COMP_ARRAY(COMP_CPU("s3c24xx-iis")),
0206     DAILINK_COMP_ARRAY(COMP_CODEC("uda134x-codec", "uda134x-hifi")),
0207     DAILINK_COMP_ARRAY(COMP_PLATFORM("s3c24xx-iis")));
0208 
0209 static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
0210     .name = "UDA134X",
0211     .stream_name = "UDA134X",
0212     .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
0213            SND_SOC_DAIFMT_CBS_CFS,
0214     .ops = &s3c24xx_uda134x_ops,
0215     SND_SOC_DAILINK_REG(uda134x),
0216 };
0217 
0218 static struct snd_soc_card snd_soc_s3c24xx_uda134x = {
0219     .name = "S3C24XX_UDA134X",
0220     .owner = THIS_MODULE,
0221     .dai_link = &s3c24xx_uda134x_dai_link,
0222     .num_links = 1,
0223 };
0224 
0225 static int s3c24xx_uda134x_probe(struct platform_device *pdev)
0226 {
0227     struct snd_soc_card *card = &snd_soc_s3c24xx_uda134x;
0228     struct s3c24xx_uda134x *priv;
0229     int ret;
0230 
0231     priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
0232     if (!priv)
0233         return -ENOMEM;
0234 
0235     mutex_init(&priv->clk_lock);
0236 
0237     card->dev = &pdev->dev;
0238     snd_soc_card_set_drvdata(card, priv);
0239 
0240     ret = devm_snd_soc_register_card(&pdev->dev, card);
0241     if (ret)
0242         dev_err(&pdev->dev, "failed to register card: %d\n", ret);
0243 
0244     return ret;
0245 }
0246 
0247 static struct platform_driver s3c24xx_uda134x_driver = {
0248     .probe  = s3c24xx_uda134x_probe,
0249     .driver = {
0250         .name = "s3c24xx_uda134x",
0251     },
0252 };
0253 module_platform_driver(s3c24xx_uda134x_driver);
0254 
0255 MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
0256 MODULE_DESCRIPTION("S3C24XX_UDA134X ALSA SoC audio driver");
0257 MODULE_LICENSE("GPL");