I2C设备驱动之字符设备简写

最近有机会需要写一个 挂载在I2C总线的I2C设备驱动,外设芯片是MCP23017 IO扩展芯片,测试是否可以通信成功,以下是部分代码以及调试的一些注意项:

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/ioctl.h>
#include <linux/mm.h>
#include <asm/uaccess.h>
#include <linux/blkdev.h>
 
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/slab.h>
#include <linux/string.h>

#include <linux/major.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/seq_file.h>

#include <linux/kobject.h>
#include <linux/kobj_map.h>
#include <linux/cdev.h>
#include <linux/mutex.h>
#include <linux/backing-dev.h>
#include <linux/tty.h> 
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/hrtimer.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/async.h>
#include <linux/irq.h>
#include <linux/workqueue.h>
#include <linux/proc_fs.h>
#include <linux/input/mt.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/device.h>

#include <linux/MCP23017.h> 

int CDRIVER_MAJOR=0;
int CDRIVER_MINOR=0;
int count=1;
#define CDRIVER_NAME "simple_chrdev"
struct cdev *simple_cdev;
dev_t simple_dev;
static struct device *dev;
static struct class *simple_class;

static struct i2c_client *mcp23017_client = NULL;
/*********************************************************************************************************/
int mcp_iic_addr = 0x24;

static int mcp23017_i2c_write( struct i2c_client* client,uint8_t reg,uint8_t data)  
{  
    unsigned char buffer[2];  
    int ret;

    buffer[0] = reg;  
    buffer[1] = data;  
	
	struct i2c_msg msgs[] = {
		{
			 .addr = mcp_iic_addr,
			 .flags = 0,
			// .len = writelen,
			.len = sizeof(buffer),
			 .buf = buffer,
		 },
	};
	client->addr=mcp_iic_addr;
	ret = i2c_transfer(client->adapter, msgs, 1);
	if (ret < 0)
	{
		dev_err(&client->dev, "%s: i2c write error.\n", __func__);
		printk("i2c write error\n");
	}

    return 0;  
} 


static int mcp23017_i2c_read( struct i2c_client* client,unsigned char reg,uint8_t *data)  
{  
	int ret;
	struct i2c_msg msgs[] = {
			{
				 .addr = mcp_iic_addr,
				 .flags = 0,
				// .len = 1,
				 .len = sizeof(reg),
				 .buf = &reg,// 寄存器地址
			 },
			{
				 .addr = mcp_iic_addr,
				// .flags = I2C_M_RD,0x01
				 .flags = I2C_M_RD,
				 .len = sizeof(data),
				 .buf = data,// 寄存器的值
			 },
		};

		ret = i2c_transfer(client->adapter, msgs, 2);
			if (ret < 0)
			{
				printk("i2c read error\n");
			}
		
	return ret;
		
} 
struct file_operations simple_fops=
{
 .owner=THIS_MODULE,
 //.open=mac_open,
 //.read=mac_read,
};


static int mcp23017_probe(struct i2c_client *client, struct i2c_device_id *id)
{
	int ret;	
	
	 if(CDRIVER_MAJOR!=0)
    {
        simple_dev=MKDEV(CDRIVER_MAJOR,CDRIVER_MINOR);
        ret=register_chrdev_region(simple_dev,count,CDRIVER_NAME);
    }
    else
    {
        /*dynamic assign major*/
        ret=alloc_chrdev_region(&simple_dev,CDRIVER_MINOR,count,CDRIVER_NAME);
        CDRIVER_MAJOR=MAJOR(simple_dev);
    }
	if(ret<0)
    {
        printk(KERN_ERR"cannot get major %d \n",CDRIVER_MAJOR);
        return -1;
    }
	/*register character device driver*/
    simple_cdev=cdev_alloc();
    if(simple_cdev!=NULL)
    {
        cdev_init(simple_cdev,&simple_fops);
        simple_cdev->ops=&simple_fops;
        simple_cdev->owner=THIS_MODULE;
        if(cdev_add(simple_cdev,simple_dev,count)!=0)
        {
            printk(KERN_NOTICE "something wrong when adding simple_cdev!\n");
        }
        else
        {
            printk("success adding simple_cdev!\n");
        }
    }
    else
    {
        printk(KERN_ERR "register simple_dev error!\n");
        return -1;
    }
    simple_class = class_create(THIS_MODULE, "simple");
     
    if (IS_ERR(simple_class))
    {
        printk( KERN_DEBUG "class_create error\n" );
        return -1;
    }
    printk(KERN_ERR "devno is %d \n",simple_dev);

    dev=device_create(simple_class, NULL, simple_dev,NULL,"cdev_mhr");
    mcp23017_client = client;
}


static const struct i2c_device_id mcp23017_id[] = {
	{"mcp23017", 0},
	{}
};

MODULE_DEVICE_TABLE(i2c, mcp23017_id);

static const struct of_device_id of_rk_mcp23017_match[] = {
	{.compatible = "3q,mcp23017" },
};

static struct i2c_driver mcp23017_drv = { 
    .driver     = { 
        .name   = "mcp23017",
        .owner  = THIS_MODULE,
        .of_match_table = of_match_ptr(of_rk_mcp23017_match),
    },  
    .probe      = mcp23017_probe,
	.id_table       = mcp23017_id,
};

static int mcp23017_init(void)
{
    i2c_add_driver(&mcp23017_drv);
    return 0;
}

static void mcp23017_exit(void)
{
    i2c_del_driver(&mcp23017_drv);
	
   device_destroy(simple_class, simple_dev);
    class_destroy(simple_class);
    cdev_del(simple_cdev);
    unregister_chrdev_region(simple_dev,count);
}

module_init(mcp23017_init);
module_exit(mcp23017_exit);
MODULE_LICENSE("GPL");

设备树:

&i2c2 {
status = "okay";
	mcp23017@24 {
		compatible = "3q,mcp23017";
		reg = <0x24>;
		status = "okay";
	};
};

注意:设备树中 reg地址是 i2c设备地址(不包括读写位,所以要右移一位),我的硬件设置是A2为1,即0x24

在这里插入图片描述
驱动加载成功后 可以用I2C-tools查看相关信息。i2c-tools相关信息在另一篇博客中。

猜你喜欢

转载自blog.csdn.net/LinuxArmbiggod/article/details/83744674