fingerprint: goodix_fod: import picasso-r-oss changes

This commit is contained in:
spakkkk 2021-02-04 21:16:19 +00:00
parent dfb8d70a07
commit adc4e3014b
10 changed files with 1532 additions and 0 deletions

View File

@ -213,6 +213,8 @@ source "drivers/input/misc/Kconfig"
source "drivers/input/rmi4/Kconfig" source "drivers/input/rmi4/Kconfig"
source "drivers/input/fingerprint/Kconfig"
endif endif
menu "Hardware I/O ports" menu "Hardware I/O ports"

View File

@ -24,6 +24,7 @@ obj-$(CONFIG_INPUT_MOUSE) += mouse/
obj-$(CONFIG_INPUT_JOYSTICK) += joystick/ obj-$(CONFIG_INPUT_JOYSTICK) += joystick/
obj-$(CONFIG_INPUT_TABLET) += tablet/ obj-$(CONFIG_INPUT_TABLET) += tablet/
obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/ obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/
obj-$(CONFIG_INPUT_FINGERPRINT) += fingerprint/
obj-$(CONFIG_INPUT_MISC) += misc/ obj-$(CONFIG_INPUT_MISC) += misc/
obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o

View File

@ -0,0 +1,22 @@
#
# Fingerprint driver configuration
#
config FINGERPRINT_FP_VREG_CONTROL
bool "fingerprint fp_vdd_reg regulator control"
default n
---help---
Say Y here to enable fp_vdd_vreg regulator by device driver
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/goodix_fod/Kconfig"
endif

View File

@ -0,0 +1,9 @@
#
# Makefile for the fingerprint drivers.
#
# Each configuration option enables a list of files.
obj-$(CONFIG_FINGERPRINT_GOODIX_TA) += goodix_ta/
obj-$(CONFIG_FINGERPRINT_FPC_TEE) += fpc_tee/
obj-$(CONFIG_FINGERPRINT_GOODIX_FOD) += goodix_fod/

View File

@ -0,0 +1,10 @@
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.

View File

@ -0,0 +1 @@
obj-$(CONFIG_FINGERPRINT_GOODIX_FOD) += gf_spi.o platform.o netlink.o

File diff suppressed because it is too large Load Diff

View 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*/
/*#define GF_FASYNC 1*//*If support fasync mechanism.*/
#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;
#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*/

View File

@ -0,0 +1,100 @@
/*
* netlink interface
*
* Copyright (c) 2017 Goodix
* Copyright (C) 2021 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 = NULL;
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");
}

View File

@ -0,0 +1,144 @@
/*
* 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, "goodix,gpio-pwr",
0);
pr_info("gf::pwr_gpio:%d\n", gf_dev->pwr_gpio);
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);
pr_info("gf::reset_gpio:%d\n", gf_dev->reset_gpio);
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);
}
}