LINUX GPIO 基操之驱动篇


注:所有文章基于linux-3.13 以上,本系列主要介绍 GPIO的一些基本知识,驱动操作GPIO的接口,应用层通过sysfs操作GPIO的接口,GPIO一些debug信息查看,以及对高通相关GPIO的寄存器操作。分享给刚刚接触外设bsp的小伙伴们。当然后面有时间还会分享GPIO子系统框架和pinctrl子系统框架,先知道黑盒怎么使用,然后咱再打开仔细瞅瞅。有错误不正当点,勿喷,还请指出,一起修改,谢谢!!
本篇为驱动申请GPIO和操作GPIO接口篇,分别介绍驱动通过GPIO子系统和PINCTRL 子系统提供的接口对GPIO的操作

GPIO 子系统操作GPIO

GPIO子系统接口简介

相关实现在driver/gpio/gpiolib.c 下
1)gpio_request
申请GPIO

int gpio_request(unsigned gpio, const char *label)

参数解析:
gpio: gpio编号
label: 名称
返回值: 成功返回0,失败返回负值
gpio_request_one
申请GPIO,同时制定配置方式 输出或输入模式

int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)

2)gpio_free
释放GPIO

void gpio_free(unsigned gpio)

参数解析:
gpio: gpio编号
3)gpio_direction_input
设置GPIO为输入模式

int gpio_direction_input(unsigned gpio)

参数解析:
gpio: gpio编号
返回值: 成功返回0,失败返回负值
4)gpio_direction_output
设置GPIO为输出模式

/* linux/gpio.h */
int gpio_direction_output(unsigned gpio, int value)

参数解析:
gpio: gpio编号
value: 设置为输出模式时的初始值
返回值: 成功返回0,失败返回负值
5) gpio_set_value
设置(写)GPIO的值

/* linux/gpio.h */
void __gpio_set_value(unsigned gpio, int value)
#define gpio_set_value  __gpio_set_value

gpio: gpio编号
value: 设置的值
返回值: 成功返回0,失败返回负值
6) gpio_get_value
获取(读)GPIO的值

int __gpio_get_value(unsigned gpio)
#define gpio_get_value  __gpio_get_value

gpio: gpio编号
返回值: 获取的值
7) gpio_to_irq
内核通过调用该函数将gpio端口转换为中断

 int gpio_to_irq(unsigned gpio); 

gpio: gpio编号
返回值:中断编号可以传给request_irq()和free_irq()

单个GPIO

申请gpio4,输出模式,输出高(从设备树配置)
设备树设置

gpio_test{
	status="ok";
	gpio_req=<&tlmn 4 0>;
}

代码实现

struct device dev;
gpio4 = of_get_named_gpio(dev.of_node,"gpio_req", 0);
err = gpio_request(gpio4, "qti-can-reset");
 if (err < 0) {
         return err;
 } 
gpio_direction_output(gpio4, 0);                
gpio_set_value(gpio4,1);                

GPIO数组

申请一个gpio数组 [36,42,132],主要是设备树
设备树

			 gpios = <&tlmm 36 0>,
                        <&tlmm 42 0>,
                        <&tlmm 132 0>;
                qcom,gpio-reset = <1>;
                qcom,gpio-standby = <2>;
                qcom,gpio-req-tbl-num = <0 1 2>;  //num
                qcom,gpio-req-tbl-flags = <1 0 0>; //1 输 入,0 输出
                qcom,gpio-req-tbl-label = "CAMIF_MCLK2",  // 每个gpio对应的名字
                                                                        "CAM_RESET2",
                                                                       "CAM_STANDBY2";

解析:

PINCTRL 子系统操作GPIO

pinctrl 子系统相关接口

1) devm_pinctrl_get
解析对应的设备树,获取pinctrl资源

struct pinctrl *devm_pinctrl_get(struct device *dev)

dev: 驱动设备结构体
返回值:pinctrl节点
2)pinctrl_lookup_state
获取各种state的gpio配置

struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p, const char *name) 

p: pinctrl节点
name:gpio配置的名字
3)pinctrl_select_state
.将上面获取的指定state状态设置到硬件中*/

int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)

使用例子

高通的配置为例子
在pinctrl设备树添加一个节点

&tlmn{
	
	pin_teset_default:pin_teset_default{
                 mux {
                          pins = "gpio0", "gpio1"; //复用的gpio
                          function = "qup00";//复用成什么功能
                  };
                  config {
                          pins = "gpio0", "gpio1"; //配置的默认状态
                          drive-strength = <2>;
                          bias-disable;
                  };
	}
}

在xxx.dtsi中添加一个设备 使用

pinctrl_test{
		status="ok";
		pinctrl-name="default";
		pinctrl-0=<&pin_teset_default>;
}

代码实现

/*1.获取pinctrl节点*/
dev->pins->p = devm_pinctrl_get(dev);
/*2.获取各种state下的pin*/
 dev->pins->default_state = pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_DEFAULT); /*default的必须要
 /*3.选中进行设置*/
  pinctrl_select_state(dev->pins->p, dev->pins->default_state);

probe自动配置pinctrl

如上个例子中,我们是不需要自己进行pinctrl适配的,device和驱动在匹配之后会进行适配。调用我们驱动的probe时,pinctrl相关已经初始化好了。获取相关状态和设置相关状态

__device_attach
    bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver);
        __device_attach_driver 
            driver_match_device(drv, dev); //只有驱动和设备树节点匹配上了才会继续往下走
            driver_probe_device(struct device_driver *drv, struct device *dev)
                really_probe
                    pinctrl_bind_pins //执行到这里了,一定是驱动和设备匹配上后的。                
                        drv->probe(dev)//然后再probe我们的驱动

int pinctrl_bind_pins(struct device *dev)
{
   /*1.先get*/
   dev->pins->p = devm_pinctrl_get(dev);

   /*2.获取各种state下的pin*/
   dev->pins->default_state = pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_DEFAULT); /*default的必须要有,否则直接退出*/
   dev->pins->init_state = pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_INIT);
   /*3.选中一个state进行设置*/
   if (IS_ERR(dev->pins->init_state)) {
       /*这里对clent的gpio设备树节点进行解析,并对硬件进行了设置*/
       ret = pinctrl_select_state(dev->pins->p, dev->pins->default_state); /*如果有init state,就设置为init state,否则设置为default state, Qcom没有定义sleep state*/
   } else {
       ret = pinctrl_select_state(dev->pins->p, dev->pins->init_state);
   }

#ifdef CONFIG_PM //R上也定义了这个值
   dev->pins->sleep_state = pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_SLEEP);
   dev->pins->idle_state = pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_IDLE);
