您的位置:首页 > 运维架构 > Linux

和菜鸟一起学linux总线驱动之初识spi驱动数据传输流程

2017-10-12 13:17 866 查看
转载地址:http://blog.csdn.net/eastmoon502136/article/details/7921846

对于SPI的一些结构体都有所了解之后呢,那么再去瞧瞧SPI的那些长见的操作的函数了。

首先看一下本人画的比较挫的数据流了,仅供参考,如有不对,不吝赐教

 



 

接下来看看各个函数吧还是:

 

SPI write

 

[html]
view plain
copy

/**  
 * spi_write - SPI synchronous write  
 * @spi: device to which data will be written  
 * @buf: data buffer  
 * @len: data buffer size  
 * Context: can sleep  
 *  
 * This writes the buffer and returns zero or a negative error code.  
 * Callable only from contexts that can sleep.  
 */  
static inline int  
spi_write(struct spi_device *spi, const void *buf, size_t len)  
{  
       struct spi_transfer   t = {  
                     .tx_buf           = buf,  
                     .len         = len,  
              };  
       struct spi_message  m;  
   
       spi_message_init(&m);  
       spi_message_add_tail(&t, &m);  
       return spi_sync(spi, &m);  
  
}  

SPI发送函数,数据放在buf中,然后把要发送的数据放在工作队列中

 

SPI  read

 

[html]
view plain
copy

/**  
 * spi_read - SPI synchronous read  
 * @spi: device from which data will be read  
 * @buf: data buffer  
 * @len: data buffer size  
 * Context: can sleep  
 *  
 * This reads the buffer and returns zero or a negative error code.  
 * Callable only from contexts that can sleep.  
 */  
static inline int  
spi_read(struct spi_device *spi, void *buf, size_t len)  
{  
       struct spi_transfer   t = {  
                     .rx_buf           = buf,  
                     .len         = len,  
              };  
       struct spi_message  m;  
  
       spi_message_init(&m);  
       spi_message_add_tail(&t, &m);  
       return spi_sync(spi, &m);  
}  

SPI接收函数,数据放在buf中,然后把要发送的数据放在工作队列中,发送出去

 

SPI write 8 bits read 8 bits

 

[html]
view plain
copy

/* this copies txbuf and rxbuf data; for small transfers only! */  
extern int spi_write_then_read(struct spi_device *spi,  
              const void *txbuf, unsigned n_tx,  
              void *rxbuf, unsigned n_rx);  
/**  
 * spi_w8r8 - SPI synchronous 8 bit write followed by 8 bit read  
 * @spi: device with which data will be exchanged  
 * @cmd: command to be written before data is read back  
 * Context: can sleep  
 *  
 * This returns the (unsigned) eight bit number returned by the  
 * device, or else a negative error code.  Callable only from  
 * contexts that can sleep.  
 */  
static inline ssize_t spi_w8r8(struct spi_device *spi, u8 cmd)  
{  
       ssize_t                   status;  
       u8                  result;   
       status = spi_write_then_read(spi, &cmd, 1, &result, 1);  
  
       /* return negative errno or unsigned value */  
       return (status < 0) ? status : result;  
}  

 

 

SPI write 8 bit read 16 bits

 

[html]
view plain
copy

/**  
 * spi_w8r16 - SPI synchronous 8 bit write followed by 16 bit read  
 * @spi: device with which data will be exchanged  
 * @cmd: command to be written before data is read back  
 * Context: can sleep  
 *  
 * This returns the (unsigned) sixteen bit number returned by the  
 * device, or else a negative error code.  Callable only from  
 * contexts that can sleep.  
 *  
 * The number is returned in wire-order, which is at least sometimes  
 * big-endian.  
 */  
static inline ssize_t spi_w8r16(struct spi_device *spi, u8 cmd)  
{  
       ssize_t                   status;  
       u16                result;  
   
       status = spi_write_then_read(spi, &cmd, 1, (u8 *) &result, 2);  
   
       /* return negative errno or unsigned value */  
       return (status < 0) ? status : result;  
}  

 

[html]
view plain
copy

