pinctrl和 gpio子系统实验

文章讲述了如何在设备树中配置pinctrl和gpio子系统来控制GPIO引脚,用于LED设备。它详细解析了设备树中的配置项,并展示了一个简单的Linux字符设备驱动程序,该程序用于打开、关闭LED灯。驱动程序包括设备的打开、写入和释放操作,以及GPIO管脚的申请、方向设置和值的改变。
摘要由CSDN通过智能技术生成

1、修改设备数

在设备树下添加:

pinctrl子系统:

pinctrl_gpioled: gpioled{
			fsl,pins = <
				MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 	0x10B0 
				MX6UL_PAD_CSI_MCLK__CSI_MCLK		0x1b088
				MX6UL_PAD_CSI_PIXCLK__CSI_PIXCLK	0x1b088
			>;
		};

gpio子系统:

/*gpioled的设备*/
	gpioled {
 			compatible = "atkalpha-led";
			pinctrl-names="default";
			pinctrl-0=<&pinctrl_gpioled>; 
			cd-gpio=<&gpio1 3 GPIO_ACTIVE_LOW>;
 			status = "okay";	
 		};

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/slab.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/errno.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/mach/map.h>

#include <linux/cdev.h>
#include <linux/device.h>

#include <linux/of.h>
#include <linux/of_address.h>

#include <linux/of_irq.h>
#include <linux/of_gpio.h>

#define GPIOLED_CNT 1
#define GPIOLED_NAME "gpioled"

struct gpioled_dev {
    int major;
    int minor;
    dev_t devide;//设备号
    struct cdev cdev;
    struct class *class;
    struct device *device;
    struct device_node * bl_nd1;/*设备节点*/
    int led_gpio;/*属性编号*/
};

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

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

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

    ledstat = databuf[0]; /* 获取状态值 */
    if(ledstat == 0) { 
       gpio_set_value(dev->led_gpio,0); /* 打开 LED 灯 */
    } else if(ledstat == 1) {
       gpio_set_value(dev->led_gpio,1); /* 关闭 LED 灯 */
    }
 
	return 0;
}

/*
 * @description		: 关闭/释放设备
 * @param - filp 	: 要关闭的设备文件(文件描述符)
 * @return 			: 0 成功;其他 失败
 */
static int gpioled_release(struct inode *inode, struct file *filp)
{
	//printk("chrdevbase release!\r\n");
	return 0;
}

static struct file_operations gpioled_ops={
    .owner=THIS_MODULE,
    .open=gpioled_open,
    .release=gpioled_release,
    .write=gpioled_write,
};

static int __init gpioled_init(void)
{
    int ret=0;

    /*获取设备节点*/
    gpioled.bl_nd1=of_find_node_by_path("/gpioled");
    if(gpioled.bl_nd1==NULL)
    {
        printk("of_find_node_by_path failed\r\n");
        return -EINVAL;
    }
    
/*获取设备cd-gpio属性的第一个GPIO编号*/
    gpioled.led_gpio=of_get_named_gpio(gpioled.bl_nd1,"cd-gpio",0);
    if(gpioled.led_gpio<0)
    {
        printk("of_get_named_gpio failed\r\n");
        return -EINVAL;
    }

    
/*申请一个GPIO管脚*/
    ret=gpio_request(gpioled.led_gpio,"cd-gpio");
    if(ret==0){
        printk("gpio_requests success\n");
    }

    
/*将GPIO设置为输出,默认输出高电平*/
    ret=gpio_direction_output(gpioled.led_gpio,1);
    if(ret<0)
    {
        printk("gpio_direction_output failed\n");
    }

    
/*注册设备号*/
    gpioled.major=0;
    if(gpioled.major){
        gpioled.devide=MKDEV(gpioled.major,0);
        register_chrdev_region(gpioled.devide,GPIOLED_CNT,GPIOLED_NAME);
    }else{
        ret=alloc_chrdev_region(&gpioled.devide, 0, GPIOLED_CNT, GPIOLED_NAME);	/* 申请设备号 */
		if(ret<0)
            {
                goto fail_devide;
            }
        gpioled.major = MAJOR(gpioled.devide);	/* 获取分配号的主设备号 */
		gpioled.minor = MINOR(gpioled.devide);	/* 获取分配号的次设备号 */
        printk("major=%d\n",gpioled.major);
        printk("minor=%d\n",gpioled.minor);
    }
     
/*初始化cdev*/
    gpioled.cdev.owner=THIS_MODULE;
    cdev_init(&gpioled.cdev, &gpioled_ops);
    
	
/* 3、添加一个cdev */
	ret= cdev_add(&gpioled.cdev, gpioled.devide, GPIOLED_CNT);
    if(ret<0)
        {
            goto fail_cdev;
        }
    
//创建设备节点
	
/* 4、创建类 */
	gpioled.class = class_create(THIS_MODULE, GPIOLED_NAME);
	if (IS_ERR(gpioled.class)) {
		ret= PTR_ERR(gpioled.class);
        goto fail_class;
	}
	
/* 5、创建设备 */
	gpioled.device = device_create(gpioled.class, NULL, gpioled.devide, NULL, GPIOLED_NAME);
	if (IS_ERR(gpioled.device)) {
		ret=PTR_ERR(gpioled.device);
        goto fail_device;
	}    
    return 0;
    fail_device:
        class_destroy(gpioled.class);
    fail_class:
        cdev_del(&gpioled.cdev);
    fail_cdev:
        unregister_chrdev_region(gpioled.devide, GPIOLED_CNT);
    fail_devide:
        return ret;
}

