diff --git a/drivers/input/misc/goodix_fod_mmi/gf_spi.c b/drivers/input/misc/goodix_fod_mmi/gf_spi.c index ac6638404b76..ae340809c3fe 100644 --- a/drivers/input/misc/goodix_fod_mmi/gf_spi.c +++ b/drivers/input/misc/goodix_fod_mmi/gf_spi.c @@ -41,6 +41,7 @@ #include #include #include +#include #include "gf_spi.h" #if defined(USE_SPI_BUS) @@ -91,6 +92,12 @@ static struct gf_key_map maps[] = { #endif }; +struct FPS_data { + unsigned int enabled; + unsigned int state; + struct blocking_notifier_head nhead; +} *fpsData; + static void gf_enable_irq(struct gf_dev *gf_dev) { if (gf_dev->irq_enabled) { @@ -111,6 +118,108 @@ static void gf_disable_irq(struct gf_dev *gf_dev) } } +struct FPS_data *FPS_init(struct device *dev) +{ + struct FPS_data *mdata = devm_kzalloc(dev, + sizeof(struct FPS_data), GFP_KERNEL); + if (mdata) { + BLOCKING_INIT_NOTIFIER_HEAD(&mdata->nhead); + pr_debug("%s: FPS notifier data structure init-ed\n", __func__); + } + return mdata; +} + +int FPS_register_notifier(struct notifier_block *nb, + unsigned long stype, bool report) +{ + int error; + struct FPS_data *mdata = fpsData; + + if (!mdata) + return -ENODEV; + + mdata->enabled = (unsigned int)stype; + pr_info("%s: FPS sensor %lu notifier enabled\n", __func__, stype); + + error = blocking_notifier_chain_register(&mdata->nhead, nb); + if (!error && report) { + int state = mdata->state; + /* send current FPS state on register request */ + blocking_notifier_call_chain(&mdata->nhead, + stype, (void *)&state); + pr_debug("%s: FPS reported state %d\n", __func__, state); + } + return error; +} +EXPORT_SYMBOL_GPL(FPS_register_notifier); + +int FPS_unregister_notifier(struct notifier_block *nb, + unsigned long stype) +{ + int error; + struct FPS_data *mdata = fpsData; + + if (!mdata) + return -ENODEV; + + error = blocking_notifier_chain_unregister(&mdata->nhead, nb); + pr_debug("%s: FPS sensor %lu notifier unregister\n", __func__, stype); + + if (!mdata->nhead.head) { + mdata->enabled = 0; + pr_info("%s: FPS sensor %lu no clients\n", __func__, stype); + } + + return error; +} +EXPORT_SYMBOL_GPL(FPS_unregister_notifier); + +void FPS_notify(unsigned long stype, int state) +{ + struct FPS_data *mdata = fpsData; + + pr_debug("%s: Enter", __func__); + + if (!mdata) { + pr_err("%s: FPS notifier not initialized yet\n", __func__); + return; + } else if (!mdata->enabled) { + pr_debug("%s: !mdata->enabled", __func__); + return; + } + + pr_debug("%s: FPS current state %d -> (0x%x)\n", __func__, + mdata->state, state); + + if (mdata->state != state) { + mdata->state = state; + blocking_notifier_call_chain(&mdata->nhead, + stype, (void *)&state); + pr_debug("%s: FPS notification sent\n", __func__); + } else + pr_warn("%s: mdata->state==state", __func__); +} + +static ssize_t dev_enable_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int state = (*buf == '1') ? 1 : 0; + + FPS_notify(0xbeef, state); + dev_dbg(dev, "%s state = %d\n", __func__, state); + return count; +} +static DEVICE_ATTR(dev_enable, S_IWUSR | S_IWGRP, NULL, dev_enable_set); + +static struct attribute *attributes[] = { + &dev_attr_dev_enable.attr, + NULL +}; + +static const struct attribute_group attribute_group = { + .attrs = attributes, +}; + #ifdef AP_CONTROL_CLK static long spi_clk_max_rate(struct clk *clk, unsigned long rate) { @@ -355,6 +464,7 @@ static long gf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) #endif int retval = 0; u8 netlink_route = NETLINK_TEST; + u8 dev_enable = 0; struct gf_ioc_chip_info info; if (_IOC_TYPE(cmd) != GF_IOC_MAGIC) @@ -468,6 +578,16 @@ static long gf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) pr_info("mode : 0x%x\n", info.mode); pr_info("operation: 0x%x\n", info.operation); break; + case GF_IOC_ENABLE_DEV: + pr_debug("%s GF_IOC_ENABLE_DEV\n", __func__); + if (copy_from_user(&dev_enable, (void __user *)arg, sizeof(uint8_t))) { + pr_err("failed to copy dev enable status from user to kernel\n"); + retval = -EFAULT; + break; + } + FPS_notify(0xbeef, (dev_enable == 0)? 0: 1); + pr_debug("%s device enable status %d\n", __func__, dev_enable); + break; default: pr_warn("unsupport cmd:0x%x\n", cmd); @@ -741,12 +861,23 @@ static int gf_probe(struct platform_device *pdev) gf_disable_irq(gf_dev); device_init_wakeup(dev, true); + fpsData = FPS_init(dev); + status = sysfs_create_group(&dev->kobj, &attribute_group); + + if (status) { + pr_err("failed to create sysfs group. %d\n", status); + goto err_sysfs; + } + pr_info("version V%d.%d.%02d.%02d\n", VER_MAJOR, VER_MINOR, PATCH_LEVEL, EXTEND_VER); pr_info("gf_probe: status = %d\n", status); return status; - +err_sysfs: + device_init_wakeup(dev, false); + if (gf_dev->irq) + free_irq(gf_dev->irq, gf_dev); err_irq: input_unregister_device(gf_dev->input); #ifdef AP_CONTROL_CLK @@ -783,6 +914,7 @@ static int gf_remove(struct platform_device *pdev) struct gf_dev *gf_dev = &gf; struct device *dev = &gf_dev->spi->dev; + sysfs_remove_group(&dev->kobj, &attribute_group); device_init_wakeup(dev, false); /* make sure ops on existing fds can abort cleanly */ if (gf_dev->irq) diff --git a/drivers/input/misc/goodix_fod_mmi/gf_spi.h b/drivers/input/misc/goodix_fod_mmi/gf_spi.h index 648c3156c719..19614c7bf188 100644 --- a/drivers/input/misc/goodix_fod_mmi/gf_spi.h +++ b/drivers/input/misc/goodix_fod_mmi/gf_spi.h @@ -88,28 +88,49 @@ struct gf_ioc_chip_info { unsigned char reserved[5]; }; -#define GF_IOC_MAGIC 'g' -#define GF_IOC_INIT _IOR(GF_IOC_MAGIC, 0, uint8_t) -#define GF_IOC_EXIT _IO(GF_IOC_MAGIC, 1) -#define GF_IOC_RESET _IO(GF_IOC_MAGIC, 2) -#define GF_IOC_ENABLE_IRQ _IO(GF_IOC_MAGIC, 3) -#define GF_IOC_DISABLE_IRQ _IO(GF_IOC_MAGIC, 4) -#define GF_IOC_ENABLE_SPI_CLK _IOW(GF_IOC_MAGIC, 5, uint32_t) -#define GF_IOC_DISABLE_SPI_CLK _IO(GF_IOC_MAGIC, 6) -#define GF_IOC_ENABLE_POWER _IO(GF_IOC_MAGIC, 7) -#define GF_IOC_DISABLE_POWER _IO(GF_IOC_MAGIC, 8) -#define GF_IOC_INPUT_KEY_EVENT _IOW(GF_IOC_MAGIC, 9, struct gf_key) -#define GF_IOC_ENTER_SLEEP_MODE _IO(GF_IOC_MAGIC, 10) -#define GF_IOC_GET_FW_INFO _IOR(GF_IOC_MAGIC, 11, uint8_t) -#define GF_IOC_REMOVE _IO(GF_IOC_MAGIC, 12) -#define GF_IOC_CHIP_INFO _IOW(GF_IOC_MAGIC, 13, struct gf_ioc_chip_info) - +enum GF_IOC_COUNT { + GF_IOC_INIT_COUNT = 0, + GF_IOC_EXIT_COUNT, // 1 + GF_IOC_RESET_COUNT, // 2 + GF_IOC_ENABLE_IRQ_COUNT, // 3 + GF_IOC_DISABLE_IRQ_COUNT, // 4 + GF_IOC_ENABLE_SPI_CLK_COUNT, // 5 + GF_IOC_DISABLE_SPI_CLK_COUNT, // 6 + GF_IOC_ENABLE_POWER_COUNT, // 7 + GF_IOC_DISABLE_POWER_COUNT, // 8 + GF_IOC_INPUT_KEY_EVENT_COUNT, // 9 + GF_IOC_ENTER_SLEEP_MODE_COUNT, // 10 + GF_IOC_GET_FW_INFO_COUNT, // 11 + GF_IOC_REMOVE_COUNT, // 12 + GF_IOC_CHIP_INFO_COUNT, // 13 #if defined(SUPPORT_NAV_EVENT) -#define GF_IOC_NAV_EVENT _IOW(GF_IOC_MAGIC, 14, gf_nav_event_t) -#define GF_IOC_MAXNR 15 /* THIS MACRO IS NOT USED NOW... */ + GF_IOC_NAV_EVENT_COUNT, // 14 #else -#define GF_IOC_MAXNR 14 /* THIS MACRO IS NOT USED NOW... */ + GF_IOC_14, // 14 #endif + GF_IOC_ENABLE_DEV_COUNT, // 15 + GF_IOC_MAXNR, +}; + +#define GF_IOC_MAGIC 'g' +#define GF_IOC_INIT _IOR(GF_IOC_MAGIC, GF_IOC_INIT_COUNT, uint8_t) +#define GF_IOC_EXIT _IO(GF_IOC_MAGIC, GF_IOC_EXIT_COUNT) +#define GF_IOC_RESET _IO(GF_IOC_MAGIC, GF_IOC_RESET_COUNT) +#define GF_IOC_ENABLE_IRQ _IO(GF_IOC_MAGIC, GF_IOC_ENABLE_IRQ_COUNT) +#define GF_IOC_DISABLE_IRQ _IO(GF_IOC_MAGIC, GF_IOC_DISABLE_IRQ_COUNT) +#define GF_IOC_ENABLE_SPI_CLK _IOW(GF_IOC_MAGIC, GF_IOC_ENABLE_SPI_CLK_COUNT, uint32_t) +#define GF_IOC_DISABLE_SPI_CLK _IO(GF_IOC_MAGIC, GF_IOC_DISABLE_SPI_CLK_COUNT) +#define GF_IOC_ENABLE_POWER _IO(GF_IOC_MAGIC, GF_IOC_ENABLE_POWER_COUNT) +#define GF_IOC_DISABLE_POWER _IO(GF_IOC_MAGIC, GF_IOC_DISABLE_POWER_COUNT) +#define GF_IOC_INPUT_KEY_EVENT _IOW(GF_IOC_MAGIC, GF_IOC_INPUT_KEY_EVENT_COUNT, struct gf_key) +#define GF_IOC_ENTER_SLEEP_MODE _IO(GF_IOC_MAGIC, GF_IOC_ENTER_SLEEP_MODE_COUNT) +#define GF_IOC_GET_FW_INFO _IOR(GF_IOC_MAGIC, GF_IOC_GET_FW_INFO_COUNT, uint8_t) +#define GF_IOC_REMOVE _IO(GF_IOC_MAGIC, GF_IOC_REMOVE_COUNT) +#define GF_IOC_CHIP_INFO _IOW(GF_IOC_MAGIC, GF_IOC_CHIP_INFO_COUNT, struct gf_ioc_chip_info) +#if defined(SUPPORT_NAV_EVENT) +#define GF_IOC_NAV_EVENT _IOW(GF_IOC_MAGIC, GF_IOC_NAV_EVENT_COUNT, gf_nav_event_t) +#endif +#define GF_IOC_ENABLE_DEV _IOW(GF_IOC_MAGIC, GF_IOC_ENABLE_DEV_COUNT, uint8_t) /*#define AP_CONTROL_CLK 1*/ #define USE_PLATFORM_BUS 1 diff --git a/include/linux/fingerprint_mmi.h b/include/linux/fingerprint_mmi.h new file mode 100644 index 000000000000..09328bc8aaa4 --- /dev/null +++ b/include/linux/fingerprint_mmi.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2020 Motorola Mobility LLC + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __LINUX_FINGERPRINT_MMI_H_ +#define __LINUX_FINGERPRINT_MMI_H_ + +#include + +extern int FPS_register_notifier(struct notifier_block *nb, unsigned long stype, bool report); +extern int FPS_unregister_notifier(struct notifier_block *nb, unsigned long stype); + +#endif