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

};

2)Board-zx297520v3.c中調用i2c_add_devices()函數添加I2C設備;

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函數;

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