小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

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

 風(fēng)之library 2014-08-13

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

一、前言

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

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

(2)發(fā)現(xiàn)某個(gè)driver不能正常工作,辛辛苦苦debug后發(fā)現(xiàn)僅僅是因?yàn)槠渌膁river在初始化的過(guò)程中修改了引腳的配置,導(dǎo)致自己的driver無(wú)法正常工作

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

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

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

 

二、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為例,描述了一個(gè)具體的low level的driver,這個(gè)driver涉及的文件包括pinctrl-samsung.c,pinctrl-samsung.h和pinctrl-s3c24xx.c。

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

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

文件名 描述
consumer.h 其他的driver要使用pin control subsystem的下列接口:
a、設(shè)置引腳復(fù)用功能
b、配置引腳的電氣特性
這時(shí)候需要include這個(gè)頭文件
devinfo.h 這是for linux內(nèi)核的驅(qū)動(dòng)模型模塊(driver model)使用的接口。struct device中包括了一個(gè)struct dev_pin_info    *pins的成員,這個(gè)成員描述了該設(shè)備的引腳的初始狀態(tài)信息,在probe之前,driver model中的core driver在調(diào)用driver的probe函數(shù)之前會(huì)先設(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 這個(gè)接口主要是提供給各種pin controller driver使用的,不是外部接口。
pinconf.h pin configuration 接口
pinctrl-state.h pin control state狀態(tài)定義
pinmux.h pin mux function接口

 

三、pin control subsystem的軟件框架圖

1、功能和接口概述

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

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

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

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

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

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

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

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

pcb

pin control subsystem會(huì)向系統(tǒng)中的其他driver提供接口以便進(jìn)行該driver的pin config和pin mux的設(shè)定,這部分的接口在第四章描述。理想的狀態(tài)是GPIO controll driver也只是象UART,SPI這樣driver一樣和pin control subsystem進(jìn)行交互,但是,實(shí)際上由于各種源由(后文詳述),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)很簡(jiǎn)單,本文就不再分析了。

 

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

當(dāng)你準(zhǔn)備撰寫一個(gè)普通的linux driver(例如串口驅(qū)動(dòng))的時(shí)候,你期望pin control subsystem提供的接口是什么樣子的?簡(jiǎn)單,當(dāng)然最好是簡(jiǎn)單的,最最好是沒(méi)有接口,當(dāng)然這是可能的,具體請(qǐng)參考第六章的接口。

1、概述

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

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

(2)設(shè)定該device對(duì)應(yīng)的那些pin的電氣特性。

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

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

(2)設(shè)定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被掛入到了一個(gè)全局鏈表中
    struct device *dev;---該pin control state holder對(duì)應(yīng)的device
    struct list_head states;----該設(shè)備的所有的狀態(tài)被掛入到這個(gè)鏈表中
    struct pinctrl_state *state;---當(dāng)前的pin control state
    struct list_head dt_maps;----mapping table
    struct kref users;------reference count
};

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

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

一個(gè)pin state包含若干個(gè)setting,所有的settings被掛入一個(gè)鏈表中,鏈表頭就是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;
};

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

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

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

struct pinctrl_setting_mux {
    unsigned group;--------該setting所對(duì)應(yīng)的group selector
    unsigned func;---------該setting所對(duì)應(yīng)的function selector
};

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

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

 

