版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)
文檔簡介
1、Linux下SPI總線驅(qū)動有通用接口,一般的SPI設(shè)備驅(qū)動使用這個驅(qū)動接口實現(xiàn)設(shè)備驅(qū)動。分析驅(qū)動最好是先了解核心代碼,然后從具體設(shè)備分析入手,然后從下至上,了解整個框架,再從上到下分析,理解透徹。以下分析內(nèi)核根目錄均以src代替。內(nèi)核代碼http:/lxr.linux.no/,版本。SPI的核心代碼即src/drivers/spi/spi.cSPI 初始化和核心代碼src/drivers/spi/spi_gpio.cIO模擬SPI接口代碼頭文件:src/include/linux/spi/spi.hsrc/include/linux/spi/spi_gpio.hsrc/incl
2、ude/linux/spi/spi_bitbang.h首先,先看核心代碼。一步步來,先分析代碼,然后看了具體驅(qū)動再回過頭來看這個核心代碼。spi.c- /* 這個函數(shù)是驅(qū)動模塊卸載時使用 */ 32static void spidev_release(struct device *dev) 33 /* 標(biāo)準(zhǔn)設(shè)備結(jié)構(gòu)體轉(zhuǎn)換成SPI設(shè)備結(jié)構(gòu)體 * 調(diào)用container_of函數(shù)獲取dev設(shè)備所在的SPI設(shè)備結(jié)構(gòu)體指針 */ 34 struct spi_device *spi = to_spi_device(dev); 35 36 /* spi masters may cleanup for re
3、leased devices */ /* 清空SPI主機申請的內(nèi)存 */ 37 if (spi-master-cleanup) 38 spi-master-cleanup(spi); 39 /* 減調(diào)用次數(shù) */ 40 spi_master_put(spi-master); /* 釋放SPI設(shè)備節(jié)點內(nèi)存 */ 41 kfree(spi); 42 43 /* 打印模塊別名 */ 44static ssize_t 45modalias_show(struct device *dev, struct device_attribute *a, char *buf) 46 47 const struct
4、 spi_device *spi = to_spi_device(dev); 48 49 return sprintf(buf, %sn, spi-modalias); 50 51/* 設(shè)置SPI總線屬性名稱/顯示 */ 52static struct device_attribute spi_dev_attrs = 53 _ATTR_RO(modalias), 54 _ATTR_NULL, 55;56 /* 獲取設(shè)備ID */ 57/* modalias support makes modprobe $MODALIAS new-style hotplug work, 58 * and the
5、 sysfs version makes coldplug work too. 59 */ 60 61static const struct spi_device_id *spi_match_id(const struct spi_device_id *id, 62 const struct spi_device *sdev) 63 /* 判斷設(shè)備中名稱與模塊別名相同,則返回該設(shè)備ID */ 64 while (id-name0) 65 if (!strcmp(sdev-modalias, id-name) 66 return id; 67 id+; 68 69 return NULL; 70
6、 71 /* 返回設(shè)備ID */ 72const struct spi_device_id *spi_get_device_id(const struct spi_device *sdev) 73 74 const struct spi_driver *sdrv = to_spi_driver(sdev-dev.driver); 75 76 return spi_match_id(sdrv-id_table, sdev); 77 78EXPORT_SYMBOL_GPL(spi_get_device_id);接上一個繼續(xù)看spi.c。-匹配設(shè)備 /* 名詞解釋of: OpenFirmware *
7、 調(diào)用層次spi_match_device-of_driver_match_device-of_match_device- * of_match_node * 用于驅(qū)動程序檢查platform_device是否在其支持列表里 */ 80static int spi_match_device(struct device *dev, struct device_driver *drv) 81 82 const struct spi_device *spi = to_spi_device(dev); 83 const struct spi_driver *sdrv = to_spi_driver(d
8、rv); 84 85 /* Attempt an OF style match */ /* 不匹配返回0;匹配返回非0,指向struct of_device_id類型的指針 * dev:需要查找的設(shè)備; drv:驅(qū)動程序結(jié)構(gòu)體 */ 86 if (of_driver_match_device(dev, drv) 87 return 1; 88 /* 在驅(qū)動查找設(shè)備ID,找到返回真,否則假 */ 89 if (sdrv-id_table) 90 return !spi_match_id(sdrv-id_table, spi); 91 /* 比較設(shè)備別名和驅(qū)動名稱,匹配返回真 */ 92 retu
9、rn strcmp(spi-modalias, drv-name) = 0; 93 94-uevent /* struct kobj_uevent_env 是內(nèi)核用戶空間的一個環(huán)境參數(shù) * uevent是sysfs向用戶空間發(fā)出的消息,這里實際上添加的是一串字符串消息。 * 關(guān)于uevent參考:/walkingman321/archive/2010/10/01/.aspx */ 95static int spi_uevent(struct device *dev, struct kobj_uevent_env *env) 96 97 const stru
10、ct spi_device *spi = to_spi_device(dev); 98 99 add_uevent_var(env, MODALIAS=%s%s, SPI_MODULE_PREFIX, spi-modalias); 100 return 0; 101-電源管理 /* 配置了電源管理 * 現(xiàn)在不清楚suspend和resume函數(shù)哪里實現(xiàn),等找到了再說 */ 103#ifdef CONFIG_PM 104 /* 掛起 */ 105static int spi_suspend(struct device *dev, pm_message_t message) 106 107 int
11、 value = 0; 108 struct spi_driver *drv = to_spi_driver(dev-driver); 109 110 /* suspend will stop irqs and dma; no more i/o */ /* 掛起將定制終端和DMA,沒有輸入輸出 */ 111 if (drv) /* 驅(qū)動實現(xiàn)了掛起操作函數(shù) */ 112 if (drv-suspend) 113 value = drv-suspend(to_spi_device(dev), message); 114 else 115 dev_dbg(dev, . cant suspendn);
12、 116 117 return value; 118 119 /* 恢復(fù) */ 120static int spi_resume(struct device *dev) 121 122 int value = 0; 123 struct spi_driver *drv = to_spi_driver(dev-driver); 124 125 /* resume may restart the i/o queue */ /* 重新開始輸入輸出隊列 */ 126 if (drv) 127 if (drv-resume) 128 value = drv-resume(to_spi_device(de
13、v); 129 else 130 dev_dbg(dev, . cant resumen); 131 132 return value; 133 134 135#else /* 沒有電源管理 */ 136#define spi_suspend NULL 137#define spi_resume NULL 138#endif-總線 /* 總線 參考:/xingzuzi/blog/item/d12c03f473b3c2a0a50f5260.html */ 140struct bus_type spi_bus_type = 141 .name = spi, 14
14、2 .dev_attrs = spi_dev_attrs, 143 .match = spi_match_device, 144 .uevent = spi_uevent, 145 .suspend = spi_suspend, 146 .resume = spi_resume, 147; 148EXPORT_SYMBOL_GPL(spi_bus_type);-驅(qū)動注冊、刪除/* 驅(qū)動注冊 */ 151static int spi_drv_probe(struct device *dev) 152 153 const struct spi_driver *sdrv = to_spi_drive
15、r(dev-driver); 154 155 return sdrv-probe(to_spi_device(dev); 156 157 /* 驅(qū)動刪除 */ 158static int spi_drv_remove(struct device *dev) 159 160 const struct spi_driver *sdrv = to_spi_driver(dev-driver); 161 162 return sdrv-remove(to_spi_device(dev); 163 164 /* 關(guān)閉 */ 165static void spi_drv_shutdown(struct d
16、evice *dev) 166 167 const struct spi_driver *sdrv = to_spi_driver(dev-driver); 168 169 sdrv-shutdown(to_spi_device(dev); 170-注冊SPI總線驅(qū)動 /* 注冊SPI驅(qū)動 */ 172/* 173 * spi_register_driver - register a SPI driver 174 * sdrv: the driver to register 175 * Context: can sleep 176 */ 177int spi_register_driver(s
17、truct spi_driver *sdrv) 178 /* 初始化總線結(jié)構(gòu)體 */ 179 sdrv-driver.bus = &spi_bus_type; /* 初始化驅(qū)動相關(guān)函數(shù) */ 180 if (sdrv-probe) 181 be = spi_drv_probe; 182 if (sdrv-remove) 183 sdrv-driver.remove = spi_drv_remove; 184 if (sdrv-shutdown) 185 sdrv-driver.shutdown = spi_drv_shutdown; /* 驅(qū)動注冊 * 添加驅(qū)動到
18、總線 * sysfs、uevent等創(chuàng)建、初始化 */ 186 return driver_register(&sdrv-driver); 187 188EXPORT_SYMBOL_GPL(spi_register_driver);接下去看spi.c特殊的板級相關(guān)設(shè)備添加方法 /* 神奇的分割線 */ 190/*-*/ 191 192/* SPI devices should normally not be created by SPI device drivers; that 193 * would make them board-specific. Similarly with SPI m
19、aster drivers. 194 * Device registration normally goes into like arch/./mach./board-YYY.c 195 * with other readonly (flashable) information about mainboard devices. 196 */ 197 /* 板級相關(guān)信息鏈表 */ 198struct boardinfo 199 struct list_head list; 200 struct spi_board_info board_info; 201; 202 203static LIST_
20、HEAD(board_list); 204static LIST_HEAD(spi_master_list); 206/* 207 * Used to protect add/del opertion for board_info list and 208 * spi_master list, and their matching process 209 */ /* 鏈表操作鎖 */ 210static DEFINE_MUTEX(board_lock); 211 212/* 213 * spi_alloc_device - Allocate a new SPI device 214 * mas
21、ter: Controller to which device is connected 215 * Context: can sleep 216 * 217 * Allows a driver to allocate and initialize a spi_device without 218 * registering it immediately. This allows a driver to directly 219 * fill the spi_device with device parameters before calling 220 * spi_add_device()
22、on it. 221 * 222 * Caller is responsible to call spi_add_device() on the returned 223 * spi_device structure to add it to the SPI master. If the caller 224 * needs to discard the spi_device without adding it, then it should 225 * call spi_dev_put() on it. 226 * 227 * Returns a pointer to the new dev
23、ice, or NULL. 228 */ /* 為申請SPI設(shè)備結(jié)構(gòu)體空間而不注冊設(shè)備,必須調(diào)用spi_add_device,如要丟棄這個設(shè)備 * 則必須調(diào)用spi_dev_put */ 229struct spi_device *spi_alloc_device(struct spi_master *master) 230 231 struct spi_device *spi; 232 struct device *dev = master-dev.parent; 233 /* 增加設(shè)備引用次數(shù),相反操作spi_master_put */ 234 if (!spi_master_get(ma
24、ster) 235 return NULL; 236 /* 申請內(nèi)核空間內(nèi)存 */ 237 spi = kzalloc(sizeof *spi, GFP_KERNEL); 238 if (!spi) 239 dev_err(dev, cannot alloc spi_devicen); 240 spi_master_put(master); 241 return NULL; 242 243 /* SPI主機控制結(jié)構(gòu)體 */ 244 spi-master = master; /* 設(shè)備 */ 245 spi-dev.parent = dev; /* 總線 */ 246 spi-dev.bus =
25、 &spi_bus_type; /* 刪除方法 */ 247 spi-dev.release = spidev_release; /* 設(shè)備初始化 * 初始化kobject,dma池鏈表,設(shè)備互斥鎖,自旋鎖,設(shè)備對象的電源相關(guān)部分 * src/drivers/base/core.c */ 248 device_initialize(&spi-dev); /* 返回spi設(shè)備結(jié)構(gòu)體指針 */ 249 return spi; 250 251EXPORT_SYMBOL_GPL(spi_alloc_device); 252 253/* 254 * spi_add_device - Add spi_de
26、vice allocated with spi_alloc_device 255 * spi: spi_device to register 256 * 257 * Companion function to spi_alloc_device. Devices allocated with 258 * spi_alloc_device can be added onto the spi bus with this function. 259 * 260 * Returns 0 on success; negative errno on failure 261 */ /* 與spi_alloc_
27、device配合使用,將設(shè)備結(jié)構(gòu)體添加到SPI總線 */ 262int spi_add_device(struct spi_device *spi) 263 264 static DEFINE_MUTEX(spi_add_lock); 265 struct device *dev = spi-master-dev.parent; 266 struct device *d; 267 int status; 268 269 /* Chipselects are numbered 0.max; validate. */ /* 設(shè)備片選編號比SPI主控制器的片選大,出錯 */ 270 if (spi-
28、chip_select = spi-master-num_chipselect) 271 dev_err(dev, cs%d = max %dn, 272 spi-chip_select, 273 spi-master-num_chipselect); 274 return -EINVAL; 275 276 277 /* Set the bus ID string */ /* 設(shè)置設(shè)備名稱,調(diào)用kobject的設(shè)置設(shè)備名稱參數(shù)方法 */ 278 dev_set_name(&spi-dev, %s.%u, dev_name(&spi-master-dev), 279 spi-chip_selec
29、t); 280 281 282 /* We need to make sure theres no other device with this 283 * chipselect *BEFORE* we call setup(), else well trash 284 * its configuration. Lock against concurrent add() calls. 285 */ /* 互斥鎖,保證設(shè)置時,沒有其他設(shè)備用這個片選,防止并發(fā)添加add() */ 286 mutex_lock(&spi_add_lock); 287 /* 按照名稱字符查找設(shè)備結(jié)構(gòu)體,設(shè)備名稱由de
30、v_name查找kobject返回 * 能夠找到說明設(shè)備已經(jīng)在用 */ 288 d = bus_find_device_by_name(&spi_bus_type, NULL, dev_name(&spi-dev); 289 if (d != NULL) 290 dev_err(dev, chipselect %d already in usen, 291 spi-chip_select); 292 put_device(d); 293 status = -EBUSY; 294 goto done; 295 296 297 /* Drivers may modify this initial
31、i/o setup, but will 298 * normally rely on the device being setup. Devices 299 * using SPI_CS_HIGH cant coexist well otherwise. 300 */ /* /* 設(shè)置SPI模式和時鐘頻率 * 驅(qū)動可以初始化IO,當(dāng)設(shè)備被設(shè)置的時候 * 取消片選沒有用 * 詳細(xì)見后面驅(qū)動核心方法spi_setup解析 */ 301 status = spi_setup(spi); 302 if (status dev), status); 305 goto done; 306 307 308
32、/* Device may be bound to an active driver when this returns */ /* 將設(shè)備添加到驅(qū)動層次結(jié)構(gòu),添加到kobject層次結(jié)構(gòu),添加到其他子系統(tǒng) */ 309 status = device_add(&spi-dev); 310 if (status dev), status); 313 else 314 dev_dbg(dev, registered child %sn, dev_name(&spi-dev); 315 316done: 317 mutex_unlock(&spi_add_lock); 318 return sta
33、tus; 319 320EXPORT_SYMBOL_GPL(spi_add_device); 321 322/* 323 * spi_new_device - instantiate one new SPI device 324 * master: Controller to which device is connected 325 * chip: Describes the SPI device 326 * Context: can sleep 327 * 328 * On typical mainboards, this is purely internal; and its not n
34、eeded 329 * after board init creates the hard-wired devices. Some development 330 * platforms may not be able to use spi_register_board_info though, and 331 * this is exported so that for example a USB or parport based adapter 332 * driver could add devices (which it would learn about out-of-band).
35、333 * 334 * Returns the new device, or NULL. 335 */ /* 有些開發(fā)平臺可能不能通過spi_register_board_info添加設(shè)備 * 這個用來讓一些比如基于USB適配的驅(qū)動添加設(shè)備 */ 336struct spi_device *spi_new_device(struct spi_master *master, 337 struct spi_board_info *chip) 338 339 struct spi_device *proxy; 340 int status; 341 342 /* NOTE: caller did a
36、ny chip-bus_num checks necessary. 343 * 344 * Also, unless we change the return value convention to use 345 * error-or-pointer (not NULL-or-pointer), troubleshootability 346 * suggests syslogged diagnostics are best here (ugh). 347 */ 348 /* 分配設(shè)備結(jié)構(gòu)體內(nèi)存空間,并初始化 */ 349 proxy = spi_alloc_device(master);
37、350 if (!proxy) 351 return NULL; 352 353 WARN_ON(strlen(chip-modalias) = sizeof(proxy-modalias); 354 355 proxy-chip_select = chip-chip_select; 356 proxy-max_speed_hz = chip-max_speed_hz; 357 proxy-mode = chip-mode; 358 proxy-irq = chip-irq; 359 strlcpy(proxy-modalias, chip-modalias, sizeof(proxy-mod
38、alias); 360 proxy-dev.platform_data = (void *) chip-platform_data; 361 proxy-controller_data = chip-controller_data; 362 proxy-controller_state = NULL; 363 /* 添加設(shè)備 */ 364 status = spi_add_device(proxy); 365 if (status bus_num != bi-bus_num) 380 return; 381 382 dev = spi_new_device(master, bi); 383 i
39、f (!dev) 384 dev_err(master-dev.parent, cant create new device for %sn, 385 bi-modalias); 386 387 388/* 389 * spi_register_board_info - register SPI devices for a given board 390 * info: array of chip descriptors 391 * n: how many descriptors are provided 392 * Context: can sleep 393 * 394 * Board-s
40、pecific early init code calls this (probably during arch_initcall) 395 * with segments of the SPI device table. Any device nodes are created later, 396 * after the relevant parent SPI controller (bus_num) is defined. We keep 397 * this table of devices forever, so that reloading a controller driver
41、will 398 * not make Linux forget about these hard-wired devices. 399 * 400 * Other code can also call this, e.g. a particular add-on board might provide 401 * SPI devices through its expansion connector, so code initializing that board 402 * would naturally declare its SPI devices. 403 * 404 * The b
42、oard info passed can safely be _initdata . but be careful of 405 * any embedded pointers (platform_data, etc), theyre copied as-is. 406 */ /* 使用一系列板級描述信息初始化設(shè)備 */ 407int _init 408spi_register_board_info(struct spi_board_info const *info, unsigned n) 409 410 struct boardinfo *bi; 411 int i; 412 413 bi
43、 = kzalloc(n * sizeof(*bi), GFP_KERNEL); 414 if (!bi) 415 return -ENOMEM; 416 417 for (i = 0; i board_info, info, sizeof(*info); 421 mutex_lock(&board_lock); /* 添加到板級描述符鏈表 */ 422 list_add_tail(&bi-list, &board_list); /* 將主機控制類鏈表所有的節(jié)點匹配板級信息的設(shè)備初始化 */ 423 list_for_each_entry(master, &spi_master_list, list) 424 spi_match_master_to_boardinfo(master, &bi-board_info); 425 mutex_unlock(&board_lock); 4
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025-2030新能源礦產(chǎn)行業(yè)資源開發(fā)與環(huán)境保護技術(shù)研究分析報告
- 智慧農(nóng)業(yè)技術(shù)推廣策劃方案
- 苗圃場養(yǎng)護標(biāo)準(zhǔn)及管理操作方案
- 葡萄酒品牌市場推廣與銷售策劃方案
- 城市軌道交通工地施工安全方案
- 2025年電工(初級)復(fù)審考試及作業(yè)考試題庫詳解及答案
- 施工機械進場管理計劃模板
- 2025 年大學(xué)人力資源管理(人力理論)期中測試卷
- 中考英語一模試題及評分標(biāo)準(zhǔn)
- 八年級英語口語測試題詳解
- 基于多模型構(gòu)建與數(shù)值模擬的禽流感傳播機制及防控策略研究
- 2025-2026學(xué)年高三上學(xué)期《挑戰(zhàn)極限青春無悔》主題班會課件
- 律師事務(wù)所績效考核評分細(xì)則
- 醫(yī)院醫(yī)療設(shè)備定期維護計劃表
- 民事檢察案例匯報
- 2025秋季學(xué)期國開電大法學(xué)本科《國際私法》期末紙質(zhì)考試簡述題題庫珍藏版
- 2025年道教傳度考試題及答案
- 微機電系統(tǒng)(MEMS)技術(shù) 柔性微機電器件循環(huán)彎曲變形后電氣特性測試方法 編制說明
- 小區(qū)充電樁轉(zhuǎn)讓合同范本
- (2025年標(biāo)準(zhǔn))國債使用協(xié)議書
- 2025年南京市事業(yè)單位教師招聘考試體育學(xué)科專業(yè)知識試卷(秋季篇)
評論
0/150
提交評論