pinctrl框架
pinctrl框架是linux系统为统一各SOC厂家pin管理,目的是为了减少SOC厂家系统移植工作量。
通常通过设备树初始化pinctrl,并提供调用io接口,以下为全志A64平台的实例:
在drivers/pinctrl/sunxi/pinctrl-sun50iw1p1.c:
 static const struct sunxi_desc_pin sun50iw1p1_pins[] = {
     SUNXI_PIN(SUNXI_PINCTRL_PIN(B, ),
           SUNXI_FUNCTION(0x0, "gpio_in"),
           SUNXI_FUNCTION(0x1, "gpio_out"),
           SUNXI_FUNCTION(0x2, "uart2"),        /*TX*/
           SUNXI_FUNCTION(0x3, "vdevice"),    /*vdevice for test */
           SUNXI_FUNCTION(0x4, "jtag0"),        /*MS0*/
           SUNXI_FUNCTION(0x7, "io_disabled"),
           SUNXI_FUNCTION_IRQ_BANK(0x6, , )),    /*PB_EINT0 */
     SUNXI_PIN(SUNXI_PINCTRL_PIN(B, ),
           SUNXI_FUNCTION(0x0, "gpio_in"),
           SUNXI_FUNCTION(0x1, "gpio_out"),
           SUNXI_FUNCTION(0x2, "uart2"),        /*RX*/
           SUNXI_FUNCTION(0x3, "vdevice"),    /*vdevice for test */
           SUNXI_FUNCTION(0x4, "jtag0"),        /*CK0*/
           SUNXI_FUNCTION(0x5, "sim0"),        /*PWREN*/
           SUNXI_FUNCTION(0x7, "io_disabled"),
           SUNXI_FUNCTION_IRQ_BANK(0x6, , )),    /*PB_EINT1 */
     ......
     ......
     ......
 };
 static const struct sunxi_pinctrl_desc sun50iw1p1_pinctrl_data = {
     .pins = sun50iw1p1_pins,
     .npins = ARRAY_SIZE(sun50iw1p1_pins),
     .irq_banks = ,
 };
 static int sun50iw1p1_pinctrl_probe(struct platform_device *pdev)
 {
     pr_warn("[%s][%d]\n", __func__, __LINE__);
     return sunxi_pinctrl_init(pdev,
                   &sun50iw1p1_pinctrl_data);
 }
 static struct of_device_id sun50iw1p1_pinctrl_match[] = {
     { .compatible = "allwinner,sun50i-pinctrl", },
     {}
 };
 MODULE_DEVICE_TABLE(of, sun50iw1p1_pinctrl_match);
 static struct platform_driver sun50iw1p1_pinctrl_driver = {
     .probe    = sun50iw1p1_pinctrl_probe,
     .driver    = {
         .name        = "sun50i-pinctrl",
         .owner        = THIS_MODULE,
         .of_match_table    = sun50iw1p1_pinctrl_match,
     },
 };
 static int __init sun50iw1p1_pio_init(void)
 {
     int ret;
     ret = platform_driver_register(&sun50iw1p1_pinctrl_driver);
     if (IS_ERR_VALUE(ret)) {
         pr_debug("register sun50i pio controller failed\n");
         return -EINVAL;
     }
     return ;
 }
 postcore_initcall(sun50iw1p1_pio_init);
