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

posted on 2011-12-02 07:04  _song  阅读(377)  评论(0编辑  收藏  举报