正点原子IMX6UL 驱动多路LED或者继电器

前言:

项目需要改jtag为普通IO口, 所以要修改设备树

1 设备树修改

 添加IO口功能设置

		pinctrl_j_pwr_ctrls: j_pwr_ctrlgrp {
			fsl,pins = <
				MX6UL_PAD_JTAG_TDI__GPIO1_IO13		0x17059	/* j1 */
				MX6UL_PAD_JTAG_TDO__GPIO1_IO12		0x17059	/* j2 */
				MX6UL_PAD_JTAG_TCK__GPIO1_IO14		0x17059	/* j3 */
				MX6UL_PAD_JTAG_TMS__GPIO1_IO11		0x17059	/* j4 */
				MX6UL_PAD_JTAG_TRST_B__GPIO1_IO15	0x17059	/* j5 */
			>;
		};

 添加节点

	j_pwr_ctrl{
		compatible = "fsl,imx6ul-gpio", "fsl,imx35-gpio";
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_j_pwr_ctrls>;
		status = "okay";
		j_pwr_ctrls@1{
			label = "j1";
			gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>;
			default-state = "off";
		};

		j_pwr_ctrls@2{
			label = "j2";
			gpios = <&gpio1 12 GPIO_ACTIVE_HIGH>;
			default-state = "off";
		};

		j_pwr_ctrls@3{
			label = "j3";
			gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>;
			default-state = "off";
		};

		j_pwr_ctrls@4{
			label = "j4";
			gpios = <&gpio1 11 GPIO_ACTIVE_HIGH>;
			default-state = "off";
		};

		j_pwr_ctrls@5{
			label = "j5";
			gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>;
			default-state = "off";
		};
	};

 注意一定要添加compatible = "fsl,imx6ul-gpio", "fsl,imx35-gpio"; 不然用不了GPIO

2驱动

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>


struct gpio_ctl
{
    uint8_t io;
    uint8_t state;
};


#define GPIO_CNT			4		  	/* 设备号个数 */
#define GPIO_NODE_NAME		"/j_pwr_ctrl"	/* 名字 */
#define GPIO_NODE_PROPETY_NAME      "gpios"
#define GPIO_OFF 				0			/* 关灯 */
#define GPIO_ON 				1			/* 开灯 */
#define GPIO_DEFAULT_STATE  GPIO_OFF  // default level
struct node_gpio
{
   
	int gpio;			/* led所使用的GPIO编号		*/
};


/* gpioled设备结构体 */
struct gpio_dev{
	dev_t devid;			/* 设备号 	 */
	struct cdev cdev;		/* cdev 	*/
	struct class *class;	/* 类 		*/
	struct device *device;	/* 设备 	 */
    struct device_node	*nd; /* 设备节点 */
	int major;				/* 主设备号	  */
	int minor;				/* 次设备号   */
	struct node_gpio node_gpio[GPIO_CNT];
};

struct gpio_dev gpio;	/* led设备 */

/*
 * @description		: 打开设备
 * @param - inode 	: 传递给驱动的inode
 * @param - filp 	: 设备文件,file结构体有个叫做private_data的成员变量
 * 					  一般在open的时候将private_data指向设备结构体。
 * @return 			: 0 成功;其他 失败
 */
static int gpio_open(struct inode *inode, struct file *filp)
{
	filp->private_data = &gpio; /* 设置私有数据 */
	return 0;
}

/*
 * @description		: 从设备读取数据 
 * @param - filp 	: 要打开的设备文件(文件描述符)
 * @param - buf 	: 返回给用户空间的数据缓冲区
 * @param - cnt 	: 要读取的数据长度
 * @param - offt 	: 相对于文件首地址的偏移
 * @return 			: 读取的字节数,如果为负值,表示读取失败
 */
static ssize_t gpio_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
	return 0;
}

/*
 * @description		: 向设备写数据 
 * @param - filp 	: 设备文件,表示打开的文件描述符
 * @param - buf 	: 要写给设备写入的数据
 * @param - cnt 	: 要写入的数据长度
 * @param - offt 	: 相对于文件首地址的偏移
 * @return 			: 写入的字节数,如果为负值,表示写入失败
 */
static ssize_t gpio_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
	// int retvalue;
	// unsigned char databuf[1];
	// unsigned char ledstat;
	// struct gpioled_dev *dev = filp->private_data;

	// retvalue = copy_from_user(databuf, buf, cnt);
	// if(retvalue < 0) {
	// 	printk("kernel write failed!\r\n");
	// 	return -EFAULT;
	// }

	// ledstat = databuf[0];		/* 获取状态值 */

	// if(ledstat == LEDON) {	
	// 	gpio_set_value(dev->led_gpio, 0);	/* 打开LED灯 */
	// } else if(ledstat == LEDOFF) {
	// 	gpio_set_value(dev->led_gpio, 1);	/* 关闭LED灯 */
	// }
	return 0;
}

// io 
static long gpio_ioctl(struct file *filp , unsigned int cmd , unsigned long args)
{
  
struct gpio_ctl ctl;
int ret=0;
ret = copy_from_user(&ctl, (struct gpio_ctl*)args, sizeof(struct gpio_ctl));
if(ret!=0){
    return -1;
}
gpio_set_value(gpio.node_gpio[ctl.io].gpio, ctl.state);
 printk("gpio %d %d\r\n",ctl.io,ctl.state);
    return 0;
}
/*
 * @description		: 关闭/释放设备
 * @param - filp 	: 要关闭的设备文件(文件描述符)
 * @return 			: 0 成功;其他 失败
 */
