金牌会员
- 积分
- 1572
- 金钱
- 1572
- 注册时间
- 2017-7-17
- 在线时间
- 308 小时
|
IMX6ULL, alpha开发板,这几天在做内核控制器空置LED灯闪烁(GPIO1_IO03)的实现,想通过读取LED引脚电平,然后翻转来实现LED灯闪烁,使用的是pinctrl和gpio子系统来设置LED灯引脚。但是遇到了一个很基本,但是又很头疼的问题。使用 gpio_get_value()函数来读取LED引脚电平的时候,总是读取到0,不管引脚是高电平还是低电平。
经过查阅资料,发现需要开启MUX寄存器的SION位,使能输入回环,方法是在设备树里面,将config寄存器的值,第30位置1,这样pinctrl子系统驱动会自动检测这个位,检测到了就会将MUX寄存器的SION位设置为1. 我试了,还是没用。
然后我直接在imx6ul-pinfunc.h里面,将MUX寄存器的0x5改成0x15,直接设置SION位,还是没用
我就去NXP官网提问,为啥SION置1了,gpio_get_value还是返回0啊。。。
直到我用ioremap的方法,映射了MUX寄存器,然后将寄存器的值读出来,发现居然是默认的0x5,注意,这个值是上电默认就是0x5. 然后不管我在设备树里面将GPIO1_IO03复用为啥功能,MUX寄存器读出来都是0x5,雷打不动,感觉pinctrl的配置根本就没起作用一样。
然后我使用writel的方法,把MUX寄存器设置为0x15, gpio_get_value果然就能读到正确的电平了。。。。
顺便说一句,虽然读电平有问题,但是输出电平没有问题哦,可以正常开关LED灯。而且,当把引脚设置为输入功能时,gpio_get_value()也是可以正确返回电平值的。所以,问题总结如下:
当一个引脚被用作GPIO输出引脚时,gpio_get_value()不能正确返回引脚电平值,表层原因是设备树里面的pinctrl节点参数没有被写到MUX寄存器里面。
另外,我还用蜂鸣器引脚(GPIO5_IO01)也试过了,MUX读出来也是默认的0x0,而不是在pinctrl节点里面配置的值。
下面是我的设备树配置截图,以及驱动代码,有兴趣的可以试试。我不知道深层次原因是什么,肯定是原子修改过的内核代码问题,用vscode读源码太费劲,跳转功能不好用,所以我放弃了找原因,毕竟能力有限,如果有人找到原因了,记得告诉我。
1)pinctrl节点
2)led节点
led节点
3)驱动代码
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/ide.h>
#define REG_MUX_GPIO5_IO01 0x0229000C
static void __iomem *mux_gpio5_io01;
static int gpio;
static int __init led_init(void)
{
const char *status;
int ret, value;
struct device_node *node = NULL;
node = of_find_compatible_node(NULL, NULL, "alientek-alpha,leds");
if(!node) {
printk("error: of_find_compatible_node\n");
return -ENODEV;
}
ret = of_property_read_string(node, "status", &status);
if((ret != 0) || (strcmp(status, "okay") != 0)) {
printk("error: of_property_read_string\n");
return -ENODEV;
}
gpio = of_get_named_gpio(node, "led-gpios", 0);
if(gpio < 0) {
printk("error: of_get_named_gpio\n");
return -ENODEV;
}
ret = gpio_request(gpio, "led-pin");
if(ret) {
printk("error: gpio_request\n");
return -ENODEV;
}
ret = gpio_direction_output(gpio, 1);
if(ret) {
printk("error: gpio_direction_output\n");
goto error;
}
value = gpio_get_value(gpio);
printk("gpio value = %d\n", value);
mux_gpio5_io01 = ioremap(REG_MUX_GPIO5_IO01, 4);
if(mux_gpio5_io01) {
value = readl(mux_gpio5_io01);
printk("reg value = %08X\n", value);
}
return 0;
error:
gpio_free(gpio);
return -1;
}
static void __exit led_exit(void)
{
int value;
value = gpio_get_value(gpio);
printk("gpio value = %d\n", value);
if(mux_gpio5_io01) {
value = readl(mux_gpio5_io01);
printk("reg value = %08X\n", value);
}
gpio_free(gpio);
if(mux_gpio5_io01) iounmap(mux_gpio5_io01);
}
module_init(led_init);
module_exit(led_exit);
MODULE_AUTHOR("David");
MODULE_LICENSE("GPL");
|
|