linux设备/驱动的注册

Platform_device_register向系统注册设备; Platform_driver_register向系统注册驱动,过程中在系统寻找注册的设备(根据.name),找到后运行.probe进行初始化。 所以Platform_device_register必须先于Platform_driver_register执行。

1. Platform_device_register执行流程。

1)zx297520v3-device.c中zx29_device_table中定义了所有的设备;

 #ifdef CONFIG_MTD_ZXIC_SPIFC

    
  static struct resource spi_nand_resource[] = {
    
       [0] = {
    
       .start  = ZX_SPIFC0_BASE,
    
       .end    = ZX_SPIFC0_BASE + SZ_4K - 1,
    
       .flags  = IORESOURCE_MEM,
    
       .name   = "spifc_reg",
    
       },
    
       [2] = {
    
       .start  = SPI_FC0_INT,
    
       .end    = SPI_FC0_INT,
    
       .flags  = IORESOURCE_IRQ,
    
  
    
       },
    
   };
    
 #endif
 #ifdef CONFIG_MTD_ZXIC_SPIFC

    
 struct platform_device zx29_device_spi_nand = {
    
     .name       = "spi-nand-dt",
    
     .id     = -1,
    
     .num_resources  = ARRAY_SIZE(spi_nand_resource),
    
     .resource   = spi_nand_resource,
    
 };
    
 #endif
 struct platform_device *zx29_device_table[] __initdata={

    
 #ifdef CONFIG_SERIAL_ZX29_UART
    
     &zx29_uart0_device,
    
     &zx29_uart1_device,
    
     &zx29_uart2_device,
    
 #endif
    
 #ifdef CONFIG_MTD_NAND_DENALI
    
     &zx29_device_nand,
    
 #endif
    
 #ifdef CONFIG_DWC_OTG_USB
    
     &zx29_usb0_device,
    
 #endif
    
 #ifdef CONFIG_USB_DWC_OTG_HCD
    
     &zx29_usb1_device,
    
 #endif
    
 #ifdef CONFIG_MTD_ZXIC_SPIFC
    
     &zx29_device_spi_nand,
    
 #endif
    
 #ifdef CONFIG_ZX29_DMA
    
     &zx29_dma_device,
    
 #endif
    
 ......
    
 }

2)board-zx297520v3.c中board_init()函数中调用platform_add_devices;

 static void __init board_init(void)

    
 {
    
     ......
    
     platform_add_devices(zx29_device_table, zx29_device_table_num);
    
     ......
    
 }

3)platform_add_devices中对table进行遍历,调用platform_device_register进行注册;

 int platform_add_devices(struct platform_device **devs, int num)

    
 {
    
     int i, ret = 0;
    
  
    
     for (i = 0; i < num; i++) {
    
     ret = platform_device_register(devs[i]);
    
     if (ret) {
    
         while (--i >= 0)
    
             platform_device_unregister(devs[i]);
    
         break;
    
     }
    
     }
    
  
    
     return ret;
    
 }

4)platform_device_register先调用device_initialize,再调用platform_device_add; device_initialize主要是初始化设备结构体,包括kobject、mutex、spin_lock、list、pm初始化等,方便后面的platform_device_add使用; platform_device_add中先调用insert_resource(p,r)将platform资源(上面截图的resource)添加进内核,由内核进行统一管理,然后再调用device_add()。

2. Platform_driver_register执行流程。

1)调用Platform_driver_register注册驱动;

 static const struct of_device_id spifc_nand_dt_ids[] = {

    
     { .compatible = "spifc,spifc-nand-dt" },
    
     { /* sentinel */ }
    
 };
    
  
    
 MODULE_DEVICE_TABLE(of, spifc_nand_dt_ids);
    
  
    
 static struct platform_driver spifc_dt_driver = 
    
 {
    
  
    
     .probe      = spifc_drv_probe,
    
     .remove     = spifc_drv_remove,
    
     .driver     = {
    
     .name   = "spi-nand-dt",
    
     .owner  = THIS_MODULE,
    
     .of_match_table = spifc_nand_dt_ids,
    
     },
    
 };
    
  
    
 module_platform_driver(spifc_dt_driver);

module_platform_driver(xxx);

最终展开后就是如下形式:

static int __init xxx_init(void)

{

return platform_driver_register(&xxx);

}

module_init(xxx_init);

static void __exit xxx_init(void)

{

return platform_driver_unregister(&xxx);

}

module_exit(xxx_exit);

