root/sound/soc/samsung/s3c24xx_uda134x.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. s3c24xx_uda134x_startup
  2. s3c24xx_uda134x_shutdown
  3. s3c24xx_uda134x_hw_params
  4. s3c24xx_uda134x_probe

   1 // SPDX-License-Identifier: GPL-2.0
   2 //
   3 // Modifications by Christian Pellegrin <chripell@evolware.org>
   4 //
   5 // s3c24xx_uda134x.c - S3C24XX_UDA134X ALSA SoC Audio board driver
   6 //
   7 // Copyright 2007 Dension Audio Systems Ltd.
   8 // Author: Zoltan Devai
   9 
  10 #include <linux/clk.h>
  11 #include <linux/gpio.h>
  12 #include <linux/module.h>
  13 
  14 #include <sound/soc.h>
  15 #include <sound/s3c24xx_uda134x.h>
  16 
  17 #include "regs-iis.h"
  18 #include "s3c24xx-i2s.h"
  19 
  20 struct s3c24xx_uda134x {
  21         struct clk *xtal;
  22         struct clk *pclk;
  23         struct mutex clk_lock;
  24         int clk_users;
  25 };
  26 
  27 /* #define ENFORCE_RATES 1 */
  28 /*
  29   Unfortunately the S3C24XX in master mode has a limited capacity of
  30   generating the clock for the codec. If you define this only rates
  31   that are really available will be enforced. But be careful, most
  32   user level application just want the usual sampling frequencies (8,
  33   11.025, 22.050, 44.1 kHz) and anyway resampling is a costly
  34   operation for embedded systems. So if you aren't very lucky or your
  35   hardware engineer wasn't very forward-looking it's better to leave
  36   this undefined. If you do so an approximate value for the requested
  37   sampling rate in the range -/+ 5% will be chosen. If this in not
  38   possible an error will be returned.
  39 */
  40 
  41 static unsigned int rates[33 * 2];
  42 #ifdef ENFORCE_RATES
  43 static const struct snd_pcm_hw_constraint_list hw_constraints_rates = {
  44         .count  = ARRAY_SIZE(rates),
  45         .list   = rates,
  46         .mask   = 0,
  47 };
  48 #endif
  49 
  50 static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream)
  51 {
  52         struct snd_soc_pcm_runtime *rtd = substream->private_data;
  53         struct s3c24xx_uda134x *priv = snd_soc_card_get_drvdata(rtd->card);
  54         struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
  55         int ret = 0;
  56 
  57         mutex_lock(&priv->clk_lock);
  58 
  59         if (priv->clk_users == 0) {
  60                 priv->xtal = clk_get(rtd->dev, "xtal");
  61                 if (IS_ERR(priv->xtal)) {
  62                         dev_err(rtd->dev, "%s cannot get xtal\n", __func__);
  63                         ret = PTR_ERR(priv->xtal);
  64                 } else {
  65                         priv->pclk = clk_get(cpu_dai->dev, "iis");
  66                         if (IS_ERR(priv->pclk)) {
  67                                 dev_err(rtd->dev, "%s cannot get pclk\n",
  68                                         __func__);
  69                                 clk_put(priv->xtal);
  70                                 ret = PTR_ERR(priv->pclk);
  71                         }
  72                 }
  73                 if (!ret) {
  74                         int i, j;
  75 
  76                         for (i = 0; i < 2; i++) {
  77                                 int fs = i ? 256 : 384;
  78 
  79                                 rates[i*33] = clk_get_rate(priv->xtal) / fs;
  80                                 for (j = 1; j < 33; j++)
  81                                         rates[i*33 + j] = clk_get_rate(priv->pclk) /
  82                                                 (j * fs);
  83                         }
  84                 }
  85         }
  86         priv->clk_users += 1;
  87         mutex_unlock(&priv->clk_lock);
  88 
  89         if (!ret) {
  90 #ifdef ENFORCE_RATES
  91                 ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
  92                                                  SNDRV_PCM_HW_PARAM_RATE,
  93                                                  &hw_constraints_rates);
  94                 if (ret < 0)
  95                         dev_err(rtd->dev, "%s cannot set constraints\n",
  96                                 __func__);
  97 #endif
  98         }
  99         return ret;
 100 }
 101 
 102 static void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream)
 103 {
 104         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 105         struct s3c24xx_uda134x *priv = snd_soc_card_get_drvdata(rtd->card);
 106 
 107         mutex_lock(&priv->clk_lock);
 108         priv->clk_users -= 1;
 109         if (priv->clk_users == 0) {
 110                 clk_put(priv->xtal);
 111                 priv->xtal = NULL;
 112                 clk_put(priv->pclk);
 113                 priv->pclk = NULL;
 114         }
 115         mutex_unlock(&priv->clk_lock);
 116 }
 117 
 118 static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream,
 119                                         struct snd_pcm_hw_params *params)
 120 {
 121         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 122         struct snd_soc_dai *codec_dai = rtd->codec_dai;
 123         struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 124         unsigned int clk = 0;
 125         int ret = 0;
 126         int clk_source, fs_mode;
 127         unsigned long rate = params_rate(params);
 128         long err, cerr;
 129         unsigned int div;
 130         int i, bi;
 131 
 132         err = 999999;
 133         bi = 0;
 134         for (i = 0; i < 2*33; i++) {
 135                 cerr = rates[i] - rate;
 136                 if (cerr < 0)
 137                         cerr = -cerr;
 138                 if (cerr < err) {
 139                         err = cerr;
 140                         bi = i;
 141                 }
 142         }
 143         if (bi / 33 == 1)
 144                 fs_mode = S3C2410_IISMOD_256FS;
 145         else
 146                 fs_mode = S3C2410_IISMOD_384FS;
 147         if (bi % 33 == 0) {
 148                 clk_source = S3C24XX_CLKSRC_MPLL;
 149                 div = 1;
 150         } else {
 151                 clk_source = S3C24XX_CLKSRC_PCLK;
 152                 div = bi % 33;
 153         }
 154 
 155         dev_dbg(rtd->dev, "%s desired rate %lu, %d\n", __func__, rate, bi);
 156 
 157         clk = (fs_mode == S3C2410_IISMOD_384FS ? 384 : 256) * rate;
 158 
 159         dev_dbg(rtd->dev, "%s will use: %s %s %d sysclk %d err %ld\n", __func__,
 160                 fs_mode == S3C2410_IISMOD_384FS ? "384FS" : "256FS",
 161                 clk_source == S3C24XX_CLKSRC_MPLL ? "MPLLin" : "PCLK",
 162                 div, clk, err);
 163 
 164         if ((err * 100 / rate) > 5) {
 165                 dev_err(rtd->dev, "effective frequency too different "
 166                                   "from desired (%ld%%)\n", err * 100 / rate);
 167                 return -EINVAL;
 168         }
 169 
 170         ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source , clk,
 171                         SND_SOC_CLOCK_IN);
 172         if (ret < 0)
 173                 return ret;
 174 
 175         ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, fs_mode);
 176         if (ret < 0)
 177                 return ret;
 178 
 179         ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK,
 180                         S3C2410_IISMOD_32FS);
 181         if (ret < 0)
 182                 return ret;
 183 
 184         ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
 185                         S3C24XX_PRESCALE(div, div));
 186         if (ret < 0)
 187                 return ret;
 188 
 189         /* set the codec system clock for DAC and ADC */
 190         ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk,
 191                         SND_SOC_CLOCK_OUT);
 192         if (ret < 0)
 193                 return ret;
 194 
 195         return 0;
 196 }
 197 
 198 static const struct snd_soc_ops s3c24xx_uda134x_ops = {
 199         .startup = s3c24xx_uda134x_startup,
 200         .shutdown = s3c24xx_uda134x_shutdown,
 201         .hw_params = s3c24xx_uda134x_hw_params,
 202 };
 203 
 204 SND_SOC_DAILINK_DEFS(uda134x,
 205         DAILINK_COMP_ARRAY(COMP_CPU("s3c24xx-iis")),
 206         DAILINK_COMP_ARRAY(COMP_CODEC("uda134x-codec", "uda134x-hifi")),
 207         DAILINK_COMP_ARRAY(COMP_PLATFORM("s3c24xx-iis")));
 208 
 209 static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
 210         .name = "UDA134X",
 211         .stream_name = "UDA134X",
 212         .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 213                    SND_SOC_DAIFMT_CBS_CFS,
 214         .ops = &s3c24xx_uda134x_ops,
 215         SND_SOC_DAILINK_REG(uda134x),
 216 };
 217 
 218 static struct snd_soc_card snd_soc_s3c24xx_uda134x = {
 219         .name = "S3C24XX_UDA134X",
 220         .owner = THIS_MODULE,
 221         .dai_link = &s3c24xx_uda134x_dai_link,
 222         .num_links = 1,
 223 };
 224 
 225 static int s3c24xx_uda134x_probe(struct platform_device *pdev)
 226 {
 227         struct snd_soc_card *card = &snd_soc_s3c24xx_uda134x;
 228         struct s3c24xx_uda134x *priv;
 229         int ret;
 230 
 231         priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 232         if (!priv)
 233                 return -ENOMEM;
 234 
 235         mutex_init(&priv->clk_lock);
 236 
 237         card->dev = &pdev->dev;
 238         snd_soc_card_set_drvdata(card, priv);
 239 
 240         ret = devm_snd_soc_register_card(&pdev->dev, card);
 241         if (ret)
 242                 dev_err(&pdev->dev, "failed to register card: %d\n", ret);
 243 
 244         return ret;
 245 }
 246 
 247 static struct platform_driver s3c24xx_uda134x_driver = {
 248         .probe  = s3c24xx_uda134x_probe,
 249         .driver = {
 250                 .name = "s3c24xx_uda134x",
 251         },
 252 };
 253 module_platform_driver(s3c24xx_uda134x_driver);
 254 
 255 MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
 256 MODULE_DESCRIPTION("S3C24XX_UDA134X ALSA SoC audio driver");
 257 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */