jetson agx xavier gpio-user驱动

3 篇文章 0 订阅

设备树

Linux_for_Tegra/source/public/hardware/nvidia/platform/t19x/galen/kernel-dts/tegra194-p2888-0001-p2822-0000.dts

#include "common/tegra194-p2888-0001-p2822-0000-common.dtsi"
#include "common/tegra194-p2822-camera-modules.dtsi"
#include "t19x-common-modules/tegra194-camera-plugin-manager.dtsi"
#include "user/user-gpio.dtsi"

Linux_for_Tegra/source/public/hardware/nvidia/platform/t19x/galen/kernel-dts/user/user-gpio.dtsi

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

/ {
        user-gpios {
                compatible = "user,user-init-gpio";
                status = "okay";
                
                out-gpios-num = <2>;
                out-1-gpios = <&tegra_main_gpio TEGRA194_MAIN_GPIO(N, 1) GPIO_ACTIVE_HIGH>;
                out-2-gpios = <&tegra_main_gpio TEGRA194_MAIN_GPIO(H, 7) GPIO_ACTIVE_LOW>;

                input-gpios-num = <1>;
                in-1-gpios = <&tegra_main_gpio TEGRA194_MAIN_GPIO(H, 0) GPIO_ACTIVE_HIGH>;
        };
};

驱动

Linux_for_Tegra/source/public/kernel/kernel-4.9/drivers/gpio/gpio-user.c

#include <linux/list.h>
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/time.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <linux/kthread.h>

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

#define GPIOX_MAX_NUM 30

enum direction_type_t {
	GPIO_IN,
	GPIO_OUT,
	GPIO_IRQ
};

struct gpiox_device_t {
	int gpio;
	struct device * dev;

	int active_low;
	int direction;
	int edge;
	int value;
	int irq_num;
};

struct gpiox_class_t {
	struct class *gpio_class;
	struct gpiox_device_t gpio_devs[GPIOX_MAX_NUM];
	int gpio_cnt;
};


static ssize_t gpiox_active_low_show(struct device * dev, struct device_attribute * attr, char * buf)
{
	struct gpiox_device_t * xdev = dev_get_drvdata(dev);
	if(xdev == NULL)
		return 0;

	if(!strcmp(attr->attr.name, "active_low")){
		if(xdev->active_low == 0)
			return strlcpy(buf, "0\n", 3);
		else
			return strlcpy(buf, "1\n", 3);
	}
	return strlcpy(buf, "0\n", 3);
}

static ssize_t gpiox_active_low_store(struct device * dev, struct device_attribute * attr, const char * buf, size_t count)
{
	struct gpiox_device_t * xdev = dev_get_drvdata(dev);
	unsigned long on = simple_strtoul(buf, NULL, 10);
	if(xdev == NULL)
		return 0;

	if(!strcmp(attr->attr.name, "active_low")){
	}
	xdev->active_low = on ? 1 : 0;
	return count;
}

static ssize_t gpiox_direction_show(struct device * dev, struct device_attribute * attr, char * buf)
{
	struct gpiox_device_t * xdev = dev_get_drvdata(dev);
	if(xdev == NULL)
		return 0;

	if(!strcmp(attr->attr.name, "direction")){
		switch(xdev->direction){
		case GPIO_IN:
			return strlcpy(buf, "in\n", 4);
		break;
		case GPIO_OUT:
			return strlcpy(buf, "out\n", 5);
		break;
		case GPIO_IRQ:
			return strlcpy(buf,"irq\n", 5);
		break;
		}
	}
	return strlcpy(buf, "none\n", 6);
}

static ssize_t gpiox_direction_store(struct device * dev, struct device_attribute * attr, const char * buf, size_t count)
{
	int direction = 0;
	struct gpiox_device_t * xdev = dev_get_drvdata(dev);
	unsigned long on = simple_strtoul(buf, NULL, 10);
	if(xdev == NULL)
		return 0;

	if(!strcmp(attr->attr.name, "direction")){
		direction = (on==1)? GPIO_OUT :(on==0)? GPIO_IN:GPIO_IRQ; /* not used */
	}

	return 0;
}

static ssize_t gpiox_edge_show(struct device * dev, struct device_attribute * attr, char * buf)
{
	struct gpiox_device_t * xdev = dev_get_drvdata(dev);
	if(xdev == NULL)
		return 0;

	if(!strcmp(attr->attr.name, "edge")){
		if(xdev->edge == 0)
			return strlcpy(buf, "0\n", 3);
		else
			return strlcpy(buf, "1\n", 3);
	}
	return strlcpy(buf, "0\n", 3);
}

