在嵌入式系统开发中,我们不可避免的要跟SOC 的GPIO模块打交道。在单片机的开发中,我们一般使用的是下面的模式
void XXX_init()
{
//gpio fuction mux select
//peripheral regsiter configure
//other related software resourece init
}
其实在早期的linux系统中,外设的初始化也是一个类似的过程,只不过是要使用linux提供提供的一些接口而已,不像单片机可以随心所欲的写code
但是随着linux的发展 device tree已经慢慢统治了powerpc linux和arm linux。就使用来说,的确是简单了很多,但是linux引入了大量的框架来支持这些便利,要多了一些需要精读的代码,这里不分析代码实现的细节,只是从使用的角度来记录一下,方便以后的工作中,查询使用。
这里分三种情况来举例说明
1. 外围控制器的mux功能选择,以IPQ409的SPI控制器举例,这里主要用的是PINCTRL 的MUX 设定
要想把某组pin分配给SPI0控制器,需要在dts里做如下定义:
1).定义一个pn mux
spi_0_pins: spi_0_pinmux {
mux {
pins = "gpio12", "gpio13", "gpio14", "gpio15"; //pin列表,可以查看芯片手册获取这个group
function = "blsp_spi0";
bias-disable;
};
2).在spi的控制器节点引用之
spi_0: spi@78b5000 {
/* BLSP1 QUP1 */
pinctrl-0 = <&spi_0_pins>;
pinctrl-names = "default";
status = "ok";
m25p80@0 {
#address-cells = <1>;
#size-cells = <1>;
reg = <0>;
compatible = "n25q128a11";
linux,modalias = "m25p80", "n25q128a11";
spi-max-frequency = <24000000>;
use-default-sizes;
};
};
2. 定义pin为gpio,并设置默认的 输入输出属性已经上下拉配置以及驱动电流等
dts文件里在pinctrl节点下添加以下定义,可以定义若干pin group,或者只对某个pin做特殊的描述,
gpio可以配置的属性如下:
bias-disable – disable any pin bias
bias-pull-up – pull up the pin
bias-pull-down – pull down the pin
drive-strength – sink or source at most X mA
input-enable – enable input on pin (no effect on output)
input-disable – disable input on pin (no effect on output)
output-low – set the pin to output mode with low-level
output-high – set the pin to output mode with high-level
pinctrl@0x01000000 {
pinctrl-0 = <&example_gpio>;
pinctrl-names = "default";
............
example_gpio: hw_gpio{
led{
pins = "gpio37","gpio42","gpio51","gpio52","gpio61","gpio68";
output-low;
};
gpio{
pins = "gpio49";
output-high;
};
gpio_i2c{
pins = "gpio21","gpio20";
drive-strength = <4>;
};
};
.................
};
3. 在某个device node需要使用gpio,或者使用gpio作为中断输入
这里以一个GPIO模拟的I2C控制器举例
i2c_1 {
compatible = "atmel,i2c-gpio";
status = "ok";
gpios = <&tlmm 21 0 &tlmm 20 0>; /*i2c pin */
i2c-gpio,delay-us = <2>;
i2c-gpio,scl-open-drain;
#address-cells = <1>;
#size-cells = <0>;
isl28022@40 {
/* power monitor */
compatible = "isl,isl28022";
reg = <0x40>;
/*use gpio 43 as gpio interrupt,tlmm is the gpio controller defined in the example soc system*/
interrupt-parent = <&tlmm>;
interrupts = <43 0x8>;
irq-gpio = <&tlmm 43 0>;
};