nuc980 linux 控制 gpio 引脚电平

        这里使用miscdevice设备的方式编写,关键结构体与API

#define MISC_DYNAMIC_MINOR	255
struct miscdevice  {
	int minor;
	const char *name;
	const struct file_operations *fops;
	struct list_head list;
	struct device *parent;
	struct device *this_device;
	const struct attribute_group **groups;
	const char *nodename;
	umode_t mode;
};
extern int misc_register(struct miscdevice *misc);
extern void misc_deregister(struct miscdevice *misc);

  注册misc设备:

extern int misc_register(struct miscdevice *misc)

注销misc设备:

extern void misc_deregister(struct miscdevice *misc);

 gpiolib的API接口:

static inline void gpio_set_value(unsigned gpio, int value)
static inline int gpio_get_value(unsigned gpio)
static inline int gpio_request(unsigned gpio, const char *label)
static inline int gpio_direction_output(unsigned gpio, int value)
static inline int gpio_direction_input(unsigned gpio)
static inline void gpio_free(unsigned gpio)
   

混杂设备注册起来比较方便不需要使用复杂的设备和类创建,驱动程序代码:

#include "linux/kernel.h"
#include "linux/module.h"
#include "linux/fs.h"
#include "linux/cdev.h"
#include "asm-generic/gpio.h"
#include "linux/gpio.h"
#include "linux/miscdevice.h"
#include "linux/file.h"
#include <asm/uaccess.h>

#define print_ret(ret) printk("line:%d,fun:%s,ret:%d \n",__LINE__,__FUNCTION__,ret)
#define GET_GPIO_VALUE 0x01
#define SET_GPIO_VALUE 0x02

static ssize_t gpio_read(struct file *fp, char __user *buff, size_t size, loff_t *off);
static int gpio_open(struct inode *i, struct file *fp);
static ssize_t gpio_write(struct file *fp, const char __user *buff, size_t size, loff_t *off);
static int gpio_release(struct inode *i, struct file *fp);
static long gpio_compat_ioctl(struct file *fp, unsigned int cmd, unsigned long arg);

struct gpio_device{
    struct miscdevice *gp;
    unsigned gpio;
    const char *label;
};

static struct file_operations fp={
    .owner = THIS_MODULE,
    .open = gpio_open,
    .release = gpio_release,
    .write = gpio_write,
    .read = gpio_read,
    .compat_ioctl = gpio_compat_ioctl,
};
static struct miscdevice gpio_md={
    .minor = MISC_DYNAMIC_MINOR,
    .name = "gpio_device",
    .fops = &fp,
};
static struct gpio_device gd={
    .gpio = 0xC0,//NUC980_PG0	(0xC0 + 0)
    .label = "NUC980_PG0",
    .gp = &gpio_md,
};


static ssize_t gpio_read(struct file *fp, char __user *buff, size_t size, loff_t *off)
{
    ssize_t ret;
    struct gpio_device *g = (struct gpio_device *)fp->private_data;
    ret = gpio_get_value(g->gpio);
    ret = copy_to_user(buff,&ret,sizeof(ret));
    return ret;
}

static int gpio_open(struct inode *i, struct file *fp)
{
    int ret=0;
    fp->private_data = &gd;
    return ret;
}

static ssize_t gpio_write(struct file *fp, const char __user *buff, size_t size, loff_t *off)
{
    ssize_t ret=0;
    char value[1];
    struct gpio_device *g = (struct gpio_device *)fp->private_data;
    ret=copy_from_user(value,buff,sizeof(value));
    gpio_set_value(g->gpio,value[0]);
    return ret;
}

static int gpio_release(struct inode *i, struct file *fp)
{
    int ret=0;
    return ret;
}
static long gpio_compat_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
{
    long ret=0;
    unsigned long *p = (unsigned long *)arg;
    struct gpio_device *g = (struct gpio_device *)fp->private_data;

    switch (cmd){
    case GET_GPIO_VALUE:
        ret = gpio_get_value(g->gpio);
        *p = ret;
        break;
    case SET_GPIO_VALUE:
        gpio_set_value(g->gpio,*p);
        break;
    default:
        ret = -1;break;
    }
    return ret;
}


int __init gpio_init(void)
{	
	int ret;

//	printk("%s\n%d,%s exec \n",__FILE__,__LINE__,__FUNCTION__);
    ret = gpio_request(gd.gpio,gd.label);
    print_ret(ret);
    ret = gpio_direction_output(gd.gpio,1);
    print_ret(ret);
    ret = misc_register(&gpio_md);
    print_ret(ret);
	return 0;
}