static ssize_t gpiox_edge_store(struct device * dev, struct device_attribute * attr, const char * buf, size_t count)
{
	struct gpiox_device_t * xdev = dev_get_drvdata(dev);
	unsigned long on = simple_strtoul(buf, NULL, 10);
	if(xdev == NULL)
		return 0;

	if(!strcmp(attr->attr.name, "edge")){
		if(on)
			gpio_direction_output(xdev->gpio, 1);
		else
			gpio_direction_output(xdev->gpio, 0);
	}
	xdev->edge = on ? 1 : 0;
	return count;
}


static ssize_t gpiox_value_show(struct device * dev, struct device_attribute * attr, char * buf)
{
	struct gpiox_device_t * xdev = dev_get_drvdata(dev);
	if(xdev == NULL)
		return 0;

	if(!strcmp(attr->attr.name, "value")){
		switch(xdev->direction){
		case GPIO_IN:
			xdev->value = gpio_get_value(xdev->gpio);
		case GPIO_OUT:
			if(xdev->value == 0)
				return strlcpy(buf, "0\n", 3);
			else
				return strlcpy(buf, "1\n", 3);
		break;
		case GPIO_IRQ:
		break;
		}
	}
	return strlcpy(buf, "0\n", 3);
}

static ssize_t gpiox_value_store(struct device * dev, struct device_attribute * attr, const char * buf, size_t count)
{
	struct gpiox_device_t * xdev = dev_get_drvdata(dev);

	unsigned long on = simple_strtoul(buf, NULL, 10);
	if(xdev == NULL)
		return 0;

	if(!strcmp(attr->attr.name, "value")){
		if(on)
			gpio_direction_output(xdev->gpio, 1);
		else
			gpio_direction_output(xdev->gpio, 0);
	}
	xdev->value = on ? 1 : 0;
	return count;
}

static DEVICE_ATTR(value, 0664, gpiox_value_show, gpiox_value_store);
static DEVICE_ATTR(direction, 0664, gpiox_direction_show, gpiox_direction_store);
static DEVICE_ATTR(edge, 0664, gpiox_edge_show, gpiox_edge_store);
static DEVICE_ATTR(active_low, 0664, gpiox_active_low_show, gpiox_active_low_store);
static struct attribute * gpiox_attrs[] = {
	&dev_attr_value.attr,
	&dev_attr_direction.attr,
	&dev_attr_edge.attr,
	&dev_attr_active_low.attr,
	NULL
};


static const struct attribute_group gpiox_group = {
	.attrs = gpiox_attrs,
};

static int init_device_data(struct gpiox_device_t *dev,int gpio,int active,int direction,int edge,int value)
{
	int irq_num;

	if(dev == NULL)
		return -1;

	value =(value==0)?1:0;
	dev->gpio = gpio;
	dev->active_low = active;
	dev->direction = direction;
	dev->edge = edge;
	dev->value = value;

	switch(direction){ 
	case GPIO_IN:
		printk("set gpio%d direction input \n",dev->gpio);
		gpio_direction_input(dev->gpio);
	break;
	case GPIO_OUT:
		printk("set gpio%d direction output[%d] \n",dev->gpio,value);
		gpio_direction_output(dev->gpio,value);
	break;
	case GPIO_IRQ:
		irq_num = gpio_to_irq(dev->gpio);
		dev->irq_num = (irq_num>0)?irq_num:-1;
	break;
	}

	return 0;
}

static int create_device_nodes(struct gpiox_class_t *cls,int gpio_num,enum direction_type_t direction,int flag)
{
	int ret = 0;
	char name[10];
	if(cls == NULL)
		return -1;
	if(cls->gpio_cnt>=GPIOX_MAX_NUM)	
		return -2;
	
	memset(name,0,sizeof(name));
	sprintf(name,"gpio%d",gpio_num);
	cls->gpio_devs[cls->gpio_cnt].dev = device_create(cls->gpio_class, NULL,MKDEV(0, cls->gpio_cnt), NULL, "%s", name);
	ret = sysfs_create_group(&cls->gpio_devs[cls->gpio_cnt].dev->kobj,&gpiox_group);

	init_device_data(&cls->gpio_devs[cls->gpio_cnt],gpio_num,1,direction,0,flag);
	
	dev_set_drvdata(cls->gpio_devs[cls->gpio_cnt].dev, &cls->gpio_devs[cls->gpio_cnt]);

	cls->gpio_cnt++;

	return 0;
}

