輕鬆掌握pinctrl子系統驅動開發——一個虛擬pinctrl dev驅動開發

2020-08-29 jerry的編程路

這周主要對pinctrl子系統進行分析,該分析的基本上已經分析完成,唯一沒有細說的估計就是gpio與pinctrl之間的關聯了。本章即是pinctrl子系統分析的最後一章,本章我們主要實現一個虛擬的pinctrl device驅動,以便我們能夠使用pinctrl子系統提供的接口,實現pinctrl device的驅動開發(本章實現的驅動代碼可以在ubuntu18.04系統上正常運行)。

本篇文章的目的如下:

  1. 實現一個虛擬的pinctrl dev驅動,掌握pinctrl dev的驅動開發;
  2. 不需要藉助開發板,即可完成pinctrl dev驅動開發及驗證工作(我們既然分析內核各驅動子系統模塊,要學習的就是他們的系統設計方法、硬體抽象等工作。本篇文章保證在沒有硬體開發板的情況下,也可以進行pinctrl 子系統的驅動開發,其實大多數驅動工程師可能都不一定有開發pinctrl 子系統驅動的場景,pinctrl device驅動開發基本上是soc廠家實現的)。


本篇文章涉及的知識點:

  1. 需要知道platform device、driver的知識;
  2. 需要對sysfs有個大概的理解,我們通過sysfs子系統的屬性文件,查看pin mux配置是否生效;
  3. 需要使用一個虛擬的gpio控制器驅動(在之前gpio專欄中已經實現,此處增加對pinctrl的支持),驗證gpio相關的引腳配置功能;
  4. 需要使用一個虛擬控制器驅動,驗證device與pinctr的綁定功能(此處我們使用之前在spi專欄中實現的虛擬spi控制器驅動,該驅動在此處基本上無需修改)。


本章的主要章節如下:

一、 virt soc pin描述

二、 virt pinctrl dev驅動實現

三、virt board pin描述及pinctrl maps註冊

四、device與pinctrl的綁定

五、gpio與pinctrl子系統相關知識點說明

六、功能驗證

一、Virt soc pin描述

既然pinctrl device是對soc pin controller的驅動程序,因此我們需要定義下我們虛擬的soc引腳定義。

如下圖所示,本virt soc 提供32個pin,每一個pin支持4個可選狀態。提供2個32bit寄存器描述該soc引腳復用信息,因為每個pin支持4個可選狀態,因此使用2bits描述該pin的狀態。因為只是一個虛擬的soc pin描述,因此此處僅定義了32個pin信息。

兩個寄存器分別定義pinmux_reg0、pinmux_reg1,其中pin0使用pinmux_reg0的bit0、bit1描述其狀態:00b表示gpio0;01b iic0_sdat。Pin1使用pinmux_reg0的bit2、bit3描述其狀態:00b表示gpio1;10表示uart0_tx;

該soc可支持32個gpio、3個iic、2個uart、1個spi、2個can、1個nandflash的功能復用,而這些功能中存在著引腳復用。


二、 virt pinctrl dev驅動實現

前面的文章中,已經說明了pinctrl dev的驅動開發流程,此處再次說明一下:

主要包含如下幾個步驟:

  1. 為該soc pin controller 實現platform device driver驅動,然後在該驅動的probe接口中實現如下功能:
  2. 定義struct pinctrl_desc類型的變量,並實現相應的成員變量的配置,包含支持的引腳描述、支持的引腳復用接口的賦值、支持的引腳配置接口的賦值、支持的group操作接口以及dt2map接口的賦值等;
  3. 調用pinctrl_register/devm_pinctrl_register完成pinctrl device的註冊
  4. 定義該soc pin controller的group相關變量的添加(若使用自行定義的結構存儲就自行實現,也可調用pinctrl_generic_add_group接口實現);
  5. 定義該soc pin controller的function相關變量的添加(若使用自行定義的結構存儲就自行實現,也可調用pinctrl_generic_add_function接口實現);


Virt pinctrl dev數據結構

