linux下drivers/gpio/gpiolib.c上再封装一层user gpio驱动

每个SOC芯片厂家BSP包,基于drivers/gpio/gpiolib.c下封装一层属于自己的GPIO驱动。

生成的驱动节点一般在/sys/devices/platform/gpio/gpioxxx

上层应用程序可以通过该节点下的value:/sys/devices/platform/gpio/gpioxxx/value,来对GPIO引脚进行输出电平控制。

但是xxx是底层驱动通过某个公司换算出来的一组数值,用户无法明确知道对应的是哪个GPIO口。

所以可以自己在SOC厂家的驱动基础上再封装一层,让用户可以明确对应的GPIO。

比如led1的GPIO控制

1. 首先注册实际的GPIO控制节点:/sys/devices/platform/gpio/gpioxxx

2. 在/sys/devices/platform/下注册user_gpio节点

3. 在/sys/devices/platform/user_gpio下创建led1链接,指向/sys/devices/platform/gpio/gpioxxx

   /sys/devices/platform/user_gpio/led1  --> /sys/devices/platform/gpio/gpioxxx

用户可以通过控制led1节点下的value来对led灯进行控制

 

以下是具体的代码实例:

设备树实例:


/* ****************************************************************************
 * USER-GPIO
 */


/ {
    local_gpio: daughter-gpio {
        compatible = "Arm,user-gpio";

        status = "okay";

        led1 {
            label = "led1-ctl";
            gpios = <&gpio5 24 0>;
            output-low;
        };
        

    };

    remote_gpio: mother-gpio {
        compatible = "Arm,user-gpio";

        status = "disabled";
    };
};

驱动代码实例:

drivers/gpio/gpio-arm-user-gpio.c

#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
#include <linux/gpio.h>
#include "gpiolib.h"
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/err.h>
#include <linux/kref.h>
#include <linux/gpio/consumer.h>
#include <linux/device.h>

#include <dt-bindings/gpio/gpio.h>

struct Arm_user_gpio {
	struct device dev;
	struct kref ref;
};

static struct Arm_user_gpio *user_gpio;
static struct kobj_type Armgpio_ktype;

/**
 * Arm_user_gpio_release() - free all resources when all instances are removed
 *
 * @ref : kref used
 */
static void Arm_user_gpio_release(struct kref *ref)
{
	kobject_del(&user_gpio->dev.kobj);
	kfree(user_gpio);
	user_gpio = NULL;
}

/**
 *
 */
static void Arm_user_gpiod_release(struct device *dev, void *res)
{
	struct gpio_desc **desc = res;

	dev_dbg(dev, "clean-up : %s\n", (*desc)->label);

	/* Remove specific symlinks */
	sysfs_remove_link(&dev->kobj, (*desc)->label);
	sysfs_remove_link(&user_gpio->dev.kobj, (*desc)->label);

	/* free requested gpio */
	gpiod_put(*desc);
}

