sync: huiwei: e94a4cf98b93de7f711637033a43f0e2f5f3ac7a

merge into c2a6429c9b9d3fe12738317f410fb1b5cb96cb3b
This commit is contained in:
lin_jiayong
2024-01-27 18:55:31 +08:00
committed by Han Gao
parent a1feea7628
commit 698e02e86a
745 changed files with 916719 additions and 96 deletions

View File

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

View File

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

View 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

View 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/

View 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

View 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

View 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__ */

View 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(&notifier);
is_screen_on = 1;
return 0;
}
static int deinit_notifier_call(){
fb_unregister_client(&notifier);
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");

View 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_ */

View 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;
}

View 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

View 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

View 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
View 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");