红外模块在很多方面都有应用,比如:测距,避障,报警等,由于我们要利用红外模块实现一个类似报警的功能,所以,在android5.1里面添加了如下红外模块驱动。
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/sysfs.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/input.h>
#include <linux/jiffies.h>
#include <linux/mutex.h>
#include <linux/ctype.h>
#include <linux/pm_runtime.h>
#include <linux/device.h>
#include <linux/irq.h>
#include <linux/of_gpio.h>
#include <linux/wait.h>
#include <asm/uaccess.h>
struct doorbell_data{
int enable;
int poll_time; //50 ms
int rx_gpio; //13
int irq;
int distance;
struct mutex data_lock;
bool data_ready;
wait_queue_head_t data_queue;
struct delayed_work cmd_work;
};
static irqreturn_t doorbell_interrupt_handler(int irq, void *ptr){
struct doorbell_data* data = (struct doorbell_data*)ptr;
mutex_lock(&data->data_lock);
data->distance = 1;
mutex_unlock(&data->data_lock);
data-> data_ready = true;
wake_up_interruptible(&data->data_queue);
return IRQ_HANDLED;
}
static void cmd_work_func(struct work_struct* work){
struct doorbell_data* data = container_of(work,struct doorbell_data,cmd_work.work);
if(gpio_get_value(data->rx_gpio)){
data->distance = 0;
}
data->data_ready = true;
wake_up_interruptible(&data->data_queue);
schedule_delayed_work(&data->cmd_work,msecs_to_jiffies(data->poll_time));
}
static int parse_dt(struct platform_device* pdev,struct doorbell_data* data){
int rc;
struct device_node* node = pdev->dev.of_node;
rc = of_property_read_u32(node,"thunder,poll_time",&data->poll_time);
if(rc){
pr_warning("%s you should point time\n",__FUNCTION__);
data->poll_time = 20;
}
data->rx_gpio = of_get_named_gpio(node,"thunder,gpio_rx",0);
if(gpio_is_valid(data->rx_gpio)){
rc = gpio_request(data->rx_gpio,"doorbell_rx_gpio");
if(rc < 0){
pr_err("uanble to request rx gpio\n");
}
rc = gpio_direction_input(data->rx_gpio);
}
if(data->rx_gpio<0){
pr_err("%s,error gpio\n",__FUNCTION__);
return -EINVAL;
}
return 0;
}
static ssize_t doorbell_show_value(struct device *dev,
struct device_attribute* attr,char* buf){
struct doorbell_data* data = dev_get_drvdata(dev);
ssize_t lenth;
wait_event_interruptible(data->data_queue,data->data_ready);
data->data_ready = false;
mutex_lock(&data->data_lock);
lenth = sprintf(buf,"%d\n",data->distance);
printk("%d\n",data->distance);
mutex_unlock(&data->data_lock);
return lenth;
}
static DEVICE_ATTR(value,0644,doorbell_show_value,NULL);
static int doorbell_probe(struct platform_device *pdev){
struct doorbell_data* data;
int result;
data = kmalloc(sizeof(struct doorbell_data),GFP_KERNEL);
if(!data){
pr_err("%s kmalloc error\n",__FUNCTION__);
return -ENOMEM;
}
dev_set_drvdata(&pdev->dev,data);
result = parse_dt(pdev,data);
if(result<0){
pr_err("%s error when parse dt\n",__FUNCTION__);
result = -EINVAL;
goto err_parse_dt;
}
data->irq = gpio_to_irq(data->rx_gpio);
result = request_irq(data->irq,doorbell_interrupt_handler,IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING,"doorbell_int",data);
if(result<0){
pr_err("Unable to request irq\n");
goto err_parse_dt;
}
INIT_DELAYED_WORK(&data->cmd_work,cmd_work_func);
mutex_init(&data->data_lock);
init_waitqueue_head(&data->data_queue);
schedule_delayed_work(&data->cmd_work,msecs_to_jiffies(data->poll_time));
result=sysfs_create_file(&pdev->dev.kobj,&dev_attr_value.attr);
printk("doorbell probe sucess\n");
return 0;
err_parse_dt:
kfree(data);
printk("doorbell probe failed\n");
return result;
}
static int doorbell_remove(struct platform_device *pdev){
return 0;
}
static struct of_device_id doorbell_match_table[] = {
{ .compatible = "thundersoft,doorbell",},
{ },
};
static struct platform_driver doorbell_driver = {
.probe = doorbell_probe,
.remove = doorbell_remove,
.driver = {
.owner = THIS_MODULE,
.name = "doorbell-irda",
.of_match_table = doorbell_match_table,
},
};
module_platform_driver(doorbell_driver);
MODULE_AUTHOR("IRDA");
MODULE_LICENSE("GPL v2");