6410 spi设备驱动

来源:互联网 发布:js模仿select 编辑:程序博客网 时间:2024/06/05 06:51

可以参考这篇文章  mostmark   linux设备模型之SPI子系统:http://blog.csdn.net/gdt_a20/article/details/6437941

重要的结构体:

struct spi_transfer {/* it's ok if tx_buf == rx_buf (right?) * for MicroWire, one buffer must be null * buffers must work with dma_*map_single() calls, unless *   spi_message.is_dma_mapped reports a pre-existing mapping */const void*tx_buf;void*rx_buf;unsignedlen;dma_addr_ttx_dma;dma_addr_trx_dma;unsignedcs_change:1;u8bits_per_word;u16delay_usecs;u32speed_hz;struct list_head transfer_list;};struct spi_message {struct list_headtransfers;struct spi_device*spi;unsignedis_dma_mapped:1;/* REVISIT:  we might want a flag affecting the behavior of the * last transfer ... allowing things like "read 16 bit length L" * immediately followed by "read L bytes".  Basically imposing * a specific message scheduling algorithm. * * Some controller drivers (message-at-a-time queue processing) * could provide that as their default scheduling algorithm.  But * others (with multi-message pipelines) could need a flag to * tell them about such special cases. *//* completion is reported through a callback */void(*complete)(void *context);void*context;unsignedactual_length;intstatus;/* for optional use by whatever driver currently owns the * spi_message ...  between calls to spi_async and then later * complete(), that's the spi_master controller driver. */struct list_headqueue;void*state;};


分析设备写:

struct spi_transfer st[2];
struct spi_message  msg;
spi_message_init( &msg );

spi_message_add_tail( &st[0], &msg );
spi_sync( flash->spi, &msg ); 函数的原型位于:drivers/spi/spi.c 中


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

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;
}


int spi_async_locked(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);


ret = __spi_async(spi, message);


spin_unlock_irqrestore(&master->bus_lock_spinlock, flags);


return ret;


}


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 调用的是 drivers/spi/spi_s3c64xx.c里的s3c64xx_spi_transfer函数。

接着查看 linux设备驱动剖析之SPI(三) 网址为:http://www.cnblogs.com/lknlfy/p/3265054.html


修改drivers/spi/spi_s3c64xx.c

static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd,
struct spi_transfer *xfer, int dma_mode)
{
struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
void __iomem *regs = sdd->regs;
unsigned long val;
int ms;


/* millisecs to xfer 'len' bytes @ 'cur_speed' */
ms = xfer->len * 8 * 1000 / sdd->cur_speed;
ms += 10; /* some tolerance */


if (dma_mode) {
val = msecs_to_jiffies(ms) + 10;
val = wait_for_completion_timeout(&sdd->xfer_completion, val);
} else {
u32 status;
val = msecs_to_loops(ms);
do {
status = readl(regs + S3C64XX_SPI_STATUS);
} while (RX_FIFO_LVL(status, sci) < xfer->len && --val);
}


if (!val)
return -EIO;


if (dma_mode) {
u32 status;


/*
* DmaTx returns after simply writing data in the FIFO,
* w/o waiting for real transmission on the bus to finish.
* DmaRx returns only after Dma read data from FIFO which
* needs bus transmission to finish, so we don't worry if
* Xfer involved Rx(with or without Tx).
*/
if (xfer->rx_buf == NULL) {
val = msecs_to_loops(10);
status = readl(regs + S3C64XX_SPI_STATUS);
while ((TX_FIFO_LVL(status, sci)
|| !S3C64XX_SPI_ST_TX_DONE(status, sci))
&& --val) {
cpu_relax();
status = readl(regs + S3C64XX_SPI_STATUS);
}


if (!val)
return -EIO;
}
} else {
/* If it was only Tx */
if (xfer->rx_buf == NULL) {
sdd->state &= ~TXBUSY;
return 0;
}
/*
switch (sdd->cur_bpw) {
case 32:
ioread32_rep(regs + S3C64XX_SPI_RX_DATA,
xfer->rx_buf, xfer->len / 4);
break;
case 16:
ioread16_rep(regs + S3C64XX_SPI_RX_DATA,
xfer->rx_buf, xfer->len / 2);
break;
default:
ioread8_rep(regs + S3C64XX_SPI_RX_DATA,
xfer->rx_buf, xfer->len);
break;
}
*/

i = 0;
        buf = xfer->rx_buf;
        while (i < xfer->len)
while(ren);
            buf[i++] = readb(regs + S3C64XX_SPI_RX_DATA);



        sdd->state &= ~RXBUSY;

}

return 0;

}


红色的内容替换蓝色的内容。

0 0
原创粉丝点击