kernel_samsung_a53x/drivers/fingerprint/gw9558x_common.c
2024-06-15 16:02:09 -03:00

974 lines
25 KiB
C
Executable file

/*
* Copyright (C) 2018, Samsung Electronics Co. Ltd. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include "fingerprint.h"
#include "gw9558x_common.h"
static LIST_HEAD(device_list);
static DEFINE_MUTEX(device_list_lock);
static const struct of_device_id gw9558_of_match[] = {
{ .compatible = "goodix,gw9558x", },
{},
};
MODULE_DEVICE_TABLE(of, gw9558_of_match);
struct debug_logger *g_logger;
static ssize_t bfs_values_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct gf_device *gf_dev = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "\"FP_SPICLK\":\"%d\"\n",
gf_dev->clk_setting->spi_speed);
}
static ssize_t type_check_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct gf_device *gf_dev = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%d\n", gf_dev->sensortype);
}
static ssize_t vendor_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", "GOODIX");
}
static ssize_t name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct gf_device *gf_dev = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%s\n", gf_dev->chipid);
}
static ssize_t adm_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", DETECT_ADM);
}
static ssize_t resetcnt_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct gf_device *gf_dev = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%d\n", gf_dev->reset_count);
}
static ssize_t resetcnt_store(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t size)
{
struct gf_device *gf_dev = dev_get_drvdata(dev);
if (sysfs_streq(buf, "c")) {
gf_dev->reset_count = 0;
pr_info("initialization is done\n");
}
return size;
}
static ssize_t position_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct gf_device *gf_dev = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%s\n", gf_dev->sensor_position);
}
static ssize_t rb_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct gf_device *gf_dev = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%s\n", gf_dev->rb);
}
static DEVICE_ATTR_RO(bfs_values);
static DEVICE_ATTR_RO(type_check);
static DEVICE_ATTR_RO(vendor);
static DEVICE_ATTR_RO(name);
static DEVICE_ATTR_RO(adm);
static DEVICE_ATTR_RW(resetcnt);
static DEVICE_ATTR_RO(position);
static DEVICE_ATTR_RO(rb);
static struct device_attribute *fp_attrs[] = {
&dev_attr_bfs_values,
&dev_attr_type_check,
&dev_attr_vendor,
&dev_attr_name,
&dev_attr_adm,
&dev_attr_resetcnt,
&dev_attr_position,
&dev_attr_rb,
NULL,
};
static ssize_t gw9558_read(struct file *filp, char __user *buf,
size_t count, loff_t *f_pos)
{
return -EFAULT;
}
static ssize_t gw9558_write(struct file *filp, const char __user *buf,
size_t count, loff_t *f_pos)
{
return -EFAULT;
}
static long gw9558_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct gf_device *gf_dev = NULL;
unsigned int onoff = 0;
int retval = 0;
u8 temp = 0;
if (_IOC_TYPE(cmd) != GF_IOC_MAGIC)
return -EINVAL;
if (!filp || !filp->private_data) {
pr_err("NULL pointer passed\n");
return -EINVAL;
}
if (IS_ERR((void __user *)arg)) {
pr_err("invalid user space pointer %lu\n", arg);
return -EINVAL;
}
gf_dev = (struct gf_device *)filp->private_data;
switch (cmd) {
case GF_IOC_INIT:
pr_debug("GF_IOC_INIT\n");
if (copy_to_user((void __user *)arg, (void *)&temp, sizeof(temp)))
retval = -EFAULT;
break;
case GF_IOC_RESET:
pr_info("GF_IOC_RESET\n");
gw9558_hw_reset(gf_dev, 0);
break;
case GF_IOC_ENABLE_SPI_CLK:
if (copy_from_user(&onoff, (void __user *)arg,
sizeof(onoff))) {
pr_err("Failed to copy spi_speed value from user to kernel\n");
}
pr_info("GF_IOC_ENABLE_SPI_CLK : %d, fromUser : %d\n",
gf_dev->clk_setting->spi_speed, onoff);
spi_clk_enable(gf_dev->clk_setting);
break;
case GF_IOC_DISABLE_SPI_CLK:
pr_info("GF_IOC_DISABLE_SPI_CLK\n");
spi_clk_disable(gf_dev->clk_setting);
break;
case GF_IOC_ENABLE_POWER:
pr_info("GF_IOC_ENABLE_POWER\n");
gw9558_hw_power_enable(gf_dev, 1);
break;
case GF_IOC_DISABLE_POWER:
pr_info("GF_IOC_DISABLE_POWER\n");
gw9558_hw_power_enable(gf_dev, 0);
break;
case GF_IOC_POWER_CONTROL:
if (copy_from_user(&onoff, (void __user *)arg,
sizeof(onoff))) {
pr_err("Failed to copy onoff value from user to kernel\n");
retval = -EFAULT;
break;
}
pr_info("GF_IOC_POWER_CONTROL %d\n", onoff);
gw9558_hw_power_enable(gf_dev, onoff);
break;
case GF_IOC_GET_FW_INFO:
temp = 1;
pr_debug("GET_FW_INFO : 0x%x\n", temp);
if (copy_to_user((void __user *)arg, (void *)&temp,
sizeof(temp))) {
pr_err("Failed to copy data to user\n");
retval = -EFAULT;
}
break;
#ifndef ENABLE_SENSORS_FPRINT_SECURE
case GF_IOC_TRANSFER_RAW_CMD:
mutex_lock(&gf_dev->buf_lock);
retval = gw9558_ioctl_transfer_raw_cmd(gf_dev, arg, (unsigned int)TANSFER_MAX_LEN);
mutex_unlock(&gf_dev->buf_lock);
break;
#endif /* !ENABLE_SENSORS_FPRINT_SECURE */
#ifdef ENABLE_SENSORS_FPRINT_SECURE
case GF_IOC_SET_SENSOR_TYPE:
if (copy_from_user(&onoff, (void __user *)arg,
sizeof(onoff)) != 0) {
pr_err("Failed to copy sensor type from user to kernel\n");
return -EFAULT;
}
set_sensor_type((int)onoff, &gf_dev->sensortype);
break;
#endif
case GF_IOC_SPEEDUP:
if (copy_from_user(&onoff, (void __user *)arg,
sizeof(onoff)) != 0) {
pr_err("Failed to copy speedup from user to kernel\n");
return -EFAULT;
}
if (onoff)
retval = cpu_speedup_enable(gf_dev->boosting);
else
retval = cpu_speedup_disable(gf_dev->boosting);
break;
case GF_MODEL_INFO:
pr_info("GF_MODEL_INFO : %s\n", gf_dev->model_info);
if (copy_to_user((void __user *)arg, gf_dev->model_info, 10)) {
pr_err("Failed to copy data to user\n");
retval = -EFAULT;
}
break;
case GF_IOC_RESERVED01:
case GF_IOC_RESERVED02:
case GF_IOC_RESERVED03:
case GF_IOC_RESERVED04:
case GF_IOC_RESERVED05:
case GF_IOC_RESERVED06:
case GF_IOC_RESERVED07:
break;
default:
pr_err("doesn't support this command(%x)\n", cmd);
break;
}
return retval;
}
#ifdef CONFIG_COMPAT
static long gw9558_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
static int gw9558_open(struct inode *inode, struct file *filp)
{
struct gf_device *gf_dev = NULL;
int retval = -ENXIO;
pr_info("Entry\n");
mutex_lock(&device_list_lock);
list_for_each_entry(gf_dev, &device_list, device_entry) {
if (gf_dev->devno == inode->i_rdev) {
pr_info("Found\n");
retval = 0;
break;
}
}
mutex_unlock(&device_list_lock);
if (retval == 0) {
filp->private_data = gf_dev;
nonseekable_open(inode, filp);
pr_info("Success to open device\n");
} else {
pr_err("No device for minor %d\n", iminor(inode));
}
return retval;
}
static int gw9558_release(struct inode *inode, struct file *filp)
{
struct gf_device *gf_dev = NULL;
pr_info("Entry\n");
gf_dev = filp->private_data;
return 0;
}
static const struct file_operations gw9558_fops = {
.owner = THIS_MODULE,
.write = gw9558_write,
.read = gw9558_read,
.unlocked_ioctl = gw9558_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = gw9558_compat_ioctl,
#endif
.open = gw9558_open,
.release = gw9558_release,
};
static void gw9558_work_func_debug(struct work_struct *work)
{
u8 rst_value = -1;
struct debug_logger *logger;
struct gf_device *gf_dev;
logger = container_of(work, struct debug_logger, work_debug);
gf_dev = dev_get_drvdata(logger->dev);
if (gf_dev->reset_gpio)
rst_value = gpio_get_value(gf_dev->reset_gpio);
pr_info("ldo: %d, sleep: %d, tz: %d type: %s\n",
gf_dev->ldo_onoff, rst_value, gf_dev->tz_mode,
gf_dev->sensortype > 0 ? gf_dev->chipid : sensor_status[gf_dev->sensortype + 2]);
}
int gw9558_pin_control(struct gf_device *gf_dev, bool pin_set)
{
int retval = 0;
#ifndef ENABLE_SENSORS_FPRINT_SECURE
if (pin_set) {
if (!IS_ERR(gf_dev->pins_poweron)) {
retval = pinctrl_select_state(gf_dev->p, gf_dev->pins_poweron);
if (retval)
pr_err("can't set pin wakeup state\n");
pr_debug("idle\n");
}
} else {
if (!IS_ERR(gf_dev->pins_poweroff)) {
retval = pinctrl_select_state(gf_dev->p, gf_dev->pins_poweroff);
if (retval)
pr_err("can't set pin sleep state\n");
pr_debug("sleep\n");
}
}
#endif
return retval;
}
void gw9558_hw_power_enable(struct gf_device *gf_dev, u8 onoff)
{
int retval = 0;
if (onoff && !gf_dev->ldo_onoff) {
gw9558_pin_control(gf_dev, 1);
if (gf_dev->pwr_gpio) {
gpio_set_value(gf_dev->pwr_gpio, 1);
} else if (gf_dev->regulator_3p3 != NULL) {
retval = regulator_enable(gf_dev->regulator_3p3);
if (retval) {
pr_err("regulator enable failed, rc=%d\n", retval);
goto regulator_failed;
}
}
if (gf_dev->reset_gpio) {
usleep_range(11000, 11050);
gpio_set_value(gf_dev->reset_gpio, 1);
}
gf_dev->ldo_onoff = 1;
} else if (!onoff && gf_dev->ldo_onoff) {
if (gf_dev->reset_gpio) {
gpio_set_value(gf_dev->reset_gpio, 0);
usleep_range(11000, 11050);
}
if (gf_dev->pwr_gpio) {
gpio_set_value(gf_dev->pwr_gpio, 0);
} else if (gf_dev->regulator_3p3 != NULL) {
retval = regulator_disable(gf_dev->regulator_3p3);
if (retval) {
pr_err("regulator disable failed, rc=%d\n", retval);
if (gf_dev->reset_gpio)
gpio_set_value(gf_dev->reset_gpio, 1);
goto regulator_failed;
}
}
gf_dev->ldo_onoff = 0;
gw9558_pin_control(gf_dev, 0);
} else if (onoff == 0 || onoff == 1) {
pr_err("power is already %s\n",
(gf_dev->ldo_onoff ? "Enabled" : "Disabled"));
} else {
pr_err("can't support this value:%d\n", onoff);
}
pr_debug("status = %d\n", gf_dev->ldo_onoff);
regulator_failed:
return;
}
void gw9558_hw_reset(struct gf_device *gf_dev, u8 delay)
{
if (gf_dev->reset_gpio) {
gpio_set_value(gf_dev->reset_gpio, 0);
usleep_range(3000, 3050);
gpio_set_value(gf_dev->reset_gpio, 1);
usleep_range((delay * 1000), (delay * 1000) + 50);
gf_dev->reset_count++;
}
}
/* GPIO pins reference */
int gw9558_get_gpio_dts_info(struct device *dev, struct gf_device *gf_dev)
{
struct device_node *np = dev->of_node;
int retval = 0;
/* get pwr resource */
gf_dev->pwr_gpio = of_get_named_gpio(np, "goodix,gpio_pwr", 0);
if (!gpio_is_valid(gf_dev->pwr_gpio)) {
pr_info("not use PWR GPIO\n");
gf_dev->pwr_gpio = 0;
} else {
pr_info("goodix_pwr:%d\n", gf_dev->pwr_gpio);
retval = gpio_request(gf_dev->pwr_gpio, "goodix_pwr");
if (retval < 0) {
pr_err("Failed to request PWR GPIO = %d\n", retval);
return retval;
}
gpio_direction_output(gf_dev->pwr_gpio, 0);
}
if (of_property_read_string(np, "goodix,btp-regulator", &gf_dev->btp_vdd) < 0) {
pr_info("not use btp_regulator\n");
gf_dev->btp_vdd = NULL;
} else {
gf_dev->regulator_3p3 = regulator_get(NULL, gf_dev->btp_vdd);
if ((gf_dev->regulator_3p3) == NULL) {
pr_info("fail to get regulator_3p3\n");
return -EINVAL;
} else if (IS_ERR(gf_dev->regulator_3p3)) {
pr_info("fail to get regulator_3p3: %ld", PTR_ERR(gf_dev->regulator_3p3));
return PTR_ERR(gf_dev->regulator_3p3);
}
pr_info("btp_regulator ok\n");
}
/* get reset resource */
gf_dev->reset_gpio = of_get_named_gpio(np, "goodix,gpio_reset", 0);
if (!gpio_is_valid(gf_dev->reset_gpio)) {
pr_err("RESET GPIO is invalid.\n");
return gf_dev->reset_gpio;
}
pr_info("goodix_reset:%d\n", gf_dev->reset_gpio);
retval = gpio_request(gf_dev->reset_gpio, "goodix_reset");
if (retval < 0) {
pr_err("Failed to request RESET GPIO = %d\n", retval);
return retval;
}
gpio_direction_output(gf_dev->reset_gpio, 0);
if (of_property_read_u32(np, "goodix,min_cpufreq_limit",
&gf_dev->boosting->min_cpufreq_limit))
gf_dev->boosting->min_cpufreq_limit = 0;
if (of_property_read_string_index(np, "goodix,chip_id", 0,
(const char **)&gf_dev->chipid))
gf_dev->chipid = "NULL";
pr_info("Chip ID:%s\n", gf_dev->chipid);
if (of_property_read_string_index(np, "goodix,position", 0,
(const char **)&gf_dev->sensor_position)) {
gf_dev->sensor_position = "14.31,0.00,9.10,9.10,14.80,14.80,12.00,12.00,5.00";
}
pr_info("position: %s\n", gf_dev->sensor_position);
if (of_property_read_string_index(np, "goodix,rb", 0,
(const char **)&gf_dev->rb)) {
gf_dev->rb = "525,-1,-1";
}
pr_info("rb: %s\n", gf_dev->rb);
if (of_property_read_string_index(np, "goodix,modelinfo", 0,
(const char **)&gf_dev->model_info)) {
gf_dev->model_info = "NONE";
}
pr_info("modelinfo: %s\n", gf_dev->model_info);
gf_dev->p = pinctrl_get_select_default(dev);
if (IS_ERR(gf_dev->p)) {
pr_err("failed pinctrl_get\n");
return PTR_ERR(gf_dev->p);
}
#ifndef ENABLE_SENSORS_FPRINT_SECURE
gf_dev->pins_poweroff = pinctrl_lookup_state(gf_dev->p, "pins_poweroff");
if (IS_ERR(gf_dev->pins_poweroff)) {
pr_err("could not get pins sleep_state (%li)\n",
PTR_ERR(gf_dev->pins_poweroff));
}
gf_dev->pins_poweron = pinctrl_lookup_state(gf_dev->p, "pins_poweron");
if (IS_ERR(gf_dev->pins_poweron)) {
pr_err("could not get pins idle_state (%li)\n",
PTR_ERR(gf_dev->pins_poweron));
}
#endif
return retval;
}
void gw9558_cleanup_info(struct gf_device *gf_dev)
{
if (gpio_is_valid(gf_dev->reset_gpio)) {
gpio_free(gf_dev->reset_gpio);
pr_debug("remove reset_gpio\n");
}
if (gpio_is_valid(gf_dev->pwr_gpio)) {
gpio_free(gf_dev->pwr_gpio);
pr_debug("remove pwr_gpio\n");
}
if (gf_dev->regulator_3p3) {
regulator_put(gf_dev->regulator_3p3);
pr_debug("remove regulator\n");
}
}
#ifndef ENABLE_SENSORS_FPRINT_SECURE
int gw9558_type_check(struct gf_device *gf_dev)
{
int retval = -ENODEV;
unsigned char mcuid[2] = {0x00, 0x00};
u32 mcuid32 = 0;
#if defined(CONFIG_SENSORS_FINGERPRINT_NORMALSPI)
unsigned char wake_wp_0[4] = {0x00, 0x01, 0x00, 0x00};
unsigned char spi_mode[4] = {0x00, 0x01, 0x00, 0x11};
#endif
gw9558_hw_power_enable(gf_dev, 1);
usleep_range(4950, 5000);
#if defined(CONFIG_SENSORS_FINGERPRINT_NORMALSPI)
gw9558_spi_write_bytes(gf_dev, 0xe500, 4, wake_wp_0);
usleep_range(1000, 1050);
gw9558_spi_write_bytes(gf_dev, 0x0022, 4, spi_mode);
usleep_range(1000, 1050);
#endif
gw9558_spi_read_bytes(gf_dev, 0x0000, 2, mcuid);
mcuid32 = mcuid[0] << 8 | mcuid[1];
pr_info("Sensor read : %x %x\n", mcuid[0], mcuid[1]);
pr_info("Sensor read : 0x%4x\n", mcuid32);
if (mcuid32 == G3_MCU_ID) {
gf_dev->sensortype = SENSOR_OK;
pr_info("sensor type is G3 %s\n", gf_dev->chipid);
retval = 0;
} else if (mcuid32 == GX_MCU_ID) {
gf_dev->sensortype = SENSOR_OK;
pr_info("sensor type is GX %s\n", gf_dev->chipid);
retval = 0;
} else if (mcuid32 == G3S_MCU_ID) {
gf_dev->sensortype = SENSOR_OK;
pr_info("sensor type is G3S %s\n", gf_dev->chipid);
retval = 0;
} else {
gf_dev->sensortype = SENSOR_FAILED;
pr_err("sensor type is FAILED 0x%4x\n", mcuid32);
}
gw9558_hw_power_enable(gf_dev, 0);
return retval;
}
#endif
static struct gf_device *alloc_platformdata(struct device *dev)
{
struct gf_device *gf_dev;
gf_dev = devm_kzalloc(dev, sizeof(struct gf_device), GFP_KERNEL);
if (gf_dev == NULL)
return NULL;
gf_dev->clk_setting = devm_kzalloc(dev, sizeof(*gf_dev->clk_setting), GFP_KERNEL);
if (gf_dev->clk_setting == NULL)
return NULL;
gf_dev->boosting = devm_kzalloc(dev, sizeof(*gf_dev->boosting), GFP_KERNEL);
if (gf_dev->boosting == NULL)
return NULL;
gf_dev->logger = devm_kzalloc(dev, sizeof(*gf_dev->logger), GFP_KERNEL);
if (gf_dev->logger == NULL)
return NULL;
return gf_dev;
}
static int gw9558_probe_common(struct device *dev, struct gf_device *gf_dev)
{
int retval = -EINVAL;
#ifndef ENABLE_SENSORS_FPRINT_SECURE
int retry = 0;
#endif
pr_info("Entry\n");
spin_lock_init(&gf_dev->spi_lock);
INIT_LIST_HEAD(&gf_dev->device_entry);
/* Initialize the driver data */
gf_dev->device_count = 0;
gf_dev->ldo_onoff = 0;
gf_dev->reset_count = 0;
gf_dev->dev = dev;
gf_dev->logger->dev = dev;
dev_set_drvdata(dev, gf_dev);
/* get gpio info from dts or defination */
retval = gw9558_get_gpio_dts_info(dev, gf_dev);
if (retval < 0) {
pr_err("Failed to get gpio info:%d\n", retval);
goto gw9558_probe_get_gpio;
}
#ifndef ENABLE_SENSORS_FPRINT_SECURE
gw9558_spi_setup_conf(gf_dev, 1);
#endif
/* set AP spectific configuration */
retval = spi_clk_register(gf_dev->clk_setting, dev);
if (retval < 0) {
pr_err("Failed to register spi clk:%d\n", retval);
goto gw9558_probe_spi_clk_register;
}
/* create class */
gf_dev->class = class_create(THIS_MODULE, GF_CLASS_NAME);
if (IS_ERR(gf_dev->class)) {
pr_err("Failed to create class.\n");
retval = -ENODEV;
goto gw9558_probe_class_create;
}
/* get device no */
if (GF_DEV_MAJOR > 0) {
gf_dev->devno = MKDEV(GF_DEV_MAJOR, gf_dev->device_count++);
retval = register_chrdev_region(gf_dev->devno, 1, GF_DEV_NAME);
} else {
retval = alloc_chrdev_region(&gf_dev->devno,
gf_dev->device_count++, 1, GF_DEV_NAME);
}
if (retval < 0) {
pr_err("Failed to alloc devno.\n");
goto gw9558_probe_devno;
} else {
pr_info("major=%d, minor=%d\n",
MAJOR(gf_dev->devno), MINOR(gf_dev->devno));
}
/* create device */
gf_dev->fp_device = device_create(gf_dev->class, dev,
gf_dev->devno, gf_dev, GF_DEV_NAME);
if (IS_ERR(gf_dev->fp_device)) {
pr_err("Failed to create device.\n");
retval = -ENODEV;
goto gw9558_probe_device;
} else {
mutex_lock(&device_list_lock);
list_add(&gf_dev->device_entry, &device_list);
mutex_unlock(&device_list_lock);
pr_info("device create success.\n");
}
#ifndef ENABLE_SENSORS_FPRINT_SECURE
do {
retval = gw9558_type_check(gf_dev);
pr_info("type (%u), retry (%d)\n", gf_dev->sensortype, retry);
} while (!gf_dev->sensortype && ++retry < 3);
if (retval == -ENODEV)
pr_err("type_check failed\n");
#endif
/* create sysfs */
retval = fingerprint_register(gf_dev->fp_device,
gf_dev, fp_attrs, "fingerprint");
if (retval) {
pr_err("sysfs register failed\n");
goto gw9558_probe_sysfs;
}
/* cdev init and add */
cdev_init(&gf_dev->cdev, &gw9558_fops);
gf_dev->cdev.owner = THIS_MODULE;
retval = cdev_add(&gf_dev->cdev, gf_dev->devno, 1);
if (retval) {
pr_err("Failed to add cdev.\n");
goto gw9558_probe_cdev;
}
#if KERNEL_VERSION(4, 19, 188) > LINUX_VERSION_CODE
/* 4.19 R */
wakeup_source_init(gf_dev->clk_setting->spi_wake_lock, "gw9558_wake_lock");
/* 4.19 Q */
if (!(gf_dev->clk_setting->spi_wake_lock)) {
gf_dev->clk_setting->spi_wake_lock = wakeup_source_create("gw9558_wake_lock");
if (gf_dev->clk_setting->spi_wake_lock)
wakeup_source_add(gf_dev->clk_setting->spi_wake_lock);
}
#else
/* 5.4 R */
gf_dev->clk_setting->spi_wake_lock = wakeup_source_register(gf_dev->dev, "gw9558_wake_lock");
#endif
g_logger = gf_dev->logger;
retval = set_fp_debug_timer(gf_dev->logger, gw9558_work_func_debug);
if (retval)
goto gw9558_probe_debug_timer;
enable_fp_debug_timer(gf_dev->logger);
pr_info("probe finished\n");
return 0;
gw9558_probe_debug_timer:
cdev_del(&gf_dev->cdev);
gw9558_probe_cdev:
fingerprint_unregister(gf_dev->fp_device, fp_attrs);
gw9558_probe_sysfs:
device_destroy(gf_dev->class, gf_dev->devno);
list_del(&gf_dev->device_entry);
gw9558_probe_device:
unregister_chrdev_region(gf_dev->devno, 1);
gw9558_probe_devno:
class_destroy(gf_dev->class);
gw9558_probe_class_create:
spi_clk_unregister(gf_dev->clk_setting);
gw9558_probe_spi_clk_register:
gw9558_probe_get_gpio:
pr_err("failed. %d", retval);
return retval;
}
#ifdef ENABLE_SENSORS_FPRINT_SECURE
static int gw9558_probe(struct platform_device *pdev)
{
int retval = -ENOMEM;
struct gf_device *gf_dev;
pr_info("platform_driver Entry\n");
gf_dev = alloc_platformdata(&pdev->dev);
if (gf_dev == NULL)
goto gw9558_platform_alloc_failed;
gf_dev->clk_setting->enabled_clk = false;
gf_dev->tz_mode = true;
gf_dev->sensortype = SENSOR_UNKNOWN;
gf_dev->clk_setting->spi_speed = (unsigned int)GW9558_SPI_BAUD_RATE;
retval = gw9558_probe_common(&pdev->dev, gf_dev);
if (retval)
goto gw9558_platform_probe_failed;
pr_info("is successful\n");
return retval;
gw9558_platform_probe_failed:
gf_dev = NULL;
gw9558_platform_alloc_failed:
pr_err("is failed : %d\n", retval);
return retval;
}
#else
static int gw9558_probe(struct spi_device *spi)
{
int retval = -ENOMEM;
struct gf_device *gf_dev = NULL;
pr_info("spi_driver Entry\n");
gf_dev = alloc_platformdata(&spi->dev);
if (gf_dev == NULL)
goto gw9558_spi_probe_alloc_failed;
spi->mode = SPI_MODE_0;
spi->max_speed_hz = (unsigned int)GW9558_SPI_BAUD_RATE;
spi->bits_per_word = 8;
gf_dev->clk_setting->spi_speed = (unsigned int)GW9558_SPI_BAUD_RATE;
gf_dev->prev_bits_per_word = 8;
gf_dev->tz_mode = false;
gf_dev->spi = spi;
mutex_init(&gf_dev->buf_lock);
if (spi_setup(gf_dev->spi)) {
pr_err("failed to setup spi conf\n");
goto gw9558_spi_spi_setup_failed;
} else {
pr_info("setup spi success.\n");
}
/* init transfer buffer */
retval = gw9558_init_buffer(gf_dev);
if (retval < 0) {
pr_err("Failed to Init transfer buffer.\n");
goto gw9558_spi_init_buffer_failed;
}
retval = gw9558_probe_common(&spi->dev, gf_dev);
if (retval)
goto gw9558_spi_probe_failed;
pr_info("is successful\n");
return retval;
gw9558_spi_probe_failed:
gw9558_free_buffer(gf_dev);
gw9558_spi_init_buffer_failed:
gw9558_spi_spi_setup_failed:
mutex_destroy(&gf_dev->buf_lock);
gf_dev = NULL;
gw9558_spi_probe_alloc_failed:
pr_err("is failed : %d\n", retval);
return retval;
}
#endif
static int gw9558_remove_common(struct device *dev)
{
struct gf_device *gf_dev = dev_get_drvdata(dev);
pr_info("Entry\n");
gw9558_hw_power_enable(gf_dev, 0);
spi_clk_unregister(gf_dev->clk_setting);
disable_fp_debug_timer(gf_dev->logger);
wakeup_source_unregister(gf_dev->clk_setting->spi_wake_lock);
gw9558_cleanup_info(gf_dev);
fingerprint_unregister(gf_dev->fp_device, fp_attrs);
cdev_del(&gf_dev->cdev);
device_destroy(gf_dev->class, gf_dev->devno);
list_del(&gf_dev->device_entry);
unregister_chrdev_region(gf_dev->devno, 1);
class_destroy(gf_dev->class);
return 0;
}
#ifdef ENABLE_SENSORS_FPRINT_SECURE
static int gw9558_remove(struct platform_device *pdev)
{
struct gf_device *gf_dev = platform_get_drvdata(pdev);
gw9558_remove_common(&pdev->dev);
gf_dev = NULL;
return 0;
}
#else
#if LINUX_VERSION_CODE > KERNEL_VERSION(6, 1, 0)
static void gw9558_remove(struct spi_device *spi)
{
struct gf_device *gf_dev = spi_get_drvdata(spi);
gw9558_free_buffer(gf_dev);
gw9558_remove_common(&spi->dev);
mutex_destroy(&gf_dev->buf_lock);
spin_lock_irq(&gf_dev->spi_lock);
gf_dev->spi = NULL;
spin_unlock_irq(&gf_dev->spi_lock);
gf_dev = NULL;
}
#else
static int gw9558_remove(struct spi_device *spi)
{
struct gf_device *gf_dev = spi_get_drvdata(spi);
gw9558_free_buffer(gf_dev);
gw9558_remove_common(&spi->dev);
mutex_destroy(&gf_dev->buf_lock);
spin_lock_irq(&gf_dev->spi_lock);
gf_dev->spi = NULL;
spin_unlock_irq(&gf_dev->spi_lock);
gf_dev = NULL;
return 0;
}
#endif
#endif
static int gw9558_pm_suspend(struct device *dev)
{
struct gf_device *gf_dev = dev_get_drvdata(dev);
pr_info("Entry\n");
disable_fp_debug_timer(gf_dev->logger);
return 0;
}
static int gw9558_pm_resume(struct device *dev)
{
struct gf_device *gf_dev = dev_get_drvdata(dev);
pr_info("Entry\n");
enable_fp_debug_timer(gf_dev->logger);
return 0;
}
static const struct dev_pm_ops gw9558_pm_ops = {
.suspend = gw9558_pm_suspend,
.resume = gw9558_pm_resume
};
#ifndef ENABLE_SENSORS_FPRINT_SECURE
static struct spi_driver gw9558_spi_driver = {
#else
static struct platform_driver gw9558_spi_driver = {
#endif
.driver = {
.name = GF_DEV_NAME,
#ifndef ENABLE_SENSORS_FPRINT_SECURE
.bus = &spi_bus_type,
#endif
.owner = THIS_MODULE,
.pm = &gw9558_pm_ops,
.of_match_table = gw9558_of_match,
},
.probe = gw9558_probe,
.remove = gw9558_remove,
};
static int __init gw9558_init(void)
{
int retval = 0;
pr_info("Entry\n");
#ifndef ENABLE_SENSORS_FPRINT_SECURE
retval = spi_register_driver(&gw9558_spi_driver);
#else
retval = platform_driver_register(&gw9558_spi_driver);
#endif
if (retval < 0) {
pr_err("Failed to register SPI driver.\n");
return -EINVAL;
}
return retval;
}
module_init(gw9558_init);
static void __exit gw9558_exit(void)
{
pr_info("Entry\n");
#ifndef ENABLE_SENSORS_FPRINT_SECURE
spi_unregister_driver(&gw9558_spi_driver);
#else
platform_driver_unregister(&gw9558_spi_driver);
#endif
}
module_exit(gw9558_exit);
MODULE_AUTHOR("fp.sec@samsung.com");
MODULE_DESCRIPTION("Samsung Electronics Inc. GW9558 driver");
MODULE_LICENSE("GPL");