static void handle_power_key_state(unsigned int code, int value) { int ret = 0; if (code == KEY_POWER && value == 1) { KEY_LOGI("[PWR][STATE]try to schedule power key pressed due\n"); ret = schedule_delayed_work(&power_key_state_disable_work, PWRKEY_PRESS_DUE); if (!ret) { KEY_LOGI("[PWR][STATE]Schedule power key pressed due failed, seems already have one, try to cancel...\n"); ret = __cancel_delayed_work(&power_key_state_disable_work); if (!ret) { setPowerKeyState(1); if (schedule_delayed_work(&power_key_state_disable_work, PWRKEY_PRESS_DUE)) { KEY_LOGI("[PWR][STATE]Re-schedule power key pressed due SCCUESS.\n"); KEY_LOGI("[PWR][STATE] start count for power key pressed due\n"); setPowerKeyState(1); } else KEY_LOGI("[PWR][STATE]Re-schedule power key pressed due FAILED, reason unknown, give up.\n"); } else { KEY_LOGI("[PWR][STATE]Cancel scheduled power key due success, now re-schedule.\n"); if (schedule_delayed_work(&power_key_state_disable_work, PWRKEY_PRESS_DUE)) { KEY_LOGI("[PWR][STATE]Re-schedule power key pressed due SCCUESS.\n"); KEY_LOGI("[PWR][STATE] start count for power key pressed due\n"); setPowerKeyState(1); } else KEY_LOGI("[PWR][STATE]Re-schedule power key pressed due FAILED, reason unknown, give up.\n"); } } else { KEY_LOGI("[PWR][STATE] start count for power key pressed due\n"); setPowerKeyState(1); } } }
static ssize_t vol_wakeup_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned char bitmask = 0; bitmask = simple_strtoull(buf, NULL, 10); mutex_lock(&wakeup_mutex); if (bitmask) { if (bitmask == 127) wakeup_bitmask &= bitmask; else if (bitmask > 128) wakeup_bitmask &= bitmask; else wakeup_bitmask |= bitmask; } if (wakeup_bitmask && (!set_wakeup)) { enable_irq_wake(vol_up_irq); enable_irq_wake(vol_down_irq); set_wakeup = 1; KEY_LOGI("%s:change to wake up function(%d, %d)\n", __func__, vol_up_irq, vol_down_irq); } else if ((!wakeup_bitmask) && set_wakeup){ disable_irq_wake(vol_up_irq); disable_irq_wake(vol_down_irq); set_wakeup = 0; KEY_LOGI("%s:change to non-wake up function(%d, %d)\n", __func__, vol_up_irq, vol_down_irq); } mutex_unlock(&wakeup_mutex); return count; }
static void power_key_led_off_work_func(struct work_struct *dummy) { if (power_key_led_requested) { if (cancel_delayed_work_sync(&power_key_led_on_work)) { KEY_LOGI("[PWR] cancel power key led work successfully(%x)\n", power_key_led_requested); } else KEY_LOGI("[PWR] cancel power key led work unsuccessfully (%x)\n", power_key_led_requested); power_key_led_requested = 0; } if (pre_power_key_led_status == 1) { #ifdef CONFIG_POWER_KEY_CLR_RESET cancel_delayed_work_sync(&power_key_restart_work); #endif KEY_LOGI("[PWR] change power key led off\n"); #ifdef CONFIG_QPNP_PWM #ifdef CONFIG_VK_LED qpnp_led_set_for_key(0); #endif #else pm8xxx_led_current_set_for_key(0); #endif pre_power_key_led_status = 0; #ifdef CONFIG_POWER_KEY_CLR_RESET if(!is_rrm1_mode()) #endif set_hw_reason(0); } }
static int gpio_event_input_request_irqs(struct gpio_input_state *ds) { int i; int err; int value; unsigned int irq; unsigned long req_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; for (i = 0; i < ds->info->keymap_size; i++) { err = irq = gpio_to_irq(ds->info->keymap[i].gpio); if (err < 0) goto err_gpio_get_irq_num_failed; if (ds->info->keymap[i].code == KEY_POWER) { #ifdef CONFIG_PWRKEY_WAKESRC_LOG power_key_gpio = ds->info->keymap[i].gpio; KEY_LOGI("Power Key gpio = %d", power_key_gpio); #endif power_key_intr_flag = 0; value = gpio_get_value(ds->info->keymap[i].gpio); req_flags = value ? IRQF_TRIGGER_FALLING: IRQF_TRIGGER_RISING; KEY_LOGI("keycode = %d, gpio = %d, type = %lx", ds->info->keymap[i].code, value, req_flags); } else req_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; #ifdef CONFIG_MFD_MAX8957 INIT_WORK(&ds->key_state[i].work, keypad_do_work); queue_work(ki_queue, &ds->key_state[i].work); #endif err = request_any_context_irq(irq, gpio_event_input_irq_handler, req_flags, "gpio_keys", &ds->key_state[i]); if (err < 0) { KEY_LOGE("KEY_ERR: %s: request_irq " "failed for input %d, irq %d, err %d\n", __func__, ds->info->keymap[i].gpio, irq, err); goto err_request_irq_failed; } if (ds->info->keymap[i].code == KEY_VOLUMEUP || ds->info->keymap[i].code == KEY_VOLUMEDOWN || ds->info->keymap[i].code == KEY_HP ) { KEY_LOGI("keycode = %d, gpio = %d, irq = %d", ds->info->keymap[i].code, ds->info->keymap[i].gpio, irq); if (ds->info->keymap[i].code == KEY_VOLUMEUP) vol_up_irq = irq; else if (ds->info->keymap[i].code == KEY_VOLUMEDOWN) vol_down_irq = irq; } else enable_irq_wake(irq); } #ifdef CONFIG_PWRKEY_STATUS_API init_power_key_api(); #endif return 0; for (i = ds->info->keymap_size - 1; i >= 0; i--) { free_irq(gpio_to_irq(ds->info->keymap[i].gpio), &ds->key_state[i]); err_request_irq_failed: err_gpio_get_irq_num_failed: ; } return err; }
static void power_key_led_on_work_func(struct work_struct *dummy) { KEY_LOGI("[PWR] %s in (%x)\n", __func__, power_key_led_requested); if (power_key_led_requested == 1) { pre_power_key_led_status = 1; KEY_LOGI("[PWR] change power key led on\n"); button_backlight_flash(1); } }
static void power_key_clr_check_work_func(struct work_struct *dummy) { if (cancel_delayed_work_sync(&power_key_check_reset_work)) KEY_LOGI("[PWR] cancel power key check reset work successfully\n"); else KEY_LOGI("[PWR] cancel power key check reset work unsuccessfully\n"); wake_unlock(&key_reset_clr_wake_lock); }
static void power_key_led_on_work_func(struct work_struct *dummy) { KEY_LOGI("[PWR] %s in (%x)\n", __func__, power_key_led_requested); if (power_key_led_requested == 1) { pre_power_key_led_status = 1; KEY_LOGI("[PWR] change power key led on\n"); pm8xxx_led_current_set_for_key(1); } }
static void power_key_led_on_work_func(struct work_struct *dummy) { KEY_LOGI("[PWR] %s in (%x)\n", __func__, power_key_led_requested); if (power_key_led_requested == 1) { pre_power_key_led_status = 1; KEY_LOGI("[PWR] change power key led on\n"); pm8xxx_led_current_set_for_key(1); set_hw_reason(HW_RESET_REASON); KEY_LOGI("[PWR] Show Blocked State -- long press power key\n"); show_state_filter(TASK_UNINTERRUPTIBLE); } }
static int gpio_event_input_request_irqs(struct gpio_input_state *ds) { int i; int err; int value; unsigned int irq; unsigned long req_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; for (i = 0; i < ds->info->keymap_size; i++) { err = irq = gpio_to_irq(ds->info->keymap[i].gpio); if (err < 0) goto err_gpio_get_irq_num_failed; if (ds->info->keymap[i].code == KEY_POWER) { power_key_intr_flag = 0; value = gpio_get_value(ds->info->keymap[i].gpio); req_flags = value ? IRQF_TRIGGER_FALLING: IRQF_TRIGGER_RISING; KEY_LOGI("keycode = %d, gpio = %d, type = %lx", ds->info->keymap[i].code, value, req_flags); } else req_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; err = request_any_context_irq(irq, gpio_event_input_irq_handler, req_flags, "gpio_keys", &ds->key_state[i]); if (err < 0) { KEY_LOGE("KEY_ERR: %s: request_irq " "failed for input %d, irq %d, err %d\n", __func__, ds->info->keymap[i].gpio, irq, err); goto err_request_irq_failed; } if (ds->info->keymap[i].code == KEY_VOLUMEUP || ds->info->keymap[i].code == KEY_VOLUMEDOWN) { KEY_LOGI("keycode = %d, gpio = %d, irq = %d", ds->info->keymap[i].code, ds->info->keymap[i].gpio, irq); if (ds->info->keymap[i].code == KEY_VOLUMEUP) vol_up_irq = irq; else vol_down_irq = irq; } else enable_irq_wake(irq); } return 0; for (i = ds->info->keymap_size - 1; i >= 0; i--) { free_irq(gpio_to_irq(ds->info->keymap[i].gpio), &ds->key_state[i]); err_request_irq_failed: err_gpio_get_irq_num_failed: ; } return err; }
static void do_reset_fn(void *priv) { struct keyreset_state *state = priv; if (state->restart_requested) panic("[KEY] keyboard reset failed, %d", state->restart_requested); if (state->reset_fn) { KEY_LOGI("keyboard reset\n"); state->restart_requested = state->reset_fn(); } else { KEY_LOGI("keyboard reset (default)\n"); do_restart(); state->restart_requested = 1; } }
static void handle_transition_according_to_power_key(int value) { struct gpio_input_state *ds = gb_ddata; #ifdef CONFIG_KPDPWR_S2_DVDD_RESET clear_kpdpwr_s2_rst_flag = 0; if (hrtimer_is_queued(&clr_kpd_reset_timer)) hrtimer_cancel(&clr_kpd_reset_timer); if (hrtimer_is_queued(&enable_kpd_s2_timer)) hrtimer_cancel(&enable_kpd_s2_timer); #endif if (ds->disable_reset_flag == 0 && value) { #ifdef CONFIG_POWER_VOLUP_RESET wake_lock_timeout(&key_reset_clr_wake_lock, msecs_to_jiffies(1000)); if (!schedule_delayed_work(&power_key_check_reset_work, msecs_to_jiffies(0))) #else wake_lock_timeout(&key_reset_clr_wake_lock, PWRKEYCHKRST_WAKELOCK_TIMEOUT); if (!schedule_delayed_work(&power_key_check_reset_work, PWRKEYCHKRST_DELAY)) #endif KEY_LOGI("[PWR] the reset work in already in the queue\n"); } else if (ds->disable_reset_flag != 0) { handle_only_power_key(KEY_POWER, value); } }
static void power_key_led_off_work_func(struct work_struct *dummy) { if (power_key_led_requested) { if (cancel_delayed_work_sync(&power_key_led_on_work)) { KEY_LOGI("[PWR] cancel power key led work successfully(%x)\n", power_key_led_requested); } else KEY_LOGI("[PWR] cancel power key led work unsuccessfully (%x)\n", power_key_led_requested); power_key_led_requested = 0; } if (pre_power_key_led_status == 1) { KEY_LOGI("[PWR] change power key led off\n"); button_backlight_flash(0); pre_power_key_led_status = 0; } }
static void handle_power_key_reset(unsigned int code, int value) { if (code == KEY_POWER) { if (value) { wake_lock_timeout(&key_reset_clr_wake_lock, PWRKEYCHKRST_WAKELOCK_TIMEOUT); KEY_LOGI("[PWR] start count for power key check reset\n"); if (!schedule_delayed_work(&power_key_check_reset_work, PWRKEYCHKRST_DELAY)) KEY_LOGI("[PWR] the reset work in already in the queue\n"); } else { KEY_LOGI("[PWR] start count for power key clear check\n"); if (!schedule_delayed_work(&power_key_clr_check_work, PWRKEYCLRCHK_DELAY)) KEY_LOGI("[PWR] the clear work in already in the queue\n"); } } }
static void handle_power_key_led(unsigned int code, int value) { if (code == KEY_POWER) { if (pre_power_key_status == value) return; pre_power_key_status = value; if (value) { KEY_LOGI("[PWR] start count for power key led on\n"); schedule_delayed_work(&power_key_led_on_work, PWRKEYLEDON_DELAY); power_key_led_requested = 1; } else { KEY_LOGI("[PWR] start count for power key led off\n"); schedule_delayed_work(&power_key_led_off_work, PWRKEYLEDOFF_DELAY); } } }
static void disable_reset_func(struct work_struct *work) { struct delayed_work *dwork = container_of(work, struct delayed_work, work); struct gpio_input_state *ds = container_of(dwork, struct gpio_input_state, disable_reset_work); const struct gpio_event_direct_entry *key_entry = ds->info->keymap; unsigned long irqflags; unsigned gpio_flags = ds->info->flags; unsigned npolarity; uint8_t idx_pwr = 0; int i = 0; int pressed; spin_lock_irqsave(&ds->irq_lock, irqflags); ds->disable_reset_flag = 0; __cancel_delayed_work(&ds->clear_hw_reset_work); for (i = 0; i < ds->info->keymap_size; i++, key_entry++) if (key_entry->code == KEY_POWER) idx_pwr = i; key_entry = ds->info->keymap; npolarity = !(gpio_flags & GPIOEDF_ACTIVE_HIGH); pressed = gpio_get_value((key_entry + idx_pwr)->gpio) ^ npolarity; handle_transition_according_to_power_key(pressed); wake_unlock(&disable_reset_wake_lock); spin_unlock_irqrestore(&ds->irq_lock, irqflags); KEY_LOGI("%s, %d\n", __func__, ds->disable_reset_flag); }
static void power_key_led_off_work_func(struct work_struct *dummy) { if (power_key_led_requested) { if (cancel_delayed_work_sync(&power_key_led_on_work)) { KEY_LOGI("[PWR] cancel power key led work successfully(%x)\n", power_key_led_requested); } else KEY_LOGI("[PWR] cancel power key led work unsuccessfully (%x)\n", power_key_led_requested); power_key_led_requested = 0; } if (pre_power_key_led_status == 1) { pr_info("[PWR] change power key led off\n"); pm8xxx_led_current_set_for_key(0); pre_power_key_led_status = 0; } }
static void power_key_state_disable_work_func(struct work_struct *dummy) { setPowerKeyState(0); #ifdef CONFIG_CIR_ALWAYS power_key_pressed = 0; #endif KEY_LOGI("[PWR][STATE]power key pressed outdated\n"); }
static ssize_t disable_reset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned int value; int i = 0; int pressed; struct gpio_input_state *ds = gb_ddata; const struct gpio_event_direct_entry *key_entry = ds->info->keymap; struct gpio_key_state *key_state = ds->key_state; unsigned gpio_flags = ds->info->flags; unsigned npolarity; unsigned long irqflags; uint8_t idx_pwr = 0; if (kstrtouint(buf, 10, &value) < 0) { KEY_LOGI("%s: input out of range\n",__func__); return -EINVAL; } spin_lock_irqsave(&ds->irq_lock, irqflags); wake_lock(&disable_reset_wake_lock); ds->disable_reset_flag = value; queue_delayed_work(ds->disable_reset_wq, &ds->disable_reset_work, msecs_to_jiffies(ds->disable_reset_flag * 1000)); for (i = 0; i < ds->info->keymap_size; i++, key_entry++, key_state++) if (key_entry->code == KEY_POWER) idx_pwr = i; key_entry = ds->info->keymap; npolarity = !(gpio_flags & GPIOEDF_ACTIVE_HIGH); #ifdef CONFIG_POWER_KEY_LED handle_power_key_led(KEY_POWER, 0); #endif if (__cancel_delayed_work(&power_key_check_reset_work)) KEY_LOGI("[PWR] cancel power key check reset work successfully\n"); pressed = gpio_get_value((key_entry + idx_pwr)->gpio) ^ npolarity; handle_transition_according_to_power_key(pressed); spin_unlock_irqrestore(&ds->irq_lock, irqflags); KEY_LOGI("%s, %d\n", __func__, ds->disable_reset_flag); return count; }
static ssize_t fm_radio_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { fm_radio_status = simple_strtoull(buf, NULL, 10); KEY_LOGI("GPIO_EVENT:: fm_radio_status=%d\n", fm_radio_status); return count; }
static void power_key_check_reset_work_func(struct work_struct *dummy) { struct gpio_event_input_info *aa = gis; int pocket_mode = 0; KEY_LOGI("[PWR] %s\n", __func__); if ((aa->clear_hw_reset)) { /* Check P/L sensor status */ pocket_mode = power_key_check_in_pocket(); if (pocket_mode) { printk(KERN_INFO "[KEY] power_key_check_in_pocket = %d\n", pocket_mode); aa->clear_hw_reset(); } } else { KEY_LOGI("[PWR] No reset clear function\n"); } handle_power_key_reset(KEY_POWER, 1); }
static void clear_hw_reset(void) { struct gpio_event_input_info *aa = gis; KEY_LOGI("[PWR] %s\n", __func__); #ifdef CONFIG_OF if ((aa->dt_clear_hw_reset)) { printk(KERN_INFO "[KEY] clear hw reset\n"); aa->dt_clear_hw_reset(aa->clr_gpio); } #else if ((aa->clear_hw_reset)) { printk(KERN_INFO "[KEY] clear hw reset\n"); aa->clear_hw_reset(); } #endif else { KEY_LOGI("[PWR] No reset clear function\n"); } }
static void do_restart(struct work_struct *unused) { #if defined(CONFIG_POWER_KEY_CLR_RESET) clear_hw_reset(); #endif sys_sync(); KEY_LOGI("[PWR] Show Blocked State -- long press power key\n"); show_state_filter(TASK_UNINTERRUPTIBLE); machine_restart("power-key-force-hard"); }
static void report_key(struct gpio_kp *kp, int key_index, int out, int in) { struct gpio_event_matrix_info *mi = kp->keypad_info; int pressed = test_bit(key_index, kp->keys_pressed); unsigned short keyentry = mi->keymap[key_index]; unsigned short keycode = keyentry & MATRIX_KEY_MASK; unsigned short dev = keyentry >> MATRIX_CODE_BITS; #ifdef CONFIG_OPTICALJOYSTICK_CRUCIAL static unsigned need_send_spec_key = 1; #endif if (pressed != test_bit(keycode, kp->input_devs->dev[dev]->key)) { if (keycode == KEY_RESERVED) { KEY_LOGI("gpiomatrix: unmapped key, %d-%d " "(%d-%d) changed to %d\n", out, in, mi->output_gpios[out], mi->input_gpios[in], pressed); } else { KEY_LOGI("gpiomatrix: key %d, %d-%d (%d-%d) " "changed to %d\n", keycode, out, in, mi->output_gpios[out], mi->input_gpios[in], pressed); #ifdef CONFIG_OPTICALJOYSTICK_CRUCIAL if (mi->info.oj_btn && keycode == BTN_MOUSE) ; else #endif input_report_key(kp->input_devs->dev[dev], keycode, pressed); } } #ifdef CONFIG_OPTICALJOYSTICK_CRUCIAL if (mi->info.oj_btn && keycode == BTN_MOUSE) { if (need_send_spec_key == pressed) { curcial_oj_send_key(keycode, pressed); need_send_spec_key = !pressed; KEY_LOGI("%s: send OJ action key, pressed: %d\n", __func__, pressed); } } #endif }
static void clear_phantom_key(struct gpio_kp *kp, int out, int in) { struct gpio_event_matrix_info *mi = kp->keypad_info; int key_index = out * mi->ninputs + in; unsigned short keyentry = mi->keymap[key_index]; unsigned short keycode = keyentry & MATRIX_KEY_MASK; unsigned short dev = keyentry >> MATRIX_CODE_BITS; if (!test_bit(keycode, kp->input_devs->dev[dev]->key)) { if (mi->flags & GPIOKPF_PRINT_PHANTOM_KEYS) KEY_LOGI("gpiomatrix: phantom key %d, %d-%d (%d-%d) " "cleared\n", keycode, out, in, mi->output_gpios[out], mi->input_gpios[in]); __clear_bit(key_index, kp->keys_pressed); } else { if (mi->flags & GPIOKPF_PRINT_PHANTOM_KEYS) KEY_LOGI("gpiomatrix: phantom key %d, %d-%d (%d-%d) " "not cleared\n", keycode, out, in, mi->output_gpios[out], mi->input_gpios[in]); } }
static void power_key_check_reset_work_func(struct work_struct *dummy) { struct gpio_event_input_info *aa = gis; int pocket_mode = 0; KEY_LOGI("[PWR] %s\n", __func__); if ((aa->clear_hw_reset)) { if (aa->info.rrm1_mode) { printk(KERN_INFO "[KEY] Power key check in Lab Test RRM1 mode.\n"); aa->clear_hw_reset(); } else { pocket_mode = power_key_check_in_pocket(); if (pocket_mode) { printk(KERN_INFO "[KEY] power_key_check_in_pocket = %d\n", pocket_mode); aa->clear_hw_reset(); } } } else { KEY_LOGI("[PWR] No reset clear function\n"); } handle_power_key_reset(KEY_POWER, 1); }
static void doubleshot_set_qty_irq(uint8_t disable) { uint32_t i; static uint8_t already_disabled; KEY_LOGI("%s disable=%d, already_disabled=%d\n", __func__, disable, already_disabled); if (!(disable ^ already_disabled)) return; already_disabled = disable; for (i = 0; i < KEYMAP_NUM_COLS; i++) { if (disable) disable_irq(gpio_to_irq(doubleshot_pmic_col_gpios[i])); else enable_irq(gpio_to_irq(doubleshot_pmic_col_gpios[i])); } }
int gpio_event_input_func(struct gpio_event_input_devs *input_devs, struct gpio_event_info *info, void **data, int func) { int ret; int i; unsigned long irqflags; struct gpio_event_input_info *di; struct gpio_input_state *ds = *data; struct kobject *keyboard_kobj; di = container_of(info, struct gpio_event_input_info, info); if (func == GPIO_EVENT_FUNC_SUSPEND) { if (ds->use_irq) for (i = 0; i < di->keymap_size; i++) disable_irq(gpio_to_irq(di->keymap[i].gpio)); hrtimer_cancel(&ds->timer); return 0; } if (func == GPIO_EVENT_FUNC_RESUME) { spin_lock_irqsave(&ds->irq_lock, irqflags); if (ds->use_irq) for (i = 0; i < di->keymap_size; i++) enable_irq(gpio_to_irq(di->keymap[i].gpio)); hrtimer_start(&ds->timer, ktime_set(0, 0), HRTIMER_MODE_REL); spin_unlock_irqrestore(&ds->irq_lock, irqflags); return 0; } if (func == GPIO_EVENT_FUNC_INIT) { if (ktime_to_ns(di->poll_time) <= 0) di->poll_time = ktime_set(0, 20 * NSEC_PER_MSEC); *data = ds = kzalloc(sizeof(*ds) + sizeof(ds->key_state[0]) * di->keymap_size, GFP_KERNEL); if (ds == NULL) { ret = -ENOMEM; KEY_LOGE("gpio_event_input_func: " "Failed to allocate private data\n"); goto err_ds_alloc_failed; } ds->debounce_count = di->keymap_size; ds->input_devs = input_devs; ds->info = di; wake_lock_init(&ds->wake_lock, WAKE_LOCK_SUSPEND, "gpio_input"); spin_lock_init(&ds->irq_lock); if (board_build_flag() == 0) ds->debug_log = 0; else ds->debug_log = 1; for (i = 0; i < di->keymap_size; i++) { int dev = di->keymap[i].dev; if (dev >= input_devs->count) { KEY_LOGE("gpio_event_input_func: bad device " "index %d >= %d for key code %d\n", dev, input_devs->count, di->keymap[i].code); ret = -EINVAL; goto err_bad_keymap; } input_set_capability(input_devs->dev[dev], di->type, di->keymap[i].code); ds->key_state[i].ds = ds; ds->key_state[i].debounce = DEBOUNCE_UNKNOWN; } for (i = 0; i < di->keymap_size; i++) { ret = gpio_request(di->keymap[i].gpio, "gpio_kp_in"); if (ret) { KEY_LOGE("gpio_event_input_func: gpio_request " "failed for %d\n", di->keymap[i].gpio); goto err_gpio_request_failed; } ret = gpio_direction_input(di->keymap[i].gpio); if (ret) { KEY_LOGE("gpio_event_input_func: " "gpio_direction_input failed for %d\n", di->keymap[i].gpio); goto err_gpio_configure_failed; } } if (di->setup_input_gpio) di->setup_input_gpio(); ret = gpio_event_input_request_irqs(ds); keyboard_kobj = kobject_create_and_add("keyboard", NULL); if (keyboard_kobj == NULL) { KEY_LOGE("KEY_ERR: %s: subsystem_register failed\n", __func__); ret = -ENOMEM; return ret; } if (sysfs_create_file(keyboard_kobj, &dev_attr_vol_wakeup.attr)) KEY_LOGE("gpio_event_input_func: sysfs_create_file " "return %d\n", ret); wakeup_bitmask = 0; set_wakeup = 0; spin_lock_irqsave(&ds->irq_lock, irqflags); ds->use_irq = ret == 0; KEY_LOGI("GPIO Input Driver: Start gpio inputs for %s%s in %s " "mode\n", input_devs->dev[0]->name, (input_devs->count > 1) ? "..." : "", ret == 0 ? "interrupt" : "polling"); hrtimer_init(&ds->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ds->timer.function = gpio_event_input_timer_func; hrtimer_start(&ds->timer, ktime_set(0, 0), HRTIMER_MODE_REL); spin_unlock_irqrestore(&ds->irq_lock, irqflags); return 0; } ret = 0; spin_lock_irqsave(&ds->irq_lock, irqflags); hrtimer_cancel(&ds->timer); if (ds->use_irq) { for (i = di->keymap_size - 1; i >= 0; i--) { free_irq(gpio_to_irq(di->keymap[i].gpio), &ds->key_state[i]); } } spin_unlock_irqrestore(&ds->irq_lock, irqflags); for (i = di->keymap_size - 1; i >= 0; i--) { err_gpio_configure_failed: gpio_free(di->keymap[i].gpio); err_gpio_request_failed: ; } err_bad_keymap: wake_lock_destroy(&ds->wake_lock); kfree(ds); err_ds_alloc_failed: return ret; }
static void gpio_event_input_delayed_func(struct work_struct *key_work) { int i; int pressed; struct gpio_input_state *ds = container_of((struct delayed_work *)key_work, struct gpio_key_state, key_work)->ds; unsigned npolarity; unsigned gpio_flags = ds->info->flags; int nkeys = ds->info->keymap_size; const struct gpio_event_direct_entry *key_entry; struct gpio_key_state *key_state; unsigned long irqflags; uint8_t debounce; bool sync_needed; key_entry = ds->info->keymap; key_state = ds->key_state; npolarity = !(gpio_flags & GPIOEDF_ACTIVE_HIGH); for (i = 0; i < nkeys; i++, key_entry++, key_state++) { key_state->keyValue = gpio_get_value(key_entry->gpio) ^ npolarity; key_state->irq_enable_needed = 0; key_state->need_queue = 0; } #ifdef KEYPAD_DEBUG KEY_LOGD("Before process: \n"); print_key_ds(ds); #endif key_entry = ds->info->keymap; key_state = ds->key_state; sync_needed = false; spin_lock_irqsave(&ds->irq_lock, irqflags); for (i = 0; i < nkeys; i++, key_entry++, key_state++) { debounce = key_state->debounce; if (debounce & DEBOUNCE_WAIT_IRQ) continue; if (key_state->debounce & DEBOUNCE_UNSTABLE) { debounce = key_state->debounce = DEBOUNCE_UNKNOWN; key_state->irq_enable_needed = 1; if (gpio_flags & GPIOEDF_PRINT_KEY_UNSTABLE) KEY_LOGD("gpio_keys_scan_keys: key %x-%x, %d " "(%d) continue debounce," #ifdef KEYPAD_DEBUG " enable irq#%d\n" #endif , ds->info->type, key_entry->code, i, key_entry->gpio #ifdef KEYPAD_DEBUG , gpio_to_irq(key_entry->gpio) #endif ); } pressed = key_state->keyValue; if (debounce & DEBOUNCE_POLL) { if (pressed == !(debounce & DEBOUNCE_PRESSED)) { ds->debounce_count++; key_state->need_queue = 1; key_state->debounce = DEBOUNCE_UNKNOWN; if (gpio_flags & GPIOEDF_PRINT_KEY_DEBOUNCE) KEY_LOGD("gpio_keys_scan_keys: key %x-" "%x, %d (%d) start debounce\n", ds->info->type, key_entry->code, i, key_entry->gpio); } continue; } if (pressed && (debounce & DEBOUNCE_NOTPRESSED)) { if (gpio_flags & GPIOEDF_PRINT_KEY_DEBOUNCE) KEY_LOGD("gpio_keys_scan_keys: key %x-%x, %d " "(%d) debounce pressed 1\n", ds->info->type, key_entry->code, i, key_entry->gpio); key_state->debounce = DEBOUNCE_PRESSED; key_state->need_queue = 1; continue; } if (!pressed && (debounce & DEBOUNCE_PRESSED)) { if (gpio_flags & GPIOEDF_PRINT_KEY_DEBOUNCE) KEY_LOGD("gpio_keys_scan_keys: key %x-%x, %d " "(%d) debounce pressed 0\n", ds->info->type, key_entry->code, i, key_entry->gpio); key_state->debounce = DEBOUNCE_NOTPRESSED; key_state->need_queue = 1; continue; } /* key is stable */ ds->debounce_count--; if (ds->use_irq) key_state->debounce |= DEBOUNCE_WAIT_IRQ; else key_state->debounce |= DEBOUNCE_POLL; if (gpio_flags & GPIOEDF_PRINT_KEYS) KEY_LOGD("gpio_keys_scan_keys: key %x-%x, %d (%d) " "changed to %d\n", ds->info->type, key_entry->code, i, key_entry->gpio, pressed); #ifdef CONFIG_POWER_KEY_LED handle_power_key_led(key_entry->code, pressed); #endif input_event(ds->input_devs->dev[key_entry->dev], ds->info->type, key_entry->code, pressed); sync_needed = true; } if (sync_needed) { for (i = 0; i < ds->input_devs->count; i++) input_sync(ds->input_devs->dev[i]); } #if 0 key_entry = kp->keys_info->keymap; key_state = kp->key_state; for (i = 0; i < nkeys; i++, key_entry++, key_state++) { pr_info("gpio_read_detect_status %d %d\n", key_entry->gpio, gpio_read_detect_status(key_entry->gpio)); } #endif if (ds->debounce_count) { key_entry = ds->info->keymap; key_state = ds->key_state; for (i = 0; i < nkeys; i++, key_entry++, key_state++) { if (key_state->need_queue) if (!queue_delayed_work(ki_queue, &(key_state->key_work), KTIME_TO_JIFFIES(ds->info->debounce_time))) KEY_LOGI("Keycode: 0x%X has been queued already.\n", key_entry->code); } } else if (!ds->use_irq) { key_entry = ds->info->keymap; key_state = ds->key_state; for (i = 0; i < nkeys; i++, key_entry++, key_state++) { if (key_state->need_queue) if (!queue_delayed_work(ki_queue, &(key_state->key_work), KTIME_TO_JIFFIES(ds->info->poll_time))) KEY_LOGI("Keycode: 0x%X has been queued already.\n", key_entry->code); } } else wake_unlock(&ds->wake_lock); spin_unlock_irqrestore(&ds->irq_lock, irqflags); #if 0 key_entry = ds->info->keymap; key_state = ds->key_state; for (i = 0; i < nkeys; i++, key_entry++, key_state++) if (key_state->irq_enable_needed) enable_irq(gpio_to_irq(key_entry->gpio)); #endif #ifdef KEYPAD_DEBUG KEY_LOGD("After process:\n"); print_key_ds(ds); #endif }
int gpio_event_input_func(struct gpio_event_input_devs *input_devs, struct gpio_event_info *info, void **data, int func) { int ret; int i; unsigned long irqflags; struct gpio_event_input_info *di; struct gpio_input_state *ds = *data; di = container_of(info, struct gpio_event_input_info, info); if (func == GPIO_EVENT_FUNC_SUSPEND) { if (ds->use_irq) for (i = 0; i < di->keymap_size; i++) disable_irq(gpio_to_irq(di->keymap[i].gpio)); #ifndef CONFIG_MFD_MAX8957 hrtimer_cancel(&ds->timer); #else for (i = 0; i < di->keymap_size; i++) { if (cancel_delayed_work_sync(&(ds->key_state[i].key_work))) KEY_LOGI("Cancel delayed debounce function of keycode:0x%X success.\n", ds->info->keymap[i].code); else KEY_LOGI("Cancel delayed debounce function of keycode:0x%X fail.\n", ds->info->keymap[i].code); } #endif return 0; } if (func == GPIO_EVENT_FUNC_RESUME) { spin_lock_irqsave(&ds->irq_lock, irqflags); if (ds->use_irq) for (i = 0; i < di->keymap_size; i++) enable_irq(gpio_to_irq(di->keymap[i].gpio)); #ifndef CONFIG_MFD_MAX8957 hrtimer_start(&ds->timer, ktime_set(0, 0), HRTIMER_MODE_REL); #else queue_delayed_work(ki_queue, &(ds->key_state[0].key_work), 0); #endif spin_unlock_irqrestore(&ds->irq_lock, irqflags); return 0; } if (func == GPIO_EVENT_FUNC_INIT) { if (ktime_to_ns(di->poll_time) <= 0) di->poll_time = ktime_set(0, 20 * NSEC_PER_MSEC); *data = ds = kzalloc(sizeof(*ds) + sizeof(ds->key_state[0]) * di->keymap_size, GFP_KERNEL); if (ds == NULL) { ret = -ENOMEM; KEY_LOGE("KEY_ERR: %s: " "Failed to allocate private data\n", __func__); goto err_ds_alloc_failed; } ds->debounce_count = di->keymap_size; ds->input_devs = input_devs; ds->info = di; wake_lock_init(&ds->wake_lock, WAKE_LOCK_SUSPEND, "gpio_input"); spin_lock_init(&ds->irq_lock); if (board_build_flag() == 0) ds->debug_log = 0; else ds->debug_log = 1; for (i = 0; i < di->keymap_size; i++) { int dev = di->keymap[i].dev; if (dev >= input_devs->count) { KEY_LOGE("KEY_ERR: %s: bad device " "index %d >= %d for key code %d\n", __func__, dev, input_devs->count, di->keymap[i].code); ret = -EINVAL; goto err_bad_keymap; } input_set_capability(input_devs->dev[dev], di->type, di->keymap[i].code); ds->key_state[i].ds = ds; ds->key_state[i].debounce = DEBOUNCE_UNKNOWN; } for (i = 0; i < di->keymap_size; i++) { ret = gpio_request(di->keymap[i].gpio, "gpio_kp_in"); if (ret) { KEY_LOGE("KEY_ERR: %s: gpio_request " "failed for %d\n", __func__, di->keymap[i].gpio); goto err_gpio_request_failed; } ret = gpio_direction_input(di->keymap[i].gpio); if (ret) { KEY_LOGE("KEY_ERR: %s: " "gpio_direction_input failed for %d\n", __func__, di->keymap[i].gpio); goto err_gpio_configure_failed; } } if (di->setup_input_gpio) di->setup_input_gpio(); #ifdef CONFIG_MFD_MAX8957 ki_queue = create_singlethread_workqueue("ki_queue"); #endif ret = gpio_event_input_request_irqs(ds); spin_lock_irqsave(&ds->irq_lock, irqflags); ds->use_irq = ret == 0; KEY_LOGI("GPIO Input Driver: Start gpio inputs for %s%s in %s " "mode\n", input_devs->dev[0]->name, (input_devs->count > 1) ? "..." : "", ret == 0 ? "interrupt" : "polling"); #ifndef CONFIG_MFD_MAX8957 hrtimer_init(&ds->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ds->timer.function = gpio_event_input_timer_func; hrtimer_start(&ds->timer, ktime_set(0, 0), HRTIMER_MODE_REL); #else for (i = 0; i < di->keymap_size; i++) INIT_DELAYED_WORK(&(ds->key_state[i].key_work), gpio_event_input_delayed_func); queue_delayed_work(ki_queue, &(ds->key_state[0].key_work), 0); #endif spin_unlock_irqrestore(&ds->irq_lock, irqflags); return 0; } ret = 0; spin_lock_irqsave(&ds->irq_lock, irqflags); #ifndef CONFIG_MFD_MAX8957 hrtimer_cancel(&ds->timer); #else for (i = 0; i < di->keymap_size; i++) { if (cancel_delayed_work_sync(&(ds->key_state[i].key_work))) KEY_LOGI("Cancel delayed debounce function of keycode:0x%X success.\n", ds->info->keymap[i].code); else KEY_LOGI("Cancel delayed debounce function of keycode:0x%X fail.\n", ds->info->keymap[i].code); } #endif if (ds->use_irq) { for (i = di->keymap_size - 1; i >= 0; i--) { free_irq(gpio_to_irq(di->keymap[i].gpio), &ds->key_state[i]); } } spin_unlock_irqrestore(&ds->irq_lock, irqflags); for (i = di->keymap_size - 1; i >= 0; i--) { err_gpio_configure_failed: gpio_free(di->keymap[i].gpio); err_gpio_request_failed: ; } err_bad_keymap: wake_lock_destroy(&ds->wake_lock); kfree(ds); err_ds_alloc_failed: return ret; }
static irqreturn_t gpio_event_input_irq_handler(int irq, void *dev_id) { struct gpio_key_state *ks = dev_id; struct gpio_input_state *ds = ks->ds; int keymap_index = ks - ds->key_state; const struct gpio_event_direct_entry *key_entry; unsigned long irqflags; int pressed; KEY_LOGD("%s, irq=%d, use_irq=%d, keycode=0x%X\n", __func__, irq, ds->use_irq, ds->info->keymap[keymap_index].code); if (!ds->use_irq) return IRQ_HANDLED; key_entry = &ds->info->keymap[keymap_index]; if (ds->info->debounce_time.tv64) { spin_lock_irqsave(&ds->irq_lock, irqflags); if (ks->debounce & DEBOUNCE_WAIT_IRQ) { ks->debounce = DEBOUNCE_UNKNOWN; if (ds->debounce_count++ == 0) { wake_lock(&ds->wake_lock); #ifndef CONFIG_MFD_MAX8957 hrtimer_start( &ds->timer, ds->info->debounce_time, HRTIMER_MODE_REL); #else if (!queue_delayed_work(ki_queue, &(ks->key_work), KTIME_TO_JIFFIES(ds->info->debounce_time))) KEY_LOGI("Keycode: 0x%X has been queued already.\n", key_entry->code); #endif } if (ds->info->flags & GPIOEDF_PRINT_KEY_DEBOUNCE) KEY_LOGD("gpio_event_input_irq_handler: " "key %x-%x, %d (%d) start debounce\n", ds->info->type, key_entry->code, keymap_index, key_entry->gpio); } else { #ifndef CONFIG_MFD_MAX8957 disable_irq_nosync(irq); #endif #ifdef KEYPAD_DEBUG if (ds->info->flags & GPIOEDF_PRINT_KEY_UNSTABLE) KEY_LOGD("Disable IRQ because of bouncing."); #endif ks->debounce = DEBOUNCE_UNSTABLE; } spin_unlock_irqrestore(&ds->irq_lock, irqflags); } else { pressed = gpio_get_value(key_entry->gpio) ^ !(ds->info->flags & GPIOEDF_ACTIVE_HIGH); if (ds->info->flags & GPIOEDF_PRINT_KEYS) KEY_LOGD("gpio_event_input_irq_handler: key %x-%x, %d " "(%d) changed to %d\n", ds->info->type, key_entry->code, keymap_index, key_entry->gpio, pressed); input_event(ds->input_devs->dev[key_entry->dev], ds->info->type, key_entry->code, pressed); input_sync(ds->input_devs->dev[key_entry->dev]); } return IRQ_HANDLED; }