linux设备驱动 spi详解5-应用到驱动的完整流程

所有的应用程序使用dev/目录下创建的设备,这些字符设备的操作函数集在文件spidev.c中实现。

 1 static const struct file_operations spidev_fops = {
 2     .owner =    THIS_MODULE,
 3     /* REVISIT switch to aio primitives, so that userspace
 4      * gets more complete API coverage. It'll simplify things
 5      * too, except for the locking.
 6      */
 7     .write =    spidev_write,
 8     .read =        spidev_read,
 9     .unlocked_ioctl = spidev_ioctl,
10     .open =        spidev_open,
11     .release =    spidev_release,
12 };

1 spidev_ioctl函数

以上是所有应用程序所能够做的所有操作,由此开始追踪spi 驱动程序的完整执行流程
其中,最重要的就是ioctl, 从这里开始先重点剖析ioctl函数 

  1 spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
  2 {
  3     int err = 0;
  4     int retval = 0;
  5     struct spidev_data *spidev;
  6     struct spi_device *spi;
  7     u32 tmp;
  8     unsigned n_ioc;
  9     struct spi_ioc_transfer *ioc;
 10     //ioctl cmd 检查
 11     /* Check type and command number */
 12     if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC)
 13         return -ENOTTY;
 14     
 15     /* Check access direction once here; don't repeat below.
 16      * IOC_DIR is from the user perspective, while access_ok is
 17      * from the kernel perspective; so they look reversed.
 18      */
 19     if (_IOC_DIR(cmd) & _IOC_READ)
 20         err = !access_ok(VERIFY_WRITE,
 21                 (void __user *)arg, _IOC_SIZE(cmd));
 22     if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE)
 23         err = !access_ok(VERIFY_READ,
 24                 (void __user *)arg, _IOC_SIZE(cmd));
 25     if (err)
 26         return -EFAULT;
 27 
 28     /* guard against device removal before, or while,
 29      * we issue this ioctl.
 30      */
 31     //通过以下方式获取spi_device-----spi(是之后操作的基础)
 32     spidev = filp->private_data;
 33     spin_lock_irq(&spidev->spi_lock);
 34     spi = spi_dev_get(spidev->spi);
 35     spin_unlock_irq(&spidev->spi_lock);
 36 
 37     if (spi == NULL)
 38         return -ESHUTDOWN;
 39 
 40     /* use the buffer lock here for triple duty:
 41      * - prevent I/O (from us) so calling spi_setup() is safe;
 42      * - prevent concurrent SPI_IOC_WR_* from morphing
 43      * data fields while SPI_IOC_RD_* reads them;
 44      * - SPI_IOC_MESSAGE needs the buffer locked "normally".
 45      */
 46     mutex_lock(&spidev->buf_lock);
 47     //以上是进行check,检查命令有效性,以及进行初始化数据,这里不在多做说明
 48     switch (cmd) {
 49     /* read requests */
 50     case SPI_IOC_RD_MODE://获取模式信息,将信息发送给用户
 51         retval = __put_user(spi->mode & SPI_MODE_MASK,
 52                     (__u8 __user *)arg);
 53         break;
 54     case SPI_IOC_RD_LSB_FIRST://获取spi最低有效位
 55         retval = __put_user((spi->mode & SPI_LSB_FIRST) ? 1 : 0,
 56                     (__u8 __user *)arg);
 57         break;
 58     case SPI_IOC_RD_BITS_PER_WORD:
 59         retval = __put_user(spi->bits_per_word, (__u8 __user *)arg);
 60         break;
 61     case SPI_IOC_RD_MAX_SPEED_HZ:
 62         retval = __put_user(spi->max_speed_hz, (__u32 __user *)arg);
 63         break;
 64 
 65     /* write requests */
 66     case SPI_IOC_WR_MODE://设置数据传输模式,这里只是把设置的数据保存在spi 中,但并没有对spi device做任何操作,对spi device的操作一并在最后进行
 67         retval = __get_user(tmp, (u8 __user *)arg);
 68         if (retval == 0) {
 69             u8 save = spi->mode;
 70 
 71             if (tmp & ~SPI_MODE_MASK) {
 72                 retval = -EINVAL;
 73                 break;
 74             }
 75 
 76             tmp |= spi->mode & ~SPI_MODE_MASK;
 77             spi->mode = (u8)tmp;
 78             retval = spi_setup(spi);
 79             if (retval < 0)
 80                 spi->mode = save;
 81             else
 82                 dev_dbg(&spi->dev, "spi mode %02xn", tmp);
 83         }
 84         break;
 85     case SPI_IOC_WR_LSB_FIRST://设置设置spi写最低有效位,同上
 86         retval = __get_user(tmp, (__u8 __user *)arg);
 87         if (retval == 0) {
 88             u8 save = spi->mode;
 89 
 90             if (tmp)
 91                 spi->mode |= SPI_LSB_FIRST;
 92             else
 93                 spi->mode &= ~SPI_LSB_FIRST;
 94             retval = spi_setup(spi);
 95             if (retval < 0)
 96                 spi->mode = save;
 97             else
 98                 dev_dbg(&spi->dev, "%csb firstn",
 99                         tmp ? 'l' : 'm');
100         }
101         break;
102     case SPI_IOC_WR_BITS_PER_WORD://设置spi写每个字含多个个位,同上
103         retval = __get_user(tmp, (__u8 __user *)arg);
104         if (retval == 0) {
105             u8 save = spi->bits_per_word;
106 
107             spi->bits_per_word = tmp;
108             retval = spi_setup(spi);
109             if (retval < 0)
110                 spi->bits_per_word = save;
111             else
112                 dev_dbg(&spi->dev, "%d bits per wordn", tmp);
113         }
114         break;
115     case SPI_IOC_WR_MAX_SPEED_HZ://设置spi写最大速率,同上
116         retval = __get_user(tmp, (__u32 __user *)arg);
117         if (retval == 0) {
118             u32 save = spi->max_speed_hz;
119 
120             spi->max_speed_hz = tmp;
121             retval = spi_setup(spi);
122             if (retval < 0)
123                 spi->max_speed_hz = save;
124             else
125                 dev_dbg(&spi->dev, "%d Hz (max)n", tmp);
126         }
127         break;
128 
129     default:
130         /* segmented and/or full-duplex I/O request */
131         if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0))//查看是否为数据write命令
132                 || _IOC_DIR(cmd) != _IOC_WRITE) {
133             retval = -ENOTTY;
134             break;
135         }
136         //pay more time on understanding below method
137         tmp = _IOC_SIZE(cmd);//从命令参数中解析出用户数据大小
138         if ((tmp % sizeof(struct spi_ioc_transfer)) != 0) {//数据大小必须是struct spi_ioc_transfer的整数倍
139             retval = -EINVAL;
140             break;
141         }
142         n_ioc = tmp / sizeof(struct spi_ioc_transfer);//将要传输的数据分成n个传输数据段
143         if (n_ioc == 0)
144             break;
145 
146         /* copy into scratch area */
147         ioc = kmalloc(tmp, GFP_KERNEL);//获取n个数据段的数据管理结构体的内存空间
148         if (!ioc) {
149             retval = -ENOMEM;
150             break;
151         }
152         if (__copy_from_user(ioc, (void __user *)arg, tmp)) {//从用户空间获取数据管理结构体的初始化值
153             kfree(ioc);
154             retval = -EFAULT;
155             break;
156         }
157 
158         /* translate to spi_message, execute */
159         retval = spidev_message(spidev, ioc, n_ioc);//数据传输,这是整个流程中的核心
160         kfree(ioc);
161         break;
162     }
163 
164     mutex_unlock(&spidev->buf_lock);
165     spi_dev_put(spi);
166     return retval;
167 }

