创建字符设备给文件系统接口并建立I2C与MCU直之间通信驱动

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]=0x%02x\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");
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值