diff --git a/drivers/input/fingerprint/fpc/fpc1020_tee.c b/drivers/input/fingerprint/fpc/fpc1020_tee.c index fa756fe9cb72..675c5bc446e5 100644 --- a/drivers/input/fingerprint/fpc/fpc1020_tee.c +++ b/drivers/input/fingerprint/fpc/fpc1020_tee.c @@ -63,6 +63,9 @@ module_param(ignor_home_for_ESD, uint, S_IRUGO | S_IWUSR); #define FPC1020_RESET_HIGH2_US 1250 #define FPC_TTW_HOLD_TIME 1000 +/* Unused key value to avoid interfering with active keys */ +#define KEY_FINGERPRINT 0x2ee + #define ONEPLUS_EDIT //Onplus modify for msm8996 platform and 15801 HW struct fpc1020_data { @@ -84,13 +87,18 @@ struct fpc1020_data { int id1_gpio; int id2_gpio; struct input_dev *input_dev; - int screen_state; - /*int sensor_version;*/ + int screen_state; //1: on 0:off + /*int sensor_version;*/ //0x01:fpc1245 0x02:fpc1263 int project_version; #endif #if defined(CONFIG_FB) struct notifier_block fb_notif; #endif + struct work_struct pm_work; + int proximity_state; /* 0:far 1:near */ + bool irq_enabled; + spinlock_t irq_lock; + struct completion irq_sent; }; static int fpc1020_request_named_gpio(struct fpc1020_data *fpc1020, @@ -263,8 +271,20 @@ static ssize_t irq_get(struct device* device, char* buffer) { struct fpc1020_data* fpc1020 = dev_get_drvdata(device); - int irq = gpio_get_value(fpc1020->irq_gpio); - return scnprintf(buffer, PAGE_SIZE, "%i\n", irq); + bool irq_enabled; + int irq; + ssize_t count; + + spin_lock(&fpc1020->irq_lock); + irq_enabled = fpc1020->irq_enabled; + spin_unlock(&fpc1020->irq_lock); + + irq = irq_enabled && gpio_get_value(fpc1020->irq_gpio); + count = scnprintf(buffer, PAGE_SIZE, "%i\n", irq); + + complete(&fpc1020->irq_sent); + + return count; } @@ -282,29 +302,55 @@ static ssize_t irq_ack(struct device* device, } static DEVICE_ATTR(irq, S_IRUSR | S_IWUSR, irq_get, irq_ack); + +static void set_fpc_irq(struct fpc1020_data *fpc1020, bool enable) +{ + bool irq_enabled; + + spin_lock(&fpc1020->irq_lock); + irq_enabled = fpc1020->irq_enabled; + fpc1020->irq_enabled = enable; + spin_unlock(&fpc1020->irq_lock); + + if (enable == irq_enabled) + return; + + if (enable) + enable_irq(gpio_to_irq(fpc1020->irq_gpio)); + else + disable_irq(gpio_to_irq(fpc1020->irq_gpio)); +} + static ssize_t report_home_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct fpc1020_data *fpc1020 = dev_get_drvdata(dev); + //unsigned long time; if(ignor_home_for_ESD) return -EINVAL; - if (!strncmp(buf, "down", strlen("down"))) { - input_report_key(fpc1020->input_dev, - KEY_HOME, 1); - input_sync(fpc1020->input_dev); - } else if (!strncmp(buf, "up", strlen("up"))) { - input_report_key(fpc1020->input_dev, - KEY_HOME, 0); - input_sync(fpc1020->input_dev); - } else if (!strncmp(buf, "timeout", strlen("timeout"))) { - input_report_key(fpc1020->input_dev, KEY_F2, 1); - input_sync(fpc1020->input_dev); - input_report_key(fpc1020->input_dev, KEY_F2, 0); - input_sync(fpc1020->input_dev); - } else { - return -EINVAL; + if (!strncmp(buf, "down", strlen("down"))) + { + input_report_key(fpc1020->input_dev, + KEY_HOME, 1); + input_sync(fpc1020->input_dev); } + else if (!strncmp(buf, "up", strlen("up"))) + { + input_report_key(fpc1020->input_dev, + KEY_HOME, 0); + input_sync(fpc1020->input_dev); + } + else if (!strncmp(buf, "timeout", strlen("timeout"))) + { + input_report_key(fpc1020->input_dev,KEY_F2,1); + input_sync(fpc1020->input_dev); + input_report_key(fpc1020->input_dev,KEY_F2,0); + input_sync(fpc1020->input_dev); + } + else + return -EINVAL; + return count; } static DEVICE_ATTR(report_home, S_IWUSR, NULL, report_home_set); @@ -342,25 +388,45 @@ static ssize_t screen_state_get(struct device* device, } static DEVICE_ATTR(screen_state, S_IRUSR , screen_state_get, NULL); -/* + static ssize_t sensor_version_get(struct device* device, struct device_attribute* attribute, char* buffer) { - struct fpc1020_data* fpc1020 = dev_get_drvdata(device); - return scnprintf(buffer, PAGE_SIZE, "%i\n", fpc1020->sensor_version); + return scnprintf(buffer, PAGE_SIZE, "%i\n", fp_version); } static DEVICE_ATTR(sensor_version, S_IRUSR , sensor_version_get, NULL); -*/ + +static ssize_t proximity_state_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct fpc1020_data *fpc1020 = dev_get_drvdata(dev); + int rc, val; + + rc = kstrtoint(buf, 10, &val); + if (rc) + return -EINVAL; + + fpc1020->proximity_state = !!val; + + if (!fpc1020->screen_state) + set_fpc_irq(fpc1020, !fpc1020->proximity_state); + + return count; +} + +static DEVICE_ATTR(proximity_state, S_IWUSR, NULL, proximity_state_set); + static struct attribute *attributes[] = { //&dev_attr_hw_reset.attr, &dev_attr_irq.attr, &dev_attr_report_home.attr, &dev_attr_update_info.attr, &dev_attr_screen_state.attr, - /*&dev_attr_sensor_version.attr,*/ + &dev_attr_sensor_version.attr, &dev_attr_report_key.attr, + &dev_attr_proximity_state.attr, NULL }; @@ -390,19 +456,21 @@ int fpc1020_input_init(struct fpc1020_data *fpc1020) set_bit(EV_SYN, fpc1020->input_dev->evbit); set_bit(EV_ABS, fpc1020->input_dev->evbit); - set_bit(KEY_POWER, fpc1020->input_dev->keybit); - set_bit(KEY_F2, fpc1020->input_dev->keybit); - set_bit(KEY_HOME, fpc1020->input_dev->keybit); - /* - set_bit(BTN_A, fpc1020->input_dev->keybit); - set_bit(BTN_C, fpc1020->input_dev->keybit); - */ - set_bit(BTN_B, fpc1020->input_dev->keybit); - set_bit(ABS_Z, fpc1020->input_dev->keybit); - set_bit(KEY_UP, fpc1020->input_dev->keybit); - set_bit(KEY_DOWN, fpc1020->input_dev->keybit); - set_bit(KEY_LEFT, fpc1020->input_dev->keybit); - set_bit(KEY_RIGHT, fpc1020->input_dev->keybit); + set_bit(KEY_POWER, fpc1020->input_dev->keybit); + set_bit(KEY_F2, fpc1020->input_dev->keybit); + set_bit(KEY_HOME, fpc1020->input_dev->keybit); + set_bit(KEY_FINGERPRINT, fpc1020->input_dev->keybit); + + /* + set_bit(BTN_A, fpc1020->input_dev->keybit); + set_bit(BTN_C, fpc1020->input_dev->keybit); + set_bit(BTN_B, fpc1020->input_dev->keybit); + set_bit(ABS_Z, fpc1020->input_dev->keybit); + set_bit(KEY_UP, fpc1020->input_dev->keybit); + set_bit(KEY_DOWN, fpc1020->input_dev->keybit); + set_bit(KEY_LEFT, fpc1020->input_dev->keybit); + set_bit(KEY_RIGHT, fpc1020->input_dev->keybit); + */ /* Register the input device */ error = input_register_device(fpc1020->input_dev); @@ -427,29 +495,37 @@ void fpc1020_input_destroy(struct fpc1020_data *fpc1020) input_free_device(fpc1020->input_dev); } +static void fpc1020_suspend_resume(struct work_struct *work) +{ + struct fpc1020_data *fpc1020 = + container_of(work, typeof(*fpc1020), pm_work); + + if (fpc1020->screen_state) { + set_fpc_irq(fpc1020, true); + } + + sysfs_notify(&fpc1020->dev->kobj, NULL, + dev_attr_screen_state.attr.name); +} + #if defined(CONFIG_FB) static int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data) { - struct fb_event *evdata = data; - int *blank; - struct fpc1020_data *fpc1020 = container_of(self, struct fpc1020_data, fb_notif); + struct fb_event *evdata = data; + int *blank = evdata->data; - if(FB_EARLY_EVENT_BLANK != event && FB_EVENT_BLANK != event) - return 0; - if((evdata) && (evdata->data) && (fpc1020)) { - blank = evdata->data; - if( *blank == FB_BLANK_UNBLANK && (event == FB_EARLY_EVENT_BLANK )) { - dev_err(fpc1020->dev, "%s screen on\n", __func__); - fpc1020->screen_state = 1; - sysfs_notify(&fpc1020->dev->kobj, NULL, dev_attr_screen_state.attr.name); + if (event != FB_EARLY_EVENT_BLANK) + return 0; - } else if( *blank == FB_BLANK_POWERDOWN && (event == FB_EARLY_EVENT_BLANK/*FB_EVENT_BLANK*/ )) { - dev_err(fpc1020->dev, "%s screen off\n", __func__); - fpc1020->screen_state = 0; - sysfs_notify(&fpc1020->dev->kobj, NULL, dev_attr_screen_state.attr.name); - } + if (*blank == FB_BLANK_UNBLANK) { + fpc1020->screen_state = 1; + queue_work(system_highpri_wq, &fpc1020->pm_work); + } else if (*blank == FB_BLANK_POWERDOWN) { + fpc1020->screen_state = 0; + queue_work(system_highpri_wq, &fpc1020->pm_work); } + return 0; } #endif @@ -457,21 +533,22 @@ static int fb_notifier_callback(struct notifier_block *self, unsigned long event static irqreturn_t fpc1020_irq_handler(int irq, void *handle) { struct fpc1020_data *fpc1020 = handle; - //dev_err(fpc1020->dev, "%s\n", __func__); - - /* Make sure 'wakeup_enabled' is updated before using it - ** since this is interrupt context (other thread...) */ - //smp_rmb(); -/* - if (fpc1020->wakeup_enabled ) { - wake_lock_timeout(&fpc1020->ttw_wl, msecs_to_jiffies(FPC_TTW_HOLD_TIME)); - } -*/ - wake_lock_timeout(&fpc1020->ttw_wl, msecs_to_jiffies(FPC_TTW_HOLD_TIME));//changhua add for KeyguardUpdateMonitor: fingerprint acquired, grabbing fp wakelock - //dev_err(fpc1020->dev, "%s before sysfs_notify\n", __func__); sysfs_notify(&fpc1020->dev->kobj, NULL, dev_attr_irq.attr.name); - //dev_err(fpc1020->dev, "%s after sysfs_notify\n", __func__); + + reinit_completion(&fpc1020->irq_sent); + wait_for_completion_timeout(&fpc1020->irq_sent, msecs_to_jiffies(100)); + + if (fpc1020->screen_state) + return IRQ_HANDLED; + + wake_lock_timeout(&fpc1020->ttw_wl, msecs_to_jiffies(FPC_TTW_HOLD_TIME)); + + /* Report button input to trigger CPU boost */ + input_report_key(fpc1020->input_dev, KEY_FINGERPRINT, 1); + input_sync(fpc1020->input_dev); + input_report_key(fpc1020->input_dev, KEY_FINGERPRINT, 0); + input_sync(fpc1020->input_dev); return IRQ_HANDLED; } @@ -480,14 +557,14 @@ static int fpc1020_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; int rc = 0; - int irqf; - /*int id0, id1, id2;*/ + unsigned long irqf; struct device_node *np; struct fpc1020_data *fpc1020; pr_info("%s: fp version %x\n", __func__, fp_version); if ((fp_version != 0x01) && (fp_version != 0x02)) return 0; + np = dev->of_node; fpc1020 = devm_kzalloc(dev, sizeof(*fpc1020), GFP_KERNEL); @@ -514,19 +591,11 @@ static int fpc1020_probe(struct platform_device *pdev) else fpc1020->project_version = 0x01; - printk(KERN_INFO "%s 111111111111111\n", __func__); - - - rc = fpc1020_request_named_gpio(fpc1020, "fpc,irq-gpio", &fpc1020->irq_gpio); if (rc) goto exit; - - printk(KERN_INFO "%s 222222222222222\n", __func__); - - rc = gpio_direction_input(fpc1020->irq_gpio); if (rc) { @@ -541,31 +610,6 @@ static int fpc1020_probe(struct platform_device *pdev) goto exit;*/ #ifdef ONEPLUS_EDIT - /* - rc = fpc1020_request_named_gpio(fpc1020, "fpc,gpio_id0", - &fpc1020->id0_gpio); - if(gpio_is_valid(fpc1020->id0_gpio)) - { - dev_err(dev, "%s: gpio_is_valid(fpc1020->id0_gpio=%d)\n", __func__,fpc1020->id0_gpio); - gpio_direction_input(fpc1020->id0_gpio); - } - - rc = fpc1020_request_named_gpio(fpc1020, "fpc,gpio_id1", - &fpc1020->id1_gpio); - if(gpio_is_valid(fpc1020->id1_gpio)) - { - dev_err(dev, "%s: gpio_is_valid(fpc1020->id1_gpio=%d)\n", __func__,fpc1020->id1_gpio); - gpio_direction_input(fpc1020->id1_gpio); - } - - rc = fpc1020_request_named_gpio(fpc1020, "fpc,gpio_id2", - &fpc1020->id2_gpio); - if(gpio_is_valid(fpc1020->id2_gpio)) - { - dev_err(dev, "%s: gpio_is_valid(fpc1020->id2_gpio=%d)\n", __func__,fpc1020->id2_gpio); - gpio_direction_input(fpc1020->id2_gpio); - } - */ /* in xbl rc = fpc1020_request_named_gpio(fpc1020, "fpc,gpio_1V8_EN", &fpc1020->EN_VDD_gpio); @@ -587,6 +631,8 @@ static int fpc1020_probe(struct platform_device *pdev) if (rc) goto exit; + INIT_WORK(&fpc1020->pm_work, fpc1020_suspend_resume); + #if defined(CONFIG_FB) fpc1020->fb_notif.notifier_call = fb_notifier_callback; rc = fb_register_client(&fpc1020->fb_notif); @@ -595,8 +641,12 @@ static int fpc1020_probe(struct platform_device *pdev) fpc1020->screen_state = 1; #endif + spin_lock_init(&fpc1020->irq_lock); + fpc1020->irq_enabled = true; + irqf = IRQF_TRIGGER_RISING | IRQF_ONESHOT; mutex_init(&fpc1020->lock); + init_completion(&fpc1020->irq_sent); rc = devm_request_threaded_irq(dev, gpio_to_irq(fpc1020->irq_gpio), NULL, fpc1020_irq_handler, irqf, dev_name(dev), fpc1020); @@ -654,34 +704,6 @@ static int fpc1020_probe(struct platform_device *pdev) * Goodix 1 0 1 * */ -/* - fpc1020->sensor_version = 0x02; - id0 = gpio_get_value(fpc1020->id0_gpio); - id1 = gpio_get_value(fpc1020->id1_gpio); - id2 = gpio_get_value(fpc1020->id2_gpio); - if (id0 && id1 && id2) { - push_component_info(FINGERPRINTS, "fpc1245", "FPC(OF)"); - fpc1020->sensor_version = 0x01; - } else if (id0 && !id1 && !id2) { - push_component_info(FINGERPRINTS, "fpc1245", "FPC(Primax)"); - fpc1020->sensor_version = 0x01; - } else if (!id0 && !id1 && id2) { - push_component_info(FINGERPRINTS, "fpc1245", "FPC(truly)"); - fpc1020->sensor_version = 0x01; - } else if (id0 && id1 && !id2) { - push_component_info(FINGERPRINTS, "fpc1263", "FPC(OF)"); - } else if (!id0 && !id1 && !id2) { - push_component_info(FINGERPRINTS, "fpc1263", "FPC(Primax)"); - } else if (!id0 && id1 && id2) { - push_component_info(FINGERPRINTS, "fpc1263", "FPC(truly)"); - } else if (!id0 && id1 && !id2) { - push_component_info(FINGERPRINTS, "fpc1263", "FPC(f/p)"); - } else if (id0 && !id1 && id2) { - push_component_info(FINGERPRINTS, "fpc1263", "FPC(Goodix)"); - } else { - push_component_info(FINGERPRINTS, "fpc", "PC"); - } -*/ dev_info(dev, "%s: ok\n", __func__); exit: return rc;