转自:
对于SPI的一些结构体都有所了解之后呢,那么再去瞧瞧SPI的那些长见的操作的函数了。
首先看一下本人画的比较挫的数据流了,仅供参考,如有不对,不吝赐教
接下来看看各个函数吧还是:
SPI write
- /**
- * 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
- /**
- * 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
- /* 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
- /**
- * 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;
- }
- 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
- int spi_sync(struct spi_device *spi, struct spi_message *message)
- {
- return __spi_sync(spi, message, 0);
- }
接着调用了__spi_sync
- 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
- 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
- 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函数
- 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;
-
- }
主要看下下面三个函数
- 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,看一下这个函数
- 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;
-
- }
看到这个函数指针了吧:
- if (!bitbang->master->transfer)
-
- bitbang->master->transfer = spi_bitbang_transfer;
那么设备驱动调用的master->transfer(spi, message);就是调用到了spi_bitbang_transfer了,
- /**
-
- * 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做了什么
- 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);
-
- }
当队列非空的时候就一直去取队列的数据,然后会执行到
- status = bitbang->setup_transfer(spi, t);
这个函数,因为在spi_bitbang_start中
- 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;
- 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的。
- 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 中有
- cs->txrx_word = bitbang->txrx_word[spi->mode & (SPI_CPOL|SPI_CPHA)];
所以,这个最终还是调用到了spi_gpio.c文件中的spi_gpio_spec_txrx_word_mode0
- 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中
- 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中的
- const u8 *tx = t->tx_buf;
-
- u8 *rx = t->rx_buf;
这里是强制转换的,由于大小端的问题,可能导致数据相反,从而传输会出现问题的,如果是8bit的,那么就没有任何问题了。
一段小插曲,也是用逻辑分析仪抓到的数据才发现的,如果没有这玩意儿,估计现在还纠结着。
OK,至此,linux的SPI的数据传输就到这里了。
【facebook】 张昺华 zhangbinghua
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.