nuc980 linux controls gpio pin level

        This is written using the miscdevice device method, the key structure and 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);

  Register misc device:

extern int misc_register(struct miscdevice *misc)

Unregister the misc device:

extern void misc_deregister(struct miscdevice *misc);

 API interface of gpiolib:

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)
   

It is more convenient to register hybrid devices without the need to create complex devices and classes. The driver code:

#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");

Apply test code:

#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;
}

You can also use cdev to register the device, but it is relatively complicated.

APIs to note:

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 mode device registration source code:

#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");

 Compile the device driver and application 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

        When this makefile compiles the module, it compiles the main application. When compiling the specified module, you need to modify obj-m:= file.o where file is the file name of the specified .c file.

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

        Note: For devices registered using mixed devices, use cat /proc/devices. There will be no registered device file name, and only one misc total device name will be displayed. The registered device name can be found in the dev/ directory, and the secondary device used when registering the device. The number is MISC_DYNAMIC_MINOR and is 0xFF, indicating dynamic allocation.

Guess you like

Origin blog.csdn.net/klp1358484518/article/details/126818283