1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * ----------------------------------------------------------------------------
4 * drivers/nfc/st95hf/spi.c function definitions for SPI communication
5 * ----------------------------------------------------------------------------
6 * Copyright (C) 2015 STMicroelectronics Pvt. Ltd. All rights reserved.
7 */
8
9#include "spi.h"
10
11/* Function to send user provided buffer to ST95HF through SPI */
12int st95hf_spi_send(struct st95hf_spi_context *spicontext,
13		    unsigned char *buffertx,
14		    int datalen,
15		    enum req_type reqtype)
16{
17	struct spi_message m;
18	int result = 0;
19	struct spi_device *spidev = spicontext->spidev;
20	struct spi_transfer tx_transfer = {
21		.tx_buf = buffertx,
22		.len = datalen,
23	};
24
25	mutex_lock(&spicontext->spi_lock);
26
27	if (reqtype == SYNC) {
28		spicontext->req_issync = true;
29		reinit_completion(&spicontext->done);
30	} else {
31		spicontext->req_issync = false;
32	}
33
34	spi_message_init(&m);
35	spi_message_add_tail(&tx_transfer, &m);
36
37	result = spi_sync(spidev, &m);
38	if (result) {
39		dev_err(&spidev->dev, "error: sending cmd to st95hf using SPI = %d\n",
40			result);
41		mutex_unlock(&spicontext->spi_lock);
42		return result;
43	}
44
45	/* return for asynchronous or no-wait case */
46	if (reqtype == ASYNC) {
47		mutex_unlock(&spicontext->spi_lock);
48		return 0;
49	}
50
51	result = wait_for_completion_timeout(&spicontext->done,
52					     msecs_to_jiffies(1000));
53	/* check for timeout or success */
54	if (!result) {
55		dev_err(&spidev->dev, "error: response not ready timeout\n");
56		result = -ETIMEDOUT;
57	} else {
58		result = 0;
59	}
60
61	mutex_unlock(&spicontext->spi_lock);
62
63	return result;
64}
65EXPORT_SYMBOL_GPL(st95hf_spi_send);
66
67/* Function to Receive command Response */
68int st95hf_spi_recv_response(struct st95hf_spi_context *spicontext,
69			     unsigned char *receivebuff)
70{
71	int len = 0;
72	struct spi_transfer tx_takedata;
73	struct spi_message m;
74	struct spi_device *spidev = spicontext->spidev;
75	unsigned char readdata_cmd = ST95HF_COMMAND_RECEIVE;
76	struct spi_transfer t[2] = {
77		{.tx_buf = &readdata_cmd, .len = 1,},
78		{.rx_buf = receivebuff, .len = 2, .cs_change = 1,},
79	};
80
81	int ret = 0;
82
83	memset(&tx_takedata, 0x0, sizeof(struct spi_transfer));
84
85	mutex_lock(&spicontext->spi_lock);
86
87	/* First spi transfer to know the length of valid data */
88	spi_message_init(&m);
89	spi_message_add_tail(&t[0], &m);
90	spi_message_add_tail(&t[1], &m);
91
92	ret = spi_sync(spidev, &m);
93	if (ret) {
94		dev_err(&spidev->dev, "spi_recv_resp, data length error = %d\n",
95			ret);
96		mutex_unlock(&spicontext->spi_lock);
97		return ret;
98	}
99
100	/* As 2 bytes are already read */
101	len = 2;
102
103	/* Support of long frame */
104	if (receivebuff[0] & 0x60)
105		len += (((receivebuff[0] & 0x60) >> 5) << 8) | receivebuff[1];
106	else
107		len += receivebuff[1];
108
109	/* Now make a transfer to read only relevant bytes */
110	tx_takedata.rx_buf = &receivebuff[2];
111	tx_takedata.len = len - 2;
112
113	spi_message_init(&m);
114	spi_message_add_tail(&tx_takedata, &m);
115
116	ret = spi_sync(spidev, &m);
117
118	mutex_unlock(&spicontext->spi_lock);
119	if (ret) {
120		dev_err(&spidev->dev, "spi_recv_resp, data read error = %d\n",
121			ret);
122		return ret;
123	}
124
125	return len;
126}
127EXPORT_SYMBOL_GPL(st95hf_spi_recv_response);
128
129int st95hf_spi_recv_echo_res(struct st95hf_spi_context *spicontext,
130			     unsigned char *receivebuff)
131{
132	unsigned char readdata_cmd = ST95HF_COMMAND_RECEIVE;
133	struct spi_transfer t[2] = {
134		{.tx_buf = &readdata_cmd, .len = 1,},
135		{.rx_buf = receivebuff, .len = 1,},
136	};
137	struct spi_message m;
138	struct spi_device *spidev = spicontext->spidev;
139	int ret = 0;
140
141	mutex_lock(&spicontext->spi_lock);
142
143	spi_message_init(&m);
144	spi_message_add_tail(&t[0], &m);
145	spi_message_add_tail(&t[1], &m);
146	ret = spi_sync(spidev, &m);
147
148	mutex_unlock(&spicontext->spi_lock);
149
150	if (ret)
151		dev_err(&spidev->dev, "recv_echo_res, data read error = %d\n",
152			ret);
153
154	return ret;
155}
156EXPORT_SYMBOL_GPL(st95hf_spi_recv_echo_res);
157