static int Arm_user_gpio_request(struct device *dev, struct device_node *np)
{
	int ret;
	struct gpio_desc **dr;
	unsigned long lflags = 0;
	enum of_gpio_flags flags;
	enum gpiod_flags dflags = 0;
	struct gpio_desc *desc = NULL;
	const char *label = NULL;

	of_property_read_string(np, "label", &label);
	if (!label) {
		dev_err(dev, "node require a 'label' property");
		return -EINVAL;
	}

	dr = devres_alloc(Arm_user_gpiod_release, sizeof(*dr), GFP_KERNEL);
	if (!dr)
		return -ENOMEM;

	if (of_property_read_bool(np, "input"))
		dflags |= GPIOD_IN;
	else if (of_property_read_bool(np, "output-low"))
		dflags |= GPIOD_OUT_LOW;
	else if (of_property_read_bool(np, "output-high"))
		dflags |= GPIOD_OUT_HIGH;
	else {
		dev_err(dev, "need to setup direction property for %s", label);
		ret = -EINVAL;
		goto err_devres;
	}

	desc = of_get_named_gpiod_flags(np, "gpios", 0, &flags);
	if (!desc) {
		dev_err(dev, "no entity for %s", label);
		ret = -ENOENT;
		goto err_devres;
	} else if (IS_ERR(desc)) {
		dev_err(dev, "error %ld for %s", PTR_ERR(desc), label);
		ret = PTR_ERR(desc);
		goto err_devres;
	}

	ret = gpiod_request(desc, label);
	if (ret) {
		dev_err(dev, "fail request for %s", label);
		goto err_devres;
	}

	if (flags & OF_GPIO_ACTIVE_LOW)
		lflags |= GPIO_ACTIVE_LOW;

	if (flags & OF_GPIO_SINGLE_ENDED) {
		if (flags & OF_GPIO_OPEN_DRAIN)
			lflags |= GPIO_OPEN_DRAIN;
		else
			lflags |= GPIO_OPEN_SOURCE;
	}

	ret = gpiod_configure_flags(desc, label, lflags, dflags);
	if (ret < 0) {
		dev_err(dev, "failed to configure flags for %s", label);
		goto err_request;
	}

	ret = gpiod_export(desc, false);
	if (ret) {
		dev_err(dev, "fail to export gpio %s", label);
		goto err_request;
	}

	/* Set up symlinks:
	 * - from /sys/.../dev/name to /sys/class/gpio/gpioN
	 * - from /sys/.../dev/name to /sys/devices/platform/user_gpio/<label>
	 * <label> is the one defined in associated device-tree property.
	 */
	gpiod_export_link(&user_gpio->dev, label, desc);
	gpiod_export_link(dev, label, desc);

	*dr = desc;
	devres_add(dev, dr);

	return 0;

err_request:
	gpiod_put(desc);
err_devres:
	devres_free(*dr);
	return ret;
}

static int Arm_user_gpio_of(struct device *dev)
{
	struct device_node *np = dev->of_node;
	struct device_node *child = NULL;

	/* return -EPROBE_DEFER, if the referenced GPIO controller does
	 * not have gpiochip registered at the moment
	 */
	for_each_available_child_of_node(np, child)
		if (of_get_gpio(child, 0) == -EPROBE_DEFER)
			return -EPROBE_DEFER;

	/* for each child  */
	for_each_child_of_node(np, child)
		Arm_user_gpio_request(dev, child);

	return 0;
}

/* ----------------------------------------------------------------------------
 */
static int Arm_user_gpio_probe(struct platform_device *pdev)
{
	struct device *dev;
	int res;

	dev =  &pdev->dev;

	if (!user_gpio) {
		user_gpio = kzalloc(sizeof(*user_gpio), GFP_KERNEL);
		if (!user_gpio) {
			res = -ENOMEM;
			goto exit;
		}
		kref_init(&user_gpio->ref);
		/* To allow gpios under /sys/devices/platform/user_gpio */
		res = kobject_init_and_add(&user_gpio->dev.kobj,
					   &Armgpio_ktype,
					   dev->kobj.parent, "user_gpio");
		if (res) {
			dev_err(dev, "Can't initialize fake device\n");
			kfree(user_gpio);
			goto exit;
		}
	} else {
		kref_get(&user_gpio->ref);
	}

	res = Arm_user_gpio_of(dev);
	if (res)
		goto exit_all;

	platform_set_drvdata(pdev,dev);

	goto exit;

exit_all:
	kref_put(&user_gpio->ref, Arm_user_gpio_release);
exit:
	return res;
}

static int Arm_user_gpio_remove(struct platform_device *pdev)
{
	kref_put(&user_gpio->ref, Arm_user_gpio_release);

	return 0;
}

static const struct of_device_id Arm_user_gpio_of_match[] = {
	{ .compatible = "Arm,user-gpio", },
	{ },
};
MODULE_DEVICE_TABLE(of, Arm_user_gpio_of_match);

static struct platform_driver Arm_user_gpio_driver = {
	.probe = Arm_user_gpio_probe,
	.remove = Arm_user_gpio_remove,
	.driver = {
		.name = "user_gpio",
		.owner = THIS_MODULE,
		.of_match_table = Arm_user_gpio_of_match,
	},
};
module_platform_driver(Arm_user_gpio_driver);

MODULE_AUTHOR("Arm SA");
MODULE_LICENSE("GPL v2");

 