我們定義了三個數據結構,分別為struct virt_function_desc、struct virt_group_desc、struct virt_pinctrl,其中struct virt_function_desc是對一個function的描述,struct virt_group_desc是對一個group的描述,而struct virt_pinctrl則描述一個soc pin controller。

struct virt_function_desc

該數據結構描述一個function,包含function名稱、該function所包含的group名稱數組、group的個數、引腳復用的配置參數、引腳復用配置參數的掩碼(針對我們的soc,mask為0x03(佔用2位),而mux_val即為引腳復用配置值,如針對iic function,則其mux_val為0x01)


struct virt_group_desc

該數據結構描述一個group,包含group名稱,該group包含的引腳個數、引腳id數組。


struct virt_pinctrl

該數據結構描述一個soc pin controller,包含:

  1. Struct pinctrl_dev類型的指針變量;
  2. 引腳復用寄存器(此處定義為pin_mux_reg,在實際的應用中,應是寄存器基地址的map,即reg_base變量,此處用pin_mux_reg替代);
  3. 該soc pin controller所包含的group信息;
  4. 該soc pin controller所包含的function信息



struct pinctrl_desc類型變量定義

如下是該soc pin controller對應的struct pinctrl_desc類型變量的定義,包含描述該soc pin controller的引腳信息的變量(virt_pins)、引腳復用操作接口(virt_pinmux_ops)、group獲取相關的操作接口(virt_pinctrl_ops),此處我們沒有實現引腳配置的操作接口,感興趣的童鞋可自行實現。




Pinctrl device的註冊

調用pinctrl_register/devm_pinctrl_register接口即完成virt soc controller 驅動的註冊。

如下即為該virt pinctrl dev驅動對應的platform driver probe函數的實現,相對來說比較簡單

在上面我們為該platform device註冊了屬性參數,主要用於讀取引腳復用配置寄存器virt_pinctrl_ptr->pin_mux_reg的信息,定義如下:


三、virt board pin描述及pinctrl maps註冊

上面說明soc pin controller 驅動的實現,下面我們說明virt board pin 描述及pinctrl maps的註冊。由於在ubunt1804上測試,其內核是沒有支持設備樹的,因此我們通過定義struct pinctrl_map數組,並調用pinctrl_register_mappings實現baord相關的pinctrl maps註冊。

因為僅是測試驗證,此處我們僅描述spi0的pinctrl_map(若是正常的驅動,則需要描述本board所需要配置的所有pinctrl_map信息),我們的pinctrl_map,其對應的spi設備名稱為virt_spi.0(spi master設備所對應的platform device的名稱,因為spi master並沒有使用設備與驅動綁定操作,因此此處不能是spi master對應device的名稱)、virt_pinctrl_dev是我們上面定義的virt pinctrl dev對應的struct device類型變量的名稱、spi0_group表示我們選擇的virt soc pin controller的組名稱、spi0_func表示我們選擇的virt soc pin controller的function名稱(對應最上面的引腳狀態定義表格的內容)。

調用pinctrl_regiser_mappings後,則將該pinctrl_map註冊到pinctrl_maps鍊表上。

若內核支持設備樹,則需要在各自外設的的節點中增加針對pinctrl function、pinctrl group的描述即可。如下圖時zynq-zc702的i2c0控制器的節點描述,通過pinctrl-names(描述該function的狀態,包含default、idle、sleep等,在之前的文章中已經說明,需要了解的可查看之前的文章)、pinctrl-0(對應的的function定義)即可描述



四、device與pinctrl的綁定

在上面我們定義了針對spi0的pinctrl map,那什麼時候才會配置spi0的引腳復用呢?我們在前面的《Linux pinctrl子系統分析之六 設備與pinctrl子系統的bind》文章中已經說明,當spi0對應的platform device、platform driver 匹配成功後,probe時進行設備與pinctrl子系統的綁定,並完成引腳的參數配置、復用配置操作。而在此次測試中,我們使用之前在《spi分析專欄》中實現的虛擬spi控制器驅動,完成虛擬spi控制器對應的platform device、platform driver的註冊及綁定,從而完成針對spi0引腳的復用配置操作(虛擬spi控制器驅動實現就不再此處細說了)。

