cyb4_linux/drivers/input/keyboard/s3c-keypad-qisda.c

1067 lines
35 KiB
C

/* Qisda Tony 090324, add keypad [
* drivers/input/keyboard/s3c-keypad-qisda.c
* KeyPad Interface on S3C in Qisda eBook
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
* for more details.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/irq.h>
#include <asm/arch/regs-irq.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/delay.h>
#include <asm/irq.h>
#include <asm/arch/regs-gpio.h>
/* Qisda, ShiYong Lin, 2009/08/18, Detect insertion source {*/
#include <asm/arch/regs-udc-hs.h>
#include <asm/arch/regs-s3c2416-clock.h>
/* } Qisda, ShiYong Lin, 2009/08/18, Detect insertion source */
#define DPRINTK(x...) printk("S3C-Keypad-qisda " x)
//#define DPRINTK(x...) /* !!!! */
#define DEVICE_NAME "s3c-keypad-qisda"
#define TRUE 1
#define FALSE 0
//#define IN_2416_EMU_BOARD
/* Qisda, ShiYong Lin, 2009/07/18, Set Power key as EINT for sys shutdown{*/
//#define POWER_KEY_FOR_SYS_SHUTDOWN
/* Qisda, ShiYong Lin, 2009/07/18, Set Power key as EINT for sys shutdown}*/
#define QISDA_TILT_0 0
#define QISDA_TILT_90 1
#define QISDA_TILT_180 3
#define QISDA_TILT_270 2
#if defined(CONFIG_QISDA_AS090B00_EVT1) || defined(CONFIG_QISDA_AS090B00_EVT1_1)
#define MAX_KEYPAD_QISDA 22
static int keypad_keycode_qisda[] = {
KEY_PAGEDOWN, KEY_PAGEUP, KEY_VOLUMEDOWN, KEY_VOLUMEUP,
KEY_F1, KEY_F2, KEY_F3, KEY_INSERT, KEY_ESC,
/* Qisda, ShiYong Lin, 2009/09/08, Implement for message for AP {*/
KEY_CHA_STA_WALL_CHARGER, KEY_CHA_STA_UNPLUG,
KEY_CHA_STA_USB, KEY_BATTERY_FAIL,
KEY_SLEEP, KEY_TIMER_TICK,
/* } Qisda, ShiYong Lin, 2009/09/08, Implement for message for AP */
KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_SOUND,
KEY_SD_INSERT
};
#endif
#ifdef CONFIG_QISDA_QD060B00
#define QISDA_E600
//#define QISDA_L600
#define MAX_KEYPAD_QISDA 27
static int keypad_keycode_qisda[] = {
KEY_MENU, KEY_SEARCH, KEY_PAGEDOWN, KEY_PAGEUP,
KEY_BACK, KEY_VOLUMEDOWN, KEY_VOLUMEUP, KEY_WAKEUP,
KEY_REFRESH, KEY_ENTER, KEY_UP, KEY_DOWN,
KEY_LEFT, KEY_RIGHT,
KEY_F1, KEY_F2, KEY_F3, KEY_F4,
KEY_F5, KEY_F6,
/* Qisda, ShiYong Lin, 2009/09/08, Implement for message for AP {*/
KEY_CLOSE, KEY_CHA_STA_WALL_CHARGER, KEY_CHA_STA_UNPLUG,
KEY_CHA_STA_USB, KEY_BATTERY_FAIL,
KEY_SLEEP, KEY_TIMER_TICK
/* } Qisda, ShiYong Lin, 2009/09/08, Implement for message for AP */
};
#endif
#ifdef CONFIG_QISDA_QD090B00
#define MAX_KEYPAD_QISDA 25
static int keypad_keycode_qisda[] = {
KEY_MENU, KEY_SEARCH, KEY_PAGEDOWN, KEY_PAGEUP,
KEY_BACK, KEY_VOLUMEDOWN, KEY_VOLUMEUP, KEY_WAKEUP,
KEY_REFRESH, KEY_ENTER, KEY_UP, KEY_DOWN,
KEY_F1, KEY_F2, KEY_F3, KEY_F4,
KEY_F5, KEY_F6,
/* Qisda, ShiYong Lin, 2009/09/08, Implement for message for AP {*/
KEY_CLOSE, KEY_CHA_STA_WALL_CHARGER, KEY_CHA_STA_UNPLUG,
KEY_CHA_STA_USB, KEY_BATTERY_FAIL,
KEY_SLEEP, KEY_TIMER_TICK
/* } Qisda, ShiYong Lin, 2009/09/08, Implement for message for AP */
};
#endif
struct s3c_keypad_qisda {
struct input_dev *dev;
int keycodes[MAX_KEYPAD_QISDA];
int pressed[MAX_KEYPAD_QISDA];
};
//static struct work_struct wqReadData;
static struct timer_list keypad_timer_qisda;
static int is_timer_on_qisda = FALSE;
static int keypad_set_irq = FALSE;
/* Qisda, ShiYong Lin, 2009/11/11, Fix the trembling voice issue when plugging usb {*/
static struct timer_list charger_source_timer;
/* } Qisda, ShiYong Lin, 2009/11/11, Fix the trembling voice issue when plugging usb */
/* Qisda, ShiYong Lin, 2009/11/11, Modify for pwr fail event occurring wrongly when heavy loading {*/
static struct timer_list power_fail_timer;
static struct work_struct power_fail_workq;
u32 is_pwr_fail_timer_on = 0;
/* } Qisda, ShiYong Lin, 2009/11/11, Modify for pwr fail event occurring wrongly when heavy loading */
int charging_source = 3;
struct input_dev *Message_dev = NULL;
//static unsigned prevmask = 1;
static void keypad_port_initialize(void)
{
#ifdef CONFIG_QISDA_AS090B00
//Set gpio as input and pull-up enable
s3c2410_gpio_cfgpin(S3C2410_GPD10, S3C2410_GPD10_INP); //T_SENSOR2
s3c2410_gpio_cfgpin(S3C2410_GPD11, S3C2410_GPD11_INP); //T_SENSOR1
s3c2410_gpio_cfgpin(S3C2410_GPF0, S3C2410_GPF0_EINT0); // power
s3c2410_gpio_pullup(S3C2410_GPF0, 2);
s3c2410_gpio_cfgpin(S3C2410_GPD14, S3C2410_GPD14_INP); // Menu
s3c2410_gpio_pullup(S3C2410_GPD14, 2);
s3c2410_gpio_cfgpin(S3C2410_GPD15, S3C2410_GPD15_INP); // Return
s3c2410_gpio_pullup(S3C2410_GPD15, 2);
s3c2410_gpio_cfgpin(S3C2410_GPG6, S3C2410_GPG6_INP); // Function
s3c2410_gpio_pullup(S3C2410_GPG6, 2);
s3c2410_gpio_cfgpin(S3C2410_GPH4, S3C2410_GPH4_INP); // VOL+
s3c2410_gpio_pullup(S3C2410_GPH4, 2);
s3c2410_gpio_cfgpin(S3C2410_GPH5, S3C2410_GPH5_INP); // VOL-
s3c2410_gpio_pullup(S3C2410_GPH5, 2);
s3c2410_gpio_cfgpin(S3C2410_GPF7, S3C2410_GPF7_INP); // page up
s3c2410_gpio_pullup(S3C2410_GPF7, 2);
s3c2410_gpio_cfgpin(S3C2410_GPG7, S3C2410_GPG7_INP); // Page down
s3c2410_gpio_pullup(S3C2410_GPG7, 2);
#endif
#ifdef CONFIG_QISDA_QD090B00
//Set gpio as input and pull-up enable
s3c2410_gpio_cfgpin(S3C2410_GPD10, S3C2410_GPD10_INP); //T_SENSOR2
s3c2410_gpio_cfgpin(S3C2410_GPD11, S3C2410_GPD11_INP); //T_SENSOR1
s3c2410_gpio_cfgpin(S3C2410_GPD14, S3C2410_GPD14_INP); // Search
s3c2410_gpio_pullup(S3C2410_GPD14, 2);
s3c2410_gpio_cfgpin(S3C2410_GPD15, S3C2410_GPD15_INP); // Return
s3c2410_gpio_pullup(S3C2410_GPD15, 2);
s3c2410_gpio_cfgpin(S3C2410_GPF0, S3C2410_GPF0_EINT0); // power
s3c2410_gpio_pullup(S3C2410_GPF0, 2);
s3c2410_gpio_cfgpin(S3C2410_GPF7, S3C2410_GPF7_INP); // page down
s3c2410_gpio_pullup(S3C2410_GPF7, 2);
s3c2410_gpio_cfgpin(S3C2410_GPG4, S3C2410_GPG4_INP); // Refresh
s3c2410_gpio_pullup(S3C2410_GPG4, 2);
s3c2410_gpio_cfgpin(S3C2410_GPG6, S3C2410_GPG6_INP); // Menu
s3c2410_gpio_pullup(S3C2410_GPG6, 2);
s3c2410_gpio_cfgpin(S3C2410_GPG7, S3C2410_GPG7_INP); // Page up
s3c2410_gpio_pullup(S3C2410_GPG7, 2);
s3c2410_gpio_cfgpin(S3C2410_GPH4, S3C2410_GPH4_INP); // VOL+
s3c2410_gpio_pullup(S3C2410_GPH4, 2);
s3c2410_gpio_cfgpin(S3C2410_GPH5, S3C2410_GPH5_INP); // VOL-
s3c2410_gpio_pullup(S3C2410_GPH5, 2);
#endif
#ifdef CONFIG_QISDA_QD060B00
s3c2410_gpio_cfgpin(S3C2410_GPD10, S3C2410_GPD10_INP); //T_SENSOR2
s3c2410_gpio_cfgpin(S3C2410_GPD11, S3C2410_GPD11_INP); //T_SENSOR1
//Set gpio as input and pull-up enable
s3c2410_gpio_cfgpin(S3C2410_GPD14, S3C2410_GPD14_INP); // Menu
s3c2410_gpio_pullup(S3C2410_GPD14, 2);
s3c2410_gpio_cfgpin(S3C2410_GPD15, S3C2410_GPD15_INP); // Page down / Back
s3c2410_gpio_pullup(S3C2410_GPD15, 2);
s3c2410_gpio_cfgpin(S3C2410_GPF0, S3C2410_GPF0_EINT0); // power
s3c2410_gpio_pullup(S3C2410_GPF0, 2);
s3c2410_gpio_cfgpin(S3C2410_GPF7, S3C2410_GPF7_INP); // Back / Right
s3c2410_gpio_pullup(S3C2410_GPF7, 2);
#ifdef QISDA_E600
s3c2410_gpio_cfgpin(S3C2410_GPG4, S3C2410_GPG4_INP); // Page up
s3c2410_gpio_pullup(S3C2410_GPG4, 2);
#endif
s3c2410_gpio_cfgpin(S3C2410_GPG6, S3C2410_GPG6_INP); // VOL / Down
s3c2410_gpio_pullup(S3C2410_GPG6, 2);
s3c2410_gpio_cfgpin(S3C2410_GPG7, S3C2410_GPG7_INP); // Refresh / Left
s3c2410_gpio_pullup(S3C2410_GPG7, 2);
#ifdef QISDA_L600
s3c2410_gpio_cfgpin(S3C2410_GPH4, S3C2410_GPH4_INP); // OK
s3c2410_gpio_pullup(S3C2410_GPH4, 2);
#endif
s3c2410_gpio_cfgpin(S3C2410_GPH5, S3C2410_GPH5_INP); // Search / UP
s3c2410_gpio_pullup(S3C2410_GPH5, 2);
#endif
/* Qisda, ShiYong Lin, 2009/08/27, Implement for message for AP {*/
// Power_Fail, GPG5, need to open when EVT2
// Both edge triggered
s3c2410_gpio_cfgpin(S3C2410_GPG5, S3C2410_GPG5_EINT13);
s3c2410_gpio_pullup(S3C2410_GPG5, 2);
writel((readl(S3C2410_EXTINT1) & ~(1<<23)), S3C2410_EXTINT1); /* EINT13 filter enable */
writel(((readl(S3C2410_EXTINT1) & ~(7<<20))|(6<<20)), S3C2410_EXTINT1);
// CHG_STA, GPG1, need to open when EVT2,
// Both edge triggered
s3c2410_gpio_cfgpin(S3C2410_GPG1, S3C2410_GPG1_EINT9);
s3c2410_gpio_pullup(S3C2410_GPG1, 0);
writel((readl(S3C2410_EXTINT1) & ~(1<<7)), S3C2410_EXTINT1); /* EINT9 filter enable */
writel(((readl(S3C2410_EXTINT1) & ~(7<<4))|(6<<4)), S3C2410_EXTINT1);
}
struct s3c_keypad_qisda *pdata;
/*
static s3c_keypad_qisda_workqueue(struct work_struct *work)
{
struct input_dev *dev = pdata->dev;
DPRINTK("s3c_keypad_qisda_workqueue 1\n");
input_report_key(dev,pdata->keycodes[0],1);
input_sync(dev);
msleep(200);
input_report_key(dev,pdata->keycodes[0],0);
input_sync(dev);
}
*/
/* Qisda, ShiYong Lin, 2009/09/10, Detect insertion source {*/
/*Leo*/
int IsWallCharger(void)
{
u32 i=0;
u32 read_pin=99, test_pin = 99;
udelay(1000);
if((readl(S3C2410_GPGDAT)&0x2)==0x2){
s3c2410_gpio_cfgpin(S3C2443_GPH14, S3C2443_GPH14_OUTP);
s3c2410_gpio_setpin(S3C2443_GPH14, 1); /* usb power enbale */
s3c2410_gpio_cfgpin(S3C2410_GPD13, S3C2410_GPD13_OUTP);
s3c2410_gpio_setpin(S3C2410_GPD13,1); /* usb power enbale */
/* if reset by sleep wakeup, control the retention I/O cell */
if (__raw_readl(S3C_RSTSTAT) & 0x8)
__raw_writel(__raw_readl(S3C_RSTCON)|(1<<16), S3C_RSTCON);
__raw_writel(__raw_readl(S3C2410_MISCCR)&~(1<<12), S3C2410_MISCCR);
__raw_writel(__raw_readl(S3C_PWRCFG)|(1<<4), S3C_PWRCFG);
__raw_writel((0<<2)|(1<<0), S3C_URSTCON);
udelay(1000);
__raw_writel((1<<2)|(0<<0), S3C_URSTCON);
__raw_writel((0<<2)|(0<<0), S3C_URSTCON);
__raw_writel((0<<3)|(0<<2)|(0<<1)|(0<<0), S3C_PHYCTRL);
__raw_writel((1<<31)|(0<<4)|(0<<3)|(0<<2)|(0<<1)|(0<<0), S3C_PHYPWR);
__raw_writel((0<<31)|(1<<2)|(1<<1)|(1<<0), S3C_UCLKCON);
__raw_writel((1<<31)|(1<<2)|(1<<1)|(1<<0), S3C_UCLKCON);
}
read_pin = __raw_readl(S3C_UDC_SYS_STATUS_REG)&0x60;
if(read_pin !=0x60){
// printk("usb\n");
#if defined(CONFIG_QISDA_E600_EVT2)|| defined(CONFIG_QISDA_QD060N00_DVT1_1)
if((readl(S3C2410_GPGDAT) &(1<<1))==0)
{
if((readl(S3C2410_GPHDAT) &&(1<<11))==0)
{
printk("3G Module off\n");
s3c2410_gpio_cfgpin(S3C2443_GPH14, S3C2443_GPH14_OUTP);
s3c2410_gpio_setpin(S3C2443_GPH14, 0);
}
__raw_writel((0<<31)|(0<<2)|(1<<1)|(1<<0), S3C_UCLKCON);
}
#endif
#if defined(CONFIG_QISDA_AS090B00_EVT1)||defined(CONFIG_QISDA_AS090B00_EVT1_1)||defined(CONFIG_QISDA_QD090B00_EVT1)
if((readl(S3C2410_GPGDAT) &(1<<1))==0)
{
if((readl(S3C2410_GPHDAT) &(1<<11))==0)
{
// printk("3G Module off\n");
s3c2410_gpio_cfgpin(S3C2443_GPH14, S3C2443_GPH14_OUTP);
s3c2410_gpio_setpin(S3C2443_GPH14, 0);
}
__raw_writel((0<<31)|(0<<2)|(1<<1)|(1<<0), S3C_UCLKCON);
}
#endif
return 0;
}
else
{
// printk("wall charger\n");
#if defined(CONFIG_QISDA_E600_EVT2)||defined(CONFIG_QISDA_QD060N00_DVT1_1)
if((readl(S3C2410_GPGDAT) &(1<<1))==0)
{
s3c2410_gpio_cfgpin(S3C2443_GPH14, S3C2443_GPH14_OUTP);
s3c2410_gpio_setpin(S3C2443_GPH14, 0);
__raw_writel((0<<31)|(0<<2)|(1<<1)|(1<<0), S3C_UCLKCON);
}
#endif
#if defined(CONFIG_QISDA_AS090B00_EVT1)||defined(CONFIG_QISDA_AS090B00_EVT1_1)||defined(CONFIG_QISDA_QD090B00_EVT1)
if((readl(S3C2410_GPGDAT) &(1<<1))==0)
{
if((readl(S3C2410_GPHDAT) &(1<<11))==0)
{
s3c2410_gpio_cfgpin(S3C2443_GPH14, S3C2443_GPH14_OUTP);
s3c2410_gpio_setpin(S3C2443_GPH14, 0);
}
__raw_writel((0<<31)|(0<<2)|(1<<1)|(1<<0), S3C_UCLKCON);
}
#endif
return 1;
}
}
/*Leo*/
/* } Qisda, ShiYong Lin, 2009/09/10, Detect insertion source */
static void s3c_keypad_deal(struct input_dev *dev, u32 read_pin, int key)
{
if(read_pin){ //should be released
if(pdata->pressed[key]){
input_report_key(dev, pdata->keycodes[key], 0);
input_sync(dev);
pdata->pressed[key] = 0;
printk(" release: %d\n", pdata->keycodes[key]);
}
}
else{ //should be pressed
if(!pdata->pressed[key]){
input_report_key(dev, pdata->keycodes[key], 1);
input_sync(dev);
pdata->pressed[key] = 1;
printk(" press: %d\n", pdata->keycodes[key]);
}
}
}
static irqreturn_t s3c_pwrbtn_close_irq(int irq, void *id)
{
/* Qisda, ShiYong Lin, 2009/08/27, Implementing power btn behavior {*/
struct input_dev *dev = id;
u32 read_pin;
read_pin = readl(S3C2410_GPFDAT) & (1<<0);
#if defined(CONFIG_QISDA_AS090B00_EVT1) || defined(CONFIG_QISDA_AS090B00_EVT1_1)
s3c_keypad_deal(dev, read_pin, 8);
#elif defined(CONFIG_QISDA_QD090B00) || defined(CONFIG_QISDA_QD060N00_DVT1_1)
s3c_keypad_deal(dev, read_pin, 7);
#else
s3c_keypad_deal(dev, read_pin, 7);
#endif
//close system by letting P_KEEP low
#ifdef POWER_KEY_FOR_SYS_SHUTDOWN
s3c2410_gpio_setpin(S3C2410_GPG0, 0);
s3c2410_gpio_cfgpin(S3C2410_GPG0, S3C2410_GPG0_OUTP);
#endif
/* } Qisda, ShiYong Lin, 2009/08/27, Implementing power btn behavior */
return IRQ_HANDLED;
}
/* Qisda, ShiYong Lin, 2009/11/11, Fix the trembling voice issue when plugging usb {*/
static irqreturn_t s3c_cha_sta_irq(int irq, void *id)
{
printk("s3c_cha_sta_irq\n");
disable_irq(IRQ_EINT9);
charger_source_timer.expires = jiffies + (HZ);
add_timer(&charger_source_timer);
return IRQ_HANDLED;
}
/* } Qisda, ShiYong Lin, 2009/11/11, Fix the trembling voice issue when plugging usb */
/* Qisda, ShiYong Lin, 2009/11/11, Modify for pwr fail event occurring wrongly when heavy loading {*/
static irqreturn_t s3c_pwr_fail_irq(int irq, void *id)
{
printk("s3c_pwr_fail_irq, detecting\n");
disable_irq(IRQ_EINT13);
power_fail_timer.expires = jiffies + (HZ*3);
if(is_pwr_fail_timer_on == 0){
// printk("add_timer, detected\n");
add_timer(&power_fail_timer);
is_pwr_fail_timer_on = 1;
}
else{
// printk("mod_timer, detected\n");
mod_timer(&power_fail_timer, keypad_timer_qisda.expires);
}
return IRQ_HANDLED;
}
/* } Qisda, ShiYong Lin, 2009/11/11, Modify for pwr fail event occurring wrongly when heavy loading */
/* Qisda, ShiYong Lin, 2009/07/22, Implement function for RTC tick service {*/
void rtc_tick_keypad_message_to_ap (void)
{
input_report_key(Message_dev,KEY_TIMER_TICK,1);
input_sync(Message_dev);
input_report_key(Message_dev,KEY_TIMER_TICK,0);
input_sync(Message_dev);
printk("rtc_tick_keypad_message_to_ap, keypad_message_to_ap\n");
}
/*} Qisda, ShiYong Lin, 2009/07/22, Implement function for RTC tick service */
/* Qisda, Leo SJ Yang, 2009/10/26*/
/*send key code F6 1 when USB plugin*/
/*send key code F6 0 when USB unplug*/
/*send key code F6 0 when safely remove usb{*/
void USB_SaftRemove_keypad_message_to_ap(uint uiSleep)
{
if(uiSleep==1)
{
input_report_key(Message_dev,KEY_F6,1);
input_sync(Message_dev);
}
else
{
input_report_key(Message_dev,KEY_F6,0);
input_sync(Message_dev);
printk("USB_SaftRemove_keypad_message_to_ap, USB_SaftRemove_keypad_message_to_ap press\n");
}
}
/*} Qisda, Leo SJ Yang, 2009/10/26*/
/* Qisda, ShiYong Lin, 2009/09/08, Implement sleep message to AP {*/
void s3c_keypad_pm_sleep_message_to_ap (uint uiSleep)
{
if(uiSleep){
input_report_key(Message_dev,KEY_SLEEP,1);
input_sync(Message_dev);
}
else{
input_report_key(Message_dev,KEY_SLEEP,0);
input_sync(Message_dev);
}
}
/* } Qisda, ShiYong Lin, 2009/09/08, Implement sleep message to AP */
static void s3c_keypad_set_irq(struct input_dev *dev)
{
set_irq_type(IRQ_EINT0, 0x3);
request_irq(IRQ_EINT0, s3c_pwrbtn_close_irq,
SA_INTERRUPT, DEVICE_NAME, dev);
set_irq_type(IRQ_EINT9, 0x3);
request_irq(IRQ_EINT9, s3c_cha_sta_irq,
SA_INTERRUPT, "s3c2410-charging status", dev);
/* Qisda, ShiYong Lin, 2009/11/11, Modify for pwr fail event occurring wrongly when heavy loading {*/
if((readl(S3C2410_GPGDAT) & (1<<5)) == 0){
set_irq_type(IRQ_EINT13, IRQT_HIGH);
}
else{
set_irq_type(IRQ_EINT13, IRQT_LOW);
}
/* } Qisda, ShiYong Lin, 2009/11/11, Modify for pwr fail event occurring wrongly when heavy loading */
request_irq(IRQ_EINT13, s3c_pwr_fail_irq,
SA_INTERRUPT, "s3c2410-power fail status", dev);
}
/* Qisda, ShiYong Lin, 2009/11/11, Fix the trembling voice issue when plugging usb {*/
static void charger_source_handler(unsigned long data)
{
u32 read_pin = 99;
printk("charger_source_handler_qisda\n");
read_pin = readl(S3C2410_GPGDAT) & (1<<1);
printk("GPG1 = %d\n", read_pin);
if(read_pin != 0){
input_report_key(Message_dev, KEY_CHA_STA_UNPLUG, 0);
input_sync(Message_dev);
printk("usb or wallchager\n");
if(IsWallCharger()==0){
charging_source = 0;
input_report_key(Message_dev, KEY_CHA_STA_USB, 1);
input_sync(Message_dev);
printk("USB, EN2 = 0, EN1 = 1\n");
//EN2
s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPB0_OUTP);
s3c2410_gpio_setpin(S3C2410_GPB0, 0);
//EN1
s3c2410_gpio_cfgpin(S3C2410_GPB4, S3C2410_GPB4_OUTP);
s3c2410_gpio_setpin(S3C2410_GPB4, 1);
}
else
{
charging_source = 1;
input_report_key(Message_dev, KEY_CHA_STA_WALL_CHARGER, 1);
input_sync(Message_dev);
printk("Charger, EN2 = 1, EN1 = 0\n");
//EN2
s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPB0_OUTP);
s3c2410_gpio_setpin(S3C2410_GPB0, 1);
//EN1
s3c2410_gpio_cfgpin(S3C2410_GPB4, S3C2410_GPB4_OUTP);
s3c2410_gpio_setpin(S3C2410_GPB4, 0);
}
}
else{
printk("nothing\n");
input_report_key(Message_dev, KEY_CHA_STA_UNPLUG, 1);
input_sync(Message_dev);
if(charging_source==0){
input_report_key(Message_dev, KEY_CHA_STA_USB, 0);
input_sync(Message_dev);
}
else{
input_report_key(Message_dev, KEY_CHA_STA_WALL_CHARGER, 0);
input_sync(Message_dev);
}
charging_source = 2;
printk("EN2 = 0, EN1 = 1\n");
//EN2
s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPB0_OUTP);
s3c2410_gpio_setpin(S3C2410_GPB0, 0);
//EN1
s3c2410_gpio_cfgpin(S3C2410_GPB4, S3C2410_GPB4_OUTP);
s3c2410_gpio_setpin(S3C2410_GPB4, 1);
}
enable_irq(IRQ_EINT9);
}
/* } Qisda, ShiYong Lin, 2009/11/11, Fix the trembling voice issue when plugging usb */
/* Qisda, ShiYong Lin, 2009/11/11, Modify for pwr fail event occurring wrongly when heavy loading {*/
static void power_fail_handler(unsigned long data)
{
// printk("power_fail_handler\n");
schedule_work(&power_fail_workq);
}
static void power_fail_workqueue(struct work_struct *work)
{
u32 test_pin, i;
u32 read_pin = readl(S3C2410_GPGDAT) & (1<<5);
msleep(1);
// printk("power_fail_workqueue, read_pin = %d\n",read_pin);
for(i = 0; i <100; i++){
test_pin = readl(S3C2410_GPGDAT) & (1<<5);
msleep(1);
if(read_pin != test_pin){
printk("read_pin != test_pin\n");
is_pwr_fail_timer_on = 0;
enable_irq(IRQ_EINT13);
return;
}
msleep(1);
}
// printk("power_fail_workqueue test_pin = %d\n", read_pin);
if(read_pin == 0){
// printk("send KEY_BATTERY_FAIL trigger, 0\n");
set_irq_type(IRQ_EINT13, IRQT_HIGH);
#if defined(CONFIG_QISDA_AS090B00_EVT1) || defined(CONFIG_QISDA_AS090B00_EVT1_1)
s3c_keypad_deal(Message_dev, 0, 12);
#elif defined(CONFIG_QISDA_QD090B00)
s3c_keypad_deal(Message_dev, 0, 22);
#elif CONFIG_QISDA_QD060N00_DVT1_1
s3c_keypad_deal(Message_dev, 0, 24);
#else
s3c_keypad_deal(Message_dev, 0, 12);
#endif
}
else{
// printk("send KEY_BATTERY_FAIL trigger, 1\n");
set_irq_type(IRQ_EINT13, IRQT_LOW);
#if defined(CONFIG_QISDA_AS090B00_EVT1) || defined(CONFIG_QISDA_AS090B00_EVT1_1)
s3c_keypad_deal(Message_dev, 1, 12);
#elif defined(CONFIG_QISDA_QD090B00)
s3c_keypad_deal(Message_dev, 1, 22);
#elif CONFIG_QISDA_QD060N00_DVT1_1
s3c_keypad_deal(Message_dev, 1, 24);
#else
s3c_keypad_deal(Message_dev, 1, 12);
#endif
}
is_pwr_fail_timer_on = 0;
enable_irq(IRQ_EINT13);
return;
}
/* } Qisda, ShiYong Lin, 2009/11/11, Modify for pwr fail event occurring wrongly when heavy loading */
static void keypad_timer_handler_qisda(unsigned long data)
{
u32 read_pin;
static u32 headphonr_insert;
static int headphonr_insert_counter=2;
u32 read_tilt;
static u32 tilt_status_previous;
static int tilt_counter=3;
//struct s3c_keypad_qisda *pdata = (struct s3c_keypad_qisda *)data;
pdata = (struct s3c_keypad_qisda *)data;
struct input_dev *dev = pdata->dev;
#ifdef CONFIG_QISDA_AS090B00
read_pin = readl(S3C2410_GPFDAT);
s3c_keypad_deal(dev, (read_pin & (0x1<<7)), 0); // Page down
s3c_keypad_deal(dev, (read_pin & (0x1<<1)), 21); // SD card
if(headphonr_insert != (read_pin & (1<<4))){ // Headphone
if(headphonr_insert_counter != 0){
headphonr_insert_counter --;
}
else{
if(read_pin & (1<<4)){
//printk("Earphone insert!!!!!!!!!!!!!!!!\n");
input_report_switch(dev, SW_HEADPHONE_INSERT, 1);
input_sync(dev);
}
else {
//printk("Earphone remove!!!!!!!!!!!!!!!!!!!!!\n");
input_report_switch(dev, SW_HEADPHONE_INSERT, 0);
input_sync(dev);
}
headphonr_insert = read_pin & (1<<4);
headphonr_insert_counter = 2;
}
}
else{
headphonr_insert_counter = 2;
}
read_pin = readl(S3C2410_GPGDAT);
s3c_keypad_deal(dev, (read_pin & (0x1<<6)), 6); // Function
s3c_keypad_deal(dev, (read_pin & (0x1<<7)), 1); // Page up
read_pin = readl(S3C2410_GPHDAT);
s3c_keypad_deal(dev, read_pin & 1<<5, 2); // Volume down
s3c_keypad_deal(dev, read_pin & 1<<4, 3); // Volume up
read_pin = readl(S3C2410_GPDDAT);
s3c_keypad_deal(dev, read_pin & 1<<14, 5); // Menu
s3c_keypad_deal(dev, read_pin & 1<<15, 7); // Return
read_tilt = (readl(S3C2410_GPDDAT) & (0x3<<10)) >> 10;
if(tilt_status_previous != read_tilt){
if(tilt_counter != 0){
tilt_counter--;
}
else{
if(read_tilt == QISDA_TILT_270){
s3c_keypad_deal(dev, 1, 16);
s3c_keypad_deal(dev, 1, 17);
s3c_keypad_deal(dev, 1, 18);
s3c_keypad_deal(dev, 0, 19);
}
else if(read_tilt == QISDA_TILT_90){
s3c_keypad_deal(dev, 1, 16);
s3c_keypad_deal(dev, 1, 18);
s3c_keypad_deal(dev, 1, 19);
s3c_keypad_deal(dev, 0, 17);
}
else if(read_tilt == QISDA_TILT_180){
s3c_keypad_deal(dev, 1, 16);
s3c_keypad_deal(dev, 1, 17);
s3c_keypad_deal(dev, 1, 19);
s3c_keypad_deal(dev, 0, 18);
}
else{ //QISDA_TILT_0
s3c_keypad_deal(dev, 1, 17);
s3c_keypad_deal(dev, 1, 18);
s3c_keypad_deal(dev, 1, 19);
s3c_keypad_deal(dev, 0, 16);
}
tilt_status_previous = read_tilt;
tilt_counter = 3;
}
}
else{
tilt_counter = 3;
s3c_keypad_deal(dev, 1, 16);
s3c_keypad_deal(dev, 1, 17);
s3c_keypad_deal(dev, 1, 18);
s3c_keypad_deal(dev, 1, 19);
}
#endif
#ifdef CONFIG_QISDA_QD090B00
read_pin = readl(S3C2410_GPFDAT);
s3c_keypad_deal(dev, (read_pin & (0x1<<7)), 2); // Page down
s3c_keypad_deal(dev, (read_pin & (0x1<<1)), 16); // SD card
if(headphonr_insert != (read_pin & (1<<4))){ // Headphone
if(headphonr_insert_counter != 0){
headphonr_insert_counter --;
}
else{
if(read_pin & (1<<4)){
//printk("Earphone insert!!!!!!!!!!!!!!!!\n");
input_report_switch(dev, SW_HEADPHONE_INSERT, 1);
input_sync(dev);
}
else {
//printk("Earphone remove!!!!!!!!!!!!!!!!!!!!!\n");
input_report_switch(dev, SW_HEADPHONE_INSERT, 0);
input_sync(dev);
}
headphonr_insert = read_pin & (1<<4);
headphonr_insert_counter = 2;
}
}
else{
headphonr_insert_counter = 2;
}
read_pin = readl(S3C2410_GPGDAT);
s3c_keypad_deal(dev, (read_pin & (0x1<<4)), 8); // Refresh
s3c_keypad_deal(dev, (read_pin & (0x1<<6)), 0); // Menu
s3c_keypad_deal(dev, (read_pin & (0x1<<7)), 3); // Page up
read_pin = readl(S3C2410_GPHDAT);
s3c_keypad_deal(dev, read_pin & 1<<5, 5); // Volume down
s3c_keypad_deal(dev, read_pin & 1<<4, 6); // Volume up
read_pin = readl(S3C2410_GPDDAT);
s3c_keypad_deal(dev, read_pin & 1<<14, 1); // Search
s3c_keypad_deal(dev, read_pin & 1<<15, 4); // Return
read_tilt = (read_pin & (0x3<<10)) >> 10;
if(tilt_status_previous != read_tilt){
if(tilt_counter != 0){
tilt_counter--;
}
else{
if(read_tilt == QISDA_TILT_270){
s3c_keypad_deal(dev, 1, 12);
s3c_keypad_deal(dev, 1, 13);
s3c_keypad_deal(dev, 1, 14);
s3c_keypad_deal(dev, 0, 15);
}
else if(read_tilt == QISDA_TILT_90){
s3c_keypad_deal(dev, 1, 12);
s3c_keypad_deal(dev, 1, 15);
s3c_keypad_deal(dev, 1, 14);
s3c_keypad_deal(dev, 0, 13);
}
else if(read_tilt == QISDA_TILT_180){
s3c_keypad_deal(dev, 1, 15);
s3c_keypad_deal(dev, 1, 12);
s3c_keypad_deal(dev, 1, 13);
s3c_keypad_deal(dev, 0, 14);
}
else{ //QISDA_TILT_0
s3c_keypad_deal(dev, 1, 15);
s3c_keypad_deal(dev, 1, 13);
s3c_keypad_deal(dev, 1, 14);
s3c_keypad_deal(dev, 0, 12);
}
tilt_status_previous = read_tilt;
tilt_counter = 3;
}
}
else{
tilt_counter = 3;
s3c_keypad_deal(dev, 1, 12);
s3c_keypad_deal(dev, 1, 13);
s3c_keypad_deal(dev, 1, 14);
s3c_keypad_deal(dev, 1, 15);
}
#endif
#ifdef CONFIG_QISDA_QD060B00
read_pin = readl(S3C2410_GPFDAT);
#ifdef QISDA_E600
s3c_keypad_deal(dev, (read_pin & (0x1<<7)), 4); // Back
#endif
#ifdef QISDA_L600
s3c_keypad_deal(dev, (read_pin & (0x1<<7)), 13); // Right
#endif
s3c_keypad_deal(dev, (read_pin & (0x1<<1)), 18); // SD card
if(headphonr_insert != (read_pin & (1<<4))){ // Headphone
if(headphonr_insert_counter != 0){
headphonr_insert_counter --;
}
else{
if(read_pin & (1<<4)){
//printk("Earphone removed\n");
input_report_switch(dev, SW_HEADPHONE_INSERT, 0);
input_sync(dev);
}
else {
//printk("Earphone inserted\n");
input_report_switch(dev, SW_HEADPHONE_INSERT, 1);
input_sync(dev);
}
headphonr_insert = read_pin & (1<<4);
headphonr_insert_counter = 2;
}
}
else{
headphonr_insert_counter = 2;
}
read_pin = readl(S3C2410_GPGDAT);
#ifdef QISDA_E600
s3c_keypad_deal(dev, (read_pin & (0x1<<4)), 3); // Page up
s3c_keypad_deal(dev, (read_pin & (0x1<<6)), 6); // Volume
s3c_keypad_deal(dev, (read_pin & (0x1<<7)), 8); // Refresh
#endif
#ifdef QISDA_L600
s3c_keypad_deal(dev, (read_pin & (0x1<<6)), 11); // Down
s3c_keypad_deal(dev, (read_pin & (0x1<<7)), 12); // Left
#endif
read_pin = readl(S3C2410_GPHDAT);
#ifdef QISDA_E600
s3c_keypad_deal(dev, read_pin & 1<<5, 1); // Search
#endif
#ifdef QISDA_L600
s3c_keypad_deal(dev, read_pin & 1<<4, 9); // OK
s3c_keypad_deal(dev, read_pin & 1<<5, 10); // Up
#endif
read_pin = readl(S3C2410_GPDDAT);
s3c_keypad_deal(dev, read_pin & 1<<14, 0); // Menu
#ifdef QISDA_E600
s3c_keypad_deal(dev, read_pin & 1<<15, 2); // Page down
#endif
#ifdef QISDA_L600
s3c_keypad_deal(dev, read_pin & 1<<15, 4); // Back
#endif
read_tilt = (read_pin & (0x3<<10)) >> 10;
if(tilt_status_previous != read_tilt){
if(tilt_counter != 0){
tilt_counter--;
}
else{
if(read_tilt == QISDA_TILT_270){
s3c_keypad_deal(dev, 1, 14);
s3c_keypad_deal(dev, 1, 15);
s3c_keypad_deal(dev, 1, 16);
s3c_keypad_deal(dev, 0, 17);
}
else if(read_tilt == QISDA_TILT_90){
s3c_keypad_deal(dev, 1, 14);
s3c_keypad_deal(dev, 1, 17);
s3c_keypad_deal(dev, 1, 16);
s3c_keypad_deal(dev, 0, 15);
}
else if(read_tilt == QISDA_TILT_180){
s3c_keypad_deal(dev, 1, 17);
s3c_keypad_deal(dev, 1, 14);
s3c_keypad_deal(dev, 1, 15);
s3c_keypad_deal(dev, 0, 16);
}
else{ //QISDA_TILT_0
s3c_keypad_deal(dev, 1, 17);
s3c_keypad_deal(dev, 1, 15);
s3c_keypad_deal(dev, 1, 16);
s3c_keypad_deal(dev, 0, 14);
}
tilt_status_previous = read_tilt;
tilt_counter = 3;
}
}
else{
tilt_counter = 3;
s3c_keypad_deal(dev, 1, 14);
s3c_keypad_deal(dev, 1, 15);
s3c_keypad_deal(dev, 1, 16);
s3c_keypad_deal(dev, 1, 17);
}
#endif
if (is_timer_on_qisda == FALSE) {
add_timer(&keypad_timer_qisda);
is_timer_on_qisda = TRUE;
} else {
keypad_timer_qisda.expires = jiffies + (HZ/8);
mod_timer(&keypad_timer_qisda,keypad_timer_qisda.expires);
}
if(!keypad_set_irq){
s3c_keypad_set_irq(pdata->dev);
keypad_set_irq = TRUE;
}
}
static int __init s3c_keypad_qisda_probe(struct platform_device *pdev)
{
int ret=0;
int i;
struct input_dev *input_dev;
struct s3c_keypad_qisda *s3c_keypad_qisda;
DPRINTK("s3c_keypad_qisda_probe for Qisda eBook\n");
keypad_port_initialize();
s3c_keypad_qisda = kzalloc(sizeof(struct s3c_keypad_qisda), GFP_KERNEL);
input_dev = input_allocate_device();
if (!s3c_keypad_qisda || !input_dev) {
ret = -ENOMEM;
goto out;
}
platform_set_drvdata(pdev, s3c_keypad_qisda);
s3c_keypad_qisda->dev = input_dev;
/* create and register the input driver */
set_bit(EV_KEY, input_dev->evbit);
//set_bit(EV_REP, input_dev->evbit);
set_bit(EV_SW, input_dev->evbit);
set_bit(SW_HEADPHONE_INSERT, input_dev->swbit);
for(i=0; i<MAX_KEYPAD_QISDA; i++){
s3c_keypad_qisda->keycodes[i] = keypad_keycode_qisda[i];
s3c_keypad_qisda->pressed[i] = 0;
set_bit(s3c_keypad_qisda->keycodes[i] & KEY_MAX, input_dev->keybit);
}
input_dev->name = DEVICE_NAME;
input_dev->phys = "s3c-keypad-qisda/input0";
input_dev->cdev.dev = &pdev->dev;
input_dev->private = s3c_keypad_qisda;
input_dev->id.bustype = BUS_HOST;
input_dev->id.vendor = 0x0001;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0001;
input_dev->keycode = keypad_keycode_qisda;
input_register_device(input_dev);
/* Scan timer init */
init_timer(&keypad_timer_qisda);
keypad_timer_qisda.function = keypad_timer_handler_qisda;
keypad_timer_qisda.data = (unsigned long)s3c_keypad_qisda;
keypad_timer_qisda.expires = jiffies + (HZ*10);
if (is_timer_on_qisda == FALSE) {
add_timer(&keypad_timer_qisda);
is_timer_on_qisda = TRUE;
} else {
mod_timer(&keypad_timer_qisda,keypad_timer_qisda.expires);
}
/* Qisda, ShiYong Lin, 2009/11/11, Fix the trembling voice issue when plugging usb {*/
init_timer(&charger_source_timer);
charger_source_timer.function = charger_source_handler;
/* } Qisda, ShiYong Lin, 2009/11/11, Fix the trembling voice issue when plugging usb */
/* Qisda, ShiYong Lin, 2009/11/11, Modify for pwr fail event occurring wrongly when heavy loading {*/
init_timer(&power_fail_timer);
power_fail_timer.function = power_fail_handler;
INIT_WORK(&power_fail_workq, power_fail_workqueue);
/* } Qisda, ShiYong Lin, 2009/11/11, Modify for pwr fail event occurring wrongly when heavy loading */
//initial work queue
//INIT_WORK(&wqReadData,s3c_keypad_qisda_workqueue);
DPRINTK("s3c_keypad_qisda_probe finished\n");
/* Qisda, ShiYong Lin, 2009/08/27, Implement for message for AP {*/
Message_dev = input_dev;
/* } Qisda, ShiYong Lin, 2009/08/27, Implement for message for AP */
return 0;
out:
input_unregister_device(input_dev);
kfree(s3c_keypad_qisda);
return ret;
}
static int s3c_keypad_qisda_remove(struct platform_device *pdev)
{
struct input_dev *input_dev = platform_get_drvdata(pdev);
del_timer(&keypad_timer_qisda);
input_unregister_device(input_dev);
kfree(pdev->dev.platform_data);
DPRINTK("Removed");
return 0;
}
#ifdef CONFIG_PM
static int s3c_keypad_qisda_suspend(struct platform_device *dev, pm_message_t state)
{
return 0;
}
static int s3c_keypad_qisda_resume(struct platform_device *dev)
{
keypad_port_initialize();
return 0;
}
#else
#define s3c_keypad_suspend_qisda NULL
#define s3c_keypad_resume_qisda NULL
#endif /* CONFIG_PM */
static struct platform_driver s3c_keypad_qisda_driver = {
.probe = s3c_keypad_qisda_probe,
.remove = s3c_keypad_qisda_remove,
.suspend = s3c_keypad_qisda_suspend,
.resume = s3c_keypad_qisda_resume,
.driver = {
.owner = THIS_MODULE,
.name = DEVICE_NAME,
},
};
static int __init s3c_keypad_qisda_init(void) { return platform_driver_register(&s3c_keypad_qisda_driver); }
static void __exit s3c_keypad_qisda_exit(void) { platform_driver_unregister(&s3c_keypad_qisda_driver); }
module_init(s3c_keypad_qisda_init);
module_exit(s3c_keypad_qisda_exit);
MODULE_AUTHOR("Tony YC Huang");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("KeyPad interface for Samsung S3C 2416,Qisda eBook");
// Qisda Tony 090324, add keypad ]