### 回答1: 好的,您的问题是关于使用STM32和OV7670相机模块,并且想要使用FIFO功能和HAL库吗?如果是的话,我可以为您提供一些基本的信息和建议。 首先,OV7670是一款非常流行的CMOS图像传感器,可以与STM32微控制器相结合,实现图像采集和处理功能。要使用它的FIFO功能,需要将OV7670的FIFO引脚与STM32的GPIO引脚相连,并在STM32代码中使用HAL库进行控制。具体来说,您需要使用HAL库中的GPIO和DMA模块,配置它们以实现FIFO数据的读取和传输。 以下是一些参考资料,可以帮助您更深入地了解如何使用STM32和OV7670实现FIFO功能: 1. OV7670使用指南:https://www.waveshare.net/wiki/OV7670_Camera_Module 2. STM32 HAL库使用指南:https://www.st.com/resource/en/user_manual/dm00105879-description-of-stm32f4-hal-and-lowlayer-drivers-stmicroelectronics.pdf 3. STM32 DMA模块使用指南:https://www.st.com/resource/en/user_manual/dm00094003-stm32f7-series-stm32f7x6-stm32f7x7-stm32f7x8-stm32f7x9-stm32f7xa-advanced-armbased-32bit-mcus-stmicroelectronics.pdf 希望以上信息能够帮助您解决问题。如果您有其他问题,请随时提出。 ### 回答2: STM32Ov7670是一款基于STM32系列微控制器的图像处理模块,该模块集成了Ov7670摄像头和FIFOHAL库。它可以实现图像捕获、处理和存储等功能。 Ov7670是一款CMOS图像传感器,具有高度集成、低功耗和高分辨率等特点,能够通过I2C总线与微控制器进行通信。通过与STM32系列微控制器配合使用,可以实现对图像进行捕获和处理的功能。 FIFOHAL库是针对STM32系列微控制器的图像采集和处理库,它提供了一系列函数和接口,方便开发人员对图像进行操作。通过该库,开发人员可以实现图像的读取、处理、存储以及传输等功能。 在使用STM32Ov7670带FIFOHAL库时,开发人员可以通过FIFOHAL库提供的函数对摄像头进行初始化设置,并设置图像的采集分辨率、帧率等参数。同时,也可以通过该库提供的函数进行图像的采集、存储和传输等操作。 通过使用STM32Ov7670带FIFOHAL库,开发人员可以更方便地实现图像处理功能,比如图像的实时监控、图像的检测和识别等。此外,该库还支持图像压缩和编码等功能,可以节省存储空间和提高传输效率。 综上所述,STM32Ov7670带FIFOHAL库是一种功能强大的图像处理模块,它能够实现图像的捕获、处理和存储等功能,为开发人员提供了便捷的图像处理解决方案。 ### 回答3: STM32OV7670是一种集成了FIFO(First In, First Out)功能的摄像头模块,同时使用了HAL库进行编程。 STM32OV7670是基于STM32系列单片机的一种摄像头模块,具有高清晰度和高帧率的特点。它使用了FIFO缓冲区来存储采集到的图像数据,并且可以通过使用HAL库进行编程来控制和操作。 FIFO是一种存储数据的缓冲区,采用了先进先出的原则。这意味着数据按照它们进入缓冲区的顺序进行读取和处理。对于STM32OV7670来说,它使用FIFO缓冲区来存储从摄像头采集到的图像数据,以便后续的处理和传输。 使用HAL库可以方便地对STM32OV7670进行编程。HAL库是STM32提供的一套高级抽象层函数库,它封装了底层硬件的操作,使得开发人员可以更方便地进行软件开发。通过HAL库,我们可以使用简单的函数调用来控制和操作STM32OV7670摄像头模块,包括初始化摄像头、设置采集参数、读取图像数据等等。 总结而言,STM32OV7670带有FIFO功能和HAL库,使得它可以高效地采集和处理图像数据。FIFO缓冲区存储采集到的图像数据,并按照先进先出的原则进行处理。使用HAL库可以方便地对STM32OV7670进行编程,以实现摄像头的控制和操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值