int spi_write_then_read(struct spi_device *spi,  
              const void *txbuf, unsigned n_tx,  
              void *rxbuf, unsigned n_rx)  
{  
       static DEFINE_MUTEX(lock);  
   
       int                 status;  
       struct spi_message  message;  
       struct spi_transfer   x[2];  
       u8                  *local_buf;  
   
       /* Use preallocated DMA-safe buffer.  We can't avoid copying here,  
        * (as a pure convenience thing), but we can keep heap costs  
        * out of the hot path ...  
        */  
       if ((n_tx + n_rx) > SPI_BUFSIZ)  
              return -EINVAL;  
   
       spi_message_init(&message);  
       memset(x, 0, sizeof x);  
       if (n_tx) {  
              x[0].len = n_tx;  
              spi_message_add_tail(&x[0], &message);  
       }  
       if (n_rx) {  
              x[1].len = n_rx;  
              spi_message_add_tail(&x[1], &message);  
       }  
   
       /* ... unless someone else is using the pre-allocated buffer */  
       if (!mutex_trylock(&lock)) {  
              local_buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);  
              if (!local_buf)  
                     return -ENOMEM;  
       } else  
              local_buf = buf;  
   
       memcpy(local_buf, txbuf, n_tx);  
       x[0].tx_buf = local_buf;  
       x[1].rx_buf = local_buf + n_tx;   
       /* do the i/o */  
       status = spi_sync(spi, &message);  
       if (status == 0)  
              memcpy(rxbuf, x[1].rx_buf, n_rx);  
   
       if (x[0].tx_buf == buf)  
              mutex_unlock(&lock);  
       else  
              kfree(local_buf);  
   
       return status;  
}  

 

 

SPI sync

读写都会调用到spi_sync

[html]
view plain
copy

int spi_sync(struct spi_device *spi, struct spi_message *message)  
{  
       return __spi_sync(spi, message, 0);  
}  

 

接着调用了__spi_sync

 

[html]
view plain
copy

static int __spi_sync(struct spi_device *spi, struct spi_message *message,  
                    int bus_locked)  
{  
       DECLARE_COMPLETION_ONSTACK(done);  
       int status;  
       struct spi_master *master = spi->master;  
   
       message->complete = spi_complete;  
       message->context = &done;  
   
       if (!bus_locked)  
              mutex_lock(&master->bus_lock_mutex);  
        status = spi_async_locked(spi, message);  
   
       if (!bus_locked)  
              mutex_unlock(&master->bus_lock_mutex);  
   
       if (status == 0) {  
              wait_for_completion(&done);  
              status = message->status;  
       }  
       message->context = NULL;  
       return status;  
}  

 

 

然后就是spi_async

[html]
view plain
copy

int spi_async(struct spi_device *spi, struct spi_message *message)  
{  
       struct spi_master *master = spi->master;  
       int ret;  
       unsigned long flags;  
   
       spin_lock_irqsave(&master->bus_lock_spinlock, flags);  
   
       if (master->bus_lock_flag)  
              ret = -EBUSY;  
       else  
              ret = __spi_async(spi, message);  
   
       spin_unlock_irqrestore(&master->bus_lock_spinlock, flags);  
   
       return ret;  
}  

 

最后调用__spi_async

[html]
view plain
copy

static int __spi_async(struct spi_device *spi, struct spi_message *message)  
{  
       struct spi_master *master = spi->master;  
   
       /* Half-duplex links include original MicroWire, and ones with  
        * only one data pin like SPI_3WIRE (switches direction) or where  
        * either MOSI or MISO is missing.  They can also be caused by  
        * software limitations.  
        */  
       if ((master->flags & SPI_MASTER_HALF_DUPLEX)  
                     || (spi->mode & SPI_3WIRE)) {  
              struct spi_transfer *xfer;  
              unsigned flags = master->flags;  
   
              list_for_each_entry(xfer, &message->transfers, transfer_list) {  
                     if (xfer->rx_buf && xfer->tx_buf)  
                            return -EINVAL;  
                     if ((flags & SPI_MASTER_NO_TX) && xfer->tx_buf)  
                            return -EINVAL;  
                     if ((flags & SPI_MASTER_NO_RX) && xfer->rx_buf)  
                            return -EINVAL;  
              }  
       }  
  
       message->spi = spi;  
       message->status = -EINPROGRESS;  
       return master->transfer(spi, message);  
}  

 

返回了master->transfer(spi, message);那么就是控制器里去工作了。

 

我用的是gpio模拟的spi,所以那用gpio模拟的那个控制器去看控制器的处理了。

先还是看一下probe函数

 

[html]
view plain
copy

static int __init spi_gpio_probe(struct platform_device *pdev)  
  
