| /* |
| * ---------------------------------------------------------------------------- |
| * drivers/nfc/st95hf/spi.c function definitions for SPI communication |
| * ---------------------------------------------------------------------------- |
| * Copyright (C) 2015 STMicroelectronics Pvt. Ltd. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms and conditions of the GNU General Public License, |
| * version 2, as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| */ |
| |
| #include "spi.h" |
| |
| /* Function to send user provided buffer to ST95HF through SPI */ |
| int st95hf_spi_send(struct st95hf_spi_context *spicontext, |
| unsigned char *buffertx, |
| int datalen, |
| enum req_type reqtype) |
| { |
| struct spi_message m; |
| int result = 0; |
| struct spi_device *spidev = spicontext->spidev; |
| struct spi_transfer tx_transfer = { |
| .tx_buf = buffertx, |
| .len = datalen, |
| }; |
| |
| mutex_lock(&spicontext->spi_lock); |
| |
| if (reqtype == SYNC) { |
| spicontext->req_issync = true; |
| reinit_completion(&spicontext->done); |
| } else { |
| spicontext->req_issync = false; |
| } |
| |
| spi_message_init(&m); |
| spi_message_add_tail(&tx_transfer, &m); |
| |
| result = spi_sync(spidev, &m); |
| if (result) { |
| dev_err(&spidev->dev, "error: sending cmd to st95hf using SPI = %d\n", |
| result); |
| mutex_unlock(&spicontext->spi_lock); |
| return result; |
| } |
| |
| /* return for asynchronous or no-wait case */ |
| if (reqtype == ASYNC) { |
| mutex_unlock(&spicontext->spi_lock); |
| return 0; |
| } |
| |
| result = wait_for_completion_timeout(&spicontext->done, |
| msecs_to_jiffies(1000)); |
| /* check for timeout or success */ |
| if (!result) { |
| dev_err(&spidev->dev, "error: response not ready timeout\n"); |
| result = -ETIMEDOUT; |
| } else { |
| result = 0; |
| } |
| |
| mutex_unlock(&spicontext->spi_lock); |
| |
| return result; |
| } |
| EXPORT_SYMBOL_GPL(st95hf_spi_send); |
| |
| /* Function to Receive command Response */ |
| int st95hf_spi_recv_response(struct st95hf_spi_context *spicontext, |
| unsigned char *receivebuff) |
| { |
| int len = 0; |
| struct spi_transfer tx_takedata; |
| struct spi_message m; |
| struct spi_device *spidev = spicontext->spidev; |
| unsigned char readdata_cmd = ST95HF_COMMAND_RECEIVE; |
| struct spi_transfer t[2] = { |
| {.tx_buf = &readdata_cmd, .len = 1,}, |
| {.rx_buf = receivebuff, .len = 2, .cs_change = 1,}, |
| }; |
| |
| int ret = 0; |
| |
| memset(&tx_takedata, 0x0, sizeof(struct spi_transfer)); |
| |
| mutex_lock(&spicontext->spi_lock); |
| |
| /* First spi transfer to know the length of valid data */ |
| spi_message_init(&m); |
| spi_message_add_tail(&t[0], &m); |
| spi_message_add_tail(&t[1], &m); |
| |
| ret = spi_sync(spidev, &m); |
| if (ret) { |
| dev_err(&spidev->dev, "spi_recv_resp, data length error = %d\n", |
| ret); |
| mutex_unlock(&spicontext->spi_lock); |
| return ret; |
| } |
| |
| /* As 2 bytes are already read */ |
| len = 2; |
| |
| /* Support of long frame */ |
| if (receivebuff[0] & 0x60) |
| len += (((receivebuff[0] & 0x60) >> 5) << 8) | receivebuff[1]; |
| else |
| len += receivebuff[1]; |
| |
| /* Now make a transfer to read only relevant bytes */ |
| tx_takedata.rx_buf = &receivebuff[2]; |
| tx_takedata.len = len - 2; |
| |
| spi_message_init(&m); |
| spi_message_add_tail(&tx_takedata, &m); |
| |
| ret = spi_sync(spidev, &m); |
| |
| mutex_unlock(&spicontext->spi_lock); |
| if (ret) { |
| dev_err(&spidev->dev, "spi_recv_resp, data read error = %d\n", |
| ret); |
| return ret; |
| } |
| |
| return len; |
| } |
| EXPORT_SYMBOL_GPL(st95hf_spi_recv_response); |
| |
| int st95hf_spi_recv_echo_res(struct st95hf_spi_context *spicontext, |
| unsigned char *receivebuff) |
| { |
| unsigned char readdata_cmd = ST95HF_COMMAND_RECEIVE; |
| struct spi_transfer t[2] = { |
| {.tx_buf = &readdata_cmd, .len = 1,}, |
| {.rx_buf = receivebuff, .len = 1,}, |
| }; |
| struct spi_message m; |
| struct spi_device *spidev = spicontext->spidev; |
| int ret = 0; |
| |
| mutex_lock(&spicontext->spi_lock); |
| |
| spi_message_init(&m); |
| spi_message_add_tail(&t[0], &m); |
| spi_message_add_tail(&t[1], &m); |
| ret = spi_sync(spidev, &m); |
| |
| mutex_unlock(&spicontext->spi_lock); |
| |
| if (ret) |
| dev_err(&spidev->dev, "recv_echo_res, data read error = %d\n", |
| ret); |
| |
| return ret; |
| } |
| EXPORT_SYMBOL_GPL(st95hf_spi_recv_echo_res); |