void __exit gpio_clean(void)
{	
    gpio_free(gd.gpio);
    misc_deregister(&gpio_md);
    printk("%s\n%d,%s exit \n",__FILE__,__LINE__,__FUNCTION__);
}

module_init(gpio_init);
module_exit(gpio_clean);

MODULE_AUTHOR("klp");
MODULE_DESCRIPTION("ubuntu test");
MODULE_LICENSE("GPL");
MODULE_ALIAS("mod:test");

应用测试代码:

#include "stdio.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc,char*argv[])
{
    printf("%s,%d main app exit \n",__FILE__,__LINE__);
    char buffer[1]={0};
    int fd = open("/dev/gpio_device",O_RDWR);
    while(1){
        buffer[0]=1;
        write(fd,buffer,1);
        sleep(1);
        buffer[0]=0;
        write(fd,buffer,1);
        sleep(1);
    }
    close(fd);
    return 0;
}

也可以使用cdev的方式注册设备只不过相对复杂一些。

需要注意的API:

struct device *device_create(struct class *cls, struct device *parent,
			     dev_t devt, void *drvdata,
			     const char *fmt, ...);
extern void device_destroy(struct class *cls, dev_t devt);
#define class_create(owner, name)
void class_destroy(struct class *cls);
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
			const char *name)
int register_chrdev_region(dev_t from, unsigned count, const char *name)
void unregister_chrdev_region(dev_t from, unsigned count)

cdev方式设备注册源码:

#include "linux/kernel.h"
#include "linux/module.h"
#include "linux/fs.h"
#include "linux/cdev.h"
#include "asm-generic/gpio.h"
#include "linux/gpio.h"
#include "linux/cdev.h"
#include "linux/file.h"
#include <asm/uaccess.h>

#define print_ret(ret) printk("line:%d,fun:%s,ret:%d \n",__LINE__,__FUNCTION__,ret)
#define GET_GPIO_VALUE 0x01
#define SET_GPIO_VALUE 0x02

static ssize_t gpio_read(struct file *fp, char __user *buff, size_t size, loff_t *off);
static int gpio_open(struct inode *i, struct file *fp);
static ssize_t gpio_write(struct file *fp, const char __user *buff, size_t size, loff_t *off);
static int gpio_release(struct inode *i, struct file *fp);
static long gpio_compat_ioctl(struct file *fp, unsigned int cmd, unsigned long arg);

struct gpio_device{
    struct cdev * gp;
    dev_t devid;
    unsigned gpio;
    const char *label;
    struct class *gpio_class;;
};

static struct file_operations fp={
    .owner = THIS_MODULE,
    .open = gpio_open,
    .release = gpio_release,
    .write = gpio_write,
    .read = gpio_read,
    .compat_ioctl = gpio_compat_ioctl,
};

static struct gpio_device gd={
    .gpio = 0xC0,//NUC980_PG0	(0xC0 + 0)
    .label = "gpio_device",
};


static ssize_t gpio_read(struct file *fp, char __user *buff, size_t size, loff_t *off)
{
    ssize_t ret;
    struct gpio_device *g = (struct gpio_device *)fp->private_data;
    ret = gpio_get_value(g->gpio);
    ret = copy_to_user(buff,&ret,sizeof(ret));
    return ret;
}

static int gpio_open(struct inode *i, struct file *fp)
{
    int ret=0;
    fp->private_data = &gd;
    return ret;
}

static ssize_t gpio_write(struct file *fp, const char __user *buff, size_t size, loff_t *off)
{
    ssize_t ret=0;
    char value[1];
    struct gpio_device *g = (struct gpio_device *)fp->private_data;
    ret=copy_from_user(value,buff,sizeof(value));
    gpio_set_value(g->gpio,value[0]);
    return ret;
}

static int gpio_release(struct inode *i, struct file *fp)
{
    int ret=0;
    return ret;
}
static long gpio_compat_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
{
    long ret=0;
    unsigned long *p = (unsigned long *)arg;
    struct gpio_device *g = (struct gpio_device *)fp->private_data;

    switch (cmd){
    case GET_GPIO_VALUE:
        ret = gpio_get_value(g->gpio);
        *p = ret;
        break;
    case SET_GPIO_VALUE:
        gpio_set_value(g->gpio,*p);
        break;
    default:
        ret = -1;break;
    }
    return ret;
}


