#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");
人體感應喚醒系統
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.