mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-10 14:19:09 -04:00
dlkm: Add focaltech fps module
Add focaltech fps module to bring up side fps FT9391. Change-Id: I52a4b1a328a7e7135ab8743cdad76c513a4ff9eb Signed-off-by: Yan Zhang <zhangy26@motorola.com> Reviewed-on: https://gerrit.mot.com/2085146 SME-Granted: SME Approvals Granted SLTApproved: Slta Waiver Tested-by: Jira Key Reviewed-by: Xiangpo Zhao <zhaoxp3@motorola.com> Submit-Approved: Jira Key
This commit is contained in:
parent
690f92f0f4
commit
da19276c28
8 changed files with 1321 additions and 0 deletions
16
drivers/input/misc/focal_fps_mmi/Android.mk
Normal file
16
drivers/input/misc/focal_fps_mmi/Android.mk
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
DLKM_DIR := motorola/kernel/modules
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
ifeq ($(DLKM_INSTALL_TO_VENDOR_OUT),true)
|
||||
FOCAL_FPS_MMI_MODULE_PATH := $(TARGET_OUT_VENDOR)/lib/modules/
|
||||
else
|
||||
FOCAL_FPS_MMI_MODULE_PATH := $(KERNEL_MODULES_OUT)
|
||||
endif
|
||||
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := focal_fps_mmi.ko
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_MODULE_PATH := $(FOCAL_FPS_MMI_MODULE_PATH)
|
||||
include $(DLKM_DIR)/AndroidKernelModule.mk
|
||||
|
||||
41
drivers/input/misc/focal_fps_mmi/Kbuild
Normal file
41
drivers/input/misc/focal_fps_mmi/Kbuild
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
# add -Wall to try to catch everything we can.
|
||||
EXTRA_CFLAGS += -Wall
|
||||
EXTRA_CFLAGS += -I$(ANDROID_BUILD_TOP)/motorola/kernel/modules/include \
|
||||
-I$(ANDROID_BUILD_TOP)/motorola/kernel/modules/drivers/input/misc/focal_fps_mmi
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Early-logging level for ff_hal, ff_ta and driver as well. Note that this
|
||||
# logging level only takes effect before ff_config module is loaded.
|
||||
#
|
||||
# Options:
|
||||
# 0 - FF_LOG_LEVEL_ALL, All
|
||||
# 1 - FF_LOG_LEVEL_VBS, Verbose
|
||||
# 2 - FF_LOG_LEVEL_DBG, Debug
|
||||
# 3 - FF_LOG_LEVEL_INF, Info
|
||||
# 4 - FF_LOG_LEVEL_WRN, Warning
|
||||
# 5 - FF_LOG_LEVEL_ERR, Error
|
||||
EXTRA_CFLAGS += -D__FF_BUILD_DATE=\"$(shell date +%Y%m%d)\"
|
||||
EXTRA_CFLAGS += -D__FF_EARLY_LOG_LEVEL=2
|
||||
|
||||
|
||||
focal_fps_mmi-y += ff_ctl.o plat-msm.o
|
||||
|
||||
ifneq ($(filter m y,$(CONFIG_INPUT_EGISTEC_FPS_NAVI)),)
|
||||
EXTRA_CFLAGS += -DCONFIG_INPUT_EGISTEC_FPS_NAVI
|
||||
ets_fps_mmi-y += ets_navi_input.o
|
||||
endif
|
||||
ifneq ($(filter m y,$(CONFIG_INPUT_EGISTEC_FPS_NAVI_VERTICAL)),)
|
||||
EXTRA_CFLAGS += -DCONFIG_INPUT_EGISTEC_FPS_NAVI_VERTICAL
|
||||
endif
|
||||
ifeq ($(TARGET_BUILD_VARIANT),userdebug)
|
||||
EXTRA_CFLAGS += -DFP_SPI_DEBUG
|
||||
endif
|
||||
|
||||
obj-m += focal_fps_mmi.o
|
||||
|
||||
|
||||
13
drivers/input/misc/focal_fps_mmi/Makefile
Normal file
13
drivers/input/misc/focal_fps_mmi/Makefile
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
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
|
||||
|
||||
|
||||
|
||||
737
drivers/input/misc/focal_fps_mmi/ff_ctl.c
Normal file
737
drivers/input/misc/focal_fps_mmi/ff_ctl.c
Normal file
|
|
@ -0,0 +1,737 @@
|
|||
/**
|
||||
* The device control driver for FocalTech's fingerprint sensor.
|
||||
*
|
||||
* Copyright (C) 2016-2017 FocalTech Systems Co., Ltd. All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* 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.
|
||||
**/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/bug.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/param.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/notifier.h>
|
||||
#if 0
|
||||
#ifdef CONFIG_PM_WAKELOCKS
|
||||
#include <linux/pm_wakeup.h>
|
||||
#else
|
||||
#include <linux/wakelock.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
#include <linux/compat.h>
|
||||
#endif
|
||||
|
||||
#include "ff_log.h"
|
||||
#include "ff_err.h"
|
||||
#include "ff_ctl.h"
|
||||
|
||||
/*
|
||||
* Define the driver version string.
|
||||
*/
|
||||
#define FF_DRV_VERSION "v2.1.2"
|
||||
|
||||
/*
|
||||
* Define the driver name.
|
||||
*/
|
||||
#define FF_DRV_NAME "focaltech_fp"
|
||||
|
||||
/*
|
||||
* Driver context definition and its singleton instance.
|
||||
*/
|
||||
typedef struct {
|
||||
struct miscdevice miscdev;
|
||||
int irq_num;
|
||||
struct work_struct work_queue;
|
||||
struct fasync_struct *async_queue;
|
||||
struct input_dev *input;
|
||||
struct notifier_block fb_notifier;
|
||||
#if 0
|
||||
struct wakeup_source *wake_lock;
|
||||
//#else
|
||||
struct wake_lock *wake_lock;
|
||||
#endif
|
||||
bool b_driver_inited;
|
||||
bool b_config_dirtied;
|
||||
} ff_ctl_context_t;
|
||||
static ff_ctl_context_t *g_context = NULL;
|
||||
|
||||
/*
|
||||
* Driver configuration.
|
||||
*/
|
||||
static ff_driver_config_t driver_config;
|
||||
ff_driver_config_t *g_config = NULL;
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// Logging driver to logcat through uevent mechanism.
|
||||
|
||||
# undef LOG_TAG
|
||||
#define LOG_TAG "ff_ctl"
|
||||
|
||||
/*
|
||||
* Log level can be runtime configurable by 'FF_IOC_SYNC_CONFIG'.
|
||||
*/
|
||||
ff_log_level_t g_log_level = 3;//__FF_EARLY_LOG_LEVEL;
|
||||
#define MAX_UP_TIME (1 * MSEC_PER_SEC)
|
||||
int ff_log_printf(ff_log_level_t level, const char *tag, const char *fmt, ...)
|
||||
{
|
||||
/* Prepare the storage. */
|
||||
va_list ap;
|
||||
static char uevent_env_buf[128];
|
||||
char *ptr = uevent_env_buf;
|
||||
int n, available = sizeof(uevent_env_buf);
|
||||
|
||||
/* Fill logging level. */
|
||||
available -= sprintf(uevent_env_buf, "FF_LOG=%1d", level);
|
||||
ptr += strlen(uevent_env_buf);
|
||||
|
||||
/* Fill logging message. */
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(ptr, available, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
/* Send to ff_device. */
|
||||
if (likely(g_context) && likely(g_config) && unlikely(g_config->logcat_driver)) {
|
||||
char *uevent_env[2] = {uevent_env_buf, NULL};
|
||||
kobject_uevent_env(&g_context->miscdev.this_device->kobj, KOBJ_CHANGE, uevent_env);
|
||||
}
|
||||
|
||||
/* Native output. */
|
||||
switch (level) {
|
||||
case FF_LOG_LEVEL_ERR:
|
||||
n = printk(KERN_ERR FF_DRV_NAME": %s\n", ptr);
|
||||
break;
|
||||
case FF_LOG_LEVEL_WRN:
|
||||
n = printk(KERN_WARNING FF_DRV_NAME": %s\n", ptr);
|
||||
break;
|
||||
case FF_LOG_LEVEL_INF:
|
||||
n = printk(KERN_INFO FF_DRV_NAME": %s\n", ptr);
|
||||
break;
|
||||
case FF_LOG_LEVEL_DBG:
|
||||
case FF_LOG_LEVEL_VBS:
|
||||
default:
|
||||
n = printk(KERN_DEBUG FF_DRV_NAME": %s\n", ptr);
|
||||
break;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
const char *ff_err_strerror(int err)
|
||||
{
|
||||
static char errstr[32] = {'\0', };
|
||||
|
||||
switch (err) {
|
||||
case FF_SUCCESS : return "Success";
|
||||
case FF_ERR_INTERNAL: return "Internal error";
|
||||
|
||||
/* Base on unix errno. */
|
||||
case FF_ERR_NOENT: return "No such file or directory";
|
||||
case FF_ERR_INTR : return "Interrupted";
|
||||
case FF_ERR_IO : return "I/O error";
|
||||
case FF_ERR_AGAIN: return "Try again";
|
||||
case FF_ERR_NOMEM: return "Out of memory";
|
||||
case FF_ERR_BUSY : return "Resource busy / Timeout";
|
||||
|
||||
/* Common error. */
|
||||
case FF_ERR_BAD_PARAMS : return "Bad parameter(s)";
|
||||
case FF_ERR_NULL_PTR : return "Null pointer";
|
||||
case FF_ERR_BUF_OVERFLOW: return "Buffer overflow";
|
||||
case FF_ERR_BAD_PROTOCOL: return "Bad protocol";
|
||||
case FF_ERR_SENSOR_SIZE : return "Wrong sensor dimension";
|
||||
case FF_ERR_NULL_DEVICE : return "Device not found";
|
||||
case FF_ERR_DEAD_DEVICE : return "Device is dead";
|
||||
case FF_ERR_REACH_LIMIT : return "Up to the limit";
|
||||
case FF_ERR_REE_TEMPLATE: return "Template store in REE";
|
||||
case FF_ERR_NOT_TRUSTED : return "Untrusted enrollment";
|
||||
|
||||
default:
|
||||
sprintf(errstr, "%d", err);
|
||||
break;
|
||||
}
|
||||
|
||||
return (const char *)errstr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/* See plat-xxxx.c for platform dependent implementation. */
|
||||
extern int ff_ctl_init_pins(int *irq_num);
|
||||
extern int ff_ctl_free_pins(void);
|
||||
#ifdef FF_SPI_SET
|
||||
extern int ff_ctl_enable_spiclk(bool on);
|
||||
#endif
|
||||
extern int ff_ctl_enable_power(bool on);
|
||||
extern int ff_ctl_reset_device(void);
|
||||
extern const char *ff_ctl_arch_str(void);
|
||||
|
||||
|
||||
#ifdef CHIP_TYPE_FT9304
|
||||
/* See chip-xxxx.c for chip dependent implementation. */
|
||||
extern int ff_chip_init(void);
|
||||
#endif
|
||||
|
||||
static int ff_ctl_enable_irq(bool on)
|
||||
{
|
||||
int err = 0;
|
||||
FF_LOGV("'%s' enter.", __func__);
|
||||
FF_LOGD("irq: '%s'.", on ? "enable" : "disabled");
|
||||
|
||||
if (unlikely(!g_context)) {
|
||||
return (-ENOSYS);
|
||||
}
|
||||
|
||||
if (on) {
|
||||
enable_irq(g_context->irq_num);
|
||||
} else {
|
||||
disable_irq(g_context->irq_num);
|
||||
}
|
||||
|
||||
FF_LOGV("'%s' leave.", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void ff_ctl_device_event(struct work_struct *ws)
|
||||
{
|
||||
ff_ctl_context_t *ctx = container_of(ws, ff_ctl_context_t, work_queue);
|
||||
char *uevent_env[2] = {"FF_INTERRUPT", NULL};
|
||||
FF_LOGV("'%s' enter.", __func__);
|
||||
|
||||
FF_LOGD("%s(irq = %d, ..) toggled.", __func__, ctx->irq_num);
|
||||
#if 0
|
||||
__pm_wakeup_event(g_context->wake_lock, jiffies_to_msecs(2*HZ));
|
||||
//#else
|
||||
wake_lock_timeout(g_context->wake_lock, 2 * HZ); // 2 seconds.
|
||||
#endif
|
||||
pm_wakeup_event(g_context->miscdev.this_device, MAX_UP_TIME);
|
||||
kobject_uevent_env(&ctx->miscdev.this_device->kobj, KOBJ_CHANGE, uevent_env);
|
||||
|
||||
FF_LOGV("'%s' leave.", __func__);
|
||||
}
|
||||
|
||||
static irqreturn_t ff_ctl_device_irq(int irq, void *dev_id)
|
||||
{
|
||||
ff_ctl_context_t *ctx = (ff_ctl_context_t *)dev_id;
|
||||
disable_irq_nosync(irq);
|
||||
|
||||
if (likely(irq == ctx->irq_num)) {
|
||||
if (g_config && g_config->enable_fasync && g_context->async_queue) {
|
||||
kill_fasync(&g_context->async_queue, SIGIO, POLL_IN);
|
||||
} else {
|
||||
schedule_work(&ctx->work_queue);
|
||||
}
|
||||
}
|
||||
|
||||
enable_irq(irq);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int ff_ctl_report_key_event(struct input_dev *input, ff_key_event_t *kevent)
|
||||
{
|
||||
int err = 0;
|
||||
FF_LOGV("'%s' enter.", __func__);
|
||||
|
||||
input_report_key(input, kevent->code, kevent->value);
|
||||
input_sync(input);
|
||||
|
||||
FF_LOGV("'%s' leave.", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
static const char *ff_ctl_get_version(void)
|
||||
{
|
||||
static char version[FF_DRV_VERSION_LEN] = {'\0', };
|
||||
FF_LOGV("'%s' enter.", __func__);
|
||||
|
||||
/* Version info. */
|
||||
version[0] = '\0';
|
||||
strcat(version, FF_DRV_VERSION);
|
||||
#ifdef __FF_SVN_REV
|
||||
if (strlen(__FF_SVN_REV) > 0) {
|
||||
sprintf(version, "%s-r%s", version, __FF_SVN_REV);
|
||||
}
|
||||
#endif
|
||||
#ifdef __FF_BUILD_DATE
|
||||
strcat(version, "-"__FF_BUILD_DATE);
|
||||
#endif
|
||||
sprintf(version, "%s-%s", version, ff_ctl_arch_str());
|
||||
FF_LOGD("version: '%s'.", version);
|
||||
|
||||
FF_LOGV("'%s' leave.", __func__);
|
||||
return (const char *)version;
|
||||
}
|
||||
static char screen_state[1];
|
||||
static int ff_ctl_fb_notifier_callback(struct notifier_block *nb, unsigned long action, void *data)
|
||||
{
|
||||
struct fb_event *event;
|
||||
int blank;
|
||||
char *uevent_env[2];
|
||||
|
||||
/* If we aren't interested in this event, skip it immediately ... */
|
||||
if (action != FB_EVENT_BLANK /* FB_EARLY_EVENT_BLANK */) {
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
FF_LOGV("'%s' enter.", __func__);
|
||||
|
||||
event = (struct fb_event *)data;
|
||||
blank = *(int *)event->data;
|
||||
|
||||
switch (blank) {
|
||||
case FB_BLANK_UNBLANK:
|
||||
uevent_env[0] = "FF_SCREEN_ON";
|
||||
screen_state[0] = 0;
|
||||
break;
|
||||
case FB_BLANK_POWERDOWN:
|
||||
uevent_env[0] = "FF_SCREEN_OFF";
|
||||
screen_state[0] = 1;
|
||||
break;
|
||||
default:
|
||||
uevent_env[0] = "FF_SCREEN_??";
|
||||
break;
|
||||
}
|
||||
uevent_env[1] = NULL;
|
||||
// kobject_uevent_env(&g_context->miscdev.this_device->kobj, KOBJ_CHANGE, uevent_env);
|
||||
kill_fasync(&g_context->async_queue, SIGIO, POLL_IN);
|
||||
|
||||
FF_LOGV("'%s' leave.", __func__);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static int ff_ctl_register_input(void)
|
||||
{
|
||||
int err = 0;
|
||||
FF_LOGV("'%s' enter.", __func__);
|
||||
|
||||
/* Allocate the input device. */
|
||||
g_context->input = input_allocate_device();
|
||||
if (!g_context->input) {
|
||||
FF_LOGE("input_allocate_device() failed.");
|
||||
return (-ENOMEM);
|
||||
}
|
||||
|
||||
/* Register the key event capabilities. */
|
||||
if (g_config) {
|
||||
input_set_capability(g_context->input, EV_KEY, g_config->keycode_nav_left );
|
||||
input_set_capability(g_context->input, EV_KEY, g_config->keycode_nav_right );
|
||||
input_set_capability(g_context->input, EV_KEY, g_config->keycode_nav_up );
|
||||
input_set_capability(g_context->input, EV_KEY, g_config->keycode_nav_down );
|
||||
input_set_capability(g_context->input, EV_KEY, g_config->keycode_double_click);
|
||||
input_set_capability(g_context->input, EV_KEY, g_config->keycode_click );
|
||||
input_set_capability(g_context->input, EV_KEY, g_config->keycode_long_press );
|
||||
input_set_capability(g_context->input, EV_KEY, g_config->keycode_simulation );
|
||||
}
|
||||
|
||||
/* Register the allocated input device. */
|
||||
g_context->input->name = "uinput-focal";
|
||||
err = input_register_device(g_context->input);
|
||||
if (err) {
|
||||
FF_LOGE("input_register_device(..) = %d.", err);
|
||||
input_free_device(g_context->input);
|
||||
g_context->input = NULL;
|
||||
return (-ENODEV);
|
||||
}
|
||||
|
||||
FF_LOGV("'%s' leave.", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ff_ctl_free_driver(void)
|
||||
{
|
||||
int err = 0;
|
||||
FF_LOGV("'%s' enter.", __func__);
|
||||
|
||||
/* Unregister framebuffer event notifier. */
|
||||
err = fb_unregister_client(&g_context->fb_notifier);
|
||||
|
||||
#ifdef FF_SPI_SET
|
||||
/* Disable SPI clock. */
|
||||
err = ff_ctl_enable_spiclk(0);
|
||||
#endif
|
||||
|
||||
/* Disable the fingerprint module's power. */
|
||||
err = ff_ctl_enable_power(0);
|
||||
|
||||
#ifdef FF_SPI_SET
|
||||
/* Unregister the spidev device. */
|
||||
err = ff_spi_free();
|
||||
#endif
|
||||
|
||||
/* De-initialize the input subsystem. */
|
||||
if (g_context->input) {
|
||||
/*
|
||||
* Once input device was registered use input_unregister_device() and
|
||||
* memory will be freed once last reference to the device is dropped.
|
||||
*/
|
||||
input_unregister_device(g_context->input);
|
||||
g_context->input = NULL;
|
||||
}
|
||||
|
||||
/* Release IRQ resource. */
|
||||
if (g_context->irq_num > 0) {
|
||||
err = disable_irq_wake(g_context->irq_num);
|
||||
if (err) {
|
||||
FF_LOGE("disable_irq_wake(%d) = %d.", g_context->irq_num, err);
|
||||
}
|
||||
free_irq(g_context->irq_num, (void*)g_context);
|
||||
g_context->irq_num = -1;
|
||||
}
|
||||
|
||||
/* Release pins resource. */
|
||||
err = ff_ctl_free_pins();
|
||||
|
||||
FF_LOGV("'%s' leave.", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ff_ctl_init_driver(void)
|
||||
{
|
||||
int err = 0;
|
||||
FF_LOGV("'%s' enter.", __func__);
|
||||
|
||||
if (unlikely(!g_context)) {
|
||||
return (-ENOSYS);
|
||||
}
|
||||
|
||||
do {
|
||||
/* Initialize the PWR/SPI/RST/INT pins resource. */
|
||||
err = ff_ctl_init_pins(&g_context->irq_num);
|
||||
if (err > 0) {
|
||||
g_context->b_config_dirtied = true;
|
||||
} else \
|
||||
if (err) {
|
||||
FF_LOGE("ff_ctl_init_pins(..) = %d.", err);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Register IRQ. */
|
||||
err = request_irq(g_context->irq_num, ff_ctl_device_irq,
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT, "ff_irq", (void*)g_context);
|
||||
if (err) {
|
||||
FF_LOGE("request_irq(..) = %d.", err);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Wake up the system while receiving the interrupt. */
|
||||
err = enable_irq_wake(g_context->irq_num);
|
||||
if (err) {
|
||||
FF_LOGE("enable_irq_wake(%d) = %d.", g_context->irq_num, err);
|
||||
}
|
||||
|
||||
/* Register spidev device. For REE-Emulation solution only. */
|
||||
if (g_config && g_config->enable_spidev) {
|
||||
#ifdef FF_SPI_SET
|
||||
err = ff_spi_init();
|
||||
if (err) {
|
||||
FF_LOGE("ff_spi_init(..) = %d.", err);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} while (0);
|
||||
|
||||
if (err) {
|
||||
ff_ctl_free_driver();
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Initialize the input subsystem. */
|
||||
err = ff_ctl_register_input();
|
||||
if (err) {
|
||||
FF_LOGE("ff_ctl_init_input() = %d.", err);
|
||||
//return err;
|
||||
}
|
||||
|
||||
/* Enable the fingerprint module's power at system startup. */
|
||||
err = ff_ctl_enable_power(1);
|
||||
|
||||
#ifdef FF_SPI_SET
|
||||
/* Enable SPI clock. */
|
||||
err = ff_ctl_enable_spiclk(1);
|
||||
#endif
|
||||
|
||||
/* Register screen on/off callback. */
|
||||
g_context->fb_notifier.notifier_call = ff_ctl_fb_notifier_callback;
|
||||
err = fb_register_client(&g_context->fb_notifier);
|
||||
|
||||
|
||||
g_context->b_driver_inited = true;
|
||||
FF_LOGV("'%s' leave.", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// struct file_operations fields.
|
||||
|
||||
static int ff_ctl_fasync(int fd, struct file *filp, int mode)
|
||||
{
|
||||
int err = 0;
|
||||
FF_LOGV("'%s' enter.", __func__);
|
||||
|
||||
FF_LOGD("%s: mode = 0x%08x.", __func__, mode);
|
||||
err = fasync_helper(fd, filp, mode, &g_context->async_queue);
|
||||
|
||||
FF_LOGV("'%s' leave.", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
static long ff_ctl_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
int err = 0;
|
||||
struct miscdevice *dev = (struct miscdevice *)filp->private_data;
|
||||
ff_ctl_context_t *ctx = container_of(dev, ff_ctl_context_t, miscdev);
|
||||
FF_LOGV("'%s' enter.", __func__);
|
||||
|
||||
#if 1
|
||||
if (g_log_level <= FF_LOG_LEVEL_DBG) {
|
||||
static const char *cmd_names[] = {
|
||||
"FF_IOC_INIT_DRIVER", "FF_IOC_FREE_DRIVER",
|
||||
"FF_IOC_RESET_DEVICE",
|
||||
"FF_IOC_ENABLE_IRQ", "FF_IOC_DISABLE_IRQ",
|
||||
"FF_IOC_ENABLE_SPI_CLK", "FF_IOC_DISABLE_SPI_CLK",
|
||||
"FF_IOC_ENABLE_POWER", "FF_IOC_DISABLE_POWER",
|
||||
"FF_IOC_REPORT_KEY_EVENT", "FF_IOC_SYNC_CONFIG",
|
||||
"FF_IOC_GET_VERSION", "unknown",
|
||||
};
|
||||
unsigned int _cmd = _IOC_NR(cmd);
|
||||
if (_cmd > FF_IOC_GET_VERSION) {
|
||||
_cmd = FF_IOC_GET_VERSION + 1;
|
||||
}
|
||||
FF_LOGD("%s(.., %s, ..) invoke.", __func__, cmd_names[_cmd]);
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (cmd) {
|
||||
case FF_IOC_INIT_DRIVER: {
|
||||
if (g_context->b_driver_inited) {
|
||||
err = ff_ctl_free_driver();
|
||||
}
|
||||
if (!err) {
|
||||
err = ff_ctl_init_driver();
|
||||
// TODO: Sync the dirty configuration back to HAL.
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FF_IOC_FREE_DRIVER:
|
||||
if (g_context->b_driver_inited) {
|
||||
err = ff_ctl_free_driver();
|
||||
g_context->b_driver_inited = false;
|
||||
}
|
||||
break;
|
||||
case FF_IOC_RESET_DEVICE:
|
||||
err = ff_ctl_reset_device();
|
||||
break;
|
||||
case FF_IOC_ENABLE_IRQ:
|
||||
err = ff_ctl_enable_irq(1);
|
||||
break;
|
||||
case FF_IOC_DISABLE_IRQ:
|
||||
err = ff_ctl_enable_irq(0);
|
||||
break;
|
||||
case FF_IOC_ENABLE_SPI_CLK:
|
||||
#ifdef FF_SPI_SET
|
||||
err = ff_ctl_enable_spiclk(1);
|
||||
#endif
|
||||
break;
|
||||
case FF_IOC_DISABLE_SPI_CLK:
|
||||
#ifdef FF_SPI_SET
|
||||
err = ff_ctl_enable_spiclk(0);
|
||||
#endif
|
||||
break;
|
||||
case FF_IOC_ENABLE_POWER:
|
||||
err = ff_ctl_enable_power(1);
|
||||
break;
|
||||
case FF_IOC_DISABLE_POWER:
|
||||
err = ff_ctl_enable_power(0);
|
||||
break;
|
||||
case FF_IOC_REPORT_KEY_EVENT: {
|
||||
ff_key_event_t kevent;
|
||||
if (copy_from_user(&kevent, (ff_key_event_t *)arg, sizeof(ff_key_event_t))) {
|
||||
FF_LOGE("copy_from_user(..) failed.");
|
||||
err = (-EFAULT);
|
||||
break;
|
||||
}
|
||||
err = ff_ctl_report_key_event(ctx->input, &kevent);
|
||||
break;
|
||||
}
|
||||
case FF_IOC_SYNC_CONFIG: {
|
||||
if (copy_from_user(&driver_config, (ff_driver_config_t *)arg, sizeof(ff_driver_config_t))) {
|
||||
FF_LOGE("copy_from_user(..) failed.");
|
||||
err = (-EFAULT);
|
||||
break;
|
||||
}
|
||||
g_config = &driver_config;
|
||||
|
||||
/* Take logging level effect. */
|
||||
g_log_level = 3;//g_config->log_level;
|
||||
break;
|
||||
}
|
||||
case FF_IOC_GET_VERSION: {
|
||||
if (copy_to_user((void *)arg, ff_ctl_get_version(), FF_DRV_VERSION_LEN)) {
|
||||
FF_LOGE("copy_to_user(..) failed.");
|
||||
err = (-EFAULT);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FF_IOC_GET_SCREEN_STATE: {
|
||||
if (copy_to_user((void *)arg, (const char*)screen_state, 1)) {
|
||||
FF_LOGE("copy_to_user(..) failed.");
|
||||
err = (-EFAULT);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
err = (-EINVAL);
|
||||
break;
|
||||
}
|
||||
|
||||
FF_LOGV("'%s' leave.", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ff_ctl_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
FF_LOGD("'%s' nothing to do.", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ff_ctl_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
int err = 0;
|
||||
FF_LOGV("'%s' enter.", __func__);
|
||||
|
||||
/* Remove this filp from the asynchronously notified filp's. */
|
||||
err = ff_ctl_fasync(-1, filp, 0);
|
||||
|
||||
FF_LOGV("'%s' leave.", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
static long ff_ctl_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
int err = 0;
|
||||
FF_LOGV("focal '%s' enter.\n", __func__);
|
||||
|
||||
err = ff_ctl_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
|
||||
|
||||
FF_LOGV("'%s' leave.", __func__);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static struct file_operations ff_ctl_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.fasync = ff_ctl_fasync,
|
||||
.unlocked_ioctl = ff_ctl_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = ff_ctl_compat_ioctl,
|
||||
#endif
|
||||
.open = ff_ctl_open,
|
||||
.release = ff_ctl_release,
|
||||
};
|
||||
|
||||
static ff_ctl_context_t ff_ctl_context = {
|
||||
.miscdev = {
|
||||
.minor = MISC_DYNAMIC_MINOR,
|
||||
.name = FF_DRV_NAME,
|
||||
.fops = &ff_ctl_fops,
|
||||
}, 0,
|
||||
};
|
||||
|
||||
static int __init ff_ctl_driver_init(void)
|
||||
{
|
||||
int err = 0;
|
||||
FF_LOGV("'%s' enter.", __func__);
|
||||
|
||||
/* Register as a miscellaneous device. */
|
||||
err = misc_register(&ff_ctl_context.miscdev);
|
||||
if (err) {
|
||||
FF_LOGE("misc_register(..) = %d.", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Init the interrupt workqueue. */
|
||||
INIT_WORK(&ff_ctl_context.work_queue, ff_ctl_device_event);
|
||||
|
||||
#if 0
|
||||
ff_ctl_context.wake_lock = wakeup_source_create("ff_wake_lock");
|
||||
if (!ff_ctl_context.wake_lock) {
|
||||
FF_LOGE("wakeup_source_create failed.");
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
wakeup_source_add(ff_ctl_context.wake_lock);
|
||||
}
|
||||
//#else
|
||||
wake_lock_init(ff_ctl_context.wake_lock, WAKE_LOCK_SUSPEND, "ff_wake_lock");
|
||||
#endif
|
||||
|
||||
/* Assign the context instance. */
|
||||
g_context = &ff_ctl_context;
|
||||
|
||||
g_context->b_driver_inited = false;
|
||||
/* Init the wake lock. */
|
||||
err = device_init_wakeup(g_context->miscdev.this_device, true);
|
||||
FF_LOGI("FocalTech fingerprint device control driver registered err=%d.", err);
|
||||
FF_LOGV("'%s' leave.", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit ff_ctl_driver_exit(void)
|
||||
{
|
||||
int err = 0;
|
||||
FF_LOGV("'%s' enter.", __func__);
|
||||
|
||||
/* Release the HW resources if needs. */
|
||||
if (g_context->b_driver_inited) {
|
||||
err = ff_ctl_free_driver();
|
||||
g_context->b_driver_inited = false;
|
||||
}
|
||||
|
||||
/* De-init the wake lock. */
|
||||
err = device_init_wakeup(g_context->miscdev.this_device, false);
|
||||
#if 0
|
||||
wakeup_source_destroy(g_context->wake_lock);
|
||||
//#else
|
||||
wake_lock_destroy(g_context->wake_lock);
|
||||
#endif
|
||||
|
||||
/* Unregister the miscellaneous device. */
|
||||
misc_deregister(&g_context->miscdev);
|
||||
|
||||
/* 'g_context' could not use any more. */
|
||||
g_context = NULL;
|
||||
|
||||
FF_LOGI("FocalTech fingerprint device control driver released.");
|
||||
FF_LOGV("'%s' leave.", __func__);
|
||||
}
|
||||
|
||||
module_init(ff_ctl_driver_init);
|
||||
module_exit(ff_ctl_driver_exit);
|
||||
|
||||
MODULE_DESCRIPTION("The device control driver for FocalTech's fingerprint sensor.");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
MODULE_AUTHOR("FocalTech Fingerprint R&D department");
|
||||
|
||||
118
drivers/input/misc/focal_fps_mmi/ff_ctl.h
Normal file
118
drivers/input/misc/focal_fps_mmi/ff_ctl.h
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/**
|
||||
* User space driver API for FocalTech's fingerprint device.
|
||||
* ATTENTION: Do NOT edit this file unless the corresponding driver changed.
|
||||
*
|
||||
* Copyright (C) 2016-2017 FocalTech Systems Co., Ltd. All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* 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 __FF_CTRL_API_H__
|
||||
#define __FF_CTRL_API_H__
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
|
||||
/* Device node. */
|
||||
#define FF_CTL_DEV_NAME "/dev/focaltech_fp"
|
||||
|
||||
/* Max driver version buffer length. */
|
||||
#define FF_DRV_VERSION_LEN 32
|
||||
|
||||
/* set chip type */
|
||||
/*
|
||||
#define CHIP_TYPE_FT9304
|
||||
*/
|
||||
#define CHIP_TYPE_MSM
|
||||
|
||||
/* set spi */
|
||||
//#define FF_SPI_SET
|
||||
|
||||
/* set vdd gpio */
|
||||
//#define FF_VDD_GPIO
|
||||
|
||||
/* set iovcc gpio */
|
||||
//#define FF_IOVCC_GPIO
|
||||
|
||||
typedef struct {
|
||||
unsigned int code;
|
||||
int value;
|
||||
} ff_key_event_t;
|
||||
|
||||
typedef struct {
|
||||
/* Using asynchronous notification mechanism instead of NETLINK. */
|
||||
bool enable_fasync;
|
||||
|
||||
/* Gesture(Key emulation & Navigation) key codes. */
|
||||
int32_t keycode_nav_left;
|
||||
int32_t keycode_nav_right;
|
||||
int32_t keycode_nav_up;
|
||||
int32_t keycode_nav_down;
|
||||
int32_t keycode_double_click;
|
||||
int32_t keycode_click;
|
||||
int32_t keycode_long_press;
|
||||
int32_t keycode_simulation;
|
||||
|
||||
/* For '/dev/spidevB.C' of REE-Emulation. */
|
||||
bool enable_spidev;
|
||||
int32_t spidev_bus;
|
||||
int32_t spidev_c_s;
|
||||
|
||||
/* For obsolete driver that doesn't support device tree. */
|
||||
int32_t gpio_mosi_pin;
|
||||
int32_t gpio_miso_pin;
|
||||
int32_t gpio_ck_pin;
|
||||
int32_t gpio_cs_pin;
|
||||
int32_t gpio_rst_pin;
|
||||
int32_t gpio_int_pin;
|
||||
int32_t gpio_power_pin;
|
||||
int32_t gpio_iovcc_pin;
|
||||
|
||||
|
||||
/* Logging driver to logcat through uevent mechanism. */
|
||||
int32_t log_level;
|
||||
bool logcat_driver;
|
||||
} ff_driver_config_t;
|
||||
|
||||
/* Magic code for IOCTL-subsystem, 'f'(0x66) means '[F]ocalTech'. */
|
||||
#define FF_IOC_MAGIC 'f'
|
||||
|
||||
/* Allocate/Release driver resource (GPIO/SPI etc.). */
|
||||
#define FF_IOC_INIT_DRIVER _IO(FF_IOC_MAGIC, 0x00)
|
||||
#define FF_IOC_FREE_DRIVER _IO(FF_IOC_MAGIC, 0x01)
|
||||
|
||||
/* HW reset the fingerprint module. */
|
||||
#define FF_IOC_RESET_DEVICE _IO(FF_IOC_MAGIC, 0x02)
|
||||
|
||||
/* Low-level IRQ control. */
|
||||
#define FF_IOC_ENABLE_IRQ _IO(FF_IOC_MAGIC, 0x03)
|
||||
#define FF_IOC_DISABLE_IRQ _IO(FF_IOC_MAGIC, 0x04)
|
||||
|
||||
/* SPI bus clock control, for power-saving purpose. */
|
||||
#define FF_IOC_ENABLE_SPI_CLK _IO(FF_IOC_MAGIC, 0x05)
|
||||
#define FF_IOC_DISABLE_SPI_CLK _IO(FF_IOC_MAGIC, 0x06)
|
||||
|
||||
/* Fingerprint module power control. */
|
||||
#define FF_IOC_ENABLE_POWER _IO(FF_IOC_MAGIC, 0x07)
|
||||
#define FF_IOC_DISABLE_POWER _IO(FF_IOC_MAGIC, 0x08)
|
||||
|
||||
/* Androind system-wide key event, for navigation purpose. */
|
||||
#define FF_IOC_REPORT_KEY_EVENT _IOW(FF_IOC_MAGIC, 0x09, ff_key_event_t)
|
||||
|
||||
/* Sync 'ff_driver_config_t', the driver configuration. */
|
||||
#define FF_IOC_SYNC_CONFIG _IOWR(FF_IOC_MAGIC, 0x0a, ff_driver_config_t)
|
||||
|
||||
/* Query the driver version string. */
|
||||
#define FF_IOC_GET_VERSION _IOR(FF_IOC_MAGIC, 0x0b, const char)
|
||||
|
||||
/* get screen state. */
|
||||
#define FF_IOC_GET_SCREEN_STATE _IOR(FF_IOC_MAGIC, 0x0c, const char)
|
||||
|
||||
#endif /* __FF_CTRL_API_H__ */
|
||||
101
drivers/input/misc/focal_fps_mmi/ff_err.h
Normal file
101
drivers/input/misc/focal_fps_mmi/ff_err.h
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/**
|
||||
* ${ANDROID_BUILD_TOP}/vendor/focaltech/src/base/focaltech/ff_err.h
|
||||
*
|
||||
* Copyright (C) 2014-2017 FocalTech Systems Co., Ltd. All Rights Reserved.
|
||||
*
|
||||
**/
|
||||
|
||||
#ifndef __FF_ERROR_H__
|
||||
#define __FF_ERROR_H__
|
||||
|
||||
#include "ff_log.h" /* FF_LOGE(..) */
|
||||
|
||||
//
|
||||
// All the following macros will return while error.
|
||||
//
|
||||
|
||||
#define FF_CHECK_ERR(expr) \
|
||||
do { \
|
||||
int __e = (expr); \
|
||||
if (__e) { \
|
||||
FF_LOGE("'%s'.", ff_err_strerror(__e)); \
|
||||
return (__e); \
|
||||
} \
|
||||
} while (0)
|
||||
/* End of FF_CHECK_ERR */
|
||||
|
||||
#define FF_CHECK_PTR(ptr) \
|
||||
do { \
|
||||
if ((ptr) == NULL) { \
|
||||
FF_CHECK_ERR(FF_ERR_NULL_PTR); \
|
||||
} \
|
||||
} while (0)
|
||||
/* End of FF_CHECK_PTR */
|
||||
|
||||
#define FF_FAILURE_RETRY(expr, retry) \
|
||||
do { \
|
||||
int __e, i = 0, j = retry; \
|
||||
do { \
|
||||
__e = (expr); \
|
||||
if (!__e) break; \
|
||||
if (++i <= j) { \
|
||||
FF_LOGW("'"#expr"' failed, try again (%d/%d).", i, j); \
|
||||
} else { \
|
||||
FF_LOGE("'%s'.", ff_err_strerror(__e)); \
|
||||
return (__e); \
|
||||
} \
|
||||
} while (true); \
|
||||
} while (0)
|
||||
/* End of FF_FAILURE_RETRY */
|
||||
|
||||
typedef enum {
|
||||
FF_SUCCESS = 0, /* No error. */
|
||||
FF_ERR_INTERNAL = -1, /* Generic error. */
|
||||
|
||||
/* Base on unix errno. */
|
||||
FF_ERR_NOENT = -2,
|
||||
FF_ERR_INTR = -4,
|
||||
FF_ERR_IO = -5,
|
||||
FF_ERR_AGAIN = -11,
|
||||
FF_ERR_NOMEM = -12,
|
||||
FF_ERR_BUSY = -16,
|
||||
|
||||
/* Common error. */
|
||||
FF_ERR_BAD_PARAMS = -200,
|
||||
FF_ERR_NULL_PTR = -201,
|
||||
FF_ERR_BUF_OVERFLOW = -202,
|
||||
FF_ERR_BAD_PROTOCOL = -203,
|
||||
FF_ERR_SENSOR_SIZE = -204,
|
||||
FF_ERR_NULL_DEVICE = -205,
|
||||
FF_ERR_DEAD_DEVICE = -206,
|
||||
FF_ERR_REACH_LIMIT = -207,
|
||||
FF_ERR_REE_TEMPLATE = -208,
|
||||
FF_ERR_NOT_TRUSTED = -209,
|
||||
} ff_err_t;
|
||||
|
||||
/*
|
||||
* For some functions that don't return an int(ff_err_t) type error
|
||||
* code, 'ff_last_error' shall be set if there is an error happened.
|
||||
*/
|
||||
extern ff_err_t ff_last_error;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Return an error description string corresponding to $err.
|
||||
*
|
||||
* @params
|
||||
* err: Error number.
|
||||
*
|
||||
* @return
|
||||
* Static error description string.
|
||||
*/
|
||||
const char *ff_err_strerror(int err);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __FF_ERROR_H__ */
|
||||
109
drivers/input/misc/focal_fps_mmi/ff_log.h
Normal file
109
drivers/input/misc/focal_fps_mmi/ff_log.h
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* ${ANDROID_BUILD_TOP}/vendor/focaltech/src/base/focaltech/ff_log.h
|
||||
*
|
||||
* Copyright (C) 2014-2017 FocalTech Systems Co., Ltd. All Rights Reserved.
|
||||
*
|
||||
**/
|
||||
|
||||
#ifndef __FF_LOGGING_H__
|
||||
#define __FF_LOGGING_H__
|
||||
|
||||
/*
|
||||
* The default LOG_TAG is 'focaltech', using these two lines to define newtag.
|
||||
* # undef LOG_TAG
|
||||
* #define LOG_TAG "newtag"
|
||||
*/
|
||||
#define LOG_TAG "focaltech"
|
||||
|
||||
/*
|
||||
* Log level can be used in 'logcat <tag>[:priority]', and also be
|
||||
* used in output control while '__FF_EARLY_LOG_LEVEL' is defined.
|
||||
*/
|
||||
typedef enum {
|
||||
FF_LOG_LEVEL_ALL = 0,
|
||||
FF_LOG_LEVEL_VBS = 1, /* Verbose */
|
||||
FF_LOG_LEVEL_DBG = 2, /* Debug */
|
||||
FF_LOG_LEVEL_INF = 3, /* Info */
|
||||
FF_LOG_LEVEL_WRN = 4, /* Warning */
|
||||
FF_LOG_LEVEL_ERR = 5, /* Error */
|
||||
} ff_log_level_t;
|
||||
|
||||
/*
|
||||
* __FF_EARLY_LOG_LEVEL can be defined as compilation option.
|
||||
* default level is FF_LOG_LEVEL_ALL(all the logs will be output).
|
||||
*/
|
||||
#ifndef __FF_EARLY_LOG_LEVEL
|
||||
#define __FF_EARLY_LOG_LEVEL FF_LOG_LEVEL_ALL
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Log level can be runtime configurable.
|
||||
*/
|
||||
extern ff_log_level_t g_log_level; /* = __FF_EARLY_LOG_LEVEL */
|
||||
|
||||
/*
|
||||
* Using the following five macros for conveniently logging.
|
||||
*/
|
||||
#define FF_LOGV(...) \
|
||||
do { \
|
||||
if (g_log_level <= FF_LOG_LEVEL_VBS) { \
|
||||
ff_log_printf(FF_LOG_LEVEL_VBS, LOG_TAG, __VA_ARGS__); \
|
||||
}; \
|
||||
} while (0)
|
||||
|
||||
#define FF_LOGD(...) \
|
||||
do { \
|
||||
if (g_log_level <= FF_LOG_LEVEL_DBG) { \
|
||||
ff_log_printf(FF_LOG_LEVEL_DBG, LOG_TAG, __VA_ARGS__); \
|
||||
}; \
|
||||
} while (0)
|
||||
|
||||
#define FF_LOGI(...) \
|
||||
do { \
|
||||
if (g_log_level <= FF_LOG_LEVEL_INF) { \
|
||||
ff_log_printf(FF_LOG_LEVEL_INF, LOG_TAG, __VA_ARGS__); \
|
||||
}; \
|
||||
} while (0)
|
||||
|
||||
#define FF_LOGW(...) \
|
||||
do { \
|
||||
if (g_log_level <= FF_LOG_LEVEL_WRN) { \
|
||||
ff_log_printf(FF_LOG_LEVEL_WRN, LOG_TAG, __VA_ARGS__); \
|
||||
}; \
|
||||
} while (0)
|
||||
|
||||
#define FF_LOGE(format, ...) \
|
||||
do { \
|
||||
if (g_log_level <= FF_LOG_LEVEL_ERR) { \
|
||||
const char *__fname__ = __FILE__, *s = __fname__; \
|
||||
do { if (*s == '/') __fname__ = s + 1; } while (*s++); \
|
||||
ff_log_printf(FF_LOG_LEVEL_ERR, LOG_TAG, \
|
||||
"error at %s[%s:%d]: " format, __FUNCTION__, \
|
||||
__fname__, __LINE__, ##__VA_ARGS__); \
|
||||
}; \
|
||||
} while (0)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Logging API. Do NOT use it directly but FF_LOF* instead.
|
||||
*
|
||||
* @params
|
||||
* level: Logging level for logcat.
|
||||
* tag : Logging tag for logcat.
|
||||
* fmt : See POSIX printf(..).
|
||||
* ... : See POSIX printf(..).
|
||||
*
|
||||
* @return
|
||||
* The number of characters printed, or a negative value if there
|
||||
* was an output error.
|
||||
*/
|
||||
int ff_log_printf(ff_log_level_t level, const char *tag, const char *fmt, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __FF_LOGGING_H__ */
|
||||
186
drivers/input/misc/focal_fps_mmi/plat-msm.c
Normal file
186
drivers/input/misc/focal_fps_mmi/plat-msm.c
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
/**
|
||||
* plat-msm.c
|
||||
*
|
||||
**/
|
||||
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/bug.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
#include "ff_log.h"
|
||||
#include "ff_ctl.h"
|
||||
|
||||
# undef LOG_TAG
|
||||
#define LOG_TAG "msm"
|
||||
|
||||
#define FF_COMPATIBLE_NODE "focaltech,fingerprint"
|
||||
|
||||
/* Define pinctrl state types. */
|
||||
typedef enum {
|
||||
FF_PINCTRL_STATE_PWR_ACT,
|
||||
FF_PINCTRL_STATE_PWR_CLR,
|
||||
FF_PINCTRL_STATE_RST_CLR,
|
||||
FF_PINCTRL_STATE_RST_ACT,
|
||||
FF_PINCTRL_STATE_INT_ACT,
|
||||
FF_PINCTRL_STATE_MAXIMUM /* Array size */
|
||||
} ff_pinctrl_state_t;
|
||||
|
||||
/* Define pinctrl state names. */
|
||||
static const char *g_pinctrl_state_names[FF_PINCTRL_STATE_MAXIMUM] = {
|
||||
"fpsensor_finger_power_high","fpsensor_finger_power_low","fpsensor_finger_rst_low","fpsensor_finger_rst_high","fpsensor_eint_as_int"
|
||||
};
|
||||
|
||||
/* Native context and its singleton instance. */
|
||||
typedef struct {
|
||||
struct pinctrl *pinctrl;
|
||||
struct pinctrl_state *pin_states[FF_PINCTRL_STATE_MAXIMUM];
|
||||
} ff_msm_context_t;
|
||||
static ff_msm_context_t ff_msm_context, *g_context = &ff_msm_context;
|
||||
|
||||
int ff_ctl_enable_power(bool on);
|
||||
|
||||
int ff_ctl_init_pins(int *irq_num)
|
||||
{
|
||||
int err = 0, i;
|
||||
int irq_num1 = 0;
|
||||
struct device_node *dev_node = NULL;
|
||||
struct platform_device *pdev = NULL;
|
||||
|
||||
printk("'%s' enter.", __func__);
|
||||
|
||||
/* Find device tree node. */
|
||||
dev_node = of_find_compatible_node(NULL, NULL, FF_COMPATIBLE_NODE);
|
||||
if (!dev_node) {
|
||||
printk("of_find_compatible_node(.., '%s') failed.", FF_COMPATIBLE_NODE);
|
||||
return (-ENODEV);
|
||||
}
|
||||
printk("dev_node :%s",dev_node->name);
|
||||
|
||||
irq_num1 = irq_of_parse_and_map(dev_node, 0);
|
||||
*irq_num = irq_num1;
|
||||
printk("irq number is %d.", irq_num1);
|
||||
|
||||
/* Convert to platform device. */
|
||||
pdev = of_find_device_by_node(dev_node);
|
||||
if (!pdev) {
|
||||
printk("of_find_device_by_node(..) failed.");
|
||||
return (-ENODEV);
|
||||
}
|
||||
|
||||
/* Retrieve the pinctrl handler. */
|
||||
g_context->pinctrl = devm_pinctrl_get(&pdev->dev);
|
||||
if (!g_context->pinctrl) {
|
||||
printk("devm_pinctrl_get(..) failed.");
|
||||
return (-ENODEV);
|
||||
}
|
||||
|
||||
printk("register pins.");
|
||||
/* Register all pins. */
|
||||
for (i = 0; i < FF_PINCTRL_STATE_MAXIMUM; ++i) {
|
||||
g_context->pin_states[i] = pinctrl_lookup_state(g_context->pinctrl, g_pinctrl_state_names[i]);
|
||||
if (!g_context->pin_states[i]) {
|
||||
printk("can't find pinctrl state for '%s'.", g_pinctrl_state_names[i]);
|
||||
err = (-ENODEV);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < FF_PINCTRL_STATE_MAXIMUM) {
|
||||
return (-ENODEV);
|
||||
}
|
||||
|
||||
/* Initialize the INT pin. */
|
||||
printk("init int pin.");
|
||||
err = pinctrl_select_state(g_context->pinctrl, g_context->pin_states[FF_PINCTRL_STATE_INT_ACT]);
|
||||
|
||||
/* Initialize the RST pin. */
|
||||
pinctrl_select_state(g_context->pinctrl, g_context->pin_states[FF_PINCTRL_STATE_RST_ACT]);
|
||||
|
||||
ff_ctl_enable_power(true);
|
||||
|
||||
printk("'%s' leave.", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
int ff_ctl_free_pins(void)
|
||||
{
|
||||
int err = 0;
|
||||
printk("'%s' enter.", __func__);
|
||||
|
||||
// TODO:
|
||||
if (g_context->pinctrl) {
|
||||
pinctrl_put(g_context->pinctrl);
|
||||
g_context->pinctrl = NULL;
|
||||
}
|
||||
printk("'%s' leave.", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
int ff_ctl_enable_spiclk(bool on)
|
||||
{
|
||||
int err = 0;
|
||||
FF_LOGV("'%s' enter.", __func__);
|
||||
FF_LOGD("clock: '%s'.", on ? "enable" : "disabled");
|
||||
|
||||
if (on) {
|
||||
// TODO:
|
||||
} else {
|
||||
// TODO:
|
||||
}
|
||||
|
||||
FF_LOGV("'%s' leave.", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
int ff_ctl_enable_power(bool on)
|
||||
{
|
||||
int err = 0;
|
||||
printk("'%s' enter.", __func__);
|
||||
printk("power: '%s'.", on ? "on" : "off");
|
||||
|
||||
if (unlikely(!g_context->pinctrl)) {
|
||||
return (-ENOSYS);
|
||||
}
|
||||
|
||||
if (on) {
|
||||
err = pinctrl_select_state(g_context->pinctrl, g_context->pin_states[FF_PINCTRL_STATE_PWR_ACT]);
|
||||
} else {
|
||||
err = pinctrl_select_state(g_context->pinctrl, g_context->pin_states[FF_PINCTRL_STATE_PWR_CLR]);
|
||||
}
|
||||
|
||||
printk("'%s' leave.", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
int ff_ctl_reset_device(void)
|
||||
{
|
||||
int err = 0;
|
||||
printk("'%s' enter.", __func__);
|
||||
|
||||
if (unlikely(!g_context->pinctrl)) {
|
||||
return (-ENOSYS);
|
||||
}
|
||||
|
||||
err = pinctrl_select_state(g_context->pinctrl, g_context->pin_states[FF_PINCTRL_STATE_RST_ACT]);
|
||||
mdelay(1);
|
||||
/* 3-1: Pull down RST pin. */
|
||||
err = pinctrl_select_state(g_context->pinctrl, g_context->pin_states[FF_PINCTRL_STATE_RST_CLR]);
|
||||
|
||||
/* 3-2: Delay for 10ms. */
|
||||
mdelay(10);
|
||||
|
||||
/* Pull up RST pin. */
|
||||
err = pinctrl_select_state(g_context->pinctrl, g_context->pin_states[FF_PINCTRL_STATE_RST_ACT]);
|
||||
|
||||
printk("'%s' leave.", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
const char *ff_ctl_arch_str(void)
|
||||
{
|
||||
return "msm";
|
||||
}
|
||||
|
||||
Loading…
Reference in a new issue