Linux pinctrl子系统概念介绍和LED驱动示例
创始人
2025-05-31 07:48:48
0

Linux pinctrl子系统介绍

在很多SOC内部都有pin的控制器,通过配置pin控制器,可以将引脚配置为特定的功能特性,在软件方面,linux内核提供pinctrl子系统,目的为了统一soc厂商的pin脚管理。

以NXP i.MX7D为例,每个IO引脚有多达8种的复用功能,具体用哪一种功能,通过IOMUXC来配置引脚的具体特性。

Linux pinctrl的处理工作

引脚复用

在Linux内核DT文件夹中arch/arm/boot/dts/imx7d-pinfunc.h的文件中,定义了所有引脚的复用配置。以下面的为例

#define MX7D_PAD_I2C1_SDA_GPIO4_IO9   0x014c 0x03BC 0x0000 0x5 0x0
  • 0x014c是IOMUXC_SW_MUX_CTL_PAD_I2C1_SDA多路复用寄存器的偏移量

  • 0x03BC是IOMUXC_SW_PAD_CTL_PAD_I2C1_SDA控制寄存器的偏移量

  • 0x5 是IOMUXC_SW_MUX_CTL_PAD_I2C1_SDA多路复用寄存器ALT5的模式,也就当做普通的GPIO来用

引脚配置

引脚的具体配置,从linux3.x内核后都是在设备树中进行具体的复用和配置。

以ledclassRGB节点为例,此节点对应的IO配置为pinctrl_gpio_leds、pinctrl_gpio_led,其中pinctrl_gpio_leds主要对MX7D_PAD_SAI2_TX_BCLK__GPIO6_IO20、MX7D_PAD_SAI2_RX_DATA__GPIO6_IO21引脚进行复用,最后的0x11是配置前面控制寄存器的值

0x11

mux_reg:复用配置寄存器偏移地址
conf_reg:引脚配置寄存器偏移地址
input_reg:输入配置寄存器偏移地址
mux_mode:复用配置寄存器值
input_val:输入配置寄存器值
ledclassRGB {compatible = "arrow,RGBclassleds";reg = <0x30200000 0x60000>;    pinctrl-names = "default";pinctrl-0 = <&pinctrl_gpio_leds &pinctrl_gpio_led>;red {label = "red";};green {label = "green";};blue {label = "blue";linux,default-trigger = "heartbeat";};};pinctrl_gpio_leds: pinctrl_gpio_leds_grp {fsl,pins = ;};

MMIO(内存映射IO)设备访问

对外围设备的控制是通过写入及读取其寄存器来实现的,通过内存地址空间(MMIO)或地址空间(PIO)的连续地址来访问这些寄存器的

1:MMIO

主存和IO设备使用相同的总线地址

使用常规指令访问IO设备

linux支持的不同体系结构中使用广泛的IO方法

2:PIO

主存和IO设备使用不同的地址空间

使用特殊的CPU指令来访问IO设备

x86上的示例:IN和OUT指令

i.MX7D使用的是MMIO,但是驱动程序中无法直接访问物理地址,需要MMU进行映射。

可以通过下面的函数

1:使用ioremap、iounmap

2: 使用devm_ioremap、devm_iounmap

3:ioread8\ioread16 iowrite8\iowrite16

LED驱动示例:

