日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

linux內(nèi)核中的GPIO系統(tǒng)之(2):pin control subsystem

 風之library 2014-08-13

作者:linuxer 發(fā)布于:2014-7-26 18:24 分類:Linux內(nèi)核分析

一、前言

在linux2.6內(nèi)核上工作的嵌入式軟件工程師在pin control上都會遇到這樣的狀況:

(1)啟動一個新的項目后,需要根據(jù)硬件平臺的設定進行pin control相關(guān)的編碼。例如:在bootloader中建立一個大的table,描述各個引腳的配置和缺省狀態(tài)。此外,由于SOC的引腳是可以復用的,因此在各個具體的driver中,也可能會對引腳進行的配置。這些工作都是比較繁瑣的工作,需要極大的耐心和細致度。

(2)發(fā)現(xiàn)某個driver不能正常工作,辛辛苦苦debug后發(fā)現(xiàn)僅僅是因為其他的driver在初始化的過程中修改了引腳的配置,導致自己的driver無法正常工作

(3)即便是主CPU是一樣的項目,但是由于外設的不同,我們也不能使用一個kernel image,而是必須要修改代碼(這些代碼主要是board-specific startup code)

(4)代碼不是非常的整潔,cut-and-pasted代碼滿天飛,linux中的冗余代碼太多

作為一個嵌入式軟件工程師,項目做多了,接觸的CPU就多了,摔的跤就多了,之后自然會去思考,我們是否可以解決上面的問題呢?此外,對于基于ARM core那些SOC,雖然表面上看起來各個SOC各不相同,但是在pin control上還有很多相同的內(nèi)容的,是否可以把它抽取出來,進行進一步的抽象呢?新版本中的內(nèi)核(本文以3.14版本內(nèi)核為例)提出了pin control subsystem來解決這些問題。

 

二、pin control subsystem的文件列表

1、源文件列表

我們整理linux/drivers/pinctrl目錄下pin control subsystem的源文件列表如下:

文件名 描述
core.c core.h pin control subsystem的core driver
pinctrl-utils.c pinctrl-utils.h pin control subsystem的一些utility接口函數(shù)
pinmux.c pinmux.h pin control subsystem的core driver(pin muxing部分的代碼,也稱為pinmux driver)
pinconf.c pinconf.h pin control subsystem的core driver(pin config部分的代碼,也稱為pin config driver)
devicetree.c devicetree.h pin control subsystem的device tree代碼
pinctrl-xxxx.c 各種pin controller的low level driver。

pin controller driver文檔中 ,我們以2416的pin controller為例,描述了一個具體的low level的driver,這個driver涉及的文件包括pinctrl-samsung.c,pinctrl-samsung.h和pinctrl-s3c24xx.c。

2、和其他內(nèi)核模塊接口頭文件

很多內(nèi)核的其他模塊需要用到pin control subsystem的服務,這些頭文件就定義了pin control subsystem的外部接口以及相關(guān)的數(shù)據(jù)結(jié)構(gòu)。我們整理linux/include/linux/pinctrl目錄下pin control subsystem的外部接口頭文件列表如下:

文件名 描述
consumer.h 其他的driver要使用pin control subsystem的下列接口:
a、設置引腳復用功能
b、配置引腳的電氣特性
這時候需要include這個頭文件
devinfo.h 這是for linux內(nèi)核的驅(qū)動模型模塊(driver model)使用的接口。struct device中包括了一個struct dev_pin_info    *pins的成員,這個成員描述了該設備的引腳的初始狀態(tài)信息,在probe之前,driver model中的core driver在調(diào)用driver的probe函數(shù)之前會先設定pin state
machine.h 和machine模塊的接口。

 

3、Low level pin controller driver接口

我們整理linux/include/linux/pinctrl目錄下pin control subsystem提供給底層specific pin controller driver的頭文件列表如下:

文件名 描述
pinconf-generic.h 這個接口主要是提供給各種pin controller driver使用的,不是外部接口。
pinconf.h pin configuration 接口
pinctrl-state.h pin control state狀態(tài)定義
pinmux.h pin mux function接口

 

