ckfwq/linux-3.0.4/drivers/input/keyboard/amr_keypad.c

305 lines
7.8 KiB
C

/*
* amr_keypad.c
*
*
* Copyright (C) 2012 Loongson Corporation
*
* 2013-03-15
*/
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/rcupdate.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/completion.h>
#include <asm/io.h>
#include <linux/fs.h>
#include <linux/fcntl.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <linux/gpio.h>
#include <gsc3280/gpio.h>
#include <gsc3280/sysctl.h>
#define AMR_KPD_GPIO_SET_REG_BIT(reg) do {\
int i;\
unsigned int reg_val = 0;\
reg_val = __raw_readl((volatile unsigned int *)(reg));\
for (i = 0; i < AMR_PIN_NR; i++) {\
reg_val |= (0x01 << amr_gpios[i].gpio);\
}\
__raw_writel(reg_val, (volatile unsigned int *)(reg));\
} while (0)
#define AMR_KPD_GPIO_CLR_REG_BIT(reg) do {\
int i;\
unsigned int reg_val = 0;\
reg_val = __raw_readl((volatile unsigned int *)(reg));\
for (i = 0; i < AMR_PIN_NR; i++) {\
reg_val &= ~(0x01 << amr_gpios[i].gpio);\
}\
__raw_writel(reg_val, (volatile unsigned int *)(reg));\
} while (0)
enum {
AMR_KYP_UP = 0,
AMR_KYP_DOWN,
AMR_KYP_LEFT,
AMR_KYP_RIGHT,
AMR_KYP_OK,
AMR_KYP_CANCEL,
AMR_PIN_NR,
};
struct gpio amr_gpios[AMR_PIN_NR] = {
{GSC3280_GPA(9) , GPIOF_IN, "UP"},
{GSC3280_GPA(10), GPIOF_IN, "DOWN"},
{GSC3280_GPA(11), GPIOF_IN, "LEFT"},
{GSC3280_GPA(12), GPIOF_IN, "RIGHT"},
{GSC3280_GPA(21), GPIOF_IN, "OK"},
{GSC3280_GPA(27), GPIOF_IN, "CANCEL"}
};
static const int amr_keycode[AMR_PIN_NR] = {
KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT,
KEY_OK, KEY_CANCEL
};
/*----------------------------------------------------------------------------*/
struct amr_keypad {
struct input_dev *input;
struct gpio *arr_gpio;
struct timer_list amr_timer;
unsigned int cur_index;
bool timer_run;
};
struct amr_keypad amr_keypad_priv;
void amr_timer_fn(unsigned long arg)
{
unsigned int cur_gpio_index;
struct amr_keypad *p_amr_keypad = (struct amr_keypad *)arg;
cur_gpio_index = p_amr_keypad->cur_index;
if (!gpio_get_value(p_amr_keypad->arr_gpio[cur_gpio_index].gpio)) {
int key_code = amr_keycode[cur_gpio_index];
input_report_key(p_amr_keypad->input, key_code,
!test_bit(key_code, p_amr_keypad->input->key));
input_sync(p_amr_keypad->input);
}
p_amr_keypad->timer_run = false;
}
/*----------------------------------------------------------------------------*/
static irqreturn_t amr_keypad_isr(int irq, void *dev_id)
{
unsigned int reg_val = 0;
int key_code = 0;
struct amr_keypad *p_amr_keypad = dev_id;
/*
if (timer_pending(&p_amr_keypad->amr_timer))
return IRQ_HANDLED;
*/
reg_val =
__raw_readl((volatile unsigned int *)(GSC3280_REGADDR_GPIO_INTSTATUS));
if (reg_val & (0x01 << p_amr_keypad->arr_gpio[AMR_KYP_UP].gpio)) {
p_amr_keypad->cur_index = AMR_KYP_UP;
} else if (reg_val & (0x01 << p_amr_keypad->arr_gpio[AMR_KYP_DOWN].gpio)) {
p_amr_keypad->cur_index = AMR_KYP_DOWN;
} else if (reg_val & (0x01 << p_amr_keypad->arr_gpio[AMR_KYP_LEFT].gpio)) {
p_amr_keypad->cur_index = AMR_KYP_LEFT;
} else if (reg_val & (0x01 << p_amr_keypad->arr_gpio[AMR_KYP_RIGHT].gpio)) {
p_amr_keypad->cur_index = AMR_KYP_RIGHT;
} else if (reg_val & (0x01 << p_amr_keypad->arr_gpio[AMR_KYP_OK].gpio)) {
p_amr_keypad->cur_index = AMR_KYP_OK;
} else if (reg_val & (0x01 << p_amr_keypad->arr_gpio[AMR_KYP_CANCEL].gpio)) {
p_amr_keypad->cur_index = AMR_KYP_CANCEL;
} else {
return IRQ_HANDLED;
}
if (!gpio_get_value(p_amr_keypad->arr_gpio[p_amr_keypad->cur_index].gpio)) {
key_code = amr_keycode[p_amr_keypad->cur_index];
input_report_key(p_amr_keypad->input, key_code,
!test_bit(key_code, p_amr_keypad->input->key));
input_sync(p_amr_keypad->input);
}
/*
if (false == p_amr_keypad->timer_run)
{
printk(KERN_ERR "=************==== BUTONN %d", p_amr_keypad->cur_index);
p_amr_keypad->timer_run = true;
p_amr_keypad->amr_timer.data = (unsigned long)p_amr_keypad;
p_amr_keypad->amr_timer.expires = jiffies + 20;
p_amr_keypad->amr_timer.function = amr_timer_fn;
add_timer(&p_amr_keypad->amr_timer);
}
*/
AMR_KPD_GPIO_SET_REG_BIT(GSC3280_REGADDR_GPIO_PORTA_EOI);
return IRQ_HANDLED;
}
/*----------------------------------------------------------------------------*/
static int amr_kp_open(struct input_dev *dev)
{
//enable pin interrupt
AMR_KPD_GPIO_SET_REG_BIT(GSC3280_REGADDR_GPIO_INTEN);
// clear interrupt
AMR_KPD_GPIO_SET_REG_BIT(GSC3280_REGADDR_GPIO_PORTA_EOI);
return 0;
}
/*----------------------------------------------------------------------------*/
static void amr_kp_close(struct input_dev *dev)
{
//disable pin interrupt
AMR_KPD_GPIO_CLR_REG_BIT(GSC3280_REGADDR_GPIO_INTEN);
return;
}
void enable_amr_keypad_gpio_ctrl(void)
{
//edge trigger
AMR_KPD_GPIO_SET_REG_BIT(GSC3280_REGADDR_GPIO_INTTYPE_LEVEL);
//debounce
AMR_KPD_GPIO_SET_REG_BIT(GSC3280_REGADDR_GPIO_DEBOUNCE);
//unmask
AMR_KPD_GPIO_CLR_REG_BIT(GSC3280_REGADDR_GPIO_INTMASK);
}
/*----------------------------------------------------------------------------*/
static int __init amr_keypad_init(void)
{
int i = 0;
int err = 0;
int p_irq = gpio_to_irq(amr_gpios[0].gpio);
err = gpio_request_array(amr_gpios, AMR_PIN_NR);
if (err < 0) {
printk(KERN_ERR "amr_keypad_init gpio_request_array failed!\n");
err = -ENODEV;
goto EXIT;
}
amr_keypad_priv.arr_gpio = amr_gpios;
err = request_irq(p_irq, &amr_keypad_isr, IRQF_DISABLED,
"amr-kpd", &amr_keypad_priv);
if (err < 0) {
printk(KERN_ERR "amr_keypad_init request_irq[%d] failed!\n", p_irq);
err = -ENODEV;
goto FREE_GPIO;
}
enable_amr_keypad_gpio_ctrl();
amr_keypad_priv.input = input_allocate_device();
if (!amr_keypad_priv.input) {
err = -ENOMEM;
goto out_free_irq;
}
/* event type set */
set_bit(EV_KEY, amr_keypad_priv.input->evbit);
amr_keypad_priv.input->name = "amr_keypad";
amr_keypad_priv.input->phys = "input/amr_keypad";
amr_keypad_priv.input->id.bustype = BUS_HOST;
amr_keypad_priv.input->id.vendor = 0;
amr_keypad_priv.input->id.product = 0;
amr_keypad_priv.input->id.version = 0x0001;
for (i = 0; i < AMR_PIN_NR; i++)
set_bit(amr_keycode[i], amr_keypad_priv.input->keybit);
//set_bit(KEY_WAKEUP, amr_keypad_priv.input->keybit);
input_set_drvdata(amr_keypad_priv.input, &amr_keypad_priv);
amr_keypad_priv.input->open = amr_kp_open;
amr_keypad_priv.input->close = amr_kp_close;
err = input_register_device(amr_keypad_priv.input);
if (err) {
printk("unable to register input device: %d\n", err);
goto out_freeinput;
}
init_timer(&amr_keypad_priv.amr_timer);
amr_keypad_priv.timer_run = false;
sysctl_iomux_disable(SYSCTL_IOMUX_JTAG);
//sysctl_mod_disable(SYSCTL_IOMUX_JTAG);
return err;
out_freeinput:
input_free_device(amr_keypad_priv.input);
out_free_irq:
for (i = 0; i < AMR_PIN_NR; i++) {
int p_irq = gpio_to_irq(amr_gpios[i].gpio);
free_irq(p_irq, &amr_gpios[i]);
}
FREE_GPIO:
gpio_free_array(amr_gpios, AMR_PIN_NR);
EXIT:
return err;
}
/*----------------------------------------------------------------------------*/
static void __exit amr_keypad_exit(void)
{
int i = 0;
input_free_device(amr_keypad_priv.input);
for (i = 0; i < AMR_PIN_NR; i++) {
int p_irq = gpio_to_irq(amr_gpios[i].gpio);
free_irq(p_irq, &amr_gpios[i]);
}
gpio_free_array(amr_gpios, AMR_PIN_NR);
}
/*----------------------------------------------------------------------------*/
module_init(amr_keypad_init);
module_exit(amr_keypad_exit);
/*----------------------------------------------------------------------------*/
MODULE_AUTHOR("ansonn.wang@gmail.com");
MODULE_DESCRIPTION("amr keypad");
MODULE_LICENSE("GPL");
/*----------------------------------------------------------------------------*/