通过调用函数spi->master->setup()来设置SPI模式。

1 static inline int
2 spi_setup(struct spi_device *spi)
3 {
4  return spi->master->setup(spi);
5 }

2 set_up函数

master->setup成员被初始化成函数s3c24xx_spi_setup()。这一工作是在函数s3c24xx_spi_probe()中进行的

hw->bitbang.master->setup  = s3c24xx_spi_setup;

函数s3c24xx_spi_setup()是在文件linux/drivers/spi/spi_s3c24xx.c中实现的。

 1 static int s3c24xx_spi_setup(struct spi_device *spi)
 2 {
 3     struct s3c24xx_spi_devstate *cs = spi->controller_state;
 4     struct s3c24xx_spi *hw = to_hw(spi);
 5     int ret;
 6 
 7     /* allocate settings on the first call */
 8     if (!cs) {
 9         cs = kzalloc(sizeof(struct s3c24xx_spi_devstate), GFP_KERNEL);
10         if (!cs) {
11             dev_err(&spi->dev, "no memory for controller staten");
12             return -ENOMEM;
13         }
14 
15         cs->spcon = SPCON_DEFAULT;
16         cs->hz = -1;
17         spi->controller_state = cs;
18     }
19 
20     /* initialise the state from the device */
21     ret = s3c24xx_spi_update_state(spi, NULL);
22     if (ret)
23         return ret;
24 
25     spin_lock(&hw->bitbang.lock);
26     //bitbang包含了数据传输函数,在数据传输时忙碌标识bitbang.busy置1,也就是在数据传输过程中不能改变数据传输模式。
27     if (!hw->bitbang.busy) {
28         hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE);
29         /* need to ndelay for 0.5 clocktick ? */
30     }
31     spin_unlock(&hw->bitbang.lock);
32 
33     return 0;
34 }

