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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM