最近有机会需要写一个 挂载在I2C总线的I2C设备驱动,外设芯片是MCP23017 IO扩展芯片,测试是否可以通信成功,以下是部分代码以及调试的一些注意项:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
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 = ®,// 寄存器地址
},
{
.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