Linux i2c->sound

平台:i.MX6ul


// i2c总线
struct bus_type i2c_bus_type = {
 .name  = "i2c",
 .match  = i2c_device_match,
 .probe  = i2c_device_probe,
 .remove  = i2c_device_remove,
 .shutdown = i2c_device_shutdown,
};

/* 当device或driver被加载时,总线会调用该match方法对device和driver进行匹配,如果有匹配device和driver将调用driver的probe函数 */
static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
 struct i2c_client *client = i2c_verify_client(dev);
 struct i2c_driver *driver;

 if (!client)
  return 0;

 /* 3中方式对device和driver进行匹配,匹配成功返回1,然后i2c_imx_probe将会被调用 */
 if (of_driver_match_device(dev, drv))// 1、从设备树节点进行匹配
  return 1;

 if (acpi_driver_match_device(dev, drv))// 2、没使用过ACPI,这个应该是X86
  return 1;

 driver = to_i2c_driver(drv);
 if (driver->id_table)// 3、id_table进行匹配
  return i2c_match_id(driver->id_table, client) != NULL;

 return 0;


i2c_adap_imx_init(void)// drivers\i2c\busses\i2c-imx.c
 platform_driver_register(&i2c_imx_driver);------------------------>


/

              设备层

/
 
static struct platform_driver i2c_imx_driver = {
 .probe = i2c_imx_probe,
 .remove = i2c_imx_remove,
 .driver = {
  .name = DRIVER_NAME,
  .owner = THIS_MODULE,
  .of_match_table = i2c_imx_dt_ids,
  .pm = IMX_I2C_PM,
 },
 .id_table = imx_i2c_devtype,
};
 
static int i2c_imx_probe(struct platform_device *pdev)
 struct imx_i2c_struct *i2c_imx;
 
 
 phy_addr = (dma_addr_t)res->start;// DMA使用
 i2c_imx = devm_kzalloc(&pdev->dev, sizeof(*i2c_imx), GFP_KERNEL);// 分配i2c_imx(同时也分配了i2c_adapter),i2c_imx结构体包含了struct i2c_adapter adapter;
 i2c_imx->adapter.owner  = THIS_MODULE;
 i2c_imx->adapter.algo  = &i2c_imx_algo;// 算法,关注(硬件传输数据)
 i2c_imx->adapter.dev.parent = &pdev->dev;
 i2c_imx->adapter.nr  = pdev->id;
 i2c_imx->adapter.dev.of_node = pdev->dev.of_node;
 i2c_imx->base   = base;
 
 ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, IRQF_NO_SUSPEND, pdev->name, i2c_imx);// 设置中断处理函数,devm_打头的不需要free
 init_waitqueue_head(&i2c_imx->queue);// 初始化等待队列
 ret = i2c_add_numbered_adapter(&i2c_imx->adapter);//
    if (adap->nr == -1) /* -1 means dynamically assign bus id */
     return i2c_add_adapter(adap);
        return i2c_register_adapter(adapter);-------------------------------------> i2c_register_adapter
    return __i2c_add_numbered_adapter(adap);
       i2c_register_adapter(adap);// 同样走上面这套-------------------------------------> i2c_register_adapter
 /* Init DMA config if supported */
 i2c_imx_dma_request(i2c_imx, phy_addr);
/
       
static int i2c_register_adapter(struct i2c_adapter *adap)// drivers\i2c\i2c-core.c
 adap->dev.bus = &i2c_bus_type;// 挂到i2c总线上,device和driver之前如何匹配查看i2c_bus_type的match方法(i2c_device_match)
 adap->dev.type = &i2c_adapter_type;// 类型为adapter,主意和下面的client区别
 res = device_register(&adap->dev);// 注册adapter的device
   of_i2c_register_devices(adap);
     for_each_available_child_of_node(adap->dev.of_node, node)
      of_i2c_register_device(adap, node);
       i2c_new_device(adap, &info);// 创建i2c_client
        struct i2c_client *client;
        client = kzalloc(sizeof *client, GFP_KERNEL);// 同时也分配了一个device结构体
        client->adapter = adap;// 设置i2c_client的adapter
        client->flags = info->flags;
        client->addr = info->addr;// 设备地址
        client->irq = info->irq;
        i2c_check_client_addr_validity(client);// 检查设备地址是否有效(分10位和7位地址2中情况)
        i2c_check_addr_busy(adap, client->addr);// 检查设备地址是否被占用
        
        client->dev.parent = &client->adapter->dev;
        client->dev.bus = &i2c_bus_type;// 也挂到i2c总线上
        client->dev.type = &i2c_client_type;// 类型为client,主意和上面adapter的区别
        client->dev.of_node = info->of_node;
        client->dev.fwnode = info->fwnode;
        device_register(&client->dev)// 注册client的device
