Linux第75步_pinctrl子系统驱动和gpio子系统的常用函数

1、STM32MP1的pinctrl子系统驱动

pinctrl子系统源码目录为drivers/pinctrl,一个PIN最好只能被一个外设使用。

“stm32mp151.dtsi”中有一个“pin-controller节点标签”叫pinctrl

pinctrl: pin-controller@50002000 {

#address-cells = <1>;

/*定义子节点的reg和rangesaddres长度为32个位*/

#size-cells = <1>; 

/*定义子节点的reg和rangeslength长度为32个位*/

compatible = "st,stm32mp157-pinctrl";

/*compatible属性用于将设备和驱动绑定起来*/

ranges = <0 0x50002000 0xa400>; 

            /*子节点寄存器起始地址为0*/

/*父节点寄存器起始地址为0x50002000*/

/*寄存器最大偏移地址为0xa400*/

interrupt-parent = <&exti>;

st,syscfg = <&exti 0x60 0xff>;

hwlocks = <&hsem 0 1>;

pins-are-numbered;

gpioa: gpio@50002000 {  /*子节点gpio起始地址为0x50002000*/

gpio-controller;

#gpio-cells = <2>;

/*定义描述使用一个gpio口需要提供2个指定的参数*/

interrupt-controller;

#interrupt-cells = <2>;

reg = <0x0 0x400>; 

/*reg属性的值:当前节点寄存器起始地址为0,长度为0x400*/

clocks = <&rcc GPIOA>;

st,bank-name = "GPIOA";

status = "disabled";

};

gpiob: gpio@50003000 {

gpio-controller;

#gpio-cells = <2>;

interrupt-controller;

#interrupt-cells = <2>;

/*表明引用这个中断控制器需要2个cell*/

/*一个是使用哪个中断,另外一个是中断触发类型*/

reg = <0x1000 0x400>;

/*reg属性的值:当前节点寄存器起始地址为0x1000,长度为0x400*/

clocks = <&rcc GPIOB>;

st,bank-name = "GPIOB";

status = "disabled";

};

gpioc: gpio@50004000 {

gpio-controller;

#gpio-cells = <2>;

interrupt-controller;

#interrupt-cells = <2>;

reg = <0x2000 0x400>;

/*reg属性的值:当前节点寄存器起始地址为0x2000,长度为0x400*/

clocks = <&rcc GPIOC>;

st,bank-name = "GPIOC";

status = "disabled";

};

gpiod: gpio@50005000 {

gpio-controller;

#gpio-cells = <2>;

interrupt-controller;

#interrupt-cells = <2>;

reg = <0x3000 0x400>;

/*reg属性的值:当前节点寄存器起始地址为0x3000,长度为0x400*/

clocks = <&rcc GPIOD>;

st,bank-name = "GPIOD";

status = "disabled";

};

gpioe: gpio@50006000 {

gpio-controller;

#gpio-cells = <2>;

interrupt-controller;

#interrupt-cells = <2>;

reg = <0x4000 0x400>;

/*reg属性的值:当前节点寄存器起始地址为0x4000,长度为0x400*/

clocks = <&rcc GPIOE>;

st,bank-name = "GPIOE";

status = "disabled";

};

gpiof: gpio@50007000 {

gpio-controller;

#gpio-cells = <2>;

interrupt-controller;

#interrupt-cells = <2>;

reg = <0x5000 0x400>;

/*reg属性的值:当前节点寄存器起始地址为0x5000,长度为0x400*/

clocks = <&rcc GPIOF>;

st,bank-name = "GPIOF";

status = "disabled";

};

gpiog: gpio@50008000 {

gpio-controller;

#gpio-cells = <2>;

interrupt-controller;

#interrupt-cells = <2>;

reg = <0x6000 0x400>;

/*reg属性的值:当前节点寄存器起始地址为0x6000,长度为0x400*/

clocks = <&rcc GPIOG>;

st,bank-name = "GPIOG";

status = "disabled";

};

gpioh: gpio@50009000 {

gpio-controller;

#gpio-cells = <2>;

interrupt-controller;

#interrupt-cells = <2>;

reg = <0x7000 0x400>;

/*reg属性的值:当前节点寄存器起始地址为0x7000,长度为0x400*/

clocks = <&rcc GPIOH>;

st,bank-name = "GPIOH";

status = "disabled";

};

gpioi: gpio@5000a000 {

gpio-controller;

#gpio-cells = <2>;

interrupt-controller;

#interrupt-cells = <2>;

reg = <0x8000 0x400>;

/*reg属性的值:当前节点寄存器起始地址为0x8000,长度为0x400*/

clocks = <&rcc GPIOI>;

st,bank-name = "GPIOI";

status = "disabled";

};

gpioj: gpio@5000b000 {

gpio-controller;

#gpio-cells = <2>;

interrupt-controller;

#interrupt-cells = <2>;

reg = <0x9000 0x400>;

/*reg属性的值:当前节点寄存器起始地址为0x9000,长度为0x400*/

clocks = <&rcc GPIOJ>;

st,bank-name = "GPIOJ";

status = "disabled";

};

gpiok: gpio@5000c000 {

gpio-controller;

#gpio-cells = <2>;

interrupt-controller;

#interrupt-cells = <2>;

reg = <0xa000 0x400>;

/*reg属性的值:当前节点寄存器起始地址为0xa000,长度为0x400*/

clocks = <&rcc GPIOK>;

st,bank-name = "GPIOK";

status = "disabled";

};

};

