1 概要
Linux核心中提供了pinctrl子系統,目的是為了統一各SoC廠商的pin腳管理,避免各SoC廠商各自實作相同的pin腳管理子系統,減少SoC廠商系統移植工作量。
1.1 主要功能
1. 管理系統中所有可以控制的pin。在系統初始化的時候,枚舉所有可以控制的pin,并辨別這些pin。
2. 管理這些pin的複用(Multiplexing)。對于SOC而言,其引腳除了配置成普通GPIO之外,若幹個引腳還可以組成一個pin group,形成特定的功能。例如pin number是{ 0, 8, 16, 24 }這四個引腳組合形成一個pin group,提供SPI的功能。pin control subsystem要管理所有的pin group。
3. 配置這些pin的特性。例如配置該引腳上的pull-up/down電阻,配置drive strength等。
4. 與GPIO子系統的互動
5. 實作pin中斷
1.2 核心驅動源碼檔案
1.3 總體架構
2源碼分析
kernel配置檔案: lichee/linux-3.4/arch/arm/configs/sun8iw7p1smp_android_defconfig
系統配置檔案:lichee\tools\pack\chips\sun8iw7p1\configs\dolphin-p1\sys_config.fex
arch/arm/mach-sunxi/ sys_config.c //分析、處理sys_config.fex檔案。
drivers/pinctrl/ core.c //建立debug fs,提供pinctrl_register等函數接口。
drivers/pinctrl/ pinctrl-sun8iw7.c //該平台下的pin腳資料
2.1 驅動加載時主流程代碼
(1) drivers/pinctrl/ pinctrl-sunxi.c
1 sunxi_pinctrl_probe函數:
pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL); // devm_kzalloc基于slab配置設定在實體上連續的實際的記憶體, 并且帶有釋放記憶體的回調函數,當該裝置與驅動分開時,自動釋放記憶體。
pctl->desc = (struct sunxi_pinctrl_desc *)(&sunxi_pinctrl_data);
1.1 sunxi_pinctrl_build_state(pdev);//将pctl->desc的子項資料複制到pctl相應子項。
1.2 pctl->pctl_dev = pinctrl_register(&sunxi_pctrl_desc, &pdev->dev, pctl); //建立pinctrl_dev裝置,調用pinctrl_register_pins(pctldev, pctldesc->pins, pctldesc->npins);注冊所有的pin。
1.2.1 pinctrl_register_pins對每一個pin腳調用 ret=pinctrl_register_one_pin(pctldev, pins[i].number, pins[i].name); //将pin 的實體位址,名字存入pin_desc結構體,将該結構體加入pin_desc_tree連結清單。
1.2.2 pctldev->p = pinctrl_get_locked(pctldev->dev); //先調用find_pinctrl從pinctrl_list連結清單中查找看pin control state holder是否存在;存在,即表明其正在使用中;不存在時,調用create_pinctrl建立pinctrl,從pinctrl_maps連結清單查找對應dev的maps_node,而maps裡面的資料是從sys_config.fex檔案分析擷取,詳見1.5。如找到對應的maps_node,則調用add_setting(p, map);該函數針對map->type填充pinctrl_setting相應成員變量,如果是PIN_MAP_TYPE_MUX_GROUP類型,填充之後,還會調用pin_request注冊同組中所有的pin。
最後将pinctrl加入pinctrl_list連結清單。
1.2.3 pinctrl_init_device_debugfs(pctldev); //注冊debugfs
1.3 gpiochip_add //GPIO驅動将通過chip來與pinctrl聯系,相應的操作将通過sunxi_pinctrl_gpio_chip結構的方法成員實作相應的操作。
将全局變量gpio_desc的成員變量chip、flags賦初值。後續GPIO相應操作将通過gpio_desc進行。
1.3.1 of_gpiochip_add(chip);
初始化chip的相應變量,并增加chip->of_node的引用計數
1.3.2 gpiochip_export(chip)
建立gpiochip0裝置,其屬性檔案用來show chip->ngpio, chip->label, chip->base
1.4 gpiochip_add_pin_range 建立動态連結清單chip->pin_ranges,node為gpio_pin_range,其成員range包含pin腳基位址。
1.5 sunxi_pinctrl_parse_pin_cfg (pdev); //分析擷取sys_config.fex檔案中的配置,
1.5.1 sunxi_pinctrl_creat_mappings(pdev, pin_count, pin_list, device_name, state_name); //用配置資料填充pinctrl_map
1.5.2 pinctrl_register_mappings //建立pinctrl_maps,将pinctrl_map指派給其maps成員變量,并加入pinctrl_maps連結清單。
1.6 sunxi_eint_gpio_init //注冊中斷
(2) drivers/gpio/ gpio-sunxi.c
1. gpio_sw_init // 讀取sys_config.fex檔案中gpio_para參數對應的配置資料組,有單獨led_assign進行處理
1.1 gpio_request //向pinctrl請求pin用作GPIO,成功後,該Pin僅能被GPIO驅動所使用,不能被其他驅動所混用
通過本檔案的靜态結構數組gpio_desc找到對應的pin腳的設定,具體資料見Pinctrl-sun8iw7.c (drivers\pinctrl)
chip->request 等價于執行 sunxi_pinctrl_gpio_chip. Request = sunxi_pinctrl_gpio_request
-> pinctrl_request_gpio -> pinmux_request_gpio -> pin_request -> pctldev->desc->pmxops->
(1. gpio_request_enable 2. request)
1.2 platform_device_register(gpio_sw_dev[i]) //注冊平台裝置
gpio_sw_dev[i]->name = "gpio_sw";
gpio_sw_dev[i]->id = i;
gpio_sw_dev[i]->dev.platform_data = sw_pdata[i];
gpio_sw_dev[i]->dev.release = gpio_sw_release;
1.3 platform_driver_register(&gpio_sw_driver)
注冊gpio_sw驅動,
gpio_sw_probe: 調用gpio_sw_cfg_set及gpio_sw_data_set函數根據參數配置設定,調用gpio_sw_classdev_register建立相應的裝置屬性檔案,即提供接口給上層,如上接,寫1/0等操作。根據sw_pdata->link建立超連結
/sys/class/gpio_sw /normal_led -> PA15
/sys/class/gpio_sw /standby_led -> PL10
/sys/devices/platform/gpio_sw.0/gpio_sw/PL10/cfg
/sys/devices/platform/gpio_sw.1/gpio_sw/PA15/cfg
2.2 向其他驅動子產品提供的接口函數
1. 非GPIO驅動子產品使用的接口:
pinctrl_get //擷取裝置的pin操作句柄
struct pinctrl *pinctrl_get(struct device *dev) à p = pinctrl_get_locked(dev);
第641行調用find_pinctrl函數
第645行調用create_pinctrl,擷取pinctrl結構體
pinctrl_put
devm_pinctrl_get
devm_pinctrl_put
pinctrl_lookup_state //查找pinctrl_state
pinctrl_select_state //将pin句柄對應的pinctrl設定為state句柄對應的狀态,其核心為通過pinmux_enable_setting或pinconf_apply_setting來調用pinctrl_desc的ops來設定pin狀态。
devm_pinctrl_get_select
devm_pinctrl_get_select_default
pin_config_get //擷取指定pin的屬性,最終是通過confops->pin_config_get擷取
pin_config_set //設定指定pin的屬性,最終是通過confops->pin_config_set設定
pin_config_group_get //與上類似,pin_config_group_get
pin_config_group_set //與上類似,pin_config_group_set
2.3 GPIO驅動使用的接口
drivers/gpio/ gpiolib.c
gpio_request
gpio_free
gpio_direction_input
gpio_direction_output
__gpio_get_value
__gpio_set_value
2.4 各資料之間的聯系圖
3 使用方法及執行個體
1. GPIO口配置:
lichee/tools/pack/chips/sun8iw7p1/configs/dolphin-p1/sys_config.fex 參照如下配置即可:
;----------------------------------------------------------------------------------
;userspace gpio interface for android
;----------------------------------------------------------------------------------
[gpio_para]
gpio_used = 1
gpio_num = 2
gpio_pin_1 = port:PL10<1><default><default><1>
gpio_pin_2 = port:PA15<1><default><default><0>
a. 向應用層提供的接口檔案如下:
/sys/devices/platform/gpio_sw.0/gpio_sw/PL10/
/sys/devices/platform/gpio_sw.1/gpio_sw/PA15/
b. 核心其他子產品使用:
#include <linux/gpio.h>
__gpio_get_value
__gpio_set_value
2. 非GPIO驅動子產品的使用
#include <linux/pinctrl/consumer.h>
devm_pinctrl_get
pinctrl_lookup_state
pinctrl_select_state
4 參考文獻
1.《H3 Pinctrl(GPIO)接口使用說明V1.0.pdf》
2. http://www.wowotech.net/gpio_subsystem/pin-control-subsystem.html/ comment-page-2#comments