淺析linux裝置驅動的clock(時鐘)的註冊

來源:互聯網
上載者:User
 

做嵌入式 linux 驅動的時候,難免會遇到clock,今天上網查閱關於clock的資料,發現網上大多數資料都是關於linux核心的時鐘機制,而不是關於Linux裝置驅動的時鐘。

於是將自己今天學習的經驗寫出來,跟大家交流交流,有不對的地方希望高手們指出。

我會以三星的smdkc220開發板為例。

分析代碼, 它將clock也看作一種裝置,使用前也要register註冊一下,但這個register又有別於一般的裝置,不會在sysfs下device,driver或bus等目錄下產生node。

先看註冊函數exynos4_register_clocks(void),在arch\arm\mach-exynos\Clock-exynos4.c檔案裡,

void __init exynos4_register_clocks(void)
{

        //........ 省略 

        s3c_register_clksrc(exynos4_clksrcs, ARRAY_SIZE(exynos4_clksrcs));
s3c_register_clocks(exynos4_init_clocks, ARRAY_SIZE(exynos4_init_clocks));

s3c_register_clocks(exynos4_init_clocks_off, ARRAY_SIZE(exynos4_init_clocks_off));
s3c_disable_clocks(exynos4_init_clocks_off, ARRAY_SIZE(exynos4_init_clocks_off));

s3c_register_clocks(exynos4_init_audss_clocks, ARRAY_SIZE(exynos4_init_audss_clocks));
s3c_disable_clocks(exynos4_init_audss_clocks, ARRAY_SIZE(exynos4_init_audss_clocks));

        

        //...........省略

        s3c_pwmclk_init();
}


三星將clock按裝置分類,比如jpeg, fimc, mipi-csi, mipi-dsi等裝置,就歸到exynos4_init_clocks_off這個數組中,比如exynos4_clksrcs數組裡,就是各種各樣的source clk。

不用管上面幾個register函數長得不一樣,其實他們的本質都是一樣的,只是他們給不同類的clock註冊,就用了不同的名字而已。


在執行register前,得先定義好clock,也就是各個數組的內容。

以exynos4_init_clocks_off為例,

static struct clk exynos4_init_clocks_off[] = {

                 //....省略

           {
.name = "csis",
.devname
= "s3c-csis.0",
.enable
= exynos4_clk_ip_cam_ctrl,
.ctrlbit
= (1 << 4),

       }, {
.name = "fimc",
.devname
= "s3c-fimc.0",
.enable
= exynos4_clk_ip_cam_ctrl,
.ctrlbit
= (1 << 0),

}, {
.name = "jpeg",
.enable
= exynos4_clk_ip_cam_ctrl,
.ctrlbit
= ((1 << 11) | (1 << 6)),

        }, {
.name = "dsim0",
.enable
= exynos4_clk_ip_lcd0_ctrl,
.ctrlbit
= (1 << 3),
}

        //..........省略

}


這裡,就定義了jpeg, fimc, mipi-dsi, mipi-csi這四種裝置的clk了,還給了他們clock名字(.name),enable的函數,還指出了在clock control寄存器裡哪一位是控制他們各自的(ctrlbit)。但這裡雖註冊一下,最近三星還加多了一個devname這個東東,這個是指裝置的名字,比如fimc這個裝置名稱字叫s3c-fimc.0, 但它的時鐘名字叫"fimc"。注意要將兩者區別開。以後註冊裝置的時候會用到(註冊clock是在註冊裝置之前先進行的)。


接下來,細看怎麼註冊吧。

void __init s3c_register_clocks(struct clk *clkp, int nr_clks)
{
int ret;

for (; nr_clks > 0; nr_clks--, clkp++) {
ret = s3c24xx_register_clock(clkp);

if (ret < 0) {
printk(KERN_ERR "Failed to register clock %s (%d)\n",
      clkp->name, ret);
}
}
}


回想起剛才exynos4_init_clocks_off[]數組吧,裡面定義了某些裝置的clock。通過參數 clkp 將數組傳進來,然後用一個for迴圈, 對裡面各個裝置的clock進行分別註冊。

這裡調用了s3c24xx_register_clock(clkp)來對一個裝置的clock進行註冊。註冊完後通過指標++,又指向下一下裝置的clock。


int s3c24xx_register_clock(struct clk *clk)
{
if (clk->enable == NULL)
clk->enable = clk_null_enable;

/* fill up the clk_lookup structure and register it*/
clk->lookup.dev_id = clk->devname;
clk->lookup.con_id = clk->name;
clk->lookup.clk = clk;
clkdev_add(&clk->lookup);

return 0;
}

