Synopsys DesignWare的I2C master的code主要在drivers/i2c/busses/I2C-designware-platdrv.c中。kernel中将I2C master也叫做 I2c adapter driver
static struct platform_driver dw_i2c_driver = {
.probe = dw_i2c_plat_probe,
.remove = dw_i2c_plat_remove,
.driver = {
.name = "i2c_designware",
.of_match_table = of_match_ptr(dw_i2c_of_match),
.acpi_match_table = ACPI_PTR(dw_i2c_acpi_match),
.pm = DW_I2C_DEV_PMOPS,
},
};
static int __init dw_i2c_init_driver(void)
{
return platform_driver_register(&dw_i2c_driver);
}
subsys_initcall(dw_i2c_init_driver);
static void __exit dw_i2c_exit_driver(void)
{
platform_driver_unregister(&dw_i2c_driver);
}
module_exit(dw_i2c_exit_driver);
还是一贯的写法,这里注意的是和module_exit 对应的不一定是module_init ,这里就是和subsys_initcall。
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:i2c_designware");
针对ACPI bus的话,hotplut可以通过
static const struct acpi_device_id dw_i2c_acpi_match[] = {
{ "INT33C2", 0 },
{ "INT33C3", 0 },
{ "INT3432", 0 },
{ "INT3433", 0 },
{ "80860F41", 0 },
{ "808622C1", 0 },
{ "AMD0010", ACCESS_INTR_MASK },
{ "AMDI0010", ACCESS_INTR_MASK },
{ "AMDI0510", 0 },
{ "APMC0D0F", 0 },
{ }
};
MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match);
来在module_alias中产生相关的信息 ,但是如果匹配的id不在acpi_device_id中的话,还是需要通过下面的code来
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:i2c_designware");
在module_alias中产生相关的信息 。也就是一般不同特别显示调用MODULE_ALIAS,从这里也可以知道同一个ko在module_alias 中的对应的alias不止一个.
我这里是通过bios传递APMC0D0F。因此匹配,调用dw_i2c_plat_probe
static int dw_i2c_plat_probe(struct platform_device *pdev)
{
//通过dev_get_platdata 拿到bios传递的platform_data
struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct dw_i2c_dev *dev;
struct i2c_adapter *adap;
struct resource *mem;
int irq, r;
u32 acpi_speed, ht = 0;
//platform_get_irq 中通过platform_get_resource得到irq 资源。
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
//申请dw_i2c_dev 空间
dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
//得到bios传递过来的mem资源,并remap成虚拟地址
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dev->base = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(dev->base))
return PTR_ERR(dev->base);
dev->dev = &pdev->dev;
dev->irq = irq;
//将struct dw_i2c_dev *dev; 保存为drv_data。
platform_set_drvdata(pdev, dev);
/* fast mode by default because of legacy reasons */
dev->clk_freq = 400000;
if (pdata) {
dev->clk_freq = pdata->i2c_scl_freq;
} else {
//通过dt得到参数
device_property_read_u32(&pdev->dev, "i2c-sda-hold-time-ns",
&ht);
device_property_read_u32(&pdev->dev, "i2c-sda-falling-time-ns",
&dev->sda_falling_time);
device_property_read_u32(&pdev->dev, "i2c-scl-falling-time-ns",
&dev->scl_falling_time);
device_property_read_u32(&pdev->dev, "clock-frequency",
&dev->clk_freq);
}
//得到传输speed,这个speed 是在bios传递给kernel的ACPI 表中已经规定好的,这里只是找到而已.
acpi_speed = i2c_acpi_find_bus_speed(&pdev->dev);
if (acpi_speed)
dev->clk_freq = acpi_speed;
//看是否同ACPI 传递参数的.
if (has_acpi_companion(&pdev->dev))
dw_i2c_acpi_configure(pdev);
/*
* Only standard mode at 100kHz, fast mode at 400kHz,
* fast mode plus at 1MHz and high speed mode at 3.4MHz are supported.
*/
if (dev->clk_freq != 100000 && dev->clk_freq != 400000
&& dev->clk_freq != 1000000 && dev->clk_freq != 3400000) {
dev_err(&pdev->dev,
"Only 100kHz, 400kHz, 1MHz and 3.4MHz supported");
return -EINVAL;
}
//没有定义CONFIG_I2C_DESIGNWARE_BAYTRAIL的话,为空函数.
r = i2c_dw_eval_lock_support(dev);
if (r)
return r;
dev->functionality =
I2C_FUNC_I2C |
I2C_FUNC_10BIT_ADDR |
I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_I2C_BLOCK;
dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
DW_IC_CON_RESTART_EN;
//支持三种speed :std/fast/high
switch (dev->clk_freq) {
case 100000:
dev->master_cfg |= DW_IC_CON_SPEED_STD;
break;
case 3400000:
dev->master_cfg |= DW_IC_CON_SPEED_HIGH;
break;
default:
dev->master_cfg |= DW_IC_CON_SPEED_FAST;
}
//得到clk
dev->clk = devm_clk_get(&pdev->dev, NULL);
if (!i2c_dw_plat_prepare_clk(dev, true)) {
dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
if (!dev->sda_hold_time && ht)
dev->sda_hold_time = div_u64(
(u64)dev->get_clk_rate_khz(dev) * ht + 500000,
1000000);
}
//配置发送fifo的深度
if (!dev->tx_fifo_depth) {
u32 param1 = i2c_dw_read_comp_param(dev);
dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1;
dev->rx_fifo_depth = ((param1 >> 8) & 0xff) + 1;
dev->adapter.nr = pdev->id;
}
adap = &dev->adapter;
adap->owner = THIS_MODULE;
adap->class = I2C_CLASS_DEPRECATED;
//通过ACPI_COMPANION(&pdev->dev)得到acpi的fwnode再赋值给adap->dev
ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev));
adap->dev.of_node = pdev->dev.of_node;
//power相关的设定
if (dev->pm_runtime_disabled) {
pm_runtime_forbid(&pdev->dev);
} else {
pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
}
//继续调用i2c_dw_probe
r = i2c_dw_probe(dev);
if (r && !dev->pm_runtime_disabled)
pm_runtime_disable(&pdev->dev);
return r;
}
int i2c_dw_probe(struct dw_i2c_dev *dev)
{
struct i2c_adapter *adap = &dev->adapter;
int r;
//初始化完成量,完成量一般用于中断中,这里可以看出I2C master的发送和接收肯定用的是中断
init_completion(&dev->cmd_complete);
//硬件的初始化,主要是设定寄存器
r = i2c_dw_init(dev);
if (r)
return r;
//将名字改为Synopsys DesignWare I2C adapter。
snprintf(adap->name, sizeof(adap->name),
"Synopsys DesignWare I2C adapter");
adap->retries = 3;
adap->algo = &i2c_dw_algo;
adap->dev.parent = dev->dev;
i2c_set_adapdata(adap, dev);
i2c_dw_disable_int(dev);
//注册中断
r = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr,
IRQF_SHARED | IRQF_COND_SUSPEND,
dev_name(dev->dev), dev);
if (r) {
dev_err(dev->dev, "failure requesting irq %i: %d\n",
dev->irq, r);
return r;
}
/*
* Increment PM usage count during adapter registration in order to
* avoid possible spurious runtime suspend when adapter device is
* registered to the device core and immediate resume in case bus has
* registered I2C slaves that do I2C transfers in their probe.
*/
pm_runtime_get_noresume(dev->dev);
//添加这个adaper对应的device
r = i2c_add_numbered_adapter(adap);
if (r)
dev_err(dev->dev, "failure adding adapter: %d\n", r);
pm_runtime_put_noidle(dev->dev);
return r;
}
int i2c_add_numbered_adapter(struct i2c_adapter *adap)
{
//一般都是动态分配bus id
if (adap->nr == -1) /* -1 means dynamically assign bus id */
return i2c_add_adapter(adap);
return __i2c_add_numbered_adapter(adap);
}
int i2c_add_adapter(struct i2c_adapter *adapter)
{
struct device *dev = &adapter->dev;
int id;
//通过dt传递参数
if (dev->of_node) {
id = of_alias_get_id(dev->of_node, "i2c");
if (id >= 0) {
adapter->nr = id;
return __i2c_add_numbered_adapter(adapter);
}
}
//下面通过acpi 传递参数,这里的id 从__i2c_first_dynamic_bus_num 开始,一般为0.
mutex_lock(&core_lock);
id = idr_alloc(&i2c_adapter_idr, adapter,
__i2c_first_dynamic_bus_num, 0, GFP_KERNEL);
mutex_unlock(&core_lock);
if (WARN(id < 0, "couldn't get idr"))
return id;
//所以这里如果是地一个adapter的话,这里id就是0
adapter->nr = id;
//继续调用i2c_register_adapter
return i2c_register_adapter(adapter);
}
static int i2c_register_adapter(struct i2c_adapter *adap)
{
int res = -EINVAL;
/* Can't register until after driver model init */
if (WARN_ON(!is_registered)) {
res = -EAGAIN;
goto out_list;
}
/* Sanity checks */
if (WARN(!adap->name[0], "i2c adapter has no name"))
goto out_list;
if (!adap->algo) {
pr_err("adapter '%s': no algo supplied!\n", adap->name);
goto out_list;
}
if (!adap->lock_ops)
adap->lock_ops = &i2c_adapter_lock_ops;
rt_mutex_init(&adap->bus_lock);
rt_mutex_init(&adap->mux_lock);
mutex_init(&adap->userspace_clients_lock);
INIT_LIST_HEAD(&adap->userspace_clients);
/* Set default timeout to 1 second if not already set */
if (adap->timeout == 0)
adap->timeout = HZ;
//这里如果是第一个adapter的name就是i2c-0
dev_set_name(&adap->dev, "i2c-%d", adap->nr);
//这里adapter的bus type是i2c_bus_type
adap->dev.bus = &i2c_bus_type;
adap->dev.type = &i2c_adapter_type;
//添加这个device
res = device_register(&adap->dev);
if (res) {
pr_err("adapter '%s': can't register device (%d)\n", adap->name, res);
goto out_list;
}
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
}
static struct platform_driver dw_i2c_driver = {
.probe = dw_i2c_plat_probe,
.remove = dw_i2c_plat_remove,
.driver = {
.name = "i2c_designware",
.of_match_table = of_match_ptr(dw_i2c_of_match),
.acpi_match_table = ACPI_PTR(dw_i2c_acpi_match),
.pm = DW_I2C_DEV_PMOPS,
},
};
static int __init dw_i2c_init_driver(void)
{
return platform_driver_register(&dw_i2c_driver);
}
subsys_initcall(dw_i2c_init_driver);
static void __exit dw_i2c_exit_driver(void)
{
platform_driver_unregister(&dw_i2c_driver);
}
module_exit(dw_i2c_exit_driver);
还是一贯的写法,这里注意的是和module_exit 对应的不一定是module_init ,这里就是和subsys_initcall。
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:i2c_designware");
针对ACPI bus的话,hotplut可以通过
static const struct acpi_device_id dw_i2c_acpi_match[] = {
{ "INT33C2", 0 },
{ "INT33C3", 0 },
{ "INT3432", 0 },
{ "INT3433", 0 },
{ "80860F41", 0 },
{ "808622C1", 0 },
{ "AMD0010", ACCESS_INTR_MASK },
{ "AMDI0010", ACCESS_INTR_MASK },
{ "AMDI0510", 0 },
{ "APMC0D0F", 0 },
{ }
};
MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match);
来在module_alias中产生相关的信息 ,但是如果匹配的id不在acpi_device_id中的话,还是需要通过下面的code来
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:i2c_designware");
在module_alias中产生相关的信息 。也就是一般不同特别显示调用MODULE_ALIAS,从这里也可以知道同一个ko在module_alias 中的对应的alias不止一个.
我这里是通过bios传递APMC0D0F。因此匹配,调用dw_i2c_plat_probe
static int dw_i2c_plat_probe(struct platform_device *pdev)
{
//通过dev_get_platdata 拿到bios传递的platform_data
struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct dw_i2c_dev *dev;
struct i2c_adapter *adap;
struct resource *mem;
int irq, r;
u32 acpi_speed, ht = 0;
//platform_get_irq 中通过platform_get_resource得到irq 资源。
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
//申请dw_i2c_dev 空间
dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
//得到bios传递过来的mem资源,并remap成虚拟地址
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dev->base = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(dev->base))
return PTR_ERR(dev->base);
dev->dev = &pdev->dev;
dev->irq = irq;
//将struct dw_i2c_dev *dev; 保存为drv_data。
platform_set_drvdata(pdev, dev);
/* fast mode by default because of legacy reasons */
dev->clk_freq = 400000;
if (pdata) {
dev->clk_freq = pdata->i2c_scl_freq;
} else {
//通过dt得到参数
device_property_read_u32(&pdev->dev, "i2c-sda-hold-time-ns",
&ht);
device_property_read_u32(&pdev->dev, "i2c-sda-falling-time-ns",
&dev->sda_falling_time);
device_property_read_u32(&pdev->dev, "i2c-scl-falling-time-ns",
&dev->scl_falling_time);
device_property_read_u32(&pdev->dev, "clock-frequency",
&dev->clk_freq);
}
//得到传输speed,这个speed 是在bios传递给kernel的ACPI 表中已经规定好的,这里只是找到而已.
acpi_speed = i2c_acpi_find_bus_speed(&pdev->dev);
if (acpi_speed)
dev->clk_freq = acpi_speed;
//看是否同ACPI 传递参数的.
if (has_acpi_companion(&pdev->dev))
dw_i2c_acpi_configure(pdev);
/*
* Only standard mode at 100kHz, fast mode at 400kHz,
* fast mode plus at 1MHz and high speed mode at 3.4MHz are supported.
*/
if (dev->clk_freq != 100000 && dev->clk_freq != 400000
&& dev->clk_freq != 1000000 && dev->clk_freq != 3400000) {
dev_err(&pdev->dev,
"Only 100kHz, 400kHz, 1MHz and 3.4MHz supported");
return -EINVAL;
}
//没有定义CONFIG_I2C_DESIGNWARE_BAYTRAIL的话,为空函数.
r = i2c_dw_eval_lock_support(dev);
if (r)
return r;
dev->functionality =
I2C_FUNC_I2C |
I2C_FUNC_10BIT_ADDR |
I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_I2C_BLOCK;
dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
DW_IC_CON_RESTART_EN;
//支持三种speed :std/fast/high
switch (dev->clk_freq) {
case 100000:
dev->master_cfg |= DW_IC_CON_SPEED_STD;
break;
case 3400000:
dev->master_cfg |= DW_IC_CON_SPEED_HIGH;
break;
default:
dev->master_cfg |= DW_IC_CON_SPEED_FAST;
}
//得到clk
dev->clk = devm_clk_get(&pdev->dev, NULL);
if (!i2c_dw_plat_prepare_clk(dev, true)) {
dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
if (!dev->sda_hold_time && ht)
dev->sda_hold_time = div_u64(
(u64)dev->get_clk_rate_khz(dev) * ht + 500000,
1000000);
}
//配置发送fifo的深度
if (!dev->tx_fifo_depth) {
u32 param1 = i2c_dw_read_comp_param(dev);
dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1;
dev->rx_fifo_depth = ((param1 >> 8) & 0xff) + 1;
dev->adapter.nr = pdev->id;
}
adap = &dev->adapter;
adap->owner = THIS_MODULE;
adap->class = I2C_CLASS_DEPRECATED;
//通过ACPI_COMPANION(&pdev->dev)得到acpi的fwnode再赋值给adap->dev
ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev));
adap->dev.of_node = pdev->dev.of_node;
//power相关的设定
if (dev->pm_runtime_disabled) {
pm_runtime_forbid(&pdev->dev);
} else {
pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
}
//继续调用i2c_dw_probe
r = i2c_dw_probe(dev);
if (r && !dev->pm_runtime_disabled)
pm_runtime_disable(&pdev->dev);
return r;
}
int i2c_dw_probe(struct dw_i2c_dev *dev)
{
struct i2c_adapter *adap = &dev->adapter;
int r;
//初始化完成量,完成量一般用于中断中,这里可以看出I2C master的发送和接收肯定用的是中断
init_completion(&dev->cmd_complete);
//硬件的初始化,主要是设定寄存器
r = i2c_dw_init(dev);
if (r)
return r;
//将名字改为Synopsys DesignWare I2C adapter。
snprintf(adap->name, sizeof(adap->name),
"Synopsys DesignWare I2C adapter");
adap->retries = 3;
adap->algo = &i2c_dw_algo;
adap->dev.parent = dev->dev;
i2c_set_adapdata(adap, dev);
i2c_dw_disable_int(dev);
//注册中断
r = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr,
IRQF_SHARED | IRQF_COND_SUSPEND,
dev_name(dev->dev), dev);
if (r) {
dev_err(dev->dev, "failure requesting irq %i: %d\n",
dev->irq, r);
return r;
}
/*
* Increment PM usage count during adapter registration in order to
* avoid possible spurious runtime suspend when adapter device is
* registered to the device core and immediate resume in case bus has
* registered I2C slaves that do I2C transfers in their probe.
*/
pm_runtime_get_noresume(dev->dev);
//添加这个adaper对应的device
r = i2c_add_numbered_adapter(adap);
if (r)
dev_err(dev->dev, "failure adding adapter: %d\n", r);
pm_runtime_put_noidle(dev->dev);
return r;
}
int i2c_add_numbered_adapter(struct i2c_adapter *adap)
{
//一般都是动态分配bus id
if (adap->nr == -1) /* -1 means dynamically assign bus id */
return i2c_add_adapter(adap);
return __i2c_add_numbered_adapter(adap);
}
int i2c_add_adapter(struct i2c_adapter *adapter)
{
struct device *dev = &adapter->dev;
int id;
//通过dt传递参数
if (dev->of_node) {
id = of_alias_get_id(dev->of_node, "i2c");
if (id >= 0) {
adapter->nr = id;
return __i2c_add_numbered_adapter(adapter);
}
}
//下面通过acpi 传递参数,这里的id 从__i2c_first_dynamic_bus_num 开始,一般为0.
mutex_lock(&core_lock);
id = idr_alloc(&i2c_adapter_idr, adapter,
__i2c_first_dynamic_bus_num, 0, GFP_KERNEL);
mutex_unlock(&core_lock);
if (WARN(id < 0, "couldn't get idr"))
return id;
//所以这里如果是地一个adapter的话,这里id就是0
adapter->nr = id;
//继续调用i2c_register_adapter
return i2c_register_adapter(adapter);
}
static int i2c_register_adapter(struct i2c_adapter *adap)
{
int res = -EINVAL;
/* Can't register until after driver model init */
if (WARN_ON(!is_registered)) {
res = -EAGAIN;
goto out_list;
}
/* Sanity checks */
if (WARN(!adap->name[0], "i2c adapter has no name"))
goto out_list;
if (!adap->algo) {
pr_err("adapter '%s': no algo supplied!\n", adap->name);
goto out_list;
}
if (!adap->lock_ops)
adap->lock_ops = &i2c_adapter_lock_ops;
rt_mutex_init(&adap->bus_lock);
rt_mutex_init(&adap->mux_lock);
mutex_init(&adap->userspace_clients_lock);
INIT_LIST_HEAD(&adap->userspace_clients);
/* Set default timeout to 1 second if not already set */
if (adap->timeout == 0)
adap->timeout = HZ;
//这里如果是第一个adapter的name就是i2c-0
dev_set_name(&adap->dev, "i2c-%d", adap->nr);
//这里adapter的bus type是i2c_bus_type
adap->dev.bus = &i2c_bus_type;
adap->dev.type = &i2c_adapter_type;
//添加这个device
res = device_register(&adap->dev);
if (res) {
pr_err("adapter '%s': can't register device (%d)\n", adap->name, res);
goto out_list;
}
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
}