tegrakernel/kernel/kernel-4.9/drivers/nfc/st95hf/spi.c

168 lines
4.3 KiB
C

/*
* ----------------------------------------------------------------------------
* drivers/nfc/st95hf/spi.c function definitions for SPI communication
* ----------------------------------------------------------------------------
* Copyright (C) 2015 STMicroelectronics Pvt. Ltd. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "spi.h"
/* Function to send user provided buffer to ST95HF through SPI */
int st95hf_spi_send(struct st95hf_spi_context *spicontext,
unsigned char *buffertx,
int datalen,
enum req_type reqtype)
{
struct spi_message m;
int result = 0;
struct spi_device *spidev = spicontext->spidev;
struct spi_transfer tx_transfer = {
.tx_buf = buffertx,
.len = datalen,
};
mutex_lock(&spicontext->spi_lock);
if (reqtype == SYNC) {
spicontext->req_issync = true;
reinit_completion(&spicontext->done);
} else {
spicontext->req_issync = false;
}
spi_message_init(&m);
spi_message_add_tail(&tx_transfer, &m);
result = spi_sync(spidev, &m);
if (result) {
dev_err(&spidev->dev, "error: sending cmd to st95hf using SPI = %d\n",
result);
mutex_unlock(&spicontext->spi_lock);
return result;
}
/* return for asynchronous or no-wait case */
if (reqtype == ASYNC) {
mutex_unlock(&spicontext->spi_lock);
return 0;
}
result = wait_for_completion_timeout(&spicontext->done,
msecs_to_jiffies(1000));
/* check for timeout or success */
if (!result) {
dev_err(&spidev->dev, "error: response not ready timeout\n");
result = -ETIMEDOUT;
} else {
result = 0;
}
mutex_unlock(&spicontext->spi_lock);
return result;
}
EXPORT_SYMBOL_GPL(st95hf_spi_send);
/* Function to Receive command Response */
int st95hf_spi_recv_response(struct st95hf_spi_context *spicontext,
unsigned char *receivebuff)
{
int len = 0;
struct spi_transfer tx_takedata;
struct spi_message m;
struct spi_device *spidev = spicontext->spidev;
unsigned char readdata_cmd = ST95HF_COMMAND_RECEIVE;
struct spi_transfer t[2] = {
{.tx_buf = &readdata_cmd, .len = 1,},
{.rx_buf = receivebuff, .len = 2, .cs_change = 1,},
};
int ret = 0;
memset(&tx_takedata, 0x0, sizeof(struct spi_transfer));
mutex_lock(&spicontext->spi_lock);
/* First spi transfer to know the length of valid data */
spi_message_init(&m);
spi_message_add_tail(&t[0], &m);
spi_message_add_tail(&t[1], &m);
ret = spi_sync(spidev, &m);
if (ret) {
dev_err(&spidev->dev, "spi_recv_resp, data length error = %d\n",
ret);
mutex_unlock(&spicontext->spi_lock);
return ret;
}
/* As 2 bytes are already read */
len = 2;
/* Support of long frame */
if (receivebuff[0] & 0x60)
len += (((receivebuff[0] & 0x60) >> 5) << 8) | receivebuff[1];
else
len += receivebuff[1];
/* Now make a transfer to read only relevant bytes */
tx_takedata.rx_buf = &receivebuff[2];
tx_takedata.len = len - 2;
spi_message_init(&m);
spi_message_add_tail(&tx_takedata, &m);
ret = spi_sync(spidev, &m);
mutex_unlock(&spicontext->spi_lock);
if (ret) {
dev_err(&spidev->dev, "spi_recv_resp, data read error = %d\n",
ret);
return ret;
}
return len;
}
EXPORT_SYMBOL_GPL(st95hf_spi_recv_response);
int st95hf_spi_recv_echo_res(struct st95hf_spi_context *spicontext,
unsigned char *receivebuff)
{
unsigned char readdata_cmd = ST95HF_COMMAND_RECEIVE;
struct spi_transfer t[2] = {
{.tx_buf = &readdata_cmd, .len = 1,},
{.rx_buf = receivebuff, .len = 1,},
};
struct spi_message m;
struct spi_device *spidev = spicontext->spidev;
int ret = 0;
mutex_lock(&spicontext->spi_lock);
spi_message_init(&m);
spi_message_add_tail(&t[0], &m);
spi_message_add_tail(&t[1], &m);
ret = spi_sync(spidev, &m);
mutex_unlock(&spicontext->spi_lock);
if (ret)
dev_err(&spidev->dev, "recv_echo_res, data read error = %d\n",
ret);
return ret;
}
EXPORT_SYMBOL_GPL(st95hf_spi_recv_echo_res);