五、gpio與pinctrl子系統相關知識點說明

針對gpio的使用,一般也是需要進行引腳復用配置,如我們在此處定義的引腳狀態表中,這32個引腳既可以作為gpio引腳、也可以作為不同控制器的引腳。而針對gpio控制器而言,和普通的設備引腳復用又有所不同,針對普通的設備而言,若作為設備引腳使用,則這些引腳均被設備使用(如iic0 sda、iic0 scl)。但是針對gpio控制器而言,如我們實現虛擬gpio控制器,其包含32個gpio引腳,但是由於引腳復用的關係,該gpio控制器中可能只有部分引腳可以作為gpio,因此針對gpio的引腳復用配置,pinctrl與gpio子系統做了兼容設置。

在調用gpio_request時,則會調用pinctrl 子系統提供的pin_request操作,通過pin_request確定該引腳是否已被其他模塊使用(gpiochip_generic_request接口或者pinctrl_request_gpio、pinctrl_gpio_requeset)。而針對gpio與pinctrl,存在gpio引腳index與pinctrl pin index的轉換工作,因此定義數據結構描述gpio引腳與pinctrl 引腳的轉換;主要數據結構為struct gpio_pin_range、pinctrl_gpio_range,主要也就是gpio控制器的gpio base、num_gpio、pinctrl pin引腳的base index等信息。只需要在gpio_chip註冊時,將struct gpio_pin_range類型的變量,添加到struct pinctrl_dev的成員變量鍊表gpio_ranges上即可。



本篇文章我們的虛擬gpio控制器驅動(該驅動是在之前《gpio專欄》中實現的,此處不再細述),增加實現了該功能。主要是在虛擬gpio控制器驅動對應platform driver probe中增加針對gpio range的註冊代碼,實現如下:


六、功能驗證

  1. 首先將pinctrl device驅動註冊到系統中:
  2. insmod ./images/virt_pinctrl_dev.ko;
  3. insmod ./images/pinctrl-virt0612.ko

執行完成以上工作後,即完成soc pinctrl dev、pinctrl map的註冊,而我們的pinctrl device對應的platform device路徑為/sys/devices/platform/virt_pinctrl_dev,我們可以在該目錄下查看引腳復用寄存器的設置值。如下:

  1. 將spi controller 註冊到系統中
  2. insmod ./images/virtual_spi_controller.ko

執行完成insmod後,查看寄存器的值

已經完成引腳復用的配置。

  1. 將gpio controller驅動註冊到系統中
  2. insmod ./images/virt_gpio.ko
  3. insmod ./images/virt_gpio_dev.ko

測試驗證下:

我們註冊的gpio的base index為256,我們會發現能夠設置gpio0(即256),但是不能設置gpio6(262),那是引腳6我們已經用作spi0 clk了。下面我們註銷spi 0 controller:

註銷spi0後,就可以使用gpio6了,那是在spi controller註銷時,會調用pin_free釋放該引腳,因此就可以將pin6作為gpio使用了。


以上就是本章的主要內容,我們實現了一個虛擬的pinctrl device驅動,且藉助虛擬的spi控制器驅動、虛擬的gpio控制器驅動、sysfs的屬性文件,完成了完整的模擬工作。希望對學習pinctrl子系統的童鞋有所幫助。(本篇文章涉及的所有代碼,會放到gitee上,稍後會把連結放出來)

