上篇pinctrl子系统我们说到:pinctrl是设置引脚的复用功能和电气特性,那么我们在驱动中使用gpio_request和gpio_direction_output,gpio_direction_input,gpio_set_value,gpio_get_value,gpio_free等API来使用gpio;这些api是怎么工作的呢,是怎么跟pinctrl子系统配合的呢?我们从gpio控制器驱动开始看最重要的两部分:gpio_chip的成员函数以及gpiochip_add_data。源码文件(pinctrl-rockchip.c/pinctrl-msm.c)
static int rockchip_gpiolib_register(struct platform_device *pdev,
struct rockchip_pinctrl *info)
{
struct rockchip_pin_ctrl *ctrl = info->ctrl;
struct rockchip_pin_bank *bank = ctrl->pin_banks;
struct gpio_chip *gc;
int ret;
int i;
for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
if (!bank->valid) {
dev_warn(&pdev->dev, "bank %s is not valid\n",
bank->name);
continue;
}
bank->gpio_chip = rockchip_gpiolib_chip;
gc = &bank->gpio_chip;
gc->base = bank->pin_base;
gc->ngpio = bank->nr_pins;
gc->parent = &pdev->dev;
gc->of_node = bank->of_node;
gc->label = bank->name;
ret = gpiochip_add_data(gc, bank);
if (ret) {
dev_err(&pdev->dev, "failed to register gpio_chip %s, error code: %d\n",
gc->label, ret);
goto fail;
}
}
rockchip_interrupts_register(pdev, info);
return 0;
fail:
for (--i, --bank; i >= 0; --i, --bank) {
if (!bank->valid)
continue;
gpiochip_remove(&bank->gpio_chip);
}
return ret;
}
gpio_chip的成员函数
上面这个函数就涵盖了gpio子系统的关键信息;首先是rockchip_gpiolib_chip,这个gpio_chip实例的成员跟上面提到的驱动里面常用的几个api能够一一对上,除了.set和.get,get_direction是直接设置和读取寄存器,其他几个都是调用的pinctrl的接口(上篇pinctrl子系统里注册驱动时的那三个ops里面的各个实例)
static const struct gpio_chip rockchip_gpiolib_chip = {
.request = gpiochip_generic_request,
.free = gpiochip_generic_free,
.set = rockchip_gpio_set,
.get = rockchip_gpio_get,
.get_direction = rockchip_gpio_get_direction,
.direction_input = rockchip_gpio_direction_input,
.direction_output = rockchip_gpio_direction_output,
.to_irq = rockchip_gpio_to_irq,
.owner = THIS_MODULE,
};
gpio_request
我们先看一个gpio_request的简化代码,最终调用的request就是gpio_chip的request,也即gpiochip_generic_request
gpiod_request
__gpiod_request
chip->request(chip, gpio_chip_hwgpio(desc));
那么gpiochip_generic_request调用的pinctrl_request_gpio的具体实现如下:通过range来得到gpio对应的pin,然后通过pinmux_request_gpio来申请一个gpio
int pinctrl_request_gpio(unsigned gpio)
{
struct pinctrl_dev *pctldev;
struct pinctrl_gpio_range *range;
int ret;
int pin;
ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
if (ret) {
if (pinctrl_ready_for_gpio_range(gpio))
ret = 0;
return ret;
}
mutex_lock(&pctldev->mutex);
/* Convert to the pin controllers number space */
pin = gpio_to_pin(range, gpio);
ret = pinmux_request_gpio(pctldev, range, pin, gpio);
mutex_unlock(&pctldev->mutex);
return ret;
}
pinmux_request_gpio调用的pin_request会先判断pin是否被占用,然后通过pinctrl驱动注册的pinmux_ops的gpio_request_enable或者request成员来将pin申请为gpio功能
static int pin_request(struct pinctrl_dev *pctldev,
int pin, const char *owner,
struct pinctrl_gpio_range *gpio_range)
{
struct pin_desc *desc;
const struct pinmux_ops *ops = pctldev->desc->pmxops;
int status = -EINVAL;
desc = pin_desc_get(pctldev, pin);
if (desc == NULL) {
dev_err(pctldev->dev,
"pin %d is not registered so it cannot be requested\n",
pin);
goto out;
}
dev_dbg(pctldev->dev, "request pin %d (%s) for %s\n",
pin, desc->name, owner);
if (gpio_range) {
/* There's no need to support multiple GPIO requests */
if (desc->gpio_owner) {
dev_err(pctldev->dev,
"pin %s already requested by %s; cannot claim for %s\n",
desc->name, desc->gpio_owner, owner);
goto out;
}
if (ops->strict && desc->mux_usecount &&
strcmp(desc->mux_owner, owner)) {
dev_err(pctldev->dev,
"pin %s already requested by %s; cannot claim for %s\n",
desc->name, desc->mux_owner, owner);
goto out;
}
desc->gpio_owner = owner;
} else {
if (desc->mux_usecount && strcmp(desc->mux_owner, owner)) {
dev_err(pctldev->dev,
"pin %s already requested by %s; cannot claim for %s\n",
desc->name, desc->mux_owner, owner);
goto out;
}
if (ops->strict && desc->gpio_owner) {
dev_err(pctldev->dev,
"pin %s already requested by %s; cannot claim for %s\n",
desc->name, desc->gpio_owner, owner);
goto out;
}
desc->mux_usecount++;
if (desc->mux_usecount > 1)
return 0;
desc->mux_owner = owner;
}
/* Let each pin increase references to this module */
if (!try_module_get(pctldev->owner)) {
dev_err(pctldev->dev,
"could not increase module refcount for pin %d\n",
pin);
status = -EINVAL;
goto out_free_pin;
}
/*
* 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;
if (status) {
dev_err(pctldev->dev, "request() failed for pin %d\n", pin);
module_put(pctldev->owner);
}
out_free_pin:
if (status) {
if (gpio_range) {
desc->gpio_owner = NULL;
} else {
desc->mux_usecount--;
if (!desc->mux_usecount)
desc->mux_owner = NULL;
}
}
out:
if (status)
dev_err(pctldev->dev, "pin-%d (%s) status %d\n",
pin, owner, status);
return status;
}
gpio_direction_output/input
但是不同的平台这两个函数不一定被半导体厂商实现了,那么肯定会在其他地方来做这件事(复用为gpio功能),我们知道gpio_request之后,下一步就该用gpio_direction_output/input来设置方向了;那我们去看看gpio_chip的 direction_output成员究竟做没做
rockchip_gpio_direction_output
rockchip_gpio_set(gc, offset, value);
pinctrl_gpio_direction_output(gc->base + offset);
pinctrl_gpio_direction
pinctrl_gpio_direction
ops->gpio_set_direction(pctldev, range, pin, input);
rockchip_pmx_gpio_set_direction
最终在下面这里设置了复用gpio功能(不同平台又有区别,有的平台的寄存器的某个位都是复用为gpio的,有的并不是,所以不同平台会做不同处理,暂不展开),并通过写对应寄存器来设置方向
static int _rockchip_pmx_gpio_set_direction(struct gpio_chip *chip,
int pin, bool input)
{
struct rockchip_pin_bank *bank;
int ret;
unsigned long flags;
u32 data;
bank = gpiochip_get_data(chip);
ret = rockchip_set_mux(bank, pin, RK_FUNC_GPIO);
if (ret < 0)
return ret;
clk_enable(bank->clk);
raw_spin_lock_irqsave(&bank->slock, flags);
data = readl_relaxed(bank->reg_base + GPIO_SWPORT_DDR);
/* set bit to 1 for output, 0 for input */
if (!input)
data |= BIT(pin);
else
data &= ~BIT(pin);
writel_relaxed(data, bank->reg_base + GPIO_SWPORT_DDR);
raw_spin_unlock_irqrestore(&bank->slock, flags);
clk_disable(bank->clk);
return 0;
}
gpio_set_value
上面的配置都好了,设置值这个就好说了,就是单纯的gpio_chip.set=rockchip_gpio_set来设置数据寄存器,输出高低电平
static void rockchip_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
{
struct rockchip_pin_bank *bank = gpiochip_get_data(gc);
void __iomem *reg = bank->reg_base + GPIO_SWPORT_DR;
unsigned long flags;
u32 data;
clk_enable(bank->clk);
raw_spin_lock_irqsave(&bank->slock, flags);
data = readl(reg);
data &= ~BIT(offset);
if (value)
data |= BIT(offset);
writel(data, reg);
raw_spin_unlock_irqrestore(&bank->slock, flags);
clk_disable(bank->clk);
}
gpio_add_data
先列出部分重要代码,再在小章节依次分析
int gpiochip_add_data(struct gpio_chip *chip, void *data)
{
.................
if (base < 0) {
base = gpiochip_find_base(chip->ngpio);
if (base < 0) {
status = base;
spin_unlock_irqrestore(&gpio_lock, flags);
goto err_free_descs;
}
chip->base = base;
}
.................
for (id = 0; id < chip->ngpio; id++) {
struct gpio_desc *desc = &descs[id];
desc->chip = chip;
/* REVISIT: most hardware initializes GPIOs as inputs (often
* with pullups enabled) so power usage is minimized. Linux
* code should set the gpio direction first thing; but until
* it does, and in case chip->get_direction is not set, we may
* expose the wrong direction in sysfs.
*/
desc->flags = !chip->direction_input ? (1 << FLAG_IS_OUT) : 0;
}
gpiochip_set_desc_names(chip);
................
status = of_gpiochip_add(chip);
acpi_gpiochip_add(chip);
................
status = gpiochip_sysfs_register(chip);
}
gpio编号从何开始
不知同学们注意到一个问题没,有些平台的gpio编号是从1023一次递减的,有些平台是从0递增的,那么选择那种方式,其实就是由base值而定的,小于0就动态分配
static int gpiochip_find_base(int ngpio)
{
struct gpio_chip *chip;
int base = ARCH_NR_GPIOS - ngpio;
list_for_each_entry_reverse(chip, &gpio_chips, list) {
/* found a free space? */
if (chip->base + chip->ngpio <= base)
break;
else
/* nope, check the space right before the chip */
base = chip->base - ngpio;
}
if (gpio_is_valid(base)) {
pr_debug("%s: found new base at %d\n", __func__, base);
return base;
} else {
pr_err("%s: cannot find free range\n", __func__);
return -ENOSPC;
}
}
比如高通某平台的的三个gpio_chip(gpiochip0/1/2),的起始编号 = “现阶段最大的编号” 减去 “本gpio_chip的pin脚总数”。大于等于0,那么地址等于多少就是多少
chip = &pctrl->chip;
chip->base = -1;
chip->ngpio = ngpio;
gpiochip_add_data(&pctrl->chip, pctrl);
gpio_desc
我们看下这个结构体的定义,主要包含gpio_chip和flag,name,这个flag的不同bit代表了不同的状态标记,那么在上面的代码设置了FLAG_IS_OUT,以及gpiochip_set_desc_names(chip)
struct gpio_desc {
struct gpio_chip *chip;
unsigned long flags;
/* flag symbols are bit numbers */
#define FLAG_REQUESTED 0
#define FLAG_IS_OUT 1
#define FLAG_EXPORT 2 /* protected by sysfs_lock */
#define FLAG_SYSFS 3 /* exported via /sys/class/gpio/control */
#define FLAG_ACTIVE_LOW 6 /* value has active low */
#define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */
#define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */
#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */
#define FLAG_IS_HOGGED 11 /* GPIO is hogged */
/* Connection label */
const char *label;
/* Name of the GPIO */
const char *name;
};
of_gpiochip_add
这个函数的主要内容如下
of_gpiochip_add(chip);
of_gpiochip_add_pin_range(chip);
of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3,index, &pinspec);
pctldev = of_pinctrl_get(pinspec.np);
gpiochip_add_pin_range(chip,
pinctrl_dev_get_devname(pctldev),
pinspec.args[0],
pinspec.args[1],
pinspec.args[2]);
rockchip平台的gpio节点没有这个属性,但是在pinctrl驱动里面用pinctrl_add_gpio_range添加了这个映射
for (bank = 0; bank < info->ctrl->nr_banks; ++bank) {
pin_bank = &info->ctrl->pin_banks[bank];
pin_bank->grange.name = pin_bank->name;
pin_bank->grange.id = bank;
pin_bank->grange.pin_base = pin_bank->pin_base;
pin_bank->grange.base = pin_bank->gpio_chip.base;
pin_bank->grange.npins = pin_bank->gpio_chip.ngpio;
pin_bank->grange.gc = &pin_bank->gpio_chip;
pinctrl_add_gpio_range(info->pctl_dev, &pin_bank->grange);
}
不然gpio_request -> gpio_chip.request -> gpiochip_generic_request->pinctrl_request_gpio会去找range,找失败了直接就返回了
gpio-ranges:<&iomuxc 0 23 10>代表了当前gpio1控制器的0号gpio,的gpio编号偏移为23,并且从0开始的连续10个脚的偏移都是23
gpio1: gpio@0209c000 {
gpio-ranges = <&iomuxc 0 23 10>, <&iomuxc 10 17 6>,
<&iomuxc 16 33 16>;
};
gpio2: gpio@020a0000 {
gpio-ranges = <&iomuxc 0 49 16>, <&iomuxc 16 111 6>;
};
但是高通的就是自己实现的request,其gpio字节点没有gpio_range属性,照样工作正常,因为其引脚范围都放进soc的groups里了
static int msm_pinmux_request_gpio(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned offset)
{
struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
const struct msm_pingroup *g = &pctrl->soc->groups[offset];
/* No funcs? Probably ACPI so can't do anything here */
if (!g->nfuncs)
return 0;
/* For now assume function 0 is GPIO because it always is */
return msm_pinmux_set_mux(pctldev, g->funcs[0], offset);
}
static const struct pinmux_ops msm_pinmux_ops = {
.request = msm_pinmux_request,
.free = msm_pinmux_free,
.get_functions_count = msm_get_functions_count,
.get_function_name = msm_get_function_name,
.get_function_groups = msm_get_function_groups,
.gpio_request_enable = msm_pinmux_request_gpio,
.set_mux = msm_pinmux_set_mux,
};
但是高通为了兼容acpi_gpiochip_add还是必须调用gpiochip_add_pin_range,这么做就是单纯的为了兼容acpi系统而已
if (!of_property_read_bool(pctrl->dev->of_node, "gpio-ranges")) {
ret = gpiochip_add_pin_range(&pctrl->chip,
dev_name(pctrl->dev), 0, 0, chip->ngpio);
if (ret) {
dev_err(pctrl->dev, "Failed to add pin range\n");
gpiochip_remove(&pctrl->chip);
return ret;
}
}