static int user_gpio_probe(struct platform_device * pdev)
{
	struct device_node * node = pdev->dev.of_node;
	struct gpiox_class_t * gpiox_class;
	enum of_gpio_flags flags;
	int gpio;
	int ret,i;
	int cnt = 0;
	char gpio_name[32];

	if(!node)
		return -ENODEV;

	gpiox_class = kzalloc(sizeof(struct gpiox_class_t), GFP_KERNEL);
	if (!gpiox_class){
		printk("%s -ENOMEM\n",__func__);
		return -ENOMEM;
	}
	gpiox_class->gpio_cnt = 0;
	gpiox_class->gpio_class = class_create(THIS_MODULE, "gpio_usr");
	
	ret = of_property_read_u32(node, "out-gpios-num", &cnt);
	if (ret || !cnt) {
		pr_err("no gpio\n");
		goto INIT_ERR_FREE;
	}
	printk("get out-gpios-num:%d\n",cnt);
  
	for (i = 0; i < cnt; i++) {
		sprintf(gpio_name, "out-%d-gpios", i + 1);
		//gpio = of_get_named_gpio(node, gpio_name,0);
		gpio = of_get_named_gpio_flags(node, gpio_name,0,&flags);

		if (gpio_request(gpio, NULL)) {
			pr_err("out-%d-gpios(%d) gpio_request fail\n",i + 1,gpio);
			continue;
		}
		printk("out-%d-gpios(%d) gpio_is_valid\n", i + 1, gpio);
		create_device_nodes(gpiox_class,gpio,GPIO_OUT,flags);
	}
	
	ret = of_property_read_u32(node, "input-gpios-num", &cnt);
	if (ret || !cnt) {
		pr_err("no in gpio\n");
		cnt = 0;
	}
	printk("get input-gpios-num:%d\n",cnt);

	for (i = 0; i < cnt; i++) {
		sprintf(gpio_name, "in-%d-gpios", i + 1);
		gpio = of_get_named_gpio(node, gpio_name,0);

		if (gpio_request(gpio, NULL)) {
			pr_err("in-%d-gpios(%d) gpio_request fail\n",i + 1,gpio);
			continue;
		}
		printk("in-%d-gpios(%d) gpio_is_valid\n", i + 1, gpio);
		create_device_nodes(gpiox_class,gpio,GPIO_IN,flags);
	}

	dev_set_drvdata(&pdev->dev, gpiox_class);
	pr_info("gpio_init finish\n");
	return 0;

INIT_ERR_FREE:
	pr_err("gpio_init err\n");
	kfree(gpiox_class);
	return -1;
}

static int user_gpio_remove(struct platform_device *pdev)
{
	int i = 0;
	struct gpiox_class_t * xdev = dev_get_drvdata(&pdev->dev);
	if(xdev != NULL){
		for(i=0;i<xdev->gpio_cnt;i++){
	 		gpio_free(xdev->gpio_devs[i].gpio);
			printk("gpio%d free %d\n",i,xdev->gpio_devs[i].gpio);
			sysfs_remove_group(&xdev->gpio_devs[i].dev->kobj, &gpiox_group);
			
			device_destroy(xdev->gpio_class,MKDEV(0, i));
		}
		class_destroy(xdev->gpio_class);
	}
	return 0;
}

#ifdef CONFIG_PM
static int user_gpio_suspend(struct device *dev)
{
	return 0;
}

static int user_gpio_resume(struct device *dev)
{
	return 0;
}
#else
#define user_gpio_suspend NULL
#define user_gpio_resume NULL
#endif

static const struct dev_pm_ops user_gpio_pm_ops = {
	.suspend = user_gpio_suspend,
	.resume = user_gpio_resume,
};

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

static struct platform_driver user_gpio_driver = {
	.driver		= {
		.name	= "user-gpio",
		.owner	= THIS_MODULE,
		.pm	= &user_gpio_pm_ops,
		.of_match_table	= of_match_ptr(user_gpio_of_match),
	},
	.probe		= user_gpio_probe,
	.remove		= user_gpio_remove,
};
module_platform_driver(user_gpio_driver);

MODULE_DESCRIPTION("user gpio driver");
MODULE_AUTHOR("zhengweiqing, 1548889230@qq.com");
MODULE_LICENSE("GPL");

Makefile

Linux_for_Tegra/source/public/kernel/kernel-4.9/drivers/gpio/Makefile
最后添加:

obj-$(CONFIG_GPIO_USER)    += gpio-user.o

Kconfig

Linux_for_Tegra/source/public/kernel/kernel-4.9/drivers/gpio/Kconfig
增加GPIO_USER部分:

config GPIO_LOONGSON1
        tristate "Loongson1 GPIO support"
        depends on MACH_LOONGSON32
        select GPIO_GENERIC
        help
          Say Y or M here to support GPIO on Loongson1 SoCs.

config GPIO_USER
        tristate "USER GPIO support"
        depends on GPIOLIB
        default m
        help
          Say Y or M here to support USER GPIO .

endmenu

menu "Port-mapped I/O GPIO drivers"

tegra_defconfig

Linux_for_Tegra/source/public/kernel/kernel-4.9/arch/arm64/configs/tegra_defconfig
增加

CONFIG_GPIO_USER=m

编译

