From 13c8448ae29931a0c514812773f6fffa70e1ab5c Mon Sep 17 00:00:00 2001
From: Paul Kocialkowski <contact@paulk.fr>
Date: Sat, 30 Mar 2013 19:28:13 +0100
Subject: [PATCH 1/2] sun4i-keyboard: Refactor code following code guidelines

Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
---
 drivers/input/keyboard/sun4i-keyboard.c |  695 +++++++++++++++----------------
 1 files changed, 339 insertions(+), 356 deletions(-)

diff --git a/drivers/input/keyboard/sun4i-keyboard.c b/drivers/input/keyboard/sun4i-keyboard.c
index be5c99b..717fc93 100644
--- a/drivers/input/keyboard/sun4i-keyboard.c
+++ b/drivers/input/keyboard/sun4i-keyboard.c
@@ -1,23 +1,21 @@
 /*
-* This program is free software; you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published by
-* the Free Software Foundation; either version 2 of the License, or
-* (at your option) any later version.
-*
-* 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.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program; if not, write to the Free Software
-*
-* Copyright (c) 2011
-*
-* ChangeLog
-*
-*
-*/
+ * Copyright (C) 2011
+ * Copyright (C) 2013 Paul Kocialkowski
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ */
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/input.h>
@@ -26,419 +24,404 @@
 #include <linux/interrupt.h>
 #include <linux/keyboard.h>
 #include <linux/ioport.h>
+#include <linux/timer.h>
 #include <asm/irq.h>
 #include <asm/io.h>
-#include <linux/timer.h>
 
 #ifdef CONFIG_HAS_EARLYSUSPEND
-    #include <linux/pm.h>
-    #include <linux/earlysuspend.h>
+#include <linux/pm.h>
+#include <linux/earlysuspend.h>
 #endif