函数s3c24xx_spi_update_state定义如下:

 1 static int s3c24xx_spi_update_state(struct spi_device *spi,
 2                  struct spi_transfer *t)
 3 {
 4     struct s3c24xx_spi *hw = to_hw(spi);
 5     struct s3c24xx_spi_devstate *cs = spi->controller_state;
 6     unsigned int bpw;
 7     unsigned int hz;
 8     unsigned int div;
 9     unsigned long clk;
10 
11     bpw = t ? t->bits_per_word : spi->bits_per_word;
12     hz = t ? t->speed_hz : spi->max_speed_hz;
13 
14     if (!bpw)
15         bpw = 8;
16 
17     if (!hz)
18         hz = spi->max_speed_hz;
19 
20     if (bpw != 8) {
21         dev_err(&spi->dev, "invalid bits-per-word (%d)n", bpw);
22         return -EINVAL;
23     }
24 
25     if (spi->mode != cs->mode) {
26         u8 spcon = SPCON_DEFAULT;
27 
28         if (spi->mode & SPI_CPHA)
29             spcon |= S3C2410_SPCON_CPHA_FMTB;
30 
31         if (spi->mode & SPI_CPOL)
32             spcon |= S3C2410_SPCON_CPOL_HIGH;
33 
34         cs->mode = spi->mode;
35         cs->spcon = spcon;
36     }
37 
38     if (cs->hz != hz) {
39         clk = clk_get_rate(hw->clk);
40         div = DIV_ROUND_UP(clk, hz * 2) - 1;
41 
42         if (div > 255)
43             div = 255;
44 
45         dev_dbg(&spi->dev, "pre-scaler=%d (wanted %d, got %ld)n",
46             div, hz, clk / (2 * (div + 1)));
47 
48         cs->hz = hz;
49         cs->sppre = div;
50     }
51 
52     return 0;
53 }

