linuxUDA134X ASoc板驱动

来源:互联网 发布:安卓数据恢复破解版apk 编辑:程序博客网 时间:2024/05/01 22:25
 

static int __init s3c24xx_uda134x_init(void)
{
 return platform_driver_register(&s3c24xx_uda134x_driver);
}

static struct platform_driver s3c24xx_uda134x_driver = {
 .probe  = s3c24xx_uda134x_probe,
 .remove = s3c24xx_uda134x_remove,
 .driver = {
  .name = "s3c24xx_uda134x",
  .owner = THIS_MODULE,
 },
};

这里就是模块初始化函数。我们都知道当注册成功的时候也就是.name和平台设备的.name匹配成功的时候将调用.probe,这里就是s3c24xx_uda134x_probe。那么平台的设备是什么时候加入的呢。看linux-2.6.32.2\arch\arm\mach-s3c2440\mach-mini2440.中的

mini2440_machine_init()

{...

  platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));

  .....

}

static struct platform_device *mini2440_devices[] __initdata = {

...
 &s3c24xx_uda134x,

...
 };

static struct s3c24xx_uda134x_platform_data s3c24xx_uda134x_data = {
 .l3_clk = S3C2410_GPB(4),
 .l3_data = S3C2410_GPB(3),
 .l3_mode = S3C2410_GPB(2),
 .model = UDA134X_UDA1341,
};

static struct platform_device s3c24xx_uda134x = {
 .name = "s3c24xx_uda134x",
 .dev = {
  .platform_data    = &s3c24xx_uda134x_data,
 }
};

所以s3c24xx_uda134x_probe会得到运行。讲这个函数之前先看看一些结构体,变量

static struct s3c24xx_uda134x_platform_data *s3c24xx_uda134x_l3_pins用来指向&s3c24xx_uda134x_data

tatic struct uda134x_platform_data s3c24xx_uda134x = {
 .l3 = {
  .setdat = setdat,
  .setclk = setclk,
  .setmode = setmode,
  .data_hold = 1,
  .data_setup = 1,
  .clock_high = 1,
  .mode_hold = 1,
  .mode = 1,
  .mode_setup = 1,
 },
};与L3MODE,L3CLOCK,L3DATA有关,也就是编码相关的数据。它会赋值给static struct snd_soc_device s3c24xx_uda134x_snd_devdata

snd_soc_device s3c24xx_uda134x_snd_devdata非常重要。是对ASoc设备的整体封装。包括封装ASoc Codec设备用的snd_soc_codec_device(.codec_dev 成员),板和平台设备用的snd_soc_card组件(.card成员)。

--------------------------------------------------------------------------------------

static struct snd_soc_device s3c24xx_uda134x_snd_devdata = {
 .card = &snd_soc_s3c24xx_uda134x,
 .codec_dev = &soc_codec_dev_uda134x,
 .codec_data = &s3c24xx_uda134x,
};

---------------------------------------------------------------------------------------

封装的ASoc Codec设备用的snd_soc_codec_device(.codec_dev 成员)定义如下:

struct snd_soc_codec_device soc_codec_dev_uda134x = {
 .probe =        uda134x_soc_probe,
 .remove =       uda134x_soc_remove,
 .suspend =      uda134x_soc_suspend,
 .resume =       uda134x_soc_resume,
};
EXPORT_SYMBOL_GPL(soc_codec_dev_uda134x);

在snd_soc_card组件(.card成员)中封装了板和平台的定义如下:

static struct snd_soc_card snd_soc_s3c24xx_uda134x = {
 .name = "S3C24XX_UDA134X",
 .platform = &s3c24xx_soc_platform,平台,在s3c24xx-pcm.c中注册了平台
 .dai_link = &s3c24xx_uda134x_dai_link,板
 .num_links = 1,
};

板&s3c24xx_uda134x_dai_link起绑定codec驱动和平台I2C驱动的作用定义:

static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
 .name = "UDA134X",
 .stream_name = "UDA134X",
 .codec_dai = &uda134x_dai,//codec驱动
 .cpu_dai = &s3c24xx_i2s_dai,//平台I2S驱动
 .ops = &s3c24xx_uda134x_ops,//操作板驱动的函数
};

static struct snd_soc_ops s3c24xx_uda134x_ops = {
 .startup = s3c24xx_uda134x_startup,
 .shutdown = s3c24xx_uda134x_shutdown,
 .hw_params = s3c24xx_uda134x_hw_params,
};

 

