linux/sound/soc/s3c24xx/s3c24xx_uda134x.c
<<
>>
Prefs
   1/*
   2 * Modifications by Christian Pellegrin <chripell@evolware.org>
   3 *
   4 * s3c24xx_uda134x.c  --  S3C24XX_UDA134X ALSA SoC Audio board driver
   5 *
   6 * Copyright 2007 Dension Audio Systems Ltd.
   7 * Author: Zoltan Devai
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License version 2 as
  11 * published by the Free Software Foundation.
  12 */
  13
  14#include <linux/module.h>
  15#include <linux/clk.h>
  16#include <linux/mutex.h>
  17#include <linux/gpio.h>
  18#include <sound/pcm.h>
  19#include <sound/pcm_params.h>
  20#include <sound/soc.h>
  21#include <sound/soc-dapm.h>
  22#include <sound/s3c24xx_uda134x.h>
  23#include <sound/uda134x.h>
  24
  25#include <plat/regs-iis.h>
  26
  27#include "s3c24xx-pcm.h"
  28#include "s3c24xx-i2s.h"
  29#include "../codecs/uda134x.h"
  30
  31
  32/* #define ENFORCE_RATES 1 */
  33/*
  34  Unfortunately the S3C24XX in master mode has a limited capacity of
  35  generating the clock for the codec. If you define this only rates
  36  that are really available will be enforced. But be careful, most
  37  user level application just want the usual sampling frequencies (8,
  38  11.025, 22.050, 44.1 kHz) and anyway resampling is a costly
  39  operation for embedded systems. So if you aren't very lucky or your
  40  hardware engineer wasn't very forward-looking it's better to leave
  41  this undefined. If you do so an approximate value for the requested
  42  sampling rate in the range -/+ 5% will be chosen. If this in not
  43  possible an error will be returned.
  44*/
  45
  46static struct clk *xtal;
  47static struct clk *pclk;
  48/* this is need because we don't have a place where to keep the
  49 * pointers to the clocks in each substream. We get the clocks only
  50 * when we are actually using them so we don't block stuff like
  51 * frequency change or oscillator power-off */
  52static int clk_users;
  53static DEFINE_MUTEX(clk_lock);
  54
  55static unsigned int rates[33 * 2];
  56#ifdef ENFORCE_RATES
  57static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
  58        .count  = ARRAY_SIZE(rates),
  59        .list   = rates,
  60        .mask   = 0,
  61};
  62#endif
  63
  64static struct platform_device *s3c24xx_uda134x_snd_device;
  65
  66static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream)
  67{
  68        int ret = 0;
  69#ifdef ENFORCE_RATES
  70        struct snd_pcm_runtime *runtime = substream->runtime;
  71#endif
  72
  73        mutex_lock(&clk_lock);
  74        pr_debug("%s %d\n", __func__, clk_users);
  75        if (clk_users == 0) {
  76                xtal = clk_get(&s3c24xx_uda134x_snd_device->dev, "xtal");
  77                if (!xtal) {
  78                        printk(KERN_ERR "%s cannot get xtal\n", __func__);
  79                        ret = -EBUSY;
  80                } else {
  81                        pclk = clk_get(&s3c24xx_uda134x_snd_device->dev,
  82                                       "pclk");
  83                        if (!pclk) {
  84                                printk(KERN_ERR "%s cannot get pclk\n",
  85                                       __func__);
  86                                clk_put(xtal);
  87                                ret = -EBUSY;
  88                        }
  89                }
  90                if (!ret) {
  91                        int i, j;
  92
  93                        for (i = 0; i < 2; i++) {
  94                                int fs = i ? 256 : 384;
  95
  96                                rates[i*33] = clk_get_rate(xtal) / fs;
  97                                for (j = 1; j < 33; j++)
  98                                        rates[i*33 + j] = clk_get_rate(pclk) /
  99                                                (j * fs);
 100                        }
 101                }
 102        }
 103        clk_users += 1;
 104        mutex_unlock(&clk_lock);
 105        if (!ret) {
 106#ifdef ENFORCE_RATES
 107                ret = snd_pcm_hw_constraint_list(runtime, 0,
 108                                                 SNDRV_PCM_HW_PARAM_RATE,
 109                                                 &hw_constraints_rates);
 110                if (ret < 0)
 111                        printk(KERN_ERR "%s cannot set constraints\n",
 112                               __func__);
 113#endif
 114        }
 115        return ret;
 116}
 117
 118static void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream)
 119{
 120        mutex_lock(&clk_lock);
 121        pr_debug("%s %d\n", __func__, clk_users);
 122        clk_users -= 1;
 123        if (clk_users == 0) {
 124                clk_put(xtal);
 125                xtal = NULL;
 126                clk_put(pclk);
 127                pclk = NULL;
 128        }
 129        mutex_unlock(&clk_lock);
 130}
 131
 132static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream,
 133                                        struct snd_pcm_hw_params *params)
 134{
 135        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 136        struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
 137        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 138        unsigned int clk = 0;
 139        int ret = 0;
 140        int clk_source, fs_mode;
 141        unsigned long rate = params_rate(params);
 142        long err, cerr;
 143        unsigned int div;
 144        int i, bi;
 145
 146        err = 999999;
 147        bi = 0;
 148        for (i = 0; i < 2*33; i++) {
 149                cerr = rates[i] - rate;
 150                if (cerr < 0)
 151                        cerr = -cerr;
 152                if (cerr < err) {
 153                        err = cerr;
 154                        bi = i;
 155                }
 156        }
 157        if (bi / 33 == 1)
 158                fs_mode = S3C2410_IISMOD_256FS;
 159        else
 160                fs_mode = S3C2410_IISMOD_384FS;
 161        if (bi % 33 == 0) {
 162                clk_source = S3C24XX_CLKSRC_MPLL;
 163                div = 1;
 164        } else {
 165                clk_source = S3C24XX_CLKSRC_PCLK;
 166                div = bi % 33;
 167        }
 168        pr_debug("%s desired rate %lu, %d\n", __func__, rate, bi);
 169
 170        clk = (fs_mode == S3C2410_IISMOD_384FS ? 384 : 256) * rate;
 171        pr_debug("%s will use: %s %s %d sysclk %d err %ld\n", __func__,
 172                 fs_mode == S3C2410_IISMOD_384FS ? "384FS" : "256FS",
 173                 clk_source == S3C24XX_CLKSRC_MPLL ? "MPLLin" : "PCLK",
 174                 div, clk, err);
 175
 176        if ((err * 100 / rate) > 5) {
 177                printk(KERN_ERR "S3C24XX_UDA134X: effective frequency "
 178                       "too different from desired (%ld%%)\n",
 179                       err * 100 / rate);
 180                return -EINVAL;
 181        }
 182
 183        ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
 184                        SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
 185        if (ret < 0)
 186                return ret;
 187
 188        ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
 189                        SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
 190        if (ret < 0)
 191                return ret;
 192
 193        ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source , clk,
 194                        SND_SOC_CLOCK_IN);
 195        if (ret < 0)
 196                return ret;
 197
 198        ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, fs_mode);
 199        if (ret < 0)
 200                return ret;
 201
 202        ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK,
 203                        S3C2410_IISMOD_32FS);
 204        if (ret < 0)
 205                return ret;
 206
 207        ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
 208                        S3C24XX_PRESCALE(div, div));
 209        if (ret < 0)
 210                return ret;
 211
 212        /* set the codec system clock for DAC and ADC */
 213        ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk,
 214                        SND_SOC_CLOCK_OUT);
 215        if (ret < 0)
 216                return ret;
 217
 218        return 0;
 219}
 220
 221static struct snd_soc_ops s3c24xx_uda134x_ops = {
 222        .startup = s3c24xx_uda134x_startup,
 223        .shutdown = s3c24xx_uda134x_shutdown,
 224        .hw_params = s3c24xx_uda134x_hw_params,
 225};
 226
 227static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
 228        .name = "UDA134X",
 229        .stream_name = "UDA134X",
 230        .codec_dai = &uda134x_dai,
 231        .cpu_dai = &s3c24xx_i2s_dai,
 232        .ops = &s3c24xx_uda134x_ops,
 233};
 234
 235static struct snd_soc_card snd_soc_s3c24xx_uda134x = {
 236        .name = "S3C24XX_UDA134X",
 237        .platform = &s3c24xx_soc_platform,
 238        .dai_link = &s3c24xx_uda134x_dai_link,
 239        .num_links = 1,
 240};
 241
 242static struct s3c24xx_uda134x_platform_data *s3c24xx_uda134x_l3_pins;
 243
 244static void setdat(int v)
 245{
 246        gpio_set_value(s3c24xx_uda134x_l3_pins->l3_data, v > 0);
 247}
 248
 249static void setclk(int v)
 250{
 251        gpio_set_value(s3c24xx_uda134x_l3_pins->l3_clk, v > 0);
 252}
 253
 254static void setmode(int v)
 255{
 256        gpio_set_value(s3c24xx_uda134x_l3_pins->l3_mode, v > 0);
 257}
 258
 259static struct uda134x_platform_data s3c24xx_uda134x = {
 260        .l3 = {
 261                .setdat = setdat,
 262                .setclk = setclk,
 263                .setmode = setmode,
 264                .data_hold = 1,
 265                .data_setup = 1,
 266                .clock_high = 1,
 267                .mode_hold = 1,
 268                .mode = 1,
 269                .mode_setup = 1,
 270        },
 271};
 272
 273static struct snd_soc_device s3c24xx_uda134x_snd_devdata = {
 274        .card = &snd_soc_s3c24xx_uda134x,
 275        .codec_dev = &soc_codec_dev_uda134x,
 276        .codec_data = &s3c24xx_uda134x,
 277};
 278
 279static int s3c24xx_uda134x_setup_pin(int pin, char *fun)
 280{
 281        if (gpio_request(pin, "s3c24xx_uda134x") < 0) {
 282                printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: "
 283                       "l3 %s pin already in use", fun);
 284                return -EBUSY;
 285        }
 286        gpio_direction_output(pin, 0);
 287        return 0;
 288}
 289
 290static int s3c24xx_uda134x_probe(struct platform_device *pdev)
 291{
 292        int ret;
 293
 294        printk(KERN_INFO "S3C24XX_UDA134X SoC Audio driver\n");
 295
 296        s3c24xx_uda134x_l3_pins = pdev->dev.platform_data;
 297        if (s3c24xx_uda134x_l3_pins == NULL) {
 298                printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: "
 299                       "unable to find platform data\n");
 300                return -ENODEV;
 301        }
 302        s3c24xx_uda134x.power = s3c24xx_uda134x_l3_pins->power;
 303        s3c24xx_uda134x.model = s3c24xx_uda134x_l3_pins->model;
 304
 305        if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_data,
 306                                      "data") < 0)
 307                return -EBUSY;
 308        if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_clk,
 309                                      "clk") < 0) {
 310                gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
 311                return -EBUSY;
 312        }
 313        if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_mode,
 314                                      "mode") < 0) {
 315                gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
 316                gpio_free(s3c24xx_uda134x_l3_pins->l3_clk);
 317                return -EBUSY;
 318        }
 319
 320        s3c24xx_uda134x_snd_device = platform_device_alloc("soc-audio", -1);
 321        if (!s3c24xx_uda134x_snd_device) {
 322                printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: "
 323                       "Unable to register\n");
 324                return -ENOMEM;
 325        }
 326
 327        platform_set_drvdata(s3c24xx_uda134x_snd_device,
 328                             &s3c24xx_uda134x_snd_devdata);
 329        s3c24xx_uda134x_snd_devdata.dev = &s3c24xx_uda134x_snd_device->dev;
 330        ret = platform_device_add(s3c24xx_uda134x_snd_device);
 331        if (ret) {
 332                printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: Unable to add\n");
 333                platform_device_put(s3c24xx_uda134x_snd_device);
 334        }
 335
 336        return ret;
 337}
 338
 339static int s3c24xx_uda134x_remove(struct platform_device *pdev)
 340{
 341        platform_device_unregister(s3c24xx_uda134x_snd_device);
 342        gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
 343        gpio_free(s3c24xx_uda134x_l3_pins->l3_clk);
 344        gpio_free(s3c24xx_uda134x_l3_pins->l3_mode);
 345        return 0;
 346}
 347
 348static struct platform_driver s3c24xx_uda134x_driver = {
 349        .probe  = s3c24xx_uda134x_probe,
 350        .remove = s3c24xx_uda134x_remove,
 351        .driver = {
 352                .name = "s3c24xx_uda134x",
 353                .owner = THIS_MODULE,
 354        },
 355};
 356
 357static int __init s3c24xx_uda134x_init(void)
 358{
 359        return platform_driver_register(&s3c24xx_uda134x_driver);
 360}
 361
 362static void __exit s3c24xx_uda134x_exit(void)
 363{
 364        platform_driver_unregister(&s3c24xx_uda134x_driver);
 365}
 366
 367
 368module_init(s3c24xx_uda134x_init);
 369module_exit(s3c24xx_uda134x_exit);
 370
 371MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
 372MODULE_DESCRIPTION("S3C24XX_UDA134X ALSA SoC audio driver");
 373MODULE_LICENSE("GPL");
 374