static void cypress_touchkey_work(struct work_struct *work) { struct cypress_touchkey_info *info = container_of(work, struct cypress_touchkey_info, key_work); struct timeval diff; int code; int press; if (info->keybuf == 0xFF) { dev_err(&info->client->dev, "keybuf: 0x%2X\n", info->keybuf); goto out; } press = !(info->keybuf & PRESS_BIT_MASK); code = (int)(info->keybuf & KEYCODE_BIT_MASK) - 1; if (code < 0) { dev_err(&info->client->dev, "not proper interrupt 0x%2X.\n", info->keybuf); if (info->press == 0) goto out; dev_err(&info->client->dev, "forced key released.\n"); code = info->code; press = 0; } /* ignore invalid keycode, keypress value */ if (code > 1 || press > 1) { dev_err(&info->client->dev, "invalid keycode or keypress 0x%2X.\n", info->keybuf); goto out; } #if !defined(CONFIG_SAMSUNG_PRODUCT_SHIP) TOUCHKEY_LOG(info->keycode[code], press); #endif if (touch_is_pressed && press) { #if !defined(CONFIG_SAMSUNG_PRODUCT_SHIP) printk(KERN_DEBUG "[TouchKey]touchkey pressed but don't send event because touch is pressed.\n"); #endif goto out; } if (code == 0 && press == 1) { do_gettimeofday(&info->end); diff.tv_sec = info->end.tv_sec - info->start.tv_sec; diff.tv_usec = info->end.tv_usec - info->start.tv_usec; if (diff.tv_sec >= 0) { if (diff.tv_usec < 0) { (diff.tv_sec)--; diff.tv_usec = (info->end.tv_usec + 1000000L) - info->start.tv_usec; } /* If the interval of pressed menu-key is below 100msec */ if (diff.tv_sec == 0 && diff.tv_usec < 100000) { dev_err(&info->client->dev, "Interval below 100msec:%ldusec\n", diff.tv_usec); info->start.tv_sec = info->end.tv_sec; info->start.tv_usec = info->end.tv_usec; goto out; } } /* refresh timeval */ info->start.tv_sec = info->end.tv_sec; info->start.tv_usec = info->end.tv_usec; } info->code = code; info->press = press; input_report_key(info->input_dev, info->keycode[code], press); input_sync(info->input_dev); out: enable_irq(info->irq); return; }
static irqreturn_t cypress_touchkey_interrupt(int irq, void *dev_id) { struct cypress_touchkey_info *info = dev_id; u8 buf[10] = {0,}; int code; int press; int ret; if (!atomic_read(&info->keypad_enable)) { goto out; } ret = gpio_get_value(info->pdata->gpio_int); if (ret) { dev_err(&info->client->dev, "not real interrupt (%d).\n", ret); goto out; } if (info->is_powering_on) { dev_err(&info->client->dev, "%s: ignoring spurious boot " "interrupt\n", __func__); return IRQ_HANDLED; } #if defined(SEC_TOUCHKEY_VERBOSE_DEBUG) ret = i2c_smbus_read_i2c_block_data(info->client, CYPRESS_GEN, ARRAY_SIZE(buf), buf); if (ret != ARRAY_SIZE(buf)) { dev_err(&info->client->dev, "interrupt failed with %d.\n", ret); goto out; } print_hex_dump(KERN_DEBUG, "cypress_touchkey: ", DUMP_PREFIX_OFFSET, 32, 1, buf, 10, false); #else buf[0] = i2c_smbus_read_byte_data(info->client, CYPRESS_GEN); if (buf[0] < 0) { dev_err(&info->client->dev, "interrupt failed with %d.\n", ret); goto out; } #endif press = !(buf[0] & PRESS_BIT_MASK); code = (int)(buf[0] & KEYCODE_BIT_MASK) - 1; dev_dbg(&info->client->dev, "[TouchKey]press=%d, code=%d\n", press, code); if (code < 0) { dev_err(&info->client->dev, "not profer interrupt 0x%2X.\n", buf[0]); goto out; } #if defined(SEC_TOUCHKEY_DEBUG) TOUCHKEY_LOG(info->keycode[code], press); #endif // if (touch_is_pressed && press) { // printk(KERN_ERR "[TouchKey] don't send event because touch is pressed.\n"); // printk(KERN_ERR "[TouchKey] touch_pressed = %d\n", // touch_is_pressed); // } else { input_report_key(info->input_dev, info->keycode[code], press); input_sync(info->input_dev); // } out: return IRQ_HANDLED; }