1:linux下的IIC
linux中最重要的思想就是分层思想,一般开发者对接的是中间层也就是接口,linux不关注底层,这个底层一般是内核与厂家联合初始化的。
通过设备树提供IIC信息,然后再提供一些接口
在驱动结构体中:厂商提供IIC的信息,再匹配设备树提供的信息,会自动去匹配对应的设备文件。
2:linux下的IIC的中间层接口
linux下的IIC接口是平台设备总线类型的,需要注册驱动信息,从而匹配设备信息
2.1 接口函数
头文件:
#include "linux/i2c.h"
IIC的驱动的信息注册函数:
int i2c_add_driver(struct i2c_driver *driver)
int i2c_register_driver(struct module *owner, struct i2c_driver *driver);
函数功能:
向内核注册IIC 驱动信息,主要是去匹配设备树的IIC信息。
函数参数:
driver:
注册内核I2C设备信息,主要对应的是入口、出口、匹配信息
struct i2c_driver { //匹配函数 int (*probe)(struct i2c_client *client, const struct i2c_device_id *id); int (*probe_new)(struct i2c_client *client); //注销函数 int (*remove)(struct i2c_client *client); struct device_driver driver { const char *name;//一般填写 const struct of_device_id *of_match_table; //匹配 compatible } const struct i2c_device_id *id_table { char name[I2C_NAME_SIZE]; } }
返回值:
成功返回 0
失败返回 非0
匹配成功后的probe(struct i2c_client * client)
其中的信息结构体:
struct i2c_client { unsigned short addr;//设备树传递过来的从机地址! struct i2c_adapter *adapter;//他就是 IICx 的抽象的内核结构体 //有了他 你就可以任意的操作内核 IIC 了! //有了它你就可以调用 i2c_transfer //做数据的读写收发了! }
函数功能:用于内核层的IIC的读写
函数原型:
int i2c_transfer( struct i2c_adapter *adap, struct i2c_msg *msgs, int num );
函数的参数:
adapt:IIC的抽象结构体
msgs:
struct i2c_msg { __u16 addr; //从机地址 __u16 flags;//标志 : 0/1 -> 写 / 读 __u16 len; //读写的数据长度 __u8 *buf;//读写缓冲区 }
num:有结果msg需要发送。
3:BH1750
3.1: BH1750 介绍

3.2 核心信息
从机地址:
两种从机地址可以选择
默认我们没有接 ADDR: 0100011 = 0x23
工作流程:
设置 BH1750 的工作模式
写入 BH1750 指令 0x11(高分辨率模式 2), 产生停止
等待 180ms->BH1750 就开始以这个模式正常工作
BH1750 不断采集外部光照数据给主机返回
主机每隔 120ms 找从机要一次数据即可
注意返回的数据是 16bit
工作模式:
4:IIC驱动BH1750设备代码示例
//bh1750光照传感器
#include "linux/kernel.h"
#include "linux/module.h"
#include "linux/of.h"
#include "linux/cdev.h"
#include "linux/fs.h"
#include "linux/gpio.h"
#include "linux/of_gpio.h"
#include "linux/device/class.h"
#include "linux/device.h"
#include "linux/platform_device.h"
#include "linux/miscdevice.h"
#include "asm/uaccess.h"
#include "linux/irq.h"
#include "linux/interrupt.h"
#include "linux/sched.h"
#include "linux/wait.h"
#include "linux/i2c.h"
#include "linux/delay.h"
struct i2c_client * bh1750_client;
struct miscdevice *misc;
struct file_operations *fops;
struct i2c_adapter *adap;
int bh1750_open (struct inode * ind, struct file *file)
{
//初始化bh1750发送0X10
// i2c_smbus_write_block_data();
uint8_t cmd =0x10;
struct i2c_msg msgs;
msgs.addr = bh1750_client->addr;//从机地址
msgs.buf = &cmd;
msgs.len =1;
msgs.flags = 0;//代表写入数据
int rem = i2c_transfer(bh1750_client->adapter,&msgs,1);
mdelay(200);//延时200ms
rem =rem;
return 0;
}
int bh1750_close (struct inode * ind, struct file *file)
{
return 0;
}
ssize_t bh1750_read (struct file * fil, char __user * buff, size_t size, loff_t * lof)
{
//读取从机的数据
//返回的数据是16bit的
uint8_t readbuf[2] ={0};
uint16_t value;
struct i2c_msg msgs;
msgs.addr = bh1750_client->addr;
msgs.buf = readbuf;
msgs.len = 2;
msgs.flags = 1;
int rem = i2c_transfer(bh1750_client->adapter,&msgs,1);
value = readbuf[0]<<8 | readbuf[1];
int ret = copy_to_user(buff,&value,2);
ret =0;
rem =rem;
return 0;
}
int bh1750_probel(struct i2c_client *client)
{
printk("检测到信息\r\n");
bh1750_client = client;
// node= dev->dev.of_node;//承接设备树信息
//注册杂项设备
misc = kzalloc(sizeof(struct miscdevice),GFP_KERNEL);
fops = kzalloc(sizeof(struct file_operations),GFP_KERNEL);
fops->open = bh1750_open;
fops->owner = THIS_MODULE;
fops->release = bh1750_close;
fops->read = bh1750_read;
misc->minor = 255;
misc->name = "xyd_bh1750";
misc->fops = fops;
return misc_register(misc);
}
struct of_device_id id_tible={
.compatible = "xydbh1750",//匹配名字
};
struct i2c_driver bh1750_driver = {
.probe_new = bh1750_probel,
.driver = {
.name = "xyd_bh1750",
.of_match_table = &id_tible,
},
};
//加载函数
static int __init bh1750_init(void)
{
//添加设备树
i2c_add_driver(&bh1750_driver);
// platform_driver_register(&bh1750);
return 0;
}
static void __exit bh1750_exit(void)
{
// platform_driver_unregister(&bh1750);
}
module_init(bh1750_init);
module_exit(bh1750_exit);
MODULE_LICENSE("GPL");