#define XGPIOPS_NR_GPIOS 118
这里一共注册了118个GPIO口,看看Datasheet就知道这里的意思应该是MIO[0:53]+EMIO[54:117],也就是54个MIO加上64个EMIO,看到这里我还是有一些疑问,因为并不是所有的IO口都作为GPIO来使用的,有很大一部分是进行IO复用的,下面是我在XPS中的MIO配置截图:
EMIO的配置,可以在上面的截图中看到XPS中配置了60个EMIO,并且在xps的ucf文件中可以找到配置相关注释:
#############################################################
# #
# GPIO Interface #
# #
#############################################################
………………………………
############################
# #
# On-board OLED #
# #
# Voltage control and #
# Bitbanged SPI over GPIO #
# #
############################
net processing_system7_0_GPIO<1> LOC = U11 | IOSTANDARD = LVCMOS33;
# OLED-VBAT
net processing_system7_0_GPIO<2> LOC = U12 | IOSTANDARD = LVCMOS33;
# OLED-VDD
net processing_system7_0_GPIO<3> LOC = U9 | IOSTANDARD = LVCMOS33;
# OLED-RES
net processing_system7_0_GPIO<4> LOC = U10 | IOSTANDARD = LVCMOS33;
# OLED-DC
net processing_system7_0_GPIO<5> LOC = AB12 | IOSTANDARD = LVCMOS33;
# OLED-SCLK
net processing_system7_0_GPIO<6> LOC = AA12 | IOSTANDARD = LVCMOS33;
# OLED-SDIN
############################
# #
# On-board LED's #
# #
############################
net processing_system7_0_GPIO<7> LOC = T22 | IOSTANDARD = LVCMOS33;
# LD0
net processing_system7_0_GPIO<8> LOC = T21 | IOSTANDARD = LVCMOS33;
# LD1
net processing_system7_0_GPIO<9> LOC = U22 | IOSTANDARD = LVCMOS33;
# LD2
net processing_system7_0_GPIO<10> LOC = U21 | IOSTANDARD = LVCMOS33;
# LD3
net processing_system7_0_GPIO<11> LOC = V22 | IOSTANDARD = LVCMOS33;
# LD4
net processing_system7_0_GPIO<12> LOC = W22 | IOSTANDARD = LVCMOS33;
# LD5
net processing_system7_0_GPIO<13> LOC = U19 | IOSTANDARD = LVCMOS33;
# LD6
net processing_system7_0_GPIO<14> LOC = U14 | IOSTANDARD = LVCMOS33;
# LD7
############################
# #
# On-board Slide Switches #
# #
############################
net processing_system7_0_GPIO<15> LOC = F22 | IOSTANDARD = LVCMOS33;
# SW0
net processing_system7_0_GPIO<16> LOC = G22 | IOSTANDARD = LVCMOS33;
# SW1
net processing_system7_0_GPIO<17> LOC = H22 | IOSTANDARD = LVCMOS33;
# SW2
net processing_system7_0_GPIO<18> LOC = F21 | IOSTANDARD = LVCMOS33;
# SW3
net processing_system7_0_GPIO<19> LOC = H19 | IOSTANDARD = LVCMOS33;
# SW4
net processing_system7_0_GPIO<20> LOC = H18 | IOSTANDARD = LVCMOS33;
# SW5
net processing_system7_0_GPIO<21> LOC = H17 | IOSTANDARD = LVCMOS33;
# SW6
net processing_system7_0_GPIO<22> LOC = M15 | IOSTANDARD = LVCMOS33;
# SW7
这里的processing_system7_0_GPIO指的的就是EMIO,所以可以看到EMIO[1:6]是用的OLED,而在GPIO寄存器配置中:
GPIO Bank0, MIO[0:31]
GPIO Bank1, MIO[32:53]
GPIO Bank2, EMIO[0:31]
GPIO Bank3, EMIO[32:63]
是顺序排列的,所以上面这里的EMIO[1:6]对应的就是GPIO[55:60],然后我们可以在devicetree源文件中找到oled的配置:
zed_oled
{
compatible
=
"dglnt,pmodoled-gpio"
;
/* GPIO Pins */
vbat
-
gpio
=
<&
gpiops
55
0
>;
vdd
-
gpio
=
<&
gpiops
56
0
>;
res
-
gpio
=
<&
gpiops
57
0
>;
dc
-
gpio
=
<&
gpiops
58
0
>;
/* SPI-GPIOs */
spi
-
bus
-
num
=
<
2
>;
spi
-
speed
-
hz
=
<
4000000
>;
spi
-
sclk
-
gpio
=
<&
gpiops
59
0
>;
spi
-
sdin
-
gpio
=
<&
gpiops
60
0
>;
};
这里面的GPIO的号码正好对应了刚才计算出来的数字,到这里也就能理解这些号码的意义了:-)(这里需要事先设置好GPIO控制器,可以在前面找到gpio-controller字段)。
但是看到这里不禁又有了另一个疑问,为什么设备树只有oled的配置,而没有led和switch的配置,这也是当初我找不到内核在哪里操作led的原因。有一次无意间在ZedBoard_Linux_Design的doc目录下的DemoFeatures.txt中发现内核中自带了这样两个命令:
SWITCHES
/
LEDS
:
Scripts
are included
for
writing to the
LEDs
and
reading
the state of the switches
.
To
read the state of the switches
,
run the
command
:
read_sw
It
will
return
the state of the switches
as
both hexadecimal
and
decimal
.
A script
for
changing the state of the
LEDs
is
also included
.
To
turn all
8
LEDs
on
,
run one of the following two commands
:
write_led
255
write_led
0xFF
然后再仔细一看ramdisk中read_sw,write_led里面的内容:
thinki@G31T
-
M2
:
$ cat write_led
#!/bin/sh
value=$(($1));
if
[
$value
-
ge
0
];
then
for
i
in
0
1
2
3
4
5
6
7
;
do
led
=
$
((
$i
+
61
));
echo $
((
$value
&
0x01
))
>
/sys/
class
/
gpio
/
gpio$led
/
value
;
value
=
$
((
$value
/
2
));
done
;
fi
;
thinki@G31T
-
M2
:
$ cat read_sw
#!/bin/sh
value=0;
for i in 0 1 2 3 4 5 6 7;
do
sw=$((76-$i));
sw_tmp=`cat /sys/class/gpio/gpio$sw/value`;
value=$(($value*2));
value=$(($value+$sw_tmp));
done;
printf "0x%x %d\n" $value $value;
可以看到这里直接操作了sysfs下面的gpio class进行LED的写和Switch的读,但是这些目录以及相关的文件并不是凭空而来的,最后在ramdisk的etc/init.d/rcS中可以找到这样一段脚本:
echo
"++ Exporting LEDs & SWs"
for
i
in
0
1
2
3
4
5
6
7
;
do
sw
=
$
((
$i
+
69
));
led
=
$
((
$i
+
61
));
echo $sw
>
/sys/
class
/
gpio
/
export
;
echo $led
>
/sys/
class
/
gpio
/
export
;
echo
out
>
/sys/
class
/
gpio
/
gpio$led
/
direction
;
done
;
这才是这些目录真正的开端,启动时配置了这些,你只要Google一下sysfs gpio就可以找到一大堆东西,这里我简要介绍一下,也就是linux下gpio支持sysfs空间的操作,也就是可以绕过创建设备节点进行此操作,不过首先需要开启内核对sysfs的支持以及gpiolib对sysfs的支持,相关的代码依旧在drivers/gpio/gpiolib.c文件中,我们可以找到相关的宏:
#ifdef CONFIG_GPIO_SYSFS
这个宏下面的内容都是针对SYSFS相关的支持,这里涉及的知识比较多,需要理解Linux 2.6的设备模型相关的知识。如果是直观的操作的话,你只需要在/sys/class/gpio下进行echo XXX > export操作,不过这里XXX必须是内核支持的gpio号,比如内核启动之后在rcS脚本中echo的就是[61:68]和[69:76],这样就会在/sys/class/gpio目录下创建gpioXXX目录,然后我们可以设置led对应的gpioXXX目录下的direction属性为out就能够设置GPIO为输出,最后只需要像write_led脚本中那样向/sys/class/gpio/gpioXXX/value echo 0或者1就可以了,最终你会看到LED灯点亮!
当然你也可以使用类似于pmodoled驱动的形式,最终以/dev目录下的设备节点来操作底层硬件,这样的话就需要注册platform驱动并且通过设备树中的节点进行匹配,可以在设备树源文件最后添加下面的配置信息:
emio
-
oled
{
compatible
=
"dglnt,emioled-gpio"
;
/* GPIO Pins */
ld0
-
gpio
=
<&
gpiops
61
0
>;
ld1
-
gpio
=
<&
gpiops
62
0
>;
ld2
-
gpio
=
<&
gpiops
63
0
>;
ld3
-
gpio
=
<&
gpiops
64
0
>;
ld4
-
gpio
=
<&
gpiops
65
0
>;
ld5
-
gpio
=
<&
gpiops
66
0
>;
ld6
-
gpio
=
<&
gpiops
67
0
>;
ld7
-
gpio
=
<&
gpiops
68
0
>;
};
有时间我把我写的代码贴出来晒晒!
在platform驱动中的probe函数中来进行cdev的初始化与file_operations的设置,具体可以参考pmodoled驱动中的代码。
同时gpiolib还支持debugfs,可以查看哪些GPIO口被哪些设备分配了,不过使用之前需要先挂载debugfs,它与sysfs一样也是基于内存的文件系统:
mount
-
t debugfs debugfs
/
sys
/
kernel
/
debug
然后在板子上输出gpio文件的信息:
zynq
>
mount
-
t debugfs debugfs
/
sys
/
kernel
/
debug
zynq
>
cat
/
sys
/
kernel
/
debug
/
gpio
GPIOs
0
-
117
,
platform
/
e000a000
.
gpio
,
xgpiops
:
zynq
>
mount
-
t debugfs debugfs
/
sys
/
kernel
/
debug
zynq
>
cat
/
sys
/
kernel
/
debug
/
gpio
GPIOs
0
-
117
,
platform
/
e000a000
.
gpio
,
xgpiops
:
gpio
-
7
(
mmc_led
)
out
lo
gpio
-
55
(
OLED
VBat
)
out
lo
gpio
-
56
(
OLED VDD
)
out
lo
gpio
-
57
(
OLED_RESET
)
out
hi
gpio
-
58
(
OLED_D
/
C
)
out
hi
gpio
-
59
(
spi_gpio
.
2
)
out
lo
gpio
-
60
(
spi_gpio
.
2
)
out
lo
gpio
-
61
(
sysfs
)
out
lo
gpio
-
62
(
sysfs
)
out
lo
gpio
-
63
(
sysfs
)
out
lo
gpio
-
64
(
sysfs
)
out
lo
gpio
-
65
(
sysfs
)
out
lo
gpio
-
66
(
sysfs
)
out
lo
gpio
-
67
(
sysfs
)
out
lo
gpio
-
68
(
sysfs
)
out
lo
gpio
-
69
(
sysfs
)
in
hi
gpio
-
70
(
sysfs
)
in
lo
gpio
-
71
(
sysfs
)
in
lo
gpio
-
72
(
sysfs
)
in
hi
gpio
-
73
(
sysfs
)
in
hi
gpio
-
74
(
sysfs
)
in
lo
gpio
-
75
(
sysfs
)
in
hi
gpio
-
76
(
sysfs
)
in
lo
可以看到其中GPIO[55:60]被pmodoled驱动分配了,而GPIO[61:76]则是被sysfs分配了,最前面的GPIO[7]则是被linux的led驱动分配了,代码的位置是在drivers/leds/leds-gpio.c。
最终要深入的话还是建议看内核源码和文档:
drivers/gpio/gpiolib.c
Documentation/gpio.txt
参考链接: