rk3288 Pinctrl子系统的概念学习

Pinctrl子系统

主要的参考文档Document\devicetree\bindings\pinctrl\pinctrl-bindings.txt
文档中提到了两个概念,虽然读音上很相似但是概念不一样:

  1. Pinctrl client devices:声明自己需要使用那些引脚功能,怎么配置他们。设备在不同状态时,可以使用pin controller来指定引脚,配置不同的功能。
  2. Pin controller devices:用来复用引脚、配置引脚,它是一个软件的概念。它很多种配置方式,对应与Pinctrl client device的需要。

Pinctrl
上图中device设置了两种状态,pinctrl-0对应的是第一种状态,pinctrl-1对应的是第二种状态。而且状态后面引用的是节点。这个节点定义在pincontroller中,它定义了使用引脚的什么功能,设置引脚的配置等。

在pin controller中,是芯片厂家自己定义的。虽然格式不统一,但是具体的分类是一致的。就是都有:

  1. groups:设备会用到一个或多个引脚,这些引脚可以归类为一组(group)
  2. functions:这些引脚可以组合成某个功能。
    如:一个设备有A1、A2两组引脚,A1组复用为F1功能,A2组复用为F2功能。

在这里插入图片描述
rhockchip.pins设置了使用那些引脚,后面配置了一些参数,上下拉等等。
至于代码中如何使用pinctrl,这个驱动基本不用管,当设备切换的过程中,对应的pinctrl就会被调用。相关的函数有

devm_pinctrl_get_select_default(struct device *dev);			// 使用"default"状态的引脚
pinctrl_get_select(struct device *dev, const char *name); 		// 根据 name 选择某种状态的引脚
pinctrl_put(struct pinctrl *p); 								// 不再使用, 退出时调用

GPIO子系统

使用gpio子系统的好处,不用在对具体的硬件配置了,因为BSP工程师已经做好了配置。
我们可以通过操作GPIO子系统的标准函数来获得GPIO、设置GPIO方向,读取/设置GPIO的值。当然前提需要在设备树中指定GPIO引脚。
在这里插入图片描述

设备树中指定引脚

gpio-controller;			//表示这个节点是一个GPIO Controller,它下面有很多引脚
#gpio-cells = <2>;			//表示这个控制器下面每一个引脚要用2个32位的数(cell)来描述

这里定义了cell的2位,一位用来指定具体引脚,另一位用来指定它是高电平还是低电平有效。

GPIO_ACTIVE_LOW				//高电平有效
GPIO_ACTIVE_HIGH			//低电平有效
[<name>-]gpios				//表示gpios的属性

gpio子系统使用

驱动中使用gpio子系统

GPIO子系统有两套接口:基于描述符的(descriptor-based)和历史遗留版本(legacy),区别在于gpiod_前缀和gpio_前缀。
基本流程,get引脚,然后设置方向,读值、写值

基于描述符的的API

#include <linux/gpio/consumer.h>			//descriptor-based
//获取GPIO
struct gpio_desc *__must_check gpiod_get(struct device *dev, const char *con_id, enum gpiod_flags flags);
struct gpio_desc *__must_check gpiod_get_index(struct device *dev, const char *con_id, 
						unsigned int idx,enum gpiod_flags flags);
struct gpio_descs *__must_check gpiod_get_array(struct device *dev, const char *con_id, enum gpiod_flags flags);

struct gpio_desc *__must_check devm_gpiod_get(struct device *dev, const char *con_id, enum gpiod_flags flags);
struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev, const char *con_id, 
							unsigned int idx, enum gpiod_flags flags);
struct gpio_descs *__must_check devm_gpiod_get_array(struct device *dev, const char *con_id, enum gpiod_flags flags);
//设置方向
int gpiod_direction_input(struct gpio_desc *desc);
int gpiod_direction_output(struct gpio_desc *desc, int value);
//读值、写值
int gpiod_get_value(const struct gpio_desc *desc);
void gpiod_set_value(struct gpio_desc *desc, int value);
//释放GPIO
void gpiod_put(struct gpio_desc *desc);
void gpiod_put_array(struct gpio_descs *descs);
void devm_gpiod_put(struct device *dev, struct gpio_desc *desc);
void devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs);
// 使用 devm 的相关函数,在内存申请失败时可以直接返回:设备的销毁函数会自动地释放已经申请了的 GPIO 资源。
// 建议使用“devm_”版本的相关函数。

历史遗留版本

#include <linux/gpio.h>						//legacy
static inline int gpio_request(unsigned gpio, const char *label);						//获得 GPIO
static inline int gpio_request_array(const struct gpio *array, size_t num);
static inline int gpio_direction_input(unsigned gpio);									//设置方向
static inline int gpio_direction_output(unsigned gpio, int value);
static inline int gpio_get_value_cansleep(unsigned gpio);								//读值、写值
static inline void gpio_set_value(unsigned int gpio, int value);
static inline void gpio_free(unsigned gpio);
static inline void gpio_free_array(const struct gpio *array, size_t num);				//释放GPIO

基于描述符的使用例子

//如果设备树中定义了下面的节点:
foo_device {
	compatible = "acme,foo";
	//...
	led-gpios = <&gpio 15 GPIO_ACTIVE_HIGH>, /* red */
		<&gpio 16 GPIO_ACTIVE_HIGH>, /* green */
		<&gpio 17 GPIO_ACTIVE_HIGH>; /* blue */
	power-gpios = <&gpio 1 GPIO_ACTIVE_LOW>;
};

//获取引脚
struct gpio_desc *red, *green, *blue, *power;
red = gpiod_get_index(dev, "led", 0, GPIOD_OUT_HIGH);
green = gpiod_get_index(dev, "led", 1, GPIOD_OUT_HIGH);
blue = gpiod_get_index(dev, "led", 2, GPIOD_OUT_HIGH);
power = gpiod_get(dev, "power", GPIOD_OUT_HIGH);

遗留版本例子使用例子

旧的gpio接口,不从设备树获取引脚信息,取而代之的是基准引脚号。这些引脚号在注册GPIO Controller时会确定。

在开发板的/sys/class/gpio目录下,找到各个gpiochipxxxx目录:
/sys/class/gpio
然后进入某个gpiochip目录,查看文件label内容,label内容对比设备树。这里直接就是gpio4
label内容
所以gpio4的基准引脚号就是96,cat base也可以再次确认。

如果引脚是14,那么 GPIO4_14 的号码是 96+14=110,可以如下操作读取按键值:

echo 110 > /sys/class/gpio/export
echo in > /sys/class/gpio/gpio110/direction
cat /sys/class/gpio/gpio110/value
echo 110 > /sys/class/gpio/unexport

对于输出引脚,假设引脚号为 N,可以用下面的方法设置它的值为 1:

echo N > /sys/class/gpio/export
echo out > /sys/class/gpio/gpioN/direction
echo 1 > /sys/class/gpio/gpioN/value
echo N > /sys/class/gpio/unexport

如果驱动程序已经使用了该引脚,那么将会 export 失败,会提示下面的错误:

-sh: echo: write error: Device or resource busy
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

习惯就好zz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值