pinctrl_z: pin-controller-z@54004000 {

#address-cells = <1>;

#size-cells = <1>;

compatible = "st,stm32mp157-z-pinctrl";

ranges = <0 0x54004000 0x400>;

            /*子节点寄存器起始地址为0*/

/*父节点寄存器起始地址为0x50004000*/

/*寄存器最大偏移地址为0x400*/

pins-are-numbered;

interrupt-parent = <&exti>;

st,syscfg = <&exti 0x60 0xff>;

hwlocks = <&hsem 0 1>;

gpioz: gpio@54004000 {

gpio-controller;

#gpio-cells = <2>;

interrupt-controller;

#interrupt-cells = <2>;

reg = <0 0x400>;

/*reg属性的值:当前节点寄存器起始地址为0,长度为0x400*/

clocks = <&scmi0_clk CK_SCMI0_GPIOZ>;

st,bank-name = "GPIOZ";

st,bank-ioport = <11>;

status = "disabled";

};

};

stm32mp15-pinctrl.dtsi中有一个pinctrl节点

&pinctrl {                     /*&pinctrl为节点名称*/

adc1_in6_pins_a: adc1-in6 {  /*adc1-in6为设备名*/

pins {

pinmux = <STM32_PINMUX('F', 12, ANALOG)>;

            /*GPIOF12用做AD输入口*/

};

};

m_can1_pins_a: m-can1-0 {

pins1 {

pinmux = <STM32_PINMUX('H', 13, AF9)>; /* GPIOH13用作CAN1_TX */

slew-rate = <1>;

drive-push-pull;/*推挽输出*/

bias-disable;/*禁止使用内部偏置电压*/

};

pins2 {

pinmux = <STM32_PINMUX('I', 9, AF9)>; /*GPIOI9用作CAN1_RX */

bias-disable;/*禁止使用内部偏置电压*/

};

};

uart4_pins_a: uart4-0 {

pins1 {

pinmux = <STM32_PINMUX('G', 11, AF6)>; /*GPIOG11用作UART4_TX */

bias-disable;/*禁止使用内部偏置电压*/

drive-push-pull;/*推挽输出*/

slew-rate = <0>;

};

pins2 {

pinmux = <STM32_PINMUX('B', 2, AF8)>; /*GPIOB2用作UART4_RX */

bias-disable;/*禁止使用内部偏置电压*/

};

};

uart4_pins_b: uart4-1 {

pins1 {

pinmux = <STM32_PINMUX('D', 1, AF8)>; /* GPIOD1用作UART4_TX */

bias-disable;  /*禁止使用内部偏置电压*/

drive-push-pull; /*推挽输出*/

slew-rate = <0>;

};

pins2 {

pinmux = <STM32_PINMUX('B', 2, AF8)>; /* GPIOB2用作UART4_RX */

bias-disable;/*禁止使用内部偏置电压*/

};

};

pwm1_pins_a: pwm1-0 {

pins {

pinmux = <STM32_PINMUX('E', 9, AF1)>, /* GPIOE9用作TIM1_CH1 */

 <STM32_PINMUX('E', 11, AF1)>, /*GPIOE11用作TIM1_CH2 */

 <STM32_PINMUX('E', 14, AF1)>; /* GPIOE14用作TIM1_CH4 */

bias-pull-down;/*内部下拉*/

drive-push-pull;/*推挽输出*/

slew-rate = <0>;

};

};

};

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