2)platform_driver_register(&xx_driver) 会向系统注册xx_driver这个驱动程序,这个函数会根据 xx_driver中的.name内容,搜索系统注册的device中有没有这个platform_device,如果有,就会执行 platform_driver(也就是xx_driver的类型)中的.probe函数,即上述截图的spifc_drv_probe()函数。

I2C设备/驱动的注册

1. 设备的注册

1)zx297520v3-devices.c中定义了需要添加的I2C设备;

 #ifdef CONFIG_MFD_ZX234290_I2C

    
 static struct  zx234290_board zx234290_platform = {
    
     .irq_gpio_num       =   PIN_PMU_INT, //EX0_INT,
    
     .irq_gpio_func      =   PMU_INT_FUNC_SEL,
    
     .pshold_gpio_num    =   PIN_PMU_PSHOLD,
    
     .pshold_gpio_func   =   PMU_PSHOLD_FUNC_SEL,
    
     .irq_base   =   ENT_ZX234290_IRQ_BASE,
    
 };
    
 #endif
 static struct i2c_board_info zx29_i2c0_devices[] = {

    
 #ifdef CONFIG_MFD_ZX234290_I2C
    
     [0]={
    
     I2C_BOARD_INFO("zx234290", 0x12),
    
     .irq        = EX0_INT,
    
     .platform_data  = &zx234290_platform,
    
     },
    
 #endif
    
  
    
 };
 void __init i2c_add_devices(void)

    
 {
    
     unsigned  devices_num = 0;
    
     int ret = 0;
    
  
    
     /* *i2c devices on bus 0
    
       */
    
     devices_num = ARRAY_SIZE(zx29_i2c0_devices);
    
     if (devices_num){
    
     ret = i2c_register_board_info(0,zx29_i2c0_devices, devices_num);
    
     if(ret)
    
         BUG();
    
     }
    
  
    
     /* *i2c devices on bus 1
    
       */
    
     devices_num = ARRAY_SIZE(zx29_i2c1_devices);
    
     if (devices_num){
    
     ret = i2c_register_board_info(1,zx29_i2c1_devices, devices_num);
    
     if(ret)
    
         BUG();
    
     }
    
 }

3)i2c_add_devices里面将各个设备的信息插入到__i2c_board_list的list中;

4)在I2C驱动初始化时,例如i2c-zx29.c中,将I2C的驱动注册进platform驱动;

 static struct platform_driver zx29_i2c_driver = {

    
     .probe      = zx29_i2c_probe,
    
     .remove     = zx29_i2c_remove,
    
 #ifdef CONFIG_PM
    
     .suspend    = zx29_i2c_suspend,
    
     .resume     = zx29_i2c_resume,
    
 #endif
    
     .driver     = {
    
     .owner  = THIS_MODULE,
    
     .name   = "zx29_i2c",
    
     .of_match_table = zx29_i2c_match,
    
     },
    
 };
    
  
    
 static int __init i2c_adap_zx29_init(void)
    
 {
    
     int ret;
    
  
    
     ret=platform_driver_register(&zx29_i2c_driver);
    
     if (ret<0) {
    
     printk(KERN_INFO "zx29 i2c driver register fail\n");
    
     }
    
     return ret;
    
 }
    
 subsys_initcall(i2c_adap_zx29_init);

5)在平台驱动的probe函数中,通过调用i2c_add_numbered_adapter()-->i2c_register_adapter()-->i2c_scan_static_board_info()-->i2c_new_device()-->device_register()完成设备的注册的。

2. 驱动的注册

1)通过调用i2c_add_driver添加对应的驱动;

 #if 1

    
 static struct i2c_driver zx234290_i2c_driver = {
    
     .driver = {
    
        .name = "zx234290",
    
        .owner = THIS_MODULE,
    
     },
    
     .probe = zx234290_i2c_probe,
    
     .remove = zx234290_i2c_remove,
    
     .id_table = zx234290_i2c_id,
    
 };
    
 #endif
    
  
    
 static int __init zx234290_i2c_init(void)
    
 {
    
     int ret;
    
  
    
     ret = i2c_add_driver(&zx234290_i2c_driver);
    
     if (ret != 0)
    
     pr_err("Failed to register ZX234290 I2C driver: %d\n", ret);
    
  
    
     return ret;
    
 }
    
 /* init early so consumer devices can complete system boot */
    
 subsys_initcall(zx234290_i2c_init);

2)I2c_add_driver()-->i2c_register_driver()-->driver_register()注册驱动,里面会进行驱动与设备的匹配,匹配成功后,会调用到驱动注册的probe函数。

