中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

wordpress vip 插件網(wǎng)站seo推廣seo教程

wordpress vip 插件,網(wǎng)站seo推廣seo教程,偽靜態(tài)nginx wordpress,海南疫情最新通報前言 Linux的spi接口驅(qū)動實現(xiàn)目錄在kernel\drivers\spi下。這個目錄和一些層次比較明顯的驅(qū)動目錄布局不同,全放在這個文件夾下,因此還是只好通過看Kconfig 和 Makefile來找找思路 先看Makefile,里面關(guān)鍵幾行: obj-$(CONFIG_SPI…

前言

Linux的spi接口驅(qū)動實現(xiàn)目錄在kernel\drivers\spi下。這個目錄和一些層次比較明顯的驅(qū)動目錄布局不同,全放在這個文件夾下,因此還是只好通過看Kconfig 和 Makefile來找找思路

先看Makefile,里面關(guān)鍵幾行:
obj-$(CONFIG_SPI_MASTER) += spi.o //這個是針對有spi控制器的soc選項,一般的soc都有spi控制器吧。
# SPI master controller drivers (bus) //下面的這些就是針對不同soc上的spi控制器的驅(qū)動了,我們可以通過make menuconfig的時候選上自己對應(yīng)平臺的

# SPI master controller drivers (bus)
obj-$(CONFIG_SPI_ALTERA)		+= spi-altera.o
obj-$(CONFIG_SPI_ARMADA_3700)		+= spi-armada-3700.o
............
obj-$(CONFIG_SPI_AXI_SPI_ENGINE)	+= spi-axi-spi-engine.o

下面這些就是針對于主機作為spi從設(shè)備的時候用的,暫時貌似沒支持,畢竟現(xiàn)實中幾乎沒有用過,而是作為master端出現(xiàn)

# SPI slave protocol handlers
obj-$(CONFIG_SPI_SLAVE_TIME)		+= spi-slave-time.o
obj-$(CONFIG_SPI_SLAVE_SYSTEM_CONTROL)	+= spi-slave-system-control.o

再看Kconfig,第一個SPI選項我覺得有必要貼一下,首先只有選擇它了才能進行后面的配置,其次它的help對spi的描述說的很清楚!

#
# SPI driver configuration
#
menuconfig SPIbool "SPI support"depends on HAS_IOMEMhelpThe "Serial Peripheral Interface" is a low level synchronousprotocol.  Chips that support SPI can have data transfer ratesup to several tens of Mbit/sec.  Chips are addressed with acontroller and a chipselect.  Most SPI slaves don't supportdynamic device discovery; some are even write-only or read-only.SPI is widely used by microcontrollers to talk with sensors,eeprom and flash memory, codecs and various other controllerchips, analog to digital (and d-to-a) converters, and more.MMC and SD cards can be accessed using SPI protocol; and forDataFlash cards used in MMC sockets, SPI must always be used.SPI is one of a family of similar protocols using a four wireinterface (select, clock, data in, data out) including Microwire(half duplex), SSP, SSI, and PSP.  This driver framework shouldwork with most such devices and controllers.

我們其次需要配上的選項就是SPI_MASTERCONFIG_SPI_ROCKCHIP(我手上的是RK的SDK)。

config SPI_MASTER
#	bool "SPI Master Support"booldefault SPIhelpIf your system has an master-capable SPI controller (whichprovides the clock and chipselect), you can enable thatcontroller and the protocol drivers for the SPI slave chipsthat are connected.config SPI_ROCKCHIPtristate "Rockchip SPI controller driver"helpThis selects a driver for Rockchip SPI controller.If you say yes to this option, support will be included forRK3066, RK3188 and RK3288 families of SPI controller.Rockchip SPI controller support DMA transport and PIO mode.The main usecase of this controller is to use spi flash as bootdevice.

于是從Makefile里得到如下語句和我們相關(guān):

obj-$(CONFIG_SPI_ROCKCHIP)		+= spi-rockchip.o

于是我們要分析的代碼主要有:spi.c spi-rockchip.c,瞬間沒壓力了,就兩個文件,呵呵

下面主要從三個方面來分析spi框架

  1. spi控制器驅(qū)動的實現(xiàn)(畢竟spi控制器的驅(qū)動還是有可能要接觸的)
  2. spi設(shè)備的驅(qū)動(我們更多的是編寫設(shè)備的驅(qū)動,還是以eeprom為例吧,雖然我很想以spi接口的nor flash驅(qū)動為例,但是那又會牽涉出mtd子系統(tǒng),這個留在mtd子系統(tǒng)分析吧)
  3. spi核心層的實現(xiàn)(上面1、2都是以各自的驅(qū)動實現(xiàn)為目標(biāo),并不深入到spi核心層,也就是至于spi核心層怎么為我們提供的服務(wù)不去關(guān)心,只需要按spi核心層使用它提供的服務(wù)就是了。所以現(xiàn)在統(tǒng)一分析spi核心層,看它是怎么提供的服務(wù))

spi控制器驅(qū)動的實現(xiàn)

spi-rockchip.c為例,直接看module_platform_driver

static struct platform_driver rockchip_spi_driver = {.driver = {.name	= DRIVER_NAME,.pm = &rockchip_spi_pm,.of_match_table = of_match_ptr(rockchip_spi_dt_match),},.probe = rockchip_spi_probe,.remove = rockchip_spi_remove,
};

平臺驅(qū)動的內(nèi)部流程就不分析了,直接看匹配成功后rockchip_spi_probe的調(diào)用,但這里還是插入平臺spi控制器設(shè)備端相關(guān)的代碼:

  1. 使用spi_alloc_master函數(shù)為平臺設(shè)備pdev分配一個SPI主設(shè)備結(jié)構(gòu)體,并將其大小設(shè)置為sizeof(struct rockchip_spi)。這個函數(shù)會分配內(nèi)存并初始化主設(shè)備結(jié)構(gòu)體的各個字段。調(diào)用platform_set_drvdata函數(shù)將主設(shè)備結(jié)構(gòu)體指針保存在平臺設(shè)備的私有數(shù)據(jù)中,以便后續(xù)在驅(qū)動的其他函數(shù)中可以訪問該指針。使用spi_master_get_devdata函數(shù)獲取之前保存在私有數(shù)據(jù)中的主設(shè)備結(jié)構(gòu)體指針rs。
	master = spi_alloc_master(&pdev->dev, sizeof(struct rockchip_spi));if (!master)return -ENOMEM;platform_set_drvdata(pdev, master);rs = spi_master_get_devdata(master);
  1. 使用platform_get_resource函數(shù)獲取SPI控制器的IO資源。這些資源包括寄存器地址、中斷號等信息,向操作系統(tǒng)請求資源空間并建立起映射為以后所用。
	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);rs->regs = devm_ioremap_resource(&pdev->dev, mem);if (IS_ERR(rs->regs)) {ret =  PTR_ERR(rs->regs);goto err_ioremap_resource;}
  1. 使用devm_clk_get函數(shù)獲取SPI控制器所需的時鐘,包括"apb_pclk"和"spiclk"。這些時鐘用于控制SPI控制器的時序和傳輸速率。
	rs->apb_pclk = devm_clk_get(&pdev->dev, "apb_pclk");if (IS_ERR(rs->apb_pclk)) {dev_err(&pdev->dev, "Failed to get apb_pclk\n");ret = PTR_ERR(rs->apb_pclk);goto err_ioremap_resource;}rs->spiclk = devm_clk_get(&pdev->dev, "spiclk");if (IS_ERR(rs->spiclk)) {dev_err(&pdev->dev, "Failed to get spi_pclk\n");ret = PTR_ERR(rs->spiclk);goto err_ioremap_resource;}
  1. 使用clk_prepare_enable函數(shù)使獲取到的時鐘生效,確保SPI控制器可以正常工作。
	ret = clk_prepare_enable(rs->apb_pclk);if (ret) {dev_err(&pdev->dev, "Failed to enable apb_pclk\n");goto err_ioremap_resource;}ret = clk_prepare_enable(rs->spiclk);if (ret) {dev_err(&pdev->dev, "Failed to enable spi_clk\n");goto err_spiclk_enable;}
  1. 調(diào)用spi_enable_chip函數(shù)使SPI芯片處于可用狀態(tài)。這個函數(shù)會執(zhí)行一些特定的SPI控制器寄存器的配置,以便使芯片可以正常通信。設(shè)置SPI主設(shè)備的屬性。這些屬性包括SPI總線類型、主設(shè)備指針、設(shè)備指針、最大頻率等。
	spi_enable_chip(rs, 0);rs->type = SSI_MOTO_SPI;rs->master = master;rs->dev = &pdev->dev;rs->max_freq = clk_get_rate(rs->spiclk);
  1. 使用of_property_read_u32函數(shù)從設(shè)備節(jié)點中讀取屬性值。在這個例子中,它讀取了"rx-sample-delay-ns"屬性,并將其存儲在rsd_nsecs變量中。調(diào)用get_fifo_len函數(shù)獲取FIFO的長度。FIFO用于在SPI傳輸過程中暫存數(shù)據(jù)。
