设备树中pinctrl的简单使用

文档:内核 Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt

s3c2440-pinctrl.dtsi

/*
 * Samsung S3C2416 pinctrl settings
 *
 * Copyright (c) 2013 Heiko Stuebner 
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include 

&pinctrl_0 {
	/*
	 * Pin banks
	 */

	gpa: gpa {
		gpio-controller;
		#gpio-cells = <2>;
	};

	gpb: gpb {
		gpio-controller;
		#gpio-cells = <2>;
	};

	gpc: gpc {
		gpio-controller;
		#gpio-cells = <2>;
	};

	gpd: gpd {
		gpio-controller;
		#gpio-cells = <2>;
	};

	gpe: gpe {
		gpio-controller;
		#gpio-cells = <2>;
	};

	gpf: gpf {
		gpio-controller;
		#gpio-cells = <2>;
		interrupt-controller;
		#interrupt-cells = <2>;
	};

	gpg: gpg {
		gpio-controller;//gpio控制器
		#gpio-cells = <2>;
		interrupt-controller;//中断控制器
		#interrupt-cells = <2>;
	};

	gph: gph {
		gpio-controller;
		#gpio-cells = <2>;
	};

	gpj: gpj {
		gpio-controller;
		#gpio-cells = <2>;
	};

	/*
	 * Pin groups
	 */

	uart0_data: uart0-data {
		samsung,pins = "gph-0", "gph-1";
		samsung,pin-function = <2>;
	};

	i2c0_bus: i2c0-bus {
		samsung,pins = "gpe-14", "gpe-15";
		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
	};

	nand_pinctrl: nand_pinctrl {
		samsung,pins = "gpa-17", "gpa-18", "gpa-19",
				 "gpa-20", "gpa-22";
		samsung,pin-function = <1>;
	};

	lcd_pinctrl: lcd_pinctrl {
		samsung,pins = "gpc-8", "gpc-9", "gpc-10", "gpc-11", "gpc-12", "gpc-13", "gpc-14", "gpc-15",
				"gpd-0", "gpd-1", "gpd-2", "gpd-3", "gpd-4", "gpd-5", "gpd-6", "gpd-7",
				"gpd-8", "gpd-9", "gpd-10", "gpd-11", "gpd-12", "gpd-13", "gpd-14", "gpd-15",
				"gpc-1", "gpc-2", "gpc-3", "gpc-4";
		samsung,pin-function = <2>;
	};

	lcd_backlight: lcd_backlight {
		samsung,pins = "gpg-4";
		samsung,pin-function = <3>;
	};

	uda1340_codec_pinctrl: uda1340_codec_pinctrl {
		samsung,pins = "gpb-4", "gpb-3", "gpb-2";
		samsung,pin-function = <1>;
	};

	s3c2440_iis_pinctrl: s3c2440_iis_pinctrl {
		samsung,pins = "gpe-0", "gpe-1", "gpe-2", "gpe-3", "gpe-4";
		samsung,pin-function = <2>;
	};
};

几个概念:
Bank: 以引脚名为依据, 这些引脚分为若干组, 每组称为一个Bank
比如s3c2440里有GPA、GPB、GPC等Bank,
每个Bank中有若干个引脚, 比如GPA0,GPA1, …, GPC0, GPC1,…等引脚

Group: 以功能为依据, 具有相同功能的引脚称为一个Group
比如s3c2440中串口0的TxD、RxD引脚使用 GPH2,GPH3, 那这2个引脚可以列为一组
比如s3c2440中串口0的流量控制引脚使用 GPH0,GPH1, 那这2个引脚也可以列为一组

State: 设备的某种状态, 比如内核自己定义的"default",“init”,“idel”,"sleep"状态;
也可以是其他自己定义的状态, 比如串口的"flow_ctrl"状态(使用流量控制);
设备处于某种状态时, 它可以使用若干个Group引脚。

a. 设备树中pinctrl节点:
1.它定义了各种 pin bank, 比如s3c2440有GPA,GPB,GPC,…,GPB各种BANK, 每个BANK中有若干引脚:
pinctrl_0: pinctrl@56000000 {
reg = <0x56000000 0x1000>;

	gpa: gpa {
		gpio-controller;
		#gpio-cells = <2>;  /* 以后想使用gpa bank中的引脚时, 需要2个u32来指定引脚 */
	};

	gpb: gpb {
		gpio-controller;
		#gpio-cells = <2>;
	};

	gpc: gpc {
		gpio-controller;
		#gpio-cells = <2>;
	};

	gpd: gpd {
		gpio-controller;
		#gpio-cells = <2>;
	};
};
  1. 它还定义了各种group(组合), 某种功能所涉及的引脚称为group,
    比如串口0要用到2个引脚: gph0, gph1:

    uart0_data: uart0-data {
    samsung,pins = “gph-0”, “gph-1”;
    samsung,pin-function = <2>;
    };

    uart0_sleep: uart0_sleep {
    samsung,pins = “gph-0”, “gph-1”;
    samsung,pin-function = <0>; /* 0 — 输入功能*/
    };
    /* 在GPHCON寄存器中gph0,gph1可以设置以下值:
    0 — 输入功能00
    1 — 输出功能01
    2 — 串口功能10
    我们要使用串口功能, samsung,pin-function 设置为2

b. 设备节点中要使用某一个 pin group:
//串口设备节点
serial@50000000 {

pinctrl-names = “default”, “sleep”; /* 既是名字, 也称为state(状态) */
pinctrl-0 = <&uart0_data>;
pinctrl-1 = <&uart0_sleep>;
};

pinctrl-names中定义了2种state: default 和 sleep,
default 对应的引脚是: pinctrl-0, 它指定了使用哪些pin group: uart0_data
sleep 对应的引脚是: pinctrl-1, 它指定了使用哪些pin group: uart0_sleep

c. platform_device, platform_driver匹配时:
“第3课第06节_platform_device跟platform_driver的匹配” 中讲解了platform_device和platform_driver的匹配过程,
最终都会调用到 really_probe (drivers/base/dd.c)

really_probe:
	/* If using pinctrl, bind pins now before probing */
	ret = pinctrl_bind_pins(dev);
				dev->pins->default_state = pinctrl_lookup_state(dev->pins->p,
								PINCTRL_STATE_DEFAULT);  /* 获得"default"状态的pinctrl */
				dev->pins->init_state = pinctrl_lookup_state(dev->pins->p,
								PINCTRL_STATE_INIT);    /* 获得"init"状态的pinctrl */

				ret = pinctrl_select_state(dev->pins->p, dev->pins->init_state);    /* 优先设置"init"状态的引脚 */
				ret = pinctrl_select_state(dev->pins->p, dev->pins->default_state); /* 如果没有init状态, 则设置"default"状态的引脚 */
			ret = drv->probe(dev);					

所以: 如果设备节点中指定了pinctrl, 在对应的probe函数被调用之前, 先"bind pins", 即先绑定、设置引脚

d. 驱动中想选择、设置某个状态的引脚:
devm_pinctrl_get_select_default(struct device *dev); // 使用"default"状态的引脚
pinctrl_get_select(struct device *dev, const char *name); // 根据name选择某种状态的引脚

pinctrl_put(struct pinctrl *p); // 不再使用, 退出时调用

你可能感兴趣的:(linux驱动)