/*++ 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 . WonderMedia Technologies, Inc. 10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C. --*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* 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; igpio) == 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; inum_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