三、pin control subsystem的軟件框架圖

1、功能和接口概述

一般而言,學習復雜的軟件組件或者軟件模塊是一個痛苦的過程。我們可以把我們要學習的那個軟件block看成一個黑盒子,不論里面有多么復雜,第一步總是先了解其功能和外部接口特性。如果你愿意,你可以不去看其內(nèi)部實現(xiàn),先自己思考其內(nèi)部邏輯,并形成若干問題,然后帶著這些問題去看代碼,往往事半功倍。

(1)、功能規(guī)格。pin control subsystem的主要功能包括:

(A)管理系統(tǒng)中所有可以控制的pin。在系統(tǒng)初始化的時候,枚舉所有可以控制的pin,并標識這些pin。

(B)管理這些pin的復用(Multiplexing)。對于SOC而言,其引腳除了配置成普通GPIO之外,若干個引腳還可以組成一個pin group,形成特定的功能。例如pin number是{ 0, 8, 16, 24 }這四個引腳組合形成一個pin group,提供SPI的功能。pin control subsystem要管理所有的pin group。

(C)配置這些pin的特性。例如配置該引腳上的pull-up/down電阻,配置drive strength等

(2)接口規(guī)格。linux內(nèi)核的某個軟件組件必須放回到linux系統(tǒng)中才容易探討它的接口以及在系統(tǒng)中的位置,因此,在本章的第二節(jié)會基于系統(tǒng)block上描述各個pin control subsystem和其他內(nèi)核模塊的接口。

(3)內(nèi)部邏輯。要研究一個subsystem的內(nèi)部邏輯,首先要打開黑盒子,細分模塊,然后針對每一個模塊進行功能分析、外部接口分析、內(nèi)部邏輯分析。如果模塊還是比較大,難于掌握,那么就繼續(xù)細分,拆成子模塊,重復上面的分析過程。在本章的第三節(jié)中,我們打開pin control subsystem的黑盒子進行進一步的分析。

2、pin control subsystem在和其他linux內(nèi)核模塊的接口關(guān)系圖如下圖所示:

pcb

pin control subsystem會向系統(tǒng)中的其他driver提供接口以便進行該driver的pin config和pin mux的設定,這部分的接口在第四章描述。理想的狀態(tài)是GPIO controll driver也只是象UART,SPI這樣driver一樣和pin control subsystem進行交互,但是,實際上由于各種源由(后文詳述),pin control subsystem和GPIO subsystem必須有交互,這部分的接口在第五章描述。第六章描述了Driver model和pin control subsystem的接口,第七章描述了為Pin control subsystem提供database支持的Device Tree和Machine driver的接口。

 

3、pin control subsystem內(nèi)部block diagram

pccore

起始理解了接口部分內(nèi)容,閱讀和解析pin control subsystem的內(nèi)部邏輯已經(jīng)很簡單,本文就不再分析了。

 

四、pin control subsystem向其他driver提供的接口

當你準備撰寫一個普通的linux driver(例如串口驅(qū)動)的時候,你期望pin control subsystem提供的接口是什么樣子的?簡單,當然最好是簡單的,最最好是沒有接口,當然這是可能的,具體請參考第六章的接口。

1、概述

普通driver調(diào)用pin control subsystem的主要目標是:

(1)設定該設備的功能復用。設定設備的功能復用需要了解兩個概念,一個是function,另外一個pin group。function是功能抽象,對應一個HW邏輯block,例如SPI0。雖然給定了具體的gunction name,我們并不能確定其使用的pins的情況。例如:為了設計靈活,芯片內(nèi)部的SPI0的功能可能引出到pin group { A8, A7, A6, A5 },也可能引出到另外一個pin group{ G4, G3, G2, G1 },但毫無疑問,這兩個pin group不能同時active,畢竟芯片內(nèi)部的SPI0的邏輯功能電路只有一個。 因此,只有給出function selector(所謂selector就是一個ID或者index)以及function的pin group selector才能進行function mux的設定。

