RK30SDK開發板驅動分析(一):platform device 的概念與注冊


做過51單片機或者ARM開發的人都知道,單片機內部都有自己的“片內外設”,比如UART,比如I2C,比如SPI等等。。。

寫單片機程序的時候,比如對於UART的驅動,我們都是在程序中直接寫一套函數,來操作相關的UART寄存器,在程序中的其它地方調用這些函數,完成串口的收發。 在小規模的單片機程序中,這樣做是再正常不過的。

但是,在規模龐大的LINUX內核中,要處理各種各樣的CPU,各種各樣的UART收發器,上述辦法就有心無力了:沒有靈活性,無法移植,接口不一致,很難想象有一個UART驅動程序能夠完成這個工作。

OK,有了上面的理解,我們再來看LINUX中的platform device和platform driver。 platform device 其實就是相當於“片內外設”,比如UART,內核剛開始啟動時,並不知道它所運行的CPU上面有哪些片內外設。有沒有UART? 有沒有I2C?等等這些問題,內核都是一無所知。而platform device的作用就是全面定義描述該CPU的所有片內外設,並注冊到系統中,每一個platform device都有一個唯一的名字name。

更進一步,將“片內外設”擴展到“板載外設”,一塊電路板上不止有CPU,還有很多其它設備通過GPIO,I2C/SPI等總線來連接,比如led燈,就需要一個GPIO來控制它的亮滅;比如繼電器,也需要一個GPIO來控制它的開合。 GPIO控制的開關設備是最簡單的,對應的驅動也是非常簡單的。

RK30SDK使用了ROCKCHIP的CPU,型號是RK3066。在RK30SDK中,我們以led驅動為例,首先查找它的platform device定義,在arch/arm/mach-rk30/board-rk30-box.c文件中,有如下的定義:

static struct platform_device rk29_device_gpio_leds = {
    .name    = "leds-gpio",
    .id    = -1,
    .dev    = {
        .platform_data  = &rk29_leds_pdata,
    },
};

這個設備的名稱是"leds-gpio",這個platform_data里面包含了各個不同led的名稱/GPIO資源占用情況,它的定義如下:

static struct gpio_led_platform_data rk29_leds_pdata = {
    .leds = rk29_leds,
    .num_leds = ARRAY_SIZE(rk29_leds),
};

似乎有很多led,定義成了一個數組?帶着疑問,我們找到rk29_leds的定義:

#ifdef CONFIG_LEDS_GPIO_PLATFORM
static struct gpio_led rk29_leds[] = {
#ifdef CONFIG_DISPLAY_KEY_LED_CONTROL
    #ifdef CONFIG_HDMI_RK30
    {
        .name = "hdmi-soc",
        .gpio = RK30_PIN4_PD7,
//        .default_trigger = "timer",
        .active_low = 0,
        .retain_state_suspended = 0,
        .default_state = LEDS_GPIO_DEFSTATE_OFF,
    },
    #endif
    #ifdef CONFIG_HDMI_ITV
    {
        .name = "hdmi-transmitter",
        .gpio = RK30_PIN4_PD2,
        .active_low = 0,
        .retain_state_suspended = 0,
        .default_state = LEDS_GPIO_DEFSTATE_OFF,
    },
    #endif

沒錯,這就是一個數組,只是有很多ifdef。不用管它,他們的意思是這里的源碼支持在make menuconfig里面進行配置,如果將來你設計的電路板上有hdmi發送的指示燈,就可以把CONFIG_HDMI_ITV打開,這樣led驅動里面就包含HDMI的發送指示燈了。gpio = RK30_PIN4_PD2這句話表示這個led燈是通過RK30_PIN4_PD2這個管腳進行控制的,如果你去看電路原理圖,這個管腳一定是連着一個led燈,如果在你設計的電路板上是另外的管腳,那么這里改成你自己的管腳名稱就行了。

至此,我們看完了RK上led的platform device定義了,一句話,它描述了RK開發板上led的所有控制IO口管腳,led名稱等信息。實際上,這些配置代碼是通過電路原理圖寫出來的,如果你能看懂原理圖,那你也能寫出這樣的代碼。

那么,platform device是如何告知內核自己的存在呢?我們繼續在board-rk30-box.c中尋找rk29_device_gpio_leds出現的地方:

static struct platform_device *devices[] __initdata = {
#ifdef CONFIG_BACKLIGHT_RK29_BL
    &rk29_device_backlight,
#endif
#ifdef CONFIG_FB_ROCKCHIP
    &device_fb,
#endif
#ifdef CONFIG_ION
    &device_ion,
#endif
#ifdef CONFIG_ANDROID_TIMED_GPIO
    &rk29_device_vibrator,
#endif
#ifdef CONFIG_LEDS_GPIO_PLATFORM
    &rk29_device_gpio_leds,
#endif

OK,看來我們的rk29_device_gpio_leds被包含在了devices數組中,而且是支持make menuconfig配置的,這是多么的合情合理啊!我們可以在menuconfig中打開或者關閉led,非常好。其它地方沒有再用到rk29_device_gpio_leds這個device了,我們需要繼續尋找devices數組是怎么被使用的:

static void __init machine_rk30_board_init(void)
{
    avs_init();
    gpio_request(POWER_ON_PIN, "poweronpin");
    gpio_direction_output(POWER_ON_PIN, GPIO_HIGH);
    
    pm_power_off = rk30_pm_power_off;
    
    rk30_i2c_register_board_info();
    spi_register_board_info(board_spi_devices, ARRAY_SIZE(board_spi_devices));
    platform_add_devices(devices, ARRAY_SIZE(devices));
    board_usb_detect_init(RK30_PIN6_PA3);

#ifdef CONFIG_WIFI_CONTROL_FUNC
    rk29sdk_wifi_bt_gpio_control_init();
#endif
}

哈哈,終於找到它了,看名字也知道這里是向內核注冊platform device了,關於platform_add_devices的工作原理這里就不說了,網上一大把,無非就是調用另外一個函數將devices數組中的每一個device分別注冊到系統中。這里上面的代碼,這里先打個埋伏:platform_add_devices是注冊所有的"platform"總線上的設備,"platform"是一個虛擬的總線,因為實際上這些外設並沒有掛在總線上,只是通過GPIO簡單的連接起來。而上面的rk30_i2c_register_board_info和spi_register_board_info則是分別注冊I2C總線和SPI總線上的設備了,邏輯上來說,他們和platform總線的概念是對等的。I2C是廣泛使用的,用來連接CPU和其它外部IC的總線,你所看到的各種sensor,EEPROM等都是通過I2C和CPU進行通信的。

在文件的末尾,有這樣的代碼:

MACHINE_START(RK30, "RK30board")
    .boot_params    = PLAT_PHYS_OFFSET + 0x800,
    .fixup        = rk30_fixup,
    .reserve    = &rk30_reserve,
    .map_io        = rk30_map_io,
    .init_irq    = rk30_init_irq,
    .timer        = &rk30_timer,
    .init_machine    = machine_rk30_board_init,
MACHINE_END

看樣子,一起都是從machine_rk30_board_init函數開始的,如果我們倒回來看,就知道這個led device是如何被注冊到內核里面的。

至於led device對應的platform driver,我們在下一篇分析。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM