红外模块在很多方面都有应用,比如:测距,避障,报警等,由于我们要利用红外模块实现一个类似报警的功能,所以,在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");