需要包含头文件#include <linux/gpio.h>

1)、申请“gpio编号”

int gpio_request(unsigned gpio, const char *label)

gpio:要申请的“gpio编号”

Iabel:给这个gpio引脚设置个名字为label所指向的字符串

返回值:0,申请“gpio编号”成功;其他值,申请“gpio编号”失败;

注意:GPIOA有16个引脚,因此GA0的“gpio编号”为0,GA15的“gpio编号”为15;GPIOB有16个引脚,因此GB0的“gpio编号”为16,GB15的“gpio编号”为31;GPIOC有16个引脚,因此GC0的“gpio编号”为32,GC15的“gpio编号”为47;等等以此类推

2)、释放“gpio编号”

void gpio_free(unsigned gpio)

gpio:要释放的“gpio编号”

struct MyGpioLED_dev{

  dev_t devid; /*声明32位变量devid用来给保存设备号 */

  int major; /* 主设备号 */

  int minor; /* 次设备号 */

  struct cdev  cdev; /*字符设备结构变量cdev */

  struct class *class; /* 类 */

  struct device *device;/*设备*/

  struct device_node *nd;/* 设备节点 */

  int led_gpio; /* led所使用的GPIO编号 */

};

struct MyGpioLED_dev strMyGpioLED;

int ret;

strMyGpioLED.nd = of_find_node_by_path("/gpio_led");

//path="/gpio_led,使用“全路径的节点名“在“stm32mp157d-atk.dts“中查找节点“gpio_led”

//返回值:返回找到的节点,如果为NULL,表示查找失败。

if(strMyGpioLED.nd == NULL) {

    printk("gpio_led node not find!\r\n");

    return -EINVAL;

}

strMyGpioLED.led_gpio = of_get_named_gpio(strMyGpioLED.nd, "led-gpio", 0);

  //在gpio_led节点中,led-gpio = <&gpioi 0 GPIO_ACTIVE_LOW>

  //np=strMyGpioLED.nd,指定的“设备节点”

  //propname="led-gpio",给定要读取的属性名字

  //Index=0,给定的GPIO索引为0

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

if(strMyGpioLED.led_gpio < 0) {

    printk("can't get led-gpio");

    return -EINVAL;

  }

printk("led-gpio num = %d\r\n", strMyGpioLED.led_gpio);

  //打印结果为:“led-gpio num = 128“

  //因为GPIO编号是从0开始的,GPIOI端口的序号是8,每个端口有16个IO口,因此GPIOI0的编号为8*16=12

ret = gpio_request(strMyGpioLED.led_gpio, "LED-GPIO");

  //gpio=strMyGpioLED.led_gpio,指定要申请的“gpio编号”

  //Iabel="LED-GPIO",给这个gpio引脚设置个名字为"LED-GPIO"

  //返回值:0,申请“gpio编号”成功;其他值,申请“gpio编号”失败;

if (ret) {

    printk(KERN_ERR "strMyGpioLED: Failed to request led-gpio\n");

    return ret;

  }

gpio_free(strMyGpioLED.led_gpio);//释放“gpio编号”

3)、设置“某个GPIO为输入口”

int gpio_direction_input(unsigned gpio)

gpio:要设置为输入的“gpio编号”;

返回值:0,设置“某个GPIO为输入口”成功;负值,设置“某个GPIO为输入口”失败。

4)、设置“某个GPIO为输出口”

int gpio_direction_output(unsigned gpio, int value)

gpio:要设置为输出的“gpio编号”;

Value:GPIO 默认输出值;
返回值:0,设置“某个GPIO为输出口”成功;负值,设置“某个GPIO为输出口”失败。

5)、读取某个gpio口的值

#define gpio_get_value  __gpio_get_value

int __gpio_get_value(unsigned gpio)

gpio:要获取的“gpio编号”;

返回值:非负值,返回“gpio口的值”;负值,获取“gpio口的值”失败。

6)、设置gpio口的值为value

#define gpio_set_value  __gpio_set_value

void __gpio_set_value(unsigned gpio, int value)

