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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/543796.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数字电子技术实验(四)

单选题 1.组合逻辑电路中产生竞争冒险的原因是&#xff1f; A. 电路没有最简化 。 B. 时延 。 C. 电路有多个输出。 D. 逻辑门的类型不同。 答案&#xff1a;B 评语&#xff1a;10分 单选题 2.下列表达式不存在竞争冒险的有&#xff1f; 答案&#xff1a;A 评语&#x…

工作总结!日志打印的11条建议

前言 大家好&#xff0c;我是 JavaPub。日志是我们定位问题的得力助手&#xff0c;也是我们团队间协作沟通&#xff08;甩锅&#xff09;、明确责任归属&#xff08;撕B&#xff09;的利器。没有日志的程序运行起来就如同脱缰的野&#x1f40e;。打印日志非常重要。今天我们来…

深度强化学习(六)(改进价值学习)

深度强化学习(六)(改进价值学习) 一.经验回放 把智能体与环境交互的记录(即经验)储存到 一个数组里&#xff0c;事后反复利用这些经验训练智能体。这个数组被称为经验回放数组&#xff08;replay buffer&#xff09;。 具体来说, 把智能体的轨迹划分成 ( s t , a t , r t ,…

使用PWM实现呼吸灯功能

CC表示的意思位捕获比较&#xff0c;CCR表示的是捕获比较寄存器 占空比等效于PWM模拟出来的电压的多少&#xff0c;占空比越大等效出的模拟电压越趋近于高电平&#xff0c;占空比越小等效出来的模拟电压越趋近于低电平&#xff0c;分辨率表示的是占空比变化的精细程度&#xf…

中间件 | RPC - [Dubbo]

INDEX 1 Dubbo 与 web 容器的关系2 注册发现流程3 服务配置3.1 注册方式 & 订阅方式3.2 服务导出3.3 配置参数 4 底层技术4.1 Dubbo 的 spi 机制4.2 Dubbo 的线程池4.3 Dubbo 的负载均衡策略4.3 Dubbo 的协议 1 Dubbo 与 web 容器的关系 dubbo 本质上是一个 RPC 框架&…

【Poi-tl Documentation】自定义占位符来设置图片大小

前置说明&#xff1a; <dependency><groupId>com.deepoove</groupId><artifactId>poi-tl</artifactId><version>1.12.1</version> </dependency>模板文件&#xff1a; image_test.docx package run.siyuan.poi.tl.policy;imp…

【Poi-tl Documentation】区块对标签显示隐藏改造

前置说明&#xff1a; <dependency><groupId>com.deepoove</groupId><artifactId>poi-tl</artifactId><version>1.12.1</version> </dependency>模板&#xff1a; 删除行表格测试.docx 改造前测试效果 package run.siyuan…

磁盘未格式化,数据恢复有妙招

一、初遇磁盘未格式化&#xff0c;惊慌失措 在日常生活和工作中&#xff0c;我们经常会使用各种存储设备来保存重要的文件和数据。然而&#xff0c;有时当我们尝试访问这些存储设备时&#xff0c;却会突然遇到一个令人头痛的问题——磁盘未格式化。这个突如其来的提示让我们措…

墨子web3时事周报

链上游戏平台Crypto Gladiator League推出全链游戏平台 链上游戏平台 Crypto Gladiator League&#xff08;CGL&#xff09;宣布重大升级&#xff0c;推出全链游戏平台&#xff0c;标志着其在区块链游戏领域的新突破。全新平台主要包括三大创新&#xff1a; 首先&#xff0c;推…

(每日持续更新)jdk api之StringBufferInputStream基础、应用、实战

博主18年的互联网软件开发经验&#xff0c;从一名程序员小白逐步成为了一名架构师&#xff0c;我想通过平台将经验分享给大家&#xff0c;因此博主每天会在各个大牛网站点赞量超高的博客等寻找该技术栈的资料结合自己的经验&#xff0c;晚上进行用心精简、整理、总结、定稿&…

《Python深度学习》阅读笔记

以下是《Python深度学习》一书中学习过程中记录的一些重要的专属名词和概念&#xff1a; 一、概念 深度学习&#xff08;Deep Learning&#xff09;&#xff1a;指使用多层神经网络进行机器学习的技术。神经网络&#xff08;Neural Network&#xff09;&#xff1a;一种模仿生…

『scrapy爬虫』05. 使用管道将数据写入mysql(详细注释步骤)

目录 1. 新建管道类,并启用2. 准备好mysql数据库新建表3. 实现管道写入数据库的代码测试一下 总结 欢迎关注 『scrapy爬虫』 专栏&#xff0c;持续更新中 欢迎关注 『scrapy爬虫』 专栏&#xff0c;持续更新中 如果对mysql和python不熟悉可看专栏【Python之pymysql库学习】 1.…