int __init gpio_init(void)
{	
	int ret;

    printk("%s\n%d,%s exec \n",__FILE__,__LINE__,__FUNCTION__);
    ret = gpio_request(gd.gpio,gd.label);
    print_ret(ret);
    ret = gpio_direction_output(gd.gpio,1);
    print_ret(ret);

    ret = alloc_chrdev_region(&gd.devid, 0, 1,gd.label);
    print_ret(ret);
    gd.gp = cdev_alloc();
    gd.gp->owner = THIS_MODULE;
    gd.gp->ops = &fp;
    ret = cdev_add(gd.gp,gd.devid,1);
    print_ret(ret);

    gd.gpio_class = class_create(THIS_MODULE, gd.label);
    device_create(gd.gpio_class, NULL, gd.devid,NULL, gd.label);
    return 0;
}

void __exit gpio_clean(void)
{	
    gpio_free(gd.gpio);
    unregister_chrdev_region(gd.devid,1);
    device_destroy(gd.gpio_class, gd.devid);
    class_destroy(gd.gpio_class);


    printk("%s\n%d,%s exit \n",__FILE__,__LINE__,__FUNCTION__);
}

module_init(gpio_init);
module_exit(gpio_clean);

MODULE_AUTHOR("klp");
MODULE_DESCRIPTION("ubuntu test");
MODULE_LICENSE("GPL");
MODULE_ALIAS("mod:test");

 编译设备驱动以及应用的makefile:

obj-m := gpiocontrolcdev.o
#gpiotest-objs := *.o
kernel_path := /home/klppc/nuc980/NUC980-linux-4.4.y
PWD := $(shell pwd)

all:default
	arm-linux-gcc -o main main.c
	cp main  /nfsroot/
default:
	$(MAKE) -C $(kernel_path) M=$(PWD) modules
	cp *.ko /nfsroot/
clean:
	$(MAKE) -C $(kernel_path) M=$(PWD) clean

        这个makefile编译模块的同时,编译main应用程序,编译指定模块的时候需要修改 obj-m:= file.o  这里的file为指定.c文件的文件名字。

gitee地址:https://gitee.com/already_use/nuc980-linux-driver-learning

        注意:使用混杂设备注册的设备使用 cat /proc/devices 这里面不会有注册的设备文件名字显示只有一个misc总设备名字,可以在 dev/目录里面找到注册设备名字,注册设备时使用的次设备号是 MISC_DYNAMIC_MINOR 为 0xFF,表示动态分配。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用:为了修改使用的设备树文件 nuc980-dev-v1.0.dts,您可以使用以下步骤: 1. 进入 nuc980-sdk/NUC980-linux-5.10.y/ 目录 2. 打开 nuc980-dev-v1.0.dts 文件,您可以使用 gedit 或其他文本编辑器进行编辑 引用[2]:修改完成后,您需要进行编译和拷贝操作: 1. 设置编译工具链,可以使用以下命令设置环境变量: ``` export ARCH=arm export CROSS_COMPILE=arm-buildroot-linux-gnueabi- export PATH=$PATH:/home/nx/nuc980-sdk/buildroot-2023.02/output/host/bin ``` 2. 编译生成设备树文件,可以使用以下命令: ``` make dtbs ``` 3. 编译完成后,将生成的设备树文件拷贝到电脑上,再拷贝到 SD 卡中。例如,可以使用以下命令将设备树文件拷贝到共享文件夹: ``` sudo cp arch/arm/boot/dts/nuc980-dev-v1.0.dtb /media/sf_common/ ``` 4. 如果您的开发环境和开发板在同一局域网中,您可以直接通过网络将设备树文件拷贝到开发板上。具体操作可以参考以下步骤: - 在开发板中挂载 boot 分区: ``` mount /dev/mmcblk0p1 /mnt/ ``` - 在 Ubuntu 中使用 scp 命令拷贝设备树文件到开发板上。假设开发板的 IP 地址是 192.168.31.142,可以使用以下命令: ``` scp arch/arm/boot/dts/nuc980-dev-v1.0.dtb root@192.168.31.142:/mnt/ ``` 5. 拷贝完成后,重新启动开发板进行测试: ``` reboot ``` 引用:这篇文章是在以下文章的基础上进行的:《新唐NUC980使用记录(5.10.y内核):访问以太网(LAN8720A) & 启用SSH 使用参考与演示 使用参考》。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值