if (!of_property_read_u32(pdev->dev.of_node, "rx-sample-delay-ns",&rsd_nsecs))rs->rsd_nsecs = rsd_nsecs;rs->fifo_len = get_fifo_len(rs);
if (!rs->fifo_len) {dev_err(&pdev->dev, "Failed to get fifo length\n");ret = -EINVAL;goto err_get_fifo_len;
}
  1. 初始化自旋鎖。自旋鎖用于保護共享資源,防止多個進程同時訪問造成沖突。設(shè)置設(shè)備的運行時PM狀態(tài)為活動,并啟用運行時PM。允許系統(tǒng)在不需要SPI設(shè)備時將其置于低功耗狀態(tài)。
spin_lock_init(&rs->lock);pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
  1. 設(shè)置主設(shè)備的一些屬性,例如自動運行時PM、總線號、模式位、芯片選擇數(shù)量、設(shè)備節(jié)點等。同時設(shè)置主設(shè)備的回調(diào)函數(shù)。這些回調(diào)函數(shù)將在SPI傳輸中的不同階段被調(diào)用,以執(zhí)行相應(yīng)的操作
	master->auto_runtime_pm = true;master->bus_num = pdev->id;master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_LSB_FIRST;master->num_chipselect = 2;master->dev.of_node = pdev->dev.of_node;master->bits_per_word_mask = SPI_BPW_MASK(16) | SPI_BPW_MASK(8);master->set_cs = rockchip_spi_set_cs;master->prepare_message = rockchip_spi_prepare_message;master->unprepare_message = rockchip_spi_unprepare_message;master->transfer_one = rockchip_spi_transfer_one;master->handle_err = rockchip_spi_handle_err;
  1. 使用dma_request_slave_channel函數(shù)請求DMA通道,如果同時成功請求到了TX和RX的DMA通道,則設(shè)置DMA傳輸?shù)牡刂泛头较?#xff0c;并將相應(yīng)的DMA通道設(shè)置為主設(shè)備的屬性。
	rs->dma_tx.ch = dma_request_slave_channel(rs->dev, "tx");if (IS_ERR_OR_NULL(rs->dma_tx.ch)) {/* Check tx to see if we need defer probing driver */if (PTR_ERR(rs->dma_tx.ch) == -EPROBE_DEFER) {ret = -EPROBE_DEFER;goto err_get_fifo_len;}dev_warn(rs->dev, "Failed to request TX DMA channel\n");}rs->dma_rx.ch = dma_request_slave_channel(rs->dev, "rx");if (!rs->dma_rx.ch) {if (rs->dma_tx.ch) {dma_release_channel(rs->dma_tx.ch);rs->dma_tx.ch = NULL;}dev_warn(rs->dev, "Failed to request RX DMA channel\n");}
  1. 使用pinctrl_lookup_state函數(shù)查找高速模式的引腳控制狀態(tài)。檢查查找高速模式的引腳控制狀態(tài)是否成功。
	rs->high_speed_state = pinctrl_lookup_state(rs->dev->pins->p,"high_speed");if (IS_ERR_OR_NULL(rs->high_speed_state)) {dev_warn(&pdev->dev, "no high_speed pinctrl state\n");rs->high_speed_state = NULL;}
  1. 使用devm_spi_register_master函數(shù)注冊SPI主設(shè)備。
	ret = devm_spi_register_master(&pdev->dev, master);if (ret) {dev_err(&pdev->dev, "Failed to register master\n");goto err_register_master;}

