mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-09 05:39:54 -04:00
KeivJP: bringup chipone fps driver
bringup chipone fps driver build fpsensor_spi_tee NO_PROP_NEEDED:chipone fps only used kiev Change-Id: If53eb500939061791959c31d5525d2f323736df2 Signed-off-by: daiss1 <daiss1@lenovo.com> Reviewed-on: https://gerrit.mot.com/1649664 SLTApproved: Slta Waiver SME-Granted: SME Approvals Granted Tested-by: Jira Key Reviewed-by: Guobin Zhang <zhanggb@motorola.com> Submit-Approved: Jira Key
This commit is contained in:
parent
f7aadbe62a
commit
ea2e8997d1
6 changed files with 896 additions and 0 deletions
9
drivers/input/misc/chipone_fps_mmi/Android.mk
Normal file
9
drivers/input/misc/chipone_fps_mmi/Android.mk
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
DLKM_DIR := motorola/kernel/modules
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := fpsensor_spi_tee.ko
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
|
||||
include $(DLKM_DIR)/AndroidKernelModule.mk
|
||||
|
||||
5
drivers/input/misc/chipone_fps_mmi/Kbuild
Normal file
5
drivers/input/misc/chipone_fps_mmi/Kbuild
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# add -Wall to try to catch everything we can.
|
||||
EXTRA_CFLAGS += -Wall
|
||||
EXTRA_CFLAGS += -I$(TOP)/motorola/kernel/modules/include
|
||||
|
||||
obj-m += fpsensor_spi_tee.o
|
||||
10
drivers/input/misc/chipone_fps_mmi/Makefile
Normal file
10
drivers/input/misc/chipone_fps_mmi/Makefile
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KERNEL_SRC) M=$(shell pwd) modules $(KBUILD_OPTIONS)
|
||||
|
||||
modules_install:
|
||||
$(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(shell pwd) modules_install
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean
|
||||
735
drivers/input/misc/chipone_fps_mmi/fpsensor_spi_tee.c
Normal file
735
drivers/input/misc/chipone_fps_mmi/fpsensor_spi_tee.c
Normal file
|
|
@ -0,0 +1,735 @@
|
|||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <net/sock.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
#include <linux/compat.h>
|
||||
#endif
|
||||
|
||||
#include "fpsensor_spi_tee.h"
|
||||
#include "fpsensor_wakelock.h"
|
||||
#define FPSENSOR_FB_DRM 1
|
||||
#define FPSENSOR_FB_OLD 2
|
||||
|
||||
#define FPSENSOR_WAKEUP_SOURCE 1
|
||||
#define FPSENSOR_WAKEUP_OLD 2
|
||||
|
||||
#define FPSENSOR_SPI_VERSION "fpsensor_spi_tee_qcomm_v1.23.1"
|
||||
#define FPSENSOR_USE_QCOM_POWER_GPIO 0
|
||||
#define FPSENSOR_WAKEUP_TYPE FPSENSOR_WAKEUP_SOURCE
|
||||
#define FP_NOTIFY 1
|
||||
#define FP_NOTIFY_TYPE FPSENSOR_FB_DRM
|
||||
|
||||
#if FP_NOTIFY
|
||||
#if FP_NOTIFY_TYPE == FPSENSOR_FB_DRM
|
||||
#include <linux/msm_drm_notify.h>
|
||||
#define FP_NOTIFY_ON MSM_DRM_BLANK_UNBLANK
|
||||
#define FP_NOTIFY_OFF MSM_DRM_BLANK_POWERDOWN
|
||||
#define FP_NOTIFY_EVENT_BLANK MSM_DRM_EARLY_EVENT_BLANK //MSM_DRM_EVENT_BLANK
|
||||
#define fpsensor_fb_register_client(client) msm_drm_register_client(client);
|
||||
#define fpsensor_fb_unregister_client(client) msm_drm_unregister_client(client);
|
||||
#else
|
||||
#define FP_NOTIFY_ON FB_BLANK_UNBLANK
|
||||
#define FP_NOTIFY_OFF FB_BLANK_POWERDOWN
|
||||
#define FP_NOTIFY_EVENT_BLANK FB_EVENT_BLANK
|
||||
#define fpsensor_fb_register_client(client) fb_register_client(client);
|
||||
#define fpsensor_fb_unregister_client(client) fb_unregister_client(client)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* debug log setting */
|
||||
static u8 fpsensor_debug_level = INFO_LOG;
|
||||
/* global variables */
|
||||
static fpsensor_data_t *g_fpsensor = NULL;
|
||||
uint32_t g_cmd_sn = 0;
|
||||
|
||||
#if FPSENSOR_WAKEUP_TYPE == FPSENSOR_WAKEUP_SOURCE
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/device.h>
|
||||
struct wakeup_source g_ttw_wl;
|
||||
#else
|
||||
#include <linux/wakelock.h>
|
||||
struct wake_lock g_ttw_wl;
|
||||
#endif
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* fingerprint chip hardware configuration */
|
||||
/* -------------------------------------------------------------------- */
|
||||
static void fpsensor_gpio_free(fpsensor_data_t *fpsensor)
|
||||
{
|
||||
struct device *dev = &fpsensor->spi->dev;
|
||||
|
||||
if (fpsensor->irq_gpio != 0 ) {
|
||||
devm_gpio_free(dev, fpsensor->irq_gpio);
|
||||
fpsensor->irq_gpio = 0;
|
||||
}
|
||||
if (fpsensor->reset_gpio != 0) {
|
||||
devm_gpio_free(dev, fpsensor->reset_gpio);
|
||||
fpsensor->reset_gpio = 0;
|
||||
}
|
||||
#if FPSENSOR_USE_QCOM_POWER_GPIO
|
||||
if (fpsensor->power_gpio != 0) {
|
||||
devm_gpio_free(dev, fpsensor->power_gpio);
|
||||
fpsensor->power_gpio = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void fpsensor_irq_gpio_cfg(fpsensor_data_t *fpsensor)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
error = gpio_direction_input(fpsensor->irq_gpio);
|
||||
if (error) {
|
||||
fpsensor_debug(ERR_LOG, "setup fpsensor irq gpio for input failed!error[%d]\n", error);
|
||||
return ;
|
||||
}
|
||||
|
||||
fpsensor->irq = gpio_to_irq(fpsensor->irq_gpio);
|
||||
fpsensor_debug(DEBUG_LOG, "fpsensor irq number[%d]\n", fpsensor->irq);
|
||||
if (fpsensor->irq <= 0) {
|
||||
fpsensor_debug(ERR_LOG, "fpsensor irq gpio to irq failed!\n");
|
||||
return ;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int fpsensor_request_named_gpio(fpsensor_data_t *fpsensor_dev, const char *label, int *gpio)
|
||||
{
|
||||
struct device *dev = &fpsensor_dev->spi->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
int ret = of_get_named_gpio(np, label, 0);
|
||||
|
||||
if (ret < 0) {
|
||||
fpsensor_debug(ERR_LOG, "failed to get '%s'\n", label);
|
||||
return ret;
|
||||
}
|
||||
*gpio = ret;
|
||||
ret = devm_gpio_request(dev, *gpio, label);
|
||||
if (ret) {
|
||||
fpsensor_debug(ERR_LOG, "failed to request gpio %d\n", *gpio);
|
||||
return ret;
|
||||
}
|
||||
|
||||
fpsensor_debug(ERR_LOG, "%s %d\n", label, *gpio);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* delay us after reset */
|
||||
static void fpsensor_hw_reset(int delay)
|
||||
{
|
||||
FUNC_ENTRY();
|
||||
gpio_set_value(g_fpsensor->reset_gpio, 1);
|
||||
|
||||
udelay(100);
|
||||
gpio_set_value(g_fpsensor->reset_gpio, 0);
|
||||
|
||||
udelay(1000);
|
||||
gpio_set_value(g_fpsensor->reset_gpio, 1);
|
||||
|
||||
if (delay) {
|
||||
udelay(delay);
|
||||
}
|
||||
|
||||
FUNC_EXIT();
|
||||
return;
|
||||
}
|
||||
|
||||
static int fpsensor_get_gpio_dts_info(fpsensor_data_t *fpsensor)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
FUNC_ENTRY();
|
||||
// get interrupt gpio resource
|
||||
ret = fpsensor_request_named_gpio(fpsensor, "fp-gpio-int", &fpsensor->irq_gpio);
|
||||
if (ret) {
|
||||
fpsensor_debug(ERR_LOG, "Failed to request irq GPIO. ret = %d\n", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// get reest gpio resourece
|
||||
ret = fpsensor_request_named_gpio(fpsensor, "fp-gpio-reset", &fpsensor->reset_gpio);
|
||||
if (ret) {
|
||||
fpsensor_debug(ERR_LOG, "Failed to request reset GPIO. ret = %d\n", ret);
|
||||
return -1;
|
||||
}
|
||||
#if FPSENSOR_USE_QCOM_POWER_GPIO
|
||||
// get power gpio resourece
|
||||
ret = fpsensor_request_named_gpio(fpsensor, "fp-gpio-power", &fpsensor->power_gpio);
|
||||
if (ret) {
|
||||
fpsensor_debug(ERR_LOG, "Failed to request power GPIO. ret = %d\n", ret);
|
||||
return -1;
|
||||
}
|
||||
// set power direction output
|
||||
gpio_direction_output(fpsensor->power_gpio, 1);
|
||||
gpio_set_value(fpsensor->power_gpio, 1);
|
||||
#endif
|
||||
// set reset direction output
|
||||
gpio_direction_output(fpsensor->reset_gpio, 1);
|
||||
fpsensor_hw_reset(1250);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void setRcvIRQ(int val)
|
||||
{
|
||||
fpsensor_data_t *fpsensor_dev = g_fpsensor;
|
||||
fpsensor_dev->RcvIRQ = val;
|
||||
}
|
||||
|
||||
static void fpsensor_enable_irq(fpsensor_data_t *fpsensor_dev)
|
||||
{
|
||||
FUNC_ENTRY();
|
||||
setRcvIRQ(0);
|
||||
/* Request that the interrupt should be wakeable */
|
||||
if (fpsensor_dev->irq_enabled == 0) {
|
||||
enable_irq(fpsensor_dev->irq);
|
||||
fpsensor_dev->irq_enabled = 1;
|
||||
}
|
||||
FUNC_EXIT();
|
||||
return;
|
||||
}
|
||||
|
||||
static void fpsensor_disable_irq(fpsensor_data_t *fpsensor_dev)
|
||||
{
|
||||
FUNC_ENTRY();
|
||||
|
||||
if (0 == fpsensor_dev->device_available) {
|
||||
fpsensor_debug(ERR_LOG, "%s, devices not available\n", __func__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (0 == fpsensor_dev->irq_enabled) {
|
||||
fpsensor_debug(ERR_LOG, "%s, irq already disabled\n", __func__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fpsensor_dev->irq) {
|
||||
disable_irq_nosync(fpsensor_dev->irq);
|
||||
fpsensor_debug(DEBUG_LOG, "%s disable interrupt!\n", __func__);
|
||||
}
|
||||
fpsensor_dev->irq_enabled = 0;
|
||||
|
||||
out:
|
||||
setRcvIRQ(0);
|
||||
FUNC_EXIT();
|
||||
return;
|
||||
}
|
||||
|
||||
static irqreturn_t fpsensor_irq(int irq, void *handle)
|
||||
{
|
||||
fpsensor_data_t *fpsensor_dev = (fpsensor_data_t *)handle;
|
||||
|
||||
/* Make sure 'wakeup_enabled' is updated before using it
|
||||
** since this is interrupt context (other thread...) */
|
||||
smp_rmb();
|
||||
#if FPSENSOR_WAKEUP_TYPE == FPSENSOR_WAKEUP_SOURCE
|
||||
__pm_wakeup_event(&g_ttw_wl, 1000);
|
||||
#else
|
||||
wake_lock_timeout(&g_ttw_wl, msecs_to_jiffies(1000));
|
||||
#endif
|
||||
setRcvIRQ(1);
|
||||
wake_up_interruptible(&fpsensor_dev->wq_irq_return);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
// release and cleanup fpsensor char device
|
||||
static void fpsensor_dev_cleanup(fpsensor_data_t *fpsensor)
|
||||
{
|
||||
FUNC_ENTRY();
|
||||
|
||||
cdev_del(&fpsensor->cdev);
|
||||
unregister_chrdev_region(fpsensor->devno, FPSENSOR_NR_DEVS);
|
||||
device_destroy(fpsensor->class, fpsensor->devno);
|
||||
class_destroy(fpsensor->class);
|
||||
|
||||
FUNC_EXIT();
|
||||
}
|
||||
|
||||
static long fpsensor_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
fpsensor_data_t *fpsensor_dev = NULL;
|
||||
int retval = 0;
|
||||
uint32_t val = 0;
|
||||
int irqf;
|
||||
|
||||
fpsensor_debug(INFO_LOG, "[rickon]: fpsensor ioctl cmd : 0x%x \n", cmd );
|
||||
fpsensor_dev = (fpsensor_data_t *)filp->private_data;
|
||||
fpsensor_dev->cancel = 0 ;
|
||||
switch (cmd) {
|
||||
case FPSENSOR_IOC_INIT:
|
||||
fpsensor_debug(INFO_LOG, "%s: fpsensor init started======\n", __func__);
|
||||
retval = fpsensor_get_gpio_dts_info(fpsensor_dev);
|
||||
if (retval) {
|
||||
break;
|
||||
}
|
||||
fpsensor_irq_gpio_cfg(fpsensor_dev);
|
||||
//regist irq
|
||||
irqf = IRQF_TRIGGER_RISING | IRQF_ONESHOT;
|
||||
retval = devm_request_threaded_irq(&g_fpsensor->spi->dev, g_fpsensor->irq, fpsensor_irq,
|
||||
NULL, irqf, dev_name(&g_fpsensor->spi->dev), g_fpsensor);
|
||||
if (retval == 0) {
|
||||
fpsensor_debug(INFO_LOG, " irq thread reqquest success!\n");
|
||||
} else {
|
||||
fpsensor_debug(INFO_LOG, " irq thread request failed , retval =%d \n", retval);
|
||||
break;
|
||||
}
|
||||
enable_irq_wake(g_fpsensor->irq);
|
||||
fpsensor_dev->device_available = 1;
|
||||
// fix Unbalanced enable for IRQ, disable irq at first
|
||||
fpsensor_dev->irq_enabled = 1;
|
||||
fpsensor_disable_irq(fpsensor_dev);
|
||||
fpsensor_debug(INFO_LOG, "%s: fpsensor init finished======\n", __func__);
|
||||
break;
|
||||
|
||||
case FPSENSOR_IOC_EXIT:
|
||||
fpsensor_disable_irq(fpsensor_dev);
|
||||
if (fpsensor_dev->irq) {
|
||||
free_irq(fpsensor_dev->irq, fpsensor_dev);
|
||||
fpsensor_dev->irq_enabled = 0;
|
||||
}
|
||||
fpsensor_dev->device_available = 0;
|
||||
fpsensor_gpio_free(fpsensor_dev);
|
||||
fpsensor_debug(INFO_LOG, "%s: fpsensor exit finished======\n", __func__);
|
||||
break;
|
||||
|
||||
case FPSENSOR_IOC_RESET:
|
||||
fpsensor_debug(INFO_LOG, "%s: chip reset command\n", __func__);
|
||||
fpsensor_hw_reset(1250);
|
||||
break;
|
||||
|
||||
case FPSENSOR_IOC_ENABLE_IRQ:
|
||||
fpsensor_debug(INFO_LOG, "%s: chip ENable IRQ command\n", __func__);
|
||||
fpsensor_enable_irq(fpsensor_dev);
|
||||
break;
|
||||
|
||||
case FPSENSOR_IOC_DISABLE_IRQ:
|
||||
fpsensor_debug(INFO_LOG, "%s: chip disable IRQ command\n", __func__);
|
||||
fpsensor_disable_irq(fpsensor_dev);
|
||||
break;
|
||||
case FPSENSOR_IOC_GET_INT_VAL:
|
||||
val = gpio_get_value(fpsensor_dev->irq_gpio);
|
||||
if (copy_to_user((void __user *)arg, (void *)&val, sizeof(uint32_t))) {
|
||||
fpsensor_debug(ERR_LOG, "Failed to copy data to user\n");
|
||||
retval = -EFAULT;
|
||||
break;
|
||||
}
|
||||
retval = 0;
|
||||
break;
|
||||
case FPSENSOR_IOC_ENABLE_SPI_CLK:
|
||||
fpsensor_debug(INFO_LOG, "%s: ENABLE_SPI_CLK ======\n", __func__);
|
||||
break;
|
||||
case FPSENSOR_IOC_DISABLE_SPI_CLK:
|
||||
fpsensor_debug(INFO_LOG, "%s: DISABLE_SPI_CLK ======\n", __func__);
|
||||
break;
|
||||
case FPSENSOR_IOC_ENABLE_POWER:
|
||||
fpsensor_debug(INFO_LOG, "%s: FPSENSOR_IOC_ENABLE_POWER ======\n", __func__);
|
||||
break;
|
||||
case FPSENSOR_IOC_DISABLE_POWER:
|
||||
fpsensor_debug(INFO_LOG, "%s: FPSENSOR_IOC_DISABLE_POWER ======\n", __func__);
|
||||
break;
|
||||
case FPSENSOR_IOC_REMOVE:
|
||||
fpsensor_disable_irq(fpsensor_dev);
|
||||
if (fpsensor_dev->irq) {
|
||||
free_irq(fpsensor_dev->irq, fpsensor_dev);
|
||||
fpsensor_dev->irq_enabled = 0;
|
||||
}
|
||||
fpsensor_dev->device_available = 0;
|
||||
fpsensor_gpio_free(fpsensor_dev);
|
||||
fpsensor_dev_cleanup(fpsensor_dev);
|
||||
#if FP_NOTIFY
|
||||
fpsensor_fb_unregister_client(&fpsensor_dev->notifier);
|
||||
#endif
|
||||
fpsensor_dev->free_flag = 1;
|
||||
fpsensor_debug(INFO_LOG, "%s remove finished\n", __func__);
|
||||
break;
|
||||
case FPSENSOR_IOC_CANCEL_WAIT:
|
||||
fpsensor_debug(INFO_LOG, "%s: FPSENSOR CANCEL WAIT\n", __func__);
|
||||
wake_up_interruptible(&fpsensor_dev->wq_irq_return);
|
||||
fpsensor_dev->cancel = 1;
|
||||
break;
|
||||
#if FP_NOTIFY
|
||||
case FPSENSOR_IOC_GET_FP_STATUS :
|
||||
val = fpsensor_dev->fb_status;
|
||||
fpsensor_debug(INFO_LOG, "%s: FPSENSOR_IOC_GET_FP_STATUS %d \n",__func__, fpsensor_dev->fb_status);
|
||||
if (copy_to_user((void __user *)arg, (void *)&val, sizeof(uint32_t))) {
|
||||
fpsensor_debug(ERR_LOG, "Failed to copy data to user\n");
|
||||
retval = -EFAULT;
|
||||
break;
|
||||
}
|
||||
retval = 0;
|
||||
break;
|
||||
#endif
|
||||
case FPSENSOR_IOC_ENABLE_REPORT_BLANKON:
|
||||
if (copy_from_user(&val, (void __user *)arg, sizeof(uint32_t))) {
|
||||
retval = -EFAULT;
|
||||
break;
|
||||
}
|
||||
fpsensor_dev->enable_report_blankon = val;
|
||||
fpsensor_debug(INFO_LOG, "%s: FPSENSOR_IOC_ENABLE_REPORT_BLANKON: %d\n", __func__, val);
|
||||
break;
|
||||
case FPSENSOR_IOC_UPDATE_DRIVER_SN:
|
||||
if (copy_from_user(&g_cmd_sn, (void __user *)arg, sizeof(uint32_t))) {
|
||||
fpsensor_debug(ERR_LOG, "Failed to copy g_cmd_sn from user to kernel\n");
|
||||
retval = -EFAULT;
|
||||
break;
|
||||
}
|
||||
//fpsensor_debug(INFO_LOG, "%s: FPSENSOR_IOC_UPDATE_DRIVER_SN: %d\n", __func__, g_cmd_sn);
|
||||
break;
|
||||
default:
|
||||
fpsensor_debug(ERR_LOG, "fpsensor doesn't support this command(0x%x)\n", cmd);
|
||||
break;
|
||||
}
|
||||
|
||||
//FUNC_EXIT();
|
||||
return retval;
|
||||
}
|
||||
|
||||
static long fpsensor_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
return fpsensor_ioctl(filp, cmd, (unsigned long)(arg));
|
||||
}
|
||||
|
||||
static unsigned int fpsensor_poll(struct file *filp, struct poll_table_struct *wait)
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
|
||||
ret |= POLLIN;
|
||||
poll_wait(filp, &g_fpsensor->wq_irq_return, wait);
|
||||
if (g_fpsensor->cancel == 1) {
|
||||
fpsensor_debug(ERR_LOG, " cancle\n");
|
||||
ret = POLLERR;
|
||||
g_fpsensor->cancel = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ( g_fpsensor->RcvIRQ) {
|
||||
if (g_fpsensor->RcvIRQ == 2) {
|
||||
fpsensor_debug(ERR_LOG, " get fp on notify\n");
|
||||
ret |= POLLHUP;
|
||||
} else {
|
||||
fpsensor_debug(ERR_LOG, " get irq\n");
|
||||
ret |= POLLRDNORM;
|
||||
}
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fpsensor_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
fpsensor_data_t *fpsensor_dev;
|
||||
|
||||
FUNC_ENTRY();
|
||||
fpsensor_dev = container_of(inode->i_cdev, fpsensor_data_t, cdev);
|
||||
fpsensor_dev->users++;
|
||||
fpsensor_dev->device_available = 1;
|
||||
filp->private_data = fpsensor_dev;
|
||||
FUNC_EXIT();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fpsensor_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
fpsensor_data_t *fpsensor_dev;
|
||||
int status = 0;
|
||||
|
||||
FUNC_ENTRY();
|
||||
fpsensor_dev = filp->private_data;
|
||||
filp->private_data = NULL;
|
||||
|
||||
/*last close??*/
|
||||
fpsensor_dev->users--;
|
||||
if (fpsensor_dev->users <= 0) {
|
||||
fpsensor_debug(INFO_LOG, "%s, disble_irq. irq = %d\n", __func__, fpsensor_dev->irq);
|
||||
fpsensor_disable_irq(fpsensor_dev);
|
||||
}
|
||||
fpsensor_dev->device_available = 0;
|
||||
FUNC_EXIT();
|
||||
return status;
|
||||
}
|
||||
|
||||
static ssize_t fpsensor_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
|
||||
{
|
||||
fpsensor_debug(ERR_LOG, "Not support read opertion in TEE version\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
static ssize_t fpsensor_write(struct file *filp, const char __user *buf, size_t count,
|
||||
loff_t *f_pos)
|
||||
{
|
||||
fpsensor_debug(ERR_LOG, "Not support write opertion in TEE version\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
static const struct file_operations fpsensor_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.write = fpsensor_write,
|
||||
.read = fpsensor_read,
|
||||
.unlocked_ioctl = fpsensor_ioctl,
|
||||
.compat_ioctl = fpsensor_compat_ioctl,
|
||||
.open = fpsensor_open,
|
||||
.release = fpsensor_release,
|
||||
.poll = fpsensor_poll,
|
||||
|
||||
};
|
||||
|
||||
// create and register a char device for fpsensor
|
||||
static int fpsensor_dev_setup(fpsensor_data_t *fpsensor)
|
||||
{
|
||||
int ret = 0;
|
||||
dev_t dev_no = 0;
|
||||
struct device *dev = NULL;
|
||||
int fpsensor_dev_major = FPSENSOR_DEV_MAJOR;
|
||||
int fpsensor_dev_minor = 0;
|
||||
|
||||
FUNC_ENTRY();
|
||||
|
||||
if (fpsensor_dev_major) {
|
||||
dev_no = MKDEV(fpsensor_dev_major, fpsensor_dev_minor);
|
||||
ret = register_chrdev_region(dev_no, FPSENSOR_NR_DEVS, FPSENSOR_DEV_NAME);
|
||||
} else {
|
||||
ret = alloc_chrdev_region(&dev_no, fpsensor_dev_minor, FPSENSOR_NR_DEVS, FPSENSOR_DEV_NAME);
|
||||
fpsensor_dev_major = MAJOR(dev_no);
|
||||
fpsensor_dev_minor = MINOR(dev_no);
|
||||
fpsensor_debug(INFO_LOG, "fpsensor device major is %d, minor is %d\n",
|
||||
fpsensor_dev_major, fpsensor_dev_minor);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
fpsensor_debug(ERR_LOG, "can not get device major number %d\n", fpsensor_dev_major);
|
||||
goto out;
|
||||
}
|
||||
|
||||
cdev_init(&fpsensor->cdev, &fpsensor_fops);
|
||||
fpsensor->cdev.owner = THIS_MODULE;
|
||||
fpsensor->cdev.ops = &fpsensor_fops;
|
||||
fpsensor->devno = dev_no;
|
||||
ret = cdev_add(&fpsensor->cdev, dev_no, FPSENSOR_NR_DEVS);
|
||||
if (ret) {
|
||||
fpsensor_debug(ERR_LOG, "add char dev for fpsensor failed\n");
|
||||
goto release_region;
|
||||
}
|
||||
|
||||
fpsensor->class = class_create(THIS_MODULE, FPSENSOR_CLASS_NAME);
|
||||
if (IS_ERR(fpsensor->class)) {
|
||||
fpsensor_debug(ERR_LOG, "create fpsensor class failed\n");
|
||||
ret = PTR_ERR(fpsensor->class);
|
||||
goto release_cdev;
|
||||
}
|
||||
|
||||
dev = device_create(fpsensor->class, &fpsensor->spi->dev, dev_no, fpsensor, FPSENSOR_DEV_NAME);
|
||||
if (IS_ERR(dev)) {
|
||||
fpsensor_debug(ERR_LOG, "create device for fpsensor failed\n");
|
||||
ret = PTR_ERR(dev);
|
||||
goto release_class;
|
||||
}
|
||||
FUNC_EXIT();
|
||||
return ret;
|
||||
|
||||
release_class:
|
||||
class_destroy(fpsensor->class);
|
||||
fpsensor->class = NULL;
|
||||
release_cdev:
|
||||
cdev_del(&fpsensor->cdev);
|
||||
release_region:
|
||||
unregister_chrdev_region(dev_no, FPSENSOR_NR_DEVS);
|
||||
out:
|
||||
FUNC_EXIT();
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if FP_NOTIFY
|
||||
static int fpsensor_fb_notifier_callback(struct notifier_block* self, unsigned long event, void* data)
|
||||
{
|
||||
int retval = 0;
|
||||
static char screen_status[64] = { '\0' };
|
||||
struct fb_event* evdata = data;
|
||||
unsigned int blank;
|
||||
fpsensor_data_t *fpsensor_dev = g_fpsensor;
|
||||
|
||||
fpsensor_debug(INFO_LOG,"%s enter, event: 0x%x\n", __func__, (unsigned)event);
|
||||
if (event != FP_NOTIFY_EVENT_BLANK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
blank = *(int*)evdata->data;
|
||||
fpsensor_debug(INFO_LOG,"%s enter, blank=0x%x\n", __func__, blank);
|
||||
|
||||
switch (blank) {
|
||||
case FP_NOTIFY_ON:
|
||||
fpsensor_debug(INFO_LOG,"%s: lcd on notify\n", __func__);
|
||||
sprintf(screen_status, "SCREEN_STATUS=%s", "ON");
|
||||
fpsensor_dev->fb_status = 1;
|
||||
if( fpsensor_dev->enable_report_blankon) {
|
||||
fpsensor_dev->RcvIRQ = 2;
|
||||
wake_up_interruptible(&fpsensor_dev->wq_irq_return);
|
||||
}
|
||||
break;
|
||||
|
||||
case FP_NOTIFY_OFF:
|
||||
fpsensor_debug(INFO_LOG,"%s: lcd off notify\n", __func__);
|
||||
sprintf(screen_status, "SCREEN_STATUS=%s", "OFF");
|
||||
fpsensor_dev->fb_status = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
fpsensor_debug(INFO_LOG,"%s: other notifier, ignore\n", __func__);
|
||||
break;
|
||||
}
|
||||
|
||||
fpsensor_debug(INFO_LOG,"%s %s leave.\n", screen_status, __func__);
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int fpsensor_probe(struct platform_device *pdev)
|
||||
{
|
||||
int status = 0;
|
||||
fpsensor_data_t *fpsensor_dev = NULL;
|
||||
|
||||
FUNC_ENTRY();
|
||||
|
||||
/* Allocate driver data */
|
||||
fpsensor_dev = kzalloc(sizeof(*fpsensor_dev), GFP_KERNEL);
|
||||
if (!fpsensor_dev) {
|
||||
status = -ENOMEM;
|
||||
fpsensor_debug(ERR_LOG, "%s, Failed to alloc memory for fpsensor device.\n", __func__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Initialize the driver data */
|
||||
g_fpsensor = fpsensor_dev;
|
||||
fpsensor_dev->spi = pdev ;
|
||||
fpsensor_dev->device_available = 0;
|
||||
fpsensor_dev->users = 0;
|
||||
fpsensor_dev->irq = 0;
|
||||
fpsensor_dev->power_gpio = 0;
|
||||
fpsensor_dev->reset_gpio = 0;
|
||||
fpsensor_dev->irq_gpio = 0;
|
||||
fpsensor_dev->irq_enabled = 0;
|
||||
fpsensor_dev->free_flag = 0;
|
||||
fpsensor_dev->fb_status = 1;
|
||||
/* setup a char device for fpsensor */
|
||||
status = fpsensor_dev_setup(fpsensor_dev);
|
||||
if (status) {
|
||||
fpsensor_debug(ERR_LOG, "fpsensor setup char device failed, %d", status);
|
||||
goto release_drv_data;
|
||||
}
|
||||
init_waitqueue_head(&fpsensor_dev->wq_irq_return);
|
||||
#if FPSENSOR_WAKEUP_TYPE == FPSENSOR_WAKEUP_SOURCE
|
||||
wakeup_source_init(&g_ttw_wl, "fpsensor_ttw_wl");
|
||||
#else
|
||||
wake_lock_init(&g_ttw_wl, WAKE_LOCK_SUSPEND, "fpsensor_ttw_wl");
|
||||
#endif
|
||||
fpsensor_dev->device_available = 1;
|
||||
#if FP_NOTIFY
|
||||
fpsensor_dev->notifier.notifier_call = fpsensor_fb_notifier_callback;
|
||||
fpsensor_fb_register_client(&fpsensor_dev->notifier);
|
||||
#endif
|
||||
|
||||
fpsensor_debug(INFO_LOG, "%s finished, driver version: %s\n", __func__, FPSENSOR_SPI_VERSION);
|
||||
goto out;
|
||||
|
||||
release_drv_data:
|
||||
kfree(fpsensor_dev);
|
||||
fpsensor_dev = NULL;
|
||||
out:
|
||||
FUNC_EXIT();
|
||||
return status;
|
||||
}
|
||||
|
||||
static int fpsensor_remove(struct platform_device *pdev)
|
||||
{
|
||||
fpsensor_data_t *fpsensor_dev = g_fpsensor;
|
||||
|
||||
FUNC_ENTRY();
|
||||
fpsensor_disable_irq(fpsensor_dev);
|
||||
if (fpsensor_dev->irq)
|
||||
free_irq(fpsensor_dev->irq, fpsensor_dev);
|
||||
|
||||
#if FP_NOTIFY
|
||||
fpsensor_fb_unregister_client(&fpsensor_dev->notifier);
|
||||
#endif
|
||||
fpsensor_gpio_free(fpsensor_dev);
|
||||
fpsensor_dev_cleanup(fpsensor_dev);
|
||||
#if FPSENSOR_WAKEUP_TYPE == FPSENSOR_WAKEUP_SOURCE
|
||||
wakeup_source_trash(&g_ttw_wl);
|
||||
#else
|
||||
wake_lock_destroy(&g_ttw_wl);
|
||||
#endif
|
||||
kfree(fpsensor_dev);
|
||||
g_fpsensor = NULL;
|
||||
|
||||
FUNC_EXIT();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fpsensor_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fpsensor_resume( struct platform_device *pdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id fpsensor_of_match[] = {
|
||||
{ .compatible = "qcom,fingerprint-gpio" },
|
||||
{}
|
||||
};
|
||||
//MODULE_DEVICE_TABLE(of, fpsensor_of_match);
|
||||
#endif
|
||||
|
||||
static struct platform_driver fpsensor_driver = {
|
||||
.driver = {
|
||||
.name = FPSENSOR_DEV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
#ifdef CONFIG_OF
|
||||
.of_match_table = fpsensor_of_match,
|
||||
#endif
|
||||
},
|
||||
.probe = fpsensor_probe,
|
||||
.remove = fpsensor_remove,
|
||||
.suspend = fpsensor_suspend,
|
||||
.resume = fpsensor_resume,
|
||||
};
|
||||
|
||||
static int __init fpsensor_init(void)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = platform_driver_register(&fpsensor_driver);
|
||||
if (status < 0) {
|
||||
fpsensor_debug(ERR_LOG, "%s, Failed to register SPI driver.\n", __func__);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
module_init(fpsensor_init);
|
||||
|
||||
static void __exit fpsensor_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&fpsensor_driver);
|
||||
}
|
||||
module_exit(fpsensor_exit);
|
||||
|
||||
MODULE_AUTHOR("xhli");
|
||||
MODULE_DESCRIPTION(" Fingerprint chip TEE driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:fpsensor-drivers");
|
||||
69
drivers/input/misc/chipone_fps_mmi/fpsensor_spi_tee.h
Normal file
69
drivers/input/misc/chipone_fps_mmi/fpsensor_spi_tee.h
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
#ifndef __FPSENSOR_SPI_TEE_H
|
||||
#define __FPSENSOR_SPI_TEE_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/notifier.h>
|
||||
|
||||
#define FPSENSOR_DEV_NAME "fpsensor"
|
||||
#define FPSENSOR_CLASS_NAME "fpsensor"
|
||||
#define FPSENSOR_DEV_MAJOR 0
|
||||
#define N_SPI_MINORS 32 /* ... up to 256 */
|
||||
#define FPSENSOR_NR_DEVS 1
|
||||
|
||||
#define ERR_LOG (0)
|
||||
#define INFO_LOG (1)
|
||||
#define DEBUG_LOG (2)
|
||||
#define fpsensor_debug(level, fmt, args...) do { \
|
||||
if (fpsensor_debug_level >= level) {\
|
||||
printk("[fpCoreDriver][SN=%d] " fmt, g_cmd_sn, ##args); \
|
||||
} \
|
||||
} while (0)
|
||||
#define FUNC_ENTRY() fpsensor_debug(DEBUG_LOG, "%s, %d, entry\n", __func__, __LINE__)
|
||||
#define FUNC_EXIT() fpsensor_debug(DEBUG_LOG, "%s, %d, exit\n", __func__, __LINE__)
|
||||
|
||||
/**********************IO Magic**********************/
|
||||
#define FPSENSOR_IOC_MAGIC 0xf0 //CHIP
|
||||
|
||||
/* define commands */
|
||||
#define FPSENSOR_IOC_INIT _IOWR(FPSENSOR_IOC_MAGIC,0,uint32_t)
|
||||
#define FPSENSOR_IOC_EXIT _IOWR(FPSENSOR_IOC_MAGIC,1,uint32_t)
|
||||
#define FPSENSOR_IOC_RESET _IOWR(FPSENSOR_IOC_MAGIC,2,uint32_t)
|
||||
#define FPSENSOR_IOC_ENABLE_IRQ _IOWR(FPSENSOR_IOC_MAGIC,3,uint32_t)
|
||||
#define FPSENSOR_IOC_DISABLE_IRQ _IOWR(FPSENSOR_IOC_MAGIC,4,uint32_t)
|
||||
#define FPSENSOR_IOC_GET_INT_VAL _IOWR(FPSENSOR_IOC_MAGIC,5,uint32_t)
|
||||
#define FPSENSOR_IOC_DISABLE_SPI_CLK _IOWR(FPSENSOR_IOC_MAGIC,6,uint32_t)
|
||||
#define FPSENSOR_IOC_ENABLE_SPI_CLK _IOWR(FPSENSOR_IOC_MAGIC,7,uint32_t)
|
||||
#define FPSENSOR_IOC_ENABLE_POWER _IOWR(FPSENSOR_IOC_MAGIC,8,uint32_t)
|
||||
#define FPSENSOR_IOC_DISABLE_POWER _IOWR(FPSENSOR_IOC_MAGIC,9,uint32_t)
|
||||
/* fp sensor has change to sleep mode while screen off */
|
||||
#define FPSENSOR_IOC_ENTER_SLEEP_MODE _IOWR(FPSENSOR_IOC_MAGIC,11,uint32_t)
|
||||
#define FPSENSOR_IOC_REMOVE _IOWR(FPSENSOR_IOC_MAGIC,12,uint32_t)
|
||||
#define FPSENSOR_IOC_CANCEL_WAIT _IOWR(FPSENSOR_IOC_MAGIC,13,uint32_t)
|
||||
#define FPSENSOR_IOC_GET_FP_STATUS _IOWR(FPSENSOR_IOC_MAGIC,19,uint32_t)
|
||||
#define FPSENSOR_IOC_ENABLE_REPORT_BLANKON _IOWR(FPSENSOR_IOC_MAGIC,21,uint32_t)
|
||||
#define FPSENSOR_IOC_UPDATE_DRIVER_SN _IOWR(FPSENSOR_IOC_MAGIC,22,uint32_t)
|
||||
typedef struct {
|
||||
dev_t devno;
|
||||
struct class *class;
|
||||
struct cdev cdev;
|
||||
struct platform_device *spi;
|
||||
unsigned int users;
|
||||
u8 device_available; /* changed during fingerprint chip sleep and wakeup phase */
|
||||
u8 irq_enabled;
|
||||
volatile unsigned int RcvIRQ;
|
||||
int irq;
|
||||
int irq_gpio;
|
||||
int reset_gpio;
|
||||
int power_gpio;
|
||||
wait_queue_head_t wq_irq_return;
|
||||
int cancel;
|
||||
struct notifier_block notifier;
|
||||
u8 fb_status;
|
||||
int enable_report_blankon;
|
||||
int free_flag;
|
||||
} fpsensor_data_t;
|
||||
|
||||
#endif /* __FPSENSOR_SPI_TEE_H */
|
||||
68
drivers/input/misc/chipone_fps_mmi/fpsensor_wakelock.h
Normal file
68
drivers/input/misc/chipone_fps_mmi/fpsensor_wakelock.h
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/* include/linux/wakelock.h
|
||||
*
|
||||
* Copyright (C) 2007-2012 Google, Inc.
|
||||
*
|
||||
* 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 _BF_FP_WAKELOCK_H
|
||||
#define _BF_FP_WAKELOCK_H
|
||||
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
/* A wake_lock prevents the system from entering suspend or other low power
|
||||
* states when active. If the type is set to WAKE_LOCK_SUSPEND, the wake_lock
|
||||
* prevents a full system suspend.
|
||||
*/
|
||||
|
||||
enum {
|
||||
WAKE_LOCK_SUSPEND, /* Prevent suspend */
|
||||
WAKE_LOCK_TYPE_COUNT
|
||||
};
|
||||
|
||||
struct wake_lock {
|
||||
struct wakeup_source ws;
|
||||
};
|
||||
|
||||
static inline void wake_lock_init(struct wake_lock *lock, int type,
|
||||
const char *name)
|
||||
{
|
||||
wakeup_source_init(&lock->ws, name);
|
||||
}
|
||||
|
||||
static inline void wake_lock_destroy(struct wake_lock *lock)
|
||||
{
|
||||
wakeup_source_trash(&lock->ws);
|
||||
}
|
||||
|
||||
static inline void wake_lock(struct wake_lock *lock)
|
||||
{
|
||||
__pm_stay_awake(&lock->ws);
|
||||
}
|
||||
|
||||
static inline void wake_lock_timeout(struct wake_lock *lock, long timeout)
|
||||
{
|
||||
__pm_wakeup_event(&lock->ws, jiffies_to_msecs(timeout));
|
||||
}
|
||||
|
||||
static inline void wake_unlock(struct wake_lock *lock)
|
||||
{
|
||||
__pm_relax(&lock->ws);
|
||||
}
|
||||
|
||||
static inline int wake_lock_active(struct wake_lock *lock)
|
||||
{
|
||||
return lock->ws.active;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Loading…
Reference in a new issue