Linux设备驱动入门----I2C设备驱动
/* * I2C驱动的一些模板: * (1)、I2C总线驱动的的模块加载和卸载函数模板 * (2)、I2C总线通信方法 * (3)、I2C设备驱动模块的加载和卸载 * (4)、I2C设备驱动的文件操作接口 * (与普通驱动的文件操作一致,只是要使用 * i2c_client,i2c_driver,i2c_adapter,i2c_algorithm * 结构体和I2C核心,需要协同合作) *//* * (1) : 初始化I2C适配器所使用的硬件资源, * 如申请I/O地址,中断号等。通过i2c_add_adapter() * 添加i2c_adapter的数据结构,当然这个i2c_adapter * 数据结构的成员已经被XXX设配器的相应函数指针所初始化 * 说明:xxx_adapter_hw_init();xxx_adapter_hw_free(); * 函数的实现都与具体的CPU和I2C设备硬件直接相关。 */static int __init i2c_adapter_xxx_init(void){xxx_adapter_hw_init();i2c_add_adapter(&xxx_adapter);}static void __exit i2c_adapter_xxx_exit(void){xxx_adapter_hw_free();i2c_del_adapter(&xxx_adapter);}/* * (2): 主要实现i2c_algorithm 的master_xfer() * 函数和 functionality()函数。 * functionality()函数用于返回algorithm所支持的通信协议 * master_xfer()函数在I2C适配器上完成传递给它的 * i2c_msg数组中的每个I2C消息。 * * 说明:模板中的i2c_adapter_xxx_start(),setaddr(), * wait_ack(),readbytes(),writebytes(),stop()函数用于 * 适配器的底层硬件操作,与I2C适配器和CPU的具体硬件直接 * 相关,需要由工程师根据芯片的数据手册来实现。 * */static int i2c_adapter_xxx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num){...for(i = 0; i < num; i++){i2c_adapter_xxx_start(); /* 产生开始位 *//* 是读消息 */if (msgs[i]->flags & I2C_M_RD){/* 发送从设备读地址 */i2c_adapter_xxx_setaddr((msg->addr << 1) | 1);i2c_adapter_xxx_wait_ack(); /* 获取从设备的ack *//* 读取msgs[i]->len长的数据到msgs[i]->buf */i2c_adapter_xxx_readbytes(msgs[i]->buf, msgs[i]->len);}else{/* 写消息 *//* 发送从设备写地址 */i2c_adapter_xxx_setaddr(msg->addr << 1); i2c_adapter_xxx_wait_ack; //获取从设备的ack/* 读取msgs[i]->len长的数据到msgs[i]->buf */ i2c_adapter_xxx_writebytes(msgs[i]->buf, msgs[i]->len);}}i2c_adapter_xxx_stop(); /* 产生停止位 */}/* * (3): 通过register_chrdev()函数将I2C设备注册为一个字符设备; * 通过I2C核心的i2c_add_driver()函数添加i2c_driver; * */static int __init yyy_init(void){ int res;/* 注册字符设备 */res = register_chrdev(YYY_MAJOR, "YYY", &yyy_fops);//老内核接口if (res)goto out;/* 添加i2c_driver */res = i2c_add_driver(&yyy_driver);if(res){goto out_unreg_class;}return 0;out_unreg_class:unregister_chrdev(I2C_MAJOR, "i2c");out:printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__);return res;}static void __exit yyy_exit(void){i2c_del_driver(&i2cdev_driver);unregiister_chrdev(YYY_MAJOR, "YYY");}/* * i2c_add_driver(&yyy_driver)的执行会引发i2c_driver * 结构体中yyy_attach_adapter()函数的执行,可以在该函 * 数立探测物理设备,只需要调用I2C核心的i2c_probe() * */static int yyy_attach_adapter(struct i2c_adapter * adapter){/* * param1:i2c_adapter指针 * param2:要探测的地址数据 * param3:具体的探测函数 */return i2c_probe(adapter, &addr_data, yyy_detect);}/* * i2c_probe()函数会引发yyy_detect()函数的调用, * 可以在yyy_detect()函数中初始化i2c_client */static int yyy_detect(struct i2c_adapter *adapter, int address, int kind){struct i2c_client * new_client;struct yyy_data *data;int err = 0;if(!i2c_check_functionality(adapter, I2C_FUNC_XXX))goto exit;if (!(data = kzalloc(sizeof(struct yyy_data), GFP_KERBEL))){err = - ENOMEM;goto exit;}new_client = &data->client;new_client->addr = address;new_client->adapter = adapter;new_client->driver = &yyy_driver;new_client->flags = 0;/* 新的client将依附于adapter */if ((err = i2c_attach_client(new_client)))goto exit_kfree;yyy_init_client(new_client);//此函数是与硬件相关的return 0;exit_kfree:kfree(data);exit:return err;}/* i2c_detach_client函数 */static int yyy_detach_client(struct i2c_client *client){int err;struct yyy_data *data = i2c_get_clientdata(client);if((err = i2c_detach_client(client)))return err;kfree(data);return 0;}/* * yyy_command()的实现,它实现了针对设备的控制命令; * 具体的控制命令是设备相关的,对于实时钟而言,命令 * 将是设置时间和获取时间, 而对于视频AD设备而言, * 命令会是设置采样方式,选择通道等。 */static int yyy_command(struct i2c_client *client, unsigned int cmd, void * arg){switch(cmd){case YYY_CMD1:return yyy_cmd1(client, arg);case YYY_CMD2:return yyy_cmd2(client, arg);default:return -EINVAL;}}/* * I2C设备具体命令处理函数模板 */static int yyy_cmd1(struct i2c_client *client, struct rtc_time *dt){struct i2c_msg msg[2];/* 第一条是写消息 */msg[0].addr = client->addr;msg[0].flags = 0;msg[0].len = 1;msg[0].buf = &offs;/* 第二条消息是读消息 */msg[1].addr = client->addr;msg[1].flags = I2C_M_RD;msg[1].len = sizeof(buf);msg[1].buf = &buf[0];i2c_transfer(client->adapter, msg, 2);...;}/* * (4)、I2C设备文件的接口写函数范例 * 具体的写操作与设备密切相关 * I2C设备驱动的文件操作接口也不是必须的; * 大多数情况下,只需要通过i2c-dev.c文件 * 提供的I2C适配器设备文件接口久可完成对I2C * 设备的读写。 * */static ssize_t yyy_write(struct file * file, char *buf, size_t count, loff_t off) {struct i2c_client *client = (struct i2c_client*)file->private_data;i2c_msg msg[1];char *tmp;int ret;tmp = kmalloc(count, GFP_KERNEL);if (tmp == NULL)return -ENOMEM;if(copy_from_user(tmp, buf, count)){kfree(tmp);return -EFAULT;}msg[0].addr = client->addr; //地址msg[0].flags = 0; // 0为写msg[0].len = count; //要写的字节数msg[0].buf = tmp; //要写的数据ret = i2c_transfer(client->adapter, msg, 1); //传输I2C消息return (ret == 1) ? count : ret;}另:S3C2410 I2C总线驱动实例:http://download.csdn.net/detail/cailiwei712/4496578