Linux pinctrl子系統分析之七---一個虛擬pinctrl dev驅動開發實例

     這周主要對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接口中實現如下功能:
    1. 定義struct pinctrl_desc類型的變量,並實現相應的成員變量的配置,包含支持的引腳描述、支持的引腳複用接口的賦值、支持的引腳配置接口的賦值、支持的group操作接口以及dt2map接口的賦值等;
    2. 調用pinctrl_register/devm_pinctrl_register完成pinctrl device的註冊
    3. 定義該soc  pin controller的group相關變量的添加(若使用自行定義的結構存儲就自行實現,也可調用pinctrl_generic_add_group接口實現);
    4. 定義該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驅動註冊到系統中:
    1. insmod ./images/virt_pinctrl_dev.ko;
    2. insmod ./images/pinctrl-virt0612.ko

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

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

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

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

  1. 將gpio controller驅動註冊到系統中
    1. insmod ./images/virt_gpio.ko
    2. 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子系統的童鞋有所幫助。

      本章所實現的所有測試代碼鏈接如下:https://gitee.com/jerry_chg/virt_pinctrl_dev.git

(代碼已在ubuntu18.04上完成驗證)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章