(2)設定該device對應的那些pin的電氣特性。

此外,由于電源管理的要求,某個device可能處于某個電源管理狀態(tài),例如idle或者sleep,這時候,屬于該device的所有的pin就會需要處于另外的狀態(tài)。綜合上述的需求,我們把定義了pin control state的概念,也就是說設備可能處于非常多的狀態(tài)中的一個,device driver可以切換設備處于的狀態(tài)。為了方便管理pin control state,我們又提出了一個pin control state holder的概念,用來管理一個設備的所有的pin control狀態(tài)。因此普通driver調(diào)用pin control subsystem的接口從邏輯上將主要是:

(1)獲取pin control state holder的句柄

(2)設定pin control狀態(tài)

(3)釋放pin control state holder的句柄

pin control state holder的定義如下:

struct pinctrl {
    struct list_head node;--系統(tǒng)中的所有device的pin control state holder被掛入到了一個全局鏈表中
    struct device *dev;---該pin control state holder對應的device
    struct list_head states;----該設備的所有的狀態(tài)被掛入到這個鏈表中
    struct pinctrl_state *state;---當前的pin control state
    struct list_head dt_maps;----mapping table
    struct kref users;------reference count
};

系統(tǒng)中的每一個需要和pin control subsystem進行交互的設備在進行設定之前都需要首先獲取這個句柄。而屬于該設備的所有的狀態(tài)都是掛入到一個鏈表中,鏈表頭就是pin control state holder的states成員,一個state的定義如下:

struct pinctrl_state {
    struct list_head node;---掛入鏈表頭的節(jié)點
    const char *name;-----該state的名字
    struct list_head settings;---屬于該狀態(tài)的所有的settings
};

一個pin state包含若干個setting,所有的settings被掛入一個鏈表中,鏈表頭就是pin state中的settings成員,定義如下:

struct pinctrl_setting {
    struct list_head node;
    enum pinctrl_map_type type;
    struct pinctrl_dev *pctldev;
    const char *dev_name;
    union {
        struct pinctrl_setting_mux mux;
        struct pinctrl_setting_configs configs;
    } data;
};

當driver設定一個pin state的時候,pin control subsystem內(nèi)部會遍歷該state的settings鏈表,將一個一個的setting進行設定。這些settings有各種類型,定義如下:

enum pinctrl_map_type {
    PIN_MAP_TYPE_INVALID,
    PIN_MAP_TYPE_DUMMY_STATE,
    PIN_MAP_TYPE_MUX_GROUP,---功能復用的setting
    PIN_MAP_TYPE_CONFIGS_PIN,----設定單一一個pin的電氣特性
    PIN_MAP_TYPE_CONFIGS_GROUP,----設定單pin group的電氣特性
};

有pin mux相關(guān)的設定(PIN_MAP_TYPE_MUX_GROUP),定義如下:

struct pinctrl_setting_mux {
    unsigned group;--------該setting所對應的group selector
    unsigned func;---------該setting所對應的function selector
};

有了function selector以及屬于該functiong的roup selector就可以進行該device和pin mux相關(guān)的設定了。設定電氣特性的settings定義如下:

struct pinctrl_map_configs {
    const char *group_or_pin;----該pin或者pin group的名字
    unsigned long *configs;----要設定的值的列表。這個值被用來寫入HW
    unsigned num_configs;----列表中值的個數(shù)
};

 

2、具體的接口

(1)devm_pinctrl_get和pinctrl_get。devm_pinctrl_get是Resource managed版本的pinctrl_get,核心還是pinctrl_get函數(shù)。這兩個接口都是獲取設備(設備模型中的struct device)的pin control state holder(struct pinctrl)。pin control state holder不是靜態(tài)定義的,一般在第一次調(diào)用該函數(shù)的時候會動態(tài)創(chuàng)建。創(chuàng)建一個pin control state holder是一個大工程,我們分析一下這段代碼:

static struct pinctrl *create_pinctrl(struct device *dev)
{

   分配pin control state holder占用的內(nèi)存并初始化
    p = kzalloc(sizeof(*p), GFP_KERNEL);
    p->dev = dev;
    INIT_LIST_HEAD(&p->states);
    INIT_LIST_HEAD(&p->dt_maps);

mapping table這個database的建立也是動態(tài)的,當?shù)谝淮握{(diào)用pin control state holder的get函數(shù)的時候,就會通過調(diào)用pinctrl_dt_to_map來建立該device需要的mapping entry。具體請參考第七章。

    ret = pinctrl_dt_to_map(p);

    devname = dev_name(dev);

    mutex_lock(&pinctrl_maps_mutex);
    for_each_maps(maps_node, i, map) {
        /* Map must be for this device */
        if (strcmp(map->dev_name, devname))
            continue;

        ret = add_setting(p, map);----分析一個mapping entry,把這個setting的代碼加入到holder中

    }
    mutex_unlock(&pinctrl_maps_mutex);

    kref_init(&p->users);

    /* 把這個新增加的pin control state holder加入到全局鏈表中 */
    mutex_lock(&pinctrl_list_mutex);
    list_add_tail(&p->node, &pinctrl_list);
    mutex_unlock(&pinctrl_list_mutex);

    return p;
}

(2)devm_pinctrl_put和pinctrl_put。是(1)接口中的逆函數(shù)。devm_pinctrl_get和pinctrl_get獲取句柄的時候申請了很多資源,在devm_pinctrl_put和pinctrl_put可以釋放。需要注意的是多次調(diào)用get函數(shù)不會重復分配資源,只會reference count加一,在put中referrenct count減一,當count==0的時候才釋放該device的pin control state holder持有的所有資源。

(3)pinctrl_lookup_state。根據(jù)state name在pin control state holder找到對應的pin control state。具體的state是各個device自己定義的,不過pin control subsystem自己定義了一些標準的pin control state,定義在pinctrl-state.h文件中:

#define PINCTRL_STATE_DEFAULT "default"
#define PINCTRL_STATE_IDLE "idle"
#define PINCTRL_STATE_SLEEP "sleep"

(4)pinctrl_select_state。設定一個具體的pin control state接口。

 

五、和GPIO subsystem交互

1、為何pin control subsystem要和GPIO subsystem交互?

作為軟件工程師,我們期望的硬件設計應該如下圖所示:pin hw

GPIO的HW block應該和其他功能復用的block是對等關(guān)系的,它們共同輸入到一個復用器block,這個block的寄存器控制哪一個功能電路目前是active的。pin configuration是全局的,不論哪種功能是active的,都可以針對pin進行電氣特性的設定。這樣的架構(gòu)下,上圖中紅色邊框的三個block是完全獨立的HW block,其控制寄存器在SOC datasheet中應該是分成三個章節(jié)描述,同時,這些block的寄存器應該分別處于不同的地址區(qū)間。

對于軟件工程師,我們可以讓pin control subsystem和GPIO subsystem完全獨立,各自進行初始化,各自映射自己的寄存器地址空間,對于pin control subsystem而言,GPIO和其他的HW block沒有什么不同,都是使用自己提供服務的一個軟件模塊而已。然而實際上SOC的設計并非總是向軟件工程師期望的那樣,有的SOC的設計框架圖如下:

pin hw2

這時候,GPIO block是alway active的,而紅色邊框的三個block是緊密的捆綁在一起,它們的寄存器占據(jù)了一個memory range(datasheet中用一個章節(jié)描述這三個block)。這時候,對于軟件工程師來說就有些糾結(jié)了,本來不屬于我的GPIO控制也被迫要參與進來。這時候,硬件寄存器的控制都是pin controller來處理,GPIO相關(guān)的操作都要經(jīng)過pin controller driver,這時候,pin controller driver要作為GPIO driver的back-end出現(xiàn)。

2、具體的接口形態(tài)

(1)pinctrl_request_gpio。該接口主要用來申請GPIO。GPIO也是一種資源,使用前應該request,使用完畢后釋放。具體的代碼如下:

int pinctrl_request_gpio(unsigned gpio)----這里傳入的是GPIO 的ID
{
    struct pinctrl_dev *pctldev;
    struct pinctrl_gpio_range *range;
    int ret;
    int pin;

    ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);---A
    if (ret) {
        if (pinctrl_ready_for_gpio_range(gpio))
            ret = 0;
        return ret;
    }

    mutex_lock(&pctldev->mutex); 
    pin = gpio_to_pin(range, gpio); ---將GPIO ID轉(zhuǎn)換成pin ID

    ret = pinmux_request_gpio(pctldev, range, pin, gpio); ------B

    mutex_unlock(&pctldev->mutex);

    return ret;
}

毫無疑問,申請GPIO資源本應該是GPIO subsystem的責任,但是由于上一節(jié)描述的源由,pin control subsystem提供了這樣一個接口函數(shù)供GPIO driver使用(其他的內(nèi)核driver不應該調(diào)用,它們應該使用GPIO subsystem提供的接口)。多么丑陋的代碼,作為pin control subsystem,除了維護pin space中的ID,還要維護GPIO 的ID以及pin ID和GPIO ID的關(guān)系。

A:根據(jù)GPIO ID找到該ID對應的pin control device(struct pinctrl_dev)和GPIO rang(pinctrl_gpio_range)。在core driver中,每個low level的pin controller device都被映射成一個struct pinctrl_dev,并形成鏈表,鏈表頭就是pinctrldev_list。由于實際的硬件設計(例如GPIO block被分成若干個GPIO 的bank,每個bank就對應一個HW GPIO Controller Block),一個pin control device要管理的GPIO ID是分成區(qū)域的,每個區(qū)域用struct pinctrl_gpio_range來抽象,在low level 的pin controller初始化的時候(具體參考samsung_pinctrl_register的代碼),會調(diào)用pinctrl_add_gpio_range將每個GPIO bank表示的gpio range掛入到pin control device的range list中(gpio_ranges成員)。pinctrl_gpio_range 的定義如下:

struct pinctrl_gpio_range {
    struct list_head node;
    const char *name;
    unsigned int id;-----------GPIO chip ID
    unsigned int base;------該range中的起始GPIO IDD
    unsigned int pin_base;---在線性映射的情況下,這是起始的pin base
    unsigned const *pins;---在非線性映射的時候,這是table是pin到GPIO的lookup table
    unsigned int npins;----這個range有多少個GPIO引腳
    struct gpio_chip *gc;------每個GPIO bank都是一個gpio chip,對應一個GPIO range
};

pin ID和GPIO ID有兩種映射關(guān)系,一種是線性映射(這時候pin_base有效),也就是說,對于這個GPIO range,GPIO base ID是a,pin ID base是b,那么a<--->b,a+1<--->b+1,a+2<--->b+2,以此類推。對于非線性映射(pin_base無效,pins是有效的),我們需要建立一個lookup table,以GPIO ID為索引,可以找到對于的pin ID。

B:這里主要是進行復用功能的設定,畢竟GPIO也是引腳的一個特定的功能。pinmux_request_gpio函數(shù)的作用主要有兩個,一個是在core driver中標記該pin已經(jīng)用作GPIO了,這樣,如果有模塊后續(xù)request該資源,那么core driver可以拒絕不合理的要求。第二步就是調(diào)用底層pin controller driver的callback函數(shù),進行底層寄存器相關(guān)的操作。

(2)pinctrl_free_gpio。有申請就有釋放,這是pinctrl_request_gpio的逆函數(shù)

(3)pinctrl_gpio_direction_input和pinctrl_gpio_direction_output。為已經(jīng)指定為GPIO功能的引腳設定方向,輸入或者輸出。代碼很簡單,不再贅述。

 

六、和驅(qū)動模型的接口

