命令行界面控制GPIO方法
配置
Linux 4.9在终端下查看是否有/sys/class/gpio 目录
没有打开内核选项
Device Drivers-》GPIO Support -》/sys/class/gpio/… (sysfs interface) ==CONFIG_GPIO_SYSFS
操作
1 echo “166” > /sys/class/gpio/export
2 echo “out” > /sys/class/gpio/gpio166/direction
3 echo “1” > /sys/class/gpio/gpio166/value
- 将166编号的GPIO 导出
- 将166编号的GPIO方向设置成out
- 设置166编号的GPIO电平
166 编号的由来
不同平台编号计算方式不一样
以hisi 3559为例 166 对应 SHUB_GPIO1_6
hisi3559 平台一共GPIO0----GPIO18 SHUB0—SHUB4 《SHUB(Senosr Hub)》
按编号模拟SHUB0 -》GPIO19,SHUB_GPIO1-》GPIO20 以此类推。。。
(设备树文件中可以查看到)
hisi 每组GPIO最多含8个脚,所以编号166==20 * 8 +6
有的平台可能就是20 * 32 ,不同平台计算方式不一样
注意
1.GPIO的第二功能寄存器记得配置成GPIO模式
2.hisiGPIO 数据寄存器的地址包含读写寄存器屏蔽位,熟读并背诵数据手册
若地址为为0x3FC(0b11_1111_1100),则对GPIO_DATA[7:0]这8bit操作全部有
效。
若地址为0x200(0b10_0000_0000),则仅对GPIO_DATA[7]的操作有效。
如何得知gpio的编号
由上面得知每一个编号对应一个gpio,这个编号其实是没有意义的,只是认为的将gpio管脚人为的定义一个号码来对应,简化操作。那么我们最终操作的是gpio,那么如何得知gpio他的编号是多少。这种管脚对应编号的编码方式每个公司厂家的芯片可能都不一样,最重要的是找到这个关系,才能知道编号
比如novatek平台
找到arch中描述gpio的文件
arch\arm\plat-novatek\include\plat-na51089\nvt-gpio.h
/* GPIO pin number translation */
#define C_GPIO(pin) (pin)
#define P_GPIO(pin) (pin + 0x20)
#define S_GPIO(pin) (pin + 0x40)
#define L_GPIO(pin) (pin + 0x60)
#define D_GPIO(pin) (pin + 0x80)
#define H_GPIO(pin) (pin + 0xA0)
#define A_GPIO(pin) (pin + 0xC0)
#define DSI_GPIO(pin) (pin + 0xE0)
#define C_GPIO_NUM 23
#define P_GPIO_NUM 26
#define S_GPIO_NUM 9
#define L_GPIO_NUM 10
#define H_GPIO_NUM 12
#define D_GPIO_NUM 8
#define A_GPIO_NUM 3
#define DSI_GPIO_NUM 11
nt平台不像hisi有顺序的1 2 3 4 组,他分组C P S L D H A ,,
A_GPIO 3 那么他的编号就是 0xC0 + 3 ,这样计算而来。
他这个排序的规则也是按照数据手册寄存器的递增的规则定义的
hisi平台
hisi平台的pinctl采用的是gpio-pl061驱动,而每组的GPIO都有编号
比如GPIO1_2,GPIO14_7等。
设备树中每块chip都有描述
从pl061的驱动来看,获取gpio的alias
并将gpio的每组第一个管脚编号即每个gpio chip的base为序号*8
比如GPIO12,那么他的gpio chip 的base 就是12*8;
static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
{
....
if (dev->of_node) {
i = of_alias_get_id(dev->of_node, "gpio");
chip->gc.base = i * PL061_GPIO_NR;//#define PL061_GPIO_NR 8
}
...
ret = gpiochip_add_data(&chip->gc, chip);
...
}
然后在gpiochip_add_data中会对这个chip申请PL061_GPIO_NR 个gpio的desc,
用来表示各个管脚,因为每个chip有8个管脚,所以前面GPIO20_6,为什么他的编号为166,是驱动定义导致的。
static int pl061_get_value(struct gpio_chip *gc, unsigned offset)
{
struct pl061_gpio *chip = gpiochip_get_data(gc);
return !!readb(chip->base + (BIT(offset + 2)));
}
在pl061中get value有+2的操作,是因为这个GPIO口的data寄存器硬件设计原因。
他的BIT[9:2]才描述GPIOX_0----7的管脚状态
GPIO_DATA 寄存器利用 PADDR[9:2] 实现了读写寄存器比特的屏蔽操作。
最后我们可以整一个脚本来操作
#!/bin/sh
GPIO_DIR=$1
GPIO_NUM=$2
GPIO_VAL=$3
if [[ "${GPIO_DIR}" != "out" ]] && [[ "${GPIO_DIR}" != 'in' ]] && [[ $# != 3 ]];
then
echo "para error!"
echo "example: ./gpio out/in XXX 1"
exit 1
fi
if [[ ${GPIO_VAL} != 0 ]] ;then
GPIO_VAL=1;
fi
if [ ! -d "/sys/class/gpio/gpio${GPIO_NUM}" ] ;then
echo ${GPIO_NUM} > /sys/class/gpio/export
fi
echo ${GPIO_DIR} > /sys/class/gpio/gpio${GPIO_NUM}/direction
if [ "${GPIO_DIR}" == 'out' ] ;then
echo ${GPIO_VAL} > /sys/class/gpio/gpio${GPIO_NUM}/value
else
echo "gpio${GPIO_NUM}: `cat /sys/class/gpio/gpio${GPIO_NUM}/value`"
fi