看這個註冊函數,先判斷之前定義好的裝置clock裡,有沒有enable函數,沒有的話,給它一個空的,有名無實的空函數。

然後,還記得剛才定義clock的時候,還給了它clock name和device name吧? 將這兩個名字分別複製到 clk 結構體中 lookup結構體身上的成員變數裡。

這裡我們先看看clk結構體吧, 三星是這樣定義它的,跟原來linux中的不一樣。


struct clk {
struct list_head      list;
struct module        *owner;
struct clk           *parent;
const char           *name;
const char
*devname;
int      id;
int      usage;
unsigned long         rate;
unsigned long         ctrlbit;

struct clk_ops*ops;
int    (*enable)(struct clk *, int enable);
struct clk_lookuplookup;
#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS)
struct dentry
*dent; /* For visible tree hierarchy */
#endif
};

剛才定義裝置的clock的時候,name給了,devname也給了,enable函數也給了,ctrlbit也給了。但現在其他成員還是空的,以後慢慢會填 滿的。

現在先看看clk_lookup結構體,這個成員有什麼用呢?

顧名思義,lookup,肯定是尋找的時候用到的。那什麼時候尋找呢,找什麼呢?

在這裡,我們將註冊裝置和註冊裝置的clock分開操作了,註冊裝置的clock是一次過完成的,一次將各種裝置的clock註冊好的,但是我們裝置的註冊,是個別進行的。

所以,在我們註冊裝置的時候,要在這一堆先前已經註冊好的clock堆中,找到屬於自己的那個clock。這時候就要靠clk_lookup結構體了。


struct clk_lookup {
struct list_headnode;
const char
*dev_id;
const char
*con_id;
struct clk
*clk;
};

看這結構,裡面有dev_id, con_id兩個成員,它們分別代表了clock name和device name。所以又回到之前,我們要先將clock name和device name複製到這兩個成員裡才行。於是就有了

clk->lookup.dev_id = clk->devname;
clk->lookup.con_id = clk->name;

然後clk->lookup.clk = clk;也是同理。

再回頭看 clkdev_add(&clk->lookup);這句話是什麼意思呢?

先說說在註冊裝置時我們怎麼在clock堆 裡找到自己的clock吧。 是通過一條clock鏈的(listhead),這是一條雙向迴圈的鏈。這條鏈的每個結點是什麼呢?

就是clk_lookup結構體!

現在我們知道每個clk_lookup都包含了各自裝置的一些簡單資訊了吧(name,devname),這些資訊足夠豐富而又能將不同的clk_lookup結構體分開了。

clkdev_add(&clk->lookup); 這句話的意思就是, 將clk_lookup結構體,當成一個結點node,接到這條鏈的尾巴上。

你來看它的詳細就知道,

void clkdev_add(struct clk_lookup *cl)
{
mutex_lock(&clocks_mutex);
list_add_tail(&cl->node, &clocks);
mutex_unlock(&clocks_mutex);
}

又顧名思義,list_add_tail,就是加到尾巴上嘛。

那將一件東西接到鏈子上,那這個東西上應該有個小掛鈎或者其他什麼東西才行啊~

這個就是clk_lookup裡的node成員變數(在上面函數中就是 cl->node)

這個node是什麼東西,看它在clk_lookup裡的定義:

struct list_head
node;

我們知道,list_head結構,就像一個前面有個小掛鈎,後面又有個小掛鈎的東西,很多的list_head通過彼此的小掛鈎互相鉤住,就形成了一條鏈了。

於是,各個不同的clk_lookup結構體,就通過node,互相接起來,形成了一條鏈了。

這條鏈形如下:

                       clk_lookup1        clk_lookup2           clk_lookup3

                 .... ------node1-----------node2-----------------node3----------....

                                  |                         |                                 |

                             *name1            *name2                   *name3

                                  |                         |                                 |

                        *devname1        *devname2              *devname3

                                  |                         |                                 |

                                ...                        ...                               ...


這條鏈是一開始就定義了的,我們通過static LIST_HEAD(clocks); 定義一條靜態空鏈,供全體使用。然後一個結點一個結點地往上接。

將clk_lookup結構體串連到鏈上之後,也就是將各個裝置的clock串連到這條鏈上了,為什嗎?因為clk_lookup結構體裡包含了一個叫clk的成員變數。它就是clock。

至此,我們就完成了註冊了。

如果問註冊的目的是什嗎?

我想,就是形成一條鏈,以後讓在註冊裝置的時候尋找唄。




小弟知識淺陋,有不正確的地方請大牛們指出。也歡迎同好者一起來交流。郵箱alvinlee910@hotmail.com。轉載請註明出處。


相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.