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);

扫描二维码关注公众号,回复: 1853391 查看本文章
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 = 110001000,
.mode = SPI_MODE_0,
.controller_data = 25,
},
#endif

#ifdef CONFIG_TRANSCEIVER_XN297L
{
.modalias = "xn297l_rx",
.bus_num = 1,
.chip_select = 0,
.max_speed_hz = 110001000,
.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函数;

猜你喜欢

转载自blog.51cto.com/13824435/2135671