2012-01-08 22:11:38數據結構
目的:我須要掌握spi驅動相關數據結構關係,及在哪部分函數中把這些數值進行底層寄存器賦值的。結合應用層函數完成spi驅動的代碼測試。已達到靈活修改的目的。app
按順序看probe函數中async
if (!pdata->set_cs)ide
則 hw->set_cs = s3c24xx_spi_gpiocs;函數
gpio_direction_output(pdata->pin_cs, 1);測試
因爲個人platform_device.platform_data沒設置set_cs。默認設置gpio片選。而且把pin_cs腳設置爲輸出。接着指針
s3c24xx_spi_initialsetup(hw);函數裏面有設置寄存器操做,設置默認值,代碼以下:調試
/* for the moment, permanently enable the clock */rest
clk_enable(hw->clk);orm
/* program defaults into the registers */
writeb(0xff, hw->regs + S3C2410_SPPRE);
writeb(SPPIN_DEFAULT, hw->regs + S3C2410_SPPIN);
writeb(SPCON_DEFAULT, hw->regs + S3C2410_SPCON);
再接着就是spi_add_device函數中調用s3c24xx_spi_setup,裏面有設置寄存器。
if (!spi->bits_per_word)
spi->bits_per_word = 8;
因爲個人spi->bits_per_word以前都沒有定義過。因此爲0,那麼默認設置spi->bits_per_word = 8;
接着調用s3c24xx_spi_setupxfer函數第一句就是struct s3c24xx_spi *hw = to_hw(spi);分析一下。
仔細看了下to_hw就是說spi把spi_device結構轉換爲s3c24xx_spi結構。
方法就是spi(spi_device結構)先指向父指針master(spi_master結構)。
接着就是指向dev(spi_master的device成員),再接着指向driver_data(device結構的driver_data成員)爲何說這就是s3c24xx_spi的類型哪?看probe一開始的幾句代碼便可。
struct s3c24xx_spi *hw;
hw = spi_master_get_devdata(master);
memset(hw, 0, sizeof(struct s3c24xx_spi));
接着回到s3c24xx_spi_setupxfer函數下面的代碼是
bpw = t ? t->bits_per_word : spi->bits_per_word;
hz = t ? t->speed_hz : spi->max_speed_hz;
因爲t傳進來是NULL,因此bpw= spi->bits_per_word;剛纔分析過了s3c24xx_spi_setup中把它設置爲默認值8。hz = spi->max_speed_hz;在spi_add_device函數以前的spi_new_device有賦值proxy->max_speed_hz = chip->max_speed_hz;就是spi_board_info裏的賦值,我本身設置的值。至於要寫入寄存器是在接下來的hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE)中調用hw->set_cs(hw->pdata, spi->chip_select, cspol^1);(probe中hw->set_cs = s3c24xx_spi_gpiocs裏定義的) s3c24xx_spi_gpiocs函數,設置cspol值爲0。
此函數也調用div = clk_get_rate(hw->clk) / hz;設置波特率寄存器。
===========================================================bitbang_work函數中有調用bitbang->chipselect(spi, BITBANG_CS_ACTIVE);
s3c24xx_spi_probe中有定義 hw->bitbang.chipselect = s3c24xx_spi_chipsel;
s3c24xx_spi_chipsel函數裏面有設置spi模式。數據來源是spi->mode。spi->mode又是在那裏賦值的呢?帶着問題作了以下探索
bitbang_work是在spi_bitbang_start中調用。
s3c24xx_spi_probe->spi_bitbang_start->bitbang_work但此時,spi-mode並無賦值。
賦值是在哪裏呢?換個方法,按順序查找。
s3c24xx_spi_probe->spi_bitbang_start->spi_register_master->scan_boardinfo->spi_new_device經過從頭至尾的方式查找,惟一首先出現spi_master與spi_device關係的是spi_new_device函數。進入其中調用的spi_alloc_device函數,查看註釋發現。
* Caller is responsible to call spi_add_device() on the returned
* spi_device structure to add it to the SPI master.
能夠肯定,spi->mode的首次賦值就是詞句代碼
proxy->mode = chip->mode;在bitbang_work函數中spi-mode並無賦值可是還在用是爲何呢?再仔細看代碼,原來while有個判斷條件。以前沒看到,搜索錯了方向。
在spi_new_device函數中proxy是spi_device結構。Spi->mode等都是在以下這裏賦值
proxy->chip_select = chip->chip_select;
proxy->max_speed_hz = chip->max_speed_hz;
proxy->mode = chip->mode; //s3c2410_spi1_board中沒定義,則默認爲0
proxy->irq = chip->irq;
strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias));
proxy->dev.platform_data = (void *) chip->platform_data;
proxy->controller_data = chip->controller_data;
proxy->controller_state = NULL;
========================
接着就是spi_add_device函數,裏面有一句if (spi->chip_select >= spi->master->num_chipselect) 他們分別是什麼值呢?spi->master->num_chipselect在哪裏?帶着問題,開始了以下探索歷程
spi->chip_select在spi_board_info s3c2410_spi1_board[]結構賦值中爲0。
static struct spi_board_info s3c2410_spi1_board[] = {
[0] = {
.modalias = "spidev",
.bus_num = 1, .chip_select = 0,
.irq = IRQ_EINT9,
.max_speed_hz = 2000*1000,
},
};
在scan_boardinfo 中調用函數時候傳遞的參數是(void) spi_new_device(master, chip);master是spi_master結構。再以前的spi_register_master函數中有對spi_master的num_chipselect成員賦值的核對。代碼以下:
if (master->num_chipselect == 0)
return -EINVAL;再往前找應該就能找到賦值了。
spi_bitbang_start中有對spi_register_master的調用。代碼以下:
status = spi_register_master(bitbang->master);
再往前看。s3c24xx_spi_probe函數中調用spi_bitbang_start,往上看到了master->num_chipselect的賦值語句了。代碼以下:
master->num_chipselect = hw->pdata->num_cs;
而hw->pdata = pdata = pdev->dev.platform_data;
而struct platform_device *pdev是platform_device中的platform_data結構,已經賦值了以下
static struct s3c2410_spi_info s3c2410_spi1_platdata = {
.pin_cs = S3C2410_GPG3,
.num_cs = 1,
.bus_num = 1,
};
因此chip_select= 0, spi->master->num_chipselect值爲1.
經過倒序來找,從spi_add_device一直找到了s3c24xx_spi_probe,按順序寫下:
s3c24xx_spi_probe->spi_bitbang_start->spi_register_master->scan_boardinfo->spi_new_device->spi_add_device
一個接口對應一個master,一個master對應一條SPI總線,一條總線上可能掛有多個設備,num_chipselect 就表示該總線上的設備, chip_select表示該SPI設備在該條SPI總線上的設備號的惟一標識。
====================================================probe中函數綁定與調用分析
hw->bitbang.master = hw->master;
hw->bitbang.setup_transfer = s3c24xx_spi_setupxfer;// s3c24xx_spi_setup中調用ret = s3c24xx_spi_setupxfer(spi, NULL);
hw->bitbang.chipselect = s3c24xx_spi_chipsel;//s3c24xx_spi_setupxfer中調用hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE);
hw->bitbang.txrx_bufs = s3c24xx_spi_txrx;// bitbang_work中調用status = bitbang->txrx_bufs(spi, t);
hw->bitbang.master->setup = s3c24xx_spi_setup;// spi_add_device中調用status = spi->master->setup(spi);
按probe初始化順序,則spi_add_device函數中調用
status = spi->master->setup(spi);//(s3c24xx_spi_setup)
接着s3c24xx_spi_setup函數中調用
ret = s3c24xx_spi_setupxfer(spi, NULL);
接着s3c24xx_spi_setupxfer函數中調用
hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE)
關於如上圖的問題,怎麼HZ數一開始不是我默認設置的呢?原來是由於,用戶層函數調用的時候先是從octl函數開始的不是從probe函數開始的。
probe函數打印出來的信息徹底正確。以下圖:
先調用spidev_message如何調用到bitbang_work的?
spi_bitbang_start->bitbang_work接着就沒方向了,不可能到spidev_message了。因而查了網上的資料,是spi_bitbang_transfer 中的代碼以下:queue_work(bitbang->workqueue, &bitbang->work); 調用了bitbang_work函數。爲何bitbang->work指示的就是bitbang_work函數呢?原來在 spi_bitbang_start函數中的第一句代碼INIT_WORK(&bitbang->work, bitbang_work);就說明了。好了,這樣就有方向繼續摸索了。關係流程以下:
spidev_message ->spidev_sync->spi_async【spi->master->transfer(spi, message); 定義在spi_bitbang_start函數中bitbang->master->transfer = spi_bitbang_transfer;】 -> spi_bitbang_transfer->bitbang_work
===============================================================
bitbang_work函數中有句代碼
setup_transfer = bitbang->setup_transfer;
if (setup_transfer) {
status = setup_transfer(spi, t);
bitbang->setup_transfer(spi, t)又是調用哪一個具體函數呢?
很面熟,想起來以前好像看到過在bitbang相關函數中,因而找到了spi_bitbang_start函數中有,代碼以下:
if (!bitbang->master->setup) {
if (!bitbang->setup_transfer)
bitbang->setup_transfer = spi_bitbang_setup_transfer;
原來是調用準備spi_bitbang_setup_transfer函數,先設置指針,傳遞進來的參數是(spi, t); 接着就在bitbang_work函數中調用status = setup_transfer(spi, t);即spi_bitbang_setup_transfer函數
其中與修改頻率相關的代碼以下:t是指向用戶傳遞來的數值,若是應用層函數沒有傳遞Hz值,則使用spi->max_speed_hz;就是spi_board_info中我本身定義的值。終於找到了賦值的元兇。代碼以下:
/* 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;
}
從打印的信息看出spi_bitbang_setup_transfer會調用s3c24xx_spi_setupxfer函數?原來以前分析錯了status = setup_transfer(spi, t);調用的probe中的s3c24xx_spi_setupxfer。由於這個if (!bitbang->master->setup) 條件不成了,因此bitbang.setup_transfer = s3c24xx_spi_setupxfer。這樣就能進入s3c24xx_spi_setupxfer函數了,而且這時候t不等於NULL。
bitbang_work函數中的struct spi_transfer *t = NULL;那麼究竟是哪一句爲t賦值的呢?再調試。應該是list_for_each_entry (t, &m->transfers, transfer_list) 句。
繼續分析串口信息,又進入了s3c24xx_spi_setupxfer啊!bitbang_work有調用嗎?繼續看,代碼以下
/* 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);
}
天呢!原來回複數據。也就是說個人這次spi自收發,用的不是初始化的值。緣由是在應用層函數中傳入了if (t->speed_hz || t->bits_per_word) 判斷條件中的2個值。若是不傳這2個值,那麼應該就用的是我在kernel中設置的默認值了。試一下,名稱爲spidev_test5
見下圖,效果和想象的是一致的。speed_hz與bits_per_word我在應用層註釋掉了。就沒調用以下代碼段,途中的「ready to change freq」信息應該寫成finish to change freq and other比較好,呵呵。
if (t->speed_hz || t->bits_per_word) {
printk("go bitbang_work 1\n");//by apple
setup_transfer = bitbang->setup_transfer;
if (!setup_transfer) {
status = -ENOPROTOOPT;
break;
}
}
if (setup_transfer) {
printk("setup_transfer\n"); //by apple
printk("NULL addr is 0x%2x,t addr is 0x%2x ",NULL,t); //by apple
status = setup_transfer(spi, t);
if (status < 0)
break;
}
備註:個人spidev_test函數的主函數中write和read函數都被我註釋掉了。直接先transfer(fd);接着在read 2個寄存器後打印出來mode和speed。
上圖1:
上圖2:
上圖3: