/* * ---------------------------------------------------------------------------- * 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 . */ #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);