暫時不進入到spi核心層分析,這里我們只需要知道調(diào)用核心層的注冊函數(shù)后,核心層會遍歷所有注冊到核心層的設(shè)備(實際最開始是加入到一個全局鏈表里,和I2C核心層的實現(xiàn)類似),然后嘗試著添加每一個總線號為該控制器衍生出的總線號的設(shè)備到該spi控制器上,當(dāng)然如果該spi控制器不支持某一個設(shè)備,那就取消添加這個設(shè)備,如果添加成功,那么該設(shè)備將會添加到spi總線上去,這條總線是spi核心層注冊的,用來管理spi接口的設(shè)備和spi接口的驅(qū)動。

總結(jié)下probe函數(shù)的主要工作:

  • 分配和初始化SPI主設(shè)備結(jié)構(gòu)體。
  • 獲取并映射IO資源。
  • 獲取和使能時鐘。
  • 設(shè)置SPI主設(shè)備的屬性和回調(diào)函數(shù)。
  • 請求并設(shè)置DMA通道。
  • 注冊SPI主設(shè)備。

spi設(shè)備的驅(qū)動

以eeprom為例,我們分析下文件at25.c:

同樣的,driver的注冊過程我們就不深入了解了,其實就是一個總線設(shè)備驅(qū)動模型。我們直接看probe函數(shù)做了什么。

