blob: 43ba28cbb1dbc750f35a01edf5904507f9c92b0d [file] [log] [blame]
/*******************************************************************************
* Copyright (C) 2009, mbtk Corporation.
*
* File Name: mbtk_GpioWakeUp.c
* File Mark:
* Description:
* Others:
* Version: V1.0
* Author: xxxx
* Date: 2023-07-04
* History 1:
* Date:
* Version:
* Author:
* Modification:
* History 2:
********************************************************************************/
/****************************************************************************
* Include files
****************************************************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/types.h>
#include <linux/suspend.h>
#include <linux/tick.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
//#include <mach/irqs.h>
//#include <uapi/linux/gpio.h>
//#include <linux/soc/sc/pcu.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/pm_wakeup.h>
//#include <linux/soc/sc/drv_idle.h>
#include <linux/sysfs.h>
#include <linux/kobject.h>
#include <linux/input.h>
/****************************************************************************
* Local Macros
****************************************************************************/
#define HAS_WAKE_OUT_PIN 1 // 1: for output pin level when wakeup or sleeping; 0 is disable
#define HAS_WAKE_SOURCE_LOCK 1 //1: for wakelock when wakeup and release when sleeping with the wake gpio level
#define HAL_GPIO_WAKUP_PM 1 // release or lock wakelock when sleep or wakeup
#define WAKEUP_STATE_VALUE 0
#define WAKEUP_KEY KEY_1 //KEY_POWER ,report key code to application
#define CP_WAKE_STATUS 1
#define CP_SLEEP_STATUS 0
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#define GPIO_WAKUP_DEBUG
#ifdef GPIO_WAKUP_DEBUG
#define GPIO_WAKUP_debug(fmt, args...) printk(KERN_INFO "[SLP] " fmt, ##args)
#else
#define GPIO_WAKUP_debug(fmt, args...)
#endif
#define GPIO_WAKUP_STATE "GpioWakeUp_state"
/****************************************************************************
* Local Types
****************************************************************************/
struct mbtkGpioWakeUp_dev
{
struct device *dev;
struct pinctrl *pctrl_wk_int;
struct pinctrl_state *st_gpio;
struct pinctrl_state *st_int;
int wake_state;
int curr_gpio_value;
struct task_struct *wake_int_thread;
spinlock_t wk_lock;
struct semaphore wk_sem;
int wake_ap_gpio;
int wake_me_gpio;
struct gpio_desc *gd;
struct input_dev *input;
int eint_irq;
int GpioWakeUp_irq_state;
int wake_cnt;
int sleep_cnt;
struct wakeup_source *GpioWakeUp_ws;
};
/****************************************************************************
* Global Variables
****************************************************************************/
//static int wakeup_irq_occurs = 0;
struct wakeup_source *GpioWakeUp_wake_lock;
static int GpioWakeUp_init_flag = 0;
static int currState = 1;
/****************************************************************************
* Local Constants
****************************************************************************/
struct mbtkGpioWakeUp_dev g_GpioWakeUp = {0};
/*******************************************************************************
* Function: ApWakeCp int
* Description: ap2cp wake up int thread
* Parameters:
* Input:
*
* Output:
*
* Returns:
*
* Others:
********************************************************************************/
irqreturn_t GpioWakeUp_wkcp_thread_fn(int irq, void *priv)
{
unsigned long flags;
int gpio_value;
struct mbtkGpioWakeUp_dev *GpioWakeUp_dev = (struct mbtkGpioWakeUp_dev *)priv;
disable_irq_nosync(irq);/*jb.qi add for dtr on 20240202*/
gpio_value = 0 ;
//pr_err("%s/L%d\n", __func__, __LINE__);
if(GpioWakeUp_dev->GpioWakeUp_ws){
//gpio_value = gpio_get_value_cansleep(GpioWakeUp_dev->wake_me_gpio) ;
//if(gpio_value == 0)
__pm_wakeup_event(GpioWakeUp_dev->GpioWakeUp_ws, 2000);
}
/*if (pinctrl_select_state(GpioWakeUp_dev->pctrl_wk_int, GpioWakeUp_dev->st_gpio) < 0) {
printk("setting card detect gpio failed\n");
}*/
spin_lock_irqsave(&GpioWakeUp_dev->wk_lock, flags);
gpio_value = gpio_get_value_cansleep(GpioWakeUp_dev->wake_me_gpio) ;
spin_unlock_irqrestore(&GpioWakeUp_dev->wk_lock, flags);
if(gpio_value < 0)
{
printk( "[%s-%d]: gpio get state failed\n",__func__,__LINE__);
}
if(gpio_value != currState)
{
GPIO_WAKUP_debug("interrup handler: gpio%d_value is %d \n",GpioWakeUp_dev->wake_me_gpio,gpio_value);
GpioWakeUp_dev->wake_state = gpio_value;
//input_report_key(GpioWakeUp_dev->input, WAKEUP_KEY, !!gpio_value);
input_event(GpioWakeUp_dev->input, EV_MSC, MSC_RAW, !!gpio_value);
input_sync(GpioWakeUp_dev->input);
#if HAS_WAKE_SOURCE_LOCK
if(WAKEUP_STATE_VALUE == gpio_value){ //wake up
pm_stay_awake(g_GpioWakeUp.dev);
}
else{ //into sleep
pm_relax(g_GpioWakeUp.dev);
}
#endif
}
currState = gpio_value;
enable_irq(GpioWakeUp_dev->eint_irq);
return IRQ_HANDLED;
}
#if HAL_GPIO_WAKUP_PM
static int mbtkGpioWakeUp_pm_resume(struct device *dev)
{
//pm_stay_awake(g_GpioWakeUp.dev);
//gpio_direction_output(g_GpioWakeUp.wake_ap_gpio, CP_WAKE_STATUS);
pr_info("mbtkGpioWakeUp_pm_resume\n");
return 0;
}
static int mbtkGpioWakeUp_pm_suspend(struct device *dev)
{
//pm_relax(g_GpioWakeUp.dev);
gpio_direction_output(g_GpioWakeUp.wake_ap_gpio, CP_SLEEP_STATUS);
pr_info("mbtkGpioWakeUp_pm_suspend\n");
return 0;
}
static int mbtkGpioWakeUp_pm_runtime_resume(struct device *dev)
{
/* enable clk and restore regs */
pr_info("mbtkGpioWakeUp_pm_runtime_resume\n");
return 0;
}
static int mbtkGpioWakeUp_pm_runtime_suspend(struct device *dev)
{
/* backup regs and disable clk */
pr_info("mbtkGpioWakeUp_pm_runtime_suspend\n");
return 0;
}
static int mbtkGpioWakeUp_pm_runtime_idle(struct device *dev)
{
pr_info("mbtkGpioWakeUp_pm_runtime_idle\n");
return 0;
}
static const struct dev_pm_ops mbtkGpioWakeUp_pm = {
.resume = mbtkGpioWakeUp_pm_resume,
.suspend = mbtkGpioWakeUp_pm_suspend,
.runtime_resume = mbtkGpioWakeUp_pm_runtime_resume,
.runtime_suspend = mbtkGpioWakeUp_pm_runtime_suspend,
.runtime_idle = mbtkGpioWakeUp_pm_runtime_idle
};
#endif
static const struct of_device_id mbtkGpioWakeUp_match[] = {
{ .compatible = "mbtk,GpioWakeUp", },
{ }
};
static ssize_t mbtkGpioWakeUp_value_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int gpio_value;
unsigned long flags;
struct mbtkGpioWakeUp_dev *GpioWakeUp_dev = &g_GpioWakeUp;
spin_lock_irqsave(&GpioWakeUp_dev->wk_lock, flags);
gpio_value = gpio_get_value_cansleep(GpioWakeUp_dev->wake_me_gpio) ;
spin_unlock_irqrestore(&GpioWakeUp_dev->wk_lock, flags);
currState = gpio_value;
input_event(GpioWakeUp_dev->input, EV_MSC, MSC_RAW, gpio_value);
input_sync(GpioWakeUp_dev->input);
sprintf(buf, "%d\n", gpio_value);
printk("gpio%d = %d \n",GpioWakeUp_dev->wake_me_gpio,gpio_value);
return strlen(buf) + 1;
}
static ssize_t mbtkGpioWakeUp_value_store(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t size)
{
int gpio_value=0;
struct mbtkGpioWakeUp_dev *GpioWakeUp_dev = &g_GpioWakeUp;
sscanf(buf, "%d", &gpio_value);
if (gpio_value != 0 && gpio_value != 1) {
pr_err("%s: invalid value %d, should be 0 or 1\n",
__func__, gpio_value);
return -EINVAL;
}
input_event(GpioWakeUp_dev->input, EV_MSC, MSC_RAW, gpio_value);
input_sync(GpioWakeUp_dev->input);
return size;
}
static DEVICE_ATTR(WakeUpValue, 0664, mbtkGpioWakeUp_value_show, mbtkGpioWakeUp_value_store);
int mbtkGpioWakeUp_probe(struct platform_device *pdev)
{
int gpio;
int gpio_value;
unsigned long flags;
int ret = 0, error;
struct device_node *np = NULL;
struct input_dev *input;
g_GpioWakeUp.dev = &pdev->dev;
np = pdev->dev.of_node;
sema_init(&g_GpioWakeUp.wk_sem,0);
spin_lock_init(&g_GpioWakeUp.wk_lock);
device_init_wakeup(&pdev->dev, true);
g_GpioWakeUp.GpioWakeUp_ws = wakeup_source_register(g_GpioWakeUp.dev ,"GpioWakeUp");
if(g_GpioWakeUp.GpioWakeUp_ws == NULL){
printk("adb_setup wakeup_source_create fail\n");
goto wake_source_init_fail;
}
gpio = of_get_named_gpio(np, "wakeup-in-gpio", 0);
if (unlikely(gpio < 0)) {
pr_err("%s. parse wakeup-in-gpio failed\n", __func__);
ret = -EINVAL;
} else {
pr_err("%s. wakeup-in-gpio=%d\n", __func__, gpio);
}
if(gpio >= 0)
{
/*LYNQ_MODFIY_START
ret = gpio_request(gpio, "wakeup-in");
if(ret < 0)
{
pr_err("%s. gpio_request for wakeup-in-gpio=%d failed\n", __func__,gpio);
return ret;
}
LYNQ_MODFIY_END*/
g_GpioWakeUp.wake_me_gpio = gpio;
gpio_direction_input(g_GpioWakeUp.wake_me_gpio);
g_GpioWakeUp.eint_irq = gpio_to_irq(g_GpioWakeUp.wake_me_gpio);
if (g_GpioWakeUp.eint_irq < 0)
{
error = g_GpioWakeUp.eint_irq ;
printk("Unable to get irq number for GPIO %d, error %d\n",g_GpioWakeUp.wake_me_gpio, error);
goto wake_in_pin_init_fail;
}
else
{
printk("wake in gpio request irq %d sucess\n", g_GpioWakeUp.eint_irq);
}
}
input = input_allocate_device();;
if (!input) {
printk("failed to allocate state\n");
error = -ENOMEM;
goto input_fail;
}
g_GpioWakeUp.input = input;
input->name = "WAKE-in-GPIO";
/* 2. ?? */
/* 2.1 ??????? */
set_bit(EV_MSC, g_GpioWakeUp.input->evbit);
set_bit(EV_SYN, g_GpioWakeUp.input->evbit);
/* 2.2 ?????????????: L,S,ENTER,LEFTSHIT */
set_bit(MSC_RAW, g_GpioWakeUp.input->mscbit);
//set_bit(KEY_LEFTSHIFT, buttons_dev->keybit);
/* 3. ?? */
input_set_capability(g_GpioWakeUp.input, EV_MSC, MSC_RAW);
error = input_register_device(input);
if (error)
{
pr_err("%s. input_register_device=%d failed\n", __func__,error);
goto input_fail;
}
spin_lock_irqsave(&g_GpioWakeUp.wk_lock, flags);
gpio_value = gpio_get_value(g_GpioWakeUp.wake_me_gpio) ;
spin_unlock_irqrestore(&g_GpioWakeUp.wk_lock, flags);
if(gpio_value < 0)
{
printk( "[%s-%d]: gpio get state failed\n",__func__,__LINE__);
}
//input_report_key(g_GpioWakeUp.input, KEY_1, !!gpio_value);
input_event(input, EV_MSC, MSC_RAW, !!gpio_value);
input_sync(input);
#if HAS_WAKE_SOURCE_LOCK
if(WAKEUP_STATE_VALUE == gpio_value)
{
pm_stay_awake(g_GpioWakeUp.dev);
}
else
{
pm_relax(g_GpioWakeUp.dev);
}
#endif
currState = gpio_value;
GPIO_WAKUP_debug("%s. devm_request_threaded_irqn", __func__);
ret = devm_request_threaded_irq(g_GpioWakeUp.dev, g_GpioWakeUp.eint_irq,NULL,GpioWakeUp_wkcp_thread_fn, (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT),"GpioWakeUp_wake int", &g_GpioWakeUp);
if(ret<0){
panic("mbtkGpioWakeUp_probe request_irq fail, %d", ret);
}
enable_irq_wake(g_GpioWakeUp.eint_irq);
ret = device_create_file(g_GpioWakeUp.dev, &dev_attr_WakeUpValue);
if(ret)
{
printk("ERROR: mbtkGpioWakeUp device_create_file failed\n");
}
#if HAS_WAKE_OUT_PIN
gpio = of_get_named_gpio(np, "wakeup-out-gpio", 0);
if (unlikely(gpio < 0)) {
pr_err("%s. parse wakeup-out-gpio failed\n", __func__);
} else
{
pr_err("%s. wakeup-out-gpio=%d\n", __func__, gpio);
}
if(gpio >= 0)
{
/*LYNQ_MODFIY_START
ret = gpio_request(gpio, "wakeup-out");
if(ret < 0)
{
pr_err("%s. gpio_request for wakeup-out-gpio=%d failed\n", __func__,gpio);
goto wake_out_pin_init_fail;
}
LYNQ_MODFIY_END*/
g_GpioWakeUp.wake_ap_gpio = gpio;
GPIO_WAKUP_debug("%s. gpio_request for wakeup-out-gpio=%d sucess\n", __func__,g_GpioWakeUp.wake_ap_gpio);
}
gpio_direction_output(g_GpioWakeUp.wake_ap_gpio, CP_WAKE_STATUS);
#endif
g_GpioWakeUp.wake_cnt = 0;
g_GpioWakeUp.sleep_cnt = 0;
#if HAS_WAKE_OUT_PIN
wake_out_pin_init_fail:
if(ret){
pr_err("wakeup-out gpio%d init failed\n",gpio);
}
#endif
input_fail:
input_free_device(g_GpioWakeUp.input);
wake_in_pin_init_fail:
if(ret){
pr_err("wakeup-in gpio%d init failed\n",gpio);
}
//pinctrl_init_fail:
// if(ret){
// printk("pinctrl_init_fail\n");
// }
wake_source_init_fail:
//pm_relax(g_GpioWakeUp.dev);
return ret;
}
static struct platform_driver mbtkGpioWakeUp_driver = {
.probe = mbtkGpioWakeUp_probe,
.driver = {
.name = "mbtk_GpioWakeUp",
#if HAL_GPIO_WAKUP_PM
.pm = &mbtkGpioWakeUp_pm,
#endif
.of_match_table = mbtkGpioWakeUp_match,
},
};
/*******************************************************************************
* Function: zDrvAp2cp_Initiate
* Description:
* Parameters:
* Input:
*
* Output:
*
* Returns:
*
* Others:
********************************************************************************/
static int __init zDrvGpioWakeUp_Initiate(void)
{
int ret=0;
//int errCode = -1;
GpioWakeUp_init_flag = 1;
ret = platform_driver_register(&mbtkGpioWakeUp_driver);
if (ret != 0){
printk("GPIO_WAKUP: platform_driver_register fail!\n");
return ret;
}
return 0;
}
int zDrvGpioWakeUp_Release(void)
{
gpio_free(g_GpioWakeUp.wake_me_gpio);
#if HAS_WAKE_OUT_PIN
gpio_free(g_GpioWakeUp.wake_ap_gpio);
#endif
return 0;
}
late_initcall(zDrvGpioWakeUp_Initiate);
//module_exit(zDrvGpioWakeUp_Release);