{  
  
       int                        status;  
  
       struct spi_master           *master;  
  
       struct spi_gpio                     *spi_gpio;  
  
       struct spi_gpio_platform_data       *pdata;  
  
       u16 master_flags = 0;  
  
   
  
       pdata = pdev->dev.platform_data;  
  
#ifdef GENERIC_BITBANG  
  
       if (!pdata || !pdata->num_chipselect)  
  
              return -ENODEV;  
  
#endif  
  
   
  
       status = spi_gpio_request(pdata, dev_name(&pdev->dev), &master_flags);  
  
       if (status < 0)  
  
              return status;  
  
   
  
       master = spi_alloc_master(&pdev->dev, sizeof *spi_gpio);  
  
       if (!master) {  
  
              status = -ENOMEM;  
  
              goto gpio_free;  
  
       }  
  
       spi_gpio = spi_master_get_devdata(master);  
  
       platform_set_drvdata(pdev, spi_gpio);  
  
   
  
       spi_gpio->pdev = pdev;  
  
       if (pdata)  
  
              spi_gpio->pdata = *pdata;  
  
   
  
       master->flags = master_flags;  
  
       master->bus_num = pdev->id;  
  
       master->num_chipselect = SPI_N_CHIPSEL;  
  
       master->setup = spi_gpio_setup;  
  
       master->cleanup = spi_gpio_cleanup;  
  
   
  
       spi_gpio->bitbang.master = spi_master_get(master);  
  
       spi_gpio->bitbang.chipselect = spi_gpio_chipselect;  
  
   
  
       if ((master_flags & (SPI_MASTER_NO_TX | SPI_MASTER_NO_RX)) == 0) {  
  
              spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_word_mode0;  
  
              spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_word_mode1;  
  
              spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_word_mode2;  
  
              spi_gpio->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_txrx_word_mode3;  
  
       } else {  
  
              spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_spec_txrx_word_mode0;  
  
              spi_gpio->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_spec_txrx_word_mode1;  
  
              spi_gpio->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_spec_txrx_word_mode2;  
  
              spi_gpio->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_spec_txrx_word_mode3;  
  
       }  
  
       spi_gpio->bitbang.setup_transfer = spi_bitbang_setup_transfer;  
  
       spi_gpio->bitbang.flags = SPI_CS_HIGH;  
  
   
  
       status = spi_bitbang_start(&spi_gpio->bitbang);  
  
       if (status < 0) {  
  
              spi_master_put(spi_gpio->bitbang.master);  
  
gpio_free:  
  
              if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO)  
  
                     gpio_free(SPI_MISO_GPIO);  
  
              if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI)  
  
                     gpio_free(SPI_MOSI_GPIO);  
  
              gpio_free(SPI_SCK_GPIO);  
  
              spi_master_put(master);  
  
       }  
  
   
  
       return status;  
  
}  

 

主要看下下面三个函数

[html]
view plain
copy

spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_word_mode0;  
  
spi_gpio->bitbang.setup_transfer = spi_bitbang_setup_transfer;  
  
status = spi_bitbang_start(&spi_gpio->bitbang);   

 

spi_gpio_txrx_word_mode0;就是最后调用到的先放一边,spi_bitbang_start,看一下这个函数

 

[html]
view plain
copy

int spi_bitbang_start(struct spi_bitbang *bitbang)  
  
{  
  
       int   status;  
  
   
  
       if (!bitbang->master || !bitbang->chipselect)  
  
              return -EINVAL;  
  
   
  
       INIT_WORK(&bitbang->work, bitbang_work);  
  
       spin_lock_init(&bitbang->lock);  
  
       INIT_LIST_HEAD(&bitbang->queue);  
  
   
  
       if (!bitbang->master->mode_bits)  
  
              bitbang->master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags;  
  
   
  
       if (!bitbang->master->transfer)  
  
              bitbang->master->transfer = spi_bitbang_transfer;  
  
       if (!bitbang->txrx_bufs) {  
  
              bitbang->use_dma = 0;  
  
              bitbang->txrx_bufs = spi_bitbang_bufs;  
  
              if (!bitbang->master->setup) {  
  
                     if (!bitbang->setup_transfer)  
  
                            bitbang->setup_transfer =  
  
                                    spi_bitbang_setup_transfer;  
  
                     bitbang->master->setup = spi_bitbang_setup;  
  
                     bitbang->master->cleanup = spi_bitbang_cleanup;  
  
              }  
  
       } else if (!bitbang->master->setup)  
  
              return -EINVAL;  
  
       if (bitbang->master->transfer == spi_bitbang_transfer &&  
  
                     !bitbang->setup_transfer)  
  
              return -EINVAL;  
  
   
  
       /* this task is the only thing to touch the SPI bits */  
  
       bitbang->busy = 0;  
  
       bitbang->workqueue = create_singlethread_workqueue(  
  
                     dev_name(bitbang->master->dev.parent));  
  
       if (bitbang->workqueue == NULL) {  
  
              status = -EBUSY;  
  
              goto err1;  
  
       }  
  
   
  
       /* driver may get busy before register() returns, especially  
  
        * if someone registered boardinfo for devices  
  
        */  
  
       status = spi_register_master(bitbang->master);  
  
       if (status < 0)  
  
              goto err2;  
  
   
  
       return status;  
  
   
  
err2:  
  
       destroy_workqueue(bitbang->workqueue);  
  
err1:  
  
       return status;  
  
}  

 