SPI设备/驱动的注册

1.设备的注册

1)zx297520v3-devices.c中定义了需要添加的SPI设备;

 static struct spi_board_info zx29_spi_devices[] = {

    
 #ifdef CONFIG_FB_LEADT15DS26
    
     {
    
     .modalias       = "lead_t15ds26",
    
     .bus_num        = 0,
    
     .chip_select    = 0,
    
     .max_speed_hz   = 13000000,
    
     .mode           = SPI_MODE_3,
    
     .platform_data  = &lead_lcd_platform,
    
     .controller_data = &lead_lcd_chip_info,
    
     },
    
 #endif
    
  
    
 #ifdef CONFIG_TRANSCEIVER_XN297L
    
     {
    
     .modalias       = "xn297l_tx",
    
     .bus_num        = 0,
    
     .chip_select    = 0,
    
     .max_speed_hz   = 1*1000*1000,
    
     .mode           = SPI_MODE_0,
    
     .controller_data = 25,
    
     },
    
 #endif
    
  
    
 #ifdef CONFIG_TRANSCEIVER_XN297L
    
     {
    
     .modalias       = "xn297l_rx",
    
     .bus_num        = 1,
    
     .chip_select    = 0,
    
     .max_speed_hz   = 1*1000*1000,
    
     .mode           = SPI_MODE_0,
    
     .controller_data = 87,
    
     },
    
 #endif
    
 };

2)Board-zx297520v3.c中调用spi_add_devices()函数添加SPI设备;

3)spi_add_devices()中通过调用spi_register_board_info来进行设备的注册;

 void __init spi_add_devices(void)

    
 {
    
     unsigned  devices_num = ARRAY_SIZE(zx29_spi_devices);
    
     int ret = 0;
    
     printk("spi_register_board_info success,devices_num=%d\n",devices_num);
    
     if (devices_num){
    
     ret = spi_register_board_info(zx29_spi_devices, devices_num);
    
     printk("spi_register_board_info success,ret=%d\n",ret);
    
     if(ret)
    
         BUG();
    
     }
    
 }

4)spi_register_board_info中遍历spi设备表中的所有设备,并通过spi_match_master_to_boardinfo()-->spi_new_device()-->spi_add_device()-->device_add()来进行设备的注册;

2. 驱动的注册

1)调用spi_register_driver注册spi驱动;

 static int __init xn297l_init(void)

    
 {
    
     int ret;
    
     int minor = 0;
    
  
    
     XN_DATA("register char dev for xn297l.");
    
  
    
     ret = spi_register_driver(&xn297l_spi_tx_driver);
    
     if (ret != 0){
    
     XN_ERR("failed to register xn297l_tx_spi_driver : %d", ret);
    
     return ret;
    
     }
    
  
    
     ret = spi_register_driver(&xn297l_spi_rx_driver);
    
     if (ret != 0){
    
     XN_ERR("failed to register xn297l_rx_spi_driver : %d", ret);
    
     return ret;
    
     }
    
     }
 /*spi driver begin*/

    
 static const struct spi_device_id xn297l_tx_id[] = {
    
     {"xn297l_tx", 0 },
    
     { }
    
 };
    
  
    
 MODULE_DEVICE_TABLE(spi, xn297l_tx_id);
    
  
    
 static struct spi_driver xn297l_spi_tx_driver = {
    
     .driver = {
    
     .name = "xn297l_tx",
    
     .owner = THIS_MODULE,
    
     },
    
     .probe = xn297l_tx_probe,
    
     .remove = __devexit_p(xn297l_tx_remove),
    
     .id_table = xn297l_tx_id,
    
 };
    
  
    
 static const struct spi_device_id xn297l_rx_id[] = {
    
     {"xn297l_rx", 1 },
    
     { }
    
 };
    
  
    
 MODULE_DEVICE_TABLE(spi, xn297l_rx_id);
    
  
    
 static struct spi_driver xn297l_spi_rx_driver = {
    
     .driver = {
    
     .name = "xn297l_rx",
    
     .owner = THIS_MODULE,
    
     },
    
     .probe = xn297l_rx_probe,
    
     .remove = __devexit_p(xn297l_rx_remove),
    
     .id_table = xn297l_rx_id,
    
 };
    
 /*spi driver end*/

2)spi_register_driver里面会调用driver_register进行驱动的注册,里面会进行驱动与设备的匹配,匹配成功后,会调用到驱动注册的probe函数;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值