现在的位置: 首页 > 综合 > 正文

Android学习之 Platform总线 2

2013年10月01日 ⁄ 综合 ⁄ 共 7621字 ⁄ 字号 评论关闭

1       基于Platform总线的驱动开发流程

·定义初始化platform bus

·定义各种platform devices

·注册各种platform devices

·定义相关platform driver

·注册相关platform driver

·操作相关设备

 

基于Mx53QSB为例,实现流程如下:

1.1 初始化platform_bus

初始化代码在kernel_imx/drivers/base/platform.c#L28

struct device platform_bus = {

       .init_name  = "platform",

};

EXPORT_SYMBOL_GPL(platform_bus);

 

 

int __init platform_bus_init(void)   #L1020

{

       int error;

 

       early_platform_cleanup();

 

       error = device_register(&platform_bus);

       if (error)

              return error;

       error =  bus_register(&platform_bus_type);

       if (error)

              device_unregister(&platform_bus);

       return error;

}

 

该函数创建了一个名为“platform”的设备,后续platform的设备都会以此为parent,在sysfs中表示为:所有platform类型的设备都会添加在platform_bus所代表的目录下,即/sys/devices/platform

 

Platform_bus必须在系统注册任何platform driverplatform device之前初始化,实现如下:

Kernel_imx/drivers/base/Init.c  #L20

/**

 * driver_init - initialize driver model.

 *

 * Call the driver model init functions to initialize their

 * subsystems. Called early from init/main.c.

 */

void __init driver_init(void)

{

       /* These are the core pieces */

       devtmpfs_init();

       devices_init();

       buses_init();

       classes_init();

       firmware_init();

       hypervisor_init();

 

       /* These are also core pieces, but must come after the

        * core core pieces.

        */

       platform_bus_init();

       system_bus_init();

       cpu_dev_init();

       memory_dev_init();

}