#include 
#include 
#include 
#include 
#include 
#include #define GPDAT1_offset        0x00
#define GPDIR1_offset        0x04
#define GPDAT6_offset        0x50000
#define GPDIR6_offset        0x50004#define GPIO1_DIR_MASK 1 << 2
#define GPIO1_DATA_MASK 1 << 2#define GPIO6_DIR_MASK (1 << 20 | 1 << 21)
#define GPIO6_DATA_MASK (1 << 20 | 1 << 21)#define LED_RED_MASK 1 << 2
#define LED_GREEN_MASK 1 << 20
#define LED_BLUE_MASK 1 << 21struct led_dev
{u32 led_mask; /* different mask if led is R,G or B */void __iomem *base;struct led_classdev cdev;
};static void led_control(struct led_classdev *led_cdev, enum led_brightness b)
{u32 read, write;struct led_dev *led = container_of(led_cdev, struct led_dev, cdev);if (b != LED_OFF) { /* LED ON */if (led->led_mask == LED_RED_MASK) {read = ioread32(led->base + GPDAT1_offset);write = read | led->led_mask;iowrite32(write, led->base + GPDAT1_offset);}if ((led->led_mask == LED_GREEN_MASK) || (led->led_mask == LED_BLUE_MASK)) {read = ioread32(led->base + GPDAT6_offset);write = read | led->led_mask;iowrite32(write, led->base + GPDAT6_offset);}}else {if (led->led_mask == LED_RED_MASK) {read = ioread32(led->base + GPDAT1_offset);write = read & ~(led->led_mask);iowrite32(write, led->base + GPDAT1_offset);}if ((led->led_mask == LED_GREEN_MASK) || (led->led_mask == LED_BLUE_MASK)) {read = ioread32(led->base + GPDAT6_offset);write = read & ~(led->led_mask);iowrite32(write, led->base + GPDAT6_offset);}}
}static int __init ledclass_probe(struct platform_device *pdev)
{u32 GPDIR1_read, GPDIR1_write;u32 GPDIR6_read, GPDIR6_write;u32 GPDAT1_read, GPDAT1_write;u32 GPDAT6_read, GPDAT6_write;void __iomem *g_ioremap_addr;struct device_node *child;struct resource *r;struct device *dev = &pdev->dev;int count, ret;dev_info(dev, "platform_probe enter\n");/* get our first memory resource from device tree */r = platform_get_resource(pdev, IORESOURCE_MEM, 0);if (!r) {dev_err(dev, "IORESOURCE_MEM, 0 does not exist\n");return -EINVAL;}dev_info(dev, "r->start = 0x%08lx\n", (long unsigned int)r->start);dev_info(dev, "r->end = 0x%08lx\n", (long unsigned int)r->end);/* ioremap our memory region */g_ioremap_addr = devm_ioremap(dev, r->start, resource_size(r));if (!g_ioremap_addr) {dev_err(dev, "ioremap failed \n");return -ENOMEM;}count = of_get_child_count(dev->of_node);if (!count)return -EINVAL;dev_info(dev, "there are %d nodes\n", count);/* Set GPIO1_IO_2 direction bit to output */GPDIR1_read = ioread32(g_ioremap_addr + GPDIR1_offset);GPDIR1_write = GPDIR1_read | (GPIO1_DIR_MASK);iowrite32(GPDIR1_write, g_ioremap_addr + GPDIR1_offset);GPDIR6_read = ioread32(g_ioremap_addr + GPDIR6_offset);GPDIR6_write = GPDIR6_read | (GPIO6_DIR_MASK);iowrite32(GPDIR6_write, g_ioremap_addr + GPDIR6_offset);/* set all leds to 0 output */GPDAT1_read = ioread32(g_ioremap_addr + GPDAT1_offset);GPDAT1_write = GPDAT1_read & ~(GPIO1_DATA_MASK);iowrite32(GPDAT1_write, g_ioremap_addr + GPDAT1_offset);GPDAT6_read = ioread32(g_ioremap_addr + GPDAT6_offset);GPDAT6_write = GPDAT6_read & ~(GPIO6_DATA_MASK);iowrite32(GPDAT6_write, g_ioremap_addr + GPDAT6_offset);for_each_child_of_node(dev->of_node, child){struct led_dev *led_device;struct led_classdev *cdev;led_device = devm_kzalloc(dev, sizeof(*led_device), GFP_KERNEL);if (!led_device)return -ENOMEM;cdev = &led_device->cdev;led_device->base = g_ioremap_addr;of_property_read_string(child, "label", &cdev->name);if (strcmp(cdev->name,"red") == 0) {led_device->led_mask = LED_RED_MASK;led_device->cdev.default_trigger = "heartbeat";}else if (strcmp(cdev->name,"green") == 0) {led_device->led_mask = LED_GREEN_MASK;}else if (strcmp(cdev->name,"blue") == 0) {led_device->led_mask = LED_BLUE_MASK;}else {dev_info(dev, "Bad device tree value\n");return -EINVAL;}/* Disable timer trigger until led is on */led_device->cdev.brightness = LED_OFF;led_device->cdev.brightness_set = led_control;ret = devm_led_classdev_register(dev, &led_device->cdev);if (ret) {dev_err(dev, "failed to register the led %s\n", cdev->name);of_node_put(child);return ret;}}dev_info(dev, "leds_probe exit\n");return 0;
}static int __exit ledclass_remove(struct platform_device *pdev)
{dev_info(&pdev->dev, "leds_remove enter\n");dev_info(&pdev->dev, "leds_remove exit\n");return 0;
}static const struct of_device_id my_of_ids[] = {{ .compatible = "arrow,RGBclassleds"},{},
};MODULE_DEVICE_TABLE(of, my_of_ids);static struct platform_driver led_platform_driver = {.probe = ledclass_probe,.remove = ledclass_remove,.driver = {.name = "RGBclassleds",.of_match_table = my_of_ids,.owner = THIS_MODULE,}
};static int ledRGBclass_init(void)
{int ret_val;pr_info("demo_init enter\n");ret_val = platform_driver_register(&led_platform_driver);if (ret_val !=0){pr_err("platform value returned %d\n", ret_val);return ret_val;}pr_info("demo_init exit\n");return 0;
}static void ledRGBclass_exit(void)
{pr_info("led driver enter\n");platform_driver_unregister(&led_platform_driver);pr_info("led driver exit\n");
}module_init(ledRGBclass_init);
module_exit(ledRGBclass_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("Alberto Liberal ");
MODULE_DESCRIPTION("This is a driver that turns on/off RGB leds \using the LED subsystem");

相关内容

热门资讯

iPhone手机怎么玩安卓系统... 你有没有想过,你的iPhone手机竟然也能玩安卓系统?没错,就是那个一直以来让你觉得遥不可及的安卓世...
平板删安卓系统更新不了,原因及... 最近是不是你也遇到了这样的烦恼?平板电脑上的安卓系统更新不了,是不是让你头疼得要命?别急,今天就来给...
苹果组装机安卓系统卡,卡顿背后... 你有没有发现,最近用苹果手机的时候,有时候系统有点卡呢?这可真是让人头疼啊!你知道吗,其实这背后还有...
安卓系统原生浏览器,功能与体验... 你有没有发现,每次打开手机,那个小小的浏览器窗口总是默默无闻地在那里,陪你浏览网页、搜索信息、看视频...
安卓机如何上苹果系统,跨平台体... 你是不是也和我一样,对安卓机和苹果系统之间的切换充满了好奇?想象你的安卓手机里装满了各种应用,而苹果...
安卓导入系统证书失败,原因分析... 最近在使用安卓手机的时候,你是不是也遇到了一个让人头疼的问题——导入系统证书失败?别急,今天就来给你...
安卓原生系统有哪些手机,盘点搭... 你有没有想过,为什么有些手机用起来就是那么流畅,那么顺心呢?这背后可大有学问哦!今天,就让我带你一起...
安卓系统关机了怎么定位,安卓系... 手机突然关机了,是不是有点慌张呢?别担心,今天就来教你一招,让你的安卓手机即使关机了,也能轻松定位到...
安卓系统游戏加速器,畅享无延迟... 你有没有发现,手机游戏越来越好玩了?不过,有时候游戏体验可能并不那么顺畅,是不是因为手机性能不够强大...
安卓4系统天气功能,尽在掌握 安卓4系统天气功能大揭秘在当今这个数字化的世界里,手机已经不仅仅是一个通信工具,它更是一个集成了各种...
安卓系统如何玩碧蓝幻想,攻略与... 你有没有想过,在安卓系统上玩《碧蓝幻想》竟然可以这么酷炫?没错,就是那个让你沉迷其中的二次元大作!今...
安卓系统搜不到图朵,图朵生成之... 最近是不是你也遇到了这样的烦恼?手机里明明有那么多美美的图片,但是用安卓系统搜索的时候,却怎么也找不...
魁族8刷安卓系统,系统升级后的... 哇,你知道吗?最近在安卓系统圈子里,有一个话题可是引起了不小的轰动,那就是魁族8刷安卓系统。你是不是...
微信正版安装安卓系统,畅享沟通... 你有没有想过,你的微信是不是正版安装的安卓系统呢?这可不是一个小问题哦,它关系到你的微信使用体验和隐...
电视能刷安卓系统吗,电视也能刷... 电视能刷安卓系统吗?揭秘智能电视的无限可能想象你家的电视不再只是用来观看节目的工具,而是变成了一个功...
安卓系统开通通知功能,畅享智能... 你知道吗?最近安卓系统更新后,新增了一个超级实用的功能——开通通知功能!这可是个大喜事,让咱们的生活...
苹果系统安卓爱思助手,系统兼容... 你有没有发现,手机的世界里,苹果系统和安卓系统就像是一对欢喜冤家,总是各有各的粉丝,各有各的拥趸。而...
安卓系统占用很大内存,揭秘内存... 手机里的安卓系统是不是让你感觉内存不够用,就像你的房间堆满了杂物,总是找不到地方放新东西?别急,今天...
安卓系统p30,安卓系统下的摄... 你有没有发现,最近安卓系统P30在手机圈里可是火得一塌糊涂呢!这不,我就来给你好好扒一扒这款手机的那...
siri被安卓系统进入了,智能... 你知道吗?最近科技圈可是炸开了锅,因为一个大家伙——Siri,竟然悄悄地溜进了安卓系统!这可不是什么...