static const struct of_device_id at25_of_match[] = {{ .compatible = "atmel,at25", },{ }
};
MODULE_DEVICE_TABLE(of, at25_of_match);static struct spi_driver at25_driver = {.driver = {.name		= "at25",.of_match_table = at25_of_match,},.probe		= at25_probe,.remove		= at25_remove,
};
  1. 檢查spi->dev.platform_data是否存在,如果不存在,則調(diào)用at25_fw_to_chip函數(shù)將固件信息轉(zhuǎn)換為芯片描述,并將其存儲在chip結(jié)構(gòu)體中。如果存在,則直接將spi->dev.platform_data強制類型轉(zhuǎn)換為spi_eeprom結(jié)構(gòu)體,并將其賦值給chip。
	/* Chip description */if (!spi->dev.platform_data) {err = at25_fw_to_chip(&spi->dev, &chip);if (err)return err;} elsechip = *(struct spi_eeprom *)spi->dev.platform_data;
  1. 根據(jù)chip結(jié)構(gòu)體中的標(biāo)志位判斷EEPROM的地址長度是8位、16位還是24位,并將相應(yīng)的值賦給addrlen變量。
	/* For now we only support 8/16/24 bit addressing */if (chip.flags & EE_ADDR1)addrlen = 1;else if (chip.flags & EE_ADDR2)addrlen = 2;else if (chip.flags & EE_ADDR3)addrlen = 3;else {dev_dbg(&spi->dev, "unsupported address type\n");return -EINVAL;}
  1. 通過發(fā)送AT25_RDSR指令讀取EEPROM的狀態(tài)寄存器。如果讀取失敗或狀態(tài)寄存器中的AT25_SR_nRDY位為1,表示EEPROM不可用,返回錯誤碼-ENXIO。
	/* Ping the chip ... the status register is pretty portable,* unlike probing manufacturer IDs.  We do expect that system* firmware didn't write it in the past few milliseconds!*/sr = spi_w8r8(spi, AT25_RDSR);if (sr < 0 || sr & AT25_SR_nRDY) {dev_dbg(&spi->dev, "rdsr --> %d (%02x)\n", sr, sr);return -ENXIO;}
  1. 使用devm_kzalloc函數(shù)為at25_data結(jié)構(gòu)體分配內(nèi)存,并使用GFP_KERNEL標(biāo)志指定內(nèi)存分配的上下文。初始化互斥鎖at25->lock,用于保護共享資源的訪問。將chip結(jié)構(gòu)體和spi設(shè)備保存在at25_data結(jié)構(gòu)體中。使用spi_set_drvdata函數(shù)將at25_data結(jié)構(gòu)體指針存儲在spi設(shè)備的私有數(shù)據(jù)中,以便在后續(xù)的函數(shù)中可以方便地訪問。將地址長度addrlen保存在at25_data結(jié)構(gòu)體的addrlen字段中。
	at25 = devm_kzalloc(&spi->dev, sizeof(struct at25_data), GFP_KERNEL);if (!at25)return -ENOMEM;mutex_init(&at25->lock);at25->chip = chip;at25->spi = spi_dev_get(spi);spi_set_drvdata(spi, at25);at25->addrlen = addrlen;
  1. 創(chuàng)建應(yīng)用層用來操作的文件,使用sysfs_bin_attr_init函數(shù)初始化at25->bin成員變量,其中at25->binstruct bin_attribute類型的變量。設(shè)置at25->bin的屬性名稱為"eeprom",訪問權(quán)限為用戶只讀模式(S_IRUSR)。設(shè)置at25->bin的讀回調(diào)函數(shù)為at25_bin_read,寫回調(diào)函數(shù)為at25_bin_write。
	sysfs_bin_attr_init(&at25->bin);at25->bin.attr.name = "eeprom";at25->bin.attr.mode = S_IRUSR;at25->bin.read = at25_bin_read;at25->mem.read = at25_mem_read;
  1. 根據(jù)chip的只讀標(biāo)志位(EE_READONLY),確定是否將寫回調(diào)函數(shù)和寫權(quán)限添加到at25->bin
	at25->bin.size = at25->chip.byte_len;if (!(chip.flags & EE_READONLY)) {at25->bin.write = at25_bin_write;at25->bin.attr.mode |= S_IWUSR;at25->mem.write = at25_mem_write;}
  1. 使用sysfs_create_bin_file函數(shù)將at25->bin添加到SPI設(shè)備的內(nèi)核對象(spi->dev.kobj)中,以便將EEPROM字節(jié)通過sysfs導(dǎo)出。
	err = sysfs_create_bin_file(&spi->dev.kobj, &at25->bin);if (err)return err;
  1. 如果chipsetup字段不為空,將調(diào)用chip.setup函數(shù),并將at25->memchip.context作為參數(shù)傳遞。使用dev_info函數(shù)打印一條設(shè)備信息消息,包括EEPROM的大小、名稱、是否只讀以及頁面大小。
