久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Linux下SPI從設(shè)備驅(qū)動的編寫

 XeonGate 2015-08-18

 SPI(Serial Peripheral Interface) 是一個同步的四線制串行線,,用于連接微控制器和傳感器、存儲器及外圍設(shè)備。三條信號線持有時鐘信號(SCLK,,經(jīng)常在10MHz左右)和并行數(shù)據(jù)線帶有主出,從進(MOSI)”或是主進,,從出(MISO)”信號,。數(shù)據(jù)交換的時候有四種時鐘模式,模式0和模式3是最經(jīng)常使用的,。每個時鐘周期將會傳遞數(shù)據(jù)進和出,。如果沒有數(shù)據(jù)傳遞的話,時鐘將不會循環(huán),。

 

SPI驅(qū)動分為兩類:

控制器驅(qū)動:它們通常內(nèi)嵌于片上系統(tǒng)處理器,,通常既支持主設(shè)備,又支持從設(shè)備,。這些驅(qū)動涉及硬件寄存器,,可能使用DMA?;蛩鼈兪褂?/span>GPIO引腳成為PIO bitbangers,。這部分通常會由特定的開發(fā)板提供商提供,不用自己寫,。

協(xié)議驅(qū)動:它們通過控制器驅(qū)動,,以SPI連接的方式在主從設(shè)備之間傳遞信息。這部分涉及具體的SPI從設(shè)備,,通常需要自己編寫,。

那么特定的目標(biāo)板如何讓Linux 操控SPI設(shè)備,?下面以AT91SAM9260系列CAN設(shè)備驅(qū)動為例,Linux內(nèi)核版本為2.6.19,。本文不涉及控制器驅(qū)動分析,。

board_info提供足夠的信息使得系統(tǒng)正常工作而不需要芯片驅(qū)動加載

  1. 在arch/arm/mach-at91rm9200/board-at91sam9260.c中有如下代碼:  
  2. #include <linux/platform_device.h>  
  3. #include <linux/spi/spi.h>  
  4. …….  
  5. static struct spi_board_info ek_spi_devices[] = {  
  6. /* spi can ,add by mrz */  
  7. #if defined(CONFIG_CAN_MCP2515)    
  8.     {  
  9.         .modalias = "mcp2515",  
  10.         .chip_select = 0,  
  11. //      .controller_data = AT91_PIN_PB3,  
  12.         .irq = AT91_PIN_PC6, //AT91SAM9260_ID_IRQ0,  
  13.         .platform_data = &mcp251x_data,  
  14.         .max_speed_hz = 10 * 1000 * 1000,  
  15.         .bus_num = 1,  
  16.         .mode = 0,  
  17.     }  
  18.     #endif  
  19. };.  
  20. ………  
  21. static void __init ek_board_init(void)  
  22. {  
  23. ……  
  24. /* SPI */  
  25.     at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));  
  26. }  

這樣在Linux初始化時候就可以加載SPI CAN驅(qū)動。

 

下面來看MCP2515 CAN驅(qū)動的結(jié)構(gòu),,協(xié)議驅(qū)動有點類似平臺設(shè)備驅(qū)動,,本文只列出框架,不涉及具體實現(xiàn)代碼,,在/driver/CAN/MCP2515.c中:

