備樹在根節(jié)點(diǎn)添加key后,為什么還需要添加pinctrl_key部分?)
這是一個(gè)非常硬核且典型的內(nèi)核驅(qū)動(dòng)開發(fā)問題。你問到了設(shè)備樹Device Tree中最容易讓初學(xué)者困惑的“分層設(shè)計(jì)”邏輯。直接回答你的核心疑問在根節(jié)點(diǎn)添加key按鍵只是定義了“功能需求”而添加pinctrl部分則是定義了“物理實(shí)現(xiàn)”。兩者缺一不可少了pinctrl內(nèi)核只知道你要用按鍵但不知道該去操作哪根引腳、怎么操作這根引腳。為了讓你徹底理解我把這個(gè)過程拆解為硬件電路設(shè)計(jì)的三個(gè)層次1. 根節(jié)點(diǎn)下的“key”功能節(jié)點(diǎn)你在根節(jié)點(diǎn)或根節(jié)點(diǎn)下的某個(gè)子節(jié)點(diǎn)添加的key屬于功能抽象層。/ { key: key-node { compatible gpio-keys; // 告訴內(nèi)核這是一個(gè)GPIO按鍵 pinctrl-names default; // 引用下面定義的pinctrl狀態(tài) pinctrl-0 key_pins; // 把“功能”和“引腳”綁定起來 button-1 { label KEY_POWER; gpios gpio1 10 GPIO_ACTIVE_LOW; linux,code 116; // 按鍵鍵值 (POWER) }; }; };這個(gè)節(jié)點(diǎn)只負(fù)責(zé)三件事告訴內(nèi)核“我是個(gè)按鍵”compatible。告訴內(nèi)核“按下去后上報(bào)什么鍵值”linux,code。引用了一個(gè)叫key_pins的東西但并沒有定義這個(gè)key_pins具體是什么。2. pinctrl_key 部分引腳功能節(jié)點(diǎn)你在/pinctrl或/pinmux節(jié)點(diǎn)下添加的pinctrl_key屬于物理實(shí)現(xiàn)層。pinctrl { key_pins: key_pins { pins GPIO1_IO10; // 指定具體芯片引腳 function gpio_in; // 復(fù)用功能作為GPIO輸入 bias-pull-up; // 使能內(nèi)部上拉電阻防止懸空 input-enable; // 使能輸入模式 drive-strength 2; // 驅(qū)動(dòng)電流能力 }; };這個(gè)節(jié)點(diǎn)負(fù)責(zé)另外三件事引腳復(fù)用Pin Mux芯片的同一個(gè)物理引腳可能有“UART”“I2C”“GPIO”等多種功能。pinctrl告訴芯片這個(gè)腳要當(dāng)gpio_inGPIO輸入用而不是串口。電氣特性是否需要上拉/下拉電阻引腳速率是多少這直接關(guān)系到按鍵的穩(wěn)定性和抗干擾能力。電源域歸屬屬于哪個(gè)電壓域1.8V還是3.3V。3. 為什么一定要分開寫核心原因解耦與復(fù)用同一個(gè)功能節(jié)點(diǎn)key可以適配不同的硬件板子。比如你的產(chǎn)品有高配版和低配版按鍵功能完全一樣但低配版用了不同的GPIO引腳。此時(shí)你只需修改pinctrl_key里的引腳號(hào)功能節(jié)點(diǎn)key-node的代碼一行都不用改。SoC 管腳數(shù)量巨大一顆ARM芯片有上百個(gè)引腳如果每個(gè)功能節(jié)點(diǎn)都要重復(fù)寫“輸入輸出模式”“上拉電阻”這些電氣參數(shù)代碼會(huì)極度冗余。抽象成pinctrl后多個(gè)設(shè)備可以共享同一套引腳配置。驅(qū)動(dòng)分離gpio-keys驅(qū)動(dòng)只管“檢測(cè)電平變化上報(bào)事件”它不需要知道引腳怎么復(fù)用的而pinctrl子系統(tǒng)專門管“引腳怎么配置”。這是Linux內(nèi)核“單一職責(zé)原則”的體現(xiàn)。4. 編譯時(shí)的“鏈接”過程關(guān)鍵你可能會(huì)想“我在key節(jié)點(diǎn)里寫了pinctrl-0 key_pins編譯器怎么知道對(duì)應(yīng)哪個(gè)”key_pins是一個(gè)標(biāo)簽引用Label Reference。設(shè)備樹編譯DTC時(shí)編譯器會(huì)去/pinctrl下找到key_pins: key_pins { ... };這個(gè)節(jié)點(diǎn)并把它的物理地址和配置數(shù)據(jù)填入key節(jié)點(diǎn)的pinctrl-0屬性中。內(nèi)核啟動(dòng)時(shí)pinctrl子系統(tǒng)會(huì)解析key節(jié)點(diǎn)的pinctrl-0屬性進(jìn)而調(diào)用SoC底層的寄存器操作把對(duì)應(yīng)的物理引腳真正配置成GPIO模式。5. 如果不添加 pinctrl_key 會(huì)發(fā)生什么編譯階段如果pinctrl-0引用的標(biāo)簽key_pins不存在DTC編譯會(huì)直接報(bào)錯(cuò)生成不了dtb文件。運(yùn)行階段假設(shè)你硬編碼繞過了編譯檢查內(nèi)核在probegpio-keys驅(qū)動(dòng)時(shí)GPIO子系統(tǒng)會(huì)因?yàn)樵撘_尚未配置復(fù)用功能而初始化失敗按鍵驅(qū)動(dòng)無法加載。更嚴(yán)重的情況是該引腳可能被默認(rèn)配置為UART功能你在按鍵上按下去信號(hào)會(huì)被UART控制器當(dāng)作串口數(shù)據(jù)解析導(dǎo)致系統(tǒng)異常。一個(gè)便于記憶的比喻功能節(jié)點(diǎn)key 你家裝修的“設(shè)計(jì)圖”上面寫著“這里要裝一個(gè)開關(guān)”。pinctrl節(jié)點(diǎn) 電工的“施工圖”上面寫著“從配電箱拉一根2.5平方的銅線到墻上這個(gè)86盒接在L端”。沒有設(shè)計(jì)圖電工不知道裝什么沒有施工圖設(shè)計(jì)師的話只是空想。如果你現(xiàn)在正在移植某個(gè)開發(fā)板的按鍵驅(qū)動(dòng)遇到了編譯報(bào)錯(cuò)比如undefined reference to key_pins或者probe失敗可以把你的設(shè)備樹片段發(fā)出來我可以幫你具體看下是引腳編號(hào)沖突還是復(fù)用功能沒寫對(duì)。