#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <asm/mach/map.h>
#include <linux/platform_device.h>
#include <asm/io.h>
#include <linux/mod_devicetable.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/timekeeping.h>
static struct cdev dht11_cdev;
static struct class *dht11_class;
struct gpio_desc * dht11_gpio_desc;
static int major;
static unsigned char g_us[40];
static void dht11_reset(void)
{
gpiod_direction_output(dht11_gpio_desc, 1);
}
// 注意!!!!!!
static void dht11_start(void)
{
// 不能使用GPIOD_OUT_HIGH,有问题,字节用0,1
mdelay(30);
gpiod_set_value(dht11_gpio_desc, 0);
mdelay(20);
gpiod_set_value(dht11_gpio_desc, 1);
udelay(40);
gpiod_direction_input(dht11_gpio_desc);
udelay(2);
}
static int dht11_wait_ready(void)
{
int timeout_us = 20000;
/* 等待低电平 */
timeout_us = 200;
while(gpiod_get_value(dht11_gpio_desc) && --timeout_us) {
udelay(1);
}
// 超时
if (!timeout_us) {
printk("----debug1-----\n");
return -1;
}
/* 等待高电平 */
timeout_us = 200;
while(!gpiod_get_value(dht11_gpio_desc) && --timeout_us) {
udelay(1);
}
if (!timeout_us) {
printk("----debug2-----\n");
return -1;
}
/* 等待低电平 */
timeout_us = 200;
while(gpiod_get_value(dht11_gpio_desc) && --timeout_us) {
udelay(1);
}
// 超时
if (!timeout_us) {
printk("----debug3-----\n");
return -1;
}
return 0;
}
static int dht11_read_byte(unsigned char *data)
{
int i = 0;
unsigned char buffer;
int timeout_us = 400;
int high_us = 0;
for (i=0;i<8;i++) {
/* 等待高电平 */
timeout_us = 400;
while(!gpiod_get_value(dht11_gpio_desc) && --timeout_us) {
udelay(1);
}
if (!timeout_us) {
return -1;
}
udelay(40);
if (gpiod_get_value(dht11_gpio_desc)) {
buffer = (buffer << 1) | 1;
/* 等待高电平结束 */
timeout_us = 400;
while(gpiod_get_value(dht11_gpio_desc) && --timeout_us) {
udelay(1);
}
if (!timeout_us) {
return -1;
}
} else {
buffer = (buffer << 1) | 0;
}
}
*data = buffer;
return 0;
}
/* 写法与协议有关 */
static ssize_t dht11_drv_read(struct file * file, char __user * buf, size_t size, loff_t *offset)
{
int i = 0;
unsigned long flags;
unsigned char kernel_buf[5];
u64 pre,last;
if (size !=4 ) {
return -EINVAL;
}
local_irq_save(flags);
pre = ktime_get_boottime_ns();
//for(i=0;i<1000;i++)
// udelay(1);
udelay(40);
last = ktime_get_boottime_ns();
printk("udelay 1000 times use ns: %lld\n", last-pre);
// 1. 发送高脉冲启动DHT11
dht11_reset();
dht11_start();
// 2. 等待DHT11就绪
if (0 != dht11_wait_ready()) {
printk("设备未就绪\n");
local_irq_restore(flags);
return -1;
}
// 3. 读取5个字节
for (i=0;i<5;i++) {
if (dht11_read_byte(&kernel_buf[i]) != 0) {
local_irq_restore(flags);
return -1;
}
}
dht11_reset();
local_irq_restore(flags);
// 4. 根据检验码验证数据
if (kernel_buf[4] != kernel_buf[0] + kernel_buf[1] + kernel_buf[2] + kernel_buf[3]) {
printk("验证错误\n");
local_irq_restore(flags);
return -1;
}
// 5. 返回给用户
size = copy_to_user(buf, kernel_buf, size);
return size;
}
static ssize_t dht11_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
return 0;
}
static int dht11_drv_open(struct inode *node, struct file *file)
{
return 0;
}
static int dht11_drv_close(struct inode *node, struct file *file)
{
return 0;
}
static struct file_operations dht11_opr = {
.open = dht11_drv_open,
.release = dht11_drv_close,
.read = dht11_drv_read,
.write = dht11_drv_write,
};
static int dht11_probe(struct platform_device *pdev)
{
int err;
dev_t devid;
printk("====%s====\n", __FUNCTION__);
// 从设备树获取资源
dht11_gpio_desc = gpiod_get(&pdev->dev, NULL, GPIOD_OUT_HIGH);
//dht11_data_pin = gpiod_get(&pdev->dev, NULL, GPIOD_OUT_HIGH);
if (IS_ERR(dht11_gpio_desc)) {
printk("get gpiod_desc error");
return -1;
}
// 设置/注册cdev
err = alloc_chrdev_region(&devid, 0, 1, "dht11");
major = MAJOR(devid);
cdev_init(&dht11_cdev, &dht11_opr);
cdev_add(&dht11_cdev, devid, 1);
// 建立class
dht11_class = class_create(THIS_MODULE, "dht11_class");
// 建立device
device_create(dht11_class, NULL, MKDEV(major, 0), NULL, "dht11"); // 创建节点/dev/dht11
return 0;
}
static int dht11_remove(struct platform_device *pdev)
{
// 释放class,device
printk("======%s=======\n", __FUNCTION__);
device_destroy(dht11_class, MKDEV(major, 0));
class_destroy(dht11_class);
unregister_chrdev(major, "dht11");
gpiod_put(dht11_gpio_desc);
return 0;
}
static const struct of_device_id dht11_match[] = {
{ .compatible = "fire,dht11" },
{ },
};
struct platform_driver dht11_driver = {
.probe = dht11_probe,
.remove = dht11_remove,
.driver = {
.name = "my_dht11_driver",
.of_match_table = dht11_match,
},
};
// 入口函数
static int dht11_platform_driver_init(void)
{
int ret = 0;
printk("====%s====\n", __FUNCTION__);
ret = platform_driver_register(&dht11_driver); // 注册设备信息
return ret;
}
// 出口函数
static void dht11_platform_driver_exit(void)
{
printk("====%s====\n", __FUNCTION__);
platform_driver_unregister(&dht11_driver); // 注册设备信息
}
module_init(dht11_platform_driver_init);
module_exit(dht11_platform_driver_exit);
MODULE_LICENSE("GPL");