1、创建字符设备 如果不是I2C的驱动设备,要创建一个字符设备,方法如下: 定义全局变量: //字符设备 #define SOCTOMCU_DEVICE_NAME “soctomcu” tatic int soctomcu_major = 0; static struct class *soctomcu_class; struct device *soctomcu_device; #define FRAME_LEN_MAX 132 typedef struct{ unsigned char buf[FRAME_LEN_MAX]; int len; }soctomcu_frame; //I2C设备 struct i2c_client *i2c_connect_client; struct SOCTOR78I2C_data{ struct i2c_client *SOCTOR78I2C_client; struct delayed_work work; }; static struct SOCTOR78I2C_data *SOCTOR78I2C_i2c;
定义文件系统接口: static const struct file_operations soctomcu_fops = { .owner = THIS_MODULE, .open = soctomcu_open, .release = soctomcu_close, .read = socto_lvdsmcu_read, .write = socto_lvdsmcu_write, }; 在init初始化函数中: static int __init soctor78_init(void) { /*创建I2C设备定义/ struct i2c_board_info info; struct i2c_adapter *adapter; struct i2c_client *client; int ret=0; … //获取主设备号 soctomcu_major = register_chrdev(0, SOCTOMCU_DEVICE_NAME, &soctomcu_fops); if(soctomcu_major < 0){ unregister_chrdev(soctomcu_major, SOCTOMCU_DEVICE_NAME); pr_info(“soctomcu register_chrdev fail!\n”); ret =soctomcu_major; } //获取设备类 soctomcu_class = class_create(THIS_MODULE, SOCTOMCU_DEVICE_NAME); if (IS_ERR(soctomcu_class)) { class_destroy(soctomcu_class); printk(KERN_ERR “Error creating class.\n”); ret = -1; } //创建字符设备 soctomcu_device = device_create(soctomcu_class, NULL, MKDEV(soctomcu_major, 0), NULL, SOCTOMCU_DEVICE_NAME); if (IS_ERR(soctomcu_device)) { device_destroy(soctomcu_class, MKDEV(soctomcu_major, 0)); printk(KERN_ERR “Error creating class device.\n”); ret = -1; } memset(&info, 0, sizeof(struct i2c_board_info)); info.addr = SOCTOR78I2C_ADDR; strlcpy(info.type, “SocToR78_I2c”, I2C_NAME_SIZE);
adapter = i2c_get_adapter(0); //创建I2C适配器,后面的i2c_transfer()函数需要用到这个适配器 if (!adapter) { printk(KERN_ERR "Can't get i2c adapter 0\n"); //kfree(pdata); ret = -ENODEV; goto exit; } client = i2c_new_device(adapter, &info); //取到client,后面传给probe()函数,在probe()函数中保存给后面的i2C通信函数使用 //printk("i2c_new_device::client=0x%x\n",*client); i2c_put_adapter(adapter); if (!client) { printk(KERN_ERR "Can't add i2c device at 0x%x\n", (unsigned int)info.addr); //kfree(pdata); ret = -ENOMEM; goto exit; }printk(“soctor78 driver installing…\n”); return i2c_add_driver(&soctor78_driver); }
static int __devinit soctor78_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret=0; struct SOCTOR78I2C_data *ts_pdata; client->addr=SOCTOR78I2C_ADDR; i2c_connect_client = client; if(!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE|I2C_FUNC_SMBUS_BYTE_DATA)){ printk("[mcui2c]:i2c_check_functionality failed \n"); return -1; } ts_pdata = kzalloc(sizeof(struct SOCTOR78I2C_data), GFP_KERNEL); if (!ts_pdata) return -ENOMEM; ts_pdata->SOCTOR78I2C_client=client; i2c_set_clientdata(client,ts_pdata); SOCTOR78I2C_i2c = ts_pdata; SOCTOR78I2C_i2c->SOCTOR78I2C_client =client; SOCTOR78I2C_i2c->SOCTOR78I2C_client->adapter=client->adapter; return 0; }后面使用probe()函数中保存的client取到adapter用于I2C接口通信 I2C写:
static int LvdsMcuWrite(int wLen,unsigned char *wData) { struct SOCTOR78I2C_data *pata=i2c_get_clientdata(i2c_connect_client);//从保存的client中取到client数据,后面用于I2C数据传输pata->SOCTOR78I2C_client->adapter struct i2c_msg msgs[1]; unsigned char WriteData[10]; unsigned int msg0_len=0; unsigned char i=0; unsigned char j=0; unsigned int ret=0; WriteData[i++]=0xFF; WriteData[i++]=0x55; for(j=0; j<(wLen);j++){ WriteData[i++]=*(wData+j); } WriteData[i++]=SOCWriteIIC_GetSum((wLen),&WriteData[3]); msg0_len = wLen+3; for(i=0;i< msg0_len;i++) printk("WriteData[%d]=0x%x\n",i,WriteData[i]); msgs[0].flags = !I2C_M_RD; msgs[0].addr = pata->SOCTOR78I2C_client->addr; msgs[0].len = msg0_len; msgs[0].buf = &WriteData[0]; write_read_cmd =WriteData[4]; printk("I2cToRt87::i2c Read write :: write_read_cmd=0x%x\n",write_read_cmd); ret = i2c_transfer(pata->SOCTOR78I2C_client->adapter, msgs,1); if(ret < 0){ printk("I2cToRt87::i2c Read write error ret=%d\n",ret); } printk("I2cToRt87::i2c Read write OK ret=%d\n",ret); return ret; }I2C读:
static int LvdsMcuRead(int rLen,unsigned char *rData) { struct SOCTOR78I2C_data *pata=i2c_get_clientdata(i2c_connect_client); struct i2c_msg msgs[1]; unsigned char ReadTPAckData[20]; unsigned char i=0; unsigned int ret=0; printk("LvdsMcuRead()::rLen=%d,i2c_connect_client->addr=0x%x\n",rLen,i2c_connect_client->addr); msgs[0].flags = I2C_M_RD; msgs[0].addr = pata->SOCTOR78I2C_client->addr; msgs[0].len = rLen; msgs[0].buf = &ReadTPAckData[0]; ret = i2c_transfer(pata->SOCTOR78I2C_client->adapter, msgs,1); if(ret < 0){ printk("I2cToRt87::i2c Read write error ret=%d\n",ret); } for(i=0;i<rLen;i++){ //printk("I2cToRt87::ReadTPAckData[%d]=0x%x\n",i,ReadTPAckData[i]); *(rData+i)=ReadTPAckData[i]; } return ret; }例如复位TP的通信指令:
const unsigned char TOUCHPANEL_RESET[]={0x03,0x10,0x13}; int Lvdsmcu_Resettp(void) { unsigned char wTempdata[10]; unsigned char ret=0; wTempdata[0]=TOUCHPANEL_RESET[0]; wTempdata[1]=TOUCHPANEL_RESET[1]; wTempdata[2]=TOUCHPANEL_RESET[2]; ret=LvdsMcuWrite(wTempdata[0], &wTempdata[0]); if(ret<0){ printk("LvdsMcuWrite()::touchpannel reset error ret=%d\n",ret); return ret; } printk("LvdsMcuWrite()::touchpannel reset ok ret=%d\n",ret); return ret; }最后整个驱动代码:
#include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/i2c.h> #include <linux/irq.h> #include <linux/platform_device.h> #include <linux/input-polldev.h> #include <linux/input.h> #include <linux/wait.h> #include <linux/workqueue.h> #include <linux/proc_fs.h> #include <linux/clk.h> #include <linux/io.h> #include <linux/gpio.h> #include <linux/proc_fs.h> #include <linux/kernel.h> #include <linux/sched.h> #include <asm/mach-types.h> #include <linux/clk.h> #include <linux/device.h> #include <linux/types.h> #include <linux/workqueue.h> #include <linux/spinlock.h> #include <linux/regulator/consumer.h> #include <linux/fsl_devices.h> #include <linux/input.h> #include <linux/workqueue.h> #include <linux/mutex.h> #include <linux/slab.h> #include <linux/mutex.h> #include <linux/uaccess.h> /*Winfred Young add for tftloader*/ #include <linux/cdev.h> #include <linux/io.h> #include <linux/kthread.h> #include <linux/sched.h> #include <linux/workqueue.h> #include <linux/poll.h> #include <linux/gpio.h> /**************soc to mcu communication protocol ****************/ #define SOCTOR78I2C_NAME "SocToR78_I2c" #define SOCTOR78I2C_NAME_SIZE 20 #define SOCTOR78I2C_ADDR 0x3c //0x78 //add soc to R87 connect test const unsigned char GET_COMMUNICATIONDET[]={0x03,0x10,0x88}; const unsigned char TOUCHPANEL_RESET[]={0x03,0x10,0x13}; struct i2c_client *i2c_connect_client; struct SOCTOR78I2C_data{ struct i2c_client *SOCTOR78I2C_client; struct delayed_work work; }; static struct SOCTOR78I2C_data *SOCTOR78I2C_i2c; /******************************************************** *Soc to mcu IO ctrl interface ************************************************************/ #define SOCTOMCU_DEVICE_NAME "soctomcu" //static DECLARE_WAIT_QUEUE_HEAD(inq); //int is_read_frame = 0; static unsigned char write_read_cmd =0x00; static int soctomcu_major = 0; static struct class *soctomcu_class; struct device *soctomcu_device; static int soctomcuopen=0; #define FRAME_LEN_MAX 132 typedef struct{ unsigned char buf[FRAME_LEN_MAX]; int len; }soctomcu_frame; static spinlock_t mcu_lock; /**************************************END ***************************/ unsigned char SOCWriteIIC_GetSum(unsigned char cLen,unsigned char *cData) { unsigned char i; unsigned char checkSum=0; for(i=0; i<(cLen-1); i++){ checkSum += *(cData+i); } return(checkSum); } /********************************************************************** wLen: Packet Length:Byte count from CID to CSUM wData: Byte count from CID to Para-N 1 frame data length=package head + 1byte wlwn+wLen = 2+1+wLen ***********************************************************************/ //static int LvdsMcuWrite(unsigned char wLen,unsigned char *wData) static int LvdsMcuWrite(int wLen,unsigned char *wData) { struct SOCTOR78I2C_data *pata=i2c_get_clientdata(i2c_connect_client);; struct i2c_msg msgs[1]; unsigned char WriteData[10]; unsigned int msg0_len=0; unsigned char i=0; unsigned char j=0; unsigned int ret=0; WriteData[i++]=0xFF; WriteData[i++]=0x55; for(j=0; j<(wLen);j++){ WriteData[i++]=*(wData+j); } WriteData[i++]=SOCWriteIIC_GetSum((wLen),&WriteData[3]); msg0_len = wLen+3; for(i=0;i< msg0_len;i++) printk("WriteData[%d]=0x%x\n",i,WriteData[i]); msgs[0].flags = !I2C_M_RD; msgs[0].addr = pata->SOCTOR78I2C_client->addr; msgs[0].len = msg0_len; msgs[0].buf = &WriteData[0]; write_read_cmd =WriteData[4]; printk("I2cToRt87::i2c Read write :: write_read_cmd=0x%x\n",write_read_cmd); ret = i2c_transfer(pata->SOCTOR78I2C_client->adapter, msgs,1); if(ret < 0){ printk("I2cToRt87::i2c Read write error ret=%d\n",ret); } printk("I2cToRt87::i2c Read write OK ret=%d\n",ret); return ret; } /************************************************************* rLen: 1 frame data length rData: read 1 frame data length 1 frame data length=package head + 1byte wlwn+wLen = 2+1+wLen ****************************************************************/ //static int LvdsMcuRead(unsigned char rLen,unsigned char *rData) static int LvdsMcuRead(int rLen,unsigned char *rData) { struct SOCTOR78I2C_data *pata=i2c_get_clientdata(i2c_connect_client); struct i2c_msg msgs[1]; unsigned char ReadTPAckData[20]; unsigned char i=0; unsigned int ret=0; printk("LvdsMcuRead()::rLen=%d,i2c_connect_client->addr=0x%x\n",rLen,i2c_connect_client->addr); msgs[0].flags = I2C_M_RD; msgs[0].addr = pata->SOCTOR78I2C_client->addr; msgs[0].len = rLen; msgs[0].buf = &ReadTPAckData[0]; ret = i2c_transfer(pata->SOCTOR78I2C_client->adapter, msgs,1); if(ret < 0){ printk("I2cToRt87::i2c Read write error ret=%d\n",ret); } for(i=0;i<rLen;i++){ //printk("I2cToRt87::ReadTPAckData[%d]=0x%x\n",i,ReadTPAckData[i]); *(rData+i)=ReadTPAckData[i]; } return ret; } int Lvdsmcu_Resettp(void) { unsigned char wTempdata[10]; unsigned char ret=0; wTempdata[0]=TOUCHPANEL_RESET[0]; wTempdata[1]=TOUCHPANEL_RESET[1]; wTempdata[2]=TOUCHPANEL_RESET[2]; ret=LvdsMcuWrite(wTempdata[0], &wTempdata[0]); if(ret<0){ printk("LvdsMcuWrite()::touchpannel reset error ret=%d\n",ret); return ret; } printk("LvdsMcuWrite()::touchpannel reset ok ret=%d\n",ret); return ret; } EXPORT_SYMBOL(Lvdsmcu_Resettp); int SocConnect_Rt87Mcu(void) { unsigned char i=0,ret=0; unsigned char ReadR17Data[10]; unsigned char WriteData[10]; WriteData[0]=GET_COMMUNICATIONDET[0]; WriteData[1]=GET_COMMUNICATIONDET[1]; WriteData[2]=GET_COMMUNICATIONDET[2]; ret=LvdsMcuWrite(WriteData[0], &WriteData[0]); if(ret<0){ printk("LvdsMcuWrite()::touchpannel reset error ret=%d\n",ret); return ret; } printk("LvdsMcuWrite()::touchpannel reset ok ret=%d\n",ret); msleep(30); ret=LvdsMcuRead(9,&ReadR17Data[0]); //read 9 byte if(ret<0){ printk("LvdsMcuRead()::touchpannel reset ACK error ret=%d\n",ret); return ret; } for(i=0;i<9;i++) printk("I2cToRt87::*(rData+%d)=0x%x\n",i,ReadR17Data[i]); return ret; } EXPORT_SYMBOL(SocConnect_Rt87Mcu); static int __devinit soctor78_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret=0; struct SOCTOR78I2C_data *ts_pdata; //struct i2c_adapter *adapter; //struct i2c_msg msgs[1]; //unsigned char ReadR17Data[10]; //unsigned char WriteData[10]; //unsigned char PwmData[2]; client->addr=SOCTOR78I2C_ADDR; //printk("soctor78_probe::client=0x%x\n",*client); i2c_connect_client = client; if(!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE|I2C_FUNC_SMBUS_BYTE_DATA)){ printk("[mcui2c]:i2c_check_functionality failed \n"); return -1; } printk("[soctor78]:%s\n",__FUNCTION__); ts_pdata = kzalloc(sizeof(struct SOCTOR78I2C_data), GFP_KERNEL); if (!ts_pdata) return -ENOMEM; ts_pdata->SOCTOR78I2C_client=client; i2c_set_clientdata(client,ts_pdata); SOCTOR78I2C_i2c = ts_pdata; SOCTOR78I2C_i2c->SOCTOR78I2C_client =client; SOCTOR78I2C_i2c->SOCTOR78I2C_client->adapter=client->adapter; /*********************************************************/ / //add soc to R87 mcu connect tes dect /* ret= SocConnect_Rt87Mcu(); if(ret < 0){ printk("SocConnect_Rt87Mcu failed!\n"); return -1; } msleep(20); */ return 0; } static int soctor78_remove(struct i2c_client *client) { int ret=0; struct mcui2c *pdata=i2c_get_clientdata(client); i2c_set_clientdata(client,NULL); kfree(pdata); return ret; } //I2C devie id static const struct i2c_device_id soctor78_id[]={ {SOCTOR78I2C_NAME,0}, { } }; MODULE_DEVICE_TABLE(i2c,soctor78_id); static struct i2c_driver soctor78_driver={ .driver={ .name = SOCTOR78I2C_NAME, .owner = THIS_MODULE, }, .probe = soctor78_probe, .remove = __devexit_p(soctor78_remove), .id_table = soctor78_id, }; /****************Analysis of communication protocol************************/ /*************************soc to mcu file system interface *******************/ static void soctomcu_lock_init(void) { /* init lock */ spin_lock_init(&mcu_lock); } static void soctomcu_lock(void) { spin_lock(&mcu_lock); } static void soctomcu_unlock(void) { spin_unlock(&mcu_lock); } static int soctomcu_open(struct inode* inode, struct file* filep) { printk("<semisky><soctomcu open>soctomcu_open++\n"); if (soctomcuopen) { printk(KERN_DEBUG "device_open() - Returning EBUSY. \ Device already open... \n"); return -EBUSY; } soctomcu_lock(); soctomcuopen++; soctomcu_unlock(); try_module_get(THIS_MODULE); return 0; } static int soctomcu_close(struct inode *inode, struct file *filep) { printk("<semisky><soctomcu close>soctomcu_close++\n"); soctomcu_lock(); soctomcuopen--; soctomcu_unlock(); module_put(THIS_MODULE); return 0; } static void printFrame(soctomcu_frame * frame) { int index; return ; for(index = 0; index < frame->len; index++) { pr_info("<semisky> soctomcu_package[%d]=0xx\n",index,frame->buf[index]); } } /***************************************************************/ static ssize_t socto_lvdsmcu_read(struct file *filp, char __user *buf, size_t count,loff_t *f_pos) { soctomcu_frame mcu_read_pkg; int i; printk("<semisky><mcu read>soctomcu_read++\n"); memset(&mcu_read_pkg, 0, sizeof(soctomcu_frame)); mcu_read_pkg.len=count; soctomcu_lock(); LvdsMcuRead(mcu_read_pkg.len,&mcu_read_pkg.buf[0]); soctomcu_unlock(); printFrame(&mcu_read_pkg); if(copy_to_user((unsigned char *)buf, &mcu_read_pkg.buf[0], count)){ printk("<semisky><mcu_udpate>SOCTOMCU_READ_PACKAGE, copy fail\n"); return -1; } printk("<semisky><mcu_udpate>SOCTOMCU_READ_PACKAGE ok\n"); return 0; } /***************************************************************/ static ssize_t socto_lvdsmcu_write(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { soctomcu_frame soctomcu_write_pkg; unsigned char soctomcu_cmd ; int i=0; printk("<semisky><soctomcu write>soctomcu_write++\n"); memset(&soctomcu_write_pkg, 0, sizeof(soctomcu_frame)); if (copy_from_user(&soctomcu_write_pkg.buf[0], (unsigned char*)buf, count)) { printk("<semisky><SOCTOMCU_WRITE>write farme buff error\n"); } soctomcu_write_pkg.len=count; for(i=0;i<soctomcu_write_pkg.len;i++) printk("<soctomcu write>soctomcu_write_pkg.buf[%d]=0x%x\n",i,soctomcu_write_pkg.buf[i]); soctomcu_cmd = soctomcu_write_pkg.buf[2]; printk("%s, soctomcu_cmd = 0x%x,soctomcu_write_pkg.len=%d\n",__FUNCTION__,soctomcu_cmd,soctomcu_write_pkg.len); soctomcu_lock(); LvdsMcuWrite(soctomcu_write_pkg.len, &soctomcu_write_pkg.buf[0]); soctomcu_unlock(); return 0; } /***************************************************************/ static const struct file_operations soctomcu_fops = { .owner = THIS_MODULE, .open = soctomcu_open, .release = soctomcu_close, .read = socto_lvdsmcu_read, .write = socto_lvdsmcu_write, }; /********************************END*************************/ static int __init soctor78_init(void) { //struct goodix_ts_platform_data *pdata; //struct SOCTOR78I2C_data *pdata; struct i2c_board_info info; struct i2c_adapter *adapter; struct i2c_client *client; int ret=0; printk("%s\n",__FUNCTION__); /********************************creat char device node*******************/ /* init access lock */ soctomcu_lock_init(); soctomcuopen = 0; //printk("<semisky><soctomcu >soctomcu_init++\n"); soctomcu_major = register_chrdev(0, SOCTOMCU_DEVICE_NAME, &soctomcu_fops); if(soctomcu_major < 0){ unregister_chrdev(soctomcu_major, SOCTOMCU_DEVICE_NAME); pr_info("<semisky><soctomcu>soctomcu register_chrdev fail!\n"); ret =soctomcu_major; } //pr_info("<semisky><soctomcu>register_chrdev success!\n"); soctomcu_class = class_create(THIS_MODULE, SOCTOMCU_DEVICE_NAME); if (IS_ERR(soctomcu_class)) { class_destroy(soctomcu_class); printk(KERN_ERR "<semisky><soctomcu>Error creating class.\n"); ret = -1; } soctomcu_device = device_create(soctomcu_class, NULL, MKDEV(soctomcu_major, 0), NULL, SOCTOMCU_DEVICE_NAME); if (IS_ERR(soctomcu_device)) { device_destroy(soctomcu_class, MKDEV(soctomcu_major, 0)); printk(KERN_ERR "<semisky><soctomcu>Error creating class device.\n"); ret = -1; } memset(&info, 0, sizeof(struct i2c_board_info)); info.addr = SOCTOR78I2C_ADDR; strlcpy(info.type, "SocToR78_I2c", I2C_NAME_SIZE); adapter = i2c_get_adapter(0); if (!adapter) { printk(KERN_ERR "Can't get i2c adapter 0\n"); //kfree(pdata); ret = -ENODEV; goto exit; } client = i2c_new_device(adapter, &info); //printk("i2c_new_device::client=0x%x\n",*client); i2c_put_adapter(adapter); if (!client) { printk(KERN_ERR "Can't add i2c device at 0x%x\n", (unsigned int)info.addr); //kfree(pdata); ret = -ENOMEM; goto exit; } printk("soctor78 driver installing..\n"); return i2c_add_driver(&soctor78_driver); exit: return ret; } static void __exit soctor78_exit(void) { printk("%s\n",__FUNCTION__); i2c_del_driver(&soctor78_driver); i2c_unregister_device(i2c_connect_client); /*************************************************/ /*unregister_chrdev_region(MKDEV(SOCTOMCU_MAJOR,SOCTOMCU_MINOR),10); cdev_del(soctomcudev); device_destroy(soctomcu_class, soctomcu_dev); class_destroy(soctomcu_class); */ device_destroy(soctomcu_class, MKDEV(soctomcu_major, 0)); class_destroy(soctomcu_class); unregister_chrdev(soctomcu_major, SOCTOMCU_DEVICE_NAME); /**************************************************/ } module_init(soctor78_init); module_exit(soctor78_exit); MODULE_AUTHOR("czwyle"); MODULE_DESCRIPTION("Driver for soctor78 I2C devices"); MODULE_LICENSE("GPL");