/*
* This is a driver code for matrix keyboard
* GPN0 1 2 --- ROW0 1 2
* GPN4 5 6 9 --- COL0 1 2 3
* use EINT0 1 2 for EX IRQ
* AUTHOR: LiuTao
* date : 2011-12-02
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
MODULE_AUTHOR("HaNdAEr~L.T");
MODULE_LICENSE("GPL");
struct input_dev *button_devp;
static char *name = "my6410_buttons";
volatile int COLVAL = 0;
volatile int ROWVAL = 0;
volatile int key_num = 0;
/*struct of irq*/
struct button_irq_desc{
int irq;
int pin;
int number;
char *name;
};
/*IRQ for module*/
static struct button_irq_desc button_irqs[] = {
{ IRQ_EINT(0),S3C64XX_GPN(0), 0, "rol1"},
{ IRQ_EINT(1),S3C64XX_GPN(1), 1, "rol2"},
{ IRQ_EINT(2),S3C64XX_GPN(2), 2, "rol3"},
{ IRQ_EINT(3),S3C64XX_GPN(3), 3, "s27" },
};
/*input_report_key */
static void report_key(int keyno,int reportval)
{
// printk("in check_key ...ret_keyno = %d...\n",keyno);
//printk("in check_key ...reportval = %d...\n",reportval);
switch(keyno){
case 1:
//printk("key1 down...\n");
input_report_key(button_devp, BTN_0, reportval);
break;
case 2:
//printk("key2 down...\n");
input_report_key(button_devp, BTN_1, reportval);
break;
case 3:
//printk("key3 down...\n");
input_report_key(button_devp, BTN_2, reportval);
break;
case 4:
//printk("key4 down...\n");
input_report_key(button_devp, BTN_3, reportval);
break;
case 5:
// printk("key5 down...\n");
input_report_key(button_devp, BTN_4, reportval);
break;
case 6:
// printk("key6 down...\n");
input_report_key(button_devp, BTN_5, reportval);
break;
case 7:
// printk("key7 down...\n");
input_report_key(button_devp, BTN_6, reportval);
break;
case 8:
// printk("key8 down...\n");
input_report_key(button_devp, BTN_7, reportval);
break;
case 9:
// printk("key9 down...\n");
input_report_key(button_devp, BTN_8, reportval);
break;
case 10:
// printk("key10 down...\n");
input_report_key(button_devp, BTN_9, reportval);
break;
case 11:
// printk("key11 down...\n");
input_report_key(button_devp, BTN_A, reportval);
break;
case 12:
// printk("key12 down...\n");
input_report_key(button_devp, BTN_B, reportval);
break;
default:
break;
}
input_sync(button_devp);
}
/*012 as input VS 4 5 6 9 as output*/
static void port_init(void)
{
unsigned int tmp = 0;
tmp = readl(S3C64XX_GPNCON);
tmp &= ~(0xffffffff); //0 1 2 input
tmp |= (1 << 8) | (1 << 10) | (1 << 12) | (1 << 18) ; // 4 5 6 9 0x010101 01
writel(tmp,S3C64XX_GPNCON);
}
/*012 output VS 4 5 6 9 as input*/
static void Port_Init(void)
{
unsigned int tmp = 0;
tmp = readl(S3C64XX_GPNCON);
tmp &= ~(0xffffffff);
tmp |= 0x00000015;
writel(tmp,S3C64XX_GPNCON);
}
volatile unsigned long GPNDAT,GPN_VIRT;
/*to make sure COLVAL = ? ROWVAL = ?*/
static void Scan_Keyboard(void)
{
volatile unsigned int IOValue = 0,iovalue = 0;
volatile unsigned int temp = 0;
volatile unsigned int reiovalue = 0;
volatile int i;
//int count = 0;
temp = readl(GPNDAT);
temp |= (1 << 4) | (1 << 5) | (1 << 6) | (1 << 9);
// temp &= ~(1 << 0) & ~(1 << 1) & ~(1 << 2);
writel(temp,GPNDAT);
Port_Init();
IOValue = readl(GPNDAT);
//printk("1...IOVAlue = %x...\n",IOValue);
if((IOValue & (1 << 0)) == 0)
{
ROWVAL= 1;
}
else if((IOValue & (1 << 1)) == 0)
{
ROWVAL= 2;
}
else if((IOValue & (1 << 2)) == 0)
{
ROWVAL = 3;
}
/* delay */
for (i=0; i<10000; i++) asm ("");
iovalue = readl(GPNDAT);
//printk("IOValue = %x..\n",iovalue);
iovalue |= (1 << 4) | (1 << 5) | (1 << 6) | (1 << 9);
//iovalue |= (1 << 0) | (1 << 1) | (1 << 2);
//iovalue &= ~(1 << 4) & ~(1 << 5) & ~(1 << 6) & ~(1 << 9);
//printk("IOValue = %x...\n",IOValue);
writel(iovalue,GPNDAT);
port_init(); // init GPNCON set 0 1 2 output
temp = readl(GPNDAT);
//printk("temp = %x..\n",temp);
if((temp & (1 << 4)) == 0)
{
COLVAL = 1;
}
else if((temp & (1 << 5)) == 0)
{
COLVAL = 2;
}
else if((temp & ( 1 << 6)) == 0)
{
COLVAL = 3;
}
else if((temp & (1 << 9)) == 0)
{
COLVAL = 4;
}
/*set GPNDAT4 5 6 9 low level */
/*The most important step*/
reiovalue = readl(GPNDAT);
reiovalue &= ~(1 << 4) & ~(1 << 5) & ~(1 << 6) & ~(1 << 9);
writel(reiovalue,GPNDAT);
}
/*to make sure which key... key_num = ? */
static void set_keynum(int Cval,int Rval,int reportval)
{
if(Rval == 1)
{
switch(Cval)
{
case 1:
key_num = 1;
break;
case 2:
key_num = 2;
break;
case 3:
key_num = 3;
break;
case 4:
key_num = 4;
break;
}
}
else if(Rval == 2)
{
switch(Cval)
{
case 1:
key_num = 5;
break;
case 2:
key_num = 6;
break;
case 3:
key_num = 7;
break;
case 4:
key_num = 8;
break;
}
}
else if(Rval == 3)
{
switch(Cval)
{
case 1:
key_num = 9;
break;
case 2:
key_num = 10;
break;
case 3:
key_num = 11;
break;
case 4:
key_num = 12;
break;
}
}
}
/*interrupt code */
static int save_irq = 0;
static irqreturn_t button_interrupt(int irq, void* dev_id)
{
struct button_irq_desc *button_irqs = (struct button_irq_desc*)dev_id;
unsigned int IOValue = 0;
int status, retval;
disable_irq(IRQ_EINT(0));
disable_irq(IRQ_EINT(1));
disable_irq(IRQ_EINT(2));
status = readl(S3C64XX_GPNDAT) & ( 0x1 << button_irqs->number);
retval = status ? 0 : 1;
//printk("retval = %d \n",retval);
if(retval == 1){
save_irq = button_irqs->irq;
Scan_Keyboard(); //scan_keyboard
//printk("\n COLVAL =%d ROWVAL = %d.....\n",COLVAL,ROWVAL );
//printk("+++++++++\n");
set_keynum(COLVAL,ROWVAL,retval); // key_num ?
report_key(key_num,retval);
//printk("\nkey_num = %d...\n",key_num);
IOValue = readl(S3C64XX_GPNCON);
IOValue &= ~(0xffffffff);
IOValue |= 0x000415aa;;
writel(IOValue,S3C64XX_GPNCON);
}
else if ((retval == 0) && (save_irq == button_irqs->irq))
{
report_key(key_num,retval);
}
enable_irq(IRQ_EINT(0));
enable_irq(IRQ_EINT(1));
enable_irq(IRQ_EINT(2));
//printk("end irq+++++++++\n");
return IRQ_RETVAL(IRQ_HANDLED);
}
/*request IRQ IRQ_EINT(0 1 2)*/
static int Request_Irq(void)
{
int err = 0;
int i;
for(i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++)
{
err = request_irq(button_irqs[i].irq, button_interrupt, IRQ_TYPE_EDGE_BOTH, button_irqs[i].name, (void *)&button_irqs[i]);
if(err)
{
break;
}
}
if(err)
{
i--;
for(; i >= 0; i--)
{
if(button_irqs[i].irq < 0)
{
continue;
}
disable_irq(button_irqs[i].irq);
free_irq(button_irqs[i].irq, (void*)&button_irqs[i]);
}
return -EBUSY;
}
return 0;
}
/*first run*/
static int __init button_init(void)
{
struct input_dev *input_dev;
int ret;
GPN_VIRT = ioremap(0x7F008000,SZ_4K);
GPNDAT = GPN_VIRT + 0x834;
input_dev = input_allocate_device();
if(!input_dev)
{
printk(KERN_ERR"Unable to alloc the input device!!\n");
}
button_devp = input_dev;
button_devp->name = name;
Request_Irq();
set_bit(EV_KEY, button_devp->evbit);
set_bit(BTN_0, button_devp->keybit);
set_bit(BTN_1, button_devp->keybit);
set_bit(BTN_2, button_devp->keybit);
set_bit(BTN_3, button_devp->keybit);
set_bit(BTN_4, button_devp->keybit);
set_bit(BTN_5, button_devp->keybit);
set_bit(BTN_6, button_devp->keybit);
set_bit(BTN_7, button_devp->keybit);
set_bit(BTN_8, button_devp->keybit);
set_bit(BTN_9, button_devp->keybit);
set_bit(BTN_A, button_devp->keybit);
set_bit(BTN_B, button_devp->keybit);
set_bit(BTN_C, button_devp->keybit);
ret = input_register_device(button_devp);
if(ret < 0){
printk("input_register_device(): failed !! \n");
}
return ret;
}
/*exit*/
static void __exit button_exit(void)
{
int i;
for(i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++)
{
disable_irq(button_irqs[i].irq);
free_irq(button_irqs[i].irq, (void*)&button_irqs[i]);
}
input_unregister_device(button_devp);
}
module_init(button_init);
module_exit(button_exit);