linux/net/nfc/nci/spi.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2013  Intel Corporation. All rights reserved.
   3 *
   4 * This program is free software; you can redistribute it and/or modify it
   5 * under the terms and conditions of the GNU General Public License,
   6 * version 2, as published by the Free Software Foundation.
   7 *
   8 * This program is distributed in the hope it will be useful, but WITHOUT
   9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  11 * more details.
  12 *
  13 * You should have received a copy of the GNU General Public License along with
  14 * this program; if not, write to the Free Software Foundation, Inc.,
  15 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  16 *
  17 */
  18
  19#define pr_fmt(fmt) "nci_spi: %s: " fmt, __func__
  20
  21#include <linux/module.h>
  22
  23#include <linux/export.h>
  24#include <linux/spi/spi.h>
  25#include <linux/crc-ccitt.h>
  26#include <net/nfc/nci_core.h>
  27
  28#define NCI_SPI_ACK_SHIFT               6
  29#define NCI_SPI_MSB_PAYLOAD_MASK        0x3F
  30
  31#define NCI_SPI_SEND_TIMEOUT    (NCI_CMD_TIMEOUT > NCI_DATA_TIMEOUT ? \
  32                                        NCI_CMD_TIMEOUT : NCI_DATA_TIMEOUT)
  33
  34#define NCI_SPI_DIRECT_WRITE    0x01
  35#define NCI_SPI_DIRECT_READ     0x02
  36
  37#define ACKNOWLEDGE_NONE        0
  38#define ACKNOWLEDGE_ACK         1
  39#define ACKNOWLEDGE_NACK        2
  40
  41#define CRC_INIT                0xFFFF
  42
  43static int __nci_spi_send(struct nci_spi *nspi, struct sk_buff *skb,
  44                          int cs_change)
  45{
  46        struct spi_message m;
  47        struct spi_transfer t;
  48
  49        memset(&t, 0, sizeof(struct spi_transfer));
  50        /* a NULL skb means we just want the SPI chip select line to raise */
  51        if (skb) {
  52                t.tx_buf = skb->data;
  53                t.len = skb->len;
  54        } else {
  55                /* still set tx_buf non NULL to make the driver happy */
  56                t.tx_buf = &t;
  57                t.len = 0;
  58        }
  59        t.cs_change = cs_change;
  60        t.delay_usecs = nspi->xfer_udelay;
  61        t.speed_hz = nspi->xfer_speed_hz;
  62
  63        spi_message_init(&m);
  64        spi_message_add_tail(&t, &m);
  65
  66        return spi_sync(nspi->spi, &m);
  67}
  68
  69int nci_spi_send(struct nci_spi *nspi,
  70                 struct completion *write_handshake_completion,
  71                 struct sk_buff *skb)
  72{
  73        unsigned int payload_len = skb->len;
  74        unsigned char *hdr;
  75        int ret;
  76        long completion_rc;
  77
  78        /* add the NCI SPI header to the start of the buffer */
  79        hdr = skb_push(skb, NCI_SPI_HDR_LEN);
  80        hdr[0] = NCI_SPI_DIRECT_WRITE;
  81        hdr[1] = nspi->acknowledge_mode;
  82        hdr[2] = payload_len >> 8;
  83        hdr[3] = payload_len & 0xFF;
  84
  85        if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
  86                u16 crc;
  87
  88                crc = crc_ccitt(CRC_INIT, skb->data, skb->len);
  89                skb_put_u8(skb, crc >> 8);
  90                skb_put_u8(skb, crc & 0xFF);
  91        }
  92
  93        if (write_handshake_completion) {
  94                /* Trick SPI driver to raise chip select */
  95                ret = __nci_spi_send(nspi, NULL, 1);
  96                if (ret)
  97                        goto done;
  98
  99                /* wait for NFC chip hardware handshake to complete */
 100                if (wait_for_completion_timeout(write_handshake_completion,
 101                                                msecs_to_jiffies(1000)) == 0) {
 102                        ret = -ETIME;
 103                        goto done;
 104                }
 105        }
 106
 107        ret = __nci_spi_send(nspi, skb, 0);
 108        if (ret != 0 || nspi->acknowledge_mode == NCI_SPI_CRC_DISABLED)
 109                goto done;
 110
 111        reinit_completion(&nspi->req_completion);
 112        completion_rc = wait_for_completion_interruptible_timeout(
 113                                                        &nspi->req_completion,
 114                                                        NCI_SPI_SEND_TIMEOUT);
 115
 116        if (completion_rc <= 0 || nspi->req_result == ACKNOWLEDGE_NACK)
 117                ret = -EIO;
 118
 119done:
 120        kfree_skb(skb);
 121
 122        return ret;
 123}
 124EXPORT_SYMBOL_GPL(nci_spi_send);
 125
 126/* ---- Interface to NCI SPI drivers ---- */
 127
 128/**
 129 * nci_spi_allocate_spi - allocate a new nci spi
 130 *
 131 * @spi: SPI device
 132 * @acknowledge_mode: Acknowledge mode used by the NFC device
 133 * @delay: delay between transactions in us
 134 * @ndev: nci dev to send incoming nci frames to
 135 */
 136struct nci_spi *nci_spi_allocate_spi(struct spi_device *spi,
 137                                     u8 acknowledge_mode, unsigned int delay,
 138                                     struct nci_dev *ndev)
 139{
 140        struct nci_spi *nspi;
 141
 142        nspi = devm_kzalloc(&spi->dev, sizeof(struct nci_spi), GFP_KERNEL);
 143        if (!nspi)
 144                return NULL;
 145
 146        nspi->acknowledge_mode = acknowledge_mode;
 147        nspi->xfer_udelay = delay;
 148        /* Use controller max SPI speed by default */
 149        nspi->xfer_speed_hz = 0;
 150        nspi->spi = spi;
 151        nspi->ndev = ndev;
 152        init_completion(&nspi->req_completion);
 153
 154        return nspi;
 155}
 156EXPORT_SYMBOL_GPL(nci_spi_allocate_spi);
 157
 158static int send_acknowledge(struct nci_spi *nspi, u8 acknowledge)
 159{
 160        struct sk_buff *skb;
 161        unsigned char *hdr;
 162        u16 crc;
 163        int ret;
 164
 165        skb = nci_skb_alloc(nspi->ndev, 0, GFP_KERNEL);
 166
 167        /* add the NCI SPI header to the start of the buffer */
 168        hdr = skb_push(skb, NCI_SPI_HDR_LEN);
 169        hdr[0] = NCI_SPI_DIRECT_WRITE;
 170        hdr[1] = NCI_SPI_CRC_ENABLED;
 171        hdr[2] = acknowledge << NCI_SPI_ACK_SHIFT;
 172        hdr[3] = 0;
 173
 174        crc = crc_ccitt(CRC_INIT, skb->data, skb->len);
 175        skb_put_u8(skb, crc >> 8);
 176        skb_put_u8(skb, crc & 0xFF);
 177
 178        ret = __nci_spi_send(nspi, skb, 0);
 179
 180        kfree_skb(skb);
 181
 182        return ret;
 183}
 184
 185static struct sk_buff *__nci_spi_read(struct nci_spi *nspi)
 186{
 187        struct sk_buff *skb;
 188        struct spi_message m;
 189        unsigned char req[2], resp_hdr[2];
 190        struct spi_transfer tx, rx;
 191        unsigned short rx_len = 0;
 192        int ret;
 193
 194        spi_message_init(&m);
 195
 196        memset(&tx, 0, sizeof(struct spi_transfer));
 197        req[0] = NCI_SPI_DIRECT_READ;
 198        req[1] = nspi->acknowledge_mode;
 199        tx.tx_buf = req;
 200        tx.len = 2;
 201        tx.cs_change = 0;
 202        tx.speed_hz = nspi->xfer_speed_hz;
 203        spi_message_add_tail(&tx, &m);
 204
 205        memset(&rx, 0, sizeof(struct spi_transfer));
 206        rx.rx_buf = resp_hdr;
 207        rx.len = 2;
 208        rx.cs_change = 1;
 209        rx.speed_hz = nspi->xfer_speed_hz;
 210        spi_message_add_tail(&rx, &m);
 211
 212        ret = spi_sync(nspi->spi, &m);
 213        if (ret)
 214                return NULL;
 215
 216        if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED)
 217                rx_len = ((resp_hdr[0] & NCI_SPI_MSB_PAYLOAD_MASK) << 8) +
 218                                resp_hdr[1] + NCI_SPI_CRC_LEN;
 219        else
 220                rx_len = (resp_hdr[0] << 8) | resp_hdr[1];
 221
 222        skb = nci_skb_alloc(nspi->ndev, rx_len, GFP_KERNEL);
 223        if (!skb)
 224                return NULL;
 225
 226        spi_message_init(&m);
 227
 228        memset(&rx, 0, sizeof(struct spi_transfer));
 229        rx.rx_buf = skb_put(skb, rx_len);
 230        rx.len = rx_len;
 231        rx.cs_change = 0;
 232        rx.delay_usecs = nspi->xfer_udelay;
 233        rx.speed_hz = nspi->xfer_speed_hz;
 234        spi_message_add_tail(&rx, &m);
 235
 236        ret = spi_sync(nspi->spi, &m);
 237        if (ret)
 238                goto receive_error;
 239
 240        if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
 241                *(u8 *)skb_push(skb, 1) = resp_hdr[1];
 242                *(u8 *)skb_push(skb, 1) = resp_hdr[0];
 243        }
 244
 245        return skb;
 246
 247receive_error:
 248        kfree_skb(skb);
 249
 250        return NULL;
 251}
 252
 253static int nci_spi_check_crc(struct sk_buff *skb)
 254{
 255        u16 crc_data = (skb->data[skb->len - 2] << 8) |
 256                        skb->data[skb->len - 1];
 257        int ret;
 258
 259        ret = (crc_ccitt(CRC_INIT, skb->data, skb->len - NCI_SPI_CRC_LEN)
 260                        == crc_data);
 261
 262        skb_trim(skb, skb->len - NCI_SPI_CRC_LEN);
 263
 264        return ret;
 265}
 266
 267static u8 nci_spi_get_ack(struct sk_buff *skb)
 268{
 269        u8 ret;
 270
 271        ret = skb->data[0] >> NCI_SPI_ACK_SHIFT;
 272
 273        /* Remove NFCC part of the header: ACK, NACK and MSB payload len */
 274        skb_pull(skb, 2);
 275
 276        return ret;
 277}
 278
 279/**
 280 * nci_spi_read - read frame from NCI SPI drivers
 281 *
 282 * @nspi: The nci spi
 283 * Context: can sleep
 284 *
 285 * This call may only be used from a context that may sleep.  The sleep
 286 * is non-interruptible, and has no timeout.
 287 *
 288 * It returns an allocated skb containing the frame on success, or NULL.
 289 */
 290struct sk_buff *nci_spi_read(struct nci_spi *nspi)
 291{
 292        struct sk_buff *skb;
 293
 294        /* Retrieve frame from SPI */
 295        skb = __nci_spi_read(nspi);
 296        if (!skb)
 297                goto done;
 298
 299        if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
 300                if (!nci_spi_check_crc(skb)) {
 301                        send_acknowledge(nspi, ACKNOWLEDGE_NACK);
 302                        goto done;
 303                }
 304
 305                /* In case of acknowledged mode: if ACK or NACK received,
 306                 * unblock completion of latest frame sent.
 307                 */
 308                nspi->req_result = nci_spi_get_ack(skb);
 309                if (nspi->req_result)
 310                        complete(&nspi->req_completion);
 311        }
 312
 313        /* If there is no payload (ACK/NACK only frame),
 314         * free the socket buffer
 315         */
 316        if (!skb->len) {
 317                kfree_skb(skb);
 318                skb = NULL;
 319                goto done;
 320        }
 321
 322        if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED)
 323                send_acknowledge(nspi, ACKNOWLEDGE_ACK);
 324
 325done:
 326
 327        return skb;
 328}
 329EXPORT_SYMBOL_GPL(nci_spi_read);
 330
 331MODULE_LICENSE("GPL");
 332