s3c24xx_spi_update_state 方法对设置项做了以下初始化和检查,并未做任何的有关于硬件的任何操作,
所有对硬件的设置是通过s3c24xx_spi_probe中填充好的s3c24xx_spi_chipsel方法实现的

 1 static int s3c24xx_spi_probe(struct platform_device *pdev)
 2 {
 3   ...
 4 /* setup the state for the bitbang driver */
 5 
 6     hw->bitbang.master = hw->master;
 7     hw->bitbang.setup_transfer = s3c24xx_spi_setupxfer;
 8     hw->bitbang.chipselect = s3c24xx_spi_chipsel;
 9     hw->bitbang.txrx_bufs = s3c24xx_spi_txrx;
10 
11     hw->master->setup = s3c24xx_spi_setup;
12     hw->master->cleanup = s3c24xx_spi_cleanup;
13   ...
14 }

下面看一下这个方法的具体实现过程:

 1 static void s3c24xx_spi_chipsel(struct spi_device *spi, int value)
 2 {
 3     struct s3c24xx_spi_devstate *cs = spi->controller_state;
 4     struct s3c24xx_spi *hw = to_hw(spi);
 5     unsigned int cspol = spi->mode & SPI_CS_HIGH ? 1 : 0;
 6 
 7     /* change the chipselect state and the state of the spi engine clock */
 8 
 9     switch (value) {
10     case BITBANG_CS_INACTIVE:
11         hw->set_cs(hw->pdata, spi->chip_select, cspol^1);
12         writeb(cs->spcon, hw->regs + S3C2410_SPCON);
13         break;
14 
15     case BITBANG_CS_ACTIVE:
16         writeb(cs->spcon | S3C2410_SPCON_ENSCK,
17         hw->regs + S3C2410_SPCON);
18         hw->set_cs(hw->pdata, spi->chip_select, cspol);
19         break;
20     }
21 }

上面对本函数的调用传递的参数是BITBANG_CS_INACTIVE。可以看出上层函数对数据传输模式的设置,

只能改变spi->mode字段,而不能通过函数spi->master->setup(spi);的调用而将要设置的传输模式写入硬件。

这或许是linux中的SPI子系统还不够完善吧。但spi->mode的值最终是会被写入SPI的控制寄存器中的,

hw->bitbang.chipselect(spi, BITBANG_CS_ACTIVE);  的时候。在后面会遇到,这里是在s3c24xx_spi_probe 方法中填充的

3 spidev_message函数

