當開發一款新的LCD驅動時往往需要關注的是LCD最底層的驅動,即是LCD屏的初始化、亮屏、熄屏以及背光操作。個人覺得以下幾個問題有必要弄清楚(參考Qualcomm芯片上的驅動代碼):
1、如何添加一款新屏驅動
下面以東芝屏為例(參照源代碼mipi_toshiba_video_wvga_pt.c mipi_toshiba.c)
模塊初始化:module_init(mipi_video_toshiba_wvga_pt_init);
在mipi_video_toshiba_wvga_pt_init()中主要工作是設置LCD屏的參數,然后注冊一個名為mipi_toshiba的平台驅動和平台設備。在注冊平台設備時將LCD亮屏、熄屏以及背光操作添加到平台設備中。在mipi_toshiba的平台驅動中利用probe函數調用msm_fb_add_device()。當需要添加一款新屏的驅動時最主要的工作就是注冊一個相關的平台驅動和平台設備,可以參照上面的兩個源文件。這里需要說明一下:msm_fb_add_device()函數里定義了一個非常重要的數據結構msm_fb_data_type mfd,這個結構里包括了fb_info,還定義了panel有關的變量。
2、LCD驅動是如何依次打開MDP、MIPI DSI和LCD PANEL
首先在驅動里注冊了三個平台設備msm_fb,mdp,mipi_dsi,然后再對應平台驅動probe的時候把各自設備的指針鏈接到一起,看下面的調用關系:
mdp_probe(pdev)
|
|--->msm_fb_dev = platform_device_alloc('msm_fb', pdev->id)
|
|
|--->pdata = msm_fb_dev->dev.platform_data
|
|
|--->pdata->on = mdp_dsi_video_on
|
|
|--->pdata->off = mdp_dsi_video_off
|
|
|--->pdata->next = pdev
mipi_dsi_probe(pdev)
|
|--->mdp_dev = platform_device_alloc('mdp', pdev->id)
|
|
|--->pdata = mdp_dev->dev.platform_data
|
|
|--->pdata->on = mipi_dsi_on
|
|
|--->pdata->off = mipi_dsi_off
|
|
|--->pdata->next = pdev
mipi_toshiba_lcd_probe(pdev)
|
|
msm_fb_add_device(pdev)
|
|
|--->pdata = pdev->dev.platform_data
|
|
|--->this_dev = msm_fb_device_alloc(pdata, type, id)
|
|
|--->this_dev = platform_device_alloc()
|
|
|--->platform_device_add_data(this_dev, pdata, ...)
當pdata->next指向this_dev時,執行pdata->on,pdata->off時,即調用到mipi_toshiba_lcd_on和mipi_toshiba_lcd_off。
從上面的分析來看,從MDP到panel的調用順序應該是:mdp_dsi_video_on-->mipi_dsi_on-->mipi_toshiba_lcd_on。msm_fb_blank_sub()是通過mfd->pdev->dev.platform_data來獲取pdata,再調用pdata->on(),從而完成上面的調用,在這里mfd->pdev->dev.platform_data指向的就是msm_fb設備的數據。
3、mfd是如何保存msm_fb設備的指針
msm_fb_add_device(pdev)
|
|--->fbi=framebuffer_alloc(sizeof(struct msm_fb_data_type),NULL)
|
|
|--->mfd=(struct msm_fb_data_type *)fbi->par
|
|
|--->mfd->pdev=this_dev (this_dev即mipi_dsi)
|
|
|--->platform_set_drvdata(this_dev,mfd)
mipi_dsi_probe(pdev)
|
|--->mfd=platform_get_drvdata(pdev)
|
|
|--->mfd->pdev=mdp_dev
|
|
|--->platform_set_drvdata(mdp_dev,mfd)
mdp_probe(pdev)
|
|--->mfd=platform_get_drvdata(pdev)
|
|
|--->mfd->pdev=msm_fb_dev
|
|
|--->platform_set_drvdata(msm_fb_dev,mfd)
從上面的調用關系來看,mfd->pdev最終指向了平台設備msm_fb,值得一提的是,在這幾個函數中完成了mfd結構的填充。
int panel_next_on(struct platform_device *pdev)
每次執行完一個->on后執行panel_next_on,執行下一個->on