2、具體的接口

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

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這個(gè)database的建立也是動(dòng)態(tài)的,當(dāng)?shù)谝淮握{(diào)用pin control state holder的get函數(shù)的時(shí)候,就會(huì)通過(guò)調(diào)用pinctrl_dt_to_map來(lái)建立該device需要的mapping entry。具體請(qǐng)參考第七章。

    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);----分析一個(gè)mapping entry,把這個(gè)setting的代碼加入到holder中

    }
    mutex_unlock(&pinctrl_maps_mutex);

    kref_init(&p->users);

    /* 把這個(gè)新增加的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獲取句柄的時(shí)候申請(qǐng)了很多資源,在devm_pinctrl_put和pinctrl_put可以釋放。需要注意的是多次調(diào)用get函數(shù)不會(huì)重復(fù)分配資源,只會(huì)reference count加一,在put中referrenct count減一,當(dāng)count==0的時(shí)候才釋放該device的pin control state holder持有的所有資源。

(3)pinctrl_lookup_state。根據(jù)state name在pin control state holder找到對(duì)應(yīng)的pin control state。具體的state是各個(gè)device自己定義的,不過(guò)pin control subsystem自己定義了一些標(biāo)準(zhǔn)的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。設(shè)定一個(gè)具體的pin control state接口。

 

五、和GPIO subsystem交互

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

作為軟件工程師,我們期望的硬件設(shè)計(jì)應(yīng)該如下圖所示:pin hw

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

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

pin hw2

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

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

(1)pinctrl_request_gpio。該接口主要用來(lái)申請(qǐng)GPIO。GPIO也是一種資源,使用前應(yīng)該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;
}

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

A:根據(jù)GPIO ID找到該ID對(duì)應(yīng)的pin control device(struct pinctrl_dev)和GPIO rang(pinctrl_gpio_range)。在core driver中,每個(gè)low level的pin controller device都被映射成一個(gè)struct pinctrl_dev,并形成鏈表,鏈表頭就是pinctrldev_list。由于實(shí)際的硬件設(shè)計(jì)(例如GPIO block被分成若干個(gè)GPIO 的bank,每個(gè)bank就對(duì)應(yīng)一個(gè)HW GPIO Controller Block),一個(gè)pin control device要管理的GPIO ID是分成區(qū)域的,每個(gè)區(qū)域用struct pinctrl_gpio_range來(lái)抽象,在low level 的pin controller初始化的時(shí)候(具體參考samsung_pinctrl_register的代碼),會(huì)調(diào)用pinctrl_add_gpio_range將每個(gè)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;---在非線性映射的時(shí)候,這是table是pin到GPIO的lookup table
    unsigned int npins;----這個(gè)range有多少個(gè)GPIO引腳
    struct gpio_chip *gc;------每個(gè)GPIO bank都是一個(gè)gpio chip,對(duì)應(yīng)一個(gè)GPIO range
};

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

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

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

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

 

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

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

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

    if (dev->bus->probe) {------下面是真正的probe過(guò)程
        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)有一個(gè)pins的成員,它描述了和該設(shè)備相關(guān)的pin control的信息,定義如下:

struct dev_pin_info {
    struct pinctrl *p;------------該device對(duì)應(yīng)的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對(duì)應(yīng)的 pin control state holder句柄。

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

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

 

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

1、概述

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

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

 

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

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

3、通過(guò)device tree來(lái)建立pin mapping database

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

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

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

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

對(duì)普通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……表示了該設(shè)備的一個(gè)個(gè)的狀態(tài),這里我們定義了兩個(gè)pinctrl-0和pinctrl-1分別對(duì)應(yīng)sleep和default狀態(tài)。這里每次循環(huán)分析一個(gè)pin state。

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

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

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

(5)遍歷一個(gè)pin state中的pin configuration list,這里的pin configuration實(shí)際應(yīng)該是pin controler device node中的sub node,用phandle標(biāo)識(shí)。

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

(7)分析一個(gè)pin configuration,具體下面會(huì)仔細(xì)分析

(8)如果該設(shè)備沒(méi)有定義pin configuration,那么也要?jiǎng)?chuàng)建一個(gè)dummy的pin state。

這里我們已經(jīng)進(jìn)入對(duì)pin controller node下面的子節(jié)點(diǎn)的分析過(guò)程了。分析一個(gè)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對(duì)應(yīng)的parent node(也就是pin controler對(duì)應(yīng)的node),如果找不到或者是root node,則進(jìn)入出錯(cuò)處理。

(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信息注冊(cè)到系統(tǒng)中

 

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

pin controller描述符。每一個(gè)特定的pin controller都用一個(gè)struct pinctrl_desc來(lái)抽象,具體如下:

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

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

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

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

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

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

call back函數(shù) 描述
pin_config_get 給定一個(gè)pin ID以及config type ID,獲取該引腳上指定type的配置。
pin_config_set 設(shè)定一個(gè)指定pin的配置
pin_config_group_get 以pin group為單位,獲取pin上的配置信息
pin_config_group_set 以pin group為單位,設(shè)定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接口

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

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多