-//#define  KEY_DEBUG
-//#define  KEY_DEBUG_LEVEL2
-#define  PRINT_SUSPEND_INFO
-
-#define  KEY_MAX_CNT  		(13)
-
-#define  KEY_BASSADDRESS	(0xf1c22800)
-#define  LRADC_CTRL		(0x00)
-#define  LRADC_INTC		(0x04)
-#define  LRADC_INT_STA 		(0x08)
-#define  LRADC_DATA0		(0x0c)
-#define  LRADC_DATA1		(0x10)
-
-#define  FIRST_CONCERT_DLY		(2<<24)
-#define  CHAN				(0x3)
-#define  ADC_CHAN_SELECT		(CHAN<<22)
-#define  LRADC_KEY_MODE		(0)
-#define  KEY_MODE_SELECT		(LRADC_KEY_MODE<<12)
-#define  LEVELB_VOL			(0<<4)
-
-#define  LRADC_HOLD_EN		(1<<6)
-
-#define  LRADC_SAMPLE_32HZ		(3<<2)
-#define  LRADC_SAMPLE_62HZ		(2<<2)
-#define  LRADC_SAMPLE_125HZ		(1<<2)
-#define  LRADC_SAMPLE_250HZ		(0<<2)
-
-
-#define  LRADC_EN			(1<<0)
-
-#define  LRADC_ADC1_UP_EN		(1<<12)
-#define  LRADC_ADC1_DOWN_EN		(1<<9)
-#define  LRADC_ADC1_DATA_EN		(1<<8)
-
-#define  LRADC_ADC0_UP_EN		(1<<4)
-#define  LRADC_ADC0_DOWN_EN		(1<<1)
-#define  LRADC_ADC0_DATA_EN		(1<<0)
-
-#define  LRADC_ADC1_UPPEND		(1<<12)
-#define  LRADC_ADC1_DOWNPEND	(1<<9)
-#define  LRADC_ADC1_DATAPEND		(1<<8)
-
-
-#define  LRADC_ADC0_UPPEND 		(1<<4)
-#define  LRADC_ADC0_DOWNPEND	(1<<1)
-#define  LRADC_ADC0_DATAPEND		(1<<0)
-
-#define EVB
-//#define CUSTUM
-#define ONE_CHANNEL
-#define MODE_0V2
-//#define MODE_0V15
-//#define TWO_CHANNEL
-#ifdef MODE_0V2
-//standard of key maping
-//0.2V mode
-
-#define REPORT_START_NUM			(5)
-#define REPORT_KEY_LOW_LIMIT_COUNT		(3)
-#define MAX_CYCLE_COUNTER			(100)
-//#define REPORT_REPEAT_KEY_BY_INPUT_CORE
-//#define REPORT_REPEAT_KEY_FROM_HW
-#define INITIAL_VALUE				(0Xff)
-
-static unsigned char keypad_mapindex[64] =
-{
-    0,0,0,0,0,0,0,0,               //key 1, 8个， 0-7
-    1,1,1,1,1,1,1,                 //key 2, 7个， 8-14
-    2,2,2,2,2,2,2,                 //key 3, 7个， 15-21
-    3,3,3,3,3,3,                   //key 4, 6个， 22-27
-    4,4,4,4,4,4,                   //key 5, 6个， 28-33
-    5,5,5,5,5,5,                   //key 6, 6个， 34-39
-    6,6,6,6,6,6,6,6,6,6,           //key 7, 10个，40-49
-    7,7,7,7,7,7,7,7,7,7,7,7,7,7    //key 8, 17个，50-63
-};
+
+// LRADC address and offsets
+#define LRADC_BASE		(0xf1c22800)
+#define LRADC_DATA1		(0x10)
+#define LRADC_DATA0		(0x0c)
+#define LRADC_INT_STA		(0x08)
+#define LRADC_INTC		(0x04)
+#define LRADC_CTRL		(0x00)
+
+// LRADC control values
+#define LRADC_FIRST_CONCERT_DLY	(0x02 << 24)
+#define LRADC_CHAN_SELECT	(0x03 << 22)
+#define LRADC_KEY_MODE_SELECT	(0x00 << 12)
+#define LRADC_HOLD_EN		(0x01 << 6)
+#define LRADC_LEVELB_VOL	(0x00 << 4)
+#define LRADC_SAMPLE_32HZ	(0x03 << 2)
+#define LRADC_SAMPLE_62HZ	(0x02 << 2)
+#define LRADC_SAMPLE_125HZ	(0x01 << 2)
+#define LRADC_SAMPLE_250HZ	(0x00 << 2)
+#define LRADC_EN		(0x01 << 0)
+
+// LRADC values
+#define LRADC_ADC1_UP_EN	(0x01 << 12)
+#define LRADC_ADC1_DOWN_EN	(0x01 << 9)
+#define LRADC_ADC1_DATA_EN	(0x01 << 8)
+#define LRADC_ADC0_UP_EN	(0x01 << 4)
+#define LRADC_ADC0_DOWN_EN	(0x01 << 1)
+#define LRADC_ADC0_DATA_EN	(0x01 << 0)
+
+#define LRADC_ADC1_UPPEND	(0x01 << 12)
+#define LRADC_ADC1_DOWNPEND	(0x01 << 9)
+#define LRADC_ADC1_DATAPEND	(0x01 << 8)
+#define LRADC_ADC0_UPPEND	(0x01 << 4)
+#define LRADC_ADC0_DOWNPEND	(0x01 << 1)
+#define LRADC_ADC0_DATAPEND	(0x01 << 0)
+
+#define LRADC_MAX		(0x3f)
+
+// LRADC config
+#define LRADC_ONE_CHANNEL
+//#define LRADC_MODE_OV15
+#define LRADC_MODE_0V20
+
+// SUN4I Keyboard values
+#define SUN4I_KEYBOARD_REPORT_START_NUM		5
+#define SUN4I_KEYBOARD_KEY_COUNT_MIN		3
+#define SUN4I_KEYBOARD_KEY_INDEX_INIT		(0xff)
+
+// SUN4I Keyboard config
+// #define SUN4I_KEYBOARD_REPORT_REPEAT
+// #define SUN4I_KEYBOARD_DEBUG
+#define SUN4I_KEYBOARD_DEBUG_SUSPEND
+
+struct sun4i_keyboard_data {
+	struct input_dev *dev;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct early_suspend early_suspend;
 #endif
+	unsigned char cycle_buffer[SUN4I_KEYBOARD_REPORT_START_NUM];
+	unsigned int key_val;
+	int key_count;
+	int key_index;
+};
 
