162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * ----------------------------------------------------------------------------
462306a36Sopenharmony_ci * drivers/nfc/st95hf/spi.c function definitions for SPI communication
562306a36Sopenharmony_ci * ----------------------------------------------------------------------------
662306a36Sopenharmony_ci * Copyright (C) 2015 STMicroelectronics Pvt. Ltd. All rights reserved.
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include "spi.h"
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci/* Function to send user provided buffer to ST95HF through SPI */
1262306a36Sopenharmony_ciint st95hf_spi_send(struct st95hf_spi_context *spicontext,
1362306a36Sopenharmony_ci		    unsigned char *buffertx,
1462306a36Sopenharmony_ci		    int datalen,
1562306a36Sopenharmony_ci		    enum req_type reqtype)
1662306a36Sopenharmony_ci{
1762306a36Sopenharmony_ci	struct spi_message m;
1862306a36Sopenharmony_ci	int result = 0;
1962306a36Sopenharmony_ci	struct spi_device *spidev = spicontext->spidev;
2062306a36Sopenharmony_ci	struct spi_transfer tx_transfer = {
2162306a36Sopenharmony_ci		.tx_buf = buffertx,
2262306a36Sopenharmony_ci		.len = datalen,
2362306a36Sopenharmony_ci	};
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	mutex_lock(&spicontext->spi_lock);
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	if (reqtype == SYNC) {
2862306a36Sopenharmony_ci		spicontext->req_issync = true;
2962306a36Sopenharmony_ci		reinit_completion(&spicontext->done);
3062306a36Sopenharmony_ci	} else {
3162306a36Sopenharmony_ci		spicontext->req_issync = false;
3262306a36Sopenharmony_ci	}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	spi_message_init(&m);
3562306a36Sopenharmony_ci	spi_message_add_tail(&tx_transfer, &m);
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	result = spi_sync(spidev, &m);
3862306a36Sopenharmony_ci	if (result) {
3962306a36Sopenharmony_ci		dev_err(&spidev->dev, "error: sending cmd to st95hf using SPI = %d\n",
4062306a36Sopenharmony_ci			result);
4162306a36Sopenharmony_ci		mutex_unlock(&spicontext->spi_lock);
4262306a36Sopenharmony_ci		return result;
4362306a36Sopenharmony_ci	}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	/* return for asynchronous or no-wait case */
4662306a36Sopenharmony_ci	if (reqtype == ASYNC) {
4762306a36Sopenharmony_ci		mutex_unlock(&spicontext->spi_lock);
4862306a36Sopenharmony_ci		return 0;
4962306a36Sopenharmony_ci	}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	result = wait_for_completion_timeout(&spicontext->done,
5262306a36Sopenharmony_ci					     msecs_to_jiffies(1000));
5362306a36Sopenharmony_ci	/* check for timeout or success */
5462306a36Sopenharmony_ci	if (!result) {
5562306a36Sopenharmony_ci		dev_err(&spidev->dev, "error: response not ready timeout\n");
5662306a36Sopenharmony_ci		result = -ETIMEDOUT;
5762306a36Sopenharmony_ci	} else {
5862306a36Sopenharmony_ci		result = 0;
5962306a36Sopenharmony_ci	}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	mutex_unlock(&spicontext->spi_lock);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	return result;
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(st95hf_spi_send);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci/* Function to Receive command Response */
6862306a36Sopenharmony_ciint st95hf_spi_recv_response(struct st95hf_spi_context *spicontext,
6962306a36Sopenharmony_ci			     unsigned char *receivebuff)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	int len = 0;
7262306a36Sopenharmony_ci	struct spi_transfer tx_takedata;
7362306a36Sopenharmony_ci	struct spi_message m;
7462306a36Sopenharmony_ci	struct spi_device *spidev = spicontext->spidev;
7562306a36Sopenharmony_ci	unsigned char readdata_cmd = ST95HF_COMMAND_RECEIVE;
7662306a36Sopenharmony_ci	struct spi_transfer t[2] = {
7762306a36Sopenharmony_ci		{.tx_buf = &readdata_cmd, .len = 1,},
7862306a36Sopenharmony_ci		{.rx_buf = receivebuff, .len = 2, .cs_change = 1,},
7962306a36Sopenharmony_ci	};
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	int ret = 0;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	memset(&tx_takedata, 0x0, sizeof(struct spi_transfer));
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	mutex_lock(&spicontext->spi_lock);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	/* First spi transfer to know the length of valid data */
8862306a36Sopenharmony_ci	spi_message_init(&m);
8962306a36Sopenharmony_ci	spi_message_add_tail(&t[0], &m);
9062306a36Sopenharmony_ci	spi_message_add_tail(&t[1], &m);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	ret = spi_sync(spidev, &m);
9362306a36Sopenharmony_ci	if (ret) {
9462306a36Sopenharmony_ci		dev_err(&spidev->dev, "spi_recv_resp, data length error = %d\n",
9562306a36Sopenharmony_ci			ret);
9662306a36Sopenharmony_ci		mutex_unlock(&spicontext->spi_lock);
9762306a36Sopenharmony_ci		return ret;
9862306a36Sopenharmony_ci	}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	/* As 2 bytes are already read */
10162306a36Sopenharmony_ci	len = 2;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	/* Support of long frame */
10462306a36Sopenharmony_ci	if (receivebuff[0] & 0x60)
10562306a36Sopenharmony_ci		len += (((receivebuff[0] & 0x60) >> 5) << 8) | receivebuff[1];
10662306a36Sopenharmony_ci	else
10762306a36Sopenharmony_ci		len += receivebuff[1];
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	/* Now make a transfer to read only relevant bytes */
11062306a36Sopenharmony_ci	tx_takedata.rx_buf = &receivebuff[2];
11162306a36Sopenharmony_ci	tx_takedata.len = len - 2;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	spi_message_init(&m);
11462306a36Sopenharmony_ci	spi_message_add_tail(&tx_takedata, &m);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	ret = spi_sync(spidev, &m);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	mutex_unlock(&spicontext->spi_lock);
11962306a36Sopenharmony_ci	if (ret) {
12062306a36Sopenharmony_ci		dev_err(&spidev->dev, "spi_recv_resp, data read error = %d\n",
12162306a36Sopenharmony_ci			ret);
12262306a36Sopenharmony_ci		return ret;
12362306a36Sopenharmony_ci	}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	return len;
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(st95hf_spi_recv_response);
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ciint st95hf_spi_recv_echo_res(struct st95hf_spi_context *spicontext,
13062306a36Sopenharmony_ci			     unsigned char *receivebuff)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	unsigned char readdata_cmd = ST95HF_COMMAND_RECEIVE;
13362306a36Sopenharmony_ci	struct spi_transfer t[2] = {
13462306a36Sopenharmony_ci		{.tx_buf = &readdata_cmd, .len = 1,},
13562306a36Sopenharmony_ci		{.rx_buf = receivebuff, .len = 1,},
13662306a36Sopenharmony_ci	};
13762306a36Sopenharmony_ci	struct spi_message m;
13862306a36Sopenharmony_ci	struct spi_device *spidev = spicontext->spidev;
13962306a36Sopenharmony_ci	int ret = 0;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	mutex_lock(&spicontext->spi_lock);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	spi_message_init(&m);
14462306a36Sopenharmony_ci	spi_message_add_tail(&t[0], &m);
14562306a36Sopenharmony_ci	spi_message_add_tail(&t[1], &m);
14662306a36Sopenharmony_ci	ret = spi_sync(spidev, &m);
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	mutex_unlock(&spicontext->spi_lock);
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	if (ret)
15162306a36Sopenharmony_ci		dev_err(&spidev->dev, "recv_echo_res, data read error = %d\n",
15262306a36Sopenharmony_ci			ret);
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	return ret;
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(st95hf_spi_recv_echo_res);
157