Linux之pinctrl subsystem

概述:

在各个平台(cpu厂商)上,都会用很多pin用于和外设通讯,同一个pin也会有多种功能,如同一个pin具有gpio,spi,uart,I2C等功能,这些功能会根据需求切换,以及在不同功能下都会上下拉,驱动能力,电压域的配置。linux为管理这些pin,就设计出了pinctrl subsystem来解决这类问题。当然,也可以不用pinctrl来管理,平台厂商如果不用,就会自己设计接口来管理,这种情况就具体看了。

pinctrl subsystem的结构:

个人理解,在linux提供给驱动用的subsystem基本上都是:

  • 外设驱动开发接口
  • 平台(cpu)开发接口
  • pinctrl core

本文将按照这三个部分,来讲述pinctrl subsystem。

pinctrl core:

  • pinctrl core目的(效果,作用):
    驱动开发者,在开发外设驱动时,将外部设备与主控连接的pin配置需要的功能时,只需要简单的提供设备的struct device和功能的名字,这两个信息就可以设置到需要的功能。

  • 为实现目的,设计三个结构体为核心(drivers\pinctrl\core.h):
    struct pinctrl_dev;
    struct pinctrl_map;
    struct pinctrl;
    同时也定义了这三个结构体链表,方便管理和查询pinctrldev_list,pinctrl_maps,pinctrl_list(定义都在drivers\pinctrl\core.c)
    (1)首先,平台厂商通过pinctrl_register()注册struct pinctrl_dev到core,
    struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,struct device *dev, void *driver_data)
    重点就在构建struct pinctrl_desc 和driver_data.
    (2)一般在驱动开发中,都是通过platform注册,在probe前会调用在drivers\base\dd.c里面函数really_preboe(),在这个函数里面,又会调用pinctrl_bind_pins(),这个函数就会为struct device创建pins成员,如果device中of_node(dts中节点)指向的dts节点中,有:

    pinctrl-names = "default","gpio";
    pinctrl-0 = <0xb8 0xb9>;
    pinctrl-1 = <0xba>;

则根据phandle值,建立struct pinctrl_map,这样,设备device的pins(struct pinctrl)通过pinctrl_map与pinctrl_dev联系起来,达到了通过device查询到pinctrl_dev里面pin的配置。改变pin属性配置,就变成了只需要修改dts里面设备节点phandle的值了。

外设驱动开发接口:

平台提供商在releas的code里面,如果用pinctrl来管理pin,那么一般都会做好cpu的pin资源与pinctrl subsystem的对接。那剩下给外设驱动开发,配置某个pin成需要的功能,就非常简单了。主要用下面两个函数即可,用下面的函数需要在驱动模块里面包含如下头文件:

#include <linux/pinctrl/consumer.h>

函数:

struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p,
                         const char *name);
int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)

用法:

  1. 首先用pinctrl_lookup_state()查询是否有name指定的功能,如果有返回pinctrl_state这个结构体的指针,没有返回负数。
  2. 然后用pinctrl_select_state()切换pin到需要的功能。

例子:

struct device dev;
struct pinctrl_state *pinfunc;
pinfunc = pinctrl_lookup_state(dev.pins->p,"gpio");
if(IS_ERR(pinfunc))
    return -1;//error
if(pinctrl_select_state(dev.pins->p,pinfunc))
    return -1;//error
return 0; 

在dts中查看pin可以配置那些功能:
一般情况,为了描述CPU可控制pin的情况,会在dts中创建一个pinctrl node,如下:

pinctrl@ff770000{
...
...
    gpi08_i2c1{
        i2c1-sda{
            rockchip,pins = <0x8a41>;//具体哪个pin和pin配置成什么功能,这里是i2c的sda
            rockchip,pull = <0x4>;//I2C功能,pin上下拉配置要求
            rockchip,drive = <0x0>;//pin的驱动能力
            linux,phandle = <0xb8>;//此配置的编号,这个值在dts中是唯一的(老版本写法,为了兼容)
            phandle = <0xb8>;//和linux,phandle是一样的,此处是新版本,
        };
        i2c1-scl{
            rockchip,pins = <0x8a51>;
            rockchip,pull = <0x4>;
            rockchip,drive = <0x0>;
            linux,phandle = <0xb9>;
            phandle = <0xb9>;
        };
        i2c1-gpio{
            rockchip,pins = <0x8a40>;
            rockchip,drive = <0x0>;
            linux,phandle = <0xba>;
            phandle = <0xba>;
        };
    };
};
...
...

下面是配置成I2C功能,需要指定pin配置:

i2c@ff140000{
...
...
pinctrl-names = "default","gpio";//这个节点提供了两种功能default和gpio
pinctrl-0 = <0xb8 0xb9>;//对应default功能(i2c),pin配置采用上面"phandle = <0xb8>""phandle = <0xb9>"所在节点(dts节点)属性配置
pinctrl-1 = <0xba>;//对应gpio,pin配置采用“phandle = <0xba>”所在节点(dts节点)属性配置
...
...
};

回到下面这行代码,就很清楚了:
pinfunc = pinctrl_lookup_state(dev.pins->p,”gpio”);

待续……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值