Linux pinctrl 和 gpio 子系统使用

由于直接对寄存器操作-----达到IO复用 操作电气属性的目的 太过于底层

linux提供了一些配置GPIO驱动的函数

————————————————————1——————————————————————

pinctrl 子系统:

①、获取设备树中 pin 信息。

②、根据获取到的 pin 信息来设置 pin 的复用功能

③、根据获取到的 pin 信息来设置 pin 的电气特性,比如上/下拉、速度、驱动能力等
-————————————————————
设备树里面设置好某个 pin 的相关属性即可,其他的初始化工作可由 pinctrl 子系统来完成

   alphaled {
        #address-cells = <1>;
        #size-cells =<1>;
        status = "okay";
        compatible = "alientek,alphaled";
        //地址 地址长度 
        reg = < 0X020C406C 0X04    /* CCM_CCGR1_BASE */
                0X020E0068 0X04 /* SW_MUX_GPIO1_IO03_BASE */
                0X020E02F4 0X04 /* SW_PAD_GPIO1_IO03_BASE */
                0X0209C000 0X04 /* GPIO1_DR_BASE */
             0X0209C004 0X04 >; /* GPIO1_GDIR_BASE */

};

/*寄存器物理地址定义*/
#define CCM_CCGR1_BASE                (0X020C406C)     /*CCGR1时钟地址 控制GPIO*/
#define SW_MUX_GPIO1_IO03_BASE        (0X020E0068)    /*IO口打复用地址*/
#define SW_PAD_GPIO1_IO03_BASE        (0X020E02F4)    /*电气属性*/
#define GPIO1_DR_BASE                (0X0209C000)    /*高低电平设置*/
#define GPIO1_GDIR_BASE                (0X0209C004)    /*设置输入输出模式 4*8=32位*/

————————————————变更

————————————重点:在设备树中添加引脚信息
在 iomuxc(IO复用) 节点 中的“imx6ul-evk”子节点下添加“pinctrl_xxx”节点

此节点需要的属性:“fsl,pins”属性

pinctrl 驱动程序是通过读取“fsl,pins”属性值来获取 PIN 的配置信息

根 据  reg 属 性 可 知 IOMUXC 外 设 寄 存 器 起 始 地 址 为 0x020e0000


		/*属于pinctrl子系统 
        对于一个 PIN 的配置主要包括两方面,
        一个是设置这个 PIN 的复用功能
        另一个就是设置这个 PIN 的电气特性*/
	pincrtl_gpioled: gpioledgrp{
		fsl,pins = <
		/*led灯的外设电气属性 加 寄存器地址*/
        /*MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 
         *宏定义0x0068 0x02F4 0x0000 0x5 0x0在imx6ul-pinfun

         *0x0068 复用寄存器偏移地址 
         IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03的偏移地址 20E_0000h base + 68h offset = 20E_0068h

         *0x02F4 电气属性寄存器偏移地址
         IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03的偏移地址 20E_0000h base + 2F4h offset = 20E_02F4h

         *0x0000寄存器偏移地址,有些外设有 input_reg 寄存器

         *0x5 第一个寄 存 器 值 复用
          0101 ALT5 — Select mux mode: ALT5 mux port: GPIO1_IO03 of instance: gpio1

         *0x0 input_reg 寄存器值  */
//0x10b0 为电气属性寄存器的值
		MX6UL_PAD_GPIO1_IO03__GPIO1_IO03	0x10b0
			>;
		};

将pinctrl 节点添加到设备节点中

pinctrl-0 = <&pincrtl_gpioled>;

————————————————————2——————————————————————
gpio 子系统:
           用于初始化 GPIO 并且提供相应的 API 函数,比如设置 GPIO 为输入输出,读取 GPIO 的值等.在设备树下添加一个属性值描述节点
        
        在内核中,关于GPIO的API函数都需要使用到GPIO编号,即将<&gpio1 3 GPIO_ACTIVE_LOW>的属性信息转换成编号 通过编号进行API函数的操作
————————————————
 led-gpios = <&gpio1 3 GPIO_ACTIVE_LOW>;//灯低电平有效