start_kernel----rest_init----kernel_init----kernel_init_freeable----do_basic_setup----do_initcalls调用postcore_initcall。
注册平台驱动,匹配设备最后调用sunxi_pinctrl_init(pdev, &sun50iw1p1_pinctrl_data);
sun50iw1p1_pins为全志平台的PIN IO和IRQ的定义,里面定义引脚名字name,复用功能muxval,中断号irqnum。
忽略部分代码的drivers/pinctrl/sunxi/pinctrl-sunxi.c:
int sunxi_pinctrl_init(struct platform_device *pdev,
const struct sunxi_pinctrl_desc *desc)
{
struct device_node *node = pdev->dev.of_node;
struct pinctrl_desc *pctrl_desc;
struct pinctrl_pin_desc *pins;
struct sunxi_pinctrl *pctl;
struct resource *res;
int i, ret, last_pin;
struct clk *clk;
pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL); platform_set_drvdata(pdev, pctl); res = platform_get_resource(pdev, IORESOURCE_MEM, );
pctl->membase = devm_ioremap_resource(&pdev->dev, res); //返回设备的MEM资源的虚拟地址 pctl->dev = &pdev->dev;
pctl->desc = desc; pctl->irq_array = devm_kcalloc(&pdev->dev, IRQ_PER_BANK * pctl->desc->irq_banks,
sizeof(*pctl->irq_array), GFP_KERNEL); //把sunxi_pinctrl_desc的内容全部映射到sunxi_pinctrl的成员(sunxi_pinctrl_group、irq_array和sunxi_pinctrl_function)
ret = sunxi_pinctrl_build_state(pdev); pins = devm_kzalloc(&pdev->dev, pctl->desc->npins * sizeof(*pins), GFP_KERNEL); for (i = ; i < pctl->desc->npins; i++)
pins[i] = pctl->desc->pins[i].pin; //注册pctldev,这里把平台硬件相关函数向上映射到pinctrl子系统
pctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*pctrl_desc), GFP_KERNEL); //confops、pctlops和pmxops都是直接和硬件相关,新设备配置PIN需要用到
pctrl_desc->name = dev_name(&pdev->dev);
pctrl_desc->owner = THIS_MODULE;
pctrl_desc->pins = pins;
pctrl_desc->npins = pctl->desc->npins;
pctrl_desc->confops = &sunxi_pconf_ops; //pin config operations vtable
pctrl_desc->pctlops = &sunxi_pctrl_ops; //pin control operation vtable
pctrl_desc->pmxops = &sunxi_pmx_ops; //pinmux operations vtable //把描述表的name和number加入radix_tree,分配pinctrl_dev并把加入双链表,这里没有创建新的pinctrl设备,也没有state
pctl->pctl_dev = pinctrl_register(pctrl_desc, &pdev->dev, pctl); //注册gpio子系统,把平台硬件相关函数向上映射到gpio子系统
pctl->chip = devm_kzalloc(&pdev->dev, sizeof(*pctl->chip), GFP_KERNEL); last_pin = pctl->desc->pins[pctl->desc->npins - ].pin.number;
pctl->chip->owner = THIS_MODULE;
pctl->chip->request = sunxi_pinctrl_gpio_request,
pctl->chip->free = sunxi_pinctrl_gpio_free,
pctl->chip->direction_input = sunxi_pinctrl_gpio_direction_input,
pctl->chip->direction_output = sunxi_pinctrl_gpio_direction_output,
pctl->chip->get = sunxi_pinctrl_gpio_get,
pctl->chip->set = sunxi_pinctrl_gpio_set,
pctl->chip->set_debounce = sunxi_pinctrl_gpio_set_debounce,
pctl->chip->of_xlate = sunxi_pinctrl_gpio_of_xlate,
pctl->chip->to_irq = sunxi_pinctrl_gpio_to_irq,
pctl->chip->of_gpio_n_cells = ,
pctl->chip->can_sleep = false,
pctl->chip->ngpio = round_up(last_pin + , PINS_PER_BANK) - pctl->desc->pin_base;
pctl->chip->label = dev_name(&pdev->dev);
pctl->chip->dev = &pdev->dev;
pctl->chip->base = pctl->desc->pin_base; ret = gpiochip_add(pctl->chip); //把gpio_chip(A64有两个chip)加入双链表 for (i = ; i < pctl->desc->npins; i++) {
const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
//注册gpio_ranges,并加入双链表
ret = gpiochip_add_pin_range(pctl->chip, dev_name(&pdev->dev),
pin->pin.number - pctl->desc->pin_base,
pin->pin.number, );
} clk = devm_clk_get(&pdev->dev, NULL); ret = clk_prepare_enable(clk);
if (ret)
goto gpiochip_error; pctl->irq = devm_kcalloc(&pdev->dev,
pctl->desc->irq_banks,
sizeof(*pctl->irq),
GFP_KERNEL); for (i = ; i < pctl->desc->irq_banks; i++) {
pctl->irq[i] = platform_get_irq(pdev, i); //获取中断资源
} pctl->domain = irq_domain_add_linear(node, pctl->desc->irq_banks * IRQ_PER_BANK,
&irq_domain_simple_ops, NULL); //把pinctrl加入线性中断域,pin中断都域中搜索 for (i = ; i < (pctl->desc->irq_banks * IRQ_PER_BANK); i++) {
int irqno = irq_create_mapping(pctl->domain, i); //获取线性中断域的irq号 irq_set_chip_and_handler(irqno, &sunxi_pinctrl_edge_irq_chip,
handle_edge_irq); //sunxi_pinctrl_edge_irq_chip为全志底层irq_chip操作
irq_set_chip_data(irqno, pctl);
}; for (i = ; i < pctl->desc->irq_banks; i++) {
/* Mask and clear all IRQs before registering a handler */
writel(, pctl->membase + sunxi_irq_ctrl_reg_from_bank(i));
writel(0xffffffff, pctl->membase + sunxi_irq_status_reg_from_bank(i));
if(pctl->desc->pin_base >= PL_BASE){
ret = devm_request_irq(&pdev->dev, pctl->irq[i], sunxi_pinctrl_irq_handler,
IRQF_SHARED | IRQF_NO_SUSPEND, "PIN_GRP", pctl);
//同一个bank的gpio中断均共享一个中断,在sunxi_pinctrl_irq_handler通过gpio的中断号
//启动对应generic_handle_irq
}else{
ret = devm_request_irq(&pdev->dev, pctl->irq[i], sunxi_pinctrl_irq_handler,
IRQF_SHARED, "PIN_GRP", pctl); //同上
}
} return ;
}
在设备树实例(一)中的:
      soc@01c00000 {
          compatible = "simple-bus";
          #address-cells = <0x2>;
          #size-cells = <0x2>;
          ranges;
          device_type = "soc";
          pinctrl@01c20800 {
              compatible = "allwinner,sun50i-pinctrl";
              reg = <0x0 0x1c20800 0x0 0x400>;
              interrupts = <0x0 0xb 0x4 0x0 0x11 0x4 0x0 0x15 0x4>;
              device_type = "pio";
              clocks = <0xa>;
              gpio-controller;
              interrupt-controller;
              #interrupt-cells = <0x2>;
              #size-cells = <0x0>;
              #gpio-cells = <0x6>;
              linux,phandle = <0x30>;
              phandle = <0x30>;
              uart0@ {
                  allwinner,pins = "PB8", "PB9";
                  allwinner,pname = "uart0_tx", "uart0_rx";
                  allwinner,function = "uart0";
                  allwinner,muxsel = <0x4>;
                  allwinner,drive = <0x1>;
                  allwinner,pull = <0x1>;
                  linux,phandle = <0x19>;
                  phandle = <0x19>;
              };
              uart0@ {
                  allwinner,pins = "PB8", "PB9";
                  allwinner,function = "io_disabled";
                  allwinner,muxsel = <0x7>;
                  allwinner,drive = <0x1>;
                  allwinner,pull = <0x1>;
                  linux,phandle = <0x1a>;
                  phandle = <0x1a>;
              };
              ......
              ......
              ......
          };
          uart@01c28000 {
              compatible = "allwinner,sun50i-uart";
              device_type = "uart0";
              reg = <0x0 0x1c28000 0x0 0x400>;
              interrupts = <0x0 0x0 0x4>;
              clocks = <0x18>;
              pinctrl-names = "default", "sleep";
              pinctrl- = <0x19>;
              pinctrl- = <0x1a>;
              uart0_port = <0x0>;
              uart0_type = <0x2>;
              status = "disabled";
          };
pinctrl-names = "default", "sleep";的两种状态的phandle对应于pinctrl-0(uart0@0)和pinctrl-1(uart0@1),uart0@0里面的配置是全志硬件平台相关,跟confops、pctlops和pmxops相关。
如何开启设备树对应的pin配置?
一般在driver程序里面调用devm_pinctrl_get_select_default就可以。
定义在linux3-10/include/pintrl/consumer.h:
static inline struct pinctrl * __must_check devm_pinctrl_get_select(
struct device *dev, const char *name)
{
struct pinctrl *p;
struct pinctrl_state *s;
int ret; //通过device获取phandle,若是新设备则会调用创建head_list,找到pinctrl父设备sun50i-pinctrl ,解析设备树,
//创建states,获取硬件相关配置,最后add devices。
p = devm_pinctrl_get(dev);
if (IS_ERR(p))
return p; s = pinctrl_lookup_state(p, name);
if (IS_ERR(s)) {
devm_pinctrl_put(p);
return ERR_CAST(s);
}
//设置state(默认是DEFAULT)从设备树对应的配置
ret = pinctrl_select_state(p, s);
if (ret < ) {
devm_pinctrl_put(p);
return ERR_PTR(ret);
} return p;
}
调用IO口或者中断可以参考linux-3.10/drivers/pinctrl/sunxi/pinctrl-sunxi-test.c
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/sys_config.h>
#include <linux/string.h> static struct of_device_id sunxi_pinctrl_test_match[] = {
{ .compatible = "allwinner,sun50i-vdevice"},
}; //这里要在dts文件建立compatible = "allwinner,sun50i-vdevice"的node才能匹配driver static irqreturn_t test_sunxi_pinctrl_irq_handler(int irq, void *dev_id)
{
pr_warn("[%s] handler for test pinctrl eint api.\n", __func__);
disable_irq_nosync(irq);
return IRQ_HANDLED; } static int sunxi_pinctrl_test_probe(struct platform_device *pdev)
{
struct gpio_config config;
unsigned int ret;
struct device_node *node; int req_irq_status;
int req_status;
int virq; node=of_find_node_by_type(NULL, "vdevice"); //通过属性device_type = "vdevice"找到设备树节点
if(!node){
printk("find node\n");
}
ret = of_get_named_gpio_flags(node, "test-gpios", , (enum of_gpio_flags *)&config);
//找到设备树属性test-gpios,解析GPIO配置,这步是重点(不同硬件平台不一定相同)
if (!gpio_is_valid(ret)) {
return -EINVAL;
}
printk("config: gpio=%d mul=%d drive=%d pull=%d data=%d\n"
, config.gpio
, config.mul_sel
, config.drv_level
, config.pull
, config.data);
req_status = gpio_request(config.gpio, NULL);
if ( != req_status)
return -EINVAL;
virq = gpio_to_irq(config.gpio);
if (IS_ERR_VALUE(virq)) {
pr_warn("gpio[%d]get virq[%d] failed!\n", config.gpio, virq);
return -EINVAL;
}
req_irq_status = devm_request_irq(&pdev->dev, virq,
test_sunxi_pinctrl_irq_handler,
IRQF_TRIGGER_LOW, "GPIO_EINT", NULL);
if (IS_ERR_VALUE(req_irq_status)) {
pr_warn("request irq failed !\n");
return -EINVAL;
}
return ;
} static struct platform_driver sunxi_pinctrl_test_driver = {
.probe = sunxi_pinctrl_test_probe,
.driver = {
.name = "vdevice",
.owner = THIS_MODULE,
.of_match_table = sunxi_pinctrl_test_match,
},
}; static int __init sunxi_pinctrl_test_init(void)
{
int ret;
ret = platform_driver_register(&sunxi_pinctrl_test_driver);
if (IS_ERR_VALUE(ret)) {
pr_warn("register sunxi pinctrl platform driver failed\n");
return -EINVAL;
}
return ;
}
late_initcall(sunxi_pinctrl_test_init); MODULE_AUTHOR("Huangshr<huangshr@allwinnertech.com");
MODULE_DESCRIPTION("Allwinner SUNXI Pinctrl driver test");
MODULE_LICENSE("GPL");
一般应用是
pinctrl框架的更多相关文章
- pinctrl框架【转】
		
转自:http://www.cnblogs.com/kevinhwang/p/5703192.html pinctrl框架是linux系统为统一各SOC厂家pin管理,目的是为了减少SOC厂家系统移植 ...
 - gpio子系统和pinctrl子系统(中)
		
pinctrl子系统核心实现分析 pinctrl子系统的内容在drivers/pinctrl文件夹下,主要文件有(建议先看看pinctrl内核文档Documentation/pinctrl.txt): ...
 - gpio子系统和pinctrl子系统(上)
		
前言 随着内核的发展,linux驱动框架在不断的变化.很早很早以前,出现了gpio子系统,后来又出现了pinctrl子系统.在网上很难看到一篇讲解这类子系统的文章.就拿gpio操作来说吧,很多时候都是 ...
 - Linux驱动架构之pinctrl子系统分析(一)
		
1.前言在嵌入式系统中,许多SoC的内部都包含了pin控制器,通过芯片内部的pin控制器,我们可以配置一个或者一组引脚的状态和功能特性,Linux内核为了统一各SoC厂商的引脚管理,提供了pinctr ...
 - Linux驱动之GPIO子系统和pinctrl子系统
		
前期知识 1.如何编写一个简单的Linux驱动(一)--驱动的基本框架 2.如何编写一个简单的Linux驱动(二)--设备操作集file_operations 3.如何编写一个简单的Lin ...
 - Linux 驱动框架---linux 设备
		
Linux 设备 Linux驱动中的三大主要基础成员主要是设备,总线和驱动.今天先来从设备开始分析先把设备相关的数据结构放到这里方便后面看到来查,其中有些进行了简单的注释. struct device ...
 - 避免重复造轮子的UI自动化测试框架开发
		
一懒起来就好久没更新文章了,其实懒也还是因为忙,今年上半年的加班赶上了去年一年的加班,加班不息啊,好了吐槽完就写写一直打算继续的自动化开发 目前各种UI测试框架层出不穷,但是万变不离其宗,驱动PC浏览 ...
 - ABP入门系列(1)——学习Abp框架之实操演练
		
作为.Net工地搬砖长工一名,一直致力于挖坑(Bug)填坑(Debug),但技术却不见长进.也曾热情于新技术的学习,憧憬过成为技术大拿.从前端到后端,从bootstrap到javascript,从py ...
 - 旺财速啃H5框架之Bootstrap(五)
		
在上一篇<<旺财速啃H5框架之Bootstrap(四)>>做了基本的框架,<<旺财速啃H5框架之Bootstrap(二)>>篇里也大体认识了bootst ...
 
随机推荐
- lua优化
			
前言 Lua是一门以其性能著称的脚本语言,被广泛应用在很多方面,尤其是游戏.像<魔兽世界>的插件,手机游戏<大掌门><神曲><迷失之地>等都是用Lua来 ...
 - mysqldump: Got error: 1135: Can't create a new thread (errno 11); if you are not out of available memory, you can consult the manual for a possible OS-dependent bug when trying to connect 解决办法
			
在进行数据库备份的时候发现服务器报 mysqldump: Got error: 1135: Can't create a new thread (errno 11); if you are not o ...
 - STL应用——hdu1702(队列+堆栈)
			
水题 练习一下堆栈和队列的使用 #include <iostream> #include <cstdio> #include <algorithm> #includ ...
 - NO12——快速幂取模
			
long long quickmod(long long a,long long b,long long m) { ; while(b)//用一个循环从右到左便利b的所有二进制位 { )//判断此时b ...
 - Alpha项目冲刺(团队作业5)
			
团队成员 组 员 学号 朱世杰 211414141 曹晔宁 211306302 一.冲刺(7次 Scrum) [Alpha版本]冲刺阶段--Day 1 [Alpha版本]冲刺阶段--Day 2 [Al ...
 - MFC MDI 工程禁用win7任务栏(taskbar)多视图缩略图(preview)功能
			
花费了好几天,google上的把搜索关键字都想烂了终于搜出了答案 app的init函数中在创建mainframe之前调用 EnableTaskbarInteraction(FALSE);
 - webmagic 二次开发爬虫 爬取网站图片
			
webmagic的是一个无须配置.便于二次开发的爬虫框架,它提供简单灵活的API,只需少量代码即可实现一个爬虫. webmagic介绍 编写一个简单的爬虫 webmagic的使用文档:http://w ...
 - lintcode-74-第一个错误的代码版本
			
74-第一个错误的代码版本 代码库的版本号是从 1 到 n 的整数.某一天,有人提交了错误版本的代码,因此造成自身及之后版本的代码在单元测试中均出错.请找出第一个错误的版本号. 你可以通过 isBad ...
 - vue2.0介绍
			
1.vue.js 是什么 vue(view)是一套构建用户界面的渐进式框架 Vue (pronounced /vjuː/, like view) is a progressive framework ...
 - Maven中如何将源码之外的文件打包及添加本地jar
			
<build> <resources> <resource> <directory>src/main/resources</directory&g ...