看到这个函数指针了吧:

[html]
view plain
copy

if (!bitbang->master->transfer)  
  
              bitbang->master->transfer = spi_bitbang_transfer;  

那么设备驱动调用的master->transfer(spi, message);就是调用到了spi_bitbang_transfer了,
 

[html]
view plain
copy

/**  
  
 * spi_bitbang_transfer - default submit to transfer queue  
  
 */  
  
int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m)  
  
{  
  
       struct spi_bitbang   *bitbang;  
  
       unsigned long        flags;  
  
       int                 status = 0;  
  
   
  
       m->actual_length = 0;  
  
       m->status = -EINPROGRESS;  
  
   
  
       bitbang = spi_master_get_devdata(spi->master);  
  
   
  
       spin_lock_irqsave(&bitbang->lock, flags);  
  
       if (!spi->max_speed_hz)  
  
              status = -ENETDOWN;  
  
       else {  
  
              list_add_tail(&m->queue, &bitbang->queue);  
  
              queue_work(bitbang->workqueue, &bitbang->work);  
  
       }  
  
       spin_unlock_irqrestore(&bitbang->lock, flags);  
  
   
  
       return status;  
  
}  

这里是把信息加到了bitbang->workqueue,然后在bitbang->work里处理

 

再来看下bitbang->work做了什么

[html]
view plain
copy

static void bitbang_work(struct work_struct *work)  
  
