mirror of
https://github.com/revyos/thead-kernel.git
synced 2026-08-09 23:51:25 +02:00
sync: huiwei: e94a4cf98b93de7f711637033a43f0e2f5f3ac7a
merge into c2a6429c9b9d3fe12738317f410fb1b5cb96cb3b
This commit is contained in:
@@ -24,6 +24,16 @@ config INPUT
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called input.
|
||||
|
||||
config INPUT_FINGERPRINT
|
||||
default y
|
||||
help
|
||||
fingerprint
|
||||
|
||||
config INPUT_HALL
|
||||
default y
|
||||
help
|
||||
hall
|
||||
|
||||
if INPUT
|
||||
|
||||
config INPUT_LEDS
|
||||
@@ -211,5 +221,9 @@ source "drivers/input/gameport/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
||||
source "drivers/input/fingerprint/Kconfig"
|
||||
|
||||
source "drivers/input/hall/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@ obj-$(CONFIG_INPUT_JOYSTICK) += joystick/
|
||||
obj-$(CONFIG_INPUT_TABLET) += tablet/
|
||||
obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/
|
||||
obj-$(CONFIG_INPUT_MISC) += misc/
|
||||
obj-$(CONFIG_MICROARRAY_FINGERPRINT) += fingerprint/
|
||||
obj-$(CONFIG_HS_MH248) += hall/
|
||||
|
||||
obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o
|
||||
|
||||
|
||||
51
drivers/input/fingerprint/Kconfig
Normal file
51
drivers/input/fingerprint/Kconfig
Normal file
@@ -0,0 +1,51 @@
|
||||
#
|
||||
#Fingerprint
|
||||
#
|
||||
menu "Fingerprint support"
|
||||
depends on INPUT
|
||||
|
||||
config MTK_FINGERPRINT_SUPPORT
|
||||
bool "Mediatek Fingerprint"
|
||||
default n
|
||||
help
|
||||
Fingerprint mtk driver enable/disable in the kernel.
|
||||
Say Y here if you want to use mediatek fingerprint driver,
|
||||
fingerprint driver will support fingerprint function
|
||||
|
||||
if MTK_FINGERPRINT_SUPPORT
|
||||
|
||||
config MICROARRAY_FINGERPRINT
|
||||
bool "Microarray Fingerprint"
|
||||
default y
|
||||
help
|
||||
Microarray fingerprint Microarray's 121/112/88/64/48 device.
|
||||
|
||||
if MICROARRAY_FINGERPRINT = ""
|
||||
config MTK_FINGERPRINT_SELECT
|
||||
string "sensor type"
|
||||
default "GF318M"
|
||||
endif
|
||||
|
||||
if MTK_FINGERPRINT_SELECT = "FPC1145"
|
||||
config FPC_FINGERPRINT
|
||||
bool "FPC Fingerprint"
|
||||
default y
|
||||
help
|
||||
FPC fingerprint FPC's 102x/104x device.
|
||||
endif
|
||||
|
||||
if MTK_FINGERPRINT_SELECT = "GF318M"
|
||||
config GOODIX_FINGERPRINT
|
||||
bool "Goodix Fingerprint"
|
||||
default y
|
||||
help
|
||||
Goodix Fingerprint chip GF316M/GF318M/GF3118M/GF518M/GF5118M/GF516M/GF816M/GF3208/GF5216 TEE driver
|
||||
|
||||
config GOODIX_SENSOR_TYPE
|
||||
string "SENSOR_TYPE"
|
||||
default "GF318M"
|
||||
help
|
||||
Must input sensor type, or default is GF316M GF318M GF3118M GF518M GF5118M GF516M GF816M GF3208 GF5216
|
||||
endif
|
||||
endif
|
||||
endmenu
|
||||
7
drivers/input/fingerprint/Makefile
Normal file
7
drivers/input/fingerprint/Makefile
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
# Makefile for all kinds of Fingerprint
|
||||
#
|
||||
|
||||
obj-$(CONFIG_GOODIX_FINGERPRINT) += goodix/
|
||||
obj-$(CONFIG_FPC_FINGERPRINT) += fpc/
|
||||
obj-$(CONFIG_MICROARRAY_FINGERPRINT) += microarray_fp/
|
||||
8
drivers/input/fingerprint/microarray_fp/Kconfig
Normal file
8
drivers/input/fingerprint/microarray_fp/Kconfig
Normal file
@@ -0,0 +1,8 @@
|
||||
# Copyright (C) MicroArray
|
||||
# MicroArray Fprint Driver Code
|
||||
# Kconfig
|
||||
# Date: 2017-3-15
|
||||
# Version: v4.0.06
|
||||
# Author: guq
|
||||
# Contact: guq@microarray.com.cn
|
||||
|
||||
30
drivers/input/fingerprint/microarray_fp/Makefile
Normal file
30
drivers/input/fingerprint/microarray_fp/Makefile
Normal file
@@ -0,0 +1,30 @@
|
||||
# Copyright (C) Microarray
|
||||
# MicroArray Fprint Driver Code
|
||||
# MAKEFILE
|
||||
# Date: 2017-3-15
|
||||
# Version: v4.0.06
|
||||
# Author: guq
|
||||
# Contact: guq@microarray.com.cn
|
||||
|
||||
|
||||
subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat/$(MTK_PLATFORM)/include \
|
||||
-I$(srctree)/drivers/misc/mediatek/include/mt-plat
|
||||
|
||||
MTK_PLATFORM := $(subst ",,$(CONFIG_MTK_PLATFORM))
|
||||
subdir-ccflags-y += -Werror
|
||||
subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/include
|
||||
subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/$(MTK_PLATFORM)
|
||||
subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat/$(MTK_PLATFORM)/include
|
||||
subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat
|
||||
subdir-ccflags-y += -I$(srctree)/drivers/spi/mediatek/$(MTK_PLATFORM)
|
||||
|
||||
#compatible for trustkernel
|
||||
subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/tkcore/include/
|
||||
subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/tkcore/core
|
||||
|
||||
#compatible for microtrust
|
||||
ccflags-y += -I$(srctree)/drivers/misc/mediatek/teei/V1.0/tz_vfs
|
||||
|
||||
obj-y += madev.o mtk-settings.o
|
||||
|
||||
|
||||
65
drivers/input/fingerprint/microarray_fp/ioctl_cmd.h
Normal file
65
drivers/input/fingerprint/microarray_fp/ioctl_cmd.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/* Copyright (C) MicroArray
|
||||
* MicroArray Fprint Driver Code
|
||||
* ioctl_cmd.h
|
||||
* Date: 2017-3-15
|
||||
* Version: v4.0.06
|
||||
* Author: guq
|
||||
* Contact: guq@microarray.com.cn
|
||||
*/
|
||||
#ifndef __IOCTL_CMD_H__
|
||||
#define __IOCTL_CMD_H__
|
||||
|
||||
#define MA_DRV_VERSION (0x00004006)
|
||||
|
||||
#define MA_IOC_MAGIC 'M'
|
||||
//#define MA_IOC_INIT _IOR(MA_IOC_MAGIC, 0, unsigned char)
|
||||
#define TIMEOUT_WAKELOCK _IO(MA_IOC_MAGIC, 1)
|
||||
#define SLEEP _IO(MA_IOC_MAGIC, 2) //陷入内核
|
||||
#define WAKEUP _IO(MA_IOC_MAGIC, 3) //唤醒
|
||||
#define ENABLE_CLK _IO(MA_IOC_MAGIC, 4) //打开spi时钟
|
||||
#define DISABLE_CLK _IO(MA_IOC_MAGIC, 5) //关闭spi时钟
|
||||
#define ENABLE_INTERRUPT _IO(MA_IOC_MAGIC, 6) //开启中断上报
|
||||
#define DISABLE_INTERRUPT _IO(MA_IOC_MAGIC, 7) //关闭中断上报
|
||||
#define TAP_DOWN _IO(MA_IOC_MAGIC, 8)
|
||||
#define TAP_UP _IO(MA_IOC_MAGIC, 9)
|
||||
#define SINGLE_TAP _IO(MA_IOC_MAGIC, 11)
|
||||
#define DOUBLE_TAP _IO(MA_IOC_MAGIC, 12)
|
||||
#define LONG_TAP _IO(MA_IOC_MAGIC, 13)
|
||||
|
||||
#define MA_IOC_VTIM _IOR(MA_IOC_MAGIC, 14, unsigned char) //version time
|
||||
#define MA_IOC_CNUM _IOR(MA_IOC_MAGIC, 15, unsigned char) //cover num
|
||||
#define MA_IOC_SNUM _IOR(MA_IOC_MAGIC, 16, unsigned char) //sensor type
|
||||
#define MA_IOC_UKRP _IOW(MA_IOC_MAGIC, 17, unsigned char) //user define the report key
|
||||
|
||||
#define MA_KEY_UP/*KEY_UP*/ _IO(MA_IOC_MAGIC, 18) //nav up
|
||||
#define MA_KEY_LEFT/*KEY_LEFT*/ _IO(MA_IOC_MAGIC, 19) //nav left
|
||||
#define MA_KEY_DOWN/*KEY_DOWN*/ _IO(MA_IOC_MAGIC, 20) //nav down
|
||||
#define MA_KEY_RIGHT/*KEY_RIGHT*/ _IO(MA_IOC_MAGIC, 21) //nav right
|
||||
|
||||
#define MA_KEY_F14/*KEY_F14*/ _IO(MA_IOC_MAGIC, 23) //for chuanyin
|
||||
#define SET_MODE _IOW(MA_IOC_MAGIC, 33, unsigned int) //for yude
|
||||
#define GET_MODE _IOR(MA_IOC_MAGIC, 34, unsigned int) //for yude
|
||||
|
||||
|
||||
#define ENABLE_IRQ/*ENABLE_IQ*/ _IO(MA_IOC_MAGIC, 31)
|
||||
#define DISABLE_IRQ/*DISABLE_IQ*/ _IO(MA_IOC_MAGIC, 32)
|
||||
|
||||
#define MA_IOC_GVER _IOR(MA_IOC_MAGIC, 35, unsigned int) //get the driver version,the version mapping in the u32 is the final 4+4+8,as ******** ******* ****(major verson number) ****(minor version number) ********(revised version number), the front 16 byte is reserved.
|
||||
#define SCREEN_OFF _IO(MA_IOC_MAGIC, 36)
|
||||
#define SCREEN_ON _IO(MA_IOC_MAGIC, 37)
|
||||
#define SET_SPI_SPEED _IOW(MA_IOC_MAGIC, 38, unsigned int)
|
||||
|
||||
|
||||
#define WAIT_FACTORY_CMD _IO(MA_IOC_MAGIC, 39)//for fingerprintd
|
||||
#define WAKEUP_FINGERPRINTD _IO(MA_IOC_MAGIC, 40)//for factory test
|
||||
#define WAIT_FINGERPRINTD_RESPONSE _IOR(MA_IOC_MAGIC, 41, unsigned int)//for factory test
|
||||
#define WAKEUP_FACTORY_TEST_SEND_FINGERPRINTD_RESPONSE _IOW(MA_IOC_MAGIC, 42, unsigned int)//for fingerprintd
|
||||
#define WAIT_SCREEN_STATUS_CHANGE _IOR(MA_IOC_MAGIC, 43, unsigned int)
|
||||
#define GET_INTERRUPT_STATUS _IOR(MA_IOC_MAGIC, 44, unsigned int)
|
||||
#define SYNC _IO(MA_IOC_MAGIC, 45)
|
||||
#define SYNC2 _IO(MA_IOC_MAGIC, 46)
|
||||
#define GET_SCREEN_STATUS _IOR(MA_IOC_MAGIC, 47, unsigned int)
|
||||
#define MA_RESET _IOW(MA_IOC_MAGIC, 48, unsigned int)
|
||||
#define GET_MA_RESET_STATE _IOR(MA_IOC_MAGIC, 49, unsigned int)
|
||||
#endif /* __IOCTL_CMD_H__ */
|
||||
|
||||
889
drivers/input/fingerprint/microarray_fp/madev.c
Normal file
889
drivers/input/fingerprint/microarray_fp/madev.c
Normal file
@@ -0,0 +1,889 @@
|
||||
/* Copyright (C) MicroArray
|
||||
oALOGD("start");
|
||||
* MicroArray Fprint Driver Code for REE enviroment
|
||||
* madev.c
|
||||
* Date: 2017-3-15
|
||||
* Version: v4.0.06
|
||||
* Author: guq
|
||||
* Contact: guq@microarray.com.cn
|
||||
*/
|
||||
#include "madev.h"
|
||||
|
||||
#ifdef TEE_ID_COMPATIBLE_MICROTRUST
|
||||
#include <fp_vendor.h>
|
||||
#include "teei_fp.h"
|
||||
#include "tee_client_api.h"
|
||||
#endif
|
||||
|
||||
//spdev use for recording the data for other use
|
||||
static unsigned int irq, ret;
|
||||
static unsigned int ma_drv_reg;
|
||||
static unsigned int ma_speed;
|
||||
static unsigned int is_screen_on;
|
||||
static struct notifier_block notifier;
|
||||
static unsigned int int_pin_state;
|
||||
static unsigned int compatible;
|
||||
static unsigned int screen_flag;
|
||||
static DECLARE_WAIT_QUEUE_HEAD(screenwaitq);
|
||||
static DECLARE_WAIT_QUEUE_HEAD(gWaitq);
|
||||
static DECLARE_WAIT_QUEUE_HEAD(U1_Waitq);
|
||||
static DECLARE_WAIT_QUEUE_HEAD(U2_Waitq);
|
||||
#ifdef CONFIG_PM_WAKELOCKS
|
||||
struct wakeup_source *gProcessWakeLock;
|
||||
#else
|
||||
struct wake_lock gProcessWakeLock;
|
||||
#endif
|
||||
|
||||
struct work_struct gWork;
|
||||
struct workqueue_struct *gWorkq;
|
||||
//
|
||||
static LIST_HEAD(dev_list);
|
||||
static DEFINE_MUTEX(dev_lock);
|
||||
static DEFINE_MUTEX(drv_lock);
|
||||
static DEFINE_MUTEX(ioctl_lock);
|
||||
#ifdef COMPATIBLE_VERSION3
|
||||
static DECLARE_WAIT_QUEUE_HEAD(drv_waitq);
|
||||
#endif
|
||||
|
||||
static struct fprint_dev *sdev = NULL;
|
||||
static struct fprint_spi *smas = NULL;
|
||||
|
||||
static u8* stxb;
|
||||
static u8* srxb;
|
||||
|
||||
#define IMAGE_SIZE 13312
|
||||
#define IMAGE_DMA_SIZE 32*1024
|
||||
|
||||
static void mas_work(struct work_struct *pws) {
|
||||
smas->f_irq = 1;
|
||||
wake_up(&gWaitq);
|
||||
#ifdef COMPATIBLE_VERSION3
|
||||
wake_up(&drv_waitq);
|
||||
#endif
|
||||
}
|
||||
|
||||
static irqreturn_t mas_interrupt(int irq, void *dev_id) {
|
||||
|
||||
#ifdef CONFIG_PM_WAKELOCKS
|
||||
__pm_wakeup_event(gProcessWakeLock, 5000);
|
||||
#else
|
||||
wake_lock_timeout(&gProcessWakeLock, 5 * HZ);
|
||||
#endif
|
||||
#ifdef DOUBLE_EDGE_IRQ
|
||||
if(mas_get_interrupt_gpio(0)==1){
|
||||
//TODO IRQF_TRIGGER_RISING
|
||||
}else{
|
||||
//TODO IRQF_TRIGGER_FALLING
|
||||
}
|
||||
#else
|
||||
|
||||
queue_work(gWorkq, &gWork);
|
||||
#endif
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------- fops ------------------------------------*/
|
||||
|
||||
/* 读写数据
|
||||
* @buf 数据
|
||||
* @len 长度
|
||||
* @返回值:0成功,否则失败
|
||||
*/
|
||||
int mas_sync(u8 *txb, u8 *rxb, int len) {
|
||||
int ret = 0;
|
||||
#if 1
|
||||
|
||||
struct spi_message m;
|
||||
struct spi_transfer t = {
|
||||
.tx_buf = txb,
|
||||
.rx_buf = rxb,
|
||||
.len = len,
|
||||
.speed_hz = smas->spi->max_speed_hz,
|
||||
};
|
||||
mutex_lock(&dev_lock);
|
||||
// len = (len + 1023) << 10 >> 10;
|
||||
// t.len = len;
|
||||
spi_message_init(&m);
|
||||
spi_message_add_tail(&t, &m);
|
||||
ret= spi_sync(smas->spi,&m);
|
||||
mutex_unlock(&dev_lock);
|
||||
|
||||
return ret;
|
||||
#else
|
||||
|
||||
|
||||
mutex_lock(&dev_lock);
|
||||
mas_select_transfer(smas->spi, len);
|
||||
smas->xfer.tx_nbits=SPI_NBITS_SINGLE;
|
||||
smas->xfer.tx_buf = txb;
|
||||
smas->xfer.rx_nbits=SPI_NBITS_SINGLE;
|
||||
smas->xfer.rx_buf = rxb;
|
||||
smas->xfer.delay_usecs = 1;
|
||||
smas->xfer.len = len;
|
||||
smas->xfer.bits_per_word = 8;
|
||||
smas->xfer.speed_hz = smas->spi->max_speed_hz;
|
||||
spi_message_init(&smas->msg);
|
||||
spi_message_add_tail(&smas->xfer, &smas->msg);
|
||||
ret = spi_sync(smas->spi, &smas->msg);
|
||||
mutex_unlock(&dev_lock);
|
||||
|
||||
return ret;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* 读数据
|
||||
* @return 成功:count, -1count太大,-2通讯失败, -3拷贝失败
|
||||
*/
|
||||
static ssize_t mas_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) {
|
||||
int val, ret = 0;
|
||||
//MALOGD("start");
|
||||
//printk("zzzz count - %d\n", (int)count);
|
||||
ret = mas_sync(stxb, srxb, count);
|
||||
if(ret) {
|
||||
MALOGW("mas_sync failed.");
|
||||
return -2;
|
||||
}
|
||||
ret = copy_to_user(buf, srxb, count);
|
||||
if(!ret) val = count;
|
||||
else {
|
||||
val = -3;
|
||||
MALOGW("copy_to_user failed.");
|
||||
}
|
||||
//MALOGD("end.");
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
static void mas_set_input(void) {
|
||||
struct input_dev *input = NULL;
|
||||
input = input_allocate_device();
|
||||
if (!input) {
|
||||
MALOGW("input_allocate_device failed.");
|
||||
return ;
|
||||
}
|
||||
set_bit(EV_KEY, input->evbit);
|
||||
//set_bit(EV_ABS, input->evbit);
|
||||
set_bit(EV_SYN, input->evbit);
|
||||
set_bit(FINGERPRINT_SWIPE_UP, input->keybit); //单触
|
||||
set_bit(FINGERPRINT_SWIPE_DOWN, input->keybit);
|
||||
set_bit(FINGERPRINT_SWIPE_LEFT, input->keybit);
|
||||
set_bit(FINGERPRINT_SWIPE_RIGHT, input->keybit);
|
||||
set_bit(FINGERPRINT_TAP, input->keybit);
|
||||
set_bit(FINGERPRINT_DTAP, input->keybit);
|
||||
set_bit(FINGERPRINT_LONGPRESS, input->keybit);
|
||||
|
||||
set_bit(KEY_POWER, input->keybit);
|
||||
|
||||
input->name = MA_CHR_DEV_NAME;
|
||||
input->id.bustype = BUS_SPI;
|
||||
ret = input_register_device(input);
|
||||
if (ret) {
|
||||
input_free_device(input);
|
||||
MALOGW("failed to register input device.");
|
||||
return;
|
||||
}
|
||||
smas->input = input;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//static int mas_ioctl (struct inode *node, struct file *filp, unsigned int cmd, uns igned long arg)
|
||||
//this function only supported while the linux kernel version under v2.6.36,while the kernel version under v2.6.36, use this line
|
||||
static long mas_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) {
|
||||
//MALOGF("start");
|
||||
int tmp;
|
||||
switch(cmd){
|
||||
case TIMEOUT_WAKELOCK: //延时锁 timeout lock
|
||||
#ifdef CONFIG_PM_WAKELOCKS
|
||||
__pm_wakeup_event(gProcessWakeLock, 5000);
|
||||
#else
|
||||
wake_lock_timeout(&gProcessWakeLock, 5 * HZ);
|
||||
#endif
|
||||
break;
|
||||
case SLEEP: //remove the process out of the runqueue
|
||||
if(mas_get_interrupt_gpio(0) == 1) {
|
||||
MALOGF("int pull down failed!");
|
||||
return 0;
|
||||
}
|
||||
smas->f_irq = 0;
|
||||
ret = wait_event_freezable(gWaitq, smas->f_irq != 0);
|
||||
break;
|
||||
case WAKEUP: //wake up, schedule the process into the runqueue
|
||||
smas->f_irq = 1;
|
||||
wake_up(&gWaitq);
|
||||
break;
|
||||
case ENABLE_CLK:
|
||||
mas_enable_spi_clock(smas->spi); //if the spi clock is not opening always, do this methods
|
||||
break;
|
||||
case DISABLE_CLK:
|
||||
mas_disable_spi_clock(smas->spi); //disable the spi clock
|
||||
break;
|
||||
case ENABLE_INTERRUPT:
|
||||
enable_irq(irq); //enable the irq,in fact, you can make irq enable always
|
||||
break;
|
||||
case DISABLE_INTERRUPT:
|
||||
disable_irq(irq); //disable the irq
|
||||
break;
|
||||
case TAP_DOWN:
|
||||
input_report_key(smas->input, FINGERPRINT_TAP, 1);
|
||||
input_sync(smas->input); //tap down
|
||||
break;
|
||||
case TAP_UP:
|
||||
input_report_key(smas->input, FINGERPRINT_TAP, 0);
|
||||
input_sync(smas->input); //tap up
|
||||
break;
|
||||
case SINGLE_TAP:
|
||||
input_report_key(smas->input, FINGERPRINT_TAP, 1);
|
||||
input_sync(smas->input);
|
||||
input_report_key(smas->input, FINGERPRINT_TAP, 0);
|
||||
input_sync(smas->input); //single tap
|
||||
break;
|
||||
case DOUBLE_TAP:
|
||||
input_report_key(smas->input, FINGERPRINT_DTAP, 1);
|
||||
input_sync(smas->input);
|
||||
input_report_key(smas->input, FINGERPRINT_DTAP, 0);
|
||||
input_sync(smas->input); //double tap
|
||||
break;
|
||||
case LONG_TAP:
|
||||
input_report_key(smas->input, FINGERPRINT_LONGPRESS, 1);
|
||||
input_sync(smas->input);
|
||||
input_report_key(smas->input, FINGERPRINT_LONGPRESS, 0);
|
||||
input_sync(smas->input); //long tap
|
||||
break;
|
||||
case MA_KEY_UP:
|
||||
input_report_key(smas->input, FINGERPRINT_SWIPE_UP, 1);
|
||||
input_sync(smas->input);
|
||||
input_report_key(smas->input, FINGERPRINT_SWIPE_UP, 0);
|
||||
input_sync(smas->input);
|
||||
break;
|
||||
case MA_KEY_LEFT:
|
||||
input_report_key(smas->input, FINGERPRINT_SWIPE_LEFT, 1);
|
||||
input_sync(smas->input);
|
||||
input_report_key(smas->input, FINGERPRINT_SWIPE_LEFT, 0);
|
||||
input_sync(smas->input);
|
||||
break;
|
||||
case MA_KEY_DOWN:
|
||||
input_report_key(smas->input, FINGERPRINT_SWIPE_DOWN, 1);
|
||||
input_sync(smas->input);
|
||||
input_report_key(smas->input, FINGERPRINT_SWIPE_DOWN, 0);
|
||||
input_sync(smas->input);
|
||||
break;
|
||||
case MA_KEY_RIGHT:
|
||||
input_report_key(smas->input, FINGERPRINT_SWIPE_RIGHT, 1);
|
||||
input_sync(smas->input);
|
||||
input_report_key(smas->input, FINGERPRINT_SWIPE_RIGHT, 0);
|
||||
input_sync(smas->input);
|
||||
break;
|
||||
case SET_MODE:
|
||||
mutex_lock(&ioctl_lock);
|
||||
ret = copy_from_user(&ma_drv_reg, (unsigned int*)arg, sizeof(unsigned int));
|
||||
mutex_unlock(&ioctl_lock);
|
||||
break;
|
||||
case GET_MODE:
|
||||
mutex_lock(&ioctl_lock);
|
||||
ret = copy_to_user((unsigned int*)arg, &ma_drv_reg, sizeof(unsigned int));
|
||||
mutex_unlock(&ioctl_lock);
|
||||
break;
|
||||
case MA_IOC_GVER:
|
||||
{
|
||||
unsigned int ma_drv_version = MA_DRV_VERSION;
|
||||
mutex_lock(&ioctl_lock);
|
||||
if (copy_to_user((void *)arg, &ma_drv_version, sizeof(unsigned int))) {
|
||||
MALOGE("copy_to_user(..) failed.\n");
|
||||
ret = (-EFAULT);
|
||||
}
|
||||
mutex_unlock(&ioctl_lock);
|
||||
}
|
||||
break;
|
||||
case SCREEN_ON:
|
||||
mas_switch_power(1);
|
||||
break;
|
||||
case SCREEN_OFF:
|
||||
mas_switch_power(0);
|
||||
break;
|
||||
case MA_RESET:
|
||||
mas_finger_set_reset(arg);
|
||||
break;
|
||||
case GET_MA_RESET_STATE:
|
||||
break;
|
||||
|
||||
case SET_SPI_SPEED:
|
||||
ret = copy_from_user(&ma_speed, (unsigned int*)arg, sizeof(unsigned int));
|
||||
ma_spi_change(smas->spi, ma_speed, 0);
|
||||
break;
|
||||
case WAIT_FACTORY_CMD:
|
||||
smas->u2_flag = 0;
|
||||
ret = wait_event_freezable(U2_Waitq, smas->u2_flag != 0);
|
||||
break;
|
||||
case WAKEUP_FINGERPRINTD:
|
||||
smas->u2_flag = 1;
|
||||
wake_up(&U2_Waitq);
|
||||
break;
|
||||
case WAIT_FINGERPRINTD_RESPONSE:
|
||||
smas->u1_flag = 0;
|
||||
ret = wait_event_freezable(U1_Waitq, smas->u1_flag != 0);
|
||||
mutex_lock(&ioctl_lock);
|
||||
tmp = copy_to_user((unsigned int*)arg, &ma_drv_reg, sizeof(unsigned int));
|
||||
mutex_unlock(&ioctl_lock);
|
||||
break;
|
||||
case WAKEUP_FACTORY_TEST_SEND_FINGERPRINTD_RESPONSE:
|
||||
mutex_lock(&ioctl_lock);
|
||||
ret = copy_from_user(&ma_drv_reg, (unsigned int*)arg, sizeof(unsigned int));
|
||||
mutex_unlock(&ioctl_lock);
|
||||
msleep(4);
|
||||
smas->u1_flag = 1;
|
||||
wake_up(&U1_Waitq);
|
||||
break;
|
||||
case WAIT_SCREEN_STATUS_CHANGE:
|
||||
screen_flag = 0;
|
||||
ret = wait_event_freezable(screenwaitq, screen_flag != 0);
|
||||
mutex_lock(&ioctl_lock);
|
||||
tmp = copy_to_user((unsigned int*)arg, &is_screen_on, sizeof(unsigned int));
|
||||
mutex_unlock(&ioctl_lock);
|
||||
break;
|
||||
case GET_INTERRUPT_STATUS:
|
||||
int_pin_state = mas_get_interrupt_gpio(0);
|
||||
mutex_lock(&ioctl_lock);
|
||||
tmp = copy_to_user((unsigned int*)arg, &int_pin_state, sizeof(unsigned int));
|
||||
mutex_unlock(&ioctl_lock);
|
||||
break;
|
||||
case GET_SCREEN_STATUS:
|
||||
mutex_lock(&ioctl_lock);
|
||||
ret = copy_to_user((unsigned int*)arg, &is_screen_on, sizeof(unsigned int));
|
||||
mutex_unlock(&ioctl_lock);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
MALOGW("mas_ioctl no such cmd");
|
||||
}
|
||||
//MALOGF("end");
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
static long mas_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
int retval = 0;
|
||||
retval = filp->f_op->unlocked_ioctl(filp, cmd, arg);
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef COMPATIBLE_VERSION3
|
||||
int version3_ioctl(int cmd, int arg){
|
||||
int ret = 0;
|
||||
|
||||
printd("%s: start cmd=0x%.3x arg=%d\n", __func__, cmd, arg);
|
||||
|
||||
switch (cmd) {
|
||||
case IOCTL_DEBUG:
|
||||
sdeb = (u8) arg;
|
||||
break;
|
||||
case IOCTL_IRQ_ENABLE:
|
||||
break;
|
||||
case IOCTL_SPI_SPEED:
|
||||
smas->spi->max_speed_hz = (u32) arg;
|
||||
spi_setup(smas->spi);
|
||||
break;
|
||||
case IOCTL_COVER_NUM:
|
||||
ret = COVER_NUM;
|
||||
break;
|
||||
case IOCTL_GET_VDATE:
|
||||
ret = 20160425;
|
||||
break;
|
||||
case IOCTL_CLR_INTF:
|
||||
smas->f_irq = FALSE;
|
||||
break;
|
||||
case IOCTL_GET_INTF:
|
||||
ret = smas->f_irq;
|
||||
break;
|
||||
case IOCTL_REPORT_FLAG:
|
||||
smas->f_repo = arg;
|
||||
break;
|
||||
case IOCTL_REPORT_KEY:
|
||||
input_report_key(smas->input, arg, 1);
|
||||
input_sync(smas->input);
|
||||
input_report_key(smas->input, arg, 0);
|
||||
input_sync(smas->input);
|
||||
break;
|
||||
case IOCTL_SET_WORK:
|
||||
smas->do_what = arg;
|
||||
break;
|
||||
case IOCTL_GET_WORK:
|
||||
ret = smas->do_what;
|
||||
break;
|
||||
case IOCTL_SET_VALUE:
|
||||
smas->value = arg;
|
||||
break;
|
||||
case IOCTL_GET_VALUE:
|
||||
ret = smas->value;
|
||||
break;
|
||||
case IOCTL_TRIGGER:
|
||||
smas->f_wake = TRUE;
|
||||
wake_up_interruptible(&drv_waitq);
|
||||
break;
|
||||
case IOCTL_WAKE_LOCK:
|
||||
#ifdef CONFIG_PM_WAKELOCKS
|
||||
__pm_stay_awake(&smas->wl);
|
||||
#else
|
||||
wake_lock(&smas->wl);
|
||||
#endif
|
||||
break;
|
||||
case IOCTL_WAKE_UNLOCK:
|
||||
#ifdef CONFIG_PM_WAKELOCKS
|
||||
__pm_relax(&smas->wl);
|
||||
#else
|
||||
wake_unlock(&smas->wl);
|
||||
#endif
|
||||
break;
|
||||
case IOCTL_KEY_DOWN:
|
||||
input_report_key(smas->input, KEY_F11 1);
|
||||
input_sync(smas->input);
|
||||
break;
|
||||
case IOCTL_KEY_UP:
|
||||
input_report_key(smas->input, KEY_F11, 0);
|
||||
input_sync(smas->input);
|
||||
break;
|
||||
}
|
||||
|
||||
printd("%s: end. ret=%d f_irq=%d, f_repo=%d\n", __func__, ret, smas->f_irq, smas->f_repo);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 写数据
|
||||
* @return 成功:count, -1count太大,-2拷贝失败
|
||||
*/
|
||||
static ssize_t mas_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) {
|
||||
int val = 0;
|
||||
//MALOGD("start");
|
||||
if(count==6) { //cmd ioctl, old version used the write interface to do ioctl, this is only for the old version
|
||||
int cmd, arg;
|
||||
u8 tmp[6];
|
||||
ret = copy_from_user(tmp, buf, count);
|
||||
cmd = tmp[0];
|
||||
cmd <<= 8;
|
||||
cmd += tmp[1];
|
||||
arg = tmp[2];
|
||||
arg <<= 8;
|
||||
arg += tmp[3];
|
||||
arg <<= 8;
|
||||
arg += tmp[4];
|
||||
arg <<= 8;
|
||||
arg += tmp[5];
|
||||
#ifdef COMPATIBLE_VERSION3
|
||||
val = (int)version3_ioctl(NULL, (unsigned int)cmd, (unsigned long)arg);
|
||||
#endif
|
||||
} else {
|
||||
//memset(stxb, 0, FBUF);
|
||||
memset(stxb, 0xff, IMAGE_DMA_SIZE);
|
||||
ret = copy_from_user(stxb, buf, count);
|
||||
if(ret) {
|
||||
MALOGW("copy form user failed");
|
||||
val = -2;
|
||||
} else {
|
||||
val = count;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
void * kernel_memaddr = NULL;
|
||||
unsigned long kernel_memesize = 0;
|
||||
|
||||
int mas_mmap(struct file *filp, struct vm_area_struct *vma){
|
||||
unsigned long page;
|
||||
if ( !kernel_memaddr ) {
|
||||
kernel_memaddr = kmalloc(128*1024, GFP_KERNEL);
|
||||
if( !kernel_memaddr ) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
page = virt_to_phys((void *)kernel_memaddr) >> PAGE_SHIFT;
|
||||
vma->vm_page_prot=pgprot_noncached(vma->vm_page_prot);
|
||||
if( remap_pfn_range(vma, vma->vm_start, page, (vma->vm_end - vma->vm_start),
|
||||
vma->vm_page_prot) )
|
||||
return -1;
|
||||
//vma->vm_flags |= VM_RESERVED;
|
||||
vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
|
||||
printk("remap_pfn_rang page:[%lu] ok.\n", page);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef COMPATIBLE_VERSION3
|
||||
static unsigned int mas_poll(struct file *filp, struct poll_table_struct *wait) {
|
||||
unsigned int mask = 0;
|
||||
|
||||
printd("%s: start. f_irq=%d f_repo=%d f_wake=%d\n",
|
||||
__func__, smas->f_irq, smas->f_repo, smas->f_wake);
|
||||
|
||||
poll_wait(filp, &drv_waitq, wait);
|
||||
if(smas->f_irq && smas->f_repo) {
|
||||
smas->f_repo = FALSE;
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
} else if( smas->f_wake ) {
|
||||
smas->f_wake = FALSE;
|
||||
mask |= POLLPRI;
|
||||
}
|
||||
|
||||
printd("%s: end. mask=%d\n", __func__, mask);
|
||||
|
||||
return mask;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*---------------------------------- fops ------------------------------------*/
|
||||
static const struct file_operations sfops = {
|
||||
.owner = THIS_MODULE,
|
||||
.write = mas_write,
|
||||
.read = mas_read,
|
||||
.unlocked_ioctl = mas_ioctl,
|
||||
.mmap = mas_mmap,
|
||||
//.ioctl = mas_ioctl,
|
||||
//using the previous line replacing the unlock_ioctl while the linux kernel under version2.6.36
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = mas_compat_ioctl,
|
||||
#endif
|
||||
#ifdef COMPATIBLE_VERSION3
|
||||
.poll = mas_poll,
|
||||
#endif
|
||||
};
|
||||
/*---------------------------------- fops end ---------------------------------*/
|
||||
|
||||
static int init_file_node(void)
|
||||
{
|
||||
int ret;
|
||||
//MALOGF("start");
|
||||
ret = alloc_chrdev_region(&sdev->idd, 0, 1, MA_CHR_DEV_NAME);
|
||||
if(ret < 0)
|
||||
{
|
||||
MALOGW("alloc_chrdev_region error!");
|
||||
return -1;
|
||||
}
|
||||
sdev->chd = cdev_alloc();
|
||||
if (!sdev->chd)
|
||||
{
|
||||
MALOGW("cdev_alloc error!");
|
||||
return -1;
|
||||
}
|
||||
sdev->chd->owner = THIS_MODULE;
|
||||
sdev->chd->ops = &sfops;
|
||||
cdev_add(sdev->chd, sdev->idd, 1);
|
||||
sdev->cls = class_create(THIS_MODULE, MA_CHR_DEV_NAME);
|
||||
if (IS_ERR(sdev->cls)) {
|
||||
MALOGE("class_create");
|
||||
return -1;
|
||||
}
|
||||
sdev->dev = device_create(sdev->cls, NULL, sdev->idd, NULL, MA_CHR_FILE_NAME);
|
||||
ret = IS_ERR(sdev->dev) ? PTR_ERR(sdev->dev) : 0;
|
||||
if(ret){
|
||||
MALOGE("device_create");
|
||||
}
|
||||
//MALOGF("end");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int deinit_file_node(void)
|
||||
{
|
||||
cdev_del(sdev->chd);
|
||||
device_destroy(sdev->cls, sdev->idd);
|
||||
unregister_chrdev_region(sdev->idd, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init_interrupt(void)
|
||||
{
|
||||
const char*tname = MA_EINT_NAME;
|
||||
irq = mas_get_irq(&smas->spi->dev);
|
||||
if(irq<=0){
|
||||
ret = irq;
|
||||
MALOGE("mas_get_irq");
|
||||
}
|
||||
#ifdef DOUBLE_EDGE_IRQ
|
||||
ret = request_irq(irq, mas_interrupt, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, tname, NULL);
|
||||
#else
|
||||
ret = request_irq(irq, mas_interrupt, IRQF_TRIGGER_RISING, tname, NULL);
|
||||
#endif
|
||||
if(ret<0){
|
||||
MALOGE("request_irq");
|
||||
}
|
||||
enable_irq_wake(irq);
|
||||
return ret;
|
||||
}
|
||||
static int deinit_interrupt(void)
|
||||
{
|
||||
disable_irq(irq);
|
||||
free_irq(irq, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int init_vars(void)
|
||||
{
|
||||
sdev = kmalloc(sizeof(struct fprint_dev), GFP_KERNEL);
|
||||
smas = kmalloc(sizeof(struct fprint_spi), GFP_KERNEL);
|
||||
stxb = (u8*)__get_free_pages(GFP_KERNEL, get_order(IMAGE_DMA_SIZE));
|
||||
srxb = (u8*)__get_free_pages(GFP_KERNEL, get_order(IMAGE_DMA_SIZE));
|
||||
|
||||
if (sdev==NULL || smas==NULL || stxb==NULL || srxb==NULL) {
|
||||
MALOGW("smas kmalloc failed.");
|
||||
if(sdev!=NULL) kfree(sdev);
|
||||
if(smas!=NULL) kfree(smas);
|
||||
if(stxb!=NULL) free_pages((unsigned long)stxb, get_order(IMAGE_DMA_SIZE));
|
||||
if(srxb!=NULL) free_pages((unsigned long)srxb, get_order(IMAGE_DMA_SIZE));
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memset(stxb,0x00,get_order(IMAGE_DMA_SIZE));
|
||||
memset(srxb,0x00,get_order(IMAGE_DMA_SIZE));
|
||||
|
||||
#ifdef CONFIG_PM_WAKELOCKS
|
||||
//wakeup_source_init(&gProcessWakeLock, "microarray_process_wakelock");
|
||||
//wakeup_source_add(&gProcessWakeLock, "microarray_process_wakelock");
|
||||
gProcessWakeLock = wakeup_source_register(NULL,"microarray_process_wakelock");
|
||||
#else
|
||||
wake_lock_init(&gProcessWakeLock, WAKE_LOCK_SUSPEND, "microarray_process_wakelock");
|
||||
#endif
|
||||
|
||||
INIT_WORK(&gWork, mas_work);
|
||||
gWorkq = create_singlethread_workqueue("mas_workqueue");
|
||||
if (!gWorkq) {
|
||||
MALOGW("create_single_workqueue error!");
|
||||
return -ENOMEM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int deinit_vars(void)
|
||||
{
|
||||
destroy_workqueue(gWorkq);
|
||||
//wake_lock_destroy(&gProcessWakeLock);
|
||||
wakeup_source_unregister(gProcessWakeLock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init_spi(struct spi_device *spi){
|
||||
smas->spi = spi;
|
||||
smas->spi->max_speed_hz = SPI_SPEED;
|
||||
spi_setup(spi);
|
||||
INIT_LIST_HEAD(&smas->dev_entry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int deinit_spi(struct spi_device *spi){
|
||||
smas->spi = NULL;
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* init_connect function to check whether the chip is microarray's
|
||||
* @return 0 not 1 yes
|
||||
* param void
|
||||
*/
|
||||
int init_connect(void){
|
||||
int i;
|
||||
MALOGD("start");
|
||||
for(i=0; i<4; i++){
|
||||
stxb[0] = 0x8c;
|
||||
stxb[1] = 0xff;
|
||||
stxb[2] = 0xff;
|
||||
stxb[3] = 0xff;
|
||||
#ifdef TEE_ID_COMPATIBLE_TRUSTKERNEL
|
||||
mas_tee_spi_transfer(stxb, srxb, 4);
|
||||
#else
|
||||
mas_sync(stxb, srxb, 4);
|
||||
#endif
|
||||
msleep(8);
|
||||
stxb[0] = 0x00;
|
||||
stxb[1] = 0xff;
|
||||
stxb[2] = 0xff;
|
||||
stxb[3] = 0xff;
|
||||
#ifdef TEE_ID_COMPATIBLE_TRUSTKERNEL
|
||||
ret = mas_tee_spi_transfer(stxb, srxb, 4);
|
||||
#else
|
||||
ret = mas_sync(stxb, srxb, 4);
|
||||
#endif
|
||||
if(ret!=0) MALOGW("do init_connect failed!");
|
||||
printk("guq srxb[3] = %d srxb[2] = %d\n", srxb[3], srxb[2]);
|
||||
if(srxb[3] == 0x41 || srxb[3] == 0x45) return 1;
|
||||
}
|
||||
MALOGD("end");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int deinit_connect(void){
|
||||
mas_free_dts_info();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mas_fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data){
|
||||
struct fb_event *evdata = data;
|
||||
unsigned int blank;
|
||||
if(event != FB_EVENT_BLANK) {
|
||||
return 0;
|
||||
}
|
||||
blank = *(int *)evdata->data;
|
||||
switch(blank){
|
||||
case FB_BLANK_UNBLANK:
|
||||
is_screen_on = 1;
|
||||
break;
|
||||
case FB_BLANK_POWERDOWN:
|
||||
is_screen_on = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
screen_flag = 1;
|
||||
wake_up(&screenwaitq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init_notifier_call(void);
|
||||
static int deinit_notifier_call(void);
|
||||
|
||||
static int init_notifier_call(){
|
||||
notifier.notifier_call = mas_fb_notifier_callback;
|
||||
fb_register_client(¬ifier);
|
||||
is_screen_on = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int deinit_notifier_call(){
|
||||
fb_unregister_client(¬ifier);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mas_plat_probe(struct platform_device *pdev) {
|
||||
MALOGD("start");
|
||||
ret = mas_finger_get_gpio_info(pdev);
|
||||
if(ret){
|
||||
MALOGE("mas_plat_probe do mas_finger_get_gpio_info");
|
||||
}
|
||||
ret = mas_finger_set_gpio_info(1);
|
||||
if(ret){
|
||||
MALOGE("mas_plat_probe do mas_finger_set_gpio_info");
|
||||
}
|
||||
MALOGD("end");
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mas_plat_remove(struct platform_device *pdev) {
|
||||
mas_finger_set_gpio_info(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int mas_probe(struct spi_device *spi) {
|
||||
|
||||
int ret = 0;
|
||||
|
||||
MALOGD("start");
|
||||
|
||||
mas_do_some_for_probe(spi);
|
||||
ret = init_vars();
|
||||
if(ret){
|
||||
goto err1;
|
||||
}
|
||||
|
||||
MALOGD("start3333");
|
||||
ret = init_spi(spi);
|
||||
if(ret){
|
||||
goto err2;
|
||||
}
|
||||
#ifdef READ_CHIP_ID
|
||||
mas_enable_spi_clock(smas->spi);
|
||||
ret = init_connect();
|
||||
mas_disable_spi_clock(smas->spi);
|
||||
|
||||
|
||||
if(ret == 0){//not chip
|
||||
goto err3;
|
||||
} else {
|
||||
#ifdef TEE_ID_COMPATIBLE_MICROTRUST
|
||||
struct TEEC_UUID vendor_uuid = {0xedcf9395, 0x3518, 0x9067, { 0x61, 0x4c, 0xaf, 0xae, 0x29, 0x09, 0x77, 0x5b }};
|
||||
//memcpy(&uuid_ta, &vendor_uuid, sizeof(struct TEEC_UUID));
|
||||
memcpy(&uuid_fp, &vendor_uuid, sizeof(struct TEEC_UUID));
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
ret = 0;
|
||||
#endif
|
||||
|
||||
MALOGD("start11111");
|
||||
|
||||
|
||||
ret = init_interrupt();
|
||||
if(ret < 0){
|
||||
goto err4;
|
||||
}
|
||||
|
||||
MALOGD("start22222");
|
||||
ret = init_file_node();
|
||||
if(ret){
|
||||
goto err5;
|
||||
}
|
||||
|
||||
mas_set_input();
|
||||
MALOGF("end");
|
||||
ret = init_notifier_call();
|
||||
if(ret != 0){
|
||||
ret = -ENODEV;
|
||||
goto err6;
|
||||
}
|
||||
|
||||
|
||||
MALOGD("end1111");
|
||||
return ret;
|
||||
|
||||
err6:
|
||||
deinit_notifier_call();
|
||||
err5:
|
||||
deinit_file_node();
|
||||
err4:
|
||||
deinit_interrupt();
|
||||
#ifdef READ_CHIP_ID
|
||||
err3:
|
||||
deinit_connect();
|
||||
#endif
|
||||
err2:
|
||||
deinit_spi(spi);
|
||||
err1:
|
||||
deinit_vars();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mas_remove(struct spi_device *spi) {
|
||||
deinit_file_node();
|
||||
deinit_interrupt();
|
||||
deinit_vars();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int __init mas_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
MALOGF("start");
|
||||
compatible = 1;
|
||||
ret = mas_get_platform();
|
||||
if(ret){
|
||||
MALOGE("mas_get_platform");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit mas_exit(void)
|
||||
{
|
||||
}
|
||||
|
||||
late_initcall_sync(mas_init);
|
||||
module_exit(mas_exit);
|
||||
|
||||
MODULE_AUTHOR("Microarray");
|
||||
MODULE_DESCRIPTION("Driver for microarray fingerprint sensor");
|
||||
MODULE_LICENSE("GPL");
|
||||
236
drivers/input/fingerprint/microarray_fp/madev.h
Normal file
236
drivers/input/fingerprint/microarray_fp/madev.h
Normal file
@@ -0,0 +1,236 @@
|
||||
/* Copyright (C) MicroArray
|
||||
* MicroArray Fprint Driver Code * madev.h
|
||||
* Date: 2017-3-15
|
||||
* Version: v4.0.06
|
||||
* Author: guq
|
||||
* Contact: guq@microarray.com.cn
|
||||
*/
|
||||
|
||||
#ifndef __MADEV_H_
|
||||
#define __MADEV_H_
|
||||
|
||||
// #define CONFIG_PM_WAKELOCKS
|
||||
|
||||
//settings macro
|
||||
#define MTK //[MTK|QUALCOMM|SPRD|X86]
|
||||
|
||||
//#define READ_CHIP_ID //detect the chip id when defined
|
||||
|
||||
#define MALOGD_LEVEL KERN_EMERG //[KERN_DEBUG|KERN_EMERG] usually, the debug level is used for the release version
|
||||
|
||||
#define MA_CHR_FILE_NAME "madev0" //do not neeed modify usually
|
||||
#define MA_CHR_DEV_NAME "madev" //do not neeed modify usually
|
||||
|
||||
#define MA_EINT_NAME "mediatek,finger_print-eint"
|
||||
|
||||
|
||||
//#define DOUBLE_EDGE_IRQ
|
||||
|
||||
//#define COMPATIBLE_VERSION3
|
||||
|
||||
//key define just modify the KEY_FN_* for different platform
|
||||
#define FINGERPRINT_SWIPE_UP KEY_FN_F1//827
|
||||
#define FINGERPRINT_SWIPE_DOWN KEY_FN_F2//828
|
||||
#define FINGERPRINT_SWIPE_LEFT KEY_FN_F3//829
|
||||
#define FINGERPRINT_SWIPE_RIGHT KEY_FN_F4//830
|
||||
#define FINGERPRINT_TAP KEY_FN_F9// 831
|
||||
#define FINGERPRINT_DTAP KEY_FN_F6// 832
|
||||
#define FINGERPRINT_LONGPRESS KEY_FN_F7//833
|
||||
|
||||
//key define end
|
||||
|
||||
|
||||
//old macro
|
||||
#define SPI_SPEED (4*1000000) //120/121:10M, 80/81:6M
|
||||
|
||||
//表面类型
|
||||
#define COVER_T 1
|
||||
#define COVER_N 2
|
||||
#define COVER_M 3
|
||||
#define COVER_NUM COVER_N
|
||||
|
||||
//指纹类型
|
||||
#define AFS120 0x78
|
||||
//#define AFS80 0x50
|
||||
|
||||
#define FBUF (32*1024)
|
||||
|
||||
#if defined(AFS120)
|
||||
#define W 120 //宽
|
||||
#define H 120 //高
|
||||
#define WBUF 121
|
||||
#elif defined(AFS80)
|
||||
#define W 80 //宽
|
||||
#define H 192 //高
|
||||
#define WBUF 81
|
||||
#define FIMG (W*H)
|
||||
#endif
|
||||
|
||||
//settings macro end
|
||||
#include <linux/poll.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/fb.h>
|
||||
//this two head file for the screen on/off test
|
||||
#include <linux/freezer.h>
|
||||
|
||||
#include <asm/ioctl.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/ioctl.h>
|
||||
//#include <linux/wakelock.h>
|
||||
//#include <linux/pm_wakeup.h>
|
||||
|
||||
#ifdef CONFIG_PM_WAKELOCKS
|
||||
#include <linux/pm_wakeup.h>
|
||||
#else
|
||||
#include <linux/wakelock.h>
|
||||
#endif
|
||||
|
||||
#include <linux/mm.h>
|
||||
#include "ioctl_cmd.h"
|
||||
|
||||
#ifdef MTK
|
||||
#include "mtk-settings.h"
|
||||
#elif defined QUALCOMM
|
||||
#include "qualcomm-settings.h"
|
||||
#elif defined SPRD
|
||||
#include "sprd-settings.h"
|
||||
#elif defined X86
|
||||
#include "x86-settings.h"
|
||||
#endif
|
||||
|
||||
|
||||
//value define
|
||||
//fprint_spi struct use to save the value
|
||||
struct fprint_spi {
|
||||
u8 do_what; //工作内容
|
||||
u8 f_wake; //唤醒标志
|
||||
int value;
|
||||
volatile u8 f_irq; //中断标志
|
||||
volatile u8 u1_flag; //reserve for ours thread interrupt
|
||||
volatile u8 u2_flag; //reserve for ours thread interrupt
|
||||
volatile u8 f_repo; //上报开关
|
||||
spinlock_t spi_lock;
|
||||
struct spi_device *spi;
|
||||
struct list_head dev_entry;
|
||||
struct spi_message msg;
|
||||
struct spi_transfer xfer;
|
||||
struct input_dev *input;
|
||||
struct work_struct work;
|
||||
struct workqueue_struct *workq;
|
||||
#ifdef CONFIG_HAS_EARLYSUSPEND
|
||||
struct early_suspend suspend;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM_WAKELOCKS
|
||||
struct wakeup_source wl;
|
||||
#else
|
||||
struct wake_lock wl;
|
||||
#endif
|
||||
};
|
||||
//end
|
||||
|
||||
struct fprint_dev {
|
||||
dev_t idd;
|
||||
int major;
|
||||
int minor;
|
||||
struct cdev *chd;
|
||||
struct class *cls;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
|
||||
//function define
|
||||
|
||||
//extern the settings.h function
|
||||
extern void mas_select_transfer(struct spi_device *spi, int len);
|
||||
extern int mas_finger_get_gpio_info(struct platform_device *pdev);
|
||||
extern int mas_finger_set_gpio_info(int cmd);
|
||||
extern void mas_enable_spi_clock(struct spi_device *spi);
|
||||
extern void mas_disable_spi_clock(struct spi_device *spi);
|
||||
extern unsigned int mas_get_irq(struct device *dev);
|
||||
extern int mas_get_platform(void);
|
||||
extern int mas_remove_platform(void);
|
||||
extern void ma_spi_change(struct spi_device *spi, unsigned int speed, int flag);
|
||||
extern int mas_get_interrupt_gpio(unsigned int index);
|
||||
extern int mas_switch_power(unsigned int on_off);
|
||||
extern int mas_do_some_for_probe(struct spi_device *spi);
|
||||
//end
|
||||
|
||||
//use for the log print
|
||||
#define MALOG_TAG "MAFP_"
|
||||
//#define MALOGE(x) printk(KERN_ERR "%s%s: error log! the function %s is failed, ret = %d\n", MALOG_TAG, __func__, x, ret); //error log
|
||||
//#define MALOGF(x) printk(MALOGD_LEVEL "%s%s: debug log! %s!\n", MALOG_TAG, __func__, x); //flag log
|
||||
//#define MALOGD(x) MALOGF(x) //debug log
|
||||
//#define MALOGW(x) printk(KERN_WARNING "%s%s: warning log! the function %s's ret = %d\n", MALOG_TAG, __func__,x, ret); //warning log
|
||||
//use for the log print
|
||||
|
||||
#define MALOGD(fmt, args...) do{printk(KERN_ERR "<mafp>-dbg-[%04d]-[@%s]" fmt "\n", __LINE__, __FUNCTION__, ##args);}while(0)
|
||||
#define MALOGE(fmt, args...) do{printk(KERN_ERR "<mafp>-err-[%04d]-[@%s]" fmt "\n", __LINE__, __FUNCTION__, ##args);}while(0)
|
||||
#define MALOGF(x) do{printk(KERN_ERR "<mafp>-fun-[%04d]-[@%s] is called!\n", __LINE__, __FUNCTION__);}while(0)
|
||||
#define MALOGW(fmt, args...) do{printk(KERN_ERR "<mafp>-warn-[%04d]-[@%s]" fmt "\n", __LINE__, __FUNCTION__, ##args);}while(0)
|
||||
|
||||
|
||||
/**
|
||||
* the old ioctl command, compatible for the old version
|
||||
*/
|
||||
//ioctl cmd
|
||||
#ifdef COMPATIBLE_VERSION3
|
||||
#define IOCTL_DEBUG 0x100 //调试信息 //debug message
|
||||
#define IOCTL_IRQ_ENABLE 0x101 //中断使能 //enable interrupt
|
||||
#define IOCTL_SPI_SPEED 0x102 //SPI速度 //spi speed
|
||||
#define IOCTL_READ_FLEN 0x103 //读帧长度(保留) //the length of one frame
|
||||
#define IOCTL_LINK_DEV 0x104 //连接设备(保留) //connect the device
|
||||
#define IOCTL_COVER_NUM 0x105 //材料编号 //the index of the material
|
||||
#define IOCTL_GET_VDATE 0x106 //版本日期 //the date fo the version
|
||||
|
||||
#define IOCTL_CLR_INTF 0x110 //清除中断标志
|
||||
#define IOCTL_GET_INTF 0x111 //获取中断标志
|
||||
#define IOCTL_REPORT_FLAG 0x112 //上报标志
|
||||
#define IOCTL_REPORT_KEY 0x113 //上报键值
|
||||
#define IOCTL_SET_WORK 0x114 //设置工作
|
||||
#define IOCTL_GET_WORK 0x115 //获取工作
|
||||
#define IOCTL_SET_VALUE 0x116 //设值
|
||||
#define IOCTL_GET_VALUE 0x117 //取值
|
||||
#define IOCTL_TRIGGER 0x118 //自触发
|
||||
#define IOCTL_WAKE_LOCK 0x119 //唤醒上锁
|
||||
#define IOCTL_WAKE_UNLOCK 0x120 //唤醒解锁
|
||||
|
||||
#define IOCTL_SCREEN_ON 0x121
|
||||
|
||||
#define IOCTL_KEY_DOWN 0x121 //按下
|
||||
#define IOCTL_KEY_UP 0x122 //抬起
|
||||
#define IOCTL_SET_X 0x123 //偏移X
|
||||
#define IOCTL_SET_Y 0x124 //偏移Y
|
||||
#define IOCTL_KEY_TAP 0x125 //单击
|
||||
#define IOCTL_KEY_DTAP 0x126 //双击
|
||||
#define IOCTL_KEY_LTAP 0x127 //长按
|
||||
|
||||
#define IOCTL_ENABLE_CLK 0x128
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#endif /* __MADEV_H_ */
|
||||
|
||||
486
drivers/input/fingerprint/microarray_fp/mtk-settings.c
Normal file
486
drivers/input/fingerprint/microarray_fp/mtk-settings.c
Normal file
@@ -0,0 +1,486 @@
|
||||
/* Copyright (C) MicroArray
|
||||
* MicroArray Fprint Driver Code
|
||||
* mtk-settings.c
|
||||
* Date: 2017-3-15
|
||||
* Version: v4.0.06
|
||||
* Author: guq
|
||||
* Contact: guq@microarray.com.cn
|
||||
*/
|
||||
|
||||
#include "mtk-settings.h"
|
||||
|
||||
#ifdef TEE_ID_COMPATIBLE_TRUSTKERNEL
|
||||
#include <linux/tee_fp.h>
|
||||
#endif
|
||||
static int ret;
|
||||
//pin control sturct data, define using for the dts settings,
|
||||
struct pinctrl *mas_finger_pinctrl;
|
||||
struct pinctrl_state *mas_finger_power2v8_on, *mas_finger_power2v8_off, //power2v8
|
||||
*mas_finger_power1v8_on, *mas_finger_power1v8_off, //power1v8
|
||||
*mas_finger_eint_on, *mas_finger_eint_off, //eint
|
||||
*mas_spi_ck_on, *mas_spi_ck_off, //for ck
|
||||
*mas_spi_cs_on, *mas_spi_cs_off, //for cs
|
||||
*mas_spi_mi_on, *mas_spi_mi_off, //for mi
|
||||
*mas_spi_mo_on, *mas_spi_mo_off, //for mo
|
||||
*mas_spi_default; //same odms only use default to setting the dts
|
||||
static struct device_node *node;
|
||||
|
||||
static unsigned int finger_int_pin;
|
||||
|
||||
/**
|
||||
* the platform struct start,for getting the platform device to set gpio state
|
||||
*/
|
||||
//#ifdef CONFIG_OF
|
||||
static struct of_device_id sof_match[] = {
|
||||
{ .compatible = MA_DTS_NAME, }, //this name is used for matching the dts device for settings the gpios
|
||||
};
|
||||
static struct of_device_id sof_dev_match[] = {
|
||||
{ .compatible = "microarray,microarray-fp", }, //this name is used for matching the dts device for settings the gpios
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sof_match);
|
||||
MODULE_DEVICE_TABLE(of, sof_dev_match);
|
||||
//#endif
|
||||
static struct platform_driver spdrv = {
|
||||
.probe = mas_plat_probe,
|
||||
.remove = mas_plat_remove,
|
||||
.driver = {
|
||||
.name = MA_DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
//#ifdef CONFIG_OF
|
||||
.of_match_table = sof_match,
|
||||
//#endif
|
||||
}
|
||||
};
|
||||
/**
|
||||
* the platform struct start,for getting the platform device to set gpio state end
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* the spi struct date start,for getting the spi_device to set the spi clock enable start
|
||||
*/
|
||||
|
||||
struct spi_device_id sdev_id = {MA_DRV_NAME, 0};
|
||||
struct spi_driver sdrv = {
|
||||
.driver = {
|
||||
.name = MA_DRV_NAME,
|
||||
.bus = &spi_bus_type,
|
||||
.owner = THIS_MODULE,
|
||||
#ifdef CONFIG_OF
|
||||
.of_match_table = sof_dev_match,
|
||||
#endif
|
||||
},
|
||||
.probe = mas_probe,
|
||||
.remove = mas_remove,
|
||||
.id_table = &sdev_id,
|
||||
};
|
||||
|
||||
#ifdef TEE_ID_COMPATIBLE_TRUSTKERNEL
|
||||
//driver end
|
||||
static struct mt_chip_conf smt_conf = {
|
||||
.setuptime=15,
|
||||
.holdtime=15,
|
||||
.high_time=15, // 10--6m 15--4m 20--3m 30--2m [ 60--1m 120--0.5m 300--0.2m]
|
||||
.low_time=15,
|
||||
.cs_idletime=15,
|
||||
.ulthgh_thrsh=0,
|
||||
.cpol=0,
|
||||
.cpha=0,
|
||||
.rx_mlsb=SPI_MSB,
|
||||
.tx_mlsb=SPI_MSB,
|
||||
.tx_endian=0,
|
||||
.rx_endian=0,
|
||||
.com_mod=FIFO_TRANSFER,
|
||||
.pause=0,
|
||||
.finish_intr=5,
|
||||
.deassert=0,
|
||||
.ulthigh=0,
|
||||
.tckdly=0,
|
||||
};
|
||||
#endif
|
||||
|
||||
struct spi_board_info smt_info[] __initdata = {
|
||||
[0] = {
|
||||
.modalias = MA_DRV_NAME,
|
||||
.max_speed_hz = (4*1000000),
|
||||
.bus_num = 0,
|
||||
.chip_select = 0,
|
||||
.mode = SPI_MODE_0,
|
||||
//.controller_data = &smt_conf,
|
||||
},
|
||||
};
|
||||
//device end
|
||||
|
||||
/**
|
||||
* the spi struct date start,for getting the spi_device to set the spi clock enable end
|
||||
*/
|
||||
|
||||
|
||||
void mas_select_transfer(struct spi_device *spi, int len) {
|
||||
/* static int mode = -1;
|
||||
int tmp = len>32? DMA_TRANSFER: FIFO_TRANSFER;
|
||||
struct mt_chip_conf *conf = NULL;
|
||||
if(tmp!=mode) {
|
||||
conf = (struct mt_chip_conf *) spi->controller_data;
|
||||
conf->com_mod = tmp;
|
||||
spi_setup(spi);
|
||||
mode = tmp;
|
||||
}*/
|
||||
}
|
||||
|
||||
/*
|
||||
* set spi speed, often we must check whether the setting is efficient
|
||||
*/
|
||||
|
||||
void ma_spi_change(struct spi_device *spi, unsigned int speed, int flag)
|
||||
{
|
||||
/* struct mt_chip_conf *mcc = (struct mt_chip_conf *)spi->controller_data;
|
||||
if(flag == 0) {
|
||||
mcc->com_mod = FIFO_TRANSFER;
|
||||
} else {
|
||||
mcc->com_mod = DMA_TRANSFER;
|
||||
}
|
||||
mcc->high_time = speed;
|
||||
mcc->low_time = speed;
|
||||
if(spi_setup(spi) < 0){
|
||||
MALOGE("change the spi error!\n");
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
int mas_do_some_for_probe(struct spi_device *spi){
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int mas_get_platform(void) {
|
||||
MALOGD("start!");
|
||||
ret = platform_driver_register(&spdrv);
|
||||
if(ret){
|
||||
MALOGE("platform_driver_register");
|
||||
}
|
||||
/*MALOGD("start board info");
|
||||
ret = spi_register_board_info(smt_info, ARRAY_SIZE(smt_info));
|
||||
if(ret){
|
||||
MALOGE("spi_register_board_info");
|
||||
}*/
|
||||
|
||||
MALOGD("start register spi");
|
||||
ret = spi_register_driver(&sdrv);
|
||||
if(ret) {
|
||||
MALOGE("spi_register_driver");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mas_remove_platform(void){
|
||||
spi_unregister_driver(&sdrv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mas_finger_get_gpio_info(struct platform_device *pdev){
|
||||
MALOGD("start!");
|
||||
node = of_find_compatible_node(NULL, NULL, MA_DTS_NAME);
|
||||
//pdev = of_find_device_by_node(node);
|
||||
mas_finger_pinctrl = devm_pinctrl_get(&pdev->dev);
|
||||
if (IS_ERR(mas_finger_pinctrl)) {
|
||||
ret = PTR_ERR(mas_finger_pinctrl);
|
||||
dev_err(&pdev->dev, "mas_finger_pinctrl cannot find pinctrl\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** this is the demo, setup follow the requirement
|
||||
* mas_finger_eint_on = pinctrl_lookup_state(mas_finger_pinctrl, "finger_int_as_int");
|
||||
* if (IS_ERR(mas_finger_eint_on)) {
|
||||
* ret = PTR_ERR(mas_finger_eint_on);
|
||||
* dev_err(&pdev->dev, " Cannot find mas_finger pinctrl mas_finger_eint_on!\n");
|
||||
* return ret;
|
||||
* }
|
||||
* if needed, change the dts label and the pinctrl for the other gpio
|
||||
*/
|
||||
|
||||
|
||||
mas_finger_power2v8_on = pinctrl_lookup_state(mas_finger_pinctrl, "finger_power_en1");
|
||||
if (IS_ERR(mas_finger_power2v8_on)) {
|
||||
ret = PTR_ERR(mas_finger_power2v8_on);
|
||||
dev_err(&pdev->dev, " Cannot find mas_finger_power2v8_on pinctrl!\n");
|
||||
return ret;
|
||||
}
|
||||
mas_finger_power2v8_off = pinctrl_lookup_state(mas_finger_pinctrl, "finger_power_en0");
|
||||
if (IS_ERR(mas_finger_power2v8_off)) {
|
||||
ret = PTR_ERR(mas_finger_power2v8_off);
|
||||
dev_err(&pdev->dev, " Cannot find mas_finger_power2v8_off pinctrl!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
mas_finger_power1v8_on = pinctrl_lookup_state(mas_finger_pinctrl, "finger_power_18v_en1");
|
||||
if (IS_ERR(mas_finger_power1v8_on)) {
|
||||
ret = PTR_ERR(mas_finger_power1v8_on);
|
||||
dev_err(&pdev->dev, " Cannot find mas_finger_power1v8_on pinctrl!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
mas_finger_power1v8_off = pinctrl_lookup_state(mas_finger_pinctrl, "finger_power_18v_en0");
|
||||
if (IS_ERR(mas_finger_power1v8_off)) {
|
||||
ret = PTR_ERR(mas_finger_power1v8_off);
|
||||
dev_err(&pdev->dev, " Cannot find mas_finger_power1v8_off pinctrl!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
mas_spi_mi_on = pinctrl_lookup_state(mas_finger_pinctrl, "finger_spi0_mi_as_spi0_mi");
|
||||
if (IS_ERR(mas_spi_mi_on)) {
|
||||
ret = PTR_ERR(mas_spi_mi_on);
|
||||
dev_err(&pdev->dev, " Cannot find mas_spi_mi_on pinctrl!\n");
|
||||
return ret;
|
||||
}
|
||||
mas_spi_mi_off = pinctrl_lookup_state(mas_finger_pinctrl, "finger_spi0_mi_as_gpio");
|
||||
if (IS_ERR(mas_spi_mi_off)) {
|
||||
ret = PTR_ERR(mas_spi_mi_off);
|
||||
dev_err(&pdev->dev, " Cannot find mas_spi_mi_off pinctrl!\n");
|
||||
return ret;
|
||||
}
|
||||
mas_spi_mo_on = pinctrl_lookup_state(mas_finger_pinctrl, "finger_spi0_mo_as_spi0_mo");
|
||||
if (IS_ERR(mas_spi_mo_on)) {
|
||||
ret = PTR_ERR(mas_spi_mo_on);
|
||||
dev_err(&pdev->dev, " Cannot find mas_spi_mo_on pinctrl!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
mas_spi_mo_off = pinctrl_lookup_state(mas_finger_pinctrl, "finger_spi0_mo_as_gpio");
|
||||
if (IS_ERR(mas_spi_mo_off)) {
|
||||
ret = PTR_ERR(mas_spi_mo_off);
|
||||
dev_err(&pdev->dev, " Cannot find mas_spi_mo_off!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
mas_spi_ck_on = pinctrl_lookup_state(mas_finger_pinctrl, "finger_spi0_clk_as_spi0_clk");
|
||||
if (IS_ERR(mas_spi_ck_on)) {
|
||||
ret = PTR_ERR(mas_spi_ck_on);
|
||||
dev_err(&pdev->dev, " Cannot find mas_spi_ck_on pinctrl!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
mas_spi_ck_off = pinctrl_lookup_state(mas_finger_pinctrl, "finger_spi0_clk_as_gpio");
|
||||
if (IS_ERR(mas_spi_ck_off)) {
|
||||
ret = PTR_ERR(mas_spi_ck_off);
|
||||
dev_err(&pdev->dev, " Cannot find mas_spi_ck_off pinctrl !\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
mas_spi_cs_on = pinctrl_lookup_state(mas_finger_pinctrl, "finger_spi0_cs_as_spi0_cs");
|
||||
if (IS_ERR(mas_spi_cs_on)) {
|
||||
ret = PTR_ERR(mas_spi_cs_on);
|
||||
dev_err(&pdev->dev, " Cannot find mas_spi_cs_on pinctrl!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
mas_spi_cs_off = pinctrl_lookup_state(mas_finger_pinctrl, "finger_spi0_cs_as_gpio");
|
||||
if (IS_ERR(mas_spi_cs_off)) {
|
||||
ret = PTR_ERR(mas_spi_cs_off);
|
||||
dev_err(&pdev->dev, " Cannot find mas_spi_cs_off pinctrl!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
mas_finger_eint_on = pinctrl_lookup_state(mas_finger_pinctrl, "finger_int_as_int");
|
||||
if (IS_ERR(mas_finger_eint_on)) {
|
||||
ret = PTR_ERR(mas_finger_eint_on);
|
||||
dev_err(&pdev->dev, " Cannot find mas_finger_eint_on pinctrl!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
MALOGD("end!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mas_free_dts_info(void)
|
||||
{
|
||||
if(mas_finger_pinctrl != NULL) devm_pinctrl_put(mas_finger_pinctrl);
|
||||
}
|
||||
|
||||
int mas_finger_set_spi(int cmd){
|
||||
//#if 0
|
||||
switch(cmd)
|
||||
{
|
||||
case 0:
|
||||
if( (!IS_ERR(mas_spi_cs_off)) & (!IS_ERR(mas_spi_ck_off)) & (!IS_ERR(mas_spi_mi_off)) & (!IS_ERR(mas_spi_mo_off)) ){
|
||||
pinctrl_select_state(mas_finger_pinctrl, mas_spi_cs_off);
|
||||
pinctrl_select_state(mas_finger_pinctrl, mas_spi_ck_off);
|
||||
pinctrl_select_state(mas_finger_pinctrl, mas_spi_mi_off);
|
||||
pinctrl_select_state(mas_finger_pinctrl, mas_spi_mo_off);
|
||||
}else{
|
||||
MALOGE("mas_spi_gpio_slect_pinctrl cmd=0 err!");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if( (!IS_ERR(mas_spi_cs_on)) & (!IS_ERR(mas_spi_ck_on)) & (!IS_ERR(mas_spi_mi_on)) & (!IS_ERR(mas_spi_mo_on)) ){
|
||||
pinctrl_select_state(mas_finger_pinctrl, mas_spi_cs_on);
|
||||
pinctrl_select_state(mas_finger_pinctrl, mas_spi_ck_on);
|
||||
pinctrl_select_state(mas_finger_pinctrl, mas_spi_mi_on);
|
||||
pinctrl_select_state(mas_finger_pinctrl, mas_spi_mo_on);
|
||||
}else{
|
||||
MALOGE("mas_spi_gpio_slect_pinctrl cmd=1 err!");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
//#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void mas_finger_set_reset(int count)
|
||||
{
|
||||
pinctrl_select_state(mas_finger_pinctrl, mas_finger_power1v8_on);
|
||||
mdelay(count);
|
||||
pinctrl_select_state(mas_finger_pinctrl, mas_finger_power1v8_off);
|
||||
}
|
||||
|
||||
|
||||
int mas_finger_set_power(int cmd)
|
||||
{
|
||||
|
||||
pinctrl_select_state(mas_finger_pinctrl, mas_finger_power2v8_on);
|
||||
#if 0
|
||||
switch (cmd)
|
||||
{
|
||||
case 0 :
|
||||
if( (!IS_ERR(mas_finger_power2v8_off)) & (!IS_ERR(mas_finger_power1v8_off)) ){
|
||||
pinctrl_select_state(mas_finger_pinctrl, mas_finger_power2v8_off);
|
||||
//pinctrl_select_state(mas_finger_pinctrl, mas_finger_power1v8_off);
|
||||
}else{
|
||||
MALOGE("mas_power_gpio_slect_pinctrl cmd=0 err!");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 1 :
|
||||
if( (!IS_ERR(mas_finger_power2v8_on)) & (!IS_ERR(mas_finger_power1v8_on)) ){
|
||||
pinctrl_select_state(mas_finger_pinctrl, mas_finger_power2v8_on);
|
||||
//pinctrl_select_state(mas_finger_pinctrl, mas_finger_power1v8_on);
|
||||
}else{
|
||||
MALOGE("mas_power_gpio_slect_pinctrl cmd=1 err!");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* this is a demo function,if the power on-off switch by other way
|
||||
* modify it as the right way
|
||||
* on_off 1 on 0 off
|
||||
*/
|
||||
int mas_switch_power(unsigned int on_off){
|
||||
mas_finger_set_power(on_off); //use this fuction directly if the dts way
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mas_finger_set_eint(int cmd)
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case 0 :
|
||||
if(!IS_ERR(mas_finger_eint_off)){
|
||||
pinctrl_select_state(mas_finger_pinctrl, mas_finger_eint_off);
|
||||
}else{
|
||||
MALOGE("mas_eint_gpio_slect_pinctrl cmd=0 err!");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 1 :
|
||||
if(!IS_ERR(mas_finger_eint_on)){
|
||||
pinctrl_select_state(mas_finger_pinctrl, mas_finger_eint_on);
|
||||
}else{
|
||||
MALOGE("mas_eint_gpio_slect_pinctrl cmd=1 err!");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int mas_finger_set_gpio_info(int cmd){
|
||||
ret = 0;
|
||||
MALOGD("start!");
|
||||
ret |= mas_finger_set_spi(cmd);
|
||||
ret |= mas_finger_set_power(cmd);
|
||||
// ret |= mas_finger_set_eint(cmd);
|
||||
MALOGD("end!");
|
||||
return ret;
|
||||
}
|
||||
|
||||
void mas_enable_spi_clock(struct spi_device *spi){
|
||||
|
||||
#if defined(TEE_ID_COMPATIBLE_TRUSTKERNEL) || defined(TEE_ID_COMPATIBLE_MICROTRUST)
|
||||
#ifdef CONFIG_MTK_CLKMGR
|
||||
enable_clock(MT_CG_PERI_SPI0, "spi");
|
||||
#elif defined(MT6797)
|
||||
mt_spi_enable_clk(spi_master_get_devdata(spi->master));
|
||||
#else
|
||||
mt_spi_enable_master_clk(spi);
|
||||
//enable_clk();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void mas_disable_spi_clock(struct spi_device *spi){
|
||||
|
||||
#if defined(TEE_ID_COMPATIBLE_TRUSTKERNEL) || defined(TEE_ID_COMPATIBLE_MICROTRUST)
|
||||
#ifdef CONFIG_MTK_CLKMGR
|
||||
disable_clock(MT_CG_PERI_SPI0, "spi");
|
||||
#elif defined(MT6797)
|
||||
mt_spi_disable_clk(spi_master_get_devdata(spi->master));
|
||||
#else
|
||||
mt_spi_disable_master_clk(spi);
|
||||
//disable_clk();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
int mas_tee_spi_transfer(u8 *txb, u8 *rxb, int len) {
|
||||
int val = 0;
|
||||
|
||||
#ifdef TEE_ID_COMPATIBLE_TRUSTKERNEL
|
||||
val = tee_spi_transfer(&smt_conf,sizeof(struct mt_chip_conf),txb, rxb, 4);
|
||||
#endif
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
unsigned int mas_get_irq(struct device *dev){
|
||||
int irq_num;
|
||||
finger_int_pin = of_get_named_gpio_flags(dev->of_node,
|
||||
"fingerprint,touch-int-gpio", 0, NULL);
|
||||
if (!gpio_is_valid(finger_int_pin)){
|
||||
MALOGE("invalid irq gpio!");
|
||||
return -EINVAL;
|
||||
}
|
||||
gpio_direction_input(finger_int_pin);
|
||||
irq_num = gpio_to_irq(finger_int_pin);
|
||||
return irq_num;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* this function used for check the interrupt gpio state
|
||||
* @index 0 gpio level 1 gpio mode, often use 0
|
||||
* @return 0 gpio low 1 gpio high if index = 1,the return is the gpio mode
|
||||
* under 0 the of_property_read_u32_index return errno,check the dts as below:
|
||||
* last but not least use this function must checkt the label on dts file, after is an example:
|
||||
* ma_finger: ma_finger{
|
||||
* compatible = "mediatek,afs120x";
|
||||
* finger_int_pin = <100 0>;
|
||||
* }
|
||||
*/
|
||||
int mas_get_interrupt_gpio(unsigned int index){
|
||||
int val;
|
||||
val = gpio_get_value(finger_int_pin);
|
||||
//printk if need
|
||||
return val;
|
||||
}
|
||||
|
||||
220
drivers/input/fingerprint/microarray_fp/mtk-settings.h
Normal file
220
drivers/input/fingerprint/microarray_fp/mtk-settings.h
Normal file
@@ -0,0 +1,220 @@
|
||||
/* Copyright (C) MicroArray
|
||||
* MicroArray Fprint Driver Code
|
||||
* mtk-settings.h
|
||||
* Date: 2017-3-15
|
||||
* Version: v4.0.06
|
||||
* Author: guq
|
||||
* Contact: guq@microarray.com.cn
|
||||
*/
|
||||
|
||||
#ifndef __MTK_SETTINGS_H_
|
||||
#define __MTK_SETTINGS_H_
|
||||
|
||||
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include "madev.h"
|
||||
#include <linux/spi/spi.h>
|
||||
//#include <linux/wakelock.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/spi/spi.h>
|
||||
////lude "mt_spi.h"
|
||||
//#include <linux/wakelock.h>
|
||||
////lude <mt-plat/mt_gpio.h>
|
||||
#ifdef CONFIG_MTK_CLKMGR
|
||||
#include "mach/mt_clkmgr.h"
|
||||
#endif
|
||||
//macro settings
|
||||
#include <linux/clk.h>
|
||||
|
||||
#define MA_DRV_NAME "madev"
|
||||
|
||||
#define MA_DTS_NAME "mediatek,microarray_finger"
|
||||
|
||||
#define MA_EINT_DTS_NAME "mediatek,microarray_finger"
|
||||
|
||||
#define MA_INT_PIN_LABEL "finger_int_pin"
|
||||
//#define TEE_ID_COMPATIBLE_TRUSTKERNEL //TrustKernel TEE
|
||||
//#define TEE_ID_COMPATIBLE_MICROTRUST //MicroTrust TEE
|
||||
//macro settings end
|
||||
|
||||
|
||||
|
||||
//call madev function
|
||||
extern int mas_plat_probe(struct platform_device *pdev);
|
||||
extern int mas_plat_remove(struct platform_device *pdev);
|
||||
|
||||
extern int mas_probe(struct spi_device *spi);
|
||||
extern int mas_remove(struct spi_device *spi);
|
||||
|
||||
/* add for spi cls ctl start */
|
||||
#ifdef CONFIG_SPI_MT65XX
|
||||
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
enum spi_sample_sel {
|
||||
POSEDGE,
|
||||
NEGEDGE
|
||||
};
|
||||
enum spi_cs_pol {
|
||||
ACTIVE_LOW,
|
||||
ACTIVE_HIGH
|
||||
};
|
||||
|
||||
enum spi_cpol {
|
||||
SPI_CPOL_0,
|
||||
SPI_CPOL_1
|
||||
};
|
||||
|
||||
enum spi_cpha {
|
||||
SPI_CPHA_0,
|
||||
SPI_CPHA_1
|
||||
};
|
||||
|
||||
enum spi_mlsb {
|
||||
SPI_LSB,
|
||||
SPI_MSB
|
||||
};
|
||||
|
||||
enum spi_endian {
|
||||
SPI_LENDIAN,
|
||||
SPI_BENDIAN
|
||||
};
|
||||
|
||||
enum spi_transfer_mode {
|
||||
FIFO_TRANSFER,
|
||||
DMA_TRANSFER,
|
||||
OTHER1,
|
||||
OTHER2,
|
||||
};
|
||||
|
||||
enum spi_pause_mode {
|
||||
PAUSE_MODE_DISABLE,
|
||||
PAUSE_MODE_ENABLE
|
||||
};
|
||||
enum spi_finish_intr {
|
||||
FINISH_INTR_DIS,
|
||||
FINISH_INTR_EN,
|
||||
};
|
||||
|
||||
enum spi_deassert_mode {
|
||||
DEASSERT_DISABLE,
|
||||
DEASSERT_ENABLE
|
||||
};
|
||||
|
||||
enum spi_ulthigh {
|
||||
ULTRA_HIGH_DISABLE,
|
||||
ULTRA_HIGH_ENABLE
|
||||
};
|
||||
|
||||
enum spi_tckdly {
|
||||
TICK_DLY0,
|
||||
TICK_DLY1,
|
||||
TICK_DLY2,
|
||||
TICK_DLY3
|
||||
};
|
||||
|
||||
struct mt_chip_conf {
|
||||
u32 setuptime;
|
||||
u32 holdtime;
|
||||
u32 high_time;
|
||||
u32 low_time;
|
||||
u32 cs_idletime;
|
||||
u32 ulthgh_thrsh;
|
||||
enum spi_sample_sel sample_sel;
|
||||
enum spi_cs_pol cs_pol;
|
||||
enum spi_cpol cpol;
|
||||
enum spi_cpha cpha;
|
||||
enum spi_mlsb tx_mlsb;
|
||||
enum spi_mlsb rx_mlsb;
|
||||
enum spi_endian tx_endian;
|
||||
enum spi_endian rx_endian;
|
||||
enum spi_transfer_mode com_mod;
|
||||
enum spi_pause_mode pause;
|
||||
enum spi_finish_intr finish_intr;
|
||||
enum spi_deassert_mode deassert;
|
||||
enum spi_ulthigh ulthigh;
|
||||
enum spi_tckdly tckdly;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
struct mt_spi_t {
|
||||
struct platform_device *pdev;
|
||||
void __iomem *regs;
|
||||
int irq;
|
||||
int running;
|
||||
//struct wake_lock wk_lock;
|
||||
struct mt_chip_conf *config;
|
||||
struct spi_master *master;
|
||||
|
||||
struct spi_transfer *cur_transfer;
|
||||
struct spi_transfer *next_transfer;
|
||||
|
||||
spinlock_t lock;
|
||||
struct list_head queue;
|
||||
#if !defined(CONFIG_MTK_CLKMGR)
|
||||
struct clk *clk_main;
|
||||
#endif
|
||||
};
|
||||
void mt_spi_enable_clk(struct mt_spi_t *ms);
|
||||
void mt_spi_disable_clk(struct mt_spi_t *ms);
|
||||
void mt_spi_enable_master_clk(struct spi_device *spidev);
|
||||
void mt_spi_disable_master_clk(struct spi_device *spidev);
|
||||
|
||||
/* add for spi cls ctl end this func only used in tee enviroment*/
|
||||
//packaging
|
||||
//void mas_enable_spi_clock(struct spi_device *spi);
|
||||
//void mas_diasble_spi_clock(struct spi_device *spi);
|
||||
//packaging end
|
||||
|
||||
//the interface called by madev
|
||||
void mas_select_transfer(struct spi_device *spi, int len);
|
||||
int mas_finger_get_gpio_info(struct platform_device *pdev);
|
||||
int mas_finger_set_gpio_info(int cmd);
|
||||
void mas_enable_spi_clock(struct spi_device *spi);
|
||||
void mas_disable_spi_clock(struct spi_device *spi);
|
||||
|
||||
unsigned int mas_get_irq(struct device *dev);
|
||||
int mas_get_platform(void);
|
||||
int mas_remove_platform(void);
|
||||
int mas_power(int cmd);
|
||||
int get_screen(void);
|
||||
void ma_spi_change(struct spi_device *spi, unsigned int speed, int flag);
|
||||
int mas_get_interrupt_gpio(unsigned int index);
|
||||
int mas_switch_power(unsigned int on_off);
|
||||
int mas_do_some_for_probe(struct spi_device *spi);
|
||||
void mas_finger_set_reset(int count);
|
||||
void mas_free_dts_info(void);
|
||||
int mas_tee_spi_transfer(u8 *txb, u8 *rxb, int len);
|
||||
#endif
|
||||
14
drivers/input/hall/Kconfig
Normal file
14
drivers/input/hall/Kconfig
Normal file
@@ -0,0 +1,14 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# hall sensor drivers configuration
|
||||
#
|
||||
|
||||
menuconfig HALL_DEVICE
|
||||
tristate "hall sensor device support"
|
||||
|
||||
if HALL_DEVICE
|
||||
|
||||
config HS_MH248
|
||||
tristate "hall sensor mh248"
|
||||
|
||||
endif
|
||||
2
drivers/input/hall/Makefile
Normal file
2
drivers/input/hall/Makefile
Normal file
@@ -0,0 +1,2 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
obj-$(CONFIG_HS_MH248) += mh248.o
|
||||
174
drivers/input/hall/mh248.c
Normal file
174
drivers/input/hall/mh248.c
Normal file
@@ -0,0 +1,174 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2020 Rockchip Electronics Co. Ltd.
|
||||
*
|
||||
* Author: Bin Yang <yangbin@rock-chips.com>
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/sensor-dev.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/rk_keys.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
struct mh248_para {
|
||||
struct device *dev;
|
||||
struct notifier_block fb_notif;
|
||||
struct mutex ops_lock;
|
||||
struct input_dev *hall_input;
|
||||
int is_suspend;
|
||||
int gpio_pin;
|
||||
int irq;
|
||||
int active_value;
|
||||
};
|
||||
|
||||
static int hall_fb_notifier_callback(struct notifier_block *self,
|
||||
unsigned long action, void *data)
|
||||
{
|
||||
struct mh248_para *mh248;
|
||||
struct fb_event *event = data;
|
||||
|
||||
mh248 = container_of(self, struct mh248_para, fb_notif);
|
||||
|
||||
if (action != FB_EVENT_BLANK)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
mutex_lock(&mh248->ops_lock);
|
||||
switch (*((int *)event->data)) {
|
||||
case FB_BLANK_UNBLANK:
|
||||
mh248->is_suspend = 0;
|
||||
break;
|
||||
default:
|
||||
mh248->is_suspend = 1;
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&mh248->ops_lock);
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static irqreturn_t hall_mh248_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct mh248_para *mh248 = (struct mh248_para *)dev_id;
|
||||
int gpio_value = 0;
|
||||
|
||||
gpio_value = gpio_get_value(mh248->gpio_pin);
|
||||
if ((gpio_value != mh248->active_value) &&
|
||||
(mh248->is_suspend == 0)) {
|
||||
input_report_key(mh248->hall_input, KEY_POWER, 1);
|
||||
input_sync(mh248->hall_input);
|
||||
input_report_key(mh248->hall_input, KEY_POWER, 0);
|
||||
input_sync(mh248->hall_input);
|
||||
} else if ((gpio_value == mh248->active_value) &&
|
||||
(mh248->is_suspend == 1)) {
|
||||
input_report_key(mh248->hall_input, KEY_WAKEUP, 1);
|
||||
input_sync(mh248->hall_input);
|
||||
input_report_key(mh248->hall_input, KEY_WAKEUP, 0);
|
||||
input_sync(mh248->hall_input);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int hall_mh248_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct mh248_para *mh248;
|
||||
enum of_gpio_flags irq_flags;
|
||||
int hallactive = 0;
|
||||
int ret = 0;
|
||||
|
||||
mh248 = devm_kzalloc(&pdev->dev, sizeof(*mh248), GFP_KERNEL);
|
||||
if (!mh248)
|
||||
return -ENOMEM;
|
||||
|
||||
mh248->dev = &pdev->dev;
|
||||
|
||||
mh248->gpio_pin = of_get_named_gpio_flags(np, "irq-gpio",
|
||||
0, &irq_flags);
|
||||
if (!gpio_is_valid(mh248->gpio_pin)) {
|
||||
dev_err(mh248->dev, "Can not read property irq-gpio\n");
|
||||
return mh248->gpio_pin;
|
||||
}
|
||||
mh248->irq = gpio_to_irq(mh248->gpio_pin);
|
||||
|
||||
of_property_read_u32(np, "hall-active", &hallactive);
|
||||
mh248->active_value = hallactive;
|
||||
mh248->is_suspend = 0;
|
||||
mutex_init(&mh248->ops_lock);
|
||||
|
||||
ret = devm_gpio_request_one(mh248->dev, mh248->gpio_pin,
|
||||
GPIOF_DIR_IN, "hall_mh248");
|
||||
if (ret < 0) {
|
||||
dev_err(mh248->dev, "fail to request gpio:%d\n", mh248->gpio_pin);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(mh248->dev, mh248->irq,
|
||||
NULL, hall_mh248_interrupt,
|
||||
irq_flags | IRQF_NO_SUSPEND | IRQF_ONESHOT,
|
||||
"hall_mh248", mh248);
|
||||
if (ret < 0) {
|
||||
dev_err(mh248->dev, "request irq(%d) failed, ret=%d\n",
|
||||
mh248->irq, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mh248->hall_input = devm_input_allocate_device(&pdev->dev);
|
||||
if (!mh248->hall_input) {
|
||||
dev_err(&pdev->dev, "Can't allocate hall input dev\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
mh248->hall_input->name = "hall wake key";
|
||||
input_set_capability(mh248->hall_input, EV_KEY, KEY_POWER);
|
||||
input_set_capability(mh248->hall_input, EV_KEY, KEY_WAKEUP);
|
||||
|
||||
ret = input_register_device(mh248->hall_input);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Unable to register input device, error: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
enable_irq_wake(mh248->irq);
|
||||
mh248->fb_notif.notifier_call = hall_fb_notifier_callback;
|
||||
fb_register_client(&mh248->fb_notif);
|
||||
dev_info(mh248->dev, "hall_mh248_probe success.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id hall_mh248_match[] = {
|
||||
{ .compatible = "hall-mh248" },
|
||||
{ /* Sentinel */ }
|
||||
};
|
||||
|
||||
static struct platform_driver hall_mh248_driver = {
|
||||
.probe = hall_mh248_probe,
|
||||
.driver = {
|
||||
.name = "mh248",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = hall_mh248_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(hall_mh248_driver);
|
||||
|
||||
MODULE_ALIAS("platform:mh248");
|
||||
MODULE_AUTHOR("Bin Yang <yangbin@rock-chips.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("Hall Sensor MH248 driver");
|
||||
Reference in New Issue
Block a user