Linux I2C总线(二)I2C设备驱动编写方法

copy from :https://blog.csdn.net/weixin_42462202/article/details/100083033

文章目录
Linux I2C总线(二)I2C设备驱动编写方法
一、I2C驱动的注册
二、I2C设备的注册
2.1 静态注册
2.2 动态注册
2.3 在用户空间注册
三、I2C数据传输
四、I2C驱动模板
一、I2C驱动的注册
1.设置I2C驱动

static const struct i2c_device_id my_i2c_dev_id[] = {
{ "my_i2c_dev", 0}, /* 设备名字 */
{ }
};

static struct i2c_driver my_i2c_drv = {
.driver = {
.name = "no", /* 这个名字不重要 */
.owner = THIS_MODULE,
},
.probe = my_i2c_drv_probe, /* 当匹配到i2c设备时调用 */
.remove = my_i2c_drv_remove, /* 当卸载i2c设备或驱动时调用 */
.id_table = my_i2c_dev_id, /* 这个结构体中的名字很重要 */
};

其中的my_i2c_dev_id非常重要,数组元素中的名称指明了支持的I2C设备

要定义号probe函数和remove函数,注册时发现有设备和驱动匹配,probe函数会被调用,在卸载匹配的驱动或者设备的时候,remove函数会被调用

2.注册I2C驱动

通过i2c_add_driver来注册一个I2C驱动

static int __init my_i2c_drv_init(void)
{

i2c_add_driver(&my_i2c_drv_drv);

return 0;
}

二、I2C设备的注册
注册I2C设备有多种方法,下面介绍三种

2.1 静态注册
静态注册表示只可以在内核启动时就讲i2c设备注册进内核

定义一个i2c_board_info对象

static struct i2c_board_info my_i2c_dev_info = {
I2C_BOARD_INFO("my_i2c_dev", 0x2d), //名字,设备地址
};

通过i2c_register_board_info注册

/*
* busnum:哪一条总线,也就是选择哪一个i2c控制器
* info:i2c设备信息数组
* n:数组有几项
*/
i2c_register_board_info(int busnum, struct i2c_board_info const * info, unsigned n);

2.2 动态注册
动态注册可以在内核运行期间注册,也就是可以应用在加载驱动模块中

定义一个i2c_board_info对象

static struct i2c_board_info my_i2c_dev_info = {
I2C_BOARD_INFO("my_i2c_dev", 0x2d), //名字,设备地址
};

通过i2c_new_device来动态注册

/*
* adap:指定i2c设备器,以后访问设备的时候,使用过哪一个设备器(i2c主机控制器)去访问
* info:指定i2c设备信息
*/
struct i2c_client *
i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info);

2.3 在用户空间注册
注册设备

# echo my_i2c_dev 0x55 > sys/devices/platform/s3c2440-i2c.0/i2c-0/new_device
1
注销设备

echo 0x55 > sys/devices/platform/s3c2440-i2c.0/i2c-0/delete_device
1
三、I2C数据传输
I2C数据传输通过i2c_transfer

/*
* adap:i2c适配器
* msgs:消息数据
* num:数组的个数
*/
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)

i2c_msg的定义如下

struct i2c_msg {
__u16 addr; //从设备地址
__u16 flags; //读或写
__u16 len; //消息的长度
__u8 *buf; //消息
};

例如要发送下列的时序

/* 定义 i2c_msg 结构体 */
struct i2c_msg msg[2];

char val[10]

/* 填充msg */
msg[0].addr = my_i2c_client->addr; /* 这个client在probe函数中得到的 */
msg[0].flags = 0; /* 0表示写,1表示读 */
msg[0].buf = 0x80; /* 写:要发送的数据地址,读:读取到的数据存放的地址 */
msg[0].len = 1; /* 想要传输的字节数 */

/* 填充msg */
msg[1].addr = my_i2c_client->addr; /* 这个client在probe函数中得到的 */
msg[1].flags = 1; /* 1表示读 */
msg[1].buf = val; /* 读到的数据存在这里 */
msg[1].len = 4; /* 想要读取的字节数 */


/* 传输数据 */
i2c_transfer(my_i2c_client->adapter, msg, 2); /* 有两个msg */

四、I2C驱动模板
I2C设备

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/slab.h>

static struct i2c_board_info my_i2c_dev_info = {
I2C_BOARD_INFO("my_i2c_dev", 0x50), /* 这个名字和地址很重要 */
};

static struct i2c_client *my_i2c_client;

static int i2c_dev_init(void)
{
struct i2c_adapter *i2c_adap;

i2c_adap = i2c_get_adapter(0); /* 得到i2c设备器,i2c设备在哪条总线上 */
my_i2c_client = i2c_new_device(i2c_adap, &my_i2c_dev_info);
i2c_put_adapter(i2c_adap);

return 0;
}

static void i2c_dev_exit(void)
{
i2c_unregister_device(my_i2c_client);
}

module_init(i2c_dev_init);
module_exit(i2c_dev_exit);
MODULE_LICENSE("GPL");

I2C驱动

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/earlysuspend.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/ioc4.h>
#include <linux/io.h>

#include <linux/proc_fs.h>

#include <mach/gpio.h>
#include <mach/hardware.h>
#include <plat/gpio-cfg.h>
#include <plat/irqs.h>


static struct i2c_client *my_i2c_client;

static const struct i2c_device_id my_i2c_dev_id[] = {
{ "my_i2c_dev", 0 },
{ }
};

static int my_i2c_drv_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
/* 记录下i2c设备client */
my_i2c_client = client;

/* 在这里注册字符设备,创建设备节点 */

/* 这里为了简单,只是打印一句话而已 */
printk("my_i2c_ddrv_probe\n");

return 0;
}

static int my_i2c_drv_remove(struct i2c_client *client)
{
/* 在这里卸载字符设备 */

/* 这里为了简单,只打印一句话 */
printk("my_i2c_dev_remove\n")

return 0;
}

static struct i2c_driver my_i2c_drv = {
.driver = {
.name = "jt_ts",
.owner = THIS_MODULE,
},
.probe = my_i2c_drv_probe,
.remove = my_i2c_drv_remove,
.id_table = my_i2c_dev_id,
};

static int __init my_i2c_drv_init(void)
{

i2c_add_driver(&my_i2c_drv);

return 0;
}

static void __exit my_i2c_drv_exit(void)
{

i2c_del_driver(&my_i2c_drv);

return;
}

module_init(my_i2c_drv_init);
module_exit(my_i2c_drv_exit);

MODULE_LICENSE("GPL");
————————————————
版权声明:本文为CSDN博主「JT同学」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42462202/article/details/100083033

猜你喜欢

转载自www.cnblogs.com/Oude/p/12441078.html