18a00a61bSFrederic Danis /* 28a00a61bSFrederic Danis * Copyright (C) 2013 Intel Corporation. All rights reserved. 38a00a61bSFrederic Danis * 48a00a61bSFrederic Danis * This program is free software; you can redistribute it and/or modify it 58a00a61bSFrederic Danis * under the terms and conditions of the GNU General Public License, 68a00a61bSFrederic Danis * version 2, as published by the Free Software Foundation. 78a00a61bSFrederic Danis * 88a00a61bSFrederic Danis * This program is distributed in the hope it will be useful, but WITHOUT 98a00a61bSFrederic Danis * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 108a00a61bSFrederic Danis * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 118a00a61bSFrederic Danis * more details. 128a00a61bSFrederic Danis * 138a00a61bSFrederic Danis * You should have received a copy of the GNU General Public License along with 148a00a61bSFrederic Danis * this program; if not, write to the Free Software Foundation, Inc., 158a00a61bSFrederic Danis * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 168a00a61bSFrederic Danis * 178a00a61bSFrederic Danis */ 188a00a61bSFrederic Danis 198a00a61bSFrederic Danis #define pr_fmt(fmt) "nci_spi: %s: " fmt, __func__ 208a00a61bSFrederic Danis 21fcd9d046SVincent Cuissard #include <linux/module.h> 22fcd9d046SVincent Cuissard 238a00a61bSFrederic Danis #include <linux/export.h> 248a00a61bSFrederic Danis #include <linux/spi/spi.h> 25ee9596d4SFrederic Danis #include <linux/crc-ccitt.h> 268a00a61bSFrederic Danis #include <net/nfc/nci_core.h> 278a00a61bSFrederic Danis 28391d8a2dSFrederic Danis #define NCI_SPI_ACK_SHIFT 6 29391d8a2dSFrederic Danis #define NCI_SPI_MSB_PAYLOAD_MASK 0x3F 308a00a61bSFrederic Danis 31ee9596d4SFrederic Danis #define NCI_SPI_SEND_TIMEOUT (NCI_CMD_TIMEOUT > NCI_DATA_TIMEOUT ? \ 32ee9596d4SFrederic Danis NCI_CMD_TIMEOUT : NCI_DATA_TIMEOUT) 33ee9596d4SFrederic Danis 34ee9596d4SFrederic Danis #define NCI_SPI_DIRECT_WRITE 0x01 35ee9596d4SFrederic Danis #define NCI_SPI_DIRECT_READ 0x02 36ee9596d4SFrederic Danis 37ee9596d4SFrederic Danis #define ACKNOWLEDGE_NONE 0 38ee9596d4SFrederic Danis #define ACKNOWLEDGE_ACK 1 39ee9596d4SFrederic Danis #define ACKNOWLEDGE_NACK 2 40ee9596d4SFrederic Danis 41ee9596d4SFrederic Danis #define CRC_INIT 0xFFFF 42ee9596d4SFrederic Danis 432bed2785SEric Lapuyade static int __nci_spi_send(struct nci_spi *nspi, struct sk_buff *skb, 442bed2785SEric Lapuyade int cs_change) 45ee9596d4SFrederic Danis { 46ee9596d4SFrederic Danis struct spi_message m; 47ee9596d4SFrederic Danis struct spi_transfer t; 48ee9596d4SFrederic Danis 49a4ada6caSEric Lapuyade memset(&t, 0, sizeof(struct spi_transfer)); 502bed2785SEric Lapuyade /* a NULL skb means we just want the SPI chip select line to raise */ 512bed2785SEric Lapuyade if (skb) { 52ee9596d4SFrederic Danis t.tx_buf = skb->data; 53ee9596d4SFrederic Danis t.len = skb->len; 542bed2785SEric Lapuyade } else { 552bed2785SEric Lapuyade /* still set tx_buf non NULL to make the driver happy */ 562bed2785SEric Lapuyade t.tx_buf = &t; 572bed2785SEric Lapuyade t.len = 0; 582bed2785SEric Lapuyade } 592bed2785SEric Lapuyade t.cs_change = cs_change; 60fa544fffSEric Lapuyade t.delay_usecs = nspi->xfer_udelay; 612bd83245SVincent Cuissard t.speed_hz = nspi->xfer_speed_hz; 62ee9596d4SFrederic Danis 63ee9596d4SFrederic Danis spi_message_init(&m); 64ee9596d4SFrederic Danis spi_message_add_tail(&t, &m); 65ee9596d4SFrederic Danis 66fa544fffSEric Lapuyade return spi_sync(nspi->spi, &m); 67ee9596d4SFrederic Danis } 68ee9596d4SFrederic Danis 692bed2785SEric Lapuyade int nci_spi_send(struct nci_spi *nspi, 702bed2785SEric Lapuyade struct completion *write_handshake_completion, 712bed2785SEric Lapuyade struct sk_buff *skb) 728a00a61bSFrederic Danis { 73ee9596d4SFrederic Danis unsigned int payload_len = skb->len; 74ee9596d4SFrederic Danis unsigned char *hdr; 75ee9596d4SFrederic Danis int ret; 76ee9596d4SFrederic Danis long completion_rc; 77ee9596d4SFrederic Danis 78ee9596d4SFrederic Danis /* add the NCI SPI header to the start of the buffer */ 79ee9596d4SFrederic Danis hdr = skb_push(skb, NCI_SPI_HDR_LEN); 80ee9596d4SFrederic Danis hdr[0] = NCI_SPI_DIRECT_WRITE; 81fa544fffSEric Lapuyade hdr[1] = nspi->acknowledge_mode; 82ee9596d4SFrederic Danis hdr[2] = payload_len >> 8; 83ee9596d4SFrederic Danis hdr[3] = payload_len & 0xFF; 84ee9596d4SFrederic Danis 85fa544fffSEric Lapuyade if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) { 86ee9596d4SFrederic Danis u16 crc; 87ee9596d4SFrederic Danis 88ee9596d4SFrederic Danis crc = crc_ccitt(CRC_INIT, skb->data, skb->len); 894df864c1SJohannes Berg *(u8 *)skb_put(skb, 1) = crc >> 8; 904df864c1SJohannes Berg *(u8 *)skb_put(skb, 1) = crc & 0xFF; 91ee9596d4SFrederic Danis } 92ee9596d4SFrederic Danis 932bed2785SEric Lapuyade if (write_handshake_completion) { 942bed2785SEric Lapuyade /* Trick SPI driver to raise chip select */ 952bed2785SEric Lapuyade ret = __nci_spi_send(nspi, NULL, 1); 962bed2785SEric Lapuyade if (ret) 972bed2785SEric Lapuyade goto done; 98ee9596d4SFrederic Danis 992bed2785SEric Lapuyade /* wait for NFC chip hardware handshake to complete */ 1002bed2785SEric Lapuyade if (wait_for_completion_timeout(write_handshake_completion, 1012bed2785SEric Lapuyade msecs_to_jiffies(1000)) == 0) { 1022bed2785SEric Lapuyade ret = -ETIME; 1032bed2785SEric Lapuyade goto done; 1042bed2785SEric Lapuyade } 1052bed2785SEric Lapuyade } 106ee9596d4SFrederic Danis 1072bed2785SEric Lapuyade ret = __nci_spi_send(nspi, skb, 0); 108fa544fffSEric Lapuyade if (ret != 0 || nspi->acknowledge_mode == NCI_SPI_CRC_DISABLED) 109ee9596d4SFrederic Danis goto done; 110ee9596d4SFrederic Danis 1119bec44bfSAxel Lin reinit_completion(&nspi->req_completion); 112d5937511SEric Lapuyade completion_rc = wait_for_completion_interruptible_timeout( 113fa544fffSEric Lapuyade &nspi->req_completion, 114ee9596d4SFrederic Danis NCI_SPI_SEND_TIMEOUT); 115ee9596d4SFrederic Danis 116fa544fffSEric Lapuyade if (completion_rc <= 0 || nspi->req_result == ACKNOWLEDGE_NACK) 117ee9596d4SFrederic Danis ret = -EIO; 118ee9596d4SFrederic Danis 119ee9596d4SFrederic Danis done: 1202bed2785SEric Lapuyade kfree_skb(skb); 1212bed2785SEric Lapuyade 122ee9596d4SFrederic Danis return ret; 1238a00a61bSFrederic Danis } 124fa544fffSEric Lapuyade EXPORT_SYMBOL_GPL(nci_spi_send); 1258a00a61bSFrederic Danis 1268a00a61bSFrederic Danis /* ---- Interface to NCI SPI drivers ---- */ 1278a00a61bSFrederic Danis 1288a00a61bSFrederic Danis /** 129fa544fffSEric Lapuyade * nci_spi_allocate_spi - allocate a new nci spi 1308a00a61bSFrederic Danis * 1318a00a61bSFrederic Danis * @spi: SPI device 132fa544fffSEric Lapuyade * @acknowledge_mode: Acknowledge mode used by the NFC device 1338a00a61bSFrederic Danis * @delay: delay between transactions in us 134fa544fffSEric Lapuyade * @ndev: nci dev to send incoming nci frames to 1358a00a61bSFrederic Danis */ 136fa544fffSEric Lapuyade struct nci_spi *nci_spi_allocate_spi(struct spi_device *spi, 137fa544fffSEric Lapuyade u8 acknowledge_mode, unsigned int delay, 138fa544fffSEric Lapuyade struct nci_dev *ndev) 1398a00a61bSFrederic Danis { 140fa544fffSEric Lapuyade struct nci_spi *nspi; 1418a00a61bSFrederic Danis 142fa544fffSEric Lapuyade nspi = devm_kzalloc(&spi->dev, sizeof(struct nci_spi), GFP_KERNEL); 143fa544fffSEric Lapuyade if (!nspi) 1448a00a61bSFrederic Danis return NULL; 1458a00a61bSFrederic Danis 146fa544fffSEric Lapuyade nspi->acknowledge_mode = acknowledge_mode; 147fa544fffSEric Lapuyade nspi->xfer_udelay = delay; 1482bd83245SVincent Cuissard /* Use controller max SPI speed by default */ 1492bd83245SVincent Cuissard nspi->xfer_speed_hz = 0; 150645d5087SEric Lapuyade nspi->spi = spi; 151fa544fffSEric Lapuyade nspi->ndev = ndev; 1529bec44bfSAxel Lin init_completion(&nspi->req_completion); 1538a00a61bSFrederic Danis 154fa544fffSEric Lapuyade return nspi; 1558a00a61bSFrederic Danis } 156fa544fffSEric Lapuyade EXPORT_SYMBOL_GPL(nci_spi_allocate_spi); 1578a00a61bSFrederic Danis 158fa544fffSEric Lapuyade static int send_acknowledge(struct nci_spi *nspi, u8 acknowledge) 159391d8a2dSFrederic Danis { 160391d8a2dSFrederic Danis struct sk_buff *skb; 161391d8a2dSFrederic Danis unsigned char *hdr; 162391d8a2dSFrederic Danis u16 crc; 163391d8a2dSFrederic Danis int ret; 164391d8a2dSFrederic Danis 165fa544fffSEric Lapuyade skb = nci_skb_alloc(nspi->ndev, 0, GFP_KERNEL); 166391d8a2dSFrederic Danis 167391d8a2dSFrederic Danis /* add the NCI SPI header to the start of the buffer */ 168391d8a2dSFrederic Danis hdr = skb_push(skb, NCI_SPI_HDR_LEN); 169391d8a2dSFrederic Danis hdr[0] = NCI_SPI_DIRECT_WRITE; 170391d8a2dSFrederic Danis hdr[1] = NCI_SPI_CRC_ENABLED; 171391d8a2dSFrederic Danis hdr[2] = acknowledge << NCI_SPI_ACK_SHIFT; 172391d8a2dSFrederic Danis hdr[3] = 0; 173391d8a2dSFrederic Danis 174391d8a2dSFrederic Danis crc = crc_ccitt(CRC_INIT, skb->data, skb->len); 1754df864c1SJohannes Berg *(u8 *)skb_put(skb, 1) = crc >> 8; 1764df864c1SJohannes Berg *(u8 *)skb_put(skb, 1) = crc & 0xFF; 177391d8a2dSFrederic Danis 1782bed2785SEric Lapuyade ret = __nci_spi_send(nspi, skb, 0); 179391d8a2dSFrederic Danis 180391d8a2dSFrederic Danis kfree_skb(skb); 181391d8a2dSFrederic Danis 182391d8a2dSFrederic Danis return ret; 183391d8a2dSFrederic Danis } 184391d8a2dSFrederic Danis 18522d4aae5SEric Lapuyade static struct sk_buff *__nci_spi_read(struct nci_spi *nspi) 186391d8a2dSFrederic Danis { 187391d8a2dSFrederic Danis struct sk_buff *skb; 188391d8a2dSFrederic Danis struct spi_message m; 189391d8a2dSFrederic Danis unsigned char req[2], resp_hdr[2]; 190391d8a2dSFrederic Danis struct spi_transfer tx, rx; 191391d8a2dSFrederic Danis unsigned short rx_len = 0; 192391d8a2dSFrederic Danis int ret; 193391d8a2dSFrederic Danis 194391d8a2dSFrederic Danis spi_message_init(&m); 195a4ada6caSEric Lapuyade 196a4ada6caSEric Lapuyade memset(&tx, 0, sizeof(struct spi_transfer)); 197391d8a2dSFrederic Danis req[0] = NCI_SPI_DIRECT_READ; 198fa544fffSEric Lapuyade req[1] = nspi->acknowledge_mode; 199391d8a2dSFrederic Danis tx.tx_buf = req; 200391d8a2dSFrederic Danis tx.len = 2; 201391d8a2dSFrederic Danis tx.cs_change = 0; 2022bd83245SVincent Cuissard tx.speed_hz = nspi->xfer_speed_hz; 203391d8a2dSFrederic Danis spi_message_add_tail(&tx, &m); 204a4ada6caSEric Lapuyade 205a4ada6caSEric Lapuyade memset(&rx, 0, sizeof(struct spi_transfer)); 206391d8a2dSFrederic Danis rx.rx_buf = resp_hdr; 207391d8a2dSFrederic Danis rx.len = 2; 208391d8a2dSFrederic Danis rx.cs_change = 1; 2092bd83245SVincent Cuissard rx.speed_hz = nspi->xfer_speed_hz; 210391d8a2dSFrederic Danis spi_message_add_tail(&rx, &m); 211a4ada6caSEric Lapuyade 212fa544fffSEric Lapuyade ret = spi_sync(nspi->spi, &m); 213391d8a2dSFrederic Danis if (ret) 214391d8a2dSFrederic Danis return NULL; 215391d8a2dSFrederic Danis 216fa544fffSEric Lapuyade if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) 217391d8a2dSFrederic Danis rx_len = ((resp_hdr[0] & NCI_SPI_MSB_PAYLOAD_MASK) << 8) + 218391d8a2dSFrederic Danis resp_hdr[1] + NCI_SPI_CRC_LEN; 219391d8a2dSFrederic Danis else 220391d8a2dSFrederic Danis rx_len = (resp_hdr[0] << 8) | resp_hdr[1]; 221391d8a2dSFrederic Danis 222fa544fffSEric Lapuyade skb = nci_skb_alloc(nspi->ndev, rx_len, GFP_KERNEL); 223391d8a2dSFrederic Danis if (!skb) 224391d8a2dSFrederic Danis return NULL; 225391d8a2dSFrederic Danis 226391d8a2dSFrederic Danis spi_message_init(&m); 227a4ada6caSEric Lapuyade 228a4ada6caSEric Lapuyade memset(&rx, 0, sizeof(struct spi_transfer)); 229391d8a2dSFrederic Danis rx.rx_buf = skb_put(skb, rx_len); 230391d8a2dSFrederic Danis rx.len = rx_len; 231391d8a2dSFrederic Danis rx.cs_change = 0; 232fa544fffSEric Lapuyade rx.delay_usecs = nspi->xfer_udelay; 2332bd83245SVincent Cuissard rx.speed_hz = nspi->xfer_speed_hz; 234391d8a2dSFrederic Danis spi_message_add_tail(&rx, &m); 235a4ada6caSEric Lapuyade 236fa544fffSEric Lapuyade ret = spi_sync(nspi->spi, &m); 237391d8a2dSFrederic Danis if (ret) 238391d8a2dSFrederic Danis goto receive_error; 239391d8a2dSFrederic Danis 240fa544fffSEric Lapuyade if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) { 241*d58ff351SJohannes Berg *(u8 *)skb_push(skb, 1) = resp_hdr[1]; 242*d58ff351SJohannes Berg *(u8 *)skb_push(skb, 1) = resp_hdr[0]; 243391d8a2dSFrederic Danis } 244391d8a2dSFrederic Danis 245391d8a2dSFrederic Danis return skb; 246391d8a2dSFrederic Danis 247391d8a2dSFrederic Danis receive_error: 248391d8a2dSFrederic Danis kfree_skb(skb); 249391d8a2dSFrederic Danis 250391d8a2dSFrederic Danis return NULL; 251391d8a2dSFrederic Danis } 252391d8a2dSFrederic Danis 253391d8a2dSFrederic Danis static int nci_spi_check_crc(struct sk_buff *skb) 254391d8a2dSFrederic Danis { 255391d8a2dSFrederic Danis u16 crc_data = (skb->data[skb->len - 2] << 8) | 256391d8a2dSFrederic Danis skb->data[skb->len - 1]; 257391d8a2dSFrederic Danis int ret; 258391d8a2dSFrederic Danis 259391d8a2dSFrederic Danis ret = (crc_ccitt(CRC_INIT, skb->data, skb->len - NCI_SPI_CRC_LEN) 260391d8a2dSFrederic Danis == crc_data); 261391d8a2dSFrederic Danis 262391d8a2dSFrederic Danis skb_trim(skb, skb->len - NCI_SPI_CRC_LEN); 263391d8a2dSFrederic Danis 264391d8a2dSFrederic Danis return ret; 265391d8a2dSFrederic Danis } 266391d8a2dSFrederic Danis 267391d8a2dSFrederic Danis static u8 nci_spi_get_ack(struct sk_buff *skb) 268391d8a2dSFrederic Danis { 269391d8a2dSFrederic Danis u8 ret; 270391d8a2dSFrederic Danis 271391d8a2dSFrederic Danis ret = skb->data[0] >> NCI_SPI_ACK_SHIFT; 272391d8a2dSFrederic Danis 273391d8a2dSFrederic Danis /* Remove NFCC part of the header: ACK, NACK and MSB payload len */ 274391d8a2dSFrederic Danis skb_pull(skb, 2); 275391d8a2dSFrederic Danis 276391d8a2dSFrederic Danis return ret; 277391d8a2dSFrederic Danis } 278391d8a2dSFrederic Danis 279391d8a2dSFrederic Danis /** 28022d4aae5SEric Lapuyade * nci_spi_read - read frame from NCI SPI drivers 281391d8a2dSFrederic Danis * 282fa544fffSEric Lapuyade * @nspi: The nci spi 283391d8a2dSFrederic Danis * Context: can sleep 284391d8a2dSFrederic Danis * 285391d8a2dSFrederic Danis * This call may only be used from a context that may sleep. The sleep 286391d8a2dSFrederic Danis * is non-interruptible, and has no timeout. 287391d8a2dSFrederic Danis * 28822d4aae5SEric Lapuyade * It returns an allocated skb containing the frame on success, or NULL. 289391d8a2dSFrederic Danis */ 29022d4aae5SEric Lapuyade struct sk_buff *nci_spi_read(struct nci_spi *nspi) 291391d8a2dSFrederic Danis { 292391d8a2dSFrederic Danis struct sk_buff *skb; 293391d8a2dSFrederic Danis 294391d8a2dSFrederic Danis /* Retrieve frame from SPI */ 29522d4aae5SEric Lapuyade skb = __nci_spi_read(nspi); 29622d4aae5SEric Lapuyade if (!skb) 297391d8a2dSFrederic Danis goto done; 298391d8a2dSFrederic Danis 299fa544fffSEric Lapuyade if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) { 300391d8a2dSFrederic Danis if (!nci_spi_check_crc(skb)) { 301fa544fffSEric Lapuyade send_acknowledge(nspi, ACKNOWLEDGE_NACK); 302391d8a2dSFrederic Danis goto done; 303391d8a2dSFrederic Danis } 304391d8a2dSFrederic Danis 305391d8a2dSFrederic Danis /* In case of acknowledged mode: if ACK or NACK received, 306391d8a2dSFrederic Danis * unblock completion of latest frame sent. 307391d8a2dSFrederic Danis */ 308fa544fffSEric Lapuyade nspi->req_result = nci_spi_get_ack(skb); 309fa544fffSEric Lapuyade if (nspi->req_result) 310fa544fffSEric Lapuyade complete(&nspi->req_completion); 311391d8a2dSFrederic Danis } 312391d8a2dSFrederic Danis 313391d8a2dSFrederic Danis /* If there is no payload (ACK/NACK only frame), 314391d8a2dSFrederic Danis * free the socket buffer 315391d8a2dSFrederic Danis */ 31622d4aae5SEric Lapuyade if (!skb->len) { 317391d8a2dSFrederic Danis kfree_skb(skb); 31822d4aae5SEric Lapuyade skb = NULL; 319391d8a2dSFrederic Danis goto done; 320391d8a2dSFrederic Danis } 321391d8a2dSFrederic Danis 322fa544fffSEric Lapuyade if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) 323fa544fffSEric Lapuyade send_acknowledge(nspi, ACKNOWLEDGE_ACK); 324391d8a2dSFrederic Danis 325391d8a2dSFrederic Danis done: 326391d8a2dSFrederic Danis 32722d4aae5SEric Lapuyade return skb; 328391d8a2dSFrederic Danis } 32922d4aae5SEric Lapuyade EXPORT_SYMBOL_GPL(nci_spi_read); 330fcd9d046SVincent Cuissard 331fcd9d046SVincent Cuissard MODULE_LICENSE("GPL"); 332