Shikha Singh | cab4733 | 2015-12-22 00:03:30 +0100 | [diff] [blame] | 1 | /* |
| 2 | * ---------------------------------------------------------------------------- |
| 3 | * drivers/nfc/st95hf/spi.c function definitions for SPI communication |
| 4 | * ---------------------------------------------------------------------------- |
| 5 | * Copyright (C) 2015 STMicroelectronics Pvt. Ltd. All rights reserved. |
| 6 | * |
| 7 | * This program is free software; you can redistribute it and/or modify it |
| 8 | * under the terms and conditions of the GNU General Public License, |
| 9 | * version 2, as published by the Free Software Foundation. |
| 10 | * |
| 11 | * This program is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | * GNU General Public License for more details. |
| 15 | * |
| 16 | * You should have received a copy of the GNU General Public License |
| 17 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 18 | */ |
| 19 | |
| 20 | #include "spi.h" |
| 21 | |
| 22 | /* Function to send user provided buffer to ST95HF through SPI */ |
| 23 | int st95hf_spi_send(struct st95hf_spi_context *spicontext, |
| 24 | unsigned char *buffertx, |
| 25 | int datalen, |
| 26 | enum req_type reqtype) |
| 27 | { |
| 28 | struct spi_message m; |
| 29 | int result = 0; |
| 30 | struct spi_device *spidev = spicontext->spidev; |
| 31 | struct spi_transfer tx_transfer = { |
| 32 | .tx_buf = buffertx, |
| 33 | .len = datalen, |
| 34 | }; |
| 35 | |
| 36 | mutex_lock(&spicontext->spi_lock); |
| 37 | |
| 38 | if (reqtype == SYNC) { |
| 39 | spicontext->req_issync = true; |
| 40 | reinit_completion(&spicontext->done); |
| 41 | } else { |
| 42 | spicontext->req_issync = false; |
| 43 | } |
| 44 | |
| 45 | spi_message_init(&m); |
| 46 | spi_message_add_tail(&tx_transfer, &m); |
| 47 | |
| 48 | result = spi_sync(spidev, &m); |
| 49 | if (result) { |
| 50 | dev_err(&spidev->dev, "error: sending cmd to st95hf using SPI = %d\n", |
| 51 | result); |
| 52 | mutex_unlock(&spicontext->spi_lock); |
| 53 | return result; |
| 54 | } |
| 55 | |
| 56 | /* return for asynchronous or no-wait case */ |
| 57 | if (reqtype == ASYNC) { |
| 58 | mutex_unlock(&spicontext->spi_lock); |
| 59 | return 0; |
| 60 | } |
| 61 | |
| 62 | result = wait_for_completion_timeout(&spicontext->done, |
| 63 | msecs_to_jiffies(1000)); |
| 64 | /* check for timeout or success */ |
| 65 | if (!result) { |
| 66 | dev_err(&spidev->dev, "error: response not ready timeout\n"); |
| 67 | result = -ETIMEDOUT; |
| 68 | } else { |
| 69 | result = 0; |
| 70 | } |
| 71 | |
| 72 | mutex_unlock(&spicontext->spi_lock); |
| 73 | |
| 74 | return result; |
| 75 | } |
| 76 | EXPORT_SYMBOL_GPL(st95hf_spi_send); |
| 77 | |
| 78 | /* Function to Receive command Response */ |
| 79 | int st95hf_spi_recv_response(struct st95hf_spi_context *spicontext, |
| 80 | unsigned char *receivebuff) |
| 81 | { |
| 82 | int len = 0; |
| 83 | struct spi_transfer tx_takedata; |
| 84 | struct spi_message m; |
| 85 | struct spi_device *spidev = spicontext->spidev; |
| 86 | unsigned char readdata_cmd = ST95HF_COMMAND_RECEIVE; |
| 87 | struct spi_transfer t[2] = { |
| 88 | {.tx_buf = &readdata_cmd, .len = 1,}, |
| 89 | {.rx_buf = receivebuff, .len = 2, .cs_change = 1,}, |
| 90 | }; |
| 91 | |
| 92 | int ret = 0; |
| 93 | |
| 94 | memset(&tx_takedata, 0x0, sizeof(struct spi_transfer)); |
| 95 | |
| 96 | mutex_lock(&spicontext->spi_lock); |
| 97 | |
| 98 | /* First spi transfer to know the length of valid data */ |
| 99 | spi_message_init(&m); |
| 100 | spi_message_add_tail(&t[0], &m); |
| 101 | spi_message_add_tail(&t[1], &m); |
| 102 | |
| 103 | ret = spi_sync(spidev, &m); |
| 104 | if (ret) { |
| 105 | dev_err(&spidev->dev, "spi_recv_resp, data length error = %d\n", |
| 106 | ret); |
| 107 | mutex_unlock(&spicontext->spi_lock); |
| 108 | return ret; |
| 109 | } |
| 110 | |
| 111 | /* As 2 bytes are already read */ |
| 112 | len = 2; |
| 113 | |
| 114 | /* Support of long frame */ |
| 115 | if (receivebuff[0] & 0x60) |
| 116 | len += (((receivebuff[0] & 0x60) >> 5) << 8) | receivebuff[1]; |
| 117 | else |
| 118 | len += receivebuff[1]; |
| 119 | |
| 120 | /* Now make a transfer to read only relevant bytes */ |
| 121 | tx_takedata.rx_buf = &receivebuff[2]; |
| 122 | tx_takedata.len = len - 2; |
| 123 | |
| 124 | spi_message_init(&m); |
| 125 | spi_message_add_tail(&tx_takedata, &m); |
| 126 | |
| 127 | ret = spi_sync(spidev, &m); |
| 128 | |
| 129 | mutex_unlock(&spicontext->spi_lock); |
| 130 | if (ret) { |
| 131 | dev_err(&spidev->dev, "spi_recv_resp, data read error = %d\n", |
| 132 | ret); |
| 133 | return ret; |
| 134 | } |
| 135 | |
| 136 | return len; |
| 137 | } |
| 138 | EXPORT_SYMBOL_GPL(st95hf_spi_recv_response); |
| 139 | |
| 140 | int st95hf_spi_recv_echo_res(struct st95hf_spi_context *spicontext, |
| 141 | unsigned char *receivebuff) |
| 142 | { |
| 143 | unsigned char readdata_cmd = ST95HF_COMMAND_RECEIVE; |
| 144 | struct spi_transfer t[2] = { |
| 145 | {.tx_buf = &readdata_cmd, .len = 1,}, |
| 146 | {.rx_buf = receivebuff, .len = 1,}, |
| 147 | }; |
| 148 | struct spi_message m; |
| 149 | struct spi_device *spidev = spicontext->spidev; |
| 150 | int ret = 0; |
| 151 | |
| 152 | mutex_lock(&spicontext->spi_lock); |
| 153 | |
| 154 | spi_message_init(&m); |
| 155 | spi_message_add_tail(&t[0], &m); |
| 156 | spi_message_add_tail(&t[1], &m); |
| 157 | ret = spi_sync(spidev, &m); |
| 158 | |
| 159 | mutex_unlock(&spicontext->spi_lock); |
| 160 | |
| 161 | if (ret) |
| 162 | dev_err(&spidev->dev, "recv_echo_res, data read error = %d\n", |
| 163 | ret); |
| 164 | |
| 165 | return ret; |
| 166 | } |
| 167 | EXPORT_SYMBOL_GPL(st95hf_spi_recv_echo_res); |