人體感應喚醒系統

#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/kmemcheck.h>
#include <linux/ctype.h>
#include <linux/delay.h>
#include <linux/idr.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/signal.h>

#include <linux/time.h>
#include <linux/timer.h>

#include <mach/sys_config.h>
#include <mach/gpio.h>
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/input.h>
#include <asm/irq.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
	#include <linux/earlysuspend.h>
#endif

#define SW_GPIO_WAKEUP_SYSTEM

struct sw_gpio{
    struct work_struct irq_work;
    u32 irq_hd;                         /* 中斷句柄     */
    unsigned long trig_type;  /* 中斷觸發方式 */
    struct input_dev *key;
#if defined(CONFIG_HAS_EARLYSUSPEND)
	struct early_suspend gpio_early_suspend;
#endif
};



static irqreturn_t gpio_irq_interrupt(int irq, void *para)
{
	struct sw_gpio *gpio = (struct sw_gpio *)para;

	pr_err("%s,%d\n",__func__,__LINE__);
#ifdef  SW_GPIO_WAKEUP_SYSTEM
    schedule_work(&gpio->irq_work);
#endif

	return IRQ_HANDLED;
}

#ifdef  SW_GPIO_WAKEUP_SYSTEM
static int gpio_create_input_device(struct sw_gpio *gpio)
{
    int ret = 0;

    gpio->key = input_allocate_device();
    if (!gpio->key) {
        pr_err("err: not enough memory for input device\n");
        return -ENOMEM;
    }
	
	printk("%s,%d\n",__func__,__LINE__);
	
    gpio->key->name          = "sw_gpio";
    gpio->key->phys          = "gpio/input0";

    gpio->key->evbit[0] = BIT_MASK(EV_KEY);
    set_bit(KEY_POWER, gpio->key->keybit);

    ret = input_register_device(gpio->key);
    if (ret) {
        pr_err("err: input_register_device failed\n");
        input_free_device(gpio->key);
        return -ENOMEM;
    }

    return 0;
}

static int gpio_free_input_device(struct sw_gpio *gpio)
{
    if(gpio->key){
        input_unregister_device(gpio->key);
        input_free_device(gpio->key);
    }

    return 0;
}

/* wake up system */
static void gpio_wakeup_system(struct sw_gpio *gpio)
{
    pr_err("---------gpio wakeup system----------\n");

    input_report_key(gpio->key, KEY_POWER, 1);
    input_sync(gpio->key);
    msleep(100);
    input_report_key(gpio->key, KEY_POWER, 0);
    input_sync(gpio->key);

    return ;
}
#endif

#ifdef  SW_GPIO_WAKEUP_SYSTEM
static void gpio_irq_work(struct work_struct *data)
{
	struct sw_gpio *gpio = container_of(data, struct sw_gpio, irq_work);
	pr_err("%s,%d\n",__func__,__LINE__);
	gpio_wakeup_system(gpio);

	return;
}
#endif

static void gpio_irq_enable(struct sw_gpio *gpio)
{
	printk("%s,%d\n",__func__,__LINE__);
	enable_irq(gpio->irq_hd);

    return;
}

static void gpio_irq_disable(struct sw_gpio *gpio)
{
	printk("%s,%d\n",__func__,__LINE__);
	disable_irq(gpio->irq_hd);
	
    return;
}

static gpio_register_wake_irq(struct sw_gpio *gpio)
{
	script_item_u val;
	script_item_value_type_e type;
	int ret = 0;
	
	printk("%s,%d\n",__func__,__LINE__);
#ifdef  SW_GPIO_WAKEUP_SYSTEM
    ret = gpio_create_input_device(gpio);
    if(ret != 0){
        pr_err("err: gpio_create_input_device failed\n");
        return -1;
    }

	INIT_WORK(&gpio->irq_work, gpio_irq_work);
#endif	
	type = script_get_item("wakeup_src_para", "wakeup_src_wl", &val);
	if (SCIRPT_ITEM_VALUE_TYPE_PIO != type){
		printk("get wake gpio failed\n");
		return -1;
	}
	
	gpio->irq_hd = gpio_to_irq(val.gpio.gpio);
	ret = request_irq(gpio->irq_hd, gpio_irq_interrupt, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "eken_io_wake", gpio);
	if(IS_ERR_VALUE(ret)){
        pr_err("err: request_irq failed\n");
#ifdef  SW_GPIO_WAKEUP_SYSTEM
        gpio_free_input_device(gpio);
#endif
        return -1;
    }

    gpio_irq_disable(gpio);
	return 0;
}
#ifdef CONFIG_HAS_EARLYSUSPEND
static void eken_io_wake_early_suspend(struct early_suspend *h)
{
	struct sw_gpio *gpio =
		container_of(h, struct sw_gpio, gpio_early_suspend);
	printk("%s,%d\n",__func__,__LINE__);	
	gpio_irq_enable(gpio);
    
	return;
}