前文已經(jīng)表述過,最好是讓統(tǒng)一設備驅(qū)動模型(Driver model)來處理pin 的各種設定。與其自己寫代碼調(diào)用devm_pinctrl_get、pinctrl_lookup_state、pinctrl_select_state等pin control subsystem的接口函數(shù),為了不讓linux內(nèi)核自己的框架處理呢。本章將分析具體的代碼,這些代碼實例對自己driver調(diào)用pin control subsystem的接口函數(shù)來設定本device的pin control的相關(guān)設定也是有指導意義的。 linux kernel中的驅(qū)動模型提供了driver和device的綁定機制,一旦匹配會調(diào)用probe函數(shù)如下:

static int really_probe(struct device *dev, struct device_driver *drv)
{
    ……
    ret = pinctrl_bind_pins(dev); ---對該device涉及的pin進行pin control相關(guān)設定
    ……

    if (dev->bus->probe) {------下面是真正的probe過程
        ret = dev->bus->probe(dev);
        if (ret)
            goto probe_failed;
    } else if (drv->probe) {
        ret = drv->probe(dev);
        if (ret)
            goto probe_failed;
    }

……

}

pinctrl_bind_pins的代碼如下:

int pinctrl_bind_pins(struct device *dev)
{
    int ret;

    dev->pins = devm_kzalloc(dev, sizeof(*(dev->pins)), GFP_KERNEL);---(1)

    dev->pins->p = devm_pinctrl_get(dev);-----------------(2)

    dev->pins->default_state = pinctrl_lookup_state(dev->pins->p, -------(3)
                    PINCTRL_STATE_DEFAULT);

    ret = pinctrl_select_state(dev->pins->p, dev->pins->default_state); -----(4)


    dev->pins->sleep_state = pinctrl_lookup_state(dev->pins->p, ------(3)
                    PINCTRL_STATE_SLEEP);

    dev->pins->idle_state = pinctrl_lookup_state(dev->pins->p, -------(3)
                    PINCTRL_STATE_IDLE);

    return 0;
}

(1)struct device數(shù)據(jù)結(jié)構(gòu)有一個pins的成員,它描述了和該設備相關(guān)的pin control的信息,定義如下:

struct dev_pin_info {
    struct pinctrl *p;------------該device對應的pin control state holder
    struct pinctrl_state *default_state;----缺省狀態(tài)
    struct pinctrl_state *sleep_state;-----電源管理相關(guān)的狀態(tài)
    struct pinctrl_state *idle_state;-----電源管理相關(guān)的狀態(tài)
};

(2)調(diào)用devm_pinctrl_get獲取該device對應的 pin control state holder句柄。

(3)搜索default state,sleep state,idle state并記錄在本device中

(3)將該設備設定為pin default state

 

七、和device tree或者machine driver相關(guān)的接口

1、概述

device tree或者machine driver這兩個模塊主要是為 pin control subsystem提供pin mapping database的支持。這個database的每個entry用下面的數(shù)據(jù)結(jié)構(gòu)表示:

struct pinctrl_map {
    const char *dev_name;---使用這個mapping entry的設備名
    const char *name;------該名字表示了該mapping entry
    enum pinctrl_map_type type;---這個entry的mapping type
    const char *ctrl_dev_name; -----pin controller這個設備的名字
    union {
        struct pinctrl_map_mux mux;
        struct pinctrl_map_configs configs;
    } data;
};

 

2、通過machine driver靜態(tài)定義的數(shù)據(jù)來建立pin mapping database

machine driver定義一個巨大的mapping table,描述,然后在machine初始化的時候,調(diào)用pinctrl_register_mappings將該table注冊到pin control subsystem中。

3、通過device tree來建立pin mapping database

pin mapping信息定義在dts中,主要包括兩個部分,一個是定義在各個具體的device node中,另外一處是定義在pin controller的device node中。

一個典型的device tree中的外設node定義如下(建議先看看pin controller driver的第二章關(guān)于dts的描述):

device-node-name { 
        定義該device自己的屬性  

        pinctrl-names = "sleep", "default";
        pinctrl-0 = ;
        pinctrl-1 = ;        
    };

