blob: 4fe68e84b42771ed7c7244f1d7033e221dc90800 [file] [log] [blame]
/*
* Copyright (C) 2016 Samsung Electronics. 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
* version 2 as published by the Free Software Foundation.
*
* 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 <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include "et7xx.h"
int et7xx_io_read_register(struct et7xx_data *etspi, u8 *addr, u8 *buf)
{
#ifdef ENABLE_SENSORS_FPRINT_SECURE
return 0;
#else
int retval = 0;
struct spi_message m;
int read_len = 1;
u8 val, addrval;
struct spi_transfer xfer = {
.tx_buf = etspi->buf,
.rx_buf = etspi->buf,
.len = 3,
};
memset(etspi->buf, 0, xfer.len);
*etspi->buf = OP_REG_R;
if (copy_from_user(&addrval, (const u8 __user *) (uintptr_t) addr
, read_len)) {
pr_err("buffer copy_from_user fail\n");
return -EFAULT;
}
*(etspi->buf + 1) = addrval;
spi_message_init(&m);
spi_message_add_tail(&xfer, &m);
retval = spi_sync(etspi->spi, &m);
if (retval < 0) {
pr_err("read data error retval = %d\n", retval);
return retval;
}
val = *(etspi->buf + 2);
pr_debug("len = %d addr = %x val = %x\n", read_len, addrval, val);
if (copy_to_user((u8 __user *) (uintptr_t) buf, &val, read_len)) {
pr_err("buffer copy_to_user fail retval\n");
return -EFAULT;
}
return retval;
#endif
}
int et7xx_io_burst_read_register(struct et7xx_data *etspi,
struct egis_ioc_transfer *ioc)
{
#ifdef ENABLE_SENSORS_FPRINT_SECURE
return 0;
#else
int retval = 0;
struct spi_message m;
struct spi_transfer xfer = {
.tx_buf = etspi->buf,
.rx_buf = etspi->buf,
.len = ioc->len + 2,
};
if (ioc->len <= 0 || ioc->len + 2 > etspi->bufsiz) {
retval = -ENOMEM;
pr_err("error retval = %d\n", retval);
goto end;
}
memset(etspi->buf, 0, xfer.len);
*etspi->buf = OP_REG_R_S;
if (copy_from_user(etspi->buf + 1,
(const u8 __user *) (uintptr_t) ioc->tx_buf, 1)) {
pr_err("buffer copy_from_user fail\n");
retval = -EFAULT;
goto end;
}
pr_debug("tx_buf = %p op = %x reg = %x, len = %d\n",
ioc->tx_buf, *etspi->buf, *(etspi->buf + 1), xfer.len);
spi_message_init(&m);
spi_message_add_tail(&xfer, &m);
retval = spi_sync(etspi->spi, &m);
if (retval < 0) {
retval = -ENOMEM;
pr_err("error retval = %d\n", retval);
goto end;
}
if (copy_to_user((u8 __user *) (uintptr_t)ioc->rx_buf, etspi->buf + 2,
ioc->len)) {
retval = -EFAULT;
pr_err("buffer copy_to_user fail retval\n");
goto end;
}
end:
return retval;
#endif
}
int et7xx_io_burst_read_register_backward(struct et7xx_data *etspi,
struct egis_ioc_transfer *ioc)
{
#ifdef ENABLE_SENSORS_FPRINT_SECURE
return 0;
#else
int retval = 0;
struct spi_message m;
struct spi_transfer xfer = {
.tx_buf = etspi->buf,
.rx_buf = etspi->buf,
.len = ioc->len + 2,
};
if (ioc->len <= 0 || ioc->len + 2 > etspi->bufsiz) {
retval = -ENOMEM;
pr_err("error retval = %d\n", retval);
goto end;
}
memset(etspi->buf, 0, xfer.len);
*etspi->buf = OP_REG_R_S_BW;
if (copy_from_user(etspi->buf + 1,
(const u8 __user *) (uintptr_t)ioc->tx_buf, 1)) {
pr_err("buffer copy_from_user fail\n");
retval = -EFAULT;
goto end;
}
pr_debug("tx_buf = %p op = %x reg = %x, len = %d\n",
ioc->tx_buf, *etspi->buf, *(etspi->buf + 1), xfer.len);
spi_message_init(&m);
spi_message_add_tail(&xfer, &m);
retval = spi_sync(etspi->spi, &m);
if (retval < 0) {
retval = -ENOMEM;
pr_err("error retval = %d\n", retval);
goto end;
}
if (copy_to_user((u8 __user *) (uintptr_t)ioc->rx_buf, etspi->buf + 2,
ioc->len)) {
retval = -EFAULT;
pr_err("buffer copy_to_user fail retval\n");
goto end;
}
end:
return retval;
#endif
}
int et7xx_io_write_register(struct et7xx_data *etspi, u8 *buf)
{
#ifdef ENABLE_SENSORS_FPRINT_SECURE
return 0;
#else
int retval = 0;
int write_len = 2;
struct spi_message m;
u8 val[3];
struct spi_transfer xfer = {
.tx_buf = etspi->buf,
.len = 3,
};
memset(etspi->buf, 0, xfer.len);
*etspi->buf = OP_REG_W;
if (copy_from_user(val, (const u8 __user *) (uintptr_t) buf,
write_len)) {
pr_err("buffer copy_from_user fail\n");
return -EFAULT;
}
pr_debug("write_len = %d addr = %x data = %x\n",
write_len, val[0], val[1]);
*(etspi->buf + 1) = val[0];
*(etspi->buf + 2) = val[1];
spi_message_init(&m);
spi_message_add_tail(&xfer, &m);
retval = spi_sync(etspi->spi, &m);
if (retval < 0) {
pr_err("read data error retval = %d\n", retval);
return retval;
}
return retval;
#endif
}
int et7xx_io_burst_write_register(struct et7xx_data *etspi,
struct egis_ioc_transfer *ioc)
{
#ifdef ENABLE_SENSORS_FPRINT_SECURE
return 0;
#else
int retval = 0;
struct spi_message m;
struct spi_transfer xfer = {
.tx_buf = etspi->buf,
.len = ioc->len + 1,
};
if (ioc->len <= 0 || ioc->len + 2 > etspi->bufsiz) {
retval = -ENOMEM;
pr_err("error retval = %d\n", retval);
goto end;
}
memset(etspi->buf, 0, ioc->len + 1);
*etspi->buf = OP_REG_W_S;
if (copy_from_user(etspi->buf + 1,
(const u8 __user *) (uintptr_t) ioc->tx_buf,
ioc->len)) {
pr_err("buffer copy_from_user fail\n");
retval = -EFAULT;
goto end;
}
pr_debug("tx_buf = %p op = %x reg = %x, len = %d\n",
ioc->tx_buf, *etspi->buf, *(etspi->buf + 1), xfer.len);
spi_message_init(&m);
spi_message_add_tail(&xfer, &m);
retval = spi_sync(etspi->spi, &m);
if (retval < 0) {
pr_err("error retval = %d\n", retval);
goto end;
}
end:
return retval;
#endif
}
int et7xx_io_burst_write_register_backward(struct et7xx_data *etspi,
struct egis_ioc_transfer *ioc)
{
#ifdef ENABLE_SENSORS_FPRINT_SECURE
return 0;
#else
int retval = 0;
struct spi_message m;
struct spi_transfer xfer = {
.tx_buf = etspi->buf,
.len = ioc->len + 1,
};
if (ioc->len <= 0 || ioc->len + 2 > etspi->bufsiz) {
retval = -ENOMEM;
pr_err("error retval = %d\n", retval);
goto end;
}
memset(etspi->buf, 0, ioc->len + 1);
*etspi->buf = OP_REG_W_S_BW;
if (copy_from_user(etspi->buf + 1,
(const u8 __user *) (uintptr_t)ioc->tx_buf, ioc->len)) {
pr_err("buffer copy_from_user fail\n");
retval = -EFAULT;
goto end;
}
pr_debug("tx_buf = %p op = %x reg = %x, len = %d\n",
ioc->tx_buf, *etspi->buf, *(etspi->buf + 1), xfer.len);
spi_message_init(&m);
spi_message_add_tail(&xfer, &m);
retval = spi_sync(etspi->spi, &m);
if (retval < 0) {
pr_err("error retval = %d\n", retval);
goto end;
}
end:
return retval;
#endif
}
int et7xx_io_read_efuse(struct et7xx_data *etspi, struct egis_ioc_transfer *ioc)
{
#ifdef ENABLE_SENSORS_FPRINT_SECURE
return 0;
#else
int retval;
struct spi_message m;
u8 *buf = NULL;
struct spi_transfer xfer = {
.tx_buf = NULL,
.rx_buf = NULL,
.len = ioc->len + 1,
};
if (xfer.len >= LARGE_SPI_TRANSFER_BUFFER) {
if ((xfer.len) % DIVISION_OF_IMAGE != 0)
xfer.len = xfer.len + (DIVISION_OF_IMAGE -
(xfer.len % DIVISION_OF_IMAGE));
}
buf = kzalloc(xfer.len, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
xfer.tx_buf = xfer.rx_buf = buf;
buf[0] = OP_EF_R;
pr_debug("len = %d, xfer.len = %d, buf = %p, rx_buf = %p\n",
ioc->len, xfer.len, buf, ioc->rx_buf);
spi_message_init(&m);
spi_message_add_tail(&xfer, &m);
retval = spi_sync(etspi->spi, &m);
if (retval < 0) {
pr_err("read data error retval = %d\n", retval);
goto end;
}
if (copy_to_user((u8 __user *) (uintptr_t) ioc->rx_buf, buf + 1,
ioc->len)) {
pr_err("buffer copy_to_user fail retval\n");
retval = -EFAULT;
}
end:
kfree(buf);
return retval;
#endif
}
int et7xx_io_write_efuse(struct et7xx_data *etspi,
struct egis_ioc_transfer *ioc)
{
#ifdef ENABLE_SENSORS_FPRINT_SECURE
return 0;
#else
int retval;
struct spi_message m;
u8 *buf = NULL;
struct spi_transfer xfer = {
.tx_buf = NULL,
.rx_buf = NULL,
.len = ioc->len + 1,
};
if (xfer.len >= LARGE_SPI_TRANSFER_BUFFER) {
if ((xfer.len) % DIVISION_OF_IMAGE != 0)
xfer.len = xfer.len + (DIVISION_OF_IMAGE -
(xfer.len % DIVISION_OF_IMAGE));
}
buf = kzalloc(xfer.len, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
if (copy_from_user((u8 __user *) (uintptr_t) buf + 1, ioc->tx_buf,
ioc->len)) {
pr_err("buffer copy_from_user fail retval\n");
retval = -EFAULT;
goto end;
}
xfer.tx_buf = xfer.rx_buf = buf;
buf[0] = OP_EF_W;
pr_debug("len = %d, xfer.len = %d, buf = %p, tx_buf = %p\n",
ioc->len, xfer.len, buf, ioc->tx_buf);
spi_message_init(&m);
spi_message_add_tail(&xfer, &m);
retval = spi_sync(etspi->spi, &m);
if (retval < 0)
pr_err("write data error retval = %d\n", retval);
end:
kfree(buf);
return retval;
#endif
}
int et7xx_io_get_frame(struct et7xx_data *etspi, u8 *fr, u32 size)
{
#ifdef ENABLE_SENSORS_FPRINT_SECURE
return 0;
#else
int retval;
struct spi_message m;
u8 *buf = NULL;
struct spi_transfer xfer = {
.tx_buf = NULL,
.rx_buf = NULL,
.len = size + 1,
};
if (xfer.len >= LARGE_SPI_TRANSFER_BUFFER) {
if ((xfer.len) % DIVISION_OF_IMAGE != 0)
xfer.len = xfer.len + (DIVISION_OF_IMAGE -
(xfer.len % DIVISION_OF_IMAGE));
}
buf = kzalloc(xfer.len, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
xfer.tx_buf = xfer.rx_buf = buf;
buf[0] = OP_FB_R;
pr_debug("size = %d, xfer.len = %d, buf = %p, fr = %p\n",
size, xfer.len, buf, fr);
spi_message_init(&m);
spi_message_add_tail(&xfer, &m);
retval = spi_sync(etspi->spi, &m);
if (retval < 0) {
pr_err("read data error retval = %d\n", retval);
goto end;
}
if (copy_to_user((u8 __user *) (uintptr_t) fr, buf + 1, size)) {
pr_err("buffer copy_to_user fail retval\n");
retval = -EFAULT;
}
end:
kfree(buf);
return retval;
#endif
}
int et7xx_io_write_frame(struct et7xx_data *etspi, u8 *fr, u32 size)
{
#ifdef ENABLE_SENSORS_FPRINT_SECURE
return 0;
#else
int retval;
struct spi_message m;
u8 *buf = NULL;
struct spi_transfer xfer = {
.tx_buf = NULL,
.rx_buf = NULL,
.len = size + 1,
};
if (xfer.len >= LARGE_SPI_TRANSFER_BUFFER) {
if ((xfer.len) % DIVISION_OF_IMAGE != 0)
xfer.len = xfer.len + (DIVISION_OF_IMAGE -
(xfer.len % DIVISION_OF_IMAGE));
}
buf = kzalloc(xfer.len, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
if (copy_from_user((u8 __user *)(uintptr_t)buf + 1, fr, size)) {
pr_err("buffer copy_from_user fail retval\n");
retval = -EFAULT;
goto end;
}
xfer.tx_buf = xfer.rx_buf = buf;
buf[0] = OP_FB_W;
pr_debug("size = %d, xfer.len = %d, buf = %p, fr = %p\n",
size, xfer.len, buf, fr);
spi_message_init(&m);
spi_message_add_tail(&xfer, &m);
retval = spi_sync(etspi->spi, &m);
if (retval < 0)
pr_err("write data error retval = %d\n", retval);
end:
kfree(buf);
return retval;
#endif
}
int et7xx_io_get_zone_average(struct et7xx_data *etspi, u8 *fr, u32 size)
{
#ifdef ENABLE_SENSORS_FPRINT_SECURE
return 0;
#else
int retval;
struct spi_message m;
u8 *buf = NULL;
struct spi_transfer xfer = {
.tx_buf = NULL,
.rx_buf = NULL,
.len = size + 1,
};
if (xfer.len >= LARGE_SPI_TRANSFER_BUFFER) {
if ((xfer.len) % DIVISION_OF_IMAGE != 0)
xfer.len = xfer.len + (DIVISION_OF_IMAGE -
(xfer.len % DIVISION_OF_IMAGE));
}
buf = kzalloc(xfer.len, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
xfer.tx_buf = xfer.rx_buf = buf;
buf[0] = OP_ZAVG_R;
pr_debug("size = %d, xfer.len = %d, buf = %p, fr = %p\n",
size, xfer.len, buf, fr);
spi_message_init(&m);
spi_message_add_tail(&xfer, &m);
retval = spi_sync(etspi->spi, &m);
if (retval < 0) {
pr_err("read data error retval = %d\n", retval);
goto end;
}
if (copy_to_user((u8 __user *) (uintptr_t) fr, buf + 1, size)) {
pr_err("buffer copy_to_user fail retval\n");
retval = -EFAULT;
}
end:
kfree(buf);
return retval;
#endif
}
int et7xx_io_get_histogram(struct et7xx_data *etspi, u8 *fr, u32 size)
{
#ifdef ENABLE_SENSORS_FPRINT_SECURE
return 0;
#else
int retval;
struct spi_message m;
u8 *buf = NULL;
struct spi_transfer xfer = {
.tx_buf = NULL,
.rx_buf = NULL,
.len = size + 1,
};
if (xfer.len >= LARGE_SPI_TRANSFER_BUFFER) {
if ((xfer.len) % DIVISION_OF_IMAGE != 0)
xfer.len = xfer.len + (DIVISION_OF_IMAGE -
(xfer.len % DIVISION_OF_IMAGE));
}
buf = kzalloc(xfer.len, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
xfer.tx_buf = xfer.rx_buf = buf;
buf[0] = OP_HSTG_R;
pr_debug("size = %d, xfer.len = %d, buf = %p, fr = %p\n",
size, xfer.len, buf, fr);
spi_message_init(&m);
spi_message_add_tail(&xfer, &m);
retval = spi_sync(etspi->spi, &m);
if (retval < 0) {
pr_err("read data error retval = %d\n", retval);
goto end;
}
if (copy_to_user((u8 __user *) (uintptr_t) fr, buf + 1, size)) {
pr_err("buffer copy_to_user fail retval\n");
retval = -EFAULT;
}
end:
kfree(buf);
return retval;
#endif
}
int et7xx_io_read_cis_register(struct et7xx_data *etspi, u8 *addr, u8 *buf)
{
#ifdef ENABLE_SENSORS_FPRINT_SECURE
return 0;
#else
#define CIS_READ_TIMEOUT 1000
int retval = 0, read_len = 2, try_time = 0;
struct spi_message m;
u8 tr[] = { OP_CIS_ADDR_R, 0x24, 0x00, 0x00, 0x00, 0x00};
u8 val;
struct spi_transfer xfer_addr = {
.tx_buf = tr,
.len = 6,
};
struct spi_transfer xfer_data = {
.rx_buf = tr,
.len = 1,
};
if (copy_from_user(&tr[2], (const u8 __user *) (uintptr_t) addr
, read_len)) {
pr_err("buffer copy_from_user fail. addr(%p)\n", addr);
return -EFAULT;
}
tr[5] = tr[0] + tr[1] + tr[2] + tr[3] + tr[4];
pr_info("len(%d) addr(%p) i2c(%x) addrH(%x) addrL(%x) crc(%x) buf(%p)\n",
read_len, addr, tr[1], tr[2], tr[3], tr[5], buf);
spi_message_init(&m);
spi_message_add_tail(&xfer_addr, &m);
retval = spi_sync(etspi->spi, &m);
if (retval < 0) {
pr_err("read data (0x71) error retval = %d\n", retval);
return retval;
}
while (try_time < CIS_READ_TIMEOUT) {
tr[0] = 0x00;
spi_message_init(&m);
spi_message_add_tail(&xfer_data, &m);
retval = spi_sync(etspi->spi, &m);
if (retval < 0) {
pr_err("read data error retval = %d\n", retval);
return retval;
}
if (tr[0] == 0xAA) {
pr_info("tr[0] = %x, try_time(%d)\n", tr[0], try_time);
break;
}
usleep_range(10, 20);
try_time++;
}
if (try_time >= CIS_READ_TIMEOUT)
pr_err("TIMEOUT!! try_time >= CIS_READ_TIMEOUT(1000)\n");
tr[0] = 0x81;
tr[1] = 0x24;
tr[2] = 0x00;
tr[3] = 0x00;
tr[4] = 0x00;
tr[5] = tr[0] + tr[1] + tr[2] + tr[3] + tr[4];
pr_info("op(%d) i2c(%x) crc(%d)\n", tr[0], tr[1], tr[5]);
spi_message_init(&m);
spi_message_add_tail(&xfer_addr, &m);
retval = spi_sync(etspi->spi, &m);
if (retval < 0) {
pr_err("read data (0x81) error retval = %d\n", retval);
return retval;
}
tr[0] = 0x00;
pr_info("get data(0x81) tr[0] = %x\n", tr[0]);
spi_message_init(&m);
spi_message_add_tail(&xfer_data, &m);
retval = spi_sync(etspi->spi, &m);
if (retval < 0) {
pr_err("read data error retval = %d\n", retval);
return retval;
}
val = tr[0];
pr_info("val = %x\n", val);
if (copy_to_user((u8 __user *) (uintptr_t) buf, &val, 1)) {
pr_err("buffer copy_to_user fail retval\n");
return -EFAULT;
}
if (try_time >= CIS_READ_TIMEOUT)
return -ETIME;
else
return retval;
#endif
}
int et7xx_io_write_cis_register(struct et7xx_data *etspi, u8 *buf)
{
#ifdef ENABLE_SENSORS_FPRINT_SECURE
return 0;
#else
int retval = 0, write_len = 3, try_time = 0;
struct spi_message m;
u8 tx[] = {OP_CIS_REG_W, 0x24, 0x00, 0x00, 0x00, 0x00}, val[3];
struct spi_transfer xfer = {
.tx_buf = tx,
.len = 6,
};
struct spi_transfer xfer_data = {
.rx_buf = tx,
.len = 1,
};
if (copy_from_user(val, (const u8 __user *) (uintptr_t) buf
, write_len)) {
pr_err("buffer copy_from_user fail. buf(%p)\n", buf);
return -EFAULT;
}
pr_info("write_len = %d addrH = %x addrL = %x data = %x buf = %p\n",
write_len, val[0], val[1], val[2], buf);
tx[2] = val[0];
tx[3] = val[1];
tx[4] = val[2];
tx[5] = tx[0] + tx[1] + tx[2] + tx[3] + tx[4];
spi_message_init(&m);
spi_message_add_tail(&xfer, &m);
retval = spi_sync(etspi->spi, &m);
if (retval < 0) {
pr_err("write data (0x70) error retval = %d\n", retval);
return retval;
}
while (try_time < 2000) {
tx[0] = 0x00;
spi_message_init(&m);
spi_message_add_tail(&xfer_data, &m);
retval = spi_sync(etspi->spi, &m);
if (retval < 0) {
pr_err("read data error retval = %d\n", retval);
return retval;
}
if (tx[0] == 0xAA) {
pr_info("tx[0] == 0xAA, try_time = %d\n", try_time);
break;
}
usleep_range(10, 20);
try_time++;
}
if (try_time >= 2000)
pr_err("------------- try_time >= 2000 ---------------\n");
return retval;
#endif
}
int et7xx_io_pre_capture(struct et7xx_data *etspi)
{
#ifdef ENABLE_SENSORS_FPRINT_SECURE
return 0;
#else
int retval = 0;
struct spi_message m;
u8 tx[] = {OP_PRE_CAPTURE, 0x00, 0x00, 0x00, 0x00, 0x00};
int try_time = 0;
struct spi_transfer xfer = {
.tx_buf = tx,
.len = 6,
};
struct spi_transfer xfer_data = {
.rx_buf = tx,
.len = 1,
};
pr_info("tx[0] = %d\n", tx[0]);
tx[5] = tx[0] + tx[1] + tx[2] + tx[3] + tx[4];
spi_message_init(&m);
spi_message_add_tail(&xfer, &m);
retval = spi_sync(etspi->spi, &m);
if (retval < 0) {
pr_err("set pre capture error retval = %d\n", retval);
return retval;
}
while (try_time < 8000) {
tx[0] = 0x00;
spi_message_init(&m);
spi_message_add_tail(&xfer_data, &m);
retval = spi_sync(etspi->spi, &m);
if (retval < 0) {
pr_err("read data error retval = %d\n", retval);
return retval;
}
if (tx[0] == 0xAA) {
pr_info("tx[0] == 0xAA, try_time = %d\n", try_time);
break;
}
usleep_range(10, 20);
try_time++;
}
if (try_time >= 8000) {
pr_err("------------- try_time >= 8000 ---------------\n");
return -ETIME;
}
return retval;
#endif
}
int et7xx_io_get_cis_frame(struct et7xx_data *etspi, u8 *fr, u32 size)
{
#ifdef ENABLE_SENSORS_FPRINT_SECURE
return 0;
#else
int retval;
struct spi_message m;
u8 *buf = NULL;
u8 tx[] = { OP_GET_FRAME, 0x00, 0x00, 0x00, 0x00, 0x00};
u32 size_et736 = 0;
struct spi_transfer xfer_op = {
.tx_buf = tx,
.len = 6,
};
struct spi_transfer xfer_data = {
.rx_buf = NULL,
};
size_et736 = ((324 * 324) / 1024) * 1024 + 1024;
buf = kzalloc(size_et736, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
pr_info("size = %d, buf = %p, fr = %p\n", size, buf, fr);
/*read sector 0.*/
xfer_data.rx_buf = buf;
xfer_data.len = 60*1024;
tx[4] = 60;
tx[5] = tx[0] + tx[1] + tx[2] + tx[3] + tx[4];
pr_info("(0) xfer_data.len = %d, rx_buf = %p, tx[2](%x), tx[3](%x), tx[4](%x)\n",
xfer_data.len, xfer_data.rx_buf, tx[2], tx[3], tx[4]);
spi_message_init(&m);
spi_message_add_tail(&xfer_op, &m);
retval = spi_sync(etspi->spi, &m);
if (retval < 0) {
pr_err("set sector(0) error retval = %d\n", retval);
goto end;
}
/*read sector 0.*/
spi_message_init(&m);
spi_message_add_tail(&xfer_data, &m);
retval = spi_sync(etspi->spi, &m);
if (retval < 0) {
pr_err("read data(0) error retval = %d\n", retval);
goto end;
}
tx[2] = 60;
tx[4] = 43;
tx[5] = tx[0] + tx[1] + tx[2] + tx[3] + tx[4];
pr_info("(1) xfer_data.len = %d, rx_buf = %p, tx[2](%x), tx[3](%x), tx[4](%x)\n",
size_et736 - 60 * 1024, buf + 60 * 1024, tx[2], tx[3], tx[4]);
usleep_range(10 * 1000, 12 * 1000);
spi_message_init(&m);
spi_message_add_tail(&xfer_op, &m);
retval = spi_sync(etspi->spi, &m);
if (retval < 0) {
pr_err("set sector(0) error retval = %d\n", retval);
goto end;
}
/* read sector 1 */
xfer_data.rx_buf = buf + 60 * 1024;
xfer_data.len = size_et736 - 60 * 1024;
spi_message_init(&m);
spi_message_add_tail(&xfer_data, &m);
retval = spi_sync(etspi->spi, &m);
if (retval < 0) {
pr_err("read data(0) error retval = %d\n", retval);
goto end;
}
pr_info("(1) xfer_data.len = %d, rx_buf = %p, tx[1](%x), tx[2](%x), tx[3](%x)\n",
xfer_data.len, xfer_data.rx_buf, tx[1], tx[2], tx[3]);
if (copy_to_user((u8 __user *) (uintptr_t) fr, buf, size)) {
pr_err("buffer copy_to_user fail.\n");
retval = -EFAULT;
}
end:
kfree(buf);
return retval;
#endif
}
int et7xx_io_transfer_command(struct et7xx_data *etspi, u8 *tx, u8 *rx,
u32 size)
{
#ifdef ENABLE_SENSORS_FPRINT_SECURE
return 0;
#else
int retval = 0;
struct spi_message m;
u8 *tr;
struct spi_transfer xfer = {
.len = size,
};
pr_info("tx(%p), rx(%p), size(%d)\n", tx, rx, size);
tr = kzalloc(size, GFP_KERNEL);
if (tr == NULL)
return -ENOMEM;
xfer.tx_buf = xfer.rx_buf = tr;
if (copy_from_user(tr, (const u8 __user *)(uintptr_t)tx, size)) {
pr_err("buffer copy_from_user fail. tr(%p), tx(%p)\n", tr,
tx);
retval = -EFAULT;
goto out;
}
spi_message_init(&m);
spi_message_add_tail(&xfer, &m);
retval = spi_sync(etspi->spi, &m);
if (retval < 0) {
pr_err("retval = %d\n", retval);
goto out;
}
if (copy_to_user(rx, (const u8 __user *)(uintptr_t)tr, size)) {
pr_err("buffer copy_to_user fail. tr(%p) rx(%p)\n", tr,
rx);
retval = -EFAULT;
goto out;
}
out:
kfree(tr);
return retval;
#endif
}
int et7xx_write_register(struct et7xx_data *etspi, u8 addr, u8 buf)
{
#ifdef ENABLE_SENSORS_FPRINT_SECURE
return 0;
#else
int retval;
struct spi_message m;
u8 tx[] = {OP_REG_W, addr, buf};
struct spi_transfer xfer = {
.tx_buf = tx,
.rx_buf = NULL,
.len = 3,
};
spi_message_init(&m);
spi_message_add_tail(&xfer, &m);
retval = spi_sync(etspi->spi, &m);
if (retval == 0) {
pr_info("address = %x\n", addr);
} else {
pr_err("read data error retval = %d\n", retval);
}
return retval;
#endif
}
int et7xx_read_register(struct et7xx_data *etspi, u8 addr, u8 *buf)
{
#ifdef ENABLE_SENSORS_FPRINT_SECURE
return 0;
#else
int retval;
struct spi_message m;
u8 read_value[] = {OP_REG_R, addr, 0x00};
u8 result[] = {0xFF, 0xFF, 0xFF};
struct spi_transfer xfer = {
.tx_buf = read_value,
.rx_buf = result,
.len = 3,
};
spi_message_init(&m);
spi_message_add_tail(&xfer, &m);
retval = spi_sync(etspi->spi, &m);
if (retval == 0) {
*buf = result[2];
pr_info("address = %x result = %x %x\n", addr, result[1], result[2]);
} else {
pr_err("read data error retval = %d\n", retval);
}
return retval;
#endif
}
/* For microchip sst */
/* microchip sst communication opcode */
#define MICROCHIP_SST_PAGE_PROGRAM 0x02 /* To program up to 256 Bytes */
#define MICROCHIP_SST_READ 0x03 /* Read Memory */
#define MICROCHIP_SST_WRDI 0x04 /* Write-Disable */
#define MICROCHIP_SST_RDSR 0x05 /* Read-Status-Register */
#define MICROCHIP_SST_WREN 0x06 /* Write-Enable */
#define MICROCHIP_SST_CHIP_ERASE 0x60 /* Erase Full Memory Array */
#define MICROCHIP_SST_SECTOR_ERASE 0xD7 /* Erase 4 KByle sector */
#define MICROCHIP_SST_BLOCK_ERASE 0xD8 /* Erase 64 KByle block */
#define MICROCHIP_SST_ADDRESS_SIZE 3
#define MICROCHIP_SST_RW_OFFSET 4 /* OP code 8 bits and address 32bits */
/* The programmed data must be between 1 to 256 Bytes and in whole byte
* increments; sending less than a full byte will cause the partial byte to
* be ignored.
*/
#define MICROCHIP_SST_PAGE_PROGRAM_LIMITATION 256
#define MICROCHIP_SST_HIGH_SPEED_READ_DUMMY_LEN 1
/* Wait to write/erase finish */
#define MICROCHIP_SST_STATUS_MAX_RETRY_COUNT 100
int et7xx_eeprom_rdsr(struct et7xx_data *etspi, u8 *eeprom_status)
{
#ifdef ENABLE_SENSORS_FPRINT_SECURE
return 0;
#else
int retval;
struct spi_message m;
u8 buf[2];
struct spi_transfer xfer = {
.tx_buf = NULL,
.rx_buf = NULL,
.len = 2,
};
xfer.tx_buf = xfer.rx_buf = buf;
buf[0] = MICROCHIP_SST_RDSR;
spi_message_init(&m);
spi_message_add_tail(&xfer, &m);
retval = spi_sync(etspi->spi, &m);
if (retval < 0) {
pr_err("spi_sync error retval = %d\n", retval);
} else {
if (copy_to_user((u8 __user *) (uintptr_t) eeprom_status,
buf + 1, 1)) {
pr_err("buffer copy_to_user fail\n");
retval = -EFAULT;
}
pr_info("eeprom_status = %d\n", buf[1]);
}
return retval;
#endif
}
int et7xx_eeprom_read_status_internal(struct et7xx_data *etspi, u8 *eeprom_status)
{
#ifdef ENABLE_SENSORS_FPRINT_SECURE
return 0;
#else
int retval;
struct spi_message m;
u8 buf[2];
struct spi_transfer xfer = {
.tx_buf = NULL,
.rx_buf = NULL,
.len = 2,
};
xfer.tx_buf = xfer.rx_buf = buf;
buf[0] = MICROCHIP_SST_RDSR;
spi_message_init(&m);
spi_message_add_tail(&xfer, &m);
retval = spi_sync(etspi->spi, &m);
if (retval < 0) {
pr_err("spi_sync error retval = %d\n", retval);
} else {
*eeprom_status = buf[1];
pr_info("eeprom_status = %d\n", *eeprom_status);
}
return retval;
#endif
}
int et7xx_eeprom_chip_erase(struct et7xx_data *etspi)
{
#ifdef ENABLE_SENSORS_FPRINT_SECURE
return 0;
#else
int retval;
struct spi_message m;
u8 buf[1];
struct spi_transfer xfer = {
.tx_buf = NULL,
.rx_buf = NULL,
.len = 1,
};
xfer.tx_buf = buf;
buf[0] = MICROCHIP_SST_CHIP_ERASE;
spi_message_init(&m);
spi_message_add_tail(&xfer, &m);
retval = spi_sync(etspi->spi, &m);
if (retval < 0)
pr_err("spi_sync error retval = %d\n", retval);
return retval;
#endif
}
int et7xx_eeprom_sector_erase(struct et7xx_data *etspi, struct egis_ioc_transfer *ioc)
{
#ifdef ENABLE_SENSORS_FPRINT_SECURE
return 0;
#else
struct spi_message m;
int retval;
u8 *buf = NULL;
struct spi_transfer xfer = {
.tx_buf = NULL,
.rx_buf = NULL,
.len = 0,
};
if (ioc->len > MICROCHIP_SST_PAGE_PROGRAM_LIMITATION) {
pr_err("len EINVAL\n");
retval = -EINVAL;
}
buf = kzalloc(ioc->len + 1, GFP_KERNEL);
if (buf == NULL) {
pr_err("buf kzalloc fail\n");
retval = -ENOMEM;
goto end;
}
if (copy_from_user(buf + 1, (const u8 __user *) (uintptr_t) ioc->tx_buf
, ioc->len)) {
pr_err("buffer copy_from_user fail\n");
retval = -EFAULT;
goto end;
}
pr_info("Init ioc->len = %d, buf[1] = 0x%x buf[2] = 0x%x, buf[3] = 0x%x\n",
ioc->len, buf[1], buf[2], buf[3]);
xfer.len = ioc->len + 1; /* OP code */
xfer.tx_buf = buf;
xfer.rx_buf = NULL;
buf[0] = MICROCHIP_SST_SECTOR_ERASE;
spi_message_init(&m);
spi_message_add_tail(&xfer, &m);
retval = spi_sync(etspi->spi, &m);
end:
if (buf)
kfree(buf);
return retval;
#endif
}
int et7xx_eeprom_block_erase(struct et7xx_data *etspi, struct egis_ioc_transfer *ioc)
{
#ifdef ENABLE_SENSORS_FPRINT_SECURE
return 0;
#else
struct spi_message m;
int retval;
u8 *buf = NULL;
struct spi_transfer xfer = {
.tx_buf = NULL,
.rx_buf = NULL,
.len = 0,
};
if (ioc->len > MICROCHIP_SST_PAGE_PROGRAM_LIMITATION) {
pr_err("len EINVAL\n");
retval = -EINVAL;
}
buf = kzalloc(ioc->len + 1, GFP_KERNEL);
if (buf == NULL) {
pr_err("buf kzalloc fail\n");
retval = -ENOMEM;
goto end;
}
if (copy_from_user(buf + 1, (const u8 __user *) (uintptr_t) ioc->tx_buf
, ioc->len)) {
pr_err("buffer copy_from_user fail\n");
retval = -EFAULT;
goto end;
}
pr_info("Init ioc->len = %d, buf[1] = 0x%x buf[2] = 0x%x, buf[3] = 0x%x\n",
ioc->len, buf[1], buf[2], buf[3]);
xfer.len = ioc->len + 1; /* OP code */
xfer.tx_buf = buf;
xfer.rx_buf = NULL;
buf[0] = MICROCHIP_SST_BLOCK_ERASE;
spi_message_init(&m);
spi_message_add_tail(&xfer, &m);
retval = spi_sync(etspi->spi, &m);
end:
if (buf)
kfree(buf);
return retval;
#endif
}
int et7xx_eeprom_write_controller(struct et7xx_data *etspi, int enable)
{
#ifdef ENABLE_SENSORS_FPRINT_SECURE
return 0;
#else
int retval;
struct spi_message m;
u8 buf[1];
struct spi_transfer xfer = {
.tx_buf = NULL,
.rx_buf = NULL,
.len = 1,
};
xfer.tx_buf = xfer.rx_buf = buf;
if (enable > 0)
buf[0] = MICROCHIP_SST_WREN;
else
buf[0] = MICROCHIP_SST_WRDI;
spi_message_init(&m);
spi_message_add_tail(&xfer, &m);
retval = spi_sync(etspi->spi, &m);
if (retval < 0)
pr_err("spi_sync error retval = %d\n", retval);
return retval;
#endif
}
int et7xx_eeprom_read(struct et7xx_data *etspi, struct egis_ioc_transfer *ioc)
{
#ifdef ENABLE_SENSORS_FPRINT_SECURE
return 0;
#else
struct spi_message m;
int retval;
u8 *buf = NULL, addr[MICROCHIP_SST_ADDRESS_SIZE];
struct spi_transfer xfer = {
.tx_buf = NULL,
.rx_buf = NULL,
.len = 0,
};
pr_info("Version is 1128-3");
if (copy_from_user(addr, (const u8 __user *) (uintptr_t) ioc->tx_buf
, MICROCHIP_SST_ADDRESS_SIZE)) {
pr_err("buffer copy_from_user fail\n");
return -EFAULT;
}
xfer.len = ioc->len + MICROCHIP_SST_RW_OFFSET;
if (xfer.len >= LARGE_SPI_TRANSFER_BUFFER) {
if ((xfer.len) % DIVISION_OF_IMAGE != 0)
xfer.len = xfer.len + (DIVISION_OF_IMAGE -
(xfer.len % DIVISION_OF_IMAGE));
}
pr_info("xfer.len = %d, addr[0] = 0x%x addr[1] = 0x%x, addr[2] = 0x%x\n",
xfer.len, addr[0], addr[1], addr[2]);
buf = kzalloc(xfer.len, GFP_KERNEL);
if (buf == NULL) {
pr_err("buf kzalloc fail\n");
return -ENOMEM;
}
memset(buf, 0x0, xfer.len);
xfer.tx_buf = xfer.rx_buf = buf;
buf[0] = MICROCHIP_SST_READ;
memcpy(buf + 1, addr, MICROCHIP_SST_ADDRESS_SIZE);
pr_info("ioc->len = %d, xfer.len = %d, buf = %p ", ioc->len, xfer.len, buf);
spi_message_init(&m);
spi_message_add_tail(&xfer, &m);
retval = spi_sync(etspi->spi, &m);
if (retval < 0) {
pr_err("spi_sync error retval = %d\n", retval);
goto end;
}
if (copy_to_user((u8 __user *) (uintptr_t) ioc->rx_buf,
buf + MICROCHIP_SST_RW_OFFSET, ioc->len)) {
pr_err("buffer copy_to_user fail\n");
retval = -EFAULT;
}
end:
if (buf)
kfree(buf);
return retval;
#endif
}
int et7xx_eeprom_high_speed_read(struct et7xx_data *etspi, struct egis_ioc_transfer *ioc)
{
#ifdef ENABLE_SENSORS_FPRINT_SECURE
return 0;
#else
struct spi_message m;
int retval;
u8 *buf = NULL, addr[MICROCHIP_SST_ADDRESS_SIZE];
struct spi_transfer xfer = {
.tx_buf = NULL,
.rx_buf = NULL,
.len = 0,
};
pr_info("Version is 1124-5");
if (copy_from_user(addr, (const u8 __user *) (uintptr_t) ioc->tx_buf
, MICROCHIP_SST_ADDRESS_SIZE)) {
pr_err("buffer copy_from_user fail\n");
return -EFAULT;
}
xfer.len = ioc->len + MICROCHIP_SST_RW_OFFSET;
if (xfer.len >= LARGE_SPI_TRANSFER_BUFFER) {
if ((xfer.len) % DIVISION_OF_IMAGE != 0)
xfer.len = xfer.len + (DIVISION_OF_IMAGE -
(xfer.len % DIVISION_OF_IMAGE));
}
pr_info("xfer.len = %d, addr[0] = 0x%x addr[1] = 0x%x, addr[2] = 0x%x\n",
xfer.len, addr[0], addr[1], addr[2]);
buf = kzalloc(xfer.len + MICROCHIP_SST_HIGH_SPEED_READ_DUMMY_LEN,
GFP_KERNEL);
if (buf == NULL) {
pr_err("buf kzalloc fail\n");
return -ENOMEM;
}
memset(buf, 0x0, xfer.len);
xfer.tx_buf = xfer.rx_buf = buf;
buf[0] = MICROCHIP_SST_READ;
memcpy(buf + 1, addr, MICROCHIP_SST_ADDRESS_SIZE);
pr_info("ioc->len = %d, xfer.len = %d, buf = %p ",
ioc->len, xfer.len, buf);
spi_message_init(&m);
spi_message_add_tail(&xfer, &m);
retval = spi_sync(etspi->spi, &m);
if (retval < 0) {
pr_err("spi_sync error retval = %d\n", retval);
goto end;
}
if (copy_to_user((u8 __user *) (uintptr_t) ioc->rx_buf,
buf + MICROCHIP_SST_RW_OFFSET +
MICROCHIP_SST_HIGH_SPEED_READ_DUMMY_LEN, ioc->len)) {
pr_err("buffer copy_to_user fail\n");
retval = -EFAULT;
}
end:
if (buf)
kfree(buf);
return retval;
#endif
}
int et7xx_eeprom_write(struct et7xx_data *etspi, struct egis_ioc_transfer *ioc)
{
#ifdef ENABLE_SENSORS_FPRINT_SECURE
return 0;
#else
struct spi_message m;
int retval;
u8 *buf = NULL;
struct spi_transfer xfer = {
.tx_buf = NULL,
.rx_buf = NULL,
.len = 0,
};
if (ioc->len > MICROCHIP_SST_PAGE_PROGRAM_LIMITATION) {
pr_err("len EINVAL\n");
retval = -EINVAL;
}
buf = kzalloc(ioc->len + 1, GFP_KERNEL);
if (buf == NULL) {
pr_err("buf kzalloc fail\n");
retval = -ENOMEM;
goto end;
}
if (copy_from_user(buf + 1, (const u8 __user *) (uintptr_t) ioc->tx_buf
, ioc->len)) {
pr_err("buffer copy_from_user fail\n");
retval = -EFAULT;
goto end;
}
pr_info("Init ioc->len = %d, buf[1] = 0x%x buf[2] = 0x%x, buf[3] = 0x%x\n",
ioc->len, buf[1], buf[2], buf[3]);
xfer.len = ioc->len + 1; /* OP code */
xfer.tx_buf = buf;
xfer.rx_buf = NULL;
buf[0] = MICROCHIP_SST_PAGE_PROGRAM;
spi_message_init(&m);
spi_message_add_tail(&xfer, &m);
retval = spi_sync(etspi->spi, &m);
end:
if (buf)
kfree(buf);
return retval;
#endif
}
void et7xx_eeprom_finish_operation(struct et7xx_data *etspi)
{
pr_info("Entry\n");
gpio_set_value(etspi->sleepPin, 1);
usleep_range(1050, 1100);
gpio_set_value(etspi->sleepPin, 0);
}
int et7xx_eeprom_write_in_non_tz(struct et7xx_data *etspi, struct egis_ioc_transfer *ioc)
{
#ifdef ENABLE_SENSORS_FPRINT_SECURE
return 0;
#else
struct spi_message m;
int retval, page_count, index = 0, address_64bits, current_len,
status_retry_count = 0;
u8 *buf = NULL, *data = NULL, eeprom_status = 0x0;
struct spi_transfer xfer = {
.tx_buf = NULL,
.rx_buf = NULL,
.len = 0,
};
et7xx_eeprom_finish_operation(etspi);
retval = et7xx_eeprom_write_controller(etspi, 1);
if (retval < 0) {
pr_err("Write enable fail retval = %d\n", retval);
return retval;
}
et7xx_eeprom_finish_operation(etspi);
retval = et7xx_eeprom_chip_erase(etspi);
if (retval < 0) {
pr_err("erase full fail retval = %d\n", retval);
return retval;
}
et7xx_eeprom_finish_operation(etspi);
do {
usleep_range(500, 1000);
retval = et7xx_eeprom_read_status_internal(etspi, &eeprom_status);
et7xx_eeprom_finish_operation(etspi);
if (retval < 0) {
pr_err("get eeprom_status fail retval = %d\n", retval);
goto end;
}
if (++status_retry_count > MICROCHIP_SST_STATUS_MAX_RETRY_COUNT) {
pr_err("not finish erase eeprom\n");
break;
}
} while ((eeprom_status & 0x01) != 0);
retval = et7xx_eeprom_write_controller(etspi, 0);
if (retval < 0) {
pr_err("Write disable fail retval = %d\n", retval);
return retval;
}
et7xx_eeprom_finish_operation(etspi);
data = kzalloc(ioc->len, GFP_KERNEL);
if (data == NULL) {
pr_err("data kzalloc fail\n");
return -ENOMEM;
}
buf = kzalloc(MICROCHIP_SST_RW_OFFSET +
MICROCHIP_SST_PAGE_PROGRAM_LIMITATION, GFP_KERNEL);
if (buf == NULL) {
pr_err("buf kzalloc fail\n");
retval = -ENOMEM;
goto end;
}
if (copy_from_user(data, (const u8 __user *) (uintptr_t) ioc->tx_buf
, ioc->len)) {
pr_err("buffer copy_from_user fail\n");
retval = -EFAULT;
goto end;
}
address_64bits = (data[0] << 16) + (data[1] << 8) + data[2];
page_count = (ioc->len - MICROCHIP_SST_ADDRESS_SIZE) /
MICROCHIP_SST_PAGE_PROGRAM_LIMITATION;
if ((ioc->len - MICROCHIP_SST_ADDRESS_SIZE) %
MICROCHIP_SST_PAGE_PROGRAM_LIMITATION != 0)
page_count++;
pr_info("Init data : ioc->len = %d, page_count = %d\n",
ioc->len, page_count);
pr_info("Init ioc->len = %d, address = 0x%x address[1] = 0x%x address[2] = 0x%x, address[3] = 0x%x\n",
ioc->len, address_64bits, data[0], data[1], data[2]);
write_eeprom:
retval = et7xx_eeprom_write_controller(etspi, 1);
if (retval < 0) {
pr_err("Write enable fail retval = %d\n", retval);
goto end;
}
et7xx_eeprom_finish_operation(etspi);
if (index >= (page_count - 1)) {
current_len = (ioc->len - MICROCHIP_SST_ADDRESS_SIZE) %
MICROCHIP_SST_PAGE_PROGRAM_LIMITATION;
if (current_len == 0)
current_len = MICROCHIP_SST_PAGE_PROGRAM_LIMITATION;
} else {
current_len = MICROCHIP_SST_PAGE_PROGRAM_LIMITATION;
}
pr_info("Run data : ioc->len = %d, page_count = %d\n",
ioc->len, page_count);
xfer.len = MICROCHIP_SST_RW_OFFSET + current_len;
xfer.tx_buf = buf;
xfer.rx_buf = NULL;
buf[0] = MICROCHIP_SST_PAGE_PROGRAM;
buf[1] = (address_64bits & 0xff0000) >> 16;
buf[2] = (address_64bits & 0x00ff00) >> 8;
buf[3] = (address_64bits & 0x0000ff);
memcpy(buf + MICROCHIP_SST_RW_OFFSET, data + MICROCHIP_SST_ADDRESS_SIZE +
(index * MICROCHIP_SST_PAGE_PROGRAM_LIMITATION), current_len);
pr_info("Run index = %d page_count = %d current_len = %d, xfer.len = %d\n",
index, page_count, current_len, xfer.len);
pr_info("Run address = 0x%x address[1] = 0x%x address[2] = 0x%x, address[3] = 0x%x\n",
address_64bits, buf[1], buf[2], buf[3]);
spi_message_init(&m);
spi_message_add_tail(&xfer, &m);
retval = spi_sync(etspi->spi, &m);
et7xx_eeprom_finish_operation(etspi);
if (retval < 0) {
pr_err("spi_sync error retval = %d\n", retval);
goto end;
}
status_retry_count = 0;
eeprom_status = 0x0;
do {
usleep_range(500, 1000);
retval = et7xx_eeprom_read_status_internal(etspi, &eeprom_status);
et7xx_eeprom_finish_operation(etspi);
if (retval < 0) {
pr_err("get eeprom_status fail retval = %d\n", retval);
goto end;
}
if (++status_retry_count > MICROCHIP_SST_STATUS_MAX_RETRY_COUNT) {
pr_err("not finish writing eeprom\n");
break;
}
} while ((eeprom_status & 0x01) != 0);
retval = et7xx_eeprom_write_controller(etspi, 0);
if (retval < 0) {
pr_err("Write disable fail retval = %d\n", retval);
goto end;
}
et7xx_eeprom_finish_operation(etspi);
if (++index < page_count) {
address_64bits += MICROCHIP_SST_PAGE_PROGRAM_LIMITATION;
goto write_eeprom;
}
end:
gpio_set_value(etspi->sleepPin, 1);
if (buf)
kfree(buf);
if (data)
kfree(data);
return retval;
#endif
}