static void eken_io_wake_late_resume(struct early_suspend *h)
{
	struct sw_gpio *gpio =
		container_of(h, struct sw_gpio, gpio_early_suspend);
	pr_err("%s,%d\n",__func__,__LINE__);	
	gpio_irq_disable(gpio);
    
	return;
}
#endif

static int __init eken_io_wake_probe(struct platform_device *pdev)
{
	int ret = 0;
	struct sw_gpio *gpio;
	gpio = kzalloc(sizeof(struct sw_gpio), GFP_KERNEL);
	if (!gpio) {
		return -ENOMEM;
	}
	dev_set_drvdata(pdev, gpio);

	printk("%s,%d\n",__func__,__LINE__);
#ifdef CONFIG_HAS_EARLYSUSPEND
	gpio->gpio_early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1;
	gpio->gpio_early_suspend.suspend = eken_io_wake_early_suspend;
	gpio->gpio_early_suspend.resume = eken_io_wake_late_resume;
	register_early_suspend(&gpio->gpio_early_suspend);
#endif
	pr_err("%s,%d,%x\n",__func__,__LINE__,gpio);
	ret = gpio_register_wake_irq(gpio);
	return ret;
}


static int eken_io_wake_suspend(struct platform_device *pdev, pm_message_t message)
{
	printk("%s,%d\n",__func__,__LINE__);
    return 0;
}

static int eken_io_wake_resume(struct platform_device *pdev)
{
	struct sw_gpio *gpio = dev_get_drvdata(pdev);
	pr_err("%s,%d\n",__func__,__LINE__);
	gpio_wakeup_system(gpio);
    return 0;
}

static int eken_io_wake_remove(struct platform_device *pdev)
{
	struct sw_gpio *gpio = dev_get_drvdata(pdev);
	
	if(pdev == NULL){
        pr_err("err: invalid argment\n");
        return -1;
	}

#ifdef CONFIG_HAS_EARLYSUSPEND
	unregister_early_suspend(&gpio->gpio_early_suspend);
#endif
	gpio_irq_disable(gpio);
	cancel_work_sync(&gpio->irq_work);
	return 0;
}


static struct platform_device gpio_device = { 
    .name = "eken_io_wake", 
};

static struct platform_driver eken_io_wake_driver = {
	.driver		= {
		.name	= "eken_io_wake",
		.owner	= THIS_MODULE,
	},

    .probe      = eken_io_wake_probe,
    .remove     = eken_io_wake_remove,
#if defined(CONFIG_PM)
    .suspend    = eken_io_wake_suspend,
    .resume     = eken_io_wake_resume,
#endif 
};

static int __init eken_io_wake_init(void) {
	int ret = 0;
	
	printk("%s,%d\n",__func__,__LINE__);
	ret = platform_device_register(&gpio_device);
	if (ret == 0) {
		ret = platform_driver_register(&eken_io_wake_driver);
	}
	if(ret){
        pr_err("ERR: platform_driver_probe failed\n");
        return -1;
    }
	return 0;
	
}

static void __exit eken_io_wake_exit(void) {
	platform_driver_unregister(&eken_io_wake_driver);
	platform_device_unregister(&gpio_device);
}



module_init(eken_io_wake_init);
module_exit(eken_io_wake_exit);

MODULE_DESCRIPTION("gpio driver");
MODULE_AUTHOR("<span style="color: rgb(215, 223, 234); font-family: 'lucida Grande', Verdana; line-height: 18px; background-color: rgb(53, 75, 102);"></span><[email protected]><span style="color: rgb(215, 223, 234); font-family: 'lucida Grande', Verdana; line-height: 18px; background-color: rgb(53, 75, 102);"></span>");
MODULE_LICENSE("GPL");

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章