對普通device的dts分析在函數(shù)pinctrl_dt_to_map中,代碼如下:

int pinctrl_dt_to_map(struct pinctrl *p)
{  
    of_node_get(np); 
    for (state = 0; ; state++) {-------------------(1)
        /* Retrieve the pinctrl-* property */
        propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state);
        prop = of_find_property(np, propname, &size); 
        kfree(propname);
        if (!prop)
            break;
        list = prop->value;
        size /= sizeof(*list); --------------(2)

        /* Determine whether pinctrl-names property names the state */
        ret = of_property_read_string_index(np, "pinctrl-names", ------(3)
                            state, &statename); 

        if (ret < 0) {
            /* strlen("pinctrl-") == 8 */
            statename = prop->name + 8; -------------(4)
        }

        /* For every referenced pin configuration node in it */
        for (config = 0; config < size; config++) { -----------(5)
            phandle = be32_to_cpup(list++);

            /* Look up the pin configuration node */
            np_config = of_find_node_by_phandle(phandle); ------(6)

            /* Parse the node */
            ret = dt_to_map_one_config(p, statename, np_config); ----(7)
            of_node_put(np_config);
            if (ret < 0)
                goto err;
        }

        /* No entries in DT? Generate a dummy state table entry */
        if (!size) {
            ret = dt_remember_dummy_state(p, statename); -------(8)
            if (ret < 0)
                goto err;
        }
    }

    return 0;

err:
    pinctrl_dt_free_maps(p);
    return ret;
}

(1)pinctrl-0 pinctrl-1 pinctrl-2……表示了該設備的一個個的狀態(tài),這里我們定義了兩個pinctrl-0和pinctrl-1分別對應sleep和default狀態(tài)。這里每次循環(huán)分析一個pin state。

(2)代碼執(zhí)行到這里,size和list分別保存了該pin state中所涉及pin configuration phandle的數(shù)目以及phandle的列表

(3)讀取從pinctrl-names屬性中獲取state name

(4)如果沒有定義pinctrl-names屬性,那么我們將pinctrl-0 pinctrl-1 pinctrl-2……中的那個ID取出來作為state name

(5)遍歷一個pin state中的pin configuration list,這里的pin configuration實際應該是pin controler device node中的sub node,用phandle標識。

(6)用phandle作為索引,在device tree中找他該phandle表示的那個pin configuration

(7)分析一個pin configuration,具體下面會仔細分析

(8)如果該設備沒有定義pin configuration,那么也要創(chuàng)建一個dummy的pin state。

這里我們已經(jīng)進入對pin controller node下面的子節(jié)點的分析過程了。分析一個pin configuration的代碼如下:

static int dt_to_map_one_config(struct pinctrl *p, const char *statename,
                struct device_node *np_config)
{
    struct device_node *np_pctldev;
    struct pinctrl_dev *pctldev;
    const struct pinctrl_ops *ops;
    int ret;
    struct pinctrl_map *map;
    unsigned num_maps;

    /* Find the pin controller containing np_config */
    np_pctldev = of_node_get(np_config);
    for (;;) {
        np_pctldev = of_get_next_parent(np_pctldev);-------(1)
        if (!np_pctldev || of_node_is_root(np_pctldev)) {
            of_node_put(np_pctldev);
            return -EPROBE_DEFER;
        }
        pctldev = get_pinctrl_dev_from_of_node(np_pctldev);-----(2)
        if (pctldev)
            break;------------------------(3)
        /* Do not defer probing of hogs (circular loop) */
        if (np_pctldev == p->dev->of_node) {
            of_node_put(np_pctldev);
            return -ENODEV;
        }
    }
    of_node_put(np_pctldev);

    /*
     * Call pinctrl driver to parse device tree node, and
     * generate mapping table entries
     */
    ops = pctldev->desc->pctlops;
    ret = ops->dt_node_to_map(pctldev, np_config, &map, &num_maps);----(4)
    if (ret < 0)
        return ret;

