goodix_fod_mmi: Add device enable notifier chain

Add fingerprint notifier chain in kernel module.
When fingerprint sensor is in working mode, HAL will set dev enable
status, and driver will broadcast this info to FPS notifier chain.

Change-Id: I075cf59aaf031d491f6e7edbe11ed509786e73aa
Signed-off-by: haojl2 <haojl2@motorola.com>
Reviewed-on: https://gerrit.mot.com/1551681
SLTApproved: Slta Waiver
SME-Granted: SME Approvals Granted
Tested-by: Jira Key
Reviewed-by: Qiuliang Cheng <chengql2@motorola.com>
Reviewed-by: Konstantin Makariev <kmakariev@motorola.com>
Submit-Approved: Jira Key
This commit is contained in:
haojl2 2020-05-11 15:44:36 +08:00 • committed by Jialei Hao
commit 4bd01a0a20
3 changed files with 195 additions and 20 deletions

View file

@ -41,6 +41,7 @@
#include <linux/fb.h>
#include <linux/pm_qos.h>
#include <linux/cpufreq.h>
#include <linux/fingerprint_mmi.h>
#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)

View file

@ -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

View file

@ -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 <linux/notifier.h>
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