// 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