/

              驱动层

/
static struct snd_soc_dai_driver wm8960_dai = {// sound\soc\codecs\wm8960.c
 .name = "wm8960-hifi",
 .playback = {
  .stream_name = "Playback",
  .channels_min = 1,
  .channels_max = 2,
  .rates = WM8960_RATES,
  .formats = WM8960_FORMATS,},
 .capture = {
  .stream_name = "Capture",
  .channels_min = 1,
  .channels_max = 2,
  .rates = WM8960_RATES,
  .formats = WM8960_FORMATS,},
 .ops = &wm8960_dai_ops,
 .symmetric_rates = 1,
};

codec: wm8960@1a {// 设备树里面定义的
 compatible = "wlf,wm8960";
 reg = <0x1a>;
 clocks = <&clks IMX6UL_CLK_SAI2>;
 clock-names = "mclk";
 wlf,shared-lrclk;
};

static const struct of_device_id wm8960_of_match[] = {// sound\soc\codecs\wm8960.c
       { .compatible = "wlf,wm8960", },
       { }
};
 
static struct i2c_driver wm8960_i2c_driver = {// sound\soc\codecs\wm8960.c
 .driver = {
  .name = "wm8960",
  .owner = THIS_MODULE,
  .of_match_table = wm8960_of_match,
 },
 .probe =    wm8960_i2c_probe,
 .remove =   wm8960_i2c_remove,
 .id_table = wm8960_i2c_id,
};

module_i2c_driver(wm8960_i2c_driver);// i2c_driver注册、反注册都实现了

#define module_i2c_driver(__i2c_driver) \// include\linux\i2c.h
 module_driver(__i2c_driver, i2c_add_driver, \
   i2c_del_driver)
#define i2c_add_driver(driver) i2c_register_driver(THIS_MODULE, driver)

int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
 driver->driver.owner = owner;
 driver->driver.bus = &i2c_bus_type;
 driver_register(&driver->driver);// 注册i2c的driver
  i2c_for_each_dev(driver, __process_new_driver);
  
static int __process_new_driver(struct device *dev, void *data)
{
 if (dev->type != &i2c_adapter_type)
  return 0;
 return i2c_do_add_adapter(data, to_i2c_adapter(dev));
    i2c_detect(adap, driver);// 看下有没有驱动注册的那个设备
}
/
static int wm8960_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)// sound\soc\codecs\wm8960.c
 i2c_set_clientdata(i2c, wm8960);
 ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8960, &wm8960_dai, 1);// 注册一个snd_soc_codec



分析 x Symbol: SND_SOC_ROCKCHIP_I2S [=n] x x Type : tristate x x Prompt: Rockchip I2S Device Driver x x Location: x x -> Device Drivers x x -> Sound card support (SOUND [=y]) x x -> Advanced Linux Sound Architecture (SND [=y]) x x (6) -> ALSA for SoC audio support (SND_SOC [=y]) x x -> ASoC support for Rockchip (SND_SOC_ROCKCHIP [=n]) x x Defined at sound/soc/rockchip/Kconfig:18 x x Depends on: SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && CLKDEV_LOOKUP [=y] && SND_SOC_ROCKCHIP [=n] x x Selects: SND_SOC_GENERIC_DMAENGINE_PCM [=n] x x Selected by [n]: x x - SND_SOC_ROCKCHIP_MAX98090 [=n] && SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && SND_SOC_ROCKCHIP [=n] && I2C [=y] && GPIOLIB [=y] && CLKDEV_LOOKUP [=y] x x - SND_SOC_ROCKCHIP_RT5645 [=n] && SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && SND_SOC_ROCKCHIP [=n] && I2C [=y] && GPIOLIB [=y] && CLKDEV_LOOKUP [=y] x x - SND_SOC_ROCKCHIP_RT5651 [=n] && SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && SND_SOC_ROCKCHIP [=n] && I2C [=y] && GPIOLIB [=y] && CLKDEV_LOOKUP [=y] x x - SND_SOC_ROCKCHIP_RT5651_RK628 [=n] && SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && SND_SOC_ROCKCHIP [=n] && I2C [=y] && GPIOLIB [=y] && CLKDEV_LOOKUP [=y] x x - SND_SOC_RK3288_HDMI_ANALOG [=n] && SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && SND_SOC_ROCKCHIP [=n] && I2C [=y] && GPIOLIB [=y] && CLKDEV_LOOKUP [=y] x x - SND_SOC_RK3399_GRU_SOUND [=n] && SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && SND_SOC_ROCKCHIP [=n] && I2C [=y] && GPIOLIB [=y] && CLKDEV_LOOKUP [=y] && SPI [=y] x
最新发布
07-20
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值