micro2440装备的是at24c08
配置内核的i2c主机控制器驱动
Device Drivers ---><*> I2C support ---> I2C Hardware Bus support ---><M> S3C2410 I2C Driver 。
这里把它配置成模块形式,并重新编译烧写内核。
查看该项目的help:symbol: I2C_S3C2410 [=m],然后再根据Kconfig和Makefile可知对应的原文件是i2c-s3c2410.c。
编译出的模块文件是 i2c-s3c2410.ko,将其下载到板子上insmod时出现如下信息:
[root@FriendlyARM plg]# insmod i2c-s3c2410.ko
s3c-i2c s3c2440-i2c: slave address 0x10
s3c-i2c s3c2440-i2c: bus frequency set to 98 KHz
s3c-i2c s3c2440-i2c: i2c-0: S3C I2C adapter
并生成设备节点/dev/i2c/0....查看i2c-s3c2410.c并没有发现注册字符设备(或创建设备节点)的代码。。。
是在驱动里面使用class_create和device_create然后借助用户空间mudev自动创建设备节点的。
如下
1.
micro2440的i2c驱动的最外层是platform平台。在板子设备集合中加入了平台设备s3c_device_i2c0,它会在板子启动时注册。如下
/opt/FriendlyArm/mini2440/linux-2.6.32.2/arch/arm/mach-s3c2440/mach-mini2440.c
static struct platform_device *mini2440_devices[] __initdata = {
&s3c_device_usb,
&s3c_device_rtc,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c0,//
&s3c_device_iis,
&mini2440_device_eth,
&s3c24xx_uda134x,
&s3c_device_nand,
&s3c_device_sdi,
&s3c_device_usbgadget,
};
s3c_device_i2c0如下
arch/arm/plat-s3c/dev-i2c0.c
static struct resource s3c_i2c_resource[] = {
[0] = {
.start = S3C_PA_IIC,
.end = S3C_PA_IIC + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_IIC,
.end = IRQ_IIC,
.flags = IORESOURCE_IRQ,
},
};
struct platform_device s3c_device_i2c0 = {
.name = "s3c2410-i2c",
#ifdef CONFIG_S3C_DEV_I2C1
.id = 0,
#else
.id = -1,
#endif
.num_resources = ARRAY_SIZE(s3c_i2c_resource),
.resource = s3c_i2c_resource,
};
static struct s3c2410_platform_i2c default_i2c_data0 __initdata = {
.flags = 0,
.slave_addr = 0x10,
.frequency = 100*1000,
.sda_delay = 100,
};
2.平台驱动s3c24xx_i2c_driver写在
drivers/i2c/buses/i2c-s3c2410.c
static struct platform_device_id s3c24xx_driver_ids[] = {
{
.name = "s3c2410-i2c",
.driver_data = TYPE_S3C2410,
}, {
.name = "s3c2440-i2c",
.driver_data = TYPE_S3C2440,
}, { },
};
MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids);
static struct platform_driver s3c24xx_i2c_driver = {
.probe = s3c24xx_i2c_probe,
.remove = s3c24xx_i2c_remove,
.id_table = s3c24xx_driver_ids,
.driver = {
.owner = THIS_MODULE,
.name = "s3c-i2c",
.pm = S3C24XX_DEV_PM_OPS,
},
};
static int __init i2c_adap_s3c_init(void)
{
return platform_driver_register(&s3c24xx_i2c_driver);
}
3.在insmod i2c-s3c2410.ko 时,platform核心会根据已注册的设备找到驱动-----名字都是s3c2410-i2c(platform_driver如果有id_table,用id_table里的name;否则用platform_driver里的name,看源码可知),执行驱动的s3c24xx_i2c_probe,在s3c24xx_i2c_probe函数里面调用i2c_add_numbered_adapter,如下
drivers/i2c/buses/i2c-s3c2410.c
ret = i2c_add_numbered_adapter(&i2c->adap);
if (ret < 0) {
dev_err(&pdev->dev, "failed to add bus to i2c core\n");
goto err_cpufreq;
}
i2c_add_numbered_adapter是i2c内核的而一个函数,此函数又执行如下动作即注册adapterret = i2c_add_numbered_adapter(&i2c->adap);----->return i2c_register_adapter(adapter);暂停,然后从另一个线索跟进,如下。
i2c-dev.c是一个被编译进内核的文件--实现用户空间的接口,设备即外设驱动,如下
Device Drivers ---><*> I2C support ---> <*> I2C device interface
static struct i2c_driver i2cdev_driver = {
.driver = {
.name = "dev_driver",
},
.attach_adapter = i2cdev_attach_adapter,
.detach_adapter = i2cdev_detach_adapter,
};
static int __init i2c_dev_init(void)
{
int res;
printk(KERN_INFO "i2c /dev entries driver\n");
res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);
if (res)
goto out;
i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");
if (IS_ERR(i2c_dev_class)) {
res = PTR_ERR(i2c_dev_class);
goto out_unreg_chrdev;
}
res = i2c_add_driver(&i2cdev_driver);
if (res)
goto out_unreg_class;
return 0;
out_unreg_class:
class_destroy(i2c_dev_class);
out_unreg_chrdev:
unregister_chrdev(I2C_MAJOR, "i2c");
out:
printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__);
return res;
}
i2c_dev_init函数里面创建了字符设备,register_chrdev并且class_create:i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");
当有新的adapter注册比如i2c_add_numbered_adapter() 时,就会执行 i2cdev_attach_adapter,
函数实现如下
.attach_adapter = i2cdev_attach_adapter,
static struct class *i2c_dev_class;
static int i2cdev_attach_adapter(struct i2c_adapter *adap)
{
struct i2c_dev *i2c_dev;
int res;
i2c_dev = get_free_i2c_dev(adap);
if (IS_ERR(i2c_dev))
return PTR_ERR(i2c_dev);
/* register this i2c device with the driver core */
i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,
MKDEV(I2C_MAJOR, adap->nr), NULL,
"i2c-%d", adap->nr);
if (IS_ERR(i2c_dev->dev)) {
res = PTR_ERR(i2c_dev->dev);
goto error;
}
res = device_create_file(i2c_dev->dev, &dev_attr_name);
if (res)
goto error_destroy;
pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
adap->name, adap->nr);
return 0;
error_destroy:
device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
error:
return_i2c_dev(i2c_dev);
return res;
}
可看到
device_create(i2c_dev_class, &adap->dev,MKDEV(I2C_MAJOR, adap->nr), NULL,"i2c-%d", adap->nr);
从这里可得知借助mdev会创建如/dev/i2c-0设备文件
但是实际上创建的是/dev/i2c/0文件。查看mdev的规则文件可以解答这个问题:
[root@FriendlyARM /]# vi /etc/mdev.conf
...
# i2c devices
i2c-0 0:0 0666 =i2c/0
i2c-1 0:0 0666 =i2c/1
...
所以自动创建的设备节点是 /dev/i2c/0
所以如果把上面的一行 i2c-0 0:0 0666 =i2c/0 注释掉,那么创建的则是/dev/i2c-0
所以可以得知,只要有adapter注册,i2c-dev.c都会创建一个设备文件/dev/i2c-xx