if (chip.setup)chip.setup(&at25->mem, chip.context);dev_info(&spi->dev, "%Zd %s %s eeprom%s, pagesize %u\n",(at25->bin.size < 1024)? at25->bin.size: (at25->bin.size / 1024),(at25->bin.size < 1024) ? "Byte" : "KByte",at25->chip.name,(chip.flags & EE_READONLY) ? " (readonly)" : "",at25->chip.page_size);

該代碼的功能是在SPI設(shè)備上探測并初始化一個EEPROM芯片,然后將EEPROM的字節(jié)通過sysfs導(dǎo)出,以便其他內(nèi)核代碼或用戶空間程序可以方便地訪問和操作EEPROM數(shù)據(jù)。

spi核心層的實現(xiàn)

主要看spi.c文件:

static int __init spi_init(void)postcore_initcall(spi_init); 

從這里可以知道spi_init的調(diào)用(也就是spi核心層的初始化)是在驅(qū)動加載前的。

調(diào)用kmalloc函數(shù)為SPI子系統(tǒng)分配一個大小為SPI_BUFSIZ的內(nèi)核內(nèi)存緩沖區(qū),并將返回的指針賦值給buf

buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
if (!buf) {status = -ENOMEM;goto err0;
}

調(diào)用bus_register函數(shù)注冊SPI總線類型,將其添加到系統(tǒng)總線列表中。如果注冊失敗,將status設(shè)置為返回的錯誤碼,并跳轉(zhuǎn)到err1標(biāo)簽處進行錯誤處理。

