注:本节大量引用和参考了博客http://blog.csdn.net/yj4231/article/details/7755709的内容
step1:
我们现在就通过ADS8344的ioctl函数可分析一下整个数据是如何传递和接受的
static int ads8344_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
send2user=0X00000000;
u8 channel,revData[AVERAGETIMES][3];
u8 control_word;
int ret = 0, i,k,z;
int temp[AVERAGETIMES][3];
pr_debug("ioctl cmd %d is issued...\n", cmd);
if((cmd>7)||(cmd<0))
return -EINVAL;
switch (cmd) {
case 0: channel = 0; break;
case 1: channel = 4; break;
case 2: channel = 1; break;
case 3: channel = 5; break;
case 4: channel = 2; break;
case 5: channel = 6; break;
case 6: channel = 3; break;
case 7: channel = 7; break;
default: channel = 0; break;
}
mutex_lock(&ads8344_data.lock);
for (i = 0; i < AVERAGETIMES; i++) {
control_word = (1u << 7)|(channel << 4)|(1u << 2)|0x3;
/*发送命令control_word,同时ADS8344中接受3个字节的数据存入revData[i] */
ret = spi_write_then_read(ads8344_data.spi, &control_word, 1,revData[i],3);
if (ret)
break;
}
mutex_unlock(&ads8344_data.lock);
if (ret)
return -EIO;
for(k=0;k<AVERAGETIMES;k++)
{
temp[k][0]=(int)revData[k][0];
temp[k][1]=(int)revData[k][1];
temp[k][2]=(int)revData[k][2];
}
for(z=0;z<AVERAGETIMES;z++)
{
send2user += ((temp[z][0]<<16)|(temp[z][1]<<8)|temp[z][2])>>7;
}
send2user= send2user>>2;
send2user &=0xffff;
return ret;
}
step2:
上面代码中最重要的就是 spi_write_then_read(ads8344_data.spi, &control_word, 1,revData[i],3)。它实现对对ADS8344设备的读写。我追踪一下这个函数。
int spi_write_then_read(struct spi_device *spi,
const u8 *txbuf, unsigned n_tx,
u8 *rxbuf, unsigned n_rx)
{
static DEFINE_MUTEX(lock);
int status;
struct spi_message message;
struct spi_transfer x[2];
u8 *local_buf;
if ((n_tx + n_rx) > SPI_BUFSIZ)
return -EINVAL;
spi_message_init(&message); //初始化message
memset(x, 0, sizeof x);
if (n_tx) {
x[0].len = n_tx;
spi_message_add_tail(&x[0], &message); //将x[0]加入传输的message
}
if (n_rx) {
x[1].len = n_rx;
spi_message_add_tail(&x[1], &message); //将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[0]
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;
}
这个函数主要做了两件事一是分配好struct spi_message message; struct spi_transfer x[2]; 同时将发送的数据填充进去。另一件就是调用 spi_sync(spi, &message)函数实现的数据的收发。现在我们追踪一下spi_sync()函数。
int spi_sync(struct spi_device *spi, struct spi_message *message)
{
DECLARE_COMPLETION_ONSTACK(done); /*创建completion*/
int status;
message->complete = spi_complete; /*定义complete方法*/
message->context = &done; /*complete方法的参数*/
status = spi_async(spi, message); /*实现数据的收发*/
if (status == 0) {
wait_for_completion(&done); /*在bitbang_work中调用complete方法来唤醒*/
status = message->status;
}
message->context = NULL;
return status;
}
这个函数就中最重要的就是调用了spi_async(spi, message)函数,接下来我们继续追踪一下spi_async()这个函数。
spi_async(struct spi_device *spi, struct spi_message *message)
{
message->spi = spi;
return spi->master->transfer(spi, message);
}
上面这个函数调用了spi->master->transfer(spi, message)这个函数。但是spi->master->transfer(spi, message)是哪个函数呢。实际上它指向的是spi_bitbang_transfer函数。那它是如何发生关联的呢?之前我们提到过通过指针的相互赋值使
{
struct s3c24xx_spi *hw;
struct spi_master *master
struct spi_bitbang bitbang
}
这几个数据结构可以相互查找到对方。
(1)
在 s3c24xx_spi_probe(struct platform_device *pdev)函数中有
hw->master = spi_master_get(master);
hw->bitbang.master = hw->master;
(2)
在spi_bitbang_start(struct spi_bitbang *bitbang)
bitbang->master->transfer = spi_bitbang_transfer
(3)
spi_alloc_device(struct spi_master *master)函数中
spi->master = master;
整理以上关系可得 hw->bitbang.master = hw->master =spi->master=master;
所以 可有 bitbang->master->transfer = spi_bitbang_transfer
得到spi->master->transfer(spi, message) = spi_bitbang_transfer(spi, message)
step3:
接着我们继续追踪这个spi_bitbang_transfer(spi, message)函数
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); /*获取bitbang结构*/
spin_lock_irqsave(&bitbang->lock, flags);
if (!spi->max_speed_hz)
status = -ENETDOWN;
else {
list_add_tail(&m->queue, &bitbang->queue); /*将message添加到bitbang的queue链表中*/
queue_work(bitbang->workqueue, &bitbang->work); /*提交工作到工作队列*/
}
spin_unlock_irqrestore(&bitbang->lock, flags);
return status;
}
这个函数的主要是将message添加到bitbang的queue链表中和提交工作队列。工作和工作队列的初始化的工作在
spi_bitbang_start(struct spi_bitbang *bitbang)函数中完成。代码如下:
INIT_WORK(&bitbang->work, bitbang_work)
bitbang->workqueue = create_singlethread_workqueue(dev_name(bitbang->master->dev.parent))
所要当内核空闲的时候就会调用bitbang_work函数完成数据的收发。
step4:
接着我们继续追踪这个 bitbang_work函数做了什么工作。
static void bitbang_work(struct work_struct *work)
{
struct spi_bitbang *bitbang =
container_of(work, struct spi_bitbang, work); /*获取spi_bitbang*/
unsigned long flags;
spin_lock_irqsave(&bitbang->lock, flags);
bitbang->busy = 1;
while (!list_empty(&bitbang->queue)) { /*遍历bitbang->queue链表上的spi_message,进行数据收发*/
struct spi_message *m;
struct spi_device *spi;
unsigned nsecs;
struct spi_transfer *t = NULL;
unsigned tmp;
unsigned cs_change;
int status;
int (*setup_transfer)(struct spi_device *,
struct spi_transfer *);
m = container_of(bitbang->queue.next, struct spi_message, /*获取spi_message*/
queue);
list_del_init(&m->queue); /*将获取spi_message从bitbang->queue链表删去*/
spin_unlock_irqrestore(&bitbang->lock, flags);
nsecs = 100;
spi = m->spi;
tmp = 0;
cs_change = 1;
status = 0;
setup_transfer = NULL;
/*遍历,获取所有的spi_transfer*/
list_for_each_entry (t, &m->transfers, transfer_list) {
/* override or restore speed and wordsize */
if (t->speed_hz || t->bits_per_word) { /*如果这两个参数有任何一个已经设置了,本例中没有定义*/
setup_transfer = bitbang->setup_transfer;
if (!setup_transfer) {
status = -ENOPROTOOPT;
break;
}
}
if (setup_transfer) { /*本例中为NULL*/
status = setup_transfer(spi, t);
if (status < 0)
break;
}
/* 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) { /*初值为1*/
/*即调用s3c24xx_spi_chipsel,激活CS信号,写寄存器,设置SPI模式*/
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;
}
if (t->len) {
if (!m->is_dma_mapped)
t->rx_dma = t->tx_dma = 0; /*不使用DMA*/
status = bitbang->txrx_bufs(spi, t); /*即调用s3c24xx_spi_txrx,开始发送数据,status为已发送数据的大小*/
}
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) /*判断是否需要禁止CS,为1表示要求在两次数据传输之间禁止CS*/
continue;
if (t->transfer_list.next == &m->transfers) /*当message.queue链表上已没有transfer,表示所有的 transfer已传输完毕*/
break;
ndelay(nsecs);
bitbang->chipselect(spi, BITBANG_CS_INACTIVE); /*禁止CS*/
ndelay(nsecs);
} /*遍历spi_transfer结束*/
m->status = status;
m->complete(m->context); /*调用complete,一个message处理完毕*/
/* restore speed and wordsize */
if (setup_transfer)
setup_transfer(spi, NULL);
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->txrx_bufs(spi, t); 进行了数据的收发。
step5:
bitbang->txrx_bufs(spi, t)指向的是s3c24xx_spi_txrx()函数。继续追踪s3c24xx_spi_txrx()函数。
static int s3c24xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
{
struct s3c24xx_spi *hw = to_hw(spi);
dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n",
t->tx_buf, t->rx_buf, t->len);
hw->tx = t->tx_buf;
hw->rx = t->rx_buf;
hw->len = t->len;
hw->count = 0;
init_completion(&hw->done);
/* send the first byte */
writeb(hw_txbyte(hw, 0), hw->regs + S3C2410_SPTDAT); /*发送第一个数据,tx[0]*/
wait_for_completion(&hw->done);
return hw->count;
}
在s3c24xx_spi_txrx函数中,首先发送了待发送数据中的第一个字节,随后就调用wait_for_completion来等待剩余的数据发送完成。
NOTE:这里的completion是master驱动层的,spi设备驱动也有一个completion,用于IO同步,不要混淆。
当第一个数据发送完成以后,SPI中断产生,开始执行中断服务程序。在中断服务程序中,将判断是否需要读取数据,如果是则从寄存器中读取数据。
NOTE:如果是使用read系统调用,那么在此发送的数据将是0。
随后发送下一个数据,直到数据发送完成。发送完成后调用complete,使在s3c24xx_spi_txrx的wait_for_completion得以返回。接着,s3c24xx_spi_txrx就将返回已发送的字节数。
NOTE:其实该中断服务子程序实现了全双工数据的传输,只不过特定于具体的系统调用,从而分为了半双工读和写。
step6:
这里再将中断函数s3c24xx_spi_irq贴出。同时回答了上一将提出的问题,那就是中断函数何时别调用。好了一个spi驱动大致完成了。
static irqreturn_t s3c24xx_spi_irq(int irq, void *dev)
{
struct s3c24xx_spi *hw = dev;
unsigned int spsta = readb(hw->regs + S3C2410_SPSTA);
unsigned int count = hw->count;
if (spsta & S3C2410_SPSTA_DCOL) {
dev_dbg(hw->dev, "data-collision\n");
complete(&hw->done);
goto irq_done;
}
if (!(spsta & S3C2410_SPSTA_READY)) {
dev_dbg(hw->dev, "spi not ready for tx?\n");
complete(&hw->done);
goto irq_done;
}
hw->count++;
if (hw->rx)
hw->rx[count] = readb(hw->regs + S3C2410_SPRDAT);
count++;
if (count < hw->len)
writeb(hw_txbyte(hw, count), hw->regs + S3C2410_SPTDAT);
else
complete(&hw->done);
irq_done:
return IRQ_HANDLED;
}
注:本节大量引用和参考了博客http://blog.csdn.net/yj4231/article/details/7755709