在iotcl中, 除了(1) 中讲到的设置项,以下便是重点中的重点
retval = spidev_message(spidev, ioc, n_ioc);//数据传输

 1 static int spidev_message(struct spidev_data *spidev,
 2         struct spi_ioc_transfer *u_xfers, unsigned n_xfers)
 3 {
 4     struct spi_message    msg;
 5     struct spi_transfer    *k_xfers;
 6     struct spi_transfer    *k_tmp;
 7     struct spi_ioc_transfer *u_tmp;
 8     unsigned        n, total;
 9     u8            *buf;
10     int            status = -EFAULT;
11 
12     spi_message_init(&msg);
13     k_xfers = kcalloc(n_xfers, sizeof(*k_tmp), GFP_KERNEL);//每个 spi_transfer代表一段要传输的数据
14     if (k_xfers == NULL)
15         return -ENOMEM;
16 
17     /* Construct spi_message, copying any tx data to bounce buffer.
18      * We walk the array of user-provided transfers, using each one
19      * to initialize a kernel version of the same transfer.
20      */
21     buf = spidev->buffer;
22     total = 0;
23     for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers;
24             n;
25             n--, k_tmp++, u_tmp++) {
26         k_tmp->len = u_tmp->len;
27         //将要传输的数据分成n个数据段每个数据段用一个spi_transfer管理,u_xfers为用户空间传来的数据段
28         total += k_tmp->len;//要传输的数据总量
29         if (total > bufsiz) {
30             status = -EMSGSIZE;
31             goto done;
32         }
33 
34         if (u_tmp->rx_buf) {//需要接收则分给一段用于接收数据的内存
35             k_tmp->rx_buf = buf;
36             if (!access_ok(VERIFY_WRITE, (u8 __user *)
37                         (uintptr_t) u_tmp->rx_buf,
38                         u_tmp->len))
39                 goto done;
40         }
41         if (u_tmp->tx_buf) {
42             k_tmp->tx_buf = buf;
43             if (copy_from_user(buf, (const u8 __user *)
44                         (uintptr_t) u_tmp->tx_buf,
45                     u_tmp->len))
46                 goto done;
47         }
48         buf += k_tmp->len;//指向下一段内存
49 
50         k_tmp->cs_change = !!u_tmp->cs_change;//双非操作取其逻辑值
51         k_tmp->bits_per_word = u_tmp->bits_per_word;
52         k_tmp->delay_usecs = u_tmp->delay_usecs;//一段数据的完全传输需要一定时间的等待
53         k_tmp->speed_hz = u_tmp->speed_hz;
54 #ifdef VERBOSE
55         dev_dbg(&spi->dev,
56             " xfer len %zd %s%s%s%dbits %u usec %uHzn",
57             u_tmp->len,
58             u_tmp->rx_buf ? "rx " : "",
59             u_tmp->tx_buf ? "tx " : "",
60             u_tmp->cs_change ? "cs " : "",
61             u_tmp->bits_per_word ? : spi->bits_per_word,
62             u_tmp->delay_usecs,
63             u_tmp->speed_hz ? : spi->max_speed_hz);
64 #endif
65         spi_message_add_tail(k_tmp, &msg);//将用于数据传输的数据段挂在msg上
66     }
67 
68     status = spidev_sync(spidev, &msg);//调用底层函数进行数据传输
69     if (status < 0)
70         goto done;
71 
72     /* copy any rx data out of bounce buffer */
73     buf = spidev->buffer;
74     for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) {
75         if (u_tmp->rx_buf) {
76             if (__copy_to_user((u8 __user *)
77                     (uintptr_t) u_tmp->rx_buf, buf,
78                     u_tmp->len)) {//分段向用户空间传输数据
79                 status = -EFAULT;
80                 goto done;
81             }
82         }
83         buf += u_tmp->len;
84     }
85     status = total;
86 
87 done:
88     kfree(k_xfers);
89     return status;
90 }

spidev_sync定义如下:

 1 static ssize_t
 2 spidev_sync(struct spidev_data *spidev, struct spi_message *message)
 3 {
 4     DECLARE_COMPLETION_ONSTACK(done);
 5     int status;
 6 
 7     message->complete = spidev_complete;
 8     message->context = &done;//在底层的数据传输函数中会调用函数spidev_complete来通知数据传输完成,在此留一标记
 9 
10     spin_lock_irq(&spidev->spi_lock);
11     if (spidev->spi == NULL)
12         status = -ESHUTDOWN;
13     else
14         status = spi_async(spidev->spi, message);
15     spin_unlock_irq(&spidev->spi_lock);
16 
17     if (status == 0) {
18         wait_for_completion(&done); //等待数据完成
19         status = message->status;
20         if (status == 0)
21             status = message->actual_length;
22     }
23     return status;
24 }

函数spi_async定义如下:

 1 int spi_async(struct spi_device *spi, struct spi_message *message)
 2 {
 3     struct spi_master *master = spi->master;
 4 
 5     /* Half-duplex links include original MicroWire, and ones with
 6      * only one data pin like SPI_3WIRE (switches direction) or where
 7      * either MOSI or MISO is missing. They can also be caused by
 8      * software limitations.
 9      */
10     if ((master->flags & SPI_MASTER_HALF_DUPLEX)
11             || (spi->mode & SPI_3WIRE)) {
12         struct spi_transfer *xfer;
13         unsigned flags = master->flags;
14 
15         list_for_each_entry(xfer, &message->transfers, transfer_list) {
16             if (xfer->rx_buf && xfer->tx_buf)
17                 return -EINVAL;
18             if ((flags & SPI_MASTER_NO_TX) && xfer->tx_buf)
19                 return -EINVAL;
20             if ((flags & SPI_MASTER_NO_RX) && xfer->rx_buf)
21                 return -EINVAL;
22         }
23     }
24 
25     message->spi = spi;
26     message->status = -EINPROGRESS;
27     return master->transfer(spi, message);
28 }
29 EXPORT_SYMBOL_GPL(spi_async);