相關焦點

  • Linux pinctrl子系統分析之四 pinctrl device的註冊與註銷
    前面我們分析了pinctrl子系統相關的數據結構等內容,本章我們分析pinctrl device的註冊與註銷接口。 針對pinctrl device的註冊與註銷主要涉及pinctrl_register、pinctrl_unregister、devm_pinctrl_register、devm_pinctrl_unregister這幾個接口。
  • Pinctrl子系統重要概念
    現在的晶片動輒幾百個引腳,在使用到GPIO功能時,讓你一個引腳一個引腳去找對應的寄存器,這要瘋掉。術業有專攻,這些累活就讓晶片廠家做吧──他們是BSP工程師。我們在他們的基礎上開發,我們是驅動工程師。開玩笑的,BSP工程師是更懂他自家的晶片,但是如果驅動工程師看不懂他們的代碼,那你的進步也有限啊。
  • Linux pinctrl子系統分析之六 設備與pinctrl子系統的bind
    設備與pinctrl 子系統的bind 在前面我們說了,device是pinctrl的持有者,因此設備相關的引腳復用設置以及引腳配置均應由設備來進行控制,若由設備進行控制的話,難道由每個設備的驅動程序實現引腳復用相關的調用,那豈不是很大的改動量???
  • Linux pinctrl子系統分析之五 pinctrl map註冊與註銷
    前面我們分析了pinctrl device的註冊與註銷接口。本章我們分析pinctrl maps的註冊,pinctrl maps屬於board pin描述相關的範疇。 針對pinctrl map的註冊與註銷主要涉及兩方面:當內核不支持設備樹時,則通過調用pinctrl_register_mappings、pinctrl_register_map接口實現pinctrl maps的註冊;當內核支持設備樹時,則在設備與驅動match後,在設備驅動的probe接口調用pinctrl_bind_pins
  • 「正點原子Linux連載」第四十五章 pinctrl和gpio子系統實驗一
    Linux是一個龐大而完善的系統,尤其是驅動框架,像GPIO這種最基本的驅動不可能採用「原始」的裸機驅動開發方式,否則就相當於你買了一輛車,結果每天推著車去上班。Linux內核提供了pinctrl和gpio子系統用於GPIO驅動,本章我們就來學習一下如何藉助pinctrl和gpio子系統來簡化GPIO驅動開發。
  • GPIO和Pinctrl子系統的使用在100ASK_IMX6ULL上機實驗
    我們也把它上傳到GIT去了,使用GIT命令載後,在這個目錄下:01_all_series_quickstart\04_快速入門_正式開始\02_嵌入式Linux驅動開發基礎知識\source\05_gpio_and_pinctrl\tools\imx\安裝「Pins_Tool_for_i.MX_Processors_v6_x64.exe」後運行,打開IMX6ULL的配置文件「MCIMX6Y2xxx08.mex」,就可以在GUI界面中選擇引腳,配置它的功能,這就可以自動生成Pinctrl的子節點信息。
  • 「正點原子Linux連載」第五十九章Linux LCD驅動實驗
    在裸機中我們可以隨意的分配顯存,但是在Linux系統中內存的管理很嚴格,顯存是不需要申請的,不是你想用就能用的。而且因為虛擬內存的存在,驅動程序設置的顯存和應用程式訪問的顯存要是同一片物理內存。fb是一種機制,將系統中所有跟顯示有關的硬體以及軟體集合起來,虛擬出一個fb設備,當我們編寫好LCD驅動以後會生成一個名為/dev/fbX(X=0~n)的設備,應用程式通過訪問/dev/fbX這個設備就可以訪問LCD。
  • Linux regulator子系統分析之三 regulator註冊、註銷接口分析
    在上一章我們介紹了regulator子系統相關的數據結構間的關聯以及每一個數據結構的定義。針對數據結構間的關聯則需要regulator子系統提供的接口實現。而本章我們就說明這些接口。這兩個接口是否只設置一個等;為該regulator_dev創建struct device類型的變量,並註冊到linux設備驅動模型子系統中,並完成與regulator_class的關聯;為該regulator_dev創建設備屬性文件(在sysfs文件系統下創建屬性文件,以便應用程式通過設備屬性文件即可查看該regulator_dev相關的配置信息,如最小電壓、最大電壓
  • i.MX8 系列 | 如何通過 GPIO 驅動配置實現控制 i.MX8 晶片引腳電平變化
    本文我們要講的是如何通過 GPIO 驅動配置實現控制 i.MX8 晶片引腳電平變化。= "default"; pinctrl-0 = <&pinctrl_gpio_keys>; };使用的引腳編號為 GPIO4_22,引腳功能定義 pinctrl_gpio_keys 如下:pinctrl_gpio_keys: myled{
  • Linux regulator子系統分析之四 虛擬regulator device驅動實現
    在前面幾章,我們分析了regulator子系統框架,主要是從數據結構及數據結構間的關聯分析了regulator子系統。為了讓大家對regulator子系統有一個深入的認識,我們本章將實現一個虛擬的regulator device驅動,從而掌握對regulator子系統的開發流程。
  • 「正點原子Linux連載」第六十一章Linux I2C驅動實驗
    第六十一章Linux I2C驅動實驗I2C是很常用的一個串行通信接口,用於連接各種外設、傳感器等器件,在裸機篇已經對I.MX6U的I2C接口做了詳細的講解。本章我們來學習一下如何在Linux下開發I2C接口器件驅動,重點是學習Linux下的I2C驅動框架,按照指定的框架去編寫I2C設備驅動。
  • 「正點原子Linux連載」第六十二章Linux SPI驅動實驗
    第六十二章Linux SPI驅動實驗上一章我們講解了如何編寫Linux下的I2C設備驅動,SPI也是很常用的一個串行通信協議,本章我們就來學習一下如何在Linux下編寫SPI設備驅動。62.3 SPI設備驅動編寫流程62.3.1 SPI設備信息描述1、IO的pinctrl子節點創建與修改首先肯定是根據所使用的IO來創建或修改pinctrl子節點,這個沒什麼好說的,唯獨要注意的就是檢查相應的IO有沒有被其他的設備所使用
  • Linux regmap子系統分析之二 從數據結構分析系統實現
    另外有的設備廠家針對一款設備可能存在iic接口與spi接口兩種可選的接口方式,針對這一類設備進行設備驅動開發時,該驅動也會抽象出統一的讀寫接口(如AD913x型號、AD538x型號的設備,就包含兩種接口類型的型號);基於以上考慮,linux內核子系統提供了regmap子系統,該子系統對外提供統一的讀寫接口,而針對AD913x型號、AD538x型號的設備驅動而言,則只需要提供兩種類型的probe、remove
  • AM335x(TQ335x)學習筆記——WM8960音效卡驅動移植
    經過一段時間的調試,終於調好了TQ335x的音效卡驅動。TQ335x採用的Codec是WM8960,本文來總結下WM8960驅動在AM335x平臺上的移植方法。Linux音效卡驅動架構有OSS和ALSA兩種架構,目前最常用的架構是ALSA,本文也使用ALSA架構對WM8960驅動進行移植。ASoC是對ALSA驅動架構的進一步封裝。
  • i2c的設備樹和驅動是如何匹配以及何時調用probe的?
    粉絲手裡的I2C外設是ov5640,一個攝像頭。 粉絲提問,一口君必須安排。 = "default";  pinctrl-0 = <&pinctrl_csi1                    
  • 基於Linux平臺的FPGA驅動開發
    這個工作頻率能夠使處理器輕鬆運行於Windows CE,Linux等作業系統並進行較為複雜的信息處理。為此,本文以S3C2410上使用Altera公司的EP2S30F67214為例,系統地介紹了在Linux系統環境下的FPGA的驅動方法。1 基本原理 Linux下的設備驅動程序通常是一個存在於應用程式和實際設備間的軟體層。
  • RK3399 探索之旅 / Audio 驅動層速讀
    從驅動開發的角度大致了解一下 RK3399 Audio 功能。在 Asoc 驅動中,用 Widget 來描述一個音效卡的功能部件參考文檔:Documentation/sound/alsa/soc/dapm.txt這裡定義了 2 個 Widget:Headphone Jack,代表 3.5 mm 耳機座3) 設置單板相關的 Routing
  • LINUX 中斷子系統專欄之二 虛擬中斷控制器驅動實現
    在上一篇文章中,我們簡要分析了中斷子系統框架,本章我們將通過實現一個虛擬的中斷控制器驅動,說明如何進行中斷控制器驅動開發。本章的內容大概分為如下幾部分:一、實現虛擬中斷控制器的可行性說明二、中斷控制器驅動的開發流程三、虛擬中斷控制器驅動設計說明一、實現虛擬中斷控制器的可行性說明在進行虛擬中斷控制器的設計之前,我們先說明下linux系統中硬體中斷觸發後的處理過程。