{  
  
       struct spi_bitbang   *bitbang =  
  
              container_of(work, struct spi_bitbang, work);  
  
       unsigned long        flags;  
  
   
  
       spin_lock_irqsave(&bitbang->lock, flags);  
  
       bitbang->busy = 1;  
  
       while (!list_empty(&bitbang->queue)) {  
  
              struct spi_message  *m;  
  
              struct spi_device     *spi;  
  
              unsigned         nsecs;  
  
              struct spi_transfer   *t = NULL;  
  
              unsigned         tmp;  
  
              unsigned         cs_change;  
  
              int                 status;  
  
              int                 do_setup = -1;  
  
   
  
              m = container_of(bitbang->queue.next, struct spi_message,  
  
                            queue);  
  
              list_del_init(&m->queue);  
  
              spin_unlock_irqrestore(&bitbang->lock, flags);  
  
   
  
              /* FIXME this is made-up ... the correct value is known to  
  
               * word-at-a-time bitbang code, and presumably chipselect()  
  
               * should enforce these requirements too?  
  
               */  
  
              nsecs = 100;  
  
   
  
              spi = m->spi;  
  
              tmp = 0;  
  
              cs_change = 1;  
  
              status = 0;  
  
   
  
              list_for_each_entry (t, &m->transfers, transfer_list) {  
  
   
  
                     /* override speed or wordsize? */  
  
                     if (t->speed_hz || t->bits_per_word)  
  
                            do_setup = 1;  
  
   
  
                     /* init (-1) or override (1) transfer params */  
  
                     if (do_setup != 0) {  
  
                            status = bitbang->setup_transfer(spi, t);  
  
                            if (status < 0)  
  
                                   break;  
  
                            if (do_setup == -1)  
  
                                   do_setup = 0;  
  
                     }  
  
   
  
                     /* set up default clock polarity, and activate chip;  
  
                      * this implicitly updates clock and spi modes as  
  
                      * previously recorded for this device via setup().  
  
                      * (and also deselects any other chip that might be  
  
                      * selected ...)  
  
                      */  
  
                     if (cs_change) {  
  
                            bitbang->chipselect(spi, BITBANG_CS_ACTIVE);  
  
                            ndelay(nsecs);  
  
                     }  
  
                     cs_change = t->cs_change;  
  
                     if (!t->tx_buf && !t->rx_buf && t->len) {  
  
                            status = -EINVAL;  
  
                            break;  
  
                     }  
  
   
  
                     /* transfer data.  the lower level code handles any  
  
                      * new dma mappings it needs. our caller always gave  
  
                      * us dma-safe buffers.  
  
                      */  
  
                     if (t->len) {  
  
                            /* REVISIT dma API still needs a designated  
  
                             * DMA_ADDR_INVALID; ~0 might be better.  
  
                             */  
  
                            if (!m->is_dma_mapped)  
  
                                   t->rx_dma = t->tx_dma = 0;  
  
                            status = bitbang->txrx_bufs(spi, t);  
  
                     }  
  
                     if (status > 0)  
  
                            m->actual_length += status;  
  
                     if (status != t->len) {  
  
                            /* always report some kind of error */  
  
                            if (status >= 0)  
  
                                   status = -EREMOTEIO;  
  
                            break;  
  
                     }  
  
                     status = 0;  
  
   
  
                     /* protocol tweaks before next transfer */  
  
                     if (t->delay_usecs)  
  
                            udelay(t->delay_usecs);  
  
   
  
                     if (!cs_change)  
  
                            continue;  
  
                     if (t->transfer_list.next == &m->transfers)  
  
                            break;  
  
   
  
                     /* sometimes a short mid-message deselect of the chip  
  
                      * may be needed to terminate a mode or command  
  
                      */  
  
                     ndelay(nsecs);  
  
                     bitbang->chipselect(spi, BITBANG_CS_INACTIVE);  
  
                     ndelay(nsecs);  
  
              }  
  
   
  
              m->status = status;  
  
              m->complete(m->context);  
  
   
  
              /* normally deactivate chipselect ... unless no error and  
  
               * cs_change has hinted that the next message will probably  
  
               * be for this chip too.  
  
               */  
  
              if (!(status == 0 && cs_change)) {  
  
                     ndelay(nsecs);  
  
                     bitbang->chipselect(spi, BITBANG_CS_INACTIVE);  
  
                     ndelay(nsecs);  
  
              }  
  
   
  
              spin_lock_irqsave(&bitbang->lock, flags);  
  
       }  
  
       bitbang->busy = 0;  
  
       spin_unlock_irqrestore(&bitbang->lock, flags);  
  
}  

 

当队列非空的时候就一直去取队列的数据,然后会执行到

[html]
view plain
copy

status = bitbang->setup_transfer(spi, t);  

这个函数,因为在spi_bitbang_start中

[html]
view plain
copy

if (!bitbang->txrx_bufs) {  
  
              bitbang->use_dma = 0;  
  
              bitbang->txrx_bufs = spi_bitbang_bufs;  
  
              if (!bitbang->master->setup) {  
  
                     if (!bitbang->setup_transfer)  
  
                            bitbang->setup_transfer =  
  
                                    spi_bitbang_setup_transfer;  
  
                     bitbang->master->setup = spi_bitbang_setup;  
  
                     bitbang->master->cleanup = spi_bitbang_cleanup;  
  
              }  
  
       }  

所以就调用了spi_bitbang_setup_transfer;

 

 

[html]
view plain
copy

int spi_bitbang_setup_transfer(struct spi_device *spi, struct spi_transfer *t)  
  
{  
  
       struct spi_bitbang_cs      *cs = spi->controller_state;  
  
       u8                  bits_per_word;  
  
       u32                hz;  
  
   
  
       if (t) {  
  
              bits_per_word = t->bits_per_word;  
  
              hz = t->speed_hz;  
  
       } else {  
  
              bits_per_word = 0;  
  
              hz = 0;  
  
       }  
  
   
  
       /* spi_transfer level calls that work per-word */  
  
       if (!bits_per_word)  
  
              bits_per_word = spi->bits_per_word;  
  
       if (bits_per_word <= 8)  
  
              cs->txrx_bufs = bitbang_txrx_8;  
  
       else if (bits_per_word <= 16)  
  
              cs->txrx_bufs = bitbang_txrx_16;  
  
       else if (bits_per_word <= 32)  
  
              cs->txrx_bufs = bitbang_txrx_32;  
  
       else  
  
              return -EINVAL;  
  
   
  
       /* nsecs = (clock period)/2 */  
  
       if (!hz)  
  
              hz = spi->max_speed_hz;  
  
       if (hz) {  
  
              cs->nsecs = (1000000000/2) / hz;  
  
              if (cs->nsecs > (MAX_UDELAY_MS * 1000 * 1000))  
  
                     return -EINVAL;  
  
       }  
  
   
  
       return 0;  
  
}  

 