[c-sharp] view plaincopy
  1. static struct spi_driver mcp251x_driver = {  
  2.     .driver = {  
  3.         .name   = mcp2515,  
  4.         .bus    = &spi_bus_type,  
  5.         .owner  = THIS_MODULE,  
  6.     },  
  7.     .probe  = mcp251x_probe,  
  8.     .remove = __devexit_p(mcp251x_remove),  
  9. #ifdef CONFIG_PM  
  10.     .suspend    = mcp251x_suspend,  
  11.     .resume = mcp251x_resume,  
  12. #endif  
  13. };  
  14. 驅(qū)動將自動試圖綁定驅(qū)動到任何board_info給定別名為" mcp2515"的SPI設(shè)備,。  
  15. static int __devinit mcp251x_probe(struct spi_device *spi)  
  16. {  
  17.     struct mcp251x *chip;  
  18.     int ret = 0;  
  19.   
  20.     dev_dbg(&spi->dev, "%s: start/n",  __FUNCTION__);  
  21.   
  22.     chip = kmalloc(sizeof(struct mcp251x), GFP_KERNEL);  
  23.     if (!chip) {  
  24.         ret = -ENOMEM;  
  25.         goto error_alloc;  
  26.     }  
  27.   
  28.     dev_set_drvdata(&spi->dev, chip);  
  29.       
  30.     chip->txbin = chip->txbout = 0;  
  31.     chip->rxbin = chip->rxbout = 0;  
  32.     chip->count = 0;  
  33.     chip->spi = spi;  
  34.     init_MUTEX(&chip->lock);  
  35.     init_MUTEX(&chip->txblock);  
  36.     init_MUTEX(&chip->rxblock);  
  37.     init_waitqueue_head(&chip->wq);  
  38.      
  39. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))  
  40.     INIT_WORK(&chip->irq_work, mcp251x_irq_handler);  
  41. #else  
  42.     INIT_WORK(&chip->irq_work, mcp251x_irq_handler, spi);  
  43. #endif  
  44.       
  45.     chip->spi_transfer_buf = kmalloc(SPI_TRANSFER_BUF_LEN, GFP_KERNEL);  
  46.     if (!chip->spi_transfer_buf) {  
  47.         ret = -ENOMEM;  
  48.         goto error_buf;  
  49.     }  
  50.       
  51.     ret = request_irq(spi->irq, mcp251x_irq, SA_SAMPLE_RANDOM, DRIVER_NAME, spi);  
  52.     if (ret < 0) {  
  53.         dev_err(&spi->dev, "request irq %d failed (ret = %d)/n", spi->irq, ret);  
  54.         goto error_irq;  
  55.     }  
  56.       
  57.     cdev_init(&chip->cdev, &mcp251x_fops);  
  58.     chip->cdev.owner = THIS_MODULE;  
  59.     ret = cdev_add(&chip->cdev, MKDEV(MAJOR(can_devt), can_minor), 1);  
  60.     if (ret < 0) {  
  61.         dev_err(&spi->dev, "register char device failed (ret = %d)/n", ret);  
  62.         goto error_register;  
  63.     }  
  64.   
  65.     chip->class_dev = class_device_create(can_class, NULL,  
  66.                           MKDEV(MAJOR(can_devt), can_minor),  
  67.                           &spi->dev, "can%d", can_minor);  
  68.     if (IS_ERR(chip->class_dev)) {  
  69.         dev_err(&spi->dev, "cannot create CAN class device/n");  
  70.         ret = PTR_ERR(chip->class_dev);  
  71.         goto error_class_reg;  
  72.     }  
  73.       
  74.     dev_info(&spi->dev, "device register at dev(%d:%d)/n",  
  75.          MAJOR(can_devt), can_minor);  
  76.       
  77.     mcp251x_hw_init(spi);  
  78.     mcp251x_set_bit_rate(spi, 125000); /* A reasonable default */  
  79.     mcp251x_hw_sleep(spi);  
  80.   
  81.     can_minor++;  
  82.       
  83.     return 0;  
  84.       
  85. error_class_reg:  
  86.     cdev_del(&chip->cdev);  
  87. error_register:  
  88.     free_irq(spi->irq, spi);  
  89. error_irq:  
  90.     kfree(chip->spi_transfer_buf);  
  91. error_buf:  
  92.     kfree(chip);  
  93. error_alloc:  
  94.     return ret;  
  95. }  
  

一旦進入probe(),驅(qū)動使用"struct spi_message"SPI設(shè)備要求I/O,。當(dāng)remove()返回時,,驅(qū)動保證將不會提交任何這種信息。
一個spi_message是協(xié)議操作序列,,以一個原子序列執(zhí)行,。SPI驅(qū)動控制包括:
   
1)當(dāng)雙向讀寫開始,是根據(jù)spi_transfer要求序列是怎樣安排的,。
   
2)隨意設(shè)定傳遞后的短延時,,使用spi_transfer.delay_usecs設(shè)定。
   
3)在一次傳遞和任何延時之后,,無論片選是否活躍,,使用spi_transfer.cs_change標(biāo)志,    暗示下條信息是否進入這個同樣的設(shè)備,,使用原子組中最后一次傳輸上的spi_transfer.cs_change標(biāo)志位,,可能節(jié)省芯片選擇取消操作的成本。

 

 

 

 

 

 

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點,。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多