最后看看s3c24xx_uda134x_probe()做了什么:

获得设备资源赋值给s3c24xx_uda134x_l3_pins。设置s3c24xx_uda134x的power,model.

通过函数s3c24xx_uda134x_setup_pin()获得音频口的clk,data,model引脚使用,设置输出为0;

申请s3c24xx_uda134x_snd_device内存并通过platform_set_drvdata()设置ASoc设备的整体封装s3c24xx_uda134x_snd_devdata 为其私有数据。然后设置s3c24xx_uda134x_snd_devdata的dev指向s3c24xx_uda134x_snd_device的dev.最后添加s3c24xx_uda134x_snd_device平台设备。

添加这的这个平台设备.name为“soc-audio”,在soc-core.c有个平台驱动的.name也为“soc-audio”。

所以会引起匹配调用在soc-core.c文件中的.probe,所以s3c24xx_uda134x_snd_device会传递给soc-core.c文件中的.probe函数作为参数。也就完成了ASoc设备的整体封装s3c24xx_uda134x_snd_devdata的传递。

 

 

下面是板驱动的源代码:

#include <linux/module.h>
#include <linux/clk.h>
#include <linux/mutex.h>
#include <linux/gpio.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/s3c24xx_uda134x.h>
#include <sound/uda134x.h>

#include <plat/regs-iis.h>

#include "s3c24xx-pcm.h"
#include "s3c24xx-i2s.h"
#include "../codecs/uda134x.h"



static struct clk *xtal;
static struct clk *pclk;

static int clk_users;
static DEFINE_MUTEX(clk_lock);

static unsigned int rates[33 * 2];
#ifdef ENFORCE_RATES
static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
 .count = ARRAY_SIZE(rates),
 .list = rates,
 .mask = 0,
};
#endif

static struct platform_device *s3c24xx_uda134x_snd_device;

static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream)
{
 int ret = 0;
#ifdef ENFORCE_RATES
 struct snd_pcm_runtime *runtime = substream->runtime;
#endif

 mutex_lock(&clk_lock);
 pr_debug("%s %d\n", __func__, clk_users);
 if (clk_users == 0) {
  xtal = clk_get(&s3c24xx_uda134x_snd_device->dev, "xtal");
  if (!xtal) {
   printk(KERN_ERR "%s cannot get xtal\n", __func__);
   ret = -EBUSY;
  } else {
   pclk = clk_get(&s3c24xx_uda134x_snd_device->dev,
           "pclk");
   if (!pclk) {
    printk(KERN_ERR "%s cannot get pclk\n",
           __func__);
    clk_put(xtal);
    ret = -EBUSY;
   }
  }
  if (!ret) {
   int i, j;

   for (i = 0; i < 2; i++) {
    int fs = i ? 256 : 384;

    rates[i*33] = clk_get_rate(xtal) / fs;
    for (j = 1; j < 33; j++)
     rates[i*33 + j] = clk_get_rate(pclk) /
      (j * fs);
   }
  }
 }
 clk_users += 1;
 mutex_unlock(&clk_lock);
 if (!ret) {
#ifdef ENFORCE_RATES
  ret = snd_pcm_hw_constraint_list(runtime, 0,
       SNDRV_PCM_HW_PARAM_RATE,
       &hw_constraints_rates);
  if (ret < 0)
   printk(KERN_ERR "%s cannot set constraints\n",
          __func__);
#endif
 }
 return ret;
}

static void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream)
{
 mutex_lock(&clk_lock);
 pr_debug("%s %d\n", __func__, clk_users);
 clk_users -= 1;
 if (clk_users == 0) {
  clk_put(xtal);
  xtal = NULL;
  clk_put(pclk);
  pclk = NULL;
 }
 mutex_unlock(&clk_lock);
}

static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream,
     struct snd_pcm_hw_params *params)
{
 struct snd_soc_pcm_runtime *rtd = substream->private_data;
 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 unsigned int clk = 0;
 int ret = 0;
 int clk_source, fs_mode;
 unsigned long rate = params_rate(params);
 long err, cerr;
 unsigned int div;
 int i, bi;