    /* Stash the mapping table chunk away for later use */
    return dt_remember_or_free_map(p, statename, pctldev, map, num_maps);----(5)
}

(1)首先找到該pin configuration node對應的parent node(也就是pin controler對應的node),如果找不到或者是root node,則進入出錯處理。

(2)獲取pin control class device

(3)一旦找到pin control class device則跳出for循環(huán)

(4)調(diào)用底層的callback函數(shù)處理pin configuration node。這也是合理的,畢竟很多的pin controller bindings是需要自己解析的。

(5)將該pin configuration node的mapping entry信息注冊到系統(tǒng)中

 

八、core driver和low level pin controller driver的接口規(guī)格

pin controller描述符。每一個特定的pin controller都用一個struct pinctrl_desc來抽象,具體如下:

struct pinctrl_desc {
    const char *name;
    struct pinctrl_pin_desc const *pins;
    unsigned int npins;
    const struct pinctrl_ops *pctlops;
    const struct pinmux_ops *pmxops;
    const struct pinconf_ops *confops;
    struct module *owner;
};

pin controller描述符需要描述它可以控制多少個pin(成員npins),每一個pin的信息為何?(成員pins)。這兩個成員就確定了一個pin controller所能控制的引腳的信息。

pin controller描述符中包括了三類操作函數(shù):pctlops是一些全局的控制函數(shù),pmxops是復用引腳相關(guān)的操作函數(shù),confops操作函數(shù)是用來配置引腳的特性(例如:pull-up/down)。struct pinctrl_ops中各個callback函數(shù)的具體的解釋如下:

callback函數(shù) 描述
get_groups_count 該pin controller支持多少個pin group。pin group的定義可以參考本文關(guān)于pin controller的功能規(guī)格中的描述。注意不要把pin group和IO port的硬件分組搞混了。例如:S3C2416有138個I/O 端口,分成11組,分別是gpa~gpl,這個組并不叫pin group,而是叫做pin bank。pin group是和特定功能(例如SPI、I2C)相關(guān)的一組pin。
get_group_name 給定一個selector(index),獲取指定pin group的name
get_group_pins 給定一個selector(index),獲取該pin group中pin的信息(該pin group包括多少個pin,每個pin的ID是什么)
pin_dbg_show debug fs的callback接口
dt_node_to_map 分析一個pin configuration node并把分析的結(jié)果保存成mapping table entry,每一個entry表示一個setting(一個功能復用設定,或者電氣特性設定)
dt_free_map 上面函數(shù)的逆函數(shù)

復用引腳相關(guān)的操作函數(shù)的具體解釋如下:

call back函數(shù) 描述
request pin control core進行具體的復用設定之前需要調(diào)用該函數(shù),主要是用來請底層的driver判斷某個引腳的復用設定是否是OK的。
free 是request的逆函數(shù)。調(diào)用request函數(shù)請求占用了某些pin的資源,調(diào)用free可以釋放這些資源
get_functions_count 就是返回pin controller支持的function的數(shù)目
get_function_name 給定一個selector(index),獲取指定function的name
get_function_groups 給定一個selector(index),獲取指定function的pin groups信息
enable enable一個function。當然要給出function selector和pin group的selector
disable enable的逆函數(shù)
gpio_request_enable request并且enable一個單獨的gpio pin
gpio_disable_free gpio_request_enable的逆函數(shù)
gpio_set_direction 設定GPIO方向的回調(diào)函數(shù)

配置引腳的特性的struct pinconf_ops數(shù)據(jù)結(jié)構(gòu)的各個成員定義如下:

call back函數(shù) 描述
pin_config_get 給定一個pin ID以及config type ID,獲取該引腳上指定type的配置。
pin_config_set 設定一個指定pin的配置
pin_config_group_get 以pin group為單位,獲取pin上的配置信息
pin_config_group_set 以pin group為單位,設定pin group的特性配置
pin_config_dbg_parse_modify debug接口
pin_config_dbg_show debug接口
pin_config_group_dbg_show debug接口
pin_config_config_dbg_show debug接口

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多