gpio控制器驱动注册流程

1 gpio控制器驱动probe函数主要实现3个功能

1、实现struct gpio_chip
注册一个GPIO控制器
对于只能做简单GPIO的引脚控制器,简单的struct gpio_chip就足以处理它。
2、实现struct irq_chip
如果控制器可以在GPIO功能之上产生中断,则必须设置struct irq_chip,并将其注册到IRQ子系统
这个结构实现了一组描述如何驱动中断控制器的方法,这些方法由核心IRQ代码直接调用
3、注册中断处理函数
devm_request_irq或者irq_set_chained_handler_and_data
下面代码是海思gpio控制器中断的注册
中断处理函数主要读寄存器确认是gpio组中具体哪一个gpio产生中断,拿到对应的irq,并调用子gpio注册的中断处理函数

static irqreturn_t pl061_irq_handler(int irq, void *data)
{
	unsigned long pending;
	int offset;
	struct gpio_chip *gc = data;
	struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);

	pending = readb(chip->base + GPIOMIS);//读中断状态寄存器
	writeb(pending, chip->base + GPIOIC);
	if (pending) {
		for_each_set_bit(offset, &pending, PL061_GPIO_NR)
			generic_handle_irq(irq_find_mapping(gc->irqdomain,//该函数获取gpio管脚对应的irq,并传给handle处理调用中断处理函数
							    offset));
	}

	return IRQ_HANDLED;
}

2 直接代码说明

	static struct irq_chip pl061_irqchip = {
	.name		= "pl061",
	//用于CPU对该irq的回应,通常表示cpu希望要清除该irq的pending状态,准备接受下一个irq请求
	.irq_ack	= pl061_irq_ack,
	//irq_mask	 这个钩子屏蔽硬件中的中断源,使它不能再被引起中断
	.irq_mask	= pl061_irq_mask,
	//irq_unmask 该钩子取消屏蔽中断源
	.irq_unmask	= pl061_irq_unmask,
	//设置IRQ的流类型(IRQ_TYPE_LEVEL/等)。
	.irq_set_type	= pl061_irq_type,
	//启用/禁用IRQ的电源管理唤醒
	.irq_set_wake	= pl061_irq_set_wake,
};

static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
{
	struct device *dev = &adev->dev;
	struct pl061_platform_data *pdata = dev_get_platdata(dev);
	struct pl061_gpio *chip;
	int ret, irq, i, irq_base;

	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
	if (chip == NULL)
		return -ENOMEM;

	if (pdata) {
		chip->gc.base = pdata->gpio_base;
		irq_base = pdata->irq_base;
		if (irq_base <= 0) {
			dev_err(&adev->dev, "invalid IRQ base in pdata\n");
			return -ENODEV;
		}
	} else {
#ifdef CONFIG_ARCH_HISI_BVT
		if (dev->of_node) {
			i = of_alias_get_id(dev->of_node, "gpio");
			chip->gc.base = i * PL061_GPIO_NR;
		}

		if (chip->gc.base < 0)
			chip->gc.base = -1;
#else
		chip->gc.base = -1;
#endif
		irq_base = 0;
	}

	chip->base = devm_ioremap_resource(dev, &adev->res);
	if (IS_ERR(chip->base))
		return PTR_ERR(chip->base);

	spin_lock_init(&chip->lock);
	if (of_property_read_bool(dev->of_node, "gpio-ranges")) {
		chip->gc.request = gpiochip_generic_request;
		chip->gc.free = gpiochip_generic_free;
	}

	chip->gc.get_direction = pl061_get_direction;
	chip->gc.direction_input = pl061_direction_input;
	chip->gc.direction_output = pl061_direction_output;
	chip->gc.get = pl061_get_value;
	chip->gc.set = pl061_set_value;
	chip->gc.ngpio = PL061_GPIO_NR;
	chip->gc.label = dev_name(dev);
	chip->gc.parent = dev;
	chip->gc.owner = THIS_MODULE;
//注册struct gpio_chip
	ret = gpiochip_add_data(&chip->gc, chip);
	if (ret)
		return ret;

	/*
	 * irq_chip support
	 */
	writeb(0, chip->base + GPIOIE); /* disable irqs */
	irq = adev->irq[0];
	if (irq < 0) {
		dev_err(&adev->dev, "invalid IRQ\n");
		return -ENODEV;
	}
//注册struct irq_chip
	ret = gpiochip_irqchip_add(&chip->gc, &pl061_irqchip,
				   irq_base, handle_bad_irq,
				   IRQ_TYPE_NONE);
	if (ret) {
		dev_info(&adev->dev, "could not add irqchip\n");
		return ret;
	}
#ifdef CONFIG_ARCH_HISI_BVT
//注册gpio控制器中断处理函数,一组GPIO共享一个中断源,中断处理函数中区分具体哪个gpio
	ret = devm_request_irq(dev, irq, pl061_irq_handler, IRQF_SHARED,
			dev_name(dev), &chip->gc);
	if (ret) {
		dev_info(dev, "request irq failed: %d\n", ret);
		return ret;
	}

	/* Set the parent IRQ for all affected IRQs */
	for (i = 0; i < chip->gc.ngpio; i++)
		irq_set_parent(irq_find_mapping(chip->gc.irqdomain, i), irq);
#else
	gpiochip_set_chained_irqchip(&chip->gc, &pl061_irqchip,
				     irq, pl061_irq_handler);
#endif

	for (i = 0; i < PL061_GPIO_NR; i++) {
		if (pdata) {
			if (pdata->directions & (BIT(i)))
				pl061_direction_output(&chip->gc, i,
						pdata->values & (BIT(i)));
			else
				pl061_direction_input(&chip->gc, i);
		}
	}

	amba_set_drvdata(adev, chip);
	dev_info(&adev->dev, "PL061 GPIO chip @%pa registered\n",
		 &adev->res.start);

	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值