函数spi->master->transfer()在函数spi_bitbang_start()中被初始化为函数spi_bitbang_transfer()如下

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

4 spi主机的transfer函数

函数spi_bitbang_transfer()又在函数s3c24xx_spi_probe()中被调用。

函数spi_bitbang_transfer()在文件spi_bitbang.c中实现。

 1 int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m)
 2 {
 3     struct spi_bitbang    *bitbang;
 4     unsigned long        flags;
 5     int            status = 0;
 6 
 7     m->actual_length = 0;
 8     m->status = -EINPROGRESS;
 9 
10     bitbang = spi_master_get_devdata(spi->master);
11 
12     spin_lock_irqsave(&bitbang->lock, flags);
13     if (!spi->max_speed_hz)
14         status = -ENETDOWN;
15     else {  
16         //将携带数据的结构体spi_message挂到bitbang->queue上。每一次数据传输都将要传输的数据包装成结构体spi_message传递
17         list_add_tail(&m->queue, &bitbang->queue);
18         //将该传输任务添加到工作队列头bitbang->workqueue。接下来将调用任务处理函数进一步数据处理。
19         queue_work(bitbang->workqueue, &bitbang->work);
20     }
21     spin_unlock_irqrestore(&bitbang->lock, flags);
22 
23     return status;
24 }
25 EXPORT_SYMBOL_GPL(spi_bitbang_transfer);

在此不得不讨论一下结构体,这是一个完成数据传输的重要结构体。

 1 struct spi_bitbang {
 2  struct workqueue_struct *workqueue; //工作队列头。
 3  struct work_struct work; //每一次数据传输都传递下来一个spi_message,都向工作队列头添加一个任务。
 4   ...
 5 //挂接spi_message,如果上一次的spi_message还没处理完接下来的spi_message就挂接在 queue上等待处理。
 6  struct list_head queue; 
 7  u8   busy;  //忙碌标识。
 8   ...
 9 
10  struct spi_master *master;
11 
12  // 以下三个函数都是在函数s3c24xx_spi_probe()中被初始化的。
13 
14  int (*setup_transfer)(struct spi_device *spi,struct spi_transfer *t);  //设置数据传输波特率
15 
16  void (*chipselect)(struct spi_device *spi, int is_on);  //将数据传输模式写入控制寄存器。
17 
18  //向SPTDAT中写入要传输的第一个数据,数据传输是通过中断方式完成的,只要进行一次中断触发,以后向SPTDAT中写数据
19 
20  //的工作就在中断处理函数中进行。
21 
22  int (*txrx_bufs)(struct spi_device *spi, struct spi_transfer *t); 
23   ...
24 };

数据传输是SPI接口的任务,结构体master代表了一个接口,当一个spi_message从上层函数传递下来时,

master的成员函数bitbang->master->transfer将该数据传输任务添加到工作队列头。

queue_work(bitbang->workqueue, &bitbang->work);

函数bitbang->master->transfer()在上面已经讲解。

工作队列struct workqueue_struct *workqueue;的创建和 struct work_struct work的初始化都是在函数

spi_bitbang_start()中进行的。

INIT_WORK(&bitbang->work, bitbang_work); //bitbang_work是任务处理函数

bitbang->workqueue = create_singlethread_workqueue(dev_name(bitbang->master->dev.parent));