start_kernel(init/main.c#L539) >>rest_init(init/main.c#L429)>>kenel_init(init/main.c#L866)>>do_basic_setup(init/Main.c#L797)>>driver_init>>platform_bus_init

 

 

platform driver platform devices 的初始化是在do_initcallsdo_basic_setup(init/Main.c#L806处调用))中进行的的。

1.2 定义platform_device

Kernel_imx/arch/arm/mach-mx5/Devices.c #L649中定义了系统的资源,大部分板级资源都在这里集中定义。

static struct resource mxci2c1_resources[] = {

       {

              .start = I2C1_BASE_ADDR,

              .end = I2C1_BASE_ADDR + SZ_4K - 1,

              .flags = IORESOURCE_MEM,

       },

       {

              .start = MXC_INT_I2C1,

              .end = MXC_INT_I2C1,

              .flags = IORESOURCE_IRQ,

       },

};

 

static struct resource mxci2c2_resources[] = {

       {

              .start = I2C2_BASE_ADDR,

              .end = I2C2_BASE_ADDR + SZ_4K - 1,

              .flags = IORESOURCE_MEM,

       },

       {

              .start = MXC_INT_I2C2,

              .end = MXC_INT_I2C2,

              .flags = IORESOURCE_IRQ,

       },

};

 

static struct resource mxci2c3_resources[] = {

       {

              .start = I2C3_BASE_ADDR,

              .end = I2C3_BASE_ADDR + SZ_4K - 1,

              .flags = IORESOURCE_MEM,

              },

       {

              .start = MXC_INT_I2C3,

              .end = MXC_INT_I2C3,

              .flags = IORESOURCE_IRQ,

              },

};

 

struct platform_device mxci2c_devices[] = {

       {

              .name = "imx-i2c",

              .id = 0,

              .num_resources = ARRAY_SIZE(mxci2c1_resources),

              .resource = mxci2c1_resources,

       },

       {

              .name = "imx-i2c",

              .id = 1,

              .num_resources = ARRAY_SIZE(mxci2c2_resources),

              .resource = mxci2c2_resources,

       },

       {

              .name = "imx-i2c",

              .id = 2,

              .num_resources = ARRAY_SIZE(mxci2c3_resources),

              .resource = mxci2c3_resources,

       },

};
设备名称为imx-i2c.id说明设备的序号,共有三个, mxci2c1_resourcesmxci2c2_resourcesmxci2c3_resources分别对应设备的资源,资源包括I2c控制器的寄存器空间和中断信息。

 

1.3 注册platform_device

定义了platflat_device后,需要添加到系统中,就可以调用函数mxc_register_device

Kernel_imx/arch /arm/plat-mxc.c#L108

int __init mxc_register_device(struct platform_device *pdev, void *data)

{

       int ret;

 

       pdev->dev.platform_data = data;

 

       ret = platform_device_register(pdev);

       if (ret)

              pr_debug("Unable to register platform device '%s': %d/n",

                      pdev->name, ret);

 

       return ret;

}

mxc_board_init()函数中,调用mxc_register_device对一些外设进行注册。

static void __init mxc_board_init(void)

{

       mxc_ipu_data.di_clk[0] = clk_get(NULL, "ipu_di0_clk");

       mxc_ipu_data.di_clk[1] = clk_get(NULL, "ipu_di1_clk");

       mxc_ipu_data.csi_clk[0] = clk_get(NULL, "ssi_ext1_clk");

       mxc_spdif_data.spdif_core_clk = clk_get(NULL, "spdif_xtal_clk");

       clk_put(mxc_spdif_data.spdif_core_clk);

 

       mxcsdhc3_device.resource[2].start = IOMUX_TO_IRQ_V3(SD3_CD);

       mxcsdhc3_device.resource[2].end = IOMUX_TO_IRQ_V3(SD3_CD);

 

       mxc_cpu_common_init();

       mx53_loco_io_init();

 

       mxc_register_device(&mxc_dma_device, NULL);

       mxc_register_device(&mxc_wdt_device, NULL);

       mxc_register_device(&mxci2c_devices[0], &mxci2c_data);

       mxc_register_device(&mxci2c_devices[1], &mxci2c_data);

 

       mx53_loco_init_da9052();

 

       mxc_register_device(&mxc_rtc_device, NULL);

       mxc_register_device(&mxc_ipu_device, &mxc_ipu_data);

       mxc_register_device(&mxc_ldb_device, &ldb_data);

       mxc_register_device(&mxc_tve_device, &tve_data);

       mxc_register_device(&mxcvpu_device, &mxc_vpu_data);

       mxc_register_device(&gpu_device, &z160_revision);

       mxc_register_device(&mxcscc_device, NULL);

       mxc_register_device(&mxc_dvfs_core_device, &dvfs_core_data);

       mxc_register_device(&busfreq_device, &bus_freq_data);

       mxc_register_device(&mxc_iim_device, &iim_data);

       mxc_register_device(&mxc_pwm2_device, NULL);

       mxc_register_device(&mxc_pwm1_backlight_device, &mxc_pwm_backlight_data);

       mxc_register_device(&mxcsdhc1_device, &mmc1_data);

       mxc_register_device(&mxcsdhc3_device, &mmc3_data);

       mxc_register_device(&mxc_ssi1_device, NULL);

       mxc_register_device(&mxc_ssi2_device, NULL);

       mxc_register_device(&mxc_alsa_spdif_device, &mxc_spdif_data);

       mxc_register_device(&ahci_fsl_device, &sata_data);

       mxc_register_device(&mxc_fec_device, &fec_data);

       /* ASRC is only available for MX53 TO2.0 */

       if (cpu_is_mx53_rev(CHIP_REV_2_0) >= 1) {

              mxc_asrc_data.asrc_core_clk = clk_get(NULL, "asrc_clk");

              clk_put(mxc_asrc_data.asrc_core_clk);

              mxc_asrc_data.asrc_audio_clk = clk_get(NULL, "asrc_serial_clk");

              clk_set_rate(mxc_asrc_data.asrc_audio_clk, 1190000);

              clk_put(mxc_asrc_data.asrc_audio_clk);

              mxc_register_device(&mxc_asrc_device, &mxc_asrc_data);

       }

 

       i2c_register_board_info(0, mxc_i2c0_board_info,

                            ARRAY_SIZE(mxc_i2c0_board_info));

       i2c_register_board_info(1, mxc_i2c1_board_info,

                            ARRAY_SIZE(mxc_i2c1_board_info));

 

       mxc_register_device(&mxc_sgtl5000_device, &sgtl5000_data);

       mx5_usb_dr_init();

       mx5_set_host1_vbus_func(mx53_loco_usbh1_vbus);

       mx5_usbh1_init();

       mxc_register_device(&mxc_v4l2_device, NULL);

       mxc_register_device(&mxc_v4l2out_device, NULL);

       mxc_register_device(&mxc_android_pmem_device, &android_pmem_data);

       mxc_register_device(&mxc_android_pmem_gpu_device, &android_pmem_gpu_data);

       mxc_register_device(&usb_mass_storage_device, &mass_storage_data);

       mxc_register_device(&usb_rndis_device, &rndis_data);

       mxc_register_device(&android_usb_device, &android_usb_data);

       loco_add_device_buttons();

}

 

mxc_board_init定义在Mx53_LOCO板子的MACHINE_START中。

MACHINE_START(MX53_LOCO, "Freescale MX53 LOCO Board")

       /* Maintainer: Freescale Semiconductor, Inc. */

       .fixup = fixup_mxc_board,

       .map_io = mx5_map_io,

       .init_irq = mx5_init_irq,

       .init_machine = mxc_board_init,

       .timer = &mxc_timer,

MACHINE_END

利用mxc_register_device将系统资源注册进系统,在此之前platform bus 需要初始化成功,否则无法将platform devices挂接到platform bus上。为了保证platform drvier初始化时,相关platform资源已经注册进系统,mxc_board_init需要很早执行,而其作为init_machine时,将优先于系统所有驱动的初始化。

调用顺序如下:start_kernel(init/main.c#L539) >>setup_arch(arch/arm/kernel/setup.c#L670)>> init_machine(arch/arm/kernel/setup.c#L742)>> customize_machine(arch/arm/kernel/setup.c#L663)>>arch_initcall(arch/arm/kernel/setup.c#L670)

 

void __init setup_arch(char **cmdline_p)

{

        struct tag *tags = (struct tag *)&init_tags;

        struct machine_desc *mdesc;

        char *from = default_command_line;

 

        unwind_init();

 

抱歉!评论已关闭.