mirror of
https://github.com/physwizz/a155-U-u1.git
synced 2025-08-15 06:35:18 +00:00
283 lines
6.8 KiB
C
283 lines
6.8 KiB
C
#include "fingerprint.h"
|
|
#include "gw3x_common.h"
|
|
|
|
#ifndef ENABLE_SENSORS_FPRINT_SECURE
|
|
void gw3x_spi_setup_conf(struct gf_device *gf_dev, u32 bits)
|
|
{
|
|
gf_dev->spi->bits_per_word = 8;
|
|
if (gf_dev->prev_bits_per_word != gf_dev->spi->bits_per_word) {
|
|
if (spi_setup(gf_dev->spi))
|
|
pr_err("failed to setup spi conf\n");
|
|
pr_info("prev-bpw:%d, bpw:%d\n",
|
|
gf_dev->prev_bits_per_word, gf_dev->spi->bits_per_word);
|
|
gf_dev->prev_bits_per_word = gf_dev->spi->bits_per_word;
|
|
}
|
|
}
|
|
|
|
int gw3x_spi_read_bytes(struct gf_device *gf_dev, u16 addr,
|
|
u32 data_len, u8 *rx_buf)
|
|
{
|
|
struct spi_message msg;
|
|
struct spi_transfer *xfer = NULL;
|
|
u8 *tmp_buf = NULL;
|
|
|
|
xfer = kzalloc(sizeof(*xfer) * 2, GFP_KERNEL);
|
|
if (xfer == NULL)
|
|
return -ENOMEM;
|
|
|
|
tmp_buf = gf_dev->spi_buffer;
|
|
|
|
spi_message_init(&msg);
|
|
*tmp_buf = 0xF0;
|
|
*(tmp_buf + 1) = (u8)((addr >> 8) & 0xFF);
|
|
*(tmp_buf + 2) = (u8)(addr & 0xFF);
|
|
xfer[0].tx_buf = tmp_buf;
|
|
xfer[0].len = 3;
|
|
set_delay_in_spi_transfer(&xfer[0], SPI_TRANSFER_DELAY);
|
|
spi_message_add_tail(&xfer[0], &msg);
|
|
spi_sync(gf_dev->spi, &msg);
|
|
|
|
spi_message_init(&msg);
|
|
/* memset((tmp_buf + 4), 0x00, data_len + 1); */
|
|
/* 4 bytes align */
|
|
*(tmp_buf + 4) = 0xF1;
|
|
xfer[1].tx_buf = tmp_buf + 4;
|
|
xfer[1].rx_buf = tmp_buf + 4;
|
|
xfer[1].len = data_len + 1;
|
|
set_delay_in_spi_transfer(&xfer[1], SPI_TRANSFER_DELAY);
|
|
spi_message_add_tail(&xfer[1], &msg);
|
|
spi_sync(gf_dev->spi, &msg);
|
|
|
|
memcpy(rx_buf, (tmp_buf + 5), data_len);
|
|
|
|
kfree(xfer);
|
|
if (xfer != NULL)
|
|
xfer = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int gw3x_spi_write_bytes(struct gf_device *gf_dev, u16 addr,
|
|
u32 data_len, u8 *tx_buf)
|
|
{
|
|
struct spi_message msg;
|
|
struct spi_transfer *xfer = NULL;
|
|
u8 *tmp_buf = NULL;
|
|
|
|
xfer = kzalloc(sizeof(*xfer), GFP_KERNEL);
|
|
if (xfer == NULL)
|
|
return -ENOMEM;
|
|
|
|
tmp_buf = gf_dev->spi_buffer;
|
|
|
|
spi_message_init(&msg);
|
|
*tmp_buf = 0xF0;
|
|
*(tmp_buf + 1) = (u8)((addr >> 8) & 0xFF);
|
|
*(tmp_buf + 2) = (u8)(addr & 0xFF);
|
|
memcpy(tmp_buf + 3, tx_buf, data_len);
|
|
xfer[0].len = data_len + 3;
|
|
xfer[0].tx_buf = tmp_buf;
|
|
set_delay_in_spi_transfer(&xfer[0], SPI_TRANSFER_DELAY);
|
|
spi_message_add_tail(&xfer[0], &msg);
|
|
spi_sync(gf_dev->spi, &msg);
|
|
|
|
kfree(xfer);
|
|
if (xfer != NULL)
|
|
xfer = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int gw3x_spi_read_byte(struct gf_device *gf_dev, u16 addr, u8 *value)
|
|
{
|
|
struct spi_message msg;
|
|
struct spi_transfer *xfer = NULL;
|
|
|
|
xfer = kzalloc(sizeof(*xfer) * 2, GFP_KERNEL);
|
|
if (xfer == NULL)
|
|
return -ENOMEM;
|
|
|
|
spi_message_init(&msg);
|
|
*gf_dev->spi_buffer = 0xF0;
|
|
*(gf_dev->spi_buffer + 1) = (u8)((addr >> 8) & 0xFF);
|
|
*(gf_dev->spi_buffer + 2) = (u8)(addr & 0xFF);
|
|
|
|
xfer[0].tx_buf = gf_dev->spi_buffer;
|
|
xfer[0].len = 3;
|
|
set_delay_in_spi_transfer(&xfer[0], SPI_TRANSFER_DELAY);
|
|
spi_message_add_tail(&xfer[0], &msg);
|
|
spi_sync(gf_dev->spi, &msg);
|
|
|
|
spi_message_init(&msg);
|
|
/* 4 bytes align */
|
|
*(gf_dev->spi_buffer + 4) = 0xF1;
|
|
xfer[1].tx_buf = gf_dev->spi_buffer + 4;
|
|
xfer[1].rx_buf = gf_dev->spi_buffer + 4;
|
|
xfer[1].len = 2;
|
|
set_delay_in_spi_transfer(&xfer[1], SPI_TRANSFER_DELAY);
|
|
spi_message_add_tail(&xfer[1], &msg);
|
|
spi_sync(gf_dev->spi, &msg);
|
|
|
|
*value = *(gf_dev->spi_buffer + 5);
|
|
|
|
kfree(xfer);
|
|
if (xfer != NULL)
|
|
xfer = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int gw3x_spi_write_byte(struct gf_device *gf_dev, u16 addr, u8 value)
|
|
{
|
|
struct spi_message msg;
|
|
struct spi_transfer *xfer = NULL;
|
|
|
|
xfer = kzalloc(sizeof(*xfer), GFP_KERNEL);
|
|
if (xfer == NULL)
|
|
return -ENOMEM;
|
|
|
|
spi_message_init(&msg);
|
|
*gf_dev->spi_buffer = 0xF0;
|
|
*(gf_dev->spi_buffer + 1) = (u8)((addr >> 8) & 0xFF);
|
|
*(gf_dev->spi_buffer + 2) = (u8)(addr & 0xFF);
|
|
*(gf_dev->spi_buffer + 3) = value;
|
|
|
|
xfer[0].tx_buf = gf_dev->spi_buffer;
|
|
xfer[0].len = 3 + 1;
|
|
set_delay_in_spi_transfer(&xfer[0], SPI_TRANSFER_DELAY);
|
|
spi_message_add_tail(&xfer[0], &msg);
|
|
spi_sync(gf_dev->spi, &msg);
|
|
|
|
kfree(xfer);
|
|
if (xfer != NULL)
|
|
xfer = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int gw3x_spi_transfer_raw(struct gf_device *gf_dev, u8 *tx_buf,
|
|
u8 *rx_buf, u32 len)
|
|
{
|
|
struct spi_message msg;
|
|
struct spi_transfer xfer;
|
|
|
|
spi_message_init(&msg);
|
|
memset(&xfer, 0, sizeof(struct spi_transfer));
|
|
|
|
xfer.tx_buf = tx_buf;
|
|
xfer.rx_buf = rx_buf;
|
|
xfer.len = len;
|
|
spi_message_add_tail(&xfer, &msg);
|
|
spi_sync(gf_dev->spi, &msg);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int gw3x_ioctl_transfer_raw_cmd(struct gf_device *gf_dev,
|
|
unsigned long arg, unsigned int bufsiz)
|
|
{
|
|
struct gf_ioc_transfer_raw ioc_xraw;
|
|
int retval = 0;
|
|
uint32_t len;
|
|
#ifdef CONFIG_SENSORS_FINGERPRINT_32BITS_PLATFORM_ONLY
|
|
struct gf_ioc_transfer_raw_32 ioc_xraw_32;
|
|
u64 read_buf_64;
|
|
u64 write_buf_64;
|
|
#endif
|
|
|
|
do {
|
|
#ifdef CONFIG_SENSORS_FINGERPRINT_32BITS_PLATFORM_ONLY
|
|
if (copy_from_user(&ioc_xraw_32, (void __user *)arg,
|
|
sizeof(struct gf_ioc_transfer_raw_32)))
|
|
#else
|
|
if (copy_from_user(&ioc_xraw, (void __user *)arg,
|
|
sizeof(struct gf_ioc_transfer_raw)))
|
|
#endif
|
|
{
|
|
pr_err("Failed to copy gf_ioc_transfer_raw from user to kernel\n");
|
|
retval = -EFAULT;
|
|
break;
|
|
}
|
|
|
|
#ifdef CONFIG_SENSORS_FINGERPRINT_32BITS_PLATFORM_ONLY
|
|
read_buf_64 = (u64)ioc_xraw_32.read_buf;
|
|
write_buf_64 = (u64)ioc_xraw_32.write_buf;
|
|
ioc_xraw.read_buf = (u8 *)read_buf_64;
|
|
ioc_xraw.write_buf = (u8 *)write_buf_64;
|
|
ioc_xraw.high_time = ioc_xraw_32.high_time;
|
|
ioc_xraw.bits_per_word = ioc_xraw_32.bits_per_word;
|
|
ioc_xraw.len = ioc_xraw_32.len;
|
|
#endif
|
|
if ((ioc_xraw.len > bufsiz) || (ioc_xraw.len == 0)) {
|
|
pr_err("request transfer length larger than maximum buffer\n");
|
|
retval = -EINVAL;
|
|
break;
|
|
}
|
|
|
|
if (ioc_xraw.read_buf == NULL || ioc_xraw.write_buf == NULL) {
|
|
pr_err("read buf and write buf can not equal to NULL simultaneously.\n");
|
|
retval = -EINVAL;
|
|
break;
|
|
}
|
|
|
|
/* change speed and set transfer mode */
|
|
gw3x_spi_setup_conf(gf_dev, ioc_xraw.bits_per_word);
|
|
|
|
len = ioc_xraw.len;
|
|
|
|
if (copy_from_user(gf_dev->tx_buf, (void __user *)ioc_xraw.write_buf,
|
|
ioc_xraw.len)) {
|
|
pr_err("Failed to copy gf_ioc_transfer from user to kernel\n");
|
|
retval = -EFAULT;
|
|
break;
|
|
}
|
|
|
|
gw3x_spi_transfer_raw(gf_dev, gf_dev->tx_buf, gf_dev->rx_buf, len);
|
|
|
|
if (copy_to_user((void __user *)ioc_xraw.read_buf,
|
|
gf_dev->rx_buf, ioc_xraw.len)) {
|
|
pr_err("Failed to copy gf_ioc_transfer_raw from kernel to user\n");
|
|
retval = -EFAULT;
|
|
}
|
|
|
|
} while (0);
|
|
|
|
return retval;
|
|
}
|
|
|
|
int gw3x_init_buffer(struct gf_device *gf_dev)
|
|
{
|
|
int retval = 0;
|
|
int len = TANSFER_MAX_LEN;
|
|
|
|
gf_dev->spi_buffer = kzalloc(len, GFP_KERNEL);
|
|
if (gf_dev->spi_buffer == NULL) {
|
|
retval = -ENOMEM;
|
|
goto alloc_failed;
|
|
}
|
|
|
|
gf_dev->tx_buf = kzalloc(len, GFP_KERNEL);
|
|
if (gf_dev->tx_buf == NULL) {
|
|
retval = -ENOMEM;
|
|
goto alloc_failed;
|
|
}
|
|
|
|
gf_dev->rx_buf = kzalloc(len, GFP_KERNEL);
|
|
if (gf_dev->rx_buf == NULL) {
|
|
kfree(gf_dev->tx_buf);
|
|
pr_err("failed to allocate raw rx buffer\n");
|
|
retval = -ENOMEM;
|
|
}
|
|
alloc_failed:
|
|
return retval;
|
|
}
|
|
|
|
int gw3x_free_buffer(struct gf_device *gf_dev)
|
|
{
|
|
kfree(gf_dev->spi_buffer);
|
|
kfree(gf_dev->tx_buf);
|
|
kfree(gf_dev->rx_buf);
|
|
return 0;
|
|
}
|
|
#endif
|