/* * amr_keypad.c * * * Copyright (C) 2012 Loongson Corporation * * 2013-03-15 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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"); /*----------------------------------------------------------------------------*/