static void __exit gpioled_exit(void)
{
    gpio_set_value(gpioled.led_gpio,1);
    device_destroy(gpioled.class,gpioled.devide);
    
    class_destroy(gpioled.class);
    cdev_del(&gpioled.cdev);

    unregister_chrdev_region(gpioled.devide, GPIOLED_CNT);
    gpio_free(gpioled.led_gpio);

    printk("exit\n");
    printk("exit\n");
}

/*模块的加载与卸载*/
module_init(gpioled_init);
module_exit(gpioled_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("liuchuanqiang");

3、程序说明

  1. 在设备树下添加pinctrl和 gpio子系统,其中pinctrl子系统是对具体引脚的功能设置,设置内容包括复用、电气属性;gpio子系统是对具体设备的引用,gpio子系统调用pinctrl子系统。
  2. gpioled.led_gpio=of_get_named_gpio(gpioled.bl_nd1,"cd-gpio",0);获取GPIO编号,

int of_get_named_gpio(struct device_node *np, const char *propname, int index) 

函数参数和返回值含义如下:

np:设备节点。

propname:包含要获取 GPIO 信息的属性名。

index:GPIO 索引,因为一个属性里面可能包含多个 GPIO,此参数指定要获取哪个 GPIO

的编号,如果只有一个 GPIO 信息的话此参数为 0。

返回值:正值,获取到的 GPIO 编号;负值,失败。

    3、ret=gpio_request(gpioled.led_gpio,"cd-gpio");

    int gpio_request(unsigned gpio, const char *label) 函数用于申请一个GPIO管脚

函数参数和返回值含义如下:

gpio:要申请的 gpio 标号,使用 of_get_named_gpio 函数从设备树获取指定 GPIO 属性信息,此函数会返回这个 GPIO 的标号。

label:给 gpio 设置个名字。

返回值:0,申请成功;其他值,申请失败。

      4、gpio_direction_output(gpioled.led_gpio,1);设置GPIO为输出。

        int gpio_direction_output(unsigned gpio, int value)

 函数参数和返回值含义如下:

 gpio:要设置为输出的 GPIO 标号。

 value:GPIO 默认输出值。

 返回值:0,设置成功;负值,设置失败。

5、 gpio_set_value(dev->led_gpio,0);设置GPIO的值

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

函数参数和返回值含义如下:

gpio:要设置的 GPIO 标号。

value:要设置的值。

返回值:无

6、iomuxc节点是I.MX6ULL的IOMUXC外设对应的节点

对一个PIN(引脚)配置主要包括两个方面:一、PIN的复用功能;

                                                                       二、PIN的电气特性。

GPIO子系统编写:一、检查pinctrl设置;

                               二、检查这个GPIO有没有被其他外设使用。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值