 err = 999999;
 bi = 0;
 for (i = 0; i < 2*33; i++) {
  cerr = rates[i] - rate;
  if (cerr < 0)
   cerr = -cerr;
  if (cerr < err) {
   err = cerr;
   bi = i;
  }
 }
 if (bi / 33 == 1)
  fs_mode = S3C2410_IISMOD_256FS;
 else
  fs_mode = S3C2410_IISMOD_384FS;
 if (bi % 33 == 0) {
  clk_source = S3C24XX_CLKSRC_MPLL;
  div = 1;
 } else {
  clk_source = S3C24XX_CLKSRC_PCLK;
  div = bi % 33;
 }
 pr_debug("%s desired rate %lu, %d\n", __func__, rate, bi);

 clk = (fs_mode == S3C2410_IISMOD_384FS ? 384 : 256) * rate;
 pr_debug("%s will use: %s %s %d sysclk %d err %ld\n", __func__,
   fs_mode == S3C2410_IISMOD_384FS ? "384FS" : "256FS",
   clk_source == S3C24XX_CLKSRC_MPLL ? "MPLLin" : "PCLK",
   div, clk, err);

 if ((err * 100 / rate) > 5) {
  printk(KERN_ERR "S3C24XX_UDA134X: effective frequency "
         "too different from desired (%ld%%)\n",
         err * 100 / rate);
  return -EINVAL;
 }

 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
   SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
 if (ret < 0)
  return ret;

 ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
   SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
 if (ret < 0)
  return ret;

 ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source , clk,
   SND_SOC_CLOCK_IN);
 if (ret < 0)
  return ret;

 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, fs_mode);
 if (ret < 0)
  return ret;

 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK,
   S3C2410_IISMOD_32FS);
 if (ret < 0)
  return ret;

 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
   S3C24XX_PRESCALE(div, div));
 if (ret < 0)
  return ret;

 
 ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk,
   SND_SOC_CLOCK_OUT);
 if (ret < 0)
  return ret;

 return 0;
}

static struct snd_soc_ops s3c24xx_uda134x_ops = {
 .startup = s3c24xx_uda134x_startup,
 .shutdown = s3c24xx_uda134x_shutdown,
 .hw_params = s3c24xx_uda134x_hw_params,
};

static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
 .name = "UDA134X",
 .stream_name = "UDA134X",
 .codec_dai = &uda134x_dai,
 .cpu_dai = &s3c24xx_i2s_dai,
 .ops = &s3c24xx_uda134x_ops,
};

static struct snd_soc_card snd_soc_s3c24xx_uda134x = {
 .name = "S3C24XX_UDA134X",
 .platform = &s3c24xx_soc_platform,
 .dai_link = &s3c24xx_uda134x_dai_link,
 .num_links = 1,
};

static struct s3c24xx_uda134x_platform_data *s3c24xx_uda134x_l3_pins;

static void setdat(int v)
{
 gpio_set_value(s3c24xx_uda134x_l3_pins->l3_data, v > 0);
}

static void setclk(int v)
{
 gpio_set_value(s3c24xx_uda134x_l3_pins->l3_clk, v > 0);
}

static void setmode(int v)
{
 gpio_set_value(s3c24xx_uda134x_l3_pins->l3_mode, v > 0);
}

static struct uda134x_platform_data s3c24xx_uda134x = {
 .l3 = {
  .setdat = setdat,
  .setclk = setclk,
  .setmode = setmode,
  .data_hold = 1,
  .data_setup = 1,
  .clock_high = 1,
  .mode_hold = 1,
  .mode = 1,
  .mode_setup = 1,
 },
};

static struct snd_soc_device s3c24xx_uda134x_snd_devdata = {
 .card = &snd_soc_s3c24xx_uda134x,
 .codec_dev = &soc_codec_dev_uda134x,
 .codec_data = &s3c24xx_uda134x,
};

static int s3c24xx_uda134x_setup_pin(int pin, char *fun)
{
 if (gpio_request(pin, "s3c24xx_uda134x") < 0) {
  printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: "
         "l3 %s pin already in use", fun);
  return -EBUSY;
 }
 gpio_direction_output(pin, 0);
 return 0;
}