-#ifdef MODE_0V15
-//0.15V mode
-static unsigned char keypad_mapindex[64] =
-{
-	0,0,0,                      //key1
-	1,1,1,1,1,                  //key2
-	2,2,2,2,2,
-	3,3,3,3,
-	4,4,4,4,4,
-	5,5,5,5,5,
-	6,6,6,6,6,
-	7,7,7,7,
-	8,8,8,8,8,
-	9,9,9,9,9,
-	10,10,10,10,
-	11,11,11,11,
-	12,12,12,12,12,12,12,12,12,12 //key13
+static void *driver_data;
+
+static unsigned int sun4i_keyboard_keys[] = {
+	[0]	= KEY_VOLUMEUP,
+	[1]	= KEY_VOLUMEDOWN,
+	[2]	= KEY_MENU,
+	[3]	= KEY_SEARCH,
+	[4]	= KEY_HOME,
+	[5]	= KEY_ESC,
+	[6]	= KEY_ENTER,
+	[7]	= KEY_RESERVED,
+	[8]	= KEY_RESERVED,
+	[9]	= KEY_RESERVED,
+	[10]	= KEY_RESERVED,
+	[11]	= KEY_RESERVED,
+	[12]	= KEY_RESERVED,
 };
-#endif
 
-#ifdef EVB
-static unsigned int sun4i_scankeycodes[KEY_MAX_CNT]=
-{
-	[0 ] = KEY_VOLUMEUP,
-	[1 ] = KEY_VOLUMEDOWN,
-	[2 ] = KEY_MENU,
-	[3 ] = KEY_SEARCH,
-	[4 ] = KEY_HOME,
-	[5 ] = KEY_ESC,
-	[6 ] = KEY_ENTER,
-	[7 ] = KEY_RESERVED,
-	[8 ] = KEY_RESERVED,
-	[9 ] = KEY_RESERVED,
-	[10] = KEY_RESERVED,
-	[11] = KEY_RESERVED,
-	[12] = KEY_RESERVED,
+#ifdef LRADC_MODE_0V15
+// Key map for 0.15V mode
+static unsigned char sun4i_keyboard_key_map[64] = {
+	0, 0, 0,					// key index 0
+	1, 1, 1, 1, 1,					// key index 1
+	2, 2, 2, 2, 2,					// key index 2
+	3, 3, 3, 3,					// key index 3
+	4, 4, 4, 4, 4,					// key index 4
+	5, 5, 5, 5, 5,					// key index 5
+	6, 6, 6, 6, 6,					// key index 6
+	7, 7, 7, 7,					// key index 7
+	8, 8, 8, 8, 8,					// key index 8
+	9, 9, 9, 9, 9,					// key index 9
+	10, 10, 10, 10,					// key index 10
+	11, 11, 11, 11,					// key index 11
+	12, 12, 12, 12, 12, 12, 12, 12, 12, 12		// key index 12
 };
 #endif
 
-#ifdef CONFIG_HAS_EARLYSUSPEND
-struct sun4i_keyboard_data {
-    struct early_suspend early_suspend;
+#ifdef LRADC_MODE_0V20
+// Key map for 0.20V mode
+static unsigned char sun4i_keyboard_key_map[64] = {
+	0, 0, 0, 0, 0, 0, 0, 0,				// key index 0
+	1, 1, 1, 1, 1, 1, 1,				// key index 1
+	2, 2, 2, 2, 2, 2, 2,				// key index 2
+	3, 3, 3, 3, 3, 3,				// key index 3
+	4, 4, 4, 4, 4, 4,				// key index 4
+	5, 5, 5, 5, 5, 5,				// key index 5
+	6, 6, 6, 6, 6, 6, 6, 6, 6, 6,			// key index 6
+	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7	// key index 7
 };
 #endif
 
-static volatile unsigned int key_val;
-static struct input_dev *sun4ikbd_dev;
-static unsigned char scancode;
-
-static unsigned char key_cnt = 0;
-static unsigned char cycle_buffer[REPORT_START_NUM] = {0};
-static unsigned char transfer_code = INITIAL_VALUE;
-
-#ifdef CONFIG_HAS_EARLYSUSPEND
-static struct sun4i_keyboard_data *keyboard_data;
+static irqreturn_t sun4i_keyboard_irq(int irq, void *data)
+{
+	struct sun4i_keyboard_data *sun4i_keyboard_data;
+	unsigned int reg_val, key_val;
+	int key_index;
+	int report = 0;
+	int index, i, j;
+
+#ifdef SUN4I_KEYBOARD_DEBUG
+	printk(KERN_DEBUG "%s()\n", __func__);
 #endif
 
-//停用设备
-#ifdef CONFIG_HAS_EARLYSUSPEND
-static void sun4i_keyboard_suspend(struct early_suspend *h)
-{
-	/*int ret;
-	struct sun4i_keyboard_data *ts = container_of(h, struct sun4i_keyboard_data, early_suspend);
-      */
-    #ifdef PRINT_SUSPEND_INFO
-        printk("enter earlysuspend: sun4i_keyboard_suspend. \n");
-    #endif
-
-    writel(0,KEY_BASSADDRESS + LRADC_CTRL);
-	return ;
-}
+	if (data == NULL)
+		return IRQ_HANDLED;
 
-//重新唤醒
-static void sun4i_keyboard_resume(struct early_suspend *h)
-{
-/*int ret;
-	struct sun4i_keyboard_data *ts = container_of(h, struct sun4i_keyboard_data, early_suspend);
-*/
-#ifdef PRINT_SUSPEND_INFO
-	printk("enter laterresume: sun4i_keyboard_resume. \n");
-#endif
+	sun4i_keyboard_data = (struct sun4i_keyboard_data *) data;
 
-	writel(FIRST_CONCERT_DLY|LEVELB_VOL|KEY_MODE_SELECT|LRADC_HOLD_EN|ADC_CHAN_SELECT|LRADC_SAMPLE_62HZ|LRADC_EN,KEY_BASSADDRESS + LRADC_CTRL);
-	return ;
-}
-#else
+	reg_val = readl(LRADC_BASE + LRADC_INT_STA);
 
+#ifdef SUN4I_KEYBOARD_DEBUG
+	if (reg_val & LRADC_ADC0_DOWNPEND)
+		printk(KERN_DEBUG "%s: Key down\n", __func__);
+	if (reg_val & LRADC_ADC0_UPPEND)
+		printk(KERN_DEBUG "%s: Key up\n", __func__);
 #endif
 
+	if (reg_val & LRADC_ADC0_DATAPEND) {
+		// Key data is available
 
-static irqreturn_t sun4i_isr_key(int irq, void *dummy)
-{
-	unsigned int  reg_val;
-	int judge_flag = 0;
-	int loop = 0;
-
-	#ifdef KEY_DEBUG
-	    printk("Key Interrupt\n");
-  	#endif
-	reg_val  = readl(KEY_BASSADDRESS + LRADC_INT_STA);
-	//writel(reg_val,KEY_BASSADDRESS + LRADC_INT_STA);
-	if(reg_val&LRADC_ADC0_DOWNPEND)
-	{
-		#ifdef KEY_DEBUG
-		    printk("key down\n");
-		#endif
-	}
+		key_val = readl(LRADC_BASE + LRADC_DATA0);
+		sun4i_keyboard_data->key_val = key_val;
 
-	if(reg_val&LRADC_ADC0_DATAPEND)
-	{
-		key_val = readl(KEY_BASSADDRESS+LRADC_DATA0);
-		if(key_val < 0x3f)
-		{
-		/*key_val = readl(KEY_BASSADDRESS + LRADC_DATA0);
-		cancode = keypad_mapindex[key_val&0x3f];
-#ifdef KEY_DEBUG
-		printk("raw data: key_val == %u , scancode == %u \n", key_val, scancode);
-#endif
-		*/
-		cycle_buffer[key_cnt%REPORT_START_NUM] = key_val&0x3f;
-		if((key_cnt + 1) < REPORT_START_NUM)
-		{
-			//do not report key message
-
-		}else{
-			//scancode = cycle_buffer[(key_cnt-2)%REPORT_START_NUM];
-			if(cycle_buffer[(key_cnt - REPORT_START_NUM + 1)%REPORT_START_NUM] \
-			== cycle_buffer[(key_cnt - REPORT_START_NUM + 2)%REPORT_START_NUM])
-			{
-			key_val = cycle_buffer[(key_cnt - REPORT_START_NUM + 1)%REPORT_START_NUM];
-			scancode = keypad_mapindex[key_val&0x3f];
-			judge_flag = 1;
+		if (key_val < LRADC_MAX) {
+			index = sun4i_keyboard_data->key_count % SUN4I_KEYBOARD_REPORT_START_NUM;
+			sun4i_keyboard_data->cycle_buffer[index] = key_val & LRADC_MAX;
 
-			}
-			if((!judge_flag) && cycle_buffer[(key_cnt - REPORT_START_NUM + 4)%REPORT_START_NUM] \
-			== cycle_buffer[(key_cnt - REPORT_START_NUM + 5)%REPORT_START_NUM])
-			{
-			key_val = cycle_buffer[(key_cnt - REPORT_START_NUM + 5)%REPORT_START_NUM];
-			scancode = keypad_mapindex[key_val&0x3f];
-			judge_flag = 1;
+			if ((sun4i_keyboard_data->key_count + 1) >= SUN4I_KEYBOARD_REPORT_START_NUM) {
+				// Enough samples were obtained and we can deduce the correct key
 
-			}
-			if(1 == judge_flag)
-			{
-#ifdef KEY_DEBUG_LEVEL2
-				printk("report data: key_val :%8d transfer_code: %8d , scancode: %8d\n",\
-				key_val, transfer_code, scancode);
-#endif
+				i = (sun4i_keyboard_data->key_count - SUN4I_KEYBOARD_REPORT_START_NUM + 1) % SUN4I_KEYBOARD_REPORT_START_NUM;
+				j = (sun4i_keyboard_data->key_count - SUN4I_KEYBOARD_REPORT_START_NUM + 2) % SUN4I_KEYBOARD_REPORT_START_NUM;
+				if (sun4i_keyboard_data->cycle_buffer[i] == sun4i_keyboard_data->cycle_buffer[j]) {
+					key_val = sun4i_keyboard_data->cycle_buffer[i];
+					report = 1;
+					goto report;
+				}
 
-				if(transfer_code == scancode){
-				//report repeat key value
-#ifdef REPORT_REPEAT_KEY_FROM_HW
-				input_report_key(sun4ikbd_dev, sun4i_scankeycodes[scancode], 0);
-				input_sync(sun4ikbd_dev);
-				input_report_key(sun4ikbd_dev, sun4i_scankeycodes[scancode], 1);
-				input_sync(sun4ikbd_dev);
-#else
-				//do not report key value
-#endif
-				}else if(INITIAL_VALUE != transfer_code){
-				//report previous key value up signal + report current key value down
-				input_report_key(sun4ikbd_dev, sun4i_scankeycodes[transfer_code], 0);
-				input_sync(sun4ikbd_dev);
-				input_report_key(sun4ikbd_dev, sun4i_scankeycodes[scancode], 1);
-				input_sync(sun4ikbd_dev);
-				transfer_code = scancode;
-
-				}else{
-				//INITIAL_VALUE == transfer_code, first time to report key event
-				input_report_key(sun4ikbd_dev, sun4i_scankeycodes[scancode], 1);
-				input_sync(sun4ikbd_dev);
-				transfer_code = scancode;
+				i = (sun4i_keyboard_data->key_count - SUN4I_KEYBOARD_REPORT_START_NUM + 4) % SUN4I_KEYBOARD_REPORT_START_NUM;
+				j = (sun4i_keyboard_data->key_count - SUN4I_KEYBOARD_REPORT_START_NUM + 5) % SUN4I_KEYBOARD_REPORT_START_NUM;
+				if (sun4i_keyboard_data->cycle_buffer[i] == sun4i_keyboard_data->cycle_buffer[j]) {
+					key_val = sun4i_keyboard_data->cycle_buffer[i];
+					report = 1;
+					goto report;
 				}
 
+report:
+				if (report) {
+					index = key_val & LRADC_MAX;
+					key_index = sun4i_keyboard_key_map[index];
+
+					if (sun4i_keyboard_data->key_index == key_index) {
+						// Report key repeat
+#ifdef SUN4I_KEYBOARD_REPORT_REPEAT
+						input_report_key(sun4i_keyboard_data->dev, sun4i_keyboard_keys[key_index], 0);
+						input_sync(sun4i_keyboard_data->dev);
+						input_report_key(sun4i_keyboard_data->dev, sun4i_keyboard_keys[key_index], 1);
+						input_sync(sun4i_keyboard_data->dev);
+#endif
+					} else if (sun4i_keyboard_data->key_index == SUN4I_KEYBOARD_KEY_INDEX_INIT) {
+						// Report key event for the first time
+						input_report_key(sun4i_keyboard_data->dev, sun4i_keyboard_keys[key_index], 1);
+						input_sync(sun4i_keyboard_data->dev);
+					} else {
+						// Report previous key up and current key down
+						input_report_key(sun4i_keyboard_data->dev, sun4i_keyboard_keys[sun4i_keyboard_data->key_index], 0);
+						input_sync(sun4i_keyboard_data->dev);
+						input_report_key(sun4i_keyboard_data->dev, sun4i_keyboard_keys[key_index], 1);
+						input_sync(sun4i_keyboard_data->dev);
+					}
+
+					sun4i_keyboard_data->key_index = key_index;
+				}
 			}
 
-			}
-			key_cnt++;
-			if(key_cnt > 2 * MAX_CYCLE_COUNTER ){
-			key_cnt -= MAX_CYCLE_COUNTER;
-			}
+			sun4i_keyboard_data->key_count++;
+			if (sun4i_keyboard_data->key_count > 2 * 100)
+				sun4i_keyboard_data->key_count -= 100;
 
+			sun4i_keyboard_data->key_val = key_val;
 		}
 	}
 
-	if(reg_val&LRADC_ADC0_UPPEND)
-	{
-		if(key_cnt > REPORT_START_NUM)
-		{
-			if(INITIAL_VALUE != transfer_code)
-			{
-#ifdef KEY_DEBUG_LEVEL2
-			printk("report data: key_val :%8d transfer_code: %8d \n",key_val, transfer_code);
-#endif
-			input_report_key(sun4ikbd_dev, sun4i_scankeycodes[transfer_code], 0);
-			input_sync(sun4ikbd_dev);
-			}
+	if (reg_val & LRADC_ADC0_UPPEND) {
+		if (sun4i_keyboard_data->key_count > SUN4I_KEYBOARD_REPORT_START_NUM) {
+			// Enough samples were obtained to report key up
 
-		}else if((key_cnt + 1) >= REPORT_KEY_LOW_LIMIT_COUNT){
-			//rely on hardware first_delay work, need to be verified!
-			if(cycle_buffer[0] == cycle_buffer[1]){
-				key_val = cycle_buffer[0];
-				scancode = keypad_mapindex[key_val&0x3f];
-#ifdef KEY_DEBUG_LEVEL2
-				printk("report data: key_val :%8d scancode: %8d \n",key_val, scancode);
-#endif
-				input_report_key(sun4ikbd_dev, sun4i_scankeycodes[scancode], 1);
-				input_sync(sun4ikbd_dev);
-				input_report_key(sun4ikbd_dev, sun4i_scankeycodes[scancode], 0);
-				input_sync(sun4ikbd_dev);
+			if (sun4i_keyboard_data->key_index != SUN4I_KEYBOARD_KEY_INDEX_INIT) {
+				input_report_key(sun4i_keyboard_data->dev, sun4i_keyboard_keys[sun4i_keyboard_data->key_index], 0);
+				input_sync(sun4i_keyboard_data->dev);
+			}
+		} else if ((sun4i_keyboard_data->key_count + 1) >= SUN4I_KEYBOARD_KEY_COUNT_MIN) {
+			// Not enough samples were obtained, rely on the first samples
+			if (sun4i_keyboard_data->cycle_buffer[0] == sun4i_keyboard_data->cycle_buffer[1]) {
+				key_val = sun4i_keyboard_data->cycle_buffer[0];
+				index = key_val & LRADC_MAX;
+				key_index = sun4i_keyboard_key_map[index];
+
+				sun4i_keyboard_data->key_val = key_val;
+
+				input_report_key(sun4i_keyboard_data->dev, sun4i_keyboard_keys[key_index], 1);
+				input_sync(sun4i_keyboard_data->dev);
+				input_report_key(sun4i_keyboard_data->dev, sun4i_keyboard_keys[key_index], 0);
+				input_sync(sun4i_keyboard_data->dev);
 			}
-
 		}
 
-#ifdef KEY_DEBUG
-		printk("key up \n");
-#endif
+		sun4i_keyboard_data->key_count = 0;
+		sun4i_keyboard_data->key_index = SUN4I_KEYBOARD_KEY_INDEX_INIT;
 
-		key_cnt = 0;
-		judge_flag = 0;
-		transfer_code = INITIAL_VALUE;
-		for(loop = 0; loop < REPORT_START_NUM; loop++)
-		{
-			cycle_buffer[loop] = 0;
-		}
+		for (i = 0 ; i < SUN4I_KEYBOARD_REPORT_START_NUM ; i++)
+			sun4i_keyboard_data->cycle_buffer[i] = 0;
 
 	}
 
-	writel(reg_val,KEY_BASSADDRESS + LRADC_INT_STA);
+	writel(reg_val, LRADC_BASE + LRADC_INT_STA);
+
 	return IRQ_HANDLED;
 }
 
-static int __init sun4ikbd_init(void)
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void sun4i_keyboard_suspend(struct early_suspend *h)
+{
+#ifdef SUN4I_KEYBOARD_DEBUG_SUSPEND
+	printk(KERN_DEBUG "%s()\n", __func__);
+#endif
+
+	writel(0, LRADC_BASE + LRADC_CTRL);
+}
+
+static void sun4i_keyboard_resume(struct early_suspend *h)
 {
+#ifdef SUN4I_KEYBOARD_DEBUG_SUSPEND
+	printk(KERN_DEBUG "%s()\n", __func__);
+#endif
+
+	writel(LRADC_FIRST_CONCERT_DLY | LRADC_LEVELB_VOL | LRADC_KEY_MODE_SELECT | LRADC_HOLD_EN | LRADC_CHAN_SELECT | LRADC_SAMPLE_62HZ | LRADC_EN,
+		LRADC_BASE + LRADC_CTRL);
+}
+#endif
+
+static int __init sun4i_keyboard_init(void)
+{
+	struct sun4i_keyboard_data *sun4i_keyboard_data;
+	int count;
+	int rc = 0;
 	int i;
-	int err =0;
 
-#ifdef KEY_DEBUG
-	printk("sun4ikbd_init \n");
+#ifdef SUN4I_KEYBOARD_DEBUG
+	printk(KERN_DEBUG "%s()\n", __func__);
 #endif
-	sun4ikbd_dev = input_allocate_device();
-	if (!sun4ikbd_dev) {
-		printk(KERN_ERR "sun4ikbd: not enough memory for input device\n");
-		err = -ENOMEM;
-		goto fail1;
+
+	sun4i_keyboard_data = (struct sun4i_keyboard_data *)
+		kzalloc(sizeof(struct sun4i_keyboard_data), GFP_KERNEL);
+	if (sun4i_keyboard_data == NULL) {
+		printk(KERN_ERR "%s: Unable to alloc sun4i keyboard data\n", __func__);
+		rc = -ENOMEM;
+		goto error_data_alloc;
 	}
 
-	sun4ikbd_dev->name = "sun4i-keyboard";
-	sun4ikbd_dev->phys = "sun4ikbd/input0";
-	sun4ikbd_dev->id.bustype = BUS_HOST;
-	sun4ikbd_dev->id.vendor = 0x0001;
-	sun4ikbd_dev->id.product = 0x0001;
-	sun4ikbd_dev->id.version = 0x0100;
+	driver_data = (void *) sun4i_keyboard_data;
 
-#ifdef REPORT_REPEAT_KEY_BY_INPUT_CORE
-	sun4ikbd_dev->evbit[0] = BIT_MASK(EV_KEY)|BIT_MASK(EV_REP);
-	printk("REPORT_REPEAT_KEY_BY_INPUT_CORE is defined, support report repeat key value. \n");
-#else
-	sun4ikbd_dev->evbit[0] = BIT_MASK(EV_KEY);
-#endif
+	sun4i_keyboard_data->key_index = SUN4I_KEYBOARD_KEY_INDEX_INIT;
 
-	for (i = 0; i < KEY_MAX_CNT; i++)
-		set_bit(sun4i_scankeycodes[i], sun4ikbd_dev->keybit);
+	sun4i_keyboard_data->dev = input_allocate_device();
+	if (sun4i_keyboard_data->dev == NULL) {
+		printk(KERN_ERR "%s: Unable to alloc input device\n", __func__);
+		rc = -ENOMEM;
+		goto error_input_alloc;
+	}
 
-#ifdef ONE_CHANNEL
-	writel(LRADC_ADC0_DOWN_EN|LRADC_ADC0_UP_EN|LRADC_ADC0_DATA_EN,KEY_BASSADDRESS + LRADC_INTC);
-	writel(FIRST_CONCERT_DLY|LEVELB_VOL|KEY_MODE_SELECT|LRADC_HOLD_EN|ADC_CHAN_SELECT|LRADC_SAMPLE_62HZ|LRADC_EN,KEY_BASSADDRESS + LRADC_CTRL);
-	//writel(FIRST_CONCERT_DLY|LEVELB_VOL|KEY_MODE_SELECT|ADC_CHAN_SELECT|LRADC_SAMPLE_62HZ|LRADC_EN,KEY_BASSADDRESS + LRADC_CTRL);
+	sun4i_keyboard_data->dev->name		= "sun4i-keyboard";
+	sun4i_keyboard_data->dev->phys		= "sun4ikbd/input0";
+	sun4i_keyboard_data->dev->id.bustype	= BUS_HOST;
+	sun4i_keyboard_data->dev->id.vendor	= 0x0001;
+	sun4i_keyboard_data->dev->id.product	= 0x0001;
+	sun4i_keyboard_data->dev->id.version	= 0x0100;
 
+#ifdef SUN4I_KEYBOARD_REPORT_REPEAT
+	sun4i_keyboard_data->dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
 #else
+	sun4i_keyboard_data->dev->evbit[0] = BIT_MASK(EV_KEY);
 #endif
 
+	count = ARRAY_SIZE(sun4i_keyboard_keys);
+	for (i = 0 ; i < count ; i++)
+		set_bit(sun4i_keyboard_keys[i], sun4i_keyboard_data->dev->keybit);
 
-	if (request_irq(SW_INT_IRQNO_LRADC, sun4i_isr_key, 0, "sun4ikbd", NULL)){
-		err = -EBUSY;
-		printk("request irq failure. \n");
-		goto fail2;
-	}
+#ifdef LRADC_ONE_CHANNEL
+	writel(LRADC_ADC0_DOWN_EN | LRADC_ADC0_UP_EN | LRADC_ADC0_DATA_EN,
+		LRADC_BASE + LRADC_INTC);
+	writel(LRADC_FIRST_CONCERT_DLY | LRADC_LEVELB_VOL | LRADC_KEY_MODE_SELECT | LRADC_HOLD_EN | LRADC_CHAN_SELECT | LRADC_SAMPLE_62HZ | LRADC_EN,
+		LRADC_BASE + LRADC_CTRL);
+#endif
 
-	err = input_register_device(sun4ikbd_dev);
-	if (err)
-		goto fail3;
+	rc = request_irq(SW_INT_IRQNO_LRADC, sun4i_keyboard_irq, 0, "sun4ikbd", (void *) sun4i_keyboard_data);
+	if (rc) {
+		printk(KERN_ERR "%s: Unable to request IRQ\n", __func__);
+		rc = -EBUSY;
+		goto error_irq;
+	}
 
-#ifdef CONFIG_HAS_EARLYSUSPEND
-	printk("==register_early_suspend =\n");
-	keyboard_data = kzalloc(sizeof(*keyboard_data), GFP_KERNEL);
-	if (keyboard_data == NULL) {
-		err = -ENOMEM;
-		goto err_alloc_data_failed;
+	rc = input_register_device(sun4i_keyboard_data->dev);
+	if (rc) {
+		printk(KERN_ERR "%s: Unable to register input device\n", __func__);
+		rc = -1;
+		goto error_input_register;
 	}
 
-	keyboard_data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 3;
-	keyboard_data->early_suspend.suspend = sun4i_keyboard_suspend;
-	keyboard_data->early_suspend.resume	= sun4i_keyboard_resume;
-	register_early_suspend(&keyboard_data->early_suspend);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	sun4i_keyboard_data->early_suspend.level	= EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 3;
+	sun4i_keyboard_data->early_suspend.suspend	= sun4i_keyboard_suspend;
+	sun4i_keyboard_data->early_suspend.resume	= sun4i_keyboard_resume;
+	register_early_suspend(&sun4i_keyboard_data->early_suspend);
 #endif
 
 	return 0;
-#ifdef CONFIG_HAS_EARLYSUSPEND
- err_alloc_data_failed:
-#endif
- fail3:
-	free_irq(SW_INT_IRQNO_LRADC, sun4i_isr_key);
- fail2:
-	input_free_device(sun4ikbd_dev);
- fail1:
-     ;
-#ifdef KEY_DEBUG
-	printk("sun4ikbd_init failed. \n");
-#endif
 
- return err;
+error_input_register:
+	free_irq(SW_INT_IRQNO_LRADC, sun4i_keyboard_irq);
+
+error_irq:
+	if (sun4i_keyboard_data->dev != NULL)
+		input_free_device(sun4i_keyboard_data->dev);
+
+error_input_alloc:
+	if (sun4i_keyboard_data != NULL)
+		kfree((void *) sun4i_keyboard_data);
+
+error_data_alloc:
+	driver_data = NULL;
+
+	return rc;
 }
 
-static void __exit sun4ikbd_exit(void)
+static void __exit sun4i_keyboard_exit(void)
 {
+	struct sun4i_keyboard_data *sun4i_keyboard_data;
+
+#ifdef SUN4I_KEYBOARD_DEBUG
+	printk(KERN_DEBUG "%s()\n", __func__);
+#endif
+
+	if (driver_data == NULL)
+		return;
+
+	sun4i_keyboard_data = (struct sun4i_keyboard_data *) driver_data;
+
 #ifdef CONFIG_HAS_EARLYSUSPEND
-	 unregister_early_suspend(&keyboard_data->early_suspend);
+	unregister_early_suspend(&sun4i_keyboard_data->early_suspend);
 #endif
-	free_irq(SW_INT_IRQNO_LRADC, sun4i_isr_key);
-	input_unregister_device(sun4ikbd_dev);
-}
 
-module_init(sun4ikbd_init);
-module_exit(sun4ikbd_exit);
+	free_irq(SW_INT_IRQNO_LRADC, sun4i_keyboard_irq);
 
+	if (sun4i_keyboard_data->dev != NULL) {
+		input_unregister_device(sun4i_keyboard_data->dev);
+		input_free_device(sun4i_keyboard_data->dev);
+	}
+
+	kfree(driver_data);
+	driver_data = NULL;
+}
+
+module_init(sun4i_keyboard_init);
+module_exit(sun4i_keyboard_exit);
 
 MODULE_AUTHOR(" <@>");
 MODULE_DESCRIPTION("sun4i-keyboard driver");
 MODULE_LICENSE("GPL");
-
-- 
1.7.5.4

