linux驱动之--I2C子系统

I2C编程框架
1. 入口,出口函数
module_init(at24c02_init)
module_exit(at24c02_exit);
MODULE_LICENSE(“GPL”);
2. 向i2c_code注册i2c设备
static int __init at24c02_init(void)
{
printk(“———%s———-\n”, FUNCTION);
//向i2c_code注册i2c设备
return i2c_add_driver(&at24c02_drv);
}
3. 构建一个i2c设备
static struct i2c_driver at24c02_drv = {
.probe = at24c02_probe,//match匹配后调用probe方法
.remove = at24c02_remove,
.driver = {//设备信息
.owner = THIS_MODULE,
//用于match配对
.name = “at24c02”,
},
//用于I2C driver的probe函数调用
.id_table = e2prom_table,
};

//i2c总线比较特殊,一定要有一个id表
//i2c_device_id用于device与drive配对
struct i2c_device_id e2prom_table[]={
[0]={
.name =”24c02”,
.driver_data =0,
},
[1]={
.name =”24c08”,
.driver_data =0,
},
};
4. 实现probe方法
int at24c02_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
printk(“———%s———-\n”, FUNCTION);
// 编写字符设备框架
int ret;
//用来查看当前适配器是否支持I2C_FUNC_SMBUS_BYTE_DATA| I2C_FUNC_SMBUS_WORD_DATA
ret = i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA| I2C_FUNC_SMBUS_WORD_DATA);
if(!ret)
{
printk(“function is not support\n”);
return -ENODEV;
}
//申请一段地址空间
at24c02_dev = kzalloc(sizeof(struct e2prom_dev), GFP_KERNEL);
if(!at24c02_dev)
{
printk(KERN_ERR “kzalloc error\n”);
return -ENOMEM;
}
at24c02_dev->client = client;
//register_chrdev可获取一个或多个设备编号
//其中参数major如果等于0,则表示采用系统动态分配的主设备号;不为0,则表示静态注册
at24c02_dev->dev_major = register_chrdev(0, “at24c02”, &fops);
if(at24c02_dev->dev_major < 0)
{
printk(KERN_ERR “register_chrdev error\n”);
ret = -ENODEV;
goto err_0;
}
//创建一个设备类
at24c02_dev->cls = class_create(THIS_MODULE, “e2prom”);
if(IS_ERR(at24c02_dev->cls))
{
printk(KERN_ERR “class_create error\n”);
//数据转换
ret = PTR_ERR(at24c02_dev->cls);
goto err_1;

}
//向内核注册一个设备,返回值为注册的主设备号
at24c02_dev->dev    =   device_create(at24c02_dev->cls,NULL,MKDEV(at24c02_dev->dev_major,0),
                NULL, "i2c-e2prom0");
if(IS_ERR(at24c02_dev->dev))
{
    printk(KERN_ERR "class_create error\n");
    ret =  PTR_ERR(at24c02_dev->dev);
    goto err_2;
        }
return 0;

err_3:
device_destroy(at24c02_dev->cls, MKDEV(at24c02_dev->dev_major, 0));
err_2:
class_destroy(at24c02_dev->cls);
err_1:
unregister_chrdev(at24c02_dev->dev_major, “at24c02”);
err_0:
kfree(at24c02_dev);
return ret;
}
5. 自定义设备数据
struct e2prom_dev{
int dev_major;
struct i2c_client *client;
struct class *cls;
struct device *dev;
};
6. 自写读写方法
static int i2c_read_bytes(char *buf, int count)
{
int ret = 0;
//获取client信息
struct i2c_client *client = at24c02_dev->client;
struct i2c_msg msg;// 定义一个临时的数据包
msg.addr = client->addr;// 将从机地址写入数据包
msg.flags |= I2C_M_RD?// 将从机标志并入数据包
msg.len = count;// 将此次发送的数据字节数写入数据包
msg.buf = buf;// 将发送数据指针写入数据包
// 调用平台接口发送数据
ret = i2c_transfer(client->adapter, &msg, 1);
if(ret < 0)
printk(KERN_ERR”i2c_transfer error\n”);
return ret;
}
//构建i2c写数据
static int i2c_write_bytes(char *buf, int count)
{
int ret = 0;
struct i2c_client *client = at24c02_dev->client;
struct i2c_msg msg;

msg.addr = client->addr;
msg.flags = 0,
msg.len = count;
msg.buf = buf;
// 调用平台接口发送数据
ret = i2c_transfer(client->adapter, &msg, 1);
if(ret < 0)
    printk(KERN_ERR"i2c_transfer error\n");
return ret;

}
7. 重写操作函数
static const struct file_operations fops = {
.owner = THIS_MODULE,
.open = at24c02_open,
.read = at24c02_read,
.write = at24c02_write,
.release = at24c02_close,
};
8. 实现操作函数
static int at24c02_open(struct inode *inode, struct file *file)
{
return 0;
}
//写数据
static ssize_t at24c02_write(struct file *file, const char __user *buf, size_t size, loff_t *opps)
{
int ret=0;
char *tmp;
tmp =kmalloc(size,GFP_KERNEL);
if(tmp==NULL)
{
printk(“mallo failed!\n”);
return -ENOMEM;
}
//从用户拷贝数据到内核
ret =copy_from_user(tmp,buf,size);
if(ret)
{
printk(“copy data faile!\n”);
ret =-EFAULT;
goto err_0;
}
//写数据到tmp中
ret=i2c_write_bytes(tmp,size);
if(ret < 0){
printk(“write byte failed!\n”);
ret =-EINVAL;
goto err_0;
}
kfree(tmp);
return size;
err_0:
kfree(tmp);
return ret;
}
//读数据
static ssize_t at24c02_read(struct file *file, char __user *buf, size_t size, loff_t *opps)
{
int ret=0;
char *tmp;
tmp =kmalloc(size,GFP_KERNEL);
if(tmp==NULL)
{
printk(“mallco failed!\n”);
return -ENOMEM;
}
//从tmp读数据
ret = i2c_read_bytes(tmp, size);
if(ret < 0)
{
printk(“write byte failed!\n”);
ret =-EINVAL;
goto err_0;
}
//把数据拷贝给buf
ret = copy_to_user(buf, tmp, size);
if(ret)
{
printk(“copy data faile!\n”);
ret =-EFAULT;
goto err_0;
}
kfree(tmp);
return ret ? -EINVAL : size;
err_0:
kfree(tmp);
return ret;
}
//关闭
int at24c02_close(struct inode *inode, struct file *filp)
{
return 0;
}

  1. 移除模块
    int at24c02_remove(struct i2c_client *client)
    {
    printk(“———%s———-\n”, FUNCTION);
    device_destroy(at24c02_dev->cls, MKDEV(at24c02_dev->dev_major, 0));
    class_destroy(at24c02_dev->cls);
    unregister_chrdev(at24c02_dev->dev_major, “at24c02”);
    kfree(at24c02_dev);
    return 0;
    }
  2. 关闭入口函数
    static void __exit at24c02_exit(void)
    {
    printk(“———%s———-\n”, FUNCTION);
    //卸载i2c设备
    i2c_del_driver(&at24c02_drv);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值