/********************************************************************************* * Copyright: (C) 2017 NetEase(Hangzhou) Network Co., Ltd. * All rights reserved. * * Filename: R16-keyboard.c * Description: This is the common button driver runs on S3C2440 * * Version: 1.0.0(8/3/2017) * Author: Netease IHW * ChangeLog: 1, Release initial version * ********************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define USED_SYSCONF 0 #define DRV_NAME ("r16kbd") #define GPIO_HOME_KEY GPIOL(9) #define GPIO_MUTE_KEY GPIOL(9) #if USED_SYSCONF struct encoder_gkey_config { u32 encoder1_gkey; u32 encoder2_gkey; }; #else #define GPIO_ENCODER1 GPIOL(11) #define GPIO_ENCODER2 GPIOL(12) struct Volkey_status { u8 nVolup; u8 nVoldown; }; #endif enum { DEBUG_INIT = 1U << 0, DEBUG_INT = 1U << 1, DEBUG_DATA_INFO = 1U << 2, DEBUG_SUSPEND = 1U << 3, }; static u32 debug_mask = 0; #define dprintk(level_mask, fmt, arg...) \ if (unlikely(debug_mask & level_mask)) \ printk(fmt, ##arg) struct gpio_keys_button_data { int last_state; int count; int threshold; int can_sleep; }; struct gpio_keys_polled_dev { struct input_polled_dev *poll_dev; struct device *dev; struct gpio_keys_platform_data *pdata; struct gpio_keys_button_data data[0]; }; #if USED_SYSCONF static struct encoder_gkey_config *r16_gkey; #endif static struct Volkey_status *sVolkey_status; static struct input_dev *tymr16kbd_dev; static struct input_polled_dev *poll_dev; #define VOL_CONFIRM 5 #define GPIO_BUTTON(gpio_num, ev_code, act_low, descr, wake, debounce) \ { \ .gpio = gpio_num, .type = EV_KEY, .code = ev_code, \ .active_low = act_low, .desc = "btn " descr, .wakeup = wake, \ .debounce_interval = debounce, \ } static struct gpio_keys_button tym_r16_buttons[] = { GPIO_BUTTON(GPIO_HOME_KEY, KEY_HOME, 1, "user-key-home", 0, 1), }; struct rotary_encoder_data { u8 encoder_state; }; static struct gpio_keys_platform_data tym_r16_button_data = { .buttons = tym_r16_buttons, .nbuttons = ARRAY_SIZE(tym_r16_buttons), .poll_interval = 50, .name = "tymkey", }; static void init_nVol(void) { sVolkey_status->nVolup = 0; sVolkey_status->nVoldown = 0; } static irqreturn_t rotary_encoder_check_state_irq(int irq, void *dummy) { int state_a, state_b; #if USED_SYSCONF state_a = !!gpio_get_value(r16_gkey->encoder1_gkey); state_b = !!gpio_get_value(r16_gkey->encoder2_gkey); #else state_a = !!gpio_get_value(GPIO_ENCODER1); state_b = !!gpio_get_value(GPIO_ENCODER2); #endif if (state_b != state_a) { sVolkey_status->nVoldown++; /*dprintk(DEBUG_INIT,"encoder check state v+ \n"); input_event(tymr16kbd_dev, EV_KEY, KEY_VOLUMEDOWN, 2); input_sync(tymr16kbd_dev);*/ } else { sVolkey_status->nVolup++; /*dprintk(DEBUG_INIT,"encoder check state v- \n"); input_event(tymr16kbd_dev, EV_KEY, KEY_VOLUMEUP, 2); input_sync(tymr16kbd_dev);*/ } if (sVolkey_status->nVoldown > VOL_CONFIRM) { init_nVol(); dprintk(DEBUG_INIT, "encoder check state v+ \n"); input_event(tymr16kbd_dev, EV_KEY, KEY_VOLUMEDOWN, 2); input_sync(tymr16kbd_dev); } if (sVolkey_status->nVolup > VOL_CONFIRM) { init_nVol(); dprintk(DEBUG_INIT, "encoder check state v- \n"); input_event(tymr16kbd_dev, EV_KEY, KEY_VOLUMEUP, 2); input_sync(tymr16kbd_dev); } return IRQ_HANDLED; } static void gpio_keys_polled_check_state(struct input_dev *input, struct gpio_keys_button *button, struct gpio_keys_button_data *bdata) { int state; // dprintk(DEBUG_INIT,"gpio_keys_polled_check_state\n"); if (bdata->can_sleep) state = !!gpio_get_value_cansleep(button->gpio); else state = !!gpio_get_value(button->gpio); if (state != bdata->last_state) { unsigned int type = button->type ?: EV_KEY; dprintk(DEBUG_INIT, "button->gpio, %d , state, %d \n", button->gpio, state); input_event(input, type, button->code, !!(state ^ button->active_low)); input_sync(input); bdata->count = 0; bdata->last_state = state; } } static void gpio_keys_polled_poll(struct input_polled_dev *dev) { struct gpio_keys_polled_dev *bdev = dev->private; struct gpio_keys_platform_data *pdata = bdev->pdata; struct input_dev *input = dev->input; int i; // dprintk(DEBUG_INIT,"gpio_keys_polled_poll"); for (i = 0; i < bdev->pdata->nbuttons; i++) { struct gpio_keys_button_data *bdata = &bdev->data[i]; gpio_keys_polled_check_state(input, &pdata->buttons[i], bdata); } } static void gpio_keys_polled_open(struct input_polled_dev *dev) { struct gpio_keys_polled_dev *bdev = dev->private; struct gpio_keys_platform_data *pdata = bdev->pdata; if (pdata->enable) pdata->enable(bdev->dev); } static void gpio_keys_polled_close(struct input_polled_dev *dev) { struct gpio_keys_polled_dev *bdev = dev->private; struct gpio_keys_platform_data *pdata = bdev->pdata; if (pdata->disable) pdata->disable(bdev->dev); } #if USED_SYSCONF static int GPIO_fetch_sysconfig_para(void) { int ret = -1; int gpio_used = -1; script_item_u val; script_item_value_type_e type; dprintk(DEBUG_INIT, "gpio fetch sysconfig para!\n"); r16_gkey = input_allocate_device(); if (!r16_gkey) { pr_err("tymkbd: not enough memory for input device\n"); ret = -ENOMEM; goto script_get_item_err; } type = script_get_item("gkey_para", "gkey_used", &val); if (SCIRPT_ITEM_VALUE_TYPE_INT != type) { pr_err("%s: gkey_used script_get_item err. \n", __func__); goto script_get_item_err; } gpio_used = val.val; if (1 == gpio_used) { type = script_get_item("gkey_para", "gkey_encoder1", &val); if (SCIRPT_ITEM_VALUE_TYPE_PIO != type) { goto script_get_item_err; } r16_gkey->encoder1_gkey = val.gpio.gpio; type = script_get_item("gkey_para", "gkey_encoder2", &val); if (SCIRPT_ITEM_VALUE_TYPE_PIO != type) { goto script_get_item_err; } r16_gkey->encoder2_gkey = val.gpio.gpio; ret = 0; } else { pr_err("%s: gkey_unused. \n", __func__); ret = -1; } script_get_item_err: printk("get gpio fetch sysconfig para error!\n"); return ret; } #endif static int __init r16_button_init(void) { #if 1 struct gpio_keys_polled_dev *bdev; int i; int error; int virq; dprintk(DEBUG_INIT, "r16_button_init\n"); #if USED_SYSCONF GPIO_fetch_sysconfig_para(); #endif sVolkey_status = kzalloc(sizeof(struct Volkey_status), GFP_KERNEL); init_nVol(); bdev = kzalloc(sizeof(struct gpio_keys_polled_dev) + tym_r16_button_data.nbuttons * sizeof(struct gpio_keys_button_data), GFP_KERNEL); if (!bdev) { pr_err("no memory for private data\n"); return -ENOMEM; } bdev->pdata = &tym_r16_button_data; poll_dev = input_allocate_polled_device(); if (!poll_dev) { pr_err("no memory for polled device\n"); goto err_free_bdev; } poll_dev->private = bdev; poll_dev->poll = gpio_keys_polled_poll; poll_dev->poll_interval = 50; // poll_dev->open = gpio_keys_polled_open; // poll_dev->close = gpio_keys_polled_close; tymr16kbd_dev = input_allocate_device(); if (!tymr16kbd_dev) { pr_err("tymkbd: not enough memory for input device\n"); error = -ENOMEM; goto fail1; } tymr16kbd_dev->name = DRV_NAME; tymr16kbd_dev->phys = "r16kbd/input0"; tymr16kbd_dev->id.bustype = BUS_HOST; tymr16kbd_dev->id.vendor = 0x0001; tymr16kbd_dev->id.product = 0x0001; tymr16kbd_dev->id.version = 0x0100; tymr16kbd_dev->evbit[0] = BIT_MASK(EV_KEY); poll_dev->input = tymr16kbd_dev; for (i = 0; i < tym_r16_button_data.nbuttons; i++) { struct gpio_keys_button *button = &tym_r16_buttons[i]; // struct gpio_keys_button_data *bdata = &bdev->data[i]; unsigned int gpio = tym_r16_buttons[i].gpio; unsigned int type = tym_r16_buttons[i].type ?: EV_KEY; unsigned int desc = tym_r16_buttons[i].desc ?: DRV_NAME; error = gpio_request(gpio, desc); if (error) { pr_err("unable to claim gpio %u, err=%d\n", gpio, error); goto err_free_gpio; } error = gpio_direction_input(gpio); if (error) { pr_err("unable to set direction on gpio %u, err=%d\n", gpio, error); goto err_free_gpio; } // bdata->can_sleep = gpio_cansleep(gpio); // bdata->last_state = -1; // bdata->threshold = //DIV_ROUND_UP(button->debounce_interval, poll_dev->poll_interval); input_set_capability(tymr16kbd_dev, type, button->code); } input_set_capability(tymr16kbd_dev, EV_KEY, KEY_VOLUMEUP); input_set_capability(tymr16kbd_dev, EV_KEY, KEY_VOLUMEDOWN); error = input_register_polled_device(poll_dev); if (error) { pr_err("unable to register polled device, err=%d\n", error); goto err_free_gpio; } /* for (i = 0; i < tym_r16_button_data.nbuttons; i++) gpio_keys_polled_check_state(tymr16kbd_dev, &tym_r16_buttons[i], &bdev->data[i]); */ #if USED_SYSCONF gpio_request(r16_gkey->encoder2_gkey, "gpio_encoder2"); gpio_direction_input(r16_gkey->encoder2_gkey); virq = gpio_to_irq(r16_gkey->encoder1_gkey); if (request_irq(virq, rotary_encoder_check_state_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "r16kbd", NULL)) { // err = -EBUSY; pr_err("request irq failure. \n"); goto fail2; } if (request_irq(virq, rotary_encoder_check_rising_state_irq, IRQF_TRIGGER_RISING, "r16kbd", NULL)) { // err = -EBUSY; pr_err("request irq failure. \n"); goto fail2; } if (request_irq(virq, rotary_encoder_check_falling_state_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "r16kbd", NULL)) { // err = -EBUSY; pr_err("request irq failure. \n"); goto fail2; } #else gpio_request(GPIO_ENCODER2, "gpio_encoder2"); gpio_direction_input(GPIO_ENCODER2); virq = gpio_to_irq(GPIO_ENCODER1); if (request_irq(virq, rotary_encoder_check_state_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "r16kbd", NULL)) { // err = -EBUSY; pr_err("request irq failure. \n"); goto fail2; } #endif dprintk(DEBUG_INIT, "Regist R16 %s device successfully.\n", DRV_NAME); return 0; err_free_gpio: while (--i >= 0) gpio_free(tym_r16_buttons[i].gpio); input_free_polled_device(poll_dev); err_free_bdev: kfree(bdev); fail1: pr_err("sunxikbd_init failed. \n"); fail2: kfree(sVolkey_status); free_irq(virq, NULL); #if USED_SYSCONF gpio_free(r16_gkey->encoder2_gkey); #else gpio_free(GPIO_ENCODER2); #endif return error; #endif } static void r16_button_exit(void) { int i; int virq; input_unregister_polled_device(poll_dev); for (i = 0; i < tym_r16_button_data.nbuttons; i++) gpio_free(tym_r16_button_data.buttons[i].gpio); input_free_polled_device(poll_dev); #if USED_SYSCONF gpio_free(r16_gkey->encoder2_gkey); virq = gpio_to_irq(r16_gkey->encoder1_gkey); #else gpio_free(GPIO_ENCODER2); virq = gpio_to_irq(GPIO_ENCODER1); #endif free_irq(virq, NULL); kfree(sVolkey_status); kfree(tymr16kbd_dev); dprintk(DEBUG_INIT, "R16 %s platform device removed.\n", DRV_NAME); return 0; } module_init(r16_button_init); module_exit(r16_button_exit); MODULE_AUTHOR("Netease IHW"); MODULE_DESCRIPTION("Netease r16 button driver"); MODULE_LICENSE("GPL");