ZYNQ的GPIO子系统应用

设备树设置:

由于ZYNQ的引脚分配应该在VIVADO中硬件设计时完全确定,且在应用时往往不需要再对引脚进行分配,所以并不需要对pinctrl子系统所需要的设备树进行配置。
但是,对于某个功能来说,例如点亮LED,需要对LED所需要的GPIO进行相关的描述,可以在顶层.dts补充内容,例如:

#define GPIO_ACTIVE_HIGH 0
#define GPIO_ACTIVE_LOW 1
....
        led {
                compatible = "zynq,led";
                status = "okay";
                default-state = "on";
                led-gpio = <&gpio0 7 GPIO_ACTIVE_HIGH>,
                        <&gpio0 8 GPIO_ACTIVE_HIGH>;    
        };

代码使用的是就是MIO7和MIO8。EMIO按照编号往后排。

设备驱动程序:

可以利用GPIO子系统提供的API编写具体的驱动。常见的API及相关OF函数有:

int of_get_named_gpio(struct device_node *np, const char *propname, int index)
gpioled.led_gpio[i] = of_get_named_gpio(gpioled.nd,"led-gpio",i);

np:设备节点。
propname:包含要获取 GPIO 信息的属性名。
index :GPIO 索引,因为一个属性里面可能包含多个 GPIO,此参数指定要获取哪个 GPIO 的编号。上面的设备树led-gpio属性有两个GPIO,索引分别0,1.
返回值:正值,获取到的 GPIO 编号,这个编号最好在用户设备结构体里定义;负值,失败。

int gpio_request(unsigned gpio, const char *label)

gpio:要申请的 gpio 标号,使用 of_get_named_gpio 函数从设备树获取指定 GPIO 属性信息,此函数会返回这个 GPIO 的标号。
label:给 gpio 设置个名字,随便取,不要重复。
返回值:0,申请成功;其他值,申请失败。

调用 gpio_free 函数对申请的GPIO进行释放。函数原型如下:

void gpio_free(unsigned gpio)

设置某个 GPIO 为输入:

int gpio_direction_input(unsigned gpio)

设置某个 GPIO 为输出,带输出值的那种:

int gpio_direction_output(unsigned gpio, int value)

gpio:要设置为输出的 GPIO 标号。
value :GPIO 默认输出值。
返回值:0,设置成功;负值,设置失败。

获取某个 GPIO 的值(0 或 1),此函数是个宏,定义所示:

#define gpio_get_value __gpio_get_value
int __gpio_get_value(unsigned gpio)

函数参数和返回值含义如下:
gpio:要获取的 GPIO 标号。
返回值:非负值,得到的 GPIO 值;负值,获取失败。

gpio_set_value 函数
此函数用于设置某个 GPIO 的值,此函数是个宏,定义如下

#define gpio_set_value __gpio_set_value
void __gpio_set_value(unsigned gpio, int value)

函数参数和返回值含义如下:
gpio:要设置的 GPIO 标号。
value :要设置的值。
返回值:无

具体的LED设备驱动代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define NEWCHRLED_CNT 1 //the number of the devids
#define NEWCHRLED_NAME		"gpio-led"
#define LED_CNT                 2

struct chrdevbase_dev{
    dev_t devid;
    struct cdev cdev;
    struct class *class;
    struct device *device;
    int major;
    int minor;
    struct device_node *nd;
    int led_gpio[LED_CNT]; //the numbers of each led
};
const static char led_name[2][10] = {"LED-GPIO-0","LED-GPIO-1"};

static struct chrdevbase_dev gpioled;

static int chrdev_open(struct inode *inode, struct file *filp)
{
	filp->private_data = &gpioled;	/* 设置私有数据 */
    printk("led-dev!\r\n");
	return 0;
}


static ssize_t chrdev_read(struct file *filp, char __user *buf,
			size_t cnt, loff_t *offt)
{

    return 0;
}


static ssize_t chrdev_write(struct file *filp, const char __user *buf,
			size_t cnt, loff_t *offt)
{
    int ret;
	char kern_buf[1];

	ret = copy_from_user(kern_buf, buf, cnt);	// 得到应用层传递过来的数据
	if(0 > ret) {
		printk(KERN_ERR "kernel write failed!\r\n");
		return -EFAULT;
	}

	if (0 == kern_buf[0])
		gpio_set_value(gpioled.led_gpio[0], 0);	// 如果传递过来的数据是0则关闭led0
	else if (1 == kern_buf[0])
		gpio_set_value(gpioled.led_gpio[0], 1);	// 如果传递过来的数据是1则点亮led0
    else if (2 == kern_buf[0])
        gpio_set_value(gpioled.led_gpio[1], 0);	// 如果传递过来的数据是2则点亮led1
    else if (3 == kern_buf[0])
        gpio_set_value(gpioled.led_gpio[1], 1);	// 如果传递过来的数据是3则点亮led1

	return 0;
}


