drivers: input: fingerprint: Import Xiaomi drivers
* From munch-s-oss, thanks Xiaomi for not releasing them in dagu-s-oss * Run clang-format on source files Change-Id: Ia67bee9b717437c216cb44a25b36fbc595c9b9bb
This commit is contained in:
committed by
Sebastiano Barezzi
parent
80805de18a
commit
71eaf6fee4
@@ -213,6 +213,8 @@ source "drivers/input/misc/Kconfig"
|
||||
|
||||
source "drivers/input/rmi4/Kconfig"
|
||||
|
||||
source "drivers/input/fingerprint/Kconfig"
|
||||
|
||||
endif
|
||||
|
||||
menu "Hardware I/O ports"
|
||||
|
||||
@@ -31,3 +31,5 @@ obj-$(CONFIG_INPUT_KEYRESET) += keyreset.o
|
||||
obj-$(CONFIG_INPUT_KEYCOMBO) += keycombo.o
|
||||
|
||||
obj-$(CONFIG_RMI4_CORE) += rmi4/
|
||||
|
||||
obj-$(CONFIG_INPUT_FINGERPRINT) += fingerprint/
|
||||
|
||||
20
drivers/input/fingerprint/Kconfig
Normal file
20
drivers/input/fingerprint/Kconfig
Normal file
@@ -0,0 +1,20 @@
|
||||
#
|
||||
# Fingerprint driver configuration
|
||||
#
|
||||
menuconfig INPUT_FINGERPRINT
|
||||
bool "Fingerprints"
|
||||
help
|
||||
Say Y here, and a list of supported fingerprints will be displayed.
|
||||
This option doesn't affect the kernel.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
if INPUT_FINGERPRINT
|
||||
|
||||
source "drivers/input/fingerprint/fpc/Kconfig"
|
||||
source "drivers/input/fingerprint/fpc_fod/Kconfig"
|
||||
source "drivers/input/fingerprint/goodix/Kconfig"
|
||||
source "drivers/input/fingerprint/goodix_fod/Kconfig"
|
||||
source "drivers/input/fingerprint/goodix_fod_psy/Kconfig"
|
||||
|
||||
endif
|
||||
11
drivers/input/fingerprint/Makefile
Normal file
11
drivers/input/fingerprint/Makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
#
|
||||
# Makefile for the fingerprint drivers.
|
||||
#
|
||||
|
||||
# Each configuration option enables a list of files.
|
||||
|
||||
obj-$(CONFIG_FINGERPRINT_FPC) += fpc/
|
||||
obj-$(CONFIG_FINGERPRINT_FPC_FOD) += fpc_fod/
|
||||
obj-$(CONFIG_FINGERPRINT_GOODIX) += goodix/
|
||||
obj-$(CONFIG_FINGERPRINT_GOODIX_FOD) += goodix_fod/
|
||||
obj-$(CONFIG_FINGERPRINT_GOODIX_FOD_PSY) += goodix_fod_psy/
|
||||
9
drivers/input/fingerprint/fpc/Kconfig
Normal file
9
drivers/input/fingerprint/fpc/Kconfig
Normal file
@@ -0,0 +1,9 @@
|
||||
config FINGERPRINT_FPC
|
||||
tristate "Finger print card fpc"
|
||||
depends on INPUT_FINGERPRINT
|
||||
help
|
||||
Say Y here to enable support for retrieving self-test reports.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here.
|
||||
1
drivers/input/fingerprint/fpc/Makefile
Normal file
1
drivers/input/fingerprint/fpc/Makefile
Normal file
@@ -0,0 +1 @@
|
||||
obj-$(CONFIG_FINGERPRINT_FPC) += fpc1020_tee.o
|
||||
1103
drivers/input/fingerprint/fpc/fpc1020_tee.c
Normal file
1103
drivers/input/fingerprint/fpc/fpc1020_tee.c
Normal file
File diff suppressed because it is too large
Load Diff
10
drivers/input/fingerprint/fpc_fod/Kconfig
Normal file
10
drivers/input/fingerprint/fpc_fod/Kconfig
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
# FPC sensors
|
||||
#
|
||||
|
||||
config FINGERPRINT_FPC_FOD
|
||||
tristate "FPC1020 fingerprint sensor IRQ support"
|
||||
depends on INPUT_FINGERPRINT
|
||||
help
|
||||
If you say yes here you get IRQ support for the FPC1020 family
|
||||
of fingerprint sensors from Fingerprint Cards (FPC).
|
||||
1
drivers/input/fingerprint/fpc_fod/Makefile
Normal file
1
drivers/input/fingerprint/fpc_fod/Makefile
Normal file
@@ -0,0 +1 @@
|
||||
obj-$(CONFIG_FINGERPRINT_FPC_FOD) += fpc1020_platform_tee.o
|
||||
1340
drivers/input/fingerprint/fpc_fod/fpc1020_platform_tee.c
Normal file
1340
drivers/input/fingerprint/fpc_fod/fpc1020_platform_tee.c
Normal file
File diff suppressed because it is too large
Load Diff
9
drivers/input/fingerprint/goodix/Kconfig
Normal file
9
drivers/input/fingerprint/goodix/Kconfig
Normal file
@@ -0,0 +1,9 @@
|
||||
config FINGERPRINT_GOODIX
|
||||
tristate "Finger print card goodix"
|
||||
depends on INPUT_FINGERPRINT
|
||||
help
|
||||
Say Y here to enable support for retrieving self-test reports.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here.
|
||||
1
drivers/input/fingerprint/goodix/Makefile
Normal file
1
drivers/input/fingerprint/goodix/Makefile
Normal file
@@ -0,0 +1 @@
|
||||
obj-$(CONFIG_FINGERPRINT_GOODIX) += gf_spi.o platform.o netlink.o
|
||||
1114
drivers/input/fingerprint/goodix/gf_spi.c
Normal file
1114
drivers/input/fingerprint/goodix/gf_spi.c
Normal file
File diff suppressed because it is too large
Load Diff
165
drivers/input/fingerprint/goodix/gf_spi.h
Normal file
165
drivers/input/fingerprint/goodix/gf_spi.h
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* driver definition for sensor driver
|
||||
*
|
||||
* Coypright (c) 2017 Goodix
|
||||
* Copyright (C) 2022 XiaoMi, Inc.
|
||||
*/
|
||||
#ifndef __GF_SPI_H
|
||||
#define __GF_SPI_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/notifier.h>
|
||||
/**********************************************************/
|
||||
enum FP_MODE {
|
||||
GF_IMAGE_MODE = 0,
|
||||
GF_KEY_MODE,
|
||||
GF_SLEEP_MODE,
|
||||
GF_FF_MODE,
|
||||
GF_DEBUG_MODE = 0x56
|
||||
};
|
||||
|
||||
#define SUPPORT_NAV_EVENT
|
||||
|
||||
#if defined(SUPPORT_NAV_EVENT)
|
||||
#define GF_NAV_INPUT_UP KEY_UP
|
||||
#define GF_NAV_INPUT_DOWN KEY_DOWN
|
||||
#define GF_NAV_INPUT_LEFT KEY_LEFT
|
||||
#define GF_NAV_INPUT_RIGHT KEY_RIGHT
|
||||
#define GF_NAV_INPUT_CLICK KEY_VOLUMEDOWN
|
||||
#define GF_NAV_INPUT_DOUBLE_CLICK KEY_VOLUMEUP
|
||||
#define GF_NAV_INPUT_LONG_PRESS KEY_SEARCH
|
||||
#define GF_NAV_INPUT_HEAVY KEY_CHAT
|
||||
#endif
|
||||
|
||||
#define GF_KEY_INPUT_HOME KEY_HOME
|
||||
#define GF_KEY_INPUT_MENU KEY_MENU
|
||||
#define GF_KEY_INPUT_BACK KEY_BACK
|
||||
#define GF_KEY_INPUT_POWER KEY_POWER
|
||||
#define GF_KEY_INPUT_CAMERA KEY_CAMERA
|
||||
|
||||
#if defined(SUPPORT_NAV_EVENT)
|
||||
typedef enum gf_nav_event {
|
||||
GF_NAV_NONE = 0,
|
||||
GF_NAV_FINGER_UP,
|
||||
GF_NAV_FINGER_DOWN,
|
||||
GF_NAV_UP,
|
||||
GF_NAV_DOWN,
|
||||
GF_NAV_LEFT,
|
||||
GF_NAV_RIGHT,
|
||||
GF_NAV_CLICK,
|
||||
GF_NAV_HEAVY,
|
||||
GF_NAV_LONG_PRESS,
|
||||
GF_NAV_DOUBLE_CLICK,
|
||||
} gf_nav_event_t;
|
||||
#endif
|
||||
|
||||
typedef enum gf_key_event {
|
||||
GF_KEY_NONE = 0,
|
||||
GF_KEY_HOME,
|
||||
GF_KEY_POWER,
|
||||
GF_KEY_MENU,
|
||||
GF_KEY_BACK,
|
||||
GF_KEY_CAMERA,
|
||||
} gf_key_event_t;
|
||||
|
||||
struct gf_key {
|
||||
enum gf_key_event key;
|
||||
uint32_t value; /* key down = 1, key up = 0 */
|
||||
};
|
||||
|
||||
struct gf_key_map {
|
||||
unsigned int type;
|
||||
unsigned int code;
|
||||
};
|
||||
|
||||
struct gf_ioc_chip_info {
|
||||
unsigned char vendor_id;
|
||||
unsigned char mode;
|
||||
unsigned char operation;
|
||||
unsigned char reserved[5];
|
||||
};
|
||||
|
||||
#define GF_IOC_MAGIC 'g' /*define magic number*/
|
||||
#define GF_IOC_INIT _IOR(GF_IOC_MAGIC, 0, uint8_t)
|
||||
#define GF_IOC_EXIT _IO(GF_IOC_MAGIC, 1)
|
||||
#define GF_IOC_RESET _IO(GF_IOC_MAGIC, 2)
|
||||
#define GF_IOC_ENABLE_IRQ _IO(GF_IOC_MAGIC, 3)
|
||||
#define GF_IOC_DISABLE_IRQ _IO(GF_IOC_MAGIC, 4)
|
||||
#define GF_IOC_ENABLE_SPI_CLK _IOW(GF_IOC_MAGIC, 5, uint32_t)
|
||||
#define GF_IOC_DISABLE_SPI_CLK _IO(GF_IOC_MAGIC, 6)
|
||||
#define GF_IOC_ENABLE_POWER _IO(GF_IOC_MAGIC, 7)
|
||||
#define GF_IOC_DISABLE_POWER _IO(GF_IOC_MAGIC, 8)
|
||||
#define GF_IOC_INPUT_KEY_EVENT _IOW(GF_IOC_MAGIC, 9, struct gf_key)
|
||||
#define GF_IOC_ENTER_SLEEP_MODE _IO(GF_IOC_MAGIC, 10)
|
||||
#define GF_IOC_GET_FW_INFO _IOR(GF_IOC_MAGIC, 11, uint8_t)
|
||||
#define GF_IOC_REMOVE _IO(GF_IOC_MAGIC, 12)
|
||||
#define GF_IOC_CHIP_INFO _IOW(GF_IOC_MAGIC, 13, struct gf_ioc_chip_info)
|
||||
|
||||
#if defined(SUPPORT_NAV_EVENT)
|
||||
#define GF_IOC_NAV_EVENT _IOW(GF_IOC_MAGIC, 14, gf_nav_event_t)
|
||||
#define GF_IOC_MAXNR 15 /* THIS MACRO IS NOT USED NOW... */
|
||||
#else
|
||||
#define GF_IOC_MAXNR 14 /* THIS MACRO IS NOT USED NOW... */
|
||||
#endif
|
||||
|
||||
/*#define AP_CONTROL_CLK 1*/
|
||||
#define USE_PLATFORM_BUS 1
|
||||
/*#define USE_SPI_BUS 1*/
|
||||
/*#define GF_FASYNC 1*/ /*If support fasync mechanism.*/
|
||||
#define CONFIG_FINGERPRINT_FP_VREG_CONTROL
|
||||
#ifndef CONFIG_FINGERPRINT_FP_VREG_CONTROL
|
||||
#define GF_PW_CTL 1
|
||||
#endif
|
||||
#define GF_NETLINK_ENABLE 1
|
||||
#define GF_NET_EVENT_IRQ 1
|
||||
#define GF_NET_EVENT_FB_BLACK 2
|
||||
#define GF_NET_EVENT_FB_UNBLACK 3
|
||||
#define NETLINK_TEST 25
|
||||
|
||||
struct gf_dev {
|
||||
dev_t devt;
|
||||
struct list_head device_entry;
|
||||
#if defined(USE_SPI_BUS)
|
||||
struct spi_device *spi;
|
||||
#elif defined(USE_PLATFORM_BUS)
|
||||
struct platform_device *spi;
|
||||
#endif
|
||||
struct clk *core_clk;
|
||||
struct clk *iface_clk;
|
||||
|
||||
struct input_dev *input;
|
||||
/* buffer is NULL unless this device is open (users > 0) */
|
||||
unsigned users;
|
||||
signed irq_gpio;
|
||||
signed reset_gpio;
|
||||
signed pwr_gpio;
|
||||
int irq;
|
||||
int irq_enabled;
|
||||
int clk_enabled;
|
||||
#ifdef GF_FASYNC
|
||||
struct fasync_struct *async;
|
||||
#endif
|
||||
struct notifier_block notifier;
|
||||
char device_available;
|
||||
char fb_black;
|
||||
char wait_finger_down;
|
||||
struct work_struct work;
|
||||
uint32_t key_flag; /*if not up, flag = 1*/
|
||||
#ifdef CONFIG_FINGERPRINT_FP_VREG_CONTROL
|
||||
struct regulator *vreg;
|
||||
#endif
|
||||
};
|
||||
|
||||
int gf_parse_dts(struct gf_dev *gf_dev);
|
||||
void gf_cleanup(struct gf_dev *gf_dev);
|
||||
|
||||
int gf_power_on(struct gf_dev *gf_dev);
|
||||
int gf_power_off(struct gf_dev *gf_dev);
|
||||
|
||||
int gf_hw_reset(struct gf_dev *gf_dev, unsigned int delay_ms);
|
||||
int gf_irq_num(struct gf_dev *gf_dev);
|
||||
|
||||
void sendnlmsg(char *message);
|
||||
int netlink_init(void);
|
||||
void netlink_exit(void);
|
||||
#endif /*__GF_SPI_H*/
|
||||
97
drivers/input/fingerprint/goodix/netlink.c
Normal file
97
drivers/input/fingerprint/goodix/netlink.c
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* netlink interface
|
||||
*
|
||||
* Copyright (c) 2017 Goodix
|
||||
* Copyright (C) 2022 XiaoMi, Inc.
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/types.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/netlink.h>
|
||||
|
||||
#define NETLINK_TEST 25
|
||||
#define MAX_MSGSIZE 32
|
||||
int stringlength(char *s);
|
||||
void sendnlmsg(char *message);
|
||||
static int pid = -1;
|
||||
struct sock *nl_sk;
|
||||
|
||||
void sendnlmsg(char *message)
|
||||
{
|
||||
struct sk_buff *skb_1;
|
||||
struct nlmsghdr *nlh;
|
||||
int len = NLMSG_SPACE(MAX_MSGSIZE);
|
||||
int slen = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (!message || !nl_sk || !pid) {
|
||||
return;
|
||||
}
|
||||
|
||||
skb_1 = alloc_skb(len, GFP_KERNEL);
|
||||
|
||||
if (!skb_1) {
|
||||
pr_err("alloc_skb error\n");
|
||||
return;
|
||||
}
|
||||
|
||||
slen = strlen(message);
|
||||
nlh = nlmsg_put(skb_1, 0, 0, 0, MAX_MSGSIZE, 0);
|
||||
NETLINK_CB(skb_1).portid = 0;
|
||||
NETLINK_CB(skb_1).dst_group = 0;
|
||||
message[slen] = '\0';
|
||||
memcpy(NLMSG_DATA(nlh), message, slen + 1);
|
||||
ret = netlink_unicast(nl_sk, skb_1, pid, MSG_DONTWAIT);
|
||||
|
||||
if (!ret) {
|
||||
/*kfree_skb(skb_1);*/
|
||||
pr_err("send msg from kernel to usespace failed ret 0x%x\n",
|
||||
ret);
|
||||
}
|
||||
}
|
||||
|
||||
void nl_data_ready(struct sk_buff *__skb)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct nlmsghdr *nlh;
|
||||
char str[100];
|
||||
skb = skb_get(__skb);
|
||||
|
||||
if (skb->len >= NLMSG_SPACE(0)) {
|
||||
nlh = nlmsg_hdr(skb);
|
||||
memcpy(str, NLMSG_DATA(nlh), sizeof(str));
|
||||
pid = nlh->nlmsg_pid;
|
||||
kfree_skb(skb);
|
||||
}
|
||||
}
|
||||
|
||||
int netlink_init(void)
|
||||
{
|
||||
struct netlink_kernel_cfg netlink_cfg;
|
||||
memset(&netlink_cfg, 0, sizeof(struct netlink_kernel_cfg));
|
||||
netlink_cfg.groups = 0;
|
||||
netlink_cfg.flags = 0;
|
||||
netlink_cfg.input = nl_data_ready;
|
||||
netlink_cfg.cb_mutex = NULL;
|
||||
nl_sk = netlink_kernel_create(&init_net, NETLINK_TEST, &netlink_cfg);
|
||||
|
||||
if (!nl_sk) {
|
||||
pr_err("create netlink socket error\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void netlink_exit(void)
|
||||
{
|
||||
if (nl_sk != NULL) {
|
||||
netlink_kernel_release(nl_sk);
|
||||
nl_sk = NULL;
|
||||
}
|
||||
|
||||
pr_info("self module exited\n");
|
||||
}
|
||||
142
drivers/input/fingerprint/goodix/platform.c
Normal file
142
drivers/input/fingerprint/goodix/platform.c
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* platform indepent driver interface
|
||||
*
|
||||
* Coypritht (c) 2017 Goodix
|
||||
* Copyright (C) 2022 XiaoMi, Inc.
|
||||
*/
|
||||
#define DEBUG
|
||||
#define pr_fmt(fmt) "gf_platform: " fmt
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include "gf_spi.h"
|
||||
|
||||
#if defined(USE_SPI_BUS)
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/spidev.h>
|
||||
#elif defined(USE_PLATFORM_BUS)
|
||||
#include <linux/platform_device.h>
|
||||
#endif
|
||||
|
||||
int gf_parse_dts(struct gf_dev *gf_dev)
|
||||
{
|
||||
#ifdef GF_PW_CTL
|
||||
/*get pwr resource*/
|
||||
gf_dev->pwr_gpio =
|
||||
of_get_named_gpio(gf_dev->spi->dev.of_node, "fp-gpio-pwr", 0);
|
||||
|
||||
if (!gpio_is_valid(gf_dev->pwr_gpio)) {
|
||||
pr_info("PWR GPIO is invalid.\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
#endif
|
||||
/*get reset resource*/
|
||||
gf_dev->reset_gpio = of_get_named_gpio(gf_dev->spi->dev.of_node,
|
||||
"goodix,gpio-reset", 0);
|
||||
|
||||
if (!gpio_is_valid(gf_dev->reset_gpio)) {
|
||||
pr_info("RESET GPIO is invalid.\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
/*get irq resourece*/
|
||||
gf_dev->irq_gpio = of_get_named_gpio(gf_dev->spi->dev.of_node,
|
||||
"goodix,gpio-irq", 0);
|
||||
pr_info("gf::irq_gpio:%d\n", gf_dev->irq_gpio);
|
||||
|
||||
if (!gpio_is_valid(gf_dev->irq_gpio)) {
|
||||
pr_info("IRQ GPIO is invalid.\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gf_cleanup(struct gf_dev *gf_dev)
|
||||
{
|
||||
pr_info("[info] %s\n", __func__);
|
||||
|
||||
if (gpio_is_valid(gf_dev->irq_gpio)) {
|
||||
gpio_free(gf_dev->irq_gpio);
|
||||
pr_info("remove irq_gpio success\n");
|
||||
}
|
||||
|
||||
if (gpio_is_valid(gf_dev->reset_gpio)) {
|
||||
gpio_free(gf_dev->reset_gpio);
|
||||
pr_info("remove reset_gpio success\n");
|
||||
}
|
||||
|
||||
#ifdef GF_PW_CTL
|
||||
|
||||
if (gpio_is_valid(gf_dev->pwr_gpio)) {
|
||||
gpio_free(gf_dev->pwr_gpio);
|
||||
pr_info("remove pwr_gpio success\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
int gf_power_on(struct gf_dev *gf_dev)
|
||||
{
|
||||
int rc = 0;
|
||||
#ifdef GF_PW_CTL
|
||||
|
||||
if (gpio_is_valid(gf_dev->pwr_gpio)) {
|
||||
rc = gpio_direction_output(gf_dev->pwr_gpio, 1);
|
||||
pr_info("---- power on result: %d----\n", rc);
|
||||
} else {
|
||||
pr_info("%s: gpio_is_invalid\n", __func__);
|
||||
}
|
||||
|
||||
#endif
|
||||
msleep(10);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int gf_power_off(struct gf_dev *gf_dev)
|
||||
{
|
||||
int rc = 0;
|
||||
#ifdef GF_PW_CTL
|
||||
|
||||
if (gpio_is_valid(gf_dev->pwr_gpio)) {
|
||||
rc = gpio_direction_output(gf_dev->pwr_gpio, 0);
|
||||
pr_info("---- power off result: %d----\n", rc);
|
||||
} else {
|
||||
pr_info("%s: gpio_is_invalid\n", __func__);
|
||||
}
|
||||
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
int gf_hw_reset(struct gf_dev *gf_dev, unsigned int delay_ms)
|
||||
{
|
||||
if (gf_dev == NULL) {
|
||||
pr_info("Input buff is NULL.\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
gpio_direction_output(gf_dev->reset_gpio, 0);
|
||||
mdelay(3);
|
||||
gpio_set_value(gf_dev->reset_gpio, 1);
|
||||
mdelay(delay_ms);
|
||||
pr_info("%s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gf_irq_num(struct gf_dev *gf_dev)
|
||||
{
|
||||
if (gf_dev == NULL) {
|
||||
pr_info("Input buff is NULL.\n");
|
||||
return -EPERM;
|
||||
} else {
|
||||
return gpio_to_irq(gf_dev->irq_gpio);
|
||||
}
|
||||
}
|
||||
9
drivers/input/fingerprint/goodix_fod/Kconfig
Normal file
9
drivers/input/fingerprint/goodix_fod/Kconfig
Normal file
@@ -0,0 +1,9 @@
|
||||
config FINGERPRINT_GOODIX_FOD
|
||||
tristate "Finger print card goodix"
|
||||
depends on INPUT_FINGERPRINT
|
||||
help
|
||||
Say Y here to enable support for retrieving self-test reports.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here.
|
||||
1
drivers/input/fingerprint/goodix_fod/Makefile
Normal file
1
drivers/input/fingerprint/goodix_fod/Makefile
Normal file
@@ -0,0 +1 @@
|
||||
obj-$(CONFIG_FINGERPRINT_GOODIX_FOD) += gf_spi.o platform.o netlink.o
|
||||
1085
drivers/input/fingerprint/goodix_fod/gf_spi.c
Normal file
1085
drivers/input/fingerprint/goodix_fod/gf_spi.c
Normal file
File diff suppressed because it is too large
Load Diff
160
drivers/input/fingerprint/goodix_fod/gf_spi.h
Normal file
160
drivers/input/fingerprint/goodix_fod/gf_spi.h
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* driver definition for sensor driver
|
||||
*
|
||||
* Coypright (c) 2017 Goodix
|
||||
*/
|
||||
#ifndef __GF_SPI_H
|
||||
#define __GF_SPI_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/notifier.h>
|
||||
/**********************************************************/
|
||||
enum FP_MODE {
|
||||
GF_IMAGE_MODE = 0,
|
||||
GF_KEY_MODE,
|
||||
GF_SLEEP_MODE,
|
||||
GF_FF_MODE,
|
||||
GF_DEBUG_MODE = 0x56
|
||||
};
|
||||
|
||||
#define SUPPORT_NAV_EVENT
|
||||
|
||||
#if defined(SUPPORT_NAV_EVENT)
|
||||
#define GF_NAV_INPUT_UP KEY_UP
|
||||
#define GF_NAV_INPUT_DOWN KEY_DOWN
|
||||
#define GF_NAV_INPUT_LEFT KEY_LEFT
|
||||
#define GF_NAV_INPUT_RIGHT KEY_RIGHT
|
||||
#define GF_NAV_INPUT_CLICK KEY_VOLUMEDOWN
|
||||
#define GF_NAV_INPUT_DOUBLE_CLICK KEY_VOLUMEUP
|
||||
#define GF_NAV_INPUT_LONG_PRESS KEY_SEARCH
|
||||
#define GF_NAV_INPUT_HEAVY KEY_CHAT
|
||||
#endif
|
||||
|
||||
#define GF_KEY_INPUT_HOME KEY_HOME
|
||||
#define GF_KEY_INPUT_MENU KEY_MENU
|
||||
#define GF_KEY_INPUT_BACK KEY_BACK
|
||||
#define GF_KEY_INPUT_POWER KEY_POWER
|
||||
#define GF_KEY_INPUT_CAMERA KEY_CAMERA
|
||||
|
||||
#if defined(SUPPORT_NAV_EVENT)
|
||||
typedef enum gf_nav_event {
|
||||
GF_NAV_NONE = 0,
|
||||
GF_NAV_FINGER_UP,
|
||||
GF_NAV_FINGER_DOWN,
|
||||
GF_NAV_UP,
|
||||
GF_NAV_DOWN,
|
||||
GF_NAV_LEFT,
|
||||
GF_NAV_RIGHT,
|
||||
GF_NAV_CLICK,
|
||||
GF_NAV_HEAVY,
|
||||
GF_NAV_LONG_PRESS,
|
||||
GF_NAV_DOUBLE_CLICK,
|
||||
} gf_nav_event_t;
|
||||
#endif
|
||||
|
||||
typedef enum gf_key_event {
|
||||
GF_KEY_NONE = 0,
|
||||
GF_KEY_HOME,
|
||||
GF_KEY_POWER,
|
||||
GF_KEY_MENU,
|
||||
GF_KEY_BACK,
|
||||
GF_KEY_CAMERA,
|
||||
} gf_key_event_t;
|
||||
|
||||
struct gf_key {
|
||||
enum gf_key_event key;
|
||||
uint32_t value; /* key down = 1, key up = 0 */
|
||||
};
|
||||
|
||||
struct gf_key_map {
|
||||
unsigned int type;
|
||||
unsigned int code;
|
||||
};
|
||||
|
||||
struct gf_ioc_chip_info {
|
||||
unsigned char vendor_id;
|
||||
unsigned char mode;
|
||||
unsigned char operation;
|
||||
unsigned char reserved[5];
|
||||
};
|
||||
|
||||
#define GF_IOC_MAGIC 'g' /*define magic number */
|
||||
#define GF_IOC_INIT _IOR(GF_IOC_MAGIC, 0, uint8_t)
|
||||
#define GF_IOC_EXIT _IO(GF_IOC_MAGIC, 1)
|
||||
#define GF_IOC_RESET _IO(GF_IOC_MAGIC, 2)
|
||||
#define GF_IOC_ENABLE_IRQ _IO(GF_IOC_MAGIC, 3)
|
||||
#define GF_IOC_DISABLE_IRQ _IO(GF_IOC_MAGIC, 4)
|
||||
#define GF_IOC_ENABLE_SPI_CLK _IOW(GF_IOC_MAGIC, 5, uint32_t)
|
||||
#define GF_IOC_DISABLE_SPI_CLK _IO(GF_IOC_MAGIC, 6)
|
||||
#define GF_IOC_ENABLE_POWER _IO(GF_IOC_MAGIC, 7)
|
||||
#define GF_IOC_DISABLE_POWER _IO(GF_IOC_MAGIC, 8)
|
||||
#define GF_IOC_INPUT_KEY_EVENT _IOW(GF_IOC_MAGIC, 9, struct gf_key)
|
||||
#define GF_IOC_ENTER_SLEEP_MODE _IO(GF_IOC_MAGIC, 10)
|
||||
#define GF_IOC_GET_FW_INFO _IOR(GF_IOC_MAGIC, 11, uint8_t)
|
||||
#define GF_IOC_REMOVE _IO(GF_IOC_MAGIC, 12)
|
||||
#define GF_IOC_CHIP_INFO _IOW(GF_IOC_MAGIC, 13, struct gf_ioc_chip_info)
|
||||
|
||||
#if defined(SUPPORT_NAV_EVENT)
|
||||
#define GF_IOC_NAV_EVENT _IOW(GF_IOC_MAGIC, 14, gf_nav_event_t)
|
||||
#define GF_IOC_MAXNR 15 /* THIS MACRO IS NOT USED NOW... */
|
||||
#else
|
||||
#define GF_IOC_MAXNR 14 /* THIS MACRO IS NOT USED NOW... */
|
||||
#endif
|
||||
|
||||
/*#define AP_CONTROL_CLK 1*/
|
||||
#define USE_PLATFORM_BUS 1
|
||||
/*#define USE_SPI_BUS 1*/
|
||||
/*#define GF_FASYNC 1*/ /*If support fasync mechanism. */
|
||||
#define GF_PW_CTL 1
|
||||
#define GF_NETLINK_ENABLE 1
|
||||
#define GF_NET_EVENT_IRQ 1
|
||||
#define GF_NET_EVENT_FB_BLACK 2
|
||||
#define GF_NET_EVENT_FB_UNBLACK 3
|
||||
#define NETLINK_TEST 25
|
||||
|
||||
struct gf_dev {
|
||||
dev_t devt;
|
||||
struct list_head device_entry;
|
||||
#if defined(USE_SPI_BUS)
|
||||
struct spi_device *spi;
|
||||
#elif defined(USE_PLATFORM_BUS)
|
||||
struct platform_device *spi;
|
||||
#endif
|
||||
struct clk *core_clk;
|
||||
struct clk *iface_clk;
|
||||
|
||||
struct input_dev *input;
|
||||
/* buffer is NULL unless this device is open (users > 0) */
|
||||
unsigned users;
|
||||
signed irq_gpio;
|
||||
signed reset_gpio;
|
||||
signed pwr_gpio;
|
||||
int irq;
|
||||
int irq_enabled;
|
||||
int clk_enabled;
|
||||
#ifdef GF_FASYNC
|
||||
struct fasync_struct *async;
|
||||
#endif
|
||||
struct notifier_block notifier;
|
||||
char device_available;
|
||||
char fb_black;
|
||||
char wait_finger_down;
|
||||
struct work_struct work;
|
||||
#ifdef CONFIG_FINGERPRINT_FP_VREG_CONTROL
|
||||
struct regulator *vreg;
|
||||
#endif
|
||||
};
|
||||
|
||||
int gf_parse_dts(struct gf_dev *gf_dev);
|
||||
void gf_cleanup(struct gf_dev *gf_dev);
|
||||
|
||||
int gf_power_on(struct gf_dev *gf_dev);
|
||||
int gf_power_off(struct gf_dev *gf_dev);
|
||||
|
||||
int gf_hw_reset(struct gf_dev *gf_dev, unsigned int delay_ms);
|
||||
int gf_irq_num(struct gf_dev *gf_dev);
|
||||
|
||||
void sendnlmsg(char *message);
|
||||
int netlink_init(void);
|
||||
void netlink_exit(void);
|
||||
#endif /*__GF_SPI_H*/
|
||||
96
drivers/input/fingerprint/goodix_fod/netlink.c
Normal file
96
drivers/input/fingerprint/goodix_fod/netlink.c
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* netlink interface
|
||||
*
|
||||
* Copyright (c) 2017 Goodix
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/types.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/netlink.h>
|
||||
|
||||
#define NETLINK_TEST 25
|
||||
#define MAX_MSGSIZE 32
|
||||
int stringlength(char *s);
|
||||
void sendnlmsg(char *message);
|
||||
static int pid = -1;
|
||||
struct sock *nl_sk;
|
||||
|
||||
void sendnlmsg(char *message)
|
||||
{
|
||||
struct sk_buff *skb_1;
|
||||
struct nlmsghdr *nlh;
|
||||
int len = NLMSG_SPACE(MAX_MSGSIZE);
|
||||
int slen = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (!message || !nl_sk || !pid) {
|
||||
return;
|
||||
}
|
||||
|
||||
skb_1 = alloc_skb(len, GFP_KERNEL);
|
||||
|
||||
if (!skb_1) {
|
||||
pr_err("alloc_skb error\n");
|
||||
return;
|
||||
}
|
||||
|
||||
slen = strlen(message);
|
||||
nlh = nlmsg_put(skb_1, 0, 0, 0, MAX_MSGSIZE, 0);
|
||||
NETLINK_CB(skb_1).portid = 0;
|
||||
NETLINK_CB(skb_1).dst_group = 0;
|
||||
message[slen] = '\0';
|
||||
memcpy(NLMSG_DATA(nlh), message, slen + 1);
|
||||
ret = netlink_unicast(nl_sk, skb_1, pid, MSG_DONTWAIT);
|
||||
|
||||
if (!ret) {
|
||||
/*kfree_skb(skb_1); */
|
||||
pr_err("send msg from kernel to usespace failed ret 0x%x\n",
|
||||
ret);
|
||||
}
|
||||
}
|
||||
|
||||
void nl_data_ready(struct sk_buff *__skb)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct nlmsghdr *nlh;
|
||||
char str[100];
|
||||
skb = skb_get(__skb);
|
||||
|
||||
if (skb->len >= NLMSG_SPACE(0)) {
|
||||
nlh = nlmsg_hdr(skb);
|
||||
memcpy(str, NLMSG_DATA(nlh), sizeof(str));
|
||||
pid = nlh->nlmsg_pid;
|
||||
kfree_skb(skb);
|
||||
}
|
||||
}
|
||||
|
||||
int netlink_init(void)
|
||||
{
|
||||
struct netlink_kernel_cfg netlink_cfg;
|
||||
memset(&netlink_cfg, 0, sizeof(struct netlink_kernel_cfg));
|
||||
netlink_cfg.groups = 0;
|
||||
netlink_cfg.flags = 0;
|
||||
netlink_cfg.input = nl_data_ready;
|
||||
netlink_cfg.cb_mutex = NULL;
|
||||
nl_sk = netlink_kernel_create(&init_net, NETLINK_TEST, &netlink_cfg);
|
||||
|
||||
if (!nl_sk) {
|
||||
pr_err("create netlink socket error\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void netlink_exit(void)
|
||||
{
|
||||
if (nl_sk != NULL) {
|
||||
netlink_kernel_release(nl_sk);
|
||||
nl_sk = NULL;
|
||||
}
|
||||
|
||||
pr_info("self module exited\n");
|
||||
}
|
||||
139
drivers/input/fingerprint/goodix_fod/platform.c
Normal file
139
drivers/input/fingerprint/goodix_fod/platform.c
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* platform indepent driver interface
|
||||
*
|
||||
* Coypritht (c) 2017 Goodix
|
||||
*/
|
||||
#define DEBUG
|
||||
#define pr_fmt(fmt) "gf_platform: " fmt
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include "gf_spi.h"
|
||||
|
||||
#if defined(USE_SPI_BUS)
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/spidev.h>
|
||||
#elif defined(USE_PLATFORM_BUS)
|
||||
#include <linux/platform_device.h>
|
||||
#endif
|
||||
|
||||
int gf_parse_dts(struct gf_dev *gf_dev)
|
||||
{
|
||||
#ifdef GF_PW_CTL
|
||||
/*get pwr resource */
|
||||
gf_dev->pwr_gpio =
|
||||
of_get_named_gpio(gf_dev->spi->dev.of_node, "fp-gpio-pwr", 0);
|
||||
|
||||
if (!gpio_is_valid(gf_dev->pwr_gpio)) {
|
||||
pr_info("PWR GPIO is invalid.\n");
|
||||
return -EPERM;
|
||||
}
|
||||
#endif
|
||||
/*get reset resource */
|
||||
gf_dev->reset_gpio = of_get_named_gpio(gf_dev->spi->dev.of_node,
|
||||
"goodix,gpio-reset", 0);
|
||||
|
||||
if (!gpio_is_valid(gf_dev->reset_gpio)) {
|
||||
pr_info("RESET GPIO is invalid.\n");
|
||||
return -EPERM;
|
||||
}
|
||||
pr_info("gf::gpio-reset:%d\n", gf_dev->reset_gpio);
|
||||
|
||||
/*get irq resourece */
|
||||
gf_dev->irq_gpio = of_get_named_gpio(gf_dev->spi->dev.of_node,
|
||||
"goodix,gpio-irq", 0);
|
||||
pr_info("gf::irq_gpio:%d\n", gf_dev->irq_gpio);
|
||||
|
||||
if (!gpio_is_valid(gf_dev->irq_gpio)) {
|
||||
pr_info("IRQ GPIO is invalid.\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gf_cleanup(struct gf_dev *gf_dev)
|
||||
{
|
||||
pr_info("[info] %s\n", __func__);
|
||||
|
||||
if (gpio_is_valid(gf_dev->irq_gpio)) {
|
||||
gpio_free(gf_dev->irq_gpio);
|
||||
pr_info("remove irq_gpio success\n");
|
||||
}
|
||||
|
||||
if (gpio_is_valid(gf_dev->reset_gpio)) {
|
||||
gpio_free(gf_dev->reset_gpio);
|
||||
pr_info("remove reset_gpio success\n");
|
||||
}
|
||||
#ifdef GF_PW_CTL
|
||||
|
||||
if (gpio_is_valid(gf_dev->pwr_gpio)) {
|
||||
gpio_free(gf_dev->pwr_gpio);
|
||||
pr_info("remove pwr_gpio success\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int gf_power_on(struct gf_dev *gf_dev)
|
||||
{
|
||||
int rc = 0;
|
||||
#ifdef GF_PW_CTL
|
||||
|
||||
if (gpio_is_valid(gf_dev->pwr_gpio)) {
|
||||
rc = gpio_direction_output(gf_dev->pwr_gpio, 1);
|
||||
pr_info("---- power on result: %d----\n", rc);
|
||||
} else {
|
||||
pr_info("%s: gpio_is_invalid\n", __func__);
|
||||
}
|
||||
|
||||
#endif
|
||||
msleep(10);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int gf_power_off(struct gf_dev *gf_dev)
|
||||
{
|
||||
int rc = 0;
|
||||
#ifdef GF_PW_CTL
|
||||
|
||||
if (gpio_is_valid(gf_dev->pwr_gpio)) {
|
||||
rc = gpio_direction_output(gf_dev->pwr_gpio, 0);
|
||||
pr_info("---- power off result: %d----\n", rc);
|
||||
} else {
|
||||
pr_info("%s: gpio_is_invalid\n", __func__);
|
||||
}
|
||||
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
int gf_hw_reset(struct gf_dev *gf_dev, unsigned int delay_ms)
|
||||
{
|
||||
if (gf_dev == NULL) {
|
||||
pr_info("Input buff is NULL.\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
gpio_direction_output(gf_dev->reset_gpio, 0);
|
||||
mdelay(3);
|
||||
gpio_set_value(gf_dev->reset_gpio, 1);
|
||||
mdelay(delay_ms);
|
||||
pr_info("%s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gf_irq_num(struct gf_dev *gf_dev)
|
||||
{
|
||||
if (gf_dev == NULL) {
|
||||
pr_info("Input buff is NULL.\n");
|
||||
return -EPERM;
|
||||
} else {
|
||||
return gpio_to_irq(gf_dev->irq_gpio);
|
||||
}
|
||||
}
|
||||
9
drivers/input/fingerprint/goodix_fod_psy/Kconfig
Normal file
9
drivers/input/fingerprint/goodix_fod_psy/Kconfig
Normal file
@@ -0,0 +1,9 @@
|
||||
config FINGERPRINT_GOODIX_FOD_PSY
|
||||
tristate "Finger print card goodix"
|
||||
depends on INPUT_FINGERPRINT
|
||||
help
|
||||
Say Y here to enable support for retrieving self-test reports.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here.
|
||||
1
drivers/input/fingerprint/goodix_fod_psy/Makefile
Normal file
1
drivers/input/fingerprint/goodix_fod_psy/Makefile
Normal file
@@ -0,0 +1 @@
|
||||
obj-$(CONFIG_FINGERPRINT_GOODIX_FOD_PSY) += gf_spi.o platform.o netlink.o
|
||||
1165
drivers/input/fingerprint/goodix_fod_psy/gf_spi.c
Normal file
1165
drivers/input/fingerprint/goodix_fod_psy/gf_spi.c
Normal file
File diff suppressed because it is too large
Load Diff
162
drivers/input/fingerprint/goodix_fod_psy/gf_spi.h
Normal file
162
drivers/input/fingerprint/goodix_fod_psy/gf_spi.h
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* driver definition for sensor driver
|
||||
*
|
||||
* Coypright (c) 2017 Goodix
|
||||
*/
|
||||
#ifndef __GF_SPI_H
|
||||
#define __GF_SPI_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/notifier.h>
|
||||
/**********************************************************/
|
||||
enum FP_MODE {
|
||||
GF_IMAGE_MODE = 0,
|
||||
GF_KEY_MODE,
|
||||
GF_SLEEP_MODE,
|
||||
GF_FF_MODE,
|
||||
GF_DEBUG_MODE = 0x56
|
||||
};
|
||||
|
||||
#define SUPPORT_NAV_EVENT
|
||||
|
||||
#if defined(SUPPORT_NAV_EVENT)
|
||||
#define GF_NAV_INPUT_UP KEY_UP
|
||||
#define GF_NAV_INPUT_DOWN KEY_DOWN
|
||||
#define GF_NAV_INPUT_LEFT KEY_LEFT
|
||||
#define GF_NAV_INPUT_RIGHT KEY_RIGHT
|
||||
#define GF_NAV_INPUT_CLICK KEY_VOLUMEDOWN
|
||||
#define GF_NAV_INPUT_DOUBLE_CLICK KEY_VOLUMEUP
|
||||
#define GF_NAV_INPUT_LONG_PRESS KEY_SEARCH
|
||||
#define GF_NAV_INPUT_HEAVY KEY_CHAT
|
||||
#endif
|
||||
|
||||
#define GF_KEY_INPUT_HOME KEY_HOME
|
||||
#define GF_KEY_INPUT_MENU KEY_MENU
|
||||
#define GF_KEY_INPUT_BACK KEY_BACK
|
||||
#define GF_KEY_INPUT_POWER KEY_POWER
|
||||
#define GF_KEY_INPUT_CAMERA KEY_CAMERA
|
||||
|
||||
#if defined(SUPPORT_NAV_EVENT)
|
||||
typedef enum gf_nav_event {
|
||||
GF_NAV_NONE = 0,
|
||||
GF_NAV_FINGER_UP,
|
||||
GF_NAV_FINGER_DOWN,
|
||||
GF_NAV_UP,
|
||||
GF_NAV_DOWN,
|
||||
GF_NAV_LEFT,
|
||||
GF_NAV_RIGHT,
|
||||
GF_NAV_CLICK,
|
||||
GF_NAV_HEAVY,
|
||||
GF_NAV_LONG_PRESS,
|
||||
GF_NAV_DOUBLE_CLICK,
|
||||
} gf_nav_event_t;
|
||||
#endif
|
||||
|
||||
typedef enum gf_key_event {
|
||||
GF_KEY_NONE = 0,
|
||||
GF_KEY_HOME,
|
||||
GF_KEY_POWER,
|
||||
GF_KEY_MENU,
|
||||
GF_KEY_BACK,
|
||||
GF_KEY_CAMERA,
|
||||
} gf_key_event_t;
|
||||
|
||||
struct gf_key {
|
||||
enum gf_key_event key;
|
||||
uint32_t value; /* key down = 1, key up = 0 */
|
||||
};
|
||||
|
||||
struct gf_key_map {
|
||||
unsigned int type;
|
||||
unsigned int code;
|
||||
};
|
||||
|
||||
struct gf_ioc_chip_info {
|
||||
unsigned char vendor_id;
|
||||
unsigned char mode;
|
||||
unsigned char operation;
|
||||
unsigned char reserved[5];
|
||||
};
|
||||
|
||||
#define GF_IOC_MAGIC 'g' /*define magic number */
|
||||
#define GF_IOC_INIT _IOR(GF_IOC_MAGIC, 0, uint8_t)
|
||||
#define GF_IOC_EXIT _IO(GF_IOC_MAGIC, 1)
|
||||
#define GF_IOC_RESET _IO(GF_IOC_MAGIC, 2)
|
||||
#define GF_IOC_ENABLE_IRQ _IO(GF_IOC_MAGIC, 3)
|
||||
#define GF_IOC_DISABLE_IRQ _IO(GF_IOC_MAGIC, 4)
|
||||
#define GF_IOC_ENABLE_SPI_CLK _IOW(GF_IOC_MAGIC, 5, uint32_t)
|
||||
#define GF_IOC_DISABLE_SPI_CLK _IO(GF_IOC_MAGIC, 6)
|
||||
#define GF_IOC_ENABLE_POWER _IO(GF_IOC_MAGIC, 7)
|
||||
#define GF_IOC_DISABLE_POWER _IO(GF_IOC_MAGIC, 8)
|
||||
#define GF_IOC_INPUT_KEY_EVENT _IOW(GF_IOC_MAGIC, 9, struct gf_key)
|
||||
#define GF_IOC_ENTER_SLEEP_MODE _IO(GF_IOC_MAGIC, 10)
|
||||
#define GF_IOC_GET_FW_INFO _IOR(GF_IOC_MAGIC, 11, uint8_t)
|
||||
#define GF_IOC_REMOVE _IO(GF_IOC_MAGIC, 12)
|
||||
#define GF_IOC_CHIP_INFO _IOW(GF_IOC_MAGIC, 13, struct gf_ioc_chip_info)
|
||||
|
||||
#if defined(SUPPORT_NAV_EVENT)
|
||||
#define GF_IOC_NAV_EVENT _IOW(GF_IOC_MAGIC, 14, gf_nav_event_t)
|
||||
#define GF_IOC_MAXNR 15 /* THIS MACRO IS NOT USED NOW... */
|
||||
#else
|
||||
#define GF_IOC_MAXNR 14 /* THIS MACRO IS NOT USED NOW... */
|
||||
#endif
|
||||
|
||||
/*#define AP_CONTROL_CLK 1*/
|
||||
#define USE_PLATFORM_BUS 1
|
||||
/*#define USE_SPI_BUS 1*/
|
||||
|
||||
/*If support fasync mechanism. */
|
||||
/*#define GF_PW_CTL 1*/
|
||||
#undef GF_PW_CTL
|
||||
#define GF_NETLINK_ENABLE 1
|
||||
#define GF_NET_EVENT_IRQ 1
|
||||
#define GF_NET_EVENT_FB_BLACK 2
|
||||
#define GF_NET_EVENT_FB_UNBLACK 3
|
||||
#define NETLINK_TEST 25
|
||||
|
||||
struct gf_dev {
|
||||
dev_t devt;
|
||||
struct list_head device_entry;
|
||||
#if defined(USE_SPI_BUS)
|
||||
struct spi_device *spi;
|
||||
#elif defined(USE_PLATFORM_BUS)
|
||||
struct platform_device *spi;
|
||||
#endif
|
||||
struct clk *core_clk;
|
||||
struct clk *iface_clk;
|
||||
|
||||
struct input_dev *input;
|
||||
/* buffer is NULL unless this device is open (users > 0) */
|
||||
unsigned users;
|
||||
signed irq_gpio;
|
||||
signed reset_gpio;
|
||||
signed pwr_gpio;
|
||||
int irq;
|
||||
int irq_enabled;
|
||||
int clk_enabled;
|
||||
#ifdef GF_FASYNC
|
||||
struct fasync_struct *async;
|
||||
#endif
|
||||
struct notifier_block notifier;
|
||||
char device_available;
|
||||
char fb_black;
|
||||
char wait_finger_down;
|
||||
struct work_struct work;
|
||||
#ifdef CONFIG_FINGERPRINT_FP_VREG_CONTROL
|
||||
struct regulator *vreg;
|
||||
#endif
|
||||
};
|
||||
|
||||
int gf_parse_dts(struct gf_dev *gf_dev);
|
||||
void gf_cleanup(struct gf_dev *gf_dev);
|
||||
|
||||
int gf_power_on(struct gf_dev *gf_dev);
|
||||
int gf_power_off(struct gf_dev *gf_dev);
|
||||
|
||||
int gf_hw_reset(struct gf_dev *gf_dev, unsigned int delay_ms);
|
||||
int gf_irq_num(struct gf_dev *gf_dev);
|
||||
|
||||
void sendnlmsg(char *message);
|
||||
int netlink_init(void);
|
||||
void netlink_exit(void);
|
||||
#endif /*__GF_SPI_H*/
|
||||
96
drivers/input/fingerprint/goodix_fod_psy/netlink.c
Normal file
96
drivers/input/fingerprint/goodix_fod_psy/netlink.c
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* netlink interface
|
||||
*
|
||||
* Copyright (c) 2017 Goodix
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/types.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/netlink.h>
|
||||
|
||||
#define NETLINK_TEST 25
|
||||
#define MAX_MSGSIZE 32
|
||||
int stringlength(char *s);
|
||||
void sendnlmsg(char *message);
|
||||
static int pid = -1;
|
||||
struct sock *nl_sk;
|
||||
|
||||
void sendnlmsg(char *message)
|
||||
{
|
||||
struct sk_buff *skb_1;
|
||||
struct nlmsghdr *nlh;
|
||||
int len = NLMSG_SPACE(MAX_MSGSIZE);
|
||||
int slen = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (!message || !nl_sk || !pid) {
|
||||
return;
|
||||
}
|
||||
|
||||
skb_1 = alloc_skb(len, GFP_KERNEL);
|
||||
|
||||
if (!skb_1) {
|
||||
pr_err("alloc_skb error\n");
|
||||
return;
|
||||
}
|
||||
|
||||
slen = strlen(message);
|
||||
nlh = nlmsg_put(skb_1, 0, 0, 0, MAX_MSGSIZE, 0);
|
||||
NETLINK_CB(skb_1).portid = 0;
|
||||
NETLINK_CB(skb_1).dst_group = 0;
|
||||
message[slen] = '\0';
|
||||
memcpy(NLMSG_DATA(nlh), message, slen + 1);
|
||||
ret = netlink_unicast(nl_sk, skb_1, pid, MSG_DONTWAIT);
|
||||
|
||||
if (!ret) {
|
||||
/*kfree_skb(skb_1); */
|
||||
pr_err("send msg from kernel to usespace failed ret 0x%x\n",
|
||||
ret);
|
||||
}
|
||||
}
|
||||
|
||||
void nl_data_ready(struct sk_buff *__skb)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct nlmsghdr *nlh;
|
||||
char str[100];
|
||||
skb = skb_get(__skb);
|
||||
|
||||
if (skb->len >= NLMSG_SPACE(0)) {
|
||||
nlh = nlmsg_hdr(skb);
|
||||
memcpy(str, NLMSG_DATA(nlh), sizeof(str));
|
||||
pid = nlh->nlmsg_pid;
|
||||
kfree_skb(skb);
|
||||
}
|
||||
}
|
||||
|
||||
int netlink_init(void)
|
||||
{
|
||||
struct netlink_kernel_cfg netlink_cfg;
|
||||
memset(&netlink_cfg, 0, sizeof(struct netlink_kernel_cfg));
|
||||
netlink_cfg.groups = 0;
|
||||
netlink_cfg.flags = 0;
|
||||
netlink_cfg.input = nl_data_ready;
|
||||
netlink_cfg.cb_mutex = NULL;
|
||||
nl_sk = netlink_kernel_create(&init_net, NETLINK_TEST, &netlink_cfg);
|
||||
|
||||
if (!nl_sk) {
|
||||
pr_err("create netlink socket error\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void netlink_exit(void)
|
||||
{
|
||||
if (nl_sk != NULL) {
|
||||
netlink_kernel_release(nl_sk);
|
||||
nl_sk = NULL;
|
||||
}
|
||||
|
||||
pr_info("self module exited\n");
|
||||
}
|
||||
139
drivers/input/fingerprint/goodix_fod_psy/platform.c
Normal file
139
drivers/input/fingerprint/goodix_fod_psy/platform.c
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* platform indepent driver interface
|
||||
*
|
||||
* Coypritht (c) 2017 Goodix
|
||||
*/
|
||||
#define DEBUG
|
||||
#define pr_fmt(fmt) "gf_platform: " fmt
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include "gf_spi.h"
|
||||
|
||||
#if defined(USE_SPI_BUS)
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/spidev.h>
|
||||
#elif defined(USE_PLATFORM_BUS)
|
||||
#include <linux/platform_device.h>
|
||||
#endif
|
||||
|
||||
int gf_parse_dts(struct gf_dev *gf_dev)
|
||||
{
|
||||
#ifdef GF_PW_CTL
|
||||
/*get pwr resource */
|
||||
gf_dev->pwr_gpio =
|
||||
of_get_named_gpio(gf_dev->spi->dev.of_node, "fp-gpio-pwr", 0);
|
||||
|
||||
if (!gpio_is_valid(gf_dev->pwr_gpio)) {
|
||||
pr_info("PWR GPIO is invalid.\n");
|
||||
return -EPERM;
|
||||
}
|
||||
#endif
|
||||
/*get reset resource */
|
||||
gf_dev->reset_gpio = of_get_named_gpio(gf_dev->spi->dev.of_node,
|
||||
"goodix,gpio-reset", 0);
|
||||
|
||||
if (!gpio_is_valid(gf_dev->reset_gpio)) {
|
||||
pr_info("RESET GPIO is invalid.\n");
|
||||
return -EPERM;
|
||||
}
|
||||
pr_info("gf::gpio-reset:%d\n", gf_dev->reset_gpio);
|
||||
|
||||
/*get irq resourece */
|
||||
gf_dev->irq_gpio = of_get_named_gpio(gf_dev->spi->dev.of_node,
|
||||
"goodix,gpio-irq", 0);
|
||||
pr_info("gf::irq_gpio:%d\n", gf_dev->irq_gpio);
|
||||
|
||||
if (!gpio_is_valid(gf_dev->irq_gpio)) {
|
||||
pr_info("IRQ GPIO is invalid.\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gf_cleanup(struct gf_dev *gf_dev)
|
||||
{
|
||||
pr_info("[info] %s\n", __func__);
|
||||
|
||||
if (gpio_is_valid(gf_dev->irq_gpio)) {
|
||||
gpio_free(gf_dev->irq_gpio);
|
||||
pr_info("remove irq_gpio success\n");
|
||||
}
|
||||
|
||||
if (gpio_is_valid(gf_dev->reset_gpio)) {
|
||||
gpio_free(gf_dev->reset_gpio);
|
||||
pr_info("remove reset_gpio success\n");
|
||||
}
|
||||
#ifdef GF_PW_CTL
|
||||
|
||||
if (gpio_is_valid(gf_dev->pwr_gpio)) {
|
||||
gpio_free(gf_dev->pwr_gpio);
|
||||
pr_info("remove pwr_gpio success\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int gf_power_on(struct gf_dev *gf_dev)
|
||||
{
|
||||
int rc = 0;
|
||||
#ifdef GF_PW_CTL
|
||||
|
||||
if (gpio_is_valid(gf_dev->pwr_gpio)) {
|
||||
rc = gpio_direction_output(gf_dev->pwr_gpio, 1);
|
||||
pr_info("---- power on result: %d----\n", rc);
|
||||
} else {
|
||||
pr_info("%s: gpio_is_invalid\n", __func__);
|
||||
}
|
||||
|
||||
#endif
|
||||
msleep(10);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int gf_power_off(struct gf_dev *gf_dev)
|
||||
{
|
||||
int rc = 0;
|
||||
#ifdef GF_PW_CTL
|
||||
|
||||
if (gpio_is_valid(gf_dev->pwr_gpio)) {
|
||||
rc = gpio_direction_output(gf_dev->pwr_gpio, 0);
|
||||
pr_info("---- power off result: %d----\n", rc);
|
||||
} else {
|
||||
pr_info("%s: gpio_is_invalid\n", __func__);
|
||||
}
|
||||
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
int gf_hw_reset(struct gf_dev *gf_dev, unsigned int delay_ms)
|
||||
{
|
||||
if (gf_dev == NULL) {
|
||||
pr_info("Input buff is NULL.\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
gpio_direction_output(gf_dev->reset_gpio, 0);
|
||||
mdelay(3);
|
||||
gpio_set_value(gf_dev->reset_gpio, 1);
|
||||
mdelay(delay_ms);
|
||||
pr_info("%s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gf_irq_num(struct gf_dev *gf_dev)
|
||||
{
|
||||
if (gf_dev == NULL) {
|
||||
pr_info("Input buff is NULL.\n");
|
||||
return -EPERM;
|
||||
} else {
|
||||
return gpio_to_irq(gf_dev->irq_gpio);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user