summaryrefslogtreecommitdiff
path: root/ANDROID_3.4.5/drivers/input/keyboard
diff options
context:
space:
mode:
authorKevin2014-11-15 10:00:36 +0800
committerKevin2014-11-15 10:00:36 +0800
commit9d40ac5867b9aefe0722bc1f110b965ff294d30d (patch)
treede942df665fac4bac0d9cb7ae86910fe937b0c1a /ANDROID_3.4.5/drivers/input/keyboard
parent392e8802486cb573b916e746010e141a75f507e6 (diff)
downloadFOSSEE-netbook-kernel-source-9d40ac5867b9aefe0722bc1f110b965ff294d30d.tar.gz
FOSSEE-netbook-kernel-source-9d40ac5867b9aefe0722bc1f110b965ff294d30d.tar.bz2
FOSSEE-netbook-kernel-source-9d40ac5867b9aefe0722bc1f110b965ff294d30d.zip
add via modify part source code for wm8880 4.4 kitkat
Diffstat (limited to 'ANDROID_3.4.5/drivers/input/keyboard')
-rw-r--r--ANDROID_3.4.5/drivers/input/keyboard/Kconfig18
-rw-r--r--ANDROID_3.4.5/drivers/input/keyboard/Makefile2
-rwxr-xr-xANDROID_3.4.5/drivers/input/keyboard/wmt_kpad.c466
-rwxr-xr-xANDROID_3.4.5/drivers/input/keyboard/wmt_saradc.c718
4 files changed, 1204 insertions, 0 deletions
diff --git a/ANDROID_3.4.5/drivers/input/keyboard/Kconfig b/ANDROID_3.4.5/drivers/input/keyboard/Kconfig
index f354813a..906d86aa 100644
--- a/ANDROID_3.4.5/drivers/input/keyboard/Kconfig
+++ b/ANDROID_3.4.5/drivers/input/keyboard/Kconfig
@@ -502,6 +502,24 @@ config KEYBOARD_DAVINCI
To compile this driver as a module, choose M here: the
module will be called davinci_keyscan.
+config KEYBOARD_WMT
+ tristate "WMT keypad support"
+ depends on INPUT && INPUT_KEYBOARD
+ ---help---
+ Say Y here if you want to use keypad on WMT based EVB.
+
+ To compile this driver as a module, choose M here: the
+ module will be called wmt_keypad.
+
+config SARADC_WMT
+ tristate "WMT saradc support"
+ depends on INPUT && INPUT_KEYBOARD
+ ---help---
+ Say Y here if you want to use keypad on WMT based EVB.
+
+ To compile this driver as a module, choose M here: the
+ module will be called wmt_saradc.
+
config KEYBOARD_OMAP
tristate "TI OMAP keypad support"
depends on (ARCH_OMAP1 || ARCH_OMAP2)
diff --git a/ANDROID_3.4.5/drivers/input/keyboard/Makefile b/ANDROID_3.4.5/drivers/input/keyboard/Makefile
index df7061f1..587a9f25 100644
--- a/ANDROID_3.4.5/drivers/input/keyboard/Makefile
+++ b/ANDROID_3.4.5/drivers/input/keyboard/Makefile
@@ -51,4 +51,6 @@ obj-$(CONFIG_KEYBOARD_TEGRA) += tegra-kbc.o
obj-$(CONFIG_KEYBOARD_TNETV107X) += tnetv107x-keypad.o
obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o
obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
+obj-$(CONFIG_KEYBOARD_WMT) += wmt_kpad.o
obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o
+obj-$(CONFIG_SARADC_WMT) += wmt_saradc.o
diff --git a/ANDROID_3.4.5/drivers/input/keyboard/wmt_kpad.c b/ANDROID_3.4.5/drivers/input/keyboard/wmt_kpad.c
new file mode 100755
index 00000000..cf50cf1c
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/input/keyboard/wmt_kpad.c
@@ -0,0 +1,466 @@
+/*++
+linux/drivers/input/keyboard/wmt_kpad.c
+
+Some descriptions of such software. Copyright (c) 2008 WonderMedia Technologies, Inc.
+
+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, see <http://www.gnu.org/licenses/>.
+
+WonderMedia Technologies, Inc.
+10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C.
+--*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/errno.h>
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <linux/suspend.h>
+#include <linux/gpio.h>
+#include <mach/wmt_iomux.h>
+
+
+/* Debug macros */
+#if 0
+#define DPRINTK(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __func__ , ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+//#define USE_HOME
+#define wmt_kpad_timeout (HZ/50)
+
+#define WMT_KPAD_FUNCTION_NUM 7
+
+
+static unsigned int wmt_kpad_codes[WMT_KPAD_FUNCTION_NUM] = {
+ [0] = KEY_VOLUMEUP,
+ [1] = KEY_VOLUMEDOWN,
+ [2] = KEY_BACK,
+ [3] = KEY_HOME,
+ [4] = KEY_MENU,
+ [5] = KEY_CAMERA,
+ [6] = KEY_PLAYPAUSE,
+};
+
+
+enum {
+ KEY_ST_up,
+ KEY_ST_down,
+ KEY_ST_debounce,
+};
+
+static struct input_dev *kpad_dev;
+
+int key_num = 0;
+
+struct wmt_key{
+ int gpio;
+ int keycode;
+
+ int status;
+ int debounce;
+ struct timer_list timer;
+} ;
+struct wmt_key gpio_key[5];
+
+#ifdef CONFIG_CPU_FREQ
+/*
+ * Well, the debounce time is not very critical while zac2_clk
+ * rescaling, but we still do it.
+ */
+
+/* kpad_clock_notifier()
+ *
+ * When changing the processor core clock frequency, it is necessary
+ * to adjust the KPMIR register.
+ *
+ * Returns: 0 on success, -1 on error
+ */
+static int kpad_clock_notifier(struct notifier_block *nb, unsigned long event,
+ void *data)
+{
+ return 0;
+}
+
+/*
+ * Notify callback while issusing zac2_clk rescale.
+ */
+static struct notifier_block kpad_clock_nblock = {
+ .notifier_call = kpad_clock_notifier,
+ .priority = 1
+};
+#endif
+
+static int wmt_kpad_gpio_requst(void)
+{
+ int i,j,ret;
+ DPRINTK("Start\n");
+ for(i=0; i< key_num; i++){
+ ret = gpio_request(gpio_key[i].gpio,"kpad");
+ if(ret)
+ goto exit;
+ }
+
+ DPRINTK("End\n");
+ return ret;
+exit:
+ for(j=0; j < i; j++)
+ gpio_free(gpio_key[j].gpio);
+ return ret;
+}
+
+static int wmt_kpad_gpio_init(void)
+{
+ int i;
+ for(i=0; i<key_num; i++){
+ gpio_direction_input(gpio_key[i].gpio);
+ wmt_gpio_setpull(gpio_key[i].gpio,WMT_GPIO_PULL_UP);
+ }
+
+ return 0;
+}
+
+
+static int wmt_kpad_gpio_free(void)
+{
+ int i;
+ for(i=0; i<key_num; i++){
+ gpio_free(gpio_key[i].gpio);
+ }
+
+ return 0;
+}
+
+static void wmt_kpad_poll(unsigned long fcontext)
+{
+ struct wmt_key *gpk = (struct wmt_key *)fcontext;
+
+ //DPRINTK("Start\n");
+ if (__gpio_get_value(gpk->gpio) == 0) { /*Active Low*/
+ if(gpk->status == KEY_ST_up){
+ gpk->debounce = 5;
+ gpk->status = KEY_ST_debounce;
+ DPRINTK("vd down to debounce\n");
+ }
+
+ if(gpk->status == KEY_ST_debounce){
+ if(--gpk->debounce == 0){
+ gpk->status = KEY_ST_down;
+ /* report volume down key down */
+ input_report_key(kpad_dev, gpk->keycode, 1);
+ input_sync(kpad_dev);
+ DPRINTK("WMT Volume up keep press\n");
+ }
+ }
+ //DPRINTK("vd level is low,status=%d\n",vu_status);
+
+ }
+ else {/* Level High */
+ if(gpk->status == KEY_ST_down){
+ gpk->status = KEY_ST_up;
+ /*Volume down release*/
+ input_report_key(kpad_dev, gpk->keycode, 0); /*row4 key is release*/
+ input_sync(kpad_dev);
+ DPRINTK("WMT_Volume down release key = %d \n", gpk->keycode);
+ }
+
+ if(gpk->status == KEY_ST_debounce){
+ if(--gpk->debounce == 0){
+ gpk->status = KEY_ST_up;
+ }
+ }
+
+ //DPRINTK("vd level is high,status=%d\n",vu_status);
+
+ }
+
+ mod_timer(&gpk->timer, jiffies + wmt_kpad_timeout);
+ //DPRINTK("End\n");
+
+ return;
+}
+
+static int init_key_timer(void)
+{
+ int i;
+ for(i=0; i<key_num;i++){
+ init_timer(&gpio_key[i].timer);
+ gpio_key[i].timer.function = wmt_kpad_poll;
+ gpio_key[i].timer.data = (unsigned long)&gpio_key[i];
+ }
+
+ return 0;
+}
+
+static int start_key_timer(void)
+{ int i;
+ for(i=0;i<key_num;i++){
+ gpio_key[i].status = KEY_ST_up;
+ mod_timer(&gpio_key[i].timer, jiffies + HZ/10);
+ }
+
+ return 0;
+}
+
+static int del_key_timer(void)
+{ int i;
+ for(i=0;i<key_num;i++){
+ gpio_key[i].status = KEY_ST_up;
+ del_timer_sync(&gpio_key[i].timer);
+ }
+
+ return 0;
+}
+static int kpad_open(struct input_dev *dev)
+{
+ int ret = 0;
+ DPRINTK("Start\n");
+
+ /*init timer*/
+ init_key_timer();
+ start_key_timer();
+ wmt_kpad_gpio_init();
+ DPRINTK("End2\n");
+
+ return ret;
+}
+
+static void kpad_close(struct input_dev *dev)
+{
+ DPRINTK("Start\n");
+
+ del_key_timer();
+ /*
+ * Unregister input device driver
+ */
+ input_unregister_device(dev);
+
+ DPRINTK("End2\n");
+}
+
+static int wmt_kpad_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ unsigned int i;
+ DPRINTK("Start\n");
+ kpad_dev = input_allocate_device();
+ if (kpad_dev == NULL) {
+ DPRINTK("End 1\n");
+ return -1;
+ }
+ /*
+ * Simply check resources parameters.
+ */
+ DPRINTK("pdev->num_resources = 0x%x\n",pdev->num_resources);
+ if (pdev->num_resources < 0 || pdev->num_resources > 2) {
+ ret = -ENODEV;
+ goto kpad_probe_out;
+ }
+
+ /* Register an input event device. */
+ kpad_dev->name = "keypad",
+ kpad_dev->phys = "keypad",
+
+ /*
+ * Let kpad to implement key repeat.
+ */
+
+ set_bit(EV_KEY, kpad_dev->evbit);
+
+ for (i = 0; i < WMT_KPAD_FUNCTION_NUM; i++)
+ set_bit(wmt_kpad_codes[i], kpad_dev->keybit);
+
+ kpad_dev->keycode = wmt_kpad_codes;
+ kpad_dev->keycodesize = sizeof(unsigned int);
+ kpad_dev->keycodemax = WMT_KPAD_FUNCTION_NUM;
+
+ /*
+ * For better view of /proc/bus/input/devices
+ */
+ kpad_dev->id.bustype = 0;
+ kpad_dev->id.vendor = 0;
+ kpad_dev->id.product = 0;
+ kpad_dev->id.version = 0;
+
+ input_register_device(kpad_dev);
+ kpad_open(kpad_dev);
+ DPRINTK("End2\n");
+kpad_probe_out:
+
+#ifndef CONFIG_SKIP_DRIVER_MSG
+ printk(KERN_INFO "WMT keypad driver initialized: %s\n",
+ (ret == 0) ? "ok" : "failed");
+#endif
+ DPRINTK("End3\n");
+ return ret;
+}
+
+static int wmt_kpad_remove(struct platform_device *pdev)
+{
+ int ret;
+ DPRINTK("Start\n");
+ kpad_close(kpad_dev);
+ wmt_kpad_gpio_free();
+ DPRINTK("End\n");
+#ifdef CONFIG_CPU_FREQ
+ ret = cpufreq_unregister_notifier(&kpad_clock_nblock, \
+ CPUFREQ_TRANSITION_NOTIFIER);
+
+ if (ret) {
+ printk(KERN_ERR "Unable to unregister CPU frequency " \
+ "change notifier (%d)\n", ret);
+ }
+#endif
+ return 0;
+}
+
+static int wmt_kpad_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ DPRINTK("Start\n");
+
+ switch (state.event) {
+ case PM_EVENT_SUSPEND:
+ del_key_timer();
+ break;
+ case PM_EVENT_FREEZE:
+ case PM_EVENT_PRETHAW:
+
+ default:
+ break;
+ }
+
+ DPRINTK("End2\n");
+ return 0;
+}
+
+static int wmt_kpad_resume(struct platform_device *pdev)
+{
+ DPRINTK("Start\n");
+ wmt_kpad_gpio_init();
+ start_key_timer();
+ DPRINTK("End\n");
+ return 0;
+}
+
+static void wmt_kpad_release(struct device *dev)
+{
+ return ;
+}
+
+static struct platform_driver wmt_kpad_driver = {
+ .driver.name = "wmt-kpad",
+ .probe = &wmt_kpad_probe,
+ .remove = &wmt_kpad_remove,
+ .suspend = &wmt_kpad_suspend,
+ .resume = &wmt_kpad_resume
+};
+
+static struct resource wmt_kpad_resources[] = {
+ [0] = {
+ .start = IRQ_GPIO,
+ .end = IRQ_GPIO,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device wmt_kpad_device = {
+ .name = "wmt-kpad",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(wmt_kpad_resources),
+ .resource = wmt_kpad_resources,
+ .dev = {
+ .release = wmt_kpad_release,
+ }
+};
+
+extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen);
+
+static int __init kpad_init(void)
+{
+ int i,ret;
+ int retval;
+ unsigned char buf[80];
+ int varlen = 80;
+ char *varname = "wmt.io.kpad";
+ char *p=NULL;
+ int gpio,code;
+
+ DPRINTK(KERN_ALERT "Start\n");
+ retval = wmt_getsyspara(varname, buf, &varlen);
+ if (retval == 0) {
+ sscanf(buf,"%d:", &key_num);
+ if (key_num <= 0)
+ return -ENODEV;
+ p = buf;
+ for(i=0; i<key_num && p!=NULL; i++){
+ p = strchr(p,':');
+ p++;
+ sscanf(p,"[%d,%d]",&gpio,&code);
+ gpio_key[i].gpio = gpio;
+ gpio_key[i].keycode = code;
+ printk("gpio=%d,code=%d\n",gpio,gpio_key[i].keycode);
+ }
+
+ } else {
+ printk("##Warning: \"wmt.io.kpad\" not find\n");
+ return -EIO;
+ }
+ ret = wmt_kpad_gpio_requst();
+ if(ret){
+ printk("##Warning:Request gpio failed.\n");
+ return ret;
+ }
+
+#ifdef CONFIG_CPU_FREQ
+ ret = cpufreq_register_notifier(&kpad_clock_nblock, \
+ CPUFREQ_TRANSITION_NOTIFIER);
+
+ if (ret) {
+ printk(KERN_ERR "Unable to register CPU frequency " \
+ "change notifier (%d)\n", ret);
+ }
+#endif
+ ret = platform_device_register(&wmt_kpad_device);
+ if (ret != 0) {
+ DPRINTK("End1 ret = %x\n",ret);
+ return -ENODEV;
+ }
+
+ ret = platform_driver_register(&wmt_kpad_driver);
+ DPRINTK("End2 ret = %x\n",ret);
+ return ret;
+}
+
+static void __exit kpad_exit(void)
+{
+ DPRINTK("Start\n");
+ platform_driver_unregister(&wmt_kpad_driver);
+ platform_device_unregister(&wmt_kpad_device);
+ DPRINTK("End\n");
+}
+
+module_init(kpad_init);
+module_exit(kpad_exit);
+
+MODULE_AUTHOR("WonderMedia Technologies, Inc.");
+MODULE_DESCRIPTION("WMT [generic keypad] driver");
+MODULE_LICENSE("GPL");
diff --git a/ANDROID_3.4.5/drivers/input/keyboard/wmt_saradc.c b/ANDROID_3.4.5/drivers/input/keyboard/wmt_saradc.c
new file mode 100755
index 00000000..132f0ae0
--- /dev/null
+++ b/ANDROID_3.4.5/drivers/input/keyboard/wmt_saradc.c
@@ -0,0 +1,718 @@
+/*++
+linux/drivers/input/keyboard/wmt_kpad.c
+
+Some descriptions of such software. Copyright (c) 2008 WonderMedia Technologies, Inc.
+
+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, see <http://www.gnu.org/licenses/>.
+
+WonderMedia Technologies, Inc.
+10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C.
+--*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/errno.h>
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <mach/wmt_saradc.h>
+#include <linux/suspend.h>
+
+
+/* #define COUNTTIMER */
+#ifdef COUNTTIMER
+unsigned int start_time;
+#endif
+
+/* Debug macros */
+#if 0
+#define DPRINTK(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __func__ , ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+/* the shortest response time is 20 ms, original timeout (HZ/100)*100 */
+#define wmt_saradc_timeout ((HZ/100)*2)
+#define WMT_SARADC_FUNCTION_NUM 6
+#define SAMETIMES 2
+unsigned int HW_Hz;
+unsigned int SW_timeout;
+unsigned int INT_timeout;
+
+enum adc_func {
+ FUNC_KPAD,
+ FUNC_BAT,
+ FUNC_NONE,
+};
+unsigned int func = FUNC_NONE;
+
+/* SARADC battery */
+unsigned int BatteryCODE;
+static unsigned int bat_interval = 3;
+static struct delayed_work bat_work;
+
+static unsigned int wmt_saradc_codes[WMT_SARADC_FUNCTION_NUM] = {
+ [0] = KEY_VOLUMEUP,
+ [1] = KEY_VOLUMEDOWN,
+ [2] = KEY_BACK,
+ [3] = KEY_MENU,
+ [4] = KEY_HOME,
+ [5] = KEY_RESERVED,
+};
+
+/*high resolution timer */
+static struct hrtimer wmt_saradc_hrtimer;
+static struct input_dev *saradc_dev;
+
+static struct wmt_saradc_s saradc = {
+ .ref = 0,
+ .res = NULL,
+ .regs = NULL,
+ .irq = 0,
+};
+
+int count_sample_rate(unsigned APB_clock, int Hz)
+{
+ int temp_slot;
+ /* the Hz that we want */
+ temp_slot = APB_clock/(4096 * Hz); /* (APB clock/32)/ (128 * HZ)*/
+ return temp_slot;
+}
+
+static int saradc_sample_rate(unsigned ADC_clock, int Hz)
+{
+ int temp_slot;
+ /* the Hz that we want */
+ temp_slot = ADC_clock/(128 * Hz); /* ADC clock/ (128 * HZ)*/
+ return temp_slot;
+}
+
+int saradc_event_table(unsigned int eventcode)
+{
+ DPRINTK("eventcode = %d\n", eventcode);
+ if (eventcode >= 39 && eventcode <= 42)
+ return 0;
+ else if (eventcode >= 63 && eventcode <= 64)
+ return 1;
+ else if (eventcode >= 84 && eventcode <= 85)
+ return 2;
+ else if (eventcode >= 18 && eventcode <= 20)
+ return 3;
+ else if (eventcode == 0)
+ return 4;
+ else if (eventcode >= 29 && eventcode <= 31)
+ return 5;
+ else if (eventcode == 127)
+ return 5;
+ else
+ return 5;
+}
+
+static void wmt_saradc_hw_init(void)
+{
+ unsigned int auto_temp_slot;
+ //unsigned int APB_clk;
+ unsigned int ADC_clk;
+ DPRINTK("Start\n");
+
+ /*
+ * Turn on saradc clocks.
+ */
+ auto_pll_divisor(DEV_ADC, CLK_ENABLE, 0, 0);
+
+ /* Set the ADC clock to 4.8 MHz */
+ auto_pll_divisor(DEV_ADC, SET_DIV, 1, 4800);
+
+ /* Turn on SARADC controll power */
+ saradc.regs->Ctr0 &= ~PD;
+
+ /* Enable SARADC digital clock */
+ saradc.regs->Ctr0 |= DigClkEn;
+
+ /* Simply clean all previous saradc status. */
+ saradc.regs->Ctr0 |= (ClrIntADC | ClrIntTOut);
+ saradc.regs->Ctr1 |= ClrIntValDet;
+
+ if (((saradc.regs->Ctr2 & EndcIntStatus) == EndcIntStatus) ||
+ ((saradc.regs->Ctr2 & TOutStatus) == TOutStatus) ||
+ ((saradc.regs->Ctr2 & ValDetIntStatus) == ValDetIntStatus))
+ printk(KERN_ERR "[saradc] clear status failed! status = %x\n", saradc.regs->Ctr2);
+
+ /*Set Timeout Value*/
+ saradc.regs->Ctr0 &= 0xffff0000;
+ saradc.regs->Ctr0 |= TOutDly(0xffff);
+
+ /* get APB clock & count sample rate*/
+ ADC_clk = auto_pll_divisor(DEV_ADC, GET_FREQ, 0, 0);
+ DPRINTK("[%s] ADC_clk = %d\n", __func__, ADC_clk);
+ /* sample rate: 500 Hz , 1 ms/sample */
+ auto_temp_slot = saradc_sample_rate(ADC_clk, 500);
+#if 0
+ /* get APB clock & count sample rate*/
+ APB_clk = auto_pll_divisor(DEV_APB, GET_FREQ, 0, 0);
+ /* sample rate: 1000 Hz , 1 ms/sample */
+ auto_temp_slot = count_sample_rate(APB_clk, HW_Hz);
+ DPRINTK("[%s] APB_clk = %d\n", __func__, APB_clk);
+#endif
+ /*Set Sample Rate*/
+ saradc.regs->Ctr1 &= 0x0000ffff;
+ saradc.regs->Ctr1 |= (auto_temp_slot << 16);
+ DPRINTK("[%s] auto_temp_slot = %x ctr1: %x\n", __func__, auto_temp_slot, saradc.regs->Ctr1);
+ /* Set saradc as auto mode */
+ saradc.regs->Ctr0 |= AutoMode;
+
+ msleep(200);
+
+ /* Enable value changing interrupt and Buffer data valid */
+ saradc.regs->Ctr1 |= (ValDetIntEn | BufRd);
+ /* saradc.regs->Ctr0 |= TOutEn; */
+
+ DPRINTK("End\n");
+}
+
+enum hrtimer_restart wmt_saradc_timeout_hrtimer(struct hrtimer *timer)
+{
+ unsigned int SARCODE = 0xffff;
+ static unsigned int OLDCODE = 0xffff;
+ static int time, same;
+ static bool saradc_flag = 1; /* 0: report event state, 1: get SARCODE value state */
+ int new_event = -1;
+ static int pre_event = -1, button_press;
+ ktime_t ktime;
+ /* count timeout value */
+#ifdef COUNTTIMER
+ unsigned int end_time;
+ end_time = wmt_read_oscr();
+ printk(KERN_ERR "time = %d\n", (end_time - start_time)/3);
+#endif
+ ktime = ktime_set(0, SW_timeout * 1000);
+
+ DPRINTK("[%s] Start\n", __func__);
+ while ((saradc.regs->Ctr2 & EndcIntStatus) == 0)
+ ;
+ SARCODE = SARCode(saradc.regs->Ctr1);
+
+ if (saradc_flag && time < 10) {
+ if ((SARCODE/4 - OLDCODE/4) <= 1 || (SARCODE/4 - OLDCODE/4) >= -1) {
+ same++;
+ DPRINTK("time:%d SARCODE=%u SARCODE/4=%u, OLDCODE=%u, OLDCODE/4=%u, same=%d\n",
+ time, SARCODE, SARCODE/4, OLDCODE, OLDCODE/4, same);
+ if (same == SAMETIMES)
+ saradc_flag = 0; /* get the new event */
+ } else
+ same = 0;
+
+ DPRINTK("time:%d SARCODE=%u SARCODE/4=%u, OLDCODE=%u, OLDCODE/4=%u, same=%d\n",
+ time, SARCODE, SARCODE/4, OLDCODE, OLDCODE/4, same);
+ OLDCODE = SARCODE;
+ time++;
+
+ /* don't call timer when 10th get SARCODE or enough same time */
+ if (time < 10 && same != SAMETIMES) {
+ hrtimer_start(&wmt_saradc_hrtimer, ktime, HRTIMER_MODE_REL);
+ /* count timer from callback function to callback function */
+#ifdef COUNTTIMER
+ start_time = wmt_read_oscr();
+#endif
+ }
+ /* if not get stable SARCODE value in 10 times, report SARACODE is NONE event */
+ if (time == 10 && same != SAMETIMES) {
+ SARCODE = 508;
+ DPRINTK("time %d SARCODE %u", time, SARCODE);
+ }
+ }
+ if (time == 10 || saradc_flag == 0)
+ time = 0;
+
+ /* disable BufRd */
+ saradc.regs->Ctr1 &= ~BufRd;
+
+ new_event = saradc_event_table(SARCODE/4);
+
+ if (SARCODE == 0xffff) {
+ printk(KERN_ERR "Auto mode witn INT test fail\n");
+ /*Disable interrupt*/
+ saradc.regs->Ctr1 &= ~ValDetIntEn;
+ /* Clean all previous saradc status. */
+ saradc.regs->Ctr0 |= (ClrIntTOut | ClrIntADC);
+ saradc.regs->Ctr1 |= ClrIntValDet;
+ } else {
+ /*DPRINTK("Buf_rdata = %u Buf_rdata/4 = %u\n", data, data/4);*/
+ DPRINTK("SARCODE = %u SARCODE/4 = %u\n", SARCODE, SARCODE/4);
+ /*Disable interrupt*/
+ saradc.regs->Ctr1 &= ~ValDetIntEn;
+ /* Clean all previous saradc status. */
+ saradc.regs->Ctr0 |= (ClrIntTOut | ClrIntADC);
+ saradc.regs->Ctr1 |= ClrIntValDet;
+ }
+
+ if (saradc_flag == 0) {
+ /* switch other button means release button*/
+ if ((pre_event != new_event) && (SARCODE/4 != 127)) {
+ button_press = 0;
+ DPRINTK("Different event, pre_event = %d, new_event = %d\n", pre_event, new_event);
+ DPRINTK("WMT_ROW1_KEY_NUM release key = %d, event=%d\n", SARCODE/4, pre_event);
+ input_report_key(saradc_dev, wmt_saradc_codes[pre_event], 0); /* key is release*/
+ input_sync(saradc_dev);
+ }
+
+ if (SARCODE/4 == 127 || SARCODE/4 == 126) { /*Active Low*/
+ DPRINTK("WMT_ROW1_KEY_NUM release key = %d, event=%d\n", SARCODE/4, pre_event);
+ input_report_key(saradc_dev, wmt_saradc_codes[pre_event], 0); /* key is release*/
+ input_sync(saradc_dev);
+ button_press = 0;
+ } else {
+ if (button_press == 0) {
+ DPRINTK("new event = %d\n", new_event);
+ input_report_key(saradc_dev, wmt_saradc_codes[new_event], 1);/* key is press*/
+ input_sync(saradc_dev);
+ DPRINTK("saradc code = %d\n", wmt_saradc_codes[new_event]);
+ button_press = 1;
+ }
+ DPRINTK("WMT_ROW1_KEY_NUM keep press key = %d, event=%d\n", SARCODE/4, new_event);
+ }
+ pre_event = new_event;
+ saradc_flag = 1; /* report new event to Android, get new SARCODE */
+ same = 0;
+ }
+ saradc.regs->Ctr1 |= ValDetIntEn;
+ DPRINTK("[%s] End\n", __func__);
+ return HRTIMER_NORESTART; /* avoid to timer restart */
+}
+
+static irqreturn_t
+saradc_interrupt(int irq, void *dev_id)
+{
+ ktime_t ktime;
+ ktime = ktime_set(0, INT_timeout * 1000); /* ms */
+ DPRINTK("[%s] Start\n", __func__);
+ DPRINTK("status = %x\n", saradc.regs->Ctr2);
+ /* Disable interrupt */
+ /* disable_irq_nosync(saradc.irq);*/
+ saradc.regs->Ctr1 &= ~ValDetIntEn;
+
+ saradc.regs->Ctr1 |= BufRd;
+ /*
+ * Get saradc interrupt status and clean interrput source.
+ */
+
+ /* if (((saradc.regs->Ctr1 & ValDetIntEn) == ValDetIntEn) && */
+ if ((saradc.regs->Ctr2 & ValDetIntStatus) == ValDetIntStatus) {
+ /* clear value chaning interrupt */
+ saradc.regs->Ctr1 |= ClrIntValDet;
+ /* start hrtimer */
+ hrtimer_start(&wmt_saradc_hrtimer, ktime, HRTIMER_MODE_REL);
+
+ /* count timer from interrupt to callback function */
+#ifdef COUNTTIMER
+ start_time = wmt_read_oscr();
+#endif
+ }
+
+ if ((saradc.regs->Ctr2 & ValDetIntStatus) == ValDetIntStatus)
+ printk(KERN_ERR "[saradc] status clear failed!\n");
+
+
+ /* Enable interrupt */
+ /* saradc.regs->Ctr1 |= ValDetIntEn; // enable INT in wmt_saradc_timeout_timer*/
+ DPRINTK("[%s] End\n", __func__);
+ return IRQ_HANDLED;
+}
+
+
+static unsigned int saradc_read(void)
+{
+ int i;
+ int min=0xfff,max=0;
+ int total=0,val;
+
+ for(i=0; i < 7; i++){
+ while ((saradc.regs->Ctr2 & EndcIntStatus) == 0);
+
+ val = SARCode(saradc.regs->Ctr1);
+ //printk("%d--",val);
+
+ if(max < val) max = val;
+ if(min > val) min = val;
+ total +=val;
+ }
+ //printk("value %d\n",(total-max-min)/5);
+ return (total-max-min)/5;
+
+}
+
+/* Read SARADC BATTRTY CODE */
+unsigned int ReadBattery(void)
+{
+ return BatteryCODE;
+}
+EXPORT_SYMBOL_GPL(ReadBattery);
+
+/* Update SARCODE BATTERY CODE */
+static void WriteBattery(unsigned int value)
+{
+ BatteryCODE = value;
+}
+static void saradc_bat_handler(struct work_struct *work)
+{
+ unsigned int sarcode = 0xffff;
+
+ DPRINTK("Start\n");
+ /* disable value change interrupt */
+ saradc.regs->Ctr1 &= ~ValDetIntEn;
+ /* Switch to BATTERY channel and clear INT status */
+ saradc.regs->Ctr0 |= (AdcChSel | ClrIntADC | ClrIntTOut);
+ saradc.regs->Ctr1 |= (ClrIntValDet);
+ msleep(20);
+ //printk("bat:\n");
+ sarcode = saradc_read();
+ WriteBattery(sarcode/4);
+ DPRINTK("sarcode = %d\n", sarcode);
+ /* Switch to ADC channel */
+ saradc.regs->Ctr0 &= ~AdcChSel;
+ /* too early to clear status will cause interrupts */
+ msleep(5);
+ /* Switch to BATTERY channel and clear INT status */
+ saradc.regs->Ctr0 |= (ClrIntADC | ClrIntTOut);
+ saradc.regs->Ctr1 |= (ClrIntValDet);
+
+ /* enable value change interrupt */
+ saradc.regs->Ctr1 |= ValDetIntEn;
+
+ schedule_delayed_work(&bat_work, bat_interval*HZ);
+ DPRINTK("End\n\n\n");
+ return ;
+}
+
+static int saradc_open(struct input_dev *dev)
+{
+ int ret = 0;
+ unsigned int i;
+ DPRINTK("Start saradc.ref = %d\n", saradc.ref);
+
+ if (saradc.ref++) {
+ /* Return success, but not initialize again. */
+ DPRINTK("End 1 saradc.ref=%d\n", saradc.ref);
+ return 0;
+ }
+
+ if (func != FUNC_KPAD)
+ goto bat_init;
+
+ ret = request_irq(saradc.irq, saradc_interrupt, IRQF_DISABLED, "saradc", dev);
+
+ if (ret) {
+ printk(KERN_ERR "%s: Can't allocate irq %d\n", __func__, IRQ_TSC);
+ saradc.ref--;
+ free_irq(saradc.irq, dev);
+ goto saradc_open_out;
+ }
+
+ /* Init hr timer */
+ hrtimer_init(&wmt_saradc_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ wmt_saradc_hrtimer.function = &wmt_saradc_timeout_hrtimer;
+
+ /* Register an input event device. */
+ dev->name = "saradc",
+ dev->phys = "saradc",
+
+ /*
+ * Let kpad to implement key repeat.
+ */
+
+ set_bit(EV_KEY, dev->evbit);
+
+ for (i = 0; i < WMT_SARADC_FUNCTION_NUM; i++)
+ set_bit(wmt_saradc_codes[i], dev->keybit);
+
+
+ dev->keycode = wmt_saradc_codes;
+ dev->keycodesize = sizeof(unsigned int);
+ dev->keycodemax = WMT_SARADC_FUNCTION_NUM;
+
+ /*
+ * For better view of /proc/bus/input/devices
+ */
+ dev->id.bustype = 0;
+ dev->id.vendor = 0;
+ dev->id.product = 0;
+ dev->id.version = 0;
+
+ input_register_device(dev);
+
+bat_init:
+ if (func == FUNC_BAT) {
+ INIT_DELAYED_WORK(&bat_work,saradc_bat_handler);
+ schedule_delayed_work(&bat_work, HZ);
+ }
+
+ wmt_saradc_hw_init();
+
+ DPRINTK("End2\n");
+saradc_open_out:
+ DPRINTK("End3\n");
+ return ret;
+}
+
+static void saradc_close(struct input_dev *dev)
+{
+ DPRINTK("Start\n");
+ if (--saradc.ref) {
+ DPRINTK("End1\n");
+ return;
+ }
+
+ /* Free interrupt resource */
+ free_irq(saradc.irq, dev);
+
+ /*Disable clock*/
+ auto_pll_divisor(DEV_ADC, CLK_DISABLE, 0, 0);
+
+ /* Unregister input device driver */
+ input_unregister_device(dev);
+ DPRINTK("End2\n");
+}
+
+static int wmt_saradc_probe(struct platform_device *pdev)
+{
+ unsigned long base;
+ int ret = 0;
+ DPRINTK("Start\n");
+ saradc_dev = input_allocate_device();
+ if (saradc_dev == NULL) {
+ DPRINTK("End 1\n");
+ return -1;
+ }
+ /*
+ * Simply check resources parameters.
+ */
+ if (pdev->num_resources < 2 || pdev->num_resources > 3) {
+ ret = -ENODEV;
+ goto saradc_probe_out;
+ }
+
+ base = pdev->resource[0].start;
+
+ saradc.irq = pdev->resource[1].start;
+
+ saradc.regs = (struct saradc_regs_s *)ADC_BASE_ADDR;
+
+ if (!saradc.regs) {
+ ret = -ENOMEM;
+ goto saradc_probe_out;
+ }
+
+ saradc_dev->open = saradc_open,
+ saradc_dev->close = saradc_close,
+
+ saradc_open(saradc_dev);
+ DPRINTK("End2\n");
+saradc_probe_out:
+
+#ifndef CONFIG_SKIP_DRIVER_MSG
+ printk(KERN_INFO "WMT saradc driver initialized: %s\n",
+ (ret == 0) ? "ok" : "failed");
+#endif
+ DPRINTK("End3\n");
+ return ret;
+}
+
+static int wmt_saradc_remove(struct platform_device *pdev)
+{
+ DPRINTK("Start\n");
+ saradc_close(saradc_dev);
+
+ /*
+ * Free allocated resource
+ */
+ /*kfree(kpad.res);
+ kpad.res = NULL;
+
+ if (kpad.regs) {
+ iounmap(kpad.regs);
+ kpad.regs = NULL;
+ }*/
+
+ saradc.ref = 0;
+ saradc.irq = 0;
+
+ DPRINTK("End\n");
+ return 0;
+}
+
+static int wmt_saradc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ DPRINTK("Start\n");
+
+ switch (state.event) {
+ case PM_EVENT_SUSPEND:
+ /*Disable clock*/
+ auto_pll_divisor(DEV_ADC, CLK_DISABLE, 0, 0);
+ break;
+ case PM_EVENT_FREEZE:
+ case PM_EVENT_PRETHAW:
+
+ default:
+ break;
+ }
+
+ DPRINTK("End2\n");
+ return 0;
+}
+
+static int wmt_saradc_resume(struct platform_device *pdev)
+{
+ DPRINTK("Start\n");
+ wmt_saradc_hw_init();
+ DPRINTK("End\n");
+ return 0;
+}
+
+static struct platform_driver wmt_saradc_driver = {
+ .driver.name = "wmt-saradc",
+ .probe = &wmt_saradc_probe,
+ .remove = &wmt_saradc_remove,
+ .suspend = &wmt_saradc_suspend,
+ .resume = &wmt_saradc_resume
+};
+
+static struct resource wmt_saradc_resources[] = {
+ [0] = {
+ .start = ADC_BASE_ADDR,
+ .end = (ADC_BASE_ADDR + 0xFFFF),
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_TSC,
+ .end = IRQ_TSC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device wmt_saradc_device = {
+ .name = "wmt-saradc",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(wmt_saradc_resources),
+ .resource = wmt_saradc_resources,
+};
+
+static int __init saradc_init(void)
+{
+ int ret;
+ int retval;
+ unsigned char buf[80];
+ int varlen = 80;
+ char *varname1 = "wmt.keypad.param";
+ char *varname2 = "wmt.battery.param";
+ char *p;
+ int temp = 0, enable_saradc = 0, function_sel = 0;
+
+ DPRINTK(KERN_ALERT "Start\n");
+ /*read keypad enable*/
+ retval = wmt_getsyspara(varname1, buf, &varlen);
+ if (retval == 0) {
+ sscanf(buf, "%X:%d:%d:%d", &temp, &HW_Hz, &INT_timeout, &SW_timeout);
+ enable_saradc = temp & 0xf;
+ function_sel = (temp >> 4) & 0xf;
+ printk(KERN_ALERT "wmt.keypad.param = %x:%d:%d:%d, enable = %x, function = %x\n",
+ temp, HW_Hz, INT_timeout, SW_timeout, enable_saradc, function_sel);
+
+ if (enable_saradc != 1 || function_sel != 1) {
+ printk(KERN_ALERT "Disable SARADC as keypad function!!\n");
+ goto bat;
+ } else if (enable_saradc == 1 && function_sel == 1)
+ printk(KERN_ALERT "HW_HZ = %d, INT_time = %d, SW_timeout = %d\n",
+ HW_Hz, INT_timeout, SW_timeout);
+ if ((HW_Hz == 0) || (INT_timeout == 0) || (SW_timeout == 0)) {
+ HW_Hz = 1000; /* 1000 Hz */
+ INT_timeout = 20000; /* 20 ms */
+ SW_timeout = 1000; /* 1 ms */
+ printk(KERN_ALERT "wmt.keypad.param isn't correct. Set the default value\n");
+ printk(KERN_ALERT "Default HW_HZ = %d, INT_time = %d, SW_timeout = %d\n",
+ HW_Hz, INT_timeout, SW_timeout);
+ }
+ func = FUNC_KPAD;
+ } else {
+ printk(KERN_ALERT "##Warning: \"wmt.keypad.param\" not find\n");
+ printk(KERN_ALERT "Default wmt.keypad.param = %x\n", temp);
+ //return -ENODEV;
+ }
+
+bat:
+ if (func != FUNC_KPAD) {
+ memset(buf, 0x00,sizeof(buf));
+ /* read battery enable, dev name and */
+ retval = wmt_getsyspara(varname2, buf, &varlen);
+ if (retval == 0) {
+ p = buf;
+ if(!strncmp(p,"saradc", 6)){
+ p = strchr(p,':');
+ if(p){
+ p++;
+ sscanf(p,"%d",&bat_interval);
+ }
+ printk("Bat ADC sample period = %ds\n", bat_interval);
+ func = FUNC_BAT;
+ }
+ }
+ }
+
+ if (func == FUNC_NONE) {
+ printk("SARADC not enable\n");
+ return -ENODEV;
+ }
+
+/* check saradc can switch freq.
+#ifdef CONFIG_CPU_FREQ
+ ret = cpufreq_register_notifier(&kpad_clock_nblock, \
+ CPUFREQ_TRANSITION_NOTIFIER);
+
+ if (ret) {
+ printk(KERN_ERR "Unable to register CPU frequency " \
+ "change notifier (%d)\n", ret);
+ }
+#endif
+*/
+ ret = platform_device_register(&wmt_saradc_device);
+ if (ret != 0) {
+ DPRINTK("End1 ret = %x\n", ret);
+ return -ENODEV;
+ }
+
+ ret = platform_driver_register(&wmt_saradc_driver);
+ DPRINTK("End2 ret = %x\n", ret);
+ return ret;
+}
+
+static void __exit saradc_exit(void)
+{
+ DPRINTK("Start\n");
+ platform_driver_unregister(&wmt_saradc_driver);
+ platform_device_unregister(&wmt_saradc_device);
+ DPRINTK("End\n");
+}
+
+module_init(saradc_init);
+module_exit(saradc_exit);
+
+MODULE_AUTHOR("WonderMedia Technologies, Inc.");
+MODULE_DESCRIPTION("WMT [generic saradc] driver");
+MODULE_LICENSE("GPL");