leds-gpio driver

我們還是先看看platform device是如何define的

platform device 是如何定義的

  • example1

在板級驅動中定義, 通過platform_add_devices()函數將這個platform device註冊進系統.
arch\arm\plat-samsung\devs.c

struct platform_device s3c_device_hsmmc0 = {
    .name       = "s3c-sdhci",
    .id     = 0,
    .num_resources  = ARRAY_SIZE(s3c_hsmmc_resource),
    .resource   = s3c_hsmmc_resource,
    .dev        = {
        .dma_mask       = &samsung_device_dma_mask,
        .coherent_dma_mask  = DMA_BIT_MASK(32),
        .platform_data      = &s3c_hsmmc0_def_platdata,
    },
};

arch\arm\mach-s3c24xx\mach-smdk2416.c

static struct platform_device *smdk2416_devices[] __initdata = {
    &s3c_device_fb,
    &s3c_device_wdt,
    &s3c_device_ohci,
    &s3c_device_i2c0,
    &s3c_device_hsmmc0,
    &s3c_device_hsmmc1,
    &s3c_device_usb_hsudc,
    &s3c2443_device_dma,
};

並最終通過platform_add_devices()函數將這個platform device註冊進系統。
arch\arm\mach-s3c24xx\mach-smdk2416.c

static void __init smdk2416_machine_init(void)
{
    //...

    platform_add_devices(smdk2416_devices, ARRAY_SIZE(smdk2416_devices));

    //...
}
  • example2

在在板級驅動中定義,通過platform_device_register()函數將這個platform device註冊進系統.
arch\arm\mach-imx\mach-imx6sx.c

platform_device_register_simple("imx6q-cpufreq", -1, NULL, 0);

arch\arm\mach-imx\mach-imx6q.c

static struct platform_device imx6q_cpufreq_pdev = {
    .name = "imx6q-cpufreq",
};

static void __init imx6q_init_late(void)
{
    //...
        platform_device_register(&imx6q_cpufreq_pdev);
    // ...
}
  • example3

通過設備樹定義.
在早期的ARM Linux Kernel中,板級細節使用代碼形式,存放在arch/arm/目錄。名字通常爲:plat-xxxx或者mach-xxxx,內容多爲特定板上細節信息,如platform, i2c_board_info, spi_board_info和各類資源數據。

但這類目錄對Linux Kernel來說,意義非常有限,因爲板級代碼只對相應開發板有用。使用這種方法顯然不是一個好辦法。與此同時PowerPC等其它架構已經在使用一種新的方法:Flattened Device Tree(FDT)。Device Tree是一種描述硬件的數據結構。它包含板級硬件細節信息,這樣,通過Device Tree,就可以把硬件信息傳遞給Kernel,而不需要再硬編碼了。

arch\arm\boot\dts\bcm2710-rpi-3-b.dts

&leds {
    act_led: act {
        label = "led0";
        linux,default-trigger = "mmc0";
        gpios = <&virtgpio 0 0>;
    };

    pwr_led: pwr {
        label = "led1";
        linux,default-trigger = "input";
        gpios = <&expgpio 7 0>;
    };
};

至於設備樹中定義的platform_device是如何被kernel解析並定義的, 參考
Device Tree(三):代碼分析

machine初始化的代碼可以沿着start_kernel->rest_init->kernel_init->kernel_init_freeable->do_basic_setup->do_initcalls路徑尋找。在do_initcalls函數中,kernel會依次執行各個initcall函數,在這個過程中,會調用customize_machine,

在這個函數中,一般會調用machine描述符中的init_machine callback函數來把各種Device Tree中定義的platform device設備節點加入到系統(即platform bus的所有的子節點,對於device tree中其他的設備節點,需要在各自bus controller初始化的時候自行處理)。如果machine描述符中沒有定義init_machine函數,那麼直接調用of_platform_populate把所有的platform device加入到kernel中。

不過這裏好像和arch\arm\mach-bcm\board_bcm2835.c對應不上

但是內核中處理解析dts的機制是一樣的
of_platform_default_populate_init
of_platform_device_create
of_platform_device_create_pdata
of_device_add

static int __init of_platform_default_populate_init(void)
{
    struct device_node *node;
    if (!of_have_populated_dt())
        return -ENODEV;
    /*
     * Handle certain compatibles explicitly, since we don't want to create
     * platform_devices for every node in /reserved-memory with a
     * "compatible",
     */
    for_each_matching_node(node, reserved_mem_matches)
        of_platform_device_create(node, NULL, NULL);
    node = of_find_node_by_path("/firmware");
    if (node) {
        of_platform_populate(node, NULL, NULL, NULL);
        of_node_put(node);
    }
    /* Populate everything else. */
    of_platform_default_populate(NULL, NULL, NULL);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章