static int s3c24xx_uda134x_probe(struct platform_device *pdev)
{
 int ret;

 printk(KERN_INFO "S3C24XX_UDA134X SoC Audio driver\n");

 s3c24xx_uda134x_l3_pins = pdev->dev.platform_data;
 if (s3c24xx_uda134x_l3_pins == NULL) {
  printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: "
         "unable to find platform data\n");
  return -ENODEV;
 }
 s3c24xx_uda134x.power = s3c24xx_uda134x_l3_pins->power;
 s3c24xx_uda134x.model = s3c24xx_uda134x_l3_pins->model;

 if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_data,
          "data") < 0)
  return -EBUSY;
 if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_clk,
          "clk") < 0) {
  gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
  return -EBUSY;
 }
 if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_mode,
          "mode") < 0) {
  gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
  gpio_free(s3c24xx_uda134x_l3_pins->l3_clk);
  return -EBUSY;
 }

 s3c24xx_uda134x_snd_device = platform_device_alloc("soc-audio", -1);
 if (!s3c24xx_uda134x_snd_device) {
  printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: "
         "Unable to register\n");
  return -ENOMEM;
 }

 platform_set_drvdata(s3c24xx_uda134x_snd_device,
        &s3c24xx_uda134x_snd_devdata);
 s3c24xx_uda134x_snd_devdata.dev = &s3c24xx_uda134x_snd_device->dev;
 ret = platform_device_add(s3c24xx_uda134x_snd_device);
 if (ret) {
  printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: Unable to add\n");
  platform_device_put(s3c24xx_uda134x_snd_device);
 }

 return ret;
}

static int s3c24xx_uda134x_remove(struct platform_device *pdev)
{
 platform_device_unregister(s3c24xx_uda134x_snd_device);
 gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
 gpio_free(s3c24xx_uda134x_l3_pins->l3_clk);
 gpio_free(s3c24xx_uda134x_l3_pins->l3_mode);
 return 0;
}

static struct platform_driver s3c24xx_uda134x_driver = {
 .probe  = s3c24xx_uda134x_probe,
 .remove = s3c24xx_uda134x_remove,
 .driver = {
  .name = "s3c24xx_uda134x",
  .owner = THIS_MODULE,
 },
};

static int __init s3c24xx_uda134x_init(void)
{
 return platform_driver_register(&s3c24xx_uda134x_driver);
}

static void __exit s3c24xx_uda134x_exit(void)
{
 platform_driver_unregister(&s3c24xx_uda134x_driver);
}


module_init(s3c24xx_uda134x_init);
module_exit(s3c24xx_uda134x_exit);

MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
MODULE_DESCRIPTION("S3C24XX_UDA134X ALSA SoC audio driver");
MODULE_LICENSE("GPL");

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 div放图片多出的空白怎么办 我14岁射精让我记忆力差了怎么办 qq闪退聊天记录全没了怎么办 木瓜奇迹忘记升级过头转职了怎么办 孩子进入青春期什么坏事都干怎么办 母狗狗第一次来月经应该怎么办图 社保断了想补缴怎么办?这些要知道 换工作社保断了一个月怎么办 北京社保中间断了几个月怎么办 农保和社保都交了医保怎么办 如果交了社保结婚生孩子断了怎么办 南京社保中间断了几个月怎么办 mu大师等级技能点加点太慢怎么办 永恒纪元戒不是本职业套装石怎么办 全民奇迹忘记在哪个区了怎么办 全民奇迹安卓的忘记那个区了怎么办 大天使之剑h5所在服人少怎么办 买的裙子因为好看没有勇气穿怎么办 魅蓝s6锁屏密码忘了怎么办 u盘被占用不能安全弹出怎么办 洛克王国得到了魔攻巨蟹座怎么办 在育碧下载游戏下一半不下了怎么办 轩辕传奇单机版忘记哪个区了怎么办 登腾讯游戏动态密码啥意思怎么办 说了不该说的话别人不原谅怎么办 轩辕传奇手游金币用错了怎么办 神秘时代4法杖按键冲突怎么办 孕2个月发烧38度怎么办 不知道怀孕喝了止咳糖浆怎么办? 小孩刮头发的备皮刀割住手怎么办? 天梭手表里面的刻度掉了怎么办 国战天下手游帐号丢失怎么办 肺力咳合剂一次喝了50多了怎么办 头孢和藿香正气水一起吃了怎么办 小儿胃蛋自酶合剂吃多了怎么办 刚出生的婴儿很容易被惊醒怎么办 1个多月的宝宝小腿不直怎么办 20个月宝宝腿不直小腿外八怎么办 小孩手青枝骨骨折拆石膏还弯怎么办 宝宝喝柴胡注射剂有不良反应怎么办 九个月宝宝便秘拉不出来怎么办