linux/drivers/net/caif/caif_spi_slave.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) ST-Ericsson AB 2010
   4 * Author:  Daniel Martensson
   5 */
   6#include <linux/module.h>
   7#include <linux/device.h>
   8#include <linux/platform_device.h>
   9#include <linux/string.h>
  10#include <linux/semaphore.h>
  11#include <linux/workqueue.h>
  12#include <linux/completion.h>
  13#include <linux/list.h>
  14#include <linux/interrupt.h>
  15#include <linux/dma-mapping.h>
  16#include <linux/delay.h>
  17#include <linux/sched.h>
  18#include <linux/debugfs.h>
  19#include <net/caif/caif_spi.h>
  20
  21#ifndef CONFIG_CAIF_SPI_SYNC
  22#define SPI_DATA_POS 0
  23static inline int forward_to_spi_cmd(struct cfspi *cfspi)
  24{
  25        return cfspi->rx_cpck_len;
  26}
  27#else
  28#define SPI_DATA_POS SPI_CMD_SZ
  29static inline int forward_to_spi_cmd(struct cfspi *cfspi)
  30{
  31        return 0;
  32}
  33#endif
  34
  35int spi_frm_align = 2;
  36
  37/*
  38 * SPI padding options.
  39 * Warning: must be a base of 2 (& operation used) and can not be zero !
  40 */
  41int spi_up_head_align   = 1 << 1;
  42int spi_up_tail_align   = 1 << 0;
  43int spi_down_head_align = 1 << 2;
  44int spi_down_tail_align = 1 << 1;
  45
  46#ifdef CONFIG_DEBUG_FS
  47static inline void debugfs_store_prev(struct cfspi *cfspi)
  48{
  49        /* Store previous command for debugging reasons.*/
  50        cfspi->pcmd = cfspi->cmd;
  51        /* Store previous transfer. */
  52        cfspi->tx_ppck_len = cfspi->tx_cpck_len;
  53        cfspi->rx_ppck_len = cfspi->rx_cpck_len;
  54}
  55#else
  56static inline void debugfs_store_prev(struct cfspi *cfspi)
  57{
  58}
  59#endif
  60
  61void cfspi_xfer(struct work_struct *work)
  62{
  63        struct cfspi *cfspi;
  64        u8 *ptr = NULL;
  65        unsigned long flags;
  66        int ret;
  67        cfspi = container_of(work, struct cfspi, work);
  68
  69        /* Initialize state. */
  70        cfspi->cmd = SPI_CMD_EOT;
  71
  72        for (;;) {
  73
  74                cfspi_dbg_state(cfspi, CFSPI_STATE_WAITING);
  75
  76                /* Wait for master talk or transmit event. */
  77                wait_event_interruptible(cfspi->wait,
  78                                 test_bit(SPI_XFER, &cfspi->state) ||
  79                                 test_bit(SPI_TERMINATE, &cfspi->state));
  80
  81                if (test_bit(SPI_TERMINATE, &cfspi->state))
  82                        return;
  83
  84#if CFSPI_DBG_PREFILL
  85                /* Prefill buffers for easier debugging. */
  86                memset(cfspi->xfer.va_tx, 0xFF, SPI_DMA_BUF_LEN);
  87                memset(cfspi->xfer.va_rx, 0xFF, SPI_DMA_BUF_LEN);
  88#endif  /* CFSPI_DBG_PREFILL */
  89
  90                cfspi_dbg_state(cfspi, CFSPI_STATE_AWAKE);
  91
  92        /* Check whether we have a committed frame. */
  93                if (cfspi->tx_cpck_len) {
  94                        int len;
  95
  96                        cfspi_dbg_state(cfspi, CFSPI_STATE_FETCH_PKT);
  97
  98                        /* Copy committed SPI frames after the SPI indication. */
  99                        ptr = (u8 *) cfspi->xfer.va_tx;
 100                        ptr += SPI_IND_SZ;
 101                        len = cfspi_xmitfrm(cfspi, ptr, cfspi->tx_cpck_len);
 102                        WARN_ON(len != cfspi->tx_cpck_len);
 103        }
 104
 105                cfspi_dbg_state(cfspi, CFSPI_STATE_GET_NEXT);
 106
 107                /* Get length of next frame to commit. */
 108                cfspi->tx_npck_len = cfspi_xmitlen(cfspi);
 109
 110                WARN_ON(cfspi->tx_npck_len > SPI_DMA_BUF_LEN);
 111
 112                /*
 113                 * Add indication and length at the beginning of the frame,
 114                 * using little endian.
 115                 */
 116                ptr = (u8 *) cfspi->xfer.va_tx;
 117                *ptr++ = SPI_CMD_IND;
 118                *ptr++ = (SPI_CMD_IND  & 0xFF00) >> 8;
 119                *ptr++ = cfspi->tx_npck_len & 0x00FF;
 120                *ptr++ = (cfspi->tx_npck_len & 0xFF00) >> 8;
 121
 122                /* Calculate length of DMAs. */
 123                cfspi->xfer.tx_dma_len = cfspi->tx_cpck_len + SPI_IND_SZ;
 124                cfspi->xfer.rx_dma_len = cfspi->rx_cpck_len + SPI_CMD_SZ;
 125
 126                /* Add SPI TX frame alignment padding, if necessary. */
 127                if (cfspi->tx_cpck_len &&
 128                        (cfspi->xfer.tx_dma_len % spi_frm_align)) {
 129
 130                        cfspi->xfer.tx_dma_len += spi_frm_align -
 131                            (cfspi->xfer.tx_dma_len % spi_frm_align);
 132                }
 133
 134                /* Add SPI RX frame alignment padding, if necessary. */
 135                if (cfspi->rx_cpck_len &&
 136                        (cfspi->xfer.rx_dma_len % spi_frm_align)) {
 137
 138                        cfspi->xfer.rx_dma_len += spi_frm_align -
 139                            (cfspi->xfer.rx_dma_len % spi_frm_align);
 140                }
 141
 142                cfspi_dbg_state(cfspi, CFSPI_STATE_INIT_XFER);
 143
 144                /* Start transfer. */
 145                ret = cfspi->dev->init_xfer(&cfspi->xfer, cfspi->dev);
 146                WARN_ON(ret);
 147
 148                cfspi_dbg_state(cfspi, CFSPI_STATE_WAIT_ACTIVE);
 149
 150                /*
 151                 * TODO: We might be able to make an assumption if this is the
 152                 * first loop. Make sure that minimum toggle time is respected.
 153                 */
 154                udelay(MIN_TRANSITION_TIME_USEC);
 155
 156                cfspi_dbg_state(cfspi, CFSPI_STATE_SIG_ACTIVE);
 157
 158                /* Signal that we are ready to receive data. */
 159                cfspi->dev->sig_xfer(true, cfspi->dev);
 160
 161                cfspi_dbg_state(cfspi, CFSPI_STATE_WAIT_XFER_DONE);
 162
 163                /* Wait for transfer completion. */
 164                wait_for_completion(&cfspi->comp);
 165
 166                cfspi_dbg_state(cfspi, CFSPI_STATE_XFER_DONE);
 167
 168                if (cfspi->cmd == SPI_CMD_EOT) {
 169                        /*
 170                         * Clear the master talk bit. A xfer is always at
 171                         *  least two bursts.
 172                         */
 173                        clear_bit(SPI_SS_ON, &cfspi->state);
 174                }
 175
 176                cfspi_dbg_state(cfspi, CFSPI_STATE_WAIT_INACTIVE);
 177
 178                /* Make sure that the minimum toggle time is respected. */
 179                if (SPI_XFER_TIME_USEC(cfspi->xfer.tx_dma_len,
 180                                        cfspi->dev->clk_mhz) <
 181                        MIN_TRANSITION_TIME_USEC) {
 182
 183                        udelay(MIN_TRANSITION_TIME_USEC -
 184                                SPI_XFER_TIME_USEC
 185                                (cfspi->xfer.tx_dma_len, cfspi->dev->clk_mhz));
 186                }
 187
 188                cfspi_dbg_state(cfspi, CFSPI_STATE_SIG_INACTIVE);
 189
 190                /* De-assert transfer signal. */
 191                cfspi->dev->sig_xfer(false, cfspi->dev);
 192
 193                /* Check whether we received a CAIF packet. */
 194                if (cfspi->rx_cpck_len) {
 195                        int len;
 196
 197                        cfspi_dbg_state(cfspi, CFSPI_STATE_DELIVER_PKT);
 198
 199                        /* Parse SPI frame. */
 200                        ptr = ((u8 *)(cfspi->xfer.va_rx + SPI_DATA_POS));
 201
 202                        len = cfspi_rxfrm(cfspi, ptr, cfspi->rx_cpck_len);
 203                        WARN_ON(len != cfspi->rx_cpck_len);
 204                }
 205
 206                /* Check the next SPI command and length. */
 207                ptr = (u8 *) cfspi->xfer.va_rx;
 208
 209                ptr += forward_to_spi_cmd(cfspi);
 210
 211                cfspi->cmd = *ptr++;
 212                cfspi->cmd |= ((*ptr++) << 8) & 0xFF00;
 213                cfspi->rx_npck_len = *ptr++;
 214                cfspi->rx_npck_len |= ((*ptr++) << 8) & 0xFF00;
 215
 216                WARN_ON(cfspi->rx_npck_len > SPI_DMA_BUF_LEN);
 217                WARN_ON(cfspi->cmd > SPI_CMD_EOT);
 218
 219                debugfs_store_prev(cfspi);
 220
 221                /* Check whether the master issued an EOT command. */
 222                if (cfspi->cmd == SPI_CMD_EOT) {
 223                        /* Reset state. */
 224                        cfspi->tx_cpck_len = 0;
 225                        cfspi->rx_cpck_len = 0;
 226                } else {
 227                        /* Update state. */
 228                        cfspi->tx_cpck_len = cfspi->tx_npck_len;
 229                        cfspi->rx_cpck_len = cfspi->rx_npck_len;
 230                }
 231
 232                /*
 233                 * Check whether we need to clear the xfer bit.
 234                 * Spin lock needed for packet insertion.
 235                 * Test and clear of different bits
 236                 * are not supported.
 237                 */
 238                spin_lock_irqsave(&cfspi->lock, flags);
 239                if (cfspi->cmd == SPI_CMD_EOT && !cfspi_xmitlen(cfspi)
 240                        && !test_bit(SPI_SS_ON, &cfspi->state))
 241                        clear_bit(SPI_XFER, &cfspi->state);
 242
 243                spin_unlock_irqrestore(&cfspi->lock, flags);
 244        }
 245}
 246
 247struct platform_driver cfspi_spi_driver = {
 248        .probe = cfspi_spi_probe,
 249        .remove = cfspi_spi_remove,
 250        .driver = {
 251                   .name = "cfspi_sspi",
 252                   .owner = THIS_MODULE,
 253                   },
 254};
 255