设备树
1、设备树IO修改
pinctrl_i2c1 就是 I2C1 的 IO 节点,这里将 UART4_TXD 和 UART4_RXD 这两个 IO 分别
复用为 I2C1_SCL 和 I2C1_SDA,电气属性都设置为 0x4001b8b0。
2、在 i2c1 节点追加子节点
设置完成后,拷贝设备树到linux内核
sudo cp arch/arm/boot/dts/imx6ull-alientek-emmc.dtb /home/sjh/linux/tftpboot/ -f
3、查看设备树是否修改成功
重启开发板
/sys/bus/i2c/devices 目录下存放着所有 I2C 设备,如果设备树修改正确的话,会在
/sys/bus/i2c/devices 目录下看到一个名为“0-005a”的子目录
0-005a 就是MLX90614设备目录
ls /sys/bus/platform/devices/ 查看设备名
ls /sys/bus/platform/drivers/ 查看驱动名
驱动程序编写
驱动代码
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/i2c.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include "MLX90614reg.h"
#define MLX90614_CNT 1
#define MLX90614_NAME "MLX90614"
struct MLX90614_dev{
dev_t devid; /* 设备号 */
struct cdev cdev; /* cdev */
struct class *class; /* 类 */
struct device *device; /* 设备 */
struct device_node *nd; /* 设备节点 */
int major; /* 主设备号 */
void *private_data; /* 私有数据 */
float temp; /* 温度 */
unsigned int t1;
};
static struct MLX90614_dev MLX90614dev;
//============================================================================//
static const unsigned char crc_table[] = {
0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31,
0x24, 0x23, 0x2a, 0x2d, 0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65,
0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d, 0xe0, 0xe7, 0xee, 0xe9,
0xfc, 0xfb, 0xf2, 0xf5, 0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd,
0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85, 0xa8, 0xaf, 0xa6, 0xa1,
0xb4, 0xb3, 0xba, 0xbd, 0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2,
0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea, 0xb7, 0xb0, 0xb9, 0xbe,
0xab, 0xac, 0xa5, 0xa2, 0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a,
0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32, 0x1f, 0x18, 0x11, 0x16,
0x03, 0x04, 0x0d, 0x0a, 0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42,
0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a, 0x89, 0x8e, 0x87, 0x80,
0x95, 0x92, 0x9b, 0x9c, 0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4,
0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec, 0xc1, 0xc6, 0xcf, 0xc8,
0xdd, 0xda, 0xd3, 0xd4, 0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c,
0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44, 0x19, 0x1e, 0x17, 0x10,
0x05, 0x02, 0x0b, 0x0c, 0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34,
0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b, 0x76, 0x71, 0x78, 0x7f,
0x6a, 0x6d, 0x64, 0x63, 0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b,
0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13, 0xae, 0xa9, 0xa0, 0xa7,
0xb2, 0xb5, 0xbc, 0xbb, 0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83,
0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb, 0xe6, 0xe1, 0xe8, 0xef,
0xfa, 0xfd, 0xf4, 0xf3
};
unsigned char CRC8_Calc (unsigned char *p, unsigned char len)
{
unsigned int i;
unsigned int crc = 0x0;
while (len--) {
i = (crc ^ *p++) & 0xFF;
crc = (crc_table[i] ^ (crc << 8)) & 0xFF;
}
return (crc & 0xFF);
}
static int MLX90614_read_regs(struct MLX90614_dev *dev,u8 reg,void *val,int len)
{
struct i2c_client *client = (struct i2c_client *)dev->private_data;
int ret;
struct i2c_msg msg[2];
msg[0].addr = (client->addr)<<1;
msg[0].flags = 0;
msg[0].buf = ®
msg[0].len = 1;
msg[1].addr = (client->addr)<<1;
msg[1].flags = I2C_M_RD;
msg[1].buf = val;
msg[1].len = len;
ret = i2c_transfer(client->adapter, msg, 2);
if(ret == 2) {
ret = 0;
} else {
printk("i2c rd failed=%d reg=%06x len=%d\n",ret, reg, len);
ret = -EREMOTEIO;
}
return ret;
}
static unsigned char * MLX90614_read_reg(struct MLX90614_dev *dev, u8 reg)
{
u8 data[3];
u8 *p=NULL;
// MLX90614_read_regs(dev, reg, data, 3);
// p = data;
// return p;
#if 0
struct i2c_client *client = (struct i2c_client *)dev->private_data;
return i2c_smbus_read_byte_data(client, reg);
#endif
/*连续读函数*/
struct i2c_client *client = (struct i2c_client *)dev->private_data;
i2c_smbus_read_i2c_block_data(client,reg,3,data);
p = data;
return p;
}
void MLX90614_readdata(struct MLX90614_dev *dev)
{
unsigned char ValBuf[6] = {0};
unsigned char prcRegVal = 0;
unsigned char *save;
ValBuf[0] = MLX90614_ADDR << 1;
ValBuf[1] = MLX90614_TOBJ1;
ValBuf[2] = (MLX90614_ADDR << 1) | 0x01;
save = MLX90614_read_reg(dev, MLX90614_TOBJ1);
// save[0] = MLX90614_read_reg(dev, MLX90614_TOBJ1);
// save[1] = MLX90614_read_reg(dev, MLX90614_TOBJ1);
// save[2] = MLX90614_read_reg(dev, MLX90614_TOBJ1);
ValBuf[3] = save[0];
ValBuf[4] = save[1];
ValBuf[5] = save[2];
//printk("save : %x %x %x \r\n",save[0],save[1],save[2]);
prcRegVal = CRC8_Calc(ValBuf,5);
if(prcRegVal == ValBuf[5])
dev->t1 = (ValBuf[4] << 8) + ValBuf[3];
//printk("dev->t1 = %d\r\n",dev->t1);
}
static int MLX90614_open(struct inode *inode,struct file *filp)
{
filp->private_data = &MLX90614dev;
printk("MLX90614_open\r\n");
return 0;
}
static ssize_t MLX90614_read(struct file *filp,char __user *buf,size_t cnt,loff_t *off)
{
unsigned int test;
long err = 0;
struct MLX90614_dev *dev = (struct MLX90614_dev *)filp->private_data;
MLX90614_readdata(dev);
test = dev->t1;
err = copy_to_user(buf,&test,sizeof(test));
return 0;
}
static int MLX90614_release(struct inode *inode,struct file *filp)
{
printk("MLX90614_release\r\n");
return 0;
}
static const struct file_operations MLX90614_ops = {
.owner = THIS_MODULE,
.open = MLX90614_open,
.read = MLX90614_read,
.release = MLX90614_release,
};
static int MLX90614_probe(struct i2c_client *client,const struct i2c_device_id *id)
{
printk("MLX90614_probe\r\n");
/*构建设备号*/
if(MLX90614dev.major){
MLX90614dev.devid = MKDEV(MLX90614dev.major,0);
register_chrdev_region(MLX90614dev.devid,MLX90614_CNT,MLX90614_NAME);
}else
{
alloc_chrdev_region(&MLX90614dev.devid,0,MLX90614_CNT,MLX90614_NAME);
MLX90614dev.major = MAJOR(MLX90614dev.devid);
}
/*注册设备*/
cdev_init(&MLX90614dev.cdev,&MLX90614_ops);
cdev_add(&MLX90614dev.cdev,MLX90614dev.devid,MLX90614_CNT);
/*创建类*/
MLX90614dev.class = class_create(THIS_MODULE,MLX90614_NAME);
if(IS_ERR(MLX90614dev.class)){
return PTR_ERR(MLX90614dev.class);
}
/*创建设备*/
MLX90614dev.device = device_create(MLX90614dev.class,NULL,MLX90614dev.devid,NULL,MLX90614_NAME);
if(IS_ERR(MLX90614dev.device)){
return PTR_ERR(MLX90614dev.device);
}
MLX90614dev.private_data =client;
return 0;
}
static int MLX90614_remove(struct i2c_client *client)
{
printk("MLX90614_remove\r\n");
/* 删除设备 */
cdev_del(&MLX90614dev.cdev);
unregister_chrdev_region(MLX90614dev.devid, MLX90614_CNT);
/* 注销掉类和设备 */
device_destroy(MLX90614dev.class, MLX90614dev.devid);
class_destroy(MLX90614dev.class);
return 0;
}
/* 传统匹配方式ID列表 */
static const struct i2c_device_id MLX90614_id[] = {
{"alientek,MLX90614", 0},
{}
};
static const struct of_device_id MLX90614_of_math[]={
{ .compatible = "alientek,MLX90614"},
{}
};
/*iac驱动结构体*/
static struct i2c_driver MLX90614_driver = {
.probe = MLX90614_probe,
.remove = MLX90614_remove,
.driver = {
.owner = THIS_MODULE,
.name = "MLX90614",
.of_match_table = MLX90614_of_math,
},
.id_table = MLX90614_id,
};
/*驱动入口函数*/
static int __init MLX90614_init(void)
{
int ret = 0;
ret = i2c_add_driver(&MLX90614_driver);
return ret;
}
/*驱动出口函数*/
static void __exit MLX90614_exit(void)
{
i2c_del_driver(&MLX90614_driver);
}
module_init(MLX90614_init);
module_exit(MLX90614_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("sjh");
应用代码
#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "sys/ioctl.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
#include <poll.h>
#include <sys/select.h>
#include <sys/time.h>
#include <signal.h>
#include <fcntl.h>
/*
* @description : main主程序
* @param - argc : argv数组元素个数
* @param - argv : 具体参数
* @return : 0 成功;其他 失败
*/
int main(int argc, char *argv[])
{
int fd;
char *filename;
int ret = 0;
unsigned int test;
float read_dat;
if (argc != 2) {
printf("Error Usage!\r\n");
return -1;
}
filename = argv[1];
fd = open(filename, O_RDWR);
if(fd < 0) {
printf("can't open file %s\r\n", filename);
return -1;
}
printf("Run!\r\n");
while (1) {
ret = read(fd, &test, sizeof(test));
if(ret == 0) { /* 数据读取成功 */
read_dat = (test * 0.02) - 273.15;;
printf("Temp = %.2f摄氏度\r\n",read_dat);
}
usleep(200000); /*100ms */
}
close(fd); /* 关闭文件 */
return 0;
}
结果截图