1.pinctrl驅動
SoC內部都包含pin控制器,通過控制pin的寄存器,我們可以配置一個或者一組引腳的功能和特性
linux系統下采用pinctrl子系統管理所有的IO管腳
# ls out/target/product/msm8998/obj/kernel/msm-4.4/drivers/pinctrl/qcom/ -l
總用量 1668
-rw-r--r-- 1 root root 821920 6月 8 13:37 built-in.o
-rw-r--r-- 1 root root 136 6月 8 15:33 modules.builtin
-rw-r--r-- 1 root root 0 6月 8 15:35 modules.order
-rw-r--r-- 1 root root 254448 6月 8 13:37 pinctrl-msm8998.o
-rw-r--r-- 1 root root 206232 11月 10 2017 pinctrl-msm.o
-rw-r--r-- 1 root root 233064 11月 10 2017 pinctrl-sdm660.o
-rw-r--r-- 1 root root 155960 11月 10 2017 pinctrl-wcd.o
驅動位置kernel/msm-4.4/drivers/pinctrl/qcom/pinctrl-msm8998.c
platform_driver_register(&msm8998_pinctrl_driver);
static const struct of_device_id msm8998_pinctrl_of_match[] = {
{ .compatible = "qcom,msm8998-pinctrl", },
{ },
}
static const struct msm_pinctrl_soc_data msm8998_pinctrl = {
.pins = msm8998_pins,//管腳描述,包括管腳編號和管腳字符串描述
.npins = ARRAY_SIZE(msm8998_pins),//管腳的總個數
.functions = msm8998_functions,//數組描述所有的SOC所支持的mux functions
.nfunctions = ARRAY_SIZE(msm8998_functions),
.groups = msm8998_groups,//描述引腳SOC支持的所有引腳組的陣列
.ngroups = ARRAY_SIZE(msm8998_groups),
.ngpios = 153,//可以導出的gpio的數量
};
dts
compatible = "qcom,msm8998-pinctrl";
kernel/msm-4.4/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi:
//msm_uart功能
uart_console_active: uart_console_active {
mux {
pins = "gpio4", "gpio5";
function = "blsp_uart8_a";//串口功能
};
config {
pins = "gpio4", "gpio5";
drive-strength = <2>;
bias-disable;
};
};
led_disable: led_disable {
mux {
pins = "gpio21";
function = "gpio";//gpio功能
};
config {
pins = "gpio21";
drive_strength = <2>;
output-low;
bias-disable;
};
};
2. gpiolib驅動
在drivers/gpio下實現了通用的基於gpiolib的GPIO驅動,
其中定義了一個通用的用於描述底層GPIO控制器的gpio_chip結構體,
並要求具體的SoC實現gpio_chip結構體的成員函數,
最後透過gpiochip_add()註冊gpio_chip
kernel/msm-4.4/drivers/gpio/gpiolib.c
在用戶空間/sys/class/gpio目錄下看到
msm8998:/sys/class/gpio # ls
export gpiochip346 gpiochip506 gpiochip666 gpiochip826 gpiochip986
gpiochip0 gpiochip378 gpiochip538 gpiochip698 gpiochip858 unexport
gpiochip1018 gpiochip410 gpiochip570 gpiochip730 gpiochip890
gpiochip1019 gpiochip442 gpiochip602 gpiochip762 gpiochip922
gpiochip341 gpiochip474 gpiochip634 gpiochip794 gpiochip954
操作gpio以gpio21爲例
msm8998:/sys/class/gpio # echo 21 > export
msm8998:/sys/class/gpio # cd gpio21/
echo in/out > direction //設置gpio輸入或輸出
msm8998:/sys/class/gpio/gpio21 # echo out > direction
msm8998:/sys/class/gpio/gpio21 # echo '1' > value //設置gpio的電平
操作完成後
msm8998:/sys/class/gpio # echo 21 > unexport
主要操作direction和value這兩個文件
direction 用來配置輸入(in)還是輸出(out)
value 如果這個GPIO配置成了輸入,那麼通過cat value可以查看當前這個GPIO是什麼電位
如果配置成了輸出,那麼可以通過echo 1/0 > value給這個GPIO口指定輸出電平
3.在內核中配置gpio
1)單個gpio的配置
kernel/msm-4.4/arch/arm/boot/dts/qcom/msm8998-qrd-skuk-hdk.dtsi
st,reset-gpio = <&tlmm 89 0x00>;
驅動代碼的獲取
int rest_gpio = of_get_named_gpio_flags(np,”st, reset-gpio”, 0, NULL);
gpio_request(rest_gpio, "gpio_name");
gpio_direction_output(rest_gpio, 1);
gpio_set_value(rest_gpio, 0);
gpio_free(rest_gpio);
關於TLMM
MSM Socs擁有pinmux controller作爲Top-LEVEL Mode Multiplexer(TLMM)
TLMM支持複用和配置不同類型的pins
2)用pinctrl配置設備樹,一次配置多個gpio
在驅動裏邊常常碰到驅動相關的一個或者幾個gpio,在
醒來或者睡眠的時候需要設置成不同的類型,例如醒來的時候是i2c端口,但睡眠的時候可能要
設置成GPIO並把輸出設置成0等。
參考:kernel/msm-4.4/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
kernel/msm-4.4/arch/arm/boot/dts/qcom/msm8998-qrd-skuk-hdk.dtsi
pinctrl-0 = <&ts_active>; //引用ts_active
pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>;//引用ts_int_suspend ts-reset_suspend
在kernel/msm-4.4/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi中
ts_mux {
ts_active: ts_active {
mux {
pins = "gpio89", "gpio125";
function = "gpio";
};
config {
pins = "gpio89", "gpio125";
drive-strength = <16>;
bias-pull-up;//上拉
};
};
ts_reset_suspend: ts_reset_suspend {
mux {
pins = "gpio89";
function = "gpio";
};
config {
pins = "gpio89";
drive-strength = <2>;
bias-pull-down;//下拉
};
};
ts_int_suspend: ts_int_suspend {
mux {
pins = "gpio125";
function = "gpio";
};
config {
pins = "gpio125";
drive-strength = <2>;
bias-disable;
};
};
};
};
內核驅動代碼
kernel/msm-4.4/drivers/input/touchscreen/st/fts.c
kernel/msm-4.4/drivers/input/touchscreen/ft5x06_ts.c
ft5x06_data->ts_pinctrl = devm_pinctrl_get(&(ft5x06_data->client->dev));//獲取device對應節點下的pinctrl
ft5x06_data->pinctrl_state_active
= pinctrl_lookup_state(ft5x06_data->ts_pinctrl,PINCTRL_STATE_ACTIVE);//通過pinctrl名獲取pinctrl對應狀態
ft5x06_data->pinctrl_state_release
= pinctrl_lookup_state(ft5x06_data->ts_pinctrl,PINCTRL_STATE_RELEASE);
pinctrl_select_state(data->ts_pinctrl,data->pinctrl_state_release);////設置pinctrl的狀態爲pinctrl_state_release
devm_pinctrl_put(ft5x06_data->ts_pinctrl);//釋放資源