gpio:要设置的“gpio编号”;

Value:要设置的值;

举例:

struct MyGpioLED_dev{

  dev_t devid; /*声明32位变量devid用来给保存设备号 */

  int major; /* 主设备号 */

  int minor; /* 次设备号 */

  struct cdev  cdev; /*字符设备结构变量cdev */

  struct class *class; /* 类 */

  struct device *device;/*设备*/

  struct device_node *nd;/* 设备节点 */

  int led_gpio; /* led所使用的GPIO编号 */

};

struct MyGpioLED_dev strMyGpioLED;

int ret;

strMyGpioLED.nd = of_find_node_by_path("/gpio_led");

//path="/gpio_led,使用“全路径的节点名“在“stm32mp157d-atk.dts“中查找节点“gpio_led”

//返回值:返回找到的节点,如果为NULL,表示查找失败。

if(strMyGpioLED.nd == NULL) {

    printk("gpio_led node not find!\r\n");

    return -EINVAL;

}

strMyGpioLED.led_gpio = of_get_named_gpio(strMyGpioLED.nd, "led-gpio", 0);

  //在gpio_led节点中,led-gpio = <&gpioi 0 GPIO_ACTIVE_LOW>

  //np=strMyGpioLED.nd,指定的“设备节点”

  //propname="led-gpio",给定要读取的属性名字

  //Index=0,给定的GPIO索引为0

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

if(strMyGpioLED.led_gpio < 0) {

    printk("can't get led-gpio");

    return -EINVAL;

  }

printk("led-gpio num = %d\r\n", strMyGpioLED.led_gpio);

  //打印结果为:“led-gpio num = 128“

  //因为GPIO编号是从0开始的,GPIOI端口的序号是8,每个端口有16个IO口,因此GPIOI0的编号为8*16=12

gpio_set_value(strMyGpioLED->led_gpio, 0); /* 打开LED灯 */

3、与gpio相关的of函数

需要包含头文件#include <linux/of_gpio.h>

1)、根据给定的“设备节点”和“GPIO属性”,统计GPIO的数量

int of_gpio_named_count(struct device_node *np, const char *propname)

np:指定的“设备节点”。

propname:要统计的GPIO属性。

返回值:正值,统计到的GPIO数量;负值,失败。

2)、根据给定的“设备节点”,统计具有“gpios属性”的GPIO的数量

int of_gpio_count(struct device_node *np)

np:指定的“设备节点”。

返回值:正值,返回具有“gpios属性”的GPIO的数量;负值,失败。

3)、根据给定的“设备节点”,属性名和GPIO索引,读取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编号;负值,失败。

struct MyGpioLED_dev{

  dev_t devid; /*声明32位变量devid用来给保存设备号 */

  int major; /* 主设备号 */

  int minor; /* 次设备号 */

  struct cdev  cdev; /*字符设备结构变量cdev */

  struct class *class; /* 类 */

  struct device *device;/*设备*/

  struct device_node *nd;/* 设备节点 */

  int led_gpio; /* led所使用的GPIO编号 */

};

struct MyGpioLED_dev strMyGpioLED;

int ret;

strMyGpioLED.nd = of_find_node_by_path("/gpio_led");

//path="/gpio_led,使用“全路径的节点名“在“stm32mp157d-atk.dts“中查找节点“gpio_led”

//返回值:返回找到的节点,如果为NULL,表示查找失败。

if(strMyGpioLED.nd == NULL) {

    printk("gpio_led node not find!\r\n");

    return -EINVAL;

}

strMyGpioLED.led_gpio = of_get_named_gpio(strMyGpioLED.nd, "led-gpio", 0);

  //在gpio_led节点中,led-gpio = <&gpioi 0 GPIO_ACTIVE_LOW>

  //np=strMyGpioLED.nd,指定的“设备节点”

  //propname="led-gpio",给定要读取的属性名字

  //Index=0,给定的GPIO索引为0

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

if(strMyGpioLED.led_gpio < 0) {

    printk("can't get led-gpio");

    return -EINVAL;

  }

printk("led-gpio num = %d\r\n", strMyGpioLED.led_gpio);

  //打印结果为:“led-gpio num = 128“

  //因为GPIO编号是从0开始的,GPIOI端口的序号是8,每个端口有16个IO口,因此GPIOI0的编号为8*16=128