mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-12 15:49:17 -04:00
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:
parent
991f9f0549
commit
4bd01a0a20
3 changed files with 195 additions and 20 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
22
include/linux/fingerprint_mmi.h
Normal file
22
include/linux/fingerprint_mmi.h
Normal 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
|
||||
Loading…
Reference in a new issue