这里主要是根据bits_per_word选择传输的方式,分8、16,、32三种模式,ads7843touchscreen是用bits_per_word默认没有,选择bitbang_txrx_8的。

 

[html]
view plain
copy

static unsigned bitbang_txrx_8(  
  
       struct spi_device     *spi,  
  
       u32                (*txrx_word)(struct spi_device *spi,  
  
                                   unsigned nsecs,  
  
                                   u32 word, u8 bits),  
  
       unsigned         ns,  
  
       struct spi_transfer   *t  
  
) {  
  
       unsigned         bits = t->bits_per_word ? : spi->bits_per_word;  
  
       unsigned         count = t->len;  
  
       const u8         *tx = t->tx_buf;  
  
       u8                  *rx = t->rx_buf;  
  
   
  
       while (likely(count > 0)) {  
  
              u8           word = 0;  
  
   
  
              if (tx)  
  
                     word = *tx++;  
  
              word = txrx_word(spi, ns, word, bits);  
  
              if (rx)  
  
                     *rx++ = word;  
  
              count -= 1;  
  
       }  
  
       return t->len - count;  
  
}  
  
   

这里word = txrx_word(spi, ns, word, bits);会调用到哪里呢?,首先看下这个函数的指针指向哪里。

在spi_bitbang_start中,bitbang->master->setup = spi_bitbang_setup;

然后在spi_bitbang_setup中有

[html]
view plain
copy

cs->txrx_word = bitbang->txrx_word[spi->mode & (SPI_CPOL|SPI_CPHA)];  

所以,这个最终还是调用到了spi_gpio.c文件中的spi_gpio_spec_txrx_word_mode0

[html]
view plain
copy

static u32 spi_gpio_spec_txrx_word_mode0(struct spi_device *spi,  
  
              unsigned nsecs, u32 word, u8 bits)  
  
{  
  
       unsigned flags = spi->master->flags;  
  
       return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits);  
  
}  

然后这个函数就调用了bitbang_txrx_be_cpha0,这个函数在spi-bitbang-txrx.h中

 

[html]
view plain
copy

static inline u32  
  
bitbang_txrx_be_cpha0(struct spi_device *spi,  
  
              unsigned nsecs, unsigned cpol, unsigned flags,  
  
              u32 word, u8 bits)  
  
{  
  
       /* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */  
  
   
  
       /* clock starts at inactive polarity */  
  
       for (word <<= (32 - bits); likely(bits); bits--) {  
  
   
  
              /* setup MSB (to slave) on trailing edge */  
  
              if ((flags & SPI_MASTER_NO_TX) == 0)  
  
                     setmosi(spi, word & (1 << 31));  
  
              spidelay(nsecs);      /* T(setup) */  
  
   
  
              setsck(spi, !cpol);  
  
              spidelay(nsecs);  
  
   
  
              /* sample MSB (from slave) on leading edge */  
  
              word <<= 1;  
  
              if ((flags & SPI_MASTER_NO_RX) == 0)  
  
                     word |= getmiso(spi);  
  
              setsck(spi, cpol);  
  
       }  
  
       return word;  
  
}  

这里就是gpio模拟的spi总线的协议过程了。这样,从最上面设备程序调用到控制器的整个数据流就结束了。

 

注:这里有一个很恶心的东东,就是在bitbang_txrx_16,bitbang_txrx_32中的

[html]
view plain
copy

const u8         *tx = t->tx_buf;  
  
u8                  *rx = t->rx_buf;  

这里是强制转换的,由于大小端的问题,可能导致数据相反,从而传输会出现问题的,如果是8bit的,那么就没有任何问题了。

一段小插曲,也是用逻辑分析仪抓到的数据才发现的,如果没有这玩意儿,估计现在还纠结着。

OK,至此,linux的SPI的数据传输就到这里了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: