Thomas Gleixner | 46fe777 | 2019-05-31 01:09:57 -0700 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0-only |
Shikha Singh | cab4733 | 2015-12-22 00:03:30 +0100 | [diff] [blame] | 2 | /* |
| 3 | * ---------------------------------------------------------------------------- |
| 4 | * drivers/nfc/st95hf/spi.c function definitions for SPI communication |
| 5 | * ---------------------------------------------------------------------------- |
| 6 | * Copyright (C) 2015 STMicroelectronics Pvt. Ltd. All rights reserved. |
Shikha Singh | cab4733 | 2015-12-22 00:03:30 +0100 | [diff] [blame] | 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(&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 | } |
| 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); |
| 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 | } |
| 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); |
| 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 | } |
| 156 | EXPORT_SYMBOL_GPL(st95hf_spi_recv_echo_res); |