status = bus_register(&spi_bus_type);
if (status < 0)goto err1;

調(diào)用class_register函數(shù)注冊SPI主控制器類,將其添加到系統(tǒng)設(shè)備類列表中。如果注冊失敗,將status設(shè)置為返回的錯誤碼,并跳轉(zhuǎn)到err2標(biāo)簽處進行錯誤處理。

status = class_register(&spi_master_class);
if (status < 0)goto err2;

所有注冊到核心層的spi控制器都屬于這個class。

http://www.risenshineclean.com/news/2095.html

相關(guān)文章:

  • 深圳疫情最新消息今天seo指搜索引擎
  • 西安做網(wǎng)站公司網(wǎng)絡(luò)優(yōu)化師是什么工作
  • 安徽六安瓜片是什么茶百家號seo怎么做
  • 企業(yè)商城建站最新小組排名
  • 網(wǎng)站建設(shè)及發(fā)展成品視頻直播軟件推薦哪個好一點
  • 微信上如何做網(wǎng)站網(wǎng)絡(luò)服務(wù)提供者不履行法律行政法規(guī)規(guī)定
  • 做網(wǎng)站付多少定金seo推廣績效考核指標(biāo)是什么
  • XART視頻庫WordPressseo黑帽技術(shù)有哪些
  • 高唐做網(wǎng)站建設(shè)公司小程序拉新推廣平臺
  • 網(wǎng)上做論文的網(wǎng)站鄭州seo公司哪家好
  • 做商城網(wǎng)站簡單嗎廣東百度seo關(guān)鍵詞排名
  • 臨沂高端網(wǎng)站建設(shè)百度官網(wǎng)地址
  • 網(wǎng)站做好后怎么做seo湖南靠譜seo優(yōu)化
  • 郵箱注冊網(wǎng)站查詢百度公司簡介
  • 無錫網(wǎng)站制作楚天軟件所有代刷平臺推廣
  • 手機網(wǎng)站前端百度站長工具網(wǎng)站提交
  • .com免費網(wǎng)站怎么做東莞seo優(yōu)化seo關(guān)鍵詞
  • 福田做商城網(wǎng)站建設(shè)哪家技術(shù)好免費建站系統(tǒng)哪個好用嗎
  • 華亞快印網(wǎng)站開發(fā)長春網(wǎng)站公司哪家好
  • laravel 和wordpress百度seo軟件首選帝搜軟件
  • 建手機網(wǎng)站藥品網(wǎng)絡(luò)營銷公司
  • 襄陽做網(wǎng)站公司電話精準(zhǔn)引流怎么推廣
  • 網(wǎng)站推廣策劃案效果好在線之家
  • 三型布局的網(wǎng)站營銷軟文怎么寫
  • 新國際網(wǎng)站建設(shè)百度網(wǎng)站app下載
  • 11免費建網(wǎng)站寧波seo外包
  • 商品網(wǎng)站建設(shè)設(shè)計思路網(wǎng)絡(luò)工程師培訓(xùn)機構(gòu)排名
  • 珠海網(wǎng)站建設(shè)搭建重慶網(wǎng)絡(luò)推廣
  • 網(wǎng)站建設(shè)的技術(shù)有哪些培訓(xùn)計劃方案模板
  • 自學(xué)做動態(tài)網(wǎng)站徐州百度快照優(yōu)化