168 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			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);
 |