任务处理函数如下:

  1 static void bitbang_work(struct work_struct *work)
  2 {
  3     struct spi_bitbang    *bitbang =
  4         container_of(work, struct spi_bitbang, work);
  5     unsigned long        flags;
  6     int            do_setup = -1;
  7     int            (*setup_transfer)(struct spi_device *,
  8                     struct spi_transfer *);
  9 
 10     setup_transfer = bitbang->setup_transfer;
 11 
 12     spin_lock_irqsave(&bitbang->lock, flags);
 13     bitbang->busy = 1;
 14     while (!list_empty(&bitbang->queue)) {
 15         struct spi_message    *m;
 16         struct spi_device    *spi;
 17         unsigned        nsecs;
 18         struct spi_transfer    *t = NULL;
 19         unsigned        tmp;
 20         unsigned        cs_change;
 21         int            status;
 22 
 23         m = container_of(bitbang->queue.next, struct spi_message,
 24                 queue);
 25         list_del_init(&m->queue);
 26         spin_unlock_irqrestore(&bitbang->lock, flags);
 27 
 28         /* FIXME this is made-up ... the correct value is known to
 29          * word-at-a-time bitbang code, and presumably chipselect()
 30          * should enforce these requirements too?
 31          */
 32         nsecs = 100;
 33 
 34         spi = m->spi;
 35         tmp = 0;
 36         cs_change = 1;
 37         status = 0;
 38 
 39         list_for_each_entry (t, &m->transfers, transfer_list) {
 40 
 41             /* override speed or wordsize? */
 42             if (t->speed_hz || t->bits_per_word)
 43                 do_setup = 1;
 44 
 45             /* init (-1) or override (1) transfer params */
 46             if (do_setup != 0) {
 47                 if (!setup_transfer) {
 48                     status = -ENOPROTOOPT;
 49                     break;
 50                 }
 51                 status = setup_transfer(spi, t);
 52                 if (status < 0)
 53                     break;
 54             }
 55 
 56             /* set up default clock polarity, and activate chip;
 57              * this implicitly updates clock and spi modes as
 58              * previously recorded for this device via setup().
 59              * (and also deselects any other chip that might be
 60              * selected ...)
 61              */
 62             if (cs_change) {
 63                 //多段数据传输时只需第一段数据传输时调用以下模式设置,将spi->mode
 64                             //写入SPI的模式控制寄存器。并调用函数hw->set_cs,片选设置
 65                             //在函数讲解函数spidev_ioctl()中的模式设置时讲到过。在那里  调用的函数chipselect(spi, BITBANG_CS_INACTIVE);
 66                             //传递的传输是BITBANG_CS_INACTIVE是不能将数据传输模式spi->mode写入SPI控制寄存器的,不过在那里设置了spi->mode的值。
 67                 bitbang->chipselect(spi, BITBANG_CS_ACTIVE);
 68                 ndelay(nsecs);
 69             }
 70             cs_change = t->cs_change;
 71             if (!t->tx_buf && !t->rx_buf && t->len) {
 72                 status = -EINVAL;
 73                 break;
 74             }
 75 
 76             /* transfer data. the lower level code handles any
 77              * new dma mappings it needs. our caller always gave
 78              * us dma-safe buffers.
 79              */
 80             if (t->len) {
 81                 /* REVISIT dma API still needs a designated
 82                  * DMA_ADDR_INVALID; ~0 might be better.
 83                  */
 84                 if (!m->is_dma_mapped)
 85                     t->rx_dma = t->tx_dma = 0;
 86                 status = bitbang->txrx_bufs(spi, t);
 87             }
 88             if (status > 0)
 89                 m->actual_length += status;
 90             if (status != t->len) {
 91                 /* always report some kind of error */
 92                 if (status >= 0)
 93                     status = -EREMOTEIO;
 94                 break;
 95             }
 96             status = 0;
 97 
 98             /* protocol tweaks before next transfer */
 99             if (t->delay_usecs)//延时等待一段数据传输完,因为一段数据要经过多次中断传输
100                 udelay(t->delay_usecs);
101 
102             if (!cs_change)//多段数据传输时t->cs_change为0表示下面还有未传输数据否者判断遍历是否结束
103                 continue;
104             if (t->transfer_list.next == &m->transfers)
105                 break;
106 
107             /* sometimes a short mid-message deselect of the chip
108              * may be needed to terminate a mode or command
109              */
110             ndelay(nsecs);
111             bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
112             ndelay(nsecs);
113         }
114 
115         m->status = status;
116         m->complete(m->context);// 通知一次数据传输完
117 
118         /* restore speed and wordsize if it was overridden */
119         if (do_setup == 1)
120             setup_transfer(spi, NULL);
121         do_setup = 0;
122 
123         /* normally deactivate chipselect ... unless no error and
124          * cs_change has hinted that the next message will probably
125          * be for this chip too.
126          */
127         if (!(status == 0 && cs_change)) {
128             ndelay(nsecs);
129             bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
130             ndelay(nsecs);
131         }
132 
133         spin_lock_irqsave(&bitbang->lock, flags);
134     }
135     bitbang->busy = 0;
136     spin_unlock_irqrestore(&bitbang->lock, flags);
137 }