static int gpio_release(struct inode *inode, struct file *filp)
{
	return 0;
}

/* 设备操作函数 */
static struct file_operations gpio_fops = {
	.owner = THIS_MODULE,
	.open = gpio_open,
	.read = gpio_read,
	.write = gpio_write,
    .unlocked_ioctl = gpio_ioctl,
	.release = 	gpio_release,
};

/* gpio操作函数*/
static int gpio_node_init(void)
{
    int ret =0;
	/* 设置LED所使用的GPIO */
	/* 1、获取设备节点:gpioled */
	gpio.nd = of_find_node_by_path(GPIO_NODE_NAME);
	if(gpio.nd == NULL) {
		printk("node not find!\r\n");
		return -EINVAL;
	} else {
		printk("node find!\r\n");
	}
    

    struct device_node *cnp;
	struct device_node *prev = NULL;
    int i = 0;
    for(i=0;i<GPIO_CNT;i++){
        cnp = of_get_next_child(gpio.nd, prev);
        if(cnp==NULL){
            break;
        }
        prev = cnp;
        gpio.node_gpio[i].gpio = of_get_named_gpio(cnp, GPIO_NODE_PROPETY_NAME, 0);
        printk("node gpio:%d %d\r\n",i,gpio.node_gpio[i].gpio);
    }
    // not calc all
    if(i!=GPIO_CNT){
        printk("node find not enought!\r\n");
        return -1;
    }
    
    // 初始化
    for(i=0;i<GPIO_CNT;i++){
        ret = gpio_direction_output( gpio.node_gpio[i].gpio, GPIO_DEFAULT_STATE);
        if(ret!=0){
            break;
        }
    }
    // not enought
    if(i!=GPIO_CNT){
        printk("gpio set default error!\r\n");
        return -1;
    }
    return 0;
}
/*
 * @description	: 驱动出口函数
 * @param 		: 无
 * @return 		: 无
 */
static int __init gpio_init(void)
{
	int ret = 0;

    if(gpio_node_init() < 0){
        printk("gpio init error!\r\n");
        return -1;
    }

	/* 注册字符设备驱动 */
	/* 1、创建设备号 */
	if (gpio.major) {		/*  定义了设备号 */
		gpio.devid = MKDEV(gpio.major, 0);
		register_chrdev_region(gpio.devid, GPIO_CNT, GPIO_NODE_NAME);
	} else {						/* 没有定义设备号 */
		alloc_chrdev_region(&gpio.devid, 0, GPIO_CNT, GPIO_NODE_NAME);	/* 申请设备号 */
		gpio.major = MAJOR(gpio.devid);	/* 获取分配号的主设备号 */
		gpio.minor = MINOR(gpio.devid);	/* 获取分配号的次设备号 */
	}
	printk("gpio major=%d,minor=%d\r\n",gpio.major, gpio.minor);	
	
	/* 2、初始化cdev */
	gpio.cdev.owner = THIS_MODULE;
	cdev_init(&gpio.cdev, &gpio_fops);
	
	/* 3、添加一个cdev */
	cdev_add(&gpio.cdev, gpio.devid, GPIO_CNT);

	/* 4、创建类 */
	gpio.class = class_create(THIS_MODULE, GPIO_NODE_NAME);
	if (IS_ERR(gpio.class)) {
		return PTR_ERR(gpio.class);
	}

	/* 5、创建设备 */
	gpio.device = device_create(gpio.class, NULL, gpio.devid, NULL, GPIO_NODE_NAME);
	if (IS_ERR(gpio.device)) {
		return PTR_ERR(gpio.device);
	}
	return 0;
}

/*
 * @description	: 驱动出口函数
 * @param 		: 无
 * @return 		: 无
 */
static void __exit gpio_exit(void)
{
	/* 注销字符设备驱动 */
	cdev_del(&gpio.cdev);/*  删除cdev */
	unregister_chrdev_region(gpio.devid, GPIO_CNT); /* 注销设备号 */

	device_destroy(gpio.class, gpio.devid);
	class_destroy(gpio.class);
}

module_init(gpio_init);
module_exit(gpio_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("kirito");

3 应用

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
#include "stdint.h"
#define LEDOFF 	0
#define LEDON 	1


struct gpio_ctl
{
    uint8_t io;
    uint8_t state;
};

/*
 * @description		: main主程序
 * @param - argc 	: argv数组元素个数
 * @param - argv 	: 具体参数
 * @return 			: 0 成功;其他 失败
 */
int main(int argc, char *argv[])
{
	int fd, retvalue;
	char *filename;
	
	
	if(argc != 2){
		printf("Error Usage!\r\n");
		return -1;
	}

	filename = argv[1];
	/* 打开led驱动 */
	fd = open(filename, O_RDWR);
	if(fd < 0){
		printf("file %s open failed!\r\n", argv[1]);
		return -1;
	}
 
    struct gpio_ctl ctl;
    int state = 0;
    int i =0;
    while (1)
    {
     sleep(1);
     if(state){
        state = 0;
     }else{
         state =1;
     }
     
     for( i =0;i<4;i++){
            ctl.io=i;
            ctl.state = state;
            ioctl(fd,1,&ctl);
     }
    }
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值