static int chrdev_release(struct inode *inode, struct file *filp)
{
	printk("chrdevbase release!\r\n");
    return 0;
}

static struct file_operations chrdev_fops = {
	.owner		= THIS_MODULE,
	.open		= chrdev_open,
	.read		= chrdev_read,
	.write		= chrdev_write,
	.release	= chrdev_release,
};

static int __init chrdevbase_init(void)
{
    int ret;
	const char *str;
    u8 i=0;

    gpioled.nd = of_find_node_by_path("/led");

    if(NULL == gpioled.nd){
           printk("cant find the led\r\n");
        return -EINVAL;
    }

    for(i=0;i<LED_CNT;i++){
        gpioled.led_gpio[i] = of_get_named_gpio(gpioled.nd,"led-gpio",i);
        if(!gpio_is_valid(gpioled.led_gpio[i])) {
            printk(KERN_ERR "gpioled: Failed to get led-gpio %d!\r\n",i);
            return -EINVAL;
        }
        printk(KERN_INFO "gpioled: led-gpio num = %d\r\n", gpioled.led_gpio[i]);

        ret = gpio_request(gpioled.led_gpio[i],led_name[i]);
        if (ret){
            printk("gpioled:Failed to request led-gpio- %d!\r\n",i);
            return ret;
        }

        gpio_direction_output(gpioled.led_gpio[i],0);

        ret = of_property_read_string(gpioled.nd, "default-state", &str);
        if(!ret) {
            if (!strcmp(str, "on"))
                gpio_set_value(gpioled.led_gpio[i], 1);
            else
                gpio_set_value(gpioled.led_gpio[i], 0);
        } else
            gpio_set_value(gpioled.led_gpio[i], 0);

    }

    /* major minor and devid */
    ret = alloc_chrdev_region(&gpioled.devid,0,NEWCHRLED_CNT,NEWCHRLED_NAME);
    if(ret)
        goto out1;
    gpioled.major = MAJOR(gpioled.devid);
    gpioled.major = MINOR(gpioled.devid);

    printk("chrdevbase major=%d,minor=%d\r\n",gpioled.major, gpioled.minor);

    /*initailization of cdev*/
    gpioled.cdev.owner = THIS_MODULE;
    cdev_init(&gpioled.cdev,&chrdev_fops);

    ret = cdev_add(&gpioled.cdev, gpioled.devid,NEWCHRLED_CNT);
    if(ret)
        goto out2;

    /* create a class*/
    gpioled.class = class_create(THIS_MODULE,NEWCHRLED_NAME);
    	if (IS_ERR(gpioled.class)) {
		ret = PTR_ERR(gpioled.class);
		goto out3;
	}
    
    gpioled.device = device_create(gpioled.class, NULL,
				gpioled.devid, NULL, NEWCHRLED_NAME);
	if (IS_ERR(gpioled.device)) {
		ret = PTR_ERR(gpioled.device);
		goto out4;
	}

	return 0;

out4:
	class_destroy(gpioled.class);
out3:
	cdev_del(&gpioled.cdev);
out2:
    unregister_chrdev_region(gpioled.devid,NEWCHRLED_CNT);
out1:
    gpio_free(gpioled.led_gpio[0]);
    gpio_free(gpioled.led_gpio[1]);
    return ret;
}

static void __exit chrdevbase_exit(void)
{   
    printk("Closing the driver!");
    
    device_destroy(gpioled.class, gpioled.devid);

    class_destroy(gpioled.class);

    cdev_del(&gpioled.cdev);

    unregister_chrdev_region(gpioled.devid,NEWCHRLED_CNT);

    gpio_free(gpioled.led_gpio[0]);
    gpio_free(gpioled.led_gpio[1]);
    
}

module_init(chrdevbase_init);
module_exit(chrdevbase_exit);

MODULE_AUTHOR("zangyujiagood");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("gpio_test");

你可能感兴趣的:(ZYNQ的GPIO子系统应用)