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 */ |
12 | int 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(x: &spicontext->done); |
30 | } else { |
31 | spicontext->req_issync = false; |
32 | } |
33 | |
34 | spi_message_init(m: &m); |
35 | spi_message_add_tail(t: &tx_transfer, m: &m); |
36 | |
37 | result = spi_sync(spi: spidev, message: &m); |
38 | if (result) { |
39 | dev_err(&spidev->dev, "error: sending cmd to st95hf using SPI = %d\n" , |
40 | result); |
41 | mutex_unlock(lock: &spicontext->spi_lock); |
42 | return result; |
43 | } |
44 | |
45 | /* return for asynchronous or no-wait case */ |
46 | if (reqtype == ASYNC) { |
47 | mutex_unlock(lock: &spicontext->spi_lock); |
48 | return 0; |
49 | } |
50 | |
51 | result = wait_for_completion_timeout(x: &spicontext->done, |
52 | timeout: msecs_to_jiffies(m: 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(lock: &spicontext->spi_lock); |
62 | |
63 | return result; |
64 | } |
65 | EXPORT_SYMBOL_GPL(st95hf_spi_send); |
66 | |
67 | /* Function to Receive command Response */ |
68 | int 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: &m); |
89 | spi_message_add_tail(t: &t[0], m: &m); |
90 | spi_message_add_tail(t: &t[1], m: &m); |
91 | |
92 | ret = spi_sync(spi: spidev, message: &m); |
93 | if (ret) { |
94 | dev_err(&spidev->dev, "spi_recv_resp, data length error = %d\n" , |
95 | ret); |
96 | mutex_unlock(lock: &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: &m); |
114 | spi_message_add_tail(t: &tx_takedata, m: &m); |
115 | |
116 | ret = spi_sync(spi: spidev, message: &m); |
117 | |
118 | mutex_unlock(lock: &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 | } |
127 | EXPORT_SYMBOL_GPL(st95hf_spi_recv_response); |
128 | |
129 | int 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: &m); |
144 | spi_message_add_tail(t: &t[0], m: &m); |
145 | spi_message_add_tail(t: &t[1], m: &m); |
146 | ret = spi_sync(spi: spidev, message: &m); |
147 | |
148 | mutex_unlock(lock: &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 | } |
156 | EXPORT_SYMBOL_GPL(st95hf_spi_recv_echo_res); |
157 | |