TP X 双击唤醒 X 高通msm8916 X 方案1

最近要实现双击唤醒屏幕

第一个方案:勉强实现,但是功耗大,还没进行消抖处理

实现步骤如下:
1.找到tp实现的代码kernel/drivers/input/touchscreen/gsl/gslX68X.c

2.找到tp休眠挂起的代码,开启中断,去掉拉低电源引脚
在static struct i2c_driver gsl_ts_driver结构体中有 .pm = &gsl2680_ts_pm_ops,此结构体进行电源管理,唤醒和休眠,如下:

static const struct dev_pm_ops gsl2680_ts_pm_ops = {
	.suspend = gsl_ts_suspend,  //休眠函数,拉低shutdown的引脚,供给低电压
	.resume = gsl_ts_resume,    //唤醒函数
};

下面是休眠函数

static int gsl_ts_suspend(struct device *dev)
{	
	...
	struct gsl_ts *ts = dev_get_drvdata(dev);
	...
	gsl_halt_flag = 1;
	
	enable_irq(ts->irq);  //当进入休眠的时候,为了获取双击坐标,要先打开中断
	//disable_irq_nosync(ts->irq);  去掉关中断 	
	//gslX680_shutdown_low();       去掉拉低电源,其函数如下
	return 0;
}
/************************************************
  Description	: Put the shutdown(Reset) on Lower Voltage;
  Input			: None
  Return Value	: return 0
 ************************************************/
static int gslX680_shutdown_low(void)
{
	gpio_direction_output(ts_globe->reset_gpio, 0);  //
	return 0;
}
在设备树msm8916-mtp.dtsi中找到
goodix,reset-gpio = <&msm_gpio 12 0x0>;  12号是shutdown引脚,同时可以去原理图中得到验证

3.注册键值
首先在static int gsl_ts_init_ts函数中,注册键值,在probe函数中会调用的函数。
注册语句:input_set_capability(ts->input, EV_KEY, KEY_POWER);

4.上报KEY_POWER键值
上报键值的位置:在中断处理函数的下半段中,进行判断,上报KEY_POWER键值或者进行正常上报
INIT_WORK(&ts->work, gsl_ts_xy_worker); //下半段函数为gsl_ts_xy_worker

#include              //用前后两次jiffies来判断是否双击
static unsigned long old = 0;		   //记录上一次jiffies
static void gsl_ts_xy_worker(struct work_struct *work)
{
	int rc;
	u8 read_buf[4] = { 0 };
	struct gsl_ts *ts = container_of(work, struct gsl_ts, work);
	...
	if(gsl_halt_flag == 1)   //进入了休眠模式
	{
		if(old == 0)         //old==0 为第一次触摸
		{
			old = jiffies;
			return;
		}
		//前后两次触摸在20个时钟中断到80个时钟中断之间,说明双击,上报键值
		//1s发生1HZ个时钟中断,此系统1HZ==100
		else if((old != 0)&& ((jiffies-old) < 80) && ((jiffies-old) > 20))    
		{
			gsl_halt_flag = 0;  //休眠标志置为0
			old = 0;            //old也置为0
			//注意:上报KEY_POWER键值要上报两次,第一次键值为1,第二次键为0
			/*因为是报告键值是虚拟,所以必须报1,0两次,如果只报1,会被认为KEY_POWER一直按下没有放开,导致input只上报KEY_POWER不成功。*/
			input_report_key(ts->input,KEY_POWER, 1);					
			input_sync(ts->input);				
			input_report_key(ts->input,KEY_POWER, 0);					
			input_sync(ts->input);
		}
		//超过了80个时钟中断,第二次按下无效,old清0
		else if((old != 0)&&((jiffies-old) >= 80))
		{
			old = 0;
		}
		enable_irq(ts->irq);
		return;
	}
	...
	如果不是进入休眠模式,则进行正常的上报
}

5.测试时,发现如下bug:插上usb时可以进行双击唤醒,正常情况(无usb)不能进行双击唤醒,下面解bug

5.1猜想1,认为是tp在无usb插入的时候,一段时间过后tp关闭
让tp一直打开,方法:去电源的设备树中进行设置
在msm8916-regulator.dtsi中的两个regulator中加入regulator-always-on;
之所以是两个,是因为在驱动代码中发现了的gsl_power_on函数中,regulator_enable(data->vdd);和 regulator_enable(data->vcc_i2c);

	rpm-regulator-ldoa6 {
		status = "okay";
		pm8916_l6: regulator-l6 {
		...
			regulator-always-on;
		};
	};
	rpm-regulator-ldoa17 {
		status = "okay";
		pm8916_l17: regulator-l17 {
			...
			regulator-always-on;
		};
	};
结果:tp正常唤醒速度加快,因为tp一直打开,但是仍然不能解决bug

5.2打印无usb的灭屏log发现:
Freezing of tasks aborted after 0.006 seconds (50 tasks refusing to freeze, wq_busy=0): //说明进入了深度睡眠,冻结了许多内核线程

//打开log,发现的确是进入了kernle\power下的Suspend.c函数,电源挂起了
[  182.810610] BMS: report_vm_bms_soc: ============last_soc=92 calculated_soc=92 soc=92 time_since_last_change=20
[  185.261140] pm_suspend^^^^^^^^^^^^^^
[  185.283804] enter_state------PM: Preparing system for mem sleep
[  185.306882] suspend_prepare^^^^^^^^^^^^^^
[  185.311425] freeze_processes^^^^^^^^^^^^^^
[  185.317467] try_to_freeze_tasks^^^^^^^^^^^^^^
[  185.323754] Freezing of tasks aborted after 0.006 seconds (50 tasks refusing to freeze, wq_busy=0):
[  185.341550] pm_suspend^^^^^^^^^^^^^^
[  185.352996] enter_state------PM: Preparing system for mem sleep
[  185.360836] suspend_prepare^^^^^^^^^^^^^^
[  185.365439] freeze_processes^^^^^^^^^^^^^^
[  185.371014] try_to_freeze_tasks^^^^^^^^^^^^^^
[  185.379308] suspend_freeze_processes^^^^^^^^^^^^^^
[  185.384690] freeze_kernel_threads^^^^^^^^^^^^^^
[  185.390697] try_to_freeze_tasks^^^^^^^^^^^^^^
//进入Suspend.c,屏蔽电源挂起相关代码
int pm_suspend(suspend_state_t state)
{
	...
	pr_err("pm_suspend-------------\n");
	error = enter_state(state);
	...
}
//进入enter_state(state);
static int enter_state(suspend_state_t state)
{
	int error;
	if(0){//屏蔽代码
	... 
	}
	error = 0;
	return error;

6.bug暂时解决,但是会造成耗电多,因为进入深度睡眠的时候没有冻结许多线程,同时没进行消抖处理

7.下篇继续研究,优化

now,我想说

学习辛苦了,现在不妨换换思路,瞧点文学东西,

如果你喜欢,聊历史,思哲学,品诗集,赏国学。

那就关注公众号:二校五叔

这个是博主的文学公众号啦^ _ ^

你可能感兴趣的:(驱动--tp)