//&gpio1”表示led引脚所使用的 IO 属于 GPIO1
//“3” 表示 GPIO1 组的第 3号 IO
//表示低电平有效。
GPIO1 控制器的寄存器基地址为 0X0209C000
//gpio设备子节点在/目录下添加
	gpioled{
		compatible = "alientek,gpioled";
		//pinctrl子系统 控制外设寄存器地址和电气属性
		pinctrl-names = "default";
		pinctrl-0 = <&pincrtl_gpioled>;
        //gpio子系统
	    led-gpios = <&gpio1 3 GPIO_ACTIVE_LOW>;//灯低电平有效
        status = "okay";
	};

—————————————————————————————————— 

1、设置GPIO1—IO03的IO复用和电气属性

2、配置了GPIO1-IO03 添加 GPIO 属性信息,表明 LED所使用的 GPIO 是哪个引脚

gpio 子系统提供的常用的 API 函数

添加完成后,检查引脚 是否被其他外设使用①、检查 pinctrl 设置②、如检查 GPIO 设置

_________________________________使用 make dtbs

然后使用新编译出来的设备树 文件启动 Linux 系统,
启动成功以后进入“/proc/device-tree”目录中 查看“gpioled”节点是否存在

——————————————————————————————————————————

程序编写

描述一个设备信息

/*gpioled设备结构体*/
/*该设备需要的*/
struct gpioled_dev
{
    dev_t devid; /*设备号 32位*/
    int major ;/*主设备号 高12位*/
    int minor ;/*次设备号 低20位*/
    /*cdev表示字符设备 结构体初始化就是初始化结构体变量*/
    struct cdev cdev ;//包含了操作函数集 和 设备号 包含头文件 #include
    struct class *class; /*类*/
    struct device *device; /*设备*/
    struct device_node *nd; //节点
    int led_gpio ;//led 所使用的 GPIO 编号

};
struct gpioled_dev gpioled;

——————————————————————————

/*入口 -注册字符设备*/中注册设备号 /cdev 具体的字符设备操作集合 向内核添加字符设备 自动创建设备节点 不变

根据设备树文件

 /*1-找到节点  dts文件中的节点信息 gpioled*/

/*全路径是  backlight---使用全路径查找*/
    gpioled.nd = of_find_node_by_path("/gpioled");
    if(gpioled.nd == NULL)//是否成功
    {
        ret = -EINVAL ; 
        goto failed_findnd;
    }

/*2-获取编号 最重要的是gpios属性        —————————这里使用的是gpio子系统提供的API函数*/ 

   /*获取led对应的gpio led-gpios 获取 GPIO 编号*/  
    //gpio 的节点 获取GPIO信息的属性名  指定要获取哪个 GPIO的编号,如果只有一个 GPIO 信息的话此参数为 0
    //正值,获取到的 GPIO 编号;负值,失败。

    gpioled.led_gpio = of_get_named_gpio(gpioled.nd,"led-gpios", 0);
    if( gpioled.led_gpio < 0 )
    {
        printk("cant't find led-gpios \r\n");
        ret = -EINVAL;
        goto failed_named;
    }
    printk("led gpio num =%d \r\n" ,ret );

/*3 在使用一个 GPIO 之前要先申请GPIO管脚-----------在退出中要有释放*/

 //gpio_request 函数用于申请一个 GPIO 管脚
    //0,申请成功;其他值,申请失败
    //GPIO 的标号 给 gpio 设置个名字 


    //如果不申请就无法检测这个IO有没有被使用
    ret = gpio_request(gpioled.led_gpio, "ledgpio");
    if(ret)
    {
        printk("falied to request the led gpio \r\n");
        ret = -EINVAL;
        goto failed_request;
    }

/*4————————申请成功后需要使用IO  */
    /*设置为输出*/
    //gpio:要设置为输出的 GPIO 标号value:GPIO 默认输出值。
    //:0,设置成功;负值,设置失败

    //灯低电平点亮 默认不亮 高电平
    ret = gpio_direction_output(gpioled.led_gpio, 1);
    if(ret<0)
    {
        printk("falied to set the led gpio output \r\n");
        ret = -EINVAL;
        goto failed_output;
    }
    /*5——————设置输出后就可以控制灯输出高低电平了*/
    //输出低电平 点亮LED灯
   // gpio:要设置的 GPIO 标号 value:要设置的值。
    gpio_set_value(gpioled.led_gpio, 0);
————————————————————

同样 在操作函数中也调用GPIO的API函数(这是在注册字符设备的时候完成的)

你可能感兴趣的:(驱动,笔记,linux)