很高兴之前分析gpioLib能有机会帮助解决问题。
描述下遇到的问题的现象:
将GPIO设置为output并设置为高电平,这时候再去读取电平却读到低电平,使用万用表测量管脚,确认是实实在在的高电平。用命令演示一下拗口的文字:
# echo out > /sys/class/gpio/gpio34/direciton
# echo 1 > /sys/class/gpio/gpio34/value
# cat /sys/class/gpio/gpio34/value
# 0
因为已经确认实际管脚的上是能够正常工作的,初步判断出读功能那里出错,最后定位到gpio-generic.c下gpio_get.
static int bgpio_get(struct gpio_chip *gc, unsigned int gpio)
{
struct bgpio_chip *bgc = to_bgpio_chip(gc);
return !!(bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio));
}
在之前的文章中我们分析过初始化的过程就不展开来说了,乍一看这个读寄存器并没有问题。
我们翻看芯片手册看看这个芯片描述:
PSR寄存器:
Each bit stores the value of the corresponding input signal
DR寄存器:
GPIO_DR register stores data that is ready to be driven to the output lines.
这里PSR寄存器只说了记录输出的信号,没有说输入的情况,而DR寄存器是配置输出电平。
所以实际上配置为输出时,我们只能回读DR寄存器,而不能读PSR,以前我用过3.x的内核并没有这个问题,所以参考一下对应的代码。
static int mxc_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct mxc_gpio_port *port =
container_of(chip, struct mxc_gpio_port, chip);
u32 gpio_direction;
gpio_direction = __raw_readl(port->base + GPIO_GDIR);
if (((gpio_direction >> offset) & 1)) /* output mode */
return (__raw_readl(port->base + GPIO_DR) >> offset) & 1;
else /* input mode */
return (__raw_readl(port->base + GPIO_PSR) >> offset) & 1;
}
很明显是判断了当前的输入输出 配置,然后分别读GPIO_DR/GPIO_PSR寄存器。
所以,我们将4.x代码修改一下:
static int bgpio_get_mxc(struct gpio_chip *gc, unsigned int gpio)
{
struct bgpio_chip *bgc = to_bgpio_chip(gc);
if( !!(bgc->read_reg(bgc->reg_dir) & bgc->pin2mask(bgc, gpio)) ){
return !!(bgc->read_reg(bgc->reg_set) & bgc->pin2mask(bgc, gpio));
}else{
return !!(bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio));
}
}
#endif