#endif

   return 0;
}
  • 3
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: GPIO是英文General Purpose Input/Output的缩写,翻译过来就是通用输入输出。Linux内核提供了GPIO驱动框架,可以通过该框架来控制硬件上的GPIO,实现对外设的控制。 在Linux内核中,GPIO驱动可以分为两类:基于平台的GPIO驱动和基于设备的GPIO驱动。基于平台的GPIO驱动是针对整个平台的GPIO控制,而基于设备的GPIO驱动则是针对单个设备的GPIO控制。 在使用GPIO驱动时,需要先找到所使用的GPIO引脚的编号,并将其映射到内存中的地址。然后通过读写内存中的寄存器来控制GPIO的状态。 对于GPIO的操作可以通过Linux内核提供的sysfs接口来实现。在sysfs中,每个GPIO都被表示为一个文件,可以通过读写文件来进行GPIO的操作。 需要注意的是,在使用GPIO驱动时,需要谨慎操作,避免对硬件造成损坏。同时,还需要了解所使用的硬件设备的特性和限制,以确保GPIO驱动的正确使用。补充说明: 在Linux内核中,GPIO驱动主要由GPIO子系统和GPIO控制器驱动两部分组成。GPIO子系统提供了一个通用的接口,用于操作GPIO控制器驱动,而GPIO控制器驱动则是实际控制硬件的部分。 GPIO子系统可以分为两个部分:GPIO框架和GPIO API。GPIO框架是一个通用的框架,用于管理GPIO控制器和GPIO设备,它定义了一些数据结构和函数接口,用于注册和管理GPIO控制器和GPIO设备。GPIO API是一个用户空间的API,提供了一些函数接口,用于操作GPIOGPIO控制器驱动是针对特定的GPIO控制器的驱动程序,它负责实际控制GPIO的硬件操作。在Linux内核中,每种GPIO控制器都有一个对应的GPIO控制器驱动程序。当使用GPIO时,首先需要通过GPIO子系统将GPIO控制器驱动注册到系统中,然后才能使用GPIO API对GPIO进行操作。 需要注意的是,在使用GPIO驱动时,需要注意GPIO的电气特性,避免对硬件造成损坏。同时,在进行GPIO操作时,还需要注意GPIO的并发访问和竞争问题,以确保系统的正确性和稳定性。 ### 回答2: Linux GPI驱动指的是Linux系统中通过General Purpose Input/Output(GPIO)接口与硬件设备进行交互的驱动程序GPIO接口是一组通用的、可编程的多功能引脚,可用于连接各种外部设备,例如开关、LED、传感器、驱动器等。 Linux GPIO驱动可以实现对GPIO引脚的读写操作、中断处理等功能。它不仅可以与单片机等嵌入式设备进行通信,还可与各种外接硬件设备进行连接和通信。 在Linux系统中,用户可以通过/sys/class/gpio文件系统来访问GPIO引脚。在使用GPIO驱动时,用户需要首先加载相应的内核模块,然后使用GPIO API来对引脚进行读写操作或开启中断。 GPIO驱动程序需要实现以下功能: 1. 查询GPIO可用性及分配资源。通常,由于GPIO是多路的,因此设备需要分配资源共享GPIO。 2. 初始化GPIO引脚,包括定义方向及设置上下拉电阻等。 3. 实现GPIO引脚的读写操作。 4. 解除分配资源并释放相关资源。 正常情况下,GPIO驱动程序会提供一个设备文件,用户可以通过读写该文件实现GPIO引脚的操作。 总之,Linux GPIO驱动具有良好的可移植性和稳定性,可以方便地与其他硬件设备进行交互,因此被广泛应用于各种嵌入式设备和嵌入式系统中。 ### 回答3: Linux GPIO驱动是一种在嵌入式系统中实现通用输入输出(GPIO,General Purpose Input/Output)功能的软件驱动GPIO是一种非常有用的硬件资源,它可以连接到外部设备,例如LED灯、按键和触摸屏等。 Linux内核支持GPIO操作,当你的嵌入式系统上有GPIO设备时,你可以利用GPIO来读取或设置其状态。驱动程序能够将GPIO标记为输入或输出,并且它们可以在运行时进行配置。 在Linux中,一般有两种方式将GPIO驱动程序添加到内核中:一种是将其编译到内核中,另一种是将其作为模块加载。 GPIO驱动程序等价于操作系统提供的设备文件,例如/dev/gpiochip0,它允许用户空间应用程序访问GPIO。这些设备文件可用于读取或写入GPIO状态。例如,要控制一个LED,需要将GPIO设置为输出模式,然后将其电平设置为高或低即可。 除此之外,GPIO驱动程序也可以实现中断(interrupt)机制,GPIO的状态变化时可以产生中断事件,这常用于处理GPIO键盘或GPIO中断信号的应用场景。 总结来说,Linux内核支持GPIO驱动需要有以下几个步骤:配置GPIO硬件;添加驱动程序;编写用户空间应用程序,按需要读取或设置GPIO状态来和外设交互。GPIO驱动程序是嵌入式系统中非常必要的组成部分,它们能够随时提供接口以方便对外部设备的读写访问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值