linux spi設備驅動中probe函數何時被調用

這兩天被設備文件快搞瘋了,也怪自己學東西一知半解吧,弄了幾天總算能把設備註冊理清楚一點點了。就以spi子設備的註冊爲例總結一下,免得自己忘記。

首先以註冊一個spidev的設備爲例:

  1. static struct spi_board_info imx5_spi_printer_device[] __initdata =
  2. {
  3. {
  4. .modalias = "spidev",
  5. .max_speed_hz = 8000000,
  6. .bus_num = 1,
  7. .chip_select = 1,
  8. .mode = SPI_MODE_0,
  9. },
  10. };
spi_register_board_info(imx5_spi_printer_device,ARRAY_SIZE(imx5_spi_printer_device));

在mx5_loco.c文件中添加上面結構體spi_board_info,modalias必須指定已有的一個驅動,至於bus_num和chip_select,如果你不知道bus_num是多少,可以在你的父驅動中打印出來,這裏的bus_num一定要和父類的bus_num一致,否則是無法生成設備文件的。如果spi一直沒有時鐘信號,很有可能是bus_num不對。

這樣系統起來之後就會在/dev目錄下出現一個名爲spidev1.1的設備文件,讀寫這個文件就可以實現spi的操作

還有下面這種情況:

  1. static struct spi_board_info prt_spi_device[] __initdata = {
  2. {
  3. .modalias = "HotPRT",
  4. .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
  5. .bus_num = 1,
  6. .chip_select = 1,
  7. // .mode = SPI_MODE_0,
  8. .platform_data = 0,
  9. },
  10. };
spi_register_board_info(prt_spi_device, ARRAY_SIZE(prt_spi_device));

我自己實現了一個spi的驅動,然後需要創建一個設備文件,設備文件的創建是在probe中完成。
  1. static struct spi_driver prt_driver = {
  2. .driver = {
  3. .name = "HotPRT",
  4. .bus = &spi_bus_type,
  5. .owner = THIS_MODULE,
  6. },
  7. .probe = prt_probe,
  8. .remove = __devexit_p(prt_remove),
  9. };
  10. spi_register_driver(&prt_driver);
但是我開始一直觸發不了probe,於是找啊找,總算知道probe的調用過程了,如下:
  1. int spi_register_driver(struct spi_driver *sdrv)
  2. {
  3. sdrv->driver.bus = &spi_bus_type;
  4. if (sdrv->probe)
  5. sdrv->driver.probe = spi_drv_probe;
  6. if (sdrv->remove)
  7. sdrv->driver.remove = spi_drv_remove;
  8. if (sdrv->shutdown)
  9. sdrv->driver.shutdown = spi_drv_shutdown;
  10. return driver_register(&sdrv->driver);
  11. }

然後調用driver_register

  1. <pre name="code" class="cpp">int driver_register(struct device_driver *drv)
  2. {
  3. int ret;
  4. struct device_driver *other;
  5. BUG_ON(!drv->bus->p);
  6. if ((drv->bus->probe && drv->probe) ||
  7. (drv->bus->remove && drv->remove) ||
  8. (drv->bus->shutdown && drv->shutdown))
  9. printk(KERN_WARNING "Driver '%s' needs updating - please use "
  10. "bus_type methods\n", drv->name);
  11. other = driver_find(drv->name, drv->bus);
  12. if (other) {
  13. put_driver(other);
  14. printk(KERN_ERR "Error: Driver '%s' is already registered, "
  15. "aborting...\n", drv->name);
  16. return -EBUSY;
  17. }
  18. ret = bus_add_driver(drv);
  19. if (ret)
  20. return ret;
  21. ret = driver_add_groups(drv, drv->groups);
  22. if (ret)
  23. bus_remove_driver(drv);
  24. return ret;
  25. }

直接看bus_add_driver

  1. klist_init(&priv->klist_devices, NULL, NULL);
  2. priv->driver = drv;
  3. drv->p = priv;
  4. priv->kobj.kset = bus->p->drivers_kset;
  5. error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
  6. "%s", drv->name);
  7. if (error)
  8. goto out_unregister;
  9. if (drv->bus->p->drivers_autoprobe) {
  10. error = driver_attach(drv);
  11. if (error)
  12. goto out_unregister;
  13. }
  14. klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
  15. module_add_driver(drv->owner, drv);

這裏只截取一部分,最後調用的是driver_attach

  1. int driver_attach(struct device_driver * drv)
  2. {
  3. return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
  4. }

真正起作用的是__driver_attach:

  1. static int __driver_attach(struct device * dev, void * data)
  2. {
  3. 。。。
  4. if (!dev->driver)
  5. driver_probe_device(drv, dev);
  6. 。。。
  7. }


  1. int driver_probe_device(struct device_driver * drv, struct device * dev)
  2. {
  3. 。。。
  4. //1.先是判斷bus是否match:
  5. if (drv->bus->match && !drv->bus->match(dev, drv))
  6. goto done;
  7. //2.再具體執行probe:
  8. ret = really_probe(dev, drv);
  9. 。。。
  10. }

really_probe纔是我們要找的函數:
  1. static int really_probe(struct device *dev, struct device_driver *drv)
  2. {
  3. 。。。
  4. //1.先是調用的驅動所屬總線的probe函數:
  5. if (dev->bus->probe) {
  6. ret = dev->bus->probe(dev);
  7. if (ret)
  8. goto probe_failed;
  9. } else if (drv->probe) {
  10. //2.再調用你的驅動中的probe函數:
  11. ret = drv->probe(dev);
  12. if (ret)
  13. goto probe_failed;
  14. }
  15. 。。。
  16. }

其中,drv->probe(dev),纔是真正調用你的驅動實現的具體的probe函數。至此probe函數被調用。

在板文件中添加spi_board_info,並在板文件的init函數中調用spi_register_board_info(

prt_spi_device<span style="font-family: NSimSum; line-height: 1.5; ">,ARRAY_SIZE(</span><span style="font-family: NSimSum; ">prt_spi_device</span><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; line-height: 1.5; "><span style="line-height: 1.5; font-family: NSimSum; ">))</span></span><span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; line-height: 1.5; ">;</span>

//註冊spi_board_info。這個代碼會把spi_board_info註冊到鏈表board_list上。spi_device封裝了一個spi_master結構體,事實上spi_master的註冊會在spi_register_board_info之後,spi_master註冊的過程中會調用scan_boardinfo掃描board_list,找到掛接在它上面的spi設備,然後創建並註冊spi_device。

另外有關spi片選引腳的設置:1、直接將gpio配置成spi片選功能引腳。 2、將gpio配置成片選引腳,這個時候就需要設置結構體

  1. static void mx53_loco_gpio_spi_chipselect_active(int cspi_mode, int status,
  2. int chipselect)
  3. {
  4. switch (cspi_mode) {
  5. case 1: //ESPI1,bus_num 1
  6. switch (chipselect) {
  7. case 0x1://SS0 chipselect = .chip_select + 1
  8. {
  9. iomux_v3_cfg_t cspi_ss0 = MX53_PAD_CSI0_DAT7__ECSPI1_SS0;
  10. iomux_v3_cfg_t cspi_ss2 = MX53_PAD_KEY_ROW2__GPIO4_11;//SS2
  11. mxc_iomux_v3_setup_pad(cspi_ss0);
  12. mxc_iomux_v3_setup_pad(cspi_ss2);
  13. gpio_request(ECSPI1_CS2, "ecspi-cs2");
  14. gpio_direction_input(ECSPI1_CS2);
  15. }
  16. break;
  17. default:
  18. break;
  19. }
  20. case 2://ESPI2,bus_num 2
  21. switch (chipselect) {
  22. case 0x2://SS0
  23. {
  24. gpio_request(ECSPI2_SS1, "ecspi-cs1");
  25. gpio_direction_output(ECSPI2_SS1, 1);
  26. }
  27. break;
  28. case 0x3://SS1
  29. {
  30. gpio_request(ECSPI2_SS1, "ecspi-cs1");
  31. gpio_direction_output(ECSPI2_SS1, 0);
  32. }
  33. break;
  34. default:
  35. break;
  36. }
  37. default:
  38. break;
  39. }
  40. }
  41. static void mx53_loco_gpio_spi_chipselect_inactive(int cspi_mode, int status,
  42. int chipselect)
  43. {
  44. switch (cspi_mode) {
  45. case 1:
  46. switch (chipselect) {
  47. case 0x1:
  48. gpio_free(ECSPI1_CS2);
  49. break;
  50. default:
  51. break;
  52. }
  53. case 2:
  54. switch (chipselect) {
  55. case 0x2:
  56. {
  57. gpio_request(ECSPI2_SS1, "ecspi-cs1");
  58. gpio_direction_output(ECSPI2_SS1, 0);
  59. }
  60. break;
  61. case 0x3:
  62. {
  63. gpio_request(ECSPI2_SS1, "ecspi-cs1");
  64. gpio_direction_output(ECSPI2_SS1, 1);
  65. }
  66. break;
  67. default:
  68. break;
  69. }
  70. default:
  71. break;
  72. }
  73. }
  74. static struct mxc_spi_master mxcspi_data = {
  75. .maxchipselect = 4,
  76. .spi_version = 23,
  77. .chipselect_active = mx53_loco_gpio_spi_chipselect_active,
  78. .chipselect_inactive = mx53_loco_gpio_spi_chipselect_inactive,
  79. };
這樣設置後就不再需要手動設置片選的狀態了。

設備文件的生成:

1、用mknod手動生成

通過cat /proc/devices命令,可以看到主設備的編號,例如spi是153 ,如果想生成一個spi的子設備可以用 mknod /dev/spidev -c 153 1

mknod 設備名 設備類型 主設備號 子設備號

2、在驅動中就加入創建設備文件的代碼:

  1. struct device *devi;
  2. prt_class = class_create(THIS_MODULE, PRT_DEV_NAME);
  3. if(IS_ERR(prt_class))
  4. PTR_ERR(prt_class);
  5. devi = device_create(prt_class,NULL,MKDEV(PRT_DEV_MAJOR, 1), NULL, PRT_DEV_NAME);
  6. if(IS_ERR(devi))
  7. PTR_ERR(devi);
首先class_create用它來創建一個類,這個類存放於sysfs下面,再調用device_create(…)函數來在/dev目錄下創建相應的設備節點。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章