s3c24xx_spi_txrx定义如下:

 1 static int s3c24xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
 2 {
 3     struct s3c24xx_spi *hw = to_hw(spi);
 4 
 5     dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %dn",
 6         t->tx_buf, t->rx_buf, t->len);
 7 
 8     hw->tx = t->tx_buf;
 9     hw->rx = t->rx_buf;
10     hw->len = t->len;
11     hw->count = 0;
12 
13     init_completion(&hw->done);
14 
15     /* send the first byte */
16     writeb(hw_txbyte(hw, 0), hw->regs + S3C2410_SPTDAT);
17 
18     wait_for_completion(&hw->done);
19 
20     return hw->count;
21 }

函数hw_txbyte()的实现如下:

1 static inline unsigned int hw_txbyte(struct s3c24xx_spi *hw, int count)
2 {
3 return hw->tx ? hw->tx[count] : 0;
4 }

将要传输的数据段的第一个数据写入SPI数据寄存器S3C2410_SPTDAT。即便是数据接收也得向数据寄存器写入数据才能触发一次数据的传输。只需将该数据段的第一个数据写入数据寄存器就可以触发数据传输结束中断,以后的数据就在中断处理函数中写入数据寄存器。

数据传输中断:

 1 static irqreturn_t s3c24xx_spi_irq(int irq, void *dev)
 2 {
 3     struct s3c24xx_spi *hw = dev;
 4     unsigned int spsta = readb(hw->regs + S3C2410_SPSTA);
 5     unsigned int count = hw->count;
 6 
 7     if (spsta & S3C2410_SPSTA_DCOL) {
 8         dev_dbg(hw->dev, "data-collisionn");
 9         complete(&hw->done);
10         goto irq_done;
11     }
12 
13     if (!(spsta & S3C2410_SPSTA_READY)) {//数据准备好
14         dev_dbg(hw->dev, "spi not ready for tx?n");
15         complete(&hw->done);
16         goto irq_done;
17     }
18 
19     hw->count++;
20 
21     if (hw->rx)
22         hw->rx[count] = readb(hw->regs + S3C2410_SPRDAT);//接收数据
23 
24     count++;
25 
26     if (count < hw->len)
27         writeb(hw_txbyte(hw, count), hw->regs + S3C2410_SPTDAT);//写入数据
28     else
29         complete(&hw->done);
30 
31  irq_done:
32     return IRQ_HANDLED;
33 }

总结一下:
spi的读写请求通过:
spi_transfer->spi_message->spi_bitbang添加都bitbang->queue中,被bitbang->work反方向提取出来执行(后面会提到)。
通过queue_work(bitbang->workqueue, &bitbang->work)把bitbang-work加入bitbang->workqueue后,在某个合适的时间, bitbang->work将被调度运行,bitbang_work函数将被调用

参考博文:http://dainh.blog.chinaunix.net/uid-26765074-id-3510913.html

posted @ 2020-06-04 22:12  Action_er  阅读(3412)  评论(0编辑  收藏  举报