coding无法使用浏览器打开,必须用git工具下载:
git clone https://e.coding.net/weidongshan/linux/doc_and_source_for_drivers.git
参考资料:
假设使用这个虚拟的GPIO Controller的pinA来控制LED:
要使用pinA来控制LED,首先要通过Pinctrl子系统把它设置为GPIO功能,然后才能设置它为输出引脚、设置它的输出值。
所以在设备树文件里,应该添加Pinctrl的内容:
virtual_pincontroller {
compatible = "100ask,virtual_pinctrl";
myled_pin: myled_pin {
functions = "gpio";
groups = "pin0";
configs = <0x11223344>;
};
};
gpio_virt: virtual_gpiocontroller {
compatible = "100ask,virtual_gpio";
gpio-controller;
#gpio-cells = <2>;
ngpios = <4>;
};
myled {
compatible = "100ask,leddrv";
led-gpios = <&gpio_virt 0 GPIO_ACTIVE_LOW>;
pinctrl-names = "default";
pinctrl-0 = <&myled_pin>;
};
但是很多芯片,并不要求在设备树中把把引脚复用为GPIO功能。
比如STM32MP157,在它的设备树工具STM32CubeMX
即使把引脚配置为GPIO功能,它也不会在设备树中出现。
原因在于:GPIO走了后门。
现实的芯片中,并没有Pinctrl这样的硬件,它的功能大部分是在GPIO模块中实现的。
Pinctrl是一个软件虚拟处理的概念,它的实现本来就跟GPIO密切相关。
甚至一些引脚默认就是GPIO功能。
按理说:
一个引脚可能被用作GPIO,也可能被用作I2C,GPIO和I2C这些功能时相同低位的。
要用作GPIO,需要先通过Pinctrl把引脚复用为GPIO功能。
但是Pinctrl和GPIO关系密切,当你使用gpiod_get获得GPIO引脚时,它就偷偷地
通过Pinctrl把引脚复用为GPIO功能了。
从上图可知:
GPIO子系统中的request函数,用来申请某个GPIO引脚,
它会导致Pinctrl子系统中的这2个函数之一被调用:pmxops->gpio_request_enable
或pmxops->request
调用关系如下:
gpiod_get
gpiod_get_index
desc = of_find_gpio(dev, con_id, idx, &lookupflags);
ret = gpiod_request(desc, con_id ? con_id : devname);
ret = gpiod_request_commit(desc, label);
if (chip->request) {
ret = chip->request(chip, offset);
}
我们编写GPIO驱动程序时,所设置chip->request
函数,一般直接调用gpiochip_generic_request
,它导致Pinctrl把引脚复用为GPIO功能。
gpiochip_generic_request(struct gpio_chip *chip, unsigned offset)
pinctrl_request_gpio(chip->gpiodev->base + offset)
ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range); // gpio是引脚的全局编号
/* Convert to the pin controllers number space */
pin = gpio_to_pin(range, gpio);
ret = pinmux_request_gpio(pctldev, range, pin, gpio);
ret = pin_request(pctldev, pin, owner, range);
Pinctrl子系统中的pin_request函数就会把引脚配置为GPIO功能:
static int pin_request(struct pinctrl_dev *pctldev,
int pin, const char *owner,
struct pinctrl_gpio_range *gpio_range)
{
const struct pinmux_ops *ops = pctldev->desc->pmxops;
/*
* If there is no kind of request function for the pin we just assume
* we got it by default and proceed.
*/
if (gpio_range && ops->gpio_request_enable)
/* This requests and enables a single GPIO pin */
status = ops->gpio_request_enable(pctldev, gpio_range, pin);
else if (ops->request)
status = ops->request(pctldev, pin);
else
status = 0;
}
如果不想在使用GPIO引脚时,在设备树中设置Pinctrl信息,
如果想让GPIO和Pinctrl之间建立联系,
我们需要做这些事情:
在GPIO设备树中使用gpio-ranges
来描述它们之间的联系:
在GPIO驱动程序中,解析跟Pinctrl之间的联系:处理gpio-ranges
:
gpio_chip->request
pmxops->gpio_request_enable
或pmxops->request