cd  Linux_for_Tegra/source/public/kernel/kernel-4.9
./build.sh

build.sh内容:

export CROSS_COMPILE=aarch64-linux-gnu-
make ARCH=arm64 tegra_defconfig
make ARCH=arm64 -j12

#TOP_PATH=/home/z/nvidia/Linux_for_Tegra
TOP_PATH=`pwd`/../../../../
cp arch/arm64/boot/Image $TOP_PATH/kernel/Image
cp arch/arm64/boot/dts/* $TOP_PATH/kernel/dtb/

sudo make ARCH=arm64 modules_install INSTALL_MOD_PATH=$TOP_PATH/rootfs/

更新设备树以及驱动上传

agx进入Recovery模式后,执行

cd  Linux_for_Tegra

./flash.sh -k kernel-dtb jetson-agx-xavier-devkit mmcblk0p1

更新完成后,重启板子,将生成驱动文件 gpio-user.ko放到板子中加载。

测试

sudo insmod gpio-user.ko 

ls /sys/class/gpio_usr/
gpio344  gpio351  gpio393

~$ cat /sys/class/gpio_usr/gpio351/direction 
out
~$ cat /sys/class/gpio_usr/gpio393/direction 
out
~$ cat /sys/class/gpio_usr/gpio344/direction 
in

~$ cat /sys/class/gpio_usr/gpio344/value
0
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: Jetson AGX Xavier手册是一个重要的指南,覆盖了NVIDIA Jetson AGX Xavier嵌入式系统的所有方面。手册提供了对该系统的全面介绍,包括硬件和软件特性、性能参数以及可用的开发工具。 手册的第一部分介绍了Jetson AGX Xavier的硬件,包括其处理器、内存、存储和外部接口。此外,手册还详细介绍了各种传感器和模块,这些模块可以帮助您扩展Jetson AGX Xavier的功能。 手册的第二部分介绍了Jetson AGX Xavier的软件特性,包括它支持的操作系统、软件开发工具和提供的软件库。此外,手册还提供了关于如何使用Jetson AGX Xavier进行深度学习和机器学习的详细指导,包括使用TensorFlow和PyTorch等流行的框架。 手册的最后部分介绍了如何开始开发应用程序,包括如何设置Jetson AGX Xavier,如何使用SDK Manager进行软件更新和安装以及如何使用NVIDIA的深度学习和机器学习工具包进行应用程序开发。此外,手册还提供了一些示例应用程序,帮助您了解如何使用Jetson AGX Xavier完成特定任务。 总体而言,Jetson AGX Xavier手册是一个非常有用的资源,提供了对这个强大的嵌入式系统的全面理解。这个手册是每个Jetson AGX Xavier用户的必备指南,值得所有开发人员和研究人员仔细阅读。 ### 回答2: Jetson AGX Xavier手册是一个详尽的用户指南,旨在帮助新手了解Jetson AGX Xavier平台的架构和使用方法。 手册涵盖了Jetson AGX Xavier的硬件和软件特性,包括处理器和存储器规格,运行TensorFlow和其他机器学习框架的方法,以及如何通过多种通信接口(如HDMI,USB和串行端口)连接和控制外设设备。该手册还涵盖了Jetson AGX Xavier的软件生态系统,包括操作系统(如Linux),驱动程序和库,以及如何使用图形用户界面和命令行界面。 此外,手册还介绍了如何优化Jetson AGX Xavier的性能和保护其硬件,例如使用供电方案、散热和其他物理配件。它还提供了有关所需系统要求的详细信息,例如需要的操作系统版本和所需的工具和软件。 总之,Jetson AGX Xavier手册是一本非常详尽的指南,旨在帮助用户更好地了解和使用这款强大的平台。通过这本手册,用户可以快速了解平台的设计和功能,为进一步开发和优化应用程序做好准备。 ### 回答3: Jetson AGX Xavier手册是一本详细介绍NVIDIA Jetson AGX Xavier嵌入式计算平台的手册。该手册以系统规格和硬件开发为主题,涵盖了该平台的架构、开发工具、软件开发包等方面的内容。手册中详细阐述了Jetson AGX Xavier的硬件设计,并提供了硬件接口与排板说明,使用户可以方便地使用该平台进行机器学习和深度学习计算任务。 手册中还提供了NVIDIA JetPack SDK安装和配置的详细说明,包括如何使用TensorRT进行模型优化和推理、如何使用CUDA加速计算任务等,为用户提供了丰富的开发资源。此外,手册中还介绍了如何在Jetson AGX Xavier上部署不同类型的计算任务,包括机器视觉、AI集成、自动驾驶等领域的应用。 Jetson AGX Xavier手册对于想要快速了解和掌握该平台的开发者来说是非常有价值的,同时该手册也是Jetson AGX Xavier开发者工作的重要参考资料。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值