i2c--insmod
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内核的而一个函数,此函数又执行如下动作即注册adapter
ret = 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