MTK keypad调试,扩张键盘IC AW9523

按键没有hal层

设备中断-------驱动------>内核按键码(SCANCODE)-------*.kl--------> android keycode(char*)--------- KeycodeLabels.h ------>android keyevent(int, KeyEvent.java)

B:android keycode(char*)--------------- *.kcm/*.kcm.bin ------------>显示字符(char)


---

\alps\frameworks\base\policy\src\com\android\internal\policy\impl\PhoneWindowManager.java

    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
        if (!mSystemBooted) {
            // If we have not yet booted, don't let key events do anything.
            return 0;
        }
...
    // Handle special keys.
        switch (keyCode) {
            //add by //SCAN_123  ---
			case KeyEvent.KEYCODE_FN:
				if (down){
					fnflag = (!fnflag);
					Log.i(TAG, "fn status is " + fnflag);
					result &= ~ACTION_PASS_TO_USER;
					//add fn icon 	trs 2012-07-20
					Intent intent = new Intent(Intent.ACTION_FN_STATUS);
					intent.putExtra("fn_status", fnflag);
			        mContext.sendBroadcast(intent);
				}
				break;
			case KeyEvent.KEYCODE_F1:
			case KeyEvent.KEYCODE_F2:
			case KeyEvent.KEYCODE_F3:
			case KeyEvent.KEYCODE_F4:
				if (!down){
					handleFKeys(keyCode);
				}
				result &= ~ACTION_PASS_TO_USER;
				break;
			//add end//SCAN_123 ---		


event hub  alps\frameworks\base\services\input\
event read

------------- alps\frameworks\base\core\java\android\view\KeyEvent.java 上层

public class KeyEvent extends InputEvent implements Parcelable {
    /** Key code constant: Unknown key code. */
    public static final int KEYCODE_UNKNOWN         = 0;
    /** Key code constant: Soft Left key.
     * Usually situated below the display on phones and used as a multi-function
     * feature key for selecting a software defined function shown on the bottom left
     * of the display. */
    public static final int KEYCODE_SOFT_LEFT       = 1;
    /** Key code constant: Soft Right key.
     * Usually situated below the display on phones and used as a multi-function
     * feature key for selecting a software defined function shown on the bottom right
     * of the display. */
    public static final int KEYCODE_SOFT_RIGHT      = 2;
    /** Key code constant: Home key.
     * This key is handled by the framework and is never delivered to applications. */
    public static final int KEYCODE_HOME            = 3;
    /** Key code constant: Back key. */
    public static final int KEYCODE_BACK            = 4;
    /** Key code constant: Call key. */
    public static final int KEYCODE_CALL            = 5;
    public static final int KEYCODE_KANA            = 218;
    /** Key code constant: Assist key.
     * Launches the global assist activity.  Not delivered to applications. */
    public static final int KEYCODE_ASSIST          = 219;
    public static final int KEYCODE_SCAN          = 220;//sam add 
    public static final int KEYCODE_SCAN_LEFT          = 221;
    public static final int KEYCODE_SCAN_RIGHT          = 222;
    public static final int KEYCODE_FN             = 223;
    private static final int LAST_KEYCODE           = KEYCODE_FN;//KEYCODE_ASSIST;

     private static void populateKeycodeSymbolicNames() {
        SparseArray<String> names = KEYCODE_SYMBOLIC_NAMES;
        names.append(KEYCODE_UNKNOWN, "KEYCODE_UNKNOWN");
        names.append(KEYCODE_SOFT_LEFT, "KEYCODE_SOFT_LEFT");
        names.append(KEYCODE_SOFT_RIGHT, "KEYCODE_SOFT_RIGHT");
        names.append(KEYCODE_HOME, "KEYCODE_HOME");
        names.append(KEYCODE_BACK, "KEYCODE_BACK");
        names.append(KEYCODE_CALL, "KEYCODE_CALL");
        names.append(KEYCODE_ENDCALL, "KEYCODE_ENDCALL");
        names.append(KEYCODE_0, "KEYCODE_0");

alps\frameworks\base\api\17.txt   // android API 17 = android4.2 //找到 17.txt文件改  //可能需要使用命令:./make update-api

    field public static final int KEYCODE_HOME = 3; // 0x3  //与上面的数字值要一样。
    ...
    field public static final int META_SHIFT_RIGHT_ON = 128; // 0x80
    field public static final int META_SYM_ON = 4; // 0x4
    field public static final int KEYCODE_SCAN = 220; // 0xdc
    field public static final int KEYCODE_SCAN_LEFT = 221; // 0xdd
    field public static final int KEYCODE_SCAN_RIGHT = 221; // 0xde


---

alpsAteam\frameworks\native\include\android\keycodes.h

    AKEYCODE_KANA            = 218,
    AKEYCODE_ASSIST          = 219,
    AKEYCODE_SCAN            = 220,//sam add
    AKEYCODE_SCAN_LEFT       = 221,
    AKEYCODE_SCAN_RIGHT      = 222,
    AKEYCODE_FN              = 223,
    // NOTE: If you add a new keycode here you must also add it to several other files.
    //       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
};

---

\alps\frameworks\base\libs\androidfw\Input.cpp

bool KeyEvent::isSystemKey(int32_t keyCode) {
    switch (keyCode) {
        case AKEYCODE_MENU:
        case AKEYCODE_SOFT_RIGHT:
        case AKEYCODE_HOME:
        case AKEYCODE_BACK:
        case AKEYCODE_CALL:
        ....
        case AKEYCODE_SEARCH:
        case AKEYCODE_SCAN://sam add --below...
        case AKEYCODE_SCAN_LEFT:
        case AKEYCODE_SCAN_RIGHT:
        case AKEYCODE_FN:
        case AKEYCODE_F1:
        case AKEYCODE_F2:
        case AKEYCODE_F3:
        case AKEYCODE_F4:
            return true;
    }


----

alps\frameworks\native\include\input\KeycodeLabels.h
...
static const KeycodeLabel KEYCODES[] = {//下层与上层的对照,能过字符串把两个数字来找的。
 
  { "SOFT_LEFT", 1 },
   { "SOFT_RIGHT", 2 },
   { "HOME", 3 },
   { "BACK", 4 },
...
    { "KANA", 218 },
    { "ASSIST", 219 },
    { "SCAN", 220 },//sam add
    { "SCAN_LEFT", 221 },
    { "SCAN_RIGHT", 222 },
	{ "FN", 223 },
    // NOTE: If you add a new keycode here you must also add it to several other files.
    //       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.


    { NULL, 0 }
};



mtk-kpd.kl //底层
....

key 102   HOME
...
key 59   F1
key 60   F2
key 61   F3
key 62   F4
key 464  FN

key 220   SCAN
key 125   SCAN_LEFT
key 128   SCAN_RIGHT


...
----
//mt6571/72可以做18个的扩展键盘(3个row pin和3个col pin),但做不了更多,
3*3*2 =power , volume ,   

更多keypad需要做8*8 (8 row pin 和8 col pin)

也可以外挂一个键盘ic来做。
-----
//mtk默认pmic有两个key ,一个是 power key,另一个是 vlume down key/home key/ 

在codegen.dws中
[KEYPAD Setting]页面,有一个PowerKey use EINT ,选中,则会打开了这个开关  KPD_PWRKEY_USE_EINT在mediatek\kernel\drivers\keypad\kpd.c中使用到.一般我们不用EINT做power key,而是默认使用pmic做power key.
</pre><pre code_snippet_id="378654" snippet_file_name="blog_20140605_4_3325559" name="code" class="cpp">alps\mediatek\platform\mt6572\kernel\drivers\keypad\kpd.c
/*
 * Copyright (C) 2010 MediaTek, Inc.
 *
 * Author: Terry Chang <terry.chang@mediatek.com>
 *
 * This software is licensed under the terms of the GNU General Public
 * License version 2, as published by the Free Software Foundation, and
 * may be copied, distributed, and modified under those terms.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/input.h>
#include <linux/workqueue.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>
#include <linux/earlysuspend.h>
#include <linux/spinlock.h>

#include <asm/atomic.h>
#include <asm/uaccess.h>


#include <mach/mt_reg_base.h>
#include <mach/mt_boot.h>
#include <mtk_kpd.h>		/* custom file */
#include <mach/irqs.h>
#include <mach/eint.h>
#include <mach/mt_gpio.h>
#include <mach/mt_pmic_wrap.h>
#include <mach/mt_sleep.h>
#include <mach/kpd.h>
#include <mach/sync_write.h>

#include <linux/aee.h>

#if 1	//ATA_TEST
#define KPD_AUTOTEST_BY_KP	
#endif

#define KPD_NAME	"mtk-kpd"

/* Keypad registers */
#define KP_STA			(KP_BASE + 0x0000)
#define KP_MEM1			(KP_BASE + 0x0004)
#define KP_MEM2			(KP_BASE + 0x0008)
#define KP_MEM3			(KP_BASE + 0x000c)
#define KP_MEM4			(KP_BASE + 0x0010)
#define KP_MEM5			(KP_BASE + 0x0014)
#define KP_DEBOUNCE		(KP_BASE + 0x0018)
#define KP_SCAN_TIMING		(KP_BASE + 0x001C)
#define KP_SEL			(KP_BASE + 0x0020)
#define KP_EN			(KP_BASE + 0x0024)

#define KPD_NUM_MEMS	5
#define KPD_MEM5_BITS	8

#define KPD_NUM_KEYS	72	/* 4 * 16 + KPD_MEM5_BITS */

#define KPD_DEBOUNCE_MASK	((1U << 14) - 1)

#define KPD_SAY		"kpd: "
#if KPD_DEBUG
#define kpd_print(fmt, arg...)	printk(KPD_SAY fmt, ##arg)
#else
#define kpd_print(fmt, arg...)	do {} while (0)
#endif


static struct input_dev *kpd_input_dev;
static bool kpd_suspend = false;
static int kpd_show_hw_keycode = 1;
static int kpd_show_register = 1;
static int kpd_enable_lprst = 1;

/* for AEE manual dump */
#if 0
static bool kpd_volumn_down_flag = false;
static bool kpd_volumn_up_flag = false;
static inline void check_aee_dump()
{
	if( (kpd_volumn_down_flag == true) && (kpd_volumn_up_flag == true))
	{
		printk(KPD_SAY "kpd_volumn_up+ volumn_down,will trige DB\n");
		aee_kernel_reminding("manual dump ", "Triggered by press KEY_VOLUMEUP+KEY_VOLUMEDOWN");
	}
}
#endif

/* for backlight control */
#if KPD_DRV_CTRL_BACKLIGHT
static void kpd_switch_backlight(struct work_struct *work);
static void kpd_backlight_timeout(unsigned long data);
static DECLARE_WORK(kpd_backlight_work, kpd_switch_backlight);
static DEFINE_TIMER(kpd_backlight_timer, kpd_backlight_timeout, 0, 0);

static unsigned long kpd_wake_keybit[BITS_TO_LONGS(KEY_CNT)];
static u16 kpd_wake_key[] __initdata = KPD_BACKLIGHT_WAKE_KEY;

static volatile bool kpd_backlight_on;
static atomic_t kpd_key_pressed = ATOMIC_INIT(0);
#endif

/* for slide QWERTY */
#if KPD_HAS_SLIDE_QWERTY
static void kpd_slide_handler(unsigned long data);
static DECLARE_TASKLET(kpd_slide_tasklet, kpd_slide_handler, 0);

static u8 kpd_slide_state = !KPD_SLIDE_POLARITY;
#endif

/* for Power key using EINT */
#if KPD_PWRKEY_USE_EINT
static void kpd_pwrkey_handler(unsigned long data);
static DECLARE_TASKLET(kpd_pwrkey_tasklet, kpd_pwrkey_handler, 0);
static u8 kpd_pwrkey_state = !KPD_PWRKEY_POLARITY;
#endif

/* for Power key using PMIC */
/*********************************************************************/
#if 0//KPD_PWRKEY_USE_PMIC //for 77 chip and earlier version   power key bug, has fixed on 89 chip

static void kpd_pwrkey_handler(struct work_struct *work);
static DECLARE_WORK(pwrkey_pmic_work, kpd_pwrkey_handler);
#endif
/*********************************************************************/

/* for keymap handling */
static DEFINE_SPINLOCK(keymap_handler_spinlock);
static void kpd_keymap_handler(unsigned long data);
static DECLARE_TASKLET(kpd_keymap_tasklet, kpd_keymap_handler, 0);


#define KPD_INIT_KEYMAP_FULL()	\
{	\
	[0] = KEY_1,		\
	[1] = KEY_2,		\
	[2] = KEY_3,		\
	[3] = KEY_4,		\
	[4] = KEY_5,		\
	[5] = KEY_6,		\
	[6] = KEY_7,		\
	[7] = KEY_8,		\
	[8] = KEY_9,		\
	[9] = KEY_VOLUMEDOWN,		\
	[10] = KEY_VOLUMEUP,		\
	[11] = KEY_0,		\
	[12] = KEY_ENTER,		\
	[13] = KEY_TAB,		\
	[14] = KEY_BACKSPACE,		\
	[15] = KEY_STAR,		\
	[16] = KEY_POUND,		\
	[17] = KEY_SYM,		\
	[18] = KEY_DOT,		\
	[19] = KEY_FN,		\
	[20] = KEY_F1,		\
	[21] = KEY_F2,		\
	[22] = KEY_F3,		\
	[23] = KEY_F4,		\
	[24] = KEY_DEL,		\
	[25] = KEY_S,		\	
	[25] = KEY_OK,		\		
}	 


//static u16 kpd_keymap[KPD_NUM_KEYS] = KPD_INIT_KEYMAP_FULL();	//KPD_INIT_KEYMAP();
static u16 kpd_keymap[KPD_NUM_KEYS] = KPD_INIT_KEYMAP();
static u16 kpd_keymap_state[KPD_NUM_MEMS] = {
	0xffff, 0xffff, 0xffff, 0xffff, 0x00ff
};
/*********************************************************************/
/*************************kpd function decleare***************************/
/*********************************************************************/
static int kpd_pdrv_probe(struct platform_device *pdev);
static int kpd_pdrv_remove(struct platform_device *pdev);
#ifndef CONFIG_HAS_EARLYSUSPEND	
static int kpd_pdrv_suspend(struct platform_device *pdev, pm_message_t state);
static int kpd_pdrv_resume(struct platform_device *pdev);
#endif

void mtk_kpd_get_gpio_col(unsigned int COL_REG[], unsigned int GPIO_MODE[]);
void kpd_auto_test_for_factorymode(void);

static struct platform_driver kpd_pdrv = {
	.probe		= kpd_pdrv_probe,
	.remove		= kpd_pdrv_remove,
#ifndef CONFIG_HAS_EARLYSUSPEND	
	.suspend	= kpd_pdrv_suspend,
	.resume		= kpd_pdrv_resume,
#endif	
	.driver		= {
		.name	= KPD_NAME,
		.owner	= THIS_MODULE,
	},
};
/********************************************************************/
void mtk_kpd_get_gpio_col(unsigned int COL_REG[], unsigned int GPIO_MODE[])
{
	int i;
	for(i = 0; i< 8; i++)
	{
		COL_REG[i] = 0;
		GPIO_MODE[i] = 0;
	}
	kpd_print("Enter mtk_kpd_get_gpio_col! \n");
	
	#ifdef GPIO_KPD_KCOL0_PIN
		kpd_print("checking GPIO_KPD_KCOL0_PIN! \n");
		COL_REG[0] = GPIO_KPD_KCOL0_PIN;
		GPIO_MODE[0] |= (GPIO_KPD_KCOL0_PIN_M_KCOL << 4);
	#endif

	#ifdef GPIO_KPD_KCOL1_PIN
		kpd_print("checking GPIO_KPD_KCOL1_PIN! \n");
		COL_REG[1] = GPIO_KPD_KCOL1_PIN;
		GPIO_MODE[1] |= (GPIO_KPD_KCOL1_PIN_M_KCOL << 4);
	#endif

	#ifdef GPIO_KPD_KCOL2_PIN
		kpd_print("checking GPIO_KPD_KCOL2_PIN! \n");
		COL_REG[2] = GPIO_KPD_KCOL2_PIN;
		GPIO_MODE[2] |= (GPIO_KPD_KCOL2_PIN_M_KCOL << 4);
	#endif

	#ifdef GPIO_KPD_KCOL3_PIN
		kpd_print("checking GPIO_KPD_KCOL3_PIN! \n");
		COL_REG[3] = GPIO_KPD_KCOL3_PIN;
		GPIO_MODE[3] |= (GPIO_KPD_KCOL3_PIN_M_KCOL << 4);
	#endif

	#ifdef GPIO_KPD_KCOL4_PIN
		kpd_print("checking GPIO_KPD_KCOL4_PIN! \n");
		COL_REG[4] = GPIO_KPD_KCOL4_PIN;
		GPIO_MODE[4] |= (GPIO_KPD_KCOL4_PIN_M_KCOL << 4);
	#endif

	#ifdef GPIO_KPD_KCOL5_PIN
		kpd_print("checking GPIO_KPD_KCOL5_PIN! \n");
		COL_REG[5] = GPIO_KPD_KCOL5_PIN;
		GPIO_MODE[5] |= (GPIO_KPD_KCOL5_PIN_M_KCOL << 4);
	#endif

	#ifdef GPIO_KPD_KCOL6_PIN
		kpd_print("checking GPIO_KPD_KCOL6_PIN! \n");
		COL_REG[6] = GPIO_KPD_KCOL6_PIN;
		GPIO_MODE[6] |= (GPIO_KPD_KCOL6_PIN_M_KCOL << 4);
	#endif

	#ifdef GPIO_KPD_KCOL7_PIN
		kpd_print("checking GPIO_KPD_KCOL7_PIN! \n");
		COL_REG[7] = GPIO_KPD_KCOL7_PIN;
		GPIO_MODE[7] |= (GPIO_KPD_KCOL7_PIN_M_KCOL << 4);
	#endif
}

#ifdef KPD_AUTOTEST_BY_KP
void kpd_reset_keymap_state(u16 state[])
{
	int	i;
	for(i = 0; i < (KPD_NUM_MEMS - 1); i++)
		state[i] = 0xffff;
	
	state[(KPD_NUM_MEMS - 1)] = 0x00ff;
	return;
}

void kpd_kcol_scan_for_factorymode(void)
{
	unsigned int COL_REG[8], COL_LAST = 0;
	unsigned int GPIO_MODE[8];
	int i, col_num;
	
#if !KPD_USE_EXTEND_TYPE
	kpd_print("Enter kpd_kcol_scan_for_factorymode on single keypad! \n");
	col_num	=	8;
#else				
	kpd_print("Enter kpd_kcol_scan_for_factorymode on double keypad! \n");	
	col_num	=	3;
#endif	
	
	disable_irq_nosync(MT_KP_IRQ_ID);
	*(volatile u16 *)KP_EN = 0;
	kpd_keymap_handler(1);
	msleep(100);	
	
	mtk_kpd_get_gpio_col(COL_REG, GPIO_MODE);
	
	for(i = 0; i < col_num; i++)
	{
		if (COL_REG[i] != 0)
			mt_set_gpio_mode(COL_REG[i], GPIO_MODE_GPIO);
	}

	for(i = 0; i < col_num; i++)
	{
		if (COL_REG[i] != 0)
		{
			mt_set_gpio_mode(COL_REG[i], ((GPIO_MODE[i] >> 4) & 0x0f));
			kpd_reset_keymap_state(kpd_keymap_state);
			COL_LAST = COL_REG[i];
			*(volatile u16 *)KP_EN = 0x1;
			kpd_print("kpd_kcol_scan_for_factorymode:  KP enable KCOL=%d \n", i);
		}
		                      
		msleep(100);
		if(*(volatile u16 *)KP_STA & 0x01)                      
				kpd_keymap_handler(2);

		if(0 != COL_LAST)
		{	
			msleep(100);
			kpd_keymap_handler(1);
			*(volatile u16 *)KP_EN = 0;
			mt_set_gpio_mode(COL_LAST, GPIO_MODE_GPIO);
			kpd_print("kpd_kcol_scan_for_factorymode:  KP disable KCOL=%d \n", i);
			COL_LAST = 0;
		}
	}

	for(i = 0; i < col_num; i++)
	{
		if (COL_REG[i] != 0)
			mt_set_gpio_mode(COL_REG[i], ((GPIO_MODE[i] >> 4) & 0x0f));
	}
	
	kpd_reset_keymap_state(kpd_keymap_state);
	*(volatile u16 *)KP_EN = 0x1;	
	
	if(upmu_get_pwrkey_deb()!=1)
	{
			kpd_pwrkey_pmic_handler(0);
			msleep(100);
			kpd_pwrkey_pmic_handler(1);
	}	
	
	enable_irq(MT_KP_IRQ_ID);
	return;
}
#else		//KPD_AUTOTEST_BY_KP
void kpd_auto_test_for_factorymode(void)
{
	unsigned int COL_REG[8];
	unsigned int GPIO_MODE[8];
	int i;
	
	kpd_pwrkey_pmic_handler(1);
	msleep(100);
	kpd_pwrkey_pmic_handler(0);
	
#ifdef KPD_PMIC_RSTKEY_MAP
	kpd_pmic_rstkey_handler(1);
	msleep(100);
	kpd_pmic_rstkey_handler(0);
#endif

	kpd_print("Enter kpd_auto_test_for_factorymode! \n");
	mtk_kpd_get_gpio_col(COL_REG, GPIO_MODE);
	
	for(i = 0; i < 8; i++)
	{
		if (COL_REG[i] != 0)
		{
			msleep(100);
			kpd_print("kpd kcolumn %d pull down!\n", COL_REG[i]);
			mt_set_gpio_pull_select(COL_REG[i], 0);
			msleep(100);
			kpd_print("kpd kcolumn %d pull up!\n", COL_REG[i]);
			mt_set_gpio_pull_select(COL_REG[i], 1);
		}
	}

	return;
}
#endif		//KPD_AUTOTEST_BY_KP

/********************************************************************/


/********************************************************************/
/*****************for kpd auto set wake up source*************************/
/********************************************************************/
static volatile int call_status = 0;
static ssize_t kpd_store_call_state(struct device_driver *ddri, const char *buf, size_t count)
{
	if (sscanf(buf, "%u", &call_status) != 1) {
			kpd_print("kpd call state: Invalid values\n");
			return -EINVAL;
		}

	switch(call_status)
    	{
        case 1 :
			kpd_print("kpd call state: Idle state!\n");
     	break;
		case 2 :
			kpd_print("kpd call state: ringing state!\n");
		break;
		case 3 :
			kpd_print("kpd call state: active or hold state!\n");	
		break;
            
		default:
   			kpd_print("kpd call state: Invalid values\n");
        break;
  	}
	return count;
}

static ssize_t kpd_show_call_state(struct device_driver *ddri, char *buf)
{
	ssize_t res;
	res = snprintf(buf, PAGE_SIZE, "%d\n", call_status);     
	return res;   
}
static DRIVER_ATTR(kpd_call_state,	S_IWUSR | S_IRUGO,	kpd_show_call_state,	kpd_store_call_state);

static struct driver_attribute *kpd_attr_list[] = {
	&driver_attr_kpd_call_state,
};

/*----------------------------------------------------------------------------*/
static int kpd_create_attr(struct device_driver *driver) 
{
	int idx, err = 0;
	int num = (int)(sizeof(kpd_attr_list)/sizeof(kpd_attr_list[0]));
	if (driver == NULL)
	{
		return -EINVAL;
	}

	for(idx = 0; idx < num; idx++)
	{
		if((err = driver_create_file(driver, kpd_attr_list[idx])))
		{            
			kpd_print("driver_create_file (%s) = %d\n", kpd_attr_list[idx]->attr.name, err);
			break;
		}
	}    
	return err;
}
/*----------------------------------------------------------------------------*/
static int kpd_delete_attr(struct device_driver *driver)
	{
	int idx ,err = 0;
	int num = (int)(sizeof(kpd_attr_list)/sizeof(kpd_attr_list[0]));

	if (!driver)
	return -EINVAL;

	for (idx = 0; idx < num; idx++) 
	{
		driver_remove_file(driver, kpd_attr_list[idx]);
	}
	
	return err;
}
/*----------------------------------------------------------------------------*/
/********************************************************************/
/********************************************************************/
/********************************************************************/

/* for autotest */
#if KPD_AUTOTEST
static const u16 kpd_auto_keymap[] = {
	KEY_OK, KEY_MENU,
	KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT,
	KEY_HOME, KEY_BACK,
	KEY_CALL, KEY_ENDCALL,
	KEY_VOLUMEUP, KEY_VOLUMEDOWN,
	KEY_FOCUS, KEY_CAMERA,
};
#endif

/* for AEE manual dump */
#define AEE_VOLUMEUP_BIT	0
#define AEE_VOLUMEDOWN_BIT	1
#define AEE_DELAY_TIME		15
/* enable volup + voldown was pressed 5~15 s Trigger aee manual dump */
#define AEE_ENABLE_5_15		1
static struct hrtimer aee_timer;
static unsigned long  aee_pressed_keys;
static bool aee_timer_started;

#if AEE_ENABLE_5_15
#define AEE_DELAY_TIME_5S	5
static struct hrtimer aee_timer_5s;
static bool aee_timer_5s_started;
static bool flags_5s;
#endif

static inline void kpd_update_aee_state(void) {
	if(aee_pressed_keys == ((1<<AEE_VOLUMEUP_BIT) | (1<<AEE_VOLUMEDOWN_BIT))) {
		/* if volumeup and volumedown was pressed the same time then start the time of ten seconds */
		aee_timer_started = true;
		
#if AEE_ENABLE_5_15
		aee_timer_5s_started = true;
		hrtimer_start(&aee_timer_5s, 
				ktime_set(AEE_DELAY_TIME_5S, 0),
				HRTIMER_MODE_REL);
#endif
		hrtimer_start(&aee_timer, 
				ktime_set(AEE_DELAY_TIME, 0),
				HRTIMER_MODE_REL);
		kpd_print("aee_timer started\n");
	} else {
		if(aee_timer_started) {
/*
  * hrtimer_cancel - cancel a timer and wait for the handler to finish.
  * Returns:
  *	0 when the timer was not active. 
  *	1 when the timer was active.
 */
			if(hrtimer_cancel(&aee_timer))
			{
				kpd_print("try to cancel hrtimer \n");
#if AEE_ENABLE_5_15
				if(flags_5s)
				{
					printk("Pressed Volup + Voldown5s~15s then trigger aee manual dump.\n");
					aee_kernel_reminding("manual dump", "Trigger Vol Up +Vol Down 5s");
				}
#endif
					
			}
#if AEE_ENABLE_5_15
			flags_5s = false;
#endif
			aee_timer_started = false;
			kpd_print("aee_timer canceled\n");
		}

#if AEE_ENABLE_5_15
		if(aee_timer_5s_started) {
/*
  * hrtimer_cancel - cancel a timer and wait for the handler to finish.
  * Returns:
  *	0 when the timer was not active. 
  *	1 when the timer was active.
 */
			if(hrtimer_cancel(&aee_timer_5s))
			{
				kpd_print("try to cancel hrtimer (5s) \n");
			}
			aee_timer_5s_started = false;
			kpd_print("aee_timer canceled (5s)\n");
		}

#endif
	}
}

static void kpd_aee_handler(u32 keycode, u16 pressed) {
	if(pressed) {
		if(keycode == KEY_VOLUMEUP) {
			__set_bit(AEE_VOLUMEUP_BIT, &aee_pressed_keys);
		} else if(keycode == KEY_VOLUMEDOWN) {
			__set_bit(AEE_VOLUMEDOWN_BIT, &aee_pressed_keys);
		} else {
			return;
		}
		kpd_update_aee_state();
	} else {
		if(keycode == KEY_VOLUMEUP) {
			__clear_bit(AEE_VOLUMEUP_BIT, &aee_pressed_keys);
		} else if(keycode == KEY_VOLUMEDOWN) {
			__clear_bit(AEE_VOLUMEDOWN_BIT, &aee_pressed_keys);
		} else {
			return;
		}
		kpd_update_aee_state();
	}
}

static enum hrtimer_restart aee_timer_func(struct hrtimer *timer) {
	//printk("kpd: vol up+vol down AEE manual dump!\n");
	//aee_kernel_reminding("manual dump ", "Triggered by press KEY_VOLUMEUP+KEY_VOLUMEDOWN");
	aee_trigger_kdb();
	return HRTIMER_NORESTART;
}

#if AEE_ENABLE_5_15
static enum hrtimer_restart aee_timer_5s_func(struct hrtimer *timer) {
	
	//printk("kpd: vol up+vol down AEE manual dump timer 5s !\n");
	flags_5s = true;
	return HRTIMER_NORESTART;
}
#endif

static inline void kpd_get_keymap_state(u16 state[])
{
	state[0] = *(volatile u16 *)KP_MEM1;
	state[1] = *(volatile u16 *)KP_MEM2;
	state[2] = *(volatile u16 *)KP_MEM3;
	state[3] = *(volatile u16 *)KP_MEM4;
	state[4] = *(volatile u16 *)KP_MEM5;
	if (kpd_show_register) {
		printk(KPD_SAY "register = %x %x %x %x %x\n",
		       state[0], state[1], state[2], state[3], state[4]);
	}
}

static inline void kpd_set_debounce(u16 val)
{
	mt65xx_reg_sync_writew((u16)(val & KPD_DEBOUNCE_MASK), KP_DEBOUNCE);
}

#if KPD_DRV_CTRL_BACKLIGHT
static void kpd_switch_backlight(struct work_struct *work)
{
	if (kpd_backlight_on) {
		kpd_enable_backlight();
		kpd_print("backlight is on\n");
	} else {
		kpd_disable_backlight();
		kpd_print("backlight is off\n");
	}
}

static void kpd_backlight_timeout(unsigned long data)
{
	if (!atomic_read(&kpd_key_pressed)) {
		kpd_backlight_on = !!atomic_read(&kpd_key_pressed);
		schedule_work(&kpd_backlight_work);
		data = 1;
	}
	kpd_print("backlight timeout%s\n", 
	          data ? ": schedule backlight work" : "");
}

void kpd_backlight_handler(bool pressed, u16 linux_keycode)
{
	if (kpd_suspend && !test_bit(linux_keycode, kpd_wake_keybit)) {
		kpd_print("Linux keycode %u is not WAKE key\n", linux_keycode);
		return;
	}

	/* not in suspend or the key pressed is WAKE key */
	if (pressed) {
		atomic_inc(&kpd_key_pressed);
		kpd_backlight_on = !!atomic_read(&kpd_key_pressed);
		schedule_work(&kpd_backlight_work);
		kpd_print("switch backlight on\n");
	} else {
		atomic_dec(&kpd_key_pressed);
		mod_timer(&kpd_backlight_timer,
		          jiffies + KPD_BACKLIGHT_TIME * HZ);
		kpd_print("activate backlight timer\n");
	}
}
#endif

#if KPD_HAS_SLIDE_QWERTY
static void kpd_slide_handler(unsigned long data)
{
	bool slid;
	u8 old_state = kpd_slide_state;

	kpd_slide_state = !kpd_slide_state;
	slid = (kpd_slide_state == !!KPD_SLIDE_POLARITY);
	/* for SW_LID, 1: lid open => slid, 0: lid shut => closed */
	input_report_switch(kpd_input_dev, SW_LID, slid);
	input_sync(kpd_input_dev);
	kpd_print("report QWERTY = %s\n", slid ? "slid" : "closed");

	if(old_state) {
		mt_set_gpio_pull_select(GPIO_QWERTYSLIDE_EINT_PIN, 0);
	} else {
		mt_set_gpio_pull_select(GPIO_QWERTYSLIDE_EINT_PIN, 1);
	}
	/* for detecting the return to old_state */
	mt65xx_eint_set_polarity(KPD_SLIDE_EINT, old_state);
	mt65xx_eint_unmask(KPD_SLIDE_EINT);
}

static void kpd_slide_eint_handler(void)
{
	tasklet_schedule(&kpd_slide_tasklet);
}
#endif

#if KPD_PWRKEY_USE_EINT
static void kpd_pwrkey_handler(unsigned long data)
{
	bool pressed;
	u8 old_state = kpd_pwrkey_state;

	kpd_pwrkey_state = !kpd_pwrkey_state;
	pressed = (kpd_pwrkey_state == !!KPD_PWRKEY_POLARITY);
	if (kpd_show_hw_keycode) {
		printk(KPD_SAY "(%s) HW keycode = using EINT\n",
		       pressed ? "pressed" : "released");
	}
	kpd_backlight_handler(pressed, KPD_PWRKEY_MAP);
	input_report_key(kpd_input_dev, KPD_PWRKEY_MAP, pressed);
	input_sync(kpd_input_dev);
	kpd_print("report Linux keycode = %u\n", KPD_PWRKEY_MAP);

	/* for detecting the return to old_state */
	mt65xx_eint_set_polarity(KPD_PWRKEY_EINT, old_state);
	mt65xx_eint_unmask(KPD_PWRKEY_EINT);
}

static void kpd_pwrkey_eint_handler(void)
{
	tasklet_schedule(&kpd_pwrkey_tasklet);
}
#endif
/*********************************************************************/
#if 0//KPD_PWRKEY_USE_PMIC //for 77 chip and earlier version   power key bug, has fixed on 89 chip
static void kpd_pwrkey_handler(struct work_struct *work)
{
	int pressed = 1;
	/* report  Press*/
	input_report_key(kpd_input_dev, KPD_PWRKEY_MAP, pressed);
	input_sync(kpd_input_dev);
	if (kpd_show_hw_keycode) {
		printk(KPD_SAY "(%s) HW keycode = using PMIC\n",
		       pressed ? "pressed" : "released");
	}
	while(1)
	{
		if(upmu_get_pwrkey_deb() == 1)
		{
			pressed = 0;
			/* Report Release */
			input_report_key(kpd_input_dev, KPD_PWRKEY_MAP, pressed);
			input_sync(kpd_input_dev);
	    if (kpd_show_hw_keycode) {
		       printk(KPD_SAY "(%s) HW keycode = using PMIC\n",
		         pressed ? "pressed" : "released");
	    }			
			break;
		}
		msleep(10);
	}		
}

void kpd_pwrkey_pmic_handler(unsigned long pressed)
{
	printk(KPD_SAY "Power Key generate, pressed=%ld\n", pressed);
	if(!kpd_input_dev) {
		printk("KPD input device not ready\n");
		return;
	}
	if(get_chip_eco_ver() == CHIP_E2) {
		input_report_key(kpd_input_dev, KPD_PWRKEY_MAP, pressed);
		input_sync(kpd_input_dev);
		if (kpd_show_hw_keycode) {
			printk(KPD_SAY "(%s) HW keycode =%d using PMIC\n",
			       pressed ? "pressed" : "released", KPD_PWRKEY_MAP);
		}
	} else {
		schedule_work(&pwrkey_pmic_work);
	}
}
#endif
/*********************************************************************/
#if KPD_PWRKEY_USE_PMIC

void kpd_pwrkey_pmic_handler(unsigned long pressed)
{
	printk(KPD_SAY "Power Key generate, pressed=%ld\n", pressed);
	if(!kpd_input_dev) {
		printk("KPD input device not ready\n");
		return;
	}
	
		input_report_key(kpd_input_dev, KPD_PWRKEY_MAP, pressed);
		input_sync(kpd_input_dev);
		if (kpd_show_hw_keycode) {
			printk(KPD_SAY "(%s) HW keycode =%d using PMIC\n",
			       pressed ? "pressed" : "released", KPD_PWRKEY_MAP);
		}
}
#endif

/*********************************************************************/
void kpd_pmic_rstkey_handler(unsigned long pressed)
{
	printk(KPD_SAY "PMIC reset Key generate, pressed=%ld\n", pressed);
	if(!kpd_input_dev) {
		printk("KPD input device not ready\n");
		return;
	}
#ifdef KPD_PMIC_RSTKEY_MAP
		input_report_key(kpd_input_dev, KPD_PMIC_RSTKEY_MAP, pressed);
		input_sync(kpd_input_dev);
		if (kpd_show_hw_keycode) {
			printk(KPD_SAY "(%s) HW keycode =%d using PMIC\n",
			       pressed ? "pressed" : "released", KPD_PMIC_RSTKEY_MAP);
		}
		kpd_aee_handler(KPD_PMIC_RSTKEY_MAP, pressed);
#endif
}

static void kpd_keymap_handler(unsigned long data)
{
	int i, j;
	bool pressed;
	u16 new_state[KPD_NUM_MEMS], change, mask;
	u16 hw_keycode, linux_keycode;

	spin_lock(&keymap_handler_spinlock);
	kpd_get_keymap_state(new_state);

#ifdef KPD_AUTOTEST_BY_KP
	if(data == 1)
		kpd_reset_keymap_state(new_state);
		kpd_print("kpd_keymap_handler:  data=%d, new_state = %x %x %x %x %x \n",
					 data, new_state[0], new_state[1], new_state[2], new_state[3], new_state[4]);		
#endif

	for (i = 0; i < KPD_NUM_MEMS; i++) {
		change = new_state[i] ^ kpd_keymap_state[i];
		if (!change)
			continue;

		for (j = 0; j < 16; j++) {
			mask = 1U << j;
			if (!(change & mask))
				continue;

			hw_keycode = (i << 4) + j;
			/* bit is 1: not pressed, 0: pressed */
			pressed = !(new_state[i] & mask);
			if (kpd_show_hw_keycode) {
				printk(KPD_SAY "(%s) HW keycode = %u\n",
				       pressed ? "pressed" : "released",
				       hw_keycode);
			}
			BUG_ON(hw_keycode >= KPD_NUM_KEYS);
			linux_keycode = kpd_keymap[hw_keycode];			
			if (unlikely(linux_keycode == 0)) {
				kpd_print("Linux keycode = 0\n");
				continue;
			}		
			
#ifdef KPD_AUTOTEST_BY_KP
			if((get_boot_mode() != FACTORY_BOOT) && (get_boot_mode() != ATE_FACTORY_BOOT))
#endif			
			kpd_aee_handler(linux_keycode, pressed);
			kpd_backlight_handler(pressed, linux_keycode);
			input_report_key(kpd_input_dev, linux_keycode, pressed);
			input_sync(kpd_input_dev);
			kpd_print("report Linux keycode = %u\n", linux_keycode);
		}
	}
	
	memcpy(kpd_keymap_state, new_state, sizeof(new_state));
	//kpd_print("save new keymap state\n");
#ifdef KPD_AUTOTEST_BY_KP
	if(data == 0)
#endif
	enable_irq(MT_KP_IRQ_ID);
	spin_unlock(&keymap_handler_spinlock);
}

static irqreturn_t kpd_irq_handler(int irq, void *dev_id)
{
	/* use _nosync to avoid deadlock */
	disable_irq_nosync(MT_KP_IRQ_ID);

	tasklet_schedule(&kpd_keymap_tasklet);
	return IRQ_HANDLED;
}

static long kpd_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	void __user *uarg = (void __user *)arg;
	struct kpd_ledctl ledctl;

	switch (cmd) {
#if KPD_AUTOTEST
	case PRESS_OK_KEY://KPD_AUTOTEST disable auto test setting to resolve CR ALPS00464496
		if(test_bit(KEY_OK, kpd_input_dev->keybit)){
		printk("[AUTOTEST] PRESS OK KEY!!\n");
		input_report_key(kpd_input_dev, KEY_OK, 1);
		input_sync(kpd_input_dev);
		}else{
			printk("[AUTOTEST] Not Support OK KEY!!\n");
		}
		break;
	case RELEASE_OK_KEY:
		if(test_bit(KEY_OK, kpd_input_dev->keybit)){
		printk("[AUTOTEST] RELEASE OK KEY!!\n");
		input_report_key(kpd_input_dev, KEY_OK, 0);
		input_sync(kpd_input_dev);
		}else{
			printk("[AUTOTEST] Not Support OK KEY!!\n");
		}
		break;
	case PRESS_MENU_KEY:
		if(test_bit(KEY_MENU, kpd_input_dev->keybit)){
		printk("[AUTOTEST] PRESS MENU KEY!!\n");
		input_report_key(kpd_input_dev, KEY_MENU, 1);
		input_sync(kpd_input_dev);
		}else{
			printk("[AUTOTEST] Not Support MENU KEY!!\n");
		}
		break;
	case RELEASE_MENU_KEY:
		if(test_bit(KEY_MENU, kpd_input_dev->keybit)){
		printk("[AUTOTEST] RELEASE MENU KEY!!\n");
		input_report_key(kpd_input_dev, KEY_MENU, 0);
		input_sync(kpd_input_dev);
		}else{
			printk("[AUTOTEST] Not Support MENU KEY!!\n");
		}

		break;
	case PRESS_UP_KEY:
		if(test_bit(KEY_UP, kpd_input_dev->keybit)){
		printk("[AUTOTEST] PRESS UP KEY!!\n");
		input_report_key(kpd_input_dev, KEY_UP, 1);
		input_sync(kpd_input_dev);
		}else{
			printk("[AUTOTEST] Not Support UP KEY!!\n");
		}
		break;
	case RELEASE_UP_KEY:
		if(test_bit(KEY_UP, kpd_input_dev->keybit)){
		printk("[AUTOTEST] RELEASE UP KEY!!\n");
		input_report_key(kpd_input_dev, KEY_UP, 0);
		input_sync(kpd_input_dev);
		}else{
			printk("[AUTOTEST] Not Support UP KEY!!\n");
		}
		break;
	case PRESS_DOWN_KEY:
		if(test_bit(KEY_DOWN, kpd_input_dev->keybit)){
		printk("[AUTOTEST] PRESS DOWN KEY!!\n");
		input_report_key(kpd_input_dev, KEY_DOWN, 1);
		input_sync(kpd_input_dev);
		}else{
			printk("[AUTOTEST] Not Support DOWN KEY!!\n");
		}
		break;
	case RELEASE_DOWN_KEY:
		if(test_bit(KEY_DOWN, kpd_input_dev->keybit)){
		printk("[AUTOTEST] RELEASE DOWN KEY!!\n");
		input_report_key(kpd_input_dev, KEY_DOWN, 0);
		input_sync(kpd_input_dev);
		}else{
			printk("[AUTOTEST] Not Support DOWN KEY!!\n");
		}
		break;
	case PRESS_LEFT_KEY:
		if(test_bit(KEY_LEFT, kpd_input_dev->keybit)){
		printk("[AUTOTEST] PRESS LEFT KEY!!\n");
		input_report_key(kpd_input_dev, KEY_LEFT, 1);
		input_sync(kpd_input_dev);
		}else{
			printk("[AUTOTEST] Not Support LEFT KEY!!\n");
		}
		break;
	case RELEASE_LEFT_KEY:
		if(test_bit(KEY_LEFT, kpd_input_dev->keybit)){
		printk("[AUTOTEST] RELEASE LEFT KEY!!\n");
		input_report_key(kpd_input_dev, KEY_LEFT, 0);
		input_sync(kpd_input_dev);
		}else{
			printk("[AUTOTEST] Not Support LEFT KEY!!\n");
		}
		break;
	case PRESS_RIGHT_KEY:
		if(test_bit(KEY_RIGHT, kpd_input_dev->keybit)){
		printk("[AUTOTEST] PRESS RIGHT KEY!!\n");
		input_report_key(kpd_input_dev, KEY_RIGHT, 1);
		input_sync(kpd_input_dev);
		}else{
			printk("[AUTOTEST] Not Support RIGHT KEY!!\n");
		}
		break;
	case RELEASE_RIGHT_KEY:
		if(test_bit(KEY_RIGHT, kpd_input_dev->keybit)){
		printk("[AUTOTEST] RELEASE RIGHT KEY!!\n");
		input_report_key(kpd_input_dev, KEY_RIGHT, 0);
		input_sync(kpd_input_dev);
		}else{
			printk("[AUTOTEST] Not Support RIGHT KEY!!\n");
		}
		break;
	case PRESS_HOME_KEY:
		if(test_bit(KEY_HOME, kpd_input_dev->keybit)){
		printk("[AUTOTEST] PRESS HOME KEY!!\n");
		input_report_key(kpd_input_dev, KEY_HOME, 1);
		input_sync(kpd_input_dev);
		}else{
			printk("[AUTOTEST] Not Support HOME KEY!!\n");
		}
		break;
	case RELEASE_HOME_KEY:
		if(test_bit(KEY_HOME, kpd_input_dev->keybit)){
		printk("[AUTOTEST] RELEASE HOME KEY!!\n");
		input_report_key(kpd_input_dev, KEY_HOME, 0);
		input_sync(kpd_input_dev);
		}else{
			printk("[AUTOTEST] Not Support HOME KEY!!\n");
		}
		break;
	case PRESS_BACK_KEY:
		if(test_bit(KEY_BACK, kpd_input_dev->keybit)){
		printk("[AUTOTEST] PRESS BACK KEY!!\n");
		input_report_key(kpd_input_dev, KEY_BACK, 1);
		input_sync(kpd_input_dev);
		}else{
			printk("[AUTOTEST] Not Support BACK KEY!!\n");
		}
		break;
	case RELEASE_BACK_KEY:
		if(test_bit(KEY_BACK, kpd_input_dev->keybit)){
		printk("[AUTOTEST] RELEASE BACK KEY!!\n");
		input_report_key(kpd_input_dev, KEY_BACK, 0);
		input_sync(kpd_input_dev);
		}else{
			printk("[AUTOTEST] Not Support BACK KEY!!\n");
		}
		break;
	case PRESS_CALL_KEY:
		if(test_bit(KEY_CALL, kpd_input_dev->keybit)){
		printk("[AUTOTEST] PRESS CALL KEY!!\n");
		input_report_key(kpd_input_dev, KEY_CALL, 1);
		input_sync(kpd_input_dev);
		}else{
			printk("[AUTOTEST] Not Support CALL KEY!!\n");
		}
		break;
	case RELEASE_CALL_KEY:
		if(test_bit(KEY_CALL, kpd_input_dev->keybit)){
		printk("[AUTOTEST] RELEASE CALL KEY!!\n");
		input_report_key(kpd_input_dev, KEY_CALL, 0);
		input_sync(kpd_input_dev);
		}else{
			printk("[AUTOTEST] Not Support CALL KEY!!\n");
		}
		break;
	case PRESS_ENDCALL_KEY:
		if(test_bit(KEY_ENDCALL, kpd_input_dev->keybit)){
		printk("[AUTOTEST] PRESS ENDCALL KEY!!\n");
		input_report_key(kpd_input_dev, KEY_ENDCALL, 1);
		input_sync(kpd_input_dev);
		}else{
			printk("[AUTOTEST] Not Support ENDCALL KEY!!\n");
		}
		break;
	case RELEASE_ENDCALL_KEY:
		if(test_bit(KEY_ENDCALL, kpd_input_dev->keybit)){
		printk("[AUTOTEST] RELEASE ENDCALL KEY!!\n");
		input_report_key(kpd_input_dev, KEY_ENDCALL, 0);
		input_sync(kpd_input_dev);
		}else{
			printk("[AUTOTEST] Not Support ENDCALL KEY!!\n");
		}
		break;
	case PRESS_VLUP_KEY:
		if(test_bit(KEY_VOLUMEUP, kpd_input_dev->keybit)){
		printk("[AUTOTEST] PRESS VOLUMEUP KEY!!\n");
		input_report_key(kpd_input_dev, KEY_VOLUMEUP, 1);
		input_sync(kpd_input_dev);
		}else{
			printk("[AUTOTEST] Not Support VOLUMEUP KEY!!\n");
		}
		break;
	case RELEASE_VLUP_KEY:
		if(test_bit(KEY_VOLUMEUP, kpd_input_dev->keybit)){
		printk("[AUTOTEST] RELEASE VOLUMEUP KEY!!\n");
		input_report_key(kpd_input_dev, KEY_VOLUMEUP, 0);
		input_sync(kpd_input_dev);
		}else{
			printk("[AUTOTEST] Not Support VOLUMEUP KEY!!\n");
		}
		break;
	case PRESS_VLDOWN_KEY:
		if(test_bit(KEY_VOLUMEDOWN, kpd_input_dev->keybit)){
		printk("[AUTOTEST] PRESS VOLUMEDOWN KEY!!\n");
		input_report_key(kpd_input_dev, KEY_VOLUMEDOWN, 1);
		input_sync(kpd_input_dev);
		}else{
			printk("[AUTOTEST] Not Support VOLUMEDOWN KEY!!\n");
		}
		break;
	case RELEASE_VLDOWN_KEY:
		if(test_bit(KEY_VOLUMEDOWN, kpd_input_dev->keybit)){
		printk("[AUTOTEST] RELEASE VOLUMEDOWN KEY!!\n");
		input_report_key(kpd_input_dev, KEY_VOLUMEDOWN, 0);
		input_sync(kpd_input_dev);
		}else{
			printk("[AUTOTEST] Not Support VOLUMEDOWN KEY!!\n");
		}
		break;
	case PRESS_FOCUS_KEY:
		if(test_bit(KEY_FOCUS, kpd_input_dev->keybit)){
		printk("[AUTOTEST] PRESS FOCUS KEY!!\n");
		input_report_key(kpd_input_dev, KEY_FOCUS, 1);
		input_sync(kpd_input_dev);
		}else{
			printk("[AUTOTEST] Not Support FOCUS KEY!!\n");
		}
		break;
	case RELEASE_FOCUS_KEY:
		if(test_bit(KEY_FOCUS, kpd_input_dev->keybit)){
		printk("[AUTOTEST] RELEASE FOCUS KEY!!\n");
		input_report_key(kpd_input_dev, KEY_FOCUS, 0);
		input_sync(kpd_input_dev);
		}else{
			printk("[AUTOTEST] Not Support RELEASE KEY!!\n");
		}
		break;
	case PRESS_CAMERA_KEY:
		if(test_bit(KEY_CAMERA, kpd_input_dev->keybit)){
		printk("[AUTOTEST] PRESS CAMERA KEY!!\n");
		input_report_key(kpd_input_dev, KEY_CAMERA, 1);
		input_sync(kpd_input_dev);
		}else{
			printk("[AUTOTEST] Not Support CAMERA KEY!!\n");
		}
		break;
	case RELEASE_CAMERA_KEY:
		if(test_bit(KEY_CAMERA, kpd_input_dev->keybit)){
		printk("[AUTOTEST] RELEASE CAMERA KEY!!\n");
		input_report_key(kpd_input_dev, KEY_CAMERA, 0);
		input_sync(kpd_input_dev);
		}else{
			printk("[AUTOTEST] Not Support CAMERA KEY!!\n");
		}
		break;
#endif

	case SET_KPD_BACKLIGHT:
		if (copy_from_user(&ledctl, uarg, sizeof(struct kpd_ledctl)))
			return -EFAULT;

		//kpd_set_backlight(ledctl.onoff, &ledctl.div, &ledctl.duty);
		break;

	case SET_KPD_KCOL:
#ifndef KPD_AUTOTEST_BY_KP
		kpd_auto_test_for_factorymode();
#else
		kpd_kcol_scan_for_factorymode();
#endif		
		printk("[kpd_auto_test_for_factorymode] test performed!!\n");
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

static int kpd_dev_open(struct inode *inode, struct file *file)
{
	return 0;
}

static struct file_operations kpd_dev_fops = {
	.owner		= THIS_MODULE,
	.unlocked_ioctl	= kpd_dev_ioctl,
	.open		= kpd_dev_open,
};

static struct miscdevice kpd_dev = {
	.minor	= MISC_DYNAMIC_MINOR,
	.name	= KPD_NAME,
	.fops	= &kpd_dev_fops,
};

static int kpd_open(struct input_dev *dev)
{
#if KPD_HAS_SLIDE_QWERTY
	bool evdev_flag=false;
	bool power_op=false;
	struct input_handler *handler;
	struct input_handle *handle;
	handle = rcu_dereference(dev->grab);
	if (handle)
	{
		handler = handle->handler;
		if(strcmp(handler->name, "evdev")==0) 
		{
			return -1;
		}	
	}
	else 
	{
		list_for_each_entry_rcu(handle, &dev->h_list, d_node) {
			handler = handle->handler;
			if(strcmp(handler->name, "evdev")==0) 
			{
				evdev_flag=true;
				break;
			}
		}
		if(evdev_flag==false)
		{
			return -1;	
		}	
	}

	power_op = powerOn_slidePin_interface();
	if(!power_op) {
		printk(KPD_SAY "Qwerty slide pin interface power on fail\n");
	} else {
		kpd_print("Qwerty slide pin interface power on success\n");
	}
		
	mt65xx_eint_set_sens(KPD_SLIDE_EINT, KPD_SLIDE_SENSITIVE);
	mt65xx_eint_set_hw_debounce(KPD_SLIDE_EINT, KPD_SLIDE_DEBOUNCE);
	mt65xx_eint_registration(KPD_SLIDE_EINT, true, KPD_SLIDE_POLARITY,
	                         kpd_slide_eint_handler, false);
	                         
	power_op = powerOff_slidePin_interface();
	if(!power_op) {
		printk(KPD_SAY "Qwerty slide pin interface power off fail\n");
	} else {
		kpd_print("Qwerty slide pin interface power off success\n");
	}

#if 0
	/*qwerty slide: GPIO 214. input, mode=EINT, pull enbale, pull select high*/
	mt_set_gpio_mode(214, 2);
	mt_set_gpio_dir(214, 0);
	mt_set_gpio_pull_enable(214, 1);
	mt_set_gpio_pull_select(214, 0);
#endif
#endif	
	return 0;
}





#if 1 // AW9523  扩展键盘IC:

#define GPIO_SIMULATE_I2C

#define AW9523_EINT_GPIO               GPIO144
#define AW9523_EINT_NO                 5  //CUST_EINT_MHALL_NUM	

#define AW9523_RESET_PIN GPIO128

#define KPD_AW9523_SWITCH_DEBOUNCE       10   //50  // 30
#define KPD_AW9523_SWITCH_POLARITY          CUST_EINT_MHALL_POLARITY
#define KPD_AW9523_SWITCH_SENSITIVE      CUST_EINT_EDGE_SENSITIVE  // CUST_EINT_MHALL_SENSITIVE

static void kpd_aw9523_handler(unsigned long data);
static DECLARE_TASKLET(kpd_aw9523_tasklet, kpd_aw9523_handler, 0);
static u8 kpd_aw9523_state = !CUST_EINT_POLARITY_LOW; 

#define LED_SLAVE_ADDR        0xb0//0xB6
//#if defined(GPIO_SIMULATE_I2C)
#define I2C_SDA_GPIO         GPIO114	//GPIO111      // ROW1
#define I2C_SCL_GPIO         GPIO113	//GPIO108      // COL1

typedef enum {
P0_0=0,
P0_1,
P0_2,
P0_3,
P0_4,
P0_5,
P0_6,
P0_7
} P0_Enum;

typedef enum {
P1_0=0,
P1_1,
P1_2, 
P1_3,
P1_4, 
P1_5,
P1_6,
P1_7
} P1_Enum;

#define AW9523_I2C_MAX_LOOP 50

#define Y_NUM  6  
#define X_NUM  6                // has pullup resistor 

//  P0 ---> X_NUM ---> col         input
//  P1 ---> Y_NUM ---> line(row)   output
const P0_Enum COL[X_NUM] =  {P0_0, P0_1, P0_2, P0_3, P0_4, P0_5};
//const P1_Enum Line[Y_NUM] = {P1_2, P1_3, P1_4, P1_5, P1_6, P1_7};  
const P1_Enum Line[Y_NUM] = {P1_0, P1_1, P1_2, P1_3, P1_4, P1_5};  

const u8  aw9523_key[Y_NUM][X_NUM]={
//     1          2          3          4              5              6
/*
	{KEY_7,     KEY_8,    KEY_9, KEY_POUND,         KEY_OK,         KEY_BACK},
	{KEY_4,     KEY_5,      KEY_6,  KEY_STAR		,KEY_1,     KEY_2},
	{KEY_LEFT,  KEY_UP,      KEY_MENU,     KEY_RIGHT,         KEY_DOWN,         KEY_HOME},
	{KEY_A,	KEY_0,   KEY_B, KEY_C,         KEY_D,         KEY_S},		//SCAN here
	{KEY_E,     KEY_F,      KEY_G,     KEY_H,   KEY_I,         KEY_J},
	{KEY_K,     KEY_L,      KEY_M,     KEY_N,         KEY_O,         KEY_P},
*/

	{KEY_F1,     KEY_F2,    KEY_F3, KEY_F4,         KEY_DEL,         KEY_3},
	{KEY_FN,     KEY_0,      KEY_DOT,  KEY_SYM		,KEY_OK,     KEY_ENTER},
	{KEY_7,  KEY_8,      KEY_9,     KEY_POUND,         KEY_TAB,         KEY_BACK},
	{KEY_4,	KEY_5,   KEY_6, KEY_STAR,         KEY_1,         KEY_2},
	{KEY_LEFT,     KEY_UP,      KEY_MENU,     KEY_RIGHT,   KEY_DOWN,         KEY_HOME},
	{KEY_K,     KEY_L,      KEY_M,     KEY_N,         KEY_O,         KEY_S},

};

u8 P0_kbd_used[8]={1, 1, 1, 1, 1, 1, 0, 0};

u8 P1_kbd_used[8]={0, 0, 1, 1, 1, 1, 1, 1}; 

typedef  enum {
    KEY_STATE_PRESSED=0,
    KEY_STATE_RELEASED,
    KEY_STATE_LONGPRESS,
    KEY_STATE_REPEATED, 
    KEY_STATE_NULL 
}TOUCHKEY_STATE;


u8  P0_INT_STATE=0x0;
u8  P1_INT_STATE=0x0;
u8  P0_IN_OUT_STATE=0x0;
u8  P1_IN_OUT_STATE=0x0;
u8  P0_kbd_used_temp=0x0;
u8  pre_x=0x00;
u8  pre_y=0x00;
u8  P0_X[X_NUM];
u8  P1_Y[Y_NUM];
u8  P1_VALUE=0;
u8 KeyBoard_Key=0xFF;
u8 KeyBoard_Key_Previous=0xFF;
TOUCHKEY_STATE KeyBoardKey_State=KEY_STATE_NULL;


u8 DELAY_TIMES=2;

//extern void kpled_ctrl_open(u8 enable);
#define AW9523_delay_1us(ms)     udelay(ms*DELAY_TIMES)


#define GPIO_ModeSetup(x, y)      mt_set_gpio_mode(x, y);
#define GPIO_InitIO(x, y)                mt_set_gpio_dir(y, x)
#define GPIO_WriteIO(x, y)            mt_set_gpio_out(y, x)
#define GPIO_ReadIO(x)                  mt_get_gpio_in(x)


#define I2C_SDA_MODE           mt_set_gpio_mode(I2C_SDA_GPIO, GPIO_MODE_GPIO)
#define I2C_SCL_MODE           mt_set_gpio_mode(I2C_SCL_GPIO, GPIO_MODE_GPIO)
#define I2C_SDA_OUTPUT      mt_set_gpio_dir(I2C_SDA_GPIO, GPIO_DIR_OUT)
#define I2C_SDA_INPUT          mt_set_gpio_dir(I2C_SDA_GPIO, GPIO_DIR_IN)
#define I2C_SCL_OUTPUT       mt_set_gpio_dir(I2C_SCL_GPIO, GPIO_DIR_OUT)
#define I2C_SDA_HIGH            mt_set_gpio_out(I2C_SDA_GPIO, GPIO_OUT_ONE)
#define I2C_SDA_LOW             mt_set_gpio_out(I2C_SDA_GPIO, GPIO_OUT_ZERO)
#define I2C_SCL_HIGH            mt_set_gpio_out(I2C_SCL_GPIO, GPIO_OUT_ONE)
#define I2C_SCL_LOW             mt_set_gpio_out(I2C_SCL_GPIO, GPIO_OUT_ZERO)
#define I2C_SDA_READ           mt_get_gpio_in(I2C_SDA_GPIO)

#define NEW_I2C_TIMING              1


void AW9523_i2c_initial(void)
{
#if NEW_I2C_TIMING
        I2C_SDA_MODE;
	I2C_SCL_MODE;
	I2C_SDA_OUTPUT;
	I2C_SCL_OUTPUT;

   mt_set_gpio_pull_enable(I2C_SDA_GPIO, GPIO_PULL_ENABLE); 
   mt_set_gpio_pull_enable(I2C_SCL_GPIO, GPIO_PULL_ENABLE); 

	I2C_SDA_HIGH;
	I2C_SCL_HIGH;
#else
	GPIO_ModeSetup(I2C_SCL_GPIO, 0);
	GPIO_InitIO(1, I2C_SCL_GPIO);
	mt_set_gpio_pull_enable(I2C_SCL_GPIO, GPIO_PULL_ENABLE);
	GPIO_WriteIO(1, I2C_SCL_GPIO);
	
	GPIO_ModeSetup(I2C_SDA_GPIO, 0);
	GPIO_InitIO(1,I2C_SDA_GPIO);
	mt_set_gpio_pull_enable(I2C_SDA_GPIO, GPIO_PULL_ENABLE);
	GPIO_WriteIO(0, I2C_SDA_GPIO);
	AW9523_delay_1us(5);
	GPIO_WriteIO(1, I2C_SDA_GPIO);//脦陋卤脺脙芒i2c initial 脢卤虏煤脡煤\u017d铆脦贸碌脛脳\u017d脤卢拢卢脧脠路垄脪禄\u017e枚脥拢脰鹿脤玫\u0152镁
#endif
}

void AW9523_Hw_reset(void)
{   

	GPIO_ModeSetup(GPIO74, 0);
	GPIO_InitIO(0, AW9523_RESET_PIN);
	AW9523_delay_1us(50);


	GPIO_ModeSetup(AW9523_RESET_PIN, 0);
	GPIO_InitIO(1, AW9523_RESET_PIN);
	GPIO_WriteIO(0, AW9523_RESET_PIN);
	//kpled_ctrl_open(1);           // Kpled on , then reset be pulled down

	AW9523_delay_1us(200); //\u017e\u017d脦禄脨脜潞脜脦陋碌脥碌莽脝\u0153碌脛鲁脰脨酶脢卤\u0152盲卤脴脨毛脰脕脡脵20us虏脜脛脺脮媒鲁拢\u017e\u017d脦禄  
	GPIO_WriteIO(1, AW9523_RESET_PIN); 
	//kpled_ctrl_open(0);            // Kpled off, then reset be pulled up by VIO18
	//AW9523_delay_1us(30); 
	mdelay(30);
}

static void AW9523_i2c_start(void)
{
#if NEW_I2C_TIMING
        I2C_SDA_MODE;
	I2C_SCL_MODE;
	I2C_SDA_OUTPUT;
	I2C_SCL_OUTPUT;
        //spin_lock_irqsave(&gpio_i2c_spinLock, flags_spin);
	I2C_SDA_HIGH;
	AW9523_delay_1us(5);  //udelay(10); //udelay(100); //mdelay(1); 
	I2C_SCL_HIGH;
	AW9523_delay_1us(5);  //udelay(10); //udelay(100); //mdelay(1); 
	I2C_SDA_LOW;
	AW9523_delay_1us(5);  //udelay(10); //udelay(100); //mdelay(1); 
#else
	GPIO_InitIO(1,I2C_SDA_GPIO);
	GPIO_InitIO(1,I2C_SCL_GPIO);
	
	GPIO_WriteIO(1, I2C_SDA_GPIO);
	GPIO_WriteIO(1, I2C_SCL_GPIO);
	AW9523_delay_1us(2);
	GPIO_WriteIO(0, I2C_SDA_GPIO);
	AW9523_delay_1us(2);	
	GPIO_WriteIO(0, I2C_SCL_GPIO);
	AW9523_delay_1us(2);	
#endif 
}

static void AW9523_i2c_stop(void)
{
#if NEW_I2C_TIMING
	I2C_SDA_OUTPUT;
	I2C_SCL_OUTPUT;
	//spin_lock_irqsave(&gpio_i2c_spinLock, flags_spin);
	I2C_SCL_LOW;   // test @20131009
	AW9523_delay_1us(5);  //udelay(10); //udelay(100); //mdelay(1);     // 20131010
	I2C_SDA_LOW;
	AW9523_delay_1us(5);  //udelay(10); //udelay(100); //mdelay(1); 
	I2C_SCL_HIGH;
	AW9523_delay_1us(5);  //udelay(10); //udelay(100); //mdelay(1); 
	I2C_SDA_HIGH;
        AW9523_delay_1us(5);  //udelay(10); //udelay(100); //mdelay(1); 
#else
	GPIO_InitIO(1,I2C_SDA_GPIO);
	GPIO_InitIO(1,I2C_SCL_GPIO);	
	GPIO_WriteIO(0, I2C_SCL_GPIO);
	AW9523_delay_1us(2);
	GPIO_WriteIO(0, I2C_SDA_GPIO);
	GPIO_WriteIO(1, I2C_SCL_GPIO);
	AW9523_delay_1us(2);
	GPIO_WriteIO(1, I2C_SDA_GPIO);
#endif
}

static char AW9523_i2c_write_byte(unsigned char data)
{
#if NEW_I2C_TIMING

        char  i = 0;
        char times = 0;
	//unsigned long flags_spin;

        //spin_lock_irqsave(&gpio_i2c_spinLock, flags_spin);
        I2C_SCL_LOW;
	AW9523_delay_1us(5);  //udelay(10); //udelay(100); //mdelay(1); 
	I2C_SDA_OUTPUT;

        for(i=0;i<8;i++)
        {
            if((data<<i)&0x80)
                     I2C_SDA_HIGH;
            else
                     I2C_SDA_LOW;               
            AW9523_delay_1us(5);  //udelay(10); //udelay(100); //mdelay(1); 
            I2C_SCL_HIGH;           
            AW9523_delay_1us(5);  //udelay(10); //udelay(100); //mdelay(1); 
            I2C_SCL_LOW;
	    AW9523_delay_1us(5);  //udelay(10); //udelay(100); //mdelay(1); 
        }        

        I2C_SDA_INPUT;
        AW9523_delay_1us(5);  //udelay(10); //udelay(100); //mdelay(1);
	I2C_SCL_HIGH;
	AW9523_delay_1us(5);  //udelay(10); //udelay(100); //mdelay(1); 
	//spin_unlock_irqrestore(&gpio_i2c_spinLock, flags_spin);
	while  (I2C_SDA_READ==1)
	{
	     AW9523_delay_1us(5);  //udelay(10);//return 1;
        times++;
        if (times==10)
          break;
	}
	
	I2C_SCL_LOW;
	AW9523_delay_1us(5);  //udelay(10); //udelay(100); //mdelay(1); 
	
        return 1;

#else

	u8 i;
	char ack;
	
	GPIO_InitIO(1,I2C_SDA_GPIO);
	for	(i=0; i<8; i++)
	{
		if (data & 0x80)
			GPIO_WriteIO(1,I2C_SDA_GPIO);
		else
			GPIO_WriteIO(0,I2C_SDA_GPIO);
		data <<= 1;
		AW9523_delay_1us(1);
		GPIO_WriteIO(1,I2C_SCL_GPIO);
		AW9523_delay_1us(1);
		GPIO_WriteIO(0,I2C_SCL_GPIO);
		AW9523_delay_1us(1);
	}
	GPIO_InitIO(0,I2C_SDA_GPIO);
	AW9523_delay_1us(6);
	GPIO_WriteIO(1,I2C_SCL_GPIO);
	ack = GPIO_ReadIO(I2C_SDA_GPIO); /// ack   
	AW9523_delay_1us(1);
	GPIO_WriteIO(0,I2C_SCL_GPIO);
	return ack;	
#endif
}

static u8 AW9523_i2c_read_byte(void)
{
#if NEW_I2C_TIMING
        u8 rec_byte = 0x00;
	u8 i = 0;

	//I2C_SCL_LOW;
	//mdelay(1); 
	
	for (i=0; i<8; i++)
	{
	      rec_byte <<=1;
	     //I2C_SCL_LOW;
             //mdelay(1);
	     I2C_SCL_HIGH;
	     AW9523_delay_1us(5);  //udelay(10); //udelay(100); //mdelay(1);

	     rec_byte |= I2C_SDA_READ;
	     I2C_SCL_LOW;
             AW9523_delay_1us(5);  //udelay(10); //udelay(100); //mdelay(1);
	}

         I2C_SDA_OUTPUT;
	 I2C_SDA_HIGH;
	 AW9523_delay_1us(5);  //udelay(10); //udelay(100); //mdelay(1);

	 I2C_SCL_HIGH;  
         AW9523_delay_1us(5);  //udelay(10); //udelay(100); //mdelay(1);
	 I2C_SCL_LOW;  
         AW9523_delay_1us(5);  //udelay(10); //udelay(100); //mdelay(1);	
         
	 return rec_byte;
#else
	u8 i;
	u8 bData;
	GPIO_InitIO(0, I2C_SDA_GPIO);
	//脢媒\u0178脻露脕鲁枚
	  bData = 0x00;
	  for (i=0;i<8;i++) {
		  bData <<= 1;
		  AW9523_delay_1us(4);
		  GPIO_WriteIO(1, I2C_SCL_GPIO);
		  if (GPIO_ReadIO(I2C_SDA_GPIO)) {
			  bData |= 0x01;
		  } else {
			  bData &= 0xfe;
		  }
		  AW9523_delay_1us(1);
		   GPIO_WriteIO(0, I2C_SCL_GPIO);
	  }
	  AW9523_delay_1us(1);
	  GPIO_WriteIO(1, I2C_SCL_GPIO);	
	  AW9523_delay_1us(1);
	  GPIO_WriteIO(0, I2C_SCL_GPIO);
	  return bData;
#endif
}

static char AW9523_i2c_write_reg_org(unsigned char reg,unsigned char data)
{
#if NEW_I2C_TIMING
        AW9523_i2c_start();
	AW9523_i2c_write_byte(LED_SLAVE_ADDR);
	AW9523_i2c_write_byte(reg);
	AW9523_i2c_write_byte(data);
	AW9523_i2c_stop();
	return 1;
#else

	char ack=0;
	AW9523_i2c_start();	
	ack|=AW9523_i2c_write_byte(LED_SLAVE_ADDR); 	//write device address
	ack|=AW9523_i2c_write_byte(reg);  	// reg address
	ack|= AW9523_i2c_write_byte(data);	// data
	AW9523_i2c_stop();
	return ack;
#endif

}

static char AW9523_i2c_write_reg(unsigned char reg,unsigned char data)
{
#if NEW_I2C_TIMING
        AW9523_i2c_start();
	AW9523_i2c_write_byte(LED_SLAVE_ADDR);
	AW9523_i2c_write_byte(reg);
	AW9523_i2c_write_byte(data);
	AW9523_i2c_stop();
	return 1;
#else
	char ack=0;
	char i;
	for (i=0;i<AW9523_I2C_MAX_LOOP;i++)
		{
			ack=AW9523_i2c_write_reg_org(reg,data);
			if(ack==0) // ack success
				break;
		}
	return ack;
#endif
}

u8 AW9523_i2c_read_reg(u8 regaddr) 
{
#if NEW_I2C_TIMING
        u8 read_byte = 0;

        AW9523_i2c_start();
        AW9523_i2c_write_byte(LED_SLAVE_ADDR);
	AW9523_i2c_write_byte(regaddr);
	AW9523_i2c_stop();             /
	AW9523_i2c_start();            //restart signal
	AW9523_i2c_write_byte(LED_SLAVE_ADDR|0x01);
	read_byte = AW9523_i2c_read_byte();
	AW9523_i2c_stop();
	return read_byte;
#else
	u8 mask,i, bData;
	char ack1,ack2,ack3;
	u8 i2caddr;
	for (i=0;i<AW9523_I2C_MAX_LOOP;i++)
		{
			AW9523_i2c_start();	
			ack1=AW9523_i2c_write_byte(LED_SLAVE_ADDR); 	//write device address
			ack2=AW9523_i2c_write_byte(regaddr);  	// reg address
			AW9523_i2c_stop();
			AW9523_i2c_start();	
			ack3=AW9523_i2c_write_byte((LED_SLAVE_ADDR|0x01)); 	//write device address
			if((ack1 || ack2 || ack3)==0) // ack success
				break;
		}
	bData=AW9523_i2c_read_byte();
	AW9523_i2c_stop();
    	return bData;
#endif

}

static void AW9523_SDA_Change(void) 
{
	u8 SDA_index = 0;
	GPIO_WriteIO(0,I2C_SDA_GPIO);
	AW9523_delay_1us(80);
	for (SDA_index=0;SDA_index<50;SDA_index++)
		{			
			GPIO_InitIO(0, I2C_SDA_GPIO);
			AW9523_delay_1us(420);  //SDA碌脛脰脺脝脷拢卢\u017e脽碌莽脝\u0153420us拢卢 脭脷\u017e梅脝\u0153脤\u0161脧脗脟毛\u017e霉\u0178脻脰梅脝碌脌\u017d碌梅脮没拢卢卤拢鲁脰脪禄脰脗
			GPIO_InitIO(1, I2C_SDA_GPIO);//SDA碌脛脰脺脝脷拢卢碌脥碌莽脝\u015380us拢卢 脭脷\u017e梅脝\u0153脤\u0161脧脗脟毛\u017e霉\u0178脻脰梅脝碌脌\u017d碌梅脮没拢卢卤拢鲁脰脪禄脰脗
			AW9523_delay_1us(80); //SDA碌脥碌莽脝\u015380us
		}
	GPIO_InitIO(1, I2C_SDA_GPIO);
	GPIO_WriteIO(1,I2C_SDA_GPIO);
	AW9523_delay_1us(420);  
}

char AW9523_POWER_ON(void)
{    // AW9523 POWER-ON拢卢 脟毛驴脥禄搂虏禄脪陋\u017e脛露炉\u017d脣潞炉脢媒
     // 脭脷aw9523_init()脰脨拢卢脧脠\u0153酶脨脨POWER-ON拢卢脭脵\u0153酶脨脨驴脥禄搂脳脭脡铆碌脛脧脿鹿脴虏脵脳梅
	char ack=0;
	u8 count=0;
	AW9523_i2c_initial();
	AW9523_Hw_reset();
	  while(count++ < 120) 		//
			  {
				  if(AW9523_i2c_write_reg_org(0x55,0x55))   //脜脨露脧脫\u0160\u017d冒脛拢脢\u0153隆拢0x55脦陋驴脮\u0152脛\u017d忙脝梅拢卢虏禄禄谩露脭驴脥禄搂脫\u0160脫脙虏煤脡煤脫掳脧矛
					  {
					  AW9523_SDA_Change();
					  continue;
					  }
				  if(AW9523_i2c_write_reg_org(0xaa,0xaa))
					  {
					  AW9523_SDA_Change();
					  continue;
					  }   
				  if(AW9523_i2c_write_reg_org(0x55,0xaa))
					  {
					  AW9523_SDA_Change();
					  continue;
					  } 			  
				  if(AW9523_i2c_write_reg_org(0xaa,0x55)) 
					  {
					  AW9523_SDA_Change();
					  continue;
					  } 			  				  

				  break;				  
			  }
	ack |= AW9523_i2c_write_reg_org(0x55,0x55); 
	ack |= AW9523_i2c_write_reg_org(0xaa,0xaa); 
	//SCI_TRACE_LOW("----AW9523 POWER ON -----end =%d\r\n", count);
	return ack;
}

/*=======================================i2c driver end =================================*/

/*===========================aw9523\u0152脛\u017d忙脝梅碌脛虏脵脳梅\u0153脫驴脷 begin ================================*/
void aw9523_p0_p1_in_out_setting(void)  /* 脡猫脰脙 p0 p1 脢盲脠毛脢盲鲁枚脳\u017d脤卢*/
{
    P0_IN_OUT_STATE=0xFF;
    AW9523_i2c_write_reg(0x04,P0_IN_OUT_STATE);//脡猫脰脙脣霉脫脨P0_\u0153脜脦陋脢盲脠毛脳\u017d脤卢
    P1_IN_OUT_STATE=0x0;
    AW9523_i2c_write_reg(0x05,P1_IN_OUT_STATE);//脡猫脰脙脣霉脫脨P1_\u0153脜脦陋脢盲鲁枚脳\u017d脤卢
}

void aw9523_p0_p1_interrupt_setting(void)   /* 脡猫脰脙 p0 p1 脭脢脨铆脰脨露脧脳\u017d脤卢*/
{
    u8 i=0;
    P0_INT_STATE=0x0; 
    for (i=0;i<X_NUM;i++) {
        P0_INT_STATE=P0_INT_STATE|(1<<COL[i]);//\u017e霉\u0178脻掳\u017d\u0152眉脜脜虏\u0152脌\u017d脡猫脰脙脰脨露脧
    }
    P0_INT_STATE=~P0_INT_STATE;
    AW9523_i2c_write_reg(0x06,P0_INT_STATE);//潞脥掳\u017d\u0152眉脕脨露脭脫\u0160碌脛P0_\u0153脜脭脢脨铆脰脨露脧

    P1_INT_STATE=0xFF;
    AW9523_i2c_write_reg(0x07,P1_INT_STATE);//p1\u0153脜露\u0152虏禄脛脺脰脨露脧

}

void aw9523_p0_int_restore(void)
{
    AW9523_i2c_write_reg(0x06,P0_INT_STATE);

}

void aw9523_P1_int_restore()
{
    AW9523_i2c_write_reg(0x07,P1_INT_STATE);
}

void aw9523_p0_int_disable()
{
    AW9523_i2c_write_reg(0x06, 0xff);
}

void aw9523_p1_int_disable()
{
    AW9523_i2c_write_reg(0x07, 0xff);
}

u8 aw9523_get_p0(void)  
{
    //AW9523_i2c_read_reg(0x01);       //just for test 20131129
    return AW9523_i2c_read_reg(0x00);
}

u8 aw9523_get_p1(void)
{
    return AW9523_i2c_read_reg(0x01);
}

void aw9523_set_p0(u8 data)
{
    AW9523_i2c_write_reg(0x02,data);
}

void aw9523_set_p1(u8 data)
{
    AW9523_i2c_write_reg(0x03,data);
}

void RE_P0_WRITE(u8 P0,u8 data) 
{
	u8 tmp_value;
	tmp_value = AW9523_i2c_read_reg(0x02);
	if(data==1)
	{
		AW9523_i2c_write_reg(0x02,(tmp_value|(1<<P0)));
	}
	else
	{
		AW9523_i2c_write_reg(0x02,(tmp_value&(~(1<<P0))));
	}	
}

void RE_P1_WRITE(u8 P1,u8 data)
{
	u8 tmp_value;
	tmp_value = AW9523_i2c_read_reg(0x03);
	if(data==1)
	{
		AW9523_i2c_write_reg(0x03,(tmp_value|(1<<P1)));
	}
	else
	{
		AW9523_i2c_write_reg(0x03,(tmp_value&(~(1<<P1))));
	}	
}

void aw9523_keylight_open(u8 enable)
{
        if (enable)
        {
              AW9523_i2c_write_reg(0x20, 0x40);       // led current P1_0
              AW9523_i2c_write_reg(0x21, 0x40);       // led current P1_1
              
              AW9523_i2c_write_reg(0x13, 0xFf);       // P1_0, P1_1 working mode
        }
	else
	{
              AW9523_i2c_write_reg(0x20, 0x00);       // led current P1_0
              AW9523_i2c_write_reg(0x21, 0x00);       // led current P1_1

              AW9523_i2c_write_reg(0x13, 0xFf);       // P1_0, P1_1 working mode			  
	}
}

#include <mach/mt_pm_ldo.h>

#define SCAN_GPIO    GPIO30           
#define SCAN_POWER_GPIO    GPIO134           
#define SCAN_POWER2_GPIO    GPIO110

void SCAN_init(void)
{
/*
	GPIO_ModeSetup(SCAN_POWER_GPIO, 0);
	GPIO_InitIO(1, SCAN_POWER_GPIO);
	GPIO_WriteIO(1, SCAN_POWER_GPIO);
	
	GPIO_ModeSetup(SCAN_POWER2_GPIO, 0);
	GPIO_InitIO(1, SCAN_POWER2_GPIO);
	GPIO_WriteIO(1, SCAN_POWER2_GPIO);

    hwPowerDown(MT6323_POWER_LDO_VGP2, "TP");
    hwPowerOn(MT6323_POWER_LDO_VGP2, VOL_1800, "TP");
	
    hwPowerDown(MT6323_POWER_LDO_VGP1, "TP");
    hwPowerOn(MT6323_POWER_LDO_VGP1, VOL_3300, "TP");


	GPIO_ModeSetup(SCAN_GPIO, 0);
	GPIO_InitIO(1, SCAN_GPIO);
	GPIO_WriteIO(1, SCAN_GPIO);
*/	
}

void SCAN_test(void)
{
   printk("\===== SCAN_test\r\n");

	GPIO_ModeSetup(SCAN_GPIO, 0);
	GPIO_InitIO(1, SCAN_GPIO);
	GPIO_WriteIO(1, SCAN_GPIO);
	mdelay(20);

	GPIO_ModeSetup(SCAN_POWER_GPIO, 0);
	GPIO_InitIO(1, SCAN_POWER_GPIO);
	GPIO_WriteIO(1, SCAN_POWER_GPIO);
	
	GPIO_ModeSetup(SCAN_POWER2_GPIO, 0);
	GPIO_InitIO(1, SCAN_POWER2_GPIO);
	GPIO_WriteIO(1, SCAN_POWER2_GPIO);

    hwPowerDown(MT6323_POWER_LDO_VGP2, "TP");
    hwPowerOn(MT6323_POWER_LDO_VGP2, VOL_1800, "TP");
	
    hwPowerDown(MT6323_POWER_LDO_VGP1, "TP");
    hwPowerOn(MT6323_POWER_LDO_VGP1, VOL_3300, "TP");


	mdelay(100);
   
	
	GPIO_WriteIO(0, SCAN_GPIO);
	mdelay(1500);

	GPIO_WriteIO(1, SCAN_GPIO);
	mdelay(100);
	
    hwPowerDown(MT6323_POWER_LDO_VGP1, "TP");
    hwPowerDown(MT6323_POWER_LDO_VGP1, "TP");
    hwPowerDown(MT6323_POWER_LDO_VGP1, "TP");
    hwPowerDown(MT6323_POWER_LDO_VGP1, "TP");

	//GPIO_WriteIO(1, SCAN_GPIO);

}


EXPORT_SYMBOL(SCAN_init);
EXPORT_SYMBOL(SCAN_test);

void trig_scan_evel(int level)
{
#if 0
	SCAN_test();

#else
	printk("\===== SCAN_test\r\n");

	GPIO_ModeSetup(SCAN_GPIO, 0);
	GPIO_InitIO(1, SCAN_GPIO);
	GPIO_WriteIO(1, SCAN_GPIO);
	mdelay(20);

	GPIO_ModeSetup(SCAN_POWER_GPIO, 0);
	GPIO_InitIO(1, SCAN_POWER_GPIO);
	GPIO_WriteIO(1, SCAN_POWER_GPIO);

	GPIO_ModeSetup(SCAN_POWER2_GPIO, 0);
	GPIO_InitIO(1, SCAN_POWER2_GPIO);
	GPIO_WriteIO(1, SCAN_POWER2_GPIO);

	if(level > 0)
	{		
	    hwPowerDown(MT6323_POWER_LDO_VGP2, "TP");
	    hwPowerOn(MT6323_POWER_LDO_VGP2, VOL_1800, "TP");
		
	    hwPowerDown(MT6323_POWER_LDO_VGP1, "TP");
	    hwPowerOn(MT6323_POWER_LDO_VGP1, VOL_3300, "TP");

		mdelay(200);
	   	
		GPIO_WriteIO(0, SCAN_GPIO);
		mdelay(100);
	}
	else
	{		
		GPIO_WriteIO(1, SCAN_GPIO);
		mdelay(100);
		
	    hwPowerDown(MT6323_POWER_LDO_VGP1, "TP");
	    hwPowerDown(MT6323_POWER_LDO_VGP1, "TP");
	    hwPowerDown(MT6323_POWER_LDO_VGP1, "TP");
	    hwPowerDown(MT6323_POWER_LDO_VGP1, "TP");
	}
#endif	
}



void aw9523_test(void)
{
// i2c_initial();  
//	 AW9523_Hw_reset();
//	 AW9523_i2c_initial();
   printk("\===== naw9523_test_entry=\r\n");
   printk("\===== naw9523_i2c_read_reg_0x00=0x%x\r\n",AW9523_i2c_read_reg(0x00));
   printk("\===== naw9523_i2c_read_reg_0x01=0x%x\r\n",AW9523_i2c_read_reg(0x01)); 
   printk("\===== naw9523_i2c_read_reg_0x02=0x%x\r\n",AW9523_i2c_read_reg(0x02));
   printk("\===== naw9523_i2c_read_reg_0x03=0x%x\r\n",AW9523_i2c_read_reg(0x03)); 
   printk("\===== naw9523_i2c_read_reg_0x04=0x%x\r\n",AW9523_i2c_read_reg(0x04));
   printk("\===== naw9523_i2c_read_reg_0x05=0x%x\r\n",AW9523_i2c_read_reg(0x05)); 
   printk("\===== naw9523_i2c_read_reg_0x06=0x%x\r\n",AW9523_i2c_read_reg(0x06));
   printk("\===== naw9523_i2c_read_reg_0x07=0x%x\r\n",AW9523_i2c_read_reg(0x07));    
   printk("\===== naw9523_i2c_read_reg_0x10=0x%x\r\n",AW9523_i2c_read_reg(0x10));    
   printk("\===== naw9523_i2c_read_reg_0x11=0x%x\r\n",AW9523_i2c_read_reg(0x11));    
   printk("\===== naw9523_i2c_read_reg_0x12=0x%x\r\n",AW9523_i2c_read_reg(0x12));
   printk("\===== naw9523_i2c_read_reg_0x13=0x%x\r\n",AW9523_i2c_read_reg(0x13));   
}

 void aw9523_set_p1_gpio_mode(void)
 {
	 AW9523_i2c_write_reg(0x13,0xff);
 }

void aw9523_init()
{
	//AW9523_POWER_ON();          // test new i2c timing , delete this code 
	//GPIO_ModeSetup(GPIO73, 0);
	//GPIO_InitIO(1, GPIO73);
	//GPIO_WriteIO(0, GPIO73);
	printk("======= aw9523_init\n");

        AW9523_i2c_initial();
        AW9523_Hw_reset();  
		
#if 1
        AW9523_i2c_write_reg(0x7F, 0x00);   // sw reset
        mdelay(10);

        aw9523_keylight_open(0);        // close P1_0, P1_1 mos fet
		
        aw9523_p0_int_disable(); 

		aw9523_set_p1_gpio_mode();

		//liubiao
        aw9523_p0_p1_in_out_setting();
        aw9523_p0_p1_interrupt_setting();
        aw9523_set_p1(P1_VALUE);
        AW9523_i2c_read_reg(0x00); 
        AW9523_i2c_read_reg(0x01);    
#endif
}

void Set_P0_X_AND_P1_Y(void) 
{
    u8 i=0;
    u8 temp=0;
    for (i=0;i<X_NUM;i++) {
        temp=temp|(1<<COL[i]);
  }
    //SCI_TRACE_LOW("temp=%x\r\n",temp);

    for (i=0;i<X_NUM;i++) {
        P0_X[i]=temp&(~(1<<COL[i]));
        //SCI_TRACE_LOW("P0_X[%d]=%x\r\n",i,P0_X[i]);
    }

    temp=0;
    for (i=0;i<Y_NUM;i++) {
        temp=temp|(1<<Line[i]);
    }
    //SCI_TRACE_LOW("temp=%x\r\n",temp);
    for (i=0;i<Y_NUM;i++) {
        P1_Y[i]=temp&(~(1<<Line[i]));
        //SCI_TRACE_LOW("P1_Y[%d]=%x\r\n",i,P1_Y[i]);
    }
   
   	for(i=0;i<8;i++)
	{
		if(P0_kbd_used[i]==1)
		{
			P0_kbd_used_temp|=1<<i;
		}
	}
    //SCI_TRACE_LOW("P0_kbd_used_temp=%x\r\n",P0_kbd_used_temp);
}

u8 keyboard_get_press_key(void)
{
    u8 x=0xFF,y=0XFF;
    u8 i=0,j=0,k=0;
    u8 get_p0=0xff; 
	
    get_p0=aw9523_get_p0();
    i=(get_p0)|(~(P0_kbd_used_temp));  //脦\u017d脫脙脳枚\u0152眉脜脤脡\u0161脙猫碌脛P0驴脷,脝盲露脕鲁枚碌脛脰碌卤禄脝脕卤脦
    //i=get_p0 & P0_kbd_used_temp;  //脦\u017d脫脙脳枚\u0152眉脜脤脡\u0161脙猫碌脛P0驴脷,脝盲露脕鲁枚碌脛脰碌卤禄脝脕卤脦
    //SCI_TRACE_LOW("===aw9523_get_p0()===%x\r\n",get_p0);
    if (i==0xff) 
    {
    	//  SCI_TRACE_LOW("------get_key=0xff----\r\n");	
        return 0xFF;
    }
    else 
    {
    //SCI_TRACE_LOW("===aw9523_get_p0()===%x\r\n",i);    
       if(KeyBoardKey_State==KEY_STATE_PRESSED || KeyBoardKey_State==KEY_STATE_LONGPRESS)
	{
        	//脠莽鹿没脰庐脟掳脢脟\u017d\u0160脫脷脫脨掳\u017d\u0152眉碌脛脳\u017d脤卢,脭貌脰卤\u0153脫脠楼\u0152矛虏芒脮芒\u017e枚掳\u017d\u0152眉脢脟路帽脢脥路脜
     	 //SCI_TRACE_LOW("------press or longpress entry ,pre_x=%d,pre_y=%d ----\r\n",pre_x,pre_y); 
     	 	AW9523_i2c_write_reg(0x05,P1_Y[pre_y]);
     	 	get_p0=aw9523_get_p0(); 
          //i=get_p0 & P0_kbd_used_temp;
              if  ((get_p0&(1<<COL[pre_x])) == 0)
		{
         	   AW9523_i2c_write_reg(0x05,P1_VALUE); 
         	   return aw9523_key[pre_y][pre_x];
		}
              else 
         	{
         	   AW9523_i2c_write_reg(0x05,P1_VALUE);
         	   return 0xFF;
         	}
        } 
        else 
	 {
   	//\u0152矛虏芒掳\u017d\u0152眉碌脛鲁脤脨貌脠毛驴脷
           for (j=0;j<X_NUM;j++) 
	    {
    	        if((i&(1<<COL[j]))==0)
		 {
        //if (i==P0_X[j]) {
            //卤\u0178脌媒脰脨P0_X[0:7]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f},
            //脠么露脕鲁枚碌脛P0_脰碌脛鲁脪禄脦禄脦陋0拢卢脭貌脜脨露脧鲁枚掳\u017d脧脗碌脛脢脟脮芒脪禄脕脨
                  x=j;
                  break;
               }
           }
		   
           if (x==0xFF) 
	    {
       // SCI_TRACE_LOW("------get_key=0xff----\r\n");	
              return 0xFF;
           }
		   
	    for (j=0;j<Y_NUM;j++) 
	    {
           // aw9523_set_p1(P1_Y[j]); 
             AW9523_i2c_write_reg(0x05,P1_Y[j]);
            /*脗脰脩炉脡\u0161脙猫隆拢脪脌\u017d脦\u0153芦脛鲁脪禄脨脨P1脰碌脰脙0拢卢脝盲脣没脨脨脰脙1禄貌\u017e脽脳猫拢卢脙驴脡\u0161脙猫脪禄脨脨脢卤拢卢露\u0152露脕脪禄\u017d脦P0脰碌
            碌卤脡\u0161脙猫碌\u0153脛鲁脪禄脨脨脢卤拢卢脠么露脕鲁枚碌脛P0脰碌脫毛脰庐脟掳脜脨露脧碌\u0153碌脛P0脰碌脧脿碌脠拢卢脭貌脜脨露脧鲁枚掳\u017d脧脗碌脛脢脟脮芒脪禄脨脨 */
             get_p0=aw9523_get_p0(); 
             k=(get_p0)|(~(P0_kbd_used_temp));           
          // if (k==P0_X[x]) { 
             if ((k&(1<<COL[x]))==0)
	      {	
                y=j;
                break;
             }
           }
        //aw9523_set_p1(P1_VALUE);
           AW9523_i2c_write_reg(0x05,P1_VALUE);
          // get_p0=aw9523_get_p0(); 
          // k=get_p0 & P0_kbd_used_temp; 
        //SCI_TRACE_LOW("------get_key: x=%d,y=%d----\r\n",x,y);
           if (x!=0xFF && y!=0xFF ) 
	    {
        	  pre_x=x;
        	  pre_y=y;
                return aw9523_key[y][x];
           }
	    else 
	    {
                return 0xFF;
           }
     }}
} 

static void kpd_aw9523_handler(unsigned long data)
{
	//bool pressed;
	u8 old_state = kpd_aw9523_state;
        //static u8 flag = 1;

        //mt65xx_eint_set_polarity(AW9523_EINT_NO, old_state);
        aw9523_p0_int_disable();
        disable_irq(MT_KP_IRQ_ID);
        mt_eint_mask(AW9523_EINT_NO);  // mt65xx_eint_mask(AW9523_EINT_NO);
	//aw9523_p0_int_disable();
	printk("====== kpd_aw9523_handler state=%d\n", kpd_aw9523_state);
	
        //printk("\n<<<<  xxx==kpd_aw9523_handler state=%d\n", kpd_aw9523_state);
        //mt65xx_eint_unmask(AW9523_EINT_NO);
	kpd_aw9523_state = !kpd_aw9523_state;

		#if 0
         if (kpd_aw9523_state!=KPD_AW9523_SWITCH_POLARITY)
         {

	    mt65xx_eint_set_polarity(AW9523_EINT_NO, old_state);
	    enable_irq(MT_KP_IRQ_ID);	
	    mt65xx_eint_unmask(AW9523_EINT_NO);

            aw9523_p0_int_restore();   

	    return;
         }
		 #endif
		
        printk("\n<<<<  ==== key =%d  pressed=======\r\n",keyboard_get_press_key());
        KeyBoard_Key=keyboard_get_press_key();	//KEY_HOME;
        printk("\n<<<<  === aw9523_handler==key =%d  pressed,old_state=%d==\r\n",KeyBoard_Key, old_state);
/*
		if(KeyBoard_Key==158)
			KeyBoard_Key=KEY_3;
*/			
		//if(KeyBoard_Key==232)
		//	KeyBoard_Key=KEY_DEL;

		//if(((KeyBoard_Key>1)&&(KeyBoard_Key<12))||(KeyBoard_Key==103)||(KeyBoard_Key==105)||(KeyBoard_Key==106)||(KeyBoard_Key==108))
		//if((KeyBoard_Key>1)&&(KeyBoard_Key<12))
		//if(KeyBoard_Key==KEY_S)
		//	SCAN_test();


		//if(KeyBoard_Key==KEY_STAR)
		//	trig_scan_evel(1);
		//if(KeyBoard_Key==KEY_POUND)
		//	trig_scan_evel(0);
		

        if (KeyBoardKey_State==KEY_STATE_NULL||KeyBoardKey_State==KEY_STATE_RELEASED) 
        {
            if (KeyBoard_Key!=0xFF) 
	    {
               KeyBoardKey_State=KEY_STATE_PRESSED;

               KeyBoard_Key_Previous=KeyBoard_Key;
	       input_report_key(kpd_input_dev, KeyBoard_Key, 1);
	       input_sync(kpd_input_dev);

            }
       } 
       else if (KeyBoardKey_State==KEY_STATE_PRESSED) 
       {
            if (KeyBoard_Key != KeyBoard_Key_Previous) 
	    {
                KeyBoardKey_State=KEY_STATE_RELEASED;
		//---
		input_report_key(kpd_input_dev, KeyBoard_Key_Previous, 0); //发送键值
	        input_sync(kpd_input_dev); //同步
	        //-----
             }
        } 
  //      */

        AW9523_i2c_write_reg(0x05,P1_VALUE);

	enable_irq(MT_KP_IRQ_ID);	
	mt_eint_unmask(AW9523_EINT_NO);  // mt65xx_eint_unmask(AW9523_EINT_NO);

        aw9523_p0_int_restore();  
		
		AW9523_i2c_read_reg(0x00);
		AW9523_i2c_read_reg(0x01);


#if 0
		aw9523_test();
#endif

        //mt65xx_eint_set_polarity(AW9523_EINT_NO, old_state);
}

static void kpd_aw9523_eint_handler(void)
{
	printk("===== kpd_aw9523_eint_handler\n");

        //printk("\nxxx==kpd_halldet_eint_handler===\n");
	tasklet_schedule(&kpd_aw9523_tasklet);
}

#endif

static int kpd_pdrv_probe(struct platform_device *pdev)
{
	
	int i, r;
	int err = 0;

		printk("===== kpd_pdrv_probe\n");

	
//#ifdef CONFIG_MTK_LDVT	
//unsigned int a, c, j;
//unsigned int addr[]= {0x0502, 0xc0d8, 0xc0e0, 0xc0e8, 0xc0f0, 0xc048};
//unsigned int data[]= {0x4000, 0x1249, 0x1249, 0x1249, 0x0009, 0x00ff};
//	
//for(j = 0; j < 6; j++) {
// a = pwrap_read(addr[j],&c);
// if(a != 0)
// 	printk("kpd read fail, addr: 0x%x\n", addr[j]);
// 	printk("kpd read addr: 0x%x: data:0x%x\n",addr[j], c);
// a = pwrap_write(addr[j],data[j]);
// if(a != 0)
// 	printk("kpd write fail, addr: 0x%x\n", addr[j]);	
// a = pwrap_read(addr[j],&c);
// if(a != 0)
// 	printk("kpd read fail, addr: 0x%x\n", addr[j]);
// printk("kpd read addr: 0x%x: data:0x%x\n",addr[j], c);
//}
//
	*(volatile u16 *)(KP_PMIC) = 0x1;
	printk("kpd register for pmic set!\n");
//#endif

	/* initialize and register input device (/dev/input/eventX) */
	kpd_input_dev = input_allocate_device();
	if (!kpd_input_dev)
		return -ENOMEM;

	kpd_input_dev->name = KPD_NAME;
	kpd_input_dev->id.bustype = BUS_HOST;
	kpd_input_dev->id.vendor = 0x2454;
	kpd_input_dev->id.product = 0x6572;
	kpd_input_dev->id.version = 0x0010;
	kpd_input_dev->open = kpd_open;

	__set_bit(EV_KEY, kpd_input_dev->evbit);

#if (KPD_PWRKEY_USE_EINT||KPD_PWRKEY_USE_PMIC)
	__set_bit(KPD_PWRKEY_MAP, kpd_input_dev->keybit);
	kpd_keymap[8] = 0;
#endif
	for (i = 17; i < KPD_NUM_KEYS; i += 9)	/* only [8] works for Power key */
		kpd_keymap[i] = 0;

	for (i = 0; i < KPD_NUM_KEYS; i++) {
		if (kpd_keymap[i] != 0)
			__set_bit(kpd_keymap[i], kpd_input_dev->keybit);
	}

#if KPD_AUTOTEST
	for (i = 0; i < ARRAY_SIZE(kpd_auto_keymap); i++)
		__set_bit(kpd_auto_keymap[i], kpd_input_dev->keybit);
#endif

#if KPD_HAS_SLIDE_QWERTY
	__set_bit(EV_SW, kpd_input_dev->evbit);
	__set_bit(SW_LID, kpd_input_dev->swbit);
#endif

#ifdef KPD_PMIC_RSTKEY_MAP
	__set_bit(KPD_PMIC_RSTKEY_MAP, kpd_input_dev->keybit);
#endif

	kpd_input_dev->dev.parent = &pdev->dev;
	r = input_register_device(kpd_input_dev);
	if (r) {
		printk(KPD_SAY "register input device failed (%d)\n", r);
		input_free_device(kpd_input_dev);
		return r;
	}

	/* register misc device (/dev/mtk-kpd) */
	kpd_dev.parent = &pdev->dev;
	r = misc_register(&kpd_dev);
	if (r) {
		printk(KPD_SAY "register device failed (%d)\n", r);
		input_unregister_device(kpd_input_dev);
		return r;
	}

	/* register IRQ and EINT */
	kpd_set_debounce(KPD_KEY_DEBOUNCE);
	r = request_irq(MT_KP_IRQ_ID, kpd_irq_handler, IRQF_TRIGGER_FALLING, KPD_NAME, NULL);
	if (r) {
		printk(KPD_SAY "register IRQ failed (%d)\n", r);
		misc_deregister(&kpd_dev);
		input_unregister_device(kpd_input_dev);
		return r;
	}


#if 0	//KPD_PWRKEY_USE_EINT
	mt65xx_eint_set_sens(KPD_PWRKEY_EINT, KPD_PWRKEY_SENSITIVE);
	mt65xx_eint_set_hw_debounce(KPD_PWRKEY_EINT, KPD_PWRKEY_DEBOUNCE);
	mt65xx_eint_registration(KPD_PWRKEY_EINT, true, KPD_PWRKEY_POLARITY,
	                         kpd_pwrkey_eint_handler, false);
#endif





#if 1
	printk("===== AW9523 probe\n");

	GPIO_ModeSetup(SCAN_GPIO, 0);
	GPIO_InitIO(1, SCAN_GPIO);
	GPIO_WriteIO(1, SCAN_GPIO);

    mt_set_gpio_mode(AW9523_EINT_GPIO, GPIO_MODE_03);
    mt_set_gpio_dir(AW9523_EINT_GPIO, GPIO_DIR_IN);
    mt_set_gpio_pull_enable(AW9523_EINT_GPIO, GPIO_PULL_ENABLE); //To disable GPIO PULL.

    Set_P0_X_AND_P1_Y();
    aw9523_init();

	mt_eint_set_sens(AW9523_EINT_NO, KPD_AW9523_SWITCH_SENSITIVE);
	mt_eint_set_hw_debounce(AW9523_EINT_NO, KPD_AW9523_SWITCH_DEBOUNCE);
	mt_eint_registration(AW9523_EINT_NO, EINTF_TRIGGER_FALLING, kpd_aw9523_eint_handler, false);
	mt_eint_unmask(AW9523_EINT_NO);
#endif




#ifndef KPD_EARLY_PORTING /*add for avoid early porting build err the macro is defined in custom file*/
/*long press reboot function realize*/
	if(kpd_enable_lprst && get_boot_mode() == NORMAL_BOOT) {
		kpd_print("Normal Boot long press reboot selection\n");
		upmu_set_rg_pwrkey_rst_en(0x00);//pmic package function for long press reboot function setting
		upmu_set_rg_homekey_rst_en(0x00);		
		
	#ifdef CONFIG_ONEKEY_REBOOT_NORMAL_MODE
		kpd_print("Enable ONE KEY normal mode LPRST\n");
		upmu_set_rg_pwrkey_rst_en(0x01);//pmic_config_interface(TOP_RST_MISC, 0x01, PMIC_RG_PWRKEY_RST_EN_MASK, PMIC_RG_PWRKEY_RST_EN_SHIFT);
		upmu_set_rg_pwrkey_rst_td(CONFIG_KPD_PMIC_LPRST_TD);
	#endif
	#ifdef CONFIG_TWOKEY_REBOOT_NORMAL_MODE
		kpd_print("Enable TWO KEY normal mode LPRST\n");
		upmu_set_rg_pwrkey_rst_en(0x01);//pmic package function for long press reboot function setting//pmic_config_interface(TOP_RST_MISC, 0x01, PMIC_RG_PWRKEY_RST_EN_MASK, PMIC_RG_PWRKEY_RST_EN_SHIFT);
		upmu_set_rg_homekey_rst_en(0x01);//pmic_config_interface(TOP_RST_MISC, 0x01, PMIC_RG_HOMEKEY_RST_EN_MASK, PMIC_RG_HOMEKEY_RST_EN_SHIFT);
		//upmu_set_rg_homekey_puen(0x01);//pmic_config_interface(GPIO_SMT_CON3,0x01, PMIC_RG_HOMEKEY_PUEN_MASK, PMIC_RG_HOMEKEY_PUEN_SHIFT);//pull up homekey pin of PMIC for 89 project
		upmu_set_rg_pwrkey_rst_td(CONFIG_KPD_PMIC_LPRST_TD);
	#endif
	} 
	else {
		kpd_print("Other Boot Mode long press reboot selection\n");
		upmu_set_rg_pwrkey_rst_en(0x00);//pmic package function for long press reboot function setting
		upmu_set_rg_homekey_rst_en(0x00);		
	
	#ifdef CONFIG_ONEKEY_REBOOT_OTHER_MODE
		kpd_print("Enable ONE KEY other mode LPRST\n");
		upmu_set_rg_pwrkey_rst_en(0x01);//pmic_config_interface(TOP_RST_MISC, 0x01, PMIC_RG_PWRKEY_RST_EN_MASK, PMIC_RG_PWRKEY_RST_EN_SHIFT);
		upmu_set_rg_pwrkey_rst_td(CONFIG_KPD_PMIC_LPRST_TD);
	#endif	
	#ifdef CONFIG_TWOKEY_REBOOT_OTHER_MODE
		kpd_print("Enable TWO KEY other mode LPRST\n");
		upmu_set_rg_pwrkey_rst_en(0x01);//pmic package function for long press reboot function setting//pmic_config_interface(TOP_RST_MISC, 0x01, PMIC_RG_PWRKEY_RST_EN_MASK, PMIC_RG_PWRKEY_RST_EN_SHIFT);
		upmu_set_rg_homekey_rst_en(0x01);//pmic_config_interface(TOP_RST_MISC, 0x01, PMIC_RG_HOMEKEY_RST_EN_MASK, PMIC_RG_HOMEKEY_RST_EN_SHIFT);
		//upmu_set_rg_homekey_puen(0x01);//pmic_config_interface(GPIO_SMT_CON3,0x01, PMIC_RG_HOMEKEY_PUEN_MASK, PMIC_RG_HOMEKEY_PUEN_SHIFT);//pull up homekey pin of PMIC for 89 project
		upmu_set_rg_pwrkey_rst_td(CONFIG_KPD_PMIC_LPRST_TD);
	#endif
	}
	/*
	int reg;
	pmic_read_interface(TOP_RST_MISC, &reg, PMIC_RG_PWRKEY_RST_TD_MASK, PMIC_RG_PWRKEY_RST_TD_SHIFT);
	kpd_print("long press reboot time value reg = %d\n", reg);
	*/
#endif	
	hrtimer_init(&aee_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
	aee_timer.function = aee_timer_func;

#if AEE_ENABLE_5_15
    hrtimer_init(&aee_timer_5s, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
    aee_timer_5s.function = aee_timer_5s_func;


#endif

	if((err = kpd_create_attr(&kpd_pdrv.driver)))
	{
		kpd_print("create attr file fail\n");
		kpd_delete_attr(&kpd_pdrv.driver);
		return err;
	}

/**********************disable kpd as wake up source operation********************************/
	#ifndef EVB_PLATFORM
	kpd_print("disable kpd as wake up source operation!\n");
	upmu_set_rg_smps_autoff_dis(0x00);
	#endif
/****************************************************************************************/


#if 0
	/* KCOL0: GPIO103: KCOL1: GPIO108, KCOL2: GPIO105 input + pull enable + pull up */
	mt_set_gpio_mode(103, 1);
	mt_set_gpio_dir(103, 0);
	mt_set_gpio_pull_enable(103, 1);
	mt_set_gpio_pull_select(103, 1);
	
	
	mt_set_gpio_mode(108, 1);
	mt_set_gpio_dir(108, 0);
	mt_set_gpio_pull_enable(108, 1);
	mt_set_gpio_pull_select(108, 1);
	
	mt_set_gpio_mode(105, 1);
	mt_set_gpio_dir(105, 0);
	mt_set_gpio_pull_enable(105, 1);
	mt_set_gpio_pull_select(105, 1);
	/* KROW0: GPIO98, KROW1: GPIO97: KROW2: GPIO95 output + pull disable + pull down */
	mt_set_gpio_mode(98, 1);
	mt_set_gpio_dir(98, 1);
	mt_set_gpio_pull_enable(98, 0);	
	mt_set_gpio_pull_select(98, 0);
	
	mt_set_gpio_mode(97, 1);
	mt_set_gpio_dir(97, 1);
	mt_set_gpio_pull_enable(97, 0);	
	mt_set_gpio_pull_select(97, 0);
	
	mt_set_gpio_mode(95, 1);
	mt_set_gpio_dir(95, 1);
	mt_set_gpio_pull_enable(95, 0);		
	mt_set_gpio_pull_select(95, 0);
#endif
	return 0;
}

/* should never be called */
static int kpd_pdrv_remove(struct platform_device *pdev)
{
	return 0;
}

#define MTK_KP_WAKESOURCE//this is for auto set wake up source
static int incall = 0;//this is for whether phone in call state judgement when resume

#ifndef CONFIG_HAS_EARLYSUSPEND
static int kpd_pdrv_suspend(struct platform_device *pdev, pm_message_t state)
{
	kpd_suspend = true;
#ifdef MTK_KP_WAKESOURCE
	#if 0 // TODO: check whether need to enable in 6572
	if(call_status == 2){
		if(incall == 0){
			kpd_print("kpd_early_suspend wake up source enable!! (%d)\n", kpd_suspend);
			upmu_set_rg_smps_autoff_dis(0x01);
			incall = 1;
			}
		//if(incall == 1){}
	}else{
		//if(incall == 0){}
		if(incall == 1){
			kpd_print("kpd_early_resume wake up source disable!! (%d)\n", kpd_suspend);
			upmu_set_rg_smps_autoff_dis(0x00);
			incall = 0;
			}
	}
	#endif
#endif		
	kpd_disable_backlight();
	kpd_print("suspend!! (%d)\n", kpd_suspend);
	return 0;
}

static int kpd_pdrv_resume(struct platform_device *pdev)
{
	kpd_suspend = false;
	//kpd_enable_backlight();
	kpd_print("resume!! (%d)\n", kpd_suspend);
	return 0;
}
#else
#define kpd_pdrv_suspend	NULL
#define kpd_pdrv_resume		NULL
#endif

#ifdef CONFIG_HAS_EARLYSUSPEND
static void kpd_early_suspend(struct early_suspend *h)
{
	kpd_suspend = true;
#ifdef MTK_KP_WAKESOURCE
	#if 0 // FIXME: check whether need to enable in 6572
	if(call_status == 2){
		if(incall == 0){
			kpd_print("kpd_early_suspend wake up source enable!! (%d)\n", kpd_suspend);
			upmu_set_rg_smps_autoff_dis(0x01);
			incall = 1;
			}
		//if(incall == 1){}
	}else{
		//if(incall == 0){}
		if(incall == 1){
			kpd_print("kpd_early_resume wake up source disable!! (%d)\n", kpd_suspend);
			upmu_set_rg_smps_autoff_dis(0x00);
			incall = 0;
			}
	}
	#endif
#endif	
	kpd_disable_backlight();
	kpd_print("early suspend!! (%d)\n", kpd_suspend);
}

static void kpd_early_resume(struct early_suspend *h)
{
	kpd_suspend = false;
	//kpd_enable_backlight();
	kpd_print("early resume!! (%d)\n", kpd_suspend);
}

static struct early_suspend kpd_early_suspend_desc = {
	.level		= EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1,
	.suspend	= kpd_early_suspend,
	.resume		= kpd_early_resume,
};
#endif

static int __init kpd_mod_init(void)
{
	int r;

#if KPD_DRV_CTRL_BACKLIGHT
	for (r = 0; r < ARRAY_SIZE(kpd_wake_key); r++)
		__set_bit(kpd_wake_key[r], kpd_wake_keybit);
#endif

	r = platform_driver_register(&kpd_pdrv);
	if (r) {
		printk(KPD_SAY "register driver failed (%d)\n", r);
		return r;
	}

#ifdef CONFIG_HAS_EARLYSUSPEND
	register_early_suspend(&kpd_early_suspend_desc);
#endif
	return 0;
}

/* should never be called */
static void __exit kpd_mod_exit(void)
{
}

module_init(kpd_mod_init);
module_exit(kpd_mod_exit);

module_param(kpd_show_hw_keycode, int, 0644);
module_param(kpd_show_register, int, 0644);
module_param(kpd_enable_lprst, int, 0644);

MODULE_AUTHOR("Terry Chang <terry.chang@mediatek.com>");
MODULE_DESCRIPTION("